Snap for 5999261 from 58676c988f4a9521d455412a20afad7d0fabe3b1 to r-keystone-qcom-release

Change-Id: I6c4515c8762daa822d9c71ecd55c15f0a6c639b7
diff --git a/.checkpatch.conf b/.checkpatch.conf
new file mode 100644
index 0000000..baa983d
--- /dev/null
+++ b/.checkpatch.conf
@@ -0,0 +1,91 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#
+# Configure how the Linux checkpatch script should be invoked in the context of
+# the Trusted Firmware source tree.
+#
+
+# This is not Linux so don't expect a Linux tree!
+--no-tree
+
+# The Linux kernel expects the SPDX license tag in the first line of each file.
+# We don't follow this in the Trusted Firmware.
+--ignore SPDX_LICENSE_TAG
+
+# This clarifes the lines indications in the report.
+#
+# E.g.:
+# Without this option, we have the following output:
+#      #333: FILE: drivers/arm/gic/arm_gic.c:160:
+# So we have 2 lines indications (333 and 160), which is confusing.
+# We only care about the position in the source file.
+#
+# With this option, it becomes:
+#      drivers/arm/gic/arm_gic.c:160:
+--showfile
+
+# Don't show some messages like the list of ignored types or the suggestion to
+# use "--fix" or report changes to the maintainers.
+--quiet
+
+#
+# Ignore the following message types, as they don't necessarily make sense in
+# the context of the Trusted Firmware.
+#
+
+# COMPLEX_MACRO generates false positives.
+--ignore COMPLEX_MACRO
+
+# Commit messages might contain a Gerrit Change-Id.
+--ignore GERRIT_CHANGE_ID
+
+# Do not check the format of commit messages, as Gerrit's merge commits do not
+# preserve it.
+--ignore GIT_COMMIT_ID
+
+# FILE_PATH_CHANGES reports this kind of message:
+# "added, moved or deleted file(s), does MAINTAINERS need updating?"
+# We do not use this MAINTAINERS file process in TF.
+--ignore FILE_PATH_CHANGES
+
+# AVOID_EXTERNS reports this kind of messages:
+# "externs should be avoided in .c files"
+# We don't follow this convention in TF.
+--ignore AVOID_EXTERNS
+
+# NEW_TYPEDEFS reports this kind of messages:
+# "do not add new typedefs"
+# We allow adding new typedefs in TF.
+--ignore NEW_TYPEDEFS
+
+# Avoid "Does not appear to be a unified-diff format patch" message
+--ignore NOT_UNIFIED_DIFF
+
+# VOLATILE reports this kind of messages:
+# "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt"
+# We allow the usage of the volatile keyword in TF.
+--ignore VOLATILE
+
+# BRACES reports this kind of messages:
+# braces {} are not necessary for any arm of this statement
+--ignore BRACES
+
+# PREFER_KERNEL_TYPES reports this kind of messages (when using --strict):
+# "Prefer kernel type 'u32' over 'uint32_t'"
+--ignore PREFER_KERNEL_TYPES
+
+# USLEEP_RANGE reports this kind of messages (when using --strict):
+# "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt"
+--ignore USLEEP_RANGE
+
+# COMPARISON_TO_NULL reports this kind of messages (when using --strict):
+# Comparison to NULL could be written ""
+--ignore COMPARISON_TO_NULL
+
+# UNNECESSARY_PARENTHESES reports this kind of messages (when using --strict):
+# Unnecessary parentheses around ""
+--ignore UNNECESSARY_PARENTHESES
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..928c307
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Trusted Firmware-A Coding style spec for editors.
+
+# References:
+# [EC]          http://editorconfig.org/
+# [CONT]        contributing.rst
+# [LCS]         Linux Coding Style
+#               (https://www.kernel.org/doc/html/v4.10/process/coding-style.html)
+
+
+root = true
+
+# set default to match [LCS] .c/.h settings.
+# This will also apply to .S, .mk, .sh, Makefile, .dts, etc.
+[*]
+# Not specified, but fits current ARM-TF sources.
+charset = utf-8
+
+# Not specified, but implicit for "LINUX coding style".
+end_of_line = lf
+
+# [LCS] Chapter 1: Indentation
+#       "and thus indentations are also 8 characters"
+indent_size = 8
+
+# [LCS] Chapter 1: Indentation
+#       "Outside of comments,...spaces are never used for indentation"
+indent_style = tab
+
+# Not specified by [LCS], but sensible
+insert_final_newline = true
+
+# [LCS] Chapter 2: Breaking long lines and strings
+#       "The limit on the length of lines is 80 columns"
+#   This is a "soft" requirement for Arm-TF, and should not be the sole
+#   reason for changes.
+max_line_length = 80
+
+# [LCS] Chapter 1: Indentation
+#       "Tabs are 8 characters"
+tab_width = 8
+
+# [LCS] Chapter 1: Indentation
+#       "Get a decent editor and don't leave whitespace at the end of lines."
+# [LCS] Chapter 3.1: Spaces
+#       "Do not leave trailing whitespace at the ends of lines."
+trim_trailing_whitespace = true
+
+
+# Adjustment for existing .rst files with different format
+[*.{rst,md}]
+indent_size = 4
+indent_style = space
+max_line_length = 180
+# 180 only selected to prevent changes to existing text.
+tab_width = 4
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6b1e057
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+# Ignore miscellaneous files
+cscope.*
+*.swp
+*.patch
+*~
+.project
+.cproject
+
+# Ignore build directory
+build/
+
+# Ignore build products from tools
+tools/**/*.o
+tools/renesas/rcar_layout_create/*.bin
+tools/renesas/rcar_layout_create/*.srec
+tools/renesas/rcar_layout_create/*.map
+tools/renesas/rcar_layout_create/*.elf
+tools/fiptool/fiptool
+tools/fiptool/fiptool.exe
+tools/cert_create/src/*.o
+tools/cert_create/src/**/*.o
+tools/cert_create/cert_create
+tools/cert_create/cert_create.exe
+tools/marvell/doimage/doimage
+tools/meson/doimage
+tools/stm32image/*.o
+tools/stm32image/stm32image
+tools/stm32image/stm32image.exe
+tools/sptool/sptool
+tools/sptool/sptool.exe
+
+# GNU GLOBAL files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..78d4156
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,64 @@
+Copyright (c) [XXXX-]YYYY, <OWNER>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+-  Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+-  Redistributions in binary form must reproduce the above copyright notice, this
+   list of conditions and the following disclaimer in the documentation and/or
+   other materials provided with the distribution.
+
+-  Neither the name of Arm nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific prior
+   written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------
+
+.. note::
+   Individual files contain the following tag instead of the full license text.
+
+::
+
+    SPDX-License-Identifier:    BSD-3-Clause
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
+
+------------------
+
+Copyright 1992-2019 The FreeBSD Project.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project.
+
+--------------
+
+.. note::
+   Individual files contain the following tag instead of the full license text.
+
+::
+
+    SPDX-License-Identifier:    BSD-2-Clause-FreeBSD
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..198f5ce
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,18 @@
+name: "arm-trusted-firmware"
+description:
+    "The Trusted Firmware-A project provides a reference implementation
+    of secure world software for Armv7-A and Armv8-A class processors."
+
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://developer.trustedfirmware.org/dashboard/view/6/"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/ARM-software/arm-trusted-firmware.git"
+  }
+  version: "v2.1"
+  last_upgrade_date { year: 2019 month: 8 day: 20 }
+  license_type: NOTICE
+}
diff --git a/MODULE_LICENSE_BSD b/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..43ff8d2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,988 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#
+# Trusted Firmware Version
+#
+VERSION_MAJOR			:= 2
+VERSION_MINOR			:= 1
+
+# Default goal is build all images
+.DEFAULT_GOAL			:= all
+
+# Avoid any implicit propagation of command line variable definitions to
+# sub-Makefiles, like CFLAGS that we reserved for the firmware images'
+# usage. Other command line options like "-s" are still propagated as usual.
+MAKEOVERRIDES =
+
+MAKE_HELPERS_DIRECTORY := make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+################################################################################
+# Default values for build configurations, and their dependencies
+################################################################################
+
+include ${MAKE_HELPERS_DIRECTORY}defaults.mk
+
+# Assertions enabled for DEBUG builds by default
+ENABLE_ASSERTIONS		:= ${DEBUG}
+ENABLE_PMF			:= ${ENABLE_RUNTIME_INSTRUMENTATION}
+PLAT				:= ${DEFAULT_PLAT}
+
+################################################################################
+# Checkpatch script options
+################################################################################
+
+CHECKCODE_ARGS		:=	--no-patch
+# Do not check the coding style on imported library files or documentation files
+INC_LIB_DIRS_TO_CHECK	:=	$(sort $(filter-out			\
+					include/lib/libfdt		\
+					include/lib/libc,		\
+					$(wildcard include/lib/*)))
+INC_DIRS_TO_CHECK	:=	$(sort $(filter-out			\
+					include/lib,			\
+					$(wildcard include/*)))
+LIB_DIRS_TO_CHECK	:=	$(sort $(filter-out			\
+					lib/compiler-rt			\
+					lib/libfdt%			\
+					lib/libc,			\
+					$(wildcard lib/*)))
+ROOT_DIRS_TO_CHECK	:=	$(sort $(filter-out			\
+					lib				\
+					include				\
+					docs				\
+					%.rst,				\
+					$(wildcard *)))
+CHECK_PATHS		:=	${ROOT_DIRS_TO_CHECK}			\
+				${INC_DIRS_TO_CHECK}			\
+				${INC_LIB_DIRS_TO_CHECK}		\
+				${LIB_DIRS_TO_CHECK}
+
+
+################################################################################
+# Process build options
+################################################################################
+
+# Verbose flag
+ifeq (${V},0)
+        Q:=@
+        ECHO:=@echo
+        CHECKCODE_ARGS	+=	--no-summary --terse
+else
+        Q:=
+        ECHO:=$(ECHO_QUIET)
+endif
+
+ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),)
+        Q:=@
+        ECHO:=$(ECHO_QUIET)
+endif
+
+export Q ECHO
+
+# Process Debug flag
+$(eval $(call add_define,DEBUG))
+ifneq (${DEBUG}, 0)
+        BUILD_TYPE	:=	debug
+        TF_CFLAGS	+= 	-g
+
+        ifneq ($(findstring clang,$(notdir $(CC))),)
+             ASFLAGS		+= 	-g
+        else
+             ASFLAGS		+= 	-g -Wa,--gdwarf-2
+        endif
+
+        # Use LOG_LEVEL_INFO by default for debug builds
+        LOG_LEVEL	:=	40
+else
+        BUILD_TYPE	:=	release
+        # Use LOG_LEVEL_NOTICE by default for release builds
+        LOG_LEVEL	:=	20
+endif
+
+# Default build string (git branch and commit)
+ifeq (${BUILD_STRING},)
+        BUILD_STRING	:=	$(shell git describe --always --dirty --tags 2> /dev/null)
+endif
+VERSION_STRING		:=	v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STRING}
+
+# The cert_create tool cannot generate certificates individually, so we use the
+# target 'certificates' to create them all
+ifneq (${GENERATE_COT},0)
+        FIP_DEPS += certificates
+        FWU_FIP_DEPS += fwu_certificates
+endif
+
+# Process BRANCH_PROTECTION value and set
+# Pointer Authentication and Branch Target Identification flags
+ifeq (${BRANCH_PROTECTION},0)
+	# Default value turns off all types of branch protection
+	BP_OPTION := none
+else ifneq (${ARCH},aarch64)
+        $(error BRANCH_PROTECTION requires AArch64)
+else ifeq (${BRANCH_PROTECTION},1)
+	# Enables all types of branch protection features
+	BP_OPTION := standard
+	ENABLE_BTI := 1
+	ENABLE_PAUTH := 1
+else ifeq (${BRANCH_PROTECTION},2)
+	# Return address signing to its standard level
+	BP_OPTION := pac-ret
+	ENABLE_PAUTH := 1
+else ifeq (${BRANCH_PROTECTION},3)
+	# Extend the signing to include leaf functions
+	BP_OPTION := pac-ret+leaf
+	ENABLE_PAUTH := 1
+else
+        $(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION})
+endif
+
+################################################################################
+# Toolchain
+################################################################################
+
+HOSTCC			:=	gcc
+export HOSTCC
+
+CC			:=	${CROSS_COMPILE}gcc
+CPP			:=	${CROSS_COMPILE}cpp
+AS			:=	${CROSS_COMPILE}gcc
+AR			:=	${CROSS_COMPILE}ar
+LINKER			:=	${CROSS_COMPILE}ld
+OC			:=	${CROSS_COMPILE}objcopy
+OD			:=	${CROSS_COMPILE}objdump
+NM			:=	${CROSS_COMPILE}nm
+PP			:=	${CROSS_COMPILE}gcc -E
+DTC			:=	dtc
+
+# Use ${LD}.bfd instead if it exists (as absolute path or together with $PATH).
+ifneq ($(strip $(wildcard ${LD}.bfd) \
+	$(foreach dir,$(subst :, ,${PATH}),$(wildcard ${dir}/${LINKER}.bfd))),)
+LINKER			:=	${LINKER}.bfd
+endif
+
+ifeq (${ARM_ARCH_MAJOR},7)
+target32-directive	= 	-target arm-none-eabi
+# Will set march32-directive from platform configuration
+else
+target32-directive	= 	-target armv8a-none-eabi
+
+# Set the compiler's target architecture profile based on ARM_ARCH_MINOR option
+ifeq (${ARM_ARCH_MINOR},0)
+march32-directive	= 	-march=armv8-a
+march64-directive	= 	-march=armv8-a
+else
+march32-directive	= 	-march=armv8.${ARM_ARCH_MINOR}-a
+march64-directive	= 	-march=armv8.${ARM_ARCH_MINOR}-a
+endif
+endif
+
+ifneq ($(findstring armclang,$(notdir $(CC))),)
+TF_CFLAGS_aarch32	=	-target arm-arm-none-eabi $(march32-directive)
+TF_CFLAGS_aarch64	=	-target aarch64-arm-none-eabi $(march64-directive)
+LD			=	$(LINKER)
+AS			=	$(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH))
+CPP			=	$(CC) -E $(TF_CFLAGS_$(ARCH))
+PP			=	$(CC) -E $(TF_CFLAGS_$(ARCH))
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+TF_CFLAGS_aarch32	=	$(target32-directive) $(march32-directive)
+TF_CFLAGS_aarch64	=	-target aarch64-elf $(march64-directive)
+LD			=	$(LINKER)
+AS			=	$(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH))
+CPP			=	$(CC) -E
+PP			=	$(CC) -E
+else
+TF_CFLAGS_aarch32	=	$(march32-directive)
+TF_CFLAGS_aarch64	=	$(march64-directive)
+LD			=	$(LINKER)
+endif
+
+ifeq (${AARCH32_INSTRUCTION_SET},A32)
+TF_CFLAGS_aarch32	+=	-marm
+else ifeq (${AARCH32_INSTRUCTION_SET},T32)
+TF_CFLAGS_aarch32	+=	-mthumb
+else
+$(error Error: Unknown AArch32 instruction set ${AARCH32_INSTRUCTION_SET})
+endif
+
+TF_CFLAGS_aarch32	+=	-mno-unaligned-access
+TF_CFLAGS_aarch64	+=	-mgeneral-regs-only -mstrict-align
+
+ifneq (${BP_OPTION},none)
+TF_CFLAGS_aarch64	+=	-mbranch-protection=${BP_OPTION}
+endif
+
+ASFLAGS_aarch32		=	$(march32-directive)
+ASFLAGS_aarch64		=	$(march64-directive)
+
+WARNING1 := -Wextra
+WARNING1 += -Wmissing-declarations
+WARNING1 += -Wmissing-format-attribute
+WARNING1 += -Wmissing-prototypes
+WARNING1 += -Wold-style-definition
+WARNING1 += -Wunused-const-variable
+
+WARNING2 := -Waggregate-return
+WARNING2 += -Wcast-align
+WARNING2 += -Wnested-externs
+WARNING2 += -Wshadow
+WARNING2 += -Wlogical-op
+WARNING2 += -Wmissing-field-initializers
+WARNING2 += -Wsign-compare
+
+WARNING3 := -Wbad-function-cast
+WARNING3 += -Wcast-qual
+WARNING3 += -Wconversion
+WARNING3 += -Wpacked
+WARNING3 += -Wpadded
+WARNING3 += -Wpointer-arith
+WARNING3 += -Wredundant-decls
+WARNING3 += -Wswitch-default
+
+ifeq (${W},1)
+WARNINGS := $(WARNING1)
+else ifeq (${W},2)
+WARNINGS := $(WARNING1) $(WARNING2)
+else ifeq (${W},3)
+WARNINGS := $(WARNING1) $(WARNING2) $(WARNING3)
+endif
+
+WARNINGS	+=		-Wunused -Wno-unused-parameter	\
+				-Wdisabled-optimization		\
+				-Wvla
+
+ifeq ($(findstring clang,$(notdir $(CC))),)
+# not using clang
+WARNINGS	+=		-Wunused-but-set-variable	\
+				-Wmaybe-uninitialized		\
+				-Wpacked-bitfield-compat	\
+				-Wshift-overflow=2
+else
+# using clang
+WARNINGS	+=		-Wshift-overflow -Wshift-sign-overflow
+endif
+
+ifneq (${E},0)
+ERRORS := -Werror
+endif
+
+CPPFLAGS		=	${DEFINES} ${INCLUDES} ${MBEDTLS_INC} -nostdinc		\
+				-Wmissing-include-dirs $(ERRORS) $(WARNINGS)
+ASFLAGS			+=	$(CPPFLAGS) $(ASFLAGS_$(ARCH))			\
+				-ffreestanding -Wa,--fatal-warnings
+TF_CFLAGS		+=	$(CPPFLAGS) $(TF_CFLAGS_$(ARCH))		\
+				-ffreestanding -fno-builtin -Wall -std=gnu99	\
+				-Os -ffunction-sections -fdata-sections
+
+GCC_V_OUTPUT		:=	$(shell $(CC) -v 2>&1)
+
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+TF_LDFLAGS		+=	--diag_error=warning --lto_level=O1
+TF_LDFLAGS		+=	--remove --info=unused,unusedsymbols
+else
+TF_LDFLAGS		+=	--fatal-warnings -O1
+TF_LDFLAGS		+=	--gc-sections
+endif
+TF_LDFLAGS		+=	$(TF_LDFLAGS_$(ARCH))
+
+DTC_FLAGS		+=	-I dts -O dtb
+DTC_CPPFLAGS		+=	-nostdinc -Iinclude -undef -x assembler-with-cpp
+
+################################################################################
+# Common sources and include directories
+################################################################################
+include lib/compiler-rt/compiler-rt.mk
+
+BL_COMMON_SOURCES	+=	common/bl_common.c			\
+				common/tf_log.c				\
+				common/${ARCH}/debug.S			\
+				drivers/console/multi_console.c		\
+				lib/${ARCH}/cache_helpers.S		\
+				lib/${ARCH}/misc_helpers.S		\
+				plat/common/plat_bl_common.c		\
+				plat/common/plat_log_common.c		\
+				plat/common/${ARCH}/plat_common.c	\
+				plat/common/${ARCH}/platform_helpers.S	\
+				${COMPILER_RT_SRCS}
+
+ifeq ($(notdir $(CC)),armclang)
+BL_COMMON_SOURCES	+=	lib/${ARCH}/armclang_printf.S
+endif
+
+INCLUDES		+=	-Iinclude				\
+				-Iinclude/arch/${ARCH}			\
+				-Iinclude/lib/cpus/${ARCH}		\
+				-Iinclude/lib/el3_runtime/${ARCH}	\
+				${PLAT_INCLUDES}			\
+				${SPD_INCLUDES}
+
+include common/backtrace/backtrace.mk
+
+################################################################################
+# Generic definitions
+################################################################################
+
+include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk
+
+BUILD_BASE		:=	./build
+BUILD_PLAT		:=	${BUILD_BASE}/${PLAT}/${BUILD_TYPE}
+
+SPDS			:=	$(sort $(filter-out none, $(patsubst services/spd/%,%,$(wildcard services/spd/*))))
+
+# Platforms providing their own TBB makefile may override this value
+INCLUDE_TBBR_MK		:=	1
+
+
+################################################################################
+# Include SPD Makefile if one has been specified
+################################################################################
+
+ifneq (${SPD},none)
+ifeq (${ARCH},aarch32)
+        $(error "Error: SPD is incompatible with AArch32.")
+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
+        # We expect to locate an spd.mk under the specified SPD directory
+        SPD_MAKE	:=	$(wildcard services/spd/${SPD}/${SPD}.mk)
+
+        ifeq (${SPD_MAKE},)
+                $(error Error: No services/spd/${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.
+endif
+
+################################################################################
+# Include the platform specific Makefile after the SPD Makefile (the platform
+# makefile may use all previous definitions in this file)
+################################################################################
+
+include ${PLAT_MAKEFILE_FULL}
+
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_PLAT}))
+
+ifeq (${ARM_ARCH_MAJOR},7)
+include make_helpers/armv7-a-cpus.mk
+endif
+
+ifeq ($(ENABLE_PIE),1)
+    TF_CFLAGS		+=	-fpie
+    TF_LDFLAGS		+=	-pie --no-dynamic-linker
+else
+    PIE_FOUND		:=	$(findstring --enable-default-pie,${GCC_V_OUTPUT})
+    ifneq ($(PIE_FOUND),)
+        TF_CFLAGS		+=	-fno-PIE
+    endif
+endif
+
+# Include the CPU specific operations makefile, which provides default
+# values for all CPU errata workarounds and CPU specific optimisations.
+# This can be overridden by the platform.
+include lib/cpus/cpu-ops.mk
+
+ifeq (${ARCH},aarch32)
+NEED_BL32 := yes
+
+################################################################################
+# Build `AARCH32_SP` as BL32 image for AArch32
+################################################################################
+ifneq (${AARCH32_SP},none)
+# We expect to locate an sp.mk under the specified AARCH32_SP directory
+AARCH32_SP_MAKE	:=	$(wildcard bl32/${AARCH32_SP}/${AARCH32_SP}.mk)
+
+ifeq (${AARCH32_SP_MAKE},)
+  $(error Error: No bl32/${AARCH32_SP}/${AARCH32_SP}.mk located)
+endif
+
+$(info Including ${AARCH32_SP_MAKE})
+include ${AARCH32_SP_MAKE}
+endif
+
+endif
+
+################################################################################
+# Include libc if not overridden
+################################################################################
+ifeq (${OVERRIDE_LIBC},0)
+include lib/libc/libc.mk
+endif
+
+################################################################################
+# Check incompatible options
+################################################################################
+
+ifdef EL3_PAYLOAD_BASE
+        ifdef PRELOADED_BL33_BASE
+                $(warning "PRELOADED_BL33_BASE and EL3_PAYLOAD_BASE are \
+                incompatible build options. EL3_PAYLOAD_BASE has priority.")
+        endif
+        ifneq (${GENERATE_COT},0)
+                $(error "GENERATE_COT and EL3_PAYLOAD_BASE are incompatible build options.")
+        endif
+        ifneq (${TRUSTED_BOARD_BOOT},0)
+                $(error "TRUSTED_BOARD_BOOT and EL3_PAYLOAD_BASE are incompatible build options.")
+        endif
+endif
+
+ifeq (${NEED_BL33},yes)
+        ifdef EL3_PAYLOAD_BASE
+                $(warning "BL33 image is not needed when option \
+                BL33_PAYLOAD_BASE is used and won't be added to the FIP file.")
+        endif
+        ifdef PRELOADED_BL33_BASE
+                $(warning "BL33 image is not needed when option \
+                PRELOADED_BL33_BASE is used and won't be added to the FIP \
+                file.")
+        endif
+endif
+
+# When building for systems with hardware-assisted coherency, there's no need to
+# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
+ifeq ($(HW_ASSISTED_COHERENCY)-$(USE_COHERENT_MEM),1-1)
+$(error USE_COHERENT_MEM cannot be enabled with HW_ASSISTED_COHERENCY)
+endif
+
+#For now, BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is 1.
+ifeq ($(BL2_AT_EL3)-$(BL2_IN_XIP_MEM),0-1)
+$(error "BL2_IN_XIP_MEM is only supported when BL2_AT_EL3 is enabled")
+endif
+
+# For RAS_EXTENSION, require that EAs are handled in EL3 first
+ifeq ($(RAS_EXTENSION),1)
+    ifneq ($(HANDLE_EA_EL3_FIRST),1)
+        $(error For RAS_EXTENSION, HANDLE_EA_EL3_FIRST must also be 1)
+    endif
+endif
+
+# When FAULT_INJECTION_SUPPORT is used, require that RAS_EXTENSION is enabled
+ifeq ($(FAULT_INJECTION_SUPPORT),1)
+    ifneq ($(RAS_EXTENSION),1)
+        $(error For FAULT_INJECTION_SUPPORT, RAS_EXTENSION must also be 1)
+    endif
+endif
+
+# DYN_DISABLE_AUTH can be set only when TRUSTED_BOARD_BOOT=1
+ifeq ($(DYN_DISABLE_AUTH), 1)
+    ifeq (${TRUSTED_BOARD_BOOT}, 0)
+        $(error "TRUSTED_BOARD_BOOT must be enabled for DYN_DISABLE_AUTH to be set.")
+    endif
+endif
+
+# If pointer authentication is used in the firmware, make sure that all the
+# registers associated to it are also saved and restored.
+# Not doing it would leak the value of the keys used by EL3 to EL1 and S-EL1.
+ifeq ($(ENABLE_PAUTH),1)
+    ifeq ($(CTX_INCLUDE_PAUTH_REGS),0)
+        $(error Pointer Authentication requires CTX_INCLUDE_PAUTH_REGS=1)
+    endif
+endif
+
+ifeq ($(CTX_INCLUDE_PAUTH_REGS),1)
+    ifneq (${ARCH},aarch64)
+        $(error CTX_INCLUDE_PAUTH_REGS requires AArch64)
+    else
+        $(info CTX_INCLUDE_PAUTH_REGS is an experimental feature)
+    endif
+endif
+
+ifeq ($(ENABLE_PAUTH),1)
+    $(info Pointer Authentication is an experimental feature)
+endif
+
+ifeq ($(ENABLE_BTI),1)
+    $(info Branch Protection is an experimental feature)
+endif
+
+################################################################################
+# Process platform overrideable behaviour
+################################################################################
+
+# Using BL2 implies that a BL33 image also needs to be supplied for the FIP and
+# Certificate generation tools. This flag can be overridden by the platform.
+ifdef BL2_SOURCES
+        ifdef EL3_PAYLOAD_BASE
+                # If booting an EL3 payload there is no need for a BL33 image
+                # in the FIP file.
+                NEED_BL33		:=	no
+        else
+                ifdef PRELOADED_BL33_BASE
+                        # If booting a BL33 preloaded image there is no need of
+                        # another one in the FIP file.
+                        NEED_BL33		:=	no
+                else
+                        NEED_BL33		?=	yes
+                endif
+        endif
+endif
+
+# If SCP_BL2 is given, we always want FIP to include it.
+ifdef SCP_BL2
+        NEED_SCP_BL2		:=	yes
+endif
+
+# For AArch32, BL31 is not currently supported.
+ifneq (${ARCH},aarch32)
+    ifdef BL31_SOURCES
+        # When booting an EL3 payload, there is no need to compile the BL31 image nor
+        # put it in the FIP.
+        ifndef EL3_PAYLOAD_BASE
+            NEED_BL31 := yes
+        endif
+    endif
+endif
+
+# Process TBB related flags
+ifneq (${GENERATE_COT},0)
+        # Common cert_create options
+        ifneq (${CREATE_KEYS},0)
+                $(eval CRT_ARGS += -n)
+                $(eval FWU_CRT_ARGS += -n)
+                ifneq (${SAVE_KEYS},0)
+                        $(eval CRT_ARGS += -k)
+                        $(eval FWU_CRT_ARGS += -k)
+                endif
+        endif
+        # Include TBBR makefile (unless the platform indicates otherwise)
+        ifeq (${INCLUDE_TBBR_MK},1)
+                include make_helpers/tbbr/tbbr_tools.mk
+        endif
+endif
+
+ifneq (${FIP_ALIGN},0)
+FIP_ARGS += --align ${FIP_ALIGN}
+endif
+
+################################################################################
+# Include libraries' Makefile that are used in all BL
+################################################################################
+
+include lib/stack_protector/stack_protector.mk
+
+################################################################################
+# Auxiliary tools (fiptool, cert_create, etc)
+################################################################################
+
+# Variables for use with Certificate Generation Tool
+CRTTOOLPATH		?=	tools/cert_create
+CRTTOOL			?=	${CRTTOOLPATH}/cert_create${BIN_EXT}
+
+# Variables for use with Firmware Image Package
+FIPTOOLPATH		?=	tools/fiptool
+FIPTOOL			?=	${FIPTOOLPATH}/fiptool${BIN_EXT}
+
+# Variables for use with sptool
+SPTOOLPATH		?=	tools/sptool
+SPTOOL			?=	${SPTOOLPATH}/sptool${BIN_EXT}
+
+# Variables for use with ROMLIB
+ROMLIBPATH		?=	lib/romlib
+
+################################################################################
+# Include BL specific makefiles
+################################################################################
+ifdef BL1_SOURCES
+NEED_BL1 := yes
+include bl1/bl1.mk
+endif
+
+ifdef BL2_SOURCES
+NEED_BL2 := yes
+include bl2/bl2.mk
+endif
+
+ifdef BL2U_SOURCES
+NEED_BL2U := yes
+include bl2u/bl2u.mk
+endif
+
+ifeq (${NEED_BL31},yes)
+ifdef BL31_SOURCES
+include bl31/bl31.mk
+endif
+endif
+
+ifdef FDT_SOURCES
+NEED_FDT := yes
+endif
+
+################################################################################
+# Build options checks
+################################################################################
+
+$(eval $(call assert_boolean,COLD_BOOT_SINGLE_CPU))
+$(eval $(call assert_boolean,CREATE_KEYS))
+$(eval $(call assert_boolean,CTX_INCLUDE_AARCH32_REGS))
+$(eval $(call assert_boolean,CTX_INCLUDE_FPREGS))
+$(eval $(call assert_boolean,CTX_INCLUDE_PAUTH_REGS))
+$(eval $(call assert_boolean,DEBUG))
+$(eval $(call assert_boolean,DYN_DISABLE_AUTH))
+$(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
+$(eval $(call assert_boolean,ENABLE_AMU))
+$(eval $(call assert_boolean,ENABLE_ASSERTIONS))
+$(eval $(call assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS))
+$(eval $(call assert_boolean,ENABLE_PIE))
+$(eval $(call assert_boolean,ENABLE_PMF))
+$(eval $(call assert_boolean,ENABLE_PSCI_STAT))
+$(eval $(call assert_boolean,ENABLE_RUNTIME_INSTRUMENTATION))
+$(eval $(call assert_boolean,ENABLE_SPE_FOR_LOWER_ELS))
+$(eval $(call assert_boolean,ENABLE_SPM))
+$(eval $(call assert_boolean,ENABLE_SVE_FOR_NS))
+$(eval $(call assert_boolean,ERROR_DEPRECATED))
+$(eval $(call assert_boolean,FAULT_INJECTION_SUPPORT))
+$(eval $(call assert_boolean,GENERATE_COT))
+$(eval $(call assert_boolean,GICV2_G0_FOR_EL3))
+$(eval $(call assert_boolean,HANDLE_EA_EL3_FIRST))
+$(eval $(call assert_boolean,HW_ASSISTED_COHERENCY))
+$(eval $(call assert_boolean,NS_TIMER_SWITCH))
+$(eval $(call assert_boolean,OVERRIDE_LIBC))
+$(eval $(call assert_boolean,PL011_GENERIC_UART))
+$(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS))
+$(eval $(call assert_boolean,PSCI_EXTENDED_STATE_ID))
+$(eval $(call assert_boolean,RAS_EXTENSION))
+$(eval $(call assert_boolean,RESET_TO_BL31))
+$(eval $(call assert_boolean,SAVE_KEYS))
+$(eval $(call assert_boolean,SEPARATE_CODE_AND_RODATA))
+$(eval $(call assert_boolean,SPIN_ON_BL1_EXIT))
+$(eval $(call assert_boolean,SPM_MM))
+$(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
+$(eval $(call assert_boolean,USE_COHERENT_MEM))
+$(eval $(call assert_boolean,USE_ROMLIB))
+$(eval $(call assert_boolean,USE_TBBR_DEFS))
+$(eval $(call assert_boolean,WARMBOOT_ENABLE_DCACHE_EARLY))
+$(eval $(call assert_boolean,BL2_AT_EL3))
+$(eval $(call assert_boolean,BL2_IN_XIP_MEM))
+
+$(eval $(call assert_numeric,ARM_ARCH_MAJOR))
+$(eval $(call assert_numeric,ARM_ARCH_MINOR))
+$(eval $(call assert_numeric,BRANCH_PROTECTION))
+
+################################################################################
+# Add definitions to the cpp preprocessor based on the current build options.
+# This is done after including the platform specific makefile to allow the
+# platform to overwrite the default options
+################################################################################
+
+$(eval $(call add_define,ARM_ARCH_MAJOR))
+$(eval $(call add_define,ARM_ARCH_MINOR))
+$(eval $(call add_define,COLD_BOOT_SINGLE_CPU))
+$(eval $(call add_define,CTX_INCLUDE_AARCH32_REGS))
+$(eval $(call add_define,CTX_INCLUDE_FPREGS))
+$(eval $(call add_define,CTX_INCLUDE_PAUTH_REGS))
+$(eval $(call add_define,EL3_EXCEPTION_HANDLING))
+$(eval $(call add_define,ENABLE_AMU))
+$(eval $(call add_define,ENABLE_ASSERTIONS))
+$(eval $(call add_define,ENABLE_BTI))
+$(eval $(call add_define,ENABLE_MPAM_FOR_LOWER_ELS))
+$(eval $(call add_define,ENABLE_PAUTH))
+$(eval $(call add_define,ENABLE_PIE))
+$(eval $(call add_define,ENABLE_PMF))
+$(eval $(call add_define,ENABLE_PSCI_STAT))
+$(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
+$(eval $(call add_define,ENABLE_SPE_FOR_LOWER_ELS))
+$(eval $(call add_define,ENABLE_SPM))
+$(eval $(call add_define,ENABLE_SVE_FOR_NS))
+$(eval $(call add_define,ERROR_DEPRECATED))
+$(eval $(call add_define,FAULT_INJECTION_SUPPORT))
+$(eval $(call add_define,GICV2_G0_FOR_EL3))
+$(eval $(call add_define,HANDLE_EA_EL3_FIRST))
+$(eval $(call add_define,HW_ASSISTED_COHERENCY))
+$(eval $(call add_define,LOG_LEVEL))
+$(eval $(call add_define,NS_TIMER_SWITCH))
+$(eval $(call add_define,PL011_GENERIC_UART))
+$(eval $(call add_define,PLAT_${PLAT}))
+$(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS))
+$(eval $(call add_define,PSCI_EXTENDED_STATE_ID))
+$(eval $(call add_define,RAS_EXTENSION))
+$(eval $(call add_define,RESET_TO_BL31))
+$(eval $(call add_define,SEPARATE_CODE_AND_RODATA))
+$(eval $(call add_define,RECLAIM_INIT_CODE))
+$(eval $(call add_define,SPD_${SPD}))
+$(eval $(call add_define,SPIN_ON_BL1_EXIT))
+$(eval $(call add_define,SPM_MM))
+$(eval $(call add_define,TRUSTED_BOARD_BOOT))
+$(eval $(call add_define,USE_COHERENT_MEM))
+$(eval $(call add_define,USE_ROMLIB))
+$(eval $(call add_define,USE_TBBR_DEFS))
+$(eval $(call add_define,WARMBOOT_ENABLE_DCACHE_EARLY))
+$(eval $(call add_define,BL2_AT_EL3))
+$(eval $(call add_define,BL2_IN_XIP_MEM))
+
+# Define the EL3_PAYLOAD_BASE flag only if it is provided.
+ifdef EL3_PAYLOAD_BASE
+        $(eval $(call add_define,EL3_PAYLOAD_BASE))
+else
+        # Define the PRELOADED_BL33_BASE flag only if it is provided and
+        # EL3_PAYLOAD_BASE is not defined, as it has priority.
+        ifdef PRELOADED_BL33_BASE
+                $(eval $(call add_define,PRELOADED_BL33_BASE))
+        endif
+endif
+
+# Define the DYN_DISABLE_AUTH flag only if set.
+ifeq (${DYN_DISABLE_AUTH},1)
+$(eval $(call add_define,DYN_DISABLE_AUTH))
+endif
+
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+$(eval $(call add_define,USE_ARM_LINK))
+endif
+
+################################################################################
+# Build targets
+################################################################################
+
+.PHONY:	all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip fwu_fip certtool dtbs
+.SUFFIXES:
+
+all: msg_start
+
+msg_start:
+	@echo "Building ${PLAT}"
+
+ifeq (${ERROR_DEPRECATED},0)
+# Check if deprecated declarations and cpp warnings should be treated as error or not.
+ifneq ($(findstring clang,$(notdir $(CC))),)
+    CPPFLAGS		+= 	-Wno-error=deprecated-declarations
+else
+    CPPFLAGS		+= 	-Wno-error=deprecated-declarations -Wno-error=cpp
+endif
+# __ASSEMBLY__ is deprecated in favor of the compiler-builtin __ASSEMBLER__.
+ASFLAGS	+= -D__ASSEMBLY__
+# AARCH32/AARCH64 macros are deprecated in favor of the compiler-builtin __aarch64__.
+ifeq (${ARCH},aarch32)
+        $(eval $(call add_define,AARCH32))
+else
+        $(eval $(call add_define,AARCH64))
+endif
+endif # !ERROR_DEPRECATED
+
+$(eval $(call MAKE_LIB_DIRS))
+$(eval $(call MAKE_LIB,c))
+
+# Expand build macros for the different images
+ifeq (${NEED_BL1},yes)
+$(eval $(call MAKE_BL,1))
+endif
+
+ifeq (${NEED_BL2},yes)
+ifeq (${BL2_AT_EL3}, 0)
+FIP_BL2_ARGS := tb-fw
+endif
+
+$(if ${BL2}, $(eval $(call TOOL_ADD_IMG,bl2,--${FIP_BL2_ARGS})),\
+	$(eval $(call MAKE_BL,2,${FIP_BL2_ARGS})))
+endif
+
+ifeq (${NEED_SCP_BL2},yes)
+$(eval $(call TOOL_ADD_IMG,scp_bl2,--scp-fw))
+endif
+
+ifeq (${NEED_BL31},yes)
+BL31_SOURCES += ${SPD_SOURCES}
+$(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw)),\
+	$(eval $(call MAKE_BL,31,soc-fw)))
+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
+# process. Note that the dependency on BL32 applies to the FIP only.
+ifeq (${NEED_BL32},yes)
+
+BUILD_BL32 := $(if $(BL32),,$(if $(BL32_SOURCES),1))
+
+$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,32,tos-fw)),\
+	$(eval $(call TOOL_ADD_IMG,bl32,--tos-fw)))
+endif
+
+# Add the BL33 image if required by the platform
+ifeq (${NEED_BL33},yes)
+$(eval $(call TOOL_ADD_IMG,bl33,--nt-fw))
+endif
+
+ifeq (${NEED_BL2U},yes)
+$(if ${BL2U}, $(eval $(call TOOL_ADD_IMG,bl2u,--ap-fwu-cfg,FWU_)),\
+	$(eval $(call MAKE_BL,2u,ap-fwu-cfg,FWU_)))
+endif
+
+# Expand build macros for the different images
+ifeq (${NEED_FDT},yes)
+    $(eval $(call MAKE_DTBS,$(BUILD_PLAT)/fdts,$(FDT_SOURCES)))
+endif
+
+locate-checkpatch:
+ifndef CHECKPATCH
+	$(error "Please set CHECKPATCH to point to the Linux checkpatch.pl file, eg: CHECKPATCH=../linux/scripts/checkpatch.pl")
+else
+ifeq (,$(wildcard ${CHECKPATCH}))
+	$(error "The file CHECKPATCH points to cannot be found, use eg: CHECKPATCH=../linux/scripts/checkpatch.pl")
+endif
+endif
+
+clean:
+	@echo "  CLEAN"
+	$(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} --no-print-directory -C ${ROMLIBPATH} clean
+
+realclean distclean:
+	@echo "  REALCLEAN"
+	$(call SHELL_REMOVE_DIR,${BUILD_BASE})
+	$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
+	${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} --no-print-directory -C ${ROMLIBPATH} clean
+
+checkcodebase:		locate-checkpatch
+	@echo "  CHECKING STYLE"
+	@if test -d .git ; then						\
+		git ls-files | grep -E -v 'libfdt|libc|docs|\.rst' |	\
+		while read GIT_FILE ;					\
+		do ${CHECKPATCH} ${CHECKCODE_ARGS} -f $$GIT_FILE ;	\
+		done ;							\
+	else								\
+		 find . -type f -not -iwholename "*.git*"		\
+		 -not -iwholename "*build*"				\
+		 -not -iwholename "*libfdt*"				\
+		 -not -iwholename "*libc*"				\
+		 -not -iwholename "*docs*"				\
+		 -not -iwholename "*.rst"				\
+		 -exec ${CHECKPATCH} ${CHECKCODE_ARGS} -f {} \; ;	\
+	fi
+
+checkpatch:		locate-checkpatch
+	@echo "  CHECKING STYLE"
+	@if test -n "${CHECKPATCH_OPTS}"; then				\
+		echo "    with ${CHECKPATCH_OPTS} option(s)";		\
+	fi
+	${Q}COMMON_COMMIT=$$(git merge-base HEAD ${BASE_COMMIT});	\
+	for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do		\
+		printf "\n[*] Checking style of '$$commit'\n\n";	\
+		git log --format=email "$$commit~..$$commit"		\
+			-- ${CHECK_PATHS} |				\
+			${CHECKPATCH} ${CHECKPATCH_OPTS} - || true;	\
+		git diff --format=email "$$commit~..$$commit"		\
+			-- ${CHECK_PATHS} |				\
+			${CHECKPATCH}  ${CHECKPATCH_OPTS} - || true;	\
+	done
+
+certtool: ${CRTTOOL}
+
+.PHONY: ${CRTTOOL}
+${CRTTOOL}:
+	${Q}${MAKE} PLAT=${PLAT} USE_TBBR_DEFS=${USE_TBBR_DEFS} --no-print-directory -C ${CRTTOOLPATH}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+ifneq (${GENERATE_COT},0)
+certificates: ${CRT_DEPS} ${CRTTOOL}
+	${Q}${CRTTOOL} ${CRT_ARGS}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@echo "Certificates can be found in ${BUILD_PLAT}"
+	@${ECHO_BLANK_LINE}
+endif
+
+${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL}
+	${Q}${FIPTOOL} create ${FIP_ARGS} $@
+	${Q}${FIPTOOL} info $@
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+ifneq (${GENERATE_COT},0)
+fwu_certificates: ${FWU_CRT_DEPS} ${CRTTOOL}
+	${Q}${CRTTOOL} ${FWU_CRT_ARGS}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@echo "FWU certificates can be found in ${BUILD_PLAT}"
+	@${ECHO_BLANK_LINE}
+endif
+
+${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} ${FIPTOOL}
+	${Q}${FIPTOOL} create ${FWU_FIP_ARGS} $@
+	${Q}${FIPTOOL} info $@
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+fiptool: ${FIPTOOL}
+fip: ${BUILD_PLAT}/${FIP_NAME}
+fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME}
+
+.PHONY: ${FIPTOOL}
+${FIPTOOL}:
+	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${FIPTOOLPATH}
+
+sptool: ${SPTOOL}
+.PHONY: ${SPTOOL}
+${SPTOOL}:
+	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${SPTOOLPATH}
+
+.PHONY: libraries
+romlib.bin: libraries
+	${Q}${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES='${INCLUDES}' DEFINES='${DEFINES}' --no-print-directory -C ${ROMLIBPATH} all
+
+cscope:
+	@echo "  CSCOPE"
+	${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
+	${Q}cscope -b -q -k
+
+help:
+	@echo "usage: ${MAKE} [PLAT=<platform>] [OPTIONS] [TARGET]"
+	@echo ""
+	@echo "PLAT is used to specify which platform you wish to build."
+	@echo "If no platform is specified, PLAT defaults to: ${DEFAULT_PLAT}"
+	@echo ""
+	@echo "platform = ${PLATFORM_LIST}"
+	@echo ""
+	@echo "Please refer to the User Guide for a list of all supported options."
+	@echo "Note that the build system doesn't track dependencies for build "
+	@echo "options. Therefore, if any of the build options are changed "
+	@echo "from a previous build, a clean build must be performed."
+	@echo ""
+	@echo "Supported Targets:"
+	@echo "  all            Build all individual bootloader binaries"
+	@echo "  bl1            Build the BL1 binary"
+	@echo "  bl2            Build the BL2 binary"
+	@echo "  bl2u           Build the BL2U binary"
+	@echo "  bl31           Build the BL31 binary"
+	@echo "  bl32           Build the BL32 binary. If ARCH=aarch32, then "
+	@echo "                 this builds secure payload specified by AARCH32_SP"
+	@echo "  certificates   Build the certificates (requires 'GENERATE_COT=1')"
+	@echo "  fip            Build the Firmware Image Package (FIP)"
+	@echo "  fwu_fip        Build the FWU Firmware Image Package (FIP)"
+	@echo "  checkcodebase  Check the coding style of the entire source tree"
+	@echo "  checkpatch     Check the coding style on changes in the current"
+	@echo "                 branch against BASE_COMMIT (default origin/master)"
+	@echo "  clean          Clean the build for the selected platform"
+	@echo "  cscope         Generate cscope index"
+	@echo "  distclean      Remove all build artifacts for all platforms"
+	@echo "  certtool       Build the Certificate generation tool"
+	@echo "  fiptool        Build the Firmware Image Package (FIP) creation tool"
+	@echo "  sptool         Build the Secure Partition Package creation tool"
+	@echo "  dtbs           Build the Device Tree Blobs (if required for the platform)"
+	@echo ""
+	@echo "Note: most build targets require PLAT to be set to a specific platform."
+	@echo ""
+	@echo "example: build all targets for the FVP platform:"
+	@echo "  CROSS_COMPILE=aarch64-none-elf- make PLAT=fvp all"
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/bl1/aarch32/bl1_arch_setup.c b/bl1/aarch32/bl1_arch_setup.c
new file mode 100644
index 0000000..ce04aaa
--- /dev/null
+++ b/bl1/aarch32/bl1_arch_setup.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../bl1_private.h"
+
+/*******************************************************************************
+ * TODO: Function that does the first bit of architectural setup.
+ ******************************************************************************/
+void bl1_arch_setup(void)
+{
+
+}
diff --git a/bl1/aarch32/bl1_context_mgmt.c b/bl1/aarch32/bl1_context_mgmt.c
new file mode 100644
index 0000000..b5a6a34
--- /dev/null
+++ b/bl1/aarch32/bl1_context_mgmt.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+#include "../bl1_private.h"
+
+/*
+ * Following arrays will be used for context management.
+ * There are 2 instances, for the Secure and Non-Secure contexts.
+ */
+static cpu_context_t bl1_cpu_context[2];
+static smc_ctx_t bl1_smc_context[2];
+
+/* Following contains the next cpu context pointer. */
+static void *bl1_next_cpu_context_ptr;
+
+/* Following contains the next smc context pointer. */
+static void *bl1_next_smc_context_ptr;
+
+/* Following functions are used for SMC context handling */
+void *smc_get_ctx(unsigned int security_state)
+{
+	assert(sec_state_is_valid(security_state));
+	return &bl1_smc_context[security_state];
+}
+
+void smc_set_next_ctx(unsigned int security_state)
+{
+	assert(sec_state_is_valid(security_state));
+	bl1_next_smc_context_ptr = &bl1_smc_context[security_state];
+}
+
+void *smc_get_next_ctx(void)
+{
+	return bl1_next_smc_context_ptr;
+}
+
+/* Following functions are used for CPU context handling */
+void *cm_get_context(uint32_t security_state)
+{
+	assert(sec_state_is_valid(security_state));
+	return &bl1_cpu_context[security_state];
+}
+
+void cm_set_next_context(void *cpu_context)
+{
+	assert(cpu_context);
+	bl1_next_cpu_context_ptr = cpu_context;
+}
+
+void *cm_get_next_context(void)
+{
+	return bl1_next_cpu_context_ptr;
+}
+
+/*******************************************************************************
+ * Following function copies GP regs r0-r4, lr and spsr,
+ * from the CPU context to the SMC context structures.
+ ******************************************************************************/
+static void copy_cpu_ctx_to_smc_ctx(const regs_t *cpu_reg_ctx,
+		smc_ctx_t *next_smc_ctx)
+{
+	next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0);
+	next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1);
+	next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2);
+	next_smc_ctx->r3 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R3);
+	next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR);
+	next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR);
+	next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR);
+}
+
+/*******************************************************************************
+ * Following function flushes the SMC & CPU context pointer and its data.
+ ******************************************************************************/
+static void flush_smc_and_cpu_ctx(void)
+{
+	flush_dcache_range((uintptr_t)&bl1_next_smc_context_ptr,
+		sizeof(bl1_next_smc_context_ptr));
+	flush_dcache_range((uintptr_t)bl1_next_smc_context_ptr,
+		sizeof(smc_ctx_t));
+
+	flush_dcache_range((uintptr_t)&bl1_next_cpu_context_ptr,
+		sizeof(bl1_next_cpu_context_ptr));
+	flush_dcache_range((uintptr_t)bl1_next_cpu_context_ptr,
+		sizeof(cpu_context_t));
+}
+
+/*******************************************************************************
+ * This function prepares the context for Secure/Normal world images.
+ * Normal world images are transitioned to HYP(if supported) else SVC.
+ ******************************************************************************/
+void bl1_prepare_next_image(unsigned int image_id)
+{
+	unsigned int security_state, mode = MODE32_svc;
+	image_desc_t *image_desc;
+	entry_point_info_t *next_bl_ep;
+
+	/* Get the image descriptor. */
+	image_desc = bl1_plat_get_image_desc(image_id);
+	assert(image_desc);
+
+	/* Get the entry point info. */
+	next_bl_ep = &image_desc->ep_info;
+
+	/* Get the image security state. */
+	security_state = GET_SECURITY_STATE(next_bl_ep->h.attr);
+
+	/* Prepare the SPSR for the next BL image. */
+	if ((security_state != SECURE) && (GET_VIRT_EXT(read_id_pfr1()))) {
+		mode = MODE32_hyp;
+	}
+
+	next_bl_ep->spsr = SPSR_MODE32(mode, SPSR_T_ARM,
+				SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+
+	/* Allow platform to make change */
+	bl1_plat_set_ep_info(image_id, next_bl_ep);
+
+	/* Prepare the cpu context for the next BL image. */
+	cm_init_my_context(next_bl_ep);
+	cm_prepare_el3_exit(security_state);
+	cm_set_next_context(cm_get_context(security_state));
+
+	/* Prepare the smc context for the next BL image. */
+	smc_set_next_ctx(security_state);
+	copy_cpu_ctx_to_smc_ctx(get_regs_ctx(cm_get_next_context()),
+		smc_get_next_ctx());
+
+	/*
+	 * If the next image is non-secure, then we need to program the banked
+	 * non secure sctlr. This is not required when the next image is secure
+	 * because in AArch32, we expect the secure world to have the same
+	 * SCTLR settings.
+	 */
+	if (security_state == NON_SECURE) {
+		cpu_context_t *ctx = cm_get_context(security_state);
+		u_register_t ns_sctlr;
+
+		/* Temporarily set the NS bit to access NS SCTLR */
+		write_scr(read_scr() | SCR_NS_BIT);
+		isb();
+
+		ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
+		write_sctlr(ns_sctlr);
+		isb();
+
+		write_scr(read_scr() & ~SCR_NS_BIT);
+		isb();
+	}
+
+	/*
+	 * Flush the SMC & CPU context and the (next)pointers,
+	 * to access them after caches are disabled.
+	 */
+	flush_smc_and_cpu_ctx();
+
+	/* Indicate that image is in execution state. */
+	image_desc->state = IMAGE_STATE_EXECUTED;
+
+	print_entry_point_info(next_bl_ep);
+}
diff --git a/bl1/aarch32/bl1_entrypoint.S b/bl1/aarch32/bl1_entrypoint.S
new file mode 100644
index 0000000..6a15566
--- /dev/null
+++ b/bl1/aarch32/bl1_entrypoint.S
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <context.h>
+#include <el3_common_macros.S>
+#include <smccc_helpers.h>
+#include <smccc_macros.S>
+
+	.globl	bl1_vector_table
+	.globl	bl1_entrypoint
+
+	/* -----------------------------------------------------
+	 * Setup the vector table to support SVC & MON mode.
+	 * -----------------------------------------------------
+	 */
+vector_base bl1_vector_table
+	b	bl1_entrypoint
+	b	report_exception	/* Undef */
+	b	bl1_aarch32_smc_handler	/* SMC call */
+	b	report_exception	/* Prefetch abort */
+	b	report_exception	/* Data abort */
+	b	report_exception	/* Reserved */
+	b	report_exception	/* IRQ */
+	b	report_exception	/* FIQ */
+
+	/* -----------------------------------------------------
+	 * bl1_entrypoint() is the entry point into the trusted
+	 * firmware code when a cpu is released from warm or
+	 * cold reset.
+	 * -----------------------------------------------------
+	 */
+
+func bl1_entrypoint
+/* ---------------------------------------------------------------------
+* If the reset address is programmable then bl1_entrypoint() is
+* executed only on the cold boot path. Therefore, we can skip the warm
+* boot mailbox mechanism.
+* ---------------------------------------------------------------------
+*/
+	el3_entrypoint_common					\
+		_init_sctlr=1					\
+		_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS	\
+		_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU	\
+		_init_memory=1					\
+		_init_c_runtime=1				\
+		_exception_vectors=bl1_vector_table
+
+	/* -----------------------------------------------------
+	 * Perform BL1 setup
+	 * -----------------------------------------------------
+	 */
+	bl	bl1_setup
+
+	/* -----------------------------------------------------
+	 * Jump to main function.
+	 * -----------------------------------------------------
+	 */
+	bl	bl1_main
+
+	/* -----------------------------------------------------
+	 * Jump to next image.
+	 * -----------------------------------------------------
+	 */
+
+	/*
+	 * Get the smc_context for next BL image,
+	 * program the gp/system registers and save it in `r4`.
+	 */
+	bl	smc_get_next_ctx
+	mov	r4, r0
+
+	/* Only turn-off MMU if going to secure world */
+	ldr	r5, [r4, #SMC_CTX_SCR]
+	tst	r5, #SCR_NS_BIT
+	bne	skip_mmu_off
+
+	/*
+	 * MMU needs to be disabled because both BL1 and BL2/BL2U execute
+	 * in PL1, and therefore share the same address space.
+	 * BL2/BL2U will initialize the address space according to its
+	 * own requirement.
+	 */
+	bl	disable_mmu_icache_secure
+	stcopr	r0, TLBIALL
+	dsb	sy
+	isb
+
+skip_mmu_off:
+	/* Restore smc_context from `r4` and exit secure monitor mode. */
+	mov	r0, r4
+	monitor_exit
+endfunc bl1_entrypoint
diff --git a/bl1/aarch32/bl1_exceptions.S b/bl1/aarch32/bl1_exceptions.S
new file mode 100644
index 0000000..f2af9ab
--- /dev/null
+++ b/bl1/aarch32/bl1_exceptions.S
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <smccc_helpers.h>
+#include <smccc_macros.S>
+
+	.globl	bl1_aarch32_smc_handler
+
+
+func bl1_aarch32_smc_handler
+	/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
+	str	lr, [sp, #SMC_CTX_LR_MON]
+
+	/* ------------------------------------------------
+	 * SMC in BL1 is handled assuming that the MMU is
+	 * turned off by BL2.
+	 * ------------------------------------------------
+	 */
+
+	/* ----------------------------------------------
+	 * Detect if this is a RUN_IMAGE or other SMC.
+	 * ----------------------------------------------
+	 */
+	mov	lr, #BL1_SMC_RUN_IMAGE
+	cmp	lr, r0
+	bne	smc_handler
+
+	/* ------------------------------------------------
+	 * Make sure only Secure world reaches here.
+	 * ------------------------------------------------
+	 */
+	ldcopr  r8, SCR
+	tst	r8, #SCR_NS_BIT
+	blne	report_exception
+
+	/* ---------------------------------------------------------------------
+	 * Pass control to next secure image.
+	 * Here it expects r1 to contain the address of a entry_point_info_t
+	 * structure describing the BL entrypoint.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	r8, r1
+	mov	r0, r1
+	bl	bl1_print_next_bl_ep_info
+
+#if SPIN_ON_BL1_EXIT
+	bl	print_debug_loop_message
+debug_loop:
+	b	debug_loop
+#endif
+
+	mov	r0, r8
+	bl	bl1_plat_prepare_exit
+
+	stcopr	r0, TLBIALL
+	dsb	sy
+	isb
+
+	/*
+	 * Extract PC and SPSR based on struct `entry_point_info_t`
+	 * and load it in LR and SPSR registers respectively.
+	 */
+	ldr	lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
+	ldr	r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
+	msr	spsr_xc, r1
+
+	/* Some BL32 stages expect lr_svc to provide the BL33 entry address */
+	cps	#MODE32_svc
+	ldr	lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET]
+	cps	#MODE32_mon
+
+	add	r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
+	ldm	r8, {r0, r1, r2, r3}
+	eret
+endfunc bl1_aarch32_smc_handler
+
+	/* -----------------------------------------------------
+	 * Save Secure/Normal world context and jump to
+	 * BL1 SMC handler.
+	 * -----------------------------------------------------
+	 */
+func smc_handler
+	/* -----------------------------------------------------
+	 * Save the GP registers.
+	 * -----------------------------------------------------
+	 */
+	smccc_save_gp_mode_regs
+
+	/*
+	 * `sp` still points to `smc_ctx_t`. Save it to a register
+	 * and restore the C runtime stack pointer to `sp`.
+	 */
+	mov	r6, sp
+	ldr	sp, [r6, #SMC_CTX_SP_MON]
+
+	ldr	r0, [r6, #SMC_CTX_SCR]
+	and	r7, r0, #SCR_NS_BIT		/* flags */
+
+	/* Switch to Secure Mode */
+	bic	r0, #SCR_NS_BIT
+	stcopr	r0, SCR
+	isb
+
+	/* If caller is from Secure world then turn on the MMU */
+	tst	r7, #SCR_NS_BIT
+	bne	skip_mmu_on
+
+	/* Turn on the MMU */
+	mov	r0, #DISABLE_DCACHE
+	bl	enable_mmu_svc_mon
+
+	/* Enable the data cache. */
+	ldcopr	r9, SCTLR
+	orr	r9, r9, #SCTLR_C_BIT
+	stcopr	r9, SCTLR
+	isb
+
+skip_mmu_on:
+	/* Prepare arguments for BL1 SMC wrapper. */
+	ldr	r0, [r6, #SMC_CTX_GPREG_R0]	/* smc_fid */
+	mov	r1, #0				/* cookie */
+	mov	r2, r6				/* handle */
+	mov	r3, r7				/* flags */
+	bl	bl1_smc_wrapper
+
+	/* Get the smc_context for next BL image */
+	bl	smc_get_next_ctx
+	mov	r4, r0
+
+	/* Only turn-off MMU if going to secure world */
+	ldr	r5, [r4, #SMC_CTX_SCR]
+	tst	r5, #SCR_NS_BIT
+	bne	skip_mmu_off
+
+	/* Disable the MMU */
+	bl	disable_mmu_icache_secure
+	stcopr	r0, TLBIALL
+	dsb	sy
+	isb
+
+skip_mmu_off:
+	/* -----------------------------------------------------
+	 * Do the transition to next BL image.
+	 * -----------------------------------------------------
+	 */
+	mov	r0, r4
+	monitor_exit
+endfunc smc_handler
diff --git a/bl1/aarch64/bl1_arch_setup.c b/bl1/aarch64/bl1_arch_setup.c
new file mode 100644
index 0000000..624bd80
--- /dev/null
+++ b/bl1/aarch64/bl1_arch_setup.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include "../bl1_private.h"
+
+/*******************************************************************************
+ * Function that does the first bit of architectural setup that affects
+ * execution in the non-secure address space.
+ ******************************************************************************/
+void bl1_arch_setup(void)
+{
+	/* Set the next EL to be AArch64 */
+	write_scr_el3(read_scr_el3() | SCR_RW_BIT);
+}
+
+/*******************************************************************************
+ * Set the Secure EL1 required architectural state
+ ******************************************************************************/
+void bl1_arch_next_el_setup(void)
+{
+	unsigned long next_sctlr;
+
+	/* Use the same endianness than the current BL */
+	next_sctlr = (read_sctlr_el3() & SCTLR_EE_BIT);
+
+	/* Set SCTLR Secure EL1 */
+	next_sctlr |= SCTLR_EL1_RES1;
+
+	write_sctlr_el1(next_sctlr);
+}
diff --git a/bl1/aarch64/bl1_context_mgmt.c b/bl1/aarch64/bl1_context_mgmt.c
new file mode 100644
index 0000000..8be8830
--- /dev/null
+++ b/bl1/aarch64/bl1_context_mgmt.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#include "../bl1_private.h"
+
+/*
+ * Following array will be used for context management.
+ * There are 2 instances, for the Secure and Non-Secure contexts.
+ */
+static cpu_context_t bl1_cpu_context[2];
+
+/* Following contains the cpu context pointers. */
+static void *bl1_cpu_context_ptr[2];
+
+
+void *cm_get_context(uint32_t security_state)
+{
+	assert(sec_state_is_valid(security_state));
+	return bl1_cpu_context_ptr[security_state];
+}
+
+void cm_set_context(void *context, uint32_t security_state)
+{
+	assert(sec_state_is_valid(security_state));
+	bl1_cpu_context_ptr[security_state] = context;
+}
+
+/*******************************************************************************
+ * This function prepares the context for Secure/Normal world images.
+ * Normal world images are transitioned to EL2(if supported) else EL1.
+ ******************************************************************************/
+void bl1_prepare_next_image(unsigned int image_id)
+{
+	unsigned int security_state, mode = MODE_EL1;
+	image_desc_t *image_desc;
+	entry_point_info_t *next_bl_ep;
+
+#if CTX_INCLUDE_AARCH32_REGS
+	/*
+	 * Ensure that the build flag to save AArch32 system registers in CPU
+	 * context is not set for AArch64-only platforms.
+	 */
+	if (el_implemented(1) == EL_IMPL_A64ONLY) {
+		ERROR("EL1 supports AArch64-only. Please set build flag "
+				"CTX_INCLUDE_AARCH32_REGS = 0\n");
+		panic();
+	}
+#endif
+
+	/* Get the image descriptor. */
+	image_desc = bl1_plat_get_image_desc(image_id);
+	assert(image_desc);
+
+	/* Get the entry point info. */
+	next_bl_ep = &image_desc->ep_info;
+
+	/* Get the image security state. */
+	security_state = GET_SECURITY_STATE(next_bl_ep->h.attr);
+
+	/* Setup the Secure/Non-Secure context if not done already. */
+	if (!cm_get_context(security_state))
+		cm_set_context(&bl1_cpu_context[security_state], security_state);
+
+	/* Prepare the SPSR for the next BL image. */
+	if ((security_state != SECURE) && (el_implemented(2) != EL_IMPL_NONE)) {
+		mode = MODE_EL2;
+	}
+
+	next_bl_ep->spsr = SPSR_64(mode, MODE_SP_ELX,
+		DISABLE_ALL_EXCEPTIONS);
+
+	/* Allow platform to make change */
+	bl1_plat_set_ep_info(image_id, next_bl_ep);
+
+	/* Prepare the context for the next BL image. */
+	cm_init_my_context(next_bl_ep);
+	cm_prepare_el3_exit(security_state);
+
+	/* Indicate that image is in execution state. */
+	image_desc->state = IMAGE_STATE_EXECUTED;
+
+	print_entry_point_info(next_bl_ep);
+}
diff --git a/bl1/aarch64/bl1_entrypoint.S b/bl1/aarch64/bl1_entrypoint.S
new file mode 100644
index 0000000..0f8d5aa
--- /dev/null
+++ b/bl1/aarch64/bl1_entrypoint.S
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <el3_common_macros.S>
+
+	.globl	bl1_entrypoint
+
+
+	/* -----------------------------------------------------
+	 * bl1_entrypoint() is the entry point into the trusted
+	 * firmware code when a cpu is released from warm or
+	 * cold reset.
+	 * -----------------------------------------------------
+	 */
+
+func bl1_entrypoint
+	/* ---------------------------------------------------------------------
+	 * If the reset address is programmable then bl1_entrypoint() is
+	 * executed only on the cold boot path. Therefore, we can skip the warm
+	 * boot mailbox mechanism.
+	 * ---------------------------------------------------------------------
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=1					\
+		_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS	\
+		_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU	\
+		_init_memory=1					\
+		_init_c_runtime=1				\
+		_exception_vectors=bl1_exceptions
+
+	/* --------------------------------------------------------------------
+	 * Perform BL1 setup
+	 * --------------------------------------------------------------------
+	 */
+	bl	bl1_setup
+
+	/* --------------------------------------------------------------------
+	 * Enable pointer authentication
+	 * --------------------------------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el3
+	orr	x0, x0, #SCTLR_EnIA_BIT
+	msr	sctlr_el3, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	/* --------------------------------------------------------------------
+	 * Initialize platform and jump to our c-entry point
+	 * for this type of reset.
+	 * --------------------------------------------------------------------
+	 */
+	bl	bl1_main
+
+	/* --------------------------------------------------------------------
+	 * Disable pointer authentication before jumping to BL31 or that will
+	 * cause an authentication failure during the early platform init.
+	 * --------------------------------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el3
+	bic	x0, x0, #SCTLR_EnIA_BIT
+	msr	sctlr_el3, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	/* --------------------------------------------------
+	 * Do the transition to next boot image.
+	 * --------------------------------------------------
+	 */
+	b	el3_exit
+endfunc bl1_entrypoint
diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S
new file mode 100644
index 0000000..19a0ac2
--- /dev/null
+++ b/bl1/aarch64/bl1_exceptions.S
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by BL1.
+ * -----------------------------------------------------------------------------
+ */
+	.globl	bl1_exceptions
+
+vector_base bl1_exceptions
+
+	/* -----------------------------------------------------
+	 * Current EL with SP0 : 0x0 - 0x200
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSP0
+	mov	x0, #SYNC_EXCEPTION_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionSP0
+
+vector_entry IrqSP0
+	mov	x0, #IRQ_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqSP0
+
+vector_entry FiqSP0
+	mov	x0, #FIQ_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqSP0
+
+vector_entry SErrorSP0
+	mov	x0, #SERROR_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorSP0
+
+	/* -----------------------------------------------------
+	 * Current EL with SPx: 0x200 - 0x400
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSPx
+	mov	x0, #SYNC_EXCEPTION_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionSPx
+
+vector_entry IrqSPx
+	mov	x0, #IRQ_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqSPx
+
+vector_entry FiqSPx
+	mov	x0, #FIQ_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqSPx
+
+vector_entry SErrorSPx
+	mov	x0, #SERROR_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorSPx
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA64
+	/* Enable the SError interrupt */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	/* Expect only SMC exceptions */
+	mrs	x30, esr_el3
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+	cmp	x30, #EC_AARCH64_SMC
+	b.ne	unexpected_sync_exception
+
+	b	smc_handler64
+end_vector_entry SynchronousExceptionA64
+
+vector_entry IrqA64
+	mov	x0, #IRQ_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqA64
+
+vector_entry FiqA64
+	mov	x0, #FIQ_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqA64
+
+vector_entry SErrorA64
+	mov	x0, #SERROR_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorA64
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA32
+	mov	x0, #SYNC_EXCEPTION_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionA32
+
+vector_entry IrqA32
+	mov	x0, #IRQ_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqA32
+
+vector_entry FiqA32
+	mov	x0, #FIQ_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqA32
+
+vector_entry SErrorA32
+	mov	x0, #SERROR_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorA32
+
+
+func smc_handler64
+
+	/* ----------------------------------------------
+	 * Detect if this is a RUN_IMAGE or other SMC.
+	 * ----------------------------------------------
+	 */
+	mov	x30, #BL1_SMC_RUN_IMAGE
+	cmp	x30, x0
+	b.ne	smc_handler
+
+	/* ------------------------------------------------
+	 * Make sure only Secure world reaches here.
+	 * ------------------------------------------------
+	 */
+	mrs	x30, scr_el3
+	tst	x30, #SCR_NS_BIT
+	b.ne	unexpected_sync_exception
+
+	/* ----------------------------------------------
+	 * Handling RUN_IMAGE SMC. First switch back to
+	 * SP_EL0 for the C runtime stack.
+	 * ----------------------------------------------
+	 */
+	ldr	x30, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+	msr	spsel, #0
+	mov	sp, x30
+
+	/* ---------------------------------------------------------------------
+	 * Pass EL3 control to next BL image.
+	 * Here it expects X1 with the address of a entry_point_info_t
+	 * structure describing the next BL image entrypoint.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	x20, x1
+
+	mov	x0, x20
+	bl	bl1_print_next_bl_ep_info
+
+	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
+	msr	elr_el3, x0
+	msr	spsr_el3, x1
+	ubfx	x0, x1, #MODE_EL_SHIFT, #2
+	cmp	x0, #MODE_EL3
+	b.ne	unexpected_sync_exception
+
+	bl	disable_mmu_icache_el3
+	tlbi	alle3
+	dsb	ish /* ERET implies ISB, so it is not needed here */
+
+#if SPIN_ON_BL1_EXIT
+	bl	print_debug_loop_message
+debug_loop:
+	b	debug_loop
+#endif
+
+	mov	x0, x20
+	bl	bl1_plat_prepare_exit
+
+	ldp	x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
+	ldp	x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
+	ldp	x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
+	ldp	x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
+	eret
+endfunc smc_handler64
+
+unexpected_sync_exception:
+	mov	x0, #SYNC_EXCEPTION_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+
+	/* -----------------------------------------------------
+	 * Save Secure/Normal world context and jump to
+	 * BL1 SMC handler.
+	 * -----------------------------------------------------
+	 */
+smc_handler:
+	/* -----------------------------------------------------
+	 * Save the GP registers x0-x29.
+	 * TODO: Revisit to store only SMCCC specified registers.
+	 * -----------------------------------------------------
+	 */
+	bl	save_gp_registers
+
+	/* -----------------------------------------------------
+	 * Populate the parameters for the SMC handler. We
+	 * already have x0-x4 in place. x5 will point to a
+	 * cookie (not used now). x6 will point to the context
+	 * structure (SP_EL3) and x7 will contain flags we need
+	 * to pass to the handler.
+	 * -----------------------------------------------------
+	 */
+	mov	x5, xzr
+	mov	x6, sp
+
+	/* -----------------------------------------------------
+	 * Restore the saved C runtime stack value which will
+	 * become the new SP_EL0 i.e. EL3 runtime stack. It was
+	 * saved in the 'cpu_context' structure prior to the last
+	 * ERET from EL3.
+	 * -----------------------------------------------------
+	 */
+	ldr	x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+
+	/* ---------------------------------------------
+	 * Switch back to SP_EL0 for the C runtime stack.
+	 * ---------------------------------------------
+	 */
+	msr	spsel, #0
+	mov	sp, x12
+
+	/* -----------------------------------------------------
+	 * Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there
+	 * is a world switch during SMC handling.
+	 * -----------------------------------------------------
+	 */
+	mrs	x16, spsr_el3
+	mrs	x17, elr_el3
+	mrs	x18, scr_el3
+	stp	x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+	str	x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+
+	/* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
+	bfi	x7, x18, #0, #1
+
+	/* -----------------------------------------------------
+	 * Go to BL1 SMC handler.
+	 * -----------------------------------------------------
+	 */
+	bl	bl1_smc_handler
+
+	/* -----------------------------------------------------
+	 * Do the transition to next BL image.
+	 * -----------------------------------------------------
+	 */
+	b	el3_exit
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
new file mode 100644
index 0000000..c4f6b99
--- /dev/null
+++ b/bl1/bl1.ld.S
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl1_entrypoint)
+
+MEMORY {
+    ROM (rx): ORIGIN = BL1_RO_BASE, LENGTH = BL1_RO_LIMIT - BL1_RO_BASE
+    RAM (rwx): ORIGIN = BL1_RW_BASE, LENGTH = BL1_RW_LIMIT - BL1_RW_BASE
+}
+
+SECTIONS
+{
+    . = BL1_RO_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL1_RO_BASE address is not aligned on a page boundary.")
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl1_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+     } >ROM
+
+     /* .ARM.extab and .ARM.exidx are only added because Clang need them */
+     .ARM.extab . : {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+     } >ROM
+
+     .ARM.exidx . : {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+     } >ROM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /*
+         * No need to pad out the .rodata section to a page boundary. Next is
+         * the .data section, which can mapped in ROM with the same memory
+         * attributes as the .rodata section.
+         */
+        __RODATA_END__ = .;
+    } >ROM
+#else
+    ro . : {
+        __RO_START__ = .;
+        *bl1_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        *(.vectors)
+        __RO_END__ = .;
+    } >ROM
+#endif
+
+    ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
+           "cpu_ops not defined for this platform.")
+
+    . = BL1_RW_BASE;
+    ASSERT(BL1_RW_BASE == ALIGN(PAGE_SIZE),
+           "BL1_RW_BASE address is not aligned on a page boundary.")
+
+    /*
+     * The .data section gets copied from ROM to RAM at runtime.
+     * Its LMA should be 16-byte aligned to allow efficient copying of 16-bytes
+     * aligned regions in it.
+     * Its VMA must be page-aligned as it marks the first read/write page.
+     *
+     * It must be placed at a lower address than the stacks if the stack
+     * protector is enabled. Alternatively, the .data.stack_protector_canary
+     * section can be placed independently of the main .data section.
+     */
+    .data . : ALIGN(16) {
+        __DATA_RAM_START__ = .;
+        *(.data*)
+        __DATA_RAM_END__ = .;
+    } >RAM AT>ROM
+
+    stacks . (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss : ALIGN(16) {
+        __BSS_START__ = .;
+        *(.bss*)
+        *(COMMON)
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+#endif
+
+    __BL1_RAM_START__ = ADDR(.data);
+    __BL1_RAM_END__ = .;
+
+    __DATA_ROM_START__ = LOADADDR(.data);
+    __DATA_SIZE__ = SIZEOF(.data);
+
+    /*
+     * The .data section is the last PROGBITS section so its end marks the end
+     * of BL1's actual content in Trusted ROM.
+     */
+    __BL1_ROM_END__ =  __DATA_ROM_START__ + __DATA_SIZE__;
+    ASSERT(__BL1_ROM_END__ <= BL1_RO_LIMIT,
+           "BL1's ROM content has exceeded its limit.")
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+
+#if USE_COHERENT_MEM
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+    ASSERT(. <= BL1_RW_LIMIT, "BL1's RW section has exceeded its limit.")
+}
diff --git a/bl1/bl1.mk b/bl1/bl1.mk
new file mode 100644
index 0000000..b839990
--- /dev/null
+++ b/bl1/bl1.mk
@@ -0,0 +1,28 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL1_SOURCES		+=	bl1/bl1_main.c				\
+				bl1/${ARCH}/bl1_arch_setup.c		\
+				bl1/${ARCH}/bl1_context_mgmt.c		\
+				bl1/${ARCH}/bl1_entrypoint.S		\
+				bl1/${ARCH}/bl1_exceptions.S		\
+				lib/cpus/${ARCH}/cpu_helpers.S		\
+				lib/cpus/errata_report.c		\
+				lib/el3_runtime/${ARCH}/context_mgmt.c	\
+				plat/common/plat_bl1_common.c		\
+				plat/common/${ARCH}/platform_up_stack.S \
+				${MBEDTLS_SOURCES}
+
+ifeq (${ARCH},aarch64)
+BL1_SOURCES		+=	lib/cpus/aarch64/dsu_helpers.S		\
+				lib/el3_runtime/aarch64/context.S
+endif
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+BL1_SOURCES		+=	bl1/bl1_fwu.c
+endif
+
+BL1_LINKERFILE		:=	bl1/bl1.ld.S
diff --git a/bl1/bl1_fwu.c b/bl1/bl1_fwu.c
new file mode 100644
index 0000000..d222b9c
--- /dev/null
+++ b/bl1/bl1_fwu.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/auth/auth_mod.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+#include "bl1_private.h"
+
+/*
+ * Function declarations.
+ */
+static int bl1_fwu_image_copy(unsigned int image_id,
+			uintptr_t image_src,
+			unsigned int block_size,
+			unsigned int image_size,
+			unsigned int flags);
+static int bl1_fwu_image_auth(unsigned int image_id,
+			uintptr_t image_src,
+			unsigned int image_size,
+			unsigned int flags);
+static int bl1_fwu_image_execute(unsigned int image_id,
+			void **handle,
+			unsigned int flags);
+static register_t bl1_fwu_image_resume(register_t image_param,
+			void **handle,
+			unsigned int flags);
+static int bl1_fwu_sec_image_done(void **handle,
+			unsigned int flags);
+static int bl1_fwu_image_reset(unsigned int image_id,
+			unsigned int flags);
+__dead2 static void bl1_fwu_done(void *client_cookie, void *reserved);
+
+/*
+ * This keeps track of last executed secure image id.
+ */
+static unsigned int sec_exec_image_id = INVALID_IMAGE_ID;
+
+/*******************************************************************************
+ * Top level handler for servicing FWU SMCs.
+ ******************************************************************************/
+register_t bl1_fwu_smc_handler(unsigned int smc_fid,
+			register_t x1,
+			register_t x2,
+			register_t x3,
+			register_t x4,
+			void *cookie,
+			void *handle,
+			unsigned int flags)
+{
+
+	switch (smc_fid) {
+	case FWU_SMC_IMAGE_COPY:
+		SMC_RET1(handle, bl1_fwu_image_copy(x1, x2, x3, x4, flags));
+
+	case FWU_SMC_IMAGE_AUTH:
+		SMC_RET1(handle, bl1_fwu_image_auth(x1, x2, x3, flags));
+
+	case FWU_SMC_IMAGE_EXECUTE:
+		SMC_RET1(handle, bl1_fwu_image_execute(x1, &handle, flags));
+
+	case FWU_SMC_IMAGE_RESUME:
+		SMC_RET1(handle, bl1_fwu_image_resume(x1, &handle, flags));
+
+	case FWU_SMC_SEC_IMAGE_DONE:
+		SMC_RET1(handle, bl1_fwu_sec_image_done(&handle, flags));
+
+	case FWU_SMC_IMAGE_RESET:
+		SMC_RET1(handle, bl1_fwu_image_reset(x1, flags));
+
+	case FWU_SMC_UPDATE_DONE:
+		bl1_fwu_done((void *)x1, NULL);
+
+	default:
+		assert(0); /* Unreachable */
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/*******************************************************************************
+ * Utility functions to keep track of the images that are loaded at any time.
+ ******************************************************************************/
+
+#ifdef PLAT_FWU_MAX_SIMULTANEOUS_IMAGES
+#define FWU_MAX_SIMULTANEOUS_IMAGES	PLAT_FWU_MAX_SIMULTANEOUS_IMAGES
+#else
+#define FWU_MAX_SIMULTANEOUS_IMAGES	10
+#endif
+
+static unsigned int bl1_fwu_loaded_ids[FWU_MAX_SIMULTANEOUS_IMAGES] = {
+	[0 ... FWU_MAX_SIMULTANEOUS_IMAGES-1] = INVALID_IMAGE_ID
+};
+
+/*
+ * Adds an image_id to the bl1_fwu_loaded_ids array.
+ * Returns 0 on success, 1 on error.
+ */
+static int bl1_fwu_add_loaded_id(unsigned int image_id)
+{
+	int i;
+
+	/* Check if the ID is already in the list */
+	for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+		if (bl1_fwu_loaded_ids[i] == image_id)
+			return 0;
+	}
+
+	/* Find an empty slot */
+	for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+		if (bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) {
+			bl1_fwu_loaded_ids[i] = image_id;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Removes an image_id from the bl1_fwu_loaded_ids array.
+ * Returns 0 on success, 1 on error.
+ */
+static int bl1_fwu_remove_loaded_id(unsigned int image_id)
+{
+	int i;
+
+	/* Find the ID */
+	for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+		if (bl1_fwu_loaded_ids[i] == image_id) {
+			bl1_fwu_loaded_ids[i] = INVALID_IMAGE_ID;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/*******************************************************************************
+ * This function checks if the specified image overlaps another image already
+ * loaded. It returns 0 if there is no overlap, a negative error code otherwise.
+ ******************************************************************************/
+static int bl1_fwu_image_check_overlaps(unsigned int image_id)
+{
+	const image_desc_t *image_desc, *checked_image_desc;
+	const image_info_t *info, *checked_info;
+
+	uintptr_t image_base, image_end;
+	uintptr_t checked_image_base, checked_image_end;
+
+	checked_image_desc = bl1_plat_get_image_desc(image_id);
+	checked_info = &checked_image_desc->image_info;
+
+	/* Image being checked mustn't be empty. */
+	assert(checked_info->image_size != 0);
+
+	checked_image_base = checked_info->image_base;
+	checked_image_end = checked_image_base + checked_info->image_size - 1;
+	/* No need to check for overflows, it's done in bl1_fwu_image_copy(). */
+
+	for (int i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+
+		/* Skip INVALID_IMAGE_IDs and don't check image against itself */
+		if ((bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) ||
+				(bl1_fwu_loaded_ids[i] == image_id))
+			continue;
+
+		image_desc = bl1_plat_get_image_desc(bl1_fwu_loaded_ids[i]);
+
+		/* Only check images that are loaded or being loaded. */
+		assert (image_desc && image_desc->state != IMAGE_STATE_RESET);
+
+		info = &image_desc->image_info;
+
+		/* There cannot be overlaps with an empty image. */
+		if (info->image_size == 0)
+			continue;
+
+		image_base = info->image_base;
+		image_end = image_base + info->image_size - 1;
+		/*
+		 * Overflows cannot happen. It is checked in
+		 * bl1_fwu_image_copy() when the image goes from RESET to
+		 * COPYING or COPIED.
+		 */
+		assert (image_end > image_base);
+
+		/* Check if there are overlaps. */
+		if (!(image_end < checked_image_base ||
+		    checked_image_end < image_base)) {
+			VERBOSE("Image with ID %d overlaps existing image with ID %d",
+				checked_image_desc->image_id, image_desc->image_id);
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function is responsible for copying secure images in AP Secure RAM.
+ ******************************************************************************/
+static int bl1_fwu_image_copy(unsigned int image_id,
+			uintptr_t image_src,
+			unsigned int block_size,
+			unsigned int image_size,
+			unsigned int flags)
+{
+	uintptr_t dest_addr;
+	unsigned int remaining;
+
+	/* Get the image descriptor. */
+	image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
+	if (!image_desc) {
+		WARN("BL1-FWU: Invalid image ID %u\n", image_id);
+		return -EPERM;
+	}
+
+	/*
+	 * The request must originate from a non-secure caller and target a
+	 * secure image. Any other scenario is invalid.
+	 */
+	if (GET_SECURITY_STATE(flags) == SECURE) {
+		WARN("BL1-FWU: Copy not allowed from secure world.\n");
+		return -EPERM;
+	}
+	if (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == NON_SECURE) {
+		WARN("BL1-FWU: Copy not allowed for non-secure images.\n");
+		return -EPERM;
+	}
+
+	/* Check whether the FWU state machine is in the correct state. */
+	if ((image_desc->state != IMAGE_STATE_RESET) &&
+	    (image_desc->state != IMAGE_STATE_COPYING)) {
+		WARN("BL1-FWU: Copy not allowed at this point of the FWU"
+			" process.\n");
+		return -EPERM;
+	}
+
+	if ((!image_src) || (!block_size) ||
+	    check_uptr_overflow(image_src, block_size - 1)) {
+		WARN("BL1-FWU: Copy not allowed due to invalid image source"
+			" or block size\n");
+		return -ENOMEM;
+	}
+
+	if (image_desc->state == IMAGE_STATE_COPYING) {
+		/*
+		 * There must have been at least 1 copy operation for this image
+		 * previously.
+		 */
+		assert(image_desc->copied_size != 0);
+		/*
+		 * The image size must have been recorded in the 1st copy
+		 * operation.
+		 */
+		image_size = image_desc->image_info.image_size;
+		assert(image_size != 0);
+		assert(image_desc->copied_size < image_size);
+
+		INFO("BL1-FWU: Continuing image copy in blocks\n");
+	} else { /* image_desc->state == IMAGE_STATE_RESET */
+		INFO("BL1-FWU: Initial call to copy an image\n");
+
+		/*
+		 * image_size is relevant only for the 1st copy request, it is
+		 * then ignored for subsequent calls for this image.
+		 */
+		if (!image_size) {
+			WARN("BL1-FWU: Copy not allowed due to invalid image"
+				" size\n");
+			return -ENOMEM;
+		}
+
+		/* Check that the image size to load is within limit */
+		if (image_size > image_desc->image_info.image_max_size) {
+			WARN("BL1-FWU: Image size out of bounds\n");
+			return -ENOMEM;
+		}
+
+		/* Save the given image size. */
+		image_desc->image_info.image_size = image_size;
+
+		/* Make sure the image doesn't overlap other images. */
+		if (bl1_fwu_image_check_overlaps(image_id)) {
+			image_desc->image_info.image_size = 0;
+			WARN("BL1-FWU: This image overlaps another one\n");
+			return -EPERM;
+		}
+
+		/*
+		 * copied_size must be explicitly initialized here because the
+		 * FWU code doesn't necessarily do it when it resets the state
+		 * machine.
+		 */
+		image_desc->copied_size = 0;
+	}
+
+	/*
+	 * If the given block size is more than the total image size
+	 * then clip the former to the latter.
+	 */
+	remaining = image_size - image_desc->copied_size;
+	if (block_size > remaining) {
+		WARN("BL1-FWU: Block size is too big, clipping it.\n");
+		block_size = remaining;
+	}
+
+	/* Make sure the source image is mapped in memory. */
+	if (bl1_plat_mem_check(image_src, block_size, flags)) {
+		WARN("BL1-FWU: Source image is not mapped.\n");
+		return -ENOMEM;
+	}
+
+	if (bl1_fwu_add_loaded_id(image_id)) {
+		WARN("BL1-FWU: Too many images loaded at the same time.\n");
+		return -ENOMEM;
+	}
+
+	/* Allow the platform to handle pre-image load before copying */
+	if (image_desc->state == IMAGE_STATE_RESET) {
+		if (bl1_plat_handle_pre_image_load(image_id) != 0) {
+			ERROR("BL1-FWU: Failure in pre-image load of image id %d\n",
+					image_id);
+			return -EPERM;
+		}
+	}
+
+	/* Everything looks sane. Go ahead and copy the block of data. */
+	dest_addr = image_desc->image_info.image_base + image_desc->copied_size;
+	memcpy((void *) dest_addr, (const void *) image_src, block_size);
+	flush_dcache_range(dest_addr, block_size);
+
+	image_desc->copied_size += block_size;
+	image_desc->state = (block_size == remaining) ?
+		IMAGE_STATE_COPIED : IMAGE_STATE_COPYING;
+
+	INFO("BL1-FWU: Copy operation successful.\n");
+	return 0;
+}
+
+/*******************************************************************************
+ * This function is responsible for authenticating Normal/Secure images.
+ ******************************************************************************/
+static int bl1_fwu_image_auth(unsigned int image_id,
+			uintptr_t image_src,
+			unsigned int image_size,
+			unsigned int flags)
+{
+	int result;
+	uintptr_t base_addr;
+	unsigned int total_size;
+
+	/* Get the image descriptor. */
+	image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
+	if (!image_desc)
+		return -EPERM;
+
+	if (GET_SECURITY_STATE(flags) == SECURE) {
+		if (image_desc->state != IMAGE_STATE_RESET) {
+			WARN("BL1-FWU: Authentication from secure world "
+				"while in invalid state\n");
+			return -EPERM;
+		}
+	} else {
+		if (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE) {
+			if (image_desc->state != IMAGE_STATE_COPIED) {
+				WARN("BL1-FWU: Authentication of secure image "
+					"from non-secure world while not in copied state\n");
+				return -EPERM;
+			}
+		} else {
+			if (image_desc->state != IMAGE_STATE_RESET) {
+				WARN("BL1-FWU: Authentication of non-secure image "
+					"from non-secure world while in invalid state\n");
+				return -EPERM;
+			}
+		}
+	}
+
+	if (image_desc->state == IMAGE_STATE_COPIED) {
+		/*
+		 * Image is in COPIED state.
+		 * Use the stored address and size.
+		 */
+		base_addr = image_desc->image_info.image_base;
+		total_size = image_desc->image_info.image_size;
+	} else {
+		if ((!image_src) || (!image_size) ||
+		    check_uptr_overflow(image_src, image_size - 1)) {
+			WARN("BL1-FWU: Auth not allowed due to invalid"
+				" image source/size\n");
+			return -ENOMEM;
+		}
+
+		/*
+		 * Image is in RESET state.
+		 * Check the parameters and authenticate the source image in place.
+		 */
+		if (bl1_plat_mem_check(image_src, image_size,	\
+					image_desc->ep_info.h.attr)) {
+			WARN("BL1-FWU: Authentication arguments source/size not mapped\n");
+			return -ENOMEM;
+		}
+
+		if (bl1_fwu_add_loaded_id(image_id)) {
+			WARN("BL1-FWU: Too many images loaded at the same time.\n");
+			return -ENOMEM;
+		}
+
+		base_addr = image_src;
+		total_size = image_size;
+
+		/* Update the image size in the descriptor. */
+		image_desc->image_info.image_size = total_size;
+	}
+
+	/*
+	 * Authenticate the image.
+	 */
+	INFO("BL1-FWU: Authenticating image_id:%d\n", image_id);
+	result = auth_mod_verify_img(image_id, (void *)base_addr, total_size);
+	if (result != 0) {
+		WARN("BL1-FWU: Authentication Failed err=%d\n", result);
+
+		/*
+		 * Authentication has failed.
+		 * Clear the memory if the image was copied.
+		 * This is to prevent an attack where this contains
+		 * some malicious code that can somehow be executed later.
+		 */
+		if (image_desc->state == IMAGE_STATE_COPIED) {
+			/* Clear the memory.*/
+			zero_normalmem((void *)base_addr, total_size);
+			flush_dcache_range(base_addr, total_size);
+
+			/* Indicate that image can be copied again*/
+			image_desc->state = IMAGE_STATE_RESET;
+		}
+
+		/*
+		 * Even if this fails it's ok because the ID isn't in the array.
+		 * The image cannot be in RESET state here, it is checked at the
+		 * beginning of the function.
+		 */
+		bl1_fwu_remove_loaded_id(image_id);
+		return -EAUTH;
+	}
+
+	/* Indicate that image is in authenticated state. */
+	image_desc->state = IMAGE_STATE_AUTHENTICATED;
+
+	/* Allow the platform to handle post-image load */
+	result = bl1_plat_handle_post_image_load(image_id);
+	if (result != 0) {
+		ERROR("BL1-FWU: Failure %d in post-image load of image id %d\n",
+				result, image_id);
+		/*
+		 * Panic here as the platform handling of post-image load is
+		 * not correct.
+		 */
+		plat_error_handler(result);
+	}
+
+	/*
+	 * Flush image_info to memory so that other
+	 * secure world images can see changes.
+	 */
+	flush_dcache_range((unsigned long)&image_desc->image_info,
+		sizeof(image_info_t));
+
+	INFO("BL1-FWU: Authentication was successful\n");
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function is responsible for executing Secure images.
+ ******************************************************************************/
+static int bl1_fwu_image_execute(unsigned int image_id,
+			void **handle,
+			unsigned int flags)
+{
+	/* Get the image descriptor. */
+	image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
+
+	/*
+	 * Execution is NOT allowed if:
+	 * image_id is invalid OR
+	 * Caller is from Secure world OR
+	 * Image is Non-Secure OR
+	 * Image is Non-Executable OR
+	 * Image is NOT in AUTHENTICATED state.
+	 */
+	if ((!image_desc) ||
+	    (GET_SECURITY_STATE(flags) == SECURE) ||
+	    (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == NON_SECURE) ||
+	    (EP_GET_EXE(image_desc->ep_info.h.attr) == NON_EXECUTABLE) ||
+	    (image_desc->state != IMAGE_STATE_AUTHENTICATED)) {
+		WARN("BL1-FWU: Execution not allowed due to invalid state/args\n");
+		return -EPERM;
+	}
+
+	INFO("BL1-FWU: Executing Secure image\n");
+
+#ifdef __aarch64__
+	/* Save NS-EL1 system registers. */
+	cm_el1_sysregs_context_save(NON_SECURE);
+#endif
+
+	/* Prepare the image for execution. */
+	bl1_prepare_next_image(image_id);
+
+	/* Update the secure image id. */
+	sec_exec_image_id = image_id;
+
+#ifdef __aarch64__
+	*handle = cm_get_context(SECURE);
+#else
+	*handle = smc_get_ctx(SECURE);
+#endif
+	return 0;
+}
+
+/*******************************************************************************
+ * This function is responsible for resuming execution in the other security
+ * world
+ ******************************************************************************/
+static register_t bl1_fwu_image_resume(register_t image_param,
+			void **handle,
+			unsigned int flags)
+{
+	image_desc_t *image_desc;
+	unsigned int resume_sec_state;
+	unsigned int caller_sec_state = GET_SECURITY_STATE(flags);
+
+	/* Get the image descriptor for last executed secure image id. */
+	image_desc = bl1_plat_get_image_desc(sec_exec_image_id);
+	if (caller_sec_state == NON_SECURE) {
+		if (!image_desc) {
+			WARN("BL1-FWU: Resume not allowed due to no available"
+				"secure image\n");
+			return -EPERM;
+		}
+	} else {
+		/* image_desc must be valid for secure world callers */
+		assert(image_desc);
+	}
+
+	assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE);
+	assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE);
+
+	if (caller_sec_state == SECURE) {
+		assert(image_desc->state == IMAGE_STATE_EXECUTED);
+
+		/* Update the flags. */
+		image_desc->state = IMAGE_STATE_INTERRUPTED;
+		resume_sec_state = NON_SECURE;
+	} else {
+		assert(image_desc->state == IMAGE_STATE_INTERRUPTED);
+
+		/* Update the flags. */
+		image_desc->state = IMAGE_STATE_EXECUTED;
+		resume_sec_state = SECURE;
+	}
+
+	INFO("BL1-FWU: Resuming %s world context\n",
+		(resume_sec_state == SECURE) ? "secure" : "normal");
+
+#ifdef __aarch64__
+	/* Save the EL1 system registers of calling world. */
+	cm_el1_sysregs_context_save(caller_sec_state);
+
+	/* Restore the EL1 system registers of resuming world. */
+	cm_el1_sysregs_context_restore(resume_sec_state);
+
+	/* Update the next context. */
+	cm_set_next_eret_context(resume_sec_state);
+
+	*handle = cm_get_context(resume_sec_state);
+#else
+	/* Update the next context. */
+	cm_set_next_context(cm_get_context(resume_sec_state));
+
+	/* Prepare the smc context for the next BL image. */
+	smc_set_next_ctx(resume_sec_state);
+
+	*handle = smc_get_ctx(resume_sec_state);
+#endif
+	return image_param;
+}
+
+/*******************************************************************************
+ * This function is responsible for resuming normal world context.
+ ******************************************************************************/
+static int bl1_fwu_sec_image_done(void **handle, unsigned int flags)
+{
+	image_desc_t *image_desc;
+
+	/* Make sure caller is from the secure world */
+	if (GET_SECURITY_STATE(flags) == NON_SECURE) {
+		WARN("BL1-FWU: Image done not allowed from normal world\n");
+		return -EPERM;
+	}
+
+	/* Get the image descriptor for last executed secure image id */
+	image_desc = bl1_plat_get_image_desc(sec_exec_image_id);
+
+	/* image_desc must correspond to a valid secure executing image */
+	assert(image_desc);
+	assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE);
+	assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE);
+	assert(image_desc->state == IMAGE_STATE_EXECUTED);
+
+#if ENABLE_ASSERTIONS
+	int rc = bl1_fwu_remove_loaded_id(sec_exec_image_id);
+	assert(rc == 0);
+#else
+	bl1_fwu_remove_loaded_id(sec_exec_image_id);
+#endif
+
+	/* Update the flags. */
+	image_desc->state = IMAGE_STATE_RESET;
+	sec_exec_image_id = INVALID_IMAGE_ID;
+
+	INFO("BL1-FWU: Resuming Normal world context\n");
+#ifdef __aarch64__
+	/*
+	 * Secure world is done so no need to save the context.
+	 * Just restore the Non-Secure context.
+	 */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+
+	/* Update the next context. */
+	cm_set_next_eret_context(NON_SECURE);
+
+	*handle = cm_get_context(NON_SECURE);
+#else
+	/* Update the next context. */
+	cm_set_next_context(cm_get_context(NON_SECURE));
+
+	/* Prepare the smc context for the next BL image. */
+	smc_set_next_ctx(NON_SECURE);
+
+	*handle = smc_get_ctx(NON_SECURE);
+#endif
+	return 0;
+}
+
+/*******************************************************************************
+ * This function provides the opportunity for users to perform any
+ * platform specific handling after the Firmware update is done.
+ ******************************************************************************/
+__dead2 static void bl1_fwu_done(void *client_cookie, void *reserved)
+{
+	NOTICE("BL1-FWU: *******FWU Process Completed*******\n");
+
+	/*
+	 * Call platform done function.
+	 */
+	bl1_plat_fwu_done(client_cookie, reserved);
+	assert(0);
+}
+
+/*******************************************************************************
+ * This function resets an image to IMAGE_STATE_RESET. It fails if the image is
+ * being executed.
+ ******************************************************************************/
+static int bl1_fwu_image_reset(unsigned int image_id, unsigned int flags)
+{
+	image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
+
+	if ((!image_desc) || (GET_SECURITY_STATE(flags) == SECURE)) {
+		WARN("BL1-FWU: Reset not allowed due to invalid args\n");
+		return -EPERM;
+	}
+
+	switch (image_desc->state) {
+
+	case IMAGE_STATE_RESET:
+		/* Nothing to do. */
+		break;
+
+	case IMAGE_STATE_INTERRUPTED:
+	case IMAGE_STATE_AUTHENTICATED:
+	case IMAGE_STATE_COPIED:
+	case IMAGE_STATE_COPYING:
+
+		if (bl1_fwu_remove_loaded_id(image_id)) {
+			WARN("BL1-FWU: Image reset couldn't find the image ID\n");
+			return -EPERM;
+		}
+
+		if (image_desc->copied_size) {
+			/* Clear the memory if the image is copied */
+			assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE);
+
+			zero_normalmem((void *)image_desc->image_info.image_base,
+					image_desc->copied_size);
+			flush_dcache_range(image_desc->image_info.image_base,
+					image_desc->copied_size);
+		}
+
+		/* Reset status variables */
+		image_desc->copied_size = 0;
+		image_desc->image_info.image_size = 0;
+		image_desc->state = IMAGE_STATE_RESET;
+
+		/* Clear authentication state */
+		auth_img_flags[image_id] = 0;
+
+		break;
+
+	case IMAGE_STATE_EXECUTED:
+	default:
+		assert(0); /* Unreachable */
+		break;
+	}
+
+	return 0;
+}
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
new file mode 100644
index 0000000..d44b46d
--- /dev/null
+++ b/bl1/bl1_main.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/console.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+#include <tools_share/uuid.h>
+
+#include "bl1_private.h"
+
+/* BL1 Service UUID */
+DEFINE_SVC_UUID2(bl1_svc_uid,
+	0xd46739fd, 0xcb72, 0x9a4d, 0xb5, 0x75,
+	0x67, 0x15, 0xd6, 0xf4, 0xbb, 0x4a);
+
+static void bl1_load_bl2(void);
+
+/*******************************************************************************
+ * Helper utility to calculate the BL2 memory layout taking into consideration
+ * the BL1 RW data assuming that it is at the top of the memory layout.
+ ******************************************************************************/
+void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
+			meminfo_t *bl2_mem_layout)
+{
+	assert(bl1_mem_layout != NULL);
+	assert(bl2_mem_layout != NULL);
+
+	/*
+	 * Remove BL1 RW data from the scope of memory visible to BL2.
+	 * This is assuming BL1 RW data is at the top of bl1_mem_layout.
+	 */
+	assert(BL1_RW_BASE > bl1_mem_layout->total_base);
+	bl2_mem_layout->total_base = bl1_mem_layout->total_base;
+	bl2_mem_layout->total_size = BL1_RW_BASE - bl1_mem_layout->total_base;
+
+	flush_dcache_range((unsigned long)bl2_mem_layout, sizeof(meminfo_t));
+}
+
+/*******************************************************************************
+ * Setup function for BL1.
+ ******************************************************************************/
+void bl1_setup(void)
+{
+	/* Perform early platform-specific setup */
+	bl1_early_platform_setup();
+
+#ifdef __aarch64__
+	/*
+	 * Update pointer authentication key before the MMU is enabled. It is
+	 * saved in the rodata section, that can be writen before enabling the
+	 * MMU. This function must be called after the console is initialized
+	 * in the early platform setup.
+	 */
+	bl_handle_pauth();
+#endif /* __aarch64__ */
+
+	/* Perform late platform-specific setup */
+	bl1_plat_arch_setup();
+}
+
+/*******************************************************************************
+ * Function to perform late architectural and platform specific initialization.
+ * It also queries the platform to load and run next BL image. Only called
+ * by the primary cpu after a cold boot.
+ ******************************************************************************/
+void bl1_main(void)
+{
+	unsigned int image_id;
+
+	/* Announce our arrival */
+	NOTICE(FIRMWARE_WELCOME_STR);
+	NOTICE("BL1: %s\n", version_string);
+	NOTICE("BL1: %s\n", build_message);
+
+	INFO("BL1: RAM %p - %p\n", (void *)BL1_RAM_BASE,
+					(void *)BL1_RAM_LIMIT);
+
+	print_errata_status();
+
+#if ENABLE_ASSERTIONS
+	u_register_t val;
+	/*
+	 * Ensure that MMU/Caches and coherency are turned on
+	 */
+#ifdef __aarch64__
+	val = read_sctlr_el3();
+#else
+	val = read_sctlr();
+#endif
+	assert(val & SCTLR_M_BIT);
+	assert(val & SCTLR_C_BIT);
+	assert(val & SCTLR_I_BIT);
+	/*
+	 * Check that Cache Writeback Granule (CWG) in CTR_EL0 matches the
+	 * provided platform value
+	 */
+	val = (read_ctr_el0() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
+	/*
+	 * If CWG is zero, then no CWG information is available but we can
+	 * at least check the platform value is less than the architectural
+	 * maximum.
+	 */
+	if (val != 0)
+		assert(CACHE_WRITEBACK_GRANULE == SIZE_FROM_LOG2_WORDS(val));
+	else
+		assert(CACHE_WRITEBACK_GRANULE <= MAX_CACHE_LINE_SIZE);
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Perform remaining generic architectural setup from EL3 */
+	bl1_arch_setup();
+
+#if TRUSTED_BOARD_BOOT
+	/* Initialize authentication module */
+	auth_mod_init();
+#endif /* TRUSTED_BOARD_BOOT */
+
+	/* Perform platform setup in BL1. */
+	bl1_platform_setup();
+
+	/* Get the image id of next image to load and run. */
+	image_id = bl1_plat_get_next_image_id();
+
+	/*
+	 * We currently interpret any image id other than
+	 * BL2_IMAGE_ID as the start of firmware update.
+	 */
+	if (image_id == BL2_IMAGE_ID)
+		bl1_load_bl2();
+	else
+		NOTICE("BL1-FWU: *******FWU Process Started*******\n");
+
+	bl1_prepare_next_image(image_id);
+
+	console_flush();
+}
+
+/*******************************************************************************
+ * This function locates and loads the BL2 raw binary image in the trusted SRAM.
+ * Called by the primary cpu after a cold boot.
+ * TODO: Add support for alternative image load mechanism e.g using virtio/elf
+ * loader etc.
+ ******************************************************************************/
+static void bl1_load_bl2(void)
+{
+	image_desc_t *image_desc;
+	image_info_t *image_info;
+	int err;
+
+	/* Get the image descriptor */
+	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+	assert(image_desc);
+
+	/* Get the image info */
+	image_info = &image_desc->image_info;
+	INFO("BL1: Loading BL2\n");
+
+	err = bl1_plat_handle_pre_image_load(BL2_IMAGE_ID);
+	if (err) {
+		ERROR("Failure in pre image load handling of BL2 (%d)\n", err);
+		plat_error_handler(err);
+	}
+
+	err = load_auth_image(BL2_IMAGE_ID, image_info);
+	if (err) {
+		ERROR("Failed to load BL2 firmware.\n");
+		plat_error_handler(err);
+	}
+
+	/* Allow platform to handle image information. */
+	err = bl1_plat_handle_post_image_load(BL2_IMAGE_ID);
+	if (err) {
+		ERROR("Failure in post image load handling of BL2 (%d)\n", err);
+		plat_error_handler(err);
+	}
+
+	NOTICE("BL1: Booting BL2\n");
+}
+
+/*******************************************************************************
+ * Function called just before handing over to the next BL to inform the user
+ * about the boot progress. In debug mode, also print details about the BL
+ * image's execution context.
+ ******************************************************************************/
+void bl1_print_next_bl_ep_info(const entry_point_info_t *bl_ep_info)
+{
+#ifdef __aarch64__
+	NOTICE("BL1: Booting BL31\n");
+#else
+	NOTICE("BL1: Booting BL32\n");
+#endif /* __aarch64__ */
+	print_entry_point_info(bl_ep_info);
+}
+
+#if SPIN_ON_BL1_EXIT
+void print_debug_loop_message(void)
+{
+	NOTICE("BL1: Debug loop, spinning forever\n");
+	NOTICE("BL1: Please connect the debugger to continue\n");
+}
+#endif
+
+/*******************************************************************************
+ * Top level handler for servicing BL1 SMCs.
+ ******************************************************************************/
+register_t bl1_smc_handler(unsigned int smc_fid,
+	register_t x1,
+	register_t x2,
+	register_t x3,
+	register_t x4,
+	void *cookie,
+	void *handle,
+	unsigned int flags)
+{
+
+#if TRUSTED_BOARD_BOOT
+	/*
+	 * Dispatch FWU calls to FWU SMC handler and return its return
+	 * value
+	 */
+	if (is_fwu_fid(smc_fid)) {
+		return bl1_fwu_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+			handle, flags);
+	}
+#endif
+
+	switch (smc_fid) {
+	case BL1_SMC_CALL_COUNT:
+		SMC_RET1(handle, BL1_NUM_SMC_CALLS);
+
+	case BL1_SMC_UID:
+		SMC_UUID_RET(handle, bl1_svc_uid);
+
+	case BL1_SMC_VERSION:
+		SMC_RET1(handle, BL1_SMC_MAJOR_VER | BL1_SMC_MINOR_VER);
+
+	default:
+		break;
+	}
+
+	WARN("Unimplemented BL1 SMC Call: 0x%x \n", smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/*******************************************************************************
+ * BL1 SMC wrapper.  This function is only used in AArch32 mode to ensure ABI
+ * compliance when invoking bl1_smc_handler.
+ ******************************************************************************/
+register_t bl1_smc_wrapper(uint32_t smc_fid,
+	void *cookie,
+	void *handle,
+	unsigned int flags)
+{
+	register_t x1, x2, x3, x4;
+
+	assert(handle);
+
+	get_smc_params_from_ctx(handle, x1, x2, x3, x4);
+	return bl1_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/bl1/bl1_private.h b/bl1/bl1_private.h
new file mode 100644
index 0000000..927c7b8
--- /dev/null
+++ b/bl1/bl1_private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL1_PRIVATE_H
+#define BL1_PRIVATE_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+
+/******************************************
+ * Function prototypes
+ *****************************************/
+void bl1_arch_setup(void);
+void bl1_arch_next_el_setup(void);
+
+void bl1_prepare_next_image(unsigned int image_id);
+
+register_t bl1_fwu_smc_handler(unsigned int smc_fid,
+		register_t x1,
+		register_t x2,
+		register_t x3,
+		register_t x4,
+		void *cookie,
+		void *handle,
+		unsigned int flags);
+
+#endif /* BL1_PRIVATE_H */
diff --git a/bl1/tbbr/tbbr_img_desc.c b/bl1/tbbr/tbbr_img_desc.c
new file mode 100644
index 0000000..e8df73d
--- /dev/null
+++ b/bl1/tbbr/tbbr_img_desc.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <bl1/bl1.h>
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+
+image_desc_t bl1_tbbr_image_descs[] = {
+    {
+	    .image_id = FWU_CERT_ID,
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_1, image_info_t, 0),
+	    .image_info.image_base = BL2_BASE,
+	    .image_info.image_max_size = BL2_LIMIT - BL2_BASE,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_1, entry_point_info_t, SECURE),
+    },
+#if NS_BL1U_BASE
+    {
+	    .image_id = NS_BL1U_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_1, entry_point_info_t, NON_SECURE | EXECUTABLE),
+	    .ep_info.pc = NS_BL1U_BASE,
+    },
+#endif
+#if SCP_BL2U_BASE
+    {
+	    .image_id = SCP_BL2U_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_1, image_info_t, 0),
+	    .image_info.image_base = SCP_BL2U_BASE,
+	    .image_info.image_max_size = SCP_BL2U_LIMIT - SCP_BL2U_BASE,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_1, entry_point_info_t, SECURE),
+    },
+#endif
+#if BL2U_BASE
+    {
+	    .image_id = BL2U_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_1, image_info_t, 0),
+	    .image_info.image_base = BL2U_BASE,
+	    .image_info.image_max_size = BL2U_LIMIT - BL2U_BASE,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_1, entry_point_info_t, SECURE | EXECUTABLE),
+	    .ep_info.pc = BL2U_BASE,
+    },
+#endif
+#if NS_BL2U_BASE
+    {
+	    .image_id = NS_BL2U_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_1, entry_point_info_t, NON_SECURE),
+    },
+#endif
+	    BL2_IMAGE_DESC,
+
+    {
+	    .image_id = INVALID_IMAGE_ID,
+    }
+};
diff --git a/bl2/aarch32/bl2_arch_setup.c b/bl2/aarch32/bl2_arch_setup.c
new file mode 100644
index 0000000..4fd8d07
--- /dev/null
+++ b/bl2/aarch32/bl2_arch_setup.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../bl2_private.h"
+
+/*******************************************************************************
+ * Place holder function to perform any Secure SVC specific architectural
+ * setup. At the moment there is nothing to do.
+ ******************************************************************************/
+void bl2_arch_setup(void)
+{
+
+}
diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S
new file mode 100644
index 0000000..9b4da6b
--- /dev/null
+++ b/bl2/aarch32/bl2_el3_entrypoint.S
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+	.globl	bl2_entrypoint
+	.globl	bl2_run_next_image
+
+
+func bl2_entrypoint
+	/* Save arguments x0-x3 from previous Boot loader */
+	mov	r9, r0
+	mov	r10, r1
+	mov	r11, r2
+	mov	r12, r3
+
+	el3_entrypoint_common                                   \
+                _init_sctlr=1                                   \
+                _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS  \
+                _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU      \
+                _init_memory=1                                  \
+                _init_c_runtime=1                               \
+                _exception_vectors=bl2_vector_table
+
+	/*
+	 * Restore parameters of boot rom
+	 */
+	mov	r0, r9
+	mov	r1, r10
+	mov	r2, r11
+	mov	r3, r12
+
+	/* ---------------------------------------------
+	 * Perform BL2 setup
+	 * ---------------------------------------------
+	 */
+	bl	bl2_el3_setup
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+
+endfunc bl2_entrypoint
+
+func bl2_run_next_image
+	mov	r8,r0
+
+	/*
+	 * MMU needs to be disabled because both BL2 and BL32 execute
+	 * in PL1, and therefore share the same address space.
+	 * BL32 will initialize the address space according to its
+	 * own requirement.
+	 */
+	bl	disable_mmu_icache_secure
+	stcopr	r0, TLBIALL
+	dsb	sy
+	isb
+	mov	r0, r8
+	bl	bl2_el3_plat_prepare_exit
+
+	/*
+	 * Extract PC and SPSR based on struct `entry_point_info_t`
+	 * and load it in LR and SPSR registers respectively.
+	 */
+	ldr	lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
+	ldr	r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
+	msr	spsr_xc, r1
+
+	/* Some BL32 stages expect lr_svc to provide the BL33 entry address */
+	cps	#MODE32_svc
+	ldr	lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET]
+	cps	#MODE32_mon
+
+	add	r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
+	ldm	r8, {r0, r1, r2, r3}
+	eret
+endfunc bl2_run_next_image
diff --git a/bl2/aarch32/bl2_el3_exceptions.S b/bl2/aarch32/bl2_el3_exceptions.S
new file mode 100644
index 0000000..087b665
--- /dev/null
+++ b/bl2/aarch32/bl2_el3_exceptions.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+	.globl	bl2_vector_table
+
+vector_base bl2_vector_table
+	b	bl2_entrypoint
+	b	report_exception	/* Undef */
+	b	report_exception	/* SVC call */
+	b	report_exception	/* Prefetch abort */
+	b	report_exception	/* Data abort */
+	b	report_exception	/* Reserved */
+	b	report_exception	/* IRQ */
+	b	report_exception	/* FIQ */
diff --git a/bl2/aarch32/bl2_entrypoint.S b/bl2/aarch32/bl2_entrypoint.S
new file mode 100644
index 0000000..102fd2f
--- /dev/null
+++ b/bl2/aarch32/bl2_entrypoint.S
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+	.globl	bl2_vector_table
+	.globl	bl2_entrypoint
+
+
+vector_base bl2_vector_table
+	b	bl2_entrypoint
+	b	report_exception	/* Undef */
+	b	report_exception	/* SVC call */
+	b	report_exception	/* Prefetch abort */
+	b	report_exception	/* Data abort */
+	b	report_exception	/* Reserved */
+	b	report_exception	/* IRQ */
+	b	report_exception	/* FIQ */
+
+
+func bl2_entrypoint
+	/*---------------------------------------------
+	 * Save arguments x0 - x3 from BL1 for future
+	 * use.
+	 * ---------------------------------------------
+	 */
+	mov	r9, r0
+	mov	r10, r1
+	mov	r11, r2
+	mov	r12, r3
+
+	/* ---------------------------------------------
+	 * Set the exception vector to something sane.
+	 * ---------------------------------------------
+	 */
+	ldr	r0, =bl2_vector_table
+	stcopr	r0, VBAR
+	isb
+
+	/* --------------------------------------------------------
+	 * Enable the instruction cache - disable speculative loads
+	 * --------------------------------------------------------
+	 */
+	ldcopr	r0, SCTLR
+	orr	r0, r0, #SCTLR_I_BIT
+	bic	r0, r0, #SCTLR_DSSBS_BIT
+	stcopr	r0, SCTLR
+	isb
+
+	/* ---------------------------------------------
+	 * Since BL2 executes after BL1, it is assumed
+	 * here that BL1 has already has done the
+	 * necessary register initializations.
+	 * ---------------------------------------------
+	 */
+
+	/* ---------------------------------------------
+	 * Invalidate the RW memory used by the BL2
+	 * image. This includes the data and NOBITS
+	 * sections. This is done to safeguard against
+	 * possible corruption of this memory by dirty
+	 * cache lines in a system cache as a result of
+	 * use by an earlier boot loader stage.
+	 * ---------------------------------------------
+	 */
+	ldr	r0, =__RW_START__
+	ldr	r1, =__RW_END__
+	sub	r1, r1, r0
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Zero out NOBITS sections. There are 2 of them:
+	 *   - the .bss section;
+	 *   - the coherent memory section.
+	 * ---------------------------------------------
+	 */
+	ldr	r0, =__BSS_START__
+	ldr	r1, =__BSS_SIZE__
+	bl	zeromem
+
+#if USE_COHERENT_MEM
+	ldr	r0, =__COHERENT_RAM_START__
+	ldr	r1, =__COHERENT_RAM_UNALIGNED_SIZE__
+	bl	zeromem
+#endif
+
+	/* --------------------------------------------
+	 * Allocate a stack whose memory will be marked
+	 * as Normal-IS-WBWA when the MMU is enabled.
+	 * There is no risk of reading stale stack
+	 * memory after enabling the MMU as only the
+	 * primary cpu is running at the moment.
+	 * --------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+	/* ---------------------------------------------
+	 * Initialize the stack protector canary before
+	 * any C code is called.
+	 * ---------------------------------------------
+	 */
+#if STACK_PROTECTOR_ENABLED
+	bl	update_stack_protector_canary
+#endif
+
+	/* ---------------------------------------------
+	 * Perform BL2 setup
+	 * ---------------------------------------------
+	 */
+	mov	r0, r9
+	mov	r1, r10
+	mov	r2, r11
+	mov	r3, r12
+
+	bl	bl2_setup
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+
+endfunc bl2_entrypoint
diff --git a/bl2/aarch64/bl2_arch_setup.c b/bl2/aarch64/bl2_arch_setup.c
new file mode 100644
index 0000000..54052f7
--- /dev/null
+++ b/bl2/aarch64/bl2_arch_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include "../bl2_private.h"
+
+/*******************************************************************************
+ * Place holder function to perform any S-EL1 specific architectural setup. At
+ * the moment there is nothing to do.
+ ******************************************************************************/
+void bl2_arch_setup(void)
+{
+	/* Give access to FP/SIMD registers */
+	write_cpacr(CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
+}
diff --git a/bl2/aarch64/bl2_el3_entrypoint.S b/bl2/aarch64/bl2_el3_entrypoint.S
new file mode 100644
index 0000000..261d295
--- /dev/null
+++ b/bl2/aarch64/bl2_el3_entrypoint.S
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+	.globl	bl2_entrypoint
+	.globl	bl2_el3_run_image
+	.globl	bl2_run_next_image
+
+func bl2_entrypoint
+	/* Save arguments x0-x3 from previous Boot loader */
+	mov	x20, x0
+	mov	x21, x1
+	mov	x22, x2
+	mov	x23, x3
+
+	el3_entrypoint_common                                   \
+		_init_sctlr=1                                   \
+		_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS  \
+		_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU      \
+		_init_memory=1                                  \
+		_init_c_runtime=1                               \
+		_exception_vectors=bl2_el3_exceptions
+
+	/* ---------------------------------------------
+	 * Restore parameters of boot rom
+	 * ---------------------------------------------
+	 */
+	mov	x0, x20
+	mov	x1, x21
+	mov	x2, x22
+	mov	x3, x23
+
+	/* ---------------------------------------------
+	 * Perform BL2 setup
+	 * ---------------------------------------------
+	 */
+	bl	bl2_el3_setup
+
+	/* ---------------------------------------------
+	 * Enable pointer authentication
+	 * ---------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el3
+	orr	x0, x0, #SCTLR_EnIA_BIT
+#if ENABLE_BTI
+	/* ---------------------------------------------
+	 * Enable PAC branch type compatibility
+	 * ---------------------------------------------
+	 */
+	bic	x0, x0, #SCTLR_BT_BIT
+#endif	/* ENABLE_BTI */
+	msr	sctlr_el3, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+endfunc bl2_entrypoint
+
+func bl2_run_next_image
+	mov	x20,x0
+	/* ---------------------------------------------
+	 * MMU needs to be disabled because both BL2 and BL31 execute
+	 * in EL3, and therefore share the same address space.
+	 * BL31 will initialize the address space according to its
+	 * own requirement.
+	 * ---------------------------------------------
+	 */
+	bl	disable_mmu_icache_el3
+	tlbi	alle3
+	bl	bl2_el3_plat_prepare_exit
+
+	/* ---------------------------------------------
+	 * Disable pointer authentication before jumping to BL31 or that will
+	 * cause an authentication failure during the early platform init.
+	 * ---------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el3
+	bic	x0, x0, #SCTLR_EnIA_BIT
+	msr	sctlr_el3, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
+	msr	elr_el3, x0
+	msr	spsr_el3, x1
+
+	ldp	x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
+	ldp	x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
+	ldp	x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
+	ldp	x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
+	eret
+endfunc bl2_run_next_image
diff --git a/bl2/aarch64/bl2_el3_exceptions.S b/bl2/aarch64/bl2_el3_exceptions.S
new file mode 100644
index 0000000..3d58051
--- /dev/null
+++ b/bl2/aarch64/bl2_el3_exceptions.S
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by BL2.
+ * -----------------------------------------------------------------------------
+ */
+	.globl	bl2_el3_exceptions
+
+vector_base bl2_el3_exceptions
+
+	/* -----------------------------------------------------
+	 * Current EL with SP0 : 0x0 - 0x200
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSP0
+	mov	x0, #SYNC_EXCEPTION_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionSP0
+
+vector_entry IrqSP0
+	mov	x0, #IRQ_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqSP0
+
+vector_entry FiqSP0
+	mov	x0, #FIQ_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqSP0
+
+vector_entry SErrorSP0
+	mov	x0, #SERROR_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorSP0
+
+	/* -----------------------------------------------------
+	 * Current EL with SPx: 0x200 - 0x400
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSPx
+	mov	x0, #SYNC_EXCEPTION_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionSPx
+
+vector_entry IrqSPx
+	mov	x0, #IRQ_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqSPx
+
+vector_entry FiqSPx
+	mov	x0, #FIQ_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqSPx
+
+vector_entry SErrorSPx
+	mov	x0, #SERROR_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorSPx
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA64
+	mov	x0, #SYNC_EXCEPTION_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionA64
+
+vector_entry IrqA64
+	mov	x0, #IRQ_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqA64
+
+vector_entry FiqA64
+	mov	x0, #FIQ_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqA64
+
+vector_entry SErrorA64
+	mov	x0, #SERROR_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorA64
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA32
+	mov	x0, #SYNC_EXCEPTION_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionA32
+
+vector_entry IrqA32
+	mov	x0, #IRQ_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqA32
+
+vector_entry FiqA32
+	mov	x0, #FIQ_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqA32
+
+vector_entry SErrorA32
+	mov	x0, #SERROR_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorA32
diff --git a/bl2/aarch64/bl2_entrypoint.S b/bl2/aarch64/bl2_entrypoint.S
new file mode 100644
index 0000000..5e5b83b
--- /dev/null
+++ b/bl2/aarch64/bl2_entrypoint.S
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+
+	.globl	bl2_entrypoint
+
+
+
+func bl2_entrypoint
+	/*---------------------------------------------
+	 * Save arguments x0 - x3 from BL1 for future
+	 * use.
+	 * ---------------------------------------------
+	 */
+	mov	x20, x0
+	mov	x21, x1
+	mov	x22, x2
+	mov	x23, x3
+
+	/* ---------------------------------------------
+	 * Set the exception vector to something sane.
+	 * ---------------------------------------------
+	 */
+	adr	x0, early_exceptions
+	msr	vbar_el1, x0
+	isb
+
+	/* ---------------------------------------------
+	 * Enable the SError interrupt now that the
+	 * exception vectors have been setup.
+	 * ---------------------------------------------
+	 */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	/* ---------------------------------------------
+	 * Enable the instruction cache, stack pointer
+	 * and data access alignment checks and disable
+	 * speculative loads.
+	 * ---------------------------------------------
+	 */
+	mov	x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
+	mrs	x0, sctlr_el1
+	orr	x0, x0, x1
+	bic	x0, x0, #SCTLR_DSSBS_BIT
+	msr	sctlr_el1, x0
+	isb
+
+	/* ---------------------------------------------
+	 * Invalidate the RW memory used by the BL2
+	 * image. This includes the data and NOBITS
+	 * sections. This is done to safeguard against
+	 * possible corruption of this memory by dirty
+	 * cache lines in a system cache as a result of
+	 * use by an earlier boot loader stage.
+	 * ---------------------------------------------
+	 */
+	adr	x0, __RW_START__
+	adr	x1, __RW_END__
+	sub	x1, x1, x0
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Zero out NOBITS sections. There are 2 of them:
+	 *   - the .bss section;
+	 *   - the coherent memory section.
+	 * ---------------------------------------------
+	 */
+	adrp	x0, __BSS_START__
+	add	x0, x0, :lo12:__BSS_START__
+	adrp	x1, __BSS_END__
+	add	x1, x1, :lo12:__BSS_END__
+	sub	x1, x1, x0
+	bl	zeromem
+
+#if USE_COHERENT_MEM
+	adrp	x0, __COHERENT_RAM_START__
+	add	x0, x0, :lo12:__COHERENT_RAM_START__
+	adrp	x1, __COHERENT_RAM_END_UNALIGNED__
+	add	x1, x1, :lo12:__COHERENT_RAM_END_UNALIGNED__
+	sub	x1, x1, x0
+	bl	zeromem
+#endif
+
+	/* --------------------------------------------
+	 * Allocate a stack whose memory will be marked
+	 * as Normal-IS-WBWA when the MMU is enabled.
+	 * There is no risk of reading stale stack
+	 * memory after enabling the MMU as only the
+	 * primary cpu is running at the moment.
+	 * --------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+	/* ---------------------------------------------
+	 * Initialize the stack protector canary before
+	 * any C code is called.
+	 * ---------------------------------------------
+	 */
+#if STACK_PROTECTOR_ENABLED
+	bl	update_stack_protector_canary
+#endif
+
+	/* ---------------------------------------------
+	 * Perform BL2 setup
+	 * ---------------------------------------------
+	 */
+	mov	x0, x20
+	mov	x1, x21
+	mov	x2, x22
+	mov	x3, x23
+	bl	bl2_setup
+
+	/* ---------------------------------------------
+	 * Enable pointer authentication
+	 * ---------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el1
+	orr	x0, x0, #SCTLR_EnIA_BIT
+#if ENABLE_BTI
+	/* ---------------------------------------------
+	 * Enable PAC branch type compatibility
+	 * ---------------------------------------------
+	 */
+	bic	x0, x0, #(SCTLR_BT0_BIT | SCTLR_BT1_BIT)
+#endif	/* ENABLE_BTI */
+	msr	sctlr_el1, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+
+endfunc bl2_entrypoint
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
new file mode 100644
index 0000000..30cdf7d
--- /dev/null
+++ b/bl2/bl2.ld.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl2_entrypoint)
+
+MEMORY {
+    RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE
+}
+
+
+SECTIONS
+{
+    . = BL2_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL2_BASE address is not aligned on a page boundary.")
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl2_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+     } >RAM
+
+     /* .ARM.extab and .ARM.exidx are only added because Clang need them */
+     .ARM.extab . : {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+     } >RAM
+
+     .ARM.exidx . : {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+     } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_END__ = .;
+    } >RAM
+#else
+    ro . : {
+        __RO_START__ = .;
+        *bl2_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        *(.vectors)
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as
+         * read-only, executable.  No RW data from the next section must
+         * creep in.  Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __RO_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    /*
+     * .data must be placed at a lower address than the stacks if the stack
+     * protector is enabled. Alternatively, the .data.stack_protector_canary
+     * section can be placed independently of the main .data section.
+     */
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss : ALIGN(16) {
+        __BSS_START__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+    __BL2_END__ = .;
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+
+#if USE_COHERENT_MEM
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+    ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.")
+}
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
new file mode 100644
index 0000000..6dc0f18
--- /dev/null
+++ b/bl2/bl2.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL2_SOURCES		+=	bl2/bl2_image_load_v2.c			\
+				bl2/bl2_main.c				\
+				bl2/${ARCH}/bl2_arch_setup.c		\
+				lib/locks/exclusive/${ARCH}/spinlock.S	\
+				plat/common/${ARCH}/platform_up_stack.S	\
+				${MBEDTLS_SOURCES}
+
+ifeq (${ARCH},aarch64)
+BL2_SOURCES		+=	common/aarch64/early_exceptions.S
+endif
+
+ifeq (${BL2_AT_EL3},0)
+BL2_SOURCES		+=	bl2/${ARCH}/bl2_entrypoint.S
+BL2_LINKERFILE		:=	bl2/bl2.ld.S
+
+else
+BL2_SOURCES		+=	bl2/${ARCH}/bl2_el3_entrypoint.S	\
+				bl2/${ARCH}/bl2_el3_exceptions.S	\
+				lib/cpus/${ARCH}/cpu_helpers.S		\
+				lib/cpus/errata_report.c
+
+ifeq (${ARCH},aarch64)
+BL2_SOURCES		+=	lib/cpus/aarch64/dsu_helpers.S
+endif
+
+BL2_LINKERFILE		:=	bl2/bl2_el3.ld.S
+endif
diff --git a/bl2/bl2_el3.ld.S b/bl2/bl2_el3.ld.S
new file mode 100644
index 0000000..82b51a8
--- /dev/null
+++ b/bl2/bl2_el3.ld.S
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl2_entrypoint)
+
+MEMORY {
+#if BL2_IN_XIP_MEM
+    ROM (rx): ORIGIN = BL2_RO_BASE, LENGTH = BL2_RO_LIMIT - BL2_RO_BASE
+    RAM (rwx): ORIGIN = BL2_RW_BASE, LENGTH = BL2_RW_LIMIT - BL2_RW_BASE
+#else
+    RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE
+#endif
+}
+
+#if !BL2_IN_XIP_MEM
+#define ROM RAM
+#endif
+
+SECTIONS
+{
+#if BL2_IN_XIP_MEM
+    . = BL2_RO_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL2_RO_BASE address is not aligned on a page boundary.")
+#else
+    . = BL2_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL2_BASE address is not aligned on a page boundary.")
+#endif
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+	__TEXT_RESIDENT_START__ = .;
+	*bl2_el3_entrypoint.o(.text*)
+	*(.text.asm.*)
+	__TEXT_RESIDENT_END__ = .;
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+     } >ROM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_END__ = .;
+    } >ROM
+
+    ASSERT(__TEXT_RESIDENT_END__ - __TEXT_RESIDENT_START__ <= PAGE_SIZE,
+          "Resident part of BL2 has exceeded its limit.")
+#else
+    ro . : {
+        __RO_START__ = .;
+	__TEXT_RESIDENT_START__ = .;
+	*bl2_el3_entrypoint.o(.text*)
+	*(.text.asm.*)
+	__TEXT_RESIDENT_END__ = .;
+        *(.text*)
+        *(.rodata*)
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        *(.vectors)
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as
+         * read-only, executable.  No RW data from the next section must
+         * creep in.  Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+
+        __RO_END__ = .;
+    } >ROM
+#endif
+
+    ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
+          "cpu_ops not defined for this platform.")
+
+#if BL2_IN_XIP_MEM
+    . = BL2_RW_BASE;
+    ASSERT(BL2_RW_BASE == ALIGN(PAGE_SIZE),
+           "BL2_RW_BASE address is not aligned on a page boundary.")
+#endif
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    /*
+     * .data must be placed at a lower address than the stacks if the stack
+     * protector is enabled. Alternatively, the .data.stack_protector_canary
+     * section can be placed independently of the main .data section.
+     */
+    .data . : {
+        __DATA_RAM_START__ = .;
+        *(.data*)
+        __DATA_RAM_END__ = .;
+    } >RAM AT>ROM
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss : ALIGN(16) {
+        __BSS_START__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+    __BL2_END__ = .;
+
+#if BL2_IN_XIP_MEM
+    __BL2_RAM_START__ = ADDR(.data);
+    __BL2_RAM_END__ = .;
+
+    __DATA_ROM_START__ = LOADADDR(.data);
+    __DATA_SIZE__ = SIZEOF(.data);
+
+    /*
+     * The .data section is the last PROGBITS section so its end marks the end
+     * of BL2's RO content in XIP memory..
+     */
+    __BL2_ROM_END__ =  __DATA_ROM_START__ + __DATA_SIZE__;
+    ASSERT(__BL2_ROM_END__ <= BL2_RO_LIMIT,
+           "BL2's RO content has exceeded its limit.")
+#endif
+    __BSS_SIZE__ = SIZEOF(.bss);
+
+
+#if USE_COHERENT_MEM
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+#if BL2_IN_XIP_MEM
+    ASSERT(. <= BL2_RW_LIMIT, "BL2's RW content has exceeded its limit.")
+#else
+    ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.")
+#endif
+}
diff --git a/bl2/bl2_image_load_v2.c b/bl2/bl2_image_load_v2.c
new file mode 100644
index 0000000..dd53e1d
--- /dev/null
+++ b/bl2/bl2_image_load_v2.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/auth/auth_mod.h>
+#include <plat/common/platform.h>
+
+#include "bl2_private.h"
+
+/*******************************************************************************
+ * This function loads SCP_BL2/BL3x images and returns the ep_info for
+ * the next executable image.
+ ******************************************************************************/
+struct entry_point_info *bl2_load_images(void)
+{
+	bl_params_t *bl2_to_next_bl_params;
+	bl_load_info_t *bl2_load_info;
+	const bl_load_info_node_t *bl2_node_info;
+	int plat_setup_done = 0;
+	int err;
+
+	/*
+	 * Get information about the images to load.
+	 */
+	bl2_load_info = plat_get_bl_image_load_info();
+	assert(bl2_load_info);
+	assert(bl2_load_info->head);
+	assert(bl2_load_info->h.type == PARAM_BL_LOAD_INFO);
+	assert(bl2_load_info->h.version >= VERSION_2);
+	bl2_node_info = bl2_load_info->head;
+
+	while (bl2_node_info) {
+		/*
+		 * Perform platform setup before loading the image,
+		 * if indicated in the image attributes AND if NOT
+		 * already done before.
+		 */
+		if (bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_PLAT_SETUP) {
+			if (plat_setup_done) {
+				WARN("BL2: Platform setup already done!!\n");
+			} else {
+				INFO("BL2: Doing platform setup\n");
+				bl2_platform_setup();
+				plat_setup_done = 1;
+			}
+		}
+
+		err = bl2_plat_handle_pre_image_load(bl2_node_info->image_id);
+		if (err) {
+			ERROR("BL2: Failure in pre image load handling (%i)\n", err);
+			plat_error_handler(err);
+		}
+
+		if (!(bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) {
+			INFO("BL2: Loading image id %d\n", bl2_node_info->image_id);
+			err = load_auth_image(bl2_node_info->image_id,
+				bl2_node_info->image_info);
+			if (err) {
+				ERROR("BL2: Failed to load image (%i)\n", err);
+				plat_error_handler(err);
+			}
+		} else {
+			INFO("BL2: Skip loading image id %d\n", bl2_node_info->image_id);
+		}
+
+		/* Allow platform to handle image information. */
+		err = bl2_plat_handle_post_image_load(bl2_node_info->image_id);
+		if (err) {
+			ERROR("BL2: Failure in post image load handling (%i)\n", err);
+			plat_error_handler(err);
+		}
+
+		/* Go to next image */
+		bl2_node_info = bl2_node_info->next_load_info;
+	}
+
+	/*
+	 * Get information to pass to the next image.
+	 */
+	bl2_to_next_bl_params = plat_get_next_bl_params();
+	assert(bl2_to_next_bl_params);
+	assert(bl2_to_next_bl_params->head);
+	assert(bl2_to_next_bl_params->h.type == PARAM_BL_PARAMS);
+	assert(bl2_to_next_bl_params->h.version >= VERSION_2);
+	assert(bl2_to_next_bl_params->head->ep_info);
+
+	/* Populate arg0 for the next BL image if not already provided */
+	if (bl2_to_next_bl_params->head->ep_info->args.arg0 == (u_register_t)0)
+		bl2_to_next_bl_params->head->ep_info->args.arg0 =
+					(u_register_t)bl2_to_next_bl_params;
+
+	/* Flush the parameters to be passed to next image */
+	plat_flush_next_bl_params();
+
+	return bl2_to_next_bl_params->head->ep_info;
+}
diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c
new file mode 100644
index 0000000..79b0e71
--- /dev/null
+++ b/bl2/bl2_main.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <bl2/bl2.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#include "bl2_private.h"
+
+#ifdef __aarch64__
+#define NEXT_IMAGE	"BL31"
+#else
+#define NEXT_IMAGE	"BL32"
+#endif
+
+#if !BL2_AT_EL3
+/*******************************************************************************
+ * Setup function for BL2.
+ ******************************************************************************/
+void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+	       u_register_t arg3)
+{
+	/* Perform early platform-specific setup */
+	bl2_early_platform_setup2(arg0, arg1, arg2, arg3);
+
+#ifdef __aarch64__
+	/*
+	 * Update pointer authentication key before the MMU is enabled. It is
+	 * saved in the rodata section, that can be writen before enabling the
+	 * MMU. This function must be called after the console is initialized
+	 * in the early platform setup.
+	 */
+	bl_handle_pauth();
+#endif /* __aarch64__ */
+
+	/* Perform late platform-specific setup */
+	bl2_plat_arch_setup();
+}
+
+#else /* if BL2_AT_EL3 */
+/*******************************************************************************
+ * Setup function for BL2 when BL2_AT_EL3=1.
+ ******************************************************************************/
+void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+		   u_register_t arg3)
+{
+	/* Perform early platform-specific setup */
+	bl2_el3_early_platform_setup(arg0, arg1, arg2, arg3);
+
+#ifdef __aarch64__
+	/*
+	 * Update pointer authentication key before the MMU is enabled. It is
+	 * saved in the rodata section, that can be writen before enabling the
+	 * MMU. This function must be called after the console is initialized
+	 * in the early platform setup.
+	 */
+	bl_handle_pauth();
+#endif /* __aarch64__ */
+
+	/* Perform late platform-specific setup */
+	bl2_el3_plat_arch_setup();
+}
+#endif /* BL2_AT_EL3 */
+
+/*******************************************************************************
+ * The only thing to do in BL2 is to load further images and pass control to
+ * next BL. The memory occupied by BL2 will be reclaimed by BL3x stages. BL2
+ * runs entirely in S-EL1.
+ ******************************************************************************/
+void bl2_main(void)
+{
+	entry_point_info_t *next_bl_ep_info;
+
+	NOTICE("BL2: %s\n", version_string);
+	NOTICE("BL2: %s\n", build_message);
+
+	/* Perform remaining generic architectural setup in S-EL1 */
+	bl2_arch_setup();
+
+#if TRUSTED_BOARD_BOOT
+	/* Initialize authentication module */
+	auth_mod_init();
+#endif /* TRUSTED_BOARD_BOOT */
+
+	/* initialize boot source */
+	bl2_plat_preload_setup();
+
+	/* Load the subsequent bootloader images. */
+	next_bl_ep_info = bl2_load_images();
+
+#if !BL2_AT_EL3
+#ifndef __aarch64__
+	/*
+	 * For AArch32 state BL1 and BL2 share the MMU setup.
+	 * Given that BL2 does not map BL1 regions, MMU needs
+	 * to be disabled in order to go back to BL1.
+	 */
+	disable_mmu_icache_secure();
+#endif /* !__aarch64__ */
+
+	console_flush();
+
+	/*
+	 * Run next BL image via an SMC to BL1. Information on how to pass
+	 * control to the BL32 (if present) and BL33 software images will
+	 * be passed to next BL image as an argument.
+	 */
+	smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0);
+#else /* if BL2_AT_EL3 */
+	NOTICE("BL2: Booting " NEXT_IMAGE "\n");
+	print_entry_point_info(next_bl_ep_info);
+	console_flush();
+
+	bl2_run_next_image(next_bl_ep_info);
+#endif /* BL2_AT_EL3 */
+}
diff --git a/bl2/bl2_private.h b/bl2/bl2_private.h
new file mode 100644
index 0000000..b1704d2
--- /dev/null
+++ b/bl2/bl2_private.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL2_PRIVATE_H
+#define BL2_PRIVATE_H
+
+#include <common/bl_common.h>
+
+/******************************************
+ * Forward declarations
+ *****************************************/
+struct entry_point_info;
+
+/******************************************
+ * Function prototypes
+ *****************************************/
+void bl2_arch_setup(void);
+struct entry_point_info *bl2_load_images(void);
+void bl2_run_next_image(const struct entry_point_info *bl_ep_info);
+
+#endif /* BL2_PRIVATE_H */
diff --git a/bl2u/aarch32/bl2u_entrypoint.S b/bl2u/aarch32/bl2u_entrypoint.S
new file mode 100644
index 0000000..6391f53
--- /dev/null
+++ b/bl2u/aarch32/bl2u_entrypoint.S
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+	.globl	bl2u_vector_table
+	.globl	bl2u_entrypoint
+
+
+vector_base bl2u_vector_table
+	b	bl2u_entrypoint
+	b	report_exception	/* Undef */
+	b	report_exception	/* SVC call */
+	b	report_exception	/* Prefetch abort */
+	b	report_exception	/* Data abort */
+	b	report_exception	/* Reserved */
+	b	report_exception	/* IRQ */
+	b	report_exception	/* FIQ */
+
+
+func bl2u_entrypoint
+	/*---------------------------------------------
+	 * Save from r1 the extents of the trusted ram
+	 * available to BL2U for future use.
+	 * r0 is not currently used.
+	 * ---------------------------------------------
+	 */
+	mov	r11, r1
+	mov	r10, r2
+
+	/* ---------------------------------------------
+	 * Set the exception vector to something sane.
+	 * ---------------------------------------------
+	 */
+	ldr	r0, =bl2u_vector_table
+	stcopr	r0, VBAR
+	isb
+
+	/* --------------------------------------------------------
+	 * Enable the instruction cache - disable speculative loads
+	 * --------------------------------------------------------
+	 */
+	ldcopr	r0, SCTLR
+	orr	r0, r0, #SCTLR_I_BIT
+	bic	r0, r0, #SCTLR_DSSBS_BIT
+	stcopr	r0, SCTLR
+	isb
+
+	/* ---------------------------------------------
+	 * Since BL2U executes after BL1, it is assumed
+	 * here that BL1 has already has done the
+	 * necessary register initializations.
+	 * ---------------------------------------------
+	 */
+
+	/* ---------------------------------------------
+	 * Invalidate the RW memory used by the BL2U
+	 * image. This includes the data and NOBITS
+	 * sections. This is done to safeguard against
+	 * possible corruption of this memory by dirty
+	 * cache lines in a system cache as a result of
+	 * use by an earlier boot loader stage.
+	 * ---------------------------------------------
+	 */
+	ldr	r0, =__RW_START__
+	ldr	r1, =__RW_END__
+	sub	r1, r1, r0
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Zero out NOBITS sections. There are 2 of them:
+	 *   - the .bss section;
+	 *   - the coherent memory section.
+	 * ---------------------------------------------
+	 */
+	ldr	r0, =__BSS_START__
+	ldr	r1, =__BSS_SIZE__
+	bl	zeromem
+
+	/* --------------------------------------------
+	 * Allocate a stack whose memory will be marked
+	 * as Normal-IS-WBWA when the MMU is enabled.
+	 * There is no risk of reading stale stack
+	 * memory after enabling the MMU as only the
+	 * primary cpu is running at the moment.
+	 * --------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+	/* ---------------------------------------------
+	 * Initialize the stack protector canary before
+	 * any C code is called.
+	 * ---------------------------------------------
+	 */
+#if STACK_PROTECTOR_ENABLED
+	bl	update_stack_protector_canary
+#endif
+
+	/* ---------------------------------------------
+	 * Perform early platform setup & platform
+	 * specific early arch. setup e.g. mmu setup
+	 * ---------------------------------------------
+	 */
+	mov	r0, r11
+	mov	r1, r10
+	bl	bl2u_early_platform_setup
+	bl	bl2u_plat_arch_setup
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2u_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+
+endfunc bl2u_entrypoint
diff --git a/bl2u/aarch64/bl2u_entrypoint.S b/bl2u/aarch64/bl2u_entrypoint.S
new file mode 100644
index 0000000..452869e
--- /dev/null
+++ b/bl2u/aarch64/bl2u_entrypoint.S
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+	.globl	bl2u_entrypoint
+
+
+func bl2u_entrypoint
+	/*---------------------------------------------
+	 * Store the extents of the tzram available to
+	 * BL2U and other platform specific information
+	 * for future use. x0 is currently not used.
+	 * ---------------------------------------------
+	 */
+	mov	x20, x1
+	mov	x21, x2
+
+	/* ---------------------------------------------
+	 * Set the exception vector to something sane.
+	 * ---------------------------------------------
+	 */
+	adr	x0, early_exceptions
+	msr	vbar_el1, x0
+	isb
+
+	/* ---------------------------------------------
+	 * Enable the SError interrupt now that the
+	 * exception vectors have been setup.
+	 * ---------------------------------------------
+	 */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	/* ---------------------------------------------
+	 * Enable the instruction cache, stack pointer
+	 * and data access alignment checks and disable
+	 * speculative loads.
+	 * ---------------------------------------------
+	 */
+	mov	x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
+	mrs	x0, sctlr_el1
+	orr	x0, x0, x1
+	bic	x0, x0, #SCTLR_DSSBS_BIT
+	msr	sctlr_el1, x0
+	isb
+
+	/* ---------------------------------------------
+	 * Invalidate the RW memory used by the BL2U
+	 * image. This includes the data and NOBITS
+	 * sections. This is done to safeguard against
+	 * possible corruption of this memory by dirty
+	 * cache lines in a system cache as a result of
+	 * use by an earlier boot loader stage.
+	 * ---------------------------------------------
+	 */
+	adr	x0, __RW_START__
+	adr	x1, __RW_END__
+	sub	x1, x1, x0
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Zero out NOBITS sections. There are 2 of them:
+	 *   - the .bss section;
+	 *   - the coherent memory section.
+	 * ---------------------------------------------
+	 */
+	ldr	x0, =__BSS_START__
+	ldr	x1, =__BSS_SIZE__
+	bl	zeromem
+
+	/* --------------------------------------------
+	 * Allocate a stack whose memory will be marked
+	 * as Normal-IS-WBWA when the MMU is enabled.
+	 * There is no risk of reading stale stack
+	 * memory after enabling the MMU as only the
+	 * primary cpu is running at the moment.
+	 * --------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+	/* ---------------------------------------------
+	 * Initialize the stack protector canary before
+	 * any C code is called.
+	 * ---------------------------------------------
+	 */
+#if STACK_PROTECTOR_ENABLED
+	bl	update_stack_protector_canary
+#endif
+
+	/* ---------------------------------------------
+	 * Perform early platform setup & platform
+	 * specific early arch. setup e.g. mmu setup
+	 * ---------------------------------------------
+	 */
+	mov	x0, x20
+	mov	x1, x21
+	bl	bl2u_early_platform_setup
+	bl	bl2u_plat_arch_setup
+
+	/* ---------------------------------------------
+	 * Jump to bl2u_main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2u_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+
+endfunc bl2u_entrypoint
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
new file mode 100644
index 0000000..8d4984f
--- /dev/null
+++ b/bl2u/bl2u.ld.S
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl2u_entrypoint)
+
+MEMORY {
+    RAM (rwx): ORIGIN = BL2U_BASE, LENGTH = BL2U_LIMIT - BL2U_BASE
+}
+
+
+SECTIONS
+{
+    . = BL2U_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL2U_BASE address is not aligned on a page boundary.")
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl2u_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+     } >RAM
+
+     /* .ARM.extab and .ARM.exidx are only added because Clang need them */
+     .ARM.extab . : {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+     } >RAM
+
+     .ARM.exidx . : {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+     } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_END__ = .;
+    } >RAM
+#else
+    ro . : {
+        __RO_START__ = .;
+        *bl2u_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        *(.vectors)
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as
+         * read-only, executable.  No RW data from the next section must
+         * creep in.  Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __RO_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    /*
+     * .data must be placed at a lower address than the stacks if the stack
+     * protector is enabled. Alternatively, the .data.stack_protector_canary
+     * section can be placed independently of the main .data section.
+     */
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss : ALIGN(16) {
+        __BSS_START__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+    __BL2U_END__ = .;
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+
+    ASSERT(. <= BL2U_LIMIT, "BL2U image has exceeded its limit.")
+}
diff --git a/bl2u/bl2u.mk b/bl2u/bl2u.mk
new file mode 100644
index 0000000..b4d7634
--- /dev/null
+++ b/bl2u/bl2u.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL2U_SOURCES		+=	bl2u/bl2u_main.c			\
+				bl2u/${ARCH}/bl2u_entrypoint.S		\
+				plat/common/${ARCH}/platform_up_stack.S
+
+ifeq (${ARCH},aarch64)
+BL2U_SOURCES		+=	common/aarch64/early_exceptions.S
+endif
+
+BL2U_LINKERFILE		:=	bl2u/bl2u.ld.S
diff --git a/bl2u/bl2u_main.c b/bl2u/bl2u_main.c
new file mode 100644
index 0000000..d49c9ce
--- /dev/null
+++ b/bl2u/bl2u_main.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <bl2u/bl2u.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function is responsible to:
+ * Load SCP_BL2U if platform has defined SCP_BL2U_BASE
+ * Perform platform setup.
+ * Go back to EL3.
+ ******************************************************************************/
+void bl2u_main(void)
+{
+	NOTICE("BL2U: %s\n", version_string);
+	NOTICE("BL2U: %s\n", build_message);
+
+#if SCP_BL2U_BASE
+	int rc;
+	/* Load the subsequent bootloader images */
+	rc = bl2u_plat_handle_scp_bl2u();
+	if (rc) {
+		ERROR("Failed to load SCP_BL2U (%i)\n", rc);
+		panic();
+	}
+#endif
+
+	/* Perform platform setup in BL2U after loading SCP_BL2U */
+	bl2u_platform_setup();
+
+	console_flush();
+
+#ifndef __aarch64__
+	/*
+	 * For AArch32 state BL1 and BL2U share the MMU setup.
+	 * Given that BL2U does not map BL1 regions, MMU needs
+	 * to be disabled in order to go back to BL1.
+	 */
+	disable_mmu_icache_secure();
+#endif /* !__aarch64__ */
+
+	/*
+	 * Indicate that BL2U is done and resume back to
+	 * normal world via an SMC to BL1.
+	 * x1 could be passed to Normal world,
+	 * so DO NOT pass any secret information.
+	 */
+	smc(FWU_SMC_SEC_IMAGE_DONE, 0, 0, 0, 0, 0, 0, 0);
+	wfi();
+}
diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S
new file mode 100644
index 0000000..e7ad5a8
--- /dev/null
+++ b/bl31/aarch64/bl31_entrypoint.S
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+#include <lib/pmf/pmf_asm_macros.S>
+#include <lib/runtime_instr.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+	.globl	bl31_entrypoint
+	.globl	bl31_warm_entrypoint
+
+	/* -----------------------------------------------------
+	 * bl31_entrypoint() is the cold boot entrypoint,
+	 * executed only by the primary cpu.
+	 * -----------------------------------------------------
+	 */
+
+func bl31_entrypoint
+	/* ---------------------------------------------------------------
+	 * Stash the previous bootloader arguments x0 - x3 for later use.
+	 * ---------------------------------------------------------------
+	 */
+	mov	x20, x0
+	mov	x21, x1
+	mov	x22, x2
+	mov	x23, x3
+
+	/* --------------------------------------------------------------------
+	 * If PIE is enabled, fixup the Global descriptor Table and dynamic
+	 * relocations
+	 * --------------------------------------------------------------------
+	 */
+#if ENABLE_PIE
+	mov_imm	x0, BL31_BASE
+	mov_imm	x1, BL31_LIMIT
+	bl	fixup_gdt_reloc
+#endif /* ENABLE_PIE */
+
+#if !RESET_TO_BL31
+	/* ---------------------------------------------------------------------
+	 * For !RESET_TO_BL31 systems, only the primary CPU ever reaches
+	 * bl31_entrypoint() during the cold boot flow, so the cold/warm boot
+	 * and primary/secondary CPU logic should not be executed in this case.
+	 *
+	 * Also, assume that the previous bootloader has already initialised the
+	 * SCTLR_EL3, including the endianness, and has initialised the memory.
+	 * ---------------------------------------------------------------------
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=0					\
+		_warm_boot_mailbox=0				\
+		_secondary_cold_boot=0				\
+		_init_memory=0					\
+		_init_c_runtime=1				\
+		_exception_vectors=runtime_exceptions
+#else
+
+	/* ---------------------------------------------------------------------
+	 * For RESET_TO_BL31 systems which have a programmable reset address,
+	 * bl31_entrypoint() is executed only on the cold boot path so we can
+	 * skip the warm boot mailbox mechanism.
+	 * ---------------------------------------------------------------------
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=1					\
+		_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS	\
+		_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU	\
+		_init_memory=1					\
+		_init_c_runtime=1				\
+		_exception_vectors=runtime_exceptions
+
+	/* ---------------------------------------------------------------------
+	 * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
+	 * there's no argument to relay from a previous bootloader. Zero the
+	 * arguments passed to the platform layer to reflect that.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	x20, 0
+	mov	x21, 0
+	mov	x22, 0
+	mov	x23, 0
+#endif /* RESET_TO_BL31 */
+
+	/* --------------------------------------------------------------------
+	 * Perform BL31 setup
+	 * --------------------------------------------------------------------
+	 */
+	mov	x0, x20
+	mov	x1, x21
+	mov	x2, x22
+	mov	x3, x23
+	bl	bl31_setup
+
+	/* --------------------------------------------------------------------
+	 * Enable pointer authentication
+	 * --------------------------------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el3
+	orr	x0, x0, #SCTLR_EnIA_BIT
+#if ENABLE_BTI
+	/* --------------------------------------------------------------------
+	 * Enable PAC branch type compatibility
+	 * --------------------------------------------------------------------
+	 */
+	bic	x0, x0, #SCTLR_BT_BIT
+#endif	/* ENABLE_BTI */
+	msr	sctlr_el3, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	/* --------------------------------------------------------------------
+	 * Jump to main function.
+	 * --------------------------------------------------------------------
+	 */
+	bl	bl31_main
+
+	/* --------------------------------------------------------------------
+	 * Clean the .data & .bss sections to main memory. This ensures
+	 * that any global data which was initialised by the primary CPU
+	 * is visible to secondary CPUs before they enable their data
+	 * caches and participate in coherency.
+	 * --------------------------------------------------------------------
+	 */
+	adr	x0, __DATA_START__
+	adr	x1, __DATA_END__
+	sub	x1, x1, x0
+	bl	clean_dcache_range
+
+	adr	x0, __BSS_START__
+	adr	x1, __BSS_END__
+	sub	x1, x1, x0
+	bl	clean_dcache_range
+
+	b	el3_exit
+endfunc bl31_entrypoint
+
+	/* --------------------------------------------------------------------
+	 * This CPU has been physically powered up. It is either resuming from
+	 * suspend or has simply been turned on. In both cases, call the BL31
+	 * warmboot entrypoint
+	 * --------------------------------------------------------------------
+	 */
+func bl31_warm_entrypoint
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+	/*
+	 * This timestamp update happens with cache off.  The next
+	 * timestamp collection will need to do cache maintenance prior
+	 * to timestamp update.
+	 */
+	pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_HW_LOW_PWR
+	mrs	x1, cntpct_el0
+	str	x1, [x0]
+#endif
+
+	/*
+	 * On the warm boot path, most of the EL3 initialisations performed by
+	 * 'el3_entrypoint_common' must be skipped:
+	 *
+	 *  - Only when the platform bypasses the BL1/BL31 entrypoint by
+	 *    programming the reset address do we need to initialise SCTLR_EL3.
+	 *    In other cases, we assume this has been taken care by the
+	 *    entrypoint code.
+	 *
+	 *  - No need to determine the type of boot, we know it is a warm boot.
+	 *
+	 *  - Do not try to distinguish between primary and secondary CPUs, this
+	 *    notion only exists for a cold boot.
+	 *
+	 *  - No need to initialise the memory or the C runtime environment,
+	 *    it has been done once and for all on the cold boot path.
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=PROGRAMMABLE_RESET_ADDRESS		\
+		_warm_boot_mailbox=0				\
+		_secondary_cold_boot=0				\
+		_init_memory=0					\
+		_init_c_runtime=0				\
+		_exception_vectors=runtime_exceptions
+
+	/*
+	 * We're about to enable MMU and participate in PSCI state coordination.
+	 *
+	 * The PSCI implementation invokes platform routines that enable CPUs to
+	 * participate in coherency. On a system where CPUs are not
+	 * cache-coherent without appropriate platform specific programming,
+	 * having caches enabled until such time might lead to coherency issues
+	 * (resulting from stale data getting speculatively fetched, among
+	 * others). Therefore we keep data caches disabled even after enabling
+	 * the MMU for such platforms.
+	 *
+	 * On systems with hardware-assisted coherency, or on single cluster
+	 * platforms, such platform specific programming is not required to
+	 * enter coherency (as CPUs already are); and there's no reason to have
+	 * caches disabled either.
+	 */
+#if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY
+	mov	x0, xzr
+#else
+	mov	x0, #DISABLE_DCACHE
+#endif
+	bl	bl31_plat_enable_mmu
+
+	/* --------------------------------------------------------------------
+	 * Enable pointer authentication
+	 * --------------------------------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	bl	pauth_load_bl_apiakey
+
+	mrs	x0, sctlr_el3
+	orr	x0, x0, #SCTLR_EnIA_BIT
+#if ENABLE_BTI
+	/* --------------------------------------------------------------------
+	 * Enable PAC branch type compatibility
+	 * --------------------------------------------------------------------
+	 */
+	bic	x0, x0, #SCTLR_BT_BIT
+#endif	/* ENABLE_BTI */
+	msr	sctlr_el3, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	bl	psci_warmboot_entrypoint
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_PSCI
+	mov	x19, x0
+
+	/*
+	 * Invalidate before updating timestamp to ensure previous timestamp
+	 * updates on the same cache line with caches disabled are properly
+	 * seen by the same core. Without the cache invalidate, the core might
+	 * write into a stale cache line.
+	 */
+	mov	x1, #PMF_TS_SIZE
+	mov	x20, x30
+	bl	inv_dcache_range
+	mov	x30, x20
+
+	mrs	x0, cntpct_el0
+	str	x0, [x19]
+#endif
+	b	el3_exit
+endfunc bl31_warm_entrypoint
diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S
new file mode 100644
index 0000000..2c41029
--- /dev/null
+++ b/bl31/aarch64/crash_reporting.S
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_macros.S>
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/utils_def.h>
+
+	.globl	report_unhandled_exception
+	.globl	report_unhandled_interrupt
+	.globl	el3_panic
+
+#if CRASH_REPORTING
+
+	/* ------------------------------------------------------
+	 * The below section deals with dumping the system state
+	 * when an unhandled exception is taken in EL3.
+	 * The layout and the names of the registers which will
+	 * be dumped during a unhandled exception is given below.
+	 * ------------------------------------------------------
+	 */
+.section .rodata.crash_prints, "aS"
+print_spacer:
+	.asciz	"             = 0x"
+
+gp_regs:
+	.asciz	"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
+		"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\
+		"x16", "x17", "x18", "x19", "x20", "x21", "x22",\
+		"x23", "x24", "x25", "x26", "x27", "x28", "x29", ""
+el3_sys_regs:
+	.asciz	"scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\
+		"daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\
+		"esr_el3", "far_el3", ""
+
+non_el3_sys_regs:
+	.asciz	"spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\
+		"spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\
+		"csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\
+		"mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\
+		"tpidrro_el0",  "par_el1", "mpidr_el1", "afsr0_el1", "afsr1_el1",\
+		"contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\
+		"cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", ""
+
+#if CTX_INCLUDE_AARCH32_REGS
+aarch32_regs:
+	.asciz	"dacr32_el2", "ifsr32_el2", ""
+#endif /* CTX_INCLUDE_AARCH32_REGS */
+
+panic_msg:
+	.asciz "PANIC in EL3.\nx30"
+excpt_msg:
+	.asciz "Unhandled Exception in EL3.\nx30"
+intr_excpt_msg:
+	.asciz "Unhandled Interrupt Exception in EL3.\nx30"
+
+	/*
+	 * Helper function to print newline to console.
+	 */
+func print_newline
+	mov	x0, '\n'
+	b	plat_crash_console_putc
+endfunc print_newline
+
+	/*
+	 * Helper function to print from crash buf.
+	 * The print loop is controlled by the buf size and
+	 * ascii reg name list which is passed in x6. The
+	 * function returns the crash buf address in x0.
+	 * Clobbers : x0 - x7, sp
+	 */
+func size_controlled_print
+	/* Save the lr */
+	mov	sp, x30
+	/* load the crash buf address */
+	mrs	x7, tpidr_el3
+test_size_list:
+	/* Calculate x5 always as it will be clobbered by asm_print_hex */
+	mrs	x5, tpidr_el3
+	add	x5, x5, #CPU_DATA_CRASH_BUF_SIZE
+	/* Test whether we have reached end of crash buf */
+	cmp	x7, x5
+	b.eq	exit_size_print
+	ldrb	w4, [x6]
+	/* Test whether we are at end of list */
+	cbz	w4, exit_size_print
+	mov	x4, x6
+	/* asm_print_str updates x4 to point to next entry in list */
+	bl	asm_print_str
+	/* x0 = number of symbols printed + 1 */
+	sub	x0, x4, x6
+	/* update x6 with the updated list pointer */
+	mov	x6, x4
+	bl	print_alignment
+	ldr	x4, [x7], #REGSZ
+	bl	asm_print_hex
+	bl	print_newline
+	b	test_size_list
+exit_size_print:
+	mov	x30, sp
+	ret
+endfunc size_controlled_print
+
+	/* -----------------------------------------------------
+	 * This function calculates and prints required number
+	 * of space characters followed by "= 0x", based on the
+	 * length of ascii register name.
+ 	 * x0: length of ascii register name + 1
+	 * ------------------------------------------------------
+ 	 */
+func print_alignment
+	/* The minimum ascii length is 3, e.g. for "x0" */
+	adr	x4, print_spacer - 3
+	add	x4, x4, x0
+	b	asm_print_str
+endfunc print_alignment
+
+	/*
+	 * Helper function to store x8 - x15 registers to
+	 * the crash buf. The system registers values are
+	 * copied to x8 to x15 by the caller which are then
+	 * copied to the crash buf by this function.
+	 * x0 points to the crash buf. It then calls
+	 * size_controlled_print to print to console.
+	 * Clobbers : x0 - x7, sp
+	 */
+func str_in_crash_buf_print
+	/* restore the crash buf address in x0 */
+	mrs	x0, tpidr_el3
+	stp	x8, x9, [x0]
+	stp	x10, x11, [x0, #REGSZ * 2]
+	stp	x12, x13, [x0, #REGSZ * 4]
+	stp	x14, x15, [x0, #REGSZ * 6]
+	b	size_controlled_print
+endfunc str_in_crash_buf_print
+
+	/* ------------------------------------------------------
+	 * This macro calculates the offset to crash buf from
+	 * cpu_data and stores it in tpidr_el3. It also saves x0
+	 * and x1 in the crash buf by using sp as a temporary
+	 * register.
+	 * ------------------------------------------------------
+	 */
+	.macro prepare_crash_buf_save_x0_x1
+	/* we can corrupt this reg to free up x0 */
+	mov	sp, x0
+	/* tpidr_el3 contains the address to cpu_data structure */
+	mrs	x0, tpidr_el3
+	/* Calculate the Crash buffer offset in cpu_data */
+	add	x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
+	/* Store crash buffer address in tpidr_el3 */
+	msr	tpidr_el3, x0
+	str	x1, [x0, #REGSZ]
+	mov	x1, sp
+	str	x1, [x0]
+	.endm
+
+	/* -----------------------------------------------------
+	 * This function allows to report a crash (if crash
+	 * reporting is enabled) when an unhandled exception
+	 * occurs. It prints the CPU state via the crash console
+	 * making use of the crash buf. This function will
+	 * not return.
+	 * -----------------------------------------------------
+	 */
+func report_unhandled_exception
+	prepare_crash_buf_save_x0_x1
+	adr	x0, excpt_msg
+	mov	sp, x0
+	/* This call will not return */
+	b	do_crash_reporting
+endfunc report_unhandled_exception
+
+
+	/* -----------------------------------------------------
+	 * This function allows to report a crash (if crash
+	 * reporting is enabled) when an unhandled interrupt
+	 * occurs. It prints the CPU state via the crash console
+	 * making use of the crash buf. This function will
+	 * not return.
+	 * -----------------------------------------------------
+	 */
+func report_unhandled_interrupt
+	prepare_crash_buf_save_x0_x1
+	adr	x0, intr_excpt_msg
+	mov	sp, x0
+	/* This call will not return */
+	b	do_crash_reporting
+endfunc report_unhandled_interrupt
+
+	/* -----------------------------------------------------
+	 * This function allows to report a crash (if crash
+	 * reporting is enabled) when panic() is invoked from
+	 * C Runtime. It prints the CPU state via the crash
+	 * console making use of the crash buf. This function
+	 * will not return.
+	 * -----------------------------------------------------
+	 */
+func el3_panic
+	msr	spsel, #MODE_SP_ELX
+	prepare_crash_buf_save_x0_x1
+	adr	x0, panic_msg
+	mov	sp, x0
+	/* This call will not return */
+	b	do_crash_reporting
+endfunc el3_panic
+
+	/* ------------------------------------------------------------
+	 * The common crash reporting functionality. It requires x0
+	 * and x1 has already been stored in crash buf, sp points to
+	 * crash message and tpidr_el3 contains the crash buf address.
+	 * The function does the following:
+	 *   - Retrieve the crash buffer from tpidr_el3
+	 *   - Store x2 to x6 in the crash buffer
+	 *   - Initialise the crash console.
+	 *   - Print the crash message by using the address in sp.
+	 *   - Print x30 value to the crash console.
+	 *   - Print x0 - x7 from the crash buf to the crash console.
+	 *   - Print x8 - x29 (in groups of 8 registers) using the
+	 *     crash buf to the crash console.
+	 *   - Print el3 sys regs (in groups of 8 registers) using the
+	 *     crash buf to the crash console.
+	 *   - Print non el3 sys regs (in groups of 8 registers) using
+	 *     the crash buf to the crash console.
+	 * ------------------------------------------------------------
+	 */
+func do_crash_reporting
+	/* Retrieve the crash buf from tpidr_el3 */
+	mrs	x0, tpidr_el3
+	/* Store x2 - x6, x30 in the crash buffer */
+	stp	x2, x3, [x0, #REGSZ * 2]
+	stp	x4, x5, [x0, #REGSZ * 4]
+	stp	x6, x30, [x0, #REGSZ * 6]
+	/* Initialize the crash console */
+	bl	plat_crash_console_init
+	/* Verify the console is initialized */
+	cbz	x0, crash_panic
+	/* Print the crash message. sp points to the crash message */
+	mov	x4, sp
+	bl	asm_print_str
+	/* Print spaces to align "x30" string */
+	mov	x0, #4
+	bl	print_alignment
+	/* load the crash buf address */
+	mrs	x0, tpidr_el3
+	/* report x30 first from the crash buf */
+	ldr	x4, [x0, #REGSZ * 7]
+	bl	asm_print_hex
+	bl	print_newline
+	/* Load the crash buf address */
+	mrs	x0, tpidr_el3
+	/* Now mov x7 into crash buf */
+	str	x7, [x0, #REGSZ * 7]
+
+	/* Report x0 - x29 values stored in crash buf*/
+	/* Store the ascii list pointer in x6 */
+	adr	x6, gp_regs
+	/* Print x0 to x7 from the crash buf */
+	bl	size_controlled_print
+	/* Store x8 - x15 in crash buf and print */
+	bl	str_in_crash_buf_print
+	/* Load the crash buf address */
+	mrs	x0, tpidr_el3
+	/* Store the rest of gp regs and print */
+	stp	x16, x17, [x0]
+	stp	x18, x19, [x0, #REGSZ * 2]
+	stp	x20, x21, [x0, #REGSZ * 4]
+	stp	x22, x23, [x0, #REGSZ * 6]
+	bl	size_controlled_print
+	/* Load the crash buf address */
+	mrs	x0, tpidr_el3
+	stp	x24, x25, [x0]
+	stp	x26, x27, [x0, #REGSZ * 2]
+	stp	x28, x29, [x0, #REGSZ * 4]
+	bl	size_controlled_print
+
+	/* Print the el3 sys registers */
+	adr	x6, el3_sys_regs
+	mrs	x8, scr_el3
+	mrs	x9, sctlr_el3
+	mrs	x10, cptr_el3
+	mrs	x11, tcr_el3
+	mrs	x12, daif
+	mrs	x13, mair_el3
+	mrs	x14, spsr_el3
+	mrs	x15, elr_el3
+	bl	str_in_crash_buf_print
+	mrs	x8, ttbr0_el3
+	mrs	x9, esr_el3
+	mrs	x10, far_el3
+	bl	str_in_crash_buf_print
+
+	/* Print the non el3 sys registers */
+	adr	x6, non_el3_sys_regs
+	mrs	x8, spsr_el1
+	mrs	x9, elr_el1
+	mrs	x10, spsr_abt
+	mrs	x11, spsr_und
+	mrs	x12, spsr_irq
+	mrs	x13, spsr_fiq
+	mrs	x14, sctlr_el1
+	mrs	x15, actlr_el1
+	bl	str_in_crash_buf_print
+	mrs	x8, cpacr_el1
+	mrs	x9, csselr_el1
+	mrs	x10, sp_el1
+	mrs	x11, esr_el1
+	mrs	x12, ttbr0_el1
+	mrs	x13, ttbr1_el1
+	mrs	x14, mair_el1
+	mrs	x15, amair_el1
+	bl	str_in_crash_buf_print
+	mrs	x8, tcr_el1
+	mrs	x9, tpidr_el1
+	mrs	x10, tpidr_el0
+	mrs	x11, tpidrro_el0
+	mrs	x12, par_el1
+	mrs	x13, mpidr_el1
+	mrs	x14, afsr0_el1
+	mrs	x15, afsr1_el1
+	bl	str_in_crash_buf_print
+	mrs	x8, contextidr_el1
+	mrs	x9, vbar_el1
+	mrs	x10, cntp_ctl_el0
+	mrs	x11, cntp_cval_el0
+	mrs	x12, cntv_ctl_el0
+	mrs	x13, cntv_cval_el0
+	mrs	x14, cntkctl_el1
+	mrs	x15, sp_el0
+	bl	str_in_crash_buf_print
+	mrs	x8, isr_el1
+	bl	str_in_crash_buf_print
+
+#if CTX_INCLUDE_AARCH32_REGS
+	/* Print the AArch32 registers */
+	adr	x6, aarch32_regs
+	mrs	x8, dacr32_el2
+	mrs	x9, ifsr32_el2
+	bl	str_in_crash_buf_print
+#endif /* CTX_INCLUDE_AARCH32_REGS */
+
+	/* Get the cpu specific registers to report */
+	bl	do_cpu_reg_dump
+	bl	str_in_crash_buf_print
+
+	/* Print some platform registers */
+	plat_crash_print_regs
+
+	bl	plat_crash_console_flush
+
+	/* Done reporting */
+	no_ret	plat_panic_handler
+endfunc do_crash_reporting
+
+#else	/* CRASH_REPORTING */
+func report_unhandled_exception
+report_unhandled_interrupt:
+	no_ret	plat_panic_handler
+endfunc report_unhandled_exception
+#endif	/* CRASH_REPORTING */
+
+
+func crash_panic
+	no_ret	plat_panic_handler
+endfunc crash_panic
diff --git a/bl31/aarch64/ea_delegate.S b/bl31/aarch64/ea_delegate.S
new file mode 100644
index 0000000..40c3191
--- /dev/null
+++ b/bl31/aarch64/ea_delegate.S
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <assert_macros.S>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <bl31/ea_handle.h>
+#include <context.h>
+#include <lib/extensions/ras_arch.h>
+
+
+	.globl	handle_lower_el_ea_esb
+	.globl	enter_lower_el_sync_ea
+	.globl	enter_lower_el_async_ea
+
+
+/*
+ * Function to delegate External Aborts synchronized by ESB instruction at EL3
+ * vector entry. This function assumes GP registers x0-x29 have been saved, and
+ * are available for use. It delegates the handling of the EA to platform
+ * handler, and returns only upon successfully handling the EA; otherwise
+ * panics. On return from this function, the original exception handler is
+ * expected to resume.
+ */
+func handle_lower_el_ea_esb
+	mov	x0, #ERROR_EA_ESB
+	mrs	x1, DISR_EL1
+	b	ea_proceed
+endfunc handle_lower_el_ea_esb
+
+
+/*
+ * This function forms the tail end of Synchronous Exception entry from lower
+ * EL, and expects to handle only Synchronous External Aborts from lower EL. If
+ * any other kind of exception is detected, then this function reports unhandled
+ * exception.
+ *
+ * Since it's part of exception vector, this function doesn't expect any GP
+ * registers to have been saved. It delegates the handling of the EA to platform
+ * handler, and upon successfully handling the EA, exits EL3; otherwise panics.
+ */
+func enter_lower_el_sync_ea
+	/*
+	 * Explicitly save x30 so as to free up a register and to enable
+	 * branching.
+	 */
+	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	mrs	x30, esr_el3
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+	/* Check for I/D aborts from lower EL */
+	cmp	x30, #EC_IABORT_LOWER_EL
+	b.eq	1f
+
+	cmp	x30, #EC_DABORT_LOWER_EL
+	b.ne	2f
+
+1:
+	/* Test for EA bit in the instruction syndrome */
+	mrs	x30, esr_el3
+	tbz	x30, #ESR_ISS_EABORT_EA_BIT, 2f
+
+	/* Save GP registers */
+	bl	save_gp_registers
+
+	/* Save ARMv8.3-PAuth registers and load firmware key */
+#if CTX_INCLUDE_PAUTH_REGS
+	bl	pauth_context_save
+#endif
+#if ENABLE_PAUTH
+	bl	pauth_load_bl_apiakey
+#endif
+
+	/* Setup exception class and syndrome arguments for platform handler */
+	mov	x0, #ERROR_EA_SYNC
+	mrs	x1, esr_el3
+	adr	x30, el3_exit
+	b	delegate_sync_ea
+
+2:
+	/* Synchronous exceptions other than the above are assumed to be EA */
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+	no_ret	report_unhandled_exception
+endfunc enter_lower_el_sync_ea
+
+
+/*
+ * This function handles SErrors from lower ELs.
+ *
+ * Since it's part of exception vector, this function doesn't expect any GP
+ * registers to have been saved. It delegates the handling of the EA to platform
+ * handler, and upon successfully handling the EA, exits EL3; otherwise panics.
+ */
+func enter_lower_el_async_ea
+	/*
+	 * Explicitly save x30 so as to free up a register and to enable
+	 * branching
+	 */
+	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	/* Save GP registers */
+	bl	save_gp_registers
+
+	/* Save ARMv8.3-PAuth registers and load firmware key */
+#if CTX_INCLUDE_PAUTH_REGS
+	bl	pauth_context_save
+#endif
+#if ENABLE_PAUTH
+	bl	pauth_load_bl_apiakey
+#endif
+
+	/* Setup exception class and syndrome arguments for platform handler */
+	mov	x0, #ERROR_EA_ASYNC
+	mrs	x1, esr_el3
+	adr	x30, el3_exit
+	b	delegate_async_ea
+endfunc enter_lower_el_async_ea
+
+
+/*
+ * Prelude for Synchronous External Abort handling. This function assumes that
+ * all GP registers have been saved by the caller.
+ *
+ * x0: EA reason
+ * x1: EA syndrome
+ */
+func delegate_sync_ea
+#if RAS_EXTENSION
+	/*
+	 * Check for Uncontainable error type. If so, route to the platform
+	 * fatal error handler rather than the generic EA one.
+	 */
+	ubfx    x2, x1, #EABORT_SET_SHIFT, #EABORT_SET_WIDTH
+	cmp     x2, #ERROR_STATUS_SET_UC
+	b.ne    1f
+
+	/* Check fault status code */
+	ubfx    x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
+	cmp     x3, #SYNC_EA_FSC
+	b.ne    1f
+
+	no_ret  plat_handle_uncontainable_ea
+1:
+#endif
+
+	b       ea_proceed
+endfunc delegate_sync_ea
+
+
+/*
+ * Prelude for Asynchronous External Abort handling. This function assumes that
+ * all GP registers have been saved by the caller.
+ *
+ * x0: EA reason
+ * x1: EA syndrome
+ */
+func delegate_async_ea
+#if RAS_EXTENSION
+	/*
+	 * Check for Implementation Defined Syndrome. If so, skip checking
+	 * Uncontainable error type from the syndrome as the format is unknown.
+	 */
+	tbnz	x1, #SERROR_IDS_BIT, 1f
+
+	/*
+	 * Check for Uncontainable error type. If so, route to the platform
+	 * fatal error handler rather than the generic EA one.
+	 */
+	ubfx	x2, x1, #EABORT_AET_SHIFT, #EABORT_AET_WIDTH
+	cmp	x2, #ERROR_STATUS_UET_UC
+	b.ne	1f
+
+	/* Check DFSC for SError type */
+	ubfx	x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
+	cmp	x3, #DFSC_SERROR
+	b.ne	1f
+
+	no_ret	plat_handle_uncontainable_ea
+1:
+#endif
+
+	b	ea_proceed
+endfunc delegate_async_ea
+
+
+/*
+ * Delegate External Abort handling to platform's EA handler. This function
+ * assumes that all GP registers have been saved by the caller.
+ *
+ * x0: EA reason
+ * x1: EA syndrome
+ */
+func ea_proceed
+	/*
+	 * If the ESR loaded earlier is not zero, we were processing an EA
+	 * already, and this is a double fault.
+	 */
+	ldr	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
+	cbz	x5, 1f
+	no_ret	plat_handle_double_fault
+
+1:
+	/* Save EL3 state */
+	mrs	x2, spsr_el3
+	mrs	x3, elr_el3
+	stp	x2, x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+
+	/*
+	 * Save ESR as handling might involve lower ELs, and returning back to
+	 * EL3 from there would trample the original ESR.
+	 */
+	mrs	x4, scr_el3
+	mrs	x5, esr_el3
+	stp	x4, x5, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+
+	/*
+	 * Setup rest of arguments, and call platform External Abort handler.
+	 *
+	 * x0: EA reason (already in place)
+	 * x1: Exception syndrome (already in place).
+	 * x2: Cookie (unused for now).
+	 * x3: Context pointer.
+	 * x4: Flags (security state from SCR for now).
+	 */
+	mov	x2, xzr
+	mov	x3, sp
+	ubfx	x4, x4, #0, #1
+
+	/* Switch to runtime stack */
+	ldr	x5, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+	msr	spsel, #0
+	mov	sp, x5
+
+	mov	x29, x30
+#if ENABLE_ASSERTIONS
+	/* Stash the stack pointer */
+	mov	x28, sp
+#endif
+	bl	plat_ea_handler
+
+#if ENABLE_ASSERTIONS
+	/*
+	 * Error handling flows might involve long jumps; so upon returning from
+	 * the platform error handler, validate that the we've completely
+	 * unwound the stack.
+	 */
+	mov	x27, sp
+	cmp	x28, x27
+	ASM_ASSERT(eq)
+#endif
+
+	/* Make SP point to context */
+	msr	spsel, #1
+
+	/* Restore EL3 state and ESR */
+	ldp	x1, x2, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+	msr	spsr_el3, x1
+	msr	elr_el3, x2
+
+	/* Restore ESR_EL3 and SCR_EL3 */
+	ldp	x3, x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+	msr	scr_el3, x3
+	msr	esr_el3, x4
+
+#if ENABLE_ASSERTIONS
+	cmp	x4, xzr
+	ASM_ASSERT(ne)
+#endif
+
+	/* Clear ESR storage */
+	str	xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
+
+	ret	x29
+endfunc ea_proceed
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
new file mode 100644
index 0000000..6ffd995
--- /dev/null
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl31/ea_handle.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/smccc.h>
+
+	.globl	runtime_exceptions
+
+	.globl	sync_exception_sp_el0
+	.globl	irq_sp_el0
+	.globl	fiq_sp_el0
+	.globl	serror_sp_el0
+
+	.globl	sync_exception_sp_elx
+	.globl	irq_sp_elx
+	.globl	fiq_sp_elx
+	.globl	serror_sp_elx
+
+	.globl	sync_exception_aarch64
+	.globl	irq_aarch64
+	.globl	fiq_aarch64
+	.globl	serror_aarch64
+
+	.globl	sync_exception_aarch32
+	.globl	irq_aarch32
+	.globl	fiq_aarch32
+	.globl	serror_aarch32
+
+	/*
+	 * Macro that prepares entry to EL3 upon taking an exception.
+	 *
+	 * With RAS_EXTENSION, this macro synchronizes pending errors with an ESB
+	 * instruction. When an error is thus synchronized, the handling is
+	 * delegated to platform EA handler.
+	 *
+	 * Without RAS_EXTENSION, this macro just saves x30, and unmasks
+	 * Asynchronous External Aborts.
+	 */
+	.macro check_and_unmask_ea
+#if RAS_EXTENSION
+	/* Synchronize pending External Aborts */
+	esb
+
+	/* Unmask the SError interrupt */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	/*
+	 * Explicitly save x30 so as to free up a register and to enable
+	 * branching
+	 */
+	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	/* Check for SErrors synchronized by the ESB instruction */
+	mrs	x30, DISR_EL1
+	tbz	x30, #DISR_A_BIT, 1f
+
+	/* Save GP registers and restore them afterwards */
+	bl	save_gp_registers
+	bl	handle_lower_el_ea_esb
+	bl	restore_gp_registers
+
+1:
+#else
+	/* Unmask the SError interrupt */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	str	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+#endif
+	.endm
+
+	/* ---------------------------------------------------------------------
+	 * This macro handles Synchronous exceptions.
+	 * Only SMC exceptions are supported.
+	 * ---------------------------------------------------------------------
+	 */
+	.macro	handle_sync_exception
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	/*
+	 * Read the timestamp value and store it in per-cpu data. The value
+	 * will be extracted from per-cpu data by the C level SMC handler and
+	 * saved to the PMF timestamp region.
+	 */
+	mrs	x30, cntpct_el0
+	str	x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+	mrs	x29, tpidr_el3
+	str	x30, [x29, #CPU_DATA_PMF_TS0_OFFSET]
+	ldr	x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
+#endif
+
+	mrs	x30, esr_el3
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+	/* Handle SMC exceptions separately from other synchronous exceptions */
+	cmp	x30, #EC_AARCH32_SMC
+	b.eq	smc_handler32
+
+	cmp	x30, #EC_AARCH64_SMC
+	b.eq	smc_handler64
+
+	/* Synchronous exceptions other than the above are assumed to be EA */
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+	b	enter_lower_el_sync_ea
+	.endm
+
+
+	/* ---------------------------------------------------------------------
+	 * This macro handles FIQ or IRQ interrupts i.e. EL3, S-EL1 and NS
+	 * interrupts.
+	 * ---------------------------------------------------------------------
+	 */
+	.macro	handle_interrupt_exception label
+
+	bl	save_gp_registers
+
+	/* Save ARMv8.3-PAuth registers and load firmware key */
+#if CTX_INCLUDE_PAUTH_REGS
+	bl	pauth_context_save
+#endif
+#if ENABLE_PAUTH
+	bl	pauth_load_bl_apiakey
+#endif
+
+	/* Save the EL3 system registers needed to return from this exception */
+	mrs	x0, spsr_el3
+	mrs	x1, elr_el3
+	stp	x0, x1, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+
+	/* Switch to the runtime stack i.e. SP_EL0 */
+	ldr	x2, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+	mov	x20, sp
+	msr	spsel, #0
+	mov	sp, x2
+
+	/*
+	 * Find out whether this is a valid interrupt type.
+	 * If the interrupt controller reports a spurious interrupt then return
+	 * to where we came from.
+	 */
+	bl	plat_ic_get_pending_interrupt_type
+	cmp	x0, #INTR_TYPE_INVAL
+	b.eq	interrupt_exit_\label
+
+	/*
+	 * Get the registered handler for this interrupt type.
+	 * A NULL return value could be 'cause of the following conditions:
+	 *
+	 * a. An interrupt of a type was routed correctly but a handler for its
+	 *    type was not registered.
+	 *
+	 * b. An interrupt of a type was not routed correctly so a handler for
+	 *    its type was not registered.
+	 *
+	 * c. An interrupt of a type was routed correctly to EL3, but was
+	 *    deasserted before its pending state could be read. Another
+	 *    interrupt of a different type pended at the same time and its
+	 *    type was reported as pending instead. However, a handler for this
+	 *    type was not registered.
+	 *
+	 * a. and b. can only happen due to a programming error. The
+	 * occurrence of c. could be beyond the control of Trusted Firmware.
+	 * It makes sense to return from this exception instead of reporting an
+	 * error.
+	 */
+	bl	get_interrupt_type_handler
+	cbz	x0, interrupt_exit_\label
+	mov	x21, x0
+
+	mov	x0, #INTR_ID_UNAVAILABLE
+
+	/* Set the current security state in the 'flags' parameter */
+	mrs	x2, scr_el3
+	ubfx	x1, x2, #0, #1
+
+	/* Restore the reference to the 'handle' i.e. SP_EL3 */
+	mov	x2, x20
+
+	/* x3 will point to a cookie (not used now) */
+	mov	x3, xzr
+
+	/* Call the interrupt type handler */
+	blr	x21
+
+interrupt_exit_\label:
+	/* Return from exception, possibly in a different security state */
+	b	el3_exit
+
+	.endm
+
+
+vector_base runtime_exceptions
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_EL0 : 0x0 - 0x200
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry sync_exception_sp_el0
+	/* We don't expect any synchronous exceptions from EL3 */
+	b	report_unhandled_exception
+end_vector_entry sync_exception_sp_el0
+
+vector_entry irq_sp_el0
+	/*
+	 * EL3 code is non-reentrant. Any asynchronous exception is a serious
+	 * error. Loop infinitely.
+	 */
+	b	report_unhandled_interrupt
+end_vector_entry irq_sp_el0
+
+
+vector_entry fiq_sp_el0
+	b	report_unhandled_interrupt
+end_vector_entry fiq_sp_el0
+
+
+vector_entry serror_sp_el0
+	no_ret	plat_handle_el3_ea
+end_vector_entry serror_sp_el0
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_ELx: 0x200 - 0x400
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry sync_exception_sp_elx
+	/*
+	 * This exception will trigger if anything went wrong during a previous
+	 * exception entry or exit or while handling an earlier unexpected
+	 * synchronous exception. There is a high probability that SP_EL3 is
+	 * corrupted.
+	 */
+	b	report_unhandled_exception
+end_vector_entry sync_exception_sp_elx
+
+vector_entry irq_sp_elx
+	b	report_unhandled_interrupt
+end_vector_entry irq_sp_elx
+
+vector_entry fiq_sp_elx
+	b	report_unhandled_interrupt
+end_vector_entry fiq_sp_elx
+
+vector_entry serror_sp_elx
+	no_ret	plat_handle_el3_ea
+end_vector_entry serror_sp_elx
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry sync_exception_aarch64
+	/*
+	 * This exception vector will be the entry point for SMCs and traps
+	 * that are unhandled at lower ELs most commonly. SP_EL3 should point
+	 * to a valid cpu context where the general purpose and system register
+	 * state can be saved.
+	 */
+	check_and_unmask_ea
+	handle_sync_exception
+end_vector_entry sync_exception_aarch64
+
+vector_entry irq_aarch64
+	check_and_unmask_ea
+	handle_interrupt_exception irq_aarch64
+end_vector_entry irq_aarch64
+
+vector_entry fiq_aarch64
+	check_and_unmask_ea
+	handle_interrupt_exception fiq_aarch64
+end_vector_entry fiq_aarch64
+
+vector_entry serror_aarch64
+	msr	daifclr, #DAIF_ABT_BIT
+	b	enter_lower_el_async_ea
+end_vector_entry serror_aarch64
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry sync_exception_aarch32
+	/*
+	 * This exception vector will be the entry point for SMCs and traps
+	 * that are unhandled at lower ELs most commonly. SP_EL3 should point
+	 * to a valid cpu context where the general purpose and system register
+	 * state can be saved.
+	 */
+	check_and_unmask_ea
+	handle_sync_exception
+end_vector_entry sync_exception_aarch32
+
+vector_entry irq_aarch32
+	check_and_unmask_ea
+	handle_interrupt_exception irq_aarch32
+end_vector_entry irq_aarch32
+
+vector_entry fiq_aarch32
+	check_and_unmask_ea
+	handle_interrupt_exception fiq_aarch32
+end_vector_entry fiq_aarch32
+
+vector_entry serror_aarch32
+	msr	daifclr, #DAIF_ABT_BIT
+	b	enter_lower_el_async_ea
+end_vector_entry serror_aarch32
+
+	/* ---------------------------------------------------------------------
+	 * The following code handles secure monitor calls.
+	 * Depending upon the execution state from where the SMC has been
+	 * invoked, it frees some general purpose registers to perform the
+	 * remaining tasks. They involve finding the runtime service handler
+	 * that is the target of the SMC & switching to runtime stacks (SP_EL0)
+	 * before calling the handler.
+	 *
+	 * Note that x30 has been explicitly saved and can be used here
+	 * ---------------------------------------------------------------------
+	 */
+func smc_handler
+smc_handler32:
+	/* Check whether aarch32 issued an SMC64 */
+	tbnz	x0, #FUNCID_CC_SHIFT, smc_prohibited
+
+smc_handler64:
+	/* NOTE: The code below must preserve x0-x4 */
+
+	/* Save general purpose registers */
+	bl	save_gp_registers
+
+	/* Save ARMv8.3-PAuth registers and load firmware key */
+#if CTX_INCLUDE_PAUTH_REGS
+	bl	pauth_context_save
+#endif
+#if ENABLE_PAUTH
+	bl	pauth_load_bl_apiakey
+#endif
+
+	/*
+	 * Populate the parameters for the SMC handler.
+	 * We already have x0-x4 in place. x5 will point to a cookie (not used
+	 * now). x6 will point to the context structure (SP_EL3) and x7 will
+	 * contain flags we need to pass to the handler.
+	 */
+	mov	x5, xzr
+	mov	x6, sp
+
+	/*
+	 * Restore the saved C runtime stack value which will become the new
+	 * SP_EL0 i.e. EL3 runtime stack. It was saved in the 'cpu_context'
+	 * structure prior to the last ERET from EL3.
+	 */
+	ldr	x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+
+	/* Switch to SP_EL0 */
+	msr	spsel, #0
+
+	/*
+	 * Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there is a world
+	 * switch during SMC handling.
+	 * TODO: Revisit if all system registers can be saved later.
+	 */
+	mrs	x16, spsr_el3
+	mrs	x17, elr_el3
+	mrs	x18, scr_el3
+	stp	x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+	str	x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+
+	/* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
+	bfi	x7, x18, #0, #1
+
+	mov	sp, x12
+
+	/* Get the unique owning entity number */
+	ubfx	x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH
+	ubfx	x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH
+	orr	x16, x16, x15, lsl #FUNCID_OEN_WIDTH
+
+	/* Load descriptor index from array of indices */
+	adr	x14, rt_svc_descs_indices
+	ldrb	w15, [x14, x16]
+
+	/* Any index greater than 127 is invalid. Check bit 7. */
+	tbnz	w15, 7, smc_unknown
+
+	/*
+	 * Get the descriptor using the index
+	 * x11 = (base + off), w15 = index
+	 *
+	 * handler = (base + off) + (index << log2(size))
+	 */
+	adr	x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)
+	lsl	w10, w15, #RT_SVC_SIZE_LOG2
+	ldr	x15, [x11, w10, uxtw]
+
+	/*
+	 * Call the Secure Monitor Call handler and then drop directly into
+	 * el3_exit() which will program any remaining architectural state
+	 * prior to issuing the ERET to the desired lower EL.
+	 */
+#if DEBUG
+	cbz	x15, rt_svc_fw_critical_error
+#endif
+	blr	x15
+
+	b	el3_exit
+
+smc_unknown:
+	/*
+	 * Unknown SMC call. Populate return value with SMC_UNK and call
+	 * el3_exit() which will restore the remaining architectural state
+	 * i.e., SYS, GP and PAuth registers(if any) prior to issuing the ERET
+         * to the desired lower EL.
+	 */
+	mov	x0, #SMC_UNK
+	str	x0, [x6, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	b	el3_exit
+
+smc_prohibited:
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+	mov	x0, #SMC_UNK
+	eret
+
+rt_svc_fw_critical_error:
+	/* Switch to SP_ELx */
+	msr	spsel, #1
+	no_ret	report_unhandled_exception
+endfunc smc_handler
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
new file mode 100644
index 0000000..c7d587c
--- /dev/null
+++ b/bl31/bl31.ld.S
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl31_entrypoint)
+
+
+MEMORY {
+    RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_LIMIT - BL31_BASE
+}
+
+#ifdef PLAT_EXTRA_LD_SCRIPT
+#include <plat.ld.S>
+#endif
+
+SECTIONS
+{
+    . = BL31_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL31_BASE address is not aligned on a page boundary.")
+
+    __BL31_START__ = .;
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl31_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+    } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+#if ENABLE_PMF
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PMF_SVC_DESCS_START__ = .;
+        KEEP(*(pmf_svc_descs))
+        __PMF_SVC_DESCS_END__ = .;
+#endif /* ENABLE_PMF */
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /*
+         * Keep the .got section in the RO section as it is patched
+         * prior to enabling the MMU and having the .got in RO is better for
+         * security. GOT is a table of addresses so ensure 8-byte alignment.
+         */
+        . = ALIGN(8);
+        __GOT_START__ = .;
+        *(.got)
+        __GOT_END__ = .;
+
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_END__ = .;
+    } >RAM
+#else
+    ro . : {
+        __RO_START__ = .;
+        *bl31_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+#if ENABLE_PMF
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PMF_SVC_DESCS_START__ = .;
+        KEEP(*(pmf_svc_descs))
+        __PMF_SVC_DESCS_END__ = .;
+#endif /* ENABLE_PMF */
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /*
+         * Keep the .got section in the RO section as it is patched
+         * prior to enabling the MMU and having the .got in RO is better for
+         * security. GOT is a table of addresses so ensure 8-byte alignment.
+         */
+        . = ALIGN(8);
+        __GOT_START__ = .;
+        *(.got)
+        __GOT_END__ = .;
+
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+        *(.vectors)
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as read-only,
+         * executable.  No RW data from the next section must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __RO_END__ = .;
+    } >RAM
+#endif
+
+    ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
+           "cpu_ops not defined for this platform.")
+
+#if ENABLE_SPM
+#ifndef SPM_SHIM_EXCEPTIONS_VMA
+#define SPM_SHIM_EXCEPTIONS_VMA         RAM
+#endif
+
+    /*
+     * Exception vectors of the SPM shim layer. They must be aligned to a 2K
+     * address, but we need to place them in a separate page so that we can set
+     * individual permissions to them, so the actual alignment needed is 4K.
+     *
+     * There's no need to include this into the RO section of BL31 because it
+     * doesn't need to be accessed by BL31.
+     */
+    spm_shim_exceptions : ALIGN(PAGE_SIZE) {
+        __SPM_SHIM_EXCEPTIONS_START__ = .;
+        *(.spm_shim_exceptions)
+        . = ALIGN(PAGE_SIZE);
+        __SPM_SHIM_EXCEPTIONS_END__ = .;
+    } >SPM_SHIM_EXCEPTIONS_VMA AT>RAM
+
+    PROVIDE(__SPM_SHIM_EXCEPTIONS_LMA__ = LOADADDR(spm_shim_exceptions));
+    . = LOADADDR(spm_shim_exceptions) + SIZEOF(spm_shim_exceptions);
+#endif
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    /*
+     * .data must be placed at a lower address than the stacks if the stack
+     * protector is enabled. Alternatively, the .data.stack_protector_canary
+     * section can be placed independently of the main .data section.
+     */
+   .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+    /*
+     * .rela.dyn needs to come after .data for the read-elf utility to parse
+     * this section correctly. Ensure 8-byte alignment so that the fields of
+     * RELA data structure are aligned.
+     */
+    . = ALIGN(8);
+    __RELA_START__ = .;
+    .rela.dyn . : {
+    } >RAM
+    __RELA_END__ = .;
+
+#ifdef BL31_PROGBITS_LIMIT
+    ASSERT(. <= BL31_PROGBITS_LIMIT, "BL31 progbits has exceeded its limit.")
+#endif
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss (NOLOAD) : ALIGN(16) {
+        __BSS_START__ = .;
+        *(.bss*)
+        *(COMMON)
+#if !USE_COHERENT_MEM
+        /*
+         * Bakery locks are stored in normal .bss memory
+         *
+         * Each lock's data is spread across multiple cache lines, one per CPU,
+         * but multiple locks can share the same cache line.
+         * The compiler will allocate enough memory for one CPU's bakery locks,
+         * the remaining cache lines are allocated by the linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __BAKERY_LOCK_START__ = .;
+        __PERCPU_BAKERY_LOCK_START__ = .;
+        *(bakery_lock)
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PERCPU_BAKERY_LOCK_END__ = .;
+        __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(__PERCPU_BAKERY_LOCK_END__ - __PERCPU_BAKERY_LOCK_START__);
+        . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __BAKERY_LOCK_END__ = .;
+
+	/*
+	 * If BL31 doesn't use any bakery lock then __PERCPU_BAKERY_LOCK_SIZE__
+	 * will be zero. For this reason, the only two valid values for
+	 * __PERCPU_BAKERY_LOCK_SIZE__ are 0 or the platform defined value
+	 * PLAT_PERCPU_BAKERY_LOCK_SIZE.
+	 */
+#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
+    ASSERT((__PERCPU_BAKERY_LOCK_SIZE__ == 0) || (__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE),
+        "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements");
+#endif
+#endif
+
+#if ENABLE_PMF
+        /*
+         * Time-stamps are stored in normal .bss memory
+         *
+         * The compiler will allocate enough memory for one CPU's time-stamps,
+         * the remaining memory for other CPUs is allocated by the
+         * linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PMF_TIMESTAMP_START__ = .;
+        KEEP(*(pmf_timestamp_array))
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PMF_PERCPU_TIMESTAMP_END__ = .;
+        __PERCPU_TIMESTAMP_SIZE__ = ABSOLUTE(. - __PMF_TIMESTAMP_START__);
+        . = . + (__PERCPU_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __PMF_TIMESTAMP_END__ = .;
+#endif /* ENABLE_PMF */
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        /*
+         * Bakery locks are stored in coherent memory
+         *
+         * Each lock's data is contiguous and fully allocated by the compiler
+         */
+        *(bakery_lock)
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+    __BL31_END__ = .;
+
+    ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
+}
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
new file mode 100644
index 0000000..c9ba926
--- /dev/null
+++ b/bl31/bl31.mk
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+################################################################################
+# Include SPM Makefile
+################################################################################
+ifeq (${ENABLE_SPM},1)
+  ifeq (${SPM_MM},1)
+    ifeq (${EL3_EXCEPTION_HANDLING},0)
+      $(error EL3_EXCEPTION_HANDLING must be 1 for SPM support)
+    endif
+    $(info Including makefile of SPM based on MM)
+    include services/std_svc/spm_mm/spm.mk
+  else
+    $(info Including SPM makefile)
+    include services/std_svc/spm/spm.mk
+  endif
+endif
+
+
+include lib/psci/psci_lib.mk
+
+BL31_SOURCES		+=	bl31/bl31_main.c				\
+				bl31/interrupt_mgmt.c				\
+				bl31/aarch64/bl31_entrypoint.S			\
+				bl31/aarch64/crash_reporting.S			\
+				bl31/aarch64/ea_delegate.S			\
+				bl31/aarch64/runtime_exceptions.S		\
+				bl31/bl31_context_mgmt.c			\
+				common/runtime_svc.c				\
+				lib/cpus/aarch64/dsu_helpers.S			\
+				plat/common/aarch64/platform_mp_stack.S		\
+				services/arm_arch_svc/arm_arch_svc_setup.c	\
+				services/std_svc/std_svc_setup.c		\
+				${PSCI_LIB_SOURCES}				\
+				${SPM_SOURCES}
+
+
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES		+=	lib/pmf/pmf_main.c
+endif
+
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES		+=	bl31/ehf.c
+endif
+
+ifeq (${SDEI_SUPPORT},1)
+ifeq (${EL3_EXCEPTION_HANDLING},0)
+  $(error EL3_EXCEPTION_HANDLING must be 1 for SDEI support)
+endif
+BL31_SOURCES		+=	services/std_svc/sdei/sdei_dispatch.S	\
+				services/std_svc/sdei/sdei_event.c	\
+				services/std_svc/sdei/sdei_intr_mgmt.c	\
+				services/std_svc/sdei/sdei_main.c	\
+				services/std_svc/sdei/sdei_state.c
+endif
+
+ifeq (${ENABLE_SPE_FOR_LOWER_ELS},1)
+BL31_SOURCES		+=	lib/extensions/spe/spe.c
+endif
+
+ifeq (${ENABLE_AMU},1)
+BL31_SOURCES		+=	lib/extensions/amu/aarch64/amu.c		\
+				lib/extensions/amu/aarch64/amu_helpers.S
+endif
+
+ifeq (${ENABLE_SVE_FOR_NS},1)
+BL31_SOURCES		+=	lib/extensions/sve/sve.c
+endif
+
+ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1)
+BL31_SOURCES		+=	lib/extensions/mpam/mpam.c
+endif
+
+ifeq (${WORKAROUND_CVE_2017_5715},1)
+BL31_SOURCES		+=	lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S	\
+				lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
+endif
+
+BL31_LINKERFILE		:=	bl31/bl31.ld.S
+
+# Flag used to indicate if Crash reporting via console should be included
+# in BL31. This defaults to being present in DEBUG builds only
+ifndef CRASH_REPORTING
+CRASH_REPORTING		:=	$(DEBUG)
+endif
+
+$(eval $(call assert_boolean,CRASH_REPORTING))
+$(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
+$(eval $(call assert_boolean,SDEI_SUPPORT))
+
+$(eval $(call add_define,CRASH_REPORTING))
+$(eval $(call add_define,EL3_EXCEPTION_HANDLING))
+$(eval $(call add_define,SDEI_SUPPORT))
diff --git a/bl31/bl31_context_mgmt.c b/bl31/bl31_context_mgmt.c
new file mode 100644
index 0000000..d41979f
--- /dev/null
+++ b/bl31/bl31_context_mgmt.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function returns a pointer to the most recent 'cpu_context' structure
+ * for the calling CPU that was set as the context for the specified security
+ * state. NULL is returned if no such structure has been specified.
+ ******************************************************************************/
+void *cm_get_context(uint32_t security_state)
+{
+	assert(security_state <= NON_SECURE);
+
+	return get_cpu_data(cpu_context[security_state]);
+}
+
+/*******************************************************************************
+ * This function sets the pointer to the current 'cpu_context' structure for the
+ * specified security state for the calling CPU
+ ******************************************************************************/
+void cm_set_context(void *context, uint32_t security_state)
+{
+	assert(security_state <= NON_SECURE);
+
+	set_cpu_data(cpu_context[security_state], context);
+}
+
+/*******************************************************************************
+ * This function returns a pointer to the most recent 'cpu_context' structure
+ * for the CPU identified by `cpu_idx` that was set as the context for the
+ * specified security state. NULL is returned if no such structure has been
+ * specified.
+ ******************************************************************************/
+void *cm_get_context_by_index(unsigned int cpu_idx,
+				unsigned int security_state)
+{
+	assert(sec_state_is_valid(security_state));
+
+	return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]);
+}
+
+/*******************************************************************************
+ * This function sets the pointer to the current 'cpu_context' structure for the
+ * specified security state for the CPU identified by CPU index.
+ ******************************************************************************/
+void cm_set_context_by_index(unsigned int cpu_idx, void *context,
+				unsigned int security_state)
+{
+	assert(sec_state_is_valid(security_state));
+
+	set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context);
+}
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
new file mode 100644
index 0000000..856ea9f
--- /dev/null
+++ b/bl31/bl31_main.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <plat/common/platform.h>
+#include <services/std_svc.h>
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+PMF_REGISTER_SERVICE_SMC(rt_instr_svc, PMF_RT_INSTR_SVC_ID,
+	RT_INSTR_TOTAL_IDS, PMF_STORE_ENABLE)
+#endif
+
+/*******************************************************************************
+ * This function pointer is used to initialise the BL32 image. It's initialized
+ * by SPD calling bl31_register_bl32_init after setting up all things necessary
+ * for SP execution. In cases where both SPD and SP are absent, or when SPD
+ * finds it impossible to execute SP, this pointer is left as NULL
+ ******************************************************************************/
+static int32_t (*bl32_init)(void);
+
+/*******************************************************************************
+ * Variable to indicate whether next image to execute after BL31 is BL33
+ * (non-secure & default) or BL32 (secure).
+ ******************************************************************************/
+static uint32_t next_image_type = NON_SECURE;
+
+/*
+ * Implement the ARM Standard Service function to get arguments for a
+ * particular service.
+ */
+uintptr_t get_arm_std_svc_args(unsigned int svc_mask)
+{
+	/* Setup the arguments for PSCI Library */
+	DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, bl31_warm_entrypoint);
+
+	/* PSCI is the only ARM Standard Service implemented */
+	assert(svc_mask == PSCI_FID_MASK);
+
+	return (uintptr_t)&psci_args;
+}
+
+/*******************************************************************************
+ * Simple function to initialise all BL31 helper libraries.
+ ******************************************************************************/
+void __init bl31_lib_init(void)
+{
+	cm_init();
+}
+
+/*******************************************************************************
+ * Setup function for BL31.
+ ******************************************************************************/
+void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+		u_register_t arg3)
+{
+	/* Perform early platform-specific setup */
+	bl31_early_platform_setup2(arg0, arg1, arg2, arg3);
+
+	/*
+	 * Update pointer authentication key before the MMU is enabled. It is
+	 * saved in the rodata section, that can be writen before enabling the
+	 * MMU. This function must be called after the console is initialized
+	 * in the early platform setup.
+	 */
+	bl_handle_pauth();
+
+	/* Perform late platform-specific setup */
+	bl31_plat_arch_setup();
+}
+
+/*******************************************************************************
+ * BL31 is responsible for setting up the runtime services for the primary cpu
+ * before passing control to the bootloader or an Operating System. This
+ * function calls runtime_svc_init() which initializes all registered runtime
+ * services. The run time services would setup enough context for the core to
+ * switch to the next exception level. When this function returns, the core will
+ * switch to the programmed exception level via an ERET.
+ ******************************************************************************/
+void bl31_main(void)
+{
+	NOTICE("BL31: %s\n", version_string);
+	NOTICE("BL31: %s\n", build_message);
+
+	/* Perform platform setup in BL31 */
+	bl31_platform_setup();
+
+	/* Initialise helper libraries */
+	bl31_lib_init();
+
+#if EL3_EXCEPTION_HANDLING
+	INFO("BL31: Initialising Exception Handling Framework\n");
+	ehf_init();
+#endif
+
+	/* Initialize the runtime services e.g. psci. */
+	INFO("BL31: Initializing runtime services\n");
+	runtime_svc_init();
+
+	/*
+	 * All the cold boot actions on the primary cpu are done. We now need to
+	 * decide which is the next image (BL32 or BL33) and how to execute it.
+	 * If the SPD runtime service is present, it would want to pass control
+	 * to BL32 first in S-EL1. In that case, SPD would have registered a
+	 * function to initialize bl32 where it takes responsibility of entering
+	 * S-EL1 and returning control back to bl31_main. Once this is done we
+	 * can prepare entry into BL33 as normal.
+	 */
+
+	/*
+	 * If SPD had registered an init hook, invoke it.
+	 */
+	if (bl32_init != NULL) {
+		INFO("BL31: Initializing BL32\n");
+
+		int32_t rc = (*bl32_init)();
+
+		if (rc == 0)
+			WARN("BL31: BL32 initialization failed\n");
+	}
+	/*
+	 * We are ready to enter the next EL. Prepare entry into the image
+	 * corresponding to the desired security state after the next ERET.
+	 */
+	bl31_prepare_next_image_entry();
+
+	console_flush();
+
+	/*
+	 * Perform any platform specific runtime setup prior to cold boot exit
+	 * from BL31
+	 */
+	bl31_plat_runtime_setup();
+}
+
+/*******************************************************************************
+ * Accessor functions to help runtime services decide which image should be
+ * executed after BL31. This is BL33 or the non-secure bootloader image by
+ * default but the Secure payload dispatcher could override this by requesting
+ * an entry into BL32 (Secure payload) first. If it does so then it should use
+ * the same API to program an entry into BL33 once BL32 initialisation is
+ * complete.
+ ******************************************************************************/
+void bl31_set_next_image_type(uint32_t security_state)
+{
+	assert(sec_state_is_valid(security_state));
+	next_image_type = security_state;
+}
+
+uint32_t bl31_get_next_image_type(void)
+{
+	return next_image_type;
+}
+
+/*******************************************************************************
+ * This function programs EL3 registers and performs other setup to enable entry
+ * into the next image after BL31 at the next ERET.
+ ******************************************************************************/
+void __init bl31_prepare_next_image_entry(void)
+{
+	entry_point_info_t *next_image_info;
+	uint32_t image_type;
+
+#if CTX_INCLUDE_AARCH32_REGS
+	/*
+	 * Ensure that the build flag to save AArch32 system registers in CPU
+	 * context is not set for AArch64-only platforms.
+	 */
+	if (el_implemented(1) == EL_IMPL_A64ONLY) {
+		ERROR("EL1 supports AArch64-only. Please set build flag "
+				"CTX_INCLUDE_AARCH32_REGS = 0\n");
+		panic();
+	}
+#endif
+
+	/* Determine which image to execute next */
+	image_type = bl31_get_next_image_type();
+
+	/* Program EL3 registers to enable entry into the next EL */
+	next_image_info = bl31_plat_get_next_image_ep_info(image_type);
+	assert(next_image_info != NULL);
+	assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
+
+	INFO("BL31: Preparing for EL3 exit to %s world\n",
+		(image_type == SECURE) ? "secure" : "normal");
+	print_entry_point_info(next_image_info);
+	cm_init_my_context(next_image_info);
+	cm_prepare_el3_exit(image_type);
+}
+
+/*******************************************************************************
+ * This function initializes the pointer to BL32 init function. This is expected
+ * to be called by the SPD after it finishes all its initialization
+ ******************************************************************************/
+void bl31_register_bl32_init(int32_t (*func)(void))
+{
+	bl32_init = func;
+}
diff --git a/bl31/ehf.c b/bl31/ehf.c
new file mode 100644
index 0000000..745f165
--- /dev/null
+++ b/bl31/ehf.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Exception handlers at EL3, their priority levels, and management.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <plat/common/platform.h>
+
+/* Output EHF logs as verbose */
+#define EHF_LOG(...)	VERBOSE("EHF: " __VA_ARGS__)
+
+#define EHF_INVALID_IDX	(-1)
+
+/* For a valid handler, return the actual function pointer; otherwise, 0. */
+#define RAW_HANDLER(h) \
+	((ehf_handler_t) ((((h) & EHF_PRI_VALID_) != 0U) ? \
+		((h) & ~EHF_PRI_VALID_) : 0U))
+
+#define PRI_BIT(idx)	(((ehf_pri_bits_t) 1u) << (idx))
+
+/*
+ * Convert index into secure priority using the platform-defined priority bits
+ * field.
+ */
+#define IDX_TO_PRI(idx) \
+	((((unsigned) idx) << (7u - exception_data.pri_bits)) & 0x7fU)
+
+/* Check whether a given index is valid */
+#define IS_IDX_VALID(idx) \
+	((exception_data.ehf_priorities[idx].ehf_handler & EHF_PRI_VALID_) != 0U)
+
+/* Returns whether given priority is in secure priority range */
+#define IS_PRI_SECURE(pri)	(((pri) & 0x80U) == 0U)
+
+/* To be defined by the platform */
+extern const ehf_priorities_t exception_data;
+
+/* Translate priority to the index in the priority array */
+static unsigned int pri_to_idx(unsigned int priority)
+{
+	unsigned int idx;
+
+	idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits);
+	assert(idx < exception_data.num_priorities);
+	assert(IS_IDX_VALID(idx));
+
+	return idx;
+}
+
+/* Return whether there are outstanding priority activation */
+static bool has_valid_pri_activations(pe_exc_data_t *pe_data)
+{
+	return pe_data->active_pri_bits != 0U;
+}
+
+static pe_exc_data_t *this_cpu_data(void)
+{
+	return &get_cpu_data(ehf_data);
+}
+
+/*
+ * Return the current priority index of this CPU. If no priority is active,
+ * return EHF_INVALID_IDX.
+ */
+static int get_pe_highest_active_idx(pe_exc_data_t *pe_data)
+{
+	if (!has_valid_pri_activations(pe_data))
+		return EHF_INVALID_IDX;
+
+	/* Current priority is the right-most bit */
+	return (int) __builtin_ctz(pe_data->active_pri_bits);
+}
+
+/*
+ * Mark priority active by setting the corresponding bit in active_pri_bits and
+ * programming the priority mask.
+ *
+ * This API is to be used as part of delegating to lower ELs other than for
+ * interrupts; e.g. while handling synchronous exceptions.
+ *
+ * This API is expected to be invoked before restoring context (Secure or
+ * Non-secure) in preparation for the respective dispatch.
+ */
+void ehf_activate_priority(unsigned int priority)
+{
+	int cur_pri_idx;
+	unsigned int old_mask, run_pri, idx;
+	pe_exc_data_t *pe_data = this_cpu_data();
+
+	/*
+	 * Query interrupt controller for the running priority, or idle priority
+	 * if no interrupts are being handled. The requested priority must be
+	 * less (higher priority) than the active running priority.
+	 */
+	run_pri = plat_ic_get_running_priority();
+	if (priority >= run_pri) {
+		ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
+				run_pri, priority);
+		panic();
+	}
+
+	/*
+	 * If there were priority activations already, the requested priority
+	 * must be less (higher priority) than the current highest priority
+	 * activation so far.
+	 */
+	cur_pri_idx = get_pe_highest_active_idx(pe_data);
+	idx = pri_to_idx(priority);
+	if ((cur_pri_idx != EHF_INVALID_IDX) &&
+			(idx >= ((unsigned int) cur_pri_idx))) {
+		ERROR("Activation priority mismatch: req=0x%x current=0x%x\n",
+				priority, IDX_TO_PRI(cur_pri_idx));
+		panic();
+	}
+
+	/* Set the bit corresponding to the requested priority */
+	pe_data->active_pri_bits |= PRI_BIT(idx);
+
+	/*
+	 * Program priority mask for the activated level. Check that the new
+	 * priority mask is setting a higher priority level than the existing
+	 * mask.
+	 */
+	old_mask = plat_ic_set_priority_mask(priority);
+	if (priority >= old_mask) {
+		ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n",
+				priority, old_mask);
+		panic();
+	}
+
+	/*
+	 * If this is the first activation, save the priority mask. This will be
+	 * restored after the last deactivation.
+	 */
+	if (cur_pri_idx == EHF_INVALID_IDX)
+		pe_data->init_pri_mask = (uint8_t) old_mask;
+
+	EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data));
+}
+
+/*
+ * Mark priority inactive by clearing the corresponding bit in active_pri_bits,
+ * and programming the priority mask.
+ *
+ * This API is expected to be used as part of delegating to to lower ELs other
+ * than for interrupts; e.g. while handling synchronous exceptions.
+ *
+ * This API is expected to be invoked after saving context (Secure or
+ * Non-secure), having concluded the respective dispatch.
+ */
+void ehf_deactivate_priority(unsigned int priority)
+{
+	int cur_pri_idx;
+	pe_exc_data_t *pe_data = this_cpu_data();
+	unsigned int old_mask, run_pri, idx;
+
+	/*
+	 * Query interrupt controller for the running priority, or idle priority
+	 * if no interrupts are being handled. The requested priority must be
+	 * less (higher priority) than the active running priority.
+	 */
+	run_pri = plat_ic_get_running_priority();
+	if (priority >= run_pri) {
+		ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
+				run_pri, priority);
+		panic();
+	}
+
+	/*
+	 * Deactivation is allowed only when there are priority activations, and
+	 * the deactivation priority level must match the current activated
+	 * priority.
+	 */
+	cur_pri_idx = get_pe_highest_active_idx(pe_data);
+	idx = pri_to_idx(priority);
+	if ((cur_pri_idx == EHF_INVALID_IDX) ||
+			(idx != ((unsigned int) cur_pri_idx))) {
+		ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n",
+				priority, IDX_TO_PRI(cur_pri_idx));
+		panic();
+	}
+
+	/* Clear bit corresponding to highest priority */
+	pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1u);
+
+	/*
+	 * Restore priority mask corresponding to the next priority, or the
+	 * one stashed earlier if there are no more to deactivate.
+	 */
+	cur_pri_idx = get_pe_highest_active_idx(pe_data);
+	if (cur_pri_idx == EHF_INVALID_IDX)
+		old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
+	else
+		old_mask = plat_ic_set_priority_mask(priority);
+
+	if (old_mask > priority) {
+		ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
+				priority, old_mask);
+		panic();
+	}
+
+	EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data));
+}
+
+/*
+ * After leaving Non-secure world, stash current Non-secure Priority Mask, and
+ * set Priority Mask to the highest Non-secure priority so that Non-secure
+ * interrupts cannot preempt Secure execution.
+ *
+ * If the current running priority is in the secure range, or if there are
+ * outstanding priority activations, this function does nothing.
+ *
+ * This function subscribes to the 'cm_exited_normal_world' event published by
+ * the Context Management Library.
+ */
+static void *ehf_exited_normal_world(const void *arg)
+{
+	unsigned int run_pri;
+	pe_exc_data_t *pe_data = this_cpu_data();
+
+	/* If the running priority is in the secure range, do nothing */
+	run_pri = plat_ic_get_running_priority();
+	if (IS_PRI_SECURE(run_pri))
+		return NULL;
+
+	/* Do nothing if there are explicit activations */
+	if (has_valid_pri_activations(pe_data))
+		return NULL;
+
+	assert(pe_data->ns_pri_mask == 0u);
+
+	pe_data->ns_pri_mask =
+		(uint8_t) plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY);
+
+	/* The previous Priority Mask is not expected to be in secure range */
+	if (IS_PRI_SECURE(pe_data->ns_pri_mask)) {
+		ERROR("Priority Mask (0x%x) already in secure range\n",
+				pe_data->ns_pri_mask);
+		panic();
+	}
+
+	EHF_LOG("Priority Mask: 0x%x => 0x%x\n", pe_data->ns_pri_mask,
+			GIC_HIGHEST_NS_PRIORITY);
+
+	return NULL;
+}
+
+/*
+ * Conclude Secure execution and prepare for return to Non-secure world. Restore
+ * the Non-secure Priority Mask previously stashed upon leaving Non-secure
+ * world.
+ *
+ * If there the current running priority is in the secure range, or if there are
+ * outstanding priority activations, this function does nothing.
+ *
+ * This function subscribes to the 'cm_entering_normal_world' event published by
+ * the Context Management Library.
+ */
+static void *ehf_entering_normal_world(const void *arg)
+{
+	unsigned int old_pmr, run_pri;
+	pe_exc_data_t *pe_data = this_cpu_data();
+
+	/* If the running priority is in the secure range, do nothing */
+	run_pri = plat_ic_get_running_priority();
+	if (IS_PRI_SECURE(run_pri))
+		return NULL;
+
+	/*
+	 * If there are explicit activations, do nothing. The Priority Mask will
+	 * be restored upon the last deactivation.
+	 */
+	if (has_valid_pri_activations(pe_data))
+		return NULL;
+
+	/* Do nothing if we don't have a valid Priority Mask to restore */
+	if (pe_data->ns_pri_mask == 0U)
+		return NULL;
+
+	old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
+
+	/*
+	 * When exiting secure world, the current Priority Mask must be
+	 * GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure
+	 * priority mask set upon calling ehf_allow_ns_preemption()
+	 */
+	if ((old_pmr != GIC_HIGHEST_NS_PRIORITY) &&
+			(old_pmr != pe_data->ns_pri_mask)) {
+		ERROR("Invalid Priority Mask (0x%x) restored\n", old_pmr);
+		panic();
+	}
+
+	EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
+
+	pe_data->ns_pri_mask = 0;
+
+	return NULL;
+}
+
+/*
+ * Program Priority Mask to the original Non-secure priority such that
+ * Non-secure interrupts may preempt Secure execution (for example, during
+ * Yielding SMC calls). The 'preempt_ret_code' parameter indicates the Yielding
+ * SMC's return value in case the call was preempted.
+ *
+ * This API is expected to be invoked before delegating a yielding SMC to Secure
+ * EL1. I.e. within the window of secure execution after Non-secure context is
+ * saved (after entry into EL3) and Secure context is restored (before entering
+ * Secure EL1).
+ */
+void ehf_allow_ns_preemption(uint64_t preempt_ret_code)
+{
+	cpu_context_t *ns_ctx;
+	unsigned int old_pmr __unused;
+	pe_exc_data_t *pe_data = this_cpu_data();
+
+	/*
+	 * We should have been notified earlier of entering secure world, and
+	 * therefore have stashed the Non-secure priority mask.
+	 */
+	assert(pe_data->ns_pri_mask != 0U);
+
+	/* Make sure no priority levels are active when requesting this */
+	if (has_valid_pri_activations(pe_data)) {
+		ERROR("PE %lx has priority activations: 0x%x\n",
+				read_mpidr_el1(), pe_data->active_pri_bits);
+		panic();
+	}
+
+	/*
+	 * Program preempted return code to x0 right away so that, if the
+	 * Yielding SMC was indeed preempted before a dispatcher gets a chance
+	 * to populate it, the caller would find the correct return value.
+	 */
+	ns_ctx = cm_get_context(NON_SECURE);
+	assert(ns_ctx != NULL);
+	write_ctx_reg(get_gpregs_ctx(ns_ctx), CTX_GPREG_X0, preempt_ret_code);
+
+	old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
+
+	EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
+
+	pe_data->ns_pri_mask = 0;
+}
+
+/*
+ * Return whether Secure execution has explicitly allowed Non-secure interrupts
+ * to preempt itself (for example, during Yielding SMC calls).
+ */
+unsigned int ehf_is_ns_preemption_allowed(void)
+{
+	unsigned int run_pri;
+	pe_exc_data_t *pe_data = this_cpu_data();
+
+	/* If running priority is in secure range, return false */
+	run_pri = plat_ic_get_running_priority();
+	if (IS_PRI_SECURE(run_pri))
+		return 0;
+
+	/*
+	 * If Non-secure preemption was permitted by calling
+	 * ehf_allow_ns_preemption() earlier:
+	 *
+	 * - There wouldn't have been priority activations;
+	 * - We would have cleared the stashed the Non-secure Priority Mask.
+	 */
+	if (has_valid_pri_activations(pe_data))
+		return 0;
+	if (pe_data->ns_pri_mask != 0U)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * Top-level EL3 interrupt handler.
+ */
+static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags,
+		void *handle, void *cookie)
+{
+	int ret = 0;
+	uint32_t intr_raw;
+	unsigned int intr, pri, idx;
+	ehf_handler_t handler;
+
+	/*
+	 * Top-level interrupt type handler from Interrupt Management Framework
+	 * doesn't acknowledge the interrupt; so the interrupt ID must be
+	 * invalid.
+	 */
+	assert(id == INTR_ID_UNAVAILABLE);
+
+	/*
+	 * Acknowledge interrupt. Proceed with handling only for valid interrupt
+	 * IDs. This situation may arise because of Interrupt Management
+	 * Framework identifying an EL3 interrupt, but before it's been
+	 * acknowledged here, the interrupt was either deasserted, or there was
+	 * a higher-priority interrupt of another type.
+	 */
+	intr_raw = plat_ic_acknowledge_interrupt();
+	intr = plat_ic_get_interrupt_id(intr_raw);
+	if (intr == INTR_ID_UNAVAILABLE)
+		return 0;
+
+	/* Having acknowledged the interrupt, get the running priority */
+	pri = plat_ic_get_running_priority();
+
+	/* Check EL3 interrupt priority is in secure range */
+	assert(IS_PRI_SECURE(pri));
+
+	/*
+	 * Translate the priority to a descriptor index. We do this by masking
+	 * and shifting the running priority value (platform-supplied).
+	 */
+	idx = pri_to_idx(pri);
+
+	/* Validate priority */
+	assert(pri == IDX_TO_PRI(idx));
+
+	handler = (ehf_handler_t) RAW_HANDLER(
+			exception_data.ehf_priorities[idx].ehf_handler);
+	if (handler == NULL) {
+		ERROR("No EL3 exception handler for priority 0x%x\n",
+				IDX_TO_PRI(idx));
+		panic();
+	}
+
+	/*
+	 * Call registered handler. Pass the raw interrupt value to registered
+	 * handlers.
+	 */
+	ret = handler(intr_raw, flags, handle, cookie);
+
+	return (uint64_t) ret;
+}
+
+/*
+ * Initialize the EL3 exception handling.
+ */
+void __init ehf_init(void)
+{
+	unsigned int flags = 0;
+	int ret __unused;
+
+	/* Ensure EL3 interrupts are supported */
+	assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3) != 0);
+
+	/*
+	 * Make sure that priority water mark has enough bits to represent the
+	 * whole priority array.
+	 */
+	assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8U));
+
+	assert(exception_data.ehf_priorities != NULL);
+
+	/*
+	 * Bit 7 of GIC priority must be 0 for secure interrupts. This means
+	 * platforms must use at least 1 of the remaining 7 bits.
+	 */
+	assert((exception_data.pri_bits >= 1U) ||
+			(exception_data.pri_bits < 8U));
+
+	/* Route EL3 interrupts when in Secure and Non-secure. */
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	set_interrupt_rm_flag(flags, SECURE);
+
+	/* Register handler for EL3 interrupts */
+	ret = register_interrupt_type_handler(INTR_TYPE_EL3,
+			ehf_el3_interrupt_handler, flags);
+	assert(ret == 0);
+}
+
+/*
+ * Register a handler at the supplied priority. Registration is allowed only if
+ * a handler hasn't been registered before, or one wasn't provided at build
+ * time. The priority for which the handler is being registered must also accord
+ * with the platform-supplied data.
+ */
+void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler)
+{
+	unsigned int idx;
+
+	/* Sanity check for handler */
+	assert(handler != NULL);
+
+	/* Handler ought to be 4-byte aligned */
+	assert((((uintptr_t) handler) & 3U) == 0U);
+
+	/* Ensure we register for valid priority */
+	idx = pri_to_idx(pri);
+	assert(idx < exception_data.num_priorities);
+	assert(IDX_TO_PRI(idx) == pri);
+
+	/* Return failure if a handler was already registered */
+	if (exception_data.ehf_priorities[idx].ehf_handler != EHF_NO_HANDLER_) {
+		ERROR("Handler already registered for priority 0x%x\n", pri);
+		panic();
+	}
+
+	/*
+	 * Install handler, and retain the valid bit. We assume that the handler
+	 * is 4-byte aligned, which is usually the case.
+	 */
+	exception_data.ehf_priorities[idx].ehf_handler =
+		(((uintptr_t) handler) | EHF_PRI_VALID_);
+
+	EHF_LOG("register pri=0x%x handler=%p\n", pri, handler);
+}
+
+SUBSCRIBE_TO_EVENT(cm_entering_normal_world, ehf_entering_normal_world);
+SUBSCRIBE_TO_EVENT(cm_exited_normal_world, ehf_exited_normal_world);
diff --git a/bl31/interrupt_mgmt.c b/bl31/interrupt_mgmt.c
new file mode 100644
index 0000000..e6efad3
--- /dev/null
+++ b/bl31/interrupt_mgmt.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <bl31/interrupt_mgmt.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Local structure and corresponding array to keep track of the state of the
+ * registered interrupt handlers for each interrupt type.
+ * The field descriptions are:
+ *
+ * 'flags' : Bit[0], Routing model for this interrupt type when execution is
+ *                   not in EL3 in the secure state. '1' implies that this
+ *                   interrupt will be routed to EL3. '0' implies that this
+ *                   interrupt will be routed to the current exception level.
+ *
+ *           Bit[1], Routing model for this interrupt type when execution is
+ *                   not in EL3 in the non-secure state. '1' implies that this
+ *                   interrupt will be routed to EL3. '0' implies that this
+ *                   interrupt will be routed to the current exception level.
+ *
+ *           All other bits are reserved and SBZ.
+ *
+ * 'scr_el3[2]'  : Mapping of the routing model in the 'flags' field to the
+ *                 value of the SCR_EL3.IRQ or FIQ bit for each security state.
+ *                 There are two instances of this field corresponding to the
+ *                 two security states.
+ ******************************************************************************/
+typedef struct intr_type_desc {
+	interrupt_type_handler_t handler;
+	uint32_t flags;
+	uint32_t scr_el3[2];
+} intr_type_desc_t;
+
+static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES];
+
+/*******************************************************************************
+ * This function validates the interrupt type.
+ ******************************************************************************/
+static int32_t validate_interrupt_type(uint32_t type)
+{
+	if ((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_NS) ||
+	    (type == INTR_TYPE_EL3))
+		return 0;
+
+	return -EINVAL;
+}
+
+/*******************************************************************************
+* This function validates the routing model for this type of interrupt
+ ******************************************************************************/
+static int32_t validate_routing_model(uint32_t type, uint32_t flags)
+{
+	uint32_t rm_flags = (flags >> INTR_RM_FLAGS_SHIFT) & INTR_RM_FLAGS_MASK;
+
+	if (type == INTR_TYPE_S_EL1)
+		return validate_sel1_interrupt_rm(rm_flags);
+
+	if (type == INTR_TYPE_NS)
+		return validate_ns_interrupt_rm(rm_flags);
+
+	if (type == INTR_TYPE_EL3)
+		return validate_el3_interrupt_rm(rm_flags);
+
+	return -EINVAL;
+}
+
+/*******************************************************************************
+ * This function returns the cached copy of the SCR_EL3 which contains the
+ * routing model (expressed through the IRQ and FIQ bits) for a security state
+ * which was stored through a call to 'set_routing_model()' earlier.
+ ******************************************************************************/
+uint32_t get_scr_el3_from_routing_model(uint32_t security_state)
+{
+	uint32_t scr_el3;
+
+	assert(sec_state_is_valid(security_state));
+	scr_el3 = intr_type_descs[INTR_TYPE_NS].scr_el3[security_state];
+	scr_el3 |= intr_type_descs[INTR_TYPE_S_EL1].scr_el3[security_state];
+	scr_el3 |= intr_type_descs[INTR_TYPE_EL3].scr_el3[security_state];
+	return scr_el3;
+}
+
+/*******************************************************************************
+ * This function uses the 'interrupt_type_flags' parameter to obtain the value
+ * of the trap bit (IRQ/FIQ) in the SCR_EL3 for a security state for this
+ * interrupt type. It uses it to update the SCR_EL3 in the cpu context and the
+ * 'intr_type_desc' for that security state.
+ ******************************************************************************/
+static void set_scr_el3_from_rm(uint32_t type,
+				uint32_t interrupt_type_flags,
+				uint32_t security_state)
+{
+	uint32_t flag, bit_pos;
+
+	flag = get_interrupt_rm_flag(interrupt_type_flags, security_state);
+	bit_pos = plat_interrupt_type_to_line(type, security_state);
+	intr_type_descs[type].scr_el3[security_state] = flag << bit_pos;
+
+	/*
+	 * Update scr_el3 only if there is a context available. If not, it
+	 * will be updated later during context initialization which will obtain
+	 * the scr_el3 value to be used via get_scr_el3_from_routing_model()
+	 */
+	if (cm_get_context(security_state) != NULL)
+		cm_write_scr_el3_bit(security_state, bit_pos, flag);
+}
+
+/*******************************************************************************
+ * This function validates the routing model specified in the 'flags' and
+ * updates internal data structures to reflect the new routing model. It also
+ * updates the copy of SCR_EL3 for each security state with the new routing
+ * model in the 'cpu_context' structure for this cpu.
+ ******************************************************************************/
+int32_t set_routing_model(uint32_t type, uint32_t flags)
+{
+	int32_t rc;
+
+	rc = validate_interrupt_type(type);
+	if (rc != 0)
+		return rc;
+
+	rc = validate_routing_model(type, flags);
+	if (rc != 0)
+		return rc;
+
+	/* Update the routing model in internal data structures */
+	intr_type_descs[type].flags = flags;
+	set_scr_el3_from_rm(type, flags, SECURE);
+	set_scr_el3_from_rm(type, flags, NON_SECURE);
+
+	return 0;
+}
+
+/******************************************************************************
+ * This function disables the routing model of interrupt 'type' from the
+ * specified 'security_state' on the local core. The disable is in effect
+ * till the core powers down or till the next enable for that interrupt
+ * type.
+ *****************************************************************************/
+int disable_intr_rm_local(uint32_t type, uint32_t security_state)
+{
+	uint32_t bit_pos, flag;
+
+	assert(intr_type_descs[type].handler != NULL);
+
+	flag = get_interrupt_rm_flag(INTR_DEFAULT_RM, security_state);
+
+	bit_pos = plat_interrupt_type_to_line(type, security_state);
+	cm_write_scr_el3_bit(security_state, bit_pos, flag);
+
+	return 0;
+}
+
+/******************************************************************************
+ * This function enables the routing model of interrupt 'type' from the
+ * specified 'security_state' on the local core.
+ *****************************************************************************/
+int enable_intr_rm_local(uint32_t type, uint32_t security_state)
+{
+	uint32_t bit_pos, flag;
+
+	assert(intr_type_descs[type].handler != NULL);
+
+	flag = get_interrupt_rm_flag(intr_type_descs[type].flags,
+				security_state);
+
+	bit_pos = plat_interrupt_type_to_line(type, security_state);
+	cm_write_scr_el3_bit(security_state, bit_pos, flag);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function registers a handler for the 'type' of interrupt specified. It
+ * also validates the routing model specified in the 'flags' for this type of
+ * interrupt.
+ ******************************************************************************/
+int32_t register_interrupt_type_handler(uint32_t type,
+					interrupt_type_handler_t handler,
+					uint32_t flags)
+{
+	int32_t rc;
+
+	/* Validate the 'handler' parameter */
+	if (handler == NULL)
+		return -EINVAL;
+
+	/* Validate the 'flags' parameter */
+	if ((flags & INTR_TYPE_FLAGS_MASK) != 0U)
+		return -EINVAL;
+
+	/* Check if a handler has already been registered */
+	if (intr_type_descs[type].handler != NULL)
+		return -EALREADY;
+
+	rc = set_routing_model(type, flags);
+	if (rc != 0)
+		return rc;
+
+	/* Save the handler */
+	intr_type_descs[type].handler = handler;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function is called when an interrupt is generated and returns the
+ * handler for the interrupt type (if registered). It returns NULL if the
+ * interrupt type is not supported or its handler has not been registered.
+ ******************************************************************************/
+interrupt_type_handler_t get_interrupt_type_handler(uint32_t type)
+{
+	if (validate_interrupt_type(type) != 0)
+		return NULL;
+
+	return intr_type_descs[type].handler;
+}
+
diff --git a/bl32/optee/optee.mk b/bl32/optee/optee.mk
new file mode 100644
index 0000000..c8aa7ce
--- /dev/null
+++ b/bl32/optee/optee.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2016-2019, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# This makefile only aims at complying with Trusted Firmware-A build process so
+# that "optee" is a valid TF-A AArch32 Secure Playload identifier.
+
+ifneq ($(ARCH),aarch32)
+$(error This directory targets AArch32 support)
+endif
+
+$(eval $(call add_define,AARCH32_SP_OPTEE))
+
+$(info Trusted Firmware-A built for OP-TEE payload support)
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
new file mode 100644
index 0000000..2ffef6a
--- /dev/null
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <el3_common_macros.S>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <smccc_helpers.h>
+#include <smccc_macros.S>
+
+	.globl	sp_min_vector_table
+	.globl	sp_min_entrypoint
+	.globl	sp_min_warm_entrypoint
+	.globl	sp_min_handle_smc
+	.globl	sp_min_handle_fiq
+
+	.macro route_fiq_to_sp_min reg
+		/* -----------------------------------------------------
+		 * FIQs are secure interrupts trapped by Monitor and non
+		 * secure is not allowed to mask the FIQs.
+		 * -----------------------------------------------------
+		 */
+		ldcopr	\reg, SCR
+		orr	\reg, \reg, #SCR_FIQ_BIT
+		bic	\reg, \reg, #SCR_FW_BIT
+		stcopr	\reg, SCR
+	.endm
+
+	.macro clrex_on_monitor_entry
+#if (ARM_ARCH_MAJOR == 7)
+	/*
+	 * ARMv7 architectures need to clear the exclusive access when
+	 * entering Monitor mode.
+	 */
+	clrex
+#endif
+	.endm
+
+vector_base sp_min_vector_table
+	b	sp_min_entrypoint
+	b	plat_panic_handler	/* Undef */
+	b	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+	b	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
+	b	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+
+/*
+ * The Cold boot/Reset entrypoint for SP_MIN
+ */
+func sp_min_entrypoint
+#if !RESET_TO_SP_MIN
+	/* ---------------------------------------------------------------
+	 * Preceding bootloader has populated r0 with a pointer to a
+	 * 'bl_params_t' structure & r1 with a pointer to platform
+	 * specific structure
+	 * ---------------------------------------------------------------
+	 */
+	mov	r9, r0
+	mov	r10, r1
+	mov	r11, r2
+	mov	r12, r3
+
+	/* ---------------------------------------------------------------------
+	 * For !RESET_TO_SP_MIN systems, only the primary CPU ever reaches
+	 * sp_min_entrypoint() during the cold boot flow, so the cold/warm boot
+	 * and primary/secondary CPU logic should not be executed in this case.
+	 *
+	 * Also, assume that the previous bootloader has already initialised the
+	 * SCTLR, including the CPU endianness, and has initialised the memory.
+	 * ---------------------------------------------------------------------
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=0					\
+		_warm_boot_mailbox=0				\
+		_secondary_cold_boot=0				\
+		_init_memory=0					\
+		_init_c_runtime=1				\
+		_exception_vectors=sp_min_vector_table
+
+	/* ---------------------------------------------------------------------
+	 * Relay the previous bootloader's arguments to the platform layer
+	 * ---------------------------------------------------------------------
+	 */
+#else
+	/* ---------------------------------------------------------------------
+	 * For RESET_TO_SP_MIN systems which have a programmable reset address,
+	 * sp_min_entrypoint() is executed only on the cold boot path so we can
+	 * skip the warm boot mailbox mechanism.
+	 * ---------------------------------------------------------------------
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=1					\
+		_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS	\
+		_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU	\
+		_init_memory=1					\
+		_init_c_runtime=1				\
+		_exception_vectors=sp_min_vector_table
+
+	/* ---------------------------------------------------------------------
+	 * For RESET_TO_SP_MIN systems, BL32 (SP_MIN) is the first bootloader
+	 * to run so there's no argument to relay from a previous bootloader.
+	 * Zero the arguments passed to the platform layer to reflect that.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	r9, #0
+	mov	r10, #0
+	mov	r11, #0
+	mov	r12, #0
+
+#endif /* RESET_TO_SP_MIN */
+
+#if SP_MIN_WITH_SECURE_FIQ
+	route_fiq_to_sp_min r4
+#endif
+
+	mov	r0, r9
+	mov	r1, r10
+	mov	r2, r11
+	mov	r3, r12
+	bl	sp_min_early_platform_setup2
+	bl	sp_min_plat_arch_setup
+
+	/* Jump to the main function */
+	bl	sp_min_main
+
+	/* -------------------------------------------------------------
+	 * Clean the .data & .bss sections to main memory. This ensures
+	 * that any global data which was initialised by the primary CPU
+	 * is visible to secondary CPUs before they enable their data
+	 * caches and participate in coherency.
+	 * -------------------------------------------------------------
+	 */
+	ldr	r0, =__DATA_START__
+	ldr	r1, =__DATA_END__
+	sub	r1, r1, r0
+	bl	clean_dcache_range
+
+	ldr	r0, =__BSS_START__
+	ldr	r1, =__BSS_END__
+	sub	r1, r1, r0
+	bl	clean_dcache_range
+
+	bl	smc_get_next_ctx
+
+	/* r0 points to `smc_ctx_t` */
+	/* The PSCI cpu_context registers have been copied to `smc_ctx_t` */
+	b	sp_min_exit
+endfunc sp_min_entrypoint
+
+
+/*
+ * SMC handling function for SP_MIN.
+ */
+func sp_min_handle_smc
+	/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
+	str	lr, [sp, #SMC_CTX_LR_MON]
+
+	smccc_save_gp_mode_regs
+
+	clrex_on_monitor_entry
+
+	/*
+	 * `sp` still points to `smc_ctx_t`. Save it to a register
+	 * and restore the C runtime stack pointer to `sp`.
+	 */
+	mov	r2, sp				/* handle */
+	ldr	sp, [r2, #SMC_CTX_SP_MON]
+
+	ldr	r0, [r2, #SMC_CTX_SCR]
+	and	r3, r0, #SCR_NS_BIT		/* flags */
+
+	/* Switch to Secure Mode*/
+	bic	r0, #SCR_NS_BIT
+	stcopr	r0, SCR
+	isb
+
+	/*
+	 * Set PMCR.DP to 1 to prohibit cycle counting whilst in Secure Mode.
+	 * Also, the PMCR.LC field has an architecturally UNKNOWN value on reset
+	 * and so set to 1 as ARM has deprecated use of PMCR.LC=0.
+	 */
+	ldcopr	r0, PMCR
+	orr	r0, r0, #(PMCR_LC_BIT | PMCR_DP_BIT)
+	stcopr	r0, PMCR
+
+	ldr	r0, [r2, #SMC_CTX_GPREG_R0]	/* smc_fid */
+	/* Check whether an SMC64 is issued */
+	tst	r0, #(FUNCID_CC_MASK << FUNCID_CC_SHIFT)
+	beq	1f
+	/* SMC32 is not detected. Return error back to caller */
+	mov	r0, #SMC_UNK
+	str	r0, [r2, #SMC_CTX_GPREG_R0]
+	mov	r0, r2
+	b	sp_min_exit
+1:
+	/* SMC32 is detected */
+	mov	r1, #0				/* cookie */
+	bl	handle_runtime_svc
+
+	/* `r0` points to `smc_ctx_t` */
+	b	sp_min_exit
+endfunc sp_min_handle_smc
+
+/*
+ * Secure Interrupts handling function for SP_MIN.
+ */
+func sp_min_handle_fiq
+#if !SP_MIN_WITH_SECURE_FIQ
+	b plat_panic_handler
+#else
+	/* FIQ has a +4 offset for lr compared to preferred return address */
+	sub	lr, lr, #4
+	/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
+	str	lr, [sp, #SMC_CTX_LR_MON]
+
+	smccc_save_gp_mode_regs
+
+	clrex_on_monitor_entry
+
+	/* load run-time stack */
+	mov	r2, sp
+	ldr	sp, [r2, #SMC_CTX_SP_MON]
+
+	/* Switch to Secure Mode */
+	ldr	r0, [r2, #SMC_CTX_SCR]
+	bic	r0, #SCR_NS_BIT
+	stcopr	r0, SCR
+	isb
+
+	/*
+	 * Set PMCR.DP to 1 to prohibit cycle counting whilst in Secure Mode.
+	 * Also, the PMCR.LC field has an architecturally UNKNOWN value on reset
+	 * and so set to 1 as ARM has deprecated use of PMCR.LC=0.
+	 */
+	ldcopr	r0, PMCR
+	orr	r0, r0, #(PMCR_LC_BIT | PMCR_DP_BIT)
+	stcopr	r0, PMCR
+
+	push	{r2, r3}
+	bl	sp_min_fiq
+	pop	{r0, r3}
+
+	b	sp_min_exit
+#endif
+endfunc sp_min_handle_fiq
+
+/*
+ * The Warm boot entrypoint for SP_MIN.
+ */
+func sp_min_warm_entrypoint
+	/*
+	 * On the warm boot path, most of the EL3 initialisations performed by
+	 * 'el3_entrypoint_common' must be skipped:
+	 *
+	 *  - Only when the platform bypasses the BL1/BL32 (SP_MIN) entrypoint by
+	 *    programming the reset address do we need to initialied the SCTLR.
+	 *    In other cases, we assume this has been taken care by the
+	 *    entrypoint code.
+	 *
+	 *  - No need to determine the type of boot, we know it is a warm boot.
+	 *
+	 *  - Do not try to distinguish between primary and secondary CPUs, this
+	 *    notion only exists for a cold boot.
+	 *
+	 *  - No need to initialise the memory or the C runtime environment,
+	 *    it has been done once and for all on the cold boot path.
+	 */
+	el3_entrypoint_common					\
+		_init_sctlr=PROGRAMMABLE_RESET_ADDRESS		\
+		_warm_boot_mailbox=0				\
+		_secondary_cold_boot=0				\
+		_init_memory=0					\
+		_init_c_runtime=0				\
+		_exception_vectors=sp_min_vector_table
+
+	/*
+	 * We're about to enable MMU and participate in PSCI state coordination.
+	 *
+	 * The PSCI implementation invokes platform routines that enable CPUs to
+	 * participate in coherency. On a system where CPUs are not
+	 * cache-coherent without appropriate platform specific programming,
+	 * having caches enabled until such time might lead to coherency issues
+	 * (resulting from stale data getting speculatively fetched, among
+	 * others). Therefore we keep data caches disabled even after enabling
+	 * the MMU for such platforms.
+	 *
+	 * On systems with hardware-assisted coherency, or on single cluster
+	 * platforms, such platform specific programming is not required to
+	 * enter coherency (as CPUs already are); and there's no reason to have
+	 * caches disabled either.
+	 */
+#if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY
+	mov	r0, #0
+#else
+	mov	r0, #DISABLE_DCACHE
+#endif
+	bl	bl32_plat_enable_mmu
+
+#if SP_MIN_WITH_SECURE_FIQ
+	route_fiq_to_sp_min r0
+#endif
+
+	bl	sp_min_warm_boot
+	bl	smc_get_next_ctx
+	/* r0 points to `smc_ctx_t` */
+	/* The PSCI cpu_context registers have been copied to `smc_ctx_t` */
+	b	sp_min_exit
+endfunc sp_min_warm_entrypoint
+
+/*
+ * The function to restore the registers from SMC context and return
+ * to the mode restored to SPSR.
+ *
+ * Arguments : r0 must point to the SMC context to restore from.
+ */
+func sp_min_exit
+	monitor_exit
+endfunc sp_min_exit
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
new file mode 100644
index 0000000..4559903
--- /dev/null
+++ b/bl32/sp_min/sp_min.ld.S
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+ENTRY(sp_min_vector_table)
+
+MEMORY {
+    RAM (rwx): ORIGIN = BL32_BASE, LENGTH = BL32_LIMIT - BL32_BASE
+}
+
+#ifdef PLAT_SP_MIN_EXTRA_LD_SCRIPT
+#include <plat_sp_min.ld.S>
+#endif
+
+SECTIONS
+{
+    . = BL32_BASE;
+   ASSERT(. == ALIGN(PAGE_SIZE),
+          "BL32_BASE address is not aligned on a page boundary.")
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+    } >RAM
+
+     /* .ARM.extab and .ARM.exidx are only added because Clang need them */
+     .ARM.extab . : {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+     } >RAM
+
+     .ARM.exidx . : {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+     } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 4-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(4);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+        /*
+         * Ensure 4-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(4);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_END__ = .;
+    } >RAM
+#else
+    ro . : {
+        __RO_START__ = .;
+        *entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        /* Ensure 4-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(4);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+        /*
+         * Ensure 4-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(4);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /* Place pubsub sections for events */
+        . = ALIGN(8);
+#include <lib/el3_runtime/pubsub_events.h>
+
+        *(.vectors)
+        __RO_END_UNALIGNED__ = .;
+
+        /*
+         * Memory page(s) mapped to this section will be marked as
+         * read-only, executable.  No RW data from the next section must
+         * creep in.  Ensure the rest of the current memory block is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __RO_END__ = .;
+    } >RAM
+#endif
+
+    ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
+           "cpu_ops not defined for this platform.")
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+#ifdef BL32_PROGBITS_LIMIT
+    ASSERT(. <= BL32_PROGBITS_LIMIT, "BL32 progbits has exceeded its limit.")
+#endif
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 8-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss (NOLOAD) : ALIGN(8) {
+        __BSS_START__ = .;
+        *(.bss*)
+        *(COMMON)
+#if !USE_COHERENT_MEM
+        /*
+         * Bakery locks are stored in normal .bss memory
+         *
+         * Each lock's data is spread across multiple cache lines, one per CPU,
+         * but multiple locks can share the same cache line.
+         * The compiler will allocate enough memory for one CPU's bakery locks,
+         * the remaining cache lines are allocated by the linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __BAKERY_LOCK_START__ = .;
+        __PERCPU_BAKERY_LOCK_START__ = .;
+        *(bakery_lock)
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PERCPU_BAKERY_LOCK_END__ = .;
+        __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(__PERCPU_BAKERY_LOCK_END__ - __PERCPU_BAKERY_LOCK_START__);
+        . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __BAKERY_LOCK_END__ = .;
+#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
+    ASSERT(__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE,
+        "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements");
+#endif
+#endif
+
+#if ENABLE_PMF
+        /*
+         * Time-stamps are stored in normal .bss memory
+         *
+         * The compiler will allocate enough memory for one CPU's time-stamps,
+         * the remaining memory for other CPUs is allocated by the
+         * linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PMF_TIMESTAMP_START__ = .;
+        KEEP(*(pmf_timestamp_array))
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PMF_PERCPU_TIMESTAMP_END__ = .;
+        __PERCPU_TIMESTAMP_SIZE__ = ABSOLUTE(. - __PMF_TIMESTAMP_START__);
+        . = . + (__PERCPU_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __PMF_TIMESTAMP_END__ = .;
+#endif /* ENABLE_PMF */
+
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+     __BSS_SIZE__ = SIZEOF(.bss);
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        /*
+         * Bakery locks are stored in coherent memory
+         *
+         * Each lock's data is contiguous and fully allocated by the compiler
+         */
+        *(bakery_lock)
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+
+   __BL32_END__ = .;
+}
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
new file mode 100644
index 0000000..6233299
--- /dev/null
+++ b/bl32/sp_min/sp_min.mk
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH}, aarch32)
+	$(error SP_MIN is only supported on AArch32 platforms)
+endif
+
+include lib/psci/psci_lib.mk
+
+INCLUDES		+=	-Iinclude/bl32/sp_min
+
+BL32_SOURCES		+=	bl32/sp_min/sp_min_main.c		\
+				bl32/sp_min/aarch32/entrypoint.S	\
+				common/runtime_svc.c			\
+				plat/common/aarch32/plat_sp_min_common.c\
+				services/std_svc/std_svc_setup.c	\
+				${PSCI_LIB_SOURCES}
+
+ifeq (${ENABLE_PMF}, 1)
+BL32_SOURCES		+=	lib/pmf/pmf_main.c
+endif
+
+ifeq (${ENABLE_AMU}, 1)
+BL32_SOURCES		+=	lib/extensions/amu/aarch32/amu.c\
+				lib/extensions/amu/aarch32/amu_helpers.S
+endif
+
+ifeq (${WORKAROUND_CVE_2017_5715},1)
+BL32_SOURCES		+=	bl32/sp_min/wa_cve_2017_5715_bpiall.S	\
+				bl32/sp_min/wa_cve_2017_5715_icache_inv.S
+endif
+
+BL32_LINKERFILE	:=	bl32/sp_min/sp_min.ld.S
+
+# Include the platform-specific SP_MIN Makefile
+# If no platform-specific SP_MIN Makefile exists, it means SP_MIN is not supported
+# on this platform.
+SP_MIN_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/sp_min/sp_min-${PLAT}.mk)
+ifeq (,${SP_MIN_PLAT_MAKEFILE})
+  $(error SP_MIN is not supported on platform ${PLAT})
+else
+  include ${SP_MIN_PLAT_MAKEFILE}
+endif
+
+RESET_TO_SP_MIN	:= 0
+$(eval $(call add_define,RESET_TO_SP_MIN))
+$(eval $(call assert_boolean,RESET_TO_SP_MIN))
+
+# Flag to allow SP_MIN to handle FIQ interrupts in monitor mode. The platform
+# port is free to override this value. It is default disabled.
+SP_MIN_WITH_SECURE_FIQ 	?= 0
+$(eval $(call add_define,SP_MIN_WITH_SECURE_FIQ))
+$(eval $(call assert_boolean,SP_MIN_WITH_SECURE_FIQ))
diff --git a/bl32/sp_min/sp_min_main.c b/bl32/sp_min/sp_min_main.c
new file mode 100644
index 0000000..f39e33b
--- /dev/null
+++ b/bl32/sp_min/sp_min_main.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_sp_min.h>
+#include <services/std_svc.h>
+#include <smccc_helpers.h>
+
+#include "sp_min_private.h"
+
+/* Pointers to per-core cpu contexts */
+static void *sp_min_cpu_ctx_ptr[PLATFORM_CORE_COUNT];
+
+/* SP_MIN only stores the non secure smc context */
+static smc_ctx_t sp_min_smc_context[PLATFORM_CORE_COUNT];
+
+/******************************************************************************
+ * Define the smccc helper library APIs
+ *****************************************************************************/
+void *smc_get_ctx(unsigned int security_state)
+{
+	assert(security_state == NON_SECURE);
+	return &sp_min_smc_context[plat_my_core_pos()];
+}
+
+void smc_set_next_ctx(unsigned int security_state)
+{
+	assert(security_state == NON_SECURE);
+	/* SP_MIN stores only non secure smc context. Nothing to do here */
+}
+
+void *smc_get_next_ctx(void)
+{
+	return &sp_min_smc_context[plat_my_core_pos()];
+}
+
+/*******************************************************************************
+ * This function returns a pointer to the most recent 'cpu_context' structure
+ * for the calling CPU that was set as the context for the specified security
+ * state. NULL is returned if no such structure has been specified.
+ ******************************************************************************/
+void *cm_get_context(uint32_t security_state)
+{
+	assert(security_state == NON_SECURE);
+	return sp_min_cpu_ctx_ptr[plat_my_core_pos()];
+}
+
+/*******************************************************************************
+ * This function sets the pointer to the current 'cpu_context' structure for the
+ * specified security state for the calling CPU
+ ******************************************************************************/
+void cm_set_context(void *context, uint32_t security_state)
+{
+	assert(security_state == NON_SECURE);
+	sp_min_cpu_ctx_ptr[plat_my_core_pos()] = context;
+}
+
+/*******************************************************************************
+ * This function returns a pointer to the most recent 'cpu_context' structure
+ * for the CPU identified by `cpu_idx` that was set as the context for the
+ * specified security state. NULL is returned if no such structure has been
+ * specified.
+ ******************************************************************************/
+void *cm_get_context_by_index(unsigned int cpu_idx,
+				unsigned int security_state)
+{
+	assert(security_state == NON_SECURE);
+	return sp_min_cpu_ctx_ptr[cpu_idx];
+}
+
+/*******************************************************************************
+ * This function sets the pointer to the current 'cpu_context' structure for the
+ * specified security state for the CPU identified by CPU index.
+ ******************************************************************************/
+void cm_set_context_by_index(unsigned int cpu_idx, void *context,
+				unsigned int security_state)
+{
+	assert(security_state == NON_SECURE);
+	sp_min_cpu_ctx_ptr[cpu_idx] = context;
+}
+
+static void copy_cpu_ctx_to_smc_stx(const regs_t *cpu_reg_ctx,
+				smc_ctx_t *next_smc_ctx)
+{
+	next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0);
+	next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1);
+	next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2);
+	next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR);
+	next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR);
+	next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR);
+}
+
+/*******************************************************************************
+ * This function invokes the PSCI library interface to initialize the
+ * non secure cpu context and copies the relevant cpu context register values
+ * to smc context. These registers will get programmed during `smc_exit`.
+ ******************************************************************************/
+static void sp_min_prepare_next_image_entry(void)
+{
+	entry_point_info_t *next_image_info;
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	u_register_t ns_sctlr;
+
+	/* Program system registers to proceed to non-secure */
+	next_image_info = sp_min_plat_get_bl33_ep_info();
+	assert(next_image_info);
+	assert(NON_SECURE == GET_SECURITY_STATE(next_image_info->h.attr));
+
+	INFO("SP_MIN: Preparing exit to normal world\n");
+
+	psci_prepare_next_non_secure_ctx(next_image_info);
+	smc_set_next_ctx(NON_SECURE);
+
+	/* Copy r0, lr and spsr from cpu context to SMC context */
+	copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
+			smc_get_next_ctx());
+
+	/* Temporarily set the NS bit to access NS SCTLR */
+	write_scr(read_scr() | SCR_NS_BIT);
+	isb();
+	ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
+	write_sctlr(ns_sctlr);
+	isb();
+
+	write_scr(read_scr() & ~SCR_NS_BIT);
+	isb();
+}
+
+/******************************************************************************
+ * Implement the ARM Standard Service function to get arguments for a
+ * particular service.
+ *****************************************************************************/
+uintptr_t get_arm_std_svc_args(unsigned int svc_mask)
+{
+	/* Setup the arguments for PSCI Library */
+	DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, sp_min_warm_entrypoint);
+
+	/* PSCI is the only ARM Standard Service implemented */
+	assert(svc_mask == PSCI_FID_MASK);
+
+	return (uintptr_t)&psci_args;
+}
+
+/******************************************************************************
+ * The SP_MIN main function. Do the platform and PSCI Library setup. Also
+ * initialize the runtime service framework.
+ *****************************************************************************/
+void sp_min_main(void)
+{
+	NOTICE("SP_MIN: %s\n", version_string);
+	NOTICE("SP_MIN: %s\n", build_message);
+
+	/* Perform the SP_MIN platform setup */
+	sp_min_platform_setup();
+
+	/* Initialize the runtime services e.g. psci */
+	INFO("SP_MIN: Initializing runtime services\n");
+	runtime_svc_init();
+
+	/*
+	 * We are ready to enter the next EL. Prepare entry into the image
+	 * corresponding to the desired security state after the next ERET.
+	 */
+	sp_min_prepare_next_image_entry();
+
+	/*
+	 * Perform any platform specific runtime setup prior to cold boot exit
+	 * from SP_MIN.
+	 */
+	sp_min_plat_runtime_setup();
+
+	console_flush();
+}
+
+/******************************************************************************
+ * This function is invoked during warm boot. Invoke the PSCI library
+ * warm boot entry point which takes care of Architectural and platform setup/
+ * restore. Copy the relevant cpu_context register values to smc context which
+ * will get programmed during `smc_exit`.
+ *****************************************************************************/
+void sp_min_warm_boot(void)
+{
+	smc_ctx_t *next_smc_ctx;
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	u_register_t ns_sctlr;
+
+	psci_warmboot_entrypoint();
+
+	smc_set_next_ctx(NON_SECURE);
+
+	next_smc_ctx = smc_get_next_ctx();
+	zeromem(next_smc_ctx, sizeof(smc_ctx_t));
+
+	copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
+			next_smc_ctx);
+
+	/* Temporarily set the NS bit to access NS SCTLR */
+	write_scr(read_scr() | SCR_NS_BIT);
+	isb();
+	ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
+	write_sctlr(ns_sctlr);
+	isb();
+
+	write_scr(read_scr() & ~SCR_NS_BIT);
+	isb();
+}
+
+#if SP_MIN_WITH_SECURE_FIQ
+/******************************************************************************
+ * This function is invoked on secure interrupts. By construction of the
+ * SP_MIN, secure interrupts can only be handled when core executes in non
+ * secure state.
+ *****************************************************************************/
+void sp_min_fiq(void)
+{
+	uint32_t id;
+
+	id = plat_ic_acknowledge_interrupt();
+	sp_min_plat_fiq_handler(id);
+	plat_ic_end_of_interrupt(id);
+}
+#endif /* SP_MIN_WITH_SECURE_FIQ */
diff --git a/bl32/sp_min/sp_min_private.h b/bl32/sp_min/sp_min_private.h
new file mode 100644
index 0000000..628581a
--- /dev/null
+++ b/bl32/sp_min/sp_min_private.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP_MIN_PRIVATE_H
+#define SP_MIN_PRIVATE_H
+
+void sp_min_main(void);
+void sp_min_warm_boot(void);
+void sp_min_fiq(void);
+
+#endif /* SP_MIN_PRIVATE_H */
diff --git a/bl32/sp_min/wa_cve_2017_5715_bpiall.S b/bl32/sp_min/wa_cve_2017_5715_bpiall.S
new file mode 100644
index 0000000..385f3d4
--- /dev/null
+++ b/bl32/sp_min/wa_cve_2017_5715_bpiall.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	wa_cve_2017_5715_bpiall_vbar
+
+vector_base wa_cve_2017_5715_bpiall_vbar
+	/* We encode the exception entry in the bottom 3 bits of SP */
+	add	sp, sp, #1	/* Reset: 0b111 */
+	add	sp, sp, #1	/* Undef: 0b110 */
+	add	sp, sp, #1	/* Syscall: 0b101 */
+	add	sp, sp, #1	/* Prefetch abort: 0b100 */
+	add	sp, sp, #1	/* Data abort: 0b011 */
+	add	sp, sp, #1	/* Reserved: 0b010 */
+	add	sp, sp, #1	/* IRQ: 0b001 */
+	nop			/* FIQ: 0b000 */
+
+	/*
+	 * Invalidate the branch predictor, `r0` is a dummy register
+	 * and is unused.
+	 */
+	stcopr	r0, BPIALL
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 *
+	 * Note, if this code is re-used by other secure payloads,
+	 * the below exception entry vectors must be changed to
+	 * the vectors specific to that secure payload.
+	 */
+
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	/* Expected encoding: 0x1 and 0x0 */
+	tst	sp, #1
+	/* Restore original value of SP by clearing the bottom 3 bits */
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+1:
+	tst	sp, #2
+	bne	2f
+
+	/* Expected encoding: 0x4 and 0x5 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+
+2:
+	/* Expected encoding: 0x7 and 0x6 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_entrypoint	/* Reset */
+	b	plat_panic_handler	/* Undef */
+
+3:
+	/* Expected encoding: 0x2 and 0x3 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
diff --git a/bl32/sp_min/wa_cve_2017_5715_icache_inv.S b/bl32/sp_min/wa_cve_2017_5715_icache_inv.S
new file mode 100644
index 0000000..d0a4625
--- /dev/null
+++ b/bl32/sp_min/wa_cve_2017_5715_icache_inv.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	wa_cve_2017_5715_icache_inv_vbar
+
+vector_base wa_cve_2017_5715_icache_inv_vbar
+	/* We encode the exception entry in the bottom 3 bits of SP */
+	add	sp, sp, #1	/* Reset: 0b111 */
+	add	sp, sp, #1	/* Undef: 0b110 */
+	add	sp, sp, #1	/* Syscall: 0b101 */
+	add	sp, sp, #1	/* Prefetch abort: 0b100 */
+	add	sp, sp, #1	/* Data abort: 0b011 */
+	add	sp, sp, #1	/* Reserved: 0b010 */
+	add	sp, sp, #1	/* IRQ: 0b001 */
+	nop			/* FIQ: 0b000 */
+
+	/*
+	 * Invalidate the instruction cache, which we assume also
+	 * invalidates the branch predictor.  This may depend on
+	 * other CPU specific changes (e.g. an ACTLR setting).
+	 */
+	stcopr	r0, ICIALLU
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 *
+	 * Note, if this code is re-used by other secure payloads,
+	 * the below exception entry vectors must be changed to
+	 * the vectors specific to that secure payload.
+	 */
+
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	/* Expected encoding: 0x1 and 0x0 */
+	tst	sp, #1
+	/* Restore original value of SP by clearing the bottom 3 bits */
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+1:
+	/* Expected encoding: 0x4 and 0x5 */
+	tst	sp, #2
+	bne	2f
+
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+
+2:
+	/* Expected encoding: 0x7 and 0x6 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_entrypoint	/* Reset */
+	b	plat_panic_handler	/* Undef */
+
+3:
+	/* Expected encoding: 0x2 and 0x3 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S
new file mode 100644
index 0000000..fd6b0fb
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_entrypoint.S
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl32/tsp/tsp.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include "../tsp_private.h"
+
+
+	.globl	tsp_entrypoint
+	.globl  tsp_vector_table
+
+
+
+	/* ---------------------------------------------
+	 * Populate the params in x0-x7 from the pointer
+	 * to the smc args structure in x0.
+	 * ---------------------------------------------
+	 */
+	.macro restore_args_call_smc
+	ldp	x6, x7, [x0, #TSP_ARG6]
+	ldp	x4, x5, [x0, #TSP_ARG4]
+	ldp	x2, x3, [x0, #TSP_ARG2]
+	ldp	x0, x1, [x0, #TSP_ARG0]
+	smc	#0
+	.endm
+
+	.macro	save_eret_context reg1 reg2
+	mrs	\reg1, elr_el1
+	mrs	\reg2, spsr_el1
+	stp	\reg1, \reg2, [sp, #-0x10]!
+	stp	x30, x18, [sp, #-0x10]!
+	.endm
+
+	.macro restore_eret_context reg1 reg2
+	ldp	x30, x18, [sp], #0x10
+	ldp	\reg1, \reg2, [sp], #0x10
+	msr	elr_el1, \reg1
+	msr	spsr_el1, \reg2
+	.endm
+
+func tsp_entrypoint _align=3
+
+	/* ---------------------------------------------
+	 * Set the exception vector to something sane.
+	 * ---------------------------------------------
+	 */
+	adr	x0, tsp_exceptions
+	msr	vbar_el1, x0
+	isb
+
+	/* ---------------------------------------------
+	 * Enable the SError interrupt now that the
+	 * exception vectors have been setup.
+	 * ---------------------------------------------
+	 */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	/* ---------------------------------------------
+	 * Enable the instruction cache, stack pointer
+	 * and data access alignment checks and disable
+	 * speculative loads.
+	 * ---------------------------------------------
+	 */
+	mov	x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
+	mrs	x0, sctlr_el1
+	orr	x0, x0, x1
+	bic	x0, x0, #SCTLR_DSSBS_BIT
+	msr	sctlr_el1, x0
+	isb
+
+	/* ---------------------------------------------
+	 * Invalidate the RW memory used by the BL32
+	 * image. This includes the data and NOBITS
+	 * sections. This is done to safeguard against
+	 * possible corruption of this memory by dirty
+	 * cache lines in a system cache as a result of
+	 * use by an earlier boot loader stage.
+	 * ---------------------------------------------
+	 */
+	adr	x0, __RW_START__
+	adr	x1, __RW_END__
+	sub	x1, x1, x0
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Zero out NOBITS sections. There are 2 of them:
+	 *   - the .bss section;
+	 *   - the coherent memory section.
+	 * ---------------------------------------------
+	 */
+	ldr	x0, =__BSS_START__
+	ldr	x1, =__BSS_SIZE__
+	bl	zeromem
+
+#if USE_COHERENT_MEM
+	ldr	x0, =__COHERENT_RAM_START__
+	ldr	x1, =__COHERENT_RAM_UNALIGNED_SIZE__
+	bl	zeromem
+#endif
+
+	/* --------------------------------------------
+	 * Allocate a stack whose memory will be marked
+	 * as Normal-IS-WBWA when the MMU is enabled.
+	 * There is no risk of reading stale stack
+	 * memory after enabling the MMU as only the
+	 * primary cpu is running at the moment.
+	 * --------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+	/* ---------------------------------------------
+	 * Initialize the stack protector canary before
+	 * any C code is called.
+	 * ---------------------------------------------
+	 */
+#if STACK_PROTECTOR_ENABLED
+	bl	update_stack_protector_canary
+#endif
+
+	/* ---------------------------------------------
+	 * Perform TSP setup
+	 * ---------------------------------------------
+	 */
+	bl	tsp_setup
+
+	/* ---------------------------------------------
+	 * Enable pointer authentication
+	 * ---------------------------------------------
+	 */
+#if ENABLE_PAUTH
+	mrs	x0, sctlr_el1
+	orr	x0, x0, #SCTLR_EnIA_BIT
+#if ENABLE_BTI
+	/* ---------------------------------------------
+	 * Enable PAC branch type compatibility
+	 * ---------------------------------------------
+	 */
+	bic	x0, x0, #(SCTLR_BT0_BIT | SCTLR_BT1_BIT)
+#endif	/* ENABLE_BTI */
+	msr	sctlr_el1, x0
+	isb
+#endif /* ENABLE_PAUTH */
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	tsp_main
+
+	/* ---------------------------------------------
+	 * Tell TSPD that we are done initialising
+	 * ---------------------------------------------
+	 */
+	mov	x1, x0
+	mov	x0, #TSP_ENTRY_DONE
+	smc	#0
+
+tsp_entrypoint_panic:
+	b	tsp_entrypoint_panic
+endfunc tsp_entrypoint
+
+
+	/* -------------------------------------------
+	 * Table of entrypoint vectors provided to the
+	 * TSPD for the various entrypoints
+	 * -------------------------------------------
+	 */
+vector_base tsp_vector_table
+	b	tsp_yield_smc_entry
+	b	tsp_fast_smc_entry
+	b	tsp_cpu_on_entry
+	b	tsp_cpu_off_entry
+	b	tsp_cpu_resume_entry
+	b	tsp_cpu_suspend_entry
+	b	tsp_sel1_intr_entry
+	b	tsp_system_off_entry
+	b	tsp_system_reset_entry
+	b	tsp_abort_yield_smc_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD when this
+	 * cpu is to be turned off through a CPU_OFF
+	 * psci call to ask the TSP to perform any
+	 * bookeeping necessary. In the current
+	 * implementation, the TSPD expects the TSP to
+	 * re-initialise its state so nothing is done
+	 * here except for acknowledging the request.
+	 * ---------------------------------------------
+	 */
+func tsp_cpu_off_entry
+	bl	tsp_cpu_off_main
+	restore_args_call_smc
+endfunc tsp_cpu_off_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD when the
+	 * system is about to be switched off (through
+	 * a SYSTEM_OFF psci call) to ask the TSP to
+	 * perform any necessary bookkeeping.
+	 * ---------------------------------------------
+	 */
+func tsp_system_off_entry
+	bl	tsp_system_off_main
+	restore_args_call_smc
+endfunc tsp_system_off_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD when the
+	 * system is about to be reset (through a
+	 * SYSTEM_RESET psci call) to ask the TSP to
+	 * perform any necessary bookkeeping.
+	 * ---------------------------------------------
+	 */
+func tsp_system_reset_entry
+	bl	tsp_system_reset_main
+	restore_args_call_smc
+endfunc tsp_system_reset_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD when this
+	 * cpu is turned on using a CPU_ON psci call to
+	 * ask the TSP to initialise itself i.e. setup
+	 * the mmu, stacks etc. Minimal architectural
+	 * state will be initialised by the TSPD when
+	 * this function is entered i.e. Caches and MMU
+	 * will be turned off, the execution state
+	 * will be aarch64 and exceptions masked.
+	 * ---------------------------------------------
+	 */
+func tsp_cpu_on_entry
+	/* ---------------------------------------------
+	 * Set the exception vector to something sane.
+	 * ---------------------------------------------
+	 */
+	adr	x0, tsp_exceptions
+	msr	vbar_el1, x0
+	isb
+
+	/* Enable the SError interrupt */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	/* ---------------------------------------------
+	 * Enable the instruction cache, stack pointer
+	 * and data access alignment checks
+	 * ---------------------------------------------
+	 */
+	mov	x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
+	mrs	x0, sctlr_el1
+	orr	x0, x0, x1
+	msr	sctlr_el1, x0
+	isb
+
+	/* --------------------------------------------
+	 * Give ourselves a stack whose memory will be
+	 * marked as Normal-IS-WBWA when the MMU is
+	 * enabled.
+	 * --------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+	/* --------------------------------------------
+	 * Enable MMU and D-caches together.
+	 * --------------------------------------------
+	 */
+	mov	x0, #0
+	bl	bl32_plat_enable_mmu
+
+	/* ---------------------------------------------
+	 * Enter C runtime to perform any remaining
+	 * book keeping
+	 * ---------------------------------------------
+	 */
+	bl	tsp_cpu_on_main
+	restore_args_call_smc
+
+	/* Should never reach here */
+tsp_cpu_on_entry_panic:
+	b	tsp_cpu_on_entry_panic
+endfunc tsp_cpu_on_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD when this
+	 * cpu is to be suspended through a CPU_SUSPEND
+	 * psci call to ask the TSP to perform any
+	 * bookeeping necessary. In the current
+	 * implementation, the TSPD saves and restores
+	 * the EL1 state.
+	 * ---------------------------------------------
+	 */
+func tsp_cpu_suspend_entry
+	bl	tsp_cpu_suspend_main
+	restore_args_call_smc
+endfunc tsp_cpu_suspend_entry
+
+	/*-------------------------------------------------
+	 * This entrypoint is used by the TSPD to pass
+	 * control for `synchronously` handling a S-EL1
+	 * Interrupt which was triggered while executing
+	 * in normal world. 'x0' contains a magic number
+	 * which indicates this. TSPD expects control to
+	 * be handed back at the end of interrupt
+	 * processing. This is done through an SMC.
+	 * The handover agreement is:
+	 *
+	 * 1. PSTATE.DAIF are set upon entry. 'x1' has
+	 *    the ELR_EL3 from the non-secure state.
+	 * 2. TSP has to preserve the callee saved
+	 *    general purpose registers, SP_EL1/EL0 and
+	 *    LR.
+	 * 3. TSP has to preserve the system and vfp
+	 *    registers (if applicable).
+	 * 4. TSP can use 'x0-x18' to enable its C
+	 *    runtime.
+	 * 5. TSP returns to TSPD using an SMC with
+	 *    'x0' = TSP_HANDLED_S_EL1_INTR
+	 * ------------------------------------------------
+	 */
+func	tsp_sel1_intr_entry
+#if DEBUG
+	mov_imm	x2, TSP_HANDLE_SEL1_INTR_AND_RETURN
+	cmp	x0, x2
+	b.ne	tsp_sel1_int_entry_panic
+#endif
+	/*-------------------------------------------------
+	 * Save any previous context needed to perform
+	 * an exception return from S-EL1 e.g. context
+	 * from a previous Non secure Interrupt.
+	 * Update statistics and handle the S-EL1
+	 * interrupt before returning to the TSPD.
+	 * IRQ/FIQs are not enabled since that will
+	 * complicate the implementation. Execution
+	 * will be transferred back to the normal world
+	 * in any case. The handler can return 0
+	 * if the interrupt was handled or TSP_PREEMPTED
+	 * if the expected interrupt was preempted
+	 * by an interrupt that should be handled in EL3
+	 * e.g. Group 0 interrupt in GICv3. In both
+	 * the cases switch to EL3 using SMC with id
+	 * TSP_HANDLED_S_EL1_INTR. Any other return value
+	 * from the handler will result in panic.
+	 * ------------------------------------------------
+	 */
+	save_eret_context x2 x3
+	bl	tsp_update_sync_sel1_intr_stats
+	bl	tsp_common_int_handler
+	/* Check if the S-EL1 interrupt has been handled */
+	cbnz	x0, tsp_sel1_intr_check_preemption
+	b	tsp_sel1_intr_return
+tsp_sel1_intr_check_preemption:
+	/* Check if the S-EL1 interrupt has been preempted */
+	mov_imm	x1, TSP_PREEMPTED
+	cmp	x0, x1
+	b.ne	tsp_sel1_int_entry_panic
+tsp_sel1_intr_return:
+	mov_imm	x0, TSP_HANDLED_S_EL1_INTR
+	restore_eret_context x2 x3
+	smc	#0
+
+	/* Should never reach here */
+tsp_sel1_int_entry_panic:
+	no_ret	plat_panic_handler
+endfunc tsp_sel1_intr_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD when this
+	 * cpu resumes execution after an earlier
+	 * CPU_SUSPEND psci call to ask the TSP to
+	 * restore its saved context. In the current
+	 * implementation, the TSPD saves and restores
+	 * EL1 state so nothing is done here apart from
+	 * acknowledging the request.
+	 * ---------------------------------------------
+	 */
+func tsp_cpu_resume_entry
+	bl	tsp_cpu_resume_main
+	restore_args_call_smc
+
+	/* Should never reach here */
+	no_ret	plat_panic_handler
+endfunc tsp_cpu_resume_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD to ask
+	 * the TSP to service a fast smc request.
+	 * ---------------------------------------------
+	 */
+func tsp_fast_smc_entry
+	bl	tsp_smc_handler
+	restore_args_call_smc
+
+	/* Should never reach here */
+	no_ret	plat_panic_handler
+endfunc tsp_fast_smc_entry
+
+	/*---------------------------------------------
+	 * This entrypoint is used by the TSPD to ask
+	 * the TSP to service a Yielding SMC request.
+	 * We will enable preemption during execution
+	 * of tsp_smc_handler.
+	 * ---------------------------------------------
+	 */
+func tsp_yield_smc_entry
+	msr	daifclr, #DAIF_FIQ_BIT | DAIF_IRQ_BIT
+	bl	tsp_smc_handler
+	msr	daifset, #DAIF_FIQ_BIT | DAIF_IRQ_BIT
+	restore_args_call_smc
+
+	/* Should never reach here */
+	no_ret	plat_panic_handler
+endfunc tsp_yield_smc_entry
+
+	/*---------------------------------------------------------------------
+	 * This entrypoint is used by the TSPD to abort a pre-empted Yielding
+	 * SMC. It could be on behalf of non-secure world or because a CPU
+	 * suspend/CPU off request needs to abort the preempted SMC.
+	 * --------------------------------------------------------------------
+	 */
+func tsp_abort_yield_smc_entry
+
+	/*
+	 * Exceptions masking is already done by the TSPD when entering this
+	 * hook so there is no need to do it here.
+	 */
+
+	/* Reset the stack used by the pre-empted SMC */
+	bl	plat_set_my_stack
+
+	/*
+	 * Allow some cleanup such as releasing locks.
+	 */
+	bl	tsp_abort_smc_handler
+
+	restore_args_call_smc
+
+	/* Should never reach here */
+	bl	plat_panic_handler
+endfunc tsp_abort_yield_smc_entry
diff --git a/bl32/tsp/aarch64/tsp_exceptions.S b/bl32/tsp/aarch64/tsp_exceptions.S
new file mode 100644
index 0000000..ad4b648
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_exceptions.S
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+
+	/* ----------------------------------------------------
+	 * The caller-saved registers x0-x18 and LR are saved
+	 * here.
+	 * ----------------------------------------------------
+	 */
+
+#define SCRATCH_REG_SIZE #(20 * 8)
+
+	.macro save_caller_regs_and_lr
+	sub	sp, sp, SCRATCH_REG_SIZE
+	stp	x0, x1, [sp]
+	stp	x2, x3, [sp, #0x10]
+	stp	x4, x5, [sp, #0x20]
+	stp	x6, x7, [sp, #0x30]
+	stp	x8, x9, [sp, #0x40]
+	stp	x10, x11, [sp, #0x50]
+	stp	x12, x13, [sp, #0x60]
+	stp	x14, x15, [sp, #0x70]
+	stp	x16, x17, [sp, #0x80]
+	stp	x18, x30, [sp, #0x90]
+	.endm
+
+	.macro restore_caller_regs_and_lr
+	ldp	x0, x1, [sp]
+	ldp	x2, x3, [sp, #0x10]
+	ldp	x4, x5, [sp, #0x20]
+	ldp	x6, x7, [sp, #0x30]
+	ldp	x8, x9, [sp, #0x40]
+	ldp	x10, x11, [sp, #0x50]
+	ldp	x12, x13, [sp, #0x60]
+	ldp	x14, x15, [sp, #0x70]
+	ldp	x16, x17, [sp, #0x80]
+	ldp	x18, x30, [sp, #0x90]
+	add	sp, sp, SCRATCH_REG_SIZE
+	.endm
+
+	/* ----------------------------------------------------
+	 * Common TSP interrupt handling routine
+	 * ----------------------------------------------------
+	 */
+	.macro	handle_tsp_interrupt label
+	/* Enable the SError interrupt */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	save_caller_regs_and_lr
+	bl	tsp_common_int_handler
+	cbz	x0, interrupt_exit_\label
+
+	/*
+	 * This interrupt was not targetted to S-EL1 so send it to
+	 * the monitor and wait for execution to resume.
+	 */
+	smc	#0
+interrupt_exit_\label:
+	restore_caller_regs_and_lr
+	eret
+	.endm
+
+	.globl	tsp_exceptions
+
+	/* -----------------------------------------------------
+	 * TSP exception handlers.
+	 * -----------------------------------------------------
+	 */
+vector_base tsp_exceptions
+	/* -----------------------------------------------------
+	 * Current EL with _sp_el0 : 0x0 - 0x200. No exceptions
+	 * are expected and treated as irrecoverable errors.
+	 * -----------------------------------------------------
+	 */
+vector_entry sync_exception_sp_el0
+	b	plat_panic_handler
+end_vector_entry sync_exception_sp_el0
+
+vector_entry irq_sp_el0
+	b	plat_panic_handler
+end_vector_entry irq_sp_el0
+
+vector_entry fiq_sp_el0
+	b	plat_panic_handler
+end_vector_entry fiq_sp_el0
+
+vector_entry serror_sp_el0
+	b	plat_panic_handler
+end_vector_entry serror_sp_el0
+
+
+	/* -----------------------------------------------------
+	 * Current EL with SPx: 0x200 - 0x400. Only IRQs/FIQs
+	 * are expected and handled
+	 * -----------------------------------------------------
+	 */
+vector_entry sync_exception_sp_elx
+	b	plat_panic_handler
+end_vector_entry sync_exception_sp_elx
+
+vector_entry irq_sp_elx
+	handle_tsp_interrupt irq_sp_elx
+end_vector_entry irq_sp_elx
+
+vector_entry fiq_sp_elx
+	handle_tsp_interrupt fiq_sp_elx
+end_vector_entry fiq_sp_elx
+
+vector_entry serror_sp_elx
+	b	plat_panic_handler
+end_vector_entry serror_sp_elx
+
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600. No exceptions
+	 * are handled since TSP does not implement a lower EL
+	 * -----------------------------------------------------
+	 */
+vector_entry sync_exception_aarch64
+	b	plat_panic_handler
+end_vector_entry sync_exception_aarch64
+
+vector_entry irq_aarch64
+	b	plat_panic_handler
+end_vector_entry irq_aarch64
+
+vector_entry fiq_aarch64
+	b	plat_panic_handler
+end_vector_entry fiq_aarch64
+
+vector_entry serror_aarch64
+	b	plat_panic_handler
+end_vector_entry serror_aarch64
+
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800. No exceptions
+	 * handled since the TSP does not implement a lower EL.
+	 * -----------------------------------------------------
+	 */
+vector_entry sync_exception_aarch32
+	b	plat_panic_handler
+end_vector_entry sync_exception_aarch32
+
+vector_entry irq_aarch32
+	b	plat_panic_handler
+end_vector_entry irq_aarch32
+
+vector_entry fiq_aarch32
+	b	plat_panic_handler
+end_vector_entry fiq_aarch32
+
+vector_entry serror_aarch32
+	b	plat_panic_handler
+end_vector_entry serror_aarch32
diff --git a/bl32/tsp/aarch64/tsp_request.S b/bl32/tsp/aarch64/tsp_request.S
new file mode 100644
index 0000000..5ad16da
--- /dev/null
+++ b/bl32/tsp/aarch64/tsp_request.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <bl32/tsp/tsp.h>
+
+	.globl tsp_get_magic
+
+
+/*
+ * This function raises an SMC to retrieve arguments from secure
+ * monitor/dispatcher, saves the returned arguments the array received in x0,
+ * and then returns to the caller
+ */
+func tsp_get_magic
+	/* Save address to stack */
+	stp	x0, xzr, [sp, #-16]!
+
+	/* Load arguments */
+	ldr	w0, _tsp_fid_get_magic
+
+	/* Raise SMC */
+	smc	#0
+
+	/* Restore address from stack */
+	ldp	x4, xzr, [sp], #16
+
+	/* Store returned arguments to the array */
+	stp	x0, x1, [x4, #0]
+
+	ret
+endfunc tsp_get_magic
+
+	.align 2
+_tsp_fid_get_magic:
+	.word	TSP_GET_ARGS
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
new file mode 100644
index 0000000..e9a1df1
--- /dev/null
+++ b/bl32/tsp/tsp.ld.S
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(tsp_entrypoint)
+
+
+MEMORY {
+    RAM (rwx): ORIGIN = TSP_SEC_MEM_BASE, LENGTH = TSP_SEC_MEM_SIZE
+}
+
+
+SECTIONS
+{
+    . = BL32_BASE;
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL32_BASE address is not aligned on a page boundary.")
+
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *tsp_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = ALIGN(PAGE_SIZE);
+        __TEXT_END__ = .;
+    } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_END__ = .;
+    } >RAM
+#else
+    ro . : {
+        __RO_START__ = .;
+        *tsp_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+        *(.vectors)
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as
+         * read-only, executable.  No RW data from the next section must
+         * creep in.  Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __RO_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+#ifdef TSP_PROGBITS_LIMIT
+    ASSERT(. <= TSP_PROGBITS_LIMIT, "TSP progbits has exceeded its limit.")
+#endif
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss : ALIGN(16) {
+        __BSS_START__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        __BSS_END__ = .;
+    } >RAM
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM
+#endif
+
+    /*
+     * Define a linker symbol to mark the end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+    __BL32_END__ = .;
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+#if USE_COHERENT_MEM
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+    ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.")
+}
diff --git a/bl32/tsp/tsp.mk b/bl32/tsp/tsp.mk
new file mode 100644
index 0000000..3fd6d99
--- /dev/null
+++ b/bl32/tsp/tsp.mk
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+INCLUDES		+=	-Iinclude/bl32/tsp
+
+BL32_SOURCES		+=	bl32/tsp/tsp_main.c			\
+				bl32/tsp/aarch64/tsp_entrypoint.S	\
+				bl32/tsp/aarch64/tsp_exceptions.S	\
+				bl32/tsp/aarch64/tsp_request.S		\
+				bl32/tsp/tsp_interrupt.c		\
+				bl32/tsp/tsp_timer.c			\
+				common/aarch64/early_exceptions.S	\
+				lib/locks/exclusive/aarch64/spinlock.S
+
+BL32_LINKERFILE		:=	bl32/tsp/tsp.ld.S
+
+# This flag determines if the TSPD initializes BL32 in tspd_init() (synchronous
+# method) or configures BL31 to pass control to BL32 instead of BL33
+# (asynchronous method).
+TSP_INIT_ASYNC         :=      0
+
+$(eval $(call assert_boolean,TSP_INIT_ASYNC))
+$(eval $(call add_define,TSP_INIT_ASYNC))
+
+# Include the platform-specific TSP Makefile
+# If no platform-specific TSP Makefile exists, it means TSP is not supported
+# on this platform.
+TSP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/tsp/tsp-${PLAT}.mk)
+ifeq (,${TSP_PLAT_MAKEFILE})
+  $(error TSP is not supported on platform ${PLAT})
+else
+  include ${TSP_PLAT_MAKEFILE}
+endif
diff --git a/bl32/tsp/tsp_interrupt.c b/bl32/tsp/tsp_interrupt.c
new file mode 100644
index 0000000..4e500b3
--- /dev/null
+++ b/bl32/tsp/tsp_interrupt.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#include "tsp_private.h"
+
+/*******************************************************************************
+ * This function updates the TSP statistics for S-EL1 interrupts handled
+ * synchronously i.e the ones that have been handed over by the TSPD. It also
+ * keeps count of the number of times control was passed back to the TSPD
+ * after handling the interrupt. In the future it will be possible that the
+ * TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to
+ * return execution. This statistic will be useful to distinguish between these
+ * two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter
+ * contains the address of the instruction in normal world where this S-EL1
+ * interrupt was generated.
+ ******************************************************************************/
+void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	tsp_stats[linear_id].sync_sel1_intr_count++;
+	if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN)
+		tsp_stats[linear_id].sync_sel1_intr_ret_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	spin_lock(&console_lock);
+	VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%llx\n",
+		read_mpidr(), elr_el3);
+	VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests,"
+		" %d sync s-el1 interrupt returns\n",
+		read_mpidr(),
+		tsp_stats[linear_id].sync_sel1_intr_count,
+		tsp_stats[linear_id].sync_sel1_intr_ret_count);
+	spin_unlock(&console_lock);
+#endif
+}
+
+/******************************************************************************
+ * This function is invoked when a non S-EL1 interrupt is received and causes
+ * the preemption of TSP. This function returns TSP_PREEMPTED and results
+ * in the control being handed over to EL3 for handling the interrupt.
+ *****************************************************************************/
+int32_t tsp_handle_preemption(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	tsp_stats[linear_id].preempt_intr_count++;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	spin_lock(&console_lock);
+	VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n",
+		read_mpidr(), tsp_stats[linear_id].preempt_intr_count);
+	spin_unlock(&console_lock);
+#endif
+	return TSP_PREEMPTED;
+}
+
+/*******************************************************************************
+ * TSP interrupt handler is called as a part of both synchronous and
+ * asynchronous handling of TSP interrupts. Currently the physical timer
+ * interrupt is the only S-EL1 interrupt that this handler expects. It returns
+ * 0 upon successfully handling the expected interrupt and all other
+ * interrupts are treated as normal world or EL3 interrupts.
+ ******************************************************************************/
+int32_t tsp_common_int_handler(void)
+{
+	uint32_t linear_id = plat_my_core_pos(), id;
+
+	/*
+	 * Get the highest priority pending interrupt id and see if it is the
+	 * secure physical generic timer interrupt in which case, handle it.
+	 * Otherwise throw this interrupt at the EL3 firmware.
+	 *
+	 * There is a small time window between reading the highest priority
+	 * pending interrupt and acknowledging it during which another
+	 * interrupt of higher priority could become the highest pending
+	 * interrupt. This is not expected to happen currently for TSP.
+	 */
+	id = plat_ic_get_pending_interrupt_id();
+
+	/* TSP can only handle the secure physical timer interrupt */
+	if (id != TSP_IRQ_SEC_PHY_TIMER)
+		return tsp_handle_preemption();
+
+	/*
+	 * Acknowledge and handle the secure timer interrupt. Also sanity check
+	 * if it has been preempted by another interrupt through an assertion.
+	 */
+	id = plat_ic_acknowledge_interrupt();
+	assert(id == TSP_IRQ_SEC_PHY_TIMER);
+	tsp_generic_timer_handler();
+	plat_ic_end_of_interrupt(id);
+
+	/* Update the statistics and print some messages */
+	tsp_stats[linear_id].sel1_intr_count++;
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	spin_lock(&console_lock);
+	VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n",
+	       read_mpidr(), id);
+	VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n",
+	     read_mpidr(), tsp_stats[linear_id].sel1_intr_count);
+	spin_unlock(&console_lock);
+#endif
+	return 0;
+}
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
new file mode 100644
index 0000000..30bf6ff
--- /dev/null
+++ b/bl32/tsp/tsp_main.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#include <platform_tsp.h>
+
+#include "tsp_private.h"
+
+
+/*******************************************************************************
+ * Lock to control access to the console
+ ******************************************************************************/
+spinlock_t console_lock;
+
+/*******************************************************************************
+ * Per cpu data structure to populate parameters for an SMC in C code and use
+ * a pointer to this structure in assembler code to populate x0-x7
+ ******************************************************************************/
+static tsp_args_t tsp_smc_args[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * Per cpu data structure to keep track of TSP activity
+ ******************************************************************************/
+work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * The TSP memory footprint starts at address BL32_BASE and ends with the
+ * linker symbol __BL32_END__. Use these addresses to compute the TSP image
+ * size.
+ ******************************************************************************/
+#define BL32_TOTAL_LIMIT BL32_END
+#define BL32_TOTAL_SIZE (BL32_TOTAL_LIMIT - (unsigned long) BL32_BASE)
+
+static tsp_args_t *set_smc_args(uint64_t arg0,
+			     uint64_t arg1,
+			     uint64_t arg2,
+			     uint64_t arg3,
+			     uint64_t arg4,
+			     uint64_t arg5,
+			     uint64_t arg6,
+			     uint64_t arg7)
+{
+	uint32_t linear_id;
+	tsp_args_t *pcpu_smc_args;
+
+	/*
+	 * Return to Secure Monitor by raising an SMC. The results of the
+	 * service are passed as an arguments to the SMC
+	 */
+	linear_id = plat_my_core_pos();
+	pcpu_smc_args = &tsp_smc_args[linear_id];
+	write_sp_arg(pcpu_smc_args, TSP_ARG0, arg0);
+	write_sp_arg(pcpu_smc_args, TSP_ARG1, arg1);
+	write_sp_arg(pcpu_smc_args, TSP_ARG2, arg2);
+	write_sp_arg(pcpu_smc_args, TSP_ARG3, arg3);
+	write_sp_arg(pcpu_smc_args, TSP_ARG4, arg4);
+	write_sp_arg(pcpu_smc_args, TSP_ARG5, arg5);
+	write_sp_arg(pcpu_smc_args, TSP_ARG6, arg6);
+	write_sp_arg(pcpu_smc_args, TSP_ARG7, arg7);
+
+	return pcpu_smc_args;
+}
+
+/*******************************************************************************
+ * Setup function for TSP.
+ ******************************************************************************/
+void tsp_setup(void)
+{
+	/* Perform early platform-specific setup */
+	tsp_early_platform_setup();
+
+	/*
+	 * Update pointer authentication key before the MMU is enabled. It is
+	 * saved in the rodata section, that can be writen before enabling the
+	 * MMU. This function must be called after the console is initialized
+	 * in the early platform setup.
+	 */
+	bl_handle_pauth();
+
+	/* Perform late platform-specific setup */
+	tsp_plat_arch_setup();
+}
+
+/*******************************************************************************
+ * TSP main entry point where it gets the opportunity to initialize its secure
+ * state/applications. Once the state is initialized, it must return to the
+ * SPD with a pointer to the 'tsp_vector_table' jump table.
+ ******************************************************************************/
+uint64_t tsp_main(void)
+{
+	NOTICE("TSP: %s\n", version_string);
+	NOTICE("TSP: %s\n", build_message);
+	INFO("TSP: Total memory base : 0x%lx\n", (unsigned long) BL32_BASE);
+	INFO("TSP: Total memory size : 0x%lx bytes\n", BL32_TOTAL_SIZE);
+
+	uint32_t linear_id = plat_my_core_pos();
+
+	/* Initialize the platform */
+	tsp_platform_setup();
+
+	/* Initialize secure/applications state here */
+	tsp_generic_timer_start();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+	tsp_stats[linear_id].cpu_on_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	spin_lock(&console_lock);
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
+	     read_mpidr(),
+	     tsp_stats[linear_id].smc_count,
+	     tsp_stats[linear_id].eret_count,
+	     tsp_stats[linear_id].cpu_on_count);
+	spin_unlock(&console_lock);
+#endif
+	return (uint64_t) &tsp_vector_table;
+}
+
+/*******************************************************************************
+ * This function performs any remaining book keeping in the test secure payload
+ * after this cpu's architectural state has been setup in response to an earlier
+ * psci cpu_on request.
+ ******************************************************************************/
+tsp_args_t *tsp_cpu_on_main(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	/* Initialize secure/applications state here */
+	tsp_generic_timer_start();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+	tsp_stats[linear_id].cpu_on_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	spin_lock(&console_lock);
+	INFO("TSP: cpu 0x%lx turned on\n", read_mpidr());
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
+		read_mpidr(),
+		tsp_stats[linear_id].smc_count,
+		tsp_stats[linear_id].eret_count,
+		tsp_stats[linear_id].cpu_on_count);
+	spin_unlock(&console_lock);
+#endif
+	/* Indicate to the SPD that we have completed turned ourselves on */
+	return set_smc_args(TSP_ON_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * This function performs any remaining book keeping in the test secure payload
+ * before this cpu is turned off in response to a psci cpu_off request.
+ ******************************************************************************/
+tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
+			   uint64_t arg1,
+			   uint64_t arg2,
+			   uint64_t arg3,
+			   uint64_t arg4,
+			   uint64_t arg5,
+			   uint64_t arg6,
+			   uint64_t arg7)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	/*
+	 * This cpu is being turned off, so disable the timer to prevent the
+	 * secure timer interrupt from interfering with power down. A pending
+	 * interrupt will be lost but we do not care as we are turning off.
+	 */
+	tsp_generic_timer_stop();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+	tsp_stats[linear_id].cpu_off_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	spin_lock(&console_lock);
+	INFO("TSP: cpu 0x%lx off request\n", read_mpidr());
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n",
+		read_mpidr(),
+		tsp_stats[linear_id].smc_count,
+		tsp_stats[linear_id].eret_count,
+		tsp_stats[linear_id].cpu_off_count);
+	spin_unlock(&console_lock);
+#endif
+
+	/* Indicate to the SPD that we have completed this request */
+	return set_smc_args(TSP_OFF_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * This function performs any book keeping in the test secure payload before
+ * this cpu's architectural state is saved in response to an earlier psci
+ * cpu_suspend request.
+ ******************************************************************************/
+tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0,
+			       uint64_t arg1,
+			       uint64_t arg2,
+			       uint64_t arg3,
+			       uint64_t arg4,
+			       uint64_t arg5,
+			       uint64_t arg6,
+			       uint64_t arg7)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	/*
+	 * Save the time context and disable it to prevent the secure timer
+	 * interrupt from interfering with wakeup from the suspend state.
+	 */
+	tsp_generic_timer_save();
+	tsp_generic_timer_stop();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+	tsp_stats[linear_id].cpu_suspend_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	spin_lock(&console_lock);
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
+		read_mpidr(),
+		tsp_stats[linear_id].smc_count,
+		tsp_stats[linear_id].eret_count,
+		tsp_stats[linear_id].cpu_suspend_count);
+	spin_unlock(&console_lock);
+#endif
+
+	/* Indicate to the SPD that we have completed this request */
+	return set_smc_args(TSP_SUSPEND_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * This function performs any book keeping in the test secure payload after this
+ * cpu's architectural state has been restored after wakeup from an earlier psci
+ * cpu_suspend request.
+ ******************************************************************************/
+tsp_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl,
+			      uint64_t arg1,
+			      uint64_t arg2,
+			      uint64_t arg3,
+			      uint64_t arg4,
+			      uint64_t arg5,
+			      uint64_t arg6,
+			      uint64_t arg7)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	/* Restore the generic timer context */
+	tsp_generic_timer_restore();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+	tsp_stats[linear_id].cpu_resume_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	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",
+		read_mpidr(),
+		tsp_stats[linear_id].smc_count,
+		tsp_stats[linear_id].eret_count,
+		tsp_stats[linear_id].cpu_suspend_count);
+	spin_unlock(&console_lock);
+#endif
+	/* Indicate to the SPD that we have completed this request */
+	return set_smc_args(TSP_RESUME_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * This function performs any remaining bookkeeping in the test secure payload
+ * before the system is switched off (in response to a psci SYSTEM_OFF request)
+ ******************************************************************************/
+tsp_args_t *tsp_system_off_main(uint64_t arg0,
+				uint64_t arg1,
+				uint64_t arg2,
+				uint64_t arg3,
+				uint64_t arg4,
+				uint64_t arg5,
+				uint64_t arg6,
+				uint64_t arg7)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	spin_lock(&console_lock);
+	INFO("TSP: cpu 0x%lx SYSTEM_OFF request\n", read_mpidr());
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", read_mpidr(),
+	     tsp_stats[linear_id].smc_count,
+	     tsp_stats[linear_id].eret_count);
+	spin_unlock(&console_lock);
+#endif
+
+	/* Indicate to the SPD that we have completed this request */
+	return set_smc_args(TSP_SYSTEM_OFF_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * This function performs any remaining bookkeeping in the test secure payload
+ * before the system is reset (in response to a psci SYSTEM_RESET request)
+ ******************************************************************************/
+tsp_args_t *tsp_system_reset_main(uint64_t arg0,
+				uint64_t arg1,
+				uint64_t arg2,
+				uint64_t arg3,
+				uint64_t arg4,
+				uint64_t arg5,
+				uint64_t arg6,
+				uint64_t arg7)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	spin_lock(&console_lock);
+	INFO("TSP: cpu 0x%lx SYSTEM_RESET request\n", read_mpidr());
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", read_mpidr(),
+	     tsp_stats[linear_id].smc_count,
+	     tsp_stats[linear_id].eret_count);
+	spin_unlock(&console_lock);
+#endif
+
+	/* Indicate to the SPD that we have completed this request */
+	return set_smc_args(TSP_SYSTEM_RESET_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * TSP fast smc handler. The secure monitor jumps to this function by
+ * doing the ERET after populating X0-X7 registers. The arguments are received
+ * in the function arguments in order. Once the service is rendered, this
+ * function returns to Secure Monitor by raising SMC.
+ ******************************************************************************/
+tsp_args_t *tsp_smc_handler(uint64_t func,
+			       uint64_t arg1,
+			       uint64_t arg2,
+			       uint64_t arg3,
+			       uint64_t arg4,
+			       uint64_t arg5,
+			       uint64_t arg6,
+			       uint64_t arg7)
+{
+	uint64_t results[2];
+	uint64_t service_args[2];
+	uint32_t linear_id = plat_my_core_pos();
+
+	/* Update this cpu's statistics */
+	tsp_stats[linear_id].smc_count++;
+	tsp_stats[linear_id].eret_count++;
+
+	INFO("TSP: cpu 0x%lx received %s smc 0x%llx\n", read_mpidr(),
+		((func >> 31) & 1) == 1 ? "fast" : "yielding",
+		func);
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets\n", read_mpidr(),
+		tsp_stats[linear_id].smc_count,
+		tsp_stats[linear_id].eret_count);
+
+	/* Render secure services and obtain results here */
+	results[0] = arg1;
+	results[1] = arg2;
+
+	/*
+	 * Request a service back from dispatcher/secure monitor. This call
+	 * return and thereafter resume execution
+	 */
+	tsp_get_magic(service_args);
+
+	/* Determine the function to perform based on the function ID */
+	switch (TSP_BARE_FID(func)) {
+	case TSP_ADD:
+		results[0] += service_args[0];
+		results[1] += service_args[1];
+		break;
+	case TSP_SUB:
+		results[0] -= service_args[0];
+		results[1] -= service_args[1];
+		break;
+	case TSP_MUL:
+		results[0] *= service_args[0];
+		results[1] *= service_args[1];
+		break;
+	case TSP_DIV:
+		results[0] /= service_args[0] ? service_args[0] : 1;
+		results[1] /= service_args[1] ? service_args[1] : 1;
+		break;
+	default:
+		break;
+	}
+
+	return set_smc_args(func, 0,
+			    results[0],
+			    results[1],
+			    0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * TSP smc abort handler. This function is called when aborting a preempted
+ * yielding SMC request. It should cleanup all resources owned by the SMC
+ * handler such as locks or dynamically allocated memory so following SMC
+ * request are executed in a clean environment.
+ ******************************************************************************/
+tsp_args_t *tsp_abort_smc_handler(uint64_t func,
+				  uint64_t arg1,
+				  uint64_t arg2,
+				  uint64_t arg3,
+				  uint64_t arg4,
+				  uint64_t arg5,
+				  uint64_t arg6,
+				  uint64_t arg7)
+{
+	return set_smc_args(TSP_ABORT_DONE, 0, 0, 0, 0, 0, 0, 0);
+}
diff --git a/bl32/tsp/tsp_private.h b/bl32/tsp/tsp_private.h
new file mode 100644
index 0000000..cbd527f
--- /dev/null
+++ b/bl32/tsp/tsp_private.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TSP_PRIVATE_H
+#define TSP_PRIVATE_H
+
+/* Definitions to help the assembler access the SMC/ERET args structure */
+#define TSP_ARGS_SIZE		0x40
+#define TSP_ARG0		0x0
+#define TSP_ARG1		0x8
+#define TSP_ARG2		0x10
+#define TSP_ARG3		0x18
+#define TSP_ARG4		0x20
+#define TSP_ARG5		0x28
+#define TSP_ARG6		0x30
+#define TSP_ARG7		0x38
+#define TSP_ARGS_END		0x40
+
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <platform_def.h> /* For CACHE_WRITEBACK_GRANULE */
+
+#include <bl32/tsp/tsp.h>
+#include <lib/cassert.h>
+#include <lib/spinlock.h>
+
+typedef struct work_statistics {
+	/* Number of s-el1 interrupts on this cpu */
+	uint32_t sel1_intr_count;
+	/* Number of non s-el1 interrupts on this cpu which preempted TSP */
+	uint32_t preempt_intr_count;
+	/* Number of sync s-el1 interrupts on this cpu */
+	uint32_t sync_sel1_intr_count;
+	/* Number of s-el1 interrupts returns on this cpu */
+	uint32_t sync_sel1_intr_ret_count;
+	uint32_t smc_count;		/* Number of returns on this cpu */
+	uint32_t eret_count;		/* Number of entries on this cpu */
+	uint32_t cpu_on_count;		/* Number of cpu on requests */
+	uint32_t cpu_off_count;		/* Number of cpu off requests */
+	uint32_t cpu_suspend_count;	/* Number of cpu suspend requests */
+	uint32_t cpu_resume_count;	/* Number of cpu resume requests */
+} __aligned(CACHE_WRITEBACK_GRANULE) work_statistics_t;
+
+typedef struct tsp_args {
+	uint64_t _regs[TSP_ARGS_END >> 3];
+} __aligned(CACHE_WRITEBACK_GRANULE) tsp_args_t;
+
+/* Macros to access members of the above structure using their offsets */
+#define read_sp_arg(args, offset)	((args)->_regs[offset >> 3])
+#define write_sp_arg(args, offset, val) (((args)->_regs[offset >> 3])	\
+					 = val)
+/*
+ * Ensure that the assembler's view of the size of the tsp_args is the
+ * same as the compilers
+ */
+CASSERT(TSP_ARGS_SIZE == sizeof(tsp_args_t), assert_sp_args_size_mismatch);
+
+void tsp_get_magic(uint64_t args[4]);
+
+tsp_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl,
+				uint64_t arg1,
+				uint64_t arg2,
+				uint64_t arg3,
+				uint64_t arg4,
+				uint64_t arg5,
+				uint64_t arg6,
+				uint64_t arg7);
+tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0,
+				 uint64_t arg1,
+				 uint64_t arg2,
+				 uint64_t arg3,
+				 uint64_t arg4,
+				 uint64_t arg5,
+				 uint64_t arg6,
+				 uint64_t arg7);
+tsp_args_t *tsp_cpu_on_main(void);
+tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
+			     uint64_t arg1,
+			     uint64_t arg2,
+			     uint64_t arg3,
+			     uint64_t arg4,
+			     uint64_t arg5,
+			     uint64_t arg6,
+			     uint64_t arg7);
+
+/* Generic Timer functions */
+void tsp_generic_timer_start(void);
+void tsp_generic_timer_handler(void);
+void tsp_generic_timer_stop(void);
+void tsp_generic_timer_save(void);
+void tsp_generic_timer_restore(void);
+
+/* S-EL1 interrupt management functions */
+void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3);
+
+
+/* Data structure to keep track of TSP statistics */
+extern spinlock_t console_lock;
+extern work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
+
+/* Vector table of jumps */
+extern tsp_vectors_t tsp_vector_table;
+
+/* functions */
+int32_t tsp_common_int_handler(void);
+int32_t tsp_handle_preemption(void);
+
+tsp_args_t *tsp_abort_smc_handler(uint64_t func,
+				  uint64_t arg1,
+				  uint64_t arg2,
+				  uint64_t arg3,
+				  uint64_t arg4,
+				  uint64_t arg5,
+				  uint64_t arg6,
+				  uint64_t arg7);
+
+tsp_args_t *tsp_smc_handler(uint64_t func,
+			       uint64_t arg1,
+			       uint64_t arg2,
+			       uint64_t arg3,
+			       uint64_t arg4,
+			       uint64_t arg5,
+			       uint64_t arg6,
+			       uint64_t arg7);
+
+tsp_args_t *tsp_system_reset_main(uint64_t arg0,
+				uint64_t arg1,
+				uint64_t arg2,
+				uint64_t arg3,
+				uint64_t arg4,
+				uint64_t arg5,
+				uint64_t arg6,
+				uint64_t arg7);
+
+tsp_args_t *tsp_system_off_main(uint64_t arg0,
+				uint64_t arg1,
+				uint64_t arg2,
+				uint64_t arg3,
+				uint64_t arg4,
+				uint64_t arg5,
+				uint64_t arg6,
+				uint64_t arg7);
+
+uint64_t tsp_main(void);
+#endif /* __ASSEMBLER__ */
+
+#endif /* TSP_PRIVATE_H */
diff --git a/bl32/tsp/tsp_timer.c b/bl32/tsp/tsp_timer.c
new file mode 100644
index 0000000..d1ff2b0
--- /dev/null
+++ b/bl32/tsp/tsp_timer.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#include "tsp_private.h"
+
+/*******************************************************************************
+ * Data structure to keep track of per-cpu secure generic timer context across
+ * power management operations.
+ ******************************************************************************/
+typedef struct timer_context {
+	uint64_t cval;
+	uint32_t ctl;
+} timer_context_t;
+
+static timer_context_t pcpu_timer_context[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * This function initializes the generic timer to fire every 0.5 second
+ ******************************************************************************/
+void tsp_generic_timer_start(void)
+{
+	uint64_t cval;
+	uint32_t ctl = 0;
+
+	/* The timer will fire every 0.5 second */
+	cval = read_cntpct_el0() + (read_cntfrq_el0() >> 1);
+	write_cntps_cval_el1(cval);
+
+	/* Enable the secure physical timer */
+	set_cntp_ctl_enable(ctl);
+	write_cntps_ctl_el1(ctl);
+}
+
+/*******************************************************************************
+ * This function deasserts the timer interrupt and sets it up again
+ ******************************************************************************/
+void tsp_generic_timer_handler(void)
+{
+	/* Ensure that the timer did assert the interrupt */
+	assert(get_cntp_ctl_istatus(read_cntps_ctl_el1()));
+
+	/*
+	 * Disable the timer and reprogram it. The barriers ensure that there is
+	 * no reordering of instructions around the reprogramming code.
+	 */
+	isb();
+	write_cntps_ctl_el1(0);
+	tsp_generic_timer_start();
+	isb();
+}
+
+/*******************************************************************************
+ * This function deasserts the timer interrupt prior to cpu power down
+ ******************************************************************************/
+void tsp_generic_timer_stop(void)
+{
+	/* Disable the timer */
+	write_cntps_ctl_el1(0);
+}
+
+/*******************************************************************************
+ * This function saves the timer context prior to cpu suspension
+ ******************************************************************************/
+void tsp_generic_timer_save(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	pcpu_timer_context[linear_id].cval = read_cntps_cval_el1();
+	pcpu_timer_context[linear_id].ctl = read_cntps_ctl_el1();
+	flush_dcache_range((uint64_t) &pcpu_timer_context[linear_id],
+			   sizeof(pcpu_timer_context[linear_id]));
+}
+
+/*******************************************************************************
+ * This function restores the timer context post cpu resumption
+ ******************************************************************************/
+void tsp_generic_timer_restore(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+
+	write_cntps_cval_el1(pcpu_timer_context[linear_id].cval);
+	write_cntps_ctl_el1(pcpu_timer_context[linear_id].ctl);
+}
diff --git a/common/aarch32/debug.S b/common/aarch32/debug.S
new file mode 100644
index 0000000..f506356
--- /dev/null
+++ b/common/aarch32/debug.S
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	asm_assert
+	.globl	do_panic
+	.globl	report_exception
+
+/* Since the max decimal input number is 65536 */
+#define MAX_DEC_DIVISOR		10000
+
+/* The offset to add to get ascii for numerals '0 - 9' */
+#define ASCII_OFFSET_NUM	'0'
+
+	.section .rodata.panic_str, "aS"
+panic_msg:
+	.asciz "PANIC at PC : 0x"
+panic_end:
+	.asciz "\r\n"
+
+	/***********************************************************
+	 * The common implementation of do_panic for all BL stages
+	 ***********************************************************/
+func do_panic
+	/* Have LR copy point to PC at the time of panic */
+	sub	r6, lr, #4
+
+	/* Initialize crash console and verify success */
+	bl	plat_crash_console_init
+	cmp	r0, #0
+	beq	1f
+
+	/* Print panic message */
+	ldr	r4, =panic_msg
+	bl	asm_print_str
+
+	/* Print LR in hex */
+	mov	r4, r6
+	bl	asm_print_hex
+
+	/* Print new line */
+	ldr	r4, =panic_end
+	bl	asm_print_str
+
+	bl	plat_crash_console_flush
+
+1:
+	mov	lr, r6
+	b	plat_panic_handler
+endfunc do_panic
+
+	/***********************************************************
+	 * This function is called from the vector table for
+	 * unhandled exceptions. It reads the current mode and
+	 * passes it to platform.
+	 ***********************************************************/
+func report_exception
+	mrs	r0, cpsr
+	and	r0, #MODE32_MASK
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+endfunc report_exception
+
+#if ENABLE_ASSERTIONS
+.section .rodata.assert_str, "aS"
+assert_msg1:
+	.asciz "ASSERT: File "
+assert_msg2:
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+	/******************************************************************
+	 * Virtualization comes with the UDIV/SDIV instructions. If missing
+	 * write file line number in hexadecimal format.
+	 ******************************************************************/
+	.asciz " Line 0x"
+#else
+	.asciz " Line "
+#endif
+
+/* ---------------------------------------------------------------------------
+ * Assertion support in assembly.
+ * The below function helps to support assertions in assembly where we do not
+ * have a C runtime stack. Arguments to the function are :
+ * r0 - File name
+ * r1 - Line no
+ * Clobber list : lr, r0 - r6
+ * ---------------------------------------------------------------------------
+ */
+func asm_assert
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	/*
+	 * Only print the output if LOG_LEVEL is higher or equal to
+	 * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1.
+	 */
+	/* Stash the parameters already in r0 and r1 */
+	mov	r5, r0
+	mov	r6, r1
+
+	/* Initialize crash console and verify success */
+	bl	plat_crash_console_init
+	cmp	r0, #0
+	beq	1f
+
+	/* Print file name */
+	ldr	r4, =assert_msg1
+	bl	asm_print_str
+	mov	r4, r5
+	bl	asm_print_str
+
+	/* Print line number string */
+	ldr	r4, =assert_msg2
+	bl	asm_print_str
+
+	/* Test for maximum supported line number */
+	ldr	r4, =~0xffff
+	tst	r6, r4
+	bne	1f
+	mov	r4, r6
+
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+	/******************************************************************
+	 * Virtualization comes with the UDIV/SDIV instructions. If missing
+	 * write file line number in hexadecimal format.
+	 ******************************************************************/
+	bl	asm_print_hex
+#else
+	/* Print line number in decimal */
+	mov	r6, #10			/* Divide by 10 after every loop iteration */
+	ldr	r5, =MAX_DEC_DIVISOR
+dec_print_loop:
+	udiv	r0, r4, r5			/* Quotient */
+	mls	r4, r0, r5, r4			/* Remainder */
+	add	r0, r0, #ASCII_OFFSET_NUM	/* Convert to ASCII */
+	bl	plat_crash_console_putc
+	udiv	r5, r5, r6			/* Reduce divisor */
+	cmp	r5, #0
+	bne	dec_print_loop
+#endif
+
+	bl	plat_crash_console_flush
+
+1:
+#endif /* LOG_LEVEL >= LOG_LEVEL_INFO */
+	no_ret	plat_panic_handler
+endfunc asm_assert
+#endif /* ENABLE_ASSERTIONS */
+
+/*
+ * This function prints a string from address in r4
+ * Clobber: lr, r0 - r4
+ */
+func asm_print_str
+	mov	r3, lr
+1:
+	ldrb	r0, [r4], #0x1
+	cmp	r0, #0
+	beq	2f
+	bl	plat_crash_console_putc
+	b	1b
+2:
+	bx	r3
+endfunc asm_print_str
+
+/*
+ * This function prints a hexadecimal number in r4.
+ * In: r4 = the hexadecimal to print.
+ * Clobber: lr, r0 - r3, r5
+ */
+func asm_print_hex
+	mov	r3, lr
+	mov	r5, #32  /* No of bits to convert to ascii */
+1:
+	sub	r5, r5, #4
+	lsr	r0, r4, r5
+	and	r0, r0, #0xf
+	cmp	r0, #0xa
+	blo	2f
+	/* Add by 0x27 in addition to ASCII_OFFSET_NUM
+	 * to get ascii for characters 'a - f'.
+	 */
+	add	r0, r0, #0x27
+2:
+	add	r0, r0, #ASCII_OFFSET_NUM
+	bl	plat_crash_console_putc
+	cmp	r5, #0
+	bne	1b
+	bx	r3
+endfunc asm_print_hex
diff --git a/common/aarch64/debug.S b/common/aarch64/debug.S
new file mode 100644
index 0000000..ac47cbe
--- /dev/null
+++ b/common/aarch64/debug.S
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/debug.h>
+
+	.globl	asm_print_str
+	.globl	asm_print_hex
+	.globl	asm_print_hex_bits
+	.globl	asm_assert
+	.globl	do_panic
+
+/* Since the max decimal input number is 65536 */
+#define MAX_DEC_DIVISOR		10000
+/* The offset to add to get ascii for numerals '0 - 9' */
+#define ASCII_OFFSET_NUM	0x30
+
+#if ENABLE_ASSERTIONS
+.section .rodata.assert_str, "aS"
+assert_msg1:
+	.asciz "ASSERT: File "
+assert_msg2:
+	.asciz " Line "
+
+	/*
+	 * This macro is intended to be used to print the
+	 * line number in decimal. Used by asm_assert macro.
+	 * The max number expected is 65536.
+	 * In: x4 = the decimal to print.
+	 * Clobber: x30, x0, x1, x2, x5, x6
+	 */
+	.macro asm_print_line_dec
+	mov	x6, #10		/* Divide by 10 after every loop iteration */
+	mov	x5, #MAX_DEC_DIVISOR
+dec_print_loop:
+	udiv	x0, x4, x5		/* Get the quotient */
+	msub	x4, x0, x5, x4		/* Find the remainder */
+	add	x0, x0, #ASCII_OFFSET_NUM		/* Convert to ascii */
+	bl	plat_crash_console_putc
+	udiv	x5, x5, x6		/* Reduce divisor */
+	cbnz	x5, dec_print_loop
+	.endm
+
+
+/* ---------------------------------------------------------------------------
+ * Assertion support in assembly.
+ * The below function helps to support assertions in assembly where we do not
+ * have a C runtime stack. Arguments to the function are :
+ * x0 - File name
+ * x1 - Line no
+ * Clobber list : x30, x0, x1, x2, x3, x4, x5, x6.
+ * ---------------------------------------------------------------------------
+ */
+func asm_assert
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	/*
+	 * Only print the output if LOG_LEVEL is higher or equal to
+	 * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1.
+	 */
+	mov	x5, x0
+	mov	x6, x1
+	/* Ensure the console is initialized */
+	bl	plat_crash_console_init
+	/* Check if the console is initialized */
+	cbz	x0, _assert_loop
+	/* The console is initialized */
+	adr	x4, assert_msg1
+	bl	asm_print_str
+	mov	x4, x5
+	bl	asm_print_str
+	adr	x4, assert_msg2
+	bl	asm_print_str
+	/* Check if line number higher than max permitted */
+	tst	x6, #~0xffff
+	b.ne	_assert_loop
+	mov	x4, x6
+	asm_print_line_dec
+	bl	plat_crash_console_flush
+_assert_loop:
+#endif /* LOG_LEVEL >= LOG_LEVEL_INFO */
+	no_ret	plat_panic_handler
+endfunc asm_assert
+#endif /* ENABLE_ASSERTIONS */
+
+/*
+ * This function prints a string from address in x4.
+ * In: x4 = pointer to string.
+ * Clobber: x30, x0, x1, x2, x3
+ */
+func asm_print_str
+	mov	x3, x30
+1:
+	ldrb	w0, [x4], #0x1
+	cbz	x0, 2f
+	bl	plat_crash_console_putc
+	b	1b
+2:
+	ret	x3
+endfunc asm_print_str
+
+/*
+ * This function prints a hexadecimal number in x4.
+ * In: x4 = the hexadecimal to print.
+ * Clobber: x30, x0 - x3, x5
+ */
+func asm_print_hex
+	mov	x5, #64  /* No of bits to convert to ascii */
+
+	/* Convert to ascii number of bits in x5 */
+asm_print_hex_bits:
+	mov	x3, x30
+1:
+	sub	x5, x5, #4
+	lsrv	x0, x4, x5
+	and	x0, x0, #0xf
+	cmp	x0, #0xA
+	b.lo	2f
+	/* Add by 0x27 in addition to ASCII_OFFSET_NUM
+	 * to get ascii for characters 'a - f'.
+	 */
+	add	x0, x0, #0x27
+2:
+	add	x0, x0, #ASCII_OFFSET_NUM
+	bl	plat_crash_console_putc
+	cbnz	x5, 1b
+	ret	x3
+endfunc asm_print_hex
+
+	/***********************************************************
+	 * The common implementation of do_panic for all BL stages
+	 ***********************************************************/
+
+.section .rodata.panic_str, "aS"
+	panic_msg: .asciz "PANIC at PC : 0x"
+
+/* ---------------------------------------------------------------------------
+ * do_panic assumes that it is invoked from a C Runtime Environment ie a
+ * valid stack exists. This call will not return.
+ * Clobber list : if CRASH_REPORTING is not enabled then x30, x0 - x6
+ * ---------------------------------------------------------------------------
+ */
+
+/* This is for the non el3 BL stages to compile through */
+	.weak el3_panic
+
+func do_panic
+#if CRASH_REPORTING
+	str	x0, [sp, #-0x10]!
+	mrs	x0, currentel
+	ubfx	x0, x0, #2, #2
+	cmp	x0, #0x3
+	ldr	x0, [sp], #0x10
+	b.eq	el3_panic
+#endif
+
+panic_common:
+/*
+ * el3_panic will be redefined by the BL31
+ * crash reporting mechanism (if enabled)
+ */
+el3_panic:
+	mov	x6, x30
+	bl	plat_crash_console_init
+	/* Check if the console is initialized */
+	cbz	x0, _panic_handler
+	/* The console is initialized */
+	adr	x4, panic_msg
+	bl	asm_print_str
+	mov	x4, x6
+	/* The panic location is lr -4 */
+	sub	x4, x4, #4
+	bl	asm_print_hex
+
+	bl	plat_crash_console_flush
+
+_panic_handler:
+	/* Pass to plat_panic_handler the address from where el3_panic was
+	 * called, not the address of the call from el3_panic. */
+	mov	x30, x6
+	b	plat_panic_handler
+endfunc do_panic
diff --git a/common/aarch64/early_exceptions.S b/common/aarch64/early_exceptions.S
new file mode 100644
index 0000000..36a8724
--- /dev/null
+++ b/common/aarch64/early_exceptions.S
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by BL2 and BL31 stages.
+ * BL31 uses them before stacks are setup. BL2 uses them throughout.
+ * -----------------------------------------------------------------------------
+ */
+	.globl	early_exceptions
+
+vector_base early_exceptions
+
+	/* -----------------------------------------------------
+	 * Current EL with SP0 : 0x0 - 0x200
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSP0
+	mov	x0, #SYNC_EXCEPTION_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionSP0
+
+vector_entry IrqSP0
+	mov	x0, #IRQ_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqSP0
+
+vector_entry FiqSP0
+	mov	x0, #FIQ_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqSP0
+
+vector_entry SErrorSP0
+	mov	x0, #SERROR_SP_EL0
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorSP0
+
+	/* -----------------------------------------------------
+	 * Current EL with SPx: 0x200 - 0x400
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSPx
+	mov	x0, #SYNC_EXCEPTION_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionSPx
+
+vector_entry IrqSPx
+	mov	x0, #IRQ_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqSPx
+
+vector_entry FiqSPx
+	mov	x0, #FIQ_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqSPx
+
+vector_entry SErrorSPx
+	mov	x0, #SERROR_SP_ELX
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorSPx
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA64
+	mov	x0, #SYNC_EXCEPTION_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionA64
+
+vector_entry IrqA64
+	mov	x0, #IRQ_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqA64
+
+vector_entry FiqA64
+	mov	x0, #FIQ_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqA64
+
+vector_entry SErrorA64
+	mov	x0, #SERROR_AARCH64
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorA64
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA32
+	mov	x0, #SYNC_EXCEPTION_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SynchronousExceptionA32
+
+vector_entry IrqA32
+	mov	x0, #IRQ_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry IrqA32
+
+vector_entry FiqA32
+	mov	x0, #FIQ_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry FiqA32
+
+vector_entry SErrorA32
+	mov	x0, #SERROR_AARCH32
+	bl	plat_report_exception
+	no_ret	plat_panic_handler
+end_vector_entry SErrorA32
diff --git a/common/backtrace/backtrace.c b/common/backtrace/backtrace.c
new file mode 100644
index 0000000..506d4a4
--- /dev/null
+++ b/common/backtrace/backtrace.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+
+/* Maximum number of entries in the backtrace to display */
+#define UNWIND_LIMIT	20U
+
+/*
+ * If -fno-omit-frame-pointer is used:
+ *
+ * - AArch64: The AAPCS defines the format of the frame records and mandates the
+ *   usage of r29 as frame pointer.
+ *
+ * - AArch32: The format of the frame records is not defined in the AAPCS.
+ *   However, at least GCC and Clang use the same format. When they are forced
+ *   to only generate A32 code (with -marm), they use r11 as frame pointer and a
+ *   similar format as in AArch64. If interworking with T32 is enabled, the
+ *   frame pointer is r7 and the format is  different. This is not supported by
+ *   this implementation of backtrace, so it is needed to use -marm.
+ */
+
+/* Frame records form a linked list in the stack */
+struct frame_record {
+	/* Previous frame record in the list */
+	struct frame_record *parent;
+	/* Return address of the function at this level */
+	uintptr_t return_addr;
+};
+
+/*
+ * Strip the Pointer Authentication Code (PAC) from the address to retrieve the
+ * original one.
+ *
+ * The PAC field is stored on the high bits of the address and defined as:
+ * - PAC field = Xn[54:bottom_PAC_bit], when address tagging is used.
+ * - PAC field = Xn[63:56, 54:bottom_PAC_bit], without address tagging.
+ *
+ * With bottom_PAC_bit = 64 - TCR_ELx.TnSZ
+ */
+#if ENABLE_PAUTH
+static uintptr_t demangle_address(uintptr_t addr)
+{
+	unsigned int el, t0sz, bottom_pac_bit;
+	uint64_t tcr, pac_mask;
+
+	/*
+	 * Different virtual address space size can be defined for each EL.
+	 * Ensure that we use the proper one by reading the corresponding
+	 * TCR_ELx register.
+	 */
+	el = get_current_el();
+
+	if (el == 3U) {
+		tcr = read_tcr_el3();
+	} else if (el == 2U) {
+		tcr = read_tcr_el2();
+	} else {
+		tcr = read_tcr_el1();
+	}
+
+	/* T0SZ = TCR_ELx[5:0] */
+	t0sz = tcr & 0x1f;
+	bottom_pac_bit = 64 - t0sz;
+	pac_mask = (1ULL << bottom_pac_bit) - 1;
+
+	/* demangle the address with the computed mask */
+	return (addr & pac_mask);
+}
+#endif /* ENABLE_PAUTH */
+
+static const char *get_el_str(unsigned int el)
+{
+	if (el == 3U) {
+		return "EL3";
+	} else if (el == 2U) {
+		return "EL2";
+	} else {
+		return "S-EL1";
+	}
+}
+
+/*
+ * Returns true if the address points to a virtual address that can be read at
+ * the current EL, false otherwise.
+ */
+#ifdef __aarch64__
+static bool is_address_readable(uintptr_t addr)
+{
+	unsigned int el = get_current_el();
+
+#if ENABLE_PAUTH
+	/*
+	 * When pointer authentication is enabled, the LR value saved on the
+	 * stack contains a PAC. It must be stripped to retrieve the return
+	 * address.
+	 */
+	addr = demangle_address(addr);
+#endif
+
+	if (el == 3U) {
+		ats1e3r(addr);
+	} else if (el == 2U) {
+		ats1e2r(addr);
+	} else {
+		ats1e1r(addr);
+	}
+
+	isb();
+
+	/* If PAR.F == 1 the address translation was aborted.  */
+	if ((read_par_el1() & PAR_F_MASK) != 0U)
+		return false;
+
+	return true;
+}
+#else /* !__aarch64__ */
+static bool is_address_readable(uintptr_t addr)
+{
+	unsigned int el = get_current_el();
+
+	if (el == 3U) {
+		write_ats1cpr(addr);
+	} else if (el == 2U) {
+		write_ats1hr(addr);
+	} else {
+		write_ats1cpr(addr);
+	}
+
+	isb();
+
+	/* If PAR.F == 1 the address translation was aborted.  */
+	if ((read64_par() & PAR_F_MASK) != 0U)
+		return false;
+
+	return true;
+}
+#endif /* __aarch64__ */
+
+/*
+ * Returns true if all the bytes in a given object are in mapped memory and an
+ * LDR using this pointer would succeed, false otherwise.
+ */
+static bool is_valid_object(uintptr_t addr, size_t size)
+{
+	assert(size > 0U);
+
+	if (addr == 0U)
+		return false;
+
+	/* Detect overflows */
+	if ((addr + size) < addr)
+		return false;
+
+	/* A pointer not aligned properly could trigger an alignment fault. */
+	if ((addr & (sizeof(uintptr_t) - 1U)) != 0U)
+		return false;
+
+	/* Check that all the object is readable */
+	for (size_t i = 0; i < size; i++) {
+		if (!is_address_readable(addr + i))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * Returns true if the specified address is correctly aligned and points to a
+ * valid memory region.
+ */
+static bool is_valid_jump_address(uintptr_t addr)
+{
+	if (addr == 0U)
+		return false;
+
+	/* Check alignment. Both A64 and A32 use 32-bit opcodes */
+	if ((addr & (sizeof(uint32_t) - 1U)) != 0U)
+		return false;
+
+	if (!is_address_readable(addr))
+		return false;
+
+	return true;
+}
+
+/*
+ * Returns true if the pointer points at a valid frame record, false otherwise.
+ */
+static bool is_valid_frame_record(struct frame_record *fr)
+{
+	return is_valid_object((uintptr_t)fr, sizeof(struct frame_record));
+}
+
+/*
+ * Adjust the frame-pointer-register value by 4 bytes on AArch32 to have the
+ * same layout as AArch64.
+ */
+static struct frame_record *adjust_frame_record(struct frame_record *fr)
+{
+#ifdef __aarch64__
+	return fr;
+#else
+	return (struct frame_record *)((uintptr_t)fr - 4U);
+#endif
+}
+
+static void unwind_stack(struct frame_record *fr, uintptr_t current_pc,
+			 uintptr_t link_register)
+{
+	uintptr_t call_site;
+	static const char *backtrace_str = "%u: %s: 0x%lx\n";
+	const char *el_str = get_el_str(get_current_el());
+
+	if (!is_valid_frame_record(fr)) {
+		printf("ERROR: Corrupted frame pointer (frame record address = %p)\n",
+		       fr);
+		return;
+	}
+
+	if (fr->return_addr != link_register) {
+		printf("ERROR: Corrupted stack (frame record address = %p)\n",
+		       fr);
+		return;
+	}
+
+	/* The level 0 of the backtrace is the current backtrace function */
+	printf(backtrace_str, 0U, el_str, current_pc);
+
+	/*
+	 * The last frame record pointer in the linked list at the beginning of
+	 * the stack should be NULL unless stack is corrupted.
+	 */
+	for (unsigned int i = 1U; i < UNWIND_LIMIT; i++) {
+		/* If an invalid frame record is found, exit. */
+		if (!is_valid_frame_record(fr))
+			return;
+		/*
+		 * A32 and A64 are fixed length so the address from where the
+		 * call was made is the instruction before the return address,
+		 * which is always 4 bytes before it.
+		 */
+		call_site = fr->return_addr - 4U;
+
+#if ENABLE_PAUTH
+		/*
+		 * When pointer authentication is enabled, the LR value saved on
+		 * the stack contains a PAC. It must be stripped to retrieve the
+		 * return address.
+		 */
+		call_site = demangle_address(call_site);
+#endif
+
+		/*
+		 * If the address is invalid it means that the frame record is
+		 * probably corrupted.
+		 */
+		if (!is_valid_jump_address(call_site))
+			return;
+
+		printf(backtrace_str, i, el_str, call_site);
+
+		fr = adjust_frame_record(fr->parent);
+	}
+
+	printf("ERROR: Max backtrace depth reached\n");
+}
+
+/*
+ * Display a backtrace. The cookie string parameter is displayed along the
+ * trace to help filter the log messages.
+ *
+ * Many things can prevent displaying the expected backtrace. For example,
+ * compiler optimizations can use a branch instead of branch with link when it
+ * detects a tail call. The backtrace level for this caller will not be
+ * displayed, as it does not appear in the call stack anymore. Also, assembly
+ * functions will not be displayed unless they setup AAPCS compliant frame
+ * records on AArch64 and compliant with GCC-specific frame record format on
+ * AArch32.
+ *
+ * Usage of the trace: addr2line can be used to map the addresses to function
+ * and source code location when given the ELF file compiled with debug
+ * information. The "-i" flag is highly recommended to improve display of
+ * inlined function. The *.dump files generated when building each image can
+ * also be used.
+ *
+ * WARNING: In case of corrupted stack, this function could display security
+ * sensitive information past the beginning of the stack so it must not be used
+ * in production build. This function is only compiled in when ENABLE_BACKTRACE
+ * is set to 1.
+ */
+void backtrace(const char *cookie)
+{
+	uintptr_t return_address = (uintptr_t)__builtin_return_address(0U);
+	struct frame_record *fr = __builtin_frame_address(0U);
+
+	/* Printing the backtrace may crash the system, flush before starting */
+	(void)console_flush();
+
+	fr = adjust_frame_record(fr);
+
+	printf("BACKTRACE: START: %s\n", cookie);
+
+	unwind_stack(fr, (uintptr_t)&backtrace, return_address);
+
+	printf("BACKTRACE: END: %s\n", cookie);
+}
diff --git a/common/backtrace/backtrace.mk b/common/backtrace/backtrace.mk
new file mode 100644
index 0000000..e669331
--- /dev/null
+++ b/common/backtrace/backtrace.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Enable backtrace by default in DEBUG AArch64 builds
+ifeq (${ARCH},aarch32)
+        ENABLE_BACKTRACE 	:=	0
+else
+        ENABLE_BACKTRACE 	:=	${DEBUG}
+endif
+
+ifeq (${ENABLE_BACKTRACE},1)
+        # Force the compiler to include the frame pointer
+        TF_CFLAGS		+=	-fno-omit-frame-pointer
+
+        BL_COMMON_SOURCES	+=	common/backtrace/backtrace.c
+endif
+
+ifeq (${ARCH},aarch32)
+        ifeq (${ENABLE_BACKTRACE},1)
+                ifneq (${AARCH32_INSTRUCTION_SET},A32)
+                        $(error Error: AARCH32_INSTRUCTION_SET=A32 is needed \
+                        for ENABLE_BACKTRACE when compiling for AArch32.)
+                endif
+        endif
+endif
+
+$(eval $(call assert_boolean,ENABLE_BACKTRACE))
+$(eval $(call add_define,ENABLE_BACKTRACE))
diff --git a/common/bl_common.c b/common/bl_common.c
new file mode 100644
index 0000000..a09cd71
--- /dev/null
+++ b/common/bl_common.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#if TRUSTED_BOARD_BOOT
+# ifdef DYN_DISABLE_AUTH
+static int disable_auth;
+
+/******************************************************************************
+ * API to dynamically disable authentication. Only meant for development
+ * systems. This is only invoked if DYN_DISABLE_AUTH is defined.
+ *****************************************************************************/
+void dyn_disable_auth(void)
+{
+	INFO("Disabling authentication of images dynamically\n");
+	disable_auth = 1;
+}
+# endif /* DYN_DISABLE_AUTH */
+
+/******************************************************************************
+ * Function to determine whether the authentication is disabled dynamically.
+ *****************************************************************************/
+static int dyn_is_auth_disabled(void)
+{
+# ifdef DYN_DISABLE_AUTH
+	return disable_auth;
+# else
+	return 0;
+# endif
+}
+#endif /* TRUSTED_BOARD_BOOT */
+
+uintptr_t page_align(uintptr_t value, unsigned dir)
+{
+	/* Round up the limit to the next page boundary */
+	if ((value & (PAGE_SIZE - 1U)) != 0U) {
+		value &= ~(PAGE_SIZE - 1U);
+		if (dir == UP)
+			value += PAGE_SIZE;
+	}
+
+	return value;
+}
+
+/*******************************************************************************
+ * Internal function to load an image at a specific address given
+ * an image ID and extents of free memory.
+ *
+ * If the load is successful then the image information is updated.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ ******************************************************************************/
+static int load_image(unsigned int image_id, image_info_t *image_data)
+{
+	uintptr_t dev_handle;
+	uintptr_t image_handle;
+	uintptr_t image_spec;
+	uintptr_t image_base;
+	size_t image_size;
+	size_t bytes_read;
+	int io_result;
+
+	assert(image_data != NULL);
+	assert(image_data->h.version >= VERSION_2);
+
+	image_base = image_data->image_base;
+
+	/* Obtain a reference to the image by querying the platform layer */
+	io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
+	if (io_result != 0) {
+		WARN("Failed to obtain reference to image id=%u (%i)\n",
+			image_id, io_result);
+		return io_result;
+	}
+
+	/* Attempt to access the image */
+	io_result = io_open(dev_handle, image_spec, &image_handle);
+	if (io_result != 0) {
+		WARN("Failed to access image id=%u (%i)\n",
+			image_id, io_result);
+		return io_result;
+	}
+
+	INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base);
+
+	/* Find the size of the image */
+	io_result = io_size(image_handle, &image_size);
+	if ((io_result != 0) || (image_size == 0U)) {
+		WARN("Failed to determine the size of the image id=%u (%i)\n",
+			image_id, io_result);
+		goto exit;
+	}
+
+	/* Check that the image size to load is within limit */
+	if (image_size > image_data->image_max_size) {
+		WARN("Image id=%u size out of bounds\n", image_id);
+		io_result = -EFBIG;
+		goto exit;
+	}
+
+	/*
+	 * image_data->image_max_size is a uint32_t so image_size will always
+	 * fit in image_data->image_size.
+	 */
+	image_data->image_size = (uint32_t)image_size;
+
+	/* We have enough space so load the image now */
+	/* TODO: Consider whether to try to recover/retry a partially successful read */
+	io_result = io_read(image_handle, image_base, image_size, &bytes_read);
+	if ((io_result != 0) || (bytes_read < image_size)) {
+		WARN("Failed to load image id=%u (%i)\n", image_id, io_result);
+		goto exit;
+	}
+
+	INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base,
+	     (uintptr_t)(image_base + image_size));
+
+exit:
+	(void)io_close(image_handle);
+	/* Ignore improbable/unrecoverable error in 'close' */
+
+	/* TODO: Consider maintaining open device connection from this bootloader stage */
+	(void)io_dev_close(dev_handle);
+	/* Ignore improbable/unrecoverable error in 'dev_close' */
+
+	return io_result;
+}
+
+static int load_auth_image_internal(unsigned int image_id,
+				    image_info_t *image_data,
+				    int is_parent_image)
+{
+	int rc;
+
+#if TRUSTED_BOARD_BOOT
+	if (dyn_is_auth_disabled() == 0) {
+		unsigned int parent_id;
+
+		/* Use recursion to authenticate parent images */
+		rc = auth_mod_get_parent_id(image_id, &parent_id);
+		if (rc == 0) {
+			rc = load_auth_image_internal(parent_id, image_data, 1);
+			if (rc != 0) {
+				return rc;
+			}
+		}
+	}
+#endif /* TRUSTED_BOARD_BOOT */
+
+	/* Load the image */
+	rc = load_image(image_id, image_data);
+	if (rc != 0) {
+		return rc;
+	}
+
+#if TRUSTED_BOARD_BOOT
+	if (dyn_is_auth_disabled() == 0) {
+		/* Authenticate it */
+		rc = auth_mod_verify_img(image_id,
+					 (void *)image_data->image_base,
+					 image_data->image_size);
+		if (rc != 0) {
+			/* Authentication error, zero memory and flush it right away. */
+			zero_normalmem((void *)image_data->image_base,
+			       image_data->image_size);
+			flush_dcache_range(image_data->image_base,
+					   image_data->image_size);
+			return -EAUTH;
+		}
+	}
+#endif /* TRUSTED_BOARD_BOOT */
+
+	/*
+	 * Flush the image to main memory so that it can be executed later by
+	 * any CPU, regardless of cache and MMU state. If TBB is enabled, then
+	 * the file has been successfully loaded and authenticated and flush
+	 * only for child images, not for the parents (certificates).
+	 */
+	if (is_parent_image == 0) {
+		flush_dcache_range(image_data->image_base,
+				   image_data->image_size);
+	}
+
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Generic function to load and authenticate an image. The image is actually
+ * loaded by calling the 'load_image()' function. Therefore, it returns the
+ * same error codes if the loading operation failed, or -EAUTH if the
+ * authentication failed. In addition, this function uses recursion to
+ * authenticate the parent images up to the root of trust.
+ ******************************************************************************/
+int load_auth_image(unsigned int image_id, image_info_t *image_data)
+{
+	int err;
+
+	do {
+		err = load_auth_image_internal(image_id, image_data, 0);
+	} while ((err != 0) && (plat_try_next_boot_source() != 0));
+
+	return err;
+}
+
+/*******************************************************************************
+ * Print the content of an entry_point_info_t structure.
+ ******************************************************************************/
+void print_entry_point_info(const entry_point_info_t *ep_info)
+{
+	INFO("Entry point address = 0x%lx\n", ep_info->pc);
+	INFO("SPSR = 0x%x\n", ep_info->spsr);
+
+#define PRINT_IMAGE_ARG(n)					\
+	VERBOSE("Argument #" #n " = 0x%llx\n",			\
+		(unsigned long long) ep_info->args.arg##n)
+
+	PRINT_IMAGE_ARG(0);
+	PRINT_IMAGE_ARG(1);
+	PRINT_IMAGE_ARG(2);
+	PRINT_IMAGE_ARG(3);
+#ifdef __aarch64__
+	PRINT_IMAGE_ARG(4);
+	PRINT_IMAGE_ARG(5);
+	PRINT_IMAGE_ARG(6);
+	PRINT_IMAGE_ARG(7);
+#endif
+#undef PRINT_IMAGE_ARG
+}
+
+#ifdef __aarch64__
+/*******************************************************************************
+ * Handle all possible cases regarding ARMv8.3-PAuth.
+ ******************************************************************************/
+void bl_handle_pauth(void)
+{
+#if ENABLE_PAUTH
+	/*
+	 * ENABLE_PAUTH = 1 && CTX_INCLUDE_PAUTH_REGS = 1
+	 *
+	 * Check that the system supports address authentication to avoid
+	 * getting an access fault when accessing the registers. This is all
+	 * that is needed to check. If any of the authentication mechanisms is
+	 * supported, the system knows about ARMv8.3-PAuth, so all the registers
+	 * are available and accessing them won't generate a fault.
+	 *
+	 * Obtain 128-bit instruction key A from the platform and save it to the
+	 * system registers. Pointer authentication can't be enabled here or the
+	 * authentication will fail when returning from this function.
+	 */
+	assert(is_armv8_3_pauth_apa_api_present());
+
+	uint64_t *apiakey = plat_init_apiakey();
+
+	write_apiakeylo_el1(apiakey[0]);
+	write_apiakeyhi_el1(apiakey[1]);
+#else /* if !ENABLE_PAUTH */
+
+# if CTX_INCLUDE_PAUTH_REGS
+	/*
+	 * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 1
+	 *
+	 * Assert that the ARMv8.3-PAuth registers are present or an access
+	 * fault will be triggered when they are being saved or restored.
+	 */
+	assert(is_armv8_3_pauth_present());
+# else
+	/*
+	 * ENABLE_PAUTH = 0 && CTX_INCLUDE_PAUTH_REGS = 0
+	 *
+	 * Pointer authentication is allowed in the Non-secure world, but
+	 * prohibited in the Secure world. The Trusted Firmware doesn't save the
+	 * registers during a world switch. No check needed.
+	 */
+# endif /* CTX_INCLUDE_PAUTH_REGS */
+
+#endif /* ENABLE_PAUTH */
+}
+#endif /* __aarch64__ */
diff --git a/common/desc_image_load.c b/common/desc_image_load.c
new file mode 100644
index 0000000..f2e8f60
--- /dev/null
+++ b/common/desc_image_load.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <common/tbbr/tbbr_img_def.h>
+
+static bl_load_info_t bl_load_info;
+static bl_params_t next_bl_params;
+
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void flush_bl_params_desc(void)
+{
+	flush_bl_params_desc_args(bl_mem_params_desc_ptr,
+		bl_mem_params_desc_num,
+		&next_bl_params);
+}
+
+/*******************************************************************************
+ * This function flushes the data structures specified as arguments so that they
+ * are visible in memory for the next BL image.
+ ******************************************************************************/
+void flush_bl_params_desc_args(bl_mem_params_node_t *mem_params_desc_ptr,
+	unsigned int mem_params_desc_num,
+	bl_params_t *next_bl_params_ptr)
+{
+	assert(mem_params_desc_ptr != NULL);
+	assert(mem_params_desc_num != 0U);
+	assert(next_bl_params_ptr != NULL);
+
+	flush_dcache_range((uintptr_t)mem_params_desc_ptr,
+		sizeof(*mem_params_desc_ptr) * mem_params_desc_num);
+
+	flush_dcache_range((uintptr_t)next_bl_params_ptr,
+			sizeof(*next_bl_params_ptr));
+}
+
+/*******************************************************************************
+ * This function returns the index for given image_id, within the
+ * image descriptor array provided by bl_image_info_descs_ptr, if the
+ * image is found else it returns -1.
+ ******************************************************************************/
+int get_bl_params_node_index(unsigned int image_id)
+{
+	unsigned int index;
+	assert(image_id != INVALID_IMAGE_ID);
+
+	for (index = 0U; index < bl_mem_params_desc_num; index++) {
+		if (bl_mem_params_desc_ptr[index].image_id == image_id)
+			return (int)index;
+	}
+
+	return -1;
+}
+
+/*******************************************************************************
+ * This function returns the pointer to `bl_mem_params_node_t` object for
+ * given image_id, within the image descriptor array provided by
+ * bl_mem_params_desc_ptr, if the image is found else it returns NULL.
+ ******************************************************************************/
+bl_mem_params_node_t *get_bl_mem_params_node(unsigned int image_id)
+{
+	int index;
+	assert(image_id != INVALID_IMAGE_ID);
+
+	index = get_bl_params_node_index(image_id);
+	if (index >= 0)
+		return &bl_mem_params_desc_ptr[index];
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * This function creates the list of loadable images, by populating and
+ * linking each `bl_load_info_node_t` type node, using the internal array
+ * of image descriptor provided by bl_mem_params_desc_ptr. It also populates
+ * and returns `bl_load_info_t` type structure that contains head of the list
+ * of loadable images.
+ ******************************************************************************/
+bl_load_info_t *get_bl_load_info_from_mem_params_desc(void)
+{
+	unsigned int index = 0;
+
+	/* If there is no image to start with, return NULL */
+	if (bl_mem_params_desc_num == 0U)
+		return NULL;
+
+	/* Assign initial data structures */
+	bl_load_info_node_t *bl_node_info =
+		&bl_mem_params_desc_ptr[index].load_node_mem;
+	bl_load_info.head = bl_node_info;
+	SET_PARAM_HEAD(&bl_load_info, PARAM_BL_LOAD_INFO, VERSION_2, 0U);
+
+	/* Go through the image descriptor array and create the list */
+	for (; index < bl_mem_params_desc_num; index++) {
+
+		/* Populate the image information */
+		bl_node_info->image_id = bl_mem_params_desc_ptr[index].image_id;
+		bl_node_info->image_info = &bl_mem_params_desc_ptr[index].image_info;
+
+		/* Link next image if present */
+		if ((index + 1U) < bl_mem_params_desc_num) {
+			/* Get the memory and link the next node */
+			bl_node_info->next_load_info =
+				&bl_mem_params_desc_ptr[index + 1U].load_node_mem;
+			bl_node_info = bl_node_info->next_load_info;
+		}
+	}
+
+	return &bl_load_info;
+}
+
+/*******************************************************************************
+ * This function creates the list of executable images, by populating and
+ * linking each `bl_params_node_t` type node, using the internal array of
+ * image descriptor provided by bl_mem_params_desc_ptr. It also populates
+ * and returns `bl_params_t` type structure that contains head of the list
+ * of executable images.
+ ******************************************************************************/
+bl_params_t *get_next_bl_params_from_mem_params_desc(void)
+{
+	unsigned int count;
+	unsigned int img_id = 0U;
+	unsigned int link_index = 0U;
+	bl_params_node_t *bl_current_exec_node = NULL;
+	bl_params_node_t *bl_last_exec_node = NULL;
+	bl_mem_params_node_t *desc_ptr;
+
+	/* If there is no image to start with, return NULL */
+	if (bl_mem_params_desc_num == 0U)
+		return NULL;
+
+	/* Get the list HEAD */
+	for (count = 0U; count < bl_mem_params_desc_num; count++) {
+
+		desc_ptr = &bl_mem_params_desc_ptr[count];
+
+		if ((EP_GET_EXE(desc_ptr->ep_info.h.attr) == EXECUTABLE) &&
+			(EP_GET_FIRST_EXE(desc_ptr->ep_info.h.attr) == EP_FIRST_EXE)) {
+			next_bl_params.head = &desc_ptr->params_node_mem;
+			link_index = count;
+			break;
+		}
+	}
+
+	/* Make sure we have a HEAD node */
+	assert(next_bl_params.head != NULL);
+
+	/* Populate the HEAD information */
+	SET_PARAM_HEAD(&next_bl_params, PARAM_BL_PARAMS, VERSION_2, 0U);
+
+	/*
+	 * Go through the image descriptor array and create the list.
+	 * This bounded loop is to make sure that we are not looping forever.
+	 */
+	for (count = 0U; count < bl_mem_params_desc_num; count++) {
+
+		desc_ptr = &bl_mem_params_desc_ptr[link_index];
+
+		/* Make sure the image is executable */
+		assert(EP_GET_EXE(desc_ptr->ep_info.h.attr) == EXECUTABLE);
+
+		/* Get the memory for current node */
+		bl_current_exec_node = &desc_ptr->params_node_mem;
+
+		/* Populate the image information */
+		bl_current_exec_node->image_id = desc_ptr->image_id;
+		bl_current_exec_node->image_info = &desc_ptr->image_info;
+		bl_current_exec_node->ep_info = &desc_ptr->ep_info;
+
+		if (bl_last_exec_node != NULL) {
+			/* Assert if loop detected */
+			assert(bl_last_exec_node->next_params_info == NULL);
+
+			/* Link the previous node to the current one */
+			bl_last_exec_node->next_params_info = bl_current_exec_node;
+		}
+
+		/* Update the last node */
+		bl_last_exec_node = bl_current_exec_node;
+
+		/* If no next hand-off image then break out */
+		img_id = desc_ptr->next_handoff_image_id;
+		if (img_id == INVALID_IMAGE_ID)
+			break;
+
+		/* Get the index for the next hand-off image */
+		link_index = get_bl_params_node_index(img_id);
+		assert((link_index > 0U) &&
+			(link_index < bl_mem_params_desc_num));
+	}
+
+	/* Invalid image is expected to terminate the loop */
+	assert(img_id == INVALID_IMAGE_ID);
+
+	return &next_bl_params;
+}
+
+/*******************************************************************************
+ * This function populates the entry point information with the corresponding
+ * config file for all executable BL images described in bl_params.
+ ******************************************************************************/
+void populate_next_bl_params_config(bl_params_t *bl2_to_next_bl_params)
+{
+	bl_params_node_t *params_node;
+	unsigned int fw_config_id;
+	uintptr_t hw_config_base = 0, fw_config_base;
+	bl_mem_params_node_t *mem_params;
+
+	assert(bl2_to_next_bl_params != NULL);
+
+	/*
+	 * Get the `bl_mem_params_node_t` corresponding to HW_CONFIG
+	 * if available.
+	 */
+	mem_params = get_bl_mem_params_node(HW_CONFIG_ID);
+	if (mem_params != NULL)
+		hw_config_base = mem_params->image_info.image_base;
+
+	for (params_node = bl2_to_next_bl_params->head; params_node != NULL;
+			params_node = params_node->next_params_info) {
+
+		fw_config_base = 0;
+
+		switch (params_node->image_id) {
+		case BL31_IMAGE_ID:
+			fw_config_id = SOC_FW_CONFIG_ID;
+			break;
+		case BL32_IMAGE_ID:
+			fw_config_id = TOS_FW_CONFIG_ID;
+			break;
+		case BL33_IMAGE_ID:
+			fw_config_id = NT_FW_CONFIG_ID;
+			break;
+		default:
+			fw_config_id = INVALID_IMAGE_ID;
+			break;
+		}
+
+		if (fw_config_id != INVALID_IMAGE_ID) {
+			mem_params = get_bl_mem_params_node(fw_config_id);
+			if (mem_params != NULL)
+				fw_config_base = mem_params->image_info.image_base;
+		}
+
+		/*
+		 * Pass hw and tb_fw config addresses to next images. NOTE - for
+		 * EL3 runtime images (BL31 for AArch64 and BL32 for AArch32),
+		 * arg0 is already used by generic code. Take care of not
+		 * overwriting the previous initialisations.
+		 */
+		if (params_node == bl2_to_next_bl_params->head) {
+			if (params_node->ep_info->args.arg1 == 0U)
+				params_node->ep_info->args.arg1 =
+								fw_config_base;
+			if (params_node->ep_info->args.arg2 == 0U)
+				params_node->ep_info->args.arg2 =
+								hw_config_base;
+		} else {
+			if (params_node->ep_info->args.arg0 == 0U)
+				params_node->ep_info->args.arg0 =
+								fw_config_base;
+			if (params_node->ep_info->args.arg1 == 0U)
+				params_node->ep_info->args.arg1 =
+								hw_config_base;
+		}
+	}
+}
+
+/*******************************************************************************
+ * Helper to extract BL32/BL33 entry point info from arg0 passed to BL31, for
+ * platforms that are only interested in those. Platforms that need to extract
+ * more information can parse the structures themselves.
+ ******************************************************************************/
+
+void bl31_params_parse_helper(u_register_t param,
+			      entry_point_info_t *bl32_ep_info_out,
+			      entry_point_info_t *bl33_ep_info_out)
+{
+	bl_params_node_t *node;
+	bl_params_t *v2 = (void *)(uintptr_t)param;
+
+#if !ERROR_DEPRECATED
+	if (v2->h.version == PARAM_VERSION_1) {
+		struct { /* Deprecated version 1 parameter structure. */
+			param_header_t h;
+			image_info_t *bl31_image_info;
+			entry_point_info_t *bl32_ep_info;
+			image_info_t *bl32_image_info;
+			entry_point_info_t *bl33_ep_info;
+			image_info_t *bl33_image_info;
+		} *v1 = (void *)(uintptr_t)param;
+		assert(v1->h.type == PARAM_BL31);
+		if (bl32_ep_info_out)
+			*bl32_ep_info_out = *v1->bl32_ep_info;
+		if (bl33_ep_info_out)
+			*bl33_ep_info_out = *v1->bl33_ep_info;
+		return;
+	}
+#endif /* !ERROR_DEPRECATED */
+
+	assert(v2->h.version == PARAM_VERSION_2);
+	assert(v2->h.type == PARAM_BL_PARAMS);
+	for (node = v2->head; node; node = node->next_params_info) {
+		if (node->image_id == BL32_IMAGE_ID)
+			if (bl32_ep_info_out)
+				*bl32_ep_info_out = *node->ep_info;
+		if (node->image_id == BL33_IMAGE_ID)
+			if (bl33_ep_info_out)
+				*bl33_ep_info_out = *node->ep_info;
+	}
+}
diff --git a/common/fdt_wrappers.c b/common/fdt_wrappers.c
new file mode 100644
index 0000000..e67fdb0
--- /dev/null
+++ b/common/fdt_wrappers.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Helper functions to offer easier navigation of Device Tree Blob */
+
+#include <assert.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+
+/*
+ * Read cells from a given property of the given node. At most 2 cells of the
+ * property are read, and pointer is updated. Returns 0 on success, and -1 upon
+ * error
+ */
+int fdtw_read_cells(const void *dtb, int node, const char *prop,
+		unsigned int cells, void *value)
+{
+	const uint32_t *value_ptr;
+	uint32_t hi = 0, lo;
+	int value_len;
+
+	assert(dtb != NULL);
+	assert(prop != NULL);
+	assert(value != NULL);
+	assert(node >= 0);
+
+	/* We expect either 1 or 2 cell property */
+	assert(cells <= 2U);
+
+	/* Access property and obtain its length (in bytes) */
+	value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
+			&value_len);
+	if (value_ptr == NULL) {
+		WARN("Couldn't find property %s in dtb\n", prop);
+		return -1;
+	}
+
+	/* Verify that property length accords with cell length */
+	if (NCELLS((unsigned int)value_len) != cells) {
+		WARN("Property length mismatch\n");
+		return -1;
+	}
+
+	if (cells == 2U) {
+		hi = fdt32_to_cpu(*value_ptr);
+		value_ptr++;
+	}
+
+	lo = fdt32_to_cpu(*value_ptr);
+
+	if (cells == 2U)
+		*((uint64_t *) value) = ((uint64_t) hi << 32) | lo;
+	else
+		*((uint32_t *) value) = lo;
+
+	return 0;
+}
+
+/*
+ * Read cells from a given property of the given node. Any number of 32-bit
+ * cells of the property can be read. The fdt pointer is updated. Returns 0 on
+ * success, and -1 on error.
+ */
+int fdtw_read_array(const void *dtb, int node, const char *prop,
+		unsigned int cells, void *value)
+{
+	const uint32_t *value_ptr;
+	int value_len;
+
+	assert(dtb != NULL);
+	assert(prop != NULL);
+	assert(value != NULL);
+	assert(node >= 0);
+
+	/* Access property and obtain its length (in bytes) */
+	value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
+			&value_len);
+	if (value_ptr == NULL) {
+		WARN("Couldn't find property %s in dtb\n", prop);
+		return -1;
+	}
+
+	/* Verify that property length accords with cell length */
+	if (NCELLS((unsigned int)value_len) != cells) {
+		WARN("Property length mismatch\n");
+		return -1;
+	}
+
+	uint32_t *dst = value;
+
+	for (unsigned int i = 0U; i < cells; i++) {
+		dst[i] = fdt32_to_cpu(value_ptr[i]);
+	}
+
+	return 0;
+}
+
+/*
+ * Read string from a given property of the given node. Up to 'size - 1'
+ * characters are read, and a NUL terminator is added. Returns 0 on success,
+ * and -1 upon error.
+ */
+int fdtw_read_string(const void *dtb, int node, const char *prop,
+		char *str, size_t size)
+{
+	const char *ptr;
+	size_t len;
+
+	assert(dtb != NULL);
+	assert(node >= 0);
+	assert(prop != NULL);
+	assert(str != NULL);
+	assert(size > 0U);
+
+	ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL);
+	if (ptr == NULL) {
+		WARN("Couldn't find property %s in dtb\n", prop);
+		return -1;
+	}
+
+	len = strlcpy(str, ptr, size);
+	if (len >= size) {
+		WARN("String of property %s in dtb has been truncated\n", prop);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Write cells in place to a given property of the given node. At most 2 cells
+ * of the property are written. Returns 0 on success, and -1 upon error.
+ */
+int fdtw_write_inplace_cells(void *dtb, int node, const char *prop,
+		unsigned int cells, void *value)
+{
+	int err, len;
+
+	assert(dtb != NULL);
+	assert(prop != NULL);
+	assert(value != NULL);
+	assert(node >= 0);
+
+	/* We expect either 1 or 2 cell property */
+	assert(cells <= 2U);
+
+	if (cells == 2U)
+		*(uint64_t *)value = cpu_to_fdt64(*(uint64_t *)value);
+	else
+		*(uint32_t *)value = cpu_to_fdt32(*(uint32_t *)value);
+
+	len = (int)cells * 4;
+
+	/* Set property value in place */
+	err = fdt_setprop_inplace(dtb, node, prop, value, len);
+	if (err != 0) {
+		WARN("Modify property %s failed with error %d\n", prop, err);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/common/image_decompress.c b/common/image_decompress.c
new file mode 100644
index 0000000..a4586ae
--- /dev/null
+++ b/common/image_decompress.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/image_decompress.h>
+
+static uintptr_t decompressor_buf_base;
+static uint32_t decompressor_buf_size;
+static decompressor_t *decompressor;
+static struct image_info saved_image_info;
+
+void image_decompress_init(uintptr_t buf_base, uint32_t buf_size,
+			   decompressor_t *_decompressor)
+{
+	decompressor_buf_base = buf_base;
+	decompressor_buf_size = buf_size;
+	decompressor = _decompressor;
+}
+
+void image_decompress_prepare(struct image_info *info)
+{
+	/*
+	 * If the image is compressed, it should be loaded into the temporary
+	 * buffer instead of its final destination.  We save image_info, then
+	 * override ->image_base and ->image_max_size so that load_image() will
+	 * transfer the compressed data to the temporary buffer.
+	 */
+	saved_image_info = *info;
+	info->image_base = decompressor_buf_base;
+	info->image_max_size = decompressor_buf_size;
+}
+
+int image_decompress(struct image_info *info)
+{
+	uintptr_t compressed_image_base, image_base, work_base;
+	uint32_t compressed_image_size, work_size;
+	int ret;
+
+	/*
+	 * The size of compressed data has been filled by load_image().
+	 * Read it out before restoring image_info.
+	 */
+	compressed_image_size = info->image_size;
+	compressed_image_base = info->image_base;
+	*info = saved_image_info;
+
+	assert(compressed_image_size <= decompressor_buf_size);
+
+	image_base = info->image_base;
+
+	/*
+	 * Use the rest of the temporary buffer as workspace of the
+	 * decompressor since the decompressor may need additional memory.
+	 */
+	work_base = compressed_image_base + compressed_image_size;
+	work_size = decompressor_buf_size - compressed_image_size;
+
+	ret = decompressor(&compressed_image_base, compressed_image_size,
+			   &image_base, info->image_max_size,
+			   work_base, work_size);
+	if (ret) {
+		ERROR("Failed to decompress image (err=%d)\n", ret);
+		return ret;
+	}
+
+	/* image_base is updated to the final pos when decompressor() exits. */
+	info->image_size = image_base - info->image_base;
+
+	flush_dcache_range(info->image_base, info->image_size);
+
+	return 0;
+}
diff --git a/common/runtime_svc.c b/common/runtime_svc.c
new file mode 100644
index 0000000..a2c0c09
--- /dev/null
+++ b/common/runtime_svc.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+
+/*******************************************************************************
+ * The 'rt_svc_descs' array holds the runtime service descriptors exported by
+ * services by placing them in the 'rt_svc_descs' linker section.
+ * The 'rt_svc_descs_indices' array holds the index of a descriptor in the
+ * 'rt_svc_descs' array. When an SMC arrives, the OEN[29:24] bits and the call
+ * type[31] bit in the function id are combined to get an index into the
+ * 'rt_svc_descs_indices' array. This gives the index of the descriptor in the
+ * 'rt_svc_descs' array which contains the SMC handler.
+ ******************************************************************************/
+uint8_t rt_svc_descs_indices[MAX_RT_SVCS];
+
+#define RT_SVC_DECS_NUM		((RT_SVC_DESCS_END - RT_SVC_DESCS_START)\
+					/ sizeof(rt_svc_desc_t))
+
+/*******************************************************************************
+ * Function to invoke the registered `handle` corresponding to the smc_fid in
+ * AArch32 mode.
+ ******************************************************************************/
+uintptr_t handle_runtime_svc(uint32_t smc_fid,
+			     void *cookie,
+			     void *handle,
+			     unsigned int flags)
+{
+	u_register_t x1, x2, x3, x4;
+	unsigned int index;
+	unsigned int idx;
+	const rt_svc_desc_t *rt_svc_descs;
+
+	assert(handle != NULL);
+	idx = get_unique_oen_from_smc_fid(smc_fid);
+	assert(idx < MAX_RT_SVCS);
+
+	index = rt_svc_descs_indices[idx];
+	if (index >= RT_SVC_DECS_NUM)
+		SMC_RET1(handle, SMC_UNK);
+
+	rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
+
+	get_smc_params_from_ctx(handle, x1, x2, x3, x4);
+
+	return rt_svc_descs[index].handle(smc_fid, x1, x2, x3, x4, cookie,
+						handle, flags);
+}
+
+/*******************************************************************************
+ * Simple routine to sanity check a runtime service descriptor before using it
+ ******************************************************************************/
+static int32_t validate_rt_svc_desc(const rt_svc_desc_t *desc)
+{
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (desc->start_oen > desc->end_oen)
+		return -EINVAL;
+
+	if (desc->end_oen >= OEN_LIMIT)
+		return -EINVAL;
+
+	if ((desc->call_type != SMC_TYPE_FAST) &&
+	    (desc->call_type != SMC_TYPE_YIELD))
+		return -EINVAL;
+
+	/* A runtime service having no init or handle function doesn't make sense */
+	if ((desc->init == NULL) && (desc->handle == NULL))
+		return -EINVAL;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function calls the initialisation routine in the descriptor exported by
+ * a runtime service. Once a descriptor has been validated, its start & end
+ * owning entity numbers and the call type are combined to form a unique oen.
+ * The unique oen is used as an index into the 'rt_svc_descs_indices' array.
+ * The index of the runtime service descriptor is stored at this index.
+ ******************************************************************************/
+void __init runtime_svc_init(void)
+{
+	int rc = 0;
+	uint8_t index, start_idx, end_idx;
+	rt_svc_desc_t *rt_svc_descs;
+
+	/* Assert the number of descriptors detected are less than maximum indices */
+	assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&
+			(RT_SVC_DECS_NUM < MAX_RT_SVCS));
+
+	/* If no runtime services are implemented then simply bail out */
+	if (RT_SVC_DECS_NUM == 0U)
+		return;
+
+	/* Initialise internal variables to invalid state */
+	(void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));
+
+	rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;
+	for (index = 0U; index < RT_SVC_DECS_NUM; index++) {
+		rt_svc_desc_t *service = &rt_svc_descs[index];
+
+		/*
+		 * An invalid descriptor is an error condition since it is
+		 * difficult to predict the system behaviour in the absence
+		 * of this service.
+		 */
+		rc = validate_rt_svc_desc(service);
+		if (rc != 0) {
+			ERROR("Invalid runtime service descriptor %p\n",
+				(void *) service);
+			panic();
+		}
+
+		/*
+		 * The runtime service may have separate rt_svc_desc_t
+		 * for its fast smc and yielding smc. Since the service itself
+		 * need to be initialized only once, only one of them will have
+		 * an initialisation routine defined. Call the initialisation
+		 * routine for this runtime service, if it is defined.
+		 */
+		if (service->init != NULL) {
+			rc = service->init();
+			if (rc != 0) {
+				ERROR("Error initializing runtime service %s\n",
+						service->name);
+				continue;
+			}
+		}
+
+		/*
+		 * Fill the indices corresponding to the start and end
+		 * owning entity numbers with the index of the
+		 * descriptor which will handle the SMCs for this owning
+		 * entity range.
+		 */
+		start_idx = (uint8_t)get_unique_oen(service->start_oen,
+						    service->call_type);
+		end_idx = (uint8_t)get_unique_oen(service->end_oen,
+						  service->call_type);
+		assert(start_idx <= end_idx);
+		assert(end_idx < MAX_RT_SVCS);
+		for (; start_idx <= end_idx; start_idx++)
+			rt_svc_descs_indices[start_idx] = index;
+	}
+}
diff --git a/common/tf_log.c b/common/tf_log.c
new file mode 100644
index 0000000..08d3cf4
--- /dev/null
+++ b/common/tf_log.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/* Set the default maximum log level to the `LOG_LEVEL` build flag */
+static unsigned int max_log_level = LOG_LEVEL;
+
+/*
+ * The common log function which is invoked by TF-A code.
+ * This function should not be directly invoked and is meant to be
+ * only used by the log macros defined in debug.h. The function
+ * expects the first character in the format string to be one of the
+ * LOG_MARKER_* macros defined in debug.h.
+ */
+void tf_log(const char *fmt, ...)
+{
+	unsigned int log_level;
+	va_list args;
+	const char *prefix_str;
+
+	/* We expect the LOG_MARKER_* macro as the first character */
+	log_level = fmt[0];
+
+	/* Verify that log_level is one of LOG_MARKER_* macro defined in debug.h */
+	assert((log_level > 0U) && (log_level <= LOG_LEVEL_VERBOSE));
+	assert((log_level % 10U) == 0U);
+
+	if (log_level > max_log_level)
+		return;
+
+	prefix_str = plat_log_get_prefix(log_level);
+
+	while (*prefix_str != '\0') {
+		(void)putchar(*prefix_str);
+		prefix_str++;
+	}
+
+	va_start(args, fmt);
+	(void)vprintf(fmt + 1, args);
+	va_end(args);
+}
+
+/*
+ * The helper function to set the log level dynamically by platform. The
+ * maximum log level is determined by `LOG_LEVEL` build flag at compile time
+ * and this helper can set a lower (or equal) log level than the one at compile.
+ */
+void tf_log_set_max_level(unsigned int log_level)
+{
+	assert(log_level <= LOG_LEVEL_VERBOSE);
+	assert((log_level % 10U) == 0U);
+
+	/* Cap log_level to the compile time maximum. */
+	if (log_level <= (unsigned int)LOG_LEVEL)
+		max_log_level = log_level;
+}
diff --git a/dco.txt b/dco.txt
new file mode 100644
index 0000000..8201f99
--- /dev/null
+++ b/dco.txt
@@ -0,0 +1,37 @@
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+1 Letterman Drive
+Suite D4700
+San Francisco, CA, 94129
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..eed3a08
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2019, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+SPHINXPROJ    = TrustedFirmware-A
+SOURCEDIR     = .
+BUILDDIR      = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/acknowledgements.rst b/docs/acknowledgements.rst
new file mode 100644
index 0000000..74b77ff
--- /dev/null
+++ b/docs/acknowledgements.rst
@@ -0,0 +1,17 @@
+Contributor Acknowledgements
+============================
+
+.. note::
+   This file is only relevant for legacy contributions, to acknowledge the
+   specific contributors referred to in "Arm Limited and Contributors" copyright
+   notices. As contributors are now encouraged to put their name or company name
+   directly into the copyright notices, this file is not relevant for new
+   contributions.
+
+- Linaro Limited
+- Marvell International Ltd.
+- NVIDIA Corporation
+- NXP Semiconductors
+- Socionext Inc.
+- STMicroelectronics
+- Xilinx, Inc.
diff --git a/docs/change-log.rst b/docs/change-log.rst
new file mode 100644
index 0000000..70aafc0
--- /dev/null
+++ b/docs/change-log.rst
@@ -0,0 +1,2438 @@
+Change Log & Release Notes
+==========================
+
+This document contains a summary of the new features, changes, fixes and known
+issues in each release of Trusted Firmware-A.
+
+Version 2.1
+-----------
+
+New Features
+^^^^^^^^^^^^
+
+- Architecture
+   - Support for ARMv8.3 pointer authentication in the normal and secure worlds
+
+     The use of pointer authentication in the normal world is enabled whenever
+     architectural support is available, without the need for additional build
+     flags.
+
+     Use of pointer authentication in the secure world remains an
+     experimental configuration at this time. Using both the ``ENABLE_PAUTH``
+     and ``CTX_INCLUDE_PAUTH_REGS`` build flags, pointer authentication can be
+     enabled in EL3 and S-EL1/0.
+
+     See the `Firmware Design`_ document for additional details on the use of
+     pointer authentication.
+
+   - Enable Data Independent Timing (DIT) in EL3, where supported
+
+- Build System
+   - Support for BL-specific build flags
+
+   - Support setting compiler target architecture based on ``ARM_ARCH_MINOR``
+     build option.
+
+   - New ``RECLAIM_INIT_CODE`` build flag:
+
+     A significant amount of the code used for the initialization of BL31 is
+     not needed again after boot time. In order to reduce the runtime memory
+     footprint, the memory used for this code can be reclaimed after
+     initialization.
+
+     Certain boot-time functions were marked with the ``__init`` attribute to
+     enable this reclamation.
+
+- CPU Support
+   - cortex-a76: Workaround for erratum 1073348
+   - cortex-a76: Workaround for erratum 1220197
+   - cortex-a76: Workaround for erratum 1130799
+
+   - cortex-a75: Workaround for erratum 790748
+   - cortex-a75: Workaround for erratum 764081
+
+   - cortex-a73: Workaround for erratum 852427
+   - cortex-a73: Workaround for erratum 855423
+
+   - cortex-a57: Workaround for erratum 817169
+   - cortex-a57: Workaround for erratum 814670
+
+   - cortex-a55: Workaround for erratum 903758
+   - cortex-a55: Workaround for erratum 846532
+   - cortex-a55: Workaround for erratum 798797
+   - cortex-a55: Workaround for erratum 778703
+   - cortex-a55: Workaround for erratum 768277
+
+   - cortex-a53: Workaround for erratum 819472
+   - cortex-a53: Workaround for erratum 824069
+   - cortex-a53: Workaround for erratum 827319
+
+   - cortex-a17: Workaround for erratum 852423
+   - cortex-a17: Workaround for erratum 852421
+
+   - cortex-a15: Workaround for erratum 816470
+   - cortex-a15: Workaround for erratum 827671
+
+- Documentation
+   - Exception Handling Framework documentation
+
+   - Library at ROM (romlib) documentation
+
+   - RAS framework documentation
+
+   - Coding Guidelines document
+
+- Drivers
+   - ccn: Add API for setting and reading node registers
+      - Adds ``ccn_read_node_reg`` function
+      - Adds ``ccn_write_node_reg`` function
+
+   - partition: Support MBR partition entries
+
+   - scmi: Add ``plat_css_get_scmi_info`` function
+
+     Adds a new API ``plat_css_get_scmi_info`` which lets the platform
+     register a platform-specific instance of ``scmi_channel_plat_info_t`` and
+     remove the default values
+
+   - tzc380: Add TZC-380 TrustZone Controller driver
+
+   - tzc-dmc620: Add driver to manage the TrustZone Controller within the
+     DMC-620 Dynamic Memory Controller
+
+- Library at ROM (romlib)
+   - Add platform-specific jump table list
+
+   - Allow patching of romlib functions
+
+     This change allows patching of functions in the romlib. This can be done by
+     adding "patch" at the end of the jump table entry for the function that
+     needs to be patched in the file jmptbl.i.
+
+- Library Code
+   - Support non-LPAE-enabled MMU tables in AArch32
+
+   - mmio: Add ``mmio_clrsetbits_16`` function
+      - 16-bit variant of ``mmio_clrsetbits``
+
+   - object_pool: Add Object Pool Allocator
+      - Manages object allocation using a fixed-size static array
+      - Adds ``pool_alloc`` and ``pool_alloc_n`` functions
+      - Does not provide any functions to free allocated objects (by design)
+
+   - libc: Added ``strlcpy`` function
+
+   - libc: Import ``strrchr`` function from FreeBSD
+
+   - xlat_tables: Add support for ARMv8.4-TTST
+
+   - xlat_tables: Support mapping regions without an explicitly specified VA
+
+- Math
+   - Added softudiv macro to support software division
+
+- Memory Partitioning And Monitoring (MPAM)
+   - Enabled MPAM EL2 traps (``MPAMHCR_EL2`` and ``MPAM_EL2``)
+
+- Platforms
+   - amlogic: Add support for Meson S905 (GXBB)
+
+   - arm/fvp_ve: Add support for FVP Versatile Express platform
+
+   - arm/n1sdp: Add support for Neoverse N1 System Development platform
+
+   - arm/rde1edge: Add support for Neoverse E1 platform
+
+   - arm/rdn1edge: Add support for Neoverse N1 platform
+
+   - arm: Add support for booting directly to Linux without an intermediate
+     loader (AArch32)
+
+   - arm/juno: Enable new CPU errata workarounds for A53 and A57
+
+   - arm/juno: Add romlib support
+
+     Building a combined BL1 and ROMLIB binary file with the correct page
+     alignment is now supported on the Juno platform. When ``USE_ROMLIB`` is set
+     for Juno, it generates the combined file ``bl1_romlib.bin`` which needs to
+     be used instead of bl1.bin.
+
+   - intel/stratix: Add support for Intel Stratix 10 SoC FPGA platform
+
+   - marvell: Add support for Armada-37xx SoC platform
+
+   - nxp: Add support for i.MX8M and i.MX7 Warp7 platforms
+
+   - renesas: Add support for R-Car Gen3 platform
+
+   - xilinx: Add support for Versal ACAP platforms
+
+- Position-Independent Executable (PIE)
+
+  PIE support has initially been added to BL31. The ``ENABLE_PIE`` build flag is
+  used to enable or disable this functionality as required.
+
+- Secure Partition Manager
+   - New SPM implementation based on SPCI Alpha 1 draft specification
+
+     A new version of SPM has been implemented, based on the SPCI (Secure
+     Partition Client Interface) and SPRT (Secure Partition Runtime) draft
+     specifications.
+
+     The new implementation is a prototype that is expected to undergo intensive
+     rework as the specifications change. It has basic support for multiple
+     Secure Partitions and Resource Descriptions.
+
+     The older version of SPM, based on MM (ARM Management Mode Interface
+     Specification), is still present in the codebase. A new build flag,
+     ``SPM_MM`` has been added to allow selection of the desired implementation.
+     This flag defaults to 1, selecting the MM-based implementation.
+
+- Security
+   - Spectre Variant-1 mitigations (``CVE-2017-5753``)
+
+   - Use Speculation Store Bypass Safe (SSBS) functionality where available
+
+     Provides mitigation against ``CVE-2018-19440`` (Not saving x0 to x3
+     registers can leak information from one Normal World SMC client to another)
+
+
+Changed
+^^^^^^^
+
+- Build System
+   - Warning levels are now selectable with ``W=<1,2,3>``
+
+   - Removed unneeded include paths in PLAT_INCLUDES
+
+   - "Warnings as errors" (Werror) can be disabled using ``E=0``
+
+   - Support totally quiet output with ``-s`` flag
+
+   - Support passing options to checkpatch using ``CHECKPATCH_OPTS=<opts>``
+
+   - Invoke host compiler with ``HOSTCC / HOSTCCFLAGS`` instead of ``CC / CFLAGS``
+
+   - Make device tree pre-processing similar to U-boot/Linux by:
+      - Creating separate ``CPPFLAGS`` for DT preprocessing so that compiler
+        options specific to it can be accommodated.
+      - Replacing ``CPP`` with ``PP`` for DT pre-processing
+
+- CPU Support
+   - Errata report function definition is now mandatory for CPU support files
+
+     CPU operation files must now define a ``<name>_errata_report`` function to
+     print errata status. This is no longer a weak reference.
+
+- Documentation
+   - Migrated some content from GitHub wiki to ``docs/`` directory
+
+   - Security advisories now have CVE links
+
+   - Updated copyright guidelines
+
+- Drivers
+   - console: The ``MULTI_CONSOLE_API`` framework has been rewritten in C
+
+   - console: Ported multi-console driver to AArch32
+
+   - gic: Remove 'lowest priority' constants
+
+     Removed ``GIC_LOWEST_SEC_PRIORITY`` and ``GIC_LOWEST_NS_PRIORITY``.
+     Platforms should define these if required, or instead determine the correct
+     priority values at runtime.
+
+   - delay_timer: Check that the Generic Timer extension is present
+
+   - mmc: Increase command reply timeout to 10 milliseconds
+
+   - mmc: Poll eMMC device status to ensure ``EXT_CSD`` command completion
+
+   - mmc: Correctly check return code from ``mmc_fill_device_info``
+
+- External Libraries
+
+   - libfdt: Upgraded from 1.4.2 to 1.4.6-9
+
+   - mbed TLS: Upgraded from 2.12 to 2.16
+
+     This change incorporates fixes for security issues that should be reviewed
+     to determine if they are relevant for software implementations using
+     Trusted Firmware-A. See the `mbed TLS releases`_ page for details on
+     changes from the 2.12 to the 2.16 release.
+
+- Library Code
+   - compiler-rt: Updated ``lshrdi3.c`` and ``int_lib.h`` with changes from
+     LLVM master branch (r345645)
+
+   - cpu: Updated macro that checks need for ``CVE-2017-5715`` mitigation
+
+   - libc: Made setjmp and longjmp C standard compliant
+
+   - libc: Allowed overriding the default libc (use ``OVERRIDE_LIBC``)
+
+   - libc: Moved setjmp and longjmp to the ``libc/`` directory
+
+- Platforms
+   - Removed Mbed TLS dependency from plat_bl_common.c
+
+   - arm: Removed unused ``ARM_MAP_BL_ROMLIB`` macro
+
+   - arm: Removed ``ARM_BOARD_OPTIMISE_MEM`` feature and build flag
+
+   - arm: Moved several components into ``drivers/`` directory
+
+     This affects the SDS, SCP, SCPI, MHU and SCMI components
+
+   - arm/juno: Increased maximum BL2 image size to ``0xF000``
+
+     This change was required to accommodate a larger ``libfdt`` library
+
+- SCMI
+   - Optimized bakery locks when hardware-assisted coherency is enabled using the
+     ``HW_ASSISTED_COHERENCY`` build flag
+
+- SDEI
+   - Added support for unconditionally resuming secure world execution after
+     |SDEI| event processing completes
+
+     |SDEI| interrupts, although targeting EL3, occur on behalf of the non-secure
+     world, and may have higher priority than secure world
+     interrupts. Therefore they might preempt secure execution and yield
+     execution to the non-secure |SDEI| handler. Upon completion of |SDEI| event
+     handling, resume secure execution if it was preempted.
+
+- Translation Tables (XLAT)
+   - Dynamically detect need for ``Common not Private (TTBRn_ELx.CnP)`` bit
+
+     Properly handle the case where ``ARMv8.2-TTCNP`` is implemented in a CPU
+     that does not implement all mandatory v8.2 features (and so must claim to
+     implement a lower architecture version).
+
+
+Resolved Issues
+^^^^^^^^^^^^^^^
+
+- Architecture
+   - Incorrect check for SSBS feature detection
+
+   - Unintentional register clobber in AArch32 reset_handler function
+
+- Build System
+   - Dependency issue during DTB image build
+
+   - Incorrect variable expansion in Arm platform makefiles
+
+   - Building on Windows with verbose mode (``V=1``) enabled is broken
+
+   - AArch32 compilation flags is missing ``$(march32-directive)``
+
+- BL-Specific Issues
+   - bl2: ``uintptr_t is not defined`` error when ``BL2_IN_XIP_MEM`` is defined
+
+   - bl2: Missing prototype warning in ``bl2_arch_setup``
+
+   - bl31: Omission of Global Offset Table (GOT) section
+
+- Code Quality Issues
+   - Multiple MISRA compliance issues
+
+   - Potential NULL pointer dereference (Coverity-detected)
+
+- Drivers
+   - mmc: Local declaration of ``scr`` variable causes a cache issue when
+     invalidating after the read DMA transfer completes
+
+   - mmc: ``ACMD41`` does not send voltage information during initialization,
+     resulting in the command being treated as a query. This prevents the
+     command from initializing the controller.
+
+   - mmc: When checking device state using ``mmc_device_state()`` there are no
+     retries attempted in the event of an error
+
+   - ccn: Incorrect Region ID calculation for RN-I nodes
+
+   - console: ``Fix MULTI_CONSOLE_API`` when used as a crash console
+
+   - partition: Improper NULL checking in gpt.c
+
+   - partition: Compilation failure in ``VERBOSE`` mode (``V=1``)
+
+- Library Code
+   - common: Incorrect check for Address Authentication support
+
+   - xlat: Fix XLAT_V1 / XLAT_V2 incompatibility
+
+     The file ``arm_xlat_tables.h`` has been renamed to ``xlat_tables_compat.h``
+     and has been moved to a common folder. This header can be used to guarantee
+     compatibility, as it includes the correct header based on
+     ``XLAT_TABLES_LIB_V2``.
+
+   - xlat: armclang unused-function warning on ``xlat_clean_dcache_range``
+
+   - xlat: Invalid ``mm_cursor`` checks in ``mmap_add`` and ``mmap_add_ctx``
+
+   - sdei: Missing ``context.h`` header
+
+- Platforms
+   - common: Missing prototype warning for ``plat_log_get_prefix``
+
+   - arm: Insufficient maximum BL33 image size
+
+   - arm: Potential memory corruption during BL2-BL31 transition
+
+     On Arm platforms, the BL2 memory can be overlaid by BL31/BL32. The memory
+     descriptors describing the list of executable images are created in BL2
+     R/W memory, which could be possibly corrupted later on by BL31/BL32 due
+     to overlay. This patch creates a reserved location in SRAM for these
+     descriptors and are copied over by BL2 before handing over to next BL
+     image.
+
+   - juno: Invalid behaviour when ``CSS_USE_SCMI_SDS_DRIVER`` is not set
+
+     In ``juno_pm.c`` the ``css_scmi_override_pm_ops`` function was used
+     regardless of whether the build flag was set. The original behaviour has
+     been restored in the case where the build flag is not set.
+
+- Tools
+   - fiptool: Incorrect UUID parsing of blob parameters
+
+   - doimage: Incorrect object rules in Makefile
+
+
+Deprecations
+^^^^^^^^^^^^
+
+- Common Code
+   - ``plat_crash_console_init`` function
+
+   - ``plat_crash_console_putc`` function
+
+   - ``plat_crash_console_flush`` function
+
+   - ``finish_console_register`` macro
+
+- AArch64-specific Code
+   - helpers: ``get_afflvl_shift``
+
+   - helpers: ``mpidr_mask_lower_afflvls``
+
+   - helpers: ``eret``
+
+- Secure Partition Manager (SPM)
+   - Boot-info structure
+
+
+Known Issues
+^^^^^^^^^^^^
+
+- Build System Issues
+   - dtb: DTB creation not supported when building on a Windows host.
+
+     This step in the build process is skipped when running on a Windows host. A
+     known issue from the 1.6 release.
+
+- Platform Issues
+   - arm/juno: System suspend from Linux does not function as documented in the
+     user guide
+
+     Following the instructions provided in the user guide document does not
+     result in the platform entering system suspend state as expected. A message
+     relating to the hdlcd driver failing to suspend will be emitted on the
+     Linux terminal.
+
+   - arm/juno: The firmware update use-cases do not work with motherboard
+     firmware version < v1.5.0 (the reset reason is not preserved). The Linaro
+     18.04 release has MB v1.4.9. The MB v1.5.0 is available in Linaro 18.10
+     release.
+
+   - mediatek/mt6795: This platform does not build in this release
+
+Version 2.0
+-----------
+
+New Features
+^^^^^^^^^^^^
+
+-  Removal of a number of deprecated APIs
+
+   -  A new Platform Compatibility Policy document has been created which
+      references a wiki page that maintains a listing of deprecated
+      interfaces and the release after which they will be removed.
+
+   -  All deprecated interfaces except the MULTI_CONSOLE_API have been removed
+      from the code base.
+
+   -  Various Arm and partner platforms have been updated to remove the use of
+      removed APIs in this release.
+
+   -  This release is otherwise unchanged from 1.6 release
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  No issues known at 1.6 release resolved in 2.0 release
+
+Known Issues
+^^^^^^^^^^^^
+
+-  DTB creation not supported when building on a Windows host. This step in the
+   build process is skipped when running on a Windows host. Known issue from
+   1.6 version.
+
+-  As a result of removal of deprecated interfaces the Nvidia Tegra, Marvell
+   Armada 8K and MediaTek MT6795 platforms do not build in this release.
+   Also MediaTek MT8173, NXP QorIQ LS1043A, NXP i.MX8QX, NXP i.MX8QMa,
+   Rockchip RK3328, Rockchip RK3368 and Rockchip RK3399 platforms have not been
+   confirmed to be working after the removal of the deprecated interfaces
+   although they do build.
+
+Version 1.6
+-----------
+
+New Features
+^^^^^^^^^^^^
+
+-  Addressing Speculation Security Vulnerabilities
+
+   -  Implement static workaround for CVE-2018-3639 for AArch32 and AArch64
+
+   -  Add support for dynamic mitigation for CVE-2018-3639
+
+   -  Implement dynamic mitigation for CVE-2018-3639 on Cortex-A76
+
+   -  Ensure |SDEI| handler executes with CVE-2018-3639 mitigation enabled
+
+-  Introduce RAS handling on AArch64
+
+   -  Some RAS extensions are mandatory for Armv8.2 CPUs, with others
+      mandatory for Armv8.4 CPUs however, all extensions are also optional
+      extensions to the base Armv8.0 architecture.
+
+   -  The Armv8 RAS Extensions introduced Standard Error Records which are a
+      set of standard registers to configure RAS node policy and allow RAS
+      Nodes to record and expose error information for error handling agents.
+
+   -  Capabilities are provided to support RAS Node enumeration and iteration
+      along with individual interrupt registrations and fault injections
+      support.
+
+   -  Introduce handlers for Uncontainable errors, Double Faults and EL3
+      External Aborts
+
+-  Enable Memory Partitioning And Monitoring (MPAM) for lower EL's
+
+   -  Memory Partitioning And Monitoring is an Armv8.4 feature that enables
+      various memory system components and resources to define partitions.
+      Software running at various ELs can then assign themselves to the
+      desired partition to control their performance aspects.
+
+   -  When ENABLE_MPAM_FOR_LOWER_ELS is set to 1, EL3 allows
+      lower ELs to access their own MPAM registers without trapping to EL3.
+      This patch however, doesn't make use of partitioning in EL3; platform
+      initialisation code should configure and use partitions in EL3 if
+      required.
+
+-  Introduce ROM Lib Feature
+
+   -  Support combining several libraries into a self-called "romlib" image,
+      that may be shared across images to reduce memory footprint. The romlib
+      image is stored in ROM but is accessed through a jump-table that may be
+      stored in read-write memory, allowing for the library code to be patched.
+
+-  Introduce Backtrace Feature
+
+   -  This function displays the backtrace, the current EL and security state
+      to allow a post-processing tool to choose the right binary to interpret
+      the dump.
+
+   -  Print backtrace in assert() and panic() to the console.
+
+-  Code hygiene changes and alignment with MISRA C-2012 guideline with fixes
+   addressing issues complying to the following rules:
+
+   -  MISRA rules 4.9, 5.1, 5.3, 5.7, 8.2-8.5, 8.8, 8.13, 9.3, 10.1,
+      10.3-10.4, 10.8, 11.3, 11.6, 12.1, 14.4, 15.7, 16.1-16.7, 17.7-17.8,
+      20.7, 20.10, 20.12, 21.1, 21.15, 22.7
+
+   -  Clean up the usage of void pointers to access symbols
+
+   -  Increase usage of static qualifier to locally used functions and data
+
+   -  Migrated to use of u_register_t for register read/write to better
+      match AArch32 and AArch64 type sizes
+
+   -  Use int-ll64 for both AArch32 and AArch64 to assist in consistent
+      format strings between architectures
+
+   -  Clean up TF-A libc by removing non arm copyrighted implementations
+      and replacing them with modified FreeBSD and SCC implementations
+
+-  Various changes to support Clang linker and assembler
+
+   -  The clang assembler/preprocessor is used when Clang is selected. However,
+      the clang linker is not used because it is unable to link TF-A objects
+      due to immaturity of clang linker functionality at this time.
+
+-  Refactor support APIs into Libraries
+
+   -  Evolve libfdt, mbed TLS library and standard C library sources as
+      proper libraries that TF-A may be linked against.
+
+-  CPU Enhancements
+
+   -  Add CPU support for Cortex-Ares and Cortex-A76
+
+   -  Add AMU support for Cortex-Ares
+
+   -  Add initial CPU support for Cortex-Deimos
+
+   -  Add initial CPU support for Cortex-Helios
+
+   -  Implement dynamic mitigation for CVE-2018-3639 on Cortex-A76
+
+   -  Implement Cortex-Ares erratum 1043202 workaround
+
+   -  Implement DSU erratum 936184 workaround
+
+   -  Check presence of fix for errata 843419 in Cortex-A53
+
+   -  Check presence of fix for errata 835769 in Cortex-A53
+
+-  Translation Tables Enhancements
+
+   -  The xlat v2 library has been refactored in order to be reused by
+      different TF components at different EL's including the addition of EL2.
+      Some refactoring to make the code more generic and less specific to TF,
+      in order to reuse the library outside of this project.
+
+-  SPM Enhancements
+
+   -  General cleanups and refactoring to pave the way to multiple partitions
+      support
+
+-  SDEI Enhancements
+
+   -  Allow platforms to define explicit events
+
+   -  Determine client EL from NS context's SCR_EL3
+
+   -  Make dispatches synchronous
+
+   -  Introduce jump primitives for BL31
+
+   -  Mask events after CPU wakeup in |SDEI| dispatcher to conform to the
+      specification
+
+-  Misc TF-A Core Common Code Enhancements
+
+   -  Add support for eXecute In Place (XIP) memory in BL2
+
+   -  Add support for the SMC Calling Convention 2.0
+
+   -  Introduce External Abort handling on AArch64
+      External Abort routed to EL3 was reported as an unhandled exception
+      and caused a panic. This change enables Trusted Firmware-A to handle
+      External Aborts routed to EL3.
+
+   -  Save value of ACTLR_EL1 implementation-defined register in the CPU
+      context structure rather than forcing it to 0.
+
+   -  Introduce ARM_LINUX_KERNEL_AS_BL33 build option, which allows BL31 to
+      directly jump to a Linux kernel. This makes for a quicker and simpler
+      boot flow, which might be useful in some test environments.
+
+   -  Add dynamic configurations for BL31, BL32 and BL33 enabling support for
+      Chain of Trust (COT).
+
+   -  Make TF UUID RFC 4122 compliant
+
+-  New Platform Support
+
+   -  Arm SGI-575
+
+   -  Arm SGM-775
+
+   -  Allwinner sun50i_64
+
+   -  Allwinner sun50i_h6
+
+   -  NXP QorIQ LS1043A
+
+   -  NXP i.MX8QX
+
+   -  NXP i.MX8QM
+
+   -  NXP i.MX7Solo WaRP7
+
+   -  TI K3
+
+   -  Socionext Synquacer SC2A11
+
+   -  Marvell Armada 8K
+
+   -  STMicroelectronics STM32MP1
+
+-  Misc Generic Platform Common Code Enhancements
+
+   -  Add MMC framework that supports both eMMC and SD card devices
+
+-  Misc Arm Platform Common Code Enhancements
+
+   -  Demonstrate PSCI MEM_PROTECT from el3_runtime
+
+   -  Provide RAS support
+
+   -  Migrate AArch64 port to the multi console driver. The old API is
+      deprecated and will eventually be removed.
+
+   -  Move BL31 below BL2 to enable BL2 overlay resulting in changes in the
+      layout of BL images in memory to enable more efficient use of available
+      space.
+
+   -  Add cpp build processing for dtb that allows processing device tree
+      with external includes.
+
+   -  Extend FIP io driver to support multiple FIP devices
+
+   -  Add support for SCMI AP core configuration protocol v1.0
+
+   -  Use SCMI AP core protocol to set the warm boot entrypoint
+
+   -  Add support to Mbed TLS drivers for shared heap among different
+      BL images to help optimise memory usage
+
+   -  Enable non-secure access to UART1 through a build option to support
+      a serial debug port for debugger connection
+
+-  Enhancements for Arm Juno Platform
+
+   -  Add support for TrustZone Media Protection 1 (TZMP1)
+
+-  Enhancements for Arm FVP Platform
+
+   -  Dynamic_config: remove the FVP dtb files
+
+   -  Set DYNAMIC_WORKAROUND_CVE_2018_3639=1 on FVP by default
+
+   -  Set the ability to dynamically disable Trusted Boot Board
+      authentication to be off by default with DYN_DISABLE_AUTH
+
+   -  Add librom enhancement support in FVP
+
+   -  Support shared Mbed TLS heap between BL1 and BL2 that allow a
+      reduction in BL2 size for FVP
+
+-  Enhancements for Arm SGI/SGM Platform
+
+   -  Enable ARM_PLAT_MT flag for SGI-575
+
+   -  Add dts files to enable support for dynamic config
+
+   -  Add RAS support
+
+   -  Support shared Mbed TLS heap for SGI and SGM between BL1 and BL2
+
+-  Enhancements for Non Arm Platforms
+
+   -  Raspberry Pi Platform
+
+   -  Hikey Platforms
+
+   -  Xilinx Platforms
+
+   -  QEMU Platform
+
+   -  Rockchip rk3399 Platform
+
+   -  TI Platforms
+
+   -  Socionext Platforms
+
+   -  Allwinner Platforms
+
+   -  NXP Platforms
+
+   -  NVIDIA Tegra Platform
+
+   -  Marvell Platforms
+
+   -  STMicroelectronics STM32MP1 Platform
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  No issues known at 1.5 release resolved in 1.6 release
+
+Known Issues
+^^^^^^^^^^^^
+
+-  DTB creation not supported when building on a Windows host. This step in the
+   build process is skipped when running on a Windows host. Known issue from
+   1.5 version.
+
+Version 1.5
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  Added new firmware support to enable RAS (Reliability, Availability, and
+   Serviceability) functionality.
+
+   -  Secure Partition Manager (SPM): A Secure Partition is a software execution
+      environment instantiated in S-EL0 that can be used to implement simple
+      management and security services. The SPM is the firmware component that
+      is responsible for managing a Secure Partition.
+
+   -  SDEI dispatcher: Support for interrupt-based |SDEI| events and all
+      interfaces as defined by the |SDEI| specification v1.0, see
+      `SDEI Specification`_
+
+   -  Exception Handling Framework (EHF): Framework that allows dispatching of
+      EL3 interrupts to their registered handlers which are registered based on
+      their priorities. Facilitates firmware-first error handling policy where
+      asynchronous exceptions may be routed to EL3.
+
+      Integrated the TSPD with EHF.
+
+-  Updated PSCI support:
+
+   -  Implemented PSCI v1.1 optional features `MEM_PROTECT` and `SYSTEM_RESET2`.
+      The supported PSCI version was updated to v1.1.
+
+   -  Improved PSCI STAT timestamp collection, including moving accounting for
+      retention states to be inside the locks and fixing handling of wrap-around
+      when calculating residency in AArch32 execution state.
+
+   -  Added optional handler for early suspend that executes when suspending to
+      a power-down state and with data caches enabled.
+
+      This may provide a performance improvement on platforms where it is safe
+      to perform some or all of the platform actions from `pwr_domain_suspend`
+      with the data caches enabled.
+
+-  Enabled build option, BL2_AT_EL3, for BL2 to allow execution at EL3 without
+   any dependency on TF BL1.
+
+   This allows platforms which already have a non-TF Boot ROM to directly load
+   and execute BL2 and subsequent BL stages without need for BL1. This was not
+   previously possible because BL2 executes at S-EL1 and cannot jump straight to
+   EL3.
+
+-  Implemented support for SMCCC v1.1, including `SMCCC_VERSION` and
+   `SMCCC_ARCH_FEATURES`.
+
+   Additionally, added support for `SMCCC_VERSION` in PSCI features to enable
+   discovery of the SMCCC version via PSCI feature call.
+
+-  Added Dynamic Configuration framework which enables each of the boot loader
+   stages to be dynamically configured at runtime if required by the platform.
+   The boot loader stage may optionally specify a firmware configuration file
+   and/or hardware configuration file that can then be shared with the next boot
+   loader stage.
+
+   Introduced a new BL handover interface that essentially allows passing of 4
+   arguments between the different BL stages.
+
+   Updated cert_create and fip_tool to support the dynamic configuration files.
+   The COT also updated to support these new files.
+
+-  Code hygiene changes and alignment with MISRA guideline:
+
+   -  Fix use of undefined macros.
+
+   -  Achieved compliance with Mandatory MISRA coding rules.
+
+   -  Achieved compliance for following Required MISRA rules for the default
+      build configurations on FVP and Juno platforms : 7.3, 8.3, 8.4, 8.5 and
+      8.8.
+
+-  Added support for Armv8.2-A architectural features:
+
+   -  Updated translation table set-up to set the CnP (Common not Private) bit
+      for secure page tables so that multiple PEs in the same Inner Shareable
+      domain can use the same translation table entries for a given stage of
+      translation in a particular translation regime.
+
+   -  Extended the supported values of ID_AA64MMFR0_EL1.PARange to include the
+      52-bit Physical Address range.
+
+   -  Added support for the Scalable Vector Extension to allow Normal world
+      software to access SVE functionality but disable access to SVE, SIMD and
+      floating point functionality from the Secure world in order to prevent
+      corruption of the Z-registers.
+
+-  Added support for Armv8.4-A architectural feature Activity Monitor Unit (AMU)
+    extensions.
+
+   In addition to the v8.4 architectural extension, AMU support on Cortex-A75
+   was implemented.
+
+-  Enhanced OP-TEE support to enable use of pageable OP-TEE image. The Arm
+   standard platforms are updated to load up to 3 images for OP-TEE; header,
+   pager image and paged image.
+
+   The chain of trust is extended to support the additional images.
+
+-  Enhancements to the translation table library:
+
+   -  Introduced APIs to get and set the memory attributes of a region.
+
+   -  Added support to manage both privilege levels in translation regimes that
+      describe translations for 2 Exception levels, specifically the EL1&0
+      translation regime, and extended the memory map region attributes to
+      include specifying Non-privileged access.
+
+   -  Added support to specify the granularity of the mappings of each region,
+      for instance a 2MB region can be specified to be mapped with 4KB page
+      tables instead of a 2MB block.
+
+   -  Disabled the higher VA range to avoid unpredictable behaviour if there is
+      an attempt to access addresses in the higher VA range.
+
+   -  Added helpers for Device and Normal memory MAIR encodings that align with
+      the Arm Architecture Reference Manual for Armv8-A (Arm DDI0487B.b).
+
+   -  Code hygiene including fixing type length and signedness of constants,
+      refactoring of function to enable the MMU, removing all instances where
+      the virtual address space is hardcoded and added comments that document
+      alignment needed between memory attributes and attributes specified in
+      TCR_ELx.
+
+-  Updated GIC support:
+
+   -  Introduce new APIs for GICv2 and GICv3 that provide the capability to
+      specify interrupt properties rather than list of interrupt numbers alone.
+      The Arm platforms and other upstream platforms are migrated to use
+      interrupt properties.
+
+   -  Added helpers to save / restore the GICv3 context, specifically the
+      Distributor and Redistributor contexts and architectural parts of the ITS
+      power management. The Distributor and Redistributor helpers also support
+      the implementation-defined part of GIC-500 and GIC-600.
+
+      Updated the Arm FVP platform to save / restore the GICv3 context on system
+      suspend / resume as an example of how to use the helpers.
+
+      Introduced a new TZC secured DDR carve-out for use by Arm platforms for
+      storing EL3 runtime data such as the GICv3 register context.
+
+-  Added support for Armv7-A architecture via build option ARM_ARCH_MAJOR=7.
+   This includes following features:
+
+   -  Updates GICv2 driver to manage GICv1 with security extensions.
+
+   -  Software implementation for 32bit division.
+
+   -  Enabled use of generic timer for platforms that do not set
+      ARM_CORTEX_Ax=yes.
+
+   -  Support for Armv7-A Virtualization extensions [DDI0406C_C].
+
+   -  Support for both Armv7-A platforms that only have 32-bit addressing and
+      Armv7-A platforms that support large page addressing.
+
+   -  Included support for following Armv7 CPUs: Cortex-A12, Cortex-A17,
+      Cortex-A7, Cortex-A5, Cortex-A9, Cortex-A15.
+
+   -  Added support in QEMU for Armv7-A/Cortex-A15.
+
+-  Enhancements to Firmware Update feature:
+
+   -  Updated the FWU documentation to describe the additional images needed for
+      Firmware update, and how they are used for both the Juno platform and the
+      Arm FVP platforms.
+
+-  Enhancements to Trusted Board Boot feature:
+
+   -  Added support to cert_create tool for RSA PKCS1# v1.5 and SHA384, SHA512
+      and SHA256.
+
+   -  For Arm platforms added support to use ECDSA keys.
+
+   -  Enhanced the mbed TLS wrapper layer to include support for both RSA and
+      ECDSA to enable runtime selection between RSA and ECDSA keys.
+
+-  Added support for secure interrupt handling in AArch32 sp_min, hardcoded to
+   only handle FIQs.
+
+-  Added support to allow a platform to load images from multiple boot sources,
+   for example from a second flash drive.
+
+-  Added a logging framework that allows platforms to reduce the logging level
+   at runtime and additionally the prefix string can be defined by the platform.
+
+-  Further improvements to register initialisation:
+
+   -   Control register PMCR_EL0 / PMCR is set to prohibit cycle counting in the
+       secure world. This register is added to the list of registers that are
+       saved and restored during world switch.
+
+   -   When EL3 is running in AArch32 execution state, the Non-secure version of
+       SCTLR is explicitly initialised during the warmboot flow rather than
+       relying on the hardware to set the correct reset values.
+
+-  Enhanced support for Arm platforms:
+
+   -  Introduced driver for Shared-Data-Structure (SDS) framework which is used
+      for communication between SCP and the AP CPU, replacing Boot-Over_MHU
+      (BOM) protocol.
+
+      The Juno platform is migrated to use SDS with the SCMI support added in
+      v1.3 and is set as default.
+
+      The driver can be found in the plat/arm/css/drivers folder.
+
+   -  Improved memory usage by only mapping TSP memory region when the TSPD has
+      been included in the build. This reduces the memory footprint and avoids
+      unnecessary memory being mapped.
+
+   -  Updated support for multi-threading CPUs for FVP platforms - always check
+      the MT field in MPDIR and access the bit fields accordingly.
+
+   -  Support building for platforms that model DynamIQ configuration by
+      implementing all CPUs in a single cluster.
+
+   -  Improved nor flash driver, for instance clearing status registers before
+      sending commands. Driver can be found plat/arm/board/common folder.
+
+-  Enhancements to QEMU platform:
+
+   -  Added support for TBB.
+
+   -  Added support for using OP-TEE pageable image.
+
+   -  Added support for LOAD_IMAGE_V2.
+
+   -  Migrated to use translation table library v2 by default.
+
+   -  Added support for SEPARATE_CODE_AND_RODATA.
+
+-  Applied workarounds CVE-2017-5715 on Arm Cortex-A57, -A72, -A73 and -A75, and
+   for Armv7-A CPUs Cortex-A9, -A15 and -A17.
+
+-  Applied errata workaround for Arm Cortex-A57: 859972.
+
+-  Applied errata workaround for Arm Cortex-A72: 859971.
+
+-  Added support for Poplar 96Board platform.
+
+-  Added support for Raspberry Pi 3 platform.
+
+-  Added Call Frame Information (CFI) assembler directives to the vector entries
+   which enables debuggers to display the backtrace of functions that triggered
+   a synchronous abort.
+
+-  Added ability to build dtb.
+
+-  Added support for pre-tool (cert_create and fiptool) image processing
+   enabling compression of the image files before processing by cert_create and
+   fiptool.
+
+   This can reduce fip size and may also speed up loading of images.  The image
+   verification will also get faster because certificates are generated based on
+   compressed images.
+
+   Imported zlib 1.2.11 to implement gunzip() for data compression.
+
+-  Enhancements to fiptool:
+
+   -  Enabled the fiptool to be built using Visual Studio.
+
+   -  Added padding bytes at the end of the last image in the fip to be
+      facilitate transfer by DMA.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  TF-A can be built with optimisations disabled (-O0).
+
+-  Memory layout updated to enable Trusted Board Boot on Juno platform when
+   running TF-A in AArch32 execution mode (resolving `tf-issue#501`_).
+
+Known Issues
+^^^^^^^^^^^^
+
+-  DTB creation not supported when building on a Windows host. This step in the
+   build process is skipped when running on a Windows host.
+
+Version 1.4
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  Enabled support for platforms with hardware assisted coherency.
+
+   A new build option HW_ASSISTED_COHERENCY allows platforms to take advantage
+   of the following optimisations:
+
+   -  Skip performing cache maintenance during power-up and power-down.
+
+   -  Use spin-locks instead of bakery locks.
+
+   -  Enable data caches early on warm-booted CPUs.
+
+-  Added support for Cortex-A75 and Cortex-A55 processors.
+
+   Both Cortex-A75 and Cortex-A55 processors use the Arm DynamIQ Shared Unit
+   (DSU). The power-down and power-up sequences are therefore mostly managed in
+   hardware, reducing complexity of the software operations.
+
+-  Introduced Arm GIC-600 driver.
+
+   Arm GIC-600 IP complies with Arm GICv3 architecture. For FVP platforms, the
+   GIC-600 driver is chosen when FVP_USE_GIC_DRIVER is set to FVP_GIC600.
+
+-  Updated GICv3 support:
+
+   -  Introduced power management APIs for GICv3 Redistributor. These APIs
+      allow platforms to power down the Redistributor during CPU power on/off.
+      Requires the GICv3 implementations to have power management operations.
+
+      Implemented the power management APIs for FVP.
+
+   -  GIC driver data is flushed by the primary CPU so that secondary CPU do
+      not read stale GIC data.
+
+-  Added support for Arm System Control and Management Interface v1.0 (SCMI).
+
+   The SCMI driver implements the power domain management and system power
+   management protocol of the SCMI specification (Arm DEN 0056ASCMI) for
+   communicating with any compliant power controller.
+
+   Support is added for the Juno platform. The driver can be found in the
+   plat/arm/css/drivers folder.
+
+-  Added support to enable pre-integration of TBB with the Arm TrustZone
+   CryptoCell product, to take advantage of its hardware Root of Trust and
+   crypto acceleration services.
+
+-  Enabled Statistical Profiling Extensions for lower ELs.
+
+   The firmware support is limited to the use of SPE in the Non-secure state
+   and accesses to the SPE specific registers from S-EL1 will trap to EL3.
+
+   The SPE are architecturally specified for AArch64 only.
+
+-  Code hygiene changes aligned with MISRA guidelines:
+
+   -  Fixed signed / unsigned comparison warnings in the translation table
+      library.
+
+   -  Added U(_x) macro and together with the existing ULL(_x) macro fixed
+      some of the signed-ness defects flagged by the MISRA scanner.
+
+-  Enhancements to Firmware Update feature:
+
+   -  The FWU logic now checks for overlapping images to prevent execution of
+      unauthenticated arbitrary code.
+
+   -  Introduced new FWU_SMC_IMAGE_RESET SMC that changes the image loading
+      state machine to go from COPYING, COPIED or AUTHENTICATED states to
+      RESET state. Previously, this was only possible when the authentication
+      of an image failed or when the execution of the image finished.
+
+   -  Fixed integer overflow which addressed TFV-1: Malformed Firmware Update
+      SMC can result in copy of unexpectedly large data into secure memory.
+
+-  Introduced support for Arm Compiler 6 and LLVM (clang).
+
+   TF-A can now also be built with the Arm Compiler 6 or the clang compilers.
+   The assembler and linker must be provided by the GNU toolchain.
+
+   Tested with Arm CC 6.7 and clang 3.9.x and 4.0.x.
+
+-  Memory footprint improvements:
+
+   -  Introduced `tf_snprintf`, a reduced version of `snprintf` which has
+      support for a limited set of formats.
+
+      The mbedtls driver is updated to optionally use `tf_snprintf` instead of
+      `snprintf`.
+
+   -  The `assert()` is updated to no longer print the function name, and
+      additional logging options are supported via an optional platform define
+      `PLAT_LOG_LEVEL_ASSERT`, which controls how verbose the assert output is.
+
+-  Enhancements to TF-A support when running in AArch32 execution state:
+
+   -  Support booting SP_MIN and BL33 in AArch32 execution mode on Juno. Due to
+      hardware limitations, BL1 and BL2 boot in AArch64 state and there is
+      additional trampoline code to warm reset into SP_MIN in AArch32 execution
+      state.
+
+   -  Added support for Arm Cortex-A53/57/72 MPCore processors including the
+      errata workarounds that are already implemented for AArch64 execution
+      state.
+
+   -  For FVP platforms, added AArch32 Trusted Board Boot support, including the
+      Firmware Update feature.
+
+-  Introduced Arm SiP service for use by Arm standard platforms.
+
+   -  Added new Arm SiP Service SMCs to enable the Non-secure  world to read PMF
+      timestamps.
+
+      Added PMF instrumentation points in TF-A in order to quantify the
+      overall time spent in the PSCI software implementation.
+
+   -  Added new Arm SiP service SMC to switch execution state.
+
+      This allows the lower exception level to change its execution state from
+      AArch64 to AArch32, or vice verse, via a request to EL3.
+
+-  Migrated to use SPDX[0] license identifiers to make software license
+   auditing simpler.
+
+   .. note::
+      Files that have been imported by FreeBSD have not been modified.
+
+   [0]: https://spdx.org/
+
+-  Enhancements to the translation table library:
+
+   -  Added version 2 of translation table library that allows different
+      translation tables to be modified by using different 'contexts'. Version 1
+      of the translation table library only allows the current EL's translation
+      tables to be modified.
+
+      Version 2 of the translation table also added support for dynamic
+      regions; regions that can be added and removed dynamically whilst the
+      MMU is enabled. Static regions can only be added or removed before the
+      MMU is enabled.
+
+      The dynamic mapping functionality is enabled or disabled when compiling
+      by setting the build option PLAT_XLAT_TABLES_DYNAMIC to 1 or 0. This can
+      be done per-image.
+
+   -  Added support for translation regimes with two virtual address spaces
+      such as the one shared by EL1 and EL0.
+
+      The library does not support initializing translation tables for EL0
+      software.
+
+   -  Added support to mark the translation tables as non-cacheable using an
+      additional build option `XLAT_TABLE_NC`.
+
+-  Added support for GCC stack protection. A new build option
+   ENABLE_STACK_PROTECTOR was introduced that enables compilation of all BL
+   images with one of the GCC -fstack-protector-* options.
+
+   A new platform function plat_get_stack_protector_canary() was introduced
+   that returns a value used to initialize the canary for stack corruption
+   detection. For increased effectiveness of protection platforms must provide
+   an implementation that returns a random value.
+
+-  Enhanced support for Arm platforms:
+
+   -  Added support for multi-threading CPUs, indicated by `MT` field in MPDIR.
+      A new build flag `ARM_PLAT_MT` is added, and when enabled, the functions
+      accessing MPIDR assume that the `MT` bit is set for the platform and
+      access the bit fields accordingly.
+
+      Also, a new API `plat_arm_get_cpu_pe_count` is added when `ARM_PLAT_MT` is
+      enabled, returning the Processing Element count within the physical CPU
+      corresponding to `mpidr`.
+
+   -  The Arm platforms migrated to use version 2 of the translation tables.
+
+   -  Introduced a new Arm platform layer API `plat_arm_psci_override_pm_ops`
+      which allows Arm platforms to modify `plat_arm_psci_pm_ops` and therefore
+      dynamically define PSCI capability.
+
+   -  The Arm platforms migrated to use IMAGE_LOAD_V2 by default.
+
+-  Enhanced reporting of errata workaround status with the following policy:
+
+   -  If an errata workaround is enabled:
+
+      -  If it applies (i.e. the CPU is affected by the errata), an INFO message
+         is printed, confirming that the errata workaround has been applied.
+
+      -  If it does not apply, a VERBOSE message is printed, confirming that the
+         errata workaround has been skipped.
+
+   -  If an errata workaround is not enabled, but would have applied had it
+      been, a WARN message is printed, alerting that errata workaround is
+      missing.
+
+-  Added build options ARM_ARCH_MAJOR and ARM_ARM_MINOR to choose the
+   architecture version to target TF-A.
+
+-  Updated the spin lock implementation to use the more efficient CAS (Compare
+   And Swap) instruction when available. This instruction was introduced in
+   Armv8.1-A.
+
+-  Applied errata workaround for Arm Cortex-A53: 855873.
+
+-  Applied errata workaround for Arm-Cortex-A57: 813419.
+
+-  Enabled all A53 and A57 errata workarounds for Juno, both in AArch64 and
+   AArch32 execution states.
+
+-  Added support for Socionext UniPhier SoC platform.
+
+-  Added support for Hikey960 and Hikey platforms.
+
+-  Added support for Rockchip RK3328 platform.
+
+-  Added support for NVidia Tegra T186 platform.
+
+-  Added support for Designware emmc driver.
+
+-  Imported libfdt v1.4.2 that addresses buffer overflow in fdt_offset_ptr().
+
+-  Enhanced the CPU operations framework to allow power handlers to be
+   registered on per-level basis. This enables support for future CPUs that
+   have multiple threads which might need powering down individually.
+
+-  Updated register initialisation to prevent unexpected behaviour:
+
+   -  Debug registers MDCR-EL3/SDCR and MDCR_EL2/HDCR are initialised to avoid
+      unexpected traps into the higher exception levels and disable secure
+      self-hosted debug. Additionally, secure privileged external debug on
+      Juno is disabled by programming the appropriate Juno SoC registers.
+
+   -  EL2 and EL3 configurable controls are initialised to avoid unexpected
+      traps in the higher exception levels.
+
+   -  Essential control registers are fully initialised on EL3 start-up, when
+      initialising the non-secure and secure context structures and when
+      preparing to leave EL3 for a lower EL. This gives better alignment with
+      the Arm ARM which states that software must initialise RES0 and RES1
+      fields with 0 / 1.
+
+-  Enhanced PSCI support:
+
+   -  Introduced new platform interfaces that decouple PSCI stat residency
+      calculation from PMF, enabling platforms to use alternative methods of
+      capturing timestamps.
+
+   -  PSCI stat accounting performed for retention/standby states when
+      requested at multiple power levels.
+
+-  Simplified fiptool to have a single linked list of image descriptors.
+
+-  For the TSP, resolved corruption of pre-empted secure context by aborting any
+   pre-empted SMC during PSCI power management requests.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  TF-A can be built with the latest mbed TLS version (v2.4.2). The earlier
+   version 2.3.0 cannot be used due to build warnings that the TF-A build
+   system interprets as errors.
+
+-  TBBR, including the Firmware Update feature  is now supported on FVP
+   platforms when running TF-A in AArch32 state.
+
+-  The version of the AEMv8 Base FVP used in this release has resolved the issue
+   of the model executing a reset instead of terminating in response to a
+   shutdown request using the PSCI SYSTEM_OFF API.
+
+Known Issues
+^^^^^^^^^^^^
+
+-  Building TF-A with compiler optimisations disabled (-O0) fails.
+
+-  Trusted Board Boot currently does not work on Juno when running Trusted
+   Firmware in AArch32 execution state due to error when loading the sp_min to
+   memory because of lack of free space available. See `tf-issue#501`_ for more
+   details.
+
+-  The errata workaround for A53 errata 843419 is only available from binutils
+   2.26 and is not present in GCC4.9. If this errata is applicable to the
+   platform, please use GCC compiler version of at least 5.0. See `PR#1002`_ for
+   more details.
+
+Version 1.3
+-----------
+
+
+New features
+^^^^^^^^^^^^
+
+-  Added support for running TF-A in AArch32 execution state.
+
+   The PSCI library has been refactored to allow integration with **EL3 Runtime
+   Software**. This is software that is executing at the highest secure
+   privilege which is EL3 in AArch64 or Secure SVC/Monitor mode in AArch32. See
+   `PSCI Integration Guide`_.
+
+   Included is a minimal AArch32 Secure Payload, **SP-MIN**, that illustrates
+   the usage and integration of the PSCI library with EL3 Runtime Software
+   running in AArch32 state.
+
+   Booting to the BL1/BL2 images as well as booting straight to the Secure
+   Payload is supported.
+
+-  Improvements to the initialization framework for the PSCI service and Arm
+   Standard Services in general.
+
+   The PSCI service is now initialized as part of Arm Standard Service
+   initialization. This consolidates the initializations of any Arm Standard
+   Service that may be added in the future.
+
+   A new function ``get_arm_std_svc_args()`` is introduced to get arguments
+   corresponding to each standard service and must be implemented by the EL3
+   Runtime Software.
+
+   For PSCI, a new versioned structure ``psci_lib_args_t`` is introduced to
+   initialize the PSCI Library. **Note** this is a compatibility break due to
+   the change in the prototype of ``psci_setup()``.
+
+-  To support AArch32 builds of BL1 and BL2, implemented a new, alternative
+   firmware image loading mechanism that adds flexibility.
+
+   The current mechanism has a hard-coded set of images and execution order
+   (BL31, BL32, etc). The new mechanism is data-driven by a list of image
+   descriptors provided by the platform code.
+
+   Arm platforms have been updated to support the new loading mechanism.
+
+   The new mechanism is enabled by a build flag (``LOAD_IMAGE_V2``) which is
+   currently off by default for the AArch64 build.
+
+   **Note** ``TRUSTED_BOARD_BOOT`` is currently not supported when
+   ``LOAD_IMAGE_V2`` is enabled.
+
+-  Updated requirements for making contributions to TF-A.
+
+   Commits now must have a 'Signed-off-by:' field to certify that the
+   contribution has been made under the terms of the
+   `Developer Certificate of Origin`_.
+
+   A signed CLA is no longer required.
+
+   The `Contribution Guide`_ has been updated to reflect this change.
+
+-  Introduced Performance Measurement Framework (PMF) which provides support
+   for capturing, storing, dumping and retrieving time-stamps to measure the
+   execution time of critical paths in the firmware. This relies on defining
+   fixed sample points at key places in the code.
+
+-  To support the QEMU platform port, imported libfdt v1.4.1 from
+   https://git.kernel.org/pub/scm/utils/dtc/dtc.git
+
+-  Updated PSCI support:
+
+   -  Added support for PSCI NODE_HW_STATE API for Arm platforms.
+
+   -  New optional platform hook, ``pwr_domain_pwr_down_wfi()``, in
+      ``plat_psci_ops`` to enable platforms to perform platform-specific actions
+      needed to enter powerdown, including the 'wfi' invocation.
+
+   -  PSCI STAT residency and count functions have been added on Arm platforms
+      by using PMF.
+
+-  Enhancements to the translation table library:
+
+   -  Limited memory mapping support for region overlaps to only allow regions
+      to overlap that are identity mapped or have the same virtual to physical
+      address offset, and overlap completely but must not cover the same area.
+
+      This limitation will enable future enhancements without having to
+      support complex edge cases that may not be necessary.
+
+   -  The initial translation lookup level is now inferred from the virtual
+      address space size. Previously, it was hard-coded.
+
+   -  Added support for mapping Normal, Inner Non-cacheable, Outer
+      Non-cacheable memory in the translation table library.
+
+      This can be useful to map a non-cacheable memory region, such as a DMA
+      buffer.
+
+   -  Introduced the MT_EXECUTE/MT_EXECUTE_NEVER memory mapping attributes to
+      specify the access permissions for instruction execution of a memory
+      region.
+
+-  Enabled support to isolate code and read-only data on separate memory pages,
+   allowing independent access control to be applied to each.
+
+-  Enabled SCR_EL3.SIF (Secure Instruction Fetch) bit in BL1 and BL31 common
+   architectural setup code, preventing fetching instructions from non-secure
+   memory when in secure state.
+
+-  Enhancements to FIP support:
+
+   -  Replaced ``fip_create`` with ``fiptool`` which provides a more consistent
+      and intuitive interface as well as additional support to remove an image
+      from a FIP file.
+
+   -  Enabled printing the SHA256 digest with info command, allowing quick
+      verification of an image within a FIP without having to extract the
+      image and running sha256sum on it.
+
+   -  Added support for unpacking the contents of an existing FIP file into
+      the working directory.
+
+   -  Aligned command line options for specifying images to use same naming
+      convention as specified by TBBR and already used in cert_create tool.
+
+-  Refactored the TZC-400 driver to also support memory controllers that
+   integrate TZC functionality, for example Arm CoreLink DMC-500. Also added
+   DMC-500 specific support.
+
+-  Implemented generic delay timer based on the system generic counter and
+   migrated all platforms to use it.
+
+-  Enhanced support for Arm platforms:
+
+   -  Updated image loading support to make SCP images (SCP_BL2 and SCP_BL2U)
+      optional.
+
+   -  Enhanced topology description support to allow multi-cluster topology
+      definitions.
+
+   -  Added interconnect abstraction layer to help platform ports select the
+      right interconnect driver, CCI or CCN, for the platform.
+
+   -  Added support to allow loading BL31 in the TZC-secured DRAM instead of
+      the default secure SRAM.
+
+   -  Added support to use a System Security Control (SSC) Registers Unit
+      enabling TF-A to be compiled to support multiple Arm platforms and
+      then select one at runtime.
+
+   -  Restricted mapping of Trusted ROM in BL1 to what is actually needed by
+      BL1 rather than entire Trusted ROM region.
+
+   -  Flash is now mapped as execute-never by default. This increases security
+      by restricting the executable region to what is strictly needed.
+
+-  Applied following erratum workarounds for Cortex-A57: 833471, 826977,
+   829520, 828024 and 826974.
+
+-  Added support for Mediatek MT6795 platform.
+
+-  Added support for QEMU virtualization Armv8-A target.
+
+-  Added support for Rockchip RK3368 and RK3399 platforms.
+
+-  Added support for Xilinx Zynq UltraScale+ MPSoC platform.
+
+-  Added support for Arm Cortex-A73 MPCore Processor.
+
+-  Added support for Arm Cortex-A72 processor.
+
+-  Added support for Arm Cortex-A35 processor.
+
+-  Added support for Arm Cortex-A32 MPCore Processor.
+
+-  Enabled preloaded BL33 alternative boot flow, in which BL2 does not load
+   BL33 from non-volatile storage and BL31 hands execution over to a preloaded
+   BL33. The User Guide has been updated with an example of how to use this
+   option with a bootwrapped kernel.
+
+-  Added support to build TF-A on a Windows-based host machine.
+
+-  Updated Trusted Board Boot prototype implementation:
+
+   -  Enabled the ability for a production ROM with TBBR enabled to boot test
+      software before a real ROTPK is deployed (e.g. manufacturing mode).
+      Added support to use ROTPK in certificate without verifying against the
+      platform value when ``ROTPK_NOT_DEPLOYED`` bit is set.
+
+   -  Added support for non-volatile counter authentication to the
+      Authentication Module to protect against roll-back.
+
+-  Updated GICv3 support:
+
+   -  Enabled processor power-down and automatic power-on using GICv3.
+
+   -  Enabled G1S or G0 interrupts to be configured independently.
+
+   -  Changed FVP default interrupt driver to be the GICv3-only driver.
+      **Note** the default build of TF-A will not be able to boot
+      Linux kernel with GICv2 FDT blob.
+
+   -  Enabled wake-up from CPU_SUSPEND to stand-by by temporarily re-routing
+      interrupts and then restoring after resume.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Known issues
+^^^^^^^^^^^^
+
+-  The version of the AEMv8 Base FVP used in this release resets the model
+   instead of terminating its execution in response to a shutdown request using
+   the PSCI ``SYSTEM_OFF`` API. This issue will be fixed in a future version of
+   the model.
+
+-  Building TF-A with compiler optimisations disabled (``-O0``) fails.
+
+-  TF-A cannot be built with mbed TLS version v2.3.0 due to build warnings
+   that the TF-A build system interprets as errors.
+
+-  TBBR is not currently supported when running TF-A in AArch32 state.
+
+Version 1.2
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  The Trusted Board Boot implementation on Arm platforms now conforms to the
+   mandatory requirements of the TBBR specification.
+
+   In particular, the boot process is now guarded by a Trusted Watchdog, which
+   will reset the system in case of an authentication or loading error. On Arm
+   platforms, a secure instance of Arm SP805 is used as the Trusted Watchdog.
+
+   Also, a firmware update process has been implemented. It enables
+   authenticated firmware to update firmware images from external interfaces to
+   SoC Non-Volatile memories. This feature functions even when the current
+   firmware in the system is corrupt or missing; it therefore may be used as
+   a recovery mode.
+
+-  Improvements have been made to the Certificate Generation Tool
+   (``cert_create``) as follows.
+
+   -  Added support for the Firmware Update process by extending the Chain
+      of Trust definition in the tool to include the Firmware Update
+      certificate and the required extensions.
+
+   -  Introduced a new API that allows one to specify command line options in
+      the Chain of Trust description. This makes the declaration of the tool's
+      arguments more flexible and easier to extend.
+
+   -  The tool has been reworked to follow a data driven approach, which
+      makes it easier to maintain and extend.
+
+-  Extended the FIP tool (``fip_create``) to support the new set of images
+   involved in the Firmware Update process.
+
+-  Various memory footprint improvements. In particular:
+
+   -  The bakery lock structure for coherent memory has been optimised.
+
+   -  The mbed TLS SHA1 functions are not needed, as SHA256 is used to
+      generate the certificate signature. Therefore, they have been compiled
+      out, reducing the memory footprint of BL1 and BL2 by approximately
+      6 KB.
+
+   -  On Arm development platforms, each BL stage now individually defines
+      the number of regions that it needs to map in the MMU.
+
+-  Added the following new design documents:
+
+   -  `Authentication framework`_
+   -  `Firmware Update`_
+   -  `TF-A Reset Design`_
+   -  `Power Domain Topology Design`_
+
+-  Applied the new image terminology to the code base and documentation, as
+   described in the `image terminology document`_.
+
+-  The build system has been reworked to improve readability and facilitate
+   adding future extensions.
+
+-  On Arm standard platforms, BL31 uses the boot console during cold boot
+   but switches to the runtime console for any later logs at runtime. The TSP
+   uses the runtime console for all output.
+
+-  Implemented a basic NOR flash driver for Arm platforms. It programs the
+   device using CFI (Common Flash Interface) standard commands.
+
+-  Implemented support for booting EL3 payloads on Arm platforms, which
+   reduces the complexity of developing EL3 baremetal code by doing essential
+   baremetal initialization.
+
+-  Provided separate drivers for GICv3 and GICv2. These expect the entire
+   software stack to use either GICv2 or GICv3; hybrid GIC software systems
+   are no longer supported and the legacy Arm GIC driver has been deprecated.
+
+-  Added support for Juno r1 and r2. A single set of Juno TF-A binaries can run
+   on Juno r0, r1 and r2 boards. Note that this TF-A version depends on a Linaro
+   release that does *not* contain Juno r2 support.
+
+-  Added support for MediaTek mt8173 platform.
+
+-  Implemented a generic driver for Arm CCN IP.
+
+-  Major rework of the PSCI implementation.
+
+   -  Added framework to handle composite power states.
+
+   -  Decoupled the notions of affinity instances (which describes the
+      hierarchical arrangement of cores) and of power domain topology, instead
+      of assuming a one-to-one mapping.
+
+   -  Better alignment with version 1.0 of the PSCI specification.
+
+-  Added support for the SYSTEM_SUSPEND PSCI API on Arm platforms. When invoked
+   on the last running core on a supported platform, this puts the system
+   into a low power mode with memory retention.
+
+-  Unified the reset handling code as much as possible across BL stages.
+   Also introduced some build options to enable optimization of the reset path
+   on platforms that support it.
+
+-  Added a simple delay timer API, as well as an SP804 timer driver, which is
+   enabled on FVP.
+
+-  Added support for NVidia Tegra T210 and T132 SoCs.
+
+-  Reorganised Arm platforms ports to greatly improve code shareability and
+   facilitate the reuse of some of this code by other platforms.
+
+-  Added support for Arm Cortex-A72 processor in the CPU specific framework.
+
+-  Provided better error handling. Platform ports can now define their own
+   error handling, for example to perform platform specific bookkeeping or
+   post-error actions.
+
+-  Implemented a unified driver for Arm Cache Coherent Interconnects used for
+   both CCI-400 & CCI-500 IPs. Arm platforms ports have been migrated to this
+   common driver. The standalone CCI-400 driver has been deprecated.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  The Trusted Board Boot implementation has been redesigned to provide greater
+   modularity and scalability. See the `Authentication Framework`_ document.
+   All missing mandatory features are now implemented.
+
+-  The FVP and Juno ports may now use the hash of the ROTPK stored in the
+   Trusted Key Storage registers to verify the ROTPK. Alternatively, a
+   development public key hash embedded in the BL1 and BL2 binaries might be
+   used instead. The location of the ROTPK is chosen at build-time using the
+   ``ARM_ROTPK_LOCATION`` build option.
+
+-  GICv3 is now fully supported and stable.
+
+Known issues
+^^^^^^^^^^^^
+
+-  The version of the AEMv8 Base FVP used in this release resets the model
+   instead of terminating its execution in response to a shutdown request using
+   the PSCI ``SYSTEM_OFF`` API. This issue will be fixed in a future version of
+   the model.
+
+-  While this version has low on-chip RAM requirements, there are further
+   RAM usage enhancements that could be made.
+
+-  The upstream documentation could be improved for structural consistency,
+   clarity and completeness. In particular, the design documentation is
+   incomplete for PSCI, the TSP(D) and the Juno platform.
+
+-  Building TF-A with compiler optimisations disabled (``-O0``) fails.
+
+Version 1.1
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  A prototype implementation of Trusted Board Boot has been added. Boot
+   loader images are verified by BL1 and BL2 during the cold boot path. BL1 and
+   BL2 use the PolarSSL SSL library to verify certificates and images. The
+   OpenSSL library is used to create the X.509 certificates. Support has been
+   added to ``fip_create`` tool to package the certificates in a FIP.
+
+-  Support for calling CPU and platform specific reset handlers upon entry into
+   BL3-1 during the cold and warm boot paths has been added. This happens after
+   another Boot ROM ``reset_handler()`` has already run. This enables a developer
+   to perform additional actions or undo actions already performed during the
+   first call of the reset handlers e.g. apply additional errata workarounds.
+
+-  Support has been added to demonstrate routing of IRQs to EL3 instead of
+   S-EL1 when execution is in secure world.
+
+-  The PSCI implementation now conforms to version 1.0 of the PSCI
+   specification. All the mandatory APIs and selected optional APIs are
+   supported. In particular, support for the ``PSCI_FEATURES`` API has been
+   added. A capability variable is constructed during initialization by
+   examining the ``plat_pm_ops`` and ``spd_pm_ops`` exported by the platform and
+   the Secure Payload Dispatcher. This is used by the PSCI FEATURES function
+   to determine which PSCI APIs are supported by the platform.
+
+-  Improvements have been made to the PSCI code as follows.
+
+   -  The code has been refactored to remove redundant parameters from
+      internal functions.
+
+   -  Changes have been made to the code for PSCI ``CPU_SUSPEND``, ``CPU_ON`` and
+      ``CPU_OFF`` calls to facilitate an early return to the caller in case a
+      failure condition is detected. For example, a PSCI ``CPU_SUSPEND`` call
+      returns ``SUCCESS`` to the caller if a pending interrupt is detected early
+      in the code path.
+
+   -  Optional platform APIs have been added to validate the ``power_state`` and
+      ``entrypoint`` parameters early in PSCI ``CPU_ON`` and ``CPU_SUSPEND`` code
+      paths.
+
+   -  PSCI migrate APIs have been reworked to invoke the SPD hook to determine
+      the type of Trusted OS and the CPU it is resident on (if
+      applicable). Also, during a PSCI ``MIGRATE`` call, the SPD hook to migrate
+      the Trusted OS is invoked.
+
+-  It is now possible to build TF-A without marking at least an extra page of
+   memory as coherent. The build flag ``USE_COHERENT_MEM`` can be used to
+   choose between the two implementations. This has been made possible through
+   these changes.
+
+   -  An implementation of Bakery locks, where the locks are not allocated in
+      coherent memory has been added.
+
+   -  Memory which was previously marked as coherent is now kept coherent
+      through the use of software cache maintenance operations.
+
+   Approximately, 4K worth of memory is saved for each boot loader stage when
+   ``USE_COHERENT_MEM=0``. Enabling this option increases the latencies
+   associated with acquire and release of locks. It also requires changes to
+   the platform ports.
+
+-  It is now possible to specify the name of the FIP at build time by defining
+   the ``FIP_NAME`` variable.
+
+-  Issues with dependencies on the 'fiptool' makefile target have been
+   rectified. The ``fip_create`` tool is now rebuilt whenever its source files
+   change.
+
+-  The BL3-1 runtime console is now also used as the crash console. The crash
+   console is changed to SoC UART0 (UART2) from the previous FPGA UART0 (UART0)
+   on Juno. In FVP, it is changed from UART0 to UART1.
+
+-  CPU errata workarounds are applied only when the revision and part number
+   match. This behaviour has been made consistent across the debug and release
+   builds. The debug build additionally prints a warning if a mismatch is
+   detected.
+
+-  It is now possible to issue cache maintenance operations by set/way for a
+   particular level of data cache. Levels 1-3 are currently supported.
+
+-  The following improvements have been made to the FVP port.
+
+   -  The build option ``FVP_SHARED_DATA_LOCATION`` which allowed relocation of
+      shared data into the Trusted DRAM has been deprecated. Shared data is
+      now always located at the base of Trusted SRAM.
+
+   -  BL2 Translation tables have been updated to map only the region of
+      DRAM which is accessible to normal world. This is the region of the 2GB
+      DDR-DRAM memory at 0x80000000 excluding the top 16MB. The top 16MB is
+      accessible to only the secure world.
+
+   -  BL3-2 can now reside in the top 16MB of DRAM which is accessible only to
+      the secure world. This can be done by setting the build flag
+      ``FVP_TSP_RAM_LOCATION`` to the value ``dram``.
+
+-  Separate translation tables are created for each boot loader image. The
+   ``IMAGE_BLx`` build options are used to do this. This allows each stage to
+   create mappings only for areas in the memory map that it needs.
+
+-  A Secure Payload Dispatcher (OPTEED) for the OP-TEE Trusted OS has been
+   added. Details of using it with TF-A can be found in `OP-TEE Dispatcher`_
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  The Juno port has been aligned with the FVP port as follows.
+
+   -  Support for reclaiming all BL1 RW memory and BL2 memory by overlaying
+      the BL3-1/BL3-2 NOBITS sections on top of them has been added to the
+      Juno port.
+
+   -  The top 16MB of the 2GB DDR-DRAM memory at 0x80000000 is configured
+      using the TZC-400 controller to be accessible only to the secure world.
+
+   -  The Arm GIC driver is used to configure the GIC-400 instead of using a
+      GIC driver private to the Juno port.
+
+   -  PSCI ``CPU_SUSPEND`` calls that target a standby state are now supported.
+
+   -  The TZC-400 driver is used to configure the controller instead of direct
+      accesses to the registers.
+
+-  The Linux kernel version referred to in the user guide has DVFS and HMP
+   support enabled.
+
+-  DS-5 v5.19 did not detect Version 5.8 of the Cortex-A57-A53 Base FVPs in
+   CADI server mode. This issue is not seen with DS-5 v5.20 and Version 6.2 of
+   the Cortex-A57-A53 Base FVPs.
+
+Known issues
+^^^^^^^^^^^^
+
+-  The Trusted Board Boot implementation is a prototype. There are issues with
+   the modularity and scalability of the design. Support for a Trusted
+   Watchdog, firmware update mechanism, recovery images and Trusted debug is
+   absent. These issues will be addressed in future releases.
+
+-  The FVP and Juno ports do not use the hash of the ROTPK stored in the
+   Trusted Key Storage registers to verify the ROTPK in the
+   ``plat_match_rotpk()`` function. This prevents the correct establishment of
+   the Chain of Trust at the first step in the Trusted Board Boot process.
+
+-  The version of the AEMv8 Base FVP used in this release resets the model
+   instead of terminating its execution in response to a shutdown request using
+   the PSCI ``SYSTEM_OFF`` API. This issue will be fixed in a future version of
+   the model.
+
+-  GICv3 support is experimental. There are known issues with GICv3
+   initialization in the TF-A.
+
+-  While this version greatly reduces the on-chip RAM requirements, there are
+   further RAM usage enhancements that could be made.
+
+-  The firmware design documentation for the Test Secure-EL1 Payload (TSP) and
+   its dispatcher (TSPD) is incomplete. Similarly for the PSCI section.
+
+-  The Juno-specific firmware design documentation is incomplete.
+
+Version 1.0
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  It is now possible to map higher physical addresses using non-flat virtual
+   to physical address mappings in the MMU setup.
+
+-  Wider use is now made of the per-CPU data cache in BL3-1 to store:
+
+   -  Pointers to the non-secure and secure security state contexts.
+
+   -  A pointer to the CPU-specific operations.
+
+   -  A pointer to PSCI specific information (for example the current power
+      state).
+
+   -  A crash reporting buffer.
+
+-  The following RAM usage improvements result in a BL3-1 RAM usage reduction
+   from 96KB to 56KB (for FVP with TSPD), and a total RAM usage reduction
+   across all images from 208KB to 88KB, compared to the previous release.
+
+   -  Removed the separate ``early_exception`` vectors from BL3-1 (2KB code size
+      saving).
+
+   -  Removed NSRAM from the FVP memory map, allowing the removal of one
+      (4KB) translation table.
+
+   -  Eliminated the internal ``psci_suspend_context`` array, saving 2KB.
+
+   -  Correctly dimensioned the PSCI ``aff_map_node`` array, saving 1.5KB in the
+      FVP port.
+
+   -  Removed calling CPU mpidr from the bakery lock API, saving 160 bytes.
+
+   -  Removed current CPU mpidr from PSCI common code, saving 160 bytes.
+
+   -  Inlined the mmio accessor functions, saving 360 bytes.
+
+   -  Fully reclaimed all BL1 RW memory and BL2 memory on the FVP port by
+      overlaying the BL3-1/BL3-2 NOBITS sections on top of these at runtime.
+
+   -  Made storing the FP register context optional, saving 0.5KB per context
+      (8KB on the FVP port, with TSPD enabled and running on 8 CPUs).
+
+   -  Implemented a leaner ``tf_printf()`` function, allowing the stack to be
+      greatly reduced.
+
+   -  Removed coherent stacks from the codebase. Stacks allocated in normal
+      memory are now used before and after the MMU is enabled. This saves 768
+      bytes per CPU in BL3-1.
+
+   -  Reworked the crash reporting in BL3-1 to use less stack.
+
+   -  Optimized the EL3 register state stored in the ``cpu_context`` structure
+      so that registers that do not change during normal execution are
+      re-initialized each time during cold/warm boot, rather than restored
+      from memory. This saves about 1.2KB.
+
+   -  As a result of some of the above, reduced the runtime stack size in all
+      BL images. For BL3-1, this saves 1KB per CPU.
+
+-  PSCI SMC handler improvements to correctly handle calls from secure states
+   and from AArch32.
+
+-  CPU contexts are now initialized from the ``entry_point_info``. BL3-1 fully
+   determines the exception level to use for the non-trusted firmware (BL3-3)
+   based on the SPSR value provided by the BL2 platform code (or otherwise
+   provided to BL3-1). This allows platform code to directly run non-trusted
+   firmware payloads at either EL2 or EL1 without requiring an EL2 stub or OS
+   loader.
+
+-  Code refactoring improvements:
+
+   -  Refactored ``fvp_config`` into a common platform header.
+
+   -  Refactored the fvp gic code to be a generic driver that no longer has an
+      explicit dependency on platform code.
+
+   -  Refactored the CCI-400 driver to not have dependency on platform code.
+
+   -  Simplified the IO driver so it's no longer necessary to call ``io_init()``
+      and moved all the IO storage framework code to one place.
+
+   -  Simplified the interface the the TZC-400 driver.
+
+   -  Clarified the platform porting interface to the TSP.
+
+   -  Reworked the TSPD setup code to support the alternate BL3-2
+      initialization flow where BL3-1 generic code hands control to BL3-2,
+      rather than expecting the TSPD to hand control directly to BL3-2.
+
+   -  Considerable rework to PSCI generic code to support CPU specific
+      operations.
+
+-  Improved console log output, by:
+
+   -  Adding the concept of debug log levels.
+
+   -  Rationalizing the existing debug messages and adding new ones.
+
+   -  Printing out the version of each BL stage at runtime.
+
+   -  Adding support for printing console output from assembler code,
+      including when a crash occurs before the C runtime is initialized.
+
+-  Moved up to the latest versions of the FVPs, toolchain, EDK2, kernel, Linaro
+   file system and DS-5.
+
+-  On the FVP port, made the use of the Trusted DRAM region optional at build
+   time (off by default). Normal platforms will not have such a "ready-to-use"
+   DRAM area so it is not a good example to use it.
+
+-  Added support for PSCI ``SYSTEM_OFF`` and ``SYSTEM_RESET`` APIs.
+
+-  Added support for CPU specific reset sequences, power down sequences and
+   register dumping during crash reporting. The CPU specific reset sequences
+   include support for errata workarounds.
+
+-  Merged the Juno port into the master branch. Added support for CPU hotplug
+   and CPU idle. Updated the user guide to describe how to build and run on the
+   Juno platform.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  Removed the concept of top/bottom image loading. The image loader now
+   automatically detects the position of the image inside the current memory
+   layout and updates the layout to minimize fragmentation. This resolves the
+   image loader limitations of previously releases. There are currently no
+   plans to support dynamic image loading.
+
+-  CPU idle now works on the publicized version of the Foundation FVP.
+
+-  All known issues relating to the compiler version used have now been
+   resolved. This TF-A version uses Linaro toolchain 14.07 (based on GCC 4.9).
+
+Known issues
+^^^^^^^^^^^^
+
+-  GICv3 support is experimental. The Linux kernel patches to support this are
+   not widely available. There are known issues with GICv3 initialization in
+   the TF-A.
+
+-  While this version greatly reduces the on-chip RAM requirements, there are
+   further RAM usage enhancements that could be made.
+
+-  The firmware design documentation for the Test Secure-EL1 Payload (TSP) and
+   its dispatcher (TSPD) is incomplete. Similarly for the PSCI section.
+
+-  The Juno-specific firmware design documentation is incomplete.
+
+-  Some recent enhancements to the FVP port have not yet been translated into
+   the Juno port. These will be tracked via the tf-issues project.
+
+-  The Linux kernel version referred to in the user guide has DVFS and HMP
+   support disabled due to some known instabilities at the time of this
+   release. A future kernel version will re-enable these features.
+
+-  DS-5 v5.19 does not detect Version 5.8 of the Cortex-A57-A53 Base FVPs in
+   CADI server mode. This is because the ``<SimName>`` reported by the FVP in
+   this version has changed. For example, for the Cortex-A57x4-A53x4 Base FVP,
+   the ``<SimName>`` reported by the FVP is ``FVP_Base_Cortex_A57x4_A53x4``, while
+   DS-5 expects it to be ``FVP_Base_A57x4_A53x4``.
+
+   The temporary fix to this problem is to change the name of the FVP in
+   ``sw/debugger/configdb/Boards/ARM FVP/Base_A57x4_A53x4/cadi_config.xml``.
+   Change the following line:
+
+   ::
+
+       <SimName>System Generator:FVP_Base_A57x4_A53x4</SimName>
+
+   to
+   System Generator:FVP_Base_Cortex-A57x4_A53x4
+
+   A similar change can be made to the other Cortex-A57-A53 Base FVP variants.
+
+Version 0.4
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  Makefile improvements:
+
+   -  Improved dependency checking when building.
+
+   -  Removed ``dump`` target (build now always produces dump files).
+
+   -  Enabled platform ports to optionally make use of parts of the Trusted
+      Firmware (e.g. BL3-1 only), rather than being forced to use all parts.
+      Also made the ``fip`` target optional.
+
+   -  Specified the full path to source files and removed use of the ``vpath``
+      keyword.
+
+-  Provided translation table library code for potential re-use by platforms
+   other than the FVPs.
+
+-  Moved architectural timer setup to platform-specific code.
+
+-  Added standby state support to PSCI cpu_suspend implementation.
+
+-  SRAM usage improvements:
+
+   -  Started using the ``-ffunction-sections``, ``-fdata-sections`` and
+      ``--gc-sections`` compiler/linker options to remove unused code and data
+      from the images. Previously, all common functions were being built into
+      all binary images, whether or not they were actually used.
+
+   -  Placed all assembler functions in their own section to allow more unused
+      functions to be removed from images.
+
+   -  Updated BL1 and BL2 to use a single coherent stack each, rather than one
+      per CPU.
+
+   -  Changed variables that were unnecessarily declared and initialized as
+      non-const (i.e. in the .data section) so they are either uninitialized
+      (zero init) or const.
+
+-  Moved the Test Secure-EL1 Payload (BL3-2) to execute in Trusted SRAM by
+   default. The option for it to run in Trusted DRAM remains.
+
+-  Implemented a TrustZone Address Space Controller (TZC-400) driver. A
+   default configuration is provided for the Base FVPs. This means the model
+   parameter ``-C bp.secure_memory=1`` is now supported.
+
+-  Started saving the PSCI cpu_suspend 'power_state' parameter prior to
+   suspending a CPU. This allows platforms that implement multiple power-down
+   states at the same affinity level to identify a specific state.
+
+-  Refactored the entire codebase to reduce the amount of nesting in header
+   files and to make the use of system/user includes more consistent. Also
+   split platform.h to separate out the platform porting declarations from the
+   required platform porting definitions and the definitions/declarations
+   specific to the platform port.
+
+-  Optimized the data cache clean/invalidate operations.
+
+-  Improved the BL3-1 unhandled exception handling and reporting. Unhandled
+   exceptions now result in a dump of registers to the console.
+
+-  Major rework to the handover interface between BL stages, in particular the
+   interface to BL3-1. The interface now conforms to a specification and is
+   more future proof.
+
+-  Added support for optionally making the BL3-1 entrypoint a reset handler
+   (instead of BL1). This allows platforms with an alternative image loading
+   architecture to re-use BL3-1 with fewer modifications to generic code.
+
+-  Reserved some DDR DRAM for secure use on FVP platforms to avoid future
+   compatibility problems with non-secure software.
+
+-  Added support for secure interrupts targeting the Secure-EL1 Payload (SP)
+   (using GICv2 routing only). Demonstrated this working by adding an interrupt
+   target and supporting test code to the TSP. Also demonstrated non-secure
+   interrupt handling during TSP processing.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  Now support use of the model parameter ``-C bp.secure_memory=1`` in the Base
+   FVPs (see **New features**).
+
+-  Support for secure world interrupt handling now available (see **New
+   features**).
+
+-  Made enough SRAM savings (see **New features**) to enable the Test Secure-EL1
+   Payload (BL3-2) to execute in Trusted SRAM by default.
+
+-  The tested filesystem used for this release (Linaro AArch64 OpenEmbedded
+   14.04) now correctly reports progress in the console.
+
+-  Improved the Makefile structure to make it easier to separate out parts of
+   the TF-A for re-use in platform ports. Also, improved target dependency
+   checking.
+
+Known issues
+^^^^^^^^^^^^
+
+-  GICv3 support is experimental. The Linux kernel patches to support this are
+   not widely available. There are known issues with GICv3 initialization in
+   the TF-A.
+
+-  Dynamic image loading is not available yet. The current image loader
+   implementation (used to load BL2 and all subsequent images) has some
+   limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead
+   to loading errors, even if the images should theoretically fit in memory.
+
+-  TF-A still uses too much on-chip Trusted SRAM. A number of RAM usage
+   enhancements have been identified to rectify this situation.
+
+-  CPU idle does not work on the advertised version of the Foundation FVP.
+   Some FVP fixes are required that are not available externally at the time
+   of writing. This can be worked around by disabling CPU idle in the Linux
+   kernel.
+
+-  Various bugs in TF-A, UEFI and the Linux kernel have been observed when
+   using Linaro toolchain versions later than 13.11. Although most of these
+   have been fixed, some remain at the time of writing. These mainly seem to
+   relate to a subtle change in the way the compiler converts between 64-bit
+   and 32-bit values (e.g. during casting operations), which reveals
+   previously hidden bugs in client code.
+
+-  The firmware design documentation for the Test Secure-EL1 Payload (TSP) and
+   its dispatcher (TSPD) is incomplete. Similarly for the PSCI section.
+
+Version 0.3
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  Support for Foundation FVP Version 2.0 added.
+   The documented UEFI configuration disables some devices that are unavailable
+   in the Foundation FVP, including MMC and CLCD. The resultant UEFI binary can
+   be used on the AEMv8 and Cortex-A57-A53 Base FVPs, as well as the Foundation
+   FVP.
+
+   .. note::
+      The software will not work on Version 1.0 of the Foundation FVP.
+
+-  Enabled third party contributions. Added a new contributing.md containing
+   instructions for how to contribute and updated copyright text in all files
+   to acknowledge contributors.
+
+-  The PSCI CPU_SUSPEND API has been stabilised to the extent where it can be
+   used for entry into power down states with the following restrictions:
+
+   -  Entry into standby states is not supported.
+   -  The API is only supported on the AEMv8 and Cortex-A57-A53 Base FVPs.
+
+-  The PSCI AFFINITY_INFO api has undergone limited testing on the Base FVPs to
+   allow experimental use.
+
+-  Required C library and runtime header files are now included locally in
+   TF-A instead of depending on the toolchain standard include paths. The
+   local implementation has been cleaned up and reduced in scope.
+
+-  Added I/O abstraction framework, primarily to allow generic code to load
+   images in a platform-independent way. The existing image loading code has
+   been reworked to use the new framework. Semi-hosting and NOR flash I/O
+   drivers are provided.
+
+-  Introduced Firmware Image Package (FIP) handling code and tools. A FIP
+   combines multiple firmware images with a Table of Contents (ToC) into a
+   single binary image. The new FIP driver is another type of I/O driver. The
+   Makefile builds a FIP by default and the FVP platform code expect to load a
+   FIP from NOR flash, although some support for image loading using semi-
+   hosting is retained.
+
+   .. note::
+      Building a FIP by default is a non-backwards-compatible change.
+
+   .. note::
+      Generic BL2 code now loads a BL3-3 (non-trusted firmware) image into
+      DRAM instead of expecting this to be pre-loaded at known location. This is
+      also a non-backwards-compatible change.
+
+   .. note::
+      Some non-trusted firmware (e.g. UEFI) will need to be rebuilt so that
+      it knows the new location to execute from and no longer needs to copy
+      particular code modules to DRAM itself.
+
+-  Reworked BL2 to BL3-1 handover interface. A new composite structure
+   (bl31_args) holds the superset of information that needs to be passed from
+   BL2 to BL3-1, including information on how handover execution control to
+   BL3-2 (if present) and BL3-3 (non-trusted firmware).
+
+-  Added library support for CPU context management, allowing the saving and
+   restoring of
+
+   -  Shared system registers between Secure-EL1 and EL1.
+   -  VFP registers.
+   -  Essential EL3 system registers.
+
+-  Added a framework for implementing EL3 runtime services. Reworked the PSCI
+   implementation to be one such runtime service.
+
+-  Reworked the exception handling logic, making use of both SP_EL0 and SP_EL3
+   stack pointers for determining the type of exception, managing general
+   purpose and system register context on exception entry/exit, and handling
+   SMCs. SMCs are directed to the correct EL3 runtime service.
+
+-  Added support for a Test Secure-EL1 Payload (TSP) and a corresponding
+   Dispatcher (TSPD), which is loaded as an EL3 runtime service. The TSPD
+   implements Secure Monitor functionality such as world switching and
+   EL1 context management, and is responsible for communication with the TSP.
+
+   .. note::
+      The TSPD does not yet contain support for secure world interrupts.
+   .. note::
+      The TSP/TSPD is not built by default.
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  Support has been added for switching context between secure and normal
+   worlds in EL3.
+
+-  PSCI API calls ``AFFINITY_INFO`` & ``PSCI_VERSION`` have now been tested (to
+   a limited extent).
+
+-  The TF-A build artifacts are now placed in the ``./build`` directory and
+   sub-directories instead of being placed in the root of the project.
+
+-  TF-A is now free from build warnings. Build warnings are now treated as
+   errors.
+
+-  TF-A now provides C library support locally within the project to maintain
+   compatibility between toolchains/systems.
+
+-  The PSCI locking code has been reworked so it no longer takes locks in an
+   incorrect sequence.
+
+-  The RAM-disk method of loading a Linux file-system has been confirmed to
+   work with the TF-A and Linux kernel version (based on version 3.13) used
+   in this release, for both Foundation and Base FVPs.
+
+Known issues
+^^^^^^^^^^^^
+
+The following is a list of issues which are expected to be fixed in the future
+releases of TF-A.
+
+-  The TrustZone Address Space Controller (TZC-400) is not being programmed
+   yet. Use of model parameter ``-C bp.secure_memory=1`` is not supported.
+
+-  No support yet for secure world interrupt handling.
+
+-  GICv3 support is experimental. The Linux kernel patches to support this are
+   not widely available. There are known issues with GICv3 initialization in
+   TF-A.
+
+-  Dynamic image loading is not available yet. The current image loader
+   implementation (used to load BL2 and all subsequent images) has some
+   limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead
+   to loading errors, even if the images should theoretically fit in memory.
+
+-  TF-A uses too much on-chip Trusted SRAM. Currently the Test Secure-EL1
+   Payload (BL3-2) executes in Trusted DRAM since there is not enough SRAM.
+   A number of RAM usage enhancements have been identified to rectify this
+   situation.
+
+-  CPU idle does not work on the advertised version of the Foundation FVP.
+   Some FVP fixes are required that are not available externally at the time
+   of writing.
+
+-  Various bugs in TF-A, UEFI and the Linux kernel have been observed when
+   using Linaro toolchain versions later than 13.11. Although most of these
+   have been fixed, some remain at the time of writing. These mainly seem to
+   relate to a subtle change in the way the compiler converts between 64-bit
+   and 32-bit values (e.g. during casting operations), which reveals
+   previously hidden bugs in client code.
+
+-  The tested filesystem used for this release (Linaro AArch64 OpenEmbedded
+   14.01) does not report progress correctly in the console. It only seems to
+   produce error output, not standard output. It otherwise appears to function
+   correctly. Other filesystem versions on the same software stack do not
+   exhibit the problem.
+
+-  The Makefile structure doesn't make it easy to separate out parts of the
+   TF-A for re-use in platform ports, for example if only BL3-1 is required in
+   a platform port. Also, dependency checking in the Makefile is flawed.
+
+-  The firmware design documentation for the Test Secure-EL1 Payload (TSP) and
+   its dispatcher (TSPD) is incomplete. Similarly for the PSCI section.
+
+Version 0.2
+-----------
+
+New features
+^^^^^^^^^^^^
+
+-  First source release.
+
+-  Code for the PSCI suspend feature is supplied, although this is not enabled
+   by default since there are known issues (see below).
+
+Issues resolved since last release
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  The "psci" nodes in the FDTs provided in this release now fully comply
+   with the recommendations made in the PSCI specification.
+
+Known issues
+^^^^^^^^^^^^
+
+The following is a list of issues which are expected to be fixed in the future
+releases of TF-A.
+
+-  The TrustZone Address Space Controller (TZC-400) is not being programmed
+   yet. Use of model parameter ``-C bp.secure_memory=1`` is not supported.
+
+-  No support yet for secure world interrupt handling or for switching context
+   between secure and normal worlds in EL3.
+
+-  GICv3 support is experimental. The Linux kernel patches to support this are
+   not widely available. There are known issues with GICv3 initialization in
+   TF-A.
+
+-  Dynamic image loading is not available yet. The current image loader
+   implementation (used to load BL2 and all subsequent images) has some
+   limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead
+   to loading errors, even if the images should theoretically fit in memory.
+
+-  Although support for PSCI ``CPU_SUSPEND`` is present, it is not yet stable
+   and ready for use.
+
+-  PSCI API calls ``AFFINITY_INFO`` & ``PSCI_VERSION`` are implemented but have
+   not been tested.
+
+-  The TF-A make files result in all build artifacts being placed in the root
+   of the project. These should be placed in appropriate sub-directories.
+
+-  The compilation of TF-A is not free from compilation warnings. Some of these
+   warnings have not been investigated yet so they could mask real bugs.
+
+-  TF-A currently uses toolchain/system include files like stdio.h. It should
+   provide versions of these within the project to maintain compatibility
+   between toolchains/systems.
+
+-  The PSCI code takes some locks in an incorrect sequence. This may cause
+   problems with suspend and hotplug in certain conditions.
+
+-  The Linux kernel used in this release is based on version 3.12-rc4. Using
+   this kernel with the TF-A fails to start the file-system as a RAM-disk. It
+   fails to execute user-space ``init`` from the RAM-disk. As an alternative,
+   the VirtioBlock mechanism can be used to provide a file-system to the
+   kernel.
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _SDEI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _PSCI Integration Guide: ./getting_started/psci-lib-integration-guide.rst
+.. _Developer Certificate of Origin: ../dco.txt
+.. _Contribution Guide: ./process/contributing.rst
+.. _Authentication framework: ./design/auth-framework.rst
+.. _Firmware Update: ./design/firmware-update.rst
+.. _Firmware Design: ./design/firmware-design.rst
+.. _TF-A Reset Design: ./design/reset-design.rst
+.. _Power Domain Topology Design: ./design/psci-pd-tree.rst
+.. _image terminology document: ./getting_started/image-terminology.rst
+.. _Authentication Framework: ./design/auth-framework.rst
+.. _OP-TEE Dispatcher: ./spd/optee-dispatcher.rst
+.. _tf-issue#501: https://github.com/ARM-software/tf-issues/issues/501
+.. _PR#1002: https://github.com/ARM-software/arm-trusted-firmware/pull/1002#issuecomment-312650193
diff --git a/docs/components/arm-sip-service.rst b/docs/components/arm-sip-service.rst
new file mode 100644
index 0000000..e450d37
--- /dev/null
+++ b/docs/components/arm-sip-service.rst
@@ -0,0 +1,96 @@
+Arm SiP Services
+================
+
+This document enumerates and describes the Arm SiP (Silicon Provider) services.
+
+SiP services are non-standard, platform-specific services offered by the silicon
+implementer or platform provider. They are accessed via ``SMC`` ("SMC calls")
+instruction executed from Exception Levels below EL3. SMC calls for SiP
+services:
+
+-  Follow `SMC Calling Convention`_;
+-  Use SMC function IDs that fall in the SiP range, which are ``0xc2000000`` -
+   ``0xc200ffff`` for 64-bit calls, and ``0x82000000`` - ``0x8200ffff`` for 32-bit
+   calls.
+
+The Arm SiP implementation offers the following services:
+
+-  Performance Measurement Framework (PMF)
+-  Execution State Switching service
+
+Source definitions for Arm SiP service are located in the ``arm_sip_svc.h`` header
+file.
+
+Performance Measurement Framework (PMF)
+---------------------------------------
+
+The `Performance Measurement Framework`_
+allows callers to retrieve timestamps captured at various paths in TF-A
+execution. It's described in detail in `Firmware Design document`_.
+
+Execution State Switching service
+---------------------------------
+
+Execution State Switching service provides a mechanism for a non-secure lower
+Exception Level (either EL2, or NS EL1 if EL2 isn't implemented) to request to
+switch its execution state (a.k.a. Register Width), either from AArch64 to
+AArch32, or from AArch32 to AArch64, for the calling CPU. This service is only
+available when Trusted Firmware-A (TF-A) is built for AArch64 (i.e. when build
+option ``ARCH`` is set to ``aarch64``).
+
+``ARM_SIP_SVC_EXE_STATE_SWITCH``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t Function ID
+        uint32_t PC hi
+        uint32_t PC lo
+        uint32_t Cookie hi
+        uint32_t Cookie lo
+
+    Return:
+        uint32_t
+
+The function ID parameter must be ``0x82000020``. It uniquely identifies the
+Execution State Switching service being requested.
+
+The parameters *PC hi* and *PC lo* defines upper and lower words, respectively,
+of the entry point (physical address) at which execution should start, after
+Execution State has been switched. When calling from AArch64, *PC hi* must be 0.
+
+When execution starts at the supplied entry point after Execution State has been
+switched, the parameters *Cookie hi* and *Cookie lo* are passed in CPU registers
+0 and 1, respectively. When calling from AArch64, *Cookie hi* must be 0.
+
+This call can only be made on the primary CPU, before any secondaries were
+brought up with ``CPU_ON`` PSCI call. Otherwise, the call will always fail.
+
+The effect of switching execution state is as if the Exception Level were
+entered for the first time, following power on. This means CPU registers that
+have a defined reset value by the Architecture will assume that value. Other
+registers should not be expected to hold their values before the call was made.
+CPU endianness, however, is preserved from the previous execution state. Note
+that this switches the execution state of the calling CPU only. This is not a
+substitute for PSCI ``SYSTEM_RESET``.
+
+The service may return the following error codes:
+
+-  ``STATE_SW_E_PARAM``: If any of the parameters were deemed invalid for
+   a specific request.
+-  ``STATE_SW_E_DENIED``: If the call is not successful, or when TF-A is
+   built for AArch32.
+
+If the call is successful, the caller wouldn't observe the SMC returning.
+Instead, execution starts at the supplied entry point, with the CPU registers 0
+and 1 populated with the supplied *Cookie hi* and *Cookie lo* values,
+respectively.
+
+--------------
+
+*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+.. _Performance Measurement Framework: ../design/firmware-design.rst#user-content-performance-measurement-framework
+.. _Firmware Design document: ../design/firmware-design.rst
diff --git a/docs/components/exception-handling.rst b/docs/components/exception-handling.rst
new file mode 100644
index 0000000..0d01733
--- /dev/null
+++ b/docs/components/exception-handling.rst
@@ -0,0 +1,626 @@
+Exception Handling Framework
+============================
+
+This document describes various aspects of handling exceptions by Runtime
+Firmware (BL31) that are targeted at EL3, other than SMCs. The |EHF| takes care
+of the following exceptions when targeted at EL3:
+
+-  Interrupts
+-  Synchronous External Aborts
+-  Asynchronous External Aborts
+
+|TF-A|'s handling of synchronous ``SMC`` exceptions raised from lower ELs is
+described in the `Firmware Design document`__. However, the |EHF| changes the
+semantics of `interrupt handling`__ and `synchronous exceptions`__ other than
+SMCs.
+
+.. __: firmware-design.rst#handling-an-smc
+.. __: `Interrupt handling`_
+.. __: `Effect on SMC calls`_
+
+The |EHF| is selected by setting the build option ``EL3_EXCEPTION_HANDLING`` to
+``1``, and is only available for AArch64 systems.
+
+Introduction
+------------
+
+Through various control bits in the ``SCR_EL3`` register, the Arm architecture
+allows for asynchronous exceptions to be routed to EL3. As described in the
+`Interrupt Framework Design`_ document, depending on the chosen interrupt
+routing model, TF-A appropriately sets the ``FIQ`` and ``IRQ`` bits of
+``SCR_EL3`` register to effect this routing. For most use cases, other than for
+the purpose of facilitating context switch between Normal and Secure worlds,
+FIQs and IRQs routed to EL3 are not required to be handled in EL3.
+
+However, the evolving system and standards landscape demands that various
+exceptions are targeted at and handled in EL3. For instance:
+
+-  Starting with ARMv8.2 architecture extension, many RAS features have been
+   introduced to the Arm architecture. With RAS features implemented, various
+   components of the system may use one of the asynchronous exceptions to signal
+   error conditions to PEs. These error conditions are of critical nature, and
+   it's imperative that corrective or remedial actions are taken at the earliest
+   opportunity. Therefore, a *Firmware-first Handling* approach is generally
+   followed in response to RAS events in the system.
+
+-  The Arm `SDEI specification`_ defines interfaces through which Normal world
+   interacts with the Runtime Firmware in order to request notification of
+   system events. The |SDEI| specification requires that these events are
+   notified even when the Normal world executes with the exceptions masked. This
+   too implies that firmware-first handling is required, where the events are
+   first received by the EL3 firmware, and then dispatched to Normal world
+   through purely software mechanism.
+
+For |TF-A|, firmware-first handling means that asynchronous exceptions are
+suitably routed to EL3, and the Runtime Firmware (BL31) is extended to include
+software components that are capable of handling those exceptions that target
+EL3. These components—referred to as *dispatchers* [#spd]_ in general—may
+choose to:
+
+.. _delegation-use-cases:
+
+-  Receive and handle exceptions entirely in EL3, meaning the exceptions
+   handling terminates in EL3.
+
+-  Receive exceptions, but handle part of the exception in EL3, and delegate the
+   rest of the handling to a dedicated software stack running at lower Secure
+   ELs. In this scheme, the handling spans various secure ELs.
+
+-  Receive exceptions, but handle part of the exception in EL3, and delegate
+   processing of the error to dedicated software stack running at lower secure
+   ELs (as above); additionally, the Normal world may also be required to
+   participate in the handling, or be notified of such events (for example, as
+   an |SDEI| event). In this scheme, exception handling potentially and
+   maximally spans all ELs in both Secure and Normal worlds.
+
+On any given system, all of the above handling models may be employed
+independently depending on platform choice and the nature of the exception
+received.
+
+.. [#spd] Not to be confused with `Secure Payload Dispatcher`__, which is an
+   EL3 component that operates in EL3 on behalf of Secure OS.
+
+.. __: firmware-design.rst#secure-el1-payloads-and-dispatchers
+
+The role of Exception Handling Framework
+----------------------------------------
+
+Corollary to the use cases cited above, the primary role of the |EHF| is to
+facilitate firmware-first handling of exceptions on Arm systems. The |EHF| thus
+enables multiple exception dispatchers in runtime firmware to co-exist, register
+for, and handle exceptions targeted at EL3. This section outlines the basics,
+and the rest of this document expands the various aspects of the |EHF|.
+
+In order to arbitrate exception handling among dispatchers, the |EHF| operation
+is based on a priority scheme. This priority scheme is closely tied to how the
+Arm GIC architecture defines it, although it's applied to non-interrupt
+exceptions too (SErrors, for example).
+
+The platform is required to `partition`__ the Secure priority space into
+priority levels as applicable for the Secure software stack. It then assigns the
+dispatchers to one or more priority levels. The dispatchers then register
+handlers for the priority levels at runtime. A dispatcher can register handlers
+for more than one priority level.
+
+.. __: `Partitioning priority levels`_
+
+
+.. _ehf-figure:
+
+.. image:: ../resources/diagrams/draw.io/ehf.svg
+
+A priority level is *active* when a handler at that priority level is currently
+executing in EL3, or has delegated the execution to a lower EL. For interrupts,
+this is implicit when an interrupt is targeted and acknowledged at EL3, and the
+priority of the acknowledged interrupt is used to match its registered handler.
+The priority level is likewise implicitly deactivated when the interrupt
+handling concludes by EOIing the interrupt.
+
+Non-interrupt exceptions (SErrors, for example) don't have a notion of priority.
+In order for the priority arbitration to work, the |EHF| provides APIs in order
+for these non-interrupt exceptions to assume a priority, and to interwork with
+interrupts. Dispatchers handling such exceptions must therefore explicitly
+activate and deactivate the respective priority level as and when they're
+handled or delegated.
+
+Because priority activation and deactivation for interrupt handling is implicit
+and involves GIC priority masking, it's impossible for a lower priority
+interrupt to preempt a higher priority one. By extension, this means that a
+lower priority dispatcher cannot preempt a higher-priority one. Priority
+activation and deactivation for non-interrupt exceptions, however, has to be
+explicit. The |EHF| therefore disallows for lower priority level to be activated
+whilst a higher priority level is active, and would result in a panic.
+Likewise, a panic would result if it's attempted to deactivate a lower priority
+level when a higher priority level is active.
+
+In essence, priority level activation and deactivation conceptually works like a
+stack—priority levels stack up in strictly increasing fashion, and need to be
+unstacked in strictly the reverse order. For interrupts, the GIC ensures this is
+the case; for non-interrupts, the |EHF| monitors and asserts this. See
+`Transition of priority levels`_.
+
+Interrupt handling
+------------------
+
+The |EHF| is a client of *Interrupt Management Framework*, and registers the
+top-level handler for interrupts that target EL3, as described in the `Interrupt
+Framework Design`_ document. This has the following implications.
+
+-  On GICv3 systems, when executing in S-EL1, pending Non-secure interrupts of
+   sufficient priority are signalled as FIQs, and therefore will be routed to
+   EL3. As a result, S-EL1 software cannot expect to handle Non-secure
+   interrupts at S-EL1. Essentially, this deprecates the routing mode described
+   as `CSS=0, TEL3=0`__.
+
+   .. __: interrupt-framework-design.rst#el3-interrupts
+
+   In order for S-EL1 software to handle Non-secure interrupts while having
+   |EHF| enabled, the dispatcher must adopt a model where Non-secure interrupts
+   are received at EL3, but are then `synchronously`__ handled over to S-EL1.
+
+   .. __: interrupt-framework-design.rst#secure-payload
+
+-  On GICv2 systems, it's required that the build option ``GICV2_G0_FOR_EL3`` is
+   set to ``1`` so that *Group 0* interrupts target EL3.
+
+-  While executing in Secure world, |EHF| sets GIC Priority Mask Register to the
+   lowest Secure priority. This means that no Non-secure interrupts can preempt
+   Secure execution. See `Effect on SMC calls`_ for more details.
+
+As mentioned above, with |EHF|, the platform is required to partition *Group 0*
+interrupts into distinct priority levels. A dispatcher that chooses to receive
+interrupts can then *own* one or more priority levels, and register interrupt
+handlers for them. A given priority level can be assigned to only one handler. A
+dispatcher may register more than one priority level.
+
+Dispatchers are assigned interrupt priority levels in two steps:
+
+Partitioning priority levels
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Interrupts are associated to dispatchers by way of grouping and assigning
+interrupts to a priority level. In other words, all interrupts that are to
+target a particular dispatcher should fall in a particular priority level. For
+priority assignment:
+
+-  Of the 8 bits of priority that Arm GIC architecture permits, bit 7 must be 0
+   (secure space).
+
+-  Depending on the number of dispatchers to support, the platform must choose
+   to use the top *n* of the 7 remaining bits to identify and assign interrupts
+   to individual dispatchers. Choosing *n* bits supports up to 2\ :sup:`n`
+   distinct dispatchers. For example, by choosing 2 additional bits (i.e., bits
+   6 and 5), the platform can partition into 4 secure priority ranges: ``0x0``,
+   ``0x20``, ``0x40``, and ``0x60``. See `Interrupt handling example`_.
+
+.. note::
+
+   The Arm GIC architecture requires that a GIC implementation that supports two
+   security states must implement at least 32 priority levels; i.e., at least 5
+   upper bits of the 8 bits are writeable. In the scheme described above, when
+   choosing *n* bits for priority range assignment, the platform must ensure
+   that at least ``n+1`` top bits of GIC priority are writeable.
+
+The priority thus assigned to an interrupt is also used to determine the
+priority of delegated execution in lower ELs. Delegated execution in lower EL is
+associated with a priority level chosen with ``ehf_activate_priority()`` API
+(described `later`__). The chosen priority level also determines the interrupts
+masked while executing in a lower EL, therefore controls preemption of delegated
+execution.
+
+.. __: `ehf-apis`_
+
+The platform expresses the chosen priority levels by declaring an array of
+priority level descriptors. Each entry in the array is of type
+``ehf_pri_desc_t``, and declares a priority level, and shall be populated by the
+``EHF_PRI_DESC()`` macro.
+
+.. warning::
+
+   The macro ``EHF_PRI_DESC()`` installs the descriptors in the array at a
+   computed index, and not necessarily where the macro is placed in the array.
+   The size of the array might therefore be larger than what it appears to be.
+   The ``ARRAY_SIZE()`` macro therefore should be used to determine the size of
+   array.
+
+Finally, this array of descriptors is exposed to |EHF| via the
+``EHF_REGISTER_PRIORITIES()`` macro.
+
+Refer to the `Interrupt handling example`_ for usage. See also: `Interrupt
+Prioritisation Considerations`_.
+
+Programming priority
+~~~~~~~~~~~~~~~~~~~~
+
+The text in `Partitioning priority levels`_ only describes how the platform
+expresses the required levels of priority. It however doesn't choose interrupts
+nor program the required priority in GIC.
+
+The `Firmware Design guide`__ explains methods for configuring secure
+interrupts. |EHF| requires the platform to enumerate interrupt properties (as
+opposed to just numbers) of Secure interrupts. The priority of secure interrupts
+must match that as determined in the `Partitioning priority levels`_ section above.
+
+.. __: firmware-design.rst#configuring-secure-interrupts
+
+See `Limitations`_, and also refer to `Interrupt handling example`_ for
+illustration.
+
+Registering handler
+-------------------
+
+Dispatchers register handlers for their priority levels through the following
+API:
+
+.. code:: c
+
+   int ehf_register_priority_handler(int pri, ehf_handler_t handler)
+
+The API takes two arguments:
+
+-  The priority level for which the handler is being registered;
+
+-  The handler to be registered. The handler must be aligned to 4 bytes.
+
+If a dispatcher owns more than one priority levels, it has to call the API for
+each of them.
+
+The API will succeed, and return ``0``, only if:
+
+-  There exists a descriptor with the priority level requested.
+
+-  There are no handlers already registered by a previous call to the API.
+
+Otherwise, the API returns ``-1``.
+
+The interrupt handler should have the following signature:
+
+.. code:: c
+
+   typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle,
+                   void *cookie);
+
+The parameters are as obtained from the top-level `EL3 interrupt handler`__.
+
+.. __: interrupt-framework-design.rst#el3-runtime-firmware
+
+The `SDEI dispatcher`__, for example, expects the platform to allocate two
+different priority levels—``PLAT_SDEI_CRITICAL_PRI``, and
+``PLAT_SDEI_NORMAL_PRI``—and registers the same handler to handle both levels.
+
+.. __: sdei.rst
+
+Interrupt handling example
+--------------------------
+
+The following annotated snippet demonstrates how a platform might choose to
+assign interrupts to fictitious dispatchers:
+
+.. code:: c
+
+   #include <common/interrupt_props.h>
+   #include <drivers/arm/gic_common.h>
+   #include <exception_mgmt.h>
+
+   ...
+
+   /*
+    * This platform uses 2 bits for interrupt association. In total, 3 upper
+    * bits are in use.
+    *
+    *  7 6 5   3      0
+    * .-.-.-.----------.
+    * |0|b|b|  ..0..   |
+    * '-'-'-'----------'
+    */
+   #define PLAT_PRI_BITS        2
+
+   /* Priorities for individual dispatchers */
+   #define DISP0_PRIO           0x00 /* Not used */
+   #define DISP1_PRIO           0x20
+   #define DISP2_PRIO           0x40
+   #define DISP3_PRIO           0x60
+
+   /* Install priority level descriptors for each dispatcher */
+   ehf_pri_desc_t plat_exceptions[] = {
+        EHF_PRI_DESC(PLAT_PRI_BITS, DISP1_PRIO),
+        EHF_PRI_DESC(PLAT_PRI_BITS, DISP2_PRIO),
+        EHF_PRI_DESC(PLAT_PRI_BITS, DISP3_PRIO),
+   };
+
+   /* Expose priority descriptors to Exception Handling Framework */
+   EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions),
+        PLAT_PRI_BITS);
+
+   ...
+
+   /* List interrupt properties for GIC driver. All interrupts target EL3 */
+   const interrupt_prop_t plat_interrupts[] = {
+        /* Dispatcher 1 owns interrupts d1_0 and d1_1, so assigns priority DISP1_PRIO */
+        INTR_PROP_DESC(d1_0, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
+        INTR_PROP_DESC(d1_1, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
+
+        /* Dispatcher 2 owns interrupts d2_0 and d2_1, so assigns priority DISP2_PRIO */
+        INTR_PROP_DESC(d2_0, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
+        INTR_PROP_DESC(d2_1, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
+
+        /* Dispatcher 3 owns interrupts d3_0 and d3_1, so assigns priority DISP3_PRIO */
+        INTR_PROP_DESC(d3_0, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
+        INTR_PROP_DESC(d3_1, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL),
+   };
+
+   ...
+
+   /* Dispatcher 1 registers its handler */
+   ehf_register_priority_handler(DISP1_PRIO, disp1_handler);
+
+   /* Dispatcher 2 registers its handler */
+   ehf_register_priority_handler(DISP2_PRIO, disp2_handler);
+
+   /* Dispatcher 3 registers its handler */
+   ehf_register_priority_handler(DISP3_PRIO, disp3_handler);
+
+   ...
+
+See also the `Build-time flow`_ and the `Run-time flow`_.
+
+Activating and Deactivating priorities
+--------------------------------------
+
+A priority level is said to be *active* when an exception of that priority is
+being handled: for interrupts, this is implied when the interrupt is
+acknowledged; for non-interrupt exceptions, such as SErrors or `SDEI explicit
+dispatches`__, this has to be done via calling ``ehf_activate_priority()``. See
+`Run-time flow`_.
+
+.. __: sdei.rst#explicit-dispatch-of-events
+
+Conversely, when the dispatcher has reached a logical resolution for the cause
+of the exception, the corresponding priority level ought to be deactivated. As
+above, for interrupts, this is implied when the interrupt is EOId in the GIC;
+for other exceptions, this has to be done via calling
+``ehf_deactivate_priority()``.
+
+Thanks to `different provisions`__ for exception delegation, there are
+potentially more than one work flow for deactivation:
+
+.. __: `delegation-use-cases`_
+
+.. _deactivation workflows:
+
+-  The dispatcher has addressed the cause of the exception, and decided to take
+   no further action. In this case, the dispatcher's handler deactivates the
+   priority level before returning to the |EHF|. Runtime firmware, upon exit
+   through an ``ERET``, resumes execution before the interrupt occurred.
+
+-  The dispatcher has to delegate the execution to lower ELs, and the cause of
+   the exception can be considered resolved only when the lower EL returns
+   signals complete (via an ``SMC``) at a future point in time. The following
+   sequence ensues:
+
+   #. The dispatcher calls ``setjmp()`` to setup a jump point, and arranges to
+      enter a lower EL upon the next ``ERET``.
+
+   #. Through the ensuing ``ERET`` from runtime firmware, execution is delegated
+      to a lower EL.
+
+   #. The lower EL completes its execution, and signals completion via an
+      ``SMC``.
+
+   #. The ``SMC`` is handled by the same dispatcher that handled the exception
+      previously. Noticing the conclusion of exception handling, the dispatcher
+      does ``longjmp()`` to resume beyond the previous jump point.
+
+As mentioned above, the |EHF| provides the following APIs for activating and
+deactivating interrupt:
+
+.. _ehf-apis:
+
+-  ``ehf_activate_priority()`` activates the supplied priority level, but only
+   if the current active priority is higher than the given one; otherwise
+   panics. Also, to prevent interruption by physical interrupts of lower
+   priority, the |EHF| programs the *Priority Mask Register* corresponding to
+   the PE to the priority being activated.  Dispatchers typically only need to
+   call this when handling exceptions other than interrupts, and it needs to
+   delegate execution to a lower EL at a desired priority level.
+
+-  ``ehf_deactivate_priority()`` deactivates a given priority, but only if the
+   current active priority is equal to the given one; otherwise panics. |EHF|
+   also restores the *Priority Mask Register* corresponding to the PE to the
+   priority before the call to ``ehf_activate_priority()``. Dispatchers
+   typically only need to call this after handling exceptions other than
+   interrupts.
+
+The calling of APIs are subject to allowed `transitions`__. See also the
+`Run-time flow`_.
+
+.. __: `Transition of priority levels`_
+
+Transition of priority levels
+-----------------------------
+
+The |EHF| APIs ``ehf_activate_priority()`` and ``ehf_deactivate_priority()`` can
+be called to transition the current priority level on a PE. A given sequence of
+calls to these APIs are subject to the following conditions:
+
+-  For activation, the |EHF| only allows for the priority to increase (i.e.
+   numeric value decreases);
+
+-  For deactivation, the |EHF| only allows for the priority to decrease (i.e.
+   numeric value increases). Additionally, the priority being deactivated is
+   required to be the current priority.
+
+If these are violated, a panic will result.
+
+Effect on SMC calls
+-------------------
+
+In general, Secure execution is regarded as more important than Non-secure
+execution. As discussed elsewhere in this document, EL3 execution, and any
+delegated execution thereafter, has the effect of raising GIC's priority
+mask—either implicitly by acknowledging Secure interrupts, or when dispatchers
+call ``ehf_activate_priority()``. As a result, Non-secure interrupts cannot
+preempt any Secure execution.
+
+SMCs from Non-secure world are synchronous exceptions, and are mechanisms for
+Non-secure world to request Secure services. They're broadly classified as
+*Fast* or *Yielding* (see `SMCCC`__).
+
+.. __: `http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html`
+
+-  *Fast* SMCs are atomic from the caller's point of view. I.e., they return
+   to the caller only when the Secure world has finished serving the request.
+   Any Non-secure interrupts that become pending meanwhile cannot preempt Secure
+   execution.
+
+-  *Yielding* SMCs carry the semantics of a preemptible, lower-priority request.
+   A pending Non-secure interrupt can preempt Secure execution handling a
+   Yielding SMC. I.e., the caller might observe a Yielding SMC returning when
+   either:
+
+   #. Secure world completes the request, and the caller would find ``SMC_OK``
+      as the return code.
+
+   #. A Non-secure interrupt preempts Secure execution. Non-secure interrupt is
+      handled, and Non-secure execution resumes after ``SMC`` instruction.
+
+   The dispatcher handling a Yielding SMC must provide a different return code
+   to the Non-secure caller to distinguish the latter case. This return code,
+   however, is not standardised (unlike ``SMC_UNKNOWN`` or ``SMC_OK``, for
+   example), so will vary across dispatchers that handle the request.
+
+For the latter case above, dispatchers before |EHF| expect Non-secure interrupts
+to be taken to S-EL1 [#irq]_, so would get a chance to populate the designated
+preempted error code before yielding to Non-secure world.
+
+The introduction of |EHF| changes the behaviour as described in `Interrupt
+handling`_.
+
+When |EHF| is enabled, in order to allow Non-secure interrupts to preempt
+Yielding SMC handling, the dispatcher must call ``ehf_allow_ns_preemption()``
+API. The API takes one argument, the error code to be returned to the Non-secure
+world upon getting preempted.
+
+.. [#irq] In case of GICv2, Non-secure interrupts while in S-EL1 were signalled
+          as IRQs, and in case of GICv3, FIQs.
+
+Build-time flow
+---------------
+
+Please refer to the `figure`__ above.
+
+.. __: `ehf-figure`_
+
+The build-time flow involves the following steps:
+
+#. Platform assigns priorities by installing priority level descriptors for
+   individual dispatchers, as described in `Partitioning priority levels`_.
+
+#. Platform provides interrupt properties to GIC driver, as described in
+   `Programming priority`_.
+
+#. Dispatcher calling ``ehf_register_priority_handler()`` to register an
+   interrupt handler.
+
+Also refer to the `Interrupt handling example`_.
+
+Run-time flow
+-------------
+
+.. _interrupt-flow:
+
+The following is an example flow for interrupts:
+
+#. The GIC driver, during initialization, iterates through the platform-supplied
+   interrupt properties (see `Programming priority`_), and configures the
+   interrupts. This programs the appropriate priority and group (Group 0) on
+   interrupts belonging to different dispatchers.
+
+#. The |EHF|, during its initialisation, registers a top-level interrupt handler
+   with the `Interrupt Management Framework`__ for EL3 interrupts. This also
+   results in setting the routing bits in ``SCR_EL3``.
+
+   .. __: interrupt-framework-design.rst#el3-runtime-firmware
+
+#. When an interrupt belonging to a dispatcher fires, GIC raises an EL3/Group 0
+   interrupt, and is taken to EL3.
+
+#. The top-level EL3 interrupt handler executes. The handler acknowledges the
+   interrupt, reads its *Running Priority*, and from that, determines the
+   dispatcher handler.
+
+#. The |EHF| programs the *Priority Mask Register* of the PE to the priority of
+   the interrupt received.
+
+#. The |EHF| marks that priority level *active*, and jumps to the dispatcher
+   handler.
+
+#. Once the dispatcher handler finishes its job, it has to immediately
+   *deactivate* the priority level before returning to the |EHF|. See
+   `deactivation workflows`_.
+
+.. _non-interrupt-flow:
+
+The following is an example flow for exceptions that targets EL3 other than
+interrupt:
+
+#. The platform provides handlers for the specific kind of exception.
+
+#. The exception arrives, and the corresponding handler is executed.
+
+#. The handler calls ``ehf_activate_priority()`` to activate the required
+   priority level. This also has the effect of raising GIC priority mask, thus
+   preventing interrupts of lower priority from preempting the handling. The
+   handler may choose to do the handling entirely in EL3 or delegate to a lower
+   EL.
+
+#. Once exception handling concludes, the handler calls
+   ``ehf_deactivate_priority()`` to deactivate the priority level activated
+   earlier. This also has the effect of lowering GIC priority mask to what it
+   was before.
+
+Interrupt Prioritisation Considerations
+---------------------------------------
+
+The GIC priority scheme, by design, prioritises Secure interrupts over Normal
+world ones. The platform further assigns relative priorities amongst Secure
+dispatchers through |EHF|.
+
+As mentioned in `Partitioning priority levels`_, interrupts targeting distinct
+dispatchers fall in distinct priority levels. Because they're routed via the
+GIC, interrupt delivery to the PE is subject to GIC prioritisation rules. In
+particular, when an interrupt is being handled by the PE (i.e., the interrupt is
+in *Active* state), only interrupts of higher priority are signalled to the PE,
+even if interrupts of same or lower priority are pending. This has the side
+effect of one dispatcher being starved of interrupts by virtue of another
+dispatcher handling its (higher priority) interrupts.
+
+The |EHF| doesn't enforce a particular prioritisation policy, but the platform
+should carefully consider the assignment of priorities to dispatchers integrated
+into runtime firmware. The platform should sensibly delineate priority to
+various dispatchers according to their nature. In particular, dispatchers of
+critical nature (RAS, for example) should be assigned higher priority than
+others (|SDEI|, for example); and within |SDEI|, Critical priority
+|SDEI| should be assigned higher priority than Normal ones.
+
+Limitations
+-----------
+
+The |EHF| has the following limitations:
+
+-  Although there could be up to 128 Secure dispatchers supported by the GIC
+   priority scheme, the size of descriptor array exposed with
+   ``EHF_REGISTER_PRIORITIES()`` macro is currently limited to 32. This serves most
+   expected use cases. This may be expanded in the future, should use cases
+   demand so.
+
+-  The platform must ensure that the priority assigned to the dispatcher in the
+   exception descriptor and the programmed priority of interrupts handled by the
+   dispatcher match. The |EHF| cannot verify that this has been followed.
+
+----
+
+*Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _Interrupt Framework Design: ../design/interrupt-framework-design.rst
+.. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
diff --git a/docs/components/firmware-update.rst b/docs/components/firmware-update.rst
new file mode 100644
index 0000000..30bdc24
--- /dev/null
+++ b/docs/components/firmware-update.rst
@@ -0,0 +1,404 @@
+Firmware Update (FWU)
+=====================
+
+Introduction
+------------
+
+This document describes the design of the Firmware Update (FWU) feature, which
+enables authenticated firmware to update firmware images from external
+interfaces such as USB, UART, SD-eMMC, NAND, NOR or Ethernet to SoC Non-Volatile
+memories such as NAND Flash, LPPDR2-NVM or any memory determined by the
+platform. This feature functions even when the current firmware in the system
+is corrupt or missing; it therefore may be used as a recovery mode. It may also
+be complemented by other, higher level firmware update software.
+
+FWU implements a specific part of the Trusted Board Boot Requirements (TBBR)
+specification, Arm DEN0006C-1. It should be used in conjunction with the
+`Trusted Board Boot`_ design document, which describes the image authentication
+parts of the Trusted Firmware-A (TF-A) TBBR implementation.
+
+Scope
+~~~~~
+
+This document describes the secure world FWU design. It is beyond its scope to
+describe how normal world FWU images should operate. To implement normal world
+FWU images, please refer to the "Non-Trusted Firmware Updater" requirements in
+the TBBR.
+
+FWU Overview
+------------
+
+The FWU boot flow is primarily mediated by BL1. Since BL1 executes in ROM, and
+it is usually desirable to minimize the amount of ROM code, the design allows
+some parts of FWU to be implemented in other secure and normal world images.
+Platform code may choose which parts are implemented in which images but the
+general expectation is:
+
+-  BL1 handles:
+
+   -  Detection and initiation of the FWU boot flow.
+   -  Copying images from non-secure to secure memory
+   -  FWU image authentication
+   -  Context switching between the normal and secure world during the FWU
+      process.
+
+-  Other secure world FWU images handle platform initialization required by
+   the FWU process.
+-  Normal world FWU images handle loading of firmware images from external
+   interfaces to non-secure memory.
+
+The primary requirements of the FWU feature are:
+
+#. Export a BL1 SMC interface to interoperate with other FWU images executing
+   at other Exception Levels.
+#. Export a platform interface to provide FWU common code with the information
+   it needs, and to enable platform specific FWU functionality. See the
+   `Porting Guide`_ for details of this interface.
+
+TF-A uses abbreviated image terminology for FWU images like for other TF-A
+images. An overview of this terminology can be found `here`_.
+
+The following diagram shows the FWU boot flow for Arm development platforms.
+Arm CSS platforms like Juno have a System Control Processor (SCP), and these
+use all defined FWU images. Other platforms may use a subset of these.
+
+|Flow Diagram|
+
+Image Identification
+--------------------
+
+Each FWU image and certificate is identified by a unique ID, defined by the
+platform, which BL1 uses to fetch an image descriptor (``image_desc_t``) via a
+call to ``bl1_plat_get_image_desc()``. The same ID is also used to prepare the
+Chain of Trust (Refer to the `Authentication Framework Design`_
+for more information).
+
+The image descriptor includes the following information:
+
+-  Executable or non-executable image. This indicates whether the normal world
+   is permitted to request execution of a secure world FWU image (after
+   authentication). Secure world certificates and non-AP images are examples
+   of non-executable images.
+-  Secure or non-secure image. This indicates whether the image is
+   authenticated/executed in secure or non-secure memory.
+-  Image base address and size.
+-  Image entry point configuration (an ``entry_point_info_t``).
+-  FWU image state.
+
+BL1 uses the FWU image descriptors to:
+
+-  Validate the arguments of FWU SMCs
+-  Manage the state of the FWU process
+-  Initialize the execution state of the next FWU image.
+
+FWU State Machine
+-----------------
+
+BL1 maintains state for each FWU image during FWU execution. FWU images at lower
+Exception Levels raise SMCs to invoke FWU functionality in BL1, which causes
+BL1 to update its FWU image state. The BL1 image states and valid state
+transitions are shown in the diagram below. Note that secure images have a more
+complex state machine than non-secure images.
+
+|FWU state machine|
+
+The following is a brief description of the supported states:
+
+-  RESET: This is the initial state of every image at the start of FWU.
+   Authentication failure also leads to this state. A secure
+   image may yield to this state if it has completed execution.
+   It can also be reached by using ``FWU_SMC_IMAGE_RESET``.
+
+-  COPYING: This is the state of a secure image while BL1 is copying it
+   in blocks from non-secure to secure memory.
+
+-  COPIED: This is the state of a secure image when BL1 has completed
+   copying it to secure memory.
+
+-  AUTHENTICATED: This is the state of an image when BL1 has successfully
+   authenticated it.
+
+-  EXECUTED: This is the state of a secure, executable image when BL1 has
+   passed execution control to it.
+
+-  INTERRUPTED: This is the state of a secure, executable image after it has
+   requested BL1 to resume normal world execution.
+
+BL1 SMC Interface
+-----------------
+
+BL1_SMC_CALL_COUNT
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t function ID : 0x0
+
+    Return:
+        uint32_t
+
+This SMC returns the number of SMCs supported by BL1.
+
+BL1_SMC_UID
+~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t function ID : 0x1
+
+    Return:
+        UUID : 32 bits in each of w0-w3 (or r0-r3 for AArch32 callers)
+
+This SMC returns the 128-bit `Universally Unique Identifier`_ for the
+BL1 SMC service.
+
+BL1_SMC_VERSION
+~~~~~~~~~~~~~~~
+
+::
+
+    Argument:
+        uint32_t function ID : 0x3
+
+    Return:
+        uint32_t : Bits [31:16] Major Version
+                   Bits [15:0] Minor Version
+
+This SMC returns the current version of the BL1 SMC service.
+
+BL1_SMC_RUN_IMAGE
+~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t           function ID : 0x4
+        entry_point_info_t *ep_info
+
+    Return:
+        void
+
+    Pre-conditions:
+        if (normal world caller) synchronous exception
+        if (ep_info not EL3) synchronous exception
+
+This SMC passes execution control to an EL3 image described by the provided
+``entry_point_info_t`` structure. In the normal TF-A boot flow, BL2 invokes
+this SMC for BL1 to pass execution control to BL31.
+
+FWU_SMC_IMAGE_COPY
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t     function ID : 0x10
+        unsigned int image_id
+        uintptr_t    image_addr
+        unsigned int block_size
+        unsigned int image_size
+
+    Return:
+        int : 0 (Success)
+            : -ENOMEM
+            : -EPERM
+
+    Pre-conditions:
+        if (image_id is invalid) return -EPERM
+        if (image_id is non-secure image) return -EPERM
+        if (image_id state is not (RESET or COPYING)) return -EPERM
+        if (secure world caller) return -EPERM
+        if (image_addr + block_size overflows) return -ENOMEM
+        if (image destination address + image_size overflows) return -ENOMEM
+        if (source block is in secure memory) return -ENOMEM
+        if (source block is not mapped into BL1) return -ENOMEM
+        if (image_size > free secure memory) return -ENOMEM
+        if (image overlaps another image) return -EPERM
+
+This SMC copies the secure image indicated by ``image_id`` from non-secure memory
+to secure memory for later authentication. The image may be copied in a single
+block or multiple blocks. In either case, the total size of the image must be
+provided in ``image_size`` when invoking this SMC for the first time for each
+image; it is ignored in subsequent calls (if any) for the same image.
+
+The ``image_addr`` and ``block_size`` specify the source memory block to copy from.
+The destination address is provided by the platform code.
+
+If ``block_size`` is greater than the amount of remaining bytes to copy for this
+image then the former is truncated to the latter. The copy operation is then
+considered as complete and the FWU state machine transitions to the "COPIED"
+state. If there is still more to copy, the FWU state machine stays in or
+transitions to the COPYING state (depending on the previous state).
+
+When using multiple blocks, the source blocks do not necessarily need to be in
+contiguous memory.
+
+Once the SMC is handled, BL1 returns from exception to the normal world caller.
+
+FWU_SMC_IMAGE_AUTH
+~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t     function ID : 0x11
+        unsigned int image_id
+        uintptr_t    image_addr
+        unsigned int image_size
+
+    Return:
+        int : 0 (Success)
+            : -ENOMEM
+            : -EPERM
+            : -EAUTH
+
+    Pre-conditions:
+        if (image_id is invalid) return -EPERM
+        if (secure world caller)
+            if (image_id state is not RESET) return -EPERM
+            if (image_addr/image_size is not mapped into BL1) return -ENOMEM
+        else // normal world caller
+            if (image_id is secure image)
+                if (image_id state is not COPIED) return -EPERM
+            else // image_id is non-secure image
+                if (image_id state is not RESET) return -EPERM
+                if (image_addr/image_size is in secure memory) return -ENOMEM
+                if (image_addr/image_size not mapped into BL1) return -ENOMEM
+
+This SMC authenticates the image specified by ``image_id``. If the image is in the
+RESET state, BL1 authenticates the image in place using the provided
+``image_addr`` and ``image_size``. If the image is a secure image in the COPIED
+state, BL1 authenticates the image from the secure memory that BL1 previously
+copied the image into.
+
+BL1 returns from exception to the caller. If authentication succeeds then BL1
+sets the image state to AUTHENTICATED. If authentication fails then BL1 returns
+the -EAUTH error and sets the image state back to RESET.
+
+FWU_SMC_IMAGE_EXECUTE
+~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t     function ID : 0x12
+        unsigned int image_id
+
+    Return:
+        int : 0 (Success)
+            : -EPERM
+
+    Pre-conditions:
+        if (image_id is invalid) return -EPERM
+        if (secure world caller) return -EPERM
+        if (image_id is non-secure image) return -EPERM
+        if (image_id is non-executable image) return -EPERM
+        if (image_id state is not AUTHENTICATED) return -EPERM
+
+This SMC initiates execution of a previously authenticated image specified by
+``image_id``, in the other security world to the caller. The current
+implementation only supports normal world callers initiating execution of a
+secure world image.
+
+BL1 saves the normal world caller's context, sets the secure image state to
+EXECUTED, and returns from exception to the secure image.
+
+FWU_SMC_IMAGE_RESUME
+~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t   function ID : 0x13
+        register_t image_param
+
+    Return:
+        register_t : image_param (Success)
+                   : -EPERM
+
+    Pre-conditions:
+        if (normal world caller and no INTERRUPTED secure image) return -EPERM
+
+This SMC resumes execution in the other security world while there is a secure
+image in the EXECUTED/INTERRUPTED state.
+
+For normal world callers, BL1 sets the previously interrupted secure image state
+to EXECUTED. For secure world callers, BL1 sets the previously executing secure
+image state to INTERRUPTED. In either case, BL1 saves the calling world's
+context, restores the resuming world's context and returns from exception into
+the resuming world. If the call is successful then the caller provided
+``image_param`` is returned to the resumed world, otherwise an error code is
+returned to the caller.
+
+FWU_SMC_SEC_IMAGE_DONE
+~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t function ID : 0x14
+
+    Return:
+        int : 0 (Success)
+            : -EPERM
+
+    Pre-conditions:
+        if (normal world caller) return -EPERM
+
+This SMC indicates completion of a previously executing secure image.
+
+BL1 sets the previously executing secure image state to the RESET state,
+restores the normal world context and returns from exception into the normal
+world.
+
+FWU_SMC_UPDATE_DONE
+~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t   function ID : 0x15
+        register_t client_cookie
+
+    Return:
+        N/A
+
+This SMC completes the firmware update process. BL1 calls the platform specific
+function ``bl1_plat_fwu_done``, passing the optional argument ``client_cookie`` as
+a ``void *``. The SMC does not return.
+
+FWU_SMC_IMAGE_RESET
+~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments:
+        uint32_t     function ID : 0x16
+        unsigned int image_id
+
+    Return:
+        int : 0 (Success)
+            : -EPERM
+
+    Pre-conditions:
+        if (secure world caller) return -EPERM
+        if (image in EXECUTED) return -EPERM
+
+This SMC sets the state of an image to RESET and zeroes the memory used by it.
+
+This is only allowed if the image is not being executed.
+
+--------------
+
+*Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Trusted Board Boot: ../design/trusted-board-boot.rst
+.. _Porting Guide: ../getting_started/porting-guide.rst
+.. _here: ../getting_started/image-terminology.rst
+.. _Authentication Framework Design: ../design/auth-framework.rst
+.. _Universally Unique Identifier: https://tools.ietf.org/rfc/rfc4122.txt
+
+.. |Flow Diagram| image:: ../resources/diagrams/fwu_flow.png
+.. |FWU state machine| image:: ../resources/diagrams/fwu_states.png
diff --git a/docs/components/index.rst b/docs/components/index.rst
new file mode 100644
index 0000000..f1904c0
--- /dev/null
+++ b/docs/components/index.rst
@@ -0,0 +1,18 @@
+Components
+==========
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   spd/index
+   arm-sip-service
+   exception-handling
+   firmware-update
+   platform-interrupt-controller-API
+   ras
+   romlib-design
+   sdei
+   secure-partition-manager-design
+   xlat-tables-lib-v2-design
diff --git a/docs/components/platform-interrupt-controller-API.rst b/docs/components/platform-interrupt-controller-API.rst
new file mode 100644
index 0000000..7890cd3
--- /dev/null
+++ b/docs/components/platform-interrupt-controller-API.rst
@@ -0,0 +1,308 @@
+Platform Interrupt Controller API
+=================================
+
+This document lists the optional platform interrupt controller API that
+abstracts the runtime configuration and control of interrupt controller from the
+generic code. The mandatory APIs are described in the `porting guide`__.
+
+.. __: ../getting_started/porting-guide.rst#interrupt-management-framework-in-bl31
+
+Function: unsigned int plat_ic_get_running_priority(void); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : unsigned int
+
+This API should return the priority of the interrupt the PE is currently
+servicing. This must be be called only after an interrupt has already been
+acknowledged via ``plat_ic_acknowledge_interrupt``.
+
+In the case of Arm standard platforms using GIC, the *Running Priority Register*
+is read to determine the priority of the interrupt.
+
+Function: int plat_ic_is_spi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Shared Peripheral Interrupt. Shared Peripheral Interrupts are typically
+associated to system-wide peripherals, and these interrupts can target any PE in
+the system.
+
+Function: int plat_ic_is_ppi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Private Peripheral Interrupt. Private Peripheral Interrupts are typically
+associated with peripherals that are private to each PE. Interrupts from private
+peripherals target to that PE only.
+
+Function: int plat_ic_is_sgi(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+The API should return whether the interrupt ID (first parameter) is categorized
+as a Software Generated Interrupt. Software Generated Interrupts are raised by
+explicit programming by software, and are typically used in inter-PE
+communication. Secure SGIs are reserved for use by Secure world software.
+
+Function: unsigned int plat_ic_get_interrupt_active(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API should return the *active* status of the interrupt ID specified by the
+first parameter, ``id``.
+
+In case of Arm standard platforms using GIC, the implementation of the API reads
+the GIC *Set Active Register* to read and return the active status of the
+interrupt.
+
+Function: void plat_ic_enable_interrupt(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should enable the interrupt ID specified by the first parameter,
+``id``. PEs in the system are expected to receive only enabled interrupts.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before enabling interrupt, and
+then writes to GIC *Set Enable Register* to enable the interrupt.
+
+Function: void plat_ic_disable_interrupt(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should disable the interrupt ID specified by the first parameter,
+``id``. PEs in the system are not expected to receive disabled interrupts.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+writes to GIC *Clear Enable Register* to disable the interrupt, and inserts
+barrier to make memory updates visible afterwards.
+
+Function: void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Argument : unsigned int
+    Return   : void
+
+This API should set the priority of the interrupt specified by first parameter
+``id`` to the value set by the second parameter ``priority``.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+writes to GIC *Priority Register* set interrupt priority.
+
+Function: int plat_ic_has_interrupt_type(unsigned int type); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API should return whether the platform supports a given interrupt type. The
+parameter ``type`` shall be one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, or
+``INTR_TYPE_NS``.
+
+In case of Arm standard platforms using GICv3, the implementation of the API
+returns ``1`` for all interrupt types.
+
+In case of Arm standard platforms using GICv2, the API always return ``1`` for
+``INTR_TYPE_NS``. Return value for other types depends on the value of build
+option ``GICV2_G0_FOR_EL3``:
+
+- For interrupt type ``INTR_TYPE_EL3``:
+
+  - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``0``, indicating no support
+    for EL3 interrupts.
+
+  - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``1``, indicating support for
+    EL3 interrupts.
+
+- For interrupt type ``INTR_TYPE_S_EL1``:
+
+  - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``1``, indicating support for
+    Secure EL1 interrupts.
+
+  - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``0``, indicating no support
+    for Secure EL1 interrupts.
+
+Function: void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Argument : unsigned int
+    Return   : void
+
+This API should set the interrupt specified by first parameter ``id`` to the
+type specified by second parameter ``type``. The ``type`` parameter can be
+one of:
+
+- ``INTR_TYPE_NS``: interrupt is meant to be consumed by the Non-secure world.
+
+- ``INTR_TYPE_S_EL1``: interrupt is meant to be consumed by Secure EL1.
+
+- ``INTR_TYPE_EL3``: interrupt is meant to be consumed by EL3.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+writes to the GIC *Group Register* and *Group Modifier Register* (only GICv3) to
+assign the interrupt to the right group.
+
+For GICv3:
+
+- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
+
+- ``INTR_TYPE_S_EL1`` maps to Secure Group 1 interrupt.
+
+- ``INTR_TYPE_EL3`` maps to Secure Group 0 interrupt.
+
+For GICv2:
+
+- ``INTR_TYPE_NS`` maps to Group 1 interrupt.
+
+- When the build option ``GICV2_G0_FOR_EL3`` is set to ``0`` (the default),
+  ``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to
+  Group 0 interrupt.
+
+Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Argument : u_register_t
+    Return   : void
+
+This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies
+the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the
+target PE.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before raising SGI, then writes
+to appropriate *SGI Register* in order to raise the EL3 SGI.
+
+Function: void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Argument : unsigned int
+    Argument : u_register_t
+    Return   : void
+
+This API should set the routing mode of Share Peripheral Interrupt (SPI)
+specified by first parameter ``id`` to that specified by the second parameter
+``routing_mode``.
+
+The ``routing_mode`` parameter can be one of:
+
+- ``INTR_ROUTING_MODE_ANY`` means the interrupt can be routed to any PE in the
+  system. The ``mpidr`` parameter is ignored in this case.
+
+- ``INTR_ROUTING_MODE_PE`` means the interrupt is routed to the PE whose MPIDR
+  value is specified by the parameter ``mpidr``.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set
+the routing.
+
+Function: void plat_ic_set_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should set the interrupt specified by first parameter ``id`` to
+*Pending*.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+inserts barrier to make memory updates visible before setting interrupt pending,
+and writes to the GIC *Set Pending Register* to set the interrupt pending
+status.
+
+Function: void plat_ic_clear_interrupt_pending(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+This API should clear the *Pending* status of the interrupt specified by first
+parameter ``id``.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+writes to the GIC *Clear Pending Register* to clear the interrupt pending
+status, and inserts barrier to make memory updates visible afterwards.
+
+Function: unsigned int plat_ic_set_priority_mask(unsigned int id); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This API should set the priority mask (first parameter) in the interrupt
+controller such that only interrupts of higher priority than the supplied one
+may be signalled to the PE. The API should return the current priority value
+that it's overwriting.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+inserts to order memory updates before updating mask, then writes to the GIC
+*Priority Mask Register*, and make sure memory updates are visible before
+potential trigger due to mask update.
+
+Function: unsigned int plat_ic_get_interrupt_id(unsigned int raw); [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : unsigned int
+
+This API should extract and return the interrupt number from the raw value
+obtained by the acknowledging the interrupt (read using
+``plat_ic_acknowledge_interrupt()``). If the interrupt ID is invalid, this API
+should return ``INTR_ID_UNAVAILABLE``.
+
+In case of Arm standard platforms using GIC, the implementation of the API
+masks out the interrupt ID field from the acknowledged value from GIC.
+
+----
+
+*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/ras.rst b/docs/components/ras.rst
new file mode 100644
index 0000000..137c0c3
--- /dev/null
+++ b/docs/components/ras.rst
@@ -0,0 +1,252 @@
+Reliability, Availability, and Serviceability (RAS) Extensions
+==============================================================
+
+.. |EHF| replace:: Exception Handling Framework
+.. |TF-A| replace:: Trusted Firmware-A
+
+This document describes |TF-A| support for Arm Reliability, Availability, and
+Serviceability (RAS) extensions. RAS is a mandatory extension for Armv8.2 and
+later CPUs, and also an optional extension to the base Armv8.0 architecture.
+
+In conjunction with the |EHF|, support for RAS extension enables firmware-first
+paradigm for handling platform errors: exceptions resulting from errors are
+routed to and handled in EL3. Said errors are Synchronous External Abort (SEA),
+Asynchronous External Abort (signalled as SErrors), Fault Handling and Error
+Recovery interrupts.  The |EHF| document mentions various `error handling
+use-cases`__.
+
+.. __: exception-handling.rst#delegation-use-cases
+
+For the description of Arm RAS extensions, Standard Error Records, and the
+precise definition of RAS terminology, please refer to the Arm Architecture
+Reference Manual. The rest of this document assumes familiarity with
+architecture and terminology.
+
+Overview
+--------
+
+As mentioned above, the RAS support in |TF-A| enables routing to and handling of
+exceptions resulting from platform errors in EL3. It allows the platform to
+define an External Abort handler, and to register RAS nodes and interrupts. RAS
+framework also provides `helpers`__ for accessing Standard Error Records as
+introduced by the RAS extensions.
+
+.. __: `Standard Error Record helpers`_
+
+The build option ``RAS_EXTENSION`` when set to ``1`` includes the RAS in run
+time firmware; ``EL3_EXCEPTION_HANDLING`` and ``HANDLE_EA_EL3_FIRST`` must also
+be set ``1``.
+
+.. _ras-figure:
+
+.. image:: ../resources/diagrams/draw.io/ras.svg
+
+See more on `Engaging the RAS framework`_.
+
+Platform APIs
+-------------
+
+The RAS framework allows the platform to define handlers for External Abort,
+Uncontainable Errors, Double Fault, and errors rising from EL3 execution. Please
+refer to the porting guide for the `RAS platform API descriptions`__.
+
+.. __: ../getting_started/porting-guide.rst#external-abort-handling-and-ras-support
+
+Registering RAS error records
+-----------------------------
+
+RAS nodes are components in the system capable of signalling errors to PEs
+through one one of the notification mechanisms—SEAs, SErrors, or interrupts. RAS
+nodes contain one or more error records, which are registers through which the
+nodes advertise various properties of the signalled error. Arm recommends that
+error records are implemented in the Standard Error Record format. The RAS
+architecture allows for error records to be accessible via system or
+memory-mapped registers.
+
+The platform should enumerate the error records providing for each of them:
+
+-  A handler to probe error records for errors;
+-  When the probing identifies an error, a handler to handle it;
+-  For memory-mapped error record, its base address and size in KB; for a system
+   register-accessed record, the start index of the record and number of
+   continuous records from that index;
+-  Any node-specific auxiliary data.
+
+With this information supplied, when the run time firmware receives one of the
+notification mechanisms, the RAS framework can iterate through and probe error
+records for error, and invoke the appropriate handler to handle it.
+
+The RAS framework provides the macros to populate error record information. The
+macros are versioned, and the latest version as of this writing is 1. These
+macros create a structure of type ``struct err_record_info`` from its arguments,
+which are later passed to probe and error handlers.
+
+For memory-mapped error records:
+
+.. code:: c
+
+    ERR_RECORD_MEMMAP_V1(base_addr, size_num_k, probe, handler, aux)
+
+And, for system register ones:
+
+.. code:: c
+
+    ERR_RECORD_SYSREG_V1(idx_start, num_idx, probe, handler, aux)
+
+The probe handler must have the following prototype:
+
+.. code:: c
+
+    typedef int (*err_record_probe_t)(const struct err_record_info *info,
+                    int *probe_data);
+
+The probe handler must return a non-zero value if an error was detected, or 0
+otherwise. The ``probe_data`` output parameter can be used to pass any useful
+information resulting from probe to the error handler (see `below`__). For
+example, it could return the index of the record.
+
+.. __: `Standard Error Record helpers`_
+
+The error handler must have the following prototype:
+
+.. code:: c
+
+    typedef int (*err_record_handler_t)(const struct err_record_info *info,
+               int probe_data, const struct err_handler_data *const data);
+
+The ``data`` constant parameter describes the various properties of the error,
+including the reason for the error, exception syndrome, and also ``flags``,
+``cookie``, and ``handle`` parameters from the `top-level exception handler`__.
+
+.. __: interrupt-framework-design.rst#el3-interrupts
+
+The platform is expected populate an array using the macros above, and register
+the it with the RAS framework using the macro ``REGISTER_ERR_RECORD_INFO()``,
+passing it the name of the array describing the records. Note that the macro
+must be used in the same file where the array is defined.
+
+Standard Error Record helpers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The |TF-A| RAS framework provides probe handlers for Standard Error Records, for
+both memory-mapped and System Register accesses:
+
+.. code:: c
+
+    int ras_err_ser_probe_memmap(const struct err_record_info *info,
+                int *probe_data);
+
+    int ras_err_ser_probe_sysreg(const struct err_record_info *info,
+                int *probe_data);
+
+When the platform enumerates error records, for those records in the Standard
+Error Record format, these helpers maybe used instead of rolling out their own.
+Both helpers above:
+
+-  Return non-zero value when an error is detected in a Standard Error Record;
+-  Set ``probe_data`` to the index of the error record upon detecting an error.
+
+Registering RAS interrupts
+--------------------------
+
+RAS nodes can signal errors to the PE by raising Fault Handling and/or Error
+Recovery interrupts. For the firmware-first handling paradigm for interrupts to
+work, the platform must setup and register with |EHF|. See `Interaction with
+Exception Handling Framework`_.
+
+For each RAS interrupt, the platform has to provide structure of type ``struct
+ras_interrupt``:
+
+-  Interrupt number;
+-  The associated error record information (pointer to the corresponding
+   ``struct err_record_info``);
+-  Optionally, a cookie.
+
+The platform is expected to define an array of ``struct ras_interrupt``, and
+register it with the RAS framework using the macro
+``REGISTER_RAS_INTERRUPTS()``, passing it the name of the array. Note that the
+macro must be used in the same file where the array is defined.
+
+The array of ``struct ras_interrupt`` must be sorted in the increasing order of
+interrupt number. This allows for fast look of handlers in order to service RAS
+interrupts.
+
+Double-fault handling
+---------------------
+
+A Double Fault condition arises when an error is signalled to the PE while
+handling of a previously signalled error is still underway. When a Double Fault
+condition arises, the Arm RAS extensions only require for handler to perform
+orderly shutdown of the system, as recovery may be impossible.
+
+The RAS extensions part of Armv8.4 introduced new architectural features to deal
+with Double Fault conditions, specifically, the introduction of ``NMEA`` and
+``EASE`` bits to ``SCR_EL3`` register. These were introduced to assist EL3
+software which runs part of its entry/exit routines with exceptions momentarily
+masked—meaning, in such systems, External Aborts/SErrors are not immediately
+handled when they occur, but only after the exceptions are unmasked again.
+
+|TF-A|, for legacy reasons, executes entire EL3 with all exceptions unmasked.
+This means that all exceptions routed to EL3 are handled immediately. |TF-A|
+thus is able to detect a Double Fault conditions in software, without needing
+the intended advantages of Armv8.4 Double Fault architecture extensions.
+
+Double faults are fatal, and terminate at the platform double fault handler, and
+doesn't return.
+
+Engaging the RAS framework
+--------------------------
+
+Enabling RAS support is a platform choice constructed from three distinct, but
+related, build options:
+
+-  ``RAS_EXTENSION=1`` includes the RAS framework in the run time firmware;
+
+-  ``EL3_EXCEPTION_HANDLING=1`` enables handling of exceptions at EL3. See
+   `Interaction with Exception Handling Framework`_;
+
+-  ``HANDLE_EA_EL3_FIRST=1`` enables routing of External Aborts and SErrors to
+   EL3.
+
+The RAS support in |TF-A| introduces a default implementation of
+``plat_ea_handler``, the External Abort handler in EL3. When ``RAS_EXTENSION``
+is set to ``1``, it'll first call ``ras_ea_handler()`` function, which is the
+top-level RAS exception handler. ``ras_ea_handler`` is responsible for iterating
+to through platform-supplied error records, probe them, and when an error is
+identified, look up and invoke the corresponding error handler.
+
+Note that, if the platform chooses to override the ``plat_ea_handler`` function
+and intend to use the RAS framework, it must explicitly call
+``ras_ea_handler()`` from within.
+
+Similarly, for RAS interrupts, the framework defines
+``ras_interrupt_handler()``. The RAS framework arranges for it to be invoked
+when  a RAS interrupt taken at EL3. The function bisects the platform-supplied
+sorted array of interrupts to look up the error record information associated
+with the interrupt number. That error handler for that record is then invoked to
+handle the error.
+
+Interaction with Exception Handling Framework
+---------------------------------------------
+
+As mentioned in earlier sections, RAS framework interacts with the |EHF| to
+arbitrate handling of RAS exceptions with others that are routed to EL3. This
+means that the platform must partition a `priority level`__ for handling RAS
+exceptions. The platform must then define the macro ``PLAT_RAS_PRI`` to the
+priority level used for RAS exceptions. Platforms would typically want to
+allocate the highest secure priority for RAS handling.
+
+.. __: exception-handling.rst#partitioning-priority-levels
+
+Handling of both `interrupt`__ and `non-interrupt`__ exceptions follow the
+sequences outlined in the |EHF| documentation. I.e., for interrupts, the
+priority management is implicit; but for non-interrupt exceptions, they're
+explicit using `EHF APIs`__.
+
+.. __: exception-handling.rst#interrupt-flow
+.. __: exception-handling.rst#non-interrupt-flow
+.. __: exception-handling.rst#activating-and-deactivating-priorities
+
+----
+
+*Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/components/romlib-design.rst b/docs/components/romlib-design.rst
new file mode 100644
index 0000000..d8bc89c
--- /dev/null
+++ b/docs/components/romlib-design.rst
@@ -0,0 +1,134 @@
+Library at ROM
+==============
+
+This document provides an overview of the "library at ROM" implementation in
+Trusted Firmware-A (TF-A).
+
+Introduction
+~~~~~~~~~~~~
+
+The "library at ROM" feature allows platforms to build a library of functions to
+be placed in ROM. This reduces SRAM usage by utilising the available space in
+ROM. The "library at ROM" contains a jump table with the list of functions that
+are placed in ROM. The capabilities of the "library at ROM" are:
+
+1. Functions can be from one or several libraries.
+
+2. Functions can be patched after they have been programmed into ROM.
+
+3. Platform-specific libraries can be placed in ROM.
+
+4. Functions can be accessed by one or more BL images.
+
+Index file
+~~~~~~~~~~
+
+.. image:: ../resources/diagrams/romlib_design.png
+    :width: 600
+
+Library at ROM is described by an index file with the list of functions to be
+placed in ROM. The index file is platform specific and its format is:
+
+::
+
+    lib function    [patch]
+
+    lib      -- Name of the library the function belongs to
+    function -- Name of the function to be placed in library at ROM
+    [patch]  -- Option to patch the function
+
+It is also possible to insert reserved spaces in the list by using the keyword
+"reserved" rather than the "lib" and "function" names as shown below:
+
+::
+
+    reserved
+
+The reserved spaces can be used to add more functions in the future without
+affecting the order and location of functions already existing in the jump
+table. Also, for additional flexibility and modularity, the index file can
+include other index files.
+
+For an index file example, refer to ``lib/romlib/jmptbl.i``.
+
+Wrapper functions
+~~~~~~~~~~~~~~~~~
+
+.. image:: ../resources/diagrams/romlib_wrapper.png
+    :width: 600
+
+When invoking a function of the "library at ROM", the calling sequence is as
+follows:
+
+BL image --> wrapper function --> jump table entry --> library at ROM
+
+The index file is used to create a jump table which is placed in ROM. Then, the
+wrappers refer to the jump table to call the "library at ROM" functions. The
+wrappers essentially contain a branch instruction to the jump table entry
+corresponding to the original function. Finally, the original function in the BL
+image(s) is replaced with the wrapper function.
+
+The "library at ROM" contains a necessary init function that initialises the
+global variables defined by the functions inside "library at ROM".
+
+Script
+~~~~~~
+
+There is a ``romlib_generate.py`` Python script that generates the necessary
+files for the "library at ROM" to work. It implements multiple functions:
+
+1. ``romlib_generate.py gentbl [args]`` - Generates the jump table by parsing
+   the index file.
+
+2. ``romlib_generator.py genvar [args]`` - Generates the jump table global
+   variable (**not** the jump table itself) with the absolute address in ROM.
+   This global variable is, basically, a pointer to the jump table.
+
+3. ``romlib_generator.py genwrappers [args]`` - Generates a wrapper function for
+   each entry in the index file except for the ones that contain the keyword
+   ``patch``. The generated wrapper file is called ``<fn_name>.s``.
+
+4. ``romlib_generator.py pre [args]`` - Preprocesses the index file which means
+   it resolves all the include commands in the file recursively. It can also
+   generate a dependency file of the included index files which can be directly
+   used in makefiles.
+
+Each ``romlib_generate.py`` function has its own manual which is accessible by
+runing ``romlib_generator.py [function] --help``.
+
+``romlib_generate.py`` requires Python 3 environment.
+
+
+Patching of functions in library at ROM
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``romlib_generator.py genwrappers`` does not generate wrappers for the
+entries in the index file that contain the keyword ``patch``. Thus, it allows
+calling the function from the actual library by breaking the link to the
+"library at ROM" version of this function.
+
+The calling sequence for a patched function is as follows:
+
+BL image --> function
+
+Build library at ROM
+~~~~~~~~~~~~~~~~~~~~~
+
+The environment variable ``CROSS_COMPILE`` must be set as per the user guide.
+In the below example the usage of ROMLIB together with mbed TLS is demonstrated
+to showcase the benefits of library at ROM - it's not mandatory.
+
+.. code:: shell
+
+    make PLAT=fvp                                                   \
+    MBEDTLS_DIR=</path/to/mbedtls/>                                 \
+    TRUSTED_BOARD_BOOT=1 GENERATE_COT=1                             \
+    ARM_ROTPK_LOCATION=devel_rsa                                    \
+    ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem        \
+    BL33=</path/to/bl33.bin>                                        \
+    USE_ROMLIB=1                                                    \
+    all fip
+
+--------------
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/components/sdei.rst b/docs/components/sdei.rst
new file mode 100644
index 0000000..2a777b3
--- /dev/null
+++ b/docs/components/sdei.rst
@@ -0,0 +1,373 @@
+SDEI: Software Delegated Exception Interface
+============================================
+
+This document provides an overview of the SDEI dispatcher implementation in
+Trusted Firmware-A (TF-A).
+
+Introduction
+------------
+
+`Software Delegated Exception Interface`_ (SDEI) is an Arm specification for
+Non-secure world to register handlers with firmware to receive notifications
+about system events. Firmware will first receive the system events by way of
+asynchronous exceptions and, in response, arranges for the registered handler to
+execute in the Non-secure EL.
+
+Normal world software that interacts with the SDEI dispatcher (makes SDEI
+requests and receives notifications) is referred to as the *SDEI Client*. A
+client receives the event notification at the registered handler even when it
+was executing with exceptions masked. The list of SDEI events available to the
+client are specific to the platform [#std-event]_. See also `Determining client
+EL`_.
+
+.. _general SDEI dispatch:
+
+The following figure depicts a general sequence involving SDEI client executing
+at EL2 and an event dispatch resulting from the triggering of a bound interrupt.
+A commentary is provided below:
+
+.. uml:: ../resources/diagrams/plantuml/sdei_general.puml
+
+As part of initialisation, the SDEI client binds a Non-secure interrupt [1], and
+the SDEI dispatcher returns a platform dynamic event number [2]. The client then
+registers a handler for that event [3], enables the event [5], and unmasks all
+events on the current PE [7]. This sequence is typical of an SDEI client, but it
+may involve additional SDEI calls.
+
+At a later point in time, when the bound interrupt triggers [9], it's trapped to
+EL3. The interrupt is handed over to the SDEI dispatcher, which then arranges to
+execute the registered handler [10]. The client terminates its execution with
+``SDEI_EVENT_COMPLETE`` [11], following which the dispatcher resumes the
+original EL2 execution [13]. Note that the SDEI interrupt remains active until
+the client handler completes, at which point EL3 does EOI [12].
+
+Other than events bound to interrupts, as depicted in the sequence above, SDEI
+events can be explicitly dispatched in response to other exceptions, for
+example, upon receiving an *SError* or *Synchronous External Abort*. See
+`Explicit dispatch of events`_.
+
+The remainder of this document only discusses the design and implementation of
+SDEI dispatcher in TF-A, and assumes that the reader is familiar with the SDEI
+specification, the interfaces, and their requirements.
+
+.. [#std-event] Except event 0, which is defined by the SDEI specification as a
+                standard event.
+
+Defining events
+---------------
+
+A platform choosing to include the SDEI dispatcher must also define the events
+available on the platform, along with their attributes.
+
+The platform is expected to provide two arrays of event descriptors: one for
+private events, and another for shared events. The SDEI dispatcher provides
+``SDEI_PRIVATE_EVENT()`` and ``SDEI_SHARED_EVENT()`` macros to populate the
+event descriptors. Both macros take 3 arguments:
+
+-  The event number: this must be a positive 32-bit integer.
+
+-  For an event that has a backing interrupt, the interrupt number the event is
+   bound to:
+
+   - If it's not applicable to an event, this shall be left as ``0``.
+
+   - If the event is dynamic, this should be specified as ``SDEI_DYN_IRQ``.
+
+-  A bit map of `Event flags`_.
+
+To define event 0, the macro ``SDEI_DEFINE_EVENT_0()`` should be used. This
+macro takes only one parameter: an SGI number to signal other PEs.
+
+To define an event that's meant to be `explicitly dispatched`__ (i.e., not as a
+result of receiving an SDEI interrupt), the macro ``SDEI_EXPLICIT_EVENT()``
+should be used. It accepts two parameters:
+
+.. __: `Explicit dispatch of events`_
+
+-  The event number (as above);
+
+-  Event priority: ``SDEI_MAPF_CRITICAL`` or ``SDEI_MAPF_NORMAL``, as described
+   below.
+
+Once the event descriptor arrays are defined, they should be exported to the
+SDEI dispatcher using the ``REGISTER_SDEI_MAP()`` macro, passing it the pointers
+to the private and shared event descriptor arrays, respectively. Note that the
+``REGISTER_SDEI_MAP()`` macro must be used in the same file where the arrays are
+defined.
+
+Regarding event descriptors:
+
+-  For Event 0:
+
+   - There must be exactly one descriptor in the private array, and none in the
+     shared array.
+
+   - The event should be defined using ``SDEI_DEFINE_EVENT_0()``.
+
+   - Must be bound to a Secure SGI on the platform.
+
+-  Explicit events should only be used in the private array.
+
+-  Statically bound shared and private interrupts must be bound to shared and
+   private interrupts on the platform, respectively. See the section on
+   `interrupt configuration`__.
+
+   .. __: `Configuration within Exception Handling Framework`_
+
+-  Both arrays should be one-dimensional. The ``REGISTER_SDEI_MAP()`` macro
+   takes care of replicating private events for each PE on the platform.
+
+-  Both arrays must be sorted in the increasing order of event number.
+
+The SDEI specification doesn't have provisions for discovery of available events
+on the platform. The list of events made available to the client, along with
+their semantics, have to be communicated out of band; for example, through
+Device Trees or firmware configuration tables.
+
+See also `Event definition example`_.
+
+Event flags
+~~~~~~~~~~~
+
+Event flags describe the properties of the event. They are bit maps that can be
+``OR``\ ed to form parameters to macros that `define events`__.
+
+.. __: `Defining events`_
+
+-  ``SDEI_MAPF_DYNAMIC``: Marks the event as dynamic. Dynamic events can be
+   bound to (or released from) any Non-secure interrupt at runtime via the
+   ``SDEI_INTERRUPT_BIND`` and ``SDEI_INTERRUPT_RELEASE`` calls.
+
+-  ``SDEI_MAPF_BOUND``: Marks the event as statically bound to an interrupt.
+   These events cannot be re-bound at runtime.
+
+-  ``SDEI_MAPF_NORMAL``: Marks the event as having *Normal* priority. This is
+   the default priority.
+
+-  ``SDEI_MAPF_CRITICAL``: Marks the event as having *Critical* priority.
+
+Event definition example
+------------------------
+
+.. code:: c
+
+   static sdei_ev_map_t plat_private_sdei[] = {
+        /* Event 0 definition */
+        SDEI_DEFINE_EVENT_0(8),
+
+        /* PPI */
+        SDEI_PRIVATE_EVENT(8, 23, SDEI_MAPF_BOUND),
+
+        /* Dynamic private events */
+        SDEI_PRIVATE_EVENT(100, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+        SDEI_PRIVATE_EVENT(101, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+
+        /* Events for explicit dispatch */
+        SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_NORMAL);
+        SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_CRITICAL);
+   };
+
+   /* Shared event mappings */
+   static sdei_ev_map_t plat_shared_sdei[] = {
+        SDEI_SHARED_EVENT(804, 0, SDEI_MAPF_DYNAMIC),
+
+        /* Dynamic shared events */
+        SDEI_SHARED_EVENT(3000, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
+        SDEI_SHARED_EVENT(3001, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+   };
+
+   /* Export SDEI events */
+   REGISTER_SDEI_MAP(plat_private_sdei, plat_shared_sdei);
+
+Configuration within Exception Handling Framework
+-------------------------------------------------
+
+The SDEI dispatcher functions alongside the Exception Handling Framework. This
+means that the platform must assign priorities to both Normal and Critical SDEI
+interrupts for the platform:
+
+-  Install priority descriptors for Normal and Critical SDEI interrupts.
+
+-  For those interrupts that are statically bound (i.e. events defined as having
+   the ``SDEI_MAPF_BOUND`` property), enumerate their properties for the GIC
+   driver to configure interrupts accordingly.
+
+   The interrupts must be configured to target EL3. This means that they should
+   be configured as *Group 0*.  Additionally, on GICv2 systems, the build option
+   ``GICV2_G0_FOR_EL3`` must be set to ``1``.
+
+See also `SDEI porting requirements`_.
+
+Determining client EL
+---------------------
+
+The SDEI specification requires that the *physical* SDEI client executes in the
+highest Non-secure EL implemented on the system. This means that the dispatcher
+will only allow SDEI calls to be made from:
+
+-  EL2, if EL2 is implemented. The Hypervisor is expected to implement a
+   *virtual* SDEI dispatcher to support SDEI clients in Guest Operating Systems
+   executing in Non-secure EL1.
+
+-  Non-secure EL1, if EL2 is not implemented or disabled.
+
+See the function ``sdei_client_el()`` in ``sdei_private.h``.
+
+Explicit dispatch of events
+---------------------------
+
+Typically, an SDEI event dispatch is caused by the PE receiving interrupts that
+are bound to an SDEI event. However, there are cases where the Secure world
+requires dispatch of an SDEI event as a direct or indirect result of a past
+activity, such as receiving a Secure interrupt or an exception.
+
+The SDEI dispatcher implementation provides ``sdei_dispatch_event()`` API for
+this purpose. The API has the following signature:
+
+.. code:: c
+
+        int sdei_dispatch_event(int ev_num);
+
+The parameter ``ev_num`` is the event number to dispatch. The API returns ``0``
+on success, or ``-1`` on failure.
+
+The following figure depicts a scenario involving explicit dispatch of SDEI
+event. A commentary is provided below:
+
+.. uml:: ../resources/diagrams/plantuml/sdei_explicit_dispatch.puml
+
+As part of initialisation, the SDEI client registers a handler for a platform
+event [1], enables the event [3], and unmasks the current PE [5]. Note that,
+unlike in `general SDEI dispatch`_, this doesn't involve interrupt binding, as
+bound or dynamic events can't be explicitly dispatched (see the section below).
+
+At a later point in time, a critical event [#critical-event]_ is trapped into
+EL3 [7]. EL3 performs a first-level triage of the event, and a RAS component
+assumes further handling [8]. The dispatch completes, but intends to involve
+Non-secure world in further handling, and therefore decides to explicitly
+dispatch an event [10] (which the client had already registered for [1]). The
+rest of the sequence is similar to that in the `general SDEI dispatch`_: the
+requested event is dispatched to the client (assuming all the conditions are
+met), and when the handler completes, the preempted execution resumes.
+
+.. [#critical-event] Examples of critical event are *SError*, *Synchronous
+                     External Abort*, *Fault Handling interrupt*, or *Error
+                     Recovery interrupt* from one of RAS nodes in the system.
+
+Conditions for event dispatch
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+All of the following requirements must be met for the API to return ``0`` and
+event to be dispatched:
+
+-  SDEI events must be unmasked on the PE. I.e. the client must have called
+   ``PE_UNMASK`` beforehand.
+
+-  Event 0 can't be dispatched.
+
+-  The event must be declared using the ``SDEI_EXPLICIT_EVENT()`` macro
+   described above.
+
+-  The event must be private to the PE.
+
+-  The event must have been registered for and enabled.
+
+-  A dispatch for the same event must not be outstanding. I.e. it hasn't already
+   been dispatched and is yet to be completed.
+
+-  The priority of the event (either Critical or Normal, as configured by the
+   platform at build-time) shouldn't cause priority inversion. This means:
+
+   -  If it's of Normal priority, neither Normal nor Critical priority dispatch
+      must be outstanding on the PE.
+
+   -  If it's of a Critical priority, no Critical priority dispatch must be
+      outstanding on the PE.
+
+Further, the caller should be aware of the following assumptions made by the
+dispatcher:
+
+-  The caller of the API is a component running in EL3; for example, a RAS
+   driver.
+
+-  The requested dispatch will be permitted by the Exception Handling Framework.
+   I.e. the caller must make sure that the requested dispatch has sufficient
+   priority so as not to cause priority level inversion within Exception
+   Handling Framework.
+
+-  The caller must be prepared for the SDEI dispatcher to restore the Non-secure
+   context, and mark that the active context.
+
+-  The call will block until the SDEI client completes the event (i.e. when the
+   client calls either ``SDEI_EVENT_COMPLETE`` or ``SDEI_COMPLETE_AND_RESUME``).
+
+-  The caller must be prepared for this API to return failure and handle
+   accordingly.
+
+Porting requirements
+--------------------
+
+The porting requirements of the SDEI dispatcher are outlined in the `porting
+guide`__.
+
+.. __: `SDEI porting requirements`_
+
+Note on writing SDEI event handlers
+-----------------------------------
+
+*This section pertains to SDEI event handlers in general, not just when using
+the TF-A SDEI dispatcher.*
+
+The SDEI specification requires that event handlers preserve the contents of all
+registers except ``x0`` to ``x17``. This has significance if event handler is
+written in C: compilers typically adjust the stack frame at the beginning and
+end of C functions. For example, AArch64 GCC typically produces the following
+function prologue and epilogue:
+
+::
+
+        c_event_handler:
+                stp     x29, x30, [sp,#-32]!
+                mov     x29, sp
+
+                ...
+
+                bl      ...
+
+                ...
+
+                ldp     x29, x30, [sp],#32
+                ret
+
+The register ``x29`` is used as frame pointer in the prologue. Because neither a
+valid ``SDEI_EVENT_COMPLETE`` nor ``SDEI_EVENT_COMPLETE_AND_RESUME`` calls
+return to the handler, the epilogue never gets executed, and registers ``x29``
+and ``x30`` (in the case above) are inadvertently corrupted. This violates the
+SDEI specification, and the normal execution thereafter will result in
+unexpected behaviour.
+
+To work this around, it's advised that the top-level event handlers are
+implemented in assembly, following a similar pattern as below:
+
+::
+
+        asm_event_handler:
+                /* Save link register whilst maintaining stack alignment */
+                stp     xzr, x30, [sp, #-16]!
+                bl      c_event_handler
+
+                /* Restore link register */
+                ldp     xzr, x30, [sp], #16
+
+                /* Complete call */
+                ldr     x0, =SDEI_EVENT_COMPLETE
+                smc     #0
+                b       .
+
+----
+
+*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _SDEI porting requirements: ../getting_started/porting-guide.rst#sdei-porting-requirements
+.. _Software Delegated Exception Interface: `SDEI specification`_
diff --git a/docs/components/secure-partition-manager-design.rst b/docs/components/secure-partition-manager-design.rst
new file mode 100644
index 0000000..de0792d
--- /dev/null
+++ b/docs/components/secure-partition-manager-design.rst
@@ -0,0 +1,818 @@
+Secure Partition Manager
+************************
+
+Background
+==========
+
+In some market segments that primarily deal with client-side devices like mobile
+phones, tablets, STBs and embedded devices, a Trusted OS instantiates trusted
+applications to provide security services like DRM, secure payment and
+authentication. The Global Platform TEE Client API specification defines the API
+used by Non-secure world applications to access these services. A Trusted OS
+fulfils the requirements of a security service as described above.
+
+Management services are typically implemented at the highest level of privilege
+in the system, i.e. EL3 in Trusted Firmware-A (TF-A). The service requirements are
+fulfilled by the execution environment provided by TF-A.
+
+The following diagram illustrates the corresponding software stack:
+
+|Image 1|
+
+In other market segments that primarily deal with server-side devices (e.g. data
+centres and enterprise servers) the secure software stack typically does not
+include a Global Platform Trusted OS. Security functions are accessed through
+other interfaces (e.g. ACPI TCG TPM interface, UEFI runtime variable service).
+
+Placement of management and security functions with diverse requirements in a
+privileged Exception Level (i.e. EL3 or S-EL1) makes security auditing of
+firmware more difficult and does not allow isolation of unrelated services from
+each other either.
+
+Introduction
+============
+
+A **Secure Partition** is a software execution environment instantiated in
+S-EL0 that can be used to implement simple management and security services.
+Since S-EL0 is an unprivileged Exception Level, a Secure Partition relies on
+privileged firmware (i.e. TF-A) to be granted access to system and processor
+resources. Essentially, it is a software sandbox in the Secure world that runs
+under the control of privileged software, provides one or more services and
+accesses the following system resources:
+
+- Memory and device regions in the system address map.
+
+- PE system registers.
+
+- A range of synchronous exceptions (e.g. SMC function identifiers).
+
+Note that currently TF-A only supports handling one Secure Partition.
+
+A Secure Partition enables TF-A to implement only the essential secure
+services in EL3 and instantiate the rest in a partition in S-EL0.
+Furthermore, multiple Secure Partitions can be used to isolate unrelated
+services from each other.
+
+The following diagram illustrates the place of a Secure Partition in a typical
+Armv8-A software stack. A single or multiple Secure Partitions provide secure
+services to software components in the Non-secure world and other Secure
+Partitions.
+
+|Image 2|
+
+The TF-A build system is responsible for including the Secure Partition image
+in the FIP. During boot, BL2 includes support to authenticate and load the
+Secure Partition image. A BL31 component called **Secure Partition Manager
+(SPM)** is responsible for managing the partition. This is semantically
+similar to a hypervisor managing a virtual machine.
+
+The SPM is responsible for the following actions during boot:
+
+- Allocate resources requested by the Secure Partition.
+
+- Perform architectural and system setup required by the Secure Partition to
+  fulfil a service request.
+
+- Implement a standard interface that is used for initialising a Secure
+  Partition.
+
+The SPM is responsible for the following actions during runtime:
+
+- Implement a standard interface that is used by a Secure Partition to fulfil
+  service requests.
+
+- Implement a standard interface that is used by the Non-secure world for
+  accessing the services exported by a Secure Partition. A service can be
+  invoked through a SMC.
+
+Alternatively, a partition can be viewed as a thread of execution running under
+the control of the SPM. Hence common programming concepts described below are
+applicable to a partition.
+
+Description
+===========
+
+The previous section introduced some general aspects of the software
+architecture of a Secure Partition. This section describes the specific choices
+made in the current implementation of this software architecture. Subsequent
+revisions of the implementation will include a richer set of features that
+enable a more flexible architecture.
+
+Building TF-A with Secure Partition support
+-------------------------------------------
+
+SPM is supported on the Arm FVP exclusively at the moment. The current
+implementation supports inclusion of only a single Secure Partition in which a
+service always runs to completion (e.g. the requested services cannot be
+preempted to give control back to the Normal world).
+
+It is not currently possible for BL31 to integrate SPM support and a Secure
+Payload Dispatcher (SPD) at the same time; they are mutually exclusive. In the
+SPM bootflow, a Secure Partition image executing at S-EL0 replaces the Secure
+Payload image executing at S-EL1 (e.g. a Trusted OS). Both are referred to as
+BL32.
+
+A working prototype of a SP has been implemented by re-purposing the EDK2 code
+and tools, leveraging the concept of the *Standalone Management Mode (MM)* in
+the UEFI specification (see the PI v1.6 Volume 4: Management Mode Core
+Interface). This will be referred to as the *Standalone MM Secure Partition* in
+the rest of this document.
+
+To enable SPM support in TF-A, the source code must be compiled with the build
+flag ``ENABLE_SPM=1``, along with ``EL3_EXCEPTION_HANDLING=1``. On Arm
+platforms the build option ``ARM_BL31_IN_DRAM`` must be set to 1. Also, the
+location of the binary that contains the BL32 image
+(``BL32=path/to/image.bin``) must be specified.
+
+First, build the Standalone MM Secure Partition. To build it, refer to the
+`instructions in the EDK2 repository`_.
+
+Then build TF-A with SPM support and include the Standalone MM Secure Partition
+image in the FIP:
+
+.. code:: shell
+
+    BL32=path/to/standalone/mm/sp BL33=path/to/bl33.bin \
+    make PLAT=fvp ENABLE_SPM=1 ARM_BL31_IN_DRAM=1 fip all
+
+Describing Secure Partition resources
+-------------------------------------
+
+TF-A exports a porting interface that enables a platform to specify the system
+resources required by the Secure Partition. Some instructions are given below.
+However, this interface is under development and it may change as new features
+are implemented.
+
+- A Secure Partition is considered a BL32 image, so the same defines that apply
+  to BL32 images apply to a Secure Partition: ``BL32_BASE`` and ``BL32_LIMIT``.
+
+- The following defines are needed to allocate space for the translation tables
+  used by the Secure Partition: ``PLAT_SP_IMAGE_MMAP_REGIONS`` and
+  ``PLAT_SP_IMAGE_MAX_XLAT_TABLES``.
+
+- The functions ``plat_get_secure_partition_mmap()`` and
+  ``plat_get_secure_partition_boot_info()`` have to be implemented. The file
+  ``plat/arm/board/fvp/fvp_common.c`` can be used as an example. It uses the
+  defines in ``include/plat/arm/common/arm_spm_def.h``.
+
+  - ``plat_get_secure_partition_mmap()`` returns an array of mmap regions that
+    describe the memory regions that the SPM needs to allocate for a Secure
+    Partition.
+
+  - ``plat_get_secure_partition_boot_info()`` returns a
+    ``secure_partition_boot_info_t`` struct that is populated by the platform
+    with information about the memory map of the Secure Partition.
+
+For an example of all the changes in context, you may refer to commit
+``e29efeb1b4``, in which the port for FVP was introduced.
+
+Accessing Secure Partition services
+-----------------------------------
+
+The `SMC Calling Convention`_ (*Arm DEN 0028B*) describes SMCs as a conduit for
+accessing services implemented in the Secure world. The ``MM_COMMUNICATE``
+interface defined in the `Management Mode Interface Specification`_ (*Arm DEN
+0060A*) is used to invoke a Secure Partition service as a Fast Call.
+
+The mechanism used to identify a service within the partition depends on the
+service implementation. It is assumed that the caller of the service will be
+able to discover this mechanism through standard platform discovery mechanisms
+like ACPI and Device Trees. For example, *Volume 4: Platform Initialisation
+Specification v1.6. Management Mode Core Interface* specifies that a GUID is
+used to identify a management mode service. A client populates the GUID in the
+``EFI_MM_COMMUNICATE_HEADER``. The header is populated in the communication
+buffer shared with the Secure Partition.
+
+A Fast Call appears to be atomic from the perspective of the caller and returns
+when the requested operation has completed. A service invoked through the
+``MM_COMMUNICATE`` SMC will run to completion in the partition on a given CPU.
+The SPM is responsible for guaranteeing this behaviour. This means that there
+can only be a single outstanding Fast Call in a partition on a given CPU.
+
+Exchanging data with the Secure Partition
+-----------------------------------------
+
+The exchange of data between the Non-secure world and the partition takes place
+through a shared memory region. The location of data in the shared memory area
+is passed as a parameter to the ``MM_COMMUNICATE`` SMC. The shared memory area
+is statically allocated by the SPM and is expected to be either implicitly known
+to the Non-secure world or discovered through a platform discovery mechanism
+e.g. ACPI table or device tree. It is possible for the Non-secure world to
+exchange data with a partition only if it has been populated in this shared
+memory area. The shared memory area is implemented as per the guidelines
+specified in Section 3.2.3 of the `Management Mode Interface Specification`_
+(*Arm DEN 0060A*).
+
+The format of data structures used to encapsulate data in the shared memory is
+agreed between the Non-secure world and the Secure Partition. For example, in
+the `Management Mode Interface specification`_ (*Arm DEN 0060A*), Section 4
+describes that the communication buffer shared between the Non-secure world and
+the Management Mode (MM) in the Secure world must be of the type
+``EFI_MM_COMMUNICATE_HEADER``. This data structure is defined in *Volume 4:
+Platform Initialisation Specification v1.6. Management Mode Core Interface*.
+Any caller of a MM service will have to use the ``EFI_MM_COMMUNICATE_HEADER``
+data structure.
+
+Runtime model of the Secure Partition
+=====================================
+
+This section describes how the Secure Partition interfaces with the SPM.
+
+Interface with SPM
+------------------
+
+In order to instantiate one or more secure services in the Secure Partition in
+S-EL0, the SPM should define the following types of interfaces:
+
+- Interfaces that enable access to privileged operations from S-EL0. These
+  operations typically require access to system resources that are either shared
+  amongst multiple software components in the Secure world or cannot be directly
+  accessed from an unprivileged Exception Level.
+
+- Interfaces that establish the control path between the SPM and the Secure
+  Partition.
+
+This section describes the APIs currently exported by the SPM that enable a
+Secure Partition to initialise itself and export its services in S-EL0. These
+interfaces are not accessible from the Non-secure world.
+
+Conduit
+^^^^^^^
+
+The `SMC Calling Convention`_ (*Arm DEN 0028B*) specification describes the SMC
+and HVC conduits for accessing firmware services and their availability
+depending on the implemented Exception levels. In S-EL0, the Supervisor Call
+exception (SVC) is the only architectural mechanism available for unprivileged
+software to make a request for an operation implemented in privileged software.
+Hence, the SVC conduit must be used by the Secure Partition to access interfaces
+implemented by the SPM.
+
+A SVC causes an exception to be taken to S-EL1. TF-A assumes ownership of S-EL1
+and installs a simple exception vector table in S-EL1 that relays a SVC request
+from a Secure Partition as a SMC request to the SPM in EL3. Upon servicing the
+SMC request, Trusted Firmware-A returns control directly to S-EL0 through an
+ERET instruction.
+
+Calling conventions
+^^^^^^^^^^^^^^^^^^^
+
+The `SMC Calling Convention`_ (*Arm DEN 0028B*) specification describes the
+32-bit and 64-bit calling conventions for the SMC and HVC conduits. The SVC
+conduit introduces the concept of SVC32 and SVC64 calling conventions. The SVC32
+and SVC64 calling conventions are equivalent to the 32-bit (SMC32) and the
+64-bit (SMC64) calling conventions respectively.
+
+Communication initiated by SPM
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A service request is initiated from the SPM through an exception return
+instruction (ERET) to S-EL0. Later, the Secure Partition issues an SVC
+instruction to signal completion of the request. Some example use cases are
+given below:
+
+- A request to initialise the Secure Partition during system boot.
+
+- A request to handle a runtime service request.
+
+Communication initiated by Secure Partition
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A request is initiated from the Secure Partition by executing a SVC instruction.
+An ERET instruction is used by TF-A to return to S-EL0 with the result of the
+request.
+
+For instance, a request to perform privileged operations on behalf of a
+partition (e.g.  management of memory attributes in the translation tables for
+the Secure EL1&0 translation regime).
+
+Interfaces
+^^^^^^^^^^
+
+The current implementation reserves function IDs for Fast Calls in the Standard
+Secure Service calls range (see `SMC Calling Convention`_ (*Arm DEN 0028B*)
+specification) for each API exported by the SPM. This section defines the
+function prototypes for each function ID. The function IDs specify whether one
+or both of the SVC32 and SVC64 calling conventions can be used to invoke the
+corresponding interface.
+
+Secure Partition Event Management
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The Secure Partition provides an Event Management interface that is used by the
+SPM to delegate service requests to the Secure Partition. The interface also
+allows the Secure Partition to:
+
+- Register with the SPM a service that it provides.
+- Indicate completion of a service request delegated by the SPM
+
+Miscellaneous interfaces
+------------------------
+
+``SPM_VERSION_AARCH32``
+^^^^^^^^^^^^^^^^^^^^^^^
+
+- Description
+
+  Returns the version of the interface exported by SPM.
+
+- Parameters
+
+  - **uint32** - Function ID
+
+    - SVC32 Version: **0x84000060**
+
+- Return parameters
+
+  - **int32** - Status
+
+    On success, the format of the value is as follows:
+
+    - Bit [31]: Must be 0
+    - Bits [30:16]: Major Version. Must be 0 for this revision of the SPM
+      interface.
+    - Bits [15:0]: Minor Version. Must be 1 for this revision of the SPM
+      interface.
+
+    On error, the format of the value is as follows:
+
+    - ``NOT_SUPPORTED``: SPM interface is not supported or not available for the
+      client.
+
+- Usage
+
+  This function returns the version of the Secure Partition Manager
+  implementation. The major version is 0 and the minor version is 1. The version
+  number is a 31-bit unsigned integer, with the upper 15 bits denoting the major
+  revision, and the lower 16 bits denoting the minor revision. The following
+  rules apply to the version numbering:
+
+  - Different major revision values indicate possibly incompatible functions.
+
+  - For two revisions, A and B, for which the major revision values are
+    identical, if the minor revision value of revision B is greater than the
+    minor revision value of revision A, then every function in revision A must
+    work in a compatible way with revision B. However, it is possible for
+    revision B to have a higher function count than revision A.
+
+- Implementation responsibilities
+
+  If this function returns a valid version number, all the functions that are
+  described subsequently must be implemented, unless it is explicitly stated
+  that a function is optional.
+
+See `Error Codes`_ for integer values that are associated with each return
+code.
+
+Secure Partition Initialisation
+-------------------------------
+
+The SPM is responsible for initialising the architectural execution context to
+enable initialisation of a service in S-EL0. The responsibilities of the SPM are
+listed below. At the end of initialisation, the partition issues a
+``SP_EVENT_COMPLETE_AARCH64`` call (described later) to signal readiness for
+handling requests for services implemented by the Secure Partition. The
+initialisation event is executed as a Fast Call.
+
+Entry point invocation
+^^^^^^^^^^^^^^^^^^^^^^
+
+The entry point for service requests that should be handled as Fast Calls is
+used as the target of the ERET instruction to start initialisation of the Secure
+Partition.
+
+Architectural Setup
+^^^^^^^^^^^^^^^^^^^
+
+At cold boot, system registers accessible from S-EL0 will be in their reset
+state unless otherwise specified. The SPM will perform the following
+architectural setup to enable execution in S-EL0
+
+MMU setup
+^^^^^^^^^
+
+The platform port of a Secure Partition specifies to the SPM a list of regions
+that it needs access to and their attributes. The SPM validates this resource
+description and initialises the Secure EL1&0 translation regime as follows.
+
+1. Device regions are mapped with nGnRE attributes and Execute Never
+   instruction access permissions.
+
+2. Code memory regions are mapped with RO data and Executable instruction access
+   permissions.
+
+3. Read Only data memory regions are mapped with RO data and Execute Never
+   instruction access permissions.
+
+4. Read Write data memory regions are mapped with RW data and Execute Never
+   instruction access permissions.
+
+5. If the resource description does not explicitly describe the type of memory
+   regions then all memory regions will be marked with Code memory region
+   attributes.
+
+6. The ``UXN`` and ``PXN`` bits are set for regions that are not executable by
+   S-EL0 or S-EL1.
+
+System Register Setup
+^^^^^^^^^^^^^^^^^^^^^
+
+System registers that influence software execution in S-EL0 are setup by the SPM
+as follows:
+
+1. ``SCTLR_EL1``
+
+   - ``UCI=1``
+   - ``EOE=0``
+   - ``WXN=1``
+   - ``nTWE=1``
+   - ``nTWI=1``
+   - ``UCT=1``
+   - ``DZE=1``
+   - ``I=1``
+   - ``UMA=0``
+   - ``SA0=1``
+   - ``C=1``
+   - ``A=1``
+   - ``M=1``
+
+2. ``CPACR_EL1``
+
+   - ``FPEN=b'11``
+
+3. ``PSTATE``
+
+   - ``D,A,I,F=1``
+   - ``CurrentEL=0`` (EL0)
+   - ``SpSel=0`` (Thread mode)
+   - ``NRW=0`` (AArch64)
+
+General Purpose Register Setup
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+SPM will invoke the entry point of a service by executing an ERET instruction.
+This transition into S-EL0 is special since it is not in response to a previous
+request through a SVC instruction. This is the first entry into S-EL0. The
+general purpose register usage at the time of entry will be as specified in the
+"Return State" column of Table 3-1 in Section 3.1 "Register use in AArch64 SMC
+calls" of the `SMC Calling Convention`_ (*Arm DEN 0028B*) specification. In
+addition, certain other restrictions will be applied as described below.
+
+1. ``SP_EL0``
+
+   A non-zero value will indicate that the SPM has initialised the stack pointer
+   for the current CPU.
+
+   The value will be 0 otherwise.
+
+2. ``X4-X30``
+
+   The values of these registers will be 0.
+
+3. ``X0-X3``
+
+   Parameters passed by the SPM.
+
+   - ``X0``: Virtual address of a buffer shared between EL3 and S-EL0. The
+     buffer will be mapped in the Secure EL1&0 translation regime with read-only
+     memory attributes described earlier.
+
+   - ``X1``: Size of the buffer in bytes.
+
+   - ``X2``: Cookie value (*IMPLEMENTATION DEFINED*).
+
+   - ``X3``: Cookie value (*IMPLEMENTATION DEFINED*).
+
+Runtime Event Delegation
+------------------------
+
+The SPM receives requests for Secure Partition services through a synchronous
+invocation (i.e. a SMC from the Non-secure world). These requests are delegated
+to the partition by programming a return from the last
+``SP_EVENT_COMPLETE_AARCH64`` call received from the partition. The last call
+was made to signal either completion of Secure Partition initialisation or
+completion of a partition service request.
+
+``SP_EVENT_COMPLETE_AARCH64``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Description
+
+  Signal completion of the last SP service request.
+
+- Parameters
+
+  - **uint32** - Function ID
+
+    - SVC64 Version: **0xC4000061**
+
+  - **int32** - Event Status Code
+
+    Zero or a positive value indicates that the event was handled successfully.
+    The values depend upon the original event that was delegated to the Secure
+    partition. They are described as follows.
+
+    - ``SUCCESS`` : Used to indicate that the Secure Partition was initialised
+      or a runtime request was handled successfully.
+
+    - Any other value greater than 0 is used to pass a specific Event Status
+      code in response to a runtime event.
+
+    A negative value indicates an error. The values of Event Status code depend
+    on the original event.
+
+- Return parameters
+
+  - **int32** - Event ID/Return Code
+
+    Zero or a positive value specifies the unique ID of the event being
+    delegated to the partition by the SPM.
+
+    In the current implementation, this parameter contains the function ID of
+    the ``MM_COMMUNICATE`` SMC. This value indicates to the partition that an
+    event has been delegated to it in response to an ``MM_COMMUNICATE`` request
+    from the Non-secure world.
+
+    A negative value indicates an error. The format of the value is as follows:
+
+    - ``NOT_SUPPORTED``: Function was called from the Non-secure world.
+
+    See `Error Codes`_ for integer values that are associated with each return
+    code.
+
+  - **uint32** - Event Context Address
+
+    Address of a buffer shared between the SPM and Secure Partition to pass
+    event specific information. The format of the data populated in the buffer
+    is implementation defined.
+
+    The buffer is mapped in the Secure EL1&0 translation regime with read-only
+    memory attributes described earlier.
+
+    For the SVC64 version, this parameter is a 64-bit Virtual Address (VA).
+
+    For the SVC32 version, this parameter is a 32-bit Virtual Address (VA).
+
+  - **uint32** - Event context size
+
+    Size of the memory starting at Event Address.
+
+  - **uint32/uint64** - Event Cookie
+
+    This is an optional parameter. If unused its value is SBZ.
+
+- Usage
+
+  This function signals to the SPM that the handling of the last event delegated
+  to a partition has completed. The partition is ready to handle its next event.
+  A return from this function is in response to the next event that will be
+  delegated to the partition. The return parameters describe the next event.
+
+- Caller responsibilities
+
+  A Secure Partition must only call ``SP_EVENT_COMPLETE_AARCH64`` to signal
+  completion of a request that was delegated to it by the SPM.
+
+- Callee responsibilities
+
+  When the SPM receives this call from a Secure Partition, the corresponding
+  syndrome information can be used to return control through an ERET
+  instruction, to the instruction immediately after the call in the Secure
+  Partition context. This syndrome information comprises of general purpose and
+  system register values when the call was made.
+
+  The SPM must save this syndrome information and use it to delegate the next
+  event to the Secure Partition. The return parameters of this interface must
+  specify the properties of the event and be populated in ``X0-X3/W0-W3``
+  registers.
+
+Secure Partition Memory Management
+----------------------------------
+
+A Secure Partition executes at S-EL0, which is an unprivileged Exception Level.
+The SPM is responsible for enabling access to regions of memory in the system
+address map from a Secure Partition. This is done by mapping these regions in
+the Secure EL1&0 Translation regime with appropriate memory attributes.
+Attributes refer to memory type, permission, cacheability and shareability
+attributes used in the Translation tables. The definitions of these attributes
+and their usage can be found in the `Armv8-A ARM`_ (*Arm DDI 0487*).
+
+All memory required by the Secure Partition is allocated upfront in the SPM,
+even before handing over to the Secure Partition for the first time. The initial
+access permissions of the memory regions are statically provided by the platform
+port and should allow the Secure Partition to run its initialisation code.
+
+However, they might not suit the final needs of the Secure Partition because its
+final memory layout might not be known until the Secure Partition initialises
+itself. As the Secure Partition initialises its runtime environment it might,
+for example, load dynamically some modules. For instance, a Secure Partition
+could implement a loader for a standard executable file format (e.g. an PE-COFF
+loader for loading executable files at runtime). These executable files will be
+a part of the Secure Partition image. The location of various sections in an
+executable file and their permission attributes (e.g. read-write data, read-only
+data and code) will be known only when the file is loaded into memory.
+
+In this case, the Secure Partition needs a way to change the access permissions
+of its memory regions. The SPM provides this feature through the
+``SP_MEMORY_ATTRIBUTES_SET_AARCH64`` SVC interface. This interface is available
+to the Secure Partition during a specific time window: from the first entry into
+the Secure Partition up to the first ``SP_EVENT_COMPLETE`` call that signals the
+Secure Partition has finished its initialisation. Once the initialisation is
+complete, the SPM does not allow changes to the memory attributes.
+
+This section describes the standard SVC interface that is implemented by the SPM
+to determine and change permission attributes of memory regions that belong to a
+Secure Partition.
+
+``SP_MEMORY_ATTRIBUTES_GET_AARCH64``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Description
+
+  Request the permission attributes of a memory region from S-EL0.
+
+- Parameters
+
+  - **uint32** Function ID
+
+    - SVC64 Version: **0xC4000064**
+
+  - **uint64** Base Address
+
+    This parameter is a 64-bit Virtual Address (VA).
+
+    There are no alignment restrictions on the Base Address. The permission
+    attributes of the translation granule it lies in are returned.
+
+- Return parameters
+
+  - **int32** - Memory Attributes/Return Code
+
+    On success the format of the Return Code is as follows:
+
+    - Bits[1:0] : Data access permission
+
+      - b'00 : No access
+      - b'01 : Read-Write access
+      - b'10 : Reserved
+      - b'11 : Read-only access
+
+    - Bit[2]: Instruction access permission
+
+      - b'0 : Executable
+      - b'1 : Non-executable
+
+    - Bit[30:3] : Reserved. SBZ.
+
+    - Bit[31]   : Must be 0
+
+    On failure the following error codes are returned:
+
+    - ``INVALID_PARAMETERS``: The Secure Partition is not allowed to access the
+      memory region the Base Address lies in.
+
+    - ``NOT_SUPPORTED`` : The SPM does not support retrieval of attributes of
+      any memory page that is accessible by the Secure Partition, or the
+      function was called from the Non-secure world. Also returned if it is
+      used after ``SP_EVENT_COMPLETE_AARCH64``.
+
+    See `Error Codes`_ for integer values that are associated with each return
+    code.
+
+- Usage
+
+  This function is used to request the permission attributes for S-EL0 on a
+  memory region accessible from a Secure Partition. The size of the memory
+  region is equal to the Translation Granule size used in the Secure EL1&0
+  translation regime. Requests to retrieve other memory region attributes are
+  not currently supported.
+
+- Caller responsibilities
+
+  The caller must obtain the Translation Granule Size of the Secure EL1&0
+  translation regime from the SPM through an implementation defined method.
+
+- Callee responsibilities
+
+  The SPM must not return the memory access controls for a page of memory that
+  is not accessible from a Secure Partition.
+
+``SP_MEMORY_ATTRIBUTES_SET_AARCH64``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Description
+
+  Set the permission attributes of a memory region from S-EL0.
+
+- Parameters
+
+  - **uint32** - Function ID
+
+    - SVC64 Version: **0xC4000065**
+
+  - **uint64** - Base Address
+
+    This parameter is a 64-bit Virtual Address (VA).
+
+    The alignment of the Base Address must be greater than or equal to the size
+    of the Translation Granule Size used in the Secure EL1&0 translation
+    regime.
+
+  - **uint32** - Page count
+
+    Number of pages starting from the Base Address whose memory attributes
+    should be changed. The page size is equal to the Translation Granule Size.
+
+  - **uint32** - Memory Access Controls
+
+    - Bits[1:0] : Data access permission
+
+      - b'00 : No access
+      - b'01 : Read-Write access
+      - b'10 : Reserved
+      - b'11 : Read-only access
+
+    - Bit[2] : Instruction access permission
+
+      - b'0 : Executable
+      - b'1 : Non-executable
+
+    - Bits[31:3] : Reserved. SBZ.
+
+    A combination of attributes that mark the region with RW and Executable
+    permissions is prohibited. A request to mark a device memory region with
+    Executable permissions is prohibited.
+
+- Return parameters
+
+  - **int32** - Return Code
+
+    - ``SUCCESS``: The Memory Access Controls were changed successfully.
+
+    - ``DENIED``: The SPM is servicing a request to change the attributes of a
+      memory region that overlaps with the region specified in this request.
+
+    - ``INVALID_PARAMETER``: An invalid combination of Memory Access Controls
+      has been specified. The Base Address is not correctly aligned. The Secure
+      Partition is not allowed to access part or all of the memory region
+      specified in the call.
+
+    - ``NO_MEMORY``: The SPM does not have memory resources to change the
+      attributes of the memory region in the translation tables.
+
+    - ``NOT_SUPPORTED``: The SPM does not permit change of attributes of any
+      memory region that is accessible by the Secure Partition. Function was
+      called from the Non-secure world. Also returned if it is used after
+      ``SP_EVENT_COMPLETE_AARCH64``.
+
+    See `Error Codes`_ for integer values that are associated with each return
+    code.
+
+- Usage
+
+  This function is used to change the permission attributes for S-EL0 on a
+  memory region accessible from a Secure Partition. The size of the memory
+  region is equal to the Translation Granule size used in the Secure EL1&0
+  translation regime. Requests to change other memory region attributes are not
+  currently supported.
+
+  This function is only available at boot time. This interface is revoked after
+  the Secure Partition sends the first ``SP_EVENT_COMPLETE_AARCH64`` to signal
+  that it is initialised and ready to receive run-time requests.
+
+- Caller responsibilities
+
+  The caller must obtain the Translation Granule Size of the Secure EL1&0
+  translation regime from the SPM through an implementation defined method.
+
+- Callee responsibilities
+
+  The SPM must preserve the original memory access controls of the region of
+  memory in case of an unsuccessful call.  The SPM must preserve the consistency
+  of the S-EL1 translation regime if this function is called on different PEs
+  concurrently and the memory regions specified overlap.
+
+Error Codes
+-----------
+
+.. csv-table::
+   :header: "Name", "Value"
+
+   ``SUCCESS``,0
+   ``NOT_SUPPORTED``,-1
+   ``INVALID_PARAMETER``,-2
+   ``DENIED``,-3
+   ``NO_MEMORY``,-5
+   ``NOT_PRESENT``,-7
+
+--------------
+
+*Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Armv8-A ARM: https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile
+.. _instructions in the EDK2 repository: https://github.com/tianocore/edk2-staging/blob/AArch64StandaloneMm/HowtoBuild.MD
+.. _Management Mode Interface Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0060a/DEN0060A_ARM_MM_Interface_Specification.pdf
+.. _SDEI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+
+.. |Image 1| image:: ../resources/diagrams/secure_sw_stack_tos.png
+.. |Image 2| image:: ../resources/diagrams/secure_sw_stack_sp.png
diff --git a/docs/components/spd/index.rst b/docs/components/spd/index.rst
new file mode 100644
index 0000000..25d0124
--- /dev/null
+++ b/docs/components/spd/index.rst
@@ -0,0 +1,10 @@
+Secure Payload Dispatcher (SPD)
+===============================
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+
+   optee-dispatcher
+   tlk-dispatcher
+   trusty-dispatcher
diff --git a/docs/components/spd/optee-dispatcher.rst b/docs/components/spd/optee-dispatcher.rst
new file mode 100644
index 0000000..63baccc
--- /dev/null
+++ b/docs/components/spd/optee-dispatcher.rst
@@ -0,0 +1,14 @@
+OP-TEE Dispatcher
+=================
+
+`OP-TEE OS`_ is a Trusted OS running as Secure EL1.
+
+To build and execute OP-TEE follow the instructions at
+`OP-TEE build.git`_
+
+--------------
+
+*Copyright (c) 2014-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _OP-TEE OS: https://github.com/OP-TEE/build
+.. _OP-TEE build.git: https://github.com/OP-TEE/build
diff --git a/docs/components/spd/tlk-dispatcher.rst b/docs/components/spd/tlk-dispatcher.rst
new file mode 100644
index 0000000..a6c658c
--- /dev/null
+++ b/docs/components/spd/tlk-dispatcher.rst
@@ -0,0 +1,76 @@
+Trusted Little Kernel (TLK) Dispatcher
+======================================
+
+TLK dispatcher (TLK-D) adds support for NVIDIA's Trusted Little Kernel (TLK)
+to work with Trusted Firmware-A (TF-A). TLK-D can be compiled by including it
+in the platform's makefile. TLK is primarily meant to work with Tegra SoCs,
+so while TF-A only supports TLK on Tegra, the dispatcher code can only be
+compiled for other platforms.
+
+In order to compile TLK-D, we need a BL32 image to be present. Since, TLKD
+just needs to compile, any BL32 image would do. To use TLK as the BL32, please
+refer to the "Build TLK" section.
+
+Once a BL32 is ready, TLKD can be included in the image by adding "SPD=tlkd"
+to the build command.
+
+Trusted Little Kernel (TLK)
+---------------------------
+
+TLK is a Trusted OS running as Secure EL1. It is a Free Open Source Software
+(FOSS) release of the NVIDIA® Trusted Little Kernel (TLK) technology, which
+extends technology made available with the development of the Little Kernel (LK).
+You can download the LK modular embedded preemptive kernel for use on Arm,
+x86, and AVR32 systems from https://github.com/travisg/lk
+
+NVIDIA implemented its Trusted Little Kernel (TLK) technology, designed as a
+free and open-source trusted execution environment (OTE).
+
+TLK features include:
+
+• Small, pre-emptive kernel
+• Supports multi-threading, IPCs, and thread scheduling
+• Added TrustZone features
+• Added Secure Storage
+• Under MIT/FreeBSD license
+
+NVIDIA extensions to Little Kernel (LK) include:
+
+• User mode
+• Address-space separation for TAs
+• TLK Client Application (CA) library
+• TLK TA library
+• Crypto library (encrypt/decrypt, key handling) via OpenSSL
+• Linux kernel driver
+• Cortex A9/A15 support
+• Power Management
+• TrustZone memory carve-out (reconfigurable)
+• Page table management
+• Debugging support over UART (USB planned)
+
+TLK is hosted by NVIDIA on http://nv-tegra.nvidia.com under the
+3rdparty/ote\_partner/tlk.git repository. Detailed information about
+TLK and OTE can be found in the Tegra\_BSP\_for\_Android\_TLK\_FOSS\_Reference.pdf
+manual located under the "documentation" directory\_.
+
+Build TLK
+---------
+
+To build and execute TLK, follow the instructions from "Building a TLK Device"
+section from Tegra\_BSP\_for\_Android\_TLK\_FOSS\_Reference.pdf manual.
+
+Input parameters to TLK
+-----------------------
+
+TLK expects the TZDRAM size and a structure containing the boot arguments. BL2
+passes this information to the EL3 software as members of the bl32\_ep\_info
+struct, where bl32\_ep\_info is part of bl31\_params\_t (passed by BL2 in X0)
+
+Example
+~~~~~~~
+
+::
+
+    bl32_ep_info->args.arg0 = TZDRAM size available for BL32
+    bl32_ep_info->args.arg1 = unused (used only on Armv7-A)
+    bl32_ep_info->args.arg2 = pointer to boot args
diff --git a/docs/components/spd/trusty-dispatcher.rst b/docs/components/spd/trusty-dispatcher.rst
new file mode 100644
index 0000000..a3cb829
--- /dev/null
+++ b/docs/components/spd/trusty-dispatcher.rst
@@ -0,0 +1,32 @@
+Trusty Dispatcher
+=================
+
+Trusty is a a set of software components, supporting a Trusted Execution
+Environment (TEE) on mobile devices, published and maintained by Google.
+
+Detailed information and build instructions can be found on the Android
+Open Source Project (AOSP) webpage for Trusty hosted at
+https://source.android.com/security/trusty
+
+Boot parameters
+---------------
+
+Custom boot parameters can be passed to Trusty by providing a platform
+specific function:
+
+.. code:: c
+
+    void plat_trusty_set_boot_args(aapcs64_params_t *args)
+
+If this function is provided ``args->arg0`` must be set to the memory
+size allocated to trusty. If the platform does not provide this
+function, but defines ``TSP_SEC_MEM_SIZE``, a default implementation
+will pass the memory size from ``TSP_SEC_MEM_SIZE``. ``args->arg1``
+can be set to a platform specific parameter block, and ``args->arg2``
+should then be set to the size of that block.
+
+Supported platforms
+-------------------
+
+Out of all the platforms supported by Trusted Firmware-A, Trusty is only
+verified and supported by NVIDIA's Tegra SoCs.
diff --git a/docs/components/xlat-tables-lib-v2-design.rst b/docs/components/xlat-tables-lib-v2-design.rst
new file mode 100644
index 0000000..786dd3b
--- /dev/null
+++ b/docs/components/xlat-tables-lib-v2-design.rst
@@ -0,0 +1,421 @@
+Translation (XLAT) Tables Library
+=================================
+
+This document describes the design of the translation tables library (version 2)
+used by Trusted Firmware-A (TF-A). This library provides APIs to create page
+tables based on a description of the memory layout, as well as setting up system
+registers related to the Memory Management Unit (MMU) and performing the
+required Translation Lookaside Buffer (TLB) maintenance operations.
+
+More specifically, some use cases that this library aims to support are:
+
+#. Statically allocate translation tables and populate them (at run-time) based
+   on a description of the memory layout. The memory layout is typically
+   provided by the platform port as a list of memory regions;
+
+#. Support for generating translation tables pertaining to a different
+   translation regime than the exception level the library code is executing at;
+
+#. Support for dynamic mapping and unmapping of regions, even while the MMU is
+   on. This can be used to temporarily map some memory regions and unmap them
+   later on when no longer needed;
+
+#. Support for non-identity virtual to physical mappings to compress the virtual
+   address space;
+
+#. Support for changing memory attributes of memory regions at run-time.
+
+
+About version 1 and version 2
+-----------------------------
+
+This document focuses on version 2 of the library, whose sources are available
+in the `lib/xlat_tables_v2`_ directory. Version 1 of the library can still be
+found in `lib/xlat_tables`_ directory but it is less flexible and doesn't
+support dynamic mapping. Although potential bug fixes will be applied to both
+versions, future features enhancements will focus on version 2 and might not be
+back-ported to version 1. Therefore, it is recommended to use version 2,
+especially for new platform ports.
+
+However, please note that version 2 is still in active development and is not
+considered stable yet. Hence, compatibility breaks might be introduced.
+
+From this point onwards, this document will implicitly refer to version 2 of the
+library.
+
+
+Design concepts and interfaces
+------------------------------
+
+This section presents some of the key concepts and data structures used in the
+translation tables library.
+
+`mmap` regions
+~~~~~~~~~~~~~~
+
+An ``mmap_region`` is an abstract, concise way to represent a memory region to
+map. It is one of the key interfaces to the library. It is identified by:
+
+- its physical base address;
+- its virtual base address;
+- its size;
+- its attributes;
+- its mapping granularity (optional).
+
+See the ``struct mmap_region`` type in `xlat_tables_v2.h`_.
+
+The user usually provides a list of such mmap regions to map and lets the
+library transpose that in a set of translation tables. As a result, the library
+might create new translation tables, update or split existing ones.
+
+The region attributes specify the type of memory (for example device or cached
+normal memory) as well as the memory access permissions (read-only or
+read-write, executable or not, secure or non-secure, and so on). In the case of
+the EL1&0 translation regime, the attributes also specify whether the region is
+a User region (EL0) or Privileged region (EL1). See the ``MT_xxx`` definitions
+in `xlat_tables_v2.h`_. Note that for the EL1&0 translation regime the Execute
+Never attribute is set simultaneously for both EL1 and EL0.
+
+The granularity controls the translation table level to go down to when mapping
+the region. For example, assuming the MMU has been configured to use a 4KB
+granule size, the library might map a 2MB memory region using either of the two
+following options:
+
+- using a single level-2 translation table entry;
+- using a level-2 intermediate entry to a level-3 translation table (which
+  contains 512 entries, each mapping 4KB).
+
+The first solution potentially requires less translation tables, hence
+potentially less memory.  However, if part of this 2MB region is later remapped
+with different memory attributes, the library might need to split the existing
+page tables to refine the mappings. If a single level-2 entry has been used
+here, a level-3 table will need to be allocated on the fly and the level-2
+modified to point to this new level-3 table. This has a performance cost at
+run-time.
+
+If the user knows upfront that such a remapping operation is likely to happen
+then they might enforce a 4KB mapping granularity for this 2MB region from the
+beginning; remapping some of these 4KB pages on the fly then becomes a
+lightweight operation.
+
+The region's granularity is an optional field; if it is not specified the
+library will choose the mapping granularity for this region as it sees fit (more
+details can be found in `The memory mapping algorithm`_ section below).
+
+Translation Context
+~~~~~~~~~~~~~~~~~~~
+
+The library can create or modify translation tables pertaining to a different
+translation regime than the exception level the library code is executing at.
+For example, the library might be used by EL3 software (for instance BL31) to
+create translation tables pertaining to the S-EL1&0 translation regime.
+
+This flexibility comes from the use of *translation contexts*. A *translation
+context* constitutes the superset of information used by the library to track
+the status of a set of translation tables for a given translation regime.
+
+The library internally allocates a default translation context, which pertains
+to the translation regime of the current exception level. Additional contexts
+may be explicitly allocated and initialized using the
+``REGISTER_XLAT_CONTEXT()`` macro. Separate APIs are provided to act either on
+the default translation context or on an alternative one.
+
+To register a translation context, the user must provide the library with the
+following information:
+
+* A name.
+
+  The resulting translation context variable will be called after this name, to
+  which ``_xlat_ctx`` is appended. For example, if the macro name parameter is
+  ``foo``, the context variable name will be ``foo_xlat_ctx``.
+
+* The maximum number of `mmap` regions to map.
+
+  Should account for both static and dynamic regions, if applicable.
+
+* The number of sub-translation tables to allocate.
+
+  Number of translation tables to statically allocate for this context,
+  excluding the initial lookup level translation table, which is always
+  allocated. For example, if the initial lookup level is 1, this parameter would
+  specify the number of level-2 and level-3 translation tables to pre-allocate
+  for this context.
+
+* The size of the virtual address space.
+
+  Size in bytes of the virtual address space to map using this context. This
+  will incidentally determine the number of entries in the initial lookup level
+  translation table : the library will allocate as many entries as is required
+  to map the entire virtual address space.
+
+* The size of the physical address space.
+
+  Size in bytes of the physical address space to map using this context.
+
+The default translation context is internally initialized using information
+coming (for the most part) from platform-specific defines:
+
+- name: hard-coded to ``tf`` ; hence the name of the default context variable is
+  ``tf_xlat_ctx``;
+- number of `mmap` regions: ``MAX_MMAP_REGIONS``;
+- number of sub-translation tables: ``MAX_XLAT_TABLES``;
+- size of the virtual address space: ``PLAT_VIRT_ADDR_SPACE_SIZE``;
+- size of the physical address space: ``PLAT_PHY_ADDR_SPACE_SIZE``.
+
+Please refer to the `Porting Guide`_ for more details about these macros.
+
+
+Static and dynamic memory regions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The library optionally supports dynamic memory mapping. This feature may be
+enabled using the ``PLAT_XLAT_TABLES_DYNAMIC`` platform build flag.
+
+When dynamic memory mapping is enabled, the library categorises mmap regions as
+*static* or *dynamic*.
+
+- *Static regions* are fixed for the lifetime of the system. They can only be
+  added early on, before the translation tables are created and populated. They
+  cannot be removed afterwards.
+
+- *Dynamic regions* can be added or removed any time.
+
+When the dynamic memory mapping feature is disabled, only static regions exist.
+
+The dynamic memory mapping feature may be used to map and unmap transient memory
+areas. This is useful when the user needs to access some memory for a fixed
+period of time, after which the memory may be discarded and reclaimed. For
+example, a memory region that is only required at boot time while the system is
+initializing, or to temporarily share a memory buffer between the normal world
+and trusted world. Note that it is up to the caller to ensure that these regions
+are not accessed concurrently while the regions are being added or removed.
+
+Although this feature provides some level of dynamic memory allocation, this
+does not allow dynamically allocating an arbitrary amount of memory at an
+arbitrary memory location. The user is still required to declare at compile-time
+the limits of these allocations ; the library will deny any mapping request that
+does not fit within this pre-allocated pool of memory.
+
+
+Library APIs
+------------
+
+The external APIs exposed by this library are declared and documented in the
+`xlat_tables_v2.h`_ header file. This should be the reference point for
+getting information about the usage of the different APIs this library
+provides. This section just provides some extra details and clarifications.
+
+Although the ``mmap_region`` structure is a publicly visible type, it is not
+recommended to populate these structures by hand. Instead, wherever APIs expect
+function arguments of type ``mmap_region_t``, these should be constructed using
+the ``MAP_REGION*()`` family of helper macros. This is to limit the risk of
+compatibility breaks, should the ``mmap_region`` structure type evolve in the
+future.
+
+The ``MAP_REGION()`` and ``MAP_REGION_FLAT()`` macros do not allow specifying a
+mapping granularity, which leaves the library implementation free to choose
+it. However, in cases where a specific granularity is required, the
+``MAP_REGION2()`` macro might be used instead.
+
+As explained earlier in this document, when the dynamic mapping feature is
+disabled, there is no notion of dynamic regions. Conceptually, there are only
+static regions. For this reason (and to retain backward compatibility with the
+version 1 of the library), the APIs that map static regions do not embed the
+word *static* in their functions names (for example ``mmap_add_region()``), in
+contrast with the dynamic regions APIs (for example
+``mmap_add_dynamic_region()``).
+
+Although the definition of static and dynamic regions is not based on the state
+of the MMU, the two are still related in some way. Static regions can only be
+added before ``init_xlat_tables()`` is called and ``init_xlat_tables()`` must be
+called while the MMU is still off. As a result, static regions cannot be added
+once the MMU has been enabled. Dynamic regions can be added with the MMU on or
+off. In practice, the usual call flow would look like this:
+
+#. The MMU is initially off.
+
+#. Add some static regions, add some dynamic regions.
+
+#. Initialize translation tables based on the list of mmap regions (using one of
+   the ``init_xlat_tables*()`` APIs).
+
+#. At this point, it is no longer possible to add static regions. Dynamic
+   regions can still be added or removed.
+
+#. Enable the MMU.
+
+#. Dynamic regions can continue to be added or removed.
+
+Because static regions are added early on at boot time and are all in the
+control of the platform initialization code, the ``mmap_add*()`` family of APIs
+are not expected to fail. They do not return any error code.
+
+Nonetheless, these APIs will check upfront whether the region can be
+successfully added before updating the translation context structure. If the
+library detects that there is insufficient memory to meet the request, or that
+the new region will overlap another one in an invalid way, or if any other
+unexpected error is encountered, they will print an error message on the UART.
+Additionally, when asserts are enabled (typically in debug builds), an assertion
+will be triggered. Otherwise, the function call will just return straight away,
+without adding the offending memory region.
+
+
+Library limitations
+-------------------
+
+Dynamic regions are not allowed to overlap each other. Static regions are
+allowed to overlap as long as one of them is fully contained inside the other
+one. This is allowed for backwards compatibility with the previous behaviour in
+the version 1 of the library.
+
+
+Implementation details
+----------------------
+
+Code structure
+~~~~~~~~~~~~~~
+
+The library is divided into 4 modules:
+
+- **Core module**
+
+  Provides the main functionality of the library, such as the initialization of
+  translation tables contexts and mapping/unmapping memory regions. This module
+  provides functions such as ``mmap_add_region_ctx`` that let the caller specify
+  the translation tables context affected by them.
+
+  See `xlat_tables_core.c`_.
+
+- **Active context module**
+
+  Instantiates the context that is used by the current BL image and provides
+  helpers to manipulate it, abstracting it from the rest of the code.
+  This module provides functions such as ``mmap_add_region``, that directly
+  affect the BL image using them.
+
+  See `xlat_tables_context.c`_.
+
+- **Utilities module**
+
+  Provides additional functionality like debug print of the current state of the
+  translation tables and helpers to query memory attributes and to modify them.
+
+  See `xlat_tables_utils.c`_.
+
+- **Architectural module**
+
+  Provides functions that are dependent on the current execution state
+  (AArch32/AArch64), such as the functions used for TLB invalidation, setup the
+  MMU, or calculate the Physical Address Space size. They do not need a
+  translation context to work on.
+
+  See `aarch32/xlat_tables_arch.c`_ and `aarch64/xlat_tables_arch.c`_.
+
+From mmap regions to translation tables
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A translation context contains a list of ``mmap_region_t``, which holds the
+information of all the regions that are mapped at any given time. Whenever there
+is a request to map (resp. unmap) a memory region, it is added to (resp. removed
+from) the ``mmap_region_t`` list.
+
+The mmap regions list is a conceptual way to represent the memory layout. At
+some point, the library has to convert this information into actual translation
+tables to program into the MMU.
+
+Before the ``init_xlat_tables()`` API is called, the library only acts on the
+mmap regions list. Adding a static or dynamic region at this point through one
+of the ``mmap_add*()`` APIs does not affect the translation tables in any way,
+they only get registered in the internal mmap region list. It is only when the
+user calls the ``init_xlat_tables()`` that the translation tables are populated
+in memory based on the list of mmap regions registered so far. This is an
+optimization that allows creation of the initial set of translation tables in
+one go, rather than having to edit them every time while the MMU is disabled.
+
+After the ``init_xlat_tables()`` API has been called, only dynamic regions can
+be added. Changes to the translation tables (as well as the mmap regions list)
+will take effect immediately.
+
+The memory mapping algorithm
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The mapping function is implemented as a recursive algorithm. It is however
+bound by the level of depth of the translation tables (the Armv8-A architecture
+allows up to 4 lookup levels).
+
+By default [#granularity-ref]_, the algorithm will attempt to minimize the
+number of translation tables created to satisfy the user's request. It will
+favour mapping a region using the biggest possible blocks, only creating a
+sub-table if it is strictly necessary. This is to reduce the memory footprint of
+the firmware.
+
+The most common reason for needing a sub-table is when a specific mapping
+requires a finer granularity. Misaligned regions also require a finer
+granularity than what the user may had originally expected, using a lot more
+memory than expected. The reason is that all levels of translation are
+restricted to address translations of the same granularity as the size of the
+blocks of that level.  For example, for a 4 KiB page size, a level 2 block entry
+can only translate up to a granularity of 2 MiB. If the Physical Address is not
+aligned to 2 MiB then additional level 3 tables are also needed.
+
+Note that not every translation level allows any type of descriptor. Depending
+on the page size, levels 0 and 1 of translation may only allow table
+descriptors. If a block entry could be able to describe a translation, but that
+level does not allow block descriptors, a table descriptor will have to be used
+instead, as well as additional tables at the next level.
+
+|Alignment Example|
+
+The mmap regions are sorted in a way that simplifies the code that maps
+them. Even though this ordering is only strictly needed for overlapping static
+regions, it must also be applied for dynamic regions to maintain a consistent
+order of all regions at all times. As each new region is mapped, existing
+entries in the translation tables are checked to ensure consistency. Please
+refer to the comments in the source code of the core module for more details
+about the sorting algorithm in use.
+
+.. [#granularity-ref] That is, when mmap regions do not enforce their mapping
+                      granularity.
+
+TLB maintenance operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The library takes care of performing TLB maintenance operations when required.
+For example, when the user requests removing a dynamic region, the library
+invalidates all TLB entries associated to that region to ensure that these
+changes are visible to subsequent execution, including speculative execution,
+that uses the changed translation table entries.
+
+A counter-example is the initialization of translation tables. In this case,
+explicit TLB maintenance is not required. The Armv8-A architecture guarantees
+that all TLBs are disabled from reset and their contents have no effect on
+address translation at reset [#tlb-reset-ref]_. Therefore, the TLBs invalidation
+is deferred to the ``enable_mmu*()`` family of functions, just before the MMU is
+turned on.
+
+TLB invalidation is not required when adding dynamic regions either. Dynamic
+regions are not allowed to overlap existing memory region. Therefore, if the
+dynamic mapping request is deemed legitimate, it automatically concerns memory
+that was not mapped in this translation regime and the library will have
+initialized its corresponding translation table entry to an invalid
+descriptor. Given that the TLBs are not architecturally permitted to hold any
+invalid translation table entry [#tlb-no-invalid-entry]_, this means that this
+mapping cannot be cached in the TLBs.
+
+.. [#tlb-reset-ref] See section D4.9 `Translation Lookaside Buffers (TLBs)`, subsection `TLB behavior at reset` in Armv8-A, rev C.a.
+.. [#tlb-no-invalid-entry] See section D4.10.1 `General TLB maintenance requirements` in Armv8-A, rev C.a.
+
+--------------
+
+*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _lib/xlat_tables_v2: ../../lib/xlat_tables_v2
+.. _lib/xlat_tables: ../../lib/xlat_tables
+.. _xlat_tables_v2.h: ../../include/lib/xlat_tables/xlat_tables_v2.h
+.. _xlat_tables_context.c: ../../lib/xlat_tables_v2/xlat_tables_context.c
+.. _xlat_tables_core.c: ../../lib/xlat_tables_v2/xlat_tables_core.c
+.. _xlat_tables_utils.c: ../../lib/xlat_tables_v2/xlat_tables_utils.c
+.. _aarch32/xlat_tables_arch.c: ../../lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+.. _aarch64/xlat_tables_arch.c: ../../lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+.. _Porting Guide: ../getting_started/porting-guide.rst
+.. |Alignment Example| image:: ../resources/diagrams/xlat_align.png
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..b267de0
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# See the options documentation at http://www.sphinx-doc.org/en/master/config
+
+import os
+
+# -- Project information -----------------------------------------------------
+
+project = 'Trusted Firmware-A'
+
+version = '2.1'
+release = version # We don't need these to be distinct
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.plantuml']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path .
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# Load the contents of the global substitutions file into the 'rst_prolog'
+# variable. This ensures that the substitutions are all inserted into each page.
+with open('global_substitutions.txt', 'r') as subs:
+  rst_prolog = subs.read()
+
+# Minimum version of sphinx required
+needs_sphinx = '2.0'
+
+# -- Options for HTML output -------------------------------------------------
+
+# Don't show the "Built with Sphinx" footer
+html_show_sphinx = False
+
+# Don't show copyright info in the footer (we have this content in the page)
+html_show_copyright = False
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = "sphinx_rtd_theme"
+
+# The logo to display in the sidebar
+html_logo = 'resources/TrustedFirmware-Logo_standard-white.png'
+
+# Options for the "sphinx-rtd-theme" theme
+html_theme_options = {
+    'collapse_navigation': False, # Can expand and collapse sidebar entries
+    'prev_next_buttons_location': 'both', # Top and bottom of the page
+    'style_external_links': True # Display an icon next to external links
+}
+
+# -- Options for autosectionlabel --------------------------------------------
+
+# Only generate automatic section labels for document titles
+autosectionlabel_maxdepth = 1
+
+# -- Options for plantuml ----------------------------------------------------
+
+plantuml_output_format = 'svg_img'
diff --git a/docs/contents.rst b/docs/contents.rst
new file mode 100644
index 0000000..4909dab
--- /dev/null
+++ b/docs/contents.rst
@@ -0,0 +1,165 @@
+Trusted Firmware-A Documentation Contents
+=========================================
+
+This document serves as a list of the documentation that is included with the
+Trusted Firmware-A source.
+
+Introduction
+------------
+
+`About Trusted Firmware-A`_
+
+Getting Started
+---------------
+
+`Frequently-Asked Questions (FAQ)`_
+
+`Image Terminology`_
+
+`Porting Guide`_
+
+`User Guide`_
+
+Contributing
+------------
+
+`Coding Style and Guidelines`_
+
+`Contributor Acknowledgements`_
+
+`Contributor's Guide`_
+
+`License`_
+
+`Maintainers`_
+
+Processes and Policies
+----------------------
+
+`Platform Compatibility Policy`_
+
+`Release Processes`_
+
+Secure Payload Dispatch
+-----------------------
+
+`OP-TEE Dispatcher`_
+
+`Trusted Little Kernel (TLK) Dispatcher`_
+
+`Trusty Dispatcher`_
+
+System Design and Components
+----------------------------
+
+`Arm CPU Specific Build Macros`_
+
+`Arm SiP Services`_
+
+`Authentication Framework & Chain of Trust`_
+
+`CPU Reset`_
+
+`EL3 Runtime Service Writer’s Guide`_
+
+`Exception Handling Framework`_
+
+`Firmware Design Overview`_
+
+`Firmware Update (FWU)`_
+
+`Interrupt Management Framework`_
+
+`Library at ROM`_
+
+`Platform Interrupt Controller API`_
+
+`PSCI Library Integration Guide for Armv8-A AArch32 systems`_
+
+`PSCI Power Domain Tree design`_
+
+`Reliability, Availability, and Serviceability (RAS) Extensions`_
+
+`Secure Partition Manager`_
+
+`Software Delegated Exception Interface`_
+
+`Translation (XLAT) Tables Library`_
+
+`Trusted Board Boot Design Guide`_
+
+Performance and Testing
+-----------------------
+
+`PSCI Performance Measurements on Arm Juno Development Platform`_
+
+Security and Advisories
+-----------------------
+
+`Security Processes`_
+
+`TFV-1`_
+
+`TFV-2`_
+
+`TFV-3`_
+
+`TFV-4`_
+
+`TFV-5`_
+
+`TFV-6`_
+
+`TFV-7`_
+
+`TFV-8`_
+
+Other Documents
+---------------
+
+`Change Log`_
+
+.. _About Trusted Firmware-A: ../readme.rst
+.. _Frequently-Asked Questions (FAQ): ./process/faq.rst
+.. _Image Terminology: ./getting_started/image-terminology.rst
+.. _Porting Guide: ./getting_started/porting-guide.rst
+.. _User Guide: ./getting_started/user-guide.rst
+.. _Coding Style and Guidelines: ./process/coding-guidelines.rst
+.. _Contributor Acknowledgements: ./acknowledgements.rst
+.. _`Contributor's Guide`: ./process/contributing.rst
+.. _License: ../license.rst
+.. _Maintainers: ./maintainers.rst
+.. _Platform Compatibility Policy: ./process/platform-compatibility-policy.rst
+.. _Release Processes: ./process/release-information.rst
+.. _Arm SiP Services: ./components/arm-sip-service.rst
+.. _Exception Handling Framework: ./components/exception-handling.rst
+.. _Firmware Update (FWU): ./components/firmware-update.rst
+.. _Interrupt Management Framework: ./design/interrupt-framework-design.rst
+.. _Library at ROM: ./components/romlib-design.rst
+.. _Platform Interrupt Controller API: ./components/platform-interrupt-controller-API.rst
+.. _`Reliability, Availability, and Serviceability (RAS) Extensions`: ./components/ras.rst
+.. _Secure Partition Manager: ./components/secure-partition-manager-design.rst
+.. _Software Delegated Exception Interface: ./components/sdei.rst
+.. _Translation (XLAT) Tables Library: ./components/xlat-tables-lib-v2-design.rst
+.. _OP-TEE Dispatcher: ./components/spd/optee-dispatcher.rst
+.. _Trusted Little Kernel (TLK) Dispatcher: ./components/spd/tlk-dispatcher.rst
+.. _Trusty Dispatcher: ./components/spd/trusty-dispatcher.rst
+.. _Arm CPU Specific Build Macros: ./design/cpu-specific-build-macros.rst
+.. _`Authentication Framework & Chain of Trust`: ./design/auth-framework.rst
+.. _CPU Reset: ./design/reset-design.rst
+.. _`EL3 Runtime Service Writer’s Guide`: ./getting_started/rt-svc-writers-guide.rst
+.. _Firmware Design Overview: ./design/firmware-design.rst
+.. _PSCI Library Integration Guide for Armv8-A AArch32 systems: ./getting_started/psci-lib-integration-guide.rst
+.. _PSCI Power Domain Tree design: ./design/psci-pd-tree.rst
+.. _Trusted Board Boot Design Guide: ./design/trusted-board-boot.rst
+.. _PSCI Performance Measurements on Arm Juno Development Platform: ./perf/psci-performance-juno.rst
+.. _Security Processes: ./process/security.rst
+.. _Change Log: ./change-log.rst
+.. _TFV-1: ./security_advisories/security-advisory-tfv-1.rst
+.. _TFV-2: ./security_advisories/security-advisory-tfv-2.rst
+.. _TFV-3: ./security_advisories/security-advisory-tfv-3.rst
+.. _TFV-4: ./security_advisories/security-advisory-tfv-4.rst
+.. _TFV-5: ./security_advisories/security-advisory-tfv-5.rst
+.. _TFV-6: ./security_advisories/security-advisory-tfv-6.rst
+.. _TFV-7: ./security_advisories/security-advisory-tfv-7.rst
+.. _TFV-8: ./security_advisories/security-advisory-tfv-8.rst
diff --git a/docs/design/auth-framework.rst b/docs/design/auth-framework.rst
new file mode 100644
index 0000000..da958b7
--- /dev/null
+++ b/docs/design/auth-framework.rst
@@ -0,0 +1,968 @@
+Authentication Framework & Chain of Trust
+=========================================
+
+The aim of this document is to describe the authentication framework
+implemented in Trusted Firmware-A (TF-A). This framework fulfills the
+following requirements:
+
+#. It should be possible for a platform port to specify the Chain of Trust in
+   terms of certificate hierarchy and the mechanisms used to verify a
+   particular image/certificate.
+
+#. The framework should distinguish between:
+
+   -  The mechanism used to encode and transport information, e.g. DER encoded
+      X.509v3 certificates to ferry Subject Public Keys, hashes and non-volatile
+      counters.
+
+   -  The mechanism used to verify the transported information i.e. the
+      cryptographic libraries.
+
+The framework has been designed following a modular approach illustrated in the
+next diagram:
+
+::
+
+        +---------------+---------------+------------+
+        | Trusted       | Trusted       | Trusted    |
+        | Firmware      | Firmware      | Firmware   |
+        | Generic       | IO Framework  | Platform   |
+        | Code i.e.     | (IO)          | Port       |
+        | BL1/BL2 (GEN) |               | (PP)       |
+        +---------------+---------------+------------+
+               ^               ^               ^
+               |               |               |
+               v               v               v
+         +-----------+   +-----------+   +-----------+
+         |           |   |           |   | Image     |
+         | Crypto    |   | Auth      |   | Parser    |
+         | Module    |<->| Module    |<->| Module    |
+         | (CM)      |   | (AM)      |   | (IPM)     |
+         |           |   |           |   |           |
+         +-----------+   +-----------+   +-----------+
+               ^                               ^
+               |                               |
+               v                               v
+        +----------------+             +-----------------+
+        | Cryptographic  |             | Image Parser    |
+        | Libraries (CL) |             | Libraries (IPL) |
+        +----------------+             +-----------------+
+                      |                |
+                      |                |
+                      |                |
+                      v                v
+                     +-----------------+
+                     | Misc. Libs e.g. |
+                     | ASN.1 decoder   |
+                     |                 |
+                     +-----------------+
+
+        DIAGRAM 1.
+
+This document describes the inner details of the authentication framework and
+the abstraction mechanisms available to specify a Chain of Trust.
+
+Framework design
+----------------
+
+This section describes some aspects of the framework design and the rationale
+behind them. These aspects are key to verify a Chain of Trust.
+
+Chain of Trust
+~~~~~~~~~~~~~~
+
+A CoT is basically a sequence of authentication images which usually starts with
+a root of trust and culminates in a single data image. The following diagram
+illustrates how this maps to a CoT for the BL31 image described in the
+`TBBR-Client specification`_.
+
+::
+
+        +------------------+       +-------------------+
+        | ROTPK/ROTPK Hash |------>| Trusted Key       |
+        +------------------+       | Certificate       |
+                                   | (Auth Image)      |
+                                  /+-------------------+
+                                 /            |
+                                /             |
+                               /              |
+                              /               |
+                             L                v
+        +------------------+       +-------------------+
+        | Trusted World    |------>| BL31 Key          |
+        | Public Key       |       | Certificate       |
+        +------------------+       | (Auth Image)      |
+                                   +-------------------+
+                                  /           |
+                                 /            |
+                                /             |
+                               /              |
+                              /               v
+        +------------------+ L     +-------------------+
+        | BL31 Content     |------>| BL31 Content      |
+        | Certificate PK   |       | Certificate       |
+        +------------------+       | (Auth Image)      |
+                                   +-------------------+
+                                  /           |
+                                 /            |
+                                /             |
+                               /              |
+                              /               v
+        +------------------+ L     +-------------------+
+        | BL31 Hash        |------>| BL31 Image        |
+        |                  |       | (Data Image)      |
+        +------------------+       |                   |
+                                   +-------------------+
+
+        DIAGRAM 2.
+
+The root of trust is usually a public key (ROTPK) that has been burnt in the
+platform and cannot be modified.
+
+Image types
+~~~~~~~~~~~
+
+Images in a CoT are categorised as authentication and data images. An
+authentication image contains information to authenticate a data image or
+another authentication image. A data image is usually a boot loader binary, but
+it could be any other data that requires authentication.
+
+Component responsibilities
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For every image in a Chain of Trust, the following high level operations are
+performed to verify it:
+
+#. Allocate memory for the image either statically or at runtime.
+
+#. Identify the image and load it in the allocated memory.
+
+#. Check the integrity of the image as per its type.
+
+#. Authenticate the image as per the cryptographic algorithms used.
+
+#. If the image is an authentication image, extract the information that will
+   be used to authenticate the next image in the CoT.
+
+In Diagram 1, each component is responsible for one or more of these operations.
+The responsibilities are briefly described below.
+
+TF-A Generic code and IO framework (GEN/IO)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+These components are responsible for initiating the authentication process for a
+particular image in BL1 or BL2. For each BL image that requires authentication,
+the Generic code asks recursively the Authentication module what is the parent
+image until either an authenticated image or the ROT is reached. Then the
+Generic code calls the IO framework to load the image and calls the
+Authentication module to authenticate it, following the CoT from ROT to Image.
+
+TF-A Platform Port (PP)
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The platform is responsible for:
+
+#. Specifying the CoT for each image that needs to be authenticated. Details of
+   how a CoT can be specified by the platform are explained later. The platform
+   also specifies the authentication methods and the parsing method used for
+   each image.
+
+#. Statically allocating memory for each parameter in each image which is
+   used for verifying the CoT, e.g. memory for public keys, hashes etc.
+
+#. Providing the ROTPK or a hash of it.
+
+#. Providing additional information to the IPM to enable it to identify and
+   extract authentication parameters contained in an image, e.g. if the
+   parameters are stored as X509v3 extensions, the corresponding OID must be
+   provided.
+
+#. Fulfill any other memory requirements of the IPM and the CM (not currently
+   described in this document).
+
+#. Export functions to verify an image which uses an authentication method that
+   cannot be interpreted by the CM, e.g. if an image has to be verified using a
+   NV counter, then the value of the counter to compare with can only be
+   provided by the platform.
+
+#. Export a custom IPM if a proprietary image format is being used (described
+   later).
+
+Authentication Module (AM)
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It is responsible for:
+
+#. Providing the necessary abstraction mechanisms to describe a CoT. Amongst
+   other things, the authentication and image parsing methods must be specified
+   by the PP in the CoT.
+
+#. Verifying the CoT passed by GEN by utilising functionality exported by the
+   PP, IPM and CM.
+
+#. Tracking which images have been verified. In case an image is a part of
+   multiple CoTs then it should be verified only once e.g. the Trusted World
+   Key Certificate in the TBBR-Client spec. contains information to verify
+   SCP_BL2, BL31, BL32 each of which have a separate CoT. (This
+   responsibility has not been described in this document but should be
+   trivial to implement).
+
+#. Reusing memory meant for a data image to verify authentication images e.g.
+   in the CoT described in Diagram 2, each certificate can be loaded and
+   verified in the memory reserved by the platform for the BL31 image. By the
+   time BL31 (the data image) is loaded, all information to authenticate it
+   will have been extracted from the parent image i.e. BL31 content
+   certificate. It is assumed that the size of an authentication image will
+   never exceed the size of a data image. It should be possible to verify this
+   at build time using asserts.
+
+Cryptographic Module (CM)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The CM is responsible for providing an API to:
+
+#. Verify a digital signature.
+#. Verify a hash.
+
+The CM does not include any cryptography related code, but it relies on an
+external library to perform the cryptographic operations. A Crypto-Library (CL)
+linking the CM and the external library must be implemented. The following
+functions must be provided by the CL:
+
+.. code:: c
+
+    void (*init)(void);
+    int (*verify_signature)(void *data_ptr, unsigned int data_len,
+                            void *sig_ptr, unsigned int sig_len,
+                            void *sig_alg, unsigned int sig_alg_len,
+                            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);
+
+These functions are registered in the CM using the macro:
+
+.. code:: c
+
+    REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash);
+
+``_name`` must be a string containing the name of the CL. This name is used for
+debugging purposes.
+
+Image Parser Module (IPM)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The IPM is responsible for:
+
+#. Checking the integrity of each image loaded by the IO framework.
+#. Extracting parameters used for authenticating an image based upon a
+   description provided by the platform in the CoT descriptor.
+
+Images may have different formats (for example, authentication images could be
+x509v3 certificates, signed ELF files or any other platform specific format).
+The IPM allows to register an Image Parser Library (IPL) for every image format
+used in the CoT. This library must implement the specific methods to parse the
+image. The IPM obtains the image format from the CoT and calls the right IPL to
+check the image integrity and extract the authentication parameters.
+
+See Section "Describing the image parsing methods" for more details about the
+mechanism the IPM provides to define and register IPLs.
+
+Authentication methods
+~~~~~~~~~~~~~~~~~~~~~~
+
+The AM supports the following authentication methods:
+
+#. Hash
+#. Digital signature
+
+The platform may specify these methods in the CoT in case it decides to define
+a custom CoT instead of reusing a predefined one.
+
+If a data image uses multiple methods, then all the methods must be a part of
+the same CoT. The number and type of parameters are method specific. These
+parameters should be obtained from the parent image using the IPM.
+
+#. Hash
+
+   Parameters:
+
+   #. A pointer to data to hash
+   #. Length of the data
+   #. A pointer to the hash
+   #. Length of the hash
+
+   The hash will be represented by the DER encoding of the following ASN.1
+   type:
+
+   ::
+
+       DigestInfo ::= SEQUENCE {
+           digestAlgorithm  DigestAlgorithmIdentifier,
+           digest           Digest
+       }
+
+   This ASN.1 structure makes it possible to remove any assumption about the
+   type of hash algorithm used as this information accompanies the hash. This
+   should allow the Cryptography Library (CL) to support multiple hash
+   algorithm implementations.
+
+#. Digital Signature
+
+   Parameters:
+
+   #. A pointer to data to sign
+   #. Length of the data
+   #. Public Key Algorithm
+   #. Public Key value
+   #. Digital Signature Algorithm
+   #. Digital Signature value
+
+   The Public Key parameters will be represented by the DER encoding of the
+   following ASN.1 type:
+
+   ::
+
+       SubjectPublicKeyInfo  ::=  SEQUENCE  {
+           algorithm         AlgorithmIdentifier{PUBLIC-KEY,{PublicKeyAlgorithms}},
+           subjectPublicKey  BIT STRING  }
+
+   The Digital Signature Algorithm will be represented by the DER encoding of
+   the following ASN.1 types.
+
+   ::
+
+       AlgorithmIdentifier {ALGORITHM:IOSet } ::= SEQUENCE {
+           algorithm         ALGORITHM.&id({IOSet}),
+           parameters        ALGORITHM.&Type({IOSet}{@algorithm}) OPTIONAL
+       }
+
+   The digital signature will be represented by:
+
+   ::
+
+       signature  ::=  BIT STRING
+
+The authentication framework will use the image descriptor to extract all the
+information related to authentication.
+
+Specifying a Chain of Trust
+---------------------------
+
+A CoT can be described as a set of image descriptors linked together in a
+particular order. The order dictates the sequence in which they must be
+verified. Each image has a set of properties which allow the AM to verify it.
+These properties are described below.
+
+The PP is responsible for defining a single or multiple CoTs for a data image.
+Unless otherwise specified, the data structures described in the following
+sections are populated by the PP statically.
+
+Describing the image parsing methods
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The parsing method refers to the format of a particular image. For example, an
+authentication image that represents a certificate could be in the X.509v3
+format. A data image that represents a boot loader stage could be in raw binary
+or ELF format. The IPM supports three parsing methods. An image has to use one
+of the three methods described below. An IPL is responsible for interpreting a
+single parsing method. There has to be one IPL for every method used by the
+platform.
+
+#. Raw format: This format is effectively a nop as an image using this method
+   is treated as being in raw binary format e.g. boot loader images used by
+   TF-A. This method should only be used by data images.
+
+#. X509V3 method: This method uses industry standards like X.509 to represent
+   PKI certificates (authentication images). It is expected that open source
+   libraries will be available which can be used to parse an image represented
+   by this method. Such libraries can be used to write the corresponding IPL
+   e.g. the X.509 parsing library code in mbed TLS.
+
+#. Platform defined method: This method caters for platform specific
+   proprietary standards to represent authentication or data images. For
+   example, The signature of a data image could be appended to the data image
+   raw binary. A header could be prepended to the combined blob to specify the
+   extents of each component. The platform will have to implement the
+   corresponding IPL to interpret such a format.
+
+The following enum can be used to define these three methods.
+
+.. code:: c
+
+    typedef enum img_type_enum {
+        IMG_RAW,            /* Binary image */
+        IMG_PLAT,           /* Platform specific format */
+        IMG_CERT,           /* X509v3 certificate */
+        IMG_MAX_TYPES,
+    } img_type_t;
+
+An IPL must provide functions with the following prototypes:
+
+.. code:: c
+
+    void init(void);
+    int check_integrity(void *img, unsigned int img_len);
+    int get_auth_param(const auth_param_type_desc_t *type_desc,
+                          void *img, unsigned int img_len,
+                          void **param, unsigned int *param_len);
+
+An IPL for each type must be registered using the following macro:
+
+.. code:: c
+
+    REGISTER_IMG_PARSER_LIB(_type, _name, _init, _check_int, _get_param)
+
+-  ``_type``: one of the types described above.
+-  ``_name``: a string containing the IPL name for debugging purposes.
+-  ``_init``: initialization function pointer.
+-  ``_check_int``: check image integrity function pointer.
+-  ``_get_param``: extract authentication parameter function pointer.
+
+The ``init()`` function will be used to initialize the IPL.
+
+The ``check_integrity()`` function is passed a pointer to the memory where the
+image has been loaded by the IO framework and the image length. It should ensure
+that the image is in the format corresponding to the parsing method and has not
+been tampered with. For example, RFC-2459 describes a validation sequence for an
+X.509 certificate.
+
+The ``get_auth_param()`` function is passed a parameter descriptor containing
+information about the parameter (``type_desc`` and ``cookie``) to identify and
+extract the data corresponding to that parameter from an image. This data will
+be used to verify either the current or the next image in the CoT sequence.
+
+Each image in the CoT will specify the parsing method it uses. This information
+will be used by the IPM to find the right parser descriptor for the image.
+
+Describing the authentication method(s)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As part of the CoT, each image has to specify one or more authentication methods
+which will be used to verify it. As described in the Section "Authentication
+methods", there are three methods supported by the AM.
+
+.. code:: c
+
+    typedef enum {
+        AUTH_METHOD_NONE,
+        AUTH_METHOD_HASH,
+        AUTH_METHOD_SIG,
+        AUTH_METHOD_NUM
+    } auth_method_type_t;
+
+The AM defines the type of each parameter used by an authentication method. It
+uses this information to:
+
+#. Specify to the ``get_auth_param()`` function exported by the IPM, which
+   parameter should be extracted from an image.
+
+#. Correctly marshall the parameters while calling the verification function
+   exported by the CM and PP.
+
+#. Extract authentication parameters from a parent image in order to verify a
+   child image e.g. to verify the certificate image, the public key has to be
+   obtained from the parent image.
+
+.. code:: c
+
+    typedef enum {
+        AUTH_PARAM_NONE,
+        AUTH_PARAM_RAW_DATA,        /* Raw image data */
+        AUTH_PARAM_SIG,         /* The image signature */
+        AUTH_PARAM_SIG_ALG,     /* The image signature algorithm */
+        AUTH_PARAM_HASH,        /* A hash (including the algorithm) */
+        AUTH_PARAM_PUB_KEY,     /* A public key */
+    } auth_param_type_t;
+
+The AM defines the following structure to identify an authentication parameter
+required to verify an image.
+
+.. code:: c
+
+    typedef struct auth_param_type_desc_s {
+        auth_param_type_t type;
+        void *cookie;
+    } auth_param_type_desc_t;
+
+``cookie`` is used by the platform to specify additional information to the IPM
+which enables it to uniquely identify the parameter that should be extracted
+from an image. For example, the hash of a BL3x image in its corresponding
+content certificate is stored in an X509v3 custom extension field. An extension
+field can only be identified using an OID. In this case, the ``cookie`` could
+contain the pointer to the OID defined by the platform for the hash extension
+field while the ``type`` field could be set to ``AUTH_PARAM_HASH``. A value of 0 for
+the ``cookie`` field means that it is not used.
+
+For each method, the AM defines a structure with the parameters required to
+verify the image.
+
+.. code:: c
+
+    /*
+     * Parameters for authentication by hash matching
+     */
+    typedef struct auth_method_param_hash_s {
+        auth_param_type_desc_t *data;   /* Data to hash */
+        auth_param_type_desc_t *hash;   /* Hash to match with */
+    } auth_method_param_hash_t;
+
+    /*
+     * Parameters for authentication by signature
+     */
+    typedef struct auth_method_param_sig_s {
+        auth_param_type_desc_t *pk; /* Public key */
+        auth_param_type_desc_t *sig;    /* Signature to check */
+        auth_param_type_desc_t *alg;    /* Signature algorithm */
+        auth_param_type_desc_t *tbs;    /* Data signed */
+    } auth_method_param_sig_t;
+
+The AM defines the following structure to describe an authentication method for
+verifying an image
+
+.. code:: c
+
+    /*
+     * Authentication method descriptor
+     */
+    typedef struct auth_method_desc_s {
+        auth_method_type_t type;
+        union {
+            auth_method_param_hash_t hash;
+            auth_method_param_sig_t sig;
+        } param;
+    } auth_method_desc_t;
+
+Using the method type specified in the ``type`` field, the AM finds out what field
+needs to access within the ``param`` union.
+
+Storing Authentication parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A parameter described by ``auth_param_type_desc_t`` to verify an image could be
+obtained from either the image itself or its parent image. The memory allocated
+for loading the parent image will be reused for loading the child image. Hence
+parameters which are obtained from the parent for verifying a child image need
+to have memory allocated for them separately where they can be stored. This
+memory must be statically allocated by the platform port.
+
+The AM defines the following structure to store the data corresponding to an
+authentication parameter.
+
+.. code:: c
+
+    typedef struct auth_param_data_desc_s {
+        void *auth_param_ptr;
+        unsigned int auth_param_len;
+    } auth_param_data_desc_t;
+
+The ``auth_param_ptr`` field is initialized by the platform. The ``auth_param_len``
+field is used to specify the length of the data in the memory.
+
+For parameters that can be obtained from the child image itself, the IPM is
+responsible for populating the ``auth_param_ptr`` and ``auth_param_len`` fields
+while executing the ``img_get_auth_param()`` function.
+
+The AM defines the following structure to enable an image to describe the
+parameters that should be extracted from it and used to verify the next image
+(child) in a CoT.
+
+.. code:: c
+
+    typedef struct auth_param_desc_s {
+        auth_param_type_desc_t type_desc;
+        auth_param_data_desc_t data;
+    } auth_param_desc_t;
+
+Describing an image in a CoT
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An image in a CoT is a consolidation of the following aspects of a CoT described
+above.
+
+#. A unique identifier specified by the platform which allows the IO framework
+   to locate the image in a FIP and load it in the memory reserved for the data
+   image in the CoT.
+
+#. A parsing method which is used by the AM to find the appropriate IPM.
+
+#. Authentication methods and their parameters as described in the previous
+   section. These are used to verify the current image.
+
+#. Parameters which are used to verify the next image in the current CoT. These
+   parameters are specified only by authentication images and can be extracted
+   from the current image once it has been verified.
+
+The following data structure describes an image in a CoT.
+
+.. code:: c
+
+    typedef struct auth_img_desc_s {
+        unsigned int img_id;
+        const struct auth_img_desc_s *parent;
+        img_type_t img_type;
+        const auth_method_desc_t *const img_auth_methods;
+        const auth_param_desc_t *const authenticated_data;
+    } auth_img_desc_t;
+
+A CoT is defined as an array of pointers to ``auth_image_desc_t`` structures
+linked together by the ``parent`` field. Those nodes with no parent must be
+authenticated using the ROTPK stored in the platform.
+
+Implementation example
+----------------------
+
+This section is a detailed guide explaining a trusted boot implementation using
+the authentication framework. This example corresponds to the Applicative
+Functional Mode (AFM) as specified in the TBBR-Client document. It is
+recommended to read this guide along with the source code.
+
+The TBBR CoT
+~~~~~~~~~~~~
+
+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
+of the array (passing a pointer or any other type of indirection will cause the
+registration process to fail).
+
+The number of images participating in the boot process depends on the CoT.
+There is, however, a minimum set of images that are mandatory in TF-A and thus
+all CoTs must present:
+
+-  ``BL2``
+-  ``SCP_BL2`` (platform specific)
+-  ``BL31``
+-  ``BL32`` (optional)
+-  ``BL33``
+
+The TBBR specifies the additional certificates that must accompany these images
+for a proper authentication. Details about the TBBR CoT may be found in the
+`Trusted Board Boot`_ document.
+
+Following the `Platform Porting Guide`_, a platform must provide unique
+identifiers for all the images and certificates that will be loaded during the
+boot process. If a platform is using the TBBR as a reference for trusted boot,
+these identifiers can be obtained from ``include/common/tbbr/tbbr_img_def.h``.
+Arm platforms include this file in ``include/plat/arm/common/arm_def.h``. Other
+platforms may also include this file or provide their own identifiers.
+
+**Important**: the authentication module uses these identifiers to index the
+CoT array, so the descriptors location in the array must match the identifiers.
+
+Each image descriptor must specify:
+
+-  ``img_id``: the corresponding image unique identifier defined by the platform.
+-  ``img_type``: the image parser module uses the image type to call the proper
+   parsing library to check the image integrity and extract the required
+   authentication parameters. Three types of images are currently supported:
+
+   -  ``IMG_RAW``: image is a raw binary. No parsing functions are available,
+      other than reading the whole image.
+   -  ``IMG_PLAT``: image format is platform specific. The platform may use this
+      type for custom images not directly supported by the authentication
+      framework.
+   -  ``IMG_CERT``: image is an x509v3 certificate.
+
+-  ``parent``: pointer to the parent image descriptor. The parent will contain
+   the information required to authenticate the current image. If the parent
+   is NULL, the authentication parameters will be obtained from the platform
+   (i.e. the BL2 and Trusted Key certificates are signed with the ROT private
+   key, whose public part is stored in the platform).
+-  ``img_auth_methods``: this points to an array which defines the
+   authentication methods that must be checked to consider an image
+   authenticated. Each method consists of a type and a list of parameter
+   descriptors. A parameter descriptor consists of a type and a cookie which
+   will point to specific information required to extract that parameter from
+   the image (i.e. if the parameter is stored in an x509v3 extension, the
+   cookie will point to the extension OID). Depending on the method type, a
+   different number of parameters must be specified. This pointer should not be
+   NULL.
+   Supported methods are:
+
+   -  ``AUTH_METHOD_HASH``: the hash of the image must match the hash extracted
+      from the parent image. The following parameter descriptors must be
+      specified:
+
+      -  ``data``: data to be hashed (obtained from current image)
+      -  ``hash``: reference hash (obtained from parent image)
+
+   -  ``AUTH_METHOD_SIG``: the image (usually a certificate) must be signed with
+      the private key whose public part is extracted from the parent image (or
+      the platform if the parent is NULL). The following parameter descriptors
+      must be specified:
+
+      -  ``pk``: the public key (obtained from parent image)
+      -  ``sig``: the digital signature (obtained from current image)
+      -  ``alg``: the signature algorithm used (obtained from current image)
+      -  ``data``: the data to be signed (obtained from current image)
+
+-  ``authenticated_data``: this array pointer indicates what authentication
+   parameters must be extracted from an image once it has been authenticated.
+   Each parameter consists of a parameter descriptor and the buffer
+   address/size to store the parameter. The CoT is responsible for allocating
+   the required memory to store the parameters. This pointer may be NULL.
+
+In the ``tbbr_cot.c`` file, a set of buffers are allocated to store the parameters
+extracted from the certificates. In the case of the TBBR CoT, these parameters
+are hashes and public keys. In DER format, an RSA-2048 public key requires 294
+bytes, and a hash requires 51 bytes. Depending on the CoT and the authentication
+process, some of the buffers may be reused at different stages during the boot.
+
+Next in that file, the parameter descriptors are defined. These descriptors will
+be used to extract the parameter data from the corresponding image.
+
+Example: the BL31 Chain of Trust
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Four image descriptors form the BL31 Chain of Trust:
+
+.. code:: c
+
+    static const auth_img_desc_t trusted_key_cert = {
+            .img_id = TRUSTED_KEY_CERT_ID,
+            .img_type = IMG_CERT,
+            .parent = NULL,
+            .img_auth_methods =  (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+                    [0] = {
+                            .type = AUTH_METHOD_SIG,
+                            .param.sig = {
+                                    .pk = &subject_pk,
+                                    .sig = &sig,
+                                    .alg = &sig_alg,
+                                    .data = &raw_data
+                            }
+                    },
+                    [1] = {
+                            .type = AUTH_METHOD_NV_CTR,
+                            .param.nv_ctr = {
+                                    .cert_nv_ctr = &trusted_nv_ctr,
+                                    .plat_nv_ctr = &trusted_nv_ctr
+                            }
+                    }
+            },
+            .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+                    [0] = {
+                            .type_desc = &trusted_world_pk,
+                            .data = {
+                                    .ptr = (void *)trusted_world_pk_buf,
+                                    .len = (unsigned int)PK_DER_LEN
+                            }
+                    },
+                    [1] = {
+                            .type_desc = &non_trusted_world_pk,
+                            .data = {
+                                    .ptr = (void *)non_trusted_world_pk_buf,
+                                    .len = (unsigned int)PK_DER_LEN
+                            }
+                    }
+            }
+    };
+    static const auth_img_desc_t soc_fw_key_cert = {
+            .img_id = SOC_FW_KEY_CERT_ID,
+            .img_type = IMG_CERT,
+            .parent = &trusted_key_cert,
+            .img_auth_methods =  (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+                    [0] = {
+                            .type = AUTH_METHOD_SIG,
+                            .param.sig = {
+                                    .pk = &trusted_world_pk,
+                                    .sig = &sig,
+                                    .alg = &sig_alg,
+                                    .data = &raw_data
+                            }
+                    },
+                    [1] = {
+                            .type = AUTH_METHOD_NV_CTR,
+                            .param.nv_ctr = {
+                                    .cert_nv_ctr = &trusted_nv_ctr,
+                                    .plat_nv_ctr = &trusted_nv_ctr
+                            }
+                    }
+            },
+            .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+                    [0] = {
+                            .type_desc = &soc_fw_content_pk,
+                            .data = {
+                                    .ptr = (void *)content_pk_buf,
+                                    .len = (unsigned int)PK_DER_LEN
+                            }
+                    }
+            }
+    };
+    static const auth_img_desc_t soc_fw_content_cert = {
+            .img_id = SOC_FW_CONTENT_CERT_ID,
+            .img_type = IMG_CERT,
+            .parent = &soc_fw_key_cert,
+            .img_auth_methods =  (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+                    [0] = {
+                            .type = AUTH_METHOD_SIG,
+                            .param.sig = {
+                                    .pk = &soc_fw_content_pk,
+                                    .sig = &sig,
+                                    .alg = &sig_alg,
+                                    .data = &raw_data
+                            }
+                    },
+                    [1] = {
+                            .type = AUTH_METHOD_NV_CTR,
+                            .param.nv_ctr = {
+                                    .cert_nv_ctr = &trusted_nv_ctr,
+                                    .plat_nv_ctr = &trusted_nv_ctr
+                            }
+                    }
+            },
+            .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+                    [0] = {
+                            .type_desc = &soc_fw_hash,
+                            .data = {
+                                    .ptr = (void *)soc_fw_hash_buf,
+                                    .len = (unsigned int)HASH_DER_LEN
+                            }
+                    },
+                    [1] = {
+                            .type_desc = &soc_fw_config_hash,
+                            .data = {
+                                    .ptr = (void *)soc_fw_config_hash_buf,
+                                    .len = (unsigned int)HASH_DER_LEN
+                            }
+                    }
+            }
+    };
+    static const auth_img_desc_t bl31_image = {
+            .img_id = BL31_IMAGE_ID,
+            .img_type = IMG_RAW,
+            .parent = &soc_fw_content_cert,
+            .img_auth_methods =  (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+                    [0] = {
+                            .type = AUTH_METHOD_HASH,
+                            .param.hash = {
+                                    .data = &raw_data,
+                                    .hash = &soc_fw_hash
+                            }
+                    }
+            }
+    };
+
+The **Trusted Key certificate** is signed with the ROT private key and contains
+the Trusted World public key and the Non-Trusted World public key as x509v3
+extensions. This must be specified in the image descriptor using the
+``img_auth_methods`` and ``authenticated_data`` arrays, respectively.
+
+The Trusted Key certificate is authenticated by checking its digital signature
+using the ROTPK. Four parameters are required to check a signature: the public
+key, the algorithm, the signature and the data that has been signed. Therefore,
+four parameter descriptors must be specified with the authentication method:
+
+-  ``subject_pk``: parameter descriptor of type ``AUTH_PARAM_PUB_KEY``. This type
+   is used to extract a public key from the parent image. If the cookie is an
+   OID, the key is extracted from the corresponding x509v3 extension. If the
+   cookie is NULL, the subject public key is retrieved. In this case, because
+   the parent image is NULL, the public key is obtained from the platform
+   (this key will be the ROTPK).
+-  ``sig``: parameter descriptor of type ``AUTH_PARAM_SIG``. It is used to extract
+   the signature from the certificate.
+-  ``sig_alg``: parameter descriptor of type ``AUTH_PARAM_SIG``. It is used to
+   extract the signature algorithm from the certificate.
+-  ``raw_data``: parameter descriptor of type ``AUTH_PARAM_RAW_DATA``. It is used
+   to extract the data to be signed from the certificate.
+
+Once the signature has been checked and the certificate authenticated, the
+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
+``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.
+
+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.
+
+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.
+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.
+
+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 image parser library
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The image parser module relies on libraries to check the image integrity and
+extract the authentication parameters. The number and type of parser libraries
+depend on the images used in the CoT. Raw images do not need a library, so
+only an x509v3 library is required for the TBBR CoT.
+
+Arm platforms will use an x509v3 library based on mbed TLS. This library may be
+found in ``drivers/auth/mbedtls/mbedtls_x509_parser.c``. It exports three
+functions:
+
+.. code:: c
+
+    void init(void);
+    int check_integrity(void *img, unsigned int img_len);
+    int get_auth_param(const auth_param_type_desc_t *type_desc,
+                       void *img, unsigned int img_len,
+                       void **param, unsigned int *param_len);
+
+The library is registered in the framework using the macro
+``REGISTER_IMG_PARSER_LIB()``. Each time the image parser module needs to access
+an image of type ``IMG_CERT``, it will call the corresponding function exported
+in this file.
+
+The build system must be updated to include the corresponding library and
+mbed TLS sources. Arm platforms use the ``arm_common.mk`` file to pull the
+sources.
+
+The cryptographic library
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The cryptographic module relies on a library to perform the required operations,
+i.e. verify a hash or a digital signature. Arm platforms will use a library
+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:
+
+.. code:: c
+
+    void init(void);
+    int verify_signature(void *data_ptr, unsigned int data_len,
+                         void *sig_ptr, unsigned int sig_len,
+                         void *sig_alg, unsigned int sig_alg_len,
+                         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);
+
+The mbedTLS library algorithm support is configured by the
+``TF_MBEDTLS_KEY_ALG`` variable which can take in 3 values: `rsa`, `ecdsa` or
+`rsa+ecdsa`. This variable allows the Makefile to include the corresponding
+sources in the build for the various algorithms. Setting the variable to
+`rsa+ecdsa` enables support for both rsa and ecdsa algorithms in the mbedTLS
+library.
+
+.. 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
+   implementation of SHA-256 with smaller memory footprint (~1.5 KB less) but
+   slower (~30%).
+
+--------------
+
+*Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Trusted Board Boot: ./trusted-board-boot.rst
+.. _Platform Porting Guide: ../getting_started/porting-guide.rst
+.. _TBBR-Client specification: https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
new file mode 100644
index 0000000..d3fe89d
--- /dev/null
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -0,0 +1,328 @@
+Arm CPU Specific Build Macros
+=============================
+
+This document describes the various build options present in the CPU specific
+operations framework to enable errata workarounds and to enable optimizations
+for a specific CPU on a platform.
+
+Security Vulnerability Workarounds
+----------------------------------
+
+TF-A exports a series of build flags which control which security
+vulnerability workarounds should be applied at runtime.
+
+-  ``WORKAROUND_CVE_2017_5715``: Enables the security workaround for
+   `CVE-2017-5715`_. This flag can be set to 0 by the platform if none
+   of the PEs in the system need the workaround. Setting this flag to 0 provides
+   no performance benefit for non-affected platforms, it just helps to comply
+   with the recommendation in the spec regarding workaround discovery.
+   Defaults to 1.
+
+-  ``WORKAROUND_CVE_2018_3639``: Enables the security workaround for
+   `CVE-2018-3639`_. Defaults to 1. The TF-A project recommends to keep
+   the default value of 1 even on platforms that are unaffected by
+   CVE-2018-3639, in order to comply with the recommendation in the spec
+   regarding workaround discovery.
+
+-  ``DYNAMIC_WORKAROUND_CVE_2018_3639``: Enables dynamic mitigation for
+   `CVE-2018-3639`_. This build option should be set to 1 if the target
+   platform contains at least 1 CPU that requires dynamic mitigation.
+   Defaults to 0.
+
+CPU Errata Workarounds
+----------------------
+
+TF-A exports a series of build flags which control the errata workarounds that
+are applied to each CPU by the reset handler. The errata details can be found
+in the CPU specific errata documents published by Arm:
+
+-  `Cortex-A53 MPCore Software Developers Errata Notice`_
+-  `Cortex-A57 MPCore Software Developers Errata Notice`_
+-  `Cortex-A72 MPCore Software Developers Errata Notice`_
+
+The errata workarounds are implemented for a particular revision or a set of
+processor revisions. This is checked by the reset handler at runtime. Each
+errata workaround is identified by its ``ID`` as specified in the processor's
+errata notice document. The format of the define used to enable/disable the
+errata workaround is ``ERRATA_<Processor name>_<ID>``, where the ``Processor name``
+is for example ``A57`` for the ``Cortex_A57`` CPU.
+
+Refer to the section *CPU errata status reporting* in
+`Firmware Design guide`_ for information on how to write errata workaround
+functions.
+
+All workarounds are disabled by default. The platform is responsible for
+enabling these workarounds according to its requirement by defining the
+errata workaround build flags in the platform specific makefile. In case
+these workarounds are enabled for the wrong CPU revision then the errata
+workaround is not applied. In the DEBUG build, this is indicated by
+printing a warning to the crash console.
+
+In the current implementation, a platform which has more than 1 variant
+with different revisions of a processor has no runtime mechanism available
+for it to specify which errata workarounds should be enabled or not.
+
+The value of the build flags is 0 by default, that is, disabled. A value of 1
+will enable it.
+
+For Cortex-A9, the following errata build flags are defined :
+
+-  ``ERRATA_A9_794073``: This applies errata 794073 workaround to Cortex-A9
+   CPU. This needs to be enabled for all revisions of the CPU.
+
+For Cortex-A15, the following errata build flags are defined :
+
+-  ``ERRATA_A15_816470``: This applies errata 816470 workaround to Cortex-A15
+   CPU. This needs to be enabled only for revision >= r3p0 of the CPU.
+
+-  ``ERRATA_A15_827671``: This applies errata 827671 workaround to Cortex-A15
+   CPU. This needs to be enabled only for revision >= r3p0 of the CPU.
+
+For Cortex-A17, the following errata build flags are defined :
+
+-  ``ERRATA_A17_852421``: This applies errata 852421 workaround to Cortex-A17
+   CPU. This needs to be enabled only for revision <= r1p2 of the CPU.
+
+-  ``ERRATA_A17_852423``: This applies errata 852423 workaround to Cortex-A17
+   CPU. This needs to be enabled only for revision <= r1p2 of the CPU.
+
+For Cortex-A35, the following errata build flags are defined :
+
+-  ``ERRATA_A35_855472``: This applies errata 855472 workaround to Cortex-A35
+   CPUs. This needs to be enabled only for revision r0p0 of Cortex-A35.
+
+For Cortex-A53, the following errata build flags are defined :
+
+-  ``ERRATA_A53_819472``: This applies errata 819472 workaround to all
+   CPUs. This needs to be enabled only for revision <= r0p1 of Cortex-A53.
+
+-  ``ERRATA_A53_824069``: This applies errata 824069 workaround to all
+   CPUs. This needs to be enabled only for revision <= r0p2 of Cortex-A53.
+
+-  ``ERRATA_A53_826319``: This applies errata 826319 workaround to Cortex-A53
+   CPU. This needs to be enabled only for revision <= r0p2 of the CPU.
+
+-  ``ERRATA_A53_827319``: This applies errata 827319 workaround to all
+   CPUs. This needs to be enabled only for revision <= r0p2 of Cortex-A53.
+
+-  ``ERRATA_A53_835769``: This applies erratum 835769 workaround at compile and
+   link time to Cortex-A53 CPU. This needs to be enabled for some variants of
+   revision <= r0p4. This workaround can lead the linker to create ``*.stub``
+   sections.
+
+-  ``ERRATA_A53_836870``: This applies errata 836870 workaround to Cortex-A53
+   CPU. This needs to be enabled only for revision <= r0p3 of the CPU. From
+   r0p4 and onwards, this errata is enabled by default in hardware.
+
+-  ``ERRATA_A53_843419``: This applies erratum 843419 workaround at link time
+   to Cortex-A53 CPU.  This needs to be enabled for some variants of revision
+   <= r0p4. This workaround can lead the linker to emit ``*.stub`` sections
+   which are 4kB aligned.
+
+-  ``ERRATA_A53_855873``: This applies errata 855873 workaround to Cortex-A53
+   CPUs. Though the erratum is present in every revision of the CPU,
+   this workaround is only applied to CPUs from r0p3 onwards, which feature
+   a chicken bit in CPUACTLR_EL1 to enable a hardware workaround.
+   Earlier revisions of the CPU have other errata which require the same
+   workaround in software, so they should be covered anyway.
+
+For Cortex-A55, the following errata build flags are defined :
+
+-  ``ERRATA_A55_768277``: This applies errata 768277 workaround to Cortex-A55
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A55_778703``: This applies errata 778703 workaround to Cortex-A55
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A55_798797``: This applies errata 798797 workaround to Cortex-A55
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A55_846532``: This applies errata 846532 workaround to Cortex-A55
+   CPU. This needs to be enabled only for revision <= r0p1 of the CPU.
+
+-  ``ERRATA_A55_903758``: This applies errata 903758 workaround to Cortex-A55
+   CPU. This needs to be enabled only for revision <= r0p1 of the CPU.
+
+-  ``ERRATA_A55_1221012``: This applies errata 1221012 workaround to Cortex-A55
+   CPU. This needs to be enabled only for revision <= r1p0 of the CPU.
+
+For Cortex-A57, the following errata build flags are defined :
+
+-  ``ERRATA_A57_806969``: This applies errata 806969 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A57_813419``: This applies errata 813419 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A57_813420``: This applies errata 813420 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A57_814670``: This applies errata 814670 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A57_817169``: This applies errata 817169 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r0p1 of the CPU.
+
+-  ``ERRATA_A57_826974``: This applies errata 826974 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
+
+-  ``ERRATA_A57_826977``: This applies errata 826977 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
+
+-  ``ERRATA_A57_828024``: This applies errata 828024 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r1p1 of the CPU.
+
+-  ``ERRATA_A57_829520``: This applies errata 829520 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r1p2 of the CPU.
+
+-  ``ERRATA_A57_833471``: This applies errata 833471 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r1p2 of the CPU.
+
+-  ``ERRATA_A57_859972``: This applies errata 859972 workaround to Cortex-A57
+   CPU. This needs to be enabled only for revision <= r1p3 of the CPU.
+
+
+For Cortex-A72, the following errata build flags are defined :
+
+-  ``ERRATA_A72_859971``: This applies errata 859971 workaround to Cortex-A72
+   CPU. This needs to be enabled only for revision <= r0p3 of the CPU.
+
+For Cortex-A73, the following errata build flags are defined :
+
+-  ``ERRATA_A73_852427``: This applies errata 852427 workaround to Cortex-A73
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A73_855423``: This applies errata 855423 workaround to Cortex-A73
+   CPU. This needs to be enabled only for revision <= r0p1 of the CPU.
+
+For Cortex-A75, the following errata build flags are defined :
+
+-  ``ERRATA_A75_764081``: This applies errata 764081 workaround to Cortex-A75
+   CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+-  ``ERRATA_A75_790748``: This applies errata 790748 workaround to Cortex-A75
+    CPU. This needs to be enabled only for revision r0p0 of the CPU.
+
+For Cortex-A76, the following errata build flags are defined :
+
+-  ``ERRATA_A76_1073348``: This applies errata 1073348 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r1p0 of the CPU.
+
+-  ``ERRATA_A76_1130799``: This applies errata 1130799 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r2p0 of the CPU.
+
+-  ``ERRATA_A76_1220197``: This applies errata 1220197 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r2p0 of the CPU.
+
+-  ``ERRATA_A76_1257314``: This applies errata 1257314 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_A76_1262606``: This applies errata 1262606 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_A76_1262888``: This applies errata 1262888 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_A76_1275112``: This applies errata 1275112 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+For Neoverse N1, the following errata build flags are defined :
+
+-  ``ERRATA_N1_1073348``: This applies errata 1073348 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision r0p0 and r1p0 of the CPU.
+
+-  ``ERRATA_N1_1130799``: This applies errata 1130799 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r2p0 of the CPU.
+
+-  ``ERRATA_N1_1165347``: This applies errata 1165347 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r2p0 of the CPU.
+
+-  ``ERRATA_N1_1207823``: This applies errata 1207823 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r2p0 of the CPU.
+
+-  ``ERRATA_N1_1220197``: This applies errata 1220197 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r2p0 of the CPU.
+
+-  ``ERRATA_N1_1257314``: This applies errata 1257314 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_N1_1262606``: This applies errata 1262606 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_N1_1262888``: This applies errata 1262888 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_N1_1275112``: This applies errata 1275112 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+-  ``ERRATA_N1_1315703``: This applies errata 1315703 workaround to Neoverse-N1
+   CPU. This needs to be enabled only for revision <= r3p0 of the CPU.
+
+DSU Errata Workarounds
+----------------------
+
+Similar to CPU errata, TF-A also implements workarounds for DSU (DynamIQ
+Shared Unit) errata. The DSU errata details can be found in the respective Arm
+documentation:
+
+- `Arm DSU Software Developers Errata Notice`_.
+
+Each erratum is identified by an ``ID``, as defined in the DSU errata notice
+document. Thus, the build flags which enable/disable the errata workarounds
+have the format ``ERRATA_DSU_<ID>``. The implementation and application logic
+of DSU errata workarounds are similar to `CPU errata workarounds`_.
+
+For DSU errata, the following build flags are defined:
+
+-  ``ERRATA_DSU_798953``: This applies errata 798953 workaround for the
+   affected DSU configurations. This errata applies only for those DSUs that
+   revision is r0p0 (on r0p1 it is fixed). However, please note that this
+   workaround results in increased DSU power consumption on idle.
+
+-  ``ERRATA_DSU_936184``: This applies errata 936184 workaround for the
+   affected DSU configurations. This errata applies only for those DSUs that
+   contain the ACP interface **and** the DSU revision is older than r2p0 (on
+   r2p0 it is fixed). However, please note that this workaround results in
+   increased DSU power consumption on idle.
+
+CPU Specific optimizations
+--------------------------
+
+This section describes some of the optimizations allowed by the CPU micro
+architecture that can be enabled by the platform as desired.
+
+-  ``SKIP_A57_L1_FLUSH_PWR_DWN``: This flag enables an optimization in the
+   Cortex-A57 cluster power down sequence by not flushing the Level 1 data
+   cache. The L1 data cache and the L2 unified cache are inclusive. A flush
+   of the L2 by set/way flushes any dirty lines from the L1 as well. This
+   is a known safe deviation from the Cortex-A57 TRM defined power down
+   sequence. Each Cortex-A57 based platform must make its own decision on
+   whether to use the optimization.
+
+-  ``A53_DISABLE_NON_TEMPORAL_HINT``: This flag disables the cache non-temporal
+   hint. The LDNP/STNP instructions as implemented on Cortex-A53 do not behave
+   in a way most programmers expect, and will most probably result in a
+   significant speed degradation to any code that employs them. The Armv8-A
+   architecture (see Arm DDI 0487A.h, section D3.4.3) allows cores to ignore
+   the non-temporal hint and treat LDNP/STNP as LDP/STP instead. Enabling this
+   flag enforces this behaviour. This needs to be enabled only for revisions
+   <= r0p3 of the CPU and is enabled by default.
+
+-  ``A57_DISABLE_NON_TEMPORAL_HINT``: This flag has the same behaviour as
+   ``A53_DISABLE_NON_TEMPORAL_HINT`` but for Cortex-A57. This needs to be
+   enabled only for revisions <= r1p2 of the CPU and is enabled by default,
+   as recommended in section "4.7 Non-Temporal Loads/Stores" of the
+   `Cortex-A57 Software Optimization Guide`_.
+
+--------------
+
+*Copyright (c) 2014-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _CVE-2017-5715: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715
+.. _CVE-2018-3639: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639
+.. _Cortex-A53 MPCore Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm048406/index.html
+.. _Cortex-A57 MPCore Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm049219/index.html
+.. _Cortex-A72 MPCore Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm012079/index.html
+.. _Firmware Design guide: firmware-design.rst
+.. _Cortex-A57 Software Optimization Guide: http://infocenter.arm.com/help/topic/com.arm.doc.uan0015b/Cortex_A57_Software_Optimization_Guide_external.pdf
+.. _Arm DSU Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm138168/index.html
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
new file mode 100644
index 0000000..00e199a
--- /dev/null
+++ b/docs/design/firmware-design.rst
@@ -0,0 +1,2692 @@
+Firmware Design
+===============
+
+Trusted Firmware-A (TF-A) implements a subset of the Trusted Board Boot
+Requirements (TBBR) Platform Design Document (PDD) [1]_ for Arm reference
+platforms. The TBB sequence starts when the platform is powered on and runs up
+to the stage where it hands-off control to firmware running in the normal
+world in DRAM. This is the cold boot path.
+
+TF-A also implements the Power State Coordination Interface PDD [2]_ as a
+runtime service. PSCI is the interface from normal world software to firmware
+implementing power management use-cases (for example, secondary CPU boot,
+hotplug and idle). Normal world software can access TF-A runtime services via
+the Arm SMC (Secure Monitor Call) instruction. The SMC instruction must be
+used as mandated by the SMC Calling Convention [3]_.
+
+TF-A implements a framework for configuring and managing interrupts generated
+in either security state. The details of the interrupt management framework
+and its design can be found in TF-A Interrupt Management Design guide [4]_.
+
+TF-A also implements a library for setting up and managing the translation
+tables. The details of this library can be found in `Translation tables design`_.
+
+TF-A can be built to support either AArch64 or AArch32 execution state.
+
+Cold boot
+---------
+
+The cold boot path starts when the platform is physically turned on. If
+``COLD_BOOT_SINGLE_CPU=0``, one of the CPUs released from reset is chosen as the
+primary CPU, and the remaining CPUs are considered secondary CPUs. The primary
+CPU is chosen through platform-specific means. The cold boot path is mainly
+executed by the primary CPU, other than essential CPU initialization executed by
+all CPUs. The secondary CPUs are kept in a safe platform-specific state until
+the primary CPU has performed enough initialization to boot them.
+
+Refer to the `Reset Design`_ for more information on the effect of the
+``COLD_BOOT_SINGLE_CPU`` platform build option.
+
+The cold boot path in this implementation of TF-A depends on the execution
+state. For AArch64, it is divided into five steps (in order of execution):
+
+-  Boot Loader stage 1 (BL1) *AP Trusted ROM*
+-  Boot Loader stage 2 (BL2) *Trusted Boot Firmware*
+-  Boot Loader stage 3-1 (BL31) *EL3 Runtime Software*
+-  Boot Loader stage 3-2 (BL32) *Secure-EL1 Payload* (optional)
+-  Boot Loader stage 3-3 (BL33) *Non-trusted Firmware*
+
+For AArch32, it is divided into four steps (in order of execution):
+
+-  Boot Loader stage 1 (BL1) *AP Trusted ROM*
+-  Boot Loader stage 2 (BL2) *Trusted Boot Firmware*
+-  Boot Loader stage 3-2 (BL32) *EL3 Runtime Software*
+-  Boot Loader stage 3-3 (BL33) *Non-trusted Firmware*
+
+Arm development platforms (Fixed Virtual Platforms (FVPs) and Juno) implement a
+combination of the following types of memory regions. Each bootloader stage uses
+one or more of these memory regions.
+
+-  Regions accessible from both non-secure and secure states. For example,
+   non-trusted SRAM, ROM and DRAM.
+-  Regions accessible from only the secure state. For example, trusted SRAM and
+   ROM. The FVPs also implement the trusted DRAM which is statically
+   configured. Additionally, the Base FVPs and Juno development platform
+   configure the TrustZone Controller (TZC) to create a region in the DRAM
+   which is accessible only from the secure state.
+
+The sections below provide the following details:
+
+-  dynamic configuration of Boot Loader stages
+-  initialization and execution of the first three stages during cold boot
+-  specification of the EL3 Runtime Software (BL31 for AArch64 and BL32 for
+   AArch32) entrypoint requirements for use by alternative Trusted Boot
+   Firmware in place of the provided BL1 and BL2
+
+Dynamic Configuration during cold boot
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each of the Boot Loader stages may be dynamically configured if required by the
+platform. The Boot Loader stage may optionally specify a firmware
+configuration file and/or hardware configuration file as listed below:
+
+-  HW_CONFIG - The hardware configuration file. Can be shared by all Boot Loader
+   stages and also by the Normal World Rich OS.
+-  TB_FW_CONFIG - Trusted Boot Firmware configuration file. Shared between BL1
+   and BL2.
+-  SOC_FW_CONFIG - SoC Firmware configuration file. Used by BL31.
+-  TOS_FW_CONFIG - Trusted OS Firmware configuration file. Used by Trusted OS
+   (BL32).
+-  NT_FW_CONFIG - Non Trusted Firmware configuration file. Used by Non-trusted
+   firmware (BL33).
+
+The Arm development platforms use the Flattened Device Tree format for the
+dynamic configuration files.
+
+Each Boot Loader stage can pass up to 4 arguments via registers to the next
+stage.  BL2 passes the list of the next images to execute to the *EL3 Runtime
+Software* (BL31 for AArch64 and BL32 for AArch32) via `arg0`. All the other
+arguments are platform defined. The Arm development platforms use the following
+convention:
+
+-  BL1 passes the address of a meminfo_t structure to BL2 via ``arg1``. This
+   structure contains the memory layout available to BL2.
+-  When dynamic configuration files are present, the firmware configuration for
+   the next Boot Loader stage is populated in the first available argument and
+   the generic hardware configuration is passed the next available argument.
+   For example,
+
+   -  If TB_FW_CONFIG is loaded by BL1, then its address is passed in ``arg0``
+      to BL2.
+   -  If HW_CONFIG is loaded by BL1, then its address is passed in ``arg2`` to
+      BL2. Note, ``arg1`` is already used for meminfo_t.
+   -  If SOC_FW_CONFIG is loaded by BL2, then its address is passed in ``arg1``
+      to BL31. Note, ``arg0`` is used to pass the list of executable images.
+   -  Similarly, if HW_CONFIG is loaded by BL1 or BL2, then its address is
+      passed in ``arg2`` to BL31.
+   -  For other BL3x images, if the firmware configuration file is loaded by
+      BL2, then its address is passed in ``arg0`` and if HW_CONFIG is loaded
+      then its address is passed in ``arg1``.
+
+BL1
+~~~
+
+This stage begins execution from the platform's reset vector at EL3. The reset
+address is platform dependent but it is usually located in a Trusted ROM area.
+The BL1 data section is copied to trusted SRAM at runtime.
+
+On the Arm development platforms, BL1 code starts execution from the reset
+vector defined by the constant ``BL1_RO_BASE``. The BL1 data section is copied
+to the top of trusted SRAM as defined by the constant ``BL1_RW_BASE``.
+
+The functionality implemented by this stage is as follows.
+
+Determination of boot path
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Whenever a CPU is released from reset, BL1 needs to distinguish between a warm
+boot and a cold boot. This is done using platform-specific mechanisms (see the
+``plat_get_my_entrypoint()`` function in the `Porting Guide`_). In the case of a
+warm boot, a CPU is expected to continue execution from a separate
+entrypoint. In the case of a cold boot, the secondary CPUs are placed in a safe
+platform-specific state (see the ``plat_secondary_cold_boot_setup()`` function in
+the `Porting Guide`_) while the primary CPU executes the remaining cold boot path
+as described in the following sections.
+
+This step only applies when ``PROGRAMMABLE_RESET_ADDRESS=0``. Refer to the
+`Reset Design`_ for more information on the effect of the
+``PROGRAMMABLE_RESET_ADDRESS`` platform build option.
+
+Architectural initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BL1 performs minimal architectural initialization as follows.
+
+-  Exception vectors
+
+   BL1 sets up simple exception vectors for both synchronous and asynchronous
+   exceptions. The default behavior upon receiving an exception is to populate
+   a status code in the general purpose register ``X0/R0`` and call the
+   ``plat_report_exception()`` function (see the `Porting Guide`_). The status
+   code is one of:
+
+   For AArch64:
+
+   ::
+
+       0x0 : Synchronous exception from Current EL with SP_EL0
+       0x1 : IRQ exception from Current EL with SP_EL0
+       0x2 : FIQ exception from Current EL with SP_EL0
+       0x3 : System Error exception from Current EL with SP_EL0
+       0x4 : Synchronous exception from Current EL with SP_ELx
+       0x5 : IRQ exception from Current EL with SP_ELx
+       0x6 : FIQ exception from Current EL with SP_ELx
+       0x7 : System Error exception from Current EL with SP_ELx
+       0x8 : Synchronous exception from Lower EL using aarch64
+       0x9 : IRQ exception from Lower EL using aarch64
+       0xa : FIQ exception from Lower EL using aarch64
+       0xb : System Error exception from Lower EL using aarch64
+       0xc : Synchronous exception from Lower EL using aarch32
+       0xd : IRQ exception from Lower EL using aarch32
+       0xe : FIQ exception from Lower EL using aarch32
+       0xf : System Error exception from Lower EL using aarch32
+
+   For AArch32:
+
+   ::
+
+       0x10 : User mode
+       0x11 : FIQ mode
+       0x12 : IRQ mode
+       0x13 : SVC mode
+       0x16 : Monitor mode
+       0x17 : Abort mode
+       0x1a : Hypervisor mode
+       0x1b : Undefined mode
+       0x1f : System mode
+
+   The ``plat_report_exception()`` implementation on the Arm FVP port programs
+   the Versatile Express System LED register in the following format to
+   indicate the occurrence of an unexpected exception:
+
+   ::
+
+       SYS_LED[0]   - Security state (Secure=0/Non-Secure=1)
+       SYS_LED[2:1] - Exception Level (EL3=0x3, EL2=0x2, EL1=0x1, EL0=0x0)
+                      For AArch32 it is always 0x0
+       SYS_LED[7:3] - Exception Class (Sync/Async & origin). This is the value
+                      of the status code
+
+   A write to the LED register reflects in the System LEDs (S6LED0..7) in the
+   CLCD window of the FVP.
+
+   BL1 does not expect to receive any exceptions other than the SMC exception.
+   For the latter, BL1 installs a simple stub. The stub expects to receive a
+   limited set of SMC types (determined by their function IDs in the general
+   purpose register ``X0/R0``):
+
+   -  ``BL1_SMC_RUN_IMAGE``: This SMC is raised by BL2 to make BL1 pass control
+      to EL3 Runtime Software.
+   -  All SMCs listed in section "BL1 SMC Interface" in the `Firmware Update`_
+      Design Guide are supported for AArch64 only. These SMCs are currently
+      not supported when BL1 is built for AArch32.
+
+   Any other SMC leads to an assertion failure.
+
+-  CPU initialization
+
+   BL1 calls the ``reset_handler()`` function which in turn calls the CPU
+   specific reset handler function (see the section: "CPU specific operations
+   framework").
+
+-  Control register setup (for AArch64)
+
+   -  ``SCTLR_EL3``. Instruction cache is enabled by setting the ``SCTLR_EL3.I``
+      bit. Alignment and stack alignment checking is enabled by setting the
+      ``SCTLR_EL3.A`` and ``SCTLR_EL3.SA`` bits. Exception endianness is set to
+      little-endian by clearing the ``SCTLR_EL3.EE`` bit.
+
+   -  ``SCR_EL3``. The register width of the next lower exception level is set
+      to AArch64 by setting the ``SCR.RW`` bit. The ``SCR.EA`` bit is set to trap
+      both External Aborts and SError Interrupts in EL3. The ``SCR.SIF`` bit is
+      also set to disable instruction fetches from Non-secure memory when in
+      secure state.
+
+   -  ``CPTR_EL3``. Accesses to the ``CPACR_EL1`` register from EL1 or EL2, or the
+      ``CPTR_EL2`` register from EL2 are configured to not trap to EL3 by
+      clearing the ``CPTR_EL3.TCPAC`` bit. Access to the trace functionality is
+      configured not to trap to EL3 by clearing the ``CPTR_EL3.TTA`` bit.
+      Instructions that access the registers associated with Floating Point
+      and Advanced SIMD execution are configured to not trap to EL3 by
+      clearing the ``CPTR_EL3.TFP`` bit.
+
+   -  ``DAIF``. The SError interrupt is enabled by clearing the SError interrupt
+      mask bit.
+
+   -  ``MDCR_EL3``. The trap controls, ``MDCR_EL3.TDOSA``, ``MDCR_EL3.TDA`` and
+      ``MDCR_EL3.TPM``, are set so that accesses to the registers they control
+      do not trap to EL3. AArch64 Secure self-hosted debug is disabled by
+      setting the ``MDCR_EL3.SDD`` bit. Also ``MDCR_EL3.SPD32`` is set to
+      disable AArch32 Secure self-hosted privileged debug from S-EL1.
+
+-  Control register setup (for AArch32)
+
+   -  ``SCTLR``. Instruction cache is enabled by setting the ``SCTLR.I`` bit.
+      Alignment checking is enabled by setting the ``SCTLR.A`` bit.
+      Exception endianness is set to little-endian by clearing the
+      ``SCTLR.EE`` bit.
+
+   -  ``SCR``. The ``SCR.SIF`` bit is set to disable instruction fetches from
+      Non-secure memory when in secure state.
+
+   -  ``CPACR``. Allow execution of Advanced SIMD instructions at PL0 and PL1,
+      by clearing the ``CPACR.ASEDIS`` bit. Access to the trace functionality
+      is configured not to trap to undefined mode by clearing the
+      ``CPACR.TRCDIS`` bit.
+
+   -  ``NSACR``. Enable non-secure access to Advanced SIMD functionality and
+      system register access to implemented trace registers.
+
+   -  ``FPEXC``. Enable access to the Advanced SIMD and floating-point
+      functionality from all Exception levels.
+
+   -  ``CPSR.A``. The Asynchronous data abort interrupt is enabled by clearing
+      the Asynchronous data abort interrupt mask bit.
+
+   -  ``SDCR``. The ``SDCR.SPD`` field is set to disable AArch32 Secure
+      self-hosted privileged debug.
+
+Platform initialization
+^^^^^^^^^^^^^^^^^^^^^^^
+
+On Arm platforms, BL1 performs the following platform initializations:
+
+-  Enable the Trusted Watchdog.
+-  Initialize the console.
+-  Configure the Interconnect to enable hardware coherency.
+-  Enable the MMU and map the memory it needs to access.
+-  Configure any required platform storage to load the next bootloader image
+   (BL2).
+-  If the BL1 dynamic configuration file, ``TB_FW_CONFIG``, is available, then
+   load it to the platform defined address and make it available to BL2 via
+   ``arg0``.
+-  Configure the system timer and program the `CNTFRQ_EL0` for use by NS-BL1U
+   and NS-BL2U firmware update images.
+
+Firmware Update detection and execution
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+After performing platform setup, BL1 common code calls
+``bl1_plat_get_next_image_id()`` to determine if `Firmware Update`_ is required or
+to proceed with the normal boot process. If the platform code returns
+``BL2_IMAGE_ID`` then the normal boot sequence is executed as described in the
+next section, else BL1 assumes that `Firmware Update`_ is required and execution
+passes to the first image in the `Firmware Update`_ process. In either case, BL1
+retrieves a descriptor of the next image by calling ``bl1_plat_get_image_desc()``.
+The image descriptor contains an ``entry_point_info_t`` structure, which BL1
+uses to initialize the execution state of the next image.
+
+BL2 image load and execution
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the normal boot flow, BL1 execution continues as follows:
+
+#. BL1 prints the following string from the primary CPU to indicate successful
+   execution of the BL1 stage:
+
+   ::
+
+       "Booting Trusted Firmware"
+
+#. BL1 loads a BL2 raw binary image from platform storage, at a
+   platform-specific base address. Prior to the load, BL1 invokes
+   ``bl1_plat_handle_pre_image_load()`` which allows the platform to update or
+   use the image information. If the BL2 image file is not present or if
+   there is not enough free trusted SRAM the following error message is
+   printed:
+
+   ::
+
+       "Failed to load BL2 firmware."
+
+#. BL1 invokes ``bl1_plat_handle_post_image_load()`` which again is intended
+   for platforms to take further action after image load. This function must
+   populate the necessary arguments for BL2, which may also include the memory
+   layout. Further description of the memory layout can be found later
+   in this document.
+
+#. BL1 passes control to the BL2 image at Secure EL1 (for AArch64) or at
+   Secure SVC mode (for AArch32), starting from its load address.
+
+BL2
+~~~
+
+BL1 loads and passes control to BL2 at Secure-EL1 (for AArch64) or at Secure
+SVC mode (for AArch32) . BL2 is linked against and loaded at a platform-specific
+base address (more information can be found later in this document).
+The functionality implemented by BL2 is as follows.
+
+Architectural initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For AArch64, BL2 performs the minimal architectural initialization required
+for subsequent stages of TF-A and normal world software. EL1 and EL0 are given
+access to Floating Point and Advanced SIMD registers by clearing the
+``CPACR.FPEN`` bits.
+
+For AArch32, the minimal architectural initialization required for subsequent
+stages of TF-A and normal world software is taken care of in BL1 as both BL1
+and BL2 execute at PL1.
+
+Platform initialization
+^^^^^^^^^^^^^^^^^^^^^^^
+
+On Arm platforms, BL2 performs the following platform initializations:
+
+-  Initialize the console.
+-  Configure any required platform storage to allow loading further bootloader
+   images.
+-  Enable the MMU and map the memory it needs to access.
+-  Perform platform security setup to allow access to controlled components.
+-  Reserve some memory for passing information to the next bootloader image
+   EL3 Runtime Software and populate it.
+-  Define the extents of memory available for loading each subsequent
+   bootloader image.
+-  If BL1 has passed TB_FW_CONFIG dynamic configuration file in ``arg0``,
+   then parse it.
+
+Image loading in BL2
+^^^^^^^^^^^^^^^^^^^^
+
+BL2 generic code loads the images based on the list of loadable images
+provided by the platform. BL2 passes the list of executable images
+provided by the platform to the next handover BL image.
+
+The list of loadable images provided by the platform may also contain
+dynamic configuration files. The files are loaded and can be parsed as
+needed in the ``bl2_plat_handle_post_image_load()`` function. These
+configuration files can be passed to next Boot Loader stages as arguments
+by updating the corresponding entrypoint information in this function.
+
+SCP_BL2 (System Control Processor Firmware) image load
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Some systems have a separate System Control Processor (SCP) for power, clock,
+reset and system control. BL2 loads the optional SCP_BL2 image from platform
+storage into a platform-specific region of secure memory. The subsequent
+handling of SCP_BL2 is platform specific. For example, on the Juno Arm
+development platform port the image is transferred into SCP's internal memory
+using the Boot Over MHU (BOM) protocol after being loaded in the trusted SRAM
+memory. The SCP executes SCP_BL2 and signals to the Application Processor (AP)
+for BL2 execution to continue.
+
+EL3 Runtime Software image load
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BL2 loads the EL3 Runtime Software image from platform storage into a platform-
+specific address in trusted SRAM. If there is not enough memory to load the
+image or image is missing it leads to an assertion failure.
+
+AArch64 BL32 (Secure-EL1 Payload) image load
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BL2 loads the optional BL32 image from platform storage into a platform-
+specific region of secure memory. The image executes in the secure world. BL2
+relies on BL31 to pass control to the BL32 image, if present. Hence, BL2
+populates a platform-specific area of memory with the entrypoint/load-address
+of the BL32 image. The value of the Saved Processor Status Register (``SPSR``)
+for entry into BL32 is not determined by BL2, it is initialized by the
+Secure-EL1 Payload Dispatcher (see later) within BL31, which is responsible for
+managing interaction with BL32. This information is passed to BL31.
+
+BL33 (Non-trusted Firmware) image load
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BL2 loads the BL33 image (e.g. UEFI or other test or boot software) from
+platform storage into non-secure memory as defined by the platform.
+
+BL2 relies on EL3 Runtime Software to pass control to BL33 once secure state
+initialization is complete. Hence, BL2 populates a platform-specific area of
+memory with the entrypoint and Saved Program Status Register (``SPSR``) of the
+normal world software image. The entrypoint is the load address of the BL33
+image. The ``SPSR`` is determined as specified in Section 5.13 of the
+`PSCI PDD`_. This information is passed to the EL3 Runtime Software.
+
+AArch64 BL31 (EL3 Runtime Software) execution
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BL2 execution continues as follows:
+
+#. BL2 passes control back to BL1 by raising an SMC, providing BL1 with the
+   BL31 entrypoint. The exception is handled by the SMC exception handler
+   installed by BL1.
+
+#. BL1 turns off the MMU and flushes the caches. It clears the
+   ``SCTLR_EL3.M/I/C`` bits, flushes the data cache to the point of coherency
+   and invalidates the TLBs.
+
+#. BL1 passes control to BL31 at the specified entrypoint at EL3.
+
+Running BL2 at EL3 execution level
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some platforms have a non-TF-A Boot ROM that expects the next boot stage
+to execute at EL3. On these platforms, TF-A BL1 is a waste of memory
+as its only purpose is to ensure TF-A BL2 is entered at S-EL1. To avoid
+this waste, a special mode enables BL2 to execute at EL3, which allows
+a non-TF-A Boot ROM to load and jump directly to BL2. This mode is selected
+when the build flag BL2_AT_EL3 is enabled. The main differences in this
+mode are:
+
+#. BL2 includes the reset code and the mailbox mechanism to differentiate
+   cold boot and warm boot. It runs at EL3 doing the arch
+   initialization required for EL3.
+
+#. BL2 does not receive the meminfo information from BL1 anymore. This
+   information can be passed by the Boot ROM or be internal to the
+   BL2 image.
+
+#. Since BL2 executes at EL3, BL2 jumps directly to the next image,
+   instead of invoking the RUN_IMAGE SMC call.
+
+
+We assume 3 different types of BootROM support on the platform:
+
+#. The Boot ROM always jumps to the same address, for both cold
+   and warm boot. In this case, we will need to keep a resident part
+   of BL2 whose memory cannot be reclaimed by any other image. The
+   linker script defines the symbols __TEXT_RESIDENT_START__ and
+   __TEXT_RESIDENT_END__ that allows the platform to configure
+   correctly the memory map.
+#. The platform has some mechanism to indicate the jump address to the
+   Boot ROM. Platform code can then program the jump address with
+   psci_warmboot_entrypoint during cold boot.
+#. The platform has some mechanism to program the reset address using
+   the PROGRAMMABLE_RESET_ADDRESS feature. Platform code can then
+   program the reset address with psci_warmboot_entrypoint during
+   cold boot, bypassing the boot ROM for warm boot.
+
+In the last 2 cases, no part of BL2 needs to remain resident at
+runtime. In the first 2 cases, we expect the Boot ROM to be able to
+differentiate between warm and cold boot, to avoid loading BL2 again
+during warm boot.
+
+This functionality can be tested with FVP loading the image directly
+in memory and changing the address where the system jumps at reset.
+For example:
+
+	-C cluster0.cpu0.RVBAR=0x4022000
+	--data cluster0.cpu0=bl2.bin@0x4022000
+
+With this configuration, FVP is like a platform of the first case,
+where the Boot ROM jumps always to the same address. For simplification,
+BL32 is loaded in DRAM in this case, to avoid other images reclaiming
+BL2 memory.
+
+
+AArch64 BL31
+~~~~~~~~~~~~
+
+The image for this stage is loaded by BL2 and BL1 passes control to BL31 at
+EL3. BL31 executes solely in trusted SRAM. BL31 is linked against and
+loaded at a platform-specific base address (more information can be found later
+in this document). The functionality implemented by BL31 is as follows.
+
+Architectural initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Currently, BL31 performs a similar architectural initialization to BL1 as
+far as system register settings are concerned. Since BL1 code resides in ROM,
+architectural initialization in BL31 allows override of any previous
+initialization done by BL1.
+
+BL31 initializes the per-CPU data framework, which provides a cache of
+frequently accessed per-CPU data optimised for fast, concurrent manipulation
+on different CPUs. This buffer includes pointers to per-CPU contexts, crash
+buffer, CPU reset and power down operations, PSCI data, platform data and so on.
+
+It then replaces the exception vectors populated by BL1 with its own. BL31
+exception vectors implement more elaborate support for handling SMCs since this
+is the only mechanism to access the runtime services implemented by BL31 (PSCI
+for example). BL31 checks each SMC for validity as specified by the
+`SMC calling convention PDD`_ before passing control to the required SMC
+handler routine.
+
+BL31 programs the ``CNTFRQ_EL0`` register with the clock frequency of the system
+counter, which is provided by the platform.
+
+Platform initialization
+^^^^^^^^^^^^^^^^^^^^^^^
+
+BL31 performs detailed platform initialization, which enables normal world
+software to function correctly.
+
+On Arm platforms, this consists of the following:
+
+-  Initialize the console.
+-  Configure the Interconnect to enable hardware coherency.
+-  Enable the MMU and map the memory it needs to access.
+-  Initialize the generic interrupt controller.
+-  Initialize the power controller device.
+-  Detect the system topology.
+
+Runtime services initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BL31 is responsible for initializing the runtime services. One of them is PSCI.
+
+As part of the PSCI initializations, BL31 detects the system topology. It also
+initializes the data structures that implement the state machine used to track
+the state of power domain nodes. The state can be one of ``OFF``, ``RUN`` or
+``RETENTION``. All secondary CPUs are initially in the ``OFF`` state. The cluster
+that the primary CPU belongs to is ``ON``; any other cluster is ``OFF``. It also
+initializes the locks that protect them. BL31 accesses the state of a CPU or
+cluster immediately after reset and before the data cache is enabled in the
+warm boot path. It is not currently possible to use 'exclusive' based spinlocks,
+therefore BL31 uses locks based on Lamport's Bakery algorithm instead.
+
+The runtime service framework and its initialization is described in more
+detail in the "EL3 runtime services framework" section below.
+
+Details about the status of the PSCI implementation are provided in the
+"Power State Coordination Interface" section below.
+
+AArch64 BL32 (Secure-EL1 Payload) image initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If a BL32 image is present then there must be a matching Secure-EL1 Payload
+Dispatcher (SPD) service (see later for details). During initialization
+that service must register a function to carry out initialization of BL32
+once the runtime services are fully initialized. BL31 invokes such a
+registered function to initialize BL32 before running BL33. This initialization
+is not necessary for AArch32 SPs.
+
+Details on BL32 initialization and the SPD's role are described in the
+"Secure-EL1 Payloads and Dispatchers" section below.
+
+BL33 (Non-trusted Firmware) execution
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+EL3 Runtime Software initializes the EL2 or EL1 processor context for normal-
+world cold boot, ensuring that no secure state information finds its way into
+the non-secure execution state. EL3 Runtime Software uses the entrypoint
+information provided by BL2 to jump to the Non-trusted firmware image (BL33)
+at the highest available Exception Level (EL2 if available, otherwise EL1).
+
+Using alternative Trusted Boot Firmware in place of BL1 & BL2 (AArch64 only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some platforms have existing implementations of Trusted Boot Firmware that
+would like to use TF-A BL31 for the EL3 Runtime Software. To enable this
+firmware architecture it is important to provide a fully documented and stable
+interface between the Trusted Boot Firmware and BL31.
+
+Future changes to the BL31 interface will be done in a backwards compatible
+way, and this enables these firmware components to be independently enhanced/
+updated to develop and exploit new functionality.
+
+Required CPU state when calling ``bl31_entrypoint()`` during cold boot
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This function must only be called by the primary CPU.
+
+On entry to this function the calling primary CPU must be executing in AArch64
+EL3, little-endian data access, and all interrupt sources masked:
+
+::
+
+    PSTATE.EL = 3
+    PSTATE.RW = 1
+    PSTATE.DAIF = 0xf
+    SCTLR_EL3.EE = 0
+
+X0 and X1 can be used to pass information from the Trusted Boot Firmware to the
+platform code in BL31:
+
+::
+
+    X0 : Reserved for common TF-A information
+    X1 : Platform specific information
+
+BL31 zero-init sections (e.g. ``.bss``) should not contain valid data on entry,
+these will be zero filled prior to invoking platform setup code.
+
+Use of the X0 and X1 parameters
+'''''''''''''''''''''''''''''''
+
+The parameters are platform specific and passed from ``bl31_entrypoint()`` to
+``bl31_early_platform_setup()``. The value of these parameters is never directly
+used by the common BL31 code.
+
+The convention is that ``X0`` conveys information regarding the BL31, BL32 and
+BL33 images from the Trusted Boot firmware and ``X1`` can be used for other
+platform specific purpose. This convention allows platforms which use TF-A's
+BL1 and BL2 images to transfer additional platform specific information from
+Secure Boot without conflicting with future evolution of TF-A using ``X0`` to
+pass a ``bl31_params`` structure.
+
+BL31 common and SPD initialization code depends on image and entrypoint
+information about BL33 and BL32, which is provided via BL31 platform APIs.
+This information is required until the start of execution of BL33. This
+information can be provided in a platform defined manner, e.g. compiled into
+the platform code in BL31, or provided in a platform defined memory location
+by the Trusted Boot firmware, or passed from the Trusted Boot Firmware via the
+Cold boot Initialization parameters. This data may need to be cleaned out of
+the CPU caches if it is provided by an earlier boot stage and then accessed by
+BL31 platform code before the caches are enabled.
+
+TF-A's BL2 implementation passes a ``bl31_params`` structure in
+``X0`` and the Arm development platforms interpret this in the BL31 platform
+code.
+
+MMU, Data caches & Coherency
+''''''''''''''''''''''''''''
+
+BL31 does not depend on the enabled state of the MMU, data caches or
+interconnect coherency on entry to ``bl31_entrypoint()``. If these are disabled
+on entry, these should be enabled during ``bl31_plat_arch_setup()``.
+
+Data structures used in the BL31 cold boot interface
+''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+These structures are designed to support compatibility and independent
+evolution of the structures and the firmware images. For example, a version of
+BL31 that can interpret the BL3x image information from different versions of
+BL2, a platform that uses an extended entry_point_info structure to convey
+additional register information to BL31, or a ELF image loader that can convey
+more details about the firmware images.
+
+To support these scenarios the structures are versioned and sized, which enables
+BL31 to detect which information is present and respond appropriately. The
+``param_header`` is defined to capture this information:
+
+.. code:: c
+
+    typedef struct param_header {
+        uint8_t type;       /* type of the structure */
+        uint8_t version;    /* version of this structure */
+        uint16_t size;      /* size of this structure in bytes */
+        uint32_t attr;      /* attributes: unused bits SBZ */
+    } param_header_t;
+
+The structures using this format are ``entry_point_info``, ``image_info`` and
+``bl31_params``. The code that allocates and populates these structures must set
+the header fields appropriately, and the ``SET_PARAM_HEAD()`` a macro is defined
+to simplify this action.
+
+Required CPU state for BL31 Warm boot initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When requesting a CPU power-on, or suspending a running CPU, TF-A provides
+the platform power management code with a Warm boot initialization
+entry-point, to be invoked by the CPU immediately after the reset handler.
+On entry to the Warm boot initialization function the calling CPU must be in
+AArch64 EL3, little-endian data access and all interrupt sources masked:
+
+::
+
+    PSTATE.EL = 3
+    PSTATE.RW = 1
+    PSTATE.DAIF = 0xf
+    SCTLR_EL3.EE = 0
+
+The PSCI implementation will initialize the processor state and ensure that the
+platform power management code is then invoked as required to initialize all
+necessary system, cluster and CPU resources.
+
+AArch32 EL3 Runtime Software entrypoint interface
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To enable this firmware architecture it is important to provide a fully
+documented and stable interface between the Trusted Boot Firmware and the
+AArch32 EL3 Runtime Software.
+
+Future changes to the entrypoint interface will be done in a backwards
+compatible way, and this enables these firmware components to be independently
+enhanced/updated to develop and exploit new functionality.
+
+Required CPU state when entering during cold boot
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This function must only be called by the primary CPU.
+
+On entry to this function the calling primary CPU must be executing in AArch32
+EL3, little-endian data access, and all interrupt sources masked:
+
+::
+
+    PSTATE.AIF = 0x7
+    SCTLR.EE = 0
+
+R0 and R1 are used to pass information from the Trusted Boot Firmware to the
+platform code in AArch32 EL3 Runtime Software:
+
+::
+
+    R0 : Reserved for common TF-A information
+    R1 : Platform specific information
+
+Use of the R0 and R1 parameters
+'''''''''''''''''''''''''''''''
+
+The parameters are platform specific and the convention is that ``R0`` conveys
+information regarding the BL3x images from the Trusted Boot firmware and ``R1``
+can be used for other platform specific purpose. This convention allows
+platforms which use TF-A's BL1 and BL2 images to transfer additional platform
+specific information from Secure Boot without conflicting with future
+evolution of TF-A using ``R0`` to pass a ``bl_params`` structure.
+
+The AArch32 EL3 Runtime Software is responsible for entry into BL33. This
+information can be obtained in a platform defined manner, e.g. compiled into
+the AArch32 EL3 Runtime Software, or provided in a platform defined memory
+location by the Trusted Boot firmware, or passed from the Trusted Boot Firmware
+via the Cold boot Initialization parameters. This data may need to be cleaned
+out of the CPU caches if it is provided by an earlier boot stage and then
+accessed by AArch32 EL3 Runtime Software before the caches are enabled.
+
+When using AArch32 EL3 Runtime Software, the Arm development platforms pass a
+``bl_params`` structure in ``R0`` from BL2 to be interpreted by AArch32 EL3 Runtime
+Software platform code.
+
+MMU, Data caches & Coherency
+''''''''''''''''''''''''''''
+
+AArch32 EL3 Runtime Software must not depend on the enabled state of the MMU,
+data caches or interconnect coherency in its entrypoint. They must be explicitly
+enabled if required.
+
+Data structures used in cold boot interface
+'''''''''''''''''''''''''''''''''''''''''''
+
+The AArch32 EL3 Runtime Software cold boot interface uses ``bl_params`` instead
+of ``bl31_params``. The ``bl_params`` structure is based on the convention
+described in AArch64 BL31 cold boot interface section.
+
+Required CPU state for warm boot initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When requesting a CPU power-on, or suspending a running CPU, AArch32 EL3
+Runtime Software must ensure execution of a warm boot initialization entrypoint.
+If TF-A BL1 is used and the PROGRAMMABLE_RESET_ADDRESS build flag is false,
+then AArch32 EL3 Runtime Software must ensure that BL1 branches to the warm
+boot entrypoint by arranging for the BL1 platform function,
+plat_get_my_entrypoint(), to return a non-zero value.
+
+In this case, the warm boot entrypoint must be in AArch32 EL3, little-endian
+data access and all interrupt sources masked:
+
+::
+
+    PSTATE.AIF = 0x7
+    SCTLR.EE = 0
+
+The warm boot entrypoint may be implemented by using TF-A
+``psci_warmboot_entrypoint()`` function. In that case, the platform must fulfil
+the pre-requisites mentioned in the `PSCI Library integration guide`_.
+
+EL3 runtime services framework
+------------------------------
+
+Software executing in the non-secure state and in the secure state at exception
+levels lower than EL3 will request runtime services using the Secure Monitor
+Call (SMC) instruction. These requests will follow the convention described in
+the SMC Calling Convention PDD (`SMCCC`_). The `SMCCC`_ assigns function
+identifiers to each SMC request and describes how arguments are passed and
+returned.
+
+The EL3 runtime services framework enables the development of services by
+different providers that can be easily integrated into final product firmware.
+The following sections describe the framework which facilitates the
+registration, initialization and use of runtime services in EL3 Runtime
+Software (BL31).
+
+The design of the runtime services depends heavily on the concepts and
+definitions described in the `SMCCC`_, in particular SMC Function IDs, Owning
+Entity Numbers (OEN), Fast and Yielding calls, and the SMC32 and SMC64 calling
+conventions. Please refer to that document for more detailed explanation of
+these terms.
+
+The following runtime services are expected to be implemented first. They have
+not all been instantiated in the current implementation.
+
+#. Standard service calls
+
+   This service is for management of the entire system. The Power State
+   Coordination Interface (`PSCI`_) is the first set of standard service calls
+   defined by Arm (see PSCI section later).
+
+#. Secure-EL1 Payload Dispatcher service
+
+   If a system runs a Trusted OS or other Secure-EL1 Payload (SP) then
+   it also requires a *Secure Monitor* at EL3 to switch the EL1 processor
+   context between the normal world (EL1/EL2) and trusted world (Secure-EL1).
+   The Secure Monitor will make these world switches in response to SMCs. The
+   `SMCCC`_ provides for such SMCs with the Trusted OS Call and Trusted
+   Application Call OEN ranges.
+
+   The interface between the EL3 Runtime Software and the Secure-EL1 Payload is
+   not defined by the `SMCCC`_ or any other standard. As a result, each
+   Secure-EL1 Payload requires a specific Secure Monitor that runs as a runtime
+   service - within TF-A this service is referred to as the Secure-EL1 Payload
+   Dispatcher (SPD).
+
+   TF-A provides a Test Secure-EL1 Payload (TSP) and its associated Dispatcher
+   (TSPD). Details of SPD design and TSP/TSPD operation are described in the
+   "Secure-EL1 Payloads and Dispatchers" section below.
+
+#. CPU implementation service
+
+   This service will provide an interface to CPU implementation specific
+   services for a given platform e.g. access to processor errata workarounds.
+   This service is currently unimplemented.
+
+Additional services for Arm Architecture, SiP and OEM calls can be implemented.
+Each implemented service handles a range of SMC function identifiers as
+described in the `SMCCC`_.
+
+Registration
+~~~~~~~~~~~~
+
+A runtime service is registered using the ``DECLARE_RT_SVC()`` macro, specifying
+the name of the service, the range of OENs covered, the type of service and
+initialization and call handler functions. This macro instantiates a ``const struct rt_svc_desc`` for the service with these details (see ``runtime_svc.h``).
+This structure is allocated in a special ELF section ``rt_svc_descs``, enabling
+the framework to find all service descriptors included into BL31.
+
+The specific service for a SMC Function is selected based on the OEN and call
+type of the Function ID, and the framework uses that information in the service
+descriptor to identify the handler for the SMC Call.
+
+The service descriptors do not include information to identify the precise set
+of SMC function identifiers supported by this service implementation, the
+security state from which such calls are valid nor the capability to support
+64-bit and/or 32-bit callers (using SMC32 or SMC64). Responding appropriately
+to these aspects of a SMC call is the responsibility of the service
+implementation, the framework is focused on integration of services from
+different providers and minimizing the time taken by the framework before the
+service handler is invoked.
+
+Details of the parameters, requirements and behavior of the initialization and
+call handling functions are provided in the following sections.
+
+Initialization
+~~~~~~~~~~~~~~
+
+``runtime_svc_init()`` in ``runtime_svc.c`` initializes the runtime services
+framework running on the primary CPU during cold boot as part of the BL31
+initialization. This happens prior to initializing a Trusted OS and running
+Normal world boot firmware that might in turn use these services.
+Initialization involves validating each of the declared runtime service
+descriptors, calling the service initialization function and populating the
+index used for runtime lookup of the service.
+
+The BL31 linker script collects all of the declared service descriptors into a
+single array and defines symbols that allow the framework to locate and traverse
+the array, and determine its size.
+
+The framework does basic validation of each descriptor to halt firmware
+initialization if service declaration errors are detected. The framework does
+not check descriptors for the following error conditions, and may behave in an
+unpredictable manner under such scenarios:
+
+#. Overlapping OEN ranges
+#. Multiple descriptors for the same range of OENs and ``call_type``
+#. Incorrect range of owning entity numbers for a given ``call_type``
+
+Once validated, the service ``init()`` callback is invoked. This function carries
+out any essential EL3 initialization before servicing requests. The ``init()``
+function is only invoked on the primary CPU during cold boot. If the service
+uses per-CPU data this must either be initialized for all CPUs during this call,
+or be done lazily when a CPU first issues an SMC call to that service. If
+``init()`` returns anything other than ``0``, this is treated as an initialization
+error and the service is ignored: this does not cause the firmware to halt.
+
+The OEN and call type fields present in the SMC Function ID cover a total of
+128 distinct services, but in practice a single descriptor can cover a range of
+OENs, e.g. SMCs to call a Trusted OS function. To optimize the lookup of a
+service handler, the framework uses an array of 128 indices that map every
+distinct OEN/call-type combination either to one of the declared services or to
+indicate the service is not handled. This ``rt_svc_descs_indices[]`` array is
+populated for all of the OENs covered by a service after the service ``init()``
+function has reported success. So a service that fails to initialize will never
+have it's ``handle()`` function invoked.
+
+The following figure shows how the ``rt_svc_descs_indices[]`` index maps the SMC
+Function ID call type and OEN onto a specific service handler in the
+``rt_svc_descs[]`` array.
+
+|Image 1|
+
+Handling an SMC
+~~~~~~~~~~~~~~~
+
+When the EL3 runtime services framework receives a Secure Monitor Call, the SMC
+Function ID is passed in W0 from the lower exception level (as per the
+`SMCCC`_). If the calling register width is AArch32, it is invalid to invoke an
+SMC Function which indicates the SMC64 calling convention: such calls are
+ignored and return the Unknown SMC Function Identifier result code ``0xFFFFFFFF``
+in R0/X0.
+
+Bit[31] (fast/yielding call) and bits[29:24] (owning entity number) of the SMC
+Function ID are combined to index into the ``rt_svc_descs_indices[]`` array. The
+resulting value might indicate a service that has no handler, in this case the
+framework will also report an Unknown SMC Function ID. Otherwise, the value is
+used as a further index into the ``rt_svc_descs[]`` array to locate the required
+service and handler.
+
+The service's ``handle()`` callback is provided with five of the SMC parameters
+directly, the others are saved into memory for retrieval (if needed) by the
+handler. The handler is also provided with an opaque ``handle`` for use with the
+supporting library for parameter retrieval, setting return values and context
+manipulation; and with ``flags`` indicating the security state of the caller. The
+framework finally sets up the execution stack for the handler, and invokes the
+services ``handle()`` function.
+
+On return from the handler the result registers are populated in X0-X3 before
+restoring the stack and CPU state and returning from the original SMC.
+
+Exception Handling Framework
+----------------------------
+
+Please refer to the `Exception Handling Framework`_ document.
+
+Power State Coordination Interface
+----------------------------------
+
+TODO: Provide design walkthrough of PSCI implementation.
+
+The PSCI v1.1 specification categorizes APIs as optional and mandatory. All the
+mandatory APIs in PSCI v1.1, PSCI v1.0 and in PSCI v0.2 draft specification
+`Power State Coordination Interface PDD`_ are implemented. The table lists
+the PSCI v1.1 APIs and their support in generic code.
+
+An API implementation might have a dependency on platform code e.g. CPU_SUSPEND
+requires the platform to export a part of the implementation. Hence the level
+of support of the mandatory APIs depends upon the support exported by the
+platform port as well. The Juno and FVP (all variants) platforms export all the
+required support.
+
++-----------------------------+-------------+-------------------------------+
+| PSCI v1.1 API               | Supported   | Comments                      |
++=============================+=============+===============================+
+| ``PSCI_VERSION``            | Yes         | The version returned is 1.1   |
++-----------------------------+-------------+-------------------------------+
+| ``CPU_SUSPEND``             | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``CPU_OFF``                 | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``CPU_ON``                  | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``AFFINITY_INFO``           | Yes         |                               |
++-----------------------------+-------------+-------------------------------+
+| ``MIGRATE``                 | Yes\*\*     |                               |
++-----------------------------+-------------+-------------------------------+
+| ``MIGRATE_INFO_TYPE``       | Yes\*\*     |                               |
++-----------------------------+-------------+-------------------------------+
+| ``MIGRATE_INFO_CPU``        | Yes\*\*     |                               |
++-----------------------------+-------------+-------------------------------+
+| ``SYSTEM_OFF``              | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``SYSTEM_RESET``            | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``PSCI_FEATURES``           | Yes         |                               |
++-----------------------------+-------------+-------------------------------+
+| ``CPU_FREEZE``              | No          |                               |
++-----------------------------+-------------+-------------------------------+
+| ``CPU_DEFAULT_SUSPEND``     | No          |                               |
++-----------------------------+-------------+-------------------------------+
+| ``NODE_HW_STATE``           | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``SYSTEM_SUSPEND``          | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``PSCI_SET_SUSPEND_MODE``   | No          |                               |
++-----------------------------+-------------+-------------------------------+
+| ``PSCI_STAT_RESIDENCY``     | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``PSCI_STAT_COUNT``         | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``SYSTEM_RESET2``           | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``MEM_PROTECT``             | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+| ``MEM_PROTECT_CHECK_RANGE`` | Yes\*       |                               |
++-----------------------------+-------------+-------------------------------+
+
+\*Note : These PSCI APIs require platform power management hooks to be
+registered with the generic PSCI code to be supported.
+
+\*\*Note : These PSCI APIs require appropriate Secure Payload Dispatcher
+hooks to be registered with the generic PSCI code to be supported.
+
+The PSCI implementation in TF-A is a library which can be integrated with
+AArch64 or AArch32 EL3 Runtime Software for Armv8-A systems. A guide to
+integrating PSCI library with AArch32 EL3 Runtime Software can be found
+`here`_.
+
+Secure-EL1 Payloads and Dispatchers
+-----------------------------------
+
+On a production system that includes a Trusted OS running in Secure-EL1/EL0,
+the Trusted OS is coupled with a companion runtime service in the BL31
+firmware. This service is responsible for the initialisation of the Trusted
+OS and all communications with it. The Trusted OS is the BL32 stage of the
+boot flow in TF-A. The firmware will attempt to locate, load and execute a
+BL32 image.
+
+TF-A uses a more general term for the BL32 software that runs at Secure-EL1 -
+the *Secure-EL1 Payload* - as it is not always a Trusted OS.
+
+TF-A provides a Test Secure-EL1 Payload (TSP) and a Test Secure-EL1 Payload
+Dispatcher (TSPD) service as an example of how a Trusted OS is supported on a
+production system using the Runtime Services Framework. On such a system, the
+Test BL32 image and service are replaced by the Trusted OS and its dispatcher
+service. The TF-A build system expects that the dispatcher will define the
+build flag ``NEED_BL32`` to enable it to include the BL32 in the build either
+as a binary or to compile from source depending on whether the ``BL32`` build
+option is specified or not.
+
+The TSP runs in Secure-EL1. It is designed to demonstrate synchronous
+communication with the normal-world software running in EL1/EL2. Communication
+is initiated by the normal-world software
+
+-  either directly through a Fast SMC (as defined in the `SMCCC`_)
+
+-  or indirectly through a `PSCI`_ SMC. The `PSCI`_ implementation in turn
+   informs the TSPD about the requested power management operation. This allows
+   the TSP to prepare for or respond to the power state change
+
+The TSPD service is responsible for.
+
+-  Initializing the TSP
+
+-  Routing requests and responses between the secure and the non-secure
+   states during the two types of communications just described
+
+Initializing a BL32 Image
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Secure-EL1 Payload Dispatcher (SPD) service is responsible for initializing
+the BL32 image. It needs access to the information passed by BL2 to BL31 to do
+so. This is provided by:
+
+.. code:: c
+
+    entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t);
+
+which returns a reference to the ``entry_point_info`` structure corresponding to
+the image which will be run in the specified security state. The SPD uses this
+API to get entry point information for the SECURE image, BL32.
+
+In the absence of a BL32 image, BL31 passes control to the normal world
+bootloader image (BL33). When the BL32 image is present, it is typical
+that the SPD wants control to be passed to BL32 first and then later to BL33.
+
+To do this the SPD has to register a BL32 initialization function during
+initialization of the SPD service. The BL32 initialization function has this
+prototype:
+
+.. code:: c
+
+    int32_t init(void);
+
+and is registered using the ``bl31_register_bl32_init()`` function.
+
+TF-A supports two approaches for the SPD to pass control to BL32 before
+returning through EL3 and running the non-trusted firmware (BL33):
+
+#. In the BL32 setup function, use ``bl31_set_next_image_type()`` to
+   request that the exit from ``bl31_main()`` is to the BL32 entrypoint in
+   Secure-EL1. BL31 will exit to BL32 using the asynchronous method by
+   calling ``bl31_prepare_next_image_entry()`` and ``el3_exit()``.
+
+   When the BL32 has completed initialization at Secure-EL1, it returns to
+   BL31 by issuing an SMC, using a Function ID allocated to the SPD. On
+   receipt of this SMC, the SPD service handler should switch the CPU context
+   from trusted to normal world and use the ``bl31_set_next_image_type()`` and
+   ``bl31_prepare_next_image_entry()`` functions to set up the initial return to
+   the normal world firmware BL33. On return from the handler the framework
+   will exit to EL2 and run BL33.
+
+#. The BL32 setup function registers an initialization function using
+   ``bl31_register_bl32_init()`` which provides a SPD-defined mechanism to
+   invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL32
+   entrypoint.
+
+   .. note::
+      The Test SPD service included with TF-A provides one implementation
+      of such a mechanism.
+
+   On completion BL32 returns control to BL31 via a SMC, and on receipt the
+   SPD service handler invokes the synchronous call return mechanism to return
+   to the BL32 initialization function. On return from this function,
+   ``bl31_main()`` will set up the return to the normal world firmware BL33 and
+   continue the boot process in the normal world.
+
+Crash Reporting in BL31
+-----------------------
+
+BL31 implements a scheme for reporting the processor state when an unhandled
+exception is encountered. The reporting mechanism attempts to preserve all the
+register contents and report it via a dedicated UART (PL011 console). BL31
+reports the general purpose, EL3, Secure EL1 and some EL2 state registers.
+
+A dedicated per-CPU crash stack is maintained by BL31 and this is retrieved via
+the per-CPU pointer cache. The implementation attempts to minimise the memory
+required for this feature. The file ``crash_reporting.S`` contains the
+implementation for crash reporting.
+
+The sample crash output is shown below.
+
+::
+
+    x0  :0x000000004F00007C
+    x1  :0x0000000007FFFFFF
+    x2  :0x0000000004014D50
+    x3  :0x0000000000000000
+    x4  :0x0000000088007998
+    x5  :0x00000000001343AC
+    x6  :0x0000000000000016
+    x7  :0x00000000000B8A38
+    x8  :0x00000000001343AC
+    x9  :0x00000000000101A8
+    x10 :0x0000000000000002
+    x11 :0x000000000000011C
+    x12 :0x00000000FEFDC644
+    x13 :0x00000000FED93FFC
+    x14 :0x0000000000247950
+    x15 :0x00000000000007A2
+    x16 :0x00000000000007A4
+    x17 :0x0000000000247950
+    x18 :0x0000000000000000
+    x19 :0x00000000FFFFFFFF
+    x20 :0x0000000004014D50
+    x21 :0x000000000400A38C
+    x22 :0x0000000000247950
+    x23 :0x0000000000000010
+    x24 :0x0000000000000024
+    x25 :0x00000000FEFDC868
+    x26 :0x00000000FEFDC86A
+    x27 :0x00000000019EDEDC
+    x28 :0x000000000A7CFDAA
+    x29 :0x0000000004010780
+    x30 :0x000000000400F004
+    scr_el3 :0x0000000000000D3D
+    sctlr_el3   :0x0000000000C8181F
+    cptr_el3    :0x0000000000000000
+    tcr_el3 :0x0000000080803520
+    daif    :0x00000000000003C0
+    mair_el3    :0x00000000000004FF
+    spsr_el3    :0x00000000800003CC
+    elr_el3 :0x000000000400C0CC
+    ttbr0_el3   :0x00000000040172A0
+    esr_el3 :0x0000000096000210
+    sp_el3  :0x0000000004014D50
+    far_el3 :0x000000004F00007C
+    spsr_el1    :0x0000000000000000
+    elr_el1 :0x0000000000000000
+    spsr_abt    :0x0000000000000000
+    spsr_und    :0x0000000000000000
+    spsr_irq    :0x0000000000000000
+    spsr_fiq    :0x0000000000000000
+    sctlr_el1   :0x0000000030C81807
+    actlr_el1   :0x0000000000000000
+    cpacr_el1   :0x0000000000300000
+    csselr_el1  :0x0000000000000002
+    sp_el1  :0x0000000004028800
+    esr_el1 :0x0000000000000000
+    ttbr0_el1   :0x000000000402C200
+    ttbr1_el1   :0x0000000000000000
+    mair_el1    :0x00000000000004FF
+    amair_el1   :0x0000000000000000
+    tcr_el1 :0x0000000000003520
+    tpidr_el1   :0x0000000000000000
+    tpidr_el0   :0x0000000000000000
+    tpidrro_el0 :0x0000000000000000
+    dacr32_el2  :0x0000000000000000
+    ifsr32_el2  :0x0000000000000000
+    par_el1 :0x0000000000000000
+    far_el1 :0x0000000000000000
+    afsr0_el1   :0x0000000000000000
+    afsr1_el1   :0x0000000000000000
+    contextidr_el1  :0x0000000000000000
+    vbar_el1    :0x0000000004027000
+    cntp_ctl_el0    :0x0000000000000000
+    cntp_cval_el0   :0x0000000000000000
+    cntv_ctl_el0    :0x0000000000000000
+    cntv_cval_el0   :0x0000000000000000
+    cntkctl_el1 :0x0000000000000000
+    sp_el0  :0x0000000004010780
+
+Guidelines for Reset Handlers
+-----------------------------
+
+TF-A implements a framework that allows CPU and platform ports to perform
+actions very early after a CPU is released from reset in both the cold and warm
+boot paths. This is done by calling the ``reset_handler()`` function in both
+the BL1 and BL31 images. It in turn calls the platform and CPU specific reset
+handling functions.
+
+Details for implementing a CPU specific reset handler can be found in
+Section 8. Details for implementing a platform specific reset handler can be
+found in the `Porting Guide`_ (see the ``plat_reset_handler()`` function).
+
+When adding functionality to a reset handler, keep in mind that if a different
+reset handling behavior is required between the first and the subsequent
+invocations of the reset handling code, this should be detected at runtime.
+In other words, the reset handler should be able to detect whether an action has
+already been performed and act as appropriate. Possible courses of actions are,
+e.g. skip the action the second time, or undo/redo it.
+
+Configuring secure interrupts
+-----------------------------
+
+The GIC driver is responsible for performing initial configuration of secure
+interrupts on the platform. To this end, the platform is expected to provide the
+GIC driver (either GICv2 or GICv3, as selected by the platform) with the
+interrupt configuration during the driver initialisation.
+
+Secure interrupt configuration are specified in an array of secure interrupt
+properties. In this scheme, in both GICv2 and GICv3 driver data structures, the
+``interrupt_props`` member points to an array of interrupt properties. Each
+element of the array specifies the interrupt number and its attributes
+(priority, group, configuration). Each element of the array shall be populated
+by the macro ``INTR_PROP_DESC()``. The macro takes the following arguments:
+
+- 10-bit interrupt number,
+
+- 8-bit interrupt priority,
+
+- Interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``,
+  ``INTR_TYPE_NS``),
+
+- Interrupt configuration (either ``GIC_INTR_CFG_LEVEL`` or
+  ``GIC_INTR_CFG_EDGE``).
+
+CPU specific operations framework
+---------------------------------
+
+Certain aspects of the Armv8-A architecture are implementation defined,
+that is, certain behaviours are not architecturally defined, but must be
+defined and documented by individual processor implementations. TF-A
+implements a framework which categorises the common implementation defined
+behaviours and allows a processor to export its implementation of that
+behaviour. The categories are:
+
+#. Processor specific reset sequence.
+
+#. Processor specific power down sequences.
+
+#. Processor specific register dumping as a part of crash reporting.
+
+#. Errata status reporting.
+
+Each of the above categories fulfils a different requirement.
+
+#. allows any processor specific initialization before the caches and MMU
+   are turned on, like implementation of errata workarounds, entry into
+   the intra-cluster coherency domain etc.
+
+#. allows each processor to implement the power down sequence mandated in
+   its Technical Reference Manual (TRM).
+
+#. allows a processor to provide additional information to the developer
+   in the event of a crash, for example Cortex-A53 has registers which
+   can expose the data cache contents.
+
+#. allows a processor to define a function that inspects and reports the status
+   of all errata workarounds on that processor.
+
+Please note that only 2. is mandated by the TRM.
+
+The CPU specific operations framework scales to accommodate a large number of
+different CPUs during power down and reset handling. The platform can specify
+any CPU optimization it wants to enable for each CPU. It can also specify
+the CPU errata workarounds to be applied for each CPU type during reset
+handling by defining CPU errata compile time macros. Details on these macros
+can be found in `CPU specific build macros`_.
+
+The CPU specific operations framework depends on the ``cpu_ops`` structure which
+needs to be exported for each type of CPU in the platform. It is defined in
+``include/lib/cpus/aarch64/cpu_macros.S`` and has the following fields : ``midr``,
+``reset_func()``, ``cpu_pwr_down_ops`` (array of power down functions) and
+``cpu_reg_dump()``.
+
+The CPU specific files in ``lib/cpus`` export a ``cpu_ops`` data structure with
+suitable handlers for that CPU. For example, ``lib/cpus/aarch64/cortex_a53.S``
+exports the ``cpu_ops`` for Cortex-A53 CPU. According to the platform
+configuration, these CPU specific files must be included in the build by
+the platform makefile. The generic CPU specific operations framework code exists
+in ``lib/cpus/aarch64/cpu_helpers.S``.
+
+CPU specific Reset Handling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+After a reset, the state of the CPU when it calls generic reset handler is:
+MMU turned off, both instruction and data caches turned off and not part
+of any coherency domain.
+
+The BL entrypoint code first invokes the ``plat_reset_handler()`` to allow
+the platform to perform any system initialization required and any system
+errata workarounds that needs to be applied. The ``get_cpu_ops_ptr()`` reads
+the current CPU midr, finds the matching ``cpu_ops`` entry in the ``cpu_ops``
+array and returns it. Note that only the part number and implementer fields
+in midr are used to find the matching ``cpu_ops`` entry. The ``reset_func()`` in
+the returned ``cpu_ops`` is then invoked which executes the required reset
+handling for that CPU and also any errata workarounds enabled by the platform.
+This function must preserve the values of general purpose registers x20 to x29.
+
+Refer to Section "Guidelines for Reset Handlers" for general guidelines
+regarding placement of code in a reset handler.
+
+CPU specific power down sequence
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+During the BL31 initialization sequence, the pointer to the matching ``cpu_ops``
+entry is stored in per-CPU data by ``init_cpu_ops()`` so that it can be quickly
+retrieved during power down sequences.
+
+Various CPU drivers register handlers to perform power down at certain power
+levels for that specific CPU. The PSCI service, upon receiving a power down
+request, determines the highest power level at which to execute power down
+sequence for a particular CPU. It uses the ``prepare_cpu_pwr_dwn()`` function to
+pick the right power down handler for the requested level. The function
+retrieves ``cpu_ops`` pointer member of per-CPU data, and from that, further
+retrieves ``cpu_pwr_down_ops`` array, and indexes into the required level. If the
+requested power level is higher than what a CPU driver supports, the handler
+registered for highest level is invoked.
+
+At runtime the platform hooks for power down are invoked by the PSCI service to
+perform platform specific operations during a power down sequence, for example
+turning off CCI coherency during a cluster power down.
+
+CPU specific register reporting during crash
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the crash reporting is enabled in BL31, when a crash occurs, the crash
+reporting framework calls ``do_cpu_reg_dump`` which retrieves the matching
+``cpu_ops`` using ``get_cpu_ops_ptr()`` function. The ``cpu_reg_dump()`` in
+``cpu_ops`` is invoked, which then returns the CPU specific register values to
+be reported and a pointer to the ASCII list of register names in a format
+expected by the crash reporting framework.
+
+CPU errata status reporting
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Errata workarounds for CPUs supported in TF-A are applied during both cold and
+warm boots, shortly after reset. Individual Errata workarounds are enabled as
+build options. Some errata workarounds have potential run-time implications;
+therefore some are enabled by default, others not. Platform ports shall
+override build options to enable or disable errata as appropriate. The CPU
+drivers take care of applying errata workarounds that are enabled and applicable
+to a given CPU. Refer to the section titled *CPU Errata Workarounds* in `CPUBM`_
+for more information.
+
+Functions in CPU drivers that apply errata workaround must follow the
+conventions listed below.
+
+The errata workaround must be authored as two separate functions:
+
+-  One that checks for errata. This function must determine whether that errata
+   applies to the current CPU. Typically this involves matching the current
+   CPUs revision and variant against a value that's known to be affected by the
+   errata. If the function determines that the errata applies to this CPU, it
+   must return ``ERRATA_APPLIES``; otherwise, it must return
+   ``ERRATA_NOT_APPLIES``. The utility functions ``cpu_get_rev_var`` and
+   ``cpu_rev_var_ls`` functions may come in handy for this purpose.
+
+For an errata identified as ``E``, the check function must be named
+``check_errata_E``.
+
+This function will be invoked at different times, both from assembly and from
+C run time. Therefore it must follow AAPCS, and must not use stack.
+
+-  Another one that applies the errata workaround. This function would call the
+   check function described above, and applies errata workaround if required.
+
+CPU drivers that apply errata workaround can optionally implement an assembly
+function that report the status of errata workarounds pertaining to that CPU.
+For a driver that registers the CPU, for example, ``cpux`` via ``declare_cpu_ops``
+macro, the errata reporting function, if it exists, must be named
+``cpux_errata_report``. This function will always be called with MMU enabled; it
+must follow AAPCS and may use stack.
+
+In a debug build of TF-A, on a CPU that comes out of reset, both BL1 and the
+runtime firmware (BL31 in AArch64, and BL32 in AArch32) will invoke errata
+status reporting function, if one exists, for that type of CPU.
+
+To report the status of each errata workaround, the function shall use the
+assembler macro ``report_errata``, passing it:
+
+-  The build option that enables the errata;
+
+-  The name of the CPU: this must be the same identifier that CPU driver
+   registered itself with, using ``declare_cpu_ops``;
+
+-  And the errata identifier: the identifier must match what's used in the
+   errata's check function described above.
+
+The errata status reporting function will be called once per CPU type/errata
+combination during the software's active life time.
+
+It's expected that whenever an errata workaround is submitted to TF-A, the
+errata reporting function is appropriately extended to report its status as
+well.
+
+Reporting the status of errata workaround is for informational purpose only; it
+has no functional significance.
+
+Memory layout of BL images
+--------------------------
+
+Each bootloader image can be divided in 2 parts:
+
+-  the static contents of the image. These are data actually stored in the
+   binary on the disk. In the ELF terminology, they are called ``PROGBITS``
+   sections;
+
+-  the run-time contents of the image. These are data that don't occupy any
+   space in the binary on the disk. The ELF binary just contains some
+   metadata indicating where these data will be stored at run-time and the
+   corresponding sections need to be allocated and initialized at run-time.
+   In the ELF terminology, they are called ``NOBITS`` sections.
+
+All PROGBITS sections are grouped together at the beginning of the image,
+followed by all NOBITS sections. This is true for all TF-A images and it is
+governed by the linker scripts. This ensures that the raw binary images are
+as small as possible. If a NOBITS section was inserted in between PROGBITS
+sections then the resulting binary file would contain zero bytes in place of
+this NOBITS section, making the image unnecessarily bigger. Smaller images
+allow faster loading from the FIP to the main memory.
+
+Linker scripts and symbols
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each bootloader stage image layout is described by its own linker script. The
+linker scripts export some symbols into the program symbol table. Their values
+correspond to particular addresses. TF-A code can refer to these symbols to
+figure out the image memory layout.
+
+Linker symbols follow the following naming convention in TF-A.
+
+-  ``__<SECTION>_START__``
+
+   Start address of a given section named ``<SECTION>``.
+
+-  ``__<SECTION>_END__``
+
+   End address of a given section named ``<SECTION>``. If there is an alignment
+   constraint on the section's end address then ``__<SECTION>_END__`` corresponds
+   to the end address of the section's actual contents, rounded up to the right
+   boundary. Refer to the value of ``__<SECTION>_UNALIGNED_END__`` to know the
+   actual end address of the section's contents.
+
+-  ``__<SECTION>_UNALIGNED_END__``
+
+   End address of a given section named ``<SECTION>`` without any padding or
+   rounding up due to some alignment constraint.
+
+-  ``__<SECTION>_SIZE__``
+
+   Size (in bytes) of a given section named ``<SECTION>``. If there is an
+   alignment constraint on the section's end address then ``__<SECTION>_SIZE__``
+   corresponds to the size of the section's actual contents, rounded up to the
+   right boundary. In other words, ``__<SECTION>_SIZE__ = __<SECTION>_END__ - _<SECTION>_START__``. Refer to the value of ``__<SECTION>_UNALIGNED_SIZE__``
+   to know the actual size of the section's contents.
+
+-  ``__<SECTION>_UNALIGNED_SIZE__``
+
+   Size (in bytes) of a given section named ``<SECTION>`` without any padding or
+   rounding up due to some alignment constraint. In other words,
+   ``__<SECTION>_UNALIGNED_SIZE__ = __<SECTION>_UNALIGNED_END__ - __<SECTION>_START__``.
+
+Some of the linker symbols are mandatory as TF-A code relies on them to be
+defined. They are listed in the following subsections. Some of them must be
+provided for each bootloader stage and some are specific to a given bootloader
+stage.
+
+The linker scripts define some extra, optional symbols. They are not actually
+used by any code but they help in understanding the bootloader images' memory
+layout as they are easy to spot in the link map files.
+
+Common linker symbols
+^^^^^^^^^^^^^^^^^^^^^
+
+All BL images share the following requirements:
+
+-  The BSS section must be zero-initialised before executing any C code.
+-  The coherent memory section (if enabled) must be zero-initialised as well.
+-  The MMU setup code needs to know the extents of the coherent and read-only
+   memory regions to set the right memory attributes. When
+   ``SEPARATE_CODE_AND_RODATA=1``, it needs to know more specifically how the
+   read-only memory region is divided between code and data.
+
+The following linker symbols are defined for this purpose:
+
+-  ``__BSS_START__``
+-  ``__BSS_SIZE__``
+-  ``__COHERENT_RAM_START__`` Must be aligned on a page-size boundary.
+-  ``__COHERENT_RAM_END__`` Must be aligned on a page-size boundary.
+-  ``__COHERENT_RAM_UNALIGNED_SIZE__``
+-  ``__RO_START__``
+-  ``__RO_END__``
+-  ``__TEXT_START__``
+-  ``__TEXT_END__``
+-  ``__RODATA_START__``
+-  ``__RODATA_END__``
+
+BL1's linker symbols
+^^^^^^^^^^^^^^^^^^^^
+
+BL1 being the ROM image, it has additional requirements. BL1 resides in ROM and
+it is entirely executed in place but it needs some read-write memory for its
+mutable data. Its ``.data`` section (i.e. its allocated read-write data) must be
+relocated from ROM to RAM before executing any C code.
+
+The following additional linker symbols are defined for BL1:
+
+-  ``__BL1_ROM_END__`` End address of BL1's ROM contents, covering its code
+   and ``.data`` section in ROM.
+-  ``__DATA_ROM_START__`` Start address of the ``.data`` section in ROM. Must be
+   aligned on a 16-byte boundary.
+-  ``__DATA_RAM_START__`` Address in RAM where the ``.data`` section should be
+   copied over. Must be aligned on a 16-byte boundary.
+-  ``__DATA_SIZE__`` Size of the ``.data`` section (in ROM or RAM).
+-  ``__BL1_RAM_START__`` Start address of BL1 read-write data.
+-  ``__BL1_RAM_END__`` End address of BL1 read-write data.
+
+How to choose the right base addresses for each bootloader stage image
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There is currently no support for dynamic image loading in TF-A. This means
+that all bootloader images need to be linked against their ultimate runtime
+locations and the base addresses of each image must be chosen carefully such
+that images don't overlap each other in an undesired way. As the code grows,
+the base addresses might need adjustments to cope with the new memory layout.
+
+The memory layout is completely specific to the platform and so there is no
+general recipe for choosing the right base addresses for each bootloader image.
+However, there are tools to aid in understanding the memory layout. These are
+the link map files: ``build/<platform>/<build-type>/bl<x>/bl<x>.map``, with ``<x>``
+being the stage bootloader. They provide a detailed view of the memory usage of
+each image. Among other useful information, they provide the end address of
+each image.
+
+-  ``bl1.map`` link map file provides ``__BL1_RAM_END__`` address.
+-  ``bl2.map`` link map file provides ``__BL2_END__`` address.
+-  ``bl31.map`` link map file provides ``__BL31_END__`` address.
+-  ``bl32.map`` link map file provides ``__BL32_END__`` address.
+
+For each bootloader image, the platform code must provide its start address
+as well as a limit address that it must not overstep. The latter is used in the
+linker scripts to check that the image doesn't grow past that address. If that
+happens, the linker will issue a message similar to the following:
+
+::
+
+    aarch64-none-elf-ld: BLx has exceeded its limit.
+
+Additionally, if the platform memory layout implies some image overlaying like
+on FVP, BL31 and TSP need to know the limit address that their PROGBITS
+sections must not overstep. The platform code must provide those.
+
+TF-A does not provide any mechanism to verify at boot time that the memory
+to load a new image is free to prevent overwriting a previously loaded image.
+The platform must specify the memory available in the system for all the
+relevant BL images to be loaded.
+
+For example, in the case of BL1 loading BL2, ``bl1_plat_sec_mem_layout()`` will
+return the region defined by the platform where BL1 intends to load BL2. The
+``load_image()`` function performs bounds check for the image size based on the
+base and maximum image size provided by the platforms. Platforms must take
+this behaviour into account when defining the base/size for each of the images.
+
+Memory layout on Arm development platforms
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following list describes the memory layout on the Arm development platforms:
+
+-  A 4KB page of shared memory is used for communication between Trusted
+   Firmware and the platform's power controller. This is located at the base of
+   Trusted SRAM. The amount of Trusted SRAM available to load the bootloader
+   images is reduced by the size of the shared memory.
+
+   The shared memory is used to store the CPUs' entrypoint mailbox. On Juno,
+   this is also used for the MHU payload when passing messages to and from the
+   SCP.
+
+-  Another 4 KB page is reserved for passing memory layout between BL1 and BL2
+   and also the dynamic firmware configurations.
+
+-  On FVP, BL1 is originally sitting in the Trusted ROM at address ``0x0``. On
+   Juno, BL1 resides in flash memory at address ``0x0BEC0000``. BL1 read-write
+   data are relocated to the top of Trusted SRAM at runtime.
+
+-  BL2 is loaded below BL1 RW
+
+-  EL3 Runtime Software, BL31 for AArch64 and BL32 for AArch32 (e.g. SP_MIN),
+   is loaded at the top of the Trusted SRAM, such that its NOBITS sections will
+   overwrite BL1 R/W data and BL2. This implies that BL1 global variables
+   remain valid only until execution reaches the EL3 Runtime Software entry
+   point during a cold boot.
+
+-  On Juno, SCP_BL2 is loaded temporarily into the EL3 Runtime Software memory
+   region and transfered to the SCP before being overwritten by EL3 Runtime
+   Software.
+
+-  BL32 (for AArch64) can be loaded in one of the following locations:
+
+   -  Trusted SRAM
+   -  Trusted DRAM (FVP only)
+   -  Secure region of DRAM (top 16MB of DRAM configured by the TrustZone
+      controller)
+
+   When BL32 (for AArch64) is loaded into Trusted SRAM, it is loaded below
+   BL31.
+
+The location of the BL32 image will result in different memory maps. This is
+illustrated for both FVP and Juno in the following diagrams, using the TSP as
+an example.
+
+.. note::
+   Loading the BL32 image in TZC secured DRAM doesn't change the memory
+   layout of the other images in Trusted SRAM.
+
+CONFIG section in memory layouts shown below contains:
+
+::
+
+    +--------------------+
+    |bl2_mem_params_descs|
+    |--------------------|
+    |     fw_configs     |
+    +--------------------+
+
+``bl2_mem_params_descs`` contains parameters passed from BL2 to next the
+BL image during boot.
+
+``fw_configs`` includes soc_fw_config, tos_fw_config and tb_fw_config.
+
+**FVP with TSP in Trusted SRAM with firmware configs :**
+(These diagrams only cover the AArch64 case)
+
+::
+
+                   DRAM
+    0xffffffff +----------+
+               :          :
+               |----------|
+               |HW_CONFIG |
+    0x83000000 |----------|  (non-secure)
+               |          |
+    0x80000000 +----------+
+
+               Trusted SRAM
+    0x04040000 +----------+  loaded by BL2  +----------------+
+               | BL1 (rw) |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |  BL31 NOBITS   |
+               |   BL2    |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |----------------|
+               |          |  <<<<<<<<<<<<<  | BL31 PROGBITS  |
+               |          |  <<<<<<<<<<<<<  |----------------|
+               |          |  <<<<<<<<<<<<<  |     BL32       |
+    0x04002000 +----------+                 +----------------+
+               |  CONFIG  |
+    0x04001000 +----------+
+               |  Shared  |
+    0x04000000 +----------+
+
+               Trusted ROM
+    0x04000000 +----------+
+               | BL1 (ro) |
+    0x00000000 +----------+
+
+**FVP with TSP in Trusted DRAM with firmware configs (default option):**
+
+::
+
+                     DRAM
+    0xffffffff +--------------+
+               :              :
+               |--------------|
+               |  HW_CONFIG   |
+    0x83000000 |--------------|  (non-secure)
+               |              |
+    0x80000000 +--------------+
+
+                Trusted DRAM
+    0x08000000 +--------------+
+               |     BL32     |
+    0x06000000 +--------------+
+
+                 Trusted SRAM
+    0x04040000 +--------------+  loaded by BL2  +----------------+
+               |   BL1 (rw)   |  <<<<<<<<<<<<<  |                |
+               |--------------|  <<<<<<<<<<<<<  |  BL31 NOBITS   |
+               |     BL2      |  <<<<<<<<<<<<<  |                |
+               |--------------|  <<<<<<<<<<<<<  |----------------|
+               |              |  <<<<<<<<<<<<<  | BL31 PROGBITS  |
+               |              |                 +----------------+
+               +--------------+
+               |    CONFIG    |
+    0x04001000 +--------------+
+               |    Shared    |
+    0x04000000 +--------------+
+
+                 Trusted ROM
+    0x04000000 +--------------+
+               |   BL1 (ro)   |
+    0x00000000 +--------------+
+
+**FVP with TSP in TZC-Secured DRAM with firmware configs :**
+
+::
+
+                   DRAM
+    0xffffffff +----------+
+               |  BL32    |  (secure)
+    0xff000000 +----------+
+               |          |
+               |----------|
+               |HW_CONFIG |
+    0x83000000 |----------|  (non-secure)
+               |          |
+    0x80000000 +----------+
+
+               Trusted SRAM
+    0x04040000 +----------+  loaded by BL2  +----------------+
+               | BL1 (rw) |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |  BL31 NOBITS   |
+               |   BL2    |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |----------------|
+               |          |  <<<<<<<<<<<<<  | BL31 PROGBITS  |
+               |          |                 +----------------+
+    0x04002000 +----------+
+               |  CONFIG  |
+    0x04001000 +----------+
+               |  Shared  |
+    0x04000000 +----------+
+
+               Trusted ROM
+    0x04000000 +----------+
+               | BL1 (ro) |
+    0x00000000 +----------+
+
+**Juno with BL32 in Trusted SRAM :**
+
+::
+
+                  Flash0
+    0x0C000000 +----------+
+               :          :
+    0x0BED0000 |----------|
+               | BL1 (ro) |
+    0x0BEC0000 |----------|
+               :          :
+    0x08000000 +----------+                  BL31 is loaded
+                                             after SCP_BL2 has
+               Trusted SRAM                  been sent to SCP
+    0x04040000 +----------+  loaded by BL2  +----------------+
+               | BL1 (rw) |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |  BL31 NOBITS   |
+               |   BL2    |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |----------------|
+               | SCP_BL2  |  <<<<<<<<<<<<<  | BL31 PROGBITS  |
+               |----------|  <<<<<<<<<<<<<  |----------------|
+               |          |  <<<<<<<<<<<<<  |     BL32       |
+               |          |                 +----------------+
+               |          |
+    0x04001000 +----------+
+               |   MHU    |
+    0x04000000 +----------+
+
+**Juno with BL32 in TZC-secured DRAM :**
+
+::
+
+                   DRAM
+    0xFFE00000 +----------+
+               |  BL32    |  (secure)
+    0xFF000000 |----------|
+               |          |
+               :          :  (non-secure)
+               |          |
+    0x80000000 +----------+
+
+                  Flash0
+    0x0C000000 +----------+
+               :          :
+    0x0BED0000 |----------|
+               | BL1 (ro) |
+    0x0BEC0000 |----------|
+               :          :
+    0x08000000 +----------+                  BL31 is loaded
+                                             after SCP_BL2 has
+               Trusted SRAM                  been sent to SCP
+    0x04040000 +----------+  loaded by BL2  +----------------+
+               | BL1 (rw) |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |  BL31 NOBITS   |
+               |   BL2    |  <<<<<<<<<<<<<  |                |
+               |----------|  <<<<<<<<<<<<<  |----------------|
+               | SCP_BL2  |  <<<<<<<<<<<<<  | BL31 PROGBITS  |
+               |----------|                 +----------------+
+    0x04001000 +----------+
+               |   MHU    |
+    0x04000000 +----------+
+
+Library at ROM
+---------------
+
+Please refer to the `ROMLIB Design`_ document.
+
+Firmware Image Package (FIP)
+----------------------------
+
+Using a Firmware Image Package (FIP) allows for packing bootloader images (and
+potentially other payloads) into a single archive that can be loaded by TF-A
+from non-volatile platform storage. A driver to load images from a FIP has
+been added to the storage layer and allows a package to be read from supported
+platform storage. A tool to create Firmware Image Packages is also provided
+and described below.
+
+Firmware Image Package layout
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The FIP layout consists of a table of contents (ToC) followed by payload data.
+The ToC itself has a header followed by one or more table entries. The ToC is
+terminated by an end marker entry, and since the size of the ToC is 0 bytes,
+the offset equals the total size of the FIP file. All ToC entries describe some
+payload data that has been appended to the end of the binary package. With the
+information provided in the ToC entry the corresponding payload data can be
+retrieved.
+
+::
+
+    ------------------
+    | ToC Header     |
+    |----------------|
+    | ToC Entry 0    |
+    |----------------|
+    | ToC Entry 1    |
+    |----------------|
+    | ToC End Marker |
+    |----------------|
+    |                |
+    |     Data 0     |
+    |                |
+    |----------------|
+    |                |
+    |     Data 1     |
+    |                |
+    ------------------
+
+The ToC header and entry formats are described in the header file
+``include/tools_share/firmware_image_package.h``. This file is used by both the
+tool and TF-A.
+
+The ToC header has the following fields:
+
+::
+
+    `name`: The name of the ToC. This is currently used to validate the header.
+    `serial_number`: A non-zero number provided by the creation tool
+    `flags`: Flags associated with this data.
+        Bits 0-31: Reserved
+        Bits 32-47: Platform defined
+        Bits 48-63: Reserved
+
+A ToC entry has the following fields:
+
+::
+
+    `uuid`: All files are referred to by a pre-defined Universally Unique
+        IDentifier [UUID] . The UUIDs are defined in
+        `include/tools_share/firmware_image_package.h`. The platform translates
+        the requested image name into the corresponding UUID when accessing the
+        package.
+    `offset_address`: The offset address at which the corresponding payload data
+        can be found. The offset is calculated from the ToC base address.
+    `size`: The size of the corresponding payload data in bytes.
+    `flags`: Flags associated with this entry. None are yet defined.
+
+Firmware Image Package creation tool
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The FIP creation tool can be used to pack specified images into a binary
+package that can be loaded by TF-A from platform storage. The tool currently
+only supports packing bootloader images. Additional image definitions can be
+added to the tool as required.
+
+The tool can be found in ``tools/fiptool``.
+
+Loading from a Firmware Image Package (FIP)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Firmware Image Package (FIP) driver can load images from a binary package on
+non-volatile platform storage. For the Arm development platforms, this is
+currently NOR FLASH.
+
+Bootloader images are loaded according to the platform policy as specified by
+the function ``plat_get_image_source()``. For the Arm development platforms, this
+means the platform will attempt to load images from a Firmware Image Package
+located at the start of NOR FLASH0.
+
+The Arm development platforms' policy is to only allow loading of a known set of
+images. The platform policy can be modified to allow additional images.
+
+Use of coherent memory in TF-A
+------------------------------
+
+There might be loss of coherency when physical memory with mismatched
+shareability, cacheability and memory attributes is accessed by multiple CPUs
+(refer to section B2.9 of `Arm ARM`_ for more details). This possibility occurs
+in TF-A during power up/down sequences when coherency, MMU and caches are
+turned on/off incrementally.
+
+TF-A defines coherent memory as a region of memory with Device nGnRE attributes
+in the translation tables. The translation granule size in TF-A is 4KB. This
+is the smallest possible size of the coherent memory region.
+
+By default, all data structures which are susceptible to accesses with
+mismatched attributes from various CPUs are allocated in a coherent memory
+region (refer to section 2.1 of `Porting Guide`_). The coherent memory region
+accesses are Outer Shareable, non-cacheable and they can be accessed
+with the Device nGnRE attributes when the MMU is turned on. Hence, at the
+expense of at least an extra page of memory, TF-A is able to work around
+coherency issues due to mismatched memory attributes.
+
+The alternative to the above approach is to allocate the susceptible data
+structures in Normal WriteBack WriteAllocate Inner shareable memory. This
+approach requires the data structures to be designed so that it is possible to
+work around the issue of mismatched memory attributes by performing software
+cache maintenance on them.
+
+Disabling the use of coherent memory in TF-A
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It might be desirable to avoid the cost of allocating coherent memory on
+platforms which are memory constrained. TF-A enables inclusion of coherent
+memory in firmware images through the build flag ``USE_COHERENT_MEM``.
+This flag is enabled by default. It can be disabled to choose the second
+approach described above.
+
+The below sections analyze the data structures allocated in the coherent memory
+region and the changes required to allocate them in normal memory.
+
+Coherent memory usage in PSCI implementation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``psci_non_cpu_pd_nodes`` data structure stores the platform's power domain
+tree information for state management of power domains. By default, this data
+structure is allocated in the coherent memory region in TF-A because it can be
+accessed by multiple CPUs, either with caches enabled or disabled.
+
+.. code:: c
+
+    typedef struct non_cpu_pwr_domain_node {
+        /*
+         * Index of the first CPU power domain node level 0 which has this node
+         * as its parent.
+         */
+        unsigned int cpu_start_idx;
+
+        /*
+         * Number of CPU power domains which are siblings of the domain indexed
+         * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
+         * -> cpu_start_idx + ncpus' have this node as their parent.
+         */
+        unsigned int ncpus;
+
+        /*
+         * Index of the parent power domain node.
+         */
+        unsigned int parent_node;
+
+        plat_local_state_t local_state;
+
+        unsigned char level;
+
+        /* For indexing the psci_lock array*/
+        unsigned char lock_index;
+    } non_cpu_pd_node_t;
+
+In order to move this data structure to normal memory, the use of each of its
+fields must be analyzed. Fields like ``cpu_start_idx``, ``ncpus``, ``parent_node``
+``level`` and ``lock_index`` are only written once during cold boot. Hence removing
+them from coherent memory involves only doing a clean and invalidate of the
+cache lines after these fields are written.
+
+The field ``local_state`` can be concurrently accessed by multiple CPUs in
+different cache states. A Lamport's Bakery lock ``psci_locks`` is used to ensure
+mutual exclusion to this field and a clean and invalidate is needed after it
+is written.
+
+Bakery lock data
+~~~~~~~~~~~~~~~~
+
+The bakery lock data structure ``bakery_lock_t`` is allocated in coherent memory
+and is accessed by multiple CPUs with mismatched attributes. ``bakery_lock_t`` is
+defined as follows:
+
+.. code:: c
+
+    typedef struct bakery_lock {
+        /*
+         * The lock_data is a bit-field of 2 members:
+         * Bit[0]       : choosing. This field is set when the CPU is
+         *                choosing its bakery number.
+         * Bits[1 - 15] : number. This is the bakery number allocated.
+         */
+        volatile uint16_t lock_data[BAKERY_LOCK_MAX_CPUS];
+    } bakery_lock_t;
+
+It is a characteristic of Lamport's Bakery algorithm that the volatile per-CPU
+fields can be read by all CPUs but only written to by the owning CPU.
+
+Depending upon the data cache line size, the per-CPU fields of the
+``bakery_lock_t`` structure for multiple CPUs may exist on a single cache line.
+These per-CPU fields can be read and written during lock contention by multiple
+CPUs with mismatched memory attributes. Since these fields are a part of the
+lock implementation, they do not have access to any other locking primitive to
+safeguard against the resulting coherency issues. As a result, simple software
+cache maintenance is not enough to allocate them in coherent memory. Consider
+the following example.
+
+CPU0 updates its per-CPU field with data cache enabled. This write updates a
+local cache line which contains a copy of the fields for other CPUs as well. Now
+CPU1 updates its per-CPU field of the ``bakery_lock_t`` structure with data cache
+disabled. CPU1 then issues a DCIVAC operation to invalidate any stale copies of
+its field in any other cache line in the system. This operation will invalidate
+the update made by CPU0 as well.
+
+To use bakery locks when ``USE_COHERENT_MEM`` is disabled, the lock data structure
+has been redesigned. The changes utilise the characteristic of Lamport's Bakery
+algorithm mentioned earlier. The bakery_lock structure only allocates the memory
+for a single CPU. The macro ``DEFINE_BAKERY_LOCK`` allocates all the bakery locks
+needed for a CPU into a section ``bakery_lock``. The linker allocates the memory
+for other cores by using the total size allocated for the bakery_lock section
+and multiplying it with (PLATFORM_CORE_COUNT - 1). This enables software to
+perform software cache maintenance on the lock data structure without running
+into coherency issues associated with mismatched attributes.
+
+The bakery lock data structure ``bakery_info_t`` is defined for use when
+``USE_COHERENT_MEM`` is disabled as follows:
+
+.. code:: c
+
+    typedef struct bakery_info {
+        /*
+         * The lock_data is a bit-field of 2 members:
+         * Bit[0]       : choosing. This field is set when the CPU is
+         *                choosing its bakery number.
+         * Bits[1 - 15] : number. This is the bakery number allocated.
+         */
+         volatile uint16_t lock_data;
+    } bakery_info_t;
+
+The ``bakery_info_t`` represents a single per-CPU field of one lock and
+the combination of corresponding ``bakery_info_t`` structures for all CPUs in the
+system represents the complete bakery lock. The view in memory for a system
+with n bakery locks are:
+
+::
+
+    bakery_lock section start
+    |----------------|
+    | `bakery_info_t`| <-- Lock_0 per-CPU field
+    |    Lock_0      |     for CPU0
+    |----------------|
+    | `bakery_info_t`| <-- Lock_1 per-CPU field
+    |    Lock_1      |     for CPU0
+    |----------------|
+    | ....           |
+    |----------------|
+    | `bakery_info_t`| <-- Lock_N per-CPU field
+    |    Lock_N      |     for CPU0
+    ------------------
+    |    XXXXX       |
+    | Padding to     |
+    | next Cache WB  | <--- Calculate PERCPU_BAKERY_LOCK_SIZE, allocate
+    |  Granule       |       continuous memory for remaining CPUs.
+    ------------------
+    | `bakery_info_t`| <-- Lock_0 per-CPU field
+    |    Lock_0      |     for CPU1
+    |----------------|
+    | `bakery_info_t`| <-- Lock_1 per-CPU field
+    |    Lock_1      |     for CPU1
+    |----------------|
+    | ....           |
+    |----------------|
+    | `bakery_info_t`| <-- Lock_N per-CPU field
+    |    Lock_N      |     for CPU1
+    ------------------
+    |    XXXXX       |
+    | Padding to     |
+    | next Cache WB  |
+    |  Granule       |
+    ------------------
+
+Consider a system of 2 CPUs with 'N' bakery locks as shown above. For an
+operation on Lock_N, the corresponding ``bakery_info_t`` in both CPU0 and CPU1
+``bakery_lock`` section need to be fetched and appropriate cache operations need
+to be performed for each access.
+
+On Arm Platforms, bakery locks are used in psci (``psci_locks``) and power controller
+driver (``arm_lock``).
+
+Non Functional Impact of removing coherent memory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Removal of the coherent memory region leads to the additional software overhead
+of performing cache maintenance for the affected data structures. However, since
+the memory where the data structures are allocated is cacheable, the overhead is
+mostly mitigated by an increase in performance.
+
+There is however a performance impact for bakery locks, due to:
+
+-  Additional cache maintenance operations, and
+-  Multiple cache line reads for each lock operation, since the bakery locks
+   for each CPU are distributed across different cache lines.
+
+The implementation has been optimized to minimize this additional overhead.
+Measurements indicate that when bakery locks are allocated in Normal memory, the
+minimum latency of acquiring a lock is on an average 3-4 micro seconds whereas
+in Device memory the same is 2 micro seconds. The measurements were done on the
+Juno Arm development platform.
+
+As mentioned earlier, almost a page of memory can be saved by disabling
+``USE_COHERENT_MEM``. Each platform needs to consider these trade-offs to decide
+whether coherent memory should be used. If a platform disables
+``USE_COHERENT_MEM`` and needs to use bakery locks in the porting layer, it can
+optionally define macro ``PLAT_PERCPU_BAKERY_LOCK_SIZE`` (see the
+`Porting Guide`_). Refer to the reference platform code for examples.
+
+Isolating code and read-only data on separate memory pages
+----------------------------------------------------------
+
+In the Armv8-A VMSA, translation table entries include fields that define the
+properties of the target memory region, such as its access permissions. The
+smallest unit of memory that can be addressed by a translation table entry is
+a memory page. Therefore, if software needs to set different permissions on two
+memory regions then it needs to map them using different memory pages.
+
+The default memory layout for each BL image is as follows:
+
+::
+
+       |        ...        |
+       +-------------------+
+       |  Read-write data  |
+       +-------------------+ Page boundary
+       |     <Padding>     |
+       +-------------------+
+       | Exception vectors |
+       +-------------------+ 2 KB boundary
+       |     <Padding>     |
+       +-------------------+
+       |  Read-only data   |
+       +-------------------+
+       |       Code        |
+       +-------------------+ BLx_BASE
+
+.. note::
+   The 2KB alignment for the exception vectors is an architectural
+   requirement.
+
+The read-write data start on a new memory page so that they can be mapped with
+read-write permissions, whereas the code and read-only data below are configured
+as read-only.
+
+However, the read-only data are not aligned on a page boundary. They are
+contiguous to the code. Therefore, the end of the code section and the beginning
+of the read-only data one might share a memory page. This forces both to be
+mapped with the same memory attributes. As the code needs to be executable, this
+means that the read-only data stored on the same memory page as the code are
+executable as well. This could potentially be exploited as part of a security
+attack.
+
+TF provides the build flag ``SEPARATE_CODE_AND_RODATA`` to isolate the code and
+read-only data on separate memory pages. This in turn allows independent control
+of the access permissions for the code and read-only data. In this case,
+platform code gets a finer-grained view of the image layout and can
+appropriately map the code region as executable and the read-only data as
+execute-never.
+
+This has an impact on memory footprint, as padding bytes need to be introduced
+between the code and read-only data to ensure the segregation of the two. To
+limit the memory cost, this flag also changes the memory layout such that the
+code and exception vectors are now contiguous, like so:
+
+::
+
+       |        ...        |
+       +-------------------+
+       |  Read-write data  |
+       +-------------------+ Page boundary
+       |     <Padding>     |
+       +-------------------+
+       |  Read-only data   |
+       +-------------------+ Page boundary
+       |     <Padding>     |
+       +-------------------+
+       | Exception vectors |
+       +-------------------+ 2 KB boundary
+       |     <Padding>     |
+       +-------------------+
+       |       Code        |
+       +-------------------+ BLx_BASE
+
+With this more condensed memory layout, the separation of read-only data will
+add zero or one page to the memory footprint of each BL image. Each platform
+should consider the trade-off between memory footprint and security.
+
+This build flag is disabled by default, minimising memory footprint. On Arm
+platforms, it is enabled.
+
+Publish and Subscribe Framework
+-------------------------------
+
+The Publish and Subscribe Framework allows EL3 components to define and publish
+events, to which other EL3 components can subscribe.
+
+The following macros are provided by the framework:
+
+-  ``REGISTER_PUBSUB_EVENT(event)``: Defines an event, and takes one argument,
+   the event name, which must be a valid C identifier. All calls to
+   ``REGISTER_PUBSUB_EVENT`` macro must be placed in the file
+   ``pubsub_events.h``.
+
+-  ``PUBLISH_EVENT_ARG(event, arg)``: Publishes a defined event, by iterating
+   subscribed handlers and calling them in turn. The handlers will be passed the
+   parameter ``arg``. The expected use-case is to broadcast an event.
+
+-  ``PUBLISH_EVENT(event)``: Like ``PUBLISH_EVENT_ARG``, except that the value
+   ``NULL`` is passed to subscribed handlers.
+
+-  ``SUBSCRIBE_TO_EVENT(event, handler)``: Registers the ``handler`` to
+   subscribe to ``event``. The handler will be executed whenever the ``event``
+   is published.
+
+-  ``for_each_subscriber(event, subscriber)``: Iterates through all handlers
+   subscribed for ``event``. ``subscriber`` must be a local variable of type
+   ``pubsub_cb_t *``, and will point to each subscribed handler in turn during
+   iteration. This macro can be used for those patterns that none of the
+   ``PUBLISH_EVENT_*()`` macros cover.
+
+Publishing an event that wasn't defined using ``REGISTER_PUBSUB_EVENT`` will
+result in build error. Subscribing to an undefined event however won't.
+
+Subscribed handlers must be of type ``pubsub_cb_t``, with following function
+signature:
+
+.. code:: c
+
+   typedef void* (*pubsub_cb_t)(const void *arg);
+
+There may be arbitrary number of handlers registered to the same event. The
+order in which subscribed handlers are notified when that event is published is
+not defined. Subscribed handlers may be executed in any order; handlers should
+not assume any relative ordering amongst them.
+
+Publishing an event on a PE will result in subscribed handlers executing on that
+PE only; it won't cause handlers to execute on a different PE.
+
+Note that publishing an event on a PE blocks until all the subscribed handlers
+finish executing on the PE.
+
+TF-A generic code publishes and subscribes to some events within. Platform
+ports are discouraged from subscribing to them. These events may be withdrawn,
+renamed, or have their semantics altered in the future. Platforms may however
+register, publish, and subscribe to platform-specific events.
+
+Publish and Subscribe Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A publisher that wants to publish event ``foo`` would:
+
+-  Define the event ``foo`` in the ``pubsub_events.h``.
+
+   .. code:: c
+
+      REGISTER_PUBSUB_EVENT(foo);
+
+-  Depending on the nature of event, use one of ``PUBLISH_EVENT_*()`` macros to
+   publish the event at the appropriate path and time of execution.
+
+A subscriber that wants to subscribe to event ``foo`` published above would
+implement:
+
+.. code:: c
+
+    void *foo_handler(const void *arg)
+    {
+         void *result;
+
+         /* Do handling ... */
+
+         return result;
+    }
+
+    SUBSCRIBE_TO_EVENT(foo, foo_handler);
+
+
+Reclaiming the BL31 initialization code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A significant amount of the code used for the initialization of BL31 is never
+needed again after boot time. In order to reduce the runtime memory
+footprint, the memory used for this code can be reclaimed after initialization
+has finished and be used for runtime data.
+
+The build option ``RECLAIM_INIT_CODE`` can be set to mark this boot time code
+with a ``.text.init.*`` attribute which can be filtered and placed suitably
+within the BL image for later reclamation by the platform. The platform can
+specify the filter and the memory region for this init section in BL31 via the
+plat.ld.S linker script. For example, on the FVP, this section is placed
+overlapping the secondary CPU stacks so that after the cold boot is done, this
+memory can be reclaimed for the stacks. The init memory section is initially
+mapped with ``RO``, ``EXECUTE`` attributes. After BL31 initialization has
+completed, the FVP changes the attributes of this section to ``RW``,
+``EXECUTE_NEVER`` allowing it to be used for runtime data. The memory attributes
+are changed within the ``bl31_plat_runtime_setup`` platform hook. The init
+section section can be reclaimed for any data which is accessed after cold
+boot initialization and it is upto the platform to make the decision.
+
+Performance Measurement Framework
+---------------------------------
+
+The Performance Measurement Framework (PMF) facilitates collection of
+timestamps by registered services and provides interfaces to retrieve them
+from within TF-A. A platform can choose to expose appropriate SMCs to
+retrieve these collected timestamps.
+
+By default, the global physical counter is used for the timestamp
+value and is read via ``CNTPCT_EL0``. The framework allows to retrieve
+timestamps captured by other CPUs.
+
+Timestamp identifier format
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A PMF timestamp is uniquely identified across the system via the
+timestamp ID or ``tid``. The ``tid`` is composed as follows:
+
+::
+
+    Bits 0-7: The local timestamp identifier.
+    Bits 8-9: Reserved.
+    Bits 10-15: The service identifier.
+    Bits 16-31: Reserved.
+
+#. The service identifier. Each PMF service is identified by a
+   service name and a service identifier. Both the service name and
+   identifier are unique within the system as a whole.
+
+#. The local timestamp identifier. This identifier is unique within a given
+   service.
+
+Registering a PMF service
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To register a PMF service, the ``PMF_REGISTER_SERVICE()`` macro from ``pmf.h``
+is used. The arguments required are the service name, the service ID,
+the total number of local timestamps to be captured and a set of flags.
+
+The ``flags`` field can be specified as a bitwise-OR of the following values:
+
+::
+
+    PMF_STORE_ENABLE: The timestamp is stored in memory for later retrieval.
+    PMF_DUMP_ENABLE: The timestamp is dumped on the serial console.
+
+The ``PMF_REGISTER_SERVICE()`` reserves memory to store captured
+timestamps in a PMF specific linker section at build time.
+Additionally, it defines necessary functions to capture and
+retrieve a particular timestamp for the given service at runtime.
+
+The macro ``PMF_REGISTER_SERVICE()`` only enables capturing PMF timestamps
+from within TF-A. In order to retrieve timestamps from outside of TF-A, the
+``PMF_REGISTER_SERVICE_SMC()`` macro must be used instead. This macro
+accepts the same set of arguments as the ``PMF_REGISTER_SERVICE()``
+macro but additionally supports retrieving timestamps using SMCs.
+
+Capturing a timestamp
+~~~~~~~~~~~~~~~~~~~~~
+
+PMF timestamps are stored in a per-service timestamp region. On a
+system with multiple CPUs, each timestamp is captured and stored
+in a per-CPU cache line aligned memory region.
+
+Having registered the service, the ``PMF_CAPTURE_TIMESTAMP()`` macro can be
+used to capture a timestamp at the location where it is used. The macro
+takes the service name, a local timestamp identifier and a flag as arguments.
+
+The ``flags`` field argument can be zero, or ``PMF_CACHE_MAINT`` which
+instructs PMF to do cache maintenance following the capture. Cache
+maintenance is required if any of the service's timestamps are captured
+with data cache disabled.
+
+To capture a timestamp in assembly code, the caller should use
+``pmf_calc_timestamp_addr`` macro (defined in ``pmf_asm_macros.S``) to
+calculate the address of where the timestamp would be stored. The
+caller should then read ``CNTPCT_EL0`` register to obtain the timestamp
+and store it at the determined address for later retrieval.
+
+Retrieving a timestamp
+~~~~~~~~~~~~~~~~~~~~~~
+
+From within TF-A, timestamps for individual CPUs can be retrieved using either
+``PMF_GET_TIMESTAMP_BY_MPIDR()`` or ``PMF_GET_TIMESTAMP_BY_INDEX()`` macros.
+These macros accept the CPU's MPIDR value, or its ordinal position
+respectively.
+
+From outside TF-A, timestamps for individual CPUs can be retrieved by calling
+into ``pmf_smc_handler()``.
+
+::
+
+    Interface : pmf_smc_handler()
+    Argument  : unsigned int smc_fid, u_register_t x1,
+                u_register_t x2, u_register_t x3,
+                u_register_t x4, void *cookie,
+                void *handle, u_register_t flags
+    Return    : uintptr_t
+
+    smc_fid: Holds the SMC identifier which is either `PMF_SMC_GET_TIMESTAMP_32`
+        when the caller of the SMC is running in AArch32 mode
+        or `PMF_SMC_GET_TIMESTAMP_64` when the caller is running in AArch64 mode.
+    x1: Timestamp identifier.
+    x2: The `mpidr` of the CPU for which the timestamp has to be retrieved.
+        This can be the `mpidr` of a different core to the one initiating
+        the SMC.  In that case, service specific cache maintenance may be
+        required to ensure the updated copy of the timestamp is returned.
+    x3: A flags value that is either 0 or `PMF_CACHE_MAINT`.  If
+        `PMF_CACHE_MAINT` is passed, then the PMF code will perform a
+        cache invalidate before reading the timestamp.  This ensures
+        an updated copy is returned.
+
+The remaining arguments, ``x4``, ``cookie``, ``handle`` and ``flags`` are unused
+in this implementation.
+
+PMF code structure
+~~~~~~~~~~~~~~~~~~
+
+#. ``pmf_main.c`` consists of core functions that implement service registration,
+   initialization, storing, dumping and retrieving timestamps.
+
+#. ``pmf_smc.c`` contains the SMC handling for registered PMF services.
+
+#. ``pmf.h`` contains the public interface to Performance Measurement Framework.
+
+#. ``pmf_asm_macros.S`` consists of macros to facilitate capturing timestamps in
+   assembly code.
+
+#. ``pmf_helpers.h`` is an internal header used by ``pmf.h``.
+
+Armv8-A Architecture Extensions
+-------------------------------
+
+TF-A makes use of Armv8-A Architecture Extensions where applicable. This
+section lists the usage of Architecture Extensions, and build flags
+controlling them.
+
+In general, and unless individually mentioned, the build options
+``ARM_ARCH_MAJOR`` and ``ARM_ARCH_MINOR`` select the Architecture Extension to
+target when building TF-A. Subsequent Arm Architecture Extensions are backward
+compatible with previous versions.
+
+The build system only requires that ``ARM_ARCH_MAJOR`` and ``ARM_ARCH_MINOR`` have a
+valid numeric value. These build options only control whether or not
+Architecture Extension-specific code is included in the build. Otherwise, TF-A
+targets the base Armv8.0-A architecture; i.e. as if ``ARM_ARCH_MAJOR`` == 8
+and ``ARM_ARCH_MINOR`` == 0, which are also their respective default values.
+
+See also the *Summary of build options* in `User Guide`_.
+
+For details on the Architecture Extension and available features, please refer
+to the respective Architecture Extension Supplement.
+
+Armv8.1-A
+~~~~~~~~~
+
+This Architecture Extension is targeted when ``ARM_ARCH_MAJOR`` >= 8, or when
+``ARM_ARCH_MAJOR`` == 8 and ``ARM_ARCH_MINOR`` >= 1.
+
+-  The Compare and Swap instruction is used to implement spinlocks. Otherwise,
+   the load-/store-exclusive instruction pair is used.
+
+Armv8.2-A
+~~~~~~~~~
+
+-  The presence of ARMv8.2-TTCNP is detected at runtime. When it is present, the
+   Common not Private (TTBRn_ELx.CnP) bit is enabled to indicate that multiple
+   Processing Elements in the same Inner Shareable domain use the same
+   translation table entries for a given stage of translation for a particular
+   translation regime.
+
+Armv8.3-A
+~~~~~~~~~
+
+-  Pointer authentication features of Armv8.3-A are unconditionally enabled in
+   the Non-secure world so that lower ELs are allowed to use them without
+   causing a trap to EL3.
+
+   In order to enable the Secure world to use it, ``CTX_INCLUDE_PAUTH_REGS``
+   must be set to 1. This will add all pointer authentication system registers
+   to the context that is saved when doing a world switch.
+
+   The TF-A itself has support for pointer authentication at runtime
+   that can be enabled by setting ``BRANCH_PROTECTION`` option to non-zero and
+   ``CTX_INCLUDE_PAUTH_REGS`` to 1. This enables pointer authentication in BL1,
+   BL2, BL31, and the TSP if it is used.
+
+   These options are experimental features.
+
+   Note that Pointer Authentication is enabled for Non-secure world irrespective
+   of the value of these build flags if the CPU supports it.
+
+   If ``ARM_ARCH_MAJOR == 8`` and ``ARM_ARCH_MINOR >= 3`` the code footprint of
+   enabling PAuth is lower because the compiler will use the optimized
+   PAuth instructions rather than the backwards-compatible ones.
+
+Armv8.5-A
+~~~~~~~~~
+
+-  Branch Target Identification feature is selected by ``BRANCH_PROTECTION``
+   option set to 1. This option defaults to 0 and this is an experimental feature.
+
+Armv7-A
+~~~~~~~
+
+This Architecture Extension is targeted when ``ARM_ARCH_MAJOR`` == 7.
+
+There are several Armv7-A extensions available. Obviously the TrustZone
+extension is mandatory to support the TF-A bootloader and runtime services.
+
+Platform implementing an Armv7-A system can to define from its target
+Cortex-A architecture through ``ARM_CORTEX_A<X> = yes`` in their
+``platform.mk`` script. For example ``ARM_CORTEX_A15=yes`` for a
+Cortex-A15 target.
+
+Platform can also set ``ARM_WITH_NEON=yes`` to enable neon support.
+Note that using neon at runtime has constraints on non secure wolrd context.
+TF-A does not yet provide VFP context management.
+
+Directive ``ARM_CORTEX_A<x>`` and ``ARM_WITH_NEON`` are used to set
+the toolchain  target architecture directive.
+
+Platform may choose to not define straight the toolchain target architecture
+directive by defining ``MARCH32_DIRECTIVE``.
+I.e:
+
+.. code:: make
+
+   MARCH32_DIRECTIVE := -mach=armv7-a
+
+Code Structure
+--------------
+
+TF-A code is logically divided between the three boot loader stages mentioned
+in the previous sections. The code is also divided into the following
+categories (present as directories in the source code):
+
+-  **Platform specific.** Choice of architecture specific code depends upon
+   the platform.
+-  **Common code.** This is platform and architecture agnostic code.
+-  **Library code.** This code comprises of functionality commonly used by all
+   other code. The PSCI implementation and other EL3 runtime frameworks reside
+   as Library components.
+-  **Stage specific.** Code specific to a boot stage.
+-  **Drivers.**
+-  **Services.** EL3 runtime services (eg: SPD). Specific SPD services
+   reside in the ``services/spd`` directory (e.g. ``services/spd/tspd``).
+
+Each boot loader stage uses code from one or more of the above mentioned
+categories. Based upon the above, the code layout looks like this:
+
+::
+
+    Directory    Used by BL1?    Used by BL2?    Used by BL31?
+    bl1          Yes             No              No
+    bl2          No              Yes             No
+    bl31         No              No              Yes
+    plat         Yes             Yes             Yes
+    drivers      Yes             No              Yes
+    common       Yes             Yes             Yes
+    lib          Yes             Yes             Yes
+    services     No              No              Yes
+
+The build system provides a non configurable build option IMAGE_BLx for each
+boot loader stage (where x = BL stage). e.g. for BL1 , IMAGE_BL1 will be
+defined by the build system. This enables TF-A to compile certain code only
+for specific boot loader stages
+
+All assembler files have the ``.S`` extension. The linker source files for each
+boot stage have the extension ``.ld.S``. These are processed by GCC to create the
+linker scripts which have the extension ``.ld``.
+
+FDTs provide a description of the hardware platform and are used by the Linux
+kernel at boot time. These can be found in the ``fdts`` directory.
+
+References
+----------
+
+.. [#] `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D)`_
+.. [#] `Power State Coordination Interface PDD`_
+.. [#] `SMC Calling Convention PDD`_
+.. [#] `TF-A Interrupt Management Design guide`_.
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Reset Design: ./reset-design.rst
+.. _Porting Guide: ../getting_started/porting-guide.rst
+.. _Firmware Update: ../components/firmware-update.rst
+.. _PSCI PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _SMC calling convention PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+.. _PSCI Library integration guide: ../getting_started/psci-lib-integration-guide.rst
+.. _SMCCC: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _Power State Coordination Interface PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _here: ../getting_started/psci-lib-integration-guide.rst
+.. _CPU specific build macros: ./cpu-specific-build-macros.rst
+.. _CPUBM: ./cpu-specific-build-macros.rst
+.. _Arm ARM: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0487a.e/index.html
+.. _User Guide: ../getting_started/user-guide.rst
+.. _SMC Calling Convention PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+.. _TF-A Interrupt Management Design guide: ./interrupt-framework-design.rst
+.. _Translation tables design: ../components/xlat-tables-lib-v2-design.rst
+.. _Exception Handling Framework: ../components/exception-handling.rst
+.. _ROMLIB Design: ../components/romlib-design.rst
+.. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
+
+.. |Image 1| image:: ../resources/diagrams/rt-svc-descs-layout.png
diff --git a/docs/design/index.rst b/docs/design/index.rst
new file mode 100644
index 0000000..a51a4eb
--- /dev/null
+++ b/docs/design/index.rst
@@ -0,0 +1,15 @@
+System Design
+=============
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   auth-framework
+   cpu-specific-build-macros
+   firmware-design
+   interrupt-framework-design
+   psci-pd-tree
+   reset-design
+   trusted-board-boot
diff --git a/docs/design/interrupt-framework-design.rst b/docs/design/interrupt-framework-design.rst
new file mode 100644
index 0000000..4a864f9
--- /dev/null
+++ b/docs/design/interrupt-framework-design.rst
@@ -0,0 +1,1020 @@
+Interrupt Management Framework 
+==============================
+
+This framework is responsible for managing interrupts routed to EL3. It also
+allows EL3 software to configure the interrupt routing behavior. Its main
+objective is to implement the following two requirements.
+
+#. It should be possible to route interrupts meant to be handled by secure
+   software (Secure interrupts) to EL3, when execution is in non-secure state
+   (normal world). The framework should then take care of handing control of
+   the interrupt to either software in EL3 or Secure-EL1 depending upon the
+   software configuration and the GIC implementation. This requirement ensures
+   that secure interrupts are under the control of the secure software with
+   respect to their delivery and handling without the possibility of
+   intervention from non-secure software.
+
+#. It should be possible to route interrupts meant to be handled by
+   non-secure software (Non-secure interrupts) to the last executed exception
+   level in the normal world when the execution is in secure world at
+   exception levels lower than EL3. This could be done with or without the
+   knowledge of software executing in Secure-EL1/Secure-EL0. The choice of
+   approach should be governed by the secure software. This requirement
+   ensures that non-secure software is able to execute in tandem with the
+   secure software without overriding it.
+
+Concepts
+--------
+
+Interrupt types
+~~~~~~~~~~~~~~~
+
+The framework categorises an interrupt to be one of the following depending upon
+the exception level(s) it is handled in.
+
+#. Secure EL1 interrupt. This type of interrupt can be routed to EL3 or
+   Secure-EL1 depending upon the security state of the current execution
+   context. It is always handled in Secure-EL1.
+
+#. Non-secure interrupt. This type of interrupt can be routed to EL3,
+   Secure-EL1, Non-secure EL1 or EL2 depending upon the security state of the
+   current execution context. It is always handled in either Non-secure EL1
+   or EL2.
+
+#. EL3 interrupt. This type of interrupt can be routed to EL3 or Secure-EL1
+   depending upon the security state of the current execution context. It is
+   always handled in EL3.
+
+The following constants define the various interrupt types in the framework
+implementation.
+
+.. code:: c
+
+    #define INTR_TYPE_S_EL1      0
+    #define INTR_TYPE_EL3        1
+    #define INTR_TYPE_NS         2
+
+Routing model
+~~~~~~~~~~~~~
+
+A type of interrupt can be either generated as an FIQ or an IRQ. The target
+exception level of an interrupt type is configured through the FIQ and IRQ bits
+in the Secure Configuration Register at EL3 (``SCR_EL3.FIQ`` and ``SCR_EL3.IRQ``
+bits). When ``SCR_EL3.FIQ``\ =1, FIQs are routed to EL3. Otherwise they are routed
+to the First Exception Level (FEL) capable of handling interrupts. When
+``SCR_EL3.IRQ``\ =1, IRQs are routed to EL3. Otherwise they are routed to the
+FEL. This register is configured independently by EL3 software for each security
+state prior to entry into a lower exception level in that security state.
+
+A routing model for a type of interrupt (generated as FIQ or IRQ) is defined as
+its target exception level for each security state. It is represented by a
+single bit for each security state. A value of ``0`` means that the interrupt
+should be routed to the FEL. A value of ``1`` means that the interrupt should be
+routed to EL3. A routing model is applicable only when execution is not in EL3.
+
+The default routing model for an interrupt type is to route it to the FEL in
+either security state.
+
+Valid routing models
+~~~~~~~~~~~~~~~~~~~~
+
+The framework considers certain routing models for each type of interrupt to be
+incorrect as they conflict with the requirements mentioned in Section 1. The
+following sub-sections describe all the possible routing models and specify
+which ones are valid or invalid. EL3 interrupts are currently supported only
+for GIC version 3.0 (Arm GICv3) and only the Secure-EL1 and Non-secure interrupt
+types are supported for GIC version 2.0 (Arm GICv2) (see `Assumptions in
+Interrupt Management Framework`_). The terminology used in the following
+sub-sections is explained below.
+
+#. **CSS**. Current Security State. ``0`` when secure and ``1`` when non-secure
+
+#. **TEL3**. Target Exception Level 3. ``0`` when targeted to the FEL. ``1`` when
+   targeted to EL3.
+
+Secure-EL1 interrupts
+^^^^^^^^^^^^^^^^^^^^^
+
+#. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in
+   secure state. This is a valid routing model as secure software is in
+   control of handling secure interrupts.
+
+#. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in secure
+   state. This is a valid routing model as secure software in EL3 can
+   handover the interrupt to Secure-EL1 for handling.
+
+#. **CSS=1, TEL3=0**. Interrupt is routed to the FEL when execution is in
+   non-secure state. This is an invalid routing model as a secure interrupt
+   is not visible to the secure software which violates the motivation behind
+   the Arm Security Extensions.
+
+#. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in
+   non-secure state. This is a valid routing model as secure software in EL3
+   can handover the interrupt to Secure-EL1 for handling.
+
+Non-secure interrupts
+^^^^^^^^^^^^^^^^^^^^^
+
+#. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in
+   secure state. This allows the secure software to trap non-secure
+   interrupts, perform its book-keeping and hand the interrupt to the
+   non-secure software through EL3. This is a valid routing model as secure
+   software is in control of how its execution is preempted by non-secure
+   interrupts.
+
+#. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in secure
+   state. This is a valid routing model as secure software in EL3 can save
+   the state of software in Secure-EL1/Secure-EL0 before handing the
+   interrupt to non-secure software. This model requires additional
+   coordination between Secure-EL1 and EL3 software to ensure that the
+   former's state is correctly saved by the latter.
+
+#. **CSS=1, TEL3=0**. Interrupt is routed to FEL when execution is in
+   non-secure state. This is a valid routing model as a non-secure interrupt
+   is handled by non-secure software.
+
+#. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in
+   non-secure state. This is an invalid routing model as there is no valid
+   reason to route the interrupt to EL3 software and then hand it back to
+   non-secure software for handling.
+
+EL3 interrupts
+^^^^^^^^^^^^^^
+
+#. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in
+   Secure-EL1/Secure-EL0. This is a valid routing model as secure software
+   in Secure-EL1/Secure-EL0 is in control of how its execution is preempted
+   by EL3 interrupt and can handover the interrupt to EL3 for handling.
+
+   However, when ``EL3_EXCEPTION_HANDLING`` is ``1``, this routing model is
+   invalid as EL3 interrupts are unconditionally routed to EL3, and EL3
+   interrupts will always preempt Secure EL1/EL0 execution. See `exception
+   handling`__ documentation.
+
+   .. __: exception-handling.rst#interrupt-handling
+
+#. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in
+   Secure-EL1/Secure-EL0. This is a valid routing model as secure software
+   in EL3 can handle the interrupt.
+
+#. **CSS=1, TEL3=0**. Interrupt is routed to the FEL when execution is in
+   non-secure state. This is an invalid routing model as a secure interrupt
+   is not visible to the secure software which violates the motivation behind
+   the Arm Security Extensions.
+
+#. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in
+   non-secure state. This is a valid routing model as secure software in EL3
+   can handle the interrupt.
+
+Mapping of interrupt type to signal
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The framework is meant to work with any interrupt controller implemented by a
+platform. A interrupt controller could generate a type of interrupt as either an
+FIQ or IRQ signal to the CPU depending upon the current security state. The
+mapping between the type and signal is known only to the platform. The framework
+uses this information to determine whether the IRQ or the FIQ bit should be
+programmed in ``SCR_EL3`` while applying the routing model for a type of
+interrupt. The platform provides this information through the
+``plat_interrupt_type_to_line()`` API (described in the
+`Porting Guide`_). For example, on the FVP port when the platform uses an Arm GICv2
+interrupt controller, Secure-EL1 interrupts are signaled through the FIQ signal
+while Non-secure interrupts are signaled through the IRQ signal. This applies
+when execution is in either security state.
+
+Effect of mapping of several interrupt types to one signal
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It should be noted that if more than one interrupt type maps to a single
+interrupt signal, and if any one of the interrupt type sets **TEL3=1** for a
+particular security state, then interrupt signal will be routed to EL3 when in
+that security state. This means that all the other interrupt types using the
+same interrupt signal will be forced to the same routing model. This should be
+borne in mind when choosing the routing model for an interrupt type.
+
+For example, in Arm GICv3, when the execution context is Secure-EL1/
+Secure-EL0, both the EL3 and the non secure interrupt types map to the FIQ
+signal. So if either one of the interrupt type sets the routing model so
+that **TEL3=1** when **CSS=0**, the FIQ bit in ``SCR_EL3`` will be programmed to
+route the FIQ signal to EL3 when executing in Secure-EL1/Secure-EL0, thereby
+effectively routing the other interrupt type also to EL3.
+
+Assumptions in Interrupt Management Framework
+---------------------------------------------
+
+The framework makes the following assumptions to simplify its implementation.
+
+#. Although the framework has support for 2 types of secure interrupts (EL3
+   and Secure-EL1 interrupt), only interrupt controller architectures
+   like Arm GICv3 has architectural support for EL3 interrupts in the form of
+   Group 0 interrupts. In Arm GICv2, all secure interrupts are assumed to be
+   handled in Secure-EL1. They can be delivered to Secure-EL1 via EL3 but they
+   cannot be handled in EL3.
+
+#. Interrupt exceptions (``PSTATE.I`` and ``F`` bits) are masked during execution
+   in EL3.
+
+#. Interrupt management: the following sections describe how interrupts are
+   managed by the interrupt handling framework. This entails:
+
+   #. Providing an interface to allow registration of a handler and
+      specification of the routing model for a type of interrupt.
+
+   #. Implementing support to hand control of an interrupt type to its
+      registered handler when the interrupt is generated.
+
+Both aspects of interrupt management involve various components in the secure
+software stack spanning from EL3 to Secure-EL1. These components are described
+in the section `Software components`_. The framework stores information
+associated with each type of interrupt in the following data structure.
+
+.. code:: c
+
+    typedef struct intr_type_desc {
+            interrupt_type_handler_t handler;
+            uint32_t flags;
+            uint32_t scr_el3[2];
+    } intr_type_desc_t;
+
+The ``flags`` field stores the routing model for the interrupt type in
+bits[1:0]. Bit[0] stores the routing model when execution is in the secure
+state. Bit[1] stores the routing model when execution is in the non-secure
+state. As mentioned in Section `Routing model`_, a value of ``0`` implies that
+the interrupt should be targeted to the FEL. A value of ``1`` implies that it
+should be targeted to EL3. The remaining bits are reserved and SBZ. The helper
+macro ``set_interrupt_rm_flag()`` should be used to set the bits in the
+``flags`` parameter.
+
+The ``scr_el3[2]`` field also stores the routing model but as a mapping of the
+model in the ``flags`` field to the corresponding bit in the ``SCR_EL3`` for each
+security state.
+
+The framework also depends upon the platform port to configure the interrupt
+controller to distinguish between secure and non-secure interrupts. The platform
+is expected to be aware of the secure devices present in the system and their
+associated interrupt numbers. It should configure the interrupt controller to
+enable the secure interrupts, ensure that their priority is always higher than
+the non-secure interrupts and target them to the primary CPU. It should also
+export the interface described in the `Porting Guide`_ to enable
+handling of interrupts.
+
+In the remainder of this document, for the sake of simplicity a Arm GICv2 system
+is considered and it is assumed that the FIQ signal is used to generate Secure-EL1
+interrupts and the IRQ signal is used to generate non-secure interrupts in either
+security state. EL3 interrupts are not considered.
+
+Software components
+-------------------
+
+Roles and responsibilities for interrupt management are sub-divided between the
+following components of software running in EL3 and Secure-EL1. Each component is
+briefly described below.
+
+#. EL3 Runtime Firmware. This component is common to all ports of TF-A.
+
+#. Secure Payload Dispatcher (SPD) service. This service interfaces with the
+   Secure Payload (SP) software which runs in Secure-EL1/Secure-EL0 and is
+   responsible for switching execution between secure and non-secure states.
+   A switch is triggered by a Secure Monitor Call and it uses the APIs
+   exported by the Context management library to implement this functionality.
+   Switching execution between the two security states is a requirement for
+   interrupt management as well. This results in a significant dependency on
+   the SPD service. TF-A implements an example Test Secure Payload Dispatcher
+   (TSPD) service.
+
+   An SPD service plugs into the EL3 runtime firmware and could be common to
+   some ports of TF-A.
+
+#. Secure Payload (SP). On a production system, the Secure Payload corresponds
+   to a Secure OS which runs in Secure-EL1/Secure-EL0. It interfaces with the
+   SPD service to manage communication with non-secure software. TF-A
+   implements an example secure payload called Test Secure Payload (TSP)
+   which runs only in Secure-EL1.
+
+   A Secure payload implementation could be common to some ports of TF-A,
+   just like the SPD service.
+
+Interrupt registration
+----------------------
+
+This section describes in detail the role of each software component (see
+`Software components`_) during the registration of a handler for an interrupt
+type.
+
+EL3 runtime firmware
+~~~~~~~~~~~~~~~~~~~~
+
+This component declares the following prototype for a handler of an interrupt type.
+
+.. code:: c
+
+        typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
+                                                     uint32_t flags,
+                                                     void *handle,
+                                                     void *cookie);
+
+The ``id`` is parameter is reserved and could be used in the future for passing
+the interrupt id of the highest pending interrupt only if there is a foolproof
+way of determining the id. Currently it contains ``INTR_ID_UNAVAILABLE``.
+
+The ``flags`` parameter contains miscellaneous information as follows.
+
+#. Security state, bit[0]. This bit indicates the security state of the lower
+   exception level when the interrupt was generated. A value of ``1`` means
+   that it was in the non-secure state. A value of ``0`` indicates that it was
+   in the secure state. This bit can be used by the handler to ensure that
+   interrupt was generated and routed as per the routing model specified
+   during registration.
+
+#. Reserved, bits[31:1]. The remaining bits are reserved for future use.
+
+The ``handle`` parameter points to the ``cpu_context`` structure of the current CPU
+for the security state specified in the ``flags`` parameter.
+
+Once the handler routine completes, execution will return to either the secure
+or non-secure state. The handler routine must return a pointer to
+``cpu_context`` structure of the current CPU for the target security state. On
+AArch64, this return value is currently ignored by the caller as the
+appropriate ``cpu_context`` to be used is expected to be set by the handler
+via the context management library APIs.
+A portable interrupt handler implementation must set the target context both in
+the structure pointed to by the returned pointer and via the context management
+library APIs. The handler should treat all error conditions as critical errors
+and take appropriate action within its implementation e.g. use assertion
+failures.
+
+The runtime firmware provides the following API for registering a handler for a
+particular type of interrupt. A Secure Payload Dispatcher service should use
+this API to register a handler for Secure-EL1 and optionally for non-secure
+interrupts. This API also requires the caller to specify the routing model for
+the type of interrupt.
+
+.. code:: c
+
+    int32_t register_interrupt_type_handler(uint32_t type,
+                                            interrupt_type_handler handler,
+                                            uint64_t flags);
+
+The ``type`` parameter can be one of the three interrupt types listed above i.e.
+``INTR_TYPE_S_EL1``, ``INTR_TYPE_NS`` & ``INTR_TYPE_EL3``. The ``flags`` parameter
+is as described in Section 2.
+
+The function will return ``0`` upon a successful registration. It will return
+``-EALREADY`` in case a handler for the interrupt type has already been
+registered. If the ``type`` is unrecognised or the ``flags`` or the ``handler`` are
+invalid it will return ``-EINVAL``.
+
+Interrupt routing is governed by the configuration of the ``SCR_EL3.FIQ/IRQ`` bits
+prior to entry into a lower exception level in either security state. The
+context management library maintains a copy of the ``SCR_EL3`` system register for
+each security state in the ``cpu_context`` structure of each CPU. It exports the
+following APIs to let EL3 Runtime Firmware program and retrieve the routing
+model for each security state for the current CPU. The value of ``SCR_EL3`` stored
+in the ``cpu_context`` is used by the ``el3_exit()`` function to program the
+``SCR_EL3`` register prior to returning from the EL3 exception level.
+
+.. code:: c
+
+        uint32_t cm_get_scr_el3(uint32_t security_state);
+        void cm_write_scr_el3_bit(uint32_t security_state,
+                                  uint32_t bit_pos,
+                                  uint32_t value);
+
+``cm_get_scr_el3()`` returns the value of the ``SCR_EL3`` register for the specified
+security state of the current CPU. ``cm_write_scr_el3_bit()`` writes a ``0`` or ``1``
+to the bit specified by ``bit_pos``. ``register_interrupt_type_handler()`` invokes
+``set_routing_model()`` API which programs the ``SCR_EL3`` according to the routing
+model using the ``cm_get_scr_el3()`` and ``cm_write_scr_el3_bit()`` APIs.
+
+It is worth noting that in the current implementation of the framework, the EL3
+runtime firmware is responsible for programming the routing model. The SPD is
+responsible for ensuring that the routing model has been adhered to upon
+receiving an interrupt.
+
+.. _spd-int-registration:
+
+Secure payload dispatcher
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A SPD service is responsible for determining and maintaining the interrupt
+routing model supported by itself and the Secure Payload. It is also responsible
+for ferrying interrupts between secure and non-secure software depending upon
+the routing model. It could determine the routing model at build time or at
+runtime. It must use this information to register a handler for each interrupt
+type using the ``register_interrupt_type_handler()`` API in EL3 runtime firmware.
+
+If the routing model is not known to the SPD service at build time, then it must
+be provided by the SP as the result of its initialisation. The SPD should
+program the routing model only after SP initialisation has completed e.g. in the
+SPD initialisation function pointed to by the ``bl32_init`` variable.
+
+The SPD should determine the mechanism to pass control to the Secure Payload
+after receiving an interrupt from the EL3 runtime firmware. This information
+could either be provided to the SPD service at build time or by the SP at
+runtime.
+
+Test secure payload dispatcher behavior
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+   Where this document discusses ``TSP_NS_INTR_ASYNC_PREEMPT`` as being
+   ``1``, the same results also apply when ``EL3_EXCEPTION_HANDLING`` is ``1``.
+
+The TSPD only handles Secure-EL1 interrupts and is provided with the following
+routing model at build time.
+
+-  Secure-EL1 interrupts are routed to EL3 when execution is in non-secure
+   state and are routed to the FEL when execution is in the secure state
+   i.e **CSS=0, TEL3=0** & **CSS=1, TEL3=1** for Secure-EL1 interrupts
+
+-  When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is zero, the default routing
+   model is used for non-secure interrupts. They are routed to the FEL in
+   either security state i.e **CSS=0, TEL3=0** & **CSS=1, TEL3=0** for
+   Non-secure interrupts.
+
+-  When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is defined to 1, then the
+   non secure interrupts are routed to EL3 when execution is in secure state
+   i.e **CSS=0, TEL3=1** for non-secure interrupts. This effectively preempts
+   Secure-EL1. The default routing model is used for non secure interrupts in
+   non-secure state. i.e **CSS=1, TEL3=0**.
+
+It performs the following actions in the ``tspd_init()`` function to fulfill the
+requirements mentioned earlier.
+
+#. It passes control to the Test Secure Payload to perform its
+   initialisation. The TSP provides the address of the vector table
+   ``tsp_vectors`` in the SP which also includes the handler for Secure-EL1
+   interrupts in the ``sel1_intr_entry`` field. The TSPD passes control to the TSP at
+   this address when it receives a Secure-EL1 interrupt.
+
+   The handover agreement between the TSP and the TSPD requires that the TSPD
+   masks all interrupts (``PSTATE.DAIF`` bits) when it calls
+   ``tsp_sel1_intr_entry()``. The TSP has to preserve the callee saved general
+   purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use
+   ``x0-x18`` to enable its C runtime.
+
+#. The TSPD implements a handler function for Secure-EL1 interrupts. This
+   function is registered with the EL3 runtime firmware using the
+   ``register_interrupt_type_handler()`` API as follows
+
+   .. code:: c
+
+       /* Forward declaration */
+       interrupt_type_handler tspd_secure_el1_interrupt_handler;
+       int32_t rc, flags = 0;
+       set_interrupt_rm_flag(flags, NON_SECURE);
+       rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+                                        tspd_secure_el1_interrupt_handler,
+                                        flags);
+       if (rc)
+           panic();
+
+#. When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is defined to 1, the TSPD
+   implements a handler function for non-secure interrupts. This function is
+   registered with the EL3 runtime firmware using the
+   ``register_interrupt_type_handler()`` API as follows
+
+   .. code:: c
+
+       /* Forward declaration */
+       interrupt_type_handler tspd_ns_interrupt_handler;
+       int32_t rc, flags = 0;
+       set_interrupt_rm_flag(flags, SECURE);
+       rc = register_interrupt_type_handler(INTR_TYPE_NS,
+                                       tspd_ns_interrupt_handler,
+                                       flags);
+       if (rc)
+           panic();
+
+.. _sp-int-registration:
+
+Secure payload
+~~~~~~~~~~~~~~
+
+A Secure Payload must implement an interrupt handling framework at Secure-EL1
+(Secure-EL1 IHF) to support its chosen interrupt routing model. Secure payload
+execution will alternate between the below cases.
+
+#. In the code where IRQ, FIQ or both interrupts are enabled, if an interrupt
+   type is targeted to the FEL, then it will be routed to the Secure-EL1
+   exception vector table. This is defined as the **asynchronous mode** of
+   handling interrupts. This mode applies to both Secure-EL1 and non-secure
+   interrupts.
+
+#. In the code where both interrupts are disabled, if an interrupt type is
+   targeted to the FEL, then execution will eventually migrate to the
+   non-secure state. Any non-secure interrupts will be handled as described
+   in the routing model where **CSS=1 and TEL3=0**. Secure-EL1 interrupts
+   will be routed to EL3 (as per the routing model where **CSS=1 and
+   TEL3=1**) where the SPD service will hand them to the SP. This is defined
+   as the **synchronous mode** of handling interrupts.
+
+The interrupt handling framework implemented by the SP should support one or
+both these interrupt handling models depending upon the chosen routing model.
+
+The following list briefly describes how the choice of a valid routing model
+(see `Valid routing models`_) effects the implementation of the Secure-EL1
+IHF. If the choice of the interrupt routing model is not known to the SPD
+service at compile time, then the SP should pass this information to the SPD
+service at runtime during its initialisation phase.
+
+As mentioned earlier, an Arm GICv2 system is considered and it is assumed that
+the FIQ signal is used to generate Secure-EL1 interrupts and the IRQ signal
+is used to generate non-secure interrupts in either security state.
+
+Secure payload IHF design w.r.t secure-EL1 interrupts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+#. **CSS=0, TEL3=0**. If ``PSTATE.F=0``, Secure-EL1 interrupts will be
+   triggered at one of the Secure-EL1 FIQ exception vectors. The Secure-EL1
+   IHF should implement support for handling FIQ interrupts asynchronously.
+
+   If ``PSTATE.F=1`` then Secure-EL1 interrupts will be handled as per the
+   synchronous interrupt handling model. The SP could implement this scenario
+   by exporting a separate entrypoint for Secure-EL1 interrupts to the SPD
+   service during the registration phase. The SPD service would also need to
+   know the state of the system, general purpose and the ``PSTATE`` registers
+   in which it should arrange to return execution to the SP. The SP should
+   provide this information in an implementation defined way during the
+   registration phase if it is not known to the SPD service at build time.
+
+#. **CSS=1, TEL3=1**. Interrupts are routed to EL3 when execution is in
+   non-secure state. They should be handled through the synchronous interrupt
+   handling model as described in 1. above.
+
+#. **CSS=0, TEL3=1**. Secure-EL1 interrupts are routed to EL3 when execution
+   is in secure state. They will not be visible to the SP. The ``PSTATE.F`` bit
+   in Secure-EL1/Secure-EL0 will not mask FIQs. The EL3 runtime firmware will
+   call the handler registered by the SPD service for Secure-EL1 interrupts.
+   Secure-EL1 IHF should then handle all Secure-EL1 interrupt through the
+   synchronous interrupt handling model described in 1. above.
+
+Secure payload IHF design w.r.t non-secure interrupts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+#. **CSS=0, TEL3=0**. If ``PSTATE.I=0``, non-secure interrupts will be
+   triggered at one of the Secure-EL1 IRQ exception vectors . The Secure-EL1
+   IHF should co-ordinate with the SPD service to transfer execution to the
+   non-secure state where the interrupt should be handled e.g the SP could
+   allocate a function identifier to issue a SMC64 or SMC32 to the SPD
+   service which indicates that the SP execution has been preempted by a
+   non-secure interrupt. If this function identifier is not known to the SPD
+   service at compile time then the SP could provide it during the
+   registration phase.
+
+   If ``PSTATE.I=1`` then the non-secure interrupt will pend until execution
+   resumes in the non-secure state.
+
+#. **CSS=0, TEL3=1**. Non-secure interrupts are routed to EL3. They will not
+   be visible to the SP. The ``PSTATE.I`` bit in Secure-EL1/Secure-EL0 will
+   have not effect. The SPD service should register a non-secure interrupt
+   handler which should save the SP state correctly and resume execution in
+   the non-secure state where the interrupt will be handled. The Secure-EL1
+   IHF does not need to take any action.
+
+#. **CSS=1, TEL3=0**. Non-secure interrupts are handled in the FEL in
+   non-secure state (EL1/EL2) and are not visible to the SP. This routing
+   model does not affect the SP behavior.
+
+A Secure Payload must also ensure that all Secure-EL1 interrupts are correctly
+configured at the interrupt controller by the platform port of the EL3 runtime
+firmware. It should configure any additional Secure-EL1 interrupts which the EL3
+runtime firmware is not aware of through its platform port.
+
+Test secure payload behavior
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is
+described in Section `Secure Payload Dispatcher`__. It is known to the TSPD
+service at build time.
+
+.. __: #spd-int-registration
+
+The TSP implements an entrypoint (``tsp_sel1_intr_entry()``) for handling Secure-EL1
+interrupts taken in non-secure state and routed through the TSPD service
+(synchronous handling model). It passes the reference to this entrypoint via
+``tsp_vectors`` to the TSPD service.
+
+The TSP also replaces the default exception vector table referenced through the
+``early_exceptions`` variable, with a vector table capable of handling FIQ and IRQ
+exceptions taken at the same (Secure-EL1) exception level. This table is
+referenced through the ``tsp_exceptions`` variable and programmed into the
+VBAR_EL1. It caters for the asynchronous handling model.
+
+The TSP also programs the Secure Physical Timer in the Arm Generic Timer block
+to raise a periodic interrupt (every half a second) for the purpose of testing
+interrupt management across all the software components listed in `Software
+components`_.
+
+Interrupt handling
+------------------
+
+This section describes in detail the role of each software component (see
+Section `Software components`_) in handling an interrupt of a particular type.
+
+EL3 runtime firmware
+~~~~~~~~~~~~~~~~~~~~
+
+The EL3 runtime firmware populates the IRQ and FIQ exception vectors referenced
+by the ``runtime_exceptions`` variable as follows.
+
+#. IRQ and FIQ exceptions taken from the current exception level with
+   ``SP_EL0`` or ``SP_EL3`` are reported as irrecoverable error conditions. As
+   mentioned earlier, EL3 runtime firmware always executes with the
+   ``PSTATE.I`` and ``PSTATE.F`` bits set.
+
+#. The following text describes how the IRQ and FIQ exceptions taken from a
+   lower exception level using AArch64 or AArch32 are handled.
+
+When an interrupt is generated, the vector for each interrupt type is
+responsible for:
+
+#. Saving the entire general purpose register context (x0-x30) immediately
+   upon exception entry. The registers are saved in the per-cpu ``cpu_context``
+   data structure referenced by the ``SP_EL3``\ register.
+
+#. Saving the ``ELR_EL3``, ``SP_EL0`` and ``SPSR_EL3`` system registers in the
+   per-cpu ``cpu_context`` data structure referenced by the ``SP_EL3`` register.
+
+#. Switching to the C runtime stack by restoring the ``CTX_RUNTIME_SP`` value
+   from the per-cpu ``cpu_context`` data structure in ``SP_EL0`` and
+   executing the ``msr spsel, #0`` instruction.
+
+#. Determining the type of interrupt. Secure-EL1 interrupts will be signaled
+   at the FIQ vector. Non-secure interrupts will be signaled at the IRQ
+   vector. The platform should implement the following API to determine the
+   type of the pending interrupt.
+
+   .. code:: c
+
+       uint32_t plat_ic_get_interrupt_type(void);
+
+   It should return either ``INTR_TYPE_S_EL1`` or ``INTR_TYPE_NS``.
+
+#. Determining the handler for the type of interrupt that has been generated.
+   The following API has been added for this purpose.
+
+   .. code:: c
+
+       interrupt_type_handler get_interrupt_type_handler(uint32_t interrupt_type);
+
+   It returns the reference to the registered handler for this interrupt
+   type. The ``handler`` is retrieved from the ``intr_type_desc_t`` structure as
+   described in Section 2. ``NULL`` is returned if no handler has been
+   registered for this type of interrupt. This scenario is reported as an
+   irrecoverable error condition.
+
+#. Calling the registered handler function for the interrupt type generated.
+   The ``id`` parameter is set to ``INTR_ID_UNAVAILABLE`` currently. The id along
+   with the current security state and a reference to the ``cpu_context_t``
+   structure for the current security state are passed to the handler function
+   as its arguments.
+
+   The handler function returns a reference to the per-cpu ``cpu_context_t``
+   structure for the target security state.
+
+#. Calling ``el3_exit()`` to return from EL3 into a lower exception level in
+   the security state determined by the handler routine. The ``el3_exit()``
+   function is responsible for restoring the register context from the
+   ``cpu_context_t`` data structure for the target security state.
+
+Secure payload dispatcher
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Interrupt entry
+^^^^^^^^^^^^^^^
+
+The SPD service begins handling an interrupt when the EL3 runtime firmware calls
+the handler function for that type of interrupt. The SPD service is responsible
+for the following:
+
+#. Validating the interrupt. This involves ensuring that the interrupt was
+   generated according to the interrupt routing model specified by the SPD
+   service during registration. It should use the security state of the
+   exception level (passed in the ``flags`` parameter of the handler) where
+   the interrupt was taken from to determine this. If the interrupt is not
+   recognised then the handler should treat it as an irrecoverable error
+   condition.
+
+   An SPD service can register a handler for Secure-EL1 and/or Non-secure
+   interrupts. A non-secure interrupt should never be routed to EL3 from
+   from non-secure state. Also if a routing model is chosen where Secure-EL1
+   interrupts are routed to S-EL1 when execution is in Secure state, then a
+   S-EL1 interrupt should never be routed to EL3 from secure state. The handler
+   could use the security state flag to check this.
+
+#. Determining whether a context switch is required. This depends upon the
+   routing model and interrupt type. For non secure and S-EL1 interrupt,
+   if the security state of the execution context where the interrupt was
+   generated is not the same as the security state required for handling
+   the interrupt, a context switch is required. The following 2 cases
+   require a context switch from secure to non-secure or vice-versa:
+
+   #. A Secure-EL1 interrupt taken from the non-secure state should be
+      routed to the Secure Payload.
+
+   #. A non-secure interrupt taken from the secure state should be routed
+      to the last known non-secure exception level.
+
+   The SPD service must save the system register context of the current
+   security state. It must then restore the system register context of the
+   target security state. It should use the ``cm_set_next_eret_context()`` API
+   to ensure that the next ``cpu_context`` to be restored is of the target
+   security state.
+
+   If the target state is secure then execution should be handed to the SP as
+   per the synchronous interrupt handling model it implements. A Secure-EL1
+   interrupt can be routed to EL3 while execution is in the SP. This implies
+   that SP execution can be preempted while handling an interrupt by a
+   another higher priority Secure-EL1 interrupt or a EL3 interrupt. The SPD
+   service should be able to handle this preemption or manage secure interrupt
+   priorities before handing control to the SP.
+
+#. Setting the return value of the handler to the per-cpu ``cpu_context`` if
+   the interrupt has been successfully validated and ready to be handled at a
+   lower exception level.
+
+The routing model allows non-secure interrupts to interrupt Secure-EL1 when in
+secure state if it has been configured to do so. The SPD service and the SP
+should implement a mechanism for routing these interrupts to the last known
+exception level in the non-secure state. The former should save the SP context,
+restore the non-secure context and arrange for entry into the non-secure state
+so that the interrupt can be handled.
+
+Interrupt exit
+^^^^^^^^^^^^^^
+
+When the Secure Payload has finished handling a Secure-EL1 interrupt, it could
+return control back to the SPD service through a SMC32 or SMC64. The SPD service
+should handle this secure monitor call so that execution resumes in the
+exception level and the security state from where the Secure-EL1 interrupt was
+originally taken.
+
+Test secure payload dispatcher Secure-EL1 interrupt handling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The example TSPD service registers a handler for Secure-EL1 interrupts taken
+from the non-secure state. During execution in S-EL1, the TSPD expects that the
+Secure-EL1 interrupts are handled in S-EL1 by TSP. Its handler
+``tspd_secure_el1_interrupt_handler()`` expects only to be invoked for Secure-EL1
+originating from the non-secure state. It takes the following actions upon being
+invoked.
+
+#. It uses the security state provided in the ``flags`` parameter to ensure
+   that the secure interrupt originated from the non-secure state. It asserts
+   if this is not the case.
+
+#. It saves the system register context for the non-secure state by calling
+   ``cm_el1_sysregs_context_save(NON_SECURE);``.
+
+#. It sets the ``ELR_EL3`` system register to ``tsp_sel1_intr_entry`` and sets the
+   ``SPSR_EL3.DAIF`` bits in the secure CPU context. It sets ``x0`` to
+   ``TSP_HANDLE_SEL1_INTR_AND_RETURN``. If the TSP was preempted earlier by a non
+   secure interrupt during ``yielding`` SMC processing, save the registers that
+   will be trashed, which is the ``ELR_EL3`` and ``SPSR_EL3``, in order to be able
+   to re-enter TSP for Secure-EL1 interrupt processing. It does not need to
+   save any other secure context since the TSP is expected to preserve it
+   (see section `Test secure payload dispatcher behavior`_).
+
+#. It restores the system register context for the secure state by calling
+   ``cm_el1_sysregs_context_restore(SECURE);``.
+
+#. It ensures that the secure CPU context is used to program the next
+   exception return from EL3 by calling ``cm_set_next_eret_context(SECURE);``.
+
+#. It returns the per-cpu ``cpu_context`` to indicate that the interrupt can
+   now be handled by the SP. ``x1`` is written with the value of ``elr_el3``
+   register for the non-secure state. This information is used by the SP for
+   debugging purposes.
+
+The figure below describes how the interrupt handling is implemented by the TSPD
+when a Secure-EL1 interrupt is generated when execution is in the non-secure
+state.
+
+|Image 1|
+
+The TSP issues an SMC with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier to
+signal completion of interrupt handling.
+
+The TSPD service takes the following actions in ``tspd_smc_handler()`` function
+upon receiving an SMC with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier:
+
+#. It ensures that the call originated from the secure state otherwise
+   execution returns to the non-secure state with ``SMC_UNK`` in ``x0``.
+
+#. It restores the saved ``ELR_EL3`` and ``SPSR_EL3`` system registers back to
+   the secure CPU context (see step 3 above) in case the TSP had been preempted
+   by a non secure interrupt earlier.
+
+#. It restores the system register context for the non-secure state by
+   calling ``cm_el1_sysregs_context_restore(NON_SECURE)``.
+
+#. It ensures that the non-secure CPU context is used to program the next
+   exception return from EL3 by calling ``cm_set_next_eret_context(NON_SECURE)``.
+
+#. ``tspd_smc_handler()`` returns a reference to the non-secure ``cpu_context``
+   as the return value.
+
+Test secure payload dispatcher non-secure interrupt handling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The TSP in Secure-EL1 can be preempted by a non-secure interrupt during
+``yielding`` SMC processing or by a higher priority EL3 interrupt during
+Secure-EL1 interrupt processing. When ``EL3_EXCEPTION_HANDLING`` is ``0``, only
+non-secure interrupts can cause preemption of TSP since there are no EL3
+interrupts in the system. With ``EL3_EXCEPTION_HANDLING=1`` however, any EL3
+interrupt may preempt Secure execution.
+
+It should be noted that while TSP is preempted, the TSPD only allows entry into
+the TSP either for Secure-EL1 interrupt handling or for resuming the preempted
+``yielding`` SMC in response to the ``TSP_FID_RESUME`` SMC from the normal world.
+(See Section `Implication of preempted SMC on Non-Secure Software`_).
+
+The non-secure interrupt triggered in Secure-EL1 during ``yielding`` SMC
+processing can be routed to either EL3 or Secure-EL1 and is controlled by build
+option ``TSP_NS_INTR_ASYNC_PREEMPT`` (see Section `Test secure payload
+dispatcher behavior`_). If the build option is set, the TSPD will set the
+routing model for the non-secure interrupt to be routed to EL3 from secure state
+i.e. **TEL3=1, CSS=0** and registers ``tspd_ns_interrupt_handler()`` as the
+non-secure interrupt handler. The ``tspd_ns_interrupt_handler()`` on being
+invoked ensures that the interrupt originated from the secure state and disables
+routing of non-secure interrupts from secure state to EL3. This is to prevent
+further preemption (by a non-secure interrupt) when TSP is reentered for
+handling Secure-EL1 interrupts that triggered while execution was in the normal
+world. The ``tspd_ns_interrupt_handler()`` then invokes
+``tspd_handle_sp_preemption()`` for further handling.
+
+If the ``TSP_NS_INTR_ASYNC_PREEMPT`` build option is zero (default), the default
+routing model for non-secure interrupt in secure state is in effect
+i.e. **TEL3=0, CSS=0**. During ``yielding`` SMC processing, the IRQ
+exceptions are unmasked i.e. ``PSTATE.I=0``, and a non-secure interrupt will
+trigger at Secure-EL1 IRQ exception vector. The TSP saves the general purpose
+register context and issues an SMC with ``TSP_PREEMPTED`` as the function
+identifier to signal preemption of TSP. The TSPD SMC handler,
+``tspd_smc_handler()``, ensures that the SMC call originated from the
+secure state otherwise execution returns to the non-secure state with
+``SMC_UNK`` in ``x0``. It then invokes ``tspd_handle_sp_preemption()`` for
+further handling.
+
+The ``tspd_handle_sp_preemption()`` takes the following actions upon being
+invoked:
+
+#. It saves the system register context for the secure state by calling
+   ``cm_el1_sysregs_context_save(SECURE)``.
+
+#. It restores the system register context for the non-secure state by
+   calling ``cm_el1_sysregs_context_restore(NON_SECURE)``.
+
+#. It ensures that the non-secure CPU context is used to program the next
+   exception return from EL3 by calling ``cm_set_next_eret_context(NON_SECURE)``.
+
+#. ``SMC_PREEMPTED`` is set in x0 and return to non secure state after
+   restoring non secure context.
+
+The Normal World is expected to resume the TSP after the ``yielding`` SMC
+preemption by issuing an SMC with ``TSP_FID_RESUME`` as the function identifier
+(see section `Implication of preempted SMC on Non-Secure Software`_).  The TSPD
+service takes the following actions in ``tspd_smc_handler()`` function upon
+receiving this SMC:
+
+#. It ensures that the call originated from the non secure state. An
+   assertion is raised otherwise.
+
+#. Checks whether the TSP needs a resume i.e check if it was preempted. It
+   then saves the system register context for the non-secure state by calling
+   ``cm_el1_sysregs_context_save(NON_SECURE)``.
+
+#. Restores the secure context by calling
+   ``cm_el1_sysregs_context_restore(SECURE)``
+
+#. It ensures that the secure CPU context is used to program the next
+   exception return from EL3 by calling ``cm_set_next_eret_context(SECURE)``.
+
+#. ``tspd_smc_handler()`` returns a reference to the secure ``cpu_context`` as the
+   return value.
+
+The figure below describes how the TSP/TSPD handle a non-secure interrupt when
+it is generated during execution in the TSP with ``PSTATE.I`` = 0 when the
+``TSP_NS_INTR_ASYNC_PREEMPT`` build flag is 0.
+
+|Image 2|
+
+Secure payload
+~~~~~~~~~~~~~~
+
+The SP should implement one or both of the synchronous and asynchronous
+interrupt handling models depending upon the interrupt routing model it has
+chosen (as described in section `Secure Payload`__).
+
+.. __: #sp-int-registration
+
+In the synchronous model, it should begin handling a Secure-EL1 interrupt after
+receiving control from the SPD service at an entrypoint agreed upon during build
+time or during the registration phase. Before handling the interrupt, the SP
+should save any Secure-EL1 system register context which is needed for resuming
+normal execution in the SP later e.g. ``SPSR_EL1``, ``ELR_EL1``. After handling
+the interrupt, the SP could return control back to the exception level and
+security state where the interrupt was originally taken from. The SP should use
+an SMC32 or SMC64 to ask the SPD service to do this.
+
+In the asynchronous model, the Secure Payload is responsible for handling
+non-secure and Secure-EL1 interrupts at the IRQ and FIQ vectors in its exception
+vector table when ``PSTATE.I`` and ``PSTATE.F`` bits are 0. As described earlier,
+when a non-secure interrupt is generated, the SP should coordinate with the SPD
+service to pass control back to the non-secure state in the last known exception
+level. This will allow the non-secure interrupt to be handled in the non-secure
+state.
+
+Test secure payload behavior
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The TSPD hands control of a Secure-EL1 interrupt to the TSP at the
+``tsp_sel1_intr_entry()``. The TSP handles the interrupt while ensuring that the
+handover agreement described in Section `Test secure payload dispatcher
+behavior`_ is maintained. It updates some statistics by calling
+``tsp_update_sync_sel1_intr_stats()``. It then calls
+``tsp_common_int_handler()`` which.
+
+#. Checks whether the interrupt is the secure physical timer interrupt. It
+   uses the platform API ``plat_ic_get_pending_interrupt_id()`` to get the
+   interrupt number. If it is not the secure physical timer interrupt, then
+   that means that a higher priority interrupt has preempted it. Invoke
+   ``tsp_handle_preemption()`` to handover control back to EL3 by issuing
+   an SMC with ``TSP_PREEMPTED`` as the function identifier.
+
+#. Handles the secure timer interrupt interrupt by acknowledging it using the
+   ``plat_ic_acknowledge_interrupt()`` platform API, calling
+   ``tsp_generic_timer_handler()`` to reprogram the secure physical generic
+   timer and calling the ``plat_ic_end_of_interrupt()`` platform API to signal
+   end of interrupt processing.
+
+The TSP passes control back to the TSPD by issuing an SMC64 with
+``TSP_HANDLED_S_EL1_INTR`` as the function identifier.
+
+The TSP handles interrupts under the asynchronous model as follows.
+
+#. Secure-EL1 interrupts are handled by calling the ``tsp_common_int_handler()``
+   function. The function has been described above.
+
+#. Non-secure interrupts are handled by calling the ``tsp_common_int_handler()``
+   function which ends up invoking ``tsp_handle_preemption()`` and issuing an
+   SMC64 with ``TSP_PREEMPTED`` as the function identifier. Execution resumes at
+   the instruction that follows this SMC instruction when the TSPD hands control
+   to the TSP in response to an SMC with ``TSP_FID_RESUME`` as the function
+   identifier from the non-secure state (see section `Test secure payload
+   dispatcher non-secure interrupt handling`_).
+
+Other considerations
+--------------------
+
+Implication of preempted SMC on Non-Secure Software
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A ``yielding`` SMC call to Secure payload can be preempted by a non-secure
+interrupt and the execution can return to the non-secure world for handling
+the interrupt (For details on ``yielding`` SMC refer `SMC calling convention`_).
+In this case, the SMC call has not completed its execution and the execution
+must return back to the secure payload to resume the preempted SMC call.
+This can be achieved by issuing an SMC call which instructs to resume the
+preempted SMC.
+
+A ``fast`` SMC cannot be preempted and hence this case will not happen for
+a fast SMC call.
+
+In the Test Secure Payload implementation, ``TSP_FID_RESUME`` is designated
+as the resume SMC FID. It is important to note that ``TSP_FID_RESUME`` is a
+``yielding`` SMC which means it too can be be preempted. The typical non
+secure software sequence for issuing a ``yielding`` SMC would look like this,
+assuming ``P.STATE.I=0`` in the non secure state :
+
+.. code:: c
+
+    int rc;
+    rc = smc(TSP_YIELD_SMC_FID, ...);     /* Issue a Yielding SMC call */
+    /* The pending non-secure interrupt is handled by the interrupt handler
+       and returns back here. */
+    while (rc == SMC_PREEMPTED) {       /* Check if the SMC call is preempted */
+        rc = smc(TSP_FID_RESUME);       /* Issue resume SMC call */
+    }
+
+The ``TSP_YIELD_SMC_FID`` is any ``yielding`` SMC function identifier and the smc()
+function invokes a SMC call with the required arguments. The pending non-secure
+interrupt causes an IRQ exception and the IRQ handler registered at the
+exception vector handles the non-secure interrupt and returns. The return value
+from the SMC call is tested for ``SMC_PREEMPTED`` to check whether it is
+preempted. If it is, then the resume SMC call ``TSP_FID_RESUME`` is issued. The
+return value of the SMC call is tested again to check if it is preempted.
+This is done in a loop till the SMC call succeeds or fails. If a ``yielding``
+SMC is preempted, until it is resumed using ``TSP_FID_RESUME`` SMC and
+completed, the current TSPD prevents any other SMC call from re-entering
+TSP by returning ``SMC_UNK`` error.
+
+--------------
+
+*Copyright (c) 2014-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Porting Guide: ../getting_started/porting-guide.rst
+.. _SMC calling convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+
+.. |Image 1| image:: ../resources/diagrams/sec-int-handling.png
+.. |Image 2| image:: ../resources/diagrams/non-sec-int-handling.png
diff --git a/docs/design/psci-pd-tree.rst b/docs/design/psci-pd-tree.rst
new file mode 100644
index 0000000..56a6d6f
--- /dev/null
+++ b/docs/design/psci-pd-tree.rst
@@ -0,0 +1,304 @@
+PSCI Power Domain Tree Structure
+================================
+
+Requirements
+------------
+
+#. A platform must export the ``plat_get_aff_count()`` and
+   ``plat_get_aff_state()`` APIs to enable the generic PSCI code to
+   populate a tree that describes the hierarchy of power domains in the
+   system. This approach is inflexible because a change to the topology
+   requires a change in the code.
+
+   It would be much simpler for the platform to describe its power domain tree
+   in a data structure.
+
+#. The generic PSCI code generates MPIDRs in order to populate the power domain
+   tree. It also uses an MPIDR to find a node in the tree. The assumption that
+   a platform will use exactly the same MPIDRs as generated by the generic PSCI
+   code is not scalable. The use of an MPIDR also restricts the number of
+   levels in the power domain tree to four.
+
+   Therefore, there is a need to decouple allocation of MPIDRs from the
+   mechanism used to populate the power domain topology tree.
+
+#. The current arrangement of the power domain tree requires a binary search
+   over the sibling nodes at a particular level to find a specified power
+   domain node. During a power management operation, the tree is traversed from
+   a 'start' to an 'end' power level. The binary search is required to find the
+   node at each level. The natural way to perform this traversal is to
+   start from a leaf node and follow the parent node pointer to reach the end
+   level.
+
+   Therefore, there is a need to define data structures that implement the tree in
+   a way which facilitates such a traversal.
+
+#. The attributes of a core power domain differ from the attributes of power
+   domains at higher levels. For example, only a core power domain can be identified
+   using an MPIDR. There is no requirement to perform state coordination while
+   performing a power management operation on the core power domain.
+
+   Therefore, there is a need to implement the tree in a way which facilitates this
+   distinction between a leaf and non-leaf node and any associated
+   optimizations.
+
+--------------
+
+Design
+------
+
+Describing a power domain tree
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To fulfill requirement 1., the existing platform APIs
+``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been
+removed. A platform must define an array of unsigned chars such that:
+
+#. The first entry in the array specifies the number of power domains at the
+   highest power level implemented in the platform. This caters for platforms
+   where the power domain tree does not have a single root node, for example,
+   the FVP has two cluster power domains at the highest level (1).
+
+#. Each subsequent entry corresponds to a power domain and contains the number
+   of power domains that are its direct children.
+
+#. The size of the array minus the first entry will be equal to the number of
+   non-leaf power domains.
+
+#. The value in each entry in the array is used to find the number of entries
+   to consider at the next level. The sum of the values (number of children) of
+   all the entries at a level specifies the number of entries in the array for
+   the next level.
+
+The following example power domain topology tree will be used to describe the
+above text further. The leaf and non-leaf nodes in this tree have been numbered
+separately.
+
+::
+
+                                         +-+
+                                         |0|
+                                         +-+
+                                        /   \
+                                       /     \
+                                      /       \
+                                     /         \
+                                    /           \
+                                   /             \
+                                  /               \
+                                 /                 \
+                                /                   \
+                               /                     \
+                            +-+                       +-+
+                            |1|                       |2|
+                            +-+                       +-+
+                           /   \                     /   \
+                          /     \                   /     \
+                         /       \                 /       \
+                        /         \               /         \
+                     +-+           +-+         +-+           +-+
+                     |3|           |4|         |5|           |6|
+                     +-+           +-+         +-+           +-+
+            +---+-----+    +----+----|     +----+----+     +----+-----+-----+
+            |   |     |    |    |    |     |    |    |     |    |     |     |
+            |   |     |    |    |    |     |    |    |     |    |     |     |
+            v   v     v    v    v    v     v    v    v     v    v     v     v
+          +-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
+          |0|  |1|   |2|  |3|  |4|  |5|   |6|  |7|  |8|   |9|  |10|  |11|  |12|
+          +-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
+
+This tree is defined by the platform as the array described above as follows:
+
+.. code:: c
+
+        #define PLAT_NUM_POWER_DOMAINS       20
+        #define PLATFORM_CORE_COUNT          13
+        #define PSCI_NUM_NON_CPU_PWR_DOMAINS \
+                           (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT)
+
+        unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4};
+
+Removing assumptions about MPIDRs used in a platform
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To fulfill requirement 2., it is assumed that the platform assigns a
+unique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core
+power domain. MPIDRs could be allocated in any manner and will not be used to
+populate the tree.
+
+``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core
+corresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed
+which is not allocated or corresponds to an absent core. The semantics of this
+platform API have changed since it is required to validate the passed MPIDR. It
+has been made a mandatory API as a result.
+
+Another mandatory API, ``plat_my_core_pos()`` has been added to return the core
+index for the calling core. This API provides a more lightweight mechanism to get
+the index since there is no need to validate the MPIDR of the calling core.
+
+The platform should assign the core indices (as illustrated in the diagram above)
+such that, if the core nodes are numbered from left to right, then the index
+for a core domain will be the same as the index returned by
+``plat_core_pos_by_mpidr()`` or ``plat_my_core_pos()`` for that core. This
+relationship allows the core nodes to be allocated in a separate array
+(requirement 4.) during ``psci_setup()`` in such an order that the index of the
+core in the array is the same as the return value from these APIs.
+
+Dealing with holes in MPIDR allocation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For platforms where the number of allocated MPIDRs is equal to the number of
+core power domains, for example, Juno and FVPs, the logic to convert an MPIDR to
+a core index should remain unchanged. Both Juno and FVP use a simple collision
+proof hash function to do this.
+
+It is possible that on some platforms, the allocation of MPIDRs is not
+contiguous or certain cores have been disabled. This essentially means that the
+MPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs
+used by the platform is not equal to the number of core power domains.
+
+The platform could adopt one of the following approaches to deal with this
+scenario:
+
+#. Implement more complex logic to convert a valid MPIDR to a core index while
+   maintaining the relationship described earlier. This means that the power
+   domain tree descriptor will not describe any core power domains which are
+   disabled or absent. Entries will not be allocated in the tree for these
+   domains.
+
+#. Treat unallocated MPIDRs and disabled cores as absent but still describe them
+   in the power domain descriptor, that is, the number of core nodes described
+   is equal to the size of the range of MPIDRs allocated. This approach will
+   lead to memory wastage since entries will be allocated in the tree but will
+   allow use of a simpler logic to convert an MPIDR to a core index.
+
+Traversing through and distinguishing between core and non-core power domains
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To fulfill requirement 3 and 4, separate data structures have been defined
+to represent leaf and non-leaf power domain nodes in the tree.
+
+.. code:: c
+
+    /*******************************************************************************
+     * The following two data structures implement the power domain tree. The tree
+     * is used to track the state of all the nodes i.e. power domain instances
+     * described by the platform. The tree consists of nodes that describe CPU power
+     * domains i.e. leaf nodes and all other power domains which are parents of a
+     * CPU power domain i.e. non-leaf nodes.
+     ******************************************************************************/
+    typedef struct non_cpu_pwr_domain_node {
+        /*
+         * Index of the first CPU power domain node level 0 which has this node
+         * as its parent.
+         */
+        unsigned int cpu_start_idx;
+
+        /*
+         * Number of CPU power domains which are siblings of the domain indexed
+         * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
+         * -> cpu_start_idx + ncpus' have this node as their parent.
+         */
+        unsigned int ncpus;
+
+        /* Index of the parent power domain node */
+        unsigned int parent_node;
+
+        -----
+    } non_cpu_pd_node_t;
+
+    typedef struct cpu_pwr_domain_node {
+        u_register_t mpidr;
+
+        /* Index of the parent power domain node */
+        unsigned int parent_node;
+
+        -----
+    } cpu_pd_node_t;
+
+The power domain tree is implemented as a combination of the following data
+structures.
+
+.. code:: c
+
+    non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
+    cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
+
+Populating the power domain tree
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the
+algorithm to parse the power domain descriptor exported by the platform to
+populate the two arrays. It is essentially a breadth-first-search. The nodes for
+each level starting from the root are laid out one after another in the
+``psci_non_cpu_pd_nodes`` and ``psci_cpu_pd_nodes`` arrays as follows:
+
+::
+
+    psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]]
+    psci_cpu_pd_nodes -> [Level 0 nodes]
+
+For the example power domain tree illustrated above, the ``psci_cpu_pd_nodes``
+will be populated as follows. The value in each entry is the index of the parent
+node. Other fields have been ignored for simplicity.
+
+::
+
+                          +-------------+     ^
+                    CPU0  |      3      |     |
+                          +-------------+     |
+                    CPU1  |      3      |     |
+                          +-------------+     |
+                    CPU2  |      3      |     |
+                          +-------------+     |
+                    CPU3  |      4      |     |
+                          +-------------+     |
+                    CPU4  |      4      |     |
+                          +-------------+     |
+                    CPU5  |      4      |     | PLATFORM_CORE_COUNT
+                          +-------------+     |
+                    CPU6  |      5      |     |
+                          +-------------+     |
+                    CPU7  |      5      |     |
+                          +-------------+     |
+                    CPU8  |      5      |     |
+                          +-------------+     |
+                    CPU9  |      6      |     |
+                          +-------------+     |
+                    CPU10 |      6      |     |
+                          +-------------+     |
+                    CPU11 |      6      |     |
+                          +-------------+     |
+                    CPU12 |      6      |     v
+                          +-------------+
+
+The ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in
+each entry is the index of the parent node.
+
+::
+
+                          +-------------+     ^
+                    PD0   |      -1     |     |
+                          +-------------+     |
+                    PD1   |      0      |     |
+                          +-------------+     |
+                    PD2   |      0      |     |
+                          +-------------+     |
+                    PD3   |      1      |     | PLAT_NUM_POWER_DOMAINS -
+                          +-------------+     | PLATFORM_CORE_COUNT
+                    PD4   |      1      |     |
+                          +-------------+     |
+                    PD5   |      2      |     |
+                          +-------------+     |
+                    PD6   |      2      |     |
+                          +-------------+     v
+
+Each core can find its node in the ``psci_cpu_pd_nodes`` array using the
+``plat_my_core_pos()`` function. When a core is turned on, the normal world
+provides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate
+the MPIDR before using it to find the corresponding core node. The non-core power
+domain nodes do not need to be identified.
+
+--------------
+
+*Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/design/reset-design.rst b/docs/design/reset-design.rst
new file mode 100644
index 0000000..ccd717a
--- /dev/null
+++ b/docs/design/reset-design.rst
@@ -0,0 +1,161 @@
+CPU Reset
+=========
+
+This document describes the high-level design of the framework to handle CPU
+resets in Trusted Firmware-A (TF-A). It also describes how the platform
+integrator can tailor this code to the system configuration to some extent,
+resulting in a simplified and more optimised boot flow.
+
+This document should be used in conjunction with the `Firmware Design`_, which
+provides greater implementation details around the reset code, specifically
+for the cold boot path.
+
+General reset code flow
+-----------------------
+
+The TF-A reset code is implemented in BL1 by default. The following high-level
+diagram illustrates this:
+
+|Default reset code flow|
+
+This diagram shows the default, unoptimised reset flow. Depending on the system
+configuration, some of these steps might be unnecessary. The following sections
+guide the platform integrator by indicating which build options exclude which
+steps, depending on the capability of the platform.
+
+.. note::
+   If BL31 is used as the TF-A entry point instead of BL1, the diagram
+   above is still relevant, as all these operations will occur in BL31 in
+   this case. Please refer to section 6 "Using BL31 entrypoint as the reset
+   address" for more information.
+
+Programmable CPU reset address
+------------------------------
+
+By default, TF-A assumes that the CPU reset address is not programmable.
+Therefore, all CPUs start at the same address (typically address 0) whenever
+they reset. Further logic is then required to identify whether it is a cold or
+warm boot to direct CPUs to the right execution path.
+
+If the reset vector address (reflected in the reset vector base address register
+``RVBAR_EL3``) is programmable then it is possible to make each CPU start directly
+at the right address, both on a cold and warm reset. Therefore, the boot type
+detection can be skipped, resulting in the following boot flow:
+
+|Reset code flow with programmable reset address|
+
+To enable this boot flow, compile TF-A with ``PROGRAMMABLE_RESET_ADDRESS=1``.
+This option only affects the TF-A reset image, which is BL1 by default or BL31 if
+``RESET_TO_BL31=1``.
+
+On both the FVP and Juno platforms, the reset vector address is not programmable
+so both ports use ``PROGRAMMABLE_RESET_ADDRESS=0``.
+
+Cold boot on a single CPU
+-------------------------
+
+By default, TF-A assumes that several CPUs may be released out of reset.
+Therefore, the cold boot code has to arbitrate access to hardware resources
+shared amongst CPUs. This is done by nominating one of the CPUs as the primary,
+which is responsible for initialising shared hardware and coordinating the boot
+flow with the other CPUs.
+
+If the platform guarantees that only a single CPU will ever be brought up then
+no arbitration is required. The notion of primary/secondary CPU itself no longer
+applies. This results in the following boot flow:
+
+|Reset code flow with single CPU released out of reset|
+
+To enable this boot flow, compile TF-A with ``COLD_BOOT_SINGLE_CPU=1``. This
+option only affects the TF-A reset image, which is BL1 by default or BL31 if
+``RESET_TO_BL31=1``.
+
+On both the FVP and Juno platforms, although only one core is powered up by
+default, there are platform-specific ways to release any number of cores out of
+reset. Therefore, both platform ports use ``COLD_BOOT_SINGLE_CPU=0``.
+
+Programmable CPU reset address, Cold boot on a single CPU
+---------------------------------------------------------
+
+It is obviously possible to combine both optimisations on platforms that have
+a programmable CPU reset address and which release a single CPU out of reset.
+This results in the following boot flow:
+
+
+|Reset code flow with programmable reset address and single CPU released out of reset|
+
+To enable this boot flow, compile TF-A with both ``COLD_BOOT_SINGLE_CPU=1``
+and ``PROGRAMMABLE_RESET_ADDRESS=1``. These options only affect the TF-A reset
+image, which is BL1 by default or BL31 if ``RESET_TO_BL31=1``.
+
+Using BL31 entrypoint as the reset address
+------------------------------------------
+
+On some platforms the runtime firmware (BL3x images) for the application
+processors are loaded by some firmware running on a secure system processor
+on the SoC, rather than by BL1 and BL2 running on the primary application
+processor. For this type of SoC it is desirable for the application processor
+to always reset to BL31 which eliminates the need for BL1 and BL2.
+
+TF-A provides a build-time option ``RESET_TO_BL31`` that includes some additional
+logic in the BL31 entry point to support this use case.
+
+In this configuration, the platform's Trusted Boot Firmware must ensure that
+BL31 is loaded to its runtime address, which must match the CPU's ``RVBAR_EL3``
+reset vector base address, before the application processor is powered on.
+Additionally, platform software is responsible for loading the other BL3x images
+required and providing entry point information for them to BL31. Loading these
+images might be done by the Trusted Boot Firmware or by platform code in BL31.
+
+Although the Arm FVP platform does not support programming the reset base
+address dynamically at run-time, it is possible to set the initial value of the
+``RVBAR_EL3`` register at start-up. This feature is provided on the Base FVP only.
+It allows the Arm FVP port to support the ``RESET_TO_BL31`` configuration, in
+which case the ``bl31.bin`` image must be loaded to its run address in Trusted
+SRAM and all CPU reset vectors be changed from the default ``0x0`` to this run
+address. See the `User Guide`_ for details of running the FVP models in this way.
+
+Although technically it would be possible to program the reset base address with
+the right support in the SCP firmware, this is currently not implemented so the
+Juno port doesn't support the ``RESET_TO_BL31`` configuration.
+
+The ``RESET_TO_BL31`` configuration requires some additions and changes in the
+BL31 functionality:
+
+Determination of boot path
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this configuration, BL31 uses the same reset framework and code as the one
+described for BL1 above. Therefore, it is affected by the
+``PROGRAMMABLE_RESET_ADDRESS`` and ``COLD_BOOT_SINGLE_CPU`` build options in the
+same way.
+
+In the default, unoptimised BL31 reset flow, on a warm boot a CPU is directed
+to the PSCI implementation via a platform defined mechanism. On a cold boot,
+the platform must place any secondary CPUs into a safe state while the primary
+CPU executes a modified BL31 initialization, as described below.
+
+Platform initialization
+~~~~~~~~~~~~~~~~~~~~~~~
+
+In this configuration, when the CPU resets to BL31 there are no parameters that
+can be passed in registers by previous boot stages. Instead, the platform code
+in BL31 needs to know, or be able to determine, the location of the BL32 (if
+required) and BL33 images and provide this information in response to the
+``bl31_plat_get_next_image_ep_info()`` function.
+
+Additionally, platform software is responsible for carrying out any security
+initialisation, for example programming a TrustZone address space controller.
+This might be done by the Trusted Boot Firmware or by platform code in BL31.
+
+--------------
+
+*Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _Firmware Design: firmware-design.rst
+.. _User Guide: ../getting_started/user-guide.rst
+
+.. |Default reset code flow| image:: ../resources/diagrams/default_reset_code.png
+.. |Reset code flow with programmable reset address| image:: ../resources/diagrams/reset_code_no_boot_type_check.png
+.. |Reset code flow with single CPU released out of reset| image:: ../resources/diagrams/reset_code_no_cpu_check.png
+.. |Reset code flow with programmable reset address and single CPU released out of reset| image:: ../resources/diagrams/reset_code_no_checks.png
diff --git a/docs/design/trusted-board-boot.rst b/docs/design/trusted-board-boot.rst
new file mode 100644
index 0000000..82be272
--- /dev/null
+++ b/docs/design/trusted-board-boot.rst
@@ -0,0 +1,235 @@
+Trusted Board Boot
+==================
+
+The Trusted Board Boot (TBB) feature prevents malicious firmware from running on
+the platform by authenticating all firmware images up to and including the
+normal world bootloader. It does this by establishing a Chain of Trust using
+Public-Key-Cryptography Standards (PKCS).
+
+This document describes the design of Trusted Firmware-A (TF-A) TBB, which is an
+implementation of the `Trusted Board Boot Requirements (TBBR)`_ specification,
+Arm DEN0006D. It should be used in conjunction with the `Firmware Update`_
+design document, which implements a specific aspect of the TBBR.
+
+Chain of Trust
+--------------
+
+A Chain of Trust (CoT) starts with a set of implicitly trusted components. On
+the Arm development platforms, these components are:
+
+-  A SHA-256 hash of the Root of Trust Public Key (ROTPK). It is stored in the
+   trusted root-key storage registers.
+
+-  The BL1 image, on the assumption that it resides in ROM so cannot be
+   tampered with.
+
+The remaining components in the CoT are either certificates or boot loader
+images. The certificates follow the `X.509 v3`_ standard. This standard
+enables adding custom extensions to the certificates, which are used to store
+essential information to establish the CoT.
+
+In the TBB CoT all certificates are self-signed. There is no need for a
+Certificate Authority (CA) because the CoT is not established by verifying the
+validity of a certificate's issuer but by the content of the certificate
+extensions. To sign the certificates, the PKCS#1 SHA-256 with RSA Encryption
+signature scheme is used with a RSA key length of 2048 bits. Future version of
+TF-A will support additional cryptographic algorithms.
+
+The certificates are categorised as "Key" and "Content" certificates. Key
+certificates are used to verify public keys which have been used to sign content
+certificates. Content certificates are used to store the hash of a boot loader
+image. An image can be authenticated by calculating its hash and matching it
+with the hash extracted from the content certificate. The SHA-256 function is
+used to calculate all hashes. The public keys and hashes are included as
+non-standard extension fields in the `X.509 v3`_ certificates.
+
+The keys used to establish the CoT are:
+
+-  **Root of trust key**
+
+   The private part of this key is used to sign the BL2 content certificate and
+   the trusted key certificate. The public part is the ROTPK.
+
+-  **Trusted world key**
+
+   The private part is used to sign the key certificates corresponding to the
+   secure world images (SCP_BL2, BL31 and BL32). The public part is stored in
+   one of the extension fields in the trusted world certificate.
+
+-  **Non-trusted world key**
+
+   The private part is used to sign the key certificate corresponding to the
+   non secure world image (BL33). The public part is stored in one of the
+   extension fields in the trusted world certificate.
+
+-  **BL3-X keys**
+
+   For each of SCP_BL2, BL31, BL32 and BL33, the private part is used to
+   sign the content certificate for the BL3-X image. The public part is stored
+   in one of the extension fields in the corresponding key certificate.
+
+The following images are included in the CoT:
+
+-  BL1
+-  BL2
+-  SCP_BL2 (optional)
+-  BL31
+-  BL33
+-  BL32 (optional)
+
+The following certificates are used to authenticate the images.
+
+-  **BL2 content certificate**
+
+   It is self-signed with the private part of the ROT key. It contains a hash
+   of the BL2 image.
+
+-  **Trusted key certificate**
+
+   It is self-signed with the private part of the ROT key. It contains the
+   public part of the trusted world key and the public part of the non-trusted
+   world key.
+
+-  **SCP_BL2 key certificate**
+
+   It is self-signed with the trusted world key. It contains the public part of
+   the SCP_BL2 key.
+
+-  **SCP_BL2 content certificate**
+
+   It is self-signed with the SCP_BL2 key. It contains a hash of the SCP_BL2
+   image.
+
+-  **BL31 key certificate**
+
+   It is self-signed with the trusted world key. It contains the public part of
+   the BL31 key.
+
+-  **BL31 content certificate**
+
+   It is self-signed with the BL31 key. It contains a hash of the BL31 image.
+
+-  **BL32 key certificate**
+
+   It is self-signed with the trusted world key. It contains the public part of
+   the BL32 key.
+
+-  **BL32 content certificate**
+
+   It is self-signed with the BL32 key. It contains a hash of the BL32 image.
+
+-  **BL33 key certificate**
+
+   It is self-signed with the non-trusted world key. It contains the public
+   part of the BL33 key.
+
+-  **BL33 content certificate**
+
+   It is self-signed with the BL33 key. It contains a hash of the BL33 image.
+
+The SCP_BL2 and BL32 certificates are optional, but they must be present if the
+corresponding SCP_BL2 or BL32 images are present.
+
+Trusted Board Boot Sequence
+---------------------------
+
+The CoT is verified through the following sequence of steps. The system panics
+if any of the steps fail.
+
+-  BL1 loads and verifies the BL2 content certificate. The issuer public key is
+   read from the verified certificate. A hash of that key is calculated and
+   compared with the hash of the ROTPK read from the trusted root-key storage
+   registers. If they match, the BL2 hash is read from the certificate.
+
+   .. note::
+      The matching operation is platform specific and is currently
+      unimplemented on the Arm development platforms.
+
+-  BL1 loads the BL2 image. Its hash is calculated and compared with the hash
+   read from the certificate. Control is transferred to the BL2 image if all
+   the comparisons succeed.
+
+-  BL2 loads and verifies the trusted key certificate. The issuer public key is
+   read from the verified certificate. A hash of that key is calculated and
+   compared with the hash of the ROTPK read from the trusted root-key storage
+   registers. If the comparison succeeds, BL2 reads and saves the trusted and
+   non-trusted world public keys from the verified certificate.
+
+The next two steps are executed for each of the SCP_BL2, BL31 & BL32 images.
+The steps for the optional SCP_BL2 and BL32 images are skipped if these images
+are not present.
+
+-  BL2 loads and verifies the BL3x key certificate. The certificate signature
+   is verified using the trusted world public key. If the signature
+   verification succeeds, BL2 reads and saves the BL3x public key from the
+   certificate.
+
+-  BL2 loads and verifies the BL3x content certificate. The signature is
+   verified using the BL3x public key. If the signature verification succeeds,
+   BL2 reads and saves the BL3x image hash from the certificate.
+
+The next two steps are executed only for the BL33 image.
+
+-  BL2 loads and verifies the BL33 key certificate. If the signature
+   verification succeeds, BL2 reads and saves the BL33 public key from the
+   certificate.
+
+-  BL2 loads and verifies the BL33 content certificate. If the signature
+   verification succeeds, BL2 reads and saves the BL33 image hash from the
+   certificate.
+
+The next step is executed for all the boot loader images.
+
+-  BL2 calculates the hash of each image. It compares it with the hash obtained
+   from the corresponding content certificate. The image authentication succeeds
+   if the hashes match.
+
+The Trusted Board Boot implementation spans both generic and platform-specific
+BL1 and BL2 code, and in tool code on the host build machine. The feature is
+enabled through use of specific build flags as described in the `User Guide`_.
+
+On the host machine, a tool generates the certificates, which are included in
+the FIP along with the boot loader images. These certificates are loaded in
+Trusted SRAM using the IO storage framework. They are then verified by an
+Authentication module included in TF-A.
+
+The mechanism used for generating the FIP and the Authentication module are
+described in the following sections.
+
+Authentication Framework
+------------------------
+
+The authentication framework included in TF-A provides support to implement
+the desired trusted boot sequence. Arm platforms use this framework to
+implement the boot requirements specified in the `TBBR-client`_ document.
+
+More information about the authentication framework can be found in the
+`Auth Framework`_ document.
+
+Certificate Generation Tool
+---------------------------
+
+The ``cert_create`` tool is built and runs on the host machine as part of the
+TF-A build process when ``GENERATE_COT=1``. It takes the boot loader images
+and keys as inputs (keys must be in PEM format) and generates the
+certificates (in DER format) required to establish the CoT. New keys can be
+generated by the tool in case they are not provided. The certificates are then
+passed as inputs to the ``fiptool`` utility for creating the FIP.
+
+The certificates are also stored individually in the in the output build
+directory.
+
+The tool resides in the ``tools/cert_create`` directory. It uses OpenSSL SSL
+library version 1.0.1 or later to generate the X.509 certificates. Instructions
+for building and using the tool can be found in the `User Guide`_.
+
+--------------
+
+*Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Firmware Update: ../components/firmware-update.rst
+.. _X.509 v3: https://tools.ietf.org/rfc/rfc5280.txt
+.. _User Guide: ../getting_started/user-guide.rst
+.. _Auth Framework: auth-framework.rst
+.. _TBBR-client: https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
+.. _Trusted Board Boot Requirements (TBBR): `TBBR-client`_
diff --git a/docs/getting_started/image-terminology.rst b/docs/getting_started/image-terminology.rst
new file mode 100644
index 0000000..d9e08f7
--- /dev/null
+++ b/docs/getting_started/image-terminology.rst
@@ -0,0 +1,175 @@
+Image Terminology
+=================
+
+This page contains the current name, abbreviated name and purpose of the various
+images referred to in the Trusted Firmware project.
+
+General Notes
+-------------
+
+- Some of the names and abbreviated names have changed to accomodate new
+  requirements. The changed names are as backward compatible as possible to
+  minimize confusion. Where applicable, the previous names are indicated. Some
+  code, documentation and build artefacts may still refer to the previous names;
+  these will inevitably take time to catch up.
+
+- The main name change is to prefix each image with the processor it corresponds
+  to (for example ``AP_``, ``SCP_``, ...). In situations where there is no
+  ambiguity (for example, within AP specific code/documentation), it is
+  permitted to omit the processor prefix (for example, just BL1 instead of
+  ``AP_BL1``).
+
+- Previously, the format for 3rd level images had 2 forms; ``BL3`` was either
+  suffixed with a dash ("-") followed by a number (for example, ``BL3-1``) or a
+  subscript number, depending on whether rich text formatting was available.
+  This was confusing and often the dash gets omitted in practice. Therefore the
+  new form is to just omit the dash and not use subscript formatting.
+
+- The names no longer contain dash ("-") characters at all. In some places (for
+  example, function names) it's not possible to use this character. All dashes
+  are either removed or replaced by underscores ("_").
+
+- The abbreviation BL stands for BootLoader. This is a historical anomaly.
+  Clearly, many of these images are not BootLoaders, they are simply firmware
+  images. However, the BL abbreviation is now widely used and is retained for
+  backwards compatibility.
+
+- The image names are not case sensitive. For example, ``bl1`` is
+  interchangeable with ``BL1``, although mixed case should be avoided.
+
+Trusted Firmware Images
+-----------------------
+
+AP Boot ROM: ``AP_BL1``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Typically, this is the first code to execute on the AP and cannot be modified.
+Its primary purpose is to perform the minimum intialization necessary to load
+and authenticate an updateable AP firmware image into an executable RAM
+location, then hand-off control to that image.
+
+AP RAM Firmware: ``AP_BL2``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the 2nd stage AP firmware. It is currently also known as the "Trusted
+Boot Firmware". Its primary purpose is to perform any additional initialization
+required to load and authenticate all 3rd level firmware images into their
+executable RAM locations, then hand-off control to the EL3 Runtime Firmware.
+
+EL3 Runtime Firmware: ``AP_BL31``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Also known as "SoC AP firmware" or "EL3 monitor firmware". Its primary purpose
+is to handle transitions between the normal and secure world.
+
+Secure-EL1 Payload (SP): ``AP_BL32``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Typically this is a TEE or Trusted OS, providing runtime secure services to the
+normal world. However, it may refer to a more abstract Secure-EL1 Payload (SP).
+Note that this abbreviation should only be used in systems where there is a
+single or primary image executing at Secure-EL1. In systems where there are
+potentially multiple SPs and there is no concept of a primary SP, this
+abbreviation should be avoided; use the recommended **Other AP 3rd level
+images** abbreviation instead.
+
+AP Normal World Firmware: ``AP_BL33``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For example, UEFI or uboot. Its primary purpose is to boot a normal world OS.
+
+Other AP 3rd level images: ``AP_BL3_XXX``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The abbreviated names of the existing 3rd level images imply a load/execution
+ordering (for example, ``AP_BL31 -> AP_BL32 -> AP_BL33``).  Some systems may
+have additional images and/or a different load/execution ordering. The
+abbreviated names of the existing images are retained for backward compatibility
+but new 3rd level images should be suffixed with an underscore followed by text
+identifier, not a number.
+
+In systems where 3rd level images are provided by different vendors, the
+abbreviated name should identify the vendor as well as the image
+function. For example, ``AP_BL3_ARM_RAS``.
+
+SCP Boot ROM: ``SCP_BL1`` (previously ``BL0``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Typically, this is the first code to execute on the SCP and cannot be modified.
+Its primary purpose is to perform the minimum intialization necessary to load
+and authenticate an updateable SCP firmware image into an executable RAM
+location, then hand-off control to that image. This may be performed in
+conjunction with other processor firmware (for example, ``AP_BL1`` and
+``AP_BL2``).
+
+This image was previously abbreviated as ``BL0`` but in some systems, the SCP
+may directly load/authenticate its own firmware. In these systems, it doesn't
+make sense to interleave the image terminology for AP and SCP; both AP and SCP
+Boot ROMs are ``BL1`` from their own point of view.
+
+SCP RAM Firmware: ``SCP_BL2`` (previously ``BL3-0``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the 2nd stage SCP firmware. It is currently also known as the "SCP
+runtime firmware" but it could potentially be an intermediate firmware if the
+SCP needs to load/authenticate multiple 3rd level images in future.
+
+This image was previously abbreviated as BL3-0 but from the SCP's point of view,
+this has always been the 2nd stage firmware. The previous name is too
+AP-centric.
+
+Firmware Update (FWU) Images
+----------------------------
+
+The terminology for these images has not been widely adopted yet but they have
+to be considered in a production Trusted Board Boot solution.
+
+AP Firmware Update Boot ROM: ``AP_NS_BL1U``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Typically, this is the first normal world code to execute on the AP during a
+firmware update operation, and cannot be modified. Its primary purpose is to
+load subequent firmware update images from an external interface and communicate
+with ``AP_BL1`` to authenticate those images.
+
+During firmware update, there are (potentially) multiple transitions between the
+secure and normal world. The "level" of the BL image is relative to the world
+it's in so it makes sense to encode "NS" in the normal world images. The absence
+of "NS" implies a secure world image.
+
+AP Firmware Update Config: ``AP_BL2U``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This image does the minimum necessary AP secure world configuration required to
+complete the firmware update operation. It is potentially a subset of ``AP_BL2``
+functionality.
+
+SCP Firmware Update Config: ``SCP_BL2U`` (previously ``BL2-U0``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This image does the minimum necessary SCP secure world configuration required to
+complete the firmware update operation. It is potentially a subset of
+``SCP_BL2`` functionality.
+
+AP Firmware Updater: ``AP_NS_BL2U`` (previously ``BL3-U``)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the 2nd stage AP normal world firmware updater. Its primary purpose is
+to load a new set of firmware images from an external interface and write them
+into non-volatile storage.
+
+Other Processor Firmware Images
+-------------------------------
+
+Some systems may have additional processors to the AP and SCP. For example, a
+Management Control Processor (MCP). Images for these processors should follow
+the same terminology, with the processor abbreviation prefix, followed by
+underscore and the level of the firmware image.
+
+For example,
+
+MCP Boot ROM: ``MCP_BL1``
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MCP RAM Firmware: ``MCP_BL2``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/getting_started/index.rst b/docs/getting_started/index.rst
new file mode 100644
index 0000000..23608f8
--- /dev/null
+++ b/docs/getting_started/index.rst
@@ -0,0 +1,13 @@
+Getting Started
+===============
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   user-guide
+   image-terminology
+   porting-guide
+   psci-lib-integration-guide
+   rt-svc-writers-guide
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
new file mode 100644
index 0000000..b327f6e
--- /dev/null
+++ b/docs/getting_started/porting-guide.rst
@@ -0,0 +1,2845 @@
+Porting Guide
+=============
+
+Introduction
+------------
+
+Porting Trusted Firmware-A (TF-A) to a new platform involves making some
+mandatory and optional modifications for both the cold and warm boot paths.
+Modifications consist of:
+
+-  Implementing a platform-specific function or variable,
+-  Setting up the execution context in a certain way, or
+-  Defining certain constants (for example #defines).
+
+The platform-specific functions and variables are declared in
+`include/plat/common/platform.h`_. The firmware provides a default implementation
+of variables and functions to fulfill the optional requirements. These
+implementations are all weakly defined; they are provided to ease the porting
+effort. Each platform port can override them with its own implementation if the
+default implementation is inadequate.
+
+Some modifications are common to all Boot Loader (BL) stages. Section 2
+discusses these in detail. The subsequent sections discuss the remaining
+modifications for each BL stage in detail.
+
+This document should be read in conjunction with the TF-A `User Guide`_.
+
+Please refer to the `Platform compatibility policy`_ for the policy regarding
+compatibility and deprecation of these porting interfaces.
+
+Only Arm development platforms (such as FVP and Juno) may use the
+functions/definitions in ``include/plat/arm/common/`` and the corresponding
+source files in ``plat/arm/common/``. This is done so that there are no
+dependencies between platforms maintained by different people/companies. If you
+want to use any of the functionality present in ``plat/arm`` files, please
+create a pull request that moves the code to ``plat/common`` so that it can be
+discussed.
+
+Common modifications
+--------------------
+
+This section covers the modifications that should be made by the platform for
+each BL stage to correctly port the firmware stack. They are categorized as
+either mandatory or optional.
+
+Common mandatory modifications
+------------------------------
+
+A platform port must enable the Memory Management Unit (MMU) as well as the
+instruction and data caches for each BL stage. Setting up the translation
+tables is the responsibility of the platform port because memory maps differ
+across platforms. A memory translation library (see ``lib/xlat_tables/``) is
+provided to help in this setup.
+
+Note that although this library supports non-identity mappings, this is intended
+only for re-mapping peripheral physical addresses and allows platforms with high
+I/O addresses to reduce their virtual address space. All other addresses
+corresponding to code and data must currently use an identity mapping.
+
+Also, the only translation granule size supported in TF-A is 4KB, as various
+parts of the code assume that is the case. It is not possible to switch to
+16 KB or 64 KB granule sizes at the moment.
+
+In Arm standard platforms, each BL stage configures the MMU in the
+platform-specific architecture setup function, ``blX_plat_arch_setup()``, and uses
+an identity mapping for all addresses.
+
+If the build option ``USE_COHERENT_MEM`` is enabled, each platform can allocate a
+block of identity mapped secure memory with Device-nGnRE attributes aligned to
+page boundary (4K) for each BL stage. All sections which allocate coherent
+memory are grouped under ``coherent_ram``. For ex: Bakery locks are placed in a
+section identified by name ``bakery_lock`` inside ``coherent_ram`` so that its
+possible for the firmware to place variables in it using the following C code
+directive:
+
+::
+
+    __section("bakery_lock")
+
+Or alternatively the following assembler code directive:
+
+::
+
+    .section bakery_lock
+
+The ``coherent_ram`` section is a sum of all sections like ``bakery_lock`` which are
+used to allocate any data structures that are accessed both when a CPU is
+executing with its MMU and caches enabled, and when it's running with its MMU
+and caches disabled. Examples are given below.
+
+The following variables, functions and constants must be defined by the platform
+for the firmware to work correctly.
+
+File : platform_def.h [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each platform must ensure that a header file of this name is in the system
+include path with the following constants defined. This will require updating
+the list of ``PLAT_INCLUDES`` in the ``platform.mk`` file.
+
+Platform ports may optionally use the file `include/plat/common/common_def.h`_,
+which provides typical values for some of the constants below. These values are
+likely to be suitable for all platform ports.
+
+-  **#define : PLATFORM_LINKER_FORMAT**
+
+   Defines the linker format used by the platform, for example
+   ``elf64-littleaarch64``.
+
+-  **#define : PLATFORM_LINKER_ARCH**
+
+   Defines the processor architecture for the linker by the platform, for
+   example ``aarch64``.
+
+-  **#define : PLATFORM_STACK_SIZE**
+
+   Defines the normal stack memory available to each CPU. This constant is used
+   by `plat/common/aarch64/platform_mp_stack.S`_ and
+   `plat/common/aarch64/platform_up_stack.S`_.
+
+-  **define : CACHE_WRITEBACK_GRANULE**
+
+   Defines the size in bits of the largest cache line across all the cache
+   levels in the platform.
+
+-  **#define : FIRMWARE_WELCOME_STR**
+
+   Defines the character string printed by BL1 upon entry into the ``bl1_main()``
+   function.
+
+-  **#define : PLATFORM_CORE_COUNT**
+
+   Defines the total number of CPUs implemented by the platform across all
+   clusters in the system.
+
+-  **#define : PLAT_NUM_PWR_DOMAINS**
+
+   Defines the total number of nodes in the power domain topology
+   tree at all the power domain levels used by the platform.
+   This macro is used by the PSCI implementation to allocate
+   data structures to represent power domain topology.
+
+-  **#define : PLAT_MAX_PWR_LVL**
+
+   Defines the maximum power domain level that the power management operations
+   should apply to. More often, but not always, the power domain level
+   corresponds to affinity level. This macro allows the PSCI implementation
+   to know the highest power domain level that it should consider for power
+   management operations in the system that the platform implements. For
+   example, the Base AEM FVP implements two clusters with a configurable
+   number of CPUs and it reports the maximum power domain level as 1.
+
+-  **#define : PLAT_MAX_OFF_STATE**
+
+   Defines the local power state corresponding to the deepest power down
+   possible at every power domain level in the platform. The local power
+   states for each level may be sparsely allocated between 0 and this value
+   with 0 being reserved for the RUN state. The PSCI implementation uses this
+   value to initialize the local power states of the power domain nodes and
+   to specify the requested power state for a PSCI_CPU_OFF call.
+
+-  **#define : PLAT_MAX_RET_STATE**
+
+   Defines the local power state corresponding to the deepest retention state
+   possible at every power domain level in the platform. This macro should be
+   a value less than PLAT_MAX_OFF_STATE and greater than 0. It is used by the
+   PSCI implementation to distinguish between retention and power down local
+   power states within PSCI_CPU_SUSPEND call.
+
+-  **#define : PLAT_MAX_PWR_LVL_STATES**
+
+   Defines the maximum number of local power states per power domain level
+   that the platform supports. The default value of this macro is 2 since
+   most platforms just support a maximum of two local power states at each
+   power domain level (power-down and retention). If the platform needs to
+   account for more local power states, then it must redefine this macro.
+
+   Currently, this macro is used by the Generic PSCI implementation to size
+   the array used for PSCI_STAT_COUNT/RESIDENCY accounting.
+
+-  **#define : BL1_RO_BASE**
+
+   Defines the base address in secure ROM where BL1 originally lives. Must be
+   aligned on a page-size boundary.
+
+-  **#define : BL1_RO_LIMIT**
+
+   Defines the maximum address in secure ROM that BL1's actual content (i.e.
+   excluding any data section allocated at runtime) can occupy.
+
+-  **#define : BL1_RW_BASE**
+
+   Defines the base address in secure RAM where BL1's read-write data will live
+   at runtime. Must be aligned on a page-size boundary.
+
+-  **#define : BL1_RW_LIMIT**
+
+   Defines the maximum address in secure RAM that BL1's read-write data can
+   occupy at runtime.
+
+-  **#define : BL2_BASE**
+
+   Defines the base address in secure RAM where BL1 loads the BL2 binary image.
+   Must be aligned on a page-size boundary. This constant is not applicable
+   when BL2_IN_XIP_MEM is set to '1'.
+
+-  **#define : BL2_LIMIT**
+
+   Defines the maximum address in secure RAM that the BL2 image can occupy.
+   This constant is not applicable when BL2_IN_XIP_MEM is set to '1'.
+
+-  **#define : BL2_RO_BASE**
+
+   Defines the base address in secure XIP memory where BL2 RO section originally
+   lives. Must be aligned on a page-size boundary. This constant is only needed
+   when BL2_IN_XIP_MEM is set to '1'.
+
+-  **#define : BL2_RO_LIMIT**
+
+   Defines the maximum address in secure XIP memory that BL2's actual content
+   (i.e. excluding any data section allocated at runtime) can occupy. This
+   constant is only needed when BL2_IN_XIP_MEM is set to '1'.
+
+-  **#define : BL2_RW_BASE**
+
+   Defines the base address in secure RAM where BL2's read-write data will live
+   at runtime. Must be aligned on a page-size boundary. This constant is only
+   needed when BL2_IN_XIP_MEM is set to '1'.
+
+-  **#define : BL2_RW_LIMIT**
+
+   Defines the maximum address in secure RAM that BL2's read-write data can
+   occupy at runtime. This constant is only needed when BL2_IN_XIP_MEM is set
+   to '1'.
+
+-  **#define : BL31_BASE**
+
+   Defines the base address in secure RAM where BL2 loads the BL31 binary
+   image. Must be aligned on a page-size boundary.
+
+-  **#define : BL31_LIMIT**
+
+   Defines the maximum address in secure RAM that the BL31 image can occupy.
+
+For every image, the platform must define individual identifiers that will be
+used by BL1 or BL2 to load the corresponding image into memory from non-volatile
+storage. For the sake of performance, integer numbers will be used as
+identifiers. The platform will use those identifiers to return the relevant
+information about the image to be loaded (file handler, load address,
+authentication information, etc.). The following image identifiers are
+mandatory:
+
+-  **#define : BL2_IMAGE_ID**
+
+   BL2 image identifier, used by BL1 to load BL2.
+
+-  **#define : BL31_IMAGE_ID**
+
+   BL31 image identifier, used by BL2 to load BL31.
+
+-  **#define : BL33_IMAGE_ID**
+
+   BL33 image identifier, used by BL2 to load BL33.
+
+If Trusted Board Boot is enabled, the following certificate identifiers must
+also be defined:
+
+-  **#define : TRUSTED_BOOT_FW_CERT_ID**
+
+   BL2 content certificate identifier, used by BL1 to load the BL2 content
+   certificate.
+
+-  **#define : TRUSTED_KEY_CERT_ID**
+
+   Trusted key certificate identifier, used by BL2 to load the trusted key
+   certificate.
+
+-  **#define : SOC_FW_KEY_CERT_ID**
+
+   BL31 key certificate identifier, used by BL2 to load the BL31 key
+   certificate.
+
+-  **#define : SOC_FW_CONTENT_CERT_ID**
+
+   BL31 content certificate identifier, used by BL2 to load the BL31 content
+   certificate.
+
+-  **#define : NON_TRUSTED_FW_KEY_CERT_ID**
+
+   BL33 key certificate identifier, used by BL2 to load the BL33 key
+   certificate.
+
+-  **#define : NON_TRUSTED_FW_CONTENT_CERT_ID**
+
+   BL33 content certificate identifier, used by BL2 to load the BL33 content
+   certificate.
+
+-  **#define : FWU_CERT_ID**
+
+   Firmware Update (FWU) certificate identifier, used by NS_BL1U to load the
+   FWU content certificate.
+
+-  **#define : PLAT_CRYPTOCELL_BASE**
+
+   This defines the base address of Arm® TrustZone® CryptoCell and must be
+   defined if CryptoCell crypto driver is used for Trusted Board Boot. For
+   capable Arm platforms, this driver is used if ``ARM_CRYPTOCELL_INTEG`` is
+   set.
+
+If the AP Firmware Updater Configuration image, BL2U is used, the following
+must also be defined:
+
+-  **#define : BL2U_BASE**
+
+   Defines the base address in secure memory where BL1 copies the BL2U binary
+   image. Must be aligned on a page-size boundary.
+
+-  **#define : BL2U_LIMIT**
+
+   Defines the maximum address in secure memory that the BL2U image can occupy.
+
+-  **#define : BL2U_IMAGE_ID**
+
+   BL2U image identifier, used by BL1 to fetch an image descriptor
+   corresponding to BL2U.
+
+If the SCP Firmware Update Configuration Image, SCP_BL2U is used, the following
+must also be defined:
+
+-  **#define : SCP_BL2U_IMAGE_ID**
+
+   SCP_BL2U image identifier, used by BL1 to fetch an image descriptor
+   corresponding to SCP_BL2U.
+
+   .. note::
+      TF-A does not provide source code for this image.
+
+If the Non-Secure Firmware Updater ROM, NS_BL1U is used, the following must
+also be defined:
+
+-  **#define : NS_BL1U_BASE**
+
+   Defines the base address in non-secure ROM where NS_BL1U executes.
+   Must be aligned on a page-size boundary.
+
+   .. note::
+      TF-A does not provide source code for this image.
+
+-  **#define : NS_BL1U_IMAGE_ID**
+
+   NS_BL1U image identifier, used by BL1 to fetch an image descriptor
+   corresponding to NS_BL1U.
+
+If the Non-Secure Firmware Updater, NS_BL2U is used, the following must also
+be defined:
+
+-  **#define : NS_BL2U_BASE**
+
+   Defines the base address in non-secure memory where NS_BL2U executes.
+   Must be aligned on a page-size boundary.
+
+   .. note::
+      TF-A does not provide source code for this image.
+
+-  **#define : NS_BL2U_IMAGE_ID**
+
+   NS_BL2U image identifier, used by BL1 to fetch an image descriptor
+   corresponding to NS_BL2U.
+
+For the the Firmware update capability of TRUSTED BOARD BOOT, the following
+macros may also be defined:
+
+-  **#define : PLAT_FWU_MAX_SIMULTANEOUS_IMAGES**
+
+   Total number of images that can be loaded simultaneously. If the platform
+   doesn't specify any value, it defaults to 10.
+
+If a SCP_BL2 image is supported by the platform, the following constants must
+also be defined:
+
+-  **#define : SCP_BL2_IMAGE_ID**
+
+   SCP_BL2 image identifier, used by BL2 to load SCP_BL2 into secure memory
+   from platform storage before being transferred to the SCP.
+
+-  **#define : SCP_FW_KEY_CERT_ID**
+
+   SCP_BL2 key certificate identifier, used by BL2 to load the SCP_BL2 key
+   certificate (mandatory when Trusted Board Boot is enabled).
+
+-  **#define : SCP_FW_CONTENT_CERT_ID**
+
+   SCP_BL2 content certificate identifier, used by BL2 to load the SCP_BL2
+   content certificate (mandatory when Trusted Board Boot is enabled).
+
+If a BL32 image is supported by the platform, the following constants must
+also be defined:
+
+-  **#define : BL32_IMAGE_ID**
+
+   BL32 image identifier, used by BL2 to load BL32.
+
+-  **#define : TRUSTED_OS_FW_KEY_CERT_ID**
+
+   BL32 key certificate identifier, used by BL2 to load the BL32 key
+   certificate (mandatory when Trusted Board Boot is enabled).
+
+-  **#define : TRUSTED_OS_FW_CONTENT_CERT_ID**
+
+   BL32 content certificate identifier, used by BL2 to load the BL32 content
+   certificate (mandatory when Trusted Board Boot is enabled).
+
+-  **#define : BL32_BASE**
+
+   Defines the base address in secure memory where BL2 loads the BL32 binary
+   image. Must be aligned on a page-size boundary.
+
+-  **#define : BL32_LIMIT**
+
+   Defines the maximum address that the BL32 image can occupy.
+
+If the Test Secure-EL1 Payload (TSP) instantiation of BL32 is supported by the
+platform, the following constants must also be defined:
+
+-  **#define : TSP_SEC_MEM_BASE**
+
+   Defines the base address of the secure memory used by the TSP image on the
+   platform. This must be at the same address or below ``BL32_BASE``.
+
+-  **#define : TSP_SEC_MEM_SIZE**
+
+   Defines the size of the secure memory used by the BL32 image on the
+   platform. ``TSP_SEC_MEM_BASE`` and ``TSP_SEC_MEM_SIZE`` must fully
+   accommodate the memory required by the BL32 image, defined by ``BL32_BASE``
+   and ``BL32_LIMIT``.
+
+-  **#define : TSP_IRQ_SEC_PHY_TIMER**
+
+   Defines the ID of the secure physical generic timer interrupt used by the
+   TSP's interrupt handling code.
+
+If the platform port uses the translation table library code, the following
+constants must also be defined:
+
+-  **#define : PLAT_XLAT_TABLES_DYNAMIC**
+
+   Optional flag that can be set per-image to enable the dynamic allocation of
+   regions even when the MMU is enabled. If not defined, only static
+   functionality will be available, if defined and set to 1 it will also
+   include the dynamic functionality.
+
+-  **#define : MAX_XLAT_TABLES**
+
+   Defines the maximum number of translation tables that are allocated by the
+   translation table library code. To minimize the amount of runtime memory
+   used, choose the smallest value needed to map the required virtual addresses
+   for each BL stage. If ``PLAT_XLAT_TABLES_DYNAMIC`` flag is enabled for a BL
+   image, ``MAX_XLAT_TABLES`` must be defined to accommodate the dynamic regions
+   as well.
+
+-  **#define : MAX_MMAP_REGIONS**
+
+   Defines the maximum number of regions that are allocated by the translation
+   table library code. A region consists of physical base address, virtual base
+   address, size and attributes (Device/Memory, RO/RW, Secure/Non-Secure), as
+   defined in the ``mmap_region_t`` structure. The platform defines the regions
+   that should be mapped. Then, the translation table library will create the
+   corresponding tables and descriptors at runtime. To minimize the amount of
+   runtime memory used, choose the smallest value needed to register the
+   required regions for each BL stage. If ``PLAT_XLAT_TABLES_DYNAMIC`` flag is
+   enabled for a BL image, ``MAX_MMAP_REGIONS`` must be defined to accommodate
+   the dynamic regions as well.
+
+-  **#define : PLAT_VIRT_ADDR_SPACE_SIZE**
+
+   Defines the total size of the virtual address space in bytes. For example,
+   for a 32 bit virtual address space, this value should be ``(1ULL << 32)``.
+
+-  **#define : PLAT_PHY_ADDR_SPACE_SIZE**
+
+   Defines the total size of the physical address space in bytes. For example,
+   for a 32 bit physical address space, this value should be ``(1ULL << 32)``.
+
+If the platform port uses the IO storage framework, the following constants
+must also be defined:
+
+-  **#define : MAX_IO_DEVICES**
+
+   Defines the maximum number of registered IO devices. Attempting to register
+   more devices than this value using ``io_register_device()`` will fail with
+   -ENOMEM.
+
+-  **#define : MAX_IO_HANDLES**
+
+   Defines the maximum number of open IO handles. Attempting to open more IO
+   entities than this value using ``io_open()`` will fail with -ENOMEM.
+
+-  **#define : MAX_IO_BLOCK_DEVICES**
+
+   Defines the maximum number of registered IO block devices. Attempting to
+   register more devices this value using ``io_dev_open()`` will fail
+   with -ENOMEM. MAX_IO_BLOCK_DEVICES should be less than MAX_IO_DEVICES.
+   With this macro, multiple block devices could be supported at the same
+   time.
+
+If the platform needs to allocate data within the per-cpu data framework in
+BL31, it should define the following macro. Currently this is only required if
+the platform decides not to use the coherent memory section by undefining the
+``USE_COHERENT_MEM`` build flag. In this case, the framework allocates the
+required memory within the the per-cpu data to minimize wastage.
+
+-  **#define : PLAT_PCPU_DATA_SIZE**
+
+   Defines the memory (in bytes) to be reserved within the per-cpu data
+   structure for use by the platform layer.
+
+The following constants are optional. They should be defined when the platform
+memory layout implies some image overlaying like in Arm standard platforms.
+
+-  **#define : BL31_PROGBITS_LIMIT**
+
+   Defines the maximum address in secure RAM that the BL31's progbits sections
+   can occupy.
+
+-  **#define : TSP_PROGBITS_LIMIT**
+
+   Defines the maximum address that the TSP's progbits sections can occupy.
+
+If the platform port uses the PL061 GPIO driver, the following constant may
+optionally be defined:
+
+-  **PLAT_PL061_MAX_GPIOS**
+   Maximum number of GPIOs required by the platform. This allows control how
+   much memory is allocated for PL061 GPIO controllers. The default value is
+
+   #. $(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
+
+If the platform port uses the partition driver, the following constant may
+optionally be defined:
+
+-  **PLAT_PARTITION_MAX_ENTRIES**
+   Maximum number of partition entries required by the platform. This allows
+   control how much memory is allocated for partition entries. The default
+   value is 128.
+   `For example, define the build flag in platform.mk`_:
+   PLAT_PARTITION_MAX_ENTRIES := 12
+   $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
+
+The following constant is optional. It should be defined to override the default
+behaviour of the ``assert()`` function (for example, to save memory).
+
+-  **PLAT_LOG_LEVEL_ASSERT**
+   If ``PLAT_LOG_LEVEL_ASSERT`` is higher or equal than ``LOG_LEVEL_VERBOSE``,
+   ``assert()`` prints the name of the file, the line number and the asserted
+   expression. Else if it is higher than ``LOG_LEVEL_INFO``, it prints the file
+   name and the line number. Else if it is lower than ``LOG_LEVEL_INFO``, it
+   doesn't print anything to the console. If ``PLAT_LOG_LEVEL_ASSERT`` isn't
+   defined, it defaults to ``LOG_LEVEL``.
+
+If the platform port uses the Activity Monitor Unit, the following constants
+may be defined:
+
+-  **PLAT_AMU_GROUP1_COUNTERS_MASK**
+   This mask reflects the set of group counters that should be enabled.  The
+   maximum number of group 1 counters supported by AMUv1 is 16 so the mask
+   can be at most 0xffff. If the platform does not define this mask, no group 1
+   counters are enabled. If the platform defines this mask, the following
+   constant needs to also be defined.
+
+-  **PLAT_AMU_GROUP1_NR_COUNTERS**
+   This value is used to allocate an array to save and restore the counters
+   specified by ``PLAT_AMU_GROUP1_COUNTERS_MASK`` on CPU suspend.
+   This value should be equal to the highest bit position set in the
+   mask, plus 1.  The maximum number of group 1 counters in AMUv1 is 16.
+
+File : plat_macros.S [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each platform must ensure a file of this name is in the system include path with
+the following macro defined. In the Arm development platforms, this file is
+found in ``plat/arm/board/<plat_name>/include/plat_macros.S``.
+
+-  **Macro : plat_crash_print_regs**
+
+   This macro allows the crash reporting routine to print relevant platform
+   registers in case of an unhandled exception in BL31. This aids in debugging
+   and this macro can be defined to be empty in case register reporting is not
+   desired.
+
+   For instance, GIC or interconnect registers may be helpful for
+   troubleshooting.
+
+Handling Reset
+--------------
+
+BL1 by default implements the reset vector where execution starts from a cold
+or warm boot. BL31 can be optionally set as a reset vector using the
+``RESET_TO_BL31`` make variable.
+
+For each CPU, the reset vector code is responsible for the following tasks:
+
+#. Distinguishing between a cold boot and a warm boot.
+
+#. In the case of a cold boot and the CPU being a secondary CPU, ensuring that
+   the CPU is placed in a platform-specific state until the primary CPU
+   performs the necessary steps to remove it from this state.
+
+#. In the case of a warm boot, ensuring that the CPU jumps to a platform-
+   specific address in the BL31 image in the same processor mode as it was
+   when released from reset.
+
+The following functions need to be implemented by the platform port to enable
+reset vector code to perform the above tasks.
+
+Function : plat_get_my_entrypoint() [mandatory when PROGRAMMABLE_RESET_ADDRESS == 0]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uintptr_t
+
+This function is called with the MMU and caches disabled
+(``SCTLR_EL3.M`` = 0 and ``SCTLR_EL3.C`` = 0). The function is responsible for
+distinguishing between a warm and cold reset for the current CPU using
+platform-specific means. If it's a warm reset, then it returns the warm
+reset entrypoint point provided to ``plat_setup_psci_ops()`` during
+BL31 initialization. If it's a cold reset then this function must return zero.
+
+This function does not follow the Procedure Call Standard used by the
+Application Binary Interface for the Arm 64-bit architecture. The caller should
+not assume that callee saved registers are preserved across a call to this
+function.
+
+This function fulfills requirement 1 and 3 listed above.
+
+Note that for platforms that support programming the reset address, it is
+expected that a CPU will start executing code directly at the right address,
+both on a cold and warm reset. In this case, there is no need to identify the
+type of reset nor to query the warm reset entrypoint. Therefore, implementing
+this function is not required on such platforms.
+
+Function : plat_secondary_cold_boot_setup() [mandatory when COLD_BOOT_SINGLE_CPU == 0]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+
+This function is called with the MMU and data caches disabled. It is responsible
+for placing the executing secondary CPU in a platform-specific state until the
+primary CPU performs the necessary actions to bring it out of that state and
+allow entry into the OS. This function must not return.
+
+In the Arm FVP port, when using the normal boot flow, each secondary CPU powers
+itself off. The primary CPU is responsible for powering up the secondary CPUs
+when normal world software requires them. When booting an EL3 payload instead,
+they stay powered on and are put in a holding pen until their mailbox gets
+populated.
+
+This function fulfills requirement 2 above.
+
+Note that for platforms that can't release secondary CPUs out of reset, only the
+primary CPU will execute the cold boot code. Therefore, implementing this
+function is not required on such platforms.
+
+Function : plat_is_my_cpu_primary() [mandatory when COLD_BOOT_SINGLE_CPU == 0]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : unsigned int
+
+This function identifies whether the current CPU is the primary CPU or a
+secondary CPU. A return value of zero indicates that the CPU is not the
+primary CPU, while a non-zero return value indicates that the CPU is the
+primary CPU.
+
+Note that for platforms that can't release secondary CPUs out of reset, only the
+primary CPU will execute the cold boot code. Therefore, there is no need to
+distinguish between primary and secondary CPUs and implementing this function is
+not required.
+
+Function : platform_mem_init() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function is called before any access to data is made by the firmware, in
+order to carry out any essential memory initialization.
+
+Function: plat_get_rotpk_info()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void *, void **, unsigned int *, unsigned int *
+    Return   : int
+
+This function is mandatory when Trusted Board Boot is enabled. It returns a
+pointer to the ROTPK stored in the platform (or a hash of it) and its length.
+The ROTPK must be encoded in DER format according to the following ASN.1
+structure:
+
+::
+
+    AlgorithmIdentifier  ::=  SEQUENCE  {
+        algorithm         OBJECT IDENTIFIER,
+        parameters        ANY DEFINED BY algorithm OPTIONAL
+    }
+
+    SubjectPublicKeyInfo  ::=  SEQUENCE  {
+        algorithm         AlgorithmIdentifier,
+        subjectPublicKey  BIT STRING
+    }
+
+In case the function returns a hash of the key:
+
+::
+
+    DigestInfo ::= SEQUENCE {
+        digestAlgorithm   AlgorithmIdentifier,
+        digest            OCTET STRING
+    }
+
+The function returns 0 on success. Any other value is treated as error by the
+Trusted Board Boot. The function also reports extra information related
+to the ROTPK in the flags parameter:
+
+::
+
+    ROTPK_IS_HASH      : Indicates that the ROTPK returned by the platform is a
+                         hash.
+    ROTPK_NOT_DEPLOYED : This allows the platform to skip certificate ROTPK
+                         verification while the platform ROTPK is not deployed.
+                         When this flag is set, the function does not need to
+                         return a platform ROTPK, and the authentication
+                         framework uses the ROTPK in the certificate without
+                         verifying it against the platform value. This flag
+                         must not be used in a deployed production environment.
+
+Function: plat_get_nv_ctr()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void *, unsigned int *
+    Return   : int
+
+This function is mandatory when Trusted Board Boot is enabled. It returns the
+non-volatile counter value stored in the platform in the second argument. The
+cookie in the first argument may be used to select the counter in case the
+platform provides more than one (for example, on platforms that use the default
+TBBR CoT, the cookie will correspond to the OID values defined in
+TRUSTED_FW_NVCOUNTER_OID or NON_TRUSTED_FW_NVCOUNTER_OID).
+
+The function returns 0 on success. Any other value means the counter value could
+not be retrieved from the platform.
+
+Function: plat_set_nv_ctr()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void *, unsigned int
+    Return   : int
+
+This function is mandatory when Trusted Board Boot is enabled. It sets a new
+counter value in the platform. The cookie in the first argument may be used to
+select the counter (as explained in plat_get_nv_ctr()). The second argument is
+the updated counter value to be written to the NV counter.
+
+The function returns 0 on success. Any other value means the counter value could
+not be updated.
+
+Function: plat_set_nv_ctr2()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void *, const auth_img_desc_t *, unsigned int
+    Return   : int
+
+This function is optional when Trusted Board Boot is enabled. If this
+interface is defined, then ``plat_set_nv_ctr()`` need not be defined. The
+first argument passed is a cookie and is typically used to
+differentiate between a Non Trusted NV Counter and a Trusted NV
+Counter. The second argument is a pointer to an authentication image
+descriptor and may be used to decide if the counter is allowed to be
+updated or not. The third argument is the updated counter value to
+be written to the NV counter.
+
+The function returns 0 on success. Any other value means the counter value
+either could not be updated or the authentication image descriptor indicates
+that it is not allowed to be updated.
+
+Common mandatory function modifications
+---------------------------------------
+
+The following functions are mandatory functions which need to be implemented
+by the platform port.
+
+Function : plat_my_core_pos()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : unsigned int
+
+This function returns the index of the calling CPU which is used as a
+CPU-specific linear index into blocks of memory (for example while allocating
+per-CPU stacks). This function will be invoked very early in the
+initialization sequence which mandates that this function should be
+implemented in assembly and should not rely on the availability of a C
+runtime environment. This function can clobber x0 - x8 and must preserve
+x9 - x29.
+
+This function plays a crucial role in the power domain topology framework in
+PSCI and details of this can be found in `Power Domain Topology Design`_.
+
+Function : plat_core_pos_by_mpidr()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : u_register_t
+    Return   : int
+
+This function validates the ``MPIDR`` of a CPU and converts it to an index,
+which can be used as a CPU-specific linear index into blocks of memory. In
+case the ``MPIDR`` is invalid, this function returns -1. This function will only
+be invoked by BL31 after the power domain topology is initialized and can
+utilize the C runtime environment. For further details about how TF-A
+represents the power domain topology and how this relates to the linear CPU
+index, please refer `Power Domain Topology Design`_.
+
+Function : plat_get_mbedtls_heap() [when TRUSTED_BOARD_BOOT == 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments : void **heap_addr, size_t *heap_size
+    Return    : int
+
+This function is invoked during Mbed TLS library initialisation to get a heap,
+by means of a starting address and a size. This heap will then be used
+internally by the Mbed TLS library. Hence, each BL stage that utilises Mbed TLS
+must be able to provide a heap to it.
+
+A helper function can be found in `drivers/auth/mbedtls/mbedtls_common.c` in
+which a heap is statically reserved during compile time inside every image
+(i.e. every BL stage) that utilises Mbed TLS. In this default implementation,
+the function simply returns the address and size of this "pre-allocated" heap.
+For a platform to use this default implementation, only a call to the helper
+from inside plat_get_mbedtls_heap() body is enough and nothing else is needed.
+
+However, by writting their own implementation, platforms have the potential to
+optimise memory usage. For example, on some Arm platforms, the Mbed TLS heap is
+shared between BL1 and BL2 stages and, thus, the necessary space is not reserved
+twice.
+
+On success the function should return 0 and a negative error code otherwise.
+
+Common optional modifications
+-----------------------------
+
+The following are helper functions implemented by the firmware that perform
+common platform-specific tasks. A platform may choose to override these
+definitions.
+
+Function : plat_set_my_stack()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function sets the current stack pointer to the normal memory stack that
+has been allocated for the current CPU. For BL images that only require a
+stack for the primary CPU, the UP version of the function is used. The size
+of the stack allocated to each CPU is specified by the platform defined
+constant ``PLATFORM_STACK_SIZE``.
+
+Common implementations of this function for the UP and MP BL images are
+provided in `plat/common/aarch64/platform_up_stack.S`_ and
+`plat/common/aarch64/platform_mp_stack.S`_
+
+Function : plat_get_my_stack()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uintptr_t
+
+This function returns the base address of the normal memory stack that
+has been allocated for the current CPU. For BL images that only require a
+stack for the primary CPU, the UP version of the function is used. The size
+of the stack allocated to each CPU is specified by the platform defined
+constant ``PLATFORM_STACK_SIZE``.
+
+Common implementations of this function for the UP and MP BL images are
+provided in `plat/common/aarch64/platform_up_stack.S`_ and
+`plat/common/aarch64/platform_mp_stack.S`_
+
+Function : plat_report_exception()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : void
+
+A platform may need to report various information about its status when an
+exception is taken, for example the current exception level, the CPU security
+state (secure/non-secure), the exception type, and so on. This function is
+called in the following circumstances:
+
+-  In BL1, whenever an exception is taken.
+-  In BL2, whenever an exception is taken.
+
+The default implementation doesn't do anything, to avoid making assumptions
+about the way the platform displays its status information.
+
+For AArch64, this function receives the exception type as its argument.
+Possible values for exceptions types are listed in the
+`include/common/bl_common.h`_ header file. Note that these constants are not
+related to any architectural exception code; they are just a TF-A convention.
+
+For AArch32, this function receives the exception mode as its argument.
+Possible values for exception modes are listed in the
+`include/lib/aarch32/arch.h`_ header file.
+
+Function : plat_reset_handler()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+A platform may need to do additional initialization after reset. This function
+allows the platform to do the platform specific intializations. Platform
+specific errata workarounds could also be implemented here. The API should
+preserve the values of callee saved registers x19 to x29.
+
+The default implementation doesn't do anything. If a platform needs to override
+the default implementation, refer to the `Firmware Design`_ for general
+guidelines.
+
+Function : plat_disable_acp()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This API allows a platform to disable the Accelerator Coherency Port (if
+present) during a cluster power down sequence. The default weak implementation
+doesn't do anything. Since this API is called during the power down sequence,
+it has restrictions for stack usage and it can use the registers x0 - x17 as
+scratch registers. It should preserve the value in x18 register as it is used
+by the caller to store the return address.
+
+Function : plat_error_handler()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Return   : void
+
+This API is called when the generic code encounters an error situation from
+which it cannot continue. It allows the platform to perform error reporting or
+recovery actions (for example, reset the system). This function must not return.
+
+The parameter indicates the type of error using standard codes from ``errno.h``.
+Possible errors reported by the generic code are:
+
+-  ``-EAUTH``: a certificate or image could not be authenticated (when Trusted
+   Board Boot is enabled)
+-  ``-ENOENT``: the requested image or certificate could not be found or an IO
+   error was detected
+-  ``-ENOMEM``: resources exhausted. TF-A does not use dynamic memory, so this
+   error is usually an indication of an incorrect array size
+
+The default implementation simply spins.
+
+Function : plat_panic_handler()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This API is called when the generic code encounters an unexpected error
+situation from which it cannot recover. This function must not return,
+and must be implemented in assembly because it may be called before the C
+environment is initialized.
+
+.. note::
+   The address from where it was called is stored in x30 (Link Register).
+   The default implementation simply spins.
+
+Function : plat_get_bl_image_load_info()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : bl_load_info_t *
+
+This function returns pointer to the list of images that the platform has
+populated to load. This function is invoked in BL2 to load the
+BL3xx images.
+
+Function : plat_get_next_bl_params()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : bl_params_t *
+
+This function returns a pointer to the shared memory that the platform has
+kept aside to pass TF-A related information that next BL image needs. This
+function is invoked in BL2 to pass this information to the next BL
+image.
+
+Function : plat_get_stack_protector_canary()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : u_register_t
+
+This function returns a random value that is used to initialize the canary used
+when the stack protector is enabled with ENABLE_STACK_PROTECTOR. A predictable
+value will weaken the protection as the attacker could easily write the right
+value as part of the attack most of the time. Therefore, it should return a
+true random number.
+
+.. warning::
+   For the protection to be effective, the global data need to be placed at
+   a lower address than the stack bases. Failure to do so would allow an
+   attacker to overwrite the canary as part of the stack buffer overflow attack.
+
+Function : plat_flush_next_bl_params()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function flushes to main memory all the image params that are passed to
+next image. This function is invoked in BL2 to flush this information
+to the next BL image.
+
+Function : plat_log_get_prefix()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : const char *
+
+This function defines the prefix string corresponding to the `log_level` to be
+prepended to all the log output from TF-A. The `log_level` (argument) will
+correspond to one of the standard log levels defined in debug.h. The platform
+can override the common implementation to define a different prefix string for
+the log output. The implementation should be robust to future changes that
+increase the number of log levels.
+
+Modifications specific to a Boot Loader stage
+---------------------------------------------
+
+Boot Loader Stage 1 (BL1)
+-------------------------
+
+BL1 implements the reset vector where execution starts from after a cold or
+warm boot. For each CPU, BL1 is responsible for the following tasks:
+
+#. Handling the reset as described in section 2.2
+
+#. In the case of a cold boot and the CPU being the primary CPU, ensuring that
+   only this CPU executes the remaining BL1 code, including loading and passing
+   control to the BL2 stage.
+
+#. Identifying and starting the Firmware Update process (if required).
+
+#. Loading the BL2 image from non-volatile storage into secure memory at the
+   address specified by the platform defined constant ``BL2_BASE``.
+
+#. Populating a ``meminfo`` structure with the following information in memory,
+   accessible by BL2 immediately upon entry.
+
+   ::
+
+       meminfo.total_base = Base address of secure RAM visible to BL2
+       meminfo.total_size = Size of secure RAM visible to BL2
+
+   By default, BL1 places this ``meminfo`` structure at the end of secure
+   memory visible to BL2.
+
+   It is possible for the platform to decide where it wants to place the
+   ``meminfo`` structure for BL2 or restrict the amount of memory visible to
+   BL2 by overriding the weak default implementation of
+   ``bl1_plat_handle_post_image_load`` API.
+
+The following functions need to be implemented by the platform port to enable
+BL1 to perform the above tasks.
+
+Function : bl1_early_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU.
+
+On Arm standard platforms, this function:
+
+-  Enables a secure instance of SP805 to act as the Trusted Watchdog.
+
+-  Initializes a UART (PL011 console), which enables access to the ``printf``
+   family of functions in BL1.
+
+-  Enables issuing of snoop and DVM (Distributed Virtual Memory) requests to
+   the CCI slave interface corresponding to the cluster that includes the
+   primary CPU.
+
+Function : bl1_plat_arch_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function performs any platform-specific and architectural setup that the
+platform requires. Platform-specific setup might include configuration of
+memory controllers and the interconnect.
+
+In Arm standard platforms, this function enables the MMU.
+
+This function helps fulfill requirement 2 above.
+
+Function : bl1_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function executes with the MMU and data caches enabled. It is responsible
+for performing any remaining platform-specific setup that can occur after the
+MMU and data cache have been enabled.
+
+if support for multiple boot sources is required, it initializes the boot
+sequence used by plat_try_next_boot_source().
+
+In Arm standard platforms, this function initializes the storage abstraction
+layer used to load the next bootloader image.
+
+This function helps fulfill requirement 4 above.
+
+Function : bl1_plat_sec_mem_layout() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : meminfo *
+
+This function should only be called on the cold boot path. It executes with the
+MMU and data caches enabled. The pointer returned by this function must point to
+a ``meminfo`` structure containing the extents and availability of secure RAM for
+the BL1 stage.
+
+::
+
+    meminfo.total_base = Base address of secure RAM visible to BL1
+    meminfo.total_size = Size of secure RAM visible to BL1
+
+This information is used by BL1 to load the BL2 image in secure RAM. BL1 also
+populates a similar structure to tell BL2 the extents of memory available for
+its own use.
+
+This function helps fulfill requirements 4 and 5 above.
+
+Function : bl1_plat_prepare_exit() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : entry_point_info_t *
+    Return   : void
+
+This function is called prior to exiting BL1 in response to the
+``BL1_SMC_RUN_IMAGE`` SMC request raised by BL2. It should be used to perform
+platform specific clean up or bookkeeping operations before transferring
+control to the next image. It receives the address of the ``entry_point_info_t``
+structure passed from BL2. This function runs with MMU disabled.
+
+Function : bl1_plat_set_ep_info() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int image_id, entry_point_info_t *ep_info
+    Return   : void
+
+This function allows platforms to override ``ep_info`` for the given ``image_id``.
+
+The default implementation just returns.
+
+Function : bl1_plat_get_next_image_id() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : unsigned int
+
+This and the following function must be overridden to enable the FWU feature.
+
+BL1 calls this function after platform setup to identify the next image to be
+loaded and executed. If the platform returns ``BL2_IMAGE_ID`` then BL1 proceeds
+with the normal boot sequence, which loads and executes BL2. If the platform
+returns a different image id, BL1 assumes that Firmware Update is required.
+
+The default implementation always returns ``BL2_IMAGE_ID``. The Arm development
+platforms override this function to detect if firmware update is required, and
+if so, return the first image in the firmware update process.
+
+Function : bl1_plat_get_image_desc() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int image_id
+    Return   : image_desc_t *
+
+BL1 calls this function to get the image descriptor information ``image_desc_t``
+for the provided ``image_id`` from the platform.
+
+The default implementation always returns a common BL2 image descriptor. Arm
+standard platforms return an image descriptor corresponding to BL2 or one of
+the firmware update images defined in the Trusted Board Boot Requirements
+specification.
+
+Function : bl1_plat_handle_pre_image_load() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int image_id
+    Return   : int
+
+This function can be used by the platforms to update/use image information
+corresponding to ``image_id``. This function is invoked in BL1, both in cold
+boot and FWU code path, before loading the image.
+
+Function : bl1_plat_handle_post_image_load() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int image_id
+    Return   : int
+
+This function can be used by the platforms to update/use image information
+corresponding to ``image_id``. This function is invoked in BL1, both in cold
+boot and FWU code path, after loading and authenticating the image.
+
+The default weak implementation of this function calculates the amount of
+Trusted SRAM that can be used by BL2 and allocates a ``meminfo_t``
+structure at the beginning of this free memory and populates it. The address
+of ``meminfo_t`` structure is updated in ``arg1`` of the entrypoint
+information to BL2.
+
+Function : bl1_plat_fwu_done() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int image_id, uintptr_t image_src,
+               unsigned int image_size
+    Return   : void
+
+BL1 calls this function when the FWU process is complete. It must not return.
+The platform may override this function to take platform specific action, for
+example to initiate the normal boot flow.
+
+The default implementation spins forever.
+
+Function : bl1_plat_mem_check() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uintptr_t mem_base, unsigned int mem_size,
+               unsigned int flags
+    Return   : int
+
+BL1 calls this function while handling FWU related SMCs, more specifically when
+copying or authenticating an image. Its responsibility is to ensure that the
+region of memory identified by ``mem_base`` and ``mem_size`` is mapped in BL1, and
+that this memory corresponds to either a secure or non-secure memory region as
+indicated by the security state of the ``flags`` argument.
+
+This function can safely assume that the value resulting from the addition of
+``mem_base`` and ``mem_size`` fits into a ``uintptr_t`` type variable and does not
+overflow.
+
+This function must return 0 on success, a non-null error code otherwise.
+
+The default implementation of this function asserts therefore platforms must
+override it when using the FWU feature.
+
+Boot Loader Stage 2 (BL2)
+-------------------------
+
+The BL2 stage is executed only by the primary CPU, which is determined in BL1
+using the ``platform_is_primary_cpu()`` function. BL1 passed control to BL2 at
+``BL2_BASE``. BL2 executes in Secure EL1 and and invokes
+``plat_get_bl_image_load_info()`` to retrieve the list of images to load from
+non-volatile storage to secure/non-secure RAM. After all the images are loaded
+then BL2 invokes ``plat_get_next_bl_params()`` to get the list of executable
+images to be passed to the next BL image.
+
+The following functions must be implemented by the platform port to enable BL2
+to perform the above tasks.
+
+Function : bl2_early_platform_setup2() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : u_register_t, u_register_t, u_register_t, u_register_t
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU. The 4 arguments are passed by BL1 to BL2 and these arguments
+are platform specific.
+
+On Arm standard platforms, the arguments received are :
+
+    arg0 - Points to load address of HW_CONFIG if present
+
+    arg1 - ``meminfo`` structure populated by BL1. The platform copies
+    the contents of ``meminfo`` as it may be subsequently overwritten by BL2.
+
+On Arm standard platforms, this function also:
+
+-  Initializes a UART (PL011 console), which enables access to the ``printf``
+   family of functions in BL2.
+
+-  Initializes the storage abstraction layer used to load further bootloader
+   images. It is necessary to do this early on platforms with a SCP_BL2 image,
+   since the later ``bl2_platform_setup`` must be done after SCP_BL2 is loaded.
+
+Function : bl2_plat_arch_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU.
+
+The purpose of this function is to perform any architectural initialization
+that varies across platforms.
+
+On Arm standard platforms, this function enables the MMU.
+
+Function : bl2_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function may execute with the MMU and data caches enabled if the platform
+port does the necessary initialization in ``bl2_plat_arch_setup()``. It is only
+called by the primary CPU.
+
+The purpose of this function is to perform any platform initialization
+specific to BL2.
+
+In Arm standard platforms, this function performs security setup, including
+configuration of the TrustZone controller to allow non-secure masters access
+to most of DRAM. Part of DRAM is reserved for secure world use.
+
+Function : bl2_plat_handle_pre_image_load() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This function can be used by the platforms to update/use image information
+for given ``image_id``. This function is currently invoked in BL2 before
+loading each image.
+
+Function : bl2_plat_handle_post_image_load() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int
+    Return   : int
+
+This function can be used by the platforms to update/use image information
+for given ``image_id``. This function is currently invoked in BL2 after
+loading each image.
+
+Function : bl2_plat_preload_setup [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This optional function performs any BL2 platform initialization
+required before image loading, that is not done later in
+bl2_platform_setup(). Specifically, if support for multiple
+boot sources is required, it initializes the boot sequence used by
+plat_try_next_boot_source().
+
+Function : plat_try_next_boot_source() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : int
+
+This optional function passes to the next boot source in the redundancy
+sequence.
+
+This function moves the current boot redundancy source to the next
+element in the boot sequence. If there are no more boot sources then it
+must return 0, otherwise it must return 1. The default implementation
+of this always returns 0.
+
+Boot Loader Stage 2 (BL2) at EL3
+--------------------------------
+
+When the platform has a non-TF-A Boot ROM it is desirable to jump
+directly to BL2 instead of TF-A BL1. In this case BL2 is expected to
+execute at EL3 instead of executing at EL1. Refer to the `Firmware
+Design`_ for more information.
+
+All mandatory functions of BL2 must be implemented, except the functions
+bl2_early_platform_setup and bl2_el3_plat_arch_setup, because
+their work is done now by bl2_el3_early_platform_setup and
+bl2_el3_plat_arch_setup. These functions should generally implement
+the bl1_plat_xxx() and bl2_plat_xxx() functionality combined.
+
+
+Function : bl2_el3_early_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+	Argument : u_register_t, u_register_t, u_register_t, u_register_t
+	Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU. This function receives four parameters which can be used
+by the platform to pass any needed information from the Boot ROM to BL2.
+
+On Arm standard platforms, this function does the following:
+
+-  Initializes a UART (PL011 console), which enables access to the ``printf``
+   family of functions in BL2.
+
+-  Initializes the storage abstraction layer used to load further bootloader
+   images. It is necessary to do this early on platforms with a SCP_BL2 image,
+   since the later ``bl2_platform_setup`` must be done after SCP_BL2 is loaded.
+
+- Initializes the private variables that define the memory layout used.
+
+Function : bl2_el3_plat_arch_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+	Argument : void
+	Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU.
+
+The purpose of this function is to perform any architectural initialization
+that varies across platforms.
+
+On Arm standard platforms, this function enables the MMU.
+
+Function : bl2_el3_plat_prepare_exit() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+	Argument : void
+	Return   : void
+
+This function is called prior to exiting BL2 and run the next image.
+It should be used to perform platform specific clean up or bookkeeping
+operations before transferring control to the next image. This function
+runs with MMU disabled.
+
+FWU Boot Loader Stage 2 (BL2U)
+------------------------------
+
+The AP Firmware Updater Configuration, BL2U, is an optional part of the FWU
+process and is executed only by the primary CPU. BL1 passes control to BL2U at
+``BL2U_BASE``. BL2U executes in Secure-EL1 and is responsible for:
+
+#. (Optional) Transferring the optional SCP_BL2U binary image from AP secure
+   memory to SCP RAM. BL2U uses the SCP_BL2U ``image_info`` passed by BL1.
+   ``SCP_BL2U_BASE`` defines the address in AP secure memory where SCP_BL2U
+   should be copied from. Subsequent handling of the SCP_BL2U image is
+   implemented by the platform specific ``bl2u_plat_handle_scp_bl2u()`` function.
+   If ``SCP_BL2U_BASE`` is not defined then this step is not performed.
+
+#. Any platform specific setup required to perform the FWU process. For
+   example, Arm standard platforms initialize the TZC controller so that the
+   normal world can access DDR memory.
+
+The following functions must be implemented by the platform port to enable
+BL2U to perform the tasks mentioned above.
+
+Function : bl2u_early_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : meminfo *mem_info, void *plat_info
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only
+called by the primary CPU. The arguments to this function is the address
+of the ``meminfo`` structure and platform specific info provided by BL1.
+
+The platform may copy the contents of the ``mem_info`` and ``plat_info`` into
+private storage as the original memory may be subsequently overwritten by BL2U.
+
+On Arm CSS platforms ``plat_info`` is interpreted as an ``image_info_t`` structure,
+to extract SCP_BL2U image information, which is then copied into a private
+variable.
+
+Function : bl2u_plat_arch_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only
+called by the primary CPU.
+
+The purpose of this function is to perform any architectural initialization
+that varies across platforms, for example enabling the MMU (since the memory
+map differs across platforms).
+
+Function : bl2u_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function may execute with the MMU and data caches enabled if the platform
+port does the necessary initialization in ``bl2u_plat_arch_setup()``. It is only
+called by the primary CPU.
+
+The purpose of this function is to perform any platform initialization
+specific to BL2U.
+
+In Arm standard platforms, this function performs security setup, including
+configuration of the TrustZone controller to allow non-secure masters access
+to most of DRAM. Part of DRAM is reserved for secure world use.
+
+Function : bl2u_plat_handle_scp_bl2u() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : int
+
+This function is used to perform any platform-specific actions required to
+handle the SCP firmware. Typically it transfers the image into SCP memory using
+a platform-specific protocol and waits until SCP executes it and signals to the
+Application Processor (AP) for BL2U execution to continue.
+
+This function returns 0 on success, a negative error code otherwise.
+This function is included if SCP_BL2U_BASE is defined.
+
+Boot Loader Stage 3-1 (BL31)
+----------------------------
+
+During cold boot, the BL31 stage is executed only by the primary CPU. This is
+determined in BL1 using the ``platform_is_primary_cpu()`` function. BL1 passes
+control to BL31 at ``BL31_BASE``. During warm boot, BL31 is executed by all
+CPUs. BL31 executes at EL3 and is responsible for:
+
+#. Re-initializing all architectural and platform state. Although BL1 performs
+   some of this initialization, BL31 remains resident in EL3 and must ensure
+   that EL3 architectural and platform state is completely initialized. It
+   should make no assumptions about the system state when it receives control.
+
+#. Passing control to a normal world BL image, pre-loaded at a platform-
+   specific address by BL2. On ARM platforms, BL31 uses the ``bl_params`` list
+   populated by BL2 in memory to do this.
+
+#. Providing runtime firmware services. Currently, BL31 only implements a
+   subset of the Power State Coordination Interface (PSCI) API as a runtime
+   service. See Section 3.3 below for details of porting the PSCI
+   implementation.
+
+#. Optionally passing control to the BL32 image, pre-loaded at a platform-
+   specific address by BL2. BL31 exports a set of APIs that allow runtime
+   services to specify the security state in which the next image should be
+   executed and run the corresponding image. On ARM platforms, BL31 uses the
+   ``bl_params`` list populated by BL2 in memory to do this.
+
+If BL31 is a reset vector, It also needs to handle the reset as specified in
+section 2.2 before the tasks described above.
+
+The following functions must be implemented by the platform port to enable BL31
+to perform the above tasks.
+
+Function : bl31_early_platform_setup2() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : u_register_t, u_register_t, u_register_t, u_register_t
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU. BL2 can pass 4 arguments to BL31 and these arguments are
+platform specific.
+
+In Arm standard platforms, the arguments received are :
+
+    arg0 - The pointer to the head of `bl_params_t` list
+    which is list of executable images following BL31,
+
+    arg1 - Points to load address of SOC_FW_CONFIG if present
+
+    arg2 - Points to load address of HW_CONFIG if present
+
+    arg3 - A special value to verify platform parameters from BL2 to BL31. Not
+    used in release builds.
+
+The function runs through the `bl_param_t` list and extracts the entry point
+information for BL32 and BL33. It also performs the following:
+
+-  Initialize a UART (PL011 console), which enables access to the ``printf``
+   family of functions in BL31.
+
+-  Enable issuing of snoop and DVM (Distributed Virtual Memory) requests to the
+   CCI slave interface corresponding to the cluster that includes the primary
+   CPU.
+
+Function : bl31_plat_arch_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function executes with the MMU and data caches disabled. It is only called
+by the primary CPU.
+
+The purpose of this function is to perform any architectural initialization
+that varies across platforms.
+
+On Arm standard platforms, this function enables the MMU.
+
+Function : bl31_platform_setup() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function may execute with the MMU and data caches enabled if the platform
+port does the necessary initialization in ``bl31_plat_arch_setup()``. It is only
+called by the primary CPU.
+
+The purpose of this function is to complete platform initialization so that both
+BL31 runtime services and normal world software can function correctly.
+
+On Arm standard platforms, this function does the following:
+
+-  Initialize the generic interrupt controller.
+
+   Depending on the GIC driver selected by the platform, the appropriate GICv2
+   or GICv3 initialization will be done, which mainly consists of:
+
+   -  Enable secure interrupts in the GIC CPU interface.
+   -  Disable the legacy interrupt bypass mechanism.
+   -  Configure the priority mask register to allow interrupts of all priorities
+      to be signaled to the CPU interface.
+   -  Mark SGIs 8-15 and the other secure interrupts on the platform as secure.
+   -  Target all secure SPIs to CPU0.
+   -  Enable these secure interrupts in the GIC distributor.
+   -  Configure all other interrupts as non-secure.
+   -  Enable signaling of secure interrupts in the GIC distributor.
+
+-  Enable system-level implementation of the generic timer counter through the
+   memory mapped interface.
+
+-  Grant access to the system counter timer module
+
+-  Initialize the power controller device.
+
+   In particular, initialise the locks that prevent concurrent accesses to the
+   power controller device.
+
+Function : bl31_plat_runtime_setup() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+The purpose of this function is allow the platform to perform any BL31 runtime
+setup just prior to BL31 exit during cold boot. The default weak
+implementation of this function will invoke ``console_switch_state()`` to switch
+console output to consoles marked for use in the ``runtime`` state.
+
+Function : bl31_plat_get_next_image_ep_info() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint32_t
+    Return   : entry_point_info *
+
+This function may execute with the MMU and data caches enabled if the platform
+port does the necessary initializations in ``bl31_plat_arch_setup()``.
+
+This function is called by ``bl31_main()`` to retrieve information provided by
+BL2 for the next image in the security state specified by the argument. BL31
+uses this information to pass control to that image in the specified security
+state. This function must return a pointer to the ``entry_point_info`` structure
+(that was copied during ``bl31_early_platform_setup()``) if the image exists. It
+should return NULL otherwise.
+
+Function : bl31_plat_enable_mmu [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint32_t
+    Return   : void
+
+This function enables the MMU. The boot code calls this function with MMU and
+caches disabled. This function should program necessary registers to enable
+translation, and upon return, the MMU on the calling PE must be enabled.
+
+The function must honor flags passed in the first argument. These flags are
+defined by the translation library, and can be found in the file
+``include/lib/xlat_tables/xlat_mmu_helpers.h``.
+
+On DynamIQ systems, this function must not use stack while enabling MMU, which
+is how the function in xlat table library version 2 is implemented.
+
+Function : plat_init_apiakey [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint64_t *
+
+This function populates the ``plat_apiakey`` array that contains the values used
+to set the ``APIAKey{Hi,Lo}_EL1`` registers. It returns a pointer to this array.
+
+The value should be obtained from a reliable source of randomness.
+
+This function is only needed if ARMv8.3 pointer authentication is used in the
+Trusted Firmware by building with ``ENABLE_PAUTH=1``.
+
+Function : plat_get_syscnt_freq2() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : unsigned int
+
+This function is used by the architecture setup code to retrieve the counter
+frequency for the CPU's generic timer. This value will be programmed into the
+``CNTFRQ_EL0`` register. In Arm standard platforms, it returns the base frequency
+of the system counter, which is retrieved from the first entry in the frequency
+modes table.
+
+#define : PLAT_PERCPU_BAKERY_LOCK_SIZE [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When ``USE_COHERENT_MEM = 0``, this constant defines the total memory (in
+bytes) aligned to the cache line boundary that should be allocated per-cpu to
+accommodate all the bakery locks.
+
+If this constant is not defined when ``USE_COHERENT_MEM = 0``, the linker
+calculates the size of the ``bakery_lock`` input section, aligns it to the
+nearest ``CACHE_WRITEBACK_GRANULE``, multiplies it with ``PLATFORM_CORE_COUNT``
+and stores the result in a linker symbol. This constant prevents a platform
+from relying on the linker and provide a more efficient mechanism for
+accessing per-cpu bakery lock information.
+
+If this constant is defined and its value is not equal to the value
+calculated by the linker then a link time assertion is raised. A compile time
+assertion is raised if the value of the constant is not aligned to the cache
+line boundary.
+
+SDEI porting requirements
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The |SDEI| dispatcher requires the platform to provide the following macros
+and functions, of which some are optional, and some others mandatory.
+
+Macros
+......
+
+Macro: PLAT_SDEI_NORMAL_PRI [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This macro must be defined to the EL3 exception priority level associated with
+Normal |SDEI| events on the platform. This must have a higher value
+(therefore of lower priority) than ``PLAT_SDEI_CRITICAL_PRI``.
+
+Macro: PLAT_SDEI_CRITICAL_PRI [mandatory]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This macro must be defined to the EL3 exception priority level associated with
+Critical |SDEI| events on the platform. This must have a lower value
+(therefore of higher priority) than ``PLAT_SDEI_NORMAL_PRI``.
+
+**Note**: |SDEI| exception priorities must be the lowest among Secure
+priorities. Among the |SDEI| exceptions, Critical |SDEI| priority must
+be higher than Normal |SDEI| priority.
+
+Functions
+.........
+
+Function: int plat_sdei_validate_entry_point(uintptr_t ep) [optional]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+  Argument: uintptr_t
+  Return: int
+
+This function validates the address of client entry points provided for both
+event registration and *Complete and Resume* |SDEI| calls. The function
+takes one argument, which is the address of the handler the |SDEI| client
+requested to register. The function must return ``0`` for successful validation,
+or ``-1`` upon failure.
+
+The default implementation always returns ``0``. On Arm platforms, this function
+is implemented to translate the entry point to physical address, and further to
+ensure that the address is located in Non-secure DRAM.
+
+Function: void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr) [optional]
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+::
+
+  Argument: uint64_t
+  Argument: unsigned int
+  Return: void
+
+|SDEI| specification requires that a PE comes out of reset with the events
+masked. The client therefore is expected to call ``PE_UNMASK`` to unmask
+|SDEI| events on the PE. No |SDEI| events can be dispatched until such
+time.
+
+Should a PE receive an interrupt that was bound to an |SDEI| event while the
+events are masked on the PE, the dispatcher implementation invokes the function
+``plat_sdei_handle_masked_trigger``. The MPIDR of the PE that received the
+interrupt and the interrupt ID are passed as parameters.
+
+The default implementation only prints out a warning message.
+
+Power State Coordination Interface (in BL31)
+--------------------------------------------
+
+The TF-A implementation of the PSCI API is based around the concept of a
+*power domain*. A *power domain* is a CPU or a logical group of CPUs which
+share some state on which power management operations can be performed as
+specified by `PSCI`_. Each CPU in the system is assigned a cpu index which is
+a unique number between ``0`` and ``PLATFORM_CORE_COUNT - 1``. The
+*power domains* are arranged in a hierarchical tree structure and each
+*power domain* can be identified in a system by the cpu index of any CPU that
+is part of that domain and a *power domain level*. A processing element (for
+example, a CPU) is at level 0. If the *power domain* node above a CPU is a
+logical grouping of CPUs that share some state, then level 1 is that group of
+CPUs (for example, a cluster), and level 2 is a group of clusters (for
+example, the system). More details on the power domain topology and its
+organization can be found in `Power Domain Topology Design`_.
+
+BL31's platform initialization code exports a pointer to the platform-specific
+power management operations required for the PSCI implementation to function
+correctly. This information is populated in the ``plat_psci_ops`` structure. The
+PSCI implementation calls members of the ``plat_psci_ops`` structure for performing
+power management operations on the power domains. For example, the target
+CPU is specified by its ``MPIDR`` in a PSCI ``CPU_ON`` call. The ``pwr_domain_on()``
+handler (if present) is called for the CPU power domain.
+
+The ``power-state`` parameter of a PSCI ``CPU_SUSPEND`` call can be used to
+describe composite power states specific to a platform. The PSCI implementation
+defines a generic representation of the power-state parameter, which is an
+array of local power states where each index corresponds to a power domain
+level. Each entry contains the local power state the power domain at that power
+level could enter. It depends on the ``validate_power_state()`` handler to
+convert the power-state parameter (possibly encoding a composite power state)
+passed in a PSCI ``CPU_SUSPEND`` call to this representation.
+
+The following functions form part of platform port of PSCI functionality.
+
+Function : plat_psci_stat_accounting_start() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : const psci_power_state_t *
+    Return   : void
+
+This is an optional hook that platforms can implement for residency statistics
+accounting before entering a low power state. The ``pwr_domain_state`` field of
+``state_info`` (first argument) can be inspected if stat accounting is done
+differently at CPU level versus higher levels. As an example, if the element at
+index 0 (CPU power level) in the ``pwr_domain_state`` array indicates a power down
+state, special hardware logic may be programmed in order to keep track of the
+residency statistics. For higher levels (array indices > 0), the residency
+statistics could be tracked in software using PMF. If ``ENABLE_PMF`` is set, the
+default implementation will use PMF to capture timestamps.
+
+Function : plat_psci_stat_accounting_stop() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : const psci_power_state_t *
+    Return   : void
+
+This is an optional hook that platforms can implement for residency statistics
+accounting after exiting from a low power state. The ``pwr_domain_state`` field
+of ``state_info`` (first argument) can be inspected if stat accounting is done
+differently at CPU level versus higher levels. As an example, if the element at
+index 0 (CPU power level) in the ``pwr_domain_state`` array indicates a power down
+state, special hardware logic may be programmed in order to keep track of the
+residency statistics. For higher levels (array indices > 0), the residency
+statistics could be tracked in software using PMF. If ``ENABLE_PMF`` is set, the
+default implementation will use PMF to capture timestamps.
+
+Function : plat_psci_stat_get_residency() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int, const psci_power_state_t *, int
+    Return   : u_register_t
+
+This is an optional interface that is is invoked after resuming from a low power
+state and provides the time spent resident in that low power state by the power
+domain at a particular power domain level. When a CPU wakes up from suspend,
+all its parent power domain levels are also woken up. The generic PSCI code
+invokes this function for each parent power domain that is resumed and it
+identified by the ``lvl`` (first argument) parameter. The ``state_info`` (second
+argument) describes the low power state that the power domain has resumed from.
+The current CPU is the first CPU in the power domain to resume from the low
+power state and the ``last_cpu_idx`` (third parameter) is the index of the last
+CPU in the power domain to suspend and may be needed to calculate the residency
+for that power domain.
+
+Function : plat_get_target_pwr_state() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int, const plat_local_state_t *, unsigned int
+    Return   : plat_local_state_t
+
+The PSCI generic code uses this function to let the platform participate in
+state coordination during a power management operation. The function is passed
+a pointer to an array of platform specific local power state ``states`` (second
+argument) which contains the requested power state for each CPU at a particular
+power domain level ``lvl`` (first argument) within the power domain. The function
+is expected to traverse this array of upto ``ncpus`` (third argument) and return
+a coordinated target power state by the comparing all the requested power
+states. The target power state should not be deeper than any of the requested
+power states.
+
+A weak definition of this API is provided by default wherein it assumes
+that the platform assigns a local state value in order of increasing depth
+of the power state i.e. for two power states X & Y, if X < Y
+then X represents a shallower power state than Y. As a result, the
+coordinated target local power state for a power domain will be the minimum
+of the requested local power state values.
+
+Function : plat_get_power_domain_tree_desc() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : const unsigned char *
+
+This function returns a pointer to the byte array containing the power domain
+topology tree description. The format and method to construct this array are
+described in `Power Domain Topology Design`_. The BL31 PSCI initialization code
+requires this array to be described by the platform, either statically or
+dynamically, to initialize the power domain topology tree. In case the array
+is populated dynamically, then plat_core_pos_by_mpidr() and
+plat_my_core_pos() should also be implemented suitably so that the topology
+tree description matches the CPU indices returned by these APIs. These APIs
+together form the platform interface for the PSCI topology framework.
+
+Function : plat_setup_psci_ops() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uintptr_t, const plat_psci_ops **
+    Return   : int
+
+This function may execute with the MMU and data caches enabled if the platform
+port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only
+called by the primary CPU.
+
+This function is called by PSCI initialization code. Its purpose is to let
+the platform layer know about the warm boot entrypoint through the
+``sec_entrypoint`` (first argument) and to export handler routines for
+platform-specific psci power management actions by populating the passed
+pointer with a pointer to BL31's private ``plat_psci_ops`` structure.
+
+A description of each member of this structure is given below. Please refer to
+the Arm FVP specific implementation of these handlers in
+`plat/arm/board/fvp/fvp_pm.c`_ as an example. For each PSCI function that the
+platform wants to support, the associated operation or operations in this
+structure must be provided and implemented (Refer section 4 of
+`Firmware Design`_ for the PSCI API supported in TF-A). To disable a PSCI
+function in a platform port, the operation should be removed from this
+structure instead of providing an empty implementation.
+
+plat_psci_ops.cpu_standby()
+...........................
+
+Perform the platform-specific actions to enter the standby state for a cpu
+indicated by the passed argument. This provides a fast path for CPU standby
+wherein overheads of PSCI state management and lock acquisition is avoided.
+For this handler to be invoked by the PSCI ``CPU_SUSPEND`` API implementation,
+the suspend state type specified in the ``power-state`` parameter should be
+STANDBY and the target power domain level specified should be the CPU. The
+handler should put the CPU into a low power retention state (usually by
+issuing a wfi instruction) and ensure that it can be woken up from that
+state by a normal interrupt. The generic code expects the handler to succeed.
+
+plat_psci_ops.pwr_domain_on()
+.............................
+
+Perform the platform specific actions to power on a CPU, specified
+by the ``MPIDR`` (first argument). The generic code expects the platform to
+return PSCI_E_SUCCESS on success or PSCI_E_INTERN_FAIL for any failure.
+
+plat_psci_ops.pwr_domain_off()
+..............................
+
+Perform the platform specific actions to prepare to power off the calling CPU
+and its higher parent power domain levels as indicated by the ``target_state``
+(first argument). It is called by the PSCI ``CPU_OFF`` API implementation.
+
+The ``target_state`` encodes the platform coordinated target local power states
+for the CPU power domain and its parent power domain levels. The handler
+needs to perform power management operation corresponding to the local state
+at each power level.
+
+For this handler, the local power state for the CPU power domain will be a
+power down state where as it could be either power down, retention or run state
+for the higher power domain levels depending on the result of state
+coordination. The generic code expects the handler to succeed.
+
+plat_psci_ops.pwr_domain_suspend_pwrdown_early() [optional]
+...........................................................
+
+This optional function may be used as a performance optimization to replace
+or complement pwr_domain_suspend() on some platforms. Its calling semantics
+are identical to pwr_domain_suspend(), except the PSCI implementation only
+calls this function when suspending to a power down state, and it guarantees
+that data caches are enabled.
+
+When HW_ASSISTED_COHERENCY = 0, the PSCI implementation disables data caches
+before calling pwr_domain_suspend(). If the target_state corresponds to a
+power down state and it is safe to perform some or all of the platform
+specific actions in that function with data caches enabled, it may be more
+efficient to move those actions to this function. When HW_ASSISTED_COHERENCY
+= 1, data caches remain enabled throughout, and so there is no advantage to
+moving platform specific actions to this function.
+
+plat_psci_ops.pwr_domain_suspend()
+..................................
+
+Perform the platform specific actions to prepare to suspend the calling
+CPU and its higher parent power domain levels as indicated by the
+``target_state`` (first argument). It is called by the PSCI ``CPU_SUSPEND``
+API implementation.
+
+The ``target_state`` has a similar meaning as described in
+the ``pwr_domain_off()`` operation. It encodes the platform coordinated
+target local power states for the CPU power domain and its parent
+power domain levels. The handler needs to perform power management operation
+corresponding to the local state at each power level. The generic code
+expects the handler to succeed.
+
+The difference between turning a power domain off versus suspending it is that
+in the former case, the power domain is expected to re-initialize its state
+when it is next powered on (see ``pwr_domain_on_finish()``). In the latter
+case, the power domain is expected to save enough state so that it can resume
+execution by restoring this state when its powered on (see
+``pwr_domain_suspend_finish()``).
+
+When suspending a core, the platform can also choose to power off the GICv3
+Redistributor and ITS through an implementation-defined sequence. To achieve
+this safely, the ITS context must be saved first. The architectural part is
+implemented by the ``gicv3_its_save_disable()`` helper, but most of the needed
+sequence is implementation defined and it is therefore the responsibility of
+the platform code to implement the necessary sequence. Then the GIC
+Redistributor context can be saved using the ``gicv3_rdistif_save()`` helper.
+Powering off the Redistributor requires the implementation to support it and it
+is the responsibility of the platform code to execute the right implementation
+defined sequence.
+
+When a system suspend is requested, the platform can also make use of the
+``gicv3_distif_save()`` helper to save the context of the GIC Distributor after
+it has saved the context of the Redistributors and ITS of all the cores in the
+system. The context of the Distributor can be large and may require it to be
+allocated in a special area if it cannot fit in the platform's global static
+data, for example in DRAM. The Distributor can then be powered down using an
+implementation-defined sequence.
+
+plat_psci_ops.pwr_domain_pwr_down_wfi()
+.......................................
+
+This is an optional function and, if implemented, is expected to perform
+platform specific actions including the ``wfi`` invocation which allows the
+CPU to powerdown. Since this function is invoked outside the PSCI locks,
+the actions performed in this hook must be local to the CPU or the platform
+must ensure that races between multiple CPUs cannot occur.
+
+The ``target_state`` has a similar meaning as described in the ``pwr_domain_off()``
+operation and it encodes the platform coordinated target local power states for
+the CPU power domain and its parent power domain levels. This function must
+not return back to the caller.
+
+If this function is not implemented by the platform, PSCI generic
+implementation invokes ``psci_power_down_wfi()`` for power down.
+
+plat_psci_ops.pwr_domain_on_finish()
+....................................
+
+This function is called by the PSCI implementation after the calling CPU is
+powered on and released from reset in response to an earlier PSCI ``CPU_ON`` call.
+It performs the platform-specific setup required to initialize enough state for
+this CPU to enter the normal world and also provide secure runtime firmware
+services.
+
+The ``target_state`` (first argument) is the prior state of the power domains
+immediately before the CPU was turned on. It indicates which power domains
+above the CPU might require initialization due to having previously been in
+low power states. The generic code expects the handler to succeed.
+
+plat_psci_ops.pwr_domain_suspend_finish()
+.........................................
+
+This function is called by the PSCI implementation after the calling CPU is
+powered on and released from reset in response to an asynchronous wakeup
+event, for example a timer interrupt that was programmed by the CPU during the
+``CPU_SUSPEND`` call or ``SYSTEM_SUSPEND`` call. It performs the platform-specific
+setup required to restore the saved state for this CPU to resume execution
+in the normal world and also provide secure runtime firmware services.
+
+The ``target_state`` (first argument) has a similar meaning as described in
+the ``pwr_domain_on_finish()`` operation. The generic code expects the platform
+to succeed.
+
+If the Distributor, Redistributors or ITS have been powered off as part of a
+suspend, their context must be restored in this function in the reverse order
+to how they were saved during suspend sequence.
+
+plat_psci_ops.system_off()
+..........................
+
+This function is called by PSCI implementation in response to a ``SYSTEM_OFF``
+call. It performs the platform-specific system poweroff sequence after
+notifying the Secure Payload Dispatcher.
+
+plat_psci_ops.system_reset()
+............................
+
+This function is called by PSCI implementation in response to a ``SYSTEM_RESET``
+call. It performs the platform-specific system reset sequence after
+notifying the Secure Payload Dispatcher.
+
+plat_psci_ops.validate_power_state()
+....................................
+
+This function is called by the PSCI implementation during the ``CPU_SUSPEND``
+call to validate the ``power_state`` parameter of the PSCI API and if valid,
+populate it in ``req_state`` (second argument) array as power domain level
+specific local states. If the ``power_state`` is invalid, the platform must
+return PSCI_E_INVALID_PARAMS as error, which is propagated back to the
+normal world PSCI client.
+
+plat_psci_ops.validate_ns_entrypoint()
+......................................
+
+This function is called by the PSCI implementation during the ``CPU_SUSPEND``,
+``SYSTEM_SUSPEND`` and ``CPU_ON`` calls to validate the non-secure ``entry_point``
+parameter passed by the normal world. If the ``entry_point`` is invalid,
+the platform must return PSCI_E_INVALID_ADDRESS as error, which is
+propagated back to the normal world PSCI client.
+
+plat_psci_ops.get_sys_suspend_power_state()
+...........................................
+
+This function is called by the PSCI implementation during the ``SYSTEM_SUSPEND``
+call to get the ``req_state`` parameter from platform which encodes the power
+domain level specific local states to suspend to system affinity level. The
+``req_state`` will be utilized to do the PSCI state coordination and
+``pwr_domain_suspend()`` will be invoked with the coordinated target state to
+enter system suspend.
+
+plat_psci_ops.get_pwr_lvl_state_idx()
+.....................................
+
+This is an optional function and, if implemented, is invoked by the PSCI
+implementation to convert the ``local_state`` (first argument) at a specified
+``pwr_lvl`` (second argument) to an index between 0 and
+``PLAT_MAX_PWR_LVL_STATES`` - 1. This function is only needed if the platform
+supports more than two local power states at each power domain level, that is
+``PLAT_MAX_PWR_LVL_STATES`` is greater than 2, and needs to account for these
+local power states.
+
+plat_psci_ops.translate_power_state_by_mpidr()
+..............................................
+
+This is an optional function and, if implemented, verifies the ``power_state``
+(second argument) parameter of the PSCI API corresponding to a target power
+domain. The target power domain is identified by using both ``MPIDR`` (first
+argument) and the power domain level encoded in ``power_state``. The power domain
+level specific local states are to be extracted from ``power_state`` and be
+populated in the ``output_state`` (third argument) array. The functionality
+is similar to the ``validate_power_state`` function described above and is
+envisaged to be used in case the validity of ``power_state`` depend on the
+targeted power domain. If the ``power_state`` is invalid for the targeted power
+domain, the platform must return PSCI_E_INVALID_PARAMS as error. If this
+function is not implemented, then the generic implementation relies on
+``validate_power_state`` function to translate the ``power_state``.
+
+This function can also be used in case the platform wants to support local
+power state encoding for ``power_state`` parameter of PSCI_STAT_COUNT/RESIDENCY
+APIs as described in Section 5.18 of `PSCI`_.
+
+plat_psci_ops.get_node_hw_state()
+.................................
+
+This is an optional function. If implemented this function is intended to return
+the power state of a node (identified by the first parameter, the ``MPIDR``) in
+the power domain topology (identified by the second parameter, ``power_level``),
+as retrieved from a power controller or equivalent component on the platform.
+Upon successful completion, the implementation must map and return the final
+status among ``HW_ON``, ``HW_OFF`` or ``HW_STANDBY``. Upon encountering failures, it
+must return either ``PSCI_E_INVALID_PARAMS`` or ``PSCI_E_NOT_SUPPORTED`` as
+appropriate.
+
+Implementations are not expected to handle ``power_levels`` greater than
+``PLAT_MAX_PWR_LVL``.
+
+plat_psci_ops.system_reset2()
+.............................
+
+This is an optional function. If implemented this function is
+called during the ``SYSTEM_RESET2`` call to perform a reset
+based on the first parameter ``reset_type`` as specified in
+`PSCI`_. The parameter ``cookie`` can be used to pass additional
+reset information. If the ``reset_type`` is not supported, the
+function must return ``PSCI_E_NOT_SUPPORTED``. For architectural
+resets, all failures must return ``PSCI_E_INVALID_PARAMETERS``
+and vendor reset can return other PSCI error codes as defined
+in `PSCI`_. On success this function will not return.
+
+plat_psci_ops.write_mem_protect()
+.................................
+
+This is an optional function. If implemented it enables or disables the
+``MEM_PROTECT`` functionality based on the value of ``val``.
+A non-zero value enables ``MEM_PROTECT`` and a value of zero
+disables it. Upon encountering failures it must return a negative value
+and on success it must return 0.
+
+plat_psci_ops.read_mem_protect()
+................................
+
+This is an optional function. If implemented it returns the current
+state of ``MEM_PROTECT`` via the ``val`` parameter.  Upon encountering
+failures it must return a negative value and on success it must
+return 0.
+
+plat_psci_ops.mem_protect_chk()
+...............................
+
+This is an optional function. If implemented it checks if a memory
+region defined by a base address ``base`` and with a size of ``length``
+bytes is protected by ``MEM_PROTECT``.  If the region is protected
+then it must return 0, otherwise it must return a negative number.
+
+Interrupt Management framework (in BL31)
+----------------------------------------
+
+BL31 implements an Interrupt Management Framework (IMF) to manage interrupts
+generated in either security state and targeted to EL1 or EL2 in the non-secure
+state or EL3/S-EL1 in the secure state. The design of this framework is
+described in the `IMF Design Guide`_
+
+A platform should export the following APIs to support the IMF. The following
+text briefly describes each API and its implementation in Arm standard
+platforms. The API implementation depends upon the type of interrupt controller
+present in the platform. Arm standard platform layer supports both
+`Arm Generic Interrupt Controller version 2.0 (GICv2)`_
+and `3.0 (GICv3)`_. Juno builds the Arm platform layer to use GICv2 and the
+FVP can be configured to use either GICv2 or GICv3 depending on the build flag
+``FVP_USE_GIC_DRIVER`` (See FVP platform specific build options in
+`User Guide`_ for more details).
+
+See also: `Interrupt Controller Abstraction APIs`__.
+
+.. __: ../design/platform-interrupt-controller-API.rst
+
+Function : plat_interrupt_type_to_line() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint32_t, uint32_t
+    Return   : uint32_t
+
+The Arm processor signals an interrupt exception either through the IRQ or FIQ
+interrupt line. The specific line that is signaled depends on how the interrupt
+controller (IC) reports different interrupt types from an execution context in
+either security state. The IMF uses this API to determine which interrupt line
+the platform IC uses to signal each type of interrupt supported by the framework
+from a given security state. This API must be invoked at EL3.
+
+The first parameter will be one of the ``INTR_TYPE_*`` values (see
+`IMF Design Guide`_) indicating the target type of the interrupt, the second parameter is the
+security state of the originating execution context. The return result is the
+bit position in the ``SCR_EL3`` register of the respective interrupt trap: IRQ=1,
+FIQ=2.
+
+In the case of Arm standard platforms using GICv2, S-EL1 interrupts are
+configured as FIQs and Non-secure interrupts as IRQs from either security
+state.
+
+In the case of Arm standard platforms using GICv3, the interrupt line to be
+configured depends on the security state of the execution context when the
+interrupt is signalled and are as follows:
+
+-  The S-EL1 interrupts are signaled as IRQ in S-EL0/1 context and as FIQ in
+   NS-EL0/1/2 context.
+-  The Non secure interrupts are signaled as FIQ in S-EL0/1 context and as IRQ
+   in the NS-EL0/1/2 context.
+-  The EL3 interrupts are signaled as FIQ in both S-EL0/1 and NS-EL0/1/2
+   context.
+
+Function : plat_ic_get_pending_interrupt_type() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint32_t
+
+This API returns the type of the highest priority pending interrupt at the
+platform IC. The IMF uses the interrupt type to retrieve the corresponding
+handler function. ``INTR_TYPE_INVAL`` is returned when there is no interrupt
+pending. The valid interrupt types that can be returned are ``INTR_TYPE_EL3``,
+``INTR_TYPE_S_EL1`` and ``INTR_TYPE_NS``. This API must be invoked at EL3.
+
+In the case of Arm standard platforms using GICv2, the *Highest Priority
+Pending Interrupt Register* (``GICC_HPPIR``) is read to determine the id of
+the pending interrupt. The type of interrupt depends upon the id value as
+follows.
+
+#. id < 1022 is reported as a S-EL1 interrupt
+#. id = 1022 is reported as a Non-secure interrupt.
+#. id = 1023 is reported as an invalid interrupt type.
+
+In the case of Arm standard platforms using GICv3, the system register
+``ICC_HPPIR0_EL1``, *Highest Priority Pending group 0 Interrupt Register*,
+is read to determine the id of the pending interrupt. The type of interrupt
+depends upon the id value as follows.
+
+#. id = ``PENDING_G1S_INTID`` (1020) is reported as a S-EL1 interrupt
+#. id = ``PENDING_G1NS_INTID`` (1021) is reported as a Non-secure interrupt.
+#. id = ``GIC_SPURIOUS_INTERRUPT`` (1023) is reported as an invalid interrupt type.
+#. All other interrupt id's are reported as EL3 interrupt.
+
+Function : plat_ic_get_pending_interrupt_id() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint32_t
+
+This API returns the id of the highest priority pending interrupt at the
+platform IC. ``INTR_ID_UNAVAILABLE`` is returned when there is no interrupt
+pending.
+
+In the case of Arm standard platforms using GICv2, the *Highest Priority
+Pending Interrupt Register* (``GICC_HPPIR``) is read to determine the id of the
+pending interrupt. The id that is returned by API depends upon the value of
+the id read from the interrupt controller as follows.
+
+#. id < 1022. id is returned as is.
+#. id = 1022. The *Aliased Highest Priority Pending Interrupt Register*
+   (``GICC_AHPPIR``) is read to determine the id of the non-secure interrupt.
+   This id is returned by the API.
+#. id = 1023. ``INTR_ID_UNAVAILABLE`` is returned.
+
+In the case of Arm standard platforms using GICv3, if the API is invoked from
+EL3, the system register ``ICC_HPPIR0_EL1``, *Highest Priority Pending Interrupt
+group 0 Register*, is read to determine the id of the pending interrupt. The id
+that is returned by API depends upon the value of the id read from the
+interrupt controller as follows.
+
+#. id < ``PENDING_G1S_INTID`` (1020). id is returned as is.
+#. id = ``PENDING_G1S_INTID`` (1020) or ``PENDING_G1NS_INTID`` (1021). The system
+   register ``ICC_HPPIR1_EL1``, *Highest Priority Pending Interrupt group 1
+   Register* is read to determine the id of the group 1 interrupt. This id
+   is returned by the API as long as it is a valid interrupt id
+#. If the id is any of the special interrupt identifiers,
+   ``INTR_ID_UNAVAILABLE`` is returned.
+
+When the API invoked from S-EL1 for GICv3 systems, the id read from system
+register ``ICC_HPPIR1_EL1``, *Highest Priority Pending group 1 Interrupt
+Register*, is returned if is not equal to GIC_SPURIOUS_INTERRUPT (1023) else
+``INTR_ID_UNAVAILABLE`` is returned.
+
+Function : plat_ic_acknowledge_interrupt() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint32_t
+
+This API is used by the CPU to indicate to the platform IC that processing of
+the highest pending interrupt has begun. It should return the raw, unmodified
+value obtained from the interrupt controller when acknowledging an interrupt.
+The actual interrupt number shall be extracted from this raw value using the API
+`plat_ic_get_interrupt_id()`__.
+
+.. __: ../design/platform-interrupt-controller-API.rst#function-unsigned-int-plat-ic-get-interrupt-id-unsigned-int-raw-optional
+
+This function in Arm standard platforms using GICv2, reads the *Interrupt
+Acknowledge Register* (``GICC_IAR``). This changes the state of the highest
+priority pending interrupt from pending to active in the interrupt controller.
+It returns the value read from the ``GICC_IAR``, unmodified.
+
+In the case of Arm standard platforms using GICv3, if the API is invoked
+from EL3, the function reads the system register ``ICC_IAR0_EL1``, *Interrupt
+Acknowledge Register group 0*. If the API is invoked from S-EL1, the function
+reads the system register ``ICC_IAR1_EL1``, *Interrupt Acknowledge Register
+group 1*. The read changes the state of the highest pending interrupt from
+pending to active in the interrupt controller. The value read is returned
+unmodified.
+
+The TSP uses this API to start processing of the secure physical timer
+interrupt.
+
+Function : plat_ic_end_of_interrupt() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint32_t
+    Return   : void
+
+This API is used by the CPU to indicate to the platform IC that processing of
+the interrupt corresponding to the id (passed as the parameter) has
+finished. The id should be the same as the id returned by the
+``plat_ic_acknowledge_interrupt()`` API.
+
+Arm standard platforms write the id to the *End of Interrupt Register*
+(``GICC_EOIR``) in case of GICv2, and to ``ICC_EOIR0_EL1`` or ``ICC_EOIR1_EL1``
+system register in case of GICv3 depending on where the API is invoked from,
+EL3 or S-EL1. This deactivates the corresponding interrupt in the interrupt
+controller.
+
+The TSP uses this API to finish processing of the secure physical timer
+interrupt.
+
+Function : plat_ic_get_interrupt_type() [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint32_t
+    Return   : uint32_t
+
+This API returns the type of the interrupt id passed as the parameter.
+``INTR_TYPE_INVAL`` is returned if the id is invalid. If the id is valid, a valid
+interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1`` and ``INTR_TYPE_NS``) is
+returned depending upon how the interrupt has been configured by the platform
+IC. This API must be invoked at EL3.
+
+Arm standard platforms using GICv2 configures S-EL1 interrupts as Group0 interrupts
+and Non-secure interrupts as Group1 interrupts. It reads the group value
+corresponding to the interrupt id from the relevant *Interrupt Group Register*
+(``GICD_IGROUPRn``). It uses the group value to determine the type of interrupt.
+
+In the case of Arm standard platforms using GICv3, both the *Interrupt Group
+Register* (``GICD_IGROUPRn``) and *Interrupt Group Modifier Register*
+(``GICD_IGRPMODRn``) is read to figure out whether the interrupt is configured
+as Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt.
+
+Crash Reporting mechanism (in BL31)
+-----------------------------------
+
+BL31 implements a crash reporting mechanism which prints the various registers
+of the CPU to enable quick crash analysis and debugging. This mechanism relies
+on the platform implementing ``plat_crash_console_init``,
+``plat_crash_console_putc`` and ``plat_crash_console_flush``.
+
+The file ``plat/common/aarch64/crash_console_helpers.S`` contains sample
+implementation of all of them. Platforms may include this file to their
+makefiles in order to benefit from them. By default, they will cause the crash
+output to be routed over the normal console infrastructure and get printed on
+consoles configured to output in crash state. ``console_set_scope()`` can be
+used to control whether a console is used for crash output.
+
+.. note::
+   Platforms are responsible for making sure that they only mark consoles for
+   use in the crash scope that are able to support this, i.e. that are written
+   in assembly and conform with the register clobber rules for putc()
+   (x0-x2, x16-x17) and flush() (x0-x3, x16-x17) crash callbacks.
+
+In some cases (such as debugging very early crashes that happen before the
+normal boot console can be set up), platforms may want to control crash output
+more explicitly. These platforms may instead provide custom implementations for
+these. They are executed outside of a C environment and without a stack. Many
+console drivers provide functions named ``console_xxx_core_init/putc/flush``
+that are designed to be used by these functions. See Arm platforms (like juno)
+for an example of this.
+
+Function : plat_crash_console_init [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : int
+
+This API is used by the crash reporting mechanism to initialize the crash
+console. It must only use the general purpose registers x0 through x7 to do the
+initialization and returns 1 on success.
+
+Function : plat_crash_console_putc [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Return   : int
+
+This API is used by the crash reporting mechanism to print a character on the
+designated crash console. It must only use general purpose registers x1 and
+x2 to do its work. The parameter and the return value are in general purpose
+register x0.
+
+Function : plat_crash_console_flush [mandatory]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : int
+
+This API is used by the crash reporting mechanism to force write of all buffered
+data on the designated crash console. It should only use general purpose
+registers x0 through x5 to do its work. The return value is 0 on successful
+completion; otherwise the return value is -1.
+
+External Abort handling and RAS Support
+---------------------------------------
+
+Function : plat_ea_handler
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Argument : uint64_t
+    Argument : void *
+    Argument : void *
+    Argument : uint64_t
+    Return   : void
+
+This function is invoked by the RAS framework for the platform to handle an
+External Abort received at EL3. The intention of the function is to attempt to
+resolve the cause of External Abort and return; if that's not possible, to
+initiate orderly shutdown of the system.
+
+The first parameter (``int ea_reason``) indicates the reason for External Abort.
+Its value is one of ``ERROR_EA_*`` constants defined in ``ea_handle.h``.
+
+The second parameter (``uint64_t syndrome``) is the respective syndrome
+presented to EL3 after having received the External Abort. Depending on the
+nature of the abort (as can be inferred from the ``ea_reason`` parameter), this
+can be the content of either ``ESR_EL3`` or ``DISR_EL1``.
+
+The third parameter (``void *cookie``) is unused for now. The fourth parameter
+(``void *handle``) is a pointer to the preempted context. The fifth parameter
+(``uint64_t flags``) indicates the preempted security state. These parameters
+are received from the top-level exception handler.
+
+If ``RAS_EXTENSION`` is set to ``1``, the default implementation of this
+function iterates through RAS handlers registered by the platform. If any of the
+RAS handlers resolve the External Abort, no further action is taken.
+
+If ``RAS_EXTENSION`` is set to ``0``, or if none of the platform RAS handlers
+could resolve the External Abort, the default implementation prints an error
+message, and panics.
+
+Function : plat_handle_uncontainable_ea
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Argument : uint64_t
+    Return   : void
+
+This function is invoked by the RAS framework when an External Abort of
+Uncontainable type is received at EL3. Due to the critical nature of
+Uncontainable errors, the intention of this function is to initiate orderly
+shutdown of the system, and is not expected to return.
+
+This function must be implemented in assembly.
+
+The first and second parameters are the same as that of ``plat_ea_handler``.
+
+The default implementation of this function calls
+``report_unhandled_exception``.
+
+Function : plat_handle_double_fault
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : int
+    Argument : uint64_t
+    Return   : void
+
+This function is invoked by the RAS framework when another External Abort is
+received at EL3 while one is already being handled. I.e., a call to
+``plat_ea_handler`` is outstanding. Due to its critical nature, the intention of
+this function is to initiate orderly shutdown of the system, and is not expected
+recover or return.
+
+This function must be implemented in assembly.
+
+The first and second parameters are the same as that of ``plat_ea_handler``.
+
+The default implementation of this function calls
+``report_unhandled_exception``.
+
+Function : plat_handle_el3_ea
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Return   : void
+
+This function is invoked when an External Abort is received while executing in
+EL3. Due to its critical nature, the intention of this function is to initiate
+orderly shutdown of the system, and is not expected recover or return.
+
+This function must be implemented in assembly.
+
+The default implementation of this function calls
+``report_unhandled_exception``.
+
+Build flags
+-----------
+
+There are some build flags which can be defined by the platform to control
+inclusion or exclusion of certain BL stages from the FIP image. These flags
+need to be defined in the platform makefile which will get included by the
+build system.
+
+-  **NEED_BL33**
+   By default, this flag is defined ``yes`` by the build system and ``BL33``
+   build option should be supplied as a build option. The platform has the
+   option of excluding the BL33 image in the ``fip`` image by defining this flag
+   to ``no``. If any of the options ``EL3_PAYLOAD_BASE`` or ``PRELOADED_BL33_BASE``
+   are used, this flag will be set to ``no`` automatically.
+
+C Library
+---------
+
+To avoid subtle toolchain behavioral dependencies, the header files provided
+by the compiler are not used. The software is built with the ``-nostdinc`` flag
+to ensure no headers are included from the toolchain inadvertently. Instead the
+required headers are included in the TF-A source tree. The library only
+contains those C library definitions required by the local implementation. If
+more functionality is required, the needed library functions will need to be
+added to the local implementation.
+
+Some C headers have been obtained from `FreeBSD`_ and `SCC`_, while others have
+been written specifically for TF-A. Fome implementation files have been obtained
+from `FreeBSD`_, others have been written specifically for TF-A as well. The
+files can be found in ``include/lib/libc`` and ``lib/libc``.
+
+SCC can be found in http://www.simple-cc.org/. A copy of the `FreeBSD`_ sources
+can be obtained from http://github.com/freebsd/freebsd.
+
+Storage abstraction layer
+-------------------------
+
+In order to improve platform independence and portability a storage abstraction
+layer is used to load data from non-volatile platform storage. Currently
+storage access is only required by BL1 and BL2 phases and performed inside the
+``load_image()`` function in ``bl_common.c``.
+
+.. uml:: ../resources/diagrams/plantuml/io_framework_usage_overview.puml
+
+It is mandatory to implement at least one storage driver. For the Arm
+development platforms the Firmware Image Package (FIP) driver is provided as
+the default means to load data from storage (see the "Firmware Image Package"
+section in the `User Guide`_). The storage layer is described in the header file
+``include/drivers/io/io_storage.h``. The implementation of the common library
+is in ``drivers/io/io_storage.c`` and the driver files are located in
+``drivers/io/``.
+
+.. uml:: ../resources/diagrams/plantuml/io_arm_class_diagram.puml
+
+Each IO driver must provide ``io_dev_*`` structures, as described in
+``drivers/io/io_driver.h``. These are returned via a mandatory registration
+function that is called on platform initialization. The semi-hosting driver
+implementation in ``io_semihosting.c`` can be used as an example.
+
+Each platform should register devices and their drivers via the storage
+abstraction layer. These drivers then need to be initialized by bootloader
+phases as required in their respective ``blx_platform_setup()`` functions.
+
+.. uml:: ../resources/diagrams/plantuml/io_dev_registration.puml
+
+The storage abstraction layer provides mechanisms (``io_dev_init()``) to
+initialize storage devices before IO operations are called.
+
+.. uml:: ../resources/diagrams/plantuml/io_dev_init_and_check.puml
+
+The basic operations supported by the layer
+include ``open()``, ``close()``, ``read()``, ``write()``, ``size()`` and ``seek()``.
+Drivers do not have to implement all operations, but each platform must
+provide at least one driver for a device capable of supporting generic
+operations such as loading a bootloader image.
+
+The current implementation only allows for known images to be loaded by the
+firmware. These images are specified by using their identifiers, as defined in
+``include/plat/common/common_def.h`` (or a separate header file included from
+there). The platform layer (``plat_get_image_source()``) then returns a reference
+to a device and a driver-specific ``spec`` which will be understood by the driver
+to allow access to the image data.
+
+The layer is designed in such a way that is it possible to chain drivers with
+other drivers. For example, file-system drivers may be implemented on top of
+physical block devices, both represented by IO devices with corresponding
+drivers. In such a case, the file-system "binding" with the block device may
+be deferred until the file-system device is initialised.
+
+The abstraction currently depends on structures being statically allocated
+by the drivers and callers, as the system does not yet provide a means of
+dynamically allocating memory. This may also have the affect of limiting the
+amount of open resources per driver.
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _include/plat/common/platform.h: ../include/plat/common/platform.h
+.. _include/plat/arm/common/plat_arm.h: ../include/plat/arm/common/plat_arm.h%5D
+.. _User Guide: user-guide.rst
+.. _include/plat/common/common_def.h: ../include/plat/common/common_def.h
+.. _include/plat/arm/common/arm_def.h: ../include/plat/arm/common/arm_def.h
+.. _plat/common/aarch64/platform_mp_stack.S: ../plat/common/aarch64/platform_mp_stack.S
+.. _plat/common/aarch64/platform_up_stack.S: ../plat/common/aarch64/platform_up_stack.S
+.. _For example, define the build flag in platform.mk: PLAT_PL061_MAX_GPIOS%20:=%20160
+.. _Power Domain Topology Design: ../design/psci-pd-tree.rst
+.. _include/common/bl_common.h: ../include/common/bl_common.h
+.. _include/lib/aarch32/arch.h: ../include/lib/aarch32/arch.h
+.. _Firmware Design: ../design/firmware-design.rst
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+.. _plat/arm/board/fvp/fvp_pm.c: ../plat/arm/board/fvp/fvp_pm.c
+.. _Platform compatibility policy: ../process/platform-compatibility-policy.rst
+.. _IMF Design Guide: ../design/interrupt-framework-design.rst
+.. _Arm Generic Interrupt Controller version 2.0 (GICv2): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0048b/index.html
+.. _3.0 (GICv3): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0069b/index.html
+.. _FreeBSD: https://www.freebsd.org
+.. _SCC: http://www.simple-cc.org/
diff --git a/docs/getting_started/psci-lib-integration-guide.rst b/docs/getting_started/psci-lib-integration-guide.rst
new file mode 100644
index 0000000..25936d9
--- /dev/null
+++ b/docs/getting_started/psci-lib-integration-guide.rst
@@ -0,0 +1,548 @@
+PSCI Library Integration guide for Armv8-A AArch32 systems
+==========================================================
+
+This document describes the PSCI library interface with a focus on how to
+integrate with a suitable Trusted OS for an Armv8-A AArch32 system. The PSCI
+Library implements the PSCI Standard as described in `PSCI spec`_ and is meant
+to be integrated with EL3 Runtime Software which invokes the PSCI Library
+interface appropriately. **EL3 Runtime Software** refers to software executing
+at the highest secure privileged mode, which is EL3 in AArch64 or Secure SVC/
+Monitor mode in AArch32, and provides runtime services to the non-secure world.
+The runtime service request is made via SMC (Secure Monitor Call) and the call
+must adhere to `SMCCC`_. In AArch32, EL3 Runtime Software may additionally
+include Trusted OS functionality. A minimal AArch32 Secure Payload, SP-MIN, is
+provided in Trusted Firmware-A (TF-A) to illustrate the usage and integration
+of the PSCI library. The description of PSCI library interface and its
+integration with EL3 Runtime Software in this document is targeted towards
+AArch32 systems.
+
+Generic call sequence for PSCI Library interface (AArch32)
+----------------------------------------------------------
+
+The generic call sequence of PSCI Library interfaces (see
+`PSCI Library Interface`_) during cold boot in AArch32
+system is described below:
+
+#. After cold reset, the EL3 Runtime Software performs its cold boot
+   initialization including the PSCI library pre-requisites mentioned in
+   `PSCI Library Interface`_, and also the necessary platform
+   setup.
+
+#. Call ``psci_setup()`` in Monitor mode.
+
+#. Optionally call ``psci_register_spd_pm_hook()`` to register callbacks to
+   do bookkeeping for the EL3 Runtime Software during power management.
+
+#. Call ``psci_prepare_next_non_secure_ctx()`` to initialize the non-secure CPU
+   context.
+
+#. Get the non-secure ``cpu_context_t`` for the current CPU by calling
+   ``cm_get_context()`` , then programming the registers in the non-secure
+   context and exiting to non-secure world. If the EL3 Runtime Software needs
+   additional configuration to be set for non-secure context, like routing
+   FIQs to the secure world, the values of the registers can be modified prior
+   to programming. See `PSCI CPU context management`_ for more
+   details on CPU context management.
+
+The generic call sequence of PSCI library interfaces during warm boot in
+AArch32 systems is described below:
+
+#. After warm reset, the EL3 Runtime Software performs the necessary warm
+   boot initialization including the PSCI library pre-requisites mentioned in
+   `PSCI Library Interface`_ (Note that the Data cache
+   **must not** be enabled).
+
+#. Call ``psci_warmboot_entrypoint()`` in Monitor mode. This interface
+   initializes/restores the non-secure CPU context as well.
+
+#. Do step 5 of the cold boot call sequence described above.
+
+The generic call sequence of PSCI library interfaces on receipt of a PSCI SMC
+on an AArch32 system is described below:
+
+#. On receipt of an SMC, save the register context as per `SMCCC`_.
+
+#. If the SMC function identifier corresponds to a SMC32 PSCI API, construct
+   the appropriate arguments and call the ``psci_smc_handler()`` interface.
+   The invocation may or may not return back to the caller depending on
+   whether the PSCI API resulted in power down of the CPU.
+
+#. If ``psci_smc_handler()`` returns, populate the return value in R0 (AArch32)/
+   X0 (AArch64) and restore other registers as per `SMCCC`_.
+
+PSCI CPU context management
+---------------------------
+
+PSCI library is in charge of initializing/restoring the non-secure CPU system
+registers according to `PSCI specification`_ during cold/warm boot.
+This is referred to as ``PSCI CPU Context Management``. Registers that need to
+be preserved across CPU power down/power up cycles are maintained in
+``cpu_context_t`` data structure. The initialization of other non-secure CPU
+system registers which do not require coordination with the EL3 Runtime
+Software is done directly by the PSCI library (see ``cm_prepare_el3_exit()``).
+
+The EL3 Runtime Software is responsible for managing register context
+during switch between Normal and Secure worlds. The register context to be
+saved and restored depends on the mechanism used to trigger the world switch.
+For example, if the world switch was triggered by an SMC call, then the
+registers need to be saved and restored according to `SMCCC`_. In AArch64,
+due to the tight integration with BL31, both BL31 and PSCI library
+use the same ``cpu_context_t`` data structure for PSCI CPU context management
+and register context management during world switch. This cannot be assumed
+for AArch32 EL3 Runtime Software since most AArch32 Trusted OSes already implement
+a mechanism for register context management during world switch. Hence, when
+the PSCI library is integrated with a AArch32 EL3 Runtime Software, the
+``cpu_context_t`` is stripped down for just PSCI CPU context management.
+
+During cold/warm boot, after invoking appropriate PSCI library interfaces, it
+is expected that the EL3 Runtime Software will query the ``cpu_context_t`` and
+write appropriate values to the corresponding system registers. This mechanism
+resolves 2 additional problems for AArch32 EL3 Runtime Software:
+
+#. Values for certain system registers like SCR and SCTLR cannot be
+   unilaterally determined by PSCI library and need inputs from the EL3
+   Runtime Software. Using ``cpu_context_t`` as an intermediary data store
+   allows EL3 Runtime Software to modify the register values appropriately
+   before programming them.
+
+#. The PSCI library provides appropriate LR and SPSR values (entrypoint
+   information) for exit into non-secure world. Using ``cpu_context_t`` as an
+   intermediary data store allows the EL3 Runtime Software to store these
+   values safely until it is ready for exit to non-secure world.
+
+Currently the ``cpu_context_t`` data structure for AArch32 stores the following
+registers: R0 - R3, LR (R14), SCR, SPSR, SCTLR.
+
+The EL3 Runtime Software must implement accessors to get/set pointers
+to CPU context ``cpu_context_t`` data and these are described in
+`CPU Context management API`_.
+
+PSCI Library Interface
+----------------------
+
+The PSCI library implements the `PSCI Specification`_. The interfaces
+to this library are declared in ``psci_lib.h`` and are as listed below:
+
+.. code:: c
+
+        u_register_t psci_smc_handler(uint32_t smc_fid, u_register_t x1,
+                                      u_register_t x2, u_register_t x3,
+                                      u_register_t x4, void *cookie,
+                                      void *handle, u_register_t flags);
+        int psci_setup(const psci_lib_args_t *lib_args);
+        void psci_warmboot_entrypoint(void);
+        void psci_register_spd_pm_hook(const spd_pm_ops_t *pm);
+        void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info);
+
+The CPU context data 'cpu_context_t' is programmed to the registers differently
+when PSCI is integrated with an AArch32 EL3 Runtime Software compared to
+when the PSCI is integrated with an AArch64 EL3 Runtime Software (BL31). For
+example, in the case of AArch64, there is no need to retrieve ``cpu_context_t``
+data and program the registers as it will done implicitly as part of
+``el3_exit``. The description below of the PSCI interfaces is targeted at
+integration with an AArch32 EL3 Runtime Software.
+
+The PSCI library is responsible for initializing/restoring the non-secure world
+to an appropriate state after boot and may choose to directly program the
+non-secure system registers. The PSCI generic code takes care not to directly
+modify any of the system registers affecting the secure world and instead
+returns the values to be programmed to these registers via ``cpu_context_t``.
+The EL3 Runtime Software is responsible for programming those registers and
+can use the proposed values provided in the ``cpu_context_t``, modifying the
+values if required.
+
+PSCI library needs the flexibility to access both secure and non-secure
+copies of banked registers. Hence it needs to be invoked in Monitor mode
+for AArch32 and in EL3 for AArch64. The NS bit in SCR (in AArch32) or SCR_EL3
+(in AArch64) must be set to 0. Additional requirements for the PSCI library
+interfaces are:
+
+-  Instruction cache must be enabled
+-  Both IRQ and FIQ must be masked for the current CPU
+-  The page tables must be setup and the MMU enabled
+-  The C runtime environment must be setup and stack initialized
+-  The Data cache must be enabled prior to invoking any of the PSCI library
+   interfaces except for ``psci_warmboot_entrypoint()``. For
+   ``psci_warmboot_entrypoint()``, if the build option ``HW_ASSISTED_COHERENCY``
+   is enabled however, data caches are expected to be enabled.
+
+Further requirements for each interface can be found in the interface
+description.
+
+Interface : psci_setup()
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : const psci_lib_args_t *lib_args
+    Return   : void
+
+This function is to be called by the primary CPU during cold boot before
+any other interface to the PSCI library. It takes ``lib_args``, a const pointer
+to ``psci_lib_args_t``, as the argument. The ``psci_lib_args_t`` is a versioned
+structure and is declared in ``psci_lib.h`` header as follows:
+
+.. code:: c
+
+        typedef struct psci_lib_args {
+            /* The version information of PSCI Library Interface */
+            param_header_t        h;
+            /* The warm boot entrypoint function */
+            mailbox_entrypoint_t  mailbox_ep;
+        } psci_lib_args_t;
+
+The first field ``h``, of ``param_header_t`` type, provides the version
+information. The second field ``mailbox_ep`` is the warm boot entrypoint address
+and is used to configure the platform mailbox. Helper macros are provided in
+``psci_lib.h`` to construct the ``lib_args`` argument statically or during
+runtime. Prior to calling the ``psci_setup()`` interface, the platform setup for
+cold boot must have completed. Major actions performed by this interface are:
+
+-  Initializes architecture.
+-  Initializes PSCI power domain and state coordination data structures.
+-  Calls ``plat_setup_psci_ops()`` with warm boot entrypoint ``mailbox_ep`` as
+   argument.
+-  Calls ``cm_set_context_by_index()`` (see
+   `CPU Context management API`_) for all the CPUs in the
+   platform
+
+Interface : psci_prepare_next_non_secure_ctx()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : entry_point_info_t *next_image_info
+    Return   : void
+
+After ``psci_setup()`` and prior to exit to the non-secure world, this function
+must be called by the EL3 Runtime Software to initialize the non-secure world
+context. The non-secure world entrypoint information ``next_image_info`` (first
+argument) will be used to determine the non-secure context. After this function
+returns, the EL3 Runtime Software must retrieve the ``cpu_context_t`` (using
+cm_get_context()) for the current CPU and program the registers prior to exit
+to the non-secure world.
+
+Interface : psci_register_spd_pm_hook()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : const spd_pm_ops_t *
+    Return   : void
+
+As explained in `Secure payload power management callback`_,
+the EL3 Runtime Software may want to perform some bookkeeping during power
+management operations. This function is used to register the ``spd_pm_ops_t``
+(first argument) callbacks with the PSCI library which will be called
+appropriately during power management. Calling this function is optional and
+need to be called by the primary CPU during the cold boot sequence after
+``psci_setup()`` has completed.
+
+Interface : psci_smc_handler()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : uint32_t smc_fid, u_register_t x1,
+               u_register_t x2, u_register_t x3,
+               u_register_t x4, void *cookie,
+               void *handle, u_register_t flags
+    Return   : u_register_t
+
+This function is the top level handler for SMCs which fall within the
+PSCI service range specified in `SMCCC`_. The function ID ``smc_fid`` (first
+argument) determines the PSCI API to be called. The ``x1`` to ``x4`` (2nd to 5th
+arguments), are the values of the registers r1 - r4 (in AArch32) or x1 - x4
+(in AArch64) when the SMC is received. These are the arguments to PSCI API as
+described in `PSCI spec`_. The 'flags' (8th argument) is a bit field parameter
+and is detailed in 'smccc.h' header. It includes whether the call is from the
+secure or non-secure world. The ``cookie`` (6th argument) and the ``handle``
+(7th argument) are not used and are reserved for future use.
+
+The return value from this interface is the return value from the underlying
+PSCI API corresponding to ``smc_fid``. This function may not return back to the
+caller if PSCI API causes power down of the CPU. In this case, when the CPU
+wakes up, it will start execution from the warm reset address.
+
+Interface : psci_warmboot_entrypoint()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+This function performs the warm boot initialization/restoration as mandated by
+`PSCI spec`_. For AArch32, on wakeup from power down the CPU resets to secure SVC
+mode and the EL3 Runtime Software must perform the prerequisite initializations
+mentioned at top of this section. This function must be called with Data cache
+disabled (unless build option ``HW_ASSISTED_COHERENCY`` is enabled) but with MMU
+initialized and enabled. The major actions performed by this function are:
+
+-  Invalidates the stack and enables the data cache.
+-  Initializes architecture and PSCI state coordination.
+-  Restores/Initializes the peripheral drivers to the required state via
+   appropriate ``plat_psci_ops_t`` hooks
+-  Restores the EL3 Runtime Software context via appropriate ``spd_pm_ops_t``
+   callbacks.
+-  Restores/Initializes the non-secure context and populates the
+   ``cpu_context_t`` for the current CPU.
+
+Upon the return of this function, the EL3 Runtime Software must retrieve the
+non-secure ``cpu_context_t`` using ``cm_get_context()`` and program the registers
+prior to exit to the non-secure world.
+
+EL3 Runtime Software dependencies
+---------------------------------
+
+The PSCI Library includes supporting frameworks like context management,
+cpu operations (cpu_ops) and per-cpu data framework. Other helper library
+functions like bakery locks and spin locks are also included in the library.
+The dependencies which must be fulfilled by the EL3 Runtime Software
+for integration with PSCI library are described below.
+
+General dependencies
+~~~~~~~~~~~~~~~~~~~~
+
+The PSCI library being a Multiprocessor (MP) implementation, EL3 Runtime
+Software must provide an SMC handling framework capable of MP adhering to
+`SMCCC`_ specification.
+
+The EL3 Runtime Software must also export cache maintenance primitives
+and some helper utilities for assert, print and memory operations as listed
+below. The TF-A source tree provides implementations for all
+these functions but the EL3 Runtime Software may use its own implementation.
+
+**Functions : assert(), memcpy(), memset(), printf()**
+
+These must be implemented as described in ISO C Standard.
+
+**Function : flush_dcache_range()**
+
+::
+
+    Argument : uintptr_t addr, size_t size
+    Return   : void
+
+This function cleans and invalidates (flushes) the data cache for memory
+at address ``addr`` (first argument) address and of size ``size`` (second argument).
+
+**Function : inv_dcache_range()**
+
+::
+
+    Argument : uintptr_t addr, size_t size
+    Return   : void
+
+This function invalidates (flushes) the data cache for memory at address
+``addr`` (first argument) address and of size ``size`` (second argument).
+
+**Function : do_panic()**
+
+::
+
+    Argument : void
+    Return   : void
+
+This function will be called by the PSCI library on encountering a critical
+failure that cannot be recovered from. This function **must not** return.
+
+CPU Context management API
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The CPU context management data memory is statically allocated by PSCI library
+in BSS section. The PSCI library requires the EL3 Runtime Software to implement
+APIs to store and retrieve pointers to this CPU context data. SP-MIN
+demonstrates how these APIs can be implemented but the EL3 Runtime Software can
+choose a more optimal implementation (like dedicating the secure TPIDRPRW
+system register (in AArch32) for storing these pointers).
+
+**Function : cm_set_context_by_index()**
+
+::
+
+    Argument : unsigned int cpu_idx, void *context, unsigned int security_state
+    Return   : void
+
+This function is called during cold boot when the ``psci_setup()`` PSCI library
+interface is called.
+
+This function must store the pointer to the CPU context data, ``context`` (2nd
+argument), for the specified ``security_state`` (3rd argument) and CPU identified
+by ``cpu_idx`` (first argument). The ``security_state`` will always be non-secure
+when called by PSCI library and this argument is retained for compatibility
+with BL31. The ``cpu_idx`` will correspond to the index returned by the
+``plat_core_pos_by_mpidr()`` for ``mpidr`` of the CPU.
+
+The actual method of storing the ``context`` pointers is implementation specific.
+For example, SP-MIN stores the pointers in the array ``sp_min_cpu_ctx_ptr``
+declared in ``sp_min_main.c``.
+
+**Function : cm_get_context()**
+
+::
+
+    Argument : uint32_t security_state
+    Return   : void *
+
+This function must return the pointer to the ``cpu_context_t`` structure for
+the specified ``security_state`` (first argument) for the current CPU. The caller
+must ensure that ``cm_set_context_by_index`` is called first and the appropriate
+context pointers are stored prior to invoking this API. The ``security_state``
+will always be non-secure when called by PSCI library and this argument
+is retained for compatibility with BL31.
+
+**Function : cm_get_context_by_index()**
+
+::
+
+    Argument : unsigned int cpu_idx, unsigned int security_state
+    Return   : void *
+
+This function must return the pointer to the ``cpu_context_t`` structure for
+the specified ``security_state`` (second argument) for the CPU identified by
+``cpu_idx`` (first argument). The caller must ensure that
+``cm_set_context_by_index`` is called first and the appropriate context
+pointers are stored prior to invoking this API. The ``security_state`` will
+always be non-secure when called by PSCI library and this argument is
+retained for compatibility with BL31. The ``cpu_idx`` will correspond to the
+index returned by the ``plat_core_pos_by_mpidr()`` for ``mpidr`` of the CPU.
+
+Platform API
+~~~~~~~~~~~~
+
+The platform layer abstracts the platform-specific details from the generic
+PSCI library. The following platform APIs/macros must be defined by the EL3
+Runtime Software for integration with the PSCI library.
+
+The mandatory platform APIs are:
+
+-  plat_my_core_pos
+-  plat_core_pos_by_mpidr
+-  plat_get_syscnt_freq2
+-  plat_get_power_domain_tree_desc
+-  plat_setup_psci_ops
+-  plat_reset_handler
+-  plat_panic_handler
+-  plat_get_my_stack
+
+The mandatory platform macros are:
+
+-  PLATFORM_CORE_COUNT
+-  PLAT_MAX_PWR_LVL
+-  PLAT_NUM_PWR_DOMAINS
+-  CACHE_WRITEBACK_GRANULE
+-  PLAT_MAX_OFF_STATE
+-  PLAT_MAX_RET_STATE
+-  PLAT_MAX_PWR_LVL_STATES (optional)
+-  PLAT_PCPU_DATA_SIZE (optional)
+
+The details of these APIs/macros can be found in `Porting Guide`_.
+
+All platform specific operations for power management are done via
+``plat_psci_ops_t`` callbacks registered by the platform when
+``plat_setup_psci_ops()`` API is called. The description of each of
+the callbacks in ``plat_psci_ops_t`` can be found in PSCI section of the
+`Porting Guide`_. If any these callbacks are not registered, then the
+PSCI API associated with that callback will not be supported by PSCI
+library.
+
+Secure payload power management callback
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+During PSCI power management operations, the EL3 Runtime Software may
+need to perform some bookkeeping, and PSCI library provides
+``spd_pm_ops_t`` callbacks for this purpose. These hooks must be
+populated and registered by using ``psci_register_spd_pm_hook()`` PSCI
+library interface.
+
+Typical bookkeeping during PSCI power management calls include save/restore
+of the EL3 Runtime Software context. Also if the EL3 Runtime Software makes
+use of secure interrupts, then these interrupts must also be managed
+appropriately during CPU power down/power up. Any secure interrupt targeted
+to the current CPU must be disabled or re-targeted to other running CPU prior
+to power down of the current CPU. During power up, these interrupt can be
+enabled/re-targeted back to the current CPU.
+
+.. code:: c
+
+        typedef struct spd_pm_ops {
+                void (*svc_on)(u_register_t target_cpu);
+                int32_t (*svc_off)(u_register_t __unused);
+                void (*svc_suspend)(u_register_t max_off_pwrlvl);
+                void (*svc_on_finish)(u_register_t __unused);
+                void (*svc_suspend_finish)(u_register_t max_off_pwrlvl);
+                int32_t (*svc_migrate)(u_register_t from_cpu, u_register_t to_cpu);
+                int32_t (*svc_migrate_info)(u_register_t *resident_cpu);
+                void (*svc_system_off)(void);
+                void (*svc_system_reset)(void);
+        } spd_pm_ops_t;
+
+A brief description of each callback is given below:
+
+-  svc_on, svc_off, svc_on_finish
+
+   The ``svc_on``, ``svc_off`` callbacks are called during PSCI_CPU_ON,
+   PSCI_CPU_OFF APIs respectively. The ``svc_on_finish`` is called when the
+   target CPU of PSCI_CPU_ON API powers up and executes the
+   ``psci_warmboot_entrypoint()`` PSCI library interface.
+
+-  svc_suspend, svc_suspend_finish
+
+   The ``svc_suspend`` callback is called during power down bu either
+   PSCI_SUSPEND or PSCI_SYSTEM_SUSPEND APIs. The ``svc_suspend_finish`` is
+   called when the CPU wakes up from suspend and executes the
+   ``psci_warmboot_entrypoint()`` PSCI library interface. The ``max_off_pwrlvl``
+   (first parameter) denotes the highest power domain level being powered down
+   to or woken up from suspend.
+
+-  svc_system_off, svc_system_reset
+
+   These callbacks are called during PSCI_SYSTEM_OFF and PSCI_SYSTEM_RESET
+   PSCI APIs respectively.
+
+-  svc_migrate_info
+
+   This callback is called in response to PSCI_MIGRATE_INFO_TYPE or
+   PSCI_MIGRATE_INFO_UP_CPU APIs. The return value of this callback must
+   correspond to the return value of PSCI_MIGRATE_INFO_TYPE API as described
+   in `PSCI spec`_. If the secure payload is a Uniprocessor (UP)
+   implementation, then it must update the mpidr of the CPU it is resident in
+   via ``resident_cpu`` (first argument). The updates to ``resident_cpu`` is
+   ignored if the secure payload is a multiprocessor (MP) implementation.
+
+-  svc_migrate
+
+   This callback is only relevant if the secure payload in EL3 Runtime
+   Software is a Uniprocessor (UP) implementation and supports migration from
+   the current CPU ``from_cpu`` (first argument) to another CPU ``to_cpu``
+   (second argument). This callback is called in response to PSCI_MIGRATE
+   API. This callback is never called if the secure payload is a
+   Multiprocessor (MP) implementation.
+
+CPU operations
+~~~~~~~~~~~~~~
+
+The CPU operations (cpu_ops) framework implement power down sequence specific
+to the CPU and the details of which can be found in the
+``CPU specific operations framework`` section of `Firmware Design`_. The TF-A
+tree implements the ``cpu_ops`` for various supported CPUs and the EL3 Runtime
+Software needs to include the required ``cpu_ops`` in its build. The start and
+end of the ``cpu_ops`` descriptors must be exported by the EL3 Runtime Software
+via the ``__CPU_OPS_START__`` and ``__CPU_OPS_END__`` linker symbols.
+
+The ``cpu_ops`` descriptors also include reset sequences and may include errata
+workarounds for the CPU. The EL3 Runtime Software can choose to call this
+during cold/warm reset if it does not implement its own reset sequence/errata
+workarounds.
+
+--------------
+
+*Copyright (c) 2016-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _PSCI spec: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+.. _SMCCC: https://silver.arm.com/download/ARM_and_AMBA_Architecture/AR570-DA-80002-r0p0-00rel0/ARM_DEN0028A_SMC_Calling_Convention.pdf
+.. _PSCI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+.. _PSCI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+.. _Porting Guide: ./porting-guide.rst
+.. _Firmware Design: ../design/firmware-design.rst
diff --git a/docs/getting_started/rt-svc-writers-guide.rst b/docs/getting_started/rt-svc-writers-guide.rst
new file mode 100644
index 0000000..6c17a1f
--- /dev/null
+++ b/docs/getting_started/rt-svc-writers-guide.rst
@@ -0,0 +1,308 @@
+EL3 Runtime Service Writer's Guide
+=====================================================
+
+Introduction
+------------
+
+This document describes how to add a runtime service to the EL3 Runtime
+Firmware component of Trusted Firmware-A (TF-A), BL31.
+
+Software executing in the normal world and in the trusted world at exception
+levels lower than EL3 will request runtime services using the Secure Monitor
+Call (SMC) instruction. These requests will follow the convention described in
+the SMC Calling Convention PDD (`SMCCC`_). The `SMCCC`_ assigns function
+identifiers to each SMC request and describes how arguments are passed and
+results are returned.
+
+SMC Functions are grouped together based on the implementor of the service, for
+example a subset of the Function IDs are designated as "OEM Calls" (see `SMCCC`_
+for full details). The EL3 runtime services framework in BL31 enables the
+independent implementation of services for each group, which are then compiled
+into the BL31 image. This simplifies the integration of common software from
+Arm to support `PSCI`_, Secure Monitor for a Trusted OS and SoC specific
+software. The common runtime services framework ensures that SMC Functions are
+dispatched to their respective service implementation - the `Firmware Design`_
+provides details of how this is achieved.
+
+The interface and operation of the runtime services depends heavily on the
+concepts and definitions described in the `SMCCC`_, in particular SMC Function
+IDs, Owning Entity Numbers (OEN), Fast and Standard calls, and the SMC32 and
+SMC64 calling conventions. Please refer to that document for a full explanation
+of these terms.
+
+Owning Entities, Call Types and Function IDs
+--------------------------------------------
+
+The SMC Function Identifier includes a OEN field. These values and their
+meaning are described in `SMCCC`_ and summarized in table 1 below. Some entities
+are allocated a range of of OENs. The OEN must be interpreted in conjunction
+with the SMC call type, which is either *Fast* or *Yielding*. Fast calls are
+uninterruptible whereas Yielding calls can be pre-empted. The majority of
+Owning Entities only have allocated ranges for Fast calls: Yielding calls are
+reserved exclusively for Trusted OS providers or for interoperability with
+legacy 32-bit software that predates the `SMCCC`_.
+
+::
+
+    Type       OEN     Service
+    Fast        0      Arm Architecture calls
+    Fast        1      CPU Service calls
+    Fast        2      SiP Service calls
+    Fast        3      OEM Service calls
+    Fast        4      Standard Service calls
+    Fast       5-47    Reserved for future use
+    Fast      48-49    Trusted Application calls
+    Fast      50-63    Trusted OS calls
+
+    Yielding   0- 1    Reserved for existing Armv7-A calls
+    Yielding   2-63    Trusted OS Standard Calls
+
+*Table 1: Service types and their corresponding Owning Entity Numbers*
+
+Each individual entity can allocate the valid identifiers within the entity
+range as they need - it is not necessary to coordinate with other entities of
+the same type. For example, two SoC providers can use the same Function ID
+within the SiP Service calls OEN range to mean different things - as these
+calls should be specific to the SoC. The Standard Runtime Calls OEN is used for
+services defined by Arm standards, such as `PSCI`_.
+
+The SMC Function ID also indicates whether the call has followed the SMC32
+calling convention, where all parameters are 32-bit, or the SMC64 calling
+convention, where the parameters are 64-bit. The framework identifies and
+rejects invalid calls that use the SMC64 calling convention but that originate
+from an AArch32 caller.
+
+The EL3 runtime services framework uses the call type and OEN to identify a
+specific handler for each SMC call, but it is expected that an individual
+handler will be responsible for all SMC Functions within a given service type.
+
+Getting started
+---------------
+
+TF-A has a `services`_ directory in the source tree under which
+each owning entity can place the implementation of its runtime service. The
+`PSCI`_ implementation is located here in the `lib/psci`_ directory.
+
+Runtime service sources will need to include the `runtime_svc.h`_ header file.
+
+Registering a runtime service
+-----------------------------
+
+A runtime service is registered using the ``DECLARE_RT_SVC()`` macro, specifying
+the name of the service, the range of OENs covered, the type of service and
+initialization and call handler functions.
+
+.. code:: c
+
+    #define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)
+
+-  ``_name`` is used to identify the data structure declared by this macro, and
+   is also used for diagnostic purposes
+
+-  ``_start`` and ``_end`` values must be based on the ``OEN_*`` values defined in
+   `smccc.h`_
+
+-  ``_type`` must be one of ``SMC_TYPE_FAST`` or ``SMC_TYPE_YIELD``
+
+-  ``_setup`` is the initialization function with the ``rt_svc_init`` signature:
+
+   .. code:: c
+
+       typedef int32_t (*rt_svc_init)(void);
+
+-  ``_smch`` is the SMC handler function with the ``rt_svc_handle`` signature:
+
+   .. code:: c
+
+       typedef uintptr_t (*rt_svc_handle_t)(uint32_t smc_fid,
+                                         u_register_t x1, u_register_t x2,
+                                         u_register_t x3, u_register_t x4,
+                                         void *cookie,
+                                         void *handle,
+                                         u_register_t flags);
+
+Details of the requirements and behavior of the two callbacks is provided in
+the following sections.
+
+During initialization the services framework validates each declared service
+to ensure that the following conditions are met:
+
+#. The ``_start`` OEN is not greater than the ``_end`` OEN
+#. The ``_end`` OEN does not exceed the maximum OEN value (63)
+#. The ``_type`` is one of ``SMC_TYPE_FAST`` or ``SMC_TYPE_YIELD``
+#. ``_setup`` and ``_smch`` routines have been specified
+
+`std_svc_setup.c`_ provides an example of registering a runtime service:
+
+.. code:: c
+
+    /* Register Standard Service Calls as runtime service */
+    DECLARE_RT_SVC(
+            std_svc,
+            OEN_STD_START,
+            OEN_STD_END,
+            SMC_TYPE_FAST,
+            std_svc_setup,
+            std_svc_smc_handler
+    );
+
+Initializing a runtime service
+------------------------------
+
+Runtime services are initialized once, during cold boot, by the primary CPU
+after platform and architectural initialization is complete. The framework
+performs basic validation of the declared service before calling
+the service initialization function (``_setup`` in the declaration). This
+function must carry out any essential EL3 initialization prior to receiving a
+SMC Function call via the handler function.
+
+On success, the initialization function must return ``0``. Any other return value
+will cause the framework to issue a diagnostic:
+
+::
+
+    Error initializing runtime service <name of the service>
+
+and then ignore the service - the system will continue to boot but SMC calls
+will not be passed to the service handler and instead return the *Unknown SMC
+Function ID* result ``0xFFFFFFFF``.
+
+If the system must not be allowed to proceed without the service, the
+initialization function must itself cause the firmware boot to be halted.
+
+If the service uses per-CPU data this must either be initialized for all CPUs
+during this call, or be done lazily when a CPU first issues an SMC call to that
+service.
+
+Handling runtime service requests
+---------------------------------
+
+SMC calls for a service are forwarded by the framework to the service's SMC
+handler function (``_smch`` in the service declaration). This function must have
+the following signature:
+
+.. code:: c
+
+    typedef uintptr_t (*rt_svc_handle_t)(uint32_t smc_fid,
+                                       u_register_t x1, u_register_t x2,
+                                       u_register_t x3, u_register_t x4,
+                                       void *cookie,
+                                       void *handle,
+                                       u_register_t flags);
+
+The handler is responsible for:
+
+#. Determining that ``smc_fid`` is a valid and supported SMC Function ID,
+   otherwise completing the request with the *Unknown SMC Function ID*:
+
+   .. code:: c
+
+       SMC_RET1(handle, SMC_UNK);
+
+#. Determining if the requested function is valid for the calling security
+   state. SMC Calls can be made from both the normal and trusted worlds and
+   the framework will forward all calls to the service handler.
+
+   The ``flags`` parameter to this function indicates the caller security state
+   in bit[0], where a value of ``1`` indicates a non-secure caller. The
+   ``is_caller_secure(flags)`` and ``is_caller_non_secure(flags)`` can be used to
+   test this condition.
+
+   If invalid, the request should be completed with:
+
+   .. code:: c
+
+       SMC_RET1(handle, SMC_UNK);
+
+#. Truncating parameters for calls made using the SMC32 calling convention.
+   Such calls can be determined by checking the CC field in bit[30] of the
+   ``smc_fid`` parameter, for example by using:
+
+   ::
+
+       if (GET_SMC_CC(smc_fid) == SMC_32) ...
+
+   For such calls, the upper bits of the parameters x1-x4 and the saved
+   parameters X5-X7 are UNDEFINED and must be explicitly ignored by the
+   handler. This can be done by truncating the values to a suitable 32-bit
+   integer type before use, for example by ensuring that functions defined
+   to handle individual SMC Functions use appropriate 32-bit parameters.
+
+#. Providing the service requested by the SMC Function, utilizing the
+   immediate parameters x1-x4 and/or the additional saved parameters X5-X7.
+   The latter can be retrieved using the ``SMC_GET_GP(handle, ref)`` function,
+   supplying the appropriate ``CTX_GPREG_Xn`` reference, e.g.
+
+   .. code:: c
+
+       uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+
+#. Implementing the standard SMC32 Functions that provide information about
+   the implementation of the service. These are the Call Count, Implementor
+   UID and Revision Details for each service documented in section 6 of the
+   `SMCCC`_.
+
+   TF-A expects owning entities to follow this recommendation.
+
+#. Returning the result to the caller. The `SMCCC`_ allows for up to 256 bits
+   of return value in SMC64 using X0-X3 and 128 bits in SMC32 using W0-W3. The
+   framework provides a family of macros to set the multi-register return
+   value and complete the handler:
+
+   .. code:: c
+
+       SMC_RET1(handle, x0);
+       SMC_RET2(handle, x0, x1);
+       SMC_RET3(handle, x0, x1, x2);
+       SMC_RET4(handle, x0, x1, x2, x3);
+
+The ``cookie`` parameter to the handler is reserved for future use and can be
+ignored. The ``handle`` is returned by the SMC handler - completion of the
+handler function must always be via one of the ``SMC_RETn()`` macros.
+
+.. note::
+   The PSCI and Test Secure-EL1 Payload Dispatcher services do not follow
+   all of the above requirements yet.
+
+Services that contain multiple sub-services
+-------------------------------------------
+
+It is possible that a single owning entity implements multiple sub-services. For
+example, the Standard calls service handles ``0x84000000``-``0x8400FFFF`` and
+``0xC4000000``-``0xC400FFFF`` functions. Within that range, the `PSCI`_ service
+handles the ``0x84000000``-``0x8400001F`` and ``0xC4000000``-``0xC400001F`` functions.
+In that respect, `PSCI`_ is a 'sub-service' of the Standard calls service. In
+future, there could be additional such sub-services in the Standard calls
+service which perform independent functions.
+
+In this situation it may be valuable to introduce a second level framework to
+enable independent implementation of sub-services. Such a framework might look
+very similar to the current runtime services framework, but using a different
+part of the SMC Function ID to identify the sub-service. TF-A does not provide
+such a framework at present.
+
+Secure-EL1 Payload Dispatcher service (SPD)
+-------------------------------------------
+
+Services that handle SMC Functions targeting a Trusted OS, Trusted Application,
+or other Secure-EL1 Payload are special. These services need to manage the
+Secure-EL1 context, provide the *Secure Monitor* functionality of switching
+between the normal and secure worlds, deliver SMC Calls through to Secure-EL1
+and generally manage the Secure-EL1 Payload through CPU power-state transitions.
+
+TODO: Provide details of the additional work required to implement a SPD and
+the BL31 support for these services. Or a reference to the document that will
+provide this information....
+
+--------------
+
+*Copyright (c) 2014-2018, Arm Limited and Contributors. All rights reserved.*
+
+.. _SMCCC: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+.. _Firmware Design: ../design/firmware-design.rst
+.. _services: ../../services
+.. _lib/psci: ../../lib/psci
+.. _runtime_svc.h: ../../include/common/runtime_svc.h
+.. _smccc.h: ../../include/lib/smccc.h
+.. _std_svc_setup.c: ../../services/std_svc/std_svc_setup.c
diff --git a/docs/getting_started/user-guide.rst b/docs/getting_started/user-guide.rst
new file mode 100644
index 0000000..b447f14
--- /dev/null
+++ b/docs/getting_started/user-guide.rst
@@ -0,0 +1,2183 @@
+User Guide
+==========
+
+This document describes how to build Trusted Firmware-A (TF-A) and run it with a
+tested set of other software components using defined configurations on the Juno
+Arm development platform and Arm Fixed Virtual Platform (FVP) models. It is
+possible to use other software components, configurations and platforms but that
+is outside the scope of this document.
+
+This document assumes that the reader has previous experience running a fully
+bootable Linux software stack on Juno or FVP using the prebuilt binaries and
+filesystems provided by `Linaro`_. Further information may be found in the
+`Linaro instructions`_. It also assumes that the user understands the role of
+the different software components required to boot a Linux system:
+
+-  Specific firmware images required by the platform (e.g. SCP firmware on Juno)
+-  Normal world bootloader (e.g. UEFI or U-Boot)
+-  Device tree
+-  Linux kernel image
+-  Root filesystem
+
+This document also assumes that the user is familiar with the `FVP models`_ and
+the different command line options available to launch the model.
+
+This document should be used in conjunction with the `Firmware Design`_.
+
+Host machine requirements
+-------------------------
+
+The minimum recommended machine specification for building the software and
+running the FVP models is a dual-core processor running at 2GHz with 12GB of
+RAM. For best performance, use a machine with a quad-core processor running at
+2.6GHz with 16GB of RAM.
+
+The software has been tested on Ubuntu 16.04 LTS (64-bit). Packages used for
+building the software were installed from that distribution unless otherwise
+specified.
+
+The software has also been built on Windows 7 Enterprise SP1, using CMD.EXE,
+Cygwin, and Msys (MinGW) shells, using version 5.3.1 of the GNU toolchain.
+
+Tools
+-----
+
+Install the required packages to build TF-A with the following command:
+
+.. code:: shell
+
+    sudo apt-get install device-tree-compiler build-essential gcc make git libssl-dev
+
+TF-A has been tested with Linaro Release 18.04.
+
+Download and install the AArch32 (arm-eabi) or AArch64 little-endian
+(aarch64-linux-gnu) GCC cross compiler. If you would like to use the latest
+features available, download GCC 8.3-2019.03 compiler from
+`arm Developer page`_. Otherwise, the `Linaro Release Notes`_ documents which
+version of the compiler to use for a given Linaro Release. Also, these
+`Linaro instructions`_ provide further guidance and a script, which can be used
+to download Linaro deliverables automatically.
+
+Optionally, TF-A can be built using clang version 4.0 or newer or Arm
+Compiler 6. See instructions below on how to switch the default compiler.
+
+In addition, the following optional packages and tools may be needed:
+
+-  ``device-tree-compiler`` (dtc) package if you need to rebuild the Flattened Device
+   Tree (FDT) source files (``.dts`` files) provided with this software. The
+   version of dtc must be 1.4.6 or above.
+
+-  For debugging, Arm `Development Studio 5 (DS-5)`_.
+
+-  To create and modify the diagram files included in the documentation, `Dia`_.
+   This tool can be found in most Linux distributions. Inkscape is needed to
+   generate the actual \*.png files.
+
+Getting the TF-A source code
+----------------------------
+
+Clone the repository from the Gerrit server. The project details may be found
+on the `arm-trusted-firmware-a project page`_. We recommend the "`Clone with
+commit-msg hook`" clone method, which will setup the git commit hook that
+automatically generates and inserts appropriate `Change-Id:` lines in your
+commit messages.
+
+Checking source code style
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Trusted Firmware follows the `Linux Coding Style`_ . When making changes to the
+source, for submission to the project, the source must be in compliance with
+this style guide.
+
+Additional, project-specific guidelines are defined in the `Trusted Firmware-A
+Coding Guidelines`_ document.
+
+To assist with coding style compliance, the project Makefile contains two
+targets which both utilise the `checkpatch.pl` script that ships with the Linux
+source tree. The project also defines certain *checkpatch* options in the
+``.checkpatch.conf`` file in the top-level directory.
+
+.. note::
+   Checkpatch errors will gate upstream merging of pull requests.
+   Checkpatch warnings will not gate merging but should be reviewed and fixed if
+   possible.
+
+To check the entire source tree, you must first download copies of
+``checkpatch.pl``, ``spelling.txt`` and ``const_structs.checkpatch`` available
+in the `Linux master tree`_ *scripts* directory, then set the ``CHECKPATCH``
+environment variable to point to ``checkpatch.pl`` (with the other 2 files in
+the same directory) and build the `checkcodebase` target:
+
+.. code:: shell
+
+    make CHECKPATCH=<path-to-linux>/linux/scripts/checkpatch.pl checkcodebase
+
+To just check the style on the files that differ between your local branch and
+the remote master, use:
+
+.. code:: shell
+
+    make CHECKPATCH=<path-to-linux>/linux/scripts/checkpatch.pl checkpatch
+
+If you wish to check your patch against something other than the remote master,
+set the ``BASE_COMMIT`` variable to your desired branch. By default, ``BASE_COMMIT``
+is set to ``origin/master``.
+
+Building TF-A
+-------------
+
+-  Before building TF-A, the environment variable ``CROSS_COMPILE`` must point
+   to the Linaro cross compiler.
+
+   For AArch64:
+
+   .. code:: shell
+
+       export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-linux-gnu-
+
+   For AArch32:
+
+   .. code:: shell
+
+       export CROSS_COMPILE=<path-to-aarch32-gcc>/bin/arm-eabi-
+
+   It is possible to build TF-A using Clang or Arm Compiler 6. To do so
+   ``CC`` needs to point to the clang or armclang binary, which will
+   also select the clang or armclang assembler. Be aware that the
+   GNU linker is used by default.  In case of being needed the linker
+   can be overridden using the ``LD`` variable. Clang linker version 6 is
+   known to work with TF-A.
+
+   In both cases ``CROSS_COMPILE`` should be set as described above.
+
+   Arm Compiler 6 will be selected when the base name of the path assigned
+   to ``CC`` matches the string 'armclang'.
+
+   For AArch64 using Arm Compiler 6:
+
+   .. code:: shell
+
+       export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-linux-gnu-
+       make CC=<path-to-armclang>/bin/armclang PLAT=<platform> all
+
+   Clang will be selected when the base name of the path assigned to ``CC``
+   contains the string 'clang'. This is to allow both clang and clang-X.Y
+   to work.
+
+   For AArch64 using clang:
+
+   .. code:: shell
+
+       export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-linux-gnu-
+       make CC=<path-to-clang>/bin/clang PLAT=<platform> all
+
+-  Change to the root directory of the TF-A source tree and build.
+
+   For AArch64:
+
+   .. code:: shell
+
+       make PLAT=<platform> all
+
+   For AArch32:
+
+   .. code:: shell
+
+       make PLAT=<platform> ARCH=aarch32 AARCH32_SP=sp_min all
+
+   Notes:
+
+   -  If ``PLAT`` is not specified, ``fvp`` is assumed by default. See the
+      `Summary of build options`_ for more information on available build
+      options.
+
+   -  (AArch32 only) Currently only ``PLAT=fvp`` is supported.
+
+   -  (AArch32 only) ``AARCH32_SP`` is the AArch32 EL3 Runtime Software and it
+      corresponds to the BL32 image. A minimal ``AARCH32_SP``, sp_min, is
+      provided by TF-A to demonstrate how PSCI Library can be integrated with
+      an AArch32 EL3 Runtime Software. Some AArch32 EL3 Runtime Software may
+      include other runtime services, for example Trusted OS services. A guide
+      to integrate PSCI library with AArch32 EL3 Runtime Software can be found
+      `here`_.
+
+   -  (AArch64 only) The TSP (Test Secure Payload), corresponding to the BL32
+      image, is not compiled in by default. Refer to the
+      `Building the Test Secure Payload`_ section below.
+
+   -  By default this produces a release version of the build. To produce a
+      debug version instead, refer to the "Debugging options" section below.
+
+   -  The build process creates products in a ``build`` directory tree, building
+      the objects and binaries for each boot loader stage in separate
+      sub-directories. The following boot loader binary files are created
+      from the corresponding ELF files:
+
+      -  ``build/<platform>/<build-type>/bl1.bin``
+      -  ``build/<platform>/<build-type>/bl2.bin``
+      -  ``build/<platform>/<build-type>/bl31.bin`` (AArch64 only)
+      -  ``build/<platform>/<build-type>/bl32.bin`` (mandatory for AArch32)
+
+      where ``<platform>`` is the name of the chosen platform and ``<build-type>``
+      is either ``debug`` or ``release``. The actual number of images might differ
+      depending on the platform.
+
+-  Build products for a specific build variant can be removed using:
+
+   .. code:: shell
+
+       make DEBUG=<D> PLAT=<platform> clean
+
+   ... where ``<D>`` is ``0`` or ``1``, as specified when building.
+
+   The build tree can be removed completely using:
+
+   .. code:: shell
+
+       make realclean
+
+Summary of build options
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The TF-A build system supports the following build options. Unless mentioned
+otherwise, these options are expected to be specified at the build command
+line and are not to be modified in any component makefiles. Note that the
+build system doesn't track dependency for build options. Therefore, if any of
+the build options are changed from a previous build, a clean build must be
+performed.
+
+Common build options
+^^^^^^^^^^^^^^^^^^^^
+
+-  ``AARCH32_INSTRUCTION_SET``: Choose the AArch32 instruction set that the
+   compiler should use. Valid values are T32 and A32. It defaults to T32 due to
+   code having a smaller resulting size.
+
+-  ``AARCH32_SP`` : Choose the AArch32 Secure Payload component to be built as
+   as the BL32 image when ``ARCH=aarch32``. The value should be the path to the
+   directory containing the SP source, relative to the ``bl32/``; the directory
+   is expected to contain a makefile called ``<aarch32_sp-value>.mk``.
+
+-  ``ARCH`` : Choose the target build architecture for TF-A. It can take either
+   ``aarch64`` or ``aarch32`` as values. By default, it is defined to
+   ``aarch64``.
+
+-  ``ARM_ARCH_MAJOR``: The major version of Arm Architecture to target when
+   compiling TF-A. Its value must be numeric, and defaults to 8 . See also,
+   *Armv8 Architecture Extensions* and *Armv7 Architecture Extensions* in
+   `Firmware Design`_.
+
+-  ``ARM_ARCH_MINOR``: The minor version of Arm Architecture to target when
+   compiling TF-A. Its value must be a numeric, and defaults to 0. See also,
+   *Armv8 Architecture Extensions* in `Firmware Design`_.
+
+-  ``BL2``: This is an optional build option which specifies the path to BL2
+   image for the ``fip`` target. In this case, the BL2 in the TF-A will not be
+   built.
+
+-  ``BL2U``: This is an optional build option which specifies the path to
+   BL2U image. In this case, the BL2U in TF-A will not be built.
+
+-  ``BL2_AT_EL3``: This is an optional build option that enables the use of
+   BL2 at EL3 execution level.
+
+-  ``BL2_IN_XIP_MEM``: In some use-cases BL2 will be stored in eXecute In Place
+   (XIP) memory, like BL1. In these use-cases, it is necessary to initialize
+   the RW sections in RAM, while leaving the RO sections in place. This option
+   enable this use-case. For now, this option is only supported when BL2_AT_EL3
+   is set to '1'.
+
+-  ``BL31``: This is an optional build option which specifies the path to
+   BL31 image for the ``fip`` target. In this case, the BL31 in TF-A will not
+   be built.
+
+-  ``BL31_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the
+   file that contains the BL31 private key in PEM format. If ``SAVE_KEYS=1``,
+   this file name will be used to save the key.
+
+-  ``BL32``: This is an optional build option which specifies the path to
+   BL32 image for the ``fip`` target. In this case, the BL32 in TF-A will not
+   be built.
+
+-  ``BL32_EXTRA1``: This is an optional build option which specifies the path to
+   Trusted OS Extra1 image for the  ``fip`` target.
+
+-  ``BL32_EXTRA2``: This is an optional build option which specifies the path to
+   Trusted OS Extra2 image for the ``fip`` target.
+
+-  ``BL32_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the
+   file that contains the BL32 private key in PEM format. If ``SAVE_KEYS=1``,
+   this file name will be used to save the key.
+
+-  ``BL33``: Path to BL33 image in the host file system. This is mandatory for
+   ``fip`` target in case TF-A BL2 is used.
+
+-  ``BL33_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the
+   file that contains the BL33 private key in PEM format. If ``SAVE_KEYS=1``,
+   this file name will be used to save the key.
+
+-  ``BRANCH_PROTECTION``: Numeric value to enable ARMv8.3 Pointer Authentication
+   and ARMv8.5 Branch Target Identification support for TF-A BL images themselves.
+   If enabled, it is needed to use a compiler that supports the option
+   ``-mbranch-protection``. Selects the branch protection features to use:
+-  0: Default value turns off all types of branch protection
+-  1: Enables all types of branch protection features
+-  2: Return address signing to its standard level
+-  3: Extend the signing to include leaf functions
+
+   The table below summarizes ``BRANCH_PROTECTION`` values, GCC compilation options
+   and resulting PAuth/BTI features.
+
+   +-------+--------------+-------+-----+
+   | Value |  GCC option  | PAuth | BTI |
+   +=======+==============+=======+=====+
+   |   0   |     none     |   N   |  N  |
+   +-------+--------------+-------+-----+
+   |   1   |   standard   |   Y   |  Y  |
+   +-------+--------------+-------+-----+
+   |   2   |   pac-ret    |   Y   |  N  |
+   +-------+--------------+-------+-----+
+   |   3   | pac-ret+leaf |   Y   |  N  |
+   +-------+--------------+-------+-----+
+
+   This option defaults to 0 and this is an experimental feature.
+   Note that Pointer Authentication is enabled for Non-secure world
+   irrespective of the value of this option if the CPU supports it.
+
+-  ``BUILD_MESSAGE_TIMESTAMP``: String used to identify the time and date of the
+   compilation of each build. It must be set to a C string (including quotes
+   where applicable). Defaults to a string that contains the time and date of
+   the compilation.
+
+-  ``BUILD_STRING``: Input string for VERSION_STRING, which allows the TF-A
+   build to be uniquely identified. Defaults to the current git commit id.
+
+-  ``CFLAGS``: Extra user options appended on the compiler's command line in
+   addition to the options set by the build system.
+
+-  ``COLD_BOOT_SINGLE_CPU``: This option indicates whether the platform may
+   release several CPUs out of reset. It can take either 0 (several CPUs may be
+   brought up) or 1 (only one CPU will ever be brought up during cold reset).
+   Default is 0. If the platform always brings up a single CPU, there is no
+   need to distinguish between primary and secondary CPUs and the boot path can
+   be optimised. The ``plat_is_my_cpu_primary()`` and
+   ``plat_secondary_cold_boot_setup()`` platform porting interfaces do not need
+   to be implemented in this case.
+
+-  ``CRASH_REPORTING``: A non-zero value enables a console dump of processor
+   register state when an unexpected exception occurs during execution of
+   BL31. This option defaults to the value of ``DEBUG`` - i.e. by default
+   this is only enabled for a debug build of the firmware.
+
+-  ``CREATE_KEYS``: This option is used when ``GENERATE_COT=1``. It tells the
+   certificate generation tool to create new keys in case no valid keys are
+   present or specified. Allowed options are '0' or '1'. Default is '1'.
+
+-  ``CTX_INCLUDE_AARCH32_REGS`` : Boolean option that, when set to 1, will cause
+   the AArch32 system registers to be included when saving and restoring the
+   CPU context. The option must be set to 0 for AArch64-only platforms (that
+   is on hardware that does not implement AArch32, or at least not at EL1 and
+   higher ELs). Default value is 1.
+
+-  ``CTX_INCLUDE_FPREGS``: Boolean option that, when set to 1, will cause the FP
+   registers to be included when saving and restoring the CPU context. Default
+   is 0.
+
+-  ``CTX_INCLUDE_PAUTH_REGS``: Boolean option that, when set to 1, enables
+   Pointer Authentication for Secure world. This will cause the ARMv8.3-PAuth
+   registers to be included when saving and restoring the CPU context as
+   part of world switch. Default value is 0 and this is an experimental feature.
+   Note that Pointer Authentication is enabled for Non-secure world irrespective
+   of the value of this flag if the CPU supports it.
+
+-  ``DEBUG``: Chooses between a debug and release build. It can take either 0
+   (release) or 1 (debug) as values. 0 is the default.
+
+-  ``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.
+
+-  ``DYN_DISABLE_AUTH``: Provides the capability to dynamically disable Trusted
+   Board Boot authentication at runtime. This option is meant to be enabled only
+   for development platforms. ``TRUSTED_BOARD_BOOT`` flag must be set if this
+   flag has to be enabled. 0 is the default.
+
+-  ``E``: Boolean option to make warnings into errors. Default is 1.
+
+-  ``EL3_PAYLOAD_BASE``: This option enables booting an EL3 payload instead of
+   the normal boot flow. It must specify the entry point address of the EL3
+   payload. Please refer to the "Booting an EL3 payload" section for more
+   details.
+
+-  ``ENABLE_AMU``: Boolean option to enable Activity Monitor Unit extensions.
+   This is an optional architectural feature available on v8.4 onwards. Some
+   v8.2 implementations also implement an AMU and this option can be used to
+   enable this feature on those systems as well. Default is 0.
+
+-  ``ENABLE_ASSERTIONS``: This option controls whether or not calls to ``assert()``
+   are compiled out. For debug builds, this option defaults to 1, and calls to
+   ``assert()`` are left in place. For release builds, this option defaults to 0
+   and calls to ``assert()`` function are compiled out. This option can be set
+   independently of ``DEBUG``. It can also be used to hide any auxiliary code
+   that is only required for the assertion and does not fit in the assertion
+   itself.
+
+-  ``ENABLE_BACKTRACE``: This option controls whether to enables backtrace
+   dumps or not. It is supported in both AArch64 and AArch32. However, in
+   AArch32 the format of the frame records are not defined in the AAPCS and they
+   are defined by the implementation. This implementation of backtrace only
+   supports the format used by GCC when T32 interworking is disabled. For this
+   reason enabling this option in AArch32 will force the compiler to only
+   generate A32 code. This option is enabled by default only in AArch64 debug
+   builds, but this behaviour can be overridden in each platform's Makefile or
+   in the build command line.
+
+-  ``ENABLE_MPAM_FOR_LOWER_ELS``: Boolean option to enable lower ELs to use MPAM
+   feature. MPAM is an optional Armv8.4 extension that enables various memory
+   system components and resources to define partitions; software running at
+   various ELs can assign themselves to desired partition to control their
+   performance aspects.
+
+   When this option is set to ``1``, EL3 allows lower ELs to access their own
+   MPAM registers without trapping into EL3. This option doesn't make use of
+   partitioning in EL3, however. Platform initialisation code should configure
+   and use partitions in EL3 as required. This option defaults to ``0``.
+
+-  ``ENABLE_PIE``: Boolean option to enable Position Independent Executable(PIE)
+   support within generic code in TF-A. This option is currently only supported
+   in BL31. Default is 0.
+
+-  ``ENABLE_PMF``: Boolean option to enable support for optional Performance
+   Measurement Framework(PMF). Default is 0.
+
+-  ``ENABLE_PSCI_STAT``: Boolean option to enable support for optional PSCI
+   functions ``PSCI_STAT_RESIDENCY`` and ``PSCI_STAT_COUNT``. Default is 0.
+   In the absence of an alternate stat collection backend, ``ENABLE_PMF`` must
+   be enabled. If ``ENABLE_PMF`` is set, the residency statistics are tracked in
+   software.
+
+-  ``ENABLE_RUNTIME_INSTRUMENTATION``: Boolean option to enable runtime
+   instrumentation which injects timestamp collection points into TF-A to
+   allow runtime performance to be measured. Currently, only PSCI is
+   instrumented. Enabling this option enables the ``ENABLE_PMF`` build option
+   as well. Default is 0.
+
+-  ``ENABLE_SPE_FOR_LOWER_ELS`` : Boolean option to enable Statistical Profiling
+   extensions. This is an optional architectural feature for AArch64.
+   The default is 1 but is automatically disabled when the target architecture
+   is AArch32.
+
+-  ``ENABLE_SPM`` : Boolean option to enable the Secure Partition Manager (SPM).
+   Refer to the `Secure Partition Manager Design guide`_ for more details about
+   this feature. Default is 0.
+
+-  ``ENABLE_SVE_FOR_NS``: Boolean option to enable Scalable Vector Extension
+   (SVE) for the Non-secure world only. SVE is an optional architectural feature
+   for AArch64. Note that when SVE is enabled for the Non-secure world, access
+   to SIMD and floating-point functionality from the Secure world is disabled.
+   This is to avoid corruption of the Non-secure world data in the Z-registers
+   which are aliased by the SIMD and FP registers. The build option is not
+   compatible with the ``CTX_INCLUDE_FPREGS`` build option, and will raise an
+   assert on platforms where SVE is implemented and ``ENABLE_SVE_FOR_NS`` set to
+   1. The default is 1 but is automatically disabled when the target
+   architecture is AArch32.
+
+-  ``ENABLE_STACK_PROTECTOR``: String option to enable the stack protection
+   checks in GCC. Allowed values are "all", "strong", "default" and "none". The
+   default value is set to "none". "strong" is the recommended stack protection
+   level if this feature is desired. "none" disables the stack protection. For
+   all values other than "none", the ``plat_get_stack_protector_canary()``
+   platform hook needs to be implemented. The value is passed as the last
+   component of the option ``-fstack-protector-$ENABLE_STACK_PROTECTOR``.
+
+-  ``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
+   APIs as error) or 0. The default is 0.
+
+-  ``EL3_EXCEPTION_HANDLING``: When set to ``1``, enable handling of exceptions
+   targeted at EL3. When set ``0`` (default), no exceptions are expected or
+   handled at EL3, and a panic will result. This is supported only for AArch64
+   builds.
+
+-  ``FAULT_INJECTION_SUPPORT``: ARMv8.4 extensions introduced support for fault
+   injection from lower ELs, and this build option enables lower ELs to use
+   Error Records accessed via System Registers to inject faults. This is
+   applicable only to AArch64 builds.
+
+   This feature is intended for testing purposes only, and is advisable to keep
+   disabled for production images.
+
+-  ``FIP_NAME``: This is an optional build option which specifies the FIP
+   filename for the ``fip`` target. Default is ``fip.bin``.
+
+-  ``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``.
+
+-  ``GENERATE_COT``: Boolean flag used to build and execute the ``cert_create``
+   tool to create certificates as per the Chain of Trust described in
+   `Trusted Board Boot`_. The build system then calls ``fiptool`` to
+   include the certificates in the FIP and FWU_FIP. Default value is '0'.
+
+   Specify both ``TRUSTED_BOARD_BOOT=1`` and ``GENERATE_COT=1`` to include support
+   for the Trusted Board Boot feature in the BL1 and BL2 images, to generate
+   the corresponding certificates, and to include those certificates in the
+   FIP and FWU_FIP.
+
+   Note that if ``TRUSTED_BOARD_BOOT=0`` and ``GENERATE_COT=1``, the BL1 and BL2
+   images will not include support for Trusted Board Boot. The FIP will still
+   include the corresponding certificates. This FIP can be used to verify the
+   Chain of Trust on the host machine through other mechanisms.
+
+   Note that if ``TRUSTED_BOARD_BOOT=1`` and ``GENERATE_COT=0``, the BL1 and BL2
+   images will include support for Trusted Board Boot, but the FIP and FWU_FIP
+   will not include the corresponding certificates, causing a boot failure.
+
+-  ``GICV2_G0_FOR_EL3``: Unlike GICv3, the GICv2 architecture doesn't have
+   inherent support for specific EL3 type interrupts. Setting this build option
+   to ``1`` assumes GICv2 *Group 0* interrupts are expected to target EL3, both
+   by `platform abstraction layer`__ and `Interrupt Management Framework`__.
+   This allows GICv2 platforms to enable features requiring EL3 interrupt type.
+   This also means that all GICv2 Group 0 interrupts are delivered to EL3, and
+   the Secure Payload interrupts needs to be synchronously handed over to Secure
+   EL1 for handling. The default value of this option is ``0``, which means the
+   Group 0 interrupts are assumed to be handled by Secure EL1.
+
+   .. __: `platform-interrupt-controller-API.rst`
+   .. __: `interrupt-framework-design.rst`
+
+-  ``HANDLE_EA_EL3_FIRST``: When set to ``1``, External Aborts and SError
+   Interrupts will be always trapped in EL3 i.e. in BL31 at runtime. When set to
+   ``0`` (default), these exceptions will be trapped in the current exception
+   level (or in EL1 if the current exception level is EL0).
+
+-  ``HW_ASSISTED_COHERENCY``: On most Arm systems to-date, platform-specific
+   software operations are required for CPUs to enter and exit coherency.
+   However, newer systems exist where CPUs' entry to and exit from coherency
+   is managed in hardware. Such systems require software to only initiate these
+   operations, and the rest is managed in hardware, minimizing active software
+   management. In such systems, this boolean option enables TF-A to carry out
+   build and run-time optimizations during boot and power management operations.
+   This option defaults to 0 and if it is enabled, then it implies
+   ``WARMBOOT_ENABLE_DCACHE_EARLY`` is also enabled.
+
+   If this flag is disabled while the platform which TF-A is compiled for
+   includes cores that manage coherency in hardware, then a compilation error is
+   generated. This is based on the fact that a system cannot have, at the same
+   time, cores that manage coherency in hardware and cores that don't. In other
+   words, a platform cannot have, at the same time, cores that require
+   ``HW_ASSISTED_COHERENCY=1`` and cores that require
+   ``HW_ASSISTED_COHERENCY=0``.
+
+   Note that, when ``HW_ASSISTED_COHERENCY`` is enabled, version 2 of
+   translation library (xlat tables v2) must be used; version 1 of translation
+   library is not supported.
+
+-  ``JUNO_AARCH32_EL3_RUNTIME``: This build flag enables you to execute EL3
+   runtime software in AArch32 mode, which is required to run AArch32 on Juno.
+   By default this flag is set to '0'. Enabling this flag builds BL1 and BL2 in
+   AArch64 and facilitates the loading of ``SP_MIN`` and BL33 as AArch32 executable
+   images.
+
+-  ``KEY_ALG``: This build flag enables the user to select the algorithm to be
+   used for generating the PKCS keys and subsequent signing of the certificate.
+   It accepts 3 values: ``rsa``, ``rsa_1_5`` and ``ecdsa``. The option
+   ``rsa_1_5`` is the legacy PKCS#1 RSA 1.5 algorithm which is not TBBR
+   compliant and is retained only for compatibility. The default value of this
+   flag is ``rsa`` which is the TBBR compliant PKCS#1 RSA 2.1 scheme.
+
+-  ``HASH_ALG``: This build flag enables the user to select the secure hash
+   algorithm. It accepts 3 values: ``sha256``, ``sha384`` and ``sha512``.
+   The default value of this flag is ``sha256``.
+
+-  ``LDFLAGS``: Extra user options appended to the linkers' command line in
+   addition to the one set by the build system.
+
+-  ``LOG_LEVEL``: Chooses the log level, which controls the amount of console log
+   output compiled into the build. This should be one of the following:
+
+   ::
+
+       0  (LOG_LEVEL_NONE)
+       10 (LOG_LEVEL_ERROR)
+       20 (LOG_LEVEL_NOTICE)
+       30 (LOG_LEVEL_WARNING)
+       40 (LOG_LEVEL_INFO)
+       50 (LOG_LEVEL_VERBOSE)
+
+   All log output up to and including the selected log level is compiled into
+   the build. The default value is 40 in debug builds and 20 in release builds.
+
+-  ``NON_TRUSTED_WORLD_KEY``: This option is used when ``GENERATE_COT=1``. It
+   specifies the file that contains the Non-Trusted World private key in PEM
+   format. If ``SAVE_KEYS=1``, this file name will be used to save the key.
+
+-  ``NS_BL2U``: Path to NS_BL2U image in the host file system. This image is
+   optional. It is only needed if the platform makefile specifies that it
+   is required in order to build the ``fwu_fip`` target.
+
+-  ``NS_TIMER_SWITCH``: Enable save and restore for non-secure timer register
+   contents upon world switch. It can take either 0 (don't save and restore) or
+   1 (do save and restore). 0 is the default. An SPD may set this to 1 if it
+   wants the timer registers to be saved and restored.
+
+-  ``OVERRIDE_LIBC``: This option allows platforms to override the default libc
+   for the BL image. It can be either 0 (include) or 1 (remove). The default
+   value is 0.
+
+-  ``PL011_GENERIC_UART``: Boolean option to indicate the PL011 driver that
+   the underlying hardware is not a full PL011 UART but a minimally compliant
+   generic UART, which is a subset of the PL011. The driver will not access
+   any register that is not part of the SBSA generic UART specification.
+   Default value is 0 (a full PL011 compliant UART is present).
+
+-  ``PLAT``: Choose a platform to build TF-A for. The chosen platform name
+   must be subdirectory of any depth under ``plat/``, and must contain a
+   platform makefile named ``platform.mk``. For example, to build TF-A for the
+   Arm Juno board, select PLAT=juno.
+
+-  ``PRELOADED_BL33_BASE``: This option enables booting a preloaded BL33 image
+   instead of the normal boot flow. When defined, it must specify the entry
+   point address for the preloaded BL33 image. This option is incompatible with
+   ``EL3_PAYLOAD_BASE``. If both are defined, ``EL3_PAYLOAD_BASE`` has priority
+   over ``PRELOADED_BL33_BASE``.
+
+-  ``PROGRAMMABLE_RESET_ADDRESS``: This option indicates whether the reset
+   vector address can be programmed or is fixed on the platform. It can take
+   either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a
+   programmable reset address, it is expected that a CPU will start executing
+   code directly at the right address, both on a cold and warm reset. In this
+   case, there is no need to identify the entrypoint on boot and the boot path
+   can be optimised. The ``plat_get_my_entrypoint()`` platform porting interface
+   does not need to be implemented in this case.
+
+-  ``PSCI_EXTENDED_STATE_ID``: As per PSCI1.0 Specification, there are 2 formats
+   possible for the PSCI power-state parameter: original and extended State-ID
+   formats. This flag if set to 1, configures the generic PSCI layer to use the
+   extended format. The default value of this flag is 0, which means by default
+   the original power-state format is used by the PSCI implementation. This flag
+   should be specified by the platform makefile and it governs the return value
+   of PSCI_FEATURES API for CPU_SUSPEND smc function id. When this option is
+   enabled on Arm platforms, the option ``ARM_RECOM_STATE_ID_ENC`` needs to be
+   set to 1 as well.
+
+-  ``RAS_EXTENSION``: When set to ``1``, enable Armv8.2 RAS features. RAS features
+   are an optional extension for pre-Armv8.2 CPUs, but are mandatory for Armv8.2
+   or later CPUs.
+
+   When ``RAS_EXTENSION`` is set to ``1``, ``HANDLE_EA_EL3_FIRST`` must also be
+   set to ``1``.
+
+   This option is disabled by default.
+
+-  ``RESET_TO_BL31``: Enable BL31 entrypoint as the CPU reset vector instead
+   of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1
+   entrypoint) or 1 (CPU reset to BL31 entrypoint).
+   The default value is 0.
+
+-  ``RESET_TO_SP_MIN``: SP_MIN is the minimal AArch32 Secure Payload provided
+   in TF-A. This flag configures SP_MIN entrypoint as the CPU reset vector
+   instead of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1
+   entrypoint) or 1 (CPU reset to SP_MIN entrypoint). The default value is 0.
+
+-  ``ROT_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the
+   file that contains the ROT private key in PEM format. If ``SAVE_KEYS=1``, this
+   file name will be used to save the key.
+
+-  ``SAVE_KEYS``: This option is used when ``GENERATE_COT=1``. It tells the
+   certificate generation tool to save the keys used to establish the Chain of
+   Trust. Allowed options are '0' or '1'. Default is '0' (do not save).
+
+-  ``SCP_BL2``: Path to SCP_BL2 image in the host file system. This image is optional.
+   If a SCP_BL2 image is present then this option must be passed for the ``fip``
+   target.
+
+-  ``SCP_BL2_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the
+   file that contains the SCP_BL2 private key in PEM format. If ``SAVE_KEYS=1``,
+   this file name will be used to save the key.
+
+-  ``SCP_BL2U``: Path to SCP_BL2U image in the host file system. This image is
+   optional. It is only needed if the platform makefile specifies that it
+   is required in order to build the ``fwu_fip`` target.
+
+-  ``SDEI_SUPPORT``: Setting this to ``1`` enables support for Software
+   Delegated Exception Interface to BL31 image. This defaults to ``0``.
+
+   When set to ``1``, the build option ``EL3_EXCEPTION_HANDLING`` must also be
+   set to ``1``.
+
+-  ``SEPARATE_CODE_AND_RODATA``: Whether code and read-only data should be
+   isolated on separate memory pages. This is a trade-off between security and
+   memory usage. See "Isolating code and read-only data on separate memory
+   pages" section in `Firmware Design`_. This flag is disabled by default and
+   affects all BL images.
+
+-  ``SPD``: Choose a Secure Payload Dispatcher component to be built into TF-A.
+   This build option is only valid if ``ARCH=aarch64``. The value should be
+   the path to the directory containing the SPD source, relative to
+   ``services/spd/``; the directory is expected to contain a makefile called
+   ``<spd-value>.mk``.
+
+-  ``SPIN_ON_BL1_EXIT``: This option introduces an infinite loop in BL1. It can
+   take either 0 (no loop) or 1 (add a loop). 0 is the default. This loop stops
+   execution in BL1 just before handing over to BL31. At this point, all
+   firmware images have been loaded in memory, and the MMU and caches are
+   turned off. Refer to the "Debugging options" section for more details.
+
+-  ``SP_MIN_WITH_SECURE_FIQ``: Boolean flag to indicate the SP_MIN handles
+   secure interrupts (caught through the FIQ line). Platforms can enable
+   this directive if they need to handle such interruption. When enabled,
+   the FIQ are handled in monitor mode and non secure world is not allowed
+   to mask these events. Platforms that enable FIQ handling in SP_MIN shall
+   implement the api ``sp_min_plat_fiq_handler()``. The default value is 0.
+
+-  ``TRUSTED_BOARD_BOOT``: Boolean flag to include support for the Trusted Board
+   Boot feature. When set to '1', BL1 and BL2 images include support to load
+   and verify the certificates and images in a FIP, and BL1 includes support
+   for the Firmware Update. The default value is '0'. Generation and inclusion
+   of certificates in the FIP and FWU_FIP depends upon the value of the
+   ``GENERATE_COT`` option.
+
+   .. warning::
+      This option depends on ``CREATE_KEYS`` to be enabled. If the keys
+      already exist in disk, they will be overwritten without further notice.
+
+-  ``TRUSTED_WORLD_KEY``: This option is used when ``GENERATE_COT=1``. It
+   specifies the file that contains the Trusted World private key in PEM
+   format. If ``SAVE_KEYS=1``, this file name will be used to save the key.
+
+-  ``TSP_INIT_ASYNC``: Choose BL32 initialization method as asynchronous or
+   synchronous, (see "Initializing a BL32 Image" section in
+   `Firmware Design`_). It can take the value 0 (BL32 is initialized using
+   synchronous method) or 1 (BL32 is initialized using asynchronous method).
+   Default is 0.
+
+-  ``TSP_NS_INTR_ASYNC_PREEMPT``: A non zero value enables the interrupt
+   routing model which routes non-secure interrupts asynchronously from TSP
+   to EL3 causing immediate preemption of TSP. The EL3 is responsible
+   for saving and restoring the TSP context in this routing model. The
+   default routing model (when the value is 0) is to route non-secure
+   interrupts to TSP allowing it to save its context and hand over
+   synchronously to EL3 via an SMC.
+
+   .. note::
+      When ``EL3_EXCEPTION_HANDLING`` is ``1``, ``TSP_NS_INTR_ASYNC_PREEMPT``
+      must also be set to ``1``.
+
+-  ``USE_ARM_LINK``: This flag determines whether to enable support for ARM
+   linker. When the ``LINKER`` build variable points to the armlink linker,
+   this flag is enabled automatically. To enable support for armlink, platforms
+   will have to provide a scatter file for the BL image. Currently, Tegra
+   platforms use the armlink support to compile BL3-1 images.
+
+-  ``USE_COHERENT_MEM``: This flag determines whether to include the coherent
+   memory region in the BL memory map or not (see "Use of Coherent memory in
+   TF-A" section in `Firmware Design`_). It can take the value 1
+   (Coherent memory region is included) or 0 (Coherent memory region is
+   excluded). Default is 1.
+
+-  ``USE_ROMLIB``: This flag determines whether library at ROM will be used.
+   This feature creates a library of functions to be placed in ROM and thus
+   reduces SRAM usage. Refer to `Library at ROM`_ for further details. Default
+   is 0.
+
+-  ``V``: Verbose build. If assigned anything other than 0, the build commands
+   are printed. Default is 0.
+
+-  ``VERSION_STRING``: String used in the log output for each TF-A image.
+   Defaults to a string formed by concatenating the version number, build type
+   and build string.
+
+-  ``W``: Warning level. Some compiler warning options of interest have been
+   regrouped and put in the root Makefile. This flag can take the values 0 to 3,
+   each level enabling more warning options. Default is 0.
+
+-  ``WARMBOOT_ENABLE_DCACHE_EARLY`` : Boolean option to enable D-cache early on
+   the CPU after warm boot. This is applicable for platforms which do not
+   require interconnect programming to enable cache coherency (eg: single
+   cluster platforms). If this option is enabled, then warm boot path
+   enables D-caches immediately after enabling MMU. This option defaults to 0.
+
+Arm development platform specific build options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``ARM_BL31_IN_DRAM``: Boolean option to select loading of BL31 in TZC secured
+   DRAM. By default, BL31 is in the secure SRAM. Set this flag to 1 to load
+   BL31 in TZC secured DRAM. If TSP is present, then setting this option also
+   sets the TSP location to DRAM and ignores the ``ARM_TSP_RAM_LOCATION`` build
+   flag.
+
+-  ``ARM_CONFIG_CNTACR``: boolean option to unlock access to the ``CNTBase<N>``
+   frame registers by setting the ``CNTCTLBase.CNTACR<N>`` register bits. The
+   frame number ``<N>`` is defined by ``PLAT_ARM_NSTIMER_FRAME_ID``, which should
+   match the frame used by the Non-Secure image (normally the Linux kernel).
+   Default is true (access to the frame is allowed).
+
+-  ``ARM_DISABLE_TRUSTED_WDOG``: boolean option to disable the Trusted Watchdog.
+   By default, Arm platforms use a watchdog to trigger a system reset in case
+   an error is encountered during the boot process (for example, when an image
+   could not be loaded or authenticated). The watchdog is enabled in the early
+   platform setup hook at BL1 and disabled in the BL1 prepare exit hook. The
+   Trusted Watchdog may be disabled at build time for testing or development
+   purposes.
+
+-  ``ARM_LINUX_KERNEL_AS_BL33``: The Linux kernel expects registers x0-x3 to
+   have specific values at boot. This boolean option allows the Trusted Firmware
+   to have a Linux kernel image as BL33 by preparing the registers to these
+   values before jumping to BL33. This option defaults to 0 (disabled). For
+   AArch64 ``RESET_TO_BL31`` and for AArch32 ``RESET_TO_SP_MIN`` must be 1 when
+   using it. If this option is set to 1, ``ARM_PRELOADED_DTB_BASE`` must be set
+   to the location of a device tree blob (DTB) already loaded in memory. The
+   Linux Image address must be specified using the ``PRELOADED_BL33_BASE``
+   option.
+
+-  ``ARM_PLAT_MT``: This flag determines whether the Arm platform layer has to
+   cater for the multi-threading ``MT`` bit when accessing MPIDR. When this flag
+   is set, the functions which deal with MPIDR assume that the ``MT`` bit in
+   MPIDR is set and access the bit-fields in MPIDR accordingly. Default value of
+   this flag is 0. Note that this option is not used on FVP platforms.
+
+-  ``ARM_RECOM_STATE_ID_ENC``: The PSCI1.0 specification recommends an encoding
+   for the construction of composite state-ID in the power-state parameter.
+   The existing PSCI clients currently do not support this encoding of
+   State-ID yet. Hence this flag is used to configure whether to use the
+   recommended State-ID encoding or not. The default value of this flag is 0,
+   in which case the platform is configured to expect NULL in the State-ID
+   field of power-state parameter.
+
+-  ``ARM_ROTPK_LOCATION``: used when ``TRUSTED_BOARD_BOOT=1``. It specifies the
+   location of the ROTPK hash returned by the function ``plat_get_rotpk_info()``
+   for Arm platforms. Depending on the selected option, the proper private key
+   must be specified using the ``ROT_KEY`` option when building the Trusted
+   Firmware. This private key will be used by the certificate generation tool
+   to sign the BL2 and Trusted Key certificates. Available options for
+   ``ARM_ROTPK_LOCATION`` are:
+
+   -  ``regs`` : return the ROTPK hash stored in the Trusted root-key storage
+      registers. The private key corresponding to this ROTPK hash is not
+      currently available.
+   -  ``devel_rsa`` : return a development public key hash embedded in the BL1
+      and BL2 binaries. This hash has been obtained from the RSA public key
+      ``arm_rotpk_rsa.der``, located in ``plat/arm/board/common/rotpk``. To use
+      this option, ``arm_rotprivk_rsa.pem`` must be specified as ``ROT_KEY`` when
+      creating the certificates.
+   -  ``devel_ecdsa`` : return a development public key hash embedded in the BL1
+      and BL2 binaries. This hash has been obtained from the ECDSA public key
+      ``arm_rotpk_ecdsa.der``, located in ``plat/arm/board/common/rotpk``. To use
+      this option, ``arm_rotprivk_ecdsa.pem`` must be specified as ``ROT_KEY``
+      when creating the certificates.
+
+-  ``ARM_TSP_RAM_LOCATION``: location of the TSP binary. Options:
+
+   -  ``tsram`` : Trusted SRAM (default option when TBB is not enabled)
+   -  ``tdram`` : Trusted DRAM (if available)
+   -  ``dram`` : Secure region in DRAM (default option when TBB is enabled,
+      configured by the TrustZone controller)
+
+-  ``ARM_XLAT_TABLES_LIB_V1``: boolean option to compile TF-A with version 1
+   of the translation tables library instead of version 2. It is set to 0 by
+   default, which selects version 2.
+
+-  ``ARM_CRYPTOCELL_INTEG`` : bool option to enable TF-A to invoke Arm®
+   TrustZone® CryptoCell functionality for Trusted Board Boot on capable Arm
+   platforms. If this option is specified, then the path to the CryptoCell
+   SBROM library must be specified via ``CCSBROM_LIB_PATH`` flag.
+
+For a better understanding of these options, the Arm development platform memory
+map is explained in the `Firmware Design`_.
+
+Arm CSS platform specific build options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``CSS_DETECT_PRE_1_7_0_SCP``: Boolean flag to detect SCP version
+   incompatibility. Version 1.7.0 of the SCP firmware made a non-backwards
+   compatible change to the MTL protocol, used for AP/SCP communication.
+   TF-A no longer supports earlier SCP versions. If this option is set to 1
+   then TF-A will detect if an earlier version is in use. Default is 1.
+
+-  ``CSS_LOAD_SCP_IMAGES``: Boolean flag, which when set, adds SCP_BL2 and
+   SCP_BL2U to the FIP and FWU_FIP respectively, and enables them to be loaded
+   during boot. Default is 1.
+
+-  ``CSS_USE_SCMI_SDS_DRIVER``: Boolean flag which selects SCMI/SDS drivers
+   instead of SCPI/BOM driver for communicating with the SCP during power
+   management operations and for SCP RAM Firmware transfer. If this option
+   is set to 1, then SCMI/SDS drivers will be used. Default is 0.
+
+Arm FVP platform specific build options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``FVP_CLUSTER_COUNT`` : Configures the cluster count to be used to
+   build the topology tree within TF-A. By default TF-A is configured for dual
+   cluster topology and this option can be used to override the default value.
+
+-  ``FVP_INTERCONNECT_DRIVER``: Selects the interconnect driver to be built. The
+   default interconnect driver depends on the value of ``FVP_CLUSTER_COUNT`` as
+   explained in the options below:
+
+   -  ``FVP_CCI`` : The CCI driver is selected. This is the default
+      if 0 < ``FVP_CLUSTER_COUNT`` <= 2.
+   -  ``FVP_CCN`` : The CCN driver is selected. This is the default
+      if ``FVP_CLUSTER_COUNT`` > 2.
+
+-  ``FVP_MAX_CPUS_PER_CLUSTER``: Sets the maximum number of CPUs implemented in
+   a single cluster.  This option defaults to 4.
+
+-  ``FVP_MAX_PE_PER_CPU``: Sets the maximum number of PEs implemented on any CPU
+   in the system. This option defaults to 1. Note that the build option
+   ``ARM_PLAT_MT`` doesn't have any effect on FVP platforms.
+
+-  ``FVP_USE_GIC_DRIVER`` : Selects the GIC driver to be built. Options:
+
+   -  ``FVP_GIC600`` : The GIC600 implementation of GICv3 is selected
+   -  ``FVP_GICV2`` : The GICv2 only driver is selected
+   -  ``FVP_GICV3`` : The GICv3 only driver is selected (default option)
+
+-  ``FVP_USE_SP804_TIMER`` : Use the SP804 timer instead of the Generic Timer
+   for functions that wait for an arbitrary time length (udelay and mdelay).
+   The default value is 0.
+
+-  ``FVP_HW_CONFIG_DTS`` : Specify the path to the DTS file to be compiled
+   to DTB and packaged in FIP as the HW_CONFIG. See `Firmware Design`_ for
+   details on HW_CONFIG. By default, this is initialized to a sensible DTS
+   file in ``fdts/`` folder depending on other build options. But some cases,
+   like shifted affinity format for MPIDR, cannot be detected at build time
+   and this option is needed to specify the appropriate DTS file.
+
+-  ``FVP_HW_CONFIG`` : Specify the path to the HW_CONFIG blob to be packaged in
+   FIP. See `Firmware Design`_ for details on HW_CONFIG. This option is
+   similar to the ``FVP_HW_CONFIG_DTS`` option, but it directly specifies the
+   HW_CONFIG blob instead of the DTS file. This option is useful to override
+   the default HW_CONFIG selected by the build system.
+
+ARM JUNO platform specific build options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``JUNO_TZMP1`` : Boolean option to configure Juno to be used for TrustZone
+   Media Protection (TZ-MP1). Default value of this flag is 0.
+
+Debugging options
+~~~~~~~~~~~~~~~~~
+
+To compile a debug version and make the build more verbose use
+
+.. code:: shell
+
+    make PLAT=<platform> DEBUG=1 V=1 all
+
+AArch64 GCC uses DWARF version 4 debugging symbols by default. Some tools (for
+example DS-5) might not support this and may need an older version of DWARF
+symbols to be emitted by GCC. This can be achieved by using the
+``-gdwarf-<version>`` flag, with the version being set to 2 or 3. Setting the
+version to 2 is recommended for DS-5 versions older than 5.16.
+
+When debugging logic problems it might also be useful to disable all compiler
+optimizations by using ``-O0``.
+
+.. warning::
+   Using ``-O0`` could cause output images to be larger and base addresses
+   might need to be recalculated (see the **Memory layout on Arm development
+   platforms** section in the `Firmware Design`_).
+
+Extra debug options can be passed to the build system by setting ``CFLAGS`` or
+``LDFLAGS``:
+
+.. code:: shell
+
+    CFLAGS='-O0 -gdwarf-2'                                     \
+    make PLAT=<platform> DEBUG=1 V=1 all
+
+Note that using ``-Wl,`` style compilation driver options in ``CFLAGS`` will be
+ignored as the linker is called directly.
+
+It is also possible to introduce an infinite loop to help in debugging the
+post-BL2 phase of TF-A. This can be done by rebuilding BL1 with the
+``SPIN_ON_BL1_EXIT=1`` build flag. Refer to the `Summary of build options`_
+section. In this case, the developer may take control of the target using a
+debugger when indicated by the console output. When using DS-5, the following
+commands can be used:
+
+::
+
+    # Stop target execution
+    interrupt
+
+    #
+    # Prepare your debugging environment, e.g. set breakpoints
+    #
+
+    # Jump over the debug loop
+    set var $AARCH64::$Core::$PC = $AARCH64::$Core::$PC + 4
+
+    # Resume execution
+    continue
+
+Building the Test Secure Payload
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The TSP is coupled with a companion runtime service in the BL31 firmware,
+called the TSPD. Therefore, if you intend to use the TSP, the BL31 image
+must be recompiled as well. For more information on SPs and SPDs, see the
+`Secure-EL1 Payloads and Dispatchers`_ section in the `Firmware Design`_.
+
+First clean the TF-A build directory to get rid of any previous BL31 binary.
+Then to build the TSP image use:
+
+.. code:: shell
+
+    make PLAT=<platform> SPD=tspd all
+
+An additional boot loader binary file is created in the ``build`` directory:
+
+::
+
+    build/<platform>/<build-type>/bl32.bin
+
+
+Building and using the FIP tool
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Firmware Image Package (FIP) is a packaging format used by TF-A to package
+firmware images in a single binary. The number and type of images that should
+be packed in a FIP is platform specific and may include TF-A images and other
+firmware images required by the platform. For example, most platforms require
+a BL33 image which corresponds to the normal world bootloader (e.g. UEFI or
+U-Boot).
+
+The TF-A build system provides the make target ``fip`` to create a FIP file
+for the specified platform using the FIP creation tool included in the TF-A
+project. Examples below show how to build a FIP file for FVP, packaging TF-A
+and BL33 images.
+
+For AArch64:
+
+.. code:: shell
+
+    make PLAT=fvp BL33=<path-to>/bl33.bin fip
+
+For AArch32:
+
+.. code:: shell
+
+    make PLAT=fvp ARCH=aarch32 AARCH32_SP=sp_min BL33=<path-to>/bl33.bin fip
+
+The resulting FIP may be found in:
+
+::
+
+    build/fvp/<build-type>/fip.bin
+
+For advanced operations on FIP files, it is also possible to independently build
+the tool and create or modify FIPs using this tool. To do this, follow these
+steps:
+
+It is recommended to remove old artifacts before building the tool:
+
+.. code:: shell
+
+    make -C tools/fiptool clean
+
+Build the tool:
+
+.. code:: shell
+
+    make [DEBUG=1] [V=1] fiptool
+
+The tool binary can be located in:
+
+::
+
+    ./tools/fiptool/fiptool
+
+Invoking the tool with ``help`` will print a help message with all available
+options.
+
+Example 1: create a new Firmware package ``fip.bin`` that contains BL2 and BL31:
+
+.. code:: shell
+
+    ./tools/fiptool/fiptool create \
+        --tb-fw build/<platform>/<build-type>/bl2.bin \
+        --soc-fw build/<platform>/<build-type>/bl31.bin \
+        fip.bin
+
+Example 2: view the contents of an existing Firmware package:
+
+.. code:: shell
+
+    ./tools/fiptool/fiptool info <path-to>/fip.bin
+
+Example 3: update the entries of an existing Firmware package:
+
+.. code:: shell
+
+    # Change the BL2 from Debug to Release version
+    ./tools/fiptool/fiptool update \
+        --tb-fw build/<platform>/release/bl2.bin \
+        build/<platform>/debug/fip.bin
+
+Example 4: unpack all entries from an existing Firmware package:
+
+.. code:: shell
+
+    # Images will be unpacked to the working directory
+    ./tools/fiptool/fiptool unpack <path-to>/fip.bin
+
+Example 5: remove an entry from an existing Firmware package:
+
+.. code:: shell
+
+    ./tools/fiptool/fiptool remove \
+        --tb-fw build/<platform>/debug/fip.bin
+
+Note that if the destination FIP file exists, the create, update and
+remove operations will automatically overwrite it.
+
+The unpack operation will fail if the images already exist at the
+destination. In that case, use -f or --force to continue.
+
+More information about FIP can be found in the `Firmware Design`_ document.
+
+Building FIP images with support for Trusted Board Boot
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Trusted Board Boot primarily consists of the following two features:
+
+-  Image Authentication, described in `Trusted Board Boot`_, and
+-  Firmware Update, described in `Firmware Update`_
+
+The following steps should be followed to build FIP and (optionally) FWU_FIP
+images with support for these features:
+
+#. Fulfill the dependencies of the ``mbedtls`` cryptographic and image parser
+   modules by checking out a recent version of the `mbed TLS Repository`_. It
+   is important to use a version that is compatible with TF-A and fixes any
+   known security vulnerabilities. See `mbed TLS Security Center`_ for more
+   information. The latest version of TF-A is tested with tag
+   ``mbedtls-2.16.0``.
+
+   The ``drivers/auth/mbedtls/mbedtls_*.mk`` files contain the list of mbed TLS
+   source files the modules depend upon.
+   ``include/drivers/auth/mbedtls/mbedtls_config.h`` contains the configuration
+   options required to build the mbed TLS sources.
+
+   Note that the mbed TLS library is licensed under the Apache version 2.0
+   license. Using mbed TLS source code will affect the licensing of TF-A
+   binaries that are built using this library.
+
+#. To build the FIP image, ensure the following command line variables are set
+   while invoking ``make`` to build TF-A:
+
+   -  ``MBEDTLS_DIR=<path of the directory containing mbed TLS sources>``
+   -  ``TRUSTED_BOARD_BOOT=1``
+   -  ``GENERATE_COT=1``
+
+   In the case of Arm platforms, the location of the ROTPK hash must also be
+   specified at build time. Two locations are currently supported (see
+   ``ARM_ROTPK_LOCATION`` build option):
+
+   -  ``ARM_ROTPK_LOCATION=regs``: the ROTPK hash is obtained from the Trusted
+      root-key storage registers present in the platform. On Juno, this
+      registers are read-only. On FVP Base and Cortex models, the registers
+      are read-only, but the value can be specified using the command line
+      option ``bp.trusted_key_storage.public_key`` when launching the model.
+      On both Juno and FVP models, the default value corresponds to an
+      ECDSA-SECP256R1 public key hash, whose private part is not currently
+      available.
+
+   -  ``ARM_ROTPK_LOCATION=devel_rsa``: use the ROTPK hash that is hardcoded
+      in the Arm platform port. The private/public RSA key pair may be
+      found in ``plat/arm/board/common/rotpk``.
+
+   -  ``ARM_ROTPK_LOCATION=devel_ecdsa``: use the ROTPK hash that is hardcoded
+      in the Arm platform port. The private/public ECDSA key pair may be
+      found in ``plat/arm/board/common/rotpk``.
+
+   Example of command line using RSA development keys:
+
+   .. code:: shell
+
+       MBEDTLS_DIR=<path of the directory containing mbed TLS sources> \
+       make PLAT=<platform> TRUSTED_BOARD_BOOT=1 GENERATE_COT=1        \
+       ARM_ROTPK_LOCATION=devel_rsa                                    \
+       ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem        \
+       BL33=<path-to>/<bl33_image>                                     \
+       all fip
+
+   The result of this build will be the bl1.bin and the fip.bin binaries. This
+   FIP will include the certificates corresponding to the Chain of Trust
+   described in the TBBR-client document. These certificates can also be found
+   in the output build directory.
+
+#. The optional FWU_FIP contains any additional images to be loaded from
+   Non-Volatile storage during the `Firmware Update`_ process. To build the
+   FWU_FIP, any FWU images required by the platform must be specified on the
+   command line. On Arm development platforms like Juno, these are:
+
+   -  NS_BL2U. The AP non-secure Firmware Updater image.
+   -  SCP_BL2U. The SCP Firmware Update Configuration image.
+
+   Example of Juno command line for generating both ``fwu`` and ``fwu_fip``
+   targets using RSA development:
+
+   ::
+
+       MBEDTLS_DIR=<path of the directory containing mbed TLS sources> \
+       make PLAT=juno TRUSTED_BOARD_BOOT=1 GENERATE_COT=1              \
+       ARM_ROTPK_LOCATION=devel_rsa                                    \
+       ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem        \
+       BL33=<path-to>/<bl33_image>                                     \
+       SCP_BL2=<path-to>/<scp_bl2_image>                               \
+       SCP_BL2U=<path-to>/<scp_bl2u_image>                             \
+       NS_BL2U=<path-to>/<ns_bl2u_image>                               \
+       all fip fwu_fip
+
+   .. note::
+      The BL2U image will be built by default and added to the FWU_FIP.
+      The user may override this by adding ``BL2U=<path-to>/<bl2u_image>``
+      to the command line above.
+
+   .. note::
+      Building and installing the non-secure and SCP FWU images (NS_BL1U,
+      NS_BL2U and SCP_BL2U) is outside the scope of this document.
+
+   The result of this build will be bl1.bin, fip.bin and fwu_fip.bin binaries.
+   Both the FIP and FWU_FIP will include the certificates corresponding to the
+   Chain of Trust described in the TBBR-client document. These certificates
+   can also be found in the output build directory.
+
+Building the Certificate Generation Tool
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``cert_create`` tool is built as part of the TF-A build process when the
+``fip`` make target is specified and TBB is enabled (as described in the
+previous section), but it can also be built separately with the following
+command:
+
+.. code:: shell
+
+    make PLAT=<platform> [DEBUG=1] [V=1] certtool
+
+For platforms that require their own IDs in certificate files, the generic
+'cert_create' tool can be built with the following command. Note that the target
+platform must define its IDs within a ``platform_oid.h`` header file for the
+build to succeed.
+
+.. code:: shell
+
+    make PLAT=<platform> USE_TBBR_DEFS=0 [DEBUG=1] [V=1] certtool
+
+``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/cert_create/cert_create -h
+
+Building a FIP for Juno and FVP
+-------------------------------
+
+This section provides Juno and FVP specific instructions to build Trusted
+Firmware, obtain the additional required firmware, and pack it all together in
+a single FIP binary. It assumes that a `Linaro Release`_ has been installed.
+
+.. note::
+   Pre-built binaries for AArch32 are available from Linaro Release 16.12
+   onwards. Before that release, pre-built binaries are only available for
+   AArch64.
+
+.. warning::
+   Follow the full instructions for one platform before switching to a
+   different one. Mixing instructions for different platforms may result in
+   corrupted binaries.
+
+.. warning::
+   The uboot image downloaded by the Linaro workspace script does not always
+   match the uboot image packaged as BL33 in the corresponding fip file. It is
+   recommended to use the version that is packaged in the fip file using the
+   instructions below.
+
+.. note::
+   For the FVP, the kernel FDT is packaged in FIP during build and loaded
+   by the firmware at runtime. See `Obtaining the Flattened Device Trees`_
+   section for more info on selecting the right FDT to use.
+
+#. Clean the working directory
+
+   .. code:: shell
+
+       make realclean
+
+#. Obtain SCP_BL2 (Juno) and BL33 (all platforms)
+
+   Use the fiptool to extract the SCP_BL2 and BL33 images from the FIP
+   package included in the Linaro release:
+
+   .. code:: shell
+
+       # Build the fiptool
+       make [DEBUG=1] [V=1] fiptool
+
+       # Unpack firmware images from Linaro FIP
+       ./tools/fiptool/fiptool unpack <path-to-linaro-release>/fip.bin
+
+   The unpack operation will result in a set of binary images extracted to the
+   current working directory. The SCP_BL2 image corresponds to
+   ``scp-fw.bin`` and BL33 corresponds to ``nt-fw.bin``.
+
+   .. note::
+      The fiptool will complain if the images to be unpacked already
+      exist in the current directory. If that is the case, either delete those
+      files or use the ``--force`` option to overwrite.
+
+   .. note::
+      For AArch32, the instructions below assume that nt-fw.bin is a
+      normal world boot loader that supports AArch32.
+
+#. Build TF-A images and create a new FIP for FVP
+
+   .. code:: shell
+
+       # AArch64
+       make PLAT=fvp BL33=nt-fw.bin all fip
+
+       # AArch32
+       make PLAT=fvp ARCH=aarch32 AARCH32_SP=sp_min BL33=nt-fw.bin all fip
+
+#. Build TF-A images and create a new FIP for Juno
+
+   For AArch64:
+
+   Building for AArch64 on Juno simply requires the addition of ``SCP_BL2``
+   as a build parameter.
+
+   .. code:: shell
+
+       make PLAT=juno BL33=nt-fw.bin SCP_BL2=scp-fw.bin all fip
+
+   For AArch32:
+
+   Hardware restrictions on Juno prevent cold reset into AArch32 execution mode,
+   therefore BL1 and BL2 must be compiled for AArch64, and BL32 is compiled
+   separately for AArch32.
+
+   -  Before building BL32, the environment variable ``CROSS_COMPILE`` must point
+      to the AArch32 Linaro cross compiler.
+
+      .. code:: shell
+
+          export CROSS_COMPILE=<path-to-aarch32-gcc>/bin/arm-linux-gnueabihf-
+
+   -  Build BL32 in AArch32.
+
+      .. code:: shell
+
+          make ARCH=aarch32 PLAT=juno AARCH32_SP=sp_min \
+          RESET_TO_SP_MIN=1 JUNO_AARCH32_EL3_RUNTIME=1 bl32
+
+   -  Save ``bl32.bin`` to a temporary location and clean the build products.
+
+      ::
+
+          cp <path-to-build>/bl32.bin <path-to-temporary>
+          make realclean
+
+   -  Before building BL1 and BL2, the environment variable ``CROSS_COMPILE``
+      must point to the AArch64 Linaro cross compiler.
+
+      .. code:: shell
+
+          export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-linux-gnu-
+
+   -  The following parameters should be used to build BL1 and BL2 in AArch64
+      and point to the BL32 file.
+
+      .. code:: shell
+
+          make ARCH=aarch64 PLAT=juno JUNO_AARCH32_EL3_RUNTIME=1 \
+          BL33=nt-fw.bin SCP_BL2=scp-fw.bin \
+          BL32=<path-to-temporary>/bl32.bin all fip
+
+The resulting BL1 and FIP images may be found in:
+
+::
+
+    # Juno
+    ./build/juno/release/bl1.bin
+    ./build/juno/release/fip.bin
+
+    # FVP
+    ./build/fvp/release/bl1.bin
+    ./build/fvp/release/fip.bin
+
+
+Booting Firmware Update images
+-------------------------------------
+
+When Firmware Update (FWU) is enabled there are at least 2 new images
+that have to be loaded, the Non-Secure FWU ROM (NS-BL1U), and the
+FWU FIP.
+
+Juno
+~~~~
+
+The new images must be programmed in flash memory by adding
+an entry in the ``SITE1/HBI0262x/images.txt`` configuration file
+on the Juno SD card (where ``x`` depends on the revision of the Juno board).
+Refer to the `Juno Getting Started Guide`_, section 2.3 "Flash memory
+programming" for more information. User should ensure these do not
+overlap with any other entries in the file.
+
+::
+
+	NOR10UPDATE: AUTO                       ;Image Update:NONE/AUTO/FORCE
+	NOR10ADDRESS: 0x00400000                ;Image Flash Address [ns_bl2u_base_address]
+	NOR10FILE: \SOFTWARE\fwu_fip.bin        ;Image File Name
+	NOR10LOAD: 00000000                     ;Image Load Address
+	NOR10ENTRY: 00000000                    ;Image Entry Point
+
+	NOR11UPDATE: AUTO                       ;Image Update:NONE/AUTO/FORCE
+	NOR11ADDRESS: 0x03EB8000                ;Image Flash Address [ns_bl1u_base_address]
+	NOR11FILE: \SOFTWARE\ns_bl1u.bin        ;Image File Name
+	NOR11LOAD: 00000000                     ;Image Load Address
+
+The address ns_bl1u_base_address is the value of NS_BL1U_BASE - 0x8000000.
+In the same way, the address ns_bl2u_base_address is the value of
+NS_BL2U_BASE - 0x8000000.
+
+FVP
+~~~
+
+The additional fip images must be loaded with:
+
+::
+
+    --data cluster0.cpu0="<path_to>/ns_bl1u.bin"@0x0beb8000	[ns_bl1u_base_address]
+    --data cluster0.cpu0="<path_to>/fwu_fip.bin"@0x08400000	[ns_bl2u_base_address]
+
+The address ns_bl1u_base_address is the value of NS_BL1U_BASE.
+In the same way, the address ns_bl2u_base_address is the value of
+NS_BL2U_BASE.
+
+
+EL3 payloads alternative boot flow
+----------------------------------
+
+On a pre-production system, the ability to execute arbitrary, bare-metal code at
+the highest exception level is required. It allows full, direct access to the
+hardware, for example to run silicon soak tests.
+
+Although it is possible to implement some baremetal secure firmware from
+scratch, this is a complex task on some platforms, depending on the level of
+configuration required to put the system in the expected state.
+
+Rather than booting a baremetal application, a possible compromise is to boot
+``EL3 payloads`` through TF-A instead. This is implemented as an alternative
+boot flow, where a modified BL2 boots an EL3 payload, instead of loading the
+other BL images and passing control to BL31. It reduces the complexity of
+developing EL3 baremetal code by:
+
+-  putting the system into a known architectural state;
+-  taking care of platform secure world initialization;
+-  loading the SCP_BL2 image if required by the platform.
+
+When booting an EL3 payload on Arm standard platforms, the configuration of the
+TrustZone controller is simplified such that only region 0 is enabled and is
+configured to permit secure access only. This gives full access to the whole
+DRAM to the EL3 payload.
+
+The system is left in the same state as when entering BL31 in the default boot
+flow. In particular:
+
+-  Running in EL3;
+-  Current state is AArch64;
+-  Little-endian data access;
+-  All exceptions disabled;
+-  MMU disabled;
+-  Caches disabled.
+
+Booting an EL3 payload
+~~~~~~~~~~~~~~~~~~~~~~
+
+The EL3 payload image is a standalone image and is not part of the FIP. It is
+not loaded by TF-A. Therefore, there are 2 possible scenarios:
+
+-  The EL3 payload may reside in non-volatile memory (NVM) and execute in
+   place. In this case, booting it is just a matter of specifying the right
+   address in NVM through ``EL3_PAYLOAD_BASE`` when building TF-A.
+
+-  The EL3 payload needs to be loaded in volatile memory (e.g. DRAM) at
+   run-time.
+
+To help in the latter scenario, the ``SPIN_ON_BL1_EXIT=1`` build option can be
+used. The infinite loop that it introduces in BL1 stops execution at the right
+moment for a debugger to take control of the target and load the payload (for
+example, over JTAG).
+
+It is expected that this loading method will work in most cases, as a debugger
+connection is usually available in a pre-production system. The user is free to
+use any other platform-specific mechanism to load the EL3 payload, though.
+
+Booting an EL3 payload on FVP
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The EL3 payloads boot flow requires the CPU's mailbox to be cleared at reset for
+the secondary CPUs holding pen to work properly. Unfortunately, its reset value
+is undefined on the FVP platform and the FVP platform code doesn't clear it.
+Therefore, one must modify the way the model is normally invoked in order to
+clear the mailbox at start-up.
+
+One way to do that is to create an 8-byte file containing all zero bytes using
+the following command:
+
+.. code:: shell
+
+    dd if=/dev/zero of=mailbox.dat bs=1 count=8
+
+and pre-load it into the FVP memory at the mailbox address (i.e. ``0x04000000``)
+using the following model parameters:
+
+::
+
+    --data cluster0.cpu0=mailbox.dat@0x04000000   [Base FVPs]
+    --data=mailbox.dat@0x04000000                 [Foundation FVP]
+
+To provide the model with the EL3 payload image, the following methods may be
+used:
+
+#. If the EL3 payload is able to execute in place, it may be programmed into
+   flash memory. On Base Cortex and AEM FVPs, the following model parameter
+   loads it at the base address of the NOR FLASH1 (the NOR FLASH0 is already
+   used for the FIP):
+
+   ::
+
+       -C bp.flashloader1.fname="<path-to>/<el3-payload>"
+
+   On Foundation FVP, there is no flash loader component and the EL3 payload
+   may be programmed anywhere in flash using method 3 below.
+
+#. When using the ``SPIN_ON_BL1_EXIT=1`` loading method, the following DS-5
+   command may be used to load the EL3 payload ELF image over JTAG:
+
+   ::
+
+       load <path-to>/el3-payload.elf
+
+#. The EL3 payload may be pre-loaded in volatile memory using the following
+   model parameters:
+
+   ::
+
+       --data cluster0.cpu0="<path-to>/el3-payload>"@address   [Base FVPs]
+       --data="<path-to>/<el3-payload>"@address                [Foundation FVP]
+
+   The address provided to the FVP must match the ``EL3_PAYLOAD_BASE`` address
+   used when building TF-A.
+
+Booting an EL3 payload on Juno
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the EL3 payload is able to execute in place, it may be programmed in flash
+memory by adding an entry in the ``SITE1/HBI0262x/images.txt`` configuration file
+on the Juno SD card (where ``x`` depends on the revision of the Juno board).
+Refer to the `Juno Getting Started Guide`_, section 2.3 "Flash memory
+programming" for more information.
+
+Alternatively, the same DS-5 command mentioned in the FVP section above can
+be used to load the EL3 payload's ELF file over JTAG on Juno.
+
+Preloaded BL33 alternative boot flow
+------------------------------------
+
+Some platforms have the ability to preload BL33 into memory instead of relying
+on TF-A to load it. This may simplify packaging of the normal world code and
+improve performance in a development environment. When secure world cold boot
+is complete, TF-A simply jumps to a BL33 base address provided at build time.
+
+For this option to be used, the ``PRELOADED_BL33_BASE`` build option has to be
+used when compiling TF-A. For example, the following command will create a FIP
+without a BL33 and prepare to jump to a BL33 image loaded at address
+0x80000000:
+
+.. code:: shell
+
+    make PRELOADED_BL33_BASE=0x80000000 PLAT=fvp all fip
+
+Boot of a preloaded kernel image on Base FVP
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following example uses a simplified boot flow by directly jumping from the
+TF-A to the Linux kernel, which will use a ramdisk as filesystem. This can be
+useful if both the kernel and the device tree blob (DTB) are already present in
+memory (like in FVP).
+
+For example, if the kernel is loaded at ``0x80080000`` and the DTB is loaded at
+address ``0x82000000``, the firmware can be built like this:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu-  \
+    make PLAT=fvp DEBUG=1             \
+    RESET_TO_BL31=1                   \
+    ARM_LINUX_KERNEL_AS_BL33=1        \
+    PRELOADED_BL33_BASE=0x80080000    \
+    ARM_PRELOADED_DTB_BASE=0x82000000 \
+    all fip
+
+Now, it is needed to modify the DTB so that the kernel knows the address of the
+ramdisk. The following script generates a patched DTB from the provided one,
+assuming that the ramdisk is loaded at address ``0x84000000``. Note that this
+script assumes that the user is using a ramdisk image prepared for U-Boot, like
+the ones provided by Linaro. If using a ramdisk without this header,the ``0x40``
+offset in ``INITRD_START`` has to be removed.
+
+.. code:: bash
+
+    #!/bin/bash
+
+    # Path to the input DTB
+    KERNEL_DTB=<path-to>/<fdt>
+    # Path to the output DTB
+    PATCHED_KERNEL_DTB=<path-to>/<patched-fdt>
+    # Base address of the ramdisk
+    INITRD_BASE=0x84000000
+    # Path to the ramdisk
+    INITRD=<path-to>/<ramdisk.img>
+
+    # Skip uboot header (64 bytes)
+    INITRD_START=$(printf "0x%x" $((${INITRD_BASE} + 0x40)) )
+    INITRD_SIZE=$(stat -Lc %s ${INITRD})
+    INITRD_END=$(printf "0x%x" $((${INITRD_BASE} + ${INITRD_SIZE})) )
+
+    CHOSEN_NODE=$(echo                                        \
+    "/ {                                                      \
+            chosen {                                          \
+                    linux,initrd-start = <${INITRD_START}>;   \
+                    linux,initrd-end = <${INITRD_END}>;       \
+            };                                                \
+    };")
+
+    echo $(dtc -O dts -I dtb ${KERNEL_DTB}) ${CHOSEN_NODE} |  \
+            dtc -O dtb -o ${PATCHED_KERNEL_DTB} -
+
+And the FVP binary can be run with the following command:
+
+.. code:: shell
+
+    <path-to>/FVP_Base_AEMv8A-AEMv8A                            \
+    -C pctl.startup=0.0.0.0                                     \
+    -C bp.secure_memory=1                                       \
+    -C cluster0.NUM_CORES=4                                     \
+    -C cluster1.NUM_CORES=4                                     \
+    -C cache_state_modelled=1                                   \
+    -C cluster0.cpu0.RVBAR=0x04020000                           \
+    -C cluster0.cpu1.RVBAR=0x04020000                           \
+    -C cluster0.cpu2.RVBAR=0x04020000                           \
+    -C cluster0.cpu3.RVBAR=0x04020000                           \
+    -C cluster1.cpu0.RVBAR=0x04020000                           \
+    -C cluster1.cpu1.RVBAR=0x04020000                           \
+    -C cluster1.cpu2.RVBAR=0x04020000                           \
+    -C cluster1.cpu3.RVBAR=0x04020000                           \
+    --data cluster0.cpu0="<path-to>/bl31.bin"@0x04020000        \
+    --data cluster0.cpu0="<path-to>/<patched-fdt>"@0x82000000   \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+    --data cluster0.cpu0="<path-to>/<ramdisk.img>"@0x84000000
+
+Boot of a preloaded kernel image on Juno
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Trusted Firmware must be compiled in a similar way as for FVP explained
+above. The process to load binaries to memory is the one explained in
+`Booting an EL3 payload on Juno`_.
+
+Running the software on FVP
+---------------------------
+
+The latest version of the AArch64 build of TF-A has been tested on the following
+Arm FVPs without shifted affinities, and that do not support threaded CPU cores
+(64-bit host machine only).
+
+.. note::
+   The FVP models used are Version 11.6 Build 45, unless otherwise stated.
+
+-  ``FVP_Base_AEMv8A-AEMv8A``
+-  ``FVP_Base_AEMv8A-AEMv8A-AEMv8A-AEMv8A-CCN502``
+-  ``FVP_Base_RevC-2xAEMv8A``
+-  ``FVP_Base_Cortex-A32x4``
+-  ``FVP_Base_Cortex-A35x4``
+-  ``FVP_Base_Cortex-A53x4``
+-  ``FVP_Base_Cortex-A55x4+Cortex-A75x4``
+-  ``FVP_Base_Cortex-A55x4``
+-  ``FVP_Base_Cortex-A57x1-A53x1``
+-  ``FVP_Base_Cortex-A57x2-A53x4``
+-  ``FVP_Base_Cortex-A57x4-A53x4``
+-  ``FVP_Base_Cortex-A57x4``
+-  ``FVP_Base_Cortex-A72x4-A53x4``
+-  ``FVP_Base_Cortex-A72x4``
+-  ``FVP_Base_Cortex-A73x4-A53x4``
+-  ``FVP_Base_Cortex-A73x4``
+-  ``FVP_Base_Cortex-A75x4``
+-  ``FVP_Base_Cortex-A76x4``
+-  ``FVP_Base_Cortex-A76AEx4``
+-  ``FVP_Base_Cortex-A76AEx8``
+-  ``FVP_Base_Cortex-A77x4`` (Version 11.7 build 36)
+-  ``FVP_Base_Neoverse-N1x4``
+-  ``FVP_CSS_SGI-575`` (Version 11.3 build 42)
+-  ``FVP_CSS_SGM-775`` (Version 11.3 build 42)
+-  ``FVP_RD_E1Edge`` (Version 11.3 build 42)
+-  ``FVP_RD_N1Edge``
+-  ``Foundation_Platform``
+
+The latest version of the AArch32 build of TF-A has been tested on the following
+Arm FVPs without shifted affinities, and that do not support threaded CPU cores
+(64-bit host machine only).
+
+-  ``FVP_Base_AEMv8A-AEMv8A``
+-  ``FVP_Base_Cortex-A32x4``
+
+.. note::
+   The ``FVP_Base_RevC-2xAEMv8A`` FVP only supports shifted affinities, which
+   is not compatible with legacy GIC configurations. Therefore this FVP does not
+   support these legacy GIC configurations.
+
+.. note::
+   The build numbers quoted above are those reported by launching the FVP
+   with the ``--version`` parameter.
+
+.. note::
+   Linaro provides a ramdisk image in prebuilt FVP configurations and full
+   file systems that can be downloaded separately. To run an FVP with a virtio
+   file system image an additional FVP configuration option
+   ``-C bp.virtioblockdevice.image_path="<path-to>/<file-system-image>`` can be
+   used.
+
+.. note::
+   The software will not work on Version 1.0 of the Foundation FVP.
+   The commands below would report an ``unhandled argument`` error in this case.
+
+.. note::
+   FVPs can be launched with ``--cadi-server`` option such that a
+   CADI-compliant debugger (for example, Arm DS-5) can connect to and control
+   its execution.
+
+.. warning::
+   Since FVP model Version 11.0 Build 11.0.34 and Version 8.5 Build 0.8.5202
+   the internal synchronisation timings changed compared to older versions of
+   the models. The models can be launched with ``-Q 100`` option if they are
+   required to match the run time characteristics of the older versions.
+
+The Foundation FVP is a cut down version of the AArch64 Base FVP. It can be
+downloaded for free from `Arm's website`_.
+
+The Cortex-A models listed above are also available to download from
+`Arm's website`_.
+
+Please refer to the FVP documentation for a detailed description of the model
+parameter options. A brief description of the important ones that affect TF-A
+and normal world software behavior is provided below.
+
+Obtaining the Flattened Device Trees
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Depending on the FVP configuration and Linux configuration used, different
+FDT files are required. FDT source files for the Foundation and Base FVPs can
+be found in the TF-A source directory under ``fdts/``. The Foundation FVP has
+a subset of the Base FVP components. For example, the Foundation FVP lacks
+CLCD and MMC support, and has only one CPU cluster.
+
+.. note::
+   It is not recommended to use the FDTs built along the kernel because not
+   all FDTs are available from there.
+
+The dynamic configuration capability is enabled in the firmware for FVPs.
+This means that the firmware can authenticate and load the FDT if present in
+FIP. A default FDT is packaged into FIP during the build based on
+the build configuration. This can be overridden by using the ``FVP_HW_CONFIG``
+or ``FVP_HW_CONFIG_DTS`` build options (refer to the
+`Arm FVP platform specific build options`_ section for detail on the options).
+
+-  ``fvp-base-gicv2-psci.dts``
+
+   For use with models such as the Cortex-A57-A53 Base FVPs without shifted
+   affinities and with Base memory map configuration.
+
+-  ``fvp-base-gicv2-psci-aarch32.dts``
+
+   For use with models such as the Cortex-A32 Base FVPs without shifted
+   affinities and running Linux in AArch32 state with Base memory map
+   configuration.
+
+-  ``fvp-base-gicv3-psci.dts``
+
+   For use with models such as the Cortex-A57-A53 Base FVPs without shifted
+   affinities and with Base memory map configuration and Linux GICv3 support.
+
+-  ``fvp-base-gicv3-psci-1t.dts``
+
+   For use with models such as the AEMv8-RevC Base FVP with shifted affinities,
+   single threaded CPUs, Base memory map configuration and Linux GICv3 support.
+
+-  ``fvp-base-gicv3-psci-dynamiq.dts``
+
+   For use with models as the Cortex-A55-A75 Base FVPs with shifted affinities,
+   single cluster, single threaded CPUs, Base memory map configuration and Linux
+   GICv3 support.
+
+-  ``fvp-base-gicv3-psci-aarch32.dts``
+
+   For use with models such as the Cortex-A32 Base FVPs without shifted
+   affinities and running Linux in AArch32 state with Base memory map
+   configuration and Linux GICv3 support.
+
+-  ``fvp-foundation-gicv2-psci.dts``
+
+   For use with Foundation FVP with Base memory map configuration.
+
+-  ``fvp-foundation-gicv3-psci.dts``
+
+   (Default) For use with Foundation FVP with Base memory map configuration
+   and Linux GICv3 support.
+
+Running on the Foundation FVP with reset to BL1 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``Foundation_Platform`` parameters should be used to boot Linux with
+4 CPUs using the AArch64 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/Foundation_Platform                   \
+    --cores=4                                       \
+    --arm-v8.0                                      \
+    --secure-memory                                 \
+    --visualization                                 \
+    --gicv3                                         \
+    --data="<path-to>/<bl1-binary>"@0x0             \
+    --data="<path-to>/<FIP-binary>"@0x08000000      \
+    --data="<path-to>/<kernel-binary>"@0x80080000   \
+    --data="<path-to>/<ramdisk-binary>"@0x84000000
+
+Notes:
+
+-  BL1 is loaded at the start of the Trusted ROM.
+-  The Firmware Image Package is loaded at the start of NOR FLASH0.
+-  The firmware loads the FDT packaged in FIP to the DRAM. The FDT load address
+   is specified via the ``hw_config_addr`` property in `TB_FW_CONFIG for FVP`_.
+-  The default use-case for the Foundation FVP is to use the ``--gicv3`` option
+   and enable the GICv3 device in the model. Note that without this option,
+   the Foundation FVP defaults to legacy (Versatile Express) memory map which
+   is not supported by TF-A.
+-  In order for TF-A to run correctly on the Foundation FVP, the architecture
+   versions must match. The Foundation FVP defaults to the highest v8.x
+   version it supports but the default build for TF-A is for v8.0. To avoid
+   issues either start the Foundation FVP to use v8.0 architecture using the
+   ``--arm-v8.0`` option, or build TF-A with an appropriate value for
+   ``ARM_ARCH_MINOR``.
+
+Running on the AEMv8 Base FVP with reset to BL1 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_RevC-2xAEMv8A`` parameters should be used to boot Linux
+with 8 CPUs using the AArch64 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_RevC-2xAEMv8A                            \
+    -C pctl.startup=0.0.0.0                                     \
+    -C bp.secure_memory=1                                       \
+    -C bp.tzc_400.diagnostics=1                                 \
+    -C cluster0.NUM_CORES=4                                     \
+    -C cluster1.NUM_CORES=4                                     \
+    -C cache_state_modelled=1                                   \
+    -C bp.secureflashloader.fname="<path-to>/<bl1-binary>"      \
+    -C bp.flashloader0.fname="<path-to>/<FIP-binary>"           \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+.. note::
+   The ``FVP_Base_RevC-2xAEMv8A`` has shifted affinities and requires
+   a specific DTS for all the CPUs to be loaded.
+
+Running on the AEMv8 Base FVP (AArch32) with reset to BL1 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_AEMv8A-AEMv8A`` parameters should be used to boot Linux
+with 8 CPUs using the AArch32 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_AEMv8A-AEMv8A                            \
+    -C pctl.startup=0.0.0.0                                     \
+    -C bp.secure_memory=1                                       \
+    -C bp.tzc_400.diagnostics=1                                 \
+    -C cluster0.NUM_CORES=4                                     \
+    -C cluster1.NUM_CORES=4                                     \
+    -C cache_state_modelled=1                                   \
+    -C cluster0.cpu0.CONFIG64=0                                 \
+    -C cluster0.cpu1.CONFIG64=0                                 \
+    -C cluster0.cpu2.CONFIG64=0                                 \
+    -C cluster0.cpu3.CONFIG64=0                                 \
+    -C cluster1.cpu0.CONFIG64=0                                 \
+    -C cluster1.cpu1.CONFIG64=0                                 \
+    -C cluster1.cpu2.CONFIG64=0                                 \
+    -C cluster1.cpu3.CONFIG64=0                                 \
+    -C bp.secureflashloader.fname="<path-to>/<bl1-binary>"      \
+    -C bp.flashloader0.fname="<path-to>/<FIP-binary>"           \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Running on the Cortex-A57-A53 Base FVP with reset to BL1 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_Cortex-A57x4-A53x4`` model parameters should be used to
+boot Linux with 8 CPUs using the AArch64 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_Cortex-A57x4-A53x4                       \
+    -C pctl.startup=0.0.0.0                                     \
+    -C bp.secure_memory=1                                       \
+    -C bp.tzc_400.diagnostics=1                                 \
+    -C cache_state_modelled=1                                   \
+    -C bp.secureflashloader.fname="<path-to>/<bl1-binary>"      \
+    -C bp.flashloader0.fname="<path-to>/<FIP-binary>"           \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Running on the Cortex-A32 Base FVP (AArch32) with reset to BL1 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_Cortex-A32x4`` model parameters should be used to
+boot Linux with 4 CPUs using the AArch32 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_Cortex-A32x4                             \
+    -C pctl.startup=0.0.0.0                                     \
+    -C bp.secure_memory=1                                       \
+    -C bp.tzc_400.diagnostics=1                                 \
+    -C cache_state_modelled=1                                   \
+    -C bp.secureflashloader.fname="<path-to>/<bl1-binary>"      \
+    -C bp.flashloader0.fname="<path-to>/<FIP-binary>"           \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Running on the AEMv8 Base FVP with reset to BL31 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_RevC-2xAEMv8A`` parameters should be used to boot Linux
+with 8 CPUs using the AArch64 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_RevC-2xAEMv8A                             \
+    -C pctl.startup=0.0.0.0                                      \
+    -C bp.secure_memory=1                                        \
+    -C bp.tzc_400.diagnostics=1                                  \
+    -C cluster0.NUM_CORES=4                                      \
+    -C cluster1.NUM_CORES=4                                      \
+    -C cache_state_modelled=1                                    \
+    -C cluster0.cpu0.RVBAR=0x04010000                            \
+    -C cluster0.cpu1.RVBAR=0x04010000                            \
+    -C cluster0.cpu2.RVBAR=0x04010000                            \
+    -C cluster0.cpu3.RVBAR=0x04010000                            \
+    -C cluster1.cpu0.RVBAR=0x04010000                            \
+    -C cluster1.cpu1.RVBAR=0x04010000                            \
+    -C cluster1.cpu2.RVBAR=0x04010000                            \
+    -C cluster1.cpu3.RVBAR=0x04010000                            \
+    --data cluster0.cpu0="<path-to>/<bl31-binary>"@0x04010000    \
+    --data cluster0.cpu0="<path-to>/<bl32-binary>"@0xff000000    \
+    --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000    \
+    --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000            \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000  \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Notes:
+
+-  If Position Independent Executable (PIE) support is enabled for BL31
+   in this config, it can be loaded at any valid address for execution.
+
+-  Since a FIP is not loaded when using BL31 as reset entrypoint, the
+   ``--data="<path-to><bl31|bl32|bl33-binary>"@<base-address-of-binary>``
+   parameter is needed to load the individual bootloader images in memory.
+   BL32 image is only needed if BL31 has been built to expect a Secure-EL1
+   Payload. For the same reason, the FDT needs to be compiled from the DT source
+   and loaded via the ``--data cluster0.cpu0="<path-to>/<fdt>"@0x82000000``
+   parameter.
+
+-  The ``FVP_Base_RevC-2xAEMv8A`` has shifted affinities and requires a
+   specific DTS for all the CPUs to be loaded.
+
+-  The ``-C cluster<X>.cpu<Y>.RVBAR=@<base-address-of-bl31>`` parameter, where
+   X and Y are the cluster and CPU numbers respectively, is used to set the
+   reset vector for each core.
+
+-  Changing the default value of ``ARM_TSP_RAM_LOCATION`` will also require
+   changing the value of
+   ``--data="<path-to><bl32-binary>"@<base-address-of-bl32>`` to the new value of
+   ``BL32_BASE``.
+
+Running on the AEMv8 Base FVP (AArch32) with reset to SP_MIN entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_AEMv8A-AEMv8A`` parameters should be used to boot Linux
+with 8 CPUs using the AArch32 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_AEMv8A-AEMv8A                             \
+    -C pctl.startup=0.0.0.0                                      \
+    -C bp.secure_memory=1                                        \
+    -C bp.tzc_400.diagnostics=1                                  \
+    -C cluster0.NUM_CORES=4                                      \
+    -C cluster1.NUM_CORES=4                                      \
+    -C cache_state_modelled=1                                    \
+    -C cluster0.cpu0.CONFIG64=0                                  \
+    -C cluster0.cpu1.CONFIG64=0                                  \
+    -C cluster0.cpu2.CONFIG64=0                                  \
+    -C cluster0.cpu3.CONFIG64=0                                  \
+    -C cluster1.cpu0.CONFIG64=0                                  \
+    -C cluster1.cpu1.CONFIG64=0                                  \
+    -C cluster1.cpu2.CONFIG64=0                                  \
+    -C cluster1.cpu3.CONFIG64=0                                  \
+    -C cluster0.cpu0.RVBAR=0x04002000                            \
+    -C cluster0.cpu1.RVBAR=0x04002000                            \
+    -C cluster0.cpu2.RVBAR=0x04002000                            \
+    -C cluster0.cpu3.RVBAR=0x04002000                            \
+    -C cluster1.cpu0.RVBAR=0x04002000                            \
+    -C cluster1.cpu1.RVBAR=0x04002000                            \
+    -C cluster1.cpu2.RVBAR=0x04002000                            \
+    -C cluster1.cpu3.RVBAR=0x04002000                            \
+    --data cluster0.cpu0="<path-to>/<bl32-binary>"@0x04002000    \
+    --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000    \
+    --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000            \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000  \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+.. note::
+   The load address of ``<bl32-binary>`` depends on the value ``BL32_BASE``.
+   It should match the address programmed into the RVBAR register as well.
+
+Running on the Cortex-A57-A53 Base FVP with reset to BL31 entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_Cortex-A57x4-A53x4`` model parameters should be used to
+boot Linux with 8 CPUs using the AArch64 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_Cortex-A57x4-A53x4                        \
+    -C pctl.startup=0.0.0.0                                      \
+    -C bp.secure_memory=1                                        \
+    -C bp.tzc_400.diagnostics=1                                  \
+    -C cache_state_modelled=1                                    \
+    -C cluster0.cpu0.RVBARADDR=0x04010000                        \
+    -C cluster0.cpu1.RVBARADDR=0x04010000                        \
+    -C cluster0.cpu2.RVBARADDR=0x04010000                        \
+    -C cluster0.cpu3.RVBARADDR=0x04010000                        \
+    -C cluster1.cpu0.RVBARADDR=0x04010000                        \
+    -C cluster1.cpu1.RVBARADDR=0x04010000                        \
+    -C cluster1.cpu2.RVBARADDR=0x04010000                        \
+    -C cluster1.cpu3.RVBARADDR=0x04010000                        \
+    --data cluster0.cpu0="<path-to>/<bl31-binary>"@0x04010000    \
+    --data cluster0.cpu0="<path-to>/<bl32-binary>"@0xff000000    \
+    --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000    \
+    --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000            \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000  \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Running on the Cortex-A32 Base FVP (AArch32) with reset to SP_MIN entrypoint
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following ``FVP_Base_Cortex-A32x4`` model parameters should be used to
+boot Linux with 4 CPUs using the AArch32 build of TF-A.
+
+.. code:: shell
+
+    <path-to>/FVP_Base_Cortex-A32x4                             \
+    -C pctl.startup=0.0.0.0                                     \
+    -C bp.secure_memory=1                                       \
+    -C bp.tzc_400.diagnostics=1                                 \
+    -C cache_state_modelled=1                                   \
+    -C cluster0.cpu0.RVBARADDR=0x04002000                       \
+    -C cluster0.cpu1.RVBARADDR=0x04002000                       \
+    -C cluster0.cpu2.RVBARADDR=0x04002000                       \
+    -C cluster0.cpu3.RVBARADDR=0x04002000                       \
+    --data cluster0.cpu0="<path-to>/<bl32-binary>"@0x04002000   \
+    --data cluster0.cpu0="<path-to>/<bl33-binary>"@0x88000000   \
+    --data cluster0.cpu0="<path-to>/<fdt>"@0x82000000           \
+    --data cluster0.cpu0="<path-to>/<kernel-binary>"@0x80080000 \
+    --data cluster0.cpu0="<path-to>/<ramdisk>"@0x84000000
+
+Running the software on Juno
+----------------------------
+
+This version of TF-A has been tested on variants r0, r1 and r2 of Juno.
+
+To execute the software stack on Juno, the version of the Juno board recovery
+image indicated in the `Linaro Release Notes`_ must be installed. If you have an
+earlier version installed or are unsure which version is installed, please
+re-install the recovery image by following the
+`Instructions for using Linaro's deliverables on Juno`_.
+
+Preparing TF-A images
+~~~~~~~~~~~~~~~~~~~~~
+
+After building TF-A, the files ``bl1.bin`` and ``fip.bin`` need copying to the
+``SOFTWARE/`` directory of the Juno SD card.
+
+Other Juno software information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Please visit the `Arm Platforms Portal`_ to get support and obtain any other Juno
+software information. Please also refer to the `Juno Getting Started Guide`_ to
+get more detailed information about the Juno Arm development platform and how to
+configure it.
+
+Testing SYSTEM SUSPEND on Juno
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The SYSTEM SUSPEND is a PSCI API which can be used to implement system suspend
+to RAM. For more details refer to section 5.16 of `PSCI`_. To test system suspend
+on Juno, at the linux shell prompt, issue the following command:
+
+.. code:: shell
+
+    echo +10 > /sys/class/rtc/rtc0/wakealarm
+    echo -n mem > /sys/power/state
+
+The Juno board should suspend to RAM and then wakeup after 10 seconds due to
+wakeup interrupt from RTC.
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _arm Developer page: https://developer.arm.com/open-source/gnu-toolchain/gnu-a/downloads
+.. _Linaro: `Linaro Release Notes`_
+.. _Linaro Release: `Linaro Release Notes`_
+.. _Linaro Release Notes: https://community.arm.com/dev-platforms/w/docs/226/old-release-notes
+.. _Linaro instructions: https://community.arm.com/dev-platforms/w/docs/304/arm-reference-platforms-deliverables
+.. _Instructions for using Linaro's deliverables on Juno: https://community.arm.com/dev-platforms/w/docs/303/juno
+.. _Arm Platforms Portal: https://community.arm.com/dev-platforms/
+.. _Development Studio 5 (DS-5): https://developer.arm.com/products/software-development-tools/ds-5-development-studio
+.. _arm-trusted-firmware-a project page: https://review.trustedfirmware.org/admin/projects/TF-A/trusted-firmware-a
+.. _`Linux Coding Style`: https://www.kernel.org/doc/html/latest/process/coding-style.html
+.. _Linux master tree: https://github.com/torvalds/linux/tree/master/
+.. _Dia: https://wiki.gnome.org/Apps/Dia/Download
+.. _here: psci-lib-integration-guide.rst
+.. _Trusted Board Boot: ../design/trusted-board-boot.rst
+.. _TB_FW_CONFIG for FVP: ../../plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
+.. _Secure-EL1 Payloads and Dispatchers: ../design/firmware-design.rst#user-content-secure-el1-payloads-and-dispatchers
+.. _Firmware Update: ../components/firmware-update.rst
+.. _Firmware Design: ../design/firmware-design.rst
+.. _mbed TLS Repository: https://github.com/ARMmbed/mbedtls.git
+.. _mbed TLS Security Center: https://tls.mbed.org/security
+.. _Arm's website: `FVP models`_
+.. _FVP models: https://developer.arm.com/products/system-design/fixed-virtual-platforms
+.. _Juno Getting Started Guide: http://infocenter.arm.com/help/topic/com.arm.doc.dui0928e/DUI0928E_juno_arm_development_platform_gsg.pdf
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _Secure Partition Manager Design guide: ../components/secure-partition-manager-design.rst
+.. _`Trusted Firmware-A Coding Guidelines`: ../process/coding-guidelines.rst
+.. _Library at ROM: ../components/romlib-design.rst
diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt
new file mode 100644
index 0000000..242e62c
--- /dev/null
+++ b/docs/global_substitutions.txt
@@ -0,0 +1,55 @@
+.. |AArch32| replace:: :term:`AArch32`
+.. |AArch64| replace:: :term:`AArch64`
+.. |API| replace:: :term:`API`
+.. |CoT| replace:: :term:`CoT`
+.. |COT| replace:: :term:`COT`
+.. |CSS| replace:: :term:`CSS`
+.. |CVE| replace:: :term:`CVE`
+.. |DS-5| replace:: :term:`DS-5`
+.. |DT| replace:: :term:`DT`
+.. |EL| replace:: :term:`EL`
+.. |EHF| replace:: :term:`EHF`
+.. |FDT| replace:: :term:`FDT`
+.. |FIP| replace:: :term:`FIP`
+.. |FVP| replace:: :term:`FVP`
+.. |FWU| replace:: :term:`FWU`
+.. |GIC| replace:: :term:`GIC`
+.. |ISA| replace:: :term:`ISA`
+.. |Linaro| replace:: :term:`Linaro`
+.. |MMU| replace:: :term:`MMU`
+.. |MPAM| replace:: :term:`MPAM`
+.. |MPIDR| replace:: :term:`MPIDR`
+.. |OEN| replace:: :term:`OEN`
+.. |OP-TEE| replace:: :term:`OP-TEE`
+.. |OTE| replace:: :term:`OTE`
+.. |PDD| replace:: :term:`PDD`
+.. |PMF| replace:: :term:`PMF`
+.. |PSCI| replace:: :term:`PSCI`
+.. |RAS| replace:: :term:`RAS`
+.. |ROT| replace:: :term:`ROT`
+.. |SCMI| replace:: :term:`SCMI`
+.. |SCP| replace:: :term:`SCP`
+.. |SDEI| replace:: :term:`SDEI`
+.. |SDS| replace:: :term:`SDS`
+.. |SEA| replace:: :term:`SEA`
+.. |SiP| replace:: :term:`SiP`
+.. |SIP| replace:: :term:`SIP`
+.. |SMC| replace:: :term:`SMC`
+.. |SMCCC| replace:: :term:`SMCCC`
+.. |SoC| replace:: :term:`SoC`
+.. |SP| replace:: :term:`SP`
+.. |SPD| replace:: :term:`SPD`
+.. |SPM| replace:: :term:`SPM`
+.. |SVE| replace:: :term:`SVE`
+.. |TBB| replace:: :term:`TBB`
+.. |TBBR| replace:: :term:`TBBR`
+.. |TEE| replace:: :term:`TEE`
+.. |TF-A| replace:: :term:`TF-A`
+.. |TF-M| replace:: :term:`TF-M`
+.. |TLB| replace:: :term:`TLB`
+.. |TLK| replace:: :term:`TLK`
+.. |TSP| replace:: :term:`TSP`
+.. |TZC| replace:: :term:`TZC`
+.. |UEFI| replace:: :term:`UEFI`
+.. |WDOG| replace:: :term:`WDOG`
+.. |XLAT| replace:: :term:`XLAT`
\ No newline at end of file
diff --git a/docs/glossary.rst b/docs/glossary.rst
new file mode 100644
index 0000000..afe0acf
--- /dev/null
+++ b/docs/glossary.rst
@@ -0,0 +1,177 @@
+Glossary
+========
+
+This glossary provides definitions for terms and abbreviations used in the TF-A
+documentation.
+
+You can find additional definitions in the `Arm Glossary`_.
+
+.. glossary::
+   :sorted:
+
+   AArch32
+      32-bit execution state of the ARMv8 ISA
+
+   AArch64
+      64-bit execution state of the ARMv8 ISA
+
+   API
+      Application Programming Interface
+
+   CoT
+   COT
+      Chain of Trust
+
+   CSS
+      Compute Sub-System
+
+   CVE
+      Common Vulnerabilities and Exposures. A CVE document is commonly used to
+      describe a publicly-known security vulnerability.
+
+   DS-5
+      Arm Development Studio 5
+
+   DT
+      Device Tree
+
+   EL
+      Exception Level
+
+   EHF
+      Exception Handling Framework
+
+   FDT
+      Flattened Device Tree
+
+   FIP
+      Firmware Image Package
+
+   FVP
+      Fixed Virtual Platform
+
+   FWU
+      FirmWare Update
+
+   GIC
+      Generic Interrupt Controller
+
+   ISA
+      Instruction Set Architecture
+
+   Linaro
+      A collaborative engineering organization consolidating
+      and optimizing open source software and tools for the Arm architecture.
+
+   MMU
+      Memory Management Unit
+
+   MPAM
+      Memory Partitioning And Monitoring. An optional Armv8.4 extension.
+
+   MPIDR
+      Multiprocessor Affinity Register
+
+   OEN
+      Owning Entity Number
+
+   OP-TEE
+      Open Portable Trusted Execution Environment. An example of a :term:`TEE`
+
+   OTE
+      Open-source Trusted Execution Environment
+
+   PDD
+      Platform Design Document
+
+   PMF
+      Performance Measurement Framework
+
+   PSCI
+      Power State Coordination Interface
+
+   RAS
+      Reliability, Availability, and Serviceability extensions. A mandatory
+      extension for the Armv8.2 architecture and later. An optional extension to
+      the base Armv8 architecture.
+
+   ROT
+      Root of Trust
+
+   SCMI
+      System Control and Management Interface
+
+   SCP
+      System Control Processor
+
+   SDEI
+      Software Delegated Exception Interface
+
+   SDS
+      Shared Data Storage
+
+   SEA
+      Synchronous External Abort
+
+   SiP
+   SIP
+      Silicon Provider
+
+   SMC
+      Secure Monitor Call
+
+   SMCCC
+      :term:`SMC` Calling Convention
+
+   SoC
+      System on Chip
+
+   SP
+      Secure Partition
+
+   SPD
+      Secure Payload Dispatcher
+
+   SPM
+      Secure Partition Manager
+
+   SVE
+      Scalable Vector Extension
+
+   TBB
+      Trusted Board Boot
+
+   TBBR
+      Trusted Board Boot Requirements
+
+   TEE
+      Trusted Execution Environment
+
+   TF-A
+      Trusted Firmware-A
+
+   TF-M
+      Trusted Firmware-M
+
+   TLB
+      Translation Lookaside Buffer
+
+   TLK
+      Trusted Little Kernel. A Trusted OS from NVIDIA.
+
+   TSP
+      Test Secure Payload
+
+   TZC
+      TrustZone Controller
+
+   UEFI
+      Unified Extensible Firmware Interface
+
+   WDOG
+      Watchdog
+
+   XLAT
+      Translation (abbr.). For example, "XLAT table".
+
+.. _`Arm Glossary`: https://developer.arm.com/support/arm-glossary
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..2023ceb
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,304 @@
+Trusted Firmware-A Documentation
+================================
+
+.. toctree::
+   :maxdepth: 1
+   :hidden:
+
+   Home<self>
+   getting_started/index
+   process/index
+   components/index
+   design/index
+   plat/index
+   perf/index
+   security_advisories/index
+   change-log
+   acknowledgements
+   glossary
+   maintainers
+   license
+
+.. contents:: On This Page
+    :depth: 3
+
+Trusted Firmware-A (TF-A) provides a reference implementation of secure world
+software for `Armv7-A and Armv8-A`_, including a `Secure Monitor`_ executing
+at Exception Level 3 (EL3). It implements various Arm interface standards,
+such as:
+
+-  The `Power State Coordination Interface (PSCI)`_
+-  `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT)`_
+-  `SMC Calling Convention`_
+-  `System Control and Management Interface (SCMI)`_
+-  `Software Delegated Exception Interface (SDEI)`_
+
+Where possible, the code is designed for reuse or porting to other Armv7-A and
+Armv8-A model and hardware platforms.
+
+This release provides a suitable starting point for productization of secure
+world boot and runtime firmware, in either the AArch32 or AArch64 execution
+states.
+
+Users are encouraged to do their own security validation, including penetration
+testing, on any secure world code derived from TF-A.
+
+Arm will continue development in collaboration with interested parties to
+provide a full reference implementation of Secure Monitor code and Arm standards
+to the benefit of all developers working with Armv7-A and Armv8-A TrustZone
+technology.
+
+Functionality
+-------------
+
+-  Initialization of the secure world, for example exception vectors, control
+   registers and interrupts for the platform.
+
+-  Library support for CPU specific reset and power down sequences. This
+   includes support for errata workarounds and the latest Arm DynamIQ CPUs.
+
+-  Drivers to enable standard initialization of Arm System IP, for example
+   Generic Interrupt Controller (GIC), Cache Coherent Interconnect (CCI),
+   Cache Coherent Network (CCN), Network Interconnect (NIC) and TrustZone
+   Controller (TZC).
+
+-  A generic `SCMI`_ driver to interface with conforming power controllers, for
+   example the Arm System Control Processor (SCP).
+
+-  SMC (Secure Monitor Call) handling, conforming to the `SMC Calling
+   Convention`_ using an EL3 runtime services framework.
+
+-  `PSCI`_ library support for CPU, cluster and system power management
+   use-cases.
+   This library is pre-integrated with the AArch64 EL3 Runtime Software, and
+   is also suitable for integration with other AArch32 EL3 Runtime Software,
+   for example an AArch32 Secure OS.
+
+-  A minimal AArch32 Secure Payload (SP\_MIN) to demonstrate `PSCI`_ library
+   integration with AArch32 EL3 Runtime Software.
+
+-  Secure Monitor library code such as world switching, EL1 context management
+   and interrupt routing.
+   When a Secure-EL1 Payload (SP) is present, for example a Secure OS, the
+   AArch64 EL3 Runtime Software must be integrated with a Secure Payload
+   Dispatcher (SPD) component to customize the interaction with the SP.
+
+-  A Test SP and SPD to demonstrate AArch64 Secure Monitor functionality and SP
+   interaction with PSCI.
+
+-  SPDs for the `OP-TEE Secure OS`_, `NVIDIA Trusted Little Kernel`_
+   and `Trusty Secure OS`_.
+
+-  A Trusted Board Boot implementation, conforming to all mandatory TBBR
+   requirements. This includes image authentication, Firmware Update (or
+   recovery mode), and packaging of the various firmware images into a
+   Firmware Image Package (FIP).
+
+-  Pre-integration of TBB with the Arm CryptoCell product, to take advantage of
+   its hardware Root of Trust and crypto acceleration services.
+
+-  Reliability, Availability, and Serviceability (RAS) functionality, including
+
+   -  A Secure Partition Manager (SPM) to manage Secure Partitions in
+      Secure-EL0, which can be used to implement simple management and
+      security services.
+
+   -  An |SDEI| dispatcher to route interrupt-based |SDEI| events.
+
+   -  An Exception Handling Framework (EHF) that allows dispatching of EL3
+      interrupts to their registered handlers, to facilitate firmware-first
+      error handling.
+
+-  A dynamic configuration framework that enables each of the firmware images
+   to be configured at runtime if required by the platform. It also enables
+   loading of a hardware configuration (for example, a kernel device tree)
+   as part of the FIP, to be passed through the firmware stages.
+
+-  Support for alternative boot flows, for example to support platforms where
+   the EL3 Runtime Software is loaded using other firmware or a separate
+   secure system processor, or where a non-TF-A ROM expects BL2 to be loaded
+   at EL3.
+
+-  Support for the GCC, LLVM and Arm Compiler 6 toolchains.
+
+-  Support for combining several libraries into a "romlib" image that may be
+   shared across images to reduce memory footprint. The romlib image is stored
+   in ROM but is accessed through a jump-table that may be stored
+   in read-write memory, allowing for the library code to be patched.
+
+-  A prototype implementation of a Secure Partition Manager (SPM) that is based
+   on the SPCI Alpha 1 and SPRT draft specifications.
+
+-  Support for ARMv8.3 pointer authentication in the normal and secure worlds.
+   The use of pointer authentication in the normal world is enabled whenever
+   architectural support is available, without the need for additional build
+   flags. Use of pointer authentication in the secure world remains an
+   experimental configuration at this time and requires the ``ENABLE_PAUTH``
+   build flag to be set.
+
+-  Position-Independent Executable (PIE) support. Initially for BL31 only, with
+   further support to be added in a future release.
+
+For a full description of functionality and implementation details, please
+see the `Firmware Design`_ and supporting documentation. The `Change Log`_
+provides details of changes made since the last release.
+
+Platforms
+---------
+
+Various AArch32 and AArch64 builds of this release have been tested on r0, r1
+and r2 variants of the `Juno Arm Development Platform`_.
+
+The latest version of the AArch64 build of TF-A has been tested on the following
+Arm FVPs without shifted affinities, and that do not support threaded CPU cores
+(64-bit host machine only).
+
+.. note::
+   The FVP models used are Version 11.5 Build 33, unless otherwise stated.
+
+-  ``FVP_Base_AEMv8A-AEMv8A``
+-  ``FVP_Base_AEMv8A-AEMv8A-AEMv8A-AEMv8A-CCN502``
+-  ``FVP_Base_RevC-2xAEMv8A``
+-  ``FVP_Base_Cortex-A32x4``
+-  ``FVP_Base_Cortex-A35x4``
+-  ``FVP_Base_Cortex-A53x4``
+-  ``FVP_Base_Cortex-A55x4+Cortex-A75x4``
+-  ``FVP_Base_Cortex-A55x4``
+-  ``FVP_Base_Cortex-A57x1-A53x1``
+-  ``FVP_Base_Cortex-A57x2-A53x4``
+-  ``FVP_Base_Cortex-A57x4-A53x4``
+-  ``FVP_Base_Cortex-A57x4``
+-  ``FVP_Base_Cortex-A72x4-A53x4``
+-  ``FVP_Base_Cortex-A72x4``
+-  ``FVP_Base_Cortex-A73x4-A53x4``
+-  ``FVP_Base_Cortex-A73x4``
+-  ``FVP_Base_Cortex-A75x4``
+-  ``FVP_Base_Cortex-A76x4``
+-  ``FVP_Base_Cortex-A76AEx4`` (Tested with internal model)
+-  ``FVP_Base_Cortex-A76AEx8`` (Tested with internal model)
+-  ``FVP_Base_Cortex-A77x4`` (Version 11.7 build 36)
+-  ``FVP_Base_Neoverse-N1x4`` (Tested with internal model)
+-  ``FVP_CSS_SGI-575`` (Version 11.3 build 42)
+-  ``FVP_CSS_SGM-775`` (Version 11.3 build 42)
+-  ``FVP_RD_E1Edge`` (Version 11.3 build 42)
+-  ``FVP_RD_N1Edge`` (Version 11.3 build 42)
+-  ``Foundation_Platform``
+
+The latest version of the AArch32 build of TF-A has been tested on the following
+Arm FVPs without shifted affinities, and that do not support threaded CPU cores
+(64-bit host machine only).
+
+-  ``FVP_Base_AEMv8A-AEMv8A``
+-  ``FVP_Base_Cortex-A32x4``
+
+.. note::
+   The ``FVP_Base_RevC-2xAEMv8A`` FVP only supports shifted affinities.
+
+The Foundation FVP can be downloaded free of charge. The Base FVPs can be
+licensed from Arm. See the `Arm FVP website`_.
+
+All the above platforms have been tested with `Linaro Release 18.04`_.
+
+This release also contains the following platform support:
+
+-  Allwinner sun50i_a64 and sun50i_h6
+-  Amlogic Meson S905 (GXBB)
+-  Arm Juno Software Development Platform
+-  Arm Neoverse N1 System Development Platform (N1SDP)
+-  Arm Neoverse Reference Design N1 Edge (RD-N1-Edge) FVP
+-  Arm Neoverse Reference Design E1 Edge (RD-E1-Edge) FVP
+-  Arm SGI-575 and SGM-775
+-  Arm Versatile Express FVP
+-  HiKey, HiKey960 and Poplar boards
+-  Intel Stratix 10 SoC FPGA
+-  Marvell Armada 3700 and 8K
+-  MediaTek MT6795 and MT8173 SoCs
+-  NVIDIA T132, T186 and T210 SoCs
+-  NXP QorIQ LS1043A, i.MX8MM, i.MX8MQ, i.MX8QX, i.MX8QM and i.MX7Solo WaRP7
+-  QEMU
+-  Raspberry Pi 3
+-  Renesas R-Car Generation 3
+-  RockChip RK3328, RK3368 and RK3399 SoCs
+-  Socionext UniPhier SoC family and SynQuacer SC2A11 SoCs
+-  STMicroelectronics STM32MP1
+-  Texas Instruments K3 SoCs
+-  Xilinx Versal and Zynq UltraScale + MPSoC
+
+Still to come
+-------------
+
+-  Support for additional platforms.
+
+-  Refinements to Position Independent Executable (PIE) support.
+
+-  Refinements to the SPCI-based SPM implementation as the draft SPCI and SPRT
+   specifications continue to evolve.
+
+-  Documentation enhancements.
+
+-  Ongoing support for new architectural features, CPUs and System IP.
+
+-  Ongoing support for new Arm system architecture specifications.
+
+-  Ongoing security hardening, optimization and quality improvements.
+
+For a full list of detailed issues in the current code, please see the `Change
+Log`_ and the `issue tracker`_.
+
+Getting started
+---------------
+
+See the `User Guide`_ for instructions on how to download, install, build and
+use TF-A with the Arm `FVP`_\ s.
+
+See the `Firmware Design`_ for information on how TF-A works.
+
+See the `Porting Guide`_ as well for information about how to use this
+software on another Armv7-A or Armv8-A platform.
+
+See the `Contributing Guidelines`_ for information on how to contribute to this
+project and the `Acknowledgments`_ file for a list of contributors to the
+project.
+
+Contact us
+~~~~~~~~~~
+
+We welcome any feedback on TF-A. If you think you have found a security
+vulnerability, please report this using the process defined in the TF-A
+`Security Center`_. For all other feedback, you can use either the
+`issue tracker`_ or our `mailing list`_.
+
+Arm licensees may contact Arm directly via their partner managers.
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Armv7-A and Armv8-A: https://developer.arm.com/products/architecture/a-profile
+.. _Secure Monitor: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php
+.. _Power State Coordination Interface (PSCI): PSCI_
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
+.. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+.. _System Control and Management Interface (SCMI): SCMI_
+.. _SCMI: http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf
+.. _Software Delegated Exception Interface (SDEI): SDEI_
+.. _SDEI: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _Juno Arm Development Platform: http://www.arm.com/products/tools/development-boards/versatile-express/juno-arm-development-platform.php
+.. _Arm FVP website: FVP_
+.. _FVP: https://developer.arm.com/products/system-design/fixed-virtual-platforms
+.. _Linaro Release 18.04: https://community.arm.com/dev-platforms/b/documents/posts/linaro-release-notes-deprecated#LinaroRelease18.04
+.. _OP-TEE Secure OS: https://github.com/OP-TEE/optee_os
+.. _NVIDIA Trusted Little Kernel: http://nv-tegra.nvidia.com/gitweb/?p=3rdparty/ote_partner/tlk.git;a=summary
+.. _Trusty Secure OS: https://source.android.com/security/trusty
+.. _trustedfirmware.org: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+.. _issue tracker: https://issues.trustedfirmware.org
+.. _mailing list: https://lists.trustedfirmware.org/mailman/listinfo/tf-a
+.. _Security Center: ./process/security.rst
+.. _license: ./license.rst
+.. _Contributing Guidelines: ./process/contributing.rst
+.. _Acknowledgments: ./acknowledgements.rst
+.. _Firmware Design: ./design/firmware-design.rst
+.. _Change Log: ./change-log.rst
+.. _User Guide: ./getting_started/user-guide.rst
+.. _Porting Guide: ./getting_started/porting-guide.rst
diff --git a/docs/license.rst b/docs/license.rst
new file mode 100644
index 0000000..b62286f
--- /dev/null
+++ b/docs/license.rst
@@ -0,0 +1,80 @@
+License
+=======
+
+The software is provided under a BSD-3-Clause license (below). Contributions to
+this project are accepted under the same license with developer sign-off as
+described in the :ref:`contributor_guide`.
+
+::
+
+    Copyright (c) [XXXX-]YYYY, <OWNER>. All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without modification,
+    are permitted provided that the following conditions are met:
+
+    -  Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+
+    -  Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+    -  Neither the name of Arm nor the names of its contributors may be used to
+    endorse or promote products derived from this software without specific
+    prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+SPDX Identifiers
+----------------
+
+Individual files contain the following tag instead of the full license text.
+
+::
+
+    SPDX-License-Identifier:    BSD-3-Clause
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
+
+
+Other Projects
+--------------
+
+This project contains code from other projects as listed below. The original
+license text is included in those source files.
+
+-  The libc source code is derived from `FreeBSD`_ and `SCC`_. FreeBSD uses
+   various BSD licenses, including BSD-3-Clause and BSD-2-Clause. The SCC code
+   is used under the BSD-3-Clause license with the author's permission.
+
+-  The libfdt source code is disjunctively dual licensed
+   (GPL-2.0+ OR BSD-2-Clause). It is used by this project under the terms of
+   the BSD-2-Clause license. Any contributions to this code must be made under
+   the terms of both licenses.
+
+-  The LLVM compiler-rt source code is disjunctively dual licensed
+   (NCSA OR MIT). It is used by this project under the terms of the NCSA
+   license (also known as the University of Illinois/NCSA Open Source License),
+   which is a permissive license compatible with BSD-3-Clause. Any
+   contributions to this code must be made under the terms of both licenses.
+
+-  The zlib source code is licensed under the Zlib license, which is a
+   permissive license compatible with BSD-3-Clause.
+
+-  Some STMicroelectronics platform source code is disjunctively dual licensed
+   (GPL-2.0+ OR BSD-3-Clause). It is used by this project under the terms of the
+   BSD-3-Clause license. Any contributions to this code must be made under the
+   terms of both licenses.
+
+.. _FreeBSD: http://www.freebsd.org
+.. _SCC: http://www.simple-cc.org/
\ No newline at end of file
diff --git a/docs/maintainers.rst b/docs/maintainers.rst
new file mode 100644
index 0000000..cbfc652
--- /dev/null
+++ b/docs/maintainers.rst
@@ -0,0 +1,306 @@
+Maintainers
+===========
+
+Trusted Firmware-A (TF-A) is an Arm maintained project. All contributions are
+ultimately merged by the maintainers listed below. Technical ownership of some
+parts of the codebase is delegated to the sub-maintainers listed below. An
+acknowledgement from these sub-maintainers may be required before the
+maintainers merge a contribution.
+
+Main maintainers
+----------------
+:M: Dan Handley <dan.handley@arm.com>
+:G: `danh-arm`_
+:M: Soby Mathew <soby.mathew@arm.com>
+:G: `soby-mathew`_
+:M: Sandrine Bailleux <sandrine.bailleux@arm.com>
+:G: `sandrine-bailleux-arm`_
+:M: Alexei Fedorov <alexei.fedorov@arm.com>
+:G: `AlexeiFedorov`_
+:M: Paul Beesley <paul.beesley@arm.com>
+:G: `pbeesley-arm`_
+:M: John Tsichritzis <john.tsichritzis@arm.com>
+:G: `jts-arm`_
+
+Allwinner ARMv8 platform port
+-----------------------------
+:M: Andre Przywara <andre.przywara@arm.com>
+:G: `Andre-ARM`_
+:M: Samuel Holland <samuel@sholland.org>
+:G: `smaeul`_
+:F: docs/plat/allwinner.rst
+:F: plat/allwinner/
+:F: drivers/allwinner/
+
+Amlogic Meson S905 (GXBB) platform port
+---------------------------------------
+:M: Andre Przywara <andre.przywara@arm.com>
+:G: `Andre-ARM`_
+:F: docs/plat/meson-gxbb.rst
+:F: drivers/meson/
+:F: plat/meson/gxbb/
+
+Amlogic Meson S905x (GXL) platform port
+---------------------------------------
+:M: Remi Pommarel <repk@triplefau.lt>
+:G: `remi-triplefault`_
+:F: docs/plat/meson-gxl.rst
+:F: drivers/meson/gxl
+:F: plat/meson/gxl/
+
+Armv7-A architecture port
+-------------------------
+:M: Etienne Carriere <etienne.carriere@linaro.org>
+:G: `etienne-lms`_
+
+Arm System Guidance for Infrastructure / Mobile FVP platforms
+-------------------------------------------------------------
+:M: Nariman Poushin <nariman.poushin@linaro.org>
+:G: `npoushin`_
+:M: Thomas Abraham <thomas.abraham@arm.com>
+:G: `thomas-arm`_
+:F: plat/arm/css/sgi/
+:F: plat/arm/css/sgm/
+:F: plat/arm/board/sgi575/
+:F: plat/arm/board/sgm775/
+
+Console API framework
+---------------------
+:M: Julius Werner <jwerner@chromium.org>
+:G: `jwerner-chromium`_
+:F: drivers/console/
+:F: include/drivers/console.h
+:F: plat/common/aarch64/crash_console_helpers.S
+
+coreboot support libraries
+--------------------------
+:M: Julius Werner <jwerner@chromium.org>
+:G: `jwerner-chromium`_
+:F: drivers/coreboot/
+:F: include/drivers/coreboot/
+:F: include/lib/coreboot.h
+:F: lib/coreboot/
+
+eMMC/UFS drivers
+----------------
+:M: Haojian Zhuang <haojian.zhuang@linaro.org>
+:G: `hzhuang1`_
+:F: drivers/partition/
+:F: drivers/synopsys/emmc/
+:F: drivers/synopsys/ufs/
+:F: drivers/ufs/
+:F: include/drivers/dw_ufs.h
+:F: include/drivers/ufs.h
+:F: include/drivers/synopsys/dw_mmc.h
+
+HiSilicon HiKey and HiKey960 platform ports
+-------------------------------------------
+:M: Haojian Zhuang <haojian.zhuang@linaro.org>
+:G: `hzhuang1`_
+:F: docs/plat/hikey.rst
+:F: docs/plat/hikey960.rst
+:F: plat/hisilicon/hikey/
+:F: plat/hisilicon/hikey960/
+
+HiSilicon Poplar platform port
+------------------------------
+:M: Shawn Guo <shawn.guo@linaro.org>
+:G: `shawnguo2`_
+:F: docs/plat/poplar.rst
+:F: plat/hisilicon/poplar/
+
+Intel SocFPGA platform ports
+----------------------------
+:M: Tien Hock Loh <tien.hock.loh@intel.com>
+:G: `thloh85-intel`_
+:M: Hadi Asyrafi <muhammad.hadi.asyrafi.abdul.halim@intel.com>
+:G: `mabdulha`_
+:F: plat/intel/soc
+:F: drivers/intel/soc/
+
+MediaTek platform ports
+-----------------------
+:M: Yidi Lin (林以廸) <yidi.lin@mediatek.com>
+:G: `mtk09422`_
+:F: plat/mediatek/
+
+Marvell platform ports and SoC drivers
+--------------------------------------
+:M: Konstantin Porotchkin <kostap@marvell.com>
+:G: `kostapr`_
+:F: docs/marvell/
+:F: plat/marvell/
+:F: drivers/marvell/
+:F: tools/marvell/
+
+NVidia platform ports
+---------------------
+:M: Varun Wadekar <vwadekar@nvidia.com>
+:G: `vwadekar`_
+:F: docs/plat/nvidia-tegra.rst
+:F: include/lib/cpus/aarch64/denver.h
+:F: lib/cpus/aarch64/denver.S
+:F: plat/nvidia/
+
+NXP QorIQ Layerscape platform ports
+-----------------------------------
+:M: Jiafei Pan <jiafei.pan@nxp.com>
+:G: `qoriq-open-source`_
+:F: docs/plat/ls1043a.rst
+:F: plat/layerscape/
+
+NXP i.MX 7 WaRP7 platform port and SoC drivers
+----------------------------------------------
+:M: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+:G: `bryanodonoghue`_
+:M: Jun Nie <jun.nie@linaro.org>
+:G: `niej`_
+:F: docs/plat/warp7.rst
+:F: plat/imx/common/
+:F: plat/imx/imx7/
+:F: drivers/imx/timer/
+:F: drivers/imx/uart/
+:F: drivers/imx/usdhc/
+
+NXP i.MX 8 platform port
+------------------------
+:M: Anson Huang <Anson.Huang@nxp.com>
+:G: `Anson-Huang`_
+:F: docs/plat/imx8.rst
+:F: plat/imx/
+
+NXP i.MX8M platform port
+------------------------
+:M: Jacky Bai <ping.bai@nxp.com>
+:G: `JackyBai`_
+:F: doc/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: services/spd/opteed/
+
+QEMU platform port
+------------------
+:M: Jens Wiklander <jens.wiklander@linaro.org>
+:G: `jenswi-linaro`_
+:F: docs/plat/qemu.rst
+:F: plat/qemu/
+
+Raspberry Pi 3 platform port
+----------------------------
+:M: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+:G: `grandpaul`_
+:F: docs/plat/rpi3.rst
+:F: plat/rpi3/
+:F: drivers/rpi3/
+:F: include/drivers/rpi3/
+
+Renesas rcar-gen3 platform port
+-------------------------------
+:M: Jorge Ramirez-Ortiz  <jramirez@baylibre.com>
+:G: `ldts`_
+:M: Marek Vasut <marek.vasut@gmail.com>
+:G: `marex`_
+:F: docs/plat/rcar-gen3.rst
+:F: plat/renesas/rcar
+:F: drivers/renesas/rcar
+:F: tools/renesas/rcar_layout_create
+
+RockChip platform port
+----------------------
+:M: Tony Xie <tony.xie@rock-chips.com>
+:G: `TonyXie06`_
+:G: `rockchip-linux`_
+:M: Heiko Stuebner <heiko@sntech.de>
+:G: `mmind`_
+:F: plat/rockchip/
+
+STM32MP1 platform port
+----------------------
+:M: Yann Gautier <yann.gautier@st.com>
+:G: `Yann-lms`_
+:F: docs/plat/stm32mp1.rst
+:F: drivers/st/
+:F: fdts/stm32\*
+:F: include/drivers/st/
+:F: include/dt-bindings/\*/stm32\*
+:F: plat/st/
+:F: tools/stm32image/
+
+Synquacer platform port
+-----------------------
+:M: Sumit Garg <sumit.garg@linaro.org>
+:G: `b49020`_
+:F: docs/plat/synquacer.rst
+:F: plat/socionext/synquacer/
+
+Texas Instruments platform port
+-------------------------------
+:M: Andrew F. Davis <afd@ti.com>
+:G: `glneo`_
+:F: docs/plat/ti-k3.rst
+:F: plat/ti/
+
+TLK/Trusty secure payloads
+--------------------------
+:M: Varun Wadekar <vwadekar@nvidia.com>
+:G: `vwadekar`_
+:F: docs/spd/tlk-dispatcher.rst
+:F: docs/spd/trusty-dispatcher.rst
+:F: include/bl32/payloads/tlk.h
+:F: services/spd/tlkd/
+:F: services/spd/trusty/
+
+UniPhier platform port
+----------------------
+:M: Masahiro Yamada <yamada.masahiro@socionext.com>
+:G: `masahir0y`_
+:F: docs/plat/socionext-uniphier.rst
+:F: plat/socionext/uniphier/
+
+Xilinx platform port
+--------------------
+:M: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
+:G: `sivadur`_
+:F: docs/plat/xilinx-zynqmp.rst
+:F: plat/xilinx/
+
+.. _AlexeiFedorov: https://github.com/AlexeiFedorov
+.. _Andre-ARM: https://github.com/Andre-ARM
+.. _Anson-Huang: https://github.com/Anson-Huang
+.. _bryanodonoghue: https://github.com/bryanodonoghue
+.. _b49020: https://github.com/b49020
+.. _danh-arm: https://github.com/danh-arm
+.. _etienne-lms: https://github.com/etienne-lms
+.. _glneo: https://github.com/glneo
+.. _grandpaul: https://github.com/grandpaul
+.. _hzhuang1: https://github.com/hzhuang1
+.. _JackyBai: https://github.com/JackyBai
+.. _jenswi-linaro: https://github.com/jenswi-linaro
+.. _jts-arm: https://github.com/jts-arm
+.. _jwerner-chromium: https://github.com/jwerner-chromium
+.. _kostapr: https://github.com/kostapr
+.. _ldts: https://github.com/ldts
+.. _marex: https://github.com/marex
+.. _masahir0y: https://github.com/masahir0y
+.. _mmind: https://github.com/mmind
+.. _mtk09422: https://github.com/mtk09422
+.. _niej: https://github.com/niej
+.. _npoushin: https://github.com/npoushin
+.. _pbeesley-arm: https://github.com/pbeesley-arm
+.. _qoriq-open-source: https://github.com/qoriq-open-source
+.. _remi-triplefault: https://github.com/repk
+.. _rockchip-linux: https://github.com/rockchip-linux
+.. _sandrine-bailleux-arm: https://github.com/sandrine-bailleux-arm
+.. _shawnguo2: https://github.com/shawnguo2
+.. _sivadur: https://github.com/sivadur
+.. _smaeul: https://github.com/smaeul
+.. _soby-mathew: https://github.com/soby-mathew
+.. _thomas-arm: https://github.com/thomas-arm
+.. _TonyXie06: https://github.com/TonyXie06
+.. _vwadekar: https://github.com/vwadekar
+.. _Yann-lms: https://github.com/Yann-lms
diff --git a/docs/perf/index.rst b/docs/perf/index.rst
new file mode 100644
index 0000000..50833b8
--- /dev/null
+++ b/docs/perf/index.rst
@@ -0,0 +1,9 @@
+Performance & Testing
+=====================
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   psci-performance-juno
diff --git a/docs/perf/psci-performance-juno.rst b/docs/perf/psci-performance-juno.rst
new file mode 100644
index 0000000..4cc4302
--- /dev/null
+++ b/docs/perf/psci-performance-juno.rst
@@ -0,0 +1,292 @@
+PSCI Performance Measurements on Arm Juno Development Platform
+==============================================================
+
+This document summarises the findings of performance measurements of key
+operations in the Trusted Firmware-A Power State Coordination Interface (PSCI)
+implementation, using the in-built Performance Measurement Framework (PMF) and
+runtime instrumentation timestamps.
+
+Method
+------
+
+We used the `Juno R1 platform`_ for these tests, which has 4 x Cortex-A53 and 2
+x Cortex-A57 clusters running at the following frequencies:
+
++-----------------+--------------------+
+| Domain          | Frequency (MHz)    |
++=================+====================+
+| Cortex-A57      | 900 (nominal)      |
++-----------------+--------------------+
+| Cortex-A53      | 650 (underdrive)   |
++-----------------+--------------------+
+| AXI subsystem   | 533                |
++-----------------+--------------------+
+
+Juno supports CPU, cluster and system power down states, corresponding to power
+levels 0, 1 and 2 respectively. It does not support any retention states.
+
+We used the upstream `TF master as of 31/01/2017`_, building the platform using
+the ``ENABLE_RUNTIME_INSTRUMENTATION`` option:
+
+.. code:: shell
+
+    make PLAT=juno ENABLE_RUNTIME_INSTRUMENTATION=1 \
+        SCP_BL2=<path/to/scp-fw.bin>                \
+        BL33=<path/to/test-fw.bin>                  \
+        all fip
+
+When using the debug build of TF, there was no noticeable difference in the
+results.
+
+The tests are based on an ARM-internal test framework. The release build of this
+framework was used because the results in the debug build became skewed; the
+console output prevented some of the tests from executing in parallel.
+
+The tests consist of both parallel and sequential tests, which are broadly
+described as follows:
+
+- **Parallel Tests** This type of test powers on all the non-lead CPUs and
+  brings them and the lead CPU to a common synchronization point.  The lead CPU
+  then initiates the test on all CPUs in parallel.
+
+- **Sequential Tests** This type of test powers on each non-lead CPU in
+  sequence. The lead CPU initiates the test on a non-lead CPU then waits for the
+  test to complete before proceeding to the next non-lead CPU. The lead CPU then
+  executes the test on itself.
+
+In the results below, CPUs 0-3 refer to CPUs in the little cluster (A53) and
+CPUs 4-5 refer to CPUs in the big cluster (A57). In all cases CPU 4 is the lead
+CPU.
+
+``PSCI_ENTRY`` refers to the time taken from entering the TF PSCI implementation
+to the point the hardware enters the low power state (WFI). Referring to the TF
+runtime instrumentation points, this corresponds to:
+``(RT_INSTR_ENTER_HW_LOW_PWR - RT_INSTR_ENTER_PSCI)``.
+
+``PSCI_EXIT`` refers to the time taken from the point the hardware exits the low
+power state to exiting the TF PSCI implementation. This corresponds to:
+``(RT_INSTR_EXIT_PSCI - RT_INSTR_EXIT_HW_LOW_PWR)``.
+
+``CFLUSH_OVERHEAD`` refers to the part of ``PSCI_ENTRY`` taken to flush the
+caches. This corresponds to: ``(RT_INSTR_EXIT_CFLUSH - RT_INSTR_ENTER_CFLUSH)``.
+
+Note there is very little variance observed in the values given (~1us), although
+the values for each CPU are sometimes interchanged, depending on the order in
+which locks are acquired. Also, there is very little variance observed between
+executing the tests sequentially in a single boot or rebooting between tests.
+
+Given that runtime instrumentation using PMF is invasive, there is a small
+(unquantified) overhead on the results. PMF uses the generic counter for
+timestamps, which runs at 50MHz on Juno.
+
+Results and Commentary
+----------------------
+
+``CPU_SUSPEND`` to deepest power level on all CPUs in parallel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
++-------+---------------------+--------------------+--------------------------+
+| CPU   | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) |
++=======+=====================+====================+==========================+
+| 0     | 27                  | 20                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 1     | 114                 | 86                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 2     | 202                 | 58                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 3     | 375                 | 29                 | 94                       |
++-------+---------------------+--------------------+--------------------------+
+| 4     | 20                  | 22                 | 6                        |
++-------+---------------------+--------------------+--------------------------+
+| 5     | 290                 | 18                 | 206                      |
++-------+---------------------+--------------------+--------------------------+
+
+A large variance in ``PSCI_ENTRY`` and ``PSCI_EXIT`` times across CPUs is
+observed due to TF PSCI lock contention. In the worst case, CPU 3 has to wait
+for the 3 other CPUs in the cluster (0-2) to complete ``PSCI_ENTRY`` and release
+the lock before proceeding.
+
+The ``CFLUSH_OVERHEAD`` times for CPUs 3 and 5 are higher because they are the
+last CPUs in their respective clusters to power down, therefore both the L1 and
+L2 caches are flushed.
+
+The ``CFLUSH_OVERHEAD`` time for CPU 5 is a lot larger than that for CPU 3
+because the L2 cache size for the big cluster is lot larger (2MB) compared to
+the little cluster (1MB).
+
+``CPU_SUSPEND`` to power level 0 on all CPUs in parallel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
++-------+---------------------+--------------------+--------------------------+
+| CPU   | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) |
++=======+=====================+====================+==========================+
+| 0     | 116                 | 14                 | 8                        |
++-------+---------------------+--------------------+--------------------------+
+| 1     | 204                 | 14                 | 8                        |
++-------+---------------------+--------------------+--------------------------+
+| 2     | 287                 | 13                 | 8                        |
++-------+---------------------+--------------------+--------------------------+
+| 3     | 376                 | 13                 | 9                        |
++-------+---------------------+--------------------+--------------------------+
+| 4     | 29                  | 15                 | 7                        |
++-------+---------------------+--------------------+--------------------------+
+| 5     | 21                  | 15                 | 8                        |
++-------+---------------------+--------------------+--------------------------+
+
+There is no lock contention in TF generic code at power level 0 but the large
+variance in ``PSCI_ENTRY`` times across CPUs is due to lock contention in Juno
+platform code. The platform lock is used to mediate access to a single SCP
+communication channel. This is compounded by the SCP firmware waiting for each
+AP CPU to enter WFI before making the channel available to other CPUs, which
+effectively serializes the SCP power down commands from all CPUs.
+
+On platforms with a more efficient CPU power down mechanism, it should be
+possible to make the ``PSCI_ENTRY`` times smaller and consistent.
+
+The ``PSCI_EXIT`` times are consistent across all CPUs because TF does not
+require locks at power level 0.
+
+The ``CFLUSH_OVERHEAD`` times for all CPUs are small and consistent since only
+the cache associated with power level 0 is flushed (L1).
+
+``CPU_SUSPEND`` to deepest power level on all CPUs in sequence
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
++-------+---------------------+--------------------+--------------------------+
+| CPU   | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) |
++=======+=====================+====================+==========================+
+| 0     | 114                 | 20                 | 94                       |
++-------+---------------------+--------------------+--------------------------+
+| 1     | 114                 | 20                 | 94                       |
++-------+---------------------+--------------------+--------------------------+
+| 2     | 114                 | 20                 | 94                       |
++-------+---------------------+--------------------+--------------------------+
+| 3     | 114                 | 20                 | 94                       |
++-------+---------------------+--------------------+--------------------------+
+| 4     | 195                 | 22                 | 180                      |
++-------+---------------------+--------------------+--------------------------+
+| 5     | 21                  | 17                 | 6                        |
++-------+---------------------+--------------------+--------------------------+
+
+The ``CLUSH_OVERHEAD`` times for lead CPU 4 and all CPUs in the non-lead cluster
+are large because all other CPUs in the cluster are powered down during the
+test. The ``CPU_SUSPEND`` call powers down to the cluster level, requiring a
+flush of both L1 and L2 caches.
+
+The ``CFLUSH_OVERHEAD`` time for CPU 4 is a lot larger than those for the little
+CPUs because the L2 cache size for the big cluster is lot larger (2MB) compared
+to the little cluster (1MB).
+
+The ``PSCI_ENTRY`` and ``CFLUSH_OVERHEAD`` times for CPU 5 are low because lead
+CPU 4 continues to run while CPU 5 is suspended. Hence CPU 5 only powers down to
+level 0, which only requires L1 cache flush.
+
+``CPU_SUSPEND`` to power level 0 on all CPUs in sequence
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
++-------+---------------------+--------------------+--------------------------+
+| CPU   | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) |
++=======+=====================+====================+==========================+
+| 0     | 22                  | 14                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 1     | 22                  | 14                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 2     | 21                  | 14                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 3     | 22                  | 14                 | 5                        |
++-------+---------------------+--------------------+--------------------------+
+| 4     | 17                  | 14                 | 6                        |
++-------+---------------------+--------------------+--------------------------+
+| 5     | 18                  | 15                 | 6                        |
++-------+---------------------+--------------------+--------------------------+
+
+Here the times are small and consistent since there is no contention and it is
+only necessary to flush the cache to power level 0 (L1). This is the best case
+scenario.
+
+The ``PSCI_ENTRY`` times for CPUs in the big cluster are slightly smaller than
+for the CPUs in little cluster due to greater CPU performance.
+
+The ``PSCI_EXIT`` times are generally lower than in the last test because the
+cluster remains powered on throughout the test and there is less code to execute
+on power on (for example, no need to enter CCI coherency)
+
+``CPU_OFF`` on all non-lead CPUs in sequence then ``CPU_SUSPEND`` on lead CPU to deepest power level
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The test sequence here is as follows:
+
+1. Call ``CPU_ON`` and ``CPU_OFF`` on each non-lead CPU in sequence.
+
+2. Program wake up timer and suspend the lead CPU to the deepest power level.
+
+3. Call ``CPU_ON`` on non-lead CPU to get the timestamps from each CPU.
+
++-------+---------------------+--------------------+--------------------------+
+| CPU   | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) |
++=======+=====================+====================+==========================+
+| 0     | 110                 | 28                 | 93                       |
++-------+---------------------+--------------------+--------------------------+
+| 1     | 110                 | 28                 | 93                       |
++-------+---------------------+--------------------+--------------------------+
+| 2     | 110                 | 28                 | 93                       |
++-------+---------------------+--------------------+--------------------------+
+| 3     | 111                 | 28                 | 93                       |
++-------+---------------------+--------------------+--------------------------+
+| 4     | 195                 | 22                 | 181                      |
++-------+---------------------+--------------------+--------------------------+
+| 5     | 20                  | 23                 | 6                        |
++-------+---------------------+--------------------+--------------------------+
+
+The ``CFLUSH_OVERHEAD`` times for all little CPUs are large because all other
+CPUs in that cluster are powerered down during the test. The ``CPU_OFF`` call
+powers down to the cluster level, requiring a flush of both L1 and L2 caches.
+
+The ``PSCI_ENTRY`` and ``CFLUSH_OVERHEAD`` times for CPU 5 are small because
+lead CPU 4 is running and CPU 5 only powers down to level 0, which only requires
+an L1 cache flush.
+
+The ``CFLUSH_OVERHEAD`` time for CPU 4 is a lot larger than those for the little
+CPUs because the L2 cache size for the big cluster is lot larger (2MB) compared
+to the little cluster (1MB).
+
+The ``PSCI_EXIT`` times for CPUs in the big cluster are slightly smaller than
+for CPUs in the little cluster due to greater CPU performance.  These times
+generally are greater than the ``PSCI_EXIT`` times in the ``CPU_SUSPEND`` tests
+because there is more code to execute in the "on finisher" compared to the
+"suspend finisher" (for example, GIC redistributor register programming).
+
+``PSCI_VERSION`` on all CPUs in parallel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Since very little code is associated with ``PSCI_VERSION``, this test
+approximates the round trip latency for handling a fast SMC at EL3 in TF.
+
++-------+-------------------+
+| CPU   | TOTAL TIME (ns)   |
++=======+===================+
+| 0     | 3020              |
++-------+-------------------+
+| 1     | 2940              |
++-------+-------------------+
+| 2     | 2980              |
++-------+-------------------+
+| 3     | 3060              |
++-------+-------------------+
+| 4     | 520               |
++-------+-------------------+
+| 5     | 720               |
++-------+-------------------+
+
+The times for the big CPUs are less than the little CPUs due to greater CPU
+performance.
+
+We suspect the time for lead CPU 4 is shorter than CPU 5 due to subtle cache
+effects, given that these measurements are at the nano-second level.
+
+--------------
+
+*Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Juno R1 platform: https://www.arm.com/files/pdf/Juno_r1_ARM_Dev_datasheet.pdf
+.. _TF master as of 31/01/2017: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/?id=c38b36d
diff --git a/docs/plat/allwinner.rst b/docs/plat/allwinner.rst
new file mode 100644
index 0000000..a1e0659
--- /dev/null
+++ b/docs/plat/allwinner.rst
@@ -0,0 +1,46 @@
+Allwinner ARMv8 SoCs
+====================
+
+Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Allwinner
+SoCs with ARMv8 cores. Only BL31 is used to provide proper EL3 setup and
+PSCI runtime services.
+
+U-Boot's SPL acts as a loader, loading both BL31 and BL33 (typically U-Boot).
+Loading is done from SD card, eMMC or SPI flash, also via an USB debug
+interface (FEL).
+
+BL31 lives in SRAM A2, which is documented to be accessible from secure
+world only.
+
+Current limitations:
+
+-  Missing PMIC support
+
+After building bl31.bin, the binary must be fed to the U-Boot build system
+to include it in the FIT image that the SPL loader will process.
+bl31.bin can be either copied (or sym-linked) into U-Boot's root directory,
+or the environment variable BL31 must contain the binary's path.
+See the respective `U-Boot documentation`_ for more details.
+
+To build for machines with an A64 or H5 SoC:
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_a64 DEBUG=1 bl31
+
+To build for machines with an H6 SoC:
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_h6 DEBUG=1 bl31
+
+.. _U-Boot documentation: http://git.denx.de/?p=u-boot.git;f=board/sunxi/README.sunxi64;hb=HEAD
+
+Trusted OS dispatcher
+---------------------
+
+One can boot Trusted OS(OP-TEE OS, bl32 image) along side bl31 image on Allwinner A64.
+
+In order to include the 'opteed' dispatcher in the image, pass 'SPD=opteed' on the command line
+while compiling the bl31 image and make sure the loader (SPL) loads the Trusted OS binary to
+the beginning of DRAM (0x40000000).
diff --git a/docs/plat/fvp_ve.rst b/docs/plat/fvp_ve.rst
new file mode 100644
index 0000000..6abf9e5
--- /dev/null
+++ b/docs/plat/fvp_ve.rst
@@ -0,0 +1,80 @@
+Arm Versatile Express
+=====================
+
+Versatile Express (VE) family development platform provides an ultra fast
+environment for prototyping Armv7 System-on-Chip designs. VE Fixed Virtual
+Platforms (FVP) are simulations of Versatile Express boards. The platform in
+Trusted Firmware-A has been verified with Arm Cortex-A5 and Cortex-A7 VE FVP's.
+This platform is tested on and only expected to work with single core models.
+
+Boot Sequence
+-------------
+
+BL1 --> BL2 --> BL32(sp_min) --> BL33(u-boot) --> Linux kernel
+
+How to build
+------------
+
+Code Locations
+~~~~~~~~~~~~~~
+-  `U-boot <https://git.linaro.org/landing-teams/working/arm/u-boot.git>`__
+
+-  `Trusted Firmware-A <https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git>`__
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Obtain arm toolchain. The software stack has been verified with linaro 6.2
+   `arm-linux-gnueabihf <https://releases.linaro.org/components/toolchain/binaries/6.2-2016.11/arm-linux-gnueabihf/>`__.
+   Set the CROSS_COMPILE environment variable to point to the toolchain folder.
+
+-  Fetch and build u-boot.
+   Make the .config file using the command:
+
+   .. code:: shell
+
+      make ARCH=arm vexpress_aemv8a_aarch32_config
+
+   Make the u-boot binary for Cortex-A5 using the command:
+
+   .. code:: shell
+
+     make ARCH=arm SUPPORT_ARCH_TIMER=no
+
+   Make the u-boot binary for Cortex-A7 using the command:
+
+   .. code:: shell
+
+     make ARCH=arm
+
+
+-  Build TF-A:
+
+   The make command for Cortex-A5 is:
+
+   .. code:: shell
+
+       make PLAT=fvp_ve ARCH=aarch32 ARM_ARCH_MAJOR=7 ARM_CORTEX_A5=yes \
+       AARCH32_SP=sp_min FVP_HW_CONFIG_DTS=fdts/fvp-ve-Cortex-A5x1.dts \
+       ARM_XLAT_TABLES_LIB_V1=1 BL33=<path_to_u-boot.bin> all fip
+
+   The make command for Cortex-A7 is:
+
+   .. code:: shell
+
+      make PLAT=fvp_ve ARCH=aarch32 ARM_ARCH_MAJOR=7 ARM_CORTEX_A7=yes \
+      AARCH32_SP=sp_min FVP_HW_CONFIG_DTS=fdts/fvp-ve-Cortex-A7x1.dts  \
+      BL33=<path_to_u-boot.bin> all fip
+
+Run Procedure
+~~~~~~~~~~~~~
+
+The following model parameters should be used to boot Linux using the build of
+Trusted Firmware-A made using the above make commands:
+
+  .. code:: shell
+
+    ./<path_to_model> <path_to_bl1.elf> \
+          -C motherboard.flashloader1.fname=<path_to_fip.bin> \
+          --data cluster.cpu0=<path_to_zImage>@0x80080000  \
+          --data cluster.cpu0=<path_to_ramdisk>@0x84000000
diff --git a/docs/plat/hikey.rst b/docs/plat/hikey.rst
new file mode 100644
index 0000000..74ff2f4
--- /dev/null
+++ b/docs/plat/hikey.rst
@@ -0,0 +1,171 @@
+Description
+===========
+
+HiKey is one of 96boards. Hisilicon Kirin6220 processor is installed on HiKey.
+
+More information are listed in `link`_.
+
+How to build
+============
+
+Code Locations
+--------------
+
+-  Trusted Firmware-A:
+   `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+-  OP-TEE
+   `link <https://github.com/OP-TEE/optee_os>`__
+
+-  edk2:
+   `link <https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5>`__
+
+-  OpenPlatformPkg:
+   `link <https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4>`__
+
+-  l-loader:
+   `link <https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2>`__
+
+-  uefi-tools:
+   `link <https://git.linaro.org/uefi/uefi-tools.git>`__
+
+-  atf-fastboot:
+   `link <https://github.com/96boards-hikey/atf-fastboot/tree/master>`__
+
+Build Procedure
+---------------
+
+-  Fetch all the above repositories into local host.
+   Make all the repositories in the same ${BUILD\_PATH}.
+
+  .. code:: shell
+
+       git clone https://github.com/ARM-software/arm-trusted-firmware -b integration
+       git clone https://github.com/OP-TEE/optee_os
+       git clone https://github.com/96boards-hikey/edk2 -b testing/hikey960_v2.5
+       git clone https://github.com/96boards-hikey/OpenPlatformPkg -b testing/hikey960_v1.3.4
+       git clone https://github.com/96boards-hikey/l-loader -b testing/hikey960_v1.2
+       git clone https://git.linaro.org/uefi/uefi-tools
+       git clone https://github.com/96boards-hikey/atf-fastboot
+
+-  Create the symbol link to OpenPlatformPkg in edk2.
+
+   .. code:: shell
+
+       $cd ${BUILD_PATH}/edk2
+       $ln -sf ../OpenPlatformPkg
+
+-  Prepare AARCH64 && AARCH32 toolchain. Prepare python.
+
+-  If your hikey hardware is built by CircuitCo, update *uefi-tools/platform.config* first. *(optional)*
+   **Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
+   console on hikey.**
+
+   .. code:: shell
+
+       BUILDFLAGS=-DSERIAL_BASE=0xF8015000
+
+   If your hikey hardware is built by LeMaker, nothing to do.
+
+-  Build it as debug mode. Create your own build script file or you could refer to **build\_uefi.sh** in l-loader git repository.
+
+   .. code:: shell
+
+       BUILD_OPTION=DEBUG
+       export AARCH64_TOOLCHAIN=GCC5
+       export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools
+       export EDK2_DIR=${BUILD_PATH}/edk2
+       EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}
+       # Build fastboot for Trusted Firmware-A. It's used for recovery mode.
+       cd ${BUILD_PATH}/atf-fastboot
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=hikey DEBUG=1
+       # Convert DEBUG/RELEASE to debug/release
+       FASTBOOT_BUILD_OPTION=$(echo ${BUILD_OPTION} | tr '[A-Z]' '[a-z]')
+       cd ${EDK2_DIR}
+       # Build UEFI & Trusted Firmware-A
+       ${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware -s ../optee_os hikey
+
+-  Generate l-loader.bin and partition table for aosp. The eMMC capacity is either 8GB or 4GB. Just change "aosp-8g" to "linux-8g" for debian.
+
+   .. code:: shell
+
+       cd ${BUILD_PATH}/l-loader
+       ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
+       ln -sf ${EDK2_OUTPUT_DIR}/FV/bl2.bin
+       ln -sf ${BUILD_PATH}/atf-fastboot/build/hikey/${FASTBOOT_BUILD_OPTION}/bl1.bin fastboot.bin
+       make hikey PTABLE_LST=aosp-8g
+
+Setup Console
+-------------
+
+-  Install ser2net. Use telnet as the console since UEFI fails to display Boot Manager GUI in minicom. **If you don't need Boot Manager GUI, just ignore this section.**
+
+   .. code:: shell
+
+       $sudo apt-get install ser2net
+
+-  Configure ser2net.
+
+   .. code:: shell
+
+       $sudo vi /etc/ser2net.conf
+
+   Append one line for serial-over-USB in below.
+   *#ser2net.conf*
+
+   .. code:: shell
+
+       2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner
+
+-  Start ser2net
+
+   .. code:: shell
+
+       $sudo killall ser2net
+       $sudo ser2net -u
+
+-  Open the console.
+
+   .. code:: shell
+
+       $telnet localhost 2004
+
+   And you could open the console remotely, too.
+
+Flash images in recovery mode
+-----------------------------
+
+-  Make sure Pin3-Pin4 on J15 are connected for recovery mode. Then power on HiKey.
+
+-  Remove the modemmanager package. This package may cause the idt tool failure.
+
+   .. code:: shell
+
+       $sudo apt-get purge modemmanager
+
+-  Run the command to download recovery.bin into HiKey.
+
+   .. code:: shell
+
+       $sudo python hisi-idt.py -d /dev/ttyUSB1 --img1 recovery.bin
+
+-  Update images. All aosp or debian images could be fetched from `link <http://releases.linaro.org/96boards/>`__.
+
+   .. code:: shell
+
+       $sudo fastboot flash ptable prm_ptable.img
+       $sudo fastboot flash loader l-loader.bin
+       $sudo fastboot flash fastboot fip.bin
+       $sudo fastboot flash boot boot.img
+       $sudo fastboot flash cache cache.img
+       $sudo fastboot flash system system.img
+       $sudo  fastboot flash userdata userdata.img
+
+Boot UEFI in normal mode
+------------------------
+
+-  Make sure Pin3-Pin4 on J15 are open for normal boot mode. Then power on HiKey.
+
+-  Reference `link <https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md>`__
+
+.. _link: https://www.96boards.org/documentation/consumer/hikey/
diff --git a/docs/plat/hikey960.rst b/docs/plat/hikey960.rst
new file mode 100644
index 0000000..7ddb0b1
--- /dev/null
+++ b/docs/plat/hikey960.rst
@@ -0,0 +1,192 @@
+Description
+===========
+
+HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960.
+
+More information are listed in `link`_.
+
+How to build
+============
+
+Code Locations
+--------------
+
+-  Trusted Firmware-A:
+   `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+-  OP-TEE:
+   `link <https://github.com/OP-TEE/optee_os>`__
+
+-  edk2:
+   `link <https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5>`__
+
+-  OpenPlatformPkg:
+   `link <https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4>`__
+
+-  l-loader:
+   `link <https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2>`__
+
+-  uefi-tools:
+   `link <https://git.linaro.org/uefi/uefi-tools.git>`__
+
+Build Procedure
+---------------
+
+-  Fetch all the above 5 repositories into local host.
+   Make all the repositories in the same ${BUILD\_PATH}.
+
+  .. code:: shell
+
+       git clone https://github.com/ARM-software/arm-trusted-firmware -b integration
+       git clone https://github.com/OP-TEE/optee_os
+       git clone https://github.com/96boards-hikey/edk2 -b testing/hikey960_v2.5
+       git clone https://github.com/96boards-hikey/OpenPlatformPkg -b testing/hikey960_v1.3.4
+       git clone https://github.com/96boards-hikey/l-loader -b testing/hikey960_v1.2
+       git clone https://git.linaro.org/uefi/uefi-tools
+
+-  Create the symbol link to OpenPlatformPkg in edk2.
+
+   .. code:: shell
+
+       $cd ${BUILD_PATH}/edk2
+       $ln -sf ../OpenPlatformPkg
+
+-  Prepare AARCH64 toolchain.
+
+-  If your hikey960 hardware is v1, update *uefi-tools/platform.config* first. *(optional)*
+   **Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
+   console on hikey960 v1.**
+
+   .. code:: shell
+
+       BUILDFLAGS=-DSERIAL_BASE=0xFDF05000
+
+   If your hikey960 hardware is v2 or newer, nothing to do.
+
+-  Build it as debug mode. Create script file for build.
+
+   .. code:: shell
+
+       BUILD_OPTION=DEBUG
+       export AARCH64_TOOLCHAIN=GCC5
+       export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools
+       export EDK2_DIR=${BUILD_PATH}/edk2
+       EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey960/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}
+       cd ${EDK2_DIR}
+       # Build UEFI & Trusted Firmware-A
+       ${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware -s ../optee_os hikey960
+
+-  Generate l-loader.bin and partition table.
+   *Make sure that you're using the sgdisk in the l-loader directory.*
+
+   .. code:: shell
+
+       cd ${BUILD_PATH}/l-loader
+       ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin
+       ln -sf ${EDK2_OUTPUT_DIR}/FV/bl2.bin
+       ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin
+       ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd
+       make hikey960
+
+Setup Console
+-------------
+
+-  Install ser2net. Use telnet as the console since UEFI will output window
+   that fails to display in minicom.
+
+   .. code:: shell
+
+       $sudo apt-get install ser2net
+
+-  Configure ser2net.
+
+   .. code:: shell
+
+       $sudo vi /etc/ser2net.conf
+
+   Append one line for serial-over-USB in *#ser2net.conf*
+
+   ::
+
+       2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner
+
+-  Start ser2net
+
+   .. code:: shell
+
+       $sudo killall ser2net
+       $sudo ser2net -u
+
+-  Open the console.
+
+   .. code:: shell
+
+       $telnet localhost 2004
+
+   And you could open the console remotely, too.
+
+Boot UEFI in recovery mode
+--------------------------
+
+-  Fetch that are used in recovery mode. The code location is in below.
+   `link <https://github.com/96boards-hikey/tools-images-hikey960>`__
+
+-  Prepare recovery binary.
+
+   .. code:: shell
+
+       $cd tools-images-hikey960
+       $ln -sf ${BUILD_PATH}/l-loader/l-loader.bin
+       $ln -sf ${BUILD_PATH}/l-loader/fip.bin
+       $ln -sf ${BUILD_PATH}/l-loader/recovery.bin
+
+-  Prepare config file.
+
+   .. code:: shell
+
+       $vi config
+       # The content of config file
+       ./sec_usb_xloader.img 0x00020000
+       ./sec_uce_boot.img 0x6A908000
+       ./recovery.bin 0x1AC00000
+
+-  Remove the modemmanager package. This package may causes hikey\_idt tool failure.
+
+   .. code:: shell
+
+       $sudo apt-get purge modemmanager
+
+-  Run the command to download recovery.bin into HiKey960.
+
+   .. code:: shell
+
+       $sudo ./hikey_idt -c config -p /dev/ttyUSB1
+
+-  UEFI running in recovery mode.
+   When prompt '.' is displayed on console, press hotkey 'f' in keyboard. Then Android fastboot app is running.
+   The timeout of prompt '.' is 10 seconds.
+
+-  Update images.
+
+   .. code:: shell
+
+       $sudo fastboot flash ptable prm_ptable.img
+       $sudo fastboot flash xloader sec_xloader.img
+       $sudo fastboot flash fastboot l-loader.bin
+       $sudo fastboot flash fip fip.bin
+       $sudo fastboot flash boot boot.img
+       $sudo fastboot flash cache cache.img
+       $sudo fastboot flash system system.img
+       $sudo fastboot flash userdata userdata.img
+
+-  Notice: UEFI could also boot kernel in recovery mode, but BL31 isn't loaded in
+   recovery mode.
+
+Boot UEFI in normal mode
+------------------------
+
+-  Make sure "Boot Mode" switch is OFF for normal boot mode. Then power on HiKey960.
+
+-  Reference `link <https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md>`__
+
+.. _link: https://www.96boards.org/documentation/consumer/hikey/hikey960
diff --git a/docs/plat/imx8.rst b/docs/plat/imx8.rst
new file mode 100644
index 0000000..49ba374
--- /dev/null
+++ b/docs/plat/imx8.rst
@@ -0,0 +1,58 @@
+NXP i.MX 8 Series
+=================
+
+The i.MX 8 series of applications processors is a feature- and
+performance-scalable multi-core platform that includes single-,
+dual-, and quad-core families based on the Arm® Cortex®
+architecture—including combined Cortex-A72 + Cortex-A53,
+Cortex-A35, and Cortex-M4 based solutions for advanced graphics,
+imaging, machine vision, audio, voice, video, and safety-critical
+applications.
+
+The i.MX8QM is with 2 Cortex-A72 ARM core, 4 Cortex-A53 ARM core
+and 1 Cortex-M4 system controller.
+
+The i.MX8QX is with 4 Cortex-A35 ARM core and 1 Cortex-M4 system
+controller.
+
+The System Controller (SC) represents the evolution of centralized
+control for system-level resources on i.MX8. The heart of the system
+controller is a Cortex-M4 that executes system controller firmware.
+
+Boot Sequence
+-------------
+
+Bootrom --> BL31 --> BL33(u-boot) --> Linux kernel
+
+How to build
+------------
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Prepare AARCH64 toolchain.
+
+-  Build System Controller Firmware and u-boot firstly, and get binary images: scfw_tcm.bin and u-boot.bin
+
+-  Build TF-A
+
+   Build bl31:
+
+   .. code:: shell
+
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31
+
+   Target_SoC should be "imx8qm" for i.MX8QM SoC.
+   Target_SoC should be "imx8qx" for i.MX8QX SoC.
+
+Deploy TF-A Images
+~~~~~~~~~~~~~~~~~~
+
+TF-A binary(bl31.bin), scfw_tcm.bin and u-boot.bin are combined together
+to generate a binary file called flash.bin, the imx-mkimage tool is used
+to generate flash.bin, and flash.bin needs to be flashed into SD card
+with certain offset for BOOT ROM. The system controller firmware,
+u-boot and imx-mkimage will be upstreamed soon, this doc will be updated
+once they are ready, and the link will be posted.
+
+.. _i.MX8: https://www.nxp.com/products/processors-and-microcontrollers/applications-processors/i.mx-applications-processors/i.mx-8-processors/i.mx-8-family-arm-cortex-a53-cortex-a72-virtualization-vision-3d-graphics-4k-video:i.MX8
diff --git a/docs/plat/imx8m.rst b/docs/plat/imx8m.rst
new file mode 100644
index 0000000..8acd13c
--- /dev/null
+++ b/docs/plat/imx8m.rst
@@ -0,0 +1,43 @@
+NXP i.MX 8M Series
+==================
+
+The i.MX 8M family of applications processors based on Arm Corte-A53 and Cortex-M4
+cores provide high-performance computing, power efficiency, enhanced system
+reliability and embedded security needed to drive the growth of fast-growing
+edge node computing, streaming multimedia, and machine learning applications.
+
+Boot Sequence
+-------------
+
+Bootrom --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel
+
+How to build
+------------
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Prepare AARCH64 toolchain.
+
+-  Build spl and u-boot firstly, and get binary images: u-boot-spl.bin,
+   u-boot-nodtb.bin and dtb for the target board.
+
+-  Build TF-A
+
+   Build bl31:
+
+   .. code:: shell
+
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31
+
+   Target_SoC should be "imx8mq" for i.MX8MQ SoC.
+   Target_SoC should be "imx8mm" for i.MX8MM SoC.
+
+Deploy TF-A Images
+~~~~~~~~~~~~~~~~~~
+
+TF-A binary(bl31.bin), u-boot-spl.bin u-boot-nodtb.bin and dtb are combined
+together to generate a binary file called flash.bin, the imx-mkimage tool is
+used to generate flash.bin, and flash.bin needs to be flashed into SD card
+with certain offset for BOOT ROM. the u-boot and imx-mkimage will be upstreamed
+soon, this doc will be updated once they are ready, and the link will be posted.
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
new file mode 100644
index 0000000..5951413
--- /dev/null
+++ b/docs/plat/index.rst
@@ -0,0 +1,29 @@
+Platform Ports
+==============
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   allwinner
+   fvp_ve
+   imx8
+   imx8m
+   intel-stratix10
+   ls1043a
+   meson-gxbb
+   meson-gxl
+   mt8183
+   nvidia-tegra
+   qemu
+   rcar-gen3
+   rockchip
+   rpi3
+   socionext-uniphier
+   stm32mp1
+   synquacer
+   ti-k3
+   warp7
+   xilinx-versal
+   xilinx-zynqmp
diff --git a/docs/plat/intel-agilex.rst b/docs/plat/intel-agilex.rst
new file mode 100644
index 0000000..015a195
--- /dev/null
+++ b/docs/plat/intel-agilex.rst
@@ -0,0 +1,85 @@
+Intel Agilex SoCFPGA
+========================
+
+Agilex SoCFPGA is a FPGA with integrated quad-core 64-bit Arm Cortex A53 processor.
+
+Upon boot, Boot ROM loads bl2 into OCRAM. Bl2 subsequently initializes
+the hardware, then loads bl31 and bl33 (UEFI) into DDR and boots to bl33.
+
+::
+
+    Boot ROM --> Trusted Firmware-A --> UEFI
+
+How to build
+------------
+
+Code Locations
+~~~~~~~~~~~~~~
+
+-  Trusted Firmware-A:
+   `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+-  UEFI (to be updated with new upstreamed UEFI):
+   `link <https://github.com/altera-opensource/uefi-socfpga>`__
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Fetch all the above 2 repositories into local host.
+   Make all the repositories in the same ${BUILD\_PATH}.
+
+-  Prepare the AARCH64 toolchain.
+
+-  Build UEFI using Agilex platform as configuration
+   This will be updated to use an updated UEFI using the latest EDK2 source
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu- device=agx
+
+-  Build atf providing the previously generated UEFI as the BL33 image
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu- bl2 fip PLAT=agilex
+       BL33=PEI.ROM
+
+Install Procedure
+~~~~~~~~~~~~~~~~~
+
+- dd fip.bin to a A2 partition on the MMC drive to be booted in Agilex
+  board.
+
+- Generate a SOF containing bl2
+
+.. code:: bash
+
+        aarch64-linux-gnu-objcopy -I binary -O ihex --change-addresses 0xffe00000 bl2.bin bl2.hex
+        quartus_cpf --bootloader bl2.hex <quartus_generated_sof> <output_sof_with_bl2>
+
+- Configure SOF to board
+
+.. code:: bash
+
+        nios2-configure-sof <output_sof_with_bl2>
+
+Boot trace
+----------
+
+::
+        INFO:    DDR: DRAM calibration success.
+        INFO:    ECC is disabled.
+        NOTICE:  BL2: v2.1(debug)
+        NOTICE:  BL2: Built
+        INFO:    BL2: Doing platform setup
+        NOTICE:  BL2: Booting BL31
+        INFO:    Entry point address = 0xffe1c000
+        INFO:    SPSR = 0x3cd
+        NOTICE:  BL31: v2.1(debug)
+        NOTICE:  BL31: Built
+        INFO:    ARM GICv2 driver initialized
+        INFO:    BL31: Initializing runtime services
+        WARNING: BL31: cortex_a53
+        INFO:    BL31: Preparing for EL3 exit to normal world
+        INFO:    Entry point address = 0x50000
+        INFO:    SPSR = 0x3c9
diff --git a/docs/plat/intel-stratix10.rst b/docs/plat/intel-stratix10.rst
new file mode 100644
index 0000000..77a45a4
--- /dev/null
+++ b/docs/plat/intel-stratix10.rst
@@ -0,0 +1,93 @@
+Intel Stratix 10 SoCFPGA
+========================
+
+Stratix 10 SoCFPGA is a FPGA with integrated quad-core 64-bit Arm Cortex A53 processor.
+
+Upon boot, Boot ROM loads bl2 into OCRAM. Bl2 subsequently initializes
+the hardware, then loads bl31 and bl33 (UEFI) into DDR and boots to bl33.
+
+::
+
+    Boot ROM --> Trusted Firmware-A --> UEFI
+
+How to build
+------------
+
+Code Locations
+~~~~~~~~~~~~~~
+
+-  Trusted Firmware-A:
+   `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+-  UEFI (to be updated with new upstreamed UEFI):
+   `link <https://github.com/altera-opensource/uefi-socfpga>`__
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Fetch all the above 2 repositories into local host.
+   Make all the repositories in the same ${BUILD\_PATH}.
+
+-  Prepare the AARCH64 toolchain.
+
+-  Build UEFI using Stratix 10 platform as configuration
+   This will be updated to use an updated UEFI using the latest EDK2 source
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu- device=s10
+
+-  Build atf providing the previously generated UEFI as the BL33 image
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu- bl2 fip PLAT=stratix10
+       BL33=PEI.ROM
+
+Install Procedure
+~~~~~~~~~~~~~~~~~
+
+- dd fip.bin to a A2 partition on the MMC drive to be booted in Stratix 10
+  board.
+
+- Generate a SOF containing bl2
+
+.. code:: bash
+
+        aarch64-linux-gnu-objcopy -I binary -O ihex --change-addresses 0xffe00000 bl2.bin bl2.hex
+        quartus_cpf --bootloader bl2.hex <quartus_generated_sof> <output_sof_with_bl2>
+
+- Configure SOF to board
+
+.. code:: bash
+
+        nios2-configure-sof <output_sof_with_bl2>
+
+Boot trace
+----------
+
+::
+         INFO:    DDR: DRAM calibration success.
+         INFO:    ECC is disabled.
+         INFO:    Init HPS NOC's DDR Scheduler.
+         NOTICE:  BL2: v2.0(debug):v2.0-809-g7f8474a-dirty
+         NOTICE:  BL2: Built : 17:38:19, Feb 18 2019
+         INFO:    BL2: Doing platform setup
+         INFO:    BL2: Loading image id 3
+         INFO:    Loading image id=3 at address 0xffe1c000
+         INFO:    Image id=3 loaded: 0xffe1c000 - 0xffe24034
+         INFO:    BL2: Loading image id 5
+         INFO:    Loading image id=5 at address 0x50000
+         INFO:    Image id=5 loaded: 0x50000 - 0x550000
+         NOTICE:  BL2: Booting BL31
+         INFO:    Entry point address = 0xffe1c000
+         INFO:    SPSR = 0x3cd
+         NOTICE:  BL31: v2.0(debug):v2.0-810-g788c436-dirty
+         NOTICE:  BL31: Built : 15:17:16, Feb 20 2019
+         INFO:    ARM GICv2 driver initialized
+         INFO:    BL31: Initializing runtime services
+         WARNING: BL31: cortex_a53: CPU workaround for 855873 was missing!
+         INFO:    BL31: Preparing for EL3 exit to normal world
+         INFO:    Entry point address = 0x50000
+         INFO:    SPSR = 0x3c9
+         UEFI firmware (version 1.0 built at 11:26:18 on Nov  7 2018)
diff --git a/docs/plat/ls1043a.rst b/docs/plat/ls1043a.rst
new file mode 100644
index 0000000..72a51f3
--- /dev/null
+++ b/docs/plat/ls1043a.rst
@@ -0,0 +1,91 @@
+NXP QorIQ® LS1043A
+==================
+
+The QorIQ® LS1043A processor is NXP's first quad-core, 64-bit Arm®-based
+processor for embedded networking. The LS1023A (two core version) and the
+LS1043A (four core version) deliver greater than 10 Gbps of performance
+in a flexible I/O package supporting fanless designs. This SoC is a
+purpose-built solution for small-form-factor networking and industrial
+applications with BOM optimizations for economic low layer PCB, lower cost
+power supply and single clock design. The new 0.9V versions of the LS1043A
+and LS1023A deliver addition power savings for applications such as Wireless
+LAN and to Power over Ethernet systems.
+
+LS1043ARDB Specification:
+-------------------------
+Memory subsystem:
+	* 2GByte DDR4 SDRAM (32bit bus)
+	* 128 Mbyte NOR flash single-chip memory
+	* 512 Mbyte NAND flash
+	* 16 Mbyte high-speed SPI flash
+	* SD connector to interface with the SD memory card
+
+Ethernet:
+	* XFI 10G port
+	* QSGMII with 4x 1G ports
+	* Two RGMII ports
+
+PCIe:
+	* PCIe2 (Lanes C) to mini-PCIe slot
+	* PCIe3 (Lanes D) to PCIe slot
+
+USB 3.0: two super speed USB 3.0 type A ports
+
+UART: supports two UARTs up to 115200 bps for console
+
+More information are listed in `ls1043`_.
+
+Boot Sequence
+-------------
+
+
+Bootrom --> TF-A BL1 --> TF-A BL2 --> TF-A BL1 --> TF-A BL31
+--> BL32(Tee OS) --> TF-A BL31 --> BL33(u-boot) --> Linux kernel
+
+
+How to build
+------------
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Prepare AARCH64 toolchain.
+
+-  Build u-boot and OPTee firstly, and get binary images: u-boot.bin and tee.bin
+
+-  Build TF-A for Nor boot
+
+   Build bl1:
+
+   .. code:: shell
+
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=ls1043 bl1
+
+   Build fip:
+
+   .. code:: shell
+
+       CROSS_COMPILE=aarch64-linux-gnu- make PLAT=ls1043 fip \
+       BL33=u-boot.bin NEED_BL32=yes BL32=tee.bin SPD=opteed
+
+Deploy TF-A Images
+~~~~~~~~~~~~~~~~~~
+
+-  Deploy TF-A images on Nor flash Alt Bank.
+
+   .. code:: shell
+
+       => tftp 82000000  bl1.bin
+       => pro off all;era 64100000 +$filesize;cp.b 82000000 64100000 $filesize
+
+       => tftp 82000000  fip.bin
+       => pro off all;era 64120000 +$filesize;cp.b 82000000 64120000 $filesize
+
+   Then change to Alt bank and boot up TF-A:
+
+   .. code:: shell
+
+       => cpld reset altbank
+
+
+.. _ls1043: https://www.nxp.com/products/processors-and-microcontrollers/arm-based-processors-and-mcus/qoriq-layerscape-arm-processors/qoriq-layerscape-1043a-and-1023a-multicore-communications-processors:LS1043A?lang_cd=en
diff --git a/docs/plat/marvell/build.txt b/docs/plat/marvell/build.txt
new file mode 100644
index 0000000..7b75196
--- /dev/null
+++ b/docs/plat/marvell/build.txt
@@ -0,0 +1,194 @@
+TF-A Build Instructions
+======================
+
+This section describes how to compile the ARM Trusted Firmware (TF-A) project for Marvell's platforms.
+
+Build Instructions
+------------------
+(1) Set the cross compiler::
+
+		> export CROSS_COMPILE=/path/to/toolchain/aarch64-linux-gnu-
+
+(2) Set path for FIP images:
+
+	Set U-Boot image path (relatively to TF-A root or absolute path)::
+
+		> export BL33=path/to/u-boot.bin
+
+	For example: if U-Boot project (and its images) is located at ~/project/u-boot,
+	BL33 should be ~/project/u-boot/u-boot.bin
+
+	.. note::
+
+	   u-boot.bin should be used and not u-boot-spl.bin
+
+	Set MSS/SCP image path (mandatory only for Armada80x0)::
+
+		> export SCP_BL2=path/to/mrvl_scp_bl2*.img
+
+(3) Armada-37x0 build requires WTP tools installation.
+
+	See below in the section "Tools and external components installation".
+	Install ARM 32-bit cross compiler, which is required for building WTMI image for CM3::
+
+		> sudo apt-get install gcc-arm-linux-gnueabi
+
+(4) Clean previous build residuals (if any)::
+
+		> make distclean
+
+(5) Build TF-A:
+
+	There are several build options:
+
+	- DEBUG: default is without debug information (=0). in order to enable it use DEBUG=1
+		Must be disabled when building UART recovery images due to current console driver
+		implementation that is not compatible with Xmodem protocol used for boot image download.
+
+	- LOG_LEVEL: defines the level of logging which will be purged to the default output port.
+
+		LOG_LEVEL_NONE		0
+		LOG_LEVEL_ERROR		10
+		LOG_LEVEL_NOTICE	20
+		LOG_LEVEL_WARNING	30
+		LOG_LEVEL_INFO		40
+		LOG_LEVEL_VERBOSE	50
+
+	- USE_COHERENT_MEM: This flag determines whether to include the coherent memory region in the
+		BL memory map or not.
+
+	- LLC_ENABLE: Flag defining the LLC (L3) cache state. The cache is enabled by default (LLC_ENABLE=1).
+
+	- MARVELL_SECURE_BOOT: build trusted(=1)/non trusted(=0) image, default is non trusted.
+
+	- BLE_PATH:
+		Points to BLE (Binary ROM extension) sources folder. Only required for A8K builds.
+		The parameter is optional, its default value is "plat/marvell/a8k/common/ble".
+
+	- MV_DDR_PATH:
+		For A7/8K, use this parameter to point to mv_ddr driver sources to allow BLE build. For A37x0,
+		it is used for ddr_tool build.
+		Usage example: MV_DDR_PATH=path/to/mv_ddr
+		The parameter is optional for A7/8K, when this parameter is not set, the mv_ddr
+		sources are expected to be located at: drivers/marvell/mv_ddr. However, the parameter
+		is necessary for A37x0.
+		For the mv_ddr source location, check the section "Tools and external components installation"
+
+	- DDR_TOPOLOGY: For Armada37x0 only, the DDR topology map index/name, default is 0.
+		Supported Options:
+			- DDR3 1CS (0): DB-88F3720-DDR3-Modular (512MB); EspressoBIN (512MB)
+			- DDR4 1CS (1): DB-88F3720-DDR4-Modular (512MB)
+			- DDR3 2CS (2): EspressoBIN V3-V5 (1GB)
+			- DDR4 2CS (3): DB-88F3720-DDR4-Modular (4GB)
+			- DDR3 1CS (4): DB-88F3720-DDR3-Modular (1GB)
+			- DDR4 1CS (5): EspressoBin V7 (1GB)
+			- DDR4 2CS (6): EspressoBin V7 (2GB)
+			- CUSTOMER (CUST): Customer board, DDR3 1CS 512MB
+
+	- CLOCKSPRESET: For Armada37x0 only, the clock tree configuration preset including CPU and DDR frequency,
+		default is CPU_800_DDR_800.
+			- CPU_600_DDR_600	-	CPU at 600 MHz, DDR at 600 MHz
+			- CPU_800_DDR_800	-	CPU at 800 MHz, DDR at 800 MHz
+			- CPU_1000_DDR_800	-	CPU at 1000 MHz, DDR at 800 MHz
+			- CPU_1200_DDR_750	-	CPU at 1200 MHz, DDR at 750 MHz
+
+	- BOOTDEV: For Armada37x0 only, the flash boot device, default is SPINOR,
+		Currently, Armada37x0 only supports SPINOR, SPINAND, EMMCNORM and SATA:
+
+			- SPINOR - SPI NOR flash boot
+			- SPINAND - SPI NAND flash boot
+			- EMMCNORM - eMMC Download Mode
+				Download boot loader or program code from eMMC flash into CM3 or CA53
+				Requires full initialization and command sequence
+			- SATA - SATA device boot
+
+	- PARTNUM: For Armada37x0 only, the boot partition number, default is 0. To boot from eMMC, the value
+		should be aligned with the parameter in U-Boot with name of CONFIG_SYS_MMC_ENV_PART, whose
+		value by default is 1.
+		For details about CONFIG_SYS_MMC_ENV_PART, please refer to the U-Boot build instructions.
+
+	- WTMI_IMG: For Armada37x0 only, the path of the WTMI image can point to an image which does
+		nothing, an image which supports EFUSE or a customized CM3 firmware binary. The default image
+		is wtmi.bin that built from sources in WTP folder, which is the next option. If the default
+		image is OK, then this option should be skipped.
+
+	- WTP: For Armada37x0 only, use this parameter to point to wtptools source code directory, which
+		can be found as a3700_utils.zip in the release.
+		Usage example: WTP=/path/to/a3700_utils
+
+	For example, in order to build the image in debug mode with log level up to 'notice' level run::
+
+		> make DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 PLAT=<MARVELL_PLATFORM> all fip
+
+	And if we want to build a Armada37x0 image in debug mode with log level up to 'notice' level,
+	the image has the preset CPU at 1000 MHz, preset DDR3 at 800 MHz, the DDR topology of DDR4 2CS,
+	the image boot from SPI NOR flash partition 0, and the image is non trusted in WTP, the command
+	line is as following::
+
+		> make DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 CLOCKSPRESET=CPU_1000_DDR_800 \
+			MARVELL_SECURE_BOOT=0 DDR_TOPOLOGY=3 BOOTDEV=SPINOR PARTNUM=0 PLAT=a3700 all fip
+
+	Supported MARVELL_PLATFORM are:
+		- a3700 (for both A3720 DB and EspressoBin)
+		- a70x0
+		- a70x0_amc (for AMC board)
+		- a80x0
+		- a80x0_mcbin (for MacciatoBin)
+
+Special Build Flags
+--------------------
+	- PLAT_RECOVERY_IMAGE_ENABLE: When set this option to enable secondary recovery function when build
+		atf. In order to build UART recovery image this operation should be disabled for a70x0 and a80x0
+		because of hardware limitation (boot from secondary image can interrupt UART recovery process).
+		This MACRO definition is set in plat/marvell/a8k/common/include/platform_def.h file
+
+(for more information about build options, please refer to section 'Summary of build options' in  TF-A user-guide:
+ https://github.com/ARM-software/arm-trusted-firmware/blob/master/docs/user-guide.md)
+
+
+Build output
+-------------
+Marvell's TF-A compilation generates 7 files:
+	- ble.bin		- BLe image
+	- bl1.bin		- BL1 image
+	- bl2.bin		- BL2 image
+	- bl31.bin		- BL31 image
+	- fip.bin		- FIP image (contains BL2, BL31 & BL33 (U-Boot) images)
+	- boot-image.bin	- TF-A image (contains BL1 and FIP images)
+	- flash-image.bin	- Image which contains boot-image.bin and SPL image;
+				  should be placed on the boot flash/device.
+
+
+Tools and external components installation
+==========================================
+
+Armada37x0 Builds require installation of 3 components
+-------------------------------------------------------
+
+(1) ARM cross compiler capable of building images for the service CPU (CM3).
+    This component is usually included in the Linux host packages.
+    On Debian/Ubuntu hosts the default GNU ARM tool chain can be installed
+    using the following command::
+
+		> sudo apt-get install gcc-arm-linux-gnueabi
+
+    Only if required, the default tool chain prefix "arm-linux-gnueabi-" can be
+    overwritten using the environment variable CROSS_CM3.
+    Example for BASH shell::
+
+		> export CROSS_CM3=/opt/arm-cross/bin/arm-linux-gnueabi
+
+(2) DDR initialization library sources (mv_ddr) available at the following repository
+    (use the "mv_ddr-armada-atf-mainline" branch)::
+    https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
+
+(3) Armada3700 tools available at the following repository (use the latest release branch)::
+    https://github.com/MarvellEmbeddedProcessors/A3700-utils-marvell.git
+
+Armada70x0 and Armada80x0 Builds require installation of an additional component
+--------------------------------------------------------------------------------
+
+(1) DDR initialization library sources (mv_ddr) available at the following repository
+    (use the "mv_ddr-armada-atf-mainline" branch)::
+    https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
+
diff --git a/docs/plat/marvell/misc/mvebu-a8k-addr-map.txt b/docs/plat/marvell/misc/mvebu-a8k-addr-map.txt
new file mode 100644
index 0000000..586e8b7
--- /dev/null
+++ b/docs/plat/marvell/misc/mvebu-a8k-addr-map.txt
@@ -0,0 +1,47 @@
+Address decoding flow and address translation units of Marvell Armada 8K SoC family
+
++--------------------------------------------------------------------------------------------------+
+|                                                              +-------------+    +--------------+ |
+|                                                              | Memory      +-----   DRAM CS    | |
+|+------------+ +-----------+ +-----------+                    | Controller  |    +--------------+ |
+||  AP DMA    | |           | |           |                    +-------------+                     |
+||  SD/eMMC   | | CA72 CPUs | |  AP MSS   |                    +-------------+                     |
+||  MCI-0/1   | |           | |           |                    | Memory      |                     |
+|+------+-----+ +--+--------+ +--------+--+  +------------+    | Controller  |     +-------------+ |
+|       |          |                   |     |            +----- Translaton  |     |AP           | |
+|       |          |                   |     |            |    +-------------+     |Configuration| |
+|       |          |                   +-----+            +-------------------------Space        | |
+|       |          | +-------------+         |  CCU       |                        +-------------+ |
+|       |          | | MMU         +---------+  Windows   |   +-----------+        +-------------+ |
+|       |          +-| translation |         |  Lookup    +----           +---------   AP SPI    | |
+|       |            +-------------+         |            |   |           |        +-------------+ |
+|       |            +-------------+         |            |   |  IO       |        +-------------+ |
+|       +------------| SMMU        +---------+            |   |  Windows  +---------  AP MCI0/1  | |
+|                    | translation |         +------------+   |  Lookup   |        +-------------+ |
+|                    +---------+---+                          |           |        +-------------+ |
+|             -                |                              |           +---------   AP STM    | |
+|             +-----------------                              |           |        +-------------+ |
+| AP          |                |                              +-+---------+                        |
++---------------------------------------------------------------|----------------------------------+
++-------------|-------------------------------------------------|----------------------------------+
+| CP          |            +-------------+               +------+-----+      +-------------------+ |
+|             |            |             |               |            +-------   SB CFG Space    | |
+|             |            |   DIOB      |               |            |      +-------------------+ |
+|             |            |   Windows   -----------------  IOB       |      +-------------------+ |
+|             |            |   Control   |               |  Windows   +------| SB PCIe-0 - PCIe2 | |
+|             |            |             |               |  Lookup    |      +-------------------+ |
+|             |            +------+------+               |            |      +-------------------+ |
+|             |                   |                      |            +------+      SB NAND      | |
+|             |                   |                      +------+-----+      +-------------------+ |
+|             |                   |                             |                                  |
+|             |                   |                             |                                  |
+|   +------------------+   +------------+                +------+-----+      +-------------------+ |
+|   | Network Engine   |   |            |                |            +-------  SB SPI-0/SPI-1   | |
+|   | Security Engine  |   | PCIe, MSS  |                |  RUNIT     |      +-------------------+ |
+|   | SATA, USB        |   | DMA        |                |  Windows   |      +-------------------+ |
+|   | SD/eMMC          |   |            |                |  Lookup    +-------   SB Device Bus   | |
+|   | TDM, I2C         |   |            |                |            |      +-------------------+ |
+|   +------------------+   +------------+                +------------+                            |
+|                                                                                                  |
++--------------------------------------------------------------------------------------------------+
+
diff --git a/docs/plat/marvell/misc/mvebu-amb.txt b/docs/plat/marvell/misc/mvebu-amb.txt
new file mode 100644
index 0000000..2a7a41e
--- /dev/null
+++ b/docs/plat/marvell/misc/mvebu-amb.txt
@@ -0,0 +1,45 @@
+AMB - AXI MBUS address decoding
+-------------------------------
+
+AXI to M-bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs.
+
+- The Runit offers a second level of address windows lookup. It is used to map transaction towards
+the CD BootROM, SPI0, SPI1 and Device bus (NOR).
+- The Runit contains eight configurable windows. Each window defines a contiguous,
+address space and the properties associated with that address space.
+
+Unit		Bank		ATTR
+Device-Bus	DEV_BOOT_CS 	0x2F
+		DEV_CS0     	0x3E
+		DEV_CS1     	0x3D
+		DEV_CS2     	0x3B
+		DEV_CS3     	0x37
+SPI-0		SPI_A_CS0 	0x1E
+		SPI_A_CS1 	0x5E
+		SPI_A_CS2 	0x9E
+		SPI_A_CS3 	0xDE
+		SPI_A_CS4 	0x1F
+		SPI_A_CS5 	0x5F
+		SPI_A_CS6 	0x9F
+		SPI_A_CS7 	0xDF
+SPI1		SPI_B_CS0 	0x1A
+		SPI_B_CS1 	0x5A
+		SPI_B_CS2	0x9A
+		SPI_B_CS3	0xDA
+BOOT_ROM	BOOT_ROM	0x1D
+UART		UART		0x01
+
+Mandatory functions:
+	- marvell_get_amb_memory_map
+		returns the AMB windows configuration and the number of windows
+
+Mandatory structures:
+	amb_memory_map - Array that include the configuration of the windows
+	  every window/entry is a struct which has 2 parameters:
+	  - base address of the window
+	  - Attribute of the window
+
+Examples:
+	struct addr_map_win amb_memory_map[] = {
+		{0xf900,	AMB_DEV_CS0_ID},
+	};
diff --git a/docs/plat/marvell/misc/mvebu-ccu.txt b/docs/plat/marvell/misc/mvebu-ccu.txt
new file mode 100644
index 0000000..9764027
--- /dev/null
+++ b/docs/plat/marvell/misc/mvebu-ccu.txt
@@ -0,0 +1,23 @@
+Marvell CCU address decoding bindings
+=====================================
+
+CCU configration driver (1st stage address translation) for Marvell Armada 8K and 8K+ SoCs.
+
+The CCU node includes a description of the address decoding configuration.
+
+Mandatory functions:
+	- marvell_get_ccu_memory_map
+		return the CCU windows configuration and the number of windows
+		of the specific AP.
+
+Mandatory structures:
+	ccu_memory_map - Array that includes the configuration of the windows
+	  every window/entry is a struct which has 3 parameters:
+	  - Base address of the window
+	  - Size of the window
+	  - Target-ID of the window
+
+Example:
+	struct addr_map_win ccu_memory_map[] = {
+		{0x00000000f2000000,     0x00000000e000000,      IO_0_TID}, /* IO window */
+	};
diff --git a/docs/plat/marvell/misc/mvebu-io-win.txt b/docs/plat/marvell/misc/mvebu-io-win.txt
new file mode 100644
index 0000000..c83ad1f
--- /dev/null
+++ b/docs/plat/marvell/misc/mvebu-io-win.txt
@@ -0,0 +1,35 @@
+Marvell IO WIN address decoding bindings
+=====================================
+
+IO Window configration driver (2nd stage address translation) for Marvell Armada 8K and 8K+ SoCs.
+
+The IO WIN includes a description of the address decoding configuration.
+
+Transactions that are decoded by CCU windows as IO peripheral, have an additional
+layer of decoding. This additional address decoding layer defines one of the
+following targets:
+	0x0 = BootRom
+	0x1 = STM (Serial Trace Macro-cell, a programmer's port into trace stream)
+	0x2 = SPI direct access
+	0x3 = PCIe registers
+	0x4 = MCI Port
+	0x5 = PCIe port
+
+Mandatory functions:
+	- marvell_get_io_win_memory_map
+		returns the IO windows configuration and the number of windows
+		of the specific AP.
+
+Mandatory structures:
+	io_win_memory_map - Array that include the configuration of the windows
+	  every window/entry is a struct which has 3 parameters:
+	  - Base address of the window
+	  - Size of the window
+	  - Target-ID of the window
+
+Example:
+	struct addr_map_win io_win_memory_map[] = {
+		{0x00000000fe000000,	0x000000001f00000,	PCIE_PORT_TID}, /* PCIe window 31Mb for PCIe port*/
+		{0x00000000ffe00000,	0x000000000100000,	PCIE_REGS_TID}, /* PCI-REG window 64Kb for PCIe-reg*/
+		{0x00000000f6000000,	0x000000000100000,	MCIPHY_TID},	/* MCI window  1Mb for PHY-reg*/
+	};
diff --git a/docs/plat/marvell/misc/mvebu-iob.txt b/docs/plat/marvell/misc/mvebu-iob.txt
new file mode 100644
index 0000000..97ec09d
--- /dev/null
+++ b/docs/plat/marvell/misc/mvebu-iob.txt
@@ -0,0 +1,40 @@
+Marvell IOB address decoding bindings
+=====================================
+
+IO bridge configration driver (3rd stage address translation) for Marvell Armada 8K and 8K+ SoCs.
+
+The IOB includes a description of the address decoding configuration.
+
+IOB supports up to n (in CP110 n=24) windows for external memory transaction.
+When a transaction passes through the IOB, its address is compared to each of
+the enabled windows. If there is a hit and it passes the security checks, it is
+advanced to the target port.
+
+Mandatory functions:
+	- marvell_get_iob_memory_map
+		returns the IOB windows configuration and the number of windows
+
+Mandatory structures:
+	iob_memory_map - Array that include the configuration of the windows
+	  every window/entry is a struct which has 3 parameters:
+	  - Base address of the window
+	  - Size of the window
+	  - Target-ID of the window
+
+Target ID options:
+	- 0x0 = Internal configuration space
+	- 0x1 = MCI0
+	- 0x2 = PEX1_X1
+	- 0x3 = PEX2_X1
+	- 0x4 = PEX0_X4
+	- 0x5 = NAND flash
+	- 0x6 = RUNIT (NOR/SPI/BootRoom)
+	- 0x7 = MCI1
+
+Example:
+	struct addr_map_win iob_memory_map[] = {
+		{0x00000000f7000000,	0x0000000001000000,	PEX1_TID}, /* PEX1_X1 window */
+		{0x00000000f8000000,	0x0000000001000000,	PEX2_TID}, /* PEX2_X1 window */
+		{0x00000000f6000000,	0x0000000001000000,	PEX0_TID}, /* PEX0_X4 window */
+		{0x00000000f9000000,	0x0000000001000000,	NAND_TID}  /* NAND window */
+	};
diff --git a/docs/plat/marvell/porting.txt b/docs/plat/marvell/porting.txt
new file mode 100644
index 0000000..f9a39a0
--- /dev/null
+++ b/docs/plat/marvell/porting.txt
@@ -0,0 +1,118 @@
+.. _porting:
+
+TF-A Porting Guide
+=================
+
+This section describes how to port TF-A to a customer board, assuming that the SoC being used is already supported
+in TF-A.
+
+
+Source Code Structure
+---------------------
+- The customer platform specific code shall reside under "plat/marvell/<soc family>/<soc>_cust"
+	(e.g. 'plat/marvell/a8k/a7040_cust').
+- The platform name for build purposes is called "<soc>_cust" (e.g. a7040_cust).
+- The build system will reuse all files from within the soc directory, and take only the porting
+  files from the customer platform directory.
+
+Files that require porting are located at "plat/marvell/<soc family>/<soc>_cust" directory.
+
+
+Armada-70x0/Armada-80x0 Porting
+-------------------------------
+
+  - SoC Physical Address Map (marvell_plat_config.c):
+	- This file describes the SoC physical memory mapping to be used for the CCU, IOWIN, AXI-MBUS and IOB
+	  address decode units (Refer to the functional spec for more details).
+	- In most cases, using the default address decode windows should work OK.
+	- In cases where a special physical address map is needed (e.g. Special size for PCIe MEM windows,
+	  large memory mapped SPI flash...), then porting of the SoC memory map is required.
+	- Note: For a detailed information on how CCU, IOWIN, AXI-MBUS & IOB work, please refer to the SoC functional spec,
+	  and under "docs/marvell/misc/mvebu-[ccu/iob/amb/io-win].txt" files.
+
+  - boot loader recovery (marvell_plat_config.c):
+	- Background:
+		boot rom can skip the current image and choose to boot from next position if a specific value
+		(0xDEADB002) is returned by the ble main function. This feature is used for boot loader recovery
+		by booting from a valid flash-image saved in next position on flash (e.g. address 2M in SPI flash).
+
+		Supported options to implement the skip request are:
+			- GPIO
+			- I2C
+			- User defined
+
+	- Porting:
+		Under marvell_plat_config.c, implement struct skip_image that includes specific board parameters.
+		.. warning:: to disable this feature make sure the struct skip_image is not implemented.
+
+	- Example:
+		In A7040-DB specific implementation (plat/marvell/a8k/a70x0/board/marvell_plat_config.c),
+		the image skip is implemented using GPIO: mpp 33 (SW5).
+
+		Before resetting the board make sure there is a valid image on the next flash address:
+			-tftp [valid address] flash-image.bin
+			-sf update [valid address] 0x2000000 [size]
+
+		Press reset and keep pressing the button connected to the chosen GPIO pin. A skip image request
+		message is printed on the screen and boot rom boots from the saved image at the next position.
+
+  - DDR Porting (dram_port.c):
+	- This file defines the dram topology and parameters of the target board.
+	- The DDR code is part of the BLE component, which is an extension of ARM Trusted Firmware (TF-A).
+	- The DDR driver called mv_ddr is released separately apart from TF-A sources.
+	- The BLE and consequently, the DDR init code is executed at the early stage of the boot process.
+	- Each supported platform of the TF-A has its own DDR porting file called dram_port.c located at
+	  ``atf/plat/marvell/a8k/<platform>/board`` directory.
+	- Please refer to '<path_to_mv_ddr_sources>/doc/porting_guide.txt' for detailed porting description.
+	- The build target directory is "build/<platform>/release/ble".
+
+  - Comphy Porting (phy-porting-layer.h or phy-default-porting-layer.h)
+	- Background:
+		Some of the comphy's parameters value depend on the HW connection between the SoC and the PHY. Every
+		board type has specific HW characteristics like wire length. Due to those differences some comphy
+		parameters vary between board types. Therefore each board type can have its own list of values for
+		all relevant comphy parameters. The PHY porting layer specifies which parameters need to be suited and
+		the board designer should provide relevant values.
+
+		.. seealso::
+			For XFI/SFI comphy type there is procedure "rx_training" which eases process of suiting some of
+			the parameters. Please see :ref:`uboot_cmd` section: rx_training.
+
+		The PHY porting layer simplifies updating static values per board type, which are now grouped in one place.
+
+		.. note::
+			The parameters for the same type of comphy may vary even for the same board type, it is because
+			the lanes from comphy-x to some PHY may have different HW characteristic than lanes from
+			comphy-y to the same (multiplexed) or other PHY.
+
+	- Porting:
+		The porting layer for PHY was introduced in TF-A. There is one file
+		``drivers/marvell/comphy/phy-default-porting-layer.h`` which contains the defaults. Those default
+		parameters are used only if there is no appropriate phy-porting-layer.h file under:
+		``plat/marvell/<soc family>/<platform>/board/phy-porting-layer.h``. If the phy-porting-layer.h exists,
+		the phy-default-porting-layer.h is not going to be included.
+
+		.. warning::
+			Not all comphy types are already reworked to support the PHY porting layer, currently the porting
+			layer is supported for XFI/SFI and SATA comphy types.
+
+		The easiest way to prepare the PHY porting layer for custom board is to copy existing example to a new
+		platform:
+
+		- cp ``plat/marvell/a8k/a80x0/board/phy-porting-layer.h`` "plat/marvell/<soc family>/<platform>/board/phy-porting-layer.h"
+		- adjust relevant parameters or
+		- if different comphy index is used for specific feature, move it to proper table entry and then adjust.
+
+		.. note::
+			The final table size with comphy parameters can be different, depending on the CP module count for
+			given SoC type.
+
+	- Example:
+		Example porting layer for armada-8040-db is under: ``plat/marvell/a8k/a80x0/board/phy-porting-layer.h``
+
+		.. note::
+			If there is no PHY porting layer for new platform (missing phy-porting-layer.h), the default
+			values are used (drivers/marvell/comphy/phy-default-porting-layer.h) and the user is warned:
+
+		.. warning::
+			"Using default comphy parameters - it may be required to suit them for your board".
diff --git a/docs/plat/meson-gxbb.rst b/docs/plat/meson-gxbb.rst
new file mode 100644
index 0000000..2cd8342
--- /dev/null
+++ b/docs/plat/meson-gxbb.rst
@@ -0,0 +1,26 @@
+Amlogic Meson S905 (GXBB)
+=========================
+
+The Amlogic Meson S905 is a SoC with a quad core Arm Cortex-A53 running at
+1.5Ghz. It also contains a Cortex-M3 used as SCP.
+
+This port is a minimal implementation of BL31 capable of booting mainline U-Boot
+and Linux:
+
+- SCPI support.
+- Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0
+  can't be turned off, so there is a workaround to hide this from the caller.
+- GICv2 driver set up.
+- Basic SIP services (read efuse data, enable/disable JTAG).
+
+In order to build it:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=gxbb bl31
+
+This port has been tested in a ODROID-C2. After building it, follow the
+instructions in the `U-Boot repository`_, replacing the mentioned **bl31.bin**
+by the one built from this port.
+
+.. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/odroid-c2/README.odroid-c2
diff --git a/docs/plat/meson-gxl.rst b/docs/plat/meson-gxl.rst
new file mode 100644
index 0000000..c6d8504
--- /dev/null
+++ b/docs/plat/meson-gxl.rst
@@ -0,0 +1,27 @@
+Amlogic Meson S905x (GXL)
+=========================
+
+The Amlogic Meson S905x is a SoC with a quad core Arm Cortex-A53 running at
+1.5Ghz. It also contains a Cortex-M3 used as SCP.
+
+This port is a minimal implementation of BL31 capable of booting mainline U-Boot
+and Linux:
+
+- SCPI support.
+- Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0
+  can't be turned off, so there is a workaround to hide this from the caller.
+- GICv2 driver set up.
+- Basic SIP services (read efuse data, enable/disable JTAG).
+
+In order to build it:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=gxl
+
+This port has been tested on a Lepotato. After building it, follow the
+instructions in the `gxlimg repository` or `U-Boot repository`_, replacing the
+mentioned **bl31.img** by the one built from this port.
+
+.. _gxlimg repository: https://github.com/repk/gxlimg/blob/master/README
+.. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/p212/README.libretech-cc
diff --git a/docs/plat/mt8183.rst b/docs/plat/mt8183.rst
new file mode 100644
index 0000000..c639be1
--- /dev/null
+++ b/docs/plat/mt8183.rst
@@ -0,0 +1,20 @@
+MediaTek 8183
+=============
+
+MediaTek 8183 (MT8183) is a 64-bit ARM SoC introduced by MediaTek in early 2018.
+The chip incorporates eight cores - four Cortex-A53 little cores and Cortex-A73.
+Both clusters can operate at up to 2 GHz.
+
+Boot Sequence
+-------------
+
+::
+
+    Boot Rom --> Coreboot --> TF-A BL31 --> Depthcharge --> Linux Kernel
+
+How to Build
+------------
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=mt8183 DEBUG=1
diff --git a/docs/plat/nvidia-tegra.rst b/docs/plat/nvidia-tegra.rst
new file mode 100644
index 0000000..bc9e35b
--- /dev/null
+++ b/docs/plat/nvidia-tegra.rst
@@ -0,0 +1,140 @@
+NVIDIA Tegra
+============
+
+-  .. rubric:: T186
+      :name: t186
+
+The NVIDIA® Parker (T186) series system-on-chip (SoC) delivers a heterogeneous
+multi-processing (HMP) solution designed to optimize performance and
+efficiency.
+
+T186 has Dual NVIDIA Denver 2 ARM® CPU cores, plus Quad ARM Cortex®-A57 cores,
+in a coherent multiprocessor configuration. The Denver 2 and Cortex-A57 cores
+support ARMv8, executing both 64-bit Aarch64 code, and 32-bit Aarch32 code
+including legacy ARMv7 applications. The Denver 2 processors each have 128 KB
+Instruction and 64 KB Data Level 1 caches; and have a 2MB shared Level 2
+unified cache. The Cortex-A57 processors each have 48 KB Instruction and 32 KB
+Data Level 1 caches; and also have a 2 MB shared Level 2 unified cache. A
+high speed coherency fabric connects these two processor complexes and allows
+heterogeneous multi-processing with all six cores if required.
+
+-  .. rubric:: T210
+      :name: t210
+
+T210 has Quad Arm® Cortex®-A57 cores in a switched configuration with a
+companion set of quad Arm Cortex-A53 cores. The Cortex-A57 and A53 cores
+support Armv8-A, executing both 64-bit Aarch64 code, and 32-bit Aarch32 code
+including legacy Armv7-A applications. The Cortex-A57 processors each have
+48 KB Instruction and 32 KB Data Level 1 caches; and have a 2 MB shared
+Level 2 unified cache. The Cortex-A53 processors each have 32 KB Instruction
+and 32 KB Data Level 1 caches; and have a 512 KB shared Level 2 unified cache.
+
+-  .. rubric:: T132
+      :name: t132
+
+Denver is NVIDIA's own custom-designed, 64-bit, dual-core CPU which is
+fully Armv8-A architecture compatible. Each of the two Denver cores
+implements a 7-way superscalar microarchitecture (up to 7 concurrent
+micro-ops can be executed per clock), and includes a 128KB 4-way L1
+instruction cache, a 64KB 4-way L1 data cache, and a 2MB 16-way L2
+cache, which services both cores.
+
+Denver implements an innovative process called Dynamic Code Optimization,
+which optimizes frequently used software routines at runtime into dense,
+highly tuned microcode-equivalent routines. These are stored in a
+dedicated, 128MB main-memory-based optimization cache. After being read
+into the instruction cache, the optimized micro-ops are executed,
+re-fetched and executed from the instruction cache as long as needed and
+capacity allows.
+
+Effectively, this reduces the need to re-optimize the software routines.
+Instead of using hardware to extract the instruction-level parallelism
+(ILP) inherent in the code, Denver extracts the ILP once via software
+techniques, and then executes those routines repeatedly, thus amortizing
+the cost of ILP extraction over the many execution instances.
+
+Denver also features new low latency power-state transitions, in addition
+to extensive power-gating and dynamic voltage and clock scaling based on
+workloads.
+
+Directory structure
+-------------------
+
+-  plat/nvidia/tegra/common - Common code for all Tegra SoCs
+-  plat/nvidia/tegra/soc/txxx - Chip specific code
+
+Trusted OS dispatcher
+---------------------
+
+Tegra supports multiple Trusted OS'.
+
+- Trusted Little Kernel (TLK): In order to include the 'tlkd' dispatcher in
+  the image, pass 'SPD=tlkd' on the command line while preparing a bl31 image.
+- Trusty: In order to include the 'trusty' dispatcher in the image, pass
+  'SPD=trusty' on the command line while preparing a bl31 image.
+
+This allows other Trusted OS vendors to use the upstream code and include
+their dispatchers in the image without changing any makefiles.
+
+These are the supported Trusted OS' by Tegra platforms.
+
+Tegra132: TLK
+Tegra210: TLK and Trusty
+Tegra186: Trusty
+
+Scatter files
+-------------
+
+Tegra platforms currently support scatter files and ld.S scripts. The scatter
+files help support ARMLINK linker to generate BL31 binaries. For now, there
+exists a common scatter file, plat/nvidia/tegra/scat/bl31.scat, for all Tegra
+SoCs. The `LINKER` build variable needs to point to the ARMLINK binary for
+the scatter file to be used. Tegra platforms have verified BL31 image generation
+with ARMCLANG (compilation) and ARMLINK (linking) for the Tegra186 platforms.
+
+Preparing the BL31 image to run on Tegra SoCs
+---------------------------------------------
+
+.. code:: shell
+
+    CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-none-elf- make PLAT=tegra \
+    TARGET_SOC=<target-soc e.g. t186|t210|t132> SPD=<dispatcher e.g. trusty|tlkd>
+    bl31
+
+Platforms wanting to use different TZDRAM\_BASE, can add ``TZDRAM_BASE=<value>``
+to the build command line.
+
+The Tegra platform code expects a pointer to the following platform specific
+structure via 'x1' register from the BL2 layer which is used by the
+bl31\_early\_platform\_setup() handler to extract the TZDRAM carveout base and
+size for loading the Trusted OS and the UART port ID to be used. The Tegra
+memory controller driver programs this base/size in order to restrict NS
+accesses.
+
+typedef struct plat\_params\_from\_bl2 {
+/\* TZ memory size */
+uint64\_t tzdram\_size;
+/* TZ memory base */
+uint64\_t tzdram\_base;
+/* UART port ID \*/
+int uart\_id;
+/* L2 ECC parity protection disable flag \*/
+int l2\_ecc\_parity\_prot\_dis;
+/* SHMEM base address for storing the boot logs \*/
+uint64\_t boot\_profiler\_shmem\_base;
+} plat\_params\_from\_bl2\_t;
+
+Power Management
+----------------
+
+The PSCI implementation expects each platform to expose the 'power state'
+parameter to be used during the 'SYSTEM SUSPEND' call. The state-id field
+is implementation defined on Tegra SoCs and is preferably defined by
+tegra\_def.h.
+
+Tegra configs
+-------------
+
+-  'tegra\_enable\_l2\_ecc\_parity\_prot': This flag enables the L2 ECC and Parity
+   Protection bit, for Arm Cortex-A57 CPUs, during CPU boot. This flag will
+   be enabled by Tegrs SoCs during 'Cluster power up' or 'System Suspend' exit.
diff --git a/docs/plat/poplar.rst b/docs/plat/poplar.rst
new file mode 100644
index 0000000..5884ed9
--- /dev/null
+++ b/docs/plat/poplar.rst
@@ -0,0 +1,176 @@
+Description
+===========
+
+Poplar is the first development board compliant with the 96Boards Enterprise
+Edition TV Platform specification.
+
+The board features the Hi3798C V200 with an integrated quad-core 64-bit
+Arm Cortex A53 processor and high performance Mali T720 GPU, making it capable
+of running any commercial set-top solution based on Linux or Android.
+
+It supports a premium user experience with up to H.265 HEVC decoding of 4K
+video at 60 frames per second.
+
+::
+
+    SOC Hisilicon Hi3798CV200
+    CPU Quad-core Arm Cortex-A53 64 bit
+    DRAM DDR3/3L/4 SDRAM interface, maximum 32-bit data width 2 GB
+    USB Two USB 2.0 ports One USB 3.0 ports
+    CONSOLE USB-micro port for console support
+    ETHERNET 1 GBe Ethernet
+    PCIE One PCIe 2.0 interfaces
+    JTAG 8-Pin JTAG
+    EXPANSION INTERFACE Linaro 96Boards Low Speed Expansion slot
+    DIMENSION Standard 160×120 mm 96Boards Enterprice Edition form factor
+    WIFI 802.11AC 2*2 with Bluetooth
+    CONNECTORS One connector for Smart Card One connector for TSI
+
+At the start of the boot sequence, the bootROM executes the so called l-loader
+binary whose main role is to change the processor state to 64bit mode. This
+must happen prior to invoking Trusted Firmware-A:
+
+::
+
+    l-loader --> Trusted Firmware-A --> u-boot
+
+How to build
+============
+
+Code Locations
+--------------
+
+-  Trusted Firmware-A:
+   `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+-  l-loader:
+   `link <https://github.com/Linaro/poplar-l-loader.git>`__
+
+-  u-boot:
+   `link <http://git.denx.de/u-boot.git>`__
+
+Build Procedure
+---------------
+
+-  Fetch all the above 3 repositories into local host.
+   Make all the repositories in the same ${BUILD\_PATH}.
+
+-  Prepare the AARCH64 toolchain.
+
+-  Build u-boot using poplar_defconfig
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu- poplar_defconfig
+       make CROSS_COMPILE=aarch64-linux-gnu-
+
+-  Build atf providing the previously generated u-boot.bin as the BL33 image
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu-  all fip SPD=none PLAT=poplar
+       BL33=u-boot.bin
+
+-  Build l-loader (generated the final fastboot.bin)
+       1. copy the atf generated files fip.bin and bl1.bin to l-loader/atf/
+       2. export ARM_TRUSTED_FIRMWARE=${ATF_SOURCE_PATH)
+       3. make
+
+Install Procedure
+-----------------
+
+- Copy l-loader/fastboot.bin to a FAT partition on a USB pen drive.
+
+- Plug the USB pen drive to any of the USB2 ports
+
+- Power the board while keeping S3 pressed (usb_boot)
+
+The system will boot into a u-boot shell which you can then use to write the
+working firmware to eMMC.
+
+Boot trace
+==========
+
+::
+
+    Bootrom start
+    Boot Media: eMMC
+    Decrypt auxiliary code ...OK
+
+    lsadc voltage min: 000000FE, max: 000000FF, aver: 000000FE, index: 00000000
+
+    Entry boot auxiliary code
+
+    Auxiliary code - v1.00
+    DDR code - V1.1.2 20160205
+    Build: Mar 24 2016 - 17:09:44
+    Reg Version:  v134
+    Reg Time:     2016/03/18 09:44:55
+    Reg Name:     hi3798cv2dmb_hi3798cv200_ddr3_2gbyte_8bitx4_4layers.reg
+
+    Boot auxiliary code success
+    Bootrom success
+
+    LOADER:  Switched to aarch64 mode
+    LOADER:  Entering ARM TRUSTED FIRMWARE
+    LOADER:  CPU0 executes at 0x000ce000
+
+    INFO:    BL1: 0xe1000 - 0xe7000 [size = 24576]
+    NOTICE:  Booting Trusted Firmware
+    NOTICE:  BL1: v1.3(debug):v1.3-372-g1ba9c60
+    NOTICE:  BL1: Built : 17:51:33, Apr 30 2017
+    INFO:    BL1: RAM 0xe1000 - 0xe7000
+    INFO:    BL1: Loading BL2
+    INFO:    Loading image id=1 at address 0xe9000
+    INFO:    Image id=1 loaded at address 0xe9000, size = 0x5008
+    NOTICE:  BL1: Booting BL2
+    INFO:    Entry point address = 0xe9000
+    INFO:    SPSR = 0x3c5
+    NOTICE:  BL2: v1.3(debug):v1.3-372-g1ba9c60
+    NOTICE:  BL2: Built : 17:51:33, Apr 30 2017
+    INFO:    BL2: Loading BL31
+    INFO:    Loading image id=3 at address 0x129000
+    INFO:    Image id=3 loaded at address 0x129000, size = 0x8038
+    INFO:    BL2: Loading BL33
+    INFO:    Loading image id=5 at address 0x37000000
+    INFO:    Image id=5 loaded at address 0x37000000, size = 0x58f17
+    NOTICE:  BL1: Booting BL31
+    INFO:    Entry point address = 0x129000
+    INFO:    SPSR = 0x3cd
+    INFO:    Boot bl33 from 0x37000000 for 364311 Bytes
+    NOTICE:  BL31: v1.3(debug):v1.3-372-g1ba9c60
+    NOTICE:  BL31: Built : 17:51:33, Apr 30 2017
+    INFO:    BL31: Initializing runtime services
+    INFO:    BL31: Preparing for EL3 exit to normal world
+    INFO:    Entry point address = 0x37000000
+    INFO:    SPSR = 0x3c9
+
+
+    U-Boot 2017.05-rc2-00130-gd2255b0 (Apr 30 2017 - 17:51:28 +0200)poplar
+
+    Model: HiSilicon Poplar Development Board
+    BOARD: Hisilicon HI3798cv200 Poplar
+    DRAM:  1 GiB
+    MMC:   Hisilicon DWMMC: 0
+    In:    serial@f8b00000
+    Out:   serial@f8b00000
+    Err:   serial@f8b00000
+    Net:   Net Initialization Skipped
+    No ethernet found.
+
+    Hit any key to stop autoboot:  0
+    starting USB...
+    USB0:   USB EHCI 1.00
+    scanning bus 0 for devices... 1 USB Device(s) found
+    USB1:   USB EHCI 1.00
+    scanning bus 1 for devices... 4 USB Device(s) found
+           scanning usb for storage devices... 1 Storage Device(s) found
+           scanning usb for ethernet devices... 1 Ethernet Device(s) found
+
+    USB device 0:
+        Device 0: Vendor: SanDisk Rev: 1.00 Prod: Cruzer Blade
+                Type: Removable Hard Disk
+                Capacity: 7632.0 MB = 7.4 GB (15630336 x 512)
+    ... is now current device
+    Scanning usb 0:1...
+    =>
diff --git a/docs/plat/qemu.rst b/docs/plat/qemu.rst
new file mode 100644
index 0000000..4ebe64b
--- /dev/null
+++ b/docs/plat/qemu.rst
@@ -0,0 +1,48 @@
+QEMU virt Armv8-A
+=================
+
+Trusted Firmware-A (TF-A) implements the EL3 firmware layer for QEMU virt
+Armv8-A. BL1 is used as the BootROM, supplied with the -bios argument.
+When QEMU starts all CPUs are released simultaneously, BL1 selects a
+primary CPU to handle the boot and the secondaries are placed in a polling
+loop to be released by normal world via PSCI.
+
+BL2 edits the Flattened Device Tree, FDT, generated by QEMU at run-time to
+add a node describing PSCI and also enable methods for the CPUs.
+
+An ARM64 defconfig v4.5 Linux kernel is known to boot, FDT doesn't need to be
+provided as it's generated by QEMU.
+
+Current limitations:
+
+-  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_GCC49/QEMU_EFI.fd
+
+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:
+
+-  ``bl2.bin`` -> BL2
+-  ``bl31.bin`` -> BL31
+-  ``bl33.bin`` -> BL33 (``QEMU_EFI.fd``)
+-  ``Image`` -> linux/Image
+
+To build:
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-none-elf- PLAT=qemu
+
+To start (QEMU v2.6.0):
+
+.. code:: shell
+
+    qemu-system-aarch64 -nographic -machine virt,secure=on -cpu cortex-a57  \
+        -kernel Image                           \
+        -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
diff --git a/docs/plat/rcar-gen3.rst b/docs/plat/rcar-gen3.rst
new file mode 100644
index 0000000..7107bea
--- /dev/null
+++ b/docs/plat/rcar-gen3.rst
@@ -0,0 +1,268 @@
+Renesas R-Car
+=============
+
+"R-Car" is the nickname for Renesas' system-on-chip (SoC) family for
+car information systems designed for the next-generation of automotive
+computing for the age of autonomous vehicles.
+
+The scalable R-Car hardware platform and flexible software platform
+cover the full product range, from the premium class to the entry
+level. Plug-ins are available for multiple open-source software tools.
+
+
+Renesas R-Car Gen3 evaluation boards:
+-------------------------------------
+
++------------+-----------------+-----------------------------+
+|            |     Standard    |   Low Cost Boards (LCB)     |
++============+=================+=============================+
+| R-Car H3   | - Salvator-X    | - R-Car Starter Kit Premier |
+|            | - Salvator-XS   |                             |
++------------+-----------------+-----------------------------+
+| R-Car M3-W | - Salvator-X    |                             |
+|            | - Salvator-XS   | - R-Car Starter Kit Pro     |
++------------+-----------------+-----------------------------+
+| R-Car M3-N | - Salvator-X    |                             |
+|            | - Salvator-XS   |                             |
++------------+-----------------+-----------------------------+
+| R-Car V3M  | - Eagle         | - Starter Kit               |
++------------+-----------------+-----------------------------+
+| R-Car V3H  | - Condor        | - Starter Kit               |
++------------+-----------------+-----------------------------+
+| R-Car D3   | - Draak         |                             |
++------------+-----------------+-----------------------------+
+
+`boards info <https://elinux.org/R-Car>`__
+
+The current TF-A port has been tested on the R-Car H3 Salvator-X
+Soc_id r8a7795 revision ES1.1 (uses a Secure Payload Dispatcher)
+
+
+::
+
+    ARM CA57 (ARMv8) 1.5 GHz quad core, with NEON/VFPv4, L1$ I/D
+    48K/32K, L2$ 2MB
+    ARM CA53 (ARMv8) 1.2 GHz quad core, with NEON/VFPv4, L1$ I/D 32K/32K,
+    L2$ 512K
+    Memory controller for LPDDR4-3200 4GB in 2 channels, each 64-bit wide
+    Two- and three-dimensional graphics engines,
+    Video processing units,
+    3 channels Display Output,
+    6 channels Video Input,
+    SD card host interface,
+    USB3.0 and USB2.0 interfaces,
+    CAN interfaces
+    Ethernet AVB
+    PCI Express Interfaces
+    Memories
+        INTERNAL 384KB SYSTEM RAM
+        DDR 4 GB LPDDR4
+        HYPERFLASH 64 MB HYPER FLASH (512 MBITS, 160 MHZ, 320 MBYTES/S)
+        QSPI FLASH 16MB QSPI (128 MBITS,80 MHZ,80 MBYTES/S)1 HEADER QSPI
+        MODULE
+        EMMC 32 GB EMMC (HS400 240 MBYTES/S)
+        MICROSD-CARD SLOT (SDR104 100 MBYTES/S)
+
+
+Overview
+--------
+On the rcar-gen3 the BOOTROM starts the cpu at EL3; for this port BL2
+will therefore be entered at this exception level (the Renesas' ATF
+reference tree [1] resets into EL1 before entering BL2 - see its
+bl2.ld.S)
+
+BL2 initializes DDR (and on some platforms i2c to interface to the
+PMIC) before determining the boot reason (cold or warm).
+
+During suspend all CPUs are switched off and the DDR is put in backup
+mode (some kind of self-refresh mode). This means that BL2 is always
+entered in a cold boot scenario.
+
+Once BL2 boots, it determines the boot reason, writes it to shared
+memory (BOOT_KIND_BASE) together with the BL31 parameters
+(PARAMS_BASE) and jumps to BL31.
+
+To all effects, BL31 is as if it is being entered in reset mode since
+it still needs to initialize the rest of the cores; this is the reason
+behind using direct shared memory access to  BOOT_KIND_BASE _and_
+PARAMS_BASE instead of using registers to get to those locations (see
+el3_common_macros.S and bl31_entrypoint.S for the RESET_TO_BL31 use
+case).
+
+Depending on the boot reason BL31 initializes the rest of the cores:
+in case of suspend, it uses a MBOX memory region to recover the
+program counters.
+
+[1] https://github.com/renesas-rcar/arm-trusted-firmware
+
+
+How to build
+------------
+
+The TF-A build options depend on the target board so you will have to
+refer to those specific instructions. What follows is customized to
+the H3 SiP Salvator-X development system used in this port.
+
+Build Tested:
+~~~~~~~~~~~~~
+RCAR_OPT="LSI=H3 RCAR_DRAM_SPLIT=1 RCAR_LOSSY_ENABLE=1"
+MBEDTLS_DIR=$mbedtls_src
+
+$ MBEDTLS_DIR=$mbedtls_src_tree make clean bl2 bl31 rcar_layout_tool \
+PLAT=rcar ${RCAR_OPT} SPD=opteed
+
+System Tested:
+~~~~~~~~~~~~~~
+* mbed_tls:
+  git@github.com:ARMmbed/mbedtls.git [devel]
+
+  commit 552754a6ee82bab25d1bdf28c8261a4518e65e4d
+  Merge: 68dbc94 f34a4c1
+  Author: Simon Butcher <simon.butcher@arm.com>
+  Date:   Thu Aug 30 00:57:28 2018 +0100
+
+* optee_os:
+  https://github.com/BayLibre/optee_os
+
+  Until it gets merged into OP-TEE, the port requires Renesas'
+  Trusted   Environment with a modification to support power
+  management.
+  commit 80105192cba9e704ebe8df7ab84095edc2922f84
+
+  Author: Jorge Ramirez-Ortiz <jramirez@baylibre.com>
+  Date:   Thu Aug 30 16:49:49 2018 +0200
+  plat-rcar: cpu-suspend: handle the power level
+  Signed-off-by: Jorge Ramirez-Ortiz <jramirez@baylibre.com>
+
+* u-boot:
+  The port has beent tested using mainline uboot.
+
+  commit 4cdeda511f8037015b568396e6dcc3d8fb41e8c0
+  Author: Fabio Estevam <festevam@gmail.com>
+  Date:   Tue Sep 4 10:23:12 2018 -0300
+
+* linux:
+  The port has beent tested using mainline kernel.
+
+  commit 7876320f88802b22d4e2daf7eb027dd14175a0f8
+  Author: Linus Torvalds <torvalds@linux-foundation.org>
+  Date:   Sun Sep 16 11:52:37 2018 -0700
+  Linux 4.19-rc4
+
+TF-A Build Procedure
+~~~~~~~~~~~~~~~~~~~~
+
+-  Fetch all the above 4 repositories.
+
+-  Prepare the AARCH64 toolchain.
+
+-  Build u-boot using r8a7795_salvator-x_defconfig.
+   Result: u-boot-elf.srec
+
+.. code:: bash
+
+       make CROSS_COMPILE=aarch64-linux-gnu-
+	  r8a7795_salvator-x_defconfig
+
+       make CROSS_COMPILE=aarch64-linux-gnu-
+
+-  Build atf
+   Result: bootparam_sa0.srec, cert_header_sa6.srec, bl2.srec, bl31.srec
+
+.. code:: bash
+
+       RCAR_OPT="LSI=H3 RCAR_DRAM_SPLIT=1 RCAR_LOSSY_ENABLE=1"
+
+       MBEDTLS_DIR=$mbedtls_src_tree make clean bl2 bl31 rcar \
+       PLAT=rcar ${RCAR_OPT} SPD=opteed
+
+-  Build optee-os
+   Result: tee.srec
+
+.. code:: bash
+
+       make -j8 PLATFORM="rcar" CFG_ARM64_core=y
+
+Install Procedure
+~~~~~~~~~~~~~~~~~
+
+- Boot the board in Mini-monitor mode and enable access to the
+  Hyperflash.
+
+
+- Use the XSL2 Mini-monitor utility to accept all the SREC ascii
+  transfers over serial.
+
+
+Boot trace
+----------
+
+Notice that BL31 traces are not accessible via the console and that in
+order to verbose the BL2 output you will have to compile TF-A with
+LOG_LEVEL=50 and DEBUG=1
+
+::
+
+   Initial Program Loader(CA57) Rev.1.0.22
+   NOTICE:  BL2: PRR is R-Car H3 Ver.1.1
+   NOTICE:  BL2: Board is Salvator-X Rev.1.0
+   NOTICE:  BL2: Boot device is HyperFlash(80MHz)
+   NOTICE:  BL2: LCM state is CM
+   NOTICE:  AVS setting succeeded. DVFS_SetVID=0x53
+   NOTICE:  BL2: DDR1600(rev.0.33)NOTICE:  [COLD_BOOT]NOTICE:  ..0
+   NOTICE:  BL2: DRAM Split is 4ch
+   NOTICE:  BL2: QoS is default setting(rev.0.37)
+   NOTICE:  BL2: Lossy Decomp areas
+   NOTICE:       Entry 0: DCMPAREACRAx:0x80000540 DCMPAREACRBx:0x570
+   NOTICE:       Entry 1: DCMPAREACRAx:0x40000000 DCMPAREACRBx:0x0
+   NOTICE:       Entry 2: DCMPAREACRAx:0x20000000 DCMPAREACRBx:0x0
+   NOTICE:  BL2: v2.0(release):v2.0-rc0-32-gbcda69a
+   NOTICE:  BL2: Built : 16:41:23, Oct  2 2018
+   NOTICE:  BL2: Normal boot
+   INFO:    BL2: Doing platform setup
+   INFO:    BL2: Loading image id 3
+   NOTICE:  BL2: dst=0xe6322000 src=0x8180000 len=512(0x200)
+   NOTICE:  BL2: dst=0x43f00000 src=0x8180400 len=6144(0x1800)
+   WARNING: r-car ignoring the BL31 size from certificate,using
+   RCAR_TRUSTED_SRAM_SIZE instead
+   INFO:    Loading image id=3 at address 0x44000000
+   NOTICE:  rcar_file_len: len: 0x0003e000
+   NOTICE:  BL2: dst=0x44000000 src=0x81c0000 len=253952(0x3e000)
+   INFO:    Image id=3 loaded: 0x44000000 - 0x4403e000
+   INFO:    BL2: Loading image id 4
+   INFO:    Loading image id=4 at address 0x44100000
+   NOTICE:  rcar_file_len: len: 0x00100000
+   NOTICE:  BL2: dst=0x44100000 src=0x8200000 len=1048576(0x100000)
+   INFO:    Image id=4 loaded: 0x44100000 - 0x44200000
+   INFO:    BL2: Loading image id 5
+   INFO:    Loading image id=5 at address 0x50000000
+   NOTICE:  rcar_file_len: len: 0x00100000
+   NOTICE:  BL2: dst=0x50000000 src=0x8640000 len=1048576(0x100000)
+   INFO:    Image id=5 loaded: 0x50000000 - 0x50100000
+   NOTICE:  BL2: Booting BL31
+   INFO:    Entry point address = 0x44000000
+   INFO:    SPSR = 0x3cd
+   VERBOSE: Argument #0 = 0xe6325578
+   VERBOSE: Argument #1 = 0x0
+   VERBOSE: Argument #2 = 0x0
+   VERBOSE: Argument #3 = 0x0
+   VERBOSE: Argument #4 = 0x0
+   VERBOSE: Argument #5 = 0x0
+   VERBOSE: Argument #6 = 0x0
+   VERBOSE: Argument #7 = 0x0
+
+
+   U-Boot 2018.09-rc3-00028-g3711616 (Sep 27 2018 - 18:50:24 +0200)
+
+   CPU: Renesas Electronics R8A7795 rev 1.1
+   Model: Renesas Salvator-X board based on r8a7795 ES2.0+
+   DRAM:  3.5 GiB
+   Flash: 64 MiB
+   MMC:   sd@ee100000: 0, sd@ee140000: 1, sd@ee160000: 2
+   Loading Environment from MMC... OK
+   In:    serial@e6e88000
+   Out:   serial@e6e88000
+   Err:   serial@e6e88000
+   Net:   eth0: ethernet@e6800000
+   Hit any key to stop autoboot:  0
+   =>
diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst
new file mode 100644
index 0000000..b7c43fb
--- /dev/null
+++ b/docs/plat/rockchip.rst
@@ -0,0 +1,55 @@
+Rockchip SoCs
+=============
+
+Trusted Firmware-A supports a number of Rockchip ARM SoCs from both
+AARCH32 and AARCH64 fields.
+
+This includes right now:
+-  px30: Quad-Core Cortex-A53
+-  rk3288: Quad-Core Cortex-A17 (past A12)
+-  rk3328: Quad-Core Cortex-A53
+-  rk3368: Octa-Core Cortex-A53
+-  rk3399: Hexa-Core Cortex-A53/A72
+
+
+Boot Sequence
+-------------
+
+For AARCH32:
+    Bootrom --> BL1/BL2 --> BL32 --> BL33 --> Linux kernel
+
+For AARCH64:
+    Bootrom --> BL1/BL2 --> BL31 --> BL33 --> Linux kernel
+
+BL1/2 and BL33 can currently be supplied from either:
+-  Coreboot + Depthcharge
+-  U-Boot - either separately as TPL+SPL or only SPL
+
+
+How to build
+------------
+
+Rockchip SoCs expect TF-A's BL31 (AARCH64) or BL32 (AARCH32) to get
+integrated with other boot software like U-Boot or Coreboot, so only
+these images need to get build from the TF-A repository.
+
+For AARCH64 architectures the build command looks like
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3399 bl32
+
+while AARCH32 needs a slightly different command
+
+    make ARCH=aarch32 CROSS_COMPILE=arm-linux-gnueabihf- PLAT=rk3288 AARCH32_SP=sp_min bl32
+
+Both need replacing the PLAT argument with the platform from above you
+want to build for and the CROSS_COMPILE argument with you cross-
+compilation toolchain.
+
+
+How to deploy
+-------------
+
+Both upstream U-Boot and Coreboot projects contain instructions on where
+to put the built images during their respective build process.
+So after successfully building TF-A just follow their build instructions
+to continue.
diff --git a/docs/plat/rpi3.rst b/docs/plat/rpi3.rst
new file mode 100644
index 0000000..38c3dfa
--- /dev/null
+++ b/docs/plat/rpi3.rst
@@ -0,0 +1,466 @@
+Raspberry Pi 3
+==============
+
+The `Raspberry Pi 3`_ is an inexpensive single-board computer that contains four
+Arm Cortex-A53 cores.
+
+The following instructions explain how to use this port of the TF-A with the
+default distribution of `Raspbian`_ because that's the distribution officially
+supported by the Raspberry Pi Foundation. At the moment of writing this, the
+officially supported kernel is a AArch32 kernel. This doesn't mean that this
+port of TF-A can't boot a AArch64 kernel. The `Linux tree fork`_ maintained by
+the Foundation can be compiled for AArch64 by following the steps in
+`AArch64 kernel build instructions`_.
+
+**IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM,
+which is available from both the Non-secure and Secure worlds. This port
+shouldn't be considered more than a prototype to play with and implement
+elements like PSCI to support the Linux kernel.
+
+Design
+------
+
+The SoC used by the Raspberry Pi 3 is the Broadcom BCM2837. It is a SoC with a
+VideoCore IV that acts as primary processor (and loads everything from the SD
+card) and is located between all Arm cores and the DRAM. Check the `Raspberry Pi
+3 documentation`_ for more information.
+
+This explains why it is possible to change the execution state (AArch64/AArch32)
+depending on a few files on the SD card. We only care about the cases in which
+the cores boot in AArch64 mode.
+
+The rules are simple:
+
+- If a file called ``kernel8.img`` is located on the ``boot`` partition of the
+  SD card, it will load it and execute in EL2 in AArch64. Basically, it executes
+  a `default AArch64 stub`_ at address **0x0** that jumps to the kernel.
+
+- If there is also a file called ``armstub8.bin``, it will load it at address
+  **0x0** (instead of the default stub) and execute it in EL3 in AArch64. All
+  the cores are powered on at the same time and start at address **0x0**.
+
+This means that we can use the default AArch32 kernel provided in the official
+`Raspbian`_ distribution by renaming it to ``kernel8.img``, while TF-A and
+anything else we need is in ``armstub8.bin``. This way we can forget about the
+default bootstrap code. When using a AArch64 kernel, it is only needed to make
+sure that the name on the SD card is ``kernel8.img``.
+
+Ideally, we want to load the kernel and have all cores available, which means
+that we need to make the secondary cores work in the way the kernel expects, as
+explained in `Secondary cores`_. In practice, a small bootstrap is needed
+between TF-A and the kernel.
+
+To get the most out of a AArch32 kernel, we want to boot it in Hypervisor mode
+in AArch32. This means that BL33 can't be in EL2 in AArch64 mode. The
+architecture specifies that AArch32 Hypervisor mode isn't present when AArch64
+is used for EL2. When using a AArch64 kernel, it should simply start in EL2.
+
+Placement of images
+~~~~~~~~~~~~~~~~~~~
+
+The file ``armstub8.bin`` contains BL1 and the FIP. It is needed to add padding
+between them so that the addresses they are loaded to match the ones specified
+when compiling TF-A. This is done automatically by the build system.
+
+The device tree block is loaded by the VideoCore loader from an appropriate
+file, but we can specify the address it is loaded to in ``config.txt``.
+
+The file ``kernel8.img`` contains a kernel image that is loaded to the address
+specified in ``config.txt``. The `Linux kernel tree`_ has information about how
+a AArch32 Linux kernel image is loaded in ``Documentation/arm/Booting``:
+
+::
+
+    The zImage may also be placed in system RAM and called there.  The
+    kernel should be placed in the first 128MiB of RAM.  It is recommended
+    that it is loaded above 32MiB in order to avoid the need to relocate
+    prior to decompression, which will make the boot process slightly
+    faster.
+
+There are no similar restrictions for AArch64 kernels, as specified in the file
+``Documentation/arm64/booting.txt``.
+
+This means that we need to avoid the first 128 MiB of RAM when placing the
+TF-A images (and specially the first 32 MiB, as they are directly used to
+place the uncompressed AArch32 kernel image. This way, both AArch32 and
+AArch64 kernels can be placed at the same address.
+
+In the end, the images look like the following diagram when placed in memory.
+All addresses are Physical Addresses from the point of view of the Arm cores.
+Again, note that this is all just part of the same DRAM that goes from
+**0x00000000** to **0x3F000000**, it just has different names to simulate a real
+secure platform!
+
+::
+
+    0x00000000 +-----------------+
+               |       ROM       | BL1
+    0x00020000 +-----------------+
+               |       FIP       |
+    0x00200000 +-----------------+
+               |                 |
+               |       ...       |
+               |                 |
+    0x01000000 +-----------------+
+               |       DTB       | (Loaded by the VideoCore)
+               +-----------------+
+               |                 |
+               |       ...       |
+               |                 |
+    0x02000000 +-----------------+
+               |     Kernel      | (Loaded by the VideoCore)
+               +-----------------+
+               |                 |
+               |       ...       |
+               |                 |
+    0x10000000 +-----------------+
+               |   Secure SRAM   | BL2, BL31
+    0x10100000 +-----------------+
+               |   Secure DRAM   | BL32 (Secure payload)
+    0x11000000 +-----------------+
+               | Non-secure DRAM | BL33
+               +-----------------+
+               |                 |
+               |       ...       |
+               |                 |
+    0x3F000000 +-----------------+
+               |       I/O       |
+    0x40000000 +-----------------+
+
+The area between **0x10000000** and **0x11000000** has to be manually protected
+so that the kernel doesn't use it. The current port tries to modify the live DTB
+to add a memreserve region that reserves the previously mentioned area.
+
+If this is not possible, the user may manually add ``memmap=16M$256M`` to the
+command line passed to the kernel in ``cmdline.txt``. See the `Setup SD card`_
+instructions to see how to do it. This system is strongly discouraged.
+
+The last 16 MiB of DRAM can only be accessed by the VideoCore, that has
+different mappings than the Arm cores in which the I/O addresses don't overlap
+the DRAM. The memory reserved to be used by the VideoCore is always placed at
+the end of the DRAM, so this space isn't wasted.
+
+Considering the 128 MiB allocated to the GPU and the 16 MiB allocated for
+TF-A, there are 880 MiB available for Linux.
+
+Boot sequence
+~~~~~~~~~~~~~
+
+The boot sequence of TF-A is the usual one except when booting an AArch32
+kernel. In that case, BL33 is booted in AArch32 Hypervisor mode so that it
+can jump to the kernel in the same mode and let it take over that privilege
+level. If BL33 was running in EL2 in AArch64 (as in the default bootflow of
+TF-A) it could only jump to the kernel in AArch32 in Supervisor mode.
+
+The `Linux kernel tree`_ has instructions on how to jump to the Linux kernel
+in ``Documentation/arm/Booting`` and ``Documentation/arm64/booting.txt``. The
+bootstrap should take care of this.
+
+This port support a direct boot of the Linux kernel from the firmware (as a BL33
+image). Alternatively, U-Boot or other bootloaders may be used.
+
+Secondary cores
+~~~~~~~~~~~~~~~
+
+This port of the Trusted Firmware-A supports ``PSCI_CPU_ON``,
+``PSCI_SYSTEM_RESET`` and ``PSCI_SYSTEM_OFF``. The last one doesn't really turn
+the system off, it simply reboots it and asks the VideoCore firmware to keep it
+in a low power mode permanently.
+
+The kernel used by `Raspbian`_ doesn't have support for PSCI, so it is needed to
+use mailboxes to trap the secondary cores until they are ready to jump to the
+kernel. This mailbox is located at a different address in the AArch32 default
+kernel than in the AArch64 kernel.
+
+Kernels with PSCI support can use the PSCI calls instead for a cleaner boot.
+
+Also, this port of TF-A has another Trusted Mailbox in Shared BL RAM. During
+cold boot, all secondary cores wait in a loop until they are given given an
+address to jump to in this Mailbox (``bl31_warm_entrypoint``).
+
+Once BL31 has finished and the primary core has jumped to the BL33 payload, it
+has to call ``PSCI_CPU_ON`` to release the secondary CPUs from the wait loop.
+The payload then makes them wait in another waitloop listening from messages
+from the kernel. When the primary CPU jumps into the kernel, it will send an
+address to the mailbox so that the secondary CPUs jump to it and are recognised
+by the kernel.
+
+Build Instructions
+------------------
+
+To boot a AArch64 kernel, only the AArch64 toolchain is required.
+
+To boot a AArch32 kernel, both AArch64 and AArch32 toolchains are required. The
+AArch32 toolchain is needed for the AArch32 bootstrap needed to load a 32-bit
+kernel.
+
+The build system concatenates BL1 and the FIP so that the addresses match the
+ones in the memory map. The resulting file is ``armstub8.bin``, located in the
+build folder (e.g. ``build/rpi3/debug/armstub8.bin``). To know how to use this
+file, follow the instructions in `Setup SD card`_.
+
+The following build options are supported:
+
+- ``RPI3_BL33_IN_AARCH32``: This port can load a AArch64 or AArch32 BL33 image.
+  By default this option is 0, which means that TF-A will jump to BL33 in EL2
+  in AArch64 mode. If set to 1, it will jump to BL33 in Hypervisor in AArch32
+  mode.
+
+- ``PRELOADED_BL33_BASE``: Used to specify the address of a BL33 binary that has
+  been preloaded by any other system than using the firmware. ``BL33`` isn't
+  needed in the build command line if this option is used. Specially useful
+  because the file ``kernel8.img`` can be loaded anywhere by modifying the file
+  ``config.txt``. It doesn't have to contain a kernel, it could have any
+  arbitrary payload.
+
+- ``RPI3_DIRECT_LINUX_BOOT``: Disabled by default. Set to 1 to enable the direct
+  boot of the Linux kernel from the firmware. Option ``RPI3_PRELOADED_DTB_BASE``
+  is mandatory when the direct Linux kernel boot is used. Options
+  ``PRELOADED_BL33_BASE`` will most likely be needed as well because it is
+  unlikely that the kernel image will fit in the space reserved for BL33 images.
+  This option can be combined with ``RPI3_BL33_IN_AARCH32`` in order to boot a
+  32-bit kernel. The only thing this option does is to set the arguments in
+  registers x0-x3 or r0-r2 as expected by the kernel.
+
+- ``RPI3_PRELOADED_DTB_BASE``: Auxiliary build option needed when using
+  ``RPI3_DIRECT_LINUX_BOOT=1``. This option allows to specify the location of a
+  DTB in memory.
+
+- ``RPI3_RUNTIME_UART``: Indicates whether the UART should be used at runtime
+  or disabled. ``-1`` (default) disables the runtime UART. Any other value
+  enables the default UART (currently UART1) for runtime messages.
+
+- ``RPI3_USE_UEFI_MAP``: Set to 1 to build ATF with the altername memory
+  mapping required for an UEFI firmware payload. These changes are needed
+  to be able to run Windows on ARM64. This option, which is disabled by
+  default, results in the following memory mappings:
+
+::
+
+    0x00000000 +-----------------+
+               |       ROM       | BL1
+    0x00010000 +-----------------+
+               |       DTB       | (Loaded by the VideoCore)
+    0x00020000 +-----------------+
+               |       FIP       |
+    0x00030000 +-----------------+
+               |                 |
+               |  UEFI PAYLOAD   |
+               |                 |
+    0x00200000 +-----------------+
+               |   Secure SRAM   | BL2, BL31
+    0x00300000 +-----------------+
+               |   Secure DRAM   | BL32 (Secure payload)
+    0x00400000 +-----------------+
+               |                 |
+               |                 |
+               | Non-secure DRAM | BL33
+               |                 |
+               |                 |
+    0x01000000 +-----------------+
+               |                 |
+               |       ...       |
+               |                 |
+    0x3F000000 +-----------------+
+               |       I/O       |
+
+- ``BL32``: This port can load and run OP-TEE. The OP-TEE image is optional.
+  Please use the code from `here <https://github.com/OP-TEE/optee_os>`__.
+  Build the Trusted Firmware with option ``BL32=tee-header_v2.bin
+  BL32_EXTRA1=tee-pager_v2.bin  BL32_EXTRA2=tee-pageable_v2.bin``
+  to put the binaries into the FIP.
+
+  .. warning::
+     If OP-TEE is used it may be needed to add the following options to the
+     Linux command line so that the USB driver doesn't use FIQs:
+     ``dwc_otg.fiq_enable=0 dwc_otg.fiq_fsm_enable=0 dwc_otg.nak_holdoff=0``.
+     This will unfortunately reduce the performance of the USB driver. It is
+     needed when using Raspbian, for example.
+
+- ``TRUSTED_BOARD_BOOT``: This port supports TBB. Set this option to 1 to enable
+  it. In order to use TBB, you might want to set ``GENERATE_COT=1`` to let the
+  contents of the FIP automatically signed by the build process. The ROT key
+  will be generated and output to ``rot_key.pem`` in the build directory. It is
+  able to set ROT_KEY to your own key in PEM format.  Also in order to build,
+  you need to clone mbed TLS from `here <https://github.com/ARMmbed/mbedtls>`__.
+  ``MBEDTLS_DIR`` must point at the mbed TLS source directory.
+
+- ``ENABLE_STACK_PROTECTOR``: Disabled by default. It uses the hardware RNG of
+  the board.
+
+The following is not currently supported:
+
+- AArch32 for TF-A itself.
+
+- ``EL3_PAYLOAD_BASE``: The reason is that you can already load anything to any
+  address by changing the file ``armstub8.bin``, so there's no point in using
+  TF-A in this case.
+
+- ``MULTI_CONSOLE_API=0``: The multi console API must be enabled. Note that the
+  crash console uses the internal 16550 driver functions directly in order to be
+  able to print error messages during early crashes before setting up the
+  multi console API.
+
+Building the firmware for kernels that don't support PSCI
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is the case for the 32-bit image of Raspbian, for example. 64-bit kernels
+always support PSCI, but they may not know that the system understands PSCI due
+to an incorrect DTB file.
+
+First, clone and compile the 32-bit version of the `Raspberry Pi 3 TF-A
+bootstrap`_. Choose the one needed for the architecture of your kernel.
+
+Then compile TF-A. For a 32-bit kernel, use the following command line:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3             \
+    RPI3_BL33_IN_AARCH32=1                                      \
+    BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin
+
+For a 64-bit kernel, use this other command line:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3             \
+    BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin
+
+However, enabling PSCI support in a 64-bit kernel is really easy. In the
+repository `Raspberry Pi 3 TF-A bootstrap`_ there is a patch that can be applied
+to the Linux kernel tree maintained by the Raspberry Pi foundation. It modifes
+the DTS to tell the kernel to use PSCI. Once this patch is applied, follow the
+instructions in `AArch64 kernel build instructions`_ to get a working 64-bit
+kernel image and supporting files.
+
+Building the firmware for kernels that support PSCI
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For a 64-bit kernel:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3             \
+    PRELOADED_BL33_BASE=0x02000000                              \
+    RPI3_PRELOADED_DTB_BASE=0x01000000                          \
+    RPI3_DIRECT_LINUX_BOOT=1
+
+For a 32-bit kernel:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3             \
+    PRELOADED_BL33_BASE=0x02000000                              \
+    RPI3_PRELOADED_DTB_BASE=0x01000000                          \
+    RPI3_DIRECT_LINUX_BOOT=1                                    \
+    RPI3_BL33_IN_AARCH32=1
+
+AArch64 kernel build instructions
+---------------------------------
+
+The following instructions show how to install and run a AArch64 kernel by
+using a SD card with the default `Raspbian`_ install as base. Skip them if you
+want to use the default 32-bit kernel.
+
+Note that this system won't be fully 64-bit because all the tools in the
+filesystem are 32-bit binaries, but it's a quick way to get it working, and it
+allows the user to run 64-bit binaries in addition to 32-bit binaries.
+
+1. Clone the `Linux tree fork`_ maintained by the Raspberry Pi Foundation. To
+   speed things up, do a shallow clone of the desired branch.
+
+.. code:: shell
+
+    git clone --depth=1 -b rpi-4.18.y https://github.com/raspberrypi/linux
+    cd linux
+
+2. Configure and compile the kernel. Adapt the number after ``-j`` so that it is
+   1.5 times the number of CPUs in your computer. This may take some time to
+   finish.
+
+.. code:: shell
+
+    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcmrpi3_defconfig
+    make -j 6 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
+
+3. Copy the kernel image and the device tree to the SD card. Replace the path
+   by the corresponding path in your computers to the ``boot`` partition of the
+   SD card.
+
+.. code:: shell
+
+    cp arch/arm64/boot/Image /path/to/boot/kernel8.img
+    cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb /path/to/boot/
+    cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dtb /path/to/boot/
+
+4. Install the kernel modules. Replace the path by the corresponding path to the
+   filesystem partition of the SD card on your computer.
+
+.. code:: shell
+
+    make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
+    INSTALL_MOD_PATH=/path/to/filesystem modules_install
+
+5. Follow the instructions in `Setup SD card`_ except for the step of renaming
+   the existing ``kernel7.img`` (we have already copied a AArch64 kernel).
+
+Setup SD card
+-------------
+
+The instructions assume that you have an SD card with a fresh install of
+`Raspbian`_ (or that, at least, the ``boot`` partition is untouched, or nearly
+untouched). They have been tested with the image available in 2018-03-13.
+
+1. Insert the SD card and open the ``boot`` partition.
+
+2. Rename ``kernel7.img`` to ``kernel8.img``. This tricks the VideoCore
+   bootloader into booting the Arm cores in AArch64 mode, like TF-A needs,
+   even though the kernel is not compiled for AArch64.
+
+3. Copy ``armstub8.bin`` here. When ``kernel8.img`` is available, The VideoCore
+   bootloader will look for a file called ``armstub8.bin`` and load it at
+   address **0x0** instead of a predefined one.
+
+4. To enable the serial port "Mini UART" in Linux, open ``cmdline.txt`` and add
+   ``console=serial0,115200 console=tty1``.
+
+5. Open ``config.txt`` and add the following lines at the end (``enable_uart=1``
+   is only needed to enable debugging through the Mini UART):
+
+::
+
+    enable_uart=1
+    kernel_address=0x02000000
+    device_tree_address=0x01000000
+
+If you connect a serial cable to the Mini UART and your computer, and connect
+to it (for example, with ``screen /dev/ttyUSB0 115200``) you should see some
+text. In the case of an AArch32 kernel, you should see something like this:
+
+::
+
+    NOTICE:  Booting Trusted Firmware
+    NOTICE:  BL1: v1.4(release):v1.4-329-g61e94684-dirty
+    NOTICE:  BL1: Built : 00:09:25, Nov  6 2017
+    NOTICE:  BL1: Booting BL2
+    NOTICE:  BL2: v1.4(release):v1.4-329-g61e94684-dirty
+    NOTICE:  BL2: Built : 00:09:25, Nov  6 2017
+    NOTICE:  BL1: Booting BL31
+    NOTICE:  BL31: v1.4(release):v1.4-329-g61e94684-dirty
+    NOTICE:  BL31: Built : 00:09:25, Nov  6 2017
+    [    0.266484] bcm2835-aux-uart 3f215040.serial: could not get clk: -517
+
+    Raspbian GNU/Linux 9 raspberrypi ttyS0
+    raspberrypi login:
+
+Just enter your credentials, everything should work as expected. Note that the
+HDMI output won't show any text during boot.
+
+.. _default Arm stub: https://github.com/raspberrypi/tools/blob/master/armstubs/armstub7.S
+.. _default AArch64 stub: https://github.com/raspberrypi/tools/blob/master/armstubs/armstub8.S
+.. _Linux kernel tree: https://github.com/torvalds/linux
+.. _Linux tree fork: https://github.com/raspberrypi/linux
+.. _Raspberry Pi 3: https://www.raspberrypi.org/products/raspberry-pi-3-model-b/
+.. _Raspberry Pi 3 TF-A bootstrap: https://github.com/AntonioND/rpi3-arm-tf-bootstrap
+.. _Raspberry Pi 3 documentation: https://www.raspberrypi.org/documentation/
+.. _Raspbian: https://www.raspberrypi.org/downloads/raspbian/
diff --git a/docs/plat/socionext-uniphier.rst b/docs/plat/socionext-uniphier.rst
new file mode 100644
index 0000000..82b9b50
--- /dev/null
+++ b/docs/plat/socionext-uniphier.rst
@@ -0,0 +1,117 @@
+Socionext UniPhier
+==================
+
+Socionext UniPhier Armv8-A SoCs use Trusted Firmware-A (TF-A) as the secure
+world firmware, supporting BL2 and BL31.
+
+UniPhier SoC family implements its internal boot ROM, which loads 64KB [1]_
+image from a non-volatile storage to the on-chip SRAM, and jumps over to it.
+TF-A provides a special mode, BL2-AT-EL3, which enables BL2 to execute at EL3.
+It is useful for platforms with non-TF-A boot ROM, like UniPhier. Here, a
+problem is BL2 does not fit in the 64KB limit if `Trusted Board Boot`_ (TBB)
+is enabled. To solve this issue, Socionext provides a first stage loader
+called `UniPhier BL`_. This loader runs in the on-chip SRAM, initializes the
+DRAM, expands BL2 there, and hands the control over to it. Therefore, all images
+of TF-A run in DRAM.
+
+The UniPhier platform works with/without TBB. See below for the build process
+of each case. The image authentication for the UniPhier platform fully
+complies with the Trusted Board Boot Requirements (TBBR) specification.
+
+The UniPhier BL does not implement the authentication functionality, that is,
+it can not verify the BL2 image by itself. Instead, the UniPhier BL assures
+the BL2 validity in a different way; BL2 is GZIP-compressed and appended to
+the UniPhier BL. The concatenation of the UniPhier BL and the compressed BL2
+fits in the 64KB limit. The concatenated image is loaded by the internal boot
+ROM (and verified if the chip fuses are blown).
+
+
+Boot Flow
+---------
+
+1. The Boot ROM
+
+   This is hard-wired ROM, so never corrupted. It loads the UniPhier BL (with
+   compressed-BL2 appended) into the on-chip SRAM. If the SoC fuses are blown,
+   the image is verified by the SoC's own method.
+
+2. UniPhier BL
+
+   This runs in the on-chip SRAM. After the minimum SoC initialization and DRAM
+   setup, it decompresses the appended BL2 image into the DRAM, then jumps to
+   the BL2 entry.
+
+3. BL2 (at EL3)
+
+   This runs in the DRAM. It extracts more images such as BL31, BL33 (optionally
+   SCP_BL2, BL32 as well) from Firmware Image Package (FIP). If TBB is enabled,
+   they are all authenticated by the standard mechanism of TF-A.
+   After loading all the images, it jumps to the BL31 entry.
+
+4. BL31, BL32, and BL33
+
+   They all run in the DRAM. See `Firmware Design`_ for details.
+
+
+Basic Build
+-----------
+
+BL2 must be compressed for the reason above. The UniPhier's platform makefile
+provides a build target ``bl2_gzip`` for this.
+
+For a non-secure boot loader (aka BL33), U-Boot is well supported for UniPhier
+SoCs. The U-Boot image (``u-boot.bin``) must be built in advance. For the build
+procedure of U-Boot, refer to the document in the `U-Boot`_ project.
+
+To build minimum functionality for UniPhier (without TBB)::
+
+    make CROSS_COMPILE=<gcc-prefix> PLAT=uniphier BL33=<path-to-BL33> bl2_gzip fip
+
+Output images:
+
+- ``bl2.bin.gz``
+- ``fip.bin``
+
+
+Optional features
+-----------------
+
+- Trusted Board Boot
+
+  `mbed TLS`_ is needed as the cryptographic and image parser modules.
+  Refer to the `User Guide`_ for the appropriate version of mbed TLS.
+
+  To enable TBB, add the following options to the build command::
+
+      TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR=<path-to-mbedtls>
+
+- System Control Processor (SCP)
+
+  If desired, FIP can include an SCP BL2 image. If BL2 finds an SCP BL2 image
+  in FIP, BL2 loads it into DRAM and kicks the SCP. Most of UniPhier boards
+  still work without SCP, but SCP provides better power management support.
+
+  To include SCP BL2, add the following option to the build command::
+
+      SCP_BL2=<path-to-SCP>
+
+- BL32 (Secure Payload)
+
+  To enable BL32, add the following options to the build command::
+
+      SPD=<spd> BL32=<path-to-BL32>
+
+  If you use TSP for BL32, ``BL32=<path-to-BL32>`` is not required. Just add the
+  following::
+
+      SPD=tspd
+
+
+.. [1] Some SoCs can load 80KB, but the software implementation must be aligned
+   to the lowest common denominator.
+.. _Trusted Board Boot: ../trusted-board-boot.rst
+.. _UniPhier BL: https://github.com/uniphier/uniphier-bl
+.. _Firmware Design: ../firmware-design.rst
+.. _U-Boot: https://www.denx.de/wiki/U-Boot
+.. _mbed TLS: https://tls.mbed.org/
+.. _User Guide: ../user-guide.rst
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
new file mode 100644
index 0000000..88251d6
--- /dev/null
+++ b/docs/plat/stm32mp1.rst
@@ -0,0 +1,112 @@
+STMicroelectronics STM32MP1
+===========================
+
+STM32MP1 is a microprocessor designed by STMicroelectronics
+based on a dual Arm Cortex-A7.
+It is an Armv7-A platform, using dedicated code from TF-A.
+The STM32MP1 chip also embeds a Cortex-M4.
+More information can be found on `STM32MP1 Series`_ page.
+
+
+Design
+------
+The STM32MP1 resets in the ROM code of the Cortex-A7.
+The primary boot core (core 0) executes the boot sequence while
+secondary boot core (core 1) is kept in a holding pen loop.
+The ROM code boot sequence loads the TF-A binary image from boot device
+to embedded SRAM.
+
+The TF-A image must be properly formatted with a STM32 header structure
+for ROM code is able to load this image.
+Tool stm32image can be used to prepend this header to the generated TF-A binary.
+
+At compilation step, BL2, BL32 and DTB file are linked together in a single
+binary. The stm32image tool is also generated and the header is added to TF-A
+binary. This binary file with header is named tf-a-stm32mp157c-ev1.stm32.
+It can then be copied in the first partition of the boot device.
+
+
+Memory mapping
+~~~~~~~~~~~~~~
+
+::
+
+    0x00000000 +-----------------+
+               |                 |   ROM
+    0x00020000 +-----------------+
+               |                 |
+               |       ...       |
+               |                 |
+    0x2FFC0000 +-----------------+ \
+               |                 | |
+               |       ...       | |
+               |                 | |
+    0x2FFD8000 +-----------------+ |
+               |    TF-A DTB     | | Embedded SRAM
+    0x2FFDC000 +-----------------+ |
+               |       BL2       | |
+    0x2FFEF000 +-----------------+ |
+               |       BL32      | |
+    0x30000000 +-----------------+ /
+               |                 |
+               |       ...       |
+               |                 |
+    0x40000000 +-----------------+
+               |                 |
+               |                 |   Devices
+               |                 |
+    0xC0000000 +-----------------+ \
+               |                 | |
+    0xC0100000 +-----------------+ |
+               |       BL33      | | Non-secure RAM (DDR)
+               |       ...       | |
+               |                 | |
+    0xFFFFFFFF +-----------------+ /
+
+
+Boot sequence
+~~~~~~~~~~~~~
+
+ROM code -> BL2 (compiled with BL2_AT_EL3) -> BL32 (SP_min) -> BL33 (U-Boot)
+
+or if Op-TEE is used:
+
+ROM code -> BL2 (compiled with BL2_AT_EL3) -> OP-TEE -> BL33 (U-Boot)
+
+
+Build Instructions
+------------------
+
+To build with SP_min:
+
+.. code:: bash
+
+    make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min DTB_FILE_NAME=stm32mp157c-ev1.dtb
+    cd <u-boot_directory>
+    make stm32mp15_trusted_defconfig
+    make DEVICE_TREE=stm32mp157c-ev1 all
+
+To build TF-A with with Op-TEE support:
+
+.. code:: bash
+
+    make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee
+
+The following build options are supported:
+
+- ``ENABLE_STACK_PROTECTOR``: To enable the stack protection.
+
+
+Populate SD-card
+----------------
+
+The SD-card has to be formated with GPT.
+It should contain at least those partitions:
+
+- fsbl: to copy the tf-a-stm32mp157c-ev1.stm32 binary
+- ssbl: to copy the u-boot.stm32 binary
+
+Usually, two copies of fsbl are used (fsbl1 and fsbl2) instead of one partition fsbl.
+
+
+.. _STM32MP1 Series: https://www.st.com/en/microcontrollers-microprocessors/stm32mp1-series.html
diff --git a/docs/plat/synquacer.rst b/docs/plat/synquacer.rst
new file mode 100644
index 0000000..dd29d29
--- /dev/null
+++ b/docs/plat/synquacer.rst
@@ -0,0 +1,117 @@
+Socionext Synquacer
+===================
+
+Socionext's Synquacer SC2A11 is a multi-core processor with 24 cores of Arm
+Cortex-A53. The Developerbox, of 96boards, is a platform that contains this
+processor. This port of the Trusted Firmware only supports this platform at
+the moment.
+
+More information are listed in `link`_.
+
+How to build
+------------
+
+Code Locations
+~~~~~~~~~~~~~~
+
+-  Trusted Firmware-A:
+   `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+-  edk2:
+   `link <https://github.com/tianocore/edk2>`__
+
+-  edk2-platforms:
+   `link <https://github.com/tianocore/edk2-platforms>`__
+
+-  edk2-non-osi:
+   `link <https://github.com/tianocore/edk2-non-osi>`__
+
+Boot Flow
+~~~~~~~~~
+
+SCP firmware --> TF-A BL31 --> UEFI(edk2)
+
+Build Procedure
+~~~~~~~~~~~~~~~
+
+-  Firstly, in addition to the “normal” build tools you will also need a
+   few specialist tools. On a Debian or Ubuntu operating system try:
+
+   .. code:: shell
+
+       sudo apt install acpica-tools device-tree-compiler uuid-dev
+
+-  Secondly, create a new working directory and store the absolute path to this
+   directory in an environment variable, WORKSPACE. It does not matter where
+   this directory is created but as an example:
+
+   .. code:: shell
+
+       export WORKSPACE=$HOME/build/developerbox-firmware
+       mkdir -p $WORKSPACE
+
+-  Run the following commands to clone the source code:
+
+   .. code:: shell
+
+       cd $WORKSPACE
+       git clone https://github.com/ARM-software/arm-trusted-firmware -b master
+       git clone https://github.com/tianocore/edk2.git -b master
+       git clone https://github.com/tianocore/edk2-platforms.git -b master
+       git clone https://github.com/tianocore/edk2-non-osi.git -b master
+
+-  Build ATF:
+
+   .. code:: shell
+
+       cd $WORKSPACE/arm-trusted-firmware
+       make -j`nproc` PLAT=synquacer PRELOADED_BL33_BASE=0x8200000 bl31 fiptool
+       tools/fiptool/fiptool create \
+             --tb-fw ./build/synquacer/release/bl31.bin \
+             --soc-fw ./build/synquacer/release/bl31.bin \
+             --scp-fw ./build/synquacer/release/bl31.bin \
+             ../edk2-non-osi/Platform/Socionext/DeveloperBox/fip_all_arm_tf.bin
+
+-  Build EDK2:
+
+   .. code:: shell
+
+       cd $WORKSPACE
+       export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms:$WORKSPACE/edk2-non-osi
+       export ACTIVE_PLATFORM="Platform/Socionext/DeveloperBox/DeveloperBox.dsc"
+       export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-
+       unset ARCH
+
+       . edk2/edksetup.sh
+       make -C edk2/BaseTools
+
+       build -p $ACTIVE_PLATFORM -b RELEASE -a AARCH64 -t GCC5 -n `nproc` -D DO_X86EMU=TRUE
+
+-  The firmware image, which comprises the option ROM, ARM trusted firmware and
+   EDK2 itself, can be found $WORKSPACE/../Build/DeveloperBox/RELEASE_GCC5/FV/.
+   Use SYNQUACERFIRMWAREUPDATECAPSULEFMPPKCS7.Cap for UEFI capsule update and
+   SPI_NOR_IMAGE.fd for the serial flasher.
+
+   Note #1: -t GCC5 can be loosely translated as “enable link-time-optimization”;
+   any version of gcc >= 5 will support this feature and may be used to build EDK2.
+
+   Note #2: Replace -b RELEASE with -b DEBUG to build a debug.
+
+Install the System Firmware
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+-  Providing your Developerbox is fully working and has on operating system
+   installed then you can adopt your the newly compiled system firmware using
+   the capsule update method:.
+
+   .. code:: shell
+
+       sudo apt install fwupdate
+       sudo fwupdate --apply {50b94ce5-8b63-4849-8af4-ea479356f0e3} \
+                     SYNQUACERFIRMWAREUPDATECAPSULEFMPPKCS7.Cap
+       sudo reboot
+
+-  Alternatively you can install SPI_NOR_IMAGE.fd using the `board recovery method`_.
+
+.. _link: https://www.96boards.org/product/developerbox/
+.. _board recovery method: https://www.96boards.org/documentation/enterprise/developerbox/installation/board-recovery.md.html
diff --git a/docs/plat/ti-k3.rst b/docs/plat/ti-k3.rst
new file mode 100644
index 0000000..4843227
--- /dev/null
+++ b/docs/plat/ti-k3.rst
@@ -0,0 +1,57 @@
+Texas Instruments K3
+====================
+
+Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Texas Instruments K3 SoCs.
+
+Boot Flow
+---------
+
+::
+
+   R5(U-Boot) --> TF-A BL31 --> BL32(OP-TEE) --> TF-A BL31 --> BL33(U-Boot) --> Linux
+                                                       \
+                                                   Optional direct to Linux boot
+                                                           \
+                                                           --> BL33(Linux)
+
+Texas Instruments K3 SoCs contain an R5 processor used as the boot master, it
+loads the needed images for A53 startup, because of this we do not need BL1 or
+BL2 TF-A stages.
+
+Build Instructions
+------------------
+
+https://github.com/ARM-software/arm-trusted-firmware.git
+
+TF-A:
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=k3 SPD=opteed all
+
+OP-TEE:
+
+.. code:: shell
+
+    make ARCH=arm CROSS_COMPILE64=aarch64-linux-gnu- PLATFORM=k3 CFG_ARM64_core=y all
+
+R5 U-Boot:
+
+.. code:: shell
+
+    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- am65x_evm_r5_defconfig
+    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- SYSFW=<path to SYSFW>
+
+A53 U-Boot:
+
+.. code:: shell
+
+    make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- am65x_evm_a53_defconfig
+    make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- ATF=<path> TEE=<path>
+
+Deploy Images
+-------------
+
+.. code:: shell
+
+    cp tiboot3.bin tispl.bin u-boot.img /sdcard/boot/
diff --git a/docs/plat/warp7.rst b/docs/plat/warp7.rst
new file mode 100644
index 0000000..f98a76f
--- /dev/null
+++ b/docs/plat/warp7.rst
@@ -0,0 +1,210 @@
+NXP i.MX7 WaRP7
+===============
+
+The Trusted Firmware-A port for the i.MX7Solo WaRP7 implements BL2 at EL3.
+The i.MX7S contains a BootROM with a High Assurance Boot (HAB) functionality.
+This functionality provides a mechanism for establishing a root-of-trust from
+the reset vector to the command-line in user-space.
+
+Boot Flow
+---------
+
+BootROM --> TF-A BL2 --> BL32(OP-TEE) --> BL33(U-Boot) --> Linux
+
+In the WaRP7 port we encapsulate OP-TEE, DTB and U-Boot into a FIP. This FIP is
+expected and required
+
+Build Instructions
+------------------
+
+We need to use a file generated by u-boot in order to generate a .imx image the
+BootROM will boot. It is therefore _required_ to build u-boot before TF-A and
+furthermore it is _recommended_ to use the mkimage in the u-boot/tools directory
+to generate the TF-A .imx image.
+
+U-Boot
+~~~~~~
+
+https://git.linaro.org/landing-teams/working/mbl/u-boot.git
+
+.. code:: shell
+
+    git checkout -b rms-atf-optee-uboot linaro-mbl/rms-atf-optee-uboot
+    make warp7_bl33_defconfig;
+    make u-boot.imx arch=ARM CROSS_COMPILE=arm-linux-gnueabihf-
+
+OP-TEE
+~~~~~~
+
+https://github.com/OP-TEE/optee_os.git
+
+.. code:: shell
+
+    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- PLATFORM=imx PLATFORM_FLAVOR=mx7swarp7 ARCH=arm CFG_PAGEABLE_ADDR=0 CFG_DT_ADDR=0x83000000 CFG_NS_ENTRY_ADDR=0x87800000
+
+TF-A
+~~~~
+
+https://github.com/ARM-software/arm-trusted-firmware.git
+
+The following commands assume that a directory exits in the top-level TFA build
+directory "fiptool_images". "fiptool_images" contains
+
+- u-boot.bin
+  The binary output from the u-boot instructions above
+
+- tee-header_v2.bin
+- tee-pager_v2.bin
+- tee-pageable_v2.bin
+  Binary outputs from the previous OPTEE build steps
+
+It is also assumed copy of mbedtls is available on the path path ../mbedtls
+  https://github.com/ARMmbed/mbedtls.git
+  At the time of writing HEAD points to 0592ea772aee48ca1e6d9eb84eca8e143033d973
+
+.. code:: shell
+
+    mkdir fiptool_images
+    cp /path/to/optee/out/arm-plat-imx/core/tee-header_v2.bin fiptool_images
+    cp /path/to/optee/out/arm-plat-imx/core/tee-pager_v2.bin fiptool_images
+    cp /path/to/optee/out/arm-plat-imx/core/tee-pageable_v2.bin fiptool_images
+
+    make CROSS_COMPILE=${CROSS_COMPILE} PLAT=warp7 ARCH=aarch32 ARM_ARCH_MAJOR=7 \
+         ARM_CORTEX_A7=yes AARCH32_SP=optee PLAT_WARP7_UART=1 GENERATE_COT=1 \
+         TRUSTED_BOARD_BOOT=1 USE_TBBR_DEFS=1 MBEDTLS_DIR=../mbedtls \
+         NEED_BL32=yes BL32=fiptool_images/tee-header_v2.bin \
+         BL32_EXTRA1=fiptool_images/tee-pager_v2.bin \
+         BL32_EXTRA2=fiptool_images/tee-pageable_v2.bin \
+         BL33=fiptool_images/u-boot.bin certificates all
+
+    /path/to/u-boot/tools/mkimage -n /path/to/u-boot/u-boot.cfgout -T imximage -e 0x9df00000 -d ./build/warp7/debug/bl2.bin ./build/warp7/debug/bl2.bin.imx
+
+FIP
+~~~
+
+.. code:: shell
+
+    cp /path/to/uboot/u-boot.bin fiptool_images
+    cp /path/to/linux/arch/boot/dts/imx7s-warp.dtb fiptool_images
+
+    tools/cert_create/cert_create -n --rot-key "build/warp7/debug/rot_key.pem" \
+               --tfw-nvctr 0 \
+               --ntfw-nvctr 0 \
+               --trusted-key-cert fiptool_images/trusted-key-cert.key-crt \
+               --tb-fw=build/warp7/debug/bl2.bin \
+               --tb-fw-cert fiptool_images/trusted-boot-fw.key-crt\
+               --tos-fw fiptool_images/tee-header_v2.bin \
+               --tos-fw-cert fiptool_images/tee-header_v2.bin.crt \
+               --tos-fw-key-cert fiptool_images/tee-header_v2.bin.key-crt \
+               --tos-fw-extra1 fiptool_images/tee-pager_v2.bin \
+               --tos-fw-extra2 fiptool_images/tee-pageable_v2.bin \
+               --nt-fw fiptool_images/u-boot.bin \
+               --nt-fw-cert fiptool_images/u-boot.bin.crt \
+               --nt-fw-key-cert fiptool_images/u-boot.bin.key-crt \
+               --hw-config fiptool_images/imx7s-warp.dtb
+
+    tools/fiptool/fiptool create --tos-fw fiptool_images/tee-header_v2.bin \
+              --tos-fw-extra1 fiptool_images/tee-pager_v2.bin \
+              --tos-fw-extra2 fiptool_images/tee-pageable_v2.bin \
+              --nt-fw fiptool_images/u-boot.bin \
+              --hw-config fiptool_images/imx7s-warp.dtb \
+              --tos-fw-cert fiptool_images/tee-header_v2.bin.crt \
+              --tos-fw-key-cert fiptool_images/tee-header_v2.bin.key-crt \
+              --nt-fw-cert fiptool_images/u-boot.bin.crt \
+              --nt-fw-key-cert fiptool_images/u-boot.bin.key-crt \
+              --trusted-key-cert fiptool_images/trusted-key-cert.key-crt \
+              --tb-fw-cert fiptool_images/trusted-boot-fw.key-crt warp7.fip
+
+Deploy Images
+-------------
+
+First place the WaRP7 into UMS mode in u-boot this should produce an entry in
+/dev like /dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0
+
+.. code:: shell
+
+    => ums 0 mmc 0
+
+Next flash bl2.imx and warp7.fip
+
+bl2.imx is flashed @ 1024 bytes
+warp7.fip is flash @ 1048576 bytes
+
+.. code:: shell
+
+    sudo dd if=bl2.bin.imx of=/dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0 bs=512 seek=2 conv=notrunc
+    # Offset is 1MB 1048576 => 1048576 / 512 = 2048
+    sudo dd if=./warp7.fip of=/dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0 bs=512 seek=2048 conv=notrunc
+
+Remember to umount the USB device pefore proceeding
+
+.. code:: shell
+
+    sudo umount /dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0*
+
+
+Signing BL2
+-----------
+
+A further step is to sign BL2.
+
+The image_sign.sh and bl2_sign.csf files alluded to blow are available here.
+
+https://github.com/bryanodonoghue/atf-code-signing
+
+It is suggested you use this script plus the example CSF file in order to avoid
+hard-coding data into your CSF files.
+
+Download both "image_sign.sh" and "bl2_sign.csf" to your
+arm-trusted-firmware top-level directory.
+
+.. code:: shell
+
+    #!/bin/bash
+    SIGN=image_sign.sh
+    TEMP=`pwd`/temp
+    BL2_CSF=bl2_sign.csf
+    BL2_IMX=bl2.bin.imx
+    CST_PATH=/path/to/cst-2.3.2
+    CST_BIN=${CST_PATH}/linux64/cst
+
+    #Remove temp
+    rm -rf ${TEMP}
+    mkdir ${TEMP}
+
+    # Generate IMX header
+    /path/to/u-boot/tools/mkimage -n u-boot.cfgout.warp7 -T imximage -e 0x9df00000 -d ./build/warp7/debug/bl2.bin ./build/warp7/debug/bl2.bin.imx > ${TEMP}/${BL2_IMX}.log
+
+    # Copy required items to $TEMP
+    cp build/warp7/debug/bl2.bin.imx ${TEMP}
+    cp ${CST_PATH}/keys/* ${TEMP}
+    cp ${CST_PATH}/crts/* ${TEMP}
+    cp ${BL2_CSF} ${TEMP}
+
+    # Generate signed BL2 image
+    ./${SIGN} image_sign_mbl_binary ${TEMP} ${BL2_CSF} ${BL2_IMX} ${CST_BIN}
+
+    # Copy signed BL2 to top-level directory
+    cp ${TEMP}/${BL2_IMX}-signed .
+    cp ${BL2_RECOVER_CSF} ${TEMP}
+
+
+The resulting bl2.bin.imx-signed can replace bl2.bin.imx in the Deploy
+Images section above, once done.
+
+Suggested flow for verifying.
+
+1. Followed all previous steps above and verify a non-secure ATF boot
+2. Down the NXP Code Singing Tool
+3. Generate keys
+4. Program the fuses on your board
+5. Replace bl2.bin.imx with bl2.bin.imx-signed
+6. Verify inside u-boot that "hab_status" shows no events
+7. Subsequently close your board.
+
+If you have HAB events @ step 6 - do not lock your board.
+
+To get a good over-view of generating keys and programming the fuses on the
+board read "High Assurance Boot for Dummies" by Boundary Devices.
+
+https://boundarydevices.com/high-assurance-boot-hab-dummies/
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
new file mode 100644
index 0000000..231286e
--- /dev/null
+++ b/docs/plat/xilinx-versal.rst
@@ -0,0 +1,35 @@
+Xilinx Versal
+=============
+
+Trusted Firmware-A implements the EL3 firmware layer for Xilinx Versal.
+The platform only uses the runtime part of TF-A as Xilinx Versal already has a
+BootROM (BL1) and PMC FW (BL2).
+
+BL31 is TF-A.
+BL32 is an optional Secure Payload.
+BL33 is the non-secure world software (U-Boot, Linux etc).
+
+To build:
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31
+```
+
+To build ATF for different platform (for now its just versal virtual "versal_virt")
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31
+```
+
+Xilinx Versal platform specific build options
+---------------------------------------------
+
+*   `VERSAL_ATF_MEM_BASE`: Specifies the base address of the bl31 binary.
+*   `VERSAL_ATF_MEM_SIZE`: Specifies the size of the memory region of the bl31 binary.
+*   `VERSAL_BL32_MEM_BASE`: Specifies the base address of the bl32 binary.
+*   `VERSAL_BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary.
+
+*   `VERSAL_CONSOLE`: Select the console driver. Options:
+    -   `pl011`, `pl011_0`: ARM pl011 UART 0
+    -   `pl011_1`         : ARM pl011 UART 1
+
+*   `VERSAL_PLATFORM`: Select the platform. Options:
+    -   `versal_virt`	: Versal Virtual platform
diff --git a/docs/plat/xilinx-zynqmp.rst b/docs/plat/xilinx-zynqmp.rst
new file mode 100644
index 0000000..5db4488
--- /dev/null
+++ b/docs/plat/xilinx-zynqmp.rst
@@ -0,0 +1,67 @@
+Xilinx Zynq UltraScale+ MPSoC
+=============================
+
+Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Xilinx Zynq
+UltraScale + MPSoC.
+The platform only uses the runtime part of TF-A as ZynqMP already has a
+BootROM (BL1) and FSBL (BL2).
+
+BL31 is TF-A.
+BL32 is an optional Secure Payload.
+BL33 is the non-secure world software (U-Boot, Linux etc).
+
+To build:
+
+.. code:: bash
+
+    make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31
+
+To build bl32 TSP you have to rebuild bl31 too:
+
+.. code:: bash
+
+    make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32
+
+ZynqMP platform specific build options
+--------------------------------------
+
+-  ``ZYNQMP_ATF_MEM_BASE``: Specifies the base address of the bl31 binary.
+-  ``ZYNQMP_ATF_MEM_SIZE``: Specifies the size of the memory region of the bl31 binary.
+-  ``ZYNQMP_BL32_MEM_BASE``: Specifies the base address of the bl32 binary.
+-  ``ZYNQMP_BL32_MEM_SIZE``: Specifies the size of the memory region of the bl32 binary.
+
+-  ``ZYNQMP_CONSOLE``: Select the console driver. Options:
+
+   -  ``cadence``, ``cadence0``: Cadence UART 0
+   -  ``cadence1`` : Cadence UART 1
+
+FSBL->TF-A Parameter Passing
+----------------------------
+
+The FSBL populates a data structure with image information for TF-A. TF-A uses
+that data to hand off to the loaded images. The address of the handoff data
+structure is passed in the ``PMU_GLOBAL.GLOBAL_GEN_STORAGE6`` register. The
+register is free to be used by other software once TF-A has brought up
+further firmware images.
+
+Power Domain Tree
+-----------------
+
+The following power domain tree represents the power domain model used by TF-A
+for ZynqMP:
+
+::
+
+                    +-+
+                    |0|
+                    +-+
+         +-------+---+---+-------+
+         |       |       |       |
+         |       |       |       |
+         v       v       v       v
+        +-+     +-+     +-+     +-+
+        |0|     |1|     |2|     |3|
+        +-+     +-+     +-+     +-+
+
+The 4 leaf power domains represent the individual A53 cores, while resources
+common to the cluster are grouped in the power domain on the top.
diff --git a/docs/process/coding-guidelines.rst b/docs/process/coding-guidelines.rst
new file mode 100644
index 0000000..a53da77
--- /dev/null
+++ b/docs/process/coding-guidelines.rst
@@ -0,0 +1,586 @@
+Coding Style & Guidelines
+=========================
+
+The following sections contain TF coding guidelines. They are continually
+evolving and should not be considered "set in stone". Feel free to question them
+and provide feedback.
+
+Some of the guidelines may also apply to other codebases.
+
+.. note::
+   The existing TF codebase does not necessarily comply with all the
+   below guidelines but the intent is for it to do so eventually.
+
+Checkpatch overrides
+--------------------
+
+Some checkpatch warnings in the TF codebase are deliberately ignored. These
+include:
+
+- ``**WARNING: line over 80 characters**``: Although the codebase should
+  generally conform to the 80 character limit this is overly restrictive in some
+  cases.
+
+- ``**WARNING: Use of volatile is usually wrong``: see
+  `Why the “volatile” type class should not be used`_ . Although this document
+  contains some very useful information, there are several legimate uses of the
+  volatile keyword within the TF codebase.
+
+Headers and inclusion
+---------------------
+
+Header guards
+^^^^^^^^^^^^^
+
+For a header file called "some_driver.h" the style used by the Trusted Firmware
+is:
+
+.. code:: c
+
+  #ifndef SOME_DRIVER_H
+  #define SOME_DRIVER_H
+
+  <header content>
+
+  #endif /* SOME_DRIVER_H */
+
+Include statement ordering
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+All header files that are included by a source file must use the following,
+grouped ordering. This is to improve readability (by making it easier to quickly
+read through the list of headers) and maintainability.
+
+#. *System* includes: Header files from the standard *C* library, such as
+   ``stddef.h`` and ``string.h``.
+
+#. *Project* includes: Header files under the ``include/`` directory within TF
+   are *project* includes.
+
+#. *Platform* includes: Header files relating to a single, specific platform,
+   and which are located under the ``plat/<platform_name>`` directory within TF,
+   are *platform* includes.
+
+Within each group, ``#include`` statements must be in alphabetical order,
+taking both the file and directory names into account.
+
+Groups must be separated by a single blank line for clarity.
+
+The example below illustrates the ordering rules using some contrived header
+file names; this type of name reuse should be otherwise avoided.
+
+.. code:: c
+
+  #include <string.h>
+
+  #include <a_dir/example/a_header.h>
+  #include <a_dir/example/b_header.h>
+  #include <a_dir/test/a_header.h>
+  #include <b_dir/example/a_header.h>
+
+  #include "./a_header.h"
+
+Include statement variants
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Two variants of the ``#include`` directive are acceptable in the TF codebase.
+Correct use of the two styles improves readability by suggesting the location
+of the included header and reducing ambiguity in cases where generic and
+platform-specific headers share a name.
+
+For header files that are in the same directory as the source file that is
+including them, use the ``"..."`` variant.
+
+For header files that are **not** in the same directory as the source file that
+is including them, use the ``<...>`` variant.
+
+Example (bl1_fwu.c):
+
+.. code:: c
+
+  #include <assert.h>
+  #include <errno.h>
+  #include <string.h>
+
+  #include "bl1_private.h"
+
+Platform include paths
+^^^^^^^^^^^^^^^^^^^^^^
+
+Platforms are allowed to add more include paths to be passed to the compiler.
+The ``PLAT_INCLUDES`` variable is used for this purpose. This is needed in
+particular for the file ``platform_def.h``.
+
+Example:
+
+.. code:: c
+
+  PLAT_INCLUDES  += -Iinclude/plat/myplat/include
+
+Types and typedefs
+------------------
+
+Use of built-in *C* and *libc* data types
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The TF codebase should be kept as portable as possible, especially since both
+64-bit and 32-bit platforms are supported. To help with this, the following data
+type usage guidelines should be followed:
+
+- Where possible, use the built-in *C* data types for variable storage (for
+  example, ``char``, ``int``, ``long long``, etc) instead of the standard *C99*
+  types. Most code is typically only concerned with the minimum size of the
+  data stored, which the built-in *C* types guarantee.
+
+- Avoid using the exact-size standard *C99* types in general (for example,
+  ``uint16_t``, ``uint32_t``, ``uint64_t``, etc) since they can prevent the
+  compiler from making optimizations. There are legitimate uses for them,
+  for example to represent data of a known structure. When using them in struct
+  definitions, consider how padding in the struct will work across architectures.
+  For example, extra padding may be introduced in AArch32 systems if a struct
+  member crosses a 32-bit boundary.
+
+- Use ``int`` as the default integer type - it's likely to be the fastest on all
+  systems. Also this can be assumed to be 32-bit as a consequence of the
+  `Procedure Call Standard for the Arm Architecture`_ and the `Procedure Call
+  Standard for the Arm 64-bit Architecture`_ .
+
+- Avoid use of ``short`` as this may end up being slower than ``int`` in some
+  systems. If a variable must be exactly 16-bit, use ``int16_t`` or
+  ``uint16_t``.
+
+- Avoid use of ``long``. This is guaranteed to be at least 32-bit but, given
+  that `int` is 32-bit on Arm platforms, there is no use for it. For integers of
+  at least 64-bit, use ``long long``.
+
+- Use ``char`` for storing text. Use ``uint8_t`` for storing other 8-bit data.
+
+- Use ``unsigned`` for integers that can never be negative (counts,
+  indices, sizes, etc). TF intends to comply with MISRA "essential type" coding
+  rules (10.X), where signed and unsigned types are considered different
+  essential types. Choosing the correct type will aid this. MISRA static
+  analysers will pick up any implicit signed/unsigned conversions that may lead
+  to unexpected behaviour.
+
+- For pointer types:
+
+  - If an argument in a function declaration is pointing to a known type then
+    simply use a pointer to that type (for example: ``struct my_struct *``).
+
+  - If a variable (including an argument in a function declaration) is pointing
+    to a general, memory-mapped address, an array of pointers or another
+    structure that is likely to require pointer arithmetic then use
+    ``uintptr_t``. This will reduce the amount of casting required in the code.
+    Avoid using ``unsigned long`` or ``unsigned long long`` for this purpose; it
+    may work but is less portable.
+
+  - For other pointer arguments in a function declaration, use ``void *``. This
+    includes pointers to types that are abstracted away from the known API and
+    pointers to arbitrary data. This allows the calling function to pass a
+    pointer argument to the function without any explicit casting (the cast to
+    ``void *`` is implicit). The function implementation can then do the
+    appropriate casting to a specific type.
+
+  - Use ``ptrdiff_t`` to compare the difference between 2 pointers.
+
+- Use ``size_t`` when storing the ``sizeof()`` something.
+
+- Use ``ssize_t`` when returning the ``sizeof()`` something from a function that
+  can also return an error code; the signed type allows for a negative return
+  code in case of error. This practice should be used sparingly.
+
+- Use ``u_register_t`` when it's important to store the contents of a register
+  in its native size (32-bit in AArch32 and 64-bit in AArch64). This is not a
+  standard *C99* type but is widely available in libc implementations,
+  including the FreeBSD version included with the TF codebase. Where possible,
+  cast the variable to a more appropriate type before interpreting the data. For
+  example, the following struct in ``ep_info.h`` could use this type to minimize
+  the storage required for the set of registers:
+
+.. code:: c
+
+    typedef struct aapcs64_params {
+            u_register_t arg0;
+            u_register_t arg1;
+            u_register_t arg2;
+            u_register_t arg3;
+            u_register_t arg4;
+            u_register_t arg5;
+            u_register_t arg6;
+            u_register_t arg7;
+    } aapcs64_params_t;
+
+If some code wants to operate on ``arg0`` and knows that it represents a 32-bit
+unsigned integer on all systems, cast it to ``unsigned int``.
+
+These guidelines should be updated if additional types are needed.
+
+Avoid anonymous typedefs of structs/enums in headers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For example, the following definition:
+
+.. code:: c
+
+  typedef struct {
+          int arg1;
+          int arg2;
+  } my_struct_t;
+
+
+is better written as:
+
+.. code:: c
+
+  struct my_struct {
+          int arg1;
+          int arg2;
+  };
+
+This allows function declarations in other header files that depend on the
+struct/enum to forward declare the struct/enum instead of including the
+entire header:
+
+.. code:: c
+
+  #include <my_struct.h>
+  void my_func(my_struct_t *arg);
+
+instead of:
+
+.. code:: c
+
+  struct my_struct;
+  void my_func(struct my_struct *arg);
+
+Some TF definitions use both a struct/enum name **and** a typedef name. This
+is discouraged for new definitions as it makes it difficult for TF to comply
+with MISRA rule 8.3, which states that "All declarations of an object or
+function shall use the same names and type qualifiers".
+
+The Linux coding standards also discourage new typedefs and checkpatch emits
+a warning for this.
+
+Existing typedefs will be retained for compatibility.
+
+Libc functions that are banned or to be used with caution
+---------------------------------------------------------
+
+Below is a list of functions that present security risks and either must not be
+used (Banned) or are discouraged from use and must be used with care (Caution).
+
++------------------------+-----------+--------------------------------------+
+|    libc function       | Status    | Comments                             |
++========================+===========+======================================+
+| ``strcpy, wcscpy``,    | Banned    | use strlcpy instead                  |
+| ``strncpy``            |           |                                      |
++------------------------+-----------+--------------------------------------+
+| ``strcat, wcscat``,    | Banned    | use strlcat instead                  |
+| ``strncat``            |           |                                      |
++------------------------+-----------+--------------------------------------+
+| ``sprintf, vsprintf``  | Banned    | use snprintf, vsnprintf              |
+|                        |           | instead                              |
++------------------------+-----------+--------------------------------------+
+| ``snprintf``           | Caution   | ensure result fits in buffer         |
+|                        |           | i.e : snprintf(buf,size...) < size   |
++------------------------+-----------+--------------------------------------+
+| ``vsnprintf``          | Caution   | inspect va_list match types          |
+|                        |           | specified in format string           |
++------------------------+-----------+--------------------------------------+
+| ``strtok``             | Banned    | use strtok_r or strsep instead       |
++------------------------+-----------+--------------------------------------+
+| ``strtok_r, strsep``   | Caution   | inspect for terminated input buffer  |
++------------------------+-----------+--------------------------------------+
+| ``ato*``               | Banned    | use equivalent strto* functions      |
++------------------------+-----------+--------------------------------------+
+| ``*toa``               | Banned    | Use snprintf instead                 |
++------------------------+-----------+--------------------------------------+
+
+The `libc` component in the codebase will not add support for the banned APIs.
+
+Error handling and robustness
+-----------------------------
+
+Using CASSERT to check for compile time data errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Where possible, use the ``CASSERT`` macro to check the validity of data known at
+compile time instead of checking validity at runtime, to avoid unnecessary
+runtime code.
+
+For example, this can be used to check that the assembler's and compiler's views
+of the size of an array is the same.
+
+.. code:: c
+
+  #include <cassert.h>
+
+  define MY_STRUCT_SIZE 8 /* Used by assembler source files */
+
+  struct my_struct {
+      uint32_t arg1;
+      uint32_t arg2;
+  };
+
+  CASSERT(MY_STRUCT_SIZE == sizeof(struct my_struct), assert_my_struct_size_mismatch);
+
+
+If ``MY_STRUCT_SIZE`` in the above example were wrong then the compiler would
+emit an error like this:
+
+::
+
+  my_struct.h:10:1: error: size of array ‘assert_my_struct_size_mismatch’ is negative
+
+
+Using assert() to check for programming errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In general, each secure world TF image (BL1, BL2, BL31 and BL32) should be
+treated as a tightly integrated package; the image builder should be aware of
+and responsible for all functionality within the image, even if code within that
+image is provided by multiple entities. This allows us to be more aggressive in
+interpreting invalid state or bad function arguments as programming errors using
+``assert()``, including arguments passed across platform porting interfaces.
+This is in contrast to code in a Linux environment, which is less tightly
+integrated and may attempt to be more defensive by passing the error back up the
+call stack.
+
+Where possible, badly written TF code should fail early using ``assert()``. This
+helps reduce the amount of untested conditional code. By default these
+statements are not compiled into release builds, although this can be overridden
+using the ``ENABLE_ASSERTIONS`` build flag.
+
+Examples:
+
+- Bad argument supplied to library function
+- Bad argument provided by platform porting function
+- Internal secure world image state is inconsistent
+
+
+Handling integration errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Each secure world image may be provided by a different entity (for example, a
+Trusted Boot vendor may provide the BL2 image, a TEE vendor may provide the BL32
+image and the OEM/SoC vendor may provide the other images).
+
+An image may contain bugs that are only visible when the images are integrated.
+The system integrator may not even have access to the debug variants of all the
+images in order to check if asserts are firing. For example, the release variant
+of BL1 may have already been burnt into the SoC. Therefore, TF code that detects
+an integration error should _not_ consider this a programming error, and should
+always take action, even in release builds.
+
+If an integration error is considered non-critical it should be treated as a
+recoverable error. If the error is considered critical it should be treated as
+an unexpected unrecoverable error.
+
+Handling recoverable errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The secure world **must not** crash when supplied with bad data from an external
+source. For example, data from the normal world or a hardware device. Similarly,
+the secure world **must not** crash if it detects a non-critical problem within
+itself or the system. It must make every effort to recover from the problem by
+emitting a ``WARN`` message, performing any necessary error handling and
+continuing.
+
+Examples:
+
+- Secure world receives SMC from normal world with bad arguments.
+- Secure world receives SMC from normal world at an unexpected time.
+- BL31 receives SMC from BL32 with bad arguments.
+- BL31 receives SMC from BL32 at unexpected time.
+- Secure world receives recoverable error from hardware device. Retrying the
+  operation may help here.
+- Non-critical secure world service is not functioning correctly.
+- BL31 SPD discovers minor configuration problem with corresponding SP.
+
+Handling unrecoverable errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In some cases it may not be possible for the secure world to recover from an
+error. This situation should be handled in one of the following ways:
+
+1. If the unrecoverable error is unexpected then emit an ``ERROR`` message and
+   call ``panic()``. This will end up calling the platform-specific function
+   ``plat_panic_handler()``.
+2. If the unrecoverable error is expected to occur in certain circumstances,
+   then emit an ``ERROR`` message and call the platform-specific function
+   ``plat_error_handler()``.
+
+Cases 1 and 2 are subtly different. A platform may implement ``plat_panic_handler``
+and ``plat_error_handler`` in the same way (for example, by waiting for a secure
+watchdog to time-out or by invoking an interface on the platform's power
+controller to reset the platform). However, ``plat_error_handler`` may take
+additional action for some errors (for example, it may set a flag so the
+platform resets into a different mode). Also, ``plat_panic_handler()`` may
+implement additional debug functionality (for example, invoking a hardware
+breakpoint).
+
+Examples of unexpected unrecoverable errors:
+
+- BL32 receives an unexpected SMC response from BL31 that it is unable to
+  recover from.
+- BL31 Trusted OS SPD code discovers that BL2 has not loaded the corresponding
+  Trusted OS, which is critical for platform operation.
+- Secure world discovers that a critical hardware device is an unexpected and
+  unrecoverable state.
+- Secure world receives an unexpected and unrecoverable error from a critical
+  hardware device.
+- Secure world discovers that it is running on unsupported hardware.
+
+Examples of expected unrecoverable errors:
+
+- BL1/BL2 fails to load the next image due to missing/corrupt firmware on disk.
+- BL1/BL2 fails to authenticate the next image due to an invalid certificate.
+- Secure world continuously receives recoverable errors from a hardware device
+  but is unable to proceed without a valid response.
+
+Handling critical unresponsiveness
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the secure world is waiting for a response from an external source (for
+example, the normal world or a hardware device) which is critical for continued
+operation, it must not wait indefinitely. It must have a mechanism (for example,
+a secure watchdog) for resetting itself and/or the external source to prevent
+the system from executing in this state indefinitely.
+
+Examples:
+
+- BL1 is waiting for the normal world to raise an SMC to proceed to the next
+  stage of the secure firmware update process.
+- A Trusted OS is waiting for a response from a proxy in the normal world that
+  is critical for continued operation.
+- Secure world is waiting for a hardware response that is critical for continued
+  operation.
+
+Security considerations
+-----------------------
+
+Part of the security of a platform is handling errors correctly, as described in
+the previous section. There are several other security considerations covered in
+this section.
+
+Do not leak secrets to the normal world
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The secure world **must not** leak secrets to the normal world, for example in
+response to an SMC.
+
+Handling Denial of Service attacks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The secure world **should never** crash or become unusable due to receiving too
+many normal world requests (a *Denial of Service* or *DoS* attack). It should
+have a mechanism for throttling or ignoring normal world requests.
+
+Performance considerations
+--------------------------
+
+Avoid printf and use logging macros
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``debug.h`` provides logging macros (for example, ``WARN`` and ``ERROR``)
+which wrap ``tf_log`` and which allow the logging call to be compiled-out
+depending on the ``make`` command. Use these macros to avoid print statements
+being compiled unconditionally into the binary.
+
+Each logging macro has a numerical log level:
+
+.. code:: c
+
+  #define LOG_LEVEL_NONE    0
+  #define LOG_LEVEL_ERROR   10
+  #define LOG_LEVEL_NOTICE  20
+  #define LOG_LEVEL_WARNING 30
+  #define LOG_LEVEL_INFO    40
+  #define LOG_LEVEL_VERBOSE 50
+
+
+By default, all logging statements with a log level ``<= LOG_LEVEL_INFO`` will
+be compiled into debug builds and all statements with a log level
+``<= LOG_LEVEL_NOTICE`` will be compiled into release builds. This can be
+overridden from the command line or by the platform makefile (although it may be
+necessary to clean the build directory first). For example, to enable
+``VERBOSE`` logging on FVP:
+
+``make PLAT=fvp LOG_LEVEL=50 all``
+
+Use const data where possible
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For example, the following code:
+
+.. code:: c
+
+  struct my_struct {
+          int arg1;
+          int arg2;
+  };
+
+  void init(struct my_struct *ptr);
+
+  void main(void)
+  {
+          struct my_struct x;
+          x.arg1 = 1;
+          x.arg2 = 2;
+          init(&x);
+  }
+
+is better written as:
+
+.. code:: c
+
+  struct my_struct {
+          int arg1;
+          int arg2;
+  };
+
+  void init(const struct my_struct *ptr);
+
+  void main(void)
+  {
+          const struct my_struct x = { 1, 2 };
+          init(&x);
+  }
+
+This allows the linker to put the data in a read-only data section instead of a
+writeable data section, which may result in a smaller and faster binary. Note
+that this may require dependent functions (``init()`` in the above example) to
+have ``const`` arguments, assuming they don't need to modify the data.
+
+Library and driver code
+-----------------------
+
+TF library code (under ``lib/`` and ``include/lib``) is any code that provides a
+reusable interface to other code, potentially even to code outside of TF.
+
+In some systems drivers must conform to a specific driver framework to provide
+services to the rest of the system. TF has no driver framework and the
+distinction between a driver and library is somewhat subjective.
+
+A driver (under ``drivers/`` and ``include/drivers/``) is defined as code that
+interfaces with hardware via a memory mapped interface.
+
+Some drivers (for example, the Arm CCI driver in ``include/drivers/arm/cci.h``)
+provide a general purpose API to that specific hardware. Other drivers (for
+example, the Arm PL011 console driver in ``drivers/arm/pl011/pl011_console.S``)
+provide a specific hardware implementation of a more abstract library API. In
+the latter case there may potentially be multiple drivers for the same hardware
+device.
+
+Neither libraries nor drivers should depend on platform-specific code. If they
+require platform-specific data (for example, a base address) to operate then
+they should provide an initialization function that takes the platform-specific
+data as arguments.
+
+TF common code (under ``common/`` and ``include/common/``) is code that is re-used
+by other generic (non-platform-specific) TF code. It is effectively internal
+library code.
+
+.. _`Why the “volatile” type class should not be used`: https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html
+.. _`Procedure Call Standard for the Arm Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
+.. _`Procedure Call Standard for the Arm 64-bit Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
diff --git a/docs/process/contributing.rst b/docs/process/contributing.rst
new file mode 100644
index 0000000..66b282c
--- /dev/null
+++ b/docs/process/contributing.rst
@@ -0,0 +1,149 @@
+Contributor's Guide
+===================
+
+Getting Started
+---------------
+
+-  Make sure you have a Github account and you are logged on
+   `developer.trustedfirmware.org`_.
+-  Create an `issue`_ for your work if one does not already exist. This gives
+   everyone visibility of whether others are working on something similar.
+
+   -  If you intend to include Third Party IP in your contribution, please
+      raise a separate `issue`_ for this and ensure that the changes that
+      include Third Party IP are made on a separate topic branch.
+
+-  Clone `Trusted Firmware-A`_ on your own machine as suggested on the
+   `User Guide`_.
+-  Create a local topic branch based on the `Trusted Firmware-A`_ ``master``
+   branch.
+
+Making Changes
+--------------
+
+-  Make commits of logical units. See these general `Git guidelines`_ for
+   contributing to a project.
+-  Follow the `Coding Guidelines`_.
+
+   -  Use the checkpatch.pl script provided with the Linux source tree. A
+      Makefile target is provided for convenience (see the "Checking source code
+      style" section in the `User Guide`_).
+
+-  Keep the commits on topic. If you need to fix another bug or make another
+   enhancement, please create a separate `issue`_ and address it on a separate
+   topic branch.
+-  Avoid long commit series. If you do have a long series, consider whether
+   some commits should be squashed together or addressed in a separate topic.
+-  Make sure your commit messages are in the proper format. If a commit fixes
+   an `issue`_, include a reference.
+-  Where appropriate, please update the documentation.
+
+   -  Consider whether the `User Guide`_, `Porting Guide`_, `Firmware Design`_
+      or other in-source documentation needs updating.
+   -  Ensure that each changed file has the correct copyright and license
+      information. Files that entirely consist of contributions to this
+      project should have a copyright notice and BSD-3-Clause SPDX license
+      identifier of the form as shown in `license.rst`_. Files that contain
+      changes to imported Third Party IP files should retain their original
+      copyright and license notices. For significant contributions you may
+      add your own copyright notice in following format:
+
+      ::
+
+          Portions copyright (c) [XXXX-]YYYY, <OWNER>. All rights reserved.
+
+      where XXXX is the year of first contribution (if different to YYYY) and
+      YYYY is the year of most recent contribution. <OWNER> is your name or
+      your company name.
+   -  If you are submitting new files that you intend to be the technical
+      sub-maintainer for (for example, a new platform port), then also update
+      the `Maintainers`_ file.
+   -  For topics with multiple commits, you should make all documentation
+      changes (and nothing else) in the last commit of the series. Otherwise,
+      include the documentation changes within the single commit.
+
+-  Please test your changes. As a minimum, ensure that Linux boots on the
+   Foundation FVP. See `Running the software on FVP`_ for more information. For
+   more extensive testing, consider running the `TF-A Tests`_ against your
+   patches.
+
+Submitting Changes
+------------------
+
+-  Ensure that each commit in the series has at least one ``Signed-off-by:``
+   line, using your real name and email address. The names in the
+   ``Signed-off-by:`` and ``Author:`` lines must match. If anyone else
+   contributes to the commit, they must also add their own ``Signed-off-by:``
+   line. By adding this line the contributor certifies the contribution is made
+   under the terms of the `Developer Certificate of Origin (DCO)`_.
+
+   More details may be found in the `Gerrit Signed-off-by Lines guidelines`_.
+
+-  Ensure that each commit also has a unique ``Change-Id:`` line. If you have
+   cloned the repository with the "`Clone with commit-msg hook`" clone method
+   (as advised on the `User Guide`_), this should already be the case.
+
+   More details may be found in the `Gerrit Change-Ids documentation`_.
+
+-  Submit your changes for review at https://review.trustedfirmware.org
+   targeting the ``integration`` branch.
+
+   -  The changes will then undergo further review and testing by the
+      `Maintainers`_. Any review comments will be made directly on your patch.
+      This may require you to do some rework.
+
+   Refer to the `Gerrit Uploading Changes documentation`_ for more details.
+
+-  When the changes are accepted, the `Maintainers`_ will integrate them.
+
+   -  Typically, the `Maintainers`_ will merge the changes into the
+      ``integration`` branch.
+   -  If the changes are not based on a sufficiently-recent commit, or if they
+      cannot be automatically rebased, then the `Maintainers`_ may rebase it on
+      the ``master`` branch or ask you to do so.
+   -  After final integration testing, the changes will make their way into the
+      ``master`` branch. If a problem is found during integration, the merge
+      commit will be removed from the ``integration`` branch and the
+      `Maintainers`_ will ask you to create a new patch set to resolve the
+      problem.
+
+Binary Components
+-----------------
+
+-  Platforms may depend on binary components submitted to the `Trusted Firmware
+   binary repository`_ if they require code that the contributor is unable or
+   unwilling to open-source. This should be used as a rare exception.
+-  All binary components must follow the contribution guidelines (in particular
+   licensing rules) outlined in the `readme.rst <tf-binaries-readme_>`_ file of
+   the binary repository.
+-  Binary components must be restricted to only the specific functionality that
+   cannot be open-sourced and must be linked into a larger open-source platform
+   port. The majority of the platform port must still be implemented in open
+   source. Platform ports that are merely a thin wrapper around a binary
+   component that contains all the actual code will not be accepted.
+-  Only platform port code (i.e. in the ``plat/<vendor>`` directory) may rely on
+   binary components. Generic code must always be fully open-source.
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _developer.trustedfirmware.org: https://developer.trustedfirmware.org
+.. _issue: https://developer.trustedfirmware.org/project/board/1/
+.. _Trusted Firmware-A: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+.. _Git guidelines: http://git-scm.com/book/ch5-2.html
+.. _Coding Guidelines: ./coding-guidelines.rst
+.. _User Guide: ../getting_started/user-guide.rst
+.. _Porting Guide: ../getting_started/porting-guide.rst
+.. _Firmware Design: ../design/firmware-design.rst
+.. _license.rst: ../license.rst
+.. _Acknowledgements: ../acknowledgements.rst
+.. _Maintainers: ../maintainers.rst
+.. _Running the software on FVP: ../getting_started/user-guide.rst#user-content-running-the-software-on-fvp
+.. _Developer Certificate of Origin (DCO): ../../dco.txt
+.. _Gerrit Uploading Changes documentation: https://review.trustedfirmware.org/Documentation/user-upload.html
+.. _Gerrit Signed-off-by Lines guidelines: https://review.trustedfirmware.org/Documentation/user-signedoffby.html
+.. _Gerrit Change-Ids documentation: https://review.trustedfirmware.org/Documentation/user-changeid.html
+.. _TF-A Tests: https://git.trustedfirmware.org/TF-A/tf-a-tests.git/about/
+.. _Trusted Firmware binary repository: https://review.trustedfirmware.org/admin/repos/tf-binaries
+.. _tf-binaries-readme: https://git.trustedfirmware.org/tf-binaries.git/tree/readme.rst
diff --git a/docs/process/faq.rst b/docs/process/faq.rst
new file mode 100644
index 0000000..6aa04f0
--- /dev/null
+++ b/docs/process/faq.rst
@@ -0,0 +1,79 @@
+Frequently-Asked Questions (FAQ)
+================================
+
+How do I update my changes?
+---------------------------
+
+Often it is necessary to update your patch set before it is merged. Refer to the
+`Gerrit Upload Patch Set documentation`_ on how to do so.
+
+If you need to modify an existing patch set with multiple commits, refer to the
+`Gerrit Replace Changes documentation`_.
+
+How long will my changes take to merge into ``integration``?
+------------------------------------------------------------
+
+This can vary a lot, depending on:
+
+* How important the patch set is considered by the TF maintainers. Where
+  possible, you should indicate the required timescales for merging the patch
+  set and the impact of any delay. Feel free to add a comment to your patch set
+  to get an estimate of when it will be merged.
+
+* The quality of the patch set. Patches are likely to be merged more quickly if
+  they follow the coding guidelines, have already had some code review, and have
+  been appropriately tested.
+
+* The impact of the patch set. For example, a patch that changes a key generic
+  API is likely to receive much greater scrutiny than a local change to a
+  specific platform port.
+
+* How much opportunity for external review is required. For example, the TF
+  maintainers may not wait for external review comments to merge trivial
+  bug-fixes but may wait up to a week to merge major changes, or ones requiring
+  feedback from specific parties.
+
+* How many other patch sets are waiting to be integrated and the risk of
+  conflict between the topics.
+
+* If there is a code freeze in place in preparation for the release. Please
+  refer the `release information`_ for more details.
+
+* The workload of the TF maintainers.
+
+How long will it take for my changes to go from ``integration`` to ``master``?
+------------------------------------------------------------------------------
+
+This depends on how many concurrent patches are being processed at the same
+time. In simple cases where all potential regressions have already been tested,
+the delay will be less than 1 day. If the TF maintainers are trying to merge
+several things over the course of a few days, it might take up to a week.
+Typically, it will be 1-2 days.
+
+The worst case is if the TF maintainers are trying to make a release while also
+receiving patches that will not be merged into the release. In this case, the
+patches will be merged onto ``integration``, which will temporarily diverge from
+the release branch. The ``integration`` branch will be rebased onto ``master``
+after the release, and then ``master`` will be fast-forwarded to ``integration``
+1-2 days later. This whole process could take up 4 weeks. Please refer the
+`release information`_ for code freeze dates. The TF maintainers will inform the
+patch owner if this is going to happen.
+
+It is OK to create a patch based on commits that are only available in
+``integration`` or another patch set, rather than ``master``. There is a risk
+that the dependency commits will change (for example due to patch set rework or
+integration problems). If this happens, the dependent patch will need reworking.
+
+What are these strange comments in my changes?
+----------------------------------------------
+
+All the comments from ``ci-bot-user`` are associated with Continuous Integration
+infrastructure. The links published on the comment are not currently accessible,
+but would be after the CI has been transitioned to `trustedfirmware.org`_.
+Please refer to https://github.com/ARM-software/tf-issues/issues/681 for more
+details on the timelines.
+
+.. _release information: release-information.rst
+.. _Gerrit Upload Patch Set documentation: https://review.trustedfirmware.org/Documentation/intro-user.html#upload-patch-set
+.. _Gerrit Replace Changes documentation: https://review.trustedfirmware.org/Documentation/user-upload.html#push_replace
+.. _trustedfirmware.org: https://www.trustedfirmware.org/
diff --git a/docs/process/index.rst b/docs/process/index.rst
new file mode 100644
index 0000000..a870c8f
--- /dev/null
+++ b/docs/process/index.rst
@@ -0,0 +1,15 @@
+Processes & Policies
+====================
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   release-information
+   security
+   platform-compatibility-policy
+   coding-guidelines
+   contributing
+   faq
+   security-hardening
diff --git a/docs/process/platform-compatibility-policy.rst b/docs/process/platform-compatibility-policy.rst
new file mode 100644
index 0000000..a11ba38
--- /dev/null
+++ b/docs/process/platform-compatibility-policy.rst
@@ -0,0 +1,38 @@
+Platform Compatibility Policy
+=============================
+
+Introduction
+------------
+
+This document clarifies the project's policy around compatibility for upstream
+platforms.
+
+Platform compatibility policy
+-----------------------------
+
+Platform compatibility is mainly affected by changes to Platform APIs (as
+documented in the `Porting Guide`_), driver APIs (like the GICv3 drivers) or
+library interfaces (like xlat_table library). The project will try to maintain
+compatibility for upstream platforms. Due to evolving requirements and
+enhancements, there might be changes affecting platform compatibility which
+means the previous interface needs to be deprecated and a new interface
+introduced to replace it. In case the migration to the new interface is trivial,
+the contributor of the change is expected to make good effort to migrate the
+upstream platforms to the new interface.
+
+The deprecated interfaces are listed inside `Release information`_ as well as
+the release after which each one will be removed. When an interface is
+deprecated, the page must be updated to indicate the release after which the
+interface will be removed. This must be at least 1 full release cycle in future.
+For non-trivial interface changes, an email should be sent out to the `TF-A
+public mailing list`_ to notify platforms that they should migrate away from the
+deprecated interfaces. Platforms are expected to migrate before the removal of
+the deprecated interface.
+
+--------------
+
+*Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Porting Guide: ../getting_started/porting-guide.rst
+.. _Release information: ./release-information.rst#removal-of-deprecated-interfaces
+.. _TF-A public mailing list: https://lists.trustedfirmware.org/mailman/listinfo/tf-a
diff --git a/docs/process/release-information.rst b/docs/process/release-information.rst
new file mode 100644
index 0000000..b81d42d
--- /dev/null
+++ b/docs/process/release-information.rst
@@ -0,0 +1,82 @@
+Release Processes
+=================
+
+Project Release Cadence
+-----------------------
+
+The project currently aims to do a release once every 6 months which will be
+tagged on the master branch. There will be a code freeze (stop merging
+non-essential PRs) up to 4 weeks prior to the target release date. The release
+candidates will start appearing after this and only bug fixes or updates
+required for the release will be merged. The maintainers are free to use their
+judgement on what PRs are essential for the release. A release branch may be
+created after code freeze if there are significant PRs that need merging onto
+the integration branch during the merge window.
+
+The release testing will be performed on release candidates and depending on
+issues found, additional release candidates may be created to fix the issues.
+
+::
+
+                            |<----------6 months---------->|
+            |<---4 weeks--->|              |<---4 weeks--->|
+       +-----------------------------------------------------------> time
+            |               |              |               |
+         code freeze       ver w.x       code freeze     ver y.z
+
+
+Upcoming Releases
+~~~~~~~~~~~~~~~~~
+
+These are the estimated dates for the upcoming release. These may change
+depending on project requirement and partner feedback.
+
++-----------------+---------------------------+------------------------------+
+| Release Version |  Target Date              | Expected Code Freeze         |
++=================+===========================+==============================+
+| v2.0            | 1st week of Oct '18       | 1st week of Sep '18          |
++-----------------+---------------------------+------------------------------+
+| v2.1            | 5th week of Mar '19       | 1st week of Mar '19          |
++-----------------+---------------------------+------------------------------+
+
+Removal of Deprecated Interfaces
+--------------------------------
+
+As mentioned in the `Platform compatibility policy`_, this is a live document
+cataloging all the deprecated interfaces in TF-A project and the Release version
+after which it will be removed.
+
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| Interface                      | Deprecation | Removed | Comments                                                |
+|                                | Date        | after   |                                                         |
+|                                |             | Release |                                                         |
++================================+=============+=========+=========================================================+
+| Legacy Console API             | Jan '18     | v2.1    | Deprecated in favour of ``MULTI_CONSOLE_API``           |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| Weak default                   | Oct '18     | v2.1    | The default implementations are defined in              |
+| ``plat_crash_console_*``       |             |         | `crash_console_helpers.S`_. The platforms have to       |
+| APIs                           |             |         | define ``plat_crash_console_*``.                        |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| ``finish_console_register``    | Oct '18     | v2.1    | The old version of the macro is deprecated. See commit  |
+| macro in                       |             |         | cc5859c_ for more details.                              |
+| ``MULTI_CONSOLE_API``          |             |         |                                                         |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| Types ``tzc_action_t`` and     | Oct '18     | v2.1    | Using logical operations such as OR in enumerations     |
+| ``tzc_region_attributes_t``    |             |         | goes against the MISRA guidelines.                      |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| Macro ``EL_IMPLEMENTED()``     | Oct '18     | v2.1    | Deprecated in favour of ``el_implemented()``.           |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| ``get_afflvl_shift()``,        | Dec '18     | v2.1    | Removed.                                                |
+| ``mpidr_mask_lower_afflvls()``,|             |         |                                                         |
+| and ``eret()``.                |             |         |                                                         |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+| Extra include paths in the     | Jan '18     | v2.1    | Now it is needed to use the full path of the common     |
+| Makefile in ``INCLUDES``.      |             |         | header files. More information in commit 09d40e0e0828_. |
++--------------------------------+-------------+---------+---------------------------------------------------------+
+
+*Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Platform compatibility policy: platform-compatibility-policy.rst
+.. _crash_console_helpers.S: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/common/aarch64/crash_console_helpers.S
+.. _cc5859c: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=cc5859ca19ff546c35eb0331000dae090b6eabcf
+.. _09d40e0e0828: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=09d40e0e08283a249e7dce0e106c07c5141f9b7e
diff --git a/docs/process/security-hardening.rst b/docs/process/security-hardening.rst
new file mode 100644
index 0000000..e2c68b8
--- /dev/null
+++ b/docs/process/security-hardening.rst
@@ -0,0 +1,58 @@
+Security hardening
+==================
+
+This page contains guidance on what to check for additional security measures,
+including build options that can be modified to improve security or catch issues
+early in development.
+
+Build options
+-------------
+
+Several build options can be used to check for security issues. Refer to the
+`user guide`_ for detailed information on the specific build options.
+
+- The ``BRANCH_PROTECTION`` build flag can be used to enable Pointer
+  Authentication and Branch Target Identification.
+
+- The ``ENABLE_STACK_PROTECTOR`` build flag can be used to identify buffer
+  overflows.
+
+- The ``W`` build flag can be used to enable a number of compiler warning
+  options to detect potentially incorrect code.
+
+  - W=0 (default value)
+
+    The ``Wunused`` with ``Wno-unused-parameter``, ``Wdisabled-optimization``
+    and ``Wvla`` flags are enabled.
+
+    The ``Wunused-but-set-variable``, ``Wmaybe-uninitialized`` and
+    ``Wpacked-bitfield-compat`` are GCC specific flags that are also enabled.
+
+  - W=1
+
+    Adds ``Wextra``, ``Wmissing-declarations``, ``Wmissing-format-attribute``,
+    ``Wmissing-prototypes``, ``Wold-style-definition`` and
+    ``Wunused-const-variable``.
+
+  - W=2
+
+    Adds ``Waggregate-return``, ``Wcast-align``, ``Wnested-externs``,
+    ``Wshadow``, ``Wlogical-op``, ``Wmissing-field-initializers`` and
+    ``Wsign-compare``.
+
+  - W=3
+
+    Adds ``Wbad-function-cast``, ``Wcast-qual``, ``Wconversion``, ``Wpacked``,
+    ``Wpadded``, ``Wpointer-arith``, ``Wredundant-decls`` and
+    ``Wswitch-default``.
+
+  Refer to the GCC or Clang documentation for more information on the individual
+  options: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html and
+  https://clang.llvm.org/docs/DiagnosticsReference.html.
+
+  NB: The ``Werror`` flag is enabled by default in TF-A and can be disabled by
+  setting the ``E`` build flag to 0.
+
+*Copyright (c) 2019, Arm Limited. All rights reserved.*
+
+.. _user guide: ../getting_started/user-guide.rst
diff --git a/docs/process/security-reporting.asc b/docs/process/security-reporting.asc
new file mode 100644
index 0000000..8c41f7b
--- /dev/null
+++ b/docs/process/security-reporting.asc
@@ -0,0 +1,45 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGP Desktop 10.2.0 (Build 2317)
+
+mQENBFey/QMBCACyxJaLsMYU794ZfzLdY172tHXRJfP0X3b34HU35G7kYl1zNiYc
+/NoygtQdtDv/aW1B2A/YTNhGge+gX4BWAREd5CYDbdPEoMWC395/qbnmMmez7YNY
+PEJ9Iq9e5AayAWwZTL1zgKwdvE+WTwWok/nMbsifJSEdhdrOIHNqRcZgplUUyZ2R
+sDqFtSbACO3xj4Psk8KJ23Ax7UZgULouZOJaHOnyq8F9V/U7zWvX4Odf96XaC1Em
+cUTsG0kQfa7Y4Hqqjzowq366I4k2o2LAtuLPWNCvq5jjEceLs2+qV4cNLgyL2dzO
+wtUL6EdkrGfkxsPHpsVKXig4wjeX9ehCSqRlABEBAAG0PVRydXN0ZWQgRmlybXdh
+cmUgU2VjdXJpdHkgPHRydXN0ZWQtZmlybXdhcmUtc2VjdXJpdHlAYXJtLmNvbT6J
+AYwEEAECAHYFAley/SEwFIAAAAAAIAAHcHJlZmVycmVkLWVtYWlsLWVuY29kaW5n
+QHBncC5jb21wZ3BtaW1lCAsJCAcDAgEKAhkBGRhsZGFwOi8va2V5c2VydmVyLnBn
+cC5jb20FGwMAAAAFFgADAgEFHgEAAAAGFQgJCgMCAAoJEDq378tFoN/QFJsH/0ly
+H91LYYzKIQrbolQw7Rp47lgzH88uN1rInYpW2GaTbjwPffAhYJ4VsN8RaiFskD9m
+DjMg4vY8p0jPTCUX1Acq20Wq0Ybv3HcrtjUp4ie0+rLUi3043yJyKFMWkJC2Kr+p
+SobnxSrAie4HDFUgSaPoh9Qf1zXEzOavdgcziMiyS5iVUf6NXYZ9z82OTZ6TdPKS
+u+L5zOHTdrV3+hD54w00Xa+EIE7u4v0to6Uwm977508hyGuvpOVq+u7+S3qJQvnY
++JheStbgLsm6CyoRjyrlTE01ujAD6hI6Ef9yMgEljOBEy4phKAJ67SCRLEOiCp5U
+YHFCULwhzIyg2y3WmZSJASIEEAECAAwFAlezAnwFAwASdQAACgkQlxC4m8pXrXzd
+GAf/T8YEICI9qQt2vnCtCbBvVaTc2sAphVZ51kZVDqCDPB7znDtJYRBpi/9IPELt
+mYwIElMx2mqmahVaeUghmbzmcLZe8QHUi8GanO1mh+ook6uyjRojSIq6VUVV5uUf
+tuscfhpilOvUclqMqYEIgXfl08YwS40Kmmj0qokwad0co0zGQ8GEhlgMi2yvJfiG
+fPS0Xcn1J0980E/VgJQCAKwZvukrbb32WVwuhgepqs/4/62PZNxglcErioFt6P0A
+ik4t9Hr0uErqCeEKiYtmEw5e9ioRdX7CV+tJgIk907Tpv6E0iDFRJHmJBvmsz82O
+stOazS3wZ5Xck7asTqkvoyo9Z7kBDQRXsv0DAQgAsmL1UUIWyoNmYJWixSPDmclP
+0ul3T1FCOsIlWTeVeshnHByYdgZOfce78ETCUoq8G7qvYm4GRrEDpqVbxqTxJioP
+4Li05WDdNCKzSoqWd8ADA48gYnnJEu2NhA7ZkEC6u3+Mdbmd3M0J6nsAWeE0BV1p
+F5zI600sJuoH2QNWB7Kv5N3GCFE4IgCIH8MwDo4Y4FTZtygx4GjEtSExiOIz+bpX
+2+GkFCQGpIyLHLP4FmQmrsNzsIdEyFuG0IdoVuQ2PtNLiw+Wkm7CXWgRmFx/dtPN
+eVnOFWdbTtjBWVv/Z6zbANos2knfc75KR4FCQ6pWRvVeJuMuMopUDkfFDMtR8QAR
+AQABiQJBBBgBAgErBQJXsv0EBRsMAAAAwF0gBBkBCAAGBQJXsv0DAAoJENaB8ph8
+s9hu/nsH/Rx696ZR+1vZi5qCTUwo6s0Qa15x4OuyJEM85VgMLVY7/MZpp1Y8If6u
+A5BynQpy4QIPxIRsRx6twduW9/gb8UVhpMRPyuJ+5sSv0/KeUqkPbKSUGro2zGlR
+sjqPrchi6uafWZqOR/y/DNkEvkgZZaP+f9xs2qWKuoF08yTioo76QoroA4DVuVAT
+MkDFe9d3natAmfmjO4kvxuthg3y7R+sdXrCHpYYJZdbiR6gyj7e8whlSLwHQT3lz
+7QBL/CvVvL/dmhu5pk8fsksbehepMQTkCJ6GGEamOPEhwh7IvlzhEt97U4uzjuMd
+BPjqOCes+4QTmn/+lMTySG0kXxnHOEUACgkQOrfvy0Wg39D8Jgf/Uf3epkMOJ9xm
+N1l5vW8tQQ6RR055YQxQ9P6JMyCQGEJmGOcvrasCho69wMQDy4AYVtJaZd25LH/3
+LX/lcyDOP4C9VYXM+IxlcaRmjBKqWx9UzQeeioIkfmjMpJFU846ZP1dacge0lPx8
+p6ocPbM0rkv0xuF/dwkDQd4BPSmv4/3/UM8FRoYo8Q7SHkDR98wJ8FCm6k9wRtWC
+K/jzmBswY2TewAHom3jLzTM0FZ/n5Sini3EGAI2EvnQrxWRpeE7ZOkHKqLHEOaHl
+zeST4U/cUgxhwgnhbGJ7zmrFsHpYnnZYM3mIKfQ3/EhksZ68TF9IB1tfUiQTij4r
+9jWa0ybRdQ==
+=nZZb
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/docs/process/security.rst b/docs/process/security.rst
new file mode 100644
index 0000000..94eb9c3
--- /dev/null
+++ b/docs/process/security.rst
@@ -0,0 +1,105 @@
+Security Handling
+=================
+
+Security Disclosures
+--------------------
+
+We disclose all security vulnerabilities we find, or are advised about, that are
+relevant to Trusted Firmware-A. We encourage responsible disclosure of
+vulnerabilities and inform users as best we can about all possible issues.
+
+We disclose TF-A vulnerabilities as Security Advisories, all of which are listed
+at the bottom of this page. Any new ones will, additionally, be announced as
+issues in the project's `issue tracker`_ with the ``security-advisory`` tag. You
+can receive notification emails for these by watching the "Trusted Firmware-A"
+project at https://developer.trustedfirmware.org/.
+
+Found a Security Issue?
+-----------------------
+
+Although we try to keep TF-A secure, we can only do so with the help of the
+community of developers and security researchers.
+
+If you think you have found a security vulnerability, please **do not** report it
+in the `issue tracker`_. Instead send an email to
+trusted-firmware-security@arm.com
+
+Please include:
+
+* Trusted Firmware-A version (or commit) affected
+
+* A description of the concern or vulnerability
+
+* Details on how to replicate the vulnerability, including:
+
+  - Configuration details
+
+  - Proof of concept exploit code
+
+  - Any additional software or tools required
+
+We recommend using `this PGP/GPG key`_ for encrypting the information. This key
+is also available at http://keyserver.pgp.com and LDAP port 389 of the same
+server. The fingerprint for this key is:
+
+::
+
+    1309 2C19 22B4 8E87 F17B FE5C 3AB7 EFCB 45A0 DFD0
+
+If you would like replies to be encrypted, please provide your public key.
+
+Please give us the time to respond to you and fix the vulnerability before going
+public. We do our best to respond and fix any issues quickly. We also need to
+ensure providers of products that use TF-A have a chance to consider the
+implications of the vulnerability and its remedy.
+
+Afterwards, we encourage you to write-up your findings about the TF-A source
+code.
+
+Attribution
+-----------
+
+We will name and thank you in the ``change-log.rst`` distributed with the source
+code and in any published security advisory.
+
+Security Advisories
+-------------------
+
++-----------+------------------------------------------------------------------+
+| ID        | Title                                                            |
++===========+==================================================================+
+| `TFV-1`_  | Malformed Firmware Update SMC can result in copy of unexpectedly |
+|           | large data into secure memory                                    |
++-----------+------------------------------------------------------------------+
+| `TFV-2`_  | Enabled secure self-hosted invasive debug interface can allow    |
+|           | normal world to panic secure world                               |
++-----------+------------------------------------------------------------------+
+| `TFV-3`_  | RO memory is always executable at AArch64 Secure EL1             |
++-----------+------------------------------------------------------------------+
+| `TFV-4`_  | Malformed Firmware Update SMC can result in copy or              |
+|           | authentication of unexpected data in secure memory in AArch32    |
+|           | state                                                            |
++-----------+------------------------------------------------------------------+
+| `TFV-5`_  | Not initializing or saving/restoring PMCR_EL0 can leak secure    |
+|           | world timing information                                         |
++-----------+------------------------------------------------------------------+
+| `TFV-6`_  | Trusted Firmware-A exposure to speculative processor             |
+|           | vulnerabilities using cache timing side-channels                 |
++-----------+------------------------------------------------------------------+
+| `TFV-7`_  | Trusted Firmware-A exposure to cache speculation vulnerability   |
+|           | Variant 4                                                        |
++-----------+------------------------------------------------------------------+
+| `TFV-8`_  | Not saving x0 to x3 registers can leak information from one      |
+|           | Normal World SMC client to another                               |
++-----------+------------------------------------------------------------------+
+
+.. _issue tracker: https://developer.trustedfirmware.org/project/board/1/
+.. _this PGP/GPG key: security-reporting.asc
+.. _TFV-1: ../security_advisories/security-advisory-tfv-1.rst
+.. _TFV-2: ../security_advisories/security-advisory-tfv-2.rst
+.. _TFV-3: ../security_advisories/security-advisory-tfv-3.rst
+.. _TFV-4: ../security_advisories/security-advisory-tfv-4.rst
+.. _TFV-5: ../security_advisories/security-advisory-tfv-5.rst
+.. _TFV-6: ../security_advisories/security-advisory-tfv-6.rst
+.. _TFV-7: ../security_advisories/security-advisory-tfv-7.rst
+.. _TFV-8: ../security_advisories/security-advisory-tfv-8.rst
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..358ed0e
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,3 @@
+sphinx>=2.0.0
+sphinx-rtd-theme>=0.4.3
+sphinxcontrib-plantuml>=0.15
diff --git a/docs/resources/TrustedFirmware-Logo_standard-white.png b/docs/resources/TrustedFirmware-Logo_standard-white.png
new file mode 100644
index 0000000..e7bff71
--- /dev/null
+++ b/docs/resources/TrustedFirmware-Logo_standard-white.png
Binary files differ
diff --git a/docs/resources/diagrams/Makefile b/docs/resources/diagrams/Makefile
new file mode 100644
index 0000000..7f583b5
--- /dev/null
+++ b/docs/resources/diagrams/Makefile
@@ -0,0 +1,74 @@
+#
+# Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+# This Makefile generates the image files used in the Trusted Firmware-A
+# document from the dia file.
+#
+# The PNG files in the present directory have been generated using Dia version
+# 0.97.2, which can be obtained from https://wiki.gnome.org/Apps/Dia/Download
+#
+
+# generate_image use the tool dia generate png from dia file
+#    $(1) = layers
+#    $(2) = image file name
+#    $(3) = image file format
+#    $(4) = addition opts
+#    $(5) = dia source file
+define generate_image
+	dia --show-layers=$(1) --filter=$(3) --export=$(2) $(4) $(5)
+endef
+
+RESET_DIA							= reset_code_flow.dia
+RESET_PNGS							=		\
+		default_reset_code.png 				\
+		reset_code_no_cpu_check.png			\
+		reset_code_no_boot_type_check.png 	\
+		reset_code_no_checks.png			\
+
+# The $(RESET_DIA) file is organized in several layers.
+# Each image is generated by combining and exporting the appropriate set of
+# layers.
+default_reset_code_layers			= "Frontground,Background,cpu_type_check,boot_type_check"
+reset_code_no_cpu_check_layers		= "Frontground,Background,no_cpu_type_check,boot_type_check"
+reset_code_no_boot_type_check_layers= "Frontground,Background,cpu_type_check,no_boot_type_check"
+reset_code_no_checks_layers			= "Frontground,Background,no_cpu_type_check,no_boot_type_check"
+
+default_reset_code_opts          	=
+reset_code_no_cpu_check_opts     	=
+reset_code_no_boot_type_check_opts	=
+reset_code_no_checks_opts			=
+
+INT_DIA								= int_handling.dia
+INT_PNGS							=		\
+		sec-int-handling.png				\
+		non-sec-int-handling.png
+
+# The $(INT_DIA) file is organized in several layers.
+# Each image is generated by combining and exporting the appropriate set of
+# layers.
+non-sec-int-handling_layers			= "non_sec_int_bg,legend,non_sec_int_note,non_sec_int_handling"
+sec-int-handling_layers				= "sec_int_bg,legend,sec_int_note,sec_int_handling"
+
+non-sec-int-handling_opts			= --size=1692x
+sec-int-handling_opts				= --size=1570x
+
+XLAT_DIA 							= xlat_align.dia
+XLAT_PNG 							= xlat_align.png
+
+xlat_align_layers					= "bg,translations"
+xlat_align_opts						=
+
+all:$(RESET_PNGS) $(INT_PNGS) $(XLAT_PNG)
+
+$(RESET_PNGS):$(RESET_DIA)
+	$(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<)
+
+$(INT_PNGS):$(INT_DIA)
+	$(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<)
+
+$(XLAT_PNG):$(XLAT_DIA)
+	$(call generate_image,$($(patsubst %.png,%_layers,$@)),$(patsubst %.png,%.svg,$@),svg,$($(patsubst %.png,%_opts,$@)),$<)
+	inkscape -z $(patsubst %.png,%.svg,$@) -e $@ -d 45
diff --git a/docs/resources/diagrams/default_reset_code.png b/docs/resources/diagrams/default_reset_code.png
new file mode 100644
index 0000000..d8675e4
--- /dev/null
+++ b/docs/resources/diagrams/default_reset_code.png
Binary files differ
diff --git a/docs/resources/diagrams/draw.io/ehf.svg b/docs/resources/diagrams/draw.io/ehf.svg
new file mode 100644
index 0000000..c98090f
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ehf.svg
@@ -0,0 +1,2 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1002px" height="512px" viewBox="-0.5 -0.5 1002 512" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0&quot; version=&quot;9.4.6&quot; editor=&quot;www.draw.io&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;5e4d6047-f7e8-a748-3faa-493b1a8db8b3&quot; name=&quot;Page-1&quot;&gt;7Vxbc9o4FP41PMaj++UxF2g703Yyzc5s++iCAt4azAiTkP31K2EbLMuAAzYhmaUzrX0k+XLu59Nxe/h2uvqkw/nkWzJScQ+B0aqH73oIIcCY+cdSXjIKhEBklLGORjltS3iI/lU5EeTUZTRSC2dimiRxGs1d4jCZzdQwdWih1smzO+0xid27zsOx8ggPwzD2qX9Ho3RSvAaT24HPKhpP8lsLxLOB3+Hwz1gny1l+vx7Cj+tfNjwNi2vlL7qYhKPkuUTC/R6+1UmSZkfT1a2KLXMLtmXrBjtGN8+t1SxtskDgbMVTGC9V8cjrB0tfCmasX0fZBaCHb54nUaoe5uHQjj4b+RvaJJ3G5gyaw0Wqkz8bppn3uXmM4vg2iRNtzmfJTG0mFUTDI7D+mRH/+fNXelI6VasSKX+fTyqZqlS/mCkb9ctWFLoH8vPnkiBBQZyUhEgL7Qtz7Rlvrr3loDnImVjPUOTx88ssVVov56khfwtnRnOm9uUQGOhwqp4T/cfj+AEeh4t5pvSP0crK5QDTDX/vSB8OaDv8hQQEABEuMCScUMmJw2/Eavnts3tDPIXdwue3x001MradnyY6nSTjZBbG/S31xtXwEqf/UWn6kruncJkmhrS9wtckme/UesNf/fIzv+L65Jc9CfYKYZEs9TB/6pyraajHqpiVu1X7QnslpVUcptGT68zq2JwvvU+itUbmEsZWwpxgIglBmEvoGpSoyC17xPwaW9Fdax2+lKbN7YTF3rtW7kMrmpBdcasXmzdupCqkRlNYbFh7M4qezOHYHpaNtRj+rYvRgmJuVVpTc5m/XuZq1+Sqd50k09/LxametWUjR9KoAIOScsEEIxI3sXHXLeCOTB7CGkFegsk3MmvkmzVp26obc9I3iZL+V1k6G13bzMqcDeNwsYiGLt/2ObxX8KrMGNSQMbnOGv0DEFWCv6entC7y57QT/WbFgeFqPpHpgecovetAigKKuBAQECAkct9JEh7QRh54e+FiYvL4uFDOnCMcaRGGSmrz/cH3a+1ljda3XffF4LYd30ZseJMSYkSFFFhIV2VqfBunATDhSHDMAJVE7Nagk8xRenx9uOp/hR+GtSiP6OdnbVETvM+YUZcKyrcKGsgPv/2vuGMdHQwG6PYsOkpqQsaZdLRVldwXjs+vrsW0liuXI0oMp7BxAyvB7RYcyMdWHu7vrOaEs1Gs9OI0oxmFi8l6biMLylGojrEXymBgC0ZhchgGMT4cWhuVDZzuVoTG5kXfcwgoci7HqPBFGBU1pSLEDAOOIQSbGF9fxZ+2+nST9FPX96QE8mKVgAEUMCwJoAgQwlzEqCiEdunAaxafrgJ+0dtfDdU8jZKZIX+2vjmajXv78NnLTW72O2CyLR1f64IhqhadRzlhfhH21xJW4eA6dfhF68jOcQ7aZD0QYQkpxxxJwfZlPa9cTQEOeMs4rehURxZGQqmPZK3Jgyg+kyvH+Bzq0tQssZ+pfvpiVoH7bz86dn53tC/uyNvmpfjIvJTCALXhFH2F/3F9IqC2K8S8Ql2bc5cTGGQbRRl/3Q1BWlNRN+JuGzW1D6nV7NY83H9rulnzTmVAjtXwFmSAfezt4a7/xVBudZRGwzD+OGx+Q1XHPi6Xs/l7oqcfiMlHe+s2mIw8JtutDzDXUWKVWZ2I6VRBG2r/1LLZC5ds/TuHAI6FcVAbu7/4XVfwea7tpH2Ff3zjKoGDii9rGQ3F3ab1b1j61Qm1yOm6btXhmAaQG2khwYkg1MVOKG62UXyqrtC2daUJVhvH0XyhDvvUBt1yLbhMJnnAGJJEQkmocYSuMdFNmex4zQ2o4mAtrUAtpC717aiM3rR1bmto0JJNltpO8rsYSukex8I1NZtUhdadv/6mfu52ab5RraL0ZzHPHHfjNVvf1d7hvxAyxioABAICJonb3Ua4GYUSEJ7/7V6+aRcPpySwli8QRVAKgFyXSfi+m7TlqJG5CwdYEIgFF7QC/bH9uPyB1S3vzVAfmAerwcAzBOOQ0zqQqdJjXtN2HsbReGZOh8p2uRmCde+2AL3OB6bRaBTvCimueXUSRAQmAQfb7TBXLyHFXgShJu120NmaeNIGRkXrIrIHpIAVaAikfGghgj1CpAS9nRDraqe9LdD3WV378q6kqpM0XO/m4bsr2ZmYGYMBEoAxCQmRwkOCUM1O27kEzZrkEwf6eZ32kiL6X9kqv5wCWAIp8oN7pSPzrFZ+rzWvgxH/PB28QuAAccYhYwwgyt1yihBmdxGwsWlCBDo2MRAMBMjkHZRxigmolApYNKvZjoiwrMHHXkepBTglKbwY0dN1/7iAQjCJqwWckZmps00ilMmfdiF60rBcP0b0dV+//C/6yxF9h1bfBDE9NhgAVpI/tBDwB4oFJDB1j5TSomySu51phOOgiANUsIKn7WpFU/zuCK3g3UIODbssDqE7TZGLA72wO1WtDEiwpuBDLpwr1I6eYWa8jwCUUISkyTGq2+cNdaCjj32YDyP2P5uiHFzff2l3s2swuKG8s3SdQMNliSRmAqDqN8uG80f2xbWRrfPW07ICx1t7aOKCeZzKgvD+fTQ1UoWQcyglBQTjqvskVSS9qV9eNwyVftS7sPBHO/DSPuzyPZldRaUSXRXNq8YawXKhzN9lAwXGadr96WSsw6k5KvV1ZUOh/h2lOkxVb7ONbeUXqycV+wZ+GRV+N10HPKAlD1HpEat3EUiYRRxaPSRCEsY7Kuj5sTlc3TZNNUyX4u02+p4SVS/EOUgqA4QpwVICIFglgaOs0o3Q1DXsvyysXrZFZ+DvoN+poVbhIutX34J1F2m054HljEACyZDddMk+oHakg+sb4C0uhznkhCMIhWQdGXHN971quNTKkd1le94zCdE4290QukmRN32355eiaIKkXFofywat2ezl/sqX7pTWwbalbj7prNlGhQEt/SqZOzFpfXm4kfM9td8F79v69FdDHEi4szWEM6+LfEcoOhwzzOn2/w7Lpm//hzbc/w8=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><rect x="1" y="1" width="1000" height="510" fill="none" stroke="#000000" stroke-width="2" pointer-events="none"/><rect x="121.02" y="161" width="100" height="100" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(122.5,189.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Interrupt Management Framework</div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Interrupt Management Framework</text></switch></g><path d="M 321 161.07 L 321 86 L 412.76 86" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 418.76 86 L 410.76 90 L 412.76 86 L 410.76 82 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 321.07 161 L 371.09 211 L 321.07 261 L 271.06 211 Z" fill="#d4e1f5" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(297.5,196.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Interrupt <br /></div><div>Type</div></div></div></foreignObject><text x="23" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 221.02 211 L 262.83 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 268.83 211 L 260.83 215 L 262.83 211 L 260.83 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 21 211 L 112.76 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 118.76 211 L 110.76 215 L 112.76 211 L 110.76 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(50.5,195.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="41" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;background-color:#ffffff;">Interrupt</div></div></foreignObject><text x="21" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Interrupt</text></switch></g><rect x="421.1" y="61" width="75.02" height="50" fill="#dae8fc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(449.5,79.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="17" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 18px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">NS</div></div></foreignObject><text x="9" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">NS</text></switch></g><rect x="421.1" y="186" width="75.02" height="50" fill="#dae8fc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(440.5,204.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="34" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 35px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">S-EL1</div></div></foreignObject><text x="17" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">S-EL1</text></switch></g><path d="M 371.09 211 L 412.86 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 418.86 211 L 410.86 215 L 412.86 211 L 410.86 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="421.1" y="311" width="75.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(446.5,329.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="22" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 23px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">EL3</div></div></foreignObject><text x="11" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">EL3</text></switch></g><path d="M 321 260.93 L 321 336 L 412.76 336" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 418.76 336 L 410.76 340 L 412.76 336 L 410.76 332 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="542.38" y="61" width="100.02" height="175" fill="#ffffff" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><g transform="translate(553.5,141.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="76" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 77px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SPD handlers</div></div></foreignObject><text x="38" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SPD handlers</text></switch></g><path d="M 496.12 86 L 534.14 86" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 540.14 86 L 532.14 90 L 534.14 86 L 532.14 82 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 496.12 211 L 534.14 211" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 540.14 211 L 532.14 215 L 534.14 211 L 532.14 207 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="542.38" y="348.5" width="100.02" height="112.5" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(543.5,383.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Exception Handling Framework</div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Exception Handling Framework</text></switch></g><path d="M 496.12 336 L 521 336 L 521 405 L 533.76 405" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 539.76 405 L 531.76 409 L 533.76 405 L 531.76 401 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 592 320.49 L 592 332 L 592 329 L 592 340.26" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 592 314.49 L 596 322.49 L 592 320.49 L 588 322.49 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 592 346.26 L 588 338.26 L 592 340.26 L 596 338.26 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="542.38" y="261" width="100.02" height="51.25" fill="#d5e8d4" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(565.5,279.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="51" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 52px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">GIC PMR</div></div></foreignObject><text x="26" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">GIC PMR</text></switch></g><rect x="722.42" y="411" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(758.5,429.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="25" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 26px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS</div></div></foreignObject><text x="13" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS</text></switch></g><rect x="722.42" y="361" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(758.5,379.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="26" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 27px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>SPM</div></div></div></foreignObject><text x="13" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="722.42" y="311" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(736.5,329.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="69" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 70px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SDEI Critical</div></div></foreignObject><text x="35" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SDEI Critical</text></switch></g><rect x="722.42" y="261" width="100.02" height="50" fill="#fff2cc" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(735.5,279.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="71" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 72px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SDEI Normal</div></div></foreignObject><text x="36" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SDEI Normal</text></switch></g><rect x="722.42" y="61" width="100.02" height="200" fill="#f5f5f5" stroke="#666666" stroke-width="2" pointer-events="none"/><g transform="translate(737.5,154.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="67" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 68px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">NS priorities</div></div></foreignObject><text x="34" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">NS priorities</text></switch></g><path d="M 684.91 354.75 L 685 336 L 714.19 336" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 720.19 336 L 712.19 340 L 714.19 336 L 712.19 332 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 684.91 367.25 L 685 436 L 713.76 436" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 719.76 436 L 711.76 440 L 713.76 436 L 711.76 432 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="685" cy="361" rx="6.25" ry="6.25" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><path d="M 642.4 405 L 662 405 L 662 361 L 679 361" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 691 361 L 709 361 L 709 386 L 713.76 386" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 719.76 386 L 711.76 390 L 713.76 386 L 711.76 382 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(826.5,60.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="27" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 28px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">0xFF</div></div></foreignObject><text x="14" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">0xFF</text></switch></g><g transform="translate(826.5,449.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="20" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 21px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>0x0</div></div></div></foreignObject><text x="10" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><g transform="translate(642.5,312.5)rotate(-90,24,13.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="48" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 48px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Interrupt Priority</div></div></div></foreignObject><text x="24" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 864.28 347.38 L 844.11 293.71" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842 288.09 L 848.56 294.17 L 844.11 293.71 L 841.07 296.99 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 866 361.17 L 846.99 341.87" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842.78 337.59 L 851.24 340.49 L 846.99 341.87 L 845.54 346.1 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 866 361.17 L 847.03 380.17" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842.79 384.42 L 845.61 375.93 L 847.03 380.17 L 851.27 381.58 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 865.14 374.1 L 844.18 428.32" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 842.02 433.91 L 841.17 425.01 L 844.18 428.32 L 848.63 427.89 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 387.86 436 L 346.08 436" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 393.86 436 L 385.86 440 L 387.86 436 L 385.86 432 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="396.09" y="423.5" width="100.02" height="25" fill="#ffb570" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(419.5,429.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="52" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 53px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">EHF APIs</div></div></foreignObject><text x="26" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">EHF APIs</text></switch></g><path d="M 496.12 435.5 L 534.1 435.77" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 540.1 435.82 L 532.07 439.76 L 534.1 435.77 L 532.13 431.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(58.5,422.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="286" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 286px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Non-interrupt exceptions use EHF APIs to program GIC PMR to arbitrate priority levels</div></div></foreignObject><text x="143" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Non-interrupt exceptions use EHF APIs to program GIC PMR to arbitrate priority levels</text></switch></g><path d="M 940.24 461 L 940.24 69.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 940.24 63.24 L 944.24 71.24 L 940.24 69.24 L 936.24 71.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(871.5,254.5)rotate(-90,52,6)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="104" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 105px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Decreasing Priority</div></div></foreignObject><text x="52" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Decreasing Priority</text></switch></g><g transform="translate(820.5,348.5)rotate(-90,57.5,6)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="115" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 116px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Secure Priority levels</div></div></foreignObject><text x="58" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Secure Priority levels</text></switch></g><path d="M 685 355 L 685 286 L 713.76 286" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 719.76 286 L 711.76 290 L 713.76 286 L 711.76 282 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/></svg>
\ No newline at end of file
diff --git a/docs/resources/diagrams/draw.io/ehf.xml b/docs/resources/diagrams/draw.io/ehf.xml
new file mode 100644
index 0000000..db1f91d
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ehf.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0" version="9.4.6" editor="www.draw.io" type="device"><diagram id="5e4d6047-f7e8-a748-3faa-493b1a8db8b3" name="Page-1">7Vxbc9o4FP41PMaj++UxF2g703Yyzc5s++iCAt4azAiTkP31K2EbLMuAAzYhmaUzrX0k+XLu59Nxe/h2uvqkw/nkWzJScQ+B0aqH73oIIcCY+cdSXjIKhEBklLGORjltS3iI/lU5EeTUZTRSC2dimiRxGs1d4jCZzdQwdWih1smzO+0xid27zsOx8ggPwzD2qX9Ho3RSvAaT24HPKhpP8lsLxLOB3+Hwz1gny1l+vx7Cj+tfNjwNi2vlL7qYhKPkuUTC/R6+1UmSZkfT1a2KLXMLtmXrBjtGN8+t1SxtskDgbMVTGC9V8cjrB0tfCmasX0fZBaCHb54nUaoe5uHQjj4b+RvaJJ3G5gyaw0Wqkz8bppn3uXmM4vg2iRNtzmfJTG0mFUTDI7D+mRH/+fNXelI6VasSKX+fTyqZqlS/mCkb9ctWFLoH8vPnkiBBQZyUhEgL7Qtz7Rlvrr3loDnImVjPUOTx88ssVVov56khfwtnRnOm9uUQGOhwqp4T/cfj+AEeh4t5pvSP0crK5QDTDX/vSB8OaDv8hQQEABEuMCScUMmJw2/Eavnts3tDPIXdwue3x001MradnyY6nSTjZBbG/S31xtXwEqf/UWn6kruncJkmhrS9wtckme/UesNf/fIzv+L65Jc9CfYKYZEs9TB/6pyraajHqpiVu1X7QnslpVUcptGT68zq2JwvvU+itUbmEsZWwpxgIglBmEvoGpSoyC17xPwaW9Fdax2+lKbN7YTF3rtW7kMrmpBdcasXmzdupCqkRlNYbFh7M4qezOHYHpaNtRj+rYvRgmJuVVpTc5m/XuZq1+Sqd50k09/LxametWUjR9KoAIOScsEEIxI3sXHXLeCOTB7CGkFegsk3MmvkmzVp26obc9I3iZL+V1k6G13bzMqcDeNwsYiGLt/2ObxX8KrMGNSQMbnOGv0DEFWCv6entC7y57QT/WbFgeFqPpHpgecovetAigKKuBAQECAkct9JEh7QRh54e+FiYvL4uFDOnCMcaRGGSmrz/cH3a+1ljda3XffF4LYd30ZseJMSYkSFFFhIV2VqfBunATDhSHDMAJVE7Nagk8xRenx9uOp/hR+GtSiP6OdnbVETvM+YUZcKyrcKGsgPv/2vuGMdHQwG6PYsOkpqQsaZdLRVldwXjs+vrsW0liuXI0oMp7BxAyvB7RYcyMdWHu7vrOaEs1Gs9OI0oxmFi8l6biMLylGojrEXymBgC0ZhchgGMT4cWhuVDZzuVoTG5kXfcwgoci7HqPBFGBU1pSLEDAOOIQSbGF9fxZ+2+nST9FPX96QE8mKVgAEUMCwJoAgQwlzEqCiEdunAaxafrgJ+0dtfDdU8jZKZIX+2vjmajXv78NnLTW72O2CyLR1f64IhqhadRzlhfhH21xJW4eA6dfhF68jOcQ7aZD0QYQkpxxxJwfZlPa9cTQEOeMs4rehURxZGQqmPZK3Jgyg+kyvH+Bzq0tQssZ+pfvpiVoH7bz86dn53tC/uyNvmpfjIvJTCALXhFH2F/3F9IqC2K8S8Ql2bc5cTGGQbRRl/3Q1BWlNRN+JuGzW1D6nV7NY83H9rulnzTmVAjtXwFmSAfezt4a7/xVBudZRGwzD+OGx+Q1XHPi6Xs/l7oqcfiMlHe+s2mIw8JtutDzDXUWKVWZ2I6VRBG2r/1LLZC5ds/TuHAI6FcVAbu7/4XVfwea7tpH2Ff3zjKoGDii9rGQ3F3ab1b1j61Qm1yOm6btXhmAaQG2khwYkg1MVOKG62UXyqrtC2daUJVhvH0XyhDvvUBt1yLbhMJnnAGJJEQkmocYSuMdFNmex4zQ2o4mAtrUAtpC717aiM3rR1bmto0JJNltpO8rsYSukex8I1NZtUhdadv/6mfu52ab5RraL0ZzHPHHfjNVvf1d7hvxAyxioABAICJonb3Ua4GYUSEJ7/7V6+aRcPpySwli8QRVAKgFyXSfi+m7TlqJG5CwdYEIgFF7QC/bH9uPyB1S3vzVAfmAerwcAzBOOQ0zqQqdJjXtN2HsbReGZOh8p2uRmCde+2AL3OB6bRaBTvCimueXUSRAQmAQfb7TBXLyHFXgShJu120NmaeNIGRkXrIrIHpIAVaAikfGghgj1CpAS9nRDraqe9LdD3WV378q6kqpM0XO/m4bsr2ZmYGYMBEoAxCQmRwkOCUM1O27kEzZrkEwf6eZ32kiL6X9kqv5wCWAIp8oN7pSPzrFZ+rzWvgxH/PB28QuAAccYhYwwgyt1yihBmdxGwsWlCBDo2MRAMBMjkHZRxigmolApYNKvZjoiwrMHHXkepBTglKbwY0dN1/7iAQjCJqwWckZmps00ilMmfdiF60rBcP0b0dV+//C/6yxF9h1bfBDE9NhgAVpI/tBDwB4oFJDB1j5TSomySu51phOOgiANUsIKn7WpFU/zuCK3g3UIODbssDqE7TZGLA72wO1WtDEiwpuBDLpwr1I6eYWa8jwCUUISkyTGq2+cNdaCjj32YDyP2P5uiHFzff2l3s2swuKG8s3SdQMNliSRmAqDqN8uG80f2xbWRrfPW07ICx1t7aOKCeZzKgvD+fTQ1UoWQcyglBQTjqvskVSS9qV9eNwyVftS7sPBHO/DSPuzyPZldRaUSXRXNq8YawXKhzN9lAwXGadr96WSsw6k5KvV1ZUOh/h2lOkxVb7ONbeUXqycV+wZ+GRV+N10HPKAlD1HpEat3EUiYRRxaPSRCEsY7Kuj5sTlc3TZNNUyX4u02+p4SVS/EOUgqA4QpwVICIFglgaOs0o3Q1DXsvyysXrZFZ+DvoN+poVbhIutX34J1F2m054HljEACyZDddMk+oHakg+sb4C0uhznkhCMIhWQdGXHN971quNTKkd1le94zCdE4290QukmRN32355eiaIKkXFofywat2ezl/sqX7pTWwbalbj7prNlGhQEt/SqZOzFpfXm4kfM9td8F79v69FdDHEi4szWEM6+LfEcoOhwzzOn2/w7Lpm//hzbc/w8=</diagram></mxfile>
\ No newline at end of file
diff --git a/docs/resources/diagrams/draw.io/ras.svg b/docs/resources/diagrams/draw.io/ras.svg
new file mode 100644
index 0000000..ff58198
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ras.svg
@@ -0,0 +1,2 @@
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1050px" height="392px" viewBox="-0.5 -0.5 1050 392" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0&quot; version=&quot;9.4.6&quot; editor=&quot;www.draw.io&quot; type=&quot;device&quot;&gt;&lt;diagram id=&quot;f2d74f7d-2b47-d0f0-3260-3a0b726db48c&quot; name=&quot;Page-1&quot;&gt;5VtLc6M4EP41rto9rAs9eB2TjD0zVbtVqclhd05TipFtNhhRQk7i/fUrQGBAECsJYGcml0Ajgfi6++tWN56hm93zZ06S7V8soNEMWsHzDH2aQQgtx5H/MsmhkABgeYVkw8NAyY6Cu/A/qoSWku7DgKaNgYKxSIRJU7hicUxXoiEjnLOn5rA1i5pPTciGaoK7FYl06d9hILblazj+8cIXGm626tEedIsL92T1sOFsH6vnzSBa53/F5R0p76VeNN2SgD3VRGgxQzecMVEc7Z5vaJSBW8JWzFv2XK3WzWksjCaoGY8k2tNyyfnCxKEEI38dmk2wZuj6aRsKepeQVXb1SepfyrZiF8kzIA9TwdlDBZp8n+t1GEU3LGJcnscsltOuA5Ju8xtmM/Qll2uiXNDnmki9wmfKdlTwgxyirmKs4CztrYT36ag8WI7Z1vSGHCUkymA21b2PoMkDhVsPhug0hjSQ9qVOGRdbtmExiRZH6XUT5Rqi/1IhDspFyF4wKTre4U/Gkl7ke5FN2Z6v1MrUWgXhG1qiUoiyNb+IPqcREeFj02e6kFRTb1koF1JpDcGW1ryWMoo1qVktfVTLMFIRxh0qciKR2WL4KA83IserEN3ztkTevzFuOO2m8iXFVUZZUrCKSJqGq1K8DKNyGI2DcpDyISlR163JjGRsi2i78XgGATV7SOTKf1DyY0viIKL8t9/H5EEZFj7hBVjaw/AfaHuSo/NfNabOf3gA+kMGIWQoB1G2X/eOCawf6RRZDhvOI4zh1tDmJP2ohos9A8N1RjJcaH/kuI07jHJwmjaFUg+vmVFKmqac7xMxmW0ulwvb98exTeT7c3s668R6iDpD3vF2Iz6VsRgZuT1N3oH8uef6wIPAdgCSim4oHgNnXq5k+ExEJ6HF84omImSxFH/JHCeMN/JwycmOPjH+MJUPFSNrV6z8b6CUBTQx97yms3UFAsuaWxC7HgLYxbbvIt3zAIBzu1/9ps7nGPheFIVJSk8DTtKkKFGsw+dMSa8hfHM8oY3mwIE+9oGPbey6TgtPt7LhRlJYotUAcRAM3en4651poUSdH/5Rk/KT79nJ3DagsTdGb1uP3s65gje41DzoJb0YoezrKONRIoo0EXKoDUiywJD2Bxzc2rBhG9Y1dnp8s6wnD4oVvDUI+R0WoJVHvl3d9dVDtLEJDxkPRYZJRB/z8rDKAd9cZHlVlHs5ptWNbNQoJ2829yGq4hxuadHryigNwpw9RNnSugi3f8nJX0GudR/3p8kaoY/mjpur0cUetkHLpUE7ivYkja8lD+i0NyatGv+J8TI96CeP009rF+UKwh2kKNdFQ8NZZKPrkJ3cEiE3qHEugRZ8V6wy3E8ZhS3g6TYNBjdq44LTuDxxAfW9LrzPV+ArV1PDO4+8FpUg8fyJK8aD9H0BctJSiguaHFIVSCYp83X1fi4rvVU7jTL2GdttR35bvtzYwc/1W0GlrarhKiRADwuFQ1T1xXSWt/3J4QP7BOroWY/nEzqnF5Cue4tM8rVEF1yt1n5Ht59E4SYLsiua6UsKMpDCFYmu1IVdGARRXyWlqcEBgG/XdX1D3OEAuCOTwtJAGc4FBNau5BwNXtM1NvquRmWx9QzLXedXaaFE0OxJcZC9IGf3tLZBDYfZnk7aZGszzaRNNtRR31Z5TFUQGA9JZfYDgOibtNhHA1FPCX9q2oAdtOGejTbgadq4DtOsxl+yRsTYwz45A22MmqBM2/9Eev/gpyCOqWEcd/czLluYfSfa+FSngzrKDfUZSic6ddwtvuVajhLKx97Cj/mlzqRbeGRQGHxze6CyWvPOwNDfL7/cJkCup0M9UZMA6xvFXwl5eEbkuz4MycrVJBt1dS8pVNPEZezRh9ZRqwEBbJ15ur7tH2K/jrv261qz82tZhzLsZP6carJbX5z4eDo16bliTSfWbdWM/iUUkX3OZjd10RGsR9PFhE28KfaqrazxLb+nsV9U1x/WHMCmvkqGe2eN3sa4ZQie39JwT/NWu5UD27eyDQv+r+1uA7c70exb2Ynxfd3tcjlsvU7pu7/h1LOkxZdlFqZvv+pJ/sWyjkYxHcbea8bAhU09uKNxjjw9/kKyUNfxd6ho8T8=&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><rect x="408" y="30" width="240" height="360" fill="none" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><path d="M 208 90 L 439.76 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 445.76 90 L 437.76 94 L 439.76 90 L 437.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 79.76 90 L 8 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 85.76 90 L 77.76 94 L 79.76 90 L 77.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(47.5,84.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="1" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;background-color:#ffffff;"><div><br /></div></div></div></foreignObject><text x="0" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">&lt;div&gt;&lt;br&gt;&lt;/div&gt;</text></switch></g><rect x="88" y="70" width="120" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(98.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="98" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 99px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">plat_ea_handler()</div></div></foreignObject><text x="49" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">plat_ea_handler()</text></switch></g><path d="M 608 90 L 669.76 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 675.76 90 L 667.76 94 L 669.76 90 L 667.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="448" y="70" width="160" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(479.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 96px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">ras_ea_handler()</div></div></foreignObject><text x="48" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">ras_ea_handler()</text></switch></g><path d="M 608 329.5 L 669.76 329.5" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 675.76 329.5 L 667.76 333.5 L 669.76 329.5 L 667.76 325.5 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="448" y="309.5" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(464.5,322.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="126" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 127px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">ras_interrupt_handler()</div></div></foreignObject><text x="63" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">ras_interrupt_handler()</text></switch></g><path d="M 79.64 326 L 48 326 L 7.88 326.25" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 85.64 326 L 77.64 330 L 79.64 326 L 77.64 322 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="87.88" y="270" width="100.02" height="112.5" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(89.5,304.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Exception Handling Framework</div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Exception Handling Framework</text></switch></g><ellipse cx="227" cy="284" rx="6.25" ry="6.25" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><path d="M 187.9 326 L 208 326 L 208 284 L 221 284" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 368.95 362 L 388 362 L 388 330 L 439.76 330" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 445.76 330 L 437.76 334 L 439.76 330 L 437.76 326 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="268.92" y="338.5" width="100.02" height="50" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(270.5,342.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="95" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 95px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>RAS</div><div>priority level handler<br /></div></div></div></foreignObject><text x="48" y="27" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 228 290 L 228 300 L 228 364 L 260.76 364" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 266.76 364 L 258.76 368 L 260.76 364 L 258.76 360 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 198.24 L 758 221.76" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="2 4" pointer-events="none"/><path d="M 758 192.24 L 762 200.24 L 758 198.24 L 754 200.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 227.76 L 754 219.76 L 758 221.76 L 762 219.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 150 L 758 118.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 112.24 L 762 120.24 L 758 118.24 L 754 120.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="150" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(708.5,163.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="98" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 99px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS error records</div></div></foreignObject><text x="49" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS error records</text></switch></g><path d="M 758 270 L 758 290 L 758 301.76" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 758 307.76 L 754 299.76 L 758 301.76 L 762 299.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="230" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(702.5,243.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="110" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 111px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS interrupts array</div></div></foreignObject><text x="55" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS interrupts array</text></switch></g><g transform="translate(485.5,3.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="85" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 86px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RAS framework</div></div></foreignObject><text x="43" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RAS framework</text></switch></g><path d="M 838 90 L 879.76 90" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 885.76 90 L 877.76 94 L 879.76 90 L 877.76 86 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="70" width="160" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(710.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="93" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 94px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><i>Iterate and probe</i></div></div></foreignObject><text x="47" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">&lt;i&gt;Iterate and probe&lt;/i&gt;</text></switch></g><rect x="888" y="70" width="160" height="40" fill="none" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(931.5,83.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="72" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 73px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Error handler</div></div></foreignObject><text x="36" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Error handler</text></switch></g><path d="M 838 329.5 L 879.76 329.5" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 885.76 329.5 L 877.76 333.5 L 879.76 329.5 L 877.76 325.5 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="678" y="309.5" width="160" height="40" fill="#ffe599" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(708.5,322.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="97" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 98px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><i>Bisect and lookup</i></div></div></foreignObject><text x="49" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">&lt;i&gt;Bisect and lookup&lt;/i&gt;</text></switch></g><rect x="888" y="309.5" width="160" height="40" fill="none" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(931.5,322.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="72" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 73px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Error handler</div></div></foreignObject><text x="36" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Error handler</text></switch></g><path d="M 608 170 L 669.76 170" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 675.76 170 L 667.76 174 L 669.76 170 L 667.76 166 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><rect x="448" y="150" width="160" height="40" fill="#d4e1f5" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(492.5,163.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="69" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 70px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">SER helpers</div></div></foreignObject><text x="35" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">SER helpers</text></switch></g><rect x="268.92" y="288" width="100.02" height="50" fill="none" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><rect x="268.92" y="238" width="100.02" height="50" fill="none" stroke="#000000" stroke-width="2" stroke-dasharray="6 6" pointer-events="none"/><g transform="translate(24.5,56.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="46" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">External Abort</div></div></foreignObject><text x="23" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">External Abort</text></switch></g><g transform="translate(21.5,307.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Interrupt</div></div></div></foreignObject><text x="23" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><g transform="translate(204.5,246.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="46" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Interrupt Priority</div></div></foreignObject><text x="23" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Interrupt Priority</text></switch></g><path d="M 138 110 L 138 150 L 138 261.76" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><path d="M 138 267.76 L 134 259.76 L 138 261.76 L 142 259.76 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(140.5,176.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="38" height="27" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 38px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">EHF APIs</div></div></foreignObject><text x="19" y="20" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">EHF APIs</text></switch></g></svg>
\ No newline at end of file
diff --git a/docs/resources/diagrams/draw.io/ras.xml b/docs/resources/diagrams/draw.io/ras.xml
new file mode 100644
index 0000000..ce6df3a
--- /dev/null
+++ b/docs/resources/diagrams/draw.io/ras.xml
@@ -0,0 +1 @@
+<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0" version="9.4.6" editor="www.draw.io" type="device"><diagram id="f2d74f7d-2b47-d0f0-3260-3a0b726db48c" name="Page-1">5VtLc6M4EP41rto9rAs9eB2TjD0zVbtVqclhd05TipFtNhhRQk7i/fUrQGBAECsJYGcml0Ajgfi6++tWN56hm93zZ06S7V8soNEMWsHzDH2aQQgtx5H/MsmhkABgeYVkw8NAyY6Cu/A/qoSWku7DgKaNgYKxSIRJU7hicUxXoiEjnLOn5rA1i5pPTciGaoK7FYl06d9hILblazj+8cIXGm626tEedIsL92T1sOFsH6vnzSBa53/F5R0p76VeNN2SgD3VRGgxQzecMVEc7Z5vaJSBW8JWzFv2XK3WzWksjCaoGY8k2tNyyfnCxKEEI38dmk2wZuj6aRsKepeQVXb1SepfyrZiF8kzIA9TwdlDBZp8n+t1GEU3LGJcnscsltOuA5Ju8xtmM/Qll2uiXNDnmki9wmfKdlTwgxyirmKs4CztrYT36ag8WI7Z1vSGHCUkymA21b2PoMkDhVsPhug0hjSQ9qVOGRdbtmExiRZH6XUT5Rqi/1IhDspFyF4wKTre4U/Gkl7ke5FN2Z6v1MrUWgXhG1qiUoiyNb+IPqcREeFj02e6kFRTb1koF1JpDcGW1ryWMoo1qVktfVTLMFIRxh0qciKR2WL4KA83IserEN3ztkTevzFuOO2m8iXFVUZZUrCKSJqGq1K8DKNyGI2DcpDyISlR163JjGRsi2i78XgGATV7SOTKf1DyY0viIKL8t9/H5EEZFj7hBVjaw/AfaHuSo/NfNabOf3gA+kMGIWQoB1G2X/eOCawf6RRZDhvOI4zh1tDmJP2ohos9A8N1RjJcaH/kuI07jHJwmjaFUg+vmVFKmqac7xMxmW0ulwvb98exTeT7c3s668R6iDpD3vF2Iz6VsRgZuT1N3oH8uef6wIPAdgCSim4oHgNnXq5k+ExEJ6HF84omImSxFH/JHCeMN/JwycmOPjH+MJUPFSNrV6z8b6CUBTQx97yms3UFAsuaWxC7HgLYxbbvIt3zAIBzu1/9ps7nGPheFIVJSk8DTtKkKFGsw+dMSa8hfHM8oY3mwIE+9oGPbey6TgtPt7LhRlJYotUAcRAM3en4651poUSdH/5Rk/KT79nJ3DagsTdGb1uP3s65gje41DzoJb0YoezrKONRIoo0EXKoDUiywJD2Bxzc2rBhG9Y1dnp8s6wnD4oVvDUI+R0WoJVHvl3d9dVDtLEJDxkPRYZJRB/z8rDKAd9cZHlVlHs5ptWNbNQoJ2829yGq4hxuadHryigNwpw9RNnSugi3f8nJX0GudR/3p8kaoY/mjpur0cUetkHLpUE7ivYkja8lD+i0NyatGv+J8TI96CeP009rF+UKwh2kKNdFQ8NZZKPrkJ3cEiE3qHEugRZ8V6wy3E8ZhS3g6TYNBjdq44LTuDxxAfW9LrzPV+ArV1PDO4+8FpUg8fyJK8aD9H0BctJSiguaHFIVSCYp83X1fi4rvVU7jTL2GdttR35bvtzYwc/1W0GlrarhKiRADwuFQ1T1xXSWt/3J4QP7BOroWY/nEzqnF5Cue4tM8rVEF1yt1n5Ht59E4SYLsiua6UsKMpDCFYmu1IVdGARRXyWlqcEBgG/XdX1D3OEAuCOTwtJAGc4FBNau5BwNXtM1NvquRmWx9QzLXedXaaFE0OxJcZC9IGf3tLZBDYfZnk7aZGszzaRNNtRR31Z5TFUQGA9JZfYDgOibtNhHA1FPCX9q2oAdtOGejTbgadq4DtOsxl+yRsTYwz45A22MmqBM2/9Eev/gpyCOqWEcd/czLluYfSfa+FSngzrKDfUZSic6ddwtvuVajhLKx97Cj/mlzqRbeGRQGHxze6CyWvPOwNDfL7/cJkCup0M9UZMA6xvFXwl5eEbkuz4MycrVJBt1dS8pVNPEZezRh9ZRqwEBbJ15ur7tH2K/jrv261qz82tZhzLsZP6carJbX5z4eDo16bliTSfWbdWM/iUUkX3OZjd10RGsR9PFhE28KfaqrazxLb+nsV9U1x/WHMCmvkqGe2eN3sa4ZQie39JwT/NWu5UD27eyDQv+r+1uA7c70exb2Ynxfd3tcjlsvU7pu7/h1LOkxZdlFqZvv+pJ/sWyjkYxHcbea8bAhU09uKNxjjw9/kKyUNfxd6ho8T8=</diagram></mxfile>
\ No newline at end of file
diff --git a/docs/resources/diagrams/fwu_flow.png b/docs/resources/diagrams/fwu_flow.png
new file mode 100644
index 0000000..534095f
--- /dev/null
+++ b/docs/resources/diagrams/fwu_flow.png
Binary files differ
diff --git a/docs/resources/diagrams/fwu_states.png b/docs/resources/diagrams/fwu_states.png
new file mode 100644
index 0000000..fda4d8f
--- /dev/null
+++ b/docs/resources/diagrams/fwu_states.png
Binary files differ
diff --git a/docs/resources/diagrams/int_handling.dia b/docs/resources/diagrams/int_handling.dia
new file mode 100644
index 0000000..12aa186
--- /dev/null
+++ b/docs/resources/diagrams/int_handling.dia
Binary files differ
diff --git a/docs/resources/diagrams/non-sec-int-handling.png b/docs/resources/diagrams/non-sec-int-handling.png
new file mode 100644
index 0000000..64082c9
--- /dev/null
+++ b/docs/resources/diagrams/non-sec-int-handling.png
Binary files differ
diff --git a/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml b/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml
new file mode 100644
index 0000000..53594c2
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml
@@ -0,0 +1,109 @@
+@startuml
+
+package arm_io_storage {
+
+	class plat_io_policy {
+		dev_handle : uintptr_t*
+		image_spec : uintptr_t
+		{abstract} check() : fctptr
+	}
+
+	class FIP_IMAGE_ID {
+		memmap_dev_handle
+		fip_block_spec
+		open_memmap()
+	}
+
+	class BL2_IMAGE_ID{
+		fip_dev_handle
+		bl2_uuid_spec
+		open_fip()
+	}
+
+	class xxx_IMAGE_ID{
+		fip_dev_handle
+		xxx_uuid_spec
+		open_fip()
+	}
+
+	class arm_io_storage {
+		fip_dev_con : io_dev_connector_t*
+		fip_dev_handle : uintptr_t
+		memmap_dev_con : io_dev_connector_t*
+		memmap_dev_handle : uintptr_t
+
+		fip_block_spec : io_block_spec_t
+
+		policies : plat_io_policy[1..*]
+
+		-open_fip()
+		-open_memmap()
+
+		+arm_io_setup()
+		+plat_get_image_source()
+	}
+
+	FIP_IMAGE_ID -up-|> plat_io_policy
+	BL2_IMAGE_ID -up-|> plat_io_policy
+	xxx_IMAGE_ID -up-|> plat_io_policy
+
+	arm_io_storage *-"1..*" plat_io_policy
+}
+
+package IO {
+	class  io_storage {
+		io_dev_open()
+		io_dev_init()
+		io_dev_close()
+
+		.. synchronous operations ..
+		io_open()
+		io_seek()
+		io_size()
+		io_read()
+		io_write()
+		io_close()
+
+		io_register_device()
+	}
+
+	class io_fip {
+		register_io_dev_fip()
+		.. io_dev_funcs_t interface ..
+		fip_dev_funcs : io_dev_funcs_t
+	}
+
+	class io_memmap {
+		register_io_dev_memmap()
+		.. io_dev_funcs_t interface ..
+		memmap_dev_funcs : io_dev_funcs_t
+	}
+
+	interface io_driver {
+		io_entity_t
+		io_dev_info_t
+
+		.. io_dev_connector_t interface ..
+		dev_open()
+
+		.. io_dev_funcs_t interface ..
+			type()
+			open()
+			seek()
+			size()
+			read()
+			write()
+			close()
+			dev_init()
+			dev_close()
+
+		io_register_device()
+	}
+}
+arm_io_storage .. io_driver
+arm_io_storage .. io_fip
+arm_io_storage .. io_memmap
+arm_io_storage .. io_storage
+
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml b/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
new file mode 100644
index 0000000..2752b33
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml
@@ -0,0 +1,62 @@
+@startuml
+
+participant arm_io_storage order 1
+participant io_storage order 2
+
+ -> arm_io_storage : plat_get_image_source(image_id, &dev_handle, &image_spec)
+
+group init and check device (image_id)
+
+alt image_id = BL2_IMAGE_ID
+note over arm_io_storage
+	get BL2_IMAGE_ID policy:
+	- fip_dev_handle
+	- open_fip()
+end note
+opt policy->check()
+	arm_io_storage -> arm_io_storage : open_fip(spec)
+	activate arm_io_storage
+	arm_io_storage -> io_storage : io_dev_init(fip_dev_handle, FIP_IMAGE_ID)
+	ref over io_storage : dev_init() on fip device
+
+	arm_io_storage -> io_storage : io_open(fip_dev_handle, spec, &local_image_handle)
+	ref over io_storage : io_open() on fip device
+
+	arm_io_storage -> io_storage : io_close(local_image_handle)
+	ref over io_storage : io_close() on fip device
+
+	hnote over arm_io_storage
+		fip_dev_handle ready
+	end note
+end opt
+deactivate arm_io_storage
+
+else image_id = FIP_IMAGE_ID
+activate arm_io_storage
+note over arm_io_storage
+	get FIP_IMAGE_ID policy:
+	- memmap_dev_handle
+	- open_memmap()
+end note
+opt policy->check()
+	arm_io_storage -> arm_io_storage : open_memmap(spec)
+	activate arm_io_storage
+	arm_io_storage -> io_storage : io_dev_init(memmap_dev_handle, NULL)
+	ref over io_storage : dev_init() on memmap device
+
+	arm_io_storage -> io_storage : io_open(memmap_dev_handle, spec, &local_image_handle)
+	ref over io_storage : io_open() on memmap device
+
+	arm_io_storage -> io_storage : io_close(local_image_handle)
+	ref over io_storage : io_close() on memmap device
+
+	hnote over arm_io_storage
+		memmap_dev_handle ready
+	end note
+	deactivate arm_io_storage
+end  opt
+deactivate arm_io_storage
+end alt
+
+end group
+@enduml
diff --git a/docs/resources/diagrams/plantuml/io_dev_registration.puml b/docs/resources/diagrams/plantuml/io_dev_registration.puml
new file mode 100644
index 0000000..114c3b7
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_dev_registration.puml
@@ -0,0 +1,52 @@
+@startuml
+
+participant arm_io_storage order 1
+participant io_storage order 2
+participant io_fip order 3
+participant io_memmap order 4
+
+ -> arm_io_storage : arm_io_setup()
+
+group io dev registration
+
+arm_io_storage -> io_fip : register_io_dev_fip(&fip_dev_con)
+io_fip -> io_storage : io_register_device(&dev_info_pool[])
+note over io_storage
+	devices[dev_count] = (fip_)dev_info_pool
+	dev_count++
+end note
+
+arm_io_storage -> io_memmap : register_io_dev_memmap(&memmap_dev_con)
+io_memmap -> io_storage : io_register_device(&memmap_dev_info)
+note over io_storage
+	devices[dev_count] = memmap_dev_info
+	dev_count++
+end note
+
+arm_io_storage -> io_storage : io_dev_open(fip_dev_con, NULL, fip_dev_handle)
+ io_storage -> io_storage : dev_open(dev_con, dev_spec, handle)
+activate io_storage
+opt dev_open() on fip device
+	io_storage -> io_fip : fip_dev_open(dev_spec, dev_info)
+	note over io_fip
+		dev_info = one of the
+		"fip_dev_info" from
+		dev_info_pool[]
+	end note
+end opt
+deactivate io_storage
+
+
+arm_io_storage -> io_storage : io_dev_open(memmap_dev_con, NULL, memmap_dev_handle)
+io_storage -> io_storage : dev_open(dev_con, dev_spec, handle)
+activate io_storage
+opt dev_open() on memmap device
+	io_storage -> io_memmap : memmap_dev_open(dev_spec, dev_info)
+	note over io_memmap
+		dev_info = memmap_dev_info
+	end note
+end opt
+deactivate io_storage
+
+end group
+@enduml
diff --git a/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml b/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
new file mode 100644
index 0000000..eb3e2b4
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml
@@ -0,0 +1,59 @@
+@startuml
+
+participant bl_common order 1
+participant arm_io_storage order 2
+participant io_storage order 3
+
+== Platform Setup ==
+
+bl1_main -> xxx_bl1_setup : bl1_platform_setup()
+xxx_bl1_setup -> arm_io_storage : plat_arm_io_setup()
+
+arm_io_storage -> arm_io_storage : arm_io_setup()
+ref over arm_io_storage, io_storage : io device registration
+
+== Get Image ==
+bl1_main -> xxx_bl1_setup : bl1_plat_get_next_image_id()
+bl1_main <-- xxx_bl1_setup : BL2_IMAGE_ID
+
+bl1_main -> bl1_main : bl1_load_bl2()
+activate bl1_main
+bl1_main -> plat_bl1_common : bl1_plat_get_image_desc(BL2_IMAGE_ID)
+bl1_main <-- plat_bl1_common : BL2_IMAGE_DESC
+
+bl1_main -> plat_bl1_common : bl1_plat_handle_pre_image_load(BL2_IMAGE_ID)
+
+bl1_main -> bl_common : load_auth_image(BL2_IMAGE_ID, image_info)
+activate bl_common
+bl_common -> bl_common : load_auth_image_internal(BL2_IMAGE_ID, image_info, is_parent_image)
+activate bl_common
+bl_common -> bl_common : load_image(BL2_IMAGE_ID, image_info)
+activate bl_common
+bl_common -> arm_io_storage : plat_get_image_source(BL2_IMAGE_ID, &dev_handle, &image_spec)
+ref over arm_io_storage, io_storage : init and check device (BL2_IMAGE_ID)
+bl_common <-- arm_io_storage : dev_handle
+
+bl_common -> io_storage : io_open(dev_handle, image_spec, &image_handle)
+ref over io_storage : io_open() on fip device
+bl_common <-- io_storage : image_handle
+bl_common -> io_storage : io_size(image_handle, &image_size)
+ref over io_storage : io_size() on fip device
+bl_common -> io_storage : io_read(image_handle, image_base, image_size, &bytes_read)
+ref over io_storage : io_read() on fip device
+bl_common -> io_storage : io_close(image_handle)
+ref over io_storage : io_close() on fip device
+bl_common -> io_storage : io_dev_close(dev_handle)
+ref over io_storage : io_dev_close() on fip device
+
+deactivate bl_common
+deactivate bl_common
+deactivate bl_common
+
+== Prepare Next Image ==
+bl1_main -> plat_bl1_common : bl1_plat_handle_post_image_load(BL2_IMAGE_ID)
+
+deactivate bl1_main
+
+== Jump to next Image ==
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml b/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml
new file mode 100644
index 0000000..90ff23c
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml
@@ -0,0 +1,51 @@
+/'
+ ' Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+autonumber "<b>[#]</b>"
+participant "SDEI client" as EL2
+participant EL3
+participant SDEI
+participant "RAS Driver" as RAS
+
+activate EL2
+EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)
+EL3->EL2: success
+EL2->EL3: **SDEI_EVENT_ENABLE**(ev)
+EL3->EL2: success
+EL2->EL3: **SDEI_PE_UNMASK**()
+EL3->EL2: 1
+
+... <<Business as usual>> ...
+
+EL3<--]: **CRITICAL EVENT**
+activate EL3 #red
+note over EL3: Critical event triage
+EL3->RAS: dispatch to handle
+deactivate EL3
+activate RAS #salmon
+note over RAS: Critical event handling
+RAS-->SDEI: sdei_dispatch_event(ev)
+deactivate RAS
+activate SDEI #salmon
+note over SDEI: Prepare SDEI dispatch
+SDEI->EL2: dispatch
+activate EL2 #salmon
+note over EL2: SDEI handler
+EL2->SDEI: **SDEI_EVENT_COMPLETE()**
+deactivate EL2
+note over SDEI: Complete SDEI dispatch
+SDEI-->RAS: return
+deactivate SDEI
+activate RAS #salmon
+RAS->EL3: error handling done
+deactivate RAS
+EL3->EL2: resumes preempted execution
+
+... <<Normal execution resumes>> ...
+
+@enduml
diff --git a/docs/resources/diagrams/plantuml/sdei_general.puml b/docs/resources/diagrams/plantuml/sdei_general.puml
new file mode 100644
index 0000000..ab6929a
--- /dev/null
+++ b/docs/resources/diagrams/plantuml/sdei_general.puml
@@ -0,0 +1,43 @@
+/'
+ ' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ '
+ ' SPDX-License-Identifier: BSD-3-Clause
+ '/
+
+@startuml
+
+autonumber "<b>[#]</b>"
+participant "SDEI client" as EL2
+participant EL3
+participant "SDEI interrupt source" as SDEI
+
+activate EL2
+EL2->EL3: **SDEI_INTERRUPT_BIND**(irq)
+EL3->EL2: event number: ev
+EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...)
+EL3->EL2: success
+EL2->EL3: **SDEI_EVENT_ENABLE**(ev)
+EL3->EL2: success
+EL2->EL3: **SDEI_PE_UNMASK**()
+EL3->EL2: 1
+
+... <<Business as usual>> ...
+
+SDEI-->EL3: SDEI interrupt
+activate SDEI #salmon
+activate EL3 #red
+note over EL3: Prepare SDEI dispatch
+EL3->EL2: dispatch
+activate EL2 #salmon
+note over EL2: SDEI handler
+EL2->EL3: **SDEI_EVENT_COMPLETE()**
+deactivate EL2
+note over EL3: Complete SDEI dispatch
+EL3-->SDEI: EOI
+deactivate SDEI
+EL3->EL2: resumes preempted execution
+deactivate EL3
+
+... <<Normal execution resumes>> ...
+
+@enduml
diff --git a/docs/resources/diagrams/psci-suspend-sequence.png b/docs/resources/diagrams/psci-suspend-sequence.png
new file mode 100644
index 0000000..1703ea6
--- /dev/null
+++ b/docs/resources/diagrams/psci-suspend-sequence.png
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_flow.dia b/docs/resources/diagrams/reset_code_flow.dia
new file mode 100644
index 0000000..133c9cf
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_flow.dia
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_no_boot_type_check.png b/docs/resources/diagrams/reset_code_no_boot_type_check.png
new file mode 100644
index 0000000..23e865f
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_no_boot_type_check.png
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_no_checks.png b/docs/resources/diagrams/reset_code_no_checks.png
new file mode 100644
index 0000000..26a179b
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_no_checks.png
Binary files differ
diff --git a/docs/resources/diagrams/reset_code_no_cpu_check.png b/docs/resources/diagrams/reset_code_no_cpu_check.png
new file mode 100644
index 0000000..4150dbe
--- /dev/null
+++ b/docs/resources/diagrams/reset_code_no_cpu_check.png
Binary files differ
diff --git a/docs/resources/diagrams/romlib_design.dia b/docs/resources/diagrams/romlib_design.dia
new file mode 100644
index 0000000..d12eec0
--- /dev/null
+++ b/docs/resources/diagrams/romlib_design.dia
Binary files differ
diff --git a/docs/resources/diagrams/romlib_design.png b/docs/resources/diagrams/romlib_design.png
new file mode 100644
index 0000000..bfffcde
--- /dev/null
+++ b/docs/resources/diagrams/romlib_design.png
Binary files differ
diff --git a/docs/resources/diagrams/romlib_wrapper.dia b/docs/resources/diagrams/romlib_wrapper.dia
new file mode 100644
index 0000000..30cfbd8
--- /dev/null
+++ b/docs/resources/diagrams/romlib_wrapper.dia
Binary files differ
diff --git a/docs/resources/diagrams/romlib_wrapper.png b/docs/resources/diagrams/romlib_wrapper.png
new file mode 100644
index 0000000..ec3a441
--- /dev/null
+++ b/docs/resources/diagrams/romlib_wrapper.png
Binary files differ
diff --git a/docs/resources/diagrams/rt-svc-descs-layout.png b/docs/resources/diagrams/rt-svc-descs-layout.png
new file mode 100644
index 0000000..1a9fa5b
--- /dev/null
+++ b/docs/resources/diagrams/rt-svc-descs-layout.png
Binary files differ
diff --git a/docs/resources/diagrams/sec-int-handling.png b/docs/resources/diagrams/sec-int-handling.png
new file mode 100644
index 0000000..fa5c340
--- /dev/null
+++ b/docs/resources/diagrams/sec-int-handling.png
Binary files differ
diff --git a/docs/resources/diagrams/secure_sw_stack_sp.png b/docs/resources/diagrams/secure_sw_stack_sp.png
new file mode 100644
index 0000000..5cb2ca7
--- /dev/null
+++ b/docs/resources/diagrams/secure_sw_stack_sp.png
Binary files differ
diff --git a/docs/resources/diagrams/secure_sw_stack_tos.png b/docs/resources/diagrams/secure_sw_stack_tos.png
new file mode 100644
index 0000000..1f2d555
--- /dev/null
+++ b/docs/resources/diagrams/secure_sw_stack_tos.png
Binary files differ
diff --git a/docs/resources/diagrams/xlat_align.dia b/docs/resources/diagrams/xlat_align.dia
new file mode 100644
index 0000000..bd88c0c
--- /dev/null
+++ b/docs/resources/diagrams/xlat_align.dia
Binary files differ
diff --git a/docs/resources/diagrams/xlat_align.png b/docs/resources/diagrams/xlat_align.png
new file mode 100644
index 0000000..cffd3c1
--- /dev/null
+++ b/docs/resources/diagrams/xlat_align.png
Binary files differ
diff --git a/docs/security_advisories/index.rst b/docs/security_advisories/index.rst
new file mode 100644
index 0000000..ce2c843
--- /dev/null
+++ b/docs/security_advisories/index.rst
@@ -0,0 +1,16 @@
+Security Advisories
+===================
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents
+   :numbered:
+
+   security-advisory-tfv-1.rst
+   security-advisory-tfv-2.rst
+   security-advisory-tfv-3.rst
+   security-advisory-tfv-4.rst
+   security-advisory-tfv-5.rst
+   security-advisory-tfv-6.rst
+   security-advisory-tfv-7.rst
+   security-advisory-tfv-8.rst
diff --git a/docs/security_advisories/security-advisory-tfv-1.rst b/docs/security_advisories/security-advisory-tfv-1.rst
new file mode 100644
index 0000000..9d58d08
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-1.rst
@@ -0,0 +1,162 @@
+Advisory TFV-1 (CVE-2016-10319)
+===============================
+
++----------------+-------------------------------------------------------------+
+| Title          | Malformed Firmware Update SMC can result in copy of         |
+|                | unexpectedly large data into secure memory                  |
++================+=============================================================+
+| CVE ID         | `CVE-2016-10319`_                                           |
++----------------+-------------------------------------------------------------+
+| Date           | 18 Oct 2016                                                 |
++----------------+-------------------------------------------------------------+
+| Versions       | v1.2 and v1.3 (since commit `48bfb88`_)                     |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | Platforms that use AArch64 BL1 plus untrusted normal world  |
+| Affected       | firmware update code executing before BL31                  |
++----------------+-------------------------------------------------------------+
+| Impact         | Copy of unexpectedly large data into the free secure memory |
+|                | reported by BL1 platform code                               |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #783`_                                        |
++----------------+-------------------------------------------------------------+
+| Credit         | IOActive                                                    |
++----------------+-------------------------------------------------------------+
+
+Generic Trusted Firmware (TF) BL1 code contains an SMC interface that is briefly
+available after cold reset to support the Firmware Update (FWU) feature (also
+known as recovery mode). This allows most FWU functionality to be implemented in
+the normal world, while retaining the essential image authentication
+functionality in BL1. When cold boot reaches the EL3 Runtime Software (for
+example, BL31 on AArch64 systems), the FWU SMC interface is replaced by the EL3
+Runtime SMC interface. Platforms may choose how much of this FWU functionality
+to use, if any.
+
+The BL1 FWU SMC handling code, currently only supported on AArch64, contains
+several vulnerabilities that may be exploited when *all* the following
+conditions apply:
+
+1. Platform code uses TF BL1 with the ``TRUSTED_BOARD_BOOT`` build option
+   enabled.
+
+2. Platform code arranges for untrusted normal world FWU code to be executed in
+   the cold boot path, before BL31 starts. Untrusted in this sense means code
+   that is not in ROM or has not been authenticated or has otherwise been
+   executed by an attacker.
+
+3. Platform code copies the insecure pattern described below from the ARM
+   platform version of ``bl1_plat_mem_check()``.
+
+The vulnerabilities consist of potential integer overflows in the input
+validation checks while handling the ``FWU_SMC_IMAGE_COPY`` SMC. The SMC
+implementation is designed to copy an image into secure memory for subsequent
+authentication, but the vulnerabilities may allow an attacker to copy
+unexpectedly large data into secure memory. Note that a separate vulnerability
+is required to leverage these vulnerabilities; for example a way to get the
+system to change its behaviour based on the unexpected secure memory contents.
+
+Two of the vulnerabilities are in the function ``bl1_fwu_image_copy()`` in
+``bl1/bl1_fwu.c``. These are listed below, referring to the v1.3 tagged version
+of the code:
+
+- Line 155:
+
+  .. code:: c
+
+    /*
+     * If last block is more than expected then
+     * clip the block to the required image size.
+     */
+    if (image_desc->copied_size + block_size >
+         image_desc->image_info.image_size) {
+        block_size = image_desc->image_info.image_size -
+            image_desc->copied_size;
+        WARN("BL1-FWU: Copy argument block_size > remaining image size."
+            " Clipping block_size\n");
+    }
+
+    /* Make sure the image src/size is mapped. */
+    if (bl1_plat_mem_check(image_src, block_size, flags)) {
+        WARN("BL1-FWU: Copy arguments source/size not mapped\n");
+        return -ENOMEM;
+    }
+
+    INFO("BL1-FWU: Continuing image copy in blocks\n");
+
+    /* Copy image for given block size. */
+    base_addr += image_desc->copied_size;
+    image_desc->copied_size += block_size;
+    memcpy((void *)base_addr, (const void *)image_src, block_size);
+    ...
+
+  This code fragment is executed when the image copy operation is performed in
+  blocks over multiple SMCs. ``block_size`` is an SMC argument and therefore
+  potentially controllable by an attacker. A very large value may result in an
+  integer overflow in the 1st ``if`` statement, which would bypass the check,
+  allowing an unclipped ``block_size`` to be passed into
+  ``bl1_plat_mem_check()``. If ``bl1_plat_mem_check()`` also passes, this may
+  result in an unexpectedly large copy of data into secure memory.
+
+- Line 206:
+
+  .. code:: c
+
+    /* Make sure the image src/size is mapped. */
+    if (bl1_plat_mem_check(image_src, block_size, flags)) {
+        WARN("BL1-FWU: Copy arguments source/size not mapped\n");
+        return -ENOMEM;
+    }
+
+    /* Find out how much free trusted ram remains after BL1 load */
+    mem_layout = bl1_plat_sec_mem_layout();
+    if ((image_desc->image_info.image_base < mem_layout->free_base) ||
+         (image_desc->image_info.image_base + image_size >
+          mem_layout->free_base + mem_layout->free_size)) {
+        WARN("BL1-FWU: Memory not available to copy\n");
+        return -ENOMEM;
+    }
+
+    /* Update the image size. */
+    image_desc->image_info.image_size = image_size;
+
+    /* Copy image for given size. */
+    memcpy((void *)base_addr, (const void *)image_src, block_size);
+    ...
+
+  This code fragment is executed during the 1st invocation of the image copy
+  operation. Both ``block_size`` and ``image_size`` are SMC arguments. A very
+  large value of ``image_size`` may result in an integer overflow in the 2nd
+  ``if`` statement, which would bypass the check, allowing execution to proceed.
+  If ``bl1_plat_mem_check()`` also passes, this may result in an unexpectedly
+  large copy of data into secure memory.
+
+If the platform's implementation of ``bl1_plat_mem_check()`` is correct then it
+may help prevent the above 2 vulnerabilities from being exploited. However, the
+ARM platform version of this function contains a similar vulnerability:
+
+- Line 88 of ``plat/arm/common/arm_bl1_fwu.c`` in function of
+  ``bl1_plat_mem_check()``:
+
+  .. code:: c
+
+    while (mmap[index].mem_size) {
+        if ((mem_base >= mmap[index].mem_base) &&
+            ((mem_base + mem_size)
+            <= (mmap[index].mem_base +
+            mmap[index].mem_size)))
+            return 0;
+
+        index++;
+    }
+    ...
+
+  This function checks that the passed memory region is within one of the
+  regions mapped in by ARM platforms. Here, ``mem_size`` may be the
+  ``block_size`` passed from ``bl1_fwu_image_copy()``. A very large value of
+  ``mem_size`` may result in an integer overflow and the function to incorrectly
+  return success. Platforms that copy this insecure pattern will have the same
+  vulnerability.
+
+.. _CVE-2016-10319: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-10319
+.. _48bfb88: https://github.com/ARM-software/arm-trusted-firmware/commit/48bfb88
+.. _Pull Request #783: https://github.com/ARM-software/arm-trusted-firmware/pull/783
diff --git a/docs/security_advisories/security-advisory-tfv-2.rst b/docs/security_advisories/security-advisory-tfv-2.rst
new file mode 100644
index 0000000..0ed2a7f
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-2.rst
@@ -0,0 +1,61 @@
+Advisory TFV-2 (CVE-2017-7564)
+==============================
+
++----------------+-------------------------------------------------------------+
+| Title          | Enabled secure self-hosted invasive debug interface can     |
+|                | allow normal world to panic secure world                    |
++================+=============================================================+
+| CVE ID         | `CVE-2017-7564`_                                            |
++----------------+-------------------------------------------------------------+
+| Date           | 02 Feb 2017                                                 |
++----------------+-------------------------------------------------------------+
+| Versions       | All versions up to v1.3                                     |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | All                                                         |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Impact         | Denial of Service (secure world panic)                      |
++----------------+-------------------------------------------------------------+
+| Fix Version    | 15 Feb 2017 `Pull Request #841`_                            |
++----------------+-------------------------------------------------------------+
+| Credit         | ARM                                                         |
++----------------+-------------------------------------------------------------+
+
+The ``MDCR_EL3.SDD`` bit controls AArch64 secure self-hosted invasive debug
+enablement. By default, the BL1 and BL31 images of the current version of ARM
+Trusted Firmware (TF) unconditionally assign this bit to ``0`` in the early
+entrypoint code, which enables debug exceptions from the secure world. This can
+be seen in the implementation of the ``el3_arch_init_common`` `AArch64 macro`_ .
+Given that TF does not currently contain support for this feature (for example,
+by saving and restoring the appropriate debug registers), this may allow a
+normal world attacker to induce a panic in the secure world.
+
+The ``MDCR_EL3.SDD`` bit should be assigned to ``1`` to disable debug exceptions
+from the secure world.
+
+Earlier versions of TF (prior to `commit 495f3d3`_) did not assign this bit.
+Since the bit has an architecturally ``UNKNOWN`` reset value, earlier versions
+may or may not have the same problem, depending on the platform.
+
+A similar issue applies to the ``MDCR_EL3.SPD32`` bits, which control AArch32
+secure self-hosted invasive debug enablement. TF assigns these bits to ``00``
+meaning that debug exceptions from Secure EL1 are enabled by the authentication
+interface. Therefore this issue only exists for AArch32 Secure EL1 code when
+secure privileged invasive debug is enabled by the authentication interface, at
+which point the device is vulnerable to other, more serious attacks anyway.
+
+However, given that TF contains no support for handling debug exceptions, the
+``MDCR_EL3.SPD32`` bits should be assigned to ``10`` to disable debug exceptions
+from AArch32 Secure EL1.
+
+Finally, this also issue applies to AArch32 platforms that use the TF SP_MIN
+image or integrate the `AArch32 equivalent`_ of the ``el3_arch_init_common``
+macro. Here the affected bits are ``SDCR.SPD``, which should also be assigned to
+``10`` instead of ``00``
+
+.. _CVE-2017-7564: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7564
+.. _commit 495f3d3: https://github.com/ARM-software/arm-trusted-firmware/commit/495f3d3
+.. _AArch64 macro: https://github.com/ARM-software/arm-trusted-firmware/blob/bcc2bf0/include/common/aarch64/el3_common_macros.S#L85
+.. _AArch32 equivalent: https://github.com/ARM-software/arm-trusted-firmware/blob/bcc2bf0/include/common/aarch32/el3_common_macros.S#L41
+.. _Pull Request #841: https://github.com/ARM-software/arm-trusted-firmware/pull/841
diff --git a/docs/security_advisories/security-advisory-tfv-3.rst b/docs/security_advisories/security-advisory-tfv-3.rst
new file mode 100644
index 0000000..b395f13
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-3.rst
@@ -0,0 +1,86 @@
+Advisory TFV-3 (CVE-2017-7563)
+==============================
+
++----------------+-------------------------------------------------------------+
+| Title          | RO memory is always executable at AArch64 Secure EL1        |
++================+=============================================================+
+| CVE ID         | `CVE-2017-7563`_                                            |
++----------------+-------------------------------------------------------------+
+| Date           | 06 Apr 2017                                                 |
++----------------+-------------------------------------------------------------+
+| Versions       | v1.3 (since `Pull Request #662`_)                           |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | AArch64 BL2, TSP or other users of xlat_tables library      |
+| Affected       | executing at AArch64 Secure EL1                             |
++----------------+-------------------------------------------------------------+
+| Impact         | Unexpected Privilege Escalation                             |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #924`_                                        |
++----------------+-------------------------------------------------------------+
+| Credit         | ARM                                                         |
++----------------+-------------------------------------------------------------+
+
+The translation table library in ARM Trusted Firmware (TF) (under
+``lib/xlat_tables`` and ``lib/xlat_tables_v2``) provides APIs to help program
+translation tables in the MMU. The xlat\_tables client specifies its required
+memory mappings in the form of ``mmap_region`` structures.  Each ``mmap_region``
+has memory attributes represented by the ``mmap_attr_t`` enumeration type. This
+contains flags to control data access permissions (``MT_RO``/``MT_RW``) and
+instruction execution permissions (``MT_EXECUTE``/``MT_EXECUTE_NEVER``). Thus a
+mapping specifying both ``MT_RO`` and ``MT_EXECUTE_NEVER`` should result in a
+Read-Only (RO), non-executable memory region.
+
+This feature does not work correctly for AArch64 images executing at Secure EL1.
+Any memory region mapped as RO will always be executable, regardless of whether
+the client specified ``MT_EXECUTE`` or ``MT_EXECUTE_NEVER``.
+
+The vulnerability is known to affect the BL2 and Test Secure Payload (TSP)
+images on platforms that enable the ``SEPARATE_CODE_AND_RODATA`` build option,
+which includes all ARM standard platforms, and the upstream Xilinx and NVidia
+platforms. The RO data section for these images on these platforms is
+unexpectedly executable instead of non-executable. Other platforms or
+``xlat_tables`` clients may also be affected.
+
+The vulnerability primarily manifests itself after `Pull Request #662`_.  Before
+that, ``xlat_tables`` clients could not specify instruction execution
+permissions separately to data access permissions. All RO normal memory regions
+were implicitly executable. Before `Pull Request #662`_.  the vulnerability
+would only manifest itself for device memory mapped as RO; use of this mapping
+is considered rare, although the upstream QEMU platform uses this mapping when
+the ``DEVICE2_BASE`` build option is used.
+
+Note that one or more separate vulnerabilities are also required to exploit this
+vulnerability.
+
+The vulnerability is due to incorrect handling of the execute-never bits in the
+translation tables. The EL3 translation regime uses a single ``XN`` bit to
+determine whether a region is executable. The Secure EL1&0 translation regime
+handles 2 Virtual Address (VA) ranges and so uses 2 bits, ``UXN`` and ``PXN``.
+The ``xlat_tables`` library only handles the ``XN`` bit, which maps to ``UXN``
+in the Secure EL1&0 regime. As a result, this programs the Secure EL0 execution
+permissions but always leaves the memory as executable at Secure EL1.
+
+The vulnerability is mitigated by the following factors:
+
+- The xlat\_tables library ensures that all Read-Write (RW) memory regions are
+  non-executable by setting the ``SCTLR_ELx.WXN`` bit. This overrides any value
+  of the ``XN``, ``UXN`` or ``PXN`` bits in the translation tables. See the
+  ``enable_mmu()`` function:
+
+  ::
+
+      sctlr = read_sctlr_el##_el();               \
+      sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT;       \
+
+- AArch32 configurations are unaffected. Here the ``XN`` bit controls execution
+  privileges of the currently executing translation regime, which is the desired
+  behaviour.
+
+- ARM TF EL3 code (for example BL1 and BL31) ensures that all non-secure memory
+  mapped into the secure world is non-executable by setting the ``SCR_EL3.SIF``
+  bit. See the ``el3_arch_init_common`` macro in ``el3_common_macros.S``.
+
+.. _CVE-2017-7563: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7563
+.. _Pull Request #662: https://github.com/ARM-software/arm-trusted-firmware/pull/662
+.. _Pull Request #924: https://github.com/ARM-software/arm-trusted-firmware/pull/924
diff --git a/docs/security_advisories/security-advisory-tfv-4.rst b/docs/security_advisories/security-advisory-tfv-4.rst
new file mode 100644
index 0000000..66dd542
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-4.rst
@@ -0,0 +1,124 @@
+Advisory TFV-4 (CVE-2017-9607)
+==============================
+
++----------------+-------------------------------------------------------------+
+| Title          | Malformed Firmware Update SMC can result in copy or         |
+|                | authentication of unexpected data in secure memory in       |
+|                | AArch32 state                                               |
++================+=============================================================+
+| CVE ID         | `CVE-2017-9607`_                                            |
++----------------+-------------------------------------------------------------+
+| Date           | 20 Jun 2017                                                 |
++----------------+-------------------------------------------------------------+
+| Versions       | None (only between 22 May 2017 and 14 June 2017)            |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | Platforms that use AArch32 BL1 plus untrusted normal world  |
+| Affected       | firmware update code executing before BL31                  |
++----------------+-------------------------------------------------------------+
+| Impact         | Copy or authentication of unexpected data in the secure     |
+|                | memory                                                      |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #979`_ (merged on 14 June 2017)               |
++----------------+-------------------------------------------------------------+
+| Credit         | ARM                                                         |
++----------------+-------------------------------------------------------------+
+
+The ``include/lib/utils_def.h`` header file provides the
+``check_uptr_overflow()`` macro, which aims at detecting arithmetic overflows
+that may occur when computing the sum of a base pointer and an offset. This
+macro evaluates to 1 if the sum of the given base pointer and offset would
+result in a value large enough to wrap around, which may lead to unpredictable
+behaviour.
+
+The macro code is at line 52, referring to the version of the code as of `commit
+c396b73`_:
+
+.. code:: c
+
+    /*
+     * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise.
+     * Both arguments must be unsigned pointer values (i.e. uintptr_t).
+     */
+    #define check_uptr_overflow(ptr, inc)       \
+        (((ptr) > UINTPTR_MAX - (inc)) ? 1 : 0)
+
+This macro does not work correctly for AArch32 images. It fails to detect
+overflows when the sum of its two parameters fall into the ``[2^32, 2^64 - 1]``
+range. Therefore, any AArch32 code relying on this macro to detect such integer
+overflows is actually not protected.
+
+The buggy code has been present in ARM Trusted Firmware (TF) since `Pull Request
+#678`_ was merged (on 18 August 2016). However, the upstream code was not
+vulnerable until `Pull Request #939`_ was merged (on 22 May 2017), which
+introduced AArch32 support for the Trusted Board Boot (TBB) feature. Before
+then, the ``check_uptr_overflow()`` macro was not used in AArch32 code.
+
+The vulnerability resides in the BL1 FWU SMC handling code and it may be
+exploited when *all* the following conditions apply:
+
+- Platform code uses TF BL1 with the ``TRUSTED_BOARD_BOOT`` build option.
+
+- Platform code uses the Firmware Update (FWU) code provided in
+  ``bl1/bl1_fwu.c``, which is part of the TBB support.
+
+- TF BL1 is compiled with the ``ARCH=aarch32`` build option.
+
+In this context, the AArch32 BL1 image might fail to detect potential integer
+overflows in the input validation checks while handling the
+``FWU_SMC_IMAGE_COPY`` and ``FWU_SMC_IMAGE_AUTH`` SMCs.
+
+The ``FWU_SMC_IMAGE_COPY`` SMC handler is designed to copy an image into secure
+memory for subsequent authentication. This is implemented by the
+``bl1_fwu_image_copy()`` function, which has the following function prototype:
+
+.. code:: c
+
+     static int bl1_fwu_image_copy(unsigned int image_id,
+                        uintptr_t image_src,
+                        unsigned int block_size,
+                        unsigned int image_size,
+                        unsigned int flags)
+
+``image_src`` is an SMC argument and therefore potentially controllable by an
+attacker. A very large 32-bit value, for example ``2^32 -1``, may result in the
+sum of ``image_src`` and ``block_size`` overflowing a 32-bit type, which
+``check_uptr_overflow()`` will fail to detect.  Depending on its implementation,
+the platform-specific function ``bl1_plat_mem_check()`` might get defeated by
+these unsanitized values and allow the following memory copy operation, that
+would wrap around.  This may allow an attacker to copy unexpected data into
+secure memory if the memory is mapped in BL1's address space, or cause a fatal
+exception if it's not.
+
+The ``FWU_SMC_IMAGE_AUTH`` SMC handler is designed to authenticate an image
+resident in secure memory. This is implemented by the ``bl1_fwu_image_auth()``
+function, which has the following function prototype:
+
+.. code:: c
+
+    static int bl1_fwu_image_auth(unsigned int image_id,
+                        uintptr_t image_src,
+                        unsigned int image_size,
+                        unsigned int flags)
+
+Similarly, if an attacker has control over the ``image_src`` or ``image_size``
+arguments through the SMC interface and injects high values whose sum overflows,
+they might defeat the ``bl1_plat_mem_check()`` function and make the
+authentication module read data outside of what's normally allowed by the
+platform code or crash the platform.
+
+Note that in both cases, a separate vulnerability is required to leverage this
+vulnerability; for example a way to get the system to change its behaviour based
+on the unexpected secure memory accesses.  Moreover, the normal world FWU code
+would need to be compromised in order to send a malformed FWU SMC that triggers
+an integer overflow.
+
+The vulnerability is known to affect all ARM standard platforms when enabling
+the ``TRUSTED_BOARD_BOOT`` and ``ARCH=aarch32`` build options.  Other platforms
+may also be affected if they fulfil the above conditions.
+
+.. _CVE-2017-9607: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9607
+.. _commit c396b73: https://github.com/ARM-software/arm-trusted-firmware/commit/c396b73
+.. _Pull Request #678: https://github.com/ARM-software/arm-trusted-firmware/pull/678
+.. _Pull Request #939: https://github.com/ARM-software/arm-trusted-firmware/pull/939
+.. _Pull Request #979: https://github.com/ARM-software/arm-trusted-firmware/pull/979
diff --git a/docs/security_advisories/security-advisory-tfv-5.rst b/docs/security_advisories/security-advisory-tfv-5.rst
new file mode 100644
index 0000000..2214f2d
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-5.rst
@@ -0,0 +1,46 @@
+Advisory TFV-5 (CVE-2017-15031)
+===============================
+
++----------------+-------------------------------------------------------------+
+| Title          | Not initializing or saving/restoring ``PMCR_EL0`` can leak  |
+|                | secure world timing information                             |
++================+=============================================================+
+| CVE ID         | `CVE-2017-15031`_                                           |
++----------------+-------------------------------------------------------------+
+| Date           | 02 Oct 2017                                                 |
++----------------+-------------------------------------------------------------+
+| Versions       | All, up to and including v1.4                               |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | All                                                         |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Impact         | Leakage of sensitive secure world timing information        |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #1127`_ (merged on 18 October 2017)           |
++----------------+-------------------------------------------------------------+
+| Credit         | Arm                                                         |
++----------------+-------------------------------------------------------------+
+
+The ``PMCR_EL0`` (Performance Monitors Control Register) provides details of the
+Performance Monitors implementation, including the number of counters
+implemented, and configures and controls the counters. If the ``PMCR_EL0.DP``
+bit is set to zero, the cycle counter (when enabled) counts during secure world
+execution, even when prohibited by the debug signals.
+
+Since Arm TF does not save and restore ``PMCR_EL0`` when switching between the
+normal and secure worlds, normal world code can set ``PMCR_EL0.DP`` to zero to
+cause leakage of secure world timing information. This register should be added
+to the list of saved/restored registers.
+
+Furthermore, ``PMCR_EL0.DP`` has an architecturally ``UNKNOWN`` reset value.
+Since Arm TF does not initialize this register, it's possible that on at least
+some implementations, ``PMCR_EL0.DP`` is set to zero by default. This and other
+bits with an architecturally UNKNOWN reset value should be initialized to
+sensible default values in the secure context.
+
+The same issue exists for the equivalent AArch32 register, ``PMCR``, except that
+here ``PMCR_EL0.DP`` architecturally resets to zero.
+
+.. _CVE-2017-15031: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15031
+.. _Pull Request #1127: https://github.com/ARM-software/arm-trusted-firmware/pull/1127
diff --git a/docs/security_advisories/security-advisory-tfv-6.rst b/docs/security_advisories/security-advisory-tfv-6.rst
new file mode 100644
index 0000000..495eddd
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-6.rst
@@ -0,0 +1,148 @@
+Advisory TFV-6 (CVE-2017-5753, CVE-2017-5715, CVE-2017-5754)
+============================================================
+
++----------------+-------------------------------------------------------------+
+| Title          | Trusted Firmware-A exposure to speculative processor        |
+|                | vulnerabilities using cache timing side-channels            |
++================+=============================================================+
+| CVE ID         | `CVE-2017-5753`_ / `CVE-2017-5715`_ / `CVE-2017-5754`_      |
++----------------+-------------------------------------------------------------+
+| Date           | 03 Jan 2018 (Updated 11 Jan, 18 Jan, 26 Jan, 30 Jan and 07  |
+|                | June 2018)                                                  |
++----------------+-------------------------------------------------------------+
+| Versions       | All, up to and including v1.4                               |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | All                                                         |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Impact         | Leakage of secure world data to normal world                |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #1214`_, `Pull Request #1228`_,               |
+|                | `Pull Request #1240`_ and `Pull Request #1405`_             |
++----------------+-------------------------------------------------------------+
+| Credit         | Google / Arm                                                |
++----------------+-------------------------------------------------------------+
+
+This security advisory describes the current understanding of the Trusted
+Firmware-A exposure to the speculative processor vulnerabilities identified by
+`Google Project Zero`_.  To understand the background and wider impact of these
+vulnerabilities on Arm systems, please refer to the `Arm Processor Security
+Update`_.
+
+Variant 1 (`CVE-2017-5753`_)
+----------------------------
+
+At the time of writing, no vulnerable patterns have been observed in upstream TF
+code, therefore no workarounds have been applied or are planned.
+
+Variant 2 (`CVE-2017-5715`_)
+----------------------------
+
+Where possible on vulnerable CPUs, Arm recommends invalidating the branch
+predictor as early as possible on entry into the secure world, before any branch
+instruction is executed. There are a number of implementation defined ways to
+achieve this.
+
+For Cortex-A57 and Cortex-A72 CPUs, the Pull Requests (PRs) in this advisory
+invalidate the branch predictor when entering EL3 by disabling and re-enabling
+the MMU.
+
+For Cortex-A73 and Cortex-A75 CPUs, the PRs in this advisory invalidate the
+branch predictor when entering EL3 by temporarily dropping into AArch32
+Secure-EL1 and executing the ``BPIALL`` instruction. This workaround is
+signifiantly more complex than the "MMU disable/enable" workaround. The latter
+is not effective at invalidating the branch predictor on Cortex-A73/Cortex-A75.
+
+Note that if other privileged software, for example a Rich OS kernel, implements
+its own branch predictor invalidation during context switch by issuing an SMC
+(to execute firmware branch predictor invalidation), then there is a dependency
+on the PRs in this advisory being deployed in order for those workarounds to
+work. If that other privileged software is able to workaround the vulnerability
+locally (for example by implementing "MMU disable/enable" itself), there is no
+such dependency.
+
+`Pull Request #1240`_ and `Pull Request #1405`_ optimise the earlier fixes by
+implementing a specified `CVE-2017-5715`_ workaround SMC
+(``SMCCC_ARCH_WORKAROUND_1``) for use by normal world privileged software. This
+is more efficient than calling an arbitrary SMC (for example ``PSCI_VERSION``).
+Details of ``SMCCC_ARCH_WORKAROUND_1`` can be found in the `CVE-2017-5715
+mitigation specification`_.  The specification and implementation also enable
+the normal world to discover the presence of this firmware service.
+
+On Juno R1 we measured the round trip latency for both the ``PSCI_VERSION`` and
+``SMCCC_ARCH_WORKAROUND_1`` SMCs on Cortex-A57, using both the "MMU
+disable/enable" and "BPIALL at AArch32 Secure-EL1" workarounds described above.
+This includes the time spent in test code conforming to the SMC Calling
+Convention (SMCCC) from AArch64. For the ``SMCCC_ARCH_WORKAROUND_1`` cases, the
+test code uses SMCCC v1.1, which reduces the number of general purpose registers
+it needs to save/restore. Although the ``BPIALL`` instruction is not effective
+at invalidating the branch predictor on Cortex-A57, the drop into Secure-EL1
+with MMU disabled that this workaround entails effectively does invalidate the
+branch predictor. Hence this is a reasonable comparison.
+
+The results were as follows:
+
++------------------------------------------------------------------+-----------+
+| Test                                                             | Time (ns) |
++==================================================================+===========+
+| ``PSCI_VERSION`` baseline (without PRs in this advisory)         | 515       |
++------------------------------------------------------------------+-----------+
+| ``PSCI_VERSION`` baseline (with PRs in this advisory)            | 527       |
++------------------------------------------------------------------+-----------+
+| ``PSCI_VERSION`` with "MMU disable/enable"                       | 930       |
++------------------------------------------------------------------+-----------+
+| ``SMCCC_ARCH_WORKAROUND_1`` with "MMU disable/enable"            | 386       |
++------------------------------------------------------------------+-----------+
+| ``PSCI_VERSION`` with "BPIALL at AArch32 Secure-EL1"             | 1276      |
++------------------------------------------------------------------+-----------+
+| ``SMCCC_ARCH_WORKAROUND_1`` with "BPIALL at AArch32 Secure-EL1"  | 770       |
++------------------------------------------------------------------+-----------+
+
+Due to the high severity and wide applicability of this issue, the above
+workarounds are enabled by default (on vulnerable CPUs only), despite some
+performance and code size overhead. Platforms can choose to disable them at
+compile time if they do not require them. `Pull Request #1240`_ disables the
+workarounds for unaffected upstream platforms.
+
+For vulnerable AArch32-only CPUs (for example Cortex-A8, Cortex-A9 and
+Cortex-A17), the ``BPIALL`` instruction should be used as early as possible on
+entry into the secure world. For Cortex-A8, also set ``ACTLR[6]`` to 1 during
+early processor initialization. Note that the ``BPIALL`` instruction is not
+effective at invalidating the branch predictor on Cortex-A15. For that CPU, set
+``ACTLR[0]`` to 1 during early processor initialization, and invalidate the
+branch predictor by performing an ``ICIALLU`` instruction.
+
+On AArch32 EL3 systems, the monitor and secure-SVC code is typically tightly
+integrated, for example as part of a Trusted OS. Therefore any Variant 2
+workaround should be provided by vendors of that software and is outside the
+scope of TF. However, an example implementation in the minimal AArch32 Secure
+Payload, ``SP_MIN`` is provided in `Pull Request #1228`_.
+
+Other Arm CPUs are not vulnerable to this or other variants. This includes
+Cortex-A76, Cortex-A53, Cortex-A55, Cortex-A32, Cortex-A7 and Cortex-A5.
+
+For more information about non-Arm CPUs, please contact the CPU vendor.
+
+Variant 3 (`CVE-2017-5754`_)
+----------------------------
+
+This variant is only exploitable between Exception Levels within the same
+translation regime, for example between EL0 and EL1, therefore this variant
+cannot be used to access secure memory from the non-secure world, and is not
+applicable for TF. However, Secure Payloads (for example, Trusted OS) should
+provide mitigations on vulnerable CPUs to protect themselves from exploited
+Secure-EL0 applications.
+
+The only Arm CPU vulnerable to this variant is Cortex-A75.
+
+.. _Google Project Zero: https://googleprojectzero.blogspot.co.uk/2018/01/reading-privileged-memory-with-side.html
+.. _Arm Processor Security Update: http://www.arm.com/security-update
+.. _CVE-2017-5753: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5753
+.. _CVE-2017-5715: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715
+.. _CVE-2017-5754: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5754
+.. _Pull Request #1214: https://github.com/ARM-software/arm-trusted-firmware/pull/1214
+.. _Pull Request #1228: https://github.com/ARM-software/arm-trusted-firmware/pull/1228
+.. _Pull Request #1240: https://github.com/ARM-software/arm-trusted-firmware/pull/1240
+.. _Pull Request #1405: https://github.com/ARM-software/arm-trusted-firmware/pull/1405
+.. _CVE-2017-5715 mitigation specification: https://developer.arm.com/cache-speculation-vulnerability-firmware-specification
diff --git a/docs/security_advisories/security-advisory-tfv-7.rst b/docs/security_advisories/security-advisory-tfv-7.rst
new file mode 100644
index 0000000..8e06762
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-7.rst
@@ -0,0 +1,107 @@
+Advisory TFV-7 (CVE-2018-3639)
+==============================
+
++----------------+-------------------------------------------------------------+
+| Title          | Trusted Firmware-A exposure to cache speculation            |
+|                | vulnerability Variant 4                                     |
++================+=============================================================+
+| CVE ID         | `CVE-2018-3639`_                                            |
++----------------+-------------------------------------------------------------+
+| Date           | 21 May 2018 (Updated 7 June 2018)                           |
++----------------+-------------------------------------------------------------+
+| Versions       | All, up to and including v1.5                               |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | All                                                         |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Impact         | Leakage of secure world data to normal world                |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #1392`_, `Pull Request #1397`_                |
++----------------+-------------------------------------------------------------+
+| Credit         | Google                                                      |
++----------------+-------------------------------------------------------------+
+
+This security advisory describes the current understanding of the Trusted
+Firmware-A (TF-A) exposure to Variant 4 of the cache speculation vulnerabilities
+identified by `Google Project Zero`_.  To understand the background and wider
+impact of these vulnerabilities on Arm systems, please refer to the `Arm
+Processor Security Update`_.
+
+At the time of writing, the TF-A project is not aware of a Variant 4 exploit
+that could be used against TF-A. It is likely to be very difficult to achieve an
+exploit against current standard configurations of TF-A, due to the limited
+interfaces into the secure world with attacker-controlled inputs. However, this
+is becoming increasingly difficult to guarantee with the introduction of complex
+new firmware interfaces, for example the `Software Delegated Exception Interface
+(SDEI)`_.  Also, the TF-A project does not have visibility of all
+vendor-supplied interfaces. Therefore, the TF-A project takes a conservative
+approach by mitigating Variant 4 in hardware wherever possible during secure
+world execution. The mitigation is enabled by setting an implementation defined
+control bit to prevent the re-ordering of stores and loads.
+
+For each affected CPU type, TF-A implements one of the two following mitigation
+approaches in `Pull Request #1392`_ and `Pull Request #1397`_.  Both approaches
+have a system performance impact, which varies for each CPU type and use-case.
+The mitigation code is enabled by default, but can be disabled at compile time
+for platforms that are unaffected or where the risk is deemed low enough.
+
+Arm CPUs not mentioned below are unaffected.
+
+Static mitigation
+-----------------
+
+For affected CPUs, this approach enables the mitigation during EL3
+initialization, following every PE reset. No mechanism is provided to disable
+the mitigation at runtime.
+
+This approach permanently mitigates the entire software stack and no additional
+mitigation code is required in other software components.
+
+TF-A implements this approach for the following affected CPUs:
+
+- Cortex-A57 and Cortex-A72, by setting bit 55 (Disable load pass store) of
+  ``CPUACTLR_EL1`` (``S3_1_C15_C2_0``).
+
+- Cortex-A73, by setting bit 3 of ``S3_0_C15_C0_0`` (not documented in the
+  Technical Reference Manual (TRM)).
+
+- Cortex-A75, by setting bit 35 (reserved in TRM) of ``CPUACTLR_EL1``
+  (``S3_0_C15_C1_0``).
+
+Dynamic mitigation
+------------------
+
+For affected CPUs, this approach also enables the mitigation during EL3
+initialization, following every PE reset. In addition, this approach implements
+``SMCCC_ARCH_WORKAROUND_2`` in the Arm architectural range to allow callers at
+lower exception levels to temporarily disable the mitigation in their execution
+context, where the risk is deemed low enough. This approach enables mitigation
+on entry to EL3, and restores the mitigation state of the lower exception level
+on exit from EL3. For more information on this approach, see `Firmware
+interfaces for mitigating cache speculation vulnerabilities`_.
+
+This approach may be complemented by additional mitigation code in other
+software components, for example code that calls ``SMCCC_ARCH_WORKAROUND_2``.
+However, even without any mitigation code in other software components, this
+approach will effectively permanently mitigate the entire software stack, since
+the default mitigation state for firmware-managed execution contexts is enabled.
+
+Since the expectation in this approach is that more software executes with the
+mitigation disabled, this may result in better system performance than the
+static approach for some systems or use-cases.  However, for other systems or
+use-cases, this performance saving may be outweighed by the additional overhead
+of ``SMCCC_ARCH_WORKAROUND_2`` calls and TF-A exception handling.
+
+TF-A implements this approach for the following affected CPU:
+
+- Cortex-A76, by setting and clearing bit 16 (reserved in TRM) of
+  ``CPUACTLR2_EL1`` (``S3_0_C15_C1_1``).
+
+.. _Google Project Zero: https://bugs.chromium.org/p/project-zero/issues/detail?id=1528
+.. _Arm Processor Security Update: http://www.arm.com/security-update
+.. _CVE-2018-3639: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639
+.. _Software Delegated Exception Interface (SDEI): http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _Firmware interfaces for mitigating cache speculation vulnerabilities: https://developer.arm.com/cache-speculation-vulnerability-firmware-specification
+.. _Pull Request #1392: https://github.com/ARM-software/arm-trusted-firmware/pull/1392
+.. _Pull Request #1397: https://github.com/ARM-software/arm-trusted-firmware/pull/1397
diff --git a/docs/security_advisories/security-advisory-tfv-8.rst b/docs/security_advisories/security-advisory-tfv-8.rst
new file mode 100644
index 0000000..c401eb3
--- /dev/null
+++ b/docs/security_advisories/security-advisory-tfv-8.rst
@@ -0,0 +1,103 @@
+Advisory TFV-8 (CVE-2018-19440)
+===============================
+
++----------------+-------------------------------------------------------------+
+| Title          | Not saving x0 to x3 registers can leak information from one |
+|                | Normal World SMC client to another                          |
++================+=============================================================+
+| CVE ID         | `CVE-2018-19440`_                                           |
++----------------+-------------------------------------------------------------+
+| Date           | 27 Nov 2018                                                 |
++----------------+-------------------------------------------------------------+
+| Versions       | All                                                         |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Configurations | Multiple normal world SMC clients calling into AArch64 BL31 |
+| Affected       |                                                             |
++----------------+-------------------------------------------------------------+
+| Impact         | Leakage of SMC return values from one normal world SMC      |
+|                | client to another                                           |
++----------------+-------------------------------------------------------------+
+| Fix Version    | `Pull Request #1710`_                                       |
++----------------+-------------------------------------------------------------+
+| Credit         | Secmation                                                   |
++----------------+-------------------------------------------------------------+
+
+When taking an exception to EL3, BL31 saves the CPU context. The aim is to
+restore it before returning into the lower exception level software that called
+into the firmware. However, for an SMC exception, the general purpose registers
+``x0`` to ``x3`` are not part of the CPU context saved on the stack.
+
+As per the `SMC Calling Convention`_, up to 4 values may be returned to the
+caller in registers ``x0`` to ``x3``. In TF-A, these return values are written
+into the CPU context, typically using one of the ``SMC_RETx()`` macros provided
+in the ``include/lib/aarch64/smccc_helpers.h`` header file.
+
+Before returning to the caller, the ``restore_gp_registers()`` function is
+called. It restores the values of all general purpose registers taken from the
+CPU context stored on the stack. This includes registers ``x0`` to ``x3``, as
+can be seen in the ``lib/el3_runtime/aarch64/context.S`` file at line 339
+(referring to the version of the code as of `commit c385955`_):
+
+::
+
+    /*
+     * This function restores all general purpose registers except x30 from the
+     * CPU context. x30 register must be explicitly restored by the caller.
+     */
+    func restore_gp_registers
+        ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+        ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+
+In the case of an SMC handler that does not use all 4 return values, the
+remaining ones are left unchanged in the CPU context. As a result,
+``restore_gp_registers()`` restores the stale values saved by a previous SMC
+request (or asynchronous exception to EL3) that used these return values.
+
+In the presence of multiple normal world SMC clients, this behaviour might leak
+some of the return values from one client to another. For example, if a victim
+client first sends an SMC that returns 4 values, a malicious client may then
+send a second SMC expecting no return values (for example, a
+``SDEI_EVENT_COMPLETE`` SMC) to get the 4 return values of the victim client.
+
+In general, the responsibility for mitigating threats due to the presence of
+multiple normal world SMC clients lies with EL2 software.  When present, EL2
+software must trap SMC calls from EL1 software to ensure secure behaviour.
+
+For this reason, TF-A does not save ``x0`` to ``x3`` in the CPU context on an
+SMC synchronous exception. It has behaved this way since the first version.
+
+We can confirm that at least upstream KVM-based systems mitigate this threat,
+and are therefore unaffected by this issue. Other EL2 software should be audited
+to assess the impact of this threat.
+
+EL2 software might find mitigating this threat somewhat onerous, because for all
+SMCs it would need to be aware of which return registers contain valid data, so
+it can sanitise any unused return registers. On the other hand, mitigating this
+in EL3 is relatively easy and cheap. Therefore, TF-A will now ensure that no
+information is leaked through registers ``x0`` to ``x3``, by preserving the
+register state over the call.
+
+Note that AArch32 TF-A is not affected by this issue. The SMC handling code in
+``SP_MIN`` already saves all general purpose registers - including ``r0`` to
+``r3``, as can be seen in the ``include/lib/aarch32/smccc_macros.S`` file at
+line 19 (referring to the version of the code as of `commit c385955`_):
+
+.. code:: c
+
+    /*
+     * Macro to save the General purpose registers (r0 - r12), the banked
+     * spsr, lr, sp registers and the `scr` register to the SMC context on entry
+     * due a SMC call. The `lr` of the current mode (monitor) is expected to be
+     * already saved. The `sp` must point to the `smc_ctx_t` to save to.
+     * Additionally, also save the 'pmcr' register as this is updated whilst
+     * executing in the secure world.
+     */
+        .macro smccc_save_gp_mode_regs
+        /* Save r0 - r12 in the SMC context */
+        stm sp, {r0-r12}
+
+.. _CVE-2018-19440: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19440
+.. _commit c385955: https://github.com/ARM-software/arm-trusted-firmware/commit/c385955
+.. _SMC Calling Convention: http://arminfo.emea.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+.. _Pull Request #1710: https://github.com/ARM-software/arm-trusted-firmware/pull/1710
diff --git a/drivers/allwinner/sunxi_rsb.c b/drivers/allwinner/sunxi_rsb.c
new file mode 100644
index 0000000..67f5b7e
--- /dev/null
+++ b/drivers/allwinner/sunxi_rsb.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <sunxi_mmap.h>
+
+#define RSB_CTRL	0x00
+#define RSB_CCR		0x04
+#define RSB_INTE	0x08
+#define RSB_STAT	0x0c
+#define RSB_DADDR0	0x10
+#define RSB_DLEN	0x18
+#define RSB_DATA0	0x1c
+#define RSB_LCR		0x24
+#define RSB_PMCR	0x28
+#define RSB_CMD		0x2c
+#define RSB_SADDR	0x30
+
+#define RSBCMD_SRTA	0xE8
+#define RSBCMD_RD8	0x8B
+#define RSBCMD_RD16	0x9C
+#define RSBCMD_RD32	0xA6
+#define RSBCMD_WR8	0x4E
+#define RSBCMD_WR16	0x59
+#define RSBCMD_WR32	0x63
+
+#define MAX_TRIES	100000
+
+static int rsb_wait_bit(const char *desc, unsigned int offset, uint32_t mask)
+{
+	uint32_t reg, tries = MAX_TRIES;
+
+	do
+		reg = mmio_read_32(SUNXI_R_RSB_BASE + offset);
+	while ((reg & mask) && --tries);	/* transaction in progress */
+	if (reg & mask) {
+		ERROR("%s: timed out\n", desc);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int rsb_wait_stat(const char *desc)
+{
+	uint32_t reg;
+	int ret = rsb_wait_bit(desc, RSB_CTRL, BIT(7));
+
+	if (ret)
+		return ret;
+
+	reg = mmio_read_32(SUNXI_R_RSB_BASE + RSB_STAT);
+	if (reg == 0x01)
+		return 0;
+
+	ERROR("%s: 0x%x\n", desc, reg);
+	return -reg;
+}
+
+/* Initialize the RSB controller. */
+int rsb_init_controller(void)
+{
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x01); /* soft reset */
+
+	return rsb_wait_bit("RSB: reset controller", RSB_CTRL, BIT(0));
+}
+
+int rsb_read(uint8_t rt_addr, uint8_t reg_addr)
+{
+	int ret;
+
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16);
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr);
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */
+
+	ret = rsb_wait_stat("RSB: read command");
+	if (ret)
+		return ret;
+
+	return mmio_read_32(SUNXI_R_RSB_BASE + RSB_DATA0) & 0xff; /* result */
+}
+
+int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value)
+{
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_WR8);	/* byte write */
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16);
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr);
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_DATA0, value);
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */
+
+	return rsb_wait_stat("RSB: write command");
+}
+
+int rsb_set_device_mode(uint32_t device_mode)
+{
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_PMCR,
+		      (device_mode & 0x00ffffff) | BIT(31));
+
+	return rsb_wait_bit("RSB: set device to RSB", RSB_PMCR, BIT(31));
+}
+
+int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq)
+{
+	uint32_t reg;
+
+	if (bus_freq == 0)
+		return -EINVAL;
+
+	reg = source_freq / bus_freq;
+	if (reg < 2)
+		return -EINVAL;
+
+	reg = reg / 2 - 1;
+	reg |= (1U << 8);		/* one cycle of CD output delay */
+
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CCR, reg);
+
+	return 0;
+}
+
+/* Initialize the RSB PMIC connection. */
+int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr)
+{
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16));
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_SRTA);
+	mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);
+
+	return rsb_wait_stat("RSB: set run-time address");
+}
diff --git a/drivers/arm/cci/cci.c b/drivers/arm/cci/cci.c
new file mode 100644
index 0000000..a139f6c
--- /dev/null
+++ b/drivers/arm/cci/cci.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/mmio.h>
+
+#define MAKE_CCI_PART_NUMBER(hi, lo)	(((hi) << 8) | (lo))
+#define CCI_PART_LO_MASK		U(0xff)
+#define CCI_PART_HI_MASK		U(0xf)
+
+/* CCI part number codes read from Peripheral ID registers 0 and 1 */
+#define CCI400_PART_NUM		0x420
+#define CCI500_PART_NUM		0x422
+#define CCI550_PART_NUM		0x423
+
+#define CCI400_SLAVE_PORTS	5
+#define CCI500_SLAVE_PORTS	7
+#define CCI550_SLAVE_PORTS	7
+
+static uintptr_t cci_base;
+static const int *cci_slave_if_map;
+
+#if ENABLE_ASSERTIONS
+static unsigned int max_master_id;
+static int cci_num_slave_ports;
+
+static bool validate_cci_map(const int *map)
+{
+	unsigned int valid_cci_map = 0U;
+	int slave_if_id;
+	unsigned int i;
+
+	/* Validate the map */
+	for (i = 0U; i <= max_master_id; i++) {
+		slave_if_id = map[i];
+
+		if (slave_if_id < 0)
+			continue;
+
+		if (slave_if_id >= cci_num_slave_ports) {
+			ERROR("Slave interface ID is invalid\n");
+			return false;
+		}
+
+		if ((valid_cci_map & (1U << slave_if_id)) != 0U) {
+			ERROR("Multiple masters are assigned same slave interface ID\n");
+			return false;
+		}
+		valid_cci_map |= 1U << slave_if_id;
+	}
+
+	if (valid_cci_map == 0U) {
+		ERROR("No master is assigned a valid slave interface\n");
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * Read CCI part number from Peripheral ID registers
+ */
+static unsigned int read_cci_part_number(uintptr_t base)
+{
+	unsigned int part_lo, part_hi;
+
+	part_lo = mmio_read_32(base + PERIPHERAL_ID0) & CCI_PART_LO_MASK;
+	part_hi = mmio_read_32(base + PERIPHERAL_ID1) & CCI_PART_HI_MASK;
+
+	return MAKE_CCI_PART_NUMBER(part_hi, part_lo);
+}
+
+/*
+ * Identify a CCI device, and return the number of slaves. Return -1 for an
+ * unidentified device.
+ */
+static int get_slave_ports(unsigned int part_num)
+{
+	int num_slave_ports = -1;
+
+	switch (part_num) {
+
+	case CCI400_PART_NUM:
+		num_slave_ports = CCI400_SLAVE_PORTS;
+		break;
+	case CCI500_PART_NUM:
+		num_slave_ports = CCI500_SLAVE_PORTS;
+		break;
+	case CCI550_PART_NUM:
+		num_slave_ports = CCI550_SLAVE_PORTS;
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return num_slave_ports;
+}
+#endif /* ENABLE_ASSERTIONS */
+
+void __init cci_init(uintptr_t base, const int *map,
+				unsigned int num_cci_masters)
+{
+	assert(map != NULL);
+	assert(base != 0U);
+
+	cci_base = base;
+	cci_slave_if_map = map;
+
+#if ENABLE_ASSERTIONS
+	/*
+	 * Master Id's are assigned from zero, So in an array of size n
+	 * the max master id is (n - 1).
+	 */
+	max_master_id = num_cci_masters - 1U;
+	cci_num_slave_ports = get_slave_ports(read_cci_part_number(base));
+#endif
+	assert(cci_num_slave_ports >= 0);
+
+	assert(validate_cci_map(map));
+}
+
+void cci_enable_snoop_dvm_reqs(unsigned int master_id)
+{
+	int slave_if_id = cci_slave_if_map[master_id];
+
+	assert(master_id <= max_master_id);
+	assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
+	assert(cci_base != 0U);
+
+	/*
+	 * Enable Snoops and DVM messages, no need for Read/Modify/Write as
+	 * rest of bits are write ignore
+	 */
+	mmio_write_32(cci_base +
+		      SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG,
+		      DVM_EN_BIT | SNOOP_EN_BIT);
+
+	/*
+	 * Wait for the completion of the write to the Snoop Control Register
+	 * before testing the change_pending bit
+	 */
+	dsbish();
+
+	/* Wait for the dust to settle down */
+	while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U)
+		;
+}
+
+void cci_disable_snoop_dvm_reqs(unsigned int master_id)
+{
+	int slave_if_id = cci_slave_if_map[master_id];
+
+	assert(master_id <= max_master_id);
+	assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
+	assert(cci_base != 0U);
+
+	/*
+	 * Disable Snoops and DVM messages, no need for Read/Modify/Write as
+	 * rest of bits are write ignore.
+	 */
+	mmio_write_32(cci_base +
+		      SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG,
+		      ~(DVM_EN_BIT | SNOOP_EN_BIT));
+
+	/*
+	 * Wait for the completion of the write to the Snoop Control Register
+	 * before testing the change_pending bit
+	 */
+	dsbish();
+
+	/* Wait for the dust to settle down */
+	while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U)
+		;
+}
+
diff --git a/drivers/arm/ccn/ccn.c b/drivers/arm/ccn/ccn.c
new file mode 100644
index 0000000..d0c5abc
--- /dev/null
+++ b/drivers/arm/ccn/ccn.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include "ccn_private.h"
+
+static const ccn_desc_t *ccn_plat_desc;
+#if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
+DEFINE_BAKERY_LOCK(ccn_lock);
+#endif
+
+/*******************************************************************************
+ * This function takes the base address of the CCN's programmer's view (PV), a
+ * region ID of one of the 256 regions (0-255) and a register offset within the
+ * region. It converts the first two parameters into a base address and uses it
+ * to read the register at the offset.
+ ******************************************************************************/
+static inline unsigned long long ccn_reg_read(uintptr_t periphbase,
+			     unsigned int region_id,
+			     unsigned int register_offset)
+{
+	uintptr_t region_base;
+
+	assert(periphbase);
+	assert(region_id < REGION_ID_LIMIT);
+
+	region_base = periphbase + region_id_to_base(region_id);
+	return mmio_read_64(region_base + register_offset);
+}
+
+/*******************************************************************************
+ * This function takes the base address of the CCN's programmer's view (PV), a
+ * region ID of one of the 256 regions (0-255), a register offset within the
+ * region and a value. It converts the first two parameters into a base address
+ * and uses it to write the value in the register at the offset.
+ ******************************************************************************/
+static inline void ccn_reg_write(uintptr_t periphbase,
+			  unsigned int region_id,
+			  unsigned int register_offset,
+			  unsigned long long value)
+{
+	uintptr_t region_base;
+
+	assert(periphbase);
+	assert(region_id < REGION_ID_LIMIT);
+
+	region_base = periphbase + region_id_to_base(region_id);
+	mmio_write_64(region_base + register_offset, value);
+}
+
+#if ENABLE_ASSERTIONS
+
+typedef struct rn_info {
+		unsigned char node_desc[MAX_RN_NODES];
+	} rn_info_t;
+
+/*******************************************************************************
+ * This function takes the base address of the CCN's programmer's view (PV) and
+ * the node ID of a Request Node (RN-D or RN-I). It returns the maximum number
+ * of master interfaces resident on that node. This number is equal to the least
+ * significant two bits of the node type ID + 1.
+ ******************************************************************************/
+static unsigned int ccn_get_rni_mcount(uintptr_t periphbase,
+				       unsigned int rn_id)
+{
+	unsigned int rn_type_id;
+
+	/* Use the node id to find the type of RN-I/D node */
+	rn_type_id = get_node_type(ccn_reg_read(periphbase,
+						rn_id + RNI_REGION_ID_START,
+						REGION_ID_OFFSET));
+
+	/* Return the number master interfaces based on node type */
+	return rn_type_id_to_master_cnt(rn_type_id);
+}
+
+/*******************************************************************************
+ * This function reads the CCN registers to find the following information about
+ * the ACE/ACELite/ACELite+DVM/CHI interfaces resident on the various types of
+ * Request Nodes (RN-Fs, RN-Is and RN-Ds) in the system:
+ *
+ * 1. The total number of such interfaces that this CCN IP supports. This is the
+ *    cumulative number of interfaces across all Request node types. It is
+ *    passed back as the return value of this function.
+ *
+ * 2. The maximum number of interfaces of a type resident on a Request node of
+ *    one of the three types. This information is populated in the 'info'
+ *    array provided by the caller as described next.
+ *
+ *    The array has 64 entries. Each entry corresponds to a Request node. The
+ *    Miscellaneous node's programmer's view has RN-F, RN-I and RN-D ID
+ *    registers. For each RN-I and RN-D ID indicated as being present in these
+ *    registers, its identification register (offset 0xFF00) is read. This
+ *    register specifies the maximum number of master interfaces the node
+ *    supports. For RN-Fs it is assumed that there can be only a single fully
+ *    coherent master resident on each node. The counts for each type of node
+ *    are use to populate the array entry at the index corresponding to the node
+ *    ID i.e. rn_info[node ID] = <number of master interfaces>
+ ******************************************************************************/
+static unsigned int ccn_get_rn_master_info(uintptr_t periphbase,
+					   rn_info_t *info)
+{
+	unsigned int num_masters = 0;
+	rn_types_t rn_type;
+
+	assert (info);
+
+	for (rn_type = RN_TYPE_RNF; rn_type < NUM_RN_TYPES; rn_type++) {
+		unsigned int mn_reg_off, node_id;
+		unsigned long long rn_bitmap;
+
+		/*
+		 * RN-F, RN-I, RN-D node registers in the MN region occupy
+		 * contiguous 16 byte apart offsets.
+		 */
+		mn_reg_off = MN_RNF_NODEID_OFFSET + (rn_type << 4);
+		rn_bitmap = ccn_reg_read(periphbase, MN_REGION_ID, mn_reg_off);
+
+		FOR_EACH_PRESENT_NODE_ID(node_id, rn_bitmap) {
+			unsigned int node_mcount;
+
+			/*
+			 * A RN-F does not have a node type since it does not
+			 * export a programmer's interface. It can only have a
+			 * single fully coherent master residing on it. If the
+			 * offset of the MN(Miscellaneous Node) register points
+			 * to a RN-I/D node then the master count is set to the
+			 * maximum number of master interfaces that can possibly
+			 * reside on the node.
+			 */
+			node_mcount = (mn_reg_off == MN_RNF_NODEID_OFFSET ? 1 :
+				       ccn_get_rni_mcount(periphbase, node_id));
+
+			/*
+			 * Use this value to increment the maximum possible
+			 * master interfaces in the system.
+			 */
+			num_masters += node_mcount;
+
+			/*
+			 * Update the entry in 'info' for this node ID with
+			 * the maximum number of masters than can sit on
+			 * it. This information will be used to validate the
+			 * node information passed by the platform later.
+			 */
+			info->node_desc[node_id] = node_mcount;
+		}
+	}
+
+	return num_masters;
+}
+
+/*******************************************************************************
+ * This function validates parameters passed by the platform (in a debug build).
+ * It collects information about the maximum number of master interfaces that:
+ * a) the CCN IP can accommodate and
+ * b) can exist on each Request node.
+ * It compares this with the information provided by the platform to determine
+ * the validity of the latter.
+ ******************************************************************************/
+static void __init ccn_validate_plat_params(const ccn_desc_t *plat_desc)
+{
+	unsigned int master_id, num_rn_masters;
+	rn_info_t info = { {0} };
+
+	assert(plat_desc);
+	assert(plat_desc->periphbase);
+	assert(plat_desc->master_to_rn_id_map);
+	assert(plat_desc->num_masters);
+	assert(plat_desc->num_masters < CCN_MAX_RN_MASTERS);
+
+	/*
+	 * Find the number and properties of fully coherent, IO coherent and IO
+	 * coherent + DVM master interfaces
+	 */
+	num_rn_masters = ccn_get_rn_master_info(plat_desc->periphbase, &info);
+	assert(plat_desc->num_masters < num_rn_masters);
+
+	/*
+	 * Iterate through the Request nodes specified by the platform.
+	 * Decrement the count of the masters in the 'info' array for each
+	 * Request node encountered. If the count would drop below 0 then the
+	 * platform's view of this aspect of CCN configuration is incorrect.
+	 */
+	for (master_id = 0; master_id < plat_desc->num_masters; master_id++) {
+		unsigned int node_id;
+
+		node_id = plat_desc->master_to_rn_id_map[master_id];
+		assert(node_id < MAX_RN_NODES);
+		assert(info.node_desc[node_id]);
+		info.node_desc[node_id]--;
+	}
+}
+#endif /* ENABLE_ASSERTIONS */
+
+/*******************************************************************************
+ * This function validates parameters passed by the platform (in a debug build)
+ * and initialises its internal data structures. A lock is required to prevent
+ * simultaneous CCN operations at runtime (only BL31) to add and remove Request
+ * nodes from coherency.
+ ******************************************************************************/
+void __init ccn_init(const ccn_desc_t *plat_desc)
+{
+#if ENABLE_ASSERTIONS
+	ccn_validate_plat_params(plat_desc);
+#endif
+
+	ccn_plat_desc = plat_desc;
+}
+
+/*******************************************************************************
+ * This function converts a bit map of master interface IDs to a bit map of the
+ * Request node IDs that they reside on.
+ ******************************************************************************/
+static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map)
+{
+	unsigned long long rn_id_map = 0;
+	unsigned int node_id, iface_id;
+
+	assert(master_map);
+	assert(ccn_plat_desc);
+
+	FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, master_map) {
+		assert(iface_id < ccn_plat_desc->num_masters);
+
+		/* Convert the master ID into the node ID */
+		node_id = ccn_plat_desc->master_to_rn_id_map[iface_id];
+
+		/* Set the bit corresponding to this node ID */
+		rn_id_map |= (1ULL << node_id);
+	}
+
+	return rn_id_map;
+}
+
+/*******************************************************************************
+ * This function executes the necessary operations to add or remove Request node
+ * IDs specified in the 'rn_id_map' bitmap from the snoop/DVM domains specified
+ * in the 'hn_id_map'. The 'region_id' specifies the ID of the first HN-F/MN
+ * on which the operation should be performed. 'op_reg_offset' specifies the
+ * type of operation (add/remove). 'stat_reg_offset' specifies the register
+ * which should be polled to determine if the operation has completed or not.
+ ******************************************************************************/
+static void ccn_snoop_dvm_do_op(unsigned long long rn_id_map,
+				unsigned long long hn_id_map,
+				unsigned int region_id,
+				unsigned int op_reg_offset,
+				unsigned int stat_reg_offset)
+{
+	unsigned int start_region_id;
+
+	assert(ccn_plat_desc);
+	assert(ccn_plat_desc->periphbase);
+
+#if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
+	bakery_lock_get(&ccn_lock);
+#endif
+	start_region_id = region_id;
+	FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) {
+		ccn_reg_write(ccn_plat_desc->periphbase,
+			      start_region_id,
+			      op_reg_offset,
+			      rn_id_map);
+	}
+
+	start_region_id = region_id;
+
+	FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) {
+		WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(start_region_id,
+						   stat_reg_offset,
+						   op_reg_offset,
+						   rn_id_map);
+	}
+
+#if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
+	bakery_lock_release(&ccn_lock);
+#endif
+}
+
+/*******************************************************************************
+ * The following functions provide the boot and runtime API to the platform for
+ * adding and removing master interfaces from the snoop/DVM domains. A bitmap of
+ * master interfaces IDs is passed as a parameter. It is converted into a bitmap
+ * of Request node IDs using the mapping provided by the platform while
+ * initialising the driver.
+ * For example, consider a dual cluster system where the clusters have values 0
+ * & 1 in the affinity level 1 field of their respective MPIDRs. While
+ * initialising this driver, the platform provides the mapping between each
+ * cluster and the corresponding Request node. To add or remove a cluster from
+ * the snoop and dvm domain, the bit position corresponding to the cluster ID
+ * should be set in the 'master_iface_map' i.e. to remove both clusters the
+ * bitmap would equal 0x11.
+ ******************************************************************************/
+void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map)
+{
+	unsigned long long rn_id_map;
+
+	rn_id_map = ccn_master_to_rn_id_map(master_iface_map);
+	ccn_snoop_dvm_do_op(rn_id_map,
+			    CCN_GET_HN_NODEID_MAP(ccn_plat_desc->periphbase,
+						  MN_HNF_NODEID_OFFSET),
+			    HNF_REGION_ID_START,
+			    HNF_SDC_SET_OFFSET,
+			    HNF_SDC_STAT_OFFSET);
+
+	ccn_snoop_dvm_do_op(rn_id_map,
+			    CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase),
+			    MN_REGION_ID,
+			    MN_DDC_SET_OFFSET,
+			    MN_DDC_STAT_OFFSET);
+}
+
+void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map)
+{
+	unsigned long long rn_id_map;
+
+	rn_id_map = ccn_master_to_rn_id_map(master_iface_map);
+	ccn_snoop_dvm_do_op(rn_id_map,
+			    CCN_GET_HN_NODEID_MAP(ccn_plat_desc->periphbase,
+						  MN_HNF_NODEID_OFFSET),
+			    HNF_REGION_ID_START,
+			    HNF_SDC_CLR_OFFSET,
+			    HNF_SDC_STAT_OFFSET);
+
+	ccn_snoop_dvm_do_op(rn_id_map,
+			    CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase),
+			    MN_REGION_ID,
+			    MN_DDC_CLR_OFFSET,
+			    MN_DDC_STAT_OFFSET);
+}
+
+void ccn_enter_dvm_domain(unsigned long long master_iface_map)
+{
+	unsigned long long rn_id_map;
+
+	rn_id_map = ccn_master_to_rn_id_map(master_iface_map);
+	ccn_snoop_dvm_do_op(rn_id_map,
+			    CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase),
+			    MN_REGION_ID,
+			    MN_DDC_SET_OFFSET,
+			    MN_DDC_STAT_OFFSET);
+}
+
+void ccn_exit_dvm_domain(unsigned long long master_iface_map)
+{
+	unsigned long long rn_id_map;
+
+	rn_id_map = ccn_master_to_rn_id_map(master_iface_map);
+	ccn_snoop_dvm_do_op(rn_id_map,
+			    CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase),
+			    MN_REGION_ID,
+			    MN_DDC_CLR_OFFSET,
+			    MN_DDC_STAT_OFFSET);
+}
+
+/*******************************************************************************
+ * This function returns the run mode of all the L3 cache partitions in the
+ * system. The state is expected to be one of NO_L3, SF_ONLY, L3_HAM or
+ * L3_FAM. Instead of comparing the states reported by all HN-Fs, the state of
+ * the first present HN-F node is reported. Since the driver does not export an
+ * interface to program them separately, there is no reason to perform this
+ * check. An HN-F could report that the L3 cache is transitioning from one mode
+ * to another e.g. HNF_PM_NOL3_2_SFONLY. In this case, the function waits for
+ * the transition to complete and reports the final state.
+ ******************************************************************************/
+unsigned int ccn_get_l3_run_mode(void)
+{
+	unsigned long long hnf_pstate_stat;
+
+	assert(ccn_plat_desc);
+	assert(ccn_plat_desc->periphbase);
+
+	/*
+	 * Wait for a L3 cache partition to enter any run mode. The pstate
+	 * parameter is read from an HN-F P-state status register. A non-zero
+	 * value in bits[1:0] means that the cache is transitioning to a run
+	 * mode.
+	 */
+	do {
+		hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase,
+					       HNF_REGION_ID_START,
+					       HNF_PSTATE_STAT_OFFSET);
+	} while (hnf_pstate_stat & 0x3);
+
+	return PSTATE_TO_RUN_MODE(hnf_pstate_stat);
+}
+
+/*******************************************************************************
+ * This function sets the run mode of all the L3 cache partitions in the
+ * system to one of NO_L3, SF_ONLY, L3_HAM or L3_FAM depending upon the state
+ * specified by the 'mode' argument.
+ ******************************************************************************/
+void ccn_set_l3_run_mode(unsigned int mode)
+{
+	unsigned long long mn_hnf_id_map, hnf_pstate_stat;
+	unsigned int region_id;
+
+	assert(ccn_plat_desc);
+	assert(ccn_plat_desc->periphbase);
+	assert(mode <= CCN_L3_RUN_MODE_FAM);
+
+	mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase,
+				     MN_REGION_ID,
+				     MN_HNF_NODEID_OFFSET);
+	region_id = HNF_REGION_ID_START;
+
+	/* Program the desired run mode */
+	FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) {
+		ccn_reg_write(ccn_plat_desc->periphbase,
+			      region_id,
+			      HNF_PSTATE_REQ_OFFSET,
+			      mode);
+	}
+
+	/* Wait for the caches to transition to the run mode */
+	region_id = HNF_REGION_ID_START;
+	FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) {
+		/*
+		 * Wait for a L3 cache partition to enter a target run
+		 * mode. The pstate parameter is read from an HN-F P-state
+		 * status register.
+		 */
+		do {
+			hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase,
+					       region_id,
+					       HNF_PSTATE_STAT_OFFSET);
+		} while (((hnf_pstate_stat & HNF_PSTATE_MASK) >> 2) != mode);
+	}
+}
+
+/*******************************************************************************
+ * This function configures system address map and provides option to enable the
+ * 3SN striping mode of Slave node operation. The Slave node IDs and the Top
+ * Address bit1 and bit0 are provided as parameters to this function. This
+ * configuration is needed only if network contains a single SN-F or 3 SN-F and
+ * must be completed before the first request by the system to normal memory.
+ ******************************************************************************/
+void ccn_program_sys_addrmap(unsigned int sn0_id,
+		 unsigned int sn1_id,
+		 unsigned int sn2_id,
+		 unsigned int top_addr_bit0,
+		 unsigned int top_addr_bit1,
+		 unsigned char three_sn_en)
+{
+	unsigned long long mn_hnf_id_map, hnf_sam_ctrl_value;
+	unsigned int region_id;
+
+	assert(ccn_plat_desc);
+	assert(ccn_plat_desc->periphbase);
+
+	mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase,
+				     MN_REGION_ID,
+				     MN_HNF_NODEID_OFFSET);
+	region_id = HNF_REGION_ID_START;
+	hnf_sam_ctrl_value = MAKE_HNF_SAM_CTRL_VALUE(sn0_id,
+						     sn1_id,
+						     sn2_id,
+						     top_addr_bit0,
+						     top_addr_bit1,
+						     three_sn_en);
+
+	FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) {
+
+		/* Program the SAM control register */
+		ccn_reg_write(ccn_plat_desc->periphbase,
+			      region_id,
+			      HNF_SAM_CTRL_OFFSET,
+			      hnf_sam_ctrl_value);
+	}
+
+}
+
+/*******************************************************************************
+ * This function returns the part0 id from the peripheralID 0 register
+ * in CCN. This id can be used to distinguish the CCN variant present in the
+ * system.
+ ******************************************************************************/
+int ccn_get_part0_id(uintptr_t periphbase)
+{
+	assert(periphbase);
+	return (int)(mmio_read_64(periphbase
+			+ MN_PERIPH_ID_0_1_OFFSET) & 0xFF);
+}
+
+/*******************************************************************************
+ * This function returns the region id corresponding to a node_id of node_type.
+ ******************************************************************************/
+static unsigned int get_region_id_for_node(node_types_t node_type,
+						unsigned int node_id)
+{
+	unsigned int mn_reg_off, region_id;
+	unsigned long long node_bitmap;
+	unsigned int loc_node_id, node_pos_in_map = 0;
+
+	assert(node_type < NUM_NODE_TYPES);
+	assert(node_id < MAX_RN_NODES);
+
+	switch (node_type) {
+	case NODE_TYPE_RNI:
+		region_id = RNI_REGION_ID_START;
+		break;
+	case NODE_TYPE_HNF:
+		region_id = HNF_REGION_ID_START;
+		break;
+	case NODE_TYPE_HNI:
+		region_id = HNI_REGION_ID_START;
+		break;
+	case NODE_TYPE_SN:
+		region_id = SBSX_REGION_ID_START;
+		break;
+	default:
+		ERROR("Un-supported Node Type = %d.\n", node_type);
+		assert(false);
+		return REGION_ID_LIMIT;
+	}
+	/*
+	 * RN-I, HN-F, HN-I, SN node registers in the MN region
+	 * occupy contiguous 16 byte apart offsets.
+	 *
+	 * RN-F and RN-D node are not supported as
+	 * none of them exposes any memory map to
+	 * configure any of their offset registers.
+	 */
+
+	mn_reg_off = MN_RNF_NODEID_OFFSET + (node_type << 4);
+	node_bitmap = ccn_reg_read(ccn_plat_desc->periphbase,
+					MN_REGION_ID, mn_reg_off);
+
+	assert((node_bitmap & (1ULL << (node_id))) != 0U);
+
+
+	FOR_EACH_PRESENT_NODE_ID(loc_node_id, node_bitmap) {
+		INFO("Index = %u with loc_nod=%u and input nod=%u\n",
+					node_pos_in_map, loc_node_id, node_id);
+		if (loc_node_id == node_id)
+			break;
+		node_pos_in_map++;
+	}
+
+	if (node_pos_in_map == CCN_MAX_RN_MASTERS) {
+		ERROR("Node Id = %d, is not found.\n", node_id);
+		assert(false);
+		return REGION_ID_LIMIT;
+	}
+
+	/*
+	 * According to section 3.1.1 in CCN specification, region offset for
+	 * the RN-I components is calculated as (128 + NodeID of RN-I).
+	 */
+	if (node_type == NODE_TYPE_RNI)
+		region_id += node_id;
+	else
+		region_id += node_pos_in_map;
+
+	return region_id;
+}
+
+/*******************************************************************************
+ * This function sets the value 'val' to the register at register_offset from
+ * the base address pointed to by the region_id.
+ * where, region id is mapped to a node_id of node_type.
+ ******************************************************************************/
+void ccn_write_node_reg(node_types_t node_type, unsigned int node_id,
+			unsigned int reg_offset, unsigned long long val)
+{
+	unsigned int region_id = get_region_id_for_node(node_type, node_id);
+
+	if (reg_offset > REGION_ID_OFFSET) {
+		ERROR("Invalid Register offset 0x%x is provided.\n",
+								reg_offset);
+		assert(false);
+		return;
+	}
+
+	/* Setting the value of Auxiliary Control Register of the Node */
+	ccn_reg_write(ccn_plat_desc->periphbase, region_id, reg_offset, val);
+	VERBOSE("Value is successfully written at address 0x%lx.\n",
+			(ccn_plat_desc->periphbase
+			+ region_id_to_base(region_id))
+			+ reg_offset);
+}
+
+/*******************************************************************************
+ * This function read the value 'val' stored in the register at register_offset
+ * from the base address pointed to by the region_id.
+ * where, region id is mapped to a node_id of node_type.
+ ******************************************************************************/
+unsigned long long ccn_read_node_reg(node_types_t node_type,
+					unsigned int node_id,
+					unsigned int reg_offset)
+{
+	unsigned long long val;
+	unsigned int region_id = get_region_id_for_node(node_type, node_id);
+
+	if (reg_offset > REGION_ID_OFFSET) {
+		ERROR("Invalid Register offset 0x%x is provided.\n",
+								reg_offset);
+		assert(false);
+		return ULL(0);
+	}
+
+	/* Setting the value of Auxiliary Control Register of the Node */
+	val = ccn_reg_read(ccn_plat_desc->periphbase, region_id, reg_offset);
+	VERBOSE("Value is successfully read from address 0x%lx.\n",
+			(ccn_plat_desc->periphbase
+			+ region_id_to_base(region_id))
+			+ reg_offset);
+
+	return val;
+}
diff --git a/drivers/arm/ccn/ccn_private.h b/drivers/arm/ccn/ccn_private.h
new file mode 100644
index 0000000..8a936d9
--- /dev/null
+++ b/drivers/arm/ccn/ccn_private.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CCN_PRIVATE_H
+#define CCN_PRIVATE_H
+
+/*
+ * A CCN implementation can have a maximum of 64 Request nodes with node IDs
+ * from 0-63. These IDs are split across the three types of Request nodes
+ * i.e. RN-F, RN-D and RN-I.
+ */
+#define MAX_RN_NODES		64
+
+/* Enum used to loop through the 3 types of Request nodes */
+typedef enum rn_types {
+	RN_TYPE_RNF = 0,
+	RN_TYPE_RNI,
+	RN_TYPE_RND,
+	NUM_RN_TYPES
+} rn_types_t;
+
+/* Macro to convert a region id to its base address */
+#define region_id_to_base(id)	((id) << 16)
+
+/*
+ * Macro to calculate the number of master interfaces resident on a RN-I/RN-D.
+ * Value of first two bits of the RN-I/D node type + 1 == Maximum number of
+ * ACE-Lite or ACE-Lite+DVM interfaces supported on this node. E.g.
+ *
+ * 0x14 : RN-I with 1 ACE-Lite interface
+ * 0x15 : RN-I with 2 ACE-Lite interfaces
+ * 0x16 : RN-I with 3 ACE-Lite interfaces
+ */
+#define rn_type_id_to_master_cnt(id)	(((id) & 0x3) + 1)
+
+/*
+ * Constants used to identify a region in the programmer's view. These are
+ * common for all regions.
+ */
+#define REGION_ID_LIMIT		256
+#define REGION_ID_OFFSET	0xFF00
+
+#define REGION_NODE_ID_SHIFT	8
+#define REGION_NODE_ID_MASK	0x7f
+#define get_node_id(id_reg)	(((id_reg) >> REGION_NODE_ID_SHIFT) \
+				 & REGION_NODE_ID_MASK)
+
+#define REGION_NODE_TYPE_SHIFT	0
+#define REGION_NODE_TYPE_MASK	0x1f
+#define get_node_type(id_reg)	(((id_reg) >> REGION_NODE_TYPE_SHIFT) \
+				 & REGION_NODE_TYPE_MASK)
+
+/* Common offsets of registers to enter or exit a snoop/dvm domain */
+#define DOMAIN_CTRL_STAT_OFFSET	0x0200
+#define DOMAIN_CTRL_SET_OFFSET	0x0210
+#define DOMAIN_CTRL_CLR_OFFSET	0x0220
+
+/*
+ * Thess macros are used to determine if an operation to add or remove a Request
+ * node from the snoop/dvm domain has completed. 'rn_id_map' is a bit map of
+ * nodes. It was used to program the SET or CLEAR control register. The type of
+ * register is specified by 'op_reg_offset'. 'status_reg' is the bit map of
+ * nodes currently present in the snoop/dvm domain. 'rn_id_map' and 'status_reg'
+ * are logically ANDed and the result it stored back in the 'status_reg'. There
+ * are two outcomes of this operation:
+ *
+ * 1. If the DOMAIN_CTRL_SET_OFFSET register was programmed, then the set bits in
+ *    'rn_id_map' should appear in 'status_reg' when the operation completes. So
+ *    after the AND operation, at some point of time 'status_reg' should equal
+ *    'rn_id_map'.
+ *
+ * 2. If the DOMAIN_CTRL_CLR_OFFSET register was programmed, then the set bits in
+ *    'rn_id_map' should disappear in 'status_reg' when the operation
+ *    completes. So after the AND operation, at some point of time 'status_reg'
+ *    should equal 0.
+ */
+#define WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(region_id, stat_reg_offset,		\
+					   op_reg_offset, rn_id_map)		\
+	{									\
+		unsigned long long status_reg;						\
+		do {								\
+			status_reg = ccn_reg_read((ccn_plat_desc->periphbase),	\
+						  (region_id),			\
+						  (stat_reg_offset));		\
+			status_reg &= (rn_id_map);				\
+		} while ((op_reg_offset) == DOMAIN_CTRL_SET_OFFSET ?		\
+			 (rn_id_map) != status_reg : status_reg);		\
+	}
+
+/*
+ * Region ID of the Miscellaneous Node is always 0 as its located at the base of
+ * the programmer's view.
+ */
+#define MN_REGION_ID		0
+
+#define MN_REGION_ID_START	0
+#define DEBUG_REGION_ID_START	1
+#define HNI_REGION_ID_START	8
+#define SBSX_REGION_ID_START	16
+#define HNF_REGION_ID_START	32
+#define XP_REGION_ID_START	64
+#define RNI_REGION_ID_START	128
+
+/* Selected register offsets from the base of a HNF region */
+#define HNF_CFG_CTRL_OFFSET	0x0000
+#define HNF_SAM_CTRL_OFFSET	0x0008
+#define HNF_PSTATE_REQ_OFFSET	0x0010
+#define HNF_PSTATE_STAT_OFFSET	0x0018
+#define HNF_SDC_STAT_OFFSET	DOMAIN_CTRL_STAT_OFFSET
+#define HNF_SDC_SET_OFFSET	DOMAIN_CTRL_SET_OFFSET
+#define HNF_SDC_CLR_OFFSET	DOMAIN_CTRL_CLR_OFFSET
+#define HNF_AUX_CTRL_OFFSET	0x0500
+
+/* Selected register offsets from the base of a MN region */
+#define MN_SAR_OFFSET		0x0000
+#define MN_RNF_NODEID_OFFSET	0x0180
+#define MN_RNI_NODEID_OFFSET	0x0190
+#define MN_RND_NODEID_OFFSET	0x01A0
+#define MN_HNF_NODEID_OFFSET	0x01B0
+#define MN_HNI_NODEID_OFFSET	0x01C0
+#define MN_SN_NODEID_OFFSET	0x01D0
+#define MN_DDC_STAT_OFFSET	DOMAIN_CTRL_STAT_OFFSET
+#define MN_DDC_SET_OFFSET	DOMAIN_CTRL_SET_OFFSET
+#define MN_DDC_CLR_OFFSET	DOMAIN_CTRL_CLR_OFFSET
+#define MN_PERIPH_ID_0_1_OFFSET	0xFE0
+#define MN_ID_OFFSET		REGION_ID_OFFSET
+
+/* HNF System Address Map register bit masks and shifts */
+#define HNF_SAM_CTRL_SN_ID_MASK		0x7f
+#define HNF_SAM_CTRL_SN0_ID_SHIFT	0
+#define HNF_SAM_CTRL_SN1_ID_SHIFT	8
+#define HNF_SAM_CTRL_SN2_ID_SHIFT	16
+
+#define HNF_SAM_CTRL_TAB0_MASK		ULL(0x3f)
+#define HNF_SAM_CTRL_TAB0_SHIFT		48
+#define HNF_SAM_CTRL_TAB1_MASK		ULL(0x3f)
+#define HNF_SAM_CTRL_TAB1_SHIFT		56
+
+#define HNF_SAM_CTRL_3SN_ENB_SHIFT	32
+#define HNF_SAM_CTRL_3SN_ENB_MASK	ULL(0x01)
+
+/*
+ * Macro to create a value suitable for programming into a HNF SAM Control
+ * register for enabling 3SN striping.
+ */
+#define MAKE_HNF_SAM_CTRL_VALUE(sn0, sn1, sn2, tab0, tab1, three_sn_en)     \
+	((((sn0) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN0_ID_SHIFT) | \
+	 (((sn1) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN1_ID_SHIFT) | \
+	 (((sn2) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN2_ID_SHIFT) | \
+	 (((tab0) & HNF_SAM_CTRL_TAB0_MASK) << HNF_SAM_CTRL_TAB0_SHIFT)   | \
+	 (((tab1) & HNF_SAM_CTRL_TAB1_MASK) << HNF_SAM_CTRL_TAB1_SHIFT)   | \
+	 (((three_sn_en) & HNF_SAM_CTRL_3SN_ENB_MASK) << HNF_SAM_CTRL_3SN_ENB_SHIFT))
+
+/* Mask to read the power state value from an HN-F P-state register */
+#define HNF_PSTATE_MASK		0xf
+
+/* Macro to extract the run mode from a p-state value */
+#define PSTATE_TO_RUN_MODE(pstate)	(((pstate) & HNF_PSTATE_MASK) >> 2)
+
+/*
+ * Helper macro that iterates through a given bit map. In each iteration,
+ * it returns the position of the set bit.
+ * It can be used by other utility macros to iterates through all nodes
+ * or masters given a bit map of them.
+ */
+#define FOR_EACH_BIT(bit_pos, bit_map)			\
+	for (bit_pos = __builtin_ctzll(bit_map);	\
+	     bit_map;					\
+	     bit_map &= ~(1ULL << (bit_pos)),		\
+	     bit_pos = __builtin_ctzll(bit_map))
+
+/*
+ * Utility macro that iterates through a bit map of node IDs. In each
+ * iteration, it returns the ID of the next present node in the bit map. Node
+ * ID of a present node == Position of set bit == Number of zeroes trailing the
+ * bit.
+ */
+#define FOR_EACH_PRESENT_NODE_ID(node_id, bit_map)	\
+		FOR_EACH_BIT(node_id, bit_map)
+
+/*
+ * Helper function to return number of set bits in bitmap
+ */
+static inline unsigned int count_set_bits(unsigned long long bitmap)
+{
+	unsigned int count = 0;
+
+	for (; bitmap; bitmap &= bitmap - 1)
+		++count;
+
+	return count;
+}
+
+/*
+ * Utility macro that iterates through a bit map of node IDs. In each iteration,
+ * it returns the ID of the next present region corresponding to a node present
+ * in the bit map. Region ID of a present node is in between passed region id
+ * and region id + number of set bits in the bitmap i.e. the number of present
+ * nodes.
+ */
+#define FOR_EACH_PRESENT_REGION_ID(region_id, bit_map)				\
+	for (unsigned long long region_id_limit = count_set_bits(bit_map)	\
+							+ region_id;		\
+	    region_id < region_id_limit;					\
+	    region_id++)
+
+/*
+ * Same macro as FOR_EACH_PRESENT_NODE, but renamed to indicate it traverses
+ * through a bit map of master interfaces.
+ */
+#define FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, bit_map)	\
+			FOR_EACH_BIT(iface_id, bit_map)
+
+/*
+ * Macro that returns the node id bit map for the Miscellaneous Node
+ */
+#define CCN_GET_MN_NODEID_MAP(periphbase)				\
+	(1 << get_node_id(ccn_reg_read(periphbase, MN_REGION_ID,	\
+						REGION_ID_OFFSET)))
+
+/*
+ * This macro returns the bitmap of Home nodes on the basis of the
+ * 'mn_hn_id_reg_offset' parameter from the Miscellaneous node's (MN)
+ * programmer's view. The MN has a register which carries the bitmap of present
+ * Home nodes of each type i.e. HN-Fs, HN-Is & HN-Ds.
+ */
+#define CCN_GET_HN_NODEID_MAP(periphbase, mn_hn_id_reg_offset)		\
+	ccn_reg_read(periphbase, MN_REGION_ID, mn_hn_id_reg_offset)
+
+#endif /* CCN_PRIVATE_H */
diff --git a/drivers/arm/css/mhu/css_mhu.c b/drivers/arm/css/mhu/css_mhu.c
new file mode 100644
index 0000000..b7faf7e
--- /dev/null
+++ b/drivers/arm/css/mhu/css_mhu.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* SCP MHU secure channel registers */
+#define SCP_INTR_S_STAT		0x200
+#define SCP_INTR_S_SET		0x208
+#define SCP_INTR_S_CLEAR	0x210
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT		0x300
+#define CPU_INTR_S_SET		0x308
+#define CPU_INTR_S_CLEAR	0x310
+
+ARM_INSTANTIATE_LOCK;
+
+/* Weak definition may be overridden in specific CSS based platform */
+#pragma weak plat_arm_pwrc_setup
+
+
+/*
+ * Slot 31 is reserved because the MHU hardware uses this register bit to
+ * indicate a non-secure access attempt. The total number of available slots is
+ * therefore 31 [30:0].
+ */
+#define MHU_MAX_SLOT_ID		30
+
+void mhu_secure_message_start(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+
+	arm_lock_get();
+
+	/* Make sure any previous command has finished */
+	while (mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) &
+							(1 << slot_id))
+		;
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+	assert(!(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) &
+							(1 << slot_id)));
+
+	/* Send command to SCP */
+	mmio_write_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+	/* Wait for response from SCP */
+	uint32_t response;
+	while (!(response = mmio_read_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_STAT)))
+		;
+
+	return response;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+
+	/*
+	 * Clear any response we got by writing one in the relevant slot bit to
+	 * the CLEAR register
+	 */
+	mmio_write_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
+
+	arm_lock_release();
+}
+
+void __init mhu_secure_init(void)
+{
+	arm_lock_init();
+
+	/*
+	 * The STAT register resets to zero. Ensure it is in the expected state,
+	 * as a stale or garbage value would make us think it's a message we've
+	 * already sent.
+	 */
+	assert(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) == 0);
+}
+
+void __init plat_arm_pwrc_setup(void)
+{
+	mhu_secure_init();
+}
diff --git a/drivers/arm/css/mhu/css_mhu_doorbell.c b/drivers/arm/css/mhu/css_mhu_doorbell.c
new file mode 100644
index 0000000..8858742
--- /dev/null
+++ b/drivers/arm/css/mhu/css_mhu_doorbell.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+
+void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info)
+{
+	MHU_RING_DOORBELL(plat_info->db_reg_addr,
+			plat_info->db_modify_mask,
+			plat_info->db_preserve_mask);
+	return;
+}
+
+void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info)
+{
+	/* wake receiver */
+	MHU_V2_ACCESS_REQUEST(MHUV2_BASE_ADDR);
+
+	/* wait for receiver to acknowledge its ready */
+	while (MHU_V2_IS_ACCESS_READY(MHUV2_BASE_ADDR) == 0)
+		;
+
+	MHU_RING_DOORBELL(plat_info->db_reg_addr,
+			plat_info->db_modify_mask,
+			plat_info->db_preserve_mask);
+
+	/* clear the access request for the receiver */
+	MHU_V2_CLEAR_REQUEST(MHUV2_BASE_ADDR);
+
+	return;
+}
diff --git a/drivers/arm/css/scmi/scmi_ap_core_proto.c b/drivers/arm/css/scmi/scmi_ap_core_proto.c
new file mode 100644
index 0000000..5941b87
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_ap_core_proto.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI AP core reset address and attributes
+ */
+int scmi_ap_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t attr)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID,
+			SCMI_AP_CORE_RESET_ADDR_SET_MSG, token);
+	mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG3(mbx_mem->payload, reset_addr & 0xffffffff,
+		reset_addr >> 32, attr);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+	assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to get the SCMI AP core reset address and attributes
+ */
+int scmi_ap_core_get_reset_addr(void *p, uint64_t *reset_addr, uint32_t *attr)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+	uint32_t lo_addr, hi_addr;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID,
+			SCMI_AP_CORE_RESET_ADDR_GET_MSG, token);
+	mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL4(mbx_mem->payload, ret, lo_addr, hi_addr, *attr);
+	*reset_addr = lo_addr | (uint64_t)hi_addr << 32;
+	assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
diff --git a/drivers/arm/css/scmi/scmi_common.c b/drivers/arm/css/scmi/scmi_common.c
new file mode 100644
index 0000000..5b3724a
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_common.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+#if HW_ASSISTED_COHERENCY
+#define scmi_lock_init(lock)
+#define scmi_lock_get(lock)		spin_lock(lock)
+#define scmi_lock_release(lock)		spin_unlock(lock)
+#else
+#define scmi_lock_init(lock)		bakery_lock_init(lock)
+#define scmi_lock_get(lock)		bakery_lock_get(lock)
+#define scmi_lock_release(lock)		bakery_lock_release(lock)
+#endif
+
+
+/*
+ * Private helper function to get exclusive access to SCMI channel.
+ */
+void scmi_get_channel(scmi_channel_t *ch)
+{
+	assert(ch->lock);
+	scmi_lock_get(ch->lock);
+
+	/* Make sure any previous command has finished */
+	assert(SCMI_IS_CHANNEL_FREE(
+			((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status));
+}
+
+/*
+ * Private helper function to transfer ownership of channel from AP to SCP.
+ */
+void scmi_send_sync_command(scmi_channel_t *ch)
+{
+	mailbox_mem_t *mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+
+	SCMI_MARK_CHANNEL_BUSY(mbx_mem->status);
+
+	/*
+	 * Ensure that any write to the SCMI payload area is seen by SCP before
+	 * we write to the doorbell register. If these 2 writes were reordered
+	 * by the CPU then SCP would read stale payload data
+	 */
+	dmbst();
+
+	ch->info->ring_doorbell(ch->info);
+	/*
+	 * Ensure that the write to the doorbell register is ordered prior to
+	 * checking whether the channel is free.
+	 */
+	dmbsy();
+
+	/* Wait for channel to be free */
+	while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status))
+		;
+
+	/*
+	 * Ensure that any read to the SCMI payload area is done after reading
+	 * mailbox status. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data
+	 */
+	dmbld();
+}
+
+/*
+ * Private helper function to release exclusive access to SCMI channel.
+ */
+void scmi_put_channel(scmi_channel_t *ch)
+{
+	/* Make sure any previous command has finished */
+	assert(SCMI_IS_CHANNEL_FREE(
+			((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status));
+
+	assert(ch->lock);
+	scmi_lock_release(ch->lock);
+}
+
+/*
+ * API to query the SCMI protocol version.
+ */
+int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, SCMI_PROTO_VERSION_MSG,
+							token);
+	mbx_mem->len = SCMI_PROTO_VERSION_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *version);
+	assert(mbx_mem->len == SCMI_PROTO_VERSION_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to query the protocol message attributes for a SCMI protocol.
+ */
+int scmi_proto_msg_attr(void *p, uint32_t proto_id,
+		uint32_t command_id, uint32_t *attr)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id,
+				SCMI_PROTO_MSG_ATTR_MSG, token);
+	mbx_mem->len = SCMI_PROTO_MSG_ATTR_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG1(mbx_mem->payload, command_id);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *attr);
+	assert(mbx_mem->len == SCMI_PROTO_MSG_ATTR_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * SCMI Driver initialization API. Returns initialized channel on success
+ * or NULL on error. The return type is an opaque void pointer.
+ */
+void *scmi_init(scmi_channel_t *ch)
+{
+	uint32_t version;
+	int ret;
+
+	assert(ch && ch->info);
+	assert(ch->info->db_reg_addr);
+	assert(ch->info->db_modify_mask);
+	assert(ch->info->db_preserve_mask);
+	assert(ch->info->ring_doorbell != NULL);
+
+	assert(ch->lock);
+
+	scmi_lock_init(ch->lock);
+
+	ch->is_initialized = 1;
+
+	ret = scmi_proto_version(ch, SCMI_PWR_DMN_PROTO_ID, &version);
+	if (ret != SCMI_E_SUCCESS) {
+		WARN("SCMI power domain protocol version message failed");
+		goto error;
+	}
+
+	if (!is_scmi_version_compatible(SCMI_PWR_DMN_PROTO_VER, version)) {
+		WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x",
+			version, SCMI_PWR_DMN_PROTO_VER);
+		goto error;
+	}
+
+	VERBOSE("SCMI power domain protocol version 0x%x detected\n", version);
+
+	ret = scmi_proto_version(ch, SCMI_SYS_PWR_PROTO_ID, &version);
+	if ((ret != SCMI_E_SUCCESS)) {
+		WARN("SCMI system power protocol version message failed");
+		goto error;
+	}
+
+	if (!is_scmi_version_compatible(SCMI_SYS_PWR_PROTO_VER, version)) {
+		WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x",
+			version, SCMI_SYS_PWR_PROTO_VER);
+		goto error;
+	}
+
+	VERBOSE("SCMI system power management protocol version 0x%x detected\n",
+						version);
+
+	INFO("SCMI driver initialized\n");
+
+	return (void *)ch;
+
+error:
+	ch->is_initialized = 0;
+	return NULL;
+}
diff --git a/drivers/arm/css/scmi/scmi_private.h b/drivers/arm/css/scmi/scmi_private.h
new file mode 100644
index 0000000..61437f6
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_private.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCMI_PRIVATE_H
+#define SCMI_PRIVATE_H
+
+#include <lib/mmio.h>
+
+/*
+ * SCMI power domain management protocol message and response lengths. It is
+ * calculated as sum of length in bytes of the message header (4) and payload
+ * area (the number of bytes of parameters or return values in the payload).
+ */
+#define SCMI_PROTO_VERSION_MSG_LEN		4
+#define SCMI_PROTO_VERSION_RESP_LEN		12
+
+#define SCMI_PROTO_MSG_ATTR_MSG_LEN		8
+#define SCMI_PROTO_MSG_ATTR_RESP_LEN		12
+
+#define SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN	16
+#define SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN	8
+
+#define SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN	4
+#define SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN	20
+
+#define SCMI_PWR_STATE_SET_MSG_LEN		16
+#define SCMI_PWR_STATE_SET_RESP_LEN		8
+
+#define SCMI_PWR_STATE_GET_MSG_LEN		8
+#define SCMI_PWR_STATE_GET_RESP_LEN		12
+
+#define SCMI_SYS_PWR_STATE_SET_MSG_LEN		12
+#define SCMI_SYS_PWR_STATE_SET_RESP_LEN		8
+
+#define SCMI_SYS_PWR_STATE_GET_MSG_LEN		4
+#define SCMI_SYS_PWR_STATE_GET_RESP_LEN		12
+
+/* SCMI message header format bit field */
+#define SCMI_MSG_ID_SHIFT		0
+#define SCMI_MSG_ID_WIDTH		8
+#define SCMI_MSG_ID_MASK		((1 << SCMI_MSG_ID_WIDTH) - 1)
+
+#define SCMI_MSG_TYPE_SHIFT		8
+#define SCMI_MSG_TYPE_WIDTH		2
+#define SCMI_MSG_TYPE_MASK		((1 << SCMI_MSG_TYPE_WIDTH) - 1)
+
+#define SCMI_MSG_PROTO_ID_SHIFT		10
+#define SCMI_MSG_PROTO_ID_WIDTH		8
+#define SCMI_MSG_PROTO_ID_MASK		((1 << SCMI_MSG_PROTO_ID_WIDTH) - 1)
+
+#define SCMI_MSG_TOKEN_SHIFT		18
+#define SCMI_MSG_TOKEN_WIDTH		10
+#define SCMI_MSG_TOKEN_MASK		((1 << SCMI_MSG_TOKEN_WIDTH) - 1)
+
+
+/* SCMI mailbox flags */
+#define SCMI_FLAG_RESP_POLL	0
+#define SCMI_FLAG_RESP_INT	1
+
+/* SCMI power domain protocol `POWER_STATE_SET` message flags */
+#define SCMI_PWR_STATE_SET_FLAG_SYNC	0
+#define SCMI_PWR_STATE_SET_FLAG_ASYNC	1
+
+/*
+ * Helper macro to create an SCMI message header given protocol, message id
+ * and token.
+ */
+#define SCMI_MSG_CREATE(_protocol, _msg_id, _token)				\
+	((((_protocol) & SCMI_MSG_PROTO_ID_MASK) << SCMI_MSG_PROTO_ID_SHIFT) |	\
+	(((_msg_id) & SCMI_MSG_ID_MASK) << SCMI_MSG_ID_SHIFT) |			\
+	(((_token) & SCMI_MSG_TOKEN_MASK) << SCMI_MSG_TOKEN_SHIFT))
+
+/* Helper macro to get the token from a SCMI message header */
+#define SCMI_MSG_GET_TOKEN(_msg)				\
+	(((_msg) >> SCMI_MSG_TOKEN_SHIFT) & SCMI_MSG_TOKEN_MASK)
+
+/* SCMI Channel Status bit fields */
+#define SCMI_CH_STATUS_RES0_MASK	0xFFFFFFFE
+#define SCMI_CH_STATUS_FREE_SHIFT	0
+#define SCMI_CH_STATUS_FREE_WIDTH	1
+#define SCMI_CH_STATUS_FREE_MASK	((1 << SCMI_CH_STATUS_FREE_WIDTH) - 1)
+
+/* Helper macros to check and write the channel status */
+#define SCMI_IS_CHANNEL_FREE(status)					\
+	(!!(((status) >> SCMI_CH_STATUS_FREE_SHIFT) & SCMI_CH_STATUS_FREE_MASK))
+
+#define SCMI_MARK_CHANNEL_BUSY(status)	do {				\
+		assert(SCMI_IS_CHANNEL_FREE(status));			\
+		(status) &= ~(SCMI_CH_STATUS_FREE_MASK <<		\
+				SCMI_CH_STATUS_FREE_SHIFT);		\
+	} while (0)
+
+/* Helper macros to copy arguments to the mailbox payload */
+#define SCMI_PAYLOAD_ARG1(payld_arr, arg1)				\
+		mmio_write_32((uintptr_t)&payld_arr[0], arg1)
+
+#define SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2)	do {		\
+		SCMI_PAYLOAD_ARG1(payld_arr, arg1);			\
+		mmio_write_32((uintptr_t)&payld_arr[1], arg2);		\
+	} while (0)
+
+#define SCMI_PAYLOAD_ARG3(payld_arr, arg1, arg2, arg3)	do {		\
+		SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2);		\
+		mmio_write_32((uintptr_t)&payld_arr[2], arg3);		\
+	} while (0)
+
+/* Helper macros to read return values from the mailbox payload */
+#define SCMI_PAYLOAD_RET_VAL1(payld_arr, val1)				\
+		(val1) = mmio_read_32((uintptr_t)&payld_arr[0])
+
+#define SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2)	do {		\
+		SCMI_PAYLOAD_RET_VAL1(payld_arr, val1);			\
+		(val2) = mmio_read_32((uintptr_t)&payld_arr[1]);	\
+	} while (0)
+
+#define SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3)	do {	\
+		SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2);		\
+		(val3) = mmio_read_32((uintptr_t)&payld_arr[2]);	\
+	} while (0)
+
+#define SCMI_PAYLOAD_RET_VAL4(payld_arr, val1, val2, val3, val4)	do {	\
+		SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3);		\
+		(val4) = mmio_read_32((uintptr_t)&payld_arr[3]);		\
+	} while (0)
+
+/*
+ * Private data structure for representing the mailbox memory layout. Refer
+ * the SCMI specification for more details.
+ */
+typedef struct mailbox_mem {
+	uint32_t res_a; /* Reserved */
+	volatile uint32_t status;
+	uint64_t res_b; /* Reserved */
+	uint32_t flags;
+	volatile uint32_t len;
+	uint32_t msg_header;
+	uint32_t payload[];
+} mailbox_mem_t;
+
+
+/* Private APIs for use within SCMI driver */
+void scmi_get_channel(scmi_channel_t *ch);
+void scmi_send_sync_command(scmi_channel_t *ch);
+void scmi_put_channel(scmi_channel_t *ch);
+
+static inline void validate_scmi_channel(scmi_channel_t *ch)
+{
+	assert(ch && ch->is_initialized);
+	assert(ch->info && ch->info->scmi_mbx_mem);
+}
+
+/*
+ * SCMI vendor specific protocol
+ */
+#define SCMI_SYS_VENDOR_EXT_PROTO_ID		0x80
+
+#endif /* SCMI_PRIVATE_H */
diff --git a/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c
new file mode 100644
index 0000000..a342aa8
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI power domain power state.
+ */
+int scmi_pwr_state_set(void *p, uint32_t domain_id,
+					uint32_t scmi_pwr_state)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+
+	/*
+	 * Only asynchronous mode of `set power state` command is allowed on
+	 * application processors.
+	 */
+	uint32_t pwr_state_set_msg_flag = SCMI_PWR_STATE_SET_FLAG_ASYNC;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID,
+			SCMI_PWR_STATE_SET_MSG, token);
+	mbx_mem->len = SCMI_PWR_STATE_SET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG3(mbx_mem->payload, pwr_state_set_msg_flag,
+						domain_id, scmi_pwr_state);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+	assert(mbx_mem->len == SCMI_PWR_STATE_SET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to get the SCMI power domain power state.
+ */
+int scmi_pwr_state_get(void *p, uint32_t domain_id,
+					uint32_t *scmi_pwr_state)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID,
+			SCMI_PWR_STATE_GET_MSG, token);
+	mbx_mem->len = SCMI_PWR_STATE_GET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG1(mbx_mem->payload, domain_id);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *scmi_pwr_state);
+	assert(mbx_mem->len == SCMI_PWR_STATE_GET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
diff --git a/drivers/arm/css/scmi/scmi_sys_pwr_proto.c b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c
new file mode 100644
index 0000000..c8e62d1
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI system power state
+ */
+int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID,
+			SCMI_SYS_PWR_STATE_SET_MSG, token);
+	mbx_mem->len = SCMI_SYS_PWR_STATE_SET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG2(mbx_mem->payload, flags, system_state);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+	assert(mbx_mem->len == SCMI_SYS_PWR_STATE_SET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to get the SCMI system power state
+ */
+int scmi_sys_pwr_state_get(void *p, uint32_t *system_state)
+{
+	mailbox_mem_t *mbx_mem;
+	unsigned int token = 0;
+	int ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID,
+			SCMI_SYS_PWR_STATE_GET_MSG, token);
+	mbx_mem->len = SCMI_SYS_PWR_STATE_GET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *system_state);
+	assert(mbx_mem->len == SCMI_SYS_PWR_STATE_GET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.c b/drivers/arm/css/scmi/vendor/scmi_sq.c
new file mode 100644
index 0000000..f185424
--- /dev/null
+++ b/drivers/arm/css/scmi/vendor/scmi_sq.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+#include "scmi_sq.h"
+
+#include <sq_common.h>
+
+/* SCMI messge ID to get the available DRAM region */
+#define SCMI_VENDOR_EXT_MEMINFO_GET_MSG		0x3
+
+#define SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN	4
+
+/*
+ * API to get the available DRAM region
+ */
+int scmi_get_draminfo(void *p, struct draminfo *info)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+	struct dram_info_resp response;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_VENDOR_EXT_PROTO_ID,
+			SCMI_VENDOR_EXT_MEMINFO_GET_MSG, token);
+	mbx_mem->len = SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+	scmi_send_sync_command(ch);
+
+	/*
+	 * Ensure that any read to the SCPI payload area is done after reading
+	 * the MHU register. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data
+	 */
+	dmbld();
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+
+	memcpy(&response, (void *)mbx_mem->payload, sizeof(response));
+
+	scmi_put_channel(ch);
+
+	*info = response.info;
+
+	return ret;
+}
diff --git a/drivers/arm/css/scmi/vendor/scmi_sq.h b/drivers/arm/css/scmi/vendor/scmi_sq.h
new file mode 100644
index 0000000..aee1a3a
--- /dev/null
+++ b/drivers/arm/css/scmi/vendor/scmi_sq.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCMI_SQ_H
+#define SCMI_SQ_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <sq_common.h>
+
+/* Structure to represent available DRAM region */
+struct dram_info_resp {
+	int status;
+	int reserved;
+	struct draminfo info;
+};
+
+/* API to get the available DRAM region */
+int scmi_get_draminfo(void *p, struct draminfo *info);
+
+#endif /* SCMI_SQ_H */
diff --git a/drivers/arm/css/scp/css_bom_bootloader.c b/drivers/arm/css/scp/css_bom_bootloader.c
new file mode 100644
index 0000000..1fc1270
--- /dev/null
+++ b/drivers/arm/css/scp/css_bom_bootloader.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/* ID of the MHU slot used for the BOM protocol */
+#define BOM_MHU_SLOT_ID		0
+
+/* Boot commands sent from AP -> SCP */
+#define BOOT_CMD_INFO	0x00
+#define BOOT_CMD_DATA	0x01
+
+/* BOM command header */
+typedef struct {
+	uint32_t id : 8;
+	uint32_t reserved : 24;
+} bom_cmd_t;
+
+typedef struct {
+	uint32_t image_size;
+	uint32_t checksum;
+} cmd_info_payload_t;
+
+/*
+ * Unlike the SCPI protocol, the boot protocol uses the same memory region
+ * for both AP -> SCP and SCP -> AP transfers; define the address of this...
+ */
+#define BOM_SHARED_MEM		PLAT_CSS_SCP_COM_SHARED_MEM_BASE
+#define BOM_CMD_HEADER		((bom_cmd_t *) BOM_SHARED_MEM)
+#define BOM_CMD_PAYLOAD		((void *) (BOM_SHARED_MEM + sizeof(bom_cmd_t)))
+
+typedef struct {
+	/* Offset from the base address of the Trusted RAM */
+	uint32_t offset;
+	uint32_t block_size;
+} cmd_data_payload_t;
+
+/*
+ * All CSS platforms load SCP_BL2/SCP_BL2U just below BL2 (this is where BL31
+ * usually resides except when ARM_BL31_IN_DRAM is
+ * set). Ensure that SCP_BL2/SCP_BL2U do not overflow into shared RAM and
+ * the tb_fw_config.
+ */
+CASSERT(SCP_BL2_LIMIT <= BL2_BASE, assert_scp_bl2_overwrite_bl2);
+CASSERT(SCP_BL2U_LIMIT <= BL2_BASE, assert_scp_bl2u_overwrite_bl2);
+
+CASSERT(SCP_BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2_overflow);
+CASSERT(SCP_BL2U_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2u_overflow);
+
+static void scp_boot_message_start(void)
+{
+	mhu_secure_message_start(BOM_MHU_SLOT_ID);
+}
+
+static void scp_boot_message_send(size_t payload_size)
+{
+	/* Ensure that any write to the BOM payload area is seen by SCP before
+	 * we write to the MHU register. If these 2 writes were reordered by
+	 * the CPU then SCP would read stale payload data */
+	dmbst();
+
+	/* Send command to SCP */
+	mhu_secure_message_send(BOM_MHU_SLOT_ID);
+}
+
+static uint32_t scp_boot_message_wait(size_t size)
+{
+	uint32_t mhu_status;
+
+	mhu_status = mhu_secure_message_wait();
+
+	/* Expect an SCP Boot Protocol message, reject any other protocol */
+	if (mhu_status != (1 << BOM_MHU_SLOT_ID)) {
+		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+			mhu_status);
+		panic();
+	}
+
+	/* Ensure that any read to the BOM payload area is done after reading
+	 * the MHU register. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data */
+	dmbld();
+
+	return *(uint32_t *) BOM_SHARED_MEM;
+}
+
+static void scp_boot_message_end(void)
+{
+	mhu_secure_message_end(BOM_MHU_SLOT_ID);
+}
+
+int css_scp_boot_image_xfer(void *image, unsigned int image_size)
+{
+	uint32_t response;
+	uint32_t checksum;
+	cmd_info_payload_t *cmd_info_payload;
+	cmd_data_payload_t *cmd_data_payload;
+
+	assert((uintptr_t) image == SCP_BL2_BASE);
+
+	if ((image_size == 0) || (image_size % 4 != 0)) {
+		ERROR("Invalid size for the SCP_BL2 image. Must be a multiple of "
+			"4 bytes and not zero (current size = 0x%x)\n",
+			image_size);
+		return -1;
+	}
+
+	/* Extract the checksum from the image */
+	checksum = *(uint32_t *) image;
+	image = (char *) image + sizeof(checksum);
+	image_size -= sizeof(checksum);
+
+	mhu_secure_init();
+
+	VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n");
+
+	/*
+	 * Send information about the SCP firmware image about to be transferred
+	 * to SCP
+	 */
+	scp_boot_message_start();
+
+	BOM_CMD_HEADER->id = BOOT_CMD_INFO;
+	cmd_info_payload = BOM_CMD_PAYLOAD;
+	cmd_info_payload->image_size = image_size;
+	cmd_info_payload->checksum = checksum;
+
+	scp_boot_message_send(sizeof(*cmd_info_payload));
+#if CSS_DETECT_PRE_1_7_0_SCP
+	{
+		const uint32_t deprecated_scp_nack_cmd = 0x404;
+		uint32_t mhu_status;
+
+		VERBOSE("Detecting SCP version incompatibility\n");
+
+		mhu_status = mhu_secure_message_wait();
+		if (mhu_status == deprecated_scp_nack_cmd) {
+			ERROR("Detected an incompatible version of the SCP firmware.\n");
+			ERROR("Only versions from v1.7.0 onwards are supported.\n");
+			ERROR("Please update the SCP firmware.\n");
+			return -1;
+		}
+
+		VERBOSE("SCP version looks OK\n");
+	}
+#endif /* CSS_DETECT_PRE_1_7_0_SCP */
+	response = scp_boot_message_wait(sizeof(response));
+	scp_boot_message_end();
+
+	if (response != 0) {
+		ERROR("SCP BOOT_CMD_INFO returned error %u\n", response);
+		return -1;
+	}
+
+	VERBOSE("Transferring SCP_BL2 image to SCP\n");
+
+	/* Transfer SCP_BL2 image to SCP */
+	scp_boot_message_start();
+
+	BOM_CMD_HEADER->id = BOOT_CMD_DATA;
+	cmd_data_payload = BOM_CMD_PAYLOAD;
+	cmd_data_payload->offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE;
+	cmd_data_payload->block_size = image_size;
+
+	scp_boot_message_send(sizeof(*cmd_data_payload));
+	response = scp_boot_message_wait(sizeof(response));
+	scp_boot_message_end();
+
+	if (response != 0) {
+		ERROR("SCP BOOT_CMD_DATA returned error %u\n", response);
+		return -1;
+	}
+
+	return 0;
+}
+
+int css_scp_boot_ready(void)
+{
+	VERBOSE("Waiting for SCP to signal it is ready to go on\n");
+
+	/* Wait for SCP to signal it's ready */
+	return scpi_wait_ready();
+}
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
new file mode 100644
index 0000000..8dbefa1
--- /dev/null
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*
+ * This file implements the SCP helper functions using SCMI protocol.
+ */
+
+/*
+ * SCMI power state parameter bit field encoding for ARM CSS platforms.
+ *
+ * 31  20 19       16 15      12 11       8 7        4 3         0
+ * +-------------------------------------------------------------+
+ * | SBZ | Max level |  Level 3 |  Level 2 |  Level 1 |  Level 0 |
+ * |     |           |   state  |   state  |   state  |   state  |
+ * +-------------------------------------------------------------+
+ *
+ * `Max level` encodes the highest level that has a valid power state
+ * encoded in the power state.
+ */
+#define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT	16
+#define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH	4
+#define SCMI_PWR_STATE_MAX_PWR_LVL_MASK		\
+				((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level)		\
+		(_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\
+				<< SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
+#define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state)		\
+		(((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT)	\
+				& SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
+
+#define SCMI_PWR_STATE_LVL_WIDTH		4
+#define SCMI_PWR_STATE_LVL_MASK			\
+				((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state)		\
+		(_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK)	\
+				<< (SCMI_PWR_STATE_LVL_WIDTH * (_level))
+#define SCMI_GET_PWR_STATE_LVL(_power_state, _level)		\
+		(((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) &	\
+				SCMI_PWR_STATE_LVL_MASK)
+
+/*
+ * The SCMI power state enumeration for a power domain level
+ */
+typedef enum {
+	scmi_power_state_off = 0,
+	scmi_power_state_on = 1,
+	scmi_power_state_sleep = 2,
+} scmi_power_state_t;
+
+/*
+ * The global handle for invoking the SCMI driver APIs after the driver
+ * has been initialized.
+ */
+static void *scmi_handle;
+
+/* The SCMI channel global object */
+static scmi_channel_t channel;
+
+ARM_SCMI_INSTANTIATE_LOCK;
+
+/*
+ * Helper function to suspend a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_suspend(const struct psci_power_state *target_state)
+{
+	int ret;
+
+	/* At least power domain level 0 should be specified to be suspended */
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+						ARM_LOCAL_STATE_OFF);
+
+	/* Check if power down at system power domain level is requested */
+	if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) {
+		/* Issue SCMI command for SYSTEM_SUSPEND */
+		ret = scmi_sys_pwr_state_set(scmi_handle,
+				SCMI_SYS_PWR_FORCEFUL_REQ,
+				SCMI_SYS_PWR_SUSPEND);
+		if (ret != SCMI_E_SUCCESS) {
+			ERROR("SCMI system power domain suspend return 0x%x unexpected\n",
+					ret);
+			panic();
+		}
+		return;
+	}
+#if !HW_ASSISTED_COHERENCY
+	unsigned int lvl;
+	uint32_t scmi_pwr_state = 0;
+	/*
+	 * If we reach here, then assert that power down at system power domain
+	 * level is running.
+	 */
+	assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
+
+	/* For level 0, specify `scmi_power_state_sleep` as the power state */
+	SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0,
+						scmi_power_state_sleep);
+
+	for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
+			break;
+
+		assert(target_state->pwr_domain_state[lvl] ==
+							ARM_LOCAL_STATE_OFF);
+		/*
+		 * Specify `scmi_power_state_off` as power state for higher
+		 * levels.
+		 */
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+						scmi_power_state_off);
+	}
+
+	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+	ret = scmi_pwr_state_set(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+#endif
+}
+
+/*
+ * Helper function to turn off a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_off(const struct psci_power_state *target_state)
+{
+	unsigned int lvl = 0;
+	int ret;
+	uint32_t scmi_pwr_state = 0;
+
+	/* At-least the CPU level should be specified to be OFF */
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+							ARM_LOCAL_STATE_OFF);
+
+	/* PSCI CPU OFF cannot be used to turn OFF system power domain */
+	assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
+
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
+			break;
+
+		assert(target_state->pwr_domain_state[lvl] ==
+							ARM_LOCAL_STATE_OFF);
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+				scmi_power_state_off);
+	}
+
+	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+	ret = scmi_pwr_state_set(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_on(u_register_t mpidr)
+{
+	unsigned int lvl = 0;
+	int ret, core_pos;
+	uint32_t scmi_pwr_state = 0;
+
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+				scmi_power_state_on);
+
+	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);
+
+	ret = scmi_pwr_state_set(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[core_pos],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+/*
+ * Helper function to get the power state of a power domain node as reported
+ * by the SCP.
+ */
+int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
+{
+	int ret, cpu_idx;
+	uint32_t scmi_pwr_state = 0, lvl_state;
+
+	/* We don't support get power state at the system power domain level */
+	if ((power_level > PLAT_MAX_PWR_LVL) ||
+			(power_level == CSS_SYSTEM_PWR_DMN_LVL)) {
+		WARN("Invalid power level %u specified for SCMI get power state\n",
+				power_level);
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	cpu_idx = plat_core_pos_by_mpidr(mpidr);
+	assert(cpu_idx > -1);
+
+	ret = scmi_pwr_state_get(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[cpu_idx],
+		&scmi_pwr_state);
+
+	if (ret != SCMI_E_SUCCESS) {
+		WARN("SCMI get power state command return 0x%x unexpected\n",
+				ret);
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	/*
+	 * Find the maximum power level described in the get power state
+	 * command. If it is less than the requested power level, then assume
+	 * the requested power level is ON.
+	 */
+	if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level)
+		return HW_ON;
+
+	lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level);
+	if (lvl_state == scmi_power_state_on)
+		return HW_ON;
+
+	assert((lvl_state == scmi_power_state_off) ||
+				(lvl_state == scmi_power_state_sleep));
+	return HW_OFF;
+}
+
+void __dead2 css_scp_system_off(int state)
+{
+	int ret;
+
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt from waking
+	 * up the AP from WFI.
+	 */
+	plat_arm_gic_cpuif_disable();
+
+	/*
+	 * Issue SCMI command. First issue a graceful
+	 * request and if that fails force the request.
+	 */
+	ret = scmi_sys_pwr_state_set(scmi_handle,
+			SCMI_SYS_PWR_FORCEFUL_REQ,
+			state);
+
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
+			state, ret);
+		panic();
+	}
+	wfi();
+	ERROR("CSS set power state: operation not handled.\n");
+	panic();
+}
+
+/*
+ * Helper function to shutdown the system via SCMI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+	css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
+/*
+ * Helper function to reset the system via SCMI.
+ */
+void __dead2 css_scp_sys_reboot(void)
+{
+	css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
+}
+
+static int scmi_ap_core_init(scmi_channel_t *ch)
+{
+#if PROGRAMMABLE_RESET_ADDRESS
+	uint32_t version;
+	int ret;
+
+	ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version);
+	if (ret != SCMI_E_SUCCESS) {
+		WARN("SCMI AP core protocol version message failed\n");
+		return -1;
+	}
+
+	if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) {
+		WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n",
+			version, SCMI_AP_CORE_PROTO_VER);
+		return -1;
+	}
+	INFO("SCMI AP core protocol version 0x%x detected\n", version);
+#endif
+	return 0;
+}
+
+void __init plat_arm_pwrc_setup(void)
+{
+	channel.info = plat_css_get_scmi_info();
+	channel.lock = ARM_SCMI_LOCK_GET_INSTANCE;
+	scmi_handle = scmi_init(&channel);
+	if (scmi_handle == NULL) {
+		ERROR("SCMI Initialization failed\n");
+		panic();
+	}
+	if (scmi_ap_core_init(&channel) < 0) {
+		ERROR("SCMI AP core protocol initialization failed\n");
+		panic();
+	}
+}
+
+/******************************************************************************
+ * This function overrides the default definition for ARM platforms. Initialize
+ * the SCMI driver, query capability via SCMI and modify the PSCI capability
+ * based on that.
+ *****************************************************************************/
+const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops)
+{
+	uint32_t msg_attr;
+	int ret;
+
+	assert(scmi_handle);
+
+	/* Check that power domain POWER_STATE_SET message is supported */
+	ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
+				SCMI_PWR_STATE_SET_MSG, &msg_attr);
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("Set power state command is not supported by SCMI\n");
+		panic();
+	}
+
+	/*
+	 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support
+	 * POWER_STATE_GET message.
+	 */
+	ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
+				SCMI_PWR_STATE_GET_MSG, &msg_attr);
+	if (ret != SCMI_E_SUCCESS)
+		ops->get_node_hw_state = NULL;
+
+	/* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */
+	ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID,
+				SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr);
+	if (ret != SCMI_E_SUCCESS) {
+		/* System power management operations are not supported */
+		ops->system_off = NULL;
+		ops->system_reset = NULL;
+		ops->get_sys_suspend_power_state = NULL;
+	} else {
+		if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
+			/*
+			 * System power management protocol is available, but
+			 * it does not support SYSTEM SUSPEND.
+			 */
+			ops->get_sys_suspend_power_state = NULL;
+		}
+		if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) {
+			/*
+			 * WARM reset is not available.
+			 */
+			ops->system_reset2 = NULL;
+		}
+	}
+
+	return ops;
+}
+
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
+{
+	if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET))
+		return PSCI_E_INVALID_PARAMS;
+
+	css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
+	/*
+	 * css_scp_system_off cannot return (it is a __dead function),
+	 * but css_system_reset2 has to return some value, even in
+	 * this case.
+	 */
+	return 0;
+}
+
+#if PROGRAMMABLE_RESET_ADDRESS
+void plat_arm_program_trusted_mailbox(uintptr_t address)
+{
+	int ret;
+
+	assert(scmi_handle);
+	ret = scmi_ap_core_set_reset_addr(scmi_handle, address,
+		SCMI_AP_CORE_LOCK_ATTR);
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("CSS: Failed to program reset address: %d\n", ret);
+		panic();
+	}
+}
+#endif
diff --git a/drivers/arm/css/scp/css_pm_scpi.c b/drivers/arm/css/scp/css_pm_scpi.c
new file mode 100644
index 0000000..b4019ce
--- /dev/null
+++ b/drivers/arm/css/scp/css_pm_scpi.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/*
+ * This file implements the SCP power management functions using SCPI protocol.
+ */
+
+/*
+ * Helper function to inform power down state to SCP.
+ */
+void css_scp_suspend(const struct psci_power_state *target_state)
+{
+	uint32_t cluster_state = scpi_power_on;
+	uint32_t system_state = scpi_power_on;
+
+	/* Check if power down at system power domain level is requested */
+	if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF)
+		system_state = scpi_power_retention;
+
+	/* Cluster is to be turned off, so disable coherency */
+	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+		cluster_state = scpi_power_off;
+
+	/*
+	 * Ask the SCP to power down the appropriate components depending upon
+	 * their state.
+	 */
+	scpi_set_css_power_state(read_mpidr_el1(),
+				 scpi_power_off,
+				 cluster_state,
+				 system_state);
+}
+
+/*
+ * Helper function to turn off a CPU power domain and its parent power domains
+ * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
+ * call the suspend helper here.
+ */
+void css_scp_off(const struct psci_power_state *target_state)
+{
+	css_scp_suspend(target_state);
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_on(u_register_t mpidr)
+{
+	/*
+	 * SCP takes care of powering up parent power domains so we
+	 * only need to care about level 0
+	 */
+	scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
+				 scpi_power_on);
+}
+
+/*
+ * Helper function to get the power state of a power domain node as reported
+ * by the SCP.
+ */
+int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
+{
+	int rc, element;
+	unsigned int cpu_state, cluster_state;
+
+	/*
+	 * The format of 'power_level' is implementation-defined, but 0 must
+	 * mean a CPU. We also allow 1 to denote the cluster
+	 */
+	if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Query SCP */
+	rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
+	if (rc != 0)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Map power states of CPU and cluster to expected PSCI return codes */
+	if (power_level == ARM_PWR_LVL0) {
+		/*
+		 * The CPU state returned by SCP is an 8-bit bit mask
+		 * corresponding to each CPU in the cluster
+		 */
+#if ARM_PLAT_MT
+		/*
+		 * The current SCPI driver only caters for single-threaded
+		 * platforms. Hence we ignore the thread ID (which is always 0)
+		 * for such platforms.
+		 */
+		element = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+#else
+		element = mpidr & MPIDR_AFFLVL_MASK;
+#endif  /* ARM_PLAT_MT */
+		return CSS_CPU_PWR_STATE(cpu_state, element) ==
+			CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
+	} else {
+		assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
+				cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
+		return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
+			HW_OFF;
+	}
+}
+
+/*
+ * Helper function to shutdown the system via SCPI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+	uint32_t response;
+
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt
+	 * from waking up the AP from WFI.
+	 */
+	plat_arm_gic_cpuif_disable();
+
+	/* Send the power down request to the SCP */
+	response = scpi_sys_power_state(scpi_system_shutdown);
+
+	if (response != SCP_OK) {
+		ERROR("CSS System Off: SCP error %u.\n", response);
+		panic();
+	}
+	wfi();
+	ERROR("CSS System Off: operation not handled.\n");
+	panic();
+}
+
+/*
+ * Helper function to reset the system via SCPI.
+ */
+void __dead2 css_scp_sys_reboot(void)
+{
+	uint32_t response;
+
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt
+	 * from waking up the AP from WFI.
+	 */
+	plat_arm_gic_cpuif_disable();
+
+	/* Send the system reset request to the SCP */
+	response = scpi_sys_power_state(scpi_system_reboot);
+
+	if (response != SCP_OK) {
+		ERROR("CSS System Reset: SCP error %u.\n", response);
+		panic();
+	}
+	wfi();
+	ERROR("CSS System Reset: operation not handled.\n");
+	panic();
+}
diff --git a/drivers/arm/css/scp/css_sds.c b/drivers/arm/css/scp/css_sds.c
new file mode 100644
index 0000000..e42ee10
--- /dev/null
+++ b/drivers/arm/css/scp/css_sds.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/delay_timer.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int css_scp_boot_image_xfer(void *image, unsigned int image_size)
+{
+	int ret;
+	unsigned int image_offset, image_flags;
+
+	ret = sds_init();
+	if (ret != SDS_OK) {
+		ERROR("SCP SDS initialization failed\n");
+		panic();
+	}
+
+	VERBOSE("Writing SCP image metadata\n");
+	image_offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE;
+	ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_ADDR_OFFSET,
+			&image_offset, SDS_SCP_IMG_ADDR_SIZE,
+			SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK)
+		goto sds_fail;
+
+	ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_SIZE_OFFSET,
+			&image_size, SDS_SCP_IMG_SIZE_SIZE,
+			SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK)
+		goto sds_fail;
+
+	VERBOSE("Marking SCP image metadata as valid\n");
+	image_flags = SDS_SCP_IMG_VALID_FLAG_BIT;
+	ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_FLAG_OFFSET,
+			&image_flags, SDS_SCP_IMG_FLAG_SIZE,
+			SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK)
+		goto sds_fail;
+
+	return 0;
+sds_fail:
+	ERROR("SCP SDS write to SCP IMG struct failed\n");
+	panic();
+}
+
+/*
+ * API to wait for SCP to signal till it's ready after booting the transferred
+ * image.
+ */
+int css_scp_boot_ready(void)
+{
+	uint32_t scp_feature_availability_flags;
+	int ret, retry = CSS_SCP_READY_10US_RETRIES;
+
+
+	VERBOSE("Waiting for SCP RAM to complete its initialization process\n");
+
+	/* Wait for the SCP RAM Firmware to complete its initialization process */
+	while (retry > 0) {
+		ret = sds_struct_read(SDS_FEATURE_AVAIL_STRUCT_ID, 0,
+				&scp_feature_availability_flags,
+				SDS_FEATURE_AVAIL_SIZE,
+				SDS_ACCESS_MODE_NON_CACHED);
+		if (ret == SDS_ERR_STRUCT_NOT_FINALIZED)
+			continue;
+
+		if (ret != SDS_OK) {
+			ERROR(" sds_struct_read failed\n");
+			panic();
+		}
+
+		if (scp_feature_availability_flags &
+				SDS_FEATURE_AVAIL_SCP_RAM_READY_BIT)
+			return 0;
+
+		udelay(10);
+		retry--;
+	}
+
+	ERROR("Timeout of %d ms expired waiting for SCP RAM Ready flag\n",
+			CSS_SCP_READY_10US_RETRIES/100);
+
+	plat_panic_handler();
+}
diff --git a/drivers/arm/css/scpi/css_scpi.c b/drivers/arm/css/scpi/css_scpi.c
new file mode 100644
index 0000000..c56b7c4
--- /dev/null
+++ b/drivers/arm/css/scpi/css_scpi.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#define SCPI_SHARED_MEM_SCP_TO_AP	PLAT_CSS_SCP_COM_SHARED_MEM_BASE
+#define SCPI_SHARED_MEM_AP_TO_SCP	(PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
+								 + 0x100)
+
+/* Header and payload addresses for commands from AP to SCP */
+#define SCPI_CMD_HEADER_AP_TO_SCP		\
+	((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
+#define SCPI_CMD_PAYLOAD_AP_TO_SCP		\
+	((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
+
+/* Header and payload addresses for responses from SCP to AP */
+#define SCPI_RES_HEADER_SCP_TO_AP \
+	((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP)
+#define SCPI_RES_PAYLOAD_SCP_TO_AP \
+	((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t)))
+
+/* ID of the MHU slot used for the SCPI protocol */
+#define SCPI_MHU_SLOT_ID		0
+
+static void scpi_secure_message_start(void)
+{
+	mhu_secure_message_start(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_send(size_t payload_size)
+{
+	/*
+	 * Ensure that any write to the SCPI payload area is seen by SCP before
+	 * we write to the MHU register. If these 2 writes were reordered by
+	 * the CPU then SCP would read stale payload data
+	 */
+	dmbst();
+
+	mhu_secure_message_send(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_receive(scpi_cmd_t *cmd)
+{
+	uint32_t mhu_status;
+
+	assert(cmd != NULL);
+
+	mhu_status = mhu_secure_message_wait();
+
+	/* Expect an SCPI message, reject any other protocol */
+	if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
+		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+			mhu_status);
+		panic();
+	}
+
+	/*
+	 * Ensure that any read to the SCPI payload area is done after reading
+	 * the MHU register. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data
+	 */
+	dmbld();
+
+	memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
+}
+
+static void scpi_secure_message_end(void)
+{
+	mhu_secure_message_end(SCPI_MHU_SLOT_ID);
+}
+
+int scpi_wait_ready(void)
+{
+	scpi_cmd_t scpi_cmd;
+
+	VERBOSE("Waiting for SCP_READY command...\n");
+
+	/* Get a message from the SCP */
+	scpi_secure_message_start();
+	scpi_secure_message_receive(&scpi_cmd);
+	scpi_secure_message_end();
+
+	/* We are expecting 'SCP Ready', produce correct error if it's not */
+	scpi_status_t status = SCP_OK;
+	if (scpi_cmd.id != SCPI_CMD_SCP_READY) {
+		ERROR("Unexpected SCP command: expected command #%u, got command #%u\n",
+		      SCPI_CMD_SCP_READY, scpi_cmd.id);
+		status = SCP_E_SUPPORT;
+	} else if (scpi_cmd.size != 0) {
+		ERROR("SCP_READY command has incorrect size: expected 0, got %u\n",
+		      scpi_cmd.size);
+		status = SCP_E_SIZE;
+	}
+
+	VERBOSE("Sending response for SCP_READY command\n");
+
+	/*
+	 * Send our response back to SCP.
+	 * We are using the same SCPI header, just update the status field.
+	 */
+	scpi_cmd.status = status;
+	scpi_secure_message_start();
+	memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd));
+	scpi_secure_message_send(0);
+	scpi_secure_message_end();
+
+	return status == SCP_OK ? 0 : -1;
+}
+
+void scpi_set_css_power_state(unsigned int mpidr,
+		scpi_power_state_t cpu_state, scpi_power_state_t cluster_state,
+		scpi_power_state_t css_state)
+{
+	scpi_cmd_t *cmd;
+	uint32_t state = 0;
+	uint32_t *payload_addr;
+
+#if ARM_PLAT_MT
+	/*
+	 * The current SCPI driver only caters for single-threaded platforms.
+	 * Hence we ignore the thread ID (which is always 0) for such platforms.
+	 */
+	state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f;	/* CPU ID */
+	state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4;	/* Cluster ID */
+#else
+	state |= mpidr & 0x0f;	/* CPU ID */
+	state |= (mpidr & 0xf00) >> 4;	/* Cluster ID */
+#endif /* ARM_PLAT_MT */
+
+	state |= cpu_state << 8;
+	state |= cluster_state << 12;
+	state |= css_state << 16;
+
+	scpi_secure_message_start();
+
+	/* Populate the command header */
+	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+	cmd->id = SCPI_CMD_SET_CSS_POWER_STATE;
+	cmd->set = SCPI_SET_NORMAL;
+	cmd->sender = 0;
+	cmd->size = sizeof(state);
+	/* Populate the command payload */
+	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+	*payload_addr = state;
+	scpi_secure_message_send(sizeof(state));
+	/*
+	 * SCP does not reply to this command in order to avoid MHU interrupts
+	 * from the sender, which could interfere with its power state request.
+	 */
+
+	scpi_secure_message_end();
+}
+
+/*
+ * Query and obtain CSS power state from SCP.
+ *
+ * In response to the query, SCP returns power states of all CPUs in all
+ * clusters of the system. The returned response is then filtered based on the
+ * supplied MPIDR. Power states of requested cluster and CPUs within are updated
+ * via supplied non-NULL pointer arguments.
+ *
+ * Returns 0 on success, or -1 on errors.
+ */
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+		unsigned int *cluster_state_p)
+{
+	scpi_cmd_t *cmd;
+	scpi_cmd_t response;
+	int power_state, cpu, cluster, rc = -1;
+
+	/*
+	 * Extract CPU and cluster membership of the given MPIDR. SCPI caters
+	 * for only up to 0xf clusters, and 8 CPUs per cluster
+	 */
+#if ARM_PLAT_MT
+	/*
+	 * The current SCPI driver only caters for single-threaded platforms.
+	 * Hence we ignore the thread ID (which is always 0) for such platforms.
+	 */
+	cpu = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cluster = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
+#else
+	cpu = mpidr & MPIDR_AFFLVL_MASK;
+	cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+#endif  /* ARM_PLAT_MT */
+	if (cpu >= 8 || cluster >= 0xf)
+		return -1;
+
+	scpi_secure_message_start();
+
+	/* Populate request headers */
+	zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd));
+	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+	cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
+
+	/*
+	 * Send message and wait for SCP's response
+	 */
+	scpi_secure_message_send(0);
+	scpi_secure_message_receive(&response);
+
+	if (response.status != SCP_OK)
+		goto exit;
+
+	/* Validate SCP response */
+	if (!CHECK_RESPONSE(response, cluster))
+		goto exit;
+
+	/* Extract power states for required cluster */
+	power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster);
+	if (CLUSTER_ID(power_state) != cluster)
+		goto exit;
+
+	/* Update power state via pointers */
+	if (cluster_state_p)
+		*cluster_state_p = CLUSTER_POWER_STATE(power_state);
+	if (cpu_state_p)
+		*cpu_state_p = CPU_POWER_STATE(power_state);
+	rc = 0;
+
+exit:
+	scpi_secure_message_end();
+	return rc;
+}
+
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
+{
+	scpi_cmd_t *cmd;
+	uint8_t *payload_addr;
+	scpi_cmd_t response;
+
+	scpi_secure_message_start();
+
+	/* Populate the command header */
+	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+	cmd->id = SCPI_CMD_SYS_POWER_STATE;
+	cmd->set = 0;
+	cmd->sender = 0;
+	cmd->size = sizeof(*payload_addr);
+	/* Populate the command payload */
+	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+	*payload_addr = system_state & 0xff;
+	scpi_secure_message_send(sizeof(*payload_addr));
+
+	scpi_secure_message_receive(&response);
+
+	scpi_secure_message_end();
+
+	return response.status;
+}
diff --git a/drivers/arm/css/sds/aarch32/sds_helpers.S b/drivers/arm/css/sds/aarch32/sds_helpers.S
new file mode 100644
index 0000000..13ff0e1
--- /dev/null
+++ b/drivers/arm/css/sds/aarch32/sds_helpers.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#include "../sds_private.h"
+
+	.globl	sds_get_primary_cpu_id
+
+	/*
+	 * int sds_get_primary_cpu_id(void);
+	 * Return the primary CPU ID from SDS Structure
+	 * Returns CPUID on success or -1 on failure
+	 */
+func sds_get_primary_cpu_id
+	ldr	r0, =PLAT_ARM_SDS_MEM_BASE
+	ldr	r2, =SDS_REGION_SIGNATURE
+	ldr	r1, [r0]
+	ubfx	r3, r1, #0, #16
+
+	/* Check if the SDS region signature found */
+	cmp	r2, r3
+	bne	2f
+
+	/* Get the structure count from region descriptor in r1 */
+	ubfx	r1, r1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH
+	cmp	r1, #0
+	beq	2f
+	add	r0, r0, #SDS_REGION_DESC_SIZE
+
+	/* Initialize the loop iterator count in r3 */
+	mov	r3, #0
+loop_begin:
+	ldrh	r2, [r0]
+	cmp	r2, #SDS_AP_CPU_INFO_STRUCT_ID
+	bne	continue_loop
+
+	/* We have found the required structure */
+	ldr	r0, [r0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)]
+	bx	lr
+continue_loop:
+	/* Increment the loop counter and exit loop if counter == structure count */
+	add	r3, r3, #0x1
+	cmp	r1, r3
+	beq	2f
+
+	/* Read the 2nd word in header */
+	ldr	r2, [r0,#4]
+	/* Get the structure size from header */
+	ubfx	r2, r2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH
+	/* Add the structure size and SDS HEADER SIZE to point to next header */
+	add	r2, r2, #SDS_HEADER_SIZE
+	add	r0, r0, r2
+	b	loop_begin
+2:
+	mov	r0, #0xffffffff
+	bx	lr
+endfunc sds_get_primary_cpu_id
diff --git a/drivers/arm/css/sds/aarch64/sds_helpers.S b/drivers/arm/css/sds/aarch64/sds_helpers.S
new file mode 100644
index 0000000..3256c2b
--- /dev/null
+++ b/drivers/arm/css/sds/aarch64/sds_helpers.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#include "../sds_private.h"
+
+	.globl	sds_get_primary_cpu_id
+
+	/*
+	 * int sds_get_primary_cpu_id(void);
+	 * Return the primary CPI ID from SDS Structure
+	 * Returns CPUID on success or -1 on failure
+	 */
+func sds_get_primary_cpu_id
+	mov_imm	x0, PLAT_ARM_SDS_MEM_BASE
+	mov	w2, #SDS_REGION_SIGNATURE
+	ldr	w1, [x0]
+
+	/* Check if the SDS region signature found */
+	cmp	w2, w1, uxth
+	b.ne	2f
+
+	/* Get the structure count from region descriptor in `w1 */
+	ubfx	w1, w1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH
+	cbz	w1, 2f
+	add	x0, x0, #SDS_REGION_DESC_SIZE
+
+	/* Initialize the loop iterator count in w3 */
+	mov	w3, #0
+loop_begin:
+	ldrh	w2, [x0]
+	cmp	w2, #SDS_AP_CPU_INFO_STRUCT_ID
+	b.ne	continue_loop
+
+	/* We have found the required structure */
+	ldr	w0, [x0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)]
+	ret
+continue_loop:
+	/* Increment the loop counter and exit loop if counter == structure count */
+	add	w3, w3, #0x1
+	cmp	w1, w3
+	b.eq	2f
+
+	/* Read the 2nd word in header */
+	ldr	w2, [x0,#4]
+	/* Get the structure size from header */
+	ubfx	x2, x2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH
+	/* Add the structure size and SDS HEADER SIZE to point to next header */
+	add	x2, x2, #SDS_HEADER_SIZE
+	add	x0, x0, x2
+	b	loop_begin
+2:
+	mov	w0, #0xffffffff
+	ret
+endfunc sds_get_primary_cpu_id
diff --git a/drivers/arm/css/sds/sds.c b/drivers/arm/css/sds/sds.c
new file mode 100644
index 0000000..1fb196c
--- /dev/null
+++ b/drivers/arm/css/sds/sds.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#include "sds_private.h"
+
+/*
+ * Variables used to track and maintain the state of the memory region reserved
+ * for usage by the SDS framework.
+ */
+
+/* Pointer to the base of the SDS memory region */
+static uintptr_t sds_mem_base;
+
+/* Size of the SDS memory region in bytes */
+static size_t sds_mem_size;
+
+/*
+ * Perform some non-exhaustive tests to determine whether any of the fields
+ * within a Structure Header contain obviously invalid data.
+ * Returns SDS_OK on success, SDS_ERR_FAIL on error.
+ */
+static int sds_struct_is_valid(uintptr_t header)
+{
+	size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header);
+
+	/* Zero is not a valid identifier */
+	if (GET_SDS_HEADER_ID(header) == 0)
+		return SDS_ERR_FAIL;
+
+	/* Check SDS Schema version */
+	if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION)
+		return SDS_ERR_FAIL;
+
+	/* The SDS Structure sizes have to be multiple of 8 */
+	if ((struct_size == 0) || ((struct_size % 8) != 0))
+		return SDS_ERR_FAIL;
+
+	if (struct_size > sds_mem_size)
+		return SDS_ERR_FAIL;
+
+	return SDS_OK;
+}
+
+/*
+ * Validate the SDS structure headers.
+ * Returns SDS_OK on success, SDS_ERR_FAIL on error.
+ */
+static int validate_sds_struct_headers(void)
+{
+	unsigned int i, structure_count;
+	uintptr_t header;
+
+	structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
+
+	if (structure_count == 0)
+		return SDS_ERR_FAIL;
+
+	header = sds_mem_base + SDS_REGION_DESC_SIZE;
+
+	/* Iterate over structure headers and validate each one */
+	for (i = 0; i < structure_count; i++) {
+		if (sds_struct_is_valid(header) != SDS_OK) {
+			WARN("SDS: Invalid structure header detected\n");
+			return SDS_ERR_FAIL;
+		}
+		header += GET_SDS_HEADER_STRUCT_SIZE(header) + SDS_HEADER_SIZE;
+	}
+	return SDS_OK;
+}
+
+/*
+ * Get the structure header pointer corresponding to the structure ID.
+ * Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
+ */
+static int get_struct_header(uint32_t structure_id, struct_header_t **header)
+{
+	unsigned int i, structure_count;
+	uintptr_t current_header;
+
+	assert(header);
+
+	structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
+	if (structure_count == 0)
+		return SDS_ERR_STRUCT_NOT_FOUND;
+
+	current_header = ((uintptr_t)sds_mem_base) + SDS_REGION_DESC_SIZE;
+
+	/* Iterate over structure headers to find one with a matching ID */
+	for (i = 0; i < structure_count; i++) {
+		if (GET_SDS_HEADER_ID(current_header) == structure_id) {
+			*header = (struct_header_t *)current_header;
+			return SDS_OK;
+		}
+		current_header += GET_SDS_HEADER_STRUCT_SIZE(current_header) +
+						SDS_HEADER_SIZE;
+	}
+
+	*header = NULL;
+	return SDS_ERR_STRUCT_NOT_FOUND;
+}
+
+/*
+ * Check if a structure header corresponding to the structure ID exists.
+ * Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
+ * if not found.
+ */
+int sds_struct_exists(unsigned int structure_id)
+{
+	struct_header_t *header = NULL;
+	int ret;
+
+	ret = get_struct_header(structure_id, &header);
+	if (ret == SDS_OK) {
+		assert(header);
+	}
+
+	return ret;
+}
+
+/*
+ * Read from field in the structure corresponding to `structure_id`.
+ * `fld_off` is the offset to the field in the structure and `mode`
+ * indicates whether cache maintenance need to performed prior to the read.
+ * The `data` is the pointer to store the read data of size specified by `size`.
+ * Returns SDS_OK on success or corresponding error codes on failure.
+ */
+int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
+		void *data, size_t size, sds_access_mode_t mode)
+{
+	int status;
+	uintptr_t field_base;
+	struct_header_t *header = NULL;
+
+	if (!data)
+		return SDS_ERR_INVALID_PARAMS;
+
+	/* Check if a structure with this ID exists */
+	status = get_struct_header(structure_id, &header);
+	if (status != SDS_OK)
+		return status;
+
+	assert(header);
+
+	if (mode == SDS_ACCESS_MODE_CACHED)
+		inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
+
+	if (!IS_SDS_HEADER_VALID(header)) {
+		WARN("SDS: Reading from un-finalized structure 0x%x\n",
+				structure_id);
+		return SDS_ERR_STRUCT_NOT_FINALIZED;
+	}
+
+	if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
+		return SDS_ERR_FAIL;
+
+	field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
+	if (check_uptr_overflow(field_base, size - 1))
+		return SDS_ERR_FAIL;
+
+	/* Copy the required field in the struct */
+	memcpy(data, (void *)field_base, size);
+
+	return SDS_OK;
+}
+
+/*
+ * Write to the field in the structure corresponding to `structure_id`.
+ * `fld_off` is the offset to the field in the structure and `mode`
+ * indicates whether cache maintenance need to performed for the write.
+ * The `data` is the pointer to data of size specified by `size`.
+ * Returns SDS_OK on success or corresponding error codes on failure.
+ */
+int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
+		void *data, size_t size, sds_access_mode_t mode)
+{
+	int status;
+	uintptr_t field_base;
+	struct_header_t *header = NULL;
+
+	if (!data)
+		return SDS_ERR_INVALID_PARAMS;
+
+	/* Check if a structure with this ID exists */
+	status = get_struct_header(structure_id, &header);
+	if (status != SDS_OK)
+		return status;
+
+	assert(header);
+
+	if (mode == SDS_ACCESS_MODE_CACHED)
+		inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
+
+	if (!IS_SDS_HEADER_VALID(header)) {
+		WARN("SDS: Writing to un-finalized structure 0x%x\n",
+				structure_id);
+		return SDS_ERR_STRUCT_NOT_FINALIZED;
+	}
+
+	if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
+		return SDS_ERR_FAIL;
+
+	field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
+	if (check_uptr_overflow(field_base, size - 1))
+		return SDS_ERR_FAIL;
+
+	/* Copy the required field in the struct */
+	memcpy((void *)field_base, data, size);
+
+	if (mode == SDS_ACCESS_MODE_CACHED)
+		flush_dcache_range((uintptr_t)field_base, size);
+
+	return SDS_OK;
+}
+
+/*
+ * Initialize the SDS driver. Also verifies the SDS version and sanity of
+ * the SDS structure headers.
+ * Returns SDS_OK on success, SDS_ERR_FAIL on error.
+ */
+int sds_init(void)
+{
+	sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE;
+
+	if (!IS_SDS_REGION_VALID(sds_mem_base)) {
+		WARN("SDS: No valid SDS Memory Region found\n");
+		return SDS_ERR_FAIL;
+	}
+
+	if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base)
+				!= SDS_REGION_SCH_VERSION) {
+		WARN("SDS: Unsupported SDS schema version\n");
+		return SDS_ERR_FAIL;
+	}
+
+	sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base);
+	if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
+		WARN("SDS: SDS Memory Region exceeds size limit\n");
+		return SDS_ERR_FAIL;
+	}
+
+	INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size);
+
+	if (validate_sds_struct_headers() != SDS_OK)
+		return SDS_ERR_FAIL;
+
+	return SDS_OK;
+}
diff --git a/drivers/arm/css/sds/sds_private.h b/drivers/arm/css/sds/sds_private.h
new file mode 100644
index 0000000..d801a04
--- /dev/null
+++ b/drivers/arm/css/sds/sds_private.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDS_PRIVATE_H
+#define SDS_PRIVATE_H
+
+/* SDS Header defines */
+#define SDS_HEADER_ID_SHIFT			0
+#define SDS_HEADER_ID_WIDTH			16
+#define SDS_HEADER_ID_MASK			((1 << SDS_HEADER_ID_WIDTH) - 1)
+
+#define SDS_HEADER_MINOR_VERSION_WIDTH		8
+#define SDS_HEADER_MINOR_VERSION_SHIFT		16
+#define SDS_HEADER_MAJOR_VERSION_WIDTH		8
+
+#define MAKE_SDS_HEADER_VERSION(major, minor)	\
+	(((((major) & 0xff) << SDS_HEADER_MINOR_VERSION_WIDTH) | ((minor) & 0xff)))
+#define SDS_HEADER_VERSION_MASK			\
+	((1 << (SDS_HEADER_MINOR_VERSION_WIDTH + SDS_HEADER_MAJOR_VERSION_WIDTH)) - 1)
+
+#define SDS_HEADER_VERSION			MAKE_SDS_HEADER_VERSION(1, 0)
+#define SDS_HEADER_STRUCT_SIZE_WIDTH		23
+#define SDS_HEADER_STRUCT_SIZE_SHIFT		1
+#define SDS_HEADER_STRUCT_SIZE_MASK		((1 << SDS_HEADER_STRUCT_SIZE_WIDTH) - 1)
+#define SDS_HEADER_VALID_MASK			0x1
+#define SDS_HEADER_VALID_SHIFT			0
+#define SDS_HEADER_SIZE				0x8
+
+/* Arbitrary, 16 bit value that indicates a valid SDS Memory Region */
+#define SDS_REGION_SIGNATURE			0xAA7A
+#define SDS_REGION_SIGNATURE_WIDTH		16
+#define SDS_REGION_SIGNATURE_SHIFT		0
+#define SDS_REGION_SIGNATURE_MASK		((1 << SDS_REGION_SIGNATURE_WIDTH) - 1)
+
+#define SDS_REGION_STRUCT_COUNT_SHIFT		16
+#define SDS_REGION_STRUCT_COUNT_WIDTH		8
+#define SDS_REGION_STRUCT_COUNT_MASK		((1 << SDS_REGION_STRUCT_COUNT_WIDTH) - 1)
+
+#define SDS_REGION_SCH_MINOR_SHIFT		24
+#define SDS_REGION_SCH_MINOR_WIDTH		4
+#define SDS_REGION_SCH_MINOR_MASK		((1 << SDS_REGION_SCH_MINOR_WIDTH) - 1)
+
+#define SDS_REGION_SCH_MAJOR_SHIFT		28
+#define SDS_REGION_SCH_MAJOR_WIDTH		4
+#define SDS_REGION_SCH_MAJOR_MASK		((1 << SDS_REGION_SCH_MAJOR_WIDTH) - 1)
+
+#define SDS_REGION_SCH_VERSION_MASK		\
+	((1 << (SDS_REGION_SCH_MINOR_WIDTH + SDS_REGION_SCH_MAJOR_WIDTH)) - 1)
+
+#define MAKE_SDS_REGION_SCH_VERSION(maj, min)	\
+	((((maj) & SDS_REGION_SCH_MAJOR_MASK) << SDS_REGION_SCH_MINOR_WIDTH) |	\
+	((min) & SDS_REGION_SCH_MINOR_MASK))
+
+#define SDS_REGION_SCH_VERSION			MAKE_SDS_REGION_SCH_VERSION(1, 0)
+#define SDS_REGION_REGIONSIZE_OFFSET		0x4
+#define SDS_REGION_DESC_SIZE			0x8
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+/* Header containing Shared Data Structure metadata */
+typedef struct structure_header {
+	uint32_t reg[2];
+} struct_header_t;
+
+#define GET_SDS_HEADER_ID(_header)			\
+	((((struct_header_t *)(_header))->reg[0]) & SDS_HEADER_ID_MASK)
+#define GET_SDS_HEADER_VERSION(_header)			\
+	(((((struct_header_t *)(_header))->reg[0]) >> SDS_HEADER_MINOR_VERSION_SHIFT)\
+	& SDS_HEADER_VERSION_MASK)
+#define GET_SDS_HEADER_STRUCT_SIZE(_header)		\
+	(((((struct_header_t *)(_header))->reg[1]) >> SDS_HEADER_STRUCT_SIZE_SHIFT)\
+	& SDS_HEADER_STRUCT_SIZE_MASK)
+#define IS_SDS_HEADER_VALID(_header)			\
+	((((struct_header_t *)(_header))->reg[1]) & SDS_HEADER_VALID_MASK)
+#define GET_SDS_STRUCT_FIELD(_header, _field_offset)	\
+	((((uint8_t *)(_header)) + sizeof(struct_header_t)) + (_field_offset))
+
+/* Region Descriptor describing the SDS Memory Region */
+typedef struct region_descriptor {
+	uint32_t reg[2];
+} region_desc_t;
+
+#define IS_SDS_REGION_VALID(region)			\
+	(((((region_desc_t *)(region))->reg[0]) & SDS_REGION_SIGNATURE_MASK) == SDS_REGION_SIGNATURE)
+#define GET_SDS_REGION_STRUCTURE_COUNT(region)		\
+	(((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_STRUCT_COUNT_SHIFT)\
+	& SDS_REGION_STRUCT_COUNT_MASK)
+#define GET_SDS_REGION_SCHEMA_VERSION(region)		\
+	(((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_SCH_MINOR_SHIFT)\
+	& SDS_REGION_SCH_VERSION_MASK)
+#define GET_SDS_REGION_SIZE(region)		((((region_desc_t *)(region))->reg[1]))
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SDS_PRIVATE_H */
diff --git a/drivers/arm/fvp/fvp_pwrc.c b/drivers/arm/fvp/fvp_pwrc.c
new file mode 100644
index 0000000..75a2b66
--- /dev/null
+++ b/drivers/arm/fvp/fvp_pwrc.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * TODO: Someday there will be a generic power controller api. At the moment
+ * each platform has its own pwrc so just exporting functions is fine.
+ */
+ARM_INSTANTIATE_LOCK;
+
+unsigned int fvp_pwrc_get_cpu_wkr(u_register_t mpidr)
+{
+	return PSYSR_WK(fvp_pwrc_read_psysr(mpidr));
+}
+
+unsigned int fvp_pwrc_read_psysr(u_register_t mpidr)
+{
+	unsigned int rc;
+	arm_lock_get();
+	mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr);
+	rc = mmio_read_32(PWRC_BASE + PSYSR_OFF);
+	arm_lock_release();
+	return rc;
+}
+
+void fvp_pwrc_write_pponr(u_register_t mpidr)
+{
+	arm_lock_get();
+	mmio_write_32(PWRC_BASE + PPONR_OFF, (unsigned int) mpidr);
+	arm_lock_release();
+}
+
+void fvp_pwrc_write_ppoffr(u_register_t mpidr)
+{
+	arm_lock_get();
+	mmio_write_32(PWRC_BASE + PPOFFR_OFF, (unsigned int) mpidr);
+	arm_lock_release();
+}
+
+void fvp_pwrc_set_wen(u_register_t mpidr)
+{
+	arm_lock_get();
+	mmio_write_32(PWRC_BASE + PWKUPR_OFF,
+		      (unsigned int) (PWKUPR_WEN | mpidr));
+	arm_lock_release();
+}
+
+void fvp_pwrc_clr_wen(u_register_t mpidr)
+{
+	arm_lock_get();
+	mmio_write_32(PWRC_BASE + PWKUPR_OFF,
+		      (unsigned int) mpidr);
+	arm_lock_release();
+}
+
+void fvp_pwrc_write_pcoffr(u_register_t mpidr)
+{
+	arm_lock_get();
+	mmio_write_32(PWRC_BASE + PCOFFR_OFF, (unsigned int) mpidr);
+	arm_lock_release();
+}
+
+/* Nothing else to do here apart from initializing the lock */
+void __init plat_arm_pwrc_setup(void)
+{
+	arm_lock_init();
+}
+
+
+
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c
new file mode 100644
index 0000000..38b2f67
--- /dev/null
+++ b/drivers/arm/gic/common/gic_common.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+
+#include "gic_common_private.h"
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading entire registers
+ ******************************************************************************/
+/*
+ * Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt
+ * `id`, 32 interrupt ids at a time.
+ */
+unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> IGROUPR_SHIFT;
+
+	return mmio_read_32(base + GICD_IGROUPR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ISENABLER corresponding to the
+ * interrupt `id`, 32 interrupt ids at a time.
+ */
+unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ISENABLER_SHIFT;
+
+	return mmio_read_32(base + GICD_ISENABLER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICENABLER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ICENABLER_SHIFT;
+
+	return mmio_read_32(base + GICD_ICENABLER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ISPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ISPENDR_SHIFT;
+
+	return mmio_read_32(base + GICD_ISPENDR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ICPENDR_SHIFT;
+
+	return mmio_read_32(base + GICD_ICPENDR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ISACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ISACTIVER_SHIFT;
+
+	return mmio_read_32(base + GICD_ISACTIVER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ICACTIVER_SHIFT;
+
+	return mmio_read_32(base + GICD_ICACTIVER + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> IPRIORITYR_SHIFT;
+
+	return mmio_read_32(base + GICD_IPRIORITYR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor ICGFR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ICFGR_SHIFT;
+
+	return mmio_read_32(base + GICD_ICFGR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor NSACR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> NSACR_SHIFT;
+
+	return mmio_read_32(base + GICD_NSACR + (n << 2));
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+/*
+ * Accessor to write the GIC Distributor IGROUPR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> IGROUPR_SHIFT;
+
+	mmio_write_32(base + GICD_IGROUPR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ISENABLER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ISENABLER_SHIFT;
+
+	mmio_write_32(base + GICD_ISENABLER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICENABLER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ICENABLER_SHIFT;
+
+	mmio_write_32(base + GICD_ICENABLER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ISPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ISPENDR_SHIFT;
+
+	mmio_write_32(base + GICD_ISPENDR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICPENDR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ICPENDR_SHIFT;
+
+	mmio_write_32(base + GICD_ICPENDR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ISACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ISACTIVER_SHIFT;
+
+	mmio_write_32(base + GICD_ISACTIVER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICACTIVER corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ICACTIVER_SHIFT;
+
+	mmio_write_32(base + GICD_ICACTIVER + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> IPRIORITYR_SHIFT;
+
+	mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor ICFGR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> ICFGR_SHIFT;
+
+	mmio_write_32(base + GICD_ICFGR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor NSACR corresponding to the
+ * interrupt `id`, 16 interrupt IDs at a time.
+ */
+void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> NSACR_SHIFT;
+
+	mmio_write_32(base + GICD_NSACR + (n << 2), val);
+}
+
+/*******************************************************************************
+ * GIC Distributor functions for accessing the GIC registers
+ * corresponding to a single interrupt ID. These functions use bitwise
+ * operations or appropriate register accesses to modify or return
+ * the bit-field corresponding the single interrupt ID.
+ ******************************************************************************/
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_igroupr(base, id);
+
+	return (reg_val >> bit_num) & 0x1U;
+}
+
+void gicd_set_igroupr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_igroupr(base, id);
+
+	gicd_write_igroupr(base, id, reg_val | (1U << bit_num));
+}
+
+void gicd_clr_igroupr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_igroupr(base, id);
+
+	gicd_write_igroupr(base, id, reg_val & ~(1U << bit_num));
+}
+
+void gicd_set_isenabler(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U);
+
+	gicd_write_isenabler(base, id, (1U << bit_num));
+}
+
+void gicd_set_icenabler(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U);
+
+	gicd_write_icenabler(base, id, (1U << bit_num));
+}
+
+void gicd_set_ispendr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U);
+
+	gicd_write_ispendr(base, id, (1U << bit_num));
+}
+
+void gicd_set_icpendr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U);
+
+	gicd_write_icpendr(base, id, (1U << bit_num));
+}
+
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_isactiver(base, id);
+
+	return (reg_val >> bit_num) & 0x1U;
+}
+
+void gicd_set_isactiver(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U);
+
+	gicd_write_isactiver(base, id, (1U << bit_num));
+}
+
+void gicd_set_icactiver(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ICACTIVER_SHIFT) - 1U);
+
+	gicd_write_icactiver(base, id, (1U << bit_num));
+}
+
+void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+	uint8_t val = pri & GIC_PRI_MASK;
+
+	mmio_write_8(base + GICD_IPRIORITYR + id, val);
+}
+
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	/* Interrupt configuration is a 2-bit field */
+	unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U);
+	unsigned int bit_shift = bit_num << 1;
+
+	uint32_t reg_val = gicd_read_icfgr(base, id);
+
+	/* Clear the field, and insert required configuration */
+	reg_val &= ~(GIC_CFG_MASK << bit_shift);
+	reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift);
+
+	gicd_write_icfgr(base, id, reg_val);
+}
diff --git a/drivers/arm/gic/common/gic_common_private.h b/drivers/arm/gic/common/gic_common_private.h
new file mode 100644
index 0000000..1ab1bdb
--- /dev/null
+++ b/drivers/arm/gic/common/gic_common_private.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC_COMMON_PRIVATE_H
+#define GIC_COMMON_PRIVATE_H
+
+#include <stdint.h>
+
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+
+/*******************************************************************************
+ * GIC Distributor interface register accessors that are common to GICv3 & GICv2
+ ******************************************************************************/
+static inline unsigned int gicd_read_ctlr(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_CTLR);
+}
+
+static inline unsigned int gicd_read_typer(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_TYPER);
+}
+
+static inline unsigned int gicd_read_iidr(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_IIDR);
+}
+
+static inline void gicd_write_ctlr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICD_CTLR, val);
+}
+
+/*******************************************************************************
+ * GIC Distributor function prototypes for accessing entire registers.
+ * Note: The raw register values correspond to multiple interrupt IDs and
+ * the number of interrupt IDs involved depends on the register accessed.
+ ******************************************************************************/
+unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id);
+unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id);
+unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id);
+unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id);
+unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id);
+unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id);
+void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val);
+void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val);
+
+/*******************************************************************************
+ * GIC Distributor function prototypes for accessing the GIC registers
+ * corresponding to a single interrupt ID. These functions use bitwise
+ * operations or appropriate register accesses to modify or return
+ * the bit-field corresponding the single interrupt ID.
+ ******************************************************************************/
+unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id);
+void gicd_set_igroupr(uintptr_t base, unsigned int id);
+void gicd_clr_igroupr(uintptr_t base, unsigned int id);
+void gicd_set_isenabler(uintptr_t base, unsigned int id);
+void gicd_set_icenabler(uintptr_t base, unsigned int id);
+void gicd_set_ispendr(uintptr_t base, unsigned int id);
+void gicd_set_icpendr(uintptr_t base, unsigned int id);
+unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id);
+void gicd_set_isactiver(uintptr_t base, unsigned int id);
+void gicd_set_icactiver(uintptr_t base, unsigned int id);
+void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
+void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg);
+
+#endif /* GIC_COMMON_PRIVATE_H */
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c
new file mode 100644
index 0000000..6739a78
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_helpers.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+
+#include "../common/gic_common_private.h"
+#include "gicv2_private.h"
+
+/*
+ * Accessor to read the GIC Distributor ITARGETSR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id)
+{
+	unsigned n = id >> ITARGETSR_SHIFT;
+	return mmio_read_32(base + GICD_ITARGETSR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor CPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id)
+{
+	unsigned n = id >> CPENDSGIR_SHIFT;
+	return mmio_read_32(base + GICD_CPENDSGIR + (n << 2));
+}
+
+/*
+ * Accessor to read the GIC Distributor SPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id)
+{
+	unsigned n = id >> SPENDSGIR_SHIFT;
+	return mmio_read_32(base + GICD_SPENDSGIR + (n << 2));
+}
+
+/*
+ * Accessor to write the GIC Distributor ITARGETSR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned n = id >> ITARGETSR_SHIFT;
+	mmio_write_32(base + GICD_ITARGETSR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor CPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned n = id >> CPENDSGIR_SHIFT;
+	mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val);
+}
+
+/*
+ * Accessor to write the GIC Distributor SPENDSGIR corresponding to the
+ * interrupt `id`, 4 interrupt IDs at a time.
+ */
+void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned n = id >> SPENDSGIR_SHIFT;
+	mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val);
+}
+
+/*******************************************************************************
+ * Get the current CPU bit mask from GICD_ITARGETSR0
+ ******************************************************************************/
+unsigned int gicv2_get_cpuif_id(uintptr_t base)
+{
+	unsigned int val;
+
+	val = gicd_read_itargetsr(base, 0);
+	return val & GIC_TARGET_CPU_MASK;
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of SPIs.
+ ******************************************************************************/
+void gicv2_spis_configure_defaults(uintptr_t gicd_base)
+{
+	unsigned int index, num_ints;
+
+	num_ints = gicd_read_typer(gicd_base);
+	num_ints &= TYPER_IT_LINES_NO_MASK;
+	num_ints = (num_ints + 1U) << 5;
+
+	/*
+	 * Treat all SPIs as G1NS by default. The number of interrupts is
+	 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
+	 */
+	for (index = MIN_SPI_ID; index < num_ints; index += 32U)
+		gicd_write_igroupr(gicd_base, index, ~0U);
+
+	/* Setup the default SPI priorities doing four at a time */
+	for (index = MIN_SPI_ID; index < num_ints; index += 4U)
+		gicd_write_ipriorityr(gicd_base,
+				      index,
+				      GICD_IPRIORITYR_DEF_VAL);
+
+	/* Treat all SPIs as level triggered by default, 16 at a time */
+	for (index = MIN_SPI_ID; index < num_ints; index += 16U)
+		gicd_write_icfgr(gicd_base, index, 0U);
+}
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 SPIs.
+ ******************************************************************************/
+void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *prop_desc;
+
+	/* Make sure there's a valid property array */
+	if (interrupt_props_num != 0U)
+		assert(interrupt_props != NULL);
+
+	for (i = 0; i < interrupt_props_num; i++) {
+		prop_desc = &interrupt_props[i];
+
+		if (prop_desc->intr_num < MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
+		gicd_clr_igroupr(gicd_base, prop_desc->intr_num);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
+				prop_desc->intr_pri);
+
+		/* Target the secure interrupts to primary CPU */
+		gicd_set_itargetsr(gicd_base, prop_desc->intr_num,
+				gicv2_get_cpuif_id(gicd_base));
+
+		/* Set interrupt configuration */
+		gicd_set_icfgr(gicd_base, prop_desc->intr_num,
+				prop_desc->intr_cfg);
+
+		/* Enable this interrupt */
+		gicd_set_isenabler(gicd_base, prop_desc->intr_num);
+	}
+}
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 SGIs and PPIs.
+ ******************************************************************************/
+void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	uint32_t sec_ppi_sgi_mask = 0;
+	const interrupt_prop_t *prop_desc;
+
+	/* Make sure there's a valid property array */
+	if (interrupt_props_num != 0U)
+		assert(interrupt_props != NULL);
+
+	/*
+	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+	 * more scalable approach as it avoids clearing the enable bits in the
+	 * GICD_CTLR.
+	 */
+	gicd_write_icenabler(gicd_base, 0U, ~0U);
+
+	/* Setup the default PPI/SGI priorities doing four at a time */
+	for (i = 0U; i < MIN_SPI_ID; i += 4U)
+		gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL);
+
+	for (i = 0U; i < interrupt_props_num; i++) {
+		prop_desc = &interrupt_props[i];
+
+		if (prop_desc->intr_num >= MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		assert(prop_desc->intr_grp == GICV2_INTR_GROUP0);
+
+		/*
+		 * Set interrupt configuration for PPIs. Configuration for SGIs
+		 * are ignored.
+		 */
+		if ((prop_desc->intr_num >= MIN_PPI_ID) &&
+				(prop_desc->intr_num < MIN_SPI_ID)) {
+			gicd_set_icfgr(gicd_base, prop_desc->intr_num,
+					prop_desc->intr_cfg);
+		}
+
+		/* We have an SGI or a PPI. They are Group0 at reset */
+		sec_ppi_sgi_mask |= (1u << prop_desc->intr_num);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, prop_desc->intr_num,
+				prop_desc->intr_pri);
+	}
+
+	/*
+	 * Invert the bitmask to create a mask for non-secure PPIs and SGIs.
+	 * Program the GICD_IGROUPR0 with this bit mask.
+	 */
+	gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask);
+
+	/* Enable the Group 0 SGIs and PPIs */
+	gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask);
+}
diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c
new file mode 100644
index 0000000..c5bced0
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_main.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/spinlock.h>
+
+#include "../common/gic_common_private.h"
+#include "gicv2_private.h"
+
+static const gicv2_driver_data_t *driver_data;
+
+/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+static spinlock_t gic_lock;
+
+/*******************************************************************************
+ * Enable secure interrupts and use FIQs to route them. Disable legacy bypass
+ * and set the priority mask register to allow all interrupts to trickle in.
+ ******************************************************************************/
+void gicv2_cpuif_enable(void)
+{
+	unsigned int val;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	/*
+	 * Enable the Group 0 interrupts, FIQEn and disable Group 0/1
+	 * bypass.
+	 */
+	val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0;
+	val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1;
+
+	/* Program the idle priority in the PMR */
+	gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK);
+	gicc_write_ctlr(driver_data->gicc_base, val);
+}
+
+/*******************************************************************************
+ * Place the cpu interface in a state where it can never make a cpu exit wfi as
+ * as result of an asserted interrupt. This is critical for powering down a cpu
+ ******************************************************************************/
+void gicv2_cpuif_disable(void)
+{
+	unsigned int val;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	/* Disable secure, non-secure interrupts and disable their bypass */
+	val = gicc_read_ctlr(driver_data->gicc_base);
+	val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT);
+	val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0;
+	val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1;
+	gicc_write_ctlr(driver_data->gicc_base, val);
+}
+
+/*******************************************************************************
+ * Per cpu gic distributor setup which will be done by all cpus after a cold
+ * boot/hotplug. This marks out the secure SPIs and PPIs & enables them.
+ ******************************************************************************/
+void gicv2_pcpu_distif_init(void)
+{
+	unsigned int ctlr;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+
+	gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base,
+			driver_data->interrupt_props,
+			driver_data->interrupt_props_num);
+
+	/* Enable G0 interrupts if not already */
+	ctlr = gicd_read_ctlr(driver_data->gicd_base);
+	if ((ctlr & CTLR_ENABLE_G0_BIT) == 0U) {
+		gicd_write_ctlr(driver_data->gicd_base,
+				ctlr | CTLR_ENABLE_G0_BIT);
+	}
+}
+
+/*******************************************************************************
+ * Global gic distributor init which will be done by the primary cpu after a
+ * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It
+ * then enables the secure GIC distributor interface.
+ ******************************************************************************/
+void gicv2_distif_init(void)
+{
+	unsigned int ctlr;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+
+	/* Disable the distributor before going further */
+	ctlr = gicd_read_ctlr(driver_data->gicd_base);
+	gicd_write_ctlr(driver_data->gicd_base,
+			ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT));
+
+	/* Set the default attribute of all SPIs */
+	gicv2_spis_configure_defaults(driver_data->gicd_base);
+
+	gicv2_secure_spis_configure_props(driver_data->gicd_base,
+			driver_data->interrupt_props,
+			driver_data->interrupt_props_num);
+
+
+	/* Re-enable the secure SPIs now that they have been configured */
+	gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT);
+}
+
+/*******************************************************************************
+ * Initialize the ARM GICv2 driver with the provided platform inputs
+ ******************************************************************************/
+void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data)
+{
+	unsigned int gic_version;
+
+	assert(plat_driver_data != NULL);
+	assert(plat_driver_data->gicd_base != 0U);
+	assert(plat_driver_data->gicc_base != 0U);
+
+	assert(plat_driver_data->interrupt_props_num > 0 ?
+			plat_driver_data->interrupt_props != NULL : 1);
+
+	/* Ensure that this is a GICv2 system */
+	gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
+	gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT)
+					& PIDR2_ARCH_REV_MASK;
+
+	/*
+	 * GICv1 with security extension complies with trusted firmware
+	 * GICv2 driver as far as virtualization and few tricky power
+	 * features are not used. GICv2 features that are not supported
+	 * by GICv1 with Security Extensions are:
+	 * - virtual interrupt support.
+	 * - wake up events.
+	 * - writeable GIC state register (for power sequences)
+	 * - interrupt priority drop.
+	 * - interrupt signal bypass.
+	 */
+	assert((gic_version == ARCH_REV_GICV2) ||
+	       (gic_version == ARCH_REV_GICV1));
+
+	driver_data = plat_driver_data;
+
+	/*
+	 * The GIC driver data is initialized by the primary CPU with caches
+	 * enabled. When the secondary CPU boots up, it initializes the
+	 * GICC/GICR interface with the caches disabled. Hence flush the
+	 * driver_data to ensure coherency. This is not required if the
+	 * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY
+	 * enabled.
+	 */
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+	flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data));
+	flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data));
+#endif
+	INFO("ARM GICv2 driver initialized\n");
+}
+
+/******************************************************************************
+ * This function returns whether FIQ is enabled in the GIC CPU interface.
+ *****************************************************************************/
+unsigned int gicv2_is_fiq_enabled(void)
+{
+	unsigned int gicc_ctlr;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base);
+	return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1U;
+}
+
+/*******************************************************************************
+ * This function returns the type of the highest priority pending interrupt at
+ * the GIC cpu interface. The return values can be one of the following :
+ *   PENDING_G1_INTID   : The interrupt type is non secure Group 1.
+ *   0 - 1019           : The interrupt type is secure Group 0.
+ *   GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
+ *                            sufficient priority to be signaled
+ ******************************************************************************/
+unsigned int gicv2_get_pending_interrupt_type(void)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
+}
+
+/*******************************************************************************
+ * This function returns the id of the highest priority pending interrupt at
+ * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no
+ * interrupt pending.
+ ******************************************************************************/
+unsigned int gicv2_get_pending_interrupt_id(void)
+{
+	unsigned int id;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK;
+
+	/*
+	 * Find out which non-secure interrupt it is under the assumption that
+	 * the GICC_CTLR.AckCtl bit is 0.
+	 */
+	if (id == PENDING_G1_INTID)
+		id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK;
+
+	return id;
+}
+
+/*******************************************************************************
+ * This functions reads the GIC cpu interface Interrupt Acknowledge register
+ * to start handling the pending secure 0 interrupt. It returns the
+ * contents of the IAR.
+ ******************************************************************************/
+unsigned int gicv2_acknowledge_interrupt(void)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	return gicc_read_IAR(driver_data->gicc_base);
+}
+
+/*******************************************************************************
+ * This functions writes the GIC cpu interface End Of Interrupt register with
+ * the passed value to finish handling the active secure group 0 interrupt.
+ ******************************************************************************/
+void gicv2_end_of_interrupt(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	gicc_write_EOIR(driver_data->gicc_base, id);
+}
+
+/*******************************************************************************
+ * This function returns the type of the interrupt id depending upon the group
+ * this interrupt has been configured under by the interrupt controller i.e.
+ * group0 secure or group1 non secure. It returns zero for Group 0 secure and
+ * one for Group 1 non secure interrupt.
+ ******************************************************************************/
+unsigned int gicv2_get_interrupt_group(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+
+	return gicd_get_igroupr(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function returns the priority of the interrupt the processor is
+ * currently servicing.
+ ******************************************************************************/
+unsigned int gicv2_get_running_priority(void)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	return gicc_read_rpr(driver_data->gicc_base);
+}
+
+/*******************************************************************************
+ * This function sets the GICv2 target mask pattern for the current PE. The PE
+ * target mask is used to translate linear PE index (returned by platform core
+ * position) to a bit mask used when targeting interrupts to a PE (for example
+ * when raising SGIs and routing SPIs).
+ ******************************************************************************/
+void gicv2_set_pe_target_mask(unsigned int proc_num)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+	assert(driver_data->target_masks != NULL);
+	assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE);
+	assert((unsigned int)proc_num < driver_data->target_masks_num);
+
+	/* Return if the target mask is already populated */
+	if (driver_data->target_masks[proc_num] != 0U)
+		return;
+
+	/*
+	 * Update target register corresponding to this CPU and flush for it to
+	 * be visible to other CPUs.
+	 */
+	if (driver_data->target_masks[proc_num] == 0U) {
+		driver_data->target_masks[proc_num] =
+			gicv2_get_cpuif_id(driver_data->gicd_base);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		/*
+		 * PEs only update their own masks. Primary updates it with
+		 * caches on. But because secondaries does it with caches off,
+		 * all updates go to memory directly, and there's no danger of
+		 * secondaries overwriting each others' mask, despite
+		 * target_masks[] not being cache line aligned.
+		 */
+		flush_dcache_range((uintptr_t)
+				&driver_data->target_masks[proc_num],
+				sizeof(driver_data->target_masks[proc_num]));
+#endif
+	}
+}
+
+/*******************************************************************************
+ * This function returns the active status of the interrupt (either because the
+ * state is active, or active and pending).
+ ******************************************************************************/
+unsigned int gicv2_get_interrupt_active(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+	assert(id <= MAX_SPI_ID);
+
+	return gicd_get_isactiver(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function enables the interrupt identified by id.
+ ******************************************************************************/
+void gicv2_enable_interrupt(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before enabling interrupt.
+	 */
+	dsbishst();
+	gicd_set_isenabler(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function disables the interrupt identified by id.
+ ******************************************************************************/
+void gicv2_disable_interrupt(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Disable interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	gicd_set_icenabler(driver_data->gicd_base, id);
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ ******************************************************************************/
+void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+	assert(id <= MAX_SPI_ID);
+
+	gicd_set_ipriorityr(driver_data->gicd_base, id, priority);
+}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The group can
+ * be any of GICV2_INTR_GROUP*
+ ******************************************************************************/
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+	assert(id <= MAX_SPI_ID);
+
+	/* Serialize read-modify-write to Distributor registers */
+	spin_lock(&gic_lock);
+	switch (type) {
+	case GICV2_INTR_GROUP1:
+		gicd_set_igroupr(driver_data->gicd_base, id);
+		break;
+	case GICV2_INTR_GROUP0:
+		gicd_clr_igroupr(driver_data->gicd_base, id);
+		break;
+	default:
+		assert(false);
+		break;
+	}
+	spin_unlock(&gic_lock);
+}
+
+/*******************************************************************************
+ * This function raises the specified SGI to requested targets.
+ *
+ * The proc_num parameter must be the linear index of the target PE in the
+ * system.
+ ******************************************************************************/
+void gicv2_raise_sgi(int sgi_num, int proc_num)
+{
+	unsigned int sgir_val, target;
+
+	assert(driver_data != NULL);
+	assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE);
+	assert(driver_data->gicd_base != 0U);
+
+	/*
+	 * Target masks array must have been supplied, and the core position
+	 * should be valid.
+	 */
+	assert(driver_data->target_masks != NULL);
+	assert((unsigned int)proc_num < driver_data->target_masks_num);
+
+	/* Don't raise SGI if the mask hasn't been populated */
+	target = driver_data->target_masks[proc_num];
+	assert(target != 0U);
+
+	sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before raising SGI.
+	 */
+	dsbishst();
+	gicd_write_sgir(driver_data->gicd_base, sgir_val);
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode. The proc_num parameter is
+ * linear index of the PE to target SPI. When proc_num < 0, the SPI may target
+ * all PEs.
+ ******************************************************************************/
+void gicv2_set_spi_routing(unsigned int id, int proc_num)
+{
+	unsigned int target;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+
+	assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID));
+
+	/*
+	 * Target masks array must have been supplied, and the core position
+	 * should be valid.
+	 */
+	assert(driver_data->target_masks != NULL);
+	assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE);
+	assert((unsigned int)proc_num < driver_data->target_masks_num);
+
+	if (proc_num < 0) {
+		/* Target all PEs */
+		target = GIC_TARGET_CPU_MASK;
+	} else {
+		/* Don't route interrupt if the mask hasn't been populated */
+		target = driver_data->target_masks[proc_num];
+		assert(target != 0U);
+	}
+
+	gicd_set_itargetsr(driver_data->gicd_base, id, target);
+}
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_clear_interrupt_pending(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+
+	/* SGIs can't be cleared pending */
+	assert(id >= MIN_PPI_ID);
+
+	/*
+	 * Clear pending interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	gicd_set_icpendr(driver_data->gicd_base, id);
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ ******************************************************************************/
+void gicv2_set_interrupt_pending(unsigned int id)
+{
+	assert(driver_data != NULL);
+	assert(driver_data->gicd_base != 0U);
+
+	/* SGIs can't be cleared pending */
+	assert(id >= MIN_PPI_ID);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before setting interrupt pending.
+	 */
+	dsbishst();
+	gicd_set_ispendr(driver_data->gicd_base, id);
+}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv2_set_pmr(unsigned int mask)
+{
+	unsigned int old_mask;
+
+	assert(driver_data != NULL);
+	assert(driver_data->gicc_base != 0U);
+
+	old_mask = gicc_read_pmr(driver_data->gicc_base);
+
+	/*
+	 * Order memory updates w.r.t. PMR write, and ensure they're visible
+	 * before potential out of band interrupt trigger because of PMR update.
+	 */
+	dmbishst();
+	gicc_write_pmr(driver_data->gicc_base, mask);
+	dsbishst();
+
+	return old_mask;
+}
+
+/*******************************************************************************
+ * This function updates single interrupt configuration to be level/edge
+ * triggered
+ ******************************************************************************/
+void gicv2_interrupt_set_cfg(unsigned int id, unsigned int cfg)
+{
+	gicd_set_icfgr(driver_data->gicd_base, id, cfg);
+}
diff --git a/drivers/arm/gic/v2/gicv2_private.h b/drivers/arm/gic/v2/gicv2_private.h
new file mode 100644
index 0000000..0fbdab0
--- /dev/null
+++ b/drivers/arm/gic/v2/gicv2_private.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV2_PRIVATE_H
+#define GICV2_PRIVATE_H
+
+#include <stdint.h>
+
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+/*******************************************************************************
+ * Private function prototypes
+ ******************************************************************************/
+void gicv2_spis_configure_defaults(uintptr_t gicd_base);
+void gicv2_secure_spis_configure_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
+void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
+unsigned int gicv2_get_cpuif_id(uintptr_t base);
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for reading entire registers
+ ******************************************************************************/
+static inline unsigned int gicd_read_pidr2(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_PIDR2_GICV2);
+}
+
+/*******************************************************************************
+ * GIC Distributor interface accessors for writing entire registers
+ ******************************************************************************/
+static inline unsigned int gicd_get_itargetsr(uintptr_t base, unsigned int id)
+{
+	return mmio_read_8(base + GICD_ITARGETSR + id);
+}
+
+static inline void gicd_set_itargetsr(uintptr_t base, unsigned int id,
+		unsigned int target)
+{
+	uint8_t val = target & GIC_TARGET_CPU_MASK;
+
+	mmio_write_8(base + GICD_ITARGETSR + id, val);
+}
+
+static inline void gicd_write_sgir(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICD_SGIR, val);
+}
+
+/*******************************************************************************
+ * GIC CPU interface accessors for reading entire registers
+ ******************************************************************************/
+
+static inline unsigned int gicc_read_ctlr(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_CTLR);
+}
+
+static inline unsigned int gicc_read_pmr(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_PMR);
+}
+
+static inline unsigned int gicc_read_BPR(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_BPR);
+}
+
+static inline unsigned int gicc_read_IAR(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_IAR);
+}
+
+static inline unsigned int gicc_read_EOIR(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_EOIR);
+}
+
+static inline unsigned int gicc_read_hppir(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_HPPIR);
+}
+
+static inline unsigned int gicc_read_ahppir(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_AHPPIR);
+}
+
+static inline unsigned int gicc_read_dir(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_DIR);
+}
+
+static inline unsigned int gicc_read_iidr(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_IIDR);
+}
+
+static inline unsigned int gicc_read_rpr(uintptr_t base)
+{
+	return mmio_read_32(base + GICC_RPR);
+}
+
+/*******************************************************************************
+ * GIC CPU interface accessors for writing entire registers
+ ******************************************************************************/
+
+static inline void gicc_write_ctlr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_CTLR, val);
+}
+
+static inline void gicc_write_pmr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_PMR, val);
+}
+
+static inline void gicc_write_BPR(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_BPR, val);
+}
+
+
+static inline void gicc_write_IAR(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_IAR, val);
+}
+
+static inline void gicc_write_EOIR(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_EOIR, val);
+}
+
+static inline void gicc_write_hppir(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_HPPIR, val);
+}
+
+static inline void gicc_write_dir(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICC_DIR, val);
+}
+
+#endif /* GICV2_PRIVATE_H */
diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c
new file mode 100644
index 0000000..4489892
--- /dev/null
+++ b/drivers/arm/gic/v3/arm_gicv3_common.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for implementation defined features that are identical in ARM GICv3
+* implementations (GIC-500 and GIC-600 for now). This driver only overrides
+* APIs that are different to those generic ones in GICv3 driver.
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <drivers/arm/gicv3.h>
+
+#include "gicv3_private.h"
+
+/*
+ * Flush the internal GIC cache of the LPIs pending tables to memory before
+ * saving the state of the Redistributor. This is required before powering off
+ * the GIC when the pending status must be preserved.
+ * `rdist_proc_num` is the processor number corresponding to the Redistributor of the
+ * current CPU.
+ */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
+{
+	uintptr_t gicr_base = 0;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	/*
+	 * The GICR_WAKER.Sleep bit should be set only when both
+	 * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on
+	 * all the Redistributors.
+	 */
+	for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) {
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[i];
+		assert(gicr_base);
+		assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT);
+		assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT);
+	}
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+	/*
+	 * According to the TRM, there is only one instance of the
+	 * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+	 * through any of the Redistributor.
+	 */
+
+	/*
+	 * Set GICR_WAKER.Sleep
+	 * After this point, the system must be configured so that the
+	 * wake_request signals for the right cores are asserted when a wakeup
+	 * interrupt is detected. The GIC will not be able to do that anymore
+	 * when the GICR_WAKER.Sleep bit is set to 1.
+	 */
+	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT);
+
+	/* Wait until the GICR_WAKER.Quiescent bit is set */
+	while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT))
+		;
+}
+
+/*
+ * Allow the LPIs pending state to be read back from the tables in memory after
+ * having restored the state of the GIC Redistributor.
+ */
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	/*
+	 * According to the TRM, there is only one instance of the
+	 * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed
+	 * through any of the Redistributor.
+	 */
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num];
+	assert(gicr_base);
+
+	/*
+	 * If the GIC had power removed, the GICR_WAKER state will be reset.
+	 * Since the GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits are cleared,
+	 * we can exit early. This also prevents the following assert from
+	 * erroneously triggering.
+	 */
+	if (!(gicr_read_waker(gicr_base) & WAKER_SL_BIT))
+		return;
+
+	/*
+	 * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent
+	 * bit is not set. We should be alright on power on path, therefore
+	 * coming out of sleep and Quiescent should be set, but we assert in
+	 * case.
+	 */
+	assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT);
+
+	/* Clear GICR_WAKER.Sleep */
+	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT);
+
+	/*
+	 * We don't know if the effects of setting GICR_WAKER.Sleep bit is
+	 * instantaneous, so we wait until the interface is not Quiescent
+	 * anymore.
+	 */
+	while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT)
+		;
+}
+
diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c
new file mode 100644
index 0000000..f03e33f
--- /dev/null
+++ b/drivers/arm/gic/v3/gic500.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC500-specific features. This driver only overrides APIs that are
+ * different to those generic ones in GICv3 driver.
+ */
+#include "gicv3_private.h"
+
+void gicv3_distif_pre_save(unsigned int proc_num)
+{
+	arm_gicv3_distif_pre_save(proc_num);
+}
+
+void gicv3_distif_post_restore(unsigned int proc_num)
+{
+	arm_gicv3_distif_post_restore(proc_num);
+}
+
diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic600.c
new file mode 100644
index 0000000..9cb2ab2
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC600-specific features. This driver only overrides APIs that are
+ * different to those generic ones in GICv3 driver.
+ *
+ * GIC600 supports independently power-gating redistributor interface.
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/gicv3.h>
+
+#include "gicv3_private.h"
+
+/* GIC600-specific register offsets */
+#define GICR_PWRR	0x24
+
+/* GICR_PWRR fields */
+#define PWRR_RDPD_SHIFT		0
+#define PWRR_RDGPD_SHIFT	2
+#define PWRR_RDGPO_SHIFT	3
+
+#define PWRR_RDGPD	(1 << PWRR_RDGPD_SHIFT)
+#define PWRR_RDGPO	(1 << PWRR_RDGPO_SHIFT)
+
+/* Values to write to GICR_PWRR register to power redistributor */
+#define PWRR_ON		(0 << PWRR_RDPD_SHIFT)
+#define PWRR_OFF	(1 << PWRR_RDPD_SHIFT)
+
+/* GIC600-specific accessor functions */
+static void gicr_write_pwrr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_PWRR, val);
+}
+
+static uint32_t gicr_read_pwrr(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_PWRR);
+}
+
+static int gicr_group_powering_down(uint32_t pwrr)
+{
+	/*
+	 * Whether the redistributor group power down operation is in transit:
+	 * i.e. it's intending to, but not finished yet.
+	 */
+	return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO));
+}
+
+static void gic600_pwr_on(uintptr_t base)
+{
+	/* Power on redistributor */
+	gicr_write_pwrr(base, PWRR_ON);
+
+	/* Wait until the power on state is reflected */
+	while (gicr_read_pwrr(base) & PWRR_RDGPO)
+		;
+}
+
+static void gic600_pwr_off(uintptr_t base)
+{
+	/* Power off redistributor */
+	gicr_write_pwrr(base, PWRR_OFF);
+
+	/*
+	 * If this is the last man, turning this redistributor frame off will
+	 * result in the group itself being powered off. In that case, wait as
+	 * long as it's in transition, or has aborted the transition altogether
+	 * for any reason.
+	 */
+	if (gicr_read_pwrr(base) & PWRR_RDGPD) {
+		while (gicr_group_powering_down(gicr_read_pwrr(base)))
+			;
+	}
+}
+
+void gicv3_distif_pre_save(unsigned int proc_num)
+{
+	arm_gicv3_distif_pre_save(proc_num);
+}
+
+void gicv3_distif_post_restore(unsigned int proc_num)
+{
+	arm_gicv3_distif_post_restore(proc_num);
+}
+
+/*
+ * Power off GIC600 redistributor
+ */
+void gicv3_rdistif_off(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base);
+
+	/* Attempt to power redistributor off */
+	gic600_pwr_off(gicr_base);
+}
+
+/*
+ * Power on GIC600 redistributor
+ */
+void gicv3_rdistif_on(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base);
+
+	/* Power redistributor on */
+	gic600_pwr_on(gicr_base);
+}
diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c
new file mode 100644
index 0000000..710532e
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_helpers.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+
+#include "../common/gic_common_private.h"
+#include "gicv3_private.h"
+
+/*
+ * Accessor to read the GIC Distributor IGRPMODR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> IGRPMODR_SHIFT;
+
+	return mmio_read_32(base + GICD_IGRPMODR + (n << 2));
+}
+
+/*
+ * Accessor to write the GIC Distributor IGRPMODR corresponding to the
+ * interrupt `id`, 32 interrupt IDs at a time.
+ */
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> IGRPMODR_SHIFT;
+
+	mmio_write_32(base + GICD_IGRPMODR + (n << 2), val);
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR.
+ */
+unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_igrpmodr(base, id);
+
+	return (reg_val >> bit_num) & 0x1U;
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR.
+ */
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_igrpmodr(base, id);
+
+	gicd_write_igrpmodr(base, id, reg_val | (1U << bit_num));
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID
+ * in GIC Distributor IGRPMODR.
+ */
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
+	unsigned int reg_val = gicd_read_igrpmodr(base, id);
+
+	gicd_write_igrpmodr(base, id, reg_val & ~(1U << bit_num));
+}
+
+/*
+ * Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupts IDs at a time.
+ */
+unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> IPRIORITYR_SHIFT;
+
+	return mmio_read_32(base + GICR_IPRIORITYR + (n << 2));
+}
+
+/*
+ * Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the
+ * interrupt `id`, 4 interrupts IDs at a time.
+ */
+void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val)
+{
+	unsigned int n = id >> IPRIORITYR_SHIFT;
+
+	mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val);
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt ID
+ * from GIC Re-distributor IGROUPR0.
+ */
+unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_igroupr0(base);
+
+	return (reg_val >> bit_num) & 0x1U;
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGROUPR0.
+ */
+void gicr_set_igroupr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_igroupr0(base);
+
+	gicr_write_igroupr0(base, reg_val | (1U << bit_num));
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGROUPR0.
+ */
+void gicr_clr_igroupr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_igroupr0(base);
+
+	gicr_write_igroupr0(base, reg_val & ~(1U << bit_num));
+}
+
+/*
+ * Accessor to get the bit corresponding to interrupt ID
+ * from GIC Re-distributor IGRPMODR0.
+ */
+unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_igrpmodr0(base);
+
+	return (reg_val >> bit_num) & 0x1U;
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGRPMODR0.
+ */
+void gicr_set_igrpmodr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_igrpmodr0(base);
+
+	gicr_write_igrpmodr0(base, reg_val | (1U << bit_num));
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID
+ * in GIC Re-distributor IGRPMODR0.
+ */
+void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_igrpmodr0(base);
+
+	gicr_write_igrpmodr0(base, reg_val & ~(1U << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID
+ * in GIC Re-distributor ISENABLER0.
+ */
+void gicr_set_isenabler0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U);
+
+	gicr_write_isenabler0(base, (1U << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICENABLER0.
+ */
+void gicr_set_icenabler0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U);
+
+	gicr_write_icenabler0(base, (1U << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISACTIVER0.
+ */
+unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U);
+	unsigned int reg_val = gicr_read_isactiver0(base);
+
+	return (reg_val >> bit_num) & 0x1U;
+}
+
+/*
+ * Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor
+ * ICPENDRR0.
+ */
+void gicr_set_icpendr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U);
+
+	gicr_write_icpendr0(base, (1U << bit_num));
+}
+
+/*
+ * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor
+ * ISPENDR0.
+ */
+void gicr_set_ispendr0(uintptr_t base, unsigned int id)
+{
+	unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U);
+
+	gicr_write_ispendr0(base, (1U << bit_num));
+}
+
+/*
+ * Accessor to set the byte corresponding to interrupt ID
+ * in GIC Re-distributor IPRIORITYR.
+ */
+void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri)
+{
+	uint8_t val = pri & GIC_PRI_MASK;
+
+	mmio_write_8(base + GICR_IPRIORITYR + id, val);
+}
+
+/*
+ * Accessor to set the bit fields corresponding to interrupt ID
+ * in GIC Re-distributor ICFGR0.
+ */
+void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	/* Interrupt configuration is a 2-bit field */
+	unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U);
+	unsigned int bit_shift = bit_num << 1U;
+
+	uint32_t reg_val = gicr_read_icfgr0(base);
+
+	/* Clear the field, and insert required configuration */
+	reg_val &= ~(GIC_CFG_MASK << bit_shift);
+	reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift);
+
+	gicr_write_icfgr0(base, reg_val);
+}
+
+/*
+ * Accessor to set the bit fields corresponding to interrupt ID
+ * in GIC Re-distributor ICFGR1.
+ */
+void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg)
+{
+	/* Interrupt configuration is a 2-bit field */
+	unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U);
+	unsigned int bit_shift = bit_num << 1U;
+
+	uint32_t reg_val = gicr_read_icfgr1(base);
+
+	/* Clear the field, and insert required configuration */
+	reg_val &= ~(GIC_CFG_MASK << bit_shift);
+	reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift);
+
+	gicr_write_icfgr1(base, reg_val);
+}
+
+/******************************************************************************
+ * This function marks the core as awake in the re-distributor and
+ * ensures that the interface is active.
+ *****************************************************************************/
+void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base)
+{
+	/*
+	 * The WAKER_PS_BIT should be changed to 0
+	 * only when WAKER_CA_BIT is 1.
+	 */
+	assert((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U);
+
+	/* Mark the connected core as awake */
+	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT);
+
+	/* Wait till the WAKER_CA_BIT changes to 0 */
+	while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U)
+		;
+}
+
+
+/******************************************************************************
+ * This function marks the core as asleep in the re-distributor and ensures
+ * that the interface is quiescent.
+ *****************************************************************************/
+void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base)
+{
+	/* Mark the connected core as asleep */
+	gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT);
+
+	/* Wait till the WAKER_CA_BIT changes to 1 */
+	while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U)
+		;
+}
+
+
+/*******************************************************************************
+ * This function probes the Redistributor frames when the driver is initialised
+ * and saves their base addresses. These base addresses are used later to
+ * initialise each Redistributor interface.
+ ******************************************************************************/
+void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
+					unsigned int rdistif_num,
+					uintptr_t gicr_base,
+					mpidr_hash_fn mpidr_to_core_pos)
+{
+	u_register_t mpidr;
+	unsigned int proc_num;
+	uint64_t typer_val;
+	uintptr_t rdistif_base = gicr_base;
+
+	assert(rdistif_base_addrs != NULL);
+
+	/*
+	 * Iterate over the Redistributor frames. Store the base address of each
+	 * frame in the platform provided array. Use the "Processor Number"
+	 * field to index into the array if the platform has not provided a hash
+	 * function to convert an MPIDR (obtained from the "Affinity Value"
+	 * field into a linear index.
+	 */
+	do {
+		typer_val = gicr_read_typer(rdistif_base);
+		if (mpidr_to_core_pos != NULL) {
+			mpidr = mpidr_from_gicr_typer(typer_val);
+			proc_num = mpidr_to_core_pos(mpidr);
+		} else {
+			proc_num = (typer_val >> TYPER_PROC_NUM_SHIFT) &
+				TYPER_PROC_NUM_MASK;
+		}
+
+		if (proc_num < rdistif_num)
+			rdistif_base_addrs[proc_num] = rdistif_base;
+
+		rdistif_base += (1U << GICR_PCPUBASE_SHIFT);
+	} while ((typer_val & TYPER_LAST_BIT) == 0U);
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of SPIs.
+ ******************************************************************************/
+void gicv3_spis_config_defaults(uintptr_t gicd_base)
+{
+	unsigned int index, num_ints;
+
+	num_ints = gicd_read_typer(gicd_base);
+	num_ints &= TYPER_IT_LINES_NO_MASK;
+	num_ints = (num_ints + 1U) << 5;
+
+	/*
+	 * Treat all SPIs as G1NS by default. The number of interrupts is
+	 * calculated as 32 * (IT_LINES + 1). We do 32 at a time.
+	 */
+	for (index = MIN_SPI_ID; index < num_ints; index += 32U)
+		gicd_write_igroupr(gicd_base, index, ~0U);
+
+	/* Setup the default SPI priorities doing four at a time */
+	for (index = MIN_SPI_ID; index < num_ints; index += 4U)
+		gicd_write_ipriorityr(gicd_base,
+				      index,
+				      GICD_IPRIORITYR_DEF_VAL);
+
+	/*
+	 * Treat all SPIs as level triggered by default, write 16 at
+	 * a time
+	 */
+	for (index = MIN_SPI_ID; index < num_ints; index += 16U)
+		gicd_write_icfgr(gicd_base, index, 0U);
+}
+
+/*******************************************************************************
+ * Helper function to configure properties of secure SPIs
+ ******************************************************************************/
+unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *current_prop;
+	unsigned long long gic_affinity_val;
+	unsigned int ctlr_enable = 0U;
+
+	/* Make sure there's a valid property array */
+	if (interrupt_props_num > 0U)
+		assert(interrupt_props != NULL);
+
+	for (i = 0U; i < interrupt_props_num; i++) {
+		current_prop = &interrupt_props[i];
+
+		if (current_prop->intr_num < MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		gicd_clr_igroupr(gicd_base, current_prop->intr_num);
+
+		/* Configure this interrupt as G0 or a G1S interrupt */
+		assert((current_prop->intr_grp == INTR_GROUP0) ||
+				(current_prop->intr_grp == INTR_GROUP1S));
+		if (current_prop->intr_grp == INTR_GROUP1S) {
+			gicd_set_igrpmodr(gicd_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+		} else {
+			gicd_clr_igrpmodr(gicd_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G0_BIT;
+		}
+
+		/* Set interrupt configuration */
+		gicd_set_icfgr(gicd_base, current_prop->intr_num,
+				current_prop->intr_cfg);
+
+		/* Set the priority of this interrupt */
+		gicd_set_ipriorityr(gicd_base, current_prop->intr_num,
+				current_prop->intr_pri);
+
+		/* Target SPIs to the primary CPU */
+		gic_affinity_val =
+			gicd_irouter_val_from_mpidr(read_mpidr(), 0U);
+		gicd_write_irouter(gicd_base, current_prop->intr_num,
+				gic_affinity_val);
+
+		/* Enable this interrupt */
+		gicd_set_isenabler(gicd_base, current_prop->intr_num);
+	}
+
+	return ctlr_enable;
+}
+
+/*******************************************************************************
+ * Helper function to configure the default attributes of SPIs.
+ ******************************************************************************/
+void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base)
+{
+	unsigned int index;
+
+	/*
+	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+	 * more scalable approach as it avoids clearing the enable bits in the
+	 * GICD_CTLR
+	 */
+	gicr_write_icenabler0(gicr_base, ~0U);
+	gicr_wait_for_pending_write(gicr_base);
+
+	/* Treat all SGIs/PPIs as G1NS by default. */
+	gicr_write_igroupr0(gicr_base, ~0U);
+
+	/* Setup the default PPI/SGI priorities doing four at a time */
+	for (index = 0U; index < MIN_SPI_ID; index += 4U)
+		gicr_write_ipriorityr(gicr_base,
+				      index,
+				      GICD_IPRIORITYR_DEF_VAL);
+
+	/* Configure all PPIs as level triggered by default */
+	gicr_write_icfgr1(gicr_base, 0U);
+}
+
+/*******************************************************************************
+ * Helper function to configure properties of secure G0 and G1S PPIs and SGIs.
+ ******************************************************************************/
+unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num)
+{
+	unsigned int i;
+	const interrupt_prop_t *current_prop;
+	unsigned int ctlr_enable = 0U;
+
+	/* Make sure there's a valid property array */
+	if (interrupt_props_num > 0U)
+		assert(interrupt_props != NULL);
+
+	for (i = 0U; i < interrupt_props_num; i++) {
+		current_prop = &interrupt_props[i];
+
+		if (current_prop->intr_num >= MIN_SPI_ID)
+			continue;
+
+		/* Configure this interrupt as a secure interrupt */
+		gicr_clr_igroupr0(gicr_base, current_prop->intr_num);
+
+		/* Configure this interrupt as G0 or a G1S interrupt */
+		assert((current_prop->intr_grp == INTR_GROUP0) ||
+				(current_prop->intr_grp == INTR_GROUP1S));
+		if (current_prop->intr_grp == INTR_GROUP1S) {
+			gicr_set_igrpmodr0(gicr_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G1S_BIT;
+		} else {
+			gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num);
+			ctlr_enable |= CTLR_ENABLE_G0_BIT;
+		}
+
+		/* Set the priority of this interrupt */
+		gicr_set_ipriorityr(gicr_base, current_prop->intr_num,
+				current_prop->intr_pri);
+
+		/*
+		 * Set interrupt configuration for PPIs. Configuration for SGIs
+		 * are ignored.
+		 */
+		if ((current_prop->intr_num >= MIN_PPI_ID) &&
+				(current_prop->intr_num < MIN_SPI_ID)) {
+			gicr_set_icfgr1(gicr_base, current_prop->intr_num,
+					current_prop->intr_cfg);
+		}
+
+		/* Enable this interrupt */
+		gicr_set_isenabler0(gicr_base, current_prop->intr_num);
+	}
+
+	return ctlr_enable;
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
new file mode 100644
index 0000000..94a20ba
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -0,0 +1,1083 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/spinlock.h>
+
+#include "gicv3_private.h"
+
+const gicv3_driver_data_t *gicv3_driver_data;
+static unsigned int gicv2_compat;
+
+/*
+ * Spinlock to guard registers needing read-modify-write. APIs protected by this
+ * spinlock are used either at boot time (when only a single CPU is active), or
+ * when the system is fully coherent.
+ */
+static spinlock_t gic_lock;
+
+/*
+ * Redistributor power operations are weakly bound so that they can be
+ * overridden
+ */
+#pragma weak gicv3_rdistif_off
+#pragma weak gicv3_rdistif_on
+
+
+/* Helper macros to save and restore GICD registers to and from the context */
+#define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG)		\
+	do {								\
+		for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \
+				int_id += (1U << REG##_SHIFT)) {	\
+			gicd_write_##reg(base, int_id,			\
+				ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \
+		}							\
+	} while (false)
+
+#define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG)			\
+	do {								\
+		for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \
+				int_id += (1U << REG##_SHIFT)) {	\
+			ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\
+					gicd_read_##reg(base, int_id);	\
+		}							\
+	} while (false)
+
+
+/*******************************************************************************
+ * This function initialises the ARM GICv3 driver in EL3 with provided platform
+ * inputs.
+ ******************************************************************************/
+void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
+{
+	unsigned int gic_version;
+
+	assert(plat_driver_data != NULL);
+	assert(plat_driver_data->gicd_base != 0U);
+	assert(plat_driver_data->gicr_base != 0U);
+	assert(plat_driver_data->rdistif_num != 0U);
+	assert(plat_driver_data->rdistif_base_addrs != NULL);
+
+	assert(IS_IN_EL3());
+
+	assert(plat_driver_data->interrupt_props_num > 0 ?
+	       plat_driver_data->interrupt_props != NULL : 1);
+
+	/* Check for system register support */
+#ifdef __aarch64__
+	assert((read_id_aa64pfr0_el1() &
+			(ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U);
+#else
+	assert((read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U);
+#endif /* __aarch64__ */
+
+	/* The GIC version should be 3.0 */
+	gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
+	gic_version >>=	PIDR2_ARCH_REV_SHIFT;
+	gic_version &= PIDR2_ARCH_REV_MASK;
+	assert(gic_version == ARCH_REV_GICV3);
+
+	/*
+	 * Find out whether the GIC supports the GICv2 compatibility mode. The
+	 * ARE_S bit resets to 0 if supported
+	 */
+	gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base);
+	gicv2_compat >>= CTLR_ARE_S_SHIFT;
+	gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK);
+
+	/*
+	 * Find the base address of each implemented Redistributor interface.
+	 * The number of interfaces should be equal to the number of CPUs in the
+	 * system. The memory for saving these addresses has to be allocated by
+	 * the platform port
+	 */
+	gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
+					   plat_driver_data->rdistif_num,
+					   plat_driver_data->gicr_base,
+					   plat_driver_data->mpidr_to_core_pos);
+
+	gicv3_driver_data = plat_driver_data;
+
+	/*
+	 * The GIC driver data is initialized by the primary CPU with caches
+	 * enabled. When the secondary CPU boots up, it initializes the
+	 * GICC/GICR interface with the caches disabled. Hence flush the
+	 * driver data to ensure coherency. This is not required if the
+	 * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY
+	 * enabled.
+	 */
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+	flush_dcache_range((uintptr_t) &gicv3_driver_data,
+			sizeof(gicv3_driver_data));
+	flush_dcache_range((uintptr_t) gicv3_driver_data,
+			sizeof(*gicv3_driver_data));
+#endif
+
+	INFO("GICv3 %s legacy support detected."
+			" ARM GICV3 driver initialized in EL3\n",
+			gicv2_compat ? "with" : "without");
+}
+
+/*******************************************************************************
+ * This function initialises the GIC distributor interface based upon the data
+ * provided by the platform while initialising the driver.
+ ******************************************************************************/
+void __init gicv3_distif_init(void)
+{
+	unsigned int bitmap = 0;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+
+	assert(IS_IN_EL3());
+
+	/*
+	 * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
+	 * the ARE_S bit. The Distributor might generate a system error
+	 * otherwise.
+	 */
+	gicd_clr_ctlr(gicv3_driver_data->gicd_base,
+		      CTLR_ENABLE_G0_BIT |
+		      CTLR_ENABLE_G1S_BIT |
+		      CTLR_ENABLE_G1NS_BIT,
+		      RWP_TRUE);
+
+	/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
+	gicd_set_ctlr(gicv3_driver_data->gicd_base,
+			CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
+
+	/* Set the default attribute of all SPIs */
+	gicv3_spis_config_defaults(gicv3_driver_data->gicd_base);
+
+	bitmap = gicv3_secure_spis_config_props(
+			gicv3_driver_data->gicd_base,
+			gicv3_driver_data->interrupt_props,
+			gicv3_driver_data->interrupt_props_num);
+
+	/* Enable the secure SPIs now that they have been configured */
+	gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
+}
+
+/*******************************************************************************
+ * This function initialises the GIC Redistributor interface of the calling CPU
+ * (identified by the 'proc_num' parameter) based upon the data provided by the
+ * platform while initialising the driver.
+ ******************************************************************************/
+void gicv3_rdistif_init(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+	unsigned int bitmap = 0U;
+	uint32_t ctlr;
+
+	assert(gicv3_driver_data != NULL);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+
+	ctlr = gicd_read_ctlr(gicv3_driver_data->gicd_base);
+	assert((ctlr & CTLR_ARE_S_BIT) != 0U);
+
+	assert(IS_IN_EL3());
+
+	/* Power on redistributor */
+	gicv3_rdistif_on(proc_num);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+	/* Set the default attribute of all SGIs and PPIs */
+	gicv3_ppi_sgi_config_defaults(gicr_base);
+
+	bitmap = gicv3_secure_ppi_sgi_config_props(gicr_base,
+			gicv3_driver_data->interrupt_props,
+			gicv3_driver_data->interrupt_props_num);
+
+	/* Enable interrupt groups as required, if not already */
+	if ((ctlr & bitmap) != bitmap)
+		gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
+}
+
+/*******************************************************************************
+ * Functions to perform power operations on GIC Redistributor
+ ******************************************************************************/
+void gicv3_rdistif_off(unsigned int proc_num)
+{
+	return;
+}
+
+void gicv3_rdistif_on(unsigned int proc_num)
+{
+	return;
+}
+
+/*******************************************************************************
+ * This function enables the GIC CPU interface of the calling CPU using only
+ * system register accesses.
+ ******************************************************************************/
+void gicv3_cpuif_enable(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+	unsigned int scr_el3;
+	unsigned int icc_sre_el3;
+
+	assert(gicv3_driver_data != NULL);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(IS_IN_EL3());
+
+	/* Mark the connected core as awake */
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	gicv3_rdistif_mark_core_awake(gicr_base);
+
+	/* Disable the legacy interrupt bypass */
+	icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT;
+
+	/*
+	 * Enable system register access for EL3 and allow lower exception
+	 * levels to configure the same for themselves. If the legacy mode is
+	 * not supported, the SRE bit is RAO/WI
+	 */
+	icc_sre_el3 |= (ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT);
+	write_icc_sre_el3(read_icc_sre_el3() | icc_sre_el3);
+
+	scr_el3 = (uint32_t) read_scr_el3();
+
+	/*
+	 * Switch to NS state to write Non secure ICC_SRE_EL1 and
+	 * ICC_SRE_EL2 registers.
+	 */
+	write_scr_el3(scr_el3 | SCR_NS_BIT);
+	isb();
+
+	write_icc_sre_el2(read_icc_sre_el2() | icc_sre_el3);
+	write_icc_sre_el1(ICC_SRE_SRE_BIT);
+	isb();
+
+	/* Switch to secure state. */
+	write_scr_el3(scr_el3 & (~SCR_NS_BIT));
+	isb();
+
+	/* Write the secure ICC_SRE_EL1 register */
+	write_icc_sre_el1(ICC_SRE_SRE_BIT);
+	isb();
+
+	/* Program the idle priority in the PMR */
+	write_icc_pmr_el1(GIC_PRI_MASK);
+
+	/* Enable Group0 interrupts */
+	write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT);
+
+	/* Enable Group1 Secure interrupts */
+	write_icc_igrpen1_el3(read_icc_igrpen1_el3() |
+				IGRPEN1_EL3_ENABLE_G1S_BIT);
+	isb();
+}
+
+/*******************************************************************************
+ * This function disables the GIC CPU interface of the calling CPU using
+ * only system register accesses.
+ ******************************************************************************/
+void gicv3_cpuif_disable(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data != NULL);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+
+	assert(IS_IN_EL3());
+
+	/* Disable legacy interrupt bypass */
+	write_icc_sre_el3(read_icc_sre_el3() |
+			  (ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT));
+
+	/* Disable Group0 interrupts */
+	write_icc_igrpen0_el1(read_icc_igrpen0_el1() &
+			      ~IGRPEN1_EL1_ENABLE_G0_BIT);
+
+	/* Disable Group1 Secure and Non-Secure interrupts */
+	write_icc_igrpen1_el3(read_icc_igrpen1_el3() &
+			      ~(IGRPEN1_EL3_ENABLE_G1NS_BIT |
+			      IGRPEN1_EL3_ENABLE_G1S_BIT));
+
+	/* Synchronise accesses to group enable registers */
+	isb();
+
+	/* Mark the connected core as asleep */
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	gicv3_rdistif_mark_core_asleep(gicr_base);
+}
+
+/*******************************************************************************
+ * This function returns the id of the highest priority pending interrupt at
+ * the GIC cpu interface.
+ ******************************************************************************/
+unsigned int gicv3_get_pending_interrupt_id(void)
+{
+	unsigned int id;
+
+	assert(IS_IN_EL3());
+	id = (uint32_t)read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK;
+
+	/*
+	 * If the ID is special identifier corresponding to G1S or G1NS
+	 * interrupt, then read the highest pending group 1 interrupt.
+	 */
+	if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID))
+		return (uint32_t)read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK;
+
+	return id;
+}
+
+/*******************************************************************************
+ * This function returns the type of the highest priority pending interrupt at
+ * the GIC cpu interface. The return values can be one of the following :
+ *   PENDING_G1S_INTID  : The interrupt type is secure Group 1.
+ *   PENDING_G1NS_INTID : The interrupt type is non secure Group 1.
+ *   0 - 1019           : The interrupt type is secure Group 0.
+ *   GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with
+ *                            sufficient priority to be signaled
+ ******************************************************************************/
+unsigned int gicv3_get_pending_interrupt_type(void)
+{
+	assert(IS_IN_EL3());
+	return (uint32_t)read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK;
+}
+
+/*******************************************************************************
+ * This function returns the type of the interrupt id depending upon the group
+ * this interrupt has been configured under by the interrupt controller i.e.
+ * group0 or group1 Secure / Non Secure. The return value can be one of the
+ * following :
+ *    INTR_GROUP0  : The interrupt type is a Secure Group 0 interrupt
+ *    INTR_GROUP1S : The interrupt type is a Secure Group 1 secure interrupt
+ *    INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure
+ *                   interrupt.
+ ******************************************************************************/
+unsigned int gicv3_get_interrupt_type(unsigned int id,
+					  unsigned int proc_num)
+{
+	unsigned int igroup, grpmodr;
+	uintptr_t gicr_base;
+
+	assert(IS_IN_EL3());
+	assert(gicv3_driver_data != NULL);
+
+	/* Ensure the parameters are valid */
+	assert((id < PENDING_G1S_INTID) || (id >= MIN_LPI_ID));
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+
+	/* All LPI interrupts are Group 1 non secure */
+	if (id >= MIN_LPI_ID)
+		return INTR_GROUP1NS;
+
+	if (id < MIN_SPI_ID) {
+		assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+		igroup = gicr_get_igroupr0(gicr_base, id);
+		grpmodr = gicr_get_igrpmodr0(gicr_base, id);
+	} else {
+		assert(gicv3_driver_data->gicd_base != 0U);
+		igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
+		grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
+	}
+
+	/*
+	 * If the IGROUP bit is set, then it is a Group 1 Non secure
+	 * interrupt
+	 */
+	if (igroup != 0U)
+		return INTR_GROUP1NS;
+
+	/* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */
+	if (grpmodr != 0U)
+		return INTR_GROUP1S;
+
+	/* Else it is a Group 0 Secure interrupt */
+	return INTR_GROUP0;
+}
+
+/*****************************************************************************
+ * Function to save and disable the GIC ITS register context. The power
+ * management of GIC ITS is implementation-defined and this function doesn't
+ * save any memory structures required to support ITS. As the sequence to save
+ * this state is implementation defined, it should be executed in platform
+ * specific code. Calling this function alone and then powering down the GIC and
+ * ITS without implementing the aforementioned platform specific code will
+ * corrupt the ITS state.
+ *
+ * This function must be invoked after the GIC CPU interface is disabled.
+ *****************************************************************************/
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx)
+{
+	unsigned int i;
+
+	assert(gicv3_driver_data != NULL);
+	assert(IS_IN_EL3());
+	assert(its_ctx != NULL);
+	assert(gits_base != 0U);
+
+	its_ctx->gits_ctlr = gits_read_ctlr(gits_base);
+
+	/* Disable the ITS */
+	gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+					(~GITS_CTLR_ENABLED_BIT));
+
+	/* Wait for quiescent state */
+	gits_wait_for_quiescent_bit(gits_base);
+
+	its_ctx->gits_cbaser = gits_read_cbaser(gits_base);
+	its_ctx->gits_cwriter = gits_read_cwriter(gits_base);
+
+	for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+		its_ctx->gits_baser[i] = gits_read_baser(gits_base, i);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC ITS register context. The power
+ * management of GIC ITS is implementation defined and this function doesn't
+ * restore any memory structures required to support ITS. The assumption is
+ * that these structures are in memory and are retained during system suspend.
+ *
+ * This must be invoked before the GIC CPU interface is enabled.
+ *****************************************************************************/
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx)
+{
+	unsigned int i;
+
+	assert(gicv3_driver_data != NULL);
+	assert(IS_IN_EL3());
+	assert(its_ctx != NULL);
+	assert(gits_base != 0U);
+
+	/* Assert that the GITS is disabled and quiescent */
+	assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0U);
+	assert((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) != 0U);
+
+	gits_write_cbaser(gits_base, its_ctx->gits_cbaser);
+	gits_write_cwriter(gits_base, its_ctx->gits_cwriter);
+
+	for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++)
+		gits_write_baser(gits_base, i, its_ctx->gits_baser[i]);
+
+	/* Restore the ITS CTLR but leave the ITS disabled */
+	gits_write_ctlr(gits_base, its_ctx->gits_ctlr &
+			(~GITS_CTLR_ENABLED_BIT));
+}
+
+/*****************************************************************************
+ * Function to save the GIC Redistributor register context. This function
+ * must be invoked after CPU interface disable and prior to Distributor save.
+ *****************************************************************************/
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx)
+{
+	uintptr_t gicr_base;
+	unsigned int int_id;
+
+	assert(gicv3_driver_data != NULL);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(IS_IN_EL3());
+	assert(rdist_ctx != NULL);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+	/*
+	 * Wait for any write to GICR_CTLR to complete before trying to save any
+	 * state.
+	 */
+	gicr_wait_for_pending_write(gicr_base);
+
+	rdist_ctx->gicr_ctlr = gicr_read_ctlr(gicr_base);
+
+	rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base);
+	rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base);
+
+	rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base);
+	rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base);
+	rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base);
+	rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base);
+	rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base);
+	rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base);
+	rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base);
+	rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base);
+	for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+			int_id += (1U << IPRIORITYR_SHIFT)) {
+		rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] =
+				gicr_read_ipriorityr(gicr_base, int_id);
+	}
+
+
+	/*
+	 * Call the pre-save hook that implements the IMP DEF sequence that may
+	 * be required on some GIC implementations. As this may need to access
+	 * the Redistributor registers, we pass it proc_num.
+	 */
+	gicv3_distif_pre_save(proc_num);
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Redistributor register context. We disable
+ * LPI and per-cpu interrupts before we start restore of the Redistributor.
+ * This function must be invoked after Distributor restore but prior to
+ * CPU interface enable. The pending and active interrupts are restored
+ * after the interrupts are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_rdistif_init_restore(unsigned int proc_num,
+				const gicv3_redist_ctx_t * const rdist_ctx)
+{
+	uintptr_t gicr_base;
+	unsigned int int_id;
+
+	assert(gicv3_driver_data != NULL);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(IS_IN_EL3());
+	assert(rdist_ctx != NULL);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+
+	/* Power on redistributor */
+	gicv3_rdistif_on(proc_num);
+
+	/*
+	 * Call the post-restore hook that implements the IMP DEF sequence that
+	 * may be required on some GIC implementations. As this may need to
+	 * access the Redistributor registers, we pass it proc_num.
+	 */
+	gicv3_distif_post_restore(proc_num);
+
+	/*
+	 * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a
+	 * more scalable approach as it avoids clearing the enable bits in the
+	 * GICD_CTLR
+	 */
+	gicr_write_icenabler0(gicr_base, ~0U);
+	/* Wait for pending writes to GICR_ICENABLER */
+	gicr_wait_for_pending_write(gicr_base);
+
+	/*
+	 * Disable the LPIs to avoid unpredictable behavior when writing to
+	 * GICR_PROPBASER and GICR_PENDBASER.
+	 */
+	gicr_write_ctlr(gicr_base,
+			rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT));
+
+	/* Restore registers' content */
+	gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser);
+	gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser);
+
+	gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0);
+
+	for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM;
+			int_id += (1U << IPRIORITYR_SHIFT)) {
+		gicr_write_ipriorityr(gicr_base, int_id,
+		rdist_ctx->gicr_ipriorityr[
+				(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]);
+	}
+
+	gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0);
+	gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1);
+	gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0);
+	gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr);
+
+	/* Restore after group and priorities are set */
+	gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0);
+	gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0);
+
+	/*
+	 * Wait for all writes to the Distributor to complete before enabling
+	 * the SGI and PPIs.
+	 */
+	gicr_wait_for_upstream_pending_write(gicr_base);
+	gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0);
+
+	/*
+	 * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case
+	 * the first write to GICR_CTLR was still in flight (this write only
+	 * restores GICR_CTLR.Enable_LPIs and no waiting is required for this
+	 * bit).
+	 */
+	gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr);
+	gicr_wait_for_pending_write(gicr_base);
+}
+
+/*****************************************************************************
+ * Function to save the GIC Distributor register context. This function
+ * must be invoked after CPU interface disable and Redistributor save.
+ *****************************************************************************/
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx)
+{
+	unsigned int num_ints;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(IS_IN_EL3());
+	assert(dist_ctx != NULL);
+
+	uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+	num_ints = gicd_read_typer(gicd_base);
+	num_ints &= TYPER_IT_LINES_NO_MASK;
+	num_ints = (num_ints + 1U) << 5;
+
+	assert(num_ints <= (MAX_SPI_ID + 1U));
+
+	/* Wait for pending write to complete */
+	gicd_wait_for_pending_write(gicd_base);
+
+	/* Save the GICD_CTLR */
+	dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
+
+	/* Save GICD_IGROUPR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+	/* Save GICD_ISENABLER for INT_IDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+	/* Save GICD_ISPENDR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+	/* Save GICD_ISACTIVER for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+	/* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+	/* Save GICD_ICFGR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+	/* Save GICD_IGRPMODR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+	/* Save GICD_NSACR for INTIDs 32 - 1020 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+	/* Save GICD_IROUTER for INTIDs 32 - 1024 */
+	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+	/*
+	 * GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> are RAZ/WI when
+	 * GICD_CTLR.ARE_(S|NS) bits are set which is the case for our GICv3
+	 * driver.
+	 */
+}
+
+/*****************************************************************************
+ * Function to restore the GIC Distributor register context. We disable G0, G1S
+ * and G1NS interrupt groups before we start restore of the Distributor. This
+ * function must be invoked prior to Redistributor restore and CPU interface
+ * enable. The pending and active interrupts are restored after the interrupts
+ * are fully configured and enabled.
+ *****************************************************************************/
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx)
+{
+	unsigned int num_ints = 0U;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(IS_IN_EL3());
+	assert(dist_ctx != NULL);
+
+	uintptr_t gicd_base = gicv3_driver_data->gicd_base;
+
+	/*
+	 * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring
+	 * the ARE_S bit. The Distributor might generate a system error
+	 * otherwise.
+	 */
+	gicd_clr_ctlr(gicd_base,
+		      CTLR_ENABLE_G0_BIT |
+		      CTLR_ENABLE_G1S_BIT |
+		      CTLR_ENABLE_G1NS_BIT,
+		      RWP_TRUE);
+
+	/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
+	gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
+
+	num_ints = gicd_read_typer(gicd_base);
+	num_ints &= TYPER_IT_LINES_NO_MASK;
+	num_ints = (num_ints + 1U) << 5;
+
+	assert(num_ints <= (MAX_SPI_ID + 1U));
+
+	/* Restore GICD_IGROUPR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
+
+	/* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
+
+	/* Restore GICD_ICFGR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
+
+	/* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
+
+	/* Restore GICD_NSACR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
+
+	/* Restore GICD_IROUTER for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
+
+	/*
+	 * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are
+	 * configured.
+	 */
+
+	/* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
+
+	/* Restore GICD_ISPENDR for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
+
+	/* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */
+	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
+
+	/* Restore the GICD_CTLR */
+	gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr);
+	gicd_wait_for_pending_write(gicd_base);
+
+}
+
+/*******************************************************************************
+ * This function gets the priority of the interrupt the processor is currently
+ * servicing.
+ ******************************************************************************/
+unsigned int gicv3_get_running_priority(void)
+{
+	return (unsigned int)read_icc_rpr_el1();
+}
+
+/*******************************************************************************
+ * This function checks if the interrupt identified by id is active (whether the
+ * state is either active, or active and pending). The proc_num is used if the
+ * interrupt is SGI or PPI and programs the corresponding Redistributor
+ * interface.
+ ******************************************************************************/
+unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num)
+{
+	unsigned int value;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(id <= MAX_SPI_ID);
+
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		value = gicr_get_isactiver0(
+				gicv3_driver_data->rdistif_base_addrs[proc_num], id);
+	} else {
+		value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id);
+	}
+
+	return value;
+}
+
+/*******************************************************************************
+ * This function enables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ ******************************************************************************/
+void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before enabling interrupt.
+	 */
+	dsbishst();
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_isenabler0(
+				gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+	} else {
+		gicd_set_isenabler(gicv3_driver_data->gicd_base, id);
+	}
+}
+
+/*******************************************************************************
+ * This function disables the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface.
+ ******************************************************************************/
+void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(id <= MAX_SPI_ID);
+
+	/*
+	 * Disable interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_icenabler0(
+				gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+
+		/* Write to clear enable requires waiting for pending writes */
+		gicr_wait_for_pending_write(
+				gicv3_driver_data->rdistif_base_addrs[proc_num]);
+	} else {
+		gicd_set_icenabler(gicv3_driver_data->gicd_base, id);
+
+		/* Write to clear enable requires waiting for pending writes */
+		gicd_wait_for_pending_write(gicv3_driver_data->gicd_base);
+	}
+
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt priority as supplied for the given interrupt
+ * id.
+ ******************************************************************************/
+void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
+		unsigned int priority)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+	assert(id <= MAX_SPI_ID);
+
+	if (id < MIN_SPI_ID) {
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+		gicr_set_ipriorityr(gicr_base, id, priority);
+	} else {
+		gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority);
+	}
+}
+
+/*******************************************************************************
+ * This function assigns group for the interrupt identified by id. The proc_num
+ * is used if the interrupt is SGI or PPI, and programs the corresponding
+ * Redistributor interface. The group can be any of GICV3_INTR_GROUP*
+ ******************************************************************************/
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+		unsigned int type)
+{
+	bool igroup = false, grpmod = false;
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+
+	switch (type) {
+	case INTR_GROUP1S:
+		igroup = false;
+		grpmod = true;
+		break;
+	case INTR_GROUP0:
+		igroup = false;
+		grpmod = false;
+		break;
+	case INTR_GROUP1NS:
+		igroup = true;
+		grpmod = false;
+		break;
+	default:
+		assert(false);
+		break;
+	}
+
+	if (id < MIN_SPI_ID) {
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+		if (igroup)
+			gicr_set_igroupr0(gicr_base, id);
+		else
+			gicr_clr_igroupr0(gicr_base, id);
+
+		if (grpmod)
+			gicr_set_igrpmodr0(gicr_base, id);
+		else
+			gicr_clr_igrpmodr0(gicr_base, id);
+	} else {
+		/* Serialize read-modify-write to Distributor registers */
+		spin_lock(&gic_lock);
+		if (igroup)
+			gicd_set_igroupr(gicv3_driver_data->gicd_base, id);
+		else
+			gicd_clr_igroupr(gicv3_driver_data->gicd_base, id);
+
+		if (grpmod)
+			gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id);
+		else
+			gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id);
+		spin_unlock(&gic_lock);
+	}
+}
+
+/*******************************************************************************
+ * This function raises the specified Secure Group 0 SGI.
+ *
+ * The target parameter must be a valid MPIDR in the system.
+ ******************************************************************************/
+void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target)
+{
+	unsigned int tgt, aff3, aff2, aff1, aff0;
+	uint64_t sgi_val;
+
+	/* Verify interrupt number is in the SGI range */
+	assert((sgi_num >= MIN_SGI_ID) && (sgi_num < MIN_PPI_ID));
+
+	/* Extract affinity fields from target */
+	aff0 = MPIDR_AFFLVL0_VAL(target);
+	aff1 = MPIDR_AFFLVL1_VAL(target);
+	aff2 = MPIDR_AFFLVL2_VAL(target);
+	aff3 = MPIDR_AFFLVL3_VAL(target);
+
+	/*
+	 * Make target list from affinity 0, and ensure GICv3 SGI can target
+	 * this PE.
+	 */
+	assert(aff0 < GICV3_MAX_SGI_TARGETS);
+	tgt = BIT_32(aff0);
+
+	/* Raise SGI to PE specified by its affinity */
+	sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_num, SGIR_IRM_TO_AFF,
+			tgt);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before raising SGI.
+	 */
+	dsbishst();
+	write_icc_sgi0r_el1(sgi_val);
+	isb();
+}
+
+/*******************************************************************************
+ * This function sets the interrupt routing for the given SPI interrupt id.
+ * The interrupt routing is specified in routing mode and mpidr.
+ *
+ * The routing mode can be either of:
+ *  - GICV3_IRM_ANY
+ *  - GICV3_IRM_PE
+ *
+ * The mpidr is the affinity of the PE to which the interrupt will be routed,
+ * and is ignored for routing mode GICV3_IRM_ANY.
+ ******************************************************************************/
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr)
+{
+	unsigned long long aff;
+	uint64_t router;
+
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+
+	assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE));
+	assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID));
+
+	aff = gicd_irouter_val_from_mpidr(mpidr, irm);
+	gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff);
+
+	/*
+	 * In implementations that do not require 1 of N distribution of SPIs,
+	 * IRM might be RAZ/WI. Read back and verify IRM bit.
+	 */
+	if (irm == GICV3_IRM_ANY) {
+		router = gicd_read_irouter(gicv3_driver_data->gicd_base, id);
+		if (((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK) == 0U) {
+			ERROR("GICv3 implementation doesn't support routing ANY\n");
+			panic();
+		}
+	}
+}
+
+/*******************************************************************************
+ * This function clears the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI, and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+
+	/*
+	 * Clear pending interrupt, and ensure that any shared variable updates
+	 * depending on out of band interrupt trigger are observed afterwards.
+	 */
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+	} else {
+		gicd_set_icpendr(gicv3_driver_data->gicd_base, id);
+	}
+	dsbishst();
+}
+
+/*******************************************************************************
+ * This function sets the pending status of an interrupt identified by id.
+ * The proc_num is used if the interrupt is SGI or PPI and programs the
+ * corresponding Redistributor interface.
+ ******************************************************************************/
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num)
+{
+	assert(gicv3_driver_data != NULL);
+	assert(gicv3_driver_data->gicd_base != 0U);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs != NULL);
+
+	/*
+	 * Ensure that any shared variable updates depending on out of band
+	 * interrupt trigger are observed before setting interrupt pending.
+	 */
+	dsbishst();
+	if (id < MIN_SPI_ID) {
+		/* For SGIs and PPIs */
+		gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num],
+				id);
+	} else {
+		gicd_set_ispendr(gicv3_driver_data->gicd_base, id);
+	}
+}
+
+/*******************************************************************************
+ * This function sets the PMR register with the supplied value. Returns the
+ * original PMR.
+ ******************************************************************************/
+unsigned int gicv3_set_pmr(unsigned int mask)
+{
+	unsigned int old_mask;
+
+	old_mask = (uint32_t) read_icc_pmr_el1();
+
+	/*
+	 * Order memory updates w.r.t. PMR write, and ensure they're visible
+	 * before potential out of band interrupt trigger because of PMR update.
+	 * PMR system register writes are self-synchronizing, so no ISB required
+	 * thereafter.
+	 */
+	dsbishst();
+	write_icc_pmr_el1(mask);
+
+	return old_mask;
+}
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
new file mode 100644
index 0000000..327a9a1
--- /dev/null
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV3_PRIVATE_H
+#define GICV3_PRIVATE_H
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+
+#include "../common/gic_common_private.h"
+
+/*******************************************************************************
+ * GICv3 private macro definitions
+ ******************************************************************************/
+
+/* Constants to indicate the status of the RWP bit */
+#define RWP_TRUE		U(1)
+#define RWP_FALSE		U(0)
+
+/*
+ * Macro to convert an mpidr to a value suitable for programming into a
+ * GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant
+ * to GICv3.
+ */
+static inline u_register_t gicd_irouter_val_from_mpidr(u_register_t mpidr,
+						       unsigned int irm)
+{
+	return (mpidr & ~(U(0xff) << 24)) |
+		((irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT);
+}
+
+/*
+ * Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24]
+ * are zeroes.
+ */
+#ifdef __aarch64__
+static inline u_register_t mpidr_from_gicr_typer(uint64_t typer_val)
+{
+	return (((typer_val >> 56) & MPIDR_AFFLVL_MASK) << MPIDR_AFF3_SHIFT) |
+		((typer_val >> 32) & U(0xffffff));
+}
+#else
+static inline u_register_t mpidr_from_gicr_typer(uint64_t typer_val)
+{
+	return (((typer_val) >> 32) & U(0xffffff));
+}
+#endif
+
+/*******************************************************************************
+ * GICv3 private global variables declarations
+ ******************************************************************************/
+extern const gicv3_driver_data_t *gicv3_driver_data;
+
+/*******************************************************************************
+ * Private GICv3 function prototypes for accessing entire registers.
+ * Note: The raw register values correspond to multiple interrupt IDs and
+ * the number of interrupt IDs involved depends on the register accessed.
+ ******************************************************************************/
+unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id);
+unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id);
+void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val);
+void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val);
+
+/*******************************************************************************
+ * Private GICv3 function prototypes for accessing the GIC registers
+ * corresponding to a single interrupt ID. These functions use bitwise
+ * operations or appropriate register accesses to modify or return
+ * the bit-field corresponding the single interrupt ID.
+ ******************************************************************************/
+unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id);
+unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id);
+unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id);
+void gicd_set_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_set_igrpmodr0(uintptr_t base, unsigned int id);
+void gicr_set_isenabler0(uintptr_t base, unsigned int id);
+void gicr_set_icenabler0(uintptr_t base, unsigned int id);
+void gicr_set_ispendr0(uintptr_t base, unsigned int id);
+void gicr_set_icpendr0(uintptr_t base, unsigned int id);
+void gicr_set_igroupr0(uintptr_t base, unsigned int id);
+void gicd_clr_igrpmodr(uintptr_t base, unsigned int id);
+void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id);
+void gicr_clr_igroupr0(uintptr_t base, unsigned int id);
+void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri);
+void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg);
+void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg);
+
+/*******************************************************************************
+ * Private GICv3 helper function prototypes
+ ******************************************************************************/
+void gicv3_spis_config_defaults(uintptr_t gicd_base);
+void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base);
+unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
+unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base,
+		const interrupt_prop_t *interrupt_props,
+		unsigned int interrupt_props_num);
+void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs,
+					unsigned int rdistif_num,
+					uintptr_t gicr_base,
+					mpidr_hash_fn mpidr_to_core_pos);
+void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base);
+void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base);
+
+/*******************************************************************************
+ * GIC Distributor interface accessors
+ ******************************************************************************/
+/*
+ * Wait for updates to :
+ * GICD_CTLR[2:0] - the Group Enables
+ * GICD_CTLR[5:4] - the ARE bits
+ * GICD_ICENABLERn - the clearing of enable state for SPIs
+ */
+static inline void gicd_wait_for_pending_write(uintptr_t gicd_base)
+{
+	while ((gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) != 0U)
+		;
+}
+
+static inline unsigned int gicd_read_pidr2(uintptr_t base)
+{
+	return mmio_read_32(base + GICD_PIDR2_GICV3);
+}
+
+static inline unsigned long long gicd_read_irouter(uintptr_t base, unsigned int id)
+{
+	assert(id >= MIN_SPI_ID);
+	return mmio_read_64(base + GICD_IROUTER + (id << 3));
+}
+
+static inline void gicd_write_irouter(uintptr_t base,
+				      unsigned int id,
+				      unsigned long long affinity)
+{
+	assert(id >= MIN_SPI_ID);
+	mmio_write_64(base + GICD_IROUTER + (id << 3), affinity);
+}
+
+static inline void gicd_clr_ctlr(uintptr_t base,
+				 unsigned int bitmap,
+				 unsigned int rwp)
+{
+	gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap);
+	if (rwp != 0U)
+		gicd_wait_for_pending_write(base);
+}
+
+static inline void gicd_set_ctlr(uintptr_t base,
+				 unsigned int bitmap,
+				 unsigned int rwp)
+{
+	gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap);
+	if (rwp != 0U)
+		gicd_wait_for_pending_write(base);
+}
+
+/*******************************************************************************
+ * GIC Redistributor interface accessors
+ ******************************************************************************/
+static inline uint32_t gicr_read_ctlr(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_CTLR);
+}
+
+static inline void gicr_write_ctlr(uintptr_t base, uint32_t val)
+{
+	mmio_write_32(base + GICR_CTLR, val);
+}
+
+static inline unsigned long long gicr_read_typer(uintptr_t base)
+{
+	return mmio_read_64(base + GICR_TYPER);
+}
+
+static inline unsigned int gicr_read_waker(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_WAKER);
+}
+
+static inline void gicr_write_waker(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_WAKER, val);
+}
+
+/*
+ * Wait for updates to :
+ * GICR_ICENABLER0
+ * GICR_CTLR.DPG1S
+ * GICR_CTLR.DPG1NS
+ * GICR_CTLR.DPG0
+ */
+static inline void gicr_wait_for_pending_write(uintptr_t gicr_base)
+{
+	while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) != 0U)
+		;
+}
+
+static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base)
+{
+	while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT) != 0U)
+		;
+}
+
+/* Private implementation of Distributor power control hooks */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num);
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num);
+
+/*******************************************************************************
+ * GIC Re-distributor functions for accessing entire registers.
+ * Note: The raw register values correspond to multiple interrupt IDs and
+ * the number of interrupt IDs involved depends on the register accessed.
+ ******************************************************************************/
+static inline unsigned int gicr_read_icenabler0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ICENABLER0);
+}
+
+static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ICENABLER0, val);
+}
+
+static inline unsigned int gicr_read_isenabler0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ISENABLER0);
+}
+
+static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ICPENDR0, val);
+}
+
+static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ISENABLER0, val);
+}
+
+static inline unsigned int gicr_read_igroupr0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_IGROUPR0);
+}
+
+static inline unsigned int gicr_read_ispendr0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ISPENDR0);
+}
+
+static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ISPENDR0, val);
+}
+
+static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_IGROUPR0, val);
+}
+
+static inline unsigned int gicr_read_igrpmodr0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_IGRPMODR0);
+}
+
+static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_IGRPMODR0, val);
+}
+
+static inline unsigned int gicr_read_nsacr(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_NSACR);
+}
+
+static inline void gicr_write_nsacr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_NSACR, val);
+}
+
+static inline unsigned int gicr_read_isactiver0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ISACTIVER0);
+}
+
+static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ISACTIVER0, val);
+}
+
+static inline unsigned int gicr_read_icfgr0(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ICFGR0);
+}
+
+static inline unsigned int gicr_read_icfgr1(uintptr_t base)
+{
+	return mmio_read_32(base + GICR_ICFGR1);
+}
+
+static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ICFGR0, val);
+}
+
+static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GICR_ICFGR1, val);
+}
+
+static inline uint64_t gicr_read_propbaser(uintptr_t base)
+{
+	return mmio_read_64(base + GICR_PROPBASER);
+}
+
+static inline void gicr_write_propbaser(uintptr_t base, uint64_t val)
+{
+	mmio_write_64(base + GICR_PROPBASER, val);
+}
+
+static inline uint64_t gicr_read_pendbaser(uintptr_t base)
+{
+	return mmio_read_64(base + GICR_PENDBASER);
+}
+
+static inline void gicr_write_pendbaser(uintptr_t base, uint64_t val)
+{
+	mmio_write_64(base + GICR_PENDBASER, val);
+}
+
+/*******************************************************************************
+ * GIC ITS functions to read and write entire ITS registers.
+ ******************************************************************************/
+static inline uint32_t gits_read_ctlr(uintptr_t base)
+{
+	return mmio_read_32(base + GITS_CTLR);
+}
+
+static inline void gits_write_ctlr(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GITS_CTLR, val);
+}
+
+static inline uint64_t gits_read_cbaser(uintptr_t base)
+{
+	return mmio_read_64(base + GITS_CBASER);
+}
+
+static inline void gits_write_cbaser(uintptr_t base, uint64_t val)
+{
+	mmio_write_64(base + GITS_CBASER, val);
+}
+
+static inline uint64_t gits_read_cwriter(uintptr_t base)
+{
+	return mmio_read_64(base + GITS_CWRITER);
+}
+
+static inline void gits_write_cwriter(uintptr_t base, uint64_t val)
+{
+	mmio_write_64(base + GITS_CWRITER, val);
+}
+
+static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id)
+{
+	assert(its_table_id < 8U);
+	return mmio_read_64(base + GITS_BASER + (8U * its_table_id));
+}
+
+static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val)
+{
+	assert(its_table_id < 8U);
+	mmio_write_64(base + GITS_BASER + (8U * its_table_id), val);
+}
+
+/*
+ * Wait for Quiescent bit when GIC ITS is disabled
+ */
+static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base)
+{
+	assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0U);
+	while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0U)
+		;
+}
+
+
+#endif /* GICV3_PRIVATE_H */
diff --git a/drivers/arm/pl011/aarch32/pl011_console.S b/drivers/arm/pl011/aarch32/pl011_console.S
new file mode 100644
index 0000000..e1e346c
--- /dev/null
+++ b/drivers/arm/pl011/aarch32/pl011_console.S
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/arm/pl011.h>
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writeable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl	console_pl011_core_init
+	.globl	console_pl011_core_putc
+	.globl	console_pl011_core_getc
+	.globl	console_pl011_core_flush
+
+	.globl	console_pl011_putc
+	.globl	console_pl011_getc
+	.globl	console_pl011_flush
+
+
+	/* -----------------------------------------------
+	 * int console_core_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: r0 - console base address
+	 *     r1 - Uart clock in Hz
+	 *     r2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : r1, r2, r3
+	 * -----------------------------------------------
+	 */
+func console_pl011_core_init
+	/* Check the input base address */
+	cmp	r0, #0
+	beq	core_init_fail
+#if !PL011_GENERIC_UART
+	/* Check baud rate and uart clock for sanity */
+	cmp	r1, #0
+	beq	core_init_fail
+	cmp	r2, #0
+	beq	core_init_fail
+	/* Disable the UART before initialization */
+	ldr	r3, [r0, #UARTCR]
+	bic	r3, r3, #PL011_UARTCR_UARTEN
+	str	r3, [r0, #UARTCR]
+	/* Program the baudrate */
+	/* Divisor =  (Uart clock * 4) / baudrate */
+	lsl	r1, r1, #2
+#if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+	push	{r0,r3}
+	softudiv	r0,r1,r2,r3
+	mov	r1, r0
+	pop	{r0,r3}
+#else
+	udiv	r2, r1, r2
+#endif
+	/* IBRD = Divisor >> 6 */
+	lsr	r1, r2, #6
+	/* Write the IBRD */
+	str	r1, [r0, #UARTIBRD]
+	/* FBRD = Divisor & 0x3F */
+	and	r1, r2, #0x3f
+	/* Write the FBRD */
+	str	r1, [r0, #UARTFBRD]
+	mov	r1, #PL011_LINE_CONTROL
+	str	r1, [r0, #UARTLCR_H]
+	/* Clear any pending errors */
+	mov	r1, #0
+	str	r1, [r0, #UARTECR]
+	/* Enable tx, rx, and uart overall */
+	ldr	r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
+	str	r1, [r0, #UARTCR]
+#endif
+	mov	r0, #1
+	bx	lr
+core_init_fail:
+	mov	r0, #0
+	bx	lr
+endfunc console_pl011_core_init
+
+	.globl console_pl011_register
+
+	/* -------------------------------------------------------
+	 * int console_pl011_register(uintptr_t baseaddr,
+	 *     uint32_t clock, uint32_t baud,
+	 *     console_pl011_t *console);
+	 * Function to initialize and register a new PL011
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: r0 - UART register base address
+	 *     r1 - UART clock in Hz
+	 *     r2 - Baud rate
+	 *     r3 - pointer to empty console_pl011_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : r0, r1, r2
+	 * -------------------------------------------------------
+	 */
+func console_pl011_register
+	push	{r4, lr}
+	mov	r4, r3
+	cmp	r4, #0
+	beq	register_fail
+	str	r0, [r4, #CONSOLE_T_PL011_BASE]
+
+	bl console_pl011_core_init
+	cmp	r0, #0
+	beq	register_fail
+
+	mov	r0, r4
+	pop	{r4, lr}
+	finish_console_register pl011 putc=1, getc=1, flush=1
+
+register_fail:
+	pop	{r4, pc}
+endfunc console_pl011_register
+
+	/* --------------------------------------------------------
+	 * int console_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : r0 - character to be printed
+	 *      r1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : r2
+	 * --------------------------------------------------------
+	 */
+func console_pl011_core_putc
+	/* Check the input parameter */
+	cmp	r1, #0
+	beq	putc_error
+	/* Prepend '\r' to '\n' */
+	cmp	r0, #0xA
+	bne	2f
+1:
+	/* Check if the transmit FIFO is full */
+	ldr	r2, [r1, #UARTFR]
+	tst	r2, #PL011_UARTFR_TXFF
+	bne	1b
+	mov	r2, #0xD
+	str	r2, [r1, #UARTDR]
+2:
+	/* Check if the transmit FIFO is full */
+	ldr	r2, [r1, #UARTFR]
+	tst	r2, #PL011_UARTFR_TXFF
+	bne	2b
+	str	r0, [r1, #UARTDR]
+	bx	lr
+putc_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_pl011_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_pl011_putc(int c, console_pl011_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In: r0 - character to be printed
+	 *     r1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list: r2
+	 * -------------------------------------------------------
+	 */
+func console_pl011_putc
+#if ENABLE_ASSERTIONS
+	cmp	r1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r1, [r1, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_putc
+endfunc console_pl011_putc
+
+	/* ---------------------------------------------
+	 * int console_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on error.
+	 * In : r0 - console base address
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_pl011_core_getc
+	cmp	r0, #0
+	beq	getc_error
+1:
+	/* Check if the receive FIFO is empty */
+	ldr	r1, [r0, #UARTFR]
+	tst	r1, #PL011_UARTFR_RXFE
+	bne	1b
+	ldr	r1, [r0, #UARTDR]
+	mov	r0, r1
+	bx	lr
+getc_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_pl011_core_getc
+
+	/* ------------------------------------------------
+	 * int console_pl011_getc(console_pl011_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : r0 - pointer to console_t structure
+	 * Out: r0 - character if available, else -1
+	 * Clobber list: r0, r1
+	 * ------------------------------------------------
+	 */
+func console_pl011_getc
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r0, [r0, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_getc
+endfunc console_pl011_getc
+
+	/* ---------------------------------------------
+	 * int console_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : r0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_pl011_core_flush
+	cmp	r0, #0
+	beq	flush_error
+
+1:
+	/* Loop while the transmit FIFO is busy */
+	ldr	r1, [r0, #UARTFR]
+	tst	r1, #PL011_UARTFR_BUSY
+	bne	1b
+
+	mov	r0, #0
+	bx	lr
+flush_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_pl011_core_flush
+
+	/* ---------------------------------------------
+	 * int console_pl011_flush(console_pl011_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : r0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list: r0, r1
+	 * ---------------------------------------------
+	 */
+func console_pl011_flush
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r0, [r0, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_flush
+endfunc console_pl011_flush
diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
new file mode 100644
index 0000000..04de99f
--- /dev/null
+++ b/drivers/arm/pl011/aarch64/pl011_console.S
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/arm/pl011.h>
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_pl011_core_init
+	.globl console_pl011_core_putc
+	.globl console_pl011_core_getc
+	.globl console_pl011_core_flush
+
+	.globl	console_pl011_putc
+	.globl	console_pl011_getc
+	.globl	console_pl011_flush
+
+	/* -----------------------------------------------
+	 * int console_pl011_core_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : x1, x2, x3, x4
+	 * -----------------------------------------------
+	 */
+func console_pl011_core_init
+	/* Check the input base address */
+	cbz	x0, core_init_fail
+#if !PL011_GENERIC_UART
+	/* Check baud rate and uart clock for sanity */
+	cbz	w1, core_init_fail
+	cbz	w2, core_init_fail
+	/* Disable uart before programming */
+	ldr	w3, [x0, #UARTCR]
+	mov	w4, #PL011_UARTCR_UARTEN
+	bic	w3, w3, w4
+	str	w3, [x0, #UARTCR]
+	/* Program the baudrate */
+	/* Divisor =  (Uart clock * 4) / baudrate */
+	lsl	w1, w1, #2
+	udiv	w2, w1, w2
+	/* IBRD = Divisor >> 6 */
+	lsr	w1, w2, #6
+	/* Write the IBRD */
+	str	w1, [x0, #UARTIBRD]
+	/* FBRD = Divisor & 0x3F */
+	and	w1, w2, #0x3f
+	/* Write the FBRD */
+	str	w1, [x0, #UARTFBRD]
+	mov	w1, #PL011_LINE_CONTROL
+	str	w1, [x0, #UARTLCR_H]
+	/* Clear any pending errors */
+	str	wzr, [x0, #UARTECR]
+	/* Enable tx, rx, and uart overall */
+	mov	w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN)
+	str	w1, [x0, #UARTCR]
+#endif
+	mov	w0, #1
+	ret
+core_init_fail:
+	mov	w0, wzr
+	ret
+endfunc console_pl011_core_init
+
+	.globl console_pl011_register
+
+	/* -----------------------------------------------
+	 * int console_pl011_register(uintptr_t baseaddr,
+	 *     uint32_t clock, uint32_t baud,
+	 *     console_pl011_t *console);
+	 * Function to initialize and register a new PL011
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_pl011_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_pl011_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_PL011_BASE]
+
+	bl	console_pl011_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register pl011 putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_pl011_register
+
+	/* --------------------------------------------------------
+	 * int console_pl011_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_pl011_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+1:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #UARTFR]
+	tbnz	w2, #PL011_UARTFR_TXFF_BIT, 1b
+	mov	w2, #0xD
+	str	w2, [x1, #UARTDR]
+2:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #UARTFR]
+	tbnz	w2, #PL011_UARTFR_TXFF_BIT, 2b
+	str	w0, [x1, #UARTDR]
+	ret
+endfunc console_pl011_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_pl011_putc(int c, console_pl011_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_pl011_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_putc
+endfunc console_pl011_putc
+
+	/* ---------------------------------------------
+	 * int console_pl011_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - console base address
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_pl011_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Check if the receive FIFO is empty */
+	ldr	w1, [x0, #UARTFR]
+	tbnz	w1, #PL011_UARTFR_RXFE_BIT, no_char
+	ldr	w1, [x0, #UARTDR]
+	mov	w0, w1
+	ret
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+endfunc console_pl011_core_getc
+
+	/* ---------------------------------------------
+	 * int console_pl011_getc(console_pl011_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - pointer to console_t structure
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_pl011_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_getc
+endfunc console_pl011_getc
+
+	/* ---------------------------------------------
+	 * int console_pl011_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_pl011_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+1:
+	/* Loop until the transmit FIFO is empty */
+	ldr	w1, [x0, #UARTFR]
+	tbnz	w1, #PL011_UARTFR_BUSY_BIT, 1b
+
+	mov	w0, #0
+	ret
+endfunc console_pl011_core_flush
+
+	/* ---------------------------------------------
+	 * int console_pl011_flush(console_pl011_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_pl011_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_flush
+endfunc console_pl011_flush
diff --git a/drivers/arm/pl061/pl061_gpio.c b/drivers/arm/pl061/pl061_gpio.c
new file mode 100644
index 0000000..97013e8
--- /dev/null
+++ b/drivers/arm/pl061/pl061_gpio.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * ARM PL061 GPIO Driver.
+ * Reference to ARM DDI 0190B document.
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/gpio.h>
+#include <lib/cassert.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+#if !PLAT_PL061_MAX_GPIOS
+# define PLAT_PL061_MAX_GPIOS	32
+#endif	/* PLAT_PL061_MAX_GPIOS */
+
+CASSERT(PLAT_PL061_MAX_GPIOS > 0, assert_plat_pl061_max_gpios);
+
+#define MAX_GPIO_DEVICES	((PLAT_PL061_MAX_GPIOS +		\
+				 (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
+
+#define PL061_GPIO_DIR		0x400
+
+#define GPIOS_PER_PL061		8
+
+static int pl061_get_direction(int gpio);
+static void pl061_set_direction(int gpio, int direction);
+static int pl061_get_value(int gpio);
+static void pl061_set_value(int gpio, int value);
+
+static uintptr_t pl061_reg_base[MAX_GPIO_DEVICES];
+
+static const gpio_ops_t pl061_gpio_ops = {
+	.get_direction	= pl061_get_direction,
+	.set_direction	= pl061_set_direction,
+	.get_value	= pl061_get_value,
+	.set_value	= pl061_set_value,
+};
+
+static int pl061_get_direction(int gpio)
+{
+	uintptr_t base_addr;
+	unsigned int data, offset;
+
+	assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
+
+	base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
+	offset = gpio % GPIOS_PER_PL061;
+	data = mmio_read_8(base_addr + PL061_GPIO_DIR);
+	if (data & BIT(offset))
+		return GPIO_DIR_OUT;
+	return GPIO_DIR_IN;
+}
+
+static void pl061_set_direction(int gpio, int direction)
+{
+	uintptr_t base_addr;
+	unsigned int data, offset;
+
+	assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
+
+	base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
+	offset = gpio % GPIOS_PER_PL061;
+	if (direction == GPIO_DIR_OUT) {
+		data = mmio_read_8(base_addr + PL061_GPIO_DIR) | BIT(offset);
+		mmio_write_8(base_addr + PL061_GPIO_DIR, data);
+	} else {
+		data = mmio_read_8(base_addr + PL061_GPIO_DIR) & ~BIT(offset);
+		mmio_write_8(base_addr + PL061_GPIO_DIR, data);
+	}
+}
+
+/*
+ * The offset of GPIODATA register is 0.
+ * The values read from GPIODATA are determined for each bit, by the mask bit
+ * derived from the address used to access the data register, PADDR[9:2].
+ * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
+ * to be read, and bits that are 0 in the address mask cause the corresponding
+ * bits in GPIODATA to be read as 0, regardless of their value.
+ */
+static int pl061_get_value(int gpio)
+{
+	uintptr_t base_addr;
+	unsigned int offset;
+
+	assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
+
+	base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
+	offset = gpio % GPIOS_PER_PL061;
+	if (mmio_read_8(base_addr + BIT(offset + 2)))
+		return GPIO_LEVEL_HIGH;
+	return GPIO_LEVEL_LOW;
+}
+
+/*
+ * In order to write GPIODATA, the corresponding bits in the mask, resulting
+ * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
+ * remain unchanged by the write.
+ */
+static void pl061_set_value(int gpio, int value)
+{
+	uintptr_t base_addr;
+	int offset;
+
+	assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
+
+	base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
+	offset = gpio % GPIOS_PER_PL061;
+	if (value == GPIO_LEVEL_HIGH)
+		mmio_write_8(base_addr + BIT(offset + 2), BIT(offset));
+	else
+		mmio_write_8(base_addr + BIT(offset + 2), 0);
+}
+
+
+/*
+ * Register the PL061 GPIO controller with a base address and the offset
+ * of start pin in this GPIO controller.
+ * This function is called after pl061_gpio_ops_init().
+ */
+void pl061_gpio_register(uintptr_t base_addr, int gpio_dev)
+{
+	assert((gpio_dev >= 0) && (gpio_dev < MAX_GPIO_DEVICES));
+
+	pl061_reg_base[gpio_dev] = base_addr;
+}
+
+/*
+ * Initialize PL061 GPIO controller with the total GPIO numbers in SoC.
+ */
+void pl061_gpio_init(void)
+{
+	gpio_init(&pl061_gpio_ops);
+}
diff --git a/drivers/arm/sbsa/sbsa.c b/drivers/arm/sbsa/sbsa.c
new file mode 100644
index 0000000..6f00a60
--- /dev/null
+++ b/drivers/arm/sbsa/sbsa.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+#include <lib/mmio.h>
+#include <stdint_.h>
+#include <assert.h>
+
+void sbsa_watchdog_offset_reg_write(uintptr_t base, uint64_t value)
+{
+	assert((value >> SBSA_WDOG_WOR_WIDTH) == 0);
+	mmio_write_32(base + SBSA_WDOG_WOR_LOW_OFFSET,
+		 ((uint32_t)value & UINT32_MAX));
+	mmio_write_32(base + SBSA_WDOG_WOR_HIGH_OFFSET, (uint32_t)(value >> 32));
+}
+
+/*
+ * Start the watchdog timer at base address "base" for a
+ * period of "ms" milliseconds.The watchdog has to be
+ * refreshed within this time period.
+ */
+void sbsa_wdog_start(uintptr_t base, uint64_t ms)
+{
+	uint64_t counter_freq;
+	uint64_t offset_reg_value;
+
+	counter_freq = (uint64_t)plat_get_syscnt_freq2();
+	offset_reg_value = ms * counter_freq / 1000;
+
+	sbsa_watchdog_offset_reg_write(base, offset_reg_value);
+	mmio_write_32(base + SBSA_WDOG_WCS_OFFSET, SBSA_WDOG_WCS_EN);
+}
+
+/* Stop the watchdog */
+void sbsa_wdog_stop(uintptr_t base)
+{
+	mmio_write_32(base + SBSA_WDOG_WCS_OFFSET, (0x0));
+}
diff --git a/drivers/arm/smmu/smmu_v3.c b/drivers/arm/smmu/smmu_v3.c
new file mode 100644
index 0000000..5493b85
--- /dev/null
+++ b/drivers/arm/smmu/smmu_v3.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <cdefs.h>
+#include <drivers/arm/smmu_v3.h>
+#include <lib/mmio.h>
+
+/* SMMU poll number of retries */
+#define SMMU_POLL_RETRY		1000000
+
+static int __init smmuv3_poll(uintptr_t smmu_reg, uint32_t mask,
+				uint32_t value)
+{
+	uint32_t reg_val, retries = SMMU_POLL_RETRY;
+
+	do {
+		reg_val = mmio_read_32(smmu_reg);
+		if ((reg_val & mask) == value)
+			return 0;
+	} while (--retries != 0U);
+
+	ERROR("Failed to poll SMMUv3 register @%p\n", (void *)smmu_reg);
+	ERROR("Read value 0x%x, expected 0x%x\n", reg_val,
+		value == 0U ? reg_val & ~mask : reg_val | mask);
+	return -1;
+}
+
+/*
+ * Abort all incoming transactions in order to implement a default
+ * deny policy on reset.
+ */
+int __init smmuv3_security_init(uintptr_t smmu_base)
+{
+	/* Attribute update has completed when SMMU_(S)_GBPA.Update bit is 0 */
+	if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U)
+		return -1;
+
+	/*
+	 * SMMU_(S)_CR0 resets to zero with all streams bypassing the SMMU,
+	 * so just abort all incoming transactions.
+	 */
+	mmio_setbits_32(smmu_base + SMMU_GBPA,
+			SMMU_GBPA_UPDATE | SMMU_GBPA_ABORT);
+
+	if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U)
+		return -1;
+
+	/* Check if the SMMU supports secure state */
+	if ((mmio_read_32(smmu_base + SMMU_S_IDR1) &
+				SMMU_S_IDR1_SECURE_IMPL) == 0U)
+		return 0;
+
+	/* Abort all incoming secure transactions */
+	if (smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U) != 0U)
+		return -1;
+
+	mmio_setbits_32(smmu_base + SMMU_S_GBPA,
+			SMMU_S_GBPA_UPDATE | SMMU_S_GBPA_ABORT);
+
+	return smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U);
+}
+
+/*
+ * Initialize the SMMU by invalidating all secure caches and TLBs.
+ * Abort all incoming transactions in order to implement a default
+ * deny policy on reset
+ */
+int __init smmuv3_init(uintptr_t smmu_base)
+{
+	/* Abort all incoming transactions */
+	if (smmuv3_security_init(smmu_base) != 0)
+		return -1;
+
+	/* Check if the SMMU supports secure state */
+	if ((mmio_read_32(smmu_base + SMMU_S_IDR1) &
+				SMMU_S_IDR1_SECURE_IMPL) == 0U)
+		return 0;
+	/*
+	 * Initiate invalidation of secure caches and TLBs if the SMMU
+	 * supports secure state. If not, it's implementation defined
+	 * as to how SMMU_S_INIT register is accessed.
+	 */
+	mmio_write_32(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL);
+
+	/* Wait for global invalidation operation to finish */
+	return smmuv3_poll(smmu_base + SMMU_S_INIT,
+				SMMU_S_INIT_INV_ALL, 0U);
+}
diff --git a/drivers/arm/sp804/sp804_delay_timer.c b/drivers/arm/sp804/sp804_delay_timer.c
new file mode 100644
index 0000000..9c5e762
--- /dev/null
+++ b/drivers/arm/sp804/sp804_delay_timer.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+uintptr_t sp804_base_addr;
+
+#define SP804_TIMER1_LOAD	(sp804_base_addr + 0x000)
+#define SP804_TIMER1_VALUE	(sp804_base_addr + 0x004)
+#define SP804_TIMER1_CONTROL	(sp804_base_addr + 0x008)
+#define SP804_TIMER1_BGLOAD	(sp804_base_addr + 0x018)
+
+#define TIMER_CTRL_ONESHOT	(1 << 0)
+#define TIMER_CTRL_32BIT	(1 << 1)
+#define TIMER_CTRL_DIV1		(0 << 2)
+#define TIMER_CTRL_DIV16	(1 << 2)
+#define TIMER_CTRL_DIV256	(2 << 2)
+#define TIMER_CTRL_IE		(1 << 5)
+#define TIMER_CTRL_PERIODIC	(1 << 6)
+#define TIMER_CTRL_ENABLE	(1 << 7)
+
+/********************************************************************
+ * The SP804 timer delay function
+ ********************************************************************/
+uint32_t sp804_get_timer_value(void)
+{
+	return mmio_read_32(SP804_TIMER1_VALUE);
+}
+
+/********************************************************************
+ * Initialize the 1st timer in the SP804 dual timer with a base
+ * address and a timer ops
+ ********************************************************************/
+void sp804_timer_ops_init(uintptr_t base_addr, const timer_ops_t *ops)
+{
+	assert(base_addr != 0);
+	assert(ops != 0 && ops->get_timer_value == sp804_get_timer_value);
+
+	sp804_base_addr = base_addr;
+	timer_init(ops);
+
+	/* disable timer1 */
+	mmio_write_32(SP804_TIMER1_CONTROL, 0);
+	mmio_write_32(SP804_TIMER1_LOAD, UINT32_MAX);
+	mmio_write_32(SP804_TIMER1_VALUE, UINT32_MAX);
+
+	/* enable as a free running 32-bit counter */
+	mmio_write_32(SP804_TIMER1_CONTROL,
+			TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE);
+}
diff --git a/drivers/arm/sp805/sp805.c b/drivers/arm/sp805/sp805.c
new file mode 100644
index 0000000..ffca1ce
--- /dev/null
+++ b/drivers/arm/sp805/sp805.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/arm/sp805.h>
+#include <lib/mmio.h>
+
+/* Inline register access functions */
+
+static inline void sp805_write_wdog_load(uintptr_t base, uint32_t value)
+{
+	mmio_write_32(base + SP805_WDOG_LOAD_OFF, value);
+}
+
+static inline void sp805_write_wdog_ctrl(uintptr_t base, uint32_t value)
+{
+	mmio_write_32(base + SP805_WDOG_CTR_OFF, value);
+}
+
+static inline void sp805_write_wdog_lock(uintptr_t base, uint32_t value)
+{
+	mmio_write_32(base + SP805_WDOG_LOCK_OFF, value);
+}
+
+
+/* Public API implementation */
+
+void sp805_start(uintptr_t base, unsigned int ticks)
+{
+	sp805_write_wdog_load(base, ticks);
+	sp805_write_wdog_ctrl(base, SP805_CTR_RESEN | SP805_CTR_INTEN);
+	/* Lock registers access */
+	sp805_write_wdog_lock(base, 0U);
+}
+
+void sp805_stop(uintptr_t base)
+{
+	sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY);
+	sp805_write_wdog_ctrl(base, 0U);
+}
+
+void sp805_refresh(uintptr_t base, unsigned int ticks)
+{
+	sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY);
+	sp805_write_wdog_load(base, ticks);
+	sp805_write_wdog_lock(base, 0U);
+}
diff --git a/drivers/arm/tzc/tzc380.c b/drivers/arm/tzc/tzc380.c
new file mode 100644
index 0000000..9518748
--- /dev/null
+++ b/drivers/arm/tzc/tzc380.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc380.h>
+#include <lib/mmio.h>
+
+struct tzc380_instance {
+	uintptr_t base;
+	uint8_t addr_width;
+	uint8_t num_regions;
+};
+
+struct tzc380_instance tzc380;
+
+static unsigned int tzc380_read_build_config(uintptr_t base)
+{
+	return mmio_read_32(base + TZC380_CONFIGURATION_OFF);
+}
+
+static void tzc380_write_action(uintptr_t base, unsigned int action)
+{
+	mmio_write_32(base + ACTION_OFF, action);
+}
+
+static void tzc380_write_region_base_low(uintptr_t base, unsigned int region,
+				      unsigned int val)
+{
+	mmio_write_32(base + REGION_SETUP_LOW_OFF(region), val);
+}
+
+static void tzc380_write_region_base_high(uintptr_t base, unsigned int region,
+				       unsigned int val)
+{
+	mmio_write_32(base + REGION_SETUP_HIGH_OFF(region), val);
+}
+
+static void tzc380_write_region_attributes(uintptr_t base, unsigned int region,
+					unsigned int val)
+{
+	mmio_write_32(base + REGION_ATTRIBUTES_OFF(region), val);
+}
+
+void tzc380_init(uintptr_t base)
+{
+	unsigned int tzc_build;
+
+	assert(base != 0U);
+	tzc380.base = base;
+
+	/* Save values we will use later. */
+	tzc_build = tzc380_read_build_config(tzc380.base);
+	tzc380.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
+			      BUILD_CONFIG_AW_MASK) + 1;
+	tzc380.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
+			       BUILD_CONFIG_NR_MASK) + 1;
+}
+
+static uint32_t addr_low(uintptr_t addr)
+{
+	return (uint32_t)addr;
+}
+
+static uint32_t addr_high(uintptr_t addr __unused)
+{
+#if (UINTPTR_MAX == UINT64_MAX)
+	return addr >> 32;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * `tzc380_configure_region` is used to program regions into the TrustZone
+ * controller.
+ */
+void tzc380_configure_region(uint8_t region, uintptr_t region_base, unsigned int attr)
+{
+	assert(tzc380.base != 0U);
+
+	assert(region < tzc380.num_regions);
+
+	tzc380_write_region_base_low(tzc380.base, region, addr_low(region_base));
+	tzc380_write_region_base_high(tzc380.base, region, addr_high(region_base));
+	tzc380_write_region_attributes(tzc380.base, region, attr);
+}
+
+void tzc380_set_action(unsigned int action)
+{
+	assert(tzc380.base != 0U);
+
+	/*
+	 * - Currently no handler is provided to trap an error via interrupt
+	 *   or exception.
+	 * - The interrupt action has not been tested.
+	 */
+	tzc380_write_action(tzc380.base, action);
+}
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
new file mode 100644
index 0000000..50d6701
--- /dev/null
+++ b/drivers/arm/tzc/tzc400.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc400.h>
+#include <lib/mmio.h>
+
+#include "tzc_common_private.h"
+
+/*
+ * Macros which will be used by common core functions.
+ */
+#define TZC_400_REGION_BASE_LOW_0_OFFSET	U(0x100)
+#define TZC_400_REGION_BASE_HIGH_0_OFFSET	U(0x104)
+#define TZC_400_REGION_TOP_LOW_0_OFFSET		U(0x108)
+#define TZC_400_REGION_TOP_HIGH_0_OFFSET	U(0x10c)
+#define TZC_400_REGION_ATTR_0_OFFSET		U(0x110)
+#define TZC_400_REGION_ID_ACCESS_0_OFFSET	U(0x114)
+
+/*
+ * Implementation defined values used to validate inputs later.
+ * Filters : max of 4 ; 0 to 3
+ * Regions : max of 9 ; 0 to 8
+ * Address width : Values between 32 to 64
+ */
+typedef struct tzc400_instance {
+	uintptr_t base;
+	uint8_t addr_width;
+	uint8_t num_filters;
+	uint8_t num_regions;
+} tzc400_instance_t;
+
+static tzc400_instance_t tzc400;
+
+static inline unsigned int _tzc400_read_build_config(uintptr_t base)
+{
+	return mmio_read_32(base + BUILD_CONFIG_OFF);
+}
+
+static inline unsigned int _tzc400_read_gate_keeper(uintptr_t base)
+{
+	return mmio_read_32(base + GATE_KEEPER_OFF);
+}
+
+static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val)
+{
+	mmio_write_32(base + GATE_KEEPER_OFF, val);
+}
+
+/*
+ * Get the open status information for all filter units.
+ */
+#define get_gate_keeper_os(_base)	((_tzc400_read_gate_keeper(_base) >>  \
+					GATE_KEEPER_OS_SHIFT) &		\
+					GATE_KEEPER_OS_MASK)
+
+
+/* Define common core functions used across different TZC peripherals. */
+DEFINE_TZC_COMMON_WRITE_ACTION(400, 400)
+DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400)
+DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400)
+DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400)
+DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400)
+DEFINE_TZC_COMMON_CONFIGURE_REGION0(400)
+DEFINE_TZC_COMMON_CONFIGURE_REGION(400)
+
+static unsigned int _tzc400_get_gate_keeper(uintptr_t base,
+				unsigned int filter)
+{
+	unsigned int open_status;
+
+	open_status = get_gate_keeper_os(base);
+
+	return (open_status >> filter) & GATE_KEEPER_FILTER_MASK;
+}
+
+/* This function is not MP safe. */
+static void _tzc400_set_gate_keeper(uintptr_t base,
+				unsigned int filter,
+				int val)
+{
+	unsigned int open_status;
+
+	/* Upper half is current state. Lower half is requested state. */
+	open_status = get_gate_keeper_os(base);
+
+	if (val != 0)
+		open_status |=  (1U << filter);
+	else
+		open_status &= ~(1U << filter);
+
+	_tzc400_write_gate_keeper(base, (open_status & GATE_KEEPER_OR_MASK) <<
+			      GATE_KEEPER_OR_SHIFT);
+
+	/* Wait here until we see the change reflected in the TZC status. */
+	while ((get_gate_keeper_os(base)) != open_status)
+		;
+}
+
+void tzc400_set_action(unsigned int action)
+{
+	assert(tzc400.base != 0U);
+	assert(action <= TZC_ACTION_ERR_INT);
+
+	/*
+	 * - Currently no handler is provided to trap an error via interrupt
+	 *   or exception.
+	 * - The interrupt action has not been tested.
+	 */
+	_tzc400_write_action(tzc400.base, action);
+}
+
+void tzc400_init(uintptr_t base)
+{
+#if DEBUG
+	unsigned int tzc400_id;
+#endif
+	unsigned int tzc400_build;
+
+	assert(base != 0U);
+	tzc400.base = base;
+
+#if DEBUG
+	tzc400_id = _tzc_read_peripheral_id(base);
+	if (tzc400_id != TZC_400_PERIPHERAL_ID) {
+		ERROR("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id);
+		panic();
+	}
+#endif
+
+	/* Save values we will use later. */
+	tzc400_build = _tzc400_read_build_config(tzc400.base);
+	tzc400.num_filters = (uint8_t)((tzc400_build >> BUILD_CONFIG_NF_SHIFT) &
+					BUILD_CONFIG_NF_MASK) + 1U;
+	tzc400.addr_width  = (uint8_t)((tzc400_build >> BUILD_CONFIG_AW_SHIFT) &
+					BUILD_CONFIG_AW_MASK) + 1U;
+	tzc400.num_regions = (uint8_t)((tzc400_build >> BUILD_CONFIG_NR_SHIFT) &
+					BUILD_CONFIG_NR_MASK) + 1U;
+}
+
+/*
+ * `tzc400_configure_region0` is used to program region 0 into the TrustZone
+ * controller. Region 0 covers the whole address space that is not mapped
+ * to any other region, and is enabled on all filters; this cannot be
+ * changed. This function only changes the access permissions.
+ */
+void tzc400_configure_region0(unsigned int sec_attr,
+			   unsigned int ns_device_access)
+{
+	assert(tzc400.base != 0U);
+	assert(sec_attr <= TZC_REGION_S_RDWR);
+
+	_tzc400_configure_region0(tzc400.base, sec_attr, ns_device_access);
+}
+
+/*
+ * `tzc400_configure_region` is used to program regions into the TrustZone
+ * controller. A region can be associated with more than one filter. The
+ * associated filters are passed in as a bitmap (bit0 = filter0).
+ * NOTE:
+ * Region 0 is special; it is preferable to use tzc400_configure_region0
+ * for this region (see comment for that function).
+ */
+void tzc400_configure_region(unsigned int filters,
+			  unsigned int region,
+			  unsigned long long region_base,
+			  unsigned long long region_top,
+			  unsigned int sec_attr,
+			  unsigned int nsaid_permissions)
+{
+	assert(tzc400.base != 0U);
+
+	/* Do range checks on filters and regions. */
+	assert(((filters >> tzc400.num_filters) == 0U) &&
+	       (region < tzc400.num_regions));
+
+	/*
+	 * Do address range check based on TZC configuration. A 64bit address is
+	 * the max and expected case.
+	 */
+	assert((region_top <= (UINT64_MAX >> (64U - tzc400.addr_width))) &&
+		(region_base < region_top));
+
+	/* region_base and (region_top + 1) must be 4KB aligned */
+	assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U);
+
+	assert(sec_attr <= TZC_REGION_S_RDWR);
+
+	_tzc400_configure_region(tzc400.base, filters, region, region_base,
+						region_top,
+						sec_attr, nsaid_permissions);
+}
+
+void tzc400_enable_filters(void)
+{
+	unsigned int state;
+	unsigned int filter;
+
+	assert(tzc400.base != 0U);
+
+	for (filter = 0U; filter < tzc400.num_filters; filter++) {
+		state = _tzc400_get_gate_keeper(tzc400.base, filter);
+		if (state != 0U) {
+			/*
+			 * The TZC filter is already configured. Changing the
+			 * programmer's view in an active system can cause
+			 * unpredictable behavior therefore panic for now rather
+			 * than try to determine whether this is safe in this
+			 * instance.
+			 *
+			 * See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R)
+			 * Address Space Controller' Technical Reference Manual.
+			 */
+			ERROR("TZC-400 : Filter %d Gatekeeper already"
+				" enabled.\n", filter);
+			panic();
+		}
+		_tzc400_set_gate_keeper(tzc400.base, filter, 1);
+	}
+}
+
+void tzc400_disable_filters(void)
+{
+	unsigned int filter;
+
+	assert(tzc400.base != 0U);
+
+	/*
+	 * We don't do the same state check as above as the Gatekeepers are
+	 * disabled after reset.
+	 */
+	for (filter = 0; filter < tzc400.num_filters; filter++)
+		_tzc400_set_gate_keeper(tzc400.base, filter, 0);
+}
diff --git a/drivers/arm/tzc/tzc_common_private.h b/drivers/arm/tzc/tzc_common_private.h
new file mode 100644
index 0000000..c800536
--- /dev/null
+++ b/drivers/arm/tzc/tzc_common_private.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC_COMMON_PRIVATE_H
+#define TZC_COMMON_PRIVATE_H
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/tzc_common.h>
+#include <lib/mmio.h>
+
+#define DEFINE_TZC_COMMON_WRITE_ACTION(fn_name, macro_name)		\
+	static inline void _tzc##fn_name##_write_action(		\
+					uintptr_t base,			\
+					unsigned int action)		\
+	{								\
+		mmio_write_32(base + TZC_##macro_name##_ACTION_OFF,	\
+			action);					\
+	}
+
+#define DEFINE_TZC_COMMON_WRITE_REGION_BASE(fn_name, macro_name)	\
+	static inline void _tzc##fn_name##_write_region_base(		\
+					uintptr_t base,			\
+					unsigned int region_no,		\
+					unsigned long long region_base)	\
+	{								\
+		mmio_write_32(base +					\
+			TZC_REGION_OFFSET(				\
+				TZC_##macro_name##_REGION_SIZE,		\
+				region_no) +				\
+			TZC_##macro_name##_REGION_BASE_LOW_0_OFFSET,	\
+			(uint32_t)region_base);				\
+		mmio_write_32(base +					\
+			TZC_REGION_OFFSET(				\
+				TZC_##macro_name##_REGION_SIZE,		\
+				region_no) +				\
+			TZC_##macro_name##_REGION_BASE_HIGH_0_OFFSET,	\
+			(uint32_t)(region_base >> 32));			\
+	}
+
+#define DEFINE_TZC_COMMON_WRITE_REGION_TOP(fn_name, macro_name)		\
+	static inline void _tzc##fn_name##_write_region_top(		\
+					uintptr_t base,			\
+					unsigned int region_no,		\
+					unsigned long long region_top)	\
+	{								\
+		mmio_write_32(base +					\
+			TZC_REGION_OFFSET				\
+				(TZC_##macro_name##_REGION_SIZE,	\
+				region_no) +				\
+			TZC_##macro_name##_REGION_TOP_LOW_0_OFFSET,	\
+			(uint32_t)region_top);				\
+		mmio_write_32(base +					\
+			TZC_REGION_OFFSET(				\
+				TZC_##macro_name##_REGION_SIZE,		\
+				region_no) +				\
+			TZC_##macro_name##_REGION_TOP_HIGH_0_OFFSET,	\
+			(uint32_t)(region_top >> 32));			\
+	}
+
+#define DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(fn_name, macro_name)	\
+	static inline void _tzc##fn_name##_write_region_attributes(	\
+						uintptr_t base,		\
+						unsigned int region_no,	\
+						unsigned int attr)	\
+	{								\
+		mmio_write_32(base +					\
+			TZC_REGION_OFFSET(				\
+				TZC_##macro_name##_REGION_SIZE,		\
+				region_no) +				\
+			TZC_##macro_name##_REGION_ATTR_0_OFFSET,	\
+			attr);						\
+	}
+
+#define DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(fn_name, macro_name)	\
+	static inline void _tzc##fn_name##_write_region_id_access(	\
+						uintptr_t base,		\
+						unsigned int region_no,	\
+						unsigned int val)	\
+	{								\
+		mmio_write_32(base +					\
+			TZC_REGION_OFFSET(				\
+				TZC_##macro_name##_REGION_SIZE,		\
+				region_no) +				\
+			TZC_##macro_name##_REGION_ID_ACCESS_0_OFFSET,	\
+			val);						\
+	}
+
+/*
+ * It is used to program region 0 ATTRIBUTES and ACCESS register.
+ */
+#define DEFINE_TZC_COMMON_CONFIGURE_REGION0(fn_name)			\
+	static void _tzc##fn_name##_configure_region0(uintptr_t base,	\
+			   unsigned int sec_attr,			\
+			   unsigned int ns_device_access)		\
+	{								\
+		assert(base != 0U);					\
+		VERBOSE("TrustZone : Configuring region 0 "		\
+			"(TZC Interface Base=0x%lx sec_attr=0x%x,"	\
+			" ns_devs=0x%x)\n", base,			\
+			sec_attr, ns_device_access);			\
+									\
+		/* Set secure attributes on region 0 */			\
+		_tzc##fn_name##_write_region_attributes(base, 0,	\
+			sec_attr << TZC_REGION_ATTR_SEC_SHIFT);		\
+									\
+		/***************************************************/	\
+		/* Specify which non-secure devices have permission*/	\
+		/* to access region 0.				   */	\
+		/***************************************************/	\
+		_tzc##fn_name##_write_region_id_access(base,		\
+						0,			\
+						ns_device_access);	\
+	}
+
+/*
+ * It is used to program a region from 1 to 8 in the TrustZone controller.
+ * NOTE:
+ * Region 0 is special; it is preferable to use
+ * ##fn_name##_configure_region0 for this region (see comment for
+ * that function).
+ */
+#define DEFINE_TZC_COMMON_CONFIGURE_REGION(fn_name)			\
+	static void _tzc##fn_name##_configure_region(uintptr_t base,	\
+				unsigned int filters,			\
+				unsigned int region_no,			\
+				unsigned long long region_base,		\
+				unsigned long long region_top,		\
+				unsigned int sec_attr,			\
+				unsigned int nsaid_permissions)		\
+	{								\
+		assert(base != 0U);					\
+		VERBOSE("TrustZone : Configuring region "		\
+			"(TZC Interface Base: 0x%lx, region_no = %u)"	\
+			"...\n", base, region_no);			\
+		VERBOSE("TrustZone : ... base = %llx, top = %llx,"	\
+			"\n", region_base, region_top);			\
+		VERBOSE("TrustZone : ... sec_attr = 0x%x,"		\
+			" ns_devs = 0x%x)\n",				\
+			sec_attr, nsaid_permissions);			\
+									\
+		/***************************************************/	\
+		/* Inputs look ok, start programming registers.    */	\
+		/* All the address registers are 32 bits wide and  */	\
+		/* have a LOW and HIGH				   */	\
+		/* component used to construct an address up to a  */	\
+		/* 64bit.					   */	\
+		/***************************************************/	\
+		_tzc##fn_name##_write_region_base(base,			\
+					region_no, region_base);	\
+		_tzc##fn_name##_write_region_top(base,			\
+					region_no, region_top);		\
+									\
+		/* Enable filter to the region and set secure attributes */\
+		_tzc##fn_name##_write_region_attributes(base,		\
+				region_no,				\
+				(sec_attr << TZC_REGION_ATTR_SEC_SHIFT) |\
+				(filters << TZC_REGION_ATTR_F_EN_SHIFT));\
+									\
+		/***************************************************/	\
+		/* Specify which non-secure devices have permission*/	\
+		/* to access this region.			   */	\
+		/***************************************************/	\
+		_tzc##fn_name##_write_region_id_access(base,		\
+						region_no,		\
+						nsaid_permissions);	\
+	}
+
+static inline unsigned int _tzc_read_peripheral_id(uintptr_t base)
+{
+	unsigned int id;
+
+	id = mmio_read_32(base + PID0_OFF);
+	/* Masks DESC part in PID1 */
+	id |= ((mmio_read_32(base + PID1_OFF) & 0xFU) << 8U);
+
+	return id;
+}
+
+#endif /* TZC_COMMON_PRIVATE_H */
diff --git a/drivers/arm/tzc/tzc_dmc500.c b/drivers/arm/tzc/tzc_dmc500.c
new file mode 100644
index 0000000..e45fbf8
--- /dev/null
+++ b/drivers/arm/tzc/tzc_dmc500.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc500.h>
+#include <drivers/arm/tzc_common.h>
+#include <lib/mmio.h>
+
+#include "tzc_common_private.h"
+
+/*
+ * Macros which will be used by common core functions.
+ */
+#define TZC_DMC500_REGION_BASE_LOW_0_OFFSET		0x054
+#define TZC_DMC500_REGION_BASE_HIGH_0_OFFSET		0x058
+#define TZC_DMC500_REGION_TOP_LOW_0_OFFSET		0x05C
+#define TZC_DMC500_REGION_TOP_HIGH_0_OFFSET		0x060
+#define TZC_DMC500_REGION_ATTR_0_OFFSET			0x064
+#define TZC_DMC500_REGION_ID_ACCESS_0_OFFSET		0x068
+
+#define TZC_DMC500_ACTION_OFF				0x50
+
+/* Pointer to the tzc_dmc500_driver_data structure populated by the platform */
+static const tzc_dmc500_driver_data_t *g_driver_data;
+static unsigned int g_sys_if_count;
+
+#define verify_region_attr(region, attr)	\
+		((g_conf_regions[(region)].sec_attr ==			\
+			((attr) >> TZC_REGION_ATTR_SEC_SHIFT))		\
+		&& ((attr) & (0x1 << TZC_REGION_ATTR_F_EN_SHIFT)))
+
+/*
+ * Structure for configured regions attributes in DMC500.
+ */
+typedef struct tzc_dmc500_regions {
+	unsigned int sec_attr;
+	int is_enabled;
+} tzc_dmc500_regions_t;
+
+/*
+ * Array storing the attributes of the configured regions. This array
+ * will be used by the `tzc_dmc500_verify_complete` to verify the flush
+ * completion.
+ */
+static tzc_dmc500_regions_t g_conf_regions[MAX_REGION_VAL + 1];
+
+/* Helper Macros for making the code readable */
+#define DMC_INST_BASE_ADDR(instance) (g_driver_data->dmc_base[instance])
+#define DMC_INST_SI_BASE(instance, interface) \
+		(DMC_INST_BASE_ADDR(instance) + IFACE_OFFSET(interface))
+
+DEFINE_TZC_COMMON_WRITE_ACTION(_dmc500, DMC500)
+DEFINE_TZC_COMMON_WRITE_REGION_BASE(_dmc500, DMC500)
+DEFINE_TZC_COMMON_WRITE_REGION_TOP(_dmc500, DMC500)
+DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(_dmc500, DMC500)
+DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(_dmc500, DMC500)
+
+DEFINE_TZC_COMMON_CONFIGURE_REGION0(_dmc500)
+DEFINE_TZC_COMMON_CONFIGURE_REGION(_dmc500)
+
+static inline unsigned int _tzc_dmc500_read_region_attr_0(
+					uintptr_t dmc_si_base,
+					unsigned int region_no)
+{
+	return mmio_read_32(dmc_si_base +
+			TZC_REGION_OFFSET(TZC_DMC500_REGION_SIZE, region_no) +
+			TZC_DMC500_REGION_ATTR_0_OFFSET);
+}
+
+static inline void _tzc_dmc500_write_flush_control(uintptr_t dmc_si_base)
+{
+	mmio_write_32(dmc_si_base + SI_FLUSH_CTRL_OFFSET, 1);
+}
+
+/*
+ * Sets the Flush controls for all the DMC Instances and System Interfaces.
+ * This initiates the flush of configuration settings from the shadow
+ * registers to the actual configuration register. The caller should poll
+ * changed register to confirm update.
+ */
+void tzc_dmc500_config_complete(void)
+{
+	int dmc_inst, sys_if;
+
+	assert(g_driver_data);
+
+	for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
+		assert(DMC_INST_BASE_ADDR(dmc_inst));
+		for (sys_if = 0; sys_if < g_sys_if_count; sys_if++)
+			_tzc_dmc500_write_flush_control(
+					DMC_INST_SI_BASE(dmc_inst, sys_if));
+	}
+}
+
+/*
+ * This function reads back the secure attributes from the configuration
+ * register for each DMC Instance and System Interface and compares it with
+ * the configured value. The successful verification of the region attributes
+ * confirms that the flush operation has completed.
+ * If the verification fails, the caller is expected to invoke this API again
+ * till it succeeds.
+ * Returns 0 on success and 1 on failure.
+ */
+int tzc_dmc500_verify_complete(void)
+{
+	int dmc_inst, sys_if, region_no;
+	unsigned int attr;
+
+	assert(g_driver_data);
+	/* Region 0 must be configured */
+	assert(g_conf_regions[0].is_enabled);
+
+	/* Iterate over all configured regions */
+	for (region_no = 0; region_no <= MAX_REGION_VAL; region_no++) {
+		if (!g_conf_regions[region_no].is_enabled)
+			continue;
+		for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count;
+								dmc_inst++) {
+			assert(DMC_INST_BASE_ADDR(dmc_inst));
+			for (sys_if = 0; sys_if < g_sys_if_count;
+							sys_if++) {
+				attr = _tzc_dmc500_read_region_attr_0(
+					DMC_INST_SI_BASE(dmc_inst, sys_if),
+					region_no);
+				VERBOSE("Verifying DMC500 region:%d"
+					" dmc_inst:%d sys_if:%d attr:%x\n",
+					region_no, dmc_inst, sys_if, attr);
+				if (!verify_region_attr(region_no, attr))
+					return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * `tzc_dmc500_configure_region0` is used to program region 0 in both the
+ * system interfaces of all the DMC-500 instances. Region 0 covers the whole
+ * address space that is not mapped to any other region for a system interface,
+ * and is always enabled; this cannot be changed. This function only changes
+ * the access permissions.
+ */
+void tzc_dmc500_configure_region0(unsigned int sec_attr,
+				  unsigned int nsaid_permissions)
+{
+	int dmc_inst, sys_if;
+
+	/* Assert if DMC-500 is not initialized */
+	assert(g_driver_data);
+
+	/* Configure region_0 in all DMC instances */
+	for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
+		assert(DMC_INST_BASE_ADDR(dmc_inst));
+		for (sys_if = 0; sys_if < g_sys_if_count; sys_if++)
+			_tzc_dmc500_configure_region0(
+					DMC_INST_SI_BASE(dmc_inst, sys_if),
+					sec_attr, nsaid_permissions);
+	}
+
+	g_conf_regions[0].sec_attr = sec_attr;
+	g_conf_regions[0].is_enabled = 1;
+}
+
+/*
+ * `tzc_dmc500_configure_region` is used to program a region into all system
+ * interfaces of all the DMC instances.
+ * NOTE:
+ * Region 0 is special; it is preferable to use tzc_dmc500_configure_region0
+ * for this region (see comment for that function).
+ */
+void tzc_dmc500_configure_region(unsigned int region_no,
+			unsigned long long region_base,
+			unsigned long long region_top,
+			unsigned int sec_attr,
+			unsigned int nsaid_permissions)
+{
+	int dmc_inst, sys_if;
+
+	assert(g_driver_data);
+	/* Do range checks on regions. */
+	assert((region_no >= 0U) && (region_no <= MAX_REGION_VAL));
+
+	/*
+	 * Do address range check based on DMC-TZ configuration. A 43bit address
+	 * is the max and expected case.
+	 */
+	assert(((region_top <= (UINT64_MAX >> (64U - 43U))) &&
+		(region_base < region_top)));
+
+	/* region_base and (region_top + 1) must be 4KB aligned */
+	assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U);
+
+	for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
+		assert(DMC_INST_BASE_ADDR(dmc_inst));
+		for (sys_if = 0; sys_if < g_sys_if_count; sys_if++)
+			_tzc_dmc500_configure_region(
+					DMC_INST_SI_BASE(dmc_inst, sys_if),
+					TZC_DMC500_REGION_ATTR_F_EN_MASK,
+					region_no, region_base, region_top,
+					sec_attr, nsaid_permissions);
+	}
+
+	g_conf_regions[region_no].sec_attr = sec_attr;
+	g_conf_regions[region_no].is_enabled = 1;
+}
+
+/* Sets the action value for all the DMC instances */
+void tzc_dmc500_set_action(unsigned int action)
+{
+	int dmc_inst;
+
+	assert(g_driver_data);
+
+	for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) {
+		assert(DMC_INST_BASE_ADDR(dmc_inst));
+		/*
+		 * - Currently no handler is provided to trap an error via
+		 *   interrupt or exception.
+		 * - The interrupt action has not been tested.
+		 */
+		_tzc_dmc500_write_action(DMC_INST_BASE_ADDR(dmc_inst), action);
+	}
+}
+
+/*
+ * A DMC-500 instance must be present at each base address provided by the
+ * platform. It also expects platform to pass at least one instance of
+ * DMC-500.
+ */
+static void validate_plat_driver_data(
+			const tzc_dmc500_driver_data_t *plat_driver_data)
+{
+#if ENABLE_ASSERTIONS
+	int i;
+	unsigned int dmc_id;
+	uintptr_t dmc_base;
+
+	assert(plat_driver_data);
+	assert(plat_driver_data->dmc_count > 0 &&
+		(plat_driver_data->dmc_count <= MAX_DMC_COUNT));
+
+	for (i = 0; i < plat_driver_data->dmc_count; i++) {
+		dmc_base = plat_driver_data->dmc_base[i];
+		assert(dmc_base);
+
+		dmc_id = _tzc_read_peripheral_id(dmc_base);
+		assert(dmc_id == DMC500_PERIPHERAL_ID);
+	}
+#endif /* ENABLE_ASSERTIONS */
+}
+
+
+/*
+ * Initializes the base address and count of DMC instances.
+ *
+ * Note : Only pointer to plat_driver_data is saved, so it is caller's
+ * responsibility to keep it valid until the driver is used.
+ */
+void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data)
+{
+	/* Check valid pointer is passed */
+	assert(plat_driver_data);
+
+	/*
+	 * NOTE: This driver expects the DMC-500 controller is already in
+	 * READY state. Hence, it uses the reconfiguration method for
+	 * programming TrustZone regions
+	 */
+	/* Validates the information passed by platform */
+	validate_plat_driver_data(plat_driver_data);
+	g_driver_data = plat_driver_data;
+
+	/* Check valid system interface count */
+	assert(g_driver_data->sys_if_count <= MAX_SYS_IF_COUNT);
+
+	g_sys_if_count = g_driver_data->sys_if_count;
+
+	/* If interface count is not present then assume max */
+	if (g_sys_if_count == 0U)
+		g_sys_if_count = MAX_SYS_IF_COUNT;
+}
diff --git a/drivers/arm/tzc/tzc_dmc620.c b/drivers/arm/tzc/tzc_dmc620.c
new file mode 100644
index 0000000..64ec5ab
--- /dev/null
+++ b/drivers/arm/tzc/tzc_dmc620.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc620.h>
+#include <lib/mmio.h>
+
+/* Mask to extract bit 31 to 16 */
+#define MASK_31_16 UINT64_C(0x0000ffff0000)
+/* Mask to extract bit 47 to 32 */
+#define MASK_47_32 UINT64_C(0xffff00000000)
+
+/* Helper macro for getting dmc_base addr of a dmc_inst */
+#define DMC_BASE(plat_data, dmc_inst) \
+	((uintptr_t)(plat_data->dmc_base[dmc_inst]))
+
+/* Pointer to the tzc_dmc620_config_data structure populated by the platform */
+static const tzc_dmc620_config_data_t *g_plat_config_data;
+
+#if ENABLE_ASSERTIONS
+/*
+ * Helper function to check if the DMC-620 instance is present at the
+ * base address provided by the platform and also check if at least
+ * one dmc instance is present.
+ */
+static void tzc_dmc620_validate_plat_driver_data(
+			const tzc_dmc620_driver_data_t *plat_driver_data)
+{
+	uint8_t dmc_inst, dmc_count;
+	unsigned int dmc_id;
+	uintptr_t base;
+
+	assert(plat_driver_data != NULL);
+
+	dmc_count = plat_driver_data->dmc_count;
+	assert(dmc_count > 0U);
+
+	for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
+		base = DMC_BASE(plat_driver_data, dmc_inst);
+		dmc_id = mmio_read_32(base + DMC620_PERIPHERAL_ID_0);
+		assert(dmc_id == DMC620_PERIPHERAL_ID_0_VALUE);
+	}
+}
+#endif
+
+/*
+ * Program a region with region base and region top addresses of all
+ * DMC-620 instances.
+ */
+static void tzc_dmc620_configure_region(int region_no,
+					unsigned long long region_base,
+					unsigned long long region_top,
+					unsigned int sec_attr)
+{
+	uint32_t min_31_00, min_47_32;
+	uint32_t max_31_00, max_47_32;
+	uint8_t dmc_inst, dmc_count;
+	uintptr_t base;
+	const tzc_dmc620_driver_data_t *plat_driver_data;
+
+	plat_driver_data = g_plat_config_data->plat_drv_data;
+	assert(plat_driver_data != NULL);
+
+	/* Do range checks on regions. */
+	assert((region_no >= 0U) && (region_no <= DMC620_ACC_ADDR_COUNT));
+
+	/* region_base and (region_top + 1) must be 4KB aligned */
+	assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U);
+
+	dmc_count = plat_driver_data->dmc_count;
+	for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
+		min_31_00 = (region_base & MASK_31_16) | sec_attr;
+		min_47_32 = (region_base & MASK_47_32)
+				>> DMC620_ACC_ADDR_WIDTH;
+		max_31_00 = (region_top  & MASK_31_16);
+		max_47_32 = (region_top  & MASK_47_32)
+				>> DMC620_ACC_ADDR_WIDTH;
+
+		/* Extract the base address of the DMC-620 instance */
+		base = DMC_BASE(plat_driver_data, dmc_inst);
+		/* Configure access address region registers */
+		mmio_write_32(base + DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no),
+				min_31_00);
+		mmio_write_32(base + DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no),
+				min_47_32);
+		mmio_write_32(base + DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no),
+				max_31_00);
+		mmio_write_32(base + DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no),
+				max_47_32);
+	}
+}
+
+/*
+ * Set the action value for all the DMC-620 instances.
+ */
+static void tzc_dmc620_set_action(void)
+{
+	uint8_t dmc_inst, dmc_count;
+	uintptr_t base;
+	const tzc_dmc620_driver_data_t *plat_driver_data;
+
+	plat_driver_data = g_plat_config_data->plat_drv_data;
+	dmc_count = plat_driver_data->dmc_count;
+	for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
+		/* Extract the base address of the DMC-620 instance */
+		base = DMC_BASE(plat_driver_data, dmc_inst);
+		/* Switch to READY */
+		mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_GO);
+		mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_EXECUTE);
+	}
+}
+
+/*
+ * Verify whether the DMC-620 configuration is complete by reading back
+ * configuration registers and comparing it with the configured value. If
+ * configuration is incomplete, loop till the configured value is reflected in
+ * the register.
+ */
+static void tzc_dmc620_verify_complete(void)
+{
+	uint8_t dmc_inst, dmc_count;
+	uintptr_t base;
+	const tzc_dmc620_driver_data_t *plat_driver_data;
+
+	plat_driver_data = g_plat_config_data->plat_drv_data;
+	dmc_count = plat_driver_data->dmc_count;
+	for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) {
+		/* Extract the base address of the DMC-620 instance */
+		base = DMC_BASE(plat_driver_data, dmc_inst);
+		while ((mmio_read_32(base + DMC620_MEMC_STATUS) &
+				DMC620_MEMC_CMD_MASK) != DMC620_MEMC_CMD_GO)
+			continue;
+	}
+}
+
+/*
+ * Initialize the DMC-620 TrustZone Controller using the region configuration
+ * supplied by the platform. The DMC620 controller should be enabled elsewhere
+ * before invoking this function.
+ */
+void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data)
+{
+	int i;
+
+	/* Check if valid pointer is passed */
+	assert(plat_config_data != NULL);
+
+	/*
+	 * Check if access address count passed by the platform is less than or
+	 * equal to DMC620's access address count
+	 */
+	assert(plat_config_data->acc_addr_count <= DMC620_ACC_ADDR_COUNT);
+
+#if ENABLE_ASSERTIONS
+	/* Validates the information passed by platform */
+	tzc_dmc620_validate_plat_driver_data(plat_config_data->plat_drv_data);
+#endif
+
+	g_plat_config_data = plat_config_data;
+
+	INFO("Configuring DMC-620 TZC settings\n");
+	for (i = 0U; i < g_plat_config_data->acc_addr_count; i++)
+		tzc_dmc620_configure_region(i,
+			g_plat_config_data->plat_acc_addr_data[i].region_base,
+			g_plat_config_data->plat_acc_addr_data[i].region_top,
+			g_plat_config_data->plat_acc_addr_data[i].sec_attr);
+
+	tzc_dmc620_set_action();
+	tzc_dmc620_verify_complete();
+	INFO("DMC-620 TZC setup completed\n");
+}
diff --git a/drivers/auth/auth_mod.c b/drivers/auth/auth_mod.c
new file mode 100644
index 0000000..a6538c4
--- /dev/null
+++ b/drivers/auth/auth_mod.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/tbbr/cot_def.h>
+#include <drivers/auth/auth_common.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <plat/common/platform.h>
+
+/* ASN.1 tags */
+#define ASN1_INTEGER                 0x02
+
+#define return_if_error(rc) \
+	do { \
+		if (rc != 0) { \
+			return rc; \
+		} \
+	} while (0)
+
+#pragma weak plat_set_nv_ctr2
+
+/* Pointer to CoT */
+extern const auth_img_desc_t *const *const cot_desc_ptr;
+extern unsigned int auth_img_flags[MAX_NUMBER_IDS];
+
+static int cmp_auth_param_type_desc(const auth_param_type_desc_t *a,
+		const auth_param_type_desc_t *b)
+{
+	if ((a->type == b->type) && (a->cookie == b->cookie)) {
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * This function obtains the requested authentication parameter data from the
+ * information extracted from the parent image after its authentication.
+ */
+static int auth_get_param(const auth_param_type_desc_t *param_type_desc,
+			  const auth_img_desc_t *img_desc,
+			  void **param, unsigned int *len)
+{
+	int i;
+
+	if (img_desc->authenticated_data == NULL)
+		return 1;
+
+	for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) {
+		if (0 == cmp_auth_param_type_desc(param_type_desc,
+				img_desc->authenticated_data[i].type_desc)) {
+			*param = img_desc->authenticated_data[i].data.ptr;
+			*len = img_desc->authenticated_data[i].data.len;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Authenticate an image by matching the data hash
+ *
+ * This function implements 'AUTH_METHOD_HASH'. To authenticate an image using
+ * this method, the image must contain:
+ *
+ *   - The data to calculate the hash from
+ *
+ * The parent image must contain:
+ *
+ *   - The hash to be matched with (including hash algorithm)
+ *
+ * For a successful authentication, both hashes must match. The function calls
+ * the crypto-module to check this matching.
+ *
+ * Parameters:
+ *   param: parameters to perform the hash authentication
+ *   img_desc: pointer to image descriptor so we can know the image type
+ *             and parent image
+ *   img: pointer to image in memory
+ *   img_len: length of image (in bytes)
+ *
+ * Return:
+ *   0 = success, Otherwise = error
+ */
+static int auth_hash(const auth_method_param_hash_t *param,
+		     const auth_img_desc_t *img_desc,
+		     void *img, unsigned int img_len)
+{
+	void *data_ptr, *hash_der_ptr;
+	unsigned int data_len, hash_der_len;
+	int rc = 0;
+
+	/* Get the hash from the parent image. This hash will be DER encoded
+	 * and contain the hash algorithm */
+	rc = auth_get_param(param->hash, img_desc->parent,
+			&hash_der_ptr, &hash_der_len);
+	return_if_error(rc);
+
+	/* Get the data to be hashed from the current image */
+	rc = img_parser_get_auth_param(img_desc->img_type, param->data,
+			img, img_len, &data_ptr, &data_len);
+	return_if_error(rc);
+
+	/* Ask the crypto module to verify this hash */
+	rc = crypto_mod_verify_hash(data_ptr, data_len,
+				    hash_der_ptr, hash_der_len);
+
+	return rc;
+}
+
+/*
+ * Authenticate by digital signature
+ *
+ * This function implements 'AUTH_METHOD_SIG'. To authenticate an image using
+ * this method, the image must contain:
+ *
+ *   - Data to be signed
+ *   - Signature
+ *   - Signature algorithm
+ *
+ * We rely on the image parser module to extract this data from the image.
+ * The parent image must contain:
+ *
+ *   - Public key (or a hash of it)
+ *
+ * If the parent image contains only a hash of the key, we will try to obtain
+ * the public key from the image itself (i.e. self-signed certificates). In that
+ * case, the signature verification is considered just an integrity check and
+ * the authentication is established by calculating the hash of the key and
+ * comparing it with the hash obtained from the parent.
+ *
+ * If the image has no parent (NULL), it means it has to be authenticated using
+ * the ROTPK stored in the platform. Again, this ROTPK could be the key itself
+ * or a hash of it.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+static int auth_signature(const auth_method_param_sig_t *param,
+			  const auth_img_desc_t *img_desc,
+			  void *img, unsigned int img_len)
+{
+	void *data_ptr, *pk_ptr, *pk_hash_ptr, *sig_ptr, *sig_alg_ptr;
+	unsigned int data_len, pk_len, pk_hash_len, sig_len, sig_alg_len;
+	unsigned int flags = 0;
+	int rc = 0;
+
+	/* Get the data to be signed from current image */
+	rc = img_parser_get_auth_param(img_desc->img_type, param->data,
+			img, img_len, &data_ptr, &data_len);
+	return_if_error(rc);
+
+	/* Get the signature from current image */
+	rc = img_parser_get_auth_param(img_desc->img_type, param->sig,
+			img, img_len, &sig_ptr, &sig_len);
+	return_if_error(rc);
+
+	/* Get the signature algorithm from current image */
+	rc = img_parser_get_auth_param(img_desc->img_type, param->alg,
+			img, img_len, &sig_alg_ptr, &sig_alg_len);
+	return_if_error(rc);
+
+	/* Get the public key from the parent. If there is no parent (NULL),
+	 * the certificate has been signed with the ROTPK, so we have to get
+	 * the PK from the platform */
+	if (img_desc->parent) {
+		rc = auth_get_param(param->pk, img_desc->parent,
+				&pk_ptr, &pk_len);
+	} else {
+		rc = plat_get_rotpk_info(param->pk->cookie, &pk_ptr, &pk_len,
+				&flags);
+	}
+	return_if_error(rc);
+
+	if (flags & (ROTPK_IS_HASH | ROTPK_NOT_DEPLOYED)) {
+		/* If the PK is a hash of the key or if the ROTPK is not
+		   deployed on the platform, retrieve the key from the image */
+		pk_hash_ptr = pk_ptr;
+		pk_hash_len = pk_len;
+		rc = img_parser_get_auth_param(img_desc->img_type,
+					param->pk, img, img_len,
+					&pk_ptr, &pk_len);
+		return_if_error(rc);
+
+		/* Ask the crypto module to verify the signature */
+		rc = crypto_mod_verify_signature(data_ptr, data_len,
+						 sig_ptr, sig_len,
+						 sig_alg_ptr, sig_alg_len,
+						 pk_ptr, pk_len);
+		return_if_error(rc);
+
+		if (flags & ROTPK_NOT_DEPLOYED) {
+			NOTICE("ROTPK is not deployed on platform. "
+				"Skipping ROTPK verification.\n");
+		} else {
+			/* Ask the crypto-module to verify the key hash */
+			rc = crypto_mod_verify_hash(pk_ptr, pk_len,
+				    pk_hash_ptr, pk_hash_len);
+		}
+	} else {
+		/* Ask the crypto module to verify the signature */
+		rc = crypto_mod_verify_signature(data_ptr, data_len,
+						 sig_ptr, sig_len,
+						 sig_alg_ptr, sig_alg_len,
+						 pk_ptr, pk_len);
+	}
+
+	return rc;
+}
+
+/*
+ * Authenticate by Non-Volatile counter
+ *
+ * To protect the system against rollback, the platform includes a non-volatile
+ * counter whose value can only be increased. All certificates include a counter
+ * value that should not be lower than the value stored in the platform. If the
+ * value is larger, the counter in the platform must be updated to the new
+ * value.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+static int auth_nvctr(const auth_method_param_nv_ctr_t *param,
+		      const auth_img_desc_t *img_desc,
+		      void *img, unsigned int img_len)
+{
+	char *p;
+	void *data_ptr = NULL;
+	unsigned int data_len, len, i;
+	unsigned int cert_nv_ctr, plat_nv_ctr;
+	int rc = 0;
+
+	/* Get the counter value from current image. The AM expects the IPM
+	 * to return the counter value as a DER encoded integer */
+	rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr,
+				       img, img_len, &data_ptr, &data_len);
+	return_if_error(rc);
+
+	/* Parse the DER encoded integer */
+	assert(data_ptr);
+	p = (char *)data_ptr;
+	if (*p != ASN1_INTEGER) {
+		/* Invalid ASN.1 integer */
+		return 1;
+	}
+	p++;
+
+	/* NV-counters are unsigned integers up to 32-bit */
+	len = (unsigned int)(*p & 0x7f);
+	if ((*p & 0x80) || (len > 4)) {
+		return 1;
+	}
+	p++;
+
+	/* Check the number is not negative */
+	if (*p & 0x80) {
+		return 1;
+	}
+
+	/* Convert to unsigned int. This code is for a little-endian CPU */
+	cert_nv_ctr = 0;
+	for (i = 0; i < len; i++) {
+		cert_nv_ctr = (cert_nv_ctr << 8) | *p++;
+	}
+
+	/* Get the counter from the platform */
+	rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr);
+	return_if_error(rc);
+
+	if (cert_nv_ctr < plat_nv_ctr) {
+		/* Invalid NV-counter */
+		return 1;
+	} else if (cert_nv_ctr > plat_nv_ctr) {
+		rc = plat_set_nv_ctr2(param->plat_nv_ctr->cookie,
+			img_desc, cert_nv_ctr);
+		return_if_error(rc);
+	}
+
+	return 0;
+}
+
+int plat_set_nv_ctr2(void *cookie, const auth_img_desc_t *img_desc __unused,
+		unsigned int nv_ctr)
+{
+	return plat_set_nv_ctr(cookie, nv_ctr);
+}
+
+/*
+ * Return the parent id in the output parameter '*parent_id'
+ *
+ * Return value:
+ *   0 = Image has parent, 1 = Image has no parent or parent is authenticated
+ */
+int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id)
+{
+	const auth_img_desc_t *img_desc = NULL;
+
+	assert(parent_id != NULL);
+
+	/* Get the image descriptor */
+	img_desc = cot_desc_ptr[img_id];
+
+	/* Check if the image has no parent (ROT) */
+	if (img_desc->parent == NULL) {
+		*parent_id = 0;
+		return 1;
+	}
+
+	/* Check if the parent has already been authenticated */
+	if (auth_img_flags[img_desc->parent->img_id] & IMG_FLAG_AUTHENTICATED) {
+		*parent_id = 0;
+		return 1;
+	}
+
+	*parent_id = img_desc->parent->img_id;
+	return 0;
+}
+
+/*
+ * Initialize the different modules in the authentication framework
+ */
+void auth_mod_init(void)
+{
+	/* Check we have a valid CoT registered */
+	assert(cot_desc_ptr != NULL);
+
+	/* Crypto module */
+	crypto_mod_init();
+
+	/* Image parser module */
+	img_parser_init();
+}
+
+/*
+ * Authenticate a certificate/image
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int auth_mod_verify_img(unsigned int img_id,
+			void *img_ptr,
+			unsigned int img_len)
+{
+	const auth_img_desc_t *img_desc = NULL;
+	const auth_method_desc_t *auth_method = NULL;
+	void *param_ptr;
+	unsigned int param_len;
+	int rc, i;
+
+	/* Get the image descriptor from the chain of trust */
+	img_desc = cot_desc_ptr[img_id];
+
+	/* Ask the parser to check the image integrity */
+	rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len);
+	return_if_error(rc);
+
+	/* Authenticate the image using the methods indicated in the image
+	 * descriptor. */
+	if (img_desc->img_auth_methods == NULL)
+		return 1;
+	for (i = 0 ; i < AUTH_METHOD_NUM ; i++) {
+		auth_method = &img_desc->img_auth_methods[i];
+		switch (auth_method->type) {
+		case AUTH_METHOD_NONE:
+			rc = 0;
+			break;
+		case AUTH_METHOD_HASH:
+			rc = auth_hash(&auth_method->param.hash,
+					img_desc, img_ptr, img_len);
+			break;
+		case AUTH_METHOD_SIG:
+			rc = auth_signature(&auth_method->param.sig,
+					img_desc, img_ptr, img_len);
+			break;
+		case AUTH_METHOD_NV_CTR:
+			rc = auth_nvctr(&auth_method->param.nv_ctr,
+					img_desc, img_ptr, img_len);
+			break;
+		default:
+			/* Unknown authentication method */
+			rc = 1;
+			break;
+		}
+		return_if_error(rc);
+	}
+
+	/* Extract the parameters indicated in the image descriptor to
+	 * authenticate the children images. */
+	if (img_desc->authenticated_data != NULL) {
+		for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) {
+			if (img_desc->authenticated_data[i].type_desc == NULL) {
+				continue;
+			}
+
+			/* Get the parameter from the image parser module */
+			rc = img_parser_get_auth_param(img_desc->img_type,
+					img_desc->authenticated_data[i].type_desc,
+					img_ptr, img_len, &param_ptr, &param_len);
+			return_if_error(rc);
+
+			/* Check parameter size */
+			if (param_len > img_desc->authenticated_data[i].data.len) {
+				return 1;
+			}
+
+			/* Copy the parameter for later use */
+			memcpy((void *)img_desc->authenticated_data[i].data.ptr,
+					(void *)param_ptr, param_len);
+		}
+	}
+
+	/* Mark image as authenticated */
+	auth_img_flags[img_desc->img_id] |= IMG_FLAG_AUTHENTICATED;
+
+	return 0;
+}
diff --git a/drivers/auth/crypto_mod.c b/drivers/auth/crypto_mod.c
new file mode 100644
index 0000000..5e5ac2b
--- /dev/null
+++ b/drivers/auth/crypto_mod.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+
+/* Variable exported by the crypto library through REGISTER_CRYPTO_LIB() */
+
+/*
+ * The crypto module is responsible for verifying digital signatures and hashes.
+ * It relies on a crypto library to perform the cryptographic operations.
+ *
+ * The crypto module itself does not impose any specific format on signatures,
+ * signature algorithm, keys or hashes, but most cryptographic libraries will
+ * take the parameters as the following DER encoded ASN.1 structures:
+ *
+ *     AlgorithmIdentifier ::= SEQUENCE  {
+ *         algorithm        OBJECT IDENTIFIER,
+ *         parameters       ANY DEFINED BY algorithm OPTIONAL
+ *     }
+ *
+ *     DigestInfo ::= SEQUENCE {
+ *         digestAlgorithm  AlgorithmIdentifier,
+ *         digest           OCTET STRING
+ *     }
+ *
+ *     SubjectPublicKeyInfo ::= SEQUENCE  {
+ *         algorithm        AlgorithmIdentifier,
+ *         subjectPublicKey BIT STRING
+ *     }
+ *
+ *     SignatureAlgorithm ::= AlgorithmIdentifier
+ *
+ *     SignatureValue ::= BIT STRING
+ */
+
+/*
+ * Perform some static checking and call the library initialization function
+ */
+void crypto_mod_init(void)
+{
+	assert(crypto_lib_desc.name != NULL);
+	assert(crypto_lib_desc.init != NULL);
+	assert(crypto_lib_desc.verify_signature != NULL);
+	assert(crypto_lib_desc.verify_hash != NULL);
+
+	/* Initialize the cryptographic library */
+	crypto_lib_desc.init();
+	INFO("Using crypto library '%s'\n", crypto_lib_desc.name);
+}
+
+/*
+ * Function to verify a digital signature
+ *
+ * Parameters:
+ *
+ *   data_ptr, data_len: signed data
+ *   sig_ptr, sig_len: the digital signature
+ *   sig_alg_ptr, sig_alg_len: the digital signature algorithm
+ *   pk_ptr, pk_len: the public key
+ */
+int crypto_mod_verify_signature(void *data_ptr, unsigned int data_len,
+				void *sig_ptr, unsigned int sig_len,
+				void *sig_alg_ptr, unsigned int sig_alg_len,
+				void *pk_ptr, unsigned int pk_len)
+{
+	assert(data_ptr != NULL);
+	assert(data_len != 0);
+	assert(sig_ptr != NULL);
+	assert(sig_len != 0);
+	assert(sig_alg_ptr != NULL);
+	assert(sig_alg_len != 0);
+	assert(pk_ptr != NULL);
+	assert(pk_len != 0);
+
+	return crypto_lib_desc.verify_signature(data_ptr, data_len,
+						sig_ptr, sig_len,
+						sig_alg_ptr, sig_alg_len,
+						pk_ptr, pk_len);
+}
+
+/*
+ * Verify a hash by comparison
+ *
+ * Parameters:
+ *
+ *   data_ptr, data_len: data to be hashed
+ *   digest_info_ptr, digest_info_len: hash to be compared
+ */
+int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len,
+			   void *digest_info_ptr, unsigned int digest_info_len)
+{
+	assert(data_ptr != NULL);
+	assert(data_len != 0);
+	assert(digest_info_ptr != NULL);
+	assert(digest_info_len != 0);
+
+	return crypto_lib_desc.verify_hash(data_ptr, data_len,
+					   digest_info_ptr, digest_info_len);
+}
diff --git a/drivers/auth/cryptocell/712/cryptocell_crypto.c b/drivers/auth/cryptocell/712/cryptocell_crypto.c
new file mode 100644
index 0000000..395c550
--- /dev/null
+++ b/drivers/auth/cryptocell/712/cryptocell_crypto.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cryptocell/712/crypto_driver.h>
+#include <drivers/arm/cryptocell/712/rsa.h>
+#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
+#include <drivers/arm/cryptocell/712/secureboot_base_func.h>
+#include <drivers/arm/cryptocell/712/secureboot_gen_defs.h>
+#include <drivers/arm/cryptocell/712/util.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <lib/utils.h>
+
+#include <mbedtls/oid.h>
+
+#define LIB_NAME		"CryptoCell 712 SBROM"
+#define RSA_SALT_LEN		32
+#define RSA_EXPONENT		65537
+
+/*
+ * AlgorithmIdentifier  ::=  SEQUENCE  {
+ *     algorithm            OBJECT IDENTIFIER,
+ *     parameters           ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * SubjectPublicKeyInfo  ::=  SEQUENCE  {
+ *     algorithm            AlgorithmIdentifier,
+ *     subjectPublicKey     BIT STRING
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm      AlgorithmIdentifier,
+ *     digest               OCTET STRING
+ * }
+ *
+ *  RSASSA-PSS-params ::= SEQUENCE {
+ *     hashAlgorithm        [0] HashAlgorithm,
+ *     maskGenAlgorithm     [1] MaskGenAlgorithm,
+ *     saltLength           [2] INTEGER,
+ *     trailerField         [3] TrailerField    DEFAULT trailerFieldBC
+ * }
+ */
+
+/*
+ * Initialize the library and export the descriptor
+ */
+static void init(void)
+{
+	CCError_t ret;
+	uint32_t lcs;
+
+	/* Initialize CC SBROM */
+	ret = CC_BsvSbromInit((uintptr_t)PLAT_CRYPTOCELL_BASE);
+	if (ret != CC_OK) {
+		ERROR("CryptoCell CC_BsvSbromInit() error %x\n", ret);
+		panic();
+	}
+
+	/* Initialize lifecycle state */
+	ret = CC_BsvLcsGetAndInit((uintptr_t)PLAT_CRYPTOCELL_BASE, &lcs);
+	if (ret != CC_OK) {
+		ERROR("CryptoCell CC_BsvLcsGetAndInit() error %x\n", ret);
+		panic();
+	}
+
+	/* If the lifecyclestate is `SD`, then stop further execution */
+	if (lcs == CC_BSV_SECURITY_DISABLED_LCS) {
+		ERROR("CryptoCell LCS is security-disabled\n");
+		panic();
+	}
+}
+
+/*
+ * Verify a signature.
+ *
+ * Parameters are passed using the DER encoding format following the ASN.1
+ * structures detailed above.
+ */
+static int verify_signature(void *data_ptr, unsigned int data_len,
+			    void *sig_ptr, unsigned int sig_len,
+			    void *sig_alg, unsigned int sig_alg_len,
+			    void *pk_ptr, unsigned int pk_len)
+{
+	CCError_t error;
+	CCSbNParams_t pk;
+	CCSbSignature_t signature;
+	int rc, exp;
+	mbedtls_asn1_buf sig_oid, alg_oid, params;
+	mbedtls_md_type_t md_alg;
+	mbedtls_pk_type_t pk_alg;
+	mbedtls_pk_rsassa_pss_options pss_opts;
+	size_t len;
+	uint8_t *p, *end;
+	/* Temp buf to store the public key modulo (N) in LE format */
+	uint32_t RevN[SB_RSA_MOD_SIZE_IN_WORDS];
+
+	/* Verify the signature algorithm */
+	/* Get pointers to signature OID and parameters */
+	p = sig_alg;
+	end = p + sig_alg_len;
+	rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &params);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/* Get the actual signature algorithm (MD + PK) */
+	rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/* The CryptoCell only supports RSASSA-PSS signature */
+	if (pk_alg != MBEDTLS_PK_RSASSA_PSS || md_alg != MBEDTLS_MD_NONE)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/* Verify the RSASSA-PSS params */
+	/* The trailer field is verified to be 0xBC internally by this API */
+	rc = mbedtls_x509_get_rsassa_pss_params(&params, &md_alg,
+			&pss_opts.mgf1_hash_id,
+			&pss_opts.expected_salt_len);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/* The CryptoCell only supports SHA256 as hash algorithm */
+	if (md_alg != MBEDTLS_MD_SHA256 || pss_opts.mgf1_hash_id != MBEDTLS_MD_SHA256)
+		return CRYPTO_ERR_SIGNATURE;
+
+	if (pss_opts.expected_salt_len != RSA_SALT_LEN)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/* Parse the public key */
+	p = pk_ptr;
+	end = p + pk_len;
+	rc = mbedtls_asn1_get_tag(&p, end, &len,
+			MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	end = p + len;
+	rc = mbedtls_asn1_get_alg_null(&p, end, &alg_oid);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	if (mbedtls_oid_get_pk_alg(&alg_oid, &pk_alg) != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	if (pk_alg != MBEDTLS_PK_RSA)
+		return CRYPTO_ERR_SIGNATURE;
+
+	rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	rc = mbedtls_asn1_get_tag(&p, end, &len,
+				MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	if (*p == 0) {
+		p++; len--;
+	}
+	if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end))
+		return CRYPTO_ERR_SIGNATURE;
+
+	/*
+	 * The CCSbVerifySignature() API expects N and Np in BE format and
+	 * the signature in LE format. Copy N from certificate.
+	 */
+	memcpy(pk.N, p, RSA_MOD_SIZE_IN_BYTES);
+
+	/* Verify the RSA exponent */
+	p += len;
+	rc = mbedtls_asn1_get_int(&p, end, &exp);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	if (exp != RSA_EXPONENT)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/*
+	 * Calculate the Np (Barrett n' value). The RSA_CalcNp() API expects
+	 * N in LE format. Hence reverse N into a temporary buffer `RevN`.
+	 */
+	UTIL_ReverseMemCopy((uint8_t *)RevN, (uint8_t *)pk.N, sizeof(RevN));
+
+	RSA_CalcNp((uintptr_t)PLAT_CRYPTOCELL_BASE, RevN, pk.Np);
+
+	/* Np is in LE format. Reverse it to BE */
+	UTIL_ReverseBuff((uint8_t *)pk.Np, sizeof(pk.Np));
+
+	/* Get the signature (bitstring) */
+	p = sig_ptr;
+	end = p + sig_len;
+	rc = mbedtls_asn1_get_bitstring_null(&p, end, &len);
+	if (rc != 0)
+		return CRYPTO_ERR_SIGNATURE;
+
+	if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end))
+		return CRYPTO_ERR_SIGNATURE;
+
+	/*
+	 *  The signature is BE format. Convert it to LE before calling
+	 *  CCSbVerifySignature().
+	 */
+	UTIL_ReverseMemCopy((uint8_t *)signature.sig, p, RSA_MOD_SIZE_IN_BYTES);
+
+	/*
+	 * CryptoCell utilises DMA internally to transfer data. Flush the data
+	 * from caches.
+	 */
+	flush_dcache_range((uintptr_t)data_ptr, data_len);
+
+	/* Verify the signature */
+	error = CCSbVerifySignature((uintptr_t)PLAT_CRYPTOCELL_BASE,
+			(uint32_t *)data_ptr, &pk, &signature,
+			data_len, RSA_PSS_2048);
+	if (error != CC_OK)
+		return CRYPTO_ERR_SIGNATURE;
+
+	/* Signature verification success */
+	return CRYPTO_SUCCESS;
+}
+
+/*
+ * Match a hash
+ *
+ * Digest info is passed in DER format following the ASN.1 structure detailed
+ * above.
+ */
+static int verify_hash(void *data_ptr, unsigned int data_len,
+		       void *digest_info_ptr, unsigned int digest_info_len)
+{
+	mbedtls_asn1_buf hash_oid, params;
+	mbedtls_md_type_t md_alg;
+	uint8_t *p, *end, *hash;
+	CCHashResult_t pubKeyHash;
+	size_t len;
+	int rc;
+	CCError_t error;
+
+	/* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
+	p = digest_info_ptr;
+	end = p + digest_info_len;
+	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				  MBEDTLS_ASN1_SEQUENCE);
+	if (rc != 0)
+		return CRYPTO_ERR_HASH;
+
+	/* Get the hash algorithm */
+	rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
+	if (rc != 0)
+		return CRYPTO_ERR_HASH;
+
+	rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
+	if (rc != 0)
+		return CRYPTO_ERR_HASH;
+	/* Verify that hash algorithm is SHA256 */
+	if (md_alg != MBEDTLS_MD_SHA256)
+		return CRYPTO_ERR_HASH;
+
+	/* Hash should be octet string type */
+	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
+	if (rc != 0)
+		return CRYPTO_ERR_HASH;
+
+	/* Length of hash must match the algorithm's size */
+	if (len != HASH_RESULT_SIZE_IN_BYTES)
+		return CRYPTO_ERR_HASH;
+
+	/*
+	 * CryptoCell utilises DMA internally to transfer data. Flush the data
+	 * from caches.
+	 */
+	flush_dcache_range((uintptr_t)data_ptr, data_len);
+
+	hash = p;
+	error = SBROM_CryptoHash((uintptr_t)PLAT_CRYPTOCELL_BASE,
+			(uintptr_t)data_ptr, data_len, pubKeyHash);
+	if (error != CC_OK)
+		return CRYPTO_ERR_HASH;
+
+	rc = memcmp(pubKeyHash, hash, HASH_RESULT_SIZE_IN_BYTES);
+	if (rc != 0)
+		return CRYPTO_ERR_HASH;
+
+	return CRYPTO_SUCCESS;
+}
+
+/*
+ * Register crypto library descriptor
+ */
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash);
+
diff --git a/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c b/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c
new file mode 100644
index 0000000..53d77db
--- /dev/null
+++ b/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <plat/common/platform.h>
+#include <tools_share/tbbr_oid.h>
+
+#include <common/debug.h>
+#include <drivers/arm/cryptocell/712/sbrom_bsv_api.h>
+#include <drivers/arm/cryptocell/712/nvm.h>
+#include <drivers/arm/cryptocell/712/nvm_otp.h>
+
+/*
+ * Return the ROTPK hash
+ *
+ * dst:   buffer into which the ROTPK hash will be copied into
+ * len:   length of the provided buffer, which must be at least enough for a
+ *        SHA256 hash
+ * flags: a pointer to integer that will be set to indicate the ROTPK status
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int cc_get_rotpk_hash(unsigned char *dst, unsigned int len, unsigned int *flags)
+{
+	CCError_t error;
+	uint32_t lcs;
+
+	assert(dst != NULL);
+	assert(len >= HASH_RESULT_SIZE_IN_WORDS);
+	assert(flags != NULL);
+
+	error = NVM_GetLCS(PLAT_CRYPTOCELL_BASE, &lcs);
+	if (error != CC_OK)
+		return 1;
+
+	/* If the lifecycle state is `SD`, return failure */
+	if (lcs == CC_BSV_SECURITY_DISABLED_LCS)
+		return 1;
+
+	/*
+	 * If the lifecycle state is `CM` or `DM`, ROTPK shouldn't be verified.
+	 * Return success after setting ROTPK_NOT_DEPLOYED flag
+	 */
+	if ((lcs == CC_BSV_CHIP_MANUFACTURE_LCS) ||
+			(lcs == CC_BSV_DEVICE_MANUFACTURE_LCS)) {
+		*flags = ROTPK_NOT_DEPLOYED;
+		return 0;
+	}
+
+	/* Copy the DER header */
+	error = NVM_ReadHASHPubKey(PLAT_CRYPTOCELL_BASE,
+			CC_SB_HASH_BOOT_KEY_256B,
+			(uint32_t *)dst, HASH_RESULT_SIZE_IN_WORDS);
+	if (error != CC_OK)
+		return 1;
+
+	*flags = ROTPK_IS_HASH;
+	return 0;
+}
+
+/*
+ * Return the non-volatile counter value stored in the platform. The cookie
+ * specifies the OID of the counter in the certificate.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	CCError_t error = CC_FAIL;
+
+	if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		error = NVM_GetSwVersion(PLAT_CRYPTOCELL_BASE,
+				CC_SW_VERSION_COUNTER1, nv_ctr);
+	} else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		error = NVM_GetSwVersion(PLAT_CRYPTOCELL_BASE,
+				CC_SW_VERSION_COUNTER2, nv_ctr);
+	}
+
+	return (error != CC_OK);
+}
+
+/*
+ * Store a new non-volatile counter value in the counter specified by the OID
+ * in the cookie. This function is not expected to be called if the Lifecycle
+ * state is RMA as the values in the certificate are expected to always match
+ * the nvcounter values. But if called when the LCS is RMA, the underlying
+ * helper functions will return success but without updating the counter.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	CCError_t error = CC_FAIL;
+
+	if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		error = NVM_SetSwVersion(PLAT_CRYPTOCELL_BASE,
+				CC_SW_VERSION_COUNTER1, nv_ctr);
+	} else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		error = NVM_SetSwVersion(PLAT_CRYPTOCELL_BASE,
+				CC_SW_VERSION_COUNTER2, nv_ctr);
+	}
+
+	return (error != CC_OK);
+}
+
diff --git a/drivers/auth/cryptocell/cryptocell_crypto.mk b/drivers/auth/cryptocell/cryptocell_crypto.mk
new file mode 100644
index 0000000..d42a2e7
--- /dev/null
+++ b/drivers/auth/cryptocell/cryptocell_crypto.mk
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/auth/mbedtls/mbedtls_common.mk
+
+# The algorithm is RSA when using Cryptocell crypto driver
+TF_MBEDTLS_KEY_ALG_ID		:=	TF_MBEDTLS_RSA
+
+# Needs to be set to drive mbed TLS configuration correctly
+$(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID))
+
+# CCSBROM_LIB_PATH must be set to the Cryptocell SBROM library path
+ifeq (${CCSBROM_LIB_PATH},)
+  $(error Error: CCSBROM_LIB_PATH not set)
+endif
+
+CRYPTOCELL_VERSION ?= 712
+ifeq (${CRYPTOCELL_VERSION},712)
+  CCSBROM_LIB_FILENAME := cc_712sbromx509
+else
+  $(error Error: CRYPTOCELL_VERSION set to invalid version)
+endif
+
+CRYPTOCELL_SRC_DIR	:= drivers/auth/cryptocell/${CRYPTOCELL_VERSION}/
+
+CRYPTOCELL_SOURCES	:= ${CRYPTOCELL_SRC_DIR}/cryptocell_crypto.c \
+			   ${CRYPTOCELL_SRC_DIR}/cryptocell_plat_helpers.c
+
+TF_LDFLAGS		+= -L$(CCSBROM_LIB_PATH)
+LDLIBS			+= -l$(CCSBROM_LIB_FILENAME)
+
+BL1_SOURCES		+= ${CRYPTOCELL_SOURCES}
+BL2_SOURCES		+= ${CRYPTOCELL_SOURCES}
diff --git a/drivers/auth/img_parser_mod.c b/drivers/auth/img_parser_mod.c
new file mode 100644
index 0000000..c4688f8
--- /dev/null
+++ b/drivers/auth/img_parser_mod.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/auth/auth_common.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <lib/utils_def.h>
+
+IMPORT_SYM(uintptr_t, __PARSER_LIB_DESCS_START__,	PARSER_LIB_DESCS_START);
+IMPORT_SYM(uintptr_t, __PARSER_LIB_DESCS_END__,		PARSER_LIB_DESCS_END);
+static unsigned int parser_lib_indices[IMG_MAX_TYPES];
+static img_parser_lib_desc_t *parser_lib_descs;
+
+#define INVALID_IDX		UINT_MAX
+
+static void validate_desc(img_parser_lib_desc_t *desc)
+{
+	assert(desc != NULL);
+	assert(desc->init != NULL);
+	assert(desc->name != NULL);
+	assert(desc->check_integrity != NULL);
+	assert(desc->get_auth_param != NULL);
+}
+
+void img_parser_init(void)
+{
+	unsigned int index, mod_num;
+
+	/* Initialise internal variables to invalid state */
+	for (index = 0; index < IMG_MAX_TYPES; index++) {
+		parser_lib_indices[index] = INVALID_IDX;
+	}
+
+	/* Calculate how many image parsers are registered. At least one parser
+	 * must be present */
+	mod_num = PARSER_LIB_DESCS_END - PARSER_LIB_DESCS_START;
+	mod_num /= sizeof(img_parser_lib_desc_t);
+	assert(mod_num > 0);
+
+	parser_lib_descs = (img_parser_lib_desc_t *) PARSER_LIB_DESCS_START;
+	for (index = 0; index < mod_num; index++) {
+
+		/* Check that the image parser library descriptor is valid */
+		validate_desc(&parser_lib_descs[index]);
+
+		/* Initialize image parser */
+		parser_lib_descs[index].init();
+
+		/* Ensure only one parser is registered for each image type */
+		assert(parser_lib_indices[parser_lib_descs[index].img_type] ==
+				INVALID_IDX);
+
+		/* Keep the index of this hash calculator */
+		parser_lib_indices[parser_lib_descs[index].img_type] = index;
+	}
+}
+
+int img_parser_check_integrity(img_type_t img_type,
+			       void *img_ptr, unsigned int img_len)
+{
+	unsigned int idx;
+
+	assert(img_ptr != NULL);
+	assert(img_len != 0);
+
+	/* No integrity checks on raw images */
+	if (img_type == IMG_RAW) {
+		return IMG_PARSER_OK;
+	}
+
+	/* Find the index of the required image parser */
+	idx = parser_lib_indices[img_type];
+	assert(idx != INVALID_IDX);
+
+	/* Call the function to check the image integrity */
+	return parser_lib_descs[idx].check_integrity(img_ptr, img_len);
+}
+
+/*
+ * Extract an authentication parameter from an image
+ *
+ * Parameters:
+ *   img_type: image type (certificate, raw image, etc)
+ *   type_desc: provides info to obtain the parameter
+ *   img_ptr: pointer to image data
+ *   img_len: image length
+ *   param_ptr: [out] stores a pointer to the parameter
+ *   param_len: [out] stores the length of the parameter
+ */
+int img_parser_get_auth_param(img_type_t img_type,
+			      const auth_param_type_desc_t *type_desc,
+			      void *img_ptr, unsigned int img_len,
+			      void **param_ptr, unsigned int *param_len)
+{
+	unsigned int idx;
+
+	assert(type_desc != NULL);
+	assert(img_ptr != NULL);
+	assert(img_len != 0);
+	assert(param_ptr != NULL);
+	assert(param_len != NULL);
+
+	/* In a raw image we can only get the data itself */
+	if (img_type == IMG_RAW) {
+		assert(type_desc->type == AUTH_PARAM_RAW_DATA);
+		*param_ptr = img_ptr;
+		*param_len = img_len;
+		return IMG_PARSER_OK;
+	}
+
+	/* Find the index of the required image parser library */
+	idx = parser_lib_indices[img_type];
+	assert(idx != INVALID_IDX);
+
+	/* Call the function to obtain the parameter */
+	return parser_lib_descs[idx].get_auth_param(type_desc, img_ptr, img_len,
+			param_ptr, param_len);
+}
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
new file mode 100644
index 0000000..4a8efae
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+/* mbed TLS headers */
+#include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/platform.h>
+
+#include <common/debug.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <plat/common/platform.h>
+
+static void cleanup(void)
+{
+	ERROR("EXIT from BL2\n");
+	panic();
+}
+
+/*
+ * mbed TLS initialization function
+ */
+void mbedtls_init(void)
+{
+	static int ready;
+	void *heap_addr;
+	size_t heap_size = 0;
+	int err;
+
+	if (!ready) {
+		if (atexit(cleanup))
+			panic();
+
+		err = plat_get_mbedtls_heap(&heap_addr, &heap_size);
+
+		/* Ensure heap setup is proper */
+		if (err < 0) {
+			ERROR("Mbed TLS failed to get a heap\n");
+			panic();
+		}
+		assert(heap_size >= TF_MBEDTLS_HEAP_SIZE);
+
+		/* Initialize the mbed TLS heap */
+		mbedtls_memory_buffer_alloc_init(heap_addr, heap_size);
+
+#ifdef MBEDTLS_PLATFORM_SNPRINTF_ALT
+		mbedtls_platform_set_snprintf(snprintf);
+#endif
+		ready = 1;
+	}
+}
+
+/*
+ * The following helper function simply returns the default allocated heap.
+ * It can be used by platforms for their plat_get_mbedtls_heap() implementation.
+ */
+int get_mbedtls_heap_helper(void **heap_addr, size_t *heap_size)
+{
+	static unsigned char heap[TF_MBEDTLS_HEAP_SIZE];
+
+	assert(heap_addr != NULL);
+	assert(heap_size != NULL);
+
+	*heap_addr = heap;
+	*heap_size = sizeof(heap);
+	return 0;
+}
diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk
new file mode 100644
index 0000000..63e65bd
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_common.mk
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${MBEDTLS_COMMON_MK},1)
+MBEDTLS_COMMON_MK	:=	1
+
+# MBEDTLS_DIR must be set to the mbed TLS main directory (it must contain
+# the 'include' and 'library' subdirectories).
+ifeq (${MBEDTLS_DIR},)
+  $(error Error: MBEDTLS_DIR not set)
+endif
+
+MBEDTLS_INC		=	-I${MBEDTLS_DIR}/include
+
+# Specify mbed TLS configuration file
+MBEDTLS_CONFIG_FILE	:=	"<drivers/auth/mbedtls/mbedtls_config.h>"
+$(eval $(call add_define,MBEDTLS_CONFIG_FILE))
+
+MBEDTLS_SOURCES	+=		drivers/auth/mbedtls/mbedtls_common.c
+
+
+LIBMBEDTLS_SRCS		:= $(addprefix ${MBEDTLS_DIR}/library/,	\
+					asn1parse.c 				\
+					asn1write.c 				\
+					memory_buffer_alloc.c			\
+					oid.c 					\
+					platform.c 				\
+					platform_util.c				\
+					bignum.c				\
+					md.c					\
+					md_wrap.c				\
+					pk.c 					\
+					pk_wrap.c 				\
+					pkparse.c 				\
+					pkwrite.c 				\
+					sha256.c            			\
+					sha512.c            			\
+					ecdsa.c					\
+					ecp_curves.c				\
+					ecp.c					\
+					rsa.c					\
+					rsa_internal.c				\
+					x509.c 					\
+					x509_crt.c 				\
+					)
+
+# The platform may define the variable 'TF_MBEDTLS_KEY_ALG' to select the key
+# algorithm to use. If the variable is not defined, select it based on algorithm
+# used for key generation `KEY_ALG`. If `KEY_ALG` is not defined or is
+# defined to `rsa`/`rsa_1_5`, then set the variable to `rsa`.
+ifeq (${TF_MBEDTLS_KEY_ALG},)
+    ifeq (${KEY_ALG}, ecdsa)
+        TF_MBEDTLS_KEY_ALG		:=	ecdsa
+    else
+        TF_MBEDTLS_KEY_ALG		:=	rsa
+    endif
+endif
+
+ifeq (${HASH_ALG}, sha384)
+    TF_MBEDTLS_HASH_ALG_ID	:=	TF_MBEDTLS_SHA384
+else ifeq (${HASH_ALG}, sha512)
+   TF_MBEDTLS_HASH_ALG_ID	:=	TF_MBEDTLS_SHA512
+else
+    TF_MBEDTLS_HASH_ALG_ID	:=	TF_MBEDTLS_SHA256
+endif
+
+ifeq (${TF_MBEDTLS_KEY_ALG},ecdsa)
+    TF_MBEDTLS_KEY_ALG_ID	:=	TF_MBEDTLS_ECDSA
+else ifeq (${TF_MBEDTLS_KEY_ALG},rsa)
+    TF_MBEDTLS_KEY_ALG_ID	:=	TF_MBEDTLS_RSA
+else ifeq (${TF_MBEDTLS_KEY_ALG},rsa+ecdsa)
+    TF_MBEDTLS_KEY_ALG_ID	:=	TF_MBEDTLS_RSA_AND_ECDSA
+else
+    $(error "TF_MBEDTLS_KEY_ALG=${TF_MBEDTLS_KEY_ALG} not supported on mbed TLS")
+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_HASH_ALG_ID))
+
+
+$(eval $(call MAKE_LIB,mbedtls))
+
+endif
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
new file mode 100644
index 0000000..33420fb
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+/* mbed TLS headers */
+#include <mbedtls/md.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <drivers/auth/mbedtls/mbedtls_config.h>
+
+#define LIB_NAME		"mbed TLS"
+
+/*
+ * AlgorithmIdentifier  ::=  SEQUENCE  {
+ *     algorithm               OBJECT IDENTIFIER,
+ *     parameters              ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * SubjectPublicKeyInfo  ::=  SEQUENCE  {
+ *     algorithm            AlgorithmIdentifier,
+ *     subjectPublicKey     BIT STRING
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm AlgorithmIdentifier,
+ *     digest OCTET STRING
+ * }
+ */
+
+/*
+ * Initialize the library and export the descriptor
+ */
+static void init(void)
+{
+	/* Initialize mbed TLS */
+	mbedtls_init();
+}
+
+/*
+ * Verify a signature.
+ *
+ * Parameters are passed using the DER encoding format following the ASN.1
+ * structures detailed above.
+ */
+static int verify_signature(void *data_ptr, unsigned int data_len,
+			    void *sig_ptr, unsigned int sig_len,
+			    void *sig_alg, unsigned int sig_alg_len,
+			    void *pk_ptr, unsigned int pk_len)
+{
+	mbedtls_asn1_buf sig_oid, sig_params;
+	mbedtls_asn1_buf signature;
+	mbedtls_md_type_t md_alg;
+	mbedtls_pk_type_t pk_alg;
+	mbedtls_pk_context pk = {0};
+	int rc;
+	void *sig_opts = NULL;
+	const mbedtls_md_info_t *md_info;
+	unsigned char *p, *end;
+	unsigned char hash[MBEDTLS_MD_MAX_SIZE];
+
+	/* Get pointers to signature OID and parameters */
+	p = (unsigned char *)sig_alg;
+	end = (unsigned char *)(p + sig_alg_len);
+	rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	/* Get the actual signature algorithm (MD + PK) */
+	rc = mbedtls_x509_get_sig_alg(&sig_oid, &sig_params, &md_alg, &pk_alg, &sig_opts);
+	if (rc != 0) {
+		return CRYPTO_ERR_SIGNATURE;
+	}
+
+	/* Parse the public key */
+	mbedtls_pk_init(&pk);
+	p = (unsigned char *)pk_ptr;
+	end = (unsigned char *)(p + pk_len);
+	rc = mbedtls_pk_parse_subpubkey(&p, end, &pk);
+	if (rc != 0) {
+		rc = CRYPTO_ERR_SIGNATURE;
+		goto end2;
+	}
+
+	/* Get the signature (bitstring) */
+	p = (unsigned char *)sig_ptr;
+	end = (unsigned char *)(p + sig_len);
+	signature.tag = *p;
+	rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len);
+	if (rc != 0) {
+		rc = CRYPTO_ERR_SIGNATURE;
+		goto end1;
+	}
+	signature.p = p;
+
+	/* Calculate the hash of the data */
+	md_info = mbedtls_md_info_from_type(md_alg);
+	if (md_info == NULL) {
+		rc = CRYPTO_ERR_SIGNATURE;
+		goto end1;
+	}
+	p = (unsigned char *)data_ptr;
+	rc = mbedtls_md(md_info, p, data_len, hash);
+	if (rc != 0) {
+		rc = CRYPTO_ERR_SIGNATURE;
+		goto end1;
+	}
+
+	/* Verify the signature */
+	rc = mbedtls_pk_verify_ext(pk_alg, sig_opts, &pk, md_alg, hash,
+			mbedtls_md_get_size(md_info),
+			signature.p, signature.len);
+	if (rc != 0) {
+		rc = CRYPTO_ERR_SIGNATURE;
+		goto end1;
+	}
+
+	/* Signature verification success */
+	rc = CRYPTO_SUCCESS;
+
+end1:
+	mbedtls_pk_free(&pk);
+end2:
+	mbedtls_free(sig_opts);
+	return rc;
+}
+
+/*
+ * Match a hash
+ *
+ * Digest info is passed in DER format following the ASN.1 structure detailed
+ * above.
+ */
+static int verify_hash(void *data_ptr, unsigned int data_len,
+		       void *digest_info_ptr, unsigned int digest_info_len)
+{
+	mbedtls_asn1_buf hash_oid, params;
+	mbedtls_md_type_t md_alg;
+	const mbedtls_md_info_t *md_info;
+	unsigned char *p, *end, *hash;
+	unsigned char data_hash[MBEDTLS_MD_MAX_SIZE];
+	size_t len;
+	int rc;
+
+	/* Digest info should be an MBEDTLS_ASN1_SEQUENCE */
+	p = (unsigned char *)digest_info_ptr;
+	end = p + digest_info_len;
+	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				  MBEDTLS_ASN1_SEQUENCE);
+	if (rc != 0) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	/* Get the hash algorithm */
+	rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, &params);
+	if (rc != 0) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg);
+	if (rc != 0) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	md_info = mbedtls_md_info_from_type(md_alg);
+	if (md_info == NULL) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	/* Hash should be octet string type */
+	rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
+	if (rc != 0) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	/* Length of hash must match the algorithm's size */
+	if (len != mbedtls_md_get_size(md_info)) {
+		return CRYPTO_ERR_HASH;
+	}
+	hash = p;
+
+	/* Calculate the hash of the data */
+	p = (unsigned char *)data_ptr;
+	rc = mbedtls_md(md_info, p, data_len, data_hash);
+	if (rc != 0) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	/* Compare values */
+	rc = memcmp(data_hash, hash, mbedtls_md_get_size(md_info));
+	if (rc != 0) {
+		return CRYPTO_ERR_HASH;
+	}
+
+	return CRYPTO_SUCCESS;
+}
+
+/*
+ * Register crypto library descriptor
+ */
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash);
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.mk b/drivers/auth/mbedtls/mbedtls_crypto.mk
new file mode 100644
index 0000000..2a9fbbf
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_crypto.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/auth/mbedtls/mbedtls_common.mk
+
+MBEDTLS_SOURCES	+=		drivers/auth/mbedtls/mbedtls_crypto.c
+
+
diff --git a/drivers/auth/mbedtls/mbedtls_x509.mk b/drivers/auth/mbedtls/mbedtls_x509.mk
new file mode 100644
index 0000000..a0557e2
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_x509.mk
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/auth/mbedtls/mbedtls_common.mk
+
+MBEDTLS_SOURCES	+=	drivers/auth/mbedtls/mbedtls_x509_parser.c
diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c
new file mode 100644
index 0000000..129566b
--- /dev/null
+++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * X509 parser based on mbed TLS
+ *
+ * This module implements functions to check the integrity of a X509v3
+ * certificate ASN.1 structure and extract authentication parameters from the
+ * extensions field, such as an image hash or a public key.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/* mbed TLS headers */
+#include <mbedtls/asn1.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/platform.h>
+
+#include <arch_helpers.h>
+#include <drivers/auth/img_parser_mod.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <lib/utils.h>
+
+/* Maximum OID string length ("a.b.c.d.e.f ...") */
+#define MAX_OID_STR_LEN			64
+
+#define LIB_NAME	"mbed TLS X509v3"
+
+/* Temporary variables to speed up the authentication parameters search. These
+ * variables are assigned once during the integrity check and used any time an
+ * authentication parameter is requested, so we do not have to parse the image
+ * again */
+static mbedtls_asn1_buf tbs;
+static mbedtls_asn1_buf v3_ext;
+static mbedtls_asn1_buf pk;
+static mbedtls_asn1_buf sig_alg;
+static mbedtls_asn1_buf signature;
+
+/*
+ * Clear all static temporary variables.
+ */
+static void clear_temp_vars(void)
+{
+#define ZERO_AND_CLEAN(x)					\
+	do {							\
+		zeromem(&x, sizeof(x));				\
+		clean_dcache_range((uintptr_t)&x, sizeof(x));	\
+	} while (0);
+
+	ZERO_AND_CLEAN(tbs)
+	ZERO_AND_CLEAN(v3_ext);
+	ZERO_AND_CLEAN(pk);
+	ZERO_AND_CLEAN(sig_alg);
+	ZERO_AND_CLEAN(signature);
+
+#undef ZERO_AND_CLEAN
+}
+
+/*
+ * Get X509v3 extension
+ *
+ * Global variable 'v3_ext' must point to the extensions region
+ * in the certificate. No need to check for errors since the image has passed
+ * the integrity check.
+ */
+static int get_ext(const char *oid, void **ext, unsigned int *ext_len)
+{
+	int oid_len;
+	size_t len;
+	unsigned char *end_ext_data, *end_ext_octet;
+	unsigned char *p;
+	const unsigned char *end;
+	char oid_str[MAX_OID_STR_LEN];
+	mbedtls_asn1_buf extn_oid;
+	int is_critical;
+
+	assert(oid != NULL);
+
+	p = v3_ext.p;
+	end = v3_ext.p + v3_ext.len;
+
+	mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+			     MBEDTLS_ASN1_SEQUENCE);
+
+	while (p < end) {
+		zeromem(&extn_oid, sizeof(extn_oid));
+		is_critical = 0; /* DEFAULT FALSE */
+
+		mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				     MBEDTLS_ASN1_SEQUENCE);
+		end_ext_data = p + len;
+
+		/* Get extension ID */
+		extn_oid.tag = *p;
+		mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID);
+		extn_oid.p = p;
+		p += extn_oid.len;
+
+		/* Get optional critical */
+		mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical);
+
+		/* Extension data */
+		mbedtls_asn1_get_tag(&p, end_ext_data, &len,
+				     MBEDTLS_ASN1_OCTET_STRING);
+		end_ext_octet = p + len;
+
+		/* Detect requested extension */
+		oid_len = mbedtls_oid_get_numeric_string(oid_str,
+							 MAX_OID_STR_LEN,
+							 &extn_oid);
+		if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
+			return IMG_PARSER_ERR;
+		}
+		if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) {
+			*ext = (void *)p;
+			*ext_len = (unsigned int)len;
+			return IMG_PARSER_OK;
+		}
+
+		/* Next */
+		p = end_ext_octet;
+	}
+
+	return IMG_PARSER_ERR_NOT_FOUND;
+}
+
+
+/*
+ * Check the integrity of the certificate ASN.1 structure.
+ *
+ * Extract the relevant data that will be used later during authentication.
+ *
+ * This function doesn't clear the static variables located on the top of this
+ * file in case of an error. It is only called from check_integrity(), which
+ * performs the cleanup if necessary.
+ */
+static int cert_parse(void *img, unsigned int img_len)
+{
+	int ret, is_critical;
+	size_t len;
+	unsigned char *p, *end, *crt_end;
+	mbedtls_asn1_buf sig_alg1, sig_alg2;
+
+	p = (unsigned char *)img;
+	len = img_len;
+	end = p + len;
+
+	/*
+	 * Certificate  ::=  SEQUENCE  {
+	 *      tbsCertificate       TBSCertificate,
+	 *      signatureAlgorithm   AlgorithmIdentifier,
+	 *      signatureValue       BIT STRING  }
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+
+	if (len > (size_t)(end - p)) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	crt_end = p + len;
+
+	/*
+	 * TBSCertificate  ::=  SEQUENCE  {
+	 */
+	tbs.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	end = p + len;
+	tbs.len = end - tbs.p;
+
+	/*
+	 * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len,
+				   MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+				   MBEDTLS_ASN1_CONSTRUCTED | 0);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	p += len;
+
+	/*
+	 * CertificateSerialNumber  ::=  INTEGER
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	p += len;
+
+	/*
+	 * signature            AlgorithmIdentifier
+	 */
+	sig_alg1.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	if ((end - p) < 1) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	sig_alg1.len = (p + len) - sig_alg1.p;
+	p += len;
+
+	/*
+	 * issuer               Name
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	p += len;
+
+	/*
+	 * Validity ::= SEQUENCE {
+	 *      notBefore      Time,
+	 *      notAfter       Time }
+	 *
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	p += len;
+
+	/*
+	 * subject              Name
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	p += len;
+
+	/*
+	 * SubjectPublicKeyInfo
+	 */
+	pk.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	pk.len = (p + len) - pk.p;
+	p += len;
+
+	/*
+	 * issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len,
+				   MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+				   MBEDTLS_ASN1_CONSTRUCTED | 1);
+	if (ret != 0) {
+		if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
+			return IMG_PARSER_ERR_FORMAT;
+		}
+	} else {
+		p += len;
+	}
+
+	/*
+	 * subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len,
+				   MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+				   MBEDTLS_ASN1_CONSTRUCTED | 2);
+	if (ret != 0) {
+		if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
+			return IMG_PARSER_ERR_FORMAT;
+		}
+	} else {
+		p += len;
+	}
+
+	/*
+	 * extensions      [3]  EXPLICIT Extensions OPTIONAL
+	 */
+	ret = mbedtls_asn1_get_tag(&p, end, &len,
+				   MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+				   MBEDTLS_ASN1_CONSTRUCTED | 3);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+
+	/*
+	 * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+	 */
+	v3_ext.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	v3_ext.len = (p + len) - v3_ext.p;
+
+	/*
+	 * Check extensions integrity
+	 */
+	while (p < end) {
+		ret = mbedtls_asn1_get_tag(&p, end, &len,
+					   MBEDTLS_ASN1_CONSTRUCTED |
+					   MBEDTLS_ASN1_SEQUENCE);
+		if (ret != 0) {
+			return IMG_PARSER_ERR_FORMAT;
+		}
+
+		/* Get extension ID */
+		ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID);
+		if (ret != 0) {
+			return IMG_PARSER_ERR_FORMAT;
+		}
+		p += len;
+
+		/* Get optional critical */
+		ret = mbedtls_asn1_get_bool(&p, end, &is_critical);
+		if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
+			return IMG_PARSER_ERR_FORMAT;
+		}
+
+		/* Data should be octet string type */
+		ret = mbedtls_asn1_get_tag(&p, end, &len,
+					   MBEDTLS_ASN1_OCTET_STRING);
+		if (ret != 0) {
+			return IMG_PARSER_ERR_FORMAT;
+		}
+		p += len;
+	}
+
+	if (p != end) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+
+	end = crt_end;
+
+	/*
+	 *  }
+	 *  -- end of TBSCertificate
+	 *
+	 *  signatureAlgorithm   AlgorithmIdentifier
+	 */
+	sig_alg2.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
+				   MBEDTLS_ASN1_SEQUENCE);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	if ((end - p) < 1) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	sig_alg2.len = (p + len) - sig_alg2.p;
+	p += len;
+
+	/* Compare both signature algorithms */
+	if (sig_alg1.len != sig_alg2.len) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
+
+	/*
+	 * signatureValue       BIT STRING
+	 */
+	signature.p = p;
+	ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING);
+	if (ret != 0) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+	signature.len = (p + len) - signature.p;
+	p += len;
+
+	/* Check certificate length */
+	if (p != end) {
+		return IMG_PARSER_ERR_FORMAT;
+	}
+
+	return IMG_PARSER_OK;
+}
+
+
+/* Exported functions */
+
+static void init(void)
+{
+	mbedtls_init();
+}
+
+/*
+ * Wrapper for cert_parse() that clears the static variables used by it in case
+ * of an error.
+ */
+static int check_integrity(void *img, unsigned int img_len)
+{
+	int rc = cert_parse(img, img_len);
+
+	if (rc != IMG_PARSER_OK)
+		clear_temp_vars();
+
+	return rc;
+}
+
+/*
+ * Extract an authentication parameter from an X509v3 certificate
+ *
+ * This function returns a pointer to the extracted data and its length.
+ * Depending on the type of parameter, a pointer to the data stored in the
+ * certificate may be returned (i.e. an octet string containing a hash). Other
+ * data may need to be copied and formatted (i.e. integers). In the later case,
+ * a buffer of the correct type needs to be statically allocated, filled and
+ * returned.
+ */
+static int get_auth_param(const auth_param_type_desc_t *type_desc,
+		void *img, unsigned int img_len,
+		void **param, unsigned int *param_len)
+{
+	int rc = IMG_PARSER_OK;
+
+	/* We do not use img because the check_integrity function has already
+	 * extracted the relevant data (v3_ext, pk, sig_alg, etc) */
+
+	switch (type_desc->type) {
+	case AUTH_PARAM_RAW_DATA:
+		/* Data to be signed */
+		*param = (void *)tbs.p;
+		*param_len = (unsigned int)tbs.len;
+		break;
+	case AUTH_PARAM_HASH:
+	case AUTH_PARAM_NV_CTR:
+		/* All these parameters are included as X509v3 extensions */
+		rc = get_ext(type_desc->cookie, param, param_len);
+		break;
+	case AUTH_PARAM_PUB_KEY:
+		if (type_desc->cookie != 0) {
+			/* Get public key from extension */
+			rc = get_ext(type_desc->cookie, param, param_len);
+		} else {
+			/* Get the subject public key */
+			*param = (void *)pk.p;
+			*param_len = (unsigned int)pk.len;
+		}
+		break;
+	case AUTH_PARAM_SIG_ALG:
+		/* Get the certificate signature algorithm */
+		*param = (void *)sig_alg.p;
+		*param_len = (unsigned int)sig_alg.len;
+		break;
+	case AUTH_PARAM_SIG:
+		/* Get the certificate signature */
+		*param = (void *)signature.p;
+		*param_len = (unsigned int)signature.len;
+		break;
+	default:
+		rc = IMG_PARSER_ERR_NOT_FOUND;
+		break;
+	}
+
+	return rc;
+}
+
+REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \
+		       check_integrity, get_auth_param);
diff --git a/drivers/auth/tbbr/tbbr_cot.c b/drivers/auth/tbbr/tbbr_cot.c
new file mode 100644
index 0000000..da3631b
--- /dev/null
+++ b/drivers/auth/tbbr/tbbr_cot.c
@@ -0,0 +1,826 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <drivers/auth/auth_mod.h>
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+
+/*
+ * Maximum key and hash sizes (in DER format)
+ */
+#define PK_DER_LEN			294
+#define HASH_DER_LEN			83
+
+/*
+ * The platform must allocate buffers to store the authentication parameters
+ * extracted from the certificates. In this case, because of the way the CoT is
+ * established, we can reuse some of the buffers on different stages
+ */
+
+static unsigned char tb_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char hw_config_hash_buf[HASH_DER_LEN];
+static unsigned char scp_fw_hash_buf[HASH_DER_LEN];
+static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN];
+
+#ifdef IMAGE_BL2
+static unsigned char soc_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_extra1_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_extra2_hash_buf[HASH_DER_LEN];
+static unsigned char trusted_world_pk_buf[PK_DER_LEN];
+static unsigned char non_trusted_world_pk_buf[PK_DER_LEN];
+static unsigned char content_pk_buf[PK_DER_LEN];
+static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN];
+static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN];
+#endif
+
+/*
+ * Parameter type descriptors
+ */
+static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID);
+
+static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, 0);
+static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_SIG, 0);
+static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_SIG_ALG, 0);
+static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_RAW_DATA, 0);
+
+
+static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID);
+static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, HW_CONFIG_HASH_OID);
+#ifdef IMAGE_BL1
+static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID);
+static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, AP_FWU_CFG_HASH_OID);
+static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, FWU_HASH_OID);
+#endif /* IMAGE_BL1 */
+
+#ifdef IMAGE_BL2
+static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID);
+static auth_param_type_desc_t trusted_world_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, TRUSTED_WORLD_PK_OID);
+static auth_param_type_desc_t non_trusted_world_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, NON_TRUSTED_WORLD_PK_OID);
+static auth_param_type_desc_t scp_fw_content_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, SCP_FW_CONTENT_CERT_PK_OID);
+static auth_param_type_desc_t soc_fw_content_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, SOC_FW_CONTENT_CERT_PK_OID);
+static auth_param_type_desc_t tos_fw_content_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, TRUSTED_OS_FW_CONTENT_CERT_PK_OID);
+static auth_param_type_desc_t nt_fw_content_pk = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_PUB_KEY, NON_TRUSTED_FW_CONTENT_CERT_PK_OID);
+static auth_param_type_desc_t scp_fw_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, SCP_FW_HASH_OID);
+static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID);
+static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID);
+static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID);
+static auth_param_type_desc_t tos_fw_extra1_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA1_HASH_OID);
+static auth_param_type_desc_t tos_fw_extra2_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA2_HASH_OID);
+static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID);
+static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC(
+		AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID);
+
+#endif /* IMAGE_BL2 */
+
+
+	/*
+	 * BL2
+	 */
+static const auth_img_desc_t trusted_boot_fw_cert = {
+	.img_id = TRUSTED_BOOT_FW_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = NULL,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &subject_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &tb_fw_hash,
+			.data = {
+				.ptr = (void *)tb_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &tb_fw_config_hash,
+			.data = {
+				.ptr = (void *)tb_fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[2] = {
+			.type_desc = &hw_config_hash,
+			.data = {
+				.ptr = (void *)hw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+	};
+#ifdef IMAGE_BL1
+static const auth_img_desc_t bl2_image = {
+	.img_id = BL2_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_boot_fw_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tb_fw_hash
+			}
+		}
+	}
+};
+#endif /* IMAGE_BL1 */
+/* HW Config */
+static const auth_img_desc_t hw_config = {
+	.img_id = HW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_boot_fw_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &hw_config_hash
+			}
+		}
+	}
+};
+/* TB FW Config */
+#ifdef IMAGE_BL1
+static const auth_img_desc_t tb_fw_config = {
+	.img_id = TB_FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_boot_fw_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tb_fw_config_hash
+			}
+		}
+	}
+};
+#endif /* IMAGE_BL1 */
+#ifdef IMAGE_BL2
+/*
+ * Trusted key certificate
+ */
+static const auth_img_desc_t trusted_key_cert = {
+	.img_id = TRUSTED_KEY_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = NULL,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &subject_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &trusted_world_pk,
+			.data = {
+				.ptr = (void *)trusted_world_pk_buf,
+				.len = (unsigned int)PK_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &non_trusted_world_pk,
+			.data = {
+				.ptr = (void *)non_trusted_world_pk_buf,
+				.len = (unsigned int)PK_DER_LEN
+			}
+		}
+	}
+};
+/*
+ * SCP Firmware
+ */
+static const auth_img_desc_t scp_fw_key_cert = {
+	.img_id = SCP_FW_KEY_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &trusted_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &trusted_world_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &scp_fw_content_pk,
+			.data = {
+				.ptr = (void *)content_pk_buf,
+				.len = (unsigned int)PK_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t scp_fw_content_cert = {
+	.img_id = SCP_FW_CONTENT_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &scp_fw_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &scp_fw_content_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &scp_fw_hash,
+			.data = {
+				.ptr = (void *)scp_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t scp_bl2_image = {
+	.img_id = SCP_BL2_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &scp_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &scp_fw_hash
+			}
+		}
+	}
+};
+/*
+ * SoC Firmware
+ */
+static const auth_img_desc_t soc_fw_key_cert = {
+	.img_id = SOC_FW_KEY_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &trusted_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &trusted_world_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &soc_fw_content_pk,
+			.data = {
+				.ptr = (void *)content_pk_buf,
+				.len = (unsigned int)PK_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t soc_fw_content_cert = {
+	.img_id = SOC_FW_CONTENT_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &soc_fw_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &soc_fw_content_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &soc_fw_hash,
+			.data = {
+				.ptr = (void *)soc_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &soc_fw_config_hash,
+			.data = {
+				.ptr = (void *)soc_fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t bl31_image = {
+	.img_id = BL31_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &soc_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &soc_fw_hash
+			}
+		}
+	}
+};
+/* SOC FW Config */
+static const auth_img_desc_t soc_fw_config = {
+	.img_id = SOC_FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &soc_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &soc_fw_config_hash
+			}
+		}
+	}
+};
+/*
+ * Trusted OS Firmware
+ */
+static const auth_img_desc_t trusted_os_fw_key_cert = {
+	.img_id = TRUSTED_OS_FW_KEY_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &trusted_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &trusted_world_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &tos_fw_content_pk,
+			.data = {
+				.ptr = (void *)content_pk_buf,
+				.len = (unsigned int)PK_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t trusted_os_fw_content_cert = {
+	.img_id = TRUSTED_OS_FW_CONTENT_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &trusted_os_fw_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &tos_fw_content_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &trusted_nv_ctr,
+				.plat_nv_ctr = &trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &tos_fw_hash,
+			.data = {
+				.ptr = (void *)tos_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &tos_fw_extra1_hash,
+			.data = {
+				.ptr = (void *)tos_fw_extra1_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[2] = {
+			.type_desc = &tos_fw_extra2_hash,
+			.data = {
+				.ptr = (void *)tos_fw_extra2_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[3] = {
+			.type_desc = &tos_fw_config_hash,
+			.data = {
+				.ptr = (void *)tos_fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t bl32_image = {
+	.img_id = BL32_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_os_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tos_fw_hash
+			}
+		}
+	}
+};
+static const auth_img_desc_t bl32_extra1_image = {
+	.img_id = BL32_EXTRA1_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_os_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tos_fw_extra1_hash
+			}
+		}
+	}
+};
+static const auth_img_desc_t bl32_extra2_image = {
+	.img_id = BL32_EXTRA2_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_os_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tos_fw_extra2_hash
+			}
+		}
+	}
+};
+/* TOS FW Config */
+static const auth_img_desc_t tos_fw_config = {
+	.img_id = TOS_FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &trusted_os_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &tos_fw_config_hash
+			}
+		}
+	}
+};
+/*
+ * Non-Trusted Firmware
+ */
+static const auth_img_desc_t non_trusted_fw_key_cert = {
+	.img_id = NON_TRUSTED_FW_KEY_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &trusted_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &non_trusted_world_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &non_trusted_nv_ctr,
+				.plat_nv_ctr = &non_trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &nt_fw_content_pk,
+			.data = {
+				.ptr = (void *)content_pk_buf,
+				.len = (unsigned int)PK_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t non_trusted_fw_content_cert = {
+	.img_id = NON_TRUSTED_FW_CONTENT_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = &non_trusted_fw_key_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &nt_fw_content_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		},
+		[1] = {
+			.type = AUTH_METHOD_NV_CTR,
+			.param.nv_ctr = {
+				.cert_nv_ctr = &non_trusted_nv_ctr,
+				.plat_nv_ctr = &non_trusted_nv_ctr
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &nt_world_bl_hash,
+			.data = {
+				.ptr = (void *)nt_world_bl_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &nt_fw_config_hash,
+			.data = {
+				.ptr = (void *)nt_fw_config_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+static const auth_img_desc_t bl33_image = {
+	.img_id = BL33_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &non_trusted_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &nt_world_bl_hash
+			}
+		}
+	}
+};
+/* NT FW Config */
+static const auth_img_desc_t nt_fw_config = {
+	.img_id = NT_FW_CONFIG_ID,
+	.img_type = IMG_RAW,
+	.parent = &non_trusted_fw_content_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &nt_fw_config_hash
+			}
+		}
+	}
+};
+#else  /* IMAGE_BL2 */
+/*
+ * FWU auth descriptor.
+ */
+static const auth_img_desc_t fwu_cert = {
+	.img_id = FWU_CERT_ID,
+	.img_type = IMG_CERT,
+	.parent = NULL,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_SIG,
+			.param.sig = {
+				.pk = &subject_pk,
+				.sig = &sig,
+				.alg = &sig_alg,
+				.data = &raw_data
+			}
+		}
+	},
+	.authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) {
+		[0] = {
+			.type_desc = &scp_bl2u_hash,
+			.data = {
+				.ptr = (void *)scp_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[1] = {
+			.type_desc = &bl2u_hash,
+			.data = {
+				.ptr = (void *)tb_fw_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		},
+		[2] = {
+			.type_desc = &ns_bl2u_hash,
+			.data = {
+				.ptr = (void *)nt_world_bl_hash_buf,
+				.len = (unsigned int)HASH_DER_LEN
+			}
+		}
+	}
+};
+/*
+ * SCP_BL2U
+ */
+static const auth_img_desc_t scp_bl2u_image = {
+	.img_id = SCP_BL2U_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &fwu_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &scp_bl2u_hash
+			}
+		}
+	}
+};
+/*
+ * BL2U
+ */
+static const auth_img_desc_t bl2u_image = {
+	.img_id = BL2U_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &fwu_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &bl2u_hash
+			}
+		}
+	}
+};
+/*
+ * NS_BL2U
+ */
+static const auth_img_desc_t ns_bl2u_image = {
+	.img_id = NS_BL2U_IMAGE_ID,
+	.img_type = IMG_RAW,
+	.parent = &fwu_cert,
+	.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {
+		[0] = {
+			.type = AUTH_METHOD_HASH,
+			.param.hash = {
+				.data = &raw_data,
+				.hash = &ns_bl2u_hash
+				}
+			}
+		}
+	};
+#endif /* IMAGE_BL2 */
+/*
+ * TBBR Chain of trust definition
+ */
+
+#ifdef IMAGE_BL1
+static const auth_img_desc_t * const cot_desc[] = {
+	[TRUSTED_BOOT_FW_CERT_ID]		=	&trusted_boot_fw_cert,
+	[BL2_IMAGE_ID]				=	&bl2_image,
+	[HW_CONFIG_ID]				=	&hw_config,
+	[TB_FW_CONFIG_ID]			=	&tb_fw_config,
+	[FWU_CERT_ID]				=	&fwu_cert,
+	[SCP_BL2U_IMAGE_ID]			=	&scp_bl2u_image,
+	[BL2U_IMAGE_ID]				=	&bl2u_image,
+	[NS_BL2U_IMAGE_ID]			=	&ns_bl2u_image
+};
+#else /* IMAGE_BL2 */
+static const auth_img_desc_t * const cot_desc[] = {
+	[TRUSTED_BOOT_FW_CERT_ID]		=	&trusted_boot_fw_cert,
+	[HW_CONFIG_ID]				=	&hw_config,
+	[TRUSTED_KEY_CERT_ID]			=	&trusted_key_cert,
+	[SCP_FW_KEY_CERT_ID]			=	&scp_fw_key_cert,
+	[SCP_FW_CONTENT_CERT_ID]		=	&scp_fw_content_cert,
+	[SCP_BL2_IMAGE_ID]			=	&scp_bl2_image,
+	[SOC_FW_KEY_CERT_ID]			=	&soc_fw_key_cert,
+	[SOC_FW_CONTENT_CERT_ID]		=	&soc_fw_content_cert,
+	[BL31_IMAGE_ID]				=	&bl31_image,
+	[SOC_FW_CONFIG_ID]			=	&soc_fw_config,
+	[TRUSTED_OS_FW_KEY_CERT_ID]		=	&trusted_os_fw_key_cert,
+	[TRUSTED_OS_FW_CONTENT_CERT_ID]		=	&trusted_os_fw_content_cert,
+	[BL32_IMAGE_ID]				=	&bl32_image,
+	[BL32_EXTRA1_IMAGE_ID]			=	&bl32_extra1_image,
+	[BL32_EXTRA2_IMAGE_ID]			=	&bl32_extra2_image,
+	[TOS_FW_CONFIG_ID]			=	&tos_fw_config,
+	[NON_TRUSTED_FW_KEY_CERT_ID]		=	&non_trusted_fw_key_cert,
+	[NON_TRUSTED_FW_CONTENT_CERT_ID]	=	&non_trusted_fw_content_cert,
+	[BL33_IMAGE_ID]				=	&bl33_image,
+	[NT_FW_CONFIG_ID]			=	&nt_fw_config,
+};
+#endif
+
+/* Register the CoT in the authentication module */
+REGISTER_COT(cot_desc);
diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S
new file mode 100644
index 0000000..ecd0c47
--- /dev/null
+++ b/drivers/cadence/uart/aarch64/cdns_console.S
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/cadence/cdns_uart.h>
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_cdns_core_init
+	.globl console_cdns_core_putc
+	.globl console_cdns_core_getc
+	.globl console_cdns_core_flush
+
+	.globl  console_cdns_putc
+	.globl  console_cdns_getc
+	.globl  console_cdns_flush
+
+	/* -----------------------------------------------
+	 * int console_cdns_core_init(uintptr_t base_addr)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * We assume that the bootloader already set up
+	 * the HW (baud, ...) and only enable the trans-
+	 * mitter and receiver here.
+	 * In: x0 - console base address
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : x1, x2, x3
+	 * -----------------------------------------------
+	 */
+func console_cdns_core_init
+	/* Check the input base address */
+	cbz	x0, core_init_fail
+
+	/* RX/TX enabled & reset */
+	mov	w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST)
+	str	w3, [x0, #R_UART_CR]
+
+	mov	w0, #1
+	ret
+core_init_fail:
+	mov	w0, wzr
+	ret
+endfunc console_cdns_core_init
+
+	.globl console_cdns_register
+
+	/* -----------------------------------------------
+	 * int console_cdns_register(uintptr_t baseaddr,
+	 *     uint32_t clock, uint32_t baud,
+	 *     console_cdns_t *console);
+	 * Function to initialize and register a new CDNS
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_16550_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_cdns_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_CDNS_BASE]
+
+	bl	console_cdns_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register cdns putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_cdns_register
+
+	/* --------------------------------------------------------
+	 * int console_cdns_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_cdns_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+1:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #R_UART_SR]
+	tbnz	w2, #UART_SR_INTR_TFUL_BIT, 1b
+	mov	w2, #0xD
+	str	w2, [x1, #R_UART_TX]
+2:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #R_UART_SR]
+	tbnz	w2, #UART_SR_INTR_TFUL_BIT, 2b
+	str	w0, [x1, #R_UART_TX]
+	ret
+endfunc console_cdns_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_cdns_putc(int c, console_cdns_t *cdns)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_cdns_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_CDNS_BASE]
+	b	console_cdns_core_putc
+endfunc console_cdns_putc
+
+	/* ---------------------------------------------
+	 * int console_cdns_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - console base address
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_cdns_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Check if the receive FIFO is empty */
+	ldr	w1, [x0, #R_UART_SR]
+	tbnz	w1, #UART_SR_INTR_REMPTY_BIT, no_char
+	ldr	w1, [x0, #R_UART_RX]
+	mov	w0, w1
+	ret
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+endfunc console_cdns_core_getc
+
+	/* ---------------------------------------------
+	 * int console_cdns_getc(console_cdns_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - pointer to console_t structure
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_cdns_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_CDNS_BASE]
+	b	console_cdns_core_getc
+endfunc console_cdns_getc
+
+	/* ---------------------------------------------
+	 * int console_cdns_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_cdns_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	/* Placeholder */
+	mov	w0, #0
+	ret
+endfunc console_cdns_core_flush
+
+	/* ---------------------------------------------
+	 * int console_cdns_flush(console_pl011_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_cdns_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_CDNS_BASE]
+	b	console_cdns_core_flush
+endfunc console_cdns_flush
diff --git a/drivers/cfi/v2m/v2m_flash.c b/drivers/cfi/v2m/v2m_flash.c
new file mode 100644
index 0000000..aadafbc
--- /dev/null
+++ b/drivers/cfi/v2m/v2m_flash.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <drivers/cfi/v2m_flash.h>
+#include <lib/mmio.h>
+
+/*
+ * This file supplies a low level interface to the vexpress NOR flash
+ * memory of juno and fvp. This memory is organized as an interleaved
+ * memory of two chips with a 16 bit word. It means that every 32 bit
+ * access is going to access to two different chips. This is very
+ * important when we send commands or read status of the chips.
+ */
+
+/*
+ * DWS ready poll retries. The number of retries in this driver have been
+ * obtained empirically from Juno. FVP implements a zero wait state NOR flash
+ * model
+ */
+#define DWS_WORD_PROGRAM_RETRIES	1000
+#define DWS_WORD_ERASE_RETRIES		3000000
+#define DWS_WORD_LOCK_RETRIES		1000
+
+/* Helper macro to detect end of command */
+#define NOR_CMD_END (NOR_DWS | NOR_DWS << 16l)
+
+/* Helper macros to access two flash banks in parallel */
+#define NOR_2X16(d)			((d << 16) | (d & 0xffff))
+
+static unsigned int nor_status(uintptr_t base_addr)
+{
+	unsigned long status;
+
+	nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
+	status = mmio_read_32(base_addr);
+	status |= status >> 16; /* merge status from both flash banks */
+
+	return status & 0xFFFF;
+}
+
+/*
+ * Poll Write State Machine.
+ * Return values:
+ *    0      = WSM ready
+ *    -EBUSY = WSM busy after the number of retries
+ */
+static int nor_poll_dws(uintptr_t base_addr, unsigned long int retries)
+{
+	unsigned long status;
+
+	do {
+		nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
+		status = mmio_read_32(base_addr);
+		if ((status & NOR_CMD_END) == NOR_CMD_END)
+			return 0;
+	} while (retries-- > 0);
+
+	return -EBUSY;
+}
+
+/*
+ * Return values:
+ *    0      = success
+ *    -EPERM = Device protected or Block locked
+ *    -EIO   = General I/O error
+ */
+static int nor_full_status_check(uintptr_t base_addr)
+{
+	unsigned long status;
+
+	/* Full status check */
+	status = nor_status(base_addr);
+
+	if (status & (NOR_PS | NOR_BLS | NOR_ESS | NOR_PSS))
+		return -EPERM;
+	if (status & (NOR_VPPS | NOR_ES))
+		return -EIO;
+	return 0;
+}
+
+void nor_send_cmd(uintptr_t base_addr, unsigned long cmd)
+{
+	mmio_write_32(base_addr, NOR_2X16(cmd));
+}
+
+/*
+ * This function programs a word in the flash. Be aware that it only
+ * can reset bits that were previously set. It cannot set bits that
+ * were previously reset. The resulting bits = old_bits & new bits.
+ * Return values:
+ *  0 = success
+ *  otherwise it returns a negative value
+ */
+int nor_word_program(uintptr_t base_addr, unsigned long data)
+{
+	uint32_t status;
+	int ret;
+
+	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
+
+	/* Set the device in write word mode */
+	nor_send_cmd(base_addr, NOR_CMD_WORD_PROGRAM);
+	mmio_write_32(base_addr, data);
+
+	ret = nor_poll_dws(base_addr, DWS_WORD_PROGRAM_RETRIES);
+	if (ret == 0) {
+		/* Full status check */
+		nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG);
+		status = mmio_read_32(base_addr);
+
+		if (status & (NOR_PS | NOR_BLS)) {
+			nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
+			ret = -EPERM;
+		}
+	}
+
+	if (ret == 0)
+		ret = nor_full_status_check(base_addr);
+	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
+
+	return ret;
+}
+
+/*
+ * Erase a full 256K block
+ * Return values:
+ *  0 = success
+ *  otherwise it returns a negative value
+ */
+int nor_erase(uintptr_t base_addr)
+{
+	int ret;
+
+	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
+
+	nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE);
+	nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE_ACK);
+
+	ret = nor_poll_dws(base_addr, DWS_WORD_ERASE_RETRIES);
+	if (ret == 0)
+		ret = nor_full_status_check(base_addr);
+	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
+
+	return ret;
+}
+
+/*
+ * Lock a full 256 block
+ * Return values:
+ *  0 = success
+ *  otherwise it returns a negative value
+ */
+int nor_lock(uintptr_t base_addr)
+{
+	int ret;
+
+	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
+
+	nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK);
+	nor_send_cmd(base_addr, NOR_LOCK_BLOCK);
+
+	ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES);
+	if (ret == 0)
+		ret = nor_full_status_check(base_addr);
+	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
+
+	return ret;
+}
+
+/*
+ * unlock a full 256 block
+ * Return values:
+ *  0 = success
+ *  otherwise it returns a negative value
+ */
+int nor_unlock(uintptr_t base_addr)
+{
+	int ret;
+
+	nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG);
+
+	nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK);
+	nor_send_cmd(base_addr, NOR_UNLOCK_BLOCK);
+
+	ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES);
+	if (ret == 0)
+		ret = nor_full_status_check(base_addr);
+	nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY);
+
+	return ret;
+}
diff --git a/drivers/console/aarch32/skeleton_console.S b/drivers/console/aarch32/skeleton_console.S
new file mode 100644
index 0000000..45ad139
--- /dev/null
+++ b/drivers/console/aarch32/skeleton_console.S
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <console_macros.S>
+
+	/*
+	 * This file contains a skeleton console driver that can be used as a
+	 * basis for a real console driver. Console drivers in Trusted Firmware
+	 * can be instantiated multiple times. Each instance is described by a
+	 * separate console_t structure which must be registered with the common
+	 * console framework via console_register(). Console drivers should
+	 * define a console_xxx_register() function that initializes a new
+	 * console_t structure passed in from the caller and registers it after
+	 * initializing the console hardware. Drivers may define their own
+	 * structures extending console_t to store private driver information.
+	 * Console drivers *MUST* ensure that the console callbacks they
+	 * implement only change registers allowed in the clobber lists defined
+	 * in this file. (Note that in addition to the explicit clobber lists,
+	 * any function may always clobber the intra-procedure-call register
+	 * r12, but may never depend on it retaining its value across any
+	 * function call.)
+	 */
+
+	.globl	console_xxx_register
+	.globl	console_xxx_putc
+	.globl	console_xxx_getc
+	.globl	console_xxx_flush
+
+	/* -----------------------------------------------
+	 * int console_xxx_register(console_xxx_t *console,
+	 * 	...additional parameters as desired...)
+	 * Function to initialize and register the console.
+	 * The caller needs to pass an empty console_xxx_t
+	 * structure in which *MUST* be allocated in
+	 * persistent memory (e.g. a global or static local
+	 * variable, *NOT* on the stack).
+	 * In : r0 - pointer to empty console_t structure
+	 *      r1 through r7: additional parameters as desired
+	 * Out: r0 - 1 on success, 0 on error
+	 * Clobber list : r0 - r7
+	 * -----------------------------------------------
+	 */
+func console_xxx_register
+	/*
+	 * Store parameters (e.g. hardware base address) in driver-specific
+	 * console_xxx_t structure field if they will need to be retrieved
+	 * by later console callback (e.g. putc).
+	 * Example:
+	 */
+	str	r1, [r0, #CONSOLE_T_XXX_BASE]
+	str	r2, [r0, #CONSOLE_T_XXX_SOME_OTHER_VALUE]
+
+	/*
+	 * Initialize console hardware, using r1 - r7 parameters as needed.
+	 * Keep console_t pointer in r0 for later.
+	 */
+
+	/*
+	 * Macro to finish up registration and return (needs valid r0 + lr).
+	 * If any of the argument is unspecified, then the corresponding
+	 * entry in console_t is set to 0.
+	 */
+	finish_console_register xxx putc=1, getc=1, flush=1
+
+	/* Jump here if hardware init fails or parameters are invalid. */
+register_fail:
+	mov	r0, #0
+	bx	lr
+endfunc console_xxx_register
+
+	/* --------------------------------------------------------
+	 * int console_xxx_putc(int c, console_xxx_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : r0 - character to be printed
+	 *      r1 - pointer to console_t struct
+	 * Out: r0 - printed character on success, < 0 on error.
+	 * Clobber list : r0, r1, r2
+	 * --------------------------------------------------------
+	 */
+func console_xxx_putc
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by r1.
+	 * Example:
+	 */
+	ldr	r1, [r1, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Write r0 to hardware.
+	 */
+
+	bx	lr
+
+	/* Jump here if output fails for any reason. */
+putc_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_xxx_putc
+
+	/* ---------------------------------------------
+	 * int console_xxx_getc(console_xxx_t *console)
+	 * Function to get a character from the console.
+	 * Even though console_getc() is blocking, this
+	 * callback has to be non-blocking and always
+	 * return immediately to allow polling multiple
+	 * drivers concurrently.
+	 * Returns the character grabbed on success,
+	 * ERROR_NO_PENDING_CHAR if no character was
+	 * available at this time, or any value
+	 * between -2 and -127 if there was an error.
+	 * In : r0 - pointer to console_t struct
+	 * Out: r0 - character on success,
+	 *           ERROR_NO_PENDING_CHAR if no char,
+	 *           < -1 on error
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_xxx_getc
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by r0.
+	 * Example:
+	 */
+	ldr	r1, [r0, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Try to read character into r0 from hardware.
+	 */
+
+	bx	lr
+
+	/* Jump here if there is no character available at this time. */
+getc_no_char:
+	mov	r0, #ERROR_NO_PENDING_CHAR
+	bx	lr
+
+	/* Jump here if there was any hardware error. */
+getc_error:
+	mov	r0, #-2		/* may pick error codes between -2 and -127 */
+	bx	lr
+endfunc console_xxx_getc
+
+	/* ---------------------------------------------
+	 * int console_xxx_flush(console_xxx_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : r0 - pointer to console_xxx_t struct
+	 * Out: r0 - 0 on success, < 0 on error
+	 * Clobber list : r0, r1, r2, r3, r4, r5
+	 * ---------------------------------------------
+	 */
+func console_xxx_flush
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by r0.
+	 * Example:
+	 */
+	ldr	r1, [r0, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Flush all remaining output from hardware FIFOs. Do not return until
+	 * all data has been flushed or there was an unrecoverable error.
+	 */
+
+	mov	r0, #0
+	bx	lr
+
+	/* Jump here if an unrecoverable error has been encountered. */
+flush_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_xxx_flush
diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S
new file mode 100644
index 0000000..957ed83
--- /dev/null
+++ b/drivers/console/aarch64/skeleton_console.S
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <console_macros.S>
+
+	/*
+	 * This file contains a skeleton console driver that can be used as a
+	 * basis for a real console driver. Console drivers in Trusted Firmware
+	 * can be instantiated multiple times. Each instance is described by a
+	 * separate console_t structure which must be registered with the common
+	 * console framework via console_register(). Console drivers should
+	 * define a console_xxx_register() function that initializes a new
+	 * console_t structure passed in from the caller and registers it after
+	 * initializing the console hardware. Drivers may define their own
+	 * structures extending console_t to store private driver information.
+	 * Console drivers *MUST* ensure that the console callbacks they
+	 * implement only change registers allowed in the clobber lists defined
+	 * in this file. (Note that in addition to the explicit clobber lists,
+	 * any function may always clobber the intra-procedure-call registers
+	 * X16 and X17, but may never depend on them retaining their values
+	 * across any function call.)
+	 */
+
+	.globl	console_xxx_register
+	.globl	console_xxx_putc
+	.globl	console_xxx_getc
+	.globl	console_xxx_flush
+
+	/* -----------------------------------------------
+	 * int console_xxx_register(console_xxx_t *console,
+	 * 	...additional parameters as desired...)
+	 * Function to initialize and register the console.
+	 * The caller needs to pass an empty console_xxx_t
+	 * structure in which *MUST* be allocated in
+	 * persistent memory (e.g. a global or static local
+	 * variable, *NOT* on the stack).
+	 * In : x0 - pointer to empty console_t structure
+	 *      x1 through x7: additional parameters as desired
+	 * Out: x0 - 1 on success, 0 on error
+	 * Clobber list : x0 - x7
+	 * -----------------------------------------------
+	 */
+func console_xxx_register
+	/*
+	 * Store parameters (e.g. hardware base address) in driver-specific
+	 * console_xxx_t structure field if they will need to be retrieved
+	 * by later console callback (e.g. putc).
+	 * Example:
+	 */
+	str	x1, [x0, #CONSOLE_T_XXX_BASE]
+	str	x2, [x0, #CONSOLE_T_XXX_SOME_OTHER_VALUE]
+
+	/*
+	 * Initialize console hardware, using x1 - x7 parameters as needed.
+	 * Keep console_t pointer in x0 for later.
+	 */
+
+	/*
+	 * Macro to finish up registration and return (needs valid x0 + x30).
+	 * If any of the argument is unspecified, then the corresponding
+	 * entry in console_t is set to 0.
+	 */
+	finish_console_register xxx putc=1, getc=1, flush=1
+
+	/* Jump here if hardware init fails or parameters are invalid. */
+register_fail:
+	mov	w0, #0
+	ret
+endfunc console_xxx_register
+
+	/* --------------------------------------------------------
+	 * int console_xxx_putc(int c, console_xxx_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t struct
+	 * Out: w0 - printed character on success, < 0 on error.
+	 * Clobber list : x0, x1, x2
+	 * --------------------------------------------------------
+	 */
+func console_xxx_putc
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by x1.
+	 * Example:
+	 */
+	ldr	x1, [x1, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Write w0 to hardware.
+	 */
+
+	ret
+
+	/* Jump here if output fails for any reason. */
+putc_error:
+	mov	w0, #-1
+	ret
+endfunc console_xxx_putc
+
+	/* ---------------------------------------------
+	 * int console_xxx_getc(console_xxx_t *console)
+	 * Function to get a character from the console.
+	 * Even though console_getc() is blocking, this
+	 * callback has to be non-blocking and always
+	 * return immediately to allow polling multiple
+	 * drivers concurrently.
+	 * Returns the character grabbed on success,
+	 * ERROR_NO_PENDING_CHAR if no character was
+	 * available at this time, or any value
+	 * between -2 and -127 if there was an error.
+	 * In : x0 - pointer to console_t struct
+	 * Out: w0 - character on success,
+	 *           ERROR_NO_PENDING_CHAR if no char,
+	 *           < -1 on error
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_xxx_getc
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by x0.
+	 * Example:
+	 */
+	ldr	x1, [x0, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Try to read character into w0 from hardware.
+	 */
+
+	ret
+
+	/* Jump here if there is no character available at this time. */
+getc_no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+
+	/* Jump here if there was any hardware error. */
+getc_error:
+	mov	w0, #-2		/* may pick error codes between -2 and -127 */
+	ret
+endfunc console_xxx_getc
+
+	/* ---------------------------------------------
+	 * int console_xxx_flush(console_xxx_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_xxx_t struct
+	 * Out: w0 - 0 on success, < 0 on error
+	 * Clobber list : x0, x1, x2, x3, x4, x5
+	 * ---------------------------------------------
+	 */
+func console_xxx_flush
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by x0.
+	 * Example:
+	 */
+	ldr	x1, [x0, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Flush all remaining output from hardware FIFOs. Do not return until
+	 * all data has been flushed or there was an unrecoverable error.
+	 */
+
+	mov	w0, #0
+	ret
+
+	/* Jump here if an unrecoverable error has been encountered. */
+flush_error:
+	mov	w0, #-1
+	ret
+endfunc console_xxx_flush
diff --git a/drivers/console/multi_console.c b/drivers/console/multi_console.c
new file mode 100644
index 0000000..d9eba7f
--- /dev/null
+++ b/drivers/console/multi_console.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/console.h>
+
+console_t *console_list;
+uint8_t console_state = CONSOLE_FLAG_BOOT;
+
+IMPORT_SYM(console_t *, __STACKS_START__, stacks_start)
+IMPORT_SYM(console_t *, __STACKS_END__, stacks_end)
+
+int console_register(console_t *console)
+{
+	/* Assert that the struct is not on the stack (common mistake). */
+	assert((console < stacks_start) || (console >= stacks_end));
+
+	/* Check that we won't make a circle in the list. */
+	if (console_is_registered(console) == 1)
+		return 1;
+
+	console->next = console_list;
+	console_list = console;
+
+	/* Return 1 for convenient tail-calling from console_xxx_register(). */
+	return 1;
+}
+
+console_t *console_unregister(console_t *to_be_deleted)
+{
+	console_t **ptr;
+
+	assert(to_be_deleted != NULL);
+
+	for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next)
+		if (*ptr == to_be_deleted) {
+			*ptr = (*ptr)->next;
+			return to_be_deleted;
+		}
+
+	return NULL;
+}
+
+int console_is_registered(console_t *to_find)
+{
+	console_t *console;
+
+	assert(to_find != NULL);
+
+	for (console = console_list; console != NULL; console = console->next)
+		if (console == to_find)
+			return 1;
+
+	return 0;
+}
+
+void console_switch_state(unsigned int new_state)
+{
+	console_state = new_state;
+}
+
+void console_set_scope(console_t *console, unsigned int scope)
+{
+	assert(console != NULL);
+
+	console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope;
+}
+
+int console_putc(int c)
+{
+	int err = ERROR_NO_VALID_CONSOLE;
+	console_t *console;
+
+	for (console = console_list; console != NULL; console = console->next)
+		if ((console->flags & console_state) && console->putc) {
+			int ret = console->putc(c, console);
+			if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
+				err = ret;
+		}
+
+	return err;
+}
+
+int console_getc(void)
+{
+	int err = ERROR_NO_VALID_CONSOLE;
+	console_t *console;
+
+	do {	/* Keep polling while at least one console works correctly. */
+		for (console = console_list; console != NULL;
+		     console = console->next)
+			if ((console->flags & console_state) && console->getc) {
+				int ret = console->getc(console);
+				if (ret >= 0)
+					return ret;
+				if (err != ERROR_NO_PENDING_CHAR)
+					err = ret;
+			}
+	} while (err == ERROR_NO_PENDING_CHAR);
+
+	return err;
+}
+
+int console_flush(void)
+{
+	int err = ERROR_NO_VALID_CONSOLE;
+	console_t *console;
+
+	for (console = console_list; console != NULL; console = console->next)
+		if ((console->flags & console_state) && console->flush) {
+			int ret = console->flush(console);
+			if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
+				err = ret;
+		}
+
+	return err;
+}
diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
new file mode 100644
index 0000000..fd04c2e
--- /dev/null
+++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/coreboot/cbmem_console.h>
+
+/*
+ * This driver implements access to coreboot's in-memory console
+ * (CBMEM console). For the original implementation, see
+ * <coreboot>/src/lib/cbmem_console.c.
+ */
+
+	.globl console_cbmc_register
+	.globl console_cbmc_putc
+	.globl console_cbmc_flush
+
+	/* -----------------------------------------------
+	 * int console_cbmc_register(uintptr_t base,
+	 *                           console_cbmc_t *console);
+	 * Registers a new CBMEM console instance. Reads
+	 * the size field from the buffer header structure
+	 * and stores it in our console_cbmc_t struct, so
+	 * that we keep the size in secure memory where we
+	 * can trust it. A malicious EL1 could manipulate
+	 * the console buffer (including the header), so we
+	 * must not trust its contents after boot.
+	 * In:  x0 - CBMEM console base address
+	 *      x1 - pointer to empty console_cbmc_t struct
+	 * Out: x0 - 1 to indicate success
+	 * Clobber list: x0, x1, x2, x7
+	 * -----------------------------------------------
+	 */
+func console_cbmc_register
+	str	x0, [x1, #CONSOLE_T_CBMC_BASE]
+	ldr	w2, [x0]
+	str	w2, [x1, #CONSOLE_T_CBMC_SIZE]
+	mov	x0, x1
+	finish_console_register cbmc putc=1, flush=1
+endfunc console_cbmc_register
+
+	/* -----------------------------------------------
+	 * int console_cbmc_puts(int c, console_cbmc_t *console)
+	 * Writes a character to the CBMEM console buffer,
+	 * including overflow handling of the cursor field.
+	 * The character must be preserved in x0.
+	 * In: x0 - character to be stored
+	 *     x1 - pointer to console_cbmc_t struct
+	 * Clobber list: x1, x2, x16, x17
+	 * -----------------------------------------------
+	 */
+func console_cbmc_putc
+	ldr	w2, [x1, #CONSOLE_T_CBMC_SIZE]
+	ldr	x1, [x1, #CONSOLE_T_CBMC_BASE]
+	add	x1, x1, #8		/* keep address of body in x1 */
+
+	ldr	w16, [x1, #-4]		/* load cursor (one u32 before body) */
+	and	w17, w16, #0xf0000000	/* keep flags part in w17 */
+	and	w16, w16, #0x0fffffff	/* keep actual cursor part in w16 */
+
+	cmp	w16, w2			/* sanity check that cursor < size */
+	b.lo	putc_within_bounds
+	mov	w0, #-1			/* cursor >= size must be malicious */
+	ret				/* so return error, don't write char */
+
+putc_within_bounds:
+	strb	w0, [x1, w16, uxtw]	/* body[cursor] = character */
+	add	w16, w16, #1		/* cursor++ */
+	cmp	w16, w2			/* if cursor < size... */
+	b.lo	putc_write_back		/* ...skip overflow handling */
+
+	mov	w16, #0			/* on overflow, set cursor back to 0 */
+	orr	w17, w17, #(1 << 31)	/* and set overflow flag */
+
+putc_write_back:
+	orr	w16, w16, w17		/* merge cursor and flags back */
+	str	w16, [x1, #-4]		/* write back cursor to memory */
+	ret
+endfunc	console_cbmc_putc
+
+	/* -----------------------------------------------
+	 * int console_cbmc_flush(console_cbmc_t *console)
+	 * Flushes the CBMEM console by flushing the
+	 * console buffer from the CPU's data cache.
+	 * In:  x0 - pointer to console_cbmc_t struct
+	 * Out: x0 - 0 for success
+	 * Clobber list: x0, x1, x2, x3, x5
+	 * -----------------------------------------------
+	 */
+func console_cbmc_flush
+	mov	x5, x30
+	ldr	x1, [x0, #CONSOLE_T_CBMC_SIZE]
+	ldr	x0, [x0, #CONSOLE_T_CBMC_BASE]
+	add	x1, x1, #8		/* add size of console header */
+	bl	clean_dcache_range	/* (clobbers x2 and x3) */
+	mov	x0, #0
+	ret	x5
+endfunc console_cbmc_flush
diff --git a/drivers/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c
new file mode 100644
index 0000000..8c2996e
--- /dev/null
+++ b/drivers/delay_timer/delay_timer.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/utils_def.h>
+
+/***********************************************************
+ * The delay timer implementation
+ ***********************************************************/
+static const timer_ops_t *timer_ops;
+
+/***********************************************************
+ * Delay for the given number of microseconds. The driver must
+ * be initialized before calling this function.
+ ***********************************************************/
+void udelay(uint32_t usec)
+{
+	assert((timer_ops != NULL) &&
+		(timer_ops->clk_mult != 0U) &&
+		(timer_ops->clk_div != 0U) &&
+		(timer_ops->get_timer_value != NULL));
+
+	uint32_t start, delta, total_delta;
+
+	assert(usec < (UINT32_MAX / timer_ops->clk_div));
+
+	start = timer_ops->get_timer_value();
+
+	/* Add an extra tick to avoid delaying less than requested. */
+	total_delta =
+		div_round_up(usec * timer_ops->clk_div,
+						timer_ops->clk_mult) + 1U;
+
+	do {
+		/*
+		 * If the timer value wraps around, the subtraction will
+		 * overflow and it will still give the correct result.
+		 */
+		delta = start - timer_ops->get_timer_value(); /* Decreasing counter */
+
+	} while (delta < total_delta);
+}
+
+/***********************************************************
+ * Delay for the given number of milliseconds. The driver must
+ * be initialized before calling this function.
+ ***********************************************************/
+void mdelay(uint32_t msec)
+{
+	udelay(msec * 1000U);
+}
+
+/***********************************************************
+ * Initialize the timer. The fields in the provided timer
+ * ops pointer must be valid.
+ ***********************************************************/
+void timer_init(const timer_ops_t *ops_ptr)
+{
+	assert((ops_ptr != NULL)  &&
+		(ops_ptr->clk_mult != 0U) &&
+		(ops_ptr->clk_div != 0U) &&
+		(ops_ptr->get_timer_value != NULL));
+
+	timer_ops = ops_ptr;
+}
diff --git a/drivers/delay_timer/generic_delay_timer.c b/drivers/delay_timer/generic_delay_timer.c
new file mode 100644
index 0000000..3d0a11f
--- /dev/null
+++ b/drivers/delay_timer/generic_delay_timer.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <plat/common/platform.h>
+
+/* Ticks elapsed in one second by a signal of 1 MHz */
+#define MHZ_TICKS_PER_SEC 1000000
+
+static timer_ops_t ops;
+
+static uint32_t get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter. The value is
+	 * clipped from 64 to 32 bits.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+void generic_delay_timer_init_args(uint32_t mult, uint32_t div)
+{
+	ops.get_timer_value	= get_timer_value;
+	ops.clk_mult		= mult;
+	ops.clk_div		= div;
+
+	timer_init(&ops);
+
+	VERBOSE("Generic delay timer configured with mult=%u and div=%u\n",
+		mult, div);
+}
+
+void generic_delay_timer_init(void)
+{
+	assert(is_armv7_gentimer_present());
+
+	/* Value in ticks */
+	unsigned int mult = MHZ_TICKS_PER_SEC;
+
+	/* Value in ticks per second (Hz) */
+	unsigned int div  = plat_get_syscnt_freq2();
+
+	/* Reduce multiplier and divider by dividing them repeatedly by 10 */
+	while (((mult % 10U) == 0U) && ((div % 10U) == 0U)) {
+		mult /= 10U;
+		div /= 10U;
+	}
+
+	generic_delay_timer_init_args(mult, div);
+}
+
diff --git a/drivers/gpio/gpio.c b/drivers/gpio/gpio.c
new file mode 100644
index 0000000..76612b2
--- /dev/null
+++ b/drivers/gpio/gpio.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * GPIO -- General Purpose Input/Output
+ *
+ * Defines a simple and generic interface to access GPIO device.
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <drivers/gpio.h>
+
+/*
+ * The gpio implementation
+ */
+static const gpio_ops_t *ops;
+
+int gpio_get_direction(int gpio)
+{
+	assert(ops);
+	assert(ops->get_direction != 0);
+	assert(gpio >= 0);
+
+	return ops->get_direction(gpio);
+}
+
+void gpio_set_direction(int gpio, int direction)
+{
+	assert(ops);
+	assert(ops->set_direction != 0);
+	assert((direction == GPIO_DIR_OUT) || (direction == GPIO_DIR_IN));
+	assert(gpio >= 0);
+
+	ops->set_direction(gpio, direction);
+}
+
+int gpio_get_value(int gpio)
+{
+	assert(ops);
+	assert(ops->get_value != 0);
+	assert(gpio >= 0);
+
+	return ops->get_value(gpio);
+}
+
+void gpio_set_value(int gpio, int value)
+{
+	assert(ops);
+	assert(ops->set_value != 0);
+	assert((value == GPIO_LEVEL_LOW) || (value == GPIO_LEVEL_HIGH));
+	assert(gpio >= 0);
+
+	ops->set_value(gpio, value);
+}
+
+void gpio_set_pull(int gpio, int pull)
+{
+	assert(ops);
+	assert(ops->set_pull != 0);
+	assert((pull == GPIO_PULL_NONE) || (pull == GPIO_PULL_UP) ||
+	       (pull == GPIO_PULL_DOWN));
+	assert(gpio >= 0);
+
+	ops->set_pull(gpio, pull);
+}
+
+int gpio_get_pull(int gpio)
+{
+	assert(ops);
+	assert(ops->get_pull != 0);
+	assert(gpio >= 0);
+
+	return ops->get_pull(gpio);
+}
+
+/*
+ * Initialize the gpio. The fields in the provided gpio
+ * ops pointer must be valid.
+ */
+void gpio_init(const gpio_ops_t *ops_ptr)
+{
+	assert(ops_ptr != 0  &&
+	       (ops_ptr->get_direction != 0) &&
+	       (ops_ptr->set_direction != 0) &&
+	       (ops_ptr->get_value != 0) &&
+	       (ops_ptr->set_value != 0));
+
+	ops = ops_ptr;
+}
diff --git a/drivers/imx/timer/imx_gpt.c b/drivers/imx/timer/imx_gpt.c
new file mode 100644
index 0000000..464efe9
--- /dev/null
+++ b/drivers/imx/timer/imx_gpt.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <imx_gpt.h>
+
+#define GPTCR_SWR		BIT(15)		/* Software reset */
+#define GPTCR_24MEN		BIT(10)		/* Enable 24MHz clock input */
+#define GPTCR_CLKSOURCE_OSC	(5 << 6)        /* Clock source OSC */
+#define GPTCR_CLKSOURCE_MASK	(0x7 << 6)
+#define GPTCR_TEN		1		/* Timer enable */
+
+#define GPTPR_PRESCL_24M_SHIFT 12
+
+#define SYS_COUNTER_FREQ_IN_MHZ 3
+
+#define GPTPR_TIMER_CTRL	(imx_base_addr + 0x000)
+#define GPTPR_TIMER_PRESCL	(imx_base_addr + 0x004)
+#define GPTPR_TIMER_CNTR	(imx_base_addr + 0x024)
+
+static uintptr_t imx_base_addr;
+
+uint32_t imx_get_timer_value(void)
+{
+	return ~mmio_read_32(GPTPR_TIMER_CNTR);
+}
+
+static const timer_ops_t imx_gpt_ops = {
+	.get_timer_value	= imx_get_timer_value,
+	.clk_mult		= 1,
+	.clk_div		= SYS_COUNTER_FREQ_IN_MHZ,
+};
+
+void imx_gpt_ops_init(uintptr_t base_addr)
+{
+	int val;
+
+	assert(base_addr != 0);
+
+	imx_base_addr = base_addr;
+
+	/* setup GP Timer */
+	mmio_write_32(GPTPR_TIMER_CTRL, GPTCR_SWR);
+	mmio_write_32(GPTPR_TIMER_CTRL, 0);
+
+	/* get 3MHz from 24MHz */
+	mmio_write_32(GPTPR_TIMER_PRESCL, (7 << GPTPR_PRESCL_24M_SHIFT));
+
+	val = mmio_read_32(GPTPR_TIMER_CTRL);
+	val &= ~GPTCR_CLKSOURCE_MASK;
+	val |= GPTCR_24MEN | GPTCR_CLKSOURCE_OSC | GPTCR_TEN;
+	mmio_write_32(GPTPR_TIMER_CTRL, val);
+
+	timer_init(&imx_gpt_ops);
+}
diff --git a/drivers/imx/timer/imx_gpt.h b/drivers/imx/timer/imx_gpt.h
new file mode 100644
index 0000000..2432633
--- /dev/null
+++ b/drivers/imx/timer/imx_gpt.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_GPT_H
+#define IMX_GPT_H
+
+#include <stdint.h>
+
+void imx_gpt_ops_init(uintptr_t reg_base);
+
+#endif /* IMX_GPT_H */
diff --git a/drivers/imx/uart/imx_crash_uart.S b/drivers/imx/uart/imx_crash_uart.S
new file mode 100644
index 0000000..aa987b3
--- /dev/null
+++ b/drivers/imx/uart/imx_crash_uart.S
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <imx_uart.h>
+#include <platform_def.h>
+
+	.globl	imx_crash_uart_init
+	.globl	imx_crash_uart_putc
+
+	/* -----------------------------------------------
+	 * int imx_crash_uart_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: r0 - console base address
+	 *     r1 - Uart clock in Hz
+	 *     r2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : r1, r2, r3, r4
+	 * -----------------------------------------------
+	 */
+func imx_crash_uart_init
+	/* Free up r1 as a scratch reg */
+	mov     r4, r0
+	mov     r0, r1
+
+	/* Reset UART via CR2 */
+	add     r1, r4, #IMX_UART_CR2_OFFSET
+	movs    r3, #0
+	str     r3, [r4, #IMX_UART_CR2_OFFSET]
+
+	/* Wait for reset complete */
+__wait_cr2_reset:
+	ldr     r3, [r1, #0]
+	ands    r3, #IMX_UART_CR2_SRST
+	beq     __wait_cr2_reset
+
+	/* Enable UART */
+	movs    r3, #IMX_UART_CR1_UARTEN
+	mov     r1, r2
+	str     r3, [r4, #IMX_UART_CR1_OFFSET]
+
+	/*
+	 * Ignore RTC/CTS - disable reset
+	 * Magic value #16423 =>
+	 * IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST
+	 */
+	movw    r3, #16423
+	str     r3, [r4, #IMX_UART_CR2_OFFSET]
+
+	/*
+	 * No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7)
+	 * Magic value => #132
+	 * IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL
+	 */
+	movs    r3, #132
+	str     r3, [r4, #IMX_UART_CR3_OFFSET]
+
+	/*
+	 * Set CTS FIFO trigger to 32 bytes bits 15:10
+	 * Magic value => #32768
+	 * FIFO trigger bitmask 100000
+	 * */
+	mov     r3, #32768
+	str     r3, [r4, #IMX_UART_CR4_OFFSET]
+
+	/*
+	 * TX/RX-thresh = 2 bytes, DCE (bit6 = 0), refclk @24MHz / 4
+	 * Magic value #2562
+	 * IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | IMX_UART_FCR_RFDIV2
+	 */
+	#ifdef IMX_UART_DTE
+	movw    r3, #2626
+	#else
+	movw    r3, #2562
+	#endif
+	str     r3, [r4, #IMX_UART_FCR_OFFSET]
+
+	/* This BIR should be set to 0x0F prior to writing the BMR */
+	movs    r3, #15
+	str     r3, [r4, #IMX_UART_BIR_OFFSET]
+
+	/* Hard-code to 115200 @ 24 MHz */
+	movs	r0, #104
+	str     r0, [r4, #IMX_UART_BMR_OFFSET]
+
+	/* Indicate success */
+	movs    r0, #1
+	bx	lr
+endfunc imx_crash_uart_init
+
+	/* --------------------------------------------------------
+	 * int imx_crash_uart_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : r0 - character to be printed
+	 *      r1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : r2
+	 * --------------------------------------------------------
+	 */
+func imx_crash_uart_putc
+	/* Output specified character to UART shift-register */
+	str	r0, [r1, #IMX_UART_TXD_OFFSET]
+
+        /* Wait for transmit IMX_UART_STAT2_OFFSET.IMX_UART_STAT2_TXDC == 1 */
+__putc_spin_ready:
+	ldr	r2, [r1, #IMX_UART_STAT2_OFFSET]
+	ands	r2, #IMX_UART_STAT2_TXDC
+	beq	__putc_spin_ready
+
+        /* Transmit complete do we need to fixup \n to \n\r */
+	cmp	r0, #10
+	beq	__putc_fixup_lf
+
+	/* No fixup necessary - exit here */
+	movs	r0, #0
+	bx	lr
+
+	/* Fixup \n to \n\r */
+__putc_fixup_lf:
+	movs	r0, #13
+	b	imx_crash_uart_putc
+endfunc imx_crash_uart_putc
diff --git a/drivers/imx/uart/imx_uart.c b/drivers/imx/uart/imx_uart.c
new file mode 100644
index 0000000..2c9652d
--- /dev/null
+++ b/drivers/imx/uart/imx_uart.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <imx_uart.h>
+
+/* TX/RX FIFO threshold */
+#define TX_RX_THRESH 2
+
+struct clk_div_factors {
+	uint32_t fcr_div;
+	uint32_t bmr_div;
+};
+
+static struct clk_div_factors clk_div[] = {
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV1,
+		.bmr_div = 1,
+	},
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV2,
+		.bmr_div = 2,
+	},
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV3,
+		.bmr_div = 3,
+	},
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV4,
+		.bmr_div = 4,
+	},
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV5,
+		.bmr_div = 5,
+	},
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV6,
+		.bmr_div = 6,
+	},
+	{
+		.fcr_div = IMX_UART_FCR_RFDIV7,
+		.bmr_div = 7,
+	},
+};
+
+static void write_reg(uintptr_t base, uint32_t offset, uint32_t val)
+{
+	mmio_write_32(base + offset, val);
+}
+
+static uint32_t read_reg(uintptr_t base, uint32_t offset)
+{
+	return mmio_read_32(base + offset);
+}
+
+int console_imx_uart_core_init(uintptr_t base_addr, unsigned int uart_clk,
+			       unsigned int baud_rate)
+{
+	uint32_t val;
+	uint8_t clk_idx = 1;
+
+	/* Reset UART */
+	write_reg(base_addr, IMX_UART_CR2_OFFSET, 0);
+	do {
+		val = read_reg(base_addr, IMX_UART_CR2_OFFSET);
+	} while (!(val & IMX_UART_CR2_SRST));
+
+	/* Enable UART */
+	write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN);
+
+	/* Ignore RTS, 8N1, enable tx/rx, disable reset */
+	val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN |
+	       IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST);
+	write_reg(base_addr, IMX_UART_CR2_OFFSET, val);
+
+	/* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */
+	val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL;
+	write_reg(base_addr, IMX_UART_CR3_OFFSET, val);
+
+	/* Set CTS FIFO trigger to 32 bytes bits 15:10 */
+	write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000);
+
+	/* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */
+	val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) |
+	      clk_div[clk_idx].fcr_div;
+	#ifdef IMX_UART_DTE
+		/* Set DTE (bit6 = 1) */
+		val |= IMX_UART_FCR_DCEDTE;
+	#endif
+	write_reg(base_addr, IMX_UART_FCR_OFFSET, val);
+
+	/*
+	 * The equation for BAUD rate calculation is
+	 * RefClk = Supplied clock / FCR_DIVx
+	 *
+	 * BAUD  =    Refclk
+	 *         ------------
+	 *       16 x (UBMR + 1/ UBIR + 1)
+	 *
+	 * We write 0x0f into UBIR to remove the 16 mult
+	 * BAUD  =    6000000
+	 *         ------------
+	 *       16 x (UBMR + 1/ 15 + 1)
+	 */
+
+	write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f);
+	val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1;
+	write_reg(base_addr, IMX_UART_BMR_OFFSET, val);
+
+	return 0;
+}
+
+/* --------------------------------------------------------
+ * int console_core_putc(int c, uintptr_t base_addr)
+ * Function to output a character over the console. It
+ * returns the character printed on success or -1 on error.
+ * In : r0 - character to be printed
+ *      r1 - console base address
+ * Out : return -1 on error else return character.
+ * Clobber list : r2
+ * --------------------------------------------------------
+ */
+int console_imx_uart_core_putc(int c, uintptr_t base_addr)
+{
+	uint32_t val;
+
+	if (c == '\n')
+		console_imx_uart_core_putc('\r', base_addr);
+
+	/* Write data */
+	write_reg(base_addr, IMX_UART_TXD_OFFSET, c);
+
+	/* Wait for transmit */
+	do {
+		val = read_reg(base_addr, IMX_UART_STAT2_OFFSET);
+	} while (!(val & IMX_UART_STAT2_TXDC));
+
+	return 0;
+}
+
+/*
+ * Function to get a character from the console.
+ * It returns the character grabbed on success
+ * or -1 on error.
+ * In : r0 - console base address
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+int console_imx_uart_core_getc(uintptr_t base_addr)
+{
+	uint32_t val;
+
+	val = read_reg(base_addr, IMX_UART_TS_OFFSET);
+	if (val & IMX_UART_TS_RXEMPTY)
+		return -1;
+
+	val = read_reg(base_addr, IMX_UART_RXD_OFFSET);
+	return (int)(val & 0x000000FF);
+}
+
+/*
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * In : r0 - console base address
+ * Out : return -1 on error else return 0.
+ * Clobber list : r0, r1
+ * ---------------------------------------------
+ */
+int console_imx_uart_core_flush(uintptr_t base_addr)
+{
+	return 0;
+}
+
diff --git a/drivers/imx/uart/imx_uart.h b/drivers/imx/uart/imx_uart.h
new file mode 100644
index 0000000..4f6d3de
--- /dev/null
+++ b/drivers/imx/uart/imx_uart.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_UART_H
+#define IMX_UART_H
+
+#include <drivers/console.h>
+
+#define IMX_UART_RXD_OFFSET	0x00
+#define IMX_UART_RXD_CHARRDY	BIT(15)
+#define IMX_UART_RXD_ERR	BIT(14)
+#define IMX_UART_RXD_OVERRUN	BIT(13)
+#define IMX_UART_RXD_FRMERR	BIT(12)
+#define IMX_UART_RXD_BRK	BIT(11)
+#define IMX_UART_RXD_PRERR	BIT(10)
+
+#define IMX_UART_TXD_OFFSET	0x40
+
+#define IMX_UART_CR1_OFFSET	0x80
+#define IMX_UART_CR1_ADEN	BIT(15)
+#define IMX_UART_CR1_ADBR	BIT(14)
+#define IMX_UART_CR1_TRDYEN	BIT(13)
+#define IMX_UART_CR1_IDEN	BIT(12)
+#define IMX_UART_CR1_RRDYEN	BIT(9)
+#define IMX_UART_CR1_RXDMAEN	BIT(8)
+#define IMX_UART_CR1_IREN	BIT(7)
+#define IMX_UART_CR1_TXMPTYEN	BIT(6)
+#define IMX_UART_CR1_RTSDEN	BIT(5)
+#define IMX_UART_CR1_SNDBRK	BIT(4)
+#define IMX_UART_CR1_TXDMAEN	BIT(3)
+#define IMX_UART_CR1_ATDMAEN	BIT(2)
+#define IMX_UART_CR1_DOZE	BIT(1)
+#define IMX_UART_CR1_UARTEN	BIT(0)
+
+#define IMX_UART_CR2_OFFSET	0x84
+#define IMX_UART_CR2_ESCI	BIT(15)
+#define IMX_UART_CR2_IRTS	BIT(14)
+#define IMX_UART_CR2_CTSC	BIT(13)
+#define IMX_UART_CR2_CTS	BIT(12)
+#define IMX_UART_CR2_ESCEN	BIT(11)
+#define IMX_UART_CR2_PREN	BIT(8)
+#define IMX_UART_CR2_PROE	BIT(7)
+#define IMX_UART_CR2_STPB	BIT(6)
+#define IMX_UART_CR2_WS		BIT(5)
+#define IMX_UART_CR2_RTSEN	BIT(4)
+#define IMX_UART_CR2_ATEN	BIT(3)
+#define IMX_UART_CR2_TXEN	BIT(2)
+#define IMX_UART_CR2_RXEN	BIT(1)
+#define IMX_UART_CR2_SRST	BIT(0)
+
+#define IMX_UART_CR3_OFFSET	0x88
+#define IMX_UART_CR3_DTREN	BIT(13)
+#define IMX_UART_CR3_PARERREN	BIT(12)
+#define IMX_UART_CR3_FARERREN	BIT(11)
+#define IMX_UART_CR3_DSD	BIT(10)
+#define IMX_UART_CR3_DCD	BIT(9)
+#define IMX_UART_CR3_RI		BIT(8)
+#define IMX_UART_CR3_ADNIMP	BIT(7)
+#define IMX_UART_CR3_RXDSEN	BIT(6)
+#define IMX_UART_CR3_AIRINTEN	BIT(5)
+#define IMX_UART_CR3_AWAKEN	BIT(4)
+#define IMX_UART_CR3_DTRDEN	BIT(3)
+#define IMX_UART_CR3_RXDMUXSEL	BIT(2)
+#define IMX_UART_CR3_INVT	BIT(1)
+#define IMX_UART_CR3_ACIEN	BIT(0)
+
+#define IMX_UART_CR4_OFFSET	0x8c
+#define IMX_UART_CR4_INVR	BIT(9)
+#define IMX_UART_CR4_ENIRI	BIT(8)
+#define IMX_UART_CR4_WKEN	BIT(7)
+#define IMX_UART_CR4_IDDMAEN	BIT(6)
+#define IMX_UART_CR4_IRSC	BIT(5)
+#define IMX_UART_CR4_LPBYP	BIT(4)
+#define IMX_UART_CR4_TCEN	BIT(3)
+#define IMX_UART_CR4_BKEN	BIT(2)
+#define IMX_UART_CR4_OREN	BIT(1)
+#define IMX_UART_CR4_DREN	BIT(0)
+
+#define IMX_UART_FCR_OFFSET	0x90
+#define IMX_UART_FCR_TXTL_MASK	(BIT(15) | BIT(14) | BIT(13) | BIT(12) |\
+				 BIT(11) | BIT(10))
+#define IMX_UART_FCR_TXTL(x)	((x) << 10)
+#define IMX_UART_FCR_RFDIV_MASK	(BIT(9) | BIT(8) | BIT(7))
+#define IMX_UART_FCR_RFDIV7	(BIT(9) | BIT(8))
+#define IMX_UART_FCR_RFDIV1	(BIT(9) | BIT(7))
+#define IMX_UART_FCR_RFDIV2	BIT(9)
+#define IMX_UART_FCR_RFDIV3	(BIT(8) | BIT(7))
+#define IMX_UART_FCR_RFDIV4	BIT(8)
+#define IMX_UART_FCR_RFDIV5	BIT(7)
+#define IMX_UART_FCR_RFDIV6	0
+#define IMX_UART_FCR_DCEDTE	BIT(6)
+#define IMX_UART_FCR_RXTL_MASK	(BIT(5) | BIT(4) | BIT(3) | BIT(2) |\
+				 BIT(1) | BIT(0))
+#define IMX_UART_FCR_RXTL(x)	x
+
+#define IMX_UART_STAT1_OFFSET	0x94
+#define IMX_UART_STAT1_PARITYERR	BIT(15)
+#define IMX_UART_STAT1_RTSS	BIT(14)
+#define IMX_UART_STAT1_TRDY	BIT(13)
+#define IMX_UART_STAT1_RTSD	BIT(12)
+#define IMX_UART_STAT1_ESCF	BIT(11)
+#define IMX_UART_STAT1_FRAMEERR	BIT(10)
+#define IMX_UART_STAT1_RRDY	BIT(9)
+#define IMX_UART_STAT1_AGTIM	BIT(8)
+#define IMX_UART_STAT1_DTRD	BIT(7)
+#define IMX_UART_STAT1_RXDS	BIT(6)
+#define IMX_UART_STAT1_AIRINT	BIT(5)
+#define IMX_UART_STAT1_AWAKE	BIT(4)
+#define IMX_UART_STAT1_SAD	BIT(3)
+
+#define IMX_UART_STAT2_OFFSET	0x98
+#define IMX_UART_STAT2_ADET	BIT(15)
+#define IMX_UART_STAT2_TXFE	BIT(14)
+#define IMX_UART_STAT2_DTRF	BIT(13)
+#define IMX_UART_STAT2_IDLE	BIT(12)
+#define IMX_UART_STAT2_ACST	BIT(11)
+#define IMX_UART_STAT2_RIDELT	BIT(10)
+#define IMX_UART_STAT2_RIIN	BIT(9)
+#define IMX_UART_STAT2_IRINT	BIT(8)
+#define IMX_UART_STAT2_WAKE	BIT(7)
+#define IMX_UART_STAT2_DCDDELT	BIT(6)
+#define IMX_UART_STAT2_DCDIN	BIT(5)
+#define IMX_UART_STAT2_RTSF	BIT(4)
+#define IMX_UART_STAT2_TXDC	BIT(3)
+#define IMX_UART_STAT2_BRCD	BIT(2)
+#define IMX_UART_STAT2_ORE	BIT(1)
+#define IMX_UART_STAT2_RCR	BIT(0)
+
+#define IMX_UART_ESC_OFFSET	0x9c
+
+#define IMX_UART_TIM_OFFSET	0xa0
+
+#define IMX_UART_BIR_OFFSET	0xa4
+
+#define IMX_UART_BMR_OFFSET	0xa8
+
+#define IMX_UART_BRC_OFFSET	0xac
+
+#define IMX_UART_ONEMS_OFFSET	0xb0
+
+#define IMX_UART_TS_OFFSET	0xb4
+#define IMX_UART_TS_FRCPERR	BIT(13)
+#define IMX_UART_TS_LOOP	BIT(12)
+#define IMX_UART_TS_DBGEN	BIT(11)
+#define IMX_UART_TS_LOOPIR	BIT(10)
+#define IMX_UART_TS_RXDBG	BIT(9)
+#define IMX_UART_TS_TXEMPTY	BIT(6)
+#define IMX_UART_TS_RXEMPTY	BIT(5)
+#define IMX_UART_TS_TXFULL	BIT(4)
+#define IMX_UART_TS_RXFULL	BIT(3)
+#define IMX_UART_TS_SOFTRST	BIT(0)
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_imx_uart_t;
+
+int console_imx_uart_register(uintptr_t baseaddr,
+			      uint32_t clock,
+			      uint32_t baud,
+			      console_imx_uart_t *console);
+#endif /*__ASSEMBLER__*/
+
+#endif /* IMX_UART_H */
diff --git a/drivers/imx/usdhc/imx_usdhc.c b/drivers/imx/usdhc/imx_usdhc.c
new file mode 100644
index 0000000..07f55b7
--- /dev/null
+++ b/drivers/imx/usdhc/imx_usdhc.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+
+#include <imx_usdhc.h>
+
+static void imx_usdhc_initialize(void);
+static int imx_usdhc_send_cmd(struct mmc_cmd *cmd);
+static int imx_usdhc_set_ios(unsigned int clk, unsigned int width);
+static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size);
+static int imx_usdhc_read(int lba, uintptr_t buf, size_t size);
+static int imx_usdhc_write(int lba, uintptr_t buf, size_t size);
+
+static const struct mmc_ops imx_usdhc_ops = {
+	.init		= imx_usdhc_initialize,
+	.send_cmd	= imx_usdhc_send_cmd,
+	.set_ios	= imx_usdhc_set_ios,
+	.prepare	= imx_usdhc_prepare,
+	.read		= imx_usdhc_read,
+	.write		= imx_usdhc_write,
+};
+
+static imx_usdhc_params_t imx_usdhc_params;
+
+#define IMX7_MMC_SRC_CLK_RATE (200 * 1000 * 1000)
+static void imx_usdhc_set_clk(int clk)
+{
+	int div = 1;
+	int pre_div = 1;
+	unsigned int sdhc_clk = IMX7_MMC_SRC_CLK_RATE;
+	uintptr_t reg_base = imx_usdhc_params.reg_base;
+
+	assert(clk > 0);
+
+	while (sdhc_clk / (16 * pre_div) > clk && pre_div < 256)
+		pre_div *= 2;
+
+	while (sdhc_clk / div > clk && div < 16)
+		div++;
+
+	pre_div >>= 1;
+	div -= 1;
+	clk = (pre_div << 8) | (div << 4);
+
+	mmio_clrbits32(reg_base + VENDSPEC, VENDSPEC_CARD_CLKEN);
+	mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_CLOCK_MASK, clk);
+	udelay(10000);
+
+	mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_PER_CLKEN | VENDSPEC_CARD_CLKEN);
+}
+
+static void imx_usdhc_initialize(void)
+{
+	unsigned int timeout = 10000;
+	uintptr_t reg_base = imx_usdhc_params.reg_base;
+
+	assert((imx_usdhc_params.reg_base & MMC_BLOCK_MASK) == 0);
+
+	/* reset the controller */
+	mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTA);
+
+	/* wait for reset done */
+	while ((mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTA)) {
+		if (!timeout)
+			ERROR("IMX MMC reset timeout.\n");
+		timeout--;
+	}
+
+	mmio_write_32(reg_base + MMCBOOT, 0);
+	mmio_write_32(reg_base + MIXCTRL, 0);
+	mmio_write_32(reg_base + CLKTUNECTRLSTS, 0);
+
+	mmio_write_32(reg_base + VENDSPEC, VENDSPEC_INIT);
+	mmio_write_32(reg_base + DLLCTRL, 0);
+	mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_IPG_CLKEN | VENDSPEC_PER_CLKEN);
+
+	/* Set the initial boot clock rate */
+	imx_usdhc_set_clk(MMC_BOOT_CLK_RATE);
+	udelay(100);
+
+	/* Clear read/write ready status */
+	mmio_clrbits32(reg_base + INTSTATEN, INTSTATEN_BRR | INTSTATEN_BWR);
+
+	/* configure as little endian */
+	mmio_write_32(reg_base + PROTCTRL, PROTCTRL_LE);
+
+	/* Set timeout to the maximum value */
+	mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_TIMEOUT_MASK,
+			  SYSCTRL_TIMEOUT(15));
+
+	/* set wartermark level as 16 for safe for MMC */
+	mmio_clrsetbits32(reg_base + WATERMARKLEV, WMKLV_MASK, 16 | (16 << 16));
+}
+
+#define FSL_CMD_RETRIES	1000
+
+static int imx_usdhc_send_cmd(struct mmc_cmd *cmd)
+{
+	uintptr_t reg_base = imx_usdhc_params.reg_base;
+	unsigned int xfertype = 0, mixctl = 0, multiple = 0, data = 0, err = 0;
+	unsigned int state, flags = INTSTATEN_CC | INTSTATEN_CTOE;
+	unsigned int cmd_retries = 0;
+
+	assert(cmd);
+
+	/* clear all irq status */
+	mmio_write_32(reg_base + INTSTAT, 0xffffffff);
+
+	/* Wait for the bus to be idle */
+	do {
+		state = mmio_read_32(reg_base + PSTATE);
+	} while (state & (PSTATE_CDIHB | PSTATE_CIHB));
+
+	while (mmio_read_32(reg_base + PSTATE) & PSTATE_DLA)
+		;
+
+	mmio_write_32(reg_base + INTSIGEN, 0);
+	udelay(1000);
+
+	switch (cmd->cmd_idx) {
+	case MMC_CMD(12):
+		xfertype |= XFERTYPE_CMDTYP_ABORT;
+		break;
+	case MMC_CMD(18):
+		multiple = 1;
+		/* fall thru for read op */
+	case MMC_CMD(17):
+	case MMC_CMD(8):
+		mixctl |= MIXCTRL_DTDSEL;
+		data = 1;
+		break;
+	case MMC_CMD(25):
+		multiple = 1;
+		/* fall thru for data op flag */
+	case MMC_CMD(24):
+		data = 1;
+		break;
+	default:
+		break;
+	}
+
+	if (multiple) {
+		mixctl |= MIXCTRL_MSBSEL;
+		mixctl |= MIXCTRL_BCEN;
+	}
+
+	if (data) {
+		xfertype |= XFERTYPE_DPSEL;
+		mixctl |= MIXCTRL_DMAEN;
+	}
+
+	if (cmd->resp_type & MMC_RSP_48 && cmd->resp_type != MMC_RESPONSE_R2)
+		xfertype |= XFERTYPE_RSPTYP_48;
+	else if (cmd->resp_type & MMC_RSP_136)
+		xfertype |= XFERTYPE_RSPTYP_136;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		xfertype |= XFERTYPE_RSPTYP_48_BUSY;
+
+	if (cmd->resp_type & MMC_RSP_CMD_IDX)
+		xfertype |= XFERTYPE_CICEN;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		xfertype |= XFERTYPE_CCCEN;
+
+	xfertype |= XFERTYPE_CMD(cmd->cmd_idx);
+
+	/* Send the command */
+	mmio_write_32(reg_base + CMDARG, cmd->cmd_arg);
+	mmio_clrsetbits32(reg_base + MIXCTRL, MIXCTRL_DATMASK, mixctl);
+	mmio_write_32(reg_base + XFERTYPE, xfertype);
+
+	/* Wait for the command done */
+	do {
+		state = mmio_read_32(reg_base + INTSTAT);
+		if (cmd_retries)
+			udelay(1);
+	} while ((!(state & flags)) && ++cmd_retries < FSL_CMD_RETRIES);
+
+	if ((state & (INTSTATEN_CTOE | CMD_ERR)) || cmd_retries == FSL_CMD_RETRIES) {
+		if (cmd_retries == FSL_CMD_RETRIES)
+			err = -ETIMEDOUT;
+		else
+			err = -EIO;
+		ERROR("imx_usdhc mmc cmd %d state 0x%x errno=%d\n",
+		      cmd->cmd_idx, state, err);
+		goto out;
+	}
+
+	/* Copy the response to the response buffer */
+	if (cmd->resp_type & MMC_RSP_136) {
+		unsigned int cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
+
+		cmdrsp3 = mmio_read_32(reg_base + CMDRSP3);
+		cmdrsp2 = mmio_read_32(reg_base + CMDRSP2);
+		cmdrsp1 = mmio_read_32(reg_base + CMDRSP1);
+		cmdrsp0 = mmio_read_32(reg_base + CMDRSP0);
+		cmd->resp_data[3] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
+		cmd->resp_data[2] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
+		cmd->resp_data[1] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
+		cmd->resp_data[0] = (cmdrsp0 << 8);
+	} else {
+		cmd->resp_data[0] = mmio_read_32(reg_base + CMDRSP0);
+	}
+
+	/* Wait until all of the blocks are transferred */
+	if (data) {
+		flags = DATA_COMPLETE;
+		do {
+			state = mmio_read_32(reg_base + INTSTAT);
+
+			if (state & (INTSTATEN_DTOE | DATA_ERR)) {
+				err = -EIO;
+				ERROR("imx_usdhc mmc data state 0x%x\n", state);
+				goto out;
+			}
+		} while ((state & flags) != flags);
+	}
+
+out:
+	/* Reset CMD and DATA on error */
+	if (err) {
+		mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTC);
+		while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTC)
+			;
+
+		if (data) {
+			mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTD);
+			while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTD)
+				;
+		}
+	}
+
+	/* clear all irq status */
+	mmio_write_32(reg_base + INTSTAT, 0xffffffff);
+
+	return err;
+}
+
+static int imx_usdhc_set_ios(unsigned int clk, unsigned int width)
+{
+	uintptr_t reg_base = imx_usdhc_params.reg_base;
+
+	imx_usdhc_set_clk(clk);
+
+	if (width == MMC_BUS_WIDTH_4)
+		mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK,
+				  PROTCTRL_WIDTH_4);
+	else if (width == MMC_BUS_WIDTH_8)
+		mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK,
+				  PROTCTRL_WIDTH_8);
+
+	return 0;
+}
+
+static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size)
+{
+	uintptr_t reg_base = imx_usdhc_params.reg_base;
+
+	mmio_write_32(reg_base + DSADDR, buf);
+	mmio_write_32(reg_base + BLKATT,
+		      (size / MMC_BLOCK_SIZE) << 16 | MMC_BLOCK_SIZE);
+
+	return 0;
+}
+
+static int imx_usdhc_read(int lba, uintptr_t buf, size_t size)
+{
+	return 0;
+}
+
+static int imx_usdhc_write(int lba, uintptr_t buf, size_t size)
+{
+	return 0;
+}
+
+void imx_usdhc_init(imx_usdhc_params_t *params,
+		    struct mmc_device_info *mmc_dev_info)
+{
+	assert((params != 0) &&
+	       ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
+	       (params->clk_rate > 0) &&
+	       ((params->bus_width == MMC_BUS_WIDTH_1) ||
+		(params->bus_width == MMC_BUS_WIDTH_4) ||
+		(params->bus_width == MMC_BUS_WIDTH_8)));
+
+	memcpy(&imx_usdhc_params, params, sizeof(imx_usdhc_params_t));
+	mmc_init(&imx_usdhc_ops, params->clk_rate, params->bus_width,
+		 params->flags, mmc_dev_info);
+}
diff --git a/drivers/imx/usdhc/imx_usdhc.h b/drivers/imx/usdhc/imx_usdhc.h
new file mode 100644
index 0000000..e063316
--- /dev/null
+++ b/drivers/imx/usdhc/imx_usdhc.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_USDHC_H
+#define IMX_USDHC_H
+
+#include <drivers/mmc.h>
+
+typedef struct imx_usdhc_params {
+	uintptr_t	reg_base;
+	int		clk_rate;
+	int		bus_width;
+	unsigned int	flags;
+} imx_usdhc_params_t;
+
+void imx_usdhc_init(imx_usdhc_params_t *params,
+		    struct mmc_device_info *mmc_dev_info);
+
+/* iMX MMC registers definition */
+#define DSADDR			0x000
+#define BLKATT			0x004
+#define CMDARG			0x008
+#define CMDRSP0			0x010
+#define CMDRSP1			0x014
+#define CMDRSP2			0x018
+#define CMDRSP3			0x01c
+
+#define XFERTYPE		0x00c
+#define XFERTYPE_CMD(x)		(((x) & 0x3f) << 24)
+#define XFERTYPE_CMDTYP_ABORT	(3 << 22)
+#define XFERTYPE_DPSEL		BIT(21)
+#define XFERTYPE_CICEN		BIT(20)
+#define XFERTYPE_CCCEN		BIT(19)
+#define XFERTYPE_RSPTYP_136	BIT(16)
+#define XFERTYPE_RSPTYP_48	BIT(17)
+#define XFERTYPE_RSPTYP_48_BUSY	(BIT(16) | BIT(17))
+
+#define PSTATE			0x024
+#define PSTATE_DAT0		BIT(24)
+#define PSTATE_DLA		BIT(2)
+#define PSTATE_CDIHB		BIT(1)
+#define PSTATE_CIHB		BIT(0)
+
+#define PROTCTRL		0x028
+#define PROTCTRL_LE		BIT(5)
+#define PROTCTRL_WIDTH_4	BIT(1)
+#define PROTCTRL_WIDTH_8	BIT(2)
+#define PROTCTRL_WIDTH_MASK	0x6
+
+#define SYSCTRL			0x02c
+#define SYSCTRL_RSTD		BIT(26)
+#define SYSCTRL_RSTC		BIT(25)
+#define SYSCTRL_RSTA		BIT(24)
+#define SYSCTRL_CLOCK_MASK	0x0000fff0
+#define SYSCTRL_TIMEOUT_MASK	0x000f0000
+#define SYSCTRL_TIMEOUT(x)	((0xf & (x)) << 16)
+
+#define INTSTAT			0x030
+#define INTSTAT_DMAE		BIT(28)
+#define INTSTAT_DEBE		BIT(22)
+#define INTSTAT_DCE		BIT(21)
+#define INTSTAT_DTOE		BIT(20)
+#define INTSTAT_CIE		BIT(19)
+#define INTSTAT_CEBE		BIT(18)
+#define INTSTAT_CCE		BIT(17)
+#define INTSTAT_DINT		BIT(3)
+#define INTSTAT_BGE		BIT(2)
+#define INTSTAT_TC		BIT(1)
+#define INTSTAT_CC		BIT(0)
+#define CMD_ERR			(INTSTAT_CIE | INTSTAT_CEBE | INTSTAT_CCE)
+#define DATA_ERR		(INTSTAT_DMAE | INTSTAT_DEBE | INTSTAT_DCE | \
+				 INTSTAT_DTOE)
+#define DATA_COMPLETE		(INTSTAT_DINT | INTSTAT_TC)
+
+#define INTSTATEN		0x034
+#define INTSTATEN_DEBE		BIT(22)
+#define INTSTATEN_DCE		BIT(21)
+#define INTSTATEN_DTOE		BIT(20)
+#define INTSTATEN_CIE		BIT(19)
+#define INTSTATEN_CEBE		BIT(18)
+#define INTSTATEN_CCE		BIT(17)
+#define INTSTATEN_CTOE		BIT(16)
+#define INTSTATEN_CINT		BIT(8)
+#define INTSTATEN_BRR		BIT(5)
+#define INTSTATEN_BWR		BIT(4)
+#define INTSTATEN_DINT		BIT(3)
+#define INTSTATEN_TC		BIT(1)
+#define INTSTATEN_CC		BIT(0)
+#define EMMC_INTSTATEN_BITS	(INTSTATEN_CC | INTSTATEN_TC | INTSTATEN_DINT | \
+				 INTSTATEN_BWR | INTSTATEN_BRR | INTSTATEN_CINT | \
+				 INTSTATEN_CTOE | INTSTATEN_CCE | INTSTATEN_CEBE | \
+				 INTSTATEN_CIE | INTSTATEN_DTOE | INTSTATEN_DCE | \
+				 INTSTATEN_DEBE)
+
+#define INTSIGEN		0x038
+
+#define WATERMARKLEV		0x044
+#define WMKLV_RD_MASK		0xff
+#define WMKLV_WR_MASK		0x00ff0000
+#define WMKLV_MASK		(WMKLV_RD_MASK | WMKLV_WR_MASK)
+
+#define MIXCTRL			0x048
+#define MIXCTRL_MSBSEL		BIT(5)
+#define MIXCTRL_DTDSEL		BIT(4)
+#define MIXCTRL_DDREN		BIT(3)
+#define MIXCTRL_AC12EN		BIT(2)
+#define MIXCTRL_BCEN		BIT(1)
+#define MIXCTRL_DMAEN		BIT(0)
+#define MIXCTRL_DATMASK		0x7f
+
+#define DLLCTRL			0x060
+
+#define CLKTUNECTRLSTS		0x068
+
+#define VENDSPEC		0x0c0
+#define VENDSPEC_RSRV1		BIT(29)
+#define VENDSPEC_CARD_CLKEN	BIT(14)
+#define VENDSPEC_PER_CLKEN	BIT(13)
+#define VENDSPEC_AHB_CLKEN	BIT(12)
+#define VENDSPEC_IPG_CLKEN	BIT(11)
+#define VENDSPEC_AC12_CHKBUSY	BIT(3)
+#define VENDSPEC_EXTDMA		BIT(0)
+#define VENDSPEC_INIT		(VENDSPEC_RSRV1	| VENDSPEC_CARD_CLKEN | \
+				 VENDSPEC_PER_CLKEN | VENDSPEC_AHB_CLKEN | \
+				 VENDSPEC_IPG_CLKEN | VENDSPEC_AC12_CHKBUSY | \
+				 VENDSPEC_EXTDMA)
+
+#define MMCBOOT			0x0c4
+
+#define mmio_clrsetbits32(addr, clear, set)	mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)) | (set))
+#define mmio_clrbits32(addr, clear)		mmio_write_32(addr, mmio_read_32(addr) & ~(clear))
+#define mmio_setbits32(addr, set)		mmio_write_32(addr, mmio_read_32(addr) | (set))
+
+#endif /* IMX_USDHC_H */
diff --git a/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
new file mode 100644
index 0000000..a0fc034
--- /dev/null
+++ b/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+
+#include "qspi/cadence_qspi.h"
+
+/* As we need to be able to keep state for seek, only one file can be open
+ * at a time. Make this a structure and point to the entity->info. When we
+ * can malloc memory we can change this to support more open files.
+ */
+typedef struct {
+	/* Use the 'in_use' flag as any value for base and file_pos could be
+	 * valid.
+	 */
+	int		in_use;
+	uintptr_t	base;
+	size_t		file_pos;
+	size_t		size;
+} file_state_t;
+
+static file_state_t current_file = {0};
+
+/* Identify the device type as memmap */
+static io_type_t device_type_memmap(void)
+{
+	return IO_TYPE_MEMMAP;
+}
+
+/* Memmap device functions */
+static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			     io_entity_t *entity);
+static int memmap_block_seek(io_entity_t *entity, int mode,
+			     ssize_t offset);
+static int memmap_block_len(io_entity_t *entity, size_t *length);
+static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
+			     size_t length, size_t *length_read);
+static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
+			      size_t length, size_t *length_written);
+static int memmap_block_close(io_entity_t *entity);
+static int memmap_dev_close(io_dev_info_t *dev_info);
+
+
+static const io_dev_connector_t memmap_dev_connector = {
+	.dev_open = memmap_dev_open
+};
+
+
+static const io_dev_funcs_t memmap_dev_funcs = {
+	.type = device_type_memmap,
+	.open = memmap_block_open,
+	.seek = memmap_block_seek,
+	.size = memmap_block_len,
+	.read = memmap_block_read,
+	.write = memmap_block_write,
+	.close = memmap_block_close,
+	.dev_init = NULL,
+	.dev_close = memmap_dev_close,
+};
+
+
+/* No state associated with this device so structure can be const */
+static const io_dev_info_t memmap_dev_info = {
+	.funcs = &memmap_dev_funcs,
+	.info = (uintptr_t)NULL
+};
+
+
+/* Open a connection to the memmap device */
+static int memmap_dev_open(const uintptr_t dev_spec __unused,
+			   io_dev_info_t **dev_info)
+{
+	assert(dev_info != NULL);
+	*dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
+
+	return 0;
+}
+
+
+
+/* Close a connection to the memmap device */
+static int memmap_dev_close(io_dev_info_t *dev_info)
+{
+	/* NOP */
+	/* TODO: Consider tracking open files and cleaning them up here */
+	return 0;
+}
+
+
+/* Open a file on the memmap device */
+static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			     io_entity_t *entity)
+{
+	int result = -ENOMEM;
+	const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
+
+	/* Since we need to track open state for seek() we only allow one open
+	 * spec at a time. When we have dynamic memory we can malloc and set
+	 * entity->info.
+	 */
+	if (current_file.in_use == 0) {
+		assert(block_spec != NULL);
+		assert(entity != NULL);
+
+		current_file.in_use = 1;
+		current_file.base = block_spec->offset;
+		/* File cursor offset for seek and incremental reads etc. */
+		current_file.file_pos = 0;
+		current_file.size = block_spec->length;
+		entity->info = (uintptr_t)&current_file;
+		result = 0;
+	} else {
+		WARN("A Memmap device is already active. Close first.\n");
+	}
+
+	return result;
+}
+
+
+/* Seek to a particular file offset on the memmap device */
+static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+{
+	int result = -ENOENT;
+	file_state_t *fp;
+
+	/* We only support IO_SEEK_SET for the moment. */
+	if (mode == IO_SEEK_SET) {
+		assert(entity != NULL);
+
+		fp = (file_state_t *) entity->info;
+
+		/* Assert that new file position is valid */
+		assert((offset >= 0) && (offset < fp->size));
+
+		/* Reset file position */
+		fp->file_pos = offset;
+		result = 0;
+	}
+
+	return result;
+}
+
+
+/* Return the size of a file on the memmap device */
+static int memmap_block_len(io_entity_t *entity, size_t *length)
+{
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	*length = ((file_state_t *)entity->info)->size;
+
+	return 0;
+}
+
+
+/* Read data from a file on the memmap device */
+static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
+			     size_t length, size_t *length_read)
+{
+	file_state_t *fp;
+	size_t pos_after;
+
+	assert(entity != NULL);
+	assert(length_read != NULL);
+
+	fp = (file_state_t *) entity->info;
+
+	/* Assert that file position is valid for this read operation */
+	pos_after = fp->file_pos + length;
+	assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
+
+	//memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
+	cad_qspi_read((void *)buffer, fp->base + fp->file_pos, length);
+	*length_read = length;
+
+	/* Set file position after read */
+	fp->file_pos = pos_after;
+
+	return 0;
+}
+
+
+/* Write data to a file on the memmap device */
+static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
+			      size_t length, size_t *length_written)
+{
+	file_state_t *fp;
+	size_t pos_after;
+
+	assert(entity != NULL);
+	assert(length_written != NULL);
+
+	fp = (file_state_t *) entity->info;
+
+	/* Assert that file position is valid for this write operation */
+	pos_after = fp->file_pos + length;
+	assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
+
+	memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
+
+	*length_written = length;
+
+	/* Set file position after write */
+	fp->file_pos = pos_after;
+
+	return 0;
+}
+
+
+/* Close a file on the memmap device */
+static int memmap_block_close(io_entity_t *entity)
+{
+	assert(entity != NULL);
+
+	entity->info = 0;
+
+	/* This would be a mem free() if we had malloc.*/
+	zeromem((void *)&current_file, sizeof(current_file));
+
+	return 0;
+}
+
+
+/* Exported functions */
+
+/* Register the memmap driver with the IO abstraction */
+int register_io_dev_memmap(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	result = io_register_device(&memmap_dev_info);
+	if (result == 0)
+		*dev_con = &memmap_dev_connector;
+
+	return result;
+}
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
new file mode 100644
index 0000000..f190a43
--- /dev/null
+++ b/drivers/io/io_block.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+
+typedef struct {
+	io_block_dev_spec_t	*dev_spec;
+	uintptr_t		base;
+	size_t			file_pos;
+	size_t			size;
+} block_dev_state_t;
+
+#define is_power_of_2(x)	((x != 0) && ((x & (x - 1)) == 0))
+
+io_type_t device_type_block(void);
+
+static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+		      io_entity_t *entity);
+static int block_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+		      size_t *length_read);
+static int block_write(io_entity_t *entity, const uintptr_t buffer,
+		       size_t length, size_t *length_written);
+static int block_close(io_entity_t *entity);
+static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int block_dev_close(io_dev_info_t *dev_info);
+
+static const io_dev_connector_t block_dev_connector = {
+	.dev_open	= block_dev_open
+};
+
+static const io_dev_funcs_t block_dev_funcs = {
+	.type		= device_type_block,
+	.open		= block_open,
+	.seek		= block_seek,
+	.size		= NULL,
+	.read		= block_read,
+	.write		= block_write,
+	.close		= block_close,
+	.dev_init	= NULL,
+	.dev_close	= block_dev_close,
+};
+
+static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES];
+
+/* Track number of allocated block state */
+static unsigned int block_dev_count;
+
+io_type_t device_type_block(void)
+{
+	return IO_TYPE_BLOCK;
+}
+
+/* Locate a block state in the pool, specified by address */
+static int find_first_block_state(const io_block_dev_spec_t *dev_spec,
+				  unsigned int *index_out)
+{
+	unsigned int index;
+	int result = -ENOENT;
+
+	for (index = 0U; index < MAX_IO_BLOCK_DEVICES; ++index) {
+		/* dev_spec is used as identifier since it's unique */
+		if (state_pool[index].dev_spec == dev_spec) {
+			result = 0;
+			*index_out = index;
+			break;
+		}
+	}
+	return result;
+}
+
+/* Allocate a device info from the pool and return a pointer to it */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+	int result = -ENOMEM;
+	assert(dev_info != NULL);
+
+	if (block_dev_count < MAX_IO_BLOCK_DEVICES) {
+		unsigned int index = 0;
+		result = find_first_block_state(NULL, &index);
+		assert(result == 0);
+		/* initialize dev_info */
+		dev_info_pool[index].funcs = &block_dev_funcs;
+		dev_info_pool[index].info = (uintptr_t)&state_pool[index];
+		*dev_info = &dev_info_pool[index];
+		++block_dev_count;
+	}
+
+	return result;
+}
+
+
+/* Release a device info to the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+	int result;
+	unsigned int index = 0;
+	block_dev_state_t *state;
+	assert(dev_info != NULL);
+
+	state = (block_dev_state_t *)dev_info->info;
+	result = find_first_block_state(state->dev_spec, &index);
+	if (result ==  0) {
+		/* free if device info is valid */
+		zeromem(state, sizeof(block_dev_state_t));
+		zeromem(dev_info, sizeof(io_dev_info_t));
+		--block_dev_count;
+	}
+
+	return result;
+}
+
+static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+		      io_entity_t *entity)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *region;
+
+	assert((dev_info->info != (uintptr_t)NULL) &&
+	       (spec != (uintptr_t)NULL) &&
+	       (entity->info == (uintptr_t)NULL));
+
+	region = (io_block_spec_t *)spec;
+	cur = (block_dev_state_t *)dev_info->info;
+	assert(((region->offset % cur->dev_spec->block_size) == 0) &&
+	       ((region->length % cur->dev_spec->block_size) == 0));
+
+	cur->base = region->offset;
+	cur->size = region->length;
+	cur->file_pos = 0;
+
+	entity->info = (uintptr_t)cur;
+	return 0;
+}
+
+/* parameter offset is relative address at here */
+static int block_seek(io_entity_t *entity, int mode, ssize_t offset)
+{
+	block_dev_state_t *cur;
+
+	assert(entity->info != (uintptr_t)NULL);
+
+	cur = (block_dev_state_t *)entity->info;
+	assert((offset >= 0) && (offset < cur->size));
+
+	switch (mode) {
+	case IO_SEEK_SET:
+		cur->file_pos = offset;
+		break;
+	case IO_SEEK_CUR:
+		cur->file_pos += offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+	assert(cur->file_pos < cur->size);
+	return 0;
+}
+
+/*
+ * This function allows the caller to read any number of bytes
+ * from any position. It hides from the caller that the low level
+ * driver only can read aligned blocks of data. For this reason
+ * we need to handle the use case where the first byte to be read is not
+ * aligned to start of the block, the last byte to be read is also not
+ * aligned to the end of a block, and there are zero or more blocks-worth
+ * of data in between.
+ *
+ * In such a case we need to read more bytes than requested (i.e. full
+ * blocks) and strip-out the leading bytes (aka skip) and the trailing
+ * bytes (aka padding). See diagram below
+ *
+ * cur->file_pos ------------
+ *                          |
+ * cur->base                |
+ *  |                       |
+ *  v                       v<----  length   ---->
+ *  --------------------------------------------------------------
+ * |           |         block#1    |        |   block#n          |
+ * |  block#0  |            +       |   ...  |     +              |
+ * |           | <- skip -> +       |        |     + <- padding ->|
+ *  ------------------------+----------------------+--------------
+ *             ^                                                  ^
+ *             |                                                  |
+ *             v    iteration#1                iteration#n        v
+ *              --------------------------------------------------
+ *             |                    |        |                    |
+ *             |<----  request ---->|  ...   |<----- request ---->|
+ *             |                    |        |                    |
+ *              --------------------------------------------------
+ *            /                   /          |                    |
+ *           /                   /           |                    |
+ *          /                   /            |                    |
+ *         /                   /             |                    |
+ *        /                   /              |                    |
+ *       /                   /               |                    |
+ *      /                   /                |                    |
+ *     /                   /                 |                    |
+ *    /                   /                  |                    |
+ *   /                   /                   |                    |
+ *  <---- request ------>                    <------ request  ----->
+ *  ---------------------                    -----------------------
+ *  |        |          |                    |          |           |
+ *  |<-skip->|<-nbytes->|           -------->|<-nbytes->|<-padding->|
+ *  |        |          |           |        |          |           |
+ *  ---------------------           |        -----------------------
+ *  ^        \           \          |        |          |
+ *  |         \           \         |        |          |
+ *  |          \           \        |        |          |
+ *  buf->offset \           \   buf->offset  |          |
+ *               \           \               |          |
+ *                \           \              |          |
+ *                 \           \             |          |
+ *                  \           \            |          |
+ *                   \           \           |          |
+ *                    \           \          |          |
+ *                     \           \         |          |
+ *                      --------------------------------
+ *                      |           |        |         |
+ * buffer-------------->|           | ...    |         |
+ *                      |           |        |         |
+ *                      --------------------------------
+ *                      <-count#1->|                   |
+ *                      <----------  count#n   -------->
+ *                      <----------  length  ---------->
+ *
+ * Additionally, the IO driver has an underlying buffer that is at least
+ * one block-size and may be big enough to allow.
+ */
+static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+		      size_t *length_read)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *buf;
+	io_block_ops_t *ops;
+	int lba;
+	size_t block_size, left;
+	size_t nbytes;  /* number of bytes read in one iteration */
+	size_t request; /* number of requested bytes in one iteration */
+	size_t count;   /* number of bytes already read */
+	/*
+	 * number of leading bytes from start of the block
+	 * to the first byte to be read
+	 */
+	size_t skip;
+
+	/*
+	 * number of trailing bytes between the last byte
+	 * to be read and the end of the block
+	 */
+	size_t padding;
+
+	assert(entity->info != (uintptr_t)NULL);
+	cur = (block_dev_state_t *)entity->info;
+	ops = &(cur->dev_spec->ops);
+	buf = &(cur->dev_spec->buffer);
+	block_size = cur->dev_spec->block_size;
+	assert((length <= cur->size) &&
+	       (length > 0) &&
+	       (ops->read != 0));
+
+	/*
+	 * We don't know the number of bytes that we are going
+	 * to read in every iteration, because it will depend
+	 * on the low level driver.
+	 */
+	count = 0;
+	for (left = length; left > 0; left -= nbytes) {
+		/*
+		 * We must only request operations aligned to the block
+		 * size. Therefore if file_pos is not block-aligned,
+		 * we have to request the operation to start at the
+		 * previous block boundary and skip the leading bytes. And
+		 * similarly, the number of bytes requested must be a
+		 * block size multiple
+		 */
+		skip = cur->file_pos & (block_size - 1);
+
+		/*
+		 * Calculate the block number containing file_pos
+		 * - e.g. block 3.
+		 */
+		lba = (cur->file_pos + cur->base) / block_size;
+
+		if (skip + left > buf->length) {
+			/*
+			 * The underlying read buffer is too small to
+			 * read all the required data - limit to just
+			 * fill the buffer, and then read again.
+			 */
+			request = buf->length;
+		} else {
+			/*
+			 * The underlying read buffer is big enough to
+			 * read all the required data. Calculate the
+			 * number of bytes to read to align with the
+			 * block size.
+			 */
+			request = skip + left;
+			request = (request + (block_size - 1)) & ~(block_size - 1);
+		}
+		request = ops->read(lba, buf->offset, request);
+
+		if (request <= skip) {
+			/*
+			 * We couldn't read enough bytes to jump over
+			 * the skip bytes, so we should have to read
+			 * again the same block, thus generating
+			 * the same error.
+			 */
+			return -EIO;
+		}
+
+		/*
+		 * Need to remove skip and padding bytes,if any, from
+		 * the read data when copying to the user buffer.
+		 */
+		nbytes = request - skip;
+		padding = (nbytes > left) ? nbytes - left : 0;
+		nbytes -= padding;
+
+		memcpy((void *)(buffer + count),
+		       (void *)(buf->offset + skip),
+		       nbytes);
+
+		cur->file_pos += nbytes;
+		count += nbytes;
+	}
+	assert(count == length);
+	*length_read = count;
+
+	return 0;
+}
+
+/*
+ * This function allows the caller to write any number of bytes
+ * from any position. It hides from the caller that the low level
+ * driver only can write aligned blocks of data.
+ * See comments for block_read for more details.
+ */
+static int block_write(io_entity_t *entity, const uintptr_t buffer,
+		       size_t length, size_t *length_written)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *buf;
+	io_block_ops_t *ops;
+	int lba;
+	size_t block_size, left;
+	size_t nbytes;  /* number of bytes read in one iteration */
+	size_t request; /* number of requested bytes in one iteration */
+	size_t count;   /* number of bytes already read */
+	/*
+	 * number of leading bytes from start of the block
+	 * to the first byte to be read
+	 */
+	size_t skip;
+
+	/*
+	 * number of trailing bytes between the last byte
+	 * to be read and the end of the block
+	 */
+	size_t padding;
+
+	assert(entity->info != (uintptr_t)NULL);
+	cur = (block_dev_state_t *)entity->info;
+	ops = &(cur->dev_spec->ops);
+	buf = &(cur->dev_spec->buffer);
+	block_size = cur->dev_spec->block_size;
+	assert((length <= cur->size) &&
+	       (length > 0) &&
+	       (ops->read != 0) &&
+	       (ops->write != 0));
+
+	/*
+	 * We don't know the number of bytes that we are going
+	 * to write in every iteration, because it will depend
+	 * on the low level driver.
+	 */
+	count = 0;
+	for (left = length; left > 0; left -= nbytes) {
+		/*
+		 * We must only request operations aligned to the block
+		 * size. Therefore if file_pos is not block-aligned,
+		 * we have to request the operation to start at the
+		 * previous block boundary and skip the leading bytes. And
+		 * similarly, the number of bytes requested must be a
+		 * block size multiple
+		 */
+		skip = cur->file_pos & (block_size - 1);
+
+		/*
+		 * Calculate the block number containing file_pos
+		 * - e.g. block 3.
+		 */
+		lba = (cur->file_pos + cur->base) / block_size;
+
+		if (skip + left > buf->length) {
+			/*
+			 * The underlying read buffer is too small to
+			 * read all the required data - limit to just
+			 * fill the buffer, and then read again.
+			 */
+			request = buf->length;
+		} else {
+			/*
+			 * The underlying read buffer is big enough to
+			 * read all the required data. Calculate the
+			 * number of bytes to read to align with the
+			 * block size.
+			 */
+			request = skip + left;
+			request = (request + (block_size - 1)) & ~(block_size - 1);
+		}
+
+		/*
+		 * The number of bytes that we are going to write
+		 * from the user buffer will depend of the size
+		 * of the current request.
+		 */
+		nbytes = request - skip;
+		padding = (nbytes > left) ? nbytes - left : 0;
+		nbytes -= padding;
+
+		/*
+		 * If we have skip or padding bytes then we have to preserve
+		 * some content and it means that we have to read before
+		 * writing
+		 */
+		if (skip > 0 || padding > 0) {
+			request = ops->read(lba, buf->offset, request);
+			/*
+			 * The read may return size less than
+			 * requested. Round down to the nearest block
+			 * boundary
+			 */
+			request &= ~(block_size-1);
+			if (request <= skip) {
+				/*
+				 * We couldn't read enough bytes to jump over
+				 * the skip bytes, so we should have to read
+				 * again the same block, thus generating
+				 * the same error.
+				 */
+				return -EIO;
+			}
+			nbytes = request - skip;
+			padding = (nbytes > left) ? nbytes - left : 0;
+			nbytes -= padding;
+		}
+
+		memcpy((void *)(buf->offset + skip),
+		       (void *)(buffer + count),
+		       nbytes);
+
+		request = ops->write(lba, buf->offset, request);
+		if (request <= skip)
+			return -EIO;
+
+		/*
+		 * And the previous write operation may modify the size
+		 * of the request, so again, we have to calculate the
+		 * number of bytes that we consumed from the user
+		 * buffer
+		 */
+		nbytes = request - skip;
+		padding = (nbytes > left) ? nbytes - left : 0;
+		nbytes -= padding;
+
+		cur->file_pos += nbytes;
+		count += nbytes;
+	}
+	assert(count == length);
+	*length_written = count;
+
+	return 0;
+}
+
+static int block_close(io_entity_t *entity)
+{
+	entity->info = (uintptr_t)NULL;
+	return 0;
+}
+
+static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *buffer;
+	io_dev_info_t *info;
+	size_t block_size;
+	int result;
+
+	assert(dev_info != NULL);
+	result = allocate_dev_info(&info);
+	if (result)
+		return -ENOENT;
+
+	cur = (block_dev_state_t *)info->info;
+	/* dev_spec is type of io_block_dev_spec_t. */
+	cur->dev_spec = (io_block_dev_spec_t *)dev_spec;
+	buffer = &(cur->dev_spec->buffer);
+	block_size = cur->dev_spec->block_size;
+	assert((block_size > 0) &&
+	       (is_power_of_2(block_size) != 0) &&
+	       ((buffer->offset % block_size) == 0) &&
+	       ((buffer->length % block_size) == 0));
+
+	*dev_info = info;	/* cast away const */
+	(void)block_size;
+	(void)buffer;
+	return 0;
+}
+
+static int block_dev_close(io_dev_info_t *dev_info)
+{
+	return free_dev_info(dev_info);
+}
+
+/* Exported functions */
+
+/* Register the Block driver with the IO abstraction */
+int register_io_dev_block(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	/*
+	 * Since dev_info isn't really used in io_register_device, always
+	 * use the same device info at here instead.
+	 */
+	result = io_register_device(&dev_info_pool[0]);
+	if (result == 0)
+		*dev_con = &block_dev_connector;
+	return result;
+}
diff --git a/drivers/io/io_dummy.c b/drivers/io/io_dummy.c
new file mode 100644
index 0000000..4f0cda6
--- /dev/null
+++ b/drivers/io/io_dummy.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_dummy.h>
+#include <drivers/io/io_storage.h>
+
+struct file_state {
+	int in_use;
+	size_t size;
+};
+
+static struct file_state current_file = {0};
+
+/* Identify the device type as dummy */
+static io_type_t device_type_dummy(void)
+{
+	return IO_TYPE_DUMMY;
+}
+
+/* Dummy device functions */
+static int dummy_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			     io_entity_t *entity);
+static int dummy_block_len(io_entity_t *entity, size_t *length);
+static int dummy_block_read(io_entity_t *entity, uintptr_t buffer,
+			     size_t length, size_t *length_read);
+static int dummy_block_close(io_entity_t *entity);
+static int dummy_dev_close(io_dev_info_t *dev_info);
+
+
+static const io_dev_connector_t dummy_dev_connector = {
+	.dev_open = dummy_dev_open
+};
+
+
+static const io_dev_funcs_t dummy_dev_funcs = {
+	.type = device_type_dummy,
+	.open = dummy_block_open,
+	.seek = NULL,
+	.size = dummy_block_len,
+	.read = dummy_block_read,
+	.write = NULL,
+	.close = dummy_block_close,
+	.dev_init = NULL,
+	.dev_close = dummy_dev_close,
+};
+
+
+static const io_dev_info_t dummy_dev_info = {
+	.funcs = &dummy_dev_funcs,
+	.info = (uintptr_t)NULL
+};
+
+
+/* Open a connection to the dummy device */
+static int dummy_dev_open(const uintptr_t dev_spec __attribute__((unused)),
+			   io_dev_info_t **dev_info)
+{
+	assert(dev_info != NULL);
+	*dev_info = (io_dev_info_t *)&dummy_dev_info;
+
+	return 0;
+}
+
+
+/* Close a connection to the dummy device */
+static int dummy_dev_close(io_dev_info_t *dev_info)
+{
+	return 0;
+}
+
+
+/* Open a file on the dummy device */
+static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			     io_entity_t *entity)
+{
+	int result;
+	const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
+
+	if (current_file.in_use == 0) {
+		assert(block_spec != NULL);
+		assert(entity != NULL);
+
+		current_file.in_use = 1;
+		current_file.size = block_spec->length;
+		entity->info = (uintptr_t)&current_file;
+		result = 0;
+	} else {
+		WARN("A Dummy device is already active. Close first.\n");
+		result = -ENOMEM;
+	}
+
+	return result;
+}
+
+
+/* Return the size of a file on the dummy device */
+static int dummy_block_len(io_entity_t *entity, size_t *length)
+{
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	*length =  ((struct file_state *)entity->info)->size;
+
+	return 0;
+}
+
+
+/* Read data from a file on the dummy device */
+static int dummy_block_read(io_entity_t *entity, uintptr_t buffer,
+			     size_t length, size_t *length_read)
+{
+	assert(length_read != NULL);
+
+	*length_read = length;
+
+	return 0;
+}
+
+
+/* Close a file on the dummy device */
+static int dummy_block_close(io_entity_t *entity)
+{
+	assert(entity != NULL);
+
+	entity->info = 0;
+	current_file.in_use = 0;
+
+	return 0;
+}
+
+
+/* Exported functions */
+
+/* Register the dummy driver with the IO abstraction */
+int register_io_dev_dummy(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	result = io_register_device(&dummy_dev_info);
+	if (result == 0)
+		*dev_con = &dummy_dev_connector;
+
+	return result;
+}
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
new file mode 100644
index 0000000..544b37d
--- /dev/null
+++ b/drivers/io/io_fip.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * 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/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+#include <tools_share/uuid.h>
+
+#ifndef MAX_FIP_DEVICES
+#define MAX_FIP_DEVICES		1
+#endif
+
+/* Useful for printing UUIDs when debugging.*/
+#define PRINT_UUID2(x)								\
+	"%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",	\
+		x.time_low, x.time_mid, x.time_hi_and_version,			\
+		x.clock_seq_hi_and_reserved, x.clock_seq_low,			\
+		x.node[0], x.node[1], x.node[2], x.node[3],			\
+		x.node[4], x.node[5]
+
+typedef struct {
+	unsigned int file_pos;
+	fip_toc_entry_t entry;
+} file_state_t;
+
+/*
+ * Maintain dev_spec per FIP Device
+ * TODO - Add backend handles and file state
+ * per FIP device here once backends like io_memmap
+ * can support multiple open files
+ */
+typedef struct {
+	uintptr_t dev_spec;
+} fip_dev_state_t;
+
+static const uuid_t uuid_null;
+/*
+ * Only one file can be open across all FIP device
+ * as backends like io_memmap don't support
+ * multiple open files. The file state and
+ * backend handle should be maintained per FIP device
+ * if the same support is available in the backend
+ */
+static file_state_t current_file = {0};
+static uintptr_t backend_dev_handle;
+static uintptr_t backend_image_spec;
+
+static fip_dev_state_t state_pool[MAX_FIP_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_FIP_DEVICES];
+
+/* Track number of allocated fip devices */
+static unsigned int fip_dev_count;
+
+/* Firmware Image Package driver functions */
+static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			  io_entity_t *entity);
+static int fip_file_len(io_entity_t *entity, size_t *length);
+static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+			  size_t *length_read);
+static int fip_file_close(io_entity_t *entity);
+static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
+static int fip_dev_close(io_dev_info_t *dev_info);
+
+
+/* Return 0 for equal uuids. */
+static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
+{
+	return memcmp(uuid1, uuid2, sizeof(uuid_t));
+}
+
+
+static inline int is_valid_header(fip_toc_header_t *header)
+{
+	if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+
+/* Identify the device type as a virtual driver */
+static io_type_t device_type_fip(void)
+{
+	return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
+}
+
+
+static const io_dev_connector_t fip_dev_connector = {
+	.dev_open = fip_dev_open
+};
+
+
+static const io_dev_funcs_t fip_dev_funcs = {
+	.type = device_type_fip,
+	.open = fip_file_open,
+	.seek = NULL,
+	.size = fip_file_len,
+	.read = fip_file_read,
+	.write = NULL,
+	.close = fip_file_close,
+	.dev_init = fip_dev_init,
+	.dev_close = fip_dev_close,
+};
+
+/* Locate a file state in the pool, specified by address */
+static int find_first_fip_state(const uintptr_t dev_spec,
+				  unsigned int *index_out)
+{
+	int result = -ENOENT;
+	unsigned int index;
+
+	for (index = 0; index < (unsigned int)MAX_FIP_DEVICES; ++index) {
+		/* dev_spec is used as identifier since it's unique */
+		if (state_pool[index].dev_spec == dev_spec) {
+			result = 0;
+			*index_out = index;
+			break;
+		}
+	}
+	return result;
+}
+
+
+/* Allocate a device info from the pool and return a pointer to it */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+	int result = -ENOMEM;
+
+	assert(dev_info != NULL);
+
+	if (fip_dev_count < (unsigned int)MAX_FIP_DEVICES) {
+		unsigned int index = 0;
+
+		result = find_first_fip_state(0, &index);
+		assert(result == 0);
+		/* initialize dev_info */
+		dev_info_pool[index].funcs = &fip_dev_funcs;
+		dev_info_pool[index].info =
+				(uintptr_t)&state_pool[index];
+		*dev_info = &dev_info_pool[index];
+		++fip_dev_count;
+	}
+
+	return result;
+}
+
+/* Release a device info to the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+	int result;
+	unsigned int index = 0;
+	fip_dev_state_t *state;
+
+	assert(dev_info != NULL);
+
+	state = (fip_dev_state_t *)dev_info->info;
+	result = find_first_fip_state(state->dev_spec, &index);
+	if (result ==  0) {
+		/* free if device info is valid */
+		zeromem(state, sizeof(fip_dev_state_t));
+		--fip_dev_count;
+	}
+
+	return result;
+}
+
+/*
+ * Multiple FIP devices can be opened depending on the value of
+ * MAX_FIP_DEVICES. Given that there is only one backend, only a
+ * single file can be open at a time by any FIP device.
+ */
+static int fip_dev_open(const uintptr_t dev_spec,
+			 io_dev_info_t **dev_info)
+{
+	int result;
+	io_dev_info_t *info;
+	fip_dev_state_t *state;
+
+	assert(dev_info != NULL);
+#if MAX_FIP_DEVICES > 1
+	assert(dev_spec != (uintptr_t)NULL);
+#endif
+
+	result = allocate_dev_info(&info);
+	if (result != 0)
+		return -ENOMEM;
+
+	state = (fip_dev_state_t *)info->info;
+
+	state->dev_spec = dev_spec;
+
+	*dev_info = info;
+
+	return 0;
+}
+
+
+/* Do some basic package checks. */
+static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
+{
+	int result;
+	unsigned int image_id = (unsigned int)init_params;
+	uintptr_t backend_handle;
+	fip_toc_header_t header;
+	size_t bytes_read;
+
+	/* Obtain a reference to the image by querying the platform layer */
+	result = plat_get_image_source(image_id, &backend_dev_handle,
+				       &backend_image_spec);
+	if (result != 0) {
+		WARN("Failed to obtain reference to image id=%u (%i)\n",
+			image_id, result);
+		result = -ENOENT;
+		goto fip_dev_init_exit;
+	}
+
+	/* Attempt to access the FIP image */
+	result = io_open(backend_dev_handle, backend_image_spec,
+			 &backend_handle);
+	if (result != 0) {
+		WARN("Failed to access image id=%u (%i)\n", image_id, result);
+		result = -ENOENT;
+		goto fip_dev_init_exit;
+	}
+
+	result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
+			&bytes_read);
+	if (result == 0) {
+		if (!is_valid_header(&header)) {
+			WARN("Firmware Image Package header check failed.\n");
+			result = -ENOENT;
+		} else {
+			VERBOSE("FIP header looks OK.\n");
+		}
+	}
+
+	io_close(backend_handle);
+
+ fip_dev_init_exit:
+	return result;
+}
+
+/* Close a connection to the FIP device */
+static int fip_dev_close(io_dev_info_t *dev_info)
+{
+	/* TODO: Consider tracking open files and cleaning them up here */
+
+	/* Clear the backend. */
+	backend_dev_handle = (uintptr_t)NULL;
+	backend_image_spec = (uintptr_t)NULL;
+
+	return free_dev_info(dev_info);
+}
+
+
+/* Open a file for access from package. */
+static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			 io_entity_t *entity)
+{
+	int result;
+	uintptr_t backend_handle;
+	const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
+	size_t bytes_read;
+	int found_file = 0;
+
+	assert(uuid_spec != NULL);
+	assert(entity != NULL);
+
+	/* Can only have one file open at a time for the moment. We need to
+	 * track state like file cursor position. We know the header lives at
+	 * offset zero, so this entry should never be zero for an active file.
+	 * When the system supports dynamic memory allocation we can allow more
+	 * than one open file at a time if needed.
+	 */
+	if (current_file.entry.offset_address != 0) {
+		WARN("fip_file_open : Only one open file at a time.\n");
+		return -ENOMEM;
+	}
+
+	/* Attempt to access the FIP image */
+	result = io_open(backend_dev_handle, backend_image_spec,
+			 &backend_handle);
+	if (result != 0) {
+		WARN("Failed to open Firmware Image Package (%i)\n", result);
+		result = -ENOENT;
+		goto fip_file_open_exit;
+	}
+
+	/* Seek past the FIP header into the Table of Contents */
+	result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
+	if (result != 0) {
+		WARN("fip_file_open: failed to seek\n");
+		result = -ENOENT;
+		goto fip_file_open_close;
+	}
+
+	found_file = 0;
+	do {
+		result = io_read(backend_handle,
+				 (uintptr_t)&current_file.entry,
+				 sizeof(current_file.entry),
+				 &bytes_read);
+		if (result == 0) {
+			if (compare_uuids(&current_file.entry.uuid,
+					  &uuid_spec->uuid) == 0) {
+				found_file = 1;
+				break;
+			}
+		} else {
+			WARN("Failed to read FIP (%i)\n", result);
+			goto fip_file_open_close;
+		}
+	} while (compare_uuids(&current_file.entry.uuid, &uuid_null) != 0);
+
+	if (found_file == 1) {
+		/* All fine. Update entity info with file state and return. Set
+		 * the file position to 0. The 'current_file.entry' holds the
+		 * base and size of the file.
+		 */
+		current_file.file_pos = 0;
+		entity->info = (uintptr_t)&current_file;
+	} else {
+		/* Did not find the file in the FIP. */
+		current_file.entry.offset_address = 0;
+		result = -ENOENT;
+	}
+
+ fip_file_open_close:
+	io_close(backend_handle);
+
+ fip_file_open_exit:
+	return result;
+}
+
+
+/* Return the size of a file in package */
+static int fip_file_len(io_entity_t *entity, size_t *length)
+{
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	*length =  ((file_state_t *)entity->info)->entry.size;
+
+	return 0;
+}
+
+
+/* Read data from a file in package */
+static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+			  size_t *length_read)
+{
+	int result;
+	file_state_t *fp;
+	size_t file_offset;
+	size_t bytes_read;
+	uintptr_t backend_handle;
+
+	assert(entity != NULL);
+	assert(length_read != NULL);
+	assert(entity->info != (uintptr_t)NULL);
+
+	/* Open the backend, attempt to access the blob image */
+	result = io_open(backend_dev_handle, backend_image_spec,
+			 &backend_handle);
+	if (result != 0) {
+		WARN("Failed to open FIP (%i)\n", result);
+		result = -ENOENT;
+		goto fip_file_read_exit;
+	}
+
+	fp = (file_state_t *)entity->info;
+
+	/* Seek to the position in the FIP where the payload lives */
+	file_offset = fp->entry.offset_address + fp->file_pos;
+	result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
+	if (result != 0) {
+		WARN("fip_file_read: failed to seek\n");
+		result = -ENOENT;
+		goto fip_file_read_close;
+	}
+
+	result = io_read(backend_handle, buffer, length, &bytes_read);
+	if (result != 0) {
+		/* We cannot read our data. Fail. */
+		WARN("Failed to read payload (%i)\n", result);
+		result = -ENOENT;
+		goto fip_file_read_close;
+	} else {
+		/* Set caller length and new file position. */
+		*length_read = bytes_read;
+		fp->file_pos += bytes_read;
+	}
+
+/* Close the backend. */
+ fip_file_read_close:
+	io_close(backend_handle);
+
+ fip_file_read_exit:
+	return result;
+}
+
+
+/* Close a file in package */
+static int fip_file_close(io_entity_t *entity)
+{
+	/* Clear our current file pointer.
+	 * If we had malloc() we would free() here.
+	 */
+	if (current_file.entry.offset_address != 0) {
+		zeromem(&current_file, sizeof(current_file));
+	}
+
+	/* Clear the Entity info. */
+	entity->info = 0;
+
+	return 0;
+}
+
+/* Exported functions */
+
+/* Register the Firmware Image Package driver with the IO abstraction */
+int register_io_dev_fip(const io_dev_connector_t **dev_con)
+{
+	int result;
+	assert(dev_con != NULL);
+
+	/*
+	 * Since dev_info isn't really used in io_register_device, always
+	 * use the same device info at here instead.
+	 */
+	result = io_register_device(&dev_info_pool[0]);
+	if (result == 0)
+		*dev_con = &fip_dev_connector;
+
+	return result;
+}
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
new file mode 100644
index 0000000..96590b6
--- /dev/null
+++ b/drivers/io/io_memmap.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+
+/* As we need to be able to keep state for seek, only one file can be open
+ * at a time. Make this a structure and point to the entity->info. When we
+ * can malloc memory we can change this to support more open files.
+ */
+typedef struct {
+	/* Use the 'in_use' flag as any value for base and file_pos could be
+	 * valid.
+	 */
+	int		in_use;
+	uintptr_t	base;
+	size_t		file_pos;
+	size_t		size;
+} file_state_t;
+
+static file_state_t current_file = {0};
+
+/* Identify the device type as memmap */
+static io_type_t device_type_memmap(void)
+{
+	return IO_TYPE_MEMMAP;
+}
+
+/* Memmap device functions */
+static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			     io_entity_t *entity);
+static int memmap_block_seek(io_entity_t *entity, int mode,
+			     ssize_t offset);
+static int memmap_block_len(io_entity_t *entity, size_t *length);
+static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
+			     size_t length, size_t *length_read);
+static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
+			      size_t length, size_t *length_written);
+static int memmap_block_close(io_entity_t *entity);
+static int memmap_dev_close(io_dev_info_t *dev_info);
+
+
+static const io_dev_connector_t memmap_dev_connector = {
+	.dev_open = memmap_dev_open
+};
+
+
+static const io_dev_funcs_t memmap_dev_funcs = {
+	.type = device_type_memmap,
+	.open = memmap_block_open,
+	.seek = memmap_block_seek,
+	.size = memmap_block_len,
+	.read = memmap_block_read,
+	.write = memmap_block_write,
+	.close = memmap_block_close,
+	.dev_init = NULL,
+	.dev_close = memmap_dev_close,
+};
+
+
+/* No state associated with this device so structure can be const */
+static const io_dev_info_t memmap_dev_info = {
+	.funcs = &memmap_dev_funcs,
+	.info = (uintptr_t)NULL
+};
+
+
+/* Open a connection to the memmap device */
+static int memmap_dev_open(const uintptr_t dev_spec __unused,
+			   io_dev_info_t **dev_info)
+{
+	assert(dev_info != NULL);
+	*dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
+
+	return 0;
+}
+
+
+
+/* Close a connection to the memmap device */
+static int memmap_dev_close(io_dev_info_t *dev_info)
+{
+	/* NOP */
+	/* TODO: Consider tracking open files and cleaning them up here */
+	return 0;
+}
+
+
+/* Open a file on the memmap device */
+static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			     io_entity_t *entity)
+{
+	int result = -ENOMEM;
+	const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
+
+	/* Since we need to track open state for seek() we only allow one open
+	 * spec at a time. When we have dynamic memory we can malloc and set
+	 * entity->info.
+	 */
+	if (current_file.in_use == 0) {
+		assert(block_spec != NULL);
+		assert(entity != NULL);
+
+		current_file.in_use = 1;
+		current_file.base = block_spec->offset;
+		/* File cursor offset for seek and incremental reads etc. */
+		current_file.file_pos = 0;
+		current_file.size = block_spec->length;
+		entity->info = (uintptr_t)&current_file;
+		result = 0;
+	} else {
+		WARN("A Memmap device is already active. Close first.\n");
+	}
+
+	return result;
+}
+
+
+/* Seek to a particular file offset on the memmap device */
+static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+{
+	int result = -ENOENT;
+	file_state_t *fp;
+
+	/* We only support IO_SEEK_SET for the moment. */
+	if (mode == IO_SEEK_SET) {
+		assert(entity != NULL);
+
+		fp = (file_state_t *) entity->info;
+
+		/* Assert that new file position is valid */
+		assert((offset >= 0) && (offset < fp->size));
+
+		/* Reset file position */
+		fp->file_pos = offset;
+		result = 0;
+	}
+
+	return result;
+}
+
+
+/* Return the size of a file on the memmap device */
+static int memmap_block_len(io_entity_t *entity, size_t *length)
+{
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	*length = ((file_state_t *)entity->info)->size;
+
+	return 0;
+}
+
+
+/* Read data from a file on the memmap device */
+static int memmap_block_read(io_entity_t *entity, uintptr_t buffer,
+			     size_t length, size_t *length_read)
+{
+	file_state_t *fp;
+	size_t pos_after;
+
+	assert(entity != NULL);
+	assert(length_read != NULL);
+
+	fp = (file_state_t *) entity->info;
+
+	/* Assert that file position is valid for this read operation */
+	pos_after = fp->file_pos + length;
+	assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
+
+	memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
+
+	*length_read = length;
+
+	/* Set file position after read */
+	fp->file_pos = pos_after;
+
+	return 0;
+}
+
+
+/* Write data to a file on the memmap device */
+static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer,
+			      size_t length, size_t *length_written)
+{
+	file_state_t *fp;
+	size_t pos_after;
+
+	assert(entity != NULL);
+	assert(length_written != NULL);
+
+	fp = (file_state_t *) entity->info;
+
+	/* Assert that file position is valid for this write operation */
+	pos_after = fp->file_pos + length;
+	assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
+
+	memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
+
+	*length_written = length;
+
+	/* Set file position after write */
+	fp->file_pos = pos_after;
+
+	return 0;
+}
+
+
+/* Close a file on the memmap device */
+static int memmap_block_close(io_entity_t *entity)
+{
+	assert(entity != NULL);
+
+	entity->info = 0;
+
+	/* This would be a mem free() if we had malloc.*/
+	zeromem((void *)&current_file, sizeof(current_file));
+
+	return 0;
+}
+
+
+/* Exported functions */
+
+/* Register the memmap driver with the IO abstraction */
+int register_io_dev_memmap(const io_dev_connector_t **dev_con)
+{
+	int result;
+	assert(dev_con != NULL);
+
+	result = io_register_device(&memmap_dev_info);
+	if (result == 0)
+		*dev_con = &memmap_dev_connector;
+
+	return result;
+}
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
new file mode 100644
index 0000000..23d09c1
--- /dev/null
+++ b/drivers/io/io_semihosting.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+
+/* Identify the device type as semihosting */
+static io_type_t device_type_sh(void)
+{
+	return IO_TYPE_SEMIHOSTING;
+}
+
+
+/* Semi-hosting functions, device info and handle */
+
+static int sh_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int sh_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+		io_entity_t *entity);
+static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int sh_file_len(io_entity_t *entity, size_t *length);
+static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+		size_t *length_read);
+static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
+		size_t length, size_t *length_written);
+static int sh_file_close(io_entity_t *entity);
+
+static const io_dev_connector_t sh_dev_connector = {
+	.dev_open = sh_dev_open
+};
+
+
+static const io_dev_funcs_t sh_dev_funcs = {
+	.type = device_type_sh,
+	.open = sh_file_open,
+	.seek = sh_file_seek,
+	.size = sh_file_len,
+	.read = sh_file_read,
+	.write = sh_file_write,
+	.close = sh_file_close,
+	.dev_init = NULL,	/* NOP */
+	.dev_close = NULL,	/* NOP */
+};
+
+
+/* No state associated with this device so structure can be const */
+static const io_dev_info_t sh_dev_info = {
+	.funcs = &sh_dev_funcs,
+	.info = (uintptr_t)NULL
+};
+
+
+/* Open a connection to the semi-hosting device */
+static int sh_dev_open(const uintptr_t dev_spec __unused,
+		io_dev_info_t **dev_info)
+{
+	assert(dev_info != NULL);
+	*dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */
+	return 0;
+}
+
+
+/* Open a file on the semi-hosting device */
+static int sh_file_open(io_dev_info_t *dev_info __unused,
+		const uintptr_t spec, io_entity_t *entity)
+{
+	int result = -ENOENT;
+	long sh_result;
+	const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
+
+	assert(file_spec != NULL);
+	assert(entity != NULL);
+
+	sh_result = semihosting_file_open(file_spec->path, file_spec->mode);
+
+	if (sh_result > 0) {
+		entity->info = (uintptr_t)sh_result;
+		result = 0;
+	}
+	return result;
+}
+
+
+/* Seek to a particular file offset on the semi-hosting device */
+static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
+{
+	long file_handle, sh_result;
+
+	assert(entity != NULL);
+
+	file_handle = (long)entity->info;
+
+	sh_result = semihosting_file_seek(file_handle, offset);
+
+	return (sh_result == 0) ? 0 : -ENOENT;
+}
+
+
+/* Return the size of a file on the semi-hosting device */
+static int sh_file_len(io_entity_t *entity, size_t *length)
+{
+	int result = -ENOENT;
+
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	long sh_handle = (long)entity->info;
+	long sh_result = semihosting_file_length(sh_handle);
+
+	if (sh_result >= 0) {
+		result = 0;
+		*length = (size_t)sh_result;
+	}
+
+	return result;
+}
+
+
+/* Read data from a file on the semi-hosting device */
+static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+		size_t *length_read)
+{
+	int result = -ENOENT;
+	long sh_result;
+	size_t bytes = length;
+	long file_handle;
+
+	assert(entity != NULL);
+	assert(length_read != NULL);
+
+	file_handle = (long)entity->info;
+
+	sh_result = semihosting_file_read(file_handle, &bytes, buffer);
+
+	if (sh_result >= 0) {
+		*length_read = (bytes != length) ? bytes : length;
+		result = 0;
+	}
+
+	return result;
+}
+
+
+/* Write data to a file on the semi-hosting device */
+static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
+		size_t length, size_t *length_written)
+{
+	long sh_result;
+	long file_handle;
+	size_t bytes = length;
+
+	assert(entity != NULL);
+	assert(length_written != NULL);
+
+	file_handle = (long)entity->info;
+
+	sh_result = semihosting_file_write(file_handle, &bytes, buffer);
+
+	*length_written = length - bytes;
+
+	return (sh_result == 0) ? 0 : -ENOENT;
+}
+
+
+/* Close a file on the semi-hosting device */
+static int sh_file_close(io_entity_t *entity)
+{
+	long sh_result;
+	long file_handle;
+
+	assert(entity != NULL);
+
+	file_handle = (long)entity->info;
+
+	sh_result = semihosting_file_close(file_handle);
+
+	return (sh_result >= 0) ? 0 : -ENOENT;
+}
+
+
+/* Exported functions */
+
+/* Register the semi-hosting driver with the IO abstraction */
+int register_io_dev_sh(const io_dev_connector_t **dev_con)
+{
+	int result;
+	assert(dev_con != NULL);
+
+	result = io_register_device(&sh_dev_info);
+	if (result == 0)
+		*dev_con = &sh_dev_connector;
+
+	return result;
+}
diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c
new file mode 100644
index 0000000..e444f87
--- /dev/null
+++ b/drivers/io/io_storage.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+/* Storage for a fixed maximum number of IO entities, definable by platform */
+static io_entity_t entity_pool[MAX_IO_HANDLES];
+
+/* Simple way of tracking used storage - each entry is NULL or a pointer to an
+ * entity */
+static io_entity_t *entity_map[MAX_IO_HANDLES];
+
+/* Track number of allocated entities */
+static unsigned int entity_count;
+
+/* Array of fixed maximum of registered devices, definable by platform */
+static const io_dev_info_t *devices[MAX_IO_DEVICES];
+
+/* Number of currently registered devices */
+static unsigned int dev_count;
+
+/* Extra validation functions only used when asserts are enabled */
+#if ENABLE_ASSERTIONS
+
+/* Return a boolean value indicating whether a device connector is valid */
+static int is_valid_dev_connector(const io_dev_connector_t *dev_con)
+{
+	int result = (dev_con != NULL) && (dev_con->dev_open != NULL);
+	return result;
+}
+
+
+/* Return a boolean value indicating whether a device handle is valid */
+static int is_valid_dev(const uintptr_t dev_handle)
+{
+	const io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
+	int result = (dev != NULL) && (dev->funcs != NULL) &&
+			(dev->funcs->type != NULL) &&
+			(dev->funcs->type() < IO_TYPE_MAX);
+	return result;
+}
+
+
+/* Return a boolean value indicating whether an IO entity is valid */
+static int is_valid_entity(const uintptr_t handle)
+{
+	const io_entity_t *entity = (io_entity_t *)handle;
+	int result = (entity != NULL) &&
+			(is_valid_dev((uintptr_t)entity->dev_handle));
+	return result;
+}
+
+
+/* Return a boolean value indicating whether a seek mode is valid */
+static int is_valid_seek_mode(io_seek_mode_t mode)
+{
+	return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX));
+}
+
+#endif /* ENABLE_ASSERTIONS */
+/* End of extra validation functions only used when asserts are enabled */
+
+
+/* Open a connection to a specific device */
+static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
+		io_dev_info_t **dev_info)
+{
+	int result;
+	assert(dev_info != NULL);
+	assert(is_valid_dev_connector(dev_con));
+
+	result = dev_con->dev_open(dev_spec, dev_info);
+	return result;
+}
+
+
+/* Set a handle to track an entity */
+static void set_handle(uintptr_t *handle, io_entity_t *entity)
+{
+	assert(handle != NULL);
+	*handle = (uintptr_t)entity;
+}
+
+
+/* Locate an entity in the pool, specified by address */
+static int find_first_entity(const io_entity_t *entity, unsigned int *index_out)
+{
+	int result = -ENOENT;
+	for (unsigned int index = 0; index < MAX_IO_HANDLES; ++index) {
+		if (entity_map[index] == entity) {
+			result = 0;
+			*index_out = index;
+			break;
+		}
+	}
+	return result;
+}
+
+
+/* Allocate an entity from the pool and return a pointer to it */
+static int allocate_entity(io_entity_t **entity)
+{
+	int result = -ENOMEM;
+	assert(entity != NULL);
+
+	if (entity_count < MAX_IO_HANDLES) {
+		unsigned int index = 0;
+		result = find_first_entity(NULL, &index);
+		assert(result == 0);
+		*entity = entity_map[index] = &entity_pool[index];
+		++entity_count;
+	}
+
+	return result;
+}
+
+
+/* Release an entity back to the pool */
+static int free_entity(const io_entity_t *entity)
+{
+	int result;
+	unsigned int index = 0;
+	assert(entity != NULL);
+
+	result = find_first_entity(entity, &index);
+	if (result ==  0) {
+		entity_map[index] = NULL;
+		--entity_count;
+	}
+
+	return result;
+}
+
+
+/* Exported API */
+
+/* Register a device driver */
+int io_register_device(const io_dev_info_t *dev_info)
+{
+	int result = -ENOMEM;
+	assert(dev_info != NULL);
+
+	if (dev_count < MAX_IO_DEVICES) {
+		devices[dev_count] = dev_info;
+		dev_count++;
+		result = 0;
+	}
+
+	return result;
+}
+
+
+/* Open a connection to an IO device */
+int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
+		uintptr_t *handle)
+{
+	int result;
+	assert(handle != NULL);
+
+	result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle);
+	return result;
+}
+
+
+/* Initialise an IO device explicitly - to permit lazy initialisation or
+ * re-initialisation */
+int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params)
+{
+	int result = 0;
+	assert(dev_handle != (uintptr_t)NULL);
+	assert(is_valid_dev(dev_handle));
+
+	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
+
+	/* Absence of registered function implies NOP here */
+	if (dev->funcs->dev_init != NULL) {
+		result = dev->funcs->dev_init(dev, init_params);
+	}
+
+	return result;
+}
+
+/* Close a connection to a device */
+int io_dev_close(uintptr_t dev_handle)
+{
+	int result = 0;
+	assert(dev_handle != (uintptr_t)NULL);
+	assert(is_valid_dev(dev_handle));
+
+	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
+
+	/* Absence of registered function implies NOP here */
+	if (dev->funcs->dev_close != NULL) {
+		result = dev->funcs->dev_close(dev);
+	}
+
+	return result;
+}
+
+
+/* Synchronous operations */
+
+
+/* Open an IO entity */
+int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
+{
+	int result;
+	assert((spec != (uintptr_t)NULL) && (handle != NULL));
+	assert(is_valid_dev(dev_handle));
+
+	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
+	io_entity_t *entity;
+
+	result = allocate_entity(&entity);
+
+	if (result == 0) {
+		assert(dev->funcs->open != NULL);
+		result = dev->funcs->open(dev, spec, entity);
+
+		if (result == 0) {
+			entity->dev_handle = dev;
+			set_handle(handle, entity);
+		} else
+			free_entity(entity);
+	}
+	return result;
+}
+
+
+/* Seek to a specific position in an IO entity */
+int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset)
+{
+	int result = -ENODEV;
+	assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
+
+	io_entity_t *entity = (io_entity_t *)handle;
+
+	io_dev_info_t *dev = entity->dev_handle;
+
+	if (dev->funcs->seek != NULL)
+		result = dev->funcs->seek(entity, mode, offset);
+
+	return result;
+}
+
+
+/* Determine the length of an IO entity */
+int io_size(uintptr_t handle, size_t *length)
+{
+	int result = -ENODEV;
+	assert(is_valid_entity(handle) && (length != NULL));
+
+	io_entity_t *entity = (io_entity_t *)handle;
+
+	io_dev_info_t *dev = entity->dev_handle;
+
+	if (dev->funcs->size != NULL)
+		result = dev->funcs->size(entity, length);
+
+	return result;
+}
+
+
+/* Read data from an IO entity */
+int io_read(uintptr_t handle,
+		uintptr_t buffer,
+		size_t length,
+		size_t *length_read)
+{
+	int result = -ENODEV;
+	assert(is_valid_entity(handle));
+
+	io_entity_t *entity = (io_entity_t *)handle;
+
+	io_dev_info_t *dev = entity->dev_handle;
+
+	if (dev->funcs->read != NULL)
+		result = dev->funcs->read(entity, buffer, length, length_read);
+
+	return result;
+}
+
+
+/* Write data to an IO entity */
+int io_write(uintptr_t handle,
+		const uintptr_t buffer,
+		size_t length,
+		size_t *length_written)
+{
+	int result = -ENODEV;
+	assert(is_valid_entity(handle));
+
+	io_entity_t *entity = (io_entity_t *)handle;
+
+	io_dev_info_t *dev = entity->dev_handle;
+
+	if (dev->funcs->write != NULL) {
+		result = dev->funcs->write(entity, buffer, length,
+				length_written);
+	}
+
+	return result;
+}
+
+
+/* Close an IO entity */
+int io_close(uintptr_t handle)
+{
+	int result = 0;
+	assert(is_valid_entity(handle));
+
+	io_entity_t *entity = (io_entity_t *)handle;
+
+	io_dev_info_t *dev = entity->dev_handle;
+
+	/* Absence of registered function implies NOP here */
+	if (dev->funcs->close != NULL)
+		result = dev->funcs->close(entity);
+
+	/* Ignore improbable free_entity failure */
+	(void)free_entity(entity);
+
+	return result;
+}
diff --git a/drivers/marvell/amb_adec.c b/drivers/marvell/amb_adec.c
new file mode 100644
index 0000000..1f67105
--- /dev/null
+++ b/drivers/marvell/amb_adec.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT			(0x1)
+
+#define MVEBU_AMB_ADEC_OFFSET		(0x70ff00)
+
+#define AMB_WIN_CR_OFFSET(win)		(amb_base + 0x0 + (0x8 * win))
+#define AMB_ATTR_OFFSET			8
+#define AMB_ATTR_MASK			0xFF
+#define AMB_SIZE_OFFSET			16
+#define AMB_SIZE_MASK			0xFF
+
+#define AMB_WIN_BASE_OFFSET(win)	(amb_base + 0x4 + (0x8 * win))
+#define AMB_BASE_OFFSET			16
+#define AMB_BASE_ADDR_MASK		((1 << (32 - AMB_BASE_OFFSET)) - 1)
+
+#define AMB_WIN_ALIGNMENT_64K		(0x10000)
+#define AMB_WIN_ALIGNMENT_1M		(0x100000)
+
+uintptr_t amb_base;
+
+static void amb_check_win(struct addr_map_win *win, uint32_t win_num)
+{
+	uint32_t base_addr;
+
+	/* make sure the base address is in 16-bit range */
+	if (win->base_addr > AMB_BASE_ADDR_MASK) {
+		WARN("Window %d: base address is too big 0x%llx\n",
+		       win_num, win->base_addr);
+		win->base_addr = AMB_BASE_ADDR_MASK;
+		WARN("Set the base address to 0x%llx\n", win->base_addr);
+	}
+
+	base_addr  = win->base_addr << AMB_BASE_OFFSET;
+	/* for AMB The base is always 1M aligned */
+	/* check if address is aligned to 1M */
+	if (IS_NOT_ALIGN(base_addr, AMB_WIN_ALIGNMENT_1M)) {
+		win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M);
+		WARN("Window %d: base address unaligned to 0x%x\n",
+		       win_num, AMB_WIN_ALIGNMENT_1M);
+		WARN("Align up the base address to 0x%llx\n", win->base_addr);
+	}
+
+	/* size parameter validity check */
+	if (!IS_POWER_OF_2(win->win_size)) {
+		WARN("Window %d: window size is not power of 2 (0x%llx)\n",
+		       win_num, win->win_size);
+		win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size);
+		WARN("Rounding size to 0x%llx\n", win->win_size);
+	}
+}
+
+static void amb_enable_win(struct addr_map_win *win, uint32_t win_num)
+{
+	uint32_t ctrl, base, size;
+
+	/*
+	 * size is 64KB granularity.
+	 * The number of ones specifies the size of the
+	 * window in 64 KB granularity. 0 is 64KB
+	 */
+	size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1;
+	ctrl = (size << AMB_SIZE_OFFSET) | (win->target_id << AMB_ATTR_OFFSET);
+	base = win->base_addr << AMB_BASE_OFFSET;
+
+	mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base);
+	mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
+
+	/* enable window after configuring window size (and attributes) */
+	ctrl |= WIN_ENABLE_BIT;
+	mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl);
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_amb_adec(void)
+{
+	uint32_t ctrl, base, win_id, attr;
+	uint32_t size, size_count;
+
+	/* Dump all AMB windows */
+	printf("bank  attribute     base          size\n");
+	printf("--------------------------------------------\n");
+	for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
+		ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
+		if (ctrl & WIN_ENABLE_BIT) {
+			base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id));
+			attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK;
+			size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK;
+			size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K;
+			printf("amb   0x%04x        0x%08x    0x%08x\n",
+			       attr, base, size);
+		}
+	}
+}
+#endif
+
+int init_amb_adec(uintptr_t base)
+{
+	struct addr_map_win *win;
+	uint32_t win_id, win_reg;
+	uint32_t win_count;
+
+	INFO("Initializing AXI to MBus Bridge Address decoding\n");
+
+	/* Get the base address of the AMB address decoding */
+	amb_base = base + MVEBU_AMB_ADEC_OFFSET;
+
+	/* Get the array of the windows and its size */
+	marvell_get_amb_memory_map(&win, &win_count, base);
+	if (win_count <= 0)
+		INFO("no windows configurations found\n");
+
+	if (win_count > AMB_MAX_WIN_ID) {
+		INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID);
+		return 0;
+	}
+
+	/* disable all AMB windows */
+	for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) {
+		win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id));
+		win_reg &= ~WIN_ENABLE_BIT;
+		mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg);
+	}
+
+	/* enable relevant windows */
+	for (win_id = 0; win_id < win_count; win_id++, win++) {
+		amb_check_win(win, win_id);
+		amb_enable_win(win, win_id);
+	}
+
+#ifdef DEBUG_ADDR_MAP
+	dump_amb_adec();
+#endif
+
+	INFO("Done AXI to MBus Bridge Address decoding Initializing\n");
+
+	return 0;
+}
diff --git a/drivers/marvell/ap807_clocks_init.c b/drivers/marvell/ap807_clocks_init.c
new file mode 100644
index 0000000..04c256b
--- /dev/null
+++ b/drivers/marvell/ap807_clocks_init.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/aro.h>
+#include <lib/mmio.h>
+
+#include <a8k_plat_def.h>
+
+/* Notify bootloader on DRAM setup */
+#define AP807_CPU_ARO_CTRL(cluster)	\
+			(MVEBU_RFU_BASE + 0x82A8 + (0xA58 * (cluster)))
+
+/* 0 - ARO clock is enabled, 1 - ARO clock is disabled */
+#define AP807_CPU_ARO_CLK_EN_OFFSET	0
+#define AP807_CPU_ARO_CLK_EN_MASK	(0x1 << AP807_CPU_ARO_CLK_EN_OFFSET)
+
+/* 0 - ARO is the clock source, 1 - PLL is the clock source */
+#define AP807_CPU_ARO_SEL_PLL_OFFSET	5
+#define AP807_CPU_ARO_SEL_PLL_MASK	(0x1 << AP807_CPU_ARO_SEL_PLL_OFFSET)
+
+/* AP807 clusters count */
+#define AP807_CLUSTER_NUM		2
+
+/* PLL frequency values */
+#define PLL_FREQ_1200			0x2AE5F002 /* 1200 */
+#define PLL_FREQ_2000			0x2FC9F002 /* 2000 */
+#define PLL_FREQ_2200			0x2AC57001 /* 2200 */
+#define PLL_FREQ_2400			0x2AE5F001 /* 2400 */
+
+/* CPU PLL control registers */
+#define AP807_CPU_PLL_CTRL(cluster)	\
+			(MVEBU_RFU_BASE + 0x82E0 + (0x8 * (cluster)))
+
+#define AP807_CPU_PLL_PARAM(cluster)	AP807_CPU_PLL_CTRL(cluster)
+#define AP807_CPU_PLL_CFG(cluster)	(AP807_CPU_PLL_CTRL(cluster) + 0x4)
+#define AP807_CPU_PLL_CFG_BYPASS_MODE	(0x1)
+#define AP807_CPU_PLL_CFG_USE_REG_FILE	(0x1 << 9)
+
+static void pll_set_freq(unsigned int freq_val)
+{
+	int i;
+
+	for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) {
+		mmio_write_32(AP807_CPU_PLL_CFG(i),
+			      AP807_CPU_PLL_CFG_USE_REG_FILE);
+		mmio_write_32(AP807_CPU_PLL_CFG(i),
+			      AP807_CPU_PLL_CFG_USE_REG_FILE |
+			      AP807_CPU_PLL_CFG_BYPASS_MODE);
+		mmio_write_32(AP807_CPU_PLL_PARAM(i), freq_val);
+		mmio_write_32(AP807_CPU_PLL_CFG(i),
+			      AP807_CPU_PLL_CFG_USE_REG_FILE);
+	}
+}
+
+/* Switch to ARO from PLL in ap807 */
+static void aro_to_pll(void)
+{
+	unsigned int reg;
+	int i;
+
+	for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) {
+		/* switch from ARO to PLL */
+		reg = mmio_read_32(AP807_CPU_ARO_CTRL(i));
+		reg |= AP807_CPU_ARO_SEL_PLL_MASK;
+		mmio_write_32(AP807_CPU_ARO_CTRL(i), reg);
+
+		mdelay(100);
+
+		/* disable ARO clk driver */
+		reg = mmio_read_32(AP807_CPU_ARO_CTRL(i));
+		reg |= (AP807_CPU_ARO_CLK_EN_MASK);
+		mmio_write_32(AP807_CPU_ARO_CTRL(i), reg);
+	}
+}
+
+/* switch from ARO to PLL
+ * in case of default frequency option, configure PLL registers
+ * to be aligned with new default frequency.
+ */
+void ap807_clocks_init(unsigned int freq_option)
+{
+	/* Switch from ARO to PLL */
+	aro_to_pll();
+
+	/* Modifications in frequency table:
+	 * 0x0: 764x: change to 2000 MHz.
+	 * 0x2: 744x change to 1800 MHz, 764x change to 2200/2400.
+	 * 0x3: 3900/744x/764x change to 1200 MHz.
+	 */
+	switch (freq_option) {
+	case CPU_2000_DDR_1200_RCLK_1200:
+		pll_set_freq(PLL_FREQ_2000);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/drivers/marvell/cache_llc.c b/drivers/marvell/cache_llc.c
new file mode 100644
index 0000000..3df93a4
--- /dev/null
+++ b/drivers/marvell/cache_llc.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* LLC driver is the Last Level Cache (L3C) driver
+ * for Marvell SoCs in AP806, AP807, and AP810
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/ccu.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#define CCU_HTC_CR(ap_index)		(MVEBU_CCU_BASE(ap_index) + 0x200)
+#define CCU_SET_POC_OFFSET		5
+
+extern void ca72_l2_enable_unique_clean(void);
+
+void llc_cache_sync(int ap_index)
+{
+	mmio_write_32(LLC_SYNC(ap_index), 0);
+	/* Atomic write, no need to wait */
+}
+
+void llc_flush_all(int ap_index)
+{
+	mmio_write_32(L2X0_CLEAN_INV_WAY(ap_index), LLC_WAY_MASK);
+	llc_cache_sync(ap_index);
+}
+
+void llc_clean_all(int ap_index)
+{
+	mmio_write_32(L2X0_CLEAN_WAY(ap_index), LLC_WAY_MASK);
+	llc_cache_sync(ap_index);
+}
+
+void llc_inv_all(int ap_index)
+{
+	mmio_write_32(L2X0_INV_WAY(ap_index), LLC_WAY_MASK);
+	llc_cache_sync(ap_index);
+}
+
+void llc_disable(int ap_index)
+{
+	llc_flush_all(ap_index);
+	mmio_write_32(LLC_CTRL(ap_index), 0);
+	dsbishst();
+}
+
+void llc_enable(int ap_index, int excl_mode)
+{
+	uint32_t val;
+
+	dsbsy();
+	llc_inv_all(ap_index);
+	dsbsy();
+
+	val = LLC_CTRL_EN;
+	if (excl_mode)
+		val |= LLC_EXCLUSIVE_EN;
+
+	mmio_write_32(LLC_CTRL(ap_index), val);
+	dsbsy();
+}
+
+int llc_is_exclusive(int ap_index)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(LLC_CTRL(ap_index));
+
+	if ((reg & (LLC_CTRL_EN | LLC_EXCLUSIVE_EN)) ==
+		   (LLC_CTRL_EN | LLC_EXCLUSIVE_EN))
+		return 1;
+
+	return 0;
+}
+
+void llc_runtime_enable(int ap_index)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(LLC_CTRL(ap_index));
+	if (reg & LLC_CTRL_EN)
+		return;
+
+	INFO("Enabling LLC\n");
+
+	/*
+	 * Enable L2 UniqueClean evictions with data
+	 *  Note: this configuration assumes that LLC is configured
+	 *	  in exclusive mode.
+	 *	  Later on in the code this assumption will be validated
+	 */
+	ca72_l2_enable_unique_clean();
+	llc_enable(ap_index, 1);
+
+	/* Set point of coherency to DDR.
+	 * This is required by units which have SW cache coherency
+	 */
+	reg = mmio_read_32(CCU_HTC_CR(ap_index));
+	reg |= (0x1 << CCU_SET_POC_OFFSET);
+	mmio_write_32(CCU_HTC_CR(ap_index), reg);
+}
diff --git a/drivers/marvell/ccu.c b/drivers/marvell/ccu.c
new file mode 100644
index 0000000..1e4ab44
--- /dev/null
+++ b/drivers/marvell/ccu.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#include <common/debug.h>
+#include <drivers/marvell/ccu.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT			(0x1)
+/* Physical address of the base of the window = {AddrLow[19:0],20'h0} */
+#define ADDRESS_SHIFT			(20 - 4)
+#define ADDRESS_MASK			(0xFFFFFFF0)
+#define CCU_WIN_ALIGNMENT		(0x100000)
+
+#define IS_DRAM_TARGET(tgt)		((((tgt) == DRAM_0_TID) || \
+					((tgt) == DRAM_1_TID) || \
+					((tgt) == RAR_TID)) ? 1 : 0)
+
+/* For storage of CR, SCR, ALR, AHR abd GCR */
+static uint32_t ccu_regs_save[MVEBU_CCU_MAX_WINS * 4 + 1];
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_ccu(int ap_index)
+{
+	uint32_t win_id, win_cr, alr, ahr;
+	uint8_t target_id;
+	uint64_t start, end;
+
+	/* Dump all AP windows */
+	printf("\tbank  target     start              end\n");
+	printf("\t----------------------------------------------------\n");
+	for (win_id = 0; win_id < MVEBU_CCU_MAX_WINS; win_id++) {
+		win_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+		if (win_cr & WIN_ENABLE_BIT) {
+			target_id = (win_cr >> CCU_TARGET_ID_OFFSET) &
+				     CCU_TARGET_ID_MASK;
+			alr = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index,
+							      win_id));
+			ahr = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_index,
+							      win_id));
+			start = ((uint64_t)alr << ADDRESS_SHIFT);
+			end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
+			printf("\tccu    %02x     0x%016llx 0x%016llx\n",
+			       target_id, start, end);
+		}
+	}
+	win_cr = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_index));
+	target_id = (win_cr >> CCU_GCR_TARGET_OFFSET) & CCU_GCR_TARGET_MASK;
+	printf("\tccu   GCR %d - all other transactions\n", target_id);
+}
+#endif
+
+void ccu_win_check(struct addr_map_win *win)
+{
+	/* check if address is aligned to 1M */
+	if (IS_NOT_ALIGN(win->base_addr, CCU_WIN_ALIGNMENT)) {
+		win->base_addr = ALIGN_UP(win->base_addr, CCU_WIN_ALIGNMENT);
+		NOTICE("%s: Align up the base address to 0x%llx\n",
+		       __func__, win->base_addr);
+	}
+
+	/* size parameter validity check */
+	if (IS_NOT_ALIGN(win->win_size, CCU_WIN_ALIGNMENT)) {
+		win->win_size = ALIGN_UP(win->win_size, CCU_WIN_ALIGNMENT);
+		NOTICE("%s: Aligning size to 0x%llx\n",
+		       __func__, win->win_size);
+	}
+}
+
+void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id)
+{
+	uint32_t ccu_win_reg;
+	uint32_t alr, ahr;
+	uint64_t end_addr;
+
+	if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) {
+		ERROR("Enabling wrong CCU window %d!\n", win_id);
+		return;
+	}
+
+	end_addr = (win->base_addr + win->win_size - 1);
+	alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+	ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+
+	mmio_write_32(CCU_WIN_ALR_OFFSET(ap_index, win_id), alr);
+	mmio_write_32(CCU_WIN_AHR_OFFSET(ap_index, win_id), ahr);
+
+	ccu_win_reg = WIN_ENABLE_BIT;
+	ccu_win_reg |= (win->target_id & CCU_TARGET_ID_MASK)
+			<< CCU_TARGET_ID_OFFSET;
+	mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), ccu_win_reg);
+}
+
+static void ccu_disable_win(int ap_index, uint32_t win_id)
+{
+	uint32_t win_reg;
+
+	if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) {
+		ERROR("Disabling wrong CCU window %d!\n", win_id);
+		return;
+	}
+
+	win_reg = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+	win_reg &= ~WIN_ENABLE_BIT;
+	mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), win_reg);
+}
+
+/* Insert/Remove temporary window for using the out-of reset default
+ * CPx base address to access the CP configuration space prior to
+ * the further base address update in accordance with address mapping
+ * design.
+ *
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
+{
+	uint32_t win_id;
+
+	for (int i = 0; i < size; i++) {
+		win_id = MVEBU_CCU_MAX_WINS - 1 - i;
+		ccu_win_check(win);
+		ccu_enable_win(ap_index, win, win_id);
+		win++;
+	}
+}
+
+/*
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
+{
+	uint32_t win_id;
+
+	for (int i = 0; i < size; i++) {
+		uint64_t base;
+		uint32_t target;
+
+		win_id = MVEBU_CCU_MAX_WINS - 1 - i;
+
+		target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+		target >>= CCU_TARGET_ID_OFFSET;
+		target &= CCU_TARGET_ID_MASK;
+
+		base = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index, win_id));
+		base <<= ADDRESS_SHIFT;
+
+		if ((win->target_id != target) || (win->base_addr != base)) {
+			ERROR("%s: Trying to remove bad window-%d!\n",
+			      __func__, win_id);
+			continue;
+		}
+		ccu_disable_win(ap_index, win_id);
+		win++;
+	}
+}
+
+/* Returns current DRAM window target (DRAM_0_TID, DRAM_1_TID, RAR_TID)
+ * NOTE: Call only once for each AP.
+ * The AP0 DRAM window is located at index 2 only at the BL31 execution start.
+ * Then it relocated to index 1 for matching the rest of APs DRAM settings.
+ * Calling this function after relocation will produce wrong results on AP0
+ */
+static uint32_t ccu_dram_target_get(int ap_index)
+{
+	/* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
+	 * All the rest of detected APs will use window at index 1.
+	 * The AP0 DRAM window is moved from index 2 to 1 during
+	 * init_ccu() execution.
+	 */
+	const uint32_t win_id = (ap_index == 0) ? 2 : 1;
+	uint32_t target;
+
+	target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+	target >>= CCU_TARGET_ID_OFFSET;
+	target &= CCU_TARGET_ID_MASK;
+
+	return target;
+}
+
+void ccu_dram_target_set(int ap_index, uint32_t target)
+{
+	/* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
+	 * All the rest of detected APs will use window at index 1.
+	 * The AP0 DRAM window is moved from index 2 to 1
+	 * during init_ccu() execution.
+	 */
+	const uint32_t win_id = (ap_index == 0) ? 2 : 1;
+	uint32_t dram_cr;
+
+	dram_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id));
+	dram_cr &= ~(CCU_TARGET_ID_MASK << CCU_TARGET_ID_OFFSET);
+	dram_cr |= (target & CCU_TARGET_ID_MASK) << CCU_TARGET_ID_OFFSET;
+	mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), dram_cr);
+}
+
+/* Setup CCU DRAM window and enable it */
+void ccu_dram_win_config(int ap_index, struct addr_map_win *win)
+{
+#if IMAGE_BLE /* BLE */
+	/* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
+	 * Since the BootROM is not accessing DRAM at BLE stage,
+	 * the DRAM window can be temporarely disabled.
+	 */
+	const uint32_t win_id = (ap_index == 0) ? 2 : 1;
+#else /* end of BLE */
+	/* At the ccu_init() execution stage, DRAM windows of all APs
+	 * are arranged at index 1.
+	 * The AP0 still has the old window BootROM DRAM at index 2, so
+	 * the window-1 can be safely disabled without breaking the DRAM access.
+	 */
+	const uint32_t win_id = 1;
+#endif
+
+	ccu_disable_win(ap_index, win_id);
+	/* enable write secure (and clear read secure) */
+	mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id),
+		      CCU_WIN_ENA_WRITE_SECURE);
+	ccu_win_check(win);
+	ccu_enable_win(ap_index, win, win_id);
+}
+
+/* Save content of CCU window + GCR */
+static void ccu_save_win_range(int ap_id, int win_first,
+			       int win_last, uint32_t *buffer)
+{
+	int win_id, idx;
+	/* Save CCU */
+	for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+		buffer[idx++] = mmio_read_32(CCU_WIN_CR_OFFSET(ap_id, win_id));
+		buffer[idx++] = mmio_read_32(CCU_WIN_SCR_OFFSET(ap_id, win_id));
+		buffer[idx++] = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_id, win_id));
+		buffer[idx++] = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_id, win_id));
+	}
+	buffer[idx] = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_id));
+}
+
+/* Restore content of CCU window + GCR */
+static void ccu_restore_win_range(int ap_id, int win_first,
+				  int win_last, uint32_t *buffer)
+{
+	int win_id, idx;
+	/* Restore CCU */
+	for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+		mmio_write_32(CCU_WIN_CR_OFFSET(ap_id, win_id),  buffer[idx++]);
+		mmio_write_32(CCU_WIN_SCR_OFFSET(ap_id, win_id), buffer[idx++]);
+		mmio_write_32(CCU_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]);
+		mmio_write_32(CCU_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]);
+	}
+	mmio_write_32(CCU_WIN_GCR_OFFSET(ap_id), buffer[idx]);
+}
+
+void ccu_save_win_all(int ap_id)
+{
+	ccu_save_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save);
+}
+
+void ccu_restore_win_all(int ap_id)
+{
+	ccu_restore_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save);
+}
+
+int init_ccu(int ap_index)
+{
+	struct addr_map_win *win, *dram_win;
+	uint32_t win_id, win_reg;
+	uint32_t win_count, array_id;
+	uint32_t dram_target;
+#if IMAGE_BLE
+	/* In BootROM context CCU Window-1
+	 * has SRAM_TID target and should not be disabled
+	 */
+	const uint32_t win_start = 2;
+#else
+	const uint32_t win_start = 1;
+#endif
+
+	INFO("Initializing CCU Address decoding\n");
+
+	/* Get the array of the windows and fill the map data */
+	marvell_get_ccu_memory_map(ap_index, &win, &win_count);
+	if (win_count <= 0) {
+		INFO("No windows configurations found\n");
+	} else if (win_count > (MVEBU_CCU_MAX_WINS - 1)) {
+		ERROR("CCU mem map array > than max available windows (%d)\n",
+		      MVEBU_CCU_MAX_WINS);
+		win_count = MVEBU_CCU_MAX_WINS;
+	}
+
+	/* Need to set GCR to DRAM before all CCU windows are disabled for
+	 * securing the normal access to DRAM location, which the ATF is running
+	 * from. Once all CCU windows are set, which have to include the
+	 * dedicated DRAM window as well, the GCR can be switched to the target
+	 * defined by the platform configuration.
+	 */
+	dram_target = ccu_dram_target_get(ap_index);
+	win_reg = (dram_target & CCU_GCR_TARGET_MASK) << CCU_GCR_TARGET_OFFSET;
+	mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg);
+
+	/* If the DRAM window was already configured at the BLE stage,
+	 * only the window target considered valid, the address range should be
+	 * updated according to the platform configuration.
+	 */
+	for (dram_win = win, array_id = 0; array_id < win_count;
+	     array_id++, dram_win++) {
+		if (IS_DRAM_TARGET(dram_win->target_id)) {
+			dram_win->target_id = dram_target;
+			break;
+		}
+	}
+
+	/* Disable all AP CCU windows
+	 * Window-0 is always bypassed since it already contains
+	 * data allowing the internal configuration space access
+	 */
+	for (win_id = win_start; win_id < MVEBU_CCU_MAX_WINS; win_id++) {
+		ccu_disable_win(ap_index, win_id);
+		/* enable write secure (and clear read secure) */
+		mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id),
+			      CCU_WIN_ENA_WRITE_SECURE);
+	}
+
+	/* win_id is the index of the current ccu window
+	 * array_id is the index of the current memory map window entry
+	 */
+	for (win_id = win_start, array_id = 0;
+	    ((win_id < MVEBU_CCU_MAX_WINS) && (array_id < win_count));
+	    win_id++) {
+		ccu_win_check(win);
+		ccu_enable_win(ap_index, win, win_id);
+		win++;
+		array_id++;
+	}
+
+	/* Get & set the default target according to board topology */
+	win_reg = (marvell_get_ccu_gcr_target(ap_index) & CCU_GCR_TARGET_MASK)
+		   << CCU_GCR_TARGET_OFFSET;
+	mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg);
+
+#ifdef DEBUG_ADDR_MAP
+	dump_ccu(ap_index);
+#endif
+
+	INFO("Done CCU Address decoding Initializing\n");
+
+	return 0;
+}
diff --git a/drivers/marvell/comphy.h b/drivers/marvell/comphy.h
new file mode 100644
index 0000000..fab564e
--- /dev/null
+++ b/drivers/marvell/comphy.h
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Driver for COMPHY unit that is part or Marvell A8K SoCs */
+
+#ifndef COMPHY_H
+#define COMPHY_H
+
+/* COMPHY registers */
+#define COMMON_PHY_CFG1_REG			0x0
+#define COMMON_PHY_CFG1_PWR_UP_OFFSET		1
+#define COMMON_PHY_CFG1_PWR_UP_MASK		\
+				(0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET)
+#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET	2
+#define COMMON_PHY_CFG1_PIPE_SELECT_MASK	\
+				(0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET)
+#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET	13
+#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK	\
+				(0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET)
+#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET	14
+#define COMMON_PHY_CFG1_CORE_RSTN_MASK		\
+				(0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET)
+#define COMMON_PHY_PHY_MODE_OFFSET		15
+#define COMMON_PHY_PHY_MODE_MASK		\
+				(0x1 << COMMON_PHY_PHY_MODE_OFFSET)
+
+#define COMMON_SELECTOR_PHY_OFFSET			0x140
+#define COMMON_SELECTOR_PIPE_OFFSET			0x144
+
+#define COMMON_PHY_SD_CTRL1				0x148
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET	0
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK	0xFFFF
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET		24
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK		\
+				(0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET)
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET		25
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK		\
+				(0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET)
+
+#define DFX_DEV_GEN_CTRL12			0x80
+#define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET		7
+#define DFX_DEV_GEN_PCIE_CLK_SRC_MASK		\
+				(0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET)
+
+/* HPIPE register */
+#define HPIPE_PWR_PLL_REG			0x4
+#define HPIPE_PWR_PLL_REF_FREQ_OFFSET		0
+#define HPIPE_PWR_PLL_REF_FREQ_MASK		\
+				(0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET)
+#define HPIPE_PWR_PLL_PHY_MODE_OFFSET		5
+#define HPIPE_PWR_PLL_PHY_MODE_MASK		\
+				(0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+
+#define HPIPE_DFE_REG0				0x01C
+#define HPIPE_DFE_RES_FORCE_OFFSET		15
+#define HPIPE_DFE_RES_FORCE_MASK		\
+				(0x1 << HPIPE_DFE_RES_FORCE_OFFSET)
+
+#define HPIPE_G2_SET_1_REG			0x040
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET	0
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK	\
+				(0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET	3
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK	\
+				(0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET	6
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK	\
+				(0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET)
+
+#define HPIPE_G3_SETTINGS_1_REG			0x048
+#define HPIPE_G3_RX_SELMUPI_OFFSET		0
+#define HPIPE_G3_RX_SELMUPI_MASK		\
+				(0x7 << HPIPE_G3_RX_SELMUPI_OFFSET)
+#define HPIPE_G3_RX_SELMUPF_OFFSET		3
+#define HPIPE_G3_RX_SELMUPF_MASK		\
+				(0x7 << HPIPE_G3_RX_SELMUPF_OFFSET)
+#define HPIPE_G3_SETTING_BIT_OFFSET		13
+#define HPIPE_G3_SETTING_BIT_MASK		\
+				(0x1 << HPIPE_G3_SETTING_BIT_OFFSET)
+
+#define HPIPE_INTERFACE_REG			0x94
+#define HPIPE_INTERFACE_GEN_MAX_OFFSET		10
+#define HPIPE_INTERFACE_GEN_MAX_MASK		\
+				(0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET)
+#define HPIPE_INTERFACE_DET_BYPASS_OFFSET	12
+#define HPIPE_INTERFACE_DET_BYPASS_MASK		\
+				(0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET)
+#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET	14
+#define HPIPE_INTERFACE_LINK_TRAIN_MASK		\
+				(0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET)
+
+#define HPIPE_VDD_CAL_CTRL_REG			0x114
+#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET		5
+#define HPIPE_EXT_SELLV_RXSAMPL_MASK		\
+				(0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET)
+
+#define HPIPE_PCIE_REG0				0x120
+#define HPIPE_PCIE_IDLE_SYNC_OFFSET		12
+#define HPIPE_PCIE_IDLE_SYNC_MASK		\
+				(0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET)
+#define HPIPE_PCIE_SEL_BITS_OFFSET		13
+#define HPIPE_PCIE_SEL_BITS_MASK		\
+				(0x3 << HPIPE_PCIE_SEL_BITS_OFFSET)
+
+#define HPIPE_LANE_ALIGN_REG			0x124
+#define HPIPE_LANE_ALIGN_OFF_OFFSET		12
+#define HPIPE_LANE_ALIGN_OFF_MASK		\
+				(0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET)
+
+#define HPIPE_MISC_REG				0x13C
+#define HPIPE_MISC_CLK100M_125M_OFFSET		4
+#define HPIPE_MISC_CLK100M_125M_MASK		\
+				(0x1 << HPIPE_MISC_CLK100M_125M_OFFSET)
+#define HPIPE_MISC_ICP_FORCE_OFFSET		5
+#define HPIPE_MISC_ICP_FORCE_MASK		\
+				(0x1 << HPIPE_MISC_ICP_FORCE_OFFSET)
+#define HPIPE_MISC_TXDCLK_2X_OFFSET		6
+#define HPIPE_MISC_TXDCLK_2X_MASK		\
+				(0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET)
+#define HPIPE_MISC_CLK500_EN_OFFSET		7
+#define HPIPE_MISC_CLK500_EN_MASK		\
+				(0x1 << HPIPE_MISC_CLK500_EN_OFFSET)
+#define HPIPE_MISC_REFCLK_SEL_OFFSET		10
+#define HPIPE_MISC_REFCLK_SEL_MASK		\
+				(0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET)
+
+#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG	0x16C
+#define HPIPE_SMAPLER_OFFSET			12
+#define HPIPE_SMAPLER_MASK			(0x1 << HPIPE_SMAPLER_OFFSET)
+
+#define HPIPE_PWR_CTR_DTL_REG			0x184
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET	2
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK		\
+				(0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET)
+
+#define HPIPE_FRAME_DET_CONTROL_REG		0x220
+#define HPIPE_FRAME_DET_LOCK_LOST_TO_OFFSET	12
+#define HPIPE_FRAME_DET_LOCK_LOST_TO_MASK	\
+				(0x1 << HPIPE_FRAME_DET_LOCK_LOST_TO_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_0_REG		0x268
+#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET		15
+#define HPIPE_TX_TRAIN_P2P_HOLD_MASK		\
+				(0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_REG			0x26C
+#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET		0
+#define HPIPE_TX_TRAIN_CTRL_G1_MASK		\
+				(0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET		1
+#define HPIPE_TX_TRAIN_CTRL_GN1_MASK		\
+				(0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET		2
+#define HPIPE_TX_TRAIN_CTRL_G0_MASK		\
+				(0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_4_REG		0x278
+#define HPIPE_TRX_TRAIN_TIMER_OFFSET		0
+#define HPIPE_TRX_TRAIN_TIMER_MASK		\
+				(0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_5_REG		0x2A4
+#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET	11
+#define HPIPE_TX_TRAIN_START_SQ_EN_MASK		\
+				(0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET	12
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK	\
+				(0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET	13
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK	\
+				(0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET)
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET	14
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK	\
+				(0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET)
+
+#define HPIPE_TX_TRAIN_REG			0x31C
+#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET		4
+#define HPIPE_TX_TRAIN_CHK_INIT_MASK		\
+				(0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET)
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET	7
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK	\
+				(0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET)
+
+#define HPIPE_CDR_CONTROL_REG			0x418
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET	14
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK	\
+				(0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET	12
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK	\
+				(0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET	9
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK		\
+				(0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET	6
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK		\
+				(0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_11_REG		0x438
+#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET	6
+#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK	\
+				(0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET)
+#define HPIPE_TX_NUM_OF_PRESET_OFFSET		10
+#define HPIPE_TX_NUM_OF_PRESET_MASK		\
+				(0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET)
+#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET		15
+#define HPIPE_TX_SWEEP_PRESET_EN_MASK		\
+				(0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET)
+#define HPIPE_G2_SETTINGS_4_REG			0x44C
+#define HPIPE_G2_DFE_RES_OFFSET			8
+#define HPIPE_G2_DFE_RES_MASK			(0x3 << HPIPE_G2_DFE_RES_OFFSET)
+
+#define HPIPE_G3_SETTING_3_REG			0x450
+#define HPIPE_G3_FFE_CAP_SEL_OFFSET		0
+#define HPIPE_G3_FFE_CAP_SEL_MASK		\
+				(0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G3_FFE_RES_SEL_OFFSET		4
+#define HPIPE_G3_FFE_RES_SEL_MASK		\
+				(0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET)
+#define HPIPE_G3_FFE_SETTING_FORCE_OFFSET	7
+#define HPIPE_G3_FFE_SETTING_FORCE_MASK		\
+				(0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET	12
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK		\
+				(0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET	14
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK	\
+				(0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G3_SETTING_4_REG			0x454
+#define HPIPE_G3_DFE_RES_OFFSET			8
+#define HPIPE_G3_DFE_RES_MASK			(0x3 << HPIPE_G3_DFE_RES_OFFSET)
+
+#define HPIPE_DFE_CONTROL_REG			0x470
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET	14
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK		\
+				(0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET)
+
+#define HPIPE_DFE_CTRL_28_REG			0x49C
+#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET		7
+#define HPIPE_DFE_CTRL_28_PIPE4_MASK		\
+				(0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET)
+
+#define HPIPE_G3_SETTING_5_REG			0x548
+#define HPIPE_G3_SETTING_5_G3_ICP_OFFSET	0
+#define HPIPE_G3_SETTING_5_G3_ICP_MASK		\
+				(0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET)
+
+#define HPIPE_LANE_STATUS1_REG			0x60C
+#define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET	0
+#define HPIPE_LANE_STATUS1_PCLK_EN_MASK		\
+				(0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET)
+
+#define HPIPE_LANE_CFG4_REG			0x620
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET	3
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK		\
+				(0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET)
+
+#define HPIPE_LANE_EQU_CONFIG_0_REG		0x69C
+#define HPIPE_CFG_EQ_FS_OFFSET			0
+#define HPIPE_CFG_EQ_FS_MASK			(0x3f << HPIPE_CFG_EQ_FS_OFFSET)
+#define HPIPE_CFG_EQ_LF_OFFSET			6
+#define HPIPE_CFG_EQ_LF_MASK			(0x3f << HPIPE_CFG_EQ_LF_OFFSET)
+#define HPIPE_CFG_PHY_RC_EP_OFFSET		12
+#define HPIPE_CFG_PHY_RC_EP_MASK		\
+				(0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG1_REG			0x6a0
+#define HPIPE_CFG_UPDATE_POLARITY_OFFSET	12
+#define HPIPE_CFG_UPDATE_POLARITY_MASK		\
+				(0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG2_REG			0x6a4
+#define HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET		14
+#define HPIPE_CFG_EQ_BUNDLE_DIS_MASK		\
+				(0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG0_REG		0x6a8
+#define HPIPE_CFG_CURSOR_PRESET0_OFFSET		0
+#define HPIPE_CFG_CURSOR_PRESET0_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET0_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET1_OFFSET		6
+#define HPIPE_CFG_CURSOR_PRESET1_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET1_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG1_REG		0x6ac
+#define HPIPE_CFG_CURSOR_PRESET2_OFFSET		0
+#define HPIPE_CFG_CURSOR_PRESET2_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET2_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET3_OFFSET		6
+#define HPIPE_CFG_CURSOR_PRESET3_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET3_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG2_REG		0x6b0
+#define HPIPE_CFG_CURSOR_PRESET4_OFFSET		0
+#define HPIPE_CFG_CURSOR_PRESET4_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET4_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET5_OFFSET		6
+#define HPIPE_CFG_CURSOR_PRESET5_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET5_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG3_REG		0x6b4
+#define HPIPE_CFG_CURSOR_PRESET6_OFFSET		0
+#define HPIPE_CFG_CURSOR_PRESET6_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET6_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET7_OFFSET		6
+#define HPIPE_CFG_CURSOR_PRESET7_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET7_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG4_REG		0x6b8
+#define HPIPE_CFG_CURSOR_PRESET8_OFFSET		0
+#define HPIPE_CFG_CURSOR_PRESET8_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET8_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET9_OFFSET		6
+#define HPIPE_CFG_CURSOR_PRESET9_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET9_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG5_REG		0x6bc
+#define HPIPE_CFG_CURSOR_PRESET10_OFFSET	0
+#define HPIPE_CFG_CURSOR_PRESET10_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET10_OFFSET)
+#define HPIPE_CFG_CURSOR_PRESET11_OFFSET	6
+#define HPIPE_CFG_CURSOR_PRESET11_MASK		\
+				(0x3f << HPIPE_CFG_CURSOR_PRESET11_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG6_REG		0x6c0
+#define HPIPE_CFG_PRE_CURSOR_PRESET0_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET0_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET0_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET0_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET0_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET0_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG7_REG		0x6c4
+#define HPIPE_CFG_PRE_CURSOR_PRESET1_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET1_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET1_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET1_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET1_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET1_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG8_REG		0x6c8
+#define HPIPE_CFG_PRE_CURSOR_PRESET2_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET2_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET2_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET2_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET2_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET2_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG9_REG		0x6cc
+#define HPIPE_CFG_PRE_CURSOR_PRESET3_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET3_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET3_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET3_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET3_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET3_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG10_REG		0x6d0
+#define HPIPE_CFG_PRE_CURSOR_PRESET4_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET4_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET4_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET4_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET4_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET4_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG11_REG		0x6d4
+#define HPIPE_CFG_PRE_CURSOR_PRESET5_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET5_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET5_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET5_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET5_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET5_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG12_REG		0x6d8
+#define HPIPE_CFG_PRE_CURSOR_PRESET6_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET6_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET6_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET6_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET6_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET6_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG13_REG		0x6dc
+#define HPIPE_CFG_PRE_CURSOR_PRESET7_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET7_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET7_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET7_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET7_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET7_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG14_REG		0x6e0
+#define HPIPE_CFG_PRE_CURSOR_PRESET8_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET8_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET8_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET8_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET8_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET8_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG15_REG		0x6e4
+#define HPIPE_CFG_PRE_CURSOR_PRESET9_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET9_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET9_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET9_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET9_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET9_OFFSET)
+
+#define HPIPE_LANE_PRESET_CFG16_REG		0x6e8
+#define HPIPE_CFG_PRE_CURSOR_PRESET10_OFFSET	0
+#define HPIPE_CFG_PRE_CURSOR_PRESET10_MASK	\
+				(0x3f << HPIPE_CFG_PRE_CURSOR_PRESET10_OFFSET)
+#define HPIPE_CFG_POST_CURSOR_PRESET10_OFFSET	6
+#define HPIPE_CFG_POST_CURSOR_PRESET10_MASK	\
+				(0x3f << HPIPE_CFG_POST_CURSOR_PRESET10_OFFSET)
+
+#define HPIPE_LANE_EQ_REMOTE_SETTING_REG	0x6f8
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET	0
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK	\
+				(0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET)
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET	1
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK	\
+				(0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET)
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET	2
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK	\
+				(0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET)
+
+#define HPIPE_RST_CLK_CTRL_REG			0x704
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET	0
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK	\
+				(0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET)
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET	2
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK	\
+				(0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET)
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET	3
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK	\
+				(0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET)
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET	9
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK	\
+				(0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET)
+
+#define HPIPE_CLK_SRC_LO_REG				0x70c
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET	1
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK		\
+			(0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET)
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET	2
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK	\
+			(0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET)
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET		5
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK		\
+			(0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET)
+
+#define HPIPE_CLK_SRC_HI_REG			0x710
+#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET	0
+#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK		\
+			(0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET	1
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK	\
+			(0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET	2
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK	\
+			(0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET)
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET	7
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK		\
+			(0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET)
+
+#define HPIPE_GLOBAL_PM_CTRL			0x740
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET	0
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK	\
+			(0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET)
+
+#endif /* COMPHY_H */
diff --git a/drivers/marvell/comphy/comphy-cp110.h b/drivers/marvell/comphy/comphy-cp110.h
new file mode 100644
index 0000000..6eb7fd0
--- /dev/null
+++ b/drivers/marvell/comphy/comphy-cp110.h
@@ -0,0 +1,865 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 SoC COMPHY unit driver */
+
+#ifndef COMPHY_CP110_H
+#define COMPHY_CP110_H
+
+#define SD_ADDR(base, lane)			(base + 0x1000 * lane)
+#define HPIPE_ADDR(base, lane)			(SD_ADDR(base, lane) + 0x800)
+#define COMPHY_ADDR(base, lane)			(base + 0x28 * lane)
+
+#define MAX_NUM_OF_FFE				8
+#define RX_TRAINING_TIMEOUT			500
+
+/* Comphy registers */
+#define COMMON_PHY_CFG1_REG			0x0
+#define COMMON_PHY_CFG1_PWR_UP_OFFSET		1
+#define COMMON_PHY_CFG1_PWR_UP_MASK		\
+				(0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET)
+#define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET	2
+#define COMMON_PHY_CFG1_PIPE_SELECT_MASK	\
+				(0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET)
+#define COMMON_PHY_CFG1_CORE_RSTN_OFFSET	13
+#define COMMON_PHY_CFG1_CORE_RSTN_MASK		\
+				(0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET)
+#define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET	14
+#define COMMON_PHY_CFG1_PWR_ON_RESET_MASK	\
+				(0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET)
+#define COMMON_PHY_PHY_MODE_OFFSET		15
+#define COMMON_PHY_PHY_MODE_MASK		\
+				(0x1 << COMMON_PHY_PHY_MODE_OFFSET)
+
+#define COMMON_PHY_CFG6_REG			0x14
+#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET	18
+#define COMMON_PHY_CFG6_IF_40_SEL_MASK		\
+				(0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET)
+
+#define COMMON_PHY_CFG6_REG			0x14
+#define COMMON_PHY_CFG6_IF_40_SEL_OFFSET	18
+#define COMMON_PHY_CFG6_IF_40_SEL_MASK		\
+				(0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET)
+
+#define COMMON_SELECTOR_PHY_REG_OFFSET		0x140
+#define COMMON_SELECTOR_PIPE_REG_OFFSET		0x144
+#define COMMON_SELECTOR_COMPHY_MASK		0xf
+#define COMMON_SELECTOR_COMPHYN_FIELD_WIDTH	4
+#define COMMON_SELECTOR_COMPHYN_SATA		0x4
+#define COMMON_SELECTOR_PIPE_COMPHY_PCIE	0x4
+#define COMMON_SELECTOR_PIPE_COMPHY_USBH	0x1
+#define COMMON_SELECTOR_PIPE_COMPHY_USBD	0x2
+
+/* SGMII/HS-SGMII/SFI/RXAUI */
+#define COMMON_SELECTOR_COMPHY0_1_2_NETWORK	0x1
+#define COMMON_SELECTOR_COMPHY3_RXAUI		0x1
+#define COMMON_SELECTOR_COMPHY3_SGMII		0x2
+#define COMMON_SELECTOR_COMPHY4_PORT1		0x1
+#define COMMON_SELECTOR_COMPHY4_ALL_OTHERS	0x2
+#define COMMON_SELECTOR_COMPHY5_RXAUI		0x2
+#define COMMON_SELECTOR_COMPHY5_SGMII		0x1
+
+#define COMMON_PHY_SD_CTRL1			0x148
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET	0
+#define COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET	4
+#define COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET	8
+#define COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET	12
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK	0xFFFF
+#define COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK	0xFF
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET	24
+#define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK	\
+				(0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET)
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET	25
+#define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK	\
+				(0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET)
+#define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET	26
+#define COMMON_PHY_SD_CTRL1_RXAUI1_MASK		\
+				(0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET)
+#define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET	27
+#define COMMON_PHY_SD_CTRL1_RXAUI0_MASK		\
+				(0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET)
+
+/* DFX register */
+#define DFX_BASE				(0x400000)
+#define DFX_DEV_GEN_CTRL12_REG			(0x280)
+#define DFX_DEV_GEN_PCIE_CLK_SRC_MUX		(0x3)
+#define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET		7
+#define DFX_DEV_GEN_PCIE_CLK_SRC_MASK		\
+				(0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET)
+
+/* SerDes IP registers */
+#define SD_EXTERNAL_CONFIG0_REG				0
+#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET		1
+#define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK		\
+			(1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET	3
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK		\
+			(0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET	7
+#define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK		\
+			(0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET		11
+#define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK		\
+			(1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET		12
+#define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK		\
+			(1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET)
+#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET	14
+#define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK		\
+			(1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET)
+#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET		15
+#define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK		\
+			(0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET)
+
+#define SD_EXTERNAL_CONFIG1_REG			0x4
+#define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET	3
+#define SD_EXTERNAL_CONFIG1_RESET_IN_MASK	\
+			(0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET	4
+#define SD_EXTERNAL_CONFIG1_RX_INIT_MASK	\
+			(0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET	5
+#define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK	\
+			(0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET)
+#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET	6
+#define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK	\
+			(0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET)
+
+#define SD_EXTERNAL_CONFIG2_REG			0x8
+#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET	4
+#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK	\
+			(0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET)
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET	7
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK	\
+			(0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET)
+
+#define SD_EXTERNAL_STATUS_REG				0xc
+#define SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET	7
+#define SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK	\
+			(1 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET)
+
+#define SD_EXTERNAL_STATUS0_REG			0x18
+#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET	2
+#define SD_EXTERNAL_STATUS0_PLL_TX_MASK		\
+			(0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET)
+#define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET	3
+#define SD_EXTERNAL_STATUS0_PLL_RX_MASK		\
+			(0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET)
+#define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET	4
+#define SD_EXTERNAL_STATUS0_RX_INIT_MASK	\
+			(0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET)
+
+#define SD_EXTERNAL_STATAUS1_REG			0x1c
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_OFFSET	0
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_MASK	\
+	(1 << SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_OFFSET)
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_OFFSET	1
+#define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_MASK	\
+	(1 << SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_OFFSET)
+
+/* HPIPE registers */
+#define HPIPE_PWR_PLL_REG			0x4
+#define HPIPE_PWR_PLL_REF_FREQ_OFFSET		0
+#define HPIPE_PWR_PLL_REF_FREQ_MASK		\
+			(0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET)
+#define HPIPE_PWR_PLL_PHY_MODE_OFFSET		5
+#define HPIPE_PWR_PLL_PHY_MODE_MASK		\
+			(0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET)
+
+#define HPIPE_CAL_REG1_REG			0xc
+#define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET	10
+#define HPIPE_CAL_REG_1_EXT_TXIMP_MASK		\
+			(0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET)
+#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET	15
+#define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK	\
+			(0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET)
+
+#define HPIPE_SQUELCH_FFE_SETTING_REG		0x18
+#define HPIPE_SQUELCH_THRESH_IN_OFFSET		8
+#define HPIPE_SQUELCH_THRESH_IN_MASK		\
+			(0xf << HPIPE_SQUELCH_THRESH_IN_OFFSET)
+#define HPIPE_SQUELCH_DETECTED_OFFSET		14
+#define HPIPE_SQUELCH_DETECTED_MASK		\
+			(0x1 << HPIPE_SQUELCH_DETECTED_OFFSET)
+
+#define HPIPE_DFE_REG0				0x1c
+#define HPIPE_DFE_RES_FORCE_OFFSET		15
+#define HPIPE_DFE_RES_FORCE_MASK		\
+			(0x1 << HPIPE_DFE_RES_FORCE_OFFSET)
+
+#define HPIPE_DFE_F3_F5_REG			0x28
+#define HPIPE_DFE_F3_F5_DFE_EN_OFFSET		14
+#define HPIPE_DFE_F3_F5_DFE_EN_MASK		\
+			(0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET)
+#define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET		15
+#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK		\
+			(0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET)
+
+#define HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG	0x30
+#define HPIPE_ADAPTED_DFE_RES_OFFSET		13
+#define HPIPE_ADAPTED_DFE_RES_MASK		\
+			(0x3 << HPIPE_ADAPTED_DFE_RES_OFFSET)
+
+#define HPIPE_G1_SET_0_REG			0x34
+#define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET		1
+#define HPIPE_G1_SET_0_G1_TX_AMP_MASK		\
+			(0x1f << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET	6
+#define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK	\
+			(0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET	7
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK		\
+			(0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET	11
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK	\
+			(0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET)
+
+#define HPIPE_G1_SET_1_REG			0x38
+#define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET	0
+#define HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK	\
+			(0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET	3
+#define HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK	\
+			(0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET	6
+#define HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK	\
+			(0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET	8
+#define HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK	\
+			(0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET	10
+#define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK	\
+			(0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET	11
+#define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK	\
+			(0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET)
+
+#define HPIPE_G2_SET_0_REG			0x3c
+#define HPIPE_G2_SET_0_G2_TX_AMP_OFFSET		1
+#define HPIPE_G2_SET_0_G2_TX_AMP_MASK		\
+			(0x1f << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET	6
+#define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK	\
+			(0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET	7
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_MASK		\
+			(0xf << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET	11
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK	\
+			(0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET)
+
+#define HPIPE_G2_SET_1_REG			0x40
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET	0
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK	\
+			(0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET	3
+#define HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK	\
+			(0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET	6
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK	\
+			(0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET	8
+#define HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK	\
+			(0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET	10
+#define HPIPE_G2_SET_1_G2_RX_DFE_EN_MASK	\
+			(0x1 << HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET	11
+#define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK	\
+			(0x3 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET)
+
+#define HPIPE_G3_SET_0_REG			0x44
+#define HPIPE_G3_SET_0_G3_TX_AMP_OFFSET		1
+#define HPIPE_G3_SET_0_G3_TX_AMP_MASK		\
+			(0x1f << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET	6
+#define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK	\
+			(0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET	7
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_MASK		\
+			(0xf << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET	11
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK	\
+			(0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET 12
+#define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK	\
+			(0x7 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET 15
+#define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK	\
+			(0x1 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET)
+
+#define HPIPE_G3_SET_1_REG				0x48
+#define HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET		0
+#define HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK		\
+			(0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET		3
+#define HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK		\
+			(0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET		6
+#define HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK		\
+			(0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET		8
+#define HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK		\
+			(0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET		10
+#define HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK		\
+			(0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET		11
+#define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK		\
+			(0x3 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET)
+#define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET	13
+#define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK	\
+			(0x1 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET)
+
+#define HPIPE_PHY_TEST_CONTROL_REG		0x54
+#define HPIPE_PHY_TEST_PATTERN_SEL_OFFSET	4
+#define HPIPE_PHY_TEST_PATTERN_SEL_MASK		\
+			(0xf << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET)
+#define HPIPE_PHY_TEST_RESET_OFFSET		14
+#define HPIPE_PHY_TEST_RESET_MASK		\
+			(0x1 << HPIPE_PHY_TEST_RESET_OFFSET)
+#define HPIPE_PHY_TEST_EN_OFFSET		15
+#define HPIPE_PHY_TEST_EN_MASK			\
+			(0x1 << HPIPE_PHY_TEST_EN_OFFSET)
+
+#define HPIPE_PHY_TEST_DATA_REG			0x6c
+#define HPIPE_PHY_TEST_DATA_OFFSET		0
+#define HPIPE_PHY_TEST_DATA_MASK		\
+			(0xffff << HPIPE_PHY_TEST_DATA_OFFSET)
+
+#define HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG	0x80
+
+#define HPIPE_PHY_TEST_OOB_0_REGISTER		0x84
+#define HPIPE_PHY_PT_OOB_EN_OFFSET		14
+#define HPIPE_PHY_PT_OOB_EN_MASK		\
+			(0x1 << HPIPE_PHY_PT_OOB_EN_OFFSET)
+#define HPIPE_PHY_TEST_PT_TESTMODE_OFFSET	12
+#define HPIPE_PHY_TEST_PT_TESTMODE_MASK		\
+			(0x3 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET)
+
+#define HPIPE_LOOPBACK_REG			0x8c
+#define HPIPE_LOOPBACK_SEL_OFFSET		1
+#define HPIPE_LOOPBACK_SEL_MASK			\
+			(0x7 << HPIPE_LOOPBACK_SEL_OFFSET)
+#define HPIPE_CDR_LOCK_OFFSET			7
+#define HPIPE_CDR_LOCK_MASK			\
+			(0x1 << HPIPE_CDR_LOCK_OFFSET)
+#define HPIPE_CDR_LOCK_DET_EN_OFFSET		8
+#define HPIPE_CDR_LOCK_DET_EN_MASK		\
+			(0x1 << HPIPE_CDR_LOCK_DET_EN_OFFSET)
+
+#define HPIPE_INTERFACE_REG			0x94
+#define HPIPE_INTERFACE_GEN_MAX_OFFSET		10
+#define HPIPE_INTERFACE_GEN_MAX_MASK		\
+			(0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET)
+#define HPIPE_INTERFACE_DET_BYPASS_OFFSET	12
+#define HPIPE_INTERFACE_DET_BYPASS_MASK		\
+			(0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET)
+#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET	14
+#define HPIPE_INTERFACE_LINK_TRAIN_MASK		\
+			(0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET)
+
+#define HPIPE_G1_SET_2_REG			0xf4
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET	0
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_MASK		\
+			(0xf << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET)
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET	4
+#define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK	\
+			(0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET)
+
+#define HPIPE_G2_SET_2_REG			0xf8
+#define HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET	0
+#define HPIPE_G2_SET_2_G2_TX_EMPH0_MASK		\
+			(0xf << HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET)
+#define HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET	4
+#define HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK	\
+			(0x1 << HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET)
+#define HPIPE_G2_TX_SSC_AMP_OFFSET		9
+#define HPIPE_G2_TX_SSC_AMP_MASK		\
+			(0x7f << HPIPE_G2_TX_SSC_AMP_OFFSET)
+
+#define HPIPE_G3_SET_2_REG			0xfc
+#define HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET	0
+#define HPIPE_G3_SET_2_G3_TX_EMPH0_MASK		\
+			(0xf << HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET)
+#define HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET	4
+#define HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK	\
+			(0x1 << HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET)
+#define HPIPE_G3_TX_SSC_AMP_OFFSET		9
+#define HPIPE_G3_TX_SSC_AMP_MASK		\
+			(0x7f << HPIPE_G3_TX_SSC_AMP_OFFSET)
+
+#define HPIPE_VDD_CAL_0_REG			0x108
+#define HPIPE_CAL_VDD_CONT_MODE_OFFSET		15
+#define HPIPE_CAL_VDD_CONT_MODE_MASK		\
+			(0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET)
+
+#define HPIPE_VDD_CAL_CTRL_REG			0x114
+#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET		5
+#define HPIPE_EXT_SELLV_RXSAMPL_MASK		\
+			(0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET)
+
+#define HPIPE_PCIE_REG0				0x120
+#define HPIPE_PCIE_IDLE_SYNC_OFFSET		12
+#define HPIPE_PCIE_IDLE_SYNC_MASK		\
+			(0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET)
+#define HPIPE_PCIE_SEL_BITS_OFFSET		13
+#define HPIPE_PCIE_SEL_BITS_MASK		\
+			(0x3 << HPIPE_PCIE_SEL_BITS_OFFSET)
+
+#define HPIPE_LANE_ALIGN_REG			0x124
+#define HPIPE_LANE_ALIGN_OFF_OFFSET		12
+#define HPIPE_LANE_ALIGN_OFF_MASK		\
+			(0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET)
+
+#define HPIPE_MISC_REG				0x13C
+#define HPIPE_MISC_CLK100M_125M_OFFSET		4
+#define HPIPE_MISC_CLK100M_125M_MASK		\
+			(0x1 << HPIPE_MISC_CLK100M_125M_OFFSET)
+#define HPIPE_MISC_ICP_FORCE_OFFSET		5
+#define HPIPE_MISC_ICP_FORCE_MASK		\
+			(0x1 << HPIPE_MISC_ICP_FORCE_OFFSET)
+#define HPIPE_MISC_TXDCLK_2X_OFFSET		6
+#define HPIPE_MISC_TXDCLK_2X_MASK		\
+			(0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET)
+#define HPIPE_MISC_CLK500_EN_OFFSET		7
+#define HPIPE_MISC_CLK500_EN_MASK		\
+			(0x1 << HPIPE_MISC_CLK500_EN_OFFSET)
+#define HPIPE_MISC_REFCLK_SEL_OFFSET		10
+#define HPIPE_MISC_REFCLK_SEL_MASK		\
+			(0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET)
+
+#define HPIPE_RX_CONTROL_1_REG			0x140
+#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET	11
+#define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK	\
+			(0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET)
+#define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET	12
+#define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK	\
+			(0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET)
+
+#define HPIPE_PWR_CTR_REG			0x148
+#define HPIPE_PWR_CTR_RST_DFE_OFFSET		0
+#define HPIPE_PWR_CTR_RST_DFE_MASK		\
+			(0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET)
+#define HPIPE_PWR_CTR_SFT_RST_OFFSET		10
+#define HPIPE_PWR_CTR_SFT_RST_MASK		\
+			(0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET)
+
+#define HPIPE_SPD_DIV_FORCE_REG				0x154
+#define HPIPE_TXDIGCK_DIV_FORCE_OFFSET			7
+#define HPIPE_TXDIGCK_DIV_FORCE_MASK			\
+			(0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET		8
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK		\
+			(0x3 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET	10
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK	\
+			(0x1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET		13
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK		\
+			(0x3 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET	15
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK	\
+			(0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET)
+
+/* HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIBRATION_CTRL_REG */
+#define HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG	0x168
+#define HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET		15
+#define HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK		\
+			(0x1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET)
+#define HPIPE_CAL_OS_PH_EXT_OFFSET			8
+#define HPIPE_CAL_OS_PH_EXT_MASK			\
+			(0x7f << HPIPE_CAL_OS_PH_EXT_OFFSET)
+
+#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG	0x16C
+#define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET		6
+#define HPIPE_RX_SAMPLER_OS_GAIN_MASK		\
+			(0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET)
+#define HPIPE_SMAPLER_OFFSET			12
+#define HPIPE_SMAPLER_MASK			\
+			(0x1 << HPIPE_SMAPLER_OFFSET)
+
+#define HPIPE_TX_REG1_REG			0x174
+#define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET	5
+#define HPIPE_TX_REG1_TX_EMPH_RES_MASK		\
+			(0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET)
+#define HPIPE_TX_REG1_SLC_EN_OFFSET		10
+#define HPIPE_TX_REG1_SLC_EN_MASK		\
+			(0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET)
+
+#define HPIPE_PWR_CTR_DTL_REG				0x184
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET		0
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK		\
+			(0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET		1
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK		\
+			(0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET		2
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK			\
+			(0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET		4
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK		\
+			(0x7 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET)
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET	10
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK	\
+			(0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET		12
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_MASK			\
+			(0x3 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET		14
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK		\
+			(1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET)
+
+#define HPIPE_PHASE_CONTROL_REG			0x188
+#define HPIPE_OS_PH_OFFSET_OFFSET		0
+#define HPIPE_OS_PH_OFFSET_MASK			\
+			(0x7f << HPIPE_OS_PH_OFFSET_OFFSET)
+#define HPIPE_OS_PH_OFFSET_FORCE_OFFSET		7
+#define HPIPE_OS_PH_OFFSET_FORCE_MASK		\
+			(0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET)
+#define HPIPE_OS_PH_VALID_OFFSET		8
+#define HPIPE_OS_PH_VALID_MASK			\
+			(0x1 << HPIPE_OS_PH_VALID_OFFSET)
+
+#define HPIPE_DATA_PHASE_OFF_CTRL_REG			0x1A0
+#define HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET		9
+#define HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK		\
+			(0x7f << HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET)
+
+#define HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG	0x1A4
+#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET	12
+#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK		\
+			(0x3 << HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET)
+#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET	8
+#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK		\
+			(0xf << HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET)
+
+#define HPIPE_SQ_GLITCH_FILTER_CTRL		0x1c8
+#define HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET	0
+#define HPIPE_SQ_DEGLITCH_WIDTH_P_MASK		\
+			(0xf << HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET)
+#define HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET	4
+#define HPIPE_SQ_DEGLITCH_WIDTH_N_MASK		\
+			(0xf << HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET)
+#define HPIPE_SQ_DEGLITCH_EN_OFFSET		8
+#define HPIPE_SQ_DEGLITCH_EN_MASK		\
+			(0x1 << HPIPE_SQ_DEGLITCH_EN_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_0_REG		0x214
+#define HPIPE_TRAIN_PAT_NUM_OFFSET		0x7
+#define HPIPE_TRAIN_PAT_NUM_MASK		\
+			(0x1FF << HPIPE_TRAIN_PAT_NUM_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_3_REG			0x220
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET	12
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK		\
+			(0x1 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET)
+
+#define HPIPE_DME_REG				0x228
+#define HPIPE_DME_ETHERNET_MODE_OFFSET		7
+#define HPIPE_DME_ETHERNET_MODE_MASK		\
+			(0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET)
+
+#define HPIPE_TRX_TRAIN_CTRL_0_REG		0x22c
+#define HPIPE_TRX_TX_F0T_EO_BASED_OFFSET	14
+#define HPIPE_TRX_TX_F0T_EO_BASED_MASK		\
+			(1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET)
+#define HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET	6
+#define HPIPE_TRX_UPDATE_THEN_HOLD_MASK		\
+			(1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET)
+#define HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET		5
+#define HPIPE_TRX_TX_CTRL_CLK_EN_MASK		\
+			(1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET)
+#define HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET	4
+#define HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK	\
+			(1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET)
+#define HPIPE_TRX_TX_TRAIN_EN_OFFSET		1
+#define HPIPE_TRX_TX_TRAIN_EN_MASK		\
+			(1 << HPIPE_TRX_TX_TRAIN_EN_OFFSET)
+#define HPIPE_TRX_RX_TRAIN_EN_OFFSET		0
+#define HPIPE_TRX_RX_TRAIN_EN_MASK		\
+			(1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_0_REG		0x268
+#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET		15
+#define HPIPE_TX_TRAIN_P2P_HOLD_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_REG			0x26C
+#define HPIPE_TX_TRAIN_CTRL_G1_OFFSET		0
+#define HPIPE_TX_TRAIN_CTRL_G1_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET		1
+#define HPIPE_TX_TRAIN_CTRL_GN1_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET)
+#define HPIPE_TX_TRAIN_CTRL_G0_OFFSET		2
+#define HPIPE_TX_TRAIN_CTRL_G0_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_4_REG		0x278
+#define HPIPE_TRX_TRAIN_TIMER_OFFSET		0
+#define HPIPE_TRX_TRAIN_TIMER_MASK		\
+			(0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_5_REG		0x2A4
+#define HPIPE_RX_TRAIN_TIMER_OFFSET		0
+#define HPIPE_RX_TRAIN_TIMER_MASK		\
+			(0x3ff << HPIPE_RX_TRAIN_TIMER_OFFSET)
+#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET	11
+#define HPIPE_TX_TRAIN_START_SQ_EN_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET	12
+#define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK	\
+			(0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET)
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET	13
+#define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK	\
+			(0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET)
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET	14
+#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK	\
+			(0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET)
+
+#define HPIPE_INTERRUPT_1_REGISTER		0x2AC
+#define HPIPE_TRX_TRAIN_FAILED_OFFSET		6
+#define HPIPE_TRX_TRAIN_FAILED_MASK		\
+			(1 << HPIPE_TRX_TRAIN_FAILED_OFFSET)
+#define HPIPE_TRX_TRAIN_TIME_OUT_INT_OFFSET	5
+#define HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK	\
+			(1 << HPIPE_TRX_TRAIN_TIME_OUT_INT_OFFSET)
+#define HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET	4
+#define HPIPE_INTERRUPT_TRX_TRAIN_DONE_MASK	\
+			(1 << HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET)
+#define HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET	3
+#define HPIPE_INTERRUPT_DFE_DONE_INT_MASK	\
+			(1 << HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET)
+#define HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_OFFSET	1
+#define HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK	\
+			(1 << HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_OFFSET)
+
+#define HPIPE_TX_TRAIN_REG			0x31C
+#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET		4
+#define HPIPE_TX_TRAIN_CHK_INIT_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET)
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET	7
+#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK	\
+			(0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET)
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET	8
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK	\
+			(0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET)
+#define HPIPE_TX_TRAIN_PAT_SEL_OFFSET		9
+#define HPIPE_TX_TRAIN_PAT_SEL_MASK		\
+			(0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET)
+
+#define HPIPE_SAVED_DFE_VALUES_REG		0x328
+#define HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET	10
+#define HPIPE_SAVED_DFE_VALUES_SAV_F0D_MASK	\
+			(0x3f << HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET)
+
+#define HPIPE_CDR_CONTROL_REG			0x418
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET	14
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK	\
+			(0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET	12
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK	\
+			(0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET	9
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK		\
+			(0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET	6
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK		\
+			(0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET)
+
+#define HPIPE_TX_TRAIN_CTRL_11_REG		0x438
+#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET	6
+#define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK	\
+			(0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET)
+#define HPIPE_TX_NUM_OF_PRESET_OFFSET		10
+#define HPIPE_TX_NUM_OF_PRESET_MASK		\
+			(0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET)
+#define HPIPE_TX_SWEEP_PRESET_EN_OFFSET		15
+#define HPIPE_TX_SWEEP_PRESET_EN_MASK		\
+			(0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET)
+
+#define HPIPE_G1_SETTINGS_3_REG				0x440
+#define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET	0
+#define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK		\
+			(0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET	4
+#define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK		\
+			(0x7 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET	7
+#define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK	\
+			(0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET		9
+#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK		\
+			(0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET	12
+#define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK	\
+			(0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET	14
+#define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK	\
+		(0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G1_SETTINGS_4_REG			0x444
+#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET	8
+#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK	\
+			(0x3 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET)
+
+#define HPIPE_G2_SETTINGS_4_REG			0x44c
+#define HPIPE_G2_DFE_RES_OFFSET			8
+#define HPIPE_G2_DFE_RES_MASK			\
+			(0x3 << HPIPE_G2_DFE_RES_OFFSET)
+
+#define HPIPE_G3_SETTING_3_REG			0x450
+#define HPIPE_G3_FFE_CAP_SEL_OFFSET		0
+#define HPIPE_G3_FFE_CAP_SEL_MASK		\
+			(0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G3_FFE_RES_SEL_OFFSET		4
+#define HPIPE_G3_FFE_RES_SEL_MASK		\
+			(0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET)
+#define HPIPE_G3_FFE_SETTING_FORCE_OFFSET	7
+#define HPIPE_G3_FFE_SETTING_FORCE_MASK		\
+			(0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET	12
+#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK		\
+			(0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET	14
+#define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK	\
+			(0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET)
+
+#define HPIPE_G3_SETTING_4_REG			0x454
+#define HPIPE_G3_DFE_RES_OFFSET			8
+#define HPIPE_G3_DFE_RES_MASK			(0x3 << HPIPE_G3_DFE_RES_OFFSET)
+
+#define HPIPE_TX_PRESET_INDEX_REG		0x468
+#define HPIPE_TX_PRESET_INDEX_OFFSET		0
+#define HPIPE_TX_PRESET_INDEX_MASK		\
+			(0xf << HPIPE_TX_PRESET_INDEX_OFFSET)
+
+#define HPIPE_DFE_CONTROL_REG			0x470
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET	14
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK		\
+			(0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET)
+
+#define HPIPE_DFE_CTRL_28_REG			0x49C
+#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET		7
+#define HPIPE_DFE_CTRL_28_PIPE4_MASK		\
+			(0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET)
+
+#define HPIPE_G1_SETTING_5_REG			0x538
+#define HPIPE_G1_SETTING_5_G1_ICP_OFFSET	0
+#define HPIPE_G1_SETTING_5_G1_ICP_MASK		\
+			(0xf << HPIPE_G1_SETTING_5_G1_ICP_OFFSET)
+
+#define HPIPE_G3_SETTING_5_REG			0x548
+#define HPIPE_G3_SETTING_5_G3_ICP_OFFSET	0
+#define HPIPE_G3_SETTING_5_G3_ICP_MASK		\
+			(0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET)
+
+#define HPIPE_LANE_CONFIG0_REG			0x600
+#define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET	0
+#define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK	\
+			(0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET)
+
+#define HPIPE_LANE_STATUS1_REG			0x60C
+#define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET	0
+#define HPIPE_LANE_STATUS1_PCLK_EN_MASK		\
+			(0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET)
+
+#define HPIPE_LANE_CFG4_REG			0x620
+#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET		0
+#define HPIPE_LANE_CFG4_DFE_CTRL_MASK		\
+			(0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET	3
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK		\
+			(0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET		6
+#define HPIPE_LANE_CFG4_DFE_OVER_MASK		\
+			(0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET)
+#define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET		7
+#define HPIPE_LANE_CFG4_SSC_CTRL_MASK		\
+			(0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET)
+
+#define HPIPE_LANE_EQ_REMOTE_SETTING_REG	0x6f8
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET	0
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK	\
+			(0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET)
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET	1
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK	\
+			(0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET)
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET	2
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK	\
+			(0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET)
+
+#define HPIPE_LANE_EQU_CONFIG_0_REG		0x69C
+#define HPIPE_CFG_PHY_RC_EP_OFFSET		12
+#define HPIPE_CFG_PHY_RC_EP_MASK		\
+			(0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG1_REG			0x6a0
+#define HPIPE_CFG_UPDATE_POLARITY_OFFSET	12
+#define HPIPE_CFG_UPDATE_POLARITY_MASK		\
+			(0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET)
+
+#define HPIPE_LANE_EQ_CFG2_REG			0x6a4
+#define HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET		14
+#define HPIPE_CFG_EQ_BUNDLE_DIS_MASK		\
+			(0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET)
+
+#define HPIPE_RST_CLK_CTRL_REG			0x704
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET	0
+#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK	\
+			(0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET)
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET	2
+#define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK	\
+			(0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET)
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET	3
+#define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK	\
+			(0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET)
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET	9
+#define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK	\
+			(0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET)
+
+#define HPIPE_TST_MODE_CTRL_REG			0x708
+#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET	2
+#define HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK	\
+			(0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET)
+
+#define HPIPE_CLK_SRC_LO_REG				0x70c
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET	1
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK		\
+			(0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET)
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET	2
+#define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK	\
+			(0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET)
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET		5
+#define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK		\
+			(0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET)
+
+#define HPIPE_CLK_SRC_HI_REG			0x710
+#define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET	0
+#define HPIPE_CLK_SRC_HI_LANE_STRT_MASK		\
+			(0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET	1
+#define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK	\
+			(0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET)
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET	2
+#define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK	\
+			(0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET)
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET	7
+#define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK		\
+			(0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET)
+
+#define HPIPE_GLOBAL_MISC_CTRL			0x718
+#define HPIPE_GLOBAL_PM_CTRL			0x740
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET	0
+#define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK	\
+			(0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET)
+
+/* General defines */
+#define PLL_LOCK_TIMEOUT			15000
+
+#endif /* COMPHY_CP110_H */
diff --git a/drivers/marvell/comphy/phy-comphy-3700.c b/drivers/marvell/comphy/phy-comphy-3700.c
new file mode 100644
index 0000000..2e8c412
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-3700.c
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#include "phy-comphy-3700.h"
+#include "phy-comphy-common.h"
+
+/*
+ * COMPHY_INDIRECT_REG points to ahci address space but the ahci region used in
+ * Linux is up to 0x178 so none will access it from Linux in runtime
+ * concurrently.
+ */
+#define COMPHY_INDIRECT_REG	(MVEBU_REGS_BASE + 0xE0178)
+
+/* The USB3_GBE1_PHY range is above USB3 registers used in dts */
+#define USB3_GBE1_PHY		(MVEBU_REGS_BASE + 0x5C000)
+#define COMPHY_SD_ADDR		(MVEBU_REGS_BASE + 0x1F000)
+
+/*
+ * Below address in used only for reading, therefore no problem with concurrent
+ * Linux access.
+ */
+#define MVEBU_TEST_PIN_LATCH_N (MVEBU_NB_GPIO_REG_BASE + 0x8)
+ #define MVEBU_XTAL_MODE_MASK		BIT(9)
+ #define MVEBU_XTAL_MODE_OFFS		9
+ #define MVEBU_XTAL_CLOCK_25MHZ		0x0
+
+struct sgmii_phy_init_data_fix {
+	uint16_t addr;
+	uint16_t value;
+};
+
+/* Changes to 40M1G25 mode data required for running 40M3G125 init mode */
+static struct sgmii_phy_init_data_fix sgmii_phy_init_fix[] = {
+	{0x005, 0x07CC}, {0x015, 0x0000}, {0x01B, 0x0000}, {0x01D, 0x0000},
+	{0x01E, 0x0000}, {0x01F, 0x0000}, {0x020, 0x0000}, {0x021, 0x0030},
+	{0x026, 0x0888}, {0x04D, 0x0152}, {0x04F, 0xA020}, {0x050, 0x07CC},
+	{0x053, 0xE9CA}, {0x055, 0xBD97}, {0x071, 0x3015}, {0x076, 0x03AA},
+	{0x07C, 0x0FDF}, {0x0C2, 0x3030}, {0x0C3, 0x8000}, {0x0E2, 0x5550},
+	{0x0E3, 0x12A4}, {0x0E4, 0x7D00}, {0x0E6, 0x0C83}, {0x101, 0xFCC0},
+	{0x104, 0x0C10}
+};
+
+/* 40M1G25 mode init data */
+static uint16_t sgmii_phy_init[512] = {
+	/* 0       1       2       3       4       5       6       7 */
+	/*-----------------------------------------------------------*/
+	/* 8       9       A       B       C       D       E       F */
+	0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26,	/* 00 */
+	0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52,	/* 08 */
+	0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000,	/* 10 */
+	0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF,	/* 18 */
+	0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000,	/* 20 */
+	0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,	/* 28 */
+	0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/* 30 */
+	0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100,	/* 38 */
+	0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00,	/* 40 */
+	0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A,	/* 48 */
+	0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001,	/* 50 */
+	0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF,	/* 58 */
+	0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000,	/* 60 */
+	0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002,	/* 68 */
+	0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780,	/* 70 */
+	0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000,	/* 78 */
+	0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000,	/* 80 */
+	0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210,	/* 88 */
+	0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F,	/* 90 */
+	0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651,	/* 98 */
+	0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000,	/* A0 */
+	0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/* A8 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/* B0 */
+	0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000,	/* B8 */
+	0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003,	/* C0 */
+	0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000,	/* C8 */
+	0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00,	/* D0 */
+	0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000,	/* D8 */
+	0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541,	/* E0 */
+	0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200,	/* E8 */
+	0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000,	/* F0 */
+	0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000,	/* F8 */
+	0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000,	/*100 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*108 */
+	0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000,	/*110 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*118 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*120 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*128 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*130 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*138 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*140 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*148 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*150 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*158 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*160 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*168 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*170 */
+	0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000,	/*178 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*180 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*188 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*190 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*198 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1A0 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1A8 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1B0 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1B8 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1C0 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1C8 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1D0 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1D8 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1E0 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1E8 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,	/*1F0 */
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000	/*1F8 */
+};
+
+/* returns reference clock in MHz (25 or 40) */
+static uint32_t get_ref_clk(void)
+{
+	uint32_t val;
+
+	val = (mmio_read_32(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
+		MVEBU_XTAL_MODE_OFFS;
+
+	if (val == MVEBU_XTAL_CLOCK_25MHZ)
+		return 25;
+	else
+		return 40;
+}
+
+/* PHY selector configures with corresponding modes */
+static void mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index,
+						uint32_t comphy_mode)
+{
+	uint32_t reg;
+	int mode = COMPHY_GET_MODE(comphy_mode);
+
+	reg = mmio_read_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG);
+	switch (mode) {
+	case (COMPHY_SATA_MODE):
+		/* SATA must be in Lane2 */
+		if (comphy_index == COMPHY_LANE2)
+			reg &= ~COMPHY_SELECTOR_USB3_PHY_SEL_BIT;
+		else
+			goto error;
+		break;
+
+	case (COMPHY_SGMII_MODE):
+	case (COMPHY_HS_SGMII_MODE):
+		if (comphy_index == COMPHY_LANE0)
+			reg &= ~COMPHY_SELECTOR_USB3_GBE1_SEL_BIT;
+		else if (comphy_index == COMPHY_LANE1)
+			reg &= ~COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT;
+		else
+			goto error;
+		break;
+
+	case (COMPHY_USB3H_MODE):
+	case (COMPHY_USB3D_MODE):
+	case (COMPHY_USB3_MODE):
+		if (comphy_index == COMPHY_LANE2)
+			reg |= COMPHY_SELECTOR_USB3_PHY_SEL_BIT;
+		else if (comphy_index == COMPHY_LANE0)
+			reg |= COMPHY_SELECTOR_USB3_GBE1_SEL_BIT;
+		else
+			goto error;
+		break;
+
+	case (COMPHY_PCIE_MODE):
+		/* PCIE must be in Lane1 */
+		if (comphy_index == COMPHY_LANE1)
+			reg |= COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT;
+		else
+			goto error;
+		break;
+
+	default:
+		goto error;
+	}
+
+	mmio_write_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG, reg);
+	return;
+error:
+	ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
+}
+
+/* It is only used for SATA and USB3 on comphy lane2. */
+static void comphy_set_indirect(uintptr_t addr, uint32_t offset, uint16_t data,
+				uint16_t mask, int mode)
+{
+	/*
+	 * When Lane 2 PHY is for USB3, access the PHY registers
+	 * through indirect Address and Data registers:
+	 * INDIR_ACC_PHY_ADDR (RD00E0178h [31:0]),
+	 * INDIR_ACC_PHY_DATA (RD00E017Ch [31:0]),
+	 * within the SATA Host Controller registers, Lane 2 base register
+	 * offset is 0x200
+	 */
+	if (mode == COMPHY_UNUSED)
+		return;
+
+	if (mode == COMPHY_SATA_MODE)
+		mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET, offset);
+	else
+		mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET,
+			      offset + USB3PHY_LANE2_REG_BASE_OFFSET);
+
+	reg_set(addr + COMPHY_LANE2_INDIR_DATA_OFFSET, data, mask);
+}
+
+/* It is only used USB3 direct access not on comphy lane2. */
+static void comphy_usb3_set_direct(uintptr_t addr, uint32_t reg_offset,
+				   uint16_t data, uint16_t mask, int mode)
+{
+	reg_set16((reg_offset * PHY_SHFT(USB3) + addr), data, mask);
+}
+
+static void comphy_sgmii_phy_init(uint32_t comphy_index, uint32_t mode,
+				  uintptr_t sd_ip_addr)
+{
+	const int fix_arr_sz = ARRAY_SIZE(sgmii_phy_init_fix);
+	int addr, fix_idx;
+	uint16_t val;
+
+	fix_idx = 0;
+	for (addr = 0; addr < 512; addr++) {
+		/*
+		 * All PHY register values are defined in full for 3.125Gbps
+		 * SERDES speed. The values required for 1.25 Gbps are almost
+		 * the same and only few registers should be "fixed" in
+		 * comparison to 3.125 Gbps values. These register values are
+		 * stored in "sgmii_phy_init_fix" array.
+		 */
+		if ((mode != COMPHY_SGMII_MODE) &&
+		    (sgmii_phy_init_fix[fix_idx].addr == addr)) {
+			/* Use new value */
+			val = sgmii_phy_init_fix[fix_idx].value;
+			if (fix_idx < fix_arr_sz)
+				fix_idx++;
+		} else {
+			val = sgmii_phy_init[addr];
+		}
+
+		reg_set16(SGMIIPHY_ADDR(addr, sd_ip_addr), val, 0xFFFF);
+	}
+}
+
+static int mvebu_a3700_comphy_sata_power_on(uint8_t comphy_index,
+					    uint32_t comphy_mode)
+{
+	int ret = 0;
+	uint32_t offset, data = 0, ref_clk;
+	uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+	debug_enter();
+
+	/* Configure phy selector for SATA */
+	mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+
+	/* Clear phy isolation mode to make it work in normal mode */
+	offset =  COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
+	comphy_set_indirect(comphy_indir_regs, offset, 0, PHY_ISOLATE_MODE,
+			    mode);
+
+	/* 0. Check the Polarity invert bits */
+	if (invert & COMPHY_POLARITY_TXD_INVERT)
+		data |= TXD_INVERT_BIT;
+	if (invert & COMPHY_POLARITY_RXD_INVERT)
+		data |= RXD_INVERT_BIT;
+
+	offset = COMPHY_SYNC_PATTERN_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
+	comphy_set_indirect(comphy_indir_regs, offset, data, TXD_INVERT_BIT |
+			    RXD_INVERT_BIT, mode);
+
+	/* 1. Select 40-bit data width width */
+	offset = COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET;
+	comphy_set_indirect(comphy_indir_regs, offset, DATA_WIDTH_40BIT,
+			    SEL_DATA_WIDTH_MASK, mode);
+
+	/* 2. Select reference clock(25M) and PHY mode (SATA) */
+	offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+	if (get_ref_clk() == 40)
+		ref_clk = REF_CLOCK_SPEED_40M;
+	else
+		ref_clk = REF_CLOCK_SPEED_25M;
+
+	comphy_set_indirect(comphy_indir_regs, offset, ref_clk | PHY_MODE_SATA,
+			    REF_FREF_SEL_MASK | PHY_MODE_MASK, mode);
+
+	/* 3. Use maximum PLL rate (no power save) */
+	offset = COMPHY_KVCO_CAL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+	comphy_set_indirect(comphy_indir_regs, offset, USE_MAX_PLL_RATE_BIT,
+			    USE_MAX_PLL_RATE_BIT, mode);
+
+	/* 4. Reset reserved bit */
+	comphy_set_indirect(comphy_indir_regs, COMPHY_RESERVED_REG, 0,
+			    PHYCTRL_FRM_PIN_BIT, mode);
+
+	/* 5. Set vendor-specific configuration (It is done in sata driver) */
+	/* XXX: in U-Boot below sequence was executed in this place, in Linux
+	 * not.  Now it is done only in U-Boot before this comphy
+	 * initialization - tests shows that it works ok, but in case of any
+	 * future problem it is left for reference.
+	 *   reg_set(MVEBU_REGS_BASE + 0xe00a0, 0, 0xffffffff);
+	 *   reg_set(MVEBU_REGS_BASE + 0xe00a4, BIT(6), BIT(6));
+	 */
+
+	/* Wait for > 55 us to allow PLL be enabled */
+	udelay(PLL_SET_DELAY_US);
+
+	/* Polling status */
+	mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET,
+		      COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET);
+
+	ret = polling_with_timeout(comphy_indir_regs +
+				   COMPHY_LANE2_INDIR_DATA_OFFSET,
+				   PLL_READY_TX_BIT, PLL_READY_TX_BIT,
+				   COMPHY_PLL_TIMEOUT, REG_32BIT);
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
+					     uint32_t comphy_mode)
+{
+	int ret = 0;
+	uint32_t mask, data, offset;
+	uintptr_t sd_ip_addr;
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+	debug_enter();
+
+	/* Set selector */
+	mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+
+	/* Serdes IP Base address
+	 * COMPHY Lane0 -- USB3/GBE1
+	 * COMPHY Lane1 -- PCIe/GBE0
+	 */
+	if (comphy_index == COMPHY_LANE0) {
+		/* Get usb3 and gbe */
+		sd_ip_addr = USB3_GBE1_PHY;
+	} else
+		sd_ip_addr = COMPHY_SD_ADDR;
+
+	/*
+	 * 1. Reset PHY by setting PHY input port PIN_RESET=1.
+	 * 2. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep
+	 *    PHY TXP/TXN output to idle state during PHY initialization
+	 * 3. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0.
+	 */
+	data = PIN_PU_IVEREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT;
+	mask = PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT |
+		PIN_PU_TX_BIT;
+	offset = MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index);
+	reg_set(offset, data, mask);
+
+	/* 4. Release reset to the PHY by setting PIN_RESET=0. */
+	data = 0;
+	mask = PIN_RESET_COMPHY_BIT;
+	reg_set(offset, data, mask);
+
+	/*
+	 * 5. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide COMPHY
+	 * bit rate
+	 */
+	if (mode == COMPHY_SGMII_MODE) {
+		/* SGMII 1G, SerDes speed 1.25G */
+		data |= SD_SPEED_1_25_G << GEN_RX_SEL_OFFSET;
+		data |= SD_SPEED_1_25_G << GEN_TX_SEL_OFFSET;
+	} else if (mode == COMPHY_HS_SGMII_MODE) {
+		/* HS SGMII (2.5G), SerDes speed 3.125G */
+		data |= SD_SPEED_2_5_G << GEN_RX_SEL_OFFSET;
+		data |= SD_SPEED_2_5_G << GEN_TX_SEL_OFFSET;
+	} else {
+		/* Other rates are not supported */
+		ERROR("unsupported SGMII speed on comphy lane%d\n",
+			comphy_index);
+		return -EINVAL;
+	}
+	mask = GEN_RX_SEL_MASK | GEN_TX_SEL_MASK;
+	reg_set(offset, data, mask);
+
+	/*
+	 * 6. Wait 10mS for bandgap and reference clocks to stabilize; then
+	 * start SW programming.
+	 */
+	mdelay(10);
+
+	/* 7. Program COMPHY register PHY_MODE */
+	data = PHY_MODE_SGMII;
+	mask = PHY_MODE_MASK;
+	reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask);
+
+	/*
+	 * 8. Set COMPHY register REFCLK_SEL to select the correct REFCLK
+	 * source
+	 */
+	data = 0;
+	mask = PHY_REF_CLK_SEL;
+	reg_set16(SGMIIPHY_ADDR(COMPHY_MISC_REG0_ADDR, sd_ip_addr), data, mask);
+
+	/*
+	 * 9. Set correct reference clock frequency in COMPHY register
+	 * REF_FREF_SEL.
+	 */
+	if (get_ref_clk() == 40)
+		data = REF_CLOCK_SPEED_50M;
+	else
+		data = REF_CLOCK_SPEED_25M;
+
+	mask = REF_FREF_SEL_MASK;
+	reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask);
+
+	/* 10. Program COMPHY register PHY_GEN_MAX[1:0]
+	 * This step is mentioned in the flow received from verification team.
+	 * However the PHY_GEN_MAX value is only meaningful for other interfaces
+	 * (not SGMII). For instance, it selects SATA speed 1.5/3/6 Gbps or PCIe
+	 * speed 2.5/5 Gbps
+	 */
+
+	/*
+	 * 11. Program COMPHY register SEL_BITS to set correct parallel data
+	 * bus width
+	 */
+	data = DATA_WIDTH_10BIT;
+	mask = SEL_DATA_WIDTH_MASK;
+	reg_set16(SGMIIPHY_ADDR(COMPHY_LOOPBACK_REG0, sd_ip_addr), data, mask);
+
+	/*
+	 * 12. As long as DFE function needs to be enabled in any mode,
+	 * COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F
+	 * for real chip during COMPHY power on.
+	 * The step 14 exists (and empty) in the original initialization flow
+	 * obtained from the verification team. According to the functional
+	 * specification DFE_UPDATE_EN already has the default value 0x3F
+	 */
+
+	/*
+	 * 13. Program COMPHY GEN registers.
+	 * These registers should be programmed based on the lab testing result
+	 * to achieve optimal performance. Please contact the CEA group to get
+	 * the related GEN table during real chip bring-up. We only required to
+	 * run though the entire registers programming flow defined by
+	 * "comphy_sgmii_phy_init" when the REF clock is 40 MHz. For REF clock
+	 * 25 MHz the default values stored in PHY registers are OK.
+	 */
+	debug("Running C-DPI phy init %s mode\n",
+	      mode == COMPHY_HS_SGMII_MODE ? "2G5" : "1G");
+	if (get_ref_clk() == 40)
+		comphy_sgmii_phy_init(comphy_index, mode, sd_ip_addr);
+
+	/*
+	 * 14. [Simulation Only] should not be used for real chip.
+	 * By pass power up calibration by programming EXT_FORCE_CAL_DONE
+	 * (R02h[9]) to 1 to shorten COMPHY simulation time.
+	 */
+
+	/*
+	 * 15. [Simulation Only: should not be used for real chip]
+	 * Program COMPHY register FAST_DFE_TIMER_EN=1 to shorten RX training
+	 * simulation time.
+	 */
+
+	/*
+	 * 16. Check the PHY Polarity invert bit
+	 */
+	data = 0x0;
+	if (invert & COMPHY_POLARITY_TXD_INVERT)
+		data |= TXD_INVERT_BIT;
+	if (invert & COMPHY_POLARITY_RXD_INVERT)
+		data |= RXD_INVERT_BIT;
+	reg_set16(SGMIIPHY_ADDR(COMPHY_SYNC_PATTERN_REG, sd_ip_addr), data, 0);
+
+	/*
+	 * 17. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 to
+	 * start PHY power up sequence. All the PHY register programming should
+	 * be done before PIN_PU_PLL=1. There should be no register programming
+	 * for normal PHY operation from this point.
+	 */
+	reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index),
+		PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT,
+		PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT);
+
+	/*
+	 * 18. Wait for PHY power up sequence to finish by checking output ports
+	 * PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1.
+	 */
+	ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
+				   COMPHY_PHY_STATUS_OFFSET(comphy_index),
+				   PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
+				   PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
+				   COMPHY_PLL_TIMEOUT, REG_32BIT);
+	if (ret)
+		ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index);
+
+	/*
+	 * 19. Set COMPHY input port PIN_TX_IDLE=0
+	 */
+	reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index),
+		0x0, PIN_TX_IDLE_BIT);
+
+	/*
+	 * 20. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1. To
+	 * start RX initialization. PIN_RX_INIT_DONE will be cleared to 0 by the
+	 * PHY After RX initialization is done, PIN_RX_INIT_DONE will be set to
+	 * 1 by COMPHY Set PIN_RX_INIT=0 after PIN_RX_INIT_DONE= 1. Please
+	 * refer to RX initialization part for details.
+	 */
+	reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index),
+		PHY_RX_INIT_BIT, 0x0);
+
+	ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
+				   COMPHY_PHY_STATUS_OFFSET(comphy_index),
+				   PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
+				   PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
+				   COMPHY_PLL_TIMEOUT, REG_32BIT);
+	if (ret)
+		ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index);
+
+
+	ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
+				   COMPHY_PHY_STATUS_OFFSET(comphy_index),
+				   PHY_RX_INIT_DONE_BIT, PHY_RX_INIT_DONE_BIT,
+				   COMPHY_PLL_TIMEOUT, REG_32BIT);
+	if (ret)
+		ERROR("Failed to init RX of SGMII PHY %d\n", comphy_index);
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
+					    uint32_t comphy_mode)
+{
+	int ret = 0;
+	uintptr_t reg_base = 0;
+	uint32_t mask, data, addr, cfg, ref_clk;
+	void (*usb3_reg_set)(uintptr_t addr, uint32_t reg_offset, uint16_t data,
+			     uint16_t mask, int mode);
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+	debug_enter();
+
+	/* Set phy seclector */
+	mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+
+	/* Set usb3 reg access func, Lane2 is indirect access */
+	if (comphy_index == COMPHY_LANE2) {
+		usb3_reg_set = &comphy_set_indirect;
+		reg_base = COMPHY_INDIRECT_REG;
+	} else {
+		/* Get the direct access register resource and map */
+		usb3_reg_set = &comphy_usb3_set_direct;
+		reg_base = USB3_GBE1_PHY;
+	}
+
+	/*
+	 * 0. Set PHY OTG Control(0x5d034), bit 4, Power up OTG module The
+	 * register belong to UTMI module, so it is set in UTMI phy driver.
+	 */
+
+	/*
+	 * 1. Set PRD_TXDEEMPH (3.5db de-emph)
+	 */
+	mask = PRD_TXDEEMPH0_MASK | PRD_TXMARGIN_MASK | PRD_TXSWING_MASK |
+		CFG_TX_ALIGN_POS_MASK;
+	usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG0_ADDR, PRD_TXDEEMPH0_MASK,
+		     mask, mode);
+
+	/*
+	 * 2. Set BIT0: enable transmitter in high impedance mode
+	 *    Set BIT[3:4]: delay 2 clock cycles for HiZ off latency
+	 *    Set BIT6: Tx detect Rx at HiZ mode
+	 *    Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db
+	 *            together with bit 0 of COMPHY_REG_LANE_CFG0_ADDR register
+	 */
+	mask = PRD_TXDEEMPH1_MASK | TX_DET_RX_MODE | GEN2_TX_DATA_DLY_MASK |
+		TX_ELEC_IDLE_MODE_EN;
+	data = TX_DET_RX_MODE | GEN2_TX_DATA_DLY_DEFT | TX_ELEC_IDLE_MODE_EN;
+	usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG1_ADDR, data, mask, mode);
+
+	/*
+	 * 3. Set Spread Spectrum Clock Enabled
+	 */
+	usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG4_ADDR,
+		     SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN, mode);
+
+	/*
+	 * 4. Set Override Margining Controls From the MAC:
+	 *    Use margining signals from lane configuration
+	 */
+	usb3_reg_set(reg_base, COMPHY_REG_TEST_MODE_CTRL_ADDR,
+		     MODE_MARGIN_OVERRIDE, REG_16_BIT_MASK, mode);
+
+	/*
+	 * 5. Set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles
+	 *    set Mode Clock Source = PCLK is generated from REFCLK
+	 */
+	usb3_reg_set(reg_base, COMPHY_REG_GLOB_CLK_SRC_LO_ADDR, 0x0,
+		     (MODE_CLK_SRC | BUNDLE_PERIOD_SEL | BUNDLE_PERIOD_SCALE |
+		      BUNDLE_SAMPLE_CTRL | PLL_READY_DLY), mode);
+
+	/*
+	 * 6. Set G2 Spread Spectrum Clock Amplitude at 4K
+	 */
+	usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_2,
+		     G2_TX_SSC_AMP_VALUE_20, G2_TX_SSC_AMP_MASK, mode);
+
+	/*
+	 * 7. Unset G3 Spread Spectrum Clock Amplitude
+	 *    set G3 TX and RX Register Master Current Select
+	 */
+	mask = G3_TX_SSC_AMP_MASK | G3_VREG_RXTX_MAS_ISET_MASK |
+		RSVD_PH03FH_6_0_MASK;
+	usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_3,
+		     G3_VREG_RXTX_MAS_ISET_60U, mask, mode);
+
+	/*
+	 * 8. Check crystal jumper setting and program the Power and PLL Control
+	 * accordingly Change RX wait
+	 */
+	if (get_ref_clk() == 40) {
+		ref_clk = REF_CLOCK_SPEED_40M;
+		cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT;
+
+	} else {
+		/* 25 MHz */
+		ref_clk = USB3_REF_CLOCK_SPEED_25M;
+		cfg = CFG_PM_RXDLOZ_WAIT_7_UNIT;
+	}
+
+	mask = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
+		PU_TX_INTP_BIT | PU_DFE_BIT | PLL_LOCK_BIT | PHY_MODE_MASK |
+		REF_FREF_SEL_MASK;
+	data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
+		PU_TX_INTP_BIT | PU_DFE_BIT | PHY_MODE_USB3 | ref_clk;
+	usb3_reg_set(reg_base, COMPHY_POWER_PLL_CTRL, data,  mask, mode);
+
+	mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK |
+		CFG_PM_RXDLOZ_WAIT_MASK;
+	data = CFG_PM_RXDEN_WAIT_1_UNIT  | cfg;
+	usb3_reg_set(reg_base, COMPHY_REG_PWR_MGM_TIM1_ADDR, data, mask, mode);
+
+	/*
+	 * 9. Enable idle sync
+	 */
+	data = UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN;
+	usb3_reg_set(reg_base, COMPHY_REG_UNIT_CTRL_ADDR, data, REG_16_BIT_MASK,
+		     mode);
+
+	/*
+	 * 10. Enable the output of 500M clock
+	 */
+	data = MISC_REG0_DEFAULT_VALUE | CLK500M_EN;
+	usb3_reg_set(reg_base, COMPHY_MISC_REG0_ADDR, data, REG_16_BIT_MASK,
+		     mode);
+
+	/*
+	 * 11. Set 20-bit data width
+	 */
+	usb3_reg_set(reg_base, COMPHY_LOOPBACK_REG0, DATA_WIDTH_20BIT,
+		     REG_16_BIT_MASK, mode);
+
+	/*
+	 * 12. Override Speed_PLL value and use MAC PLL
+	 */
+	usb3_reg_set(reg_base, COMPHY_KVCO_CAL_CTRL,
+		     (SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT),
+		     REG_16_BIT_MASK, mode);
+
+	/*
+	 * 13. Check the Polarity invert bit
+	 */
+	if (invert & COMPHY_POLARITY_TXD_INVERT)
+		usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, TXD_INVERT_BIT,
+			     TXD_INVERT_BIT, mode);
+	if (invert & COMPHY_POLARITY_RXD_INVERT)
+		usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, RXD_INVERT_BIT,
+			     RXD_INVERT_BIT, mode);
+
+	/*
+	 * 14. Set max speed generation to USB3.0 5Gbps
+	 */
+	usb3_reg_set(reg_base, COMPHY_SYNC_MASK_GEN_REG, PHY_GEN_USB3_5G,
+		     PHY_GEN_MAX_MASK, mode);
+
+	/*
+	 * 15. Set capacitor value for FFE gain peaking to 0xF
+	 */
+	usb3_reg_set(reg_base, COMPHY_REG_GEN3_SETTINGS_3,
+		     COMPHY_GEN_FFE_CAP_SEL_VALUE, COMPHY_GEN_FFE_CAP_SEL_MASK,
+		     mode);
+
+	/*
+	 * 16. Release SW reset
+	 */
+	data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4;
+	usb3_reg_set(reg_base, COMPHY_REG_GLOB_PHY_CTRL0_ADDR, data,
+		     REG_16_BIT_MASK, mode);
+
+	/* Wait for > 55 us to allow PCLK be enabled */
+	udelay(PLL_SET_DELAY_US);
+
+	if (comphy_index == COMPHY_LANE2) {
+		data = COMPHY_LOOPBACK_REG0 + USB3PHY_LANE2_REG_BASE_OFFSET;
+		mmio_write_32(reg_base + COMPHY_LANE2_INDIR_ADDR_OFFSET,
+			      data);
+
+		addr = COMPHY_LOOPBACK_REG0 + USB3PHY_LANE2_REG_BASE_OFFSET;
+		ret = polling_with_timeout(addr, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
+					   COMPHY_PLL_TIMEOUT, REG_32BIT);
+	} else {
+		ret = polling_with_timeout(LANE_STATUS1_ADDR(USB3) + reg_base,
+					   TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
+					   COMPHY_PLL_TIMEOUT, REG_16BIT);
+	}
+	if (ret)
+		ERROR("Failed to lock USB3 PLL\n");
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
+					    uint32_t comphy_mode)
+{
+	int ret;
+	uint32_t ref_clk;
+	int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
+
+	debug_enter();
+
+	/* 1. Enable max PLL. */
+	reg_set16(LANE_CFG1_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  USE_MAX_PLL_RATE_EN, 0x0);
+
+	/* 2. Select 20 bit SERDES interface. */
+	reg_set16(GLOB_CLK_SRC_LO_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  CFG_SEL_20B, 0);
+
+	/* 3. Force to use reg setting for PCIe mode */
+	reg_set16(MISC_REG1_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  SEL_BITS_PCIE_FORCE, 0);
+
+	/* 4. Change RX wait */
+	reg_set16(PWR_MGM_TIM1_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  CFG_PM_RXDEN_WAIT_1_UNIT | CFG_PM_RXDLOZ_WAIT_12_UNIT,
+		  (CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK |
+		   CFG_PM_RXDLOZ_WAIT_MASK));
+
+	/* 5. Enable idle sync */
+	reg_set16(UNIT_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN, REG_16_BIT_MASK);
+
+	/* 6. Enable the output of 100M/125M/500M clock */
+	reg_set16(MISC_REG0_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  MISC_REG0_DEFAULT_VALUE | CLK500M_EN | CLK100M_125M_EN,
+		  REG_16_BIT_MASK);
+
+	/*
+	 * 7. Enable TX, PCIE global register, 0xd0074814, it is done in
+	 * PCI-E driver
+	 */
+
+	/*
+	 * 8. Check crystal jumper setting and program the Power and PLL
+	 * Control accordingly
+	 */
+
+	if (get_ref_clk() == 40)
+		ref_clk = REF_CLOCK_SPEED_40M;
+	else
+		ref_clk = PCIE_REF_CLOCK_SPEED_25M;
+
+	reg_set16(PWR_PLL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  (PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
+		   PU_TX_INTP_BIT | PU_DFE_BIT | ref_clk | PHY_MODE_PCIE),
+		  REG_16_BIT_MASK);
+
+	/* 9. Override Speed_PLL value and use MAC PLL */
+	reg_set16(KVCO_CAL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT, REG_16_BIT_MASK);
+
+	/* 10. Check the Polarity invert bit */
+	if (invert & COMPHY_POLARITY_TXD_INVERT)
+		reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR,
+			  TXD_INVERT_BIT, 0x0);
+
+	if (invert & COMPHY_POLARITY_RXD_INVERT)
+		reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR,
+			  RXD_INVERT_BIT, 0x0);
+
+	/* 11. Release SW reset */
+	reg_set16(GLOB_PHY_CTRL0_ADDR(PCIE) + COMPHY_SD_ADDR,
+		  MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32,
+		  SOFT_RESET | MODE_REFDIV);
+
+	/* Wait for > 55 us to allow PCLK be enabled */
+	udelay(PLL_SET_DELAY_US);
+
+	ret = polling_with_timeout(LANE_STATUS1_ADDR(PCIE) + COMPHY_SD_ADDR,
+				   TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
+				   COMPHY_PLL_TIMEOUT, REG_16BIT);
+	if (ret)
+		ERROR("Failed to lock PCIE PLL\n");
+
+	debug_exit();
+
+	return ret;
+}
+
+int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode)
+{
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int ret = 0;
+
+	debug_enter();
+
+	switch (mode) {
+	case(COMPHY_SATA_MODE):
+		ret = mvebu_a3700_comphy_sata_power_on(comphy_index,
+						       comphy_mode);
+		break;
+	case(COMPHY_SGMII_MODE):
+	case(COMPHY_HS_SGMII_MODE):
+		ret = mvebu_a3700_comphy_sgmii_power_on(comphy_index,
+							comphy_mode);
+		break;
+	case (COMPHY_USB3_MODE):
+	case (COMPHY_USB3H_MODE):
+		ret = mvebu_a3700_comphy_usb3_power_on(comphy_index,
+						       comphy_mode);
+		break;
+	case (COMPHY_PCIE_MODE):
+		ret = mvebu_a3700_comphy_pcie_power_on(comphy_index,
+						       comphy_mode);
+		break;
+	default:
+		ERROR("comphy%d: unsupported comphy mode\n", comphy_index);
+		ret = -EINVAL;
+		break;
+	}
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_a3700_comphy_usb3_power_off(void)
+{
+	/*
+	 * Currently the USB3 MAC will control the USB3 PHY to set it to low
+	 * state, thus do not need to power off USB3 PHY again.
+	 */
+	debug_enter();
+	debug_exit();
+
+	return 0;
+}
+
+static int mvebu_a3700_comphy_sata_power_off(uint32_t comphy_mode)
+{
+	uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	uint32_t offset;
+
+	debug_enter();
+
+	/* Set phy isolation mode */
+	offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
+	comphy_set_indirect(comphy_indir_regs, offset, PHY_ISOLATE_MODE,
+			    PHY_ISOLATE_MODE, mode);
+
+	/* Power off PLL, Tx, Rx */
+	offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
+	comphy_set_indirect(comphy_indir_regs, offset, 0,
+			    PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT, mode);
+
+	debug_exit();
+
+	return 0;
+}
+
+int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode)
+{
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int err = 0;
+
+	debug_enter();
+
+	switch (mode) {
+	case (COMPHY_USB3_MODE):
+	case (COMPHY_USB3H_MODE):
+		err = mvebu_a3700_comphy_usb3_power_off();
+		break;
+	case (COMPHY_SATA_MODE):
+		err = mvebu_a3700_comphy_sata_power_off(comphy_mode);
+		break;
+
+	default:
+		debug("comphy%d: power off is not implemented for mode %d\n",
+		      comphy_index, mode);
+		break;
+	}
+
+	debug_exit();
+
+	return err;
+}
+
+static int mvebu_a3700_comphy_sata_is_pll_locked(void)
+{
+	uint32_t data, addr;
+	uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
+	int ret = 0;
+
+	debug_enter();
+
+	/* Polling status */
+	mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET,
+	       COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET);
+	addr = comphy_indir_regs + COMPHY_LANE2_INDIR_DATA_OFFSET;
+	data = polling_with_timeout(addr, PLL_READY_TX_BIT, PLL_READY_TX_BIT,
+				    COMPHY_PLL_TIMEOUT, REG_32BIT);
+
+	if (data != 0) {
+		ERROR("TX PLL is not locked\n");
+		ret = -ETIMEDOUT;
+	}
+
+	debug_exit();
+
+	return ret;
+}
+
+int mvebu_3700_comphy_is_pll_locked(uint8_t comphy_index, uint32_t comphy_mode)
+{
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int ret = 0;
+
+	debug_enter();
+
+	switch (mode) {
+	case(COMPHY_SATA_MODE):
+		ret = mvebu_a3700_comphy_sata_is_pll_locked();
+		break;
+
+	default:
+		ERROR("comphy[%d] mode[%d] doesn't support PLL lock check\n",
+			comphy_index, mode);
+		ret = -EINVAL;
+		break;
+	}
+
+	debug_exit();
+
+	return ret;
+}
diff --git a/drivers/marvell/comphy/phy-comphy-3700.h b/drivers/marvell/comphy/phy-comphy-3700.h
new file mode 100644
index 0000000..1628e36
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-3700.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PHY_COMPHY_3700_H
+#define PHY_COMPHY_3700_H
+
+#define PLL_SET_DELAY_US			600
+#define COMPHY_PLL_TIMEOUT			1000
+#define REG_16_BIT_MASK				0xFFFF
+
+#define COMPHY_SELECTOR_PHY_REG			0xFC
+/* bit0: 0: Lane0 is GBE0; 1: Lane1 is PCIE */
+#define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT	BIT(0)
+/* bit4: 0: Lane1 is GBE1; 1: Lane1 is USB3 */
+#define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT	BIT(4)
+/* bit8: 0: Lane1 is USB, Lane2 is SATA; 1: Lane2 is USB3 */
+#define COMPHY_SELECTOR_USB3_PHY_SEL_BIT	BIT(8)
+
+/* SATA PHY register offset */
+#define SATAPHY_LANE2_REG_BASE_OFFSET		0x200
+
+/* USB3 PHY offset compared to SATA PHY */
+#define USB3PHY_LANE2_REG_BASE_OFFSET		0x200
+
+/* Comphy lane2 indirect access register offset */
+#define COMPHY_LANE2_INDIR_ADDR_OFFSET		0x0
+#define COMPHY_LANE2_INDIR_DATA_OFFSET		0x4
+
+/* PHY shift to get related register address */
+enum {
+	PCIE = 1,
+	USB3,
+};
+
+#define PCIEPHY_SHFT		2
+#define USB3PHY_SHFT		2
+#define PHY_SHFT(unit)		((unit == PCIE) ? PCIEPHY_SHFT : USB3PHY_SHFT)
+
+/* PHY register */
+#define COMPHY_POWER_PLL_CTRL		0x01
+#define PWR_PLL_CTRL_ADDR(unit)		(COMPHY_POWER_PLL_CTRL * PHY_SHFT(unit))
+#define PU_IVREF_BIT			BIT(15)
+#define PU_PLL_BIT			BIT(14)
+#define PU_RX_BIT			BIT(13)
+#define PU_TX_BIT			BIT(12)
+#define PU_TX_INTP_BIT			BIT(11)
+#define PU_DFE_BIT			BIT(10)
+#define RESET_DTL_RX_BIT		BIT(9)
+#define PLL_LOCK_BIT			BIT(8)
+#define REF_FREF_SEL_OFFSET		0
+#define REF_FREF_SEL_MASK		(0x1F << REF_FREF_SEL_OFFSET)
+#define REF_CLOCK_SPEED_25M		(0x1 << REF_FREF_SEL_OFFSET)
+#define REF_CLOCK_SPEED_30M		(0x2 << REF_FREF_SEL_OFFSET)
+#define PCIE_REF_CLOCK_SPEED_25M	REF_CLOCK_SPEED_30M
+#define USB3_REF_CLOCK_SPEED_25M	REF_CLOCK_SPEED_30M
+#define REF_CLOCK_SPEED_40M		(0x3 << REF_FREF_SEL_OFFSET)
+#define REF_CLOCK_SPEED_50M		(0x4 << REF_FREF_SEL_OFFSET)
+#define PHY_MODE_OFFSET			5
+#define PHY_MODE_MASK			(7 << PHY_MODE_OFFSET)
+#define PHY_MODE_SATA			(0x0 << PHY_MODE_OFFSET)
+#define PHY_MODE_PCIE			(0x3 << PHY_MODE_OFFSET)
+#define PHY_MODE_SGMII			(0x4 << PHY_MODE_OFFSET)
+#define PHY_MODE_USB3			(0x5 << PHY_MODE_OFFSET)
+
+#define COMPHY_KVCO_CAL_CTRL		0x02
+#define KVCO_CAL_CTRL_ADDR(unit)	(COMPHY_KVCO_CAL_CTRL * PHY_SHFT(unit))
+#define USE_MAX_PLL_RATE_BIT		BIT(12)
+#define SPEED_PLL_OFFSET		2
+#define SPEED_PLL_MASK			(0x3F << SPEED_PLL_OFFSET)
+#define SPEED_PLL_VALUE_16		(0x10 << SPEED_PLL_OFFSET)
+
+#define COMPHY_RESERVED_REG		0x0E
+#define PHYCTRL_FRM_PIN_BIT		BIT(13)
+
+#define COMPHY_LOOPBACK_REG0		0x23
+#define DIG_LB_EN_ADDR(unit)		(COMPHY_LOOPBACK_REG0 * PHY_SHFT(unit))
+#define SEL_DATA_WIDTH_OFFSET		10
+#define SEL_DATA_WIDTH_MASK		(0x3 << SEL_DATA_WIDTH_OFFSET)
+#define DATA_WIDTH_10BIT		(0x0 << SEL_DATA_WIDTH_OFFSET)
+#define DATA_WIDTH_20BIT		(0x1 << SEL_DATA_WIDTH_OFFSET)
+#define DATA_WIDTH_40BIT		(0x2 << SEL_DATA_WIDTH_OFFSET)
+#define PLL_READY_TX_BIT		BIT(4)
+
+#define COMPHY_SYNC_PATTERN_REG		0x24
+#define SYNC_PATTERN_REG_ADDR(unit)	(COMPHY_SYNC_PATTERN_REG * \
+					 PHY_SHFT(unit))
+#define TXD_INVERT_BIT			BIT(10)
+#define RXD_INVERT_BIT			BIT(11)
+
+#define COMPHY_SYNC_MASK_GEN_REG	0x25
+#define PHY_GEN_MAX_OFFSET		10
+#define PHY_GEN_MAX_MASK		(3 << PHY_GEN_MAX_OFFSET)
+#define PHY_GEN_USB3_5G			(1 << PHY_GEN_MAX_OFFSET)
+
+#define COMPHY_ISOLATION_CTRL_REG	0x26
+#define ISOLATION_CTRL_REG_ADDR(unit)	(COMPHY_ISOLATION_CTRL_REG * \
+					 PHY_SHFT(unit))
+#define PHY_ISOLATE_MODE		BIT(15)
+
+#define COMPHY_MISC_REG0_ADDR		0x4F
+#define MISC_REG0_ADDR(unit)		(COMPHY_MISC_REG0_ADDR * PHY_SHFT(unit))
+#define CLK100M_125M_EN			BIT(4)
+#define CLK500M_EN			BIT(7)
+#define PHY_REF_CLK_SEL			BIT(10)
+#define MISC_REG0_DEFAULT_VALUE		0xA00D
+
+#define COMPHY_REG_GEN2_SET_2	0x3e
+#define GEN2_SETTING_2_ADDR(unit)	(COMPHY_REG_GEN2_SET_2 * PHY_SHFT(unit))
+#define G2_TX_SSC_AMP_VALUE_20		BIT(14)
+#define G2_TX_SSC_AMP_OFF		9
+#define G2_TX_SSC_AMP_LEN		7
+#define G2_TX_SSC_AMP_MASK		(((1 << G2_TX_SSC_AMP_LEN) - 1) << \
+					 G2_TX_SSC_AMP_OFF)
+
+#define COMPHY_REG_GEN2_SET_3	0x3f
+#define GEN2_SETTING_3_ADDR(unit)	(COMPHY_REG_GEN2_SET_3 * PHY_SHFT(unit))
+#define G3_TX_SSC_AMP_OFF		9
+#define G3_TX_SSC_AMP_LEN		7
+#define G3_TX_SSC_AMP_MASK		(((1 << G2_TX_SSC_AMP_LEN) - 1) << \
+					 G2_TX_SSC_AMP_OFF)
+#define G3_VREG_RXTX_MAS_ISET_OFF	7
+#define G3_VREG_RXTX_MAS_ISET_60U	(0 << G3_VREG_RXTX_MAS_ISET_OFF)
+#define G3_VREG_RXTX_MAS_ISET_80U	(1 << G3_VREG_RXTX_MAS_ISET_OFF)
+#define G3_VREG_RXTX_MAS_ISET_100U	(2 << G3_VREG_RXTX_MAS_ISET_OFF)
+#define G3_VREG_RXTX_MAS_ISET_120U	(3 << G3_VREG_RXTX_MAS_ISET_OFF)
+#define G3_VREG_RXTX_MAS_ISET_MASK	(BIT(7) | BIT(8))
+#define RSVD_PH03FH_6_0_OFF		0
+#define RSVD_PH03FH_6_0_LEN		7
+#define RSVD_PH03FH_6_0_MASK		(((1 << RSVD_PH03FH_6_0_LEN) - 1) << \
+					 RSVD_PH03FH_6_0_OFF)
+
+#define COMPHY_REG_UNIT_CTRL_ADDR	0x48
+#define UNIT_CTRL_ADDR(unit)		(COMPHY_REG_UNIT_CTRL_ADDR * \
+					 PHY_SHFT(unit))
+#define IDLE_SYNC_EN			BIT(12)
+#define UNIT_CTRL_DEFAULT_VALUE		0x60
+
+#define COMPHY_MISC_REG1_ADDR		0x73
+#define MISC_REG1_ADDR(unit)		(COMPHY_MISC_REG1_ADDR * PHY_SHFT(unit))
+#define SEL_BITS_PCIE_FORCE		BIT(15)
+
+#define COMPHY_REG_GEN3_SETTINGS_3	0x112
+#define COMPHY_GEN_FFE_CAP_SEL_MASK	0xF
+#define COMPHY_GEN_FFE_CAP_SEL_VALUE	0xF
+
+#define COMPHY_REG_LANE_CFG0_ADDR	0x180
+#define LANE_CFG0_ADDR(unit)		(COMPHY_REG_LANE_CFG0_ADDR * \
+					 PHY_SHFT(unit))
+#define PRD_TXDEEMPH0_MASK		BIT(0)
+#define PRD_TXMARGIN_MASK		(BIT(1) | BIT(2) | BIT(3))
+#define PRD_TXSWING_MASK		BIT(4)
+#define CFG_TX_ALIGN_POS_MASK		(BIT(5) | BIT(6) | BIT(7) | BIT(8))
+
+#define COMPHY_REG_LANE_CFG1_ADDR	0x181
+#define LANE_CFG1_ADDR(unit)		(COMPHY_REG_LANE_CFG1_ADDR * \
+					 PHY_SHFT(unit))
+#define PRD_TXDEEMPH1_MASK		BIT(15)
+#define USE_MAX_PLL_RATE_EN		BIT(9)
+#define TX_DET_RX_MODE			BIT(6)
+#define GEN2_TX_DATA_DLY_MASK		(BIT(3) | BIT(4))
+#define GEN2_TX_DATA_DLY_DEFT		(2 << 3)
+#define TX_ELEC_IDLE_MODE_EN		BIT(0)
+
+#define COMPHY_REG_LANE_STATUS1_ADDR	0x183
+#define LANE_STATUS1_ADDR(unit)		(COMPHY_REG_LANE_STATUS1_ADDR * \
+					 PHY_SHFT(unit))
+#define TXDCLK_PCLK_EN				BIT(0)
+
+#define COMPHY_REG_LANE_CFG4_ADDR	0x188
+#define LANE_CFG4_ADDR(unit)		(COMPHY_REG_LANE_CFG4_ADDR * \
+					 PHY_SHFT(unit))
+#define SPREAD_SPECTRUM_CLK_EN		BIT(7)
+
+#define COMPHY_REG_GLOB_PHY_CTRL0_ADDR	0x1C1
+#define GLOB_PHY_CTRL0_ADDR(unit)	(COMPHY_REG_GLOB_PHY_CTRL0_ADDR * \
+					 PHY_SHFT(unit))
+#define SOFT_RESET			BIT(0)
+#define MODE_REFDIV			0x30
+#define MODE_CORE_CLK_FREQ_SEL		BIT(9)
+#define MODE_PIPE_WIDTH_32		BIT(3)
+#define MODE_REFDIV_OFFSET		4
+#define MODE_REFDIV_LEN			2
+#define MODE_REFDIV_MASK		(0x3 << MODE_REFDIV_OFFSET)
+#define MODE_REFDIV_BY_4		(0x2 << MODE_REFDIV_OFFSET)
+
+#define COMPHY_REG_TEST_MODE_CTRL_ADDR	0x1C2
+#define TEST_MODE_CTRL_ADDR(unit)	(COMPHY_REG_TEST_MODE_CTRL_ADDR * \
+					 PHY_SHFT(unit))
+#define MODE_MARGIN_OVERRIDE		BIT(2)
+
+#define COMPHY_REG_GLOB_CLK_SRC_LO_ADDR	0x1C3
+#define GLOB_CLK_SRC_LO_ADDR(unit)	(COMPHY_REG_GLOB_CLK_SRC_LO_ADDR * \
+					 PHY_SHFT(unit))
+#define MODE_CLK_SRC			BIT(0)
+#define BUNDLE_PERIOD_SEL		BIT(1)
+#define BUNDLE_PERIOD_SCALE		(BIT(2) | BIT(3))
+#define BUNDLE_SAMPLE_CTRL		BIT(4)
+#define PLL_READY_DLY			(BIT(5) | BIT(6) | BIT(7))
+#define CFG_SEL_20B			BIT(15)
+
+#define COMPHY_REG_PWR_MGM_TIM1_ADDR	0x1D0
+#define PWR_MGM_TIM1_ADDR(unit)		(COMPHY_REG_PWR_MGM_TIM1_ADDR * \
+					 PHY_SHFT(unit))
+#define CFG_PM_OSCCLK_WAIT_OFF		12
+#define CFG_PM_OSCCLK_WAIT_LEN		4
+#define CFG_PM_OSCCLK_WAIT_MASK		(((1 << CFG_PM_OSCCLK_WAIT_LEN) - 1) \
+					 << CFG_PM_OSCCLK_WAIT_OFF)
+#define CFG_PM_RXDEN_WAIT_OFF		8
+#define CFG_PM_RXDEN_WAIT_LEN		4
+#define CFG_PM_RXDEN_WAIT_MASK		(((1 << CFG_PM_RXDEN_WAIT_LEN) - 1) \
+					 << CFG_PM_RXDEN_WAIT_OFF)
+#define CFG_PM_RXDEN_WAIT_1_UNIT	(1 << CFG_PM_RXDEN_WAIT_OFF)
+#define CFG_PM_RXDLOZ_WAIT_OFF		0
+#define CFG_PM_RXDLOZ_WAIT_LEN		8
+#define CFG_PM_RXDLOZ_WAIT_MASK		(((1 << CFG_PM_RXDLOZ_WAIT_LEN) - 1) \
+					 << CFG_PM_RXDLOZ_WAIT_OFF)
+#define CFG_PM_RXDLOZ_WAIT_7_UNIT	(7 << CFG_PM_RXDLOZ_WAIT_OFF)
+#define CFG_PM_RXDLOZ_WAIT_12_UNIT	(0xC << CFG_PM_RXDLOZ_WAIT_OFF)
+
+/* SGMII */
+#define COMPHY_PHY_CFG1_OFFSET(lane)	((1 - (lane)) * 0x28)
+#define PIN_PU_IVEREF_BIT		BIT(1)
+#define PIN_RESET_CORE_BIT		BIT(11)
+#define PIN_RESET_COMPHY_BIT		BIT(12)
+#define PIN_PU_PLL_BIT			BIT(16)
+#define PIN_PU_RX_BIT			BIT(17)
+#define PIN_PU_TX_BIT			BIT(18)
+#define PIN_TX_IDLE_BIT			BIT(19)
+#define GEN_RX_SEL_OFFSET		22
+#define GEN_RX_SEL_MASK			(0xF << GEN_RX_SEL_OFFSET)
+#define GEN_TX_SEL_OFFSET		26
+#define GEN_TX_SEL_MASK			(0xF << GEN_TX_SEL_OFFSET)
+#define PHY_RX_INIT_BIT			BIT(30)
+#define SD_SPEED_1_25_G			0x6
+#define SD_SPEED_2_5_G			0x8
+
+/* COMPHY status reg:
+ * lane0: PCIe/GbE0 PHY Status 1
+ * lane1: USB3/GbE1 PHY Status 1
+ */
+#define COMPHY_PHY_STATUS_OFFSET(lane)	(0x18 + (1 - (lane)) * 0x28)
+#define PHY_RX_INIT_DONE_BIT		BIT(0)
+#define PHY_PLL_READY_RX_BIT		BIT(2)
+#define PHY_PLL_READY_TX_BIT		BIT(3)
+
+#define SGMIIPHY_ADDR(off, base)	((((off) & 0x00007FF) * 2) + (base))
+
+#define MAX_LANE_NR			3
+
+/* comphy API */
+int mvebu_3700_comphy_is_pll_locked(uint8_t comphy_index, uint32_t comphy_mode);
+int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode);
+int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode);
+#endif /* PHY_COMPHY_3700_H */
diff --git a/drivers/marvell/comphy/phy-comphy-common.h b/drivers/marvell/comphy/phy-comphy-common.h
new file mode 100644
index 0000000..e3b430a
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-common.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 ana A3700 common */
+
+#ifndef PHY_COMPHY_COMMON_H
+#define PHY_COMPHY_COMMON_H
+
+/* #define DEBUG_COMPHY */
+#ifdef DEBUG_COMPHY
+#define debug(format...) printf(format)
+#else
+#define debug(format, arg...)
+#endif
+
+/* A lane is described by 4 fields:
+ *  - bit 1~0 represent comphy polarity invert
+ *  - bit 7~2 represent comphy speed
+ *  - bit 11~8 represent unit index
+ *  - bit 16~12 represent mode
+ *  - bit 17 represent comphy indication of clock source
+ *  - bit 20~18 represents pcie width (in case of pcie comphy config.)
+ *  - bit 21 represents the source of the request (Linux/Bootloader),
+ *           (reguired only for PCIe!)
+ *  - bit 31~22 reserved
+ */
+
+#define COMPHY_INVERT_OFFSET	0
+#define COMPHY_INVERT_LEN	2
+#define COMPHY_INVERT_MASK	COMPHY_MASK(COMPHY_INVERT_OFFSET, \
+						COMPHY_INVERT_LEN)
+#define COMPHY_SPEED_OFFSET	(COMPHY_INVERT_OFFSET + COMPHY_INVERT_LEN)
+#define COMPHY_SPEED_LEN	6
+#define COMPHY_SPEED_MASK	COMPHY_MASK(COMPHY_SPEED_OFFSET, \
+						COMPHY_SPEED_LEN)
+#define COMPHY_UNIT_ID_OFFSET	(COMPHY_SPEED_OFFSET + COMPHY_SPEED_LEN)
+#define COMPHY_UNIT_ID_LEN	4
+#define COMPHY_UNIT_ID_MASK	COMPHY_MASK(COMPHY_UNIT_ID_OFFSET, \
+						COMPHY_UNIT_ID_LEN)
+#define COMPHY_MODE_OFFSET	(COMPHY_UNIT_ID_OFFSET + COMPHY_UNIT_ID_LEN)
+#define COMPHY_MODE_LEN		5
+#define COMPHY_MODE_MASK	COMPHY_MASK(COMPHY_MODE_OFFSET, COMPHY_MODE_LEN)
+#define COMPHY_CLK_SRC_OFFSET	(COMPHY_MODE_OFFSET + COMPHY_MODE_LEN)
+#define COMPHY_CLK_SRC_LEN	1
+#define COMPHY_CLK_SRC_MASK	COMPHY_MASK(COMPHY_CLK_SRC_OFFSET, \
+						COMPHY_CLK_SRC_LEN)
+#define COMPHY_PCI_WIDTH_OFFSET	(COMPHY_CLK_SRC_OFFSET + COMPHY_CLK_SRC_LEN)
+#define COMPHY_PCI_WIDTH_LEN	3
+#define COMPHY_PCI_WIDTH_MASK	COMPHY_MASK(COMPHY_PCI_WIDTH_OFFSET, \
+						COMPHY_PCI_WIDTH_LEN)
+#define COMPHY_PCI_CALLER_OFFSET \
+			(COMPHY_PCI_WIDTH_OFFSET + COMPHY_PCI_WIDTH_LEN)
+#define COMPHY_PCI_CALLER_LEN	1
+#define COMPHY_PCI_CALLER_MASK	COMPHY_MASK(COMPHY_PCI_CALLER_OFFSET, \
+						COMPHY_PCI_CALLER_LEN)
+
+#define COMPHY_MASK(offset, len)	(((1 << (len)) - 1) << (offset))
+
+/* Macro which extracts mode from lane description */
+#define COMPHY_GET_MODE(x)		(((x) & COMPHY_MODE_MASK) >> \
+						COMPHY_MODE_OFFSET)
+/* Macro which extracts unit index from lane description */
+#define COMPHY_GET_ID(x)		(((x) & COMPHY_UNIT_ID_MASK) >> \
+						COMPHY_UNIT_ID_OFFSET)
+/* Macro which extracts speed from lane description */
+#define COMPHY_GET_SPEED(x)		(((x) & COMPHY_SPEED_MASK) >> \
+						COMPHY_SPEED_OFFSET)
+/* Macro which extracts clock source indication from lane description */
+#define COMPHY_GET_CLK_SRC(x)		(((x) & COMPHY_CLK_SRC_MASK) >> \
+						COMPHY_CLK_SRC_OFFSET)
+/* Macro which extracts pcie width indication from lane description */
+#define COMPHY_GET_PCIE_WIDTH(x)	(((x) & COMPHY_PCI_WIDTH_MASK) >> \
+						COMPHY_PCI_WIDTH_OFFSET)
+
+/* Macro which extracts the caller for pcie power on from lane description */
+#define COMPHY_GET_CALLER(x)		(((x) & COMPHY_PCI_CALLER_MASK) >> \
+						COMPHY_PCI_CALLER_OFFSET)
+
+/* Macro which extracts the polarity invert from lane description */
+#define COMPHY_GET_POLARITY_INVERT(x)	(((x) & COMPHY_INVERT_MASK) >> \
+						COMPHY_INVERT_OFFSET)
+
+
+#define COMPHY_SATA_MODE	0x1
+#define COMPHY_SGMII_MODE	0x2	/* SGMII 1G */
+#define COMPHY_HS_SGMII_MODE	0x3	/* SGMII 2.5G */
+#define COMPHY_USB3H_MODE	0x4
+#define COMPHY_USB3D_MODE	0x5
+#define COMPHY_PCIE_MODE	0x6
+#define COMPHY_RXAUI_MODE	0x7
+#define COMPHY_XFI_MODE		0x8
+#define COMPHY_SFI_MODE		0x9
+#define COMPHY_USB3_MODE	0xa
+#define COMPHY_AP_MODE		0xb
+
+#define	COMPHY_UNUSED		0xFFFFFFFF
+
+/* Polarity invert macro */
+#define COMPHY_POLARITY_NO_INVERT	0
+#define COMPHY_POLARITY_TXD_INVERT	1
+#define COMPHY_POLARITY_RXD_INVERT	2
+#define COMPHY_POLARITY_ALL_INVERT	(COMPHY_POLARITY_TXD_INVERT | \
+					 COMPHY_POLARITY_RXD_INVERT)
+
+enum reg_width_type {
+	REG_16BIT = 0,
+	REG_32BIT,
+};
+
+enum {
+	COMPHY_LANE0 = 0,
+	COMPHY_LANE1,
+	COMPHY_LANE2,
+	COMPHY_LANE3,
+	COMPHY_LANE4,
+	COMPHY_LANE5,
+	COMPHY_LANE_MAX,
+};
+
+static inline uint32_t polling_with_timeout(uintptr_t addr, uint32_t val,
+					    uint32_t mask,
+					    uint32_t usec_timeout,
+					    enum reg_width_type type)
+{
+	uint32_t data;
+
+	do {
+		udelay(1);
+		if (type == REG_16BIT)
+			data = mmio_read_16(addr) & mask;
+		else
+			data = mmio_read_32(addr) & mask;
+	} while (data != val  && --usec_timeout > 0);
+
+	if (usec_timeout == 0)
+		return data;
+
+	return 0;
+}
+
+static inline void reg_set(uintptr_t addr, uint32_t data, uint32_t mask)
+{
+	debug("<atf>: WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ",
+	      addr, data, mask);
+	debug("old value = 0x%x ==> ", mmio_read_32(addr));
+	mmio_clrsetbits_32(addr, mask, data);
+
+	debug("new val 0x%x\n", mmio_read_32(addr));
+}
+
+static inline void __unused reg_set16(uintptr_t addr, uint16_t data,
+				      uint16_t mask)
+{
+
+	debug("<atf>: WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ",
+	      addr, data, mask);
+	debug("old value = 0x%x ==> ", mmio_read_16(addr));
+	mmio_clrsetbits_16(addr, mask, data);
+
+	debug("new val 0x%x\n", mmio_read_16(addr));
+}
+
+#endif /* PHY_COMPHY_COMMON_H */
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.c b/drivers/marvell/comphy/phy-comphy-cp110.c
new file mode 100644
index 0000000..384dd39
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-cp110.c
@@ -0,0 +1,2486 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Marvell CP110 SoC COMPHY unit driver */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#include <mvebu_def.h>
+#include "mvebu.h"
+#include "comphy-cp110.h"
+#include "phy-comphy-cp110.h"
+#include "phy-comphy-common.h"
+
+#if __has_include("phy-porting-layer.h")
+#include "phy-porting-layer.h"
+#else
+#include "phy-default-porting-layer.h"
+#endif
+
+/* COMPHY speed macro */
+#define COMPHY_SPEED_1_25G		0 /* SGMII 1G */
+#define COMPHY_SPEED_2_5G		1
+#define COMPHY_SPEED_3_125G		2 /* SGMII 2.5G */
+#define COMPHY_SPEED_5G			3
+#define COMPHY_SPEED_5_15625G		4 /* XFI 5G */
+#define COMPHY_SPEED_6G			5
+#define COMPHY_SPEED_10_3125G		6 /* XFI 10G */
+#define COMPHY_SPEED_MAX		0x3F
+/* The  default speed for IO with fixed known speed */
+#define COMPHY_SPEED_DEFAULT		COMPHY_SPEED_MAX
+
+/* Commands for comphy driver */
+#define COMPHY_COMMAND_DIGITAL_PWR_OFF		0x00000001
+#define COMPHY_COMMAND_DIGITAL_PWR_ON		0x00000002
+
+#define COMPHY_PIPE_FROM_COMPHY_ADDR(x)	((x & ~0xffffff) + 0x120000)
+
+/* System controller registers */
+#define PCIE_MAC_RESET_MASK_PORT0	BIT(13)
+#define PCIE_MAC_RESET_MASK_PORT1	BIT(11)
+#define PCIE_MAC_RESET_MASK_PORT2	BIT(12)
+#define SYS_CTRL_UINIT_SOFT_RESET_REG	0x268
+#define SYS_CTRL_FROM_COMPHY_ADDR(x)	((x & ~0xffffff) + 0x440000)
+
+/* DFX register spaces */
+#define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET	(0)
+#define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK	(0x1 << \
+					SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET)
+#define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET	(1)
+#define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK	(0x1 << \
+					SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET)
+#define SAR_STATUS_0_REG			200
+#define DFX_FROM_COMPHY_ADDR(x)			((x & ~0xffffff) + DFX_BASE)
+
+/* The same Units Soft Reset Config register are accessed in all PCIe ports
+ * initialization, so a spin lock is defined in case when more than 1 CPUs
+ * resets PCIe MAC and need to access the register in the same time. The spin
+ * lock is shared by all CP110 units.
+ */
+spinlock_t cp110_mac_reset_lock;
+
+/* These values come from the PCI Express Spec */
+enum pcie_link_width {
+	PCIE_LNK_WIDTH_RESRV	= 0x00,
+	PCIE_LNK_X1		= 0x01,
+	PCIE_LNK_X2		= 0x02,
+	PCIE_LNK_X4		= 0x04,
+	PCIE_LNK_X8		= 0x08,
+	PCIE_LNK_X12		= 0x0C,
+	PCIE_LNK_X16		= 0x10,
+	PCIE_LNK_X32		= 0x20,
+	PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
+};
+
+_Bool rx_trainng_done[AP_NUM][CP_NUM][MAX_LANE_NR] = {0};
+
+static void mvebu_cp110_get_ap_and_cp_nr(uint8_t *ap_nr, uint8_t *cp_nr,
+					 uint64_t comphy_base)
+{
+#if (AP_NUM == 1)
+	*ap_nr = 0;
+#else
+	*ap_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(0)) /
+			 AP_IO_OFFSET);
+#endif
+
+	*cp_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(*ap_nr)) /
+		 MVEBU_CP_OFFSET);
+
+	debug("cp_base 0x%llx, ap_io_base 0x%lx, cp_offset 0x%lx\n",
+	       comphy_base, (unsigned long)MVEBU_AP_IO_BASE(*ap_nr),
+	       (unsigned long)MVEBU_CP_OFFSET);
+}
+
+/* Clear PIPE selector - avoid collision with previous configuration */
+static void mvebu_cp110_comphy_clr_pipe_selector(uint64_t comphy_base,
+						 uint8_t comphy_index)
+{
+	uint32_t reg, mask, field;
+	uint32_t comphy_offset =
+			COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+
+	mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
+	reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET);
+	field = reg & mask;
+
+	if (field) {
+		reg &= ~mask;
+		mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET,
+			     reg);
+	}
+}
+
+/* Clear PHY selector - avoid collision with previous configuration */
+static void mvebu_cp110_comphy_clr_phy_selector(uint64_t comphy_base,
+						uint8_t comphy_index)
+{
+	uint32_t reg, mask, field;
+	uint32_t comphy_offset =
+			COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+
+	mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
+	reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET);
+	field = reg & mask;
+
+	/* Clear comphy selector - if it was already configured.
+	 * (might be that this comphy was configured as PCIe/USB,
+	 * in such case, no need to clear comphy selector because PCIe/USB
+	 * are controlled by hpipe selector).
+	 */
+	if (field) {
+		reg &= ~mask;
+		mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET,
+			      reg);
+	}
+}
+
+/* PHY selector configures SATA and Network modes */
+static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	uint32_t reg, mask;
+	uint32_t comphy_offset =
+			COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+	int mode;
+
+	/* If phy selector is used the pipe selector should be marked as
+	 * unconnected.
+	 */
+	mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index);
+
+	/* Comphy mode (compound of the IO mode and id). Here, only the IO mode
+	 * is required to distinguish between SATA and network modes.
+	 */
+	mode = COMPHY_GET_MODE(comphy_mode);
+
+	mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset;
+	reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET);
+	reg &= ~mask;
+
+	/* SATA port 0/1 require the same configuration */
+	if (mode == COMPHY_SATA_MODE) {
+		/* SATA selector values is always 4 */
+		reg |= COMMON_SELECTOR_COMPHYN_SATA << comphy_offset;
+	} else {
+		switch (comphy_index) {
+		case(0):
+		case(1):
+		case(2):
+			/* For comphy 0,1, and 2:
+			 * Network selector value is always 1.
+			 */
+			reg |= COMMON_SELECTOR_COMPHY0_1_2_NETWORK <<
+				comphy_offset;
+			break;
+		case(3):
+			/* For comphy 3:
+			 * 0x1 = RXAUI_Lane1
+			 * 0x2 = SGMII/HS-SGMII Port1
+			 */
+			if (mode == COMPHY_RXAUI_MODE)
+				reg |= COMMON_SELECTOR_COMPHY3_RXAUI <<
+					comphy_offset;
+			else
+				reg |= COMMON_SELECTOR_COMPHY3_SGMII <<
+					comphy_offset;
+			break;
+		case(4):
+			 /* For comphy 4:
+			  * 0x1 = SGMII/HS-SGMII Port1, XFI1/SFI1
+			  * 0x2 = SGMII/HS-SGMII Port0: XFI0/SFI0, RXAUI_Lane0
+			  *
+			  * We want to check if SGMII1/HS_SGMII1 is the
+			  * requested mode in order to determine which value
+			  * should be set (all other modes use the same value)
+			  * so we need to strip the mode, and check the ID
+			  * because we might handle SGMII0/HS_SGMII0 too.
+			  */
+			  /* TODO: need to distinguish between CP110 and CP115
+			   * as SFI1/XFI1 available only for CP115.
+			   */
+			if ((mode == COMPHY_SGMII_MODE ||
+			    mode == COMPHY_HS_SGMII_MODE ||
+			    mode == COMPHY_SFI_MODE || mode == COMPHY_XFI_MODE)
+			    && COMPHY_GET_ID(comphy_mode) == 1)
+				reg |= COMMON_SELECTOR_COMPHY4_PORT1 <<
+					comphy_offset;
+			else
+				reg |= COMMON_SELECTOR_COMPHY4_ALL_OTHERS <<
+					comphy_offset;
+			break;
+		case(5):
+			/* For comphy 5:
+			 * 0x1 = SGMII/HS-SGMII Port2
+			 * 0x2 = RXAUI Lane1
+			 */
+			if (mode == COMPHY_RXAUI_MODE)
+				reg |= COMMON_SELECTOR_COMPHY5_RXAUI <<
+					comphy_offset;
+			else
+				reg |= COMMON_SELECTOR_COMPHY5_SGMII <<
+					comphy_offset;
+			break;
+		}
+	}
+
+	mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET, reg);
+}
+
+/* PIPE selector configures for PCIe, USB 3.0 Host, and USB 3.0 Device mode */
+static void mvebu_cp110_comphy_set_pipe_selector(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	uint32_t reg;
+	uint32_t shift = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index;
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	uint32_t mask = COMMON_SELECTOR_COMPHY_MASK << shift;
+	uint32_t pipe_sel = 0x0;
+
+	/* If pipe selector is used the phy selector should be marked as
+	 * unconnected.
+	 */
+	mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index);
+
+	reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET);
+	reg &= ~mask;
+
+	switch (mode) {
+	case (COMPHY_PCIE_MODE):
+		/* For lanes support PCIE, selector value are all same */
+		pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_PCIE;
+		break;
+
+	case (COMPHY_USB3H_MODE):
+		/* Only lane 1-4 support USB host, selector value is same */
+		if (comphy_index == COMPHY_LANE0 ||
+		    comphy_index == COMPHY_LANE5)
+			ERROR("COMPHY[%d] mode[%d] is invalid\n",
+			      comphy_index, mode);
+		else
+			pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBH;
+		break;
+
+	case (COMPHY_USB3D_MODE):
+		/* Lane 1 and 4 support USB device, selector value is same */
+		if (comphy_index == COMPHY_LANE1 ||
+		    comphy_index == COMPHY_LANE4)
+			pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBD;
+		else
+			ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index,
+			      mode);
+		break;
+
+	default:
+		ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
+		break;
+	}
+
+	mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET, reg |
+		      (pipe_sel << shift));
+}
+
+int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base, uint8_t comphy_index)
+{
+	uintptr_t sd_ip_addr, addr;
+	uint32_t mask, data;
+	int ret = 0;
+
+	debug_enter();
+
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+
+	addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+	data = SD_EXTERNAL_STATUS0_PLL_TX_MASK &
+		SD_EXTERNAL_STATUS0_PLL_RX_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask,
+				    PLL_LOCK_TIMEOUT, REG_32BIT);
+	if (data != 0) {
+		if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)
+			ERROR("RX PLL is not locked\n");
+		if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)
+			ERROR("TX PLL is not locked\n");
+
+		ret = -ETIMEDOUT;
+	}
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	uintptr_t hpipe_addr, sd_ip_addr, comphy_addr;
+	uint32_t mask, data;
+	uint8_t ap_nr, cp_nr;
+	int ret = 0;
+
+	debug_enter();
+
+	mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
+
+	const struct sata_params *sata_static_values =
+			&sata_static_values_tab[ap_nr][cp_nr][comphy_index];
+
+
+	/* configure phy selector for SATA */
+	mvebu_cp110_comphy_set_phy_selector(comphy_base,
+					    comphy_index, comphy_mode);
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+	comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+	debug(" add hpipe 0x%lx, sd 0x%lx, comphy 0x%lx\n",
+					   hpipe_addr, sd_ip_addr, comphy_addr);
+	debug("stage: RFU configurations - hard reset comphy\n");
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+	mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* Set select data  width 40Bit - SATA mode only */
+	reg_set(comphy_addr + COMMON_PHY_CFG6_REG,
+		0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET,
+		COMMON_PHY_CFG6_IF_40_SEL_MASK);
+
+	/* release from hard reset in SD external */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* Wait 1ms - until band gap and ref clock ready */
+	mdelay(1);
+
+	debug("stage: Comphy configuration\n");
+	/* Start comphy Configuration */
+	/* Set reference clock to comes from group 1 - choose 25Mhz */
+	reg_set(hpipe_addr + HPIPE_MISC_REG,
+		0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+		HPIPE_MISC_REFCLK_SEL_MASK);
+	/* Reference frequency select set 1 (for SATA = 25Mhz) */
+	mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+	data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	/* PHY mode select (set SATA = 0x0 */
+	mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+	data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+	/* Set max PHY generation setting - 6Gbps */
+	reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
+		0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
+		HPIPE_INTERFACE_GEN_MAX_MASK);
+	/* Set select data  width 40Bit (SEL_BITS[2:0]) */
+	reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
+		0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
+
+	debug("stage: Analog parameters from ETP(HW)\n");
+	/* G1 settings */
+	mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+	data = sata_static_values->g1_rx_selmupi <<
+			HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+	mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
+	data |= sata_static_values->g1_rx_selmupf <<
+			HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
+	mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
+	data |= sata_static_values->g1_rx_selmufi <<
+			HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
+	mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
+	data |= sata_static_values->g1_rx_selmuff <<
+			HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
+	mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
+	data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+
+	mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+	data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+	mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+	data |= 0x2 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+	mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+	data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+	mask |= HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK;
+	data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET;
+	mask |= HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK;
+	data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+	/* G2 settings */
+	mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
+	data = sata_static_values->g2_rx_selmupi <<
+			HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
+	mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK;
+	data |= sata_static_values->g2_rx_selmupf <<
+			HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET;
+	mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
+	data |= sata_static_values->g2_rx_selmufi <<
+			HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
+	mask |= HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK;
+	data |= sata_static_values->g2_rx_selmuff <<
+			HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET;
+	mask |= HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK;
+	data |= 0x1 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
+
+	/* G3 settings */
+	mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
+	data = sata_static_values->g3_rx_selmupi <<
+			HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
+	mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
+	data |= sata_static_values->g3_rx_selmupf <<
+			HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
+	mask |= HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK;
+	data |= sata_static_values->g3_rx_selmufi <<
+			HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET;
+	mask |= HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK;
+	data |= sata_static_values->g3_rx_selmuff <<
+			HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET;
+	mask |= HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK;
+	data |= 0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET;
+	mask |= HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK;
+	data |= 0x2 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET;
+	mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
+	data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask);
+
+	/* DTL Control */
+	mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK;
+	data = 0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET;
+	mask |= HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK;
+	data |= 0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET;
+	mask |= HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+	data |= 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+	mask |= HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK;
+	data |= 0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET;
+	mask |= HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK;
+	data |= 0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET;
+	mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_MASK;
+	data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET;
+	mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK;
+	data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+	/* Trigger sampler enable pulse */
+	mask = HPIPE_SMAPLER_MASK;
+	data = 0x1 << HPIPE_SMAPLER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+	mask = HPIPE_SMAPLER_MASK;
+	data = 0x0 << HPIPE_SMAPLER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+
+	/* VDD Calibration Control 3 */
+	mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+	data = 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+	/* DFE Resolution Control */
+	mask = HPIPE_DFE_RES_FORCE_MASK;
+	data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+	/* DFE F3-F5 Coefficient Control */
+	mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+	data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+	mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+	data = 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+	/* G3 Setting 3 */
+	mask = HPIPE_G3_FFE_CAP_SEL_MASK;
+	data = sata_static_values->g3_ffe_cap_sel <<
+			HPIPE_G3_FFE_CAP_SEL_OFFSET;
+	mask |= HPIPE_G3_FFE_RES_SEL_MASK;
+	data |= sata_static_values->g3_ffe_res_sel <<
+			HPIPE_G3_FFE_RES_SEL_OFFSET;
+	mask |= HPIPE_G3_FFE_SETTING_FORCE_MASK;
+	data |= 0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET;
+	mask |= HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
+	data |= 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
+	mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
+	data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
+
+	/* G3 Setting 4 */
+	mask = HPIPE_G3_DFE_RES_MASK;
+	data = sata_static_values->g3_dfe_res << HPIPE_G3_DFE_RES_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
+
+	/* Offset Phase Control */
+	mask = HPIPE_OS_PH_OFFSET_MASK;
+	data = sata_static_values->align90 << HPIPE_OS_PH_OFFSET_OFFSET;
+	mask |= HPIPE_OS_PH_OFFSET_FORCE_MASK;
+	data |= 0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET;
+	mask |= HPIPE_OS_PH_VALID_MASK;
+	data |= 0x0 << HPIPE_OS_PH_VALID_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+	mask = HPIPE_OS_PH_VALID_MASK;
+	data = 0x1 << HPIPE_OS_PH_VALID_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+	mask = HPIPE_OS_PH_VALID_MASK;
+	data = 0x0 << HPIPE_OS_PH_VALID_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+
+	/* Set G1 TX amplitude and TX post emphasis value */
+	mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
+	data = sata_static_values->g1_amp << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
+	mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
+	data |= sata_static_values->g1_tx_amp_adj <<
+			HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
+	mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+	data |= sata_static_values->g1_emph <<
+			HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+	mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
+	data |= sata_static_values->g1_emph_en <<
+			HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
+
+	/* Set G1 emph */
+	mask = HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
+	data = sata_static_values->g1_tx_emph_en <<
+			HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
+	mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
+	data |= sata_static_values->g1_tx_emph <<
+			HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
+
+	/* Set G2 TX amplitude and TX post emphasis value */
+	mask = HPIPE_G2_SET_0_G2_TX_AMP_MASK;
+	data = sata_static_values->g2_amp << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET;
+	mask |= HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK;
+	data |= sata_static_values->g2_tx_amp_adj <<
+			HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET;
+	mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_MASK;
+	data |= sata_static_values->g2_emph <<
+			HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET;
+	mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK;
+	data |= sata_static_values->g2_emph_en <<
+			HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G2_SET_0_REG, data, mask);
+
+	/* Set G2 emph */
+	mask = HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK;
+	data = sata_static_values->g2_tx_emph_en <<
+			HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET;
+	mask |= HPIPE_G2_SET_2_G2_TX_EMPH0_MASK;
+	data |= sata_static_values->g2_tx_emph <<
+			HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
+
+	/* Set G3 TX amplitude and TX post emphasis value */
+	mask = HPIPE_G3_SET_0_G3_TX_AMP_MASK;
+	data = sata_static_values->g3_amp << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET;
+	mask |= HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK;
+	data |= sata_static_values->g3_tx_amp_adj <<
+			HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET;
+	mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_MASK;
+	data |= sata_static_values->g3_emph <<
+			HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET;
+	mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK;
+	data |= sata_static_values->g3_emph_en <<
+			HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET;
+	mask |= HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK;
+	data |= 0x4 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET;
+	mask |= HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK;
+	data |= 0x0 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SET_0_REG, data, mask);
+
+	/* Set G3 emph */
+	mask = HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK;
+	data = sata_static_values->g3_tx_emph_en <<
+			HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET;
+	mask |= HPIPE_G3_SET_2_G3_TX_EMPH0_MASK;
+	data |= sata_static_values->g3_tx_emph <<
+			HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SET_2_REG, data, mask);
+
+	/* SERDES External Configuration 2 register */
+	mask = SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
+
+	/* DFE reset sequence */
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+		0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET,
+		HPIPE_PWR_CTR_RST_DFE_MASK);
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+		0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET,
+		HPIPE_PWR_CTR_RST_DFE_MASK);
+	/* SW reset for interrupt logic */
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+		0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET,
+		HPIPE_PWR_CTR_SFT_RST_MASK);
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
+		0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET,
+		HPIPE_PWR_CTR_SFT_RST_MASK);
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_cp110_comphy_sgmii_power_on(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
+	uint32_t mask, data, sgmii_speed = COMPHY_GET_SPEED(comphy_mode);
+	int ret = 0;
+
+	debug_enter();
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+	comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+	/* configure phy selector for SGMII */
+	mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
+					    comphy_mode);
+
+	/* Confiugre the lane */
+	debug("stage: RFU configurations - hard reset comphy\n");
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+	mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+
+	if (sgmii_speed == COMPHY_SPEED_1_25G) {
+		/* SGMII 1G, SerDes speed 1.25G */
+		data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+		data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+	} else if (sgmii_speed == COMPHY_SPEED_3_125G) {
+		/* HS SGMII (2.5G), SerDes speed 3.125G */
+		data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+		data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+	} else {
+		/* Other rates are not supported */
+		ERROR("unsupported SGMII speed on comphy%d\n", comphy_index);
+		return -EINVAL;
+	}
+
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+	data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+	data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+	data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+	/* Set hard reset */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* Release hard reset */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* Wait 1ms - until band gap and ref clock ready */
+	mdelay(1);
+
+	/* Make sure that 40 data bits is disabled
+	 * This bit is not cleared by reset
+	 */
+	mask = COMMON_PHY_CFG6_IF_40_SEL_MASK;
+	data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask);
+
+	/* Start comphy Configuration */
+	debug("stage: Comphy configuration\n");
+	/* set reference clock */
+	mask = HPIPE_MISC_REFCLK_SEL_MASK;
+	data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
+	/* Power and PLL Control */
+	mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+	data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+	data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+	/* Loopback register */
+	mask = HPIPE_LOOPBACK_SEL_MASK;
+	data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
+	/* rx control 1 */
+	mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+	data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+	mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+	data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
+	/* DTL Control */
+	mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+	data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+	/* Set analog parameters from ETP(HW) - for now use the default data */
+	debug("stage: Analog parameters from ETP(HW)\n");
+
+	reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
+		0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET,
+		HPIPE_G1_SET_0_G1_TX_EMPH1_MASK);
+
+	debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
+	/* SERDES External Configuration */
+	mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+	ret = mvebu_cp110_comphy_is_pll_locked(comphy_base, comphy_index);
+	if (ret)
+		return ret;
+
+	/* RX init */
+	mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* check that RX init done */
+	addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+	data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
+	if (data != 0) {
+		ERROR("RX init failed\n");
+		ret = -ETIMEDOUT;
+	}
+
+	debug("stage: RF Reset\n");
+	/* RF Reset */
+	mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
+					   uint8_t comphy_index,
+					   uint32_t comphy_mode)
+{
+	uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
+	uint32_t mask, data, speed = COMPHY_GET_SPEED(comphy_mode);
+	int ret = 0;
+	uint8_t ap_nr, cp_nr;
+
+	debug_enter();
+
+	mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
+
+	if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) {
+		debug("Skip %s for comphy[%d][%d][%d], due to rx training\n",
+		       __func__, ap_nr, cp_nr, comphy_index);
+		return 0;
+	}
+
+	const struct xfi_params *xfi_static_values =
+			     &xfi_static_values_tab[ap_nr][cp_nr][comphy_index];
+
+	debug("%s: the ap_nr = %d, cp_nr = %d, comphy_index %d\n",
+	      __func__, ap_nr, cp_nr, comphy_index);
+
+	debug("g1_ffe_cap_sel= 0x%x, g1_ffe_res_sel= 0x%x, g1_dfe_res= 0x%x\n",
+	      xfi_static_values->g1_ffe_cap_sel,
+	      xfi_static_values->g1_ffe_res_sel,
+	      xfi_static_values->g1_dfe_res);
+
+	if (!xfi_static_values->valid) {
+		ERROR("[ap%d][cp[%d][comphy:%d]: Has no valid static params\n",
+		      ap_nr, cp_nr, comphy_index);
+		ERROR("[ap%d][cp[%d][comphy:%d]: porting layer needs update\n",
+		      ap_nr, cp_nr, comphy_index);
+		return -EINVAL;
+	}
+
+	if ((speed != COMPHY_SPEED_5_15625G) &&
+	     (speed != COMPHY_SPEED_10_3125G) &&
+	     (speed != COMPHY_SPEED_DEFAULT)) {
+		ERROR("comphy:%d: unsupported sfi/xfi speed\n", comphy_index);
+		return -EINVAL;
+	}
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+	comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+	/* configure phy selector for XFI/SFI */
+	mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
+					    comphy_mode);
+
+	debug("stage: RFU configurations - hard reset comphy\n");
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* Make sure that 40 data bits is disabled
+	 * This bit is not cleared by reset
+	 */
+	mask = COMMON_PHY_CFG6_IF_40_SEL_MASK;
+	data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask);
+
+	/* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+	mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+	data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+	data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+	data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+	data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+	data |= 0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+	/* release from hard reset */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* Wait 1ms - until band gap and ref clock ready */
+	mdelay(1);
+
+	/* Start comphy Configuration */
+	debug("stage: Comphy configuration\n");
+	/* set reference clock */
+	mask = HPIPE_MISC_ICP_FORCE_MASK;
+	data = (speed == COMPHY_SPEED_5_15625G) ?
+		(0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) :
+		(0x1 << HPIPE_MISC_ICP_FORCE_OFFSET);
+	mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+	data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
+	/* Power and PLL Control */
+	mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+	data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+	data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+	/* Loopback register */
+	mask = HPIPE_LOOPBACK_SEL_MASK;
+	data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
+	/* rx control 1 */
+	mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+	data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+	mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+	data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
+	/* DTL Control */
+	mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+	data = 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+	/* Transmitter/Receiver Speed Divider Force */
+	if (speed == COMPHY_SPEED_5_15625G) {
+		mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK;
+		data = 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET;
+		mask |= HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK;
+		data |= 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET;
+		mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK;
+		data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET;
+		mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK;
+		data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET;
+	} else {
+		mask = HPIPE_TXDIGCK_DIV_FORCE_MASK;
+		data = 0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET;
+	}
+	reg_set(hpipe_addr + HPIPE_SPD_DIV_FORCE_REG, data, mask);
+
+	/* Set analog parameters from ETP(HW) */
+	debug("stage: Analog parameters from ETP(HW)\n");
+	/* SERDES External Configuration 2 */
+	mask = SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
+	/* 0x7-DFE Resolution control */
+	mask = HPIPE_DFE_RES_FORCE_MASK;
+	data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+	/* 0xd-G1_Setting_0 */
+	if (speed == COMPHY_SPEED_5_15625G) {
+		mask = HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+		data = 0x6 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+	} else {
+		mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
+		data = xfi_static_values->g1_amp <<
+				HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
+		mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+		data |= xfi_static_values->g1_emph <<
+				HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+
+		mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
+		data |= xfi_static_values->g1_emph_en <<
+				HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
+		mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
+		data |= xfi_static_values->g1_tx_amp_adj <<
+				HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
+	}
+	reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
+	/* Genration 1 setting 2 (G1_Setting_2) */
+	mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
+	data = xfi_static_values->g1_tx_emph <<
+				HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
+	mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
+	data |= xfi_static_values->g1_tx_emph_en <<
+				HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
+	/* Transmitter Slew Rate Control register (tx_reg1) */
+	mask = HPIPE_TX_REG1_TX_EMPH_RES_MASK;
+	data = 0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET;
+	mask |= HPIPE_TX_REG1_SLC_EN_MASK;
+	data |= 0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_REG1_REG, data, mask);
+	/* Impedance Calibration Control register (cal_reg1) */
+	mask = HPIPE_CAL_REG_1_EXT_TXIMP_MASK;
+	data = 0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
+	mask |= HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK;
+	data |= 0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_CAL_REG1_REG, data, mask);
+	/* Generation 1 Setting 5 (g1_setting_5) */
+	mask = HPIPE_G1_SETTING_5_G1_ICP_MASK;
+	data = 0 << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTING_5_REG, data, mask);
+
+	/* 0xE-G1_Setting_1 */
+	mask = HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
+	data = 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
+	if (speed == COMPHY_SPEED_5_15625G) {
+		mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+		data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+		mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
+		data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
+	} else {
+		mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+		data |= xfi_static_values->g1_rx_selmupi <<
+				HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+		mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
+		data |= xfi_static_values->g1_rx_selmupf <<
+				HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
+		mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
+		data |= xfi_static_values->g1_rx_selmufi <<
+				HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
+		mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
+		data |= xfi_static_values->g1_rx_selmuff <<
+				HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
+		mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
+		data |= 0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
+	}
+	reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+
+	/* 0xA-DFE_Reg3 */
+	mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+	data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+	mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+	data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+	/* 0x111-G1_Setting_4 */
+	mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
+	data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
+	/* Genration 1 setting 3 (G1_Setting_3) */
+	mask = HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK;
+	data = 0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET;
+	if (speed == COMPHY_SPEED_5_15625G) {
+		/* Force FFE (Feed Forward Equalization) to 5G */
+		mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+		data |= 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+		mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+		data |= 0x4 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+		mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+		data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+		reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+	} else {
+		mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+		data |= xfi_static_values->g1_ffe_cap_sel <<
+			HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+		mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+		data |= xfi_static_values->g1_ffe_res_sel <<
+			HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+		mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+		data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+		reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+		/* Use the value from CAL_OS_PH_EXT */
+		mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
+		data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
+		reg_set(hpipe_addr +
+			HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
+			data, mask);
+
+		/* Update align90 */
+		mask = HPIPE_CAL_OS_PH_EXT_MASK;
+		data = xfi_static_values->align90 << HPIPE_CAL_OS_PH_EXT_OFFSET;
+		reg_set(hpipe_addr +
+			HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
+			data, mask);
+
+		/* Force DFE resolution (use gen table value) */
+		mask = HPIPE_DFE_RES_FORCE_MASK;
+		data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
+		reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+		/* 0x111-G1 DFE_Setting_4 */
+		mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
+		data = xfi_static_values->g1_dfe_res <<
+			HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
+		reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
+	}
+
+	/* Connfigure RX training timer */
+	mask = HPIPE_RX_TRAIN_TIMER_MASK;
+	data = 0x13 << HPIPE_RX_TRAIN_TIMER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
+
+	/* Enable TX train peak to peak hold */
+	mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
+	data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
+
+	/* Configure TX preset index */
+	mask = HPIPE_TX_PRESET_INDEX_MASK;
+	data = 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_PRESET_INDEX_REG, data, mask);
+
+	/* Disable pattern lock lost timeout */
+	mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
+	data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
+
+	/* Configure TX training pattern and TX training 16bit auto */
+	mask = HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK;
+	data = 0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET;
+	mask |= HPIPE_TX_TRAIN_PAT_SEL_MASK;
+	data |= 0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
+
+	/* Configure Training patten number */
+	mask = HPIPE_TRAIN_PAT_NUM_MASK;
+	data = 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET;
+	reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_0_REG, data, mask);
+
+	/* Configure differencial manchester encoter to ethernet mode */
+	mask = HPIPE_DME_ETHERNET_MODE_MASK;
+	data = 0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DME_REG, data, mask);
+
+	/* Configure VDD Continuous Calibration */
+	mask = HPIPE_CAL_VDD_CONT_MODE_MASK;
+	data = 0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_VDD_CAL_0_REG, data, mask);
+
+	/* Trigger sampler enable pulse (by toggleing the bit) */
+	mask = HPIPE_RX_SAMPLER_OS_GAIN_MASK;
+	data = 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET;
+	mask |= HPIPE_SMAPLER_MASK;
+	data |= 0x1 << HPIPE_SMAPLER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+	mask = HPIPE_SMAPLER_MASK;
+	data = 0x0 << HPIPE_SMAPLER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+
+	/* Set External RX Regulator Control */
+	mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+	data = 0x1A << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+	debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
+	/* SERDES External Configuration */
+	mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+	/* check PLL rx & tx ready */
+	addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+	data = SD_EXTERNAL_STATUS0_PLL_RX_MASK |
+	       SD_EXTERNAL_STATUS0_PLL_TX_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask,
+				    PLL_LOCK_TIMEOUT, REG_32BIT);
+	if (data != 0) {
+		if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK)
+			ERROR("RX PLL is not locked\n");
+		if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)
+			ERROR("TX PLL is not locked\n");
+
+		ret = -ETIMEDOUT;
+	}
+
+	/* RX init */
+	mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* check that RX init done */
+	addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+	data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
+	if (data != 0) {
+		ERROR("RX init failed\n");
+		ret = -ETIMEDOUT;
+	}
+
+	debug("stage: RF Reset\n");
+	/* RF Reset */
+	mask =  SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_cp110_comphy_pcie_power_on(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	int ret = 0;
+	uint32_t reg, mask, data, pcie_width;
+	uint32_t clk_dir;
+	uintptr_t hpipe_addr, comphy_addr, addr;
+	_Bool clk_src = COMPHY_GET_CLK_SRC(comphy_mode);
+	_Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode);
+
+	/* In Armada 8K DB boards, PCIe initialization can be executed
+	 * only once (PCIe reset performed during chip power on and
+	 * it cannot be executed via GPIO later).
+	 * This means that power on can be executed only once, so let's
+	 * mark if the caller is bootloader or Linux.
+	 * If bootloader -> run power on.
+	 * If Linux -> exit.
+	 *
+	 * TODO: In MacciatoBIN, PCIe reset is connected via GPIO,
+	 * so after GPIO reset is added to Linux Kernel, it can be
+	 * powered-on by Linux.
+	 */
+	if (!called_from_uboot)
+		return ret;
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+	pcie_width = COMPHY_GET_PCIE_WIDTH(comphy_mode);
+
+	debug_enter();
+
+	spin_lock(&cp110_mac_reset_lock);
+
+	reg = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+						SYS_CTRL_UINIT_SOFT_RESET_REG);
+	switch (comphy_index) {
+	case COMPHY_LANE0:
+		reg |= PCIE_MAC_RESET_MASK_PORT0;
+		break;
+	case COMPHY_LANE4:
+		reg |= PCIE_MAC_RESET_MASK_PORT1;
+		break;
+	case COMPHY_LANE5:
+		reg |= PCIE_MAC_RESET_MASK_PORT2;
+		break;
+	}
+
+	mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+					    SYS_CTRL_UINIT_SOFT_RESET_REG, reg);
+	spin_unlock(&cp110_mac_reset_lock);
+
+	/* Configure PIPE selector for PCIE */
+	mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
+					     comphy_mode);
+
+	/*
+	 * Read SAR (Sample-At-Reset) configuration for the PCIe clock
+	 * direction.
+	 *
+	 * SerDes Lane 4/5 got the PCIe ref-clock #1,
+	 * and SerDes Lane 0 got PCIe ref-clock #0
+	 */
+	reg = mmio_read_32(DFX_FROM_COMPHY_ADDR(comphy_base) +
+			   SAR_STATUS_0_REG);
+	if (comphy_index == COMPHY_LANE4 || comphy_index == COMPHY_LANE5)
+		clk_dir = (reg & SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK) >>
+					  SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET;
+	else
+		clk_dir = (reg & SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK) >>
+					  SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET;
+
+	debug("On lane %d\n", comphy_index);
+	debug("PCIe clock direction = %x\n", clk_dir);
+	debug("PCIe Width = %d\n", pcie_width);
+
+	/* enable PCIe X4 and X2 */
+	if (comphy_index == COMPHY_LANE0) {
+		if (pcie_width == PCIE_LNK_X4) {
+			data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET;
+			mask = COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK;
+			reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+				data, mask);
+		} else if (pcie_width == PCIE_LNK_X2) {
+			data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET;
+			mask = COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK;
+			reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask);
+		}
+	}
+
+	/* If PCIe clock is output and clock source from SerDes lane 5,
+	 * need to configure the clock-source MUX.
+	 * By default, the clock source is from lane 4
+	 */
+	if (clk_dir && clk_src && (comphy_index == COMPHY_LANE5)) {
+		data = DFX_DEV_GEN_PCIE_CLK_SRC_MUX <<
+						DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET;
+		mask = DFX_DEV_GEN_PCIE_CLK_SRC_MASK;
+		reg_set(DFX_FROM_COMPHY_ADDR(comphy_base) +
+			DFX_DEV_GEN_CTRL12_REG, data, mask);
+	}
+
+	debug("stage: RFU configurations - hard reset comphy\n");
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+	mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+	mask |= COMMON_PHY_PHY_MODE_MASK;
+	data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* release from hard reset */
+	mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+	mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+	data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* Wait 1ms - until band gap and ref clock ready */
+	mdelay(1);
+	/* Start comphy Configuration */
+	debug("stage: Comphy configuration\n");
+	/* Set PIPE soft reset */
+	mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
+	data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
+	/* Set PHY datapath width mode for V0 */
+	mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
+	data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
+	/* Set Data bus width USB mode for V0 */
+	mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
+	data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
+	/* Set CORE_CLK output frequency for 250Mhz */
+	mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
+	data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
+	/* Set PLL ready delay for 0x2 */
+	data = 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET;
+	mask = HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK;
+	if (pcie_width != PCIE_LNK_X1) {
+		data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET;
+		mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK;
+		data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET;
+		mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK;
+	}
+	reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, data, mask);
+
+	/* Set PIPE mode interface to PCIe3 - 0x1  & set lane order */
+	data = 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET;
+	mask = HPIPE_CLK_SRC_HI_MODE_PIPE_MASK;
+	if (pcie_width != PCIE_LNK_X1) {
+		mask |= HPIPE_CLK_SRC_HI_LANE_STRT_MASK;
+		mask |= HPIPE_CLK_SRC_HI_LANE_MASTER_MASK;
+		mask |= HPIPE_CLK_SRC_HI_LANE_BREAK_MASK;
+		if (comphy_index == 0) {
+			data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET;
+			data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET;
+		} else if (comphy_index == (pcie_width - 1)) {
+			data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET;
+		}
+	}
+	reg_set(hpipe_addr + HPIPE_CLK_SRC_HI_REG, data, mask);
+	/* Config update polarity equalization */
+	data = 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET;
+	mask = HPIPE_CFG_UPDATE_POLARITY_MASK;
+	reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG1_REG, data, mask);
+	/* Set PIPE version 4 to mode enable */
+	data = 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET;
+	mask = HPIPE_DFE_CTRL_28_PIPE4_MASK;
+	reg_set(hpipe_addr + HPIPE_DFE_CTRL_28_REG, data, mask);
+	/* TODO: check if pcie clock is output/input - for bringup use input*/
+	/* Enable PIN clock 100M_125M */
+	mask = 0;
+	data = 0;
+	/* Only if clock is output, configure the clock-source mux */
+	if (clk_dir) {
+		mask |= HPIPE_MISC_CLK100M_125M_MASK;
+		data |= 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET;
+	}
+	/* Set PIN_TXDCLK_2X Clock Freq. Selection for outputs 500MHz clock */
+	mask |= HPIPE_MISC_TXDCLK_2X_MASK;
+	data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET;
+	/* Enable 500MHz Clock */
+	mask |= HPIPE_MISC_CLK500_EN_MASK;
+	data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET;
+	if (clk_dir) { /* output */
+		/* Set reference clock comes from group 1 */
+		mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+		data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+	} else {
+		/* Set reference clock comes from group 2 */
+		mask |= HPIPE_MISC_REFCLK_SEL_MASK;
+		data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET;
+	}
+	mask |= HPIPE_MISC_ICP_FORCE_MASK;
+	data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
+	if (clk_dir) { /* output */
+		/* Set reference frequcency select - 0x2 for 25MHz*/
+		mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+		data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	} else {
+		/* Set reference frequcency select - 0x0 for 100MHz*/
+		mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+		data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	}
+	/* Set PHY mode to PCIe */
+	mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+	data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+
+	/* ref clock alignment */
+	if (pcie_width != PCIE_LNK_X1) {
+		mask = HPIPE_LANE_ALIGN_OFF_MASK;
+		data = 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET;
+		reg_set(hpipe_addr + HPIPE_LANE_ALIGN_REG, data, mask);
+	}
+
+	/* Set the amount of time spent in the LoZ state - set for 0x7 only if
+	 * the PCIe clock is output
+	 */
+	if (clk_dir)
+		reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
+			0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
+			HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
+
+	/* Set Maximal PHY Generation Setting(8Gbps) */
+	mask = HPIPE_INTERFACE_GEN_MAX_MASK;
+	data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET;
+	/* Bypass frame detection and sync detection for RX DATA */
+	mask |= HPIPE_INTERFACE_DET_BYPASS_MASK;
+	data |= 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET;
+	/* Set Link Train Mode (Tx training control pins are used) */
+	mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK;
+	data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_INTERFACE_REG, data, mask);
+
+	/* Set Idle_sync enable */
+	mask = HPIPE_PCIE_IDLE_SYNC_MASK;
+	data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET;
+	/* Select bits for PCIE Gen3(32bit) */
+	mask |= HPIPE_PCIE_SEL_BITS_MASK;
+	data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PCIE_REG0, data, mask);
+
+	/* Enable Tx_adapt_g1 */
+	mask = HPIPE_TX_TRAIN_CTRL_G1_MASK;
+	data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET;
+	/* Enable Tx_adapt_gn1 */
+	mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK;
+	data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET;
+	/* Disable Tx_adapt_g0 */
+	mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK;
+	data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask);
+
+	/* Set reg_tx_train_chk_init */
+	mask = HPIPE_TX_TRAIN_CHK_INIT_MASK;
+	data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET;
+	/* Enable TX_COE_FM_PIN_PCIE3_EN */
+	mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK;
+	data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
+
+	debug("stage: TRx training parameters\n");
+	/* Set Preset sweep configurations */
+	mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK;
+	data = 0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET;
+	mask |= HPIPE_TX_NUM_OF_PRESET_MASK;
+	data |= 0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET;
+	mask |= HPIPE_TX_SWEEP_PRESET_EN_MASK;
+	data |= 0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_11_REG, data, mask);
+
+	/* Tx train start configuration */
+	mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK;
+	data = 0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET;
+	mask |= HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK;
+	data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET;
+	mask |= HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK;
+	data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET;
+	mask |= HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK;
+	data |= 0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
+
+	/* Enable Tx train P2P */
+	mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
+	data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
+
+	/* Configure Tx train timeout */
+	mask = HPIPE_TRX_TRAIN_TIMER_MASK;
+	data = 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_4_REG, data, mask);
+
+	/* Disable G0/G1/GN1 adaptation */
+	mask = HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK
+		| HPIPE_TX_TRAIN_CTRL_G0_OFFSET;
+	data = 0;
+	reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask);
+
+	/* Disable DTL frequency loop */
+	mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+	data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+	/* Configure G3 DFE */
+	mask = HPIPE_G3_DFE_RES_MASK;
+	data = 0x3 << HPIPE_G3_DFE_RES_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
+
+	/* Use TX/RX training result for DFE */
+	mask = HPIPE_DFE_RES_FORCE_MASK;
+	data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_REG0,  data, mask);
+
+	/* Configure initial and final coefficient value for receiver */
+	mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
+	data = 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
+
+	mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
+	data |= 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
+
+	mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
+	data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SET_1_REG,  data, mask);
+
+	/* Trigger sampler enable pulse */
+	mask = HPIPE_SMAPLER_MASK;
+	data = 0x1 << HPIPE_SMAPLER_OFFSET;
+	reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+	udelay(5);
+	reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, 0, mask);
+
+	/* FFE resistor tuning for different bandwidth  */
+	mask = HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
+	data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
+	mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
+	data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
+
+	/* Pattern lock lost timeout disable */
+	mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
+	data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
+
+	/* Configure DFE adaptations */
+	mask = HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK;
+	data = 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET;
+	mask |= HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK;
+	data |= 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET;
+	mask |= HPIPE_CDR_MAX_DFE_ADAPT_0_MASK;
+	data |= 0x0 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET;
+	mask |= HPIPE_CDR_MAX_DFE_ADAPT_1_MASK;
+	data |= 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET;
+	reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask);
+
+	mask = HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK;
+	data = 0x0 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_CONTROL_REG, data, mask);
+
+	/* Genration 2 setting 1*/
+	mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
+	data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
+	mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK;
+	data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET;
+	mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
+	data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
+
+	/* DFE enable */
+	mask = HPIPE_G2_DFE_RES_MASK;
+	data = 0x3 << HPIPE_G2_DFE_RES_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G2_SETTINGS_4_REG, data, mask);
+
+	/* Configure DFE Resolution */
+	mask = HPIPE_LANE_CFG4_DFE_EN_SEL_MASK;
+	data = 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
+
+	/* VDD calibration control */
+	mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+	data = 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+	/* Set PLL Charge-pump Current Control */
+	mask = HPIPE_G3_SETTING_5_G3_ICP_MASK;
+	data = 0x4 << HPIPE_G3_SETTING_5_G3_ICP_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G3_SETTING_5_REG, data, mask);
+
+	/* Set lane rqualization remote setting */
+	mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK;
+	data = 0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET;
+	mask |= HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK;
+	data |= 0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET;
+	mask |= HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK;
+	data |= 0x6 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET;
+	reg_set(hpipe_addr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, data, mask);
+
+	mask = HPIPE_CFG_EQ_BUNDLE_DIS_MASK;
+	data = 0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET;
+	reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG2_REG, data, mask);
+
+	debug("stage: Comphy power up\n");
+
+	/* For PCIe X4 or X2:
+	 * release from reset only after finish to configure all lanes
+	 */
+	if ((pcie_width == PCIE_LNK_X1) || (comphy_index == (pcie_width - 1))) {
+		uint32_t i, start_lane, end_lane;
+
+		if (pcie_width != PCIE_LNK_X1) {
+			/* allows writing to all lanes in one write */
+			data = 0x0;
+			if (pcie_width == PCIE_LNK_X2)
+				mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK;
+			else if (pcie_width == PCIE_LNK_X4)
+				mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK;
+			reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask);
+			start_lane = 0;
+			end_lane = pcie_width;
+
+			/* Release from PIPE soft reset
+			 * For PCIe by4 or by2:
+			 * release from soft reset all lanes - can't use
+			 * read modify write
+			 */
+			reg_set(HPIPE_ADDR(
+				COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), 0) +
+				HPIPE_RST_CLK_CTRL_REG, 0x24, 0xffffffff);
+		} else {
+			start_lane = comphy_index;
+			end_lane = comphy_index + 1;
+
+			/* Release from PIPE soft reset
+			 * for PCIe by4 or by2:
+			 * release from soft reset all lanes
+			 */
+			reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
+				0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
+				HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
+		}
+
+		if (pcie_width != PCIE_LNK_X1) {
+			/* disable writing to all lanes with one write */
+			if (pcie_width == PCIE_LNK_X2) {
+				data = (COMPHY_LANE0 <<
+				COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) |
+				(COMPHY_LANE1 <<
+				COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET);
+				mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK;
+			} else if (pcie_width == PCIE_LNK_X4) {
+				data = (COMPHY_LANE0 <<
+				COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) |
+				(COMPHY_LANE1 <<
+				COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET) |
+				(COMPHY_LANE2 <<
+				COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET) |
+				(COMPHY_LANE3 <<
+				COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET);
+				mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK;
+			}
+			reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+				data, mask);
+		}
+
+		debug("stage: Check PLL\n");
+		/* Read lane status */
+		for (i = start_lane; i < end_lane; i++) {
+			addr = HPIPE_ADDR(
+				COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), i) +
+				HPIPE_LANE_STATUS1_REG;
+			data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
+			mask = data;
+			ret = polling_with_timeout(addr, data, mask,
+						   PLL_LOCK_TIMEOUT,
+						   REG_32BIT);
+			if (ret)
+				ERROR("Failed to lock PCIE PLL\n");
+		}
+	}
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_cp110_comphy_rxaui_power_on(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
+	uint32_t mask, data;
+	int ret = 0;
+
+	debug_enter();
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+
+	/* configure phy selector for RXAUI */
+	mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index,
+					    comphy_mode);
+
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	if (comphy_index == 2) {
+		reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+			0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET,
+			COMMON_PHY_SD_CTRL1_RXAUI0_MASK);
+	}
+	if (comphy_index == 4) {
+		reg_set(comphy_base + COMMON_PHY_SD_CTRL1,
+			0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET,
+			COMMON_PHY_SD_CTRL1_RXAUI1_MASK);
+	}
+
+	/* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */
+	mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK;
+	data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK;
+	data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+	/* release from hard reset */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* Wait 1ms - until band gap and ref clock ready */
+	mdelay(1);
+
+	/* Start comphy Configuration */
+	debug("stage: Comphy configuration\n");
+	/* set reference clock */
+	reg_set(hpipe_addr + HPIPE_MISC_REG,
+		0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+		HPIPE_MISC_REFCLK_SEL_MASK);
+	/* Power and PLL Control */
+	mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+	data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+	data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+	/* Loopback register */
+	reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
+		0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
+	/* rx control 1 */
+	mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK;
+	data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET;
+	mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK;
+	data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask);
+	/* DTL Control */
+	reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG,
+		0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET,
+		HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK);
+
+	/* Set analog parameters from ETP(HW) */
+	debug("stage: Analog parameters from ETP(HW)\n");
+	/* SERDES External Configuration 2 */
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG,
+		0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET,
+		SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK);
+	/* 0x7-DFE Resolution control */
+	reg_set(hpipe_addr + HPIPE_DFE_REG0, 0x1 << HPIPE_DFE_RES_FORCE_OFFSET,
+		HPIPE_DFE_RES_FORCE_MASK);
+	/* 0xd-G1_Setting_0 */
+	reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
+		0xd << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET,
+		HPIPE_G1_SET_0_G1_TX_EMPH1_MASK);
+	/* 0xE-G1_Setting_1 */
+	mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+	data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+	mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
+	data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
+	mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
+	data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+	/* 0xA-DFE_Reg3 */
+	mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+	data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+	mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+	data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+	/* 0x111-G1_Setting_4 */
+	mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
+	data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
+
+	debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
+	/* SERDES External Configuration */
+	mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask);
+
+
+	/* check PLL rx & tx ready */
+	addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+	data = SD_EXTERNAL_STATUS0_PLL_RX_MASK |
+		SD_EXTERNAL_STATUS0_PLL_TX_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT);
+	if (data != 0) {
+		debug("Read from reg = %lx - value = 0x%x\n",
+		      sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data);
+		ERROR("SD_EXTERNAL_STATUS0_PLL_RX is %d, -\"-_PLL_TX is %d\n",
+		      (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK),
+		      (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK));
+		ret = -ETIMEDOUT;
+	}
+
+	/* RX init */
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG,
+		0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET,
+		SD_EXTERNAL_CONFIG1_RX_INIT_MASK);
+
+	/* check that RX init done */
+	addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG;
+	data = SD_EXTERNAL_STATUS0_RX_INIT_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask, 100, REG_32BIT);
+	if (data != 0) {
+		debug("Read from reg = %lx - value = 0x%x\n",
+		      sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data);
+		ERROR("SD_EXTERNAL_STATUS0_RX_INIT is 0\n");
+		ret = -ETIMEDOUT;
+	}
+
+	debug("stage: RF Reset\n");
+	/* RF Reset */
+	mask =  SD_EXTERNAL_CONFIG1_RX_INIT_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	debug_exit();
+
+	return ret;
+}
+
+static int mvebu_cp110_comphy_usb3_power_on(uint64_t comphy_base,
+				     uint8_t comphy_index, uint32_t comphy_mode)
+{
+	uintptr_t hpipe_addr, comphy_addr, addr;
+	uint32_t mask, data;
+	int ret = 0;
+
+	debug_enter();
+
+	/* Configure PIPE selector for USB3 */
+	mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index,
+					     comphy_mode);
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	comphy_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+	debug("stage: RFU configurations - hard reset comphy\n");
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+	mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+	mask |= COMMON_PHY_PHY_MODE_MASK;
+	data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* release from hard reset */
+	mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+	mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+	data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* Wait 1ms - until band gap and ref clock ready */
+	mdelay(1);
+
+	/* Start comphy Configuration */
+	debug("stage: Comphy configuration\n");
+	/* Set PIPE soft reset */
+	mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK;
+	data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET;
+	/* Set PHY datapath width mode for V0 */
+	mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK;
+	data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET;
+	/* Set Data bus width USB mode for V0 */
+	mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK;
+	data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET;
+	/* Set CORE_CLK output frequency for 250Mhz */
+	mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK;
+	data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask);
+	/* Set PLL ready delay for 0x2 */
+	reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG,
+		0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET,
+		HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK);
+	/* Set reference clock to come from group 1 - 25Mhz */
+	reg_set(hpipe_addr + HPIPE_MISC_REG,
+		0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET,
+		HPIPE_MISC_REFCLK_SEL_MASK);
+	/* Set reference frequcency select - 0x2 */
+	mask = HPIPE_PWR_PLL_REF_FREQ_MASK;
+	data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET;
+	/* Set PHY mode to USB - 0x5 */
+	mask |= HPIPE_PWR_PLL_PHY_MODE_MASK;
+	data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask);
+	/* Set the amount of time spent in the LoZ state - set for 0x7 */
+	reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL,
+		0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET,
+		HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK);
+	/* Set max PHY generation setting - 5Gbps */
+	reg_set(hpipe_addr + HPIPE_INTERFACE_REG,
+		0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET,
+		HPIPE_INTERFACE_GEN_MAX_MASK);
+	/* Set select data width 20Bit (SEL_BITS[2:0]) */
+	reg_set(hpipe_addr + HPIPE_LOOPBACK_REG,
+		0x1 << HPIPE_LOOPBACK_SEL_OFFSET,
+		HPIPE_LOOPBACK_SEL_MASK);
+	/* select de-emphasize 3.5db */
+	reg_set(hpipe_addr + HPIPE_LANE_CONFIG0_REG,
+		0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET,
+		HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK);
+	/* override tx margining from the MAC */
+	reg_set(hpipe_addr + HPIPE_TST_MODE_CTRL_REG,
+		0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET,
+		HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK);
+
+	/* Start analog parameters from ETP(HW) */
+	debug("stage: Analog parameters from ETP(HW)\n");
+	/* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */
+	mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK;
+	data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET;
+	/* Set Override PHY DFE control pins for 0x1 */
+	mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK;
+	data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET;
+	/* Set Spread Spectrum Clock Enable fot 0x1 */
+	mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK;
+	data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
+	/* Confifure SSC amplitude */
+	mask = HPIPE_G2_TX_SSC_AMP_MASK;
+	data = 0x1f << HPIPE_G2_TX_SSC_AMP_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
+	/* End of analog parameters */
+
+	debug("stage: Comphy power up\n");
+	/* Release from PIPE soft reset */
+	reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG,
+		0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET,
+		HPIPE_RST_CLK_CTRL_PIPE_RST_MASK);
+
+	/* wait 15ms - for comphy calibration done */
+	debug("stage: Check PLL\n");
+	/* Read lane status */
+	addr = hpipe_addr + HPIPE_LANE_STATUS1_REG;
+	data = HPIPE_LANE_STATUS1_PCLK_EN_MASK;
+	mask = data;
+	data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT);
+	if (data != 0) {
+		debug("Read from reg = %lx - value = 0x%x\n",
+			hpipe_addr + HPIPE_LANE_STATUS1_REG, data);
+		ERROR("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n");
+		ret = -ETIMEDOUT;
+	}
+
+	debug_exit();
+
+	return ret;
+}
+
+int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
+					      uint8_t comphy_index)
+{
+	uint32_t mask, data, timeout;
+	uint32_t g1_ffe_cap_sel, g1_ffe_res_sel, align90, g1_dfe_res;
+	uintptr_t hpipe_addr, sd_ip_addr;
+
+	uint8_t ap_nr, cp_nr;
+
+	mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
+
+	hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+				comphy_index);
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+
+	debug_enter();
+
+	debug("stage: RF Reset\n");
+
+	/* Release from hard reset */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* Wait 50ms - until band gap and ref clock ready */
+	mdelay(50);
+
+	debug("Preparation for rx_training\n\n");
+
+	/* Use the FFE table */
+	mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+	data = 0 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+	/* Use auto-calibration value */
+	mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
+	data = 0 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
+		data, mask);
+
+	/* Use Tx/Rx training results */
+	mask = HPIPE_DFE_RES_FORCE_MASK;
+	data = 0 << HPIPE_DFE_RES_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+	debug("PRBS31 loppback\n\n");
+
+	/* Configure PRBS counters */
+	mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
+	data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+	mask = HPIPE_PHY_TEST_DATA_MASK;
+	data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
+
+	mask = HPIPE_PHY_TEST_EN_MASK;
+	data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+	mdelay(10);
+	debug("Enable TX/RX training\n\n");
+
+	mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
+	data = 0x1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET;
+	mask |= HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK;
+	data |= 0x1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET;
+	mask |= HPIPE_TRX_TX_CTRL_CLK_EN_MASK;
+	data |= 0x1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET;
+	mask |= HPIPE_TRX_UPDATE_THEN_HOLD_MASK;
+	data |= 0x1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET;
+	mask |= HPIPE_TRX_TX_F0T_EO_BASED_MASK;
+	data |= 0x1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask);
+
+	/* Check the result of RX training */
+	timeout = RX_TRAINING_TIMEOUT;
+	mask = HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET |
+		HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET |
+		HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK;
+	while (timeout) {
+		data = mmio_read_32(hpipe_addr + HPIPE_INTERRUPT_1_REGISTER);
+		if (data & mask)
+			break;
+		mdelay(1);
+		timeout--;
+	}
+
+	debug("RX training result: interrupt reg 0x%lx = 0x%x\n\n",
+	       hpipe_addr + HPIPE_INTERRUPT_1_REGISTER, data);
+
+	if (timeout == 0 || data & HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK) {
+		ERROR("Rx training timeout...\n");
+		return -ETIMEDOUT;
+	}
+
+	if (data & HPIPE_TRX_TRAIN_FAILED_MASK) {
+		ERROR("Rx training failed...\n");
+		return -EINVAL;
+	}
+
+	mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
+	data = 0x0 << HPIPE_TRX_RX_TRAIN_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask);
+
+	debug("Training done, reading results...\n\n");
+
+	mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK;
+	g1_ffe_res_sel = ((mmio_read_32(hpipe_addr +
+			   HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG)
+			   & mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET);
+
+	mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK;
+	g1_ffe_cap_sel = ((mmio_read_32(hpipe_addr +
+			   HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG)
+			   & mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET);
+
+	mask = HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK;
+	align90 = ((mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG)
+		    & mask) >> HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET);
+
+	mask = HPIPE_ADAPTED_DFE_RES_MASK;
+	g1_dfe_res = ((mmio_read_32(hpipe_addr +
+		       HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG)
+		       & mask) >> HPIPE_ADAPTED_DFE_RES_OFFSET);
+
+	debug("================================================\n");
+	debug("Switching to static configuration:\n");
+	debug("FFE_RES = 0x%x FFE_CAP = 0x%x align90 = 0x%x g1_dfe_res 0x%x\n",
+	       g1_ffe_res_sel, g1_ffe_cap_sel, align90, g1_dfe_res);
+	debug("Result after training: 0x%lx= 0x%x, 0x%lx= 0x%x, 0x%lx = 0x%x\n",
+	      (hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG),
+	       mmio_read_32(hpipe_addr +
+			    HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG),
+			    (hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG),
+	       mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG),
+			    (hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG),
+	       mmio_read_32(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG));
+	debug("================================================\n");
+
+	/* Update FFE_RES */
+	mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+	data = g1_ffe_res_sel << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+	/* Update FFE_CAP */
+	mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+	data = g1_ffe_cap_sel << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+	/* Bypass the FFE table settings and use the FFE settings directly from
+	 * registers FFE_RES_SEL and FFE_CAP_SEL
+	 */
+	mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+	data = 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+	/* Use the value from CAL_OS_PH_EXT */
+	mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
+	data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
+		data, mask);
+
+	/* Update align90 */
+	mask = HPIPE_CAL_OS_PH_EXT_MASK;
+	data = align90 << HPIPE_CAL_OS_PH_EXT_OFFSET;
+	reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
+		data, mask);
+
+	/* Force DFE resolution (use gen table value) */
+	mask = HPIPE_DFE_RES_FORCE_MASK;
+	data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+	/* 0x111-G1 DFE_Setting_4 */
+	mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
+	data = g1_dfe_res << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
+	reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
+
+	debug("PRBS31 loppback\n\n");
+
+	mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK;
+	data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask);
+
+	/* Configure PRBS counters */
+	mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
+	data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+	mask = HPIPE_PHY_TEST_DATA_MASK;
+	data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
+
+	mask = HPIPE_PHY_TEST_EN_MASK;
+	data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+	/* Reset PRBS error counter */
+	mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
+	data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+	mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
+	data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
+
+	mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK;
+	data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET;
+	reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask);
+
+	printf("########################################################\n");
+	printf("# To use trained values update the ATF sources:\n");
+	printf("# plat/marvell/a8k/<board_type>/board/phy-porting-layer.h ");
+	printf("file\n# with new values as below (for appropriate AP nr %d",
+	       ap_nr);
+	printf("and CP nr: %d comphy_index %d\n\n",
+	       cp_nr, comphy_index);
+	printf("static struct xfi_params xfi_static_values_tab[AP_NUM]");
+	printf("[CP_NUM][MAX_LANE_NR] = {\n");
+	printf("\t...\n");
+	printf("\t.g1_ffe_res_sel = 0x%x,\n", g1_ffe_res_sel);
+	printf("\t.g1_ffe_cap_sel = 0x%x,\n", g1_ffe_cap_sel);
+	printf("\t.align90 = 0x%x,\n", align90);
+	printf("\t.g1_dfe_res = 0x%x\n", g1_dfe_res);
+	printf("\t...\n");
+	printf("};\n\n");
+	printf("########################################################\n");
+
+	/* check */
+	debug("PRBS error counter[0x%lx] 0x%x\n\n",
+	      hpipe_addr + HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG,
+	      mmio_read_32(hpipe_addr +
+			   HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG));
+
+	rx_trainng_done[ap_nr][cp_nr][comphy_index] = 1;
+
+	return 0;
+}
+
+/* During AP the proper mode is auto-negotiated and the mac, pcs and serdes
+ * configuration are done by the firmware loaded to the MG's CM3 for appropriate
+ * negotiated mode. Therefore there is no need to configure the mac, pcs and
+ * serdes from u-boot. The only thing that need to be setup is powering up
+ * the comphy, which is done through Common PHY<n> Configuration 1 Register
+ * (CP0: 0xF2441000, CP1: 0xF4441000). This step can't be done by MG's CM3,
+ * since it doesn't have an access to this register-set (but it has access to
+ * the network registers like: MG, AP, MAC, PCS, Serdes etc.)
+ */
+static int mvebu_cp110_comphy_ap_power_on(uint64_t comphy_base,
+					  uint8_t comphy_index)
+{
+	uint32_t mask, data;
+	uintptr_t comphy_addr = comphy_addr =
+				COMPHY_ADDR(comphy_base, comphy_index);
+
+	debug_enter();
+	debug("stage: RFU configurations - hard reset comphy\n");
+	/* RFU configurations - hard reset comphy */
+	mask = COMMON_PHY_CFG1_PWR_UP_MASK;
+	data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET;
+	mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET;
+	reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask);
+	debug_exit();
+
+	return 0;
+}
+
+/*
+ * This function allows to reset the digital synchronizers between
+ * the MAC and the PHY, it is required when the MAC changes its state.
+ */
+int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base,
+				     uint8_t comphy_index,
+				     uint32_t comphy_mode, uint32_t command)
+{
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	uintptr_t sd_ip_addr;
+	uint32_t mask, data;
+
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+
+	switch (mode) {
+	case (COMPHY_SGMII_MODE):
+	case (COMPHY_HS_SGMII_MODE):
+	case (COMPHY_XFI_MODE):
+	case (COMPHY_SFI_MODE):
+	case (COMPHY_RXAUI_MODE):
+		mask = SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+		data = ((command == COMPHY_COMMAND_DIGITAL_PWR_OFF) ?
+			0x0 : 0x1) << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+		reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+		break;
+	default:
+		ERROR("comphy%d: Digital PWR ON/OFF is not supported\n",
+			comphy_index);
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index,
+				uint64_t comphy_mode)
+{
+	int mode = COMPHY_GET_MODE(comphy_mode);
+	int err = 0;
+
+	debug_enter();
+
+	switch (mode) {
+	case(COMPHY_SATA_MODE):
+		err = mvebu_cp110_comphy_sata_power_on(comphy_base,
+						       comphy_index,
+						       comphy_mode);
+		break;
+	case(COMPHY_SGMII_MODE):
+	case(COMPHY_HS_SGMII_MODE):
+		err = mvebu_cp110_comphy_sgmii_power_on(comphy_base,
+							comphy_index,
+							comphy_mode);
+		break;
+	/* From comphy perspective, XFI and SFI are the same */
+	case (COMPHY_XFI_MODE):
+	case (COMPHY_SFI_MODE):
+		err = mvebu_cp110_comphy_xfi_power_on(comphy_base,
+						      comphy_index,
+						      comphy_mode);
+		break;
+	case (COMPHY_PCIE_MODE):
+		err = mvebu_cp110_comphy_pcie_power_on(comphy_base,
+						       comphy_index,
+						       comphy_mode);
+		break;
+	case (COMPHY_RXAUI_MODE):
+		err = mvebu_cp110_comphy_rxaui_power_on(comphy_base,
+							comphy_index,
+							comphy_mode);
+		break;
+	case (COMPHY_USB3H_MODE):
+	case (COMPHY_USB3D_MODE):
+		err = mvebu_cp110_comphy_usb3_power_on(comphy_base,
+						       comphy_index,
+						       comphy_mode);
+		break;
+	case (COMPHY_AP_MODE):
+		err = mvebu_cp110_comphy_ap_power_on(comphy_base, comphy_index);
+		break;
+	default:
+		ERROR("comphy%d: unsupported comphy mode\n", comphy_index);
+		err = -EINVAL;
+		break;
+	}
+
+	debug_exit();
+
+	return err;
+}
+
+int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index,
+				 uint64_t comphy_mode)
+{
+	uintptr_t sd_ip_addr, comphy_ip_addr;
+	uint32_t mask, data;
+	uint8_t ap_nr, cp_nr;
+	_Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode);
+
+	debug_enter();
+
+	/* Power-off might happen because of 2 things:
+	 *	1. Bootloader turns off unconnected lanes
+	 *	2. Linux turns off all lanes during boot
+	 *	   (and then reconfigure it).
+	 *
+	 * For PCIe, there's a problem:
+	 * In Armada 8K DB boards, PCIe initialization can be executed
+	 * only once (PCIe reset performed during chip power on and
+	 * it cannot be executed via GPIO later) so a lane configured to
+	 * PCIe should not be powered off by Linux.
+	 *
+	 * So, check 2 things:
+	 *	1. Is Linux called for power-off?
+	 *	2. Is the comphy configured to PCIe?
+	 * If the answer is YES for both 1 and 2, skip the power-off.
+	 *
+	 * TODO: In MacciatoBIN, PCIe reset is connected via GPIO,
+	 * so after GPIO reset is added to Linux Kernel, it can be
+	 * powered-off.
+	 */
+	if (!called_from_uboot) {
+		data = mmio_read_32(comphy_base +
+				    COMMON_SELECTOR_PIPE_REG_OFFSET);
+		data >>= (COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index);
+		data &= COMMON_SELECTOR_COMPHY_MASK;
+		if (data == COMMON_SELECTOR_PIPE_COMPHY_PCIE)
+			return 0;
+	}
+
+	mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
+
+	if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) {
+		debug("Skip %s for comphy[%d][%d][%d], due to rx training\n",
+		       __func__, ap_nr, cp_nr, comphy_index);
+		return 0;
+	}
+
+	sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
+			     comphy_index);
+	comphy_ip_addr = COMPHY_ADDR(comphy_base, comphy_index);
+
+	/* Hard reset the comphy, for Ethernet modes and Sata */
+	mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
+	data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
+	mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
+	data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
+	reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
+
+	/* PCIe reset */
+	spin_lock(&cp110_mac_reset_lock);
+
+	/* The mvebu_cp110_comphy_power_off will be called only from Linux (to
+	 * override settings done by bootloader) and it will be relevant only
+	 * to PCIe (called before check if to skip pcie power off or not).
+	 */
+	data = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+						 SYS_CTRL_UINIT_SOFT_RESET_REG);
+	switch (comphy_index) {
+	case COMPHY_LANE0:
+		data &= ~PCIE_MAC_RESET_MASK_PORT0;
+		break;
+	case COMPHY_LANE4:
+		data &= ~PCIE_MAC_RESET_MASK_PORT1;
+		break;
+	case COMPHY_LANE5:
+		data &= ~PCIE_MAC_RESET_MASK_PORT2;
+		break;
+	}
+
+	mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) +
+					   SYS_CTRL_UINIT_SOFT_RESET_REG, data);
+	spin_unlock(&cp110_mac_reset_lock);
+
+	/* Hard reset the comphy, for PCIe and usb3 */
+	mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK;
+	data = 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET;
+	mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK;
+	data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET;
+	reg_set(comphy_ip_addr + COMMON_PHY_CFG1_REG, data, mask);
+
+	/* Clear comphy PHY and PIPE selector, can't rely on previous config. */
+	mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index);
+	mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index);
+
+	debug_exit();
+
+	return 0;
+}
diff --git a/drivers/marvell/comphy/phy-comphy-cp110.h b/drivers/marvell/comphy/phy-comphy-cp110.h
new file mode 100644
index 0000000..407909b
--- /dev/null
+++ b/drivers/marvell/comphy/phy-comphy-cp110.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Those are parameters for xfi mode, which need to be tune for each board type.
+ * For known DB boards the parameters was already calibrated and placed under
+ * the plat/marvell/a8k/<board_type>/board/phy-porting-layer.h
+ */
+struct xfi_params {
+	uint8_t g1_ffe_res_sel;
+	uint8_t g1_ffe_cap_sel;
+	uint8_t align90;
+	uint8_t g1_dfe_res;
+	uint8_t g1_amp;
+	uint8_t g1_emph;
+	uint8_t g1_emph_en;
+	uint8_t g1_tx_amp_adj;
+	uint8_t g1_tx_emph_en;
+	uint8_t g1_tx_emph;
+	uint8_t g1_rx_selmuff;
+	uint8_t g1_rx_selmufi;
+	uint8_t g1_rx_selmupf;
+	uint8_t g1_rx_selmupi;
+	_Bool valid;
+};
+
+struct sata_params {
+	uint8_t g1_amp;
+	uint8_t g2_amp;
+	uint8_t g3_amp;
+
+	uint8_t g1_emph;
+	uint8_t g2_emph;
+	uint8_t g3_emph;
+
+	uint8_t g1_emph_en;
+	uint8_t g2_emph_en;
+	uint8_t g3_emph_en;
+
+	uint8_t g1_tx_amp_adj;
+	uint8_t g2_tx_amp_adj;
+	uint8_t g3_tx_amp_adj;
+
+	uint8_t g1_tx_emph_en;
+	uint8_t g2_tx_emph_en;
+	uint8_t g3_tx_emph_en;
+
+	uint8_t g1_tx_emph;
+	uint8_t g2_tx_emph;
+	uint8_t g3_tx_emph;
+
+	uint8_t g3_dfe_res;
+
+	uint8_t g3_ffe_res_sel;
+
+	uint8_t g3_ffe_cap_sel;
+
+	uint8_t align90;
+
+	uint8_t g1_rx_selmuff;
+	uint8_t g2_rx_selmuff;
+	uint8_t g3_rx_selmuff;
+
+	uint8_t g1_rx_selmufi;
+	uint8_t g2_rx_selmufi;
+	uint8_t g3_rx_selmufi;
+
+	uint8_t g1_rx_selmupf;
+	uint8_t g2_rx_selmupf;
+	uint8_t g3_rx_selmupf;
+
+	uint8_t g1_rx_selmupi;
+	uint8_t g2_rx_selmupi;
+	uint8_t g3_rx_selmupi;
+
+	_Bool valid;
+};
+
+int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base,
+				     uint8_t comphy_index);
+int mvebu_cp110_comphy_power_off(uint64_t comphy_base,
+				 uint8_t comphy_index, uint64_t comphy_mode);
+int mvebu_cp110_comphy_power_on(uint64_t comphy_base,
+				uint8_t comphy_index, uint64_t comphy_mode);
+int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
+				       uint8_t comphy_index);
+int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base, uint8_t comphy_index,
+				     uint32_t comphy_mode, uint32_t command);
diff --git a/drivers/marvell/comphy/phy-default-porting-layer.h b/drivers/marvell/comphy/phy-default-porting-layer.h
new file mode 100644
index 0000000..b3ad7eb
--- /dev/null
+++ b/drivers/marvell/comphy/phy-default-porting-layer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PHY_DEFAULT_PORTING_LAYER_H
+#define PHY_DEFAULT_PORTING_LAYER_H
+
+
+#define MAX_LANE_NR		6
+
+#warning "Using default comphy params - you may need to suit them to your board"
+
+static const struct xfi_params
+	xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+		.g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f,
+		.g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
+		.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1,
+		.g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
+		.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 1
+	}
+};
+
+static const struct sata_params
+	sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+		.g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+		.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+		.g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1,
+		.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
+		.g3_tx_amp_adj = 0x1,
+		.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
+		.g3_tx_emph_en = 0x0,
+		.g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1,
+		.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf,
+		.align90 = 0x61,
+		.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
+		.g3_rx_selmuff = 0x3,
+		.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
+		.g3_rx_selmufi = 0x3,
+		.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
+		.g3_rx_selmupf = 0x2,
+		.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
+		.g3_rx_selmupi = 0x2,
+		.valid = 0x1
+	},
+};
+#endif /* PHY_DEFAULT_PORTING_LAYER_H */
diff --git a/drivers/marvell/gwin.c b/drivers/marvell/gwin.c
new file mode 100644
index 0000000..9d94308
--- /dev/null
+++ b/drivers/marvell/gwin.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* GWIN unit device driver for Marvell AP810 SoC */
+
+#include <common/debug.h>
+#include <drivers/marvell/gwin.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT			(0x1)
+#define WIN_TARGET_MASK			(0xF)
+#define WIN_TARGET_SHIFT		(0x8)
+#define WIN_TARGET(tgt)			(((tgt) & WIN_TARGET_MASK) \
+					<< WIN_TARGET_SHIFT)
+
+/* Bits[43:26] of the physical address are the window base,
+ * which is aligned to 64MB
+ */
+#define ADDRESS_RSHIFT			(26)
+#define ADDRESS_LSHIFT			(10)
+#define GWIN_ALIGNMENT_64M		(0x4000000)
+
+/* AP registers */
+#define GWIN_CR_OFFSET(ap, win)		(MVEBU_GWIN_BASE(ap) + 0x0 + \
+						(0x10 * (win)))
+#define GWIN_ALR_OFFSET(ap, win)	(MVEBU_GWIN_BASE(ap) + 0x8 + \
+						(0x10 * (win)))
+#define GWIN_AHR_OFFSET(ap, win)	(MVEBU_GWIN_BASE(ap) + 0xc + \
+						(0x10 * (win)))
+
+#define CCU_GRU_CR_OFFSET(ap)		(MVEBU_CCU_GRU_BASE(ap))
+#define CCR_GRU_CR_GWIN_MBYPASS		(1 << 1)
+
+static void gwin_check(struct addr_map_win *win)
+{
+	/* The base is always 64M aligned */
+	if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) {
+		win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1);
+		NOTICE("%s: Align the base address to 0x%llx\n",
+		       __func__, win->base_addr);
+	}
+
+	/* size parameter validity check */
+	if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) {
+		win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M);
+		NOTICE("%s: Aligning window size to 0x%llx\n",
+		       __func__, win->win_size);
+	}
+}
+
+static void gwin_enable_window(int ap_index, struct addr_map_win *win,
+			       uint32_t win_num)
+{
+	uint32_t alr, ahr;
+	uint64_t end_addr;
+
+	if ((win->target_id & WIN_TARGET_MASK) != win->target_id) {
+		ERROR("target ID = %d, is invalid\n", win->target_id);
+		return;
+	}
+
+	/* calculate 64bit end-address */
+	end_addr = (win->base_addr + win->win_size - 1);
+
+	alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
+	ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT);
+
+	/* write start address and end address for GWIN */
+	mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr);
+	mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr);
+
+	/* write the target ID and enable the window */
+	mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num),
+		      WIN_TARGET(win->target_id) | WIN_ENABLE_BIT);
+}
+
+static void gwin_disable_window(int ap_index, uint32_t win_num)
+{
+	uint32_t win_reg;
+
+	win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
+	win_reg &= ~WIN_ENABLE_BIT;
+	mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg);
+}
+
+/* Insert/Remove temporary window for using the out-of reset default
+ * CPx base address to access the CP configuration space prior to
+ * the further base address update in accordance with address mapping
+ * design.
+ *
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
+{
+	uint32_t win_id;
+
+	for (int i = 0; i < size; i++) {
+		win_id = MVEBU_GWIN_MAX_WINS - i - 1;
+		gwin_check(win);
+		gwin_enable_window(ap_index, win, win_id);
+		win++;
+	}
+}
+
+/*
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
+{
+	uint32_t win_id;
+
+	for (int i = 0; i < size; i++) {
+		uint64_t base;
+		uint32_t target;
+
+		win_id = MVEBU_GWIN_MAX_WINS - i - 1;
+
+		target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id));
+		target >>= WIN_TARGET_SHIFT;
+		target &= WIN_TARGET_MASK;
+
+		base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id));
+		base >>= ADDRESS_LSHIFT;
+		base <<= ADDRESS_RSHIFT;
+
+		if (win->target_id != target) {
+			ERROR("%s: Trying to remove bad window-%d!\n",
+			      __func__, win_id);
+			continue;
+		}
+		gwin_disable_window(ap_index, win_id);
+		win++;
+	}
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_gwin(int ap_index)
+{
+	uint32_t win_num;
+
+	/* Dump all GWIN windows */
+	printf("\tbank  target     start              end\n");
+	printf("\t----------------------------------------------------\n");
+	for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) {
+		uint32_t cr;
+		uint64_t alr, ahr;
+
+		cr  = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num));
+		/* Window enabled */
+		if (cr & WIN_ENABLE_BIT) {
+			alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num));
+			alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
+			ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num));
+			ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT;
+			printf("\tgwin   %d     0x%016llx 0x%016llx\n",
+			       (cr >> 8) & 0xF, alr, ahr);
+		}
+	}
+}
+#endif
+
+int init_gwin(int ap_index)
+{
+	struct addr_map_win *win;
+	uint32_t win_id;
+	uint32_t win_count;
+	uint32_t win_reg;
+
+	INFO("Initializing GWIN Address decoding\n");
+
+	/* Get the array of the windows and its size */
+	marvell_get_gwin_memory_map(ap_index, &win, &win_count);
+	if (win_count <= 0) {
+		INFO("no windows configurations found\n");
+		return 0;
+	}
+
+	if (win_count > MVEBU_GWIN_MAX_WINS) {
+		ERROR("number of windows is bigger than %d\n",
+		      MVEBU_GWIN_MAX_WINS);
+		return 0;
+	}
+
+	/* disable all windows */
+	for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++)
+		gwin_disable_window(ap_index, win_id);
+
+	/* enable relevant windows */
+	for (win_id = 0; win_id < win_count; win_id++, win++) {
+		gwin_check(win);
+		gwin_enable_window(ap_index, win, win_id);
+	}
+
+	/* GWIN Miss feature has not verified, therefore any access towards
+	 * remote AP should be accompanied with proper configuration to
+	 * GWIN registers group and therefore the GWIN Miss feature
+	 * should be set into Bypass mode, need to make sure all GWIN regions
+	 * are defined correctly that will assure no GWIN miss occurrance
+	 * JIRA-AURORA2-1630
+	 */
+	INFO("Update GWIN miss bypass\n");
+	win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index));
+	win_reg |= CCR_GRU_CR_GWIN_MBYPASS;
+	mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg);
+
+#ifdef DEBUG_ADDR_MAP
+	dump_gwin(ap_index);
+#endif
+
+	INFO("Done GWIN Address decoding Initializing\n");
+
+	return 0;
+}
diff --git a/drivers/marvell/io_win.c b/drivers/marvell/io_win.c
new file mode 100644
index 0000000..c4257fa
--- /dev/null
+++ b/drivers/marvell/io_win.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#include <common/debug.h>
+#include <drivers/marvell/io_win.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+/* common defines */
+#define WIN_ENABLE_BIT			(0x1)
+/* Physical address of the base of the window = {Addr[19:0],20`h0} */
+#define ADDRESS_SHIFT			(20 - 4)
+#define ADDRESS_MASK			(0xFFFFFFF0)
+#define IO_WIN_ALIGNMENT_1M		(0x100000)
+#define IO_WIN_ALIGNMENT_64K		(0x10000)
+
+/* AP registers */
+#define IO_WIN_ALR_OFFSET(ap, win)	(MVEBU_IO_WIN_BASE(ap) + 0x0 + \
+						(0x10 * win))
+#define IO_WIN_AHR_OFFSET(ap, win)	(MVEBU_IO_WIN_BASE(ap) + 0x8 + \
+						(0x10 * win))
+#define IO_WIN_CR_OFFSET(ap, win)	(MVEBU_IO_WIN_BASE(ap) + 0xC + \
+						(0x10 * win))
+
+/* For storage of CR, ALR, AHR abd GCR */
+static uint32_t io_win_regs_save[MVEBU_IO_WIN_MAX_WINS * 3 + 1];
+
+static void io_win_check(struct addr_map_win *win)
+{
+	/* for IO The base is always 1M aligned */
+	/* check if address is aligned to 1M */
+	if (IS_NOT_ALIGN(win->base_addr, IO_WIN_ALIGNMENT_1M)) {
+		win->base_addr = ALIGN_UP(win->base_addr, IO_WIN_ALIGNMENT_1M);
+		NOTICE("%s: Align up the base address to 0x%llx\n",
+		       __func__, win->base_addr);
+	}
+
+	/* size parameter validity check */
+	if (IS_NOT_ALIGN(win->win_size, IO_WIN_ALIGNMENT_1M)) {
+		win->win_size = ALIGN_UP(win->win_size, IO_WIN_ALIGNMENT_1M);
+		NOTICE("%s: Aligning size to 0x%llx\n",
+		       __func__, win->win_size);
+	}
+}
+
+static void io_win_enable_window(int ap_index, struct addr_map_win *win,
+				 uint32_t win_num)
+{
+	uint32_t alr, ahr;
+	uint64_t end_addr;
+
+	if (win->target_id < 0 || win->target_id >= MVEBU_IO_WIN_MAX_WINS) {
+		ERROR("target ID = %d, is invalid\n", win->target_id);
+		return;
+	}
+
+	if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) {
+		ERROR("Enabling wrong IOW window %d!\n", win_num);
+		return;
+	}
+
+	/* calculate the end-address */
+	end_addr = (win->base_addr + win->win_size - 1);
+
+	alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+	alr |= WIN_ENABLE_BIT;
+	ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+
+	/* write start address and end address for IO window */
+	mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), alr);
+	mmio_write_32(IO_WIN_AHR_OFFSET(ap_index, win_num), ahr);
+
+	/* write window target */
+	mmio_write_32(IO_WIN_CR_OFFSET(ap_index, win_num), win->target_id);
+}
+
+static void io_win_disable_window(int ap_index, uint32_t win_num)
+{
+	uint32_t win_reg;
+
+	if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) {
+		ERROR("Disabling wrong IOW window %d!\n", win_num);
+		return;
+	}
+
+	win_reg = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_num));
+	win_reg &= ~WIN_ENABLE_BIT;
+	mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), win_reg);
+}
+
+/* Insert/Remove temporary window for using the out-of reset default
+ * CPx base address to access the CP configuration space prior to
+ * the further base address update in accordance with address mapping
+ * design.
+ *
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size)
+{
+	uint32_t win_id;
+
+	for (int i = 0; i < size; i++) {
+		win_id = MVEBU_IO_WIN_MAX_WINS - i - 1;
+		io_win_check(win);
+		io_win_enable_window(ap_index, win, win_id);
+		win++;
+	}
+}
+
+/*
+ * NOTE: Use the same window array for insertion and removal of
+ *       temporary windows.
+ */
+void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size)
+{
+	uint32_t win_id;
+
+	/* Start from the last window and do not touch Win0 */
+	for (int i = 0; i < size; i++) {
+		uint64_t base;
+		uint32_t target;
+
+		win_id = MVEBU_IO_WIN_MAX_WINS - i - 1;
+
+		target = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, win_id));
+		base = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id));
+		base &= ~WIN_ENABLE_BIT;
+		base <<= ADDRESS_SHIFT;
+
+		if ((win->target_id != target) || (win->base_addr != base)) {
+			ERROR("%s: Trying to remove bad window-%d!\n",
+			      __func__, win_id);
+			continue;
+		}
+		io_win_disable_window(ap_index, win_id);
+		win++;
+	}
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_io_win(int ap_index)
+{
+	uint32_t trgt_id, win_id;
+	uint32_t alr, ahr;
+	uint64_t start, end;
+
+	/* Dump all IO windows */
+	printf("\tbank  target     start              end\n");
+	printf("\t----------------------------------------------------\n");
+	for (win_id = 0; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) {
+		alr = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id));
+		if (alr & WIN_ENABLE_BIT) {
+			alr &= ~WIN_ENABLE_BIT;
+			ahr = mmio_read_32(IO_WIN_AHR_OFFSET(ap_index, win_id));
+			trgt_id = mmio_read_32(IO_WIN_CR_OFFSET(ap_index,
+								win_id));
+			start = ((uint64_t)alr << ADDRESS_SHIFT);
+			end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
+			printf("\tio-win %d     0x%016llx 0x%016llx\n",
+			       trgt_id, start, end);
+		}
+	}
+	printf("\tio-win gcr is %x\n",
+	       mmio_read_32(MVEBU_IO_WIN_BASE(ap_index) +
+	       MVEBU_IO_WIN_GCR_OFFSET));
+}
+#endif
+
+static void iow_save_win_range(int ap_id, int win_first, int win_last,
+			       uint32_t *buffer)
+{
+	int win_id, idx;
+
+	/* Save IOW */
+	for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+		buffer[idx++] = mmio_read_32(IO_WIN_CR_OFFSET(ap_id, win_id));
+		buffer[idx++] = mmio_read_32(IO_WIN_ALR_OFFSET(ap_id, win_id));
+		buffer[idx++] = mmio_read_32(IO_WIN_AHR_OFFSET(ap_id, win_id));
+	}
+	buffer[idx] = mmio_read_32(MVEBU_IO_WIN_BASE(ap_id) +
+				   MVEBU_IO_WIN_GCR_OFFSET);
+}
+
+static void iow_restore_win_range(int ap_id, int win_first, int win_last,
+				  uint32_t *buffer)
+{
+	int win_id, idx;
+
+	/* Restore IOW */
+	for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) {
+		mmio_write_32(IO_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]);
+		mmio_write_32(IO_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]);
+		mmio_write_32(IO_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]);
+	}
+	mmio_write_32(MVEBU_IO_WIN_BASE(ap_id) + MVEBU_IO_WIN_GCR_OFFSET,
+		      buffer[idx++]);
+}
+
+void iow_save_win_all(int ap_id)
+{
+	iow_save_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1,
+			   io_win_regs_save);
+}
+
+void iow_restore_win_all(int ap_id)
+{
+	iow_restore_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1,
+			      io_win_regs_save);
+}
+
+int init_io_win(int ap_index)
+{
+	struct addr_map_win *win;
+	uint32_t win_id, win_reg;
+	uint32_t win_count;
+
+	INFO("Initializing IO WIN Address decoding\n");
+
+	/* Get the array of the windows and its size */
+	marvell_get_io_win_memory_map(ap_index, &win, &win_count);
+	if (win_count <= 0)
+		INFO("no windows configurations found\n");
+
+	if (win_count > MVEBU_IO_WIN_MAX_WINS) {
+		INFO("number of windows is bigger than %d\n",
+		     MVEBU_IO_WIN_MAX_WINS);
+		return 0;
+	}
+
+	/* Get the default target id to set the GCR */
+	win_reg = marvell_get_io_win_gcr_target(ap_index);
+	mmio_write_32(MVEBU_IO_WIN_BASE(ap_index) + MVEBU_IO_WIN_GCR_OFFSET,
+		      win_reg);
+
+	/* disable all IO windows */
+	for (win_id = 1; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++)
+		io_win_disable_window(ap_index, win_id);
+
+	/* enable relevant windows, starting from win_id = 1 because
+	 * index 0 dedicated for BootROM
+	 */
+	for (win_id = 1; win_id <= win_count; win_id++, win++) {
+		io_win_check(win);
+		io_win_enable_window(ap_index, win, win_id);
+	}
+
+#ifdef DEBUG_ADDR_MAP
+	dump_io_win(ap_index);
+#endif
+
+	INFO("Done IO WIN Address decoding Initializing\n");
+
+	return 0;
+}
diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c
new file mode 100644
index 0000000..87f147a
--- /dev/null
+++ b/drivers/marvell/iob.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 - 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/marvell/iob.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+#define DEBUG_ADDR_MAP
+#endif
+
+#define MVEBU_IOB_OFFSET		(0x190000)
+#define MVEBU_IOB_MAX_WINS		16
+
+/* common defines */
+#define WIN_ENABLE_BIT			(0x1)
+/* Physical address of the base of the window = {AddrLow[19:0],20`h0} */
+#define ADDRESS_SHIFT			(20 - 4)
+#define ADDRESS_MASK			(0xFFFFFFF0)
+#define IOB_WIN_ALIGNMENT		(0x100000)
+
+/* IOB registers */
+#define IOB_WIN_CR_OFFSET(win)		(iob_base + 0x0 + (0x20 * win))
+#define IOB_TARGET_ID_OFFSET		(8)
+#define IOB_TARGET_ID_MASK		(0xF)
+
+#define IOB_WIN_SCR_OFFSET(win)		(iob_base + 0x4 + (0x20 * win))
+#define IOB_WIN_ENA_CTRL_WRITE_SECURE	(0x1)
+#define IOB_WIN_ENA_CTRL_READ_SECURE	(0x2)
+#define IOB_WIN_ENA_WRITE_SECURE	(0x4)
+#define IOB_WIN_ENA_READ_SECURE		(0x8)
+
+#define IOB_WIN_ALR_OFFSET(win)		(iob_base + 0x8 + (0x20 * win))
+#define IOB_WIN_AHR_OFFSET(win)		(iob_base + 0xC + (0x20 * win))
+
+uintptr_t iob_base;
+
+static void iob_win_check(struct addr_map_win *win, uint32_t win_num)
+{
+	/* check if address is aligned to the size */
+	if (IS_NOT_ALIGN(win->base_addr, IOB_WIN_ALIGNMENT)) {
+		win->base_addr = ALIGN_UP(win->base_addr, IOB_WIN_ALIGNMENT);
+		ERROR("Window %d: base address unaligned to 0x%x\n",
+		      win_num, IOB_WIN_ALIGNMENT);
+		printf("Align up the base address to 0x%llx\n",
+		       win->base_addr);
+	}
+
+	/* size parameter validity check */
+	if (IS_NOT_ALIGN(win->win_size, IOB_WIN_ALIGNMENT)) {
+		win->win_size = ALIGN_UP(win->win_size, IOB_WIN_ALIGNMENT);
+		ERROR("Window %d: window size unaligned to 0x%x\n", win_num,
+		      IOB_WIN_ALIGNMENT);
+		printf("Aligning size to 0x%llx\n", win->win_size);
+	}
+}
+
+static void iob_enable_win(struct addr_map_win *win, uint32_t win_id)
+{
+	uint32_t iob_win_reg;
+	uint32_t alr, ahr;
+	uint64_t end_addr;
+
+	end_addr = (win->base_addr + win->win_size - 1);
+	alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+	ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
+
+	mmio_write_32(IOB_WIN_ALR_OFFSET(win_id), alr);
+	mmio_write_32(IOB_WIN_AHR_OFFSET(win_id), ahr);
+
+	iob_win_reg = WIN_ENABLE_BIT;
+	iob_win_reg |= (win->target_id & IOB_TARGET_ID_MASK)
+		       << IOB_TARGET_ID_OFFSET;
+	mmio_write_32(IOB_WIN_CR_OFFSET(win_id), iob_win_reg);
+
+}
+
+#ifdef DEBUG_ADDR_MAP
+static void dump_iob(void)
+{
+	uint32_t win_id, win_cr, alr, ahr;
+	uint8_t target_id;
+	uint64_t start, end;
+	char *iob_target_name[IOB_MAX_TID] = {
+		"CFG  ", "MCI0 ", "PEX1 ", "PEX2 ",
+		"PEX0 ", "NAND ", "RUNIT", "MCI1 " };
+
+	/* Dump all IOB windows */
+	printf("bank  id target  start              end\n");
+	printf("----------------------------------------------------\n");
+	for (win_id = 0; win_id < MVEBU_IOB_MAX_WINS; win_id++) {
+		win_cr = mmio_read_32(IOB_WIN_CR_OFFSET(win_id));
+		if (win_cr & WIN_ENABLE_BIT) {
+			target_id = (win_cr >> IOB_TARGET_ID_OFFSET) &
+				     IOB_TARGET_ID_MASK;
+			alr = mmio_read_32(IOB_WIN_ALR_OFFSET(win_id));
+			start = ((uint64_t)alr << ADDRESS_SHIFT);
+			if (win_id != 0) {
+				ahr = mmio_read_32(IOB_WIN_AHR_OFFSET(win_id));
+				end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT);
+			} else {
+				/* Window #0 size is hardcoded to 16MB, as it's
+				 * reserved for CP configuration space.
+				 */
+				end = start + (16 << 20);
+			}
+			printf("iob   %02d %s   0x%016llx 0x%016llx\n",
+			       win_id, iob_target_name[target_id],
+			       start, end);
+		}
+	}
+}
+#endif
+
+void iob_cfg_space_update(int ap_idx, int cp_idx, uintptr_t base,
+			  uintptr_t new_base)
+{
+	debug_enter();
+
+	iob_base = base + MVEBU_IOB_OFFSET;
+
+	NOTICE("Change the base address of AP%d-CP%d to %lx\n",
+	       ap_idx, cp_idx, new_base);
+	mmio_write_32(IOB_WIN_ALR_OFFSET(0), new_base >> ADDRESS_SHIFT);
+
+	iob_base = new_base + MVEBU_IOB_OFFSET;
+
+	/* Make sure the address was configured by the CPU before
+	 * any possible access to the CP.
+	 */
+	dsb();
+
+	debug_exit();
+}
+
+int init_iob(uintptr_t base)
+{
+	struct addr_map_win *win;
+	uint32_t win_id, win_reg;
+	uint32_t win_count;
+
+	INFO("Initializing IOB Address decoding\n");
+
+	/* Get the base address of the address decoding MBUS */
+	iob_base = base + MVEBU_IOB_OFFSET;
+
+	/* Get the array of the windows and fill the map data */
+	marvell_get_iob_memory_map(&win, &win_count, base);
+	if (win_count <= 0) {
+		INFO("no windows configurations found\n");
+		return 0;
+	} else if (win_count > (MVEBU_IOB_MAX_WINS - 1)) {
+		ERROR("IOB mem map array > than max available windows (%d)\n",
+		      MVEBU_IOB_MAX_WINS);
+		win_count = MVEBU_IOB_MAX_WINS;
+	}
+
+	/* disable all IOB windows, start from win_id = 1
+	 * because can't disable internal register window
+	 */
+	for (win_id = 1; win_id < MVEBU_IOB_MAX_WINS; win_id++) {
+		win_reg = mmio_read_32(IOB_WIN_CR_OFFSET(win_id));
+		win_reg &= ~WIN_ENABLE_BIT;
+		mmio_write_32(IOB_WIN_CR_OFFSET(win_id), win_reg);
+
+		win_reg = ~IOB_WIN_ENA_CTRL_WRITE_SECURE;
+		win_reg &= ~IOB_WIN_ENA_CTRL_READ_SECURE;
+		win_reg &= ~IOB_WIN_ENA_WRITE_SECURE;
+		win_reg &= ~IOB_WIN_ENA_READ_SECURE;
+		mmio_write_32(IOB_WIN_SCR_OFFSET(win_id), win_reg);
+	}
+
+	for (win_id = 1; win_id < win_count + 1; win_id++, win++) {
+		iob_win_check(win, win_id);
+		iob_enable_win(win, win_id);
+	}
+
+#ifdef DEBUG_ADDR_MAP
+	dump_iob();
+#endif
+
+	INFO("Done IOB Address decoding Initializing\n");
+
+	return 0;
+}
diff --git a/drivers/marvell/mc_trustzone/mc_trustzone.c b/drivers/marvell/mc_trustzone/mc_trustzone.c
new file mode 100644
index 0000000..52b3006
--- /dev/null
+++ b/drivers/marvell/mc_trustzone/mc_trustzone.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/marvell/addr_map.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#include "mc_trustzone.h"
+
+#define TZ_SIZE(x)		((x) >> 13)
+
+static int fls(int x)
+{
+	if (!x)
+		return 0;
+
+	return 32 - __builtin_clz(x);
+}
+
+/* To not duplicate types, the addr_map_win is used, but the "target"
+ * filed is referring to attributes instead of "target".
+ */
+void tz_enable_win(int ap_index, const struct addr_map_win *win, int win_id)
+{
+	int tz_size;
+	uint32_t val, base = win->base_addr;
+
+	if ((win_id < 0) || (win_id > MVEBU_TZ_MAX_WINS)) {
+		ERROR("Enabling wrong MC TrustZone window %d!\n", win_id);
+		return;
+	}
+
+	/* map the window size to trustzone register convention */
+	tz_size = fls(TZ_SIZE(win->win_size));
+
+	VERBOSE("%s: window size = 0x%llx maps to tz_size %d\n",
+		__func__, win->win_size, tz_size);
+	if (tz_size < 0 || tz_size > 31) {
+		ERROR("Using not allowed size for MC TrustZone window %d!\n",
+		      win_id);
+		return;
+	}
+
+	if (base & 0xfff) {
+		base = base & ~0xfff;
+		WARN("Attempt to open MC TZ win. at 0x%llx, truncate to 0x%x\n",
+		     win->base_addr, base);
+	}
+
+	val = base | (tz_size << 7) | win->target_id | TZ_VALID;
+
+	VERBOSE("%s: base 0x%x, tz_size moved 0x%x, attr 0x%x, val 0x%x\n",
+		__func__, base, (tz_size << 7), win->target_id, val);
+
+	mmio_write_32(MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap_index, win_id), val);
+
+	VERBOSE("%s: Win%d[0x%x] configured to 0x%x\n", __func__, win_id,
+		MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap_index, win_id),
+		mmio_read_32(MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap_index, win_id)));
+
+	mmio_write_32(MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap_index, win_id),
+		     (win->base_addr >> 32));
+
+	VERBOSE("%s: Win%d[0x%x] configured to 0x%x\n", __func__, win_id,
+		MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap_index, win_id),
+		mmio_read_32(MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap_index, win_id)));
+}
diff --git a/drivers/marvell/mc_trustzone/mc_trustzone.h b/drivers/marvell/mc_trustzone/mc_trustzone.h
new file mode 100644
index 0000000..296dce8
--- /dev/null
+++ b/drivers/marvell/mc_trustzone/mc_trustzone.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MC_TRUSTZONE_H
+#define MC_TRUSTZONE_H
+
+#include <drivers/marvell/addr_map.h>
+
+#define MVEBU_TZ_MAX_WINS	16
+
+#define TZ_VALID		(1 << 0)
+#define TZ_PERM(x)		((x) << 1)
+#define TZ_RZ_ENABLE		(1 << 3)
+
+/* tz attr definitions */
+#define TZ_PERM_RW		(TZ_PERM(0))
+#define TZ_PERM_RO		(TZ_PERM(1))
+#define TZ_PERM_WO		(TZ_PERM(2))
+#define TZ_PERM_ABORT		(TZ_PERM(3))
+
+void tz_enable_win(int ap_index, const struct addr_map_win *win, int win_id);
+
+#endif /* MC_TRUSTZONE_H */
diff --git a/drivers/marvell/mci.c b/drivers/marvell/mci.c
new file mode 100644
index 0000000..06fe88e
--- /dev/null
+++ b/drivers/marvell/mci.c
@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* MCI bus driver for Marvell ARMADA 8K and 8K+ SoCs */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/mci.h>
+#include <lib/mmio.h>
+
+#include <mvebu.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+/* /HB /Units /Direct_regs /Direct regs
+ * /Configuration Register Write/Read Data Register
+ */
+#define MCI_WRITE_READ_DATA_REG(mci_index)	\
+					MVEBU_MCI_REG_BASE_REMAP(mci_index)
+/* /HB /Units /Direct_regs /Direct regs
+ * /Configuration Register Access Command Register
+ */
+#define MCI_ACCESS_CMD_REG(mci_index)		\
+				(MVEBU_MCI_REG_BASE_REMAP(mci_index) + 0x4)
+
+/* Access Command fields :
+ * bit[3:0]   - Sub command: 1 => Peripheral Config Register Read,
+ *			     0 => Peripheral Config Register Write,
+ *			     2 => Peripheral Assign ID request,
+ *			     3 => Circular Config Write
+ * bit[5]     - 1 => Local (same chip access) 0 => Remote
+ * bit[15:8]  - Destination hop ID. Put Global ID (GID) here (see scheme below).
+ * bit[23:22] - 0x3 IHB PHY REG address space, 0x0 IHB Controller space
+ * bit[21:16] - Low 6 bits of offset. Hight 2 bits are taken from bit[28:27]
+ *		of IHB_PHY_CTRL
+ *		(must be set before any PHY register access occurs):
+ *		/IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ *		/IHB Version Control Register
+ *
+ *		ixi_ihb_top		IHB PHY
+ *  AXI -----------------------------   -------------
+ *   <--| axi_hb_top | ihb_pipe_top |-->|           |
+ *   -->|   GID=1    |     GID=0    |<--|           |
+ *      -----------------------------   -------------
+ */
+#define MCI_INDIRECT_CTRL_READ_CMD		0x1
+#define MCI_INDIRECT_CTRL_ASSIGN_CMD		0x2
+#define MCI_INDIRECT_CTRL_CIRCULAR_CMD		0x3
+#define MCI_INDIRECT_CTRL_LOCAL_PKT		(1 << 5)
+#define MCI_INDIRECT_CTRL_CMD_DONE_OFFSET	6
+#define MCI_INDIRECT_CTRL_CMD_DONE		\
+				(1 << MCI_INDIRECT_CTRL_CMD_DONE_OFFSET)
+#define MCI_INDIRECT_CTRL_DATA_READY_OFFSET	7
+#define MCI_INDIRECT_CTRL_DATA_READY		\
+				(1 << MCI_INDIRECT_CTRL_DATA_READY_OFFSET)
+#define MCI_INDIRECT_CTRL_HOPID_OFFSET		8
+#define MCI_INDIRECT_CTRL_HOPID(id)		\
+			(((id) & 0xFF) << MCI_INDIRECT_CTRL_HOPID_OFFSET)
+#define MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET	16
+#define MCI_INDIRECT_REG_CTRL_ADDR(reg_num)	\
+			(reg_num << MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET)
+
+/* Hop ID values */
+#define GID_IHB_PIPE					0
+#define GID_AXI_HB					1
+#define GID_IHB_EXT					2
+
+#define MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG		0x2
+/* Target MCi Local ID (LID, which is = self DID) */
+#define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(val)	(((val) & 0xFF) << 16)
+/* Bits [15:8]: Number of MCis on chip of target MCi */
+#define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(val)	(((val) & 0xFF) << 8)
+/* Bits [7:0]: Number of hops on chip of target MCi */
+#define MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(val)		(((val) & 0xFF) << 0)
+
+/* IHB_REG domain registers */
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/
+ * Rx Memory Configuration Register (RX_MEM_CFG)
+ */
+#define MCI_CTRL_RX_MEM_CFG_REG_NUM			0x0
+#define MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(val)		(((val) & 0xFF) << 24)
+#define MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(val)		(((val) & 0xFF) << 16)
+#define MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(val)		(((val) & 0xFF) << 8)
+#define MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(val)	(((val) & 0xF) << 4)
+#define MCI_CTRL_RX_TX_MEM_CFG_RTC(val)			(((val) & 0x3) << 2)
+#define MCI_CTRL_RX_TX_MEM_CFG_WTC(val)			(((val) & 0x3) << 0)
+#define MCI_CTRL_RX_MEM_CFG_REG_DEF_CP_VAL		\
+				(MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x07) | \
+				MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x3f) | \
+				MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x3f) | \
+				MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(0xf) | \
+				MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \
+				MCI_CTRL_RX_TX_MEM_CFG_WTC(1))
+
+#define MCI_CTRL_RX_MEM_CFG_REG_DEF_AP_VAL		\
+				(MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x3f) | \
+				MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x03) | \
+				MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x3f) | \
+				MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(0xf) | \
+				MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \
+				MCI_CTRL_RX_TX_MEM_CFG_WTC(1))
+
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/
+ * Tx Memory Configuration Register (TX_MEM_CFG)
+ */
+#define MCI_CTRL_TX_MEM_CFG_REG_NUM			0x1
+/* field mapping for TX mem config register
+ * are the same as for RX register - see register above
+ */
+#define MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL			\
+				(MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x20) | \
+				MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x20) | \
+				MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x20) | \
+				MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(2) | \
+				MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \
+				MCI_CTRL_RX_TX_MEM_CFG_WTC(1))
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Link CRC Control
+ */
+/* MCi Link CRC Control Register (MCi_CRC_CTRL) */
+#define MCI_LINK_CRC_CTRL_REG_NUM			0x4
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Status Register
+ */
+/* MCi Status Register (MCi_STS) */
+#define MCI_CTRL_STATUS_REG_NUM				0x5
+#define MCI_CTRL_STATUS_REG_PHY_READY			(1 << 12)
+#define MCI_CTRL_STATUS_REG_LINK_PRESENT		(1 << 15)
+#define MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET		24
+#define MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK		\
+				(0xF << MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET)
+/* Expected successful Link result, including reserved bit */
+#define MCI_CTRL_PHY_READY		(MCI_CTRL_STATUS_REG_PHY_READY | \
+					MCI_CTRL_STATUS_REG_LINK_PRESENT | \
+					MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK)
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/
+ * MCi PHY Speed Settings Register (MCi_PHY_SETTING)
+ */
+#define MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM		0x8
+#define MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(val)	(((val) & 0xF) << 28)
+#define MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(val)		(((val) & 0xF) << 12)
+#define MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(val)		(((val) & 0xF) << 8)
+#define MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(val)	(((val) & 0xF) << 4)
+#define MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(val)		(((val) & 0x1) << 1)
+#define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL		\
+			(MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \
+			MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \
+			MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x2) | \
+			MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1))
+#define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2		\
+			(MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \
+			MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \
+			MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x5) | \
+			MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1))
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Mode Config
+ */
+#define MCI_CTRL_IHB_MODE_CFG_REG_NUM			0x25
+#define MCI_CTRL_IHB_MODE_HBCLK_DIV(val)		((val) & 0xFF)
+#define MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET		8
+#define MCI_CTRL_IHB_MODE_CHUNK_MOD			\
+				(1 << MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET)
+#define MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET		9
+#define MCI_CTRL_IHB_MODE_FWD_MOD			\
+				(1 << MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET)
+#define MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(val)		(((val) & 0xF) << 12)
+#define MCI_CTRL_IHB_MODE_RX_COMB_THRESH(val)		(((val) & 0xFF) << 16)
+#define MCI_CTRL_IHB_MODE_TX_COMB_THRESH(val)		(((val) & 0xFF) << 24)
+
+#define MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL		\
+				(MCI_CTRL_IHB_MODE_HBCLK_DIV(6) | \
+				MCI_CTRL_IHB_MODE_FWD_MOD | \
+				MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(0xF) | \
+				MCI_CTRL_IHB_MODE_RX_COMB_THRESH(0x3f) | \
+				MCI_CTRL_IHB_MODE_TX_COMB_THRESH(0x40))
+/* AXI_HB registers */
+#define MCI_AXI_ACCESS_DATA_REG_NUM			0x0
+#define MCI_AXI_ACCESS_PCIE_MODE			1
+#define MCI_AXI_ACCESS_CACHE_CHECK_OFFSET		5
+#define MCI_AXI_ACCESS_CACHE_CHECK			\
+				(1 << MCI_AXI_ACCESS_CACHE_CHECK_OFFSET)
+#define MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET		6
+#define MCI_AXI_ACCESS_FORCE_POST_WR			\
+				(1 << MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET)
+#define MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET	9
+#define MCI_AXI_ACCESS_DISABLE_CLK_GATING		\
+				(1 << MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET)
+
+/* /HB /Units /HB_REG /HB_REGHopping Bus Registers
+ * /Window 0 Address Mask Register
+ */
+#define MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM		0x2
+
+/* /HB /Units /HB_REG /HB_REGHopping Bus Registers
+ * /Window 0 Destination Register
+ */
+#define MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM		0x3
+#define MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(val)		(((val) & 0x1) << 16)
+#define MCI_HB_CTRL_WIN0_DEST_ID(val)			(((val) & 0xFF) << 0)
+
+/* /HB /Units /HB_REG /HB_REGHopping Bus Registers /Tx Control Register */
+#define MCI_HB_CTRL_TX_CTRL_REG_NUM			0xD
+#define MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET		24
+#define MCI_HB_CTRL_TX_CTRL_PCIE_MODE			\
+				(1 << MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET)
+#define MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(val)		(((val) & 0xF) << 12)
+#define MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(val)		(((val) & 0x1F) << 6)
+#define MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(val)		(((val) & 0x1F) << 0)
+
+/* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers
+ * /IHB Version Control Register
+ */
+#define MCI_PHY_CTRL_REG_NUM				0x7
+#define MCI_PHY_CTRL_MCI_MINOR				0x8 /* BITS [3:0] */
+#define MCI_PHY_CTRL_MCI_MAJOR_OFFSET			4
+#define MCI_PHY_CTRL_MCI_MAJOR				\
+				(1 << MCI_PHY_CTRL_MCI_MAJOR_OFFSET)
+#define MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET		11
+#define MCI_PHY_CTRL_MCI_SLEEP_REQ			\
+				(1 << MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET)
+/* Host=1 / Device=0 PHY mode */
+#define MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET		24
+#define MCI_PHY_CTRL_MCI_PHY_MODE_HOST			\
+				(1 << MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET)
+/* Register=1 / PWM=0 interface */
+#define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET		25
+#define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE		\
+				(1 << MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET)
+ /* PHY code InReset=1 */
+#define MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET		26
+#define MCI_PHY_CTRL_MCI_PHY_RESET_CORE			\
+				(1 << MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET)
+#define MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET		27
+#define MCI_PHY_CTRL_PHY_ADDR_MSB(addr)			\
+				(((addr) & 0x3) << \
+				MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET)
+#define MCI_PHY_CTRL_PIDI_MODE_OFFSET			31
+#define MCI_PHY_CTRL_PIDI_MODE				\
+				(1U << MCI_PHY_CTRL_PIDI_MODE_OFFSET)
+
+/* Number of times to wait for the MCI link ready after MCI configurations
+ * Normally takes 34-35 successive reads
+ */
+#define LINK_READY_TIMEOUT				100
+
+enum mci_register_type {
+	MCI_REG_TYPE_PHY = 0,
+	MCI_REG_TYPE_CTRL,
+};
+
+enum {
+	MCI_CMD_WRITE,
+	MCI_CMD_READ
+};
+
+/* Write wrapper callback for debug:
+ * will print written data in case LOG_LEVEL >= 40
+ */
+static void mci_mmio_write_32(uintptr_t addr, uint32_t value)
+{
+	VERBOSE("Write:\t0x%x = 0x%x\n", (uint32_t)addr, value);
+	mmio_write_32(addr, value);
+}
+/* Read wrapper callback for debug:
+ * will print read data in case LOG_LEVEL >= 40
+ */
+static uint32_t mci_mmio_read_32(uintptr_t addr)
+{
+	uint32_t value;
+
+	value = mmio_read_32(addr);
+	VERBOSE("Read:\t0x%x = 0x%x\n", (uint32_t)addr, value);
+	return value;
+}
+
+/* MCI indirect access command completion polling:
+ * Each write/read command done via MCI indirect registers must be polled
+ * for command completions status.
+ *
+ * Returns 1 in case of error
+ * Returns 0 in case of command completed successfully.
+ */
+static int mci_poll_command_completion(int mci_index, int command_type)
+{
+	uint32_t mci_cmd_value = 0, retry_count = 100, ret = 0;
+	uint32_t completion_flags = MCI_INDIRECT_CTRL_CMD_DONE;
+
+	debug_enter();
+	/* Read commands require validating that requested data is ready */
+	if (command_type == MCI_CMD_READ)
+		completion_flags |= MCI_INDIRECT_CTRL_DATA_READY;
+
+	do {
+		/* wait 1 ms before each polling */
+		mdelay(1);
+		mci_cmd_value = mci_mmio_read_32(MCI_ACCESS_CMD_REG(mci_index));
+	} while (((mci_cmd_value & completion_flags) != completion_flags) &&
+			 (retry_count-- > 0));
+
+	if (retry_count == 0) {
+		ERROR("%s: MCI command timeout (command status = 0x%x)\n",
+		      __func__, mci_cmd_value);
+		ret = 1;
+	}
+
+	debug_exit();
+	return ret;
+}
+
+int mci_read(int mci_idx, uint32_t cmd, uint32_t *value)
+{
+	int rval;
+
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_idx), cmd);
+
+	rval = mci_poll_command_completion(mci_idx, MCI_CMD_READ);
+
+	*value = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_idx));
+
+	return rval;
+}
+
+int  mci_write(int mci_idx, uint32_t cmd, uint32_t data)
+{
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_idx), data);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_idx), cmd);
+
+	return mci_poll_command_completion(mci_idx, MCI_CMD_WRITE);
+}
+
+/* Perform 3 configurations in one command: PCI mode,
+ * queues separation and cache bit
+ */
+static int mci_axi_set_pcie_mode(int mci_index)
+{
+	uint32_t reg_data, ret = 1;
+
+	debug_enter();
+	/* This configuration makes MCI IP behave consistently with AXI protocol
+	 * It should be configured at one side only (for example locally at AP).
+	 * The IP takes care of performing the same configurations at MCI on
+	 * another side (for example remotely at CP).
+	 */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_AXI_ACCESS_PCIE_MODE |
+			  MCI_AXI_ACCESS_CACHE_CHECK |
+			  MCI_AXI_ACCESS_FORCE_POST_WR |
+			  MCI_AXI_ACCESS_DISABLE_CLK_GATING);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_AXI_ACCESS_DATA_REG_NUM)  |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT |
+			  MCI_INDIRECT_CTRL_CIRCULAR_CMD);
+
+	/* if Write command was successful, verify PCIe mode */
+	if (mci_poll_command_completion(mci_index, MCI_CMD_WRITE) == 0) {
+		/* Verify the PCIe mode selected */
+		mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+				  MCI_INDIRECT_REG_CTRL_ADDR(
+					MCI_HB_CTRL_TX_CTRL_REG_NUM)  |
+				  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+				  MCI_INDIRECT_CTRL_LOCAL_PKT |
+				  MCI_INDIRECT_CTRL_READ_CMD);
+		/* if read was completed, verify PCIe mode */
+		if (mci_poll_command_completion(mci_index, MCI_CMD_READ) == 0) {
+			reg_data = mci_mmio_read_32(
+					MCI_WRITE_READ_DATA_REG(mci_index));
+			if (reg_data & MCI_HB_CTRL_TX_CTRL_PCIE_MODE)
+				ret = 0;
+		}
+	}
+
+	debug_exit();
+	return ret;
+}
+
+/* Reduce sequence FIFO timer expiration threshold */
+static int mci_axi_set_fifo_thresh(int mci_index)
+{
+	uint32_t reg_data, ret = 0;
+
+	debug_enter();
+	/* This configuration reduces sequence FIFO timer expiration threshold
+	 * (to 0x7 instead of 0xA).
+	 * In MCI 1.6 version this configuration prevents possible functional
+	 * issues.
+	 * In version 1.82 the configuration prevents performance degradation
+	 */
+
+	/* Configure local AP side */
+	reg_data = MCI_PHY_CTRL_PIDI_MODE |
+		   MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE |
+		   MCI_PHY_CTRL_MCI_PHY_MODE_HOST |
+		   MCI_PHY_CTRL_MCI_MAJOR |
+		   MCI_PHY_CTRL_MCI_MINOR;
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Reduce the threshold */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL);
+
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_IHB_MODE_CFG_REG_NUM) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Exit PIDI mode */
+	reg_data = MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE |
+		   MCI_PHY_CTRL_MCI_PHY_MODE_HOST |
+		   MCI_PHY_CTRL_MCI_MAJOR |
+		   MCI_PHY_CTRL_MCI_MINOR;
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Configure remote CP side */
+	reg_data = MCI_PHY_CTRL_PIDI_MODE |
+		   MCI_PHY_CTRL_MCI_MAJOR |
+		   MCI_PHY_CTRL_MCI_MINOR |
+		   MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE;
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+			  MCI_CTRL_IHB_MODE_FWD_MOD);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Reduce the threshold */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_IHB_MODE_CFG_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Exit PIDI mode */
+	reg_data = MCI_PHY_CTRL_MCI_MAJOR |
+		   MCI_PHY_CTRL_MCI_MINOR |
+		   MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE;
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+			  MCI_CTRL_IHB_MODE_FWD_MOD);
+
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	debug_exit();
+	return ret;
+}
+
+/* Configure:
+ * 1. AP & CP TX thresholds and delta configurations
+ * 2. DLO & DLI FIFO full threshold
+ * 3. RX thresholds and delta configurations
+ * 4. CP AR and AW outstanding
+ * 5. AP AR and AW outstanding
+ */
+static int mci_axi_set_fifo_rx_tx_thresh(int mci_index)
+{
+	uint32_t ret = 0;
+
+	debug_enter();
+	/* AP TX thresholds and delta configurations (IHB_reg 0x1) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_TX_MEM_CFG_REG_NUM) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* CP TX thresholds and delta configurations (IHB_reg 0x1) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_TX_MEM_CFG_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* AP DLO & DLI FIFO full threshold & Auto-Link enable (IHB_reg 0x8) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL |
+			  MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1));
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* CP DLO & DLI FIFO full threshold (IHB_reg 0x8) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* AP RX thresholds and delta configurations (IHB_reg 0x0) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_RX_MEM_CFG_REG_DEF_AP_VAL);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_RX_MEM_CFG_REG_NUM) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* CP RX thresholds and delta configurations (IHB_reg 0x0) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_CTRL_RX_MEM_CFG_REG_DEF_CP_VAL);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_CTRL_RX_MEM_CFG_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* AP AR & AW maximum AXI outstanding request cfg (HB_reg 0xd) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) |
+			  MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(3) |
+			  MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(3));
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_TX_CTRL_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* CP AR & AW maximum AXI outstanding request cfg (HB_reg 0xd) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index),
+			  MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) |
+			  MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(0xB) |
+			  MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(0x11));
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_TX_CTRL_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	debug_exit();
+	return ret;
+}
+
+/* configure MCI to allow read & write transactions to arrive at the same time.
+ * Without the below configuration, MCI won't sent response to CPU for
+ * transactions which arrived simultaneously and will lead to CPU hang.
+ * The below will configure MCI to be able to pass transactions from/to CP/AP.
+ */
+static int mci_enable_simultaneous_transactions(int mci_index)
+{
+	uint32_t ret = 0;
+
+	debug_enter();
+	/* ID assignment (assigning global ID offset to CP) */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0),
+			  MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(2) |
+			  MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(2) |
+			  MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(2));
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG) |
+			  MCI_INDIRECT_CTRL_ASSIGN_CMD);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Assigning dest. ID=3 to all transactions entering from AXI at AP */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0),
+			  MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) |
+			  MCI_HB_CTRL_WIN0_DEST_ID(3));
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* Assigning dest. ID=1 to all transactions entering from AXI at CP */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0),
+			  MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) |
+			  MCI_HB_CTRL_WIN0_DEST_ID(1));
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* End address to all transactions entering from AXI at AP.
+	 * This will lead to get match for any AXI address
+	 * and receive destination ID=3
+	 */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT);
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	/* End address to all transactions entering from AXI at CP.
+	 * This will lead to get match for any AXI address
+	 * and receive destination ID=1
+	 */
+	mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff);
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB));
+	ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE);
+
+	debug_exit();
+	return ret;
+}
+
+/* Check if MCI simultaneous transaction was already enabled.
+ * Currently bootrom does this mci configuration only when the boot source is
+ * SAR_MCIX4, in other cases it should be done at this stage.
+ * It is worth noticing that in case of booting from uart, the bootrom
+ * flow is different and this mci initialization is skipped even if boot
+ * source is SAR_MCIX4. Therefore new verification bases on appropriate mci's
+ * register content: if the appropriate reg contains 0x0 it means that the
+ * bootrom didn't perform required mci configuration.
+ *
+ * Returns:
+ * 0 - configuration already done
+ * 1 - configuration missing
+ */
+static _Bool mci_simulatenous_trans_missing(int mci_index)
+{
+	uint32_t reg, ret;
+
+	/* read 'Window 0 Destination ID assignment' from HB register 0x3
+	 * (TX_CFG_W0_DST_ID) to check whether ID assignment was already
+	 * performed by BootROM.
+	 */
+	debug_enter();
+	mci_mmio_write_32(MCI_ACCESS_CMD_REG(0),
+			  MCI_INDIRECT_REG_CTRL_ADDR(
+				MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) |
+			  MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) |
+			  MCI_INDIRECT_CTRL_LOCAL_PKT |
+			  MCI_INDIRECT_CTRL_READ_CMD);
+	ret = mci_poll_command_completion(mci_index, MCI_CMD_READ);
+
+	reg = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_index));
+
+	if (ret)
+		ERROR("Failed to verify MCI simultaneous read/write status\n");
+
+	debug_exit();
+	/* default ID assignment is 0, so if register doesn't contain zeros
+	 * it means that bootrom already performed required configuration.
+	 */
+	if (reg != 0)
+		return 0;
+
+	return 1;
+}
+
+/* For A1 revision, configure the MCI link for performance improvement:
+ * - set MCI to support read/write transactions to arrive at the same time
+ * - Switch AXI to PCIe mode
+ * - Reduce sequence FIFO threshold
+ * - Configure RX/TX FIFO thresholds
+ *
+ *   Note:
+ *   We don't exit on error code from any sub routine, to try (best effort) to
+ *   complete the MCI configuration.
+ *   (If we exit - Bootloader will surely fail to boot)
+ */
+int mci_configure(int mci_index)
+{
+	int rval;
+
+	debug_enter();
+	/* According to design guidelines the MCI simultaneous transaction
+	 * shouldn't be enabled more then once - therefore make sure that it
+	 * wasn't already enabled in bootrom.
+	 */
+	if (mci_simulatenous_trans_missing(mci_index)) {
+		VERBOSE("Enabling MCI simultaneous transaction\n");
+		/* set MCI to support read/write transactions
+		 * to arrive at the same time
+		 */
+		rval = mci_enable_simultaneous_transactions(mci_index);
+		if (rval)
+			ERROR("Failed to set MCI simultaneous read/write\n");
+	} else
+		VERBOSE("Skip MCI ID assignment - already done by bootrom\n");
+
+	/* Configure MCI for more consistent behavior with AXI protocol */
+	rval = mci_axi_set_pcie_mode(mci_index);
+	if (rval)
+		ERROR("Failed to set MCI to AXI PCIe mode\n");
+
+	/* reduce FIFO global threshold */
+	rval = mci_axi_set_fifo_thresh(mci_index);
+	if (rval)
+		ERROR("Failed to set MCI FIFO global threshold\n");
+
+	/* configure RX/TX FIFO thresholds */
+	rval = mci_axi_set_fifo_rx_tx_thresh(mci_index);
+	if (rval)
+		ERROR("Failed to set MCI RX/TX FIFO threshold\n");
+
+	debug_exit();
+	return 1;
+}
+
+int mci_get_link_status(void)
+{
+	uint32_t cmd, data;
+
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_STATUS_REG_NUM) |
+		MCI_INDIRECT_CTRL_LOCAL_PKT | MCI_INDIRECT_CTRL_READ_CMD);
+	if (mci_read(0, cmd, &data)) {
+		ERROR("Failed to read status register\n");
+		return -1;
+	}
+
+	/* Check if the link is ready */
+	if (data != MCI_CTRL_PHY_READY) {
+		ERROR("Bad link status %x\n", data);
+		return -1;
+	}
+
+	return 0;
+}
+
+void mci_turn_link_down(void)
+{
+	uint32_t cmd, data;
+	int rval = 0;
+
+	debug_enter();
+
+	/* Turn off auto-link */
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+			MCI_INDIRECT_CTRL_LOCAL_PKT);
+	data = (MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 |
+		MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(0));
+	rval = mci_write(0, cmd, data);
+	if (rval)
+		ERROR("Failed to turn off auto-link\n");
+
+	/* Reset AP PHY */
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+		MCI_INDIRECT_CTRL_LOCAL_PKT);
+	data = (MCI_PHY_CTRL_MCI_MINOR |
+		MCI_PHY_CTRL_MCI_MAJOR |
+		MCI_PHY_CTRL_MCI_PHY_MODE_HOST |
+		MCI_PHY_CTRL_MCI_PHY_RESET_CORE);
+	rval = mci_write(0, cmd, data);
+	if (rval)
+		ERROR("Failed to reset AP PHY\n");
+
+	/* Clear all status & CRC values */
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_LINK_CRC_CTRL_REG_NUM) |
+	       MCI_INDIRECT_CTRL_LOCAL_PKT);
+	data = 0x0;
+	mci_write(0, cmd, data);
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_STATUS_REG_NUM) |
+	       MCI_INDIRECT_CTRL_LOCAL_PKT);
+	data = 0x0;
+	rval = mci_write(0, cmd, data);
+	if (rval)
+		ERROR("Failed to reset AP PHY\n");
+
+	/* Wait 5ms before un-reset the PHY */
+	mdelay(5);
+
+	/* Un-reset AP PHY */
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) |
+	       MCI_INDIRECT_CTRL_LOCAL_PKT);
+	data = (MCI_PHY_CTRL_MCI_MINOR | MCI_PHY_CTRL_MCI_MAJOR |
+		MCI_PHY_CTRL_MCI_PHY_MODE_HOST);
+	rval = mci_write(0, cmd, data);
+	if (rval)
+		ERROR("Failed to un-reset AP PHY\n");
+
+	debug_exit();
+}
+
+void mci_turn_link_on(void)
+{
+	uint32_t cmd, data;
+	int rval = 0;
+
+	debug_enter();
+	/* Turn on auto-link */
+	cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) |
+			MCI_INDIRECT_CTRL_LOCAL_PKT);
+	data = (MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 |
+		MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1));
+	rval = mci_write(0, cmd, data);
+	if (rval)
+		ERROR("Failed to turn on auto-link\n");
+
+	debug_exit();
+}
+
+/* Initialize MCI for performance improvements */
+int mci_initialize(int mci_index)
+{
+	int ret;
+
+	debug_enter();
+	INFO("MCI%d initialization:\n", mci_index);
+
+	ret = mci_configure(mci_index);
+
+	debug_exit();
+	return ret;
+}
diff --git a/drivers/marvell/mochi/ap807_setup.c b/drivers/marvell/mochi/ap807_setup.c
new file mode 100644
index 0000000..864c923
--- /dev/null
+++ b/drivers/marvell/mochi/ap807_setup.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP807 Marvell SoC driver */
+
+#include <common/debug.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/mci.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#define SMMU_sACR				(MVEBU_SMMU_BASE + 0x10)
+#define SMMU_sACR_PG_64K			(1 << 16)
+
+#define CCU_GSPMU_CR				(MVEBU_CCU_BASE(MVEBU_AP0) \
+								+ 0x3F0)
+#define GSPMU_CPU_CONTROL			(0x1 << 0)
+
+#define CCU_HTC_CR				(MVEBU_CCU_BASE(MVEBU_AP0) \
+								+ 0x200)
+#define CCU_SET_POC_OFFSET			5
+
+#define DSS_CR0					(MVEBU_RFU_BASE + 0x100)
+#define DVM_48BIT_VA_ENABLE			(1 << 21)
+
+/* Secure MoChi incoming access */
+#define SEC_MOCHI_IN_ACC_REG			(MVEBU_RFU_BASE + 0x4738)
+#define SEC_MOCHI_IN_ACC_IHB0_EN		(1)
+#define SEC_MOCHI_IN_ACC_IHB1_EN		(1 << 3)
+#define SEC_MOCHI_IN_ACC_IHB2_EN		(1 << 6)
+#define SEC_MOCHI_IN_ACC_PIDI_EN		(1 << 9)
+#define SEC_IN_ACCESS_ENA_ALL_MASTERS		(SEC_MOCHI_IN_ACC_IHB0_EN | \
+						 SEC_MOCHI_IN_ACC_IHB1_EN | \
+						 SEC_MOCHI_IN_ACC_IHB2_EN | \
+						 SEC_MOCHI_IN_ACC_PIDI_EN)
+
+/* SYSRST_OUTn Config definitions */
+#define MVEBU_SYSRST_OUT_CONFIG_REG		(MVEBU_MISC_SOC_BASE + 0x4)
+#define WD_MASK_SYS_RST_OUT			(1 << 2)
+
+/* DSS PHY for DRAM */
+#define DSS_SCR_REG				(MVEBU_RFU_BASE + 0x208)
+#define DSS_PPROT_OFFS				4
+#define DSS_PPROT_MASK				0x7
+#define DSS_PPROT_PRIV_SECURE_DATA		0x1
+
+/* Used for Units of AP-807 (e.g. SDIO and etc) */
+#define MVEBU_AXI_ATTR_BASE			(MVEBU_REGS_BASE + 0x6F4580)
+#define MVEBU_AXI_ATTR_REG(index)		(MVEBU_AXI_ATTR_BASE + \
+							0x4 * index)
+
+enum axi_attr {
+	AXI_SDIO_ATTR = 0,
+	AXI_DFX_ATTR,
+	AXI_MAX_ATTR,
+};
+
+static void ap_sec_masters_access_en(uint32_t enable)
+{
+	uint32_t reg;
+
+	/* Open/Close incoming access for all masters.
+	 * The access is disabled in trusted boot mode
+	 * Could only be done in EL3
+	 */
+	reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG);
+	if (enable)
+		mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg |
+			      SEC_IN_ACCESS_ENA_ALL_MASTERS);
+	else
+		mmio_write_32(SEC_MOCHI_IN_ACC_REG,
+			      reg & ~SEC_IN_ACCESS_ENA_ALL_MASTERS);
+}
+
+static void setup_smmu(void)
+{
+	uint32_t reg;
+
+	/* Set the SMMU page size to 64 KB */
+	reg = mmio_read_32(SMMU_sACR);
+	reg |= SMMU_sACR_PG_64K;
+	mmio_write_32(SMMU_sACR, reg);
+}
+
+static void init_aurora2(void)
+{
+	uint32_t reg;
+
+	/* Enable GSPMU control by CPU */
+	reg = mmio_read_32(CCU_GSPMU_CR);
+	reg |= GSPMU_CPU_CONTROL;
+	mmio_write_32(CCU_GSPMU_CR, reg);
+
+#if LLC_ENABLE
+	/* Enable LLC for AP807 in exclusive mode */
+	llc_enable(0, 1);
+
+	/* Set point of coherency to DDR.
+	 * This is required by units which have
+	 * SW cache coherency
+	 */
+	reg = mmio_read_32(CCU_HTC_CR);
+	reg |= (0x1 << CCU_SET_POC_OFFSET);
+	mmio_write_32(CCU_HTC_CR, reg);
+#endif /* LLC_ENABLE */
+}
+
+
+/* MCIx indirect access register are based by default at 0xf4000000/0xf6000000
+ * to avoid conflict of internal registers of units connected via MCIx, which
+ * can be based on the same address (i.e CP1 base is also 0xf4000000),
+ * the following routines remaps the MCIx indirect bases to another domain
+ */
+static void mci_remap_indirect_access_base(void)
+{
+	uint32_t mci;
+
+	for (mci = 0; mci < MCI_MAX_UNIT_ID; mci++)
+		mmio_write_32(MCIX4_REG_START_ADDRESS_REG(mci),
+				  MVEBU_MCI_REG_BASE_REMAP(mci) >>
+				  MCI_REMAP_OFF_SHIFT);
+}
+
+static void ap807_axi_attr_init(void)
+{
+	uint32_t index, data;
+
+	/* Initialize AXI attributes for AP807 */
+	/* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+	for (index = 0; index < AXI_MAX_ATTR; index++) {
+		switch (index) {
+		/* DFX works with no coherent only -
+		 * there's no option to configure the Ax-Cache and Ax-Domain
+		 */
+		case AXI_DFX_ATTR:
+			continue;
+		default:
+			/* Set Ax-Cache as cacheable, no allocate, modifiable,
+			 * bufferable.
+			 * The values are different because Read & Write
+			 * definition is different in Ax-Cache
+			 */
+			data = mmio_read_32(MVEBU_AXI_ATTR_REG(index));
+			data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+			data |= (CACHE_ATTR_WRITE_ALLOC |
+				 CACHE_ATTR_CACHEABLE   |
+				 CACHE_ATTR_BUFFERABLE) <<
+				 MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+			data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+			data |= (CACHE_ATTR_READ_ALLOC |
+				 CACHE_ATTR_CACHEABLE  |
+				 CACHE_ATTR_BUFFERABLE) <<
+				 MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+			/* Set Ax-Domain as Outer domain */
+			data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+			data |= DOMAIN_OUTER_SHAREABLE <<
+				MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+			data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+			data |= DOMAIN_OUTER_SHAREABLE <<
+				MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+			mmio_write_32(MVEBU_AXI_ATTR_REG(index), data);
+		}
+	}
+}
+
+static void misc_soc_configurations(void)
+{
+	uint32_t reg;
+
+	/* Enable 48-bit VA */
+	mmio_setbits_32(DSS_CR0, DVM_48BIT_VA_ENABLE);
+
+	/* Un-mask Watchdog reset from influencing the SYSRST_OUTn.
+	 * Otherwise, upon WD timeout, the WD reset signal won't trigger reset
+	 */
+	reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG);
+	reg &= ~(WD_MASK_SYS_RST_OUT);
+	mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg);
+}
+
+void ap_init(void)
+{
+	/* Setup Aurora2. */
+	init_aurora2();
+
+	/* configure MCI mapping */
+	mci_remap_indirect_access_base();
+
+	/* configure IO_WIN windows */
+	init_io_win(MVEBU_AP0);
+
+	/* configure CCU windows */
+	init_ccu(MVEBU_AP0);
+
+	/* configure the SMMU */
+	setup_smmu();
+
+	/* Open AP incoming access for all masters */
+	ap_sec_masters_access_en(1);
+
+	/* configure axi for AP */
+	ap807_axi_attr_init();
+
+	/* misc configuration of the SoC */
+	misc_soc_configurations();
+}
+
+static void ap807_dram_phy_access_config(void)
+{
+	uint32_t reg_val;
+	/* Update DSS port access permission to DSS_PHY */
+	reg_val = mmio_read_32(DSS_SCR_REG);
+	reg_val &= ~(DSS_PPROT_MASK << DSS_PPROT_OFFS);
+	reg_val |= ((DSS_PPROT_PRIV_SECURE_DATA & DSS_PPROT_MASK) <<
+		    DSS_PPROT_OFFS);
+	mmio_write_32(DSS_SCR_REG, reg_val);
+}
+
+void ap_ble_init(void)
+{
+	/* Enable DSS port */
+	ap807_dram_phy_access_config();
+}
+
+int ap_get_count(void)
+{
+	return 1;
+}
+
+
diff --git a/drivers/marvell/mochi/apn806_setup.c b/drivers/marvell/mochi/apn806_setup.c
new file mode 100644
index 0000000..1e91c43
--- /dev/null
+++ b/drivers/marvell/mochi/apn806_setup.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP806 Marvell SoC driver */
+
+#include <common/debug.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/mci.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#define SMMU_sACR				(MVEBU_SMMU_BASE + 0x10)
+#define SMMU_sACR_PG_64K			(1 << 16)
+
+#define CCU_GSPMU_CR				(MVEBU_CCU_BASE(MVEBU_AP0) + \
+							0x3F0)
+#define GSPMU_CPU_CONTROL			(0x1 << 0)
+
+#define CCU_HTC_CR				(MVEBU_CCU_BASE(MVEBU_AP0) + \
+							0x200)
+#define CCU_SET_POC_OFFSET			5
+
+#define CCU_RGF(win)				(MVEBU_CCU_BASE(MVEBU_AP0) + \
+							0x90 + 4 * (win))
+
+#define DSS_CR0					(MVEBU_RFU_BASE + 0x100)
+#define DVM_48BIT_VA_ENABLE			(1 << 21)
+
+/* Secure MoChi incoming access */
+#define SEC_MOCHI_IN_ACC_REG			(MVEBU_RFU_BASE + 0x4738)
+#define SEC_MOCHI_IN_ACC_IHB0_EN		(1)
+#define SEC_MOCHI_IN_ACC_IHB1_EN		(1 << 3)
+#define SEC_MOCHI_IN_ACC_IHB2_EN		(1 << 6)
+#define SEC_MOCHI_IN_ACC_PIDI_EN		(1 << 9)
+#define SEC_IN_ACCESS_ENA_ALL_MASTERS		(SEC_MOCHI_IN_ACC_IHB0_EN | \
+						 SEC_MOCHI_IN_ACC_IHB1_EN | \
+						 SEC_MOCHI_IN_ACC_IHB2_EN | \
+						 SEC_MOCHI_IN_ACC_PIDI_EN)
+
+/* SYSRST_OUTn Config definitions */
+#define MVEBU_SYSRST_OUT_CONFIG_REG		(MVEBU_MISC_SOC_BASE + 0x4)
+#define WD_MASK_SYS_RST_OUT			(1 << 2)
+
+/* Generic Timer System Controller */
+#define MVEBU_MSS_GTCR_REG			(MVEBU_REGS_BASE + 0x581000)
+#define MVEBU_MSS_GTCR_ENABLE_BIT		0x1
+
+/*
+ * AXI Configuration.
+ */
+
+/* Used for Units of AP-806 (e.g. SDIO and etc) */
+#define MVEBU_AXI_ATTR_BASE			(MVEBU_REGS_BASE + 0x6F4580)
+#define MVEBU_AXI_ATTR_REG(index)		(MVEBU_AXI_ATTR_BASE + \
+							0x4 * index)
+
+enum axi_attr {
+	AXI_SDIO_ATTR = 0,
+	AXI_DFX_ATTR,
+	AXI_MAX_ATTR,
+};
+
+static void apn_sec_masters_access_en(uint32_t enable)
+{
+	uint32_t reg;
+
+	/* Open/Close incoming access for all masters.
+	 * The access is disabled in trusted boot mode
+	 * Could only be done in EL3
+	 */
+	reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG);
+	if (enable)
+		mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg |
+			      SEC_IN_ACCESS_ENA_ALL_MASTERS);
+	else
+		mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg &
+			      ~SEC_IN_ACCESS_ENA_ALL_MASTERS);
+}
+
+static void setup_smmu(void)
+{
+	uint32_t reg;
+
+	/* Set the SMMU page size to 64 KB */
+	reg = mmio_read_32(SMMU_sACR);
+	reg |= SMMU_sACR_PG_64K;
+	mmio_write_32(SMMU_sACR, reg);
+}
+
+static void apn806_errata_wa_init(void)
+{
+	/*
+	 * ERRATA ID: RES-3033912 - Internal Address Space Init state causes
+	 * a hang upon accesses to [0xf070_0000, 0xf07f_ffff]
+	 * Workaround: Boot Firmware (ATF) should configure CCU_RGF_WIN(4) to
+	 * split [0x6e_0000, 0xff_ffff] to values [0x6e_0000, 0x6f_ffff] and
+	 * [0x80_0000, 0xff_ffff] that cause accesses to the
+	 * segment of [0xf070_0000, 0xf07f_ffff] to act as RAZWI.
+	 */
+	mmio_write_32(CCU_RGF(4), 0x37f9b809);
+	mmio_write_32(CCU_RGF(5), 0x7ffa0009);
+}
+
+static void init_aurora2(void)
+{
+	uint32_t reg;
+
+	/* Enable GSPMU control by CPU */
+	reg = mmio_read_32(CCU_GSPMU_CR);
+	reg |= GSPMU_CPU_CONTROL;
+	mmio_write_32(CCU_GSPMU_CR, reg);
+
+#if LLC_ENABLE
+	/* Enable LLC for AP806 in exclusive mode */
+	llc_enable(0, 1);
+
+	/* Set point of coherency to DDR.
+	 * This is required by units which have
+	 * SW cache coherency
+	 */
+	reg = mmio_read_32(CCU_HTC_CR);
+	reg |= (0x1 << CCU_SET_POC_OFFSET);
+	mmio_write_32(CCU_HTC_CR, reg);
+#endif /* LLC_ENABLE */
+
+	apn806_errata_wa_init();
+}
+
+
+/* MCIx indirect access register are based by default at 0xf4000000/0xf6000000
+ * to avoid conflict of internal registers of units connected via MCIx, which
+ * can be based on the same address (i.e CP1 base is also 0xf4000000),
+ * the following routines remaps the MCIx indirect bases to another domain
+ */
+static void mci_remap_indirect_access_base(void)
+{
+	uint32_t mci;
+
+	for (mci = 0; mci < MCI_MAX_UNIT_ID; mci++)
+		mmio_write_32(MCIX4_REG_START_ADDRESS_REG(mci),
+			      MVEBU_MCI_REG_BASE_REMAP(mci) >>
+			      MCI_REMAP_OFF_SHIFT);
+}
+
+static void apn806_axi_attr_init(void)
+{
+	uint32_t index, data;
+
+	/* Initialize AXI attributes for APN806 */
+
+	/* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+	for (index = 0; index < AXI_MAX_ATTR; index++) {
+		switch (index) {
+		/* DFX works with no coherent only -
+		 * there's no option to configure the Ax-Cache and Ax-Domain
+		 */
+		case AXI_DFX_ATTR:
+			continue;
+		default:
+			/* Set Ax-Cache as cacheable, no allocate, modifiable,
+			 * bufferable
+			 * The values are different because Read & Write
+			 * definition is different in Ax-Cache
+			 */
+			data = mmio_read_32(MVEBU_AXI_ATTR_REG(index));
+			data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+			data |= (CACHE_ATTR_WRITE_ALLOC |
+				 CACHE_ATTR_CACHEABLE   |
+				 CACHE_ATTR_BUFFERABLE) <<
+				 MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+			data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+			data |= (CACHE_ATTR_READ_ALLOC |
+				 CACHE_ATTR_CACHEABLE  |
+				 CACHE_ATTR_BUFFERABLE) <<
+				 MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+			/* Set Ax-Domain as Outer domain */
+			data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+			data |= DOMAIN_OUTER_SHAREABLE <<
+				MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+			data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+			data |= DOMAIN_OUTER_SHAREABLE <<
+				MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+			mmio_write_32(MVEBU_AXI_ATTR_REG(index), data);
+		}
+	}
+}
+
+static void dss_setup(void)
+{
+	/* Enable 48-bit VA */
+	mmio_setbits_32(DSS_CR0, DVM_48BIT_VA_ENABLE);
+}
+
+void misc_soc_configurations(void)
+{
+	uint32_t reg;
+
+	/* Un-mask Watchdog reset from influencing the SYSRST_OUTn.
+	 * Otherwise, upon WD timeout, the WD reset signal won't trigger reset
+	 */
+	reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG);
+	reg &= ~(WD_MASK_SYS_RST_OUT);
+	mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg);
+}
+
+void ap_init(void)
+{
+	/* Setup Aurora2. */
+	init_aurora2();
+
+	/* configure MCI mapping */
+	mci_remap_indirect_access_base();
+
+	/* configure IO_WIN windows */
+	init_io_win(MVEBU_AP0);
+
+	/* configure CCU windows */
+	init_ccu(MVEBU_AP0);
+
+	/* configure DSS */
+	dss_setup();
+
+	/* configure the SMMU */
+	setup_smmu();
+
+	/* Open APN incoming access for all masters */
+	apn_sec_masters_access_en(1);
+
+	/* configure axi for APN*/
+	apn806_axi_attr_init();
+
+	/* misc configuration of the SoC */
+	misc_soc_configurations();
+}
+
+void ap_ble_init(void)
+{
+}
+
+int ap_get_count(void)
+{
+	return 1;
+}
+
diff --git a/drivers/marvell/mochi/cp110_setup.c b/drivers/marvell/mochi/cp110_setup.c
new file mode 100644
index 0000000..b4b4e0c
--- /dev/null
+++ b/drivers/marvell/mochi/cp110_setup.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CP110 Marvell SoC driver */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/amb_adec.h>
+#include <drivers/marvell/iob.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+
+#include <plat_marvell.h>
+
+/*
+ * AXI Configuration.
+ */
+
+ /* Used for Units of CP-110 (e.g. USB device, USB Host, and etc) */
+#define MVEBU_AXI_ATTR_OFFSET			(0x441300)
+#define MVEBU_AXI_ATTR_REG(index)		(MVEBU_AXI_ATTR_OFFSET + \
+							0x4 * index)
+
+/* AXI Protection bits */
+#define MVEBU_AXI_PROT_OFFSET				(0x441200)
+
+/* AXI Protection regs */
+#define MVEBU_AXI_PROT_REG(index)		((index <= 4) ? \
+						(MVEBU_AXI_PROT_OFFSET + \
+							0x4 * index) : \
+						(MVEBU_AXI_PROT_OFFSET + 0x18))
+#define MVEBU_AXI_PROT_REGS_NUM			(6)
+
+#define MVEBU_SOC_CFGS_OFFSET			(0x441900)
+#define MVEBU_SOC_CFG_REG(index)		(MVEBU_SOC_CFGS_OFFSET + \
+							0x4 * index)
+#define MVEBU_SOC_CFG_REG_NUM			(0)
+#define MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK	(0xE)
+
+/* SATA3 MBUS to AXI regs */
+#define MVEBU_BRIDGE_WIN_DIS_REG		(MVEBU_SOC_CFGS_OFFSET + 0x10)
+#define MVEBU_BRIDGE_WIN_DIS_OFF		(0x0)
+
+/* SATA3 MBUS to AXI regs */
+#define MVEBU_SATA_M2A_AXI_PORT_CTRL_REG	(0x54ff04)
+
+/* AXI to MBUS bridge registers */
+#define MVEBU_AMB_IP_OFFSET			(0x13ff00)
+#define MVEBU_AMB_IP_BRIDGE_WIN_REG(win)	(MVEBU_AMB_IP_OFFSET + \
+							(win * 0x8))
+#define MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET	0
+#define MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK		\
+				(0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET)
+#define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET	16
+#define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK	\
+				(0xffffu << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET)
+
+#define MVEBU_SAMPLE_AT_RESET_REG	(0x440600)
+#define SAR_PCIE1_CLK_CFG_OFFSET	31
+#define SAR_PCIE1_CLK_CFG_MASK		(0x1u << SAR_PCIE1_CLK_CFG_OFFSET)
+#define SAR_PCIE0_CLK_CFG_OFFSET	30
+#define SAR_PCIE0_CLK_CFG_MASK		(0x1 << SAR_PCIE0_CLK_CFG_OFFSET)
+#define SAR_I2C_INIT_EN_OFFSET		24
+#define SAR_I2C_INIT_EN_MASK		(1 << SAR_I2C_INIT_EN_OFFSET)
+
+/*******************************************************************************
+ * PCIE clock buffer control
+ ******************************************************************************/
+#define MVEBU_PCIE_REF_CLK_BUF_CTRL			(0x4404F0)
+#define PCIE1_REFCLK_BUFF_SOURCE			0x800
+#define PCIE0_REFCLK_BUFF_SOURCE			0x400
+
+/*******************************************************************************
+ * MSS Device Push Set Register
+ ******************************************************************************/
+#define MVEBU_CP_MSS_DPSHSR_REG				(0x280040)
+#define MSS_DPSHSR_REG_PCIE_CLK_SEL			0x8
+
+/*******************************************************************************
+ * RTC Configuration
+ ******************************************************************************/
+#define MVEBU_RTC_BASE					(0x284000)
+#define MVEBU_RTC_STATUS_REG				(MVEBU_RTC_BASE + 0x0)
+#define MVEBU_RTC_STATUS_ALARM1_MASK			0x1
+#define MVEBU_RTC_STATUS_ALARM2_MASK			0x2
+#define MVEBU_RTC_IRQ_1_CONFIG_REG			(MVEBU_RTC_BASE + 0x4)
+#define MVEBU_RTC_IRQ_2_CONFIG_REG			(MVEBU_RTC_BASE + 0x8)
+#define MVEBU_RTC_TIME_REG				(MVEBU_RTC_BASE + 0xC)
+#define MVEBU_RTC_ALARM_1_REG				(MVEBU_RTC_BASE + 0x10)
+#define MVEBU_RTC_ALARM_2_REG				(MVEBU_RTC_BASE + 0x14)
+#define MVEBU_RTC_CCR_REG				(MVEBU_RTC_BASE + 0x18)
+#define MVEBU_RTC_NOMINAL_TIMING			0x2000
+#define MVEBU_RTC_NOMINAL_TIMING_MASK			0x7FFF
+#define MVEBU_RTC_TEST_CONFIG_REG			(MVEBU_RTC_BASE + 0x1C)
+#define MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG		(MVEBU_RTC_BASE + 0x80)
+#define MVEBU_RTC_WRCLK_PERIOD_MASK			0xFFFF
+#define MVEBU_RTC_WRCLK_PERIOD_DEFAULT			0x3FF
+#define MVEBU_RTC_WRCLK_SETUP_OFFS			16
+#define MVEBU_RTC_WRCLK_SETUP_MASK			0xFFFF0000
+#define MVEBU_RTC_WRCLK_SETUP_DEFAULT			0x29
+#define MVEBU_RTC_BRIDGE_TIMING_CTRL1_REG		(MVEBU_RTC_BASE + 0x84)
+#define MVEBU_RTC_READ_OUTPUT_DELAY_MASK		0xFFFF
+#define MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT		0x1F
+
+enum axi_attr {
+	AXI_ADUNIT_ATTR = 0,
+	AXI_COMUNIT_ATTR,
+	AXI_EIP197_ATTR,
+	AXI_USB3D_ATTR,
+	AXI_USB3H0_ATTR,
+	AXI_USB3H1_ATTR,
+	AXI_SATA0_ATTR,
+	AXI_SATA1_ATTR,
+	AXI_DAP_ATTR,
+	AXI_DFX_ATTR,
+	AXI_DBG_TRC_ATTR = 12,
+	AXI_SDIO_ATTR,
+	AXI_MSS_ATTR,
+	AXI_MAX_ATTR,
+};
+
+/* Most stream IDS are configured centrally in the CP-110 RFU
+ * but some are configured inside the unit registers
+ */
+#define RFU_STREAM_ID_BASE	(0x450000)
+#define USB3H_0_STREAM_ID_REG	(RFU_STREAM_ID_BASE + 0xC)
+#define USB3H_1_STREAM_ID_REG	(RFU_STREAM_ID_BASE + 0x10)
+#define SATA_0_STREAM_ID_REG	(RFU_STREAM_ID_BASE + 0x14)
+#define SATA_1_STREAM_ID_REG	(RFU_STREAM_ID_BASE + 0x18)
+
+#define CP_DMA_0_STREAM_ID_REG  (0x6B0010)
+#define CP_DMA_1_STREAM_ID_REG  (0x6D0010)
+
+/* We allocate IDs 128-255 for PCIe */
+#define MAX_STREAM_ID		(0x80)
+
+uintptr_t stream_id_reg[] = {
+	USB3H_0_STREAM_ID_REG,
+	USB3H_1_STREAM_ID_REG,
+	CP_DMA_0_STREAM_ID_REG,
+	CP_DMA_1_STREAM_ID_REG,
+	SATA_0_STREAM_ID_REG,
+	SATA_1_STREAM_ID_REG,
+	0
+};
+
+static void cp110_errata_wa_init(uintptr_t base)
+{
+	uint32_t data;
+
+	/* ERRATA GL-4076863:
+	 * Reset value for global_secure_enable inputs must be changed
+	 * from '1' to '0'.
+	 * When asserted, only "secured" transactions can enter IHB
+	 * configuration space.
+	 * However, blocking AXI transactions is performed by IOB.
+	 * Performing it also at IHB/HB complicates programming model.
+	 *
+	 * Enable non-secure access in SOC configuration register
+	 */
+	data = mmio_read_32(base + MVEBU_SOC_CFG_REG(MVEBU_SOC_CFG_REG_NUM));
+	data &= ~MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK;
+	mmio_write_32(base + MVEBU_SOC_CFG_REG(MVEBU_SOC_CFG_REG_NUM), data);
+}
+
+static void cp110_pcie_clk_cfg(uintptr_t base)
+{
+	uint32_t pcie0_clk, pcie1_clk, reg;
+
+	/*
+	 * Determine the pcie0/1 clock direction (input/output) from the
+	 * sample at reset.
+	 */
+	reg = mmio_read_32(base + MVEBU_SAMPLE_AT_RESET_REG);
+	pcie0_clk = (reg & SAR_PCIE0_CLK_CFG_MASK) >> SAR_PCIE0_CLK_CFG_OFFSET;
+	pcie1_clk = (reg & SAR_PCIE1_CLK_CFG_MASK) >> SAR_PCIE1_CLK_CFG_OFFSET;
+
+	/* CP110 revision A2 */
+	if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A2) {
+		/*
+		 * PCIe Reference Clock Buffer Control register must be
+		 * set according to the clock direction (input/output)
+		 */
+		reg = mmio_read_32(base + MVEBU_PCIE_REF_CLK_BUF_CTRL);
+		reg &= ~(PCIE0_REFCLK_BUFF_SOURCE | PCIE1_REFCLK_BUFF_SOURCE);
+		if (!pcie0_clk)
+			reg |= PCIE0_REFCLK_BUFF_SOURCE;
+		if (!pcie1_clk)
+			reg |= PCIE1_REFCLK_BUFF_SOURCE;
+
+		mmio_write_32(base + MVEBU_PCIE_REF_CLK_BUF_CTRL, reg);
+	}
+
+	/* CP110 revision A1 */
+	if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A1) {
+		if (!pcie0_clk || !pcie1_clk) {
+			/*
+			 * if one of the pcie clocks is set to input,
+			 * we need to set mss_push[131] field, otherwise,
+			 * the pcie clock might not work.
+			 */
+			reg = mmio_read_32(base + MVEBU_CP_MSS_DPSHSR_REG);
+			reg |= MSS_DPSHSR_REG_PCIE_CLK_SEL;
+			mmio_write_32(base + MVEBU_CP_MSS_DPSHSR_REG, reg);
+		}
+	}
+}
+
+/* Set a unique stream id for all DMA capable devices */
+static void cp110_stream_id_init(uintptr_t base, uint32_t stream_id)
+{
+	int i = 0;
+
+	while (stream_id_reg[i]) {
+		if (i > MAX_STREAM_ID_PER_CP) {
+			NOTICE("Only first %d (maximum) Stream IDs allocated\n",
+			       MAX_STREAM_ID_PER_CP);
+			return;
+		}
+
+		if ((stream_id_reg[i] == CP_DMA_0_STREAM_ID_REG) ||
+		    (stream_id_reg[i] == CP_DMA_1_STREAM_ID_REG))
+			mmio_write_32(base + stream_id_reg[i],
+				      stream_id << 16 |  stream_id);
+		else
+			mmio_write_32(base + stream_id_reg[i], stream_id);
+
+		/* SATA port 0/1 are in the same SATA unit, and they should use
+		 * the same STREAM ID number
+		 */
+		if (stream_id_reg[i] != SATA_0_STREAM_ID_REG)
+			stream_id++;
+
+		i++;
+	}
+}
+
+static void cp110_axi_attr_init(uintptr_t base)
+{
+	uint32_t index, data;
+
+	/* Initialize AXI attributes for Armada-7K/8K SoC */
+
+	/* Go over the AXI attributes and set Ax-Cache and Ax-Domain */
+	for (index = 0; index < AXI_MAX_ATTR; index++) {
+		switch (index) {
+		/* DFX and MSS unit works with no coherent only -
+		 * there's no option to configure the Ax-Cache and Ax-Domain
+		 */
+		case AXI_DFX_ATTR:
+		case AXI_MSS_ATTR:
+			continue;
+		default:
+			/* Set Ax-Cache as cacheable, no allocate, modifiable,
+			 * bufferable
+			 * The values are different because Read & Write
+			 * definition is different in Ax-Cache
+			 */
+			data = mmio_read_32(base + MVEBU_AXI_ATTR_REG(index));
+			data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK;
+			data |= (CACHE_ATTR_WRITE_ALLOC |
+				 CACHE_ATTR_CACHEABLE   |
+				 CACHE_ATTR_BUFFERABLE) <<
+				 MVEBU_AXI_ATTR_ARCACHE_OFFSET;
+			data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK;
+			data |= (CACHE_ATTR_READ_ALLOC |
+				 CACHE_ATTR_CACHEABLE  |
+				 CACHE_ATTR_BUFFERABLE) <<
+				 MVEBU_AXI_ATTR_AWCACHE_OFFSET;
+			/* Set Ax-Domain as Outer domain */
+			data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK;
+			data |= DOMAIN_OUTER_SHAREABLE <<
+				MVEBU_AXI_ATTR_ARDOMAIN_OFFSET;
+			data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK;
+			data |= DOMAIN_OUTER_SHAREABLE <<
+				MVEBU_AXI_ATTR_AWDOMAIN_OFFSET;
+			mmio_write_32(base + MVEBU_AXI_ATTR_REG(index), data);
+		}
+	}
+
+	/* SATA IOCC supported, cache attributes
+	 * for SATA MBUS to AXI configuration.
+	 */
+	data = mmio_read_32(base + MVEBU_SATA_M2A_AXI_PORT_CTRL_REG);
+	data &= ~MVEBU_SATA_M2A_AXI_AWCACHE_MASK;
+	data |= (CACHE_ATTR_WRITE_ALLOC |
+		 CACHE_ATTR_CACHEABLE   |
+		 CACHE_ATTR_BUFFERABLE) <<
+		 MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET;
+	data &= ~MVEBU_SATA_M2A_AXI_ARCACHE_MASK;
+	data |= (CACHE_ATTR_READ_ALLOC |
+		 CACHE_ATTR_CACHEABLE  |
+		 CACHE_ATTR_BUFFERABLE) <<
+		 MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET;
+	mmio_write_32(base + MVEBU_SATA_M2A_AXI_PORT_CTRL_REG, data);
+
+	/* Set all IO's AXI attribute to non-secure access. */
+	for (index = 0; index < MVEBU_AXI_PROT_REGS_NUM; index++)
+		mmio_write_32(base + MVEBU_AXI_PROT_REG(index),
+			      DOMAIN_SYSTEM_SHAREABLE);
+}
+
+static void amb_bridge_init(uintptr_t base)
+{
+	uint32_t reg;
+
+	/* Open AMB bridge Window to Access COMPHY/MDIO registers */
+	reg = mmio_read_32(base + MVEBU_AMB_IP_BRIDGE_WIN_REG(0));
+	reg &= ~(MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK |
+		 MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK);
+	reg |= (0x7ff << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET) |
+	       (0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET);
+	mmio_write_32(base + MVEBU_AMB_IP_BRIDGE_WIN_REG(0), reg);
+}
+
+static void cp110_rtc_init(uintptr_t base)
+{
+	/* Update MBus timing parameters before accessing RTC registers */
+	mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG,
+			   MVEBU_RTC_WRCLK_PERIOD_MASK,
+			   MVEBU_RTC_WRCLK_PERIOD_DEFAULT);
+
+	mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG,
+			   MVEBU_RTC_WRCLK_SETUP_MASK,
+			   MVEBU_RTC_WRCLK_SETUP_DEFAULT <<
+			   MVEBU_RTC_WRCLK_SETUP_OFFS);
+
+	mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL1_REG,
+			   MVEBU_RTC_READ_OUTPUT_DELAY_MASK,
+			   MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT);
+
+	/*
+	 * Issue reset to the RTC if Clock Correction register
+	 * contents did not sustain the reboot/power-on.
+	 */
+	if ((mmio_read_32(base + MVEBU_RTC_CCR_REG) &
+	    MVEBU_RTC_NOMINAL_TIMING_MASK) != MVEBU_RTC_NOMINAL_TIMING) {
+		/* Reset Test register */
+		mmio_write_32(base + MVEBU_RTC_TEST_CONFIG_REG, 0);
+		mdelay(500);
+
+		/* Reset Status register */
+		mmio_write_32(base + MVEBU_RTC_STATUS_REG,
+			      (MVEBU_RTC_STATUS_ALARM1_MASK |
+			      MVEBU_RTC_STATUS_ALARM2_MASK));
+		udelay(62);
+
+		/* Turn off Int1 and Int2 sources & clear the Alarm count */
+		mmio_write_32(base + MVEBU_RTC_IRQ_1_CONFIG_REG, 0);
+		mmio_write_32(base + MVEBU_RTC_IRQ_2_CONFIG_REG, 0);
+		mmio_write_32(base + MVEBU_RTC_ALARM_1_REG, 0);
+		mmio_write_32(base + MVEBU_RTC_ALARM_2_REG, 0);
+
+		/* Setup nominal register access timing */
+		mmio_write_32(base + MVEBU_RTC_CCR_REG,
+			      MVEBU_RTC_NOMINAL_TIMING);
+
+		/* Reset Status register */
+		mmio_write_32(base + MVEBU_RTC_STATUS_REG,
+			      (MVEBU_RTC_STATUS_ALARM1_MASK |
+			      MVEBU_RTC_STATUS_ALARM2_MASK));
+		udelay(50);
+	}
+}
+
+static void cp110_amb_adec_init(uintptr_t base)
+{
+	/* enable AXI-MBUS by clearing "Bridge Windows Disable" */
+	mmio_clrbits_32(base + MVEBU_BRIDGE_WIN_DIS_REG,
+			(1 << MVEBU_BRIDGE_WIN_DIS_OFF));
+
+	/* configure AXI-MBUS windows for CP */
+	init_amb_adec(base);
+}
+
+void cp110_init(uintptr_t cp110_base, uint32_t stream_id)
+{
+	INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base);
+
+	/* configure IOB windows for CP0*/
+	init_iob(cp110_base);
+
+	/* configure AXI-MBUS windows for CP0*/
+	cp110_amb_adec_init(cp110_base);
+
+	/* configure axi for CP0*/
+	cp110_axi_attr_init(cp110_base);
+
+	/* Execute SW WA for erratas */
+	cp110_errata_wa_init(cp110_base);
+
+	/* Confiure pcie clock according to clock direction */
+	cp110_pcie_clk_cfg(cp110_base);
+
+	/* configure stream id for CP0 */
+	cp110_stream_id_init(cp110_base, stream_id);
+
+	/* Open AMB bridge for comphy for CP0 & CP1*/
+	amb_bridge_init(cp110_base);
+
+	/* Reset RTC if needed */
+	cp110_rtc_init(cp110_base);
+}
+
+/* Do the minimal setup required to configure the CP in BLE */
+void cp110_ble_init(uintptr_t cp110_base)
+{
+#if PCI_EP_SUPPORT
+	INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base);
+
+	amb_bridge_init(cp110_base);
+
+	/* Configure PCIe clock */
+	cp110_pcie_clk_cfg(cp110_base);
+
+	/* Configure PCIe endpoint */
+	ble_plat_pcie_ep_setup();
+#endif
+}
diff --git a/drivers/marvell/thermal.c b/drivers/marvell/thermal.c
new file mode 100644
index 0000000..a501ab4
--- /dev/null
+++ b/drivers/marvell/thermal.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Driver for thermal unit located in Marvell ARMADA 8K and compatible SoCs */
+
+#include <common/debug.h>
+#include <drivers/marvell/thermal.h>
+
+int marvell_thermal_init(struct tsen_config *tsen_cfg)
+{
+	if (tsen_cfg->tsen_ready == 1) {
+		INFO("thermal sensor is already initialized\n");
+		return 0;
+	}
+
+	if (tsen_cfg->ptr_tsen_probe == NULL) {
+		ERROR("initial thermal sensor configuration is missing\n");
+		return -1;
+	}
+
+	if (tsen_cfg->ptr_tsen_probe(tsen_cfg)) {
+		ERROR("thermal sensor initialization failed\n");
+		return -1;
+	}
+
+	VERBOSE("thermal sensor was initialized\n");
+
+	return 0;
+}
+
+int marvell_thermal_read(struct tsen_config *tsen_cfg, int *temp)
+{
+	if (temp == NULL) {
+		ERROR("NULL pointer for temperature read\n");
+		return -1;
+	}
+
+	if (tsen_cfg->ptr_tsen_read == NULL ||
+	    tsen_cfg->tsen_ready == 0) {
+		ERROR("thermal sensor was not initialized\n");
+		return -1;
+	}
+
+	if (tsen_cfg->ptr_tsen_read(tsen_cfg, temp)) {
+		ERROR("temperature read failed\n");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/drivers/marvell/uart/a3700_console.S b/drivers/marvell/uart/a3700_console.S
new file mode 100644
index 0000000..da1ce35
--- /dev/null
+++ b/drivers/marvell/uart/a3700_console.S
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/marvell/uart/a3700_console.h>
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_a3700_core_putc
+	.globl console_a3700_core_init
+	.globl console_a3700_core_getc
+	.globl console_a3700_core_flush
+
+	.globl console_a3700_putc
+	.globl console_a3700_getc
+	.globl console_a3700_flush
+
+	/* -----------------------------------------------
+	 * int console_a3700_core_init(unsigned long base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success
+	 * Clobber list : x1, x2, x3
+	 * -----------------------------------------------
+	 */
+func console_a3700_core_init
+	/* Check the input base address */
+	cbz	x0, init_fail
+	/* Check baud rate and uart clock for sanity */
+	cbz	w1, init_fail
+	cbz	w2, init_fail
+
+	/* Program the baudrate */
+	/* Divisor =  Uart clock / (16 * baudrate) */
+	lsl	w2, w2, #4
+	udiv	w2, w1, w2
+	and	w2, w2, #0x3ff
+
+	ldr	w3, [x0, #UART_BAUD_REG]
+	bic	w3, w3, 0x3ff
+	orr	w3, w3, w2
+	str	w3, [x0, #UART_BAUD_REG]/* set baud rate divisor */
+
+	/* Set UART to default 16X scheme */
+	mov	w3, #0
+	str	w3, [x0, #UART_POSSR_REG]
+
+	/*
+	 * Wait for the TX FIFO to be empty. If wait for 20ms, the TX FIFO is
+	 * still not empty, TX FIFO will reset by all means.
+	 */
+	mov	w1, #20				/* max time out 20ms */
+2:
+	/* Check whether TX FIFO is empty */
+	ldr	w3, [x0, #UART_STATUS_REG]
+	and	w3, w3, #UARTLSR_TXFIFOEMPTY
+	cmp	w3, #0
+	b.ne	4f
+
+	/* Delay */
+	mov	w2, #30000
+3:
+	sub     w2, w2, #1
+	cmp	w2, #0
+	b.ne	3b
+
+	/* Check whether 10ms is waited */
+	sub     w1, w1, #1
+	cmp	w1, #0
+	b.ne	2b
+
+4:
+	/* Reset FIFO */
+	mov	w3, #UART_CTRL_RXFIFO_RESET
+	orr	w3, w3, #UART_CTRL_TXFIFO_RESET
+	str	w3, [x0, #UART_CTRL_REG]
+
+	/* Delay */
+	mov	w2, #2000
+1:
+	sub     w2, w2, #1
+	cmp	w2, #0
+	b.ne	1b
+
+	/* No Parity, 1 Stop */
+	mov	w3, #0
+	str	w3, [x0, #UART_CTRL_REG]
+
+	mov	w0, #1
+	ret
+init_fail:
+	mov	w0, #0
+	ret
+endfunc console_a3700_core_init
+
+	.globl console_a3700_register
+
+	/* -----------------------------------------------
+	 * int console_a3700_register(console_16550_t *console,
+		uintptr_t base, uint32_t clk, uint32_t baud)
+	 * Function to initialize and register a new a3700
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_a3700_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_a3700_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_A3700_BASE]
+
+	bl	console_a3700_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register a3700, putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_a3700_register
+
+	/* --------------------------------------------------------
+	 * int console_a3700_core_putc(int c, unsigned int base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_a3700_core_putc
+	/* Check the input parameter */
+	cbz	x1, putc_error
+
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+	/* Check if the transmit FIFO is full */
+1:	ldr	w2, [x1, #UART_STATUS_REG]
+	and	w2, w2, #UARTLSR_TXFIFOFULL
+	cmp	w2, #UARTLSR_TXFIFOFULL
+	b.eq	1b
+	mov	w2, #0xD		/* '\r' */
+	str	w2, [x1, #UART_TX_REG]
+
+	/* Check if the transmit FIFO is full */
+2:	ldr	w2, [x1, #UART_STATUS_REG]
+	and	w2, w2, #UARTLSR_TXFIFOFULL
+	cmp	w2, #UARTLSR_TXFIFOFULL
+	b.eq	2b
+	str	w0, [x1, #UART_TX_REG]
+	ret
+putc_error:
+	mov	w0, #-1
+	ret
+endfunc console_a3700_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_a3700_putc(int c, console_a3700_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_a3700_putc
+	ldr	x1, [x1, #CONSOLE_T_A3700_BASE]
+	b	console_a3700_core_putc
+endfunc console_a3700_putc
+
+	/* ---------------------------------------------
+	 * int console_a3700_core_getc(void)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on error.
+	 * In : w0 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_a3700_core_getc
+	mov	w0, #-1
+	ret
+endfunc console_a3700_core_getc
+
+	/* ---------------------------------------------
+	 * int console_a3700_getc(console_a3700_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  x0 - pointer to console_t structure
+	 * Out : w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_a3700_getc
+	ldr	x0, [x0, #CONSOLE_T_A3700_BASE]
+	b	console_a3700_core_getc
+endfunc console_a3700_getc
+
+	/* ---------------------------------------------
+	 * int console_a3700_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_a3700_core_flush
+	mov	w0, #0
+	ret
+endfunc console_a3700_core_flush
+
+	/* ---------------------------------------------
+	 * int console_a3700_flush(console_a3700_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_a3700_flush
+	ldr	x0, [x0, #CONSOLE_T_A3700_BASE]
+	b	console_a3700_core_flush
+endfunc console_a3700_flush
+
diff --git a/drivers/mentor/i2c/mi2cv.c b/drivers/mentor/i2c/mi2cv.c
new file mode 100644
index 0000000..1cdcf74
--- /dev/null
+++ b/drivers/mentor/i2c/mi2cv.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/*
+ * This driver is for Mentor Graphics Inventra MI2CV IP core, which is used
+ * for Marvell and Allwinner SoCs in ATF.
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mentor_i2c_plat.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+#define DEBUG_I2C
+#endif
+
+#define I2C_TIMEOUT_VALUE		0x500
+#define I2C_MAX_RETRY_CNT		1000
+#define I2C_CMD_WRITE			0x0
+#define I2C_CMD_READ			0x1
+
+#define I2C_DATA_ADDR_7BIT_OFFS		0x1
+#define I2C_DATA_ADDR_7BIT_MASK		(0xFF << I2C_DATA_ADDR_7BIT_OFFS)
+
+#define I2C_CONTROL_ACK			0x00000004
+#define I2C_CONTROL_IFLG		0x00000008
+#define I2C_CONTROL_STOP		0x00000010
+#define I2C_CONTROL_START		0x00000020
+#define I2C_CONTROL_TWSIEN		0x00000040
+#define I2C_CONTROL_INTEN		0x00000080
+
+#define I2C_STATUS_START			0x08
+#define I2C_STATUS_REPEATED_START		0x10
+#define I2C_STATUS_ADDR_W_ACK			0x18
+#define I2C_STATUS_DATA_W_ACK			0x28
+#define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER	0x38
+#define I2C_STATUS_ADDR_R_ACK			0x40
+#define I2C_STATUS_DATA_R_ACK			0x50
+#define I2C_STATUS_DATA_R_NAK			0x58
+#define I2C_STATUS_LOST_ARB_GENERAL_CALL	0x78
+#define I2C_STATUS_IDLE				0xF8
+
+#define I2C_UNSTUCK_TRIGGER			0x1
+#define I2C_UNSTUCK_ONGOING			0x2
+#define I2C_UNSTUCK_ERROR			0x4
+
+static struct mentor_i2c_regs *base;
+
+static int mentor_i2c_lost_arbitration(uint32_t *status)
+{
+	*status = mmio_read_32((uintptr_t)&base->status);
+	if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) ||
+	    (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static void mentor_i2c_interrupt_clear(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32((uintptr_t)&base->control);
+#ifndef I2C_INTERRUPT_CLEAR_INVERTED
+	reg &= ~(I2C_CONTROL_IFLG);
+#else
+	reg |= I2C_CONTROL_IFLG;
+#endif
+	mmio_write_32((uintptr_t)&base->control, reg);
+	/* Wait for 1 us for the clear to take effect */
+	udelay(1);
+}
+
+static int mentor_i2c_interrupt_get(void)
+{
+	uint32_t reg;
+
+	/* get the interrupt flag bit */
+	reg = mmio_read_32((uintptr_t)&base->control);
+	reg &= I2C_CONTROL_IFLG;
+	return reg && I2C_CONTROL_IFLG;
+}
+
+static int mentor_i2c_wait_interrupt(void)
+{
+	uint32_t timeout = 0;
+
+	while (!mentor_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE))
+		;
+	if (timeout >= I2C_TIMEOUT_VALUE)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mentor_i2c_start_bit_set(void)
+{
+	int is_int_flag = 0;
+	uint32_t status;
+
+	if (mentor_i2c_interrupt_get())
+		is_int_flag = 1;
+
+	/* set start bit */
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_START);
+
+	/* in case that the int flag was set before i.e. repeated start bit */
+	if (is_int_flag) {
+		VERBOSE("%s: repeated start Bit\n", __func__);
+		mentor_i2c_interrupt_clear();
+	}
+
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* check that start bit went down */
+	if ((mmio_read_32((uintptr_t)&base->control) &
+	    I2C_CONTROL_START) != 0) {
+		ERROR("Start bit didn't went down\n");
+		return -EPERM;
+	}
+
+	/* check the status */
+	if (mentor_i2c_lost_arbitration(&status)) {
+		ERROR("%s - %d: Lost arbitration, got status %x\n",
+		      __func__, __LINE__, status);
+		return -EAGAIN;
+	}
+	if ((status != I2C_STATUS_START) &&
+	    (status != I2C_STATUS_REPEATED_START)) {
+		ERROR("Got status %x after enable start bit.\n", status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_stop_bit_set(void)
+{
+	int timeout;
+	uint32_t status;
+
+	/* Generate stop bit */
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_STOP);
+	mentor_i2c_interrupt_clear();
+
+	timeout = 0;
+	/* Read control register, check the control stop bit */
+	while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) &&
+	       (timeout++ < I2C_TIMEOUT_VALUE))
+		;
+	if (timeout >= I2C_TIMEOUT_VALUE) {
+		ERROR("Stop bit didn't went down\n");
+		return -ETIMEDOUT;
+	}
+
+	/* check that stop bit went down */
+	if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) {
+		ERROR("Stop bit didn't went down\n");
+		return -EPERM;
+	}
+
+	/* check the status */
+	if (mentor_i2c_lost_arbitration(&status)) {
+		ERROR("%s - %d: Lost arbitration, got status %x\n",
+		      __func__, __LINE__, status);
+		return -EAGAIN;
+	}
+	if (status != I2C_STATUS_IDLE) {
+		ERROR("Got status %x after enable stop bit.\n", status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_address_set(uint8_t chain, int command)
+{
+	uint32_t reg, status;
+
+	reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK;
+	reg |= command;
+	mmio_write_32((uintptr_t)&base->data, reg);
+	udelay(1);
+
+	mentor_i2c_interrupt_clear();
+
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* check the status */
+	if (mentor_i2c_lost_arbitration(&status)) {
+		ERROR("%s - %d: Lost arbitration, got status %x\n",
+		      __func__, __LINE__, status);
+		return -EAGAIN;
+	}
+	if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) ||
+	   ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) {
+		/* only in debug, since in boot we try to read the SPD
+		 * of both DRAM, and we don't want error messages in cas
+		 * DIMM doesn't exist.
+		 */
+		INFO("%s: ERROR - status %x addr in %s mode.\n", __func__,
+		     status, (command == I2C_CMD_WRITE) ? "Write" : "Read");
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+/*
+ * The I2C module contains a clock divider to generate the SCL clock.
+ * This function calculates and sets the <N> and <M> fields in the I2C Baud
+ * Rate Register (t=01) to obtain given 'requested_speed'.
+ * The requested_speed will be equal to:
+ * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N))
+ * Where M is the value represented by bits[6:3] and N is the value represented
+ * by bits[2:0] of "I2C Baud Rate Register".
+ * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the
+ * lowest possible baudrate is:
+ * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to:
+ * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest
+ * possible frequency is ~2,872KHz.
+ */
+static unsigned int mentor_i2c_bus_speed_set(unsigned int requested_speed)
+{
+	unsigned int n, m, freq, margin, min_margin = 0xffffffff;
+	unsigned int actual_n = 0, actual_m = 0;
+	int val;
+
+	/* Calculate N and M for the TWSI clock baud rate */
+	for (n = 0; n < 8; n++) {
+		for (m = 0; m < 16; m++) {
+			freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
+			val = requested_speed - freq;
+			margin = (val > 0) ? val : -val;
+
+			if ((freq <= requested_speed) &&
+			    (margin < min_margin)) {
+				min_margin = margin;
+				actual_n = n;
+				actual_m = m;
+			}
+		}
+	}
+	VERBOSE("%s: actual_n = %u, actual_m = %u\n",
+		__func__, actual_n, actual_m);
+	/* Set the baud rate */
+	mmio_write_32((uintptr_t)&base->baudrate, (actual_m << 3) | actual_n);
+
+	return 0;
+}
+
+#ifdef DEBUG_I2C
+static int mentor_i2c_probe(uint8_t chip)
+{
+	int ret = 0;
+
+	ret = mentor_i2c_start_bit_set();
+	if (ret != 0) {
+		mentor_i2c_stop_bit_set();
+		ERROR("%s - %d: %s", __func__, __LINE__,
+		      "mentor_i2c_start_bit_set failed\n");
+		return -EPERM;
+	}
+
+	ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
+	if (ret != 0) {
+		mentor_i2c_stop_bit_set();
+		ERROR("%s - %d: %s", __func__, __LINE__,
+		      "mentor_i2c_address_set failed\n");
+		return -EPERM;
+	}
+
+	mentor_i2c_stop_bit_set();
+
+	VERBOSE("%s: successful I2C probe\n", __func__);
+
+	return ret;
+}
+#endif
+
+/* regular i2c transaction */
+static int mentor_i2c_data_receive(uint8_t *p_block, uint32_t block_size)
+{
+	uint32_t reg, status, block_size_read = block_size;
+
+	/* Wait for cause interrupt */
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+	while (block_size_read) {
+		if (block_size_read == 1) {
+			reg = mmio_read_32((uintptr_t)&base->control);
+			reg &= ~(I2C_CONTROL_ACK);
+			mmio_write_32((uintptr_t)&base->control, reg);
+		}
+		mentor_i2c_interrupt_clear();
+
+		if (mentor_i2c_wait_interrupt()) {
+			ERROR("Start clear bit timeout\n");
+			return -ETIMEDOUT;
+		}
+		/* check the status */
+		if (mentor_i2c_lost_arbitration(&status)) {
+			ERROR("%s - %d: Lost arbitration, got status %x\n",
+			      __func__, __LINE__, status);
+			return -EAGAIN;
+		}
+		if ((status != I2C_STATUS_DATA_R_ACK) &&
+		    (block_size_read != 1)) {
+			ERROR("Status %x in read transaction\n", status);
+			return -EPERM;
+		}
+		if ((status != I2C_STATUS_DATA_R_NAK) &&
+		    (block_size_read == 1)) {
+			ERROR("Status %x in Rd Terminate\n", status);
+			return -EPERM;
+		}
+
+		/* read the data */
+		*p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data);
+		VERBOSE("%s: place %d read %x\n", __func__,
+			block_size - block_size_read, *p_block);
+		p_block++;
+		block_size_read--;
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_data_transmit(uint8_t *p_block, uint32_t block_size)
+{
+	uint32_t status, block_size_write = block_size;
+
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	while (block_size_write) {
+		/* write the data */
+		mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block);
+		VERBOSE("%s: index = %d, data = %x\n", __func__,
+			block_size - block_size_write, *p_block);
+		p_block++;
+		block_size_write--;
+
+		mentor_i2c_interrupt_clear();
+
+		if (mentor_i2c_wait_interrupt()) {
+			ERROR("Start clear bit timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		/* check the status */
+		if (mentor_i2c_lost_arbitration(&status)) {
+			ERROR("%s - %d: Lost arbitration, got status %x\n",
+			      __func__, __LINE__, status);
+			return -EAGAIN;
+		}
+		if (status != I2C_STATUS_DATA_W_ACK) {
+			ERROR("Status %x in write transaction\n", status);
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen)
+{
+	uint8_t off_block[2];
+	uint32_t off_size;
+
+	if (alen == 2) { /* 2-byte addresses support */
+		off_block[0] = (addr >> 8) & 0xff;
+		off_block[1] = addr & 0xff;
+		off_size = 2;
+	} else { /* 1-byte addresses support */
+		off_block[0] = addr & 0xff;
+		off_size = 1;
+	}
+	VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__,
+		off_size, off_block[0], off_block[1]);
+	return mentor_i2c_data_transmit(off_block, off_size);
+}
+
+#ifdef I2C_CAN_UNSTUCK
+static int mentor_i2c_unstuck(int ret)
+{
+	uint32_t v;
+
+	if (ret != -ETIMEDOUT)
+		return ret;
+	VERBOSE("Trying to \"unstuck i2c\"... ");
+	i2c_init(base);
+	mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER);
+	do {
+		v = mmio_read_32((uintptr_t)&base->unstuck);
+	} while (v & I2C_UNSTUCK_ONGOING);
+
+	if (v & I2C_UNSTUCK_ERROR) {
+		VERBOSE("failed - soft reset i2c\n");
+		ret = -EPERM;
+	} else {
+		VERBOSE("ok\n");
+		i2c_init(base);
+		ret = -EAGAIN;
+	}
+	return ret;
+}
+#else
+static int mentor_i2c_unstuck(int ret)
+{
+	VERBOSE("Cannot \"unstuck i2c\" - soft reset i2c\n");
+	return -EPERM;
+}
+#endif
+
+/*
+ * API Functions
+ */
+void i2c_init(void *i2c_base)
+{
+	/* For I2C speed and slave address, now we do not set them since
+	 * we just provide the working speed and slave address otherwhere
+	 * for i2c_init
+	 */
+	base = (struct mentor_i2c_regs *)i2c_base;
+
+	/* Reset the I2C logic */
+	mmio_write_32((uintptr_t)&base->soft_reset, 0);
+
+	udelay(200);
+
+	mentor_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED);
+
+	/* Enable the I2C and slave */
+	mmio_write_32((uintptr_t)&base->control,
+		      I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK);
+
+	/* set the I2C slave address */
+	mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0);
+	mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE);
+
+	/* unmask I2C interrupt */
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_INTEN);
+
+	udelay(10);
+}
+
+/*
+ * i2c_read: - Read multiple bytes from an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:	address of the chip which is to be read
+ * @addr:	i2c data address within the chip
+ * @alen:	length of the i2c data address (1..2 bytes)
+ * @buffer:	where to write the data
+ * @len:	how much byte do we want to read
+ * @return:	0 in case of success
+ */
+int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
+{
+	int ret = 0;
+	uint32_t counter = 0;
+
+#ifdef DEBUG_I2C
+	mentor_i2c_probe(chip);
+#endif
+
+	do {
+		if (ret != -EAGAIN && ret) {
+			ERROR("i2c transaction failed, after %d retries\n",
+			      counter);
+			mentor_i2c_stop_bit_set();
+			return ret;
+		}
+
+		/* wait for 1 us for the interrupt clear to take effect */
+		if (counter > 0)
+			udelay(1);
+		counter++;
+
+		ret = mentor_i2c_start_bit_set();
+		if (ret) {
+			ret = mentor_i2c_unstuck(ret);
+			continue;
+		}
+
+		/* if EEPROM device */
+		if (alen != 0) {
+			ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
+			if (ret)
+				continue;
+
+			ret = mentor_i2c_target_offset_set(chip, addr, alen);
+			if (ret)
+				continue;
+			ret = mentor_i2c_start_bit_set();
+			if (ret)
+				continue;
+		}
+
+		ret =  mentor_i2c_address_set(chip, I2C_CMD_READ);
+		if (ret)
+			continue;
+
+		ret = mentor_i2c_data_receive(buffer, len);
+		if (ret)
+			continue;
+
+		ret =  mentor_i2c_stop_bit_set();
+	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
+
+	if (counter == I2C_MAX_RETRY_CNT) {
+		ERROR("I2C transactions failed, got EAGAIN %d times\n",
+		      I2C_MAX_RETRY_CNT);
+		ret = -EPERM;
+	}
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_ACK);
+
+	udelay(1);
+	return ret;
+}
+
+/*
+ * i2c_write: -  Write multiple bytes to an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:	address of the chip which is to be written
+ * @addr:	i2c data address within the chip
+ * @alen:	length of the i2c data address (1..2 bytes)
+ * @buffer:	where to find the data to be written
+ * @len:	how much byte do we want to read
+ * @return:	0 in case of success
+ */
+int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
+{
+	int ret = 0;
+	uint32_t counter = 0;
+
+	do {
+		if (ret != -EAGAIN && ret) {
+			ERROR("i2c transaction failed\n");
+			mentor_i2c_stop_bit_set();
+			return ret;
+		}
+		/* wait for 1 us for the interrupt clear to take effect */
+		if (counter > 0)
+			udelay(1);
+		counter++;
+
+		ret = mentor_i2c_start_bit_set();
+		if (ret) {
+			ret = mentor_i2c_unstuck(ret);
+			continue;
+		}
+
+		ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
+		if (ret)
+			continue;
+
+		/* if EEPROM device */
+		if (alen != 0) {
+			ret = mentor_i2c_target_offset_set(chip, addr, alen);
+			if (ret)
+				continue;
+		}
+
+		ret = mentor_i2c_data_transmit(buffer, len);
+		if (ret)
+			continue;
+
+		ret = mentor_i2c_stop_bit_set();
+	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
+
+	if (counter == I2C_MAX_RETRY_CNT) {
+		ERROR("I2C transactions failed, got EAGAIN %d times\n",
+		      I2C_MAX_RETRY_CNT);
+		ret = -EPERM;
+	}
+
+	udelay(1);
+	return ret;
+}
diff --git a/drivers/meson/console/aarch64/meson_console.S b/drivers/meson/console/aarch64/meson_console.S
new file mode 100644
index 0000000..22d0773
--- /dev/null
+++ b/drivers/meson/console/aarch64/meson_console.S
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/meson/meson_console.h>
+
+	.globl console_meson_register
+	.globl console_meson_init
+	.globl console_meson_putc
+	.globl console_meson_getc
+	.globl console_meson_flush
+	.globl console_meson_core_putc
+	.globl console_meson_core_getc
+	.globl console_meson_core_flush
+
+	/* -----------------------------------------------
+	 * Hardware definitions
+	 * -----------------------------------------------
+	 */
+#define MESON_WFIFO_OFFSET			0x0
+#define MESON_RFIFO_OFFSET			0x4
+#define MESON_CONTROL_OFFSET			0x8
+#define MESON_STATUS_OFFSET			0xC
+#define MESON_MISC_OFFSET			0x10
+#define MESON_REG5_OFFSET			0x14
+
+#define MESON_CONTROL_CLR_ERROR_BIT		24
+#define MESON_CONTROL_RX_RESET_BIT		23
+#define MESON_CONTROL_TX_RESET_BIT		22
+#define MESON_CONTROL_RX_ENABLE_BIT		13
+#define MESON_CONTROL_TX_ENABLE_BIT		12
+
+#define MESON_STATUS_RX_EMPTY_BIT		20
+#define MESON_STATUS_TX_FULL_BIT		21
+#define MESON_STATUS_TX_EMPTY_BIT		22
+
+#define MESON_REG5_USE_XTAL_CLK_BIT		24
+#define MESON_REG5_USE_NEW_RATE_BIT		23
+#define MESON_REG5_NEW_BAUD_RATE_MASK		0x7FFFFF
+
+	/* -----------------------------------------------
+	 * int console_meson_register(uintptr_t base,
+	 *     uint32_t clk, uint32_t baud,
+	 *     console_meson_t *console);
+	 * Function to initialize and register a new MESON
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_meson_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_meson_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_MESON_BASE]
+
+	bl	console_meson_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register meson putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_meson_register
+
+	/* -----------------------------------------------
+	 * int console_meson_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : x0-x3
+	 * -----------------------------------------------
+	 */
+func console_meson_init
+	cmp	w0, #0
+	beq	init_fail
+	mov_imm	w3, 24000000 /* TODO: This only works with a 24 MHz clock. */
+	cmp	w1, w3
+	bne	init_fail
+	cmp	w2, #0
+	beq	init_fail
+	/* Set baud rate: value = ((clock / 3) / baudrate) - 1 */
+	mov	w3, #3
+	udiv	w3, w1, w3
+	udiv	w3, w3, w2
+	sub	w3, w3, #1
+	orr	w3, w3, #((1 << MESON_REG5_USE_XTAL_CLK_BIT) | \
+			  (1 << MESON_REG5_USE_NEW_RATE_BIT))
+	str	w3, [x0, #MESON_REG5_OFFSET]
+	/* Reset UART and clear error flag */
+	ldr	w3, [x0, #MESON_CONTROL_OFFSET]
+	orr	w3, w3, #((1 << MESON_CONTROL_CLR_ERROR_BIT) | \
+			  (1 << MESON_CONTROL_RX_RESET_BIT) | \
+			  (1 << MESON_CONTROL_TX_RESET_BIT))
+	str	w3, [x0, #MESON_CONTROL_OFFSET]
+	bic	w3, w3, #((1 << MESON_CONTROL_CLR_ERROR_BIT) | \
+			  (1 << MESON_CONTROL_RX_RESET_BIT) | \
+			  (1 << MESON_CONTROL_TX_RESET_BIT))
+	str	w3, [x0, #MESON_CONTROL_OFFSET]
+	/* Enable transfer and receive FIFO */
+	orr	w3, w3, #((1 << MESON_CONTROL_RX_ENABLE_BIT) | \
+			  (1 << MESON_CONTROL_TX_ENABLE_BIT))
+	str	w3, [x0, #MESON_CONTROL_OFFSET]
+	/* Success */
+	mov	w0, #1
+	ret
+init_fail:
+	mov	w0, wzr
+	ret
+endfunc console_meson_init
+
+	/* --------------------------------------------------------
+	 * int console_meson_putc(int c, console_meson_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_meson_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_MESON_BASE]
+	b	console_meson_core_putc
+endfunc console_meson_putc
+
+	/* --------------------------------------------------------
+	 * int console_meson_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_meson_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+	/* Wait until the transmit FIFO isn't full */
+1:	ldr	w2, [x1, #MESON_STATUS_OFFSET]
+	tbnz	w2, #MESON_STATUS_TX_FULL_BIT, 1b
+	/* Write '\r' if needed */
+	mov	w2, #0xD
+	str	w2, [x1, #MESON_WFIFO_OFFSET]
+	/* Wait until the transmit FIFO isn't full */
+2:	ldr	w2, [x1, #MESON_STATUS_OFFSET]
+	tbnz	w2, #MESON_STATUS_TX_FULL_BIT, 2b
+	/* Write input character */
+	str	w0, [x1, #MESON_WFIFO_OFFSET]
+	ret
+endfunc console_meson_core_putc
+
+	/* ---------------------------------------------
+	 * int console_meson_getc(console_meson_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - pointer to console_t structure
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_meson_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_MESON_BASE]
+	b	console_meson_core_getc
+endfunc console_meson_getc
+
+	/* ---------------------------------------------
+	 * int console_meson_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - console base address
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_meson_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+	/* Is the receive FIFO empty? */
+	ldr	w1, [x0, #MESON_STATUS_OFFSET]
+	tbnz	w1, #MESON_STATUS_RX_EMPTY_BIT, 1f
+	/* Read one character from the RX FIFO */
+	ldr	w0, [x0, #MESON_RFIFO_OFFSET]
+	ret
+1:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+endfunc console_meson_core_getc
+
+	/* ---------------------------------------------
+	 * int console_meson_flush(console_meson_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_meson_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_MESON_BASE]
+	b	console_meson_core_flush
+endfunc console_meson_flush
+
+	/* ---------------------------------------------
+	 * int console_meson_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_meson_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+	/* Wait until the transmit FIFO is empty */
+1:	ldr	w1, [x0, #MESON_STATUS_OFFSET]
+	tbz	w1, #MESON_STATUS_TX_EMPTY_BIT, 1b
+	mov	w0, #0
+	ret
+endfunc console_meson_core_flush
diff --git a/drivers/meson/gxl/crypto/sha_dma.c b/drivers/meson/gxl/crypto/sha_dma.c
new file mode 100644
index 0000000..a969dea
--- /dev/null
+++ b/drivers/meson/gxl/crypto/sha_dma.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <crypto/sha_dma.h>
+
+#define AML_SHA_DMA_BASE 0xc883e000
+
+#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18)
+
+#define ASD_MODE_SHA224 0x7
+#define ASD_MODE_SHA256 0x6
+
+/* SHA DMA descriptor */
+struct asd_desc {
+	uint32_t cfg;
+	uint32_t src;
+	uint32_t dst;
+};
+#define ASD_DESC_GET(x, msk, off) (((x) >> (off)) & (msk))
+#define ASD_DESC_SET(x, v, msk, off)					\
+	((x) = ((x) & ~((msk) << (off))) | (((v) & (msk)) << (off)))
+
+#define ASD_DESC_LEN_OFF 0
+#define ASD_DESC_LEN_MASK 0x1ffff
+#define ASD_DESC_LEN(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF))
+#define ASD_DESC_LEN_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF))
+
+#define ASD_DESC_IRQ_OFF 17
+#define ASD_DESC_IRQ_MASK 0x1
+#define ASD_DESC_IRQ(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF))
+#define ASD_DESC_IRQ_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF))
+
+#define ASD_DESC_EOD_OFF 18
+#define ASD_DESC_EOD_MASK 0x1
+#define ASD_DESC_EOD(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF))
+#define ASD_DESC_EOD_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF))
+
+#define ASD_DESC_LOOP_OFF 19
+#define ASD_DESC_LOOP_MASK 0x1
+#define ASD_DESC_LOOP(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF))
+#define ASD_DESC_LOOP_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF))
+
+#define ASD_DESC_MODE_OFF 20
+#define ASD_DESC_MODE_MASK 0xf
+#define ASD_DESC_MODE(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF))
+#define ASD_DESC_MODE_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF))
+
+#define ASD_DESC_BEGIN_OFF 24
+#define ASD_DESC_BEGIN_MASK 0x1
+#define ASD_DESC_BEGIN(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF))
+#define ASD_DESC_BEGIN_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF))
+
+#define ASD_DESC_END_OFF 25
+#define ASD_DESC_END_MASK 0x1
+#define ASD_DESC_END(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_END_MASK, ASD_DESC_END_OFF))
+#define ASD_DESC_END_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_END_MASK, ASD_DESC_END_OFF))
+
+#define ASD_DESC_OP_OFF 26
+#define ASD_DESC_OP_MASK 0x2
+#define ASD_DESC_OP(d)							\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF))
+#define ASD_DESC_OP_SET(d, v)						\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF))
+
+#define ASD_DESC_ENCONLY_OFF 28
+#define ASD_DESC_ENCONLY_MASK 0x1
+#define ASD_DESC_ENCONLY(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF))
+#define ASD_DESC_ENCONLY_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF))
+
+#define ASD_DESC_BLOCK_OFF 29
+#define ASD_DESC_BLOCK_MASK 0x1
+#define ASD_DESC_BLOCK(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF))
+#define ASD_DESC_BLOCK_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF))
+
+#define ASD_DESC_ERR_OFF 30
+#define ASD_DESC_ERR_MASK 0x1
+#define ASD_DESC_ERR(d)						\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF))
+#define ASD_DESC_ERR_SET(d, v)					\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF))
+
+#define ASD_DESC_OWNER_OFF 31u
+#define ASD_DESC_OWNER_MASK 0x1u
+#define ASD_DESC_OWNER(d)					\
+	(ASD_DESC_GET((d)->cfg, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF))
+#define ASD_DESC_OWNER_SET(d, v)				\
+	(ASD_DESC_SET((d)->cfg, v, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF))
+
+static void asd_compute_sha(struct asd_ctx *ctx, void *data, size_t len,
+		int finalize)
+{
+	/* Make it cache line size aligned ? */
+	struct asd_desc desc = {
+		.src = (uint32_t)(uintptr_t)data,
+		.dst = (uint32_t)(uintptr_t)ctx->digest,
+	};
+
+	/* Check data address is 32bit compatible */
+	assert((uintptr_t)data == (uintptr_t)desc.src);
+	assert((uintptr_t)ctx->digest == (uintptr_t)desc.dst);
+	assert((uintptr_t)&desc == (uintptr_t)&desc);
+
+	ASD_DESC_LEN_SET(&desc, len);
+	ASD_DESC_OWNER_SET(&desc, 1u);
+	ASD_DESC_ENCONLY_SET(&desc, 1);
+	ASD_DESC_EOD_SET(&desc, 1);
+	if (ctx->started == 0) {
+		ASD_DESC_BEGIN_SET(&desc, 1);
+		ctx->started = 1;
+	}
+	if (finalize) {
+		ASD_DESC_END_SET(&desc, 1);
+		ctx->started = 0;
+	}
+	if (ctx->mode == ASM_SHA224)
+		ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA224);
+	else
+		ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA256);
+
+	flush_dcache_range((uintptr_t)&desc, sizeof(desc));
+	flush_dcache_range((uintptr_t)data, len);
+
+	mmio_write_32(AML_SHA_DMA_STATUS, 0xf);
+	mmio_write_32(AML_SHA_DMA_DESC, ((uintptr_t)&desc) | 2);
+	while (mmio_read_32(AML_SHA_DMA_STATUS) == 0)
+		continue;
+	flush_dcache_range((uintptr_t)ctx->digest, SHA256_HASHSZ);
+}
+
+void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len)
+{
+	size_t nr;
+
+	if (ctx->blocksz) {
+		nr = MIN(len, SHA256_BLOCKSZ - ctx->blocksz);
+		memcpy(ctx->block + ctx->blocksz, data, nr);
+		ctx->blocksz += nr;
+		len -= nr;
+		data += nr;
+	}
+
+	if (ctx->blocksz == SHA256_BLOCKSZ) {
+		asd_compute_sha(ctx, ctx->block, SHA256_BLOCKSZ, 0);
+		ctx->blocksz = 0;
+	}
+
+	asd_compute_sha(ctx, data, len & ~(SHA256_BLOCKSZ - 1), 0);
+	data += len & ~(SHA256_BLOCKSZ - 1);
+
+	if (len & (SHA256_BLOCKSZ - 1)) {
+		nr = len & (SHA256_BLOCKSZ - 1);
+		memcpy(ctx->block + ctx->blocksz, data, nr);
+		ctx->blocksz += nr;
+	}
+}
+
+void asd_sha_finalize(struct asd_ctx *ctx)
+{
+	asd_compute_sha(ctx, ctx->block, ctx->blocksz, 1);
+}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
new file mode 100644
index 0000000..db6f3f9
--- /dev/null
+++ b/drivers/mmc/mmc.c
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Define a simple and generic interface to access eMMC and SD-card devices. */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <lib/utils.h>
+
+#define MMC_DEFAULT_MAX_RETRIES		5
+#define SEND_OP_COND_MAX_RETRIES	100
+
+#define MULT_BY_512K_SHIFT		19
+
+static const struct mmc_ops *ops;
+static unsigned int mmc_ocr_value;
+static struct mmc_csd_emmc mmc_csd;
+static unsigned char mmc_ext_csd[512] __aligned(16);
+static unsigned int mmc_flags;
+static struct mmc_device_info *mmc_dev_info;
+static unsigned int rca;
+static unsigned int scr[2]__aligned(16) = { 0 };
+
+static const unsigned char tran_speed_base[16] = {
+	0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
+};
+
+static const unsigned char sd_tran_speed_base[16] = {
+	0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
+};
+
+static bool is_cmd23_enabled(void)
+{
+	return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
+}
+
+static int mmc_send_cmd(unsigned int idx, unsigned int arg,
+			unsigned int r_type, unsigned int *r_data)
+{
+	struct mmc_cmd cmd;
+	int ret;
+
+	zeromem(&cmd, sizeof(struct mmc_cmd));
+
+	cmd.cmd_idx = idx;
+	cmd.cmd_arg = arg;
+	cmd.resp_type = r_type;
+
+	ret = ops->send_cmd(&cmd);
+
+	if ((ret == 0) && (r_data != NULL)) {
+		int i;
+
+		for (i = 0; i < 4; i++) {
+			*r_data = cmd.resp_data[i];
+			r_data++;
+		}
+	}
+
+	if (ret != 0) {
+		VERBOSE("Send command %u error: %d\n", idx, ret);
+	}
+
+	return ret;
+}
+
+static int mmc_device_state(void)
+{
+	int retries = MMC_DEFAULT_MAX_RETRIES;
+	unsigned int resp_data[4];
+
+	do {
+		int ret;
+
+		if (retries == 0) {
+			ERROR("CMD13 failed after %d retries\n",
+			      MMC_DEFAULT_MAX_RETRIES);
+			return -EIO;
+		}
+
+		ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
+				   MMC_RESPONSE_R1, &resp_data[0]);
+		if (ret != 0) {
+			retries--;
+			continue;
+		}
+
+		if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
+			return -EIO;
+		}
+
+		retries--;
+	} while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
+
+	return MMC_GET_STATE(resp_data[0]);
+}
+
+static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
+{
+	int ret;
+
+	ret = mmc_send_cmd(MMC_CMD(6),
+			   EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
+			   EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL,
+			   MMC_RESPONSE_R1B, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	do {
+		ret = mmc_device_state();
+		if (ret < 0) {
+			return ret;
+		}
+	} while (ret == MMC_STATE_PRG);
+
+	return 0;
+}
+
+static int mmc_sd_switch(unsigned int bus_width)
+{
+	int ret;
+	int retries = MMC_DEFAULT_MAX_RETRIES;
+	unsigned int bus_width_arg = 0;
+
+	ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr));
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* CMD55: Application Specific Command */
+	ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
+			   MMC_RESPONSE_R5, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* ACMD51: SEND_SCR */
+	do {
+		ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL);
+		if ((ret != 0) && (retries == 0)) {
+			ERROR("ACMD51 failed after %d retries (ret=%d)\n",
+			      MMC_DEFAULT_MAX_RETRIES, ret);
+			return ret;
+		}
+
+		retries--;
+	} while (ret != 0);
+
+	ret = ops->read(0, (uintptr_t)&scr, sizeof(scr));
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) &&
+	    (bus_width == MMC_BUS_WIDTH_4)) {
+		bus_width_arg = 2;
+	}
+
+	/* CMD55: Application Specific Command */
+	ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
+			   MMC_RESPONSE_R5, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* ACMD6: SET_BUS_WIDTH */
+	ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	do {
+		ret = mmc_device_state();
+		if (ret < 0) {
+			return ret;
+		}
+	} while (ret == MMC_STATE_PRG);
+
+	return 0;
+}
+
+static int mmc_set_ios(unsigned int clk, unsigned int bus_width)
+{
+	int ret;
+	unsigned int width = bus_width;
+
+	if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) {
+		if (width == MMC_BUS_WIDTH_8) {
+			WARN("Wrong bus config for SD-card, force to 4\n");
+			width = MMC_BUS_WIDTH_4;
+		}
+		ret = mmc_sd_switch(width);
+		if (ret != 0) {
+			return ret;
+		}
+	} else if (mmc_csd.spec_vers == 4U) {
+		ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH,
+				      (unsigned int)width);
+		if (ret != 0) {
+			return ret;
+		}
+	} else {
+		VERBOSE("Wrong MMC type or spec version\n");
+	}
+
+	return ops->set_ios(clk, width);
+}
+
+static int mmc_fill_device_info(void)
+{
+	unsigned long long c_size;
+	unsigned int speed_idx;
+	unsigned int nb_blocks;
+	unsigned int freq_unit;
+	int ret = 0;
+	struct mmc_csd_sd_v2 *csd_sd_v2;
+
+	switch (mmc_dev_info->mmc_dev_type) {
+	case MMC_IS_EMMC:
+		mmc_dev_info->block_size = MMC_BLOCK_SIZE;
+
+		ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd,
+				   sizeof(mmc_ext_csd));
+		if (ret != 0) {
+			return ret;
+		}
+
+		/* MMC CMD8: SEND_EXT_CSD */
+		ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL);
+		if (ret != 0) {
+			return ret;
+		}
+
+		ret = ops->read(0, (uintptr_t)&mmc_ext_csd,
+				sizeof(mmc_ext_csd));
+		if (ret != 0) {
+			return ret;
+		}
+
+		do {
+			ret = mmc_device_state();
+			if (ret < 0) {
+				return ret;
+			}
+		} while (ret != MMC_STATE_TRAN);
+
+		nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
+			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
+			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
+			    (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
+
+		mmc_dev_info->device_size = (unsigned long long)nb_blocks *
+			mmc_dev_info->block_size;
+
+		break;
+
+	case MMC_IS_SD:
+		/*
+		 * Use the same mmc_csd struct, as required fields here
+		 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
+		 */
+		mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
+
+		c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
+			 (unsigned long long)mmc_csd.c_size_low;
+		assert(c_size != 0xFFFU);
+
+		mmc_dev_info->device_size = (c_size + 1U) *
+					    BIT_64(mmc_csd.c_size_mult + 2U) *
+					    mmc_dev_info->block_size;
+
+		break;
+
+	case MMC_IS_SD_HC:
+		assert(mmc_csd.csd_structure == 1U);
+
+		mmc_dev_info->block_size = MMC_BLOCK_SIZE;
+
+		/* Need to use mmc_csd_sd_v2 struct */
+		csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
+		c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
+			 (unsigned long long)csd_sd_v2->c_size_low;
+
+		mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
+
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret < 0) {
+		return ret;
+	}
+
+	speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
+			 CSD_TRAN_SPEED_MULT_SHIFT;
+
+	assert(speed_idx > 0U);
+
+	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
+		mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
+	} else {
+		mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
+	}
+
+	freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
+	while (freq_unit != 0U) {
+		mmc_dev_info->max_bus_freq *= 10U;
+		--freq_unit;
+	}
+
+	mmc_dev_info->max_bus_freq *= 10000U;
+
+	return 0;
+}
+
+static int sd_send_op_cond(void)
+{
+	int n;
+	unsigned int resp_data[4];
+
+	for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
+		int ret;
+
+		/* CMD55: Application Specific Command */
+		ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL);
+		if (ret != 0) {
+			return ret;
+		}
+
+		/* ACMD41: SD_SEND_OP_COND */
+		ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS |
+			mmc_dev_info->ocr_voltage, MMC_RESPONSE_R3,
+			&resp_data[0]);
+		if (ret != 0) {
+			return ret;
+		}
+
+		if ((resp_data[0] & OCR_POWERUP) != 0U) {
+			mmc_ocr_value = resp_data[0];
+
+			if ((mmc_ocr_value & OCR_HCS) != 0U) {
+				mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
+			} else {
+				mmc_dev_info->mmc_dev_type = MMC_IS_SD;
+			}
+
+			return 0;
+		}
+
+		mdelay(1);
+	}
+
+	ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static int mmc_reset_to_idle(void)
+{
+	int ret;
+
+	/* CMD0: reset to IDLE */
+	ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	mdelay(2);
+
+	return 0;
+}
+
+static int mmc_send_op_cond(void)
+{
+	int ret, n;
+	unsigned int resp_data[4];
+
+	ret = mmc_reset_to_idle();
+	if (ret != 0) {
+		return ret;
+	};
+
+	for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
+		ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
+				   OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
+				   MMC_RESPONSE_R3, &resp_data[0]);
+		if (ret != 0) {
+			return ret;
+		}
+
+		if ((resp_data[0] & OCR_POWERUP) != 0U) {
+			mmc_ocr_value = resp_data[0];
+			return 0;
+		}
+
+		mdelay(10);
+	}
+
+	ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
+
+	return -EIO;
+}
+
+static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
+{
+	int ret;
+	unsigned int resp_data[4];
+
+	ops->init();
+
+	ret = mmc_reset_to_idle();
+	if (ret != 0) {
+		return ret;
+	};
+
+	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
+		ret = mmc_send_op_cond();
+	} else {
+		/* CMD8: Send Interface Condition Command */
+		ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
+				   MMC_RESPONSE_R5, &resp_data[0]);
+
+		if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
+			ret = sd_send_op_cond();
+		}
+	}
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* CMD2: Card Identification */
+	ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* CMD3: Set Relative Address */
+	if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
+		rca = MMC_FIX_RCA;
+		ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
+				   MMC_RESPONSE_R1, NULL);
+		if (ret != 0) {
+			return ret;
+		}
+	} else {
+		ret = mmc_send_cmd(MMC_CMD(3), 0,
+				   MMC_RESPONSE_R6, &resp_data[0]);
+		if (ret != 0) {
+			return ret;
+		}
+
+		rca = (resp_data[0] & 0xFFFF0000U) >> 16;
+	}
+
+	/* CMD9: CSD Register */
+	ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
+			   MMC_RESPONSE_R2, &resp_data[0]);
+	if (ret != 0) {
+		return ret;
+	}
+
+	memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
+
+	/* CMD7: Select Card */
+	ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
+			   MMC_RESPONSE_R1, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	do {
+		ret = mmc_device_state();
+		if (ret < 0) {
+			return ret;
+		}
+	} while (ret != MMC_STATE_TRAN);
+
+	ret = mmc_set_ios(clk, bus_width);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return mmc_fill_device_info();
+}
+
+size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
+{
+	int ret;
+	unsigned int cmd_idx, cmd_arg;
+
+	assert((ops != NULL) &&
+	       (ops->read != NULL) &&
+	       (size != 0U) &&
+	       ((size & MMC_BLOCK_MASK) == 0U));
+
+	ret = ops->prepare(lba, buf, size);
+	if (ret != 0) {
+		return 0;
+	}
+
+	if (is_cmd23_enabled()) {
+		/* Set block count */
+		ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
+				   MMC_RESPONSE_R1, NULL);
+		if (ret != 0) {
+			return 0;
+		}
+
+		cmd_idx = MMC_CMD(18);
+	} else {
+		if (size > MMC_BLOCK_SIZE) {
+			cmd_idx = MMC_CMD(18);
+		} else {
+			cmd_idx = MMC_CMD(17);
+		}
+	}
+
+	if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
+	    (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
+		cmd_arg = lba * MMC_BLOCK_SIZE;
+	} else {
+		cmd_arg = lba;
+	}
+
+	ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
+	if (ret != 0) {
+		return 0;
+	}
+
+	ret = ops->read(lba, buf, size);
+	if (ret != 0) {
+		return 0;
+	}
+
+	/* Wait buffer empty */
+	do {
+		ret = mmc_device_state();
+		if (ret < 0) {
+			return 0;
+		}
+	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
+
+	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
+		ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
+		if (ret != 0) {
+			return 0;
+		}
+	}
+
+	return size;
+}
+
+size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
+{
+	int ret;
+	unsigned int cmd_idx, cmd_arg;
+
+	assert((ops != NULL) &&
+	       (ops->write != NULL) &&
+	       (size != 0U) &&
+	       ((buf & MMC_BLOCK_MASK) == 0U) &&
+	       ((size & MMC_BLOCK_MASK) == 0U));
+
+	ret = ops->prepare(lba, buf, size);
+	if (ret != 0) {
+		return 0;
+	}
+
+	if (is_cmd23_enabled()) {
+		/* Set block count */
+		ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
+				   MMC_RESPONSE_R1, NULL);
+		if (ret != 0) {
+			return 0;
+		}
+
+		cmd_idx = MMC_CMD(25);
+	} else {
+		if (size > MMC_BLOCK_SIZE) {
+			cmd_idx = MMC_CMD(25);
+		} else {
+			cmd_idx = MMC_CMD(24);
+		}
+	}
+
+	if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
+		cmd_arg = lba * MMC_BLOCK_SIZE;
+	} else {
+		cmd_arg = lba;
+	}
+
+	ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
+	if (ret != 0) {
+		return 0;
+	}
+
+	ret = ops->write(lba, buf, size);
+	if (ret != 0) {
+		return 0;
+	}
+
+	/* Wait buffer empty */
+	do {
+		ret = mmc_device_state();
+		if (ret < 0) {
+			return 0;
+		}
+	} while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
+
+	if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
+		ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
+		if (ret != 0) {
+			return 0;
+		}
+	}
+
+	return size;
+}
+
+size_t mmc_erase_blocks(int lba, size_t size)
+{
+	int ret;
+
+	assert(ops != NULL);
+	assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
+
+	ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
+	if (ret != 0) {
+		return 0;
+	}
+
+	ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
+			   MMC_RESPONSE_R1, NULL);
+	if (ret != 0) {
+		return 0;
+	}
+
+	ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
+	if (ret != 0) {
+		return 0;
+	}
+
+	do {
+		ret = mmc_device_state();
+		if (ret < 0) {
+			return 0;
+		}
+	} while (ret != MMC_STATE_TRAN);
+
+	return size;
+}
+
+static inline void mmc_rpmb_enable(void)
+{
+	mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
+			PART_CFG_BOOT_PARTITION1_ENABLE |
+			PART_CFG_PARTITION1_ACCESS);
+}
+
+static inline void mmc_rpmb_disable(void)
+{
+	mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
+			PART_CFG_BOOT_PARTITION1_ENABLE);
+}
+
+size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
+{
+	size_t size_read;
+
+	mmc_rpmb_enable();
+	size_read = mmc_read_blocks(lba, buf, size);
+	mmc_rpmb_disable();
+
+	return size_read;
+}
+
+size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
+{
+	size_t size_written;
+
+	mmc_rpmb_enable();
+	size_written = mmc_write_blocks(lba, buf, size);
+	mmc_rpmb_disable();
+
+	return size_written;
+}
+
+size_t mmc_rpmb_erase_blocks(int lba, size_t size)
+{
+	size_t size_erased;
+
+	mmc_rpmb_enable();
+	size_erased = mmc_erase_blocks(lba, size);
+	mmc_rpmb_disable();
+
+	return size_erased;
+}
+
+int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
+	     unsigned int width, unsigned int flags,
+	     struct mmc_device_info *device_info)
+{
+	assert((ops_ptr != NULL) &&
+	       (ops_ptr->init != NULL) &&
+	       (ops_ptr->send_cmd != NULL) &&
+	       (ops_ptr->set_ios != NULL) &&
+	       (ops_ptr->prepare != NULL) &&
+	       (ops_ptr->read != NULL) &&
+	       (ops_ptr->write != NULL) &&
+	       (device_info != NULL) &&
+	       (clk != 0) &&
+	       ((width == MMC_BUS_WIDTH_1) ||
+		(width == MMC_BUS_WIDTH_4) ||
+		(width == MMC_BUS_WIDTH_8) ||
+		(width == MMC_BUS_WIDTH_DDR_4) ||
+		(width == MMC_BUS_WIDTH_DDR_8)));
+
+	ops = ops_ptr;
+	mmc_flags = flags;
+	mmc_dev_info = device_info;
+
+	return mmc_enumerate(clk, width);
+}
diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c
new file mode 100644
index 0000000..4577f06
--- /dev/null
+++ b/drivers/partition/gpt.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/partition/gpt.h>
+#include <lib/utils.h>
+
+static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out)
+{
+	uint8_t *name;
+	int i;
+
+	assert((str_in != NULL) && (str_out != NULL));
+
+	name = (uint8_t *)str_in;
+
+	assert(name[0] != '\0');
+
+	/* check whether the unicode string is valid */
+	for (i = 1; i < (EFI_NAMELEN << 1); i += 2) {
+		if (name[i] != '\0')
+			return -EINVAL;
+	}
+	/* convert the unicode string to ascii string */
+	for (i = 0; i < (EFI_NAMELEN << 1); i += 2) {
+		str_out[i >> 1] = name[i];
+		if (name[i] == '\0')
+			break;
+	}
+	return 0;
+}
+
+int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry)
+{
+	int result;
+
+	assert((gpt_entry != NULL) && (entry != NULL));
+
+	if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) {
+		return -EINVAL;
+	}
+
+	zeromem(entry, sizeof(partition_entry_t));
+	result = unicode_to_ascii(gpt_entry->name, (uint8_t *)entry->name);
+	if (result != 0) {
+		return result;
+	}
+	entry->start = (uint64_t)gpt_entry->first_lba * PARTITION_BLOCK_SIZE;
+	entry->length = (uint64_t)(gpt_entry->last_lba -
+				   gpt_entry->first_lba + 1) *
+			PARTITION_BLOCK_SIZE;
+	return 0;
+}
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
new file mode 100644
index 0000000..7fdbf53
--- /dev/null
+++ b/drivers/partition/partition.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/partition/partition.h>
+#include <drivers/partition/gpt.h>
+#include <drivers/partition/mbr.h>
+#include <plat/common/platform.h>
+
+static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
+static partition_entry_list_t list;
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+static void dump_entries(int num)
+{
+	char name[EFI_NAMELEN];
+	int i, j, len;
+
+	VERBOSE("Partition table with %d entries:\n", num);
+	for (i = 0; i < num; i++) {
+		len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name);
+		for (j = 0; j < EFI_NAMELEN - len - 1; j++) {
+			name[len + j] = ' ';
+		}
+		name[EFI_NAMELEN - 1] = '\0';
+		VERBOSE("%d: %s %llx-%llx\n", i + 1, name, list.list[i].start,
+			list.list[i].start + list.list[i].length - 4);
+	}
+}
+#else
+#define dump_entries(num)	((void)num)
+#endif
+
+/*
+ * Load the first sector that carries MBR header.
+ * The MBR boot signature should be always valid whether it's MBR or GPT.
+ */
+static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry)
+{
+	size_t bytes_read;
+	uintptr_t offset;
+	int result;
+
+	assert(mbr_entry != NULL);
+	/* MBR partition table is in LBA0. */
+	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
+	if (result != 0) {
+		WARN("Failed to seek (%i)\n", result);
+		return result;
+	}
+	result = io_read(image_handle, (uintptr_t)&mbr_sector,
+			 PARTITION_BLOCK_SIZE, &bytes_read);
+	if (result != 0) {
+		WARN("Failed to read data (%i)\n", result);
+		return result;
+	}
+
+	/* Check MBR boot signature. */
+	if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
+	    (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+		return -ENOENT;
+	}
+	offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET;
+	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
+	return 0;
+}
+
+/*
+ * Load GPT header and check the GPT signature.
+ * If partition numbers could be found, check & update it.
+ */
+static int load_gpt_header(uintptr_t image_handle)
+{
+	gpt_header_t header;
+	size_t bytes_read;
+	int result;
+
+	result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET);
+	if (result != 0) {
+		return result;
+	}
+	result = io_read(image_handle, (uintptr_t)&header,
+			 sizeof(gpt_header_t), &bytes_read);
+	if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) {
+		return result;
+	}
+	if (memcmp(header.signature, GPT_SIGNATURE,
+		   sizeof(header.signature)) != 0) {
+		return -EINVAL;
+	}
+
+	/* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */
+	list.entry_count = header.list_num;
+	if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) {
+		list.entry_count = PLAT_PARTITION_MAX_ENTRIES;
+	}
+	return 0;
+}
+
+static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry,
+			int part_number)
+{
+	size_t bytes_read;
+	uintptr_t offset;
+	int result;
+
+	assert(mbr_entry != NULL);
+	/* MBR partition table is in LBA0. */
+	result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET);
+	if (result != 0) {
+		WARN("Failed to seek (%i)\n", result);
+		return result;
+	}
+	result = io_read(image_handle, (uintptr_t)&mbr_sector,
+			 PARTITION_BLOCK_SIZE, &bytes_read);
+	if (result != 0) {
+		WARN("Failed to read data (%i)\n", result);
+		return result;
+	}
+
+	/* Check MBR boot signature. */
+	if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) ||
+	    (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) {
+		return -ENOENT;
+	}
+	offset = (uintptr_t)&mbr_sector +
+		MBR_PRIMARY_ENTRY_OFFSET +
+		MBR_PRIMARY_ENTRY_SIZE * part_number;
+	memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t));
+
+	return 0;
+}
+
+static int load_mbr_entries(uintptr_t image_handle)
+{
+	mbr_entry_t mbr_entry;
+	int i;
+
+	list.entry_count = MBR_PRIMARY_ENTRY_NUMBER;
+
+	for (i = 0; i < list.entry_count; i++) {
+		load_mbr_entry(image_handle, &mbr_entry, i);
+		list.list[i].start = mbr_entry.first_lba * 512;
+		list.list[i].length = mbr_entry.sector_nums * 512;
+		list.list[i].name[0] = mbr_entry.type;
+	}
+
+	return 0;
+}
+
+static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry)
+{
+	size_t bytes_read;
+	int result;
+
+	assert(entry != NULL);
+	result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t),
+			 &bytes_read);
+	if (sizeof(gpt_entry_t) != bytes_read)
+		return -EINVAL;
+	return result;
+}
+
+static int verify_partition_gpt(uintptr_t image_handle)
+{
+	gpt_entry_t entry;
+	int result, i;
+
+	for (i = 0; i < list.entry_count; i++) {
+		result = load_gpt_entry(image_handle, &entry);
+		assert(result == 0);
+		result = parse_gpt_entry(&entry, &list.list[i]);
+		if (result != 0) {
+			break;
+		}
+	}
+	if (i == 0) {
+		return -EINVAL;
+	}
+	/*
+	 * Only records the valid partition number that is loaded from
+	 * partition table.
+	 */
+	list.entry_count = i;
+	dump_entries(list.entry_count);
+
+	return 0;
+}
+
+int load_partition_table(unsigned int image_id)
+{
+	uintptr_t dev_handle, image_handle, image_spec = 0;
+	mbr_entry_t mbr_entry;
+	int result;
+
+	result = plat_get_image_source(image_id, &dev_handle, &image_spec);
+	if (result != 0) {
+		WARN("Failed to obtain reference to image id=%u (%i)\n",
+			image_id, result);
+		return result;
+	}
+
+	result = io_open(dev_handle, image_spec, &image_handle);
+	if (result != 0) {
+		WARN("Failed to access image id=%u (%i)\n", image_id, result);
+		return result;
+	}
+
+	result = load_mbr_header(image_handle, &mbr_entry);
+	if (result != 0) {
+		WARN("Failed to access image id=%u (%i)\n", image_id, result);
+		return result;
+	}
+	if (mbr_entry.type == PARTITION_TYPE_GPT) {
+		result = load_gpt_header(image_handle);
+		assert(result == 0);
+		result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET);
+		assert(result == 0);
+		result = verify_partition_gpt(image_handle);
+	} else {
+		result = load_mbr_entries(image_handle);
+	}
+
+	io_close(image_handle);
+	return result;
+}
+
+const partition_entry_t *get_partition_entry(const char *name)
+{
+	int i;
+
+	for (i = 0; i < list.entry_count; i++) {
+		if (strcmp(name, list.list[i].name) == 0) {
+			return &list.list[i];
+		}
+	}
+	return NULL;
+}
+
+const partition_entry_list_t *get_partition_entry_list(void)
+{
+	return &list;
+}
+
+void partition_init(unsigned int image_id)
+{
+	load_partition_table(image_id);
+}
diff --git a/drivers/renesas/rcar/auth/auth_mod.c b/drivers/renesas/rcar/auth/auth_mod.c
new file mode 100644
index 0000000..ece3462
--- /dev/null
+++ b/drivers/renesas/rcar/auth/auth_mod.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "rom_api.h"
+
+typedef int32_t(*secure_boot_api_f) (uint32_t a, uint32_t b, void *c);
+extern int32_t rcar_get_certificate(const int32_t name, uint32_t *cert_addr);
+
+#define	RCAR_IMAGE_ID_MAX	(10)
+#define	RCAR_CERT_MAGIC_NUM	(0xE291F358U)
+#define RCAR_BOOT_KEY_CERT	(0xE6300C00U)
+#define RCAR_BOOT_KEY_CERT_NEW	(0xE6300F00U)
+#define	RST_BASE		(0xE6160000U)
+#define	RST_MODEMR		(RST_BASE + 0x0060U)
+#define	MFISOFTMDR		(0xE6260600U)
+#define	MODEMR_MD5_MASK		(0x00000020U)
+#define	MODEMR_MD5_SHIFT	(5U)
+#define	SOFTMD_BOOTMODE_MASK	(0x00000001U)
+#define	SOFTMD_NORMALBOOT	(0x1U)
+
+static secure_boot_api_f secure_boot_api;
+
+int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id)
+{
+	return 1;
+}
+
+int auth_mod_verify_img(unsigned int img_id, void *ptr, unsigned int len)
+{
+	int32_t ret = 0, index = 0;
+	uint32_t cert_addr = 0U;
+	static const struct img_to_cert_t {
+		uint32_t id;
+		int32_t cert;
+		const char *name;
+	} image[RCAR_IMAGE_ID_MAX] = {
+		{ BL31_IMAGE_ID, SOC_FW_CONTENT_CERT_ID, "BL31" },
+		{ BL32_IMAGE_ID, TRUSTED_OS_FW_CONTENT_CERT_ID, "BL32" },
+		{ BL33_IMAGE_ID, NON_TRUSTED_FW_CONTENT_CERT_ID, "BL33" },
+		{ BL332_IMAGE_ID, BL332_CERT_ID, "BL332" },
+		{ BL333_IMAGE_ID, BL333_CERT_ID, "BL333" },
+		{ BL334_IMAGE_ID, BL334_CERT_ID, "BL334" },
+		{ BL335_IMAGE_ID, BL335_CERT_ID, "BL335" },
+		{ BL336_IMAGE_ID, BL336_CERT_ID, "BL336" },
+		{ BL337_IMAGE_ID, BL337_CERT_ID, "BL337" },
+		{ BL338_IMAGE_ID, BL338_CERT_ID, "BL338" },
+	};
+
+#if IMAGE_BL2
+	switch (img_id) {
+	case TRUSTED_KEY_CERT_ID:
+	case SOC_FW_KEY_CERT_ID:
+	case TRUSTED_OS_FW_KEY_CERT_ID:
+	case NON_TRUSTED_FW_KEY_CERT_ID:
+	case BL332_KEY_CERT_ID:
+	case BL333_KEY_CERT_ID:
+	case BL334_KEY_CERT_ID:
+	case BL335_KEY_CERT_ID:
+	case BL336_KEY_CERT_ID:
+	case BL337_KEY_CERT_ID:
+	case BL338_KEY_CERT_ID:
+	case SOC_FW_CONTENT_CERT_ID:
+	case TRUSTED_OS_FW_CONTENT_CERT_ID:
+	case NON_TRUSTED_FW_CONTENT_CERT_ID:
+	case BL332_CERT_ID:
+	case BL333_CERT_ID:
+	case BL334_CERT_ID:
+	case BL335_CERT_ID:
+	case BL336_CERT_ID:
+	case BL337_CERT_ID:
+	case BL338_CERT_ID:
+		return ret;
+	case BL31_IMAGE_ID:
+	case BL32_IMAGE_ID:
+	case BL33_IMAGE_ID:
+	case BL332_IMAGE_ID:
+	case BL333_IMAGE_ID:
+	case BL334_IMAGE_ID:
+	case BL335_IMAGE_ID:
+	case BL336_IMAGE_ID:
+	case BL337_IMAGE_ID:
+	case BL338_IMAGE_ID:
+		goto verify_image;
+	default:
+		return -1;
+	}
+
+verify_image:
+	for (index = 0; index < RCAR_IMAGE_ID_MAX; index++) {
+		if (img_id != image[index].id)
+			continue;
+
+		ret = rcar_get_certificate(image[index].cert, &cert_addr);
+		break;
+	}
+
+	if (ret || (index == RCAR_IMAGE_ID_MAX)) {
+		ERROR("Verification Failed for image id = %d\n", img_id);
+		return ret;
+	}
+#if RCAR_BL2_DCACHE == 1
+	/* clean and disable */
+	write_sctlr_el3(read_sctlr_el3() & ~SCTLR_C_BIT);
+	dcsw_op_all(DCCISW);
+#endif
+	ret = (mmio_read_32(RCAR_BOOT_KEY_CERT_NEW) == RCAR_CERT_MAGIC_NUM) ?
+	    secure_boot_api(RCAR_BOOT_KEY_CERT_NEW, cert_addr, NULL) :
+	    secure_boot_api(RCAR_BOOT_KEY_CERT, cert_addr, NULL);
+	if (ret)
+		ERROR("Verification Failed 0x%x, %s\n", ret, image[index].name);
+
+#if RCAR_BL2_DCACHE == 1
+	/* enable */
+	write_sctlr_el3(read_sctlr_el3() | SCTLR_C_BIT);
+#endif
+
+#endif
+	return ret;
+}
+
+static int32_t normal_boot_verify(uint32_t a, uint32_t b, void *c)
+{
+	return 0;
+}
+
+void auth_mod_init(void)
+{
+#if RCAR_SECURE_BOOT
+	uint32_t soft_md = mmio_read_32(MFISOFTMDR) & SOFTMD_BOOTMODE_MASK;
+	uint32_t md = mmio_read_32(RST_MODEMR) & MODEMR_MD5_MASK;
+	uint32_t lcs, ret;
+
+	secure_boot_api = (secure_boot_api_f) &rcar_rom_secure_boot_api;
+
+	ret = rcar_rom_get_lcs(&lcs);
+	if (ret) {
+		ERROR("BL2: Failed to get the LCS. (%d)\n", ret);
+		panic();
+	}
+
+	switch (lcs) {
+	case LCS_SE:
+		if (soft_md == SOFTMD_NORMALBOOT)
+			secure_boot_api = &normal_boot_verify;
+		break;
+	case LCS_SD:
+		secure_boot_api = &normal_boot_verify;
+		break;
+	default:
+		if (md >> MODEMR_MD5_SHIFT)
+			secure_boot_api = &normal_boot_verify;
+	}
+
+	NOTICE("BL2: %s boot\n",
+	       secure_boot_api == &normal_boot_verify ? "Normal" : "Secure");
+#else
+	NOTICE("BL2: Normal boot\n");
+	secure_boot_api = &normal_boot_verify;
+#endif
+}
diff --git a/drivers/renesas/rcar/avs/avs_driver.c b/drivers/renesas/rcar/avs/avs_driver.c
new file mode 100644
index 0000000..647869e
--- /dev/null
+++ b/drivers/renesas/rcar/avs/avs_driver.c
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "cpg_registers.h"
+#include "avs_driver.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+
+#if (AVS_SETTING_ENABLE == 1)
+#if PMIC_ROHM_BD9571
+/* Read PMIC register for debug. 1:enable / 0:disable */
+#define AVS_READ_PMIC_REG_ENABLE	0
+/* The re-try number of times of the AVS setting. */
+#define AVS_RETRY_NUM			(1U)
+#endif /* PMIC_ROHM_BD9571 */
+
+/* Base address of Adaptive Voltage Scaling module registers*/
+#define	AVS_BASE			(0xE60A0000U)
+/* Adaptive Dynamic Voltage ADJust Parameter2 registers */
+#define	ADVADJP2			(AVS_BASE + 0x013CU)
+
+/* Mask VOLCOND bit in ADVADJP2 registers */
+#define	ADVADJP2_VOLCOND_MASK		(0x000001FFU)	/* VOLCOND[8:0] */
+
+#if PMIC_ROHM_BD9571
+/* I2C for DVFS bit in CPG registers for module standby and software reset*/
+#define CPG_SYS_DVFS_BIT		(0x04000000U)
+#endif /* PMIC_ROHM_BD9571 */
+/* ADVFS Module bit in CPG registers for module standby and software reset*/
+#define CPG_SYS_ADVFS_BIT		(0x02000000U)
+
+#if PMIC_ROHM_BD9571
+/* Base address of IICDVFS registers*/
+#define	IIC_DVFS_BASE			(0xE60B0000U)
+/* IIC bus data register */
+#define	IIC_ICDR			(IIC_DVFS_BASE + 0x0000U)
+/* IIC bus control register */
+#define	IIC_ICCR			(IIC_DVFS_BASE + 0x0004U)
+/* IIC bus status register */
+#define	IIC_ICSR			(IIC_DVFS_BASE + 0x0008U)
+/* IIC interrupt control register */
+#define	IIC_ICIC			(IIC_DVFS_BASE + 0x000CU)
+/* IIC clock control register low */
+#define	IIC_ICCL			(IIC_DVFS_BASE + 0x0010U)
+/* IIC clock control register high */
+#define	IIC_ICCH			(IIC_DVFS_BASE + 0x0014U)
+
+/* Bit in ICSR register */
+#define ICSR_BUSY			(0x10U)
+#define ICSR_AL				(0x08U)
+#define ICSR_TACK			(0x04U)
+#define ICSR_WAIT			(0x02U)
+#define ICSR_DTE			(0x01U)
+
+/* Bit in ICIC register */
+#define ICIC_TACKE			(0x04U)
+#define ICIC_WAITE			(0x02U)
+#define ICIC_DTEE			(0x01U)
+
+/* I2C bus interface enable */
+#define ICCR_ENABLE			(0x80U)
+/* Start condition */
+#define ICCR_START			(0x94U)
+/* Stop condition */
+#define ICCR_STOP			(0x90U)
+/* Restart condition with change to receive mode change */
+#define ICCR_START_RECV			(0x81U)
+/* Stop condition for receive mode */
+#define ICCR_STOP_RECV			(0xC0U)
+
+/* Low-level period of SCL */
+#define	ICCL_FREQ_8p33M			(0x07U)	/* for CP Phy 8.3333MHz */
+#define	ICCL_FREQ_10M			(0x09U)	/* for CP Phy 10MHz */
+#define	ICCL_FREQ_12p5M			(0x0BU)	/* for CP Phy 12.5MHz */
+#define	ICCL_FREQ_16p66M		(0x0EU)	/* for CP Phy 16.6666MHz */
+/* High-level period of SCL */
+#define	ICCH_FREQ_8p33M			(0x01U)	/* for CP Phy 8.3333MHz */
+#define	ICCH_FREQ_10M			(0x02U)	/* for CP Phy 10MHz */
+#define	ICCH_FREQ_12p5M			(0x03U)	/* for CP Phy 12.5MHz */
+#define	ICCH_FREQ_16p66M		(0x05U)	/* for CP Phy 16.6666MHz */
+
+/* PMIC */
+#define	PMIC_W_SLAVE_ADDRESS		(0x60U)	/* ROHM BD9571 slave address + (W) */
+#define	PMIC_R_SLAVE_ADDRESS		(0x61U)	/* ROHM BD9571 slave address + (R) */
+#define	PMIC_DVFS_SETVID		(0x54U)	/* ROHM BD9571 DVFS SetVID register */
+#endif /* PMIC_ROHM_BD9571  */
+
+/* Individual information */
+#define EFUSE_AVS0			(0U)
+#define EFUSE_AVS_NUM			ARRAY_SIZE(init_vol_tbl)
+
+typedef struct {
+	uint32_t avs;		/* AVS code */
+	uint8_t vol;		/* Voltage */
+} initial_voltage_t;
+
+static const initial_voltage_t init_vol_tbl[] = {
+	/*      AVS code,       RHOM BD9571 DVFS SetVID register */
+	{0x00U, 0x53U},		/* AVS0, 0.83V */
+	{0x01U, 0x52U},		/* AVS1, 0.82V */
+	{0x02U, 0x51U},		/* AVS2, 0.81V */
+	{0x04U, 0x50U},		/* AVS3, 0.80V */
+	{0x08U, 0x4FU},		/* AVS4, 0.79V */
+	{0x10U, 0x4EU},		/* AVS5, 0.78V */
+	{0x20U, 0x4DU},		/* AVS6, 0.77V */
+	{0x40U, 0x4CU}		/* AVS7, 0.76V */
+};
+
+#if PMIC_ROHM_BD9571
+/* Kind of AVS settings status */
+typedef enum {
+	avs_status_none = 0,
+	avs_status_init,
+	avs_status_start_condition,
+	avs_status_set_slave_addr,
+	avs_status_write_reg_addr,
+	avs_status_write_reg_data,
+	avs_status_stop_condition,
+	avs_status_end,
+	avs_status_complete,
+	avs_status_al_start,
+	avs_status_al_transfer,
+	avs_status_nack,
+	avs_status_error_stop,
+	ave_status_error_end
+} avs_status_t;
+
+/* Kind of AVS error */
+typedef enum {
+	avs_error_none = 0,
+	avs_error_al,
+	avs_error_nack
+} avs_error_t;
+
+static avs_status_t avs_status;
+static uint32_t avs_retry;
+#endif /* PMIC_ROHM_BD9571  */
+static uint32_t efuse_avs = EFUSE_AVS0;
+
+#if PMIC_ROHM_BD9571
+/* prototype */
+static avs_error_t avs_check_error(void);
+static void avs_set_iic_clock(void);
+#if AVS_READ_PMIC_REG_ENABLE == 1
+static uint8_t avs_read_pmic_reg(uint8_t addr);
+static void avs_poll(uint8_t bit_pos, uint8_t val);
+#endif
+#endif /* PMIC_ROHM_BD9571 */
+#endif /* (AVS_SETTING_ENABLE==1) */
+
+/*
+ * Initialize to enable the AVS setting.
+ */
+void rcar_avs_init(void)
+{
+#if (AVS_SETTING_ENABLE == 1)
+	uint32_t val;
+
+#if PMIC_ROHM_BD9571
+	/* Initialize AVS status */
+	avs_status = avs_status_init;
+#endif /* PMIC_ROHM_BD9571 */
+
+	/* Enable clock supply to ADVFS. */
+	mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, CPG_SYS_ADVFS_BIT);
+
+	/* Read AVS code (Initial values are derived from eFuse) */
+	val = mmio_read_32(ADVADJP2) & ADVADJP2_VOLCOND_MASK;
+
+	for (efuse_avs = 0U; efuse_avs < EFUSE_AVS_NUM; efuse_avs++) {
+		if (val == init_vol_tbl[efuse_avs].avs)
+			break;
+	}
+
+	if (efuse_avs >= EFUSE_AVS_NUM)
+		efuse_avs = EFUSE_AVS0;	/* Not applicable */
+#if PMIC_ROHM_BD9571
+	/* Enable clock supply to DVFS. */
+	mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, CPG_SYS_DVFS_BIT);
+
+	/* Disable I2C module and All internal registers initialized. */
+	mmio_write_8(IIC_ICCR, 0x00U);
+	while ((mmio_read_8(IIC_ICCR) & ICCR_ENABLE) != 0U) {
+		/* Disable I2C module and All internal registers initialized. */
+		mmio_write_8(IIC_ICCR, 0x00U);
+	}
+
+	/* Set next status */
+	avs_status = avs_status_start_condition;
+
+#endif /* PMIC_ROHM_BD9571 */
+#endif /* (AVS_SETTING_ENABLE==1) */
+}
+
+/*
+ * Set the value of register corresponding to the voltage
+ * by transfer of I2C to PIMC.
+ */
+void rcar_avs_setting(void)
+{
+#if (AVS_SETTING_ENABLE == 1)
+#if PMIC_ROHM_BD9571
+	avs_error_t err;
+
+	switch (avs_status) {
+	case avs_status_start_condition:
+		/* Set ICCR.ICE=1 to activate the I2C module. */
+		mmio_write_8(IIC_ICCR, mmio_read_8(IIC_ICCR) | ICCR_ENABLE);
+		/* Set frequency of 400kHz */
+		avs_set_iic_clock();
+		/* Set ICIC.TACKE=1, ICIC.WAITE=1, ICIC.DTEE=1 to */
+		/* enable interrupt control.                      */
+		mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC)
+			     | ICIC_TACKE | ICIC_WAITE | ICIC_DTEE);
+		/* Write H'94 in ICCR to issue start condition */
+		mmio_write_8(IIC_ICCR, ICCR_START);
+		/* Set next status */
+		avs_status = avs_status_set_slave_addr;
+		break;
+	case avs_status_set_slave_addr:
+		/* Check error. */
+		err = avs_check_error();
+		if (err == avs_error_al) {
+			/* Recovery sequence of just after start. */
+			avs_status = avs_status_al_start;
+		} else if (err == avs_error_nack) {
+			/* Recovery sequence of detected NACK */
+			avs_status = avs_status_nack;
+		} else {
+			/* Was data transmission enabled ? */
+			if ((mmio_read_8(IIC_ICSR) & ICSR_DTE) == ICSR_DTE) {
+				/* Clear ICIC.DTEE to disable a DTE interrupt */
+				mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC)
+					     & (uint8_t) (~ICIC_DTEE));
+				/* Send PMIC slave address + (W) */
+				mmio_write_8(IIC_ICDR, PMIC_W_SLAVE_ADDRESS);
+				/* Set next status */
+				avs_status = avs_status_write_reg_addr;
+			}
+		}
+		break;
+	case avs_status_write_reg_addr:
+		/* Check error. */
+		err = avs_check_error();
+		if (err == avs_error_al) {
+			/* Recovery sequence of during data transfer. */
+			avs_status = avs_status_al_transfer;
+		} else if (err == avs_error_nack) {
+			/* Recovery sequence of detected NACK */
+			avs_status = avs_status_nack;
+		} else {
+			/* If wait state after data transmission. */
+			if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) {
+				/* Write PMIC DVFS_SetVID address */
+				mmio_write_8(IIC_ICDR, PMIC_DVFS_SETVID);
+				/* Clear ICSR.WAIT to exit from wait state. */
+				mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR)
+					     & (uint8_t) (~ICSR_WAIT));
+				/* Set next status */
+				avs_status = avs_status_write_reg_data;
+			}
+		}
+		break;
+	case avs_status_write_reg_data:
+		/* Check error. */
+		err = avs_check_error();
+		if (err == avs_error_al) {
+			/* Recovery sequence of during data transfer. */
+			avs_status = avs_status_al_transfer;
+		} else if (err == avs_error_nack) {
+			/* Recovery sequence of detected NACK */
+			avs_status = avs_status_nack;
+		} else {
+			/* If wait state after data transmission. */
+			if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) {
+				/* Dose efuse_avs exceed the number of */
+				/* the tables? */
+				if (efuse_avs >= EFUSE_AVS_NUM) {
+					ERROR("AVS number of eFuse is out "
+					      "of a range. number=%u\n",
+					      efuse_avs);
+					/* Infinite loop */
+					panic();
+				}
+				/* Write PMIC DVFS_SetVID value */
+				mmio_write_8(IIC_ICDR,
+					     init_vol_tbl[efuse_avs].vol);
+				/* Clear ICSR.WAIT to exit from wait state. */
+				mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR)
+					     & (uint8_t) (~ICSR_WAIT));
+				/* Set next status */
+				avs_status = avs_status_stop_condition;
+			}
+		}
+		break;
+	case avs_status_stop_condition:
+		err = avs_check_error();
+		if (err == avs_error_al) {
+			/* Recovery sequence of during data transfer. */
+			avs_status = avs_status_al_transfer;
+		} else if (err == avs_error_nack) {
+			/* Recovery sequence of detected NACK */
+			avs_status = avs_status_nack;
+		} else {
+			/* If wait state after data transmission. */
+			if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) {
+				/* Write H'90 in ICCR to issue stop condition */
+				mmio_write_8(IIC_ICCR, ICCR_STOP);
+				/* Clear ICSR.WAIT to exit from wait state. */
+				mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR)
+					     & (uint8_t) (~ICSR_WAIT));
+				/* Set next status */
+				avs_status = avs_status_end;
+			}
+		}
+		break;
+	case avs_status_end:
+		/* Is this module not busy?. */
+		if ((mmio_read_8(IIC_ICSR) & ICSR_BUSY) == 0U) {
+			/* Set ICCR=H'00 to disable the I2C module. */
+			mmio_write_8(IIC_ICCR, 0x00U);
+			/* Set next status */
+			avs_status = avs_status_complete;
+		}
+		break;
+	case avs_status_al_start:
+		/* Clear ICSR.AL bit */
+		mmio_write_8(IIC_ICSR, (mmio_read_8(IIC_ICSR)
+					& (uint8_t) (~ICSR_AL)));
+		/* Transmit a clock pulse */
+		mmio_write_8(IIC_ICDR, init_vol_tbl[EFUSE_AVS0].vol);
+		/* Set next status */
+		avs_status = avs_status_error_stop;
+		break;
+	case avs_status_al_transfer:
+		/* Clear ICSR.AL bit */
+		mmio_write_8(IIC_ICSR, (mmio_read_8(IIC_ICSR)
+					& (uint8_t) (~ICSR_AL)));
+		/* Set next status */
+		avs_status = avs_status_error_stop;
+		break;
+	case avs_status_nack:
+		/* Write H'90 in ICCR to issue stop condition */
+		mmio_write_8(IIC_ICCR, ICCR_STOP);
+		/* Disable a WAIT and DTEE interrupt. */
+		mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC)
+			     & (uint8_t) (~(ICIC_WAITE | ICIC_DTEE)));
+		/* Clear ICSR.TACK bit */
+		mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR)
+			     & (uint8_t) (~ICSR_TACK));
+		/* Set next status */
+		avs_status = ave_status_error_end;
+		break;
+	case avs_status_error_stop:
+		/* If wait state after data transmission. */
+		if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) {
+			/* Write H'90 in ICCR to issue stop condition */
+			mmio_write_8(IIC_ICCR, ICCR_STOP);
+			/* Clear ICSR.WAIT to exit from wait state. */
+			mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR)
+				     & (uint8_t) (~ICSR_WAIT));
+			/* Set next status */
+			avs_status = ave_status_error_end;
+		}
+		break;
+	case ave_status_error_end:
+		/* Is this module not busy?. */
+		if ((mmio_read_8(IIC_ICSR) & ICSR_BUSY) == 0U) {
+			/* Set ICCR=H'00 to disable the I2C module. */
+			mmio_write_8(IIC_ICCR, 0x00U);
+			/* Increment the re-try number of times. */
+			avs_retry++;
+			/* Set start a re-try to status. */
+			avs_status = avs_status_start_condition;
+		}
+		break;
+	case avs_status_complete:
+		/* After "avs_status" became the "avs_status_complete", */
+		/* "avs_setting()" function may be called. */
+		break;
+	default:
+		/* This case is not possible. */
+		ERROR("AVS setting is in invalid status. status=%u\n",
+		      avs_status);
+		/* Infinite loop */
+		panic();
+		break;
+	}
+#endif /* PMIC_ROHM_BD9571 */
+#endif /* (AVS_SETTING_ENABLE==1) */
+}
+
+/*
+ * Finish the AVS setting.
+ */
+void rcar_avs_end(void)
+{
+#if (AVS_SETTING_ENABLE == 1)
+	uint32_t mstp;
+
+#if PMIC_ROHM_BD9571
+	/* While status is not completion, be repeated. */
+	while (avs_status != avs_status_complete)
+		rcar_avs_setting();
+
+	NOTICE("AVS setting succeeded. DVFS_SetVID=0x%x\n",
+	       init_vol_tbl[efuse_avs].vol);
+
+#if AVS_READ_PMIC_REG_ENABLE == 1
+	{
+		uint8_t addr = PMIC_DVFS_SETVID;
+		uint8_t value = avs_read_pmic_reg(addr);
+		NOTICE("Read PMIC register. address=0x%x value=0x%x \n",
+		       addr, value);
+	}
+#endif
+
+	/* Bit of the module which wants to disable clock supply. */
+	mstp = CPG_SYS_DVFS_BIT;
+	/* Disables the supply of clock signal to a module. */
+	cpg_write(CPG_SMSTPCR9, mmio_read_32(CPG_SMSTPCR9) | mstp);
+#endif /* PMIC_ROHM_BD9571 */
+
+	/* Bit of the module which wants to disable clock supply. */
+	mstp = CPG_SYS_ADVFS_BIT;
+	/* Disables the supply of clock signal to a module. */
+	cpg_write(CPG_SMSTPCR9, mmio_read_32(CPG_SMSTPCR9) | mstp);
+
+#endif /* (AVS_SETTING_ENABLE==1) */
+}
+
+#if (AVS_SETTING_ENABLE == 1)
+#if PMIC_ROHM_BD9571
+/*
+ * Check error and judge re-try.
+ */
+static avs_error_t avs_check_error(void)
+{
+	avs_error_t ret;
+
+	if ((mmio_read_8(IIC_ICSR) & ICSR_AL) == ICSR_AL) {
+		NOTICE("Loss of arbitration is detected. "
+		       "AVS status=%d Retry=%u\n", avs_status, avs_retry);
+		/* Check of retry number of times */
+		if (avs_retry >= AVS_RETRY_NUM) {
+			ERROR("AVS setting failed in retry. max=%u\n",
+			      AVS_RETRY_NUM);
+			/* Infinite loop */
+			panic();
+		}
+		/* Set the error detected to error status. */
+		ret = avs_error_al;
+	} else if ((mmio_read_8(IIC_ICSR) & ICSR_TACK) == ICSR_TACK) {
+		NOTICE("Non-acknowledge is detected. "
+		       "AVS status=%d Retry=%u\n", avs_status, avs_retry);
+		/* Check of retry number of times */
+		if (avs_retry >= AVS_RETRY_NUM) {
+			ERROR("AVS setting failed in retry. max=%u\n",
+			      AVS_RETRY_NUM);
+			/* Infinite loop */
+			panic();
+		}
+		/* Set the error detected to error status. */
+		ret = avs_error_nack;
+	} else {
+		/* Not error. */
+		ret = avs_error_none;
+	}
+	return ret;
+}
+
+/*
+ * Set I2C for DVFS clock.
+ */
+static void avs_set_iic_clock(void)
+{
+	uint32_t md_pin;
+
+	/* Read Mode pin register. */
+	md_pin = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14;
+	/* Set the module clock (CP phy) for the IIC-DVFS. */
+	/* CP phy is EXTAL / 2.                            */
+	switch (md_pin) {
+	case MD14_MD13_TYPE_0:	/* EXTAL = 16.6666MHz */
+		mmio_write_8(IIC_ICCL, ICCL_FREQ_8p33M);
+		mmio_write_8(IIC_ICCH, ICCH_FREQ_8p33M);
+		break;
+	case MD14_MD13_TYPE_1:	/* EXTAL = 20MHz */
+		mmio_write_8(IIC_ICCL, ICCL_FREQ_10M);
+		mmio_write_8(IIC_ICCH, ICCH_FREQ_10M);
+		break;
+	case MD14_MD13_TYPE_2:	/* EXTAL = 25MHz (H3/M3) */
+		mmio_write_8(IIC_ICCL, ICCL_FREQ_12p5M);
+		mmio_write_8(IIC_ICCH, ICCH_FREQ_12p5M);
+		break;
+	case MD14_MD13_TYPE_3:	/* EXTAL = 33.3333MHz */
+		mmio_write_8(IIC_ICCL, ICCL_FREQ_16p66M);
+		mmio_write_8(IIC_ICCH, ICCH_FREQ_16p66M);
+		break;
+	default:		/* This case is not possible. */
+		/* CP Phy frequency is to be set for the 16.66MHz */
+		mmio_write_8(IIC_ICCL, ICCL_FREQ_16p66M);
+		mmio_write_8(IIC_ICCH, ICCH_FREQ_16p66M);
+		break;
+	}
+}
+
+#if AVS_READ_PMIC_REG_ENABLE == 1
+/*
+ * Read the value of the register of PMIC.
+ */
+static uint8_t avs_read_pmic_reg(uint8_t addr)
+{
+	uint8_t reg;
+
+	/* Set ICCR.ICE=1 to activate the I2C module. */
+	mmio_write_8(IIC_ICCR, mmio_read_8(IIC_ICCR) | ICCR_ENABLE);
+
+	/* Set frequency of 400kHz */
+	avs_set_iic_clock();
+
+	/* Set ICIC.WAITE=1, ICIC.DTEE=1 to enable data transmission    */
+	/* interrupt and wait interrupt.                                */
+	mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_WAITE | ICIC_DTEE);
+
+	/* Write H'94 in ICCR to issue start condition */
+	mmio_write_8(IIC_ICCR, ICCR_START);
+
+	/* Wait for a until ICSR.DTE becomes 1. */
+	avs_poll(ICSR_DTE, 1U);
+
+	/* Clear ICIC.DTEE to disable a DTE interrupt. */
+	mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE));
+	/* Send slave address of PMIC */
+	mmio_write_8(IIC_ICDR, PMIC_W_SLAVE_ADDRESS);
+
+	/* Wait for a until ICSR.WAIT becomes 1. */
+	avs_poll(ICSR_WAIT, 1U);
+
+	/* write PMIC address */
+	mmio_write_8(IIC_ICDR, addr);
+	/* Clear ICSR.WAIT to exit from WAIT status. */
+	mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT));
+
+	/* Wait for a until ICSR.WAIT becomes 1. */
+	avs_poll(ICSR_WAIT, 1U);
+
+	/* Write H'94 in ICCR to issue restart condition */
+	mmio_write_8(IIC_ICCR, ICCR_START);
+	/* Clear ICSR.WAIT to exit from WAIT status. */
+	mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT));
+	/* Set ICIC.DTEE=1 to enable data transmission interrupt. */
+	mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_DTEE);
+
+	/* Wait for a until ICSR.DTE becomes 1. */
+	avs_poll(ICSR_DTE, 1U);
+
+	/* Clear ICIC.DTEE to disable a DTE interrupt. */
+	mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE));
+	/* Send slave address of PMIC */
+	mmio_write_8(IIC_ICDR, PMIC_R_SLAVE_ADDRESS);
+
+	/* Wait for a until ICSR.WAIT becomes 1. */
+	avs_poll(ICSR_WAIT, 1U);
+
+	/* Write H'81 to ICCR to issue the repeated START condition     */
+	/* for changing the transmission mode to the receive mode.      */
+	mmio_write_8(IIC_ICCR, ICCR_START_RECV);
+	/* Clear ICSR.WAIT to exit from WAIT status. */
+	mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT));
+
+	/* Wait for a until ICSR.WAIT becomes 1. */
+	avs_poll(ICSR_WAIT, 1U);
+
+	/* Set ICCR to H'C0 for the STOP condition */
+	mmio_write_8(IIC_ICCR, ICCR_STOP_RECV);
+	/* Clear ICSR.WAIT to exit from WAIT status. */
+	mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT));
+	/* Set ICIC.DTEE=1 to enable data transmission interrupt. */
+	mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_DTEE);
+
+	/* Wait for a until ICSR.DTE becomes 1. */
+	avs_poll(ICSR_DTE, 1U);
+
+	/* Receive DVFS SetVID register */
+	/* Clear ICIC.DTEE to disable a DTE interrupt. */
+	mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE));
+	/* Receive DVFS SetVID register */
+	reg = mmio_read_8(IIC_ICDR);
+
+	/* Wait until ICSR.BUSY is cleared. */
+	avs_poll(ICSR_BUSY, 0U);
+
+	/* Set ICCR=H'00 to disable the I2C module. */
+	mmio_write_8(IIC_ICCR, 0x00U);
+
+	return reg;
+}
+
+/*
+ * Wait processing by the polling.
+ */
+static void avs_poll(uint8_t bit_pos, uint8_t val)
+{
+	uint8_t bit_val = 0U;
+
+	if (val != 0U)
+		bit_val = bit_pos;
+
+	while (1) {
+		if ((mmio_read_8(IIC_ICSR) & bit_pos) == bit_val)
+			break;
+	}
+}
+#endif /* AVS_READ_PMIC_REG_ENABLE */
+#endif /* PMIC_ROHM_BD9571 */
+#endif /* (AVS_SETTING_ENABLE==1) */
diff --git a/drivers/renesas/rcar/avs/avs_driver.h b/drivers/renesas/rcar/avs/avs_driver.h
new file mode 100644
index 0000000..aa773b6
--- /dev/null
+++ b/drivers/renesas/rcar/avs/avs_driver.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AVS_DRIVER_H
+#define AVS_DRIVER_H
+
+/* AVS Setting. 1:enable / 0:disable */
+#ifndef AVS_SETTING_ENABLE
+#define AVS_SETTING_ENABLE	1
+#endif /* AVS_SETTING_ENABLE */
+
+void rcar_avs_init(void);
+void rcar_avs_setting(void);
+void rcar_avs_end(void);
+
+#endif /* AVS_DRIVER_H */
diff --git a/drivers/renesas/rcar/board/board.c b/drivers/renesas/rcar/board/board.c
new file mode 100644
index 0000000..df17802
--- /dev/null
+++ b/drivers/renesas/rcar/board/board.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#include <iic_dvfs.h>
+
+#include "board.h"
+
+#ifndef BOARD_DEFAULT
+#if (RCAR_LSI == RCAR_D3)
+#define BOARD_DEFAULT		(BOARD_DRAAK << BOARD_CODE_SHIFT)
+#elif (RCAR_LSI == RCAR_E3)
+#define BOARD_DEFAULT		(BOARD_EBISU << BOARD_CODE_SHIFT)
+#elif (RCAR_LSI == RCAR_V3M)
+#define BOARD_DEFAULT		(BOARD_EAGLE << BOARD_CODE_SHIFT)
+#else
+#define BOARD_DEFAULT		(BOARD_SALVATOR_X << BOARD_CODE_SHIFT)
+#endif
+#endif
+
+#define BOARD_CODE_MASK		(0xF8)
+#define BOARD_REV_MASK		(0x07)
+#define BOARD_CODE_SHIFT	(0x03)
+#define BOARD_ID_UNKNOWN	(0xFF)
+
+#define SXS_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SX_ID	{ 0x10U, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SKP_ID	{ 0x10U, 0x10U, 0x20U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define SK_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define EB4_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define EB_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define DR_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define EA_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+#define KK_ID	{ 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }
+
+const char *g_board_tbl[] = {
+	[BOARD_STARTER_KIT_PRE] = "Starter Kit Premier",
+	[BOARD_STARTER_KIT] = "Starter Kit",
+	[BOARD_SALVATOR_XS] = "Salvator-XS",
+	[BOARD_SALVATOR_X] = "Salvator-X",
+	[BOARD_EBISU_4D] = "Ebisu-4D",
+	[BOARD_KRIEK] = "Kriek",
+	[BOARD_EBISU] = "Ebisu",
+	[BOARD_DRAAK] = "Draak",
+	[BOARD_EAGLE] = "Eagle",
+	[BOARD_UNKNOWN] = "unknown"
+};
+
+int32_t rcar_get_board_type(uint32_t *type, uint32_t *rev)
+{
+	int32_t ret = 0;
+	const uint8_t board_tbl[][8] = {
+		[BOARD_STARTER_KIT_PRE] = SKP_ID,
+		[BOARD_SALVATOR_XS] = SXS_ID,
+		[BOARD_STARTER_KIT] = SK_ID,
+		[BOARD_SALVATOR_X] = SX_ID,
+		[BOARD_EBISU_4D] = EB4_ID,
+		[BOARD_EBISU] = EB_ID,
+		[BOARD_DRAAK] = DR_ID,
+		[BOARD_EAGLE] = EA_ID,
+		[BOARD_KRIEK] = KK_ID,
+	};
+	static uint8_t board_id = BOARD_ID_UNKNOWN;
+
+	if (board_id != BOARD_ID_UNKNOWN)
+		goto get_type;
+
+#if PMIC_ROHM_BD9571
+	/* Board ID detection from EEPROM */
+	ret = rcar_iic_dvfs_receive(EEPROM, BOARD_ID, &board_id);
+	if (ret) {
+		board_id = BOARD_ID_UNKNOWN;
+		goto get_type;
+	}
+
+	if (board_id == BOARD_ID_UNKNOWN)
+		board_id = BOARD_DEFAULT;
+#else
+	board_id = BOARD_DEFAULT;
+#endif
+
+get_type:
+	*type = ((uint32_t) board_id & BOARD_CODE_MASK) >> BOARD_CODE_SHIFT;
+
+	if (*type >= ARRAY_SIZE(board_tbl)) {
+		/* no revision information, set Rev0.0. */
+		*rev = 0;
+		return ret;
+	}
+
+	*rev = board_tbl[*type][(uint8_t) (board_id & BOARD_REV_MASK)];
+
+	return ret;
+}
diff --git a/drivers/renesas/rcar/board/board.h b/drivers/renesas/rcar/board/board.h
new file mode 100644
index 0000000..51a8e30
--- /dev/null
+++ b/drivers/renesas/rcar/board/board.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+#define BOARD_SALVATOR_X		(0x00)
+#define BOARD_KRIEK			(0x01)
+#define BOARD_STARTER_KIT		(0x02)
+#define BOARD_SALVATOR_XS		(0x04)
+#define BOARD_EBISU			(0x08)
+#define BOARD_STARTER_KIT_PRE		(0x0B)
+#define BOARD_EBISU_4D			(0x0DU)
+#define BOARD_DRAAK			(0x0EU)
+#define BOARD_EAGLE			(0x0FU)
+#define BOARD_UNKNOWN			(BOARD_EAGLE + 1U)
+
+#define BOARD_REV_UNKNOWN		(0xFF)
+
+extern const char *g_board_tbl[];
+
+/************************************************************************
+ * Revisions are expressed in 8 bits.
+ *  The upper 4 bits are major version.
+ *  The lower 4 bits are minor version.
+ ************************************************************************/
+#define GET_BOARD_MAJOR(a)	((uint32_t)(a) >> 0x4)
+#define GET_BOARD_MINOR(a)	((uint32_t)(a) &  0xF)
+#define GET_BOARD_NAME(a)	(g_board_tbl[(a)])
+
+int32_t rcar_get_board_type(uint32_t *type, uint32_t *rev);
+
+#endif /* BOARD_H */
diff --git a/drivers/renesas/rcar/common.c b/drivers/renesas/rcar/common.c
new file mode 100644
index 0000000..42bdce5
--- /dev/null
+++ b/drivers/renesas/rcar/common.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "rcar_private.h"
+
+void
+#if IMAGE_BL31
+    __attribute__ ((section(".system_ram")))
+#endif
+    cpg_write(uintptr_t regadr, uint32_t regval)
+{
+	uint32_t value = (regval);
+	mmio_write_32((uintptr_t) RCAR_CPGWPR, ~value);
+	mmio_write_32(regadr, value);
+}
+
+void
+#if IMAGE_BL31
+    __attribute__ ((section(".system_ram")))
+#endif
+    mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit)
+{
+	uint32_t reg;
+	reg = mmio_read_32(mstpcr);
+	reg &= ~target_bit;
+	cpg_write(mstpcr, reg);
+	while ((mmio_read_32(mstpsr) & target_bit) != 0U) {
+	}
+}
diff --git a/drivers/renesas/rcar/console/rcar_console.S b/drivers/renesas/rcar/console/rcar_console.S
new file mode 100644
index 0000000..859efec
--- /dev/null
+++ b/drivers/renesas/rcar/console/rcar_console.S
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/renesas/rcar/console/console.h>
+
+	.globl	console_rcar_register
+	.globl	console_rcar_init
+	.globl	console_rcar_putc
+	.globl	console_rcar_flush
+
+	.extern	rcar_log_init
+	.extern	rcar_set_log_data
+
+	/* -----------------------------------------------
+	 * int console_rcar_register(
+	 *      uintptr_t base, uint32_t clk, uint32_t baud,
+	 *      console_rcar_t *console)
+	 * Function to initialize and register a new rcar
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_rcar_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_rcar_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_RCAR_BASE]
+
+	bl	rcar_log_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register rcar, putc=1, getc=0, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_rcar_register
+
+	/* ---------------------------------------------
+	 * int console_rcar_init(unsigned long base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func console_rcar_init
+	mov	w0, #0
+	ret
+endfunc console_rcar_init
+
+	/* --------------------------------------------------------
+	 * int console_rcar_putc(int c, console_rcar_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_rcar_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_rcar_putc
+	b	rcar_set_log_data
+endfunc console_rcar_putc
+
+	/* ---------------------------------------------
+	 * int console_rcar_flush(void)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output. It returns 0
+	 * upon successful completion, otherwise it
+	 * returns -1.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_rcar_flush
+	mov	w0, #0
+	ret
+endfunc console_rcar_flush
diff --git a/drivers/renesas/rcar/console/rcar_printf.c b/drivers/renesas/rcar/console/rcar_printf.c
new file mode 100644
index 0000000..e75b9f4
--- /dev/null
+++ b/drivers/renesas/rcar/console/rcar_printf.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_printf.h"
+
+#define INDEX_TIMER_COUNT	(4U)
+
+extern RCAR_INSTANTIATE_LOCK typedef struct log_head {
+	uint8_t head[4];
+	uint32_t index;
+	uint32_t size;
+	uint8_t res[4];
+} loghead_t;
+
+typedef struct log_map {
+	loghead_t header;
+	uint8_t log_data[RCAR_BL31_LOG_MAX];
+	uint8_t res_data[RCAR_LOG_RES_SIZE];
+} logmap_t;
+
+int32_t rcar_set_log_data(int32_t c)
+{
+	logmap_t *t_log;
+
+	t_log = (logmap_t *) RCAR_BL31_LOG_BASE;
+
+	rcar_lock_get();
+
+	/*
+	 * If index is broken, then index and size initialize
+	 */
+	if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) {
+		t_log->header.index = 0U;
+		t_log->header.size = 0U;
+	}
+	/*
+	 * data store to log area then index and size renewal
+	 */
+	t_log->log_data[t_log->header.index] = (uint8_t) c;
+	t_log->header.index++;
+	if (t_log->header.size < t_log->header.index) {
+		t_log->header.size = t_log->header.index;
+	}
+	if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) {
+		t_log->header.index = 0U;
+	}
+
+	rcar_lock_release();
+
+	return 1;
+}
+
+int32_t rcar_log_init(void)
+{
+
+	static const uint8_t const_header[] = "TLOG";
+	logmap_t *t_log;
+	int16_t init_flag = 0;
+
+	t_log = (logmap_t *) RCAR_BL31_LOG_BASE;
+	if (memcmp
+	    ((const void *)t_log->header.head, (const void *)const_header,
+	     sizeof(t_log->header.head)) != 0) {
+		/*
+		 * Log header is not "TLOG", then log area initialize
+		 */
+		init_flag = 1;
+	}
+	if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) {
+		/*
+		 * index is broken, then log area initialize
+		 */
+		init_flag = 1;
+	}
+	if (init_flag == 1) {
+		(void)memset((void *)t_log->log_data, 0,
+			     (size_t) RCAR_BL31_LOG_MAX);
+		(void)memcpy((void *)t_log->header.head,
+			     (const void *)const_header,
+			     sizeof(t_log->header.head));
+		t_log->header.index = 0U;
+		t_log->header.size = 0U;
+	}
+	rcar_lock_init();
+
+	return 1;
+}
diff --git a/drivers/renesas/rcar/console/rcar_printf.h b/drivers/renesas/rcar/console/rcar_printf.h
new file mode 100644
index 0000000..5da70e6
--- /dev/null
+++ b/drivers/renesas/rcar/console/rcar_printf.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PRINTF_H
+#define RCAR_PRINTF_H
+
+#include <string.h>
+
+int32_t rcar_set_log_data(int32_t c);
+int32_t rcar_log_init(void);
+
+#endif /* RCAR_PRINTF_H */
diff --git a/drivers/renesas/rcar/cpld/ulcb_cpld.c b/drivers/renesas/rcar/cpld/ulcb_cpld.c
new file mode 100644
index 0000000..5ffb2e1
--- /dev/null
+++ b/drivers/renesas/rcar/cpld/ulcb_cpld.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include "ulcb_cpld.h"
+
+#define SCLK			8	/* GP_6_8 */
+#define SSTBZ			3	/* GP_2_3 */
+#define MOSI			7	/* GP_6_7 */
+
+#define CPLD_ADDR_RESET		0x80	/* RW */
+
+/* LSI Multiplexed Pin Setting Mask Register */
+#define PFC_PMMR		0xE6060000
+
+/* General output registers */
+#define GPIO_OUTDT2		0xE6052008
+#define GPIO_OUTDT6		0xE6055408
+
+/* General input/output switching registers */
+#define GPIO_INOUTSEL2		0xE6052004
+#define GPIO_INOUTSEL6		0xE6055404
+
+/* General IO/Interrupt Switching Register */
+#define GPIO_IOINTSEL6		0xE6055400
+
+/* GPIO/perihperal function select */
+#define PFC_GPSR2		0xE6060108
+#define PFC_GPSR6		0xE6060118
+
+static void gpio_set_value(uint32_t addr, uint8_t gpio, uint32_t val)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(addr);
+	if (val)
+		reg |= (1 << gpio);
+	else
+		reg &= ~(1 << gpio);
+	mmio_write_32(addr, reg);
+}
+
+static void gpio_direction_output(uint32_t addr, uint8_t gpio)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(addr);
+	reg |= (1 << gpio);
+	mmio_write_32(addr, reg);
+}
+
+static void gpio_pfc(uint32_t addr, uint8_t gpio)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(addr);
+	reg &= ~(1 << gpio);
+	mmio_write_32(PFC_PMMR, ~reg);
+	mmio_write_32(addr, reg);
+}
+
+static void cpld_write(uint8_t addr, uint32_t data)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		/* MSB first */
+		gpio_set_value(GPIO_OUTDT6, MOSI, data & (1U << 31));
+		gpio_set_value(GPIO_OUTDT6, SCLK, 1);
+		data <<= 1;
+		gpio_set_value(GPIO_OUTDT6, SCLK, 0);
+	}
+
+	for (i = 0; i < 8; i++) {
+		/* MSB first */
+		gpio_set_value(GPIO_OUTDT6, MOSI, addr & 0x80);
+		gpio_set_value(GPIO_OUTDT6, SCLK, 1);
+		addr <<= 1;
+		gpio_set_value(GPIO_OUTDT6, SCLK, 0);
+	}
+
+	/* WRITE */
+	gpio_set_value(GPIO_OUTDT6, MOSI, 1);
+	gpio_set_value(GPIO_OUTDT2, SSTBZ, 0);
+	gpio_set_value(GPIO_OUTDT6, SCLK, 1);
+	gpio_set_value(GPIO_OUTDT6, SCLK, 0);
+	gpio_set_value(GPIO_OUTDT2, SSTBZ, 1);
+}
+
+static void cpld_init(void)
+{
+	gpio_pfc(PFC_GPSR6, SCLK);
+	gpio_pfc(PFC_GPSR2, SSTBZ);
+	gpio_pfc(PFC_GPSR6, MOSI);
+
+	gpio_set_value(GPIO_IOINTSEL6, SCLK, 0);
+	gpio_set_value(GPIO_OUTDT6, SCLK, 0);
+	gpio_set_value(GPIO_OUTDT2, SSTBZ, 1);
+	gpio_set_value(GPIO_OUTDT6, MOSI, 0);
+
+	gpio_direction_output(GPIO_INOUTSEL6, SCLK);
+	gpio_direction_output(GPIO_INOUTSEL2, SSTBZ);
+	gpio_direction_output(GPIO_INOUTSEL6, MOSI);
+}
+
+void rcar_cpld_reset_cpu(void)
+{
+	cpld_init();
+
+	cpld_write(CPLD_ADDR_RESET, 1);
+}
diff --git a/drivers/renesas/rcar/cpld/ulcb_cpld.h b/drivers/renesas/rcar/cpld/ulcb_cpld.h
new file mode 100644
index 0000000..1616d71
--- /dev/null
+++ b/drivers/renesas/rcar/cpld/ulcb_cpld.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_ULCB_CPLD_H__
+#define RCAR_ULCB_CPLD_H__
+
+extern void rcar_cpld_reset_cpu(void);
+
+#endif /* RCAR_ULCB_CPLD_H__ */
diff --git a/drivers/renesas/rcar/delay/micro_delay.c b/drivers/renesas/rcar/delay/micro_delay.c
new file mode 100644
index 0000000..aced589
--- /dev/null
+++ b/drivers/renesas/rcar/delay/micro_delay.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include "micro_delay.h"
+
+#define RCAR_CONV_MICROSEC		1000000U
+
+void
+#if IMAGE_BL31
+	__attribute__ ((section (".system_ram")))
+#endif
+	rcar_micro_delay(uint64_t micro_sec)
+{
+	uint64_t freq;
+	uint64_t base_count;
+	uint64_t get_count;
+	uint64_t wait_time = 0U;
+
+	freq = read_cntfrq_el0();
+	base_count = read_cntpct_el0();
+	while (micro_sec > wait_time) {
+		get_count = read_cntpct_el0();
+		wait_time = ((get_count - base_count) * RCAR_CONV_MICROSEC) / freq;
+	}
+}
diff --git a/drivers/renesas/rcar/delay/micro_delay.h b/drivers/renesas/rcar/delay/micro_delay.h
new file mode 100644
index 0000000..37b71f8
--- /dev/null
+++ b/drivers/renesas/rcar/delay/micro_delay.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MICRO_DELAY_H
+#define MICRO_DELAY_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+void rcar_micro_delay(uint64_t micro_sec);
+#endif
+
+#endif /* MICRO_DELAY_H */
diff --git a/drivers/renesas/rcar/dma/dma_driver.c b/drivers/renesas/rcar/dma/dma_driver.c
new file mode 100644
index 0000000..e0be46e
--- /dev/null
+++ b/drivers/renesas/rcar/dma/dma_driver.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+#include "cpg_registers.h"
+#include "rcar_private.h"
+
+/* DMA CHANNEL setting (0/16/32) */
+#if RCAR_LSI == RCAR_V3M
+#define	DMA_CH		16
+#else
+#define	DMA_CH		0
+#endif
+
+#if (DMA_CH == 0)
+#define SYS_DMAC_BIT	((uint32_t)1U << 19U)
+#define DMA_BASE	(0xE6700000U)
+#elif (DMA_CH == 16)
+#define SYS_DMAC_BIT	((uint32_t)1U << 18U)
+#define DMA_BASE	(0xE7300000U)
+#elif (DMA_CH == 32)
+#define SYS_DMAC_BIT	((uint32_t)1U << 17U)
+#define DMA_BASE	(0xE7320000U)
+#else
+#define SYS_DMAC_BIT	((uint32_t)1U << 19U)
+#define DMA_BASE	(0xE6700000U)
+#endif
+
+/* DMA operation */
+#define DMA_DMAOR	(DMA_BASE + 0x0060U)
+/* DMA secure control */
+#define	DMA_DMASEC	(DMA_BASE + 0x0030U)
+/* DMA channel clear */
+#define DMA_DMACHCLR	(DMA_BASE + 0x0080U)
+/* DMA source address */
+#define DMA_DMASAR	(DMA_BASE + 0x8000U)
+/* DMA destination address */
+#define DMA_DMADAR	(DMA_BASE + 0x8004U)
+/* DMA transfer count */
+#define DMA_DMATCR	(DMA_BASE + 0x8008U)
+/* DMA channel control */
+#define DMA_DMACHCR	(DMA_BASE + 0x800CU)
+/* DMA fixed destination address */
+#define DMA_DMAFIXDAR	(DMA_BASE + 0x8014U)
+
+#define	DMA_USE_CHANNEL		(0x00000001U)
+#define	DMAOR_INITIAL		(0x0301U)
+#define	DMACHCLR_CH_ALL		(0x0000FFFFU)
+#define	DMAFIXDAR_32BIT_SHIFT	(32U)
+#define	DMAFIXDAR_DAR_MASK	(0x000000FFU)
+#define	DMADAR_BOUNDARY_ADDR	(0x100000000ULL)
+#define	DMATCR_CNT_SHIFT	(6U)
+#define	DMATCR_MAX		(0x00FFFFFFU)
+#define	DMACHCR_TRN_MODE	(0x00105409U)
+#define	DMACHCR_DE_BIT		(0x00000001U)
+#define	DMACHCR_TE_BIT		(0x00000002U)
+#define	DMACHCR_CHE_BIT		(0x80000000U)
+
+#define	DMA_SIZE_UNIT		FLASH_TRANS_SIZE_UNIT
+#define	DMA_FRACTION_MASK	(0xFFU)
+#define DMA_DST_LIMIT		(0x10000000000ULL)
+
+/* transfer length limit */
+#define DMA_LENGTH_LIMIT	((DMATCR_MAX * (1U << DMATCR_CNT_SHIFT)) \
+				& ~DMA_FRACTION_MASK)
+
+static void dma_enable(void)
+{
+	mstpcr_write(CPG_SMSTPCR2, CPG_MSTPSR2, SYS_DMAC_BIT);
+}
+
+static void dma_setup(void)
+{
+	mmio_write_16(DMA_DMAOR, 0);
+	mmio_write_32(DMA_DMACHCLR, DMACHCLR_CH_ALL);
+}
+
+static void dma_start(uintptr_t dst, uint32_t src, uint32_t len)
+{
+	mmio_write_16(DMA_DMAOR, DMAOR_INITIAL);
+	mmio_write_32(DMA_DMAFIXDAR, (dst >> DMAFIXDAR_32BIT_SHIFT) &
+		      DMAFIXDAR_DAR_MASK);
+	mmio_write_32(DMA_DMADAR, dst & UINT32_MAX);
+	mmio_write_32(DMA_DMASAR, src);
+	mmio_write_32(DMA_DMATCR, len >> DMATCR_CNT_SHIFT);
+	mmio_write_32(DMA_DMASEC, DMA_USE_CHANNEL);
+	mmio_write_32(DMA_DMACHCR, DMACHCR_TRN_MODE);
+}
+
+static void dma_end(void)
+{
+	while ((mmio_read_32(DMA_DMACHCR) & DMACHCR_TE_BIT) == 0) {
+		if ((mmio_read_32(DMA_DMACHCR) & DMACHCR_CHE_BIT) != 0U) {
+			ERROR("BL2: DMA - Channel Address Error\n");
+			panic();
+			break;
+		}
+	}
+	/* DMA transfer Disable */
+	mmio_clrbits_32(DMA_DMACHCR, DMACHCR_DE_BIT);
+	while ((mmio_read_32(DMA_DMACHCR) & DMACHCR_DE_BIT) != 0)
+		;
+
+	mmio_write_32(DMA_DMASEC, 0);
+	mmio_write_16(DMA_DMAOR, 0);
+	mmio_write_32(DMA_DMACHCLR, DMA_USE_CHANNEL);
+}
+
+void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len)
+{
+	uint32_t dma_len = len;
+
+	if (len & DMA_FRACTION_MASK)
+		dma_len = (len + DMA_SIZE_UNIT) & ~DMA_FRACTION_MASK;
+
+	if (!dma_len || dma_len > DMA_LENGTH_LIMIT) {
+		ERROR("BL2: DMA - size invalid, length (0x%x)\n", dma_len);
+		panic();
+	}
+
+	if (src & DMA_FRACTION_MASK) {
+		ERROR("BL2: DMA - source address invalid (0x%x), "
+			"length (0x%x)\n", src, dma_len);
+		panic();
+	}
+
+	if ((dst & UINT32_MAX) + dma_len > DMADAR_BOUNDARY_ADDR	||
+	    (dst + dma_len > DMA_DST_LIMIT)			||
+	    (dst & DMA_FRACTION_MASK)) {
+		ERROR("BL2: DMA - destination address invalid (0x%lx), "
+		      "length (0x%x)\n", dst, dma_len);
+		panic();
+	}
+
+	dma_start(dst, src, dma_len);
+	dma_end();
+}
+
+void rcar_dma_init(void)
+{
+	dma_enable();
+	dma_setup();
+}
diff --git a/drivers/renesas/rcar/emmc/emmc_cmd.c b/drivers/renesas/rcar/emmc/emmc_cmd.c
new file mode 100644
index 0000000..a2e25e3
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_cmd.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+#include "micro_delay.h"
+
+static void emmc_little_to_big(uint8_t *p, uint32_t value)
+{
+	if (p == NULL)
+		return;
+
+	p[0] = (uint8_t) (value >> 24);
+	p[1] = (uint8_t) (value >> 16);
+	p[2] = (uint8_t) (value >> 8);
+	p[3] = (uint8_t) value;
+}
+
+static void emmc_softreset(void)
+{
+	int32_t loop = 10000;
+	int32_t retry = 1000;
+
+	/* flag clear */
+	mmc_drv_obj.during_cmd_processing = FALSE;
+	mmc_drv_obj.during_transfer = FALSE;
+	mmc_drv_obj.during_dma_transfer = FALSE;
+	mmc_drv_obj.state_machine_blocking = FALSE;
+	mmc_drv_obj.force_terminate = FALSE;
+	mmc_drv_obj.dma_error_flag = FALSE;
+
+	/* during operation ? */
+	if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) == 0)
+		goto reset;
+
+	/* wait CMDSEQ = 0 */
+	while (loop > 0) {
+		if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) == 0)
+			break;	/* ready */
+
+		loop--;
+		if ((loop == 0) && (retry > 0)) {
+			rcar_micro_delay(1000U);	/* wait 1ms */
+			loop = 10000;
+			retry--;
+		}
+	}
+
+reset:
+	/* reset */
+	SETR_32(SOFT_RST, (GETR_32(SOFT_RST) & (~SOFT_RST_SDRST)));
+	SETR_32(SOFT_RST, (GETR_32(SOFT_RST) | SOFT_RST_SDRST));
+
+	/* initialize */
+	SETR_32(SD_INFO1, 0x00000000U);
+	SETR_32(SD_INFO2, SD_INFO2_CLEAR);
+	SETR_32(SD_INFO1_MASK, 0x00000000U);	/* all interrupt disable */
+	SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);	/* all interrupt disable */
+
+}
+
+static void emmc_read_response(uint32_t *response)
+{
+	uint8_t *p;
+
+	if (response == NULL)
+		return;
+
+	/* read response */
+	if (mmc_drv_obj.response_length != EMMC_MAX_RESPONSE_LENGTH) {
+		*response = GETR_32(SD_RSP10);	/* [39:8] */
+		return;
+	}
+
+	/* CSD or CID */
+	p = (uint8_t *) (response);
+	emmc_little_to_big(p, ((GETR_32(SD_RSP76) << 8)
+			| (GETR_32(SD_RSP54) >> 24)));	/* [127:96]     */
+	emmc_little_to_big(p + 4, ((GETR_32(SD_RSP54) << 8)
+			| (GETR_32(SD_RSP32) >> 24)));	/* [95:64]      */
+	emmc_little_to_big(p + 8, ((GETR_32(SD_RSP32) << 8)
+			| (GETR_32(SD_RSP10) >> 24)));	/* [63:32]      */
+	emmc_little_to_big(p + 12, (GETR_32(SD_RSP10) << 8));
+}
+
+static EMMC_ERROR_CODE emmc_response_check(uint32_t *response,
+					   uint32_t error_mask)
+{
+
+	HAL_MEMCARD_RESPONSE_TYPE response_type =
+	    (HAL_MEMCARD_RESPONSE_TYPE) (mmc_drv_obj.cmd_info.
+					 cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK);
+
+	if (response == NULL)
+		return EMMC_ERR_PARAM;
+
+	if (response_type == HAL_MEMCARD_RESPONSE_NONE)
+		return EMMC_SUCCESS;
+
+
+	if (response_type <= HAL_MEMCARD_RESPONSE_R1b) {
+		/* R1 or R1b */
+		mmc_drv_obj.current_state =
+		    (EMMC_R1_STATE) ((*response & EMMC_R1_STATE_MASK) >>
+				     EMMC_R1_STATE_SHIFT);
+		if ((*response & error_mask) != 0) {
+			if ((0x80 & *response) != 0) {
+				ERROR("BL2: emmc SWITCH_ERROR\n");
+			}
+			return EMMC_ERR_CARD_STATUS_BIT;
+		}
+		return EMMC_SUCCESS;;
+	}
+
+	if (response_type == HAL_MEMCARD_RESPONSE_R4) {
+		if ((*response & EMMC_R4_STATUS) != 0)
+			return EMMC_ERR_CARD_STATUS_BIT;
+	}
+
+	return EMMC_SUCCESS;
+}
+
+static void emmc_WaitCmd2Cmd_8Cycle(void)
+{
+	uint32_t dataL, wait = 0;
+
+	dataL = GETR_32(SD_CLK_CTRL);
+	dataL &= 0x000000FF;
+
+	switch (dataL) {
+	case 0xFF:
+	case 0x00:
+	case 0x01:
+	case 0x02:
+	case 0x04:
+	case 0x08:
+	case 0x10:
+	case 0x20:
+		wait = 10U;
+		break;
+	case 0x40:
+		wait = 20U;
+		break;
+	case 0x80:
+		wait = 30U;
+		break;
+	}
+
+	rcar_micro_delay(wait);
+}
+
+static void cmdErrSdInfo2Log(void)
+{
+	ERROR("BL2: emmc ERR SD_INFO2 = 0x%x\n", mmc_drv_obj.error_info.info2);
+}
+
+static void emmc_data_transfer_dma(void)
+{
+	mmc_drv_obj.during_dma_transfer = TRUE;
+	mmc_drv_obj.dma_error_flag = FALSE;
+
+	SETR_32(SD_INFO1_MASK, 0x00000000U);
+	SETR_32(SD_INFO2_MASK, (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR));
+
+	/* DMAC setting */
+	if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) {
+		/* transfer complete interrupt enable */
+		SETR_32(DM_CM_INFO1_MASK,
+			(DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE));
+		SETR_32(DM_CM_INFO2_MASK,
+			(DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE));
+		/* BUFF --> FIFO */
+		SETR_32(DM_CM_DTRAN_MODE, (DM_CM_DTRAN_MODE_CH0 |
+					   DM_CM_DTRAN_MODE_BIT_WIDTH));
+	} else {
+		/* transfer complete interrupt enable */
+		SETR_32(DM_CM_INFO1_MASK,
+			(DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE));
+		SETR_32(DM_CM_INFO2_MASK,
+			(DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE));
+		/* FIFO --> BUFF */
+		SETR_32(DM_CM_DTRAN_MODE, (DM_CM_DTRAN_MODE_CH1
+					   | DM_CM_DTRAN_MODE_BIT_WIDTH));
+	}
+	SETR_32(DM_DTRAN_ADDR, (((uintptr_t) mmc_drv_obj.buff_address_virtual &
+				 DM_DTRAN_ADDR_WRITE_MASK)));
+
+	SETR_32(DM_CM_DTRAN_CTRL, DM_CM_DTRAN_CTRL_START);
+}
+
+EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response)
+{
+	EMMC_ERROR_CODE rtn_code = EMMC_SUCCESS;
+	HAL_MEMCARD_RESPONSE_TYPE response_type;
+	HAL_MEMCARD_COMMAND_TYPE cmd_type;
+	EMMC_INT_STATE state;
+	uint32_t err_not_care_flag = FALSE;
+
+	/* parameter check */
+	if (response == NULL) {
+		emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* state check */
+	if (mmc_drv_obj.clock_enable != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	if (mmc_drv_obj.state_machine_blocking == TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR);
+		return EMMC_ERR;
+	}
+
+	state = ESTATE_BEGIN;
+	response_type =
+	    (HAL_MEMCARD_RESPONSE_TYPE) (mmc_drv_obj.cmd_info.
+					 cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK);
+	cmd_type =
+	    (HAL_MEMCARD_COMMAND_TYPE) (mmc_drv_obj.cmd_info.
+					cmd & HAL_MEMCARD_COMMAND_TYPE_MASK);
+
+	/* state machine */
+	while ((mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END)) {
+		/* The interrupt factor flag is observed. */
+		emmc_interrupt();
+
+		/* wait interrupt */
+		if (mmc_drv_obj.state_machine_blocking == TRUE)
+			continue;
+
+		switch (state) {
+		case ESTATE_BEGIN:
+			/* Busy check */
+			if ((mmc_drv_obj.error_info.info2 & SD_INFO2_CBSY) != 0) {
+				emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD,
+						      EMMC_ERR_CARD_BUSY);
+				return EMMC_ERR_CARD_BUSY;
+			}
+
+			/* clear register */
+			SETR_32(SD_INFO1, 0x00000000U);
+			SETR_32(SD_INFO2, SD_INFO2_CLEAR);
+			SETR_32(SD_INFO1_MASK, SD_INFO1_INFO0);
+			SETR_32(SD_INFO2_MASK,
+				(SD_INFO2_ALL_ERR | SD_INFO2_CLEAR));
+
+			state = ESTATE_ISSUE_CMD;
+			/* through */
+
+		case ESTATE_ISSUE_CMD:
+			/* ARG */
+			SETR_32(SD_ARG, mmc_drv_obj.cmd_info.arg);
+			/* issue cmd */
+			SETR_32(SD_CMD, mmc_drv_obj.cmd_info.hw);
+			/* Set driver flag */
+			mmc_drv_obj.during_cmd_processing = TRUE;
+			mmc_drv_obj.state_machine_blocking = TRUE;
+
+			if (response_type == HAL_MEMCARD_RESPONSE_NONE) {
+				state = ESTATE_NON_RESP_CMD;
+			} else {
+				state = ESTATE_RCV_RESP;
+			}
+
+			break;
+
+		case ESTATE_NON_RESP_CMD:
+			/* interrupt disable */
+			SETR_32(SD_INFO1_MASK, 0x00000000U);
+			SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);
+
+			/* check interrupt */
+			if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) {
+				/* error interrupt */
+				cmdErrSdInfo2Log();
+				rtn_code = EMMC_ERR_INFO2;
+				state = ESTATE_ERROR;
+			} else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) ==
+				   0) {
+				/* not receive expected interrupt */
+				rtn_code = EMMC_ERR_RESPONSE;
+				state = ESTATE_ERROR;
+			} else {
+				emmc_WaitCmd2Cmd_8Cycle();
+				state = ESTATE_END;
+			}
+			break;
+
+		case ESTATE_RCV_RESP:
+			/* interrupt disable */
+			SETR_32(SD_INFO1_MASK, 0x00000000U);
+			SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);
+
+			/* check interrupt */
+			if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) {
+				if ((mmc_drv_obj.get_partition_access_flag ==
+				     TRUE)
+				    && ((mmc_drv_obj.int_event2 & SD_INFO2_ERR6)
+					!= 0U)) {
+					err_not_care_flag = TRUE;
+					rtn_code = EMMC_ERR_CMD_TIMEOUT;
+				} else {
+					/* error interrupt */
+					cmdErrSdInfo2Log();
+					rtn_code = EMMC_ERR_INFO2;
+				}
+				state = ESTATE_ERROR;
+				break;
+			} else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) ==
+				   0) {
+				/* not receive expected interrupt */
+				rtn_code = EMMC_ERR_RESPONSE;
+				state = ESTATE_ERROR;
+				break;
+			}
+
+			/* read response */
+			emmc_read_response(response);
+
+			/* check response */
+			rtn_code = emmc_response_check(response, error_mask);
+			if (rtn_code != EMMC_SUCCESS) {
+				state = ESTATE_ERROR;
+				break;
+			}
+
+			if (response_type == HAL_MEMCARD_RESPONSE_R1b) {
+				/* R1b */
+				SETR_32(SD_INFO2_MASK,
+					(SD_INFO2_ALL_ERR | SD_INFO2_CLEAR));
+				state = ESTATE_RCV_RESPONSE_BUSY;
+			} else {
+				state = ESTATE_CHECK_RESPONSE_COMPLETE;
+			}
+			break;
+
+		case ESTATE_RCV_RESPONSE_BUSY:
+			/* check interrupt */
+			if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) {
+				/* error interrupt */
+				cmdErrSdInfo2Log();
+				rtn_code = EMMC_ERR_INFO2;
+				state = ESTATE_ERROR;
+				break;
+			}
+			/* DAT0 not Busy */
+			if ((SD_INFO2_DAT0 & mmc_drv_obj.error_info.info2) != 0) {
+				state = ESTATE_CHECK_RESPONSE_COMPLETE;
+				break;
+			}
+			break;
+
+		case ESTATE_CHECK_RESPONSE_COMPLETE:
+			if (cmd_type >= HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE) {
+				state = ESTATE_DATA_TRANSFER;
+			} else {
+				emmc_WaitCmd2Cmd_8Cycle();
+				state = ESTATE_END;
+			}
+			break;
+
+		case ESTATE_DATA_TRANSFER:
+			/* ADTC command  */
+			mmc_drv_obj.during_transfer = TRUE;
+			mmc_drv_obj.state_machine_blocking = TRUE;
+
+			if (mmc_drv_obj.transfer_mode == HAL_MEMCARD_DMA) {
+				/* DMA */
+				emmc_data_transfer_dma();
+			} else {
+				/* PIO */
+				/* interrupt enable (FIFO read/write enable) */
+				if (mmc_drv_obj.cmd_info.dir ==
+				    HAL_MEMCARD_WRITE) {
+					SETR_32(SD_INFO2_MASK,
+						(SD_INFO2_BWE | SD_INFO2_ALL_ERR
+						 | SD_INFO2_CLEAR));
+				} else {
+					SETR_32(SD_INFO2_MASK,
+						(SD_INFO2_BRE | SD_INFO2_ALL_ERR
+						 | SD_INFO2_CLEAR));
+				}
+			}
+			state = ESTATE_DATA_TRANSFER_COMPLETE;
+			break;
+
+		case ESTATE_DATA_TRANSFER_COMPLETE:
+			/* check interrupt */
+			if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) {
+				/* error interrupt */
+				cmdErrSdInfo2Log();
+				rtn_code = EMMC_ERR_INFO2;
+				state = ESTATE_TRANSFER_ERROR;
+				break;
+			}
+
+			/* DMAC error ? */
+			if (mmc_drv_obj.dma_error_flag == TRUE) {
+				/* Error occurred in DMAC driver. */
+				rtn_code = EMMC_ERR_FROM_DMAC_TRANSFER;
+				state = ESTATE_TRANSFER_ERROR;
+			} else if (mmc_drv_obj.during_dma_transfer == TRUE) {
+				/* DMAC not finished. unknown error */
+				rtn_code = EMMC_ERR;
+				state = ESTATE_TRANSFER_ERROR;
+			} else {
+				SETR_32(SD_INFO1_MASK, SD_INFO1_INFO2);
+				SETR_32(SD_INFO2_MASK,
+					(SD_INFO2_ALL_ERR | SD_INFO2_CLEAR));
+
+				mmc_drv_obj.state_machine_blocking = TRUE;
+
+				state = ESTATE_ACCESS_END;
+			}
+			break;
+
+		case ESTATE_ACCESS_END:
+
+			/* clear flag */
+			if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) {
+				SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR);	/* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
+				SETR_32(SD_STOP, 0x00000000U);
+				mmc_drv_obj.during_dma_transfer = FALSE;
+			}
+
+			SETR_32(SD_INFO1_MASK, 0x00000000U);
+			SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);
+			SETR_32(SD_INFO1, 0x00000000U);
+			SETR_32(SD_INFO2, SD_INFO2_CLEAR);
+
+			if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO2) != 0) {
+				emmc_WaitCmd2Cmd_8Cycle();
+				state = ESTATE_END;
+			} else {
+				state = ESTATE_ERROR;
+			}
+			break;
+
+		case ESTATE_TRANSFER_ERROR:
+			/* The error occurred in the Data transfer.  */
+			if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) {
+				SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR);	/* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */
+				SETR_32(SD_STOP, 0x00000000U);
+				mmc_drv_obj.during_dma_transfer = FALSE;
+			}
+			/* through */
+
+		case ESTATE_ERROR:
+			if (err_not_care_flag == TRUE) {
+				mmc_drv_obj.during_cmd_processing = FALSE;
+			} else {
+				emmc_softreset();
+				emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD,
+						      rtn_code);
+			}
+			return rtn_code;
+
+		default:
+			state = ESTATE_END;
+			break;
+		}		/* switch (state) */
+	}			/*  while ( (mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END) ) */
+
+	/* force terminate */
+	if (mmc_drv_obj.force_terminate == TRUE) {
+		/* timeout timer is expired. Or, PIO data transfer error. */
+		/* Timeout occurred in the DMA transfer. */
+		if (mmc_drv_obj.during_dma_transfer == TRUE) {
+			mmc_drv_obj.during_dma_transfer = FALSE;
+		}
+		ERROR("BL2: emmc exec_cmd:EMMC_ERR_FORCE_TERMINATE\n");
+		emmc_softreset();
+
+		return EMMC_ERR_FORCE_TERMINATE;	/* error information has already been written. */
+	}
+
+	/* success */
+	mmc_drv_obj.during_cmd_processing = FALSE;
+	mmc_drv_obj.during_transfer = FALSE;
+
+	return EMMC_SUCCESS;
+}
diff --git a/drivers/renesas/rcar/emmc/emmc_config.h b/drivers/renesas/rcar/emmc/emmc_config.h
new file mode 100644
index 0000000..686ccb9
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_config.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file  emmc_config.h
+ * @brief Configuration file
+ *
+ */
+
+#ifndef EMMC_CONFIG_H
+#define EMMC_CONFIG_H
+
+/* ************************ HEADER (INCLUDE) SECTION *********************** */
+
+/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
+
+/** @brief MMC driver config
+ */
+#define EMMC_RCA                1UL	/* RCA  */
+#define EMMC_RW_DATA_TIMEOUT    0x40UL	/* 314ms (freq = 400KHz, timeout Counter = 0x04(SDCLK * 2^17)  */
+#define EMMC_RETRY_COUNT        0	/* how many times to try after fail. Don't change. */
+#define EMMC_CMD_MAX            60UL	/* Don't change. */
+
+/** @brief etc
+ */
+#define LOADIMAGE_FLAGS_DMA_ENABLE              0x00000001UL
+
+/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
+
+/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
+
+/* ************************** FUNCTION PROTOTYPES ************************** */
+
+/* ********************************* CODE ********************************** */
+
+#endif /* EMMC_CONFIG_H */
+/* ******************************** END ************************************ */
diff --git a/drivers/renesas/rcar/emmc/emmc_def.h b/drivers/renesas/rcar/emmc/emmc_def.h
new file mode 100644
index 0000000..178c795
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_def.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file  emmc_def.h
+ * @brief eMMC boot is expecting this header file
+ *
+ */
+
+#ifndef EMMC_DEF_H
+#define EMMC_DEF_H
+
+#include "emmc_std.h"
+
+/* ************************ HEADER (INCLUDE) SECTION *********************** */
+
+/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
+#define EMMC_POWER_ON		(1U)
+
+/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
+
+/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
+extern st_mmc_base mmc_drv_obj;
+
+/* ************************** FUNCTION PROTOTYPES ************************** */
+
+/** @brief for assembler program
+ */
+uint32_t _rom_emmc_finalize(void);
+
+/** @brief eMMC driver API
+ */
+EMMC_ERROR_CODE rcar_emmc_init(void);
+EMMC_ERROR_CODE emmc_terminate(void);
+EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode);
+EMMC_ERROR_CODE rcar_emmc_mount(void);
+EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq);
+EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg);
+EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id);
+EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual,
+				 uint32_t sector_number, uint32_t count,
+				 uint32_t feature_flags);
+EMMC_ERROR_CODE emmc_write_sector(uint32_t *buff_address_virtual,
+				  uint32_t sector_number, uint32_t count,
+				  uint32_t feature_flags);
+EMMC_ERROR_CODE emmc_erase_sector(uint32_t *start_address,
+				  uint32_t *end_address);
+uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom);
+
+/** @brief interrupt service
+ */
+uint32_t emmc_interrupt(void);
+
+/** @brief DMA
+ */
+
+/** @brief send command API
+ */
+EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response);
+void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg);
+void emmc_make_trans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg,
+			 uint32_t *buff_address_virtual, uint32_t len,
+			 HAL_MEMCARD_OPERATION dir,
+			 HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode);
+EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg);
+
+/** @brief for error information
+ */
+void emmc_write_error_info(uint16_t func_no, EMMC_ERROR_CODE error_code);
+void emmc_write_error_info_func_no(uint16_t func_no);
+
+/* ********************************* CODE ********************************** */
+
+#endif /* EMMC_DEF_H */
+/* ******************************** END ************************************ */
diff --git a/drivers/renesas/rcar/emmc/emmc_hal.h b/drivers/renesas/rcar/emmc/emmc_hal.h
new file mode 100644
index 0000000..f0b7e9d
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_hal.h
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file  emmc_hal.h
+ * @brief emmc boot driver is expecting this header file
+ *
+ */
+
+#ifndef EMMC_HAL_H
+#define EMMC_HAL_H
+/* ************************ HEADER (INCLUDE) SECTION *********************** */
+#include <stdint.h>
+/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
+
+/** @brief memory card error/status types
+ */
+#define HAL_MEMCARD_OUT_OF_RANGE            0x80000000L
+#define HAL_MEMCARD_ADDRESS_ERROR           0x40000000L
+#define HAL_MEMCARD_BLOCK_LEN_ERROR         0x20000000L
+#define HAL_MEMCARD_ERASE_SEQ_ERROR         0x10000000L
+#define HAL_MEMCARD_ERASE_PARAM             0x08000000L
+#define HAL_MEMCARD_WP_VIOLATION            0x04000000L
+#define HAL_MEMCARD_CARD_IS_LOCKED          0x02000000L
+#define HAL_MEMCARD_LOCK_UNLOCK_FAILED      0x01000000L
+#define HAL_MEMCARD_COM_CRC_ERROR           0x00800000L
+#define HAL_MEMCARD_ILEGAL_COMMAND          0x00400000L
+#define HAL_MEMCARD_CARD_ECC_FAILED         0x00200000L
+#define HAL_MEMCARD_CC_ERROR                0x00100000L
+#define HAL_MEMCARD_ERROR                   0x00080000L
+#define HAL_MEMCARD_UNDERRUN                0x00040000L
+#define HAL_MEMCARD_OVERRUN                 0x00020000L
+#define HAL_MEMCARD_CIDCSD_OVERWRITE        0x00010000L
+#define HAL_MEMCARD_WP_ERASE_SKIP           0x00008000L
+#define HAL_MEMCARD_CARD_ECC_DISABLED       0x00004000L
+#define HAL_MEMCARD_ERASE_RESET             0x00002000L
+#define HAL_MEMCARD_CARD_STATE              0x00001E00L
+#define HAL_MEMCARD_CARD_READY_FOR_DATA     0x00000100L
+#define HAL_MEMCARD_APP_CMD                 0x00000020L
+#define HAL_MEMCARD_SWITCH_ERROR            0x00000080L
+#define HAL_MEMCARD_AKE_SEQ_ERROR           0x00000008L
+#define HAL_MEMCARD_NO_ERRORS               0x00000000L
+
+/** @brief Memory card response types
+ */
+#define HAL_MEMCARD_COMMAND_INDEX_MASK      0x0003f
+
+/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
+
+/** @brief Type of the return value.
+ */
+typedef enum {
+	HAL_MEMCARD_FAIL = 0U,
+	HAL_MEMCARD_OK = 1U,
+	HAL_MEMCARD_DMA_ALLOC_FAIL = 2U,     /**< DMA channel allocation failed */
+	HAL_MEMCARD_DMA_TRANSFER_FAIL = 3U,  /**< DMA transfer failed */
+	HAL_MEMCARD_CARD_STATUS_ERROR = 4U,  /**< A non-masked error bit was set in the card status */
+	HAL_MEMCARD_CMD_TIMEOUT = 5U,	     /**< Command timeout occurred */
+	HAL_MEMCARD_DATA_TIMEOUT = 6U,	     /**< Data timeout occurred */
+	HAL_MEMCARD_CMD_CRC_ERROR = 7U,	     /**< Command CRC error occurred */
+	HAL_MEMCARD_DATA_CRC_ERROR = 8U	     /**< Data CRC error occurred */
+} HAL_MEMCARD_RETURN;
+
+/** @brief memory access operation
+ */
+typedef enum {
+	HAL_MEMCARD_READ = 0U,	 /**< read */
+	HAL_MEMCARD_WRITE = 1U	 /**< write */
+} HAL_MEMCARD_OPERATION;
+
+/** @brief Type of data width on memorycard bus
+ */
+typedef enum {
+	HAL_MEMCARD_DATA_WIDTH_1_BIT = 0U,
+	HAL_MEMCARD_DATA_WIDTH_4_BIT = 1U,
+	HAL_MEMCARD_DATA_WIDTH_8_BIT = 2U
+} HAL_MEMCARD_DATA_WIDTH; /**< data (bus) width types */
+
+/** @brief Presence of the memory card
+ */
+typedef enum {
+	HAL_MEMCARD_CARD_IS_IN = 0U,
+	HAL_MEMCARD_CARD_IS_OUT = 1U
+} HAL_MEMCARD_PRESENCE_STATUS;	/* presence status of the memory card */
+
+/** @brief mode of data transfer
+ */
+typedef enum {
+	HAL_MEMCARD_DMA = 0U,
+	HAL_MEMCARD_NOT_DMA = 1U
+} HAL_MEMCARD_DATA_TRANSFER_MODE;
+
+/** @brief Memory card response types.
+ */
+typedef enum hal_memcard_response_type {
+	HAL_MEMCARD_RESPONSE_NONE = 0x00000U,
+	HAL_MEMCARD_RESPONSE_R1 = 0x00100U,
+	HAL_MEMCARD_RESPONSE_R1b = 0x00200U,
+	HAL_MEMCARD_RESPONSE_R2 = 0x00300U,
+	HAL_MEMCARD_RESPONSE_R3 = 0x00400U,
+	HAL_MEMCARD_RESPONSE_R4 = 0x00500U,
+	HAL_MEMCARD_RESPONSE_R5 = 0x00600U,
+	HAL_MEMCARD_RESPONSE_R6 = 0x00700U,
+	HAL_MEMCARD_RESPONSE_R7 = 0x00800U,
+	HAL_MEMCARD_RESPONSE_TYPE_MASK = 0x00f00U
+} HAL_MEMCARD_RESPONSE_TYPE;
+
+/** @brief Memory card command types.
+ */
+typedef enum hal_memcard_command_type {
+	HAL_MEMCARD_COMMAND_TYPE_BC = 0x00000U,
+	HAL_MEMCARD_COMMAND_TYPE_BCR = 0x01000U,
+	HAL_MEMCARD_COMMAND_TYPE_AC = 0x02000U,
+	HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE = 0x03000U,
+	HAL_MEMCARD_COMMAND_TYPE_ADTC_READ = 0x04000U,
+	HAL_MEMCARD_COMMAND_TYPE_MASK = 0x07000U
+} HAL_MEMCARD_COMMAND_TYPE;
+
+/** @brief Type of memory card
+ */
+typedef enum hal_memcard_command_card_type {
+	HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON = 0x00000U,
+	HAL_MEMCARD_COMMAND_CARD_TYPE_MMC = 0x08000U,
+	HAL_MEMCARD_COMMAND_CARD_TYPE_SD = 0x10000U,
+	HAL_MEMCARD_COMMAND_CARD_TYPE_MASK = 0x18000U
+} HAL_MEMCARD_COMMAND_CARD_TYPE;
+
+/** @brief Memory card application command.
+ */
+typedef enum hal_memcard_command_app_norm {
+	HAL_MEMCARD_COMMAND_NORMAL = 0x00000U,
+	HAL_MEMCARD_COMMAND_APP = 0x20000U,
+	HAL_MEMCARD_COMMAND_APP_NORM_MASK = 0x20000U
+} HAL_MEMCARD_COMMAND_APP_NORM;
+
+/** @brief Memory card command codes.
+ */
+typedef enum {
+/* class 0 and class 1 */
+	CMD0_GO_IDLE_STATE = 0 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_BC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD0 */
+	CMD1_SEND_OP_COND = 1 | HAL_MEMCARD_RESPONSE_R3 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD1 */
+	CMD2_ALL_SEND_CID_MMC = 2 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD2 */
+	CMD2_ALL_SEND_CID_SD =
+	    2 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_BCR |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,
+	CMD3_SET_RELATIVE_ADDR = 3 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD3 */
+	CMD3_SEND_RELATIVE_ADDR =
+	    3 | HAL_MEMCARD_RESPONSE_R6 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,
+	CMD4_SET_DSR = 4 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_BC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD4 */
+	CMD5_SLEEP_AWAKE = 5 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD5 */
+	CMD6_SWITCH = 6 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD6 */
+	CMD6_SWITCH_FUNC =
+	    6 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,
+	ACMD6_SET_BUS_WIDTH =
+	    6 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+	CMD7_SELECT_CARD = 7 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD7 */
+	CMD7_SELECT_CARD_PROG = 7 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD7(from Disconnected State to Programming State) */
+	CMD7_DESELECT_CARD =
+	    7 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,
+	CMD8_SEND_EXT_CSD = 8 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD8 */
+	CMD8_SEND_IF_COND =
+	    8 | HAL_MEMCARD_RESPONSE_R7 | HAL_MEMCARD_COMMAND_TYPE_BCR |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,
+	CMD9_SEND_CSD = 9 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD9 */
+	CMD10_SEND_CID = 10 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD10 */
+	CMD11_READ_DAT_UNTIL_STOP = 11 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD11 */
+	CMD12_STOP_TRANSMISSION = 12 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD12 */
+	CMD12_STOP_TRANSMISSION_WRITE = 12 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD12(R1b : write case) */
+	CMD13_SEND_STATUS = 13 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD13 */
+	ACMD13_SD_STATUS =
+	    13 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+	CMD14_BUSTEST_R = 14 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD14 */
+	CMD15_GO_INACTIVE_STATE = 15 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD15 */
+
+/* class 2 */
+	CMD16_SET_BLOCKLEN = 16 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD16 */
+	CMD17_READ_SINGLE_BLOCK = 17 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD17 */
+	CMD18_READ_MULTIPLE_BLOCK = 18 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD18 */
+	CMD19_BUS_TEST_W = 19 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD19 */
+
+/* class 3 */
+	CMD20_WRITE_DAT_UNTIL_STOP = 20 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD20 */
+	CMD21 = 21,		/* CMD21 */
+	CMD22 = 22,		/* CMD22 */
+	ACMD22_SEND_NUM_WR_BLOCKS =
+	    22 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+
+/* class 4 */
+	CMD23_SET_BLOCK_COUNT = 23 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD23 */
+	ACMD23_SET_WR_BLK_ERASE_COUNT =
+	    23 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+	CMD24_WRITE_BLOCK = 24 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD24 */
+	CMD25_WRITE_MULTIPLE_BLOCK = 25 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD25 */
+	CMD26_PROGRAM_CID = 26 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD26 */
+	CMD27_PROGRAM_CSD = 27 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD27 */
+
+/* class 6 */
+	CMD28_SET_WRITE_PROT = 28 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD28 */
+	CMD29_CLR_WRITE_PROT = 29 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD29 */
+	CMD30_SEND_WRITE_PROT = 30 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD30 */
+	CMD30_SEND_WRITE_PROT_TYPE = 31 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD31 */
+
+/* class 5 */
+	CMD32_ERASE_WR_BLK_START = 32 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD32 */
+	CMD33_ERASE_WR_BLK_END = 33 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD33 */
+	CMD34 = 34,		/* CMD34 */
+	CMD35_ERASE_GROUP_START = 35 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD35 */
+	CMD36_ERASE_GROUP_END = 36 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD36 */
+	CMD37 = 37,		/* CMD37 */
+	CMD38_ERASE = 38 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD38 */
+
+/* class 9 */
+	CMD39_FASTIO = 39 | HAL_MEMCARD_RESPONSE_R4 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD39 */
+	CMD40_GO_IRQSTATE = 40 | HAL_MEMCARD_RESPONSE_R5 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD40 */
+	CMD41 = 41,		/* CMD41 */
+	ACMD41_SD_SEND_OP_COND =
+	    41 | HAL_MEMCARD_RESPONSE_R3 | HAL_MEMCARD_COMMAND_TYPE_BCR |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+
+/* class 7 */
+	CMD42_LOCK_UNLOCK = 42 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD42 */
+	ACMD42_SET_CLR_CARD_DETECT =
+	    42 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+	CMD43 = 43,		/* CMD43 */
+	CMD44 = 44,		/* CMD44 */
+	CMD45 = 45,		/* CMD45 */
+	CMD46 = 46,		/* CMD46 */
+	CMD47 = 47,		/* CMD47 */
+	CMD48 = 48,		/* CMD48 */
+	CMD49 = 49,		/* CMD49 */
+	CMD50 = 50,		/* CMD50 */
+	CMD51 = 51,		/* CMD51 */
+	ACMD51_SEND_SCR =
+	    51 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ |
+	    HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP,
+	CMD52 = 52,		/* CMD52 */
+	CMD53 = 53,		/* CMD53 */
+	CMD54 = 54,		/* CMD54 */
+
+/* class 8 */
+	CMD55_APP_CMD = 55 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD55 */
+	CMD56_GEN_CMD = 56 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL,	/* CMD56 */
+	CMD57 = 57,		/* CMD57 */
+	CMD58 = 58,		/* CMD58 */
+	CMD59 = 59,		/* CMD59 */
+	CMD60 = 60,		/* CMD60 */
+	CMD61 = 61,		/* CMD61 */
+	CMD62 = 62,		/* CMD62 */
+	CMD63 = 63		/* CMD63 */
+} HAL_MEMCARD_COMMAND;
+
+/** @brief Configuration structure from HAL layer.
+ *
+ * If some field is not available it should be filled with 0xFF.
+ * The API version is 32-bit unsigned integer telling the version of the API. The integer is divided to four sections which each can be treated as a 8-bit unsigned number:
+ * Bits 31-24 make the most significant part of the version number. This number starts from 1 i.e. the second version of the API will be 0x02xxxxxx. This number changes only, if the API itself changes so much that it is not compatible anymore with older releases.
+ * Bits 23-16 API minor version number. For example API version 2.1 would be 0x0201xxxx.
+ * Bits 15-8 are the number of the year when release is done. The 0 is year 2000, 1 is year 2001 and so on
+ * Bits 7- are the week number when release is done. First full week of the year is 1
+ *
+ * @note Example: let's assume that release 2.1 is done on week 10 year 2008 the version will get the value 0x0201080A
+ */
+typedef struct {
+    /**
+    * Version of the chipset API implementation
+    *
+    * bits [31:24] API specification major version number.<br>
+    * bits [23:16] API specification minor version number.<br>
+    * bits [15:8] API implemention year. (2000 = 0, 2001 = 1, ...)<br>
+    * bits [7:0] API implemention week.<br>
+    * Example: API specification version 4.0, implementation w46 2008 => 0x0400082E
+    */
+	uint32_t api_version;
+
+    /** maximum block count which can be transferred at once */
+	uint32_t max_block_count;
+
+    /** maximum clock frequence in Hz supported by HW */
+	uint32_t max_clock_freq;
+
+    /** maximum data bus width supported by HW */
+	uint16_t max_data_width;
+
+    /** Is high-speed mode supported by HW (yes=1, no=0) */
+	uint8_t hs_mode_supported;
+
+    /** Is memory card removable (yes=1, no=0) */
+	uint8_t card_removable;
+
+} HAL_MEMCARD_HW_CONF;
+
+/** @brief Configuration structure to HAL layer.
+ */
+typedef struct {
+    /** how many times to try after fail, for instance sending command */
+	uint32_t retries_after_fail;
+} HAL_MEMCARD_INIT_CONF;
+
+/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
+
+/* ************************** FUNCTION PROTOTYPES ************************** */
+
+/* ********************************* CODE ********************************** */
+
+#endif /* EMMC_HAL_H */
+
+/* ******************************** END ************************************ */
diff --git a/drivers/renesas/rcar/emmc/emmc_init.c b/drivers/renesas/rcar/emmc/emmc_init.c
new file mode 100644
index 0000000..b27e165
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_init.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+#include "rcar_private.h"
+
+st_mmc_base mmc_drv_obj;
+
+EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode)
+{
+
+	if (mode == TRUE) {
+		/* power on (Vcc&Vccq is always power on) */
+		mmc_drv_obj.card_power_enable = TRUE;
+	} else {
+		/* power off (Vcc&Vccq is always power on) */
+		mmc_drv_obj.card_power_enable = FALSE;
+		mmc_drv_obj.mount = FALSE;
+		mmc_drv_obj.selected = FALSE;
+	}
+
+	return EMMC_SUCCESS;
+}
+static __inline void emmc_set_retry_count(uint32_t retry)
+{
+	mmc_drv_obj.retries_after_fail = retry;
+}
+
+static __inline void emmc_set_data_timeout(uint32_t data_timeout)
+{
+	mmc_drv_obj.data_timeout = data_timeout;
+}
+
+static void emmc_memset(uint8_t *buff, uint8_t data, uint32_t cnt)
+{
+	if (buff == NULL) {
+		return;
+	}
+
+	while (cnt > 0) {
+		*buff++ = data;
+		cnt--;
+	}
+}
+
+static void emmc_driver_config(void)
+{
+	emmc_set_retry_count(EMMC_RETRY_COUNT);
+	emmc_set_data_timeout(EMMC_RW_DATA_TIMEOUT);
+}
+
+static void emmc_drv_init(void)
+{
+	emmc_memset((uint8_t *) (&mmc_drv_obj), 0, sizeof(st_mmc_base));
+	mmc_drv_obj.card_present = HAL_MEMCARD_CARD_IS_IN;
+	mmc_drv_obj.data_timeout = EMMC_RW_DATA_TIMEOUT;
+	mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
+}
+
+static EMMC_ERROR_CODE emmc_dev_finalize(void)
+{
+	EMMC_ERROR_CODE result;
+	uint32_t dataL;
+
+	/* MMC power off
+	 * the power supply of eMMC device is always turning on.
+	 * RST_n : Hi --> Low level.
+	 */
+	result = rcar_emmc_memcard_power(FALSE);
+
+	/* host controller reset */
+	SETR_32(SD_INFO1, 0x00000000U);		/* all interrupt clear */
+	SETR_32(SD_INFO2, SD_INFO2_CLEAR);	/* all interrupt clear */
+	SETR_32(SD_INFO1_MASK, 0x00000000U);	/* all interrupt disable */
+	SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);	/* all interrupt disable */
+	SETR_32(SD_CLK_CTRL, 0x00000000U);	/* MMC clock stop */
+
+	dataL = mmio_read_32(CPG_SMSTPCR3);
+	if ((dataL & CPG_MSTP_MMC) == 0U) {
+		dataL |= (CPG_MSTP_MMC);
+		mmio_write_32(CPG_CPGWPR, (~dataL));
+		mmio_write_32(CPG_SMSTPCR3, dataL);
+	}
+
+	return result;
+}
+
+static EMMC_ERROR_CODE emmc_dev_init(void)
+{
+	/* Enable clock supply to eMMC. */
+	mstpcr_write(CPG_SMSTPCR3, CPG_MSTPSR3, CPG_MSTP_MMC);
+
+	/* Set SD clock */
+	mmio_write_32(CPG_CPGWPR, ~((uint32_t) (BIT9 | BIT0)));	/* SD phy 200MHz */
+
+	/* Stop SDnH clock & SDn=200MHz */
+	mmio_write_32(CPG_SDxCKCR, (BIT9 | BIT0));
+
+	/* MMCIF initialize */
+	SETR_32(SD_INFO1, 0x00000000U);		/* all interrupt clear */
+	SETR_32(SD_INFO2, SD_INFO2_CLEAR);	/* all interrupt clear */
+	SETR_32(SD_INFO1_MASK, 0x00000000U);	/* all interrupt disable */
+	SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);	/* all interrupt disable */
+
+	SETR_32(HOST_MODE, 0x00000000U);	/* SD_BUF access width = 64-bit */
+	SETR_32(SD_OPTION, 0x0000C0EEU);	/* Bus width = 1bit, timeout=MAX */
+	SETR_32(SD_CLK_CTRL, 0x00000000U);	/* Automatic Control=Disable, Clock Output=Disable */
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_reset_controller(void)
+{
+	EMMC_ERROR_CODE retult;
+
+	/* initialize mmc driver */
+	emmc_drv_init();
+
+	/* initialize H/W */
+	retult = emmc_dev_init();
+	if (EMMC_SUCCESS != retult) {
+		return retult;
+	}
+
+	mmc_drv_obj.initialize = TRUE;
+
+	return retult;
+
+}
+
+EMMC_ERROR_CODE emmc_terminate(void)
+{
+	EMMC_ERROR_CODE result;
+
+	result = emmc_dev_finalize();
+
+	emmc_memset((uint8_t *) (&mmc_drv_obj), 0, sizeof(st_mmc_base));
+
+	return result;
+}
+
+EMMC_ERROR_CODE rcar_emmc_init(void)
+{
+	EMMC_ERROR_CODE retult;
+
+	retult = emmc_reset_controller();
+	if (EMMC_SUCCESS != retult) {
+		return retult;
+	}
+
+	emmc_driver_config();
+
+	return EMMC_SUCCESS;
+}
diff --git a/drivers/renesas/rcar/emmc/emmc_interrupt.c b/drivers/renesas/rcar/emmc/emmc_interrupt.c
new file mode 100644
index 0000000..37a3cf9
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_interrupt.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights
+ * reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <lib/mmio.h>
+
+#include "emmc_config.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_registers.h"
+#include "emmc_std.h"
+#include "rcar_def.h"
+
+static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual);
+
+uint32_t emmc_interrupt(void)
+{
+	EMMC_ERROR_CODE result;
+	uint32_t prr_data;
+	uint32_t cut_ver;
+	uint32_t end_bit;
+
+	prr_data = mmio_read_32((uintptr_t) RCAR_PRR);
+	cut_ver = prr_data & RCAR_CUT_MASK;
+	if ((prr_data & RCAR_PRODUCT_MASK) == RCAR_PRODUCT_H3) {
+		if (cut_ver == RCAR_CUT_VER10) {
+			end_bit = BIT17;
+		} else if (cut_ver == RCAR_CUT_VER11) {
+			end_bit = BIT17;
+		} else {
+			end_bit = BIT20;
+		}
+	} else if ((prr_data & RCAR_PRODUCT_MASK) == RCAR_PRODUCT_M3) {
+		if (cut_ver == RCAR_CUT_VER10) {
+			end_bit = BIT17;
+		} else {
+			end_bit = BIT20;
+		}
+	} else {
+		end_bit = BIT20;
+	}
+
+	/* SD_INFO */
+	mmc_drv_obj.error_info.info1 = GETR_32(SD_INFO1);
+	mmc_drv_obj.error_info.info2 = GETR_32(SD_INFO2);
+
+	/* SD_INFO EVENT */
+	mmc_drv_obj.int_event1 =
+	    mmc_drv_obj.error_info.info1 & GETR_32(SD_INFO1_MASK);
+	mmc_drv_obj.int_event2 =
+	    mmc_drv_obj.error_info.info2 & GETR_32(SD_INFO2_MASK);
+
+	/* ERR_STS */
+	mmc_drv_obj.error_info.status1 = GETR_32(SD_ERR_STS1);
+	mmc_drv_obj.error_info.status2 = GETR_32(SD_ERR_STS2);
+
+	/* DM_CM_INFO */
+	mmc_drv_obj.error_info.dm_info1 = GETR_32(DM_CM_INFO1);
+	mmc_drv_obj.error_info.dm_info2 = GETR_32(DM_CM_INFO2);
+
+	/* DM_CM_INFO EVENT */
+	mmc_drv_obj.dm_event1 =
+	    mmc_drv_obj.error_info.dm_info1 & GETR_32(DM_CM_INFO1_MASK);
+	mmc_drv_obj.dm_event2 =
+	    mmc_drv_obj.error_info.dm_info2 & GETR_32(DM_CM_INFO2_MASK);
+
+	/* ERR SD_INFO2 */
+	if ((SD_INFO2_ALL_ERR & mmc_drv_obj.int_event2) != 0) {
+		SETR_32(SD_INFO1_MASK, 0x00000000U);	/* interrupt disable */
+		SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);	/* interrupt disable */
+		SETR_32(SD_INFO1, 0x00000000U);	/* interrupt clear */
+		SETR_32(SD_INFO2, SD_INFO2_CLEAR);	/* interrupt clear */
+		mmc_drv_obj.state_machine_blocking = FALSE;
+	}
+
+	/* PIO Transfer */
+	/* BWE/BRE */
+	else if (((SD_INFO2_BWE | SD_INFO2_BRE) & mmc_drv_obj.int_event2)) {
+		/* BWE */
+		if (SD_INFO2_BWE & mmc_drv_obj.int_event2) {
+			SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BWE));
+		}
+		/* BRE */
+		else {
+			SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BRE));
+		}
+
+		result = emmc_trans_sector(mmc_drv_obj.buff_address_virtual);
+		mmc_drv_obj.buff_address_virtual += EMMC_BLOCK_LENGTH;
+		mmc_drv_obj.remain_size -= EMMC_BLOCK_LENGTH;
+
+		if (result != EMMC_SUCCESS) {
+			/* data transfer error */
+			emmc_write_error_info(EMMC_FUNCNO_NONE, result);
+
+			/* Panic */
+			SETR_32(SD_INFO1_MASK, 0x00000000U);
+			SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR);
+			SETR_32(SD_INFO1, 0x00000000U);
+			/* interrupt clear */
+			SETR_32(SD_INFO2, SD_INFO2_CLEAR);
+			mmc_drv_obj.force_terminate = TRUE;
+		} else {
+			mmc_drv_obj.during_transfer = FALSE;
+		}
+		mmc_drv_obj.state_machine_blocking = FALSE;
+	}
+
+	/* DMA_TRANSFER */
+	/* DM_CM_INFO1: DMA-ch0 transfer complete or error occurred */
+	else if ((BIT16 & mmc_drv_obj.dm_event1) != 0) {
+		SETR_32(DM_CM_INFO1, 0x00000000U);
+		SETR_32(DM_CM_INFO2, 0x00000000U);
+		/* interrupt clear */
+		SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BWE));
+		/* DM_CM_INFO2:  DMA-ch0 error occured */
+		if ((BIT16 & mmc_drv_obj.dm_event2) != 0) {
+			mmc_drv_obj.dma_error_flag = TRUE;
+		} else {
+			mmc_drv_obj.during_dma_transfer = FALSE;
+			mmc_drv_obj.during_transfer = FALSE;
+		}
+		/* wait next interrupt */
+		mmc_drv_obj.state_machine_blocking = FALSE;
+	}
+	/* DM_CM_INFO1: DMA-ch1 transfer complete or error occured */
+	else if ((end_bit & mmc_drv_obj.dm_event1) != 0U) {
+		SETR_32(DM_CM_INFO1, 0x00000000U);
+		SETR_32(DM_CM_INFO2, 0x00000000U);
+		/* interrupt clear */
+		SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BRE));
+		/* DM_CM_INFO2: DMA-ch1 error occured */
+		if ((BIT17 & mmc_drv_obj.dm_event2) != 0) {
+			mmc_drv_obj.dma_error_flag = TRUE;
+		} else {
+			mmc_drv_obj.during_dma_transfer = FALSE;
+			mmc_drv_obj.during_transfer = FALSE;
+		}
+		/* wait next interrupt */
+		mmc_drv_obj.state_machine_blocking = FALSE;
+	}
+
+	/* Response end  */
+	else if ((SD_INFO1_INFO0 & mmc_drv_obj.int_event1) != 0) {
+		/* interrupt clear */
+		SETR_32(SD_INFO1, (GETR_32(SD_INFO1) & ~SD_INFO1_INFO0));
+		mmc_drv_obj.state_machine_blocking = FALSE;
+	}
+	/* Access end  */
+	else if ((SD_INFO1_INFO2 & mmc_drv_obj.int_event1) != 0) {
+		/* interrupt clear */
+		SETR_32(SD_INFO1, (GETR_32(SD_INFO1) & ~SD_INFO1_INFO2));
+		mmc_drv_obj.state_machine_blocking = FALSE;
+	} else {
+		/* nothing to do. */
+	}
+
+	return (uint32_t) 0;
+}
+
+static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual)
+{
+	uint32_t length, i;
+	uint64_t *bufPtrLL;
+
+	if (buff_address_virtual == NULL) {
+		return EMMC_ERR_PARAM;
+	}
+
+	if ((mmc_drv_obj.during_transfer != TRUE)
+	    || (mmc_drv_obj.remain_size == 0)) {
+		return EMMC_ERR_STATE;
+	}
+
+	bufPtrLL = (uint64_t *) buff_address_virtual;
+	length = mmc_drv_obj.remain_size;
+
+	/* data transefer */
+	for (i = 0; i < (length >> 3); i++) {
+		/* Write */
+		if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) {
+			SETR_64(SD_BUF0, *bufPtrLL);	/* buffer --> FIFO */
+		}
+		/* Read */
+		else {
+			/* Checks when the read data reaches SD_SIZE. */
+			/* The BRE bit is cleared at emmc_interrupt function. */
+			if (((i %
+			      (uint32_t) (EMMC_BLOCK_LENGTH >>
+					  EMMC_BUF_SIZE_SHIFT)) == 0U)
+			    && (i != 0U)) {
+				/* BRE check */
+				while (((GETR_32(SD_INFO2)) & SD_INFO2_BRE) ==
+				       0U) {
+					/* ERROR check */
+					if (((GETR_32(SD_INFO2)) &
+					     SD_INFO2_ALL_ERR) != 0U) {
+						return EMMC_ERR_TRANSFER;
+					}
+				}
+				/* BRE clear */
+				SETR_32(SD_INFO2,
+					(uint32_t) (GETR_32(SD_INFO2) &
+						    ~SD_INFO2_BRE));
+			}
+			*bufPtrLL = GETR_64(SD_BUF0);	/* FIFO --> buffer */
+		}
+		bufPtrLL++;
+	}
+
+	return EMMC_SUCCESS;
+}
diff --git a/drivers/renesas/rcar/emmc/emmc_mount.c b/drivers/renesas/rcar/emmc/emmc_mount.c
new file mode 100644
index 0000000..dd57b0c
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_mount.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+#include "micro_delay.h"
+#include "rcar_def.h"
+
+static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode);
+static EMMC_ERROR_CODE emmc_card_init(void);
+static EMMC_ERROR_CODE emmc_high_speed(void);
+static EMMC_ERROR_CODE emmc_bus_width(uint32_t width);
+static uint32_t emmc_set_timeout_register_value(uint32_t freq);
+static void set_sd_clk(uint32_t clkDiv);
+static uint32_t emmc_calc_tran_speed(uint32_t *freq);
+static void emmc_get_partition_access(void);
+static void emmc_set_bootpartition(void);
+
+static void emmc_set_bootpartition(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	if (reg == RCAR_PRODUCT_M3_CUT10) {
+		mmc_drv_obj.boot_partition_en =
+		    (EMMC_PARTITION_ID) ((mmc_drv_obj.ext_csd_data[179] &
+					  EMMC_BOOT_PARTITION_EN_MASK) >>
+					 EMMC_BOOT_PARTITION_EN_SHIFT);
+	} else if ((reg == RCAR_PRODUCT_H3_CUT20)
+		   || (reg == RCAR_PRODUCT_M3_CUT11)) {
+		mmc_drv_obj.boot_partition_en = mmc_drv_obj.partition_access;
+	} else {
+		if ((mmio_read_32(MFISBTSTSR) & MFISBTSTSR_BOOT_PARTITION) !=
+		    0U) {
+			mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_2;
+		} else {
+			mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_1;
+		}
+	}
+}
+
+static EMMC_ERROR_CODE emmc_card_init(void)
+{
+	int32_t retry;
+	uint32_t freq = MMC_400KHZ;	/* 390KHz */
+	EMMC_ERROR_CODE result;
+	uint32_t resultCalc;
+
+	/* state check */
+	if ((mmc_drv_obj.initialize != TRUE)
+	    || (mmc_drv_obj.card_power_enable != TRUE)
+	    || ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0)
+	    ) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* clock on (force change) */
+	mmc_drv_obj.current_freq = 0;
+	mmc_drv_obj.max_freq = MMC_20MHZ;
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return EMMC_ERR;
+	}
+
+	rcar_micro_delay(1000U);	/* wait 1ms */
+
+	/* Get current access partition */
+	emmc_get_partition_access();
+
+	/* CMD0, arg=0x00000000 */
+	result = emmc_send_idle_cmd(0x00000000);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	rcar_micro_delay(200U);	/* wait 74clock 390kHz(189.74us) */
+
+	/* CMD1 */
+	emmc_make_nontrans_cmd(CMD1_SEND_OP_COND, EMMC_HOST_OCR_VALUE);
+	for (retry = 300; retry > 0; retry--) {
+		result =
+		    emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+		if (result != EMMC_SUCCESS) {
+			emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+			return result;
+		}
+
+		if ((mmc_drv_obj.r3_ocr & EMMC_OCR_STATUS_BIT) != 0) {
+			break;	/* card is ready. exit loop */
+		}
+		rcar_micro_delay(1000U);	/* wait 1ms */
+	}
+
+	if (retry == 0) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_TIMEOUT);
+		return EMMC_ERR_TIMEOUT;
+	}
+
+	switch (mmc_drv_obj.r3_ocr & EMMC_OCR_ACCESS_MODE_MASK) {
+	case EMMC_OCR_ACCESS_MODE_SECT:
+		mmc_drv_obj.access_mode = TRUE;	/* sector mode */
+		break;
+	default:
+		/* unknown value */
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR);
+		return EMMC_ERR;
+	}
+
+	/* CMD2 */
+	emmc_make_nontrans_cmd(CMD2_ALL_SEND_CID_MMC, 0x00000000);
+	mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.cid_data[0]);	/* use CID special buffer */
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* CMD3 */
+	emmc_make_nontrans_cmd(CMD3_SET_RELATIVE_ADDR, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* CMD9 (CSD) */
+	emmc_make_nontrans_cmd(CMD9_SEND_CSD, EMMC_RCA << 16);
+	mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.csd_data[0]);	/* use CSD special buffer */
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* card version check */
+	if (EMMC_CSD_SPEC_VARS() < 4) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT,
+				      EMMC_ERR_ILLEGAL_CARD);
+		return EMMC_ERR_ILLEGAL_CARD;
+	}
+
+	/* CMD7 (select card) */
+	emmc_make_nontrans_cmd(CMD7_SELECT_CARD, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	mmc_drv_obj.selected = TRUE;
+
+	/* card speed check */
+	resultCalc = emmc_calc_tran_speed(&freq);	/* Card spec is calculated from TRAN_SPEED(CSD).  */
+	if (resultCalc == 0) {
+		emmc_write_error_info(EMMC_FUNCNO_CARD_INIT,
+				      EMMC_ERR_ILLEGAL_CARD);
+		return EMMC_ERR_ILLEGAL_CARD;
+	}
+	mmc_drv_obj.max_freq = freq;	/* max frequency (card spec) */
+
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return EMMC_ERR;
+	}
+
+	/* set read/write timeout */
+	mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
+	SETR_32(SD_OPTION,
+		((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) |
+		 mmc_drv_obj.data_timeout));
+
+	/* SET_BLOCKLEN(512byte) */
+	/* CMD16 */
+	emmc_make_nontrans_cmd(CMD16_SET_BLOCKLEN, EMMC_BLOCK_LENGTH);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* Transfer Data Length */
+	SETR_32(SD_SIZE, EMMC_BLOCK_LENGTH);
+
+	/* CMD8 (EXT_CSD) */
+	emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
+			    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+			    EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ,
+			    HAL_MEMCARD_NOT_DMA);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		/* CMD12 is not send.
+		 * If BUS initialization is failed, user must be execute Bus initialization again.
+		 * Bus initialization is start CMD0(soft reset command).
+		 */
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		return result;
+	}
+
+	/* Set boot partition */
+	emmc_set_bootpartition();
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_high_speed(void)
+{
+	uint32_t freq;	      /**< High speed mode clock frequency */
+	EMMC_ERROR_CODE result;
+	uint8_t cardType;
+
+	/* state check */
+	if (mmc_drv_obj.selected != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_HIGH_SPEED, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* max frequency */
+	cardType = (uint8_t) mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_CARD_TYPE];
+	if ((cardType & EMMC_EXT_CSD_CARD_TYPE_52MHZ) != 0)
+		freq = MMC_52MHZ;
+	else if ((cardType & EMMC_EXT_CSD_CARD_TYPE_26MHZ) != 0)
+		freq = MMC_26MHZ;
+	else
+		freq = MMC_20MHZ;
+
+	/* Hi-Speed-mode selction */
+	if ((MMC_52MHZ == freq) || (MMC_26MHZ == freq)) {
+		/* CMD6 */
+		emmc_make_nontrans_cmd(CMD6_SWITCH, EMMC_SWITCH_HS_TIMING);
+		result =
+		    emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+		if (result != EMMC_SUCCESS) {
+			emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+			return result;
+		}
+
+		mmc_drv_obj.hs_timing = TIMING_HIGH_SPEED;	/* High-Speed */
+	}
+
+	/* set mmc clock */
+	mmc_drv_obj.max_freq = freq;
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+		return EMMC_ERR;
+	}
+
+	/* set read/write timeout */
+	mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq);
+	SETR_32(SD_OPTION,
+		((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) |
+		 mmc_drv_obj.data_timeout));
+
+	/* CMD13 */
+	emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
+	result =
+	    emmc_exec_cmd(EMMC_R1_ERROR_MASK_WITHOUT_CRC, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+		return result;
+	}
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode)
+{
+	uint32_t value;
+
+	/* busy check */
+	if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK,
+				      EMMC_ERR_CARD_BUSY);
+		return EMMC_ERR;
+	}
+
+	if (mode == TRUE) {
+		/* clock ON */
+		value =
+		    ((GETR_32(SD_CLK_CTRL) | MMC_SD_CLK_START) &
+		     SD_CLK_WRITE_MASK);
+		SETR_32(SD_CLK_CTRL, value);	/* on  */
+		mmc_drv_obj.clock_enable = TRUE;
+	} else {
+		/* clock OFF */
+		value =
+		    ((GETR_32(SD_CLK_CTRL) & MMC_SD_CLK_STOP) &
+		     SD_CLK_WRITE_MASK);
+		SETR_32(SD_CLK_CTRL, value);	/* off */
+		mmc_drv_obj.clock_enable = FALSE;
+	}
+
+	return EMMC_SUCCESS;
+}
+
+static EMMC_ERROR_CODE emmc_bus_width(uint32_t width)
+{
+	EMMC_ERROR_CODE result = EMMC_ERR;
+
+	/* parameter check */
+	if ((width != 8) && (width != 4) && (width != 1)) {
+		emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* state check */
+	if (mmc_drv_obj.selected != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	mmc_drv_obj.bus_width = (HAL_MEMCARD_DATA_WIDTH) (width >> 2);	/* 2 = 8bit, 1 = 4bit, 0 =1bit */
+
+	/* CMD6 */
+	emmc_make_nontrans_cmd(CMD6_SWITCH,
+			       (EMMC_SWITCH_BUS_WIDTH_1 |
+				(mmc_drv_obj.bus_width << 8)));
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		/* occurred error */
+		mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
+		goto EXIT;
+	}
+
+	switch (mmc_drv_obj.bus_width) {
+	case HAL_MEMCARD_DATA_WIDTH_1_BIT:
+		SETR_32(SD_OPTION,
+			((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT15));
+		break;
+	case HAL_MEMCARD_DATA_WIDTH_4_BIT:
+		SETR_32(SD_OPTION, (GETR_32(SD_OPTION) & ~(BIT15 | BIT13)));
+		break;
+	case HAL_MEMCARD_DATA_WIDTH_8_BIT:
+		SETR_32(SD_OPTION,
+			((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT13));
+		break;
+	default:
+		goto EXIT;
+	}
+
+	/* CMD13 */
+	emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		goto EXIT;
+	}
+
+	/* CMD8 (EXT_CSD) */
+	emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
+			    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+			    EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ,
+			    HAL_MEMCARD_NOT_DMA);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		goto EXIT;
+	}
+
+	return EMMC_SUCCESS;
+
+EXIT:
+
+	emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, result);
+	ERROR("BL2: emmc bus_width error end\n");
+	return result;
+}
+
+EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id)
+{
+	EMMC_ERROR_CODE result;
+	uint32_t arg;
+	uint32_t partition_config;
+
+	/* state check */
+	if (mmc_drv_obj.mount != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* id = PARTITION_ACCESS(Bit[2:0]) */
+	if ((id & ~PARTITION_ID_MASK) != 0) {
+		emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* EXT_CSD[179] value */
+	partition_config =
+	    (uint32_t) mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_PARTITION_CONFIG];
+	if ((partition_config & PARTITION_ID_MASK) == id) {
+		result = EMMC_SUCCESS;
+	} else {
+
+		partition_config =
+		    (uint32_t) ((partition_config & ~PARTITION_ID_MASK) | id);
+		arg = EMMC_SWITCH_PARTITION_CONFIG | (partition_config << 8);
+
+		result = emmc_set_ext_csd(arg);
+	}
+
+	return result;
+}
+
+static void set_sd_clk(uint32_t clkDiv)
+{
+	uint32_t dataL;
+
+	dataL = (GETR_32(SD_CLK_CTRL) & (~SD_CLK_CTRL_CLKDIV_MASK));
+
+	switch (clkDiv) {
+	case 1:
+		dataL |= 0x000000FFU;
+		break;		/* 1/1   */
+	case 2:
+		dataL |= 0x00000000U;
+		break;		/* 1/2   */
+	case 4:
+		dataL |= 0x00000001U;
+		break;		/* 1/4   */
+	case 8:
+		dataL |= 0x00000002U;
+		break;		/* 1/8   */
+	case 16:
+		dataL |= 0x00000004U;
+		break;		/* 1/16  */
+	case 32:
+		dataL |= 0x00000008U;
+		break;		/* 1/32  */
+	case 64:
+		dataL |= 0x00000010U;
+		break;		/* 1/64  */
+	case 128:
+		dataL |= 0x00000020U;
+		break;		/* 1/128 */
+	case 256:
+		dataL |= 0x00000040U;
+		break;		/* 1/256 */
+	case 512:
+		dataL |= 0x00000080U;
+		break;		/* 1/512 */
+	}
+
+	SETR_32(SD_CLK_CTRL, dataL);
+	mmc_drv_obj.current_freq = (uint32_t) clkDiv;
+}
+
+static void emmc_get_partition_access(void)
+{
+	uint32_t reg;
+	EMMC_ERROR_CODE result;
+
+	reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	if ((reg == RCAR_PRODUCT_H3_CUT20) || (reg == RCAR_PRODUCT_M3_CUT11)) {
+		SETR_32(SD_OPTION, 0x000060EEU);	/* 8 bits width */
+		/* CMD8 (EXT_CSD) */
+		emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000U,
+				    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+				    EMMC_MAX_EXT_CSD_LENGTH,
+				    HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA);
+		mmc_drv_obj.get_partition_access_flag = TRUE;
+		result =
+		    emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+		mmc_drv_obj.get_partition_access_flag = FALSE;
+		if (result == EMMC_SUCCESS) {
+			mmc_drv_obj.partition_access =
+			    (EMMC_PARTITION_ID) (mmc_drv_obj.ext_csd_data[179]
+						 & PARTITION_ID_MASK);
+		} else if (result == EMMC_ERR_CMD_TIMEOUT) {
+			mmc_drv_obj.partition_access = PARTITION_ID_BOOT_1;
+		} else {
+			emmc_write_error_info(EMMC_FUNCNO_GET_PERTITION_ACCESS,
+					      result);
+			panic();
+		}
+		SETR_32(SD_OPTION, 0x0000C0EEU);	/* Initialize */
+	}
+}
+
+static uint32_t emmc_calc_tran_speed(uint32_t *freq)
+{
+	const uint32_t unit[8] = { 10000, 100000, 1000000, 10000000,
+				0, 0, 0, 0 };   /**< frequency unit (1/10) */
+	const uint32_t mult[16] = { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45,
+				52, 55, 60, 70, 80 };
+
+	uint32_t maxFreq;
+	uint32_t result;
+	uint32_t tran_speed = EMMC_CSD_TRAN_SPEED();
+
+	/* tran_speed = 0x32
+	 * unit[tran_speed&0x7] = uint[0x2] = 1000000
+	 * mult[(tran_speed&0x78)>>3] = mult[0x30>>3] = mult[6] = 26
+	 * 1000000 * 26 = 26000000 (26MHz)
+	 */
+
+	result = 1;
+	maxFreq =
+	    unit[tran_speed & EMMC_TRANSPEED_FREQ_UNIT_MASK] *
+	    mult[(tran_speed & EMMC_TRANSPEED_MULT_MASK) >>
+		 EMMC_TRANSPEED_MULT_SHIFT];
+
+	if (maxFreq == 0) {
+		result = 0;
+	} else if (MMC_FREQ_52MHZ <= maxFreq)
+		*freq = MMC_52MHZ;
+	else if (MMC_FREQ_26MHZ <= maxFreq)
+		*freq = MMC_26MHZ;
+	else if (MMC_FREQ_20MHZ <= maxFreq)
+		*freq = MMC_20MHZ;
+	else
+		*freq = MMC_400KHZ;
+
+	return result;
+}
+
+static uint32_t emmc_set_timeout_register_value(uint32_t freq)
+{
+	uint32_t timeoutCnt;	/* SD_OPTION   - Timeout Counter  */
+
+	switch (freq) {
+	case 1U:
+		timeoutCnt = 0xE0U;
+		break;		/* SDCLK * 2^27 */
+	case 2U:
+		timeoutCnt = 0xE0U;
+		break;		/* SDCLK * 2^27 */
+	case 4U:
+		timeoutCnt = 0xD0U;
+		break;		/* SDCLK * 2^26 */
+	case 8U:
+		timeoutCnt = 0xC0U;
+		break;		/* SDCLK * 2^25 */
+	case 16U:
+		timeoutCnt = 0xB0U;
+		break;		/* SDCLK * 2^24 */
+	case 32U:
+		timeoutCnt = 0xA0U;
+		break;		/* SDCLK * 2^23 */
+	case 64U:
+		timeoutCnt = 0x90U;
+		break;		/* SDCLK * 2^22 */
+	case 128U:
+		timeoutCnt = 0x80U;
+		break;		/* SDCLK * 2^21 */
+	case 256U:
+		timeoutCnt = 0x70U;
+		break;		/* SDCLK * 2^20 */
+	case 512U:
+		timeoutCnt = 0x70U;
+		break;		/* SDCLK * 2^20 */
+	default:
+		timeoutCnt = 0xE0U;
+		break;		/* SDCLK * 2^27 */
+	}
+
+	return timeoutCnt;
+}
+
+EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg)
+{
+	EMMC_ERROR_CODE result;
+
+	/* CMD6 */
+	emmc_make_nontrans_cmd(CMD6_SWITCH, arg);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+
+	/* CMD13 */
+	emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+
+	/* CMD8 (EXT_CSD) */
+	emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000,
+			    (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]),
+			    EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ,
+			    HAL_MEMCARD_NOT_DMA);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+	return EMMC_SUCCESS;
+}
+
+EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq)
+{
+	/* parameter check */
+	if (freq == NULL) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* state check */
+	if ((mmc_drv_obj.initialize != TRUE)
+	    || (mmc_drv_obj.card_power_enable != TRUE)) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* clock is already running in the desired frequency. */
+	if ((mmc_drv_obj.clock_enable == TRUE)
+	    && (mmc_drv_obj.current_freq == *freq)) {
+		return EMMC_SUCCESS;
+	}
+
+	/* busy check */
+	if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) {
+		emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK,
+				      EMMC_ERR_CARD_BUSY);
+		return EMMC_ERR;
+	}
+
+	set_sd_clk(*freq);
+	mmc_drv_obj.clock_enable = FALSE;
+
+	return emmc_clock_ctrl(TRUE);	/* clock on */
+}
+
+EMMC_ERROR_CODE rcar_emmc_mount(void)
+{
+	EMMC_ERROR_CODE result;
+
+	/* state check */
+	if ((mmc_drv_obj.initialize != TRUE)
+	    || (mmc_drv_obj.card_power_enable != TRUE)
+	    || ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0)
+	    ) {
+		emmc_write_error_info(EMMC_FUNCNO_MOUNT, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* initialize card (IDLE state --> Transfer state) */
+	result = emmc_card_init();
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT);
+		if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
+			/* nothing to do. */
+		}
+		return result;
+	}
+
+	/* Switching high speed mode */
+	result = emmc_high_speed();
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED);
+		if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
+			/* nothing to do. */
+		}
+		return result;
+	}
+
+	/* Changing the data bus width */
+	result = emmc_bus_width(8);
+	if (result != EMMC_SUCCESS) {
+		emmc_write_error_info_func_no(EMMC_FUNCNO_BUS_WIDTH);
+		if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) {
+			/* nothing to do. */
+		}
+		return result;
+	}
+
+	/* mount complete */
+	mmc_drv_obj.mount = TRUE;
+
+	return EMMC_SUCCESS;
+}
diff --git a/drivers/renesas/rcar/emmc/emmc_read.c b/drivers/renesas/rcar/emmc/emmc_read.c
new file mode 100644
index 0000000..390d0ca
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_read.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+
+#define MIN_EMMC(a, b)        (((a) < (b)) ? (a) : (b))
+#define EMMC_RW_SECTOR_COUNT_MAX        0x0000ffffU
+
+static EMMC_ERROR_CODE emmc_multiple_block_read (uint32_t *buff_address_virtual,
+		uint32_t sector_number, uint32_t count,
+		HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode)
+{
+	EMMC_ERROR_CODE result;
+
+	/* parameter check */
+	if ((count > EMMC_RW_SECTOR_COUNT_MAX)
+	    || (count == 0)
+	    || ((transfer_mode != HAL_MEMCARD_DMA)
+		&& (transfer_mode != HAL_MEMCARD_NOT_DMA))
+	    ) {
+		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* CMD23 */
+	emmc_make_nontrans_cmd(CMD23_SET_BLOCK_COUNT, count);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+	SETR_32(SD_SECCNT, count);
+	SETR_32(SD_STOP, 0x00000100);
+	SETR_32(CC_EXT_MODE, (CC_EXT_MODE_CLEAR | CC_EXT_MODE_DMASDRW_ENABLE));	/* SD_BUF Read/Write DMA Transfer enable */
+
+	/* CMD18 */
+	emmc_make_trans_cmd(CMD18_READ_MULTIPLE_BLOCK, sector_number,
+			    buff_address_virtual,
+			    count << EMMC_SECTOR_SIZE_SHIFT, HAL_MEMCARD_READ,
+			    transfer_mode);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;	/* CMD18 error code */
+	}
+
+	/* CMD13 */
+	emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16);
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+#if RCAR_BL2_DCACHE == 1
+	if (transfer_mode == HAL_MEMCARD_NOT_DMA) {
+		flush_dcache_range((uint64_t) buff_address_virtual,
+				   ((size_t) count << EMMC_SECTOR_SIZE_SHIFT));
+	}
+#endif /* RCAR_BL2_DCACHE == 1 */
+
+	/* ready status check */
+	if ((mmc_drv_obj.r1_card_status & EMMC_R1_READY) == 0) {
+		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR,
+				      EMMC_ERR_CARD_BUSY);
+		return EMMC_ERR_CARD_BUSY;
+	}
+
+	/* state check */
+	if (mmc_drv_obj.current_state != EMMC_R1_STATE_TRAN) {
+		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR,
+				      EMMC_ERR_CARD_STATE);
+		return EMMC_ERR_CARD_STATE;
+	}
+
+	return EMMC_SUCCESS;
+}
+
+EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual,
+				 uint32_t sector_number,
+				 uint32_t count, uint32_t feature_flags)
+{
+	uint32_t trans_count;
+	uint32_t remain;
+	EMMC_ERROR_CODE result;
+	HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode;
+
+	/* parameter check */
+	if (count == 0) {
+		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM);
+		return EMMC_ERR_PARAM;
+	}
+
+	/* state check */
+	if (mmc_drv_obj.mount != TRUE) {
+		emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_STATE);
+		return EMMC_ERR_STATE;
+	}
+
+	/* DMA? */
+	if ((feature_flags & LOADIMAGE_FLAGS_DMA_ENABLE) != 0) {
+		transfer_mode = HAL_MEMCARD_DMA;
+	} else {
+		transfer_mode = HAL_MEMCARD_NOT_DMA;
+	}
+
+	remain = count;
+	while (remain != 0) {
+		trans_count = MIN_EMMC(remain, EMMC_RW_SECTOR_COUNT_MAX);
+		result =
+		    emmc_multiple_block_read(buff_address_virtual,
+					     sector_number, trans_count,
+					     transfer_mode);
+		if (result != EMMC_SUCCESS) {
+			return result;
+		}
+
+		buff_address_virtual += (EMMC_BLOCK_LENGTH_DW * trans_count);
+		sector_number += trans_count;
+		remain -= trans_count;
+	}
+
+	return EMMC_SUCCESS;
+}
diff --git a/drivers/renesas/rcar/emmc/emmc_registers.h b/drivers/renesas/rcar/emmc/emmc_registers.h
new file mode 100644
index 0000000..55ff33d
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_registers.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file  emmc_registers.h
+ * @brief emmc boot driver is expecting this header file. HS-MMC module header file.
+ *
+ */
+
+#ifndef EMMC_REGISTERS_H
+#define EMMC_REGISTERS_H
+
+/* ************************ HEADER (INCLUDE) SECTION *********************** */
+
+/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
+
+/* MMC channel select */
+#define MMC_CH0		(0U)	/* SDHI2/MMC0 */
+#define MMC_CH1		(1U)	/* SDHI3/MMC1 */
+
+#if RCAR_LSI == RCAR_E3
+#define USE_MMC_CH	(MMC_CH1)	/* R-Car E3 */
+#else /* RCAR_LSI == RCAR_E3 */
+#define USE_MMC_CH	(MMC_CH0)	/* R-Car H3/M3/M3N */
+#endif /* RCAR_LSI == RCAR_E3 */
+
+#define		BIT0	(0x00000001U)
+#define		BIT1	(0x00000002U)
+#define		BIT2	(0x00000004U)
+#define		BIT3	(0x00000008U)
+#define		BIT4	(0x00000010U)
+#define		BIT5	(0x00000020U)
+#define		BIT6	(0x00000040U)
+#define		BIT7	(0x00000080U)
+#define		BIT8	(0x00000100U)
+#define		BIT9	(0x00000200U)
+#define		BIT10	(0x00000400U)
+#define		BIT11	(0x00000800U)
+#define		BIT12	(0x00001000U)
+#define		BIT13	(0x00002000U)
+#define		BIT14	(0x00004000U)
+#define		BIT15	(0x00008000U)
+#define		BIT16	(0x00010000U)
+#define		BIT17	(0x00020000U)
+#define		BIT18	(0x00040000U)
+#define		BIT19	(0x00080000U)
+#define		BIT20	(0x00100000U)
+#define		BIT21	(0x00200000U)
+#define		BIT22	(0x00400000U)
+#define		BIT23	(0x00800000U)
+#define		BIT24	(0x01000000U)
+#define		BIT25	(0x02000000U)
+#define		BIT26	(0x04000000U)
+#define		BIT27	(0x08000000U)
+#define		BIT28	(0x10000000U)
+#define		BIT29	(0x20000000U)
+#define		BIT30	(0x40000000U)
+#define		BIT31	(0x80000000U)
+
+/** @brief Clock Pulse Generator (CPG) registers
+ */
+#define	CPG_BASE		(0xE6150000U)
+
+#define	CPG_MSTPSR3		(CPG_BASE+0x0048U)	/* Module stop status register 3 */
+
+#define	CPG_SMSTPCR3		(CPG_BASE+0x013CU)	/* System module stop control register 3 */
+
+#define	CPG_SD2CKCR		(CPG_BASE+0x0268U)	/* SDHI2 clock frequency control register */
+#define CPG_SD3CKCR		(CPG_BASE+0x026CU)	/* SDHI3 clock frequency control register */
+
+#define	CPG_CPGWPR		(CPG_BASE+0x0900U)	/* CPG Write Protect Register */
+
+#if USE_MMC_CH == MMC_CH0
+#define	CPG_SDxCKCR		(CPG_SD2CKCR)	/* SDHI2/MMC0 */
+#else /* USE_MMC_CH == MMC_CH0 */
+#define	CPG_SDxCKCR		(CPG_SD3CKCR)	/* SDHI3/MMC1 */
+#endif /* USE_MMC_CH == MMC_CH0 */
+
+/** Boot Status register
+ */
+#define  MFISBTSTSR			(0xE6260604U)
+
+#define  MFISBTSTSR_BOOT_PARTITION	(0x00000010U)
+
+/** brief eMMC registers
+ */
+#define	MMC0_SD_BASE		(0xEE140000U)
+#define MMC1_SD_BASE		(0xEE160000U)
+
+#if USE_MMC_CH == MMC_CH0
+#define	MMC_SD_BASE		(MMC0_SD_BASE)
+#else /* USE_MMC_CH == MMC_CH0 */
+#define	MMC_SD_BASE		(MMC1_SD_BASE)
+#endif /* USE_MMC_CH == MMC_CH0 */
+
+#define SD_CMD			(MMC_SD_BASE + 0x0000U)
+#define SD_PORTSEL		(MMC_SD_BASE + 0x0008U)
+#define SD_ARG			(MMC_SD_BASE + 0x0010U)
+#define SD_ARG1			(MMC_SD_BASE + 0x0018U)
+#define SD_STOP			(MMC_SD_BASE + 0x0020U)
+#define SD_SECCNT		(MMC_SD_BASE + 0x0028U)
+#define SD_RSP10		(MMC_SD_BASE + 0x0030U)
+#define SD_RSP1			(MMC_SD_BASE + 0x0038U)
+#define SD_RSP32		(MMC_SD_BASE + 0x0040U)
+#define SD_RSP3			(MMC_SD_BASE + 0x0048U)
+#define SD_RSP54		(MMC_SD_BASE + 0x0050U)
+#define SD_RSP5			(MMC_SD_BASE + 0x0058U)
+#define SD_RSP76		(MMC_SD_BASE + 0x0060U)
+#define SD_RSP7			(MMC_SD_BASE + 0x0068U)
+#define SD_INFO1		(MMC_SD_BASE + 0x0070U)
+#define SD_INFO2		(MMC_SD_BASE + 0x0078U)
+#define SD_INFO1_MASK		(MMC_SD_BASE + 0x0080U)
+#define SD_INFO2_MASK		(MMC_SD_BASE + 0x0088U)
+#define SD_CLK_CTRL		(MMC_SD_BASE + 0x0090U)
+#define SD_SIZE			(MMC_SD_BASE + 0x0098U)
+#define SD_OPTION		(MMC_SD_BASE + 0x00A0U)
+#define SD_ERR_STS1		(MMC_SD_BASE + 0x00B0U)
+#define SD_ERR_STS2		(MMC_SD_BASE + 0x00B8U)
+#define SD_BUF0			(MMC_SD_BASE + 0x00C0U)
+#define SDIO_MODE		(MMC_SD_BASE + 0x00D0U)
+#define SDIO_INFO1		(MMC_SD_BASE + 0x00D8U)
+#define SDIO_INFO1_MASK		(MMC_SD_BASE + 0x00E0U)
+#define CC_EXT_MODE		(MMC_SD_BASE + 0x0360U)
+#define SOFT_RST		(MMC_SD_BASE + 0x0380U)
+#define VERSION			(MMC_SD_BASE + 0x0388U)
+#define HOST_MODE		(MMC_SD_BASE + 0x0390U)
+#define DM_CM_DTRAN_MODE	(MMC_SD_BASE + 0x0820U)
+#define DM_CM_DTRAN_CTRL	(MMC_SD_BASE + 0x0828U)
+#define DM_CM_RST		(MMC_SD_BASE + 0x0830U)
+#define DM_CM_INFO1		(MMC_SD_BASE + 0x0840U)
+#define DM_CM_INFO1_MASK	(MMC_SD_BASE + 0x0848U)
+#define DM_CM_INFO2		(MMC_SD_BASE + 0x0850U)
+#define DM_CM_INFO2_MASK	(MMC_SD_BASE + 0x0858U)
+#define DM_DTRAN_ADDR		(MMC_SD_BASE + 0x0880U)
+
+/** @brief SD_INFO1 Registers
+ */
+#define SD_INFO1_HPIRES				0x00010000UL	/* Response Reception Completion        */
+#define SD_INFO1_INFO10				0x00000400UL	/* Indicates the SDDAT3 state           */
+#define SD_INFO1_INFO9				0x00000200UL	/* SDDAT3 Card Insertion                        */
+#define SD_INFO1_INFO8				0x00000100UL	/* SDDAT3 Card Removal                          */
+#define SD_INFO1_INFO7				0x00000080UL	/* Write Protect                                        */
+#define SD_INFO1_INFO5				0x00000020UL	/* Indicates the ISDCD state            */
+#define SD_INFO1_INFO4				0x00000010UL	/* ISDCD Card Insertion                         */
+#define SD_INFO1_INFO3				0x00000008UL	/* ISDCD Card Removal                           */
+#define SD_INFO1_INFO2				0x00000004UL	/* Access end                                           */
+#define SD_INFO1_INFO0				0x00000001UL	/* Response end                                         */
+
+/** @brief SD_INFO2 Registers
+ */
+#define SD_INFO2_ILA				0x00008000UL	/* Illegal Access Error                 */
+#define SD_INFO2_CBSY				0x00004000UL	/* Command Type Register Busy   */
+#define SD_INFO2_SCLKDIVEN			0x00002000UL
+#define SD_INFO2_BWE				0x00000200UL	/* SD_BUF Write Enable                  */
+#define SD_INFO2_BRE				0x00000100UL	/* SD_BUF Read Enable                   */
+#define SD_INFO2_DAT0				0x00000080UL	/* SDDAT0                                               */
+#define SD_INFO2_ERR6				0x00000040UL	/* Response Timeout                             */
+#define SD_INFO2_ERR5				0x00000020UL	/* SD_BUF Illegal Read Access   */
+#define SD_INFO2_ERR4				0x00000010UL	/* SD_BUF Illegal Write Access  */
+#define SD_INFO2_ERR3				0x00000008UL	/* Data Timeout                                 */
+#define SD_INFO2_ERR2				0x00000004UL	/* END Error                                    */
+#define SD_INFO2_ERR1				0x00000002UL	/* CRC Error                                    */
+#define SD_INFO2_ERR0				0x00000001UL	/* CMD Error                                    */
+#define SD_INFO2_ALL_ERR			0x0000807FUL
+#define SD_INFO2_CLEAR				0x00000800UL	/* BIT11 The write value should always be 1. HWM_0003 */
+
+/** @brief SOFT_RST
+ */
+#define SOFT_RST_SDRST				0x00000001UL
+
+/** @brief SD_CLK_CTRL
+ */
+#define SD_CLK_CTRL_SDCLKOFFEN		0x00000200UL
+#define SD_CLK_CTRL_SCLKEN			0x00000100UL
+#define SD_CLK_CTRL_CLKDIV_MASK     0x000000FFUL
+#define SD_CLOCK_ENABLE             0x00000100UL
+#define SD_CLOCK_DISABLE            0x00000000UL
+#define SD_CLK_WRITE_MASK           0x000003FFUL
+#define SD_CLK_CLKDIV_CLEAR_MASK    0xFFFFFF0FUL
+
+/** @brief SD_OPTION
+ */
+#define SD_OPTION_TIMEOUT_CNT_MASK	0x000000F0UL
+
+/** @brief MMC Clock Frequency
+ * 200MHz * 1/x = output clock
+ */
+#define MMC_CLK_OFF			0UL	/* Clock output is disabled                                                             */
+#define MMC_400KHZ			512UL	/* 200MHz * 1/512 = 390 KHz                             */
+#define MMC_20MHZ			16UL	/* 200MHz * 1/16   = 12.5 MHz Normal speed mode         */
+#define MMC_26MHZ			8UL	/* 200MHz * 1/8   = 25 MHz High speed mode 26Mhz        */
+#define MMC_52MHZ			4UL	/* 200MHz * 1/4   = 50 MHz High speed mode 52Mhz        */
+#define MMC_100MHZ			2UL	/* 200MHz * 1/2   = 100 MHz                             */
+#define MMC_200MHZ			1UL	/* 200MHz * 1/1   = 200 MHz                             */
+
+#define MMC_FREQ_52MHZ		52000000UL
+#define MMC_FREQ_26MHZ		26000000UL
+#define MMC_FREQ_20MHZ		20000000UL
+
+/** @brief MMC Clock DIV
+ */
+#define MMC_SD_CLK_START	0x00000100UL	/* CLOCK On             */
+#define MMC_SD_CLK_STOP		(~0x00000100UL)	/* CLOCK stop   */
+#define MMC_SD_CLK_DIV1		0x000000FFUL	/* 1/1          */
+#define MMC_SD_CLK_DIV2		0x00000000UL	/* 1/2          */
+#define MMC_SD_CLK_DIV4		0x00000001UL	/* 1/4          */
+#define MMC_SD_CLK_DIV8		0x00000002UL	/* 1/8          */
+#define MMC_SD_CLK_DIV16	0x00000004UL	/* 1/16         */
+#define MMC_SD_CLK_DIV32	0x00000008UL	/* 1/32         */
+#define MMC_SD_CLK_DIV64	0x00000010UL	/* 1/64         */
+#define MMC_SD_CLK_DIV128	0x00000020UL	/* 1/128        */
+#define MMC_SD_CLK_DIV256	0x00000040UL	/* 1/256        */
+#define MMC_SD_CLK_DIV512	0x00000080UL	/* 1/512        */
+
+/** @brief DM_CM_DTRAN_MODE
+ */
+#define DM_CM_DTRAN_MODE_CH0		0x00000000UL	/* CH0(downstream)      */
+#define DM_CM_DTRAN_MODE_CH1		0x00010000UL	/* CH1(upstream)        */
+#define DM_CM_DTRAN_MODE_BIT_WIDTH	0x00000030UL
+
+/** @brief CC_EXT_MODE
+ */
+#define CC_EXT_MODE_DMASDRW_ENABLE	0x00000002UL	/* SD_BUF Read/Write DMA Transfer */
+#define CC_EXT_MODE_CLEAR			0x00001010UL	/* BIT 12 & 4 always 1. */
+
+/** @brief DM_CM_INFO_MASK
+ */
+#define DM_CM_INFO_MASK_CLEAR		0xFFFCFFFEUL
+#define DM_CM_INFO_CH0_ENABLE		0x00010001UL
+#define DM_CM_INFO_CH1_ENABLE		0x00020001UL
+
+/** @brief DM_DTRAN_ADDR
+ */
+#define DM_DTRAN_ADDR_WRITE_MASK	0xFFFFFFF8UL
+
+/** @brief DM_CM_DTRAN_CTRL
+ */
+#define DM_CM_DTRAN_CTRL_START		0x00000001UL
+
+/** @brief SYSC Registers
+ */
+#if USE_MMC_CH == MMC_CH0
+#define CPG_MSTP_MMC		(BIT12)	/* SDHI2/MMC0 */
+#else /* USE_MMC_CH == MMC_CH0 */
+#define CPG_MSTP_MMC		(BIT11)	/* SDHI3/MMC1 */
+#endif /* USE_MMC_CH == MMC_CH0 */
+
+/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
+
+/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
+
+/* ************************** FUNCTION PROTOTYPES ************************** */
+
+/* ********************************* CODE ********************************** */
+
+#endif /* EMMC_REGISTERS_H */
+/* ******************************** END ************************************ */
diff --git a/drivers/renesas/rcar/emmc/emmc_std.h b/drivers/renesas/rcar/emmc/emmc_std.h
new file mode 100644
index 0000000..99cb6b9
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_std.h
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file  emmc_std.h
+ * @brief eMMC boot is expecting this header file
+ *
+ */
+
+#ifndef EMMC_STD_H
+#define EMMC_STD_H
+
+#include "emmc_hal.h"
+
+/* ************************ HEADER (INCLUDE) SECTION *********************** */
+
+/* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */
+#ifndef FALSE
+#define FALSE	0U
+#endif
+#ifndef TRUE
+#define TRUE	1U
+#endif
+
+/** @brief 64bit registers
+ **/
+#define SETR_64(r, v)                   (*(volatile uint64_t *)(r) = (v))
+#define GETR_64(r)                      (*(volatile uint64_t *)(r))
+
+/** @brief 32bit registers
+ **/
+#define SETR_32(r, v)                   (*(volatile uint32_t *)(r) = (v))
+#define GETR_32(r)                      (*(volatile uint32_t *)(r))
+
+/** @brief 16bit registers
+ */
+#define SETR_16(r, v)                   (*(volatile uint16_t *)(r) = (v))
+#define GETR_16(r)                      (*(volatile uint16_t *)(r))
+
+/** @brief 8bit registers
+ */
+#define SETR_8(r, v)                    (*(volatile uint8_t *)(r) = (v))
+#define GETR_8(r)                       (*(volatile uint8_t *)(r))
+
+/** @brief CSD register Macros
+ */
+#define EMMC_GET_CID(x, y) (emmc_bit_field(mmc_drv_obj.cid_data, (x), (y)))
+
+#define EMMC_CID_MID()			(EMMC_GET_CID(127, 120))
+#define EMMC_CID_CBX()			(EMMC_GET_CID(113, 112))
+#define EMMC_CID_OID()			(EMMC_GET_CID(111, 104))
+#define EMMC_CID_PNM1()			(EMMC_GET_CID(103, 88))
+#define EMMC_CID_PNM2()			(EMMC_GET_CID(87, 56))
+#define EMMC_CID_PRV()			(EMMC_GET_CID(55, 48))
+#define EMMC_CID_PSN()			(EMMC_GET_CID(47, 16))
+#define EMMC_CID_MDT()			(EMMC_GET_CID(15, 8))
+#define EMMC_CID_CRC()			(EMMC_GET_CID(7, 1))
+
+/** @brief CSD register Macros
+ */
+#define EMMC_GET_CSD(x, y) (emmc_bit_field(mmc_drv_obj.csd_data, (x), (y)))
+
+#define EMMC_CSD_CSD_STRUCTURE()        (EMMC_GET_CSD(127, 126))
+#define EMMC_CSD_SPEC_VARS()            (EMMC_GET_CSD(125, 122))
+#define EMMC_CSD_TAAC()                 (EMMC_GET_CSD(119, 112))
+#define EMMC_CSD_NSAC()                 (EMMC_GET_CSD(111, 104))
+#define EMMC_CSD_TRAN_SPEED()           (EMMC_GET_CSD(103, 96))
+#define EMMC_CSD_CCC()                  (EMMC_GET_CSD(95, 84))
+#define EMMC_CSD_READ_BL_LEN()          (EMMC_GET_CSD(83, 80))
+#define EMMC_CSD_READ_BL_PARTIAL()      (EMMC_GET_CSD(79, 79))
+#define EMMC_CSD_WRITE_BLK_MISALIGN()   (EMMC_GET_CSD(78, 78))
+#define EMMC_CSD_READ_BLK_MISALIGN()    (EMMC_GET_CSD(77, 77))
+#define EMMC_CSD_DSR_IMP()              (EMMC_GET_CSD(76, 76))
+#define EMMC_CSD_C_SIZE()               (EMMC_GET_CSD(73, 62))
+#define EMMC_CSD_VDD_R_CURR_MIN()       (EMMC_GET_CSD(61, 59))
+#define EMMC_CSD_VDD_R_CURR_MAX()       (EMMC_GET_CSD(58, 56))
+#define EMMC_CSD_VDD_W_CURR_MIN()       (EMMC_GET_CSD(55, 53))
+#define EMMC_CSD_VDD_W_CURR_MAX()       (EMMC_GET_CSD(52, 50))
+#define EMMC_CSD_C_SIZE_MULT()          (EMMC_GET_CSD(49, 47))
+#define EMMC_CSD_ERASE_GRP_SIZE()       (EMMC_GET_CSD(46, 42))
+#define EMMC_CSD_ERASE_GRP_MULT()       (EMMC_GET_CSD(41, 37))
+#define EMMC_CSD_WP_GRP_SIZE()          (EMMC_GET_CSD(36, 32))
+#define EMMC_CSD_WP_GRP_ENABLE()        (EMMC_GET_CSD(31, 31))
+#define EMMC_CSD_DEFALT_ECC()           (EMMC_GET_CSD(30, 29))
+#define EMMC_CSD_R2W_FACTOR()           (EMMC_GET_CSD(28, 26))
+#define EMMC_CSD_WRITE_BL_LEN()         (EMMC_GET_CSD(25, 22))
+#define EMMC_CSD_WRITE_BL_PARTIAL()     (EMMC_GET_CSD(21, 21))
+#define EMMC_CSD_CONTENT_PROT_APP()     (EMMC_GET_CSD(16, 16))
+#define EMMC_CSD_FILE_FORMAT_GRP()      (EMMC_GET_CSD(15, 15))
+#define EMMC_CSD_COPY()                 (EMMC_GET_CSD(14, 14))
+#define EMMC_CSD_PERM_WRITE_PROTECT()   (EMMC_GET_CSD(13, 13))
+#define EMMC_CSD_TMP_WRITE_PROTECT()    (EMMC_GET_CSD(12, 12))
+#define EMMC_CSD_FILE_FORMAT()          (EMMC_GET_CSD(11, 10))
+#define EMMC_CSD_ECC()                  (EMMC_GET_CSD(9, 8))
+#define EMMC_CSD_CRC()                  (EMMC_GET_CSD(7, 1))
+
+/** @brief for sector access
+ */
+#define EMMC_4B_BOUNDARY_CHECK_MASK         0x00000003
+#define EMMC_SECTOR_SIZE_SHIFT              9U	/* 512 = 2^9 */
+#define EMMC_SECTOR_SIZE                    512
+#define EMMC_BLOCK_LENGTH                   512
+#define EMMC_BLOCK_LENGTH_DW                128
+#define EMMC_BUF_SIZE_SHIFT                 3U	/* 8byte = 2^3 */
+
+/** @brief eMMC specification clock
+ */
+#define EMMC_CLOCK_SPEC_400K                400000UL	 /**< initialize clock 400KHz */
+#define EMMC_CLOCK_SPEC_20M                 20000000UL	 /**< normal speed 20MHz */
+#define EMMC_CLOCK_SPEC_26M                 26000000UL	 /**< high speed 26MHz */
+#define EMMC_CLOCK_SPEC_52M                 52000000UL	 /**< high speed 52MHz */
+#define EMMC_CLOCK_SPEC_100M                100000000UL	 /**< high speed 100MHz */
+
+/** @brief EMMC driver error code. (extended HAL_MEMCARD_RETURN)
+ */
+typedef enum {
+	EMMC_ERR = 0,				/**< unknown error */
+	EMMC_SUCCESS,				/**< OK */
+	EMMC_ERR_FROM_DMAC,			/**< DMAC allocation error */
+	EMMC_ERR_FROM_DMAC_TRANSFER,		/**< DMAC transfer error */
+	EMMC_ERR_CARD_STATUS_BIT,		/**< card status error. Non-masked error bit was set in the card status */
+	EMMC_ERR_CMD_TIMEOUT,			/**< command timeout error */
+	EMMC_ERR_DATA_TIMEOUT,			/**< data timeout error */
+	EMMC_ERR_CMD_CRC,			/**< command CRC error */
+	EMMC_ERR_DATA_CRC,			/**< data CRC error */
+	EMMC_ERR_PARAM,				/**< parameter error */
+	EMMC_ERR_RESPONSE,			/**< response error */
+	EMMC_ERR_RESPONSE_BUSY,			/**< response busy error */
+	EMMC_ERR_TRANSFER,			/**< data transfer error */
+	EMMC_ERR_READ_SECTOR,			/**< read sector error */
+	EMMC_ERR_WRITE_SECTOR,			/**< write sector error */
+	EMMC_ERR_STATE,				/**< state error */
+	EMMC_ERR_TIMEOUT,			/**< timeout error */
+	EMMC_ERR_ILLEGAL_CARD,			/**< illegal card */
+	EMMC_ERR_CARD_BUSY,			/**< Busy state */
+	EMMC_ERR_CARD_STATE,			/**< card state error */
+	EMMC_ERR_SET_TRACE,			/**< trace information error */
+	EMMC_ERR_FROM_TIMER,			/**< Timer error */
+	EMMC_ERR_FORCE_TERMINATE,		/**< Force terminate */
+	EMMC_ERR_CARD_POWER,			/**< card power fail */
+	EMMC_ERR_ERASE_SECTOR,			/**< erase sector error */
+	EMMC_ERR_INFO2				    /**< exec cmd error info2 */
+} EMMC_ERROR_CODE;
+
+/** @brief Function number */
+#define EMMC_FUNCNO_NONE						0U
+#define EMMC_FUNCNO_DRIVER_INIT						1U
+#define EMMC_FUNCNO_CARD_POWER_ON					2U
+#define EMMC_FUNCNO_MOUNT						3U
+#define EMMC_FUNCNO_CARD_INIT						4U
+#define EMMC_FUNCNO_HIGH_SPEED						5U
+#define EMMC_FUNCNO_BUS_WIDTH						6U
+#define EMMC_FUNCNO_MULTI_BOOT_SELECT_PARTITION				7U
+#define EMMC_FUNCNO_MULTI_BOOT_READ_SECTOR				8U
+#define EMMC_FUNCNO_TRANS_DATA_READ_SECTOR				9U
+#define EMMC_FUNCNO_UBOOT_IMAGE_SELECT_PARTITION			10U
+#define EMMC_FUNCNO_UBOOT_IMAGE_READ_SECTOR				11U
+#define EMMC_FUNCNO_SET_CLOCK						12U
+#define EMMC_FUNCNO_EXEC_CMD						13U
+#define EMMC_FUNCNO_READ_SECTOR						14U
+#define EMMC_FUNCNO_WRITE_SECTOR					15U
+#define EMMC_FUNCNO_ERASE_SECTOR					16U
+#define EMMC_FUNCNO_GET_PERTITION_ACCESS				17U
+/** @brief Response
+ */
+/** R1 */
+#define EMMC_R1_ERROR_MASK                      0xFDBFE080U	/* Type 'E' bit and bit14(must be 0). ignore bit22 */
+#define EMMC_R1_ERROR_MASK_WITHOUT_CRC          (0xFD3FE080U)	/* Ignore bit23 (Not check CRC error) */
+#define EMMC_R1_STATE_MASK                      0x00001E00U	/* [12:9] */
+#define EMMC_R1_READY                           0x00000100U	/* bit8 */
+#define EMMC_R1_STATE_SHIFT                     9
+
+/** R4 */
+#define EMMC_R4_RCA_MASK                        0xFFFF0000UL
+#define EMMC_R4_STATUS                          0x00008000UL
+
+/** CSD */
+#define EMMC_TRANSPEED_FREQ_UNIT_MASK           0x07	/* bit[2:0] */
+#define EMMC_TRANSPEED_FREQ_UNIT_SHIFT          0
+#define EMMC_TRANSPEED_MULT_MASK                0x78	/* bit[6:3] */
+#define EMMC_TRANSPEED_MULT_SHIFT               3
+
+/** OCR */
+#define EMMC_HOST_OCR_VALUE                     0x40FF8080
+#define EMMC_OCR_STATUS_BIT                     0x80000000L	/* Card power up status bit */
+#define EMMC_OCR_ACCESS_MODE_MASK               0x60000000L	/* bit[30:29] */
+#define EMMC_OCR_ACCESS_MODE_SECT               0x40000000L
+#define EMMC_OCR_ACCESS_MODE_BYTE               0x00000000L
+
+/** EXT_CSD */
+#define EMMC_EXT_CSD_S_CMD_SET                      504
+#define EMMC_EXT_CSD_INI_TIMEOUT_AP                 241
+#define EMMC_EXT_CSD_PWR_CL_DDR_52_360              239
+#define EMMC_EXT_CSD_PWR_CL_DDR_52_195              238
+#define EMMC_EXT_CSD_MIN_PERF_DDR_W_8_52            235
+#define EMMC_EXT_CSD_MIN_PERF_DDR_R_8_52            234
+#define EMMC_EXT_CSD_TRIM_MULT                      232
+#define EMMC_EXT_CSD_SEC_FEATURE_SUPPORT            231
+#define EMMC_EXT_CSD_SEC_ERASE_MULT                 229
+#define EMMC_EXT_CSD_BOOT_INFO                      228
+#define EMMC_EXT_CSD_BOOT_SIZE_MULTI                226
+#define EMMC_EXT_CSD_ACC_SIZE                       225
+#define EMMC_EXT_CSD_HC_ERASE_GRP_SIZE              224
+#define EMMC_EXT_CSD_ERASE_TIMEOUT_MULT             223
+#define EMMC_EXT_CSD_PEL_WR_SEC_C                   222
+#define EMMC_EXT_CSD_HC_WP_GRP_SIZE                 221
+#define EMMC_EXT_CSD_S_C_VCC                        220
+#define EMMC_EXT_CSD_S_C_VCCQ                       219
+#define EMMC_EXT_CSD_S_A_TIMEOUT                    217
+#define EMMC_EXT_CSD_SEC_COUNT                      215
+#define EMMC_EXT_CSD_MIN_PERF_W_8_52                210
+#define EMMC_EXT_CSD_MIN_PERF_R_8_52                209
+#define EMMC_EXT_CSD_MIN_PERF_W_8_26_4_52           208
+#define EMMC_EXT_CSD_MIN_PERF_R_8_26_4_52           207
+#define EMMC_EXT_CSD_MIN_PERF_W_4_26                206
+#define EMMC_EXT_CSD_MIN_PERF_R_4_26                205
+#define EMMC_EXT_CSD_PWR_CL_26_360                  203
+#define EMMC_EXT_CSD_PWR_CL_52_360                  202
+#define EMMC_EXT_CSD_PWR_CL_26_195                  201
+#define EMMC_EXT_CSD_PWR_CL_52_195                  200
+#define EMMC_EXT_CSD_CARD_TYPE                      196
+#define EMMC_EXT_CSD_CSD_STRUCTURE                  194
+#define EMMC_EXT_CSD_EXT_CSD_REV                    192
+#define EMMC_EXT_CSD_CMD_SET                        191
+#define EMMC_EXT_CSD_CMD_SET_REV                    189
+#define EMMC_EXT_CSD_POWER_CLASS                    187
+#define EMMC_EXT_CSD_HS_TIMING                      185
+#define EMMC_EXT_CSD_BUS_WIDTH                      183
+#define EMMC_EXT_CSD_ERASED_MEM_CONT                181
+#define EMMC_EXT_CSD_PARTITION_CONFIG               179
+#define EMMC_EXT_CSD_BOOT_CONFIG_PROT               178
+#define EMMC_EXT_CSD_BOOT_BUS_WIDTH                 177
+#define EMMC_EXT_CSD_ERASE_GROUP_DEF                175
+#define EMMC_EXT_CSD_BOOT_WP                        173
+#define EMMC_EXT_CSD_USER_WP                        171
+#define EMMC_EXT_CSD_FW_CONFIG                      169
+#define EMMC_EXT_CSD_RPMB_SIZE_MULT                 168
+#define EMMC_EXT_CSD_RST_n_FUNCTION                 162
+#define EMMC_EXT_CSD_PARTITIONING_SUPPORT           160
+#define EMMC_EXT_CSD_MAX_ENH_SIZE_MULT              159
+#define EMMC_EXT_CSD_PARTITIONS_ATTRIBUTE           156
+#define EMMC_EXT_CSD_PARTITION_SETTING_COMPLETED    155
+#define EMMC_EXT_CSD_GP_SIZE_MULT                   154
+#define EMMC_EXT_CSD_ENH_SIZE_MULT                  142
+#define EMMC_EXT_CSD_ENH_START_ADDR                 139
+#define EMMC_EXT_CSD_SEC_BAD_BLK_MGMNT              134
+
+#define EMMC_EXT_CSD_CARD_TYPE_26MHZ                0x01
+#define EMMC_EXT_CSD_CARD_TYPE_52MHZ                0x02
+#define EMMC_EXT_CSD_CARD_TYPE_DDR_52MHZ_12V        0x04
+#define EMMC_EXT_CSD_CARD_TYPE_DDR_52MHZ_18V        0x08
+#define EMMC_EXT_CSD_CARD_TYPE_52MHZ_MASK           0x0e
+
+/** SWITCH (CMD6) argument */
+#define	EXTCSD_ACCESS_BYTE	(BIT25|BIT24)
+#define	EXTCSD_SET_BITS		BIT24
+
+#define	HS_TIMING_ADD		(185<<16)	/* H'b9 */
+#define	HS_TIMING_1			(1<<8)
+#define	HS_TIMING_HS200		(2<<8)
+#define	HS_TIMING_HS400		(3<<8)
+
+#define	BUS_WIDTH_ADD		(183<<16)	/* H'b7 */
+#define	BUS_WIDTH_1			(0<<8)
+#define	BUS_WIDTH_4			(1<<8)
+#define	BUS_WIDTH_8			(2<<8)
+#define	BUS_WIDTH_4DDR		(5<<8)
+#define	BUS_WIDTH_8DDR		(6<<8)
+
+#define EMMC_SWITCH_HS_TIMING           (EXTCSD_ACCESS_BYTE|HS_TIMING_ADD|HS_TIMING_1)		/**< H'03b90100 */
+#define	EMMC_SWITCH_HS_TIMING_OFF	    (EXTCSD_ACCESS_BYTE|HS_TIMING_ADD)					/**< H'03b90000 */
+
+#define EMMC_SWITCH_BUS_WIDTH_1         (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_1)		/**< H'03b70000 */
+#define EMMC_SWITCH_BUS_WIDTH_4         (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_4)		/**< H'03b70100 */
+#define EMMC_SWITCH_BUS_WIDTH_8         (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_8)		/**< H'03b70200 */
+#define	EMMC_SWITCH_BUS_WIDTH_4DDR      (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_4DDR)	/**< H'03b70500 */
+#define	EMMC_SWITCH_BUS_WIDTH_8DDR      (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_8DDR)	/**< H'03b70600 */
+#define EMMC_SWITCH_PARTITION_CONFIG    0x03B30000UL	/**< Partition config = 0x00 */
+
+#define TIMING_HIGH_SPEED					1UL
+#define EMMC_BOOT_PARTITION_EN_MASK	0x38U
+#define EMMC_BOOT_PARTITION_EN_SHIFT	3U
+
+/** Bus width */
+#define EMMC_BUSWIDTH_1BIT              CE_CMD_SET_DATW_1BIT
+#define EMMC_BUSWIDTH_4BIT              CE_CMD_SET_DATW_4BIT
+#define EMMC_BUSWIDTH_8BIT              CE_CMD_SET_DATW_8BIT
+
+/** for st_mmc_base */
+#define EMMC_MAX_RESPONSE_LENGTH        17
+#define EMMC_MAX_CID_LENGTH             16
+#define EMMC_MAX_CSD_LENGTH             16
+#define EMMC_MAX_EXT_CSD_LENGTH         512U
+#define EMMC_RES_REG_ALIGNED            4U
+#define EMMC_BUF_REG_ALIGNED            8U
+
+/** @brief for TAAC mask
+ */
+#define TAAC_TIME_UNIT_MASK         (0x07)
+#define TAAC_MULTIPLIER_FACTOR_MASK (0x0F)
+
+/* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */
+
+/** @brief Partition id
+ */
+typedef enum {
+	PARTITION_ID_USER = 0x0,    /**< User Area */
+	PARTITION_ID_BOOT_1 = 0x1,  /**< boot partition 1 */
+	PARTITION_ID_BOOT_2 = 0x2,  /**< boot partition 2 */
+	PARTITION_ID_RPMB = 0x3,    /**< Replay Protected Memory Block */
+	PARTITION_ID_GP_1 = 0x4,    /**< General Purpose partition 1 */
+	PARTITION_ID_GP_2 = 0x5,    /**< General Purpose partition 2 */
+	PARTITION_ID_GP_3 = 0x6,    /**< General Purpose partition 3 */
+	PARTITION_ID_GP_4 = 0x7,    /**< General Purpose partition 4 */
+	PARTITION_ID_MASK = 0x7	    /**< [2:0] */
+} EMMC_PARTITION_ID;
+
+/** @brief card state in R1 response [12:9]
+ */
+typedef enum {
+	EMMC_R1_STATE_IDLE = 0,
+	EMMC_R1_STATE_READY,
+	EMMC_R1_STATE_IDENT,
+	EMMC_R1_STATE_STBY,
+	EMMC_R1_STATE_TRAN,
+	EMMC_R1_STATE_DATA,
+	EMMC_R1_STATE_RCV,
+	EMMC_R1_STATE_PRG,
+	EMMC_R1_STATE_DIS,
+	EMMC_R1_STATE_BTST,
+	EMMC_R1_STATE_SLEP
+} EMMC_R1_STATE;
+
+typedef enum {
+	ESTATE_BEGIN = 0,
+	ESTATE_ISSUE_CMD,
+	ESTATE_NON_RESP_CMD,
+	ESTATE_RCV_RESP,
+	ESTATE_RCV_RESPONSE_BUSY,
+	ESTATE_CHECK_RESPONSE_COMPLETE,
+	ESTATE_DATA_TRANSFER,
+	ESTATE_DATA_TRANSFER_COMPLETE,
+	ESTATE_ACCESS_END,
+	ESTATE_TRANSFER_ERROR,
+	ESTATE_ERROR,
+	ESTATE_END
+} EMMC_INT_STATE;
+
+/** @brief eMMC boot driver error information
+ */
+typedef struct {
+	uint16_t num;		  /**< error no */
+	uint16_t code;		  /**< error code */
+	volatile uint32_t info1;  /**< SD_INFO1 register value. (hardware dependence) */
+	volatile uint32_t info2;  /**< SD_INFO2 register value. (hardware dependence) */
+	volatile uint32_t status1;/**< SD_ERR_STS1 register value. (hardware dependence) */
+	volatile uint32_t status2;/**< SD_ERR_STS2 register value. (hardware dependence) */
+	volatile uint32_t dm_info1;/**< DM_CM_INFO1 register value. (hardware dependence) */
+	volatile uint32_t dm_info2;/**< DM_CM_INFO2 register value. (hardware dependence) */
+} st_error_info;
+
+/** @brief Command information
+ */
+typedef struct {
+	HAL_MEMCARD_COMMAND cmd;	/**< Command information */
+	uint32_t arg;			  /**< argument */
+	HAL_MEMCARD_OPERATION dir;	/**< direction */
+	uint32_t hw;			  /**< H/W dependence. SD_CMD register value. */
+} st_command_info;
+
+/** @brief MMC driver base
+ */
+typedef struct {
+	st_error_info error_info;	/**< error information */
+	st_command_info cmd_info;	/**< command information */
+
+	/* for data transfer */
+	uint32_t *buff_address_virtual;	   /**< Dest or Src buff */
+	uint32_t *buff_address_physical;   /**< Dest or Src buff */
+	HAL_MEMCARD_DATA_WIDTH bus_width;
+					/**< bus width */
+	uint32_t trans_size;		  /**< transfer size for this command */
+	uint32_t remain_size;		  /**< remain size for this command */
+	uint32_t response_length;	  /**< response length for this command */
+	uint32_t sector_size;		   /**< sector_size */
+
+	/* clock */
+	uint32_t base_clock;		  /**< MMC host controller clock */
+	uint32_t max_freq;		  /**< Max frequency (Card Spec)[Hz]. It changes dynamically by CSD and EXT_CSD. */
+	uint32_t request_freq;		  /**< request freq [Hz] (400K, 26MHz, 52MHz, etc) */
+	uint32_t current_freq;		  /**< current MMC clock[Hz] (the closest frequency supported by HW) */
+
+	/* state flag */
+	HAL_MEMCARD_PRESENCE_STATUS card_present;
+						/**< presence status of the memory card */
+	uint32_t card_power_enable;		  /**< True : Power ON */
+	uint32_t clock_enable;			  /**< True : Clock ON */
+	uint32_t initialize;			  /**< True : initialize complete. */
+	uint32_t access_mode;			  /**< True : sector access, FALSE : byte access */
+	uint32_t mount;				  /**< True : mount complete. */
+	uint32_t selected;			  /**< True : selected card. */
+	HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode;
+						    /**< 0: DMA, 1:PIO */
+	uint32_t image_num;			  /**< loaded ISSW image No. ISSW have copy image. */
+	EMMC_R1_STATE current_state;		/**< card state */
+	volatile uint32_t during_cmd_processing;  /**< True : during command processing */
+	volatile uint32_t during_transfer;	  /**< True : during transfer */
+	volatile uint32_t during_dma_transfer;	  /**< True : during transfer (DMA)*/
+	volatile uint32_t dma_error_flag;	  /**< True : occurred DMAC error */
+	volatile uint32_t force_terminate;	  /**< force terminate flag */
+	volatile uint32_t state_machine_blocking; /**< state machine blocking flag : True or False */
+	volatile uint32_t get_partition_access_flag;
+						  /**< True : get partition access processing */
+
+	EMMC_PARTITION_ID boot_partition_en;	/**< Boot partition */
+	EMMC_PARTITION_ID partition_access;	/**< Current access partition */
+
+	/* timeout */
+	uint32_t hs_timing;			/**< high speed */
+
+	/* timeout */
+	uint32_t data_timeout;			  /**< read and write data timeout.*/
+
+	/* retry */
+	uint32_t retries_after_fail;  /**< how many times to try after fail, for instance sending command */
+
+	/* interrupt */
+	volatile uint32_t int_event1; /**< interrupt SD_INFO1 Event */
+	volatile uint32_t int_event2;	  /**< interrupt SD_INFO2 Event */
+	volatile uint32_t dm_event1;  /**< interrupt DM_CM_INFO1 Event */
+	volatile uint32_t dm_event2;	  /**< interrupt DM_CM_INFO2 Event */
+
+	/* response */
+	uint32_t *response;	      /**< pointer to buffer for executing command. */
+	uint32_t r1_card_status;      /**< R1 response data */
+	uint32_t r3_ocr;	      /**< R3 response data */
+	uint32_t r4_resp;	      /**< R4 response data */
+	uint32_t r5_resp;	      /**< R5 response data */
+
+	uint32_t low_clock_mode_enable;
+				      /**< True : clock mode is low. (MMC clock = Max26MHz) */
+	uint32_t reserved2;
+	uint32_t reserved3;
+	uint32_t reserved4;
+
+	/* CSD registers (4byte align) */
+	uint8_t csd_data[EMMC_MAX_CSD_LENGTH]		      /**< CSD */
+	    __attribute__ ((aligned(EMMC_RES_REG_ALIGNED)));
+	/* CID registers (4byte align) */
+	uint8_t cid_data[EMMC_MAX_CID_LENGTH]		      /**< CID */
+	    __attribute__ ((aligned(EMMC_RES_REG_ALIGNED)));
+	/* EXT CSD registers (8byte align) */
+	uint8_t ext_csd_data[EMMC_MAX_EXT_CSD_LENGTH]	      /**< EXT_CSD */
+	    __attribute__ ((aligned(EMMC_BUF_REG_ALIGNED)));
+	/* Response registers (4byte align) */
+	uint8_t response_data[EMMC_MAX_RESPONSE_LENGTH]	      /**< other response */
+	    __attribute__ ((aligned(EMMC_RES_REG_ALIGNED)));
+} st_mmc_base;
+
+typedef int (*func) (void);
+
+/* ********************** DECLARATION OF EXTERNAL DATA ********************* */
+
+/* ************************** FUNCTION PROTOTYPES ************************** */
+uint32_t emmc_get_csd_time(void);
+
+#define MMC_DEBUG
+/* ********************************* CODE ********************************** */
+
+/* ******************************** END ************************************ */
+#endif /* EMMC_STD_H */
diff --git a/drivers/renesas/rcar/emmc/emmc_utility.c b/drivers/renesas/rcar/emmc/emmc_utility.c
new file mode 100644
index 0000000..39d9ede
--- /dev/null
+++ b/drivers/renesas/rcar/emmc/emmc_utility.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_registers.h"
+#include "emmc_def.h"
+
+static const uint32_t cmd_reg_hw[EMMC_CMD_MAX + 1] = {
+	0x00000000,		/* CMD0 */
+	0x00000701,		/* CMD1 */
+	0x00000002,		/* CMD2 */
+	0x00000003,		/* CMD3 */
+	0x00000004,		/* CMD4 */
+	0x00000505,		/* CMD5 */
+	0x00000406,		/* CMD6 */
+	0x00000007,		/* CMD7 */
+	0x00001C08,		/* CMD8 */
+	0x00000009,		/* CMD9 */
+	0x0000000A,		/* CMD10 */
+	0x00000000,		/* reserved */
+	0x0000000C,		/* CMD12 */
+	0x0000000D,		/* CMD13 */
+	0x00001C0E,		/* CMD14 */
+	0x0000000F,		/* CMD15 */
+	0x00000010,		/* CMD16 */
+	0x00000011,		/* CMD17 */
+	0x00007C12,		/* CMD18 */
+	0x00000C13,		/* CMD19 */
+	0x00000000,
+	0x00001C15,		/* CMD21 */
+	0x00000000,
+	0x00000017,		/* CMD23 */
+	0x00000018,		/* CMD24 */
+	0x00006C19,		/* CMD25 */
+	0x00000C1A,		/* CMD26 */
+	0x0000001B,		/* CMD27 */
+	0x0000001C,		/* CMD28 */
+	0x0000001D,		/* CMD29 */
+	0x0000001E,		/* CMD30 */
+	0x00001C1F,		/* CMD31 */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000423,		/* CMD35 */
+	0x00000424,		/* CMD36 */
+	0x00000000,
+	0x00000026,		/* CMD38 */
+	0x00000427,		/* CMD39 */
+	0x00000428,		/* CMD40(send cmd) */
+	0x00000000,
+	0x0000002A,		/* CMD42 */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000C31,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00007C35,
+	0x00006C36,
+	0x00000037,		/* CMD55 */
+	0x00000038,		/* CMD56(Read) */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000
+};
+
+uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom)
+{
+	uint32_t value;
+
+	uint32_t index_top = (uint32_t) (15 - (top >> 3));
+	uint32_t index_bottom = (uint32_t) (15 - (bottom >> 3));
+
+	if (index_top == index_bottom) {
+		value = data[index_top];
+	} else if ((index_top + 1) == index_bottom) {
+		value =
+		    (uint32_t) ((data[index_top] << 8) | data[index_bottom]);
+	} else if ((index_top + 2) == index_bottom) {
+		value =
+		    (uint32_t) ((data[index_top] << 16) |
+				(data[index_top + 1] << 8) | data[index_top +
+								  2]);
+	} else {
+		value =
+		    (uint32_t) ((data[index_top] << 24) |
+				(data[index_top + 1] << 16) |
+				(data[index_top + 2] << 8) | data[index_top +
+								  3]);
+	}
+
+	value = ((value >> (bottom & 0x07)) & ((1 << (top - bottom + 1)) - 1));
+
+	return value;
+}
+
+void emmc_write_error_info(uint16_t func_no, EMMC_ERROR_CODE error_code)
+{
+
+	mmc_drv_obj.error_info.num = func_no;
+	mmc_drv_obj.error_info.code = (uint16_t) error_code;
+
+	ERROR("BL2: emmc err:func_no=0x%x code=0x%x\n", func_no, error_code);
+}
+
+void emmc_write_error_info_func_no(uint16_t func_no)
+{
+
+	mmc_drv_obj.error_info.num = func_no;
+
+	ERROR("BL2: emmc err:func_no=0x%x\n", func_no);
+}
+
+void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg)
+{
+	/* command information */
+	mmc_drv_obj.cmd_info.cmd = cmd;
+	mmc_drv_obj.cmd_info.arg = arg;
+	mmc_drv_obj.cmd_info.dir = HAL_MEMCARD_READ;
+	mmc_drv_obj.cmd_info.hw =
+	    cmd_reg_hw[cmd & HAL_MEMCARD_COMMAND_INDEX_MASK];
+
+	/* clear data transfer information */
+	mmc_drv_obj.trans_size = 0;
+	mmc_drv_obj.remain_size = 0;
+	mmc_drv_obj.buff_address_virtual = NULL;
+	mmc_drv_obj.buff_address_physical = NULL;
+
+	/* response information */
+	mmc_drv_obj.response_length = 6;
+
+	switch (mmc_drv_obj.cmd_info.cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK) {
+	case HAL_MEMCARD_RESPONSE_NONE:
+		mmc_drv_obj.response = (uint32_t *) mmc_drv_obj.response_data;
+		mmc_drv_obj.response_length = 0;
+		break;
+	case HAL_MEMCARD_RESPONSE_R1:
+		mmc_drv_obj.response = &mmc_drv_obj.r1_card_status;
+		break;
+	case HAL_MEMCARD_RESPONSE_R1b:
+		mmc_drv_obj.cmd_info.hw |= BIT10;	/* bit10 = R1 busy bit */
+		mmc_drv_obj.response = &mmc_drv_obj.r1_card_status;
+		break;
+	case HAL_MEMCARD_RESPONSE_R2:
+		mmc_drv_obj.response = (uint32_t *) mmc_drv_obj.response_data;
+		mmc_drv_obj.response_length = 17;
+		break;
+	case HAL_MEMCARD_RESPONSE_R3:
+		mmc_drv_obj.response = &mmc_drv_obj.r3_ocr;
+		break;
+	case HAL_MEMCARD_RESPONSE_R4:
+		mmc_drv_obj.response = &mmc_drv_obj.r4_resp;
+		break;
+	case HAL_MEMCARD_RESPONSE_R5:
+		mmc_drv_obj.response = &mmc_drv_obj.r5_resp;
+		break;
+	default:
+		mmc_drv_obj.response = (uint32_t *) mmc_drv_obj.response_data;
+		break;
+	}
+}
+
+void emmc_make_trans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg,
+			 uint32_t *buff_address_virtual,
+			 uint32_t len,
+			 HAL_MEMCARD_OPERATION dir,
+			 HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode)
+{
+	emmc_make_nontrans_cmd(cmd, arg);	/* update common information */
+
+	/* for data transfer command */
+	mmc_drv_obj.cmd_info.dir = dir;
+	mmc_drv_obj.buff_address_virtual = buff_address_virtual;
+	mmc_drv_obj.buff_address_physical = buff_address_virtual;
+	mmc_drv_obj.trans_size = len;
+	mmc_drv_obj.remain_size = len;
+	mmc_drv_obj.transfer_mode = transfer_mode;
+}
+
+EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg)
+{
+	EMMC_ERROR_CODE result;
+	uint32_t freq;
+
+	/* initialize state */
+	mmc_drv_obj.mount = FALSE;
+	mmc_drv_obj.selected = FALSE;
+	mmc_drv_obj.during_transfer = FALSE;
+	mmc_drv_obj.during_cmd_processing = FALSE;
+	mmc_drv_obj.during_dma_transfer = FALSE;
+	mmc_drv_obj.dma_error_flag = FALSE;
+	mmc_drv_obj.force_terminate = FALSE;
+	mmc_drv_obj.state_machine_blocking = FALSE;
+
+	mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT;
+	mmc_drv_obj.max_freq = MMC_20MHZ;	/* 20MHz */
+	mmc_drv_obj.current_state = EMMC_R1_STATE_IDLE;
+
+	/* CMD0 (MMC clock is current frequency. if Data transfer mode, 20MHz or higher.) */
+	emmc_make_nontrans_cmd(CMD0_GO_IDLE_STATE, arg);	/* CMD0 */
+	result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+
+	/* change MMC clock(400KHz) */
+	freq = MMC_400KHZ;
+	result = emmc_set_request_mmc_clock(&freq);
+	if (result != EMMC_SUCCESS) {
+		return result;
+	}
+
+	return EMMC_SUCCESS;
+}
diff --git a/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c
new file mode 100644
index 0000000..39b9bb4
--- /dev/null
+++ b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+#include "cpg_registers.h"
+#include "iic_dvfs.h"
+#include "rcar_private.h"
+
+#define DVFS_RETRY_MAX				(2U)
+
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_0		(0x07)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_1		(0x09)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_2		(0x0B)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_3		(0x0E)
+#define IIC_DVFS_SET_ICCL_EXTAL_TYPE_E		(0x15)
+
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_0		(0x01)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_1		(0x02)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_2		(0x03)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_3		(0x05)
+#define IIC_DVFS_SET_ICCH_EXTAL_TYPE_E		(0x07)
+
+#define CPG_BIT_SMSTPCR9_DVFS			(0x04000000)
+
+#define IIC_DVFS_REG_BASE			(0xE60B0000)
+#define IIC_DVFS_REG_ICDR			(IIC_DVFS_REG_BASE + 0x0000)
+#define IIC_DVFS_REG_ICCR			(IIC_DVFS_REG_BASE + 0x0004)
+#define IIC_DVFS_REG_ICSR			(IIC_DVFS_REG_BASE + 0x0008)
+#define IIC_DVFS_REG_ICIC			(IIC_DVFS_REG_BASE + 0x000C)
+#define IIC_DVFS_REG_ICCL			(IIC_DVFS_REG_BASE + 0x0010)
+#define IIC_DVFS_REG_ICCH			(IIC_DVFS_REG_BASE + 0x0014)
+
+#define IIC_DVFS_BIT_ICSR_BUSY			(0x10)
+#define IIC_DVFS_BIT_ICSR_AL			(0x08)
+#define IIC_DVFS_BIT_ICSR_TACK			(0x04)
+#define IIC_DVFS_BIT_ICSR_WAIT			(0x02)
+#define IIC_DVFS_BIT_ICSR_DTE			(0x01)
+
+#define IIC_DVFS_BIT_ICCR_ENABLE		(0x80)
+#define IIC_DVFS_SET_ICCR_START			(0x94)
+#define IIC_DVFS_SET_ICCR_STOP			(0x90)
+#define	IIC_DVFS_SET_ICCR_RETRANSMISSION	(0x94)
+#define	IIC_DVFS_SET_ICCR_CHANGE		(0x81)
+#define	IIC_DVFS_SET_ICCR_STOP_READ		(0xC0)
+
+#define IIC_DVFS_BIT_ICIC_TACKE			(0x04)
+#define IIC_DVFS_BIT_ICIC_WAITE			(0x02)
+#define IIC_DVFS_BIT_ICIC_DTEE			(0x01)
+
+#define	DVFS_READ_MODE				(0x01)
+#define	DVFS_WRITE_MODE				(0x00)
+
+#define IIC_DVFS_SET_DUMMY			(0x52)
+#define IIC_DVFS_SET_BUSY_LOOP			(500000000U)
+
+typedef enum {
+	DVFS_START = 0,
+	DVFS_STOP,
+	DVFS_RETRANSMIT,
+	DVFS_READ,
+	DVFS_STOP_READ,
+	DVFS_SET_SLAVE_READ,
+	DVFS_SET_SLAVE,
+	DVFS_WRITE_ADDR,
+	DVFS_WRITE_DATA,
+	DVFS_CHANGE_SEND_TO_RECIEVE,
+	DVFS_DONE,
+} DVFS_STATE_T;
+
+#define DVFS_PROCESS			(1)
+#define DVFS_COMPLETE			(0)
+#define DVFS_ERROR			(-1)
+
+#if IMAGE_BL31
+#define IIC_DVFS_FUNC(__name, ...)					\
+static int32_t 	__attribute__ ((section (".system_ram")))		\
+dvfs_ ##__name(__VA_ARGS__)
+
+#define RCAR_DVFS_API(__name, ...)					\
+int32_t __attribute__ ((section (".system_ram"))) 			\
+rcar_iic_dvfs_ ##__name(__VA_ARGS__)
+
+#else
+#define IIC_DVFS_FUNC(__name, ...) 					\
+static int32_t dvfs_ ##__name(__VA_ARGS__)
+
+#define RCAR_DVFS_API(__name, ...)					\
+int32_t rcar_iic_dvfs_ ##__name(__VA_ARGS__)
+#endif
+
+IIC_DVFS_FUNC(check_error, DVFS_STATE_T *state, uint32_t *err, uint8_t mode)
+{
+	uint8_t icsr_al = 0, icsr_tack = 0;
+	uint8_t reg, stop;
+	uint32_t i = 0;
+
+	stop = mode == DVFS_READ_MODE ? IIC_DVFS_SET_ICCR_STOP_READ :
+	    IIC_DVFS_SET_ICCR_STOP;
+
+	reg = mmio_read_8(IIC_DVFS_REG_ICSR);
+	icsr_al = (reg & IIC_DVFS_BIT_ICSR_AL) == IIC_DVFS_BIT_ICSR_AL;
+	icsr_tack = (reg & IIC_DVFS_BIT_ICSR_TACK) == IIC_DVFS_BIT_ICSR_TACK;
+
+	if (icsr_al == 0 && icsr_tack == 0)
+		return DVFS_PROCESS;
+
+	if (icsr_al) {
+		reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_AL;
+		mmio_write_8(IIC_DVFS_REG_ICSR, reg);
+
+		if (*state == DVFS_SET_SLAVE)
+			mmio_write_8(IIC_DVFS_REG_ICDR, IIC_DVFS_SET_DUMMY);
+
+		do {
+			reg = mmio_read_8(IIC_DVFS_REG_ICSR) &
+			    IIC_DVFS_BIT_ICSR_WAIT;
+		} while (reg == 0);
+
+		mmio_write_8(IIC_DVFS_REG_ICCR, stop);
+
+		reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+		mmio_write_8(IIC_DVFS_REG_ICSR, reg);
+
+		i = 0;
+		do {
+			reg = mmio_read_8(IIC_DVFS_REG_ICSR) &
+			    IIC_DVFS_BIT_ICSR_BUSY;
+			if (reg == 0)
+				break;
+
+			if (i++ > IIC_DVFS_SET_BUSY_LOOP)
+				panic();
+
+		} while (1);
+
+		mmio_write_8(IIC_DVFS_REG_ICCR, 0x00U);
+
+		(*err)++;
+		if (*err > DVFS_RETRY_MAX)
+			return DVFS_ERROR;
+
+		*state = DVFS_START;
+
+		return DVFS_PROCESS;
+
+	}
+
+	/* icsr_tack */
+	mmio_write_8(IIC_DVFS_REG_ICCR, stop);
+
+	reg = mmio_read_8(IIC_DVFS_REG_ICIC);
+	reg &= ~(IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE);
+	mmio_write_8(IIC_DVFS_REG_ICIC, reg);
+
+	reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_TACK;
+	mmio_write_8(IIC_DVFS_REG_ICSR, reg);
+
+	i = 0;
+	while ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0) {
+		if (i++ > IIC_DVFS_SET_BUSY_LOOP)
+			panic();
+	}
+
+	mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+	(*err)++;
+
+	if (*err > DVFS_RETRY_MAX)
+		return DVFS_ERROR;
+
+	*state = DVFS_START;
+
+	return DVFS_PROCESS;
+}
+
+IIC_DVFS_FUNC(start, DVFS_STATE_T * state)
+{
+	uint8_t iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_E;
+	uint8_t icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_E;
+	int32_t result = DVFS_PROCESS;
+	uint32_t reg, lsi_product;
+	uint8_t mode;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICCR) | IIC_DVFS_BIT_ICCR_ENABLE;
+	mmio_write_8(IIC_DVFS_REG_ICCR, mode);
+
+	lsi_product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
+	if (lsi_product == RCAR_PRODUCT_E3)
+		goto start;
+
+	reg = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14;
+	switch (reg) {
+	case MD14_MD13_TYPE_0:
+		iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_0;
+		icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_0;
+		break;
+	case MD14_MD13_TYPE_1:
+		iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_1;
+		icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_1;
+		break;
+	case MD14_MD13_TYPE_2:
+		iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_2;
+		icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_2;
+		break;
+	default:
+		iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_3;
+		icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_3;
+		break;
+	}
+start:
+	mmio_write_8(IIC_DVFS_REG_ICCL, iccl);
+	mmio_write_8(IIC_DVFS_REG_ICCH, icch);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICIC)
+	    | IIC_DVFS_BIT_ICIC_TACKE
+	    | IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE;
+
+	mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+	mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_START);
+
+	*state = DVFS_SET_SLAVE;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(set_slave, DVFS_STATE_T * state, uint32_t *err, uint8_t slave)
+{
+	uint8_t mode;
+	int32_t result;
+	uint8_t address;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
+	if (mode != IIC_DVFS_BIT_ICSR_DTE)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
+	mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+	address = slave << 1;
+	mmio_write_8(IIC_DVFS_REG_ICDR, address);
+
+	*state = DVFS_WRITE_ADDR;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(write_addr, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_addr)
+{
+	uint8_t mode;
+	int32_t result;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	*state = DVFS_WRITE_DATA;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(write_data, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_data)
+{
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICDR, reg_data);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	*state = DVFS_STOP;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(stop, DVFS_STATE_T *state, uint32_t *err)
+{
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	*state = DVFS_DONE;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(done, void)
+{
+	uint32_t i;
+
+	for (i = 0; i < IIC_DVFS_SET_BUSY_LOOP; i++) {
+		if (mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY)
+			continue;
+		goto done;
+	}
+
+	panic();
+done:
+	mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+
+	return DVFS_COMPLETE;
+}
+
+IIC_DVFS_FUNC(write_reg_addr_read, DVFS_STATE_T *state, uint32_t *err,
+	uint8_t reg_addr)
+{
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	*state = DVFS_RETRANSMIT;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(retransmit, DVFS_STATE_T *state, uint32_t *err)
+{
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_RETRANSMISSION);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE;
+	mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+	*state = DVFS_SET_SLAVE_READ;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(set_slave_read, DVFS_STATE_T *state, uint32_t *err,
+		uint8_t slave)
+{
+	uint8_t address;
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
+	if (mode != IIC_DVFS_BIT_ICSR_DTE)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
+	mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+	address = ((uint8_t) (slave << 1) + DVFS_READ_MODE);
+	mmio_write_8(IIC_DVFS_REG_ICDR, address);
+
+	*state = DVFS_CHANGE_SEND_TO_RECIEVE;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(change_send_to_recieve, DVFS_STATE_T *state, uint32_t *err)
+{
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_WRITE_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_CHANGE);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	*state = DVFS_STOP_READ;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(stop_read, DVFS_STATE_T *state, uint32_t *err)
+{
+	int32_t result;
+	uint8_t mode;
+
+	result = dvfs_check_error(state, err, DVFS_READ_MODE);
+	if (result == DVFS_ERROR)
+		return result;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT;
+	if (mode != IIC_DVFS_BIT_ICSR_WAIT)
+		return result;
+
+	mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP_READ);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT;
+	mmio_write_8(IIC_DVFS_REG_ICSR, mode);
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE;
+	mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+	*state = DVFS_READ;
+
+	return result;
+}
+
+IIC_DVFS_FUNC(read, DVFS_STATE_T *state, uint8_t *reg_data)
+{
+	uint8_t mode;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE;
+	if (mode != IIC_DVFS_BIT_ICSR_DTE)
+		return DVFS_PROCESS;
+
+	mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE;
+	mmio_write_8(IIC_DVFS_REG_ICIC, mode);
+
+	*reg_data = mmio_read_8(IIC_DVFS_REG_ICDR);
+	*state = DVFS_DONE;
+
+	return DVFS_PROCESS;
+}
+
+RCAR_DVFS_API(send, uint8_t slave, uint8_t reg_addr, uint8_t reg_data)
+{
+	DVFS_STATE_T state = DVFS_START;
+	int32_t result = DVFS_PROCESS;
+	uint32_t err = 0;
+
+	mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
+	mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+again:
+	switch (state) {
+	case DVFS_START:
+		result = dvfs_start(&state);
+		break;
+	case DVFS_SET_SLAVE:
+		result = dvfs_set_slave(&state, &err, slave);
+		break;
+	case DVFS_WRITE_ADDR:
+		result = dvfs_write_addr(&state, &err, reg_addr);
+		break;
+	case DVFS_WRITE_DATA:
+		result = dvfs_write_data(&state, &err, reg_data);
+		break;
+	case DVFS_STOP:
+		result = dvfs_stop(&state, &err);
+		break;
+	case DVFS_DONE:
+		result = dvfs_done();
+		break;
+	default:
+		panic();
+		break;
+	}
+
+	if (result == DVFS_PROCESS)
+		goto again;
+
+	return result;
+}
+
+RCAR_DVFS_API(receive, uint8_t slave, uint8_t reg, uint8_t *data)
+{
+	DVFS_STATE_T state = DVFS_START;
+	int32_t result = DVFS_PROCESS;
+	uint32_t err = 0;
+
+	mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS);
+	mmio_write_8(IIC_DVFS_REG_ICCR, 0);
+again:
+	switch (state) {
+	case DVFS_START:
+		result = dvfs_start(&state);
+		break;
+	case DVFS_SET_SLAVE:
+		result = dvfs_set_slave(&state, &err, slave);
+		break;
+	case DVFS_WRITE_ADDR:
+		result = dvfs_write_reg_addr_read(&state, &err, reg);
+		break;
+	case DVFS_RETRANSMIT:
+		result = dvfs_retransmit(&state, &err);
+		break;
+	case DVFS_SET_SLAVE_READ:
+		result = dvfs_set_slave_read(&state, &err, slave);
+		break;
+	case DVFS_CHANGE_SEND_TO_RECIEVE:
+		result = dvfs_change_send_to_recieve(&state, &err);
+		break;
+	case DVFS_STOP_READ:
+		result = dvfs_stop_read(&state, &err);
+		break;
+	case DVFS_READ:
+		result = dvfs_read(&state, data);
+		break;
+	case DVFS_DONE:
+		result = dvfs_done();
+		break;
+	default:
+		panic();
+		break;
+	}
+
+	if (result == DVFS_PROCESS)
+		goto again;
+
+	return result;
+}
diff --git a/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h
new file mode 100644
index 0000000..2dec58f
--- /dev/null
+++ b/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IIC_DVFS_H
+#define IIC_DVFS_H
+
+/* PMIC slave */
+#define PMIC			(0x30)
+#define	BKUP_MODE_CNT		(0x20)
+#define	DVFS_SET_VID		(0x54)
+#define	REG_KEEP10		(0x79)
+
+/* EEPROM slave */
+#define EEPROM			(0x50)
+#define	BOARD_ID		(0x70)
+
+int32_t rcar_iic_dvfs_receive(uint8_t slave, uint8_t reg, uint8_t *data);
+int32_t rcar_iic_dvfs_send(uint8_t slave, uint8_t regr, uint8_t data);
+
+#endif /* IIC_DVFS_H */
diff --git a/drivers/renesas/rcar/io/io_common.h b/drivers/renesas/rcar/io/io_common.h
new file mode 100644
index 0000000..6eb7777
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_common.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_COMMON_H
+#define IO_COMMON_H
+
+typedef struct io_drv_spec {
+	size_t offset;
+	size_t length;
+	uint32_t partition;
+} io_drv_spec_t;
+
+#endif /* IO_COMMON_H */
diff --git a/drivers/renesas/rcar/io/io_emmcdrv.c b/drivers/renesas/rcar/io/io_emmcdrv.c
new file mode 100644
index 0000000..4b464fb
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_emmcdrv.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+#include "io_common.h"
+#include "io_emmcdrv.h"
+#include "io_private.h"
+#include "emmc_config.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+#include "emmc_def.h"
+
+static int32_t emmcdrv_dev_open(const uintptr_t spec __attribute__ ((unused)),
+				io_dev_info_t **dev_info);
+static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info);
+
+typedef struct {
+	uint32_t in_use;
+	uintptr_t base;
+	ssize_t file_pos;
+	EMMC_PARTITION_ID partition;
+} file_state_t;
+
+static file_state_t current_file = { 0 };
+
+static EMMC_PARTITION_ID emmcdrv_bootpartition = PARTITION_ID_USER;
+
+static io_type_t device_type_emmcdrv(void)
+{
+	return IO_TYPE_MEMMAP;
+}
+
+static int32_t emmcdrv_block_seek(io_entity_t *entity, int32_t mode,
+				  ssize_t offset)
+{
+	if (mode != IO_SEEK_SET)
+		return IO_FAIL;
+
+	((file_state_t *) entity->info)->file_pos = offset;
+
+	return IO_SUCCESS;
+}
+
+static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer,
+				  size_t length, size_t *length_read)
+{
+	file_state_t *fp = (file_state_t *) entity->info;
+	uint32_t sector_add, sector_num, emmc_dma = 0;
+	int32_t result = IO_SUCCESS;
+
+	sector_add = current_file.file_pos >> EMMC_SECTOR_SIZE_SHIFT;
+	sector_num = (length + EMMC_SECTOR_SIZE - 1U) >> EMMC_SECTOR_SIZE_SHIFT;
+
+	NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%lx(%d) len=0x%lx(%d)\n",
+	       buffer,
+	       current_file.partition, current_file.file_pos,
+	       sector_add, length, sector_num);
+
+	if (buffer + length - 1 <= UINT32_MAX)
+		emmc_dma = LOADIMAGE_FLAGS_DMA_ENABLE;
+
+	if (emmc_read_sector((uint32_t *) buffer, sector_add, sector_num,
+			     emmc_dma) != EMMC_SUCCESS)
+		result = IO_FAIL;
+
+	*length_read = length;
+	fp->file_pos += length;
+
+	return result;
+}
+
+static int32_t emmcdrv_block_open(io_dev_info_t *dev_info,
+				  const uintptr_t spec, io_entity_t *entity)
+{
+	const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
+
+	if (current_file.in_use) {
+		WARN("mmc_block: Only one open spec at a time\n");
+		return IO_RESOURCES_EXHAUSTED;
+	}
+
+	current_file.file_pos = 0;
+	current_file.in_use = 1;
+
+	if (emmcdrv_bootpartition == PARTITION_ID_USER) {
+		emmcdrv_bootpartition = mmc_drv_obj.boot_partition_en;
+		if ((PARTITION_ID_BOOT_1 == emmcdrv_bootpartition) ||
+		    (PARTITION_ID_BOOT_2 == emmcdrv_bootpartition)) {
+			current_file.partition = emmcdrv_bootpartition;
+
+			NOTICE("BL2: eMMC boot from partition %d\n",
+			       emmcdrv_bootpartition);
+			goto done;
+		}
+		return IO_FAIL;
+	}
+
+	if (PARTITION_ID_USER == block_spec->partition ||
+	    PARTITION_ID_BOOT_1 == block_spec->partition ||
+	    PARTITION_ID_BOOT_2 == block_spec->partition)
+		current_file.partition = block_spec->partition;
+	else
+		current_file.partition = emmcdrv_bootpartition;
+
+done:
+	if (emmc_select_partition(current_file.partition) != EMMC_SUCCESS)
+		return IO_FAIL;
+
+	entity->info = (uintptr_t) &current_file;
+
+	return IO_SUCCESS;
+}
+
+static int32_t emmcdrv_block_close(io_entity_t *entity)
+{
+	memset((void *)&current_file, 0, sizeof(current_file));
+	entity->info = 0U;
+
+	return IO_SUCCESS;
+}
+
+static const io_dev_funcs_t emmcdrv_dev_funcs = {
+	.type = &device_type_emmcdrv,
+	.open = &emmcdrv_block_open,
+	.seek = &emmcdrv_block_seek,
+	.size = NULL,
+	.read = &emmcdrv_block_read,
+	.write = NULL,
+	.close = &emmcdrv_block_close,
+	.dev_init = NULL,
+	.dev_close = &emmcdrv_dev_close
+};
+
+static const io_dev_info_t emmcdrv_dev_info = {
+	.funcs = &emmcdrv_dev_funcs,
+	.info = (uintptr_t) 0
+};
+
+static const io_dev_connector_t emmcdrv_dev_connector = {
+	&emmcdrv_dev_open,
+};
+
+static int32_t emmcdrv_dev_open(const uintptr_t spec __attribute__ ((unused)),
+				io_dev_info_t **dev_info)
+{
+	*dev_info = (io_dev_info_t *) &emmcdrv_dev_info;
+
+	return IO_SUCCESS;
+}
+
+static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info)
+{
+	return IO_SUCCESS;
+}
+
+int32_t rcar_register_io_dev_emmcdrv(const io_dev_connector_t **dev_con)
+{
+	int32_t rc;
+
+	rc = io_register_device(&emmcdrv_dev_info);
+	if (rc == IO_SUCCESS)
+		*dev_con = &emmcdrv_dev_connector;
+
+	return rc;
+}
diff --git a/drivers/renesas/rcar/io/io_emmcdrv.h b/drivers/renesas/rcar/io/io_emmcdrv.h
new file mode 100644
index 0000000..95070f2
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_emmcdrv.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_EMMCDRV_H
+#define IO_EMMCDRV_H
+
+struct io_dev_connector;
+int32_t rcar_register_io_dev_emmcdrv(const io_dev_connector_t **connector);
+
+#endif /* IO_EMMCDRV_H */
diff --git a/drivers/renesas/rcar/io/io_memdrv.c b/drivers/renesas/rcar/io/io_memdrv.c
new file mode 100644
index 0000000..3f6b4c7
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_memdrv.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+
+#include "io_common.h"
+#include "io_private.h"
+#include "io_memdrv.h"
+#include "rcar_def.h"
+
+extern void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len);
+
+static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)),
+			       io_dev_info_t **dev_info);
+static int32_t memdrv_dev_close(io_dev_info_t *dev_info);
+
+/* As we need to be able to keep state for seek, only one file can be open
+ * at a time. Make this a structure and point to the entity->info. When we
+ * can malloc memory we can change this to support more open files.
+ */
+typedef struct {
+	uint32_t in_use;
+	uintptr_t base;
+	ssize_t file_pos;
+} file_state_t;
+
+static file_state_t current_file = { 0 };
+
+static io_type_t device_type_memdrv(void)
+{
+	return IO_TYPE_MEMMAP;
+}
+
+static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+				 io_entity_t *entity)
+{
+	const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
+
+	/* Since we need to track open state for seek() we only allow one open
+	 * spec at a time. When we have dynamic memory we can malloc and set
+	 * entity->info.
+	 */
+	if (current_file.in_use)
+		return IO_RESOURCES_EXHAUSTED;
+
+	/* File cursor offset for seek and incremental reads etc. */
+	current_file.base = block_spec->offset;
+	current_file.file_pos = 0;
+	current_file.in_use = 1;
+
+	entity->info = (uintptr_t) &current_file;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode,
+				 ssize_t offset)
+{
+	if (mode != IO_SEEK_SET)
+		return IO_FAIL;
+
+	((file_state_t *) entity->info)->file_pos = offset;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_read(io_entity_t *entity, uintptr_t buffer,
+				 size_t length, size_t *cnt)
+{
+	file_state_t *fp;
+
+	fp = (file_state_t *) entity->info;
+
+	NOTICE("BL2: dst=0x%lx src=0x%lx len=%ld(0x%lx)\n",
+	       buffer, fp->base + fp->file_pos, length, length);
+
+	if (FLASH_MEMORY_SIZE < fp->file_pos + length) {
+		ERROR("BL2: check load image (source address)\n");
+		return IO_FAIL;
+	}
+
+	rcar_dma_exec(buffer, fp->base + fp->file_pos, length);
+	fp->file_pos += length;
+	*cnt = length;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_close(io_entity_t *entity)
+{
+	entity->info = 0U;
+
+	memset((void *)&current_file, 0, sizeof(current_file));
+
+	return IO_SUCCESS;
+}
+
+static const io_dev_funcs_t memdrv_dev_funcs = {
+	.type = &device_type_memdrv,
+	.open = &memdrv_block_open,
+	.seek = &memdrv_block_seek,
+	.size = NULL,
+	.read = &memdrv_block_read,
+	.write = NULL,
+	.close = &memdrv_block_close,
+	.dev_init = NULL,
+	.dev_close = &memdrv_dev_close,
+};
+
+static const io_dev_info_t memdrv_dev_info = {
+	.funcs = &memdrv_dev_funcs,
+	.info = 0,
+};
+
+static const io_dev_connector_t memdrv_dev_connector = {
+	.dev_open = &memdrv_dev_open
+};
+
+static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)),
+			       io_dev_info_t **dev_info)
+{
+	*dev_info = (io_dev_info_t *) &memdrv_dev_info;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_dev_close(io_dev_info_t *dev_info)
+{
+	return IO_SUCCESS;
+}
+
+int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **dev_con)
+{
+	int32_t result;
+
+	result = io_register_device(&memdrv_dev_info);
+	if (result == IO_SUCCESS)
+		*dev_con = &memdrv_dev_connector;
+
+	return result;
+}
diff --git a/drivers/renesas/rcar/io/io_memdrv.h b/drivers/renesas/rcar/io/io_memdrv.h
new file mode 100644
index 0000000..90e6812
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_memdrv.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MEMDRV_H
+#define IO_MEMDRV_H
+
+struct io_dev_connector;
+int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **connector);
+
+#endif /* IO_MEMDRV_H */
diff --git a/drivers/renesas/rcar/io/io_private.h b/drivers/renesas/rcar/io/io_private.h
new file mode 100644
index 0000000..207523a
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_private.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_PRIVATE_H
+#define IO_PRIVATE_H
+
+/*
+ * Return codes reported by 'io_*' APIs
+ * The value of fail should not overlap with define of the errno.
+ * The errno is in "include/lib/stdlib/sys/errno.h".
+ */
+#define IO_SUCCESS		(0)
+#define IO_FAIL			(-0x81)
+#define IO_NOT_SUPPORTED	(-0x82)
+#define IO_RESOURCES_EXHAUSTED	(-0x83)
+
+#endif /* IO_PRIVATE_H */
diff --git a/drivers/renesas/rcar/io/io_rcar.c b/drivers/renesas/rcar/io/io_rcar.c
new file mode 100644
index 0000000..650931b
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_rcar.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/auth_mod.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+#include <tools_share/uuid.h>
+
+#include "io_rcar.h"
+#include "io_common.h"
+#include "io_private.h"
+
+extern int32_t plat_get_drv_source(uint32_t id, uintptr_t *dev,
+				   uintptr_t *image_spec);
+
+extern int auth_mod_verify_img(unsigned int img_id, void *ptr,
+				unsigned int len);
+
+static int32_t rcar_dev_open(const uintptr_t dev_spec __attribute__ ((unused)),
+			     io_dev_info_t **dev_info);
+static int32_t rcar_dev_close(io_dev_info_t *dev_info);
+
+typedef struct {
+	const int32_t name;
+	const uint32_t offset;
+	const uint32_t attr;
+} plat_rcar_name_offset_t;
+
+typedef struct {
+	/* Put position above the struct to allow {0} on static init.
+	 * It is a workaround for a known bug in GCC
+	 * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
+	 */
+	uint32_t position;
+	uint32_t no_load;
+	uintptr_t offset;
+	uint32_t size;
+	uintptr_t dst;
+	uintptr_t partition;	/* for eMMC */
+	/* RCAR_EMMC_PARTITION_BOOT_0 */
+	/* RCAR_EMMC_PARTITION_BOOT_1 */
+	/* RCAR_EMMC_PARTITION_USER   */
+} file_state_t;
+
+#define RCAR_GET_FLASH_ADR(a, b)	((uint32_t)((0x40000U * (a)) + (b)))
+#define RCAR_ATTR_SET_CALCADDR(a)	((a) & 0xF)
+#define RCAR_ATTR_SET_ISNOLOAD(a)	(((a) & 0x1) << 16U)
+#define RCAR_ATTR_SET_CERTOFF(a)	(((a) & 0xF) << 8U)
+#define RCAR_ATTR_SET_ALL(a, b, c)	((uint32_t)(RCAR_ATTR_SET_CALCADDR(a) |\
+					RCAR_ATTR_SET_ISNOLOAD(b) | 	\
+					RCAR_ATTR_SET_CERTOFF(c)))
+
+#define RCAR_ATTR_GET_CALCADDR(a)	((a) & 0xFU)
+#define RCAR_ATTR_GET_ISNOLOAD(a)	(((a) >> 16) & 0x1U)
+#define RCAR_ATTR_GET_CERTOFF(a)	((uint32_t)(((a) >> 8) & 0xFU))
+
+#define RCAR_MAX_BL3X_IMAGE		(8U)
+#define RCAR_SECTOR6_CERT_OFFSET	(0x400U)
+#define RCAR_SDRAM_certESS		(0x43F00000U)
+#define RCAR_CERT_SIZE			(0x800U)
+#define RCAR_CERT_INFO_SIZE_OFFSET	(0x264U)
+#define RCAR_CERT_INFO_DST_OFFSET	(0x154U)
+#define RCAR_CERT_INFO_SIZE_OFFSET1	(0x364U)
+#define RCAR_CERT_INFO_DST_OFFSET1	(0x1D4U)
+#define RCAR_CERT_INFO_SIZE_OFFSET2	(0x464U)
+#define RCAR_CERT_INFO_DST_OFFSET2	(0x254U)
+#define RCAR_CERT_LOAD			(1U)
+
+#define RCAR_FLASH_CERT_HEADER		RCAR_GET_FLASH_ADR(6U, 0U)
+#define RCAR_EMMC_CERT_HEADER		(0x00030000U)
+
+#define RCAR_COUNT_LOAD_BL33		(2U)
+#define RCAR_COUNT_LOAD_BL33X		(3U)
+
+static const plat_rcar_name_offset_t name_offset[] = {
+	{BL31_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(0, 0, 0)},
+
+	/* BL3-2 is optional in the platform */
+	{BL32_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(1, 0, 1)},
+	{BL33_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(2, 0, 2)},
+	{BL332_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(3, 0, 3)},
+	{BL333_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(4, 0, 4)},
+	{BL334_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(5, 0, 5)},
+	{BL335_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(6, 0, 6)},
+	{BL336_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(7, 0, 7)},
+	{BL337_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(8, 0, 8)},
+	{BL338_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(9, 0, 9)},
+};
+
+#if TRUSTED_BOARD_BOOT
+static const plat_rcar_name_offset_t cert_offset[] = {
+	/* Certificates */
+	{TRUSTED_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
+	{SOC_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
+	{TRUSTED_OS_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
+	{NON_TRUSTED_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
+	{SOC_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)},
+	{TRUSTED_OS_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 1)},
+	{NON_TRUSTED_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 2)},
+	{BL332_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 3)},
+	{BL333_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 4)},
+	{BL334_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 5)},
+	{BL335_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 6)},
+	{BL336_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 7)},
+	{BL337_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 8)},
+	{BL338_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 9)},
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static file_state_t current_file = { 0 };
+
+static uintptr_t rcar_handle, rcar_spec;
+static uint64_t rcar_image_header[RCAR_MAX_BL3X_IMAGE + 2U] = { 0U };
+static uint64_t rcar_image_header_prttn[RCAR_MAX_BL3X_IMAGE + 2U] = { 0U };
+static uint64_t rcar_image_number = { 0U };
+static uint32_t rcar_cert_load = { 0U };
+
+static io_type_t device_type_rcar(void)
+{
+	return IO_TYPE_FIRMWARE_IMAGE_PACKAGE;
+}
+
+int32_t rcar_get_certificate(const int32_t name, uint32_t *cert)
+{
+#if TRUSTED_BOARD_BOOT
+	int32_t i;
+	for (i = 0; i < ARRAY_SIZE(cert_offset); i++) {
+		if (name != cert_offset[i].name)
+			continue;
+
+		*cert = RCAR_CERT_SIZE;
+		*cert *= RCAR_ATTR_GET_CERTOFF(cert_offset[i].attr);
+		*cert += RCAR_SDRAM_certESS;
+		return 0;
+	}
+#endif
+	return -EINVAL;
+}
+
+static int32_t file_to_offset(const int32_t name, uintptr_t *offset,
+			      uint32_t *cert, uint32_t *no_load,
+			      uintptr_t *partition)
+{
+	uint32_t addr;
+	int32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(name_offset); i++) {
+		if (name != name_offset[i].name)
+			continue;
+
+		addr = RCAR_ATTR_GET_CALCADDR(name_offset[i].attr);
+		if (rcar_image_number + 2 < addr)
+			continue;
+
+		*offset = rcar_image_header[addr];
+		*cert = RCAR_CERT_SIZE;
+		*cert *= RCAR_ATTR_GET_CERTOFF(name_offset[i].attr);
+		*cert += RCAR_SDRAM_certESS;
+		*no_load = RCAR_ATTR_GET_ISNOLOAD(name_offset[i].attr);
+		*partition = rcar_image_header_prttn[addr];
+		return IO_SUCCESS;
+	}
+
+#if TRUSTED_BOARD_BOOT
+	for (i = 0; i < ARRAY_SIZE(cert_offset); i++) {
+		if (name != cert_offset[i].name)
+			continue;
+
+		*no_load = RCAR_ATTR_GET_ISNOLOAD(cert_offset[i].attr);
+		*partition = 0U;
+		*offset = 0U;
+		*cert = 0U;
+		return IO_SUCCESS;
+	}
+#endif
+	return -EINVAL;
+}
+
+#define RCAR_BOOT_KEY_CERT_NEW	(0xE6300F00U)
+#define	RCAR_CERT_MAGIC_NUM	(0xE291F358U)
+
+void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *dst)
+{
+	uint32_t seed, val, info_1, info_2;
+	uintptr_t size, dsth, dstl;
+
+	cert &= 0xFFFFFFFFU;
+
+	seed = mmio_read_32(RCAR_BOOT_KEY_CERT_NEW);
+	val = mmio_read_32(RCAR_BOOT_KEY_CERT_NEW + 0xC);
+	info_1 = (val >> 18) & 0x3U;
+	val = mmio_read_32(cert + 0xC);
+	info_2 = (val >> 21) & 0x3;
+
+	if (seed == RCAR_CERT_MAGIC_NUM) {
+		if (info_1 != 1) {
+			ERROR("BL2: Cert is invalid.\n");
+			*dst = 0;
+			*len = 0;
+			return;
+		}
+
+		if (info_2 > 2) {
+			ERROR("BL2: Cert is invalid.\n");
+			*dst = 0;
+			*len = 0;
+			return;
+		}
+
+		switch (info_2) {
+		case 2:
+			size = cert + RCAR_CERT_INFO_SIZE_OFFSET2;
+			dstl = cert + RCAR_CERT_INFO_DST_OFFSET2;
+			break;
+		case 1:
+			size = cert + RCAR_CERT_INFO_SIZE_OFFSET1;
+			dstl = cert + RCAR_CERT_INFO_DST_OFFSET1;
+			break;
+		case 0:
+			size = cert + RCAR_CERT_INFO_SIZE_OFFSET;
+			dstl = cert + RCAR_CERT_INFO_DST_OFFSET;
+			break;
+		}
+
+		*len = mmio_read_32(size) * 4U;
+		dsth = dstl + 4U;
+		*dst = ((uintptr_t) mmio_read_32(dsth) << 32) +
+		    ((uintptr_t) mmio_read_32(dstl));
+		return;
+	}
+
+	size = cert + RCAR_CERT_INFO_SIZE_OFFSET;
+	*len = mmio_read_32(size) * 4U;
+	dstl = cert + RCAR_CERT_INFO_DST_OFFSET;
+	dsth = dstl + 4U;
+	*dst = ((uintptr_t) mmio_read_32(dsth) << 32) +
+	    ((uintptr_t) mmio_read_32(dstl));
+}
+
+static int32_t check_load_area(uintptr_t dst, uintptr_t len)
+{
+	uint32_t legacy = dst + len <= UINT32_MAX - 1 ? 1 : 0;
+	uintptr_t dram_start, dram_end;
+	uintptr_t prot_start, prot_end;
+	int32_t result = IO_SUCCESS;
+
+	dram_start = legacy ? DRAM1_BASE : DRAM_40BIT_BASE;
+
+	dram_end = legacy ? DRAM1_BASE + DRAM1_SIZE :
+	    DRAM_40BIT_BASE + DRAM_40BIT_SIZE;
+
+	prot_start = legacy ? DRAM_PROTECTED_BASE : DRAM_40BIT_PROTECTED_BASE;
+
+	prot_end = prot_start + DRAM_PROTECTED_SIZE;
+
+	if (dst < dram_start || dst > dram_end - len) {
+		ERROR("BL2: dst address is on the protected area.\n");
+		result = IO_FAIL;
+		goto done;
+	}
+
+	/* load image is within SDRAM protected area */
+	if (dst >= prot_start && dst < prot_end) {
+		ERROR("BL2: dst address is on the protected area.\n");
+		result = IO_FAIL;
+	}
+
+	if (dst < prot_start && dst > prot_start - len) {
+		ERROR("BL2: loaded data is on the protected area.\n");
+		result = IO_FAIL;
+	}
+done:
+	if (result == IO_FAIL)
+		ERROR("BL2: Out of range : dst=0x%lx len=0x%lx\n", dst, len);
+
+	return result;
+}
+
+static int32_t load_bl33x(void)
+{
+	static int32_t loaded = IO_NOT_SUPPORTED;
+	uintptr_t dst, partition, handle;
+	uint32_t noload, cert, len, i;
+	uintptr_t offset;
+	int32_t rc;
+	size_t cnt;
+	const int32_t img[] = {
+		BL33_IMAGE_ID,
+		BL332_IMAGE_ID,
+		BL333_IMAGE_ID,
+		BL334_IMAGE_ID,
+		BL335_IMAGE_ID,
+		BL336_IMAGE_ID,
+		BL337_IMAGE_ID,
+		BL338_IMAGE_ID
+	};
+
+	if (loaded != IO_NOT_SUPPORTED)
+		return loaded;
+
+	for (i = 1; i < rcar_image_number; i++) {
+		rc = file_to_offset(img[i], &offset, &cert, &noload,
+				    &partition);
+		if (rc != IO_SUCCESS) {
+			WARN("load_bl33x: failed to get offset\n");
+			loaded = IO_FAIL;
+			return loaded;
+		}
+
+		rcar_read_certificate((uint64_t) cert, &len, &dst);
+		((io_drv_spec_t *) rcar_spec)->partition = partition;
+
+		rc = io_open(rcar_handle, rcar_spec, &handle);
+		if (rc != IO_SUCCESS) {
+			WARN("Failed to open FIP (%i)\n", rc);
+			loaded = IO_FAIL;
+			return loaded;
+		}
+
+		rc = io_seek(handle, IO_SEEK_SET, offset);
+		if (rc != IO_SUCCESS) {
+			WARN("load_bl33x: failed to seek\n");
+			loaded = IO_FAIL;
+			return loaded;
+		}
+
+		rc = check_load_area(dst, len);
+		if (rc != IO_SUCCESS) {
+			WARN("load_bl33x: check load area\n");
+			loaded = IO_FAIL;
+			return loaded;
+		}
+
+		rc = io_read(handle, dst, len, &cnt);
+		if (rc != IO_SUCCESS) {
+			WARN("load_bl33x: failed to read\n");
+			loaded = IO_FAIL;
+			return loaded;
+		}
+#if TRUSTED_BOARD_BOOT
+		rc = auth_mod_verify_img(img[i], (void *)dst, len);
+		if (rc) {
+			memset((void *)dst, 0x00, len);
+			loaded = IO_FAIL;
+			return loaded;
+		}
+#endif
+		io_close(handle);
+	}
+
+	loaded = IO_SUCCESS;
+
+	return loaded;
+}
+
+static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name)
+{
+	uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = {
+	0};
+	uintptr_t handle;
+	ssize_t offset;
+	uint32_t i;
+	int32_t rc;
+	size_t cnt;
+
+	/* Obtain a reference to the image by querying the platform layer */
+	rc = plat_get_drv_source(name, &rcar_handle, &rcar_spec);
+	if (rc != IO_SUCCESS) {
+		WARN("Failed to obtain reference to img %ld (%i)\n", name, rc);
+		return IO_FAIL;
+	}
+
+	if (RCAR_CERT_LOAD == rcar_cert_load)
+		return IO_SUCCESS;
+
+	rc = io_open(rcar_handle, rcar_spec, &handle);
+	if (rc != IO_SUCCESS) {
+		WARN("Failed to access img %ld (%i)\n", name, rc);
+		return IO_FAIL;
+	}
+
+	/* get start address list   */
+	/* [0] address num          */
+	/* [1] BL33-1 image address */
+	/* [2] BL33-2 image address */
+	/* [3] BL33-3 image address */
+	/* [4] BL33-4 image address */
+	/* [5] BL33-5 image address */
+	/* [6] BL33-6 image address */
+	/* [7] BL33-7 image address */
+	/* [8] BL33-8 image address */
+	offset = name == EMMC_DEV_ID ? RCAR_EMMC_CERT_HEADER :
+	    RCAR_FLASH_CERT_HEADER;
+	rc = io_seek(handle, IO_SEEK_SET, offset);
+	if (rc != IO_SUCCESS) {
+		WARN("Firmware Image Package header failed to seek\n");
+		goto error;
+	}
+#if RCAR_BL2_DCACHE == 1
+	inv_dcache_range((uint64_t) header, sizeof(header));
+#endif
+	rc = io_read(handle, (uintptr_t) &header, sizeof(header), &cnt);
+	if (rc != IO_SUCCESS) {
+		WARN("Firmware Image Package header failed to read\n");
+		goto error;
+	}
+
+	rcar_image_number = header[0];
+	for (i = 0; i < rcar_image_number + 2; i++) {
+		rcar_image_header[i] = header[i * 2 + 1];
+		rcar_image_header_prttn[i] = header[i * 2 + 2];
+	}
+
+	if (rcar_image_number == 0 || rcar_image_number > RCAR_MAX_BL3X_IMAGE) {
+		WARN("Firmware Image Package header check failed.\n");
+		goto error;
+	}
+
+	rc = io_seek(handle, IO_SEEK_SET, offset + RCAR_SECTOR6_CERT_OFFSET);
+	if (rc != IO_SUCCESS) {
+		WARN("Firmware Image Package header failed to seek cert\n");
+		goto error;
+	}
+#if RCAR_BL2_DCACHE == 1
+	inv_dcache_range(RCAR_SDRAM_certESS,
+			 RCAR_CERT_SIZE * (2 + rcar_image_number));
+#endif
+	rc = io_read(handle, RCAR_SDRAM_certESS,
+		     RCAR_CERT_SIZE * (2 + rcar_image_number), &cnt);
+	if (rc != IO_SUCCESS) {
+		WARN("cert file read error.\n");
+		goto error;
+	}
+
+	rcar_cert_load = RCAR_CERT_LOAD;
+error:
+
+	if (rc != IO_SUCCESS)
+		rc = IO_FAIL;
+
+	io_close(handle);
+
+	return rc;
+
+}
+
+static int32_t rcar_file_open(io_dev_info_t *info, const uintptr_t file_spec,
+			      io_entity_t *entity)
+{
+	const io_drv_spec_t *spec = (io_drv_spec_t *) file_spec;
+	uintptr_t partition, offset, dst;
+	uint32_t noload, cert, len;
+	int32_t rc;
+
+	/* Only one file open at a time. We need to  track state (ie, file
+	 * cursor position). Since the header lives at * offset zero, this entry
+	 * should never be zero in an active file.
+	 * Once the system supports dynamic memory allocation we will allow more
+	 * than one open file at a time. */
+	if (current_file.offset != 0U) {
+		WARN("rcar_file_open : Only one open file at a time.\n");
+		return IO_RESOURCES_EXHAUSTED;
+	}
+
+	rc = file_to_offset(spec->offset, &offset, &cert, &noload, &partition);
+	if (rc != IO_SUCCESS) {
+		WARN("Failed to open file name %ld (%i)\n", spec->offset, rc);
+		return IO_FAIL;
+	}
+
+	if (noload) {
+		current_file.offset = 1;
+		current_file.dst = 0;
+		current_file.size = 1;
+		current_file.position = 0;
+		current_file.no_load = noload;
+		current_file.partition = 0;
+		entity->info = (uintptr_t) &current_file;
+
+		return IO_SUCCESS;
+	}
+
+	rcar_read_certificate((uint64_t) cert, &len, &dst);
+
+	/*----------------*
+	 * Baylibre: HACK *
+	 *----------------*/
+	if (BL31_IMAGE_ID == spec->offset && len < RCAR_TRUSTED_SRAM_SIZE) {
+		WARN("r-car ignoring the BL31 size from certificate,"
+		     "using RCAR_TRUSTED_SRAM_SIZE instead\n");
+		len = RCAR_TRUSTED_SRAM_SIZE;
+	}
+
+	current_file.partition = partition;
+	current_file.no_load = noload;
+	current_file.offset = offset;
+	current_file.position = 0;
+	current_file.size = len;
+	current_file.dst = dst;
+	entity->info = (uintptr_t) &current_file;
+
+	return IO_SUCCESS;
+}
+
+static int32_t rcar_file_len(io_entity_t *entity, size_t *length)
+{
+	*length = ((file_state_t *) entity->info)->size;
+
+	NOTICE("%s: len: 0x%08lx\n", __func__, *length);
+
+	return IO_SUCCESS;
+}
+
+static int32_t rcar_file_read(io_entity_t *entity, uintptr_t buffer,
+			      size_t length, size_t *cnt)
+{
+	file_state_t *fp = (file_state_t *) entity->info;
+	ssize_t offset = fp->offset + fp->position;
+	uintptr_t handle;
+	int32_t rc;
+
+#ifdef SPD_NONE
+	static uint32_t load_bl33x_counter = 1;
+#else
+	static uint32_t load_bl33x_counter;
+#endif
+	if (current_file.no_load) {
+		*cnt = length;
+		return IO_SUCCESS;
+	}
+
+	((io_drv_spec_t *) rcar_spec)->partition = fp->partition;
+
+	rc = io_open(rcar_handle, rcar_spec, &handle);
+	if (rc != IO_SUCCESS) {
+		WARN("Failed to open FIP (%i)\n", rc);
+		return IO_FAIL;
+	}
+
+	rc = io_seek(handle, IO_SEEK_SET, offset);
+	if (rc != IO_SUCCESS) {
+		WARN("rcar_file_read: failed to seek\n");
+		goto error;
+	}
+
+	if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33) {
+		rc = check_load_area(buffer, length);
+		if (rc != IO_SUCCESS) {
+			WARN("rcar_file_read: load area err\n");
+			goto error;
+		}
+	}
+
+	rc = io_read(handle, buffer, length, cnt);
+	if (rc != IO_SUCCESS) {
+		WARN("Failed to read payload (%i)\n", rc);
+		goto error;
+	}
+
+	fp->position += *cnt;
+	io_close(handle);
+
+	load_bl33x_counter += 1;
+	if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33X)
+		return load_bl33x();
+
+	return IO_SUCCESS;
+error:
+	io_close(handle);
+	return IO_FAIL;
+}
+
+static int32_t rcar_file_close(io_entity_t *entity)
+{
+	if (current_file.offset)
+		memset(&current_file, 0, sizeof(current_file));
+
+	entity->info = 0U;
+
+	return IO_SUCCESS;
+}
+
+static const io_dev_funcs_t rcar_dev_funcs = {
+	.type = &device_type_rcar,
+	.open = &rcar_file_open,
+	.seek = NULL,
+	.size = &rcar_file_len,
+	.read = &rcar_file_read,
+	.write = NULL,
+	.close = &rcar_file_close,
+	.dev_init = &rcar_dev_init,
+	.dev_close = &rcar_dev_close,
+};
+
+static const io_dev_info_t rcar_dev_info = {
+	.funcs = &rcar_dev_funcs,
+	.info = (uintptr_t) 0
+};
+
+static const io_dev_connector_t rcar_dev_connector = {
+	.dev_open = &rcar_dev_open
+};
+
+static int32_t rcar_dev_open(const uintptr_t dev_spec __attribute__ ((unused)),
+			     io_dev_info_t **dev_info)
+{
+	*dev_info = (io_dev_info_t *) &rcar_dev_info;
+
+	return IO_SUCCESS;
+}
+
+static int32_t rcar_dev_close(io_dev_info_t *dev_info)
+{
+	rcar_handle = 0;
+	rcar_spec = 0;
+
+	return IO_SUCCESS;
+}
+
+int32_t rcar_register_io_dev(const io_dev_connector_t **dev_con)
+{
+	int32_t result;
+
+	result = io_register_device(&rcar_dev_info);
+	if (result == IO_SUCCESS)
+		*dev_con = &rcar_dev_connector;
+
+	return result;
+}
diff --git a/drivers/renesas/rcar/io/io_rcar.h b/drivers/renesas/rcar/io/io_rcar.h
new file mode 100644
index 0000000..c26a617
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_rcar.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_RCAR_H
+#define IO_RCAR_H
+
+int32_t rcar_register_io_dev(const io_dev_connector_t **dev_con);
+int32_t rcar_get_certificate(const int32_t name, uint32_t *cert);
+void rcar_read_certificate(uint64_t cert, uint32_t *size, uintptr_t *dest);
+
+#endif /* IO_RCAR_H */
diff --git a/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c
new file mode 100644
index 0000000..aaa3b43
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <lib/mmio.h>
+#include "pfc_init_d3.h"
+#include "rcar_def.h"
+#include "../pfc_regs.h"
+
+/* PFC */
+#define GPSR0_D15		BIT(15)
+#define GPSR0_D14		BIT(14)
+#define GPSR0_D13		BIT(13)
+#define GPSR0_D12		BIT(12)
+#define GPSR0_D11		BIT(11)
+#define GPSR0_D10		BIT(10)
+#define GPSR0_D9		BIT(9)
+#define GPSR0_D8		BIT(8)
+#define GPSR0_D7		BIT(7)
+#define GPSR0_D6		BIT(6)
+#define GPSR0_D5		BIT(5)
+#define GPSR0_D4		BIT(4)
+#define GPSR0_D3		BIT(3)
+#define GPSR0_D2		BIT(2)
+#define GPSR0_D1		BIT(1)
+#define GPSR0_D0		BIT(0)
+#define GPSR1_CLKOUT		BIT(28)
+#define GPSR1_EX_WAIT0_A	BIT(27)
+#define GPSR1_WE1		BIT(26)
+#define GPSR1_WE0		BIT(25)
+#define GPSR1_RD_WR		BIT(24)
+#define GPSR1_RD		BIT(23)
+#define GPSR1_BS		BIT(22)
+#define GPSR1_CS1_A26		BIT(21)
+#define GPSR1_CS0		BIT(20)
+#define GPSR1_A19		BIT(19)
+#define GPSR1_A18		BIT(18)
+#define GPSR1_A17		BIT(17)
+#define GPSR1_A16		BIT(16)
+#define GPSR1_A15		BIT(15)
+#define GPSR1_A14		BIT(14)
+#define GPSR1_A13		BIT(13)
+#define GPSR1_A12		BIT(12)
+#define GPSR1_A11		BIT(11)
+#define GPSR1_A10		BIT(10)
+#define GPSR1_A9		BIT(9)
+#define GPSR1_A8		BIT(8)
+#define GPSR1_A7		BIT(7)
+#define GPSR1_A6		BIT(6)
+#define GPSR1_A5		BIT(5)
+#define GPSR1_A4		BIT(4)
+#define GPSR1_A3		BIT(3)
+#define GPSR1_A2		BIT(2)
+#define GPSR1_A1		BIT(1)
+#define GPSR1_A0		BIT(0)
+#define GPSR2_AVB_AVTP_CAPTURE_A	BIT(14)
+#define GPSR2_AVB_AVTP_MATCH_A	BIT(13)
+#define GPSR2_AVB_LINK		BIT(12)
+#define GPSR2_AVB_PHY_INT	BIT(11)
+#define GPSR2_AVB_MAGIC		BIT(10)
+#define GPSR2_AVB_MDC		BIT(9)
+#define GPSR2_PWM2_A		BIT(8)
+#define GPSR2_PWM1_A		BIT(7)
+#define GPSR2_PWM0		BIT(6)
+#define GPSR2_IRQ5		BIT(5)
+#define GPSR2_IRQ4		BIT(4)
+#define GPSR2_IRQ3		BIT(3)
+#define GPSR2_IRQ2		BIT(2)
+#define GPSR2_IRQ1		BIT(1)
+#define GPSR2_IRQ0		BIT(0)
+#define GPSR3_SD1_WP		BIT(15)
+#define GPSR3_SD1_CD		BIT(14)
+#define GPSR3_SD0_WP		BIT(13)
+#define GPSR3_SD0_CD		BIT(12)
+#define GPSR3_SD1_DAT3		BIT(11)
+#define GPSR3_SD1_DAT2		BIT(10)
+#define GPSR3_SD1_DAT1		BIT(9)
+#define GPSR3_SD1_DAT0		BIT(8)
+#define GPSR3_SD1_CMD		BIT(7)
+#define GPSR3_SD1_CLK		BIT(6)
+#define GPSR3_SD0_DAT3		BIT(5)
+#define GPSR3_SD0_DAT2		BIT(4)
+#define GPSR3_SD0_DAT1		BIT(3)
+#define GPSR3_SD0_DAT0		BIT(2)
+#define GPSR3_SD0_CMD		BIT(1)
+#define GPSR3_SD0_CLK		BIT(0)
+#define GPSR4_SD3_DS		BIT(17)
+#define GPSR4_SD3_DAT7		BIT(16)
+#define GPSR4_SD3_DAT6		BIT(15)
+#define GPSR4_SD3_DAT5		BIT(14)
+#define GPSR4_SD3_DAT4		BIT(13)
+#define GPSR4_SD3_DAT3		BIT(12)
+#define GPSR4_SD3_DAT2		BIT(11)
+#define GPSR4_SD3_DAT1		BIT(10)
+#define GPSR4_SD3_DAT0		BIT(9)
+#define GPSR4_SD3_CMD		BIT(8)
+#define GPSR4_SD3_CLK		BIT(7)
+#define GPSR4_SD2_DS		BIT(6)
+#define GPSR4_SD2_DAT3		BIT(5)
+#define GPSR4_SD2_DAT2		BIT(4)
+#define GPSR4_SD2_DAT1		BIT(3)
+#define GPSR4_SD2_DAT0		BIT(2)
+#define GPSR4_SD2_CMD		BIT(1)
+#define GPSR4_SD2_CLK		BIT(0)
+#define GPSR5_MLB_DAT		BIT(25)
+#define GPSR5_MLB_SIG		BIT(24)
+#define GPSR5_MLB_CLK		BIT(23)
+#define GPSR5_MSIOF0_RXD	BIT(22)
+#define GPSR5_MSIOF0_SS2	BIT(21)
+#define GPSR5_MSIOF0_TXD	BIT(20)
+#define GPSR5_MSIOF0_SS1	BIT(19)
+#define GPSR5_MSIOF0_SYNC	BIT(18)
+#define GPSR5_MSIOF0_SCK	BIT(17)
+#define GPSR5_HRTS0		BIT(16)
+#define GPSR5_HCTS0		BIT(15)
+#define GPSR5_HTX0		BIT(14)
+#define GPSR5_HRX0		BIT(13)
+#define GPSR5_HSCK0		BIT(12)
+#define GPSR5_RX2_A		BIT(11)
+#define GPSR5_TX2_A		BIT(10)
+#define GPSR5_SCK2		BIT(9)
+#define GPSR5_RTS1_TANS		BIT(8)
+#define GPSR5_CTS1		BIT(7)
+#define GPSR5_TX1_A		BIT(6)
+#define GPSR5_RX1_A		BIT(5)
+#define GPSR5_RTS0_TANS		BIT(4)
+#define GPSR5_CTS0		BIT(3)
+#define GPSR5_TX0		BIT(2)
+#define GPSR5_RX0		BIT(1)
+#define GPSR5_SCK0		BIT(0)
+#define GPSR6_USB31_OVC		BIT(31)
+#define GPSR6_USB31_PWEN	BIT(30)
+#define GPSR6_USB30_OVC		BIT(29)
+#define GPSR6_USB30_PWEN	BIT(28)
+#define GPSR6_USB1_OVC		BIT(27)
+#define GPSR6_USB1_PWEN		BIT(26)
+#define GPSR6_USB0_OVC		BIT(25)
+#define GPSR6_USB0_PWEN		BIT(24)
+#define GPSR6_AUDIO_CLKB_B	BIT(23)
+#define GPSR6_AUDIO_CLKA_A	BIT(22)
+#define GPSR6_SSI_SDATA9_A	BIT(21)
+#define GPSR6_SSI_SDATA8	BIT(20)
+#define GPSR6_SSI_SDATA7	BIT(19)
+#define GPSR6_SSI_WS78		BIT(18)
+#define GPSR6_SSI_SCK78		BIT(17)
+#define GPSR6_SSI_SDATA6	BIT(16)
+#define GPSR6_SSI_WS6		BIT(15)
+#define GPSR6_SSI_SCK6		BIT(14)
+#define GPSR6_SSI_SDATA5	BIT(13)
+#define GPSR6_SSI_WS5		BIT(12)
+#define GPSR6_SSI_SCK5		BIT(11)
+#define GPSR6_SSI_SDATA4	BIT(10)
+#define GPSR6_SSI_WS4		BIT(9)
+#define GPSR6_SSI_SCK4		BIT(8)
+#define GPSR6_SSI_SDATA3	BIT(7)
+#define GPSR6_SSI_WS34		BIT(6)
+#define GPSR6_SSI_SCK34		BIT(5)
+#define GPSR6_SSI_SDATA2_A	BIT(4)
+#define GPSR6_SSI_SDATA1_A	BIT(3)
+#define GPSR6_SSI_SDATA0	BIT(2)
+#define GPSR6_SSI_WS0129	BIT(1)
+#define GPSR6_SSI_SCK0129	BIT(0)
+#define GPSR7_HDMI1_CEC		BIT(3)
+#define GPSR7_HDMI0_CEC		BIT(2)
+#define GPSR7_AVS2		BIT(1)
+#define GPSR7_AVS1		BIT(0)
+
+#define IPSR_28_FUNC(x)		((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)		((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)		((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)		((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)		((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)		((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)		((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)		((uint32_t)(x) << 0U)
+
+#define POC_SD3_DS_33V		BIT(29)
+#define POC_SD3_DAT7_33V	BIT(28)
+#define POC_SD3_DAT6_33V	BIT(27)
+#define POC_SD3_DAT5_33V	BIT(26)
+#define POC_SD3_DAT4_33V	BIT(25)
+#define POC_SD3_DAT3_33V	BIT(24)
+#define POC_SD3_DAT2_33V	BIT(23)
+#define POC_SD3_DAT1_33V	BIT(22)
+#define POC_SD3_DAT0_33V	BIT(21)
+#define POC_SD3_CMD_33V		BIT(20)
+#define POC_SD3_CLK_33V		BIT(19)
+#define POC_SD2_DS_33V		BIT(18)
+#define POC_SD2_DAT3_33V	BIT(17)
+#define POC_SD2_DAT2_33V	BIT(16)
+#define POC_SD2_DAT1_33V	BIT(15)
+#define POC_SD2_DAT0_33V	BIT(14)
+#define POC_SD2_CMD_33V		BIT(13)
+#define POC_SD2_CLK_33V		BIT(12)
+#define POC_SD1_DAT3_33V	BIT(11)
+#define POC_SD1_DAT2_33V	BIT(10)
+#define POC_SD1_DAT1_33V	BIT(9)
+#define POC_SD1_DAT0_33V	BIT(8)
+#define POC_SD1_CMD_33V		BIT(7)
+#define POC_SD1_CLK_33V		BIT(6)
+#define POC_SD0_DAT3_33V	BIT(5)
+#define POC_SD0_DAT2_33V	BIT(4)
+#define POC_SD0_DAT1_33V	BIT(3)
+#define POC_SD0_DAT0_33V	BIT(2)
+#define POC_SD0_CMD_33V		BIT(1)
+#define POC_SD0_CLK_33V		BIT(0)
+
+#define DRVCTRL0_MASK		(0xCCCCCCCCU)
+#define DRVCTRL1_MASK		(0xCCCCCCC8U)
+#define DRVCTRL2_MASK		(0x88888888U)
+#define DRVCTRL3_MASK		(0x88888888U)
+#define DRVCTRL4_MASK		(0x88888888U)
+#define DRVCTRL5_MASK		(0x88888888U)
+#define DRVCTRL6_MASK		(0x88888888U)
+#define DRVCTRL7_MASK		(0x88888888U)
+#define DRVCTRL8_MASK		(0x88888888U)
+#define DRVCTRL9_MASK		(0x88888888U)
+#define DRVCTRL10_MASK		(0x88888888U)
+#define DRVCTRL11_MASK		(0x888888CCU)
+#define DRVCTRL12_MASK		(0xCCCFFFCFU)
+#define DRVCTRL13_MASK		(0xCC888888U)
+#define DRVCTRL14_MASK		(0x88888888U)
+#define DRVCTRL15_MASK		(0x88888888U)
+#define DRVCTRL16_MASK		(0x88888888U)
+#define DRVCTRL17_MASK		(0x88888888U)
+#define DRVCTRL18_MASK		(0x88888888U)
+#define DRVCTRL19_MASK		(0x88888888U)
+#define DRVCTRL20_MASK		(0x88888888U)
+#define DRVCTRL21_MASK		(0x88888888U)
+#define DRVCTRL22_MASK		(0x88888888U)
+#define DRVCTRL23_MASK		(0x88888888U)
+#define DRVCTRL24_MASK		(0x8888888FU)
+
+#define DRVCTRL0_QSPI0_SPCLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL0_QSPI0_MOSI_IO0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL0_QSPI0_MISO_IO1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL0_QSPI0_IO2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL0_QSPI0_IO3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL0_QSPI0_SSL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL0_QSPI1_SPCLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL0_QSPI1_MOSI_IO0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL1_QSPI1_MISO_IO1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL1_QSPI1_IO2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL1_QSPI1_IO3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL1_QSPI1_SS(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL1_RPC_INT(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL1_RPC_WP(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL1_RPC_RESET(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL1_AVB_RX_CTL(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL2_AVB_RXC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL2_AVB_RD0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL2_AVB_RD1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL2_AVB_RD2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL2_AVB_RD3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL2_AVB_TX_CTL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL2_AVB_TXC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL2_AVB_TD0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL3_AVB_TD1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL3_AVB_TD2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL3_AVB_TD3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL3_AVB_TXCREFCLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL3_AVB_MDIO(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL3_AVB_MDC(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL3_AVB_MAGIC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL3_AVB_PHY_INT(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL4_AVB_LINK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL4_AVB_AVTP_MATCH(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL4_AVB_AVTP_CAPTURE(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL4_IRQ0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL4_IRQ1(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL4_IRQ2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL4_IRQ3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL4_IRQ4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL5_IRQ5(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL5_PWM0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL5_PWM1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL5_PWM2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL5_A0(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL5_A1(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL5_A2(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL5_A3(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL6_A4(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL6_A5(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL6_A6(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL6_A7(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL6_A8(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL6_A9(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL6_A10(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL6_A11(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL7_A12(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL7_A13(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL7_A14(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL7_A15(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL7_A16(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL7_A17(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL7_A18(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL7_A19(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL8_CLKOUT(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL8_CS0(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL8_CS1_A2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL8_BS(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL8_RD(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL8_RD_W(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL8_WE0(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL8_WE1(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL9_EX_WAIT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL9_PRESETOU(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL9_D0(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL9_D1(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL9_D2(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL9_D3(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL9_D4(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL9_D5(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL10_D6(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL10_D7(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL10_D8(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL10_D9(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL10_D10(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL10_D11(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL10_D12(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL10_D13(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL11_D14(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL11_D15(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL11_AVS1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL11_AVS2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL11_HDMI0_CEC(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL11_HDMI1_CEC(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL11_DU_DOTCLKIN0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL11_DU_DOTCLKIN1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL12_DU_DOTCLKIN2(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL12_DU_DOTCLKIN3(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL12_DU_FSCLKST(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL12_DU_TMS(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_TDO(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL13_ASEBRK(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL13_SD0_CLK(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL13_SD0_CMD(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL13_SD0_DAT0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL13_SD0_DAT1(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL13_SD0_DAT2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_SD0_DAT3(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL14_SD1_CLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL14_SD1_CMD(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL14_SD1_DAT0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL14_SD1_DAT1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL14_SD1_DAT2(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL14_SD1_DAT3(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL14_SD2_CLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL14_SD2_CMD(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL15_SD2_DAT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL15_SD2_DAT1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL15_SD2_DAT2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL15_SD2_DAT3(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL15_SD2_DS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL15_SD3_CLK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL15_SD3_CMD(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL15_SD3_DAT0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL16_SD3_DAT1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL16_SD3_DAT2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL16_SD3_DAT3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL16_SD3_DAT4(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL16_SD3_DAT5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL16_SD3_DAT6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL16_SD3_DAT7(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL16_SD3_DS(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL17_SD0_CD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL17_SD0_WP(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL17_SD1_CD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL17_SD1_WP(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL17_SCK0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL17_RX0(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL17_TX0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL17_CTS0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL18_RTS0_TANS(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL18_RX1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL18_TX1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL18_CTS1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL18_RTS1_TANS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL18_SCK2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL18_TX2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL18_RX2(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL19_HSCK0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL19_HRX0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL19_HTX0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL19_HCTS0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL19_HRTS0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL19_MSIOF0_SCK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL19_MSIOF0_SYNC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL19_MSIOF0_SS1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL20_MSIOF0_TXD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL20_MSIOF0_SS2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL20_MSIOF0_RXD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL20_MLB_CLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL20_MLB_SIG(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL20_MLB_DAT(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL20_MLB_REF(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL20_SSI_SCK0129(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL21_SSI_WS0129(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL21_SSI_SDATA0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL21_SSI_SDATA1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL21_SSI_SDATA2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL21_SSI_SCK34(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL21_SSI_WS34(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL21_SSI_SDATA3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL21_SSI_SCK4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL22_SSI_WS4(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL22_SSI_SDATA4(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL22_SSI_SCK5(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL22_SSI_WS5(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL22_SSI_SDATA5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL22_SSI_SCK6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL22_SSI_WS6(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL22_SSI_SDATA6(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL23_SSI_SCK78(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL23_SSI_WS78(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL23_SSI_SDATA7(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL23_SSI_SDATA8(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL23_SSI_SDATA9(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL23_AUDIO_CLKA(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL23_AUDIO_CLKB(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL23_USB0_PWEN(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL24_USB0_OVC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL24_USB1_PWEN(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL24_USB1_OVC(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL24_USB30_PWEN(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL24_USB30_OVC(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL24_USB31_PWEN(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL24_USB31_OVC(x)	((uint32_t)(x) << 4U)
+
+#define MOD_SEL0_MSIOF3_A	((uint32_t)0U << 29U)
+#define MOD_SEL0_MSIOF3_B	((uint32_t)1U << 29U)
+#define MOD_SEL0_MSIOF3_C	((uint32_t)2U << 29U)
+#define MOD_SEL0_MSIOF3_D	((uint32_t)3U << 29U)
+#define MOD_SEL0_MSIOF3_E	((uint32_t)4U << 29U)
+#define MOD_SEL0_MSIOF2_A	((uint32_t)0U << 27U)
+#define MOD_SEL0_MSIOF2_B	((uint32_t)1U << 27U)
+#define MOD_SEL0_MSIOF2_C	((uint32_t)2U << 27U)
+#define MOD_SEL0_MSIOF2_D	((uint32_t)3U << 27U)
+#define MOD_SEL0_MSIOF1_A	((uint32_t)0U << 24U)
+#define MOD_SEL0_MSIOF1_B	((uint32_t)1U << 24U)
+#define MOD_SEL0_MSIOF1_C	((uint32_t)2U << 24U)
+#define MOD_SEL0_MSIOF1_D	((uint32_t)3U << 24U)
+#define MOD_SEL0_MSIOF1_E	((uint32_t)4U << 24U)
+#define MOD_SEL0_MSIOF1_F	((uint32_t)5U << 24U)
+#define MOD_SEL0_MSIOF1_G	((uint32_t)6U << 24U)
+#define MOD_SEL0_LBSC_A		((uint32_t)0U << 23U)
+#define MOD_SEL0_LBSC_B		((uint32_t)1U << 23U)
+#define MOD_SEL0_IEBUS_A	((uint32_t)0U << 22U)
+#define MOD_SEL0_IEBUS_B	((uint32_t)1U << 22U)
+#define MOD_SEL0_I2C2_A		((uint32_t)0U << 21U)
+#define MOD_SEL0_I2C2_B		((uint32_t)1U << 21U)
+#define MOD_SEL0_I2C1_A		((uint32_t)0U << 20U)
+#define MOD_SEL0_I2C1_B		((uint32_t)1U << 20U)
+#define MOD_SEL0_HSCIF4_A	((uint32_t)0U << 19U)
+#define MOD_SEL0_HSCIF4_B	((uint32_t)1U << 19U)
+#define MOD_SEL0_HSCIF3_A	((uint32_t)0U << 17U)
+#define MOD_SEL0_HSCIF3_B	((uint32_t)1U << 17U)
+#define MOD_SEL0_HSCIF3_C	((uint32_t)2U << 17U)
+#define MOD_SEL0_HSCIF3_D	((uint32_t)3U << 17U)
+#define MOD_SEL0_HSCIF1_A	((uint32_t)0U << 16U)
+#define MOD_SEL0_HSCIF1_B	((uint32_t)1U << 16U)
+#define MOD_SEL0_FSO_A		((uint32_t)0U << 15U)
+#define MOD_SEL0_FSO_B		((uint32_t)1U << 15U)
+#define MOD_SEL0_HSCIF2_A	((uint32_t)0U << 13U)
+#define MOD_SEL0_HSCIF2_B	((uint32_t)1U << 13U)
+#define MOD_SEL0_HSCIF2_C	((uint32_t)2U << 13U)
+#define MOD_SEL0_ETHERAVB_A	((uint32_t)0U << 12U)
+#define MOD_SEL0_ETHERAVB_B	((uint32_t)1U << 12U)
+#define MOD_SEL0_DRIF3_A	((uint32_t)0U << 11U)
+#define MOD_SEL0_DRIF3_B	((uint32_t)1U << 11U)
+#define MOD_SEL0_DRIF2_A	((uint32_t)0U << 10U)
+#define MOD_SEL0_DRIF2_B	((uint32_t)1U << 10U)
+#define MOD_SEL0_DRIF1_A	((uint32_t)0U << 8U)
+#define MOD_SEL0_DRIF1_B	((uint32_t)1U << 8U)
+#define MOD_SEL0_DRIF1_C	((uint32_t)2U << 8U)
+#define MOD_SEL0_DRIF0_A	((uint32_t)0U << 6U)
+#define MOD_SEL0_DRIF0_B	((uint32_t)1U << 6U)
+#define MOD_SEL0_DRIF0_C	((uint32_t)2U << 6U)
+#define MOD_SEL0_CANFD0_A	((uint32_t)0U << 5U)
+#define MOD_SEL0_CANFD0_B	((uint32_t)1U << 5U)
+#define MOD_SEL0_ADG_A_A	((uint32_t)0U << 3U)
+#define MOD_SEL0_ADG_A_B	((uint32_t)1U << 3U)
+#define MOD_SEL0_ADG_A_C	((uint32_t)2U << 3U)
+#define MOD_SEL1_TSIF1_A	((uint32_t)0U << 30U)
+#define MOD_SEL1_TSIF1_B	((uint32_t)1U << 30U)
+#define MOD_SEL1_TSIF1_C	((uint32_t)2U << 30U)
+#define MOD_SEL1_TSIF1_D	((uint32_t)3U << 30U)
+#define MOD_SEL1_TSIF0_A	((uint32_t)0U << 27U)
+#define MOD_SEL1_TSIF0_B	((uint32_t)1U << 27U)
+#define MOD_SEL1_TSIF0_C	((uint32_t)2U << 27U)
+#define MOD_SEL1_TSIF0_D	((uint32_t)3U << 27U)
+#define MOD_SEL1_TSIF0_E	((uint32_t)4U << 27U)
+#define MOD_SEL1_TIMER_TMU_A	((uint32_t)0U << 26U)
+#define MOD_SEL1_TIMER_TMU_B	((uint32_t)1U << 26U)
+#define MOD_SEL1_SSP1_1_A	((uint32_t)0U << 24U)
+#define MOD_SEL1_SSP1_1_B	((uint32_t)1U << 24U)
+#define MOD_SEL1_SSP1_1_C	((uint32_t)2U << 24U)
+#define MOD_SEL1_SSP1_1_D	((uint32_t)3U << 24U)
+#define MOD_SEL1_SSP1_0_A	((uint32_t)0U << 21U)
+#define MOD_SEL1_SSP1_0_B	((uint32_t)1U << 21U)
+#define MOD_SEL1_SSP1_0_C	((uint32_t)2U << 21U)
+#define MOD_SEL1_SSP1_0_D	((uint32_t)3U << 21U)
+#define MOD_SEL1_SSP1_0_E	((uint32_t)4U << 21U)
+#define MOD_SEL1_SSI_A		((uint32_t)0U << 20U)
+#define MOD_SEL1_SSI_B		((uint32_t)1U << 20U)
+#define MOD_SEL1_SPEED_PULSE_IF_A	((uint32_t)0U << 19U)
+#define MOD_SEL1_SPEED_PULSE_IF_B	((uint32_t)1U << 19U)
+#define MOD_SEL1_SIMCARD_A	((uint32_t)0U << 17U)
+#define MOD_SEL1_SIMCARD_B	((uint32_t)1U << 17U)
+#define MOD_SEL1_SIMCARD_C	((uint32_t)2U << 17U)
+#define MOD_SEL1_SIMCARD_D	((uint32_t)3U << 17U)
+#define MOD_SEL1_SDHI2_A	((uint32_t)0U << 16U)
+#define MOD_SEL1_SDHI2_B	((uint32_t)1U << 16U)
+#define MOD_SEL1_SCIF4_A	((uint32_t)0U << 14U)
+#define MOD_SEL1_SCIF4_B	((uint32_t)1U << 14U)
+#define MOD_SEL1_SCIF4_C	((uint32_t)2U << 14U)
+#define MOD_SEL1_SCIF3_A	((uint32_t)0U << 13U)
+#define MOD_SEL1_SCIF3_B	((uint32_t)1U << 13U)
+#define MOD_SEL1_SCIF2_A	((uint32_t)0U << 12U)
+#define MOD_SEL1_SCIF2_B	((uint32_t)1U << 12U)
+#define MOD_SEL1_SCIF1_A	((uint32_t)0U << 11U)
+#define MOD_SEL1_SCIF1_B	((uint32_t)1U << 11U)
+#define MOD_SEL1_SCIF_A		((uint32_t)0U << 10U)
+#define MOD_SEL1_SCIF_B		((uint32_t)1U << 10U)
+#define MOD_SEL1_REMOCON_A	((uint32_t)0U << 9U)
+#define MOD_SEL1_REMOCON_B	((uint32_t)1U << 9U)
+#define MOD_SEL1_RCAN0_A	((uint32_t)0U << 6U)
+#define MOD_SEL1_RCAN0_B	((uint32_t)1U << 6U)
+#define MOD_SEL1_PWM6_A		((uint32_t)0U << 5U)
+#define MOD_SEL1_PWM6_B		((uint32_t)1U << 5U)
+#define MOD_SEL1_PWM5_A		((uint32_t)0U << 4U)
+#define MOD_SEL1_PWM5_B		((uint32_t)1U << 4U)
+#define MOD_SEL1_PWM4_A		((uint32_t)0U << 3U)
+#define MOD_SEL1_PWM4_B		((uint32_t)1U << 3U)
+#define MOD_SEL1_PWM3_A		((uint32_t)0U << 2U)
+#define MOD_SEL1_PWM3_B		((uint32_t)1U << 2U)
+#define MOD_SEL1_PWM2_A		((uint32_t)0U << 1U)
+#define MOD_SEL1_PWM2_B		((uint32_t)1U << 1U)
+#define MOD_SEL1_PWM1_A		((uint32_t)0U << 0U)
+#define MOD_SEL1_PWM1_B		((uint32_t)1U << 0U)
+#define MOD_SEL2_I2C_5_A	((uint32_t)0U << 31U)
+#define MOD_SEL2_I2C_5_B	((uint32_t)1U << 31U)
+#define MOD_SEL2_I2C_3_A	((uint32_t)0U << 30U)
+#define MOD_SEL2_I2C_3_B	((uint32_t)1U << 30U)
+#define MOD_SEL2_I2C_0_A	((uint32_t)0U << 29U)
+#define MOD_SEL2_I2C_0_B	((uint32_t)1U << 29U)
+#define MOD_SEL2_FM_A		((uint32_t)0U << 27U)
+#define MOD_SEL2_FM_B		((uint32_t)1U << 27U)
+#define MOD_SEL2_FM_C		((uint32_t)2U << 27U)
+#define MOD_SEL2_FM_D		((uint32_t)3U << 27U)
+#define MOD_SEL2_SCIF5_A	((uint32_t)0U << 26U)
+#define MOD_SEL2_SCIF5_B	((uint32_t)1U << 26U)
+#define MOD_SEL2_I2C6_A		((uint32_t)0U << 23U)
+#define MOD_SEL2_I2C6_B		((uint32_t)1U << 23U)
+#define MOD_SEL2_I2C6_C		((uint32_t)2U << 23U)
+#define MOD_SEL2_NDF_A		((uint32_t)0U << 22U)
+#define MOD_SEL2_NDF_B		((uint32_t)1U << 22U)
+#define MOD_SEL2_SSI2_A		((uint32_t)0U << 21U)
+#define MOD_SEL2_SSI2_B		((uint32_t)1U << 21U)
+#define MOD_SEL2_SSI9_A		((uint32_t)0U << 20U)
+#define MOD_SEL2_SSI9_B		((uint32_t)1U << 20U)
+#define MOD_SEL2_TIMER_TMU2_A	((uint32_t)0U << 19U)
+#define MOD_SEL2_TIMER_TMU2_B	((uint32_t)1U << 19U)
+#define MOD_SEL2_ADG_B_A	((uint32_t)0U << 18U)
+#define MOD_SEL2_ADG_B_B	((uint32_t)1U << 18U)
+#define MOD_SEL2_ADG_C_A	((uint32_t)0U << 17U)
+#define MOD_SEL2_ADG_C_B	((uint32_t)1U << 17U)
+#define MOD_SEL2_VIN4_A		((uint32_t)0U << 0U)
+#define MOD_SEL2_VIN4_B		((uint32_t)1U << 0U)
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	mmio_write_32(PFC_PMMR, ~data);
+	mmio_write_32((uintptr_t)addr, data);
+}
+
+void pfc_init_d3(void)
+{
+	/* initialize module select */
+	pfc_reg_write(PFC_MOD_SEL0, 0x00000000U);
+	pfc_reg_write(PFC_MOD_SEL1, 0x00000000U);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0,  0x00000001U);
+	pfc_reg_write(PFC_IPSR1,  0x00000000U);
+	pfc_reg_write(PFC_IPSR2,  0x00000000U);
+	pfc_reg_write(PFC_IPSR3,  0x00000000U);
+	pfc_reg_write(PFC_IPSR4,  0x00002000U);
+	pfc_reg_write(PFC_IPSR5,  0x00000000U);
+	pfc_reg_write(PFC_IPSR6,  0x00000000U);
+	pfc_reg_write(PFC_IPSR7,  0x00000000U);
+	pfc_reg_write(PFC_IPSR8,  0x11003301U);
+	pfc_reg_write(PFC_IPSR9,  0x11111111U);
+	pfc_reg_write(PFC_IPSR10, 0x00020000U);
+	pfc_reg_write(PFC_IPSR11, 0x40001110U);
+	pfc_reg_write(PFC_IPSR12, 0x00000000U);
+	pfc_reg_write(PFC_IPSR13, 0x00000000U);
+
+	/* initialize GPIO/perihperal function select */
+	pfc_reg_write(PFC_GPSR0, 0x0000001FU);
+	pfc_reg_write(PFC_GPSR1, 0x3FFFFFFFU);
+	pfc_reg_write(PFC_GPSR2, 0xFFFFFFFFU);
+	pfc_reg_write(PFC_GPSR3, 0x000003FFU);
+	pfc_reg_write(PFC_GPSR4, 0xFC7F0F7EU);
+	pfc_reg_write(PFC_GPSR5, 0x001BFFFBU);
+	pfc_reg_write(PFC_GPSR6, 0x00003FFFU);
+
+	/* initialize POC control register */
+	pfc_reg_write(PFC_POCCTRL0,   0xC00FFFFFU);
+	pfc_reg_write(PFC_POCCTRL2,   0XFFFFFFFEU);
+	pfc_reg_write(PFC_TDSELCTRL0, 0x00000000U);
+
+	/* initialize LSI pin pull-up/down control */
+	pfc_reg_write(PFC_PUD0, 0x0047C1A2U);
+	pfc_reg_write(PFC_PUD1, 0x4E13ABFFU);
+	pfc_reg_write(PFC_PUD2, 0xFFFFFFFFU);
+	pfc_reg_write(PFC_PUD3, 0xFF0FFFFFU);
+	pfc_reg_write(PFC_PUD4, 0xE0000000U);
+	pfc_reg_write(PFC_PUD5, 0x60000000U);
+
+	/* initialize LSI pin pull-enable register */
+	pfc_reg_write(PFC_PUEN0, 0x00000000U);
+	pfc_reg_write(PFC_PUEN1, 0x00000000U);
+	pfc_reg_write(PFC_PUEN2, 0x00000000U);
+	pfc_reg_write(PFC_PUEN3, 0x000F008CU);
+	pfc_reg_write(PFC_PUEN4, 0x00000000U);
+	pfc_reg_write(PFC_PUEN5, 0x00000000U);
+
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG6, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL6, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT0, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT1, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000400U);
+	mmio_write_32(GPIO_OUTDT3, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT4, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00000006U);
+	mmio_write_32(GPIO_OUTDT6, 0x00003880U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00802000U);
+	mmio_write_32(GPIO_INOUTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL6, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h
new file mode 100644
index 0000000..b7b1754
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_D3_H
+#define PFC_INIT_D3_H
+
+void pfc_init_d3(void);
+
+#endif	/* PFC_INIT_D3_H */
diff --git a/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c
new file mode 100644
index 0000000..bd0048e
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>		/* for uint32_t */
+#include <lib/mmio.h>
+#include "pfc_init_e3.h"
+#include "rcar_def.h"
+#include "../pfc_regs.h"
+
+/* PFC */
+#define GPSR0_SDA4		BIT(17)
+#define GPSR0_SCL4		BIT(16)
+#define GPSR0_D15		BIT(15)
+#define GPSR0_D14		BIT(14)
+#define GPSR0_D13		BIT(13)
+#define GPSR0_D12		BIT(12)
+#define GPSR0_D11		BIT(11)
+#define GPSR0_D10		BIT(10)
+#define GPSR0_D9		BIT(9)
+#define GPSR0_D8		BIT(8)
+#define GPSR0_D7		BIT(7)
+#define GPSR0_D6		BIT(6)
+#define GPSR0_D5		BIT(5)
+#define GPSR0_D4		BIT(4)
+#define GPSR0_D3		BIT(3)
+#define GPSR0_D2		BIT(2)
+#define GPSR0_D1		BIT(1)
+#define GPSR0_D0		BIT(0)
+#define GPSR1_WE0		BIT(22)
+#define GPSR1_CS0		BIT(21)
+#define GPSR1_CLKOUT		BIT(20)
+#define GPSR1_A19		BIT(19)
+#define GPSR1_A18		BIT(18)
+#define GPSR1_A17		BIT(17)
+#define GPSR1_A16		BIT(16)
+#define GPSR1_A15		BIT(15)
+#define GPSR1_A14		BIT(14)
+#define GPSR1_A13		BIT(13)
+#define GPSR1_A12		BIT(12)
+#define GPSR1_A11		BIT(11)
+#define GPSR1_A10		BIT(10)
+#define GPSR1_A9		BIT(9)
+#define GPSR1_A8		BIT(8)
+#define GPSR1_A7		BIT(7)
+#define GPSR1_A6		BIT(6)
+#define GPSR1_A5		BIT(5)
+#define GPSR1_A4		BIT(4)
+#define GPSR1_A3		BIT(3)
+#define GPSR1_A2		BIT(2)
+#define GPSR1_A1		BIT(1)
+#define GPSR1_A0		BIT(0)
+#define GPSR2_BIT27_REVERSED	BIT(27)
+#define GPSR2_BIT26_REVERSED	BIT(26)
+#define GPSR2_EX_WAIT0		BIT(25)
+#define GPSR2_RD_WR		BIT(24)
+#define GPSR2_RD		BIT(23)
+#define GPSR2_BS		BIT(22)
+#define GPSR2_AVB_PHY_INT	BIT(21)
+#define GPSR2_AVB_TXCREFCLK	BIT(20)
+#define GPSR2_AVB_RD3		BIT(19)
+#define GPSR2_AVB_RD2		BIT(18)
+#define GPSR2_AVB_RD1		BIT(17)
+#define GPSR2_AVB_RD0		BIT(16)
+#define GPSR2_AVB_RXC		BIT(15)
+#define GPSR2_AVB_RX_CTL	BIT(14)
+#define GPSR2_RPC_RESET		BIT(13)
+#define GPSR2_RPC_RPC_INT	BIT(12)
+#define GPSR2_QSPI1_SSL		BIT(11)
+#define GPSR2_QSPI1_IO3		BIT(10)
+#define GPSR2_QSPI1_IO2		BIT(9)
+#define GPSR2_QSPI1_MISO_IO1	BIT(8)
+#define GPSR2_QSPI1_MOSI_IO0	BIT(7)
+#define GPSR2_QSPI1_SPCLK	BIT(6)
+#define GPSR2_QSPI0_SSL		BIT(5)
+#define GPSR2_QSPI0_IO3		BIT(4)
+#define GPSR2_QSPI0_IO2		BIT(3)
+#define GPSR2_QSPI0_MISO_IO1	BIT(2)
+#define GPSR2_QSPI0_MOSI_IO0	BIT(1)
+#define GPSR2_QSPI0_SPCLK	BIT(0)
+#define GPSR3_SD1_WP		BIT(15)
+#define GPSR3_SD1_CD		BIT(14)
+#define GPSR3_SD0_WP		BIT(13)
+#define GPSR3_SD0_CD		BIT(12)
+#define GPSR3_SD1_DAT3		BIT(11)
+#define GPSR3_SD1_DAT2		BIT(10)
+#define GPSR3_SD1_DAT1		BIT(9)
+#define GPSR3_SD1_DAT0		BIT(8)
+#define GPSR3_SD1_CMD		BIT(7)
+#define GPSR3_SD1_CLK		BIT(6)
+#define GPSR3_SD0_DAT3		BIT(5)
+#define GPSR3_SD0_DAT2		BIT(4)
+#define GPSR3_SD0_DAT1		BIT(3)
+#define GPSR3_SD0_DAT0		BIT(2)
+#define GPSR3_SD0_CMD		BIT(1)
+#define GPSR3_SD0_CLK		BIT(0)
+#define GPSR4_SD3_DS		BIT(10)
+#define GPSR4_SD3_DAT7		BIT(9)
+#define GPSR4_SD3_DAT6		BIT(8)
+#define GPSR4_SD3_DAT5		BIT(7)
+#define GPSR4_SD3_DAT4		BIT(6)
+#define GPSR4_SD3_DAT3		BIT(5)
+#define GPSR4_SD3_DAT2		BIT(4)
+#define GPSR4_SD3_DAT1		BIT(3)
+#define GPSR4_SD3_DAT0		BIT(2)
+#define GPSR4_SD3_CMD		BIT(1)
+#define GPSR4_SD3_CLK		BIT(0)
+#define GPSR5_MLB_DAT		BIT(19)
+#define GPSR5_MLB_SIG		BIT(18)
+#define GPSR5_MLB_CLK		BIT(17)
+#define GPSR5_SSI_SDATA9	BIT(16)
+#define GPSR5_MSIOF0_SS2	BIT(15)
+#define GPSR5_MSIOF0_SS1	BIT(14)
+#define GPSR5_MSIOF0_SYNC	BIT(13)
+#define GPSR5_MSIOF0_TXD	BIT(12)
+#define GPSR5_MSIOF0_RXD	BIT(11)
+#define GPSR5_MSIOF0_SCK	BIT(10)
+#define GPSR5_RX2_A		BIT(9)
+#define GPSR5_TX2_A		BIT(8)
+#define GPSR5_SCK2_A		BIT(7)
+#define GPSR5_TX1		BIT(6)
+#define GPSR5_RX1		BIT(5)
+#define GPSR5_RTS0_A		BIT(4)
+#define GPSR5_CTS0_A		BIT(3)
+#define GPSR5_TX0_A		BIT(2)
+#define GPSR5_RX0_A		BIT(1)
+#define GPSR5_SCK0_A		BIT(0)
+#define GPSR6_USB30_PWEN	BIT(17)
+#define GPSR6_SSI_SDATA6	BIT(16)
+#define GPSR6_SSI_WS6		BIT(15)
+#define GPSR6_SSI_SCK6		BIT(14)
+#define GPSR6_SSI_SDATA5	BIT(13)
+#define GPSR6_SSI_WS5		BIT(12)
+#define GPSR6_SSI_SCK5		BIT(11)
+#define GPSR6_SSI_SDATA4	BIT(10)
+#define GPSR6_USB30_OVC		BIT(9)
+#define GPSR6_AUDIO_CLKA	BIT(8)
+#define GPSR6_SSI_SDATA3	BIT(7)
+#define GPSR6_SSI_WS349		BIT(6)
+#define GPSR6_SSI_SCK349	BIT(5)
+#define GPSR6_SSI_SDATA2	BIT(4)
+#define GPSR6_SSI_SDATA1	BIT(3)
+#define GPSR6_SSI_SDATA0	BIT(2)
+#define GPSR6_SSI_WS01239	BIT(1)
+#define GPSR6_SSI_SCK01239	BIT(0)
+
+#define IPSR_28_FUNC(x)		((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)		((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)		((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)		((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)		((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)		((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)		((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)		((uint32_t)(x) << 0U)
+
+#define POCCTRL0_MASK		(0x0007F000U)
+#define POC_SD3_DS_33V		BIT(29)
+#define POC_SD3_DAT7_33V	BIT(28)
+#define POC_SD3_DAT6_33V	BIT(27)
+#define POC_SD3_DAT5_33V	BIT(26)
+#define POC_SD3_DAT4_33V	BIT(25)
+#define POC_SD3_DAT3_33V	BIT(24)
+#define POC_SD3_DAT2_33V	BIT(23)
+#define POC_SD3_DAT1_33V	BIT(22)
+#define POC_SD3_DAT0_33V	BIT(21)
+#define POC_SD3_CMD_33V		BIT(20)
+#define POC_SD3_CLK_33V		BIT(19)
+#define POC_SD1_DAT3_33V	BIT(11)
+#define POC_SD1_DAT2_33V	BIT(10)
+#define POC_SD1_DAT1_33V	BIT(9)
+#define POC_SD1_DAT0_33V	BIT(8)
+#define POC_SD1_CMD_33V		BIT(7)
+#define POC_SD1_CLK_33V		BIT(6)
+#define POC_SD0_DAT3_33V	BIT(5)
+#define POC_SD0_DAT2_33V	BIT(4)
+#define POC_SD0_DAT1_33V	BIT(3)
+#define POC_SD0_DAT0_33V	BIT(2)
+#define POC_SD0_CMD_33V		BIT(1)
+#define POC_SD0_CLK_33V		BIT(0)
+
+#define POCCTRL2_MASK		(0xFFFFFFFEU)
+#define POC2_VREF_33V		BIT(0)
+
+#define MOD_SEL0_ADGB_A		((uint32_t)0U << 29U)
+#define MOD_SEL0_ADGB_B		((uint32_t)1U << 29U)
+#define MOD_SEL0_ADGB_C		((uint32_t)2U << 29U)
+#define MOD_SEL0_DRIF0_A	((uint32_t)0U << 28U)
+#define MOD_SEL0_DRIF0_B	((uint32_t)1U << 28U)
+#define MOD_SEL0_FM_A		((uint32_t)0U << 26U)
+#define MOD_SEL0_FM_B		((uint32_t)1U << 26U)
+#define MOD_SEL0_FM_C		((uint32_t)2U << 26U)
+#define MOD_SEL0_FSO_A		((uint32_t)0U << 25U)
+#define MOD_SEL0_FSO_B		((uint32_t)1U << 25U)
+#define MOD_SEL0_HSCIF0_A	((uint32_t)0U << 24U)
+#define MOD_SEL0_HSCIF0_B	((uint32_t)1U << 24U)
+#define MOD_SEL0_HSCIF1_A	((uint32_t)0U << 23U)
+#define MOD_SEL0_HSCIF1_B	((uint32_t)1U << 23U)
+#define MOD_SEL0_HSCIF2_A	((uint32_t)0U << 22U)
+#define MOD_SEL0_HSCIF2_B	((uint32_t)1U << 22U)
+#define MOD_SEL0_I2C1_A		((uint32_t)0U << 20U)
+#define MOD_SEL0_I2C1_B		((uint32_t)1U << 20U)
+#define MOD_SEL0_I2C1_C		((uint32_t)2U << 20U)
+#define MOD_SEL0_I2C1_D		((uint32_t)3U << 20U)
+#define MOD_SEL0_I2C2_A		((uint32_t)0U << 17U)
+#define MOD_SEL0_I2C2_B		((uint32_t)1U << 17U)
+#define MOD_SEL0_I2C2_C		((uint32_t)2U << 17U)
+#define MOD_SEL0_I2C2_D		((uint32_t)3U << 17U)
+#define MOD_SEL0_I2C2_E		((uint32_t)4U << 17U)
+#define MOD_SEL0_NDFC_A		((uint32_t)0U << 16U)
+#define MOD_SEL0_NDFC_B		((uint32_t)1U << 16U)
+#define MOD_SEL0_PWM0_A		((uint32_t)0U << 15U)
+#define MOD_SEL0_PWM0_B		((uint32_t)1U << 15U)
+#define MOD_SEL0_PWM1_A		((uint32_t)0U << 14U)
+#define MOD_SEL0_PWM1_B		((uint32_t)1U << 14U)
+#define MOD_SEL0_PWM2_A		((uint32_t)0U << 12U)
+#define MOD_SEL0_PWM2_B		((uint32_t)1U << 12U)
+#define MOD_SEL0_PWM2_C		((uint32_t)2U << 12U)
+#define MOD_SEL0_PWM3_A		((uint32_t)0U << 10U)
+#define MOD_SEL0_PWM3_B		((uint32_t)1U << 10U)
+#define MOD_SEL0_PWM3_C		((uint32_t)2U << 10U)
+#define MOD_SEL0_PWM4_A		((uint32_t)0U << 9U)
+#define MOD_SEL0_PWM4_B		((uint32_t)1U << 9U)
+#define MOD_SEL0_PWM5_A		((uint32_t)0U << 8U)
+#define MOD_SEL0_PWM5_B		((uint32_t)1U << 8U)
+#define MOD_SEL0_PWM6_A		((uint32_t)0U << 7U)
+#define MOD_SEL0_PWM6_B		((uint32_t)1U << 7U)
+#define MOD_SEL0_REMOCON_A	((uint32_t)0U << 5U)
+#define MOD_SEL0_REMOCON_B	((uint32_t)1U << 5U)
+#define MOD_SEL0_REMOCON_C	((uint32_t)2U << 5U)
+#define MOD_SEL0_SCIF_A		((uint32_t)0U << 4U)
+#define MOD_SEL0_SCIF_B		((uint32_t)1U << 4U)
+#define MOD_SEL0_SCIF0_A	((uint32_t)0U << 3U)
+#define MOD_SEL0_SCIF0_B	((uint32_t)1U << 3U)
+#define MOD_SEL0_SCIF2_A	((uint32_t)0U << 2U)
+#define MOD_SEL0_SCIF2_B	((uint32_t)1U << 2U)
+#define MOD_SEL0_SPEED_PULSE_IF_A	((uint32_t)0U << 0U)
+#define MOD_SEL0_SPEED_PULSE_IF_B	((uint32_t)1U << 0U)
+#define MOD_SEL0_SPEED_PULSE_IF_C	((uint32_t)2U << 0U)
+#define MOD_SEL1_SIMCARD_A	((uint32_t)0U << 31U)
+#define MOD_SEL1_SIMCARD_B	((uint32_t)1U << 31U)
+#define MOD_SEL1_SSI2_A		((uint32_t)0U << 30U)
+#define MOD_SEL1_SSI2_B		((uint32_t)1U << 30U)
+#define MOD_SEL1_TIMER_TMU_A	((uint32_t)0U << 29U)
+#define MOD_SEL1_TIMER_TMU_B	((uint32_t)1U << 29U)
+#define MOD_SEL1_USB20_CH0_A	((uint32_t)0U << 28U)
+#define MOD_SEL1_USB20_CH0_B	((uint32_t)1U << 28U)
+#define MOD_SEL1_DRIF2_A	((uint32_t)0U << 26U)
+#define MOD_SEL1_DRIF2_B	((uint32_t)1U << 26U)
+#define MOD_SEL1_DRIF3_A	((uint32_t)0U << 25U)
+#define MOD_SEL1_DRIF3_B	((uint32_t)1U << 25U)
+#define MOD_SEL1_HSCIF3_A	((uint32_t)0U << 22U)
+#define MOD_SEL1_HSCIF3_B	((uint32_t)1U << 22U)
+#define MOD_SEL1_HSCIF3_C	((uint32_t)2U << 22U)
+#define MOD_SEL1_HSCIF3_D	((uint32_t)3U << 22U)
+#define MOD_SEL1_HSCIF3_E	((uint32_t)4U << 22U)
+#define MOD_SEL1_HSCIF4_A	((uint32_t)0U << 19U)
+#define MOD_SEL1_HSCIF4_B	((uint32_t)1U << 19U)
+#define MOD_SEL1_HSCIF4_C	((uint32_t)2U << 19U)
+#define MOD_SEL1_HSCIF4_D	((uint32_t)3U << 19U)
+#define MOD_SEL1_HSCIF4_E	((uint32_t)4U << 19U)
+#define MOD_SEL1_I2C6_A		((uint32_t)0U << 18U)
+#define MOD_SEL1_I2C6_B		((uint32_t)1U << 18U)
+#define MOD_SEL1_I2C7_A		((uint32_t)0U << 17U)
+#define MOD_SEL1_I2C7_B		((uint32_t)1U << 17U)
+#define MOD_SEL1_MSIOF2_A	((uint32_t)0U << 16U)
+#define MOD_SEL1_MSIOF2_B	((uint32_t)1U << 16U)
+#define MOD_SEL1_MSIOF3_A	((uint32_t)0U << 15U)
+#define MOD_SEL1_MSIOF3_B	((uint32_t)1U << 15U)
+#define MOD_SEL1_SCIF3_A	((uint32_t)0U << 13U)
+#define MOD_SEL1_SCIF3_B	((uint32_t)1U << 13U)
+#define MOD_SEL1_SCIF3_C	((uint32_t)2U << 13U)
+#define MOD_SEL1_SCIF4_A	((uint32_t)0U << 11U)
+#define MOD_SEL1_SCIF4_B	((uint32_t)1U << 11U)
+#define MOD_SEL1_SCIF4_C	((uint32_t)2U << 11U)
+#define MOD_SEL1_SCIF5_A	((uint32_t)0U << 9U)
+#define MOD_SEL1_SCIF5_B	((uint32_t)1U << 9U)
+#define MOD_SEL1_SCIF5_C	((uint32_t)2U << 9U)
+#define MOD_SEL1_VIN4_A		((uint32_t)0U << 8U)
+#define MOD_SEL1_VIN4_B		((uint32_t)1U << 8U)
+#define MOD_SEL1_VIN5_A		((uint32_t)0U << 7U)
+#define MOD_SEL1_VIN5_B		((uint32_t)1U << 7U)
+#define MOD_SEL1_ADGC_A		((uint32_t)0U << 5U)
+#define MOD_SEL1_ADGC_B		((uint32_t)1U << 5U)
+#define MOD_SEL1_ADGC_C		((uint32_t)2U << 5U)
+#define MOD_SEL1_SSI9_A		((uint32_t)0U << 4U)
+#define MOD_SEL1_SSI9_B		((uint32_t)1U << 4U)
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	mmio_write_32(PFC_PMMR, ~data);
+	mmio_write_32((uintptr_t)addr, data);
+}
+
+void pfc_init_e3(void)
+{
+	uint32_t reg;
+
+	/* initialize module select */
+	pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_ADGB_A
+		      | MOD_SEL0_DRIF0_A
+		      | MOD_SEL0_FM_A
+		      | MOD_SEL0_FSO_A
+		      | MOD_SEL0_HSCIF0_A
+		      | MOD_SEL0_HSCIF1_A
+		      | MOD_SEL0_HSCIF2_A
+		      | MOD_SEL0_I2C1_A
+		      | MOD_SEL0_I2C2_A
+		      | MOD_SEL0_NDFC_A
+		      | MOD_SEL0_PWM0_A
+		      | MOD_SEL0_PWM1_A
+		      | MOD_SEL0_PWM2_A
+		      | MOD_SEL0_PWM3_A
+		      | MOD_SEL0_PWM4_A
+		      | MOD_SEL0_PWM5_A
+		      | MOD_SEL0_PWM6_A
+		      | MOD_SEL0_REMOCON_A
+		      | MOD_SEL0_SCIF_A
+		      | MOD_SEL0_SCIF0_A
+		      | MOD_SEL0_SCIF2_A
+		      | MOD_SEL0_SPEED_PULSE_IF_A);
+	pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_SIMCARD_A
+		      | MOD_SEL1_SSI2_A
+		      | MOD_SEL1_TIMER_TMU_A
+		      | MOD_SEL1_USB20_CH0_B
+		      | MOD_SEL1_DRIF2_A
+		      | MOD_SEL1_DRIF3_A
+		      | MOD_SEL1_HSCIF3_A
+		      | MOD_SEL1_HSCIF4_A
+		      | MOD_SEL1_I2C6_A
+		      | MOD_SEL1_I2C7_A
+		      | MOD_SEL1_MSIOF2_A
+		      | MOD_SEL1_MSIOF3_A
+		      | MOD_SEL1_SCIF3_A
+		      | MOD_SEL1_SCIF4_A
+		      | MOD_SEL1_SCIF5_A
+		      | MOD_SEL1_VIN4_A
+		      | MOD_SEL1_VIN5_A
+		      | MOD_SEL1_ADGC_A
+		      | MOD_SEL1_SSI9_A);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0)	/* QSPI1_MISO/IO1 */
+		      | IPSR_24_FUNC(0)	/* QSPI1_MOSI/IO0 */
+		      | IPSR_20_FUNC(0)	/* QSPI1_SPCLK */
+		      | IPSR_16_FUNC(0)	/* QSPI0_IO3 */
+		      | IPSR_12_FUNC(0)	/* QSPI0_IO2 */
+		      | IPSR_8_FUNC(0)	/* QSPI0_MISO/IO1 */
+		      | IPSR_4_FUNC(0)	/* QSPI0_MOSI/IO0 */
+		      | IPSR_0_FUNC(0));	/* QSPI0_SPCLK */
+	pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(0)	/* AVB_RD2 */
+		      | IPSR_24_FUNC(0)	/* AVB_RD1 */
+		      | IPSR_20_FUNC(0)	/* AVB_RD0 */
+		      | IPSR_16_FUNC(0)	/* RPC_RESET# */
+		      | IPSR_12_FUNC(0)	/* RPC_INT# */
+		      | IPSR_8_FUNC(0)	/* QSPI1_SSL */
+		      | IPSR_4_FUNC(0)	/* QSPI1_IO3 */
+		      | IPSR_0_FUNC(0));	/* QSPI1_IO2 */
+	pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(1)	/* IRQ0 */
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(2)	/* AVB_LINK */
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)	/* AVB_MDC */
+		      | IPSR_4_FUNC(0)	/* AVB_MDIO */
+		      | IPSR_0_FUNC(0));	/* AVB_TXCREFCLK */
+	pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(5)	/* DU_HSYNC */
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(5)	/* DU_DG4 */
+		      | IPSR_8_FUNC(5)	/* DU_DOTCLKOUT0 */
+		      | IPSR_4_FUNC(5)	/* DU_DISP */
+		      | IPSR_0_FUNC(1));	/* IRQ1 */
+	pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(5)	/* DU_DB5 */
+		      | IPSR_24_FUNC(5)	/* DU_DB4 */
+		      | IPSR_20_FUNC(5)	/* DU_DB3 */
+		      | IPSR_16_FUNC(5)	/* DU_DB2 */
+		      | IPSR_12_FUNC(5)	/* DU_DG6 */
+		      | IPSR_8_FUNC(5)	/* DU_VSYNC */
+		      | IPSR_4_FUNC(5)	/* DU_DG5 */
+		      | IPSR_0_FUNC(5));	/* DU_DG7 */
+	pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(5)	/* DU_DR3 */
+		      | IPSR_24_FUNC(5)	/* DU_DB7 */
+		      | IPSR_20_FUNC(5)	/* DU_DR2 */
+		      | IPSR_16_FUNC(5)	/* DU_DR1 */
+		      | IPSR_12_FUNC(5)	/* DU_DR0 */
+		      | IPSR_8_FUNC(5)	/* DU_DB1 */
+		      | IPSR_4_FUNC(5)	/* DU_DB0 */
+		      | IPSR_0_FUNC(5));	/* DU_DB6 */
+	pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(5)	/* DU_DG1 */
+		      | IPSR_24_FUNC(5)	/* DU_DG0 */
+		      | IPSR_20_FUNC(5)	/* DU_DR7 */
+		      | IPSR_16_FUNC(2)	/* IRQ5 */
+		      | IPSR_12_FUNC(5)	/* DU_DR6 */
+		      | IPSR_8_FUNC(5)	/* DU_DR5 */
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(5));	/* DU_DR4 */
+	pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0)	/* SD0_CLK */
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(5)	/* DU_DOTCLKIN0 */
+		      | IPSR_16_FUNC(5)	/* DU_DG3 */
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(5));	/* DU_DG2 */
+	pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(0)	/* SD1_DAT0 */
+		      | IPSR_24_FUNC(0)	/* SD1_CMD */
+		      | IPSR_20_FUNC(0)	/* SD1_CLK */
+		      | IPSR_16_FUNC(0)	/* SD0_DAT3 */
+		      | IPSR_12_FUNC(0)	/* SD0_DAT2 */
+		      | IPSR_8_FUNC(0)	/* SD0_DAT1 */
+		      | IPSR_4_FUNC(0)	/* SD0_DAT0 */
+		      | IPSR_0_FUNC(0));	/* SD0_CMD */
+	pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0)	/* SD3_DAT2 */
+		      | IPSR_24_FUNC(0)	/* SD3_DAT1 */
+		      | IPSR_20_FUNC(0)	/* SD3_DAT0 */
+		      | IPSR_16_FUNC(0)	/* SD3_CMD */
+		      | IPSR_12_FUNC(0)	/* SD3_CLK */
+		      | IPSR_8_FUNC(0)	/* SD1_DAT3 */
+		      | IPSR_4_FUNC(0)	/* SD1_DAT2 */
+		      | IPSR_0_FUNC(0));	/* SD1_DAT1 */
+	pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(0)	/* SD0_WP */
+		      | IPSR_24_FUNC(0)	/* SD0_CD */
+		      | IPSR_20_FUNC(0)	/* SD3_DS */
+		      | IPSR_16_FUNC(0)	/* SD3_DAT7 */
+		      | IPSR_12_FUNC(0)	/* SD3_DAT6 */
+		      | IPSR_8_FUNC(0)	/* SD3_DAT5 */
+		      | IPSR_4_FUNC(0)	/* SD3_DAT4 */
+		      | IPSR_0_FUNC(0));	/* SD3_DAT3 */
+	pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(2)	/* AUDIO_CLKOUT1_A */
+		      | IPSR_16_FUNC(2)	/* AUDIO_CLKOUT_A */
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)	/* SD1_WP */
+		      | IPSR_0_FUNC(0));	/* SD1_CD */
+	pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)	/* RX2_A */
+		      | IPSR_8_FUNC(0)	/* TX2_A */
+		      | IPSR_4_FUNC(2)	/* AUDIO_CLKB_A */
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(2)	/* AUDIO_CLKC_A */
+		      | IPSR_4_FUNC(1)	/* HTX2_A */
+		      | IPSR_0_FUNC(1));	/* HRX2_A */
+	pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(3)	/* USB0_PWEN_B */
+		      | IPSR_24_FUNC(0)	/* SSI_SDATA4 */
+		      | IPSR_20_FUNC(0)	/* SSI_SDATA3 */
+		      | IPSR_16_FUNC(0)	/* SSI_WS349 */
+		      | IPSR_12_FUNC(0)	/* SSI_SCK349 */
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)	/* SSI_SDATA1 */
+		      | IPSR_0_FUNC(0));	/* SSI_SDATA0 */
+	pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0)	/* USB30_OVC */
+		      | IPSR_24_FUNC(0)	/* USB30_PWEN */
+		      | IPSR_20_FUNC(0)	/* AUDIO_CLKA */
+		      | IPSR_16_FUNC(1)	/* HRTS2#_A */
+		      | IPSR_12_FUNC(1)	/* HCTS2#_A */
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(3));	/* USB0_OVC_B */
+
+	/* initialize GPIO/perihperal function select */
+	pfc_reg_write(PFC_GPSR0, GPSR0_SCL4
+		      | GPSR0_D15
+		      | GPSR0_D11
+		      | GPSR0_D10
+		      | GPSR0_D9
+		      | GPSR0_D8
+		      | GPSR0_D7
+		      | GPSR0_D6
+		      | GPSR0_D5
+		      | GPSR0_D3
+		      | GPSR0_D2
+		      | GPSR0_D1
+		      | GPSR0_D0);
+	pfc_reg_write(PFC_GPSR1, GPSR1_WE0
+		      | GPSR1_CS0
+		      | GPSR1_A19
+		      | GPSR1_A18
+		      | GPSR1_A17
+		      | GPSR1_A16
+		      | GPSR1_A15
+		      | GPSR1_A14
+		      | GPSR1_A13
+		      | GPSR1_A12
+		      | GPSR1_A11
+		      | GPSR1_A10
+		      | GPSR1_A9
+		      | GPSR1_A8
+		      | GPSR1_A4
+		      | GPSR1_A3
+		      | GPSR1_A2
+		      | GPSR1_A1
+		      | GPSR1_A0);
+	pfc_reg_write(PFC_GPSR2, GPSR2_BIT27_REVERSED
+		      | GPSR2_BIT26_REVERSED
+		      | GPSR2_RD
+		      | GPSR2_AVB_PHY_INT
+		      | GPSR2_AVB_TXCREFCLK
+		      | GPSR2_AVB_RD3
+		      | GPSR2_AVB_RD2
+		      | GPSR2_AVB_RD1
+		      | GPSR2_AVB_RD0
+		      | GPSR2_AVB_RXC
+		      | GPSR2_AVB_RX_CTL
+		      | GPSR2_RPC_RESET
+		      | GPSR2_RPC_RPC_INT
+		      | GPSR2_QSPI1_SSL
+		      | GPSR2_QSPI1_IO3
+		      | GPSR2_QSPI1_IO2
+		      | GPSR2_QSPI1_MISO_IO1
+		      | GPSR2_QSPI1_MOSI_IO0
+		      | GPSR2_QSPI1_SPCLK
+		      | GPSR2_QSPI0_SSL
+		      | GPSR2_QSPI0_IO3
+		      | GPSR2_QSPI0_IO2
+		      | GPSR2_QSPI0_MISO_IO1
+		      | GPSR2_QSPI0_MOSI_IO0
+		      | GPSR2_QSPI0_SPCLK);
+	pfc_reg_write(PFC_GPSR3, GPSR3_SD1_WP
+		      | GPSR3_SD1_CD
+		      | GPSR3_SD0_WP
+		      | GPSR3_SD0_CD
+		      | GPSR3_SD1_DAT3
+		      | GPSR3_SD1_DAT2
+		      | GPSR3_SD1_DAT1
+		      | GPSR3_SD1_DAT0
+		      | GPSR3_SD1_CMD
+		      | GPSR3_SD1_CLK
+		      | GPSR3_SD0_DAT3
+		      | GPSR3_SD0_DAT2
+		      | GPSR3_SD0_DAT1
+		      | GPSR3_SD0_DAT0
+		      | GPSR3_SD0_CMD
+		      | GPSR3_SD0_CLK);
+	pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DS
+		      | GPSR4_SD3_DAT7
+		      | GPSR4_SD3_DAT6
+		      | GPSR4_SD3_DAT5
+		      | GPSR4_SD3_DAT4
+		      | GPSR4_SD3_DAT3
+		      | GPSR4_SD3_DAT2
+		      | GPSR4_SD3_DAT1
+		      | GPSR4_SD3_DAT0
+		      | GPSR4_SD3_CMD
+		      | GPSR4_SD3_CLK);
+	pfc_reg_write(PFC_GPSR5, GPSR5_SSI_SDATA9
+		      | GPSR5_MSIOF0_SS2
+		      | GPSR5_MSIOF0_SS1
+		      | GPSR5_RX2_A
+		      | GPSR5_TX2_A
+		      | GPSR5_SCK2_A
+		      | GPSR5_RTS0_A
+		      | GPSR5_CTS0_A);
+	pfc_reg_write(PFC_GPSR6, GPSR6_USB30_PWEN
+		      | GPSR6_SSI_SDATA6
+		      | GPSR6_SSI_WS6
+		      | GPSR6_SSI_WS5
+		      | GPSR6_SSI_SCK5
+		      | GPSR6_SSI_SDATA4
+		      | GPSR6_USB30_OVC
+		      | GPSR6_AUDIO_CLKA
+		      | GPSR6_SSI_SDATA3
+		      | GPSR6_SSI_WS349
+		      | GPSR6_SSI_SCK349
+		      | GPSR6_SSI_SDATA1
+		      | GPSR6_SSI_SDATA0
+		      | GPSR6_SSI_WS01239
+		      | GPSR6_SSI_SCK01239);
+
+	/* initialize POC control */
+	reg = mmio_read_32(PFC_POCCTRL0);
+	reg = ((reg & POCCTRL0_MASK) | POC_SD1_DAT3_33V
+	       | POC_SD1_DAT2_33V
+	       | POC_SD1_DAT1_33V
+	       | POC_SD1_DAT0_33V
+	       | POC_SD1_CMD_33V
+	       | POC_SD1_CLK_33V
+	       | POC_SD0_DAT3_33V
+	       | POC_SD0_DAT2_33V
+	       | POC_SD0_DAT1_33V
+	       | POC_SD0_DAT0_33V
+	       | POC_SD0_CMD_33V
+	       | POC_SD0_CLK_33V);
+	pfc_reg_write(PFC_POCCTRL0, reg);
+	reg = mmio_read_32(PFC_POCCTRL2);
+	reg = (reg & POCCTRL2_MASK);
+	pfc_reg_write(PFC_POCCTRL2, reg);
+
+	/* initialize LSI pin pull-up/down control */
+	pfc_reg_write(PFC_PUD0, 0xFDF80000U);
+	pfc_reg_write(PFC_PUD1, 0xCE298464U);
+	pfc_reg_write(PFC_PUD2, 0xA4C380F4U);
+	pfc_reg_write(PFC_PUD3, 0x0000079FU);
+	pfc_reg_write(PFC_PUD4, 0xFFF0FFFFU);
+	pfc_reg_write(PFC_PUD5, 0x40000000U);
+
+	/* initialize LSI pin pull-enable register */
+	pfc_reg_write(PFC_PUEN0, 0xFFF00000U);
+	pfc_reg_write(PFC_PUEN1, 0x00000000U);
+	pfc_reg_write(PFC_PUEN2, 0x00000004U);
+	pfc_reg_write(PFC_PUEN3, 0x00000000U);
+	pfc_reg_write(PFC_PUEN4, 0x07800010U);
+	pfc_reg_write(PFC_PUEN5, 0x00000000U);
+
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG6, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00020000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL6, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT0, 0x00000010U);
+	mmio_write_32(GPIO_OUTDT1, 0x00100000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT3, 0x00008000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00060000U);
+	mmio_write_32(GPIO_OUTDT6, 0x00000000U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000010U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x00100020U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x03000000U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x00008000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL5, 0x00060000U);
+	mmio_write_32(GPIO_INOUTSEL6, 0x00004000U);
+}
diff --git a/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h
new file mode 100644
index 0000000..647a937
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_E3_H
+#define PFC_INIT_E3_H
+
+void pfc_init_e3(void);
+
+#endif /* PFC_INIT_E3_H */
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
new file mode 100644
index 0000000..effdc76
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
@@ -0,0 +1,1183 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <lib/mmio.h>
+#include "rcar_def.h"
+#include "../pfc_regs.h"
+
+#define GPSR0_D15		BIT(15)
+#define GPSR0_D14		BIT(14)
+#define GPSR0_D13		BIT(13)
+#define GPSR0_D12		BIT(12)
+#define GPSR0_D11		BIT(11)
+#define GPSR0_D10		BIT(10)
+#define GPSR0_D9		BIT(9)
+#define GPSR0_D8		BIT(8)
+#define GPSR0_D7		BIT(7)
+#define GPSR0_D6		BIT(6)
+#define GPSR0_D5		BIT(5)
+#define GPSR0_D4		BIT(4)
+#define GPSR0_D3		BIT(3)
+#define GPSR0_D2		BIT(2)
+#define GPSR0_D1		BIT(1)
+#define GPSR0_D0		BIT(0)
+#define GPSR1_EX_WAIT0_A	BIT(27)
+#define GPSR1_WE1		BIT(26)
+#define GPSR1_WE0		BIT(25)
+#define GPSR1_RD_WR		BIT(24)
+#define GPSR1_RD		BIT(23)
+#define GPSR1_BS		BIT(22)
+#define GPSR1_CS1_A26		BIT(21)
+#define GPSR1_CS0		BIT(20)
+#define GPSR1_A19		BIT(19)
+#define GPSR1_A18		BIT(18)
+#define GPSR1_A17		BIT(17)
+#define GPSR1_A16		BIT(16)
+#define GPSR1_A15		BIT(15)
+#define GPSR1_A14		BIT(14)
+#define GPSR1_A13		BIT(13)
+#define GPSR1_A12		BIT(12)
+#define GPSR1_A11		BIT(11)
+#define GPSR1_A10		BIT(10)
+#define GPSR1_A9		BIT(9)
+#define GPSR1_A8		BIT(8)
+#define GPSR1_A7		BIT(7)
+#define GPSR1_A6		BIT(6)
+#define GPSR1_A5		BIT(5)
+#define GPSR1_A4		BIT(4)
+#define GPSR1_A3		BIT(3)
+#define GPSR1_A2		BIT(2)
+#define GPSR1_A1		BIT(1)
+#define GPSR1_A0		BIT(0)
+#define GPSR2_AVB_AVTP_CAPTURE_A	BIT(14)
+#define GPSR2_AVB_AVTP_MATCH_A	BIT(13)
+#define GPSR2_AVB_LINK		BIT(12)
+#define GPSR2_AVB_PHY_INT	BIT(11)
+#define GPSR2_AVB_MAGIC		BIT(10)
+#define GPSR2_AVB_MDC		BIT(9)
+#define GPSR2_PWM2_A		BIT(8)
+#define GPSR2_PWM1_A		BIT(7)
+#define GPSR2_PWM0		BIT(6)
+#define GPSR2_IRQ5		BIT(5)
+#define GPSR2_IRQ4		BIT(4)
+#define GPSR2_IRQ3		BIT(3)
+#define GPSR2_IRQ2		BIT(2)
+#define GPSR2_IRQ1		BIT(1)
+#define GPSR2_IRQ0		BIT(0)
+#define GPSR3_SD1_WP		BIT(15)
+#define GPSR3_SD1_CD		BIT(14)
+#define GPSR3_SD0_WP		BIT(13)
+#define GPSR3_SD0_CD		BIT(12)
+#define GPSR3_SD1_DAT3		BIT(11)
+#define GPSR3_SD1_DAT2		BIT(10)
+#define GPSR3_SD1_DAT1		BIT(9)
+#define GPSR3_SD1_DAT0		BIT(8)
+#define GPSR3_SD1_CMD		BIT(7)
+#define GPSR3_SD1_CLK		BIT(6)
+#define GPSR3_SD0_DAT3		BIT(5)
+#define GPSR3_SD0_DAT2		BIT(4)
+#define GPSR3_SD0_DAT1		BIT(3)
+#define GPSR3_SD0_DAT0		BIT(2)
+#define GPSR3_SD0_CMD		BIT(1)
+#define GPSR3_SD0_CLK		BIT(0)
+#define GPSR4_SD3_DS		BIT(17)
+#define GPSR4_SD3_DAT7		BIT(16)
+#define GPSR4_SD3_DAT6		BIT(15)
+#define GPSR4_SD3_DAT5		BIT(14)
+#define GPSR4_SD3_DAT4		BIT(13)
+#define GPSR4_SD3_DAT3		BIT(12)
+#define GPSR4_SD3_DAT2		BIT(11)
+#define GPSR4_SD3_DAT1		BIT(10)
+#define GPSR4_SD3_DAT0		BIT(9)
+#define GPSR4_SD3_CMD		BIT(8)
+#define GPSR4_SD3_CLK		BIT(7)
+#define GPSR4_SD2_DS		BIT(6)
+#define GPSR4_SD2_DAT3		BIT(5)
+#define GPSR4_SD2_DAT2		BIT(4)
+#define GPSR4_SD2_DAT1		BIT(3)
+#define GPSR4_SD2_DAT0		BIT(2)
+#define GPSR4_SD2_CMD		BIT(1)
+#define GPSR4_SD2_CLK		BIT(0)
+#define GPSR5_MLB_DAT		BIT(25)
+#define GPSR5_MLB_SIG		BIT(24)
+#define GPSR5_MLB_CLK		BIT(23)
+#define GPSR5_MSIOF0_RXD	BIT(22)
+#define GPSR5_MSIOF0_SS2	BIT(21)
+#define GPSR5_MSIOF0_TXD	BIT(20)
+#define GPSR5_MSIOF0_SS1	BIT(19)
+#define GPSR5_MSIOF0_SYNC	BIT(18)
+#define GPSR5_MSIOF0_SCK	BIT(17)
+#define GPSR5_HRTS0		BIT(16)
+#define GPSR5_HCTS0		BIT(15)
+#define GPSR5_HTX0		BIT(14)
+#define GPSR5_HRX0		BIT(13)
+#define GPSR5_HSCK0		BIT(12)
+#define GPSR5_RX2_A		BIT(11)
+#define GPSR5_TX2_A		BIT(10)
+#define GPSR5_SCK2		BIT(9)
+#define GPSR5_RTS1		BIT(8)
+#define GPSR5_CTS1		BIT(7)
+#define GPSR5_TX1_A		BIT(6)
+#define GPSR5_RX1_A		BIT(5)
+#define GPSR5_RTS0		BIT(4)
+#define GPSR5_CTS0		BIT(3)
+#define GPSR5_TX0		BIT(2)
+#define GPSR5_RX0		BIT(1)
+#define GPSR5_SCK0		BIT(0)
+#define GPSR6_USB31_OVC		BIT(31)
+#define GPSR6_USB31_PWEN	BIT(30)
+#define GPSR6_USB30_OVC		BIT(29)
+#define GPSR6_USB30_PWEN	BIT(28)
+#define GPSR6_USB1_OVC		BIT(27)
+#define GPSR6_USB1_PWEN		BIT(26)
+#define GPSR6_USB0_OVC		BIT(25)
+#define GPSR6_USB0_PWEN		BIT(24)
+#define GPSR6_AUDIO_CLKB_B	BIT(23)
+#define GPSR6_AUDIO_CLKA_A	BIT(22)
+#define GPSR6_SSI_SDATA9_A	BIT(21)
+#define GPSR6_SSI_SDATA8	BIT(20)
+#define GPSR6_SSI_SDATA7	BIT(19)
+#define GPSR6_SSI_WS78		BIT(18)
+#define GPSR6_SSI_SCK78		BIT(17)
+#define GPSR6_SSI_SDATA6	BIT(16)
+#define GPSR6_SSI_WS6		BIT(15)
+#define GPSR6_SSI_SCK6		BIT(14)
+#define GPSR6_SSI_SDATA5	BIT(13)
+#define GPSR6_SSI_WS5		BIT(12)
+#define GPSR6_SSI_SCK5		BIT(11)
+#define GPSR6_SSI_SDATA4	BIT(10)
+#define GPSR6_SSI_WS4		BIT(9)
+#define GPSR6_SSI_SCK4		BIT(8)
+#define GPSR6_SSI_SDATA3	BIT(7)
+#define GPSR6_SSI_WS34		BIT(6)
+#define GPSR6_SSI_SCK34		BIT(5)
+#define GPSR6_SSI_SDATA2_A	BIT(4)
+#define GPSR6_SSI_SDATA1_A	BIT(3)
+#define GPSR6_SSI_SDATA0	BIT(2)
+#define GPSR6_SSI_WS0129	BIT(1)
+#define GPSR6_SSI_SCK0129	BIT(0)
+#define GPSR7_AVS2		BIT(1)
+#define GPSR7_AVS1		BIT(0)
+
+#define IPSR_28_FUNC(x)		((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)		((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)		((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)		((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)		((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)		((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)		((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)		((uint32_t)(x) << 0U)
+
+#define POC_SD3_DS_33V		BIT(29)
+#define POC_SD3_DAT7_33V	BIT(28)
+#define POC_SD3_DAT6_33V	BIT(27)
+#define POC_SD3_DAT5_33V	BIT(26)
+#define POC_SD3_DAT4_33V	BIT(25)
+#define POC_SD3_DAT3_33V	BIT(24)
+#define POC_SD3_DAT2_33V	BIT(23)
+#define POC_SD3_DAT1_33V	BIT(22)
+#define POC_SD3_DAT0_33V	BIT(21)
+#define POC_SD3_CMD_33V		BIT(20)
+#define POC_SD3_CLK_33V		BIT(19)
+#define POC_SD2_DS_33V		BIT(18)
+#define POC_SD2_DAT3_33V	BIT(17)
+#define POC_SD2_DAT2_33V	BIT(16)
+#define POC_SD2_DAT1_33V	BIT(15)
+#define POC_SD2_DAT0_33V	BIT(14)
+#define POC_SD2_CMD_33V		BIT(13)
+#define POC_SD2_CLK_33V		BIT(12)
+#define POC_SD1_DAT3_33V	BIT(11)
+#define POC_SD1_DAT2_33V	BIT(10)
+#define POC_SD1_DAT1_33V	BIT(9)
+#define POC_SD1_DAT0_33V	BIT(8)
+#define POC_SD1_CMD_33V		BIT(7)
+#define POC_SD1_CLK_33V		BIT(6)
+#define POC_SD0_DAT3_33V	BIT(5)
+#define POC_SD0_DAT2_33V	BIT(4)
+#define POC_SD0_DAT1_33V	BIT(3)
+#define POC_SD0_DAT0_33V	BIT(2)
+#define POC_SD0_CMD_33V		BIT(1)
+#define POC_SD0_CLK_33V		BIT(0)
+
+#define DRVCTRL0_MASK		(0xCCCCCCCCU)
+#define DRVCTRL1_MASK		(0xCCCCCCC8U)
+#define DRVCTRL2_MASK		(0x88888888U)
+#define DRVCTRL3_MASK		(0x88888888U)
+#define DRVCTRL4_MASK		(0x88888888U)
+#define DRVCTRL5_MASK		(0x88888888U)
+#define DRVCTRL6_MASK		(0x88888888U)
+#define DRVCTRL7_MASK		(0x88888888U)
+#define DRVCTRL8_MASK		(0x88888888U)
+#define DRVCTRL9_MASK		(0x88888888U)
+#define DRVCTRL10_MASK		(0x88888888U)
+#define DRVCTRL11_MASK		(0x888888CCU)
+#define DRVCTRL12_MASK		(0xCCCFFFCFU)
+#define DRVCTRL13_MASK		(0xCC888888U)
+#define DRVCTRL14_MASK		(0x88888888U)
+#define DRVCTRL15_MASK		(0x88888888U)
+#define DRVCTRL16_MASK		(0x88888888U)
+#define DRVCTRL17_MASK		(0x88888888U)
+#define DRVCTRL18_MASK		(0x88888888U)
+#define DRVCTRL19_MASK		(0x88888888U)
+#define DRVCTRL20_MASK		(0x88888888U)
+#define DRVCTRL21_MASK		(0x88888888U)
+#define DRVCTRL22_MASK		(0x88888888U)
+#define DRVCTRL23_MASK		(0x88888888U)
+#define DRVCTRL24_MASK		(0x8888888FU)
+
+#define DRVCTRL0_QSPI0_SPCLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL0_QSPI0_MOSI_IO0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL0_QSPI0_MISO_IO1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL0_QSPI0_IO2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL0_QSPI0_IO3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL0_QSPI0_SSL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL0_QSPI1_SPCLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL0_QSPI1_MOSI_IO0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL1_QSPI1_MISO_IO1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL1_QSPI1_IO2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL1_QSPI1_IO3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL1_QSPI1_SS(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL1_RPC_INT(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL1_RPC_WP(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL1_RPC_RESET(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL1_AVB_RX_CTL(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL2_AVB_RXC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL2_AVB_RD0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL2_AVB_RD1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL2_AVB_RD2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL2_AVB_RD3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL2_AVB_TX_CTL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL2_AVB_TXC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL2_AVB_TD0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL3_AVB_TD1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL3_AVB_TD2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL3_AVB_TD3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL3_AVB_TXCREFCLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL3_AVB_MDIO(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL3_AVB_MDC(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL3_AVB_MAGIC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL3_AVB_PHY_INT(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL4_AVB_LINK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL4_AVB_AVTP_MATCH(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL4_AVB_AVTP_CAPTURE(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL4_IRQ0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL4_IRQ1(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL4_IRQ2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL4_IRQ3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL4_IRQ4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL5_IRQ5(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL5_PWM0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL5_PWM1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL5_PWM2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL5_A0(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL5_A1(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL5_A2(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL5_A3(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL6_A4(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL6_A5(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL6_A6(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL6_A7(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL6_A8(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL6_A9(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL6_A10(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL6_A11(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL7_A12(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL7_A13(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL7_A14(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL7_A15(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL7_A16(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL7_A17(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL7_A18(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL7_A19(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL8_CLKOUT(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL8_CS0(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL8_CS1_A2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL8_BS(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL8_RD(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL8_RD_W(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL8_WE0(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL8_WE1(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL9_EX_WAIT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL9_PRESETOU(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL9_D0(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL9_D1(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL9_D2(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL9_D3(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL9_D4(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL9_D5(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL10_D6(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL10_D7(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL10_D8(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL10_D9(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL10_D10(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL10_D11(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL10_D12(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL10_D13(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL11_D14(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL11_D15(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL11_AVS1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL11_AVS2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL11_GP7_02(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL11_GP7_03(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL11_DU_DOTCLKIN0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL11_DU_DOTCLKIN1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL12_DU_DOTCLKIN2(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL12_DU_DOTCLKIN3(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL12_DU_FSCLKST(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL12_DU_TMS(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_TDO(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL13_ASEBRK(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL13_SD0_CLK(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL13_SD0_CMD(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL13_SD0_DAT0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL13_SD0_DAT1(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL13_SD0_DAT2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_SD0_DAT3(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL14_SD1_CLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL14_SD1_CMD(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL14_SD1_DAT0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL14_SD1_DAT1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL14_SD1_DAT2(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL14_SD1_DAT3(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL14_SD2_CLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL14_SD2_CMD(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL15_SD2_DAT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL15_SD2_DAT1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL15_SD2_DAT2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL15_SD2_DAT3(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL15_SD2_DS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL15_SD3_CLK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL15_SD3_CMD(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL15_SD3_DAT0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL16_SD3_DAT1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL16_SD3_DAT2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL16_SD3_DAT3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL16_SD3_DAT4(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL16_SD3_DAT5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL16_SD3_DAT6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL16_SD3_DAT7(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL16_SD3_DS(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL17_SD0_CD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL17_SD0_WP(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL17_SD1_CD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL17_SD1_WP(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL17_SCK0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL17_RX0(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL17_TX0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL17_CTS0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL18_RTS0_TANS(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL18_RX1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL18_TX1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL18_CTS1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL18_RTS1_TANS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL18_SCK2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL18_TX2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL18_RX2(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL19_HSCK0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL19_HRX0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL19_HTX0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL19_HCTS0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL19_HRTS0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL19_MSIOF0_SCK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL19_MSIOF0_SYNC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL19_MSIOF0_SS1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL20_MSIOF0_TXD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL20_MSIOF0_SS2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL20_MSIOF0_RXD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL20_MLB_CLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL20_MLB_SIG(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL20_MLB_DAT(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL20_MLB_REF(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL20_SSI_SCK0129(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL21_SSI_WS0129(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL21_SSI_SDATA0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL21_SSI_SDATA1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL21_SSI_SDATA2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL21_SSI_SCK34(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL21_SSI_WS34(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL21_SSI_SDATA3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL21_SSI_SCK4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL22_SSI_WS4(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL22_SSI_SDATA4(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL22_SSI_SCK5(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL22_SSI_WS5(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL22_SSI_SDATA5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL22_SSI_SCK6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL22_SSI_WS6(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL22_SSI_SDATA6(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL23_SSI_SCK78(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL23_SSI_WS78(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL23_SSI_SDATA7(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL23_SSI_SDATA8(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL23_SSI_SDATA9(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL23_AUDIO_CLKA(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL23_AUDIO_CLKB(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL23_USB0_PWEN(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL24_USB0_OVC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL24_USB1_PWEN(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL24_USB1_OVC(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL24_USB30_PWEN(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL24_USB30_OVC(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL24_USB31_PWEN(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL24_USB31_OVC(x)	((uint32_t)(x) << 4U)
+
+#define MOD_SEL0_MSIOF3_A	((uint32_t)0U << 29U)
+#define MOD_SEL0_MSIOF3_B	((uint32_t)1U << 29U)
+#define MOD_SEL0_MSIOF3_C	((uint32_t)2U << 29U)
+#define MOD_SEL0_MSIOF3_D	((uint32_t)3U << 29U)
+#define MOD_SEL0_MSIOF2_A	((uint32_t)0U << 27U)
+#define MOD_SEL0_MSIOF2_B	((uint32_t)1U << 27U)
+#define MOD_SEL0_MSIOF2_C	((uint32_t)2U << 27U)
+#define MOD_SEL0_MSIOF2_D	((uint32_t)3U << 27U)
+#define MOD_SEL0_MSIOF1_A	((uint32_t)0U << 24U)
+#define MOD_SEL0_MSIOF1_B	((uint32_t)1U << 24U)
+#define MOD_SEL0_MSIOF1_C	((uint32_t)2U << 24U)
+#define MOD_SEL0_MSIOF1_D	((uint32_t)3U << 24U)
+#define MOD_SEL0_MSIOF1_E	((uint32_t)4U << 24U)
+#define MOD_SEL0_MSIOF1_F	((uint32_t)5U << 24U)
+#define MOD_SEL0_MSIOF1_G	((uint32_t)6U << 24U)
+#define MOD_SEL0_LBSC_A		((uint32_t)0U << 23U)
+#define MOD_SEL0_LBSC_B		((uint32_t)1U << 23U)
+#define MOD_SEL0_IEBUS_A	((uint32_t)0U << 22U)
+#define MOD_SEL0_IEBUS_B	((uint32_t)1U << 22U)
+#define MOD_SEL0_I2C6_A		((uint32_t)0U << 20U)
+#define MOD_SEL0_I2C6_B		((uint32_t)1U << 20U)
+#define MOD_SEL0_I2C6_C		((uint32_t)2U << 20U)
+#define MOD_SEL0_I2C2_A		((uint32_t)0U << 19U)
+#define MOD_SEL0_I2C2_B		((uint32_t)1U << 19U)
+#define MOD_SEL0_I2C1_A		((uint32_t)0U << 18U)
+#define MOD_SEL0_I2C1_B		((uint32_t)1U << 18U)
+#define MOD_SEL0_HSCIF4_A	((uint32_t)0U << 17U)
+#define MOD_SEL0_HSCIF4_B	((uint32_t)1U << 17U)
+#define MOD_SEL0_HSCIF3_A	((uint32_t)0U << 15U)
+#define MOD_SEL0_HSCIF3_B	((uint32_t)1U << 15U)
+#define MOD_SEL0_HSCIF3_C	((uint32_t)2U << 15U)
+#define MOD_SEL0_HSCIF3_D	((uint32_t)3U << 15U)
+#define MOD_SEL0_HSCIF2_A	((uint32_t)0U << 14U)
+#define MOD_SEL0_HSCIF2_B	((uint32_t)1U << 14U)
+#define MOD_SEL0_HSCIF1_A	((uint32_t)0U << 13U)
+#define MOD_SEL0_HSCIF1_B	((uint32_t)1U << 13U)
+#define MOD_SEL0_FSO_A		((uint32_t)0U << 12U)
+#define MOD_SEL0_FSO_B		((uint32_t)1U << 12U)
+#define MOD_SEL0_FM_A		((uint32_t)0U << 11U)
+#define MOD_SEL0_FM_B		((uint32_t)1U << 11U)
+#define MOD_SEL0_ETHERAVB_A	((uint32_t)0U << 10U)
+#define MOD_SEL0_ETHERAVB_B	((uint32_t)1U << 10U)
+#define MOD_SEL0_DRIF3_A	((uint32_t)0U << 9U)
+#define MOD_SEL0_DRIF3_B	((uint32_t)1U << 9U)
+#define MOD_SEL0_DRIF2_A	((uint32_t)0U << 8U)
+#define MOD_SEL0_DRIF2_B	((uint32_t)1U << 8U)
+#define MOD_SEL0_DRIF1_A	((uint32_t)0U << 6U)
+#define MOD_SEL0_DRIF1_B	((uint32_t)1U << 6U)
+#define MOD_SEL0_DRIF1_C	((uint32_t)2U << 6U)
+#define MOD_SEL0_DRIF0_A	((uint32_t)0U << 4U)
+#define MOD_SEL0_DRIF0_B	((uint32_t)1U << 4U)
+#define MOD_SEL0_DRIF0_C	((uint32_t)2U << 4U)
+#define MOD_SEL0_CANFD0_A	((uint32_t)0U << 3U)
+#define MOD_SEL0_CANFD0_B	((uint32_t)1U << 3U)
+#define MOD_SEL0_ADG_A		((uint32_t)0U << 1U)
+#define MOD_SEL0_ADG_B		((uint32_t)1U << 1U)
+#define MOD_SEL0_ADG_C		((uint32_t)2U << 1U)
+#define MOD_SEL0_ADG_D		((uint32_t)3U << 1U)
+#define MOD_SEL0_5LINE_A	((uint32_t)0U << 0U)
+#define MOD_SEL0_5LINE_B	((uint32_t)1U << 0U)
+#define MOD_SEL1_TSIF1_A	((uint32_t)0U << 30U)
+#define MOD_SEL1_TSIF1_B	((uint32_t)1U << 30U)
+#define MOD_SEL1_TSIF1_C	((uint32_t)2U << 30U)
+#define MOD_SEL1_TSIF1_D	((uint32_t)3U << 30U)
+#define MOD_SEL1_TSIF0_A	((uint32_t)0U << 27U)
+#define MOD_SEL1_TSIF0_B	((uint32_t)1U << 27U)
+#define MOD_SEL1_TSIF0_C	((uint32_t)2U << 27U)
+#define MOD_SEL1_TSIF0_D	((uint32_t)3U << 27U)
+#define MOD_SEL1_TSIF0_E	((uint32_t)4U << 27U)
+#define MOD_SEL1_TIMER_TMU_A	((uint32_t)0U << 26U)
+#define MOD_SEL1_TIMER_TMU_B	((uint32_t)1U << 26U)
+#define MOD_SEL1_SSP1_1_A	((uint32_t)0U << 24U)
+#define MOD_SEL1_SSP1_1_B	((uint32_t)1U << 24U)
+#define MOD_SEL1_SSP1_1_C	((uint32_t)2U << 24U)
+#define MOD_SEL1_SSP1_1_D	((uint32_t)3U << 24U)
+#define MOD_SEL1_SSP1_0_A	((uint32_t)0U << 21U)
+#define MOD_SEL1_SSP1_0_B	((uint32_t)1U << 21U)
+#define MOD_SEL1_SSP1_0_C	((uint32_t)2U << 21U)
+#define MOD_SEL1_SSP1_0_D	((uint32_t)3U << 21U)
+#define MOD_SEL1_SSP1_0_E	((uint32_t)4U << 21U)
+#define MOD_SEL1_SSI_A		((uint32_t)0U << 20U)
+#define MOD_SEL1_SSI_B		((uint32_t)1U << 20U)
+#define MOD_SEL1_SPEED_PULSE_IF_A	((uint32_t)0U << 19U)
+#define MOD_SEL1_SPEED_PULSE_IF_B	((uint32_t)1U << 19U)
+#define MOD_SEL1_SIMCARD_A	((uint32_t)0U << 17U)
+#define MOD_SEL1_SIMCARD_B	((uint32_t)1U << 17U)
+#define MOD_SEL1_SIMCARD_C	((uint32_t)2U << 17U)
+#define MOD_SEL1_SIMCARD_D	((uint32_t)3U << 17U)
+#define MOD_SEL1_SDHI2_A	((uint32_t)0U << 16U)
+#define MOD_SEL1_SDHI2_B	((uint32_t)1U << 16U)
+#define MOD_SEL1_SCIF4_A	((uint32_t)0U << 14U)
+#define MOD_SEL1_SCIF4_B	((uint32_t)1U << 14U)
+#define MOD_SEL1_SCIF4_C	((uint32_t)2U << 14U)
+#define MOD_SEL1_SCIF3_A	((uint32_t)0U << 13U)
+#define MOD_SEL1_SCIF3_B	((uint32_t)1U << 13U)
+#define MOD_SEL1_SCIF2_A	((uint32_t)0U << 12U)
+#define MOD_SEL1_SCIF2_B	((uint32_t)1U << 12U)
+#define MOD_SEL1_SCIF1_A	((uint32_t)0U << 11U)
+#define MOD_SEL1_SCIF1_B	((uint32_t)1U << 11U)
+#define MOD_SEL1_SCIF_A		((uint32_t)0U << 10U)
+#define MOD_SEL1_SCIF_B		((uint32_t)1U << 10U)
+#define MOD_SEL1_REMOCON_A	((uint32_t)0U << 9U)
+#define MOD_SEL1_REMOCON_B	((uint32_t)1U << 9U)
+#define MOD_SEL1_RCAN0_A	((uint32_t)0U << 6U)
+#define MOD_SEL1_RCAN0_B	((uint32_t)1U << 6U)
+#define MOD_SEL1_PWM6_A		((uint32_t)0U << 5U)
+#define MOD_SEL1_PWM6_B		((uint32_t)1U << 5U)
+#define MOD_SEL1_PWM5_A		((uint32_t)0U << 4U)
+#define MOD_SEL1_PWM5_B		((uint32_t)1U << 4U)
+#define MOD_SEL1_PWM4_A		((uint32_t)0U << 3U)
+#define MOD_SEL1_PWM4_B		((uint32_t)1U << 3U)
+#define MOD_SEL1_PWM3_A		((uint32_t)0U << 2U)
+#define MOD_SEL1_PWM3_B		((uint32_t)1U << 2U)
+#define MOD_SEL1_PWM2_A		((uint32_t)0U << 1U)
+#define MOD_SEL1_PWM2_B		((uint32_t)1U << 1U)
+#define MOD_SEL1_PWM1_A		((uint32_t)0U << 0U)
+#define MOD_SEL1_PWM1_B		((uint32_t)1U << 0U)
+#define MOD_SEL2_I2C_5_A	((uint32_t)0U << 31U)
+#define MOD_SEL2_I2C_5_B	((uint32_t)1U << 31U)
+#define MOD_SEL2_I2C_3_A	((uint32_t)0U << 30U)
+#define MOD_SEL2_I2C_3_B	((uint32_t)1U << 30U)
+#define MOD_SEL2_I2C_0_A	((uint32_t)0U << 29U)
+#define MOD_SEL2_I2C_0_B	((uint32_t)1U << 29U)
+#define MOD_SEL2_VIN4_A		((uint32_t)0U << 0U)
+#define MOD_SEL2_VIN4_B		((uint32_t)1U << 0U)
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	mmio_write_32(PFC_PMMR, ~data);
+	mmio_write_32((uintptr_t)addr, data);
+}
+
+void pfc_init_h3_v1(void)
+{
+	uint32_t reg;
+
+	/* initialize module select */
+	pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A
+		      | MOD_SEL0_MSIOF2_A
+		      | MOD_SEL0_MSIOF1_A
+		      | MOD_SEL0_LBSC_A
+		      | MOD_SEL0_IEBUS_A
+		      | MOD_SEL0_I2C6_A
+		      | MOD_SEL0_I2C2_A
+		      | MOD_SEL0_I2C1_A
+		      | MOD_SEL0_HSCIF4_A
+		      | MOD_SEL0_HSCIF3_A
+		      | MOD_SEL0_HSCIF2_A
+		      | MOD_SEL0_HSCIF1_A
+		      | MOD_SEL0_FM_A
+		      | MOD_SEL0_ETHERAVB_A
+		      | MOD_SEL0_DRIF3_A
+		      | MOD_SEL0_DRIF2_A
+		      | MOD_SEL0_DRIF1_A
+		      | MOD_SEL0_DRIF0_A
+		      | MOD_SEL0_CANFD0_A
+		      | MOD_SEL0_ADG_A
+		      | MOD_SEL0_5LINE_A);
+	pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A
+		      | MOD_SEL1_TSIF0_A
+		      | MOD_SEL1_TIMER_TMU_A
+		      | MOD_SEL1_SSP1_1_A
+		      | MOD_SEL1_SSP1_0_A
+		      | MOD_SEL1_SSI_A
+		      | MOD_SEL1_SPEED_PULSE_IF_A
+		      | MOD_SEL1_SIMCARD_A
+		      | MOD_SEL1_SDHI2_A
+		      | MOD_SEL1_SCIF4_A
+		      | MOD_SEL1_SCIF3_A
+		      | MOD_SEL1_SCIF2_A
+		      | MOD_SEL1_SCIF1_A
+		      | MOD_SEL1_SCIF_A
+		      | MOD_SEL1_REMOCON_A
+		      | MOD_SEL1_RCAN0_A
+		      | MOD_SEL1_PWM6_A
+		      | MOD_SEL1_PWM5_A
+		      | MOD_SEL1_PWM4_A
+		      | MOD_SEL1_PWM3_A
+		      | MOD_SEL1_PWM2_A
+		      | MOD_SEL1_PWM1_A);
+	pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A
+		      | MOD_SEL2_I2C_3_A
+		      | MOD_SEL2_I2C_0_A
+		      | MOD_SEL2_VIN4_A);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(3)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(3));
+	pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(1)
+		      | IPSR_20_FUNC(1)
+		      | IPSR_16_FUNC(1)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(4)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(1)
+		      | IPSR_0_FUNC(1));
+	pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(4)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(8)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(8));
+	pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(1)
+		      | IPSR_0_FUNC(1));
+	pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(1)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR17, IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+
+	/* initialize GPIO/perihperal function select */
+	pfc_reg_write(PFC_GPSR0, GPSR0_D15
+		      | GPSR0_D14
+		      | GPSR0_D13
+		      | GPSR0_D12
+		      | GPSR0_D11
+		      | GPSR0_D10
+		      | GPSR0_D9
+		      | GPSR0_D8);
+	pfc_reg_write(PFC_GPSR1, GPSR1_EX_WAIT0_A
+		      | GPSR1_A19
+		      | GPSR1_A18
+		      | GPSR1_A17
+		      | GPSR1_A16
+		      | GPSR1_A15
+		      | GPSR1_A14
+		      | GPSR1_A13
+		      | GPSR1_A12
+		      | GPSR1_A7
+		      | GPSR1_A6
+		      | GPSR1_A5
+		      | GPSR1_A4
+		      | GPSR1_A3
+		      | GPSR1_A2
+		      | GPSR1_A1
+		      | GPSR1_A0);
+	pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A
+		      | GPSR2_AVB_AVTP_MATCH_A
+		      | GPSR2_AVB_LINK
+		      | GPSR2_AVB_PHY_INT
+		      | GPSR2_AVB_MDC
+		      | GPSR2_PWM2_A
+		      | GPSR2_PWM1_A
+		      | GPSR2_IRQ5
+		      | GPSR2_IRQ4
+		      | GPSR2_IRQ3
+		      | GPSR2_IRQ2
+		      | GPSR2_IRQ1
+		      | GPSR2_IRQ0);
+	pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP
+		      | GPSR3_SD0_CD
+		      | GPSR3_SD1_DAT3
+		      | GPSR3_SD1_DAT2
+		      | GPSR3_SD1_DAT1
+		      | GPSR3_SD1_DAT0
+		      | GPSR3_SD0_DAT3
+		      | GPSR3_SD0_DAT2
+		      | GPSR3_SD0_DAT1
+		      | GPSR3_SD0_DAT0
+		      | GPSR3_SD0_CMD
+		      | GPSR3_SD0_CLK);
+	pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7
+		      | GPSR4_SD3_DAT6
+		      | GPSR4_SD3_DAT3
+		      | GPSR4_SD3_DAT2
+		      | GPSR4_SD3_DAT1
+		      | GPSR4_SD3_DAT0
+		      | GPSR4_SD3_CMD
+		      | GPSR4_SD3_CLK
+		      | GPSR4_SD2_DS
+		      | GPSR4_SD2_DAT3
+		      | GPSR4_SD2_DAT2
+		      | GPSR4_SD2_DAT1
+		      | GPSR4_SD2_DAT0
+		      | GPSR4_SD2_CMD
+		      | GPSR4_SD2_CLK);
+	pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2
+		      | GPSR5_MSIOF0_SS1
+		      | GPSR5_MSIOF0_SYNC
+		      | GPSR5_HRTS0
+		      | GPSR5_HCTS0
+		      | GPSR5_HTX0
+		      | GPSR5_HRX0
+		      | GPSR5_HSCK0
+		      | GPSR5_RX2_A
+		      | GPSR5_TX2_A
+		      | GPSR5_SCK2
+		      | GPSR5_RTS1
+		      | GPSR5_CTS1
+		      | GPSR5_TX1_A
+		      | GPSR5_RX1_A
+		      | GPSR5_RTS0
+		      | GPSR5_SCK0);
+	pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC
+		      | GPSR6_USB30_PWEN
+		      | GPSR6_USB1_OVC
+		      | GPSR6_USB1_PWEN
+		      | GPSR6_USB0_OVC
+		      | GPSR6_USB0_PWEN
+		      | GPSR6_AUDIO_CLKB_B
+		      | GPSR6_AUDIO_CLKA_A
+		      | GPSR6_SSI_SDATA8
+		      | GPSR6_SSI_SDATA7
+		      | GPSR6_SSI_WS78
+		      | GPSR6_SSI_SCK78
+		      | GPSR6_SSI_WS6
+		      | GPSR6_SSI_SCK6
+		      | GPSR6_SSI_SDATA4
+		      | GPSR6_SSI_WS4
+		      | GPSR6_SSI_SCK4
+		      | GPSR6_SSI_SDATA1_A
+		      | GPSR6_SSI_SDATA0
+		      | GPSR6_SSI_WS0129
+		      | GPSR6_SSI_SCK0129);
+	pfc_reg_write(PFC_GPSR7, GPSR7_AVS2
+		      | GPSR7_AVS1);
+
+	/* initialize POC control register */
+	pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V
+		      | POC_SD3_DAT7_33V
+		      | POC_SD3_DAT6_33V
+		      | POC_SD3_DAT5_33V
+		      | POC_SD3_DAT4_33V
+		      | POC_SD3_DAT3_33V
+		      | POC_SD3_DAT2_33V
+		      | POC_SD3_DAT1_33V
+		      | POC_SD3_DAT0_33V
+		      | POC_SD3_CMD_33V
+		      | POC_SD3_CLK_33V
+		      | POC_SD0_DAT3_33V
+		      | POC_SD0_DAT2_33V
+		      | POC_SD0_DAT1_33V
+		      | POC_SD0_DAT0_33V
+		      | POC_SD0_CMD_33V
+		      | POC_SD0_CLK_33V);
+
+	/* initialize DRV control register */
+	reg = mmio_read_32(PFC_DRVCTRL0);
+	reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3)
+	       | DRVCTRL0_QSPI0_MOSI_IO0(3)
+	       | DRVCTRL0_QSPI0_MISO_IO1(3)
+	       | DRVCTRL0_QSPI0_IO2(3)
+	       | DRVCTRL0_QSPI0_IO3(3)
+	       | DRVCTRL0_QSPI0_SSL(3)
+	       | DRVCTRL0_QSPI1_SPCLK(3)
+	       | DRVCTRL0_QSPI1_MOSI_IO0(3));
+	pfc_reg_write(PFC_DRVCTRL0, reg);
+	reg = mmio_read_32(PFC_DRVCTRL1);
+	reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3)
+	       | DRVCTRL1_QSPI1_IO2(3)
+	       | DRVCTRL1_QSPI1_IO3(3)
+	       | DRVCTRL1_QSPI1_SS(3)
+	       | DRVCTRL1_RPC_INT(3)
+	       | DRVCTRL1_RPC_WP(3)
+	       | DRVCTRL1_RPC_RESET(3)
+	       | DRVCTRL1_AVB_RX_CTL(7));
+	pfc_reg_write(PFC_DRVCTRL1, reg);
+	reg = mmio_read_32(PFC_DRVCTRL2);
+	reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7)
+	       | DRVCTRL2_AVB_RD0(7)
+	       | DRVCTRL2_AVB_RD1(7)
+	       | DRVCTRL2_AVB_RD2(7)
+	       | DRVCTRL2_AVB_RD3(7)
+	       | DRVCTRL2_AVB_TX_CTL(3)
+	       | DRVCTRL2_AVB_TXC(3)
+	       | DRVCTRL2_AVB_TD0(3));
+	pfc_reg_write(PFC_DRVCTRL2, reg);
+	reg = mmio_read_32(PFC_DRVCTRL3);
+	reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3)
+	       | DRVCTRL3_AVB_TD2(3)
+	       | DRVCTRL3_AVB_TD3(3)
+	       | DRVCTRL3_AVB_TXCREFCLK(7)
+	       | DRVCTRL3_AVB_MDIO(7)
+	       | DRVCTRL3_AVB_MDC(7)
+	       | DRVCTRL3_AVB_MAGIC(7)
+	       | DRVCTRL3_AVB_PHY_INT(7));
+	pfc_reg_write(PFC_DRVCTRL3, reg);
+	reg = mmio_read_32(PFC_DRVCTRL4);
+	reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7)
+	       | DRVCTRL4_AVB_AVTP_MATCH(7)
+	       | DRVCTRL4_AVB_AVTP_CAPTURE(7)
+	       | DRVCTRL4_IRQ0(7)
+	       | DRVCTRL4_IRQ1(7)
+	       | DRVCTRL4_IRQ2(7)
+	       | DRVCTRL4_IRQ3(7)
+	       | DRVCTRL4_IRQ4(7));
+	pfc_reg_write(PFC_DRVCTRL4, reg);
+	reg = mmio_read_32(PFC_DRVCTRL5);
+	reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7)
+	       | DRVCTRL5_PWM0(7)
+	       | DRVCTRL5_PWM1(7)
+	       | DRVCTRL5_PWM2(7)
+	       | DRVCTRL5_A0(3)
+	       | DRVCTRL5_A1(3)
+	       | DRVCTRL5_A2(3)
+	       | DRVCTRL5_A3(3));
+	pfc_reg_write(PFC_DRVCTRL5, reg);
+	reg = mmio_read_32(PFC_DRVCTRL6);
+	reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3)
+	       | DRVCTRL6_A5(3)
+	       | DRVCTRL6_A6(3)
+	       | DRVCTRL6_A7(3)
+	       | DRVCTRL6_A8(7)
+	       | DRVCTRL6_A9(7)
+	       | DRVCTRL6_A10(7)
+	       | DRVCTRL6_A11(7));
+	pfc_reg_write(PFC_DRVCTRL6, reg);
+	reg = mmio_read_32(PFC_DRVCTRL7);
+	reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3)
+	       | DRVCTRL7_A13(3)
+	       | DRVCTRL7_A14(3)
+	       | DRVCTRL7_A15(3)
+	       | DRVCTRL7_A16(3)
+	       | DRVCTRL7_A17(3)
+	       | DRVCTRL7_A18(3)
+	       | DRVCTRL7_A19(3));
+	pfc_reg_write(PFC_DRVCTRL7, reg);
+	reg = mmio_read_32(PFC_DRVCTRL8);
+	reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7)
+	       | DRVCTRL8_CS0(7)
+	       | DRVCTRL8_CS1_A2(7)
+	       | DRVCTRL8_BS(7)
+	       | DRVCTRL8_RD(7)
+	       | DRVCTRL8_RD_W(7)
+	       | DRVCTRL8_WE0(7)
+	       | DRVCTRL8_WE1(7));
+	pfc_reg_write(PFC_DRVCTRL8, reg);
+	reg = mmio_read_32(PFC_DRVCTRL9);
+	reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7)
+	       | DRVCTRL9_PRESETOU(7)
+	       | DRVCTRL9_D0(7)
+	       | DRVCTRL9_D1(7)
+	       | DRVCTRL9_D2(7)
+	       | DRVCTRL9_D3(7)
+	       | DRVCTRL9_D4(7)
+	       | DRVCTRL9_D5(7));
+	pfc_reg_write(PFC_DRVCTRL9, reg);
+	reg = mmio_read_32(PFC_DRVCTRL10);
+	reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7)
+	       | DRVCTRL10_D7(7)
+	       | DRVCTRL10_D8(3)
+	       | DRVCTRL10_D9(3)
+	       | DRVCTRL10_D10(3)
+	       | DRVCTRL10_D11(3)
+	       | DRVCTRL10_D12(3)
+	       | DRVCTRL10_D13(3));
+	pfc_reg_write(PFC_DRVCTRL10, reg);
+	reg = mmio_read_32(PFC_DRVCTRL11);
+	reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3)
+	       | DRVCTRL11_D15(3)
+	       | DRVCTRL11_AVS1(7)
+	       | DRVCTRL11_AVS2(7)
+	       | DRVCTRL11_GP7_02(7)
+	       | DRVCTRL11_GP7_03(7)
+	       | DRVCTRL11_DU_DOTCLKIN0(3)
+	       | DRVCTRL11_DU_DOTCLKIN1(3));
+	pfc_reg_write(PFC_DRVCTRL11, reg);
+	reg = mmio_read_32(PFC_DRVCTRL12);
+	reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3)
+	       | DRVCTRL12_DU_DOTCLKIN3(3)
+	       | DRVCTRL12_DU_FSCLKST(3)
+	       | DRVCTRL12_DU_TMS(3));
+	pfc_reg_write(PFC_DRVCTRL12, reg);
+	reg = mmio_read_32(PFC_DRVCTRL13);
+	reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3)
+	       | DRVCTRL13_ASEBRK(3)
+	       | DRVCTRL13_SD0_CLK(2)
+	       | DRVCTRL13_SD0_CMD(2)
+	       | DRVCTRL13_SD0_DAT0(2)
+	       | DRVCTRL13_SD0_DAT1(2)
+	       | DRVCTRL13_SD0_DAT2(2)
+	       | DRVCTRL13_SD0_DAT3(2));
+	pfc_reg_write(PFC_DRVCTRL13, reg);
+	reg = mmio_read_32(PFC_DRVCTRL14);
+	reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7)
+	       | DRVCTRL14_SD1_CMD(7)
+	       | DRVCTRL14_SD1_DAT0(5)
+	       | DRVCTRL14_SD1_DAT1(5)
+	       | DRVCTRL14_SD1_DAT2(5)
+	       | DRVCTRL14_SD1_DAT3(5)
+	       | DRVCTRL14_SD2_CLK(5)
+	       | DRVCTRL14_SD2_CMD(5));
+	pfc_reg_write(PFC_DRVCTRL14, reg);
+	reg = mmio_read_32(PFC_DRVCTRL15);
+	reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5)
+	       | DRVCTRL15_SD2_DAT1(5)
+	       | DRVCTRL15_SD2_DAT2(5)
+	       | DRVCTRL15_SD2_DAT3(5)
+	       | DRVCTRL15_SD2_DS(5)
+	       | DRVCTRL15_SD3_CLK(2)
+	       | DRVCTRL15_SD3_CMD(2)
+	       | DRVCTRL15_SD3_DAT0(2));
+	pfc_reg_write(PFC_DRVCTRL15, reg);
+	reg = mmio_read_32(PFC_DRVCTRL16);
+	reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(2)
+	       | DRVCTRL16_SD3_DAT2(2)
+	       | DRVCTRL16_SD3_DAT3(2)
+	       | DRVCTRL16_SD3_DAT4(7)
+	       | DRVCTRL16_SD3_DAT5(7)
+	       | DRVCTRL16_SD3_DAT6(7)
+	       | DRVCTRL16_SD3_DAT7(7)
+	       | DRVCTRL16_SD3_DS(7));
+	pfc_reg_write(PFC_DRVCTRL16, reg);
+	reg = mmio_read_32(PFC_DRVCTRL17);
+	reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7)
+	       | DRVCTRL17_SD0_WP(7)
+	       | DRVCTRL17_SD1_CD(7)
+	       | DRVCTRL17_SD1_WP(7)
+	       | DRVCTRL17_SCK0(7)
+	       | DRVCTRL17_RX0(7)
+	       | DRVCTRL17_TX0(7)
+	       | DRVCTRL17_CTS0(7));
+	pfc_reg_write(PFC_DRVCTRL17, reg);
+	reg = mmio_read_32(PFC_DRVCTRL18);
+	reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7)
+	       | DRVCTRL18_RX1(7)
+	       | DRVCTRL18_TX1(7)
+	       | DRVCTRL18_CTS1(7)
+	       | DRVCTRL18_RTS1_TANS(7)
+	       | DRVCTRL18_SCK2(7)
+	       | DRVCTRL18_TX2(7)
+	       | DRVCTRL18_RX2(7));
+	pfc_reg_write(PFC_DRVCTRL18, reg);
+	reg = mmio_read_32(PFC_DRVCTRL19);
+	reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7)
+	       | DRVCTRL19_HRX0(7)
+	       | DRVCTRL19_HTX0(7)
+	       | DRVCTRL19_HCTS0(7)
+	       | DRVCTRL19_HRTS0(7)
+	       | DRVCTRL19_MSIOF0_SCK(7)
+	       | DRVCTRL19_MSIOF0_SYNC(7)
+	       | DRVCTRL19_MSIOF0_SS1(7));
+	pfc_reg_write(PFC_DRVCTRL19, reg);
+	reg = mmio_read_32(PFC_DRVCTRL20);
+	reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7)
+	       | DRVCTRL20_MSIOF0_SS2(7)
+	       | DRVCTRL20_MSIOF0_RXD(7)
+	       | DRVCTRL20_MLB_CLK(7)
+	       | DRVCTRL20_MLB_SIG(7)
+	       | DRVCTRL20_MLB_DAT(7)
+	       | DRVCTRL20_MLB_REF(7)
+	       | DRVCTRL20_SSI_SCK0129(7));
+	pfc_reg_write(PFC_DRVCTRL20, reg);
+	reg = mmio_read_32(PFC_DRVCTRL21);
+	reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7)
+	       | DRVCTRL21_SSI_SDATA0(7)
+	       | DRVCTRL21_SSI_SDATA1(7)
+	       | DRVCTRL21_SSI_SDATA2(7)
+	       | DRVCTRL21_SSI_SCK34(7)
+	       | DRVCTRL21_SSI_WS34(7)
+	       | DRVCTRL21_SSI_SDATA3(7)
+	       | DRVCTRL21_SSI_SCK4(7));
+	pfc_reg_write(PFC_DRVCTRL21, reg);
+	reg = mmio_read_32(PFC_DRVCTRL22);
+	reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7)
+	       | DRVCTRL22_SSI_SDATA4(7)
+	       | DRVCTRL22_SSI_SCK5(7)
+	       | DRVCTRL22_SSI_WS5(7)
+	       | DRVCTRL22_SSI_SDATA5(7)
+	       | DRVCTRL22_SSI_SCK6(7)
+	       | DRVCTRL22_SSI_WS6(7)
+	       | DRVCTRL22_SSI_SDATA6(7));
+	pfc_reg_write(PFC_DRVCTRL22, reg);
+	reg = mmio_read_32(PFC_DRVCTRL23);
+	reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7)
+	       | DRVCTRL23_SSI_WS78(7)
+	       | DRVCTRL23_SSI_SDATA7(7)
+	       | DRVCTRL23_SSI_SDATA8(7)
+	       | DRVCTRL23_SSI_SDATA9(7)
+	       | DRVCTRL23_AUDIO_CLKA(7)
+	       | DRVCTRL23_AUDIO_CLKB(7)
+	       | DRVCTRL23_USB0_PWEN(7));
+	pfc_reg_write(PFC_DRVCTRL23, reg);
+	reg = mmio_read_32(PFC_DRVCTRL24);
+	reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7)
+	       | DRVCTRL24_USB1_PWEN(7)
+	       | DRVCTRL24_USB1_OVC(7)
+	       | DRVCTRL24_USB30_PWEN(7)
+	       | DRVCTRL24_USB30_OVC(7)
+	       | DRVCTRL24_USB31_PWEN(7)
+	       | DRVCTRL24_USB31_OVC(7));
+	pfc_reg_write(PFC_DRVCTRL24, reg);
+
+	/* initialize LSI pin pull-up/down control */
+	pfc_reg_write(PFC_PUD0, 0x00005FBFU);
+	pfc_reg_write(PFC_PUD1, 0x00300FFEU);
+	pfc_reg_write(PFC_PUD2, 0x330001E6U);
+	pfc_reg_write(PFC_PUD3, 0x000002E0U);
+	pfc_reg_write(PFC_PUD4, 0xFFFFFF00U);
+	pfc_reg_write(PFC_PUD5, 0x7F5FFF87U);
+	pfc_reg_write(PFC_PUD6, 0x00000055U);
+
+	/* initialize LSI pin pull-enable register */
+	pfc_reg_write(PFC_PUEN0, 0x00000FFFU);
+	pfc_reg_write(PFC_PUEN1, 0x00100234U);
+	pfc_reg_write(PFC_PUEN2, 0x000004C4U);
+	pfc_reg_write(PFC_PUEN3, 0x00000200U);
+	pfc_reg_write(PFC_PUEN4, 0x3E000000U);
+	pfc_reg_write(PFC_PUEN5, 0x1F000805U);
+	pfc_reg_write(PFC_PUEN6, 0x00000006U);
+
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG6, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG7, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL6, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL7, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT1, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000400U);
+	mmio_write_32(GPIO_OUTDT3, 0x0000C000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00000006U);
+	mmio_write_32(GPIO_OUTDT6, 0x00003880U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x00000400U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00000000U);
+#if (RCAR_GEN3_ULCB == 1)
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU);
+#else
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU);
+#endif
+	mmio_write_32(GPIO_INOUTSEL6, 0x00013880U);
+	mmio_write_32(GPIO_INOUTSEL7, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h
new file mode 100644
index 0000000..2478e1c
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_H3_V1_H
+#define PFC_INIT_H3_V1_H
+
+void pfc_init_h3_v1(void);
+
+#endif /* PFC_INIT_H3_V1_H */
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
new file mode 100644
index 0000000..a54b14b
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
@@ -0,0 +1,1216 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>		/* for uint32_t */
+#include <lib/mmio.h>
+#include "pfc_init_h3_v2.h"
+#include "rcar_def.h"
+#include "../pfc_regs.h"
+
+#define GPSR0_D15		BIT(15)
+#define GPSR0_D14		BIT(14)
+#define GPSR0_D13		BIT(13)
+#define GPSR0_D12		BIT(12)
+#define GPSR0_D11		BIT(11)
+#define GPSR0_D10		BIT(10)
+#define GPSR0_D9		BIT(9)
+#define GPSR0_D8		BIT(8)
+#define GPSR0_D7		BIT(7)
+#define GPSR0_D6		BIT(6)
+#define GPSR0_D5		BIT(5)
+#define GPSR0_D4		BIT(4)
+#define GPSR0_D3		BIT(3)
+#define GPSR0_D2		BIT(2)
+#define GPSR0_D1		BIT(1)
+#define GPSR0_D0		BIT(0)
+#define GPSR1_CLKOUT		BIT(28)
+#define GPSR1_EX_WAIT0_A	BIT(27)
+#define GPSR1_WE1		BIT(26)
+#define GPSR1_WE0		BIT(25)
+#define GPSR1_RD_WR		BIT(24)
+#define GPSR1_RD		BIT(23)
+#define GPSR1_BS		BIT(22)
+#define GPSR1_CS1_A26		BIT(21)
+#define GPSR1_CS0		BIT(20)
+#define GPSR1_A19		BIT(19)
+#define GPSR1_A18		BIT(18)
+#define GPSR1_A17		BIT(17)
+#define GPSR1_A16		BIT(16)
+#define GPSR1_A15		BIT(15)
+#define GPSR1_A14		BIT(14)
+#define GPSR1_A13		BIT(13)
+#define GPSR1_A12		BIT(12)
+#define GPSR1_A11		BIT(11)
+#define GPSR1_A10		BIT(10)
+#define GPSR1_A9		BIT(9)
+#define GPSR1_A8		BIT(8)
+#define GPSR1_A7		BIT(7)
+#define GPSR1_A6		BIT(6)
+#define GPSR1_A5		BIT(5)
+#define GPSR1_A4		BIT(4)
+#define GPSR1_A3		BIT(3)
+#define GPSR1_A2		BIT(2)
+#define GPSR1_A1		BIT(1)
+#define GPSR1_A0		BIT(0)
+#define GPSR2_AVB_AVTP_CAPTURE_A	BIT(14)
+#define GPSR2_AVB_AVTP_MATCH_A	BIT(13)
+#define GPSR2_AVB_LINK		BIT(12)
+#define GPSR2_AVB_PHY_INT	BIT(11)
+#define GPSR2_AVB_MAGIC		BIT(10)
+#define GPSR2_AVB_MDC		BIT(9)
+#define GPSR2_PWM2_A		BIT(8)
+#define GPSR2_PWM1_A		BIT(7)
+#define GPSR2_PWM0		BIT(6)
+#define GPSR2_IRQ5		BIT(5)
+#define GPSR2_IRQ4		BIT(4)
+#define GPSR2_IRQ3		BIT(3)
+#define GPSR2_IRQ2		BIT(2)
+#define GPSR2_IRQ1		BIT(1)
+#define GPSR2_IRQ0		BIT(0)
+#define GPSR3_SD1_WP		BIT(15)
+#define GPSR3_SD1_CD		BIT(14)
+#define GPSR3_SD0_WP		BIT(13)
+#define GPSR3_SD0_CD		BIT(12)
+#define GPSR3_SD1_DAT3		BIT(11)
+#define GPSR3_SD1_DAT2		BIT(10)
+#define GPSR3_SD1_DAT1		BIT(9)
+#define GPSR3_SD1_DAT0		BIT(8)
+#define GPSR3_SD1_CMD		BIT(7)
+#define GPSR3_SD1_CLK		BIT(6)
+#define GPSR3_SD0_DAT3		BIT(5)
+#define GPSR3_SD0_DAT2		BIT(4)
+#define GPSR3_SD0_DAT1		BIT(3)
+#define GPSR3_SD0_DAT0		BIT(2)
+#define GPSR3_SD0_CMD		BIT(1)
+#define GPSR3_SD0_CLK		BIT(0)
+#define GPSR4_SD3_DS		BIT(17)
+#define GPSR4_SD3_DAT7		BIT(16)
+#define GPSR4_SD3_DAT6		BIT(15)
+#define GPSR4_SD3_DAT5		BIT(14)
+#define GPSR4_SD3_DAT4		BIT(13)
+#define GPSR4_SD3_DAT3		BIT(12)
+#define GPSR4_SD3_DAT2		BIT(11)
+#define GPSR4_SD3_DAT1		BIT(10)
+#define GPSR4_SD3_DAT0		BIT(9)
+#define GPSR4_SD3_CMD		BIT(8)
+#define GPSR4_SD3_CLK		BIT(7)
+#define GPSR4_SD2_DS		BIT(6)
+#define GPSR4_SD2_DAT3		BIT(5)
+#define GPSR4_SD2_DAT2		BIT(4)
+#define GPSR4_SD2_DAT1		BIT(3)
+#define GPSR4_SD2_DAT0		BIT(2)
+#define GPSR4_SD2_CMD		BIT(1)
+#define GPSR4_SD2_CLK		BIT(0)
+#define GPSR5_MLB_DAT		BIT(25)
+#define GPSR5_MLB_SIG		BIT(24)
+#define GPSR5_MLB_CLK		BIT(23)
+#define GPSR5_MSIOF0_RXD	BIT(22)
+#define GPSR5_MSIOF0_SS2	BIT(21)
+#define GPSR5_MSIOF0_TXD	BIT(20)
+#define GPSR5_MSIOF0_SS1	BIT(19)
+#define GPSR5_MSIOF0_SYNC	BIT(18)
+#define GPSR5_MSIOF0_SCK	BIT(17)
+#define GPSR5_HRTS0		BIT(16)
+#define GPSR5_HCTS0		BIT(15)
+#define GPSR5_HTX0		BIT(14)
+#define GPSR5_HRX0		BIT(13)
+#define GPSR5_HSCK0		BIT(12)
+#define GPSR5_RX2_A		BIT(11)
+#define GPSR5_TX2_A		BIT(10)
+#define GPSR5_SCK2		BIT(9)
+#define GPSR5_RTS1		BIT(8)
+#define GPSR5_CTS1		BIT(7)
+#define GPSR5_TX1_A		BIT(6)
+#define GPSR5_RX1_A		BIT(5)
+#define GPSR5_RTS0		BIT(4)
+#define GPSR5_CTS0		BIT(3)
+#define GPSR5_TX0		BIT(2)
+#define GPSR5_RX0		BIT(1)
+#define GPSR5_SCK0		BIT(0)
+#define GPSR6_USB31_OVC		BIT(31)
+#define GPSR6_USB31_PWEN	BIT(30)
+#define GPSR6_USB30_OVC		BIT(29)
+#define GPSR6_USB30_PWEN	BIT(28)
+#define GPSR6_USB1_OVC		BIT(27)
+#define GPSR6_USB1_PWEN		BIT(26)
+#define GPSR6_USB0_OVC		BIT(25)
+#define GPSR6_USB0_PWEN		BIT(24)
+#define GPSR6_AUDIO_CLKB_B	BIT(23)
+#define GPSR6_AUDIO_CLKA_A	BIT(22)
+#define GPSR6_SSI_SDATA9_A	BIT(21)
+#define GPSR6_SSI_SDATA8	BIT(20)
+#define GPSR6_SSI_SDATA7	BIT(19)
+#define GPSR6_SSI_WS78		BIT(18)
+#define GPSR6_SSI_SCK78		BIT(17)
+#define GPSR6_SSI_SDATA6	BIT(16)
+#define GPSR6_SSI_WS6		BIT(15)
+#define GPSR6_SSI_SCK6		BIT(14)
+#define GPSR6_SSI_SDATA5	BIT(13)
+#define GPSR6_SSI_WS5		BIT(12)
+#define GPSR6_SSI_SCK5		BIT(11)
+#define GPSR6_SSI_SDATA4	BIT(10)
+#define GPSR6_SSI_WS4		BIT(9)
+#define GPSR6_SSI_SCK4		BIT(8)
+#define GPSR6_SSI_SDATA3	BIT(7)
+#define GPSR6_SSI_WS34		BIT(6)
+#define GPSR6_SSI_SCK34		BIT(5)
+#define GPSR6_SSI_SDATA2_A	BIT(4)
+#define GPSR6_SSI_SDATA1_A	BIT(3)
+#define GPSR6_SSI_SDATA0	BIT(2)
+#define GPSR6_SSI_WS0129	BIT(1)
+#define GPSR6_SSI_SCK0129	BIT(0)
+#define GPSR7_AVS2		BIT(1)
+#define GPSR7_AVS1		BIT(0)
+
+#define IPSR_28_FUNC(x)		((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)		((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)		((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)		((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)		((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)		((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)		((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)		((uint32_t)(x) << 0U)
+
+#define POC_SD3_DS_33V		BIT(29)
+#define POC_SD3_DAT7_33V	BIT(28)
+#define POC_SD3_DAT6_33V	BIT(27)
+#define POC_SD3_DAT5_33V	BIT(26)
+#define POC_SD3_DAT4_33V	BIT(25)
+#define POC_SD3_DAT3_33V	BIT(24)
+#define POC_SD3_DAT2_33V	BIT(23)
+#define POC_SD3_DAT1_33V	BIT(22)
+#define POC_SD3_DAT0_33V	BIT(21)
+#define POC_SD3_CMD_33V		BIT(20)
+#define POC_SD3_CLK_33V		BIT(19)
+#define POC_SD2_DS_33V		BIT(18)
+#define POC_SD2_DAT3_33V	BIT(17)
+#define POC_SD2_DAT2_33V	BIT(16)
+#define POC_SD2_DAT1_33V	BIT(15)
+#define POC_SD2_DAT0_33V	BIT(14)
+#define POC_SD2_CMD_33V		BIT(13)
+#define POC_SD2_CLK_33V		BIT(12)
+#define POC_SD1_DAT3_33V	BIT(11)
+#define POC_SD1_DAT2_33V	BIT(10)
+#define POC_SD1_DAT1_33V	BIT(9)
+#define POC_SD1_DAT0_33V	BIT(8)
+#define POC_SD1_CMD_33V		BIT(7)
+#define POC_SD1_CLK_33V		BIT(6)
+#define POC_SD0_DAT3_33V	BIT(5)
+#define POC_SD0_DAT2_33V	BIT(4)
+#define POC_SD0_DAT1_33V	BIT(3)
+#define POC_SD0_DAT0_33V	BIT(2)
+#define POC_SD0_CMD_33V		BIT(1)
+#define POC_SD0_CLK_33V		BIT(0)
+
+#define DRVCTRL0_MASK		(0xCCCCCCCCU)
+#define DRVCTRL1_MASK		(0xCCCCCCC8U)
+#define DRVCTRL2_MASK		(0x88888888U)
+#define DRVCTRL3_MASK		(0x88888888U)
+#define DRVCTRL4_MASK		(0x88888888U)
+#define DRVCTRL5_MASK		(0x88888888U)
+#define DRVCTRL6_MASK		(0x88888888U)
+#define DRVCTRL7_MASK		(0x88888888U)
+#define DRVCTRL8_MASK		(0x88888888U)
+#define DRVCTRL9_MASK		(0x88888888U)
+#define DRVCTRL10_MASK		(0x88888888U)
+#define DRVCTRL11_MASK		(0x888888CCU)
+#define DRVCTRL12_MASK		(0xCCCFFFCFU)
+#define DRVCTRL13_MASK		(0xCC888888U)
+#define DRVCTRL14_MASK		(0x88888888U)
+#define DRVCTRL15_MASK		(0x88888888U)
+#define DRVCTRL16_MASK		(0x88888888U)
+#define DRVCTRL17_MASK		(0x88888888U)
+#define DRVCTRL18_MASK		(0x88888888U)
+#define DRVCTRL19_MASK		(0x88888888U)
+#define DRVCTRL20_MASK		(0x88888888U)
+#define DRVCTRL21_MASK		(0x88888888U)
+#define DRVCTRL22_MASK		(0x88888888U)
+#define DRVCTRL23_MASK		(0x88888888U)
+#define DRVCTRL24_MASK		(0x8888888FU)
+
+#define DRVCTRL0_QSPI0_SPCLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL0_QSPI0_MOSI_IO0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL0_QSPI0_MISO_IO1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL0_QSPI0_IO2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL0_QSPI0_IO3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL0_QSPI0_SSL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL0_QSPI1_SPCLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL0_QSPI1_MOSI_IO0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL1_QSPI1_MISO_IO1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL1_QSPI1_IO2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL1_QSPI1_IO3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL1_QSPI1_SS(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL1_RPC_INT(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL1_RPC_WP(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL1_RPC_RESET(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL1_AVB_RX_CTL(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL2_AVB_RXC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL2_AVB_RD0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL2_AVB_RD1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL2_AVB_RD2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL2_AVB_RD3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL2_AVB_TX_CTL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL2_AVB_TXC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL2_AVB_TD0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL3_AVB_TD1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL3_AVB_TD2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL3_AVB_TD3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL3_AVB_TXCREFCLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL3_AVB_MDIO(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL3_AVB_MDC(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL3_AVB_MAGIC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL3_AVB_PHY_INT(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL4_AVB_LINK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL4_AVB_AVTP_MATCH(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL4_AVB_AVTP_CAPTURE(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL4_IRQ0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL4_IRQ1(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL4_IRQ2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL4_IRQ3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL4_IRQ4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL5_IRQ5(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL5_PWM0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL5_PWM1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL5_PWM2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL5_A0(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL5_A1(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL5_A2(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL5_A3(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL6_A4(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL6_A5(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL6_A6(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL6_A7(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL6_A8(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL6_A9(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL6_A10(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL6_A11(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL7_A12(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL7_A13(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL7_A14(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL7_A15(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL7_A16(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL7_A17(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL7_A18(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL7_A19(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL8_CLKOUT(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL8_CS0(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL8_CS1_A2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL8_BS(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL8_RD(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL8_RD_W(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL8_WE0(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL8_WE1(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL9_EX_WAIT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL9_PRESETOU(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL9_D0(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL9_D1(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL9_D2(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL9_D3(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL9_D4(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL9_D5(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL10_D6(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL10_D7(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL10_D8(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL10_D9(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL10_D10(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL10_D11(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL10_D12(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL10_D13(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL11_D14(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL11_D15(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL11_AVS1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL11_AVS2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL11_GP7_02(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL11_GP7_03(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL11_DU_DOTCLKIN0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL11_DU_DOTCLKIN1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL12_DU_DOTCLKIN2(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL12_DU_DOTCLKIN3(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL12_DU_FSCLKST(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL12_DU_TMS(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_TDO(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL13_ASEBRK(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL13_SD0_CLK(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL13_SD0_CMD(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL13_SD0_DAT0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL13_SD0_DAT1(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL13_SD0_DAT2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_SD0_DAT3(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL14_SD1_CLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL14_SD1_CMD(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL14_SD1_DAT0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL14_SD1_DAT1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL14_SD1_DAT2(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL14_SD1_DAT3(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL14_SD2_CLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL14_SD2_CMD(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL15_SD2_DAT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL15_SD2_DAT1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL15_SD2_DAT2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL15_SD2_DAT3(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL15_SD2_DS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL15_SD3_CLK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL15_SD3_CMD(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL15_SD3_DAT0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL16_SD3_DAT1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL16_SD3_DAT2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL16_SD3_DAT3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL16_SD3_DAT4(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL16_SD3_DAT5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL16_SD3_DAT6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL16_SD3_DAT7(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL16_SD3_DS(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL17_SD0_CD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL17_SD0_WP(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL17_SD1_CD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL17_SD1_WP(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL17_SCK0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL17_RX0(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL17_TX0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL17_CTS0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL18_RTS0_TANS(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL18_RX1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL18_TX1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL18_CTS1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL18_RTS1_TANS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL18_SCK2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL18_TX2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL18_RX2(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL19_HSCK0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL19_HRX0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL19_HTX0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL19_HCTS0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL19_HRTS0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL19_MSIOF0_SCK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL19_MSIOF0_SYNC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL19_MSIOF0_SS1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL20_MSIOF0_TXD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL20_MSIOF0_SS2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL20_MSIOF0_RXD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL20_MLB_CLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL20_MLB_SIG(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL20_MLB_DAT(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL20_MLB_REF(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL20_SSI_SCK0129(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL21_SSI_WS0129(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL21_SSI_SDATA0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL21_SSI_SDATA1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL21_SSI_SDATA2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL21_SSI_SCK34(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL21_SSI_WS34(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL21_SSI_SDATA3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL21_SSI_SCK4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL22_SSI_WS4(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL22_SSI_SDATA4(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL22_SSI_SCK5(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL22_SSI_WS5(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL22_SSI_SDATA5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL22_SSI_SCK6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL22_SSI_WS6(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL22_SSI_SDATA6(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL23_SSI_SCK78(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL23_SSI_WS78(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL23_SSI_SDATA7(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL23_SSI_SDATA8(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL23_SSI_SDATA9(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL23_AUDIO_CLKA(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL23_AUDIO_CLKB(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL23_USB0_PWEN(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL24_USB0_OVC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL24_USB1_PWEN(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL24_USB1_OVC(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL24_USB30_PWEN(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL24_USB30_OVC(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL24_USB31_PWEN(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL24_USB31_OVC(x)	((uint32_t)(x) << 4U)
+
+#define MOD_SEL0_MSIOF3_A	((uint32_t)0U << 29U)
+#define MOD_SEL0_MSIOF3_B	((uint32_t)1U << 29U)
+#define MOD_SEL0_MSIOF3_C	((uint32_t)2U << 29U)
+#define MOD_SEL0_MSIOF3_D	((uint32_t)3U << 29U)
+#define MOD_SEL0_MSIOF3_E	((uint32_t)4U << 29U)
+#define MOD_SEL0_MSIOF2_A	((uint32_t)0U << 27U)
+#define MOD_SEL0_MSIOF2_B	((uint32_t)1U << 27U)
+#define MOD_SEL0_MSIOF2_C	((uint32_t)2U << 27U)
+#define MOD_SEL0_MSIOF2_D	((uint32_t)3U << 27U)
+#define MOD_SEL0_MSIOF1_A	((uint32_t)0U << 24U)
+#define MOD_SEL0_MSIOF1_B	((uint32_t)1U << 24U)
+#define MOD_SEL0_MSIOF1_C	((uint32_t)2U << 24U)
+#define MOD_SEL0_MSIOF1_D	((uint32_t)3U << 24U)
+#define MOD_SEL0_MSIOF1_E	((uint32_t)4U << 24U)
+#define MOD_SEL0_MSIOF1_F	((uint32_t)5U << 24U)
+#define MOD_SEL0_MSIOF1_G	((uint32_t)6U << 24U)
+#define MOD_SEL0_LBSC_A		((uint32_t)0U << 23U)
+#define MOD_SEL0_LBSC_B		((uint32_t)1U << 23U)
+#define MOD_SEL0_IEBUS_A	((uint32_t)0U << 22U)
+#define MOD_SEL0_IEBUS_B	((uint32_t)1U << 22U)
+#define MOD_SEL0_I2C2_A		((uint32_t)0U << 21U)
+#define MOD_SEL0_I2C2_B		((uint32_t)1U << 21U)
+#define MOD_SEL0_I2C1_A		((uint32_t)0U << 20U)
+#define MOD_SEL0_I2C1_B		((uint32_t)1U << 20U)
+#define MOD_SEL0_HSCIF4_A	((uint32_t)0U << 19U)
+#define MOD_SEL0_HSCIF4_B	((uint32_t)1U << 19U)
+#define MOD_SEL0_HSCIF3_A	((uint32_t)0U << 17U)
+#define MOD_SEL0_HSCIF3_B	((uint32_t)1U << 17U)
+#define MOD_SEL0_HSCIF3_C	((uint32_t)2U << 17U)
+#define MOD_SEL0_HSCIF3_D	((uint32_t)3U << 17U)
+#define MOD_SEL0_HSCIF1_A	((uint32_t)0U << 16U)
+#define MOD_SEL0_HSCIF1_B	((uint32_t)1U << 16U)
+#define MOD_SEL0_FSO_A		((uint32_t)0U << 15U)
+#define MOD_SEL0_FSO_B		((uint32_t)1U << 15U)
+#define MOD_SEL0_HSCIF2_A	((uint32_t)0U << 13U)
+#define MOD_SEL0_HSCIF2_B	((uint32_t)1U << 13U)
+#define MOD_SEL0_HSCIF2_C	((uint32_t)2U << 13U)
+#define MOD_SEL0_ETHERAVB_A	((uint32_t)0U << 12U)
+#define MOD_SEL0_ETHERAVB_B	((uint32_t)1U << 12U)
+#define MOD_SEL0_DRIF3_A	((uint32_t)0U << 11U)
+#define MOD_SEL0_DRIF3_B	((uint32_t)1U << 11U)
+#define MOD_SEL0_DRIF2_A	((uint32_t)0U << 10U)
+#define MOD_SEL0_DRIF2_B	((uint32_t)1U << 10U)
+#define MOD_SEL0_DRIF1_A	((uint32_t)0U << 8U)
+#define MOD_SEL0_DRIF1_B	((uint32_t)1U << 8U)
+#define MOD_SEL0_DRIF1_C	((uint32_t)2U << 8U)
+#define MOD_SEL0_DRIF0_A	((uint32_t)0U << 6U)
+#define MOD_SEL0_DRIF0_B	((uint32_t)1U << 6U)
+#define MOD_SEL0_DRIF0_C	((uint32_t)2U << 6U)
+#define MOD_SEL0_CANFD0_A	((uint32_t)0U << 5U)
+#define MOD_SEL0_CANFD0_B	((uint32_t)1U << 5U)
+#define MOD_SEL0_ADG_A_A	((uint32_t)0U << 3U)
+#define MOD_SEL0_ADG_A_B	((uint32_t)1U << 3U)
+#define MOD_SEL0_ADG_A_C	((uint32_t)2U << 3U)
+#define MOD_SEL1_TSIF1_A	((uint32_t)0U << 30U)
+#define MOD_SEL1_TSIF1_B	((uint32_t)1U << 30U)
+#define MOD_SEL1_TSIF1_C	((uint32_t)2U << 30U)
+#define MOD_SEL1_TSIF1_D	((uint32_t)3U << 30U)
+#define MOD_SEL1_TSIF0_A	((uint32_t)0U << 27U)
+#define MOD_SEL1_TSIF0_B	((uint32_t)1U << 27U)
+#define MOD_SEL1_TSIF0_C	((uint32_t)2U << 27U)
+#define MOD_SEL1_TSIF0_D	((uint32_t)3U << 27U)
+#define MOD_SEL1_TSIF0_E	((uint32_t)4U << 27U)
+#define MOD_SEL1_TIMER_TMU_A	((uint32_t)0U << 26U)
+#define MOD_SEL1_TIMER_TMU_B	((uint32_t)1U << 26U)
+#define MOD_SEL1_SSP1_1_A	((uint32_t)0U << 24U)
+#define MOD_SEL1_SSP1_1_B	((uint32_t)1U << 24U)
+#define MOD_SEL1_SSP1_1_C	((uint32_t)2U << 24U)
+#define MOD_SEL1_SSP1_1_D	((uint32_t)3U << 24U)
+#define MOD_SEL1_SSP1_0_A	((uint32_t)0U << 21U)
+#define MOD_SEL1_SSP1_0_B	((uint32_t)1U << 21U)
+#define MOD_SEL1_SSP1_0_C	((uint32_t)2U << 21U)
+#define MOD_SEL1_SSP1_0_D	((uint32_t)3U << 21U)
+#define MOD_SEL1_SSP1_0_E	((uint32_t)4U << 21U)
+#define MOD_SEL1_SSI_A		((uint32_t)0U << 20U)
+#define MOD_SEL1_SSI_B		((uint32_t)1U << 20U)
+#define MOD_SEL1_SPEED_PULSE_IF_A	((uint32_t)0U << 19U)
+#define MOD_SEL1_SPEED_PULSE_IF_B	((uint32_t)1U << 19U)
+#define MOD_SEL1_SIMCARD_A	((uint32_t)0U << 17U)
+#define MOD_SEL1_SIMCARD_B	((uint32_t)1U << 17U)
+#define MOD_SEL1_SIMCARD_C	((uint32_t)2U << 17U)
+#define MOD_SEL1_SIMCARD_D	((uint32_t)3U << 17U)
+#define MOD_SEL1_SDHI2_A	((uint32_t)0U << 16U)
+#define MOD_SEL1_SDHI2_B	((uint32_t)1U << 16U)
+#define MOD_SEL1_SCIF4_A	((uint32_t)0U << 14U)
+#define MOD_SEL1_SCIF4_B	((uint32_t)1U << 14U)
+#define MOD_SEL1_SCIF4_C	((uint32_t)2U << 14U)
+#define MOD_SEL1_SCIF3_A	((uint32_t)0U << 13U)
+#define MOD_SEL1_SCIF3_B	((uint32_t)1U << 13U)
+#define MOD_SEL1_SCIF2_A	((uint32_t)0U << 12U)
+#define MOD_SEL1_SCIF2_B	((uint32_t)1U << 12U)
+#define MOD_SEL1_SCIF1_A	((uint32_t)0U << 11U)
+#define MOD_SEL1_SCIF1_B	((uint32_t)1U << 11U)
+#define MOD_SEL1_SCIF_A		((uint32_t)0U << 10U)
+#define MOD_SEL1_SCIF_B		((uint32_t)1U << 10U)
+#define MOD_SEL1_REMOCON_A	((uint32_t)0U << 9U)
+#define MOD_SEL1_REMOCON_B	((uint32_t)1U << 9U)
+#define MOD_SEL1_RCAN0_A	((uint32_t)0U << 6U)
+#define MOD_SEL1_RCAN0_B	((uint32_t)1U << 6U)
+#define MOD_SEL1_PWM6_A		((uint32_t)0U << 5U)
+#define MOD_SEL1_PWM6_B		((uint32_t)1U << 5U)
+#define MOD_SEL1_PWM5_A		((uint32_t)0U << 4U)
+#define MOD_SEL1_PWM5_B		((uint32_t)1U << 4U)
+#define MOD_SEL1_PWM4_A		((uint32_t)0U << 3U)
+#define MOD_SEL1_PWM4_B		((uint32_t)1U << 3U)
+#define MOD_SEL1_PWM3_A		((uint32_t)0U << 2U)
+#define MOD_SEL1_PWM3_B		((uint32_t)1U << 2U)
+#define MOD_SEL1_PWM2_A		((uint32_t)0U << 1U)
+#define MOD_SEL1_PWM2_B		((uint32_t)1U << 1U)
+#define MOD_SEL1_PWM1_A		((uint32_t)0U << 0U)
+#define MOD_SEL1_PWM1_B		((uint32_t)1U << 0U)
+#define MOD_SEL2_I2C_5_A	((uint32_t)0U << 31U)
+#define MOD_SEL2_I2C_5_B	((uint32_t)1U << 31U)
+#define MOD_SEL2_I2C_3_A	((uint32_t)0U << 30U)
+#define MOD_SEL2_I2C_3_B	((uint32_t)1U << 30U)
+#define MOD_SEL2_I2C_0_A	((uint32_t)0U << 29U)
+#define MOD_SEL2_I2C_0_B	((uint32_t)1U << 29U)
+#define MOD_SEL2_FM_A		((uint32_t)0U << 27U)
+#define MOD_SEL2_FM_B		((uint32_t)1U << 27U)
+#define MOD_SEL2_FM_C		((uint32_t)2U << 27U)
+#define MOD_SEL2_FM_D		((uint32_t)3U << 27U)
+#define MOD_SEL2_SCIF5_A	((uint32_t)0U << 26U)
+#define MOD_SEL2_SCIF5_B	((uint32_t)1U << 26U)
+#define MOD_SEL2_I2C6_A		((uint32_t)0U << 23U)
+#define MOD_SEL2_I2C6_B		((uint32_t)1U << 23U)
+#define MOD_SEL2_I2C6_C		((uint32_t)2U << 23U)
+#define MOD_SEL2_NDF_A		((uint32_t)0U << 22U)
+#define MOD_SEL2_NDF_B		((uint32_t)1U << 22U)
+#define MOD_SEL2_SSI2_A		((uint32_t)0U << 21U)
+#define MOD_SEL2_SSI2_B		((uint32_t)1U << 21U)
+#define MOD_SEL2_SSI9_A		((uint32_t)0U << 20U)
+#define MOD_SEL2_SSI9_B		((uint32_t)1U << 20U)
+#define MOD_SEL2_TIMER_TMU2_A	((uint32_t)0U << 19U)
+#define MOD_SEL2_TIMER_TMU2_B	((uint32_t)1U << 19U)
+#define MOD_SEL2_ADG_B_A	((uint32_t)0U << 18U)
+#define MOD_SEL2_ADG_B_B	((uint32_t)1U << 18U)
+#define MOD_SEL2_ADG_C_A	((uint32_t)0U << 17U)
+#define MOD_SEL2_ADG_C_B	((uint32_t)1U << 17U)
+#define MOD_SEL2_VIN4_A		((uint32_t)0U << 0U)
+#define MOD_SEL2_VIN4_B		((uint32_t)1U << 0U)
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	mmio_write_32(PFC_PMMR, ~data);
+	mmio_write_32((uintptr_t)addr, data);
+}
+
+void pfc_init_h3_v2(void)
+{
+	uint32_t reg;
+
+	/* initialize module select */
+	pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A
+		      | MOD_SEL0_MSIOF2_A
+		      | MOD_SEL0_MSIOF1_A
+		      | MOD_SEL0_LBSC_A
+		      | MOD_SEL0_IEBUS_A
+		      | MOD_SEL0_I2C2_A
+		      | MOD_SEL0_I2C1_A
+		      | MOD_SEL0_HSCIF4_A
+		      | MOD_SEL0_HSCIF3_A
+		      | MOD_SEL0_HSCIF1_A
+		      | MOD_SEL0_FSO_A
+		      | MOD_SEL0_HSCIF2_A
+		      | MOD_SEL0_ETHERAVB_A
+		      | MOD_SEL0_DRIF3_A
+		      | MOD_SEL0_DRIF2_A
+		      | MOD_SEL0_DRIF1_A
+		      | MOD_SEL0_DRIF0_A
+		      | MOD_SEL0_CANFD0_A
+		      | MOD_SEL0_ADG_A_A);
+	pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A
+		      | MOD_SEL1_TSIF0_A
+		      | MOD_SEL1_TIMER_TMU_A
+		      | MOD_SEL1_SSP1_1_A
+		      | MOD_SEL1_SSP1_0_A
+		      | MOD_SEL1_SSI_A
+		      | MOD_SEL1_SPEED_PULSE_IF_A
+		      | MOD_SEL1_SIMCARD_A
+		      | MOD_SEL1_SDHI2_A
+		      | MOD_SEL1_SCIF4_A
+		      | MOD_SEL1_SCIF3_A
+		      | MOD_SEL1_SCIF2_A
+		      | MOD_SEL1_SCIF1_A
+		      | MOD_SEL1_SCIF_A
+		      | MOD_SEL1_REMOCON_A
+		      | MOD_SEL1_RCAN0_A
+		      | MOD_SEL1_PWM6_A
+		      | MOD_SEL1_PWM5_A
+		      | MOD_SEL1_PWM4_A
+		      | MOD_SEL1_PWM3_A
+		      | MOD_SEL1_PWM2_A
+		      | MOD_SEL1_PWM1_A);
+	pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A
+		      | MOD_SEL2_I2C_3_A
+		      | MOD_SEL2_I2C_0_A
+		      | MOD_SEL2_FM_A
+		      | MOD_SEL2_SCIF5_A
+		      | MOD_SEL2_I2C6_A
+		      | MOD_SEL2_NDF_A
+		      | MOD_SEL2_SSI2_A
+		      | MOD_SEL2_SSI9_A
+		      | MOD_SEL2_TIMER_TMU2_A
+		      | MOD_SEL2_ADG_B_A
+		      | MOD_SEL2_ADG_C_A
+		      | MOD_SEL2_VIN4_A);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(3)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(3));
+	pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(1)
+		      | IPSR_20_FUNC(1)
+		      | IPSR_16_FUNC(1)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(4)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(1));
+	pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(4)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(8)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(8));
+	pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR17, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(1)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR18, IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+
+	/* initialize GPIO/perihperal function select */
+	pfc_reg_write(PFC_GPSR0, GPSR0_D15
+		      | GPSR0_D14
+		      | GPSR0_D13
+		      | GPSR0_D12
+		      | GPSR0_D11
+		      | GPSR0_D10
+		      | GPSR0_D9
+		      | GPSR0_D8);
+	pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT
+		      | GPSR1_EX_WAIT0_A
+		      | GPSR1_A19
+		      | GPSR1_A18
+		      | GPSR1_A17
+		      | GPSR1_A16
+		      | GPSR1_A15
+		      | GPSR1_A14
+		      | GPSR1_A13
+		      | GPSR1_A12
+		      | GPSR1_A7
+		      | GPSR1_A6
+		      | GPSR1_A5
+		      | GPSR1_A4
+		      | GPSR1_A3
+		      | GPSR1_A2
+		      | GPSR1_A1
+		      | GPSR1_A0);
+	pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A
+		      | GPSR2_AVB_AVTP_MATCH_A
+		      | GPSR2_AVB_LINK
+		      | GPSR2_AVB_PHY_INT
+		      | GPSR2_AVB_MDC
+		      | GPSR2_PWM2_A
+		      | GPSR2_PWM1_A
+		      | GPSR2_IRQ5
+		      | GPSR2_IRQ4
+		      | GPSR2_IRQ3
+		      | GPSR2_IRQ2
+		      | GPSR2_IRQ1
+		      | GPSR2_IRQ0);
+	pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP
+		      | GPSR3_SD0_CD
+		      | GPSR3_SD1_DAT3
+		      | GPSR3_SD1_DAT2
+		      | GPSR3_SD1_DAT1
+		      | GPSR3_SD1_DAT0
+		      | GPSR3_SD0_DAT3
+		      | GPSR3_SD0_DAT2
+		      | GPSR3_SD0_DAT1
+		      | GPSR3_SD0_DAT0
+		      | GPSR3_SD0_CMD
+		      | GPSR3_SD0_CLK);
+	pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7
+		      | GPSR4_SD3_DAT6
+		      | GPSR4_SD3_DAT3
+		      | GPSR4_SD3_DAT2
+		      | GPSR4_SD3_DAT1
+		      | GPSR4_SD3_DAT0
+		      | GPSR4_SD3_CMD
+		      | GPSR4_SD3_CLK
+		      | GPSR4_SD2_DS
+		      | GPSR4_SD2_DAT3
+		      | GPSR4_SD2_DAT2
+		      | GPSR4_SD2_DAT1
+		      | GPSR4_SD2_DAT0
+		      | GPSR4_SD2_CMD
+		      | GPSR4_SD2_CLK);
+	pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2
+		      | GPSR5_MSIOF0_SS1
+		      | GPSR5_MSIOF0_SYNC
+		      | GPSR5_HRTS0
+		      | GPSR5_HCTS0
+		      | GPSR5_HTX0
+		      | GPSR5_HRX0
+		      | GPSR5_HSCK0
+		      | GPSR5_RX2_A
+		      | GPSR5_TX2_A
+		      | GPSR5_SCK2
+		      | GPSR5_RTS1
+		      | GPSR5_CTS1
+		      | GPSR5_TX1_A
+		      | GPSR5_RX1_A
+		      | GPSR5_RTS0
+		      | GPSR5_SCK0);
+	pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC
+		      | GPSR6_USB30_PWEN
+		      | GPSR6_USB1_OVC
+		      | GPSR6_USB1_PWEN
+		      | GPSR6_USB0_OVC
+		      | GPSR6_USB0_PWEN
+		      | GPSR6_AUDIO_CLKB_B
+		      | GPSR6_AUDIO_CLKA_A
+		      | GPSR6_SSI_SDATA8
+		      | GPSR6_SSI_SDATA7
+		      | GPSR6_SSI_WS78
+		      | GPSR6_SSI_SCK78
+		      | GPSR6_SSI_WS6
+		      | GPSR6_SSI_SCK6
+		      | GPSR6_SSI_SDATA4
+		      | GPSR6_SSI_WS4
+		      | GPSR6_SSI_SCK4
+		      | GPSR6_SSI_SDATA1_A
+		      | GPSR6_SSI_SDATA0
+		      | GPSR6_SSI_WS0129
+		      | GPSR6_SSI_SCK0129);
+	pfc_reg_write(PFC_GPSR7, GPSR7_AVS2
+		      | GPSR7_AVS1);
+
+	/* initialize POC control register */
+	pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V
+		      | POC_SD3_DAT7_33V
+		      | POC_SD3_DAT6_33V
+		      | POC_SD3_DAT5_33V
+		      | POC_SD3_DAT4_33V
+		      | POC_SD3_DAT3_33V
+		      | POC_SD3_DAT2_33V
+		      | POC_SD3_DAT1_33V
+		      | POC_SD3_DAT0_33V
+		      | POC_SD3_CMD_33V
+		      | POC_SD3_CLK_33V
+		      | POC_SD0_DAT3_33V
+		      | POC_SD0_DAT2_33V
+		      | POC_SD0_DAT1_33V
+		      | POC_SD0_DAT0_33V
+		      | POC_SD0_CMD_33V
+		      | POC_SD0_CLK_33V);
+
+	/* initialize DRV control register */
+	reg = mmio_read_32(PFC_DRVCTRL0);
+	reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3)
+	       | DRVCTRL0_QSPI0_MOSI_IO0(3)
+	       | DRVCTRL0_QSPI0_MISO_IO1(3)
+	       | DRVCTRL0_QSPI0_IO2(3)
+	       | DRVCTRL0_QSPI0_IO3(3)
+	       | DRVCTRL0_QSPI0_SSL(3)
+	       | DRVCTRL0_QSPI1_SPCLK(3)
+	       | DRVCTRL0_QSPI1_MOSI_IO0(3));
+	pfc_reg_write(PFC_DRVCTRL0, reg);
+	reg = mmio_read_32(PFC_DRVCTRL1);
+	reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3)
+	       | DRVCTRL1_QSPI1_IO2(3)
+	       | DRVCTRL1_QSPI1_IO3(3)
+	       | DRVCTRL1_QSPI1_SS(3)
+	       | DRVCTRL1_RPC_INT(3)
+	       | DRVCTRL1_RPC_WP(3)
+	       | DRVCTRL1_RPC_RESET(3)
+	       | DRVCTRL1_AVB_RX_CTL(7));
+	pfc_reg_write(PFC_DRVCTRL1, reg);
+	reg = mmio_read_32(PFC_DRVCTRL2);
+	reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7)
+	       | DRVCTRL2_AVB_RD0(7)
+	       | DRVCTRL2_AVB_RD1(7)
+	       | DRVCTRL2_AVB_RD2(7)
+	       | DRVCTRL2_AVB_RD3(7)
+	       | DRVCTRL2_AVB_TX_CTL(3)
+	       | DRVCTRL2_AVB_TXC(3)
+	       | DRVCTRL2_AVB_TD0(3));
+	pfc_reg_write(PFC_DRVCTRL2, reg);
+	reg = mmio_read_32(PFC_DRVCTRL3);
+	reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3)
+	       | DRVCTRL3_AVB_TD2(3)
+	       | DRVCTRL3_AVB_TD3(3)
+	       | DRVCTRL3_AVB_TXCREFCLK(7)
+	       | DRVCTRL3_AVB_MDIO(7)
+	       | DRVCTRL3_AVB_MDC(7)
+	       | DRVCTRL3_AVB_MAGIC(7)
+	       | DRVCTRL3_AVB_PHY_INT(7));
+	pfc_reg_write(PFC_DRVCTRL3, reg);
+	reg = mmio_read_32(PFC_DRVCTRL4);
+	reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7)
+	       | DRVCTRL4_AVB_AVTP_MATCH(7)
+	       | DRVCTRL4_AVB_AVTP_CAPTURE(7)
+	       | DRVCTRL4_IRQ0(7)
+	       | DRVCTRL4_IRQ1(7)
+	       | DRVCTRL4_IRQ2(7)
+	       | DRVCTRL4_IRQ3(7)
+	       | DRVCTRL4_IRQ4(7));
+	pfc_reg_write(PFC_DRVCTRL4, reg);
+	reg = mmio_read_32(PFC_DRVCTRL5);
+	reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7)
+	       | DRVCTRL5_PWM0(7)
+	       | DRVCTRL5_PWM1(7)
+	       | DRVCTRL5_PWM2(7)
+	       | DRVCTRL5_A0(3)
+	       | DRVCTRL5_A1(3)
+	       | DRVCTRL5_A2(3)
+	       | DRVCTRL5_A3(3));
+	pfc_reg_write(PFC_DRVCTRL5, reg);
+	reg = mmio_read_32(PFC_DRVCTRL6);
+	reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3)
+	       | DRVCTRL6_A5(3)
+	       | DRVCTRL6_A6(3)
+	       | DRVCTRL6_A7(3)
+	       | DRVCTRL6_A8(7)
+	       | DRVCTRL6_A9(7)
+	       | DRVCTRL6_A10(7)
+	       | DRVCTRL6_A11(7));
+	pfc_reg_write(PFC_DRVCTRL6, reg);
+	reg = mmio_read_32(PFC_DRVCTRL7);
+	reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3)
+	       | DRVCTRL7_A13(3)
+	       | DRVCTRL7_A14(3)
+	       | DRVCTRL7_A15(3)
+	       | DRVCTRL7_A16(3)
+	       | DRVCTRL7_A17(3)
+	       | DRVCTRL7_A18(3)
+	       | DRVCTRL7_A19(3));
+	pfc_reg_write(PFC_DRVCTRL7, reg);
+	reg = mmio_read_32(PFC_DRVCTRL8);
+	reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7)
+	       | DRVCTRL8_CS0(7)
+	       | DRVCTRL8_CS1_A2(7)
+	       | DRVCTRL8_BS(7)
+	       | DRVCTRL8_RD(7)
+	       | DRVCTRL8_RD_W(7)
+	       | DRVCTRL8_WE0(7)
+	       | DRVCTRL8_WE1(7));
+	pfc_reg_write(PFC_DRVCTRL8, reg);
+	reg = mmio_read_32(PFC_DRVCTRL9);
+	reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7)
+	       | DRVCTRL9_PRESETOU(7)
+	       | DRVCTRL9_D0(7)
+	       | DRVCTRL9_D1(7)
+	       | DRVCTRL9_D2(7)
+	       | DRVCTRL9_D3(7)
+	       | DRVCTRL9_D4(7)
+	       | DRVCTRL9_D5(7));
+	pfc_reg_write(PFC_DRVCTRL9, reg);
+	reg = mmio_read_32(PFC_DRVCTRL10);
+	reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7)
+	       | DRVCTRL10_D7(7)
+	       | DRVCTRL10_D8(3)
+	       | DRVCTRL10_D9(3)
+	       | DRVCTRL10_D10(3)
+	       | DRVCTRL10_D11(3)
+	       | DRVCTRL10_D12(3)
+	       | DRVCTRL10_D13(3));
+	pfc_reg_write(PFC_DRVCTRL10, reg);
+	reg = mmio_read_32(PFC_DRVCTRL11);
+	reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3)
+	       | DRVCTRL11_D15(3)
+	       | DRVCTRL11_AVS1(7)
+	       | DRVCTRL11_AVS2(7)
+	       | DRVCTRL11_GP7_02(7)
+	       | DRVCTRL11_GP7_03(7)
+	       | DRVCTRL11_DU_DOTCLKIN0(3)
+	       | DRVCTRL11_DU_DOTCLKIN1(3));
+	pfc_reg_write(PFC_DRVCTRL11, reg);
+	reg = mmio_read_32(PFC_DRVCTRL12);
+	reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3)
+	       | DRVCTRL12_DU_DOTCLKIN3(3)
+	       | DRVCTRL12_DU_FSCLKST(3)
+	       | DRVCTRL12_DU_TMS(3));
+	pfc_reg_write(PFC_DRVCTRL12, reg);
+	reg = mmio_read_32(PFC_DRVCTRL13);
+	reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3)
+	       | DRVCTRL13_ASEBRK(3)
+	       | DRVCTRL13_SD0_CLK(7)
+	       | DRVCTRL13_SD0_CMD(7)
+	       | DRVCTRL13_SD0_DAT0(7)
+	       | DRVCTRL13_SD0_DAT1(7)
+	       | DRVCTRL13_SD0_DAT2(7)
+	       | DRVCTRL13_SD0_DAT3(7));
+	pfc_reg_write(PFC_DRVCTRL13, reg);
+	reg = mmio_read_32(PFC_DRVCTRL14);
+	reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7)
+	       | DRVCTRL14_SD1_CMD(7)
+	       | DRVCTRL14_SD1_DAT0(5)
+	       | DRVCTRL14_SD1_DAT1(5)
+	       | DRVCTRL14_SD1_DAT2(5)
+	       | DRVCTRL14_SD1_DAT3(5)
+	       | DRVCTRL14_SD2_CLK(5)
+	       | DRVCTRL14_SD2_CMD(5));
+	pfc_reg_write(PFC_DRVCTRL14, reg);
+	reg = mmio_read_32(PFC_DRVCTRL15);
+	reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5)
+	       | DRVCTRL15_SD2_DAT1(5)
+	       | DRVCTRL15_SD2_DAT2(5)
+	       | DRVCTRL15_SD2_DAT3(5)
+	       | DRVCTRL15_SD2_DS(5)
+	       | DRVCTRL15_SD3_CLK(7)
+	       | DRVCTRL15_SD3_CMD(7)
+	       | DRVCTRL15_SD3_DAT0(7));
+	pfc_reg_write(PFC_DRVCTRL15, reg);
+	reg = mmio_read_32(PFC_DRVCTRL16);
+	reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(7)
+	       | DRVCTRL16_SD3_DAT2(7)
+	       | DRVCTRL16_SD3_DAT3(7)
+	       | DRVCTRL16_SD3_DAT4(7)
+	       | DRVCTRL16_SD3_DAT5(7)
+	       | DRVCTRL16_SD3_DAT6(7)
+	       | DRVCTRL16_SD3_DAT7(7)
+	       | DRVCTRL16_SD3_DS(7));
+	pfc_reg_write(PFC_DRVCTRL16, reg);
+	reg = mmio_read_32(PFC_DRVCTRL17);
+	reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7)
+	       | DRVCTRL17_SD0_WP(7)
+	       | DRVCTRL17_SD1_CD(7)
+	       | DRVCTRL17_SD1_WP(7)
+	       | DRVCTRL17_SCK0(7)
+	       | DRVCTRL17_RX0(7)
+	       | DRVCTRL17_TX0(7)
+	       | DRVCTRL17_CTS0(7));
+	pfc_reg_write(PFC_DRVCTRL17, reg);
+	reg = mmio_read_32(PFC_DRVCTRL18);
+	reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7)
+	       | DRVCTRL18_RX1(7)
+	       | DRVCTRL18_TX1(7)
+	       | DRVCTRL18_CTS1(7)
+	       | DRVCTRL18_RTS1_TANS(7)
+	       | DRVCTRL18_SCK2(7)
+	       | DRVCTRL18_TX2(7)
+	       | DRVCTRL18_RX2(7));
+	pfc_reg_write(PFC_DRVCTRL18, reg);
+	reg = mmio_read_32(PFC_DRVCTRL19);
+	reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7)
+	       | DRVCTRL19_HRX0(7)
+	       | DRVCTRL19_HTX0(7)
+	       | DRVCTRL19_HCTS0(7)
+	       | DRVCTRL19_HRTS0(7)
+	       | DRVCTRL19_MSIOF0_SCK(7)
+	       | DRVCTRL19_MSIOF0_SYNC(7)
+	       | DRVCTRL19_MSIOF0_SS1(7));
+	pfc_reg_write(PFC_DRVCTRL19, reg);
+	reg = mmio_read_32(PFC_DRVCTRL20);
+	reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7)
+	       | DRVCTRL20_MSIOF0_SS2(7)
+	       | DRVCTRL20_MSIOF0_RXD(7)
+	       | DRVCTRL20_MLB_CLK(7)
+	       | DRVCTRL20_MLB_SIG(7)
+	       | DRVCTRL20_MLB_DAT(7)
+	       | DRVCTRL20_MLB_REF(7)
+	       | DRVCTRL20_SSI_SCK0129(7));
+	pfc_reg_write(PFC_DRVCTRL20, reg);
+	reg = mmio_read_32(PFC_DRVCTRL21);
+	reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7)
+	       | DRVCTRL21_SSI_SDATA0(7)
+	       | DRVCTRL21_SSI_SDATA1(7)
+	       | DRVCTRL21_SSI_SDATA2(7)
+	       | DRVCTRL21_SSI_SCK34(7)
+	       | DRVCTRL21_SSI_WS34(7)
+	       | DRVCTRL21_SSI_SDATA3(7)
+	       | DRVCTRL21_SSI_SCK4(7));
+	pfc_reg_write(PFC_DRVCTRL21, reg);
+	reg = mmio_read_32(PFC_DRVCTRL22);
+	reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7)
+	       | DRVCTRL22_SSI_SDATA4(7)
+	       | DRVCTRL22_SSI_SCK5(7)
+	       | DRVCTRL22_SSI_WS5(7)
+	       | DRVCTRL22_SSI_SDATA5(7)
+	       | DRVCTRL22_SSI_SCK6(7)
+	       | DRVCTRL22_SSI_WS6(7)
+	       | DRVCTRL22_SSI_SDATA6(7));
+	pfc_reg_write(PFC_DRVCTRL22, reg);
+	reg = mmio_read_32(PFC_DRVCTRL23);
+	reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7)
+	       | DRVCTRL23_SSI_WS78(7)
+	       | DRVCTRL23_SSI_SDATA7(7)
+	       | DRVCTRL23_SSI_SDATA8(7)
+	       | DRVCTRL23_SSI_SDATA9(7)
+	       | DRVCTRL23_AUDIO_CLKA(7)
+	       | DRVCTRL23_AUDIO_CLKB(7)
+	       | DRVCTRL23_USB0_PWEN(7));
+	pfc_reg_write(PFC_DRVCTRL23, reg);
+	reg = mmio_read_32(PFC_DRVCTRL24);
+	reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7)
+	       | DRVCTRL24_USB1_PWEN(7)
+	       | DRVCTRL24_USB1_OVC(7)
+	       | DRVCTRL24_USB30_PWEN(7)
+	       | DRVCTRL24_USB30_OVC(7)
+	       | DRVCTRL24_USB31_PWEN(7)
+	       | DRVCTRL24_USB31_OVC(7));
+	pfc_reg_write(PFC_DRVCTRL24, reg);
+
+	/* initialize LSI pin pull-up/down control */
+	pfc_reg_write(PFC_PUD0, 0x00005FBFU);
+	pfc_reg_write(PFC_PUD1, 0x00300FFEU);
+	pfc_reg_write(PFC_PUD2, 0x330001E6U);
+	pfc_reg_write(PFC_PUD3, 0x000002E0U);
+	pfc_reg_write(PFC_PUD4, 0xFFFFFF00U);
+	pfc_reg_write(PFC_PUD5, 0x7F5FFF87U);
+	pfc_reg_write(PFC_PUD6, 0x00000055U);
+
+	/* initialize LSI pin pull-enable register */
+	pfc_reg_write(PFC_PUEN0, 0x00000FFFU);
+	pfc_reg_write(PFC_PUEN1, 0x00100234U);
+	pfc_reg_write(PFC_PUEN2, 0x000004C4U);
+	pfc_reg_write(PFC_PUEN3, 0x00000200U);
+	pfc_reg_write(PFC_PUEN4, 0x3E000000U);
+	pfc_reg_write(PFC_PUEN5, 0x1F000805U);
+	pfc_reg_write(PFC_PUEN6, 0x00000006U);
+
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG6, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG7, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL6, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL7, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT1, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000400U);
+	mmio_write_32(GPIO_OUTDT3, 0x0000C000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00000006U);
+	mmio_write_32(GPIO_OUTDT6, 0x00003880U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x00000400U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00000000U);
+#if (RCAR_GEN3_ULCB == 1)
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU);
+#else
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU);
+#endif
+	mmio_write_32(GPIO_INOUTSEL6, 0x00013880U);
+	mmio_write_32(GPIO_INOUTSEL7, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h
new file mode 100644
index 0000000..b02f93e
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_H3_V2_H
+#define PFC_INIT_H3_V2_H
+
+void pfc_init_h3_v2(void);
+
+#endif /* PFC_INIT_H3_V2_H */
diff --git a/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
new file mode 100644
index 0000000..0aa3bff
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>		/* for uint32_t */
+
+#include <lib/mmio.h>
+
+#include "pfc_init_m3.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "../pfc_regs.h"
+
+#define GPSR0_D15		BIT(15)
+#define GPSR0_D14		BIT(14)
+#define GPSR0_D13		BIT(13)
+#define GPSR0_D12		BIT(12)
+#define GPSR0_D11		BIT(11)
+#define GPSR0_D10		BIT(10)
+#define GPSR0_D9		BIT(9)
+#define GPSR0_D8		BIT(8)
+#define GPSR0_D7		BIT(7)
+#define GPSR0_D6		BIT(6)
+#define GPSR0_D5		BIT(5)
+#define GPSR0_D4		BIT(4)
+#define GPSR0_D3		BIT(3)
+#define GPSR0_D2		BIT(2)
+#define GPSR0_D1		BIT(1)
+#define GPSR0_D0		BIT(0)
+#define GPSR1_CLKOUT		BIT(28)
+#define GPSR1_EX_WAIT0_A	BIT(27)
+#define GPSR1_WE1		BIT(26)
+#define GPSR1_WE0		BIT(25)
+#define GPSR1_RD_WR		BIT(24)
+#define GPSR1_RD		BIT(23)
+#define GPSR1_BS		BIT(22)
+#define GPSR1_CS1_A26		BIT(21)
+#define GPSR1_CS0		BIT(20)
+#define GPSR1_A19		BIT(19)
+#define GPSR1_A18		BIT(18)
+#define GPSR1_A17		BIT(17)
+#define GPSR1_A16		BIT(16)
+#define GPSR1_A15		BIT(15)
+#define GPSR1_A14		BIT(14)
+#define GPSR1_A13		BIT(13)
+#define GPSR1_A12		BIT(12)
+#define GPSR1_A11		BIT(11)
+#define GPSR1_A10		BIT(10)
+#define GPSR1_A9		BIT(9)
+#define GPSR1_A8		BIT(8)
+#define GPSR1_A7		BIT(7)
+#define GPSR1_A6		BIT(6)
+#define GPSR1_A5		BIT(5)
+#define GPSR1_A4		BIT(4)
+#define GPSR1_A3		BIT(3)
+#define GPSR1_A2		BIT(2)
+#define GPSR1_A1		BIT(1)
+#define GPSR1_A0		BIT(0)
+#define GPSR2_AVB_AVTP_CAPTURE_A	BIT(14)
+#define GPSR2_AVB_AVTP_MATCH_A	BIT(13)
+#define GPSR2_AVB_LINK		BIT(12)
+#define GPSR2_AVB_PHY_INT	BIT(11)
+#define GPSR2_AVB_MAGIC		BIT(10)
+#define GPSR2_AVB_MDC		BIT(9)
+#define GPSR2_PWM2_A		BIT(8)
+#define GPSR2_PWM1_A		BIT(7)
+#define GPSR2_PWM0		BIT(6)
+#define GPSR2_IRQ5		BIT(5)
+#define GPSR2_IRQ4		BIT(4)
+#define GPSR2_IRQ3		BIT(3)
+#define GPSR2_IRQ2		BIT(2)
+#define GPSR2_IRQ1		BIT(1)
+#define GPSR2_IRQ0		BIT(0)
+#define GPSR3_SD1_WP		BIT(15)
+#define GPSR3_SD1_CD		BIT(14)
+#define GPSR3_SD0_WP		BIT(13)
+#define GPSR3_SD0_CD		BIT(12)
+#define GPSR3_SD1_DAT3		BIT(11)
+#define GPSR3_SD1_DAT2		BIT(10)
+#define GPSR3_SD1_DAT1		BIT(9)
+#define GPSR3_SD1_DAT0		BIT(8)
+#define GPSR3_SD1_CMD		BIT(7)
+#define GPSR3_SD1_CLK		BIT(6)
+#define GPSR3_SD0_DAT3		BIT(5)
+#define GPSR3_SD0_DAT2		BIT(4)
+#define GPSR3_SD0_DAT1		BIT(3)
+#define GPSR3_SD0_DAT0		BIT(2)
+#define GPSR3_SD0_CMD		BIT(1)
+#define GPSR3_SD0_CLK		BIT(0)
+#define GPSR4_SD3_DS		BIT(17)
+#define GPSR4_SD3_DAT7		BIT(16)
+#define GPSR4_SD3_DAT6		BIT(15)
+#define GPSR4_SD3_DAT5		BIT(14)
+#define GPSR4_SD3_DAT4		BIT(13)
+#define GPSR4_SD3_DAT3		BIT(12)
+#define GPSR4_SD3_DAT2		BIT(11)
+#define GPSR4_SD3_DAT1		BIT(10)
+#define GPSR4_SD3_DAT0		BIT(9)
+#define GPSR4_SD3_CMD		BIT(8)
+#define GPSR4_SD3_CLK		BIT(7)
+#define GPSR4_SD2_DS		BIT(6)
+#define GPSR4_SD2_DAT3		BIT(5)
+#define GPSR4_SD2_DAT2		BIT(4)
+#define GPSR4_SD2_DAT1		BIT(3)
+#define GPSR4_SD2_DAT0		BIT(2)
+#define GPSR4_SD2_CMD		BIT(1)
+#define GPSR4_SD2_CLK		BIT(0)
+#define GPSR5_MLB_DAT		BIT(25)
+#define GPSR5_MLB_SIG		BIT(24)
+#define GPSR5_MLB_CLK		BIT(23)
+#define GPSR5_MSIOF0_RXD	BIT(22)
+#define GPSR5_MSIOF0_SS2	BIT(21)
+#define GPSR5_MSIOF0_TXD	BIT(20)
+#define GPSR5_MSIOF0_SS1	BIT(19)
+#define GPSR5_MSIOF0_SYNC	BIT(18)
+#define GPSR5_MSIOF0_SCK	BIT(17)
+#define GPSR5_HRTS0		BIT(16)
+#define GPSR5_HCTS0		BIT(15)
+#define GPSR5_HTX0		BIT(14)
+#define GPSR5_HRX0		BIT(13)
+#define GPSR5_HSCK0		BIT(12)
+#define GPSR5_RX2_A		BIT(11)
+#define GPSR5_TX2_A		BIT(10)
+#define GPSR5_SCK2		BIT(9)
+#define GPSR5_RTS1		BIT(8)
+#define GPSR5_CTS1		BIT(7)
+#define GPSR5_TX1_A		BIT(6)
+#define GPSR5_RX1_A		BIT(5)
+#define GPSR5_RTS0		BIT(4)
+#define GPSR5_CTS0		BIT(3)
+#define GPSR5_TX0		BIT(2)
+#define GPSR5_RX0		BIT(1)
+#define GPSR5_SCK0		BIT(0)
+#define GPSR6_USB31_OVC		BIT(31)
+#define GPSR6_USB31_PWEN	BIT(30)
+#define GPSR6_USB30_OVC		BIT(29)
+#define GPSR6_USB30_PWEN	BIT(28)
+#define GPSR6_USB1_OVC		BIT(27)
+#define GPSR6_USB1_PWEN		BIT(26)
+#define GPSR6_USB0_OVC		BIT(25)
+#define GPSR6_USB0_PWEN		BIT(24)
+#define GPSR6_AUDIO_CLKB_B	BIT(23)
+#define GPSR6_AUDIO_CLKA_A	BIT(22)
+#define GPSR6_SSI_SDATA9_A	BIT(21)
+#define GPSR6_SSI_SDATA8	BIT(20)
+#define GPSR6_SSI_SDATA7	BIT(19)
+#define GPSR6_SSI_WS78		BIT(18)
+#define GPSR6_SSI_SCK78		BIT(17)
+#define GPSR6_SSI_SDATA6	BIT(16)
+#define GPSR6_SSI_WS6		BIT(15)
+#define GPSR6_SSI_SCK6		BIT(14)
+#define GPSR6_SSI_SDATA5	BIT(13)
+#define GPSR6_SSI_WS5		BIT(12)
+#define GPSR6_SSI_SCK5		BIT(11)
+#define GPSR6_SSI_SDATA4	BIT(10)
+#define GPSR6_SSI_WS4		BIT(9)
+#define GPSR6_SSI_SCK4		BIT(8)
+#define GPSR6_SSI_SDATA3	BIT(7)
+#define GPSR6_SSI_WS34		BIT(6)
+#define GPSR6_SSI_SCK34		BIT(5)
+#define GPSR6_SSI_SDATA2_A	BIT(4)
+#define GPSR6_SSI_SDATA1_A	BIT(3)
+#define GPSR6_SSI_SDATA0	BIT(2)
+#define GPSR6_SSI_WS0129	BIT(1)
+#define GPSR6_SSI_SCK0129	BIT(0)
+#define GPSR7_AVS2		BIT(1)
+#define GPSR7_AVS1		BIT(0)
+
+#define IPSR_28_FUNC(x)		((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)		((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)		((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)		((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)		((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)		((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)		((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)		((uint32_t)(x) << 0U)
+
+#define POC_SD3_DS_33V		BIT(29)
+#define POC_SD3_DAT7_33V	BIT(28)
+#define POC_SD3_DAT6_33V	BIT(27)
+#define POC_SD3_DAT5_33V	BIT(26)
+#define POC_SD3_DAT4_33V	BIT(25)
+#define POC_SD3_DAT3_33V	BIT(24)
+#define POC_SD3_DAT2_33V	BIT(23)
+#define POC_SD3_DAT1_33V	BIT(22)
+#define POC_SD3_DAT0_33V	BIT(21)
+#define POC_SD3_CMD_33V		BIT(20)
+#define POC_SD3_CLK_33V		BIT(19)
+#define POC_SD2_DS_33V		BIT(18)
+#define POC_SD2_DAT3_33V	BIT(17)
+#define POC_SD2_DAT2_33V	BIT(16)
+#define POC_SD2_DAT1_33V	BIT(15)
+#define POC_SD2_DAT0_33V	BIT(14)
+#define POC_SD2_CMD_33V		BIT(13)
+#define POC_SD2_CLK_33V		BIT(12)
+#define POC_SD1_DAT3_33V	BIT(11)
+#define POC_SD1_DAT2_33V	BIT(10)
+#define POC_SD1_DAT1_33V	BIT(9)
+#define POC_SD1_DAT0_33V	BIT(8)
+#define POC_SD1_CMD_33V		BIT(7)
+#define POC_SD1_CLK_33V		BIT(6)
+#define POC_SD0_DAT3_33V	BIT(5)
+#define POC_SD0_DAT2_33V	BIT(4)
+#define POC_SD0_DAT1_33V	BIT(3)
+#define POC_SD0_DAT0_33V	BIT(2)
+#define POC_SD0_CMD_33V		BIT(1)
+#define POC_SD0_CLK_33V		BIT(0)
+
+#define DRVCTRL0_MASK		(0xCCCCCCCCU)
+#define DRVCTRL1_MASK		(0xCCCCCCC8U)
+#define DRVCTRL2_MASK		(0x88888888U)
+#define DRVCTRL3_MASK		(0x88888888U)
+#define DRVCTRL4_MASK		(0x88888888U)
+#define DRVCTRL5_MASK		(0x88888888U)
+#define DRVCTRL6_MASK		(0x88888888U)
+#define DRVCTRL7_MASK		(0x88888888U)
+#define DRVCTRL8_MASK		(0x88888888U)
+#define DRVCTRL9_MASK		(0x88888888U)
+#define DRVCTRL10_MASK		(0x88888888U)
+#define DRVCTRL11_MASK		(0x888888CCU)
+#define DRVCTRL12_MASK		(0xCCCFFFCFU)
+#define DRVCTRL13_MASK		(0xCC888888U)
+#define DRVCTRL14_MASK		(0x88888888U)
+#define DRVCTRL15_MASK		(0x88888888U)
+#define DRVCTRL16_MASK		(0x88888888U)
+#define DRVCTRL17_MASK		(0x88888888U)
+#define DRVCTRL18_MASK		(0x88888888U)
+#define DRVCTRL19_MASK		(0x88888888U)
+#define DRVCTRL20_MASK		(0x88888888U)
+#define DRVCTRL21_MASK		(0x88888888U)
+#define DRVCTRL22_MASK		(0x88888888U)
+#define DRVCTRL23_MASK		(0x88888888U)
+#define DRVCTRL24_MASK		(0x8888888FU)
+
+#define DRVCTRL0_QSPI0_SPCLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL0_QSPI0_MOSI_IO0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL0_QSPI0_MISO_IO1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL0_QSPI0_IO2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL0_QSPI0_IO3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL0_QSPI0_SSL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL0_QSPI1_SPCLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL0_QSPI1_MOSI_IO0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL1_QSPI1_MISO_IO1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL1_QSPI1_IO2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL1_QSPI1_IO3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL1_QSPI1_SS(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL1_RPC_INT(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL1_RPC_WP(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL1_RPC_RESET(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL1_AVB_RX_CTL(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL2_AVB_RXC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL2_AVB_RD0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL2_AVB_RD1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL2_AVB_RD2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL2_AVB_RD3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL2_AVB_TX_CTL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL2_AVB_TXC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL2_AVB_TD0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL3_AVB_TD1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL3_AVB_TD2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL3_AVB_TD3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL3_AVB_TXCREFCLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL3_AVB_MDIO(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL3_AVB_MDC(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL3_AVB_MAGIC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL3_AVB_PHY_INT(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL4_AVB_LINK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL4_AVB_AVTP_MATCH(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL4_AVB_AVTP_CAPTURE(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL4_IRQ0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL4_IRQ1(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL4_IRQ2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL4_IRQ3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL4_IRQ4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL5_IRQ5(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL5_PWM0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL5_PWM1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL5_PWM2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL5_A0(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL5_A1(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL5_A2(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL5_A3(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL6_A4(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL6_A5(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL6_A6(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL6_A7(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL6_A8(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL6_A9(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL6_A10(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL6_A11(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL7_A12(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL7_A13(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL7_A14(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL7_A15(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL7_A16(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL7_A17(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL7_A18(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL7_A19(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL8_CLKOUT(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL8_CS0(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL8_CS1_A2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL8_BS(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL8_RD(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL8_RD_W(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL8_WE0(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL8_WE1(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL9_EX_WAIT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL9_PRESETOU(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL9_D0(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL9_D1(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL9_D2(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL9_D3(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL9_D4(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL9_D5(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL10_D6(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL10_D7(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL10_D8(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL10_D9(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL10_D10(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL10_D11(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL10_D12(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL10_D13(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL11_D14(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL11_D15(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL11_AVS1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL11_AVS2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL11_GP7_02(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL11_GP7_03(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL11_DU_DOTCLKIN0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL11_DU_DOTCLKIN1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL12_DU_DOTCLKIN2(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL12_DU_DOTCLKIN3(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL12_DU_FSCLKST(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL12_DU_TMS(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_TDO(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL13_ASEBRK(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL13_SD0_CLK(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL13_SD0_CMD(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL13_SD0_DAT0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL13_SD0_DAT1(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL13_SD0_DAT2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_SD0_DAT3(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL14_SD1_CLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL14_SD1_CMD(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL14_SD1_DAT0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL14_SD1_DAT1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL14_SD1_DAT2(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL14_SD1_DAT3(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL14_SD2_CLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL14_SD2_CMD(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL15_SD2_DAT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL15_SD2_DAT1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL15_SD2_DAT2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL15_SD2_DAT3(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL15_SD2_DS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL15_SD3_CLK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL15_SD3_CMD(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL15_SD3_DAT0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL16_SD3_DAT1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL16_SD3_DAT2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL16_SD3_DAT3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL16_SD3_DAT4(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL16_SD3_DAT5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL16_SD3_DAT6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL16_SD3_DAT7(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL16_SD3_DS(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL17_SD0_CD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL17_SD0_WP(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL17_SD1_CD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL17_SD1_WP(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL17_SCK0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL17_RX0(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL17_TX0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL17_CTS0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL18_RTS0_TANS(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL18_RX1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL18_TX1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL18_CTS1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL18_RTS1_TANS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL18_SCK2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL18_TX2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL18_RX2(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL19_HSCK0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL19_HRX0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL19_HTX0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL19_HCTS0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL19_HRTS0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL19_MSIOF0_SCK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL19_MSIOF0_SYNC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL19_MSIOF0_SS1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL20_MSIOF0_TXD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL20_MSIOF0_SS2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL20_MSIOF0_RXD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL20_MLB_CLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL20_MLB_SIG(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL20_MLB_DAT(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL20_MLB_REF(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL20_SSI_SCK0129(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL21_SSI_WS0129(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL21_SSI_SDATA0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL21_SSI_SDATA1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL21_SSI_SDATA2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL21_SSI_SCK34(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL21_SSI_WS34(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL21_SSI_SDATA3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL21_SSI_SCK4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL22_SSI_WS4(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL22_SSI_SDATA4(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL22_SSI_SCK5(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL22_SSI_WS5(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL22_SSI_SDATA5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL22_SSI_SCK6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL22_SSI_WS6(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL22_SSI_SDATA6(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL23_SSI_SCK78(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL23_SSI_WS78(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL23_SSI_SDATA7(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL23_SSI_SDATA8(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL23_SSI_SDATA9(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL23_AUDIO_CLKA(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL23_AUDIO_CLKB(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL23_USB0_PWEN(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL24_USB0_OVC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL24_USB1_PWEN(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL24_USB1_OVC(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL24_USB30_PWEN(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL24_USB30_OVC(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL24_USB31_PWEN(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL24_USB31_OVC(x)	((uint32_t)(x) << 4U)
+
+#define MOD_SEL0_MSIOF3_A	((uint32_t)0U << 29U)
+#define MOD_SEL0_MSIOF3_B	((uint32_t)1U << 29U)
+#define MOD_SEL0_MSIOF3_C	((uint32_t)2U << 29U)
+#define MOD_SEL0_MSIOF3_D	((uint32_t)3U << 29U)
+#define MOD_SEL0_MSIOF3_E	((uint32_t)4U << 29U)
+#define MOD_SEL0_MSIOF2_A	((uint32_t)0U << 27U)
+#define MOD_SEL0_MSIOF2_B	((uint32_t)1U << 27U)
+#define MOD_SEL0_MSIOF2_C	((uint32_t)2U << 27U)
+#define MOD_SEL0_MSIOF2_D	((uint32_t)3U << 27U)
+#define MOD_SEL0_MSIOF1_A	((uint32_t)0U << 24U)
+#define MOD_SEL0_MSIOF1_B	((uint32_t)1U << 24U)
+#define MOD_SEL0_MSIOF1_C	((uint32_t)2U << 24U)
+#define MOD_SEL0_MSIOF1_D	((uint32_t)3U << 24U)
+#define MOD_SEL0_MSIOF1_E	((uint32_t)4U << 24U)
+#define MOD_SEL0_MSIOF1_F	((uint32_t)5U << 24U)
+#define MOD_SEL0_MSIOF1_G	((uint32_t)6U << 24U)
+#define MOD_SEL0_LBSC_A		((uint32_t)0U << 23U)
+#define MOD_SEL0_LBSC_B		((uint32_t)1U << 23U)
+#define MOD_SEL0_IEBUS_A	((uint32_t)0U << 22U)
+#define MOD_SEL0_IEBUS_B	((uint32_t)1U << 22U)
+#define MOD_SEL0_I2C2_A		((uint32_t)0U << 21U)
+#define MOD_SEL0_I2C2_B		((uint32_t)1U << 21U)
+#define MOD_SEL0_I2C1_A		((uint32_t)0U << 20U)
+#define MOD_SEL0_I2C1_B		((uint32_t)1U << 20U)
+#define MOD_SEL0_HSCIF4_A	((uint32_t)0U << 19U)
+#define MOD_SEL0_HSCIF4_B	((uint32_t)1U << 19U)
+#define MOD_SEL0_HSCIF3_A	((uint32_t)0U << 17U)
+#define MOD_SEL0_HSCIF3_B	((uint32_t)1U << 17U)
+#define MOD_SEL0_HSCIF3_C	((uint32_t)2U << 17U)
+#define MOD_SEL0_HSCIF3_D	((uint32_t)3U << 17U)
+#define MOD_SEL0_HSCIF1_A	((uint32_t)0U << 16U)
+#define MOD_SEL0_HSCIF1_B	((uint32_t)1U << 16U)
+#define MOD_SEL0_FSO_A		((uint32_t)0U << 15U)
+#define MOD_SEL0_FSO_B		((uint32_t)1U << 15U)
+#define MOD_SEL0_HSCIF2_A	((uint32_t)0U << 13U)
+#define MOD_SEL0_HSCIF2_B	((uint32_t)1U << 13U)
+#define MOD_SEL0_HSCIF2_C	((uint32_t)2U << 13U)
+#define MOD_SEL0_ETHERAVB_A	((uint32_t)0U << 12U)
+#define MOD_SEL0_ETHERAVB_B	((uint32_t)1U << 12U)
+#define MOD_SEL0_DRIF3_A	((uint32_t)0U << 11U)
+#define MOD_SEL0_DRIF3_B	((uint32_t)1U << 11U)
+#define MOD_SEL0_DRIF2_A	((uint32_t)0U << 10U)
+#define MOD_SEL0_DRIF2_B	((uint32_t)1U << 10U)
+#define MOD_SEL0_DRIF1_A	((uint32_t)0U << 8U)
+#define MOD_SEL0_DRIF1_B	((uint32_t)1U << 8U)
+#define MOD_SEL0_DRIF1_C	((uint32_t)2U << 8U)
+#define MOD_SEL0_DRIF0_A	((uint32_t)0U << 6U)
+#define MOD_SEL0_DRIF0_B	((uint32_t)1U << 6U)
+#define MOD_SEL0_DRIF0_C	((uint32_t)2U << 6U)
+#define MOD_SEL0_CANFD0_A	((uint32_t)0U << 5U)
+#define MOD_SEL0_CANFD0_B	((uint32_t)1U << 5U)
+#define MOD_SEL0_ADG_A_A	((uint32_t)0U << 3U)
+#define MOD_SEL0_ADG_A_B	((uint32_t)1U << 3U)
+#define MOD_SEL0_ADG_A_C	((uint32_t)2U << 3U)
+#define MOD_SEL1_TSIF1_A	((uint32_t)0U << 30U)
+#define MOD_SEL1_TSIF1_B	((uint32_t)1U << 30U)
+#define MOD_SEL1_TSIF1_C	((uint32_t)2U << 30U)
+#define MOD_SEL1_TSIF1_D	((uint32_t)3U << 30U)
+#define MOD_SEL1_TSIF0_A	((uint32_t)0U << 27U)
+#define MOD_SEL1_TSIF0_B	((uint32_t)1U << 27U)
+#define MOD_SEL1_TSIF0_C	((uint32_t)2U << 27U)
+#define MOD_SEL1_TSIF0_D	((uint32_t)3U << 27U)
+#define MOD_SEL1_TSIF0_E	((uint32_t)4U << 27U)
+#define MOD_SEL1_TIMER_TMU_A	((uint32_t)0U << 26U)
+#define MOD_SEL1_TIMER_TMU_B	((uint32_t)1U << 26U)
+#define MOD_SEL1_SSP1_1_A	((uint32_t)0U << 24U)
+#define MOD_SEL1_SSP1_1_B	((uint32_t)1U << 24U)
+#define MOD_SEL1_SSP1_1_C	((uint32_t)2U << 24U)
+#define MOD_SEL1_SSP1_1_D	((uint32_t)3U << 24U)
+#define MOD_SEL1_SSP1_0_A	((uint32_t)0U << 21U)
+#define MOD_SEL1_SSP1_0_B	((uint32_t)1U << 21U)
+#define MOD_SEL1_SSP1_0_C	((uint32_t)2U << 21U)
+#define MOD_SEL1_SSP1_0_D	((uint32_t)3U << 21U)
+#define MOD_SEL1_SSP1_0_E	((uint32_t)4U << 21U)
+#define MOD_SEL1_SSI_A		((uint32_t)0U << 20U)
+#define MOD_SEL1_SSI_B		((uint32_t)1U << 20U)
+#define MOD_SEL1_SPEED_PULSE_IF_A	((uint32_t)0U << 19U)
+#define MOD_SEL1_SPEED_PULSE_IF_B	((uint32_t)1U << 19U)
+#define MOD_SEL1_SIMCARD_A	((uint32_t)0U << 17U)
+#define MOD_SEL1_SIMCARD_B	((uint32_t)1U << 17U)
+#define MOD_SEL1_SIMCARD_C	((uint32_t)2U << 17U)
+#define MOD_SEL1_SIMCARD_D	((uint32_t)3U << 17U)
+#define MOD_SEL1_SDHI2_A	((uint32_t)0U << 16U)
+#define MOD_SEL1_SDHI2_B	((uint32_t)1U << 16U)
+#define MOD_SEL1_SCIF4_A	((uint32_t)0U << 14U)
+#define MOD_SEL1_SCIF4_B	((uint32_t)1U << 14U)
+#define MOD_SEL1_SCIF4_C	((uint32_t)2U << 14U)
+#define MOD_SEL1_SCIF3_A	((uint32_t)0U << 13U)
+#define MOD_SEL1_SCIF3_B	((uint32_t)1U << 13U)
+#define MOD_SEL1_SCIF2_A	((uint32_t)0U << 12U)
+#define MOD_SEL1_SCIF2_B	((uint32_t)1U << 12U)
+#define MOD_SEL1_SCIF1_A	((uint32_t)0U << 11U)
+#define MOD_SEL1_SCIF1_B	((uint32_t)1U << 11U)
+#define MOD_SEL1_SCIF_A		((uint32_t)0U << 10U)
+#define MOD_SEL1_SCIF_B		((uint32_t)1U << 10U)
+#define MOD_SEL1_REMOCON_A	((uint32_t)0U << 9U)
+#define MOD_SEL1_REMOCON_B	((uint32_t)1U << 9U)
+#define MOD_SEL1_RCAN0_A	((uint32_t)0U << 6U)
+#define MOD_SEL1_RCAN0_B	((uint32_t)1U << 6U)
+#define MOD_SEL1_PWM6_A		((uint32_t)0U << 5U)
+#define MOD_SEL1_PWM6_B		((uint32_t)1U << 5U)
+#define MOD_SEL1_PWM5_A		((uint32_t)0U << 4U)
+#define MOD_SEL1_PWM5_B		((uint32_t)1U << 4U)
+#define MOD_SEL1_PWM4_A		((uint32_t)0U << 3U)
+#define MOD_SEL1_PWM4_B		((uint32_t)1U << 3U)
+#define MOD_SEL1_PWM3_A		((uint32_t)0U << 2U)
+#define MOD_SEL1_PWM3_B		((uint32_t)1U << 2U)
+#define MOD_SEL1_PWM2_A		((uint32_t)0U << 1U)
+#define MOD_SEL1_PWM2_B		((uint32_t)1U << 1U)
+#define MOD_SEL1_PWM1_A		((uint32_t)0U << 0U)
+#define MOD_SEL1_PWM1_B		((uint32_t)1U << 0U)
+#define MOD_SEL2_I2C_5_A	((uint32_t)0U << 31U)
+#define MOD_SEL2_I2C_5_B	((uint32_t)1U << 31U)
+#define MOD_SEL2_I2C_3_A	((uint32_t)0U << 30U)
+#define MOD_SEL2_I2C_3_B	((uint32_t)1U << 30U)
+#define MOD_SEL2_I2C_0_A	((uint32_t)0U << 29U)
+#define MOD_SEL2_I2C_0_B	((uint32_t)1U << 29U)
+#define MOD_SEL2_FM_A		((uint32_t)0U << 27U)
+#define MOD_SEL2_FM_B		((uint32_t)1U << 27U)
+#define MOD_SEL2_FM_C		((uint32_t)2U << 27U)
+#define MOD_SEL2_FM_D		((uint32_t)3U << 27U)
+#define MOD_SEL2_SCIF5_A	((uint32_t)0U << 26U)
+#define MOD_SEL2_SCIF5_B	((uint32_t)1U << 26U)
+#define MOD_SEL2_I2C6_A		((uint32_t)0U << 23U)
+#define MOD_SEL2_I2C6_B		((uint32_t)1U << 23U)
+#define MOD_SEL2_I2C6_C		((uint32_t)2U << 23U)
+#define MOD_SEL2_NDF_A		((uint32_t)0U << 22U)
+#define MOD_SEL2_NDF_B		((uint32_t)1U << 22U)
+#define MOD_SEL2_SSI2_A		((uint32_t)0U << 21U)
+#define MOD_SEL2_SSI2_B		((uint32_t)1U << 21U)
+#define MOD_SEL2_SSI9_A		((uint32_t)0U << 20U)
+#define MOD_SEL2_SSI9_B		((uint32_t)1U << 20U)
+#define MOD_SEL2_TIMER_TMU2_A	((uint32_t)0U << 19U)
+#define MOD_SEL2_TIMER_TMU2_B	((uint32_t)1U << 19U)
+#define MOD_SEL2_ADG_B_A	((uint32_t)0U << 18U)
+#define MOD_SEL2_ADG_B_B	((uint32_t)1U << 18U)
+#define MOD_SEL2_ADG_C_A	((uint32_t)0U << 17U)
+#define MOD_SEL2_ADG_C_B	((uint32_t)1U << 17U)
+#define MOD_SEL2_VIN4_A		((uint32_t)0U << 0U)
+#define MOD_SEL2_VIN4_B		((uint32_t)1U << 0U)
+
+/* SCIF3 Registers for Dummy write */
+#define SCIF3_BASE		(0xE6C50000U)
+#define SCIF3_SCFCR		(SCIF3_BASE + 0x0018U)
+#define SCIF3_SCFDR		(SCIF3_BASE + 0x001CU)
+#define SCFCR_DATA		(0x0000U)
+
+/* Realtime module stop control */
+#define CPG_BASE		(0xE6150000U)
+#define CPG_SCMSTPCR0		(CPG_BASE + 0x0B20U)
+#define CPG_MSTPSR0		(CPG_BASE + 0x0030U)
+#define SCMSTPCR0_RTDMAC	(0x00200000U)
+
+/* RT-DMAC Registers */
+#define RTDMAC_CH		(0U)	/* choose 0 to 15 */
+
+#define RTDMAC_BASE		(0xFFC10000U)
+#define RTDMAC_RDMOR		(RTDMAC_BASE + 0x0060U)
+#define RTDMAC_RDMCHCLR		(RTDMAC_BASE + 0x0080U)
+#define RTDMAC_RDMSAR(x)	(RTDMAC_BASE + 0x8000U + (0x80U * (x)))
+#define RTDMAC_RDMDAR(x)	(RTDMAC_BASE + 0x8004U + (0x80U * (x)))
+#define RTDMAC_RDMTCR(x)	(RTDMAC_BASE + 0x8008U + (0x80U * (x)))
+#define RTDMAC_RDMCHCR(x)	(RTDMAC_BASE + 0x800CU + (0x80U * (x)))
+#define RTDMAC_RDMCHCRB(x)	(RTDMAC_BASE + 0x801CU + (0x80U * (x)))
+#define RTDMAC_RDMDPBASE(x)	(RTDMAC_BASE + 0x8050U + (0x80U * (x)))
+#define RTDMAC_DESC_BASE	(RTDMAC_BASE + 0xA000U)
+#define RTDMAC_DESC_RDMSAR	(RTDMAC_DESC_BASE + 0x0000U)
+#define RTDMAC_DESC_RDMDAR	(RTDMAC_DESC_BASE + 0x0004U)
+#define RTDMAC_DESC_RDMTCR	(RTDMAC_DESC_BASE + 0x0008U)
+
+#define RDMOR_DME		(0x0001U)	/* DMA Master Enable */
+#define RDMCHCR_DPM_INFINITE	(0x30000000U)	/* Infinite repeat mode */
+#define RDMCHCR_RPT_TCR		(0x02000000U)	/* enable to update TCR */
+#define RDMCHCR_TS_2		(0x00000008U)	/* Word(2byte) units transfer */
+#define RDMCHCR_RS_AUTO		(0x00000400U)	/* Auto request */
+#define RDMCHCR_DE		(0x00000001U)	/* DMA Enable */
+#define RDMCHCRB_DRST		(0x00008000U)	/* Descriptor reset */
+#define RDMCHCRB_SLM_256	(0x00000080U)	/* once in 256 clock cycle */
+#define RDMDPBASE_SEL_EXT	(0x00000001U)	/* External memory use */
+
+static void start_rtdma0_descriptor(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(RCAR_PRR);
+	reg &= (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	if (reg == (RCAR_PRODUCT_M3_CUT10)) {
+		/* Enable clock supply to RTDMAC. */
+		mstpcr_write(CPG_SCMSTPCR0, CPG_MSTPSR0, SCMSTPCR0_RTDMAC);
+
+		/* Initialize ch0, Reset Descriptor */
+		mmio_write_32(RTDMAC_RDMCHCLR, BIT(RTDMAC_CH));
+		mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_DRST);
+
+		/* Enable DMA */
+		mmio_write_16(RTDMAC_RDMOR, RDMOR_DME);
+
+		/* Set first transfer */
+		mmio_write_32(RTDMAC_RDMSAR(RTDMAC_CH), RCAR_PRR);
+		mmio_write_32(RTDMAC_RDMDAR(RTDMAC_CH), SCIF3_SCFDR);
+		mmio_write_32(RTDMAC_RDMTCR(RTDMAC_CH), 0x00000001U);
+
+		/* Set descriptor */
+		mmio_write_32(RTDMAC_DESC_RDMSAR, 0x00000000U);
+		mmio_write_32(RTDMAC_DESC_RDMDAR, 0x00000000U);
+		mmio_write_32(RTDMAC_DESC_RDMTCR, 0x00200000U);
+		mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_SLM_256);
+		mmio_write_32(RTDMAC_RDMDPBASE(RTDMAC_CH), RTDMAC_DESC_BASE
+			      | RDMDPBASE_SEL_EXT);
+
+		/* Set transfer parameter, Start transfer */
+		mmio_write_32(RTDMAC_RDMCHCR(RTDMAC_CH), RDMCHCR_DPM_INFINITE
+			      | RDMCHCR_RPT_TCR
+			      | RDMCHCR_TS_2
+			      | RDMCHCR_RS_AUTO
+			      | RDMCHCR_DE);
+	}
+}
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	uint32_t prr;
+
+	prr = mmio_read_32(RCAR_PRR);
+	prr &= (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+
+	mmio_write_32(PFC_PMMR, ~data);
+	if (prr == (RCAR_PRODUCT_M3_CUT10)) {
+		mmio_write_16(SCIF3_SCFCR, SCFCR_DATA);	/* Dummy write */
+	}
+	mmio_write_32((uintptr_t)addr, data);
+	if (prr == (RCAR_PRODUCT_M3_CUT10)) {
+		mmio_write_16(SCIF3_SCFCR, SCFCR_DATA);	/* Dummy write */
+	}
+}
+
+void pfc_init_m3(void)
+{
+	uint32_t reg;
+
+	/* Work around for PFC eratta */
+	start_rtdma0_descriptor();
+
+	/* initialize module select */
+	pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A
+		      | MOD_SEL0_MSIOF2_A
+		      | MOD_SEL0_MSIOF1_A
+		      | MOD_SEL0_LBSC_A
+		      | MOD_SEL0_IEBUS_A
+		      | MOD_SEL0_I2C2_A
+		      | MOD_SEL0_I2C1_A
+		      | MOD_SEL0_HSCIF4_A
+		      | MOD_SEL0_HSCIF3_A
+		      | MOD_SEL0_HSCIF1_A
+		      | MOD_SEL0_FSO_A
+		      | MOD_SEL0_HSCIF2_A
+		      | MOD_SEL0_ETHERAVB_A
+		      | MOD_SEL0_DRIF3_A
+		      | MOD_SEL0_DRIF2_A
+		      | MOD_SEL0_DRIF1_A
+		      | MOD_SEL0_DRIF0_A
+		      | MOD_SEL0_CANFD0_A
+		      | MOD_SEL0_ADG_A_A);
+	pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A
+		      | MOD_SEL1_TSIF0_A
+		      | MOD_SEL1_TIMER_TMU_A
+		      | MOD_SEL1_SSP1_1_A
+		      | MOD_SEL1_SSP1_0_A
+		      | MOD_SEL1_SSI_A
+		      | MOD_SEL1_SPEED_PULSE_IF_A
+		      | MOD_SEL1_SIMCARD_A
+		      | MOD_SEL1_SDHI2_A
+		      | MOD_SEL1_SCIF4_A
+		      | MOD_SEL1_SCIF3_A
+		      | MOD_SEL1_SCIF2_A
+		      | MOD_SEL1_SCIF1_A
+		      | MOD_SEL1_SCIF_A
+		      | MOD_SEL1_REMOCON_A
+		      | MOD_SEL1_RCAN0_A
+		      | MOD_SEL1_PWM6_A
+		      | MOD_SEL1_PWM5_A
+		      | MOD_SEL1_PWM4_A
+		      | MOD_SEL1_PWM3_A
+		      | MOD_SEL1_PWM2_A
+		      | MOD_SEL1_PWM1_A);
+	pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A
+		      | MOD_SEL2_I2C_3_A
+		      | MOD_SEL2_I2C_0_A
+		      | MOD_SEL2_FM_A
+		      | MOD_SEL2_SCIF5_A
+		      | MOD_SEL2_I2C6_A
+		      | MOD_SEL2_NDF_A
+		      | MOD_SEL2_SSI2_A
+		      | MOD_SEL2_SSI9_A
+		      | MOD_SEL2_TIMER_TMU2_A
+		      | MOD_SEL2_ADG_B_A
+		      | MOD_SEL2_ADG_C_A
+		      | MOD_SEL2_VIN4_A);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(3)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(3));
+	pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(1)
+		      | IPSR_20_FUNC(1)
+		      | IPSR_16_FUNC(1)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(4)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(1));
+	pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(4)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(8)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(8));
+	pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR17, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(1)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR18, IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+
+	/* initialize GPIO/perihperal function select */
+	pfc_reg_write(PFC_GPSR0, GPSR0_D15
+		      | GPSR0_D14
+		      | GPSR0_D13
+		      | GPSR0_D12
+		      | GPSR0_D11
+		      | GPSR0_D10
+		      | GPSR0_D9
+		      | GPSR0_D8);
+	pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT
+		      | GPSR1_EX_WAIT0_A
+		      | GPSR1_A19
+		      | GPSR1_A18
+		      | GPSR1_A17
+		      | GPSR1_A16
+		      | GPSR1_A15
+		      | GPSR1_A14
+		      | GPSR1_A13
+		      | GPSR1_A12
+		      | GPSR1_A7
+		      | GPSR1_A6
+		      | GPSR1_A5
+		      | GPSR1_A4
+		      | GPSR1_A3
+		      | GPSR1_A2
+		      | GPSR1_A1
+		      | GPSR1_A0);
+	pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A
+		      | GPSR2_AVB_AVTP_MATCH_A
+		      | GPSR2_AVB_LINK
+		      | GPSR2_AVB_PHY_INT
+		      | GPSR2_AVB_MDC
+		      | GPSR2_PWM2_A
+		      | GPSR2_PWM1_A
+		      | GPSR2_IRQ5
+		      | GPSR2_IRQ4
+		      | GPSR2_IRQ3
+		      | GPSR2_IRQ2
+		      | GPSR2_IRQ1
+		      | GPSR2_IRQ0);
+	pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP
+		      | GPSR3_SD0_CD
+		      | GPSR3_SD1_DAT3
+		      | GPSR3_SD1_DAT2
+		      | GPSR3_SD1_DAT1
+		      | GPSR3_SD1_DAT0
+		      | GPSR3_SD0_DAT3
+		      | GPSR3_SD0_DAT2
+		      | GPSR3_SD0_DAT1
+		      | GPSR3_SD0_DAT0
+		      | GPSR3_SD0_CMD
+		      | GPSR3_SD0_CLK);
+	pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7
+		      | GPSR4_SD3_DAT6
+		      | GPSR4_SD3_DAT3
+		      | GPSR4_SD3_DAT2
+		      | GPSR4_SD3_DAT1
+		      | GPSR4_SD3_DAT0
+		      | GPSR4_SD3_CMD
+		      | GPSR4_SD3_CLK
+		      | GPSR4_SD2_DS
+		      | GPSR4_SD2_DAT3
+		      | GPSR4_SD2_DAT2
+		      | GPSR4_SD2_DAT1
+		      | GPSR4_SD2_DAT0
+		      | GPSR4_SD2_CMD
+		      | GPSR4_SD2_CLK);
+	pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2
+		      | GPSR5_MSIOF0_SS1
+		      | GPSR5_MSIOF0_SYNC
+		      | GPSR5_HRTS0
+		      | GPSR5_HCTS0
+		      | GPSR5_HTX0
+		      | GPSR5_HRX0
+		      | GPSR5_HSCK0
+		      | GPSR5_RX2_A
+		      | GPSR5_TX2_A
+		      | GPSR5_SCK2
+		      | GPSR5_RTS1
+		      | GPSR5_CTS1
+		      | GPSR5_TX1_A
+		      | GPSR5_RX1_A
+		      | GPSR5_RTS0
+		      | GPSR5_SCK0);
+	pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC
+		      | GPSR6_USB30_PWEN
+		      | GPSR6_USB1_OVC
+		      | GPSR6_USB1_PWEN
+		      | GPSR6_USB0_OVC
+		      | GPSR6_USB0_PWEN
+		      | GPSR6_AUDIO_CLKB_B
+		      | GPSR6_AUDIO_CLKA_A
+		      | GPSR6_SSI_SDATA8
+		      | GPSR6_SSI_SDATA7
+		      | GPSR6_SSI_WS78
+		      | GPSR6_SSI_SCK78
+		      | GPSR6_SSI_WS6
+		      | GPSR6_SSI_SCK6
+		      | GPSR6_SSI_SDATA4
+		      | GPSR6_SSI_WS4
+		      | GPSR6_SSI_SCK4
+		      | GPSR6_SSI_SDATA1_A
+		      | GPSR6_SSI_SDATA0
+		      | GPSR6_SSI_WS0129
+		      | GPSR6_SSI_SCK0129);
+	pfc_reg_write(PFC_GPSR7, GPSR7_AVS2
+		      | GPSR7_AVS1);
+
+	/* initialize POC control register */
+	pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V
+		      | POC_SD3_DAT7_33V
+		      | POC_SD3_DAT6_33V
+		      | POC_SD3_DAT5_33V
+		      | POC_SD3_DAT4_33V
+		      | POC_SD3_DAT3_33V
+		      | POC_SD3_DAT2_33V
+		      | POC_SD3_DAT1_33V
+		      | POC_SD3_DAT0_33V
+		      | POC_SD3_CMD_33V
+		      | POC_SD3_CLK_33V
+		      | POC_SD0_DAT3_33V
+		      | POC_SD0_DAT2_33V
+		      | POC_SD0_DAT1_33V
+		      | POC_SD0_DAT0_33V
+		      | POC_SD0_CMD_33V
+		      | POC_SD0_CLK_33V);
+
+	/* initialize DRV control register */
+	reg = mmio_read_32(PFC_DRVCTRL0);
+	reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3)
+	       | DRVCTRL0_QSPI0_MOSI_IO0(3)
+	       | DRVCTRL0_QSPI0_MISO_IO1(3)
+	       | DRVCTRL0_QSPI0_IO2(3)
+	       | DRVCTRL0_QSPI0_IO3(3)
+	       | DRVCTRL0_QSPI0_SSL(3)
+	       | DRVCTRL0_QSPI1_SPCLK(3)
+	       | DRVCTRL0_QSPI1_MOSI_IO0(3));
+	pfc_reg_write(PFC_DRVCTRL0, reg);
+	reg = mmio_read_32(PFC_DRVCTRL1);
+	reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3)
+	       | DRVCTRL1_QSPI1_IO2(3)
+	       | DRVCTRL1_QSPI1_IO3(3)
+	       | DRVCTRL1_QSPI1_SS(3)
+	       | DRVCTRL1_RPC_INT(3)
+	       | DRVCTRL1_RPC_WP(3)
+	       | DRVCTRL1_RPC_RESET(3)
+	       | DRVCTRL1_AVB_RX_CTL(7));
+	pfc_reg_write(PFC_DRVCTRL1, reg);
+	reg = mmio_read_32(PFC_DRVCTRL2);
+	reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7)
+	       | DRVCTRL2_AVB_RD0(7)
+	       | DRVCTRL2_AVB_RD1(7)
+	       | DRVCTRL2_AVB_RD2(7)
+	       | DRVCTRL2_AVB_RD3(7)
+	       | DRVCTRL2_AVB_TX_CTL(3)
+	       | DRVCTRL2_AVB_TXC(3)
+	       | DRVCTRL2_AVB_TD0(3));
+	pfc_reg_write(PFC_DRVCTRL2, reg);
+	reg = mmio_read_32(PFC_DRVCTRL3);
+	reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3)
+	       | DRVCTRL3_AVB_TD2(3)
+	       | DRVCTRL3_AVB_TD3(3)
+	       | DRVCTRL3_AVB_TXCREFCLK(7)
+	       | DRVCTRL3_AVB_MDIO(7)
+	       | DRVCTRL3_AVB_MDC(7)
+	       | DRVCTRL3_AVB_MAGIC(7)
+	       | DRVCTRL3_AVB_PHY_INT(7));
+	pfc_reg_write(PFC_DRVCTRL3, reg);
+	reg = mmio_read_32(PFC_DRVCTRL4);
+	reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7)
+	       | DRVCTRL4_AVB_AVTP_MATCH(7)
+	       | DRVCTRL4_AVB_AVTP_CAPTURE(7)
+	       | DRVCTRL4_IRQ0(7)
+	       | DRVCTRL4_IRQ1(7)
+	       | DRVCTRL4_IRQ2(7)
+	       | DRVCTRL4_IRQ3(7)
+	       | DRVCTRL4_IRQ4(7));
+	pfc_reg_write(PFC_DRVCTRL4, reg);
+	reg = mmio_read_32(PFC_DRVCTRL5);
+	reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7)
+	       | DRVCTRL5_PWM0(7)
+	       | DRVCTRL5_PWM1(7)
+	       | DRVCTRL5_PWM2(7)
+	       | DRVCTRL5_A0(3)
+	       | DRVCTRL5_A1(3)
+	       | DRVCTRL5_A2(3)
+	       | DRVCTRL5_A3(3));
+	pfc_reg_write(PFC_DRVCTRL5, reg);
+	reg = mmio_read_32(PFC_DRVCTRL6);
+	reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3)
+	       | DRVCTRL6_A5(3)
+	       | DRVCTRL6_A6(3)
+	       | DRVCTRL6_A7(3)
+	       | DRVCTRL6_A8(7)
+	       | DRVCTRL6_A9(7)
+	       | DRVCTRL6_A10(7)
+	       | DRVCTRL6_A11(7));
+	pfc_reg_write(PFC_DRVCTRL6, reg);
+	reg = mmio_read_32(PFC_DRVCTRL7);
+	reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3)
+	       | DRVCTRL7_A13(3)
+	       | DRVCTRL7_A14(3)
+	       | DRVCTRL7_A15(3)
+	       | DRVCTRL7_A16(3)
+	       | DRVCTRL7_A17(3)
+	       | DRVCTRL7_A18(3)
+	       | DRVCTRL7_A19(3));
+	pfc_reg_write(PFC_DRVCTRL7, reg);
+	reg = mmio_read_32(PFC_DRVCTRL8);
+	reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7)
+	       | DRVCTRL8_CS0(7)
+	       | DRVCTRL8_CS1_A2(7)
+	       | DRVCTRL8_BS(7)
+	       | DRVCTRL8_RD(7)
+	       | DRVCTRL8_RD_W(7)
+	       | DRVCTRL8_WE0(7)
+	       | DRVCTRL8_WE1(7));
+	pfc_reg_write(PFC_DRVCTRL8, reg);
+	reg = mmio_read_32(PFC_DRVCTRL9);
+	reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7)
+	       | DRVCTRL9_PRESETOU(7)
+	       | DRVCTRL9_D0(7)
+	       | DRVCTRL9_D1(7)
+	       | DRVCTRL9_D2(7)
+	       | DRVCTRL9_D3(7)
+	       | DRVCTRL9_D4(7)
+	       | DRVCTRL9_D5(7));
+	pfc_reg_write(PFC_DRVCTRL9, reg);
+	reg = mmio_read_32(PFC_DRVCTRL10);
+	reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7)
+	       | DRVCTRL10_D7(7)
+	       | DRVCTRL10_D8(3)
+	       | DRVCTRL10_D9(3)
+	       | DRVCTRL10_D10(3)
+	       | DRVCTRL10_D11(3)
+	       | DRVCTRL10_D12(3)
+	       | DRVCTRL10_D13(3));
+	pfc_reg_write(PFC_DRVCTRL10, reg);
+	reg = mmio_read_32(PFC_DRVCTRL11);
+	reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3)
+	       | DRVCTRL11_D15(3)
+	       | DRVCTRL11_AVS1(7)
+	       | DRVCTRL11_AVS2(7)
+	       | DRVCTRL11_GP7_02(7)
+	       | DRVCTRL11_GP7_03(7)
+	       | DRVCTRL11_DU_DOTCLKIN0(3)
+	       | DRVCTRL11_DU_DOTCLKIN1(3));
+	pfc_reg_write(PFC_DRVCTRL11, reg);
+	reg = mmio_read_32(PFC_DRVCTRL12);
+	reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3)
+	       | DRVCTRL12_DU_DOTCLKIN3(3)
+	       | DRVCTRL12_DU_FSCLKST(3)
+	       | DRVCTRL12_DU_TMS(3));
+	pfc_reg_write(PFC_DRVCTRL12, reg);
+	reg = mmio_read_32(PFC_DRVCTRL13);
+	reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3)
+	       | DRVCTRL13_ASEBRK(3)
+	       | DRVCTRL13_SD0_CLK(7)
+	       | DRVCTRL13_SD0_CMD(7)
+	       | DRVCTRL13_SD0_DAT0(7)
+	       | DRVCTRL13_SD0_DAT1(7)
+	       | DRVCTRL13_SD0_DAT2(7)
+	       | DRVCTRL13_SD0_DAT3(7));
+	pfc_reg_write(PFC_DRVCTRL13, reg);
+	reg = mmio_read_32(PFC_DRVCTRL14);
+	reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7)
+	       | DRVCTRL14_SD1_CMD(7)
+	       | DRVCTRL14_SD1_DAT0(5)
+	       | DRVCTRL14_SD1_DAT1(5)
+	       | DRVCTRL14_SD1_DAT2(5)
+	       | DRVCTRL14_SD1_DAT3(5)
+	       | DRVCTRL14_SD2_CLK(5)
+	       | DRVCTRL14_SD2_CMD(5));
+	pfc_reg_write(PFC_DRVCTRL14, reg);
+	reg = mmio_read_32(PFC_DRVCTRL15);
+	reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5)
+	       | DRVCTRL15_SD2_DAT1(5)
+	       | DRVCTRL15_SD2_DAT2(5)
+	       | DRVCTRL15_SD2_DAT3(5)
+	       | DRVCTRL15_SD2_DS(5)
+	       | DRVCTRL15_SD3_CLK(7)
+	       | DRVCTRL15_SD3_CMD(7)
+	       | DRVCTRL15_SD3_DAT0(7));
+	pfc_reg_write(PFC_DRVCTRL15, reg);
+	reg = mmio_read_32(PFC_DRVCTRL16);
+	reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(7)
+	       | DRVCTRL16_SD3_DAT2(7)
+	       | DRVCTRL16_SD3_DAT3(7)
+	       | DRVCTRL16_SD3_DAT4(7)
+	       | DRVCTRL16_SD3_DAT5(7)
+	       | DRVCTRL16_SD3_DAT6(7)
+	       | DRVCTRL16_SD3_DAT7(7)
+	       | DRVCTRL16_SD3_DS(7));
+	pfc_reg_write(PFC_DRVCTRL16, reg);
+	reg = mmio_read_32(PFC_DRVCTRL17);
+	reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7)
+	       | DRVCTRL17_SD0_WP(7)
+	       | DRVCTRL17_SD1_CD(7)
+	       | DRVCTRL17_SD1_WP(7)
+	       | DRVCTRL17_SCK0(7)
+	       | DRVCTRL17_RX0(7)
+	       | DRVCTRL17_TX0(7)
+	       | DRVCTRL17_CTS0(7));
+	pfc_reg_write(PFC_DRVCTRL17, reg);
+	reg = mmio_read_32(PFC_DRVCTRL18);
+	reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7)
+	       | DRVCTRL18_RX1(7)
+	       | DRVCTRL18_TX1(7)
+	       | DRVCTRL18_CTS1(7)
+	       | DRVCTRL18_RTS1_TANS(7)
+	       | DRVCTRL18_SCK2(7)
+	       | DRVCTRL18_TX2(7)
+	       | DRVCTRL18_RX2(7));
+	pfc_reg_write(PFC_DRVCTRL18, reg);
+	reg = mmio_read_32(PFC_DRVCTRL19);
+	reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7)
+	       | DRVCTRL19_HRX0(7)
+	       | DRVCTRL19_HTX0(7)
+	       | DRVCTRL19_HCTS0(7)
+	       | DRVCTRL19_HRTS0(7)
+	       | DRVCTRL19_MSIOF0_SCK(7)
+	       | DRVCTRL19_MSIOF0_SYNC(7)
+	       | DRVCTRL19_MSIOF0_SS1(7));
+	pfc_reg_write(PFC_DRVCTRL19, reg);
+	reg = mmio_read_32(PFC_DRVCTRL20);
+	reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7)
+	       | DRVCTRL20_MSIOF0_SS2(7)
+	       | DRVCTRL20_MSIOF0_RXD(7)
+	       | DRVCTRL20_MLB_CLK(7)
+	       | DRVCTRL20_MLB_SIG(7)
+	       | DRVCTRL20_MLB_DAT(7)
+	       | DRVCTRL20_MLB_REF(7)
+	       | DRVCTRL20_SSI_SCK0129(7));
+	pfc_reg_write(PFC_DRVCTRL20, reg);
+	reg = mmio_read_32(PFC_DRVCTRL21);
+	reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7)
+	       | DRVCTRL21_SSI_SDATA0(7)
+	       | DRVCTRL21_SSI_SDATA1(7)
+	       | DRVCTRL21_SSI_SDATA2(7)
+	       | DRVCTRL21_SSI_SCK34(7)
+	       | DRVCTRL21_SSI_WS34(7)
+	       | DRVCTRL21_SSI_SDATA3(7)
+	       | DRVCTRL21_SSI_SCK4(7));
+	pfc_reg_write(PFC_DRVCTRL21, reg);
+	reg = mmio_read_32(PFC_DRVCTRL22);
+	reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7)
+	       | DRVCTRL22_SSI_SDATA4(7)
+	       | DRVCTRL22_SSI_SCK5(7)
+	       | DRVCTRL22_SSI_WS5(7)
+	       | DRVCTRL22_SSI_SDATA5(7)
+	       | DRVCTRL22_SSI_SCK6(7)
+	       | DRVCTRL22_SSI_WS6(7)
+	       | DRVCTRL22_SSI_SDATA6(7));
+	pfc_reg_write(PFC_DRVCTRL22, reg);
+	reg = mmio_read_32(PFC_DRVCTRL23);
+	reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7)
+	       | DRVCTRL23_SSI_WS78(7)
+	       | DRVCTRL23_SSI_SDATA7(7)
+	       | DRVCTRL23_SSI_SDATA8(7)
+	       | DRVCTRL23_SSI_SDATA9(7)
+	       | DRVCTRL23_AUDIO_CLKA(7)
+	       | DRVCTRL23_AUDIO_CLKB(7)
+	       | DRVCTRL23_USB0_PWEN(7));
+	pfc_reg_write(PFC_DRVCTRL23, reg);
+	reg = mmio_read_32(PFC_DRVCTRL24);
+	reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7)
+	       | DRVCTRL24_USB1_PWEN(7)
+	       | DRVCTRL24_USB1_OVC(7)
+	       | DRVCTRL24_USB30_PWEN(7)
+	       | DRVCTRL24_USB30_OVC(7)
+	       | DRVCTRL24_USB31_PWEN(7)
+	       | DRVCTRL24_USB31_OVC(7));
+	pfc_reg_write(PFC_DRVCTRL24, reg);
+
+	/* initialize LSI pin pull-up/down control */
+	pfc_reg_write(PFC_PUD0, 0x00005FBFU);
+	pfc_reg_write(PFC_PUD1, 0x00300FFEU);
+	pfc_reg_write(PFC_PUD2, 0x330001E6U);
+	pfc_reg_write(PFC_PUD3, 0x000002E0U);
+	pfc_reg_write(PFC_PUD4, 0xFFFFFF00U);
+	pfc_reg_write(PFC_PUD5, 0x7F5FFF87U);
+	pfc_reg_write(PFC_PUD6, 0x00000055U);
+
+	/* initialize LSI pin pull-enable register */
+	pfc_reg_write(PFC_PUEN0, 0x00000FFFU);
+	pfc_reg_write(PFC_PUEN1, 0x00100234U);
+	pfc_reg_write(PFC_PUEN2, 0x000004C4U);
+	pfc_reg_write(PFC_PUEN3, 0x00000200U);
+	pfc_reg_write(PFC_PUEN4, 0x3E000000U);
+	pfc_reg_write(PFC_PUEN5, 0x1F000805U);
+	pfc_reg_write(PFC_PUEN6, 0x00000006U);
+
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG6, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG7, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL6, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL7, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT1, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000400U);
+	mmio_write_32(GPIO_OUTDT3, 0x0000C000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00000006U);
+	mmio_write_32(GPIO_OUTDT6, 0x00003880U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x00000400U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00000000U);
+#if (RCAR_GEN3_ULCB == 1)
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU);
+#else
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU);
+#endif
+	mmio_write_32(GPIO_INOUTSEL6, 0x00013880U);
+	mmio_write_32(GPIO_INOUTSEL7, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h
new file mode 100644
index 0000000..70885de
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_M3_H
+#define PFC_INIT_M3_H
+
+void pfc_init_m3(void);
+
+#endif /* PFC_INIT_M3_H */
diff --git a/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
new file mode 100644
index 0000000..5014556
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
@@ -0,0 +1,1218 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>		/* for uint32_t */
+
+#include <lib/mmio.h>
+
+#include "pfc_init_m3n.h"
+#include "rcar_def.h"
+#include "../pfc_regs.h"
+
+#define GPSR0_D15		BIT(15)
+#define GPSR0_D14		BIT(14)
+#define GPSR0_D13		BIT(13)
+#define GPSR0_D12		BIT(12)
+#define GPSR0_D11		BIT(11)
+#define GPSR0_D10		BIT(10)
+#define GPSR0_D9		BIT(9)
+#define GPSR0_D8		BIT(8)
+#define GPSR0_D7		BIT(7)
+#define GPSR0_D6		BIT(6)
+#define GPSR0_D5		BIT(5)
+#define GPSR0_D4		BIT(4)
+#define GPSR0_D3		BIT(3)
+#define GPSR0_D2		BIT(2)
+#define GPSR0_D1		BIT(1)
+#define GPSR0_D0		BIT(0)
+#define GPSR1_CLKOUT		BIT(28)
+#define GPSR1_EX_WAIT0_A	BIT(27)
+#define GPSR1_WE1		BIT(26)
+#define GPSR1_WE0		BIT(25)
+#define GPSR1_RD_WR		BIT(24)
+#define GPSR1_RD		BIT(23)
+#define GPSR1_BS		BIT(22)
+#define GPSR1_CS1_A26		BIT(21)
+#define GPSR1_CS0		BIT(20)
+#define GPSR1_A19		BIT(19)
+#define GPSR1_A18		BIT(18)
+#define GPSR1_A17		BIT(17)
+#define GPSR1_A16		BIT(16)
+#define GPSR1_A15		BIT(15)
+#define GPSR1_A14		BIT(14)
+#define GPSR1_A13		BIT(13)
+#define GPSR1_A12		BIT(12)
+#define GPSR1_A11		BIT(11)
+#define GPSR1_A10		BIT(10)
+#define GPSR1_A9		BIT(9)
+#define GPSR1_A8		BIT(8)
+#define GPSR1_A7		BIT(7)
+#define GPSR1_A6		BIT(6)
+#define GPSR1_A5		BIT(5)
+#define GPSR1_A4		BIT(4)
+#define GPSR1_A3		BIT(3)
+#define GPSR1_A2		BIT(2)
+#define GPSR1_A1		BIT(1)
+#define GPSR1_A0		BIT(0)
+#define GPSR2_AVB_AVTP_CAPTURE_A	BIT(14)
+#define GPSR2_AVB_AVTP_MATCH_A	BIT(13)
+#define GPSR2_AVB_LINK		BIT(12)
+#define GPSR2_AVB_PHY_INT	BIT(11)
+#define GPSR2_AVB_MAGIC		BIT(10)
+#define GPSR2_AVB_MDC		BIT(9)
+#define GPSR2_PWM2_A		BIT(8)
+#define GPSR2_PWM1_A		BIT(7)
+#define GPSR2_PWM0		BIT(6)
+#define GPSR2_IRQ5		BIT(5)
+#define GPSR2_IRQ4		BIT(4)
+#define GPSR2_IRQ3		BIT(3)
+#define GPSR2_IRQ2		BIT(2)
+#define GPSR2_IRQ1		BIT(1)
+#define GPSR2_IRQ0		BIT(0)
+#define GPSR3_SD1_WP		BIT(15)
+#define GPSR3_SD1_CD		BIT(14)
+#define GPSR3_SD0_WP		BIT(13)
+#define GPSR3_SD0_CD		BIT(12)
+#define GPSR3_SD1_DAT3		BIT(11)
+#define GPSR3_SD1_DAT2		BIT(10)
+#define GPSR3_SD1_DAT1		BIT(9)
+#define GPSR3_SD1_DAT0		BIT(8)
+#define GPSR3_SD1_CMD		BIT(7)
+#define GPSR3_SD1_CLK		BIT(6)
+#define GPSR3_SD0_DAT3		BIT(5)
+#define GPSR3_SD0_DAT2		BIT(4)
+#define GPSR3_SD0_DAT1		BIT(3)
+#define GPSR3_SD0_DAT0		BIT(2)
+#define GPSR3_SD0_CMD		BIT(1)
+#define GPSR3_SD0_CLK		BIT(0)
+#define GPSR4_SD3_DS		BIT(17)
+#define GPSR4_SD3_DAT7		BIT(16)
+#define GPSR4_SD3_DAT6		BIT(15)
+#define GPSR4_SD3_DAT5		BIT(14)
+#define GPSR4_SD3_DAT4		BIT(13)
+#define GPSR4_SD3_DAT3		BIT(12)
+#define GPSR4_SD3_DAT2		BIT(11)
+#define GPSR4_SD3_DAT1		BIT(10)
+#define GPSR4_SD3_DAT0		BIT(9)
+#define GPSR4_SD3_CMD		BIT(8)
+#define GPSR4_SD3_CLK		BIT(7)
+#define GPSR4_SD2_DS		BIT(6)
+#define GPSR4_SD2_DAT3		BIT(5)
+#define GPSR4_SD2_DAT2		BIT(4)
+#define GPSR4_SD2_DAT1		BIT(3)
+#define GPSR4_SD2_DAT0		BIT(2)
+#define GPSR4_SD2_CMD		BIT(1)
+#define GPSR4_SD2_CLK		BIT(0)
+#define GPSR5_MLB_DAT		BIT(25)
+#define GPSR5_MLB_SIG		BIT(24)
+#define GPSR5_MLB_CLK		BIT(23)
+#define GPSR5_MSIOF0_RXD	BIT(22)
+#define GPSR5_MSIOF0_SS2	BIT(21)
+#define GPSR5_MSIOF0_TXD	BIT(20)
+#define GPSR5_MSIOF0_SS1	BIT(19)
+#define GPSR5_MSIOF0_SYNC	BIT(18)
+#define GPSR5_MSIOF0_SCK	BIT(17)
+#define GPSR5_HRTS0		BIT(16)
+#define GPSR5_HCTS0		BIT(15)
+#define GPSR5_HTX0		BIT(14)
+#define GPSR5_HRX0		BIT(13)
+#define GPSR5_HSCK0		BIT(12)
+#define GPSR5_RX2_A		BIT(11)
+#define GPSR5_TX2_A		BIT(10)
+#define GPSR5_SCK2		BIT(9)
+#define GPSR5_RTS1		BIT(8)
+#define GPSR5_CTS1		BIT(7)
+#define GPSR5_TX1_A		BIT(6)
+#define GPSR5_RX1_A		BIT(5)
+#define GPSR5_RTS0		BIT(4)
+#define GPSR5_CTS0		BIT(3)
+#define GPSR5_TX0		BIT(2)
+#define GPSR5_RX0		BIT(1)
+#define GPSR5_SCK0		BIT(0)
+#define GPSR6_USB31_OVC		BIT(31)
+#define GPSR6_USB31_PWEN	BIT(30)
+#define GPSR6_USB30_OVC		BIT(29)
+#define GPSR6_USB30_PWEN	BIT(28)
+#define GPSR6_USB1_OVC		BIT(27)
+#define GPSR6_USB1_PWEN		BIT(26)
+#define GPSR6_USB0_OVC		BIT(25)
+#define GPSR6_USB0_PWEN		BIT(24)
+#define GPSR6_AUDIO_CLKB_B	BIT(23)
+#define GPSR6_AUDIO_CLKA_A	BIT(22)
+#define GPSR6_SSI_SDATA9_A	BIT(21)
+#define GPSR6_SSI_SDATA8	BIT(20)
+#define GPSR6_SSI_SDATA7	BIT(19)
+#define GPSR6_SSI_WS78		BIT(18)
+#define GPSR6_SSI_SCK78		BIT(17)
+#define GPSR6_SSI_SDATA6	BIT(16)
+#define GPSR6_SSI_WS6		BIT(15)
+#define GPSR6_SSI_SCK6		BIT(14)
+#define GPSR6_SSI_SDATA5	BIT(13)
+#define GPSR6_SSI_WS5		BIT(12)
+#define GPSR6_SSI_SCK5		BIT(11)
+#define GPSR6_SSI_SDATA4	BIT(10)
+#define GPSR6_SSI_WS4		BIT(9)
+#define GPSR6_SSI_SCK4		BIT(8)
+#define GPSR6_SSI_SDATA3	BIT(7)
+#define GPSR6_SSI_WS34		BIT(6)
+#define GPSR6_SSI_SCK34		BIT(5)
+#define GPSR6_SSI_SDATA2_A	BIT(4)
+#define GPSR6_SSI_SDATA1_A	BIT(3)
+#define GPSR6_SSI_SDATA0	BIT(2)
+#define GPSR6_SSI_WS0129	BIT(1)
+#define GPSR6_SSI_SCK0129	BIT(0)
+#define GPSR7_AVS2		BIT(1)
+#define GPSR7_AVS1		BIT(0)
+
+#define IPSR_28_FUNC(x)		((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)		((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)		((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)		((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)		((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)		((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)		((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)		((uint32_t)(x) << 0U)
+
+#define POC_SD3_DS_33V		BIT(29)
+#define POC_SD3_DAT7_33V	BIT(28)
+#define POC_SD3_DAT6_33V	BIT(27)
+#define POC_SD3_DAT5_33V	BIT(26)
+#define POC_SD3_DAT4_33V	BIT(25)
+#define POC_SD3_DAT3_33V	BIT(24)
+#define POC_SD3_DAT2_33V	BIT(23)
+#define POC_SD3_DAT1_33V	BIT(22)
+#define POC_SD3_DAT0_33V	BIT(21)
+#define POC_SD3_CMD_33V		BIT(20)
+#define POC_SD3_CLK_33V		BIT(19)
+#define POC_SD2_DS_33V		BIT(18)
+#define POC_SD2_DAT3_33V	BIT(17)
+#define POC_SD2_DAT2_33V	BIT(16)
+#define POC_SD2_DAT1_33V	BIT(15)
+#define POC_SD2_DAT0_33V	BIT(14)
+#define POC_SD2_CMD_33V		BIT(13)
+#define POC_SD2_CLK_33V		BIT(12)
+#define POC_SD1_DAT3_33V	BIT(11)
+#define POC_SD1_DAT2_33V	BIT(10)
+#define POC_SD1_DAT1_33V	BIT(9)
+#define POC_SD1_DAT0_33V	BIT(8)
+#define POC_SD1_CMD_33V		BIT(7)
+#define POC_SD1_CLK_33V		BIT(6)
+#define POC_SD0_DAT3_33V	BIT(5)
+#define POC_SD0_DAT2_33V	BIT(4)
+#define POC_SD0_DAT1_33V	BIT(3)
+#define POC_SD0_DAT0_33V	BIT(2)
+#define POC_SD0_CMD_33V		BIT(1)
+#define POC_SD0_CLK_33V		BIT(0)
+
+#define DRVCTRL0_MASK		(0xCCCCCCCCU)
+#define DRVCTRL1_MASK		(0xCCCCCCC8U)
+#define DRVCTRL2_MASK		(0x88888888U)
+#define DRVCTRL3_MASK		(0x88888888U)
+#define DRVCTRL4_MASK		(0x88888888U)
+#define DRVCTRL5_MASK		(0x88888888U)
+#define DRVCTRL6_MASK		(0x88888888U)
+#define DRVCTRL7_MASK		(0x88888888U)
+#define DRVCTRL8_MASK		(0x88888888U)
+#define DRVCTRL9_MASK		(0x88888888U)
+#define DRVCTRL10_MASK		(0x88888888U)
+#define DRVCTRL11_MASK		(0x888888CCU)
+#define DRVCTRL12_MASK		(0xCCCFFFCFU)
+#define DRVCTRL13_MASK		(0xCC888888U)
+#define DRVCTRL14_MASK		(0x88888888U)
+#define DRVCTRL15_MASK		(0x88888888U)
+#define DRVCTRL16_MASK		(0x88888888U)
+#define DRVCTRL17_MASK		(0x88888888U)
+#define DRVCTRL18_MASK		(0x88888888U)
+#define DRVCTRL19_MASK		(0x88888888U)
+#define DRVCTRL20_MASK		(0x88888888U)
+#define DRVCTRL21_MASK		(0x88888888U)
+#define DRVCTRL22_MASK		(0x88888888U)
+#define DRVCTRL23_MASK		(0x88888888U)
+#define DRVCTRL24_MASK		(0x8888888FU)
+
+#define DRVCTRL0_QSPI0_SPCLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL0_QSPI0_MOSI_IO0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL0_QSPI0_MISO_IO1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL0_QSPI0_IO2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL0_QSPI0_IO3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL0_QSPI0_SSL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL0_QSPI1_SPCLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL0_QSPI1_MOSI_IO0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL1_QSPI1_MISO_IO1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL1_QSPI1_IO2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL1_QSPI1_IO3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL1_QSPI1_SS(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL1_RPC_INT(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL1_RPC_WP(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL1_RPC_RESET(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL1_AVB_RX_CTL(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL2_AVB_RXC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL2_AVB_RD0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL2_AVB_RD1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL2_AVB_RD2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL2_AVB_RD3(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL2_AVB_TX_CTL(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL2_AVB_TXC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL2_AVB_TD0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL3_AVB_TD1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL3_AVB_TD2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL3_AVB_TD3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL3_AVB_TXCREFCLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL3_AVB_MDIO(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL3_AVB_MDC(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL3_AVB_MAGIC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL3_AVB_PHY_INT(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL4_AVB_LINK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL4_AVB_AVTP_MATCH(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL4_AVB_AVTP_CAPTURE(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL4_IRQ0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL4_IRQ1(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL4_IRQ2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL4_IRQ3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL4_IRQ4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL5_IRQ5(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL5_PWM0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL5_PWM1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL5_PWM2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL5_A0(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL5_A1(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL5_A2(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL5_A3(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL6_A4(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL6_A5(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL6_A6(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL6_A7(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL6_A8(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL6_A9(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL6_A10(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL6_A11(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL7_A12(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL7_A13(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL7_A14(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL7_A15(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL7_A16(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL7_A17(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL7_A18(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL7_A19(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL8_CLKOUT(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL8_CS0(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL8_CS1_A2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL8_BS(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL8_RD(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL8_RD_W(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL8_WE0(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL8_WE1(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL9_EX_WAIT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL9_PRESETOU(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL9_D0(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL9_D1(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL9_D2(x)		((uint32_t)(x) << 12U)
+#define DRVCTRL9_D3(x)		((uint32_t)(x) << 8U)
+#define DRVCTRL9_D4(x)		((uint32_t)(x) << 4U)
+#define DRVCTRL9_D5(x)		((uint32_t)(x) << 0U)
+#define DRVCTRL10_D6(x)		((uint32_t)(x) << 28U)
+#define DRVCTRL10_D7(x)		((uint32_t)(x) << 24U)
+#define DRVCTRL10_D8(x)		((uint32_t)(x) << 20U)
+#define DRVCTRL10_D9(x)		((uint32_t)(x) << 16U)
+#define DRVCTRL10_D10(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL10_D11(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL10_D12(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL10_D13(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL11_D14(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL11_D15(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL11_AVS1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL11_AVS2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL11_GP7_02(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL11_GP7_03(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL11_DU_DOTCLKIN0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL11_DU_DOTCLKIN1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL12_DU_DOTCLKIN2(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL12_DU_DOTCLKIN3(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL12_DU_FSCLKST(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL12_DU_TMS(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_TDO(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL13_ASEBRK(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL13_SD0_CLK(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL13_SD0_CMD(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL13_SD0_DAT0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL13_SD0_DAT1(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL13_SD0_DAT2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL13_SD0_DAT3(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL14_SD1_CLK(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL14_SD1_CMD(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL14_SD1_DAT0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL14_SD1_DAT1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL14_SD1_DAT2(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL14_SD1_DAT3(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL14_SD2_CLK(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL14_SD2_CMD(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL15_SD2_DAT0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL15_SD2_DAT1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL15_SD2_DAT2(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL15_SD2_DAT3(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL15_SD2_DS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL15_SD3_CLK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL15_SD3_CMD(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL15_SD3_DAT0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL16_SD3_DAT1(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL16_SD3_DAT2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL16_SD3_DAT3(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL16_SD3_DAT4(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL16_SD3_DAT5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL16_SD3_DAT6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL16_SD3_DAT7(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL16_SD3_DS(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL17_SD0_CD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL17_SD0_WP(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL17_SD1_CD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL17_SD1_WP(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL17_SCK0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL17_RX0(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL17_TX0(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL17_CTS0(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL18_RTS0_TANS(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL18_RX1(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL18_TX1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL18_CTS1(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL18_RTS1_TANS(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL18_SCK2(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL18_TX2(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL18_RX2(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL19_HSCK0(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL19_HRX0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL19_HTX0(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL19_HCTS0(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL19_HRTS0(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL19_MSIOF0_SCK(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL19_MSIOF0_SYNC(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL19_MSIOF0_SS1(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL20_MSIOF0_TXD(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL20_MSIOF0_SS2(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL20_MSIOF0_RXD(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL20_MLB_CLK(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL20_MLB_SIG(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL20_MLB_DAT(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL20_MLB_REF(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL20_SSI_SCK0129(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL21_SSI_WS0129(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL21_SSI_SDATA0(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL21_SSI_SDATA1(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL21_SSI_SDATA2(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL21_SSI_SCK34(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL21_SSI_WS34(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL21_SSI_SDATA3(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL21_SSI_SCK4(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL22_SSI_WS4(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL22_SSI_SDATA4(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL22_SSI_SCK5(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL22_SSI_WS5(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL22_SSI_SDATA5(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL22_SSI_SCK6(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL22_SSI_WS6(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL22_SSI_SDATA6(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL23_SSI_SCK78(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL23_SSI_WS78(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL23_SSI_SDATA7(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL23_SSI_SDATA8(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL23_SSI_SDATA9(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL23_AUDIO_CLKA(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL23_AUDIO_CLKB(x)	((uint32_t)(x) << 4U)
+#define DRVCTRL23_USB0_PWEN(x)	((uint32_t)(x) << 0U)
+#define DRVCTRL24_USB0_OVC(x)	((uint32_t)(x) << 28U)
+#define DRVCTRL24_USB1_PWEN(x)	((uint32_t)(x) << 24U)
+#define DRVCTRL24_USB1_OVC(x)	((uint32_t)(x) << 20U)
+#define DRVCTRL24_USB30_PWEN(x)	((uint32_t)(x) << 16U)
+#define DRVCTRL24_USB30_OVC(x)	((uint32_t)(x) << 12U)
+#define DRVCTRL24_USB31_PWEN(x)	((uint32_t)(x) << 8U)
+#define DRVCTRL24_USB31_OVC(x)	((uint32_t)(x) << 4U)
+
+#define MOD_SEL0_MSIOF3_A	((uint32_t)0U << 29U)
+#define MOD_SEL0_MSIOF3_B	((uint32_t)1U << 29U)
+#define MOD_SEL0_MSIOF3_C	((uint32_t)2U << 29U)
+#define MOD_SEL0_MSIOF3_D	((uint32_t)3U << 29U)
+#define MOD_SEL0_MSIOF3_E	((uint32_t)4U << 29U)
+#define MOD_SEL0_MSIOF2_A	((uint32_t)0U << 27U)
+#define MOD_SEL0_MSIOF2_B	((uint32_t)1U << 27U)
+#define MOD_SEL0_MSIOF2_C	((uint32_t)2U << 27U)
+#define MOD_SEL0_MSIOF2_D	((uint32_t)3U << 27U)
+#define MOD_SEL0_MSIOF1_A	((uint32_t)0U << 24U)
+#define MOD_SEL0_MSIOF1_B	((uint32_t)1U << 24U)
+#define MOD_SEL0_MSIOF1_C	((uint32_t)2U << 24U)
+#define MOD_SEL0_MSIOF1_D	((uint32_t)3U << 24U)
+#define MOD_SEL0_MSIOF1_E	((uint32_t)4U << 24U)
+#define MOD_SEL0_MSIOF1_F	((uint32_t)5U << 24U)
+#define MOD_SEL0_MSIOF1_G	((uint32_t)6U << 24U)
+#define MOD_SEL0_LBSC_A		((uint32_t)0U << 23U)
+#define MOD_SEL0_LBSC_B		((uint32_t)1U << 23U)
+#define MOD_SEL0_IEBUS_A	((uint32_t)0U << 22U)
+#define MOD_SEL0_IEBUS_B	((uint32_t)1U << 22U)
+#define MOD_SEL0_I2C2_A		((uint32_t)0U << 21U)
+#define MOD_SEL0_I2C2_B		((uint32_t)1U << 21U)
+#define MOD_SEL0_I2C1_A		((uint32_t)0U << 20U)
+#define MOD_SEL0_I2C1_B		((uint32_t)1U << 20U)
+#define MOD_SEL0_HSCIF4_A	((uint32_t)0U << 19U)
+#define MOD_SEL0_HSCIF4_B	((uint32_t)1U << 19U)
+#define MOD_SEL0_HSCIF3_A	((uint32_t)0U << 17U)
+#define MOD_SEL0_HSCIF3_B	((uint32_t)1U << 17U)
+#define MOD_SEL0_HSCIF3_C	((uint32_t)2U << 17U)
+#define MOD_SEL0_HSCIF3_D	((uint32_t)3U << 17U)
+#define MOD_SEL0_HSCIF1_A	((uint32_t)0U << 16U)
+#define MOD_SEL0_HSCIF1_B	((uint32_t)1U << 16U)
+#define MOD_SEL0_FSO_A		((uint32_t)0U << 15U)
+#define MOD_SEL0_FSO_B		((uint32_t)1U << 15U)
+#define MOD_SEL0_HSCIF2_A	((uint32_t)0U << 13U)
+#define MOD_SEL0_HSCIF2_B	((uint32_t)1U << 13U)
+#define MOD_SEL0_HSCIF2_C	((uint32_t)2U << 13U)
+#define MOD_SEL0_ETHERAVB_A	((uint32_t)0U << 12U)
+#define MOD_SEL0_ETHERAVB_B	((uint32_t)1U << 12U)
+#define MOD_SEL0_DRIF3_A	((uint32_t)0U << 11U)
+#define MOD_SEL0_DRIF3_B	((uint32_t)1U << 11U)
+#define MOD_SEL0_DRIF2_A	((uint32_t)0U << 10U)
+#define MOD_SEL0_DRIF2_B	((uint32_t)1U << 10U)
+#define MOD_SEL0_DRIF1_A	((uint32_t)0U << 8U)
+#define MOD_SEL0_DRIF1_B	((uint32_t)1U << 8U)
+#define MOD_SEL0_DRIF1_C	((uint32_t)2U << 8U)
+#define MOD_SEL0_DRIF0_A	((uint32_t)0U << 6U)
+#define MOD_SEL0_DRIF0_B	((uint32_t)1U << 6U)
+#define MOD_SEL0_DRIF0_C	((uint32_t)2U << 6U)
+#define MOD_SEL0_CANFD0_A	((uint32_t)0U << 5U)
+#define MOD_SEL0_CANFD0_B	((uint32_t)1U << 5U)
+#define MOD_SEL0_ADG_A_A	((uint32_t)0U << 3U)
+#define MOD_SEL0_ADG_A_B	((uint32_t)1U << 3U)
+#define MOD_SEL0_ADG_A_C	((uint32_t)2U << 3U)
+#define MOD_SEL1_TSIF1_A	((uint32_t)0U << 30U)
+#define MOD_SEL1_TSIF1_B	((uint32_t)1U << 30U)
+#define MOD_SEL1_TSIF1_C	((uint32_t)2U << 30U)
+#define MOD_SEL1_TSIF1_D	((uint32_t)3U << 30U)
+#define MOD_SEL1_TSIF0_A	((uint32_t)0U << 27U)
+#define MOD_SEL1_TSIF0_B	((uint32_t)1U << 27U)
+#define MOD_SEL1_TSIF0_C	((uint32_t)2U << 27U)
+#define MOD_SEL1_TSIF0_D	((uint32_t)3U << 27U)
+#define MOD_SEL1_TSIF0_E	((uint32_t)4U << 27U)
+#define MOD_SEL1_TIMER_TMU_A	((uint32_t)0U << 26U)
+#define MOD_SEL1_TIMER_TMU_B	((uint32_t)1U << 26U)
+#define MOD_SEL1_SSP1_1_A	((uint32_t)0U << 24U)
+#define MOD_SEL1_SSP1_1_B	((uint32_t)1U << 24U)
+#define MOD_SEL1_SSP1_1_C	((uint32_t)2U << 24U)
+#define MOD_SEL1_SSP1_1_D	((uint32_t)3U << 24U)
+#define MOD_SEL1_SSP1_0_A	((uint32_t)0U << 21U)
+#define MOD_SEL1_SSP1_0_B	((uint32_t)1U << 21U)
+#define MOD_SEL1_SSP1_0_C	((uint32_t)2U << 21U)
+#define MOD_SEL1_SSP1_0_D	((uint32_t)3U << 21U)
+#define MOD_SEL1_SSP1_0_E	((uint32_t)4U << 21U)
+#define MOD_SEL1_SSI_A		((uint32_t)0U << 20U)
+#define MOD_SEL1_SSI_B		((uint32_t)1U << 20U)
+#define MOD_SEL1_SPEED_PULSE_IF_A	((uint32_t)0U << 19U)
+#define MOD_SEL1_SPEED_PULSE_IF_B	((uint32_t)1U << 19U)
+#define MOD_SEL1_SIMCARD_A	((uint32_t)0U << 17U)
+#define MOD_SEL1_SIMCARD_B	((uint32_t)1U << 17U)
+#define MOD_SEL1_SIMCARD_C	((uint32_t)2U << 17U)
+#define MOD_SEL1_SIMCARD_D	((uint32_t)3U << 17U)
+#define MOD_SEL1_SDHI2_A	((uint32_t)0U << 16U)
+#define MOD_SEL1_SDHI2_B	((uint32_t)1U << 16U)
+#define MOD_SEL1_SCIF4_A	((uint32_t)0U << 14U)
+#define MOD_SEL1_SCIF4_B	((uint32_t)1U << 14U)
+#define MOD_SEL1_SCIF4_C	((uint32_t)2U << 14U)
+#define MOD_SEL1_SCIF3_A	((uint32_t)0U << 13U)
+#define MOD_SEL1_SCIF3_B	((uint32_t)1U << 13U)
+#define MOD_SEL1_SCIF2_A	((uint32_t)0U << 12U)
+#define MOD_SEL1_SCIF2_B	((uint32_t)1U << 12U)
+#define MOD_SEL1_SCIF1_A	((uint32_t)0U << 11U)
+#define MOD_SEL1_SCIF1_B	((uint32_t)1U << 11U)
+#define MOD_SEL1_SCIF_A		((uint32_t)0U << 10U)
+#define MOD_SEL1_SCIF_B		((uint32_t)1U << 10U)
+#define MOD_SEL1_REMOCON_A	((uint32_t)0U << 9U)
+#define MOD_SEL1_REMOCON_B	((uint32_t)1U << 9U)
+#define MOD_SEL1_RCAN0_A	((uint32_t)0U << 6U)
+#define MOD_SEL1_RCAN0_B	((uint32_t)1U << 6U)
+#define MOD_SEL1_PWM6_A		((uint32_t)0U << 5U)
+#define MOD_SEL1_PWM6_B		((uint32_t)1U << 5U)
+#define MOD_SEL1_PWM5_A		((uint32_t)0U << 4U)
+#define MOD_SEL1_PWM5_B		((uint32_t)1U << 4U)
+#define MOD_SEL1_PWM4_A		((uint32_t)0U << 3U)
+#define MOD_SEL1_PWM4_B		((uint32_t)1U << 3U)
+#define MOD_SEL1_PWM3_A		((uint32_t)0U << 2U)
+#define MOD_SEL1_PWM3_B		((uint32_t)1U << 2U)
+#define MOD_SEL1_PWM2_A		((uint32_t)0U << 1U)
+#define MOD_SEL1_PWM2_B		((uint32_t)1U << 1U)
+#define MOD_SEL1_PWM1_A		((uint32_t)0U << 0U)
+#define MOD_SEL1_PWM1_B		((uint32_t)1U << 0U)
+#define MOD_SEL2_I2C_5_A	((uint32_t)0U << 31U)
+#define MOD_SEL2_I2C_5_B	((uint32_t)1U << 31U)
+#define MOD_SEL2_I2C_3_A	((uint32_t)0U << 30U)
+#define MOD_SEL2_I2C_3_B	((uint32_t)1U << 30U)
+#define MOD_SEL2_I2C_0_A	((uint32_t)0U << 29U)
+#define MOD_SEL2_I2C_0_B	((uint32_t)1U << 29U)
+#define MOD_SEL2_FM_A		((uint32_t)0U << 27U)
+#define MOD_SEL2_FM_B		((uint32_t)1U << 27U)
+#define MOD_SEL2_FM_C		((uint32_t)2U << 27U)
+#define MOD_SEL2_FM_D		((uint32_t)3U << 27U)
+#define MOD_SEL2_SCIF5_A	((uint32_t)0U << 26U)
+#define MOD_SEL2_SCIF5_B	((uint32_t)1U << 26U)
+#define MOD_SEL2_I2C6_A		((uint32_t)0U << 23U)
+#define MOD_SEL2_I2C6_B		((uint32_t)1U << 23U)
+#define MOD_SEL2_I2C6_C		((uint32_t)2U << 23U)
+#define MOD_SEL2_NDF_A		((uint32_t)0U << 22U)
+#define MOD_SEL2_NDF_B		((uint32_t)1U << 22U)
+#define MOD_SEL2_SSI2_A		((uint32_t)0U << 21U)
+#define MOD_SEL2_SSI2_B		((uint32_t)1U << 21U)
+#define MOD_SEL2_SSI9_A		((uint32_t)0U << 20U)
+#define MOD_SEL2_SSI9_B		((uint32_t)1U << 20U)
+#define MOD_SEL2_TIMER_TMU2_A	((uint32_t)0U << 19U)
+#define MOD_SEL2_TIMER_TMU2_B	((uint32_t)1U << 19U)
+#define MOD_SEL2_ADG_B_A	((uint32_t)0U << 18U)
+#define MOD_SEL2_ADG_B_B	((uint32_t)1U << 18U)
+#define MOD_SEL2_ADG_C_A	((uint32_t)0U << 17U)
+#define MOD_SEL2_ADG_C_B	((uint32_t)1U << 17U)
+#define MOD_SEL2_VIN4_A		((uint32_t)0U << 0U)
+#define MOD_SEL2_VIN4_B		((uint32_t)1U << 0U)
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	mmio_write_32(PFC_PMMR, ~data);
+	mmio_write_32((uintptr_t)addr, data);
+}
+
+void pfc_init_m3n(void)
+{
+	uint32_t reg;
+
+	/* initialize module select */
+	pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A
+		      | MOD_SEL0_MSIOF2_A
+		      | MOD_SEL0_MSIOF1_A
+		      | MOD_SEL0_LBSC_A
+		      | MOD_SEL0_IEBUS_A
+		      | MOD_SEL0_I2C2_A
+		      | MOD_SEL0_I2C1_A
+		      | MOD_SEL0_HSCIF4_A
+		      | MOD_SEL0_HSCIF3_A
+		      | MOD_SEL0_HSCIF1_A
+		      | MOD_SEL0_FSO_A
+		      | MOD_SEL0_HSCIF2_A
+		      | MOD_SEL0_ETHERAVB_A
+		      | MOD_SEL0_DRIF3_A
+		      | MOD_SEL0_DRIF2_A
+		      | MOD_SEL0_DRIF1_A
+		      | MOD_SEL0_DRIF0_A
+		      | MOD_SEL0_CANFD0_A
+		      | MOD_SEL0_ADG_A_A);
+	pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A
+		      | MOD_SEL1_TSIF0_A
+		      | MOD_SEL1_TIMER_TMU_A
+		      | MOD_SEL1_SSP1_1_A
+		      | MOD_SEL1_SSP1_0_A
+		      | MOD_SEL1_SSI_A
+		      | MOD_SEL1_SPEED_PULSE_IF_A
+		      | MOD_SEL1_SIMCARD_A
+		      | MOD_SEL1_SDHI2_A
+		      | MOD_SEL1_SCIF4_A
+		      | MOD_SEL1_SCIF3_A
+		      | MOD_SEL1_SCIF2_A
+		      | MOD_SEL1_SCIF1_A
+		      | MOD_SEL1_SCIF_A
+		      | MOD_SEL1_REMOCON_A
+		      | MOD_SEL1_RCAN0_A
+		      | MOD_SEL1_PWM6_A
+		      | MOD_SEL1_PWM5_A
+		      | MOD_SEL1_PWM4_A
+		      | MOD_SEL1_PWM3_A
+		      | MOD_SEL1_PWM2_A
+		      | MOD_SEL1_PWM1_A);
+	pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A
+		      | MOD_SEL2_I2C_3_A
+		      | MOD_SEL2_I2C_0_A
+		      | MOD_SEL2_FM_A
+		      | MOD_SEL2_SCIF5_A
+		      | MOD_SEL2_I2C6_A
+		      | MOD_SEL2_NDF_A
+		      | MOD_SEL2_SSI2_A
+		      | MOD_SEL2_SSI9_A
+		      | MOD_SEL2_TIMER_TMU2_A
+		      | MOD_SEL2_ADG_B_A
+		      | MOD_SEL2_ADG_C_A
+		      | MOD_SEL2_VIN4_A);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(3)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(3));
+	pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6)
+		      | IPSR_24_FUNC(6)
+		      | IPSR_20_FUNC(6)
+		      | IPSR_16_FUNC(6)
+		      | IPSR_12_FUNC(6)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_8_FUNC(6)
+		      | IPSR_4_FUNC(6)
+		      | IPSR_0_FUNC(6));
+	pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(1)
+		      | IPSR_20_FUNC(1)
+		      | IPSR_16_FUNC(1)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(1)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(4)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(1));
+	pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(4)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(8)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(3)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(3)
+		      | IPSR_0_FUNC(8));
+	pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR17, IPSR_28_FUNC(0)
+		      | IPSR_24_FUNC(0)
+		      | IPSR_20_FUNC(0)
+		      | IPSR_16_FUNC(0)
+		      | IPSR_12_FUNC(0)
+		      | IPSR_8_FUNC(0)
+		      | IPSR_4_FUNC(1)
+		      | IPSR_0_FUNC(0));
+	pfc_reg_write(PFC_IPSR18, IPSR_4_FUNC(0)
+		      | IPSR_0_FUNC(0));
+
+	/* initialize GPIO/perihperal function select */
+	pfc_reg_write(PFC_GPSR0, GPSR0_D15
+		      | GPSR0_D14
+		      | GPSR0_D13
+		      | GPSR0_D12
+		      | GPSR0_D11
+		      | GPSR0_D10
+		      | GPSR0_D9
+		      | GPSR0_D8);
+	pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT
+		      | GPSR1_EX_WAIT0_A
+		      | GPSR1_A19
+		      | GPSR1_A18
+		      | GPSR1_A17
+		      | GPSR1_A16
+		      | GPSR1_A15
+		      | GPSR1_A14
+		      | GPSR1_A13
+		      | GPSR1_A12
+		      | GPSR1_A7
+		      | GPSR1_A6
+		      | GPSR1_A5
+		      | GPSR1_A4
+		      | GPSR1_A3
+		      | GPSR1_A2
+		      | GPSR1_A1
+		      | GPSR1_A0);
+	pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A
+		      | GPSR2_AVB_AVTP_MATCH_A
+		      | GPSR2_AVB_LINK
+		      | GPSR2_AVB_PHY_INT
+		      | GPSR2_AVB_MDC
+		      | GPSR2_PWM2_A
+		      | GPSR2_PWM1_A
+		      | GPSR2_IRQ5
+		      | GPSR2_IRQ4
+		      | GPSR2_IRQ3
+		      | GPSR2_IRQ2
+		      | GPSR2_IRQ1
+		      | GPSR2_IRQ0);
+	pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP
+		      | GPSR3_SD0_CD
+		      | GPSR3_SD1_DAT3
+		      | GPSR3_SD1_DAT2
+		      | GPSR3_SD1_DAT1
+		      | GPSR3_SD1_DAT0
+		      | GPSR3_SD0_DAT3
+		      | GPSR3_SD0_DAT2
+		      | GPSR3_SD0_DAT1
+		      | GPSR3_SD0_DAT0
+		      | GPSR3_SD0_CMD
+		      | GPSR3_SD0_CLK);
+	pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7
+		      | GPSR4_SD3_DAT6
+		      | GPSR4_SD3_DAT3
+		      | GPSR4_SD3_DAT2
+		      | GPSR4_SD3_DAT1
+		      | GPSR4_SD3_DAT0
+		      | GPSR4_SD3_CMD
+		      | GPSR4_SD3_CLK
+		      | GPSR4_SD2_DS
+		      | GPSR4_SD2_DAT3
+		      | GPSR4_SD2_DAT2
+		      | GPSR4_SD2_DAT1
+		      | GPSR4_SD2_DAT0
+		      | GPSR4_SD2_CMD
+		      | GPSR4_SD2_CLK);
+	pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2
+		      | GPSR5_MSIOF0_SS1
+		      | GPSR5_MSIOF0_SYNC
+		      | GPSR5_HRTS0
+		      | GPSR5_HCTS0
+		      | GPSR5_HTX0
+		      | GPSR5_HRX0
+		      | GPSR5_HSCK0
+		      | GPSR5_RX2_A
+		      | GPSR5_TX2_A
+		      | GPSR5_SCK2
+		      | GPSR5_RTS1
+		      | GPSR5_CTS1
+		      | GPSR5_TX1_A
+		      | GPSR5_RX1_A
+		      | GPSR5_RTS0
+		      | GPSR5_SCK0);
+	pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC
+		      | GPSR6_USB30_PWEN
+		      | GPSR6_USB1_OVC
+		      | GPSR6_USB1_PWEN
+		      | GPSR6_USB0_OVC
+		      | GPSR6_USB0_PWEN
+		      | GPSR6_AUDIO_CLKB_B
+		      | GPSR6_AUDIO_CLKA_A
+		      | GPSR6_SSI_SDATA8
+		      | GPSR6_SSI_SDATA7
+		      | GPSR6_SSI_WS78
+		      | GPSR6_SSI_SCK78
+		      | GPSR6_SSI_WS6
+		      | GPSR6_SSI_SCK6
+		      | GPSR6_SSI_SDATA4
+		      | GPSR6_SSI_WS4
+		      | GPSR6_SSI_SCK4
+		      | GPSR6_SSI_SDATA1_A
+		      | GPSR6_SSI_SDATA0
+		      | GPSR6_SSI_WS0129
+		      | GPSR6_SSI_SCK0129);
+	pfc_reg_write(PFC_GPSR7, GPSR7_AVS2
+		      | GPSR7_AVS1);
+
+	/* initialize POC control register */
+	pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V
+		      | POC_SD3_DAT7_33V
+		      | POC_SD3_DAT6_33V
+		      | POC_SD3_DAT5_33V
+		      | POC_SD3_DAT4_33V
+		      | POC_SD3_DAT3_33V
+		      | POC_SD3_DAT2_33V
+		      | POC_SD3_DAT1_33V
+		      | POC_SD3_DAT0_33V
+		      | POC_SD3_CMD_33V
+		      | POC_SD3_CLK_33V
+		      | POC_SD0_DAT3_33V
+		      | POC_SD0_DAT2_33V
+		      | POC_SD0_DAT1_33V
+		      | POC_SD0_DAT0_33V
+		      | POC_SD0_CMD_33V
+		      | POC_SD0_CLK_33V);
+
+	/* initialize DRV control register */
+	reg = mmio_read_32(PFC_DRVCTRL0);
+	reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3)
+	       | DRVCTRL0_QSPI0_MOSI_IO0(3)
+	       | DRVCTRL0_QSPI0_MISO_IO1(3)
+	       | DRVCTRL0_QSPI0_IO2(3)
+	       | DRVCTRL0_QSPI0_IO3(3)
+	       | DRVCTRL0_QSPI0_SSL(3)
+	       | DRVCTRL0_QSPI1_SPCLK(3)
+	       | DRVCTRL0_QSPI1_MOSI_IO0(3));
+	pfc_reg_write(PFC_DRVCTRL0, reg);
+	reg = mmio_read_32(PFC_DRVCTRL1);
+	reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3)
+	       | DRVCTRL1_QSPI1_IO2(3)
+	       | DRVCTRL1_QSPI1_IO3(3)
+	       | DRVCTRL1_QSPI1_SS(3)
+	       | DRVCTRL1_RPC_INT(3)
+	       | DRVCTRL1_RPC_WP(3)
+	       | DRVCTRL1_RPC_RESET(3)
+	       | DRVCTRL1_AVB_RX_CTL(7));
+	pfc_reg_write(PFC_DRVCTRL1, reg);
+	reg = mmio_read_32(PFC_DRVCTRL2);
+	reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7)
+	       | DRVCTRL2_AVB_RD0(7)
+	       | DRVCTRL2_AVB_RD1(7)
+	       | DRVCTRL2_AVB_RD2(7)
+	       | DRVCTRL2_AVB_RD3(7)
+	       | DRVCTRL2_AVB_TX_CTL(3)
+	       | DRVCTRL2_AVB_TXC(3)
+	       | DRVCTRL2_AVB_TD0(3));
+	pfc_reg_write(PFC_DRVCTRL2, reg);
+	reg = mmio_read_32(PFC_DRVCTRL3);
+	reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3)
+	       | DRVCTRL3_AVB_TD2(3)
+	       | DRVCTRL3_AVB_TD3(3)
+	       | DRVCTRL3_AVB_TXCREFCLK(7)
+	       | DRVCTRL3_AVB_MDIO(7)
+	       | DRVCTRL3_AVB_MDC(7)
+	       | DRVCTRL3_AVB_MAGIC(7)
+	       | DRVCTRL3_AVB_PHY_INT(7));
+	pfc_reg_write(PFC_DRVCTRL3, reg);
+	reg = mmio_read_32(PFC_DRVCTRL4);
+	reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7)
+	       | DRVCTRL4_AVB_AVTP_MATCH(7)
+	       | DRVCTRL4_AVB_AVTP_CAPTURE(7)
+	       | DRVCTRL4_IRQ0(7)
+	       | DRVCTRL4_IRQ1(7)
+	       | DRVCTRL4_IRQ2(7)
+	       | DRVCTRL4_IRQ3(7)
+	       | DRVCTRL4_IRQ4(7));
+	pfc_reg_write(PFC_DRVCTRL4, reg);
+	reg = mmio_read_32(PFC_DRVCTRL5);
+	reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7)
+	       | DRVCTRL5_PWM0(7)
+	       | DRVCTRL5_PWM1(7)
+	       | DRVCTRL5_PWM2(7)
+	       | DRVCTRL5_A0(3)
+	       | DRVCTRL5_A1(3)
+	       | DRVCTRL5_A2(3)
+	       | DRVCTRL5_A3(3));
+	pfc_reg_write(PFC_DRVCTRL5, reg);
+	reg = mmio_read_32(PFC_DRVCTRL6);
+	reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3)
+	       | DRVCTRL6_A5(3)
+	       | DRVCTRL6_A6(3)
+	       | DRVCTRL6_A7(3)
+	       | DRVCTRL6_A8(7)
+	       | DRVCTRL6_A9(7)
+	       | DRVCTRL6_A10(7)
+	       | DRVCTRL6_A11(7));
+	pfc_reg_write(PFC_DRVCTRL6, reg);
+	reg = mmio_read_32(PFC_DRVCTRL7);
+	reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3)
+	       | DRVCTRL7_A13(3)
+	       | DRVCTRL7_A14(3)
+	       | DRVCTRL7_A15(3)
+	       | DRVCTRL7_A16(3)
+	       | DRVCTRL7_A17(3)
+	       | DRVCTRL7_A18(3)
+	       | DRVCTRL7_A19(3));
+	pfc_reg_write(PFC_DRVCTRL7, reg);
+	reg = mmio_read_32(PFC_DRVCTRL8);
+	reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7)
+	       | DRVCTRL8_CS0(7)
+	       | DRVCTRL8_CS1_A2(7)
+	       | DRVCTRL8_BS(7)
+	       | DRVCTRL8_RD(7)
+	       | DRVCTRL8_RD_W(7)
+	       | DRVCTRL8_WE0(7)
+	       | DRVCTRL8_WE1(7));
+	pfc_reg_write(PFC_DRVCTRL8, reg);
+	reg = mmio_read_32(PFC_DRVCTRL9);
+	reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7)
+	       | DRVCTRL9_PRESETOU(7)
+	       | DRVCTRL9_D0(7)
+	       | DRVCTRL9_D1(7)
+	       | DRVCTRL9_D2(7)
+	       | DRVCTRL9_D3(7)
+	       | DRVCTRL9_D4(7)
+	       | DRVCTRL9_D5(7));
+	pfc_reg_write(PFC_DRVCTRL9, reg);
+	reg = mmio_read_32(PFC_DRVCTRL10);
+	reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7)
+	       | DRVCTRL10_D7(7)
+	       | DRVCTRL10_D8(3)
+	       | DRVCTRL10_D9(3)
+	       | DRVCTRL10_D10(3)
+	       | DRVCTRL10_D11(3)
+	       | DRVCTRL10_D12(3)
+	       | DRVCTRL10_D13(3));
+	pfc_reg_write(PFC_DRVCTRL10, reg);
+	reg = mmio_read_32(PFC_DRVCTRL11);
+	reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3)
+	       | DRVCTRL11_D15(3)
+	       | DRVCTRL11_AVS1(7)
+	       | DRVCTRL11_AVS2(7)
+	       | DRVCTRL11_GP7_02(7)
+	       | DRVCTRL11_GP7_03(7)
+	       | DRVCTRL11_DU_DOTCLKIN0(3)
+	       | DRVCTRL11_DU_DOTCLKIN1(3));
+	pfc_reg_write(PFC_DRVCTRL11, reg);
+	reg = mmio_read_32(PFC_DRVCTRL12);
+	reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3)
+	       | DRVCTRL12_DU_DOTCLKIN3(3)
+	       | DRVCTRL12_DU_FSCLKST(3)
+	       | DRVCTRL12_DU_TMS(3));
+	pfc_reg_write(PFC_DRVCTRL12, reg);
+	reg = mmio_read_32(PFC_DRVCTRL13);
+	reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3)
+	       | DRVCTRL13_ASEBRK(3)
+	       | DRVCTRL13_SD0_CLK(7)
+	       | DRVCTRL13_SD0_CMD(7)
+	       | DRVCTRL13_SD0_DAT0(7)
+	       | DRVCTRL13_SD0_DAT1(7)
+	       | DRVCTRL13_SD0_DAT2(7)
+	       | DRVCTRL13_SD0_DAT3(7));
+	pfc_reg_write(PFC_DRVCTRL13, reg);
+	reg = mmio_read_32(PFC_DRVCTRL14);
+	reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7)
+	       | DRVCTRL14_SD1_CMD(7)
+	       | DRVCTRL14_SD1_DAT0(5)
+	       | DRVCTRL14_SD1_DAT1(5)
+	       | DRVCTRL14_SD1_DAT2(5)
+	       | DRVCTRL14_SD1_DAT3(5)
+	       | DRVCTRL14_SD2_CLK(5)
+	       | DRVCTRL14_SD2_CMD(5));
+	pfc_reg_write(PFC_DRVCTRL14, reg);
+	reg = mmio_read_32(PFC_DRVCTRL15);
+	reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5)
+	       | DRVCTRL15_SD2_DAT1(5)
+	       | DRVCTRL15_SD2_DAT2(5)
+	       | DRVCTRL15_SD2_DAT3(5)
+	       | DRVCTRL15_SD2_DS(5)
+	       | DRVCTRL15_SD3_CLK(7)
+	       | DRVCTRL15_SD3_CMD(7)
+	       | DRVCTRL15_SD3_DAT0(7));
+	pfc_reg_write(PFC_DRVCTRL15, reg);
+	reg = mmio_read_32(PFC_DRVCTRL16);
+	reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(7)
+	       | DRVCTRL16_SD3_DAT2(7)
+	       | DRVCTRL16_SD3_DAT3(7)
+	       | DRVCTRL16_SD3_DAT4(7)
+	       | DRVCTRL16_SD3_DAT5(7)
+	       | DRVCTRL16_SD3_DAT6(7)
+	       | DRVCTRL16_SD3_DAT7(7)
+	       | DRVCTRL16_SD3_DS(7));
+	pfc_reg_write(PFC_DRVCTRL16, reg);
+	reg = mmio_read_32(PFC_DRVCTRL17);
+	reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7)
+	       | DRVCTRL17_SD0_WP(7)
+	       | DRVCTRL17_SD1_CD(7)
+	       | DRVCTRL17_SD1_WP(7)
+	       | DRVCTRL17_SCK0(7)
+	       | DRVCTRL17_RX0(7)
+	       | DRVCTRL17_TX0(7)
+	       | DRVCTRL17_CTS0(7));
+	pfc_reg_write(PFC_DRVCTRL17, reg);
+	reg = mmio_read_32(PFC_DRVCTRL18);
+	reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7)
+	       | DRVCTRL18_RX1(7)
+	       | DRVCTRL18_TX1(7)
+	       | DRVCTRL18_CTS1(7)
+	       | DRVCTRL18_RTS1_TANS(7)
+	       | DRVCTRL18_SCK2(7)
+	       | DRVCTRL18_TX2(7)
+	       | DRVCTRL18_RX2(7));
+	pfc_reg_write(PFC_DRVCTRL18, reg);
+	reg = mmio_read_32(PFC_DRVCTRL19);
+	reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7)
+	       | DRVCTRL19_HRX0(7)
+	       | DRVCTRL19_HTX0(7)
+	       | DRVCTRL19_HCTS0(7)
+	       | DRVCTRL19_HRTS0(7)
+	       | DRVCTRL19_MSIOF0_SCK(7)
+	       | DRVCTRL19_MSIOF0_SYNC(7)
+	       | DRVCTRL19_MSIOF0_SS1(7));
+	pfc_reg_write(PFC_DRVCTRL19, reg);
+	reg = mmio_read_32(PFC_DRVCTRL20);
+	reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7)
+	       | DRVCTRL20_MSIOF0_SS2(7)
+	       | DRVCTRL20_MSIOF0_RXD(7)
+	       | DRVCTRL20_MLB_CLK(7)
+	       | DRVCTRL20_MLB_SIG(7)
+	       | DRVCTRL20_MLB_DAT(7)
+	       | DRVCTRL20_MLB_REF(7)
+	       | DRVCTRL20_SSI_SCK0129(7));
+	pfc_reg_write(PFC_DRVCTRL20, reg);
+	reg = mmio_read_32(PFC_DRVCTRL21);
+	reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7)
+	       | DRVCTRL21_SSI_SDATA0(7)
+	       | DRVCTRL21_SSI_SDATA1(7)
+	       | DRVCTRL21_SSI_SDATA2(7)
+	       | DRVCTRL21_SSI_SCK34(7)
+	       | DRVCTRL21_SSI_WS34(7)
+	       | DRVCTRL21_SSI_SDATA3(7)
+	       | DRVCTRL21_SSI_SCK4(7));
+	pfc_reg_write(PFC_DRVCTRL21, reg);
+	reg = mmio_read_32(PFC_DRVCTRL22);
+	reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7)
+	       | DRVCTRL22_SSI_SDATA4(7)
+	       | DRVCTRL22_SSI_SCK5(7)
+	       | DRVCTRL22_SSI_WS5(7)
+	       | DRVCTRL22_SSI_SDATA5(7)
+	       | DRVCTRL22_SSI_SCK6(7)
+	       | DRVCTRL22_SSI_WS6(7)
+	       | DRVCTRL22_SSI_SDATA6(7));
+	pfc_reg_write(PFC_DRVCTRL22, reg);
+	reg = mmio_read_32(PFC_DRVCTRL23);
+	reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7)
+	       | DRVCTRL23_SSI_WS78(7)
+	       | DRVCTRL23_SSI_SDATA7(7)
+	       | DRVCTRL23_SSI_SDATA8(7)
+	       | DRVCTRL23_SSI_SDATA9(7)
+	       | DRVCTRL23_AUDIO_CLKA(7)
+	       | DRVCTRL23_AUDIO_CLKB(7)
+	       | DRVCTRL23_USB0_PWEN(7));
+	pfc_reg_write(PFC_DRVCTRL23, reg);
+	reg = mmio_read_32(PFC_DRVCTRL24);
+	reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7)
+	       | DRVCTRL24_USB1_PWEN(7)
+	       | DRVCTRL24_USB1_OVC(7)
+	       | DRVCTRL24_USB30_PWEN(7)
+	       | DRVCTRL24_USB30_OVC(7)
+	       | DRVCTRL24_USB31_PWEN(7)
+	       | DRVCTRL24_USB31_OVC(7));
+	pfc_reg_write(PFC_DRVCTRL24, reg);
+
+	/* initialize LSI pin pull-up/down control */
+	pfc_reg_write(PFC_PUD0, 0x00005FBFU);
+	pfc_reg_write(PFC_PUD1, 0x00300FFEU);
+	pfc_reg_write(PFC_PUD2, 0x330001E6U);
+	pfc_reg_write(PFC_PUD3, 0x000002E0U);
+	pfc_reg_write(PFC_PUD4, 0xFFFFFF00U);
+	pfc_reg_write(PFC_PUD5, 0x7F5FFF87U);
+	pfc_reg_write(PFC_PUD6, 0x00000055U);
+
+	/* initialize LSI pin pull-enable register */
+	pfc_reg_write(PFC_PUEN0, 0x00000FFFU);
+	pfc_reg_write(PFC_PUEN1, 0x00100234U);
+	pfc_reg_write(PFC_PUEN2, 0x000004C4U);
+	pfc_reg_write(PFC_PUEN3, 0x00000200U);
+	pfc_reg_write(PFC_PUEN4, 0x3E000000U);
+	pfc_reg_write(PFC_PUEN5, 0x1F000805U);
+	pfc_reg_write(PFC_PUEN6, 0x00000006U);
+
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG6, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG7, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL6, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL7, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT1, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000400U);
+	mmio_write_32(GPIO_OUTDT3, 0x0000C000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00000006U);
+	mmio_write_32(GPIO_OUTDT6, 0x00003880U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x00000400U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00000000U);
+#if (RCAR_GEN3_ULCB == 1)
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU);
+#else
+	mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU);
+#endif
+	mmio_write_32(GPIO_INOUTSEL6, 0x00013880U);
+	mmio_write_32(GPIO_INOUTSEL7, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h
new file mode 100644
index 0000000..3e6f879
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_M3N_H
+#define PFC_INIT_M3N_H
+
+void pfc_init_m3n(void);
+
+#endif /* PFC_INIT_M3N_H */
diff --git a/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
new file mode 100644
index 0000000..6063758
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
@@ -0,0 +1,906 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>		/* for uint32_t */
+#include <lib/mmio.h>
+#include "pfc_init_v3m.h"
+#include "include/rcar_def.h"
+#include "rcar_private.h"
+#include "../pfc_regs.h"
+
+/* Pin functon bit */
+#define GPSR0_DU_EXODDF_DU_ODDF_DISP_CDE	BIT(21)
+#define GPSR0_DU_EXVSYNC_DU_VSYNC		BIT(20)
+#define GPSR0_DU_EXHSYNC_DU_HSYNC		BIT(19)
+#define GPSR0_DU_DOTCLKOUT			BIT(18)
+#define GPSR0_DU_DB7				BIT(17)
+#define GPSR0_DU_DB6				BIT(16)
+#define GPSR0_DU_DB5				BIT(15)
+#define GPSR0_DU_DB4				BIT(14)
+#define GPSR0_DU_DB3				BIT(13)
+#define GPSR0_DU_DB2				BIT(12)
+#define GPSR0_DU_DG7				BIT(11)
+#define GPSR0_DU_DG6				BIT(10)
+#define GPSR0_DU_DG5				BIT(9)
+#define GPSR0_DU_DG4				BIT(8)
+#define GPSR0_DU_DG3				BIT(7)
+#define GPSR0_DU_DG2				BIT(6)
+#define GPSR0_DU_DR7				BIT(5)
+#define GPSR0_DU_DR6				BIT(4)
+#define GPSR0_DU_DR5				BIT(3)
+#define GPSR0_DU_DR4				BIT(2)
+#define GPSR0_DU_DR3				BIT(1)
+#define GPSR0_DU_DR2				BIT(0)
+
+#define GPSR1_DIGRF_CLKOUT			BIT(27)
+#define GPSR1_DIGRF_CLKIN			BIT(26)
+#define GPSR1_CANFD_CLK				BIT(25)
+#define GPSR1_CANFD1_RX				BIT(24)
+#define GPSR1_CANFD1_TX				BIT(23)
+#define GPSR1_CANFD0_RX				BIT(22)
+#define GPSR1_CANFD0_TX				BIT(21)
+#define GPSR1_AVB0_AVTP_CAPTURE			BIT(20)
+#define GPSR1_AVB0_AVTP_MATCH			BIT(19)
+#define GPSR1_AVB0_LINK				BIT(18)
+#define GPSR1_AVB0_PHY_INT			BIT(17)
+#define GPSR1_AVB0_MAGIC			BIT(16)
+#define GPSR1_AVB0_MDC				BIT(15)
+#define GPSR1_AVB0_MDIO				BIT(14)
+#define GPSR1_AVB0_TXCREFCLK			BIT(13)
+#define GPSR1_AVB0_TD3				BIT(12)
+#define GPSR1_AVB0_TD2				BIT(11)
+#define GPSR1_AVB0_TD1				BIT(10)
+#define GPSR1_AVB0_TD0				BIT(9)
+#define GPSR1_AVB0_TXC				BIT(8)
+#define GPSR1_AVB0_TX_CTL			BIT(7)
+#define GPSR1_AVB0_RD3				BIT(6)
+#define GPSR1_AVB0_RD2				BIT(5)
+#define GPSR1_AVB0_RD1				BIT(4)
+#define GPSR1_AVB0_RD0				BIT(3)
+#define GPSR1_AVB0_RXC				BIT(2)
+#define GPSR1_AVB0_RX_CTL			BIT(1)
+#define GPSR1_IRQ0				BIT(0)
+
+#define GPSR2_VI0_FIELD				BIT(16)
+#define GPSR2_VI0_DATA11			BIT(15)
+#define GPSR2_VI0_DATA10			BIT(14)
+#define GPSR2_VI0_DATA9				BIT(13)
+#define GPSR2_VI0_DATA8				BIT(12)
+#define GPSR2_VI0_DATA7				BIT(11)
+#define GPSR2_VI0_DATA6				BIT(10)
+#define GPSR2_VI0_DATA5				BIT(9)
+#define GPSR2_VI0_DATA4				BIT(8)
+#define GPSR2_VI0_DATA3				BIT(7)
+#define GPSR2_VI0_DATA2				BIT(6)
+#define GPSR2_VI0_DATA1				BIT(5)
+#define GPSR2_VI0_DATA0				BIT(4)
+#define GPSR2_VI0_VSYNC_N			BIT(3)
+#define GPSR2_VI0_HSYNC_N			BIT(2)
+#define GPSR2_VI0_CLKENB			BIT(1)
+#define GPSR2_VI0_CLK				BIT(0)
+
+#define GPSR3_VI1_FIELD				BIT(16)
+#define GPSR3_VI1_DATA11			BIT(15)
+#define GPSR3_VI1_DATA10			BIT(14)
+#define GPSR3_VI1_DATA9				BIT(13)
+#define GPSR3_VI1_DATA8				BIT(12)
+#define GPSR3_VI1_DATA7				BIT(11)
+#define GPSR3_VI1_DATA6				BIT(10)
+#define GPSR3_VI1_DATA5				BIT(9)
+#define GPSR3_VI1_DATA4				BIT(8)
+#define GPSR3_VI1_DATA3				BIT(7)
+#define GPSR3_VI1_DATA2				BIT(6)
+#define GPSR3_VI1_DATA1				BIT(5)
+#define GPSR3_VI1_DATA0				BIT(4)
+#define GPSR3_VI1_VSYNC_N			BIT(3)
+#define GPSR3_VI1_HSYNC_N			BIT(2)
+#define GPSR3_VI1_CLKENB			BIT(1)
+#define GPSR3_VI1_CLK				BIT(0)
+
+#define GPSR4_SDA2				BIT(5)
+#define GPSR4_SCL2				BIT(4)
+#define GPSR4_SDA1				BIT(3)
+#define GPSR4_SCL1				BIT(2)
+#define GPSR4_SDA0				BIT(1)
+#define GPSR4_SCL0				BIT(0)
+
+#define GPSR5_RPC_INT_N				BIT(14)
+#define GPSR5_RPC_WP_N				BIT(13)
+#define GPSR5_RPC_RESET_N			BIT(12)
+#define GPSR5_QSPI1_SSL				BIT(11)
+#define GPSR5_QSPI1_IO3				BIT(10)
+#define GPSR5_QSPI1_IO2				BIT(9)
+#define GPSR5_QSPI1_MISO_IO1			BIT(8)
+#define GPSR5_QSPI1_MOSI_IO0			BIT(7)
+#define GPSR5_QSPI1_SPCLK			BIT(6)
+#define GPSR5_QSPI0_SSL				BIT(5)
+#define GPSR5_QSPI0_IO3				BIT(4)
+#define GPSR5_QSPI0_IO2				BIT(3)
+#define GPSR5_QSPI0_MISO_IO1			BIT(2)
+#define GPSR5_QSPI0_MOSI_IO0			BIT(1)
+#define GPSR5_QSPI0_SPCLK			BIT(0)
+
+#define IPSR_28_FUNC(x)				((uint32_t)(x) << 28U)
+#define IPSR_24_FUNC(x)				((uint32_t)(x) << 24U)
+#define IPSR_20_FUNC(x)				((uint32_t)(x) << 20U)
+#define IPSR_16_FUNC(x)				((uint32_t)(x) << 16U)
+#define IPSR_12_FUNC(x)				((uint32_t)(x) << 12U)
+#define IPSR_8_FUNC(x)				((uint32_t)(x) << 8U)
+#define IPSR_4_FUNC(x)				((uint32_t)(x) << 4U)
+#define IPSR_0_FUNC(x)				((uint32_t)(x) << 0U)
+
+#define IOCTRL30_POC_VI0_DATA5			BIT(31)
+#define IOCTRL30_POC_VI0_DATA4			BIT(30)
+#define IOCTRL30_POC_VI0_DATA3			BIT(29)
+#define IOCTRL30_POC_VI0_DATA2			BIT(28)
+#define IOCTRL30_POC_VI0_DATA1			BIT(27)
+#define IOCTRL30_POC_VI0_DATA0			BIT(26)
+#define IOCTRL30_POC_VI0_VSYNC_N		BIT(25)
+#define IOCTRL30_POC_VI0_HSYNC_N		BIT(24)
+#define IOCTRL30_POC_VI0_CLKENB			BIT(23)
+#define IOCTRL30_POC_VI0_CLK			BIT(22)
+#define IOCTRL30_POC_DU_EXODDF_DU_ODDF_DISP_CDE	BIT(21)
+#define IOCTRL30_POC_DU_EXVSYNC_DU_VSYNC	BIT(20)
+#define IOCTRL30_POC_DU_EXHSYNC_DU_HSYNC	BIT(19)
+#define IOCTRL30_POC_DU_DOTCLKOUT		BIT(18)
+#define IOCTRL30_POC_DU_DB7			BIT(17)
+#define IOCTRL30_POC_DU_DB6			BIT(16)
+#define IOCTRL30_POC_DU_DB5			BIT(15)
+#define IOCTRL30_POC_DU_DB4			BIT(14)
+#define IOCTRL30_POC_DU_DB3			BIT(13)
+#define IOCTRL30_POC_DU_DB2			BIT(12)
+#define IOCTRL30_POC_DU_DG7			BIT(11)
+#define IOCTRL30_POC_DU_DG6			BIT(10)
+#define IOCTRL30_POC_DU_DG5			BIT(9)
+#define IOCTRL30_POC_DU_DG4			BIT(8)
+#define IOCTRL30_POC_DU_DG3			BIT(7)
+#define IOCTRL30_POC_DU_DG2			BIT(6)
+#define IOCTRL30_POC_DU_DR7			BIT(5)
+#define IOCTRL30_POC_DU_DR6			BIT(4)
+#define IOCTRL30_POC_DU_DR5			BIT(3)
+#define IOCTRL30_POC_DU_DR4			BIT(2)
+#define IOCTRL30_POC_DU_DR3			BIT(1)
+#define IOCTRL30_POC_DU_DR2			BIT(0)
+
+#define IOCTRL31_POC_DUMMY_31			BIT(31)
+#define IOCTRL31_POC_DUMMY_30			BIT(30)
+#define IOCTRL31_POC_DUMMY_29			BIT(29)
+#define IOCTRL31_POC_DUMMY_28			BIT(28)
+#define IOCTRL31_POC_DUMMY_27			BIT(27)
+#define IOCTRL31_POC_DUMMY_26			BIT(26)
+#define IOCTRL31_POC_DUMMY_25			BIT(25)
+#define IOCTRL31_POC_DUMMY_24			BIT(24)
+#define IOCTRL31_POC_VI1_FIELD			BIT(23)
+#define IOCTRL31_POC_VI1_DATA11			BIT(22)
+#define IOCTRL31_POC_VI1_DATA10			BIT(21)
+#define IOCTRL31_POC_VI1_DATA9			BIT(20)
+#define IOCTRL31_POC_VI1_DATA8			BIT(19)
+#define IOCTRL31_POC_VI1_DATA7			BIT(18)
+#define IOCTRL31_POC_VI1_DATA6			BIT(17)
+#define IOCTRL31_POC_VI1_DATA5			BIT(16)
+#define IOCTRL31_POC_VI1_DATA4			BIT(15)
+#define IOCTRL31_POC_VI1_DATA3			BIT(14)
+#define IOCTRL31_POC_VI1_DATA2			BIT(13)
+#define IOCTRL31_POC_VI1_DATA1			BIT(12)
+#define IOCTRL31_POC_VI1_DATA0			BIT(11)
+#define IOCTRL31_POC_VI1_VSYNC_N		BIT(10)
+#define IOCTRL31_POC_VI1_HSYNC_N		BIT(9)
+#define IOCTRL31_POC_VI1_CLKENB			BIT(8)
+#define IOCTRL31_POC_VI1_CLK			BIT(7)
+#define IOCTRL31_POC_VI0_FIELD			BIT(6)
+#define IOCTRL31_POC_VI0_DATA11			BIT(5)
+#define IOCTRL31_POC_VI0_DATA10			BIT(4)
+#define IOCTRL31_POC_VI0_DATA9			BIT(3)
+#define IOCTRL31_POC_VI0_DATA8			BIT(2)
+#define IOCTRL31_POC_VI0_DATA7			BIT(1)
+#define IOCTRL31_POC_VI0_DATA6			BIT(0)
+#define IOCTRL32_POC2_VREF			BIT(0)
+#define IOCTRL40_SD0TDSEL1			BIT(1)
+#define IOCTRL40_SD0TDSEL0			BIT(0)
+
+#define PUEN0_PUEN_VI0_CLK			BIT(31)
+#define PUEN0_PUEN_TDI				BIT(30)
+#define PUEN0_PUEN_TMS				BIT(29)
+#define PUEN0_PUEN_TCK				BIT(28)
+#define PUEN0_PUEN_TRST_N			BIT(27)
+#define PUEN0_PUEN_IRQ0				BIT(26)
+#define PUEN0_PUEN_FSCLKST_N			BIT(25)
+#define PUEN0_PUEN_EXTALR			BIT(24)
+#define PUEN0_PUEN_PRESETOUT_N			BIT(23)
+#define PUEN0_PUEN_DU_DOTCLKIN			BIT(22)
+#define PUEN0_PUEN_DU_EXODDF_DU_ODDF_DISP_CDE	BIT(21)
+#define PUEN0_PUEN_DU_EXVSYNC_DU_VSYNC		BIT(20)
+#define PUEN0_PUEN_DU_EXHSYNC_DU_HSYNC		BIT(19)
+#define PUEN0_PUEN_DU_DOTCLKOUT			BIT(18)
+#define PUEN0_PUEN_DU_DB7			BIT(17)
+#define PUEN0_PUEN_DU_DB6			BIT(16)
+#define PUEN0_PUEN_DU_DB5			BIT(15)
+#define PUEN0_PUEN_DU_DB4			BIT(14)
+#define PUEN0_PUEN_DU_DB3			BIT(13)
+#define PUEN0_PUEN_DU_DB2			BIT(12)
+#define PUEN0_PUEN_DU_DG7			BIT(11)
+#define PUEN0_PUEN_DU_DG6			BIT(10)
+#define PUEN0_PUEN_DU_DG5			BIT(9)
+#define PUEN0_PUEN_DU_DG4			BIT(8)
+#define PUEN0_PUEN_DU_DG3			BIT(7)
+#define PUEN0_PUEN_DU_DG2			BIT(6)
+#define PUEN0_PUEN_DU_DR7			BIT(5)
+#define PUEN0_PUEN_DU_DR6			BIT(4)
+#define PUEN0_PUEN_DU_DR5			BIT(3)
+#define PUEN0_PUEN_DU_DR4			BIT(2)
+#define PUEN0_PUEN_DU_DR3			BIT(1)
+#define PUEN0_PUEN_DU_DR2			BIT(0)
+
+#define PUEN1_PUEN_VI1_DATA11			BIT(31)
+#define PUEN1_PUEN_VI1_DATA10			BIT(30)
+#define PUEN1_PUEN_VI1_DATA9			BIT(29)
+#define PUEN1_PUEN_VI1_DATA8			BIT(28)
+#define PUEN1_PUEN_VI1_DATA7			BIT(27)
+#define PUEN1_PUEN_VI1_DATA6			BIT(26)
+#define PUEN1_PUEN_VI1_DATA5			BIT(25)
+#define PUEN1_PUEN_VI1_DATA4			BIT(24)
+#define PUEN1_PUEN_VI1_DATA3			BIT(23)
+#define PUEN1_PUEN_VI1_DATA2			BIT(22)
+#define PUEN1_PUEN_VI1_DATA1			BIT(21)
+#define PUEN1_PUEN_VI1_DATA0			BIT(20)
+#define PUEN1_PUEN_VI1_VSYNC_N			BIT(19)
+#define PUEN1_PUEN_VI1_HSYNC_N			BIT(18)
+#define PUEN1_PUEN_VI1_CLKENB			BIT(17)
+#define PUEN1_PUEN_VI1_CLK			BIT(16)
+#define PUEN1_PUEN_VI0_FIELD			BIT(15)
+#define PUEN1_PUEN_VI0_DATA11			BIT(14)
+#define PUEN1_PUEN_VI0_DATA10			BIT(13)
+#define PUEN1_PUEN_VI0_DATA9			BIT(12)
+#define PUEN1_PUEN_VI0_DATA8			BIT(11)
+#define PUEN1_PUEN_VI0_DATA7			BIT(10)
+#define PUEN1_PUEN_VI0_DATA6			BIT(9)
+#define PUEN1_PUEN_VI0_DATA5			BIT(8)
+#define PUEN1_PUEN_VI0_DATA4			BIT(7)
+#define PUEN1_PUEN_VI0_DATA3			BIT(6)
+#define PUEN1_PUEN_VI0_DATA2			BIT(5)
+#define PUEN1_PUEN_VI0_DATA1			BIT(4)
+#define PUEN1_PUEN_VI0_DATA0			BIT(3)
+#define PUEN1_PUEN_VI0_VSYNC_N			BIT(2)
+#define PUEN1_PUEN_VI0_HSYNC_N			BIT(1)
+#define PUEN1_PUEN_VI0_CLKENB			BIT(0)
+
+#define PUEN2_PUEN_CANFD_CLK			BIT(31)
+#define PUEN2_PUEN_CANFD1_RX			BIT(30)
+#define PUEN2_PUEN_CANFD1_TX			BIT(29)
+#define PUEN2_PUEN_CANFD0_RX			BIT(28)
+#define PUEN2_PUEN_CANFD0_TX			BIT(27)
+#define PUEN2_PUEN_AVB0_AVTP_CAPTURE		BIT(26)
+#define PUEN2_PUEN_AVB0_AVTP_MATCH		BIT(25)
+#define PUEN2_PUEN_AVB0_LINK			BIT(24)
+#define PUEN2_PUEN_AVB0_PHY_INT			BIT(23)
+#define PUEN2_PUEN_AVB0_MAGIC			BIT(22)
+#define PUEN2_PUEN_AVB0_MDC			BIT(21)
+#define PUEN2_PUEN_AVB0_MDIO			BIT(20)
+#define PUEN2_PUEN_AVB0_TXCREFCLK		BIT(19)
+#define PUEN2_PUEN_AVB0_TD3			BIT(18)
+#define PUEN2_PUEN_AVB0_TD2			BIT(17)
+#define PUEN2_PUEN_AVB0_TD1			BIT(16)
+#define PUEN2_PUEN_AVB0_TD0			BIT(15)
+#define PUEN2_PUEN_AVB0_TXC			BIT(14)
+#define PUEN2_PUEN_AVB0_TX_CTL			BIT(13)
+#define PUEN2_PUEN_AVB0_RD3			BIT(12)
+#define PUEN2_PUEN_AVB0_RD2			BIT(11)
+#define PUEN2_PUEN_AVB0_RD1			BIT(10)
+#define PUEN2_PUEN_AVB0_RD0			BIT(9)
+#define PUEN2_PUEN_AVB0_RXC			BIT(8)
+#define PUEN2_PUEN_AVB0_RX_CTL			BIT(7)
+#define PUEN2_PUEN_SDA2				BIT(6)
+#define PUEN2_PUEN_SCL2				BIT(5)
+#define PUEN2_PUEN_SDA1				BIT(4)
+#define PUEN2_PUEN_SCL1				BIT(3)
+#define PUEN2_PUEN_SDA0				BIT(2)
+#define PUEN2_PUEN_SCL0				BIT(1)
+#define PUEN2_PUEN_VI1_FIELD			BIT(0)
+
+#define PUEN3_PUEN_DIGRF_CLKOUT			BIT(16)
+#define PUEN3_PUEN_DIGRF_CLKIN			BIT(15)
+#define PUEN3_PUEN_RPC_INT_N			BIT(14)
+#define PUEN3_PUEN_RPC_WP_N			BIT(13)
+#define PUEN3_PUEN_RPC_RESET_N			BIT(12)
+#define PUEN3_PUEN_QSPI1_SSL			BIT(11)
+#define PUEN3_PUEN_QSPI1_IO3			BIT(10)
+#define PUEN3_PUEN_QSPI1_IO2			BIT(9)
+#define PUEN3_PUEN_QSPI1_MISO_IO1		BIT(8)
+#define PUEN3_PUEN_QSPI1_MOSI_IO0		BIT(7)
+#define PUEN3_PUEN_QSPI1_SPCLK			BIT(6)
+#define PUEN3_PUEN_QSPI0_SSL			BIT(5)
+#define PUEN3_PUEN_QSPI0_IO3			BIT(4)
+#define PUEN3_PUEN_QSPI0_IO2			BIT(3)
+#define PUEN3_PUEN_QSPI0_MISO_IO1		BIT(2)
+#define PUEN3_PUEN_QSPI0_MOSI_IO0		BIT(1)
+#define PUEN3_PUEN_QSPI0_SPCLK			BIT(0)
+
+#define PUD0_PUD_VI0_CLK			BIT(31)
+#define PUD0_PUD_IRQ0				BIT(26)
+#define PUD0_PUD_FSCLKST_N			BIT(25)
+#define PUD0_PUD_PRESETOUT_N			BIT(23)
+#define PUD0_PUD_DU_EXODDF_DU_ODDF_DISP_CDE	BIT(21)
+#define PUD0_PUD_DU_EXVSYNC_DU_VSYNC		BIT(20)
+#define PUD0_PUD_DU_EXHSYNC_DU_HSYNC		BIT(19)
+#define PUD0_PUD_DU_DOTCLKOUT			BIT(18)
+#define PUD0_PUD_DU_DB7				BIT(17)
+#define PUD0_PUD_DU_DB6				BIT(16)
+#define PUD0_PUD_DU_DB5				BIT(15)
+#define PUD0_PUD_DU_DB4				BIT(14)
+#define PUD0_PUD_DU_DB3				BIT(13)
+#define PUD0_PUD_DU_DB2				BIT(12)
+#define PUD0_PUD_DU_DG7				BIT(11)
+#define PUD0_PUD_DU_DG6				BIT(10)
+#define PUD0_PUD_DU_DG5				BIT(9)
+#define PUD0_PUD_DU_DG4				BIT(8)
+#define PUD0_PUD_DU_DG3				BIT(7)
+#define PUD0_PUD_DU_DG2				BIT(6)
+#define PUD0_PUD_DU_DR7				BIT(5)
+#define PUD0_PUD_DU_DR6				BIT(4)
+#define PUD0_PUD_DU_DR5				BIT(3)
+#define PUD0_PUD_DU_DR4				BIT(2)
+#define PUD0_PUD_DU_DR3				BIT(1)
+#define PUD0_PUD_DU_DR2				BIT(0)
+
+#define PUD1_PUD_VI1_DATA11			BIT(31)
+#define PUD1_PUD_VI1_DATA10			BIT(30)
+#define PUD1_PUD_VI1_DATA9			BIT(29)
+#define PUD1_PUD_VI1_DATA8			BIT(28)
+#define PUD1_PUD_VI1_DATA7			BIT(27)
+#define PUD1_PUD_VI1_DATA6			BIT(26)
+#define PUD1_PUD_VI1_DATA5			BIT(25)
+#define PUD1_PUD_VI1_DATA4			BIT(24)
+#define PUD1_PUD_VI1_DATA3			BIT(23)
+#define PUD1_PUD_VI1_DATA2			BIT(22)
+#define PUD1_PUD_VI1_DATA1			BIT(21)
+#define PUD1_PUD_VI1_DATA0			BIT(20)
+#define PUD1_PUD_VI1_VSYNC_N			BIT(19)
+#define PUD1_PUD_VI1_HSYNC_N			BIT(18)
+#define PUD1_PUD_VI1_CLKENB			BIT(17)
+#define PUD1_PUD_VI1_CLK			BIT(16)
+#define PUD1_PUD_VI0_FIELD			BIT(15)
+#define PUD1_PUD_VI0_DATA11			BIT(14)
+#define PUD1_PUD_VI0_DATA10			BIT(13)
+#define PUD1_PUD_VI0_DATA9			BIT(12)
+#define PUD1_PUD_VI0_DATA8			BIT(11)
+#define PUD1_PUD_VI0_DATA7			BIT(10)
+#define PUD1_PUD_VI0_DATA6			BIT(9)
+#define PUD1_PUD_VI0_DATA5			BIT(8)
+#define PUD1_PUD_VI0_DATA4			BIT(7)
+#define PUD1_PUD_VI0_DATA3			BIT(6)
+#define PUD1_PUD_VI0_DATA2			BIT(5)
+#define PUD1_PUD_VI0_DATA1			BIT(4)
+#define PUD1_PUD_VI0_DATA0			BIT(3)
+#define PUD1_PUD_VI0_VSYNC_N			BIT(2)
+#define PUD1_PUD_VI0_HSYNC_N			BIT(1)
+#define PUD1_PUD_VI0_CLKENB			BIT(0)
+
+#define PUD2_PUD_CANFD_CLK			BIT(31)
+#define PUD2_PUD_CANFD1_RX			BIT(30)
+#define PUD2_PUD_CANFD1_TX			BIT(29)
+#define PUD2_PUD_CANFD0_RX			BIT(28)
+#define PUD2_PUD_CANFD0_TX			BIT(27)
+#define PUD2_PUD_AVB0_AVTP_CAPTURE		BIT(26)
+#define PUD2_PUD_AVB0_AVTP_MATCH		BIT(25)
+#define PUD2_PUD_AVB0_LINK			BIT(24)
+#define PUD2_PUD_AVB0_PHY_INT			BIT(23)
+#define PUD2_PUD_AVB0_MAGIC			BIT(22)
+#define PUD2_PUD_AVB0_MDC			BIT(21)
+#define PUD2_PUD_AVB0_MDIO			BIT(20)
+#define PUD2_PUD_AVB0_TXCREFCLK			BIT(19)
+#define PUD2_PUD_AVB0_TD3			BIT(18)
+#define PUD2_PUD_AVB0_TD2			BIT(17)
+#define PUD2_PUD_AVB0_TD1			BIT(16)
+#define PUD2_PUD_AVB0_TD0			BIT(15)
+#define PUD2_PUD_AVB0_TXC			BIT(14)
+#define PUD2_PUD_AVB0_TX_CTL			BIT(13)
+#define PUD2_PUD_AVB0_RD3			BIT(12)
+#define PUD2_PUD_AVB0_RD2			BIT(11)
+#define PUD2_PUD_AVB0_RD1			BIT(10)
+#define PUD2_PUD_AVB0_RD0			BIT(9)
+#define PUD2_PUD_AVB0_RXC			BIT(8)
+#define PUD2_PUD_AVB0_RX_CTL			BIT(7)
+#define PUD2_PUD_SDA2				BIT(6)
+#define PUD2_PUD_SCL2				BIT(5)
+#define PUD2_PUD_SDA1				BIT(4)
+#define PUD2_PUD_SCL1				BIT(3)
+#define PUD2_PUD_SDA0				BIT(2)
+#define PUD2_PUD_SCL0				BIT(1)
+#define PUD2_PUD_VI1_FIELD			BIT(0)
+
+#define PUD3_PUD_DIGRF_CLKOUT			BIT(16)
+#define PUD3_PUD_DIGRF_CLKIN			BIT(15)
+#define PUD3_PUD_RPC_INT_N			BIT(14)
+#define PUD3_PUD_RPC_WP_N			BIT(13)
+#define PUD3_PUD_RPC_RESET_N			BIT(12)
+#define PUD3_PUD_QSPI1_SSL			BIT(11)
+#define PUD3_PUD_QSPI1_IO3			BIT(10)
+#define PUD3_PUD_QSPI1_IO2			BIT(9)
+#define PUD3_PUD_QSPI1_MISO_IO1			BIT(8)
+#define PUD3_PUD_QSPI1_MOSI_IO0			BIT(7)
+#define PUD3_PUD_QSPI1_SPCLK			BIT(6)
+#define PUD3_PUD_QSPI0_SSL			BIT(5)
+#define PUD3_PUD_QSPI0_IO3			BIT(4)
+#define PUD3_PUD_QSPI0_IO2			BIT(3)
+#define PUD3_PUD_QSPI0_MISO_IO1			BIT(2)
+#define PUD3_PUD_QSPI0_MOSI_IO0			BIT(1)
+#define PUD3_PUD_QSPI0_SPCLK			BIT(0)
+
+#define MOD_SEL0_sel_hscif0			BIT(10)
+#define MOD_SEL0_sel_scif1			BIT(9)
+#define MOD_SEL0_sel_canfd0			BIT(8)
+#define MOD_SEL0_sel_pwm4			BIT(7)
+#define MOD_SEL0_sel_pwm3			BIT(6)
+#define MOD_SEL0_sel_pwm2			BIT(5)
+#define MOD_SEL0_sel_pwm1			BIT(4)
+#define MOD_SEL0_sel_pwm0			BIT(3)
+#define MOD_SEL0_sel_rfso			BIT(2)
+#define MOD_SEL0_sel_rsp			BIT(1)
+#define MOD_SEL0_sel_tmu			BIT(0)
+
+/* SCIF3 Registers for Dummy write */
+#define SCIF3_BASE		(0xE6C50000U)
+#define SCIF3_SCFCR		(SCIF3_BASE + 0x0018U)
+#define SCIF3_SCFDR		(SCIF3_BASE + 0x001CU)
+#define SCFCR_DATA		(0x0000U)
+
+/* Realtime module stop control */
+#define CPG_BASE		(0xE6150000U)
+#define CPG_MSTPSR0		(CPG_BASE + 0x0030U)
+#define CPG_RMSTPCR0		(CPG_BASE + 0x0110U)
+#define RMSTPCR0_RTDMAC		(0x00200000U)
+
+/* RT-DMAC Registers */
+#define RTDMAC_CH		(0U)		/* choose 0 to 15 */
+
+#define RTDMAC_BASE		(0xFFC10000U)
+#define RTDMAC_RDMOR		(RTDMAC_BASE + 0x0060U)
+#define RTDMAC_RDMCHCLR		(RTDMAC_BASE + 0x0080U)
+#define RTDMAC_RDMSAR(x)	(RTDMAC_BASE + 0x8000U + (0x80U * (x)))
+#define RTDMAC_RDMDAR(x)	(RTDMAC_BASE + 0x8004U + (0x80U * (x)))
+#define RTDMAC_RDMTCR(x)	(RTDMAC_BASE + 0x8008U + (0x80U * (x)))
+#define RTDMAC_RDMCHCR(x)	(RTDMAC_BASE + 0x800CU + (0x80U * (x)))
+#define RTDMAC_RDMCHCRB(x)	(RTDMAC_BASE + 0x801CU + (0x80U * (x)))
+#define RTDMAC_RDMDPBASE(x)	(RTDMAC_BASE + 0x8050U + (0x80U * (x)))
+#define RTDMAC_DESC_BASE	(RTDMAC_BASE + 0xA000U)
+#define RTDMAC_DESC_RDMSAR	(RTDMAC_DESC_BASE + 0x0000U)
+#define RTDMAC_DESC_RDMDAR	(RTDMAC_DESC_BASE + 0x0004U)
+#define RTDMAC_DESC_RDMTCR	(RTDMAC_DESC_BASE + 0x0008U)
+
+#define RDMOR_DME		(0x0001U)	/* DMA Master Enable */
+#define RDMCHCR_DPM_INFINITE	(0x30000000U)	/* Infinite repeat mode */
+#define RDMCHCR_RPT_TCR		(0x02000000U)	/* enable to update TCR */
+#define RDMCHCR_TS_2		(0x00000008U)	/* Word(2byte) units transfer */
+#define RDMCHCR_RS_AUTO		(0x00000400U)	/* Auto request */
+#define RDMCHCR_DE		(0x00000001U)	/* DMA Enable */
+#define RDMCHCRB_DRST		(0x00008000U)	/* Descriptor reset */
+#define RDMCHCRB_SLM_256	(0x00000080U)	/* once in 256 clock cycle */
+#define RDMDPBASE_SEL_EXT	(0x00000001U)	/* External memory use */
+
+static void pfc_reg_write(uint32_t addr, uint32_t data)
+{
+	mmio_write_32(PFC_PMMR, ~data);
+	mmio_write_32((uintptr_t)addr, data);
+}
+
+static void start_rtdma0_descriptor(void)
+{
+	uint32_t reg;
+
+	/* Module stop clear */
+	while ((mmio_read_32(CPG_MSTPSR0) & RMSTPCR0_RTDMAC) != 0U) {
+		reg = mmio_read_32(CPG_RMSTPCR0);
+		reg &= ~RMSTPCR0_RTDMAC;
+		cpg_write(CPG_RMSTPCR0, reg);
+	}
+
+	/* Initialize ch0, Reset Descriptor */
+	mmio_write_32(RTDMAC_RDMCHCLR, BIT(RTDMAC_CH));
+	mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_DRST);
+
+	/* Enable DMA */
+	mmio_write_16(RTDMAC_RDMOR, RDMOR_DME);
+
+	/* Set first transfer */
+	mmio_write_32(RTDMAC_RDMSAR(RTDMAC_CH), RCAR_PRR);
+	mmio_write_32(RTDMAC_RDMDAR(RTDMAC_CH), SCIF3_SCFDR);
+	mmio_write_32(RTDMAC_RDMTCR(RTDMAC_CH), 0x00000001U);
+
+	/* Set descriptor */
+	mmio_write_32(RTDMAC_DESC_RDMSAR, 0x00000000U);
+	mmio_write_32(RTDMAC_DESC_RDMDAR, 0x00000000U);
+	mmio_write_32(RTDMAC_DESC_RDMTCR, 0x00200000U);
+	mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_SLM_256);
+	mmio_write_32(RTDMAC_RDMDPBASE(RTDMAC_CH), RTDMAC_DESC_BASE
+						 | RDMDPBASE_SEL_EXT);
+
+	/* Set transfer parameter, Start transfer */
+	mmio_write_32(RTDMAC_RDMCHCR(RTDMAC_CH), RDMCHCR_DPM_INFINITE
+					       | RDMCHCR_RPT_TCR
+					       | RDMCHCR_TS_2
+					       | RDMCHCR_RS_AUTO
+					       | RDMCHCR_DE);
+}
+
+void pfc_init_v3m(void)
+{
+	/* Work around for PFC eratta */
+	start_rtdma0_descriptor();
+
+	// pin function
+	// md[4:1]!=0000
+	/* initialize GPIO/perihperal function select */
+
+	pfc_reg_write(PFC_GPSR0, 0x00000000);
+
+	pfc_reg_write(PFC_GPSR1, GPSR1_CANFD_CLK);
+
+	pfc_reg_write(PFC_GPSR2, 0x00000000);
+
+	pfc_reg_write(PFC_GPSR3, 0x00000000);
+
+	pfc_reg_write(PFC_GPSR4, GPSR4_SDA2
+				   | GPSR4_SCL2);
+
+	pfc_reg_write(PFC_GPSR5, GPSR5_QSPI1_SSL
+				   | GPSR5_QSPI1_IO3
+				   | GPSR5_QSPI1_IO2
+				   | GPSR5_QSPI1_MISO_IO1
+				   | GPSR5_QSPI1_MOSI_IO0
+				   | GPSR5_QSPI1_SPCLK
+				   | GPSR5_QSPI0_SSL
+				   | GPSR5_QSPI0_IO3
+				   | GPSR5_QSPI0_IO2
+				   | GPSR5_QSPI0_MISO_IO1
+				   | GPSR5_QSPI0_MOSI_IO0
+				   | GPSR5_QSPI0_SPCLK);
+
+	/* initialize peripheral function select */
+	pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(0)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(4)
+				   | IPSR_20_FUNC(4)
+				   | IPSR_16_FUNC(4)
+				   | IPSR_12_FUNC(4)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(0)
+				   | IPSR_24_FUNC(0)
+				   | IPSR_20_FUNC(0)
+				   | IPSR_16_FUNC(4)
+				   | IPSR_12_FUNC(0)
+				   | IPSR_8_FUNC(0)
+				   | IPSR_4_FUNC(0)
+				   | IPSR_0_FUNC(0));
+
+	/* initialize POC Control */
+
+	pfc_reg_write(PFC_POCCTRL0, IOCTRL30_POC_VI0_DATA5
+				   | IOCTRL30_POC_VI0_DATA4
+				   | IOCTRL30_POC_VI0_DATA3
+				   | IOCTRL30_POC_VI0_DATA2
+				   | IOCTRL30_POC_VI0_DATA1
+				   | IOCTRL30_POC_VI0_DATA0
+				   | IOCTRL30_POC_VI0_VSYNC_N
+				   | IOCTRL30_POC_VI0_HSYNC_N
+				   | IOCTRL30_POC_VI0_CLKENB
+				   | IOCTRL30_POC_VI0_CLK
+				   | IOCTRL30_POC_DU_EXODDF_DU_ODDF_DISP_CDE
+				   | IOCTRL30_POC_DU_EXVSYNC_DU_VSYNC
+				   | IOCTRL30_POC_DU_EXHSYNC_DU_HSYNC
+				   | IOCTRL30_POC_DU_DOTCLKOUT
+				   | IOCTRL30_POC_DU_DB7
+				   | IOCTRL30_POC_DU_DB6
+				   | IOCTRL30_POC_DU_DB5
+				   | IOCTRL30_POC_DU_DB4
+				   | IOCTRL30_POC_DU_DB3
+				   | IOCTRL30_POC_DU_DB2
+				   | IOCTRL30_POC_DU_DG7
+				   | IOCTRL30_POC_DU_DG6
+				   | IOCTRL30_POC_DU_DG5
+				   | IOCTRL30_POC_DU_DG4
+				   | IOCTRL30_POC_DU_DG3
+				   | IOCTRL30_POC_DU_DG2
+				   | IOCTRL30_POC_DU_DR7
+				   | IOCTRL30_POC_DU_DR6
+				   | IOCTRL30_POC_DU_DR5
+				   | IOCTRL30_POC_DU_DR4
+				   | IOCTRL30_POC_DU_DR3
+				   | IOCTRL30_POC_DU_DR2);
+
+	pfc_reg_write(PFC_IOCTRL31, IOCTRL31_POC_DUMMY_31
+				   | IOCTRL31_POC_DUMMY_30
+				   | IOCTRL31_POC_DUMMY_29
+				   | IOCTRL31_POC_DUMMY_28
+				   | IOCTRL31_POC_DUMMY_27
+				   | IOCTRL31_POC_DUMMY_26
+				   | IOCTRL31_POC_DUMMY_25
+				   | IOCTRL31_POC_DUMMY_24
+				   | IOCTRL31_POC_VI1_FIELD
+				   | IOCTRL31_POC_VI1_DATA11
+				   | IOCTRL31_POC_VI1_DATA10
+				   | IOCTRL31_POC_VI1_DATA9
+				   | IOCTRL31_POC_VI1_DATA8
+				   | IOCTRL31_POC_VI1_DATA7
+				   | IOCTRL31_POC_VI1_DATA6
+				   | IOCTRL31_POC_VI1_DATA5
+				   | IOCTRL31_POC_VI1_DATA4
+				   | IOCTRL31_POC_VI1_DATA3
+				   | IOCTRL31_POC_VI1_DATA2
+				   | IOCTRL31_POC_VI1_DATA1
+				   | IOCTRL31_POC_VI1_DATA0
+				   | IOCTRL31_POC_VI1_VSYNC_N
+				   | IOCTRL31_POC_VI1_HSYNC_N
+				   | IOCTRL31_POC_VI1_CLKENB
+				   | IOCTRL31_POC_VI1_CLK
+				   | IOCTRL31_POC_VI0_FIELD
+				   | IOCTRL31_POC_VI0_DATA11
+				   | IOCTRL31_POC_VI0_DATA10
+				   | IOCTRL31_POC_VI0_DATA9
+				   | IOCTRL31_POC_VI0_DATA8
+				   | IOCTRL31_POC_VI0_DATA7
+				   | IOCTRL31_POC_VI0_DATA6);
+
+	pfc_reg_write(PFC_POCCTRL2, 0x00000000);
+
+	pfc_reg_write(PFC_TDSELCTRL0, 0x00000000);
+
+	/* initialize Pull enable */
+	pfc_reg_write(PFC_PUEN0, PUEN0_PUEN_VI0_CLK
+				   | PUEN0_PUEN_TDI
+				   | PUEN0_PUEN_TMS
+				   | PUEN0_PUEN_TCK
+				   | PUEN0_PUEN_TRST_N
+				   | PUEN0_PUEN_IRQ0
+				   | PUEN0_PUEN_FSCLKST_N
+				   | PUEN0_PUEN_DU_EXHSYNC_DU_HSYNC
+				   | PUEN0_PUEN_DU_DOTCLKOUT
+				   | PUEN0_PUEN_DU_DB7
+				   | PUEN0_PUEN_DU_DB6
+				   | PUEN0_PUEN_DU_DB5
+				   | PUEN0_PUEN_DU_DB4
+				   | PUEN0_PUEN_DU_DB3
+				   | PUEN0_PUEN_DU_DB2
+				   | PUEN0_PUEN_DU_DG7
+				   | PUEN0_PUEN_DU_DG6
+				   | PUEN0_PUEN_DU_DG5
+				   | PUEN0_PUEN_DU_DG4
+				   | PUEN0_PUEN_DU_DG3
+				   | PUEN0_PUEN_DU_DG2
+				   | PUEN0_PUEN_DU_DR7
+				   | PUEN0_PUEN_DU_DR6
+				   | PUEN0_PUEN_DU_DR5
+				   | PUEN0_PUEN_DU_DR4
+				   | PUEN0_PUEN_DU_DR3
+				   | PUEN0_PUEN_DU_DR2);
+
+	pfc_reg_write(PFC_PUEN1, PUEN1_PUEN_VI1_DATA11
+				   | PUEN1_PUEN_VI1_DATA10
+				   | PUEN1_PUEN_VI1_DATA9
+				   | PUEN1_PUEN_VI1_DATA8
+				   | PUEN1_PUEN_VI1_DATA7
+				   | PUEN1_PUEN_VI1_DATA6
+				   | PUEN1_PUEN_VI1_DATA5
+				   | PUEN1_PUEN_VI1_DATA4
+				   | PUEN1_PUEN_VI1_DATA3
+				   | PUEN1_PUEN_VI1_DATA2
+				   | PUEN1_PUEN_VI1_DATA1
+				   | PUEN1_PUEN_VI1_DATA0
+				   | PUEN1_PUEN_VI1_VSYNC_N
+				   | PUEN1_PUEN_VI1_HSYNC_N
+				   | PUEN1_PUEN_VI1_CLKENB
+				   | PUEN1_PUEN_VI1_CLK
+				   | PUEN1_PUEN_VI0_DATA11
+				   | PUEN1_PUEN_VI0_DATA10
+				   | PUEN1_PUEN_VI0_DATA9
+				   | PUEN1_PUEN_VI0_DATA8
+				   | PUEN1_PUEN_VI0_DATA7
+				   | PUEN1_PUEN_VI0_DATA6
+				   | PUEN1_PUEN_VI0_DATA5
+				   | PUEN1_PUEN_VI0_DATA4
+				   | PUEN1_PUEN_VI0_DATA3
+				   | PUEN1_PUEN_VI0_DATA2
+				   | PUEN1_PUEN_VI0_DATA1);
+
+	pfc_reg_write(PFC_PUEN2, PUEN2_PUEN_CANFD_CLK
+				   | PUEN2_PUEN_CANFD1_RX
+				   | PUEN2_PUEN_CANFD1_TX
+				   | PUEN2_PUEN_CANFD0_RX
+				   | PUEN2_PUEN_CANFD0_TX
+				   | PUEN2_PUEN_AVB0_AVTP_CAPTURE
+				   | PUEN2_PUEN_AVB0_AVTP_MATCH
+				   | PUEN2_PUEN_AVB0_LINK
+				   | PUEN2_PUEN_AVB0_PHY_INT
+				   | PUEN2_PUEN_AVB0_MAGIC
+				   | PUEN2_PUEN_AVB0_TXCREFCLK
+				   | PUEN2_PUEN_AVB0_TD3
+				   | PUEN2_PUEN_AVB0_TD2
+				   | PUEN2_PUEN_AVB0_TD1
+				   | PUEN2_PUEN_AVB0_TD0
+				   | PUEN2_PUEN_AVB0_TXC
+				   | PUEN2_PUEN_AVB0_TX_CTL
+				   | PUEN2_PUEN_AVB0_RD3
+				   | PUEN2_PUEN_AVB0_RD2
+				   | PUEN2_PUEN_AVB0_RD1
+				   | PUEN2_PUEN_AVB0_RD0
+				   | PUEN2_PUEN_AVB0_RXC
+				   | PUEN2_PUEN_AVB0_RX_CTL
+				   | PUEN2_PUEN_VI1_FIELD);
+
+	pfc_reg_write(PFC_PUEN3, PUEN3_PUEN_DIGRF_CLKOUT
+				   | PUEN3_PUEN_DIGRF_CLKIN);
+
+	/* initialize PUD Control */
+	pfc_reg_write(PFC_PUD0, PUD0_PUD_VI0_CLK
+				   | PUD0_PUD_IRQ0
+				   | PUD0_PUD_FSCLKST_N
+				   | PUD0_PUD_DU_EXODDF_DU_ODDF_DISP_CDE
+				   | PUD0_PUD_DU_EXVSYNC_DU_VSYNC
+				   | PUD0_PUD_DU_EXHSYNC_DU_HSYNC
+				   | PUD0_PUD_DU_DOTCLKOUT
+				   | PUD0_PUD_DU_DB7
+				   | PUD0_PUD_DU_DB6
+				   | PUD0_PUD_DU_DB5
+				   | PUD0_PUD_DU_DB4
+				   | PUD0_PUD_DU_DB3
+				   | PUD0_PUD_DU_DB2
+				   | PUD0_PUD_DU_DG7
+				   | PUD0_PUD_DU_DG6
+				   | PUD0_PUD_DU_DG5
+				   | PUD0_PUD_DU_DG4
+				   | PUD0_PUD_DU_DG3
+				   | PUD0_PUD_DU_DG2
+				   | PUD0_PUD_DU_DR7
+				   | PUD0_PUD_DU_DR6
+				   | PUD0_PUD_DU_DR5
+				   | PUD0_PUD_DU_DR4
+				   | PUD0_PUD_DU_DR3
+				   | PUD0_PUD_DU_DR2);
+
+	pfc_reg_write(PFC_PUD1, PUD1_PUD_VI1_DATA11
+				   | PUD1_PUD_VI1_DATA10
+				   | PUD1_PUD_VI1_DATA9
+				   | PUD1_PUD_VI1_DATA8
+				   | PUD1_PUD_VI1_DATA7
+				   | PUD1_PUD_VI1_DATA6
+				   | PUD1_PUD_VI1_DATA5
+				   | PUD1_PUD_VI1_DATA4
+				   | PUD1_PUD_VI1_DATA3
+				   | PUD1_PUD_VI1_DATA2
+				   | PUD1_PUD_VI1_DATA1
+				   | PUD1_PUD_VI1_DATA0
+				   | PUD1_PUD_VI1_VSYNC_N
+				   | PUD1_PUD_VI1_HSYNC_N
+				   | PUD1_PUD_VI1_CLKENB
+				   | PUD1_PUD_VI1_CLK
+				   | PUD1_PUD_VI0_DATA11
+				   | PUD1_PUD_VI0_DATA10
+				   | PUD1_PUD_VI0_DATA9
+				   | PUD1_PUD_VI0_DATA8
+				   | PUD1_PUD_VI0_DATA7
+				   | PUD1_PUD_VI0_DATA6
+				   | PUD1_PUD_VI0_DATA5
+				   | PUD1_PUD_VI0_DATA4
+				   | PUD1_PUD_VI0_DATA3
+				   | PUD1_PUD_VI0_DATA2
+				   | PUD1_PUD_VI0_DATA1
+				   | PUD1_PUD_VI0_DATA0
+				   | PUD1_PUD_VI0_VSYNC_N
+				   | PUD1_PUD_VI0_HSYNC_N
+				   | PUD1_PUD_VI0_CLKENB);
+
+	pfc_reg_write(PFC_PUD2, PUD2_PUD_CANFD_CLK
+				   | PUD2_PUD_CANFD1_RX
+				   | PUD2_PUD_CANFD1_TX
+				   | PUD2_PUD_CANFD0_RX
+				   | PUD2_PUD_CANFD0_TX
+				   | PUD2_PUD_AVB0_AVTP_CAPTURE
+				   | PUD2_PUD_VI1_FIELD);
+
+	pfc_reg_write(PFC_PUD3, PUD3_PUD_DIGRF_CLKOUT
+				   | PUD3_PUD_DIGRF_CLKIN);
+
+	/* initialize Module Select */
+	pfc_reg_write(PFC_MOD_SEL0, 0x00000000);
+
+	// gpio
+	/* initialize positive/negative logic select */
+	mmio_write_32(GPIO_POSNEG0, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG1, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG2, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG3, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG4, 0x00000000U);
+	mmio_write_32(GPIO_POSNEG5, 0x00000000U);
+
+	/* initialize general IO/interrupt switching */
+	mmio_write_32(GPIO_IOINTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_IOINTSEL5, 0x00000000U);
+
+	/* initialize general output register */
+	mmio_write_32(GPIO_OUTDT0, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT1, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT2, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT3, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT4, 0x00000000U);
+	mmio_write_32(GPIO_OUTDT5, 0x00000000U);
+
+	/* initialize general input/output switching */
+	mmio_write_32(GPIO_INOUTSEL0, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL1, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL2, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL3, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL4, 0x00000000U);
+	mmio_write_32(GPIO_INOUTSEL5, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h
new file mode 100644
index 0000000..7bab92f
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PFC_INIT_V3M_H
+#define PFC_INIT_V3M_H
+
+void pfc_init_v3m(void);
+
+#endif	/* PFC_INIT_V3M_H */
diff --git a/drivers/renesas/rcar/pfc/pfc.mk b/drivers/renesas/rcar/pfc/pfc.mk
new file mode 100644
index 0000000..f1dd92c
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/pfc.mk
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${RCAR_LSI},${RCAR_AUTO})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
+    BL2_SOURCES += drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
+    BL2_SOURCES += drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
+    BL2_SOURCES += drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
+
+else ifdef RCAR_LSI_CUT_COMPAT
+  ifeq (${RCAR_LSI},${RCAR_H3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_H3N})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3N})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_V3M})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_E3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/E3/pfc_init_e3.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_D3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/D3/pfc_init_d3.c
+  endif
+else
+  ifeq (${RCAR_LSI},${RCAR_H3})
+    ifeq (${LSI_CUT},10)
+      BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
+    else ifeq (${LSI_CUT},11)
+      BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c
+    else
+#     LSI_CUT 20 or later
+      BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
+    endif
+  endif
+  ifeq (${RCAR_LSI},${RCAR_H3N})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/M3/pfc_init_m3.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3N})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_V3M})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_E3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/E3/pfc_init_e3.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_D3})
+    BL2_SOURCES += drivers/renesas/rcar/pfc/D3/pfc_init_d3.c
+  endif
+endif
+
+BL2_SOURCES += drivers/renesas/rcar/pfc/pfc_init.c
diff --git a/drivers/renesas/rcar/pfc/pfc_init.c b/drivers/renesas/rcar/pfc/pfc_init.c
new file mode 100644
index 0000000..e9455af
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/pfc_init.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+#if RCAR_LSI == RCAR_AUTO
+#include "H3/pfc_init_h3_v1.h"
+#include "H3/pfc_init_h3_v2.h"
+#include "M3/pfc_init_m3.h"
+#include "M3N/pfc_init_m3n.h"
+#include "V3M/pfc_init_v3m.h"
+#endif
+#if (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)	/* H3 */
+#include "H3/pfc_init_h3_v1.h"
+#include "H3/pfc_init_h3_v2.h"
+#endif
+#if RCAR_LSI == RCAR_M3		/* M3 */
+#include "M3/pfc_init_m3.h"
+#endif
+#if RCAR_LSI == RCAR_M3N	/* M3N */
+#include "M3N/pfc_init_m3n.h"
+#endif
+#if RCAR_LSI == RCAR_V3M	/* V3M */
+#include "V3M/pfc_init_v3m.h"
+#endif
+#if RCAR_LSI == RCAR_E3		/* E3 */
+#include "E3/pfc_init_e3.h"
+#endif
+#if RCAR_LSI == RCAR_D3		/* D3 */
+#include "D3/pfc_init_d3.h"
+#endif
+
+ /* Product Register */
+#define PRR			(0xFFF00044U)
+#define PRR_PRODUCT_MASK	(0x00007F00U)
+#define PRR_CUT_MASK		(0x000000FFU)
+#define PRR_PRODUCT_H3		(0x00004F00U)	/* R-Car H3 */
+#define PRR_PRODUCT_M3		(0x00005200U)	/* R-Car M3 */
+#define PRR_PRODUCT_V3M		(0x00005400U)	/* R-Car V3M */
+#define PRR_PRODUCT_M3N		(0x00005500U)	/* R-Car M3N */
+#define PRR_PRODUCT_E3		(0x00005700U)	/* R-Car E3 */
+#define PRR_PRODUCT_D3		(0x00005800U)	/* R-Car D3 */
+#define PRR_PRODUCT_10		(0x00U)
+#define PRR_PRODUCT_11		(0x01U)
+#define PRR_PRODUCT_20		(0x10U)
+
+#define PRR_PRODUCT_ERR(reg)				\
+	do {						\
+		ERROR("LSI Product ID(PRR=0x%x) PFC initialize not supported.\n", \
+			reg);				\
+		panic();				\
+	} while (0)
+
+#define PRR_CUT_ERR(reg)				\
+	do {						\
+		ERROR("LSI Cut ID(PRR=0x%x) PFC initialize not supported.\n", \
+			reg);				\
+		panic();\
+	} while (0)
+
+void rcar_pfc_init(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(RCAR_PRR);
+#if RCAR_LSI == RCAR_AUTO
+	switch (reg & RCAR_PRODUCT_MASK) {
+	case RCAR_PRODUCT_H3:
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:	/* H3 Ver.1.0 */
+			pfc_init_h3_v1();
+			break;
+		case PRR_PRODUCT_11:	/* H3 Ver.1.1 */
+			pfc_init_h3_v1();
+			break;
+		default:	/* H3 Ver.2.0 or later */
+			pfc_init_h3_v2();
+			break;
+		}
+		break;
+	case RCAR_PRODUCT_M3:
+		pfc_init_m3();
+		break;
+	case RCAR_PRODUCT_M3N:
+		pfc_init_m3n();
+		break;
+	case RCAR_PRODUCT_V3M:
+		pfc_init_v3m();
+		break;
+	default:
+		PRR_PRODUCT_ERR(reg);
+		break;
+	}
+
+#elif RCAR_LSI_CUT_COMPAT
+	switch (reg & PRR_PRODUCT_MASK) {
+	case PRR_PRODUCT_H3:
+#if (RCAR_LSI != RCAR_H3) && (RCAR_LSI != RCAR_H3N)
+		PRR_PRODUCT_ERR(reg);
+#else
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:	/* H3 Ver.1.0 */
+			pfc_init_h3_v1();
+			break;
+		case PRR_PRODUCT_11:	/* H3 Ver.1.1 */
+			pfc_init_h3_v1();
+			break;
+		default:	/* H3 Ver.2.0 or later */
+			pfc_init_h3_v2();
+			break;
+		}
+#endif
+		break;
+	case PRR_PRODUCT_M3:
+#if RCAR_LSI != RCAR_M3
+		PRR_PRODUCT_ERR(reg);
+#else
+		pfc_init_m3();
+#endif
+		break;
+	case PRR_PRODUCT_M3N:
+#if RCAR_LSI != RCAR_M3N
+		PRR_PRODUCT_ERR(reg);
+#else
+		pfc_init_m3n();
+#endif
+		break;
+	case PRR_PRODUCT_V3M:
+#if RCAR_LSI != RCAR_V3M
+		PRR_PRODUCT_ERR(reg);
+#else
+		pfc_init_v3m();
+#endif
+		break;
+	case PRR_PRODUCT_E3:
+#if RCAR_LSI != RCAR_E3
+		PRR_PRODUCT_ERR(reg);
+#else
+		pfc_init_e3();
+#endif
+		break;
+	case PRR_PRODUCT_D3:
+#if RCAR_LSI != RCAR_D3
+		PRR_PRODUCT_ERR(reg);
+#else
+		pfc_init_d3();
+#endif
+		break;
+	default:
+		PRR_PRODUCT_ERR(reg);
+		break;
+	}
+
+#else
+#if (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)	/* H3 */
+#if RCAR_LSI_CUT == RCAR_CUT_10
+	/* H3 Ver.1.0 */
+	if ((PRR_PRODUCT_H3 | PRR_PRODUCT_10)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_h3_v1();
+#elif RCAR_LSI_CUT == RCAR_CUT_11
+	/* H3 Ver.1.1 */
+	if ((PRR_PRODUCT_H3 | PRR_PRODUCT_11)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_h3_v1();
+#else
+	/* H3 Ver.2.0 or later */
+	if (PRR_PRODUCT_H3 != (reg & PRR_PRODUCT_MASK)) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_h3_v2();
+#endif
+#elif RCAR_LSI == RCAR_M3	/* M3 */
+	if ((PRR_PRODUCT_M3) != (reg & PRR_PRODUCT_MASK)) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_m3();
+#elif RCAR_LSI == RCAR_M3N	/* M3N */
+	if ((PRR_PRODUCT_M3N) != (reg & PRR_PRODUCT_MASK)) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_m3n();
+#elif RCAR_LSI == RCAR_V3M	/* V3M */
+	if ((PRR_PRODUCT_V3M) != (reg & PRR_PRODUCT_MASK)) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_v3m();
+#elif RCAR_LSI == RCAR_E3	/* E3 */
+	if ((PRR_PRODUCT_E3) != (reg & PRR_PRODUCT_MASK)) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_e3();
+#elif RCAR_LSI == RCAR_D3	/* D3 */
+	if ((PRR_PRODUCT_D3) != (reg & PRR_PRODUCT_MASK)) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	pfc_init_d3();
+#else
+#error "Don't have PFC initialize routine(unknown)."
+#endif
+#endif
+}
diff --git a/drivers/renesas/rcar/pfc/pfc_regs.h b/drivers/renesas/rcar/pfc/pfc_regs.h
new file mode 100644
index 0000000..e7dd543
--- /dev/null
+++ b/drivers/renesas/rcar/pfc/pfc_regs.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PFC_REGS_H
+#define PFC_REGS_H
+
+/* GPIO base address */
+#define GPIO_BASE		(0xE6050000U)
+
+/* GPIO registers */
+#define GPIO_IOINTSEL0		(GPIO_BASE + 0x0000U)
+#define GPIO_INOUTSEL0		(GPIO_BASE + 0x0004U)
+#define GPIO_OUTDT0		(GPIO_BASE + 0x0008U)
+#define GPIO_INDT0		(GPIO_BASE + 0x000CU)
+#define GPIO_INTDT0		(GPIO_BASE + 0x0010U)
+#define GPIO_INTCLR0		(GPIO_BASE + 0x0014U)
+#define GPIO_INTMSK0		(GPIO_BASE + 0x0018U)
+#define GPIO_MSKCLR0		(GPIO_BASE + 0x001CU)
+#define GPIO_POSNEG0		(GPIO_BASE + 0x0020U)
+#define GPIO_EDGLEVEL0		(GPIO_BASE + 0x0024U)
+#define GPIO_FILONOFF0		(GPIO_BASE + 0x0028U)
+#define GPIO_INTMSKS0		(GPIO_BASE + 0x0038U)
+#define GPIO_MSKCLRS0		(GPIO_BASE + 0x003CU)
+#define GPIO_OUTDTSEL0		(GPIO_BASE + 0x0040U)
+#define GPIO_OUTDTH0		(GPIO_BASE + 0x0044U)
+#define GPIO_OUTDTL0		(GPIO_BASE + 0x0048U)
+#define GPIO_BOTHEDGE0		(GPIO_BASE + 0x004CU)
+#define GPIO_IOINTSEL1		(GPIO_BASE + 0x1000U)
+#define GPIO_INOUTSEL1		(GPIO_BASE + 0x1004U)
+#define GPIO_OUTDT1		(GPIO_BASE + 0x1008U)
+#define GPIO_INDT1		(GPIO_BASE + 0x100CU)
+#define GPIO_INTDT1		(GPIO_BASE + 0x1010U)
+#define GPIO_INTCLR1		(GPIO_BASE + 0x1014U)
+#define GPIO_INTMSK1		(GPIO_BASE + 0x1018U)
+#define GPIO_MSKCLR1		(GPIO_BASE + 0x101CU)
+#define GPIO_POSNEG1		(GPIO_BASE + 0x1020U)
+#define GPIO_EDGLEVEL1		(GPIO_BASE + 0x1024U)
+#define GPIO_FILONOFF1		(GPIO_BASE + 0x1028U)
+#define GPIO_INTMSKS1		(GPIO_BASE + 0x1038U)
+#define GPIO_MSKCLRS1		(GPIO_BASE + 0x103CU)
+#define GPIO_OUTDTSEL1		(GPIO_BASE + 0x1040U)
+#define GPIO_OUTDTH1		(GPIO_BASE + 0x1044U)
+#define GPIO_OUTDTL1		(GPIO_BASE + 0x1048U)
+#define GPIO_BOTHEDGE1		(GPIO_BASE + 0x104CU)
+#define GPIO_IOINTSEL2		(GPIO_BASE + 0x2000U)
+#define GPIO_INOUTSEL2		(GPIO_BASE + 0x2004U)
+#define GPIO_OUTDT2		(GPIO_BASE + 0x2008U)
+#define GPIO_INDT2		(GPIO_BASE + 0x200CU)
+#define GPIO_INTDT2		(GPIO_BASE + 0x2010U)
+#define GPIO_INTCLR2		(GPIO_BASE + 0x2014U)
+#define GPIO_INTMSK2		(GPIO_BASE + 0x2018U)
+#define GPIO_MSKCLR2		(GPIO_BASE + 0x201CU)
+#define GPIO_POSNEG2		(GPIO_BASE + 0x2020U)
+#define GPIO_EDGLEVEL2		(GPIO_BASE + 0x2024U)
+#define GPIO_FILONOFF2		(GPIO_BASE + 0x2028U)
+#define GPIO_INTMSKS2		(GPIO_BASE + 0x2038U)
+#define GPIO_MSKCLRS2		(GPIO_BASE + 0x203CU)
+#define GPIO_OUTDTSEL2		(GPIO_BASE + 0x2040U)
+#define GPIO_OUTDTH2		(GPIO_BASE + 0x2044U)
+#define GPIO_OUTDTL2		(GPIO_BASE + 0x2048U)
+#define GPIO_BOTHEDGE2		(GPIO_BASE + 0x204CU)
+#define GPIO_IOINTSEL3		(GPIO_BASE + 0x3000U)
+#define GPIO_INOUTSEL3		(GPIO_BASE + 0x3004U)
+#define GPIO_OUTDT3		(GPIO_BASE + 0x3008U)
+#define GPIO_INDT3		(GPIO_BASE + 0x300CU)
+#define GPIO_INTDT3		(GPIO_BASE + 0x3010U)
+#define GPIO_INTCLR3		(GPIO_BASE + 0x3014U)
+#define GPIO_INTMSK3		(GPIO_BASE + 0x3018U)
+#define GPIO_MSKCLR3		(GPIO_BASE + 0x301CU)
+#define GPIO_POSNEG3		(GPIO_BASE + 0x3020U)
+#define GPIO_EDGLEVEL3		(GPIO_BASE + 0x3024U)
+#define GPIO_FILONOFF3		(GPIO_BASE + 0x3028U)
+#define GPIO_INTMSKS3		(GPIO_BASE + 0x3038U)
+#define GPIO_MSKCLRS3		(GPIO_BASE + 0x303CU)
+#define GPIO_OUTDTSEL3		(GPIO_BASE + 0x3040U)
+#define GPIO_OUTDTH3		(GPIO_BASE + 0x3044U)
+#define GPIO_OUTDTL3		(GPIO_BASE + 0x3048U)
+#define GPIO_BOTHEDGE3		(GPIO_BASE + 0x304CU)
+#define GPIO_IOINTSEL4		(GPIO_BASE + 0x4000U)
+#define GPIO_INOUTSEL4		(GPIO_BASE + 0x4004U)
+#define GPIO_OUTDT4		(GPIO_BASE + 0x4008U)
+#define GPIO_INDT4		(GPIO_BASE + 0x400CU)
+#define GPIO_INTDT4		(GPIO_BASE + 0x4010U)
+#define GPIO_INTCLR4		(GPIO_BASE + 0x4014U)
+#define GPIO_INTMSK4		(GPIO_BASE + 0x4018U)
+#define GPIO_MSKCLR4		(GPIO_BASE + 0x401CU)
+#define GPIO_POSNEG4		(GPIO_BASE + 0x4020U)
+#define GPIO_EDGLEVEL4		(GPIO_BASE + 0x4024U)
+#define GPIO_FILONOFF4		(GPIO_BASE + 0x4028U)
+#define GPIO_INTMSKS4		(GPIO_BASE + 0x4038U)
+#define GPIO_MSKCLRS4		(GPIO_BASE + 0x403CU)
+#define GPIO_OUTDTSEL4		(GPIO_BASE + 0x4040U)
+#define GPIO_OUTDTH4		(GPIO_BASE + 0x4044U)
+#define GPIO_OUTDTL4		(GPIO_BASE + 0x4048U)
+#define GPIO_BOTHEDGE4		(GPIO_BASE + 0x404CU)
+#define GPIO_IOINTSEL5		(GPIO_BASE + 0x5000U)
+#define GPIO_INOUTSEL5		(GPIO_BASE + 0x5004U)
+#define GPIO_OUTDT5		(GPIO_BASE + 0x5008U)
+#define GPIO_INDT5		(GPIO_BASE + 0x500CU)
+#define GPIO_INTDT5		(GPIO_BASE + 0x5010U)
+#define GPIO_INTCLR5		(GPIO_BASE + 0x5014U)
+#define GPIO_INTMSK5		(GPIO_BASE + 0x5018U)
+#define GPIO_MSKCLR5		(GPIO_BASE + 0x501CU)
+#define GPIO_POSNEG5		(GPIO_BASE + 0x5020U)
+#define GPIO_EDGLEVEL5		(GPIO_BASE + 0x5024U)
+#define GPIO_FILONOFF5		(GPIO_BASE + 0x5028U)
+#define GPIO_INTMSKS5		(GPIO_BASE + 0x5038U)
+#define GPIO_MSKCLRS5		(GPIO_BASE + 0x503CU)
+#define GPIO_OUTDTSEL5		(GPIO_BASE + 0x5040U)
+#define GPIO_OUTDTH5		(GPIO_BASE + 0x5044U)
+#define GPIO_OUTDTL5		(GPIO_BASE + 0x5048U)
+#define GPIO_BOTHEDGE5		(GPIO_BASE + 0x504CU)
+#define GPIO_IOINTSEL6		(GPIO_BASE + 0x5400U)
+#define GPIO_INOUTSEL6		(GPIO_BASE + 0x5404U)
+#define GPIO_OUTDT6		(GPIO_BASE + 0x5408U)
+#define GPIO_INDT6		(GPIO_BASE + 0x540CU)
+#define GPIO_INTDT6		(GPIO_BASE + 0x5410U)
+#define GPIO_INTCLR6		(GPIO_BASE + 0x5414U)
+#define GPIO_INTMSK6		(GPIO_BASE + 0x5418U)
+#define GPIO_MSKCLR6		(GPIO_BASE + 0x541CU)
+#define GPIO_POSNEG6		(GPIO_BASE + 0x5420U)
+#define GPIO_EDGLEVEL6		(GPIO_BASE + 0x5424U)
+#define GPIO_FILONOFF6		(GPIO_BASE + 0x5428U)
+#define GPIO_INTMSKS6		(GPIO_BASE + 0x5438U)
+#define GPIO_MSKCLRS6		(GPIO_BASE + 0x543CU)
+#define GPIO_OUTDTSEL6		(GPIO_BASE + 0x5440U)
+#define GPIO_OUTDTH6		(GPIO_BASE + 0x5444U)
+#define GPIO_OUTDTL6		(GPIO_BASE + 0x5448U)
+#define GPIO_BOTHEDGE6		(GPIO_BASE + 0x544CU)
+#define GPIO_IOINTSEL7		(GPIO_BASE + 0x5800U)
+#define GPIO_INOUTSEL7		(GPIO_BASE + 0x5804U)
+#define GPIO_OUTDT7		(GPIO_BASE + 0x5808U)
+#define GPIO_INDT7		(GPIO_BASE + 0x580CU)
+#define GPIO_INTDT7		(GPIO_BASE + 0x5810U)
+#define GPIO_INTCLR7		(GPIO_BASE + 0x5814U)
+#define GPIO_INTMSK7		(GPIO_BASE + 0x5818U)
+#define GPIO_MSKCLR7		(GPIO_BASE + 0x581CU)
+#define GPIO_POSNEG7		(GPIO_BASE + 0x5820U)
+#define GPIO_EDGLEVEL7		(GPIO_BASE + 0x5824U)
+#define GPIO_FILONOFF7		(GPIO_BASE + 0x5828U)
+#define GPIO_INTMSKS7		(GPIO_BASE + 0x5838U)
+#define GPIO_MSKCLRS7		(GPIO_BASE + 0x583CU)
+#define GPIO_OUTDTSEL7		(GPIO_BASE + 0x5840U)
+#define GPIO_OUTDTH7		(GPIO_BASE + 0x5844U)
+#define GPIO_OUTDTL7		(GPIO_BASE + 0x5848U)
+#define GPIO_BOTHEDGE7		(GPIO_BASE + 0x584CU)
+
+/* Pin functon base address */
+#define PFC_BASE		(0xE6060000U)
+
+/* Pin functon registers */
+#define PFC_PMMR		(PFC_BASE + 0x0000U)
+#define PFC_GPSR0		(PFC_BASE + 0x0100U)
+#define PFC_GPSR1		(PFC_BASE + 0x0104U)
+#define PFC_GPSR2		(PFC_BASE + 0x0108U)
+#define PFC_GPSR3		(PFC_BASE + 0x010CU)
+#define PFC_GPSR4		(PFC_BASE + 0x0110U)
+#define PFC_GPSR5		(PFC_BASE + 0x0114U)
+#define PFC_GPSR6		(PFC_BASE + 0x0118U)
+#define PFC_GPSR7		(PFC_BASE + 0x011CU)
+#define PFC_IPSR0		(PFC_BASE + 0x0200U)
+#define PFC_IPSR1		(PFC_BASE + 0x0204U)
+#define PFC_IPSR2		(PFC_BASE + 0x0208U)
+#define PFC_IPSR3		(PFC_BASE + 0x020CU)
+#define PFC_IPSR4		(PFC_BASE + 0x0210U)
+#define PFC_IPSR5		(PFC_BASE + 0x0214U)
+#define PFC_IPSR6		(PFC_BASE + 0x0218U)
+#define PFC_IPSR7		(PFC_BASE + 0x021CU)
+#define PFC_IPSR8		(PFC_BASE + 0x0220U)
+#define PFC_IPSR9		(PFC_BASE + 0x0224U)
+#define PFC_IPSR10		(PFC_BASE + 0x0228U)
+#define PFC_IPSR11		(PFC_BASE + 0x022CU)
+#define PFC_IPSR12		(PFC_BASE + 0x0230U)
+#define PFC_IPSR13		(PFC_BASE + 0x0234U)
+#define PFC_IPSR14		(PFC_BASE + 0x0238U)
+#define PFC_IPSR15		(PFC_BASE + 0x023CU)
+#define PFC_IPSR16		(PFC_BASE + 0x0240U)
+#define PFC_IPSR17		(PFC_BASE + 0x0244U)
+#define PFC_IPSR18		(PFC_BASE + 0x0248U)
+#define PFC_DRVCTRL0		(PFC_BASE + 0x0300U)
+#define PFC_DRVCTRL1		(PFC_BASE + 0x0304U)
+#define PFC_DRVCTRL2		(PFC_BASE + 0x0308U)
+#define PFC_DRVCTRL3		(PFC_BASE + 0x030CU)
+#define PFC_DRVCTRL4		(PFC_BASE + 0x0310U)
+#define PFC_DRVCTRL5		(PFC_BASE + 0x0314U)
+#define PFC_DRVCTRL6		(PFC_BASE + 0x0318U)
+#define PFC_DRVCTRL7		(PFC_BASE + 0x031CU)
+#define PFC_DRVCTRL8		(PFC_BASE + 0x0320U)
+#define PFC_DRVCTRL9		(PFC_BASE + 0x0324U)
+#define PFC_DRVCTRL10		(PFC_BASE + 0x0328U)
+#define PFC_DRVCTRL11		(PFC_BASE + 0x032CU)
+#define PFC_DRVCTRL12		(PFC_BASE + 0x0330U)
+#define PFC_DRVCTRL13		(PFC_BASE + 0x0334U)
+#define PFC_DRVCTRL14		(PFC_BASE + 0x0338U)
+#define PFC_DRVCTRL15		(PFC_BASE + 0x033CU)
+#define PFC_DRVCTRL16		(PFC_BASE + 0x0340U)
+#define PFC_DRVCTRL17		(PFC_BASE + 0x0344U)
+#define PFC_DRVCTRL18		(PFC_BASE + 0x0348U)
+#define PFC_DRVCTRL19		(PFC_BASE + 0x034CU)
+#define PFC_DRVCTRL20		(PFC_BASE + 0x0350U)
+#define PFC_DRVCTRL21		(PFC_BASE + 0x0354U)
+#define PFC_DRVCTRL22		(PFC_BASE + 0x0358U)
+#define PFC_DRVCTRL23		(PFC_BASE + 0x035CU)
+#define PFC_DRVCTRL24		(PFC_BASE + 0x0360U)
+#define PFC_POCCTRL0		(PFC_BASE + 0x0380U)
+#define PFC_IOCTRL31		(PFC_BASE + 0x0384U)
+#define PFC_POCCTRL2		(PFC_BASE + 0x0388U)
+#define PFC_TDSELCTRL0		(PFC_BASE + 0x03C0U)
+#define PFC_IOCTRL		(PFC_BASE + 0x03E0U)
+#define PFC_TSREG		(PFC_BASE + 0x03E4U)
+#define PFC_PUEN0		(PFC_BASE + 0x0400U)
+#define PFC_PUEN1		(PFC_BASE + 0x0404U)
+#define PFC_PUEN2		(PFC_BASE + 0x0408U)
+#define PFC_PUEN3		(PFC_BASE + 0x040CU)
+#define PFC_PUEN4		(PFC_BASE + 0x0410U)
+#define PFC_PUEN5		(PFC_BASE + 0x0414U)
+#define PFC_PUEN6		(PFC_BASE + 0x0418U)
+#define PFC_PUD0		(PFC_BASE + 0x0440U)
+#define PFC_PUD1		(PFC_BASE + 0x0444U)
+#define PFC_PUD2		(PFC_BASE + 0x0448U)
+#define PFC_PUD3		(PFC_BASE + 0x044CU)
+#define PFC_PUD4		(PFC_BASE + 0x0450U)
+#define PFC_PUD5		(PFC_BASE + 0x0454U)
+#define PFC_PUD6		(PFC_BASE + 0x0458U)
+#define PFC_MOD_SEL0		(PFC_BASE + 0x0500U)
+#define PFC_MOD_SEL1		(PFC_BASE + 0x0504U)
+#define PFC_MOD_SEL2		(PFC_BASE + 0x0508U)
+
+#endif /* PFC_REGS_H */
diff --git a/drivers/renesas/rcar/pwrc/call_sram.S b/drivers/renesas/rcar/pwrc/call_sram.S
new file mode 100644
index 0000000..aa8644c
--- /dev/null
+++ b/drivers/renesas/rcar/pwrc/call_sram.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+.global rcar_pwrc_switch_stack
+
+/*
+ * x0 : jump address,
+ * x1 : stack address,
+ * x2 : arg,
+ * x3 : stack address (temporary)
+ */
+func rcar_pwrc_switch_stack
+
+	/* lr to stack */
+	stp	x29, x30, [sp,#-16]
+
+	/* change stack pointer */
+	mov	x3, sp
+	mov	sp, x1
+
+	/* save stack pointer */
+	sub	sp, sp, #16
+	stp	x0, x3, [sp]
+
+	/* data synchronization barrier */
+	dsb	sy
+
+	/* jump to code */
+	mov	x1, x0
+	mov	x0, x2
+	blr	x1
+
+	/* load stack pointer */
+	ldp 	x0, x2, [sp,#0]
+
+	/* change stack pointer */
+	mov	sp, x2
+
+	/* return */
+	ldp	x29, x30, [sp,#-16]
+	ret
+endfunc rcar_pwrc_switch_stack
diff --git a/drivers/renesas/rcar/pwrc/pwrc.c b/drivers/renesas/rcar/pwrc/pwrc.c
new file mode 100644
index 0000000..32e04a7
--- /dev/null
+++ b/drivers/renesas/rcar/pwrc/pwrc.c
@@ -0,0 +1,866 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "iic_dvfs.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "micro_delay.h"
+#include "pwrc.h"
+
+/*
+ * Someday there will be a generic power controller api. At the moment each
+ * platform has its own pwrc so just exporting functions should be acceptable.
+ */
+RCAR_INSTANTIATE_LOCK
+
+#define	WUP_IRQ_SHIFT				(0U)
+#define	WUP_FIQ_SHIFT				(8U)
+#define	WUP_CSD_SHIFT				(16U)
+#define	BIT_SOFTRESET				(1U<<15)
+#define	BIT_CA53_SCU				(1U<<21)
+#define	BIT_CA57_SCU				(1U<<12)
+#define	REQ_RESUME				(1U<<1)
+#define	REQ_OFF					(1U<<0)
+#define	STATUS_PWRUP				(1U<<4)
+#define	STATUS_PWRDOWN				(1U<<0)
+#define	STATE_CA57_CPU				(27U)
+#define	STATE_CA53_CPU				(22U)
+#define	MODE_L2_DOWN				(0x00000002U)
+#define	CPU_PWR_OFF				(0x00000003U)
+#define	RCAR_PSTR_MASK				(0x00000003U)
+#define	ST_ALL_STANDBY				(0x00003333U)
+/* Suspend to ram	*/
+#define	DBSC4_REG_BASE				(0xE6790000U)
+#define	DBSC4_REG_DBSYSCNT0			(DBSC4_REG_BASE + 0x0100U)
+#define	DBSC4_REG_DBACEN			(DBSC4_REG_BASE + 0x0200U)
+#define	DBSC4_REG_DBCMD				(DBSC4_REG_BASE + 0x0208U)
+#define	DBSC4_REG_DBRFEN			(DBSC4_REG_BASE + 0x0204U)
+#define	DBSC4_REG_DBWAIT			(DBSC4_REG_BASE + 0x0210U)
+#define	DBSC4_REG_DBCALCNF			(DBSC4_REG_BASE + 0x0424U)
+#define	DBSC4_REG_DBDFIPMSTRCNF			(DBSC4_REG_BASE + 0x0520U)
+#define	DBSC4_REG_DBPDLK0			(DBSC4_REG_BASE + 0x0620U)
+#define	DBSC4_REG_DBPDRGA0			(DBSC4_REG_BASE + 0x0624U)
+#define	DBSC4_REG_DBPDRGD0			(DBSC4_REG_BASE + 0x0628U)
+#define	DBSC4_REG_DBCAM0CTRL0			(DBSC4_REG_BASE + 0x0940U)
+#define	DBSC4_REG_DBCAM0STAT0			(DBSC4_REG_BASE + 0x0980U)
+#define	DBSC4_REG_DBCAM1STAT0			(DBSC4_REG_BASE + 0x0990U)
+#define	DBSC4_REG_DBCAM2STAT0			(DBSC4_REG_BASE + 0x09A0U)
+#define	DBSC4_REG_DBCAM3STAT0			(DBSC4_REG_BASE + 0x09B0U)
+#define	DBSC4_BIT_DBACEN_ACCEN			((uint32_t)(1U << 0))
+#define	DBSC4_BIT_DBRFEN_ARFEN			((uint32_t)(1U << 0))
+#define	DBSC4_BIT_DBCAMxSTAT0			(0x00000001U)
+#define	DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN		(0x00000001U)
+#define	DBSC4_SET_DBCMD_OPC_PRE			(0x04000000U)
+#define	DBSC4_SET_DBCMD_OPC_SR			(0x0A000000U)
+#define	DBSC4_SET_DBCMD_OPC_PD			(0x08000000U)
+#define	DBSC4_SET_DBCMD_OPC_MRW			(0x0E000000U)
+#define	DBSC4_SET_DBCMD_CH_ALL			(0x00800000U)
+#define	DBSC4_SET_DBCMD_RANK_ALL		(0x00040000U)
+#define	DBSC4_SET_DBCMD_ARG_ALL			(0x00000010U)
+#define	DBSC4_SET_DBCMD_ARG_ENTER		(0x00000000U)
+#define	DBSC4_SET_DBCMD_ARG_MRW_ODTC		(0x00000B00U)
+#define	DBSC4_SET_DBSYSCNT0_WRITE_ENABLE	(0x00001234U)
+#define	DBSC4_SET_DBSYSCNT0_WRITE_DISABLE	(0x00000000U)
+#define	DBSC4_SET_DBPDLK0_PHY_ACCESS		(0x0000A55AU)
+#define	DBSC4_SET_DBPDRGA0_ACIOCR0		(0x0000001AU)
+#define	DBSC4_SET_DBPDRGD0_ACIOCR0		(0x33C03C11U)
+#define	DBSC4_SET_DBPDRGA0_DXCCR		(0x00000020U)
+#define	DBSC4_SET_DBPDRGD0_DXCCR		(0x00181006U)
+#define	DBSC4_SET_DBPDRGA0_PGCR1		(0x00000003U)
+#define	DBSC4_SET_DBPDRGD0_PGCR1		(0x0380C600U)
+#define	DBSC4_SET_DBPDRGA0_ACIOCR1		(0x0000001BU)
+#define	DBSC4_SET_DBPDRGD0_ACIOCR1		(0xAAAAAAAAU)
+#define	DBSC4_SET_DBPDRGA0_ACIOCR3		(0x0000001DU)
+#define	DBSC4_SET_DBPDRGD0_ACIOCR3		(0xAAAAAAAAU)
+#define	DBSC4_SET_DBPDRGA0_ACIOCR5		(0x0000001FU)
+#define	DBSC4_SET_DBPDRGD0_ACIOCR5		(0x000000AAU)
+#define	DBSC4_SET_DBPDRGA0_DX0GCR2		(0x000000A2U)
+#define	DBSC4_SET_DBPDRGD0_DX0GCR2		(0xAAAA0000U)
+#define	DBSC4_SET_DBPDRGA0_DX1GCR2		(0x000000C2U)
+#define	DBSC4_SET_DBPDRGD0_DX1GCR2		(0xAAAA0000U)
+#define	DBSC4_SET_DBPDRGA0_DX2GCR2		(0x000000E2U)
+#define	DBSC4_SET_DBPDRGD0_DX2GCR2		(0xAAAA0000U)
+#define	DBSC4_SET_DBPDRGA0_DX3GCR2		(0x00000102U)
+#define	DBSC4_SET_DBPDRGD0_DX3GCR2		(0xAAAA0000U)
+#define	DBSC4_SET_DBPDRGA0_ZQCR			(0x00000090U)
+#define	DBSC4_SET_DBPDRGD0_ZQCR_MD19_0		(0x04058904U)
+#define	DBSC4_SET_DBPDRGD0_ZQCR_MD19_1		(0x04058A04U)
+#define	DBSC4_SET_DBPDRGA0_DX0GCR0		(0x000000A0U)
+#define	DBSC4_SET_DBPDRGD0_DX0GCR0		(0x7C0002E5U)
+#define	DBSC4_SET_DBPDRGA0_DX1GCR0		(0x000000C0U)
+#define	DBSC4_SET_DBPDRGD0_DX1GCR0		(0x7C0002E5U)
+#define	DBSC4_SET_DBPDRGA0_DX2GCR0		(0x000000E0U)
+#define	DBSC4_SET_DBPDRGD0_DX2GCR0		(0x7C0002E5U)
+#define	DBSC4_SET_DBPDRGA0_DX3GCR0		(0x00000100U)
+#define	DBSC4_SET_DBPDRGD0_DX3GCR0		(0x7C0002E5U)
+#define	DBSC4_SET_DBPDRGA0_DX0GCR1		(0x000000A1U)
+#define	DBSC4_SET_DBPDRGD0_DX0GCR1		(0x55550000U)
+#define	DBSC4_SET_DBPDRGA0_DX1GCR1		(0x000000C1U)
+#define	DBSC4_SET_DBPDRGD0_DX1GCR1		(0x55550000U)
+#define	DBSC4_SET_DBPDRGA0_DX2GCR1		(0x000000E1U)
+#define	DBSC4_SET_DBPDRGD0_DX2GCR1		(0x55550000U)
+#define	DBSC4_SET_DBPDRGA0_DX3GCR1		(0x00000101U)
+#define	DBSC4_SET_DBPDRGD0_DX3GCR1		(0x55550000U)
+#define	DBSC4_SET_DBPDRGA0_DX0GCR3		(0x000000A3U)
+#define	DBSC4_SET_DBPDRGD0_DX0GCR3		(0x00008484U)
+#define	DBSC4_SET_DBPDRGA0_DX1GCR3		(0x000000C3U)
+#define	DBSC4_SET_DBPDRGD0_DX1GCR3		(0x00008484U)
+#define	DBSC4_SET_DBPDRGA0_DX2GCR3		(0x000000E3U)
+#define	DBSC4_SET_DBPDRGD0_DX2GCR3		(0x00008484U)
+#define	DBSC4_SET_DBPDRGA0_DX3GCR3		(0x00000103U)
+#define	DBSC4_SET_DBPDRGD0_DX3GCR3		(0x00008484U)
+#define	RST_BASE				(0xE6160000U)
+#define	RST_MODEMR				(RST_BASE + 0x0060U)
+#define	RST_MODEMR_BIT0				(0x00000001U)
+
+#define RCAR_CNTCR_OFF				(0x00U)
+#define RCAR_CNTCVL_OFF				(0x08U)
+#define RCAR_CNTCVU_OFF				(0x0CU)
+#define RCAR_CNTFID_OFF				(0x20U)
+
+#define RCAR_CNTCR_EN				((uint32_t)1U << 0U)
+#define RCAR_CNTCR_FCREQ(x)			((uint32_t)(x) << 8U)
+
+#if PMIC_ROHM_BD9571
+#define	BIT_BKUP_CTRL_OUT			((uint8_t)(1U << 4))
+#define	PMIC_BKUP_MODE_CNT			(0x20U)
+#define	PMIC_QLLM_CNT				(0x27U)
+#define	PMIC_RETRY_MAX				(100U)
+#endif
+#define	SCTLR_EL3_M_BIT				((uint32_t)1U << 0)
+#define	RCAR_CA53CPU_NUM_MAX			(4U)
+#define	RCAR_CA57CPU_NUM_MAX			(4U)
+#define IS_A53A57(c) 	((c) == RCAR_CLUSTER_A53A57)
+#define IS_CA57(c) 	((c) == RCAR_CLUSTER_CA57)
+#define IS_CA53(c) 	((c) == RCAR_CLUSTER_CA53)
+
+#ifndef __ASSEMBLER__
+IMPORT_SYM(unsigned long, __system_ram_start__, SYSTEM_RAM_START);
+IMPORT_SYM(unsigned long, __system_ram_end__, SYSTEM_RAM_END);
+IMPORT_SYM(unsigned long, __SRAM_COPY_START__, SRAM_COPY_START);
+#endif
+
+uint32_t rcar_pwrc_status(uint64_t mpidr)
+{
+	uint32_t ret = 0;
+	uint64_t cm, cpu;
+	uint32_t reg;
+	uint32_t c;
+
+	rcar_lock_get();
+
+	c = rcar_pwrc_get_cluster();
+	cm = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (!IS_A53A57(c) && cm != 0) {
+		ret = RCAR_INVALID;
+		goto done;
+	}
+
+	reg = mmio_read_32(RCAR_PRR);
+	cpu = mpidr & MPIDR_CPU_MASK;
+
+	if (IS_CA53(c))
+		if (reg & (1 << (STATE_CA53_CPU + cpu)))
+			ret = RCAR_INVALID;
+	if (IS_CA57(c))
+		if (reg & (1 << (STATE_CA57_CPU + cpu)))
+			ret = RCAR_INVALID;
+done:
+	rcar_lock_release();
+
+	return ret;
+}
+
+static void scu_power_up(uint64_t mpidr)
+{
+	uintptr_t reg_pwrsr, reg_cpumcr, reg_pwron, reg_pwrer;
+	uint32_t c, sysc_reg_bit;
+
+	c = rcar_pwrc_get_mpidr_cluster(mpidr);
+	reg_cpumcr = IS_CA57(c) ? RCAR_CA57CPUCMCR : RCAR_CA53CPUCMCR;
+	sysc_reg_bit = IS_CA57(c) ? BIT_CA57_SCU : BIT_CA53_SCU;
+	reg_pwron = IS_CA57(c) ? RCAR_PWRONCR5 : RCAR_PWRONCR3;
+	reg_pwrer = IS_CA57(c) ? RCAR_PWRER5 : RCAR_PWRER3;
+	reg_pwrsr = IS_CA57(c) ? RCAR_PWRSR5 : RCAR_PWRSR3;
+
+	if ((mmio_read_32(reg_pwrsr) & STATUS_PWRDOWN) == 0)
+		return;
+
+	if (mmio_read_32(reg_cpumcr) != 0)
+		mmio_write_32(reg_cpumcr, 0);
+
+	mmio_setbits_32(RCAR_SYSCIER, sysc_reg_bit);
+	mmio_setbits_32(RCAR_SYSCIMR, sysc_reg_bit);
+
+	do {
+		while ((mmio_read_32(RCAR_SYSCSR) & REQ_RESUME) == 0)
+			;
+		mmio_write_32(reg_pwron, 1);
+	} while (mmio_read_32(reg_pwrer) & 1);
+
+	while ((mmio_read_32(RCAR_SYSCISR) & sysc_reg_bit) == 0)
+		;
+	mmio_write_32(RCAR_SYSCISR, sysc_reg_bit);
+	while ((mmio_read_32(reg_pwrsr) & STATUS_PWRUP) == 0)
+		;
+}
+
+void rcar_pwrc_cpuon(uint64_t mpidr)
+{
+	uint32_t res_data, on_data;
+	uintptr_t res_reg, on_reg;
+	uint32_t limit, c;
+	uint64_t cpu;
+
+	rcar_lock_get();
+
+	c = rcar_pwrc_get_mpidr_cluster(mpidr);
+	res_reg = IS_CA53(c) ? RCAR_CA53RESCNT : RCAR_CA57RESCNT;
+	on_reg = IS_CA53(c) ? RCAR_CA53WUPCR : RCAR_CA57WUPCR;
+	limit = IS_CA53(c) ? 0x5A5A0000 : 0xA5A50000;
+
+	res_data = mmio_read_32(res_reg) | limit;
+	scu_power_up(mpidr);
+	cpu = mpidr & MPIDR_CPU_MASK;
+	on_data = 1 << cpu;
+	mmio_write_32(RCAR_CPGWPR, ~on_data);
+	mmio_write_32(on_reg, on_data);
+	mmio_write_32(res_reg, res_data & (~(1 << (3 - cpu))));
+
+	rcar_lock_release();
+}
+
+void rcar_pwrc_cpuoff(uint64_t mpidr)
+{
+	uint32_t c;
+	uintptr_t reg;
+	uint64_t cpu;
+
+	rcar_lock_get();
+
+	cpu = mpidr & MPIDR_CPU_MASK;
+	c = rcar_pwrc_get_mpidr_cluster(mpidr);
+	reg = IS_CA53(c) ? RCAR_CA53CPU0CR : RCAR_CA57CPU0CR;
+
+	if (read_mpidr_el1() != mpidr)
+		panic();
+
+	mmio_write_32(RCAR_CPGWPR, ~CPU_PWR_OFF);
+	mmio_write_32(reg + cpu * 0x0010, CPU_PWR_OFF);
+
+	rcar_lock_release();
+}
+
+void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr)
+{
+	uint32_t c, shift_irq, shift_fiq;
+	uintptr_t reg;
+	uint64_t cpu;
+
+	rcar_lock_get();
+
+	cpu = mpidr & MPIDR_CPU_MASK;
+	c = rcar_pwrc_get_mpidr_cluster(mpidr);
+	reg = IS_CA53(c) ? RCAR_WUPMSKCA53 : RCAR_WUPMSKCA57;
+
+	shift_irq = WUP_IRQ_SHIFT + cpu;
+	shift_fiq = WUP_FIQ_SHIFT + cpu;
+
+	mmio_write_32(reg, ~((uint32_t) 1 << shift_irq) &
+		      ~((uint32_t) 1 << shift_fiq));
+	rcar_lock_release();
+}
+
+void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr)
+{
+	uint32_t c, shift_irq, shift_fiq;
+	uintptr_t reg;
+	uint64_t cpu;
+
+	rcar_lock_get();
+
+	cpu = mpidr & MPIDR_CPU_MASK;
+	c = rcar_pwrc_get_mpidr_cluster(mpidr);
+	reg = IS_CA53(c) ? RCAR_WUPMSKCA53 : RCAR_WUPMSKCA57;
+
+	shift_irq = WUP_IRQ_SHIFT + cpu;
+	shift_fiq = WUP_FIQ_SHIFT + cpu;
+
+	mmio_write_32(reg, ((uint32_t) 1 << shift_irq) |
+		      ((uint32_t) 1 << shift_fiq));
+	rcar_lock_release();
+}
+
+void rcar_pwrc_clusteroff(uint64_t mpidr)
+{
+	uint32_t c, product, cut, reg;
+	uintptr_t dst;
+
+	rcar_lock_get();
+
+	reg = mmio_read_32(RCAR_PRR);
+	product = reg & RCAR_PRODUCT_MASK;
+	cut = reg & RCAR_CUT_MASK;
+
+	c = rcar_pwrc_get_mpidr_cluster(mpidr);
+	dst = IS_CA53(c) ? RCAR_CA53CPUCMCR : RCAR_CA57CPUCMCR;
+
+	if (RCAR_PRODUCT_M3 == product && cut < RCAR_CUT_VER30)
+		goto done;
+
+	if (RCAR_PRODUCT_H3 == product && cut <= RCAR_CUT_VER20)
+		goto done;
+
+	/* all of the CPUs in the cluster is in the CoreStandby mode */
+	mmio_write_32(dst, MODE_L2_DOWN);
+done:
+	rcar_lock_release();
+}
+
+static uint64_t rcar_pwrc_saved_cntpct_el0;
+static uint32_t rcar_pwrc_saved_cntfid;
+
+#if RCAR_SYSTEM_SUSPEND
+static void rcar_pwrc_save_timer_state(void)
+{
+	rcar_pwrc_saved_cntpct_el0 = read_cntpct_el0();
+
+	rcar_pwrc_saved_cntfid =
+		mmio_read_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTFID_OFF));
+}
+#endif
+
+void rcar_pwrc_restore_timer_state(void)
+{
+	/* Stop timer before restoring counter value */
+	mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCR_OFF), 0U);
+
+	mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCVL_OFF),
+		(uint32_t)(rcar_pwrc_saved_cntpct_el0 & 0xFFFFFFFFU));
+	mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCVU_OFF),
+		(uint32_t)(rcar_pwrc_saved_cntpct_el0 >> 32U));
+
+	mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTFID_OFF),
+		rcar_pwrc_saved_cntfid);
+
+	/* Start generic timer back */
+	write_cntfrq_el0((u_register_t)plat_get_syscnt_freq2());
+
+	mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCR_OFF),
+		(RCAR_CNTCR_FCREQ(0U) | RCAR_CNTCR_EN));
+}
+
+#if !PMIC_ROHM_BD9571
+void rcar_pwrc_system_reset(void)
+{
+	mmio_write_32(RCAR_SRESCR, 0x5AA50000U | BIT_SOFTRESET);
+}
+#endif /* PMIC_ROHM_BD9571 */
+
+#define	RST_CA53_CPU0_BARH		(0xE6160080U)
+#define	RST_CA53_CPU0_BARL		(0xE6160084U)
+#define	RST_CA57_CPU0_BARH		(0xE61600C0U)
+#define	RST_CA57_CPU0_BARL		(0xE61600C4U)
+
+void rcar_pwrc_setup(void)
+{
+	uintptr_t rst_barh;
+	uintptr_t rst_barl;
+	uint32_t i, j;
+	uint64_t reset = (uint64_t) (&plat_secondary_reset) & 0xFFFFFFFF;
+
+	const uint32_t cluster[PLATFORM_CLUSTER_COUNT] = {
+		RCAR_CLUSTER_CA53,
+		RCAR_CLUSTER_CA57
+	};
+	const uintptr_t reg_barh[PLATFORM_CLUSTER_COUNT] = {
+		RST_CA53_CPU0_BARH,
+		RST_CA57_CPU0_BARH
+	};
+	const uintptr_t reg_barl[PLATFORM_CLUSTER_COUNT] = {
+		RST_CA53_CPU0_BARL,
+		RST_CA57_CPU0_BARL
+	};
+
+	for (i = 0; i < PLATFORM_CLUSTER_COUNT; i++) {
+		rst_barh = reg_barh[i];
+		rst_barl = reg_barl[i];
+		for (j = 0; j < rcar_pwrc_get_cpu_num(cluster[i]); j++) {
+			mmio_write_32(rst_barh, 0);
+			mmio_write_32(rst_barl, (uint32_t) reset);
+			rst_barh += 0x10;
+			rst_barl += 0x10;
+		}
+	}
+
+	rcar_lock_init();
+}
+
+#if RCAR_SYSTEM_SUSPEND
+#define DBCAM_FLUSH(__bit)		\
+do {					\
+	;				\
+} while (!(mmio_read_32(DBSC4_REG_DBCAM##__bit##STAT0) & DBSC4_BIT_DBCAMxSTAT0))
+
+
+static void __attribute__ ((section(".system_ram")))
+	rcar_pwrc_set_self_refresh(void)
+{
+	uint32_t reg = mmio_read_32(RCAR_PRR);
+	uint32_t cut, product;
+
+	product = reg & RCAR_PRODUCT_MASK;
+	cut = reg & RCAR_CUT_MASK;
+
+	if (product == RCAR_PRODUCT_M3 && cut < RCAR_CUT_VER30)
+		goto self_refresh;
+
+	if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
+		goto self_refresh;
+
+	mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE);
+
+self_refresh:
+
+	/* DFI_PHYMSTR_ACK setting */
+	mmio_write_32(DBSC4_REG_DBDFIPMSTRCNF,
+			mmio_read_32(DBSC4_REG_DBDFIPMSTRCNF) &
+			(~DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN));
+
+	/* Set the Self-Refresh mode */
+	mmio_write_32(DBSC4_REG_DBACEN, 0);
+
+	if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
+		rcar_micro_delay(100);
+	else if (product == RCAR_PRODUCT_H3) {
+		mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
+		DBCAM_FLUSH(0);
+		DBCAM_FLUSH(1);
+		DBCAM_FLUSH(2);
+		DBCAM_FLUSH(3);
+		mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
+	} else if (product == RCAR_PRODUCT_M3) {
+		mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
+		DBCAM_FLUSH(0);
+		DBCAM_FLUSH(1);
+		mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
+	} else {
+		mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1);
+		DBCAM_FLUSH(0);
+		mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0);
+	}
+
+	/* Set the SDRAM calibration configuration register */
+	mmio_write_32(DBSC4_REG_DBCALCNF, 0);
+
+	reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL |
+	    DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL;
+	mmio_write_32(DBSC4_REG_DBCMD, reg);
+	while (mmio_read_32(DBSC4_REG_DBWAIT))
+		;
+
+	/* Self-Refresh entry command   */
+	reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL |
+	    DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
+	mmio_write_32(DBSC4_REG_DBCMD, reg);
+	while (mmio_read_32(DBSC4_REG_DBWAIT))
+		;
+
+	/* Mode Register Write command. (ODT disabled)  */
+	reg = DBSC4_SET_DBCMD_OPC_MRW | DBSC4_SET_DBCMD_CH_ALL |
+	    DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_MRW_ODTC;
+	mmio_write_32(DBSC4_REG_DBCMD, reg);
+	while (mmio_read_32(DBSC4_REG_DBWAIT))
+		;
+
+	/* Power Down entry command     */
+	reg = DBSC4_SET_DBCMD_OPC_PD | DBSC4_SET_DBCMD_CH_ALL |
+	    DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
+	mmio_write_32(DBSC4_REG_DBCMD, reg);
+	while (mmio_read_32(DBSC4_REG_DBWAIT))
+		;
+
+	/* Set the auto-refresh enable register */
+	mmio_write_32(DBSC4_REG_DBRFEN, 0U);
+	rcar_micro_delay(1U);
+
+	if (product == RCAR_PRODUCT_M3 && cut < RCAR_CUT_VER30)
+		return;
+
+	if (product == RCAR_PRODUCT_H3 && cut < RCAR_CUT_VER20)
+		return;
+
+	mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE);
+}
+
+static void __attribute__ ((section(".system_ram")))
+    rcar_pwrc_set_self_refresh_e3(void)
+{
+	uint32_t ddr_md;
+	uint32_t reg;
+
+	ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & RST_MODEMR_BIT0;
+
+	/* Write enable */
+	mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE);
+	mmio_write_32(DBSC4_REG_DBACEN, 0);
+	DBCAM_FLUSH(0);
+
+	reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL |
+	    DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL;
+	mmio_write_32(DBSC4_REG_DBCMD, reg);
+	while (mmio_read_32(DBSC4_REG_DBWAIT))
+		;
+
+	reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL |
+	    DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER;
+	mmio_write_32(DBSC4_REG_DBCMD, reg);
+	while (mmio_read_32(DBSC4_REG_DBWAIT))
+		;
+
+	/* Set the auto-refresh enable register */
+	/* Set the ARFEN bit to 0 in the DBRFEN */
+	mmio_write_32(DBSC4_REG_DBRFEN, 0);
+
+	mmio_write_32(DBSC4_REG_DBPDLK0, DBSC4_SET_DBPDLK0_PHY_ACCESS);
+
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR0);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR0);
+
+	/* DDR_DXCCR */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DXCCR);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DXCCR);
+
+	/* DDR_PGCR1 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_PGCR1);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_PGCR1);
+
+	/* DDR_ACIOCR1 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR1);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR1);
+
+	/* DDR_ACIOCR3 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR3);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR3);
+
+	/* DDR_ACIOCR5 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR5);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR5);
+
+	/* DDR_DX0GCR2 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR2);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR2);
+
+	/* DDR_DX1GCR2 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR2);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR2);
+
+	/* DDR_DX2GCR2 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR2);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR2);
+
+	/* DDR_DX3GCR2 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR2);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR2);
+
+	/* DDR_ZQCR */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ZQCR);
+
+	mmio_write_32(DBSC4_REG_DBPDRGD0, ddr_md == 0 ?
+		      DBSC4_SET_DBPDRGD0_ZQCR_MD19_0 :
+		      DBSC4_SET_DBPDRGD0_ZQCR_MD19_1);
+
+	/* DDR_DX0GCR0 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR0);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR0);
+
+	/* DDR_DX1GCR0 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR0);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR0);
+
+	/* DDR_DX2GCR0 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR0);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR0);
+
+	/* DDR_DX3GCR0 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR0);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR0);
+
+	/* DDR_DX0GCR1 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR1);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR1);
+
+	/* DDR_DX1GCR1 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR1);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR1);
+
+	/* DDR_DX2GCR1 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR1);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR1);
+
+	/* DDR_DX3GCR1 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR1);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR1);
+
+	/* DDR_DX0GCR3 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR3);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR3);
+
+	/* DDR_DX1GCR3 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR3);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR3);
+
+	/* DDR_DX2GCR3 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR3);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR3);
+
+	/* DDR_DX3GCR3 */
+	mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR3);
+	mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR3);
+
+	/* Write disable */
+	mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE);
+}
+
+void __attribute__ ((section(".system_ram"))) __attribute__ ((noinline))
+    rcar_pwrc_go_suspend_to_ram(void)
+{
+#if PMIC_ROHM_BD9571
+	int32_t rc = -1, qllm = -1;
+	uint8_t mode;
+	uint32_t i;
+#endif
+	uint32_t reg, product;
+
+	reg = mmio_read_32(RCAR_PRR);
+	product = reg & RCAR_PRODUCT_MASK;
+
+	if (product != RCAR_PRODUCT_E3)
+		rcar_pwrc_set_self_refresh();
+	else
+		rcar_pwrc_set_self_refresh_e3();
+
+#if PMIC_ROHM_BD9571
+	/* Set QLLM Cnt Disable */
+	for (i = 0; (i < PMIC_RETRY_MAX) && (qllm != 0); i++)
+		qllm = rcar_iic_dvfs_send(PMIC, PMIC_QLLM_CNT, 0);
+
+	/* Set trigger of power down to PMIV */
+	for (i = 0; (i < PMIC_RETRY_MAX) && (rc != 0) && (qllm == 0); i++) {
+		rc = rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode);
+		if (rc == 0) {
+			mode |= BIT_BKUP_CTRL_OUT;
+			rc = rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode);
+		}
+	}
+#endif
+	wfi();
+
+	while (1)
+		;
+}
+
+void rcar_pwrc_set_suspend_to_ram(void)
+{
+	uintptr_t jump = (uintptr_t) &rcar_pwrc_go_suspend_to_ram;
+	uintptr_t stack = (uintptr_t) (DEVICE_SRAM_STACK_BASE +
+				       DEVICE_SRAM_STACK_SIZE);
+	uint32_t sctlr;
+
+	rcar_pwrc_save_timer_state();
+
+	/* disable MMU */
+	sctlr = (uint32_t) read_sctlr_el3();
+	sctlr &= (uint32_t) ~SCTLR_EL3_M_BIT;
+	write_sctlr_el3((uint64_t) sctlr);
+
+	rcar_pwrc_switch_stack(jump, stack, NULL);
+}
+
+void rcar_pwrc_init_suspend_to_ram(void)
+{
+#if PMIC_ROHM_BD9571
+	uint8_t mode;
+
+	if (rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode))
+		panic();
+
+	mode &= (uint8_t) (~BIT_BKUP_CTRL_OUT);
+	if (rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode))
+		panic();
+#endif
+}
+
+void rcar_pwrc_suspend_to_ram(void)
+{
+#if RCAR_SYSTEM_RESET_KEEPON_DDR
+	int32_t error;
+
+	error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, 0);
+	if (error) {
+		ERROR("Failed send KEEP10 init ret=%d \n", error);
+		return;
+	}
+#endif
+	rcar_pwrc_set_suspend_to_ram();
+}
+#endif
+
+void rcar_pwrc_code_copy_to_system_ram(void)
+{
+	int ret __attribute__ ((unused));	/* in assert */
+	uint32_t attr;
+	struct device_sram_t {
+		uintptr_t base;
+		size_t len;
+	} sram = {
+		.base = (uintptr_t) DEVICE_SRAM_BASE,
+		.len = DEVICE_SRAM_SIZE,
+	};
+	struct ddr_code_t {
+		void *base;
+		size_t len;
+	} code = {
+		.base = (void *) SRAM_COPY_START,
+		.len = SYSTEM_RAM_END - SYSTEM_RAM_START,
+	};
+
+	attr = MT_MEMORY | MT_RW | MT_SECURE | MT_EXECUTE_NEVER;
+	ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
+	assert(ret == 0);
+
+	memcpy((void *)sram.base, code.base, code.len);
+	flush_dcache_range((uint64_t) sram.base, code.len);
+
+	/* Invalidate instruction cache */
+	plat_invalidate_icache();
+	dsb();
+	isb();
+
+	attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE;
+	ret = xlat_change_mem_attributes(sram.base, sram.len, attr);
+	assert(ret == 0);
+}
+
+uint32_t rcar_pwrc_get_cluster(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(RCAR_PRR);
+
+	if (reg & (1U << (STATE_CA53_CPU + RCAR_CA53CPU_NUM_MAX)))
+		return RCAR_CLUSTER_CA57;
+
+	if (reg & (1U << (STATE_CA57_CPU + RCAR_CA57CPU_NUM_MAX)))
+		return RCAR_CLUSTER_CA53;
+
+	return RCAR_CLUSTER_A53A57;
+}
+
+uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr)
+{
+	uint32_t c = rcar_pwrc_get_cluster();
+
+	if (IS_A53A57(c)) {
+		if (mpidr & MPIDR_CLUSTER_MASK)
+			return RCAR_CLUSTER_CA53;
+
+		return RCAR_CLUSTER_CA57;
+	}
+
+	return c;
+}
+
+#if RCAR_LSI == RCAR_D3
+uint32_t rcar_pwrc_get_cpu_num(uint32_t c)
+{
+	return 1;
+}
+#else
+uint32_t rcar_pwrc_get_cpu_num(uint32_t c)
+{
+	uint32_t reg = mmio_read_32(RCAR_PRR);
+	uint32_t count = 0, i;
+
+	if (IS_A53A57(c) || IS_CA53(c)) {
+		if (reg & (1 << (STATE_CA53_CPU + RCAR_CA53CPU_NUM_MAX)))
+			goto count_ca57;
+
+		for (i = 0; i < RCAR_CA53CPU_NUM_MAX; i++) {
+			if (reg & (1 << (STATE_CA53_CPU + i)))
+				continue;
+			count++;
+		}
+	}
+
+count_ca57:
+	if (IS_A53A57(c) || IS_CA57(c)) {
+		if (reg & (1U << (STATE_CA57_CPU + RCAR_CA57CPU_NUM_MAX)))
+			goto done;
+
+		for (i = 0; i < RCAR_CA57CPU_NUM_MAX; i++) {
+			if (reg & (1 << (STATE_CA57_CPU + i)))
+				continue;
+			count++;
+		}
+	}
+
+done:
+	return count;
+}
+#endif
+
+int32_t rcar_pwrc_cpu_on_check(uint64_t mpidr)
+{
+	uint64_t i;
+	uint64_t j;
+	uint64_t cpu_count;
+	uintptr_t reg_PSTR;
+	uint32_t status;
+	uint64_t my_cpu;
+	int32_t rtn;
+	uint32_t my_cluster_type;
+
+	const uint32_t cluster_type[PLATFORM_CLUSTER_COUNT] = {
+			RCAR_CLUSTER_CA53,
+			RCAR_CLUSTER_CA57
+	};
+	const uintptr_t registerPSTR[PLATFORM_CLUSTER_COUNT] = {
+			RCAR_CA53PSTR,
+			RCAR_CA57PSTR
+	};
+
+	my_cluster_type = rcar_pwrc_get_cluster();
+
+	rtn = 0;
+	my_cpu = mpidr & ((uint64_t)(MPIDR_CPU_MASK));
+	for (i = 0U; i < ((uint64_t)(PLATFORM_CLUSTER_COUNT)); i++) {
+		cpu_count = rcar_pwrc_get_cpu_num(cluster_type[i]);
+		reg_PSTR = registerPSTR[i];
+		for (j = 0U; j < cpu_count; j++) {
+			if ((my_cluster_type != cluster_type[i]) || (my_cpu != j)) {
+				status = mmio_read_32(reg_PSTR) >> (j * 4U);
+				if ((status & 0x00000003U) == 0U) {
+					rtn--;
+				}
+			}
+		}
+	}
+	return (rtn);
+
+}
diff --git a/drivers/renesas/rcar/pwrc/pwrc.h b/drivers/renesas/rcar/pwrc/pwrc.h
new file mode 100644
index 0000000..2b81783
--- /dev/null
+++ b/drivers/renesas/rcar/pwrc/pwrc.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PWRC_H
+#define PWRC_H
+
+#define PPOFFR_OFF		0x0
+#define PPONR_OFF		0x4
+#define PCOFFR_OFF		0x8
+#define PWKUPR_OFF		0xc
+#define PSYSR_OFF		0x10
+
+#define PWKUPR_WEN		(1ull << 31)
+
+#define PSYSR_AFF_L2		(1U << 31)
+#define PSYSR_AFF_L1		(1 << 30)
+#define PSYSR_AFF_L0		(1 << 29)
+#define PSYSR_WEN		(1 << 28)
+#define PSYSR_PC		(1 << 27)
+#define PSYSR_PP		(1 << 26)
+
+#define PSYSR_WK_SHIFT		(24)
+#define PSYSR_WK_MASK		(0x3)
+#define PSYSR_WK(x)		(((x) >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK)
+
+#define WKUP_COLD		0x0
+#define WKUP_RESET		0x1
+#define WKUP_PPONR		0x2
+#define WKUP_GICREQ		0x3
+
+#define	RCAR_INVALID		(0xffffffffU)
+#define PSYSR_INVALID		0xffffffff
+
+#define	RCAR_CLUSTER_A53A57	(0U)
+#define	RCAR_CLUSTER_CA53	(1U)
+#define	RCAR_CLUSTER_CA57	(2U)
+
+#ifndef __ASSEMBLER__
+void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr);
+void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr);
+void rcar_pwrc_clusteroff(uint64_t mpidr);
+void rcar_pwrc_cpuoff(uint64_t mpidr);
+void rcar_pwrc_cpuon(uint64_t mpidr);
+int32_t rcar_pwrc_cpu_on_check(uint64_t mpidr);
+void rcar_pwrc_setup(void);
+
+uint32_t rcar_pwrc_get_cpu_wkr(uint64_t mpidr);
+uint32_t rcar_pwrc_status(uint64_t mpidr);
+uint32_t rcar_pwrc_get_cluster(void);
+uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr);
+uint32_t rcar_pwrc_get_cpu_num(uint32_t cluster_type);
+void rcar_pwrc_restore_timer_state(void);
+void plat_secondary_reset(void);
+
+void rcar_pwrc_code_copy_to_system_ram(void);
+
+#if !PMIC_ROHM_BD9571
+void rcar_pwrc_system_reset(void);
+#endif
+
+#if RCAR_SYSTEM_SUSPEND
+void rcar_pwrc_go_suspend_to_ram(void);
+void rcar_pwrc_set_suspend_to_ram(void);
+void rcar_pwrc_init_suspend_to_ram(void);
+void rcar_pwrc_suspend_to_ram(void);
+#endif
+
+extern uint32_t rcar_pwrc_switch_stack(uintptr_t jump, uintptr_t stack,
+				       void *arg);
+#endif
+
+#endif /* PWRC_H */
diff --git a/drivers/renesas/rcar/qos/D3/qos_init_d3.c b/drivers/renesas/rcar/qos/D3/qos_init_d3.c
new file mode 100644
index 0000000..b96e822
--- /dev/null
+++ b/drivers/renesas/rcar/qos/D3/qos_init_d3.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_d3.h"
+
+#define	RCAR_QOS_VERSION		"rev.0.05"
+
+#include "qos_init_d3_mstat.h"
+
+struct rcar_gen3_dbsc_qos_settings d3_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBSCHCNT0, 0x000F0037 },
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00 },
+	{ DBSC_DBSCHQOS01, 0x00000B00 },
+	{ DBSC_DBSCHQOS02, 0x00000000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000300 },
+	{ DBSC_DBSCHQOS41, 0x000002F0 },
+	{ DBSC_DBSCHQOS42, 0x00000200 },
+	{ DBSC_DBSCHQOS43, 0x00000100 },
+	{ DBSC_DBSCHQOS90, 0x00000300 },
+	{ DBSC_DBSCHQOS91, 0x000002F0 },
+	{ DBSC_DBSCHQOS92, 0x00000200 },
+	{ DBSC_DBSCHQOS93, 0x00000100 },
+	{ DBSC_DBSCHQOS130, 0x00000100 },
+	{ DBSC_DBSCHQOS131, 0x000000F0 },
+	{ DBSC_DBSCHQOS132, 0x000000A0 },
+	{ DBSC_DBSCHQOS133, 0x00000040 },
+	{ DBSC_DBSCHQOS140, 0x000000C0 },
+	{ DBSC_DBSCHQOS141, 0x000000B0 },
+	{ DBSC_DBSCHQOS142, 0x00000080 },
+	{ DBSC_DBSCHQOS143, 0x00000040 },
+	{ DBSC_DBSCHQOS150, 0x00000040 },
+	{ DBSC_DBSCHQOS151, 0x00000030 },
+	{ DBSC_DBSCHQOS152, 0x00000020 },
+	{ DBSC_DBSCHQOS153, 0x00000010 },
+};
+
+void qos_init_d3(void)
+{
+	rcar_qos_dbsc_setting(d3_qos, ARRAY_SIZE(d3_qos), true);
+
+	/* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+	ERROR("DRAM Split 4ch not supported.(D3)");
+	panic();
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	ERROR("DRAM Split 2ch not supported.(D3)");
+	panic();
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO
+	ERROR("DRAM Split Auto not supported.(D3)");
+	panic();
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_LINEAR
+/*	NOTICE("BL2: DRAM Split is OFF\n"); */
+	/* Split setting(DDR 1ch) */
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	ERROR("DRAM split is an invalid value.(D3)");
+	panic();
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_RAS,   0x00000020U);
+	io_write_32(QOSCTRL_FIXTH, 0x000F0005U);
+	io_write_32(QOSCTRL_RAEN,  0x00000001U);
+	io_write_32(QOSCTRL_REGGD, 0x00000000U);
+	io_write_64(QOSCTRL_DANN,  0x0404020002020201U);
+	io_write_32(QOSCTRL_DANT,  0x00100804U);
+	io_write_32(QOSCTRL_EC,    0x00000000U);
+	io_write_64(QOSCTRL_EMS,   0x0000000000000000U);
+	io_write_32(QOSCTRL_FSS,   0x0000000AU);
+	io_write_32(QOSCTRL_INSFC, 0xC7840001U);
+	io_write_32(QOSCTRL_BERR,  0x00000000U);
+	io_write_32(QOSCTRL_EARLYR,  0x00000000U);
+	io_write_32(QOSCTRL_RACNT0,  0x00010003U);
+	io_write_32(QOSCTRL_STATGEN0, 0x00000000U);
+
+	/* GPU setting */
+	io_write_32(0xFD812030U, 0x00000000U);
+
+	/* QOSBW setting */
+	io_write_32(QOSCTRL_SL_INIT, 0x030500ACU);
+	io_write_32(QOSCTRL_REF_ARS, 0x00780000U);
+
+	/* QOSBW SRAM setting */
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+
+	/* 3DG bus Leaf setting */
+	io_write_32(GPU_ACT_GRD, 0x00001234U);
+	io_write_32(GPU_ACT0, 0x00000000U);
+	io_write_32(GPU_ACT1, 0x00000000U);
+	io_write_32(GPU_ACT2, 0x00000000U);
+	io_write_32(GPU_ACT3, 0x00000000U);
+
+	/* RT bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN,  0x00000001U);
+
+	/* QOSBW start */
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_EC,    0x00000000U);
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN,  0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/D3/qos_init_d3.h b/drivers/renesas/rcar/qos/D3/qos_init_d3.h
new file mode 100644
index 0000000..968ee7a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/D3/qos_init_d3.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H_D3__
+#define QOS_INIT_H_D3__
+
+void qos_init_d3(void);
+
+#endif	/* QOS_INIT_H_D3__ */
diff --git a/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h b/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h
new file mode 100644
index 0000000..cbf1f65
--- /dev/null
+++ b/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+static const uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004340000FFFFUL,
+	/* 0x0038, */ 0x001004140000FFFFUL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00140B030000FFFFUL,
+	/* 0x0060, */ 0x001408610000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001410620000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x000C041C0000FFFFUL,
+	/* 0x00A8, */ 0x000C04090000FFFFUL,
+	/* 0x00B0, */ 0x000C04110000FFFFUL,
+	/* 0x00B8, */ 0x0000000000000000UL,
+	/* 0x00C0, */ 0x000C041C0000FFFFUL,
+	/* 0x00C8, */ 0x000C04090000FFFFUL,
+	/* 0x00D0, */ 0x000C04110000FFFFUL,
+	/* 0x00D8, */ 0x0000000000000000UL,
+	/* 0x00E0, */ 0x0000000000000000UL,
+	/* 0x00E8, */ 0x0000000000000000UL,
+	/* 0x00F0, */ 0x001018570000FFFFUL,
+	/* 0x00F8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001008570000FFFFUL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x001008520000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00100CA30000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01A0, */ 0x0000000000000000UL,
+	/* 0x01A8, */ 0x0000000000000000UL,
+	/* 0x01B0, */ 0x0000000000000000UL,
+	/* 0x01B8, */ 0x0000000000000000UL,
+	/* 0x01C0, */ 0x0000000000000000UL,
+	/* 0x01C8, */ 0x0000000000000000UL,
+	/* 0x01D0, */ 0x0000000000000000UL,
+	/* 0x01D8, */ 0x0000000000000000UL,
+	/* 0x01E0, */ 0x0000000000000000UL,
+	/* 0x01E8, */ 0x000C04020000FFFFUL,
+	/* 0x01F0, */ 0x0000000000000000UL,
+	/* 0x01F8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04090000FFFFUL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x001410040000FFFFUL,
+	/* 0x0270, */ 0x001404020000FFFFUL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410040000FFFFUL,
+	/* 0x0298, */ 0x001404020000FFFFUL,
+	/* 0x02A0, */ 0x000C04050000FFFFUL,
+	/* 0x02A8, */ 0x000C04050000FFFFUL,
+	/* 0x02B0, */ 0x0000000000000000UL,
+	/* 0x02B8, */ 0x0000000000000000UL,
+	/* 0x02C0, */ 0x0000000000000000UL,
+	/* 0x02C8, */ 0x0000000000000000UL,
+	/* 0x02D0, */ 0x000C04050000FFFFUL,
+	/* 0x02D8, */ 0x000C04050000FFFFUL,
+	/* 0x02E0, */ 0x0000000000000000UL,
+	/* 0x02E8, */ 0x0000000000000000UL,
+	/* 0x02F0, */ 0x0000000000000000UL,
+	/* 0x02F8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x000C04020000FFFFUL,
+	/* 0x0378, */ 0x000C04020000FFFFUL,
+	/* 0x0380, */ 0x000C04090000FFFFUL,
+	/* 0x0388, */ 0x000C04090000FFFFUL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static const uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x0000000000000000UL,
+	/* 0x00A8, */ 0x0000000000000000UL,
+	/* 0x00B0, */ 0x0000000000000000UL,
+	/* 0x00B8, */ 0x0000000000000000UL,
+	/* 0x00C0, */ 0x0000000000000000UL,
+	/* 0x00C8, */ 0x0000000000000000UL,
+	/* 0x00D0, */ 0x0000000000000000UL,
+	/* 0x00D8, */ 0x0000000000000000UL,
+	/* 0x00E0, */ 0x0000000000000000UL,
+	/* 0x00E8, */ 0x0000000000000000UL,
+	/* 0x00F0, */ 0x0000000000000000UL,
+	/* 0x00F8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01A0, */ 0x0000000000000000UL,
+	/* 0x01A8, */ 0x0000000000000000UL,
+	/* 0x01B0, */ 0x0000000000000000UL,
+	/* 0x01B8, */ 0x0000000000000000UL,
+	/* 0x01C0, */ 0x00110090060FA001UL,
+	/* 0x01C8, */ 0x00110090060FA001UL,
+	/* 0x01D0, */ 0x0000000000000000UL,
+	/* 0x01D8, */ 0x0000000000000000UL,
+	/* 0x01E0, */ 0x0000000000000000UL,
+	/* 0x01E8, */ 0x0000000000000000UL,
+	/* 0x01F0, */ 0x0011001006004401UL,
+	/* 0x01F8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0011001006004401UL,
+	/* 0x0218, */ 0x0011001006009801UL,
+	/* 0x0220, */ 0x0011001006009801UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011001006009801UL,
+	/* 0x0238, */ 0x0011001006009801UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02A0, */ 0x0000000000000000UL,
+	/* 0x02A8, */ 0x0000000000000000UL,
+	/* 0x02B0, */ 0x0000000000000000UL,
+	/* 0x02B8, */ 0x0011001006003401UL,
+	/* 0x02C0, */ 0x0000000000000000UL,
+	/* 0x02C8, */ 0x0000000000000000UL,
+	/* 0x02D0, */ 0x0000000000000000UL,
+	/* 0x02D8, */ 0x0000000000000000UL,
+	/* 0x02E0, */ 0x0000000000000000UL,
+	/* 0x02E8, */ 0x0011001006003401UL,
+	/* 0x02F0, */ 0x00110090060FA001UL,
+	/* 0x02F8, */ 0x00110090060FA001UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0012001006003401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x00120090060FA001UL,
+	/* 0x0360, */ 0x00120090060FA001UL,
+	/* 0x0368, */ 0x0012001006003401UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0012001006003401UL,
+};
+#endif
+
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
new file mode 100644
index 0000000..6f4c66c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_e3_v10.h"
+
+#define	RCAR_QOS_VERSION		"rev.0.05"
+
+#define REF_ARS_ARBSTOPCYCLE_E3	(((SL_INIT_SSLOTCLK_E3) - 5U) << 16U)
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_e3_v10_mstat390.h"
+#else
+#include "qos_init_e3_v10_mstat780.h"
+#endif
+
+#endif
+
+struct rcar_gen3_dbsc_qos_settings e3_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBSCHCNT0, 0x000F0037 },
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00 },
+	{ DBSC_DBSCHQOS01, 0x00000B00 },
+	{ DBSC_DBSCHQOS02, 0x00000000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000300 },
+	{ DBSC_DBSCHQOS41, 0x000002F0 },
+	{ DBSC_DBSCHQOS42, 0x00000200 },
+	{ DBSC_DBSCHQOS43, 0x00000100 },
+	{ DBSC_DBSCHQOS90, 0x00000100 },
+	{ DBSC_DBSCHQOS91, 0x000000F0 },
+	{ DBSC_DBSCHQOS92, 0x000000A0 },
+	{ DBSC_DBSCHQOS93, 0x00000040 },
+	{ DBSC_DBSCHQOS130, 0x00000100 },
+	{ DBSC_DBSCHQOS131, 0x000000F0 },
+	{ DBSC_DBSCHQOS132, 0x000000A0 },
+	{ DBSC_DBSCHQOS133, 0x00000040 },
+	{ DBSC_DBSCHQOS140, 0x000000C0 },
+	{ DBSC_DBSCHQOS141, 0x000000B0 },
+	{ DBSC_DBSCHQOS142, 0x00000080 },
+	{ DBSC_DBSCHQOS143, 0x00000040 },
+	{ DBSC_DBSCHQOS150, 0x00000040 },
+	{ DBSC_DBSCHQOS151, 0x00000030 },
+	{ DBSC_DBSCHQOS152, 0x00000020 },
+	{ DBSC_DBSCHQOS153, 0x00000010 },
+};
+
+void qos_init_e3_v10(void)
+{
+	rcar_qos_dbsc_setting(e3_qos, ARRAY_SIZE(e3_qos), true);
+
+	/* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RCAR_E3
+#error "Don't set DRAM Split 4ch(E3)"
+#else
+	ERROR("DRAM Split 4ch not supported.(E3)");
+	panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH)
+#if RCAR_LSI == RCAR_E3
+#error "Don't set DRAM Split 2ch(E3)"
+#else
+	ERROR("DRAM Split 2ch not supported.(E3)");
+	panic();
+#endif
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 7.8 usec\n");
+#endif
+
+	io_write_32(QOSCTRL_RAS, 0x00000020U);
+	io_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x00100804U);
+	io_write_32(QOSCTRL_FSS, 0x0000000AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_EARLYR, 0x00000000U);
+	io_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+		    SL_INIT_SSLOTCLK_E3);
+	io_write_32(QOSCTRL_REF_ARS, REF_ARS_ARBSTOPCYCLE_E3);
+
+	/* QOSBW SRAM setting */
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif
+}
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h
new file mode 100644
index 0000000..2c1d8c5
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_E3_V10_H
+#define QOS_INIT_E3_V10_H
+
+void qos_init_e3_v10(void);
+
+#endif /* QOS_INIT_E3_V10_H */
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h
new file mode 100644
index 0000000..d7f9d14
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008620000FFFFUL,
+	/* 0x0038, */ 0x001008620000FFFFUL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x001415260000FFFFUL,
+	/* 0x0060, */ 0x001415260000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001414930000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08380000FFFFUL,
+	/* 0x00a8, */ 0x000C04110000FFFFUL,
+	/* 0x00b0, */ 0x000C04150000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08380000FFFFUL,
+	/* 0x00c8, */ 0x000C04110000FFFFUL,
+	/* 0x00d0, */ 0x000C04150000FFFFUL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001018580000FFFFUL,
+	/* 0x00f8, */ 0x000C084F0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001008580000FFFFUL,
+	/* 0x0118, */ 0x000C21E40000FFFFUL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001008530000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00100C960000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x001008530000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0010042A0000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00101D8D0000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x001008530000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04020000FFFFUL,
+	/* 0x01f0, */ 0x000C04090000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04090000FFFFUL,
+	/* 0x0210, */ 0x000C04090000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C2A0000FFFFUL,
+	/* 0x0268, */ 0x001410040000FFFFUL,
+	/* 0x0270, */ 0x001404020000FFFFUL,
+	/* 0x0278, */ 0x000C08110000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410040000FFFFUL,
+	/* 0x0298, */ 0x001404020000FFFFUL,
+	/* 0x02a0, */ 0x000C04090000FFFFUL,
+	/* 0x02a8, */ 0x000C04090000FFFFUL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x000C04020000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04090000FFFFUL,
+	/* 0x02d8, */ 0x000C04090000FFFFUL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x000C04020000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x000C04020000FFFFUL,
+	/* 0x0378, */ 0x000C04020000FFFFUL,
+	/* 0x0380, */ 0x000C04090000FFFFUL,
+	/* 0x0388, */ 0x000C04090000FFFFUL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005F03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0021060005FFFC01UL,
+	/* 0x01c8, */ 0x0021060005FFFC01UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021010005F79801UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021010005F79801UL,
+	/* 0x0218, */ 0x0011010005F79801UL,
+	/* 0x0220, */ 0x0011010005F79801UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011010005F79801UL,
+	/* 0x0238, */ 0x0011010005F79801UL,
+	/* 0x0240, */ 0x0012010005F79801UL,
+	/* 0x0248, */ 0x0011010005F79801UL,
+	/* 0x0250, */ 0x0012010005F79801UL,
+	/* 0x0258, */ 0x0011010005F79801UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011060005FFFC01UL,
+	/* 0x02f8, */ 0x0011060005FFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0012001005F03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0012060005FFFC01UL,
+	/* 0x0360, */ 0x0012060005FFFC01UL,
+	/* 0x0368, */ 0x0012001005F03401UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0012001005F03401UL,
+};
diff --git a/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h
new file mode 100644
index 0000000..439cafe
--- /dev/null
+++ b/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001010C40000FFFFUL,
+	/* 0x0038, */ 0x001010C40000FFFFUL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00142A4B0000FFFFUL,
+	/* 0x0060, */ 0x00142A4B0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001429260000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C10700000FFFFUL,
+	/* 0x00a8, */ 0x000C08210000FFFFUL,
+	/* 0x00b0, */ 0x000C082A0000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C10700000FFFFUL,
+	/* 0x00c8, */ 0x000C08210000FFFFUL,
+	/* 0x00d0, */ 0x000C082A0000FFFFUL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x00102CAF0000FFFFUL,
+	/* 0x00f8, */ 0x000C0C9D0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100CAF0000FFFFUL,
+	/* 0x0118, */ 0x000C43C80000FFFFUL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100CA50000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0010152C0000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x00100CA50000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008530000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001037190000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x00100CA50000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04040000FFFFUL,
+	/* 0x01f0, */ 0x000C08110000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04110000FFFFUL,
+	/* 0x0210, */ 0x000C08110000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C18530000FFFFUL,
+	/* 0x0268, */ 0x00141C070000FFFFUL,
+	/* 0x0270, */ 0x001404040000FFFFUL,
+	/* 0x0278, */ 0x000C0C210000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x00141C070000FFFFUL,
+	/* 0x0298, */ 0x001404040000FFFFUL,
+	/* 0x02a0, */ 0x000C04110000FFFFUL,
+	/* 0x02a8, */ 0x000C04110000FFFFUL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x000C04040000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04110000FFFFUL,
+	/* 0x02d8, */ 0x000C04110000FFFFUL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x000C04040000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x000C04040000FFFFUL,
+	/* 0x0378, */ 0x000C04040000FFFFUL,
+	/* 0x0380, */ 0x000C04110000FFFFUL,
+	/* 0x0388, */ 0x000C04110000FFFFUL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001002F03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0021060002FFFC01UL,
+	/* 0x01c8, */ 0x0021060002FFFC01UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021010002F3CC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021010002F3CC01UL,
+	/* 0x0218, */ 0x0011010002F3CC01UL,
+	/* 0x0220, */ 0x0011010002F3CC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011010002F3CC01UL,
+	/* 0x0238, */ 0x0011010002F3CC01UL,
+	/* 0x0240, */ 0x0012010002F3CC01UL,
+	/* 0x0248, */ 0x0011010002F3CC01UL,
+	/* 0x0250, */ 0x0012010002F3CC01UL,
+	/* 0x0258, */ 0x0011010002F3CC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011060002FFFC01UL,
+	/* 0x02f8, */ 0x0011060002FFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0012001002F03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0012060002FFFC01UL,
+	/* 0x0360, */ 0x0012060002FFFC01UL,
+	/* 0x0368, */ 0x0012001002F03401UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0012001002F03401UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
new file mode 100644
index 0000000..1fb43a7
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_h3_v10.h"
+
+#define	RCAR_QOS_VERSION		"rev.0.36"
+
+#include "qos_init_h3_v10_mstat.h"
+
+void qos_init_h3_v10(void)
+{
+	/* DRAM Split Address mapping */
+#if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \
+    (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 4ch\n");
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1BU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR1, 0x00000000U);
+	io_write_32(AXI_ADSPLCR2, 0xA8A90000U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	NOTICE("BL2: DRAM Split is 2ch\n");
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1BU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00000000U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+	/* AR Cache setting */
+	io_write_32(0xE67D1000U, 0x00000100U);
+	io_write_32(0xE67D1008U, 0x00000100U);
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_RAS, 0x00000040U);
+	io_write_32(QOSCTRL_FIXTH, 0x000F0005U);
+	io_write_32(QOSCTRL_REGGD, 0x00000004U);
+	io_write_64(QOSCTRL_DANN, 0x0202000004040404UL);
+	io_write_32(QOSCTRL_DANT, 0x003C1110U);
+	io_write_32(QOSCTRL_EC, 0x00080001U);	/* need for H3 v1.* */
+	io_write_64(QOSCTRL_EMS, 0x0000000000000000UL);
+	io_write_32(QOSCTRL_INSFC, 0xC7840001U);
+	io_write_32(QOSCTRL_BERR, 0x00000000U);
+
+	/* QOSBW setting */
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK);
+	io_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+
+	/* QOSBW SRAM setting */
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+
+	/* 3DG bus Leaf setting */
+	io_write_32(0xFD820808U, 0x00001234U);
+	io_write_32(0xFD820800U, 0x0000003FU);
+	io_write_32(0xFD821800U, 0x0000003FU);
+	io_write_32(0xFD822800U, 0x0000003FU);
+	io_write_32(0xFD823800U, 0x0000003FU);
+	io_write_32(0xFD824800U, 0x0000003FU);
+	io_write_32(0xFD825800U, 0x0000003FU);
+	io_write_32(0xFD826800U, 0x0000003FU);
+	io_write_32(0xFD827800U, 0x0000003FU);
+
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+	/* QOSBW start */
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_EC, 0x00080001U);	/* need for H3 v1.* */
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h
new file mode 100644
index 0000000..f96182a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H3_V10_H
+#define QOS_INIT_H3_V10_H
+
+void qos_init_h3_v10(void);
+
+#endif /* QOS_INIT_H3_V10_H */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h
new file mode 100644
index 0000000..fe63236
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+static const uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x00140C050000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x001404030000FFFFUL,
+	/* 0x0060, */ 0x001408060000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x00140C050000FFFFUL,
+	/* 0x0090, */ 0x001408060000FFFFUL,
+	/* 0x0098, */ 0x001404020000FFFFUL,
+	/* 0x00A0, */ 0x0000000000000000UL,
+	/* 0x00A8, */ 0x0000000000000000UL,
+	/* 0x00B0, */ 0x0000000000000000UL,
+	/* 0x00B8, */ 0x0000000000000000UL,
+	/* 0x00C0, */ 0x0000000000000000UL,
+	/* 0x00C8, */ 0x0000000000000000UL,
+	/* 0x00D0, */ 0x0000000000000000UL,
+	/* 0x00D8, */ 0x0000000000000000UL,
+	/* 0x00E0, */ 0x0000000000000000UL,
+	/* 0x00E8, */ 0x0000000000000000UL,
+	/* 0x00F0, */ 0x0000000000000000UL,
+	/* 0x00F8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001004020000FFFFUL,
+	/* 0x0140, */ 0x001004020000FFFFUL,
+	/* 0x0148, */ 0x001004020000FFFFUL,
+	/* 0x0150, */ 0x001008050000FFFFUL,
+	/* 0x0158, */ 0x001008050000FFFFUL,
+	/* 0x0160, */ 0x001008050000FFFFUL,
+	/* 0x0168, */ 0x001008050000FFFFUL,
+	/* 0x0170, */ 0x001008050000FFFFUL,
+	/* 0x0178, */ 0x001004030000FFFFUL,
+	/* 0x0180, */ 0x001004030000FFFFUL,
+	/* 0x0188, */ 0x001004030000FFFFUL,
+	/* 0x0190, */ 0x001014140000FFFFUL,
+	/* 0x0198, */ 0x001014140000FFFFUL,
+	/* 0x01A0, */ 0x001008060000FFFFUL,
+	/* 0x01A8, */ 0x001008060000FFFFUL,
+	/* 0x01B0, */ 0x001008060000FFFFUL,
+	/* 0x01B8, */ 0x0000000000000000UL,
+	/* 0x01C0, */ 0x0000000000000000UL,
+	/* 0x01C8, */ 0x0000000000000000UL,
+	/* 0x01D0, */ 0x0000000000000000UL,
+	/* 0x01D8, */ 0x0000000000000000UL,
+	/* 0x01E0, */ 0x0000000000000000UL,
+	/* 0x01E8, */ 0x0000000000000000UL,
+	/* 0x01F0, */ 0x0000000000000000UL,
+	/* 0x01F8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02A0, */ 0x0000000000000000UL,
+	/* 0x02A8, */ 0x0000000000000000UL,
+	/* 0x02B0, */ 0x0000000000000000UL,
+	/* 0x02B8, */ 0x0000000000000000UL,
+	/* 0x02C0, */ 0x0000000000000000UL,
+	/* 0x02C8, */ 0x0000000000000000UL,
+	/* 0x02D0, */ 0x0000000000000000UL,
+	/* 0x02D8, */ 0x0000000000000000UL,
+	/* 0x02E0, */ 0x0000000000000000UL,
+	/* 0x02E8, */ 0x0000000000000000UL,
+	/* 0x02F0, */ 0x0000000000000000UL,
+	/* 0x02F8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+};
+
+static const uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001000100C8FFC01UL,
+	/* 0x0008, */ 0x001000100C8FFC01UL,
+	/* 0x0010, */ 0x001000100C8FFC01UL,
+	/* 0x0018, */ 0x001000100C8FFC01UL,
+	/* 0x0020, */ 0x001000100C8FFC01UL,
+	/* 0x0028, */ 0x001000100C8FFC01UL,
+	/* 0x0030, */ 0x001000100C8FFC01UL,
+	/* 0x0038, */ 0x001000100C8FFC01UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001000100C8FFC01UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x001000100C8FFC01UL,
+	/* 0x0070, */ 0x001000100C8FFC01UL,
+	/* 0x0078, */ 0x001000100C8FFC01UL,
+	/* 0x0080, */ 0x001000100C8FFC01UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x001000100C8FFC01UL,
+	/* 0x00A8, */ 0x001000100C8FFC01UL,
+	/* 0x00B0, */ 0x001000100C8FFC01UL,
+	/* 0x00B8, */ 0x001000100C8FFC01UL,
+	/* 0x00C0, */ 0x001000100C8FFC01UL,
+	/* 0x00C8, */ 0x001000100C8FFC01UL,
+	/* 0x00D0, */ 0x001000100C8FFC01UL,
+	/* 0x00D8, */ 0x002000200C8FFC01UL,
+	/* 0x00E0, */ 0x002000200C8FFC01UL,
+	/* 0x00E8, */ 0x001000100C8FFC01UL,
+	/* 0x00F0, */ 0x001000100C8FFC01UL,
+	/* 0x00F8, */ 0x001000100C8FFC01UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x002000200C8FFC01UL,
+	/* 0x0110, */ 0x001000100C8FFC01UL,
+	/* 0x0118, */ 0x001000100C8FFC01UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x002000200C8FFC01UL,
+	/* 0x0130, */ 0x001000100C8FFC01UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01A0, */ 0x0000000000000000UL,
+	/* 0x01A8, */ 0x0000000000000000UL,
+	/* 0x01B0, */ 0x0000000000000000UL,
+	/* 0x01B8, */ 0x001000100C8FFC01UL,
+	/* 0x01C0, */ 0x001000200C8FFC01UL,
+	/* 0x01C8, */ 0x001000200C8FFC01UL,
+	/* 0x01D0, */ 0x001000200C8FFC01UL,
+	/* 0x01D8, */ 0x001000200C8FFC01UL,
+	/* 0x01E0, */ 0x001000100C8FFC01UL,
+	/* 0x01E8, */ 0x001000100C8FFC01UL,
+	/* 0x01F0, */ 0x001000100C8FFC01UL,
+	/* 0x01F8, */ 0x001000100C8FFC01UL,
+	/* 0x0200, */ 0x001000100C8FFC01UL,
+	/* 0x0208, */ 0x001000100C8FFC01UL,
+	/* 0x0210, */ 0x001000100C8FFC01UL,
+	/* 0x0218, */ 0x001000100C8FFC01UL,
+	/* 0x0220, */ 0x001000100C8FFC01UL,
+	/* 0x0228, */ 0x001000100C8FFC01UL,
+	/* 0x0230, */ 0x001000100C8FFC01UL,
+	/* 0x0238, */ 0x001000100C8FFC01UL,
+	/* 0x0240, */ 0x001000100C8FFC01UL,
+	/* 0x0248, */ 0x001000100C8FFC01UL,
+	/* 0x0250, */ 0x001000100C8FFC01UL,
+	/* 0x0258, */ 0x001000100C8FFC01UL,
+	/* 0x0260, */ 0x001000100C8FFC01UL,
+	/* 0x0268, */ 0x001000100C8FFC01UL,
+	/* 0x0270, */ 0x001000100C8FFC01UL,
+	/* 0x0278, */ 0x001000100C8FFC01UL,
+	/* 0x0280, */ 0x001000100C8FFC01UL,
+	/* 0x0288, */ 0x001000100C8FFC01UL,
+	/* 0x0290, */ 0x001000100C8FFC01UL,
+	/* 0x0298, */ 0x001000100C8FFC01UL,
+	/* 0x02A0, */ 0x001000100C8FFC01UL,
+	/* 0x02A8, */ 0x001000100C8FFC01UL,
+	/* 0x02B0, */ 0x001000100C8FFC01UL,
+	/* 0x02B8, */ 0x001000100C8FFC01UL,
+	/* 0x02C0, */ 0x001000100C8FFC01UL,
+	/* 0x02C8, */ 0x001000100C8FFC01UL,
+	/* 0x02D0, */ 0x001000100C8FFC01UL,
+	/* 0x02D8, */ 0x001000100C8FFC01UL,
+	/* 0x02E0, */ 0x001000100C8FFC01UL,
+	/* 0x02E8, */ 0x001000100C8FFC01UL,
+	/* 0x02F0, */ 0x001000200C8FFC01UL,
+	/* 0x02F8, */ 0x001000300C8FFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001000200C8FFC01UL,
+	/* 0x0310, */ 0x001000300C8FFC01UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x001000200C8FFC01UL,
+	/* 0x0328, */ 0x001000300C8FFC01UL,
+	/* 0x0330, */ 0x001000200C8FFC01UL,
+	/* 0x0338, */ 0x001000300C8FFC01UL,
+};
+#endif
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
new file mode 100644
index 0000000..329bcb8
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include <rcar_def.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_h3_v11.h"
+
+#define	RCAR_QOS_VERSION		"rev.0.37"
+
+#include "qos_init_h3_v11_mstat.h"
+
+struct rcar_gen3_dbsc_qos_settings h3_v11_qos[] = {
+	/* BUFCAM settings */
+	/* DBSC_DBCAM0CNF0 not set */
+	{ DBSC_DBCAM0CNF1, 0x00044218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	/* DBSC_DBCAM0CNF3 not set */
+	{ DBSC_DBSCHCNT0, 0x080F0037 },
+	{ DBSC_DBSCHCNT1, 0x00001010 },
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x0000F000 },
+	{ DBSC_DBSCHQOS01, 0x0000E000 },
+	{ DBSC_DBSCHQOS02, 0x00007000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000E00 },
+	{ DBSC_DBSCHQOS41, 0x00000DFF },
+	{ DBSC_DBSCHQOS42, 0x00000400 },
+	{ DBSC_DBSCHQOS43, 0x00000200 },
+	{ DBSC_DBSCHQOS90, 0x00000C00 },
+	{ DBSC_DBSCHQOS91, 0x00000BFF },
+	{ DBSC_DBSCHQOS92, 0x00000400 },
+	{ DBSC_DBSCHQOS93, 0x00000200 },
+	{ DBSC_DBSCHQOS130, 0x00000980 },
+	{ DBSC_DBSCHQOS131, 0x0000097F },
+	{ DBSC_DBSCHQOS132, 0x00000300 },
+	{ DBSC_DBSCHQOS133, 0x00000180 },
+	{ DBSC_DBSCHQOS140, 0x00000800 },
+	{ DBSC_DBSCHQOS141, 0x000007FF },
+	{ DBSC_DBSCHQOS142, 0x00000300 },
+	{ DBSC_DBSCHQOS143, 0x00000180 },
+	{ DBSC_DBSCHQOS150, 0x000007D0 },
+	{ DBSC_DBSCHQOS151, 0x000007CF },
+	{ DBSC_DBSCHQOS152, 0x000005D0 },
+	{ DBSC_DBSCHQOS153, 0x000003D0 },
+};
+
+void qos_init_h3_v11(void)
+{
+	rcar_qos_dbsc_setting(h3_v11_qos, ARRAY_SIZE(h3_v11_qos), false);
+
+	/* DRAM Split Address mapping */
+#if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \
+    (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 4ch\n");
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1BU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR1, 0x00000000U);
+	io_write_32(AXI_ADSPLCR2, 0xA8A90000U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	NOTICE("BL2: DRAM Split is 2ch\n");
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1BU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00000000U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+	/* AR Cache setting */
+	io_write_32(0xE67D1000U, 0x00000100U);
+	io_write_32(0xE67D1008U, 0x00000100U);
+
+	/* Resource Alloc setting */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	io_write_32(QOSCTRL_RAS, 0x00000020U);
+#else
+	io_write_32(QOSCTRL_RAS, 0x00000040U);
+#endif
+	io_write_32(QOSCTRL_FIXTH, 0x000F0005U);
+	io_write_32(QOSCTRL_REGGD, 0x00000000U);
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	io_write_64(QOSCTRL_DANN, 0x0101010102020201UL);
+	io_write_32(QOSCTRL_DANT, 0x00181008U);
+#else
+	io_write_64(QOSCTRL_DANN, 0x0101000004040401UL);
+	io_write_32(QOSCTRL_DANT, 0x003C2010U);
+#endif
+	io_write_32(QOSCTRL_EC, 0x00080001U);	/* need for H3 v1.* */
+	io_write_64(QOSCTRL_EMS, 0x0000000000000000UL);
+	io_write_32(QOSCTRL_INSFC, 0xC7840001U);
+	io_write_32(QOSCTRL_BERR, 0x00000000U);
+	io_write_32(QOSCTRL_RACNT0, 0x00000000U);
+
+	/* QOSBW setting */
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK);
+	io_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+
+	/* QOSBW SRAM setting */
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+
+	/* 3DG bus Leaf setting */
+	io_write_32(0xFD820808U, 0x00001234U);
+	io_write_32(0xFD820800U, 0x0000003FU);
+	io_write_32(0xFD821800U, 0x0000003FU);
+	io_write_32(0xFD822800U, 0x0000003FU);
+	io_write_32(0xFD823800U, 0x0000003FU);
+	io_write_32(0xFD824800U, 0x0000003FU);
+	io_write_32(0xFD825800U, 0x0000003FU);
+	io_write_32(0xFD826800U, 0x0000003FU);
+	io_write_32(0xFD827800U, 0x0000003FU);
+
+	/* VIO bus Leaf setting */
+	io_write_32(0xFEB89800, 0x00000001U);
+	io_write_32(0xFEB8A800, 0x00000001U);
+	io_write_32(0xFEB8B800, 0x00000001U);
+	io_write_32(0xFEB8C800, 0x00000001U);
+
+	/* HSC bus Leaf setting */
+	io_write_32(0xE6430800, 0x00000001U);
+	io_write_32(0xE6431800, 0x00000001U);
+	io_write_32(0xE6432800, 0x00000001U);
+	io_write_32(0xE6433800, 0x00000001U);
+
+	/* MP bus Leaf setting */
+	io_write_32(0xEC620800, 0x00000001U);
+	io_write_32(0xEC621800, 0x00000001U);
+
+	/* PERIE bus Leaf setting */
+	io_write_32(0xE7760800, 0x00000001U);
+	io_write_32(0xE7768800, 0x00000001U);
+
+	/* PERIW bus Leaf setting */
+	io_write_32(0xE6760800, 0x00000001U);
+	io_write_32(0xE6768800, 0x00000001U);
+
+	/* RT bus Leaf setting */
+	io_write_32(0xFFC50800, 0x00000001U);
+	io_write_32(0xFFC51800, 0x00000001U);
+
+	/* CCI bus Leaf setting */
+	uint32_t modemr = io_read_32(RCAR_MODEMR);
+
+	modemr &= MODEMR_BOOT_CPU_MASK;
+
+	if ((modemr == MODEMR_BOOT_CPU_CA57) ||
+	    (modemr == MODEMR_BOOT_CPU_CA53)) {
+		io_write_32(0xF1300800, 0x00000001U);
+		io_write_32(0xF1340800, 0x00000001U);
+		io_write_32(0xF1380800, 0x00000001U);
+		io_write_32(0xF13C0800, 0x00000001U);
+	}
+
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+	/* QOSBW start */
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_EC, 0x00080001U);	/* need for H3 v1.* */
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h
new file mode 100644
index 0000000..3faeb4f
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H3_V11_H
+#define QOS_INIT_H3_V11_H
+
+void qos_init_h3_v11(void);
+
+#endif /* QOS_INIT_H3_V11_H */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h
new file mode 100644
index 0000000..46c68c8
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+static const uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004030000FFFFUL,
+	/* 0x0038, */ 0x001008060000FFFFUL,
+	/* 0x0040, */ 0x001414090000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001410010000FFFFUL,
+	/* 0x0058, */ 0x00140C0C0000FFFFUL,
+	/* 0x0060, */ 0x00140C0C0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001410010000FFFFUL,
+	/* 0x0078, */ 0x001008060000FFFFUL,
+	/* 0x0080, */ 0x001004020000FFFFUL,
+	/* 0x0088, */ 0x001414090000FFFFUL,
+	/* 0x0090, */ 0x00140C0C0000FFFFUL,
+	/* 0x0098, */ 0x001408080000FFFFUL,
+	/* 0x00A0, */ 0x000C08020000FFFFUL,
+	/* 0x00A8, */ 0x000C04010000FFFFUL,
+	/* 0x00B0, */ 0x000C04010000FFFFUL,
+	/* 0x00B8, */ 0x0000000000000000UL,
+	/* 0x00C0, */ 0x000C08020000FFFFUL,
+	/* 0x00C8, */ 0x000C04010000FFFFUL,
+	/* 0x00D0, */ 0x000C04010000FFFFUL,
+	/* 0x00D8, */ 0x000C04030000FFFFUL,
+	/* 0x00E0, */ 0x000C100F0000FFFFUL,
+	/* 0x00E8, */ 0x0000000000000000UL,
+	/* 0x00F0, */ 0x001010080000FFFFUL,
+	/* 0x00F8, */ 0x001010080000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x000C04030000FFFFUL,
+	/* 0x0110, */ 0x001010080000FFFFUL,
+	/* 0x0118, */ 0x001010080000FFFFUL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x000C100E0000FFFFUL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001008050000FFFFUL,
+	/* 0x0140, */ 0x001008050000FFFFUL,
+	/* 0x0148, */ 0x001008050000FFFFUL,
+	/* 0x0150, */ 0x001008050000FFFFUL,
+	/* 0x0158, */ 0x001008050000FFFFUL,
+	/* 0x0160, */ 0x001008050000FFFFUL,
+	/* 0x0168, */ 0x001008050000FFFFUL,
+	/* 0x0170, */ 0x001008050000FFFFUL,
+	/* 0x0178, */ 0x001004030000FFFFUL,
+	/* 0x0180, */ 0x001004030000FFFFUL,
+	/* 0x0188, */ 0x001004030000FFFFUL,
+	/* 0x0190, */ 0x001014140000FFFFUL,
+	/* 0x0198, */ 0x001014140000FFFFUL,
+	/* 0x01A0, */ 0x001008050000FFFFUL,
+	/* 0x01A8, */ 0x001008050000FFFFUL,
+	/* 0x01B0, */ 0x001008050000FFFFUL,
+	/* 0x01B8, */ 0x0000000000000000UL,
+	/* 0x01C0, */ 0x0000000000000000UL,
+	/* 0x01C8, */ 0x0000000000000000UL,
+	/* 0x01D0, */ 0x0000000000000000UL,
+	/* 0x01D8, */ 0x0000000000000000UL,
+	/* 0x01E0, */ 0x0000000000000000UL,
+	/* 0x01E8, */ 0x0000000000000000UL,
+	/* 0x01F0, */ 0x0000000000000000UL,
+	/* 0x01F8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02A0, */ 0x000C04010000FFFFUL,
+	/* 0x02A8, */ 0x000C04010000FFFFUL,
+	/* 0x02B0, */ 0x001404010000FFFFUL,
+	/* 0x02B8, */ 0x0000000000000000UL,
+	/* 0x02C0, */ 0x0000000000000000UL,
+	/* 0x02C8, */ 0x0000000000000000UL,
+	/* 0x02D0, */ 0x000C04010000FFFFUL,
+	/* 0x02D8, */ 0x000C04010000FFFFUL,
+	/* 0x02E0, */ 0x001404010000FFFFUL,
+	/* 0x02E8, */ 0x0000000000000000UL,
+	/* 0x02F0, */ 0x0000000000000000UL,
+	/* 0x02F8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+};
+
+static const uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200100C89C401UL,
+	/* 0x0008, */ 0x001200100C89C401UL,
+	/* 0x0010, */ 0x001200100C89C401UL,
+	/* 0x0018, */ 0x001200100C89C401UL,
+	/* 0x0020, */ 0x001100100C803401UL,
+	/* 0x0028, */ 0x001100100C80FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x001100100C803401UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x0000000000000000UL,
+	/* 0x00A8, */ 0x0000000000000000UL,
+	/* 0x00B0, */ 0x0000000000000000UL,
+	/* 0x00B8, */ 0x001100100C803401UL,
+	/* 0x00C0, */ 0x0000000000000000UL,
+	/* 0x00C8, */ 0x0000000000000000UL,
+	/* 0x00D0, */ 0x0000000000000000UL,
+	/* 0x00D8, */ 0x0000000000000000UL,
+	/* 0x00E0, */ 0x0000000000000000UL,
+	/* 0x00E8, */ 0x001100100C803401UL,
+	/* 0x00F0, */ 0x0000000000000000UL,
+	/* 0x00F8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x001100100C803401UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01A0, */ 0x0000000000000000UL,
+	/* 0x01A8, */ 0x0000000000000000UL,
+	/* 0x01B0, */ 0x0000000000000000UL,
+	/* 0x01B8, */ 0x001100100C803401UL,
+	/* 0x01C0, */ 0x001100800C8FFC01UL,
+	/* 0x01C8, */ 0x001100800C8FFC01UL,
+	/* 0x01D0, */ 0x001100800C8FFC01UL,
+	/* 0x01D8, */ 0x001100800C8FFC01UL,
+	/* 0x01E0, */ 0x001100100C80FC01UL,
+	/* 0x01E8, */ 0x001200100C80FC01UL,
+	/* 0x01F0, */ 0x001100100C80FC01UL,
+	/* 0x01F8, */ 0x001100100C803401UL,
+	/* 0x0200, */ 0x001100100C80FC01UL,
+	/* 0x0208, */ 0x001200100C80FC01UL,
+	/* 0x0210, */ 0x001100100C80FC01UL,
+	/* 0x0218, */ 0x001100100C825801UL,
+	/* 0x0220, */ 0x001100100C825801UL,
+	/* 0x0228, */ 0x001100100C803401UL,
+	/* 0x0230, */ 0x001100100C825801UL,
+	/* 0x0238, */ 0x001100100C825801UL,
+	/* 0x0240, */ 0x001200100C8BB801UL,
+	/* 0x0248, */ 0x001100200C8FFC01UL,
+	/* 0x0250, */ 0x001200100C8BB801UL,
+	/* 0x0258, */ 0x001100200C8FFC01UL,
+	/* 0x0260, */ 0x001100100C84E401UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x001100100C81F401UL,
+	/* 0x0280, */ 0x001100100C803401UL,
+	/* 0x0288, */ 0x001100100C803401UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02A0, */ 0x0000000000000000UL,
+	/* 0x02A8, */ 0x0000000000000000UL,
+	/* 0x02B0, */ 0x0000000000000000UL,
+	/* 0x02B8, */ 0x001100100C803401UL,
+	/* 0x02C0, */ 0x001100100C803401UL,
+	/* 0x02C8, */ 0x001100100C803401UL,
+	/* 0x02D0, */ 0x0000000000000000UL,
+	/* 0x02D8, */ 0x0000000000000000UL,
+	/* 0x02E0, */ 0x0000000000000000UL,
+	/* 0x02E8, */ 0x001100100C803401UL,
+	/* 0x02F0, */ 0x001100300C8FFC01UL,
+	/* 0x02F8, */ 0x001100500C8FFC01UL,
+	/* 0x0300, */ 0x001100100C803401UL,
+	/* 0x0308, */ 0x001100300C8FFC01UL,
+	/* 0x0310, */ 0x001100500C8FFC01UL,
+	/* 0x0318, */ 0x001200100C803401UL,
+	/* 0x0320, */ 0x001100300C8FFC01UL,
+	/* 0x0328, */ 0x001100500C8FFC01UL,
+	/* 0x0330, */ 0x001100300C8FFC01UL,
+	/* 0x0338, */ 0x001100500C8FFC01UL,
+};
+#endif
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
new file mode 100644
index 0000000..c20ab08
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_h3_v20.h"
+
+#define RCAR_QOS_VERSION			"rev.0.21"
+
+#define QOSWT_TIME_BANK0			20000000U	/* unit:ns */
+
+#define QOSWT_WTEN_ENABLE			0x1U
+
+#define QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_20	(SL_INIT_SSLOTCLK_H3_20 - 0x5U)
+
+#define OSWT_WTREF_SLOT0_EN_REQ1_SLOT		3U
+#define OSWT_WTREF_SLOT0_EN_REQ2_SLOT		9U
+#define QOSWT_WTREF_SLOT0_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+#define QOSWT_WTREF_SLOT1_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+
+#define QOSWT_WTSET0_REQ_SSLOT0			5U
+#define WT_BASE_SUB_SLOT_NUM0			12U
+#define QOSWT_WTSET0_PERIOD0_H3_20			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3_20) - 1U)
+#define QOSWT_WTSET0_SSLOT0			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_H3_20			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3_20) - 1U)
+#define QOSWT_WTSET1_SSLOT1			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET1_SLOTSLOT1			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_h3_v20_mstat195.h"
+#else
+#include "qos_init_h3_v20_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_h3_v20_qoswt195.h"
+#else
+#include "qos_init_h3_v20_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+#endif
+
+struct rcar_gen3_dbsc_qos_settings h3_v20_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218U },
+	{ DBSC_DBCAM0CNF2, 0x000000F4U },
+	{ DBSC_DBCAM0CNF3, 0x00000000U },
+	{ DBSC_DBSCHCNT0, 0x000F0037U },
+	{ DBSC_DBSCHSZ0, 0x00000001U },
+	{ DBSC_DBSCHRW0, 0x22421111U },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123U },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00U },
+	{ DBSC_DBSCHQOS01, 0x00000B00U },
+	{ DBSC_DBSCHQOS02, 0x00000000U },
+	{ DBSC_DBSCHQOS03, 0x00000000U },
+	{ DBSC_DBSCHQOS40, 0x00000300U },
+	{ DBSC_DBSCHQOS41, 0x000002F0U },
+	{ DBSC_DBSCHQOS42, 0x00000200U },
+	{ DBSC_DBSCHQOS43, 0x00000100U },
+	{ DBSC_DBSCHQOS90, 0x00000100U },
+	{ DBSC_DBSCHQOS91, 0x000000F0U },
+	{ DBSC_DBSCHQOS92, 0x000000A0U },
+	{ DBSC_DBSCHQOS93, 0x00000040U },
+	{ DBSC_DBSCHQOS120, 0x00000040U },
+	{ DBSC_DBSCHQOS121, 0x00000030U },
+	{ DBSC_DBSCHQOS122, 0x00000020U },
+	{ DBSC_DBSCHQOS123, 0x00000010U },
+	{ DBSC_DBSCHQOS130, 0x00000100U },
+	{ DBSC_DBSCHQOS131, 0x000000F0U },
+	{ DBSC_DBSCHQOS132, 0x000000A0U },
+	{ DBSC_DBSCHQOS133, 0x00000040U },
+	{ DBSC_DBSCHQOS140, 0x000000C0U },
+	{ DBSC_DBSCHQOS141, 0x000000B0U },
+	{ DBSC_DBSCHQOS142, 0x00000080U },
+	{ DBSC_DBSCHQOS143, 0x00000040U },
+	{ DBSC_DBSCHQOS150, 0x00000040U },
+	{ DBSC_DBSCHQOS151, 0x00000030U },
+	{ DBSC_DBSCHQOS152, 0x00000020U },
+	{ DBSC_DBSCHQOS153, 0x00000010U },
+};
+
+void qos_init_h3_v20(void)
+{
+	rcar_qos_dbsc_setting(h3_v20_qos, ARRAY_SIZE(h3_v20_qos), true);
+
+	/* DRAM Split Address mapping */
+#if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \
+    (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 4ch\n");
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1BU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR1, 0x00000000U);
+	io_write_32(AXI_ADSPLCR2, 0x00001054U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	NOTICE("BL2: DRAM Split is 2ch\n");
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1BU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00001004U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_RAS, 0x00000044U);
+	io_write_64(QOSCTRL_DANN, 0x0404010002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x0020100AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+	/* GPU Boost Mode */
+	io_write_32(QOSCTRL_STATGEN0, 0x00000001U);
+
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+		    SL_INIT_SSLOTCLK_H3_20);
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	io_write_32(QOSCTRL_REF_ARS,
+		    ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_20 << 16)));
+#else
+	io_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+		io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8,
+			    qoswt_fix[i]);
+		io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8,
+			    qoswt_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+		io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]);
+		io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]);
+	}
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	/* 3DG bus Leaf setting */
+	io_write_32(GPU_ACT0, 0x00000000U);
+	io_write_32(GPU_ACT1, 0x00000000U);
+	io_write_32(GPU_ACT2, 0x00000000U);
+	io_write_32(GPU_ACT3, 0x00000000U);
+	io_write_32(GPU_ACT4, 0x00000000U);
+	io_write_32(GPU_ACT5, 0x00000000U);
+	io_write_32(GPU_ACT6, 0x00000000U);
+	io_write_32(GPU_ACT7, 0x00000000U);
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+	io_write_32(CPU_ACT2, 0x00000003U);
+	io_write_32(CPU_ACT3, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	/*  re-write training setting */
+	io_write_32(QOSWT_WTREF,
+		    ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+	io_write_32(QOSWT_WTSET0,
+		    ((QOSWT_WTSET0_PERIOD0_H3_20 << 16) |
+		     (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+	io_write_32(QOSWT_WTSET1,
+		    ((QOSWT_WTSET1_PERIOD1_H3_20 << 16) |
+		     (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+	io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h
new file mode 100644
index 0000000..9b7619e
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H3_V20_H
+#define QOS_INIT_H3_V20_H
+
+void qos_init_h3_v20(void);
+
+#endif /* QOS_INIT_H3_V20_H */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h
new file mode 100644
index 0000000..3995df3
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000FFFFUL,
+	/* 0x0038, */ 0x001008070000FFFFUL,
+	/* 0x0040, */ 0x001424110000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x001410100000FFFFUL,
+	/* 0x0060, */ 0x0014100D0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x001008070000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001424110000FFFFUL,
+	/* 0x0090, */ 0x0014100D0000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C04020000FFFFUL,
+	/* 0x00a8, */ 0x000C04010000FFFFUL,
+	/* 0x00b0, */ 0x000C04010000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C04020000FFFFUL,
+	/* 0x00c8, */ 0x000C04010000FFFFUL,
+	/* 0x00d0, */ 0x000C04010000FFFFUL,
+	/* 0x00d8, */ 0x001024090000FFFFUL,
+	/* 0x00e0, */ 0x00100C090000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001024090000FFFFUL,
+	/* 0x00f8, */ 0x000C08070000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100C090000FFFFUL,
+	/* 0x0118, */ 0x000C10100000FFFFUL,
+	/* 0x0120, */ 0x000C10100000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100C0B0000FFFFUL,
+	/* 0x0140, */ 0x00100C0B0000FFFFUL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0010100D0000FFFFUL,
+	/* 0x0158, */ 0x0010100D0000FFFFUL,
+	/* 0x0160, */ 0x00100C0B0000FFFFUL,
+	/* 0x0168, */ 0x00100C0B0000FFFFUL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008060000FFFFUL,
+	/* 0x0180, */ 0x001008060000FFFFUL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00102C2C0000FFFFUL,
+	/* 0x0198, */ 0x00102C2C0000FFFFUL,
+	/* 0x01a0, */ 0x00100C0B0000FFFFUL,
+	/* 0x01a8, */ 0x00100C0B0000FFFFUL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFFFUL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C04010000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x001408010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x001408010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200200BDFFC01UL,
+	/* 0x0008, */ 0x001200200BDFFC01UL,
+	/* 0x0010, */ 0x001200200BDFFC01UL,
+	/* 0x0018, */ 0x001200200BDFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001200100BD0FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100700BDFFC01UL,
+	/* 0x01c8, */ 0x002100700BDFFC01UL,
+	/* 0x01d0, */ 0x002100700BDFFC01UL,
+	/* 0x01d8, */ 0x002100700BDFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x002100200BDFFC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x002100200BDFFC01UL,
+	/* 0x0218, */ 0x001100200BDFFC01UL,
+	/* 0x0220, */ 0x001100200BDFFC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001100200BDFFC01UL,
+	/* 0x0238, */ 0x001100200BDFFC01UL,
+	/* 0x0240, */ 0x001200200BDFFC01UL,
+	/* 0x0248, */ 0x001100200BDFFC01UL,
+	/* 0x0250, */ 0x001200200BDFFC01UL,
+	/* 0x0258, */ 0x001100200BDFFC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x001100400BDFFC01UL,
+	/* 0x02f8, */ 0x001100600BDFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001100400BDFFC01UL,
+	/* 0x0310, */ 0x001100600BDFFC01UL,
+	/* 0x0318, */ 0x001200100BD03401UL,
+	/* 0x0320, */ 0x001100400BDFFC01UL,
+	/* 0x0328, */ 0x001100600BDFFC01UL,
+	/* 0x0330, */ 0x001100400BDFFC01UL,
+	/* 0x0338, */ 0x001100600BDFFC01UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x001200100BD0FC01UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h
new file mode 100644
index 0000000..770c022
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000FFFFUL,
+	/* 0x0038, */ 0x0010100D0000FFFFUL,
+	/* 0x0040, */ 0x001444210000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x0014201F0000FFFFUL,
+	/* 0x0060, */ 0x00141C190000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x0010100D0000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001444210000FFFFUL,
+	/* 0x0090, */ 0x00141C190000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08040000FFFFUL,
+	/* 0x00a8, */ 0x000C04020000FFFFUL,
+	/* 0x00b0, */ 0x000C04020000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08040000FFFFUL,
+	/* 0x00c8, */ 0x000C04020000FFFFUL,
+	/* 0x00d0, */ 0x000C04020000FFFFUL,
+	/* 0x00d8, */ 0x001044110000FFFFUL,
+	/* 0x00e0, */ 0x001014110000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001044110000FFFFUL,
+	/* 0x00f8, */ 0x000C100D0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001014110000FFFFUL,
+	/* 0x0118, */ 0x000C20200000FFFFUL,
+	/* 0x0120, */ 0x000C20200000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001018150000FFFFUL,
+	/* 0x0140, */ 0x001018150000FFFFUL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00101C190000FFFFUL,
+	/* 0x0158, */ 0x00101C190000FFFFUL,
+	/* 0x0160, */ 0x001018150000FFFFUL,
+	/* 0x0168, */ 0x001018150000FFFFUL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x00100C0B0000FFFFUL,
+	/* 0x0180, */ 0x00100C0B0000FFFFUL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001058570000FFFFUL,
+	/* 0x0198, */ 0x001058570000FFFFUL,
+	/* 0x01a0, */ 0x001018150000FFFFUL,
+	/* 0x01a8, */ 0x001018150000FFFFUL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFFFUL,
+	/* 0x0268, */ 0x001410010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C08020000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x00140C010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x00140C010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0012003005EFFC01UL,
+	/* 0x0008, */ 0x0012003005EFFC01UL,
+	/* 0x0010, */ 0x0012003005EFFC01UL,
+	/* 0x0018, */ 0x0012003005EFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005E0FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100D005EFFC01UL,
+	/* 0x01c8, */ 0x002100D005EFFC01UL,
+	/* 0x01d0, */ 0x002100D005EFFC01UL,
+	/* 0x01d8, */ 0x002100D005EFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021003005EFFC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021003005EFFC01UL,
+	/* 0x0218, */ 0x0011003005EFFC01UL,
+	/* 0x0220, */ 0x0011003005EFFC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011003005EFFC01UL,
+	/* 0x0238, */ 0x0011003005EFFC01UL,
+	/* 0x0240, */ 0x0012003005EFFC01UL,
+	/* 0x0248, */ 0x0011003005EFFC01UL,
+	/* 0x0250, */ 0x0012003005EFFC01UL,
+	/* 0x0258, */ 0x0011003005EFFC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011007005EFFC01UL,
+	/* 0x02f8, */ 0x001100B005EFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0011007005EFFC01UL,
+	/* 0x0310, */ 0x001100B005EFFC01UL,
+	/* 0x0318, */ 0x0012001005E03401UL,
+	/* 0x0320, */ 0x0011007005EFFC01UL,
+	/* 0x0328, */ 0x001100B005EFFC01UL,
+	/* 0x0330, */ 0x0011007005EFFC01UL,
+	/* 0x0338, */ 0x001100B005EFFC01UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0012001005E0FC01UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h
new file mode 100644
index 0000000..82e4b01
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000C010UL,
+	/* 0x0038, */ 0x001008070000C010UL,
+	/* 0x0040, */ 0x001424110000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x001410100000C010UL,
+	/* 0x0060, */ 0x0014100D0000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x001008070000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001424110000FFF0UL,
+	/* 0x0090, */ 0x0014100D0000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFF0UL,
+	/* 0x0268, */ 0x001408010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C04010000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h
new file mode 100644
index 0000000..f3e7360
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000C010UL,
+	/* 0x0038, */ 0x0010100D0000C010UL,
+	/* 0x0040, */ 0x001444210000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0014201F0000C010UL,
+	/* 0x0060, */ 0x00141C190000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0010100D0000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001444210000FFF0UL,
+	/* 0x0090, */ 0x00141C190000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFF0UL,
+	/* 0x0268, */ 0x001410010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C08020000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
new file mode 100644
index 0000000..1fe6182
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_h3_v30.h"
+
+#define	RCAR_QOS_VERSION			"rev.0.11"
+
+#define QOSWT_TIME_BANK0			20000000U	/* unit:ns */
+
+#define	QOSWT_WTEN_ENABLE			0x1U
+
+#define QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_30	(SL_INIT_SSLOTCLK_H3_30 - 0x5U)
+
+#define OSWT_WTREF_SLOT0_EN_REQ1_SLOT		3U
+#define OSWT_WTREF_SLOT0_EN_REQ2_SLOT		9U
+#define QOSWT_WTREF_SLOT0_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+#define QOSWT_WTREF_SLOT1_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+
+#define QOSWT_WTSET0_REQ_SSLOT0			5U
+#define WT_BASE_SUB_SLOT_NUM0			12U
+#define QOSWT_WTSET0_PERIOD0_H3_30			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3_30) - 1U)
+#define QOSWT_WTSET0_SSLOT0			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_H3_30		(QOSWT_WTSET0_PERIOD0_H3_30)
+#define QOSWT_WTSET1_SSLOT1			(QOSWT_WTSET0_SSLOT0)
+#define QOSWT_WTSET1_SLOTSLOT1			(QOSWT_WTSET0_SLOTSLOT0)
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_h3_v30_mstat195.h"
+#else
+#include "qos_init_h3_v30_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_h3_v30_qoswt195.h"
+#else
+#include "qos_init_h3_v30_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+#endif
+
+struct rcar_gen3_dbsc_qos_settings h3_v30_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218U },
+	{ DBSC_DBCAM0CNF2, 0x000000F4U },
+	{ DBSC_DBCAM0CNF3, 0x00000000U },
+	{ DBSC_DBSCHCNT0, 0x000F0037U },
+	{ DBSC_DBSCHSZ0, 0x00000001U },
+	{ DBSC_DBSCHRW0, 0x22421111U },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123U },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00U },
+	{ DBSC_DBSCHQOS01, 0x00000B00U },
+	{ DBSC_DBSCHQOS02, 0x00000000U },
+	{ DBSC_DBSCHQOS03, 0x00000000U },
+	{ DBSC_DBSCHQOS40, 0x00000300U },
+	{ DBSC_DBSCHQOS41, 0x000002F0U },
+	{ DBSC_DBSCHQOS42, 0x00000200U },
+	{ DBSC_DBSCHQOS43, 0x00000100U },
+	{ DBSC_DBSCHQOS90, 0x00000100U },
+	{ DBSC_DBSCHQOS91, 0x000000F0U },
+	{ DBSC_DBSCHQOS92, 0x000000A0U },
+	{ DBSC_DBSCHQOS93, 0x00000040U },
+	{ DBSC_DBSCHQOS120, 0x00000040U },
+	{ DBSC_DBSCHQOS121, 0x00000030U },
+	{ DBSC_DBSCHQOS122, 0x00000020U },
+	{ DBSC_DBSCHQOS123, 0x00000010U },
+	{ DBSC_DBSCHQOS130, 0x00000100U },
+	{ DBSC_DBSCHQOS131, 0x000000F0U },
+	{ DBSC_DBSCHQOS132, 0x000000A0U },
+	{ DBSC_DBSCHQOS133, 0x00000040U },
+	{ DBSC_DBSCHQOS140, 0x000000C0U },
+	{ DBSC_DBSCHQOS141, 0x000000B0U },
+	{ DBSC_DBSCHQOS142, 0x00000080U },
+	{ DBSC_DBSCHQOS143, 0x00000040U },
+	{ DBSC_DBSCHQOS150, 0x00000040U },
+	{ DBSC_DBSCHQOS151, 0x00000030U },
+	{ DBSC_DBSCHQOS152, 0x00000020U },
+	{ DBSC_DBSCHQOS153, 0x00000010U },
+};
+
+void qos_init_h3_v30(void)
+{
+	unsigned int split_area;
+
+	rcar_qos_dbsc_setting(h3_v30_qos, ARRAY_SIZE(h3_v30_qos), true);
+
+#if RCAR_DRAM_LPDDR4_MEMCONF == 0	/* 1GB */
+	split_area = 0x1BU;
+#else /* default 2GB */
+	split_area = 0x1CU;
+#endif
+
+	/* DRAM Split Address mapping */
+#if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \
+    (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 4ch(DDR %x)\n", (int)qos_init_ddr_phyvalid);
+
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(split_area)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR1, 0x00000000U);
+	io_write_32(AXI_ADSPLCR2, 0x00001054U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH
+	NOTICE("BL2: DRAM Split is 2ch(DDR %x)\n", (int)qos_init_ddr_phyvalid);
+
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area));
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(split_area)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00001004U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area));
+	NOTICE("BL2: DRAM Split is OFF(DDR %x)\n", (int)qos_init_ddr_phyvalid);
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_RAS, 0x00000044U);
+	io_write_64(QOSCTRL_DANN, 0x0404010002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x0020100AU);
+	io_write_32(QOSCTRL_FSS, 0x0000000AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+	/* GPU Boost Mode */
+	io_write_32(QOSCTRL_STATGEN0, 0x00000001U);
+
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+		    SL_INIT_SSLOTCLK_H3_30);
+	io_write_32(QOSCTRL_REF_ARS,
+		    ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_30 << 16)));
+
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+		io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8,
+			    qoswt_fix[i]);
+		io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8,
+			    qoswt_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+		io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]);
+		io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]);
+	}
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	/* AXI setting */
+	io_write_32(AXI_MMCR, 0x00010008U);
+	io_write_32(AXI_TR3CR, 0x00010000U);
+	io_write_32(AXI_TR4CR, 0x00010000U);
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+	io_write_32(CPU_ACT2, 0x00000003U);
+	io_write_32(CPU_ACT3, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	/*  re-write training setting */
+	io_write_32(QOSWT_WTREF,
+		    ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+	io_write_32(QOSWT_WTSET0,
+		    ((QOSWT_WTSET0_PERIOD0_H3_30 << 16) |
+		     (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+	io_write_32(QOSWT_WTSET1,
+		    ((QOSWT_WTSET1_PERIOD1_H3_30 << 16) |
+		     (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+	io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h
new file mode 100644
index 0000000..d33b43c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H3_V30_H
+#define QOS_INIT_H3_V30_H
+
+void qos_init_h3_v30(void);
+
+#endif /* QOS_INIT_H3_V30_H */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h
new file mode 100644
index 0000000..28a240f
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000FFFFUL,
+	/* 0x0038, */ 0x001008070000FFFFUL,
+	/* 0x0040, */ 0x001410070000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x0014100D0000FFFFUL,
+	/* 0x0060, */ 0x0014100D0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x001008070000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001410070000FFFFUL,
+	/* 0x0090, */ 0x0014100D0000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C04020000FFFFUL,
+	/* 0x00a8, */ 0x000C04010000FFFFUL,
+	/* 0x00b0, */ 0x000C04010000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C04020000FFFFUL,
+	/* 0x00c8, */ 0x000C04010000FFFFUL,
+	/* 0x00d0, */ 0x000C04010000FFFFUL,
+	/* 0x00d8, */ 0x001024090000FFFFUL,
+	/* 0x00e0, */ 0x00100C090000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001024090000FFFFUL,
+	/* 0x00f8, */ 0x000C100D0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100C090000FFFFUL,
+	/* 0x0118, */ 0x000C1C1B0000FFFFUL,
+	/* 0x0120, */ 0x000C1C1B0000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100C0B0000FFFFUL,
+	/* 0x0140, */ 0x00100C0B0000FFFFUL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0010100D0000FFFFUL,
+	/* 0x0158, */ 0x0010100D0000FFFFUL,
+	/* 0x0160, */ 0x00100C0B0000FFFFUL,
+	/* 0x0168, */ 0x00100C0B0000FFFFUL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008060000FFFFUL,
+	/* 0x0180, */ 0x001008060000FFFFUL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00102C2C0000FFFFUL,
+	/* 0x0198, */ 0x00102C2C0000FFFFUL,
+	/* 0x01a0, */ 0x00100C0B0000FFFFUL,
+	/* 0x01a8, */ 0x00100C0B0000FFFFUL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFFFUL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C04010000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x001408010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x001408010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200600BDFFC01UL,
+	/* 0x0008, */ 0x001200600BDFFC01UL,
+	/* 0x0010, */ 0x001200600BDFFC01UL,
+	/* 0x0018, */ 0x001200600BDFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001200100BD0FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100600BDFFC01UL,
+	/* 0x01c8, */ 0x002100600BDFFC01UL,
+	/* 0x01d0, */ 0x002100600BDFFC01UL,
+	/* 0x01d8, */ 0x002100600BDFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x002100100BDF2401UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x002100100BDF2401UL,
+	/* 0x0218, */ 0x001100100BDF2401UL,
+	/* 0x0220, */ 0x001100100BDF2401UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001100100BDF2401UL,
+	/* 0x0238, */ 0x001100100BDF2401UL,
+	/* 0x0240, */ 0x001200100BDF2401UL,
+	/* 0x0248, */ 0x001100100BDF2401UL,
+	/* 0x0250, */ 0x001200100BDF2401UL,
+	/* 0x0258, */ 0x001100100BDF2401UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x001100600BDFFC01UL,
+	/* 0x02f8, */ 0x001100600BDFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001100600BDFFC01UL,
+	/* 0x0310, */ 0x001100600BDFFC01UL,
+	/* 0x0318, */ 0x001200100BD03401UL,
+	/* 0x0320, */ 0x001100600BDFFC01UL,
+	/* 0x0328, */ 0x001100600BDFFC01UL,
+	/* 0x0330, */ 0x001100600BDFFC01UL,
+	/* 0x0338, */ 0x001100600BDFFC01UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x001200100BD0FC01UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h
new file mode 100644
index 0000000..def6585
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000FFFFUL,
+	/* 0x0038, */ 0x0010100D0000FFFFUL,
+	/* 0x0040, */ 0x00141C0E0000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001408010000FFFFUL,
+	/* 0x0058, */ 0x00141C190000FFFFUL,
+	/* 0x0060, */ 0x00141C190000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001408010000FFFFUL,
+	/* 0x0078, */ 0x0010100D0000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x00141C0E0000FFFFUL,
+	/* 0x0090, */ 0x00141C190000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08040000FFFFUL,
+	/* 0x00a8, */ 0x000C04020000FFFFUL,
+	/* 0x00b0, */ 0x000C04020000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08040000FFFFUL,
+	/* 0x00c8, */ 0x000C04020000FFFFUL,
+	/* 0x00d0, */ 0x000C04020000FFFFUL,
+	/* 0x00d8, */ 0x001044110000FFFFUL,
+	/* 0x00e0, */ 0x001014110000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001044110000FFFFUL,
+	/* 0x00f8, */ 0x000C1C1A0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001014110000FFFFUL,
+	/* 0x0118, */ 0x000C38360000FFFFUL,
+	/* 0x0120, */ 0x000C38360000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001018150000FFFFUL,
+	/* 0x0140, */ 0x001018150000FFFFUL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00101C190000FFFFUL,
+	/* 0x0158, */ 0x00101C190000FFFFUL,
+	/* 0x0160, */ 0x001018150000FFFFUL,
+	/* 0x0168, */ 0x001018150000FFFFUL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x00100C0B0000FFFFUL,
+	/* 0x0180, */ 0x00100C0B0000FFFFUL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001058570000FFFFUL,
+	/* 0x0198, */ 0x001058570000FFFFUL,
+	/* 0x01a0, */ 0x001018150000FFFFUL,
+	/* 0x01a8, */ 0x001018150000FFFFUL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFFFUL,
+	/* 0x0268, */ 0x001410010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C08020000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x00140C010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x00140C010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0012006005EFFC01UL,
+	/* 0x0008, */ 0x0012006005EFFC01UL,
+	/* 0x0010, */ 0x0012006005EFFC01UL,
+	/* 0x0018, */ 0x0012006005EFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005E0FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0021006005EFFC01UL,
+	/* 0x01c8, */ 0x0021006005EFFC01UL,
+	/* 0x01d0, */ 0x0021006005EFFC01UL,
+	/* 0x01d8, */ 0x0021006005EFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021001005E79401UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021001005E79401UL,
+	/* 0x0218, */ 0x0011001005E79401UL,
+	/* 0x0220, */ 0x0011001005E79401UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011001005E79401UL,
+	/* 0x0238, */ 0x0011001005E79401UL,
+	/* 0x0240, */ 0x0012001005E79401UL,
+	/* 0x0248, */ 0x0011001005E79401UL,
+	/* 0x0250, */ 0x0012001005E79401UL,
+	/* 0x0258, */ 0x0011001005E79401UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011006005EFFC01UL,
+	/* 0x02f8, */ 0x0011006005EFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0011006005EFFC01UL,
+	/* 0x0310, */ 0x0011006005EFFC01UL,
+	/* 0x0318, */ 0x0012001005E03401UL,
+	/* 0x0320, */ 0x0011006005EFFC01UL,
+	/* 0x0328, */ 0x0011006005EFFC01UL,
+	/* 0x0330, */ 0x0011006005EFFC01UL,
+	/* 0x0338, */ 0x0011006005EFFC01UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0012001005E0FC01UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h
new file mode 100644
index 0000000..b0c11cc
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000C010UL,
+	/* 0x0038, */ 0x001008070000C010UL,
+	/* 0x0040, */ 0x001410070000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0014100D0000C010UL,
+	/* 0x0060, */ 0x0014100D0000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x001008070000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001410070000FFF0UL,
+	/* 0x0090, */ 0x0014100D0000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFF0UL,
+	/* 0x0268, */ 0x001408010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C04010000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h
new file mode 100644
index 0000000..a1e4c72
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000C010UL,
+	/* 0x0038, */ 0x0010100D0000C010UL,
+	/* 0x0040, */ 0x00141C0E0000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00141C190000C010UL,
+	/* 0x0060, */ 0x00141C190000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0010100D0000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x00141C0E0000FFF0UL,
+	/* 0x0090, */ 0x00141C190000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFF0UL,
+	/* 0x0268, */ 0x001410010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C08020000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
new file mode 100644
index 0000000..f1ee41b
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_h3n_v30.h"
+
+#define	RCAR_QOS_VERSION			"rev.0.07"
+
+#define QOSWT_TIME_BANK0			20000000U	/* unit:ns */
+
+#define	QOSWT_WTEN_ENABLE			0x1U
+
+#define QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3N	(SL_INIT_SSLOTCLK_H3N - 0x5U)
+
+#define OSWT_WTREF_SLOT0_EN_REQ1_SLOT		3U
+#define OSWT_WTREF_SLOT0_EN_REQ2_SLOT		9U
+#define QOSWT_WTREF_SLOT0_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+#define QOSWT_WTREF_SLOT1_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+
+#define QOSWT_WTSET0_REQ_SSLOT0			5U
+#define WT_BASE_SUB_SLOT_NUM0			12U
+#define QOSWT_WTSET0_PERIOD0_H3N			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3N) - 1U)
+#define QOSWT_WTSET0_SSLOT0			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_H3N		(QOSWT_WTSET0_PERIOD0_H3N)
+#define QOSWT_WTSET1_SSLOT1			(QOSWT_WTSET0_SSLOT0)
+#define QOSWT_WTSET1_SLOTSLOT1			(QOSWT_WTSET0_SLOTSLOT0)
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_h3n_v30_mstat195.h"
+#else
+#include "qos_init_h3n_v30_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_h3n_v30_qoswt195.h"
+#else
+#include "qos_init_h3n_v30_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+#endif
+
+struct rcar_gen3_dbsc_qos_settings h3n_v30_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218U },
+	{ DBSC_DBCAM0CNF2, 0x000000F4U },
+	{ DBSC_DBCAM0CNF3, 0x00000000U },
+	{ DBSC_DBSCHCNT0, 0x000F0037U },
+	{ DBSC_DBSCHSZ0, 0x00000001U },
+	{ DBSC_DBSCHRW0, 0x22421111U },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123U },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00U },
+	{ DBSC_DBSCHQOS01, 0x00000B00U },
+	{ DBSC_DBSCHQOS02, 0x00000000U },
+	{ DBSC_DBSCHQOS03, 0x00000000U },
+	{ DBSC_DBSCHQOS40, 0x00000300U },
+	{ DBSC_DBSCHQOS41, 0x000002F0U },
+	{ DBSC_DBSCHQOS42, 0x00000200U },
+	{ DBSC_DBSCHQOS43, 0x00000100U },
+	{ DBSC_DBSCHQOS90, 0x00000100U },
+	{ DBSC_DBSCHQOS91, 0x000000F0U },
+	{ DBSC_DBSCHQOS92, 0x000000A0U },
+	{ DBSC_DBSCHQOS93, 0x00000040U },
+	{ DBSC_DBSCHQOS120, 0x00000040U },
+	{ DBSC_DBSCHQOS121, 0x00000030U },
+	{ DBSC_DBSCHQOS122, 0x00000020U },
+	{ DBSC_DBSCHQOS123, 0x00000010U },
+	{ DBSC_DBSCHQOS130, 0x00000100U },
+	{ DBSC_DBSCHQOS131, 0x000000F0U },
+	{ DBSC_DBSCHQOS132, 0x000000A0U },
+	{ DBSC_DBSCHQOS133, 0x00000040U },
+	{ DBSC_DBSCHQOS140, 0x000000C0U },
+	{ DBSC_DBSCHQOS141, 0x000000B0U },
+	{ DBSC_DBSCHQOS142, 0x00000080U },
+	{ DBSC_DBSCHQOS143, 0x00000040U },
+	{ DBSC_DBSCHQOS150, 0x00000040U },
+	{ DBSC_DBSCHQOS151, 0x00000030U },
+	{ DBSC_DBSCHQOS152, 0x00000020U },
+	{ DBSC_DBSCHQOS153, 0x00000010U },
+};
+
+void qos_init_h3n_v30(void)
+{
+	unsigned int split_area;
+
+	rcar_qos_dbsc_setting(h3n_v30_qos, ARRAY_SIZE(h3n_v30_qos), true);
+
+	/* use 1(2GB) for RCAR_DRAM_LPDDR4_MEMCONF for H3N */
+	split_area = 0x1CU;
+
+	/* DRAM Split Address mapping */
+#if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH)
+#if RCAR_LSI == RCAR_H3N
+#error "Don't set DRAM Split 4ch(H3N)"
+#else
+	ERROR("DRAM Split 4ch not supported.(H3N)");
+	panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+    (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 2ch(DDR %x)\n", (int)qos_init_ddr_phyvalid);
+
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area));
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(split_area)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00001004U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area));
+	NOTICE("BL2: DRAM Split is OFF(DDR %x)\n", (int)qos_init_ddr_phyvalid);
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_RAS, 0x00000044U);
+	io_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x0020100AU);
+	io_write_32(QOSCTRL_FSS, 0x0000000AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+	/* GPU Boost Mode */
+	io_write_32(QOSCTRL_STATGEN0, 0x00000001U);
+
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+		    SL_INIT_SSLOTCLK_H3N);
+	io_write_32(QOSCTRL_REF_ARS,
+		    ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3N << 16)));
+
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+		io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8,
+			    qoswt_fix[i]);
+		io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8,
+			    qoswt_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+		io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]);
+		io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]);
+	}
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	/* AXI setting */
+	io_write_32(AXI_MMCR, 0x00010008U);
+	io_write_32(AXI_TR3CR, 0x00010000U);
+	io_write_32(AXI_TR4CR, 0x00010000U);
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+	io_write_32(CPU_ACT2, 0x00000003U);
+	io_write_32(CPU_ACT3, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	/*  re-write training setting */
+	io_write_32(QOSWT_WTREF,
+		    ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+	io_write_32(QOSWT_WTSET0,
+		    ((QOSWT_WTSET0_PERIOD0_H3N << 16) |
+		     (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+	io_write_32(QOSWT_WTSET1,
+		    ((QOSWT_WTSET1_PERIOD1_H3N << 16) |
+		     (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+	io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h
new file mode 100644
index 0000000..46f3440
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H3N_V30_H
+#define QOS_INIT_H3N_V30_H
+
+void qos_init_h3n_v30(void);
+
+#endif /* QOS_INIT_H3N_V30_H */
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h
new file mode 100644
index 0000000..6dbc88a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000FFFFUL,
+	/* 0x0038, */ 0x001008070000FFFFUL,
+	/* 0x0040, */ 0x001410070000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x0014100D0000FFFFUL,
+	/* 0x0060, */ 0x0014100D0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001410070000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C04020000FFFFUL,
+	/* 0x00a8, */ 0x000C04010000FFFFUL,
+	/* 0x00b0, */ 0x000C04010000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C04020000FFFFUL,
+	/* 0x00c8, */ 0x000C04010000FFFFUL,
+	/* 0x00d0, */ 0x000C04010000FFFFUL,
+	/* 0x00d8, */ 0x001024090000FFFFUL,
+	/* 0x00e0, */ 0x00100C090000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001024090000FFFFUL,
+	/* 0x00f8, */ 0x000C100D0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100C090000FFFFUL,
+	/* 0x0118, */ 0x000C1C1B0000FFFFUL,
+	/* 0x0120, */ 0x000C1C1B0000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100C0B0000FFFFUL,
+	/* 0x0140, */ 0x00100C0B0000FFFFUL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0010100D0000FFFFUL,
+	/* 0x0158, */ 0x0010100D0000FFFFUL,
+	/* 0x0160, */ 0x00100C0B0000FFFFUL,
+	/* 0x0168, */ 0x00100C0B0000FFFFUL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008060000FFFFUL,
+	/* 0x0180, */ 0x001008060000FFFFUL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00102C2C0000FFFFUL,
+	/* 0x0198, */ 0x00102C2C0000FFFFUL,
+	/* 0x01a0, */ 0x00100C0B0000FFFFUL,
+	/* 0x01a8, */ 0x00100C0B0000FFFFUL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFFFUL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C04010000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x001408010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x001408010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200600BDFFC01UL,
+	/* 0x0008, */ 0x001200600BDFFC01UL,
+	/* 0x0010, */ 0x001200600BDFFC01UL,
+	/* 0x0018, */ 0x001200600BDFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001200100BD0FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100600BDFFC01UL,
+	/* 0x01c8, */ 0x002100600BDFFC01UL,
+	/* 0x01d0, */ 0x002100600BDFFC01UL,
+	/* 0x01d8, */ 0x002100600BDFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x002100100BDF2401UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x002100100BDF2401UL,
+	/* 0x0218, */ 0x001100100BDF2401UL,
+	/* 0x0220, */ 0x001100100BDF2401UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001100100BDF2401UL,
+	/* 0x0238, */ 0x001100100BDF2401UL,
+	/* 0x0240, */ 0x001200100BDF2401UL,
+	/* 0x0248, */ 0x001100100BDF2401UL,
+	/* 0x0250, */ 0x001200100BDF2401UL,
+	/* 0x0258, */ 0x001100100BDF2401UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x001100600BDFFC01UL,
+	/* 0x02f8, */ 0x001100600BDFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001100600BDFFC01UL,
+	/* 0x0310, */ 0x001100600BDFFC01UL,
+	/* 0x0318, */ 0x001200100BD03401UL,
+	/* 0x0320, */ 0x001100600BDFFC01UL,
+	/* 0x0328, */ 0x001100600BDFFC01UL,
+	/* 0x0330, */ 0x001100600BDFFC01UL,
+	/* 0x0338, */ 0x001100600BDFFC01UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x001200100BD0FC01UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h
new file mode 100644
index 0000000..880211c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000FFFFUL,
+	/* 0x0038, */ 0x0010100D0000FFFFUL,
+	/* 0x0040, */ 0x00141C0E0000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001408010000FFFFUL,
+	/* 0x0058, */ 0x00141C190000FFFFUL,
+	/* 0x0060, */ 0x00141C190000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001408010000FFFFUL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x00141C0E0000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08040000FFFFUL,
+	/* 0x00a8, */ 0x000C04020000FFFFUL,
+	/* 0x00b0, */ 0x000C04020000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08040000FFFFUL,
+	/* 0x00c8, */ 0x000C04020000FFFFUL,
+	/* 0x00d0, */ 0x000C04020000FFFFUL,
+	/* 0x00d8, */ 0x001044110000FFFFUL,
+	/* 0x00e0, */ 0x001014110000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001044110000FFFFUL,
+	/* 0x00f8, */ 0x000C1C1A0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001014110000FFFFUL,
+	/* 0x0118, */ 0x000C38360000FFFFUL,
+	/* 0x0120, */ 0x000C38360000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001018150000FFFFUL,
+	/* 0x0140, */ 0x001018150000FFFFUL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00101C190000FFFFUL,
+	/* 0x0158, */ 0x00101C190000FFFFUL,
+	/* 0x0160, */ 0x001018150000FFFFUL,
+	/* 0x0168, */ 0x001018150000FFFFUL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x00100C0B0000FFFFUL,
+	/* 0x0180, */ 0x00100C0B0000FFFFUL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001058570000FFFFUL,
+	/* 0x0198, */ 0x001058570000FFFFUL,
+	/* 0x01a0, */ 0x001018150000FFFFUL,
+	/* 0x01a8, */ 0x001018150000FFFFUL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFFFUL,
+	/* 0x0268, */ 0x001410010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C08020000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x00140C010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x00140C010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0012006005EFFC01UL,
+	/* 0x0008, */ 0x0012006005EFFC01UL,
+	/* 0x0010, */ 0x0012006005EFFC01UL,
+	/* 0x0018, */ 0x0012006005EFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005E0FC01UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0021006005EFFC01UL,
+	/* 0x01c8, */ 0x0021006005EFFC01UL,
+	/* 0x01d0, */ 0x0021006005EFFC01UL,
+	/* 0x01d8, */ 0x0021006005EFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021001005E79401UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021001005E79401UL,
+	/* 0x0218, */ 0x0011001005E79401UL,
+	/* 0x0220, */ 0x0011001005E79401UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011001005E79401UL,
+	/* 0x0238, */ 0x0011001005E79401UL,
+	/* 0x0240, */ 0x0012001005E79401UL,
+	/* 0x0248, */ 0x0011001005E79401UL,
+	/* 0x0250, */ 0x0012001005E79401UL,
+	/* 0x0258, */ 0x0011001005E79401UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011006005EFFC01UL,
+	/* 0x02f8, */ 0x0011006005EFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0011006005EFFC01UL,
+	/* 0x0310, */ 0x0011006005EFFC01UL,
+	/* 0x0318, */ 0x0012001005E03401UL,
+	/* 0x0320, */ 0x0011006005EFFC01UL,
+	/* 0x0328, */ 0x0011006005EFFC01UL,
+	/* 0x0330, */ 0x0011006005EFFC01UL,
+	/* 0x0338, */ 0x0011006005EFFC01UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0012001005E0FC01UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h
new file mode 100644
index 0000000..affd013
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000C010UL,
+	/* 0x0038, */ 0x001008070000C010UL,
+	/* 0x0040, */ 0x001410070000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0014100D0000C010UL,
+	/* 0x0060, */ 0x0014100D0000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001410070000FFF0UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFF0UL,
+	/* 0x0268, */ 0x001408010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C04010000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h
new file mode 100644
index 0000000..1c48d28
--- /dev/null
+++ b/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000C010UL,
+	/* 0x0038, */ 0x0010100D0000C010UL,
+	/* 0x0040, */ 0x00141C0E0000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00141C190000C010UL,
+	/* 0x0060, */ 0x00141C190000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x00141C0E0000FFF0UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFF0UL,
+	/* 0x0268, */ 0x001410010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C08020000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
new file mode 100644
index 0000000..a8264cb
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_m3_v10.h"
+
+#define	RCAR_QOS_VERSION		"rev.0.19"
+
+#include "qos_init_m3_v10_mstat.h"
+
+struct rcar_gen3_dbsc_qos_settings m3_v10_qos[] = {
+	/* BUFCAM settings */
+	/* DBSC_DBCAM0CNF0 not set */
+	{ DBSC_DBCAM0CNF1, 0x00043218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBCAM0CNF3, 0x00000000 },
+	{ DBSC_DBSCHCNT0, 0x080F0037 },
+	/* DBSC_DBSCHCNT1 not set */
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00 },
+	{ DBSC_DBSCHQOS01, 0x00000B00 },
+	{ DBSC_DBSCHQOS02, 0x00000000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000300 },
+	{ DBSC_DBSCHQOS41, 0x000002F0 },
+	{ DBSC_DBSCHQOS42, 0x00000200 },
+	{ DBSC_DBSCHQOS43, 0x00000100 },
+	{ DBSC_DBSCHQOS90, 0x00000300 },
+	{ DBSC_DBSCHQOS91, 0x000002F0 },
+	{ DBSC_DBSCHQOS92, 0x00000200 },
+	{ DBSC_DBSCHQOS93, 0x00000100 },
+	{ DBSC_DBSCHQOS130, 0x00000100 },
+	{ DBSC_DBSCHQOS131, 0x000000F0 },
+	{ DBSC_DBSCHQOS132, 0x000000A0 },
+	{ DBSC_DBSCHQOS133, 0x00000040 },
+	{ DBSC_DBSCHQOS140, 0x000000C0 },
+	{ DBSC_DBSCHQOS141, 0x000000B0 },
+	{ DBSC_DBSCHQOS142, 0x00000080 },
+	{ DBSC_DBSCHQOS143, 0x00000040 },
+	{ DBSC_DBSCHQOS150, 0x00000040 },
+	{ DBSC_DBSCHQOS151, 0x00000030 },
+	{ DBSC_DBSCHQOS152, 0x00000020 },
+	{ DBSC_DBSCHQOS153, 0x00000010 },
+};
+
+void qos_init_m3_v10(void)
+{
+	rcar_qos_dbsc_setting(m3_v10_qos, ARRAY_SIZE(m3_v10_qos), false);
+
+	/* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RCAR_M3
+#error "Don't set DRAM Split 4ch(M3)"
+#else
+	ERROR("DRAM Split 4ch not supported.(M3)");
+	panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+      (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 2ch\n");
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1CU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x089A0000U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_RAS, 0x00000028U);
+	io_write_32(QOSCTRL_FIXTH, 0x000F0005U);
+	io_write_32(QOSCTRL_REGGD, 0x00000000U);
+	io_write_64(QOSCTRL_DANN, 0x0101010102020201UL);
+	io_write_32(QOSCTRL_DANT, 0x00100804U);
+	io_write_32(QOSCTRL_EC, 0x00000000U);
+	io_write_64(QOSCTRL_EMS, 0x0000000000000000UL);
+	io_write_32(QOSCTRL_FSS, 0x000003e8U);
+	io_write_32(QOSCTRL_INSFC, 0xC7840001U);
+	io_write_32(QOSCTRL_BERR, 0x00000000U);
+	io_write_32(QOSCTRL_RACNT0, 0x00000000U);
+
+	/* QOSBW setting */
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK);
+	io_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+
+	/* QOSBW SRAM setting */
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+
+	/* 3DG bus Leaf setting */
+	io_write_32(0xFD820808U, 0x00001234U);
+	io_write_32(0xFD820800U, 0x00000006U);
+	io_write_32(0xFD821800U, 0x00000006U);
+	io_write_32(0xFD822800U, 0x00000006U);
+	io_write_32(0xFD823800U, 0x00000006U);
+	io_write_32(0xFD824800U, 0x00000006U);
+	io_write_32(0xFD825800U, 0x00000006U);
+	io_write_32(0xFD826800U, 0x00000006U);
+	io_write_32(0xFD827800U, 0x00000006U);
+
+	/* RT bus Leaf setting */
+	io_write_32(0xFFC50800U, 0x00000000U);
+	io_write_32(0xFFC51800U, 0x00000000U);
+
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+	/* QOSBW start */
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_EC, 0x00000000U);
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h
new file mode 100644
index 0000000..01ef46c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_M3_V10_H
+#define QOS_INIT_M3_V10_H
+
+void qos_init_m3_v10(void);
+
+#endif /* QOS_INIT_M3_V10_H */
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h
new file mode 100644
index 0000000..b78b5f1
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+static const uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004030000FFFFUL,
+	/* 0x0038, */ 0x001004030000FFFFUL,
+	/* 0x0040, */ 0x001414090000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001410010000FFFFUL,
+	/* 0x0058, */ 0x00140C090000FFFFUL,
+	/* 0x0060, */ 0x00140C090000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001410010000FFFFUL,
+	/* 0x0078, */ 0x001004020000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001414090000FFFFUL,
+	/* 0x0090, */ 0x001408060000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x000C08020000FFFFUL,
+	/* 0x00A8, */ 0x000C04010000FFFFUL,
+	/* 0x00B0, */ 0x000C04010000FFFFUL,
+	/* 0x00B8, */ 0x0000000000000000UL,
+	/* 0x00C0, */ 0x000C08020000FFFFUL,
+	/* 0x00C8, */ 0x000C04010000FFFFUL,
+	/* 0x00D0, */ 0x000C04010000FFFFUL,
+	/* 0x00D8, */ 0x000C04030000FFFFUL,
+	/* 0x00E0, */ 0x000C100F0000FFFFUL,
+	/* 0x00E8, */ 0x0000000000000000UL,
+	/* 0x00F0, */ 0x001010080000FFFFUL,
+	/* 0x00F8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001010080000FFFFUL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100C0A0000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00100C0A0000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x00100C0A0000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008050000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001028280000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01A0, */ 0x00100C0A0000FFFFUL,
+	/* 0x01A8, */ 0x0000000000000000UL,
+	/* 0x01B0, */ 0x0000000000000000UL,
+	/* 0x01B8, */ 0x0000000000000000UL,
+	/* 0x01C0, */ 0x0000000000000000UL,
+	/* 0x01C8, */ 0x0000000000000000UL,
+	/* 0x01D0, */ 0x0000000000000000UL,
+	/* 0x01D8, */ 0x0000000000000000UL,
+	/* 0x01E0, */ 0x0000000000000000UL,
+	/* 0x01E8, */ 0x0000000000000000UL,
+	/* 0x01F0, */ 0x0000000000000000UL,
+	/* 0x01F8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02A0, */ 0x000C04010000FFFFUL,
+	/* 0x02A8, */ 0x000C04010000FFFFUL,
+	/* 0x02B0, */ 0x001404010000FFFFUL,
+	/* 0x02B8, */ 0x0000000000000000UL,
+	/* 0x02C0, */ 0x0000000000000000UL,
+	/* 0x02C8, */ 0x0000000000000000UL,
+	/* 0x02D0, */ 0x000C04010000FFFFUL,
+	/* 0x02D8, */ 0x000C04010000FFFFUL,
+	/* 0x02E0, */ 0x001404010000FFFFUL,
+	/* 0x02E8, */ 0x0000000000000000UL,
+	/* 0x02F0, */ 0x0000000000000000UL,
+	/* 0x02F8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static const uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200100C89C401UL,
+	/* 0x0008, */ 0x001200100C89C401UL,
+	/* 0x0010, */ 0x001200100C89C401UL,
+	/* 0x0018, */ 0x001200100C89C401UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001100100C803401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x0000000000000000UL,
+	/* 0x00A8, */ 0x0000000000000000UL,
+	/* 0x00B0, */ 0x0000000000000000UL,
+	/* 0x00B8, */ 0x0000000000000000UL,
+	/* 0x00C0, */ 0x0000000000000000UL,
+	/* 0x00C8, */ 0x0000000000000000UL,
+	/* 0x00D0, */ 0x0000000000000000UL,
+	/* 0x00D8, */ 0x0000000000000000UL,
+	/* 0x00E0, */ 0x0000000000000000UL,
+	/* 0x00E8, */ 0x0000000000000000UL,
+	/* 0x00F0, */ 0x0000000000000000UL,
+	/* 0x00F8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01A0, */ 0x0000000000000000UL,
+	/* 0x01A8, */ 0x0000000000000000UL,
+	/* 0x01B0, */ 0x0000000000000000UL,
+	/* 0x01B8, */ 0x0000000000000000UL,
+	/* 0x01C0, */ 0x001100500C8FFC01UL,
+	/* 0x01C8, */ 0x001100500C8FFC01UL,
+	/* 0x01D0, */ 0x001100500C8FFC01UL,
+	/* 0x01D8, */ 0x001100500C8FFC01UL,
+	/* 0x01E0, */ 0x0000000000000000UL,
+	/* 0x01E8, */ 0x001200100C803401UL,
+	/* 0x01F0, */ 0x001100100C80FC01UL,
+	/* 0x01F8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x001200100C80FC01UL,
+	/* 0x0210, */ 0x001100100C80FC01UL,
+	/* 0x0218, */ 0x001100100C825801UL,
+	/* 0x0220, */ 0x001100100C825801UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001100100C825801UL,
+	/* 0x0238, */ 0x001100100C825801UL,
+	/* 0x0240, */ 0x001200100C8BB801UL,
+	/* 0x0248, */ 0x001100100C8EA401UL,
+	/* 0x0250, */ 0x001200100C8BB801UL,
+	/* 0x0258, */ 0x001100100C8EA401UL,
+	/* 0x0260, */ 0x001100100C84E401UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x001100100C81F401UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02A0, */ 0x0000000000000000UL,
+	/* 0x02A8, */ 0x0000000000000000UL,
+	/* 0x02B0, */ 0x0000000000000000UL,
+	/* 0x02B8, */ 0x001100100C803401UL,
+	/* 0x02C0, */ 0x0000000000000000UL,
+	/* 0x02C8, */ 0x0000000000000000UL,
+	/* 0x02D0, */ 0x0000000000000000UL,
+	/* 0x02D8, */ 0x0000000000000000UL,
+	/* 0x02E0, */ 0x0000000000000000UL,
+	/* 0x02E8, */ 0x001100100C803401UL,
+	/* 0x02F0, */ 0x001100300C8FFC01UL,
+	/* 0x02F8, */ 0x001100500C8FFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001100300C8FFC01UL,
+	/* 0x0310, */ 0x001100500C8FFC01UL,
+	/* 0x0318, */ 0x001200100C803401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+#endif
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
new file mode 100644
index 0000000..22fd83a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_m3_v11.h"
+
+#define	RCAR_QOS_VERSION			"rev.0.19"
+
+#define QOSWT_TIME_BANK0			20000000U	/* unit:ns */
+
+#define	QOSWT_WTEN_ENABLE			0x1U
+
+#define QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_11	(SL_INIT_SSLOTCLK_M3_11 - 0x5U)
+
+#define OSWT_WTREF_SLOT0_EN_REQ1_SLOT		3U
+#define OSWT_WTREF_SLOT0_EN_REQ2_SLOT		9U
+#define QOSWT_WTREF_SLOT0_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+#define QOSWT_WTREF_SLOT1_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+
+#define QOSWT_WTSET0_REQ_SSLOT0			5U
+#define WT_BASE_SUB_SLOT_NUM0			12U
+#define QOSWT_WTSET0_PERIOD0_M3_11			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_11) - 1U)
+#define QOSWT_WTSET0_SSLOT0			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_M3_11			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_11) - 1U)
+#define QOSWT_WTSET1_SSLOT1			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET1_SLOTSLOT1			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_m3_v11_mstat195.h"
+#else
+#include "qos_init_m3_v11_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_m3_v11_qoswt195.h"
+#else
+#include "qos_init_m3_v11_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif
+
+struct rcar_gen3_dbsc_qos_settings m3_v11_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBCAM0CNF3, 0x00000000 },
+	{ DBSC_DBSCHCNT0, 0x000F0037 },
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00 },
+	{ DBSC_DBSCHQOS01, 0x00000B00 },
+	{ DBSC_DBSCHQOS02, 0x00000000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000300 },
+	{ DBSC_DBSCHQOS41, 0x000002F0 },
+	{ DBSC_DBSCHQOS42, 0x00000200 },
+	{ DBSC_DBSCHQOS43, 0x00000100 },
+	{ DBSC_DBSCHQOS90, 0x00000100 },
+	{ DBSC_DBSCHQOS91, 0x000000F0 },
+	{ DBSC_DBSCHQOS92, 0x000000A0 },
+	{ DBSC_DBSCHQOS93, 0x00000040 },
+	{ DBSC_DBSCHQOS120, 0x00000040 },
+	{ DBSC_DBSCHQOS121, 0x00000030 },
+	{ DBSC_DBSCHQOS122, 0x00000020 },
+	{ DBSC_DBSCHQOS123, 0x00000010 },
+	{ DBSC_DBSCHQOS130, 0x00000100 },
+	{ DBSC_DBSCHQOS131, 0x000000F0 },
+	{ DBSC_DBSCHQOS132, 0x000000A0 },
+	{ DBSC_DBSCHQOS133, 0x00000040 },
+	{ DBSC_DBSCHQOS140, 0x000000C0 },
+	{ DBSC_DBSCHQOS141, 0x000000B0 },
+	{ DBSC_DBSCHQOS142, 0x00000080 },
+	{ DBSC_DBSCHQOS143, 0x00000040 },
+	{ DBSC_DBSCHQOS150, 0x00000040 },
+	{ DBSC_DBSCHQOS151, 0x00000030 },
+	{ DBSC_DBSCHQOS152, 0x00000020 },
+	{ DBSC_DBSCHQOS153, 0x00000010 },
+};
+
+void qos_init_m3_v11(void)
+{
+	rcar_qos_dbsc_setting(m3_v11_qos, ARRAY_SIZE(m3_v11_qos), false);
+
+	/* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RCAR_M3
+#error "Don't set DRAM Split 4ch(M3)"
+#else
+	ERROR("DRAM Split 4ch not supported.(M3)");
+	panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+      (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 2ch\n");
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+		    | ADSPLCR0_SPLITSEL(0xFFU)
+		    | ADSPLCR0_AREA(0x1CU)
+		    | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00001004U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_RAS, 0x00000044U);
+	io_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x0020100AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_RACNT0, 0x02010003U);	/* GPU Boost Mode ON */
+
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+		    SL_INIT_SSLOTCLK_M3_11);
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	io_write_32(QOSCTRL_REF_ARS,
+		    ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_11 << 16)));
+#else
+	io_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+		io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]);
+		io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+		io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]);
+		io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]);
+	}
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	/* 3DG bus Leaf setting */
+	io_write_32(GPU_ACT_GRD, 0x00001234U);
+	io_write_32(GPU_ACT0, 0x00000000U);
+	io_write_32(GPU_ACT1, 0x00000000U);
+	io_write_32(GPU_ACT2, 0x00000000U);
+	io_write_32(GPU_ACT3, 0x00000000U);
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+	io_write_32(CPU_ACT2, 0x00000003U);
+	io_write_32(CPU_ACT3, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	/*  re-write training setting */
+	io_write_32(QOSWT_WTREF,
+		    ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+	io_write_32(QOSWT_WTSET0,
+		    ((QOSWT_WTSET0_PERIOD0_M3_11 << 16) |
+		     (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+	io_write_32(QOSWT_WTSET1,
+		    ((QOSWT_WTSET1_PERIOD1_M3_11 << 16) |
+		     (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+	io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h
new file mode 100644
index 0000000..1552fb6
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_M3_V11_H
+#define QOS_INIT_M3_V11_H
+
+void qos_init_m3_v11(void);
+
+#endif /* QOS_INIT_M3_V11_H */
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h
new file mode 100644
index 0000000..d7e7777
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000FFFFUL,
+	/* 0x0038, */ 0x001004040000FFFFUL,
+	/* 0x0040, */ 0x001414090000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x00140C0A0000FFFFUL,
+	/* 0x0060, */ 0x00140C0A0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x001004030000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001414090000FFFFUL,
+	/* 0x0090, */ 0x001408070000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C04020000FFFFUL,
+	/* 0x00a8, */ 0x000C04010000FFFFUL,
+	/* 0x00b0, */ 0x000C04010000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C04020000FFFFUL,
+	/* 0x00c8, */ 0x000C04010000FFFFUL,
+	/* 0x00d0, */ 0x000C04010000FFFFUL,
+	/* 0x00d8, */ 0x000C08050000FFFFUL,
+	/* 0x00e0, */ 0x000C14120000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001024090000FFFFUL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100C090000FFFFUL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100C0B0000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0010100D0000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x00100C0B0000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008060000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00102C2C0000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x00100C0B0000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFFFUL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C04010000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x001408010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x001408010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200200BDFFC01UL,
+	/* 0x0008, */ 0x001200200BDFFC01UL,
+	/* 0x0010, */ 0x001200200BDFFC01UL,
+	/* 0x0018, */ 0x001200200BDFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001200100BD03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100600BDFFC01UL,
+	/* 0x01c8, */ 0x002100600BDFFC01UL,
+	/* 0x01d0, */ 0x002100600BDFFC01UL,
+	/* 0x01d8, */ 0x002100600BDFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x002100200BDFFC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x002100200BDFFC01UL,
+	/* 0x0218, */ 0x001100200BDFFC01UL,
+	/* 0x0220, */ 0x001100200BDFFC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001100200BDFFC01UL,
+	/* 0x0238, */ 0x001100200BDFFC01UL,
+	/* 0x0240, */ 0x001200200BDFFC01UL,
+	/* 0x0248, */ 0x001100200BDFFC01UL,
+	/* 0x0250, */ 0x001200200BDFFC01UL,
+	/* 0x0258, */ 0x001100200BDFFC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x001100400BDFFC01UL,
+	/* 0x02f8, */ 0x001100600BDFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001100400BDFFC01UL,
+	/* 0x0310, */ 0x001100600BDFFC01UL,
+	/* 0x0318, */ 0x001200100BD03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h
new file mode 100644
index 0000000..a9520c3
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000FFFFUL,
+	/* 0x0038, */ 0x001008070000FFFFUL,
+	/* 0x0040, */ 0x001424120000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x001414130000FFFFUL,
+	/* 0x0060, */ 0x001414130000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x001008050000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001424120000FFFFUL,
+	/* 0x0090, */ 0x0014100D0000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08040000FFFFUL,
+	/* 0x00a8, */ 0x000C04020000FFFFUL,
+	/* 0x00b0, */ 0x000C04020000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08040000FFFFUL,
+	/* 0x00c8, */ 0x000C04020000FFFFUL,
+	/* 0x00d0, */ 0x000C04020000FFFFUL,
+	/* 0x00d8, */ 0x000C0C0A0000FFFFUL,
+	/* 0x00e0, */ 0x000C24230000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001044110000FFFFUL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001014110000FFFFUL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001018150000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00101C190000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x001018150000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x00100C0B0000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001058570000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x001018150000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFFFUL,
+	/* 0x0268, */ 0x001410010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C08020000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x00140C010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x00140C010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0012003005EFFC01UL,
+	/* 0x0008, */ 0x0012003005EFFC01UL,
+	/* 0x0010, */ 0x0012003005EFFC01UL,
+	/* 0x0018, */ 0x0012003005EFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005E03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100B005EFFC01UL,
+	/* 0x01c8, */ 0x002100B005EFFC01UL,
+	/* 0x01d0, */ 0x002100B005EFFC01UL,
+	/* 0x01d8, */ 0x002100B005EFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021003005EFFC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021003005EFFC01UL,
+	/* 0x0218, */ 0x0011003005EFFC01UL,
+	/* 0x0220, */ 0x0011003005EFFC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011003005EFFC01UL,
+	/* 0x0238, */ 0x0011003005EFFC01UL,
+	/* 0x0240, */ 0x0012003005EFFC01UL,
+	/* 0x0248, */ 0x0011003005EFFC01UL,
+	/* 0x0250, */ 0x0012003005EFFC01UL,
+	/* 0x0258, */ 0x0011003005EFFC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011007005EFFC01UL,
+	/* 0x02f8, */ 0x001100B005EFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0011007005EFFC01UL,
+	/* 0x0310, */ 0x001100B005EFFC01UL,
+	/* 0x0318, */ 0x0012001005E03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h
new file mode 100644
index 0000000..04c7efd
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000C010UL,
+	/* 0x0038, */ 0x001004040000C010UL,
+	/* 0x0040, */ 0x001414090000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00140C0A0000C010UL,
+	/* 0x0060, */ 0x00140C0A0000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x001004030000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001414090000FFF0UL,
+	/* 0x0090, */ 0x001408070000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFF0UL,
+	/* 0x0268, */ 0x001408010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C04010000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h
new file mode 100644
index 0000000..73f81f5
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000C010UL,
+	/* 0x0038, */ 0x001008070000C010UL,
+	/* 0x0040, */ 0x001424120000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x001414130000C010UL,
+	/* 0x0060, */ 0x001414130000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x001008050000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001424120000FFF0UL,
+	/* 0x0090, */ 0x0014100D0000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFF0UL,
+	/* 0x0268, */ 0x001410010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C08020000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
new file mode 100644
index 0000000..e300fd5
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_m3_v30.h"
+
+#define	RCAR_QOS_VERSION			"rev.0.03"
+
+#define QOSWT_TIME_BANK0			20000000U	/* unit:ns */
+
+#define	QOSWT_WTEN_ENABLE			0x1U
+
+#define QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_30	(SL_INIT_SSLOTCLK_M3_30 - 0x5U)
+
+#define OSWT_WTREF_SLOT0_EN_REQ1_SLOT		3U
+#define OSWT_WTREF_SLOT0_EN_REQ2_SLOT		9U
+#define QOSWT_WTREF_SLOT0_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+#define QOSWT_WTREF_SLOT1_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+
+#define QOSWT_WTSET0_REQ_SSLOT0			5U
+#define WT_BASE_SUB_SLOT_NUM0			12U
+#define QOSWT_WTSET0_PERIOD0_M3_30			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_30) - 1U)
+#define QOSWT_WTSET0_SSLOT0			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_M3_30			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_30) - 1U)
+#define QOSWT_WTSET1_SSLOT1			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET1_SLOTSLOT1			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_m3_v30_mstat195.h"
+#else
+#include "qos_init_m3_v30_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_m3_v30_qoswt195.h"
+#else
+#include "qos_init_m3_v30_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif
+
+struct rcar_gen3_dbsc_qos_settings m3_v30_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBCAM0CNF3, 0x00000000 },
+	{ DBSC_DBSCHCNT0, 0x000F0037 },
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00 },
+	{ DBSC_DBSCHQOS01, 0x00000B00 },
+	{ DBSC_DBSCHQOS02, 0x00000000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000300 },
+	{ DBSC_DBSCHQOS41, 0x000002F0 },
+	{ DBSC_DBSCHQOS42, 0x00000200 },
+	{ DBSC_DBSCHQOS43, 0x00000100 },
+	{ DBSC_DBSCHQOS90, 0x00000100 },
+	{ DBSC_DBSCHQOS91, 0x000000F0 },
+	{ DBSC_DBSCHQOS92, 0x000000A0 },
+	{ DBSC_DBSCHQOS93, 0x00000040 },
+	{ DBSC_DBSCHQOS120, 0x00000040 },
+	{ DBSC_DBSCHQOS121, 0x00000030 },
+	{ DBSC_DBSCHQOS122, 0x00000020 },
+	{ DBSC_DBSCHQOS123, 0x00000010 },
+	{ DBSC_DBSCHQOS130, 0x00000100 },
+	{ DBSC_DBSCHQOS131, 0x000000F0 },
+	{ DBSC_DBSCHQOS132, 0x000000A0 },
+	{ DBSC_DBSCHQOS133, 0x00000040 },
+	{ DBSC_DBSCHQOS140, 0x000000C0 },
+	{ DBSC_DBSCHQOS141, 0x000000B0 },
+	{ DBSC_DBSCHQOS142, 0x00000080 },
+	{ DBSC_DBSCHQOS143, 0x00000040 },
+	{ DBSC_DBSCHQOS150, 0x00000040 },
+	{ DBSC_DBSCHQOS151, 0x00000030 },
+	{ DBSC_DBSCHQOS152, 0x00000020 },
+	{ DBSC_DBSCHQOS153, 0x00000010 },
+};
+
+void qos_init_m3_v30(void)
+{
+	rcar_qos_dbsc_setting(m3_v30_qos, ARRAY_SIZE(m3_v30_qos), true);
+
+	/* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+ #if RCAR_LSI == RCAR_M3
+  #error "Don't set DRAM Split 4ch(M3)"
+ #else
+	ERROR("DRAM Split 4ch not supported.(M3)");
+	panic();
+ #endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \
+      (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO)
+	NOTICE("BL2: DRAM Split is 2ch\n");
+	io_write_32(AXI_ADSPLCR0, 0x00000000U);
+	io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT
+				  | ADSPLCR0_SPLITSEL(0xFFU)
+				  | ADSPLCR0_AREA(0x1DU)
+				  | ADSPLCR0_SWP);
+	io_write_32(AXI_ADSPLCR2, 0x00001004U);
+	io_write_32(AXI_ADSPLCR3, 0x00000000U);
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_RAS, 0x00000044U);
+	io_write_64(QOSCTRL_DANN, 0x0404020002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x0020100AU);
+	io_write_32(QOSCTRL_FSS, 0x0000000AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_EARLYR, 0x00000001U);
+	io_write_32(QOSCTRL_RACNT0, 0x02010003U);	/* GPU Boost Mode ON */
+
+	/* GPU Boost Mode */
+	io_write_32(QOSCTRL_STATGEN0, 0x00000001U);
+
+	io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_M3_30);
+	io_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_30 << 16)));
+
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+		io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]);
+		io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+		io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]);
+		io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]);
+	}
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+	io_write_32(CPU_ACT2, 0x00000003U);
+	io_write_32(CPU_ACT3, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN,  0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	/*  re-write training setting */
+	io_write_32(QOSWT_WTREF,  ((QOSWT_WTREF_SLOT1_EN << 16)       | QOSWT_WTREF_SLOT0_EN));
+	io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_M3_30 << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+	io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_M3_30 << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+	io_write_32(QOSWT_WTEN,   QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN,  0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h
new file mode 100644
index 0000000..a89d512
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H_M3_V30__
+#define QOS_INIT_H_M3_V30__
+
+void qos_init_m3_v30(void);
+
+#endif	/* QOS_INIT_H_M3_V30__ */
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h
new file mode 100644
index 0000000..cd820e8
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000FFFFUL,
+	/* 0x0038, */ 0x001004040000FFFFUL,
+	/* 0x0040, */ 0x001414090000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x00140C0A0000FFFFUL,
+	/* 0x0060, */ 0x00140C0A0000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x001004030000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001414090000FFFFUL,
+	/* 0x0090, */ 0x001408070000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C04020000FFFFUL,
+	/* 0x00a8, */ 0x000C04010000FFFFUL,
+	/* 0x00b0, */ 0x000C04010000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C04020000FFFFUL,
+	/* 0x00c8, */ 0x000C04010000FFFFUL,
+	/* 0x00d0, */ 0x000C04010000FFFFUL,
+	/* 0x00d8, */ 0x000C100D0000FFFFUL,
+	/* 0x00e0, */ 0x000C1C1B0000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001024090000FFFFUL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100C090000FFFFUL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x000C1C1B0000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100C0B0000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0010100D0000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x00100C0B0000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008060000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00102C2C0000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x00100C0B0000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFFFUL,
+	/* 0x0268, */ 0x001408010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C04010000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x001408010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x001408010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x001200200BDFFC01UL,
+	/* 0x0008, */ 0x001200200BDFFC01UL,
+	/* 0x0010, */ 0x001200200BDFFC01UL,
+	/* 0x0018, */ 0x001200200BDFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001200100BD03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100600BDFFC01UL,
+	/* 0x01c8, */ 0x002100600BDFFC01UL,
+	/* 0x01d0, */ 0x002100600BDFFC01UL,
+	/* 0x01d8, */ 0x002100600BDFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x002100200BDFFC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x002100200BDFFC01UL,
+	/* 0x0218, */ 0x001100200BDFFC01UL,
+	/* 0x0220, */ 0x001100200BDFFC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001100200BDFFC01UL,
+	/* 0x0238, */ 0x001100200BDFFC01UL,
+	/* 0x0240, */ 0x001200200BDFFC01UL,
+	/* 0x0248, */ 0x001100200BDFFC01UL,
+	/* 0x0250, */ 0x001200200BDFFC01UL,
+	/* 0x0258, */ 0x001100200BDFFC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x001100400BDFFC01UL,
+	/* 0x02f8, */ 0x001100600BDFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x001100400BDFFC01UL,
+	/* 0x0310, */ 0x001100600BDFFC01UL,
+	/* 0x0318, */ 0x001200100BD03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h
new file mode 100644
index 0000000..e9037e1
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000FFFFUL,
+	/* 0x0038, */ 0x001008070000FFFFUL,
+	/* 0x0040, */ 0x001424120000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404010000FFFFUL,
+	/* 0x0058, */ 0x001414130000FFFFUL,
+	/* 0x0060, */ 0x001414130000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404010000FFFFUL,
+	/* 0x0078, */ 0x001008050000FFFFUL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001424120000FFFFUL,
+	/* 0x0090, */ 0x0014100D0000FFFFUL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08040000FFFFUL,
+	/* 0x00a8, */ 0x000C04020000FFFFUL,
+	/* 0x00b0, */ 0x000C04020000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08040000FFFFUL,
+	/* 0x00c8, */ 0x000C04020000FFFFUL,
+	/* 0x00d0, */ 0x000C04020000FFFFUL,
+	/* 0x00d8, */ 0x000C1C1A0000FFFFUL,
+	/* 0x00e0, */ 0x000C38360000FFFFUL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001044110000FFFFUL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001014110000FFFFUL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x000C38360000FFFFUL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x001018150000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00101C190000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x001018150000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x00100C0B0000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001058570000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x001018150000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x000C04010000FFFFUL,
+	/* 0x01d8, */ 0x000C04010000FFFFUL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04010000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04010000FFFFUL,
+	/* 0x0210, */ 0x000C04010000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFFFUL,
+	/* 0x0268, */ 0x001410010000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C08020000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04010000FFFFUL,
+	/* 0x02a8, */ 0x000C04010000FFFFUL,
+	/* 0x02b0, */ 0x00140C010000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04010000FFFFUL,
+	/* 0x02d8, */ 0x000C04010000FFFFUL,
+	/* 0x02e0, */ 0x00140C010000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0012003005EFFC01UL,
+	/* 0x0008, */ 0x0012003005EFFC01UL,
+	/* 0x0010, */ 0x0012003005EFFC01UL,
+	/* 0x0018, */ 0x0012003005EFFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005E03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002100B005EFFC01UL,
+	/* 0x01c8, */ 0x002100B005EFFC01UL,
+	/* 0x01d0, */ 0x002100B005EFFC01UL,
+	/* 0x01d8, */ 0x002100B005EFFC01UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021003005EFFC01UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021003005EFFC01UL,
+	/* 0x0218, */ 0x0011003005EFFC01UL,
+	/* 0x0220, */ 0x0011003005EFFC01UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011003005EFFC01UL,
+	/* 0x0238, */ 0x0011003005EFFC01UL,
+	/* 0x0240, */ 0x0012003005EFFC01UL,
+	/* 0x0248, */ 0x0011003005EFFC01UL,
+	/* 0x0250, */ 0x0012003005EFFC01UL,
+	/* 0x0258, */ 0x0011003005EFFC01UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011007005EFFC01UL,
+	/* 0x02f8, */ 0x001100B005EFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0011007005EFFC01UL,
+	/* 0x0310, */ 0x001100B005EFFC01UL,
+	/* 0x0318, */ 0x0012001005E03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h
new file mode 100644
index 0000000..6761f5d
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004040000C010UL,
+	/* 0x0038, */ 0x001004040000C010UL,
+	/* 0x0040, */ 0x001414090000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00140C0A0000C010UL,
+	/* 0x0060, */ 0x00140C0A0000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x001004030000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001414090000FFF0UL,
+	/* 0x0090, */ 0x001408070000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08020000FFF0UL,
+	/* 0x0268, */ 0x001408010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C04010000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h
new file mode 100644
index 0000000..1deed59
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008070000C010UL,
+	/* 0x0038, */ 0x001008070000C010UL,
+	/* 0x0040, */ 0x001424120000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x001414130000C010UL,
+	/* 0x0060, */ 0x001414130000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x001008050000C010UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x001424120000FFF0UL,
+	/* 0x0090, */ 0x0014100D0000C010UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C030000FFF0UL,
+	/* 0x0268, */ 0x001410010000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C08020000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410010000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
new file mode 100644
index 0000000..446340b
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_m3n_v10.h"
+
+#define	RCAR_QOS_VERSION			"rev.0.09"
+
+#define REF_ARS_ARBSTOPCYCLE_M3N			\
+	(((SL_INIT_SSLOTCLK_M3N) - 5U) << 16U)
+
+#define QOSWT_TIME_BANK0			20000000U	/* unit:ns */
+
+#define	QOSWT_WTEN_ENABLE			0x1U
+
+#define OSWT_WTREF_SLOT0_EN_REQ1_SLOT		3U
+#define OSWT_WTREF_SLOT0_EN_REQ2_SLOT		9U
+#define QOSWT_WTREF_SLOT0_EN				\
+	((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) |	\
+	(0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT))
+#define QOSWT_WTREF_SLOT1_EN			QOSWT_WTREF_SLOT0_EN
+
+#define QOSWT_WTSET0_REQ_SSLOT0			5U
+#define WT_BASE_SUB_SLOT_NUM0			12U
+#define QOSWT_WTSET0_PERIOD0_M3N			\
+	((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3N) - 1U)
+#define QOSWT_WTSET0_SSLOT0			(QOSWT_WTSET0_REQ_SSLOT0 - 1U)
+#define QOSWT_WTSET0_SLOTSLOT0			(WT_BASE_SUB_SLOT_NUM0 - 1U)
+
+#define QOSWT_WTSET1_PERIOD1_M3N		QOSWT_WTSET0_PERIOD0_M3N
+#define QOSWT_WTSET1_SSLOT1			QOSWT_WTSET0_SSLOT0
+#define QOSWT_WTSET1_SLOTSLOT1			QOSWT_WTSET0_SLOTSLOT0
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_m3n_v10_mstat195.h"
+#else
+#include "qos_init_m3n_v10_mstat390.h"
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+#include "qos_init_m3n_v10_qoswt195.h"
+#else
+#include "qos_init_m3n_v10_qoswt390.h"
+#endif
+
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+#endif
+
+struct rcar_gen3_dbsc_qos_settings m3n_v10_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00043218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBSCHCNT0, 0x000F0037 },
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+
+	/* DDR3 */
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00, 0x00000F00 },
+	{ DBSC_DBSCHQOS01, 0x00000B00 },
+	{ DBSC_DBSCHQOS02, 0x00000000 },
+	{ DBSC_DBSCHQOS03, 0x00000000 },
+	{ DBSC_DBSCHQOS40, 0x00000300 },
+	{ DBSC_DBSCHQOS41, 0x000002F0 },
+	{ DBSC_DBSCHQOS42, 0x00000200 },
+	{ DBSC_DBSCHQOS43, 0x00000100 },
+	{ DBSC_DBSCHQOS90, 0x00000100 },
+	{ DBSC_DBSCHQOS91, 0x000000F0 },
+	{ DBSC_DBSCHQOS92, 0x000000A0 },
+	{ DBSC_DBSCHQOS93, 0x00000040 },
+	{ DBSC_DBSCHQOS130, 0x00000100 },
+	{ DBSC_DBSCHQOS131, 0x000000F0 },
+	{ DBSC_DBSCHQOS132, 0x000000A0 },
+	{ DBSC_DBSCHQOS133, 0x00000040 },
+	{ DBSC_DBSCHQOS140, 0x000000C0 },
+	{ DBSC_DBSCHQOS141, 0x000000B0 },
+	{ DBSC_DBSCHQOS142, 0x00000080 },
+	{ DBSC_DBSCHQOS143, 0x00000040 },
+	{ DBSC_DBSCHQOS150, 0x00000040 },
+	{ DBSC_DBSCHQOS151, 0x00000030 },
+	{ DBSC_DBSCHQOS152, 0x00000020 },
+	{ DBSC_DBSCHQOS153, 0x00000010 },
+};
+
+void qos_init_m3n_v10(void)
+{
+	rcar_qos_dbsc_setting(m3n_v10_qos, ARRAY_SIZE(m3n_v10_qos), true);
+
+	/* DRAM Split Address mapping */
+#if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH
+#if RCAR_LSI == RCAR_M3N
+#error "Don't set DRAM Split 4ch(M3N)"
+#else
+	ERROR("DRAM Split 4ch not supported.(M3N)");
+	panic();
+#endif
+#elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH)
+#if RCAR_LSI == RCAR_M3N
+#error "Don't set DRAM Split 2ch(M3N)"
+#else
+	ERROR("DRAM Split 2ch not supported.(M3N)");
+	panic();
+#endif
+#else
+	NOTICE("BL2: DRAM Split is OFF\n");
+#endif
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+#if RCAR_REF_INT == RCAR_REF_DEFAULT
+	NOTICE("BL2: DRAM refresh interval 1.95 usec\n");
+#else
+	NOTICE("BL2: DRAM refresh interval 3.9 usec\n");
+#endif
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	NOTICE("BL2: Periodic Write DQ Training\n");
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_RAS, 0x00000028U);
+	io_write_64(QOSCTRL_DANN, 0x0402000002020201UL);
+	io_write_32(QOSCTRL_DANT, 0x00100804U);
+	io_write_32(QOSCTRL_FSS, 0x0000000AU);
+	io_write_32(QOSCTRL_INSFC, 0x06330001U);
+	io_write_32(QOSCTRL_EARLYR, 0x00000001U);
+	io_write_32(QOSCTRL_RACNT0, 0x00010003U);
+
+	io_write_32(QOSCTRL_SL_INIT,
+		    SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT |
+		    SL_INIT_SSLOTCLK_M3N);
+	io_write_32(QOSCTRL_REF_ARS, REF_ARS_ARBSTOPCYCLE_M3N);
+
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) {
+		io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8,
+			    qoswt_fix[i]);
+		io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8,
+			    qoswt_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) {
+		io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]);
+		io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]);
+	}
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	/* RT bus Leaf setting */
+	io_write_32(RT_ACT0, 0x00000000U);
+	io_write_32(RT_ACT1, 0x00000000U);
+
+	/* CCI bus Leaf setting */
+	io_write_32(CPU_ACT0, 0x00000003U);
+	io_write_32(CPU_ACT1, 0x00000003U);
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+
+#if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE
+	/*  re-write training setting */
+	io_write_32(QOSWT_WTREF,
+		    ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN));
+	io_write_32(QOSWT_WTSET0,
+		    ((QOSWT_WTSET0_PERIOD0_M3N << 16) |
+		     (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0));
+	io_write_32(QOSWT_WTSET1,
+		    ((QOSWT_WTSET1_PERIOD1_M3N << 16) |
+		     (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1));
+
+	io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE);
+#endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */
+
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+#else
+	NOTICE("BL2: QoS is None\n");
+
+	io_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h
new file mode 100644
index 0000000..0cd0c85
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_M3N_V10_H
+#define QOS_INIT_M3N_V10_H
+
+void qos_init_m3n_v10(void);
+
+#endif /* QOS_INIT_M3N_V10_H */
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h
new file mode 100644
index 0000000..9b8b9e9
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004320000FFFFUL,
+	/* 0x0038, */ 0x001004320000FFFFUL,
+	/* 0x0040, */ 0x00140C5D0000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404040000FFFFUL,
+	/* 0x0058, */ 0x00140C940000FFFFUL,
+	/* 0x0060, */ 0x00140C940000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404040000FFFFUL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0014041F0000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C041D0000FFFFUL,
+	/* 0x00a8, */ 0x000C04090000FFFFUL,
+	/* 0x00b0, */ 0x000C040B0000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C041D0000FFFFUL,
+	/* 0x00c8, */ 0x000C04090000FFFFUL,
+	/* 0x00d0, */ 0x000C040B0000FFFFUL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001024840000FFFFUL,
+	/* 0x00f8, */ 0x000C084F0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100C840000FFFFUL,
+	/* 0x0118, */ 0x000C21E60000FFFFUL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x00100CA50000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x001010C90000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x00100CA50000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x001008530000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x00101D9D0000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x00100CA50000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04010000FFFFUL,
+	/* 0x01f0, */ 0x000C04050000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04050000FFFFUL,
+	/* 0x0210, */ 0x000C04050000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08150000FFFFUL,
+	/* 0x0268, */ 0x001408020000FFFFUL,
+	/* 0x0270, */ 0x001404010000FFFFUL,
+	/* 0x0278, */ 0x000C04090000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408020000FFFFUL,
+	/* 0x0298, */ 0x001404010000FFFFUL,
+	/* 0x02a0, */ 0x000C04050000FFFFUL,
+	/* 0x02a8, */ 0x000C04050000FFFFUL,
+	/* 0x02b0, */ 0x001408050000FFFFUL,
+	/* 0x02b8, */ 0x000C04010000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04050000FFFFUL,
+	/* 0x02d8, */ 0x000C04050000FFFFUL,
+	/* 0x02e0, */ 0x001408050000FFFFUL,
+	/* 0x02e8, */ 0x000C04010000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x000C04010000FFFFUL,
+	/* 0x0378, */ 0x000C04010000FFFFUL,
+	/* 0x0380, */ 0x000C04050000FFFFUL,
+	/* 0x0388, */ 0x000C04050000FFFFUL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x001200100BD03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x002106000BDFFC01UL,
+	/* 0x01c8, */ 0x002106000BDFFC01UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x002101000BDF2401UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x002101000BDF2401UL,
+	/* 0x0218, */ 0x001101000BDF2401UL,
+	/* 0x0220, */ 0x001101000BDF2401UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x001101000BDF2401UL,
+	/* 0x0238, */ 0x001101000BDF2401UL,
+	/* 0x0240, */ 0x001201000BDF2401UL,
+	/* 0x0248, */ 0x001101000BDF2401UL,
+	/* 0x0250, */ 0x001201000BDF2401UL,
+	/* 0x0258, */ 0x001101000BDF2401UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x001106000BDFFC01UL,
+	/* 0x02f8, */ 0x001106000BDFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x001200100BD03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x001206000BDFFC01UL,
+	/* 0x0360, */ 0x001206000BDFFC01UL,
+	/* 0x0368, */ 0x001200100BD03401UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x001200100BD03401UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h
new file mode 100644
index 0000000..19143ed
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008630000FFFFUL,
+	/* 0x0038, */ 0x001008630000FFFFUL,
+	/* 0x0040, */ 0x001418BA0000FFFFUL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x001404070000FFFFUL,
+	/* 0x0058, */ 0x001415270000FFFFUL,
+	/* 0x0060, */ 0x001415270000FFFFUL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x001404070000FFFFUL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0014083E0000FFFFUL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x000C08390000FFFFUL,
+	/* 0x00a8, */ 0x000C04110000FFFFUL,
+	/* 0x00b0, */ 0x000C04150000FFFFUL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x000C08390000FFFFUL,
+	/* 0x00c8, */ 0x000C04110000FFFFUL,
+	/* 0x00d0, */ 0x000C04150000FFFFUL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x001045080000FFFFUL,
+	/* 0x00f8, */ 0x000C0C9E0000FFFFUL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x001015080000FFFFUL,
+	/* 0x0118, */ 0x000C43CB0000FFFFUL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0010194A0000FFFFUL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x00101D910000FFFFUL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0010194A0000FFFFUL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x00100CA50000FFFFUL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x001037390000FFFFUL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0010194A0000FFFFUL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x000C04010000FFFFUL,
+	/* 0x01c8, */ 0x000C04010000FFFFUL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x000C04020000FFFFUL,
+	/* 0x01f0, */ 0x000C04090000FFFFUL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x000C04090000FFFFUL,
+	/* 0x0210, */ 0x000C04090000FFFFUL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C2A0000FFFFUL,
+	/* 0x0268, */ 0x001410040000FFFFUL,
+	/* 0x0270, */ 0x001404020000FFFFUL,
+	/* 0x0278, */ 0x000C08110000FFFFUL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410040000FFFFUL,
+	/* 0x0298, */ 0x001404020000FFFFUL,
+	/* 0x02a0, */ 0x000C04090000FFFFUL,
+	/* 0x02a8, */ 0x000C04090000FFFFUL,
+	/* 0x02b0, */ 0x00140C090000FFFFUL,
+	/* 0x02b8, */ 0x000C04020000FFFFUL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x000C04090000FFFFUL,
+	/* 0x02d8, */ 0x000C04090000FFFFUL,
+	/* 0x02e0, */ 0x00140C090000FFFFUL,
+	/* 0x02e8, */ 0x000C04020000FFFFUL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x000C04020000FFFFUL,
+	/* 0x0378, */ 0x000C04020000FFFFUL,
+	/* 0x0380, */ 0x000C04090000FFFFUL,
+	/* 0x0388, */ 0x000C04090000FFFFUL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0012001005E03401UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0021060005EFFC01UL,
+	/* 0x01c8, */ 0x0021060005EFFC01UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0021010005E79401UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0021010005E79401UL,
+	/* 0x0218, */ 0x0011010005E79401UL,
+	/* 0x0220, */ 0x0011010005E79401UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0011010005E79401UL,
+	/* 0x0238, */ 0x0011010005E79401UL,
+	/* 0x0240, */ 0x0012010005E79401UL,
+	/* 0x0248, */ 0x0011010005E79401UL,
+	/* 0x0250, */ 0x0012010005E79401UL,
+	/* 0x0258, */ 0x0011010005E79401UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0011060005EFFC01UL,
+	/* 0x02f8, */ 0x0011060005EFFC01UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0012001005E03401UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0012060005EFFC01UL,
+	/* 0x0360, */ 0x0012060005EFFC01UL,
+	/* 0x0368, */ 0x0012001005E03401UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0012001005E03401UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h
new file mode 100644
index 0000000..d2e8040
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001004320000C010UL,
+	/* 0x0038, */ 0x001004320000C010UL,
+	/* 0x0040, */ 0x00140C5D0000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x00140C940000C010UL,
+	/* 0x0060, */ 0x00140C940000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0014041F0000FFF0UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C08150000FFF0UL,
+	/* 0x0268, */ 0x001408020000FFF0UL,
+	/* 0x0270, */ 0x001404010000FFF0UL,
+	/* 0x0278, */ 0x000C04090000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001408020000FFF0UL,
+	/* 0x0298, */ 0x001404010000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h
new file mode 100644
index 0000000..84f657a
--- /dev/null
+++ b/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint64_t qoswt_fix[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x001008630000C010UL,
+	/* 0x0038, */ 0x001008630000C010UL,
+	/* 0x0040, */ 0x001418BA0000FFF0UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x001415270000C010UL,
+	/* 0x0060, */ 0x001415270000C010UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0014083E0000FFF0UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x000C0C2A0000FFF0UL,
+	/* 0x0268, */ 0x001410040000FFF0UL,
+	/* 0x0270, */ 0x001404020000FFF0UL,
+	/* 0x0278, */ 0x000C08110000FFF0UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x001410040000FFF0UL,
+	/* 0x0298, */ 0x001404020000FFF0UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
+
+static uint64_t qoswt_be[] = {
+	/* 0x0000, */ 0x0000000000000000UL,
+	/* 0x0008, */ 0x0000000000000000UL,
+	/* 0x0010, */ 0x0000000000000000UL,
+	/* 0x0018, */ 0x0000000000000000UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00a0, */ 0x0000000000000000UL,
+	/* 0x00a8, */ 0x0000000000000000UL,
+	/* 0x00b0, */ 0x0000000000000000UL,
+	/* 0x00b8, */ 0x0000000000000000UL,
+	/* 0x00c0, */ 0x0000000000000000UL,
+	/* 0x00c8, */ 0x0000000000000000UL,
+	/* 0x00d0, */ 0x0000000000000000UL,
+	/* 0x00d8, */ 0x0000000000000000UL,
+	/* 0x00e0, */ 0x0000000000000000UL,
+	/* 0x00e8, */ 0x0000000000000000UL,
+	/* 0x00f0, */ 0x0000000000000000UL,
+	/* 0x00f8, */ 0x0000000000000000UL,
+	/* 0x0100, */ 0x0000000000000000UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x0000000000000000UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x0000000000000000UL,
+	/* 0x0128, */ 0x0000000000000000UL,
+	/* 0x0130, */ 0x0000000000000000UL,
+	/* 0x0138, */ 0x0000000000000000UL,
+	/* 0x0140, */ 0x0000000000000000UL,
+	/* 0x0148, */ 0x0000000000000000UL,
+	/* 0x0150, */ 0x0000000000000000UL,
+	/* 0x0158, */ 0x0000000000000000UL,
+	/* 0x0160, */ 0x0000000000000000UL,
+	/* 0x0168, */ 0x0000000000000000UL,
+	/* 0x0170, */ 0x0000000000000000UL,
+	/* 0x0178, */ 0x0000000000000000UL,
+	/* 0x0180, */ 0x0000000000000000UL,
+	/* 0x0188, */ 0x0000000000000000UL,
+	/* 0x0190, */ 0x0000000000000000UL,
+	/* 0x0198, */ 0x0000000000000000UL,
+	/* 0x01a0, */ 0x0000000000000000UL,
+	/* 0x01a8, */ 0x0000000000000000UL,
+	/* 0x01b0, */ 0x0000000000000000UL,
+	/* 0x01b8, */ 0x0000000000000000UL,
+	/* 0x01c0, */ 0x0000000000000000UL,
+	/* 0x01c8, */ 0x0000000000000000UL,
+	/* 0x01d0, */ 0x0000000000000000UL,
+	/* 0x01d8, */ 0x0000000000000000UL,
+	/* 0x01e0, */ 0x0000000000000000UL,
+	/* 0x01e8, */ 0x0000000000000000UL,
+	/* 0x01f0, */ 0x0000000000000000UL,
+	/* 0x01f8, */ 0x0000000000000000UL,
+	/* 0x0200, */ 0x0000000000000000UL,
+	/* 0x0208, */ 0x0000000000000000UL,
+	/* 0x0210, */ 0x0000000000000000UL,
+	/* 0x0218, */ 0x0000000000000000UL,
+	/* 0x0220, */ 0x0000000000000000UL,
+	/* 0x0228, */ 0x0000000000000000UL,
+	/* 0x0230, */ 0x0000000000000000UL,
+	/* 0x0238, */ 0x0000000000000000UL,
+	/* 0x0240, */ 0x0000000000000000UL,
+	/* 0x0248, */ 0x0000000000000000UL,
+	/* 0x0250, */ 0x0000000000000000UL,
+	/* 0x0258, */ 0x0000000000000000UL,
+	/* 0x0260, */ 0x0000000000000000UL,
+	/* 0x0268, */ 0x0000000000000000UL,
+	/* 0x0270, */ 0x0000000000000000UL,
+	/* 0x0278, */ 0x0000000000000000UL,
+	/* 0x0280, */ 0x0000000000000000UL,
+	/* 0x0288, */ 0x0000000000000000UL,
+	/* 0x0290, */ 0x0000000000000000UL,
+	/* 0x0298, */ 0x0000000000000000UL,
+	/* 0x02a0, */ 0x0000000000000000UL,
+	/* 0x02a8, */ 0x0000000000000000UL,
+	/* 0x02b0, */ 0x0000000000000000UL,
+	/* 0x02b8, */ 0x0000000000000000UL,
+	/* 0x02c0, */ 0x0000000000000000UL,
+	/* 0x02c8, */ 0x0000000000000000UL,
+	/* 0x02d0, */ 0x0000000000000000UL,
+	/* 0x02d8, */ 0x0000000000000000UL,
+	/* 0x02e0, */ 0x0000000000000000UL,
+	/* 0x02e8, */ 0x0000000000000000UL,
+	/* 0x02f0, */ 0x0000000000000000UL,
+	/* 0x02f8, */ 0x0000000000000000UL,
+	/* 0x0300, */ 0x0000000000000000UL,
+	/* 0x0308, */ 0x0000000000000000UL,
+	/* 0x0310, */ 0x0000000000000000UL,
+	/* 0x0318, */ 0x0000000000000000UL,
+	/* 0x0320, */ 0x0000000000000000UL,
+	/* 0x0328, */ 0x0000000000000000UL,
+	/* 0x0330, */ 0x0000000000000000UL,
+	/* 0x0338, */ 0x0000000000000000UL,
+	/* 0x0340, */ 0x0000000000000000UL,
+	/* 0x0348, */ 0x0000000000000000UL,
+	/* 0x0350, */ 0x0000000000000000UL,
+	/* 0x0358, */ 0x0000000000000000UL,
+	/* 0x0360, */ 0x0000000000000000UL,
+	/* 0x0368, */ 0x0000000000000000UL,
+	/* 0x0370, */ 0x0000000000000000UL,
+	/* 0x0378, */ 0x0000000000000000UL,
+	/* 0x0380, */ 0x0000000000000000UL,
+	/* 0x0388, */ 0x0000000000000000UL,
+	/* 0x0390, */ 0x0000000000000000UL,
+};
diff --git a/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
new file mode 100644
index 0000000..076876c
--- /dev/null
+++ b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "../qos_common.h"
+#include "../qos_reg.h"
+#include "qos_init_v3m.h"
+
+#define	RCAR_QOS_VERSION		"rev.0.01"
+
+#include "qos_init_v3m_mstat.h"
+
+struct rcar_gen3_dbsc_qos_settings v3m_qos[] = {
+	/* BUFCAM settings */
+	{ DBSC_DBCAM0CNF1, 0x00044218 },
+	{ DBSC_DBCAM0CNF2, 0x000000F4 },
+	{ DBSC_DBSCHCNT0, 0x080F003F },
+	{ DBSC_DBSCHCNT1, 0x00001010 },
+
+	{ DBSC_DBSCHSZ0, 0x00000001 },
+	{ DBSC_DBSCHRW0, 0x22421111 },
+	{ DBSC_DBSCHRW1, 0x00180034 },
+	{ DBSC_SCFCTST0, 0x180B1708 },
+	{ DBSC_SCFCTST1, 0x0808070C },
+	{ DBSC_SCFCTST2, 0x012F1123 },
+
+	/* QoS Settings */
+	{ DBSC_DBSCHQOS00,  0x0000F000 },
+	{ DBSC_DBSCHQOS01,  0x0000E000 },
+	{ DBSC_DBSCHQOS02,  0x00007000 },
+	{ DBSC_DBSCHQOS03,  0x00000000 },
+	{ DBSC_DBSCHQOS40,  0x0000F000 },
+	{ DBSC_DBSCHQOS41,  0x0000EFFF },
+	{ DBSC_DBSCHQOS42,  0x0000B000 },
+	{ DBSC_DBSCHQOS43,  0x00000000 },
+	{ DBSC_DBSCHQOS90,  0x0000F000 },
+	{ DBSC_DBSCHQOS91,  0x0000EFFF },
+	{ DBSC_DBSCHQOS92,  0x0000D000 },
+	{ DBSC_DBSCHQOS93,  0x00000000 },
+	{ DBSC_DBSCHQOS130, 0x0000F000 },
+	{ DBSC_DBSCHQOS131, 0x0000EFFF },
+	{ DBSC_DBSCHQOS132, 0x0000E800 },
+	{ DBSC_DBSCHQOS133, 0x00007000 },
+	{ DBSC_DBSCHQOS140, 0x0000F000 },
+	{ DBSC_DBSCHQOS141, 0x0000EFFF },
+	{ DBSC_DBSCHQOS142, 0x0000E800 },
+	{ DBSC_DBSCHQOS143, 0x0000B000 },
+	{ DBSC_DBSCHQOS150, 0x000007D0 },
+	{ DBSC_DBSCHQOS151, 0x000007CF },
+	{ DBSC_DBSCHQOS152, 0x000005D0 },
+	{ DBSC_DBSCHQOS153, 0x000003D0 },
+};
+
+void qos_init_v3m(void)
+{
+return;
+
+	rcar_qos_dbsc_setting(v3m_qos, ARRAY_SIZE(v3m_qos), false);
+
+#if !(RCAR_QOS_TYPE == RCAR_QOS_NONE)
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+	NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION);
+#endif
+
+	/* Resource Alloc setting */
+	io_write_32(QOSCTRL_RAS,   0x00000020U);
+	io_write_32(QOSCTRL_FIXTH, 0x000F0005U);
+	io_write_32(QOSCTRL_REGGD, 0x00000004U);
+	io_write_64(QOSCTRL_DANN,  0x0202020104040200U);
+	io_write_32(QOSCTRL_DANT,  0x00201008U);
+	io_write_32(QOSCTRL_EC,    0x00080001U);	/* need for H3 ES1 */
+	io_write_64(QOSCTRL_EMS,   0x0000000000000000U);
+	io_write_32(QOSCTRL_INSFC, 0x63C20001U);
+	io_write_32(QOSCTRL_BERR,  0x00000000U);
+
+	/* QOSBW setting */
+	io_write_32(QOSCTRL_SL_INIT, 0x0305007DU);
+	io_write_32(QOSCTRL_REF_ARS, 0x00330000U);
+
+	/* QOSBW SRAM setting */
+	uint32_t i;
+
+	for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) {
+		io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]);
+		io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]);
+	}
+	for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) {
+		io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]);
+		io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]);
+	}
+
+	/* AXI-IF arbitration setting */
+	io_write_32(DBSC_AXARB, 0x18010000U);
+
+	/* Resource Alloc start */
+	io_write_32(QOSCTRL_RAEN,  0x00000001U);
+
+	/* QOSBW start */
+	io_write_32(QOSCTRL_STATQC, 0x00000001U);
+
+#else
+	NOTICE("BL2: QoS is None\n");
+#endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */
+}
diff --git a/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h
new file mode 100644
index 0000000..2c4278b
--- /dev/null
+++ b/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H_V3M__
+#define QOS_INIT_H_V3M__
+
+void qos_init_v3m(void);
+
+#endif	/* QOS_INIT_H_V3M__ */
diff --git a/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h b/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h
new file mode 100644
index 0000000..d0b7fc3
--- /dev/null
+++ b/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if RCAR_QOS_TYPE  == RCAR_QOS_TYPE_DEFAULT
+static const uint64_t mstat_fix[] = {
+	/* 0x0000, */ 0x000000000000FFFFUL,
+	/* 0x0008, */ 0x000000000000FFFFUL,
+	/* 0x0010, */ 0x000000000000FFFFUL,
+	/* 0x0018, */ 0x000000000000FFFFUL,
+	/* 0x0020, */ 0x001414090000FFFFUL,
+	/* 0x0028, */ 0x000C00000000FFFFUL,
+	/* 0x0030, */ 0x001008040000FFFFUL,
+	/* 0x0038, */ 0x001004040000FFFFUL,
+	/* 0x0040, */ 0x001004040000FFFFUL,
+	/* 0x0048, */ 0x000000000000FFFFUL,
+	/* 0x0050, */ 0x001004040000FFFFUL,
+	/* 0x0058, */ 0x001004040000FFFFUL,
+	/* 0x0060, */ 0x000000000000FFFFUL,
+	/* 0x0068, */ 0x001404040000FFFFUL,
+	/* 0x0070, */ 0x001008030000FFFFUL,
+	/* 0x0078, */ 0x001004030000FFFFUL,
+	/* 0x0080, */ 0x001004030000FFFFUL,
+	/* 0x0088, */ 0x000000000000FFFFUL,
+	/* 0x0090, */ 0x001004040000FFFFUL,
+	/* 0x0098, */ 0x001004040000FFFFUL,
+	/* 0x00A0, */ 0x000000000000FFFFUL,
+	/* 0x00A8, */ 0x000000000000FFFFUL,
+	/* 0x00B0, */ 0x000000000000FFFFUL,
+	/* 0x00B8, */ 0x000000000000FFFFUL,
+	/* 0x00C0, */ 0x000000000000FFFFUL,
+	/* 0x00C8, */ 0x000000000000FFFFUL,
+	/* 0x00D0, */ 0x000000000000FFFFUL,
+	/* 0x00D8, */ 0x000000000000FFFFUL,
+	/* 0x00E0, */ 0x001404020000FFFFUL,
+	/* 0x00E8, */ 0x000000000000FFFFUL,
+	/* 0x00F0, */ 0x000000000000FFFFUL,
+	/* 0x00F8, */ 0x000000000000FFFFUL,
+	/* 0x0100, */ 0x000000000000FFFFUL,
+	/* 0x0108, */ 0x000C04020000FFFFUL,
+	/* 0x0110, */ 0x000000000000FFFFUL,
+	/* 0x0118, */ 0x001404020000FFFFUL,
+	/* 0x0120, */ 0x000000000000FFFFUL,
+	/* 0x0128, */ 0x000000000000FFFFUL,
+	/* 0x0130, */ 0x000000000000FFFFUL,
+	/* 0x0138, */ 0x000000000000FFFFUL,
+	/* 0x0140, */ 0x000000000000FFFFUL,
+	/* 0x0148, */ 0x000000000000FFFFUL,
+};
+
+static const uint64_t mstat_be[] = {
+	/* 0x0000, */ 0x00100020447FFC01UL,
+	/* 0x0008, */ 0x00100020447FFC01UL,
+	/* 0x0010, */ 0x00100040447FFC01UL,
+	/* 0x0018, */ 0x00100040447FFC01UL,
+	/* 0x0020, */ 0x0000000000000000UL,
+	/* 0x0028, */ 0x0000000000000000UL,
+	/* 0x0030, */ 0x0000000000000000UL,
+	/* 0x0038, */ 0x0000000000000000UL,
+	/* 0x0040, */ 0x0000000000000000UL,
+	/* 0x0048, */ 0x0000000000000000UL,
+	/* 0x0050, */ 0x0000000000000000UL,
+	/* 0x0058, */ 0x0000000000000000UL,
+	/* 0x0060, */ 0x0000000000000000UL,
+	/* 0x0068, */ 0x0000000000000000UL,
+	/* 0x0070, */ 0x0000000000000000UL,
+	/* 0x0078, */ 0x0000000000000000UL,
+	/* 0x0080, */ 0x0000000000000000UL,
+	/* 0x0088, */ 0x0000000000000000UL,
+	/* 0x0090, */ 0x0000000000000000UL,
+	/* 0x0098, */ 0x0000000000000000UL,
+	/* 0x00A0, */ 0x00100010447FFC01UL,
+	/* 0x00A8, */ 0x00100010447FFC01UL,
+	/* 0x00B0, */ 0x00100010447FFC01UL,
+	/* 0x00B8, */ 0x00100010447FFC01UL,
+	/* 0x00C0, */ 0x00100010447FFC01UL,
+	/* 0x00C8, */ 0x00100010447FFC01UL,
+	/* 0x00D0, */ 0x0000000000000000UL,
+	/* 0x00D8, */ 0x00100010447FFC01UL,
+	/* 0x00E0, */ 0x0000000000000000UL,
+	/* 0x00E8, */ 0x00100010447FFC01UL,
+	/* 0x00F0, */ 0x00100010447FFC01UL,
+	/* 0x00F8, */ 0x00100010447FFC01UL,
+	/* 0x0100, */ 0x00100010447FFC01UL,
+	/* 0x0108, */ 0x0000000000000000UL,
+	/* 0x0110, */ 0x00100010447FFC01UL,
+	/* 0x0118, */ 0x0000000000000000UL,
+	/* 0x0120, */ 0x00100010447FFC01UL,
+	/* 0x0128, */ 0x00100010447FFC01UL,
+	/* 0x0130, */ 0x00100010447FFC01UL,
+	/* 0x0138, */ 0x00100010447FFC01UL,
+	/* 0x0140, */ 0x00100020447FFC01UL,
+	/* 0x0148, */ 0x00100020447FFC01UL,
+};
+#endif
diff --git a/drivers/renesas/rcar/qos/qos.mk b/drivers/renesas/rcar/qos/qos.mk
new file mode 100644
index 0000000..da10da2
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos.mk
@@ -0,0 +1,106 @@
+#
+# Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${RCAR_LSI},${RCAR_AUTO})
+#   E3, H3N not available for LSI_AUTO
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
+else ifdef RCAR_LSI_CUT_COMPAT
+  ifeq (${RCAR_LSI},${RCAR_H3})
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_H3N})
+    BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3})
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3N})
+    BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_V3M})
+    BL2_SOURCES += drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_E3})
+    BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_D3})
+    BL2_SOURCES += drivers/renesas/rcar/qos/D3/qos_init_d3.c
+  endif
+else
+  ifeq (${RCAR_LSI},${RCAR_H3})
+    ifeq (${LSI_CUT},10)
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c
+    else ifeq (${LSI_CUT},11)
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c
+    else ifeq (${LSI_CUT},20)
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c
+    else ifeq (${LSI_CUT},30)
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
+    else
+#     LSI_CUT 30 or later
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c
+    endif
+  endif
+  ifeq (${RCAR_LSI},${RCAR_H3N})
+    ifeq (${LSI_CUT},30)
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
+    else
+#     LSI_CUT 30 or later
+      BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c
+    endif
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3})
+    ifeq (${LSI_CUT},10)
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c
+    else ifeq (${LSI_CUT},11)
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
+    else ifeq (${LSI_CUT},13)
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c
+    else ifeq (${LSI_CUT},30)
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
+    else
+#    LSI_CUT 30 or later
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c
+    endif
+  endif
+  ifeq (${RCAR_LSI},${RCAR_M3N})
+    ifeq (${LSI_CUT},10)
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
+    else
+#    LSI_CUT 10 or later
+     BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c
+    endif
+  endif
+  ifeq (${RCAR_LSI},${RCAR_V3M})
+    BL2_SOURCES += drivers/renesas/rcar/qos/V3M/qos_init_v3m.c
+  endif
+  ifeq (${RCAR_LSI},${RCAR_E3})
+    ifeq (${LSI_CUT},10)
+     BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
+    else
+#    LSI_CUT 10 or later
+     BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c
+    endif
+  endif
+  ifeq (${RCAR_LSI},${RCAR_D3})
+    BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_d3.c
+  endif
+endif
+
+BL2_SOURCES += drivers/renesas/rcar/qos/qos_init.c
diff --git a/drivers/renesas/rcar/qos/qos_common.h b/drivers/renesas/rcar/qos/qos_common.h
new file mode 100644
index 0000000..2c130ae
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_common.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_COMMON_H
+#define QOS_COMMON_H
+
+#define RCAR_REF_DEFAULT		0U
+
+/* define used for get_refperiod. */
+/* REFPERIOD_CYCLE need smaller than QOSWT_WTSET0_CYCLEs */
+/* refere to plat/renesas/rcar/ddr/ddr_a/ddr_init_e3.h for E3. */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT)	/* REF default */
+#define REFPERIOD_CYCLE		/* unit:ns */	\
+	((126 * BASE_SUB_SLOT_NUM * 1000U) / 400)
+#else					/* REF option */
+#define REFPERIOD_CYCLE		/* unit:ns */	\
+	((252 * BASE_SUB_SLOT_NUM * 1000U) / 400)
+#endif
+
+#if (RCAR_LSI == RCAR_E3)
+/* define used for E3 */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT)	/* REF 3.9usec */
+#define SUB_SLOT_CYCLE_E3		0xAFU	/* 175 */
+#else /* REF 7.8usec */
+#define SUB_SLOT_CYCLE_E3		0x15EU	/* 350 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define OPERATING_FREQ_E3		266U	/* MHz */
+#define SL_INIT_SSLOTCLK_E3		(SUB_SLOT_CYCLE_E3 - 1U)
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N)
+/* define used for M3N */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT)	/* REF 1.95usec */
+#define SUB_SLOT_CYCLE_M3N		0x7EU	/* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_M3N		0xFCU	/* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_M3N		(SUB_SLOT_CYCLE_M3N - 1U)
+#define QOSWT_WTSET0_CYCLE_M3N		/* unit:ns */	\
+	((SUB_SLOT_CYCLE_M3N * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3)
+/* define used for H3 */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT)	/* REF 1.95usec */
+#define SUB_SLOT_CYCLE_H3_20		0x7EU	/* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_H3_20		0xFCU	/* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_H3_20		(SUB_SLOT_CYCLE_H3_20 - 1U)
+#define QOSWT_WTSET0_CYCLE_H3_20	/* unit:ns */	\
+	((SUB_SLOT_CYCLE_H3_20 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+
+/* define used for H3 Cut 30 */
+#define SUB_SLOT_CYCLE_H3_30		(SUB_SLOT_CYCLE_H3_20)	/* same as H3 Cut 20 */
+#define SL_INIT_SSLOTCLK_H3_30		(SUB_SLOT_CYCLE_H3_30 - 1U)
+#define QOSWT_WTSET0_CYCLE_H3_30	/* unit:ns */	\
+	((SUB_SLOT_CYCLE_H3_30 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+
+#endif
+
+#if (RCAR_LSI == RCAR_H3N)
+/* define used for H3N */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT)	/* REF 1.95usec */
+#define SUB_SLOT_CYCLE_H3N		0x7EU	/* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_H3N		0xFCU	/* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_H3N		(SUB_SLOT_CYCLE_H3N - 1U)
+#define QOSWT_WTSET0_CYCLE_H3N		/* unit:ns */	\
+	((SUB_SLOT_CYCLE_H3N * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3)
+/* define used for M3 */
+#if (RCAR_REF_INT == RCAR_REF_DEFAULT)	/* REF 1.95usec */
+#define SUB_SLOT_CYCLE_M3_11		0x7EU	/* 126 */
+#define SUB_SLOT_CYCLE_M3_30		0x7EU	/* 126 */
+#else /* REF 3.9usec */
+#define SUB_SLOT_CYCLE_M3_11		0xFCU	/* 252 */
+#define SUB_SLOT_CYCLE_M3_30		0xFCU	/* 252 */
+#endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */
+
+#define SL_INIT_SSLOTCLK_M3_11		(SUB_SLOT_CYCLE_M3_11 - 1U)
+#define SL_INIT_SSLOTCLK_M3_30		(SUB_SLOT_CYCLE_M3_30 - 1U)
+#define QOSWT_WTSET0_CYCLE_M3_11	/* unit:ns */	\
+	((SUB_SLOT_CYCLE_M3_11 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#define QOSWT_WTSET0_CYCLE_M3_30	/* unit:ns */	\
+	((SUB_SLOT_CYCLE_M3_30 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+#endif
+
+#define OPERATING_FREQ			400U	/* MHz */
+#define BASE_SUB_SLOT_NUM		0x6U
+#define SUB_SLOT_CYCLE			0x7EU	/* 126 */
+
+#define QOSWT_WTSET0_CYCLE		/* unit:ns */	\
+	((SUB_SLOT_CYCLE * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ)
+
+#define SL_INIT_REFFSSLOT		(0x3U << 24U)
+#define SL_INIT_SLOTSSLOT		((BASE_SUB_SLOT_NUM - 1U) << 16U)
+#define SL_INIT_SSLOTCLK		(SUB_SLOT_CYCLE - 1U)
+
+static inline void io_write_32(uintptr_t addr, uint32_t value)
+{
+	*(volatile uint32_t *)addr = value;
+}
+
+static inline uint32_t io_read_32(uintptr_t addr)
+{
+	return *(volatile uint32_t *)addr;
+}
+
+static inline void io_write_64(uintptr_t addr, uint64_t value)
+{
+	*(volatile uint64_t *)addr = value;
+}
+
+typedef struct {
+	uintptr_t addr;
+	uint64_t value;
+} mstat_slot_t;
+
+struct rcar_gen3_dbsc_qos_settings {
+	uint32_t	reg;
+	uint32_t	val;
+};
+
+extern uint32_t qos_init_ddr_ch;
+extern uint8_t qos_init_ddr_phyvalid;
+
+void rcar_qos_dbsc_setting(struct rcar_gen3_dbsc_qos_settings *qos,
+			   unsigned int qos_size, bool dbsc_wren);
+
+#endif /* QOS_COMMON_H */
diff --git a/drivers/renesas/rcar/qos/qos_init.c b/drivers/renesas/rcar/qos/qos_init.c
new file mode 100644
index 0000000..884e031
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_init.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "qos_init.h"
+#include "qos_common.h"
+#include "qos_reg.h"
+#if RCAR_LSI == RCAR_AUTO
+#include "H3/qos_init_h3_v10.h"
+#include "H3/qos_init_h3_v11.h"
+#include "H3/qos_init_h3_v20.h"
+#include "H3/qos_init_h3_v30.h"
+#include "M3/qos_init_m3_v10.h"
+#include "M3/qos_init_m3_v11.h"
+#include "M3/qos_init_m3_v30.h"
+#include "M3N/qos_init_m3n_v10.h"
+#include "V3M/qos_init_v3m.h"
+#endif
+#if RCAR_LSI == RCAR_H3		/* H3 */
+#include "H3/qos_init_h3_v10.h"
+#include "H3/qos_init_h3_v11.h"
+#include "H3/qos_init_h3_v20.h"
+#include "H3/qos_init_h3_v30.h"
+#endif
+#if RCAR_LSI == RCAR_H3N	/* H3 */
+#include "H3/qos_init_h3n_v30.h"
+#endif
+#if RCAR_LSI == RCAR_M3		/* M3 */
+#include "M3/qos_init_m3_v10.h"
+#include "M3/qos_init_m3_v11.h"
+#include "M3/qos_init_m3_v30.h"
+#endif
+#if RCAR_LSI == RCAR_M3N	/* M3N */
+#include "M3N/qos_init_m3n_v10.h"
+#endif
+#if RCAR_LSI == RCAR_V3M	/* V3M */
+#include "V3M/qos_init_v3m.h"
+#endif
+#if RCAR_LSI == RCAR_E3		/* E3 */
+#include "E3/qos_init_e3_v10.h"
+#endif
+#if RCAR_LSI == RCAR_D3		/* D3 */
+#include "D3/qos_init_d3.h"
+#endif
+
+ /* Product Register */
+#define PRR			0xFFF00044U
+#define PRR_PRODUCT_MASK	0x00007F00U
+#define PRR_CUT_MASK		0x000000FFU
+#define PRR_PRODUCT_H3		0x00004F00U	/* R-Car H3 */
+#define PRR_PRODUCT_M3		0x00005200U	/* R-Car M3 */
+#define PRR_PRODUCT_V3M		0x00005400U	/* R-Car V3M */
+#define PRR_PRODUCT_M3N		0x00005500U	/* R-Car M3N */
+#define PRR_PRODUCT_E3		0x00005700U	/* R-Car E3 */
+#define PRR_PRODUCT_D3		0x00005800U	/* R-Car D3 */
+#define PRR_PRODUCT_10		0x00U
+#define PRR_PRODUCT_11		0x01U
+#define PRR_PRODUCT_20		0x10U
+#define PRR_PRODUCT_21		0x11U
+#define PRR_PRODUCT_30		0x20U
+
+#if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RCAR_V3M)
+
+#define DRAM_CH_CNT			0x04
+uint32_t qos_init_ddr_ch;
+uint8_t qos_init_ddr_phyvalid;
+#endif
+
+#define PRR_PRODUCT_ERR(reg)				\
+	do {						\
+		ERROR("LSI Product ID(PRR=0x%x) QoS "	\
+		"initialize not supported.\n", reg);	\
+		panic();				\
+	} while (0)
+
+#define PRR_CUT_ERR(reg)				\
+	do {						\
+		ERROR("LSI Cut ID(PRR=0x%x) QoS "	\
+		"initialize not supported.\n", reg);	\
+		panic();				\
+	} while (0)
+
+void rcar_qos_init(void)
+{
+	uint32_t reg;
+#if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RCAR_V3M)
+	uint32_t i;
+
+	qos_init_ddr_ch = 0;
+	qos_init_ddr_phyvalid = get_boardcnf_phyvalid();
+	for (i = 0; i < DRAM_CH_CNT; i++) {
+		if ((qos_init_ddr_phyvalid & (1 << i))) {
+			qos_init_ddr_ch++;
+		}
+	}
+#endif
+
+	reg = mmio_read_32(PRR);
+#if (RCAR_LSI == RCAR_AUTO) || RCAR_LSI_CUT_COMPAT
+	switch (reg & PRR_PRODUCT_MASK) {
+	case PRR_PRODUCT_H3:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+			qos_init_h3_v10();
+			break;
+		case PRR_PRODUCT_11:
+			qos_init_h3_v11();
+			break;
+		case PRR_PRODUCT_20:
+			qos_init_h3_v20();
+			break;
+		case PRR_PRODUCT_30:
+		default:
+			qos_init_h3_v30();
+			break;
+		}
+#elif (RCAR_LSI == RCAR_H3N)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_30:
+		default:
+			qos_init_h3n_v30();
+			break;
+		}
+#else
+		PRR_PRODUCT_ERR(reg);
+#endif
+		break;
+	case PRR_PRODUCT_M3:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+			qos_init_m3_v10();
+			break;
+		case PRR_PRODUCT_21: /* M3 Cut 13 */
+			qos_init_m3_v11();
+			break;
+		case PRR_PRODUCT_30: /* M3 Cut 30 */
+		default:
+			qos_init_m3_v30();
+			break;
+		}
+#else
+		PRR_PRODUCT_ERR(reg);
+#endif
+		break;
+	case PRR_PRODUCT_M3N:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+		default:
+			qos_init_m3n_v10();
+			break;
+		}
+#else
+		PRR_PRODUCT_ERR(reg);
+#endif
+		break;
+	case PRR_PRODUCT_V3M:
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_V3M)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+		case PRR_PRODUCT_20:
+		default:
+			qos_init_v3m();
+			break;
+		}
+#else
+		PRR_PRODUCT_ERR(reg);
+#endif
+		break;
+	case PRR_PRODUCT_E3:
+#if (RCAR_LSI == RCAR_E3)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+		default:
+			qos_init_e3_v10();
+			break;
+		}
+#else
+		PRR_PRODUCT_ERR(reg);
+#endif
+		break;
+	case PRR_PRODUCT_D3:
+#if (RCAR_LSI == RCAR_D3)
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+		default:
+			qos_init_d3();
+			break;
+		}
+#else
+		PRR_PRODUCT_ERR(reg);
+#endif
+		break;
+	default:
+		PRR_PRODUCT_ERR(reg);
+		break;
+	}
+#else
+#if RCAR_LSI == RCAR_H3		/* H3 */
+#if RCAR_LSI_CUT == RCAR_CUT_10
+	/* H3 Cut 10 */
+	if ((PRR_PRODUCT_H3 | PRR_PRODUCT_10)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_h3_v10();
+#elif RCAR_LSI_CUT == RCAR_CUT_11
+	/* H3 Cut 11 */
+	if ((PRR_PRODUCT_H3 | PRR_PRODUCT_11)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_h3_v11();
+#elif RCAR_LSI_CUT == RCAR_CUT_20
+	/* H3 Cut 20 */
+	if ((PRR_PRODUCT_H3 | PRR_PRODUCT_20)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_h3_v20();
+#else
+	/* H3 Cut 30 or later */
+	if ((PRR_PRODUCT_H3)
+	    != (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_h3_v30();
+#endif
+#elif RCAR_LSI == RCAR_H3N	/* H3 */
+	/* H3N Cut 30 or later */
+	if ((PRR_PRODUCT_H3)
+	    != (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_h3n_v30();
+#elif RCAR_LSI == RCAR_M3	/* M3 */
+#if RCAR_LSI_CUT == RCAR_CUT_10
+	/* M3 Cut 10 */
+	if ((PRR_PRODUCT_M3 | PRR_PRODUCT_10)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_m3_v10();
+#elif RCAR_LSI_CUT == RCAR_CUT_11
+	/* M3 Cut 11 */
+	if ((PRR_PRODUCT_M3 | PRR_PRODUCT_20)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_m3_v11();
+#elif RCAR_LSI_CUT == RCAR_CUT_13
+	/* M3 Cut 13 */
+	if ((PRR_PRODUCT_M3 | PRR_PRODUCT_21)
+	    != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_m3_v11();
+#else
+	/* M3 Cut 30 or later */
+	if ((PRR_PRODUCT_M3)
+	    != (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_m3_v30();
+#endif
+#elif RCAR_LSI == RCAR_M3N	/* M3N */
+	/* M3N Cut 10 or later */
+	if ((PRR_PRODUCT_M3N)
+	    != (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_m3n_v10();
+#elif RCAR_LSI == RCAR_V3M	/* V3M */
+	/* V3M Cut 10 or later */
+	if ((PRR_PRODUCT_V3M)
+			!= (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_v3m();
+#elif RCAR_LSI == RCAR_D3	/* D3 */
+	/* D3 Cut 10 or later */
+	if ((PRR_PRODUCT_D3)
+	    != (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_d3();
+#elif RCAR_LSI == RCAR_E3	/* E3 */
+	/* E3 Cut 10 or later */
+	if ((PRR_PRODUCT_E3)
+	    != (reg & (PRR_PRODUCT_MASK))) {
+		PRR_PRODUCT_ERR(reg);
+	}
+	qos_init_e3_v10();
+#else
+#error "Don't have QoS initialize routine(Unknown chip)."
+#endif
+#endif
+}
+
+#if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RCAR_V3M)
+uint32_t get_refperiod(void)
+{
+	uint32_t refperiod = QOSWT_WTSET0_CYCLE;
+
+#if (RCAR_LSI == RCAR_AUTO) || RCAR_LSI_CUT_COMPAT
+	uint32_t reg;
+
+	reg = mmio_read_32(PRR);
+	switch (reg & PRR_PRODUCT_MASK) {
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3)
+	case PRR_PRODUCT_H3:
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+		case PRR_PRODUCT_11:
+			break;
+		case PRR_PRODUCT_20:
+		case PRR_PRODUCT_30:
+		default:
+			refperiod = REFPERIOD_CYCLE;
+			break;
+		}
+		break;
+#elif (RCAR_LSI == RCAR_H3N)
+	case PRR_PRODUCT_H3:
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_30:
+		default:
+			refperiod = REFPERIOD_CYCLE;
+			break;
+		}
+		break;
+#endif
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3)
+	case PRR_PRODUCT_M3:
+		switch (reg & PRR_CUT_MASK) {
+		case PRR_PRODUCT_10:
+			break;
+		case PRR_PRODUCT_20: /* M3 Cut 11 */
+		case PRR_PRODUCT_21: /* M3 Cut 13 */
+		case PRR_PRODUCT_30: /* M3 Cut 30 */
+		default:
+			refperiod = REFPERIOD_CYCLE;
+			break;
+		}
+		break;
+#endif
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N)
+	case PRR_PRODUCT_M3N:
+		refperiod = REFPERIOD_CYCLE;
+		break;
+#endif
+	default:
+		break;
+	}
+#elif RCAR_LSI == RCAR_H3
+#if RCAR_LSI_CUT == RCAR_CUT_10
+	/* H3 Cut 10 */
+#elif RCAR_LSI_CUT == RCAR_CUT_11
+	/* H3 Cut 11 */
+#else
+	/* H3 Cut 20 */
+	/* H3 Cut 30 or later */
+	refperiod = REFPERIOD_CYCLE;
+#endif
+#elif RCAR_LSI == RCAR_H3N
+	/* H3N Cut 30 or later */
+	refperiod = REFPERIOD_CYCLE;
+#elif RCAR_LSI == RCAR_M3
+#if RCAR_LSI_CUT == RCAR_CUT_10
+	/* M3 Cut 10 */
+#else
+	/* M3 Cut 11 */
+	/* M3 Cut 13 */
+	/* M3 Cut 30 or later */
+	refperiod = REFPERIOD_CYCLE;
+#endif
+#elif RCAR_LSI == RCAR_M3N	/* for M3N */
+	refperiod = REFPERIOD_CYCLE;
+#endif
+
+	return refperiod;
+}
+#endif
+
+void rcar_qos_dbsc_setting(struct rcar_gen3_dbsc_qos_settings *qos,
+			   unsigned int qos_size, bool dbsc_wren)
+{
+	int i;
+
+	/* Register write enable */
+	if (dbsc_wren)
+		io_write_32(DBSC_DBSYSCNT0, 0x00001234U);
+
+	for (i = 0; i < qos_size; i++)
+		io_write_32(qos[i].reg, qos[i].val);
+
+	/* Register write protect */
+	if (dbsc_wren)
+		io_write_32(DBSC_DBSYSCNT0, 0x00000000U);
+}
diff --git a/drivers/renesas/rcar/qos/qos_init.h b/drivers/renesas/rcar/qos/qos_init.h
new file mode 100644
index 0000000..1b64992
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_init.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_INIT_H
+#define QOS_INIT_H
+
+extern void rcar_qos_init(void);
+extern uint8_t get_boardcnf_phyvalid(void);
+
+#endif /* QOS_INIT_H */
diff --git a/drivers/renesas/rcar/qos/qos_reg.h b/drivers/renesas/rcar/qos/qos_reg.h
new file mode 100644
index 0000000..f2012fa
--- /dev/null
+++ b/drivers/renesas/rcar/qos/qos_reg.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QOS_REG_H
+#define QOS_REG_H
+
+#define	RCAR_QOS_NONE			3U
+#define	RCAR_QOS_TYPE_DEFAULT		0U
+
+#define	RCAR_DRAM_SPLIT_LINEAR		0U
+#define	RCAR_DRAM_SPLIT_4CH		1U
+#define	RCAR_DRAM_SPLIT_2CH		2U
+#define	RCAR_DRAM_SPLIT_AUTO		3U
+#define	RST_BASE			(0xE6160000U)
+#define	RST_MODEMR			(RST_BASE + 0x0060U)
+
+#define	DBSC_BASE			0xE6790000U
+#define DBSC_DBSYSCNT0			(DBSC_BASE + 0x0100U)
+#define DBSC_AXARB			(DBSC_BASE + 0x0800U)
+#define DBSC_DBCAM0CNF1			(DBSC_BASE + 0x0904U)
+#define DBSC_DBCAM0CNF2			(DBSC_BASE + 0x0908U)
+#define DBSC_DBCAM0CNF3			(DBSC_BASE + 0x090CU)
+#define DBSC_DBSCHCNT0			(DBSC_BASE + 0x1000U)
+#define DBSC_DBSCHCNT1			(DBSC_BASE + 0x1004U)
+#define DBSC_DBSCHSZ0			(DBSC_BASE + 0x1010U)
+#define DBSC_DBSCHRW0			(DBSC_BASE + 0x1020U)
+#define DBSC_DBSCHRW1			(DBSC_BASE + 0x1024U)
+#define DBSC_DBSCHQOS00			(DBSC_BASE + 0x1030U)
+#define DBSC_DBSCHQOS01			(DBSC_BASE + 0x1034U)
+#define DBSC_DBSCHQOS02			(DBSC_BASE + 0x1038U)
+#define DBSC_DBSCHQOS03			(DBSC_BASE + 0x103CU)
+#define DBSC_DBSCHQOS40			(DBSC_BASE + 0x1070U)
+#define DBSC_DBSCHQOS41			(DBSC_BASE + 0x1074U)
+#define DBSC_DBSCHQOS42			(DBSC_BASE + 0x1078U)
+#define DBSC_DBSCHQOS43			(DBSC_BASE + 0x107CU)
+#define DBSC_DBSCHQOS90			(DBSC_BASE + 0x10C0U)
+#define DBSC_DBSCHQOS91			(DBSC_BASE + 0x10C4U)
+#define DBSC_DBSCHQOS92			(DBSC_BASE + 0x10C8U)
+#define DBSC_DBSCHQOS93			(DBSC_BASE + 0x10CCU)
+#define DBSC_DBSCHQOS120		(DBSC_BASE + 0x10F0U)
+#define DBSC_DBSCHQOS121		(DBSC_BASE + 0x10F4U)
+#define DBSC_DBSCHQOS122		(DBSC_BASE + 0x10F8U)
+#define DBSC_DBSCHQOS123		(DBSC_BASE + 0x10FCU)
+#define DBSC_DBSCHQOS130		(DBSC_BASE + 0x1100U)
+#define DBSC_DBSCHQOS131		(DBSC_BASE + 0x1104U)
+#define DBSC_DBSCHQOS132		(DBSC_BASE + 0x1108U)
+#define DBSC_DBSCHQOS133		(DBSC_BASE + 0x110CU)
+#define DBSC_DBSCHQOS140		(DBSC_BASE + 0x1110U)
+#define DBSC_DBSCHQOS141		(DBSC_BASE + 0x1114U)
+#define DBSC_DBSCHQOS142		(DBSC_BASE + 0x1118U)
+#define DBSC_DBSCHQOS143		(DBSC_BASE + 0x111CU)
+#define DBSC_DBSCHQOS150		(DBSC_BASE + 0x1120U)
+#define DBSC_DBSCHQOS151		(DBSC_BASE + 0x1124U)
+#define DBSC_DBSCHQOS152		(DBSC_BASE + 0x1128U)
+#define DBSC_DBSCHQOS153		(DBSC_BASE + 0x112CU)
+#define DBSC_SCFCTST0			(DBSC_BASE + 0x1700U)
+#define DBSC_SCFCTST1			(DBSC_BASE + 0x1708U)
+#define DBSC_SCFCTST2			(DBSC_BASE + 0x170CU)
+
+#define	AXI_BASE			0xE6784000U
+#define	AXI_ADSPLCR0			(AXI_BASE + 0x0008U)
+#define	AXI_ADSPLCR1			(AXI_BASE + 0x000CU)
+#define	AXI_ADSPLCR2			(AXI_BASE + 0x0010U)
+#define	AXI_ADSPLCR3			(AXI_BASE + 0x0014U)
+#define	AXI_MMCR			(AXI_BASE + 0x0300U)
+#define	ADSPLCR0_ADRMODE_DEFAULT	((uint32_t)0U << 31U)
+#define	ADSPLCR0_ADRMODE_GEN2		((uint32_t)1U << 31U)
+#define	ADSPLCR0_SPLITSEL(x)		((uint32_t)(x) << 16U)
+#define	ADSPLCR0_AREA(x)		((uint32_t)(x) <<  8U)
+#define	ADSPLCR0_SWP			0x0CU
+
+#define	AXI_TR3CR			0xE67D100CU
+#define	AXI_TR4CR			0xE67D1014U
+
+#define	QOS_BASE0			0xE67E0000U
+#define	QOSBW_FIX_QOS_BANK0		(QOS_BASE0 + 0x0000U)
+#define	QOSBW_FIX_QOS_BANK1		(QOS_BASE0 + 0x1000U)
+#define	QOSBW_BE_QOS_BANK0		(QOS_BASE0 + 0x2000U)
+#define	QOSBW_BE_QOS_BANK1		(QOS_BASE0 + 0x3000U)
+#define	QOSCTRL_SL_INIT			(QOS_BASE0 + 0x8000U)
+#define	QOSCTRL_REF_ARS			(QOS_BASE0 + 0x8004U)
+#define	QOSCTRL_STATQC			(QOS_BASE0 + 0x8008U)
+
+#define	QOS_BASE1			0xE67F0000U
+#define	QOSCTRL_RAS			(QOS_BASE1 + 0x0000U)
+#define	QOSCTRL_FIXTH			(QOS_BASE1 + 0x0004U)
+#define	QOSCTRL_RAEN			(QOS_BASE1 + 0x0018U)
+#define	QOSCTRL_REGGD			(QOS_BASE1 + 0x0020U)
+#define	QOSCTRL_DANN			(QOS_BASE1 + 0x0030U)
+#define	QOSCTRL_DANT			(QOS_BASE1 + 0x0038U)
+#define	QOSCTRL_EC			(QOS_BASE1 + 0x003CU)
+#define	QOSCTRL_EMS			(QOS_BASE1 + 0x0040U)
+#define	QOSCTRL_FSS			(QOS_BASE1 + 0x0048U)
+#define	QOSCTRL_INSFC			(QOS_BASE1 + 0x0050U)
+#define	QOSCTRL_BERR			(QOS_BASE1 + 0x0054U)
+#define	QOSCTRL_EARLYR			(QOS_BASE1 + 0x0060U)
+#define	QOSCTRL_RACNT0			(QOS_BASE1 + 0x0080U)
+#define	QOSCTRL_STATGEN0		(QOS_BASE1 + 0x0088U)
+
+#define	GPU_ACT_GRD			0xFD820808U
+#define	GPU_ACT0			0xFD820800U
+#define	GPU_ACT1			0xFD821800U
+#define	GPU_ACT2			0xFD822800U
+#define	GPU_ACT3			0xFD823800U
+#define	GPU_ACT4			0xFD824800U
+#define	GPU_ACT5			0xFD825800U
+#define	GPU_ACT6			0xFD826800U
+#define	GPU_ACT7			0xFD827800U
+
+#define	RT_ACT0				0xFFC50800U
+#define	RT_ACT1				0xFFC51800U
+
+#define	CPU_ACT0			0xF1300800U
+#define	CPU_ACT1			0xF1340800U
+#define	CPU_ACT2			0xF1380800U
+#define	CPU_ACT3			0xF13C0800U
+
+#define	RCAR_REWT_TRAINING_DISABLE	0U
+#define	RCAR_REWT_TRAINING_ENABLE	1U
+
+#define QOSWT_FIX_WTQOS_BANK0		(QOSBW_FIX_QOS_BANK0 + 0x0800U)
+#define QOSWT_FIX_WTQOS_BANK1		(QOSBW_FIX_QOS_BANK1 + 0x0800U)
+#define QOSWT_BE_WTQOS_BANK0		(QOSBW_BE_QOS_BANK0  + 0x0800U)
+#define QOSWT_BE_WTQOS_BANK1		(QOSBW_BE_QOS_BANK1  + 0x0800U)
+#define	QOSWT_WTEN			(QOS_BASE0 + 0x8030U)
+#define	QOSWT_WTREF			(QOS_BASE0 + 0x8034U)
+#define	QOSWT_WTSET0			(QOS_BASE0 + 0x8038U)
+#define	QOSWT_WTSET1			(QOS_BASE0 + 0x803CU)
+
+#endif /* QOS_REG_H */
diff --git a/drivers/renesas/rcar/rom/rom_api.c b/drivers/renesas/rcar/rom/rom_api.c
new file mode 100644
index 0000000..c9f8f5f
--- /dev/null
+++ b/drivers/renesas/rcar/rom/rom_api.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+#include "rom_api.h"
+
+typedef uint32_t(*rom_secure_boot_api_f) (uint32_t *key, uint32_t *cert,
+					  rom_read_flash_f pFuncReadFlash);
+
+typedef uint32_t(*rom_get_lcs_api_f) (uint32_t *lcs);
+
+#define OLD_API_TABLE1	(0U)	/* H3 Ver.1.0/Ver.1.1 */
+#define OLD_API_TABLE2	(1U)	/* H3 Ver.2.0 */
+#define OLD_API_TABLE3	(2U)	/* M3 Ver.1.0 */
+#define NEW_API_TABLE	(3U)	/* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3, D3, V3M WS2.0 */
+#define NEW_API_TABLE2	(4U)	/* V3M WS1.0 */
+#define API_TABLE_MAX	(5U)	/* table max */
+				/* Later than H3 Ver.2.0 */
+
+static uint32_t get_table_index(void)
+{
+	uint32_t product;
+	uint32_t cut_ver;
+	uint32_t index;
+
+	product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
+	cut_ver = mmio_read_32(RCAR_PRR) & RCAR_CUT_MASK;
+
+	switch (product) {
+	case RCAR_PRODUCT_H3:
+		if (cut_ver == RCAR_CUT_VER10)
+			index = OLD_API_TABLE1;
+		else if (cut_ver == RCAR_CUT_VER11)
+			index = OLD_API_TABLE1;
+		else if (cut_ver == RCAR_CUT_VER20)
+			index = OLD_API_TABLE2;
+		else
+			/* Later than H3 Ver.2.0 */
+			index = NEW_API_TABLE;
+		break;
+	case RCAR_PRODUCT_M3:
+		if (cut_ver == RCAR_CUT_VER10)
+			index = OLD_API_TABLE3;
+		else
+			/* M3 Ver.1.1 or later */
+			index = NEW_API_TABLE;
+		break;
+	case RCAR_PRODUCT_V3M:
+		if (cut_ver == RCAR_CUT_VER10)
+			/* V3M WS1.0 */
+			index = NEW_API_TABLE2;
+		else
+			/* V3M WS2.0 or later */
+			index = NEW_API_TABLE;
+		break;
+	default:
+		index = NEW_API_TABLE;
+		break;
+	}
+
+	return index;
+}
+
+uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert,
+			     rom_read_flash_f read_flash)
+{
+	static const uintptr_t rom_api_table[API_TABLE_MAX] = {
+		0xEB10DD64U,	/* H3 Ver.1.0/Ver.1.1 */
+		0xEB116ED4U,	/* H3 Ver.2.0 */
+		0xEB1102FCU,	/* M3 Ver.1.0 */
+		0xEB100180U,	/* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3, D3, V3M WS2.0 */
+		0xEB110128U,	/* V3M WS1.0 */
+	};
+	rom_secure_boot_api_f secure_boot;
+	uint32_t index;
+
+	index = get_table_index();
+	secure_boot = (rom_secure_boot_api_f) rom_api_table[index];
+
+	return secure_boot(key, cert, read_flash);
+}
+
+uint32_t rcar_rom_get_lcs(uint32_t *lcs)
+{
+	static const uintptr_t rom_get_lcs_table[API_TABLE_MAX] = {
+		0xEB10DFE0U,	/* H3 Ver.1.0/Ver.1.1 */
+		0xEB117150U,	/* H3 Ver.2.0 */
+		0xEB110578U,	/* M3 Ver.1.0 */
+		0xEB10018CU,	/* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3, D3, V3M WS2.0 */
+		0xEB1103A4U,	/* V3M WS1.0 */
+	};
+	rom_get_lcs_api_f get_lcs;
+	uint32_t index;
+
+	index = get_table_index();
+	get_lcs = (rom_get_lcs_api_f) rom_get_lcs_table[index];
+
+	return get_lcs(lcs);
+}
diff --git a/drivers/renesas/rcar/rom/rom_api.h b/drivers/renesas/rcar/rom/rom_api.h
new file mode 100644
index 0000000..1d5b03d
--- /dev/null
+++ b/drivers/renesas/rcar/rom/rom_api.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ROM_API_H
+#define ROM_API_H
+
+#include <stdint.h>
+
+#define SBROM_OK				(0x00000000U)
+#define SBROM_ILLEGAL_INPUT_PARAM_ERR		(0x0B000001U)
+#define SBROM_ILLEGAL_OEM_HASH_VALUE_ERR	(0x0B000008U)
+#define SBROM_ILLEGAL_LCS_FOR_OPERATION_ERR	(0x0B000010U)
+#define SBROM_HASH_NOT_PROGRAMMED_ERR		(0x0B000100U)
+#define SBROM_PUB_KEY_HASH_VALIDATION_FAILURE	(0xF1000006U)
+#define SBROM_RSA_SIG_VERIFICATION_FAILED	(0xF1000007U)
+
+#define LCS_CM					(0x0U)
+#define LCS_DM					(0x1U)
+#define LCS_SD					(0x3U)
+#define LCS_SE					(0x5U)
+#define LCS_FA					(0x7U)
+
+typedef uint32_t(*rom_read_flash_f) (uint64_t src, uint8_t *dst, uint32_t len);
+uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert,
+				  rom_read_flash_f f);
+uint32_t rcar_rom_get_lcs(uint32_t *lcs);
+
+#endif /* ROM_API_H */
diff --git a/drivers/renesas/rcar/rpc/rpc_driver.c b/drivers/renesas/rcar/rpc/rpc_driver.c
new file mode 100644
index 0000000..5c11b62
--- /dev/null
+++ b/drivers/renesas/rcar/rpc/rpc_driver.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "cpg_registers.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rpc_registers.h"
+
+#define MSTPSR9_RPC_BIT		(0x00020000U)
+#define RPC_CMNCR_MD_BIT	(0x80000000U)
+#define RPC_PHYCNT_CAL		BIT(31)
+#define RPC_PHYCNT_STRTIM_M3V1	(0x6 << 15UL)
+#define RPC_PHYCNT_STRTIM	(0x7 << 15UL)
+
+static void rpc_enable(void)
+{
+	/* Enable clock supply to RPC. */
+	mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, MSTPSR9_RPC_BIT);
+}
+
+static void rpc_setup(void)
+{
+	uint32_t product, cut, reg, phy_strtim;
+
+	if (mmio_read_32(RPC_CMNCR) & RPC_CMNCR_MD_BIT)
+		mmio_clrbits_32(RPC_CMNCR, RPC_CMNCR_MD_BIT);
+
+	product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
+	cut = mmio_read_32(RCAR_PRR) & RCAR_CUT_MASK;
+
+	if ((product ==  RCAR_PRODUCT_M3) && (cut < RCAR_CUT_VER30))
+		phy_strtim = RPC_PHYCNT_STRTIM_M3V1;
+	else
+		phy_strtim = RPC_PHYCNT_STRTIM;
+
+	reg = mmio_read_32(RPC_PHYCNT);
+	reg &= ~RPC_PHYCNT_STRTIM;
+	reg |= phy_strtim;
+	mmio_write_32(RPC_PHYCNT, reg);
+	reg |= RPC_PHYCNT_CAL;
+	mmio_write_32(RPC_PHYCNT, reg);
+}
+
+void rcar_rpc_init(void)
+{
+	rpc_enable();
+	rpc_setup();
+}
diff --git a/drivers/renesas/rcar/rpc/rpc_registers.h b/drivers/renesas/rcar/rpc/rpc_registers.h
new file mode 100644
index 0000000..79aea85
--- /dev/null
+++ b/drivers/renesas/rcar/rpc/rpc_registers.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPC_REGISTERS_H
+#define RPC_REGISTERS_H
+
+#define RPC_BASE	(0xEE200000U)
+#define RPC_CMNCR	(RPC_BASE + 0x0000U)
+#define RPC_SSLDR	(RPC_BASE + 0x0004U)
+#define RPC_DRCR	(RPC_BASE + 0x000CU)
+#define RPC_DRCMR	(RPC_BASE + 0x0010U)
+#define RPC_DRENR	(RPC_BASE + 0x001CU)
+#define RPC_SMCR	(RPC_BASE + 0x0020U)
+#define RPC_SMCMR	(RPC_BASE + 0x0024U)
+#define RPC_SMENR	(RPC_BASE + 0x0030U)
+#define RPC_CMNSR	(RPC_BASE + 0x0048U)
+#define RPC_DRDMCR	(RPC_BASE + 0x0058U)
+#define RPC_DRDRENR	(RPC_BASE + 0x005CU)
+#define RPC_PHYCNT	(RPC_BASE + 0x007CU)
+#define RPC_PHYINT	(RPC_BASE + 0x0088U)
+
+#endif /* RPC_REGISTERS_H */
diff --git a/drivers/renesas/rcar/scif/scif.S b/drivers/renesas/rcar/scif/scif.S
new file mode 100644
index 0000000..8309bb2
--- /dev/null
+++ b/drivers/renesas/rcar/scif/scif.S
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <drivers/renesas/rcar/console/console.h>
+
+#define	SCIF_INTERNAL_CLK	0
+#define	SCIF_EXTARNAL_CLK	1
+#define	SCIF_CLK		SCIF_INTERNAL_CLK
+
+/* product register */
+#define	PRR			(0xFFF00044)
+#define	PRR_PRODUCT_MASK	(0x00007F00)
+#define	PRR_CUT_MASK		(0x000000FF)
+#define	PRR_PRODUCT_H3_VER_10	(0x00004F00)
+#define	PRR_PRODUCT_E3		(0x00005700)
+#define	PRR_PRODUCT_D3		(0x00005800)
+
+/* module stop */
+#define	CPG_BASE		(0xE6150000)
+#define	CPG_SMSTPCR2		(0x0138)
+#define	CPG_SMSTPCR3		(0x013C)
+#define CPG_MSTPSR2		(0x0040)
+#define	CPG_MSTPSR3		(0x0048)
+#define	MSTP207			(1 << 7)
+#define	MSTP310			(1 << 10)
+#define	CPG_CPGWPR		(0x0900)
+
+/* scif */
+#define	SCIF0_BASE		(0xE6E60000)
+#define	SCIF2_BASE		(0xE6E88000)
+#define	SCIF_SCSMR		(0x00)
+#define	SCIF_SCBRR		(0x04)
+#define	SCIF_SCSCR		(0x08)
+#define	SCIF_SCFTDR		(0x0C)
+#define	SCIF_SCFSR		(0x10)
+#define	SCIF_SCFRDR		(0x14)
+#define	SCIF_SCFCR		(0x18)
+#define	SCIF_SCFDR		(0x1C)
+#define	SCIF_SCSPTR		(0x20)
+#define	SCIF_SCLSR		(0x24)
+#define	SCIF_DL			(0x30)
+#define	SCIF_CKS		(0x34)
+
+#if RCAR_LSI == RCAR_V3M
+#define SCIF_BASE		SCIF0_BASE
+#define CPG_SMSTPCR		CPG_SMSTPCR2
+#define CPG_MSTPSR		CPG_MSTPSR2
+#define MSTP			MSTP207
+#else
+#define SCIF_BASE		SCIF2_BASE
+#define CPG_SMSTPCR		CPG_SMSTPCR3
+#define CPG_MSTPSR		CPG_MSTPSR3
+#define MSTP			MSTP310
+#endif
+
+/* mode pin */
+#define	RST_MODEMR		(0xE6160060)
+#define	MODEMR_MD12		(0x00001000)
+
+#define	SCSMR_CA_MASK		(1 << 7)
+#define	SCSMR_CA_ASYNC		(0x0000)
+#define	SCSMR_CHR_MASK		(1 << 6)
+#define	SCSMR_CHR_8		(0x0000)
+#define	SCSMR_PE_MASK		(1 << 5)
+#define	SCSMR_PE_DIS		(0x0000)
+#define	SCSMR_STOP_MASK		(1 << 3)
+#define	SCSMR_STOP_1		(0x0000)
+#define	SCSMR_CKS_MASK		(3 << 0)
+#define	SCSMR_CKS_DIV1		(0x0000)
+#define	SCSMR_INIT_DATA		(SCSMR_CA_ASYNC +	\
+					 SCSMR_CHR_8 +		\
+					 SCSMR_PE_DIS +		\
+					 SCSMR_STOP_1 +		\
+					 SCSMR_CKS_DIV1)
+#define	SCBRR_115200BPS		(17)
+#define	SCBRR_115200BPSON	(16)
+#define	SCBRR_115200BPS_E3_SSCG	(15)
+#define	SCBRR_230400BPS		(8)
+
+#define	SCSCR_TE_MASK		(1 << 5)
+#define	SCSCR_TE_DIS		(0x0000)
+#define	SCSCR_TE_EN		(0x0020)
+#define	SCSCR_RE_MASK		(1 << 4)
+#define	SCSCR_RE_DIS		(0x0000)
+#define	SCSCR_RE_EN		(0x0010)
+#define	SCSCR_CKE_MASK		(3 << 0)
+#define	SCSCR_CKE_INT		(0x0000)
+#define 	SCSCR_CKE_BRG		(0x0002)
+#if SCIF_CLK == SCIF_EXTARNAL_CLK
+#define	SCSCR_CKE_INT_CLK	(SCSCR_CKE_BRG)
+#else
+#define	SCFSR_TEND_MASK		(1 << 6)
+#define	SCFSR_TEND_TRANS_END	(0x0040)
+#define	SCSCR_CKE_INT_CLK	(SCSCR_CKE_INT)
+#endif
+#define	SCFSR_INIT_DATA		(0x0000)
+#define	SCFCR_TTRG_MASK		(3 << 4)
+#define	SCFCR_TTRG_8		(0x0000)
+#define	SCFCR_TTRG_0		(0x0030)
+#define	SCFCR_TFRST_MASK	(1 << 2)
+#define	SCFCR_TFRST_DIS		(0x0000)
+#define	SCFCR_TFRST_EN		(0x0004)
+#define	SCFCR_RFRS_MASK		(1 << 1)
+#define	SCFCR_RFRS_DIS		(0x0000)
+#define	SCFCR_RFRS_EN		(0x0002)
+#define	SCFCR_INIT_DATA		(SCFCR_TTRG_8)
+#define	SCFDR_T_MASK		(0x1f << 8)
+#define	DL_INIT_DATA		(8)
+#define	CKS_CKS_DIV_MASK	(1 << 15)
+#define	CKS_CKS_DIV_CLK		(0x0000)
+#define	CKS_XIN_MASK		(1 << 14)
+#define	CKS_XIN_SCIF_CLK	(0x0000)
+#define	CKS_INIT_DATA		(CKS_CKS_DIV_CLK + CKS_XIN_SCIF_CLK)
+
+	.globl	console_rcar_register
+	.globl	console_rcar_init
+	.globl	console_rcar_putc
+	.globl	console_rcar_flush
+
+	/* -----------------------------------------------
+	 * int console_rcar_register(
+	 *      uintptr_t base, uint32_t clk, uint32_t baud,
+	 *      console_rcar_t *console)
+	 * Function to initialize and register a new rcar
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_rcar_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_rcar_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_RCAR_BASE]
+
+	bl	console_rcar_init
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register rcar, putc=1, getc=0, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_rcar_register
+
+	/* -----------------------------------------------
+	 * int console_rcar_init(unsigned long base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_rcar_register
+	 * and crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success
+	 * Clobber list : x1, x2
+	 * -----------------------------------------------
+	 */
+func console_rcar_init
+	ldr	x0, =CPG_BASE
+	ldr	w1, [x0, #CPG_SMSTPCR]
+	and	w1, w1, #~MSTP
+	mvn	w2, w1
+	str	w2, [x0, #CPG_CPGWPR]
+	str	w1, [x0, #CPG_SMSTPCR]
+5:
+	ldr w1, [x0, #CPG_MSTPSR]
+	and w1, w1, #MSTP
+	cbnz w1, 5b
+
+	ldr	x0, =SCIF_BASE
+	/* Clear bits TE and RE in SCSCR to 0 */
+	mov	w1, #(SCSCR_TE_DIS + SCSCR_RE_DIS)
+	strh	w1, [x0, #SCIF_SCSCR]
+	/* Set bits TFRST and RFRST in SCFCR to 1 */
+	ldrh	w1, [x0, #SCIF_SCFCR]
+	orr	w1, w1, #(SCFCR_TFRST_EN + SCFCR_RFRS_EN)
+	strh	w1, [x0, #SCIF_SCFCR]
+	/* Read flags of ER, DR, BRK, and RDF in SCFSR and those of TO and ORER
+	   in SCLSR, then clear them to 0 */
+	mov	w1, #SCFSR_INIT_DATA
+	strh	w1, [x0, #SCIF_SCFSR]
+	mov	w1, #0
+	strh	w1, [x0, #SCIF_SCLSR]
+	/* Set bits CKE[1:0] in SCSCR */
+	ldrh	w1, [x0, #SCIF_SCSCR]
+	and	w1, w1, #~SCSCR_CKE_MASK
+	mov	w2, #SCSCR_CKE_INT_CLK
+	orr	w1, w1, w2
+	strh	w1, [x0, #SCIF_SCSCR]
+	/* Set data transfer format in SCSMR */
+	mov	w1, #SCSMR_INIT_DATA
+	strh	w1, [x0, #SCIF_SCSMR]
+	/* Set value in SCBRR */
+#if SCIF_CLK == SCIF_INTERNAL_CLK
+	ldr	x1, =PRR
+	ldr	w1, [x1]
+	and	w1, w1, #(PRR_PRODUCT_MASK | PRR_CUT_MASK)
+	mov	w2, #PRR_PRODUCT_H3_VER_10
+	cmp	w1, w2
+	beq	3f
+	and	w1, w1, #PRR_PRODUCT_MASK
+	mov	w2, #PRR_PRODUCT_D3
+	cmp	w1, w2
+	beq	4f
+	and	w1, w1, #PRR_PRODUCT_MASK
+	mov	w2, #PRR_PRODUCT_E3
+	cmp	w1, w2
+	bne	5f
+
+	ldr	x1, =RST_MODEMR
+	ldr	w1, [x1]
+	and	w1, w1, #MODEMR_MD12
+	mov	w2, #MODEMR_MD12
+	cmp	w1, w2
+	bne	5f
+
+	mov	w1, #SCBRR_115200BPS_E3_SSCG
+	b	2f
+5:
+	mov	w1, #SCBRR_115200BPS
+	b	2f
+4:
+	mov	w1, #SCBRR_115200BPSON
+	b	2f
+3:
+	mov	w1, #SCBRR_230400BPS
+2:
+	strb	w1, [x0, SCIF_SCBRR]
+#else
+	mov	w1, #DL_INIT_DATA
+	strh	w1, [x0, #SCIF_DL]
+	mov	w1, #CKS_INIT_DATA
+	strh	w1, [x0, #SCIF_CKS]
+#endif
+	/* 1-bit interval elapsed */
+	mov	w1, #100
+1:
+	subs	w1, w1, #1
+	cbnz	w1, 1b
+	/*
+	 * Set bits RTRG[1:0], TTRG[1:0], and MCE in SCFCR
+	 * Clear bits FRST and RFRST to 0
+	 */
+	mov	w1, #SCFCR_INIT_DATA
+	strh	w1, [x0, #SCIF_SCFCR]
+	/* Set bits TE and RE in SCSCR to 1 */
+	ldrh	w1, [x0, #SCIF_SCSCR]
+	orr	w1, w1, #(SCSCR_TE_EN + SCSCR_RE_EN)
+	strh	w1, [x0, #SCIF_SCSCR]
+	mov	x0, #1
+
+	ret
+endfunc console_rcar_init
+
+	/* --------------------------------------------------------
+	 * int console_rcar_putc(int c, unsigned int base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_rcar_putc
+	ldr	x1, =SCIF_BASE
+	cmp	w0, #0xA
+	/* Prepend '\r' to '\n' */
+	bne	2f
+1:
+	/* Check if the transmit FIFO is full */
+	ldrh	w2, [x1, #SCIF_SCFDR]
+	ubfx	w2, w2, #8, #5
+	cmp	w2, #16
+	bcs	1b
+	mov	w2, #0x0D
+	strb	w2, [x1, #SCIF_SCFTDR]
+2:
+	/* Check if the transmit FIFO is full */
+	ldrh	w2, [x1, #SCIF_SCFDR]
+	ubfx	w2, w2, #8, #5
+	cmp	w2, #16
+	bcs	2b
+	strb	w0, [x1, #SCIF_SCFTDR]
+
+	/* Clear TEND flag */
+	ldrh	w2, [x1, #SCIF_SCFSR]
+	and	w2, w2, #~SCFSR_TEND_MASK
+	strh	w2, [x1, #SCIF_SCFSR]
+
+	ret
+endfunc console_rcar_putc
+
+	/* ---------------------------------------------
+	 * int console_rcar_flush(void)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output. It returns 0
+	 * upon successful completion, otherwise it
+	 * returns -1.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_rcar_flush
+	ldr	x0, =SCIF_BASE
+1:
+	/* Check TEND flag */
+	ldrh	w1, [x0, #SCIF_SCFSR]
+	and	w1, w1, #SCFSR_TEND_MASK
+	cmp	w1, #SCFSR_TEND_TRANS_END
+	bne	1b
+
+	ldr	x0, =SCIF_BASE
+	ldrh	w1, [x0, #SCIF_SCSCR]
+	and	w1, w1, #~(SCSCR_TE_EN + SCSCR_RE_EN)
+	strh	w1, [x0, #SCIF_SCSCR]
+
+	mov	w0, #0
+	ret
+endfunc console_rcar_flush
diff --git a/drivers/renesas/rcar/watchdog/swdt.c b/drivers/renesas/rcar/watchdog/swdt.c
new file mode 100644
index 0000000..8b2943c
--- /dev/null
+++ b/drivers/renesas/rcar/watchdog/swdt.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+
+extern void gicd_set_icenabler(uintptr_t base, unsigned int id);
+
+#define RST_BASE			(0xE6160000U)
+#define RST_WDTRSTCR			(RST_BASE + 0x0054U)
+#define SWDT_BASE			(0xE6030000U)
+#define SWDT_WTCNT			(SWDT_BASE + 0x0000U)
+#define SWDT_WTCSRA			(SWDT_BASE + 0x0004U)
+#define SWDT_WTCSRB			(SWDT_BASE + 0x0008U)
+#define SWDT_GICD_BASE			(0xF1010000U)
+#define SWDT_GICC_BASE			(0xF1020000U)
+#define SWDT_GICD_CTLR			(SWDT_GICD_BASE + 0x0000U)
+#define SWDT_GICD_IGROUPR		(SWDT_GICD_BASE + 0x0080U)
+#define SWDT_GICD_ISPRIORITYR		(SWDT_GICD_BASE + 0x0400U)
+#define SWDT_GICC_CTLR			(SWDT_GICC_BASE + 0x0000U)
+#define SWDT_GICC_PMR			(SWDT_GICC_BASE + 0x0004U)
+#define SWDT_GICD_ITARGETSR		(SWDT_GICD_BASE + 0x0800U)
+#define IGROUPR_NUM			(16U)
+#define ISPRIORITY_NUM			(128U)
+#define ITARGET_MASK			(0x03U)
+
+#define WDTRSTCR_UPPER_BYTE		(0xA55A0000U)
+#define WTCSRA_UPPER_BYTE		(0xA5A5A500U)
+#define WTCSRB_UPPER_BYTE		(0xA5A5A500U)
+#define WTCNT_UPPER_BYTE		(0x5A5A0000U)
+#define WTCNT_RESET_VALUE		(0xF488U)
+#define WTCSRA_BIT_CKS			(0x0007U)
+#define WTCSRB_BIT_CKS			(0x003FU)
+#define SWDT_RSTMSK			(1U << 1U)
+#define WTCSRA_WOVFE			(1U << 3U)
+#define WTCSRA_WRFLG			(1U << 5U)
+#define SWDT_ENABLE			(1U << 7U)
+
+#define WDTRSTCR_MASK_ALL		(0x0000FFFFU)
+#define WTCSRA_MASK_ALL			(0x000000FFU)
+#define WTCNT_INIT_DATA			(WTCNT_UPPER_BYTE + WTCNT_RESET_VALUE)
+#define WTCSRA_INIT_DATA		(WTCSRA_UPPER_BYTE + 0x0FU)
+#define WTCSRB_INIT_DATA		(WTCSRB_UPPER_BYTE + 0x21U)
+
+#if RCAR_LSI == RCAR_D3
+#define WTCNT_COUNT_8p13k		(0x10000U - 40760U)
+#else
+#define WTCNT_COUNT_8p13k		(0x10000U - 40687U)
+#endif
+#define WTCNT_COUNT_8p13k_H3VER10	(0x10000U - 20343U)
+#define WTCNT_COUNT_8p22k		(0x10000U - 41115U)
+#define WTCNT_COUNT_7p81k		(0x10000U - 39062U)
+#define WTCSRA_CKS_DIV16		(0x00000002U)
+
+static void swdt_disable(void)
+{
+	uint32_t rmsk;
+
+	rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL;
+	rmsk |= SWDT_RSTMSK;
+	mmio_write_32(RST_WDTRSTCR, WDTRSTCR_UPPER_BYTE | rmsk);
+
+	mmio_write_32(SWDT_WTCNT, WTCNT_INIT_DATA);
+	mmio_write_32(SWDT_WTCSRA, WTCSRA_INIT_DATA);
+	mmio_write_32(SWDT_WTCSRB, WTCSRB_INIT_DATA);
+
+	/* Set the interrupt clear enable register */
+	gicd_set_icenabler(RCAR_GICD_BASE, ARM_IRQ_SEC_WDT);
+}
+
+void rcar_swdt_init(void)
+{
+	uint32_t rmsk, sr;
+#if (RCAR_LSI != RCAR_E3)
+	uint32_t reg, val, product_cut, chk_data;
+
+	reg = mmio_read_32(RCAR_PRR);
+	product_cut = reg & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+
+	reg = mmio_read_32(RCAR_MODEMR);
+	chk_data = reg & CHECK_MD13_MD14;
+#endif
+	/* stop watchdog */
+	if (mmio_read_32(SWDT_WTCSRA) & SWDT_ENABLE)
+		mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE);
+
+	mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE |
+		      WTCSRA_WOVFE | WTCSRA_CKS_DIV16);
+
+#if (RCAR_LSI == RCAR_E3)
+	mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k);
+#else
+	val = WTCNT_UPPER_BYTE;
+
+	switch (chk_data) {
+	case MD14_MD13_TYPE_0:
+	case MD14_MD13_TYPE_2:
+		val |= WTCNT_COUNT_8p13k;
+		break;
+	case MD14_MD13_TYPE_1:
+		val |= WTCNT_COUNT_8p22k;
+		break;
+	case MD14_MD13_TYPE_3:
+		val |= product_cut == (RCAR_PRODUCT_H3 | RCAR_CUT_VER10) ?
+		    WTCNT_COUNT_8p13k_H3VER10 : WTCNT_COUNT_8p13k;
+		break;
+	default:
+		ERROR("MODEMR ERROR value = %x\n", chk_data);
+		panic();
+		break;
+	}
+
+	mmio_write_32(SWDT_WTCNT, val);
+#endif
+	rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL;
+	rmsk |= SWDT_RSTMSK | WDTRSTCR_UPPER_BYTE;
+	mmio_write_32(RST_WDTRSTCR, rmsk);
+
+	while ((mmio_read_8(SWDT_WTCSRA) & WTCSRA_WRFLG) != 0U)
+		;
+
+	/* Start the System WatchDog Timer */
+	sr = mmio_read_32(SWDT_WTCSRA) & WTCSRA_MASK_ALL;
+	mmio_write_32(SWDT_WTCSRA, (WTCSRA_UPPER_BYTE | sr | SWDT_ENABLE));
+}
+
+void rcar_swdt_release(void)
+{
+	uintptr_t itarget = SWDT_GICD_ITARGETSR +
+	    (ARM_IRQ_SEC_WDT & ~ITARGET_MASK);
+	uint32_t i;
+
+	/* Disable FIQ interrupt */
+	write_daifset(DAIF_FIQ_BIT);
+	/* FIQ interrupts are not taken to EL3 */
+	write_scr_el3(read_scr_el3() & ~SCR_FIQ_BIT);
+
+	swdt_disable();
+	gicv2_cpuif_disable();
+
+	for (i = 0; i < IGROUPR_NUM; i++)
+		mmio_write_32(SWDT_GICD_IGROUPR + i * 4, 0U);
+
+	for (i = 0; i < ISPRIORITY_NUM; i++)
+		mmio_write_32(SWDT_GICD_ISPRIORITYR + i * 4, 0U);
+
+	mmio_write_32(itarget, 0U);
+	mmio_write_32(SWDT_GICD_CTLR, 0U);
+	mmio_write_32(SWDT_GICC_CTLR, 0U);
+	mmio_write_32(SWDT_GICC_PMR, 0U);
+}
+
+void rcar_swdt_exec(uint64_t p)
+{
+	gicv2_end_of_interrupt(ARM_IRQ_SEC_WDT);
+	rcar_swdt_release();
+	ERROR("\n");
+	ERROR("System WDT overflow, occured address is %p\n", (void *)p);
+	panic();
+}
diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c
new file mode 100644
index 0000000..b39808f
--- /dev/null
+++ b/drivers/rpi3/gpio/rpi3_gpio.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+
+static struct rpi3_gpio_params rpi3_gpio_params;
+
+static int rpi3_gpio_get_direction(int gpio);
+static void rpi3_gpio_set_direction(int gpio, int direction);
+static int rpi3_gpio_get_value(int gpio);
+static void rpi3_gpio_set_value(int gpio, int value);
+static void rpi3_gpio_set_pull(int gpio, int pull);
+
+static const gpio_ops_t rpi3_gpio_ops = {
+	.get_direction  = rpi3_gpio_get_direction,
+	.set_direction  = rpi3_gpio_set_direction,
+	.get_value      = rpi3_gpio_get_value,
+	.set_value      = rpi3_gpio_set_value,
+	.set_pull       = rpi3_gpio_set_pull,
+};
+
+/**
+ * Get selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
+ *                                  RPI3_GPIO_FUNC_OUTPUT: output,
+ *                                  RPI3_GPIO_FUNC_ALT0: alt-0,
+ *                                  RPI3_GPIO_FUNC_ALT1: alt-1,
+ *                                  RPI3_GPIO_FUNC_ALT2: alt-2,
+ *                                  RPI3_GPIO_FUNC_ALT3: alt-3,
+ *                                  RPI3_GPIO_FUNC_ALT4: alt-4,
+ *                                  RPI3_GPIO_FUNC_ALT5: alt-5
+ */
+int rpi3_gpio_get_select(int gpio)
+{
+	int ret;
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 10;
+	int shift = 3 * (gpio % 10);
+	uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
+	uint32_t sel = mmio_read_32(reg_sel);
+
+	ret = (sel >> shift) & 0x07;
+
+	return ret;
+}
+
+/**
+ * Set selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
+ *                                      RPI3_GPIO_FUNC_OUTPUT: output,
+ *                                      RPI3_GPIO_FUNC_ALT0: alt-0,
+ *                                      RPI3_GPIO_FUNC_ALT1: alt-1,
+ *                                      RPI3_GPIO_FUNC_ALT2: alt-2,
+ *                                      RPI3_GPIO_FUNC_ALT3: alt-3,
+ *                                      RPI3_GPIO_FUNC_ALT4: alt-4,
+ *                                      RPI3_GPIO_FUNC_ALT5: alt-5
+ */
+void rpi3_gpio_set_select(int gpio, int fsel)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 10;
+	int shift = 3 * (gpio % 10);
+	uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
+	uint32_t sel = mmio_read_32(reg_sel);
+	uint32_t mask = U(0x07) << shift;
+
+	sel = (sel & (~mask)) | ((fsel << shift) & mask);
+	mmio_write_32(reg_sel, sel);
+}
+
+static int rpi3_gpio_get_direction(int gpio)
+{
+	int result = rpi3_gpio_get_select(gpio);
+
+	if (result == RPI3_GPIO_FUNC_INPUT)
+		return GPIO_DIR_IN;
+	else if (result == RPI3_GPIO_FUNC_OUTPUT)
+		return GPIO_DIR_OUT;
+
+	return GPIO_DIR_IN;
+}
+
+static void rpi3_gpio_set_direction(int gpio, int direction)
+{
+	switch (direction) {
+	case GPIO_DIR_IN:
+		rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
+		break;
+	case GPIO_DIR_OUT:
+		rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
+		break;
+	}
+}
+
+static int rpi3_gpio_get_value(int gpio)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 32;
+	int shift = gpio % 32;
+	uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
+	uint32_t value = mmio_read_32(reg_lev);
+
+	if ((value >> shift) & 0x01)
+		return GPIO_LEVEL_HIGH;
+	return GPIO_LEVEL_LOW;
+}
+
+static void rpi3_gpio_set_value(int gpio, int value)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 32;
+	int shift = gpio % 32;
+	uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
+	uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN);
+
+	switch (value) {
+	case GPIO_LEVEL_LOW:
+		mmio_write_32(reg_clr, U(1) << shift);
+		break;
+	case GPIO_LEVEL_HIGH:
+		mmio_write_32(reg_set, U(1) << shift);
+		break;
+	}
+}
+
+static void rpi3_gpio_set_pull(int gpio, int pull)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 32;
+	int shift = gpio % 32;
+	uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
+	uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
+
+	switch (pull) {
+	case GPIO_PULL_NONE:
+		mmio_write_32(reg_pud, 0x0);
+		break;
+	case GPIO_PULL_UP:
+		mmio_write_32(reg_pud, 0x2);
+		break;
+	case GPIO_PULL_DOWN:
+		mmio_write_32(reg_pud, 0x1);
+		break;
+	}
+	mdelay(150);
+	mmio_write_32(reg_clk, U(1) << shift);
+	mdelay(150);
+	mmio_write_32(reg_clk, 0x0);
+	mmio_write_32(reg_pud, 0x0);
+}
+
+void rpi3_gpio_init(struct rpi3_gpio_params *params)
+{
+	assert(params != 0);
+	memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params));
+	gpio_init(&rpi3_gpio_ops);
+}
diff --git a/drivers/rpi3/sdhost/rpi3_sdhost.c b/drivers/rpi3/sdhost/rpi3_sdhost.c
new file mode 100644
index 0000000..c4b6fca
--- /dev/null
+++ b/drivers/rpi3/sdhost/rpi3_sdhost.c
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+#include <drivers/mmc.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <errno.h>
+#include <string.h>
+
+static void rpi3_sdhost_initialize(void);
+static int rpi3_sdhost_send_cmd(struct mmc_cmd *cmd);
+static int rpi3_sdhost_set_ios(unsigned int clk, unsigned int width);
+static int rpi3_sdhost_prepare(int lba, uintptr_t buf, size_t size);
+static int rpi3_sdhost_read(int lba, uintptr_t buf, size_t size);
+static int rpi3_sdhost_write(int lba, uintptr_t buf, size_t size);
+
+static const struct mmc_ops rpi3_sdhost_ops = {
+	.init		= rpi3_sdhost_initialize,
+	.send_cmd	= rpi3_sdhost_send_cmd,
+	.set_ios	= rpi3_sdhost_set_ios,
+	.prepare	= rpi3_sdhost_prepare,
+	.read		= rpi3_sdhost_read,
+	.write		= rpi3_sdhost_write,
+};
+
+static struct rpi3_sdhost_params rpi3_sdhost_params;
+
+/**
+ * Wait for command being processed.
+ *
+ * This function waits the command being processed. It compares
+ * the ENABLE flag of the HC_COMMAND register. When ENABLE flag disappeared
+ * it means the command is processed by the SDHOST.
+ * The timeout is currently 1000*100 us = 100 ms.
+ *
+ * @return 0: command finished. 1: command timed out.
+ */
+static int rpi3_sdhost_waitcommand(void)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+
+	volatile int timeout = 1000;
+
+	while ((mmio_read_32(reg_base + HC_COMMAND) & HC_CMD_ENABLE)
+	       && (--timeout > 0)) {
+		udelay(100);
+	}
+
+	return ((timeout > 0) ? 0 : (-(ETIMEDOUT)));
+}
+
+/**
+ * Send the command and argument to the SDHOST
+ *
+ * This function will wait for the previous command finished. And then
+ * clear any error status of previous command. And then
+ * send out the command and args. The command will be turned on the ENABLE
+ * flag before sending out.
+ */
+static void send_command_raw(unsigned int cmd, unsigned int arg)
+{
+	unsigned int status;
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+
+	/* wait for previous command finish */
+	rpi3_sdhost_waitcommand();
+
+	/* clean error status */
+	status = mmio_read_32(reg_base + HC_HOSTSTATUS);
+	if (status & HC_HSTST_MASK_ERROR_ALL)
+		mmio_write_32(reg_base + HC_HOSTSTATUS, status);
+
+	/* recording the command */
+	rpi3_sdhost_params.current_cmd = cmd & HC_CMD_COMMAND_MASK;
+
+	/* send the argument and command */
+	mmio_write_32(reg_base + HC_ARGUMENT, arg);
+	mmio_write_32(reg_base + HC_COMMAND, cmd | HC_CMD_ENABLE);
+}
+
+/**
+ * Send the command and argument to the SDHOST, decorated with control
+ * flags.
+ *
+ * This function will use send_command_raw to send the commands to SDHOST.
+ * But before sending it will decorate the command with control flags specific
+ * to SDHOST.
+ */
+static void send_command_decorated(unsigned int cmd, unsigned int arg)
+{
+	unsigned int cmd_flags = 0;
+
+	switch (cmd & HC_CMD_COMMAND_MASK) {
+	case MMC_CMD(0):
+		cmd_flags |= HC_CMD_RESPONSE_NONE;
+		break;
+	case MMC_ACMD(51):
+		cmd_flags |= HC_CMD_READ;
+		break;
+	case MMC_CMD(8):
+	case MMC_CMD(11):
+	case MMC_CMD(17):
+	case MMC_CMD(18):
+		cmd_flags |= HC_CMD_READ;
+		break;
+	case MMC_CMD(20):
+	case MMC_CMD(24):
+	case MMC_CMD(25):
+		cmd_flags |= HC_CMD_WRITE;
+		break;
+	case MMC_CMD(12):
+		cmd_flags |= HC_CMD_BUSY;
+		break;
+	default:
+		break;
+	}
+	send_command_raw(cmd | cmd_flags, arg);
+}
+
+/**
+ * drains the FIFO on DATA port
+ *
+ * This function drains any data left in the DATA port.
+ */
+static void rpi3_drain_fifo(void)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	volatile int timeout = 100000;
+
+	rpi3_sdhost_waitcommand();
+
+	while (mmio_read_32(reg_base + HC_HOSTSTATUS) & HC_HSTST_HAVEDATA) {
+		mmio_read_32(reg_base + HC_DATAPORT);
+		udelay(100);
+	}
+
+	while (1) {
+		uint32_t edm, fsm;
+
+		edm = mmio_read_32(reg_base + HC_DEBUG);
+		fsm = edm & HC_DBG_FSM_MASK;
+
+		if ((fsm == HC_DBG_FSM_IDENTMODE) ||
+		    (fsm == HC_DBG_FSM_DATAMODE))
+			break;
+
+		if ((fsm == HC_DBG_FSM_READWAIT) ||
+		    (fsm == HC_DBG_FSM_WRITESTART1) ||
+		    (fsm == HC_DBG_FSM_READDATA)) {
+			mmio_write_32(reg_base + HC_DEBUG,
+				      edm | HC_DBG_FORCE_DATA_MODE);
+			break;
+		}
+
+		if (--timeout <= 0) {
+			ERROR("rpi3_sdhost: %s cannot recover stat\n",
+			      __func__);
+			return;
+		}
+	}
+}
+
+/**
+ * Dump SDHOST registers
+ */
+static void rpi3_sdhost_print_regs(void)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+
+	INFO("rpi3_sdhost: HC_COMMAND:        0x%08x\n",
+	     mmio_read_32(reg_base + HC_COMMAND));
+	INFO("rpi3_sdhost: HC_ARGUMENT:       0x%08x\n",
+	     mmio_read_32(reg_base + HC_ARGUMENT));
+	INFO("rpi3_sdhost: HC_TIMEOUTCOUNTER: 0x%08x\n",
+	     mmio_read_32(reg_base + HC_TIMEOUTCOUNTER));
+	INFO("rpi3_sdhost: HC_CLOCKDIVISOR:   0x%08x\n",
+	     mmio_read_32(reg_base + HC_CLOCKDIVISOR));
+	INFO("rpi3_sdhost: HC_RESPONSE_0:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_RESPONSE_0));
+	INFO("rpi3_sdhost: HC_RESPONSE_1:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_RESPONSE_1));
+	INFO("rpi3_sdhost: HC_RESPONSE_2:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_RESPONSE_2));
+	INFO("rpi3_sdhost: HC_RESPONSE_3:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_RESPONSE_3));
+	INFO("rpi3_sdhost: HC_HOSTSTATUS:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_HOSTSTATUS));
+	INFO("rpi3_sdhost: HC_POWER:          0x%08x\n",
+	     mmio_read_32(reg_base + HC_POWER));
+	INFO("rpi3_sdhost: HC_DEBUG:          0x%08x\n",
+	     mmio_read_32(reg_base + HC_DEBUG));
+	INFO("rpi3_sdhost: HC_HOSTCONFIG:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_HOSTCONFIG));
+	INFO("rpi3_sdhost: HC_BLOCKSIZE:      0x%08x\n",
+	     mmio_read_32(reg_base + HC_BLOCKSIZE));
+	INFO("rpi3_sdhost: HC_BLOCKCOUNT:     0x%08x\n",
+	     mmio_read_32(reg_base + HC_BLOCKCOUNT));
+}
+
+/**
+ * Reset SDHOST
+ */
+static void rpi3_sdhost_reset(void)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	unsigned int dbg;
+	uint32_t tmp1;
+
+	mmio_write_32(reg_base + HC_POWER, 0);
+	mmio_write_32(reg_base + HC_COMMAND, 0);
+	mmio_write_32(reg_base + HC_ARGUMENT, 0);
+
+	mmio_write_32(reg_base + HC_TIMEOUTCOUNTER, HC_TIMEOUT_DEFAULT);
+	mmio_write_32(reg_base + HC_CLOCKDIVISOR, 0);
+	mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_RESET);
+	mmio_write_32(reg_base + HC_HOSTCONFIG, 0);
+	mmio_write_32(reg_base + HC_BLOCKSIZE, 0);
+	mmio_write_32(reg_base + HC_BLOCKCOUNT, 0);
+
+	dbg = mmio_read_32(reg_base + HC_DEBUG);
+	dbg &= ~((HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_READ_SHIFT) |
+		 (HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_WRITE_SHIFT));
+	dbg |= (HC_FIFO_THRESH_READ << HC_DBG_FIFO_THRESH_READ_SHIFT) |
+		(HC_FIFO_THRESH_WRITE << HC_DBG_FIFO_THRESH_WRITE_SHIFT);
+	mmio_write_32(reg_base + HC_DEBUG, dbg);
+	mdelay(250);
+	mmio_write_32(reg_base + HC_POWER, 1);
+	mdelay(250);
+	rpi3_sdhost_params.clk_rate = 0;
+
+	mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_MAXVAL);
+	tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG);
+	mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1 | HC_HSTCF_INT_BUSY);
+}
+
+static void rpi3_sdhost_initialize(void)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+
+	assert((rpi3_sdhost_params.reg_base & MMC_BLOCK_MASK) == 0);
+
+	rpi3_sdhost_reset();
+
+	mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_PREFERVAL);
+	udelay(300);
+}
+
+static int rpi3_sdhost_send_cmd(struct mmc_cmd *cmd)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	int err = 0;
+	uint32_t cmd_idx;
+	uint32_t cmd_arg;
+	uint32_t cmd_flags = 0;
+	uint32_t intmask;
+
+	/* Wait for the command done */
+	err = rpi3_sdhost_waitcommand();
+	if (err != 0) {
+		WARN("previous command not done yet\n");
+		return err;
+	}
+
+	cmd_idx = cmd->cmd_idx & HC_CMD_COMMAND_MASK;
+
+	cmd_arg = cmd->cmd_arg;
+	if (cmd_idx == MMC_ACMD(51)) {
+		/* if previous cmd send to SDHOST is not MMC_CMD(55).
+		 * It means this MMC_ACMD(51) is a resend.
+		 * And we must also resend MMC_CMD(55) in this case
+		 */
+		if (rpi3_sdhost_params.current_cmd != MMC_CMD(55)) {
+			send_command_decorated(
+				MMC_CMD(55),
+				rpi3_sdhost_params.sdcard_rca <<
+				RCA_SHIFT_OFFSET);
+			rpi3_sdhost_params.mmc_app_cmd = 1;
+			rpi3_sdhost_waitcommand();
+
+			/* Also we need to call prepare to clean the buffer */
+			rpi3_sdhost_prepare(0, (uintptr_t)NULL, 8);
+		}
+	}
+
+	/* We ignore MMC_CMD(12) sending from the TF-A's MMC driver
+	 * because we send MMC_CMD(12) by ourselves.
+	 */
+	if (cmd_idx == MMC_CMD(12))
+		return 0;
+
+	if ((cmd->resp_type & MMC_RSP_136) &&
+	    (cmd->resp_type & MMC_RSP_BUSY)) {
+		ERROR("rpi3_sdhost: unsupported response type!\n");
+		return -(EOPNOTSUPP);
+	}
+
+	if (cmd->resp_type & MMC_RSP_48 && cmd->resp_type != MMC_RESPONSE_R2) {
+		/* 48-bit command
+		 * We don't need to set any flags here because it is default.
+		 */
+	} else if (cmd->resp_type & MMC_RSP_136) {
+		/* 136-bit command */
+		cmd_flags |= HC_CMD_RESPONSE_LONG;
+	} else {
+		/* no respond command */
+		cmd_flags |= HC_CMD_RESPONSE_NONE;
+	}
+
+	rpi3_sdhost_params.cmdbusy = 0;
+	if (cmd->resp_type & MMC_RSP_BUSY) {
+		cmd_flags |= HC_CMD_BUSY;
+		rpi3_sdhost_params.cmdbusy = 1;
+	}
+
+	if (rpi3_sdhost_params.mmc_app_cmd) {
+		switch (cmd_idx) {
+		case MMC_ACMD(41):
+			if (cmd_arg == OCR_HCS)
+				cmd_arg |= OCR_3_3_3_4;
+			break;
+		default:
+			break;
+		}
+		rpi3_sdhost_params.mmc_app_cmd = 0;
+	}
+
+	if (cmd_idx == MMC_CMD(55))
+		rpi3_sdhost_params.mmc_app_cmd = 1;
+
+	send_command_decorated(cmd_idx | cmd_flags, cmd_arg);
+
+	intmask = mmio_read_32(reg_base + HC_HOSTSTATUS);
+	if (rpi3_sdhost_params.cmdbusy && (intmask & HC_HSTST_INT_BUSY)) {
+		mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_INT_BUSY);
+		rpi3_sdhost_params.cmdbusy = 0;
+	}
+
+	if (!(cmd_flags & HC_CMD_RESPONSE_NONE)) {
+		err = rpi3_sdhost_waitcommand();
+		if (err != 0)
+			ERROR("rpi3_sdhost: cmd cannot be finished\n");
+	}
+
+	cmd->resp_data[0] = mmio_read_32(reg_base + HC_RESPONSE_0);
+	cmd->resp_data[1] = mmio_read_32(reg_base + HC_RESPONSE_1);
+	cmd->resp_data[2] = mmio_read_32(reg_base + HC_RESPONSE_2);
+	cmd->resp_data[3] = mmio_read_32(reg_base + HC_RESPONSE_3);
+
+	if (mmio_read_32(reg_base + HC_COMMAND) & HC_CMD_FAILED) {
+		uint32_t sdhsts = mmio_read_32(reg_base + HC_HOSTSTATUS);
+
+		mmio_write_32(reg_base + HC_HOSTSTATUS,
+			      HC_HSTST_MASK_ERROR_ALL);
+
+		/*
+		 * If the command SEND_OP_COND returns with CRC7 error,
+		 * it can be considered as having completed successfully.
+		 */
+		if (!(sdhsts & HC_HSTST_ERROR_CRC7)
+		    || (cmd_idx != MMC_CMD(1))) {
+			if (sdhsts & HC_HSTST_TIMEOUT_CMD) {
+				ERROR("rpi3_sdhost: timeout status 0x%x\n",
+				      sdhsts);
+				err = -(ETIMEDOUT);
+			} else {
+				ERROR("rpi3_sdhost: unknown err, cmd = 0x%x\n",
+				      mmio_read_32(reg_base + HC_COMMAND));
+				ERROR("rpi3_sdhost status: 0x%x\n", sdhsts);
+				err = -(EILSEQ);
+			}
+		}
+	}
+
+	if ((!err) && (cmd_idx == MMC_CMD(3))) {
+		/* we keep the RCA in case to send MMC_CMD(55) ourselves */
+		rpi3_sdhost_params.sdcard_rca = (cmd->resp_data[0]
+						 & 0xFFFF0000U) >> 16;
+	}
+
+	return err;
+}
+
+static int rpi3_sdhost_set_clock(unsigned int clk)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	uint32_t max_clk = 250000000;
+	uint32_t div;
+
+	if (clk < 100000) {
+		mmio_write_32(reg_base + HC_CLOCKDIVISOR,
+			      HC_CLOCKDIVISOR_MAXVAL);
+		return 0;
+	}
+
+	div = max_clk / clk;
+	if (div < 2)
+		div = 2;
+
+	if ((max_clk / div) > clk)
+		div++;
+
+	div -= 2;
+	if (div > HC_CLOCKDIVISOR_MAXVAL)
+		div = HC_CLOCKDIVISOR_MAXVAL;
+
+	rpi3_sdhost_params.clk_rate = max_clk / (div + 2);
+	rpi3_sdhost_params.ns_per_fifo_word = (1000000000 /
+					       rpi3_sdhost_params.clk_rate)
+		* 8;
+
+	mmio_write_32(reg_base + HC_CLOCKDIVISOR, div);
+	return 0;
+}
+
+static int rpi3_sdhost_set_ios(unsigned int clk, unsigned int width)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	uint32_t tmp1;
+
+	rpi3_sdhost_set_clock(clk);
+	VERBOSE("rpi3_sdhost: Changing clock to %dHz for data mode\n", clk);
+
+	if (width != MMC_BUS_WIDTH_4 && width != MMC_BUS_WIDTH_1) {
+		ERROR("rpi3_sdhost: width %d not supported\n", width);
+		return -(EOPNOTSUPP);
+	}
+	rpi3_sdhost_params.bus_width = width;
+
+	tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG);
+	tmp1 &= ~(HC_HSTCF_EXTBUS_4BIT);
+	if (rpi3_sdhost_params.bus_width == MMC_BUS_WIDTH_4)
+		tmp1 |= HC_HSTCF_EXTBUS_4BIT;
+
+	mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1);
+	tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG);
+	mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1 |
+		      HC_HSTCF_SLOW_CARD | HC_HSTCF_INTBUS_WIDE);
+
+	return 0;
+}
+
+static int rpi3_sdhost_prepare(int lba, uintptr_t buf, size_t size)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	size_t blocks;
+	size_t blocksize;
+
+	if (size < 512) {
+		blocksize = size;
+		blocks = 1;
+	} else {
+		blocksize = 512;
+		blocks = size / blocksize;
+		if (size % blocksize != 0)
+			blocks++;
+	}
+
+	rpi3_drain_fifo();
+
+	mmio_write_32(reg_base + HC_BLOCKSIZE, blocksize);
+	mmio_write_32(reg_base + HC_BLOCKCOUNT, blocks);
+	udelay(100);
+	return 0;
+}
+
+static int rpi3_sdhost_read(int lba, uintptr_t buf, size_t size)
+{
+	int err = 0;
+	uint32_t *buf1 = ((uint32_t *) buf);
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	int timeout = 100000;
+	int remaining_words = 0;
+
+	for (int i = 0; i < size / 4; i++) {
+		volatile int t = timeout;
+		uint32_t hsts_err;
+
+		while ((mmio_read_32(reg_base + HC_HOSTSTATUS)
+			& HC_HSTST_HAVEDATA) == 0) {
+			if (t == 0) {
+				ERROR("rpi3_sdhost: fifo timeout after %dus\n",
+				      timeout);
+				err = -(ETIMEDOUT);
+				break;
+			}
+			t--;
+			udelay(10);
+		}
+		if (t == 0)
+			break;
+
+		uint32_t data = mmio_read_32(reg_base + HC_DATAPORT);
+
+		hsts_err = mmio_read_32(reg_base + HC_HOSTSTATUS)
+			& HC_HSTST_MASK_ERROR_ALL;
+		if (hsts_err) {
+			ERROR("rpi3_sdhost: transfer FIFO word %d: 0x%x\n",
+			      i,
+			      mmio_read_32(reg_base + HC_HOSTSTATUS));
+			rpi3_sdhost_print_regs();
+
+			err = -(EILSEQ);
+
+			/* clean the error status */
+			mmio_write_32(reg_base + HC_HOSTSTATUS, hsts_err);
+		}
+
+		if (buf1)
+			buf1[i] = data;
+
+		/* speeding up if the remaining words are still a lot */
+		remaining_words = (mmio_read_32(reg_base + HC_DEBUG) >> 4)
+			& HC_DBG_FIFO_THRESH_MASK;
+		if (remaining_words >= 7)
+			continue;
+
+		/* delay. slowing down the read process */
+		udelay(100);
+	}
+
+	/* We decide to stop by ourselves.
+	 * It is because MMC_CMD(18) -> MMC_CMD(13) -> MMC_CMD(12)
+	 * doesn't work for RPi3 SDHost.
+	 */
+	if (rpi3_sdhost_params.current_cmd == MMC_CMD(18))
+		send_command_decorated(MMC_CMD(12), 0);
+
+	return err;
+}
+
+static int rpi3_sdhost_write(int lba, uintptr_t buf, size_t size)
+{
+	uint32_t *buf1 = ((uint32_t *) buf);
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+	int err = 0;
+	int remaining_words = 0;
+
+	for (int i = 0; i < size / 4; i++) {
+		uint32_t hsts_err;
+		uint32_t data = buf1[i];
+		uint32_t dbg;
+		uint32_t fsm_state;
+
+		mmio_write_32(reg_base + HC_DATAPORT, data);
+
+		dbg = mmio_read_32(reg_base + HC_DEBUG);
+		fsm_state = dbg & HC_DBG_FSM_MASK;
+		if (fsm_state != HC_DBG_FSM_WRITEDATA
+		    && fsm_state != HC_DBG_FSM_WRITESTART1
+		    && fsm_state != HC_DBG_FSM_WRITESTART2
+		    && fsm_state != HC_DBG_FSM_WRITECRC
+		    && fsm_state != HC_DBG_FSM_WRITEWAIT1
+		    && fsm_state != HC_DBG_FSM_WRITEWAIT2) {
+			hsts_err = mmio_read_32(reg_base + HC_HOSTSTATUS)
+				& HC_HSTST_MASK_ERROR_ALL;
+			if (hsts_err)
+				err = -(EILSEQ);
+		}
+
+		/* speeding up if the remaining words are not many */
+		remaining_words = (mmio_read_32(reg_base + HC_DEBUG) >> 4)
+			& HC_DBG_FIFO_THRESH_MASK;
+		if (remaining_words <= 4)
+			continue;
+
+		udelay(100);
+	}
+
+	/* We decide to stop by ourselves.
+	 * It is because MMC_CMD(25) -> MMC_CMD(13) -> MMC_CMD(12)
+	 * doesn't work for RPi3 SDHost.
+	 */
+	if (rpi3_sdhost_params.current_cmd == MMC_CMD(25))
+		send_command_decorated(MMC_CMD(12), 0);
+
+	return err;
+}
+
+void rpi3_sdhost_init(struct rpi3_sdhost_params *params,
+		    struct mmc_device_info *mmc_dev_info)
+{
+	assert((params != 0) &&
+	       ((params->reg_base & MMC_BLOCK_MASK) == 0));
+
+	memcpy(&rpi3_sdhost_params, params, sizeof(struct rpi3_sdhost_params));
+
+	/* backup GPIO 48 to 53 configurations */
+	for (int i = 48; i <= 53; i++) {
+		rpi3_sdhost_params.gpio48_pinselect[i - 48]
+			= rpi3_gpio_get_select(i);
+		VERBOSE("rpi3_sdhost: Original GPIO state %d: %d\n",
+			i,
+			rpi3_sdhost_params.gpio48_pinselect[i - 48]);
+	}
+
+	/* setting pull resistors for 48 to 53.
+	 * It is debatable to set SD_CLK to UP or NONE. We massively
+	 * tested different brands of SD Cards and found NONE works
+	 * most stable.
+	 *
+	 * GPIO 48 (SD_CLK) to GPIO_PULL_NONE
+	 * GPIO 49 (SD_CMD) to GPIO_PULL_UP
+	 * GPIO 50 (SD_D0)  to GPIO_PULL_UP
+	 * GPIO 51 (SD_D1)  to GPIO_PULL_UP
+	 * GPIO 52 (SD_D2)  to GPIO_PULL_UP
+	 * GPIO 53 (SD_D3)  to GPIO_PULL_UP
+	 */
+	gpio_set_pull(48, GPIO_PULL_NONE);
+	for (int i = 49; i <= 53; i++)
+		gpio_set_pull(i, GPIO_PULL_UP);
+
+	/* Set pin 48-53 to alt-0. It means route SDHOST to card slot */
+	for (int i = 48; i <= 53; i++)
+		rpi3_gpio_set_select(i, RPI3_GPIO_FUNC_ALT0);
+
+	mmc_init(&rpi3_sdhost_ops, params->clk_rate, params->bus_width,
+		 params->flags, mmc_dev_info);
+}
+
+void rpi3_sdhost_stop(void)
+{
+	uintptr_t reg_base = rpi3_sdhost_params.reg_base;
+
+	VERBOSE("rpi3_sdhost: Shutting down: drain FIFO out\n");
+	rpi3_drain_fifo();
+
+	VERBOSE("rpi3_sdhost: Shutting down: slowing down the clock\n");
+	mmio_write_32(reg_base+HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_SLOWVAL);
+	udelay(500);
+
+	VERBOSE("rpi3_sdhost: Shutting down: put SDHost into idle state\n");
+	send_command_decorated(MMC_CMD(0), 0);
+	udelay(500);
+
+	mmio_write_32(reg_base + HC_COMMAND, 0);
+	mmio_write_32(reg_base + HC_ARGUMENT, 0);
+	mmio_write_32(reg_base + HC_TIMEOUTCOUNTER, HC_TIMEOUT_IDLE);
+	mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_STOPVAL);
+
+	udelay(100);
+
+	mmio_write_32(reg_base + HC_POWER, 0);
+	mmio_write_32(reg_base + HC_HOSTCONFIG, 0);
+	mmio_write_32(reg_base + HC_BLOCKSIZE, 0x400);
+	mmio_write_32(reg_base + HC_BLOCKCOUNT, 0);
+	mmio_write_32(reg_base + HC_HOSTSTATUS, 0x7f8);
+
+	mmio_write_32(reg_base + HC_COMMAND, 0);
+	mmio_write_32(reg_base + HC_ARGUMENT, 0);
+
+	udelay(100);
+
+	/* Restore the pinmux to original state */
+	for (int i = 48; i <= 53; i++) {
+		rpi3_gpio_set_select(i,
+				     rpi3_sdhost_params.gpio48_pinselect[i-48]);
+	}
+
+	/* Reset the pull resistors before entering BL33.
+	 * GPIO 48 (SD_CLK) to GPIO_PULL_UP
+	 * GPIO 49 (SD_CMD) to GPIO_PULL_UP
+	 * GPIO 50 (SD_D0)  to GPIO_PULL_UP
+	 * GPIO 51 (SD_D1)  to GPIO_PULL_UP
+	 * GPIO 52 (SD_D2)  to GPIO_PULL_UP
+	 * GPIO 53 (SD_D3)  to GPIO_PULL_UP
+	 */
+	for (int i = 48; i <= 53; i++)
+		gpio_set_pull(i, GPIO_PULL_UP);
+}
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
new file mode 100644
index 0000000..aaecf1f
--- /dev/null
+++ b/drivers/st/bsec/bsec.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#define BSEC_IP_VERSION_1_0	0x10
+#define BSEC_COMPAT		"st,stm32mp15-bsec"
+
+#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
+
+static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused;
+
+static uint32_t bsec_power_safmem(bool power);
+
+/* BSEC access protection */
+static spinlock_t bsec_spinlock;
+static uintptr_t bsec_base;
+
+static void bsec_lock(void)
+{
+	const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
+
+	/* Lock is currently required only when MMU and cache are enabled */
+	if ((read_sctlr() & mask) == mask) {
+		spin_lock(&bsec_spinlock);
+	}
+}
+
+static void bsec_unlock(void)
+{
+	const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
+
+	/* Unlock is required only when MMU and cache are enabled */
+	if ((read_sctlr() & mask) == mask) {
+		spin_unlock(&bsec_spinlock);
+	}
+}
+
+static int bsec_get_dt_node(struct dt_node_info *info)
+{
+	int node;
+
+	node = dt_get_node(info, -1, BSEC_COMPAT);
+	if (node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	return node;
+}
+
+#if defined(IMAGE_BL32)
+static void enable_non_secure_access(uint32_t otp)
+{
+	otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
+
+	if (bsec_shadow_register(otp) != BSEC_OK) {
+		panic();
+	}
+}
+
+static bool non_secure_can_access(uint32_t otp)
+{
+	return (otp_nsec_access[otp / __WORD_BIT] &
+		BIT(otp % __WORD_BIT)) != 0;
+}
+
+static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
+{
+	int bsec_subnode;
+
+	fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
+		const fdt32_t *cuint;
+		uint32_t reg;
+		uint32_t i;
+		uint32_t size;
+		uint8_t status;
+
+		cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
+		if (cuint == NULL) {
+			panic();
+		}
+
+		reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
+		if (reg < STM32MP1_UPPER_OTP_START) {
+			continue;
+		}
+
+		status = fdt_get_status(bsec_subnode);
+		if ((status & DT_NON_SECURE) == 0U)  {
+			continue;
+		}
+
+		size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
+
+		if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
+			size++;
+		}
+
+		for (i = reg; i < (reg + size); i++) {
+			enable_non_secure_access(i);
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static uint32_t otp_bank_offset(uint32_t otp)
+{
+	assert(otp <= STM32MP1_OTP_MAX_ID);
+
+	return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
+	       sizeof(uint32_t);
+}
+
+static uint32_t bsec_check_error(uint32_t otp)
+{
+	uint32_t bit = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank = otp_bank_offset(otp);
+
+	if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+		return BSEC_DISTURBED;
+	}
+
+	if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
+		return BSEC_ERROR;
+	}
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+	void *fdt;
+	int node;
+	struct dt_node_info bsec_info;
+
+	if (fdt_get_address(&fdt) == 0) {
+		panic();
+	}
+
+	node = bsec_get_dt_node(&bsec_info);
+	if (node < 0) {
+		panic();
+	}
+
+	bsec_base = bsec_info.base;
+
+#if defined(IMAGE_BL32)
+	bsec_dt_otp_nsec_access(fdt, node);
+#endif
+	return BSEC_OK;
+}
+
+/*
+ * bsec_get_base: return BSEC base address.
+ */
+uint32_t bsec_get_base(void)
+{
+	return bsec_base;
+}
+
+/*
+ * bsec_set_config: enable and configure BSEC.
+ * cfg: pointer to param structure used to set register.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_config(struct bsec_config *cfg)
+{
+	uint32_t value;
+	int32_t result;
+
+	value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) &
+						BSEC_CONF_FRQ_MASK) |
+		 (((uint32_t)cfg->pulse_width << BSEC_CONF_PRG_WIDTH_SHIFT) &
+						BSEC_CONF_PRG_WIDTH_MASK) |
+		 (((uint32_t)cfg->tread << BSEC_CONF_TREAD_SHIFT) &
+						BSEC_CONF_TREAD_MASK));
+
+	bsec_lock();
+
+	mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, value);
+
+	bsec_unlock();
+
+	result = bsec_power_safmem((bool)cfg->power &
+				   BSEC_CONF_POWER_UP_MASK);
+	if (result != BSEC_OK) {
+		return result;
+	}
+
+	value = ((((uint32_t)cfg->upper_otp_lock << UPPER_OTP_LOCK_SHIFT) &
+						UPPER_OTP_LOCK_MASK) |
+		 (((uint32_t)cfg->den_lock << DENREG_LOCK_SHIFT) &
+						DENREG_LOCK_MASK) |
+		 (((uint32_t)cfg->prog_lock << GPLOCK_LOCK_SHIFT) &
+						GPLOCK_LOCK_MASK));
+
+	bsec_lock();
+
+	mmio_write_32(bsec_base + BSEC_OTP_LOCK_OFF, value);
+
+	bsec_unlock();
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_get_config: return config parameters set in BSEC registers.
+ * cfg: config param return.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_get_config(struct bsec_config *cfg)
+{
+	uint32_t value;
+
+	if (cfg == NULL) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	value = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
+	cfg->power = (uint8_t)((value & BSEC_CONF_POWER_UP_MASK) >>
+						BSEC_CONF_POWER_UP_SHIFT);
+	cfg->freq = (uint8_t)((value & BSEC_CONF_FRQ_MASK) >>
+						BSEC_CONF_FRQ_SHIFT);
+	cfg->pulse_width = (uint8_t)((value & BSEC_CONF_PRG_WIDTH_MASK) >>
+						BSEC_CONF_PRG_WIDTH_SHIFT);
+	cfg->tread = (uint8_t)((value & BSEC_CONF_TREAD_MASK) >>
+						BSEC_CONF_TREAD_SHIFT);
+
+	value = mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF);
+	cfg->upper_otp_lock = (uint8_t)((value & UPPER_OTP_LOCK_MASK) >>
+						UPPER_OTP_LOCK_SHIFT);
+	cfg->den_lock = (uint8_t)((value & DENREG_LOCK_MASK) >>
+						DENREG_LOCK_SHIFT);
+	cfg->prog_lock = (uint8_t)((value & GPLOCK_LOCK_MASK) >>
+						GPLOCK_LOCK_SHIFT);
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_register(uint32_t otp)
+{
+	uint32_t result;
+	bool power_up = false;
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	/* Check if shadowing of OTP is locked */
+	if (bsec_read_sr_lock(otp)) {
+		VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
+			otp);
+	}
+
+	if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+		result = bsec_power_safmem(true);
+
+		if (result != BSEC_OK) {
+			return result;
+		}
+
+		power_up = true;
+	}
+
+	bsec_lock();
+
+	/* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+	mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
+
+	while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+		;
+	}
+
+	result = bsec_check_error(otp);
+
+	bsec_unlock();
+
+	if (power_up) {
+		if (bsec_power_safmem(false) != BSEC_OK) {
+			panic();
+		}
+	}
+
+	return result;
+}
+
+/*
+ * bsec_read_otp: read an OTP data value.
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
+{
+	uint32_t result;
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	bsec_lock();
+
+	*val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
+			    (otp * sizeof(uint32_t)));
+
+	result = bsec_check_error(otp);
+
+	bsec_unlock();
+
+	return result;
+}
+
+/*
+ * bsec_write_otp: write value in BSEC data register.
+ * val: value to write.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
+{
+	uint32_t result;
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	/* Check if programming of OTP is locked */
+	if (bsec_read_sw_lock(otp)) {
+		VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
+			otp);
+	}
+
+	bsec_lock();
+
+	mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
+		      (otp * sizeof(uint32_t)), val);
+
+	result = bsec_check_error(otp);
+
+	bsec_unlock();
+
+	return result;
+}
+
+/*
+ * bsec_program_otp: program a bit in SAFMEM after the prog.
+ *	The OTP data is not refreshed.
+ * val: value to program.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
+{
+	uint32_t result;
+	bool power_up = false;
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	/* Check if programming of OTP is locked */
+	if (bsec_read_sp_lock(otp)) {
+		WARN("BSEC: OTP locked, prog will be ignored\n");
+	}
+
+	if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
+	     BIT(BSEC_LOCK_PROGRAM)) != 0U) {
+		WARN("BSEC: GPLOCK activated, prog will be ignored\n");
+	}
+
+	if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+		result = bsec_power_safmem(true);
+
+		if (result != BSEC_OK) {
+			return result;
+		}
+
+		power_up = true;
+	}
+
+	bsec_lock();
+
+	/* Set value in write register */
+	mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
+
+	/* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+	mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
+
+	while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+		;
+	}
+
+	if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
+		result = BSEC_PROG_FAIL;
+	} else {
+		result = bsec_check_error(otp);
+	}
+
+	bsec_unlock();
+
+	if (power_up) {
+		if (bsec_power_safmem(false) != BSEC_OK) {
+			panic();
+		}
+	}
+
+	return result;
+}
+
+/*
+ * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_permanent_lock_otp(uint32_t otp)
+{
+	uint32_t result;
+	bool power_up = false;
+	uint32_t data;
+	uint32_t addr;
+
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+		result = bsec_power_safmem(true);
+
+		if (result != BSEC_OK) {
+			return result;
+		}
+
+		power_up = true;
+	}
+
+	if (otp < STM32MP1_UPPER_OTP_START) {
+		addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
+		data = DATA_LOWER_OTP_PERLOCK_BIT <<
+		       ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
+	} else {
+		addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
+		data = DATA_UPPER_OTP_PERLOCK_BIT <<
+		       (otp & DATA_UPPER_OTP_PERLOCK_MASK);
+	}
+
+	bsec_lock();
+
+	/* Set value in write register */
+	mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
+
+	/* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+	mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF,
+		      addr | BSEC_WRITE | BSEC_LOCK);
+
+	while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+		;
+	}
+
+	if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
+		result = BSEC_PROG_FAIL;
+	} else {
+		result = bsec_check_error(otp);
+	}
+
+	bsec_unlock();
+
+	if (power_up) {
+		if (bsec_power_safmem(false) != BSEC_OK) {
+			panic();
+		}
+	}
+
+	return result;
+}
+
+/*
+ * bsec_write_debug_conf: write value in debug feature
+ *	to enable/disable debug service.
+ * val: value to write.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_debug_conf(uint32_t val)
+{
+	uint32_t result = BSEC_ERROR;
+	uint32_t masked_val = val & BSEC_DEN_ALL_MSK;
+
+	bsec_lock();
+
+	mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val);
+
+	if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) {
+		result = BSEC_OK;
+	}
+
+	bsec_unlock();
+
+	return result;
+}
+
+/*
+ * bsec_read_debug_conf: read debug configuration.
+ */
+uint32_t bsec_read_debug_conf(void)
+{
+	return mmio_read_32(bsec_base + BSEC_DEN_OFF);
+}
+
+/*
+ * bsec_get_status: return status register value.
+ */
+uint32_t bsec_get_status(void)
+{
+	return mmio_read_32(bsec_base + BSEC_OTP_STATUS_OFF);
+}
+
+/*
+ * bsec_get_hw_conf: return hardware configuration.
+ */
+uint32_t bsec_get_hw_conf(void)
+{
+	return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF);
+}
+
+/*
+ * bsec_get_version: return BSEC version.
+ */
+uint32_t bsec_get_version(void)
+{
+	return mmio_read_32(bsec_base + BSEC_IPVR_OFF);
+}
+
+/*
+ * bsec_get_id: return BSEC ID.
+ */
+uint32_t bsec_get_id(void)
+{
+	return mmio_read_32(bsec_base + BSEC_IP_ID_OFF);
+}
+
+/*
+ * bsec_get_magic_id: return BSEC magic number.
+ */
+uint32_t bsec_get_magic_id(void)
+{
+	return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF);
+}
+
+/*
+ * bsec_write_sr_lock: write shadow-read lock.
+ * otp: OTP number.
+ * value: value to write in the register.
+ *	Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
+{
+	bool result = false;
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t bank_value;
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+	bsec_lock();
+
+	bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+	if ((bank_value & otp_mask) == value) {
+		/*
+		 * In case of write don't need to write,
+		 * the lock is already set.
+		 */
+		if (value != 0U) {
+			result = true;
+		}
+	} else {
+		if (value != 0U) {
+			bank_value = bank_value | otp_mask;
+		} else {
+			bank_value = bank_value & ~otp_mask;
+		}
+
+		/*
+		 * We can write 0 in all other OTP
+		 * if the lock is activated in one of other OTP.
+		 * Write 0 has no effect.
+		 */
+		mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value);
+		result = true;
+	}
+
+	bsec_unlock();
+
+	return result;
+}
+
+/*
+ * bsec_read_sr_lock: read shadow-read lock.
+ * otp: OTP number.
+ * return: true if otp is locked, else false.
+ */
+bool bsec_read_sr_lock(uint32_t otp)
+{
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+	return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_write_sw_lock: write shadow-write lock.
+ * otp: OTP number.
+ * value: Value to write in the register.
+ *	Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
+{
+	bool result = false;
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank_value;
+
+	bsec_lock();
+
+	bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+	if ((bank_value & otp_mask) == value) {
+		/*
+		 * In case of write don't need to write,
+		 * the lock is already set.
+		 */
+		if (value != 0U) {
+			result = true;
+		}
+	} else {
+		if (value != 0U) {
+			bank_value = bank_value | otp_mask;
+		} else {
+			bank_value = bank_value & ~otp_mask;
+		}
+
+		/*
+		 * We can write 0 in all other OTP
+		 * if the lock is activated in one of other OTP.
+		 * Write 0 has no effect.
+		 */
+		mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value);
+		result = true;
+	}
+
+	bsec_unlock();
+
+	return result;
+}
+
+/*
+ * bsec_read_sw_lock: read shadow-write lock.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_read_sw_lock(uint32_t otp)
+{
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+	return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_write_sp_lock: write shadow-program lock.
+ * otp: OTP number.
+ * value: Value to write in the register.
+ *	Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
+{
+	bool result = false;
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t bank_value;
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+	bsec_lock();
+
+	bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+	if ((bank_value & otp_mask) == value) {
+		/*
+		 * In case of write don't need to write,
+		 * the lock is already set.
+		 */
+		if (value != 0U) {
+			result = true;
+		}
+	} else {
+		if (value != 0U) {
+			bank_value = bank_value | otp_mask;
+		} else {
+			bank_value = bank_value & ~otp_mask;
+		}
+
+		/*
+		 * We can write 0 in all other OTP
+		 * if the lock is activated in one of other OTP.
+		 * Write 0 has no effect.
+		 */
+		mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value);
+		result = true;
+	}
+
+	bsec_unlock();
+
+	return result;
+}
+
+/*
+ * bsec_read_sp_lock: read shadow-program lock.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_read_sp_lock(uint32_t otp)
+{
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+	uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+	return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_wr_lock: Read permanent lock status.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_wr_lock(uint32_t otp)
+{
+	uint32_t bank = otp_bank_offset(otp);
+	uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
+
+	if ((mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank) &
+	     lock_bit) != 0U) {
+		/*
+		 * In case of write don't need to write,
+		 * the lock is already set.
+		 */
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * bsec_otp_lock: Lock Upper OTP or Global programming or debug enable
+ * service: Service to lock see header file.
+ * value: Value to write must always set to 1 (only use for debug purpose).
+ * return: BSEC_OK if succeed.
+ */
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
+{
+	uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
+
+	switch (service) {
+	case BSEC_LOCK_UPPER_OTP:
+		mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP);
+		break;
+	case BSEC_LOCK_DEBUG:
+		mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
+		break;
+	case BSEC_LOCK_PROGRAM:
+		mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
+		break;
+	default:
+		return BSEC_INVALID_PARAM;
+	}
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_power_safmem: Activate or deactivate SAFMEM power.
+ * power: true to power up, false to power down.
+ * return: BSEC_OK if succeed.
+ */
+static uint32_t bsec_power_safmem(bool power)
+{
+	uint32_t register_val;
+	uint32_t timeout = BSEC_TIMEOUT_VALUE;
+
+	bsec_lock();
+
+	register_val = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
+
+	if (power) {
+		register_val |= BSEC_CONF_POWER_UP_MASK;
+	} else {
+		register_val &= ~BSEC_CONF_POWER_UP_MASK;
+	}
+
+	mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val);
+
+	/* Waiting loop */
+	if (power) {
+		while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) &&
+		       (timeout != 0U)) {
+			timeout--;
+		}
+	} else {
+		while (((bsec_get_status() & BSEC_MODE_PWR_MASK) != 0U) &&
+		       (timeout != 0U)) {
+			timeout--;
+		}
+	}
+
+	bsec_unlock();
+
+	if (timeout == 0U) {
+		return BSEC_TIMEOUT;
+	}
+
+	return BSEC_OK;
+}
+
+/*
+ * bsec_mode_is_closed_device: read OTP secure sub-mode.
+ * return: false if open_device and true of closed_device.
+ */
+bool bsec_mode_is_closed_device(void)
+{
+	uint32_t value;
+
+	if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
+	    (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
+		return true;
+	}
+
+	return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
+}
+
+/*
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
+ * otp_value: read value.
+ * word: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word)
+{
+	uint32_t result;
+
+	result = bsec_shadow_register(word);
+	if (result != BSEC_OK) {
+		ERROR("BSEC: %u Shadowing Error %i\n", word, result);
+		return result;
+	}
+
+	result = bsec_read_otp(otp_value, word);
+	if (result != BSEC_OK) {
+		ERROR("BSEC: %u Read Error %i\n", word, result);
+	}
+
+	return result;
+}
+
+/*
+ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
+ * otp: OTP number.
+ * return: BSEC_OK if authorized access.
+ */
+uint32_t bsec_check_nsec_access_rights(uint32_t otp)
+{
+#if defined(IMAGE_BL32)
+	if (otp > STM32MP1_OTP_MAX_ID) {
+		return BSEC_INVALID_PARAM;
+	}
+
+	if (otp >= STM32MP1_UPPER_OTP_START) {
+		/* Check if BSEC is in OTP-SECURED closed_device state. */
+		if (bsec_mode_is_closed_device()) {
+			if (!non_secure_can_access(otp)) {
+				return BSEC_ERROR;
+			}
+		}
+	}
+#endif
+
+	return BSEC_OK;
+}
+
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
new file mode 100644
index 0000000..76e6e6f
--- /dev/null
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -0,0 +1,1920 @@
+/*
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_rcc.h>
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#define MAX_HSI_HZ		64000000
+#define USB_PHY_48_MHZ		48000000
+
+#define TIMEOUT_US_200MS	U(200000)
+#define TIMEOUT_US_1S		U(1000000)
+
+#define PLLRDY_TIMEOUT		TIMEOUT_US_200MS
+#define CLKSRC_TIMEOUT		TIMEOUT_US_200MS
+#define CLKDIV_TIMEOUT		TIMEOUT_US_200MS
+#define HSIDIV_TIMEOUT		TIMEOUT_US_200MS
+#define OSCRDY_TIMEOUT		TIMEOUT_US_1S
+
+const char *stm32mp_osc_node_label[NB_OSC] = {
+	[_LSI] = "clk-lsi",
+	[_LSE] = "clk-lse",
+	[_HSI] = "clk-hsi",
+	[_HSE] = "clk-hse",
+	[_CSI] = "clk-csi",
+	[_I2S_CKIN] = "i2s_ckin",
+};
+
+enum stm32mp1_parent_id {
+/* Oscillators are defined in enum stm32mp_osc_id */
+
+/* Other parent source */
+	_HSI_KER = NB_OSC,
+	_HSE_KER,
+	_HSE_KER_DIV2,
+	_CSI_KER,
+	_PLL1_P,
+	_PLL1_Q,
+	_PLL1_R,
+	_PLL2_P,
+	_PLL2_Q,
+	_PLL2_R,
+	_PLL3_P,
+	_PLL3_Q,
+	_PLL3_R,
+	_PLL4_P,
+	_PLL4_Q,
+	_PLL4_R,
+	_ACLK,
+	_PCLK1,
+	_PCLK2,
+	_PCLK3,
+	_PCLK4,
+	_PCLK5,
+	_HCLK6,
+	_HCLK2,
+	_CK_PER,
+	_CK_MPU,
+	_CK_MCU,
+	_USB_PHY_48,
+	_PARENT_NB,
+	_UNKNOWN_ID = 0xff,
+};
+
+/* Lists only the parent clock we are interested in */
+enum stm32mp1_parent_sel {
+	_I2C12_SEL,
+	_I2C35_SEL,
+	_STGEN_SEL,
+	_I2C46_SEL,
+	_SPI6_SEL,
+	_UART1_SEL,
+	_RNG1_SEL,
+	_UART6_SEL,
+	_UART24_SEL,
+	_UART35_SEL,
+	_UART78_SEL,
+	_SDMMC12_SEL,
+	_SDMMC3_SEL,
+	_QSPI_SEL,
+	_FMC_SEL,
+	_AXIS_SEL,
+	_MCUS_SEL,
+	_USBPHY_SEL,
+	_USBO_SEL,
+	_PARENT_SEL_NB,
+	_UNKNOWN_SEL = 0xff,
+};
+
+enum stm32mp1_pll_id {
+	_PLL1,
+	_PLL2,
+	_PLL3,
+	_PLL4,
+	_PLL_NB
+};
+
+enum stm32mp1_div_id {
+	_DIV_P,
+	_DIV_Q,
+	_DIV_R,
+	_DIV_NB,
+};
+
+enum stm32mp1_clksrc_id {
+	CLKSRC_MPU,
+	CLKSRC_AXI,
+	CLKSRC_MCU,
+	CLKSRC_PLL12,
+	CLKSRC_PLL3,
+	CLKSRC_PLL4,
+	CLKSRC_RTC,
+	CLKSRC_MCO1,
+	CLKSRC_MCO2,
+	CLKSRC_NB
+};
+
+enum stm32mp1_clkdiv_id {
+	CLKDIV_MPU,
+	CLKDIV_AXI,
+	CLKDIV_MCU,
+	CLKDIV_APB1,
+	CLKDIV_APB2,
+	CLKDIV_APB3,
+	CLKDIV_APB4,
+	CLKDIV_APB5,
+	CLKDIV_RTC,
+	CLKDIV_MCO1,
+	CLKDIV_MCO2,
+	CLKDIV_NB
+};
+
+enum stm32mp1_pllcfg {
+	PLLCFG_M,
+	PLLCFG_N,
+	PLLCFG_P,
+	PLLCFG_Q,
+	PLLCFG_R,
+	PLLCFG_O,
+	PLLCFG_NB
+};
+
+enum stm32mp1_pllcsg {
+	PLLCSG_MOD_PER,
+	PLLCSG_INC_STEP,
+	PLLCSG_SSCG_MODE,
+	PLLCSG_NB
+};
+
+enum stm32mp1_plltype {
+	PLL_800,
+	PLL_1600,
+	PLL_TYPE_NB
+};
+
+struct stm32mp1_pll {
+	uint8_t refclk_min;
+	uint8_t refclk_max;
+	uint8_t divn_max;
+};
+
+struct stm32mp1_clk_gate {
+	uint16_t offset;
+	uint8_t bit;
+	uint8_t index;
+	uint8_t set_clr;
+	uint8_t sel; /* Relates to enum stm32mp1_parent_sel */
+	uint8_t fixed; /* Relates to enum stm32mp1_parent_id */
+};
+
+struct stm32mp1_clk_sel {
+	uint16_t offset;
+	uint8_t src;
+	uint8_t msk;
+	uint8_t nb_parent;
+	const uint8_t *parent;
+};
+
+#define REFCLK_SIZE 4
+struct stm32mp1_clk_pll {
+	enum stm32mp1_plltype plltype;
+	uint16_t rckxselr;
+	uint16_t pllxcfgr1;
+	uint16_t pllxcfgr2;
+	uint16_t pllxfracr;
+	uint16_t pllxcr;
+	uint16_t pllxcsgr;
+	enum stm32mp_osc_id refclk[REFCLK_SIZE];
+};
+
+/* Clocks with selectable source and non set/clr register access */
+#define _CLK_SELEC(off, b, idx, s)			\
+	{						\
+		.offset = (off),			\
+		.bit = (b),				\
+		.index = (idx),				\
+		.set_clr = 0,				\
+		.sel = (s),				\
+		.fixed = _UNKNOWN_ID,			\
+	}
+
+/* Clocks with fixed source and non set/clr register access */
+#define _CLK_FIXED(off, b, idx, f)			\
+	{						\
+		.offset = (off),			\
+		.bit = (b),				\
+		.index = (idx),				\
+		.set_clr = 0,				\
+		.sel = _UNKNOWN_SEL,			\
+		.fixed = (f),				\
+	}
+
+/* Clocks with selectable source and set/clr register access */
+#define _CLK_SC_SELEC(off, b, idx, s)			\
+	{						\
+		.offset = (off),			\
+		.bit = (b),				\
+		.index = (idx),				\
+		.set_clr = 1,				\
+		.sel = (s),				\
+		.fixed = _UNKNOWN_ID,			\
+	}
+
+/* Clocks with fixed source and set/clr register access */
+#define _CLK_SC_FIXED(off, b, idx, f)			\
+	{						\
+		.offset = (off),			\
+		.bit = (b),				\
+		.index = (idx),				\
+		.set_clr = 1,				\
+		.sel = _UNKNOWN_SEL,			\
+		.fixed = (f),				\
+	}
+
+#define _CLK_PARENT_SEL(_label, _rcc_selr, _parents)		\
+	[_ ## _label ## _SEL] = {				\
+		.offset = _rcc_selr,				\
+		.src = _rcc_selr ## _ ## _label ## SRC_SHIFT,	\
+		.msk = _rcc_selr ## _ ## _label ## SRC_MASK,	\
+		.parent = (_parents),				\
+		.nb_parent = ARRAY_SIZE(_parents)		\
+	}
+
+#define _CLK_PLL(idx, type, off1, off2, off3,		\
+		 off4, off5, off6,			\
+		 p1, p2, p3, p4)			\
+	[(idx)] = {					\
+		.plltype = (type),			\
+		.rckxselr = (off1),			\
+		.pllxcfgr1 = (off2),			\
+		.pllxcfgr2 = (off3),			\
+		.pllxfracr = (off4),			\
+		.pllxcr = (off5),			\
+		.pllxcsgr = (off6),			\
+		.refclk[0] = (p1),			\
+		.refclk[1] = (p2),			\
+		.refclk[2] = (p3),			\
+		.refclk[3] = (p4),			\
+	}
+
+static const uint8_t stm32mp1_clks[][2] = {
+	{ CK_PER, _CK_PER },
+	{ CK_MPU, _CK_MPU },
+	{ CK_AXI, _ACLK },
+	{ CK_MCU, _CK_MCU },
+	{ CK_HSE, _HSE },
+	{ CK_CSI, _CSI },
+	{ CK_LSI, _LSI },
+	{ CK_LSE, _LSE },
+	{ CK_HSI, _HSI },
+	{ CK_HSE_DIV2, _HSE_KER_DIV2 },
+};
+
+#define NB_GATES	ARRAY_SIZE(stm32mp1_clk_gate)
+
+static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
+	_CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK),
+	_CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK),
+	_CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK),
+	_CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK),
+	_CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R),
+	_CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R),
+	_CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4),
+	_CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4),
+	_CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK),
+	_CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4),
+	_CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4),
+
+	_CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
+
+	_CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2),
+	_CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
+
+	_CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID),
+
+	_CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL),
+
+	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL),
+	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL),
+	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5),
+	_CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL),
+
+	_CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL),
+
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL),
+
+	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5),
+	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5),
+	_CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL),
+	_CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5),
+
+	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL),
+	_CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL),
+
+	_CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL),
+};
+
+static const uint8_t i2c12_parents[] = {
+	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
+};
+
+static const uint8_t i2c35_parents[] = {
+	_PCLK1, _PLL4_R, _HSI_KER, _CSI_KER
+};
+
+static const uint8_t stgen_parents[] = {
+	_HSI_KER, _HSE_KER
+};
+
+static const uint8_t i2c46_parents[] = {
+	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER
+};
+
+static const uint8_t spi6_parents[] = {
+	_PCLK5, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER, _PLL3_Q
+};
+
+static const uint8_t usart1_parents[] = {
+	_PCLK5, _PLL3_Q, _HSI_KER, _CSI_KER, _PLL4_Q, _HSE_KER
+};
+
+static const uint8_t rng1_parents[] = {
+	_CSI, _PLL4_R, _LSE, _LSI
+};
+
+static const uint8_t uart6_parents[] = {
+	_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
+};
+
+static const uint8_t uart234578_parents[] = {
+	_PCLK1, _PLL4_Q, _HSI_KER, _CSI_KER, _HSE_KER
+};
+
+static const uint8_t sdmmc12_parents[] = {
+	_HCLK6, _PLL3_R, _PLL4_P, _HSI_KER
+};
+
+static const uint8_t sdmmc3_parents[] = {
+	_HCLK2, _PLL3_R, _PLL4_P, _HSI_KER
+};
+
+static const uint8_t qspi_parents[] = {
+	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
+};
+
+static const uint8_t fmc_parents[] = {
+	_ACLK, _PLL3_R, _PLL4_P, _CK_PER
+};
+
+static const uint8_t ass_parents[] = {
+	_HSI, _HSE, _PLL2
+};
+
+static const uint8_t mss_parents[] = {
+	_HSI, _HSE, _CSI, _PLL3
+};
+
+static const uint8_t usbphy_parents[] = {
+	_HSE_KER, _PLL4_R, _HSE_KER_DIV2
+};
+
+static const uint8_t usbo_parents[] = {
+	_PLL4_R, _USB_PHY_48
+};
+
+static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
+	_CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents),
+	_CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents),
+	_CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents),
+	_CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents),
+	_CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents),
+	_CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents),
+	_CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents),
+	_CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents),
+	_CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents),
+	_CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents),
+	_CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents),
+	_CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents),
+	_CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents),
+	_CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents),
+	_CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents),
+	_CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, ass_parents),
+	_CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mss_parents),
+	_CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents),
+	_CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents),
+};
+
+/* Define characteristic of PLL according type */
+#define DIVN_MIN	24
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+	[PLL_800] = {
+		.refclk_min = 4,
+		.refclk_max = 16,
+		.divn_max = 99,
+	},
+	[PLL_1600] = {
+		.refclk_min = 8,
+		.refclk_max = 16,
+		.divn_max = 199,
+	},
+};
+
+/* PLLNCFGR2 register divider by output */
+static const uint8_t pllncfgr2[_DIV_NB] = {
+	[_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT,
+	[_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT,
+	[_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT,
+};
+
+static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
+	_CLK_PLL(_PLL1, PLL_1600,
+		 RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
+		 RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
+		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
+	_CLK_PLL(_PLL2, PLL_1600,
+		 RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
+		 RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
+		 _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID),
+	_CLK_PLL(_PLL3, PLL_800,
+		 RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
+		 RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
+		 _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID),
+	_CLK_PLL(_PLL4, PLL_800,
+		 RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
+		 RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
+		 _HSI, _HSE, _CSI, _I2S_CKIN),
+};
+
+/* Prescaler table lookups for clock computation */
+/* div = /1 /2 /4 /8 / 16 /64 /128 /512 */
+static const uint8_t stm32mp1_mcu_div[16] = {
+	0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9
+};
+
+/* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */
+#define stm32mp1_mpu_div stm32mp1_mpu_apbx_div
+#define stm32mp1_apbx_div stm32mp1_mpu_apbx_div
+static const uint8_t stm32mp1_mpu_apbx_div[8] = {
+	0, 1, 2, 3, 4, 4, 4, 4
+};
+
+/* div = /1 /2 /3 /4 */
+static const uint8_t stm32mp1_axi_div[8] = {
+	1, 2, 3, 4, 4, 4, 4, 4
+};
+
+/* RCC clock device driver private */
+static unsigned long stm32mp1_osc[NB_OSC];
+static struct spinlock reg_lock;
+static unsigned int gate_refcounts[NB_GATES];
+static struct spinlock refcount_lock;
+
+static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
+{
+	return &stm32mp1_clk_gate[idx];
+}
+
+static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
+{
+	return &stm32mp1_clk_sel[idx];
+}
+
+static const struct stm32mp1_clk_pll *pll_ref(unsigned int idx)
+{
+	return &stm32mp1_clk_pll[idx];
+}
+
+static int stm32mp1_lock_available(void)
+{
+	/* The spinlocks are used only when MMU is enabled */
+	return (read_sctlr() & SCTLR_M_BIT) && (read_sctlr() & SCTLR_C_BIT);
+}
+
+static void stm32mp1_clk_lock(struct spinlock *lock)
+{
+	if (stm32mp1_lock_available() == 0U) {
+		return;
+	}
+
+	/* Assume interrupts are masked */
+	spin_lock(lock);
+}
+
+static void stm32mp1_clk_unlock(struct spinlock *lock)
+{
+	if (stm32mp1_lock_available() == 0U) {
+		return;
+	}
+
+	spin_unlock(lock);
+}
+
+bool stm32mp1_rcc_is_secure(void)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_TZEN) != 0;
+}
+
+bool stm32mp1_rcc_is_mckprot(void)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	return (mmio_read_32(rcc_base + RCC_TZCR) & RCC_TZCR_MCKPROT) != 0;
+}
+
+void stm32mp1_clk_rcc_regs_lock(void)
+{
+	stm32mp1_clk_lock(&reg_lock);
+}
+
+void stm32mp1_clk_rcc_regs_unlock(void)
+{
+	stm32mp1_clk_unlock(&reg_lock);
+}
+
+static unsigned long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx)
+{
+	if (idx >= NB_OSC) {
+		return 0;
+	}
+
+	return stm32mp1_osc[idx];
+}
+
+static int stm32mp1_clk_get_gated_id(unsigned long id)
+{
+	unsigned int i;
+
+	for (i = 0U; i < NB_GATES; i++) {
+		if (gate_ref(i)->index == id) {
+			return i;
+		}
+	}
+
+	ERROR("%s: clk id %d not found\n", __func__, (uint32_t)id);
+
+	return -EINVAL;
+}
+
+static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i)
+{
+	return (enum stm32mp1_parent_sel)(gate_ref(i)->sel);
+}
+
+static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i)
+{
+	return (enum stm32mp1_parent_id)(gate_ref(i)->fixed);
+}
+
+static int stm32mp1_clk_get_parent(unsigned long id)
+{
+	const struct stm32mp1_clk_sel *sel;
+	uint32_t j, p_sel;
+	int i;
+	enum stm32mp1_parent_id p;
+	enum stm32mp1_parent_sel s;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	for (j = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) {
+		if (stm32mp1_clks[j][0] == id) {
+			return (int)stm32mp1_clks[j][1];
+		}
+	}
+
+	i = stm32mp1_clk_get_gated_id(id);
+	if (i < 0) {
+		panic();
+	}
+
+	p = stm32mp1_clk_get_fixed_parent(i);
+	if (p < _PARENT_NB) {
+		return (int)p;
+	}
+
+	s = stm32mp1_clk_get_sel(i);
+	if (s == _UNKNOWN_SEL) {
+		return -EINVAL;
+	}
+	if (s >= _PARENT_SEL_NB) {
+		panic();
+	}
+
+	sel = clk_sel_ref(s);
+	p_sel = (mmio_read_32(rcc_base + sel->offset) & sel->msk) >> sel->src;
+	if (p_sel < sel->nb_parent) {
+		return (int)sel->parent[p_sel];
+	}
+
+	return -EINVAL;
+}
+
+static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll)
+{
+	uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr);
+	uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK;
+
+	return stm32mp1_clk_get_fixed(pll->refclk[src]);
+}
+
+/*
+ * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL
+ * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1)
+ * - PLL3 & PLL4 => return VCO     with Fpll_y_ck = FVCO / (DIVy + 1)
+ * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1)
+ */
+static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll)
+{
+	unsigned long refclk, fvco;
+	uint32_t cfgr1, fracr, divm, divn;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	cfgr1 = mmio_read_32(rcc_base + pll->pllxcfgr1);
+	fracr = mmio_read_32(rcc_base + pll->pllxfracr);
+
+	divm = (cfgr1 & (RCC_PLLNCFGR1_DIVM_MASK)) >> RCC_PLLNCFGR1_DIVM_SHIFT;
+	divn = cfgr1 & RCC_PLLNCFGR1_DIVN_MASK;
+
+	refclk = stm32mp1_pll_get_fref(pll);
+
+	/*
+	 * With FRACV :
+	 *   Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1)
+	 * Without FRACV
+	 *   Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1)
+	 */
+	if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) {
+		uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >>
+				 RCC_PLLNFRACR_FRACV_SHIFT;
+		unsigned long long numerator, denominator;
+
+		numerator = (((unsigned long long)divn + 1U) << 13) + fracv;
+		numerator = refclk * numerator;
+		denominator = ((unsigned long long)divm + 1U) << 13;
+		fvco = (unsigned long)(numerator / denominator);
+	} else {
+		fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U));
+	}
+
+	return fvco;
+}
+
+static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id,
+					    enum stm32mp1_div_id div_id)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	unsigned long dfout;
+	uint32_t cfgr2, divy;
+
+	if (div_id >= _DIV_NB) {
+		return 0;
+	}
+
+	cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2);
+	divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK;
+
+	dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U);
+
+	return dfout;
+}
+
+static unsigned long get_clock_rate(int p)
+{
+	uint32_t reg, clkdiv;
+	unsigned long clock = 0;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	switch (p) {
+	case _CK_MPU:
+	/* MPU sub system */
+		reg = mmio_read_32(rcc_base + RCC_MPCKSELR);
+		switch (reg & RCC_SELR_SRC_MASK) {
+		case RCC_MPCKSELR_HSI:
+			clock = stm32mp1_clk_get_fixed(_HSI);
+			break;
+		case RCC_MPCKSELR_HSE:
+			clock = stm32mp1_clk_get_fixed(_HSE);
+			break;
+		case RCC_MPCKSELR_PLL:
+			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
+			break;
+		case RCC_MPCKSELR_PLL_MPUDIV:
+			clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
+
+			reg = mmio_read_32(rcc_base + RCC_MPCKDIVR);
+			clkdiv = reg & RCC_MPUDIV_MASK;
+			if (clkdiv != 0U) {
+				clock /= stm32mp1_mpu_div[clkdiv];
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	/* AXI sub system */
+	case _ACLK:
+	case _HCLK2:
+	case _HCLK6:
+	case _PCLK4:
+	case _PCLK5:
+		reg = mmio_read_32(rcc_base + RCC_ASSCKSELR);
+		switch (reg & RCC_SELR_SRC_MASK) {
+		case RCC_ASSCKSELR_HSI:
+			clock = stm32mp1_clk_get_fixed(_HSI);
+			break;
+		case RCC_ASSCKSELR_HSE:
+			clock = stm32mp1_clk_get_fixed(_HSE);
+			break;
+		case RCC_ASSCKSELR_PLL:
+			clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
+			break;
+		default:
+			break;
+		}
+
+		/* System clock divider */
+		reg = mmio_read_32(rcc_base + RCC_AXIDIVR);
+		clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK];
+
+		switch (p) {
+		case _PCLK4:
+			reg = mmio_read_32(rcc_base + RCC_APB4DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _PCLK5:
+			reg = mmio_read_32(rcc_base + RCC_APB5DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		default:
+			break;
+		}
+		break;
+	/* MCU sub system */
+	case _CK_MCU:
+	case _PCLK1:
+	case _PCLK2:
+	case _PCLK3:
+		reg = mmio_read_32(rcc_base + RCC_MSSCKSELR);
+		switch (reg & RCC_SELR_SRC_MASK) {
+		case RCC_MSSCKSELR_HSI:
+			clock = stm32mp1_clk_get_fixed(_HSI);
+			break;
+		case RCC_MSSCKSELR_HSE:
+			clock = stm32mp1_clk_get_fixed(_HSE);
+			break;
+		case RCC_MSSCKSELR_CSI:
+			clock = stm32mp1_clk_get_fixed(_CSI);
+			break;
+		case RCC_MSSCKSELR_PLL:
+			clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
+			break;
+		default:
+			break;
+		}
+
+		/* MCU clock divider */
+		reg = mmio_read_32(rcc_base + RCC_MCUDIVR);
+		clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK];
+
+		switch (p) {
+		case _PCLK1:
+			reg = mmio_read_32(rcc_base + RCC_APB1DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _PCLK2:
+			reg = mmio_read_32(rcc_base + RCC_APB2DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _PCLK3:
+			reg = mmio_read_32(rcc_base + RCC_APB3DIVR);
+			clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK];
+			break;
+		case _CK_MCU:
+		default:
+			break;
+		}
+		break;
+	case _CK_PER:
+		reg = mmio_read_32(rcc_base + RCC_CPERCKSELR);
+		switch (reg & RCC_SELR_SRC_MASK) {
+		case RCC_CPERCKSELR_HSI:
+			clock = stm32mp1_clk_get_fixed(_HSI);
+			break;
+		case RCC_CPERCKSELR_HSE:
+			clock = stm32mp1_clk_get_fixed(_HSE);
+			break;
+		case RCC_CPERCKSELR_CSI:
+			clock = stm32mp1_clk_get_fixed(_CSI);
+			break;
+		default:
+			break;
+		}
+		break;
+	case _HSI:
+	case _HSI_KER:
+		clock = stm32mp1_clk_get_fixed(_HSI);
+		break;
+	case _CSI:
+	case _CSI_KER:
+		clock = stm32mp1_clk_get_fixed(_CSI);
+		break;
+	case _HSE:
+	case _HSE_KER:
+		clock = stm32mp1_clk_get_fixed(_HSE);
+		break;
+	case _HSE_KER_DIV2:
+		clock = stm32mp1_clk_get_fixed(_HSE) >> 1;
+		break;
+	case _LSI:
+		clock = stm32mp1_clk_get_fixed(_LSI);
+		break;
+	case _LSE:
+		clock = stm32mp1_clk_get_fixed(_LSE);
+		break;
+	/* PLL */
+	case _PLL1_P:
+		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P);
+		break;
+	case _PLL1_Q:
+		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q);
+		break;
+	case _PLL1_R:
+		clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R);
+		break;
+	case _PLL2_P:
+		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P);
+		break;
+	case _PLL2_Q:
+		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q);
+		break;
+	case _PLL2_R:
+		clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R);
+		break;
+	case _PLL3_P:
+		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P);
+		break;
+	case _PLL3_Q:
+		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q);
+		break;
+	case _PLL3_R:
+		clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R);
+		break;
+	case _PLL4_P:
+		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P);
+		break;
+	case _PLL4_Q:
+		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q);
+		break;
+	case _PLL4_R:
+		clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R);
+		break;
+	/* Other */
+	case _USB_PHY_48:
+		clock = USB_PHY_48_MHZ;
+		break;
+	default:
+		break;
+	}
+
+	return clock;
+}
+
+static void __clk_enable(struct stm32mp1_clk_gate const *gate)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	if (gate->set_clr != 0U) {
+		mmio_write_32(rcc_base + gate->offset, BIT(gate->bit));
+	} else {
+		mmio_setbits_32(rcc_base + gate->offset, BIT(gate->bit));
+	}
+
+	VERBOSE("Clock %d has been enabled", gate->index);
+}
+
+static void __clk_disable(struct stm32mp1_clk_gate const *gate)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	if (gate->set_clr != 0U) {
+		mmio_write_32(rcc_base + gate->offset + RCC_MP_ENCLRR_OFFSET,
+			      BIT(gate->bit));
+	} else {
+		mmio_clrbits_32(rcc_base + gate->offset, BIT(gate->bit));
+	}
+
+	VERBOSE("Clock %d has been disabled", gate->index);
+}
+
+static bool __clk_is_enabled(struct stm32mp1_clk_gate const *gate)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	return mmio_read_32(rcc_base + gate->offset) & BIT(gate->bit);
+}
+
+unsigned int stm32mp1_clk_get_refcount(unsigned long id)
+{
+	int i = stm32mp1_clk_get_gated_id(id);
+
+	if (i < 0) {
+		panic();
+	}
+
+	return gate_refcounts[i];
+}
+
+void __stm32mp1_clk_enable(unsigned long id, bool secure)
+{
+	const struct stm32mp1_clk_gate *gate;
+	int i = stm32mp1_clk_get_gated_id(id);
+	unsigned int *refcnt;
+
+	if (i < 0) {
+		ERROR("Clock %d can't be enabled\n", (uint32_t)id);
+		panic();
+	}
+
+	gate = gate_ref(i);
+	refcnt = &gate_refcounts[i];
+
+	stm32mp1_clk_lock(&refcount_lock);
+
+	if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) {
+		__clk_enable(gate);
+	}
+
+	stm32mp1_clk_unlock(&refcount_lock);
+}
+
+void __stm32mp1_clk_disable(unsigned long id, bool secure)
+{
+	const struct stm32mp1_clk_gate *gate;
+	int i = stm32mp1_clk_get_gated_id(id);
+	unsigned int *refcnt;
+
+	if (i < 0) {
+		ERROR("Clock %d can't be disabled\n", (uint32_t)id);
+		panic();
+	}
+
+	gate = gate_ref(i);
+	refcnt = &gate_refcounts[i];
+
+	stm32mp1_clk_lock(&refcount_lock);
+
+	if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) {
+		__clk_disable(gate);
+	}
+
+	stm32mp1_clk_unlock(&refcount_lock);
+}
+
+void stm32mp_clk_enable(unsigned long id)
+{
+	__stm32mp1_clk_enable(id, true);
+}
+
+void stm32mp_clk_disable(unsigned long id)
+{
+	__stm32mp1_clk_disable(id, true);
+}
+
+bool stm32mp_clk_is_enabled(unsigned long id)
+{
+	int i = stm32mp1_clk_get_gated_id(id);
+
+	if (i < 0) {
+		panic();
+	}
+
+	return __clk_is_enabled(gate_ref(i));
+}
+
+unsigned long stm32mp_clk_get_rate(unsigned long id)
+{
+	int p = stm32mp1_clk_get_parent(id);
+
+	if (p < 0) {
+		return 0;
+	}
+
+	return get_clock_rate(p);
+}
+
+static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
+{
+	uintptr_t address = stm32mp_rcc_base() + offset;
+
+	if (enable) {
+		mmio_setbits_32(address, mask_on);
+	} else {
+		mmio_clrbits_32(address, mask_on);
+	}
+}
+
+static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on)
+{
+	uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR;
+	uintptr_t address = stm32mp_rcc_base() + offset;
+
+	mmio_write_32(address, mask_on);
+}
+
+static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy)
+{
+	uint64_t timeout;
+	uint32_t mask_test;
+	uintptr_t address = stm32mp_rcc_base() + offset;
+
+	if (enable) {
+		mask_test = mask_rdy;
+	} else {
+		mask_test = 0;
+	}
+
+	timeout = timeout_init_us(OSCRDY_TIMEOUT);
+	while ((mmio_read_32(address) & mask_rdy) != mask_test) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n",
+			      mask_rdy, address, enable, mmio_read_32(address));
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static void stm32mp1_lse_enable(bool bypass, bool digbyp, uint32_t lsedrv)
+{
+	uint32_t value;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	if (digbyp) {
+		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_DIGBYP);
+	}
+
+	if (bypass || digbyp) {
+		mmio_setbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEBYP);
+	}
+
+	/*
+	 * Warning: not recommended to switch directly from "high drive"
+	 * to "medium low drive", and vice-versa.
+	 */
+	value = (mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >>
+		RCC_BDCR_LSEDRV_SHIFT;
+
+	while (value != lsedrv) {
+		if (value > lsedrv) {
+			value--;
+		} else {
+			value++;
+		}
+
+		mmio_clrsetbits_32(rcc_base + RCC_BDCR,
+				   RCC_BDCR_LSEDRV_MASK,
+				   value << RCC_BDCR_LSEDRV_SHIFT);
+	}
+
+	stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON);
+}
+
+static void stm32mp1_lse_wait(void)
+{
+	if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) {
+		VERBOSE("%s: failed\n", __func__);
+	}
+}
+
+static void stm32mp1_lsi_set(bool enable)
+{
+	stm32mp1_ls_osc_set(enable, RCC_RDLSICR, RCC_RDLSICR_LSION);
+
+	if (stm32mp1_osc_wait(enable, RCC_RDLSICR, RCC_RDLSICR_LSIRDY) != 0) {
+		VERBOSE("%s: failed\n", __func__);
+	}
+}
+
+static void stm32mp1_hse_enable(bool bypass, bool digbyp, bool css)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	if (digbyp) {
+		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_DIGBYP);
+	}
+
+	if (bypass || digbyp) {
+		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSEBYP);
+	}
+
+	stm32mp1_hs_ocs_set(true, RCC_OCENR_HSEON);
+	if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) {
+		VERBOSE("%s: failed\n", __func__);
+	}
+
+	if (css) {
+		mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON);
+	}
+}
+
+static void stm32mp1_csi_set(bool enable)
+{
+	stm32mp1_hs_ocs_set(enable, RCC_OCENR_CSION);
+	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_CSIRDY) != 0) {
+		VERBOSE("%s: failed\n", __func__);
+	}
+}
+
+static void stm32mp1_hsi_set(bool enable)
+{
+	stm32mp1_hs_ocs_set(enable, RCC_OCENR_HSION);
+	if (stm32mp1_osc_wait(enable, RCC_OCRDYR, RCC_OCRDYR_HSIRDY) != 0) {
+		VERBOSE("%s: failed\n", __func__);
+	}
+}
+
+static int stm32mp1_set_hsidiv(uint8_t hsidiv)
+{
+	uint64_t timeout;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+	uintptr_t address = rcc_base + RCC_OCRDYR;
+
+	mmio_clrsetbits_32(rcc_base + RCC_HSICFGR,
+			   RCC_HSICFGR_HSIDIV_MASK,
+			   RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv);
+
+	timeout = timeout_init_us(HSIDIV_TIMEOUT);
+	while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("HSIDIV failed @ 0x%lx: 0x%x\n",
+			      address, mmio_read_32(address));
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int stm32mp1_hsidiv(unsigned long hsifreq)
+{
+	uint8_t hsidiv;
+	uint32_t hsidivfreq = MAX_HSI_HZ;
+
+	for (hsidiv = 0; hsidiv < 4U; hsidiv++) {
+		if (hsidivfreq == hsifreq) {
+			break;
+		}
+
+		hsidivfreq /= 2U;
+	}
+
+	if (hsidiv == 4U) {
+		ERROR("Invalid clk-hsi frequency\n");
+		return -1;
+	}
+
+	if (hsidiv != 0U) {
+		return stm32mp1_set_hsidiv(hsidiv);
+	}
+
+	return 0;
+}
+
+static bool stm32mp1_check_pll_conf(enum stm32mp1_pll_id pll_id,
+				    unsigned int clksrc,
+				    uint32_t *pllcfg, int plloff)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uintptr_t rcc_base = stm32mp_rcc_base();
+	uintptr_t pllxcr = rcc_base + pll->pllxcr;
+	enum stm32mp1_plltype type = pll->plltype;
+	uintptr_t clksrc_address = rcc_base + (clksrc >> 4);
+	unsigned long refclk;
+	uint32_t ifrge = 0U;
+	uint32_t src, value, fracv;
+
+	/* Check PLL output */
+	if (mmio_read_32(pllxcr) != RCC_PLLNCR_PLLON) {
+		return false;
+	}
+
+	/* Check current clksrc */
+	src = mmio_read_32(clksrc_address) & RCC_SELR_SRC_MASK;
+	if (src != (clksrc & RCC_SELR_SRC_MASK)) {
+		return false;
+	}
+
+	/* Check Div */
+	src = mmio_read_32(rcc_base + pll->rckxselr) & RCC_SELR_REFCLK_SRC_MASK;
+
+	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
+		 (pllcfg[PLLCFG_M] + 1U);
+
+	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
+	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
+		return false;
+	}
+
+	if ((type == PLL_800) && (refclk >= 8000000U)) {
+		ifrge = 1U;
+	}
+
+	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
+		RCC_PLLNCFGR1_DIVN_MASK;
+	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
+		 RCC_PLLNCFGR1_DIVM_MASK;
+	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
+		 RCC_PLLNCFGR1_IFRGE_MASK;
+	if (mmio_read_32(rcc_base + pll->pllxcfgr1) != value) {
+		return false;
+	}
+
+	/* Fractional configuration */
+	fracv = fdt_read_uint32_default(plloff, "frac", 0);
+
+	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
+	value |= RCC_PLLNFRACR_FRACLE;
+	if (mmio_read_32(rcc_base + pll->pllxfracr) != value) {
+		return false;
+	}
+
+	/* Output config */
+	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
+		RCC_PLLNCFGR2_DIVP_MASK;
+	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
+		 RCC_PLLNCFGR2_DIVQ_MASK;
+	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
+		 RCC_PLLNCFGR2_DIVR_MASK;
+	if (mmio_read_32(rcc_base + pll->pllxcfgr2) != value) {
+		return false;
+	}
+
+	return true;
+}
+
+static void stm32mp1_pll_start(enum stm32mp1_pll_id pll_id)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
+
+	/* Preserve RCC_PLLNCR_SSCG_CTRL value */
+	mmio_clrsetbits_32(pllxcr,
+			   RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
+			   RCC_PLLNCR_DIVREN,
+			   RCC_PLLNCR_PLLON);
+}
+
+static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
+	uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT);
+
+	/* Wait PLL lock */
+	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("PLL%d start failed @ 0x%lx: 0x%x\n",
+			      pll_id, pllxcr, mmio_read_32(pllxcr));
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* Start the requested output */
+	mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
+
+	return 0;
+}
+
+static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr;
+	uint64_t timeout;
+
+	/* Stop all output */
+	mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
+			RCC_PLLNCR_DIVREN);
+
+	/* Stop PLL */
+	mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON);
+
+	timeout = timeout_init_us(PLLRDY_TIMEOUT);
+	/* Wait PLL stopped */
+	while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n",
+			      pll_id, pllxcr, mmio_read_32(pllxcr));
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id,
+				       uint32_t *pllcfg)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uintptr_t rcc_base = stm32mp_rcc_base();
+	uint32_t value;
+
+	value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT) &
+		RCC_PLLNCFGR2_DIVP_MASK;
+	value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT) &
+		 RCC_PLLNCFGR2_DIVQ_MASK;
+	value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT) &
+		 RCC_PLLNCFGR2_DIVR_MASK;
+	mmio_write_32(rcc_base + pll->pllxcfgr2, value);
+}
+
+static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id,
+			       uint32_t *pllcfg, uint32_t fracv)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uintptr_t rcc_base = stm32mp_rcc_base();
+	enum stm32mp1_plltype type = pll->plltype;
+	unsigned long refclk;
+	uint32_t ifrge = 0;
+	uint32_t src, value;
+
+	src = mmio_read_32(rcc_base + pll->rckxselr) &
+		RCC_SELR_REFCLK_SRC_MASK;
+
+	refclk = stm32mp1_clk_get_fixed(pll->refclk[src]) /
+		 (pllcfg[PLLCFG_M] + 1U);
+
+	if ((refclk < (stm32mp1_pll[type].refclk_min * 1000000U)) ||
+	    (refclk > (stm32mp1_pll[type].refclk_max * 1000000U))) {
+		return -EINVAL;
+	}
+
+	if ((type == PLL_800) && (refclk >= 8000000U)) {
+		ifrge = 1U;
+	}
+
+	value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT) &
+		RCC_PLLNCFGR1_DIVN_MASK;
+	value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT) &
+		 RCC_PLLNCFGR1_DIVM_MASK;
+	value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT) &
+		 RCC_PLLNCFGR1_IFRGE_MASK;
+	mmio_write_32(rcc_base + pll->pllxcfgr1, value);
+
+	/* Fractional configuration */
+	value = 0;
+	mmio_write_32(rcc_base + pll->pllxfracr, value);
+
+	value = fracv << RCC_PLLNFRACR_FRACV_SHIFT;
+	mmio_write_32(rcc_base + pll->pllxfracr, value);
+
+	value |= RCC_PLLNFRACR_FRACLE;
+	mmio_write_32(rcc_base + pll->pllxfracr, value);
+
+	stm32mp1_pll_config_output(pll_id, pllcfg);
+
+	return 0;
+}
+
+static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg)
+{
+	const struct stm32mp1_clk_pll *pll = pll_ref(pll_id);
+	uint32_t pllxcsg = 0;
+
+	pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
+		    RCC_PLLNCSGR_MOD_PER_MASK;
+
+	pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
+		    RCC_PLLNCSGR_INC_STEP_MASK;
+
+	pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
+		    RCC_PLLNCSGR_SSCG_MODE_MASK;
+
+	mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg);
+
+	mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr,
+			RCC_PLLNCR_SSCG_CTRL);
+}
+
+static int stm32mp1_set_clksrc(unsigned int clksrc)
+{
+	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
+	uint64_t timeout;
+
+	mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK,
+			   clksrc & RCC_SELR_SRC_MASK);
+
+	timeout = timeout_init_us(CLKSRC_TIMEOUT);
+	while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc,
+			      clksrc_address, mmio_read_32(clksrc_address));
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address)
+{
+	uint64_t timeout;
+
+	mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK,
+			   clkdiv & RCC_DIVR_DIV_MASK);
+
+	timeout = timeout_init_us(CLKDIV_TIMEOUT);
+	while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n",
+			      clkdiv, address, mmio_read_32(address));
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv)
+{
+	uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4);
+
+	/*
+	 * Binding clksrc :
+	 *      bit15-4 offset
+	 *      bit3:   disable
+	 *      bit2-0: MCOSEL[2:0]
+	 */
+	if ((clksrc & 0x8U) != 0U) {
+		mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON);
+	} else {
+		mmio_clrsetbits_32(clksrc_address,
+				   RCC_MCOCFG_MCOSRC_MASK,
+				   clksrc & RCC_MCOCFG_MCOSRC_MASK);
+		mmio_clrsetbits_32(clksrc_address,
+				   RCC_MCOCFG_MCODIV_MASK,
+				   clkdiv << RCC_MCOCFG_MCODIV_SHIFT);
+		mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON);
+	}
+}
+
+static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css)
+{
+	uintptr_t address = stm32mp_rcc_base() + RCC_BDCR;
+
+	if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) ||
+	    (clksrc != (uint32_t)CLK_RTC_DISABLED)) {
+		mmio_clrsetbits_32(address,
+				   RCC_BDCR_RTCSRC_MASK,
+				   clksrc << RCC_BDCR_RTCSRC_SHIFT);
+
+		mmio_setbits_32(address, RCC_BDCR_RTCCKEN);
+	}
+
+	if (lse_css) {
+		mmio_setbits_32(address, RCC_BDCR_LSECSSON);
+	}
+}
+
+static void stm32mp1_stgen_config(void)
+{
+	uintptr_t stgen;
+	uint32_t cntfid0;
+	unsigned long rate;
+	unsigned long long counter;
+
+	stgen = fdt_get_stgen_base();
+	cntfid0 = mmio_read_32(stgen + CNTFID_OFF);
+	rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K));
+
+	if (cntfid0 == rate) {
+		return;
+	}
+
+	mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+	counter = (unsigned long long)mmio_read_32(stgen + CNTCVL_OFF);
+	counter |= ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF)) << 32;
+	counter = (counter * rate / cntfid0);
+
+	mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)counter);
+	mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(counter >> 32));
+	mmio_write_32(stgen + CNTFID_OFF, rate);
+	mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+
+	write_cntfrq((u_register_t)rate);
+
+	/* Need to update timer with new frequency */
+	generic_delay_timer_init();
+}
+
+void stm32mp1_stgen_increment(unsigned long long offset_in_ms)
+{
+	uintptr_t stgen;
+	unsigned long long cnt;
+
+	stgen = fdt_get_stgen_base();
+
+	cnt = ((unsigned long long)mmio_read_32(stgen + CNTCVU_OFF) << 32) |
+		mmio_read_32(stgen + CNTCVL_OFF);
+
+	cnt += (offset_in_ms * mmio_read_32(stgen + CNTFID_OFF)) / 1000U;
+
+	mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+	mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt);
+	mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(cnt >> 32));
+	mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN);
+}
+
+static void stm32mp1_pkcs_config(uint32_t pkcs)
+{
+	uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU);
+	uint32_t value = pkcs & 0xFU;
+	uint32_t mask = 0xFU;
+
+	if ((pkcs & BIT(31)) != 0U) {
+		mask <<= 4;
+		value <<= 4;
+	}
+
+	mmio_clrsetbits_32(address, mask, value);
+}
+
+int stm32mp1_clk_init(void)
+{
+	uintptr_t rcc_base = stm32mp_rcc_base();
+	unsigned int clksrc[CLKSRC_NB];
+	unsigned int clkdiv[CLKDIV_NB];
+	unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
+	int plloff[_PLL_NB];
+	int ret, len;
+	enum stm32mp1_pll_id i;
+	bool lse_css = false;
+	bool pll3_preserve = false;
+	bool pll4_preserve = false;
+	bool pll4_bootrom = false;
+	const fdt32_t *pkcs_cell;
+
+	/* Check status field to disable security */
+	if (!fdt_get_rcc_secure_status()) {
+		mmio_write_32(rcc_base + RCC_TZCR, 0);
+	}
+
+	ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc,
+					(uint32_t)CLKSRC_NB);
+	if (ret < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv,
+					(uint32_t)CLKDIV_NB);
+	if (ret < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+		char name[12];
+
+		snprintf(name, sizeof(name), "st,pll@%d", i);
+		plloff[i] = fdt_rcc_subnode_offset(name);
+
+		if (!fdt_check_node(plloff[i])) {
+			continue;
+		}
+
+		ret = fdt_read_uint32_array(plloff[i], "cfg",
+					    pllcfg[i], (int)PLLCFG_NB);
+		if (ret < 0) {
+			return -FDT_ERR_NOTFOUND;
+		}
+	}
+
+	stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]);
+	stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]);
+
+	/*
+	 * Switch ON oscillator found in device-tree.
+	 * Note: HSI already ON after BootROM stage.
+	 */
+	if (stm32mp1_osc[_LSI] != 0U) {
+		stm32mp1_lsi_set(true);
+	}
+	if (stm32mp1_osc[_LSE] != 0U) {
+		bool bypass, digbyp;
+		uint32_t lsedrv;
+
+		bypass = fdt_osc_read_bool(_LSE, "st,bypass");
+		digbyp = fdt_osc_read_bool(_LSE, "st,digbypass");
+		lse_css = fdt_osc_read_bool(_LSE, "st,css");
+		lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive",
+						     LSEDRV_MEDIUM_HIGH);
+		stm32mp1_lse_enable(bypass, digbyp, lsedrv);
+	}
+	if (stm32mp1_osc[_HSE] != 0U) {
+		bool bypass, digbyp, css;
+
+		bypass = fdt_osc_read_bool(_HSE, "st,bypass");
+		digbyp = fdt_osc_read_bool(_HSE, "st,digbypass");
+		css = fdt_osc_read_bool(_HSE, "st,css");
+		stm32mp1_hse_enable(bypass, digbyp, css);
+	}
+	/*
+	 * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
+	 * => switch on CSI even if node is not present in device tree
+	 */
+	stm32mp1_csi_set(true);
+
+	/* Come back to HSI */
+	ret = stm32mp1_set_clksrc(CLK_MPU_HSI);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clksrc(CLK_AXI_HSI);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clksrc(CLK_MCU_HSI);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if ((mmio_read_32(rcc_base + RCC_MP_RSTSCLRR) &
+	     RCC_MP_RSTSCLRR_MPUP0RSTF) != 0) {
+		pll3_preserve = stm32mp1_check_pll_conf(_PLL3,
+							clksrc[CLKSRC_PLL3],
+							pllcfg[_PLL3],
+							plloff[_PLL3]);
+		pll4_preserve = stm32mp1_check_pll_conf(_PLL4,
+							clksrc[CLKSRC_PLL4],
+							pllcfg[_PLL4],
+							plloff[_PLL4]);
+	}
+
+	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+		if (((i == _PLL3) && pll3_preserve) ||
+		    ((i == _PLL4) && pll4_preserve)) {
+			continue;
+		}
+
+		ret = stm32mp1_pll_stop(i);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	/* Configure HSIDIV */
+	if (stm32mp1_osc[_HSI] != 0U) {
+		ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]);
+		if (ret != 0) {
+			return ret;
+		}
+		stm32mp1_stgen_config();
+	}
+
+	/* Select DIV */
+	/* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
+	mmio_write_32(rcc_base + RCC_MPCKDIVR,
+		      clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK);
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_AXI], rcc_base + RCC_AXIDIVR);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB4], rcc_base + RCC_APB4DIVR);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB5], rcc_base + RCC_APB5DIVR);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB3], rcc_base + RCC_APB3DIVR);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* No ready bit for RTC */
+	mmio_write_32(rcc_base + RCC_RTCDIVR,
+		      clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK);
+
+	/* Configure PLLs source */
+	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (!pll3_preserve) {
+		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	if (!pll4_preserve) {
+		ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	/* Configure and start PLLs */
+	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+		uint32_t fracv;
+		uint32_t csg[PLLCSG_NB];
+
+		if (((i == _PLL3) && pll3_preserve) ||
+		    ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) {
+			continue;
+		}
+
+		if (!fdt_check_node(plloff[i])) {
+			continue;
+		}
+
+		if ((i == _PLL4) && pll4_bootrom) {
+			/* Set output divider if not done by the Bootrom */
+			stm32mp1_pll_config_output(i, pllcfg[i]);
+			continue;
+		}
+
+		fracv = fdt_read_uint32_default(plloff[i], "frac", 0);
+
+		ret = stm32mp1_pll_config(i, pllcfg[i], fracv);
+		if (ret != 0) {
+			return ret;
+		}
+		ret = fdt_read_uint32_array(plloff[i], "csg", csg,
+					    (uint32_t)PLLCSG_NB);
+		if (ret == 0) {
+			stm32mp1_pll_csg(i, csg);
+		} else if (ret != -FDT_ERR_NOTFOUND) {
+			return ret;
+		}
+
+		stm32mp1_pll_start(i);
+	}
+	/* Wait and start PLLs ouptut when ready */
+	for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) {
+		if (!fdt_check_node(plloff[i])) {
+			continue;
+		}
+
+		ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+	/* Wait LSE ready before to use it */
+	if (stm32mp1_osc[_LSE] != 0U) {
+		stm32mp1_lse_wait();
+	}
+
+	/* Configure with expected clock source */
+	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]);
+	if (ret != 0) {
+		return ret;
+	}
+	ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MCU]);
+	if (ret != 0) {
+		return ret;
+	}
+	stm32mp1_set_rtcsrc(clksrc[CLKSRC_RTC], lse_css);
+
+	/* Configure PKCK */
+	pkcs_cell = fdt_rcc_read_prop("st,pkcs", &len);
+	if (pkcs_cell != NULL) {
+		bool ckper_disabled = false;
+		uint32_t j;
+
+		for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) {
+			uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]);
+
+			if (pkcs == (uint32_t)CLK_CKPER_DISABLED) {
+				ckper_disabled = true;
+				continue;
+			}
+			stm32mp1_pkcs_config(pkcs);
+		}
+
+		/*
+		 * CKPER is source for some peripheral clocks
+		 * (FMC-NAND / QPSI-NOR) and switching source is allowed
+		 * only if previous clock is still ON
+		 * => deactivated CKPER only after switching clock
+		 */
+		if (ckper_disabled) {
+			stm32mp1_pkcs_config(CLK_CKPER_DISABLED);
+		}
+	}
+
+	/* Switch OFF HSI if not found in device-tree */
+	if (stm32mp1_osc[_HSI] == 0U) {
+		stm32mp1_hsi_set(false);
+	}
+	stm32mp1_stgen_config();
+
+	/* Software Self-Refresh mode (SSR) during DDR initilialization */
+	mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR,
+			   RCC_DDRITFCR_DDRCKMOD_MASK,
+			   RCC_DDRITFCR_DDRCKMOD_SSR <<
+			   RCC_DDRITFCR_DDRCKMOD_SHIFT);
+
+	return 0;
+}
+
+static void stm32mp1_osc_clk_init(const char *name,
+				  enum stm32mp_osc_id index)
+{
+	uint32_t frequency;
+
+	if (fdt_osc_read_freq(name, &frequency) == 0) {
+		stm32mp1_osc[index] = frequency;
+	}
+}
+
+static void stm32mp1_osc_init(void)
+{
+	enum stm32mp_osc_id i;
+
+	for (i = (enum stm32mp_osc_id)0 ; i < NB_OSC; i++) {
+		stm32mp1_osc_clk_init(stm32mp_osc_node_label[i], i);
+	}
+}
+
+int stm32mp1_clk_probe(void)
+{
+	stm32mp1_osc_init();
+
+	return 0;
+}
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
new file mode 100644
index 0000000..87c8e2b
--- /dev/null
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+
+#define DT_STGEN_COMPAT		"st,stm32-stgen"
+
+/*
+ * Get the frequency of an oscillator from its name in device tree.
+ * @param name: oscillator name
+ * @param freq: stores the frequency of the oscillator
+ * @return: 0 on success, and a negative FDT/ERRNO error code on failure.
+ */
+int fdt_osc_read_freq(const char *name, uint32_t *freq)
+{
+	int node, subnode;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	node = fdt_path_offset(fdt, "/clocks");
+	if (node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	fdt_for_each_subnode(subnode, fdt, node) {
+		const char *cchar;
+		int ret;
+
+		cchar = fdt_get_name(fdt, subnode, &ret);
+		if (cchar == NULL) {
+			return ret;
+		}
+
+		if (strncmp(cchar, name, (size_t)ret) == 0) {
+			const fdt32_t *cuint;
+
+			cuint = fdt_getprop(fdt, subnode, "clock-frequency",
+					    &ret);
+			if (cuint == NULL) {
+				return ret;
+			}
+
+			*freq = fdt32_to_cpu(*cuint);
+
+			return 0;
+		}
+	}
+
+	/* Oscillator not found, freq=0 */
+	*freq = 0;
+	return 0;
+}
+
+/*
+ * Check the presence of an oscillator property from its id.
+ * @param osc_id: oscillator ID
+ * @param prop_name: property name
+ * @return: true/false regarding search result.
+ */
+bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
+{
+	int node, subnode;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return false;
+	}
+
+	if (osc_id >= NB_OSC) {
+		return false;
+	}
+
+	node = fdt_path_offset(fdt, "/clocks");
+	if (node < 0) {
+		return false;
+	}
+
+	fdt_for_each_subnode(subnode, fdt, node) {
+		const char *cchar;
+		int ret;
+
+		cchar = fdt_get_name(fdt, subnode, &ret);
+		if (cchar == NULL) {
+			return false;
+		}
+
+		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
+			    (size_t)ret) != 0) {
+			continue;
+		}
+
+		if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/*
+ * Get the value of a oscillator property from its ID.
+ * @param osc_id: oscillator ID
+ * @param prop_name: property name
+ * @param dflt_value: default value
+ * @return oscillator value on success, default value if property not found.
+ */
+uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
+				     const char *prop_name, uint32_t dflt_value)
+{
+	int node, subnode;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return dflt_value;
+	}
+
+	if (osc_id >= NB_OSC) {
+		return dflt_value;
+	}
+
+	node = fdt_path_offset(fdt, "/clocks");
+	if (node < 0) {
+		return dflt_value;
+	}
+
+	fdt_for_each_subnode(subnode, fdt, node) {
+		const char *cchar;
+		int ret;
+
+		cchar = fdt_get_name(fdt, subnode, &ret);
+		if (cchar == NULL) {
+			return dflt_value;
+		}
+
+		if (strncmp(cchar, stm32mp_osc_node_label[osc_id],
+			    (size_t)ret) != 0) {
+			continue;
+		}
+
+		return fdt_read_uint32_default(subnode, prop_name, dflt_value);
+	}
+
+	return dflt_value;
+}
+
+/*
+ * Get the RCC node offset from the device tree
+ * @param fdt: Device tree reference
+ * @return: Node offset or a negative value on error
+ */
+int fdt_get_rcc_node(void *fdt)
+{
+	return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+}
+
+/*
+ * Get the RCC base address from the device tree
+ * @return: RCC address or 0 on error
+ */
+uint32_t fdt_rcc_read_addr(void)
+{
+	int node;
+	void *fdt;
+	const fdt32_t *cuint;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return 0;
+	}
+
+	node = fdt_get_rcc_node(fdt);
+	if (node < 0) {
+		return 0;
+	}
+
+	cuint = fdt_getprop(fdt, node, "reg", NULL);
+	if (cuint == NULL) {
+		return 0;
+	}
+
+	return fdt32_to_cpu(*cuint);
+}
+
+/*
+ * Read a series of parameters in rcc-clk section in device tree
+ * @param prop_name: Name of the RCC property to be read
+ * @param array: the array to store the property parameters
+ * @param count: number of parameters to be read
+ * @return: 0 on succes or a negative value on error
+ */
+int fdt_rcc_read_uint32_array(const char *prop_name,
+			      uint32_t *array, uint32_t count)
+{
+	int node;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	node = fdt_get_rcc_node(fdt);
+	if (node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	return fdt_read_uint32_array(node, prop_name, array, count);
+}
+
+/*
+ * Get the subnode offset in rcc-clk section from its name in device tree
+ * @param name: name of the RCC property
+ * @return: offset on success, and a negative FDT/ERRNO error code on failure.
+ */
+int fdt_rcc_subnode_offset(const char *name)
+{
+	int node, subnode;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	node = fdt_get_rcc_node(fdt);
+	if (node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	subnode = fdt_subnode_offset(fdt, node, name);
+	if (subnode <= 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	return subnode;
+}
+
+/*
+ * Get the pointer to a rcc-clk property from its name.
+ * @param name: name of the RCC property
+ * @param lenp: stores the length of the property.
+ * @return: pointer to the property on success, and NULL value on failure.
+ */
+const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
+{
+	const fdt32_t *cuint;
+	int node, len;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return NULL;
+	}
+
+	node = fdt_get_rcc_node(fdt);
+	if (node < 0) {
+		return NULL;
+	}
+
+	cuint = fdt_getprop(fdt, node, prop_name, &len);
+	if (cuint == NULL) {
+		return NULL;
+	}
+
+	*lenp = len;
+	return cuint;
+}
+
+/*
+ * Get the secure status for rcc node in device tree.
+ * @return: true if rcc is available from secure world, false if not.
+ */
+bool fdt_get_rcc_secure_status(void)
+{
+	int node;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return false;
+	}
+
+	node = fdt_get_rcc_node(fdt);
+	if (node < 0) {
+		return false;
+	}
+
+	return !!(fdt_get_status(node) & DT_SECURE);
+}
+
+/*
+ * Get the stgen base address.
+ * @return: address of stgen on success, and NULL value on failure.
+ */
+uintptr_t fdt_get_stgen_base(void)
+{
+	int node;
+	const fdt32_t *cuint;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return 0;
+	}
+
+	node = fdt_node_offset_by_compatible(fdt, -1, DT_STGEN_COMPAT);
+	if (node < 0) {
+		return 0;
+	}
+
+	cuint = fdt_getprop(fdt, node, "reg", NULL);
+	if (cuint == NULL) {
+		return 0;
+	}
+
+	return fdt32_to_cpu(*cuint);
+}
+
+/*
+ * Get the clock ID of the given node in device tree.
+ * @param node: node offset
+ * @return: Clock ID on success, and a negative FDT/ERRNO error code on failure.
+ */
+int fdt_get_clock_id(int node)
+{
+	const fdt32_t *cuint;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	cuint = fdt_getprop(fdt, node, "clocks", NULL);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	cuint++;
+	return (int)fdt32_to_cpu(*cuint);
+}
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
new file mode 100644
index 0000000..caf8eef
--- /dev/null
+++ b/drivers/st/ddr/stm32mp1_ddr.c
@@ -0,0 +1,918 @@
+/*
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <drivers/st/stm32mp1_ddr.h>
+#include <drivers/st/stm32mp1_ddr_regs.h>
+#include <drivers/st/stm32mp1_pwr.h>
+#include <drivers/st/stm32mp1_ram.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+struct reg_desc {
+	const char *name;
+	uint16_t offset;	/* Offset for base address */
+	uint8_t par_offset;	/* Offset for parameter array */
+};
+
+#define INVALID_OFFSET	0xFFU
+
+#define TIMEOUT_US_1S	1000000U
+
+#define DDRCTL_REG(x, y)					\
+	{							\
+		.name = #x,					\
+		.offset = offsetof(struct stm32mp1_ddrctl, x),	\
+		.par_offset = offsetof(struct y, x)		\
+	}
+
+#define DDRPHY_REG(x, y)					\
+	{							\
+		.name = #x,					\
+		.offset = offsetof(struct stm32mp1_ddrphy, x),	\
+		.par_offset = offsetof(struct y, x)		\
+	}
+
+#define DDRCTL_REG_REG(x)	DDRCTL_REG(x, stm32mp1_ddrctrl_reg)
+static const struct reg_desc ddr_reg[] = {
+	DDRCTL_REG_REG(mstr),
+	DDRCTL_REG_REG(mrctrl0),
+	DDRCTL_REG_REG(mrctrl1),
+	DDRCTL_REG_REG(derateen),
+	DDRCTL_REG_REG(derateint),
+	DDRCTL_REG_REG(pwrctl),
+	DDRCTL_REG_REG(pwrtmg),
+	DDRCTL_REG_REG(hwlpctl),
+	DDRCTL_REG_REG(rfshctl0),
+	DDRCTL_REG_REG(rfshctl3),
+	DDRCTL_REG_REG(crcparctl0),
+	DDRCTL_REG_REG(zqctl0),
+	DDRCTL_REG_REG(dfitmg0),
+	DDRCTL_REG_REG(dfitmg1),
+	DDRCTL_REG_REG(dfilpcfg0),
+	DDRCTL_REG_REG(dfiupd0),
+	DDRCTL_REG_REG(dfiupd1),
+	DDRCTL_REG_REG(dfiupd2),
+	DDRCTL_REG_REG(dfiphymstr),
+	DDRCTL_REG_REG(odtmap),
+	DDRCTL_REG_REG(dbg0),
+	DDRCTL_REG_REG(dbg1),
+	DDRCTL_REG_REG(dbgcmd),
+	DDRCTL_REG_REG(poisoncfg),
+	DDRCTL_REG_REG(pccfg),
+};
+
+#define DDRCTL_REG_TIMING(x)	DDRCTL_REG(x, stm32mp1_ddrctrl_timing)
+static const struct reg_desc ddr_timing[] = {
+	DDRCTL_REG_TIMING(rfshtmg),
+	DDRCTL_REG_TIMING(dramtmg0),
+	DDRCTL_REG_TIMING(dramtmg1),
+	DDRCTL_REG_TIMING(dramtmg2),
+	DDRCTL_REG_TIMING(dramtmg3),
+	DDRCTL_REG_TIMING(dramtmg4),
+	DDRCTL_REG_TIMING(dramtmg5),
+	DDRCTL_REG_TIMING(dramtmg6),
+	DDRCTL_REG_TIMING(dramtmg7),
+	DDRCTL_REG_TIMING(dramtmg8),
+	DDRCTL_REG_TIMING(dramtmg14),
+	DDRCTL_REG_TIMING(odtcfg),
+};
+
+#define DDRCTL_REG_MAP(x)	DDRCTL_REG(x, stm32mp1_ddrctrl_map)
+static const struct reg_desc ddr_map[] = {
+	DDRCTL_REG_MAP(addrmap1),
+	DDRCTL_REG_MAP(addrmap2),
+	DDRCTL_REG_MAP(addrmap3),
+	DDRCTL_REG_MAP(addrmap4),
+	DDRCTL_REG_MAP(addrmap5),
+	DDRCTL_REG_MAP(addrmap6),
+	DDRCTL_REG_MAP(addrmap9),
+	DDRCTL_REG_MAP(addrmap10),
+	DDRCTL_REG_MAP(addrmap11),
+};
+
+#define DDRCTL_REG_PERF(x)	DDRCTL_REG(x, stm32mp1_ddrctrl_perf)
+static const struct reg_desc ddr_perf[] = {
+	DDRCTL_REG_PERF(sched),
+	DDRCTL_REG_PERF(sched1),
+	DDRCTL_REG_PERF(perfhpr1),
+	DDRCTL_REG_PERF(perflpr1),
+	DDRCTL_REG_PERF(perfwr1),
+	DDRCTL_REG_PERF(pcfgr_0),
+	DDRCTL_REG_PERF(pcfgw_0),
+	DDRCTL_REG_PERF(pcfgqos0_0),
+	DDRCTL_REG_PERF(pcfgqos1_0),
+	DDRCTL_REG_PERF(pcfgwqos0_0),
+	DDRCTL_REG_PERF(pcfgwqos1_0),
+	DDRCTL_REG_PERF(pcfgr_1),
+	DDRCTL_REG_PERF(pcfgw_1),
+	DDRCTL_REG_PERF(pcfgqos0_1),
+	DDRCTL_REG_PERF(pcfgqos1_1),
+	DDRCTL_REG_PERF(pcfgwqos0_1),
+	DDRCTL_REG_PERF(pcfgwqos1_1),
+};
+
+#define DDRPHY_REG_REG(x)	DDRPHY_REG(x, stm32mp1_ddrphy_reg)
+static const struct reg_desc ddrphy_reg[] = {
+	DDRPHY_REG_REG(pgcr),
+	DDRPHY_REG_REG(aciocr),
+	DDRPHY_REG_REG(dxccr),
+	DDRPHY_REG_REG(dsgcr),
+	DDRPHY_REG_REG(dcr),
+	DDRPHY_REG_REG(odtcr),
+	DDRPHY_REG_REG(zq0cr1),
+	DDRPHY_REG_REG(dx0gcr),
+	DDRPHY_REG_REG(dx1gcr),
+	DDRPHY_REG_REG(dx2gcr),
+	DDRPHY_REG_REG(dx3gcr),
+};
+
+#define DDRPHY_REG_TIMING(x)	DDRPHY_REG(x, stm32mp1_ddrphy_timing)
+static const struct reg_desc ddrphy_timing[] = {
+	DDRPHY_REG_TIMING(ptr0),
+	DDRPHY_REG_TIMING(ptr1),
+	DDRPHY_REG_TIMING(ptr2),
+	DDRPHY_REG_TIMING(dtpr0),
+	DDRPHY_REG_TIMING(dtpr1),
+	DDRPHY_REG_TIMING(dtpr2),
+	DDRPHY_REG_TIMING(mr0),
+	DDRPHY_REG_TIMING(mr1),
+	DDRPHY_REG_TIMING(mr2),
+	DDRPHY_REG_TIMING(mr3),
+};
+
+#define DDRPHY_REG_CAL(x)	DDRPHY_REG(x, stm32mp1_ddrphy_cal)
+static const struct reg_desc ddrphy_cal[] = {
+	DDRPHY_REG_CAL(dx0dllcr),
+	DDRPHY_REG_CAL(dx0dqtr),
+	DDRPHY_REG_CAL(dx0dqstr),
+	DDRPHY_REG_CAL(dx1dllcr),
+	DDRPHY_REG_CAL(dx1dqtr),
+	DDRPHY_REG_CAL(dx1dqstr),
+	DDRPHY_REG_CAL(dx2dllcr),
+	DDRPHY_REG_CAL(dx2dqtr),
+	DDRPHY_REG_CAL(dx2dqstr),
+	DDRPHY_REG_CAL(dx3dllcr),
+	DDRPHY_REG_CAL(dx3dqtr),
+	DDRPHY_REG_CAL(dx3dqstr),
+};
+
+#define DDR_REG_DYN(x)						\
+	{							\
+		.name = #x,					\
+		.offset = offsetof(struct stm32mp1_ddrctl, x),	\
+		.par_offset = INVALID_OFFSET \
+	}
+
+static const struct reg_desc ddr_dyn[] = {
+	DDR_REG_DYN(stat),
+	DDR_REG_DYN(init0),
+	DDR_REG_DYN(dfimisc),
+	DDR_REG_DYN(dfistat),
+	DDR_REG_DYN(swctl),
+	DDR_REG_DYN(swstat),
+	DDR_REG_DYN(pctrl_0),
+	DDR_REG_DYN(pctrl_1),
+};
+
+#define DDRPHY_REG_DYN(x)					\
+	{							\
+		.name = #x,					\
+		.offset = offsetof(struct stm32mp1_ddrphy, x),	\
+		.par_offset = INVALID_OFFSET			\
+	}
+
+static const struct reg_desc ddrphy_dyn[] = {
+	DDRPHY_REG_DYN(pir),
+	DDRPHY_REG_DYN(pgsr),
+};
+
+enum reg_type {
+	REG_REG,
+	REG_TIMING,
+	REG_PERF,
+	REG_MAP,
+	REGPHY_REG,
+	REGPHY_TIMING,
+	REGPHY_CAL,
+/*
+ * Dynamic registers => managed in driver or not changed,
+ * can be dumped in interactive mode.
+ */
+	REG_DYN,
+	REGPHY_DYN,
+	REG_TYPE_NB
+};
+
+enum base_type {
+	DDR_BASE,
+	DDRPHY_BASE,
+	NONE_BASE
+};
+
+struct ddr_reg_info {
+	const char *name;
+	const struct reg_desc *desc;
+	uint8_t size;
+	enum base_type base;
+};
+
+static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
+	[REG_REG] = {
+		.name = "static",
+		.desc = ddr_reg,
+		.size = ARRAY_SIZE(ddr_reg),
+		.base = DDR_BASE
+	},
+	[REG_TIMING] = {
+		.name = "timing",
+		.desc = ddr_timing,
+		.size = ARRAY_SIZE(ddr_timing),
+		.base = DDR_BASE
+	},
+	[REG_PERF] = {
+		.name = "perf",
+		.desc = ddr_perf,
+		.size = ARRAY_SIZE(ddr_perf),
+		.base = DDR_BASE
+	},
+	[REG_MAP] = {
+		.name = "map",
+		.desc = ddr_map,
+		.size = ARRAY_SIZE(ddr_map),
+		.base = DDR_BASE
+	},
+	[REGPHY_REG] = {
+		.name = "static",
+		.desc = ddrphy_reg,
+		.size = ARRAY_SIZE(ddrphy_reg),
+		.base = DDRPHY_BASE
+	},
+	[REGPHY_TIMING] = {
+		.name = "timing",
+		.desc = ddrphy_timing,
+		.size = ARRAY_SIZE(ddrphy_timing),
+		.base = DDRPHY_BASE
+	},
+	[REGPHY_CAL] = {
+		.name = "cal",
+		.desc = ddrphy_cal,
+		.size = ARRAY_SIZE(ddrphy_cal),
+		.base = DDRPHY_BASE
+	},
+	[REG_DYN] = {
+		.name = "dyn",
+		.desc = ddr_dyn,
+		.size = ARRAY_SIZE(ddr_dyn),
+		.base = DDR_BASE
+	},
+	[REGPHY_DYN] = {
+		.name = "dyn",
+		.desc = ddrphy_dyn,
+		.size = ARRAY_SIZE(ddrphy_dyn),
+		.base = DDRPHY_BASE
+	},
+};
+
+static uintptr_t get_base_addr(const struct ddr_info *priv, enum base_type base)
+{
+	if (base == DDRPHY_BASE) {
+		return (uintptr_t)priv->phy;
+	} else {
+		return (uintptr_t)priv->ctl;
+	}
+}
+
+static void set_reg(const struct ddr_info *priv,
+		    enum reg_type type,
+		    const void *param)
+{
+	unsigned int i;
+	unsigned int value;
+	enum base_type base = ddr_registers[type].base;
+	uintptr_t base_addr = get_base_addr(priv, base);
+	const struct reg_desc *desc = ddr_registers[type].desc;
+
+	VERBOSE("init %s\n", ddr_registers[type].name);
+	for (i = 0; i < ddr_registers[type].size; i++) {
+		uintptr_t ptr = base_addr + desc[i].offset;
+
+		if (desc[i].par_offset == INVALID_OFFSET) {
+			ERROR("invalid parameter offset for %s", desc[i].name);
+			panic();
+		} else {
+			value = *((uint32_t *)((uintptr_t)param +
+					       desc[i].par_offset));
+			mmio_write_32(ptr, value);
+		}
+	}
+}
+
+static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
+{
+	uint32_t pgsr;
+	int error = 0;
+	uint64_t timeout = timeout_init_us(TIMEOUT_US_1S);
+
+	do {
+		pgsr = mmio_read_32((uintptr_t)&phy->pgsr);
+
+		VERBOSE("  > [0x%lx] pgsr = 0x%x &\n",
+			(uintptr_t)&phy->pgsr, pgsr);
+
+		if (timeout_elapsed(timeout)) {
+			panic();
+		}
+
+		if ((pgsr & DDRPHYC_PGSR_DTERR) != 0U) {
+			VERBOSE("DQS Gate Trainig Error\n");
+			error++;
+		}
+
+		if ((pgsr & DDRPHYC_PGSR_DTIERR) != 0U) {
+			VERBOSE("DQS Gate Trainig Intermittent Error\n");
+			error++;
+		}
+
+		if ((pgsr & DDRPHYC_PGSR_DFTERR) != 0U) {
+			VERBOSE("DQS Drift Error\n");
+			error++;
+		}
+
+		if ((pgsr & DDRPHYC_PGSR_RVERR) != 0U) {
+			VERBOSE("Read Valid Training Error\n");
+			error++;
+		}
+
+		if ((pgsr & DDRPHYC_PGSR_RVEIRR) != 0U) {
+			VERBOSE("Read Valid Training Intermittent Error\n");
+			error++;
+		}
+	} while (((pgsr & DDRPHYC_PGSR_IDONE) == 0U) && (error == 0));
+	VERBOSE("\n[0x%lx] pgsr = 0x%x\n",
+		(uintptr_t)&phy->pgsr, pgsr);
+}
+
+static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
+{
+	uint32_t pir_init = pir | DDRPHYC_PIR_INIT;
+
+	mmio_write_32((uintptr_t)&phy->pir, pir_init);
+	VERBOSE("[0x%lx] pir = 0x%x -> 0x%x\n",
+		(uintptr_t)&phy->pir, pir_init,
+		mmio_read_32((uintptr_t)&phy->pir));
+
+	/* Need to wait 10 configuration clock before start polling */
+	udelay(10);
+
+	/* Wait DRAM initialization and Gate Training Evaluation complete */
+	stm32mp1_ddrphy_idone_wait(phy);
+}
+
+/* Start quasi dynamic register update */
+static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl)
+{
+	mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+	VERBOSE("[0x%lx] swctl = 0x%x\n",
+		(uintptr_t)&ctl->swctl,  mmio_read_32((uintptr_t)&ctl->swctl));
+}
+
+/* Wait quasi dynamic register update */
+static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
+{
+	uint64_t timeout;
+	uint32_t swstat;
+
+	mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+	VERBOSE("[0x%lx] swctl = 0x%x\n",
+		(uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
+
+	timeout = timeout_init_us(TIMEOUT_US_1S);
+	do {
+		swstat = mmio_read_32((uintptr_t)&ctl->swstat);
+		VERBOSE("[0x%lx] swstat = 0x%x ",
+			(uintptr_t)&ctl->swstat, swstat);
+		if (timeout_elapsed(timeout)) {
+			panic();
+		}
+	} while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U);
+
+	VERBOSE("[0x%lx] swstat = 0x%x\n",
+		(uintptr_t)&ctl->swstat, swstat);
+}
+
+/* Wait quasi dynamic register update */
+static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
+{
+	uint64_t timeout;
+	uint32_t stat;
+	int break_loop = 0;
+
+	timeout = timeout_init_us(TIMEOUT_US_1S);
+	for ( ; ; ) {
+		uint32_t operating_mode;
+		uint32_t selref_type;
+
+		stat = mmio_read_32((uintptr_t)&priv->ctl->stat);
+		operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK;
+		selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK;
+		VERBOSE("[0x%lx] stat = 0x%x\n",
+			(uintptr_t)&priv->ctl->stat, stat);
+		if (timeout_elapsed(timeout)) {
+			panic();
+		}
+
+		if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) {
+			/*
+			 * Self-refresh due to software
+			 * => checking also STAT.selfref_type.
+			 */
+			if ((operating_mode ==
+			     DDRCTRL_STAT_OPERATING_MODE_SR) &&
+			    (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) {
+				break_loop = 1;
+			}
+		} else if (operating_mode == mode) {
+			break_loop = 1;
+		} else if ((mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) &&
+			   (operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) &&
+			   (selref_type == DDRCTRL_STAT_SELFREF_TYPE_ASR)) {
+			/* Normal mode: handle also automatic self refresh */
+			break_loop = 1;
+		}
+
+		if (break_loop == 1) {
+			break;
+		}
+	}
+
+	VERBOSE("[0x%lx] stat = 0x%x\n",
+		(uintptr_t)&priv->ctl->stat, stat);
+}
+
+/* Mode Register Writes (MRW or MRS) */
+static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
+					 uint32_t data)
+{
+	uint32_t mrctrl0;
+
+	VERBOSE("MRS: %d = %x\n", addr, data);
+
+	/*
+	 * 1. Poll MRSTAT.mr_wr_busy until it is '0'.
+	 *    This checks that there is no outstanding MR transaction.
+	 *    No write should be performed to MRCTRL0 and MRCTRL1
+	 *    if MRSTAT.mr_wr_busy = 1.
+	 */
+	while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) &
+		DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) {
+		;
+	}
+
+	/*
+	 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank
+	 *    and (for MRWs) MRCTRL1.mr_data to define the MR transaction.
+	 */
+	mrctrl0 = DDRCTRL_MRCTRL0_MR_TYPE_WRITE |
+		  DDRCTRL_MRCTRL0_MR_RANK_ALL |
+		  (((uint32_t)addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) &
+		   DDRCTRL_MRCTRL0_MR_ADDR_MASK);
+	mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
+	VERBOSE("[0x%lx] mrctrl0 = 0x%x (0x%x)\n",
+		(uintptr_t)&priv->ctl->mrctrl0,
+		mmio_read_32((uintptr_t)&priv->ctl->mrctrl0), mrctrl0);
+	mmio_write_32((uintptr_t)&priv->ctl->mrctrl1, data);
+	VERBOSE("[0x%lx] mrctrl1 = 0x%x\n",
+		(uintptr_t)&priv->ctl->mrctrl1,
+		mmio_read_32((uintptr_t)&priv->ctl->mrctrl1));
+
+	/*
+	 * 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1. This
+	 *    bit is self-clearing, and triggers the MR transaction.
+	 *    The uMCTL2 then asserts the MRSTAT.mr_wr_busy while it performs
+	 *    the MR transaction to SDRAM, and no further access can be
+	 *    initiated until it is deasserted.
+	 */
+	mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR;
+	mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
+
+	while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) &
+	       DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) {
+		;
+	}
+
+	VERBOSE("[0x%lx] mrctrl0 = 0x%x\n",
+		(uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
+}
+
+/* Switch DDR3 from DLL-on to DLL-off */
+static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
+{
+	uint32_t mr1 = mmio_read_32((uintptr_t)&priv->phy->mr1);
+	uint32_t mr2 = mmio_read_32((uintptr_t)&priv->phy->mr2);
+	uint32_t dbgcam;
+
+	VERBOSE("mr1: 0x%x\n", mr1);
+	VERBOSE("mr2: 0x%x\n", mr2);
+
+	/*
+	 * 1. Set the DBG1.dis_hif = 1.
+	 *    This prevents further reads/writes being received on the HIF.
+	 */
+	mmio_setbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
+	VERBOSE("[0x%lx] dbg1 = 0x%x\n",
+		(uintptr_t)&priv->ctl->dbg1,
+		mmio_read_32((uintptr_t)&priv->ctl->dbg1));
+
+	/*
+	 * 2. Ensure all commands have been flushed from the uMCTL2 by polling
+	 *    DBGCAM.wr_data_pipeline_empty = 1,
+	 *    DBGCAM.rd_data_pipeline_empty = 1,
+	 *    DBGCAM.dbg_wr_q_depth = 0 ,
+	 *    DBGCAM.dbg_lpr_q_depth = 0, and
+	 *    DBGCAM.dbg_hpr_q_depth = 0.
+	 */
+	do {
+		dbgcam = mmio_read_32((uintptr_t)&priv->ctl->dbgcam);
+		VERBOSE("[0x%lx] dbgcam = 0x%x\n",
+			(uintptr_t)&priv->ctl->dbgcam, dbgcam);
+	} while ((((dbgcam & DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) ==
+		   DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY)) &&
+		 ((dbgcam & DDRCTRL_DBGCAM_DBG_Q_DEPTH) == 0U));
+
+	/*
+	 * 3. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers)
+	 *    to disable RTT_NOM:
+	 *    a. DDR3: Write to MR1[9], MR1[6] and MR1[2]
+	 *    b. DDR4: Write to MR1[10:8]
+	 */
+	mr1 &= ~(BIT(9) | BIT(6) | BIT(2));
+	stm32mp1_mode_register_write(priv, 1, mr1);
+
+	/*
+	 * 4. For DDR4 only: Perform an MRS command
+	 *    (using MRCTRL0 and MRCTRL1 registers) to write to MR5[8:6]
+	 *    to disable RTT_PARK
+	 */
+
+	/*
+	 * 5. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers)
+	 *    to write to MR2[10:9], to disable RTT_WR
+	 *    (and therefore disable dynamic ODT).
+	 *    This applies for both DDR3 and DDR4.
+	 */
+	mr2 &= ~GENMASK(10, 9);
+	stm32mp1_mode_register_write(priv, 2, mr2);
+
+	/*
+	 * 6. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers)
+	 *    to disable the DLL. The timing of this MRS is automatically
+	 *    handled by the uMCTL2.
+	 *    a. DDR3: Write to MR1[0]
+	 *    b. DDR4: Write to MR1[0]
+	 */
+	mr1 |= BIT(0);
+	stm32mp1_mode_register_write(priv, 1, mr1);
+
+	/*
+	 * 7. Put the SDRAM into self-refresh mode by setting
+	 *    PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure
+	 *    the DDRC has entered self-refresh.
+	 */
+	mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl,
+			DDRCTRL_PWRCTL_SELFREF_SW);
+	VERBOSE("[0x%lx] pwrctl = 0x%x\n",
+		(uintptr_t)&priv->ctl->pwrctl,
+		mmio_read_32((uintptr_t)&priv->ctl->pwrctl));
+
+	/*
+	 * 8. Wait until STAT.operating_mode[1:0]==11 indicating that the
+	 *    DWC_ddr_umctl2 core is in self-refresh mode.
+	 *    Ensure transition to self-refresh was due to software
+	 *    by checking that STAT.selfref_type[1:0]=2.
+	 */
+	stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_SR);
+
+	/*
+	 * 9. Set the MSTR.dll_off_mode = 1.
+	 *    warning: MSTR.dll_off_mode is a quasi-dynamic type 2 field
+	 */
+	stm32mp1_start_sw_done(priv->ctl);
+
+	mmio_setbits_32((uintptr_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE);
+	VERBOSE("[0x%lx] mstr = 0x%x\n",
+		(uintptr_t)&priv->ctl->mstr,
+		mmio_read_32((uintptr_t)&priv->ctl->mstr));
+
+	stm32mp1_wait_sw_done_ack(priv->ctl);
+
+	/* 10. Change the clock frequency to the desired value. */
+
+	/*
+	 * 11. Update any registers which may be required to change for the new
+	 *     frequency. This includes static and dynamic registers.
+	 *     This includes both uMCTL2 registers and PHY registers.
+	 */
+
+	/* Change Bypass Mode Frequency Range */
+	if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) {
+		mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr,
+				DDRPHYC_DLLGCR_BPS200);
+	} else {
+		mmio_setbits_32((uintptr_t)&priv->phy->dllgcr,
+				DDRPHYC_DLLGCR_BPS200);
+	}
+
+	mmio_setbits_32((uintptr_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS);
+
+	mmio_setbits_32((uintptr_t)&priv->phy->dx0dllcr,
+			DDRPHYC_DXNDLLCR_DLLDIS);
+	mmio_setbits_32((uintptr_t)&priv->phy->dx1dllcr,
+			DDRPHYC_DXNDLLCR_DLLDIS);
+	mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr,
+			DDRPHYC_DXNDLLCR_DLLDIS);
+	mmio_setbits_32((uintptr_t)&priv->phy->dx3dllcr,
+			DDRPHYC_DXNDLLCR_DLLDIS);
+
+	/* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */
+	mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl,
+			DDRCTRL_PWRCTL_SELFREF_SW);
+	stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
+
+	/*
+	 * 13. If ZQCTL0.dis_srx_zqcl = 0, the uMCTL2 performs a ZQCL command
+	 *     at this point.
+	 */
+
+	/*
+	 * 14. Perform MRS commands as required to re-program timing registers
+	 *     in the SDRAM for the new frequency
+	 *     (in particular, CL, CWL and WR may need to be changed).
+	 */
+
+	/* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes. */
+	mmio_clrbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
+	VERBOSE("[0x%lx] dbg1 = 0x%x\n",
+		(uintptr_t)&priv->ctl->dbg1,
+		mmio_read_32((uintptr_t)&priv->ctl->dbg1));
+}
+
+static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
+{
+	stm32mp1_start_sw_done(ctl);
+	/* Quasi-dynamic register update*/
+	mmio_setbits_32((uintptr_t)&ctl->rfshctl3,
+			DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
+	mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+	mmio_clrbits_32((uintptr_t)&ctl->dfimisc,
+			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+	stm32mp1_wait_sw_done_ack(ctl);
+}
+
+static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
+				     uint32_t rfshctl3, uint32_t pwrctl)
+{
+	stm32mp1_start_sw_done(ctl);
+	if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) {
+		mmio_clrbits_32((uintptr_t)&ctl->rfshctl3,
+				DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
+	}
+	if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) {
+		mmio_setbits_32((uintptr_t)&ctl->pwrctl,
+				DDRCTRL_PWRCTL_POWERDOWN_EN);
+	}
+	mmio_setbits_32((uintptr_t)&ctl->dfimisc,
+			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+	stm32mp1_wait_sw_done_ack(ctl);
+}
+
+static int board_ddr_power_init(enum ddr_type ddr_type)
+{
+	if (dt_pmic_status() > 0) {
+		return pmic_ddr_power_init(ddr_type);
+	}
+
+	return 0;
+}
+
+void stm32mp1_ddr_init(struct ddr_info *priv,
+		       struct stm32mp1_ddr_config *config)
+{
+	uint32_t pir;
+	int ret = -EINVAL;
+
+	if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
+		ret = board_ddr_power_init(STM32MP_DDR3);
+	} else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) {
+		ret = board_ddr_power_init(STM32MP_LPDDR2);
+	} else {
+		ERROR("DDR type not supported\n");
+	}
+
+	if (ret != 0) {
+		panic();
+	}
+
+	VERBOSE("name = %s\n", config->info.name);
+	VERBOSE("speed = %d kHz\n", config->info.speed);
+	VERBOSE("size  = 0x%x\n", config->info.size);
+
+	/* DDR INIT SEQUENCE */
+
+	/*
+	 * 1. Program the DWC_ddr_umctl2 registers
+	 *     nota: check DFIMISC.dfi_init_complete = 0
+	 */
+
+	/* 1.1 RESETS: presetn, core_ddrc_rstn, aresetn */
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST);
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST);
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST);
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST);
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST);
+
+	/* 1.2. start CLOCK */
+	if (stm32mp1_ddr_clk_enable(priv, config->info.speed) != 0) {
+		panic();
+	}
+
+	/* 1.3. deassert reset */
+	/* De-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST. */
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST);
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST);
+	/*
+	 * De-assert presetn once the clocks are active
+	 * and stable via DDRCAPBRST bit.
+	 */
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST);
+
+	/* 1.4. wait 128 cycles to permit initialization of end logic */
+	udelay(2);
+	/* For PCLK = 133MHz => 1 us is enough, 2 to allow lower frequency */
+
+	/* 1.5. initialize registers ddr_umctl2 */
+	/* Stop uMCTL2 before PHY is ready */
+	mmio_clrbits_32((uintptr_t)&priv->ctl->dfimisc,
+			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+	VERBOSE("[0x%lx] dfimisc = 0x%x\n",
+		(uintptr_t)&priv->ctl->dfimisc,
+		mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
+
+	set_reg(priv, REG_REG, &config->c_reg);
+
+	/* DDR3 = don't set DLLOFF for init mode */
+	if ((config->c_reg.mstr &
+	     (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE))
+	    == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) {
+		VERBOSE("deactivate DLL OFF in mstr\n");
+		mmio_clrbits_32((uintptr_t)&priv->ctl->mstr,
+				DDRCTRL_MSTR_DLL_OFF_MODE);
+		VERBOSE("[0x%lx] mstr = 0x%x\n",
+			(uintptr_t)&priv->ctl->mstr,
+			mmio_read_32((uintptr_t)&priv->ctl->mstr));
+	}
+
+	set_reg(priv, REG_TIMING, &config->c_timing);
+	set_reg(priv, REG_MAP, &config->c_map);
+
+	/* Skip CTRL init, SDRAM init is done by PHY PUBL */
+	mmio_clrsetbits_32((uintptr_t)&priv->ctl->init0,
+			   DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK,
+			   DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL);
+	VERBOSE("[0x%lx] init0 = 0x%x\n",
+		(uintptr_t)&priv->ctl->init0,
+		mmio_read_32((uintptr_t)&priv->ctl->init0));
+
+	set_reg(priv, REG_PERF, &config->c_perf);
+
+	/*  2. deassert reset signal core_ddrc_rstn, aresetn and presetn */
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST);
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST);
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST);
+
+	/*
+	 * 3. start PHY init by accessing relevant PUBL registers
+	 *    (DXGCR, DCR, PTR*, MR*, DTPR*)
+	 */
+	set_reg(priv, REGPHY_REG, &config->p_reg);
+	set_reg(priv, REGPHY_TIMING, &config->p_timing);
+	set_reg(priv, REGPHY_CAL, &config->p_cal);
+
+	/* DDR3 = don't set DLLOFF for init mode */
+	if ((config->c_reg.mstr &
+	     (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE))
+	    == (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) {
+		VERBOSE("deactivate DLL OFF in mr1\n");
+		mmio_clrbits_32((uintptr_t)&priv->phy->mr1, BIT(0));
+		VERBOSE("[0x%lx] mr1 = 0x%x\n",
+			(uintptr_t)&priv->phy->mr1,
+			mmio_read_32((uintptr_t)&priv->phy->mr1));
+	}
+
+	/*
+	 *  4. Monitor PHY init status by polling PUBL register PGSR.IDONE
+	 *     Perform DDR PHY DRAM initialization and Gate Training Evaluation
+	 */
+	stm32mp1_ddrphy_idone_wait(priv->phy);
+
+	/*
+	 *  5. Indicate to PUBL that controller performs SDRAM initialization
+	 *     by setting PIR.INIT and PIR CTLDINIT and pool PGSR.IDONE
+	 *     DRAM init is done by PHY, init0.skip_dram.init = 1
+	 */
+
+	pir = DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | DDRPHYC_PIR_ZCAL |
+	      DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_DRAMINIT | DDRPHYC_PIR_ICPC;
+
+	if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
+		pir |= DDRPHYC_PIR_DRAMRST; /* Only for DDR3 */
+	}
+
+	stm32mp1_ddrphy_init(priv->phy, pir);
+
+	/*
+	 *  6. SET DFIMISC.dfi_init_complete_en to 1
+	 *  Enable quasi-dynamic register programming.
+	 */
+	stm32mp1_start_sw_done(priv->ctl);
+
+	mmio_setbits_32((uintptr_t)&priv->ctl->dfimisc,
+			DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
+	VERBOSE("[0x%lx] dfimisc = 0x%x\n",
+		(uintptr_t)&priv->ctl->dfimisc,
+		mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
+
+	stm32mp1_wait_sw_done_ack(priv->ctl);
+
+	/*
+	 *  7. Wait for DWC_ddr_umctl2 to move to normal operation mode
+	 *     by monitoring STAT.operating_mode signal
+	 */
+
+	/* Wait uMCTL2 ready */
+	stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
+
+	/* Switch to DLL OFF mode */
+	if ((config->c_reg.mstr & DDRCTRL_MSTR_DLL_OFF_MODE) != 0U) {
+		stm32mp1_ddr3_dll_off(priv);
+	}
+
+	VERBOSE("DDR DQS training : ");
+
+	/*
+	 *  8. Disable Auto refresh and power down by setting
+	 *    - RFSHCTL3.dis_au_refresh = 1
+	 *    - PWRCTL.powerdown_en = 0
+	 *    - DFIMISC.dfiinit_complete_en = 0
+	 */
+	stm32mp1_refresh_disable(priv->ctl);
+
+	/*
+	 *  9. Program PUBL PGCR to enable refresh during training
+	 *     and rank to train
+	 *     not done => keep the programed value in PGCR
+	 */
+
+	/*
+	 * 10. configure PUBL PIR register to specify which training step
+	 * to run
+	 * Warning : RVTRN  is not supported by this PUBL
+	 */
+	stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+
+	/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
+	stm32mp1_ddrphy_idone_wait(priv->phy);
+
+	/*
+	 * 12. set back registers in step 8 to the orginal values if desidered
+	 */
+	stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+				 config->c_reg.pwrctl);
+
+	/* Enable uMCTL2 AXI port 0 */
+	mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0,
+			DDRCTRL_PCTRL_N_PORT_EN);
+	VERBOSE("[0x%lx] pctrl_0 = 0x%x\n",
+		(uintptr_t)&priv->ctl->pctrl_0,
+		mmio_read_32((uintptr_t)&priv->ctl->pctrl_0));
+
+	/* Enable uMCTL2 AXI port 1 */
+	mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_1,
+			DDRCTRL_PCTRL_N_PORT_EN);
+	VERBOSE("[0x%lx] pctrl_1 = 0x%x\n",
+		(uintptr_t)&priv->ctl->pctrl_1,
+		mmio_read_32((uintptr_t)&priv->ctl->pctrl_1));
+}
diff --git a/drivers/st/ddr/stm32mp1_ddr_helpers.c b/drivers/st/ddr/stm32mp1_ddr_helpers.c
new file mode 100644
index 0000000..fcb4cfc
--- /dev/null
+++ b/drivers/st/ddr/stm32mp1_ddr_helpers.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <lib/mmio.h>
+
+void ddr_enable_clock(void)
+{
+	stm32mp1_clk_rcc_regs_lock();
+
+	mmio_setbits_32(stm32mp_rcc_base() + RCC_DDRITFCR,
+			RCC_DDRITFCR_DDRC1EN |
+			RCC_DDRITFCR_DDRC2EN |
+			RCC_DDRITFCR_DDRPHYCEN |
+			RCC_DDRITFCR_DDRPHYCAPBEN |
+			RCC_DDRITFCR_DDRCAPBEN);
+
+	stm32mp1_clk_rcc_regs_unlock();
+}
diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c
new file mode 100644
index 0000000..4ae55fc
--- /dev/null
+++ b/drivers/st/ddr/stm32mp1_ram.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/stm32mp1_ddr.h>
+#include <drivers/st/stm32mp1_ddr_helpers.h>
+#include <drivers/st/stm32mp1_ram.h>
+#include <lib/mmio.h>
+
+#define DDR_PATTERN	0xAAAAAAAAU
+#define DDR_ANTIPATTERN	0x55555555U
+
+static struct ddr_info ddr_priv_data;
+
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
+{
+	unsigned long ddrphy_clk, ddr_clk, mem_speed_hz;
+
+	ddr_enable_clock();
+
+	ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC);
+
+	VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n",
+		mem_speed, ddrphy_clk / 1000U);
+
+	mem_speed_hz = mem_speed * 1000U;
+
+	/* Max 10% frequency delta */
+	if (ddrphy_clk > mem_speed_hz) {
+		ddr_clk = ddrphy_clk - mem_speed_hz;
+	} else {
+		ddr_clk = mem_speed_hz - ddrphy_clk;
+	}
+	if (ddr_clk > (mem_speed_hz / 10)) {
+		ERROR("DDR expected freq %d kHz, current is %ld kHz\n",
+		      mem_speed, ddrphy_clk / 1000U);
+		return -1;
+	}
+	return 0;
+}
+
+/*******************************************************************************
+ * This function tests the DDR data bus wiring.
+ * This is inspired from the Data Bus Test algorithm written by Michael Barr
+ * in "Programming Embedded Systems in C and C++" book.
+ * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
+ * File: memtest.c - This source code belongs to Public Domain.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+static uint32_t ddr_test_data_bus(void)
+{
+	uint32_t pattern;
+
+	for (pattern = 1U; pattern != 0U; pattern <<= 1) {
+		mmio_write_32(STM32MP_DDR_BASE, pattern);
+
+		if (mmio_read_32(STM32MP_DDR_BASE) != pattern) {
+			return (uint32_t)STM32MP_DDR_BASE;
+		}
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function tests the DDR address bus wiring.
+ * This is inspired from the Data Bus Test algorithm written by Michael Barr
+ * in "Programming Embedded Systems in C and C++" book.
+ * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
+ * File: memtest.c - This source code belongs to Public Domain.
+ * Returns 0 if success, and address value else.
+ ******************************************************************************/
+static uint32_t ddr_test_addr_bus(void)
+{
+	uint64_t addressmask = (ddr_priv_data.info.size - 1U);
+	uint64_t offset;
+	uint64_t testoffset = 0;
+
+	/* Write the default pattern at each of the power-of-two offsets. */
+	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+	     offset <<= 1) {
+		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset,
+			      DDR_PATTERN);
+	}
+
+	/* Check for address bits stuck high. */
+	mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
+		      DDR_ANTIPATTERN);
+
+	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+	     offset <<= 1) {
+		if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) !=
+		    DDR_PATTERN) {
+			return (uint32_t)(STM32MP_DDR_BASE + offset);
+		}
+	}
+
+	mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN);
+
+	/* Check for address bits stuck low or shorted. */
+	for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
+	     testoffset <<= 1) {
+		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
+			      DDR_ANTIPATTERN);
+
+		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
+			return STM32MP_DDR_BASE;
+		}
+
+		for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
+		     offset <<= 1) {
+			if ((mmio_read_32(STM32MP_DDR_BASE +
+					  (uint32_t)offset) != DDR_PATTERN) &&
+			    (offset != testoffset)) {
+				return (uint32_t)(STM32MP_DDR_BASE + offset);
+			}
+		}
+
+		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
+			      DDR_PATTERN);
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function checks the DDR size. It has to be run with Data Cache off.
+ * This test is run before data have been put in DDR, and is only done for
+ * cold boot. The DDR data can then be overwritten, and it is not useful to
+ * restore its content.
+ * Returns DDR computed size.
+ ******************************************************************************/
+static uint32_t ddr_check_size(void)
+{
+	uint32_t offset = sizeof(uint32_t);
+
+	mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
+
+	while (offset < STM32MP_DDR_MAX_SIZE) {
+		mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
+		dsb();
+
+		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
+			break;
+		}
+
+		offset <<= 1;
+	}
+
+	INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U));
+
+	return offset;
+}
+
+static int stm32mp1_ddr_setup(void)
+{
+	struct ddr_info *priv = &ddr_priv_data;
+	int ret;
+	struct stm32mp1_ddr_config config;
+	int node, len;
+	uint32_t uret, idx;
+	void *fdt;
+
+#define PARAM(x, y)							\
+	{								\
+		.name = x,						\
+		.offset = offsetof(struct stm32mp1_ddr_config, y),	\
+		.size = sizeof(config.y) / sizeof(uint32_t)		\
+	}
+
+#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
+#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
+
+	const struct {
+		const char *name; /* Name in DT */
+		const uint32_t offset; /* Offset in config struct */
+		const uint32_t size;   /* Size of parameters */
+	} param[] = {
+		CTL_PARAM(reg),
+		CTL_PARAM(timing),
+		CTL_PARAM(map),
+		CTL_PARAM(perf),
+		PHY_PARAM(reg),
+		PHY_PARAM(timing),
+		PHY_PARAM(cal)
+	};
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
+	if (node < 0) {
+		ERROR("%s: Cannot read DDR node in DT\n", __func__);
+		return -EINVAL;
+	}
+
+	config.info.speed = fdt_read_uint32_default(node, "st,mem-speed", 0);
+	if (!config.info.speed) {
+		VERBOSE("%s: no st,mem-speed\n", __func__);
+		return -EINVAL;
+	}
+	config.info.size = fdt_read_uint32_default(node, "st,mem-size", 0);
+	if (!config.info.size) {
+		VERBOSE("%s: no st,mem-size\n", __func__);
+		return -EINVAL;
+	}
+	config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len);
+	if (config.info.name == NULL) {
+		VERBOSE("%s: no st,mem-name\n", __func__);
+		return -EINVAL;
+	}
+	INFO("RAM: %s\n", config.info.name);
+
+	for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
+		ret = fdt_read_uint32_array(node, param[idx].name,
+					    (void *)((uintptr_t)&config +
+						     param[idx].offset),
+					    param[idx].size);
+
+		VERBOSE("%s: %s[0x%x] = %d\n", __func__,
+			param[idx].name, param[idx].size, ret);
+		if (ret != 0) {
+			ERROR("%s: Cannot read %s\n",
+			      __func__, param[idx].name);
+			return -EINVAL;
+		}
+	}
+
+	/* Disable axidcg clock gating during init */
+	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
+
+	stm32mp1_ddr_init(priv, &config);
+
+	/* Enable axidcg clock gating */
+	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
+
+	priv->info.size = config.info.size;
+
+	VERBOSE("%s : ram size(%x, %x)\n", __func__,
+		(uint32_t)priv->info.base, (uint32_t)priv->info.size);
+
+	write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
+	dcsw_op_all(DC_OP_CISW);
+
+	uret = ddr_test_data_bus();
+	if (uret != 0U) {
+		ERROR("DDR data bus test: can't access memory @ 0x%x\n",
+		      uret);
+		panic();
+	}
+
+	uret = ddr_test_addr_bus();
+	if (uret != 0U) {
+		ERROR("DDR addr bus test: can't access memory @ 0x%x\n",
+		      uret);
+		panic();
+	}
+
+	uret = ddr_check_size();
+	if (uret < config.info.size) {
+		ERROR("DDR size: 0x%x does not match DT config: 0x%x\n",
+		      uret, config.info.size);
+		panic();
+	}
+
+	write_sctlr(read_sctlr() | SCTLR_C_BIT);
+
+	return 0;
+}
+
+int stm32mp1_ddr_probe(void)
+{
+	struct ddr_info *priv = &ddr_priv_data;
+
+	VERBOSE("STM32MP DDR probe\n");
+
+	priv->ctl = (struct stm32mp1_ddrctl *)stm32mp_ddrctrl_base();
+	priv->phy = (struct stm32mp1_ddrphy *)stm32mp_ddrphyc_base();
+	priv->pwr = stm32mp_pwr_base();
+	priv->rcc = stm32mp_rcc_base();
+
+	priv->info.base = STM32MP_DDR_BASE;
+	priv->info.size = 0;
+
+	return stm32mp1_ddr_setup();
+}
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
new file mode 100644
index 0000000..343ad6c
--- /dev/null
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#define DT_GPIO_BANK_SHIFT	12
+#define DT_GPIO_BANK_MASK	GENMASK(16, 12)
+#define DT_GPIO_PIN_SHIFT	8
+#define DT_GPIO_PIN_MASK	GENMASK(11, 8)
+#define DT_GPIO_MODE_MASK	GENMASK(7, 0)
+
+/*******************************************************************************
+ * This function gets GPIO bank node in DT.
+ * Returns node offset if status is okay in DT, else return 0
+ ******************************************************************************/
+static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node)
+{
+	int pinctrl_subnode;
+	uint32_t bank_offset = stm32_get_gpio_bank_offset(bank);
+
+	fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
+		const fdt32_t *cuint;
+
+		if (fdt_getprop(fdt, pinctrl_subnode,
+				"gpio-controller", NULL) == NULL) {
+			continue;
+		}
+
+		cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
+		if (cuint == NULL) {
+			continue;
+		}
+
+		if ((fdt32_to_cpu(*cuint) == bank_offset) &&
+		    (fdt_get_status(pinctrl_subnode) != DT_DISABLED)) {
+			return pinctrl_subnode;
+		}
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function gets the pin settings from DT information.
+ * When analyze and parsing is done, set the GPIO registers.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
+{
+	const fdt32_t *cuint, *slewrate;
+	int len;
+	int pinctrl_node;
+	uint32_t i;
+	uint32_t speed = GPIO_SPEED_LOW;
+	uint32_t pull = GPIO_NO_PULL;
+
+	cuint = fdt_getprop(fdt, node, "pinmux", &len);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
+	if (pinctrl_node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
+	if (slewrate != NULL) {
+		speed = fdt32_to_cpu(*slewrate);
+	}
+
+	if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
+		pull = GPIO_PULL_UP;
+	} else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
+		pull = GPIO_PULL_DOWN;
+	} else {
+		VERBOSE("No bias configured in node %d\n", node);
+	}
+
+	for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
+		uint32_t pincfg;
+		uint32_t bank;
+		uint32_t pin;
+		uint32_t mode;
+		uint32_t alternate = GPIO_ALTERNATE_(0);
+		int bank_node;
+		int clk;
+
+		pincfg = fdt32_to_cpu(*cuint);
+		cuint++;
+
+		bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
+
+		pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
+
+		mode = pincfg & DT_GPIO_MODE_MASK;
+
+		switch (mode) {
+		case 0:
+			mode = GPIO_MODE_INPUT;
+			break;
+		case 1 ... 16:
+			alternate = mode - 1U;
+			mode = GPIO_MODE_ALTERNATE;
+			break;
+		case 17:
+			mode = GPIO_MODE_ANALOG;
+			break;
+		default:
+			mode = GPIO_MODE_OUTPUT;
+			break;
+		}
+
+		if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
+			mode |= GPIO_OPEN_DRAIN;
+		}
+
+		bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node);
+		if (bank_node == 0) {
+			ERROR("PINCTRL inconsistent in DT\n");
+			panic();
+		}
+
+		clk = fdt_get_clock_id(bank_node);
+		if (clk < 0) {
+			return -FDT_ERR_NOTFOUND;
+		}
+
+		/* Platform knows the clock: assert it is okay */
+		assert((unsigned long)clk == stm32_get_gpio_bank_clock(bank));
+
+		set_gpio(bank, pin, mode, speed, pull, alternate, status);
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function gets the pin settings from DT information.
+ * When analyze and parsing is done, set the GPIO registers.
+ * Returns 0 on success and a negative FDT/ERRNO error code on failure.
+ ******************************************************************************/
+int dt_set_pinctrl_config(int node)
+{
+	const fdt32_t *cuint;
+	int lenp = 0;
+	uint32_t i;
+	uint8_t status = fdt_get_status(node);
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	if (status == DT_DISABLED) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
+		int p_node, p_subnode;
+
+		p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+		if (p_node < 0) {
+			return -FDT_ERR_NOTFOUND;
+		}
+
+		fdt_for_each_subnode(p_subnode, fdt, p_node) {
+			int ret = dt_set_gpio_config(fdt, p_subnode, status);
+
+			if (ret < 0) {
+				return ret;
+			}
+		}
+
+		cuint++;
+	}
+
+	return 0;
+}
+
+void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
+	      uint32_t pull, uint32_t alternate, uint8_t status)
+{
+	uintptr_t base = stm32_get_gpio_bank_base(bank);
+	unsigned long clock = stm32_get_gpio_bank_clock(bank);
+
+	assert(pin <= GPIO_PIN_MAX);
+
+	stm32mp_clk_enable(clock);
+
+	mmio_clrbits_32(base + GPIO_MODE_OFFSET,
+			((uint32_t)GPIO_MODE_MASK << (pin << 1)));
+	mmio_setbits_32(base + GPIO_MODE_OFFSET,
+			(mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
+
+	if ((mode & GPIO_OPEN_DRAIN) != 0U) {
+		mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
+	} else {
+		mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
+	}
+
+	mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
+			((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
+	mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
+
+	mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
+			((uint32_t)GPIO_PULL_MASK << (pin << 1)));
+	mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
+
+	if (pin < GPIO_ALT_LOWER_LIMIT) {
+		mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
+				((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
+		mmio_setbits_32(base + GPIO_AFRL_OFFSET,
+				alternate << (pin << 2));
+	} else {
+		mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
+				((uint32_t)GPIO_ALTERNATE_MASK <<
+				 ((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
+		mmio_setbits_32(base + GPIO_AFRH_OFFSET,
+				alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
+					      2));
+	}
+
+	VERBOSE("GPIO %u mode set to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_MODE_OFFSET));
+	VERBOSE("GPIO %u speed set to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_SPEED_OFFSET));
+	VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_PUPD_OFFSET));
+	VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_AFRL_OFFSET));
+	VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
+		mmio_read_32(base + GPIO_AFRH_OFFSET));
+
+	stm32mp_clk_disable(clock);
+}
+
+void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
+{
+	uintptr_t base = stm32_get_gpio_bank_base(bank);
+	unsigned long clock = stm32_get_gpio_bank_clock(bank);
+
+	assert(pin <= GPIO_PIN_MAX);
+
+	stm32mp_clk_enable(clock);
+
+	if (secure) {
+		mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
+	} else {
+		mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
+	}
+
+	stm32mp_clk_disable(clock);
+}
diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
new file mode 100644
index 0000000..ed88052
--- /dev/null
+++ b/drivers/st/i2c/stm32_i2c.c
@@ -0,0 +1,981 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_i2c.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+/* STM32 I2C registers offsets */
+#define I2C_CR1			0x00U
+#define I2C_CR2			0x04U
+#define I2C_OAR1		0x08U
+#define I2C_OAR2		0x0CU
+#define I2C_TIMINGR		0x10U
+#define I2C_TIMEOUTR		0x14U
+#define I2C_ISR			0x18U
+#define I2C_ICR			0x1CU
+#define I2C_PECR		0x20U
+#define I2C_RXDR		0x24U
+#define I2C_TXDR		0x28U
+
+#define TIMINGR_CLEAR_MASK	0xF0FFFFFFU
+
+#define MAX_NBYTE_SIZE		255U
+
+#define I2C_NSEC_PER_SEC	1000000000L
+
+/* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */
+#define I2C_TIMING			0x10D07DB5
+
+static void notif_i2c_timeout(struct i2c_handle_s *hi2c)
+{
+	hi2c->i2c_err |= I2C_ERROR_TIMEOUT;
+	hi2c->i2c_mode = I2C_MODE_NONE;
+	hi2c->i2c_state = I2C_STATE_READY;
+}
+
+/*
+ * @brief  Configure I2C Analog noise filter.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C peripheral.
+ * @param  analog_filter: New state of the Analog filter
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_config_analog_filter(struct i2c_handle_s *hi2c,
+				    uint32_t analog_filter)
+{
+	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+		return -EBUSY;
+	}
+
+	hi2c->lock = 1;
+
+	hi2c->i2c_state = I2C_STATE_BUSY;
+
+	/* Disable the selected I2C peripheral */
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+	/* Reset I2Cx ANOFF bit */
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_ANFOFF);
+
+	/* Set analog filter bit*/
+	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, analog_filter);
+
+	/* Enable the selected I2C peripheral */
+	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+	hi2c->i2c_state = I2C_STATE_READY;
+
+	hi2c->lock = 0;
+
+	return 0;
+}
+
+/*
+ * @brief  Get I2C setup information from the device tree and set pinctrl
+ *         configuration.
+ * @param  fdt: Pointer to the device tree
+ * @param  node: I2C node offset
+ * @param  init: Ref to the initialization configuration structure
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
+				 struct stm32_i2c_init_s *init)
+{
+	const fdt32_t *cuint;
+
+	cuint = fdt_getprop(fdt, node, "i2c-scl-rising-time-ns", NULL);
+	if (cuint == NULL) {
+		init->rise_time = STM32_I2C_RISE_TIME_DEFAULT;
+	} else {
+		init->rise_time = fdt32_to_cpu(*cuint);
+	}
+
+	cuint = fdt_getprop(fdt, node, "i2c-scl-falling-time-ns", NULL);
+	if (cuint == NULL) {
+		init->fall_time = STM32_I2C_FALL_TIME_DEFAULT;
+	} else {
+		init->fall_time = fdt32_to_cpu(*cuint);
+	}
+
+	cuint = fdt_getprop(fdt, node, "clock-frequency", NULL);
+	if (cuint == NULL) {
+		init->speed_mode = STM32_I2C_SPEED_DEFAULT;
+	} else {
+		switch (fdt32_to_cpu(*cuint)) {
+		case STANDARD_RATE:
+			init->speed_mode = I2C_SPEED_STANDARD;
+			break;
+		case FAST_RATE:
+			init->speed_mode = I2C_SPEED_FAST;
+			break;
+		case FAST_PLUS_RATE:
+			init->speed_mode = I2C_SPEED_FAST_PLUS;
+			break;
+		default:
+			init->speed_mode = STM32_I2C_SPEED_DEFAULT;
+			break;
+		}
+	}
+
+	return dt_set_pinctrl_config(node);
+}
+
+/*
+ * @brief  Initialize the I2C device.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  init_data: Initialization configuration structure
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_init(struct i2c_handle_s *hi2c,
+		   struct stm32_i2c_init_s *init_data)
+{
+	int rc = 0;
+	uint32_t timing = I2C_TIMING;
+
+	if (hi2c == NULL) {
+		return -ENOENT;
+	}
+
+	if (hi2c->i2c_state == I2C_STATE_RESET) {
+		hi2c->lock = 0;
+	}
+
+	hi2c->i2c_state = I2C_STATE_BUSY;
+
+	stm32mp_clk_enable(hi2c->clock);
+
+	/* Disable the selected I2C peripheral */
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+	/* Configure I2Cx: Frequency range */
+	mmio_write_32(hi2c->i2c_base_addr + I2C_TIMINGR,
+		      timing & TIMINGR_CLEAR_MASK);
+
+	/* Disable Own Address1 before set the Own Address1 configuration */
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR1, I2C_OAR1_OA1EN);
+
+	/* Configure I2Cx: Own Address1 and ack own address1 mode */
+	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_7BIT) {
+		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
+			      I2C_OAR1_OA1EN | init_data->own_address1);
+	} else { /* I2C_ADDRESSINGMODE_10BIT */
+		mmio_write_32(hi2c->i2c_base_addr + I2C_OAR1,
+			      I2C_OAR1_OA1EN | I2C_OAR1_OA1MODE |
+			      init_data->own_address1);
+	}
+
+	mmio_write_32(hi2c->i2c_base_addr + I2C_CR2, 0);
+
+	/* Configure I2Cx: Addressing Master mode */
+	if (init_data->addressing_mode == I2C_ADDRESSINGMODE_10BIT) {
+		mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_CR2_ADD10);
+	}
+
+	/*
+	 * Enable the AUTOEND by default, and enable NACK
+	 * (should be disabled only during Slave process).
+	 */
+	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
+			I2C_CR2_AUTOEND | I2C_CR2_NACK);
+
+	/* Disable Own Address2 before set the Own Address2 configuration */
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_OAR2, I2C_DUALADDRESS_ENABLE);
+
+	/* Configure I2Cx: Dual mode and Own Address2 */
+	mmio_write_32(hi2c->i2c_base_addr + I2C_OAR2,
+		      init_data->dual_address_mode |
+		      init_data->own_address2 |
+		      (init_data->own_address2_masks << 8));
+
+	/* Configure I2Cx: Generalcall and NoStretch mode */
+	mmio_write_32(hi2c->i2c_base_addr + I2C_CR1,
+		      init_data->general_call_mode |
+		      init_data->no_stretch_mode);
+
+	/* Enable the selected I2C peripheral */
+	mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
+
+	hi2c->i2c_err = I2C_ERROR_NONE;
+	hi2c->i2c_state = I2C_STATE_READY;
+	hi2c->i2c_mode = I2C_MODE_NONE;
+
+	rc = i2c_config_analog_filter(hi2c, init_data->analog_filter ?
+						I2C_ANALOGFILTER_ENABLE :
+						I2C_ANALOGFILTER_DISABLE);
+	if (rc != 0) {
+		ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
+		stm32mp_clk_disable(hi2c->clock);
+		return rc;
+	}
+
+	stm32mp_clk_disable(hi2c->clock);
+
+	return rc;
+}
+
+/*
+ * @brief  I2C Tx data register flush process.
+ * @param  hi2c: I2C handle
+ * @retval None
+ */
+static void i2c_flush_txdr(struct i2c_handle_s *hi2c)
+{
+	/*
+	 * If a pending TXIS flag is set,
+	 * write a dummy data in TXDR to clear it.
+	 */
+	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) !=
+	    0U) {
+		mmio_write_32(hi2c->i2c_base_addr + I2C_TXDR, 0);
+	}
+
+	/* Flush TX register if not empty */
+	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXE) ==
+	    0U) {
+		mmio_setbits_32(hi2c->i2c_base_addr + I2C_ISR,
+				I2C_FLAG_TXE);
+	}
+}
+
+/*
+ * @brief  This function handles I2C Communication timeout.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  flag: Specifies the I2C flag to check
+ * @param  awaited_value: The awaited bit value for the flag (0 or 1)
+ * @param  timeout_ref: Reference to target timeout
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_wait_flag(struct i2c_handle_s *hi2c, uint32_t flag,
+			 uint8_t awaited_value, uint64_t timeout_ref)
+{
+	for ( ; ; ) {
+		uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR);
+
+		if (!!(isr & flag) != !!awaited_value) {
+			return 0;
+		}
+
+		if (timeout_elapsed(timeout_ref)) {
+			notif_i2c_timeout(hi2c);
+			hi2c->lock = 0;
+
+			return -EIO;
+		}
+	}
+}
+
+/*
+ * @brief  This function handles Acknowledge failed detection during
+ *	   an I2C Communication.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  timeout_ref: Reference to target timeout
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
+{
+	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_AF) == 0U) {
+		return 0;
+	}
+
+	/*
+	 * Wait until STOP Flag is reset.
+	 * AutoEnd should be initiate after AF.
+	 */
+	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+		I2C_FLAG_STOPF) == 0U) {
+		if (timeout_elapsed(timeout_ref)) {
+			notif_i2c_timeout(hi2c);
+			hi2c->lock = 0;
+
+			return -EIO;
+		}
+	}
+
+	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
+
+	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+	i2c_flush_txdr(hi2c);
+
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
+
+	hi2c->i2c_err |= I2C_ERROR_AF;
+	hi2c->i2c_state = I2C_STATE_READY;
+	hi2c->i2c_mode = I2C_MODE_NONE;
+
+	hi2c->lock = 0;
+
+	return -EIO;
+}
+
+/*
+ * @brief  This function handles I2C Communication timeout for specific usage
+ *	   of TXIS flag.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  timeout_ref: Reference to target timeout
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
+{
+	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+		I2C_FLAG_TXIS) == 0U) {
+		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
+			return -EIO;
+		}
+
+		if (timeout_elapsed(timeout_ref)) {
+			notif_i2c_timeout(hi2c);
+			hi2c->lock = 0;
+
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  This function handles I2C Communication timeout for specific
+ *	   usage of STOP flag.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  timeout_ref: Reference to target timeout
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t timeout_ref)
+{
+	while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+		 I2C_FLAG_STOPF) == 0U) {
+		if (i2c_ack_failed(hi2c, timeout_ref) != 0) {
+			return -EIO;
+		}
+
+		if (timeout_elapsed(timeout_ref)) {
+			notif_i2c_timeout(hi2c);
+			hi2c->lock = 0;
+
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Handles I2Cx communication when starting transfer or during transfer
+ *	   (TC or TCR flag are set).
+ * @param  hi2c: I2C handle
+ * @param  dev_addr: Specifies the slave address to be programmed
+ * @param  size: Specifies the number of bytes to be programmed.
+ *   This parameter must be a value between 0 and 255.
+ * @param  i2c_mode: New state of the I2C START condition generation.
+ *   This parameter can be one of the following values:
+ *     @arg @ref I2C_RELOAD_MODE: Enable Reload mode.
+ *     @arg @ref I2C_AUTOEND_MODE: Enable Automatic end mode.
+ *     @arg @ref I2C_SOFTEND_MODE: Enable Software end mode.
+ * @param  request: New state of the I2C START condition generation.
+ *   This parameter can be one of the following values:
+ *     @arg @ref I2C_NO_STARTSTOP: Don't Generate stop and start condition.
+ *     @arg @ref I2C_GENERATE_STOP: Generate stop condition
+ *                                  (size should be set to 0).
+ *     @arg @ref I2C_GENERATE_START_READ: Generate Restart for read request.
+ *     @arg @ref I2C_GENERATE_START_WRITE: Generate Restart for write request.
+ * @retval None
+ */
+static void i2c_transfer_config(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+				uint16_t size, uint32_t i2c_mode,
+				uint32_t request)
+{
+	uint32_t clr_value, set_value;
+
+	clr_value = (I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD |
+		     I2C_CR2_AUTOEND | I2C_CR2_START | I2C_CR2_STOP) |
+		(I2C_CR2_RD_WRN & (request >> (31U - I2C_CR2_RD_WRN_OFFSET)));
+
+	set_value = ((uint32_t)dev_addr & I2C_CR2_SADD) |
+		(((uint32_t)size << I2C_CR2_NBYTES_OFFSET) & I2C_CR2_NBYTES) |
+		i2c_mode | request;
+
+	mmio_clrsetbits_32(hi2c->i2c_base_addr + I2C_CR2, clr_value, set_value);
+}
+
+/*
+ * @brief  Master sends target device address followed by internal memory
+ *	   address for write request.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: Size of internal memory address
+ * @param  timeout_ref: Reference to target timeout
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_request_memory_write(struct i2c_handle_s *hi2c,
+				    uint16_t dev_addr, uint16_t mem_addr,
+				    uint16_t mem_add_size, uint64_t timeout_ref)
+{
+	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE,
+			    I2C_GENERATE_START_WRITE);
+
+	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
+		return -EIO;
+	}
+
+	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
+		/* Send Memory Address */
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+			     (uint8_t)(mem_addr & 0x00FFU));
+	} else {
+		/* Send MSB of Memory Address */
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
+
+		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
+			return -EIO;
+		}
+
+		/* Send LSB of Memory Address */
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+			     (uint8_t)(mem_addr & 0x00FFU));
+	}
+
+	if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0, timeout_ref) != 0) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Master sends target device address followed by internal memory
+ *	   address for read request.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: Size of internal memory address
+ * @param  timeout_ref: Reference to target timeout
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_request_memory_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+				   uint16_t mem_addr, uint16_t mem_add_size,
+				   uint64_t timeout_ref)
+{
+	i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE,
+			    I2C_GENERATE_START_WRITE);
+
+	if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
+		return -EIO;
+	}
+
+	if (mem_add_size == I2C_MEMADD_SIZE_8BIT) {
+		/* Send Memory Address */
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+			     (uint8_t)(mem_addr & 0x00FFU));
+	} else {
+		/* Send MSB of Memory Address */
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+			     (uint8_t)((mem_addr & 0xFF00U) >> 8));
+
+		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
+			return -EIO;
+		}
+
+		/* Send LSB of Memory Address */
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR,
+			     (uint8_t)(mem_addr & 0x00FFU));
+	}
+
+	if (i2c_wait_flag(hi2c, I2C_FLAG_TC, 0, timeout_ref) != 0) {
+		return -EIO;
+	}
+
+	return 0;
+}
+/*
+ * @brief  Generic function to write an amount of data in blocking mode
+ *         (for Memory Mode and Master Mode)
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address (if Memory Mode)
+ * @param  mem_add_size: Size of internal memory address (if Memory Mode)
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @param  mode: Communication mode
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+		     uint16_t mem_addr, uint16_t mem_add_size,
+		     uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
+		     enum i2c_mode_e mode)
+{
+	uint64_t timeout_ref;
+	int rc = -EIO;
+	uint8_t *p_buff = p_data;
+	uint32_t xfer_size;
+	uint32_t xfer_count = size;
+
+	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
+		return -1;
+	}
+
+	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+		return -EBUSY;
+	}
+
+	if ((p_data == NULL) || (size == 0U)) {
+		return -EINVAL;
+	}
+
+	stm32mp_clk_enable(hi2c->clock);
+
+	hi2c->lock = 1;
+
+	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
+	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
+		goto bail;
+	}
+
+	hi2c->i2c_state = I2C_STATE_BUSY_TX;
+	hi2c->i2c_mode = mode;
+	hi2c->i2c_err = I2C_ERROR_NONE;
+
+	timeout_ref = timeout_init_us(timeout_ms * 1000);
+
+	if (mode == I2C_MODE_MEM) {
+		/* In Memory Mode, Send Slave Address and Memory Address */
+		if (i2c_request_memory_write(hi2c, dev_addr, mem_addr,
+					     mem_add_size, timeout_ref) != 0) {
+			goto bail;
+		}
+
+		if (xfer_count > MAX_NBYTE_SIZE) {
+			xfer_size = MAX_NBYTE_SIZE;
+			i2c_transfer_config(hi2c, dev_addr, xfer_size,
+					    I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
+		} else {
+			xfer_size = xfer_count;
+			i2c_transfer_config(hi2c, dev_addr, xfer_size,
+					    I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
+		}
+	} else {
+		/* In Master Mode, Send Slave Address */
+		if (xfer_count > MAX_NBYTE_SIZE) {
+			xfer_size = MAX_NBYTE_SIZE;
+			i2c_transfer_config(hi2c, dev_addr, xfer_size,
+					    I2C_RELOAD_MODE,
+					    I2C_GENERATE_START_WRITE);
+		} else {
+			xfer_size = xfer_count;
+			i2c_transfer_config(hi2c, dev_addr, xfer_size,
+					    I2C_AUTOEND_MODE,
+					    I2C_GENERATE_START_WRITE);
+		}
+	}
+
+	do {
+		if (i2c_wait_txis(hi2c, timeout_ref) != 0) {
+			goto bail;
+		}
+
+		mmio_write_8(hi2c->i2c_base_addr + I2C_TXDR, *p_buff);
+		p_buff++;
+		xfer_count--;
+		xfer_size--;
+
+		if ((xfer_count != 0U) && (xfer_size == 0U)) {
+			/* Wait until TCR flag is set */
+			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
+					  timeout_ref) != 0) {
+				goto bail;
+			}
+
+			if (xfer_count > MAX_NBYTE_SIZE) {
+				xfer_size = MAX_NBYTE_SIZE;
+				i2c_transfer_config(hi2c, dev_addr,
+						    xfer_size,
+						    I2C_RELOAD_MODE,
+						    I2C_NO_STARTSTOP);
+			} else {
+				xfer_size = xfer_count;
+				i2c_transfer_config(hi2c, dev_addr,
+						    xfer_size,
+						    I2C_AUTOEND_MODE,
+						    I2C_NO_STARTSTOP);
+			}
+		}
+
+	} while (xfer_count > 0U);
+
+	/*
+	 * No need to Check TC flag, with AUTOEND mode the stop
+	 * is automatically generated.
+	 * Wait until STOPF flag is reset.
+	 */
+	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
+		goto bail;
+	}
+
+	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
+
+	hi2c->i2c_state = I2C_STATE_READY;
+	hi2c->i2c_mode  = I2C_MODE_NONE;
+
+	rc = 0;
+
+bail:
+	hi2c->lock = 0;
+	stm32mp_clk_disable(hi2c->clock);
+
+	return rc;
+}
+
+/*
+ * @brief  Write an amount of data in blocking mode to a specific memory
+ *         address.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: Size of internal memory address
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			uint16_t mem_addr, uint16_t mem_add_size,
+			uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
+{
+	return i2c_write(hi2c, dev_addr, mem_addr, mem_add_size,
+			 p_data, size, timeout_ms, I2C_MODE_MEM);
+}
+
+/*
+ * @brief  Transmits in master mode an amount of data in blocking mode.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			      uint8_t *p_data, uint16_t size,
+			      uint32_t timeout_ms)
+{
+	return i2c_write(hi2c, dev_addr, 0, 0,
+			 p_data, size, timeout_ms, I2C_MODE_MASTER);
+}
+
+/*
+ * @brief  Generic function to read an amount of data in blocking mode
+ *         (for Memory Mode and Master Mode)
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address (if Memory Mode)
+ * @param  mem_add_size: Size of internal memory address (if Memory Mode)
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @param  mode: Communication mode
+ * @retval 0 if OK, negative value else
+ */
+static int i2c_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+		    uint16_t mem_addr, uint16_t mem_add_size,
+		    uint8_t *p_data, uint16_t size, uint32_t timeout_ms,
+		    enum i2c_mode_e mode)
+{
+	uint64_t timeout_ref;
+	int rc = -EIO;
+	uint8_t *p_buff = p_data;
+	uint32_t xfer_count = size;
+	uint32_t xfer_size;
+
+	if ((mode != I2C_MODE_MASTER) && (mode != I2C_MODE_MEM)) {
+		return -1;
+	}
+
+	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+		return -EBUSY;
+	}
+
+	if ((p_data == NULL) || (size == 0U)) {
+		return  -EINVAL;
+	}
+
+	stm32mp_clk_enable(hi2c->clock);
+
+	hi2c->lock = 1;
+
+	timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000);
+	if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) {
+		goto bail;
+	}
+
+	hi2c->i2c_state = I2C_STATE_BUSY_RX;
+	hi2c->i2c_mode = mode;
+	hi2c->i2c_err = I2C_ERROR_NONE;
+
+	if (mode == I2C_MODE_MEM) {
+		/* Send Memory Address */
+		if (i2c_request_memory_read(hi2c, dev_addr, mem_addr,
+					    mem_add_size, timeout_ref) != 0) {
+			goto bail;
+		}
+	}
+
+	/*
+	 * Send Slave Address.
+	 * Set NBYTES to write and reload if xfer_count > MAX_NBYTE_SIZE
+	 * and generate RESTART.
+	 */
+	if (xfer_count > MAX_NBYTE_SIZE) {
+		xfer_size = MAX_NBYTE_SIZE;
+		i2c_transfer_config(hi2c, dev_addr, xfer_size,
+				    I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
+	} else {
+		xfer_size = xfer_count;
+		i2c_transfer_config(hi2c, dev_addr, xfer_size,
+				    I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
+	}
+
+	do {
+		if (i2c_wait_flag(hi2c, I2C_FLAG_RXNE, 0, timeout_ref) != 0) {
+			goto bail;
+		}
+
+		*p_buff = mmio_read_8(hi2c->i2c_base_addr + I2C_RXDR);
+		p_buff++;
+		xfer_size--;
+		xfer_count--;
+
+		if ((xfer_count != 0U) && (xfer_size == 0U)) {
+			if (i2c_wait_flag(hi2c, I2C_FLAG_TCR, 0,
+					  timeout_ref) != 0) {
+				goto bail;
+			}
+
+			if (xfer_count > MAX_NBYTE_SIZE) {
+				xfer_size = MAX_NBYTE_SIZE;
+				i2c_transfer_config(hi2c, dev_addr,
+						    xfer_size,
+						    I2C_RELOAD_MODE,
+						    I2C_NO_STARTSTOP);
+			} else {
+				xfer_size = xfer_count;
+				i2c_transfer_config(hi2c, dev_addr,
+						    xfer_size,
+						    I2C_AUTOEND_MODE,
+						    I2C_NO_STARTSTOP);
+			}
+		}
+	} while (xfer_count > 0U);
+
+	/*
+	 * No need to Check TC flag, with AUTOEND mode the stop
+	 * is automatically generated.
+	 * Wait until STOPF flag is reset.
+	 */
+	if (i2c_wait_stop(hi2c, timeout_ref) != 0) {
+		goto bail;
+	}
+
+	mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR2, I2C_RESET_CR2);
+
+	hi2c->i2c_state = I2C_STATE_READY;
+	hi2c->i2c_mode = I2C_MODE_NONE;
+
+	rc = 0;
+
+bail:
+	hi2c->lock = 0;
+	stm32mp_clk_disable(hi2c->clock);
+
+	return rc;
+}
+
+/*
+ * @brief  Read an amount of data in blocking mode from a specific memory
+ *	   address.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  mem_addr: Internal memory address
+ * @param  mem_add_size: Size of internal memory address
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+		       uint16_t mem_addr, uint16_t mem_add_size,
+		       uint8_t *p_data, uint16_t size, uint32_t timeout_ms)
+{
+	return i2c_read(hi2c, dev_addr, mem_addr, mem_add_size,
+			p_data, size, timeout_ms, I2C_MODE_MEM);
+}
+
+/*
+ * @brief  Receives in master mode an amount of data in blocking mode.
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  p_data: Pointer to data buffer
+ * @param  size: Amount of data to be sent
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @retval 0 if OK, negative value else
+ */
+int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			     uint8_t *p_data, uint16_t size,
+			     uint32_t timeout_ms)
+{
+	return i2c_read(hi2c, dev_addr, 0, 0,
+			p_data, size, timeout_ms, I2C_MODE_MASTER);
+}
+
+/*
+ * @brief  Checks if target device is ready for communication.
+ * @note   This function is used with Memory devices
+ * @param  hi2c: Pointer to a struct i2c_handle_s structure that contains
+ *               the configuration information for the specified I2C.
+ * @param  dev_addr: Target device address
+ * @param  trials: Number of trials
+ * @param  timeout_ms: Timeout duration in milliseconds
+ * @retval True if device is ready, false else
+ */
+bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c,
+			       uint16_t dev_addr, uint32_t trials,
+			       uint32_t timeout_ms)
+{
+	uint32_t i2c_trials = 0U;
+	bool rc = false;
+
+	if ((hi2c->i2c_state != I2C_STATE_READY) || (hi2c->lock != 0U)) {
+		return rc;
+	}
+
+	stm32mp_clk_enable(hi2c->clock);
+
+	hi2c->lock = 1;
+	hi2c->i2c_mode = I2C_MODE_NONE;
+
+	if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_BUSY) !=
+	    0U) {
+		goto bail;
+	}
+
+	hi2c->i2c_state = I2C_STATE_BUSY;
+	hi2c->i2c_err = I2C_ERROR_NONE;
+
+	do {
+		uint64_t timeout_ref;
+
+		/* Generate Start */
+		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_OAR1) &
+		     I2C_OAR1_OA1MODE) == 0) {
+			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
+				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
+				       I2C_CR2_START | I2C_CR2_AUTOEND) &
+				      ~I2C_CR2_RD_WRN);
+		} else {
+			mmio_write_32(hi2c->i2c_base_addr + I2C_CR2,
+				      (((uint32_t)dev_addr & I2C_CR2_SADD) |
+				       I2C_CR2_START | I2C_CR2_ADD10) &
+				      ~I2C_CR2_RD_WRN);
+		}
+
+		/*
+		 * No need to Check TC flag, with AUTOEND mode the stop
+		 * is automatically generated.
+		 * Wait until STOPF flag is set or a NACK flag is set.
+		 */
+		timeout_ref = timeout_init_us(timeout_ms * 1000);
+		do {
+			if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+			     (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) {
+				break;
+			}
+
+			if (timeout_elapsed(timeout_ref)) {
+				notif_i2c_timeout(hi2c);
+				goto bail;
+			}
+		} while (true);
+
+		if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) &
+		     I2C_FLAG_AF) == 0U) {
+			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
+					  timeout_ref) != 0) {
+				goto bail;
+			}
+
+			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
+				      I2C_FLAG_STOPF);
+
+			hi2c->i2c_state = I2C_STATE_READY;
+
+			rc = true;
+			goto bail;
+		}
+
+		if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0, timeout_ref) != 0) {
+			goto bail;
+		}
+
+		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_AF);
+
+		mmio_write_32(hi2c->i2c_base_addr + I2C_ICR, I2C_FLAG_STOPF);
+
+		if (i2c_trials == trials) {
+			mmio_setbits_32(hi2c->i2c_base_addr + I2C_CR2,
+					I2C_CR2_STOP);
+
+			if (i2c_wait_flag(hi2c, I2C_FLAG_STOPF, 0,
+					  timeout_ref) != 0) {
+				goto bail;
+			}
+
+			mmio_write_32(hi2c->i2c_base_addr + I2C_ICR,
+				      I2C_FLAG_STOPF);
+		}
+
+		i2c_trials++;
+	} while (i2c_trials < trials);
+
+	notif_i2c_timeout(hi2c);
+
+bail:
+	hi2c->lock = 0;
+	stm32mp_clk_disable(hi2c->clock);
+
+	return rc;
+}
+
diff --git a/drivers/st/io/io_mmc.c b/drivers/st/io/io_mmc.c
new file mode 100644
index 0000000..a239b5f
--- /dev/null
+++ b/drivers/st/io/io_mmc.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/st/io_mmc.h>
+#include <drivers/st/stm32_sdmmc2.h>
+
+/* SDMMC device functions */
+static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info);
+static int mmc_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			  io_entity_t *entity);
+static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
+static int mmc_block_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+			  size_t *length_read);
+static int mmc_block_close(io_entity_t *entity);
+static int mmc_dev_close(io_dev_info_t *dev_info);
+static io_type_t device_type_mmc(void);
+
+static ssize_t seek_offset;
+
+static const io_dev_connector_t mmc_dev_connector = {
+	.dev_open = mmc_dev_open
+};
+
+static const io_dev_funcs_t mmc_dev_funcs = {
+	.type = device_type_mmc,
+	.open = mmc_block_open,
+	.seek = mmc_block_seek,
+	.size = NULL,
+	.read = mmc_block_read,
+	.write = NULL,
+	.close = mmc_block_close,
+	.dev_init = mmc_dev_init,
+	.dev_close = mmc_dev_close,
+};
+
+static const io_dev_info_t mmc_dev_info = {
+	.funcs = &mmc_dev_funcs,
+	.info = 0,
+};
+
+/* Identify the device type as mmc device */
+static io_type_t device_type_mmc(void)
+{
+	return IO_TYPE_MMC;
+}
+
+/* Open a connection to the mmc device */
+static int mmc_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info)
+{
+	assert(dev_info != NULL);
+	*dev_info = (io_dev_info_t *)&mmc_dev_info;
+
+	return 0;
+}
+
+static int mmc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
+{
+	return 0;
+}
+
+/* Close a connection to the mmc device */
+static int mmc_dev_close(io_dev_info_t *dev_info)
+{
+	return 0;
+}
+
+/* Open a file on the mmc device */
+static int mmc_block_open(io_dev_info_t *dev_info, const  uintptr_t spec,
+			  io_entity_t *entity)
+{
+	seek_offset = 0;
+	return 0;
+}
+
+/* Seek to a particular file offset on the mmc device */
+static int mmc_block_seek(io_entity_t *entity, int mode, ssize_t offset)
+{
+	seek_offset = offset;
+	return 0;
+}
+
+/* Read data from a file on the mmc device */
+static int mmc_block_read(io_entity_t *entity, uintptr_t buffer,
+			  size_t length, size_t *length_read)
+{
+	*length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE,
+				       buffer, length);
+
+	if (*length_read != length) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* Close a file on the mmc device */
+static int mmc_block_close(io_entity_t *entity)
+{
+	return 0;
+}
+
+/* Register the mmc driver with the IO abstraction */
+int register_io_dev_mmc(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	result = io_register_device(&mmc_dev_info);
+	if (result == 0) {
+		*dev_con = &mmc_dev_connector;
+	}
+
+	return result;
+}
diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c
new file mode 100644
index 0000000..dc2977d
--- /dev/null
+++ b/drivers/st/io/io_stm32image.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/st/io_stm32image.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+static uintptr_t backend_dev_handle;
+static uintptr_t backend_image_spec;
+static uint32_t *stm32_img;
+static uint8_t first_lba_buffer[MAX_LBA_SIZE] __aligned(4);
+static struct stm32image_part_info *current_part;
+
+/* STM32 Image driver functions */
+static int stm32image_dev_open(const uintptr_t init_params,
+			       io_dev_info_t **dev_info);
+static int stm32image_partition_open(io_dev_info_t *dev_info,
+				     const uintptr_t spec, io_entity_t *entity);
+static int stm32image_partition_size(io_entity_t *entity, size_t *length);
+static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
+				     size_t length, size_t *length_read);
+static int stm32image_partition_close(io_entity_t *entity);
+static int stm32image_dev_init(io_dev_info_t *dev_info,
+			       const uintptr_t init_params);
+static int stm32image_dev_close(io_dev_info_t *dev_info);
+
+/* Identify the device type as a virtual driver */
+static io_type_t device_type_stm32image(void)
+{
+	return IO_TYPE_STM32IMAGE;
+}
+
+static const io_dev_connector_t stm32image_dev_connector = {
+	.dev_open = stm32image_dev_open
+};
+
+static const io_dev_funcs_t stm32image_dev_funcs = {
+	.type = device_type_stm32image,
+	.open = stm32image_partition_open,
+	.size = stm32image_partition_size,
+	.read = stm32image_partition_read,
+	.close = stm32image_partition_close,
+	.dev_init = stm32image_dev_init,
+	.dev_close = stm32image_dev_close,
+};
+
+static io_dev_info_t stm32image_dev_info = {
+	.funcs = &stm32image_dev_funcs,
+	.info = (uintptr_t)0,
+};
+
+static struct stm32image_device_info stm32image_dev;
+
+static int get_part_idx_by_binary_type(uint32_t binary_type)
+{
+	int i;
+
+	for (i = 0; i < STM32_PART_NUM; i++) {
+		if (stm32image_dev.part_info[i].binary_type == binary_type) {
+			return i;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/* Open a connection to the STM32IMAGE device */
+static int stm32image_dev_open(const uintptr_t init_params,
+			       io_dev_info_t **dev_info)
+{
+	int i;
+	struct stm32image_device_info *device_info =
+		(struct stm32image_device_info *)init_params;
+
+	assert(dev_info != NULL);
+	*dev_info = (io_dev_info_t *)&stm32image_dev_info;
+
+	stm32image_dev.device_size = device_info->device_size;
+	stm32image_dev.lba_size = device_info->lba_size;
+
+	for (i = 0; i < STM32_PART_NUM; i++) {
+		memcpy(stm32image_dev.part_info[i].name,
+		       device_info->part_info[i].name, MAX_PART_NAME_SIZE);
+		stm32image_dev.part_info[i].binary_type =
+			device_info->part_info[i].binary_type;
+		stm32image_dev.part_info[i].part_offset =
+			device_info->part_info[i].part_offset;
+		stm32image_dev.part_info[i].bkp_offset =
+			device_info->part_info[i].bkp_offset;
+	}
+
+	return 0;
+}
+
+/* Do some basic package checks */
+static int stm32image_dev_init(io_dev_info_t *dev_info,
+			       const uintptr_t init_params)
+{
+	int result;
+
+	if ((backend_dev_handle != 0U) || (backend_image_spec != 0U)) {
+		ERROR("STM32 Image io supports only one session\n");
+		return -ENOMEM;
+	}
+
+	/* Obtain a reference to the image by querying the platform layer */
+	result = plat_get_image_source(STM32_IMAGE_ID, &backend_dev_handle,
+				       &backend_image_spec);
+	if (result != 0) {
+		ERROR("STM32 image error (%i)\n", result);
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+/* Close a connection to the STM32 Image device */
+static int stm32image_dev_close(io_dev_info_t *dev_info)
+{
+	backend_dev_handle = 0U;
+	backend_image_spec = 0U;
+	stm32_img = NULL;
+
+	return 0;
+}
+
+/* Open a partition */
+static int stm32image_partition_open(io_dev_info_t *dev_info,
+				     const uintptr_t spec, io_entity_t *entity)
+{
+	const struct stm32image_part_info *partition_spec;
+	int idx;
+
+	assert(entity != NULL);
+
+	partition_spec = (struct stm32image_part_info *)spec;
+	assert(partition_spec != NULL);
+
+	idx = get_part_idx_by_binary_type(partition_spec->binary_type);
+	if ((idx < 0) || (idx > STM32_PART_NUM)) {
+		ERROR("Wrong partition index (%d)\n", idx);
+		return -EINVAL;
+	}
+
+	current_part = &stm32image_dev.part_info[idx];
+	stm32_img = (uint32_t *)&current_part->part_offset;
+
+	return 0;
+}
+
+/* Return the size of a partition */
+static int stm32image_partition_size(io_entity_t *entity, size_t *length)
+{
+	int result;
+	uintptr_t backend_handle;
+	size_t bytes_read;
+	boot_api_image_header_t *header =
+		(boot_api_image_header_t *)first_lba_buffer;
+
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	/* Attempt to access the image */
+	result = io_open(backend_dev_handle, backend_image_spec,
+			 &backend_handle);
+
+	if (result < 0) {
+		ERROR("%s: io_open (%i)\n", __func__, result);
+		return result;
+	}
+
+	/* Reset magic header value */
+	header->magic = 0;
+
+	while (header->magic == 0U) {
+		result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img);
+		if (result != 0) {
+			ERROR("%s: io_seek (%i)\n", __func__, result);
+			break;
+		}
+
+		result = io_read(backend_handle, (uintptr_t)header,
+				 MAX_LBA_SIZE, (size_t *)&bytes_read);
+		if (result != 0) {
+			if (current_part->bkp_offset == 0U) {
+				ERROR("%s: io_read (%i)\n", __func__, result);
+			}
+			header->magic = 0;
+		}
+
+		if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
+		    (header->binary_type != current_part->binary_type) ||
+		    (header->image_length >= stm32image_dev.device_size)) {
+			VERBOSE("%s: partition %s not found at %x\n",
+				__func__, current_part->name, *stm32_img);
+
+			if (current_part->bkp_offset == 0U) {
+				result = -ENOMEM;
+				break;
+			}
+
+			/* Header not correct, check next offset for backup */
+			*stm32_img += current_part->bkp_offset;
+			if (*stm32_img > stm32image_dev.device_size) {
+				/* No backup found, end of device reached */
+				WARN("%s : partition %s not found\n",
+				     __func__, current_part->name);
+				result = -ENOMEM;
+				break;
+			}
+			header->magic = 0;
+		}
+	}
+
+	io_close(backend_handle);
+
+	if (result != 0) {
+		return result;
+	}
+
+	if (header->image_length < stm32image_dev.lba_size) {
+		*length = stm32image_dev.lba_size;
+	} else {
+		*length = header->image_length;
+	}
+
+	INFO("STM32 Image size : %lu\n", (unsigned long)*length);
+
+	return 0;
+}
+
+static int check_header(boot_api_image_header_t *header, uintptr_t buffer)
+{
+	uint32_t i;
+	uint32_t img_checksum = 0;
+
+	/*
+	 * Check header/payload validity:
+	 *	- Header magic
+	 *	- Header version
+	 *	- Payload checksum
+	 */
+	if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
+		ERROR("Header magic\n");
+		return -EINVAL;
+	}
+
+	if (header->header_version != BOOT_API_HEADER_VERSION) {
+		ERROR("Header version\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < header->image_length; i++) {
+		img_checksum += *(uint8_t *)(buffer + i);
+	}
+
+	if (header->payload_checksum != img_checksum) {
+		ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum,
+		      header->payload_checksum);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Read data from a partition */
+static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
+				     size_t length, size_t *length_read)
+{
+	int result = 0;
+	uint8_t *local_buffer = (uint8_t *)buffer;
+	boot_api_image_header_t *header =
+		(boot_api_image_header_t *)first_lba_buffer;
+
+	assert(entity != NULL);
+	assert(buffer != 0U);
+	assert(length_read != NULL);
+
+	*length_read = 0U;
+
+	while (*length_read == 0U) {
+		int offset;
+		int local_length;
+		uintptr_t backend_handle;
+
+		if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
+			/* Check for backup as image is corrupted */
+			if (current_part->bkp_offset == 0U) {
+				result = -ENOMEM;
+				break;
+			}
+
+			*stm32_img += current_part->bkp_offset;
+			if (*stm32_img >= stm32image_dev.device_size) {
+				/* End of device reached */
+				result = -ENOMEM;
+				break;
+			}
+
+			local_buffer = (uint8_t *)buffer;
+
+			result = stm32image_partition_size(entity, &length);
+			if (result != 0) {
+				break;
+			}
+		}
+
+		/* Part of image already loaded with the header */
+		memcpy(local_buffer, (uint8_t *)first_lba_buffer +
+		       sizeof(boot_api_image_header_t),
+		       MAX_LBA_SIZE - sizeof(boot_api_image_header_t));
+		local_buffer += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
+		offset = MAX_LBA_SIZE;
+
+		/* New image length to be read */
+		local_length = round_up(length -
+					((MAX_LBA_SIZE) -
+					 sizeof(boot_api_image_header_t)),
+					stm32image_dev.lba_size);
+
+		if ((header->load_address != 0U) &&
+		    (header->load_address != buffer)) {
+			ERROR("Wrong load address\n");
+			panic();
+		}
+
+		result = io_open(backend_dev_handle, backend_image_spec,
+				 &backend_handle);
+
+		if (result != 0) {
+			ERROR("%s: io_open (%i)\n", __func__, result);
+			break;
+		}
+
+		result = io_seek(backend_handle, IO_SEEK_SET,
+				 *stm32_img + offset);
+
+		if (result != 0) {
+			ERROR("%s: io_seek (%i)\n", __func__, result);
+			*length_read = 0;
+			io_close(backend_handle);
+			break;
+		}
+
+		result = io_read(backend_handle, (uintptr_t)local_buffer,
+				 local_length, length_read);
+
+		/* Adding part of size already read from header */
+		*length_read += MAX_LBA_SIZE - sizeof(boot_api_image_header_t);
+
+		if (result != 0) {
+			ERROR("%s: io_read (%i)\n", __func__, result);
+			*length_read = 0;
+			header->magic = 0;
+			continue;
+		}
+
+		result = check_header(header, buffer);
+		if (result != 0) {
+			ERROR("Header check failed\n");
+			*length_read = 0;
+			header->magic = 0;
+		}
+
+		io_close(backend_handle);
+	}
+
+	return result;
+}
+
+/* Close a partition */
+static int stm32image_partition_close(io_entity_t *entity)
+{
+	current_part = NULL;
+
+	return 0;
+}
+
+/* Register the stm32image driver with the IO abstraction */
+int register_io_dev_stm32image(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	result = io_register_device(&stm32image_dev_info);
+	if (result == 0) {
+		*dev_con = &stm32image_dev_connector;
+	}
+
+	return result;
+}
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
new file mode 100644
index 0000000..f453ce9
--- /dev/null
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32_sdmmc2.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+/* Registers offsets */
+#define SDMMC_POWER			0x00U
+#define SDMMC_CLKCR			0x04U
+#define SDMMC_ARGR			0x08U
+#define SDMMC_CMDR			0x0CU
+#define SDMMC_RESPCMDR			0x10U
+#define SDMMC_RESP1R			0x14U
+#define SDMMC_RESP2R			0x18U
+#define SDMMC_RESP3R			0x1CU
+#define SDMMC_RESP4R			0x20U
+#define SDMMC_DTIMER			0x24U
+#define SDMMC_DLENR			0x28U
+#define SDMMC_DCTRLR			0x2CU
+#define SDMMC_DCNTR			0x30U
+#define SDMMC_STAR			0x34U
+#define SDMMC_ICR			0x38U
+#define SDMMC_MASKR			0x3CU
+#define SDMMC_ACKTIMER			0x40U
+#define SDMMC_IDMACTRLR			0x50U
+#define SDMMC_IDMABSIZER		0x54U
+#define SDMMC_IDMABASE0R		0x58U
+#define SDMMC_IDMABASE1R		0x5CU
+#define SDMMC_FIFOR			0x80U
+
+/* SDMMC power control register */
+#define SDMMC_POWER_PWRCTRL		GENMASK(1, 0)
+#define SDMMC_POWER_DIRPOL		BIT(4)
+
+/* SDMMC clock control register */
+#define SDMMC_CLKCR_WIDBUS_4		BIT(14)
+#define SDMMC_CLKCR_WIDBUS_8		BIT(15)
+#define SDMMC_CLKCR_NEGEDGE		BIT(16)
+#define SDMMC_CLKCR_HWFC_EN		BIT(17)
+#define SDMMC_CLKCR_SELCLKRX_0		BIT(20)
+
+/* SDMMC command register */
+#define SDMMC_CMDR_CMDTRANS		BIT(6)
+#define SDMMC_CMDR_CMDSTOP		BIT(7)
+#define SDMMC_CMDR_WAITRESP		GENMASK(9, 8)
+#define SDMMC_CMDR_WAITRESP_SHORT	BIT(8)
+#define SDMMC_CMDR_WAITRESP_SHORT_NOCRC	BIT(9)
+#define SDMMC_CMDR_CPSMEN		BIT(12)
+
+/* SDMMC data control register */
+#define SDMMC_DCTRLR_DTEN		BIT(0)
+#define SDMMC_DCTRLR_DTDIR		BIT(1)
+#define SDMMC_DCTRLR_DTMODE		GENMASK(3, 2)
+#define SDMMC_DCTRLR_DBLOCKSIZE_0	BIT(4)
+#define SDMMC_DCTRLR_DBLOCKSIZE_1	BIT(5)
+#define SDMMC_DCTRLR_DBLOCKSIZE_3	BIT(7)
+#define SDMMC_DCTRLR_DBLOCKSIZE		GENMASK(7, 4)
+#define SDMMC_DCTRLR_FIFORST		BIT(13)
+
+#define SDMMC_DCTRLR_CLEAR_MASK		(SDMMC_DCTRLR_DTEN | \
+					 SDMMC_DCTRLR_DTDIR | \
+					 SDMMC_DCTRLR_DTMODE | \
+					 SDMMC_DCTRLR_DBLOCKSIZE)
+#define SDMMC_DBLOCKSIZE_8		(SDMMC_DCTRLR_DBLOCKSIZE_0 | \
+					 SDMMC_DCTRLR_DBLOCKSIZE_1)
+#define SDMMC_DBLOCKSIZE_512		(SDMMC_DCTRLR_DBLOCKSIZE_0 | \
+					 SDMMC_DCTRLR_DBLOCKSIZE_3)
+
+/* SDMMC status register */
+#define SDMMC_STAR_CCRCFAIL		BIT(0)
+#define SDMMC_STAR_DCRCFAIL		BIT(1)
+#define SDMMC_STAR_CTIMEOUT		BIT(2)
+#define SDMMC_STAR_DTIMEOUT		BIT(3)
+#define SDMMC_STAR_TXUNDERR		BIT(4)
+#define SDMMC_STAR_RXOVERR		BIT(5)
+#define SDMMC_STAR_CMDREND		BIT(6)
+#define SDMMC_STAR_CMDSENT		BIT(7)
+#define SDMMC_STAR_DATAEND		BIT(8)
+#define SDMMC_STAR_DBCKEND		BIT(10)
+#define SDMMC_STAR_DPSMACT		BIT(12)
+#define SDMMC_STAR_RXFIFOHF		BIT(15)
+#define SDMMC_STAR_RXFIFOE		BIT(19)
+#define SDMMC_STAR_IDMATE		BIT(27)
+#define SDMMC_STAR_IDMABTC		BIT(28)
+
+/* SDMMC DMA control register */
+#define SDMMC_IDMACTRLR_IDMAEN		BIT(0)
+
+#define SDMMC_STATIC_FLAGS		(SDMMC_STAR_CCRCFAIL | \
+					 SDMMC_STAR_DCRCFAIL | \
+					 SDMMC_STAR_CTIMEOUT | \
+					 SDMMC_STAR_DTIMEOUT | \
+					 SDMMC_STAR_TXUNDERR | \
+					 SDMMC_STAR_RXOVERR  | \
+					 SDMMC_STAR_CMDREND  | \
+					 SDMMC_STAR_CMDSENT  | \
+					 SDMMC_STAR_DATAEND  | \
+					 SDMMC_STAR_DBCKEND  | \
+					 SDMMC_STAR_IDMATE   | \
+					 SDMMC_STAR_IDMABTC)
+
+#define TIMEOUT_US_10_MS		10000U
+#define TIMEOUT_US_1_S			1000000U
+
+#define DT_SDMMC2_COMPAT		"st,stm32-sdmmc2"
+
+static void stm32_sdmmc2_init(void);
+static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd);
+static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd);
+static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width);
+static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size);
+static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size);
+static int stm32_sdmmc2_write(int lba, uintptr_t buf, size_t size);
+
+static const struct mmc_ops stm32_sdmmc2_ops = {
+	.init		= stm32_sdmmc2_init,
+	.send_cmd	= stm32_sdmmc2_send_cmd,
+	.set_ios	= stm32_sdmmc2_set_ios,
+	.prepare	= stm32_sdmmc2_prepare,
+	.read		= stm32_sdmmc2_read,
+	.write		= stm32_sdmmc2_write,
+};
+
+static struct stm32_sdmmc2_params sdmmc2_params;
+
+#pragma weak plat_sdmmc2_use_dma
+bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory)
+{
+	return false;
+}
+
+static void stm32_sdmmc2_init(void)
+{
+	uint32_t clock_div;
+	uintptr_t base = sdmmc2_params.reg_base;
+
+	clock_div = div_round_up(sdmmc2_params.clk_rate,
+				 STM32MP_MMC_INIT_FREQ * 2);
+
+	mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
+		      sdmmc2_params.negedge |
+		      sdmmc2_params.pin_ckin);
+
+	mmio_write_32(base + SDMMC_POWER,
+		      SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol);
+
+	mdelay(1);
+}
+
+static int stm32_sdmmc2_stop_transfer(void)
+{
+	struct mmc_cmd cmd_stop;
+
+	zeromem(&cmd_stop, sizeof(struct mmc_cmd));
+
+	cmd_stop.cmd_idx = MMC_CMD(12);
+	cmd_stop.resp_type = MMC_RESPONSE_R1B;
+
+	return stm32_sdmmc2_send_cmd(&cmd_stop);
+}
+
+static int stm32_sdmmc2_send_cmd_req(struct mmc_cmd *cmd)
+{
+	uint64_t timeout;
+	uint32_t flags_cmd, status;
+	uint32_t flags_data = 0;
+	int err = 0;
+	uintptr_t base = sdmmc2_params.reg_base;
+	unsigned int cmd_reg, arg_reg;
+
+	if (cmd == NULL) {
+		return -EINVAL;
+	}
+
+	flags_cmd = SDMMC_STAR_CTIMEOUT;
+	arg_reg = cmd->cmd_arg;
+
+	if ((mmio_read_32(base + SDMMC_CMDR) & SDMMC_CMDR_CPSMEN) != 0U) {
+		mmio_write_32(base + SDMMC_CMDR, 0);
+	}
+
+	cmd_reg = cmd->cmd_idx | SDMMC_CMDR_CPSMEN;
+
+	if (cmd->resp_type == 0U) {
+		flags_cmd |= SDMMC_STAR_CMDSENT;
+	}
+
+	if ((cmd->resp_type & MMC_RSP_48) != 0U) {
+		if ((cmd->resp_type & MMC_RSP_136) != 0U) {
+			flags_cmd |= SDMMC_STAR_CMDREND;
+			cmd_reg |= SDMMC_CMDR_WAITRESP;
+		} else if ((cmd->resp_type & MMC_RSP_CRC) != 0U) {
+			flags_cmd |= SDMMC_STAR_CMDREND | SDMMC_STAR_CCRCFAIL;
+			cmd_reg |= SDMMC_CMDR_WAITRESP_SHORT;
+		} else {
+			flags_cmd |= SDMMC_STAR_CMDREND;
+			cmd_reg |= SDMMC_CMDR_WAITRESP_SHORT_NOCRC;
+		}
+	}
+
+	switch (cmd->cmd_idx) {
+	case MMC_CMD(1):
+		arg_reg |= OCR_POWERUP;
+		break;
+	case MMC_CMD(8):
+		if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
+			cmd_reg |= SDMMC_CMDR_CMDTRANS;
+		}
+		break;
+	case MMC_CMD(12):
+		cmd_reg |= SDMMC_CMDR_CMDSTOP;
+		break;
+	case MMC_CMD(17):
+	case MMC_CMD(18):
+		cmd_reg |= SDMMC_CMDR_CMDTRANS;
+		if (sdmmc2_params.use_dma) {
+			flags_data |= SDMMC_STAR_DCRCFAIL |
+				      SDMMC_STAR_DTIMEOUT |
+				      SDMMC_STAR_DATAEND |
+				      SDMMC_STAR_RXOVERR |
+				      SDMMC_STAR_IDMATE;
+		}
+		break;
+	case MMC_ACMD(41):
+		arg_reg |= OCR_3_2_3_3 | OCR_3_3_3_4;
+		break;
+	case MMC_ACMD(51):
+		cmd_reg |= SDMMC_CMDR_CMDTRANS;
+		if (sdmmc2_params.use_dma) {
+			flags_data |= SDMMC_STAR_DCRCFAIL |
+				      SDMMC_STAR_DTIMEOUT |
+				      SDMMC_STAR_DATAEND |
+				      SDMMC_STAR_RXOVERR |
+				      SDMMC_STAR_IDMATE |
+				      SDMMC_STAR_DBCKEND;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if ((cmd->resp_type & MMC_RSP_BUSY) != 0U) {
+		mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX);
+	}
+
+	mmio_write_32(base + SDMMC_ARGR, arg_reg);
+
+	mmio_write_32(base + SDMMC_CMDR, cmd_reg);
+
+	status = mmio_read_32(base + SDMMC_STAR);
+
+	timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+	while ((status & flags_cmd) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			err = -ETIMEDOUT;
+			ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n",
+			      __func__, cmd->cmd_idx, status);
+			goto err_exit;
+		}
+
+		status = mmio_read_32(base + SDMMC_STAR);
+	}
+
+	if ((status & (SDMMC_STAR_CTIMEOUT | SDMMC_STAR_CCRCFAIL)) != 0U) {
+		if ((status & SDMMC_STAR_CTIMEOUT) != 0U) {
+			err = -ETIMEDOUT;
+			/*
+			 * Those timeouts can occur, and framework will handle
+			 * the retries. CMD8 is expected to return this timeout
+			 * for eMMC
+			 */
+			if (!((cmd->cmd_idx == MMC_CMD(1)) ||
+			      (cmd->cmd_idx == MMC_CMD(13)) ||
+			      ((cmd->cmd_idx == MMC_CMD(8)) &&
+			       (cmd->resp_type == MMC_RESPONSE_R7)))) {
+				ERROR("%s: CTIMEOUT (cmd = %d,status = %x)\n",
+				      __func__, cmd->cmd_idx, status);
+			}
+		} else {
+			err = -EIO;
+			ERROR("%s: CRCFAIL (cmd = %d,status = %x)\n",
+			      __func__, cmd->cmd_idx, status);
+		}
+
+		goto err_exit;
+	}
+
+	if ((cmd_reg & SDMMC_CMDR_WAITRESP) != 0U) {
+		if ((cmd->cmd_idx == MMC_CMD(9)) &&
+		    ((cmd_reg & SDMMC_CMDR_WAITRESP) == SDMMC_CMDR_WAITRESP)) {
+			/* Need to invert response to match CSD structure */
+			cmd->resp_data[0] = mmio_read_32(base + SDMMC_RESP4R);
+			cmd->resp_data[1] = mmio_read_32(base + SDMMC_RESP3R);
+			cmd->resp_data[2] = mmio_read_32(base + SDMMC_RESP2R);
+			cmd->resp_data[3] = mmio_read_32(base + SDMMC_RESP1R);
+		} else {
+			cmd->resp_data[0] = mmio_read_32(base + SDMMC_RESP1R);
+			if ((cmd_reg & SDMMC_CMDR_WAITRESP) ==
+			    SDMMC_CMDR_WAITRESP) {
+				cmd->resp_data[1] = mmio_read_32(base +
+								 SDMMC_RESP2R);
+				cmd->resp_data[2] = mmio_read_32(base +
+								 SDMMC_RESP3R);
+				cmd->resp_data[3] = mmio_read_32(base +
+								 SDMMC_RESP4R);
+			}
+		}
+	}
+
+	if (flags_data == 0U) {
+		mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
+
+		return 0;
+	}
+
+	status = mmio_read_32(base + SDMMC_STAR);
+
+	timeout = timeout_init_us(TIMEOUT_US_10_MS);
+
+	while ((status & flags_data) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("%s: timeout 10ms (cmd = %d,status = %x)\n",
+			      __func__, cmd->cmd_idx, status);
+			err = -ETIMEDOUT;
+			goto err_exit;
+		}
+
+		status = mmio_read_32(base + SDMMC_STAR);
+	};
+
+	if ((status & (SDMMC_STAR_DTIMEOUT | SDMMC_STAR_DCRCFAIL |
+		       SDMMC_STAR_TXUNDERR | SDMMC_STAR_RXOVERR |
+		       SDMMC_STAR_IDMATE)) != 0U) {
+		ERROR("%s: Error flag (cmd = %d,status = %x)\n", __func__,
+		      cmd->cmd_idx, status);
+		err = -EIO;
+	}
+
+err_exit:
+	mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
+	mmio_clrbits_32(base + SDMMC_CMDR, SDMMC_CMDR_CMDTRANS);
+
+	if ((err != 0) && ((status & SDMMC_STAR_DPSMACT) != 0U)) {
+		int ret_stop = stm32_sdmmc2_stop_transfer();
+
+		if (ret_stop != 0) {
+			return ret_stop;
+		}
+	}
+
+	return err;
+}
+
+static int stm32_sdmmc2_send_cmd(struct mmc_cmd *cmd)
+{
+	int8_t retry;
+	int err = 0;
+
+	assert(cmd != NULL);
+
+	for (retry = 0; retry <= 3; retry++) {
+		err = stm32_sdmmc2_send_cmd_req(cmd);
+		if (err == 0) {
+			return err;
+		}
+
+		if ((cmd->cmd_idx == MMC_CMD(1)) ||
+		    (cmd->cmd_idx == MMC_CMD(13))) {
+			return 0; /* Retry managed by framework */
+		}
+
+		/* Command 8 is expected to fail for eMMC */
+		if (!(cmd->cmd_idx == MMC_CMD(8))) {
+			WARN(" CMD%d, Retry: %d, Error: %d\n",
+			     cmd->cmd_idx, retry, err);
+		}
+
+		udelay(10);
+	}
+
+	return err;
+}
+
+static int stm32_sdmmc2_set_ios(unsigned int clk, unsigned int width)
+{
+	uintptr_t base = sdmmc2_params.reg_base;
+	uint32_t bus_cfg = 0;
+	uint32_t clock_div, max_freq;
+	uint32_t clk_rate = sdmmc2_params.clk_rate;
+	uint32_t max_bus_freq = sdmmc2_params.device_info->max_bus_freq;
+
+	switch (width) {
+	case MMC_BUS_WIDTH_1:
+		break;
+	case MMC_BUS_WIDTH_4:
+		bus_cfg |= SDMMC_CLKCR_WIDBUS_4;
+		break;
+	case MMC_BUS_WIDTH_8:
+		bus_cfg |= SDMMC_CLKCR_WIDBUS_8;
+		break;
+	default:
+		panic();
+		break;
+	}
+
+	if (sdmmc2_params.device_info->mmc_dev_type == MMC_IS_EMMC) {
+		if (max_bus_freq >= 52000000U) {
+			max_freq = STM32MP_EMMC_HIGH_SPEED_MAX_FREQ;
+		} else {
+			max_freq = STM32MP_EMMC_NORMAL_SPEED_MAX_FREQ;
+		}
+	} else {
+		if (max_bus_freq >= 50000000U) {
+			max_freq = STM32MP_SD_HIGH_SPEED_MAX_FREQ;
+		} else {
+			max_freq = STM32MP_SD_NORMAL_SPEED_MAX_FREQ;
+		}
+	}
+
+	clock_div = div_round_up(clk_rate, max_freq * 2);
+
+	mmio_write_32(base + SDMMC_CLKCR,
+		      SDMMC_CLKCR_HWFC_EN | clock_div | bus_cfg |
+		      sdmmc2_params.negedge |
+		      sdmmc2_params.pin_ckin);
+
+	return 0;
+}
+
+static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
+{
+	struct mmc_cmd cmd;
+	int ret;
+	uintptr_t base = sdmmc2_params.reg_base;
+	uint32_t data_ctrl = SDMMC_DCTRLR_DTDIR;
+
+	if (size == 8U) {
+		data_ctrl |= SDMMC_DBLOCKSIZE_8;
+	} else {
+		data_ctrl |= SDMMC_DBLOCKSIZE_512;
+	}
+
+	sdmmc2_params.use_dma = plat_sdmmc2_use_dma(base, buf);
+
+	if (sdmmc2_params.use_dma) {
+		inv_dcache_range(buf, size);
+	}
+
+	/* Prepare CMD 16*/
+	mmio_write_32(base + SDMMC_DTIMER, 0);
+
+	mmio_write_32(base + SDMMC_DLENR, 0);
+
+	mmio_write_32(base + SDMMC_DCTRLR, 0);
+
+	zeromem(&cmd, sizeof(struct mmc_cmd));
+
+	cmd.cmd_idx = MMC_CMD(16);
+	if (size > MMC_BLOCK_SIZE) {
+		cmd.cmd_arg = MMC_BLOCK_SIZE;
+	} else {
+		cmd.cmd_arg = size;
+	}
+
+	cmd.resp_type = MMC_RESPONSE_R1;
+
+	ret = stm32_sdmmc2_send_cmd(&cmd);
+	if (ret != 0) {
+		ERROR("CMD16 failed\n");
+		return ret;
+	}
+
+	/* Prepare data command */
+	mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX);
+
+	mmio_write_32(base + SDMMC_DLENR, size);
+
+	if (sdmmc2_params.use_dma) {
+		mmio_write_32(base + SDMMC_IDMACTRLR,
+			      SDMMC_IDMACTRLR_IDMAEN);
+		mmio_write_32(base + SDMMC_IDMABASE0R, buf);
+
+		flush_dcache_range(buf, size);
+	}
+
+	mmio_clrsetbits_32(base + SDMMC_DCTRLR,
+			   SDMMC_DCTRLR_CLEAR_MASK,
+			   data_ctrl);
+
+	return 0;
+}
+
+static int stm32_sdmmc2_read(int lba, uintptr_t buf, size_t size)
+{
+	uint32_t error_flags = SDMMC_STAR_RXOVERR | SDMMC_STAR_DCRCFAIL |
+			       SDMMC_STAR_DTIMEOUT;
+	uint32_t flags = error_flags | SDMMC_STAR_DATAEND;
+	uint32_t status;
+	uint32_t *buffer;
+	uintptr_t base = sdmmc2_params.reg_base;
+	uintptr_t fifo_reg = base + SDMMC_FIFOR;
+	uint64_t timeout;
+	int ret;
+
+	/* Assert buf is 4 bytes aligned */
+	assert((buf & GENMASK(1, 0)) == 0U);
+
+	buffer = (uint32_t *)buf;
+
+	if (sdmmc2_params.use_dma) {
+		inv_dcache_range(buf, size);
+
+		return 0;
+	}
+
+	if (size <= MMC_BLOCK_SIZE) {
+		flags |= SDMMC_STAR_DBCKEND;
+	}
+
+	timeout = timeout_init_us(TIMEOUT_US_1_S);
+
+	do {
+		status = mmio_read_32(base + SDMMC_STAR);
+
+		if ((status & error_flags) != 0U) {
+			ERROR("%s: Read error (status = %x)\n", __func__,
+			      status);
+			mmio_write_32(base + SDMMC_DCTRLR,
+				      SDMMC_DCTRLR_FIFORST);
+
+			mmio_write_32(base + SDMMC_ICR,
+				      SDMMC_STATIC_FLAGS);
+
+			ret = stm32_sdmmc2_stop_transfer();
+			if (ret != 0) {
+				return ret;
+			}
+
+			return -EIO;
+		}
+
+		if (timeout_elapsed(timeout)) {
+			ERROR("%s: timeout 1s (status = %x)\n",
+			      __func__, status);
+			mmio_write_32(base + SDMMC_ICR,
+				      SDMMC_STATIC_FLAGS);
+
+			ret = stm32_sdmmc2_stop_transfer();
+			if (ret != 0) {
+				return ret;
+			}
+
+			return -ETIMEDOUT;
+		}
+
+		if (size < (8U * sizeof(uint32_t))) {
+			if ((mmio_read_32(base + SDMMC_DCNTR) > 0U) &&
+			    ((status & SDMMC_STAR_RXFIFOE) == 0U)) {
+				*buffer = mmio_read_32(fifo_reg);
+				buffer++;
+			}
+		} else if ((status & SDMMC_STAR_RXFIFOHF) != 0U) {
+			uint32_t count;
+
+			/* Read data from SDMMC Rx FIFO */
+			for (count = 0; count < 8U; count++) {
+				*buffer = mmio_read_32(fifo_reg);
+				buffer++;
+			}
+		}
+	} while ((status & flags) == 0U);
+
+	mmio_write_32(base + SDMMC_ICR, SDMMC_STATIC_FLAGS);
+
+	if ((status & SDMMC_STAR_DPSMACT) != 0U) {
+		WARN("%s: DPSMACT=1, send stop\n", __func__);
+		return stm32_sdmmc2_stop_transfer();
+	}
+
+	return 0;
+}
+
+static int stm32_sdmmc2_write(int lba, uintptr_t buf, size_t size)
+{
+	return 0;
+}
+
+static int stm32_sdmmc2_dt_get_config(void)
+{
+	int sdmmc_node;
+	void *fdt = NULL;
+	const fdt32_t *cuint;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	if (fdt == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	sdmmc_node = fdt_node_offset_by_compatible(fdt, -1, DT_SDMMC2_COMPAT);
+
+	while (sdmmc_node != -FDT_ERR_NOTFOUND) {
+		cuint = fdt_getprop(fdt, sdmmc_node, "reg", NULL);
+		if (cuint == NULL) {
+			continue;
+		}
+
+		if (fdt32_to_cpu(*cuint) == sdmmc2_params.reg_base) {
+			break;
+		}
+
+		sdmmc_node = fdt_node_offset_by_compatible(fdt, sdmmc_node,
+							   DT_SDMMC2_COMPAT);
+	}
+
+	if (sdmmc_node == -FDT_ERR_NOTFOUND) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	if (fdt_get_status(sdmmc_node) == DT_DISABLED) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	if (dt_set_pinctrl_config(sdmmc_node) != 0) {
+		return -FDT_ERR_BADVALUE;
+	}
+
+	cuint = fdt_getprop(fdt, sdmmc_node, "clocks", NULL);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	cuint++;
+	sdmmc2_params.clock_id = fdt32_to_cpu(*cuint);
+
+	cuint = fdt_getprop(fdt, sdmmc_node, "resets", NULL);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	cuint++;
+	sdmmc2_params.reset_id = fdt32_to_cpu(*cuint);
+
+	if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) {
+		sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0;
+	}
+
+	if ((fdt_getprop(fdt, sdmmc_node, "st,sig-dir", NULL)) != NULL) {
+		sdmmc2_params.dirpol = SDMMC_POWER_DIRPOL;
+	}
+
+	if ((fdt_getprop(fdt, sdmmc_node, "st,neg-edge", NULL)) != NULL) {
+		sdmmc2_params.negedge = SDMMC_CLKCR_NEGEDGE;
+	}
+
+	cuint = fdt_getprop(fdt, sdmmc_node, "bus-width", NULL);
+	if (cuint != NULL) {
+		switch (fdt32_to_cpu(*cuint)) {
+		case 4:
+			sdmmc2_params.bus_width = MMC_BUS_WIDTH_4;
+			break;
+
+		case 8:
+			sdmmc2_params.bus_width = MMC_BUS_WIDTH_8;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+
+unsigned long long stm32_sdmmc2_mmc_get_device_size(void)
+{
+	return sdmmc2_params.device_info->device_size;
+}
+
+int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
+{
+	assert((params != NULL) &&
+	       ((params->reg_base & MMC_BLOCK_MASK) == 0U) &&
+	       ((params->bus_width == MMC_BUS_WIDTH_1) ||
+		(params->bus_width == MMC_BUS_WIDTH_4) ||
+		(params->bus_width == MMC_BUS_WIDTH_8)));
+
+	memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params));
+
+	if (stm32_sdmmc2_dt_get_config() != 0) {
+		ERROR("%s: DT error\n", __func__);
+		return -ENOMEM;
+	}
+
+	stm32mp_clk_enable(sdmmc2_params.clock_id);
+
+	stm32mp_reset_assert(sdmmc2_params.reset_id);
+	udelay(2);
+	stm32mp_reset_deassert(sdmmc2_params.reset_id);
+	mdelay(1);
+
+	sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id);
+	sdmmc2_params.device_info->ocr_voltage = OCR_3_2_3_3 | OCR_3_3_3_4;
+
+	return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate,
+			sdmmc2_params.bus_width, sdmmc2_params.flags,
+			sdmmc2_params.device_info);
+}
diff --git a/drivers/st/pmic/stm32mp_pmic.c b/drivers/st/pmic/stm32mp_pmic.c
new file mode 100644
index 0000000..6fe51f4
--- /dev/null
+++ b/drivers/st/pmic/stm32mp_pmic.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_i2c.h>
+#include <drivers/st/stm32mp_pmic.h>
+#include <drivers/st/stpmic1.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#define STPMIC1_LDO12356_OUTPUT_MASK	(uint8_t)(GENMASK(6, 2))
+#define STPMIC1_LDO12356_OUTPUT_SHIFT	2
+#define STPMIC1_LDO3_MODE		(uint8_t)(BIT(7))
+#define STPMIC1_LDO3_DDR_SEL		31U
+#define STPMIC1_LDO3_1800000		(9U << STPMIC1_LDO12356_OUTPUT_SHIFT)
+
+#define STPMIC1_BUCK_OUTPUT_SHIFT	2
+#define STPMIC1_BUCK3_1V8		(39U << STPMIC1_BUCK_OUTPUT_SHIFT)
+
+#define STPMIC1_DEFAULT_START_UP_DELAY_MS	1
+
+static struct i2c_handle_s i2c_handle;
+static uint32_t pmic_i2c_addr;
+
+static int dt_get_pmic_node(void *fdt)
+{
+	return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
+}
+
+int dt_pmic_status(void)
+{
+	int node;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	node = dt_get_pmic_node(fdt);
+	if (node <= 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	return fdt_get_status(node);
+}
+
+/*
+ * Get PMIC and its I2C bus configuration from the device tree.
+ * Return 0 on success, negative on error, 1 if no PMIC node is found.
+ */
+static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
+			      struct stm32_i2c_init_s *init)
+{
+	int pmic_node, i2c_node;
+	void *fdt;
+	const fdt32_t *cuint;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	pmic_node = dt_get_pmic_node(fdt);
+	if (pmic_node < 0) {
+		return 1;
+	}
+
+	cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
+	if (cuint == NULL) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
+	if (pmic_i2c_addr > UINT16_MAX) {
+		return -EINVAL;
+	}
+
+	i2c_node = fdt_parent_offset(fdt, pmic_node);
+	if (i2c_node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	dt_fill_device_info(i2c_info, i2c_node);
+	if (i2c_info->base == 0U) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
+}
+
+int dt_pmic_configure_boot_on_regulators(void)
+{
+	int pmic_node, regulators_node, regulator_node;
+	void *fdt;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return -ENOENT;
+	}
+
+	pmic_node = dt_get_pmic_node(fdt);
+	if (pmic_node < 0) {
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
+
+	fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
+		const fdt32_t *cuint;
+		const char *node_name = fdt_get_name(fdt, regulator_node, NULL);
+		uint16_t voltage;
+		int status;
+
+#if defined(IMAGE_BL2)
+		if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on",
+				 NULL) == NULL) &&
+		    (fdt_getprop(fdt, regulator_node, "regulator-always-on",
+				 NULL) == NULL)) {
+#else
+		if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
+				NULL) == NULL) {
+#endif
+			continue;
+		}
+
+		if (fdt_getprop(fdt, regulator_node, "regulator-pull-down",
+				NULL) != NULL) {
+
+			status = stpmic1_regulator_pull_down_set(node_name);
+			if (status != 0) {
+				return status;
+			}
+		}
+
+		if (fdt_getprop(fdt, regulator_node, "st,mask-reset",
+				NULL) != NULL) {
+
+			status = stpmic1_regulator_mask_reset_set(node_name);
+			if (status != 0) {
+				return status;
+			}
+		}
+
+		cuint = fdt_getprop(fdt, regulator_node,
+				    "regulator-min-microvolt", NULL);
+		if (cuint == NULL) {
+			continue;
+		}
+
+		/* DT uses microvolts, whereas driver awaits millivolts */
+		voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
+
+		status = stpmic1_regulator_voltage_set(node_name, voltage);
+		if (status != 0) {
+			return status;
+		}
+
+		if (stpmic1_is_regulator_enabled(node_name) == 0U) {
+			status = stpmic1_regulator_enable(node_name);
+			if (status != 0) {
+				return status;
+			}
+		}
+	}
+
+	return 0;
+}
+
+bool initialize_pmic_i2c(void)
+{
+	int ret;
+	struct dt_node_info i2c_info;
+	struct i2c_handle_s *i2c = &i2c_handle;
+	struct stm32_i2c_init_s i2c_init;
+
+	ret = dt_pmic_i2c_config(&i2c_info, &i2c_init);
+	if (ret < 0) {
+		ERROR("I2C configuration failed %d\n", ret);
+		panic();
+	}
+
+	if (ret != 0) {
+		return false;
+	}
+
+	/* Initialize PMIC I2C */
+	i2c->i2c_base_addr		= i2c_info.base;
+	i2c->dt_status			= i2c_info.status;
+	i2c->clock			= i2c_info.clock;
+	i2c_init.own_address1		= pmic_i2c_addr;
+	i2c_init.addressing_mode	= I2C_ADDRESSINGMODE_7BIT;
+	i2c_init.dual_address_mode	= I2C_DUALADDRESS_DISABLE;
+	i2c_init.own_address2		= 0;
+	i2c_init.own_address2_masks	= I2C_OAR2_OA2NOMASK;
+	i2c_init.general_call_mode	= I2C_GENERALCALL_DISABLE;
+	i2c_init.no_stretch_mode	= I2C_NOSTRETCH_DISABLE;
+	i2c_init.analog_filter		= 1;
+	i2c_init.digital_filter_coef	= 0;
+
+	ret = stm32_i2c_init(i2c, &i2c_init);
+	if (ret != 0) {
+		ERROR("Cannot initialize I2C %x (%d)\n",
+		      i2c->i2c_base_addr, ret);
+		panic();
+	}
+
+	if (!stm32_i2c_is_device_ready(i2c, pmic_i2c_addr, 1,
+				       I2C_TIMEOUT_BUSY_MS)) {
+		ERROR("I2C device not ready\n");
+		panic();
+	}
+
+	stpmic1_bind_i2c(i2c, (uint16_t)pmic_i2c_addr);
+
+	return true;
+}
+
+void initialize_pmic(void)
+{
+	unsigned long pmic_version;
+
+	if (!initialize_pmic_i2c()) {
+		VERBOSE("No PMIC\n");
+		return;
+	}
+
+	if (stpmic1_get_version(&pmic_version) != 0) {
+		ERROR("Failed to access PMIC\n");
+		panic();
+	}
+
+	INFO("PMIC version = 0x%02lx\n", pmic_version);
+	stpmic1_dump_regulators();
+
+#if defined(IMAGE_BL2)
+	if (dt_pmic_configure_boot_on_regulators() != 0) {
+		panic();
+	};
+#endif
+}
+
+int pmic_ddr_power_init(enum ddr_type ddr_type)
+{
+	bool buck3_at_1v8 = false;
+	uint8_t read_val;
+	int status;
+
+	switch (ddr_type) {
+	case STM32MP_DDR3:
+		/* Set LDO3 to sync mode */
+		status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
+		if (status != 0) {
+			return status;
+		}
+
+		read_val &= ~STPMIC1_LDO3_MODE;
+		read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
+		read_val |= STPMIC1_LDO3_DDR_SEL <<
+			    STPMIC1_LDO12356_OUTPUT_SHIFT;
+
+		status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
+		if (status != 0) {
+			return status;
+		}
+
+		status = stpmic1_regulator_voltage_set("buck2", 1350);
+		if (status != 0) {
+			return status;
+		}
+
+		status = stpmic1_regulator_enable("buck2");
+		if (status != 0) {
+			return status;
+		}
+
+		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+
+		status = stpmic1_regulator_enable("vref_ddr");
+		if (status != 0) {
+			return status;
+		}
+
+		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+
+		status = stpmic1_regulator_enable("ldo3");
+		if (status != 0) {
+			return status;
+		}
+
+		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+		break;
+
+	case STM32MP_LPDDR2:
+		/*
+		 * Set LDO3 to 1.8V
+		 * Set LDO3 to bypass mode if BUCK3 = 1.8V
+		 * Set LDO3 to normal mode if BUCK3 != 1.8V
+		 */
+		status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val);
+		if (status != 0) {
+			return status;
+		}
+
+		if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) {
+			buck3_at_1v8 = true;
+		}
+
+		status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
+		if (status != 0) {
+			return status;
+		}
+
+		read_val &= ~STPMIC1_LDO3_MODE;
+		read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
+		read_val |= STPMIC1_LDO3_1800000;
+		if (buck3_at_1v8) {
+			read_val |= STPMIC1_LDO3_MODE;
+		}
+
+		status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
+		if (status != 0) {
+			return status;
+		}
+
+		status = stpmic1_regulator_voltage_set("buck2", 1200);
+		if (status != 0) {
+			return status;
+		}
+
+		status = stpmic1_regulator_enable("ldo3");
+		if (status != 0) {
+			return status;
+		}
+
+		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+
+		status = stpmic1_regulator_enable("buck2");
+		if (status != 0) {
+			return status;
+		}
+
+		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+
+		status = stpmic1_regulator_enable("vref_ddr");
+		if (status != 0) {
+			return status;
+		}
+
+		mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
+		break;
+
+	default:
+		break;
+	};
+
+	return 0;
+}
diff --git a/drivers/st/pmic/stpmic1.c b/drivers/st/pmic/stpmic1.c
new file mode 100644
index 0000000..9999630
--- /dev/null
+++ b/drivers/st/pmic/stpmic1.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/st/stpmic1.h>
+
+#define I2C_TIMEOUT_MS		25
+
+struct regul_struct {
+	const char *dt_node_name;
+	const uint16_t *voltage_table;
+	uint8_t voltage_table_size;
+	uint8_t control_reg;
+	uint8_t low_power_reg;
+	uint8_t pull_down_reg;
+	uint8_t pull_down;
+	uint8_t mask_reset_reg;
+	uint8_t mask_reset;
+};
+
+static struct i2c_handle_s *pmic_i2c_handle;
+static uint16_t pmic_i2c_addr;
+
+/* Voltage tables in mV */
+static const uint16_t buck1_voltage_table[] = {
+	725,
+	725,
+	725,
+	725,
+	725,
+	725,
+	750,
+	775,
+	800,
+	825,
+	850,
+	875,
+	900,
+	925,
+	950,
+	975,
+	1000,
+	1025,
+	1050,
+	1075,
+	1100,
+	1125,
+	1150,
+	1175,
+	1200,
+	1225,
+	1250,
+	1275,
+	1300,
+	1325,
+	1350,
+	1375,
+	1400,
+	1425,
+	1450,
+	1475,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+	1500,
+};
+
+static const uint16_t buck2_voltage_table[] = {
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1050,
+	1050,
+	1100,
+	1100,
+	1150,
+	1150,
+	1200,
+	1200,
+	1250,
+	1250,
+	1300,
+	1300,
+	1350,
+	1350,
+	1400,
+	1400,
+	1450,
+	1450,
+	1500,
+};
+
+static const uint16_t buck3_voltage_table[] = {
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1000,
+	1100,
+	1100,
+	1100,
+	1100,
+	1200,
+	1200,
+	1200,
+	1200,
+	1300,
+	1300,
+	1300,
+	1300,
+	1400,
+	1400,
+	1400,
+	1400,
+	1500,
+	1600,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+	3400,
+};
+
+static const uint16_t buck4_voltage_table[] = {
+	600,
+	625,
+	650,
+	675,
+	700,
+	725,
+	750,
+	775,
+	800,
+	825,
+	850,
+	875,
+	900,
+	925,
+	950,
+	975,
+	1000,
+	1025,
+	1050,
+	1075,
+	1100,
+	1125,
+	1150,
+	1175,
+	1200,
+	1225,
+	1250,
+	1275,
+	1300,
+	1300,
+	1350,
+	1350,
+	1400,
+	1400,
+	1450,
+	1450,
+	1500,
+	1600,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+	3400,
+	3500,
+	3600,
+	3700,
+	3800,
+	3900,
+};
+
+static const uint16_t ldo1_voltage_table[] = {
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+};
+
+static const uint16_t ldo2_voltage_table[] = {
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+};
+
+static const uint16_t ldo3_voltage_table[] = {
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+	3300,
+	3300,
+	3300,
+	3300,
+	3300,
+	3300,
+	500,
+	0xFFFF, /* VREFDDR */
+};
+
+static const uint16_t ldo5_voltage_table[] = {
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+	3400,
+	3500,
+	3600,
+	3700,
+	3800,
+	3900,
+};
+
+static const uint16_t ldo6_voltage_table[] = {
+	900,
+	1000,
+	1100,
+	1200,
+	1300,
+	1400,
+	1500,
+	1600,
+	1700,
+	1800,
+	1900,
+	2000,
+	2100,
+	2200,
+	2300,
+	2400,
+	2500,
+	2600,
+	2700,
+	2800,
+	2900,
+	3000,
+	3100,
+	3200,
+	3300,
+};
+
+static const uint16_t ldo4_voltage_table[] = {
+	3300,
+};
+
+static const uint16_t vref_ddr_voltage_table[] = {
+	3300,
+};
+
+/* Table of Regulators in PMIC SoC */
+static const struct regul_struct regulators_table[] = {
+	{
+		.dt_node_name	= "buck1",
+		.voltage_table	= buck1_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
+		.control_reg	= BUCK1_CONTROL_REG,
+		.low_power_reg	= BUCK1_PWRCTRL_REG,
+		.pull_down_reg	= BUCK_PULL_DOWN_REG,
+		.pull_down	= BUCK1_PULL_DOWN_SHIFT,
+		.mask_reset_reg	= MASK_RESET_BUCK_REG,
+		.mask_reset	= BUCK1_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "buck2",
+		.voltage_table	= buck2_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
+		.control_reg	= BUCK2_CONTROL_REG,
+		.low_power_reg	= BUCK2_PWRCTRL_REG,
+		.pull_down_reg	= BUCK_PULL_DOWN_REG,
+		.pull_down	= BUCK2_PULL_DOWN_SHIFT,
+		.mask_reset_reg	= MASK_RESET_BUCK_REG,
+		.mask_reset	= BUCK2_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "buck3",
+		.voltage_table	= buck3_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
+		.control_reg	= BUCK3_CONTROL_REG,
+		.low_power_reg	= BUCK3_PWRCTRL_REG,
+		.pull_down_reg	= BUCK_PULL_DOWN_REG,
+		.pull_down	= BUCK3_PULL_DOWN_SHIFT,
+		.mask_reset_reg	= MASK_RESET_BUCK_REG,
+		.mask_reset	= BUCK3_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "buck4",
+		.voltage_table	= buck4_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
+		.control_reg	= BUCK4_CONTROL_REG,
+		.low_power_reg	= BUCK4_PWRCTRL_REG,
+		.pull_down_reg	= BUCK_PULL_DOWN_REG,
+		.pull_down	= BUCK4_PULL_DOWN_SHIFT,
+		.mask_reset_reg	= MASK_RESET_BUCK_REG,
+		.mask_reset	= BUCK4_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "ldo1",
+		.voltage_table	= ldo1_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
+		.control_reg	= LDO1_CONTROL_REG,
+		.low_power_reg	= LDO1_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= LDO1_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "ldo2",
+		.voltage_table	= ldo2_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
+		.control_reg	= LDO2_CONTROL_REG,
+		.low_power_reg	= LDO2_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= LDO2_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "ldo3",
+		.voltage_table	= ldo3_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
+		.control_reg	= LDO3_CONTROL_REG,
+		.low_power_reg	= LDO3_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= LDO3_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "ldo4",
+		.voltage_table	= ldo4_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
+		.control_reg	= LDO4_CONTROL_REG,
+		.low_power_reg	= LDO4_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= LDO4_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "ldo5",
+		.voltage_table	= ldo5_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
+		.control_reg	= LDO5_CONTROL_REG,
+		.low_power_reg	= LDO5_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= LDO5_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "ldo6",
+		.voltage_table	= ldo6_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
+		.control_reg	= LDO6_CONTROL_REG,
+		.low_power_reg	= LDO6_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= LDO6_MASK_RESET,
+	},
+	{
+		.dt_node_name	= "vref_ddr",
+		.voltage_table	= vref_ddr_voltage_table,
+		.voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
+		.control_reg	= VREF_DDR_CONTROL_REG,
+		.low_power_reg	= VREF_DDR_PWRCTRL_REG,
+		.mask_reset_reg	= MASK_RESET_LDO_REG,
+		.mask_reset	= VREF_DDR_MASK_RESET,
+	},
+};
+
+#define MAX_REGUL	ARRAY_SIZE(regulators_table)
+
+static const struct regul_struct *get_regulator_data(const char *name)
+{
+	uint8_t i;
+
+	for (i = 0 ; i < MAX_REGUL ; i++) {
+		if (strncmp(name, regulators_table[i].dt_node_name,
+			    strlen(regulators_table[i].dt_node_name)) == 0) {
+			return &regulators_table[i];
+		}
+	}
+
+	/* Regulator not found */
+	panic();
+	return NULL;
+}
+
+static uint8_t voltage_to_index(const char *name, uint16_t millivolts)
+{
+	const struct regul_struct *regul = get_regulator_data(name);
+	uint8_t i;
+
+	for (i = 0 ; i < regul->voltage_table_size ; i++) {
+		if (regul->voltage_table[i] == millivolts) {
+			return i;
+		}
+	}
+
+	/* Voltage not found */
+	panic();
+
+	return 0;
+}
+
+int stpmic1_powerctrl_on(void)
+{
+	return stpmic1_register_update(MAIN_CONTROL_REG, PWRCTRL_PIN_VALID,
+				       PWRCTRL_PIN_VALID);
+}
+
+int stpmic1_switch_off(void)
+{
+	return stpmic1_register_update(MAIN_CONTROL_REG, 1,
+				       SOFTWARE_SWITCH_OFF_ENABLED);
+}
+
+int stpmic1_regulator_enable(const char *name)
+{
+	const struct regul_struct *regul = get_regulator_data(name);
+
+	return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0));
+}
+
+int stpmic1_regulator_disable(const char *name)
+{
+	const struct regul_struct *regul = get_regulator_data(name);
+
+	return stpmic1_register_update(regul->control_reg, 0, BIT(0));
+}
+
+uint8_t stpmic1_is_regulator_enabled(const char *name)
+{
+	uint8_t val;
+	const struct regul_struct *regul = get_regulator_data(name);
+
+	if (stpmic1_register_read(regul->control_reg, &val) != 0) {
+		panic();
+	}
+
+	return (val & 0x1U);
+}
+
+int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
+{
+	uint8_t voltage_index = voltage_to_index(name, millivolts);
+	const struct regul_struct *regul = get_regulator_data(name);
+	uint8_t mask;
+
+	/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
+	if (strncmp(name, "buck", 4) == 0) {
+		mask = BUCK_VOLTAGE_MASK;
+	} else if ((strncmp(name, "ldo", 3) == 0) &&
+		   (strncmp(name, "ldo4", 4) != 0)) {
+		mask = LDO_VOLTAGE_MASK;
+	} else {
+		return 0;
+	}
+
+	return stpmic1_register_update(regul->control_reg,
+				       voltage_index << LDO_BUCK_VOLTAGE_SHIFT,
+				       mask);
+}
+
+int stpmic1_regulator_pull_down_set(const char *name)
+{
+	const struct regul_struct *regul = get_regulator_data(name);
+
+	if (regul->pull_down_reg != 0) {
+		return stpmic1_register_update(regul->pull_down_reg,
+					       BIT(regul->pull_down),
+					       LDO_BUCK_PULL_DOWN_MASK <<
+					       regul->pull_down);
+	}
+
+	return 0;
+}
+
+int stpmic1_regulator_mask_reset_set(const char *name)
+{
+	const struct regul_struct *regul = get_regulator_data(name);
+
+	return stpmic1_register_update(regul->mask_reset_reg,
+				       BIT(regul->mask_reset),
+				       LDO_BUCK_RESET_MASK <<
+				       regul->mask_reset);
+}
+
+int stpmic1_regulator_voltage_get(const char *name)
+{
+	const struct regul_struct *regul = get_regulator_data(name);
+	uint8_t value;
+	uint8_t mask;
+
+	/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
+	if (strncmp(name, "buck", 4) == 0) {
+		mask = BUCK_VOLTAGE_MASK;
+	} else if ((strncmp(name, "ldo", 3) == 0) &&
+		   (strncmp(name, "ldo4", 4) != 0)) {
+		mask = LDO_VOLTAGE_MASK;
+	} else {
+		return 0;
+	}
+
+	if (stpmic1_register_read(regul->control_reg, &value))
+		return -1;
+
+	value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
+
+	if (value > regul->voltage_table_size)
+		return -1;
+
+	return (int)regul->voltage_table[value];
+}
+
+int stpmic1_register_read(uint8_t register_id,  uint8_t *value)
+{
+	return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr,
+				  (uint16_t)register_id,
+				  I2C_MEMADD_SIZE_8BIT, value,
+				  1, I2C_TIMEOUT_MS);
+}
+
+int stpmic1_register_write(uint8_t register_id, uint8_t value)
+{
+	int status;
+
+	status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr,
+				     (uint16_t)register_id,
+				     I2C_MEMADD_SIZE_8BIT, &value,
+				     1, I2C_TIMEOUT_MS);
+
+#if ENABLE_ASSERTIONS
+	if (status != 0) {
+		return status;
+	}
+
+	if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) {
+		uint8_t readval;
+
+		status = stpmic1_register_read(register_id, &readval);
+		if (status != 0) {
+			return status;
+		}
+
+		if (readval != value) {
+			return -1;
+		}
+	}
+#endif
+
+	return status;
+}
+
+int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
+{
+	int status;
+	uint8_t val;
+
+	status = stpmic1_register_read(register_id, &val);
+	if (status != 0) {
+		return status;
+	}
+
+	val = (val & ~mask) | (value & mask);
+
+	return stpmic1_register_write(register_id, val);
+}
+
+void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
+{
+	pmic_i2c_handle = i2c_handle;
+	pmic_i2c_addr = i2c_addr;
+}
+
+void stpmic1_dump_regulators(void)
+{
+	uint32_t i;
+
+	for (i = 0U; i < MAX_REGUL; i++) {
+		const char *name __unused = regulators_table[i].dt_node_name;
+
+		VERBOSE("PMIC regul %s: %sable, %dmV",
+			name,
+			stpmic1_is_regulator_enabled(name) ? "en" : "dis",
+			stpmic1_regulator_voltage_get(name));
+	}
+}
+
+int stpmic1_get_version(unsigned long *version)
+{
+	int rc;
+	uint8_t read_val;
+
+	rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
+	if (rc) {
+		return -1;
+	}
+
+	*version = (unsigned long)read_val;
+
+	return 0;
+}
diff --git a/drivers/st/reset/stm32mp1_reset.c b/drivers/st/reset/stm32mp1_reset.c
new file mode 100644
index 0000000..fd3f93e
--- /dev/null
+++ b/drivers/st/reset/stm32mp1_reset.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <limits.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#define RESET_TIMEOUT_US_1MS	U(1000)
+
+static uint32_t id2reg_offset(unsigned int reset_id)
+{
+	return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t);
+}
+
+static uint8_t id2reg_bit_pos(unsigned int reset_id)
+{
+	return (uint8_t)(reset_id & GENMASK(4, 0));
+}
+
+void stm32mp_reset_assert(uint32_t id)
+{
+	uint32_t offset = id2reg_offset(id);
+	uint32_t bitmsk = BIT(id2reg_bit_pos(id));
+	uint64_t timeout_ref;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	mmio_write_32(rcc_base + offset, bitmsk);
+
+	timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS);
+	while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) {
+		if (timeout_elapsed(timeout_ref)) {
+			panic();
+		}
+	}
+}
+
+void stm32mp_reset_deassert(uint32_t id)
+{
+	uint32_t offset = id2reg_offset(id) + RCC_RSTCLRR_OFFSET;
+	uint32_t bitmsk = BIT(id2reg_bit_pos(id));
+	uint64_t timeout_ref;
+	uintptr_t rcc_base = stm32mp_rcc_base();
+
+	mmio_write_32(rcc_base + offset, bitmsk);
+
+	timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS);
+	while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) {
+		if (timeout_elapsed(timeout_ref)) {
+			panic();
+		}
+	}
+}
diff --git a/drivers/st/uart/aarch32/stm32_console.S b/drivers/st/uart/aarch32/stm32_console.S
new file mode 100644
index 0000000..39e449b
--- /dev/null
+++ b/drivers/st/uart/aarch32/stm32_console.S
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/st/stm32_console.h>
+#include <drivers/st/stm32_uart_regs.h>
+
+#define USART_TIMEOUT		0x1000
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writeable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl	console_stm32_core_init
+	.globl	console_stm32_core_putc
+	.globl	console_stm32_core_getc
+	.globl	console_stm32_core_flush
+
+	.globl	console_stm32_putc
+	.globl	console_stm32_flush
+
+
+
+	/* -----------------------------------------------------------------
+	 * int console_core_init(uintptr_t base_addr,
+	 *			 unsigned int uart_clk,
+	 *			 unsigned int baud_rate)
+	 *
+	 * Function to initialize the console without a C Runtime to print
+	 * debug information. This function will be accessed by console_init
+	 * and crash reporting.
+	 *
+	 * In: r0 - console base address
+	 *     r1 - Uart clock in Hz
+	 *     r2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : r1, r2, r3
+	 * -----------------------------------------------------------------
+	 */
+func console_stm32_core_init
+	/* Check the input base address */
+	cmp	r0, #0
+	beq	core_init_fail
+#if defined(IMAGE_BL2)
+	/* Check baud rate and uart clock for sanity */
+	cmp	r1, #0
+	beq	core_init_fail
+	cmp	r2, #0
+	beq	core_init_fail
+	/* Disable UART */
+	ldr	r3, [r0, #USART_CR1]
+	bic	r3, r3, #USART_CR1_UE
+	str	r3, [r0, #USART_CR1]
+	/* Configure UART */
+	orr	r3, r3, #(USART_CR1_TE | USART_CR1_FIFOEN)
+	str	r3, [r0, #USART_CR1]
+	ldr	r3, [r0, #USART_CR2]
+	bic	r3, r3, #USART_CR2_STOP
+	str	r3, [r0, #USART_CR2]
+	/* Divisor =  (Uart clock + (baudrate / 2)) / baudrate */
+	lsl	r3, r2, #1
+	add	r3, r1, r3
+	udiv	r3, r3, r2
+	str	r3, [r0, #USART_BRR]
+	/* Enable UART */
+	ldr	r3, [r0, #USART_CR1]
+	orr	r3, r3, #USART_CR1_UE
+	str	r3, [r0, #USART_CR1]
+	/* Check TEACK bit */
+	mov	r2, #USART_TIMEOUT
+teack_loop:
+	subs	r2, r2, #1
+	beq	core_init_fail
+	ldr	r3, [r0, #USART_ISR]
+	tst	r3, #USART_ISR_TEACK
+	beq	teack_loop
+#endif /* IMAGE_BL2 */
+	mov	r0, #1
+	bx	lr
+core_init_fail:
+	mov	r0, #0
+	bx	lr
+endfunc console_stm32_core_init
+
+	.globl console_stm32_register
+
+	/* -------------------------------------------------------
+	 * int console_stm32_register(uintptr_t baseaddr,
+	 *     uint32_t clock, uint32_t baud,
+	 *     struct console_stm32 *console);
+	 * Function to initialize and register a new STM32
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: r0 - UART register base address
+	 *     r1 - UART clock in Hz
+	 *     r2 - Baud rate
+	 *     r3 - pointer to empty console_stm32 struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : r0, r1, r2
+	 * -------------------------------------------------------
+	 */
+func console_stm32_register
+	push	{r4, lr}
+	mov	r4, r3
+	cmp	r4, #0
+	beq	register_fail
+	str	r0, [r4, #CONSOLE_T_STM32_BASE]
+
+	bl console_stm32_core_init
+	cmp	r0, #0
+	beq	register_fail
+
+	mov	r0, r4
+	pop	{r4, lr}
+	finish_console_register stm32 putc=1, getc=0, flush=1
+
+register_fail:
+	pop	{r4, pc}
+endfunc console_stm32_register
+
+	/* ---------------------------------------------------------------
+	 * int console_core_putc(int c, uintptr_t base_addr)
+	 *
+	 * Function to output a character over the console. It returns the
+	 * character printed on success or -1 on error.
+	 *
+	 * In : r0 - character to be printed
+	 *      r1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : r2
+	 * ---------------------------------------------------------------
+	 */
+func console_stm32_core_putc
+	/* Check the input parameter */
+	cmp	r1, #0
+	beq	putc_error
+	/* Prepend '\r' to '\n' */
+	cmp	r0, #0xA
+	bne	2f
+1:
+	/* Check Transmit Data Register Empty */
+txe_loop_1:
+	ldr	r2, [r1, #USART_ISR]
+	tst	r2, #USART_ISR_TXE
+	beq	txe_loop_1
+	mov	r2, #0xD
+	str	r2, [r1, #USART_TDR]
+	/* Check transmit complete flag */
+tc_loop_1:
+	ldr	r2, [r1, #USART_ISR]
+	tst	r2, #USART_ISR_TC
+	beq	tc_loop_1
+2:
+	/* Check Transmit Data Register Empty */
+txe_loop_2:
+	ldr	r2, [r1, #USART_ISR]
+	tst	r2, #USART_ISR_TXE
+	beq	txe_loop_2
+	str	r0, [r1, #USART_TDR]
+	/* Check transmit complete flag */
+tc_loop_2:
+	ldr	r2, [r1, #USART_ISR]
+	tst	r2, #USART_ISR_TC
+	beq	tc_loop_2
+	bx	lr
+putc_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_stm32_core_putc
+
+	/* ------------------------------------------------------------
+	 * int console_stm32_putc(int c, struct console_stm32 *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In: r0 - character to be printed
+	 *     r1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list: r2
+	 * ------------------------------------------------------------
+	 */
+func console_stm32_putc
+#if ENABLE_ASSERTIONS
+	cmp	r1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r1, [r1, #CONSOLE_T_STM32_BASE]
+	b	console_stm32_core_putc
+endfunc console_stm32_putc
+
+	/* -----------------------------------------------------------
+	 * int console_core_getc(uintptr_t base_addr)
+	 *
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success or -1 on error.
+	 *
+	 * In : r0 - console base address
+	 * Out : return -1.
+	 * Clobber list : r0, r1
+	 * -----------------------------------------------------------
+	 */
+func console_stm32_core_getc
+	/* Not supported */
+	mov	r0, #-1
+	bx	lr
+endfunc console_stm32_core_getc
+
+	/* ---------------------------------------------------------------
+	 * int console_core_flush(uintptr_t base_addr)
+	 *
+	 * Function to force a write of all buffered data that hasn't been
+	 * output.
+	 *
+	 * In : r0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------------------------
+	 */
+func console_stm32_core_flush
+	cmp	r0, #0
+	beq	flush_error
+	/* Check Transmit Data Register Empty */
+txe_loop_3:
+	ldr	r1, [r0, #USART_ISR]
+	tst	r1, #USART_ISR_TXE
+	beq	txe_loop_3
+	mov	r0, #0
+	bx	lr
+flush_error:
+	mov	r0, #-1
+	bx	lr
+endfunc console_stm32_core_flush
+
+	/* ------------------------------------------------------
+	 * int console_stm32_flush(struct console_stm32 *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : r0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list: r0, r1
+	 * ------------------------------------------------------
+	 */
+func console_stm32_flush
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r0, [r0, #CONSOLE_T_STM32_BASE]
+	b	console_stm32_core_flush
+endfunc console_stm32_flush
diff --git a/drivers/staging/renesas/rcar/ddr/boot_init_dram.h b/drivers/staging/renesas/rcar/ddr/boot_init_dram.h
new file mode 100644
index 0000000..4b0a9eb
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/boot_init_dram.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOOT_INIT_DRAM_H
+#define BOOT_INIT_DRAM_H
+
+extern int32_t rcar_dram_init(void);
+
+#define INITDRAM_OK (0)
+#define INITDRAM_NG (0xffffffff)
+#define INITDRAM_ERR_I (0xffffffff)
+#define INITDRAM_ERR_O (0xfffffffe)
+#define INITDRAM_ERR_T (0xfffffff0)
+
+#endif /* BOOT_INIT_DRAM_H */
diff --git a/drivers/staging/renesas/rcar/ddr/ddr.mk b/drivers/staging/renesas/rcar/ddr/ddr.mk
new file mode 100644
index 0000000..ed7adc3
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${RCAR_LSI},${RCAR_E3})
+    include drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk
+    BL2_SOURCES += drivers/staging/renesas/rcar/ddr/dram_sub_func.c
+else ifeq (${RCAR_LSI},${RCAR_D3})
+    include drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk
+else ifeq (${RCAR_LSI},${RCAR_V3M})
+    include drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk
+else
+    include drivers/staging/renesas/rcar/ddr/ddr_b/ddr_b.mk
+    BL2_SOURCES += drivers/staging/renesas/rcar/ddr/dram_sub_func.c
+endif
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_a/boot_init_dram_regdef.h b/drivers/staging/renesas/rcar/ddr/ddr_a/boot_init_dram_regdef.h
new file mode 100644
index 0000000..397bde0
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_a/boot_init_dram_regdef.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOOT_INIT_DRAM_REGDEF_H_
+#define BOOT_INIT_DRAM_REGDEF_H_
+
+/* DBSC registers */
+#define DBSC_DBSYSCONF0		0xE6790000U
+#define DBSC_DBSYSCONF1		0xE6790004U
+#define DBSC_DBPHYCONF0		0xE6790010U
+#define DBSC_DBKIND		0xE6790020U
+#define DBSC_DBMEMCONF00	0xE6790030U
+#define DBSC_DBMEMCONF01	0xE6790034U
+#define DBSC_DBMEMCONF02	0xE6790038U
+#define DBSC_DBMEMCONF03	0xE679003CU
+#define DBSC_DBMEMCONF10	0xE6790040U
+#define DBSC_DBMEMCONF11	0xE6790044U
+#define DBSC_DBMEMCONF12	0xE6790048U
+#define DBSC_DBMEMCONF13	0xE679004CU
+#define DBSC_DBMEMCONF20	0xE6790050U
+#define DBSC_DBMEMCONF21	0xE6790054U
+#define DBSC_DBMEMCONF22	0xE6790058U
+#define DBSC_DBMEMCONF23	0xE679005CU
+#define DBSC_DBMEMCONF30	0xE6790060U
+#define DBSC_DBMEMCONF31	0xE6790064U
+#define DBSC_DBMEMCONF32	0xE6790068U
+#define DBSC_DBMEMCONF33	0xE679006CU
+#define DBSC_DBSYSCNT0		0xE6790100U
+#define DBSC_DBSVCR1		0xE6790104U
+#define DBSC_DBSTATE0		0xE6790108U
+#define DBSC_DBSTATE1		0xE679010CU
+#define DBSC_DBINTEN		0xE6790180U
+#define DBSC_DBINTSTAT0		0xE6790184U
+#define DBSC_DBACEN		0xE6790200U
+#define DBSC_DBRFEN		0xE6790204U
+#define DBSC_DBCMD		0xE6790208U
+#define DBSC_DBWAIT		0xE6790210U
+#define DBSC_DBSYSCTRL0		0xE6790280U
+#define DBSC_DBTR0		0xE6790300U
+#define DBSC_DBTR1		0xE6790304U
+#define DBSC_DBTR2		0xE6790308U
+#define DBSC_DBTR3		0xE679030CU
+#define DBSC_DBTR4		0xE6790310U
+#define DBSC_DBTR5		0xE6790314U
+#define DBSC_DBTR6		0xE6790318U
+#define DBSC_DBTR7		0xE679031CU
+#define DBSC_DBTR8		0xE6790320U
+#define DBSC_DBTR9		0xE6790324U
+#define DBSC_DBTR10		0xE6790328U
+#define DBSC_DBTR11		0xE679032CU
+#define DBSC_DBTR12		0xE6790330U
+#define DBSC_DBTR13		0xE6790334U
+#define DBSC_DBTR14		0xE6790338U
+#define DBSC_DBTR15		0xE679033CU
+#define DBSC_DBTR16		0xE6790340U
+#define DBSC_DBTR17		0xE6790344U
+#define DBSC_DBTR18		0xE6790348U
+#define DBSC_DBTR19		0xE679034CU
+#define DBSC_DBTR20		0xE6790350U
+#define DBSC_DBTR21		0xE6790354U
+#define DBSC_DBTR22		0xE6790358U
+#define DBSC_DBTR23		0xE679035CU
+#define DBSC_DBTR24		0xE6790360U
+#define DBSC_DBTR25		0xE6790364U
+#define DBSC_DBBL		0xE6790400U
+#define DBSC_DBRFCNF1		0xE6790414U
+#define DBSC_DBRFCNF2		0xE6790418U
+#define DBSC_DBTSPCNF		0xE6790420U
+#define DBSC_DBCALCNF		0xE6790424U
+#define DBSC_DBRNK2		0xE6790438U
+#define DBSC_DBRNK3		0xE679043CU
+#define DBSC_DBRNK4		0xE6790440U
+#define DBSC_DBRNK5		0xE6790444U
+#define DBSC_DBPDNCNF		0xE6790450U
+#define DBSC_DBODT0		0xE6790460U
+#define DBSC_DBODT1		0xE6790464U
+#define DBSC_DBODT2		0xE6790468U
+#define DBSC_DBODT3		0xE679046CU
+#define DBSC_DBODT4		0xE6790470U
+#define DBSC_DBODT5		0xE6790474U
+#define DBSC_DBODT6		0xE6790478U
+#define DBSC_DBODT7		0xE679047CU
+#define DBSC_DBADJ0		0xE6790500U
+#define DBSC_DBDBICNT		0xE6790518U
+#define DBSC_DBDFIPMSTRCNF	0xE6790520U
+#define DBSC_DBDFIPMSTRSTAT	0xE6790524U
+#define DBSC_DBDFILPCNF		0xE6790528U
+#define DBSC_DBDFICUPDCNF	0xE679052CU
+#define DBSC_DBDFISTAT0		0xE6790600U
+#define DBSC_DBDFICNT0		0xE6790604U
+#define DBSC_DBPDCNT00		0xE6790610U
+#define DBSC_DBPDCNT01		0xE6790614U
+#define DBSC_DBPDCNT02		0xE6790618U
+#define DBSC_DBPDCNT03		0xE679061CU
+#define DBSC_DBPDLK0		0xE6790620U
+#define DBSC_DBPDRGA0		0xE6790624U
+#define DBSC_DBPDRGD0		0xE6790628U
+#define DBSC_DBPDSTAT00		0xE6790630U
+#define DBSC_DBDFISTAT1		0xE6790640U
+#define DBSC_DBDFICNT1		0xE6790644U
+#define DBSC_DBPDCNT10		0xE6790650U
+#define DBSC_DBPDCNT11		0xE6790654U
+#define DBSC_DBPDCNT12		0xE6790658U
+#define DBSC_DBPDCNT13		0xE679065CU
+#define DBSC_DBPDLK1		0xE6790660U
+#define DBSC_DBPDRGA1		0xE6790664U
+#define DBSC_DBPDRGD1		0xE6790668U
+#define DBSC_DBPDSTAT10		0xE6790670U
+#define DBSC_DBDFISTAT2		0xE6790680U
+#define DBSC_DBDFICNT2		0xE6790684U
+#define DBSC_DBPDCNT20		0xE6790690U
+#define DBSC_DBPDCNT21		0xE6790694U
+#define DBSC_DBPDCNT22		0xE6790698U
+#define DBSC_DBPDCNT23		0xE679069CU
+#define DBSC_DBPDLK2		0xE67906A0U
+#define DBSC_DBPDRGA2		0xE67906A4U
+#define DBSC_DBPDRGD2		0xE67906A8U
+#define DBSC_DBPDSTAT20		0xE67906B0U
+#define DBSC_DBDFISTAT3		0xE67906C0U
+#define DBSC_DBDFICNT3		0xE67906C4U
+#define DBSC_DBPDCNT30		0xE67906D0U
+#define DBSC_DBPDCNT31		0xE67906D4U
+#define DBSC_DBPDCNT32		0xE67906D8U
+#define DBSC_DBPDCNT33		0xE67906DCU
+#define DBSC_DBPDLK3		0xE67906E0U
+#define DBSC_DBPDRGA3		0xE67906E4U
+#define DBSC_DBPDRGD3		0xE67906E8U
+#define DBSC_DBPDSTAT30		0xE67906F0U
+#define DBSC_DBBUS0CNF0		0xE6790800U
+#define DBSC_DBBUS0CNF1		0xE6790804U
+#define DBSC_DBCAM0CNF1		0xE6790904U
+#define DBSC_DBCAM0CNF2		0xE6790908U
+#define DBSC_DBCAM0CNF3		0xE679090CU
+#define DBSC_DBCAM0CTRL0	0xE6790940U
+#define DBSC_DBCAM0STAT0	0xE6790980U
+#define DBSC_DBCAM1STAT0	0xE6790990U
+#define DBSC_DBBCAMSWAP		0xE67909F0U
+#define DBSC_DBBCAMDIS		0xE67909FCU
+#define DBSC_DBSCHCNT0		0xE6791000U
+#define DBSC_DBSCHCNT1		0xE6791004U
+#define DBSC_DBSCHSZ0		0xE6791010U
+#define DBSC_DBSCHRW0		0xE6791020U
+#define DBSC_DBSCHRW1		0xE6791024U
+#define DBSC_DBSCHQOS00		0xE6791030U
+#define DBSC_DBSCHQOS01		0xE6791034U
+#define DBSC_DBSCHQOS02		0xE6791038U
+#define DBSC_DBSCHQOS03		0xE679103CU
+#define DBSC_DBSCHQOS10		0xE6791040U
+#define DBSC_DBSCHQOS11		0xE6791044U
+#define DBSC_DBSCHQOS12		0xE6791048U
+#define DBSC_DBSCHQOS13		0xE679104CU
+#define DBSC_DBSCHQOS20		0xE6791050U
+#define DBSC_DBSCHQOS21		0xE6791054U
+#define DBSC_DBSCHQOS22		0xE6791058U
+#define DBSC_DBSCHQOS23		0xE679105CU
+#define DBSC_DBSCHQOS30		0xE6791060U
+#define DBSC_DBSCHQOS31		0xE6791064U
+#define DBSC_DBSCHQOS32		0xE6791068U
+#define DBSC_DBSCHQOS33		0xE679106CU
+#define DBSC_DBSCHQOS40		0xE6791070U
+#define DBSC_DBSCHQOS41		0xE6791074U
+#define DBSC_DBSCHQOS42		0xE6791078U
+#define DBSC_DBSCHQOS43		0xE679107CU
+#define DBSC_DBSCHQOS50		0xE6791080U
+#define DBSC_DBSCHQOS51		0xE6791084U
+#define DBSC_DBSCHQOS52		0xE6791088U
+#define DBSC_DBSCHQOS53		0xE679108CU
+#define DBSC_DBSCHQOS60		0xE6791090U
+#define DBSC_DBSCHQOS61		0xE6791094U
+#define DBSC_DBSCHQOS62		0xE6791098U
+#define DBSC_DBSCHQOS63		0xE679109CU
+#define DBSC_DBSCHQOS70		0xE67910A0U
+#define DBSC_DBSCHQOS71		0xE67910A4U
+#define DBSC_DBSCHQOS72		0xE67910A8U
+#define DBSC_DBSCHQOS73		0xE67910ACU
+#define DBSC_DBSCHQOS80		0xE67910B0U
+#define DBSC_DBSCHQOS81		0xE67910B4U
+#define DBSC_DBSCHQOS82		0xE67910B8U
+#define DBSC_DBSCHQOS83		0xE67910BCU
+#define DBSC_DBSCHQOS90		0xE67910C0U
+#define DBSC_DBSCHQOS91		0xE67910C4U
+#define DBSC_DBSCHQOS92		0xE67910C8U
+#define DBSC_DBSCHQOS93		0xE67910CCU
+#define DBSC_DBSCHQOS100	0xE67910D0U
+#define DBSC_DBSCHQOS101	0xE67910D4U
+#define DBSC_DBSCHQOS102	0xE67910D8U
+#define DBSC_DBSCHQOS103	0xE67910DCU
+#define DBSC_DBSCHQOS110	0xE67910E0U
+#define DBSC_DBSCHQOS111	0xE67910E4U
+#define DBSC_DBSCHQOS112	0xE67910E8U
+#define DBSC_DBSCHQOS113	0xE67910ECU
+#define DBSC_DBSCHQOS120	0xE67910F0U
+#define DBSC_DBSCHQOS121	0xE67910F4U
+#define DBSC_DBSCHQOS122	0xE67910F8U
+#define DBSC_DBSCHQOS123	0xE67910FCU
+#define DBSC_DBSCHQOS130	0xE6791100U
+#define DBSC_DBSCHQOS131	0xE6791104U
+#define DBSC_DBSCHQOS132	0xE6791108U
+#define DBSC_DBSCHQOS133	0xE679110CU
+#define DBSC_DBSCHQOS140	0xE6791110U
+#define DBSC_DBSCHQOS141	0xE6791114U
+#define DBSC_DBSCHQOS142	0xE6791118U
+#define DBSC_DBSCHQOS143	0xE679111CU
+#define DBSC_DBSCHQOS150	0xE6791120U
+#define DBSC_DBSCHQOS151	0xE6791124U
+#define DBSC_DBSCHQOS152	0xE6791128U
+#define DBSC_DBSCHQOS153	0xE679112CU
+#define DBSC_SCFCTST0		0xE6791700U
+#define DBSC_SCFCTST1		0xE6791708U
+#define DBSC_SCFCTST2		0xE679170CU
+#define DBSC_DBMRRDR0		0xE6791800U
+#define DBSC_DBMRRDR1		0xE6791804U
+#define DBSC_DBMRRDR2		0xE6791808U
+#define DBSC_DBMRRDR3		0xE679180CU
+#define DBSC_DBMRRDR4		0xE6791810U
+#define DBSC_DBMRRDR5		0xE6791814U
+#define DBSC_DBMRRDR6		0xE6791818U
+#define DBSC_DBMRRDR7		0xE679181CU
+#define DBSC_DBDTMP0		0xE6791820U
+#define DBSC_DBDTMP1		0xE6791824U
+#define DBSC_DBDTMP2		0xE6791828U
+#define DBSC_DBDTMP3		0xE679182CU
+#define DBSC_DBDTMP4		0xE6791830U
+#define DBSC_DBDTMP5		0xE6791834U
+#define DBSC_DBDTMP6		0xE6791838U
+#define DBSC_DBDTMP7		0xE679183CU
+#define DBSC_DBDQSOSC00		0xE6791840U
+#define DBSC_DBDQSOSC01		0xE6791844U
+#define DBSC_DBDQSOSC10		0xE6791848U
+#define DBSC_DBDQSOSC11		0xE679184CU
+#define DBSC_DBDQSOSC20		0xE6791850U
+#define DBSC_DBDQSOSC21		0xE6791854U
+#define DBSC_DBDQSOSC30		0xE6791858U
+#define DBSC_DBDQSOSC31		0xE679185CU
+#define DBSC_DBDQSOSC40		0xE6791860U
+#define DBSC_DBDQSOSC41		0xE6791864U
+#define DBSC_DBDQSOSC50		0xE6791868U
+#define DBSC_DBDQSOSC51		0xE679186CU
+#define DBSC_DBDQSOSC60		0xE6791870U
+#define DBSC_DBDQSOSC61		0xE6791874U
+#define DBSC_DBDQSOSC70		0xE6791878U
+#define DBSC_DBDQSOSC71		0xE679187CU
+#define DBSC_DBOSCTHH00		0xE6791880U
+#define DBSC_DBOSCTHH01		0xE6791884U
+#define DBSC_DBOSCTHH10		0xE6791888U
+#define DBSC_DBOSCTHH11		0xE679188CU
+#define DBSC_DBOSCTHH20		0xE6791890U
+#define DBSC_DBOSCTHH21		0xE6791894U
+#define DBSC_DBOSCTHH30		0xE6791898U
+#define DBSC_DBOSCTHH31		0xE679189CU
+#define DBSC_DBOSCTHH40		0xE67918A0U
+#define DBSC_DBOSCTHH41		0xE67918A4U
+#define DBSC_DBOSCTHH50		0xE67918A8U
+#define DBSC_DBOSCTHH51		0xE67918ACU
+#define DBSC_DBOSCTHH60		0xE67918B0U
+#define DBSC_DBOSCTHH61		0xE67918B4U
+#define DBSC_DBOSCTHH70		0xE67918B8U
+#define DBSC_DBOSCTHH71		0xE67918BCU
+#define DBSC_DBOSCTHL00		0xE67918C0U
+#define DBSC_DBOSCTHL01		0xE67918C4U
+#define DBSC_DBOSCTHL10		0xE67918C8U
+#define DBSC_DBOSCTHL11		0xE67918CCU
+#define DBSC_DBOSCTHL20		0xE67918D0U
+#define DBSC_DBOSCTHL21		0xE67918D4U
+#define DBSC_DBOSCTHL30		0xE67918D8U
+#define DBSC_DBOSCTHL31		0xE67918DCU
+#define DBSC_DBOSCTHL40		0xE67918E0U
+#define DBSC_DBOSCTHL41		0xE67918E4U
+#define DBSC_DBOSCTHL50		0xE67918E8U
+#define DBSC_DBOSCTHL51		0xE67918ECU
+#define DBSC_DBOSCTHL60		0xE67918F0U
+#define DBSC_DBOSCTHL61		0xE67918F4U
+#define DBSC_DBOSCTHL70		0xE67918F8U
+#define DBSC_DBOSCTHL71		0xE67918FCU
+#define DBSC_DBMEMSWAPCONF0	0xE6792000U
+
+/* CPG registers */
+#define CPG_SRCR4		0xE61500BCU
+#define CPG_PLLECR		0xE61500D0U
+#define CPG_CPGWPR		0xE6150900U
+#define CPG_CPGWPCR		0xE6150904U
+#define CPG_SRSTCLR4		0xE6150950U
+
+/* MODE Monitor registers */
+#define RST_MODEMR		0xE6160060U
+
+#endif /* BOOT_INIT_DRAM_REGDEF_H_*/
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk
new file mode 100644
index 0000000..aee27a5
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${RCAR_LSI},${RCAR_E3})
+BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_e3.c
+else ifeq (${RCAR_LSI},${RCAR_D3})
+BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_d3.c
+else
+BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_v3m.c
+endif
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_d3.c b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_d3.c
new file mode 100644
index 0000000..d03b1b9
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_d3.c
@@ -0,0 +1,699 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <lib/mmio.h>
+#include <common/debug.h>
+
+#include "boot_init_dram_regdef.h"
+
+#define RCAR_DDR_VERSION	"rev.0.01"
+
+#if RCAR_LSI != RCAR_D3
+#error "Don't have DDR initialize routine."
+#endif
+
+static void init_ddr_d3_1866(void)
+{
+	uint32_t i, r2, r3, r5, r6, r7, r12;
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBKIND, 0x00000007);
+	mmio_write_32(DBSC_DBMEMCONF00, 0x0f030a01);
+	mmio_write_32(DBSC_DBPHYCONF0, 0x00000001);
+	mmio_write_32(DBSC_DBTR0, 0x0000000D);
+	mmio_write_32(DBSC_DBTR1, 0x00000009);
+	mmio_write_32(DBSC_DBTR2, 0x00000000);
+	mmio_write_32(DBSC_DBTR3, 0x0000000D);
+	mmio_write_32(DBSC_DBTR4, 0x000D000D);
+	mmio_write_32(DBSC_DBTR5, 0x0000002D);
+	mmio_write_32(DBSC_DBTR6, 0x00000020);
+	mmio_write_32(DBSC_DBTR7, 0x00060006);
+	mmio_write_32(DBSC_DBTR8, 0x00000021);
+	mmio_write_32(DBSC_DBTR9, 0x00000007);
+	mmio_write_32(DBSC_DBTR10, 0x0000000E);
+	mmio_write_32(DBSC_DBTR11, 0x0000000C);
+	mmio_write_32(DBSC_DBTR12, 0x00140014);
+	mmio_write_32(DBSC_DBTR13, 0x000000F2);
+	mmio_write_32(DBSC_DBTR14, 0x00170006);
+	mmio_write_32(DBSC_DBTR15, 0x00060005);
+	mmio_write_32(DBSC_DBTR16, 0x09210507);
+	mmio_write_32(DBSC_DBTR17, 0x040E0000);
+	mmio_write_32(DBSC_DBTR18, 0x00000200);
+	mmio_write_32(DBSC_DBTR19, 0x012B004B);
+	mmio_write_32(DBSC_DBTR20, 0x020000FB);
+	mmio_write_32(DBSC_DBTR21, 0x00040004);
+	mmio_write_32(DBSC_DBBL, 0x00000000);
+	mmio_write_32(DBSC_DBODT0, 0x00000001);
+	mmio_write_32(DBSC_DBADJ0, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCONF1, 0x00000002);
+	mmio_write_32(DBSC_DBDFICNT0, 0x00000010);
+	mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW1, 0x00000046);
+	mmio_write_32(DBSC_SCFCTST0, 0x0D020D04);
+	mmio_write_32(DBSC_SCFCTST1, 0x0306040C);
+
+	mmio_write_32(DBSC_DBPDLK0, 0x0000A55A);
+	mmio_write_32(DBSC_DBCMD, 0x01000001);
+	mmio_write_32(DBSC_DBCMD, 0x08000000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x80010000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000008);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000B8000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058A04);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000091);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000095);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BBAD);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000099);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058A00);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024641E);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010073);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0C058A00);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058A00);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0780C700);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(30)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000004);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0A206F89);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000022);
+	mmio_write_32(DBSC_DBPDRGD0, 0x1000040B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000023);
+	mmio_write_32(DBSC_DBPDRGD0, 0x35A00D77);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000024);
+	mmio_write_32(DBSC_DBPDRGD0, 0x2A8A2C28);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000025);
+	mmio_write_32(DBSC_DBPDRGD0, 0x30005E00);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000026);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0014CB49);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000027);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000F14);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000028);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000046);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000029);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003047);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000020);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00181884);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000001A);
+	mmio_write_32(DBSC_DBPDRGD0, 0x33C03C10);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000000E);
+	r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0x0000FF00) >> 0x9;
+	r3 = (r2 << 16) + (r2 << 8) + r2;
+	r6 = (r2 << 24) + (r2 << 16) + (r2 << 8) + r2;
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000011);
+	mmio_write_32(DBSC_DBPDRGD0, r3);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000012);
+	mmio_write_32(DBSC_DBPDRGD0, r3);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000016);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000017);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000018);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000019);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010181);
+	mmio_write_32(DBSC_DBCMD, 0x08000001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010601);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 2; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+
+		if (r6 > 0) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r6);
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r7);
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     ((r6 + (r5 << 1)) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00C0);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010801);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00D8);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0001F001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000AF);
+	r2 = mmio_read_32(DBSC_DBPDRGD0);
+	mmio_write_32(DBSC_DBPDRGD0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000CF);
+	r2 = mmio_read_32(DBSC_DBPDRGD0);
+	mmio_write_32(DBSC_DBPDRGD0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003087);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010401);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 2; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = ((mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8);
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+		r12 = (r5 >> 0x2);
+
+		if (r12 < r6) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r6 - r12) & 0xFF));
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | (r7 & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     ((r6 + r5 +
+						      (r5 >> 1) + r12) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00015001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0380C700);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (mmio_read_32(DBSC_DBPDRGD0) & BIT(30))
+		;
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024643E);
+
+	mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
+	mmio_write_32(DBSC_DBCALCNF, 0x0100401B);
+	mmio_write_32(DBSC_DBRFCNF1, 0x00080E23);
+	mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
+	mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
+	mmio_write_32(DBSC_DBRFEN, 0x00000001);
+	mmio_write_32(DBSC_DBACEN, 0x00000001);
+	mmio_write_32(DBSC_DBPDLK0, 0x00000000);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+
+#ifdef ddr_qos_init_setting // only for non qos_init
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218);
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4);
+	mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW0, 0x22421111);
+	mmio_write_32(DBSC_SCFCTST2, 0x012F1123);
+	mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00);
+	mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00);
+	mmio_write_32(DBSC_DBSCHQOS02, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS03, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS40, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0);
+	mmio_write_32(DBSC_DBSCHQOS42, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS43, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS90, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS91, 0x000002F0);
+	mmio_write_32(DBSC_DBSCHQOS92, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS93, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS130, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0);
+	mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0);
+	mmio_write_32(DBSC_DBSCHQOS133, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0);
+	mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0);
+	mmio_write_32(DBSC_DBSCHQOS142, 0x00000080);
+	mmio_write_32(DBSC_DBSCHQOS143, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS150, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS151, 0x00000030);
+	mmio_write_32(DBSC_DBSCHQOS152, 0x00000020);
+	mmio_write_32(DBSC_DBSCHQOS153, 0x00000010);
+	mmio_write_32(0xE67F0018, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+#endif
+}
+
+static void init_ddr_d3_1600(void)
+{
+	uint32_t i, r2, r3, r5, r6, r7, r12;
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBKIND, 0x00000007);
+	mmio_write_32(DBSC_DBMEMCONF00, 0x0f030a01);
+	mmio_write_32(DBSC_DBPHYCONF0, 0x00000001);
+	mmio_write_32(DBSC_DBTR0, 0x0000000B);
+	mmio_write_32(DBSC_DBTR1, 0x00000008);
+	mmio_write_32(DBSC_DBTR2, 0x00000000);
+	mmio_write_32(DBSC_DBTR3, 0x0000000B);
+	mmio_write_32(DBSC_DBTR4, 0x000B000B);
+	mmio_write_32(DBSC_DBTR5, 0x00000027);
+	mmio_write_32(DBSC_DBTR6, 0x0000001C);
+	mmio_write_32(DBSC_DBTR7, 0x00060006);
+	mmio_write_32(DBSC_DBTR8, 0x00000020);
+	mmio_write_32(DBSC_DBTR9, 0x00000006);
+	mmio_write_32(DBSC_DBTR10, 0x0000000C);
+	mmio_write_32(DBSC_DBTR11, 0x0000000A);
+	mmio_write_32(DBSC_DBTR12, 0x00120012);
+	mmio_write_32(DBSC_DBTR13, 0x000000D0);
+	mmio_write_32(DBSC_DBTR14, 0x00140005);
+	mmio_write_32(DBSC_DBTR15, 0x00050004);
+	mmio_write_32(DBSC_DBTR16, 0x071F0305);
+	mmio_write_32(DBSC_DBTR17, 0x040C0000);
+	mmio_write_32(DBSC_DBTR18, 0x00000200);
+	mmio_write_32(DBSC_DBTR19, 0x01000040);
+	mmio_write_32(DBSC_DBTR20, 0x020000D8);
+	mmio_write_32(DBSC_DBTR21, 0x00040004);
+	mmio_write_32(DBSC_DBBL, 0x00000000);
+	mmio_write_32(DBSC_DBODT0, 0x00000001);
+	mmio_write_32(DBSC_DBADJ0, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCONF1, 0x00000002);
+	mmio_write_32(DBSC_DBDFICNT0, 0x00000010);
+	mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW1, 0x00000046);
+	mmio_write_32(DBSC_SCFCTST0, 0x0D020C04);
+	mmio_write_32(DBSC_SCFCTST1, 0x0305040C);
+
+	mmio_write_32(DBSC_DBPDLK0, 0x0000A55A);
+	mmio_write_32(DBSC_DBCMD, 0x01000001);
+	mmio_write_32(DBSC_DBCMD, 0x08000000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x80010000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000008);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000B8000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058904);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000091);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000095);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BBAD);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000099);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024641E);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010073);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0C058900);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0780C700);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(30)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000004);
+	mmio_write_32(DBSC_DBPDRGD0, 0x08C05FF0);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000022);
+	mmio_write_32(DBSC_DBPDRGD0, 0x1000040B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000023);
+	mmio_write_32(DBSC_DBPDRGD0, 0x2D9C0B66);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000024);
+	mmio_write_32(DBSC_DBPDRGD0, 0x2A88C400);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000025);
+	mmio_write_32(DBSC_DBPDRGD0, 0x30005200);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000026);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0014A9C9);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000027);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000D70);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000028);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000046);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000029);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000098);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003047);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000020);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00181884);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000001A);
+	mmio_write_32(DBSC_DBPDRGD0, 0x33C03C10);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000000E);
+	r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0x0000FF00) >> 0x9;
+	r3 = (r2 << 16) + (r2 << 8) + r2;
+	r6 = (r2 << 24) + (r2 << 16) + (r2 << 8) + r2;
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000011);
+	mmio_write_32(DBSC_DBPDRGD0, r3);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000012);
+	mmio_write_32(DBSC_DBPDRGD0, r3);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000016);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000017);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000018);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000019);
+	mmio_write_32(DBSC_DBPDRGD0, r6);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010181);
+	mmio_write_32(DBSC_DBCMD, 0x08000001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010601);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 2; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+		if (r6 > 0) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r6);
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r7);
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     ((r6 + (r5 << 1)) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00C0);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010801);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00D8);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0001F001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000AF);
+	r2 = mmio_read_32(DBSC_DBPDRGD0);
+	mmio_write_32(DBSC_DBPDRGD0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000CF);
+	r2 = mmio_read_32(DBSC_DBPDRGD0);
+	mmio_write_32(DBSC_DBPDRGD0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00));
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003087);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010401);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 2; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+		r12 = (r5 >> 0x2);
+
+		if (r12 < r6) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r6 - r12) & 0xFF));
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | (r7 & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     ((r6 + r5 +
+						      (r5 >> 1) + r12) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00015001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0380C700);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (mmio_read_32(DBSC_DBPDRGD0) & BIT(30))
+		;
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024643E);
+
+	mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
+	mmio_write_32(DBSC_DBCALCNF, 0x0100401B);
+	mmio_write_32(DBSC_DBRFCNF1, 0x00080C30);
+	mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
+	mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
+	mmio_write_32(DBSC_DBRFEN, 0x00000001);
+	mmio_write_32(DBSC_DBACEN, 0x00000001);
+	mmio_write_32(DBSC_DBPDLK0, 0x00000000);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+
+#ifdef ddr_qos_init_setting // only for non qos_init
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218);
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4);
+	mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW0, 0x22421111);
+	mmio_write_32(DBSC_SCFCTST2, 0x012F1123);
+	mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00);
+	mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00);
+	mmio_write_32(DBSC_DBSCHQOS02, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS03, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS40, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0);
+	mmio_write_32(DBSC_DBSCHQOS42, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS43, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS90, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS91, 0x000002F0);
+	mmio_write_32(DBSC_DBSCHQOS92, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS93, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS130, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0);
+	mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0);
+	mmio_write_32(DBSC_DBSCHQOS133, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0);
+	mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0);
+	mmio_write_32(DBSC_DBSCHQOS142, 0x00000080);
+	mmio_write_32(DBSC_DBSCHQOS143, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS150, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS151, 0x00000030);
+	mmio_write_32(DBSC_DBSCHQOS152, 0x00000020);
+	mmio_write_32(DBSC_DBSCHQOS153, 0x00000010);
+	mmio_write_32(0xE67F0018, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+#endif
+}
+
+#define PRR			0xFFF00044U
+#define PRR_PRODUCT_MASK	0x00007F00U
+#define PRR_PRODUCT_D3		0x00005800U
+
+#define	MODEMR_MD19		BIT(19)
+
+int32_t rcar_dram_init(void)
+{
+	uint32_t reg;
+	uint32_t ddr_mbps;
+
+	reg = mmio_read_32(PRR);
+	if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_D3) {
+		ERROR("LSI Product ID (PRR=0x%x) DDR initialize not supported.\n",
+		      reg);
+		panic();
+	}
+
+	reg = mmio_read_32(RST_MODEMR);
+	if (reg & MODEMR_MD19) {
+		init_ddr_d3_1866();
+		ddr_mbps = 1866;
+	} else {
+		init_ddr_d3_1600();
+		ddr_mbps = 1600;
+	}
+
+	NOTICE("BL2: DDR%d\n", ddr_mbps);
+
+	return 0;
+}
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_e3.c b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_e3.c
new file mode 100644
index 0000000..7aedc88
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_e3.c
@@ -0,0 +1,1711 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "boot_init_dram.h"
+#include "boot_init_dram_regdef.h"
+
+#include "../dram_sub_func.h"
+
+#define RCAR_E3_DDR_VERSION    "rev.0.12"
+
+/* Average periodic refresh interval[ns]. Support 3900,7800 */
+#ifdef ddr_qos_init_setting
+#define REFRESH_RATE	3900U
+#else
+#if RCAR_REF_INT == 1
+#define REFRESH_RATE	7800U
+#else
+#define REFRESH_RATE	3900U
+#endif
+#endif
+
+/*
+ *  Initialize ddr
+ */
+uint32_t init_ddr(void)
+{
+	uint32_t i, r2, r5, r6, r7, r12;
+	uint32_t ddr_md;
+	uint32_t regval, j;
+	uint32_t dqsgd_0c, bdlcount_0c, bdlcount_0c_div2, bdlcount_0c_div4;
+	uint32_t bdlcount_0c_div8, bdlcount_0c_div16;
+	uint32_t gatesl_0c, rdqsd_0c, rdqsnd_0c, rbd_0c[4];
+	uint32_t pdqsr_ctl, lcdl_ctl, lcdl_judge1, lcdl_judge2;
+	uint32_t pdr_ctl;
+	uint32_t byp_ctl;
+
+	if ((mmio_read_32(0xFFF00044) & 0x000000FF) == 0x00000000) {
+		pdqsr_ctl = 1;
+		lcdl_ctl = 1;
+		pdr_ctl = 1;
+		byp_ctl = 1;
+	} else {
+		pdqsr_ctl = 0;
+		lcdl_ctl = 0;
+		pdr_ctl = 0;
+		byp_ctl = 0;
+	}
+
+	/* Judge the DDR bit rate (ddr_md : 0 = 1584Mbps, 1 = 1856Mbps) */
+	ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & BIT(0);
+
+	/* 1584Mbps setting */
+	if (ddr_md == 0) {
+		mmio_write_32(CPG_CPGWPR, 0x5A5AFFFF);
+		mmio_write_32(CPG_CPGWPCR, 0xA5A50000);
+
+		mmio_write_32(CPG_SRCR4, 0x20000000);
+
+		mmio_write_32(0xE61500DC, 0xe2200000);	/* Change to 1584Mbps */
+		while (!(mmio_read_32(CPG_PLLECR) & BIT(11)))
+			;
+
+		mmio_write_32(CPG_SRSTCLR4, 0x20000000);
+
+		mmio_write_32(CPG_CPGWPCR, 0xA5A50001);
+	}
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBKIND, 0x00000007);
+
+#if RCAR_DRAM_DDR3L_MEMCONF == 0
+	mmio_write_32(DBSC_DBMEMCONF00, 0x0f030a02);	/* 1GB */
+#else
+	mmio_write_32(DBSC_DBMEMCONF00, 0x10030a02);	/* 2GB(default) */
+#endif
+
+#if RCAR_DRAM_DDR3L_MEMDUAL == 1
+	r2 = mmio_read_32(0xE6790614);
+	mmio_write_32(0xE6790614, r2 | 0x3); /* MCS1_N/MODT1 are activated. */
+#endif
+
+	mmio_write_32(DBSC_DBPHYCONF0, 0x1);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR0, 0xB);
+		mmio_write_32(DBSC_DBTR1, 0x8);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR0, 0xD);
+		mmio_write_32(DBSC_DBTR1, 0x9);
+	}
+
+	mmio_write_32(DBSC_DBTR2, 0x00000000);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR3, 0x0000000B);
+		mmio_write_32(DBSC_DBTR4, 0x000B000B);
+		mmio_write_32(DBSC_DBTR5, 0x00000027);
+		mmio_write_32(DBSC_DBTR6, 0x0000001C);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR3, 0x0000000D);
+		mmio_write_32(DBSC_DBTR4, 0x000D000D);
+		mmio_write_32(DBSC_DBTR5, 0x0000002D);
+		mmio_write_32(DBSC_DBTR6, 0x00000020);
+	}
+
+	mmio_write_32(DBSC_DBTR7, 0x00060006);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR8, 0x00000020);
+		mmio_write_32(DBSC_DBTR9, 0x00000006);
+		mmio_write_32(DBSC_DBTR10, 0x0000000C);
+		mmio_write_32(DBSC_DBTR11, 0x0000000A);
+		mmio_write_32(DBSC_DBTR12, 0x00120012);
+		mmio_write_32(DBSC_DBTR13, 0x000000CE);
+		mmio_write_32(DBSC_DBTR14, 0x00140005);
+		mmio_write_32(DBSC_DBTR15, 0x00050004);
+		mmio_write_32(DBSC_DBTR16, 0x071F0305);
+		mmio_write_32(DBSC_DBTR17, 0x040C0000);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR8, 0x00000021);
+		mmio_write_32(DBSC_DBTR9, 0x00000007);
+		mmio_write_32(DBSC_DBTR10, 0x0000000E);
+		mmio_write_32(DBSC_DBTR11, 0x0000000C);
+		mmio_write_32(DBSC_DBTR12, 0x00140014);
+		mmio_write_32(DBSC_DBTR13, 0x000000F2);
+		mmio_write_32(DBSC_DBTR14, 0x00170006);
+		mmio_write_32(DBSC_DBTR15, 0x00060005);
+		mmio_write_32(DBSC_DBTR16, 0x09210507);
+		mmio_write_32(DBSC_DBTR17, 0x040E0000);
+	}
+
+	mmio_write_32(DBSC_DBTR18, 0x00000200);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR19, 0x01000040);
+		mmio_write_32(DBSC_DBTR20, 0x020000D6);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR19, 0x0129004B);
+		mmio_write_32(DBSC_DBTR20, 0x020000FB);
+	}
+
+	mmio_write_32(DBSC_DBTR21, 0x00040004);
+	mmio_write_32(DBSC_DBBL, 0x00000000);
+	mmio_write_32(DBSC_DBODT0, 0x00000001);
+	mmio_write_32(DBSC_DBADJ0, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCONF1, 0x00000002);
+	mmio_write_32(DBSC_DBDFICNT0, 0x00000010);
+	mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW1, 0x00000046);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_SCFCTST0, 0x0D050B03);
+		mmio_write_32(DBSC_SCFCTST1, 0x0306030C);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_SCFCTST0, 0x0C050B03);
+		mmio_write_32(DBSC_SCFCTST1, 0x0305030C);
+	}
+
+	/*
+	 * Initial_Step0( INITBYP )
+	 */
+	mmio_write_32(DBSC_DBPDLK0, 0x0000A55A);
+	mmio_write_32(DBSC_DBCMD, 0x01840001);
+	mmio_write_32(DBSC_DBCMD, 0x08840000);
+	NOTICE("BL2: [COLD_BOOT]\n");
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x80010000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/*
+	 * Initial_Step1( ZCAL,PLLINIT,DCAL,PHYRST training )
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000008);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000B8000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058904);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058A04);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000091);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000095);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BBAD);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000099);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024641E);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010073);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/*
+	 * Initial_Step2( DRAMRST/DRAMINT training )
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0C058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0C058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	if (byp_ctl == 1)
+		mmio_write_32(DBSC_DBPDRGD0, 0x0780C720);
+	else
+		mmio_write_32(DBSC_DBPDRGD0, 0x0780C700);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(30)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000004);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, (REFRESH_RATE * 792 / 125) -
+					     400 + 0x08B00000);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, (REFRESH_RATE * 928 / 125) -
+					     400 + 0x0A300000);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000022);
+	mmio_write_32(DBSC_DBPDRGD0, 0x1000040B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000023);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x2D9C0B66);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x35A00D77);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000024);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x2A88B400);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x2A8A2C28);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000025);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x30005200);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x30005E00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000026);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0014A9C9);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0014CB49);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000027);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000D70);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000F14);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000028);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000046);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000029);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		if (REFRESH_RATE > 3900)	/* [7]SRT=0 */
+			mmio_write_32(DBSC_DBPDRGD0, 0x18);
+		else				/* [7]SRT=1 */
+			mmio_write_32(DBSC_DBPDRGD0, 0x98);
+	} else {		/* 1856Mbps */
+		if (REFRESH_RATE > 3900)	/* [7]SRT=0 */
+			mmio_write_32(DBSC_DBPDRGD0, 0x20);
+		else				/* [7]SRT=1 */
+			mmio_write_32(DBSC_DBPDRGD0, 0xA0);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003047);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000020);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00181884);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000001A);
+	mmio_write_32(DBSC_DBPDRGD0, 0x33C03C10);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000107);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000108);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000109);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010181);
+	mmio_write_32(DBSC_DBCMD, 0x08840001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/*
+	 * Initial_Step3( WL/QSG training )
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010601);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+
+		if (r6 > 0) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r6);
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r7);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     ((r6 + ((r5) << 1)) &
+						     0xFF));
+		}
+	}
+
+	/*
+	 * Initial_Step4( WLADJ training )
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00C0);
+
+	if (pdqsr_ctl == 0) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR always off */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010801);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/*
+	 * Initial_Step5(Read Data Bit Deskew)
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00D8);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00011001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR dynamic */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+	}
+
+	/*
+	 * Initial_Step6(Write Data Bit Deskew)
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00012001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/*
+	 * Initial_Step7(Read Data Eye Training)
+	 */
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	}
+
+	/* PDR always off */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00014001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR dynamic */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+	}
+
+	/*
+	 * Initial_Step8(Write Data Eye Training)
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00018001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/*
+	 * Initial_Step3_2( DQS Gate Training )
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003087);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010401);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = ((mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8);
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+		r12 = (r5 >> 0x2);
+		if (r12 < r6) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r6 - r12) & 0xFF));
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | (r7 & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r6 + r5 +
+						     (r5 >> 1) + r12) & 0xFF));
+		}
+	}
+
+	/*
+	 * Initial_Step5-2_7-2( Rd bit Rd eye )
+	 */
+	if (pdqsr_ctl == 0) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR always off */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00015001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (lcdl_ctl == 1) {
+		for (i = 0; i < 4; i++) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			dqsgd_0c = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+			bdlcount_0c = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >>
+					8;
+			bdlcount_0c_div2 = bdlcount_0c >> 1;
+			bdlcount_0c_div4 = bdlcount_0c >> 2;
+			bdlcount_0c_div8 = bdlcount_0c >> 3;
+			bdlcount_0c_div16 = bdlcount_0c >> 4;
+
+			if (ddr_md == 0) {	/* 1584Mbps */
+				lcdl_judge1 = bdlcount_0c_div2 +
+					      bdlcount_0c_div4 +
+					      bdlcount_0c_div8;
+				lcdl_judge2 = bdlcount_0c +
+					      bdlcount_0c_div4 +
+					      bdlcount_0c_div16;
+			} else {		/* 1856Mbps */
+				lcdl_judge1 = bdlcount_0c_div2 +
+					      bdlcount_0c_div4;
+				lcdl_judge2 = bdlcount_0c +
+					      bdlcount_0c_div4;
+			}
+
+			if (dqsgd_0c <= lcdl_judge1)
+				continue;
+
+			if (dqsgd_0c <= lcdl_judge2) {
+				mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xFFFFFF00;
+				mmio_write_32(DBSC_DBPDRGD0,
+					      (dqsgd_0c - bdlcount_0c_div8) |
+					      regval);
+			} else {
+				mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xFFFFFF00;
+				mmio_write_32(DBSC_DBPDRGD0, regval);
+				mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+				gatesl_0c = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+				mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xFFFFFFF8;
+				mmio_write_32(DBSC_DBPDRGD0, regval |
+							     (gatesl_0c + 1));
+				mmio_write_32(DBSC_DBPDRGA0, 0xAF + i * 0x20);
+				regval = (mmio_read_32(DBSC_DBPDRGD0));
+				rdqsd_0c = (regval & 0xFF00) >> 8;
+				rdqsnd_0c = (regval & 0xFF0000) >> 16;
+				mmio_write_32(DBSC_DBPDRGA0, 0xAF + i * 0x20);
+				mmio_write_32(DBSC_DBPDRGD0,
+					      (regval & 0xFF0000FF) |
+					      ((rdqsd_0c +
+						bdlcount_0c_div4) << 8) |
+					      ((rdqsnd_0c +
+						bdlcount_0c_div4) << 16));
+				mmio_write_32(DBSC_DBPDRGA0, 0xAA + i * 0x20);
+				regval = (mmio_read_32(DBSC_DBPDRGD0));
+				rbd_0c[0] = (regval) & 0x1f;
+				rbd_0c[1] = (regval >> 8) & 0x1f;
+				rbd_0c[2] = (regval >> 16) & 0x1f;
+				rbd_0c[3] = (regval >> 24) & 0x1f;
+				mmio_write_32(DBSC_DBPDRGA0, 0xAA + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+					0xE0E0E0E0;
+				for (j = 0; j < 4; j++) {
+					rbd_0c[j] = rbd_0c[j] +
+						    bdlcount_0c_div4;
+					if (rbd_0c[j] > 0x1F)
+						rbd_0c[j] = 0x1F;
+					regval = regval | (rbd_0c[j] << 8 * j);
+				}
+				mmio_write_32(DBSC_DBPDRGD0, regval);
+				mmio_write_32(DBSC_DBPDRGA0, 0xAB + i * 0x20);
+				regval = (mmio_read_32(DBSC_DBPDRGD0));
+				rbd_0c[0] = (regval) & 0x1f;
+				rbd_0c[1] = (regval >> 8) & 0x1f;
+				rbd_0c[2] = (regval >> 16) & 0x1f;
+				rbd_0c[3] = (regval >> 24) & 0x1f;
+				mmio_write_32(DBSC_DBPDRGA0, 0xAB + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+					0xE0E0E0E0;
+				for (j = 0; j < 4; j++) {
+					rbd_0c[j] = rbd_0c[j] +
+						    bdlcount_0c_div4;
+					if (rbd_0c[j] > 0x1F)
+						rbd_0c[j] = 0x1F;
+					regval = regval | (rbd_0c[j] << 8 * j);
+				}
+				mmio_write_32(DBSC_DBPDRGD0, regval);
+			}
+		}
+		mmio_write_32(DBSC_DBPDRGA0, 0x2);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7D81E37);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	if (byp_ctl == 1)
+		mmio_write_32(DBSC_DBPDRGD0, 0x0380C720);
+	else
+		mmio_write_32(DBSC_DBPDRGD0, 0x0380C700);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (mmio_read_32(DBSC_DBPDRGD0) & BIT(30))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024643E);
+
+	mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
+	mmio_write_32(DBSC_DBCALCNF, (64000000 / REFRESH_RATE) + 0x01000000);
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBRFCNF1,
+			      (REFRESH_RATE * 99 / 125) + 0x00080000);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBRFCNF1,
+			      (REFRESH_RATE * 116 / 125) + 0x00080000);
+	}
+
+	mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
+	mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
+	mmio_write_32(DBSC_DBRFEN, 0x00000001);
+	mmio_write_32(DBSC_DBACEN, 0x00000001);
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(0xE67F0018, 0x00000001);
+		regval = mmio_read_32(0x40000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGD0, regval);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR dynamic */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+	}
+
+	/*
+	 * Initial_Step9( Initial End )
+	 */
+	mmio_write_32(DBSC_DBPDLK0, 0x00000000);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+
+#ifdef ddr_qos_init_setting /* only for non qos_init */
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218);
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4);
+	mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW0, 0x22421111);
+	mmio_write_32(DBSC_SCFCTST2, 0x012F1123);
+	mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00);
+	mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00);
+	mmio_write_32(DBSC_DBSCHQOS02, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS03, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS40, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0);
+	mmio_write_32(DBSC_DBSCHQOS42, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS43, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS90, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS91, 0x000000F0);
+	mmio_write_32(DBSC_DBSCHQOS92, 0x000000A0);
+	mmio_write_32(DBSC_DBSCHQOS93, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS130, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0);
+	mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0);
+	mmio_write_32(DBSC_DBSCHQOS133, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0);
+	mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0);
+	mmio_write_32(DBSC_DBSCHQOS142, 0x00000080);
+	mmio_write_32(DBSC_DBSCHQOS143, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS150, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS151, 0x00000030);
+	mmio_write_32(DBSC_DBSCHQOS152, 0x00000020);
+	mmio_write_32(DBSC_DBSCHQOS153, 0x00000010);
+
+	if (pdqsr_ctl == 0)
+		mmio_write_32(0xE67F0018, 0x00000001);
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+#endif
+
+	return 1;
+}
+
+static uint32_t recovery_from_backup_mode(uint32_t ddr_backup)
+{
+	/*
+	 * recovery_Step0(DBSC Setting 1) / same "init_ddr"
+	 */
+	uint32_t r2, r5, r6, r7, r12, i;
+	uint32_t ddr_md;
+	uint32_t err;
+	uint32_t regval, j;
+	uint32_t dqsgd_0c, bdlcount_0c, bdlcount_0c_div2, bdlcount_0c_div4;
+	uint32_t bdlcount_0c_div8, bdlcount_0c_div16;
+	uint32_t gatesl_0c, rdqsd_0c, rdqsnd_0c, rbd_0c[4];
+	uint32_t pdqsr_ctl, lcdl_ctl, lcdl_judge1, lcdl_judge2;
+	uint32_t pdr_ctl;
+	uint32_t byp_ctl;
+
+	if ((mmio_read_32(0xFFF00044) & 0x000000FF) == 0x00000000) {
+		pdqsr_ctl = 1;
+		lcdl_ctl = 1;
+		pdr_ctl = 1;
+		byp_ctl = 1;
+	} else {
+		pdqsr_ctl = 0;
+		lcdl_ctl = 0;
+		pdr_ctl = 0;
+		byp_ctl = 0;
+	}
+
+	/* Judge the DDR bit rate (ddr_md : 0 = 1584Mbps, 1 = 1856Mbps) */
+	ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & BIT(0);
+
+	/* 1584Mbps setting */
+	if (ddr_md == 0) {
+		mmio_write_32(CPG_CPGWPR, 0x5A5AFFFF);
+		mmio_write_32(CPG_CPGWPCR, 0xA5A50000);
+
+		mmio_write_32(CPG_SRCR4, 0x20000000);
+
+		mmio_write_32(0xE61500DC, 0xe2200000);	/* Change to 1584Mbps */
+		while (!(mmio_read_32(CPG_PLLECR) & BIT(11)))
+			;
+
+		mmio_write_32(CPG_SRSTCLR4, 0x20000000);
+
+		mmio_write_32(CPG_CPGWPCR, 0xA5A50001);
+	}
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBKIND, 0x00000007);
+
+#if RCAR_DRAM_DDR3L_MEMCONF == 0
+	mmio_write_32(DBSC_DBMEMCONF00, 0x0f030a02);
+#else
+	mmio_write_32(DBSC_DBMEMCONF00, 0x10030a02);
+#endif
+
+#if RCAR_DRAM_DDR3L_MEMDUAL == 1
+	r2 = mmio_read_32(0xE6790614);
+	mmio_write_32(0xE6790614, r2 | 0x3); /* MCS1_N/MODT1 are activated. */
+#endif
+
+	mmio_write_32(DBSC_DBPHYCONF0, 0x00000001);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR0, 0x0000000B);
+		mmio_write_32(DBSC_DBTR1, 0x00000008);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR0, 0x0000000D);
+		mmio_write_32(DBSC_DBTR1, 0x00000009);
+	}
+
+	mmio_write_32(DBSC_DBTR2, 0x00000000);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR3, 0x0000000B);
+		mmio_write_32(DBSC_DBTR4, 0x000B000B);
+		mmio_write_32(DBSC_DBTR5, 0x00000027);
+		mmio_write_32(DBSC_DBTR6, 0x0000001C);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR3, 0x0000000D);
+		mmio_write_32(DBSC_DBTR4, 0x000D000D);
+		mmio_write_32(DBSC_DBTR5, 0x0000002D);
+		mmio_write_32(DBSC_DBTR6, 0x00000020);
+	}
+
+	mmio_write_32(DBSC_DBTR7, 0x00060006);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR8, 0x00000020);
+		mmio_write_32(DBSC_DBTR9, 0x00000006);
+		mmio_write_32(DBSC_DBTR10, 0x0000000C);
+		mmio_write_32(DBSC_DBTR11, 0x0000000A);
+		mmio_write_32(DBSC_DBTR12, 0x00120012);
+		mmio_write_32(DBSC_DBTR13, 0x000000CE);
+		mmio_write_32(DBSC_DBTR14, 0x00140005);
+		mmio_write_32(DBSC_DBTR15, 0x00050004);
+		mmio_write_32(DBSC_DBTR16, 0x071F0305);
+		mmio_write_32(DBSC_DBTR17, 0x040C0000);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR8, 0x00000021);
+		mmio_write_32(DBSC_DBTR9, 0x00000007);
+		mmio_write_32(DBSC_DBTR10, 0x0000000E);
+		mmio_write_32(DBSC_DBTR11, 0x0000000C);
+		mmio_write_32(DBSC_DBTR12, 0x00140014);
+		mmio_write_32(DBSC_DBTR13, 0x000000F2);
+		mmio_write_32(DBSC_DBTR14, 0x00170006);
+		mmio_write_32(DBSC_DBTR15, 0x00060005);
+		mmio_write_32(DBSC_DBTR16, 0x09210507);
+		mmio_write_32(DBSC_DBTR17, 0x040E0000);
+	}
+
+	mmio_write_32(DBSC_DBTR18, 0x00000200);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBTR19, 0x01000040);
+		mmio_write_32(DBSC_DBTR20, 0x020000D6);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBTR19, 0x0129004B);
+		mmio_write_32(DBSC_DBTR20, 0x020000FB);
+	}
+
+	mmio_write_32(DBSC_DBTR21, 0x00040004);
+	mmio_write_32(DBSC_DBBL, 0x00000000);
+	mmio_write_32(DBSC_DBODT0, 0x00000001);
+	mmio_write_32(DBSC_DBADJ0, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCONF1, 0x00000002);
+	mmio_write_32(DBSC_DBDFICNT0, 0x00000010);
+	mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW1, 0x00000046);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_SCFCTST0, 0x0D050B03);
+		mmio_write_32(DBSC_SCFCTST1, 0x0306030C);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_SCFCTST0, 0x0C050B03);
+		mmio_write_32(DBSC_SCFCTST1, 0x0305030C);
+	}
+
+	/*
+	 * recovery_Step1(PHY setting 1)
+	 */
+	mmio_write_32(DBSC_DBPDLK0, 0x0000A55A);
+	mmio_write_32(DBSC_DBCMD, 0x01840001);
+	mmio_write_32(DBSC_DBCMD, 0x0A840000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000008);	/* DDR_PLLCR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x000B8000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);	/* DDR_PGCR1 */
+	if (byp_ctl == 1)
+		mmio_write_32(DBSC_DBPDRGD0, 0x0780C720);
+	else
+		mmio_write_32(DBSC_DBPDRGD0, 0x0780C700);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000020);	/* DDR_DXCCR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x00181884);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000001A);	/* DDR_ACIOCR0 */
+	mmio_write_32(DBSC_DBPDRGD0, 0x33C03C10);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(30)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000004);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, (REFRESH_RATE * 792 / 125) -
+					     400 + 0x08B00000);
+	} else {		/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, (REFRESH_RATE * 928 / 125) -
+					     400 + 0x0A300000);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000022);
+	mmio_write_32(DBSC_DBPDRGD0, 0x1000040B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000023);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x2D9C0B66);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x35A00D77);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000024);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x2A88B400);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x2A8A2C28);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000025);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x30005200);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x30005E00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000026);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0014A9C9);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0014CB49);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000027);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000D70);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000F14);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000028);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000046);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000029);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		if (REFRESH_RATE > 3900)
+			mmio_write_32(DBSC_DBPDRGD0, 0x18);	/* [7]SRT=0 */
+		else
+			mmio_write_32(DBSC_DBPDRGD0, 0x98);	/* [7]SRT=1 */
+	} else {	/* 1856Mbps */
+		if (REFRESH_RATE > 3900)
+			mmio_write_32(DBSC_DBPDRGD0, 0x20);	/* [7]SRT=0 */
+		else
+			mmio_write_32(DBSC_DBPDRGD0, 0xA0);	/* [7]SRT=1 */
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003047);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000091);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000095);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BBAD);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000099);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);	/* DDR_DSGCR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024641E);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x40010000);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000092);	/* DDR_ZQ0DR */
+	mmio_write_32(DBSC_DBPDRGD0, 0xC2C59AB5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000096);	/* DDR_ZQ1DR */
+	mmio_write_32(DBSC_DBPDRGD0, 0xC4285FBF);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000009A);	/* DDR_ZQ2DR */
+	mmio_write_32(DBSC_DBPDRGD0, 0xC2C59AB5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);	/* DDR_ZQCR */
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0C058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0C058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);	/* DDR_ZQCR */
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x00050001);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	/* ddr backupmode end */
+	if (ddr_backup)
+		NOTICE("BL2: [WARM_BOOT]\n");
+	else
+		NOTICE("BL2: [COLD_BOOT]\n");
+
+	err = rcar_dram_update_boot_status(ddr_backup);
+	if (err) {
+		NOTICE("BL2: [BOOT_STATUS_UPDATE_ERROR]\n");
+		return INITDRAM_ERR_I;
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000092);	/* DDR_ZQ0DR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x02C59AB5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000096);	/* DDR_ZQ1DR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x04285FBF);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000009A);	/* DDR_ZQ2DR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x02C59AB5);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x08000000);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000003);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x80010000);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010073);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);	/* DDR_ZQCR */
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0C058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x0C058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);	/* DDR_ZQCR */
+
+	/* Select setting value in bps */
+	if (ddr_md == 0)	/* 1584Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	else			/* 1856Mbps */
+		mmio_write_32(DBSC_DBPDRGD0, 0x04058A00);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000000C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x18000040);
+
+	/*
+	 * recovery_Step2(PHY setting 2)
+	 */
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000107);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000108);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000109);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+
+	mmio_write_32(DBSC_DBCALCNF, (64000000 / REFRESH_RATE) + 0x01000000);
+	mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
+
+	/* Select setting value in bps */
+	if (ddr_md == 0) {	/* 1584Mbps */
+		mmio_write_32(DBSC_DBRFCNF1,
+			      (REFRESH_RATE * 99 / 125) + 0x00080000);
+	} else {			/* 1856Mbps */
+		mmio_write_32(DBSC_DBRFCNF1,
+			      (REFRESH_RATE * 116 / 125) + 0x00080000);
+	}
+
+	mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
+	mmio_write_32(DBSC_DBRFEN, 0x00000001);
+	mmio_write_32(DBSC_DBCMD, 0x0A840001);
+	while (mmio_read_32(DBSC_DBWAIT) & BIT(0))
+		;
+
+	mmio_write_32(DBSC_DBCMD, 0x00000000);
+
+	mmio_write_32(DBSC_DBCMD, 0x04840010);
+	while (mmio_read_32(DBSC_DBWAIT) & BIT(0))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);	/* DDR_PIR */
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010701);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);	/* DDR_PGSR0 */
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+
+		if (r6 > 0) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r6);
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r7);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0,
+				      r2 | ((r6 + (r5 << 1)) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00C0);
+
+	if (pdqsr_ctl == 0) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR always off */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010801);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00D8);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00011001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR dynamic */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00012001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	}
+
+	/* PDR always off */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00014001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR dynamic */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00018001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003087);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010401);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = ((mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 0x8);
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+		r12 = r5 >> 0x2;
+
+		if (r12 < r6) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r7 + 0x1) & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | ((r6 - r12) & 0xFF));
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | (r7 & 0x7));
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00;
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0,
+				      r2 |
+				      ((r6 + r5 + (r5 >> 1) + r12) & 0xFF));
+		}
+	}
+
+	if (pdqsr_ctl == 0) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR always off */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000008);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00015001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	if (lcdl_ctl == 1) {
+		for (i = 0; i < 4; i++) {
+			mmio_write_32(DBSC_DBPDRGA0, 0x000000B0 + i * 0x20);
+			dqsgd_0c = mmio_read_32(DBSC_DBPDRGD0) & 0x000000FF;
+			mmio_write_32(DBSC_DBPDRGA0, 0x000000B1 + i * 0x20);
+			bdlcount_0c = (mmio_read_32(DBSC_DBPDRGD0) &
+					0x0000FF00) >> 8;
+			bdlcount_0c_div2 = (bdlcount_0c >> 1);
+			bdlcount_0c_div4 = (bdlcount_0c >> 2);
+			bdlcount_0c_div8 = (bdlcount_0c >> 3);
+			bdlcount_0c_div16 = (bdlcount_0c >> 4);
+
+			if (ddr_md == 0) {	/* 1584Mbps */
+				lcdl_judge1 = bdlcount_0c_div2 +
+					      bdlcount_0c_div4 +
+					      bdlcount_0c_div8;
+				lcdl_judge2 = bdlcount_0c +
+					      bdlcount_0c_div4 +
+					      bdlcount_0c_div16;
+			} else {	/* 1856Mbps */
+				lcdl_judge1 = bdlcount_0c_div2 +
+					      bdlcount_0c_div4;
+				lcdl_judge2 = bdlcount_0c +
+					      bdlcount_0c_div4;
+			}
+
+			if (dqsgd_0c <= lcdl_judge1)
+				continue;
+
+			if (dqsgd_0c <= lcdl_judge2) {
+				mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xFFFFFF00;
+				mmio_write_32(DBSC_DBPDRGD0,
+					      (dqsgd_0c - bdlcount_0c_div8) |
+					      regval);
+			} else {
+				mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xFFFFFF00;
+				mmio_write_32(DBSC_DBPDRGD0, regval);
+				mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+				gatesl_0c = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+				mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xFFFFFFF8;
+				mmio_write_32(DBSC_DBPDRGD0,
+					      regval | (gatesl_0c + 1));
+				mmio_write_32(DBSC_DBPDRGA0, 0xAF + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0);
+				rdqsd_0c = (regval & 0xFF00) >> 8;
+				rdqsnd_0c = (regval & 0xFF0000) >> 16;
+				mmio_write_32(DBSC_DBPDRGA0, 0xAF + i * 0x20);
+				mmio_write_32(DBSC_DBPDRGD0,
+					      (regval & 0xFF0000FF) |
+					      ((rdqsd_0c +
+						bdlcount_0c_div4) << 8) |
+					      ((rdqsnd_0c +
+						bdlcount_0c_div4) << 16));
+				mmio_write_32(DBSC_DBPDRGA0, 0xAA + i * 0x20);
+				regval = (mmio_read_32(DBSC_DBPDRGD0));
+				rbd_0c[0] = (regval) & 0x1f;
+				rbd_0c[1] = (regval >>  8) & 0x1f;
+				rbd_0c[2] = (regval >> 16) & 0x1f;
+				rbd_0c[3] = (regval >> 24) & 0x1f;
+				mmio_write_32(DBSC_DBPDRGA0, 0xAA + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xE0E0E0E0;
+				for (j = 0; j < 4; j++) {
+					rbd_0c[j] = rbd_0c[j] +
+						    bdlcount_0c_div4;
+					if (rbd_0c[j] > 0x1F)
+						rbd_0c[j] = 0x1F;
+					regval = regval | (rbd_0c[j] << 8 * j);
+				}
+				mmio_write_32(DBSC_DBPDRGD0, regval);
+				mmio_write_32(DBSC_DBPDRGA0, 0xAB + i * 0x20);
+				regval = (mmio_read_32(DBSC_DBPDRGD0));
+				rbd_0c[0] = regval & 0x1f;
+				rbd_0c[1] = (regval >> 8) & 0x1f;
+				rbd_0c[2] = (regval >> 16) & 0x1f;
+				rbd_0c[3] = (regval >> 24) & 0x1f;
+				mmio_write_32(DBSC_DBPDRGA0, 0xAB + i * 0x20);
+				regval = mmio_read_32(DBSC_DBPDRGD0) &
+						0xE0E0E0E0;
+				for (j = 0; j < 4; j++) {
+					rbd_0c[j] = rbd_0c[j] +
+						    bdlcount_0c_div4;
+					if (rbd_0c[j] > 0x1F)
+						rbd_0c[j] = 0x1F;
+					regval = regval | (rbd_0c[j] << 8 * j);
+				}
+				mmio_write_32(DBSC_DBPDRGD0, regval);
+			}
+		}
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000002);
+		mmio_write_32(DBSC_DBPDRGD0, 0x07D81E37);
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	if (byp_ctl == 1)
+		mmio_write_32(DBSC_DBPDRGD0, 0x0380C720);
+	else
+		mmio_write_32(DBSC_DBPDRGD0, 0x0380C700);
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (mmio_read_32(DBSC_DBPDRGD0) & BIT(30))
+		;
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024643E);
+
+	/*
+	 * recovery_Step3(DBSC Setting 2)
+	 */
+	mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
+	mmio_write_32(DBSC_DBACEN, 0x00000001);
+
+	if (pdqsr_ctl == 1) {
+		mmio_write_32(0xE67F0018, 0x00000001);
+		regval = mmio_read_32(0x40000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGD0, regval);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+		mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	}
+
+	/* PDR dynamic */
+	if (pdr_ctl == 1) {
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000A3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000C3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x000000E3);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+		mmio_write_32(DBSC_DBPDRGA0, 0x00000103);
+		mmio_write_32(DBSC_DBPDRGD0, 0x00000000);
+	}
+
+	mmio_write_32(DBSC_DBPDLK0, 0x00000000);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+
+#ifdef ddr_qos_init_setting /* only for non qos_init */
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218);
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4);
+	mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW0, 0x22421111);
+	mmio_write_32(DBSC_SCFCTST2, 0x012F1123);
+	mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00);
+	mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00);
+	mmio_write_32(DBSC_DBSCHQOS02, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS03, 0x00000000);
+	mmio_write_32(DBSC_DBSCHQOS40, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0);
+	mmio_write_32(DBSC_DBSCHQOS42, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS43, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS90, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS91, 0x000000F0);
+	mmio_write_32(DBSC_DBSCHQOS92, 0x000000A0);
+	mmio_write_32(DBSC_DBSCHQOS93, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS130, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0);
+	mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0);
+	mmio_write_32(DBSC_DBSCHQOS133, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0);
+	mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0);
+	mmio_write_32(DBSC_DBSCHQOS142, 0x00000080);
+	mmio_write_32(DBSC_DBSCHQOS143, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS150, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS151, 0x00000030);
+	mmio_write_32(DBSC_DBSCHQOS152, 0x00000020);
+	mmio_write_32(DBSC_DBSCHQOS153, 0x00000010);
+
+	if (pdqsr_ctl == 0)
+		mmio_write_32(0xE67F0018, 0x00000001);
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+#endif
+
+	return 1;
+
+} /* recovery_from_backup_mode */
+
+/*
+ * init_ddr : MD19=0,DDR3L,1584Mbps / MD19=1,DDR3L,1856Mbps
+ */
+
+/*
+ * DDR Initialize entry for IPL
+ */
+int32_t rcar_dram_init(void)
+{
+	uint32_t dataL;
+	uint32_t failcount;
+	uint32_t md = 0;
+	uint32_t ddr = 0;
+	uint32_t ddr_backup;
+
+	md = *((volatile uint32_t*)RST_MODEMR);
+	ddr = (md & 0x00080000) >> 19;
+	if (ddr == 0x0)
+		NOTICE("BL2: DDR1584(%s)\n", RCAR_E3_DDR_VERSION);
+	else if (ddr == 0x1)
+		NOTICE("BL2: DDR1856(%s)\n", RCAR_E3_DDR_VERSION);
+
+	rcar_dram_get_boot_status(&ddr_backup);
+
+	if (ddr_backup == DRAM_BOOT_STATUS_WARM)
+		dataL = recovery_from_backup_mode(ddr_backup);	/* WARM boot */
+	else
+		dataL = init_ddr();				/* COLD boot */
+
+	if (dataL == 1)
+		failcount = 0;
+	else
+		failcount = 1;
+
+	if (failcount == 0)
+		return INITDRAM_OK;
+	else
+		return INITDRAM_NG;
+
+}
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_v3m.c b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_v3m.c
new file mode 100644
index 0000000..00e1903
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_v3m.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <stdint.h>
+#include "boot_init_dram.h"
+#include "boot_init_dram_regdef.h"
+
+static uint32_t init_ddr_v3m_1600(void)
+{
+	uint32_t i, r2, r5, r6, r7, r12;
+
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	mmio_write_32(DBSC_DBKIND, 0x00000007);
+#if RCAR_DRAM_DDR3L_MEMCONF == 0
+	mmio_write_32(DBSC_DBMEMCONF00, 0x0f030a02); // 1GB: Eagle
+#else
+	mmio_write_32(DBSC_DBMEMCONF00, 0x10030a02); // 2GB: V3MSK
+#endif
+	mmio_write_32(DBSC_DBPHYCONF0, 0x00000001);
+	mmio_write_32(DBSC_DBTR0, 0x0000000B);
+	mmio_write_32(DBSC_DBTR1, 0x00000008);
+	mmio_write_32(DBSC_DBTR3, 0x0000000B);
+	mmio_write_32(DBSC_DBTR4, 0x000B000B);
+	mmio_write_32(DBSC_DBTR5, 0x00000027);
+	mmio_write_32(DBSC_DBTR6, 0x0000001C);
+	mmio_write_32(DBSC_DBTR7, 0x00060006);
+	mmio_write_32(DBSC_DBTR8, 0x00000020);
+	mmio_write_32(DBSC_DBTR9, 0x00000006);
+	mmio_write_32(DBSC_DBTR10, 0x0000000C);
+	mmio_write_32(DBSC_DBTR11, 0x0000000B);
+	mmio_write_32(DBSC_DBTR12, 0x00120012);
+	mmio_write_32(DBSC_DBTR13, 0x01180118);
+	mmio_write_32(DBSC_DBTR14, 0x00140005);
+	mmio_write_32(DBSC_DBTR15, 0x00050004);
+	mmio_write_32(DBSC_DBTR16, 0x071D0305);
+	mmio_write_32(DBSC_DBTR17, 0x040C0010);
+	mmio_write_32(DBSC_DBTR18, 0x00000200);
+	mmio_write_32(DBSC_DBTR19, 0x01000040);
+	mmio_write_32(DBSC_DBTR20, 0x02000120);
+	mmio_write_32(DBSC_DBTR21, 0x00040004);
+	mmio_write_32(DBSC_DBBL, 0x00000000);
+	mmio_write_32(DBSC_DBODT0, 0x00000001);
+	mmio_write_32(DBSC_DBADJ0, 0x00000001);
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00082010);
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x00002000);
+	mmio_write_32(DBSC_DBSCHCNT0, 0x080f003f);
+	mmio_write_32(DBSC_DBSCHCNT1, 0x00001010);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000001);
+	mmio_write_32(DBSC_DBSCHRW0, 0x00000200);
+	mmio_write_32(DBSC_DBSCHRW1, 0x00000040);
+	mmio_write_32(DBSC_DBSCHQOS40, 0x00000600);
+	mmio_write_32(DBSC_DBSCHQOS41, 0x00000480);
+	mmio_write_32(DBSC_DBSCHQOS42, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS43, 0x00000180);
+	mmio_write_32(DBSC_DBSCHQOS90, 0x00000400);
+	mmio_write_32(DBSC_DBSCHQOS91, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS92, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS93, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS130, 0x00000300);
+	mmio_write_32(DBSC_DBSCHQOS131, 0x00000240);
+	mmio_write_32(DBSC_DBSCHQOS132, 0x00000180);
+	mmio_write_32(DBSC_DBSCHQOS133, 0x000000c0);
+	mmio_write_32(DBSC_DBSCHQOS140, 0x00000200);
+	mmio_write_32(DBSC_DBSCHQOS141, 0x00000180);
+	mmio_write_32(DBSC_DBSCHQOS142, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS143, 0x00000080);
+	mmio_write_32(DBSC_DBSCHQOS150, 0x00000100);
+	mmio_write_32(DBSC_DBSCHQOS151, 0x000000c0);
+	mmio_write_32(DBSC_DBSCHQOS152, 0x00000080);
+	mmio_write_32(DBSC_DBSCHQOS153, 0x00000040);
+	mmio_write_32(DBSC_DBSYSCONF1, 0x00000002);
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00040C04);
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x000001c4);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000003);
+	mmio_write_32(DBSC_DBSCHRW1, 0x001a0080);
+	mmio_write_32(DBSC_DBDFICNT0, 0x00000010);
+
+	mmio_write_32(DBSC_DBPDLK0, 0x0000A55A);
+	mmio_write_32(DBSC_DBCMD, 0x01000001);
+	mmio_write_32(DBSC_DBCMD, 0x08000000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x80010000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000008);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000B8000);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058904);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000091);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000095);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000099);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0007BB6D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024641E);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010073);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0C058900);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000090);
+	mmio_write_32(DBSC_DBPDRGD0, 0x04058900);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0780C700);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(30)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000004);
+	mmio_write_32(DBSC_DBPDRGD0, 0x08C0C170);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000022);
+	mmio_write_32(DBSC_DBPDRGD0, 0x1000040B);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000023);
+	mmio_write_32(DBSC_DBPDRGD0, 0x2D9C0B66);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000024);
+	mmio_write_32(DBSC_DBPDRGD0, 0x2A88C400);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000025);
+	mmio_write_32(DBSC_DBPDRGD0, 0x30005200);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000026);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0014A9C9);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000027);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000D70);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000028);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000004);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000029);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00000018);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003047);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000020);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00181884);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000001A);
+	mmio_write_32(DBSC_DBPDRGD0, 0x13C03C10);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E7);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E8);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E9);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000107);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000108);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0D0D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000109);
+	mmio_write_32(DBSC_DBPDRGD0, 0x000D0D0D);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010181);
+	mmio_write_32(DBSC_DBCMD, 0x08000001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010601);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = mmio_read_32(DBSC_DBPDRGD0) & 0xFF;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = mmio_read_32(DBSC_DBPDRGD0) & 0x7;
+
+		if (r6 > 0) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8);
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, ((r7 + 1) & 0x7) | r2);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r6);
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 | r7);
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     (((r5 << 1) + r6) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00A0);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010801);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000005);
+	mmio_write_32(DBSC_DBPDRGD0, 0xC1AA00B8);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0001F001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C000285);
+	mmio_write_32(DBSC_DBPDRGA0, 0x0000002C);
+	mmio_write_32(DBSC_DBPDRGD0, 0x81003087);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00010401);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(DBSC_DBPDRGA0, 0xB1 + i * 0x20);
+		r5 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF00) >> 8;
+		mmio_write_32(DBSC_DBPDRGA0, 0xB4 + i * 0x20);
+		r6 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFF);
+
+		mmio_write_32(DBSC_DBPDRGA0, 0xB3 + i * 0x20);
+		r7 = (mmio_read_32(DBSC_DBPDRGD0) & 0x7);
+		r12 = (r5 >> 2);
+		if (r6 - r12 > 0) {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8);
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, ((r7 + 1) & 0x7) | r2);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00);
+
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, ((r6 - r12) & 0xFF) | r2);
+		} else {
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFFF8);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB2 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, (r7 & 0x7) | r2);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			r2 = (mmio_read_32(DBSC_DBPDRGD0) & 0xFFFFFF00);
+			mmio_write_32(DBSC_DBPDRGA0, 0xB0 + i * 0x20);
+			mmio_write_32(DBSC_DBPDRGD0, r2 |
+						     ((r6 + r5 +
+						      (r5 >> 1) + r12) & 0xFF));
+		}
+	}
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000A0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000C0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x000000E0);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000100);
+	mmio_write_32(DBSC_DBPDRGD0, 0x7C0002C5);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000001);
+	mmio_write_32(DBSC_DBPDRGD0, 0x00015001);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000006);
+	while (!(mmio_read_32(DBSC_DBPDRGD0) & BIT(0)))
+		;
+
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000003);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0380C700);
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000007);
+	while (mmio_read_32(DBSC_DBPDRGD0) & BIT(30))
+		;
+	mmio_write_32(DBSC_DBPDRGA0, 0x00000021);
+	mmio_write_32(DBSC_DBPDRGD0, 0x0024643E);
+
+	mmio_write_32(DBSC_DBBUS0CNF1, 0x00000000);
+	mmio_write_32(DBSC_DBBUS0CNF0, 0x00010001);
+	mmio_write_32(DBSC_DBCALCNF, 0x0100200E);
+	mmio_write_32(DBSC_DBRFCNF1, 0x00081860);
+	mmio_write_32(DBSC_DBRFCNF2, 0x00010000);
+	mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001);
+	mmio_write_32(DBSC_DBRFEN, 0x00000001);
+	mmio_write_32(DBSC_DBACEN, 0x00000001);
+	mmio_write_32(DBSC_DBPDLK0, 0x00000000);
+	mmio_write_32(0xE67F0024, 0x00000001);
+	mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+
+	return INITDRAM_OK;
+}
+
+int32_t rcar_dram_init(void)
+{
+	return init_ddr_v3m_1600();
+}
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram.c b/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram.c
new file mode 100644
index 0000000..89d666c
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram.c
@@ -0,0 +1,4574 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "ddr_regdef.h"
+#include "init_dram_tbl_h3.h"
+#include "init_dram_tbl_m3.h"
+#include "init_dram_tbl_h3ver2.h"
+#include "init_dram_tbl_m3n.h"
+#include "boot_init_dram_regdef.h"
+#include "boot_init_dram.h"
+#include "dram_sub_func.h"
+#include "micro_delay.h"
+
+#define DDR_BACKUPMODE
+#define FATAL_MSG(x) NOTICE(x)
+
+/*******************************************************************************
+ *	variables
+ ******************************************************************************/
+#ifdef RCAR_DDR_FIXED_LSI_TYPE
+#ifndef RCAR_AUTO
+#define RCAR_AUTO	99
+#define RCAR_H3	0
+#define RCAR_M3	1
+#define RCAR_M3N	2
+#define RCAR_E3	3		/*  NON */
+#define RCAR_H3N	4
+
+#define RCAR_CUT_10	0
+#define RCAR_CUT_11	1
+#define RCAR_CUT_20	10
+#define RCAR_CUT_30	20
+#endif
+#ifndef RCAR_LSI
+#define RCAR_LSI	RCAR_AUTO
+#endif
+#if(RCAR_LSI==RCAR_AUTO)
+static uint32_t Prr_Product;
+static uint32_t Prr_Cut;
+#else
+#if(RCAR_LSI==RCAR_H3)
+static const uint32_t Prr_Product = PRR_PRODUCT_H3;
+#elif(RCAR_LSI==RCAR_M3)
+static const uint32_t Prr_Product = PRR_PRODUCT_M3;
+#elif(RCAR_LSI==RCAR_M3N)
+static const uint32_t Prr_Product = PRR_PRODUCT_M3N;
+#elif(RCAR_LSI==RCAR_H3N)
+static const uint32_t Prr_Product = PRR_PRODUCT_H3;
+#endif /* RCAR_LSI */
+
+#ifndef RCAR_LSI_CUT
+static uint32_t Prr_Cut;
+#else /* RCAR_LSI_CUT */
+#if(RCAR_LSI_CUT==RCAR_CUT_10)
+static const uint32_t Prr_Cut = PRR_PRODUCT_10;
+#elif(RCAR_LSI_CUT==RCAR_CUT_11)
+static const uint32_t Prr_Cut = PRR_PRODUCT_11;
+#elif(RCAR_LSI_CUT==RCAR_CUT_20)
+static const uint32_t Prr_Cut = PRR_PRODUCT_20;
+#elif(RCAR_LSI_CUT==RCAR_CUT_30)
+static const uint32_t Prr_Cut = PRR_PRODUCT_30;
+#endif /* RCAR_LSI_CUT */
+#endif /* RCAR_LSI_CUT */
+#endif /* RCAR_AUTO_NON */
+#else /* RCAR_DDR_FIXED_LSI_TYPE */
+static uint32_t Prr_Product;
+static uint32_t Prr_Cut;
+#endif /* RCAR_DDR_FIXED_LSI_TYPE */
+
+char *pRCAR_DDR_VERSION;
+uint32_t _cnf_BOARDTYPE;
+static const uint32_t *pDDR_REGDEF_TBL;
+static uint32_t brd_clk;
+static uint32_t brd_clkdiv;
+static uint32_t brd_clkdiva;
+static uint32_t ddr_mbps;
+static uint32_t ddr_mbpsdiv;
+static uint32_t ddr_tccd;
+static uint32_t ddr_phycaslice;
+static const struct _boardcnf *Boardcnf;
+static uint32_t ddr_phyvalid;
+static uint32_t ddr_density[DRAM_CH_CNT][CS_CNT];
+static uint32_t ch_have_this_cs[CS_CNT] __attribute__ ((aligned(64)));
+static uint32_t rdqdm_dly[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9];
+static uint32_t max_density;
+static uint32_t ddr0800_mul;
+static uint32_t ddr_mul;
+static uint32_t DDR_PHY_SLICE_REGSET_OFS;
+static uint32_t DDR_PHY_ADR_V_REGSET_OFS;
+static uint32_t DDR_PHY_ADR_I_REGSET_OFS;
+static uint32_t DDR_PHY_ADR_G_REGSET_OFS;
+static uint32_t DDR_PI_REGSET_OFS;
+static uint32_t DDR_PHY_SLICE_REGSET_SIZE;
+static uint32_t DDR_PHY_ADR_V_REGSET_SIZE;
+static uint32_t DDR_PHY_ADR_I_REGSET_SIZE;
+static uint32_t DDR_PHY_ADR_G_REGSET_SIZE;
+static uint32_t DDR_PI_REGSET_SIZE;
+static uint32_t DDR_PHY_SLICE_REGSET_NUM;
+static uint32_t DDR_PHY_ADR_V_REGSET_NUM;
+static uint32_t DDR_PHY_ADR_I_REGSET_NUM;
+static uint32_t DDR_PHY_ADR_G_REGSET_NUM;
+static uint32_t DDR_PI_REGSET_NUM;
+static uint32_t DDR_PHY_ADR_I_NUM;
+#define DDR_PHY_REGSET_MAX 128
+#define DDR_PI_REGSET_MAX 320
+static uint32_t _cnf_DDR_PHY_SLICE_REGSET[DDR_PHY_REGSET_MAX];
+static uint32_t _cnf_DDR_PHY_ADR_V_REGSET[DDR_PHY_REGSET_MAX];
+static uint32_t _cnf_DDR_PHY_ADR_I_REGSET[DDR_PHY_REGSET_MAX];
+static uint32_t _cnf_DDR_PHY_ADR_G_REGSET[DDR_PHY_REGSET_MAX];
+static uint32_t _cnf_DDR_PI_REGSET[DDR_PI_REGSET_MAX];
+static uint32_t Pll3Mode;
+static uint32_t loop_max;
+#ifdef DDR_BACKUPMODE
+uint32_t ddrBackup;
+/* #define DDR_BACKUPMODE_HALF           //for Half channel(ch0,1 only) */
+#endif
+
+#ifdef ddr_qos_init_setting	/*  only for non qos_init */
+#define OPERATING_FREQ			(400U)	/* Mhz */
+#define BASE_SUB_SLOT_NUM		(0x6U)
+#define SUB_SLOT_CYCLE			(0x7EU)	/* 126 */
+#define QOSWT_WTSET0_CYCLE		((SUB_SLOT_CYCLE * BASE_SUB_SLOT_NUM * 1000U)/OPERATING_FREQ)	/* unit:ns */
+
+uint32_t get_refperiod(void)
+{
+	return QOSWT_WTSET0_CYCLE;
+}
+#else /*  ddr_qos_init_setting // only for non qos_init */
+extern uint32_t get_refperiod(void);
+#endif /* ddr_qos_init_setting // only for non qos_init */
+
+#define _reg_PHY_RX_CAL_X_NUM 11
+static const uint32_t _reg_PHY_RX_CAL_X[_reg_PHY_RX_CAL_X_NUM] = {
+	_reg_PHY_RX_CAL_DQ0,
+	_reg_PHY_RX_CAL_DQ1,
+	_reg_PHY_RX_CAL_DQ2,
+	_reg_PHY_RX_CAL_DQ3,
+	_reg_PHY_RX_CAL_DQ4,
+	_reg_PHY_RX_CAL_DQ5,
+	_reg_PHY_RX_CAL_DQ6,
+	_reg_PHY_RX_CAL_DQ7,
+	_reg_PHY_RX_CAL_DM,
+	_reg_PHY_RX_CAL_DQS,
+	_reg_PHY_RX_CAL_FDBK
+};
+
+#define _reg_PHY_CLK_WRX_SLAVE_DELAY_NUM 10
+static const uint32_t
+    _reg_PHY_CLK_WRX_SLAVE_DELAY[_reg_PHY_CLK_WRX_SLAVE_DELAY_NUM] = {
+	_reg_PHY_CLK_WRDQ0_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ1_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ2_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ3_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ4_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ5_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ6_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQ7_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDM_SLAVE_DELAY,
+	_reg_PHY_CLK_WRDQS_SLAVE_DELAY
+};
+
+#define _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY_NUM 9
+static const uint32_t
+    _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[_reg_PHY_RDDQS_X_FALL_SLAVE_DELAY_NUM] = {
+	_reg_PHY_RDDQS_DQ0_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ1_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ2_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ3_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ4_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ5_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ6_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ7_FALL_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DM_FALL_SLAVE_DELAY
+};
+
+#define _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY_NUM 9
+static const uint32_t
+    _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[_reg_PHY_RDDQS_X_RISE_SLAVE_DELAY_NUM] = {
+	_reg_PHY_RDDQS_DQ0_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ1_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ2_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ3_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ4_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ5_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ6_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DQ7_RISE_SLAVE_DELAY,
+	_reg_PHY_RDDQS_DM_RISE_SLAVE_DELAY
+};
+
+#define _reg_PHY_PAD_TERM_X_NUM 8
+static const uint32_t _reg_PHY_PAD_TERM_X[_reg_PHY_PAD_TERM_X_NUM] = {
+	_reg_PHY_PAD_FDBK_TERM,
+	_reg_PHY_PAD_DATA_TERM,
+	_reg_PHY_PAD_DQS_TERM,
+	_reg_PHY_PAD_ADDR_TERM,
+	_reg_PHY_PAD_CLK_TERM,
+	_reg_PHY_PAD_CKE_TERM,
+	_reg_PHY_PAD_RST_TERM,
+	_reg_PHY_PAD_CS_TERM
+};
+
+#define _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM 10
+static const uint32_t
+    _reg_PHY_CLK_CACS_SLAVE_DELAY_X[_reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM] = {
+	_reg_PHY_ADR0_CLK_WR_SLAVE_DELAY,
+	_reg_PHY_ADR1_CLK_WR_SLAVE_DELAY,
+	_reg_PHY_ADR2_CLK_WR_SLAVE_DELAY,
+	_reg_PHY_ADR3_CLK_WR_SLAVE_DELAY,
+	_reg_PHY_ADR4_CLK_WR_SLAVE_DELAY,
+	_reg_PHY_ADR5_CLK_WR_SLAVE_DELAY,
+
+	_reg_PHY_GRP_SLAVE_DELAY_0,
+	_reg_PHY_GRP_SLAVE_DELAY_1,
+	_reg_PHY_GRP_SLAVE_DELAY_2,
+	_reg_PHY_GRP_SLAVE_DELAY_3
+};
+
+/*******************************************************************************
+ *	Prototypes
+ ******************************************************************************/
+static inline uint32_t vch_nxt(uint32_t pos);
+static void cpg_write_32(uint32_t a, uint32_t v);
+static void pll3_control(uint32_t high);
+static inline void dsb_sev(void);
+static void wait_dbcmd(void);
+static void send_dbcmd(uint32_t cmd);
+static uint32_t reg_ddrphy_read(uint32_t phyno, uint32_t regadd);
+static void reg_ddrphy_write(uint32_t phyno, uint32_t regadd, uint32_t regdata);
+static void reg_ddrphy_write_a(uint32_t regadd, uint32_t regdata);
+static inline uint32_t ddr_regdef(uint32_t _regdef);
+static inline uint32_t ddr_regdef_adr(uint32_t _regdef);
+static inline uint32_t ddr_regdef_lsb(uint32_t _regdef);
+static void ddr_setval_s(uint32_t ch, uint32_t slice, uint32_t _regdef,
+			 uint32_t val);
+static uint32_t ddr_getval_s(uint32_t ch, uint32_t slice, uint32_t _regdef);
+static void ddr_setval(uint32_t ch, uint32_t regdef, uint32_t val);
+static void ddr_setval_ach_s(uint32_t slice, uint32_t regdef, uint32_t val);
+static void ddr_setval_ach(uint32_t regdef, uint32_t val);
+static void ddr_setval_ach_as(uint32_t regdef, uint32_t val);
+static uint32_t ddr_getval(uint32_t ch, uint32_t regdef);
+static uint32_t ddr_getval_ach(uint32_t regdef, uint32_t * p);
+static uint32_t ddr_getval_ach_as(uint32_t regdef, uint32_t * p);
+static void _tblcopy(uint32_t * to, const uint32_t * from, uint32_t size);
+static void ddrtbl_setval(uint32_t * tbl, uint32_t _regdef, uint32_t val);
+static uint32_t ddrtbl_getval(uint32_t * tbl, uint32_t _regdef);
+static uint32_t ddrphy_regif_chk(void);
+static inline void ddrphy_regif_idle();
+static uint16_t _f_scale(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv, uint32_t ps,
+			 uint16_t cyc);
+static void _f_scale_js2(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv,
+			 uint16_t * js2);
+static int16_t _f_scale_adj(int16_t ps);
+static void ddrtbl_load(void);
+static void ddr_config_sub(void);
+static void get_ca_swizzle(uint32_t ch, uint32_t ddr_csn, uint32_t * p_swz);
+static void ddr_config_sub_h3v1x(void);
+static void ddr_config(void);
+static void dbsc_regset(void);
+static void dbsc_regset_post(void);
+static uint32_t dfi_init_start(void);
+static void change_lpddr4_en(uint32_t mode);
+static uint32_t set_term_code(void);
+static void ddr_register_set(void);
+static inline uint32_t wait_freqchgreq(uint32_t assert);
+static inline void set_freqchgack(uint32_t assert);
+static inline void set_dfifrequency(uint32_t freq);
+static uint32_t pll3_freq(uint32_t on);
+static void update_dly(void);
+static uint32_t pi_training_go(void);
+static uint32_t init_ddr(void);
+static uint32_t swlvl1(uint32_t ddr_csn, uint32_t reg_cs, uint32_t reg_kick);
+static uint32_t wdqdm_man1(void);
+static uint32_t wdqdm_man(void);
+static uint32_t rdqdm_man1(void);
+static uint32_t rdqdm_man(void);
+
+static int32_t _find_change(uint64_t val, uint32_t dir);
+static uint32_t _rx_offset_cal_updn(uint32_t code);
+static uint32_t rx_offset_cal(void);
+static uint32_t rx_offset_cal_hw(void);
+static void adjust_rddqs_latency(void);
+static void adjust_wpath_latency(void);
+
+struct DdrtData {
+	int32_t init_temp;	/*  Initial Temperature (do) */
+	uint32_t init_cal[4];	/*  Initial io-code (4 is for H3) */
+	uint32_t tcomp_cal[4];	/*  Temperature compensated io-code (4 is for H3) */
+};
+struct DdrtData tcal;
+
+static void pvtcode_update(void);
+static void pvtcode_update2(void);
+static void ddr_padcal_tcompensate_getinit(uint32_t override);
+
+/*******************************************************************************
+ *	load board configuration
+ ******************************************************************************/
+#include "boot_init_dram_config.c"
+
+#ifndef DDR_FAST_INIT
+static uint32_t rdqdm_le[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9];
+static uint32_t rdqdm_te[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9];
+static uint32_t rdqdm_nw[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9];
+static uint32_t rdqdm_win[DRAM_CH_CNT][CS_CNT][SLICE_CNT];
+static uint32_t rdqdm_st[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2];
+static void rdqdm_clr1(uint32_t ch, uint32_t ddr_csn);
+static uint32_t rdqdm_ana1(uint32_t ch, uint32_t ddr_csn);
+
+static uint32_t wdqdm_le[DRAM_CH_CNT][CS_CNT][SLICE_CNT][9];
+static uint32_t wdqdm_te[DRAM_CH_CNT][CS_CNT][SLICE_CNT][9];
+static uint32_t wdqdm_dly[DRAM_CH_CNT][CS_CNT][SLICE_CNT][9];
+static uint32_t wdqdm_st[DRAM_CH_CNT][CS_CNT][SLICE_CNT];
+static uint32_t wdqdm_win[DRAM_CH_CNT][CS_CNT][SLICE_CNT];
+static void wdqdm_clr1(uint32_t ch, uint32_t ddr_csn);
+static uint32_t wdqdm_ana1(uint32_t ch, uint32_t ddr_csn);
+#endif/* DDR_FAST_INIT */
+
+/*******************************************************************************
+ *	macro for channel selection loop
+ ******************************************************************************/
+static inline uint32_t vch_nxt(uint32_t pos)
+{
+	uint32_t posn;
+
+	for (posn = pos; posn < DRAM_CH_CNT; posn++) {
+		if (ddr_phyvalid & (1U << posn))
+			break;
+	}
+	return posn;
+}
+
+#define foreach_vch(ch) \
+for(ch=vch_nxt(0);ch<DRAM_CH_CNT;ch=vch_nxt(ch+1))
+
+#define foreach_ech(ch) \
+for(ch=0;ch<DRAM_CH_CNT;ch++)
+
+/*******************************************************************************
+ *	Printing functions
+ ******************************************************************************/
+#define MSG_LF(...)
+
+/*******************************************************************************
+ *	clock settings, reset control
+ ******************************************************************************/
+static void cpg_write_32(uint32_t a, uint32_t v)
+{
+	mmio_write_32(CPG_CPGWPR, ~v);
+	mmio_write_32(a, v);
+}
+
+static void pll3_control(uint32_t high)
+{
+	uint32_t dataL, dataDIV, dataMUL, tmpDIV;
+
+	if (high) {
+		tmpDIV = 3999 * brd_clkdiv * (brd_clkdiva + 1) /
+			(brd_clk * ddr_mul) / 2;
+		dataMUL = (((ddr_mul * tmpDIV) - 1) << 24) |
+			(brd_clkdiva << 7);
+		Pll3Mode = 1;
+		loop_max = 2;
+	} else {
+		tmpDIV = 3999 * brd_clkdiv * (brd_clkdiva + 1) /
+			(brd_clk * ddr0800_mul) / 2;
+		dataMUL = (((ddr0800_mul * tmpDIV) - 1) << 24) |
+			(brd_clkdiva << 7);
+		Pll3Mode = 0;
+		loop_max = 8;
+	}
+
+	switch (tmpDIV) {
+	case 1:
+		dataDIV = 0;
+		break;
+	case 2:
+	case 3:
+	case 4:
+		dataDIV = tmpDIV;
+		break;
+	default:
+		dataDIV = 6;
+		dataMUL = (dataMUL * tmpDIV) / 3;
+		break;
+	}
+	dataMUL = dataMUL | (brd_clkdiva << 7);
+
+	/* PLL3 disable */
+	dataL = mmio_read_32(CPG_PLLECR) & ~CPG_PLLECR_PLL3E_BIT;
+	cpg_write_32(CPG_PLLECR, dataL);
+	dsb_sev();
+
+	if ((Prr_Product == PRR_PRODUCT_M3) ||
+	    ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_20))) {
+		/* PLL3 DIV resetting(Lowest value:3) */
+		dataL = 0x00030003 | (0xFF80FF80 & mmio_read_32(CPG_FRQCRD));
+		cpg_write_32(CPG_FRQCRD, dataL);
+		dsb_sev();
+
+		/* zb3 clk stop */
+		dataL = CPG_ZB3CKCR_ZB3ST_BIT | mmio_read_32(CPG_ZB3CKCR);
+		cpg_write_32(CPG_ZB3CKCR, dataL);
+		dsb_sev();
+
+		/* PLL3 enable */
+		dataL = CPG_PLLECR_PLL3E_BIT | mmio_read_32(CPG_PLLECR);
+		cpg_write_32(CPG_PLLECR, dataL);
+		dsb_sev();
+
+		do {
+			dataL = mmio_read_32(CPG_PLLECR);
+		} while ((dataL & CPG_PLLECR_PLL3ST_BIT) == 0);
+		dsb_sev();
+
+		/* PLL3 DIV resetting (Highest value:0) */
+		dataL = (0xFF80FF80 & mmio_read_32(CPG_FRQCRD));
+		cpg_write_32(CPG_FRQCRD, dataL);
+		dsb_sev();
+
+		/* DIV SET KICK */
+		dataL = CPG_FRQCRB_KICK_BIT | mmio_read_32(CPG_FRQCRB);
+		cpg_write_32(CPG_FRQCRB, dataL);
+		dsb_sev();
+
+		/* PLL3 multiplie set */
+		cpg_write_32(CPG_PLL3CR, dataMUL);
+		dsb_sev();
+
+		do {
+			dataL = mmio_read_32(CPG_PLLECR);
+		} while ((dataL & CPG_PLLECR_PLL3ST_BIT) == 0);
+		dsb_sev();
+
+		/* PLL3 DIV resetting(Target value) */
+		dataL = (dataDIV << 16) | dataDIV | (0xFF80FF80 & mmio_read_32(CPG_FRQCRD));
+		cpg_write_32(CPG_FRQCRD, dataL);
+		dsb_sev();
+
+		/* DIV SET KICK */
+		dataL = CPG_FRQCRB_KICK_BIT | mmio_read_32(CPG_FRQCRB);
+		cpg_write_32(CPG_FRQCRB, dataL);
+		dsb_sev();
+
+		do {
+			dataL = mmio_read_32(CPG_PLLECR);
+		} while ((dataL & CPG_PLLECR_PLL3ST_BIT) == 0);
+		dsb_sev();
+
+		/* zb3 clk start */
+		dataL = (~CPG_ZB3CKCR_ZB3ST_BIT) & mmio_read_32(CPG_ZB3CKCR);
+		cpg_write_32(CPG_ZB3CKCR, dataL);
+		dsb_sev();
+
+	} else { /*  H3Ver.3.0/M3N/V3H */
+
+		/* PLL3 multiplie set */
+		cpg_write_32(CPG_PLL3CR, dataMUL);
+		dsb_sev();
+
+		/* PLL3 DIV set(Target value) */
+		dataL = (dataDIV << 16) | dataDIV | (0xFF80FF80 & mmio_read_32(CPG_FRQCRD));
+		cpg_write_32(CPG_FRQCRD, dataL);
+
+		/* DIV SET KICK */
+		dataL = CPG_FRQCRB_KICK_BIT | mmio_read_32(CPG_FRQCRB);
+		cpg_write_32(CPG_FRQCRB, dataL);
+		dsb_sev();
+
+		/* PLL3 enable */
+		dataL = CPG_PLLECR_PLL3E_BIT | mmio_read_32(CPG_PLLECR);
+		cpg_write_32(CPG_PLLECR, dataL);
+		dsb_sev();
+
+		do {
+			dataL = mmio_read_32(CPG_PLLECR);
+		} while ((dataL & CPG_PLLECR_PLL3ST_BIT) == 0);
+		dsb_sev();
+	}
+}
+
+/*******************************************************************************
+ *	barrier
+ ******************************************************************************/
+static inline void dsb_sev(void)
+{
+	__asm__ __volatile__("dsb sy");
+}
+
+/*******************************************************************************
+ *	DDR memory register access
+ ******************************************************************************/
+static void wait_dbcmd(void)
+{
+	uint32_t dataL;
+	/* dummy read */
+	dataL = mmio_read_32(DBSC_DBCMD);
+	dsb_sev();
+	while (1) {
+		/* wait DBCMD 1=busy, 0=ready */
+		dataL = mmio_read_32(DBSC_DBWAIT);
+		dsb_sev();
+		if ((dataL & 0x00000001) == 0x00)
+			break;
+	}
+}
+
+static void send_dbcmd(uint32_t cmd)
+{
+	/* dummy read */
+	wait_dbcmd();
+	mmio_write_32(DBSC_DBCMD, cmd);
+	dsb_sev();
+}
+
+/*******************************************************************************
+ *	DDRPHY register access (raw)
+ ******************************************************************************/
+static uint32_t reg_ddrphy_read(uint32_t phyno, uint32_t regadd)
+{
+	uint32_t val;
+	uint32_t loop;
+
+	val = 0;
+	if ((PRR_PRODUCT_M3N != Prr_Product)
+	    && (PRR_PRODUCT_V3H != Prr_Product)) {
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd);
+		dsb_sev();
+
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) {
+			dsb_sev();
+		}
+		dsb_sev();
+
+		for (loop = 0; loop < loop_max; loop++) {
+			val = mmio_read_32(DBSC_DBPDRGD(phyno));
+			dsb_sev();
+		}
+		(void)val;
+	} else {
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00004000);
+		dsb_sev();
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) !=
+		       (regadd | 0x0000C000)) {
+			dsb_sev();
+		};
+		val = mmio_read_32(DBSC_DBPDRGA(phyno));
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00008000);
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) {
+			dsb_sev();
+		};
+		dsb_sev();
+
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00008000);
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) {
+			dsb_sev();
+		};
+
+		dsb_sev();
+		val = mmio_read_32(DBSC_DBPDRGD(phyno));
+		dsb_sev();
+		(void)val;
+	}
+	return val;
+}
+
+static void reg_ddrphy_write(uint32_t phyno, uint32_t regadd, uint32_t regdata)
+{
+	uint32_t val;
+	uint32_t loop;
+
+	if ((PRR_PRODUCT_M3N != Prr_Product)
+	    && (PRR_PRODUCT_V3H != Prr_Product)) {
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd);
+		dsb_sev();
+		for (loop = 0; loop < loop_max; loop++) {
+			val = mmio_read_32(DBSC_DBPDRGA(phyno));
+			dsb_sev();
+		}
+		mmio_write_32(DBSC_DBPDRGD(phyno), regdata);
+		dsb_sev();
+
+		for (loop = 0; loop < loop_max; loop++) {
+			val = mmio_read_32(DBSC_DBPDRGD(phyno));
+			dsb_sev();
+		}
+	} else {
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd);
+		dsb_sev();
+
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) {
+			dsb_sev();
+		};
+		dsb_sev();
+
+		mmio_write_32(DBSC_DBPDRGD(phyno), regdata);
+		dsb_sev();
+
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) !=
+		       (regadd | 0x00008000)) {
+			dsb_sev();
+		};
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00008000);
+
+		while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) {
+			dsb_sev();
+		};
+		dsb_sev();
+
+		mmio_write_32(DBSC_DBPDRGA(phyno), regadd);
+	}
+	(void)val;
+}
+
+static void reg_ddrphy_write_a(uint32_t regadd, uint32_t regdata)
+{
+	uint32_t ch;
+	uint32_t val;
+	uint32_t loop;
+
+	if ((PRR_PRODUCT_M3N != Prr_Product)
+	    && (PRR_PRODUCT_V3H != Prr_Product)) {
+		foreach_vch(ch) {
+			mmio_write_32(DBSC_DBPDRGA(ch), regadd);
+			dsb_sev();
+		}
+
+		foreach_vch(ch) {
+			mmio_write_32(DBSC_DBPDRGD(ch), regdata);
+			dsb_sev();
+		}
+
+		for (loop = 0; loop < loop_max; loop++) {
+			val = mmio_read_32(DBSC_DBPDRGD(0));
+			dsb_sev();
+		}
+		(void)val;
+	} else {
+		foreach_vch(ch) {
+			reg_ddrphy_write(ch, regadd, regdata);
+			dsb_sev();
+		}
+	}
+}
+
+static inline void ddrphy_regif_idle()
+{
+	uint32_t val;
+
+	val = reg_ddrphy_read(0, ddr_regdef_adr(_reg_PI_INT_STATUS));
+	dsb_sev();
+	(void)val;
+}
+
+/*******************************************************************************
+ *	DDRPHY register access (field modify)
+ ******************************************************************************/
+static inline uint32_t ddr_regdef(uint32_t _regdef)
+{
+	return pDDR_REGDEF_TBL[_regdef];
+}
+
+static inline uint32_t ddr_regdef_adr(uint32_t _regdef)
+{
+	return DDR_REGDEF_ADR(pDDR_REGDEF_TBL[_regdef]);
+}
+
+static inline uint32_t ddr_regdef_lsb(uint32_t _regdef)
+{
+	return DDR_REGDEF_LSB(pDDR_REGDEF_TBL[_regdef]);
+}
+
+static void ddr_setval_s(uint32_t ch, uint32_t slice, uint32_t _regdef,
+			 uint32_t val)
+{
+	uint32_t adr;
+	uint32_t lsb;
+	uint32_t len;
+	uint32_t msk;
+	uint32_t tmp;
+	uint32_t regdef;
+
+	regdef = ddr_regdef(_regdef);
+	adr = DDR_REGDEF_ADR(regdef) + 0x80 * slice;
+	len = DDR_REGDEF_LEN(regdef);
+	lsb = DDR_REGDEF_LSB(regdef);
+	if (len == 0x20)
+		msk = 0xffffffff;
+	else
+		msk = ((1U << len) - 1) << lsb;
+
+	tmp = reg_ddrphy_read(ch, adr);
+	tmp = (tmp & (~msk)) | ((val << lsb) & msk);
+	reg_ddrphy_write(ch, adr, tmp);
+}
+
+static uint32_t ddr_getval_s(uint32_t ch, uint32_t slice, uint32_t _regdef)
+{
+	uint32_t adr;
+	uint32_t lsb;
+	uint32_t len;
+	uint32_t msk;
+	uint32_t tmp;
+	uint32_t regdef;
+
+	regdef = ddr_regdef(_regdef);
+	adr = DDR_REGDEF_ADR(regdef) + 0x80 * slice;
+	len = DDR_REGDEF_LEN(regdef);
+	lsb = DDR_REGDEF_LSB(regdef);
+	if (len == 0x20)
+		msk = 0xffffffff;
+	else
+		msk = ((1U << len) - 1);
+
+	tmp = reg_ddrphy_read(ch, adr);
+	tmp = (tmp >> lsb) & msk;
+
+	return tmp;
+}
+
+static void ddr_setval(uint32_t ch, uint32_t regdef, uint32_t val)
+{
+	ddr_setval_s(ch, 0, regdef, val);
+}
+
+static void ddr_setval_ach_s(uint32_t slice, uint32_t regdef, uint32_t val)
+{
+	uint32_t ch;
+
+	foreach_vch(ch)
+	    ddr_setval_s(ch, slice, regdef, val);
+}
+
+static void ddr_setval_ach(uint32_t regdef, uint32_t val)
+{
+	ddr_setval_ach_s(0, regdef, val);
+}
+
+static void ddr_setval_ach_as(uint32_t regdef, uint32_t val)
+{
+	uint32_t slice;
+
+	for (slice = 0; slice < SLICE_CNT; slice++)
+		ddr_setval_ach_s(slice, regdef, val);
+}
+
+static uint32_t ddr_getval(uint32_t ch, uint32_t regdef)
+{
+	return ddr_getval_s(ch, 0, regdef);
+}
+
+static uint32_t ddr_getval_ach(uint32_t regdef, uint32_t * p)
+{
+	uint32_t ch;
+
+	foreach_vch(ch)
+	    p[ch] = ddr_getval_s(ch, 0, regdef);
+	return p[0];
+}
+
+static uint32_t ddr_getval_ach_as(uint32_t regdef, uint32_t * p)
+{
+	uint32_t ch, slice;
+	uint32_t *pp;
+
+	pp = p;
+	foreach_vch(ch)
+	    for (slice = 0; slice < SLICE_CNT; slice++)
+		*pp++ = ddr_getval_s(ch, slice, regdef);
+	return p[0];
+}
+
+/*******************************************************************************
+ *	handling functions for setteing ddrphy value table
+ ******************************************************************************/
+static void _tblcopy(uint32_t * to, const uint32_t * from, uint32_t size)
+{
+	uint32_t i;
+
+	for (i = 0; i < size; i++) {
+		to[i] = from[i];
+	}
+}
+
+static void ddrtbl_setval(uint32_t * tbl, uint32_t _regdef, uint32_t val)
+{
+	uint32_t adr;
+	uint32_t lsb;
+	uint32_t len;
+	uint32_t msk;
+	uint32_t tmp;
+	uint32_t adrmsk;
+	uint32_t regdef;
+
+	regdef = ddr_regdef(_regdef);
+	adr = DDR_REGDEF_ADR(regdef);
+	len = DDR_REGDEF_LEN(regdef);
+	lsb = DDR_REGDEF_LSB(regdef);
+	if (len == 0x20)
+		msk = 0xffffffff;
+	else
+		msk = ((1U << len) - 1) << lsb;
+
+	if (adr < 0x400) {
+		adrmsk = 0xff;
+	} else {
+		adrmsk = 0x7f;
+	}
+
+	tmp = tbl[adr & adrmsk];
+	tmp = (tmp & (~msk)) | ((val << lsb) & msk);
+	tbl[adr & adrmsk] = tmp;
+}
+
+static uint32_t ddrtbl_getval(uint32_t * tbl, uint32_t _regdef)
+{
+	uint32_t adr;
+	uint32_t lsb;
+	uint32_t len;
+	uint32_t msk;
+	uint32_t tmp;
+	uint32_t adrmsk;
+	uint32_t regdef;
+
+	regdef = ddr_regdef(_regdef);
+	adr = DDR_REGDEF_ADR(regdef);
+	len = DDR_REGDEF_LEN(regdef);
+	lsb = DDR_REGDEF_LSB(regdef);
+	if (len == 0x20)
+		msk = 0xffffffff;
+	else
+		msk = ((1U << len) - 1);
+
+	if (adr < 0x400) {
+		adrmsk = 0xff;
+	} else {
+		adrmsk = 0x7f;
+	}
+
+	tmp = tbl[adr & adrmsk];
+	tmp = (tmp >> lsb) & msk;
+
+	return tmp;
+}
+
+/*******************************************************************************
+ *	DDRPHY register access handling
+ ******************************************************************************/
+static uint32_t ddrphy_regif_chk(void)
+{
+	uint32_t tmp_ach[DRAM_CH_CNT];
+	uint32_t ch;
+	uint32_t err;
+	uint32_t PI_VERSION_CODE;
+
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+	    || (Prr_Product == PRR_PRODUCT_M3)) {
+		PI_VERSION_CODE = 0x2041;	/* H3 Ver.1.x/M3-W */
+	} else {
+		PI_VERSION_CODE = 0x2040;	/* H3 Ver.2.0 or later/M3-N/V3H */
+	}
+
+	ddr_getval_ach(_reg_PI_VERSION, (uint32_t *) tmp_ach);
+	err = 0;
+	foreach_vch(ch) {
+		if (PI_VERSION_CODE != tmp_ach[ch])
+			err = 1;
+	}
+	return err;
+}
+
+/*******************************************************************************
+ *	functions and parameters for timing setting
+ ******************************************************************************/
+struct _jedec_spec1 {
+	uint16_t fx3;
+	uint8_t RLwoDBI;
+	uint8_t RLwDBI;
+	uint8_t WL;
+	uint8_t nWR;
+	uint8_t nRTP;
+	uint8_t MR1;
+	uint8_t MR2;
+};
+#define JS1_USABLEC_SPEC_LO 2
+#define JS1_USABLEC_SPEC_HI 5
+#define JS1_FREQ_TBL_NUM 8
+#define JS1_MR1(f) (0x04 | ((f)<<4))
+#define JS1_MR2(f) (0x00 | ((f)<<3) | (f))
+const struct _jedec_spec1 js1[JS1_FREQ_TBL_NUM] = {
+	{  800,  6,  6,  4,  6,  8, JS1_MR1(0), JS1_MR2(0)|0x40 }, /*  533.333Mbps */
+	{ 1600, 10, 12,  8, 10,  8, JS1_MR1(1), JS1_MR2(1)|0x40 }, /* 1066.666Mbps */
+	{ 2400, 14, 16, 12, 16,  8, JS1_MR1(2), JS1_MR2(2)|0x40 }, /* 1600.000Mbps */
+	{ 3200, 20, 22, 10, 20,  8, JS1_MR1(3), JS1_MR2(3) },      /* 2133.333Mbps */
+	{ 4000, 24, 28, 12, 24, 10, JS1_MR1(4), JS1_MR2(4) },      /* 2666.666Mbps */
+	{ 4800, 28, 32, 14, 30, 12, JS1_MR1(5), JS1_MR2(5) },      /* 3200.000Mbps */
+	{ 5600, 32, 36, 16, 34, 14, JS1_MR1(6), JS1_MR2(6) },      /* 3733.333Mbps */
+	{ 6400, 36, 40, 18, 40, 16, JS1_MR1(7), JS1_MR2(7) }       /* 4266.666Mbps */
+};
+
+struct _jedec_spec2 {
+	uint16_t ps;
+	uint16_t cyc;
+};
+
+#define JS2_tSR 0
+#define JS2_tXP 1
+#define JS2_tRTP 2
+#define JS2_tRCD 3
+#define JS2_tRPpb 4
+#define JS2_tRPab 5
+#define JS2_tRAS 6
+#define JS2_tWR 7
+#define JS2_tWTR 8
+#define JS2_tRRD 9
+#define JS2_tPPD 10
+#define JS2_tFAW 11
+#define JS2_tDQSCK 12
+#define JS2_tCKEHCMD 13
+#define JS2_tCKELCMD 14
+#define JS2_tCKELPD 15
+#define JS2_tMRR 16
+#define JS2_tMRW 17
+#define JS2_tMRD 18
+#define JS2_tZQCALns 19
+#define JS2_tZQLAT 20
+#define JS2_tIEdly 21
+#define JS2_TBLCNT 22
+
+#define JS2_tRCpb (JS2_TBLCNT)
+#define JS2_tRCab (JS2_TBLCNT+1)
+#define JS2_tRFCab (JS2_TBLCNT+2)
+#define JS2_CNT (JS2_TBLCNT+3)
+
+#ifndef JS2_DERATE
+#define JS2_DERATE 0
+#endif
+const struct _jedec_spec2 jedec_spec2[2][JS2_TBLCNT] = {
+	{
+/*tSR   */ {15000, 3},
+/*tXP   */ {7500, 3},
+/*tRTP  */ {7500, 8},
+/*tRCD  */ {18000, 4},
+/*tRPpb */ {18000, 3},
+/*tRPab */ {21000, 3},
+/*tRAS  */ {42000, 3},
+/*tWR   */ {18000, 4},
+/*tWTR  */ {10000, 8},
+/*tRRD  */ {10000, 4},
+/*tPPD  */ {0, 0},
+/*tFAW  */ {40000, 0},
+/*tDQSCK*/ {3500, 0},
+/*tCKEHCMD*/ {7500, 3},
+/*tCKELCMD*/ {7500, 3},
+/*tCKELPD*/ {7500, 3},
+/*tMRR*/ {0, 8},
+/*tMRW*/ {10000, 10},
+/*tMRD*/ {14000, 10},
+/*tZQCALns*/ {1000 * 10, 0},
+/*tZQLAT*/ {30000, 10},
+/*tIEdly*/ {12500, 0}
+	 }, {
+/*tSR   */ {15000, 3},
+/*tXP   */ {7500, 3},
+/*tRTP  */ {7500, 8},
+/*tRCD  */ {19875, 4},
+/*tRPpb */ {19875, 3},
+/*tRPab */ {22875, 3},
+/*tRAS  */ {43875, 3},
+/*tWR   */ {18000, 4},
+/*tWTR  */ {10000, 8},
+/*tRRD  */ {11875, 4},
+/*tPPD  */ {0, 0},
+/*tFAW  */ {40000, 0},
+/*tDQSCK*/ {3600, 0},
+/*tCKEHCMD*/ {7500, 3},
+/*tCKELCMD*/ {7500, 3},
+/*tCKELPD*/ {7500, 3},
+/*tMRR*/ {0, 8},
+/*tMRW*/ {10000, 10},
+/*tMRD*/ {14000, 10},
+/*tZQCALns*/ {1000 * 10, 0},
+/*tZQLAT*/ {30000, 10},
+/*tIEdly*/ {12500, 0}
+	     }
+};
+
+const uint16_t jedec_spec2_tRFC_ab[7] = {
+/*	4Gb, 6Gb, 8Gb,12Gb, 16Gb, 24Gb(non), 32Gb(non)	*/
+	 130, 180, 180, 280, 280, 560, 560
+};
+
+static uint32_t js1_ind;
+static uint16_t js2[JS2_CNT];
+static uint8_t RL;
+static uint8_t WL;
+
+static uint16_t _f_scale(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv, uint32_t ps,
+			 uint16_t cyc)
+{
+	uint32_t tmp;
+	uint32_t div;
+
+	tmp = (((uint32_t) (ps) + 9) / 10) * ddr_mbps;
+	div = tmp / (200000 * ddr_mbpsdiv);
+	if (tmp != (div * 200000 * ddr_mbpsdiv))
+		div = div + 1;
+
+	if (div > cyc)
+		return (uint16_t) div;
+	return cyc;
+}
+
+static void _f_scale_js2(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv,
+			 uint16_t * js2)
+{
+	int i;
+
+	for (i = 0; i < JS2_TBLCNT; i++) {
+		js2[i] = _f_scale(ddr_mbps, ddr_mbpsdiv,
+				  1UL * jedec_spec2[JS2_DERATE][i].ps,
+				  jedec_spec2[JS2_DERATE][i].cyc);
+	}
+
+	js2[JS2_tRCpb] = js2[JS2_tRAS] + js2[JS2_tRPpb];
+	js2[JS2_tRCab] = js2[JS2_tRAS] + js2[JS2_tRPab];
+}
+
+/* scaler for DELAY value */
+static int16_t _f_scale_adj(int16_t ps)
+{
+	int32_t tmp;
+	/*
+	   tmp = (int32_t)512 * ps * ddr_mbps /2 / ddr_mbpsdiv / 1000 / 1000;
+	   = ps * ddr_mbps /2 / ddr_mbpsdiv *512 / 8 / 8 / 125 / 125
+	   = ps * ddr_mbps / ddr_mbpsdiv *4 / 125 / 125
+	 */
+	tmp =
+	    (int32_t) 4 *(int32_t) ps *(int32_t) ddr_mbps /
+	    (int32_t) ddr_mbpsdiv;
+	tmp = (int32_t) tmp / (int32_t) 15625;
+
+	return (int16_t) tmp;
+}
+
+const uint32_t _reg_PI_MR1_DATA_Fx_CSx[2][CSAB_CNT] = {
+	{
+	 _reg_PI_MR1_DATA_F0_0,
+	 _reg_PI_MR1_DATA_F0_1,
+	 _reg_PI_MR1_DATA_F0_2,
+	 _reg_PI_MR1_DATA_F0_3},
+	{
+	 _reg_PI_MR1_DATA_F1_0,
+	 _reg_PI_MR1_DATA_F1_1,
+	 _reg_PI_MR1_DATA_F1_2,
+	 _reg_PI_MR1_DATA_F1_3}
+};
+
+const uint32_t _reg_PI_MR2_DATA_Fx_CSx[2][CSAB_CNT] = {
+	{
+	 _reg_PI_MR2_DATA_F0_0,
+	 _reg_PI_MR2_DATA_F0_1,
+	 _reg_PI_MR2_DATA_F0_2,
+	 _reg_PI_MR2_DATA_F0_3},
+	{
+	 _reg_PI_MR2_DATA_F1_0,
+	 _reg_PI_MR2_DATA_F1_1,
+	 _reg_PI_MR2_DATA_F1_2,
+	 _reg_PI_MR2_DATA_F1_3}
+};
+
+const uint32_t _reg_PI_MR3_DATA_Fx_CSx[2][CSAB_CNT] = {
+	{
+	 _reg_PI_MR3_DATA_F0_0,
+	 _reg_PI_MR3_DATA_F0_1,
+	 _reg_PI_MR3_DATA_F0_2,
+	 _reg_PI_MR3_DATA_F0_3},
+	{
+	 _reg_PI_MR3_DATA_F1_0,
+	 _reg_PI_MR3_DATA_F1_1,
+	 _reg_PI_MR3_DATA_F1_2,
+	 _reg_PI_MR3_DATA_F1_3}
+};
+
+const uint32_t _reg_PI_MR11_DATA_Fx_CSx[2][CSAB_CNT] = {
+	{
+	 _reg_PI_MR11_DATA_F0_0,
+	 _reg_PI_MR11_DATA_F0_1,
+	 _reg_PI_MR11_DATA_F0_2,
+	 _reg_PI_MR11_DATA_F0_3},
+	{
+	 _reg_PI_MR11_DATA_F1_0,
+	 _reg_PI_MR11_DATA_F1_1,
+	 _reg_PI_MR11_DATA_F1_2,
+	 _reg_PI_MR11_DATA_F1_3}
+};
+
+const uint32_t _reg_PI_MR12_DATA_Fx_CSx[2][CSAB_CNT] = {
+	{
+	 _reg_PI_MR12_DATA_F0_0,
+	 _reg_PI_MR12_DATA_F0_1,
+	 _reg_PI_MR12_DATA_F0_2,
+	 _reg_PI_MR12_DATA_F0_3},
+	{
+	 _reg_PI_MR12_DATA_F1_0,
+	 _reg_PI_MR12_DATA_F1_1,
+	 _reg_PI_MR12_DATA_F1_2,
+	 _reg_PI_MR12_DATA_F1_3}
+};
+
+const uint32_t _reg_PI_MR14_DATA_Fx_CSx[2][CSAB_CNT] = {
+	{
+	 _reg_PI_MR14_DATA_F0_0,
+	 _reg_PI_MR14_DATA_F0_1,
+	 _reg_PI_MR14_DATA_F0_2,
+	 _reg_PI_MR14_DATA_F0_3},
+	{
+	 _reg_PI_MR14_DATA_F1_0,
+	 _reg_PI_MR14_DATA_F1_1,
+	 _reg_PI_MR14_DATA_F1_2,
+	 _reg_PI_MR14_DATA_F1_3}
+};
+
+/*******************************************************************************
+ * regif pll w/a   ( REGIF H3 Ver.2.0 or later/M3-N/V3H WA )
+ *******************************************************************************/
+static void regif_pll_wa(void)
+{
+	uint32_t ch;
+
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		// PLL setting for PHY : H3 Ver.1.x
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_WAIT),
+				   (0x0064U <<
+				    ddr_regdef_lsb(_reg_PHY_PLL_WAIT)));
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL),
+				   ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+						 _reg_PHY_PLL_CTRL));
+
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LP4_BOOT_PLL_CTRL),
+				   ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+						 _reg_PHY_LP4_BOOT_PLL_CTRL));
+
+	} else {
+		/*  PLL setting for PHY : M3-W/M3-N/V3H/H3 Ver.2.0 or later */
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_WAIT),
+				   (0x5064U <<
+				    ddr_regdef_lsb(_reg_PHY_PLL_WAIT)));
+
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL),
+				   (ddrtbl_getval
+				    (_cnf_DDR_PHY_ADR_G_REGSET,
+				     _reg_PHY_PLL_CTRL_TOP) << 16) |
+				   ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+						 _reg_PHY_PLL_CTRL));
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL_CA),
+				   ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+						 _reg_PHY_PLL_CTRL_CA));
+
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LP4_BOOT_PLL_CTRL),
+				   (ddrtbl_getval
+				    (_cnf_DDR_PHY_ADR_G_REGSET,
+				     _reg_PHY_LP4_BOOT_PLL_CTRL_CA) << 16) |
+				   ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+						 _reg_PHY_LP4_BOOT_PLL_CTRL));
+		reg_ddrphy_write_a(ddr_regdef_adr
+				   (_reg_PHY_LP4_BOOT_TOP_PLL_CTRL),
+				   ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+						 _reg_PHY_LP4_BOOT_TOP_PLL_CTRL));
+	}
+
+	reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LPDDR3_CS),
+				_cnf_DDR_PHY_ADR_G_REGSET[ddr_regdef_adr(_reg_PHY_LPDDR3_CS) - DDR_PHY_ADR_G_REGSET_OFS]);
+
+	/* protect register interface */
+	ddrphy_regif_idle();
+	pll3_control(0);
+
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		/*  non */
+	} else {
+		reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_DLL_RST_EN),
+				   (0x01U <<
+				    ddr_regdef_lsb(_reg_PHY_DLL_RST_EN)));
+		ddrphy_regif_idle();
+	}
+
+	/***********************************************************************
+	init start
+	***********************************************************************/
+	/* dbdficnt0:
+	 * dfi_dram_clk_disable=1
+	 * dfi_frequency = 0
+	 * freq_ratio = 01 (2:1)
+	 * init_start =0
+	 */
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F10);
+	dsb_sev();
+
+	/* dbdficnt0:
+	 * dfi_dram_clk_disable=1
+	 * dfi_frequency = 0
+	 * freq_ratio = 01 (2:1)
+	 * init_start =1
+	 */
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F11);
+	dsb_sev();
+
+	foreach_ech(ch)
+	    if (((Boardcnf->phyvalid) & (1U << ch)))
+		while ((mmio_read_32(DBSC_PLL_LOCK(ch)) & 0x1f) != 0x1f) ;
+	dsb_sev();
+}
+
+/*******************************************************************************
+ *	load table data into DDR registers
+ ******************************************************************************/
+static void ddrtbl_load(void)
+{
+	uint32_t i;
+	uint32_t slice;
+	uint32_t csab;
+	uint32_t adr;
+	uint32_t dataL;
+	uint32_t tmp[3];
+	uint16_t dataS;
+
+	/***********************************************************************
+	TIMING REGISTERS
+	***********************************************************************/
+	/* search jedec_spec1 index */
+	for (i = JS1_USABLEC_SPEC_LO; i < JS1_FREQ_TBL_NUM - 1; i++) {
+		if (js1[i].fx3 * 2U * ddr_mbpsdiv >= ddr_mbps * 3U)
+			break;
+	}
+	if (JS1_USABLEC_SPEC_HI < i)
+		js1_ind = JS1_USABLEC_SPEC_HI;
+	else
+		js1_ind = i;
+
+	if (Boardcnf->dbi_en)
+		RL = js1[js1_ind].RLwDBI;
+	else
+		RL = js1[js1_ind].RLwoDBI;
+
+	WL = js1[js1_ind].WL;
+
+	/* calculate jedec_spec2 */
+	_f_scale_js2(ddr_mbps, ddr_mbpsdiv, js2);
+
+	/***********************************************************************
+	PREPARE TBL
+	***********************************************************************/
+	if (Prr_Product == PRR_PRODUCT_H3) {
+		if (Prr_Cut <= PRR_PRODUCT_11) {
+			/*  H3 Ver.1.x */
+			_tblcopy(_cnf_DDR_PHY_SLICE_REGSET,
+				 DDR_PHY_SLICE_REGSET_H3,
+				 DDR_PHY_SLICE_REGSET_NUM_H3);
+			_tblcopy(_cnf_DDR_PHY_ADR_V_REGSET,
+				 DDR_PHY_ADR_V_REGSET_H3,
+				 DDR_PHY_ADR_V_REGSET_NUM_H3);
+			_tblcopy(_cnf_DDR_PHY_ADR_I_REGSET,
+				 DDR_PHY_ADR_I_REGSET_H3,
+				 DDR_PHY_ADR_I_REGSET_NUM_H3);
+			_tblcopy(_cnf_DDR_PHY_ADR_G_REGSET,
+				 DDR_PHY_ADR_G_REGSET_H3,
+				 DDR_PHY_ADR_G_REGSET_NUM_H3);
+			_tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_H3,
+				 DDR_PI_REGSET_NUM_H3);
+
+			DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_H3;
+			DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_H3;
+			DDR_PHY_ADR_I_REGSET_OFS = DDR_PHY_ADR_I_REGSET_OFS_H3;
+			DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_H3;
+			DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_H3;
+			DDR_PHY_SLICE_REGSET_SIZE =
+			    DDR_PHY_SLICE_REGSET_SIZE_H3;
+			DDR_PHY_ADR_V_REGSET_SIZE =
+			    DDR_PHY_ADR_V_REGSET_SIZE_H3;
+			DDR_PHY_ADR_I_REGSET_SIZE =
+			    DDR_PHY_ADR_I_REGSET_SIZE_H3;
+			DDR_PHY_ADR_G_REGSET_SIZE =
+			    DDR_PHY_ADR_G_REGSET_SIZE_H3;
+			DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_H3;
+			DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_H3;
+			DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_H3;
+			DDR_PHY_ADR_I_REGSET_NUM = DDR_PHY_ADR_I_REGSET_NUM_H3;
+			DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_H3;
+			DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_H3;
+
+			DDR_PHY_ADR_I_NUM = 1;
+		} else {
+			/*  H3 Ver.2.0 or later */
+			_tblcopy(_cnf_DDR_PHY_SLICE_REGSET,
+				 DDR_PHY_SLICE_REGSET_H3VER2,
+				 DDR_PHY_SLICE_REGSET_NUM_H3VER2);
+			_tblcopy(_cnf_DDR_PHY_ADR_V_REGSET,
+				 DDR_PHY_ADR_V_REGSET_H3VER2,
+				 DDR_PHY_ADR_V_REGSET_NUM_H3VER2);
+			_tblcopy(_cnf_DDR_PHY_ADR_G_REGSET,
+				 DDR_PHY_ADR_G_REGSET_H3VER2,
+				 DDR_PHY_ADR_G_REGSET_NUM_H3VER2);
+			_tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_H3VER2,
+				 DDR_PI_REGSET_NUM_H3VER2);
+
+			DDR_PHY_SLICE_REGSET_OFS =
+			    DDR_PHY_SLICE_REGSET_OFS_H3VER2;
+			DDR_PHY_ADR_V_REGSET_OFS =
+			    DDR_PHY_ADR_V_REGSET_OFS_H3VER2;
+			DDR_PHY_ADR_G_REGSET_OFS =
+			    DDR_PHY_ADR_G_REGSET_OFS_H3VER2;
+			DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_H3VER2;
+			DDR_PHY_SLICE_REGSET_SIZE =
+			    DDR_PHY_SLICE_REGSET_SIZE_H3VER2;
+			DDR_PHY_ADR_V_REGSET_SIZE =
+			    DDR_PHY_ADR_V_REGSET_SIZE_H3VER2;
+			DDR_PHY_ADR_G_REGSET_SIZE =
+			    DDR_PHY_ADR_G_REGSET_SIZE_H3VER2;
+			DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_H3VER2;
+			DDR_PHY_SLICE_REGSET_NUM =
+			    DDR_PHY_SLICE_REGSET_NUM_H3VER2;
+			DDR_PHY_ADR_V_REGSET_NUM =
+			    DDR_PHY_ADR_V_REGSET_NUM_H3VER2;
+			DDR_PHY_ADR_G_REGSET_NUM =
+			    DDR_PHY_ADR_G_REGSET_NUM_H3VER2;
+			DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_H3VER2;
+
+			DDR_PHY_ADR_I_NUM = 0;
+		}
+	} else if (Prr_Product == PRR_PRODUCT_M3) {
+		/*  M3-W */
+		_tblcopy(_cnf_DDR_PHY_SLICE_REGSET,
+			 DDR_PHY_SLICE_REGSET_M3, DDR_PHY_SLICE_REGSET_NUM_M3);
+		_tblcopy(_cnf_DDR_PHY_ADR_V_REGSET,
+			 DDR_PHY_ADR_V_REGSET_M3, DDR_PHY_ADR_V_REGSET_NUM_M3);
+		_tblcopy(_cnf_DDR_PHY_ADR_I_REGSET,
+			 DDR_PHY_ADR_I_REGSET_M3, DDR_PHY_ADR_I_REGSET_NUM_M3);
+		_tblcopy(_cnf_DDR_PHY_ADR_G_REGSET,
+			 DDR_PHY_ADR_G_REGSET_M3, DDR_PHY_ADR_G_REGSET_NUM_M3);
+		_tblcopy(_cnf_DDR_PI_REGSET,
+			 DDR_PI_REGSET_M3, DDR_PI_REGSET_NUM_M3);
+
+		DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_M3;
+		DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_M3;
+		DDR_PHY_ADR_I_REGSET_OFS = DDR_PHY_ADR_I_REGSET_OFS_M3;
+		DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_M3;
+		DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_M3;
+		DDR_PHY_SLICE_REGSET_SIZE = DDR_PHY_SLICE_REGSET_SIZE_M3;
+		DDR_PHY_ADR_V_REGSET_SIZE = DDR_PHY_ADR_V_REGSET_SIZE_M3;
+		DDR_PHY_ADR_I_REGSET_SIZE = DDR_PHY_ADR_I_REGSET_SIZE_M3;
+		DDR_PHY_ADR_G_REGSET_SIZE = DDR_PHY_ADR_G_REGSET_SIZE_M3;
+		DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_M3;
+		DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_M3;
+		DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_M3;
+		DDR_PHY_ADR_I_REGSET_NUM = DDR_PHY_ADR_I_REGSET_NUM_M3;
+		DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_M3;
+		DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_M3;
+
+		DDR_PHY_ADR_I_NUM = 2;
+	} else {
+		/*  M3-N/V3H */
+		_tblcopy(_cnf_DDR_PHY_SLICE_REGSET,
+			 DDR_PHY_SLICE_REGSET_M3N,
+			 DDR_PHY_SLICE_REGSET_NUM_M3N);
+		_tblcopy(_cnf_DDR_PHY_ADR_V_REGSET, DDR_PHY_ADR_V_REGSET_M3N,
+			 DDR_PHY_ADR_V_REGSET_NUM_M3N);
+		_tblcopy(_cnf_DDR_PHY_ADR_I_REGSET, DDR_PHY_ADR_I_REGSET_M3N,
+			 DDR_PHY_ADR_I_REGSET_NUM_M3N);
+		_tblcopy(_cnf_DDR_PHY_ADR_G_REGSET, DDR_PHY_ADR_G_REGSET_M3N,
+			 DDR_PHY_ADR_G_REGSET_NUM_M3N);
+		_tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_M3N,
+			 DDR_PI_REGSET_NUM_M3N);
+
+		DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_M3N;
+		DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_M3N;
+		DDR_PHY_ADR_I_REGSET_OFS = DDR_PHY_ADR_I_REGSET_OFS_M3N;
+		DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_M3N;
+		DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_M3N;
+		DDR_PHY_SLICE_REGSET_SIZE = DDR_PHY_SLICE_REGSET_SIZE_M3N;
+		DDR_PHY_ADR_V_REGSET_SIZE = DDR_PHY_ADR_V_REGSET_SIZE_M3N;
+		DDR_PHY_ADR_I_REGSET_SIZE = DDR_PHY_ADR_I_REGSET_SIZE_M3N;
+		DDR_PHY_ADR_G_REGSET_SIZE = DDR_PHY_ADR_G_REGSET_SIZE_M3N;
+		DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_M3N;
+		DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_M3N;
+		DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_M3N;
+		DDR_PHY_ADR_I_REGSET_NUM = DDR_PHY_ADR_I_REGSET_NUM_M3N;
+		DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_M3N;
+		DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_M3N;
+
+		DDR_PHY_ADR_I_NUM = 2;
+	}
+
+	/***********************************************************************
+	PLL CODE CHANGE
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut == PRR_PRODUCT_11)) {
+		ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PLL_CTRL,
+			      0x1142);
+		ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET,
+			      _reg_PHY_LP4_BOOT_PLL_CTRL, 0x1142);
+	}
+
+	/***********************************************************************
+	on fly gate adjust
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut == PRR_PRODUCT_10)) {
+		ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET,
+			      _reg_ON_FLY_GATE_ADJUST_EN, 0x00);
+	}
+
+	/***********************************************************************
+	Adjust PI parameters
+	***********************************************************************/
+#ifdef _def_LPDDR4_ODT
+	for (i = 0; i < 2; i++) {
+		for (csab = 0; csab < CSAB_CNT; csab++) {
+			ddrtbl_setval(_cnf_DDR_PI_REGSET,
+				      _reg_PI_MR11_DATA_Fx_CSx[i][csab],
+				      _def_LPDDR4_ODT);
+		}
+	}
+#endif /* _def_LPDDR4_ODT */
+
+#ifdef _def_LPDDR4_VREFCA
+	for (i = 0; i < 2; i++) {
+		for (csab = 0; csab < CSAB_CNT; csab++) {
+			ddrtbl_setval(_cnf_DDR_PI_REGSET,
+				      _reg_PI_MR12_DATA_Fx_CSx[i][csab],
+				      _def_LPDDR4_VREFCA);
+		}
+	}
+#endif /* _def_LPDDR4_VREFCA */
+	if ((Prr_Product == PRR_PRODUCT_M3N)
+	    || (Prr_Product == PRR_PRODUCT_V3H)) {
+		js2[JS2_tIEdly] = _f_scale(ddr_mbps, ddr_mbpsdiv, 7000, 0) + 7U;
+		if (js2[JS2_tIEdly] > (RL))
+			js2[JS2_tIEdly] = RL;
+	} else if ((Prr_Product == PRR_PRODUCT_H3)
+		   && (Prr_Cut > PRR_PRODUCT_11)) {
+		js2[JS2_tIEdly] = _f_scale(ddr_mbps, ddr_mbpsdiv, 9000, 0) + 4U;
+	} else if ((Prr_Product == PRR_PRODUCT_H3)
+		   && (Prr_Cut <= PRR_PRODUCT_11)) {
+		js2[JS2_tIEdly] = _f_scale(ddr_mbps, ddr_mbpsdiv, 10000, 0);
+	}
+
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut > PRR_PRODUCT_11))
+	    || (Prr_Product == PRR_PRODUCT_M3N)
+	    || (Prr_Product == PRR_PRODUCT_V3H)) {
+		if ((js2[JS2_tIEdly]) >= 0x1e)
+			dataS = 0x1e;
+		else
+			dataS = js2[JS2_tIEdly];
+	} else {
+		if ((js2[JS2_tIEdly]) >= 0x0e)
+			dataS = 0x0e;
+		else
+			dataS = js2[JS2_tIEdly];
+	}
+
+	ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_RDDATA_EN_DLY, dataS);
+	ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_RDDATA_EN_TSEL_DLY,
+		      (dataS - 2));
+	if ((Prr_Product == PRR_PRODUCT_M3N)
+	    || (Prr_Product == PRR_PRODUCT_V3H)) {
+		ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET,
+			      _reg_PHY_RDDATA_EN_OE_DLY, dataS);
+	}
+	ddrtbl_setval(_cnf_DDR_PI_REGSET, _reg_PI_RDLAT_ADJ_F1, RL - dataS);
+
+	if (ddrtbl_getval
+	    (_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_WRITE_PATH_LAT_ADD)) {
+		dataL = WL - 1;
+	} else {
+		dataL = WL;
+	}
+	ddrtbl_setval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_ADJ_F1, dataL - 2);
+	ddrtbl_setval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_F1, dataL);
+
+	if (Boardcnf->dbi_en) {
+		ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DBI_MODE,
+			      0x01);
+		ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET,
+			      _reg_PHY_WDQLVL_DATADM_MASK, 0x000);
+	} else {
+		ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DBI_MODE,
+			      0x00);
+		ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET,
+			      _reg_PHY_WDQLVL_DATADM_MASK, 0x100);
+	}
+
+	tmp[0] = js1[js1_ind].MR1;
+	tmp[1] = js1[js1_ind].MR2;
+	dataL = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_MR3_DATA_F1_0);
+	if (Boardcnf->dbi_en)
+		tmp[2] = dataL | 0xc0;
+	else
+		tmp[2] = dataL & (~0xc0);
+
+	for (i = 0; i < 2; i++) {
+		for (csab = 0; csab < CSAB_CNT; csab++) {
+			ddrtbl_setval(_cnf_DDR_PI_REGSET,
+				      _reg_PI_MR1_DATA_Fx_CSx[i][csab], tmp[0]);
+			ddrtbl_setval(_cnf_DDR_PI_REGSET,
+				      _reg_PI_MR2_DATA_Fx_CSx[i][csab], tmp[1]);
+			ddrtbl_setval(_cnf_DDR_PI_REGSET,
+				      _reg_PI_MR3_DATA_Fx_CSx[i][csab], tmp[2]);
+		}
+	}
+
+	/***********************************************************************
+	 DDRPHY INT START
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		/*  non */
+	} else {
+		regif_pll_wa();
+	}
+
+	/***********************************************************************
+	FREQ_SEL_MULTICAST & PER_CS_TRAINING_MULTICAST SET (for safety)
+	***********************************************************************/
+	reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN),
+		(0x01U << ddr_regdef_lsb(_reg_PHY_FREQ_SEL_MULTICAST_EN)));
+	ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_MULTICAST_EN, 0x01);
+
+	/***********************************************************************
+	SET DATA SLICE TABLE
+	***********************************************************************/
+	for (slice = 0; slice < SLICE_CNT; slice++) {
+		adr =
+		    DDR_PHY_SLICE_REGSET_OFS +
+		    DDR_PHY_SLICE_REGSET_SIZE * slice;
+		for (i = 0; i < DDR_PHY_SLICE_REGSET_NUM; i++) {
+			reg_ddrphy_write_a(adr + i,
+					   _cnf_DDR_PHY_SLICE_REGSET[i]);
+		}
+	}
+
+	/***********************************************************************
+	SET ADR SLICE TABLE
+	***********************************************************************/
+	adr = DDR_PHY_ADR_V_REGSET_OFS;
+	for (i = 0; i < DDR_PHY_ADR_V_REGSET_NUM; i++) {
+		reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_ADR_V_REGSET[i]);
+	}
+
+	if (((Prr_Product == PRR_PRODUCT_M3)
+	    || (Prr_Product == PRR_PRODUCT_M3N)) &&
+	    ((0x00ffffff & (uint32_t)((Boardcnf->ch[0].ca_swap) >> 40))
+	    != 0x00)) {
+		adr = DDR_PHY_ADR_I_REGSET_OFS + DDR_PHY_ADR_I_REGSET_SIZE;
+		for (i = 0; i < DDR_PHY_ADR_V_REGSET_NUM; i++) {
+			reg_ddrphy_write_a(adr + i,
+					   _cnf_DDR_PHY_ADR_V_REGSET[i]);
+		}
+		ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_ADR_DISABLE, 0x02);
+		DDR_PHY_ADR_I_NUM -= 1;
+		ddr_phycaslice = 1;
+
+#ifndef _def_LPDDR4_ODT
+		for (i = 0; i < 2; i++) {
+			for (csab = 0; csab < CSAB_CNT; csab++) {
+				ddrtbl_setval(_cnf_DDR_PI_REGSET,
+					      _reg_PI_MR11_DATA_Fx_CSx[i][csab],
+					      0x66);
+			}
+		}
+#endif/* _def_LPDDR4_ODT */
+	} else {
+		ddr_phycaslice = 0;
+	}
+
+	if (DDR_PHY_ADR_I_NUM > 0) {
+		for (slice = 0; slice < DDR_PHY_ADR_I_NUM; slice++) {
+			adr =
+			    DDR_PHY_ADR_I_REGSET_OFS +
+			    DDR_PHY_ADR_I_REGSET_SIZE * slice;
+			for (i = 0; i < DDR_PHY_ADR_I_REGSET_NUM; i++) {
+				reg_ddrphy_write_a(adr + i,
+						   _cnf_DDR_PHY_ADR_I_REGSET
+						   [i]);
+			}
+		}
+	}
+
+	/***********************************************************************
+	SET ADRCTRL SLICE TABLE
+	***********************************************************************/
+	adr = DDR_PHY_ADR_G_REGSET_OFS;
+	for (i = 0; i < DDR_PHY_ADR_G_REGSET_NUM; i++) {
+		reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_ADR_G_REGSET[i]);
+	}
+
+	/***********************************************************************
+	SET PI REGISTERS
+	***********************************************************************/
+	adr = DDR_PI_REGSET_OFS;
+	for (i = 0; i < DDR_PI_REGSET_NUM; i++) {
+		reg_ddrphy_write_a(adr + i, _cnf_DDR_PI_REGSET[i]);
+	}
+}
+
+/*******************************************************************************
+ *	CONFIGURE DDR REGISTERS
+ ******************************************************************************/
+static void ddr_config_sub(void)
+{
+	uint32_t i;
+	uint32_t ch, slice;
+	uint32_t dataL;
+	uint32_t tmp;
+	uint8_t high_byte[SLICE_CNT];
+	const uint32_t _par_CALVL_DEVICE_MAP = 1;
+	foreach_vch(ch) {
+	/***********************************************************************
+	BOARD SETTINGS (DQ,DM,VREF_DRIVING)
+	***********************************************************************/
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			high_byte[slice] =
+			    (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) % 2;
+			ddr_setval_s(ch, slice, _reg_PHY_DQ_DM_SWIZZLE0,
+				     Boardcnf->ch[ch].dq_swap[slice]);
+			ddr_setval_s(ch, slice, _reg_PHY_DQ_DM_SWIZZLE1,
+				     Boardcnf->ch[ch].dm_swap[slice]);
+			if (high_byte[slice]) {
+				/* HIGHER 16 BYTE */
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_CALVL_VREF_DRIVING_SLICE,
+					     0x00);
+			} else {
+				/* LOWER 16 BYTE */
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_CALVL_VREF_DRIVING_SLICE,
+					     0x01);
+			}
+		}
+
+	/***********************************************************************
+		BOARD SETTINGS (CA,ADDR_SEL)
+	***********************************************************************/
+		dataL = (0x00ffffff & (uint32_t)(Boardcnf->ch[ch].ca_swap)) |
+			0x00888888;
+
+		/* --- ADR_CALVL_SWIZZLE --- */
+		if (Prr_Product == PRR_PRODUCT_M3) {
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_0, dataL);
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_0,
+				   0x00000000);
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_1, dataL);
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_1,
+				   0x00000000);
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_DEVICE_MAP,
+				   _par_CALVL_DEVICE_MAP);
+		} else {
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0, dataL);
+			ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1, 0x00000000);
+			ddr_setval(ch, _reg_PHY_CALVL_DEVICE_MAP,
+				   _par_CALVL_DEVICE_MAP);
+		}
+
+		/* --- ADR_ADDR_SEL --- */
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut > PRR_PRODUCT_11)) {
+			dataL = 0x00FFFFFF & Boardcnf->ch[ch].ca_swap;
+		} else {
+			dataL = 0;
+			tmp = Boardcnf->ch[ch].ca_swap;
+			for (i = 0; i < 6; i++) {
+				dataL |= ((tmp & 0x0f) << (i * 5));
+				tmp = tmp >> 4;
+			}
+		}
+		ddr_setval(ch, _reg_PHY_ADR_ADDR_SEL, dataL);
+		if (ddr_phycaslice == 1) {
+			/* ----------- adr slice2 swap ----------- */
+			tmp  = (uint32_t)((Boardcnf->ch[ch].ca_swap) >> 40);
+			dataL = (tmp & 0x00ffffff) | 0x00888888;
+
+			/* --- ADR_CALVL_SWIZZLE --- */
+			if (Prr_Product == PRR_PRODUCT_M3) {
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE0_0, dataL);
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE1_0,
+					     0x00000000);
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE0_1, dataL);
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE1_1,
+					     0x00000000);
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_DEVICE_MAP,
+					     _par_CALVL_DEVICE_MAP);
+			} else {
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE0, dataL);
+				ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE1,
+					     0x00000000);
+				ddr_setval_s(ch, 2, _reg_PHY_CALVL_DEVICE_MAP,
+					     _par_CALVL_DEVICE_MAP);
+			}
+
+			/* --- ADR_ADDR_SEL --- */
+			dataL = 0;
+			for (i = 0; i < 6; i++) {
+				dataL |= ((tmp & 0x0f) << (i * 5));
+				tmp = tmp >> 4;
+			}
+
+			ddr_setval_s(ch, 2, _reg_PHY_ADR_ADDR_SEL, dataL);
+		}
+
+	/***********************************************************************
+		BOARD SETTINGS (BYTE_ORDER_SEL)
+	***********************************************************************/
+		if (Prr_Product == PRR_PRODUCT_M3) {
+			/* --- DATA_BYTE_SWAP --- */
+			dataL = 0;
+			tmp = Boardcnf->ch[ch].dqs_swap;
+			for (i = 0; i < 4; i++) {
+				dataL |= ((tmp & 0x03) << (i * 2));
+				tmp = tmp >> 4;
+			}
+		} else {
+			/* --- DATA_BYTE_SWAP --- */
+			dataL = Boardcnf->ch[ch].dqs_swap;
+			ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_EN, 0x01);
+			ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE0,
+				   (dataL) & 0x0f);
+			ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE1,
+				   (dataL >> 4 * 1) & 0x0f);
+			ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE2,
+				   (dataL >> 4 * 2) & 0x0f);
+			ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE3,
+				   (dataL >> 4 * 3) & 0x0f);
+
+			ddr_setval(ch, _reg_PHY_DATA_BYTE_ORDER_SEL_HIGH, 0x00);
+		}
+		ddr_setval(ch, _reg_PHY_DATA_BYTE_ORDER_SEL, dataL);
+	}
+}
+
+static void get_ca_swizzle(uint32_t ch, uint32_t ddr_csn, uint32_t * p_swz)
+{
+	uint32_t slice;
+	uint32_t tmp;
+	uint32_t tgt;
+	if (ddr_csn / 2) {
+		tgt = 3;
+	} else {
+		tgt = 1;
+	}
+
+	for (slice = 0; slice < SLICE_CNT; slice++) {
+		tmp = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+		if (tgt == tmp)
+			break;
+	}
+	tmp = 0x00FFFFFF & Boardcnf->ch[ch].ca_swap;
+	if (slice % 2)
+		tmp |= 0x00888888;
+	*p_swz = tmp;
+}
+
+static void ddr_config_sub_h3v1x(void)
+{
+	uint32_t ch, slice;
+	uint32_t dataL;
+	uint32_t tmp;
+	uint8_t high_byte[SLICE_CNT];
+	uint32_t ca_swizzle;
+	uint32_t ca;
+	uint32_t csmap;
+	uint32_t o_inv;
+	uint32_t inv;
+	uint32_t bit_soc;
+	uint32_t bit_mem;
+	uint32_t j;
+
+	const uint8_t o_mr15 = 0x55;
+	const uint8_t o_mr20 = 0x55;
+	const uint16_t o_mr32_mr40 = 0x5a3c;
+
+	foreach_vch(ch) {
+	/***********************************************************************
+		BOARD SETTINGS (DQ,DM,VREF_DRIVING)
+	***********************************************************************/
+		csmap = 0;
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			tmp = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+			high_byte[slice] = tmp % 2;
+			if (tmp == 1 && (slice >= 2))
+				csmap |= 0x05;
+			if (tmp == 3 && (slice >= 2))
+				csmap |= 0x50;
+			ddr_setval_s(ch, slice, _reg_PHY_DQ_SWIZZLING,
+				     Boardcnf->ch[ch].dq_swap[slice]);
+			if (high_byte[slice]) {
+				/* HIGHER 16 BYTE */
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_CALVL_VREF_DRIVING_SLICE,
+					     0x00);
+			} else {
+				/* LOWER 16 BYTE */
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_CALVL_VREF_DRIVING_SLICE,
+					     0x01);
+			}
+		}
+	/***********************************************************************
+		BOARD SETTINGS (CA,ADDR_SEL)
+	***********************************************************************/
+		ca = 0x00FFFFFF & Boardcnf->ch[ch].ca_swap;
+		ddr_setval(ch, _reg_PHY_ADR_ADDR_SEL, ca);
+		ddr_setval(ch, _reg_PHY_CALVL_CS_MAP, csmap);
+
+		get_ca_swizzle(ch, 0, &ca_swizzle);
+
+		ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_0, ca_swizzle);
+		ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_0, 0x00000000);
+		ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_1, 0x00000000);
+		ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_1, 0x00000000);
+		ddr_setval(ch, _reg_PHY_ADR_CALVL_DEVICE_MAP, 0x01);
+
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			ddr_setval_s(ch, slice, _reg_PI_RDLVL_PATTERN_NUM,
+				     0x01);
+			ddr_setval_s(ch, slice, _reg_PI_RDLVL_PATTERN_START,
+				     0x08);
+
+			if (high_byte[slice])
+				o_inv = o_mr20;
+			else
+				o_inv = o_mr15;
+
+			tmp = Boardcnf->ch[ch].dq_swap[slice];
+			inv = 0;
+			j = 0;
+			for (bit_soc = 0; bit_soc < 8; bit_soc++) {
+				bit_mem = (tmp >> (4 * bit_soc)) & 0x0f;
+				j |= (1U << bit_mem);
+				if (o_inv & (1U << bit_mem))
+					inv |= (1U << bit_soc);
+			}
+			dataL = o_mr32_mr40;
+			if (!high_byte[slice])
+				dataL |= (inv << 24);
+			if (high_byte[slice])
+				dataL |= (inv << 16);
+			ddr_setval_s(ch, slice, _reg_PHY_LP4_RDLVL_PATT8,
+				     dataL);
+		}
+	}
+}
+
+static void ddr_config(void)
+{
+	int32_t i;
+	uint32_t ch, slice;
+	uint32_t dataL;
+	uint32_t tmp;
+	int8_t _adj;
+	int16_t adj;
+	uint32_t dq;
+	union {
+		uint32_t ui32[4];
+		uint8_t ui8[16];
+	} patt;
+	uint16_t patm;
+
+	/***********************************************************************
+	configure ddrphy registers
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		ddr_config_sub_h3v1x();
+	} else {
+		ddr_config_sub();	/*  H3 Ver.2.0 or later/M3-N/V3H is same as M3-W */
+	}
+
+	/***********************************************************************
+	WDQ_USER_PATT
+	***********************************************************************/
+	foreach_vch(ch) {
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			patm = 0;
+			for (i = 0; i < 16; i++) {
+				tmp = Boardcnf->ch[ch].wdqlvl_patt[i];
+				patt.ui8[i] = tmp & 0xff;
+				if (tmp & 0x100)
+					patm |= (1U << i);
+			}
+			ddr_setval_s(ch, slice, _reg_PHY_USER_PATT0,
+				     patt.ui32[0]);
+			ddr_setval_s(ch, slice, _reg_PHY_USER_PATT1,
+				     patt.ui32[1]);
+			ddr_setval_s(ch, slice, _reg_PHY_USER_PATT2,
+				     patt.ui32[2]);
+			ddr_setval_s(ch, slice, _reg_PHY_USER_PATT3,
+				     patt.ui32[3]);
+			ddr_setval_s(ch, slice, _reg_PHY_USER_PATT4, patm);
+		}
+	}
+
+	/***********************************************************************
+	CACS DLY
+	***********************************************************************/
+	dataL = Boardcnf->cacs_dly + _f_scale_adj(Boardcnf->cacs_dly_adj);
+	reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN), 0x00U);
+	foreach_vch(ch) {
+		for (i = 0; i < (_reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM - 4); i++) {
+			adj = _f_scale_adj(Boardcnf->ch[ch].cacs_adj[i]);
+			ddrtbl_setval(_cnf_DDR_PHY_ADR_V_REGSET,
+				      _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i],
+				      dataL + adj);
+			reg_ddrphy_write(ch,
+					ddr_regdef_adr(
+					_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]),
+					_cnf_DDR_PHY_ADR_V_REGSET[
+					ddr_regdef_adr(
+					_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) -
+					DDR_PHY_ADR_V_REGSET_OFS]);
+		}
+
+		for (i = (_reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM - 4);
+		     i < _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM; i++) {
+			adj = _f_scale_adj(Boardcnf->ch[ch].cacs_adj[i]);
+			ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET,
+				      _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i],
+				      dataL + adj);
+			reg_ddrphy_write(ch,
+					ddr_regdef_adr(
+					_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]),
+					_cnf_DDR_PHY_ADR_G_REGSET[
+					ddr_regdef_adr(
+					_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) -
+					DDR_PHY_ADR_G_REGSET_OFS]);
+		}
+
+		if (ddr_phycaslice == 1) {
+			for (i = 0; i < 6; i++) {
+				adj = _f_scale_adj(
+					Boardcnf->ch[ch].cacs_adj[
+					i + _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM]);
+				ddrtbl_setval(_cnf_DDR_PHY_ADR_V_REGSET,
+					      _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i],
+					      dataL + adj);
+				reg_ddrphy_write(ch,
+					ddr_regdef_adr(
+					_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) +
+					0x0100,
+					_cnf_DDR_PHY_ADR_V_REGSET[
+					ddr_regdef_adr(
+					_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) -
+					DDR_PHY_ADR_V_REGSET_OFS]);
+			}
+		}
+	}
+
+	reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN),
+		(0x01U << ddr_regdef_lsb(_reg_PHY_FREQ_SEL_MULTICAST_EN)));
+
+	/***********************************************************************
+	WDQDM DLY
+	***********************************************************************/
+	dataL = Boardcnf->dqdm_dly_w;
+	foreach_vch(ch) {
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			for (i = 0; i <= 8; i++) {
+				dq = slice * 8 + i;
+				if (i == 8)
+					_adj = Boardcnf->ch[ch].dm_adj_w[slice];
+				else
+					_adj = Boardcnf->ch[ch].dq_adj_w[dq];
+				adj = _f_scale_adj(_adj);
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_CLK_WRX_SLAVE_DELAY[i],
+					     dataL + adj);
+			}
+		}
+	}
+
+	/***********************************************************************
+	RDQDM DLY
+	***********************************************************************/
+	dataL = Boardcnf->dqdm_dly_r;
+	foreach_vch(ch) {
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			for (i = 0; i <= 8; i++) {
+				dq = slice * 8 + i;
+				if (i == 8)
+					_adj = Boardcnf->ch[ch].dm_adj_r[slice];
+				else
+					_adj = Boardcnf->ch[ch].dq_adj_r[dq];
+				adj = _f_scale_adj(_adj);
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY
+					     [i], dataL + adj);
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY
+					     [i], dataL + adj);
+			}
+		}
+	}
+}
+
+/*******************************************************************************
+ *	DBSC register setting functions
+ ******************************************************************************/
+static void dbsc_regset_pre(void)
+{
+	uint32_t ch, csab;
+	uint32_t dataL;
+
+	/***********************************************************************
+	PRIMARY SETTINGS
+	***********************************************************************/
+	/* LPDDR4, BL=16, DFI interface */
+	mmio_write_32(DBSC_DBKIND, 0x0000000a);
+	mmio_write_32(DBSC_DBBL, 0x00000002);
+	mmio_write_32(DBSC_DBPHYCONF0, 0x00000001);
+
+	/* FREQRATIO=2 */
+	mmio_write_32(DBSC_DBSYSCONF1, 0x00000002);
+
+	/* Chanel map (H3 Ver.1.x) */
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+		mmio_write_32(DBSC_DBSCHCNT1, 0x00001010);
+
+	/* DRAM SIZE REGISTER:
+	 * set all ranks as density=0(4Gb) for PHY initialization
+	 */
+	foreach_vch(ch)
+	    for (csab = 0; csab < 4; csab++)
+		mmio_write_32(DBSC_DBMEMCONF(ch, csab), DBMEMCONF_REGD(0));
+
+	if (Prr_Product == PRR_PRODUCT_M3) {
+		dataL = 0xe4e4e4e4;
+		foreach_ech(ch) {
+			if ((ddr_phyvalid & (1U << ch)))
+				dataL = (dataL & (~(0x000000FF << (ch * 8))))
+				    | (((Boardcnf->ch[ch].dqs_swap & 0x0003)
+					| ((Boardcnf->ch[ch].dqs_swap & 0x0030)
+					   >> 2)
+					| ((Boardcnf->ch[ch].dqs_swap & 0x0300)
+					   >> 4)
+					| ((Boardcnf->ch[ch].dqs_swap & 0x3000)
+					   >> 6)) << (ch * 8));
+		}
+		mmio_write_32(DBSC_DBBSWAP, dataL);
+	}
+}
+
+static void dbsc_regset(void)
+{
+	int32_t i;
+	uint32_t ch;
+	uint32_t dataL;
+	uint32_t dataL2;
+	uint32_t tmp[4];
+
+	/* RFC */
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut == PRR_PRODUCT_20)
+	    && (max_density == 0)) {
+		js2[JS2_tRFCab] =
+		    _f_scale(ddr_mbps, ddr_mbpsdiv,
+			     1UL * jedec_spec2_tRFC_ab[1] * 1000, 0);
+	} else {
+		js2[JS2_tRFCab] =
+		    _f_scale(ddr_mbps, ddr_mbpsdiv,
+			     1UL * jedec_spec2_tRFC_ab[max_density] *
+			     1000, 0);
+	}
+
+	/* DBTR0.CL  : RL */
+	mmio_write_32(DBSC_DBTR(0), RL);
+
+	/* DBTR1.CWL : WL */
+	mmio_write_32(DBSC_DBTR(1), WL);
+
+	/* DBTR2.AL  : 0 */
+	mmio_write_32(DBSC_DBTR(2), 0);
+
+	/* DBTR3.TRCD: tRCD */
+	mmio_write_32(DBSC_DBTR(3), js2[JS2_tRCD]);
+
+	/* DBTR4.TRPA,TRP: tRPab,tRPpb */
+	mmio_write_32(DBSC_DBTR(4), (js2[JS2_tRPab] << 16) | js2[JS2_tRPpb]);
+
+	/* DBTR5.TRC : use tRCpb */
+	mmio_write_32(DBSC_DBTR(5), js2[JS2_tRCpb]);
+
+	/* DBTR6.TRAS : tRAS */
+	mmio_write_32(DBSC_DBTR(6), js2[JS2_tRAS]);
+
+	/* DBTR7.TRRD : tRRD */
+	mmio_write_32(DBSC_DBTR(7), (js2[JS2_tRRD] << 16) | js2[JS2_tRRD]);
+
+	/* DBTR8.TFAW : tFAW */
+	mmio_write_32(DBSC_DBTR(8), js2[JS2_tFAW]);
+
+	/* DBTR9.TRDPR : tRTP */
+	mmio_write_32(DBSC_DBTR(9), js2[JS2_tRTP]);
+
+	/* DBTR10.TWR : nWR */
+	mmio_write_32(DBSC_DBTR(10), js1[js1_ind].nWR);
+
+	/* DBTR11.TRDWR : RL + tDQSCK + BL/2 + Rounddown(tRPST) - WL + tWPRE */
+	mmio_write_32(DBSC_DBTR(11),
+		      RL + js2[JS2_tDQSCK] + (16 / 2) + 1 - WL + 2 + 2);
+
+	/* DBTR12.TWRRD : WL + 1 + BL/2 + tWTR */
+	dataL = WL + 1 + (16 / 2) + js2[JS2_tWTR];
+	mmio_write_32(DBSC_DBTR(12), (dataL << 16) | dataL);
+
+	/* DBTR13.TRFCAB : tRFCab */
+	mmio_write_32(DBSC_DBTR(13), (js2[JS2_tRFCab]));
+
+	/* DBTR14.TCKEHDLL,tCKEH : tCKEHCMD,tCKEHCMD */
+	mmio_write_32(DBSC_DBTR(14),
+		      (js2[JS2_tCKEHCMD] << 16) | (js2[JS2_tCKEHCMD]));
+
+	/* DBTR15.TCKESR,TCKEL : tSR,tCKELPD */
+	mmio_write_32(DBSC_DBTR(15), (js2[JS2_tSR] << 16) | (js2[JS2_tCKELPD]));
+
+	/* DBTR16 */
+	/* WDQL : tphy_wrlat + tphy_wrdata */
+	tmp[0] = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_F1);
+	/* DQENLTNCY : tphy_wrlat = WL-2 : PHY_WRITE_PATH_LAT_ADD == 0
+	 *             tphy_wrlat = WL-3 : PHY_WRITE_PATH_LAT_ADD != 0
+	 */
+	tmp[1] = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_ADJ_F1);
+	/* DQL : tphy_rdlat + trdata_en */
+	/* it is not important for dbsc */
+	tmp[2] = RL + 16;
+	/* DQIENLTNCY : trdata_en */
+	tmp[3] = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_RDLAT_ADJ_F1) - 1;
+	mmio_write_32(DBSC_DBTR(16),
+		      (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]);
+
+	/* DBTR24 */
+	/* WRCSLAT = WRLAT -5 */
+	tmp[0] -= 5;
+	/* WRCSGAP = 5 */
+	tmp[1] = 5;
+	/* RDCSLAT = RDLAT_ADJ +2 */
+	if (Prr_Product == PRR_PRODUCT_M3) {
+		tmp[2] = tmp[3];
+	} else {
+		tmp[2] = tmp[3] + 2;
+	}
+	/* RDCSGAP = 6 */
+	if (Prr_Product == PRR_PRODUCT_M3) {
+		tmp[3] = 4;
+	} else {
+		tmp[3] = 6;
+	}
+	mmio_write_32(DBSC_DBTR(24),
+		      (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]);
+
+	/* DBTR17.TMODRD,TMOD,TRDMR: tMRR,tMRD,(0) */
+	mmio_write_32(DBSC_DBTR(17),
+		      (js2[JS2_tMRR] << 24) | (js2[JS2_tMRD] << 16));
+
+	/* DBTR18.RODTL, RODTA, WODTL, WODTA : do not use in LPDDR4 */
+	mmio_write_32(DBSC_DBTR(18), 0);
+
+	/* DBTR19.TZQCL, TZQCS : do not use in LPDDR4 */
+	mmio_write_32(DBSC_DBTR(19), 0);
+
+	/* DBTR20.TXSDLL, TXS : tRFCab+tCKEHCMD */
+	dataL = js2[JS2_tRFCab] + js2[JS2_tCKEHCMD];
+	mmio_write_32(DBSC_DBTR(20), (dataL << 16) | dataL);
+
+	/* DBTR21.TCCD */
+	/* DBTR23.TCCD */
+	/* H3 Ver.1.0 cannot use TBTR23 feature */
+	if (ddr_tccd == 8 &&
+	    !((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_10))
+	    ) {
+		dataL = 8;
+		mmio_write_32(DBSC_DBTR(21), (dataL << 16) | dataL);
+		mmio_write_32(DBSC_DBTR(23), 0x00000002);
+	} else if (ddr_tccd <= 11) {
+		dataL = 11;
+		mmio_write_32(DBSC_DBTR(21), (dataL << 16) | dataL);
+		mmio_write_32(DBSC_DBTR(23), 0x00000000);
+	} else {
+		dataL = ddr_tccd;
+		mmio_write_32(DBSC_DBTR(21), (dataL << 16) | dataL);
+		mmio_write_32(DBSC_DBTR(23), 0x00000000);
+	}
+
+	/* DBTR22.ZQLAT : */
+	dataL = js2[JS2_tZQCALns] * 100;	/*  1000 * 1000 ps */
+	dataL = (dataL << 16) | (js2[JS2_tZQLAT] + 24 + 20);
+	mmio_write_32(DBSC_DBTR(22), dataL);
+
+	/* DBTR25 : do not use in LPDDR4 */
+	mmio_write_32(DBSC_DBTR(25), 0);
+
+	/* DBRNK : */
+	/*
+	 * DBSC_DBRNK2 rkrr
+	 * DBSC_DBRNK3 rkrw
+	 * DBSC_DBRNK4 rkwr
+	 * DBSC_DBRNK5 rkww
+	 */
+#define _par_DBRNK_VAL		(0x7007)
+
+	for (i = 0; i < 4; i++) {
+		dataL = (_par_DBRNK_VAL >> (i * 4)) & 0x0f;
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut > PRR_PRODUCT_11) && (i == 0)) {
+			dataL += 1;
+		}
+		dataL2 = 0;
+		foreach_vch(ch) {
+			dataL2 = dataL2 | (dataL << (4 * ch));
+		}
+		mmio_write_32(DBSC_DBRNK(2 + i), dataL2);
+	}
+	mmio_write_32(DBSC_DBADJ0, 0x00000000);
+
+	/***********************************************************************
+	timing registers for Scheduler
+	***********************************************************************/
+	/* SCFCTST0 */
+	/* SCFCTST0 ACT-ACT */
+	tmp[3] = 1UL * js2[JS2_tRCpb] * 800 * ddr_mbpsdiv / ddr_mbps;
+	/* SCFCTST0 RDA-ACT */
+	tmp[2] =
+	    1UL * ((16 / 2) + js2[JS2_tRTP] - 8 +
+		   js2[JS2_tRPpb]) * 800 * ddr_mbpsdiv / ddr_mbps;
+	/* SCFCTST0 WRA-ACT */
+	tmp[1] =
+	    1UL * (WL + 1 + (16 / 2) +
+		   js1[js1_ind].nWR) * 800 * ddr_mbpsdiv / ddr_mbps;
+	/* SCFCTST0 PRE-ACT */
+	tmp[0] = 1UL * js2[JS2_tRPpb];
+	mmio_write_32(DBSC_SCFCTST0,
+		      (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]);
+
+	/* SCFCTST1 */
+	/* SCFCTST1 RD-WR */
+	tmp[3] =
+	    1UL * (mmio_read_32(DBSC_DBTR(11)) & 0xff) * 800 * ddr_mbpsdiv /
+	    ddr_mbps;
+	/* SCFCTST1 WR-RD */
+	tmp[2] =
+	    1UL * (mmio_read_32(DBSC_DBTR(12)) & 0xff) * 800 * ddr_mbpsdiv /
+	    ddr_mbps;
+	/* SCFCTST1 ACT-RD/WR */
+	tmp[1] = 1UL * js2[JS2_tRCD] * 800 * ddr_mbpsdiv / ddr_mbps;
+	/* SCFCTST1 ASYNCOFS */
+	tmp[0] = 12;
+	mmio_write_32(DBSC_SCFCTST1,
+		      (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]);
+
+	/* DBSCHRW1 */
+	/* DBSCHRW1 SCTRFCAB */
+	tmp[0] = 1UL * js2[JS2_tRFCab] * 800 * ddr_mbpsdiv / ddr_mbps;
+	dataL = (((mmio_read_32(DBSC_DBTR(16)) & 0x00FF0000) >> 16)
+		 + (mmio_read_32(DBSC_DBTR(22)) & 0x0000FFFF)
+		 + (0x28 * 2)) * 400 * 2 * ddr_mbpsdiv / ddr_mbps + 7;
+	if (tmp[0] < dataL)
+		tmp[0] = dataL;
+
+	if ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut < PRR_PRODUCT_30)) {
+		mmio_write_32(DBSC_DBSCHRW1, tmp[0]
+			+ ((mmio_read_32(DBSC_DBTR(22)) & 0x0000FFFF)
+			* 400 * 2 * ddr_mbpsdiv +(ddr_mbps-1))/ddr_mbps - 3);
+	} else {
+		mmio_write_32(DBSC_DBSCHRW1, tmp[0]
+			+ ((mmio_read_32(DBSC_DBTR(22)) & 0x0000FFFF)
+			* 400 * 2 * ddr_mbpsdiv +(ddr_mbps-1))/ddr_mbps);
+	}
+
+	/***********************************************************************
+	QOS and CAM
+	***********************************************************************/
+#ifdef ddr_qos_init_setting	/*  only for non qos_init */
+	/*wbkwait(0004), wbkmdhi(4,2),wbkmdlo(1,8) */
+	mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218);
+	/*0(fillunit),8(dirtymax),4(dirtymin) */
+	mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4);
+	/*stop_tolerance */
+	mmio_write_32(DBSC_DBSCHRW0, 0x22421111);
+	/*rd-wr/wr-rd toggle priority */
+	mmio_write_32(DBSC_SCFCTST2, 0x012F1123);
+	mmio_write_32(DBSC_DBSCHSZ0, 0x00000001);
+	mmio_write_32(DBSC_DBSCHCNT0, 0x000F0037);
+
+	/* QoS Settings */
+	mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00U);
+	mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00U);
+	mmio_write_32(DBSC_DBSCHQOS02, 0x00000000U);
+	mmio_write_32(DBSC_DBSCHQOS03, 0x00000000U);
+	mmio_write_32(DBSC_DBSCHQOS40, 0x00000300U);
+	mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0U);
+	mmio_write_32(DBSC_DBSCHQOS42, 0x00000200U);
+	mmio_write_32(DBSC_DBSCHQOS43, 0x00000100U);
+	mmio_write_32(DBSC_DBSCHQOS90, 0x00000100U);
+	mmio_write_32(DBSC_DBSCHQOS91, 0x000000F0U);
+	mmio_write_32(DBSC_DBSCHQOS92, 0x000000A0U);
+	mmio_write_32(DBSC_DBSCHQOS93, 0x00000040U);
+	mmio_write_32(DBSC_DBSCHQOS120, 0x00000040U);
+	mmio_write_32(DBSC_DBSCHQOS121, 0x00000030U);
+	mmio_write_32(DBSC_DBSCHQOS122, 0x00000020U);
+	mmio_write_32(DBSC_DBSCHQOS123, 0x00000010U);
+	mmio_write_32(DBSC_DBSCHQOS130, 0x00000100U);
+	mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0U);
+	mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0U);
+	mmio_write_32(DBSC_DBSCHQOS133, 0x00000040U);
+	mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0U);
+	mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0U);
+	mmio_write_32(DBSC_DBSCHQOS142, 0x00000080U);
+	mmio_write_32(DBSC_DBSCHQOS143, 0x00000040U);
+	mmio_write_32(DBSC_DBSCHQOS150, 0x00000040U);
+	mmio_write_32(DBSC_DBSCHQOS151, 0x00000030U);
+	mmio_write_32(DBSC_DBSCHQOS152, 0x00000020U);
+	mmio_write_32(DBSC_DBSCHQOS153, 0x00000010U);
+
+	mmio_write_32(QOSCTRL_RAEN, 0x00000001U);
+#endif /* ddr_qos_init_setting */
+	/* H3 Ver.1.1 need to set monitor function */
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut == PRR_PRODUCT_11)) {
+		mmio_write_32(DBSC_DBMONCONF4, 0x00700000);
+	}
+
+	if (Prr_Product == PRR_PRODUCT_H3) {
+		if (Prr_Cut == PRR_PRODUCT_10) {
+			/* resrdis, simple mode, sc off */
+			mmio_write_32(DBSC_DBBCAMDIS, 0x00000007);
+		} else if (Prr_Cut == PRR_PRODUCT_11) {
+			/* resrdis, simple mode         */
+			mmio_write_32(DBSC_DBBCAMDIS, 0x00000005);
+		} else if (Prr_Cut < PRR_PRODUCT_30) {
+			/* H3 Ver.2.0                   */
+			/* resrdis                      */
+			mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
+		} else {	/* H3 Ver.3.0(include H3N)      */
+			/* exprespque                   */
+			mmio_write_32(DBSC_DBBCAMDIS, 0x00000010);
+		}
+	} else {		/* M3-W/M3-N/V3H                */
+		/* resrdis                      */
+		mmio_write_32(DBSC_DBBCAMDIS, 0x00000001);
+	}
+}
+
+static void dbsc_regset_post(void)
+{
+	uint32_t ch, cs;
+	uint32_t dataL;
+	uint32_t slice, rdlat_max, rdlat_min;
+
+	rdlat_max = 0;
+	rdlat_min = 0xffff;
+	foreach_vch(ch) {
+		for (cs = 0; cs < CS_CNT; cs++) {
+			if ((ch_have_this_cs[cs] & (1U << ch)) != 0) {
+				for (slice = 0; slice < SLICE_CNT; slice++) {
+					ddr_setval_s(ch, slice,
+						     _reg_PHY_PER_CS_TRAINING_INDEX,
+						     cs);
+					dataL =
+					    ddr_getval_s(ch, slice,
+							 _reg_PHY_RDDQS_LATENCY_ADJUST);
+					if (dataL > rdlat_max)
+						rdlat_max = dataL;
+					if (dataL < rdlat_min)
+						rdlat_min = dataL;
+				}
+			}
+		}
+	}
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut > PRR_PRODUCT_11)) {
+		mmio_write_32(DBSC_DBTR(24),
+			      ((rdlat_max * 2 - rdlat_min + 4) << 24) +
+			      ((rdlat_min + 2) << 16) +
+			      mmio_read_32(DBSC_DBTR(24)));
+	} else {
+		mmio_write_32(DBSC_DBTR(24),
+			      ((rdlat_max + 2) << 24) +
+			      ((rdlat_max + 2) << 16) +
+			      mmio_read_32(DBSC_DBTR(24)));
+	}
+
+	/* set ddr density information */
+	foreach_ech(ch) {
+		for (cs = 0; cs < CS_CNT; cs++) {
+			if (ddr_density[ch][cs] == 0xff) {
+				mmio_write_32(DBSC_DBMEMCONF(ch, cs), 0x00);
+			} else {
+				mmio_write_32(DBSC_DBMEMCONF(ch, cs),
+					      DBMEMCONF_REGD(ddr_density[ch]
+							     [cs]));
+			}
+		}
+		mmio_write_32(DBSC_DBMEMCONF(ch, 2), 0x00000000);
+		mmio_write_32(DBSC_DBMEMCONF(ch, 3), 0x00000000);
+	}
+
+	mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010);
+
+	/*set DBI */
+	if (Boardcnf->dbi_en)
+		mmio_write_32(DBSC_DBDBICNT, 0x00000003);
+
+	/* H3 Ver.2.0 or later/M3-N/V3H DBI wa */
+	if ((((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut > PRR_PRODUCT_11))
+	     || (Prr_Product == PRR_PRODUCT_M3N)
+	     || (Prr_Product == PRR_PRODUCT_V3H)) && (Boardcnf->dbi_en))
+		reg_ddrphy_write_a(0x00001010, 0x01000000);
+
+	/*set REFCYCLE */
+	dataL = (get_refperiod()) * ddr_mbps / 2000 / ddr_mbpsdiv;
+	mmio_write_32(DBSC_DBRFCNF1, 0x00080000 | (dataL & 0x0000ffff));
+	mmio_write_32(DBSC_DBRFCNF2, 0x00010000 | DBSC_REFINTS);
+
+#ifdef DDR_BACKUPMODE
+	if (ddrBackup == DRAM_BOOT_STATUS_WARM) {
+#ifdef DDR_BACKUPMODE_HALF	/* for Half channel(ch0,1 only) */
+		PutStr(" DEBUG_MESS : DDR_BACKUPMODE_HALF ", 1);
+		send_dbcmd(0x08040001);
+		wait_dbcmd();
+		send_dbcmd(0x0A040001);
+		wait_dbcmd();
+		send_dbcmd(0x04040010);
+		wait_dbcmd();
+
+		if (Prr_Product == PRR_PRODUCT_H3) {
+			send_dbcmd(0x08140001);
+			wait_dbcmd();
+			send_dbcmd(0x0A140001);
+			wait_dbcmd();
+			send_dbcmd(0x04140010);
+			wait_dbcmd();
+		}
+#else /* DDR_BACKUPMODE_HALF                              //for All channels */
+		send_dbcmd(0x08840001);
+		wait_dbcmd();
+		send_dbcmd(0x0A840001);
+		wait_dbcmd();
+
+		send_dbcmd(0x04840010);
+		wait_dbcmd();
+#endif /* DDR_BACKUPMODE_HALF */
+	}
+#endif /* DDR_BACKUPMODE */
+
+#if RCAR_REWT_TRAINING != 0
+	/* Periodic-WriteDQ Training seeting */
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+	    || ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut == PRR_PRODUCT_10))) {
+		/* non : H3 Ver.1.x/M3-W Ver.1.0 not support */
+	} else {
+		/* H3 Ver.2.0 or later/M3-W Ver.1.1 or later/M3-N/V3H -> Periodic-WriteDQ Training seeting */
+
+		/* Periodic WriteDQ Training seeting */
+		mmio_write_32(DBSC_DBDFIPMSTRCNF, 0x00000000);
+
+		ddr_setval_ach_as(_reg_PHY_WDQLVL_PATT, 0x04);
+		ddr_setval_ach_as(_reg_PHY_WDQLVL_QTR_DLY_STEP, 0x0F);
+		ddr_setval_ach_as(_reg_PHY_WDQLVL_DLY_STEP, 0x50);
+		ddr_setval_ach_as(_reg_PHY_WDQLVL_DQDM_SLV_DLY_START, 0x0300);
+
+		ddr_setval_ach(_reg_PI_WDQLVL_CS_MAP,
+			       ddrtbl_getval(_cnf_DDR_PI_REGSET,
+					     _reg_PI_WDQLVL_CS_MAP));
+		ddr_setval_ach(_reg_PI_LONG_COUNT_MASK, 0x1f);
+		ddr_setval_ach(_reg_PI_WDQLVL_VREF_EN, 0x00);
+		ddr_setval_ach(_reg_PI_WDQLVL_INTERVAL, 0x0100);
+		ddr_setval_ach(_reg_PI_WDQLVL_ROTATE, 0x01);
+		ddr_setval_ach(_reg_PI_TREF_F0, 0x0000);
+		ddr_setval_ach(_reg_PI_TREF_F1, 0x0000);
+		ddr_setval_ach(_reg_PI_TREF_F2, 0x0000);
+
+		if (Prr_Product == PRR_PRODUCT_M3) {
+			ddr_setval_ach(_reg_PI_WDQLVL_EN, 0x02);
+		} else {
+			ddr_setval_ach(_reg_PI_WDQLVL_EN_F1, 0x02);
+		}
+		ddr_setval_ach(_reg_PI_WDQLVL_PERIODIC, 0x01);
+
+		/* DFI_PHYMSTR_ACK , WTmode setting */
+		mmio_write_32(DBSC_DBDFIPMSTRCNF, 0x00000011);	/* DFI_PHYMSTR_ACK: WTmode =b'01 */
+	}
+#endif /* RCAR_REWT_TRAINING */
+	/* periodic dram zqcal and phy ctrl update enable */
+	mmio_write_32(DBSC_DBCALCNF, 0x01000010);
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+	    || ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut < PRR_PRODUCT_30))) {
+		/* non : H3 Ver.1.x/M3-W Ver.1.x not support */
+	} else {
+#if RCAR_DRAM_SPLIT == 2
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Boardcnf->phyvalid == 0x05))
+			mmio_write_32(DBSC_DBDFICUPDCNF, 0x2a240001);
+		else
+			mmio_write_32(DBSC_DBDFICUPDCNF, 0x28240001);
+#else /* RCAR_DRAM_SPLIT == 2 */
+		mmio_write_32(DBSC_DBDFICUPDCNF, 0x28240001);
+#endif /* RCAR_DRAM_SPLIT == 2 */
+	}
+
+	mmio_write_32(DBSC_DBRFEN, 0x00000001);
+	/* dram access enable */
+	mmio_write_32(DBSC_DBACEN, 0x00000001);
+
+	MSG_LF("dbsc_regset_post(done)");
+
+}
+
+/*******************************************************************************
+ *	DFI_INIT_START
+ ******************************************************************************/
+static uint32_t dfi_init_start(void)
+{
+	uint32_t ch;
+	uint32_t phytrainingok;
+	uint32_t retry;
+	uint32_t dataL;
+	const uint32_t RETRY_MAX = 0x10000;
+
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+	/***********************************************************************
+		PLL3 Disable
+	***********************************************************************/
+		/* protect register interface */
+		ddrphy_regif_idle();
+
+		pll3_control(0);
+
+	/***********************************************************************
+		init start
+	***********************************************************************/
+		/* dbdficnt0:
+		 * dfi_dram_clk_disable=1
+		 * dfi_frequency = 0
+		 * freq_ratio = 01 (2:1)
+		 * init_start =0
+		 */
+		foreach_vch(ch)
+		    mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F10);
+		dsb_sev();
+
+		/* dbdficnt0:
+		 * dfi_dram_clk_disable=1
+		 * dfi_frequency = 0
+		 * freq_ratio = 01 (2:1)
+		 * init_start =1
+		 */
+		foreach_vch(ch)
+		    mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F11);
+		dsb_sev();
+
+	} else {
+		ddr_setval_ach_as(_reg_PHY_DLL_RST_EN, 0x02);
+		dsb_sev();
+		ddrphy_regif_idle();
+	}
+
+	/* dll_rst negate */
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBPDCNT3(ch), 0x0000CF01);
+	dsb_sev();
+
+	/***********************************************************************
+	wait init_complete
+	***********************************************************************/
+	phytrainingok = 0;
+	retry = 0;
+	while (retry++ < RETRY_MAX) {
+		foreach_vch(ch) {
+			dataL = mmio_read_32(DBSC_DBDFISTAT(ch));
+			if (dataL & 0x00000001)
+				phytrainingok |= (1U << ch);
+		}
+		dsb_sev();
+		if (phytrainingok == ddr_phyvalid)
+			break;
+		if (retry % 256 == 0)
+			ddr_setval_ach_as(_reg_SC_PHY_RX_CAL_START, 0x01);
+	}
+
+	/***********************************************************************
+	all ch ok?
+	***********************************************************************/
+	if ((phytrainingok & ddr_phyvalid) != ddr_phyvalid) {
+		return (0xff);
+	}
+	/* dbdficnt0:
+	 * dfi_dram_clk_disable=0
+	 * dfi_frequency = 0
+	 * freq_ratio = 01 (2:1)
+	 * init_start =0
+	 */
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBDFICNT(ch), 0x00000010);
+	dsb_sev();
+
+	return 0;
+}
+
+/*******************************************************************************
+ *	drivablity setting : CMOS MODE ON/OFF
+ ******************************************************************************/
+static void change_lpddr4_en(uint32_t mode)
+{
+	uint32_t ch;
+	uint32_t i;
+	uint32_t dataL;
+	const uint32_t _reg_PHY_PAD_DRIVE_X[3] = {
+		_reg_PHY_PAD_ADDR_DRIVE,
+		_reg_PHY_PAD_CLK_DRIVE,
+		_reg_PHY_PAD_CS_DRIVE
+	};
+
+	foreach_vch(ch) {
+		for (i = 0; i < 3; i++) {
+			dataL = ddr_getval(ch, _reg_PHY_PAD_DRIVE_X[i]);
+			if (mode) {
+				dataL |= (1U << 14);
+			} else {
+				dataL &= ~(1U << 14);
+			}
+			ddr_setval(ch, _reg_PHY_PAD_DRIVE_X[i], dataL);
+		}
+	}
+}
+
+/*******************************************************************************
+ *	drivablity setting
+ ******************************************************************************/
+static uint32_t set_term_code(void)
+{
+	int32_t i;
+	uint32_t ch, index;
+	uint32_t dataL;
+	uint32_t chip_id[2];
+	uint32_t term_code;
+	uint32_t override;
+	uint32_t pvtr;
+	uint32_t pvtp;
+	uint32_t pvtn;
+	term_code = ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+				  _reg_PHY_PAD_DATA_TERM);
+	override = 0;
+	for (i = 0; i < 2; i++)
+		chip_id[i] = mmio_read_32(LIFEC_CHIPID(i));
+
+	index = 0;
+	while (1) {
+		if (TermcodeBySample[index][0] == 0xffffffff) {
+			break;
+		}
+		if ((TermcodeBySample[index][0] == chip_id[0])
+		    && (TermcodeBySample[index][1] == chip_id[1])) {
+			term_code = TermcodeBySample[index][2];
+			override = 1;
+			break;
+		}
+		index++;
+	}
+
+	if (override) {
+		for (index = 0; index < _reg_PHY_PAD_TERM_X_NUM; index++) {
+			dataL =
+			    ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET,
+					  _reg_PHY_PAD_TERM_X[index]);
+			dataL = (dataL & 0xfffe0000) | term_code;
+			ddr_setval_ach(_reg_PHY_PAD_TERM_X[index], dataL);
+		}
+	} else if ((Prr_Product == PRR_PRODUCT_M3)
+		   && (Prr_Cut == PRR_PRODUCT_10)) {
+		/*  non */
+	} else {
+		ddr_setval_ach(_reg_PHY_PAD_TERM_X[0],
+			       (ddrtbl_getval
+				(_cnf_DDR_PHY_ADR_G_REGSET,
+				 _reg_PHY_PAD_TERM_X[0]) & 0xFFFE0000));
+		ddr_setval_ach(_reg_PHY_CAL_CLEAR_0, 0x01);
+		ddr_setval_ach(_reg_PHY_CAL_START_0, 0x01);
+		foreach_vch(ch) {
+			do {
+				dataL =
+				    ddr_getval(ch, _reg_PHY_CAL_RESULT2_OBS_0);
+			} while (!(dataL & 0x00800000));
+		}
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut <= PRR_PRODUCT_11)) {
+			foreach_vch(ch) {
+				dataL = ddr_getval(ch, _reg_PHY_PAD_TERM_X[0]);
+				pvtr = (dataL >> 12) & 0x1f;
+				pvtr += 8;
+				if (pvtr > 0x1f)
+					pvtr = 0x1f;
+				dataL =
+				    ddr_getval(ch, _reg_PHY_CAL_RESULT2_OBS_0);
+				pvtn = (dataL >> 6) & 0x03f;
+				pvtp = (dataL >> 0) & 0x03f;
+
+				for (index = 0; index < _reg_PHY_PAD_TERM_X_NUM;
+				     index++) {
+					dataL =
+					    ddrtbl_getval
+					    (_cnf_DDR_PHY_ADR_G_REGSET,
+					     _reg_PHY_PAD_TERM_X[index]);
+					dataL = (dataL & 0xfffe0000)
+					    | (pvtr << 12)
+					    | (pvtn << 6)
+					    | (pvtp);
+					ddr_setval(ch,
+						   _reg_PHY_PAD_TERM_X[index],
+						   dataL);
+				}
+			}
+		} else {	/*  M3-W Ver.1.1 or later/H3 Ver.2.0 or later/M3-N/V3H */
+			foreach_vch(ch) {
+				for (index = 0; index < _reg_PHY_PAD_TERM_X_NUM;
+				     index++) {
+					dataL =
+					    ddr_getval(ch,
+						       _reg_PHY_PAD_TERM_X
+						       [index]);
+					ddr_setval(ch,
+						   _reg_PHY_PAD_TERM_X[index],
+						   (dataL & 0xFFFE0FFF) |
+						   0x00015000);
+				}
+			}
+		}
+	}
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		/*  non */
+	} else {
+		ddr_padcal_tcompensate_getinit(override);
+	}
+	return 0;
+}
+
+/*******************************************************************************
+ *	DDR mode register setting
+ ******************************************************************************/
+static void ddr_register_set(void)
+{
+	int32_t fspwp;
+	uint32_t tmp;
+
+	for (fspwp = 1; fspwp >= 0; fspwp--) {
+		/*MR13,fspwp */
+		send_dbcmd(0x0e840d08 | (fspwp << 6));
+
+		tmp =
+		    ddrtbl_getval(_cnf_DDR_PI_REGSET,
+				  _reg_PI_MR1_DATA_Fx_CSx[fspwp][0]);
+		send_dbcmd(0x0e840100 | tmp);
+
+		tmp =
+		    ddrtbl_getval(_cnf_DDR_PI_REGSET,
+				  _reg_PI_MR2_DATA_Fx_CSx[fspwp][0]);
+		send_dbcmd(0x0e840200 | tmp);
+
+		tmp =
+		    ddrtbl_getval(_cnf_DDR_PI_REGSET,
+				  _reg_PI_MR3_DATA_Fx_CSx[fspwp][0]);
+		send_dbcmd(0x0e840300 | tmp);
+
+		tmp =
+		    ddrtbl_getval(_cnf_DDR_PI_REGSET,
+				  _reg_PI_MR11_DATA_Fx_CSx[fspwp][0]);
+		send_dbcmd(0x0e840b00 | tmp);
+
+		tmp =
+		    ddrtbl_getval(_cnf_DDR_PI_REGSET,
+				  _reg_PI_MR12_DATA_Fx_CSx[fspwp][0]);
+		send_dbcmd(0x0e840c00 | tmp);
+
+		tmp =
+		    ddrtbl_getval(_cnf_DDR_PI_REGSET,
+				  _reg_PI_MR14_DATA_Fx_CSx[fspwp][0]);
+		send_dbcmd(0x0e840e00 | tmp);
+		/* MR22 */
+		send_dbcmd(0x0e841616);
+	}
+}
+
+/*******************************************************************************
+ *	Training handshake functions
+ ******************************************************************************/
+static inline uint32_t wait_freqchgreq(uint32_t assert)
+{
+	uint32_t dataL;
+	uint32_t count;
+	uint32_t ch;
+	count = 100000;
+
+	/* H3 Ver.1.x cannot see frqchg_req */
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		return 0;
+	}
+
+	if (assert) {
+		do {
+			dataL = 1;
+			foreach_vch(ch) {
+				dataL &= mmio_read_32(DBSC_DBPDSTAT(ch));
+			}
+			count = count - 1;
+		} while (((dataL & 0x01) != 0x01) & (count != 0));
+	} else {
+		do {
+			dataL = 0;
+			foreach_vch(ch) {
+				dataL |= mmio_read_32(DBSC_DBPDSTAT(ch));
+			}
+			count = count - 1;
+		} while (((dataL & 0x01) != 0x00) & (count != 0));
+	}
+
+	return (count == 0);
+}
+
+static inline void set_freqchgack(uint32_t assert)
+{
+	uint32_t ch;
+	uint32_t dataL;
+	if (assert)
+		dataL = 0x0CF20000;
+	else
+		dataL = 0x00000000;
+
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBPDCNT2(ch), dataL);
+}
+
+static inline void set_dfifrequency(uint32_t freq)
+{
+	uint32_t ch;
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		foreach_vch(ch)
+		    mmio_clrsetbits_32(DBSC_DBPDCNT1(ch), 0x1fU, freq);
+	} else {
+		foreach_vch(ch) {
+			mmio_clrsetbits_32(DBSC_DBDFICNT(ch), 0x1fU << 24,
+					   (freq << 24));
+		}
+	}
+	dsb_sev();
+}
+
+static uint32_t pll3_freq(uint32_t on)
+{
+	uint32_t timeout;
+
+	timeout = wait_freqchgreq(1);
+
+	if (timeout) {
+		return (1);
+	}
+
+	pll3_control(on);
+	set_dfifrequency(on);
+
+	set_freqchgack(1);
+	timeout = wait_freqchgreq(0);
+	set_freqchgack(0);
+
+	if (timeout) {
+		FATAL_MSG("BL2: Time out[2]\n");
+		return (1);
+	}
+	return (0);
+}
+
+/*******************************************************************************
+ *	update dly
+ ******************************************************************************/
+static void update_dly(void)
+{
+	ddr_setval_ach(_reg_SC_PHY_MANUAL_UPDATE, 0x01);
+	ddr_setval_ach(_reg_PHY_ADRCTL_MANUAL_UPDATE, 0x01);
+}
+
+/*******************************************************************************
+ *	training by pi
+ ******************************************************************************/
+static uint32_t pi_training_go(void)
+{
+	uint32_t flag;
+	uint32_t dataL;
+	uint32_t retry;
+	const uint32_t RETRY_MAX = 4096 * 16;
+	uint32_t ch;
+
+	uint32_t mst_ch;
+	uint32_t cur_frq;
+	uint32_t complete;
+	uint32_t frqchg_req;
+
+	/* ********************************************************************* */
+
+	/***********************************************************************
+	pi_start
+	***********************************************************************/
+	ddr_setval_ach(_reg_PI_START, 0x01);
+	foreach_vch(ch)
+	    ddr_getval(ch, _reg_PI_INT_STATUS);
+
+	/* set dfi_phymstr_ack = 1 */
+	mmio_write_32(DBSC_DBDFIPMSTRCNF, 0x00000001);
+	dsb_sev();
+
+	/***********************************************************************
+	wait pi_int_status[0]
+	***********************************************************************/
+	mst_ch = 0;
+	flag = 0;
+	complete = 0;
+	cur_frq = 0;
+	retry = RETRY_MAX;
+	do {
+		frqchg_req = mmio_read_32(DBSC_DBPDSTAT(mst_ch)) & 0x01;
+
+		/* H3 Ver.1.x cannot see frqchg_req */
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut <= PRR_PRODUCT_11)) {
+			if ((retry % 4096) == 1) {
+				frqchg_req = 1;
+			} else {
+				frqchg_req = 0;
+			}
+		}
+
+		if (frqchg_req) {
+			if (cur_frq) {
+				/* Low frequency */
+				flag = pll3_freq(0);
+				cur_frq = 0;
+			} else {
+				/* High frequency */
+				flag = pll3_freq(1);
+				cur_frq = 1;
+			}
+			if (flag)
+				break;
+		} else {
+			if (cur_frq) {
+				foreach_vch(ch) {
+					if (complete & (1U << ch))
+						continue;
+					dataL =
+					    ddr_getval(ch, _reg_PI_INT_STATUS);
+					if (dataL & 0x01) {
+						complete |= (1U << ch);
+					}
+				}
+				if (complete == ddr_phyvalid)
+					break;
+			}
+		}
+	} while (--retry);
+	foreach_vch(ch) {
+		/* dummy read */
+		dataL = ddr_getval_s(ch, 0, _reg_PHY_CAL_RESULT2_OBS_0);
+		dataL = ddr_getval(ch, _reg_PI_INT_STATUS);
+		ddr_setval(ch, _reg_PI_INT_ACK, dataL);
+	}
+	if (ddrphy_regif_chk()) {
+		return (0xfd);
+	}
+	return complete;
+}
+
+/*******************************************************************************
+ *	Initialize ddr
+ ******************************************************************************/
+static uint32_t init_ddr(void)
+{
+	int32_t i;
+	uint32_t dataL;
+	uint32_t phytrainingok;
+	uint32_t ch, slice;
+	uint32_t err;
+	int16_t adj;
+
+	MSG_LF("init_ddr:0\n");
+
+#ifdef DDR_BACKUPMODE
+	rcar_dram_get_boot_status(&ddrBackup);
+#endif
+
+	/***********************************************************************
+	unlock phy
+	***********************************************************************/
+	/* Unlock DDRPHY register(AGAIN) */
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBPDLK(ch), 0x0000A55A);
+	dsb_sev();
+
+	if ((((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut > PRR_PRODUCT_11))
+	     || (Prr_Product == PRR_PRODUCT_M3N)
+	     || (Prr_Product == PRR_PRODUCT_V3H)) && (Boardcnf->dbi_en))
+		reg_ddrphy_write_a(0x00001010, 0x01000001);
+	else
+		reg_ddrphy_write_a(0x00001010, 0x00000001);
+	/***********************************************************************
+	dbsc register pre-setting
+	***********************************************************************/
+	dbsc_regset_pre();
+
+	/***********************************************************************
+	load ddrphy registers
+	***********************************************************************/
+
+	ddrtbl_load();
+
+	/***********************************************************************
+	configure ddrphy registers
+	***********************************************************************/
+	ddr_config();
+
+	/***********************************************************************
+	dfi_reset assert
+	***********************************************************************/
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBPDCNT0(ch), 0x01);
+	dsb_sev();
+
+	/***********************************************************************
+	dbsc register set
+	***********************************************************************/
+	dbsc_regset();
+	MSG_LF("init_ddr:1\n");
+
+	/***********************************************************************
+	dfi_reset negate
+	***********************************************************************/
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBPDCNT0(ch), 0x00);
+	dsb_sev();
+
+	/***********************************************************************
+	dfi_init_start (start ddrphy)
+	***********************************************************************/
+	err = dfi_init_start();
+	if (err) {
+		return INITDRAM_ERR_I;
+	}
+	MSG_LF("init_ddr:2\n");
+
+	/***********************************************************************
+	ddr backupmode end
+	***********************************************************************/
+#ifdef DDR_BACKUPMODE
+	if (ddrBackup) {
+		NOTICE("BL2: [WARM_BOOT]\n");
+	} else {
+		NOTICE("BL2: [COLD_BOOT]\n");
+	}
+	err = rcar_dram_update_boot_status(ddrBackup);
+	if (err) {
+		NOTICE("BL2: [BOOT_STATUS_UPDATE_ERROR]\n");
+		return INITDRAM_ERR_I;
+	}
+#endif
+	MSG_LF("init_ddr:3\n");
+
+	/***********************************************************************
+	override term code after dfi_init_complete
+	***********************************************************************/
+	err = set_term_code();
+	if (err) {
+		return INITDRAM_ERR_I;
+	}
+	MSG_LF("init_ddr:4\n");
+
+	/***********************************************************************
+	rx offset calibration
+	***********************************************************************/
+	if ((Prr_Cut > PRR_PRODUCT_11) || (Prr_Product == PRR_PRODUCT_M3N)
+	    || (Prr_Product == PRR_PRODUCT_V3H)) {
+		err = rx_offset_cal_hw();
+	} else {
+		err = rx_offset_cal();
+	}
+	if (err)
+		return (INITDRAM_ERR_O);
+	MSG_LF("init_ddr:5\n");
+
+	/* PDX */
+	send_dbcmd(0x08840001);
+
+	/***********************************************************************
+	check register i/f is alive
+	***********************************************************************/
+	err = ddrphy_regif_chk();
+	if (err) {
+		return (INITDRAM_ERR_O);
+	}
+	MSG_LF("init_ddr:6\n");
+
+	/***********************************************************************
+	phy initialize end
+	***********************************************************************/
+
+	/***********************************************************************
+	setup DDR mode registers
+	***********************************************************************/
+	/* CMOS MODE */
+	change_lpddr4_en(0);
+
+	/* MRS */
+	ddr_register_set();
+
+	/* ZQCAL start */
+	send_dbcmd(0x0d84004F);
+
+	/* ZQLAT */
+	send_dbcmd(0x0d840051);
+
+	/***********************************************************************
+	Thermal sensor setting
+	***********************************************************************/
+	/* THCTR Bit6: PONM=0 , Bit0: THSST=1  */
+	dataL = (mmio_read_32(THS1_THCTR) & 0xFFFFFFBF) | 0x00000001;
+	mmio_write_32(THS1_THCTR, dataL);
+
+	/* LPDDR4 MODE */
+	change_lpddr4_en(1);
+
+	MSG_LF("init_ddr:7\n");
+
+	/***********************************************************************
+	mask CS_MAP if RANKx is not found
+	***********************************************************************/
+	foreach_vch(ch) {
+		dataL = ddr_getval(ch, _reg_PI_CS_MAP);
+		if (!(ch_have_this_cs[1] & (1U << ch)))
+			dataL = dataL & 0x05;
+		ddr_setval(ch, _reg_PI_CS_MAP, dataL);
+	}
+
+	/***********************************************************************
+	exec pi_training
+	***********************************************************************/
+	reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN),
+			   BIT(ddr_regdef_lsb(_reg_PHY_FREQ_SEL_MULTICAST_EN)));
+	ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_MULTICAST_EN, 0x00);
+
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+	ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_EN, 0x01);
+	} else {
+		foreach_vch(ch) {
+			for (slice = 0; slice < SLICE_CNT; slice++) {
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_PER_CS_TRAINING_EN,
+					     ((ch_have_this_cs[1]) >> ch)
+					     & 0x01);
+			}
+		}
+	}
+
+	phytrainingok = pi_training_go();
+
+	if (ddr_phyvalid != (phytrainingok & ddr_phyvalid)) {
+		return (INITDRAM_ERR_T | phytrainingok);
+	}
+
+	MSG_LF("init_ddr:8\n");
+
+	/***********************************************************************
+	CACS DLY ADJUST
+	***********************************************************************/
+	dataL = Boardcnf->cacs_dly + _f_scale_adj(Boardcnf->cacs_dly_adj);
+	foreach_vch(ch) {
+		for (i = 0; i < _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM; i++) {
+			adj = _f_scale_adj(Boardcnf->ch[ch].cacs_adj[i]);
+			ddr_setval(ch, _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i],
+				   dataL + adj);
+		}
+
+		if (ddr_phycaslice == 1) {
+			for (i = 0; i < 6; i++) {
+				adj = _f_scale_adj(Boardcnf->ch[ch].cacs_adj[i + _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM]);
+				ddr_setval_s(ch, 2, _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i],
+					     dataL + adj
+				);
+			}
+		}
+	}
+
+	update_dly();
+	MSG_LF("init_ddr:9\n");
+
+	/***********************************************************************
+	H3 fix rd latency to avoid bug in elasitic buffe
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		adjust_rddqs_latency();
+	}
+
+	/***********************************************************************
+	Adjust Write path latency
+	***********************************************************************/
+	if (ddrtbl_getval
+	    (_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_WRITE_PATH_LAT_ADD))
+		adjust_wpath_latency();
+
+	/***********************************************************************
+	RDQLVL Training
+	***********************************************************************/
+	if (ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_IE_MODE) == 0x00) {
+		ddr_setval_ach_as(_reg_PHY_IE_MODE, 0x01);
+	}
+
+	err = rdqdm_man();
+
+	if (ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_IE_MODE) == 0x00) {
+		ddr_setval_ach_as(_reg_PHY_IE_MODE, 0x00);
+	}
+
+	if (err) {
+		return (INITDRAM_ERR_T);
+	}
+	update_dly();
+	MSG_LF("init_ddr:10\n");
+
+	/***********************************************************************
+	WDQLVL Training
+	***********************************************************************/
+	err = wdqdm_man();
+	if (err) {
+		return (INITDRAM_ERR_T);
+	}
+	update_dly();
+	MSG_LF("init_ddr:11\n");
+
+	/***********************************************************************
+	training complete, setup dbsc
+	***********************************************************************/
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut > PRR_PRODUCT_11))
+	    || (Prr_Product == PRR_PRODUCT_M3N)
+	    || (Prr_Product == PRR_PRODUCT_V3H)) {
+		ddr_setval_ach_as(_reg_PHY_DFI40_POLARITY, 0x00);
+		ddr_setval_ach(_reg_PI_DFI40_POLARITY, 0x00);
+	}
+
+	dbsc_regset_post();
+	MSG_LF("init_ddr:12\n");
+
+	return phytrainingok;
+}
+
+/*******************************************************************************
+ *	SW LEVELING COMMON
+ ******************************************************************************/
+static uint32_t swlvl1(uint32_t ddr_csn, uint32_t reg_cs, uint32_t reg_kick)
+{
+	uint32_t ch;
+	uint32_t dataL;
+	uint32_t retry;
+	uint32_t waiting;
+	uint32_t err;
+
+	const uint32_t RETRY_MAX = 0x1000;
+
+	err = 0;
+	/* set EXIT -> OP_DONE is cleared */
+	ddr_setval_ach(_reg_PI_SWLVL_EXIT, 0x01);
+
+	/* kick */
+	foreach_vch(ch) {
+		if (ch_have_this_cs[ddr_csn % 2] & (1U << ch)) {
+			ddr_setval(ch, reg_cs, ddr_csn);
+			ddr_setval(ch, reg_kick, 0x01);
+		}
+	}
+	foreach_vch(ch) {
+		/*PREPARE ADDR REGISTER (for SWLVL_OP_DONE) */
+		ddr_getval(ch, _reg_PI_SWLVL_OP_DONE);
+	}
+	waiting = ch_have_this_cs[ddr_csn % 2];
+	dsb_sev();
+	retry = RETRY_MAX;
+	do {
+		foreach_vch(ch) {
+			if (!(waiting & (1U << ch)))
+				continue;
+			dataL = ddr_getval(ch, _reg_PI_SWLVL_OP_DONE);
+			if (dataL & 0x01)
+				waiting &= ~(1U << ch);
+		}
+		retry--;
+	} while (waiting && (retry > 0));
+	if (retry == 0) {
+		err = 1;
+	}
+
+	dsb_sev();
+	/* set EXIT -> OP_DONE is cleared */
+	ddr_setval_ach(_reg_PI_SWLVL_EXIT, 0x01);
+	dsb_sev();
+
+	return err;
+}
+
+/*******************************************************************************
+ *	WDQ TRAINING
+ ******************************************************************************/
+#ifndef DDR_FAST_INIT
+static void wdqdm_clr1(uint32_t ch, uint32_t ddr_csn)
+{
+	int32_t i, k;
+	uint32_t cs, slice;
+	uint32_t dataL;
+
+	/***********************************************************************
+	clr of training results buffer
+	***********************************************************************/
+	cs = ddr_csn % 2;
+	dataL = Boardcnf->dqdm_dly_w;
+	for (slice = 0; slice < SLICE_CNT; slice++) {
+		k = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+		if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2)))
+			continue;
+
+		for (i = 0; i <= 8; i++) {
+			if (ch_have_this_cs[CS_CNT - 1 - cs] & (1U << ch))
+				wdqdm_dly[ch][cs][slice][i] =
+				    wdqdm_dly[ch][CS_CNT - 1 - cs][slice][i];
+			else
+				wdqdm_dly[ch][cs][slice][i] = dataL;
+			wdqdm_le[ch][cs][slice][i] = 0;
+			wdqdm_te[ch][cs][slice][i] = 0;
+		}
+		wdqdm_st[ch][cs][slice] = 0;
+		wdqdm_win[ch][cs][slice] = 0;
+	}
+}
+
+static uint32_t wdqdm_ana1(uint32_t ch, uint32_t ddr_csn)
+{
+	int32_t i, k;
+	uint32_t cs, slice;
+	uint32_t dataL;
+	uint32_t err;
+	const uint32_t _par_WDQLVL_RETRY_THRES = 0x7c0;
+
+	int32_t min_win;
+	int32_t win;
+	int8_t _adj;
+	int16_t adj;
+	uint32_t dq;
+
+	/***********************************************************************
+	analysis of training results
+	***********************************************************************/
+	err = 0;
+	for (slice = 0; slice < SLICE_CNT; slice += 1) {
+		k = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+		if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2)))
+			continue;
+
+		cs = ddr_csn % 2;
+		ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, cs);
+		for (i = 0; i < 9; i++) {
+			dq = slice * 8 + i;
+			if (i == 8)
+				_adj = Boardcnf->ch[ch].dm_adj_w[slice];
+			else
+				_adj = Boardcnf->ch[ch].dq_adj_w[dq];
+			adj = _f_scale_adj(_adj);
+
+			dataL =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_CLK_WRX_SLAVE_DELAY[i]) + adj;
+			ddr_setval_s(ch, slice, _reg_PHY_CLK_WRX_SLAVE_DELAY[i],
+				     dataL);
+			wdqdm_dly[ch][cs][slice][i] = dataL;
+		}
+		ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN, 0x00);
+		dataL = ddr_getval_s(ch, slice, _reg_PHY_WDQLVL_STATUS_OBS);
+		wdqdm_st[ch][cs][slice] = dataL;
+		min_win = INT_LEAST32_MAX;
+		for (i = 0; i <= 8; i++) {
+			ddr_setval_s(ch, slice, _reg_PHY_WDQLVL_DQDM_OBS_SELECT,
+				     i);
+
+			dataL =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_WDQLVL_DQDM_TE_DLY_OBS);
+			wdqdm_te[ch][cs][slice][i] = dataL;
+			dataL =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_WDQLVL_DQDM_LE_DLY_OBS);
+			wdqdm_le[ch][cs][slice][i] = dataL;
+			win =
+			    (int32_t) wdqdm_te[ch][cs][slice][i] -
+			    wdqdm_le[ch][cs][slice][i];
+			if (min_win > win)
+				min_win = win;
+			if (dataL >= _par_WDQLVL_RETRY_THRES)
+				err = 2;
+		}
+		wdqdm_win[ch][cs][slice] = min_win;
+		if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN, 0x01);
+		} else {
+			ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN,
+				     ((ch_have_this_cs[1]) >> ch) & 0x01);
+		}
+	}
+	return err;
+}
+#endif/* DDR_FAST_INIT */
+
+static void wdqdm_cp(uint32_t ddr_csn, uint32_t restore)
+{
+	uint32_t i;
+	uint32_t ch, slice;
+	uint32_t tgt_cs, src_cs;
+	uint32_t tmp_r;
+
+	/***********************************************************************
+	copy of training results
+	***********************************************************************/
+	foreach_vch(ch) {
+		for (tgt_cs = 0; tgt_cs < CS_CNT; tgt_cs++) {
+			for (slice = 0; slice < SLICE_CNT; slice++) {
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_PER_CS_TRAINING_INDEX,
+					     tgt_cs);
+				src_cs = ddr_csn % 2;
+				if (!(ch_have_this_cs[1] & (1U << ch)))
+					src_cs = 0;
+				for (i = 0; i <= 4; i += 4) {
+					if (restore)
+						tmp_r =
+						    rdqdm_dly[ch][tgt_cs][slice]
+						    [i];
+					else
+						tmp_r =
+						    rdqdm_dly[ch][src_cs][slice]
+						    [i];
+
+					ddr_setval_s(ch, slice,
+						     _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY
+						     [i], tmp_r);
+				}
+			}
+		}
+	}
+}
+
+static uint32_t wdqdm_man1(void)
+{
+	int32_t k;
+	uint32_t ch, cs, slice;
+	uint32_t ddr_csn;
+	uint32_t dataL;
+	uint32_t err;
+	uint32_t high_dq[DRAM_CH_CNT];
+	uint32_t mr14_csab0_bak[DRAM_CH_CNT];
+#ifndef DDR_FAST_INIT
+	uint32_t err_flg;
+#endif/* DDR_FAST_INIT */
+
+	/***********************************************************************
+	manual execution of training
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		foreach_vch(ch) {
+			high_dq[ch] = 0;
+			for (slice = 0; slice < SLICE_CNT; slice++) {
+				k = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+				if (k >= 2)
+					high_dq[ch] |= (1U << slice);
+			}
+			ddr_setval(ch, _reg_PI_16BIT_DRAM_CONNECT, 0x00);
+		}
+	}
+	err = 0;
+	/* CLEAR PREV RESULT */
+	for (cs = 0; cs < CS_CNT; cs++) {
+		ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_INDEX, cs);
+		if (((Prr_Product == PRR_PRODUCT_H3)
+		     && (Prr_Cut > PRR_PRODUCT_11))
+		    || (Prr_Product == PRR_PRODUCT_M3N)
+		    || (Prr_Product == PRR_PRODUCT_V3H)) {
+			ddr_setval_ach_as(_reg_SC_PHY_WDQLVL_CLR_PREV_RESULTS,
+					  0x01);
+		} else {
+			ddr_setval_ach_as(_reg_PHY_WDQLVL_CLR_PREV_RESULTS,
+					  0x01);
+		}
+	}
+	ddrphy_regif_idle();
+
+#ifndef DDR_FAST_INIT
+	err_flg = 0;
+#endif/* DDR_FAST_INIT */
+	for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) {
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut <= PRR_PRODUCT_11)) {
+			foreach_vch(ch) {
+				dataL = mmio_read_32(DBSC_DBDFICNT(ch));
+				dataL &= ~(0x00ffU << 16);
+
+				if (ddr_csn >= 2)
+					k = (high_dq[ch] ^ 0x0f);
+				else
+					k = high_dq[ch];
+				dataL |= (k << 16);
+				mmio_write_32(DBSC_DBDFICNT(ch), dataL);
+				ddr_setval(ch, _reg_PI_WDQLVL_RESP_MASK, k);
+			}
+		}
+		if (((Prr_Product == PRR_PRODUCT_H3)
+		     && (Prr_Cut <= PRR_PRODUCT_11))
+		    || ((Prr_Product == PRR_PRODUCT_M3)
+			&& (Prr_Cut == PRR_PRODUCT_10))) {
+			wdqdm_cp(ddr_csn, 0);
+		}
+
+		foreach_vch(ch) {
+			dataL =
+			    ddr_getval(ch,
+				       _reg_PI_MR14_DATA_Fx_CSx[1][ddr_csn]);
+			ddr_setval(ch, _reg_PI_MR14_DATA_Fx_CSx[1][0], dataL);
+		}
+
+		/* KICK WDQLVL */
+		err = swlvl1(ddr_csn, _reg_PI_WDQLVL_CS, _reg_PI_WDQLVL_REQ);
+		if (err)
+			goto err_exit;
+
+		if (ddr_csn == 0)
+			foreach_vch(ch) {
+			mr14_csab0_bak[ch] =
+			    ddr_getval(ch, _reg_PI_MR14_DATA_Fx_CSx[1][0]);
+		} else
+			foreach_vch(ch) {
+			ddr_setval(ch, _reg_PI_MR14_DATA_Fx_CSx[1][0],
+				   mr14_csab0_bak[ch]);
+			}
+#ifndef DDR_FAST_INIT
+		foreach_vch(ch) {
+			if (!(ch_have_this_cs[ddr_csn % 2] & (1U << ch))) {
+				wdqdm_clr1(ch, ddr_csn);
+				continue;
+			}
+			err = wdqdm_ana1(ch, ddr_csn);
+			if (err)
+				err_flg |= (1U << (ddr_csn * 4 + ch));
+			ddrphy_regif_idle();
+		}
+#endif/* DDR_FAST_INIT */
+	}
+err_exit:
+#ifndef DDR_FAST_INIT
+	err |= err_flg;
+#endif/* DDR_FAST_INIT */
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		ddr_setval_ach(_reg_PI_16BIT_DRAM_CONNECT, 0x01);
+		foreach_vch(ch) {
+			dataL = mmio_read_32(DBSC_DBDFICNT(ch));
+			dataL &= ~(0x00ffU << 16);
+			mmio_write_32(DBSC_DBDFICNT(ch), dataL);
+			ddr_setval(ch, _reg_PI_WDQLVL_RESP_MASK, 0x00);
+		}
+	}
+	return (err);
+}
+
+static uint32_t wdqdm_man(void)
+{
+	uint32_t err, retry_cnt;
+	const uint32_t retry_max = 0x10;
+	uint32_t ch, ddr_csn, mr14_bkup[4][4];
+
+	ddr_setval_ach(_reg_PI_TDFI_WDQLVL_RW, (DBSC_DBTR(11) & 0xFF) + 12);
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut > PRR_PRODUCT_11))
+	    || (Prr_Product == PRR_PRODUCT_M3N)
+	    || (Prr_Product == PRR_PRODUCT_V3H)) {
+		ddr_setval_ach(_reg_PI_TDFI_WDQLVL_WR_F1,
+			       (DBSC_DBTR(12) & 0xFF) + 1);
+	} else {
+		ddr_setval_ach(_reg_PI_TDFI_WDQLVL_WR,
+			       (DBSC_DBTR(12) & 0xFF) + 1);
+	}
+	ddr_setval_ach(_reg_PI_TRFC_F1, (DBSC_DBTR(13) & 0x1FF));
+
+	retry_cnt = 0;
+	err = 0;
+	do {
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut <= PRR_PRODUCT_11)) {
+			err = wdqdm_man1();
+		} else {
+			ddr_setval_ach(_reg_PI_WDQLVL_VREF_EN, 0x01);
+			ddr_setval_ach(_reg_PI_WDQLVL_VREF_NORMAL_STEPSIZE,
+				       0x01);
+			if ((Prr_Product == PRR_PRODUCT_M3N)
+			    || (Prr_Product == PRR_PRODUCT_V3H)) {
+				ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA_F1,
+					       0x0C);
+			} else {
+				ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA, 0x0C);
+			}
+			dsb_sev();
+			err = wdqdm_man1();
+			foreach_vch(ch) {
+				for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) {
+					mr14_bkup[ch][ddr_csn] =
+					    ddr_getval(ch,
+						       _reg_PI_MR14_DATA_Fx_CSx
+						       [1][ddr_csn]);
+					dsb_sev();
+				}
+			}
+
+			if ((Prr_Product == PRR_PRODUCT_M3N)
+			    || (Prr_Product == PRR_PRODUCT_V3H)) {
+				ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA_F1,
+					       0x04);
+			} else {
+				ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA, 0x04);
+			}
+			pvtcode_update();
+			err = wdqdm_man1();
+			foreach_vch(ch) {
+				for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) {
+					mr14_bkup[ch][ddr_csn] =
+					    (mr14_bkup[ch][ddr_csn] +
+					     ddr_getval(ch,
+							_reg_PI_MR14_DATA_Fx_CSx
+							[1][ddr_csn])) / 2;
+					ddr_setval(ch,
+						   _reg_PI_MR14_DATA_Fx_CSx[1]
+						   [ddr_csn],
+						   mr14_bkup[ch][ddr_csn]);
+				}
+			}
+
+			ddr_setval_ach(_reg_PI_WDQLVL_VREF_NORMAL_STEPSIZE,
+				       0x00);
+			if ((Prr_Product == PRR_PRODUCT_M3N)
+			    || (Prr_Product == PRR_PRODUCT_V3H)) {
+				ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA_F1,
+					       0x00);
+				ddr_setval_ach
+				    (_reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F1,
+				     0x00);
+				ddr_setval_ach
+				    (_reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F1,
+				     0x00);
+			} else {
+				ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA, 0x00);
+				ddr_setval_ach
+				    (_reg_PI_WDQLVL_VREF_INITIAL_START_POINT,
+				     0x00);
+				ddr_setval_ach
+				    (_reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT,
+				     0x00);
+			}
+			ddr_setval_ach(_reg_PI_WDQLVL_VREF_INITIAL_STEPSIZE,
+				       0x00);
+
+			pvtcode_update2();
+			err = wdqdm_man1();
+			ddr_setval_ach(_reg_PI_WDQLVL_VREF_EN, 0x00);
+		}
+	} while (err && (++retry_cnt < retry_max));
+
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+	    || ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut <= PRR_PRODUCT_10))) {
+		wdqdm_cp(0, 1);
+	}
+
+	return (retry_cnt >= retry_max);
+}
+
+/*******************************************************************************
+ *	RDQ TRAINING
+ ******************************************************************************/
+#ifndef DDR_FAST_INIT
+static void rdqdm_clr1(uint32_t ch, uint32_t ddr_csn)
+{
+	int32_t i, k;
+	uint32_t cs, slice;
+	uint32_t dataL;
+
+	/***********************************************************************
+	clr of training results buffer
+	***********************************************************************/
+	cs = ddr_csn % 2;
+	dataL = Boardcnf->dqdm_dly_r;
+	for (slice = 0; slice < SLICE_CNT; slice++) {
+		k = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+		if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2)))
+			continue;
+
+		for (i = 0; i <= 8; i++) {
+			if (ch_have_this_cs[CS_CNT - 1 - cs] & (1U << ch)) {
+				rdqdm_dly[ch][cs][slice][i] =
+				    rdqdm_dly[ch][CS_CNT - 1 - cs][slice][i];
+				rdqdm_dly[ch][cs][slice + SLICE_CNT][i] =
+				    rdqdm_dly[ch][CS_CNT - 1 - cs][slice +
+								   SLICE_CNT]
+				    [i];
+			} else {
+				rdqdm_dly[ch][cs][slice][i] = dataL;
+				rdqdm_dly[ch][cs][slice + SLICE_CNT][i] = dataL;
+			}
+			rdqdm_le[ch][cs][slice][i] = 0;
+			rdqdm_le[ch][cs][slice + SLICE_CNT][i] = 0;
+			rdqdm_te[ch][cs][slice][i] = 0;
+			rdqdm_te[ch][cs][slice + SLICE_CNT][i] = 0;
+			rdqdm_nw[ch][cs][slice][i] = 0;
+			rdqdm_nw[ch][cs][slice + SLICE_CNT][i] = 0;
+		}
+		rdqdm_st[ch][cs][slice] = 0;
+		rdqdm_win[ch][cs][slice] = 0;
+	}
+}
+
+static uint32_t rdqdm_ana1(uint32_t ch, uint32_t ddr_csn)
+{
+	int32_t i, k;
+	uint32_t cs, slice;
+	uint32_t dataL;
+	uint32_t err;
+	int8_t _adj;
+	int16_t adj;
+	uint32_t dq;
+	int32_t min_win;
+	int32_t win;
+	uint32_t rdq_status_obs_select;
+
+	/***********************************************************************
+	analysis of training results
+	***********************************************************************/
+	err = 0;
+	for (slice = 0; slice < SLICE_CNT; slice++) {
+		k = (Boardcnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f;
+		if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2)))
+			continue;
+
+		cs = ddr_csn % 2;
+		ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, cs);
+		ddrphy_regif_idle();
+
+		ddr_getval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX);
+		ddrphy_regif_idle();
+
+		for (i = 0; i <= 8; i++) {
+			dq = slice * 8 + i;
+			if (i == 8)
+				_adj = Boardcnf->ch[ch].dm_adj_r[slice];
+			else
+				_adj = Boardcnf->ch[ch].dq_adj_r[dq];
+
+			adj = _f_scale_adj(_adj);
+
+			dataL =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i]) +
+			    adj;
+			ddr_setval_s(ch, slice,
+				     _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i],
+				     dataL);
+			rdqdm_dly[ch][cs][slice][i] = dataL;
+
+			dataL =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i]) +
+			    adj;
+			ddr_setval_s(ch, slice,
+				     _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i],
+				     dataL);
+			rdqdm_dly[ch][cs][slice + SLICE_CNT][i] = dataL;
+		}
+		min_win = INT_LEAST32_MAX;
+		for (i = 0; i <= 8; i++) {
+			dataL =
+			    ddr_getval_s(ch, slice, _reg_PHY_RDLVL_STATUS_OBS);
+			rdqdm_st[ch][cs][slice] = dataL;
+			rdqdm_st[ch][cs][slice + SLICE_CNT] = dataL;
+			/* k : rise/fall */
+			for (k = 0; k < 2; k++) {
+				if (i == 8) {
+					rdq_status_obs_select = 16 + 8 * k;
+				} else {
+					rdq_status_obs_select = i + k * 8;
+				}
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_RDLVL_RDDQS_DQ_OBS_SELECT,
+					     rdq_status_obs_select);
+
+				dataL =
+				    ddr_getval_s(ch, slice,
+						 _reg_PHY_RDLVL_RDDQS_DQ_LE_DLY_OBS);
+				rdqdm_le[ch][cs][slice + SLICE_CNT * k][i] =
+				    dataL;
+
+				dataL =
+				    ddr_getval_s(ch, slice,
+						 _reg_PHY_RDLVL_RDDQS_DQ_TE_DLY_OBS);
+				rdqdm_te[ch][cs][slice + SLICE_CNT * k][i] =
+				    dataL;
+
+				dataL =
+				    ddr_getval_s(ch, slice,
+						 _reg_PHY_RDLVL_RDDQS_DQ_NUM_WINDOWS_OBS);
+				rdqdm_nw[ch][cs][slice + SLICE_CNT * k][i] =
+				    dataL;
+
+				win =
+				    (int32_t) rdqdm_te[ch][cs][slice +
+							       SLICE_CNT *
+							       k][i] -
+				    rdqdm_le[ch][cs][slice + SLICE_CNT * k][i];
+				if (i != 8) {
+					if (min_win > win)
+						min_win = win;
+				}
+			}
+		}
+		rdqdm_win[ch][cs][slice] = min_win;
+		if (min_win <= 0) {
+			err = 2;
+		}
+	}
+	return (err);
+}
+#endif/* DDR_FAST_INIT */
+
+static uint32_t rdqdm_man1(void)
+{
+	uint32_t ch;
+	uint32_t ddr_csn;
+#ifdef DDR_FAST_INIT
+	uint32_t slice;
+	uint32_t i, adj, dataL;
+#endif/* DDR_FAST_INIT */
+	uint32_t err;
+
+	/***********************************************************************
+	manual execution of training
+	***********************************************************************/
+	err = 0;
+
+	for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) {
+		/* KICK RDQLVL */
+		err = swlvl1(ddr_csn, _reg_PI_RDLVL_CS, _reg_PI_RDLVL_REQ);
+		if (err)
+			goto err_exit;
+#ifndef DDR_FAST_INIT
+		foreach_vch(ch) {
+			if (!(ch_have_this_cs[ddr_csn % 2] & (1U << ch))) {
+				rdqdm_clr1(ch, ddr_csn);
+				ddrphy_regif_idle();
+				continue;
+			}
+			err = rdqdm_ana1(ch, ddr_csn);
+			ddrphy_regif_idle();
+			if (err)
+				goto err_exit;
+		}
+#else/* DDR_FAST_INIT */
+		foreach_vch(ch) {
+			if (ch_have_this_cs[ddr_csn] & (1U << ch)) {
+				for (slice = 0; slice < SLICE_CNT; slice++) {
+					if (ddr_getval_s(ch, slice,
+					    _reg_PHY_RDLVL_STATUS_OBS) !=
+					    0x0D00FFFF) {
+						err = (1U << ch) |
+							(0x10U << slice);
+						goto err_exit;
+					}
+				}
+			}
+			if (((Prr_Product == PRR_PRODUCT_H3)
+			    && (Prr_Cut <= PRR_PRODUCT_11))
+			    || ((Prr_Product == PRR_PRODUCT_M3)
+			    && (Prr_Cut <= PRR_PRODUCT_10))) {
+				for (slice = 0; slice < SLICE_CNT; slice++) {
+					for (i = 0; i <= 8; i++) {
+						if (i == 8)
+							adj = _f_scale_adj(Boardcnf->ch[ch].dm_adj_r[slice]);
+						else
+							adj = _f_scale_adj(Boardcnf->ch[ch].dq_adj_r[slice * 8 + i]);
+						ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, ddr_csn);
+						dataL = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i]) + adj;
+						ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i], dataL);
+						rdqdm_dly[ch][ddr_csn][slice][i] = dataL;
+						rdqdm_dly[ch][ddr_csn | 1][slice][i] = dataL;
+
+						dataL = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i]) + adj;
+						ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i], dataL);
+						rdqdm_dly[ch][ddr_csn][slice + SLICE_CNT][i] = dataL;
+						rdqdm_dly[ch][ddr_csn | 1][slice + SLICE_CNT][i] = dataL;
+					}
+				}
+			}
+		}
+		ddrphy_regif_idle();
+
+#endif/* DDR_FAST_INIT */
+	}
+
+err_exit:
+	return (err);
+}
+
+static uint32_t rdqdm_man(void)
+{
+	uint32_t err, retry_cnt;
+	const uint32_t retry_max = 0x01;
+
+	ddr_setval_ach_as(_reg_PHY_DQ_TSEL_ENABLE,
+			  0x00000004 | ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+						     _reg_PHY_DQ_TSEL_ENABLE));
+	ddr_setval_ach_as(_reg_PHY_DQS_TSEL_ENABLE,
+			  0x00000004 | ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+						     _reg_PHY_DQS_TSEL_ENABLE));
+	ddr_setval_ach_as(_reg_PHY_DQ_TSEL_SELECT,
+			  0xFF0FFFFF & ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+						     _reg_PHY_DQ_TSEL_SELECT));
+	ddr_setval_ach_as(_reg_PHY_DQS_TSEL_SELECT,
+			  0xFF0FFFFF & ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+						     _reg_PHY_DQS_TSEL_SELECT));
+
+	retry_cnt = 0;
+	do {
+		err = rdqdm_man1();
+		ddrphy_regif_idle();
+	} while (err && (++retry_cnt < retry_max));
+	ddr_setval_ach_as(_reg_PHY_DQ_TSEL_ENABLE,
+			  ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+					_reg_PHY_DQ_TSEL_ENABLE));
+	ddr_setval_ach_as(_reg_PHY_DQS_TSEL_ENABLE,
+			  ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+					_reg_PHY_DQS_TSEL_ENABLE));
+	ddr_setval_ach_as(_reg_PHY_DQ_TSEL_SELECT,
+			  ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+					_reg_PHY_DQ_TSEL_SELECT));
+	ddr_setval_ach_as(_reg_PHY_DQS_TSEL_SELECT,
+			  ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET,
+					_reg_PHY_DQS_TSEL_SELECT));
+
+	return (retry_cnt >= retry_max);
+}
+
+/*******************************************************************************
+ *	rx offset calibration
+ ******************************************************************************/
+static int32_t _find_change(uint64_t val, uint32_t dir)
+{
+	int32_t i;
+	uint32_t startval;
+	uint32_t curval;
+	const int32_t VAL_END = 0x3f;
+
+	if (dir == 0) {
+		startval = (val & 0x01);
+		for (i = 1; i <= VAL_END; i++) {
+			curval = (val >> i) & 0x01;
+			if (curval != startval)
+				return (i);
+		}
+		return (VAL_END);
+	} else {
+		startval = (val >> dir) & 0x01;
+		for (i = dir - 1; i >= 0; i--) {
+			curval = (val >> i) & 0x01;
+			if (curval != startval)
+				return (i);
+		}
+		return (0);
+	}
+}
+
+static uint32_t _rx_offset_cal_updn(uint32_t code)
+{
+	const uint32_t CODE_MAX = 0x40;
+	uint32_t tmp;
+
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11)) {
+		if (code == 0)
+			tmp = (1U << 6) | (CODE_MAX - 1);
+		else if (code <= 0x20)
+			tmp =
+			    ((CODE_MAX - 1 -
+			      (0x20 - code) * 2) << 6) | (CODE_MAX - 1);
+		else
+			tmp =
+			    ((CODE_MAX - 1) << 6) | (CODE_MAX - 1 -
+						     (code - 0x20) * 2);
+	} else {
+		if (code == 0)
+			tmp = (1U << 6) | (CODE_MAX - 1);
+		else
+			tmp = (code << 6) | (CODE_MAX - code);
+	}
+	return tmp;
+}
+
+static uint32_t rx_offset_cal(void)
+{
+	uint32_t index;
+	uint32_t code;
+	const uint32_t CODE_MAX = 0x40;
+	const uint32_t CODE_STEP = 2;
+	uint32_t ch, slice;
+	uint32_t tmp;
+	uint32_t tmp_ach_as[DRAM_CH_CNT][SLICE_CNT];
+	uint64_t val[DRAM_CH_CNT][SLICE_CNT][_reg_PHY_RX_CAL_X_NUM];
+	uint64_t tmpval;
+	int32_t lsb, msb;
+
+	ddr_setval_ach_as(_reg_PHY_RX_CAL_OVERRIDE, 0x01);
+	foreach_vch(ch) {
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) {
+				val[ch][slice][index] = 0;
+			}
+		}
+	}
+
+	for (code = 0; code < CODE_MAX / CODE_STEP; code++) {
+		tmp = _rx_offset_cal_updn(code * CODE_STEP);
+		for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) {
+			ddr_setval_ach_as(_reg_PHY_RX_CAL_X[index], tmp);
+		}
+		dsb_sev();
+		ddr_getval_ach_as(_reg_PHY_RX_CAL_OBS, (uint32_t *) tmp_ach_as);
+
+		foreach_vch(ch) {
+			for (slice = 0; slice < SLICE_CNT; slice++) {
+				tmp = tmp_ach_as[ch][slice];
+				for (index = 0; index < _reg_PHY_RX_CAL_X_NUM;
+				     index++) {
+					if (tmp & (1U << index)) {
+						val[ch][slice][index] |=
+						    (1ULL << code);
+					} else {
+						val[ch][slice][index] &=
+						    ~(1ULL << code);
+					}
+				}
+			}
+		}
+	}
+	foreach_vch(ch) {
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) {
+				tmpval = val[ch][slice][index];
+				lsb = _find_change(tmpval, 0);
+				msb =
+				    _find_change(tmpval,
+						 (CODE_MAX / CODE_STEP) - 1);
+				tmp = (lsb + msb) >> 1;
+
+				tmp = _rx_offset_cal_updn(tmp * CODE_STEP);
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_RX_CAL_X[index], tmp);
+			}
+		}
+	}
+	ddr_setval_ach_as(_reg_PHY_RX_CAL_OVERRIDE, 0x00);
+
+	return 0;
+}
+
+static uint32_t rx_offset_cal_hw(void)
+{
+	uint32_t ch, slice;
+	uint32_t retry;
+	uint32_t complete;
+	uint32_t tmp;
+	uint32_t tmp_ach_as[DRAM_CH_CNT][SLICE_CNT];
+
+	ddr_setval_ach_as(_reg_PHY_RX_CAL_X[9], 0x00);
+	ddr_setval_ach_as(_reg_PHY_RX_CAL_OVERRIDE, 0x00);
+	ddr_setval_ach_as(_reg_PHY_RX_CAL_SAMPLE_WAIT, 0x0f);
+
+	retry = 0;
+	while (retry < 4096) {
+		if ((retry & 0xff) == 0) {
+			ddr_setval_ach_as(_reg_SC_PHY_RX_CAL_START, 0x01);
+		}
+		foreach_vch(ch)
+		    for (slice = 0; slice < SLICE_CNT; slice++)
+			tmp_ach_as[ch][slice] =
+			    ddr_getval_s(ch, slice, _reg_PHY_RX_CAL_X[9]);
+
+		complete = 1;
+		foreach_vch(ch) {
+			for (slice = 0; slice < SLICE_CNT; slice++) {
+				tmp = tmp_ach_as[ch][slice];
+				tmp = (tmp & 0x3f) + ((tmp >> 6) & 0x3f);
+				if (((Prr_Product == PRR_PRODUCT_H3)
+				     && (Prr_Cut > PRR_PRODUCT_11))
+				    || (Prr_Product == PRR_PRODUCT_M3N)
+				    || (Prr_Product == PRR_PRODUCT_V3H)) {
+					if (tmp != 0x3E)
+						complete = 0;
+				} else {
+					if (tmp != 0x40)
+						complete = 0;
+				}
+			}
+		}
+		if (complete)
+			break;
+
+		retry++;
+	}
+
+	return (complete == 0);
+}
+
+/*******************************************************************************
+ *	adjust rddqs latency
+ ******************************************************************************/
+static void adjust_rddqs_latency(void)
+{
+	uint32_t ch, slice;
+	uint32_t dly;
+	uint32_t maxlatx2;
+	uint32_t tmp;
+	uint32_t rdlat_adjx2[SLICE_CNT];
+	foreach_vch(ch) {
+		maxlatx2 = 0;
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX,
+				     0x00);
+
+			dly =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_RDDQS_GATE_SLAVE_DELAY);
+			tmp =
+			    ddr_getval_s(ch, slice,
+					 _reg_PHY_RDDQS_LATENCY_ADJUST);
+			/* note gate_slave_delay[9] is always 0 */
+			tmp = (tmp << 1) + (dly >> 8);
+			rdlat_adjx2[slice] = tmp;
+			if (maxlatx2 < tmp)
+				maxlatx2 = tmp;
+		}
+		maxlatx2 = ((maxlatx2 + 1) >> 1) << 1;
+		for (slice = 0; slice < SLICE_CNT; slice++) {
+			tmp = maxlatx2 - rdlat_adjx2[slice];
+			tmp = (tmp >> 1);
+			if (tmp) {
+				ddr_setval_s(ch, slice, _reg_PHY_RPTR_UPDATE,
+					     ddr_getval_s(ch, slice,
+							  _reg_PHY_RPTR_UPDATE)
+					     + 1);
+			}
+		}
+	}
+}
+
+/*******************************************************************************
+ *	adjust wpath latency
+ ******************************************************************************/
+static void adjust_wpath_latency(void)
+{
+	uint32_t ch, cs, slice;
+	uint32_t dly;
+	uint32_t wpath_add;
+	const uint32_t _par_EARLY_THRESHOLD_VAL = 0x180;
+
+	foreach_vch(ch) {
+		for (slice = 0; slice < SLICE_CNT; slice += 1) {
+			for (cs = 0; cs < CS_CNT; cs++) {
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_PER_CS_TRAINING_INDEX,
+					     cs);
+				ddr_getval_s(ch, slice,
+					     _reg_PHY_PER_CS_TRAINING_INDEX);
+				dly =
+				    ddr_getval_s(ch, slice,
+						 _reg_PHY_CLK_WRDQS_SLAVE_DELAY);
+				if (dly <= _par_EARLY_THRESHOLD_VAL)
+					continue;
+
+				wpath_add =
+				    ddr_getval_s(ch, slice,
+						 _reg_PHY_WRITE_PATH_LAT_ADD);
+				ddr_setval_s(ch, slice,
+					     _reg_PHY_WRITE_PATH_LAT_ADD,
+					     wpath_add - 1);
+			}
+		}
+	}
+}
+
+/*******************************************************************************
+ *	DDR Initialize entry
+ ******************************************************************************/
+int32_t rcar_dram_init(void)
+{
+	uint32_t ch, cs;
+	uint32_t dataL;
+	uint32_t bus_mbps, bus_mbpsdiv;
+	uint32_t tmp_tccd;
+	uint32_t failcount;
+
+	/***********************************************************************
+	Thermal sensor setting
+	***********************************************************************/
+	dataL = mmio_read_32(CPG_MSTPSR5);
+	if (dataL & BIT(22)) {	/*  case THS/TSC Standby */
+		dataL &= ~(BIT(22));
+		cpg_write_32(CPG_SMSTPCR5, dataL);
+		while ((BIT(22)) & mmio_read_32(CPG_MSTPSR5));  /*  wait bit=0 */
+	}
+
+	/* THCTR Bit6: PONM=0 , Bit0: THSST=0   */
+	dataL = mmio_read_32(THS1_THCTR) & 0xFFFFFFBE;
+	mmio_write_32(THS1_THCTR, dataL);
+
+	/***********************************************************************
+	Judge product and cut
+	***********************************************************************/
+#ifdef RCAR_DDR_FIXED_LSI_TYPE
+#if(RCAR_LSI==RCAR_AUTO)
+	Prr_Product = mmio_read_32(PRR) & PRR_PRODUCT_MASK;
+	Prr_Cut = mmio_read_32(PRR) & PRR_CUT_MASK;
+#else /* RCAR_LSI */
+#ifndef RCAR_LSI_CUT
+	Prr_Cut = mmio_read_32(PRR) & PRR_CUT_MASK;
+#endif /* RCAR_LSI_CUT */
+#endif /* RCAR_LSI */
+#else /* RCAR_DDR_FIXED_LSI_TYPE */
+	Prr_Product = mmio_read_32(PRR) & PRR_PRODUCT_MASK;
+	Prr_Cut = mmio_read_32(PRR) & PRR_CUT_MASK;
+#endif /* RCAR_DDR_FIXED_LSI_TYPE */
+
+	if (Prr_Product == PRR_PRODUCT_H3) {
+		if (Prr_Cut <= PRR_PRODUCT_11) {
+			pDDR_REGDEF_TBL = (const uint32_t *)&DDR_REGDEF_TBL[0][0];
+		} else {
+			pDDR_REGDEF_TBL = (const uint32_t *)&DDR_REGDEF_TBL[2][0];
+		}
+	} else if (Prr_Product == PRR_PRODUCT_M3) {
+		pDDR_REGDEF_TBL = (const uint32_t *)&DDR_REGDEF_TBL[1][0];
+	} else if ((Prr_Product == PRR_PRODUCT_M3N)
+		   || (Prr_Product == PRR_PRODUCT_V3H)) {
+		pDDR_REGDEF_TBL = (const uint32_t *)&DDR_REGDEF_TBL[3][0];
+	} else {
+		FATAL_MSG("BL2: DDR:Unknown Product\n");
+		return 0xff;
+	}
+
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+	    || ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut < PRR_PRODUCT_30))) {
+		/* non : H3 Ver.1.x/M3-W Ver.1.x not support */
+	} else {
+		mmio_write_32(DBSC_DBSYSCNT0, 0x00001234);
+	}
+
+	/***********************************************************************
+	Judge board type
+	***********************************************************************/
+	_cnf_BOARDTYPE = boardcnf_get_brd_type();
+	if (_cnf_BOARDTYPE >= BOARDNUM) {
+		FATAL_MSG("BL2: DDR:Unknown Board\n");
+		return 0xff;
+	}
+	Boardcnf = (const struct _boardcnf *)&boardcnfs[_cnf_BOARDTYPE];
+
+/* RCAR_DRAM_SPLIT_2CH           (2U) */
+#if RCAR_DRAM_SPLIT == 2
+	/***********************************************************************
+	H3(Test for future H3-N): Swap ch2 and ch1 for 2ch-split
+	***********************************************************************/
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Boardcnf->phyvalid == 0x05)) {
+		mmio_write_32(DBSC_DBMEMSWAPCONF0, 0x00000006);
+		ddr_phyvalid = 0x03;
+	} else {
+		ddr_phyvalid = Boardcnf->phyvalid;
+	}
+#else /* RCAR_DRAM_SPLIT_2CH */
+	ddr_phyvalid = Boardcnf->phyvalid;
+#endif /* RCAR_DRAM_SPLIT_2CH */
+
+	max_density = 0;
+
+	for (cs = 0; cs < CS_CNT; cs++) {
+		ch_have_this_cs[cs] = 0;
+	}
+
+	foreach_ech(ch)
+	    for (cs = 0; cs < CS_CNT; cs++)
+		ddr_density[ch][cs] = 0xff;
+
+	foreach_vch(ch) {
+		for (cs = 0; cs < CS_CNT; cs++) {
+			dataL = Boardcnf->ch[ch].ddr_density[cs];
+			ddr_density[ch][cs] = dataL;
+
+			if (dataL == 0xff)
+				continue;
+			if (dataL > max_density)
+				max_density = dataL;
+			if ((cs == 1) && (Prr_Product == PRR_PRODUCT_H3)
+			    && (Prr_Cut <= PRR_PRODUCT_11))
+				continue;
+			ch_have_this_cs[cs] |= (1U << ch);
+		}
+	}
+
+	/***********************************************************************
+	Judge board clock frequency (in MHz)
+	***********************************************************************/
+	boardcnf_get_brd_clk(_cnf_BOARDTYPE, &brd_clk, &brd_clkdiv);
+	if ((brd_clk / brd_clkdiv) > 25) {
+		brd_clkdiva = 1;
+	} else {
+		brd_clkdiva = 0;
+	}
+
+	/***********************************************************************
+	Judge ddr operating frequency clock(in Mbps)
+	***********************************************************************/
+	boardcnf_get_ddr_mbps(_cnf_BOARDTYPE, &ddr_mbps, &ddr_mbpsdiv);
+
+	ddr0800_mul = CLK_DIV(800, 2, brd_clk, brd_clkdiv * (brd_clkdiva + 1));
+
+	ddr_mul =
+	    CLK_DIV(ddr_mbps, ddr_mbpsdiv * 2, brd_clk,
+		    brd_clkdiv * (brd_clkdiva + 1));
+
+	/***********************************************************************
+	Adjust tccd
+	***********************************************************************/
+	dataL = (0x00006000 & mmio_read_32(RST_MODEMR)) >> 13;
+	bus_mbps = 0;
+	bus_mbpsdiv = 0;
+	switch (dataL) {
+	case 0:
+		bus_mbps = brd_clk * 0x60 * 2;
+		bus_mbpsdiv = brd_clkdiv * 1;
+		break;
+	case 1:
+		bus_mbps = brd_clk * 0x50 * 2;
+		bus_mbpsdiv = brd_clkdiv * 1;
+		break;
+	case 2:
+		bus_mbps = brd_clk * 0x40 * 2;
+		bus_mbpsdiv = brd_clkdiv * 1;
+		break;
+	case 3:
+		bus_mbps = brd_clk * 0x60 * 2;
+		bus_mbpsdiv = brd_clkdiv * 2;
+		break;
+	default:
+		bus_mbps = brd_clk * 0x60 * 2;
+		bus_mbpsdiv = brd_clkdiv * 2;
+		break;
+	}
+	tmp_tccd = CLK_DIV(ddr_mbps * 8, ddr_mbpsdiv, bus_mbps, bus_mbpsdiv);
+	if (8 * ddr_mbps * bus_mbpsdiv != tmp_tccd * bus_mbps * ddr_mbpsdiv)
+		tmp_tccd = tmp_tccd + 1;
+
+	if (tmp_tccd < 8)
+		ddr_tccd = 8;
+	else
+		ddr_tccd = tmp_tccd;
+
+	NOTICE("BL2: DDR%d(%s)\n", ddr_mbps / ddr_mbpsdiv, RCAR_DDR_VERSION);
+
+	MSG_LF("Start\n");
+
+	/***********************************************************************
+	PLL Setting
+	***********************************************************************/
+	pll3_control(1);
+
+	/***********************************************************************
+	initialize DDR
+	***********************************************************************/
+	dataL = init_ddr();
+	if (dataL == ddr_phyvalid) {
+		failcount = 0;
+	} else {
+		failcount = 1;
+	}
+
+	foreach_vch(ch)
+	    mmio_write_32(DBSC_DBPDLK(ch), 0x00000000);
+	if (((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut <= PRR_PRODUCT_11))
+	    || ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut < PRR_PRODUCT_30))) {
+		/* non : H3 Ver.1.x/M3-W Ver.1.x not support */
+	} else {
+		mmio_write_32(DBSC_DBSYSCNT0, 0x00000000);
+	}
+
+	if (failcount == 0) {
+		return INITDRAM_OK;
+	} else {
+		return INITDRAM_NG;
+	}
+}
+
+void pvtcode_update(void)
+{
+	uint32_t ch;
+	uint32_t dataL;
+	uint32_t pvtp[4], pvtn[4], pvtp_init, pvtn_init;
+	int32_t pvtp_tmp, pvtn_tmp;
+
+	foreach_vch(ch) {
+		pvtn_init = (tcal.tcomp_cal[ch] & 0xFC0) >> 6;
+		pvtp_init = (tcal.tcomp_cal[ch] & 0x03F) >> 0;
+
+		if (8912 * pvtp_init > 44230) {
+			pvtp_tmp = (5000 + 8912 * pvtp_init - 44230) / 10000;
+		} else {
+			pvtp_tmp =
+			    -((-(5000 + 8912 * pvtp_init - 44230)) / 10000);
+		}
+		pvtn_tmp = (5000 + 5776 * pvtn_init + 30280) / 10000;
+
+		pvtn[ch] = pvtn_tmp + pvtn_init;
+		pvtp[ch] = pvtp_tmp + pvtp_init;
+
+		if (pvtn[ch] > 63) {
+			pvtn[ch] = 63;
+			pvtp[ch] =
+			    (pvtp_tmp) * (63 - 6 * pvtn_tmp -
+					  pvtn_init) / (pvtn_tmp) +
+			    6 * pvtp_tmp + pvtp_init;
+		}
+		if ((Prr_Product == PRR_PRODUCT_H3)
+		    && (Prr_Cut <= PRR_PRODUCT_11)) {
+			dataL = pvtp[ch] | (pvtn[ch] << 6) | (tcal.tcomp_cal[ch] & 0xfffff000);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_FDBK_TERM),
+					 dataL | 0x00020000);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_DATA_TERM),
+					 dataL);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_DQS_TERM),
+					 dataL);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_ADDR_TERM),
+					 dataL);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_CS_TERM),
+					 dataL);
+		} else {
+			dataL = pvtp[ch] | (pvtn[ch] << 6) | 0x00015000;
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_FDBK_TERM),
+					 dataL | 0x00020000);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_DATA_TERM),
+					 dataL);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_DQS_TERM),
+					 dataL);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_ADDR_TERM),
+					 dataL);
+			reg_ddrphy_write(ch,
+					 ddr_regdef_adr(_reg_PHY_PAD_CS_TERM),
+					 dataL);
+		}
+	}
+}
+
+void pvtcode_update2(void)
+{
+	uint32_t ch;
+	foreach_vch(ch) {
+		reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_FDBK_TERM),
+				 tcal.init_cal[ch] | 0x00020000);
+		reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DATA_TERM),
+				 tcal.init_cal[ch]);
+		reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DQS_TERM),
+				 tcal.init_cal[ch]);
+		reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_ADDR_TERM),
+				 tcal.init_cal[ch]);
+		reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_CS_TERM),
+				 tcal.init_cal[ch]);
+	}
+}
+
+void ddr_padcal_tcompensate_getinit(uint32_t override)
+{
+	uint32_t ch;
+	uint32_t dataL;
+	uint32_t pvtp, pvtn;
+
+	tcal.init_temp = 0;
+	for (ch = 0; ch < 4; ch++) {
+		tcal.init_cal[ch] = 0;
+		tcal.tcomp_cal[ch] = 0;
+	}
+
+	foreach_vch(ch) {
+		tcal.init_cal[ch] = ddr_getval(ch, _reg_PHY_PAD_TERM_X[1]);
+		tcal.tcomp_cal[ch] = ddr_getval(ch, _reg_PHY_PAD_TERM_X[1]);
+	}
+
+	if (!override) {
+		dataL = mmio_read_32(THS1_TEMP);
+		if (dataL < 2800) {
+			tcal.init_temp =
+			    (143 * (int32_t) dataL - 359000) / 1000;
+		} else {
+			tcal.init_temp =
+			    (121 * (int32_t) dataL - 296300) / 1000;
+		}
+
+		foreach_vch(ch) {
+			pvtp = (tcal.init_cal[ch] >> 0) & 0x000003F;
+			pvtn = (tcal.init_cal[ch] >> 6) & 0x000003F;
+			if ((int32_t) pvtp >
+			    ((tcal.init_temp * 29 - 3625) / 1000))
+				pvtp =
+				    (int32_t) pvtp +
+				    ((3625 - tcal.init_temp * 29) / 1000);
+			else
+				pvtp = 0;
+
+			if ((int32_t) pvtn >
+			    ((tcal.init_temp * 54 - 6750) / 1000))
+				pvtn =
+				    (int32_t) pvtn +
+				    ((6750 - tcal.init_temp * 54) / 1000);
+			else
+				pvtn = 0;
+
+			if ((Prr_Product == PRR_PRODUCT_H3)
+			    && (Prr_Cut <= PRR_PRODUCT_11)) {
+				tcal.init_cal[ch] =
+				    (tcal.
+				     init_cal[ch] & 0xfffff000) | (pvtn << 6) |
+				    (pvtp);
+			} else {
+				tcal.init_cal[ch] =
+				    0x00015000 | (pvtn << 6) | (pvtp);
+			}
+		}
+		tcal.init_temp = 125;
+	}
+}
+
+#ifndef ddr_qos_init_setting
+/*  for QoS init */
+uint8_t get_boardcnf_phyvalid(void)
+{
+	return ddr_phyvalid;
+}
+#endif /* ddr_qos_init_setting */
+
+/*******************************************************************************
+ *	END
+ ******************************************************************************/
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_config.c b/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_config.c
new file mode 100644
index 0000000..5d1b078
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_config.c
@@ -0,0 +1,1784 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define BOARDNUM 22
+#define BOARD_JUDGE_AUTO
+
+#ifdef BOARD_JUDGE_AUTO
+static uint32_t _board_judge(void);
+
+static uint32_t boardcnf_get_brd_type(void)
+{
+	return _board_judge();
+}
+#else
+static uint32_t boardcnf_get_brd_type(void)
+{
+	return (1);
+}
+#endif
+
+#define DDR_FAST_INIT
+
+struct _boardcnf_ch {
+	uint8_t ddr_density[CS_CNT];
+	uint64_t ca_swap;
+	uint16_t dqs_swap;
+	uint32_t dq_swap[SLICE_CNT];
+	uint8_t dm_swap[SLICE_CNT];
+	uint16_t wdqlvl_patt[16];
+	int8_t cacs_adj[16];
+	int8_t dm_adj_w[SLICE_CNT];
+	int8_t dq_adj_w[SLICE_CNT * 8];
+	int8_t dm_adj_r[SLICE_CNT];
+	int8_t dq_adj_r[SLICE_CNT * 8];
+};
+
+struct _boardcnf {
+	uint8_t phyvalid;
+	uint8_t dbi_en;
+	uint16_t cacs_dly;
+	int16_t cacs_dly_adj;
+	uint16_t dqdm_dly_w;
+	uint16_t dqdm_dly_r;
+	struct _boardcnf_ch ch[DRAM_CH_CNT];
+};
+
+#define WDQLVL_PAT {\
+	0x00AA,\
+	0x0055,\
+	0x00AA,\
+	0x0155,\
+	0x01CC,\
+	0x0133,\
+	0x00CC,\
+	0x0033,\
+	0x00F0,\
+	0x010F,\
+	0x01F0,\
+	0x010F,\
+	0x00F0,\
+	0x00F0,\
+	0x000F,\
+	0x010F}
+
+static const struct _boardcnf boardcnfs[BOARDNUM] = {
+	{
+/* boardcnf[0] RENESAS SALVATOR-X board with M3-W/SIP */
+	 .phyvalid = 0x03,
+	 .dbi_en = 0x01,
+	 .cacs_dly = 0x02c0,
+	 .cacs_dly_adj = 0,
+	 .dqdm_dly_w = 0x0300,
+	 .dqdm_dly_r = 0x00a0,
+	 .ch = {
+		{
+		 {0x02, 0x02},
+		 0x00543210U,
+		 0x3201U,
+		 {0x70612543, 0x43251670, 0x45326170, 0x10672534},
+		 {0x08, 0x08, 0x08, 0x08},
+		 WDQLVL_PAT,
+		 {0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0},
+		 {0, 0, 0, 0},
+		 {0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0},
+		 {0, 0, 0, 0},
+		 {0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0}
+		 },
+
+		{
+		 {0x02, 0x02},
+		 0x00543210,
+		 0x2310,
+		 {0x01327654, 0x34526107, 0x35421670, 0x70615324},
+		 {0x08, 0x08, 0x08, 0x08},
+		 WDQLVL_PAT,
+		 {0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0},
+		 {0, 0, 0, 0},
+		 {0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0},
+		 {0, 0, 0, 0},
+		 {0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0,
+		  0, 0, 0, 0, 0, 0, 0, 0}
+		 }
+		}
+	 },
+/* boardcnf[1] RENESAS KRIEK board with M3-W/SoC */
+	{
+	 0x03,
+	 0x01,
+	 0x2c0,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00345201,
+	   0x3201,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00302154,
+	   0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[2] RENESAS SALVATOR-X board with H3 Ver.1.x/SIP(8Gbit 1rank) */
+	{
+	 0x0f,
+	 0x00,
+	 0x300,
+	 -320,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x3210,
+	   {0x20741365, 0x34256107, 0x57460321, 0x70614532},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x3102,
+	   {0x23547610, 0x34526107, 0x67452310, 0x32106754},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x0213,
+	   {0x30216754, 0x67453210, 0x70165243, 0x07162345},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x0213,
+	   {0x01327654, 0x70615432, 0x54760123, 0x07162345},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[3] RENESAS Starter Kit board with M3-W/SIP(8Gbit 1rank) */
+	{
+	 0x03,
+	 0x01,
+	 0x02c0,
+	 0,
+	 0x0300,
+	 0x00a0,
+	 {
+	  {
+	   {0x02, 0xFF},
+	   0x00543210U,
+	   0x3201,
+	   {0x70612543, 0x43251670, 0x45326170, 0x10672534},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xFF},
+	   0x00543210,
+	   0x2310,
+	   {0x01327654, 0x34526107, 0x35421670, 0x70615324},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[4] RENESAS SALVATOR-M(1rank) board with H3 Ver.1.x/SoC */
+	{
+	 0x0f,
+	 0x00,
+	 0x2c0,
+	 -320,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0xff},
+	   0x00315024,
+	   0x3120,
+	   {0x30671254, 0x26541037, 0x17054623, 0x12307645},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00025143,
+	   0x3210,
+	   {0x70613542, 0x16245307, 0x30712645, 0x21706354},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00523104,
+	   0x2301,
+	   {0x70613542, 0x16245307, 0x30712645, 0x21706354},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00153402,
+	   0x2031,
+	   {0x30671254, 0x26541037, 0x17054623, 0x12307645},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[5] RENESAS KRIEK-1rank board with M3-W/SoC */
+	{
+	 0x03,
+	 0x01,
+	 0x2c0,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0xff},
+	   0x00345201,
+	   0x3201,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00302154,
+	   0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[6] RENESAS SALVATOR-X board with H3 Ver.1.x/SIP(8Gbit 2rank) */
+	{
+	 0x0f,
+	 0x00,
+	 0x300,
+	 -320,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x3210,
+	   {0x20741365, 0x34256107, 0x57460321, 0x70614532},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x3102,
+	   {0x23547610, 0x34526107, 0x67452310, 0x32106754},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x0213,
+	   {0x30216754, 0x67453210, 0x70165243, 0x07162345},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x0213,
+	   {0x01327654, 0x70615432, 0x54760123, 0x07162345},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[7] RENESAS SALVATOR-X board with H3 Ver.2.0 or later/SIP(8Gbit 1rank) */
+	{
+	 0x0f,
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x2310,
+	   {0x70631425, 0x34527016, 0x43527610, 0x32104567},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00105432,
+	   0x3210,
+	   {0x43256107, 0x07162354, 0x10234567, 0x01235467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x2301,
+	   {0x01327654, 0x02316457, 0x10234567, 0x01325467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x2301,
+	   {0x12034765, 0x23105467, 0x23017645, 0x32106745},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[8] RENESAS SALVATOR-X board with H3 Ver.2.0 or later/SIP(8Gbit 2rank) */
+	{
+#if RCAR_DRAM_CHANNEL == 5
+	 0x05,
+#else
+	 0x0f,
+#endif
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x2310,
+	   {0x70631425, 0x34527016, 0x43527610, 0x32104567},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+#if ((RCAR_DRAM_CHANNEL == 5) && (RCAR_DRAM_SPLIT == 2))
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x2301,
+	   {0x01327654, 0x02316457, 0x10234567, 0x01325467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+#else
+	  {
+	   {0x02, 0x02},
+	   0x00105432,
+	   0x3210,
+	   {0x43256107, 0x07162354, 0x10234567, 0x01235467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+#endif
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x2301,
+	   {0x01327654, 0x02316457, 0x10234567, 0x01325467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00543210,
+	   0x2301,
+	   {0x12034765, 0x23105467, 0x23017645, 0x32106745},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[9] RENESAS SALVATOR-MS(1rank) board with H3 Ver.2.0 or later/SoC */
+	{
+	 0x0f,
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x3210,
+	   {0x27645310, 0x75346210, 0x53467210, 0x23674510},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00543210,
+	   0x2301,
+	   {0x23764510, 0x43257610, 0x43752610, 0x37652401},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {-128, -128, -128, -128, -128, -128, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00452103,
+	   0x3210,
+	   {0x32764510, 0x43257610, 0x43752610, 0x26573401},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0xff},
+	   0x00520413,
+	   0x2301,
+	   {0x47652301, 0x75346210, 0x53467210, 0x32674501},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {30, 30, 30, 30, 30, 30, 30, 30,
+	    30, 30},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[10] RENESAS Kriek(2rank) board with M3-N/SoC */
+	{
+	 0x01,
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00345201,
+	   0x3201,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[11] RENESAS SALVATOR-X board with M3-N/SIP(8Gbit 2rank) */
+	{
+	 0x01,
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+#if (RCAR_DRAM_LPDDR4_MEMCONF == 2)
+	   {0x04, 0x04},
+#else
+	   {0x02, 0x02},
+#endif
+	   0x00342501,
+	   0x3201,
+	   {0x10672534, 0x43257106, 0x34527601, 0x71605243},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[12] RENESAS CONDOR board with V3H/SoC */
+	{
+	 0x01,
+	 0x1,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00501342,
+	   0x3201,
+	   {0x70562134, 0x34526071, 0x23147506, 0x12430567},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[13] RENESAS KRIEK board with PM3/SoC */
+	{
+	 0x05,
+	 0x00,
+	 0x2c0,
+	 -320,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00345201,
+	   0x3201,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00302154,
+	   0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00302154,
+	   0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0xff, 0xff},
+	   0,
+	   0,
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[14] SALVATOR-X board with H3 Ver.2.0 or later/SIP(16Gbit 1rank) */
+	{
+#if RCAR_DRAM_CHANNEL == 5
+	 0x05,
+#else
+	 0x0f,
+#endif
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x04, 0xff},
+	   0x00543210,
+	   0x2310,
+	   {0x70631425, 0x34527016, 0x43527610, 0x32104567},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+#if ((RCAR_DRAM_CHANNEL == 5) && (RCAR_DRAM_SPLIT == 2))
+	  {
+	   {0x04, 0xff},
+	   0x00543210,
+	   0x2301,
+	   {0x01327654, 0x02316457, 0x10234567, 0x01325467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+#else
+	  {
+	   {0x04, 0xff},
+	   0x00105432,
+	   0x3210,
+	   {0x43256107, 0x07162354, 0x10234567, 0x01235467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+#endif
+	  {
+	   {0x04, 0xff},
+	   0x00543210,
+	   0x2301,
+	   {0x01327654, 0x02316457, 0x10234567, 0x01325467},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x04, 0xff},
+	   0x00543210,
+	   0x2301,
+	   {0x12034765, 0x23105467, 0x23017645, 0x32106745},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[15] RENESAS KRIEK board with H3N */
+	{
+	 0x05,
+	 0x01,
+	 0x300,
+	 0,
+	 0x300,
+	 0x0a0,
+	 {
+	  {
+	   {0x02, 0x02},
+	   0x00345201,
+	   0x3201,
+	   {0x01672543, 0x45367012, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00302154,
+	   0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x02, 0x02},
+	   0x00302154,
+	   0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0xff, 0xff},
+	   0,
+	   0,
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[16] RENESAS KRIEK-P2P board with M3-W/SoC */
+	{
+	 0x03,
+	 0x01,
+	 0x0320,
+	 0,
+	 0x0300,
+	 0x00a0,
+	 {
+	  {
+	   {0x04, 0x04},
+	    0x520314FFFF523041,
+	    0x3201,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	    WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x04, 0x04},
+	    0x314250FFFF312405,
+	    0x2310,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	    WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   }
+	  }
+	 },
+/* boardcnf[17] RENESAS KRIEK-P2P board with M3-N/SoC */
+	{
+	 0x01,
+	 0x01,
+	 0x0300,
+	 0,
+	 0x0300,
+	 0x00a0,
+	 {
+	  {
+	   {0x04, 0x04},
+	    0x520314FFFF523041,
+	    0x3201,
+	   {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+	   {0x08, 0x08, 0x08, 0x08},
+	    WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	  }
+	 }
+	},
+/* boardcnf[18] RENESAS SALVATOR-X board with M3-W/SIP(16Gbit 2rank) */
+	{
+	 0x03,
+	 0x01,
+	 0x02c0,
+	 0,
+	 0x0300,
+	 0x00a0,
+	 {
+	  {
+	   {0x04, 0x04},
+	    0x00543210,
+	    0x3201,
+	   {0x70612543, 0x43251670, 0x45326170, 0x10672534},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x04, 0x04},
+	    0x00543210,
+	    0x2310,
+	   {0x01327654, 0x34526107, 0x35421670, 0x70615324},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	  }
+	 }
+	},
+/* boardcnf[19] RENESAS SALVATOR-X board with M3-W/SIP(16Gbit 1rank) */
+        {
+         0x03,
+         0x01,
+         0x02c0,
+         0,
+         0x0300,
+         0x00a0,
+	 {
+          {
+	   {0x04, 0xff},
+	    0x00543210,
+	    0x3201,
+	   {0x70612543, 0x43251670, 0x45326170, 0x10672534},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	   },
+	  {
+	   {0x04, 0xff},
+	    0x00543210,
+	    0x2310,
+	   {0x01327654, 0x34526107, 0x35421670, 0x70615324},
+	   {0x08, 0x08, 0x08, 0x08},
+	   WDQLVL_PAT,
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0},
+	   {0, 0, 0, 0},
+	   {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0}
+	  }
+	 }
+	},
+/* boardcnf[20] RENESAS KRIEK 16Gbit/2rank/2ch board with M3-W/SoC */
+        {
+         0x03,
+         0x01,
+         0x02c0,
+         0,
+         0x0300,
+         0x00a0,
+         {
+          {
+           {0x04, 0x04},
+            0x00345201,
+            0x3201,
+           {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+           {0x08, 0x08, 0x08, 0x08},
+            WDQLVL_PAT,
+           {0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0}
+           },
+          {
+	   {0x04, 0x04},
+            0x00302154,
+            0x2310,
+           {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+           {0x08, 0x08, 0x08, 0x08},
+           WDQLVL_PAT,
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0}
+          }
+         }
+        },
+/* boardcnf[21] RENESAS KRIEK 16Gbit/1rank/2ch board with M3-W/SoC */
+        {
+         0x03,
+         0x01,
+         0x02c0,
+         0,
+         0x0300,
+         0x00a0,
+         {
+          {
+           {0x04, 0xff},
+            0x00345201,
+            0x3201,
+           {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+           {0x08, 0x08, 0x08, 0x08},
+           WDQLVL_PAT,
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0}
+           },
+          {
+           {0x04, 0xff},
+            0x00302154,
+            0x2310,
+           {0x01672543, 0x45361207, 0x45632107, 0x60715234},
+           {0x08, 0x08, 0x08, 0x08},
+           WDQLVL_PAT,
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0},
+           {0, 0, 0, 0},
+           {0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0}
+           }
+          }
+         }
+};
+
+void boardcnf_get_brd_clk(uint32_t brd, uint32_t * clk, uint32_t * div)
+{
+	uint32_t md;
+
+	if ((Prr_Product == PRR_PRODUCT_H3) && (Prr_Cut == PRR_PRODUCT_10)) {
+		*clk = 50;
+		*div = 3;
+	} else {
+		md = (mmio_read_32(RST_MODEMR) >> 13) & 0x3;
+		switch (md) {
+		case 0x0:
+			*clk = 50;
+			*div = 3;
+			break;
+		case 0x1:
+			*clk = 60;
+			*div = 3;
+			break;
+		case 0x2:
+			*clk = 75;
+			*div = 3;
+			break;
+		case 0x3:
+			*clk = 100;
+			*div = 3;
+			break;
+		}
+	}
+	(void)brd;
+}
+
+void boardcnf_get_ddr_mbps(uint32_t brd, uint32_t * mbps, uint32_t * div)
+{
+	uint32_t md;
+
+	md = (mmio_read_32(RST_MODEMR) >> 17) & 0x5;
+	md = (md | (md >> 1)) & 0x3;
+	switch (md) {
+	case 0x0:
+		*mbps = 3200;
+		*div = 1;
+		break;
+	case 0x1:
+		*mbps = 2800;
+		*div = 1;
+		break;
+	case 0x2:
+		*mbps = 2400;
+		*div = 1;
+		break;
+	case 0x3:
+		*mbps = 1600;
+		*div = 1;
+		break;
+	}
+	(void)brd;
+}
+
+#define _def_REFPERIOD  1890
+
+#define M3_SAMPLE_TT_A84        0xB866CC10, 0x3B250421
+#define M3_SAMPLE_TT_A85        0xB866CC10, 0x3AA50421
+#define M3_SAMPLE_TT_A86        0xB866CC10, 0x3AA48421
+#define M3_SAMPLE_FF_B45        0xB866CC10, 0x3AB00C21
+#define M3_SAMPLE_FF_B49        0xB866CC10, 0x39B10C21
+#define M3_SAMPLE_FF_B56        0xB866CC10, 0x3AAF8C21
+#define M3_SAMPLE_SS_E24        0xB866CC10, 0x3BA39421
+#define M3_SAMPLE_SS_E28        0xB866CC10, 0x3C231421
+#define M3_SAMPLE_SS_E32        0xB866CC10, 0x3C241421
+
+static const uint32_t TermcodeBySample[20][3] = {
+	{M3_SAMPLE_TT_A84, 0x000158D5},
+	{M3_SAMPLE_TT_A85, 0x00015955},
+	{M3_SAMPLE_TT_A86, 0x00015955},
+	{M3_SAMPLE_FF_B45, 0x00015690},
+	{M3_SAMPLE_FF_B49, 0x00015753},
+	{M3_SAMPLE_FF_B56, 0x00015793},
+	{M3_SAMPLE_SS_E24, 0x00015996},
+	{M3_SAMPLE_SS_E28, 0x000159D7},
+	{M3_SAMPLE_SS_E32, 0x00015997},
+	{0xFFFFFFFF, 0xFFFFFFFF, 0x0001554F}
+};
+
+#ifdef BOARD_JUDGE_AUTO
+/*
+ * SAMPLE board detect function
+ */
+#define PFC_PMMR   	0xE6060000U
+#define PFC_PUEN5	0xE6060414U
+#define PFC_PUEN6	0xE6060418U
+#define PFC_PUD5	0xE6060454U
+#define PFC_PUD6	0xE6060458U
+#define GPIO_INDT5	0xE605500CU
+#define GPIO_INDT6	0xE605540CU
+#define GPIO_GPSR6 	0xE6060118U
+
+#if (RCAR_GEN3_ULCB == 0)
+static void pfc_write_and_poll(uint32_t a, uint32_t v)
+{
+	mmio_write_32(PFC_PMMR, ~v);
+	v = ~mmio_read_32(PFC_PMMR);
+	mmio_write_32(a, v);
+	while (v != mmio_read_32(a)) ;
+	dsb_sev();
+}
+#endif
+
+#ifndef RCAR_GEN3_ULCB
+#define RCAR_GEN3_ULCB		0
+#endif
+
+#if (RCAR_GEN3_ULCB == 0)	/* non Starter Kit */
+
+static uint32_t opencheck_SSI_WS6(void)
+{
+	uint32_t dataL, down, up;
+	uint32_t gpsr6_bak;
+	uint32_t puen5_bak;
+	uint32_t pud5_bak;
+
+	gpsr6_bak = mmio_read_32(GPIO_GPSR6);
+	puen5_bak = mmio_read_32(PFC_PUEN5);
+	pud5_bak = mmio_read_32(PFC_PUD5);
+	dsb_sev();
+
+	dataL = (gpsr6_bak & ~BIT(15));
+	pfc_write_and_poll(GPIO_GPSR6, dataL);
+
+	/* Pull-Up/Down Enable (PUEN5[22]=1) */
+	dataL = puen5_bak;
+	dataL |= (BIT(22));
+	pfc_write_and_poll(PFC_PUEN5, dataL);
+
+	/* Pull-Down-Enable (PUD5[22]=0, PUEN5[22]=1) */
+	dataL = pud5_bak;
+	dataL &= ~(BIT(22));
+	pfc_write_and_poll(PFC_PUD5, dataL);
+	/* GPSR6[15]=SSI_WS6 */
+	rcar_micro_delay(10);
+	down = (mmio_read_32(GPIO_INDT6) >> 15) & 0x1;
+	dsb_sev();
+
+	/* Pull-Up-Enable (PUD5[22]=1, PUEN5[22]=1) */
+	dataL = pud5_bak;
+	dataL |= (BIT(22));
+	pfc_write_and_poll(PFC_PUD5, dataL);
+
+	/* GPSR6[15]=SSI_WS6 */
+	rcar_micro_delay(10);
+	up = (mmio_read_32(GPIO_INDT6) >> 15) & 0x1;
+
+	dsb_sev();
+
+	pfc_write_and_poll(GPIO_GPSR6, gpsr6_bak);
+	pfc_write_and_poll(PFC_PUEN5, puen5_bak);
+	pfc_write_and_poll(PFC_PUD5, pud5_bak);
+
+	if (down == up) {
+		/* Same = Connect */
+		return 0;
+	} else {
+		/* Diff = Open */
+		return 1;
+	}
+}
+
+#endif
+
+static uint32_t _board_judge(void)
+{
+	uint32_t brd;
+#if (RCAR_GEN3_ULCB==1)
+	/* Starter Kit */
+	if (Prr_Product == PRR_PRODUCT_H3) {
+		if (Prr_Cut <= PRR_PRODUCT_11) {
+			/* RENESAS Starter Kit(H3 Ver.1.x/SIP) board */
+			brd = 2;
+		} else {
+			/* RENESAS Starter Kit(H3 Ver.2.0 or later/SIP) board */
+#if (RCAR_DRAM_LPDDR4_MEMCONF == 0)
+			brd = 7;
+#else
+			brd = 8;
+#endif
+		}
+	} else if (Prr_Product == PRR_PRODUCT_M3) {
+		/* RENESAS Starter Kit(M3-W/SIP 8Gbit 1rank) board */
+		brd = 3;
+	} else {
+		/* RENESAS Starter Kit(M3-N/SIP) board */
+		brd = 11;
+	}
+#else
+	uint32_t usb2_ovc_open;
+
+	usb2_ovc_open = opencheck_SSI_WS6();
+
+	/* RENESAS Eva-borad */
+	brd = 99;
+	if (Prr_Product == PRR_PRODUCT_V3H) {
+		/* RENESAS Condor board */
+		brd = 12;
+	} else if (usb2_ovc_open) {
+		if (Prr_Product == PRR_PRODUCT_M3N) {
+			/* RENESAS Kriek board with M3-N */
+			brd = 10;
+		} else if (Prr_Product == PRR_PRODUCT_M3) {
+			/* RENESAS Kriek board with M3-W */
+			brd = 1;
+		} else if ((Prr_Product == PRR_PRODUCT_H3)
+			   && (Prr_Cut<=PRR_PRODUCT_11)) {
+			/* RENESAS Kriek board with PM3 */
+			brd = 13;
+		} else if ((Prr_Product == PRR_PRODUCT_H3)
+			   && (Prr_Cut > PRR_PRODUCT_20)) {
+			/* RENESAS Kriek board with H3N */
+			brd = 15;
+		}
+	} else {
+		if (Prr_Product == PRR_PRODUCT_H3) {
+			if (Prr_Cut <= PRR_PRODUCT_11) {
+				/* RENESAS SALVATOR-X (H3 Ver.1.x/SIP) */
+				brd = 2;
+			} else if (Prr_Cut < PRR_PRODUCT_30) {
+				/* RENESAS SALVATOR-X (H3 Ver.2.0/SIP) */
+				brd = 7;	//  8Gbit/1rank
+			} else {
+				/* RENESAS SALVATOR-X (H3 Ver.3.0/SIP) */
+#if (RCAR_DRAM_LPDDR4_MEMCONF == 0)
+				brd = 7;
+#else
+				brd = 8;
+#endif
+			}
+		} else if (Prr_Product == PRR_PRODUCT_M3N) {
+			/* RENESAS SALVATOR-X (M3-N/SIP) */
+			brd = 11;
+		} else if ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut <= PRR_PRODUCT_20)) {
+			/* RENESAS SALVATOR-X (M3-W/SIP) */
+			brd = 0;
+		} else if ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut < PRR_PRODUCT_30)) {
+			/* RENESAS SALVATOR-X (M3-W Ver.1.x/SIP) */
+			brd = 19;
+		} else if ((Prr_Product == PRR_PRODUCT_M3) && (Prr_Cut >= PRR_PRODUCT_30)) {
+			/* RENESAS SALVATOR-X (M3-W ver.3.0/SIP) */
+			brd = 18;
+		}
+	}
+#endif
+
+	return brd;
+}
+#endif
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_regdef.h b/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_regdef.h
new file mode 100644
index 0000000..a1cbfbf
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_regdef.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define RCAR_DDR_VERSION	"rev.0.36"
+#define DRAM_CH_CNT		(0x04)
+#define SLICE_CNT		(0x04)
+#define CS_CNT			(0x02)
+
+/* order : CS0A, CS0B, CS1A, CS1B */
+#define CSAB_CNT		(CS_CNT * 2)
+
+/* order : CH0A, CH0B, CH1A, CH1B, CH2A, CH2B, CH3A, CH3B */
+#define CHAB_CNT		(DRAM_CH_CNT * 2)
+
+/* pll setting */
+#define CLK_DIV(a, diva, b, divb) (((a) * (divb)) /((b) * (diva)))
+#define CLK_MUL(a, diva, b, divb) (((a) * (b)) / ((diva) * (divb)))
+
+/* for ddr deisity setting */
+#define DBMEMCONF_REG(d3, row, bank, col, dw) 	\
+	((d3) << 30 | ((row) << 24) | ((bank) << 16) | ((col) << 8) | (dw))
+
+#define DBMEMCONF_REGD(density) 		\
+(DBMEMCONF_REG((density) % 2, ((density) + 1) / 2 + (29-3-10-2), 3, 10, 2))
+
+#define DBMEMCONF_VAL(ch, cs) (DBMEMCONF_REGD(DBMEMCONF_DENS(ch, cs)))
+
+/* refresh mode */
+#define DBSC_REFINTS		(0x0)
+
+/* system registers */
+#define CPG_BASE		(0xE6150000U)
+#define CPG_FRQCRB		(CPG_BASE + 0x0004U)
+
+#define CPG_PLLECR		(CPG_BASE + 0x00D0U)
+#define CPG_MSTPSR5		(CPG_BASE + 0x003CU)
+#define CPG_SRCR4		(CPG_BASE + 0x00BCU)
+#define CPG_PLL3CR		(CPG_BASE + 0x00DCU)
+#define CPG_ZB3CKCR		(CPG_BASE + 0x0380U)
+#define CPG_FRQCRD		(CPG_BASE + 0x00E4U)
+#define CPG_SMSTPCR5		(CPG_BASE + 0x0144U)
+#define CPG_CPGWPR		(CPG_BASE + 0x0900U)
+#define CPG_SRSTCLR4		(CPG_BASE + 0x0950U)
+
+#define CPG_FRQCRB_KICK_BIT	(1U<<31)
+#define CPG_PLLECR_PLL3E_BIT	(1U<<3)
+#define CPG_PLLECR_PLL3ST_BIT	(1U<<11)
+#define CPG_ZB3CKCR_ZB3ST_BIT	(1U<<11)
+
+#define RST_BASE		(0xE6160000U)
+#define RST_MODEMR		(RST_BASE + 0x0060U)
+
+#define LIFEC_CHIPID(x)		(0xE6110040U + 0x04U * (x))
+
+/* Product Register */
+#define PRR			(0xFFF00044U)
+#define PRR_PRODUCT_MASK	(0x00007F00U)
+#define PRR_CUT_MASK		(0x000000FFU)
+#define PRR_PRODUCT_H3		(0x00004F00U)	/* R-Car H3   */
+#define PRR_PRODUCT_M3		(0x00005200U)	/* R-Car M3-W */
+#define PRR_PRODUCT_M3N		(0x00005500U)	/* R-Car M3-N */
+#define PRR_PRODUCT_V3H		(0x00005600U)	/* R-Car V3H  */
+#define PRR_PRODUCT_10		(0x00U)	/*   Ver.1.0  */
+#define PRR_PRODUCT_11		(0x01U)	/*   Ver.1.1  */
+#define PRR_PRODUCT_20		(0x10U)	/*   Ver.2.0  */
+#define PRR_PRODUCT_30		(0x20U)	/*   Ver.3.0  */
+
+/* DBSC registers */
+#define DBSC_DBSYSCONF1		0xE6790004U
+#define DBSC_DBPHYCONF0		0xE6790010U
+#define DBSC_DBKIND		0xE6790020U
+
+#define DBSC_DBMEMCONF(ch, cs)	(0xE6790030U + 0x10U * (ch) + 0x04U * (cs))
+#define DBSC_DBMEMCONF_0_0	0xE6790030U
+#define DBSC_DBMEMCONF_0_1	0xE6790034U
+#define DBSC_DBMEMCONF_0_2	0xE6790038U
+#define DBSC_DBMEMCONF_0_3	0xE679003CU
+#define DBSC_DBMEMCONF_1_2	0xE6790048U
+#define DBSC_DBMEMCONF_1_3	0xE679004CU
+#define DBSC_DBMEMCONF_1_0	0xE6790040U
+#define DBSC_DBMEMCONF_1_1	0xE6790044U
+#define DBSC_DBMEMCONF_2_0	0xE6790050U
+#define DBSC_DBMEMCONF_2_1	0xE6790054U
+#define DBSC_DBMEMCONF_2_2	0xE6790058U
+#define DBSC_DBMEMCONF_2_3	0xE679005CU
+#define DBSC_DBMEMCONF_3_0	0xE6790060U
+#define DBSC_DBMEMCONF_3_1	0xE6790064U
+#define DBSC_DBMEMCONF_3_2	0xE6790068U
+#define DBSC_DBMEMCONF_3_3	0xE679006CU
+
+#define DBSC_DBSYSCNT0		0xE6790100U
+
+#define DBSC_DBACEN		0xE6790200U
+#define DBSC_DBRFEN		0xE6790204U
+#define DBSC_DBCMD		0xE6790208U
+#define DBSC_DBWAIT		0xE6790210U
+#define DBSC_DBSYSCTRL0		0xE6790280U
+
+#define DBSC_DBTR(x)		(0xE6790300U + 0x04U * (x))
+#define DBSC_DBTR0		0xE6790300U
+#define DBSC_DBTR1		0xE6790304U
+#define DBSC_DBTR3		0xE679030CU
+#define DBSC_DBTR4		0xE6790310U
+#define DBSC_DBTR5		0xE6790314U
+#define DBSC_DBTR6		0xE6790318U
+#define DBSC_DBTR7		0xE679031CU
+#define DBSC_DBTR8		0xE6790320U
+#define DBSC_DBTR9		0xE6790324U
+#define DBSC_DBTR10		0xE6790328U
+#define DBSC_DBTR11		0xE679032CU
+#define DBSC_DBTR12		0xE6790330U
+#define DBSC_DBTR13		0xE6790334U
+#define DBSC_DBTR14		0xE6790338U
+#define DBSC_DBTR15		0xE679033CU
+#define DBSC_DBTR16		0xE6790340U
+#define DBSC_DBTR17		0xE6790344U
+#define DBSC_DBTR18		0xE6790348U
+#define DBSC_DBTR19		0xE679034CU
+#define DBSC_DBTR20		0xE6790350U
+#define DBSC_DBTR21		0xE6790354U
+#define DBSC_DBTR22		0xE6790358U
+#define DBSC_DBTR23		0xE679035CU
+#define DBSC_DBTR24		0xE6790360U
+#define DBSC_DBTR25		0xE6790364U
+#define DBSC_DBTR26		0xE6790368U
+
+#define DBSC_DBBL		0xE6790400U
+#define DBSC_DBRFCNF1		0xE6790414U
+#define DBSC_DBRFCNF2		0xE6790418U
+#define DBSC_DBTSPCNF		0xE6790420U
+#define DBSC_DBCALCNF		0xE6790424U
+#define DBSC_DBRNK(x)		(0xE6790430U + 0x04U * (x))
+#define DBSC_DBRNK2		0xE6790438U
+#define DBSC_DBRNK3		0xE679043CU
+#define DBSC_DBRNK4		0xE6790440U
+#define DBSC_DBRNK5		0xE6790444U
+#define DBSC_DBODT(x)		(0xE6790460U + 0x04U * (x))
+
+#define DBSC_DBADJ0		0xE6790500U
+#define DBSC_DBDBICNT		0xE6790518U
+#define DBSC_DBDFIPMSTRCNF	0xE6790520U
+#define DBSC_DBDFICUPDCNF	0xE679052CU
+
+#define DBSC_DBDFISTAT(ch)	(0xE6790600U + 0x40U * (ch))
+#define DBSC_DBDFISTAT_0		0xE6790600U
+#define DBSC_DBDFISTAT_1		0xE6790640U
+#define DBSC_DBDFISTAT_2		0xE6790680U
+#define DBSC_DBDFISTAT_3		0xE67906C0U
+
+#define DBSC_DBDFICNT(ch)	(0xE6790604U + 0x40U * (ch))
+#define DBSC_DBDFICNT_0		0xE6790604U
+#define DBSC_DBDFICNT_1		0xE6790644U
+#define DBSC_DBDFICNT_2		0xE6790684U
+#define DBSC_DBDFICNT_3		0xE67906C4U
+
+#define DBSC_DBPDCNT0(ch)	(0xE6790610U + 0x40U * (ch))
+#define DBSC_DBPDCNT0_0		0xE6790610U
+#define DBSC_DBPDCNT0_1		0xE6790650U
+#define DBSC_DBPDCNT0_2		0xE6790690U
+#define DBSC_DBPDCNT0_3		0xE67906D0U
+
+#define DBSC_DBPDCNT1(ch)	(0xE6790614U + 0x40U * (ch))
+#define DBSC_DBPDCNT1_0		0xE6790614U
+#define DBSC_DBPDCNT1_1		0xE6790654U
+#define DBSC_DBPDCNT1_2		0xE6790694U
+#define DBSC_DBPDCNT1_3		0xE67906D4U
+
+#define DBSC_DBPDCNT2(ch)	(0xE6790618U + 0x40U * (ch))
+#define DBSC_DBPDCNT2_0		0xE6790618U
+#define DBSC_DBPDCNT2_1		0xE6790658U
+#define DBSC_DBPDCNT2_2		0xE6790698U
+#define DBSC_DBPDCNT2_3		0xE67906D8U
+
+#define DBSC_DBPDCNT3(ch)	(0xE679061CU + 0x40U * (ch))
+#define DBSC_DBPDCNT3_0		0xE679061CU
+#define DBSC_DBPDCNT3_1		0xE679065CU
+#define DBSC_DBPDCNT3_2		0xE679069CU
+#define DBSC_DBPDCNT3_3		0xE67906DCU
+
+#define DBSC_DBPDLK(ch)		(0xE6790620U + 0x40U * (ch))
+#define DBSC_DBPDLK_0		0xE6790620U
+#define DBSC_DBPDLK_1		0xE6790660U
+#define DBSC_DBPDLK_2		0xE67906a0U
+#define DBSC_DBPDLK_3		0xE67906e0U
+
+#define DBSC_DBPDRGA(ch)	(0xE6790624U + 0x40U * (ch))
+#define DBSC_DBPDRGD(ch)	(0xE6790628U + 0x40U * (ch))
+#define DBSC_DBPDRGA_0		0xE6790624U
+#define DBSC_DBPDRGD_0		0xE6790628U
+#define DBSC_DBPDRGA_1		0xE6790664U
+#define DBSC_DBPDRGD_1		0xE6790668U
+#define DBSC_DBPDRGA_2		0xE67906A4U
+#define DBSC_DBPDRGD_2		0xE67906A8U
+#define DBSC_DBPDRGA_3		0xE67906E4U
+#define DBSC_DBPDRGD_3		0xE67906E8U
+
+#define DBSC_DBPDSTAT(ch)	(0xE6790630U + 0x40U * (ch))
+#define DBSC_DBPDSTAT_0		0xE6790630U
+#define DBSC_DBPDSTAT_1		0xE6790670U
+#define DBSC_DBPDSTAT_2		0xE67906B0U
+#define DBSC_DBPDSTAT_3		0xE67906F0U
+
+#define DBSC_DBBUS0CNF0		0xE6790800U
+#define DBSC_DBBUS0CNF1		0xE6790804U
+
+#define DBSC_DBCAM0CNF1		0xE6790904U
+#define DBSC_DBCAM0CNF2		0xE6790908U
+#define DBSC_DBCAM0CNF3		0xE679090CU
+#define DBSC_DBBSWAP		0xE67909F0U
+#define DBSC_DBBCAMDIS		0xE67909FCU
+#define DBSC_DBSCHCNT0		0xE6791000U
+#define DBSC_DBSCHCNT1		0xE6791004U
+#define DBSC_DBSCHSZ0		0xE6791010U
+#define DBSC_DBSCHRW0		0xE6791020U
+#define DBSC_DBSCHRW1		0xE6791024U
+
+#define DBSC_DBSCHQOS_0(x)	(0xE6791030U +0x10U * (x))
+#define DBSC_DBSCHQOS_1(x)	(0xE6791034U +0x10U * (x))
+#define DBSC_DBSCHQOS_2(x)	(0xE6791038U +0x10U * (x))
+#define DBSC_DBSCHQOS_3(x)	(0xE679103CU +0x10U * (x))
+
+#define DBSC_DBSCTR0		0xE6791700U
+#define DBSC_DBSCTR1		0xE6791708U
+#define DBSC_DBSCHRW2		0xE679170CU
+
+#define DBSC_SCFCTST01(x)	(0xE6791700U + 0x08U * (x))
+#define DBSC_SCFCTST0		0xE6791700U
+#define DBSC_SCFCTST1		0xE6791708U
+#define DBSC_SCFCTST2		0xE679170CU
+
+#define DBSC_DBMRRDR(chab)	(0xE6791800U + 0x04U * (chab))
+#define DBSC_DBMRRDR_0		0xE6791800U
+#define DBSC_DBMRRDR_1		0xE6791804U
+#define DBSC_DBMRRDR_2		0xE6791808U
+#define DBSC_DBMRRDR_3		0xE679180CU
+#define DBSC_DBMRRDR_4		0xE6791810U
+#define DBSC_DBMRRDR_5		0xE6791814U
+#define DBSC_DBMRRDR_6		0xE6791818U
+#define DBSC_DBMRRDR_7		0xE679181CU
+
+#define DBSC_DBMEMSWAPCONF0	0xE6792000U
+
+#define DBSC_DBMONCONF4		0xE6793010U
+
+#define DBSC_PLL_LOCK(ch)	(0xE6794054U + 0x100U * (ch))
+#define DBSC_PLL_LOCK_0		0xE6794054U
+#define DBSC_PLL_LOCK_1		0xE6794154U
+#define DBSC_PLL_LOCK_2		0xE6794254U
+#define DBSC_PLL_LOCK_3		0xE6794354U
+
+/* STAT registers */
+#define MSTAT_SL_INIT		0xE67E8000U
+#define MSTAT_REF_ARS		0xE67E8004U
+#define MSTATQ_STATQC		0xE67E8008U
+#define MSTATQ_WTENABLE		0xE67E8030U
+#define MSTATQ_WTREFRESH	0xE67E8034U
+#define MSTATQ_WTSETTING0	0xE67E8038U
+#define MSTATQ_WTSETTING1	0xE67E803CU
+
+#define QOS_BASE1		(0xE67F0000U)
+#define QOSCTRL_RAS		(QOS_BASE1 + 0x0000U)
+#define QOSCTRL_FIXTH		(QOS_BASE1 + 0x0004U)
+#define QOSCTRL_RAEN		(QOS_BASE1 + 0x0018U)
+#define QOSCTRL_REGGD		(QOS_BASE1 + 0x0020U)
+#define QOSCTRL_DANN		(QOS_BASE1 + 0x0030U)
+#define QOSCTRL_DANT		(QOS_BASE1 + 0x0038U)
+#define QOSCTRL_EC		(QOS_BASE1 + 0x003CU)
+#define QOSCTRL_EMS		(QOS_BASE1 + 0x0040U)
+#define QOSCTRL_INSFC		(QOS_BASE1 + 0x0050U)
+#define QOSCTRL_BERR		(QOS_BASE1 + 0x0054U)
+#define QOSCTRL_RACNT0		(QOS_BASE1 + 0x0080U)
+#define QOSCTRL_STATGEN0	(QOS_BASE1 + 0x0088U)
+
+/* other module */
+#define THS1_THCTR		0xE6198020U
+#define THS1_TEMP		0xE6198028U
+
+#define	DBSC_BASE		(0xE6790000U)
+#define DBSC_DBSCHQOS00		(DBSC_BASE + 0x1030U)
+#define DBSC_DBSCHQOS01		(DBSC_BASE + 0x1034U)
+#define DBSC_DBSCHQOS02		(DBSC_BASE + 0x1038U)
+#define DBSC_DBSCHQOS03		(DBSC_BASE + 0x103CU)
+#define DBSC_DBSCHQOS40		(DBSC_BASE + 0x1070U)
+#define DBSC_DBSCHQOS41		(DBSC_BASE + 0x1074U)
+#define DBSC_DBSCHQOS42		(DBSC_BASE + 0x1078U)
+#define DBSC_DBSCHQOS43		(DBSC_BASE + 0x107CU)
+#define DBSC_DBSCHQOS90		(DBSC_BASE + 0x10C0U)
+#define DBSC_DBSCHQOS91		(DBSC_BASE + 0x10C4U)
+#define DBSC_DBSCHQOS92		(DBSC_BASE + 0x10C8U)
+#define DBSC_DBSCHQOS93		(DBSC_BASE + 0x10CCU)
+#define DBSC_DBSCHQOS120	(DBSC_BASE + 0x10F0U)
+#define DBSC_DBSCHQOS121	(DBSC_BASE + 0x10F4U)
+#define DBSC_DBSCHQOS122	(DBSC_BASE + 0x10F8U)
+#define DBSC_DBSCHQOS123	(DBSC_BASE + 0x10FCU)
+#define DBSC_DBSCHQOS130	(DBSC_BASE + 0x1100U)
+#define DBSC_DBSCHQOS131	(DBSC_BASE + 0x1104U)
+#define DBSC_DBSCHQOS132	(DBSC_BASE + 0x1108U)
+#define DBSC_DBSCHQOS133	(DBSC_BASE + 0x110CU)
+#define DBSC_DBSCHQOS140	(DBSC_BASE + 0x1110U)
+#define DBSC_DBSCHQOS141	(DBSC_BASE + 0x1114U)
+#define DBSC_DBSCHQOS142	(DBSC_BASE + 0x1118U)
+#define DBSC_DBSCHQOS143	(DBSC_BASE + 0x111CU)
+#define DBSC_DBSCHQOS150	(DBSC_BASE + 0x1120U)
+#define DBSC_DBSCHQOS151	(DBSC_BASE + 0x1124U)
+#define DBSC_DBSCHQOS152	(DBSC_BASE + 0x1128U)
+#define DBSC_DBSCHQOS153	(DBSC_BASE + 0x112CU)
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_b.mk b/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_b.mk
new file mode 100644
index 0000000..875f953
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_b.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram.c
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_regdef.h b/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_regdef.h
new file mode 100644
index 0000000..bad1de9
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_regdef.h
@@ -0,0 +1,5886 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define _reg_PHY_DQ_DM_SWIZZLE0                            0x00000000U
+#define _reg_PHY_DQ_DM_SWIZZLE1                            0x00000001U
+#define _reg_PHY_CLK_WR_BYPASS_SLAVE_DELAY                 0x00000002U
+#define _reg_PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY             0x00000003U
+#define _reg_PHY_BYPASS_TWO_CYC_PREAMBLE                   0x00000004U
+#define _reg_PHY_CLK_BYPASS_OVERRIDE                       0x00000005U
+#define _reg_PHY_SW_WRDQ0_SHIFT                            0x00000006U
+#define _reg_PHY_SW_WRDQ1_SHIFT                            0x00000007U
+#define _reg_PHY_SW_WRDQ2_SHIFT                            0x00000008U
+#define _reg_PHY_SW_WRDQ3_SHIFT                            0x00000009U
+#define _reg_PHY_SW_WRDQ4_SHIFT                            0x0000000aU
+#define _reg_PHY_SW_WRDQ5_SHIFT                            0x0000000bU
+#define _reg_PHY_SW_WRDQ6_SHIFT                            0x0000000cU
+#define _reg_PHY_SW_WRDQ7_SHIFT                            0x0000000dU
+#define _reg_PHY_SW_WRDM_SHIFT                             0x0000000eU
+#define _reg_PHY_SW_WRDQS_SHIFT                            0x0000000fU
+#define _reg_PHY_DQ_TSEL_ENABLE                            0x00000010U
+#define _reg_PHY_DQ_TSEL_SELECT                            0x00000011U
+#define _reg_PHY_DQS_TSEL_ENABLE                           0x00000012U
+#define _reg_PHY_DQS_TSEL_SELECT                           0x00000013U
+#define _reg_PHY_TWO_CYC_PREAMBLE                          0x00000014U
+#define _reg_PHY_DBI_MODE                                  0x00000015U
+#define _reg_PHY_PER_RANK_CS_MAP                           0x00000016U
+#define _reg_PHY_PER_CS_TRAINING_MULTICAST_EN              0x00000017U
+#define _reg_PHY_PER_CS_TRAINING_INDEX                     0x00000018U
+#define _reg_PHY_LP4_BOOT_RDDATA_EN_IE_DLY                 0x00000019U
+#define _reg_PHY_LP4_BOOT_RDDATA_EN_DLY                    0x0000001aU
+#define _reg_PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY               0x0000001bU
+#define _reg_PHY_LP4_BOOT_RPTR_UPDATE                      0x0000001cU
+#define _reg_PHY_LP4_BOOT_RDDQS_GATE_SLAVE_DELAY           0x0000001dU
+#define _reg_PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST             0x0000001eU
+#define _reg_PHY_LP4_BOOT_WRPATH_GATE_DISABLE              0x0000001fU
+#define _reg_PHY_LP4_BOOT_RDDATA_EN_OE_DLY                 0x00000020U
+#define _reg_PHY_LPBK_CONTROL                              0x00000021U
+#define _reg_PHY_LPBK_DFX_TIMEOUT_EN                       0x00000022U
+#define _reg_PHY_AUTO_TIMING_MARGIN_CONTROL                0x00000023U
+#define _reg_PHY_AUTO_TIMING_MARGIN_OBS                    0x00000024U
+#define _reg_PHY_SLICE_PWR_RDC_DISABLE                     0x00000025U
+#define _reg_PHY_PRBS_PATTERN_START                        0x00000026U
+#define _reg_PHY_PRBS_PATTERN_MASK                         0x00000027U
+#define _reg_PHY_RDDQS_DQ_BYPASS_SLAVE_DELAY               0x00000028U
+#define _reg_PHY_GATE_ERROR_DELAY_SELECT                   0x00000029U
+#define _reg_SC_PHY_SNAP_OBS_REGS                          0x0000002aU
+#define _reg_PHY_LPDDR                                     0x0000002bU
+#define _reg_PHY_LPDDR_TYPE                                0x0000002cU
+#define _reg_PHY_GATE_SMPL1_SLAVE_DELAY                    0x0000002dU
+#define _reg_PHY_GATE_SMPL2_SLAVE_DELAY                    0x0000002eU
+#define _reg_ON_FLY_GATE_ADJUST_EN                         0x0000002fU
+#define _reg_PHY_GATE_TRACKING_OBS                         0x00000030U
+#define _reg_PHY_DFI40_POLARITY                            0x00000031U
+#define _reg_PHY_LP4_PST_AMBLE                             0x00000032U
+#define _reg_PHY_RDLVL_PATT8                               0x00000033U
+#define _reg_PHY_RDLVL_PATT9                               0x00000034U
+#define _reg_PHY_RDLVL_PATT10                              0x00000035U
+#define _reg_PHY_RDLVL_PATT11                              0x00000036U
+#define _reg_PHY_LP4_RDLVL_PATT8                           0x00000037U
+#define _reg_PHY_LP4_RDLVL_PATT9                           0x00000038U
+#define _reg_PHY_LP4_RDLVL_PATT10                          0x00000039U
+#define _reg_PHY_LP4_RDLVL_PATT11                          0x0000003aU
+#define _reg_PHY_SLAVE_LOOP_CNT_UPDATE                     0x0000003bU
+#define _reg_PHY_SW_FIFO_PTR_RST_DISABLE                   0x0000003cU
+#define _reg_PHY_MASTER_DLY_LOCK_OBS_SELECT                0x0000003dU
+#define _reg_PHY_RDDQ_ENC_OBS_SELECT                       0x0000003eU
+#define _reg_PHY_RDDQS_DQ_ENC_OBS_SELECT                   0x0000003fU
+#define _reg_PHY_WR_ENC_OBS_SELECT                         0x00000040U
+#define _reg_PHY_WR_SHIFT_OBS_SELECT                       0x00000041U
+#define _reg_PHY_FIFO_PTR_OBS_SELECT                       0x00000042U
+#define _reg_PHY_LVL_DEBUG_MODE                            0x00000043U
+#define _reg_SC_PHY_LVL_DEBUG_CONT                         0x00000044U
+#define _reg_PHY_WRLVL_CAPTURE_CNT                         0x00000045U
+#define _reg_PHY_WRLVL_UPDT_WAIT_CNT                       0x00000046U
+#define _reg_PHY_WRLVL_DQ_MASK                             0x00000047U
+#define _reg_PHY_GTLVL_CAPTURE_CNT                         0x00000048U
+#define _reg_PHY_GTLVL_UPDT_WAIT_CNT                       0x00000049U
+#define _reg_PHY_RDLVL_CAPTURE_CNT                         0x0000004aU
+#define _reg_PHY_RDLVL_UPDT_WAIT_CNT                       0x0000004bU
+#define _reg_PHY_RDLVL_OP_MODE                             0x0000004cU
+#define _reg_PHY_RDLVL_RDDQS_DQ_OBS_SELECT                 0x0000004dU
+#define _reg_PHY_RDLVL_DATA_MASK                           0x0000004eU
+#define _reg_PHY_RDLVL_DATA_SWIZZLE                        0x0000004fU
+#define _reg_PHY_WDQLVL_BURST_CNT                          0x00000050U
+#define _reg_PHY_WDQLVL_PATT                               0x00000051U
+#define _reg_PHY_WDQLVL_DQDM_SLV_DLY_JUMP_OFFSET           0x00000052U
+#define _reg_PHY_WDQLVL_UPDT_WAIT_CNT                      0x00000053U
+#define _reg_PHY_WDQLVL_DQDM_OBS_SELECT                    0x00000054U
+#define _reg_PHY_WDQLVL_QTR_DLY_STEP                       0x00000055U
+#define _reg_SC_PHY_WDQLVL_CLR_PREV_RESULTS                0x00000056U
+#define _reg_PHY_WDQLVL_CLR_PREV_RESULTS                   0x00000057U
+#define _reg_PHY_WDQLVL_DATADM_MASK                        0x00000058U
+#define _reg_PHY_USER_PATT0                                0x00000059U
+#define _reg_PHY_USER_PATT1                                0x0000005aU
+#define _reg_PHY_USER_PATT2                                0x0000005bU
+#define _reg_PHY_USER_PATT3                                0x0000005cU
+#define _reg_PHY_USER_PATT4                                0x0000005dU
+#define _reg_PHY_DQ_SWIZZLING                              0x0000005eU
+#define _reg_PHY_CALVL_VREF_DRIVING_SLICE                  0x0000005fU
+#define _reg_SC_PHY_MANUAL_CLEAR                           0x00000060U
+#define _reg_PHY_FIFO_PTR_OBS                              0x00000061U
+#define _reg_PHY_LPBK_RESULT_OBS                           0x00000062U
+#define _reg_PHY_LPBK_ERROR_COUNT_OBS                      0x00000063U
+#define _reg_PHY_MASTER_DLY_LOCK_OBS                       0x00000064U
+#define _reg_PHY_RDDQ_SLV_DLY_ENC_OBS                      0x00000065U
+#define _reg_PHY_RDDQS_BASE_SLV_DLY_ENC_OBS                0x00000066U
+#define _reg_PHY_RDDQS_DQ_RISE_ADDER_SLV_DLY_ENC_OBS       0x00000067U
+#define _reg_PHY_RDDQS_DQ_FALL_ADDER_SLV_DLY_ENC_OBS       0x00000068U
+#define _reg_PHY_RDDQS_GATE_SLV_DLY_ENC_OBS                0x00000069U
+#define _reg_PHY_WRDQS_BASE_SLV_DLY_ENC_OBS                0x0000006aU
+#define _reg_PHY_WRDQ_BASE_SLV_DLY_ENC_OBS                 0x0000006bU
+#define _reg_PHY_WR_ADDER_SLV_DLY_ENC_OBS                  0x0000006cU
+#define _reg_PHY_WR_SHIFT_OBS                              0x0000006dU
+#define _reg_PHY_WRLVL_HARD0_DELAY_OBS                     0x0000006eU
+#define _reg_PHY_WRLVL_HARD1_DELAY_OBS                     0x0000006fU
+#define _reg_PHY_WRLVL_STATUS_OBS                          0x00000070U
+#define _reg_PHY_GATE_SMPL1_SLV_DLY_ENC_OBS                0x00000071U
+#define _reg_PHY_GATE_SMPL2_SLV_DLY_ENC_OBS                0x00000072U
+#define _reg_PHY_WRLVL_ERROR_OBS                           0x00000073U
+#define _reg_PHY_GTLVL_HARD0_DELAY_OBS                     0x00000074U
+#define _reg_PHY_GTLVL_HARD1_DELAY_OBS                     0x00000075U
+#define _reg_PHY_GTLVL_STATUS_OBS                          0x00000076U
+#define _reg_PHY_RDLVL_RDDQS_DQ_LE_DLY_OBS                 0x00000077U
+#define _reg_PHY_RDLVL_RDDQS_DQ_TE_DLY_OBS                 0x00000078U
+#define _reg_PHY_RDLVL_RDDQS_DQ_NUM_WINDOWS_OBS            0x00000079U
+#define _reg_PHY_RDLVL_STATUS_OBS                          0x0000007aU
+#define _reg_PHY_WDQLVL_DQDM_LE_DLY_OBS                    0x0000007bU
+#define _reg_PHY_WDQLVL_DQDM_TE_DLY_OBS                    0x0000007cU
+#define _reg_PHY_WDQLVL_STATUS_OBS                         0x0000007dU
+#define _reg_PHY_DDL_MODE                                  0x0000007eU
+#define _reg_PHY_DDL_TEST_OBS                              0x0000007fU
+#define _reg_PHY_DDL_TEST_MSTR_DLY_OBS                     0x00000080U
+#define _reg_PHY_DDL_TRACK_UPD_THRESHOLD                   0x00000081U
+#define _reg_PHY_LP4_WDQS_OE_EXTEND                        0x00000082U
+#define _reg_SC_PHY_RX_CAL_START                           0x00000083U
+#define _reg_PHY_RX_CAL_OVERRIDE                           0x00000084U
+#define _reg_PHY_RX_CAL_SAMPLE_WAIT                        0x00000085U
+#define _reg_PHY_RX_CAL_DQ0                                0x00000086U
+#define _reg_PHY_RX_CAL_DQ1                                0x00000087U
+#define _reg_PHY_RX_CAL_DQ2                                0x00000088U
+#define _reg_PHY_RX_CAL_DQ3                                0x00000089U
+#define _reg_PHY_RX_CAL_DQ4                                0x0000008aU
+#define _reg_PHY_RX_CAL_DQ5                                0x0000008bU
+#define _reg_PHY_RX_CAL_DQ6                                0x0000008cU
+#define _reg_PHY_RX_CAL_DQ7                                0x0000008dU
+#define _reg_PHY_RX_CAL_DM                                 0x0000008eU
+#define _reg_PHY_RX_CAL_DQS                                0x0000008fU
+#define _reg_PHY_RX_CAL_FDBK                               0x00000090U
+#define _reg_PHY_RX_CAL_OBS                                0x00000091U
+#define _reg_PHY_RX_CAL_LOCK_OBS                           0x00000092U
+#define _reg_PHY_RX_CAL_DISABLE                            0x00000093U
+#define _reg_PHY_CLK_WRDQ0_SLAVE_DELAY                     0x00000094U
+#define _reg_PHY_CLK_WRDQ1_SLAVE_DELAY                     0x00000095U
+#define _reg_PHY_CLK_WRDQ2_SLAVE_DELAY                     0x00000096U
+#define _reg_PHY_CLK_WRDQ3_SLAVE_DELAY                     0x00000097U
+#define _reg_PHY_CLK_WRDQ4_SLAVE_DELAY                     0x00000098U
+#define _reg_PHY_CLK_WRDQ5_SLAVE_DELAY                     0x00000099U
+#define _reg_PHY_CLK_WRDQ6_SLAVE_DELAY                     0x0000009aU
+#define _reg_PHY_CLK_WRDQ7_SLAVE_DELAY                     0x0000009bU
+#define _reg_PHY_CLK_WRDM_SLAVE_DELAY                      0x0000009cU
+#define _reg_PHY_CLK_WRDQS_SLAVE_DELAY                     0x0000009dU
+#define _reg_PHY_WRLVL_THRESHOLD_ADJUST                    0x0000009eU
+#define _reg_PHY_RDDQ0_SLAVE_DELAY                         0x0000009fU
+#define _reg_PHY_RDDQ1_SLAVE_DELAY                         0x000000a0U
+#define _reg_PHY_RDDQ2_SLAVE_DELAY                         0x000000a1U
+#define _reg_PHY_RDDQ3_SLAVE_DELAY                         0x000000a2U
+#define _reg_PHY_RDDQ4_SLAVE_DELAY                         0x000000a3U
+#define _reg_PHY_RDDQ5_SLAVE_DELAY                         0x000000a4U
+#define _reg_PHY_RDDQ6_SLAVE_DELAY                         0x000000a5U
+#define _reg_PHY_RDDQ7_SLAVE_DELAY                         0x000000a6U
+#define _reg_PHY_RDDM_SLAVE_DELAY                          0x000000a7U
+#define _reg_PHY_RDDQS_DQ0_RISE_SLAVE_DELAY                0x000000a8U
+#define _reg_PHY_RDDQS_DQ0_FALL_SLAVE_DELAY                0x000000a9U
+#define _reg_PHY_RDDQS_DQ1_RISE_SLAVE_DELAY                0x000000aaU
+#define _reg_PHY_RDDQS_DQ1_FALL_SLAVE_DELAY                0x000000abU
+#define _reg_PHY_RDDQS_DQ2_RISE_SLAVE_DELAY                0x000000acU
+#define _reg_PHY_RDDQS_DQ2_FALL_SLAVE_DELAY                0x000000adU
+#define _reg_PHY_RDDQS_DQ3_RISE_SLAVE_DELAY                0x000000aeU
+#define _reg_PHY_RDDQS_DQ3_FALL_SLAVE_DELAY                0x000000afU
+#define _reg_PHY_RDDQS_DQ4_RISE_SLAVE_DELAY                0x000000b0U
+#define _reg_PHY_RDDQS_DQ4_FALL_SLAVE_DELAY                0x000000b1U
+#define _reg_PHY_RDDQS_DQ5_RISE_SLAVE_DELAY                0x000000b2U
+#define _reg_PHY_RDDQS_DQ5_FALL_SLAVE_DELAY                0x000000b3U
+#define _reg_PHY_RDDQS_DQ6_RISE_SLAVE_DELAY                0x000000b4U
+#define _reg_PHY_RDDQS_DQ6_FALL_SLAVE_DELAY                0x000000b5U
+#define _reg_PHY_RDDQS_DQ7_RISE_SLAVE_DELAY                0x000000b6U
+#define _reg_PHY_RDDQS_DQ7_FALL_SLAVE_DELAY                0x000000b7U
+#define _reg_PHY_RDDQS_DM_RISE_SLAVE_DELAY                 0x000000b8U
+#define _reg_PHY_RDDQS_DM_FALL_SLAVE_DELAY                 0x000000b9U
+#define _reg_PHY_RDDQS_GATE_SLAVE_DELAY                    0x000000baU
+#define _reg_PHY_RDDQS_LATENCY_ADJUST                      0x000000bbU
+#define _reg_PHY_WRITE_PATH_LAT_ADD                        0x000000bcU
+#define _reg_PHY_WRLVL_DELAY_EARLY_THRESHOLD               0x000000bdU
+#define _reg_PHY_WRLVL_DELAY_PERIOD_THRESHOLD              0x000000beU
+#define _reg_PHY_WRLVL_EARLY_FORCE_ZERO                    0x000000bfU
+#define _reg_PHY_GTLVL_RDDQS_SLV_DLY_START                 0x000000c0U
+#define _reg_PHY_GTLVL_LAT_ADJ_START                       0x000000c1U
+#define _reg_PHY_WDQLVL_DQDM_SLV_DLY_START                 0x000000c2U
+#define _reg_PHY_RDLVL_RDDQS_DQ_SLV_DLY_START              0x000000c3U
+#define _reg_PHY_FDBK_PWR_CTRL                             0x000000c4U
+#define _reg_PHY_DQ_OE_TIMING                              0x000000c5U
+#define _reg_PHY_DQ_TSEL_RD_TIMING                         0x000000c6U
+#define _reg_PHY_DQ_TSEL_WR_TIMING                         0x000000c7U
+#define _reg_PHY_DQS_OE_TIMING                             0x000000c8U
+#define _reg_PHY_DQS_TSEL_RD_TIMING                        0x000000c9U
+#define _reg_PHY_DQS_OE_RD_TIMING                          0x000000caU
+#define _reg_PHY_DQS_TSEL_WR_TIMING                        0x000000cbU
+#define _reg_PHY_PER_CS_TRAINING_EN                        0x000000ccU
+#define _reg_PHY_DQ_IE_TIMING                              0x000000cdU
+#define _reg_PHY_DQS_IE_TIMING                             0x000000ceU
+#define _reg_PHY_RDDATA_EN_IE_DLY                          0x000000cfU
+#define _reg_PHY_IE_MODE                                   0x000000d0U
+#define _reg_PHY_RDDATA_EN_DLY                             0x000000d1U
+#define _reg_PHY_RDDATA_EN_TSEL_DLY                        0x000000d2U
+#define _reg_PHY_RDDATA_EN_OE_DLY                          0x000000d3U
+#define _reg_PHY_SW_MASTER_MODE                            0x000000d4U
+#define _reg_PHY_MASTER_DELAY_START                        0x000000d5U
+#define _reg_PHY_MASTER_DELAY_STEP                         0x000000d6U
+#define _reg_PHY_MASTER_DELAY_WAIT                         0x000000d7U
+#define _reg_PHY_MASTER_DELAY_HALF_MEASURE                 0x000000d8U
+#define _reg_PHY_RPTR_UPDATE                               0x000000d9U
+#define _reg_PHY_WRLVL_DLY_STEP                            0x000000daU
+#define _reg_PHY_WRLVL_RESP_WAIT_CNT                       0x000000dbU
+#define _reg_PHY_GTLVL_DLY_STEP                            0x000000dcU
+#define _reg_PHY_GTLVL_RESP_WAIT_CNT                       0x000000ddU
+#define _reg_PHY_GTLVL_BACK_STEP                           0x000000deU
+#define _reg_PHY_GTLVL_FINAL_STEP                          0x000000dfU
+#define _reg_PHY_WDQLVL_DLY_STEP                           0x000000e0U
+#define _reg_PHY_TOGGLE_PRE_SUPPORT                        0x000000e1U
+#define _reg_PHY_RDLVL_DLY_STEP                            0x000000e2U
+#define _reg_PHY_WRPATH_GATE_DISABLE                       0x000000e3U
+#define _reg_PHY_WRPATH_GATE_TIMING                        0x000000e4U
+#define _reg_PHY_ADR0_SW_WRADDR_SHIFT                      0x000000e5U
+#define _reg_PHY_ADR1_SW_WRADDR_SHIFT                      0x000000e6U
+#define _reg_PHY_ADR2_SW_WRADDR_SHIFT                      0x000000e7U
+#define _reg_PHY_ADR3_SW_WRADDR_SHIFT                      0x000000e8U
+#define _reg_PHY_ADR4_SW_WRADDR_SHIFT                      0x000000e9U
+#define _reg_PHY_ADR5_SW_WRADDR_SHIFT                      0x000000eaU
+#define _reg_PHY_ADR_CLK_WR_BYPASS_SLAVE_DELAY             0x000000ebU
+#define _reg_PHY_ADR_CLK_BYPASS_OVERRIDE                   0x000000ecU
+#define _reg_SC_PHY_ADR_MANUAL_CLEAR                       0x000000edU
+#define _reg_PHY_ADR_LPBK_RESULT_OBS                       0x000000eeU
+#define _reg_PHY_ADR_LPBK_ERROR_COUNT_OBS                  0x000000efU
+#define _reg_PHY_ADR_MASTER_DLY_LOCK_OBS_SELECT            0x000000f0U
+#define _reg_PHY_ADR_MASTER_DLY_LOCK_OBS                   0x000000f1U
+#define _reg_PHY_ADR_BASE_SLV_DLY_ENC_OBS                  0x000000f2U
+#define _reg_PHY_ADR_ADDER_SLV_DLY_ENC_OBS                 0x000000f3U
+#define _reg_PHY_ADR_SLAVE_LOOP_CNT_UPDATE                 0x000000f4U
+#define _reg_PHY_ADR_SLV_DLY_ENC_OBS_SELECT                0x000000f5U
+#define _reg_SC_PHY_ADR_SNAP_OBS_REGS                      0x000000f6U
+#define _reg_PHY_ADR_TSEL_ENABLE                           0x000000f7U
+#define _reg_PHY_ADR_LPBK_CONTROL                          0x000000f8U
+#define _reg_PHY_ADR_PRBS_PATTERN_START                    0x000000f9U
+#define _reg_PHY_ADR_PRBS_PATTERN_MASK                     0x000000faU
+#define _reg_PHY_ADR_PWR_RDC_DISABLE                       0x000000fbU
+#define _reg_PHY_ADR_TYPE                                  0x000000fcU
+#define _reg_PHY_ADR_WRADDR_SHIFT_OBS                      0x000000fdU
+#define _reg_PHY_ADR_IE_MODE                               0x000000feU
+#define _reg_PHY_ADR_DDL_MODE                              0x000000ffU
+#define _reg_PHY_ADR_DDL_TEST_OBS                          0x00000100U
+#define _reg_PHY_ADR_DDL_TEST_MSTR_DLY_OBS                 0x00000101U
+#define _reg_PHY_ADR_CALVL_START                           0x00000102U
+#define _reg_PHY_ADR_CALVL_COARSE_DLY                      0x00000103U
+#define _reg_PHY_ADR_CALVL_QTR                             0x00000104U
+#define _reg_PHY_ADR_CALVL_SWIZZLE0                        0x00000105U
+#define _reg_PHY_ADR_CALVL_SWIZZLE1                        0x00000106U
+#define _reg_PHY_ADR_CALVL_SWIZZLE0_0                      0x00000107U
+#define _reg_PHY_ADR_CALVL_SWIZZLE1_0                      0x00000108U
+#define _reg_PHY_ADR_CALVL_SWIZZLE0_1                      0x00000109U
+#define _reg_PHY_ADR_CALVL_SWIZZLE1_1                      0x0000010aU
+#define _reg_PHY_ADR_CALVL_DEVICE_MAP                      0x0000010bU
+#define _reg_PHY_ADR_CALVL_RANK_CTRL                       0x0000010cU
+#define _reg_PHY_ADR_CALVL_NUM_PATTERNS                    0x0000010dU
+#define _reg_PHY_ADR_CALVL_CAPTURE_CNT                     0x0000010eU
+#define _reg_PHY_ADR_CALVL_RESP_WAIT_CNT                   0x0000010fU
+#define _reg_PHY_ADR_CALVL_DEBUG_MODE                      0x00000110U
+#define _reg_SC_PHY_ADR_CALVL_DEBUG_CONT                   0x00000111U
+#define _reg_SC_PHY_ADR_CALVL_ERROR_CLR                    0x00000112U
+#define _reg_PHY_ADR_CALVL_OBS_SELECT                      0x00000113U
+#define _reg_PHY_ADR_CALVL_OBS0                            0x00000114U
+#define _reg_PHY_ADR_CALVL_OBS1                            0x00000115U
+#define _reg_PHY_ADR_CALVL_RESULT                          0x00000116U
+#define _reg_PHY_ADR_CALVL_FG_0                            0x00000117U
+#define _reg_PHY_ADR_CALVL_BG_0                            0x00000118U
+#define _reg_PHY_ADR_CALVL_FG_1                            0x00000119U
+#define _reg_PHY_ADR_CALVL_BG_1                            0x0000011aU
+#define _reg_PHY_ADR_CALVL_FG_2                            0x0000011bU
+#define _reg_PHY_ADR_CALVL_BG_2                            0x0000011cU
+#define _reg_PHY_ADR_CALVL_FG_3                            0x0000011dU
+#define _reg_PHY_ADR_CALVL_BG_3                            0x0000011eU
+#define _reg_PHY_ADR_ADDR_SEL                              0x0000011fU
+#define _reg_PHY_ADR_LP4_BOOT_SLV_DELAY                    0x00000120U
+#define _reg_PHY_ADR_BIT_MASK                              0x00000121U
+#define _reg_PHY_ADR_SEG_MASK                              0x00000122U
+#define _reg_PHY_ADR_CALVL_TRAIN_MASK                      0x00000123U
+#define _reg_PHY_ADR_CSLVL_TRAIN_MASK                      0x00000124U
+#define _reg_PHY_ADR_SW_TXIO_CTRL                          0x00000125U
+#define _reg_PHY_ADR_TSEL_SELECT                           0x00000126U
+#define _reg_PHY_ADR0_CLK_WR_SLAVE_DELAY                   0x00000127U
+#define _reg_PHY_ADR1_CLK_WR_SLAVE_DELAY                   0x00000128U
+#define _reg_PHY_ADR2_CLK_WR_SLAVE_DELAY                   0x00000129U
+#define _reg_PHY_ADR3_CLK_WR_SLAVE_DELAY                   0x0000012aU
+#define _reg_PHY_ADR4_CLK_WR_SLAVE_DELAY                   0x0000012bU
+#define _reg_PHY_ADR5_CLK_WR_SLAVE_DELAY                   0x0000012cU
+#define _reg_PHY_ADR_SW_MASTER_MODE                        0x0000012dU
+#define _reg_PHY_ADR_MASTER_DELAY_START                    0x0000012eU
+#define _reg_PHY_ADR_MASTER_DELAY_STEP                     0x0000012fU
+#define _reg_PHY_ADR_MASTER_DELAY_WAIT                     0x00000130U
+#define _reg_PHY_ADR_MASTER_DELAY_HALF_MEASURE             0x00000131U
+#define _reg_PHY_ADR_CALVL_DLY_STEP                        0x00000132U
+#define _reg_PHY_FREQ_SEL                                  0x00000133U
+#define _reg_PHY_FREQ_SEL_FROM_REGIF                       0x00000134U
+#define _reg_PHY_FREQ_SEL_MULTICAST_EN                     0x00000135U
+#define _reg_PHY_FREQ_SEL_INDEX                            0x00000136U
+#define _reg_PHY_SW_GRP_SHIFT_0                            0x00000137U
+#define _reg_PHY_SW_GRP_SHIFT_1                            0x00000138U
+#define _reg_PHY_SW_GRP_SHIFT_2                            0x00000139U
+#define _reg_PHY_SW_GRP_SHIFT_3                            0x0000013aU
+#define _reg_PHY_GRP_BYPASS_SLAVE_DELAY                    0x0000013bU
+#define _reg_PHY_SW_GRP_BYPASS_SHIFT                       0x0000013cU
+#define _reg_PHY_GRP_BYPASS_OVERRIDE                       0x0000013dU
+#define _reg_SC_PHY_MANUAL_UPDATE                          0x0000013eU
+#define _reg_SC_PHY_MANUAL_UPDATE_PHYUPD_ENABLE            0x0000013fU
+#define _reg_PHY_LP4_BOOT_DISABLE                          0x00000140U
+#define _reg_PHY_CSLVL_ENABLE                              0x00000141U
+#define _reg_PHY_CSLVL_CS_MAP                              0x00000142U
+#define _reg_PHY_CSLVL_START                               0x00000143U
+#define _reg_PHY_CSLVL_QTR                                 0x00000144U
+#define _reg_PHY_CSLVL_COARSE_CHK                          0x00000145U
+#define _reg_PHY_CSLVL_CAPTURE_CNT                         0x00000146U
+#define _reg_PHY_CSLVL_COARSE_DLY                          0x00000147U
+#define _reg_PHY_CSLVL_COARSE_CAPTURE_CNT                  0x00000148U
+#define _reg_PHY_CSLVL_DEBUG_MODE                          0x00000149U
+#define _reg_SC_PHY_CSLVL_DEBUG_CONT                       0x0000014aU
+#define _reg_SC_PHY_CSLVL_ERROR_CLR                        0x0000014bU
+#define _reg_PHY_CSLVL_OBS0                                0x0000014cU
+#define _reg_PHY_CSLVL_OBS1                                0x0000014dU
+#define _reg_PHY_CALVL_CS_MAP                              0x0000014eU
+#define _reg_PHY_GRP_SLV_DLY_ENC_OBS_SELECT                0x0000014fU
+#define _reg_PHY_GRP_SHIFT_OBS_SELECT                      0x00000150U
+#define _reg_PHY_GRP_SLV_DLY_ENC_OBS                       0x00000151U
+#define _reg_PHY_GRP_SHIFT_OBS                             0x00000152U
+#define _reg_PHY_ADRCTL_SLAVE_LOOP_CNT_UPDATE              0x00000153U
+#define _reg_PHY_ADRCTL_SNAP_OBS_REGS                      0x00000154U
+#define _reg_PHY_DFI_PHYUPD_TYPE                           0x00000155U
+#define _reg_PHY_ADRCTL_LPDDR                              0x00000156U
+#define _reg_PHY_LP4_ACTIVE                                0x00000157U
+#define _reg_PHY_LPDDR3_CS                                 0x00000158U
+#define _reg_PHY_CALVL_RESULT_MASK                         0x00000159U
+#define _reg_SC_PHY_UPDATE_CLK_CAL_VALUES                  0x0000015aU
+#define _reg_PHY_SW_TXIO_CTRL_0                            0x0000015bU
+#define _reg_PHY_SW_TXIO_CTRL_1                            0x0000015cU
+#define _reg_PHY_SW_TXIO_CTRL_2                            0x0000015dU
+#define _reg_PHY_SW_TXIO_CTRL_3                            0x0000015eU
+#define _reg_PHY_MEMCLK_SW_TXIO_CTRL                       0x0000015fU
+#define _reg_PHY_CA_SW_TXPWR_CTRL                          0x00000160U
+#define _reg_PHY_MEMCLK_SW_TXPWR_CTRL                      0x00000161U
+#define _reg_PHY_USER_DEF_REG_AC_0                         0x00000162U
+#define _reg_PHY_USER_DEF_REG_AC_1                         0x00000163U
+#define _reg_PHY_USER_DEF_REG_AC_2                         0x00000164U
+#define _reg_PHY_USER_DEF_REG_AC_3                         0x00000165U
+#define _reg_PHY_UPDATE_CLK_CAL_VALUES                     0x00000166U
+#define _reg_PHY_CONTINUOUS_CLK_CAL_UPDATE                 0x00000167U
+#define _reg_PHY_PLL_CTRL                                  0x00000168U
+#define _reg_PHY_PLL_CTRL_TOP                              0x00000169U
+#define _reg_PHY_PLL_CTRL_CA                               0x0000016aU
+#define _reg_PHY_PLL_BYPASS                                0x0000016bU
+#define _reg_PHY_LOW_FREQ_SEL                              0x0000016cU
+#define _reg_PHY_PAD_VREF_CTRL_DQ_0                        0x0000016dU
+#define _reg_PHY_PAD_VREF_CTRL_DQ_1                        0x0000016eU
+#define _reg_PHY_PAD_VREF_CTRL_DQ_2                        0x0000016fU
+#define _reg_PHY_PAD_VREF_CTRL_DQ_3                        0x00000170U
+#define _reg_PHY_PAD_VREF_CTRL_AC                          0x00000171U
+#define _reg_PHY_CSLVL_DLY_STEP                            0x00000172U
+#define _reg_PHY_SET_DFI_INPUT_0                           0x00000173U
+#define _reg_PHY_SET_DFI_INPUT_1                           0x00000174U
+#define _reg_PHY_SET_DFI_INPUT_2                           0x00000175U
+#define _reg_PHY_SET_DFI_INPUT_3                           0x00000176U
+#define _reg_PHY_GRP_SLAVE_DELAY_0                         0x00000177U
+#define _reg_PHY_GRP_SLAVE_DELAY_1                         0x00000178U
+#define _reg_PHY_GRP_SLAVE_DELAY_2                         0x00000179U
+#define _reg_PHY_GRP_SLAVE_DELAY_3                         0x0000017aU
+#define _reg_PHY_CS_ACS_ALLOCATION_0                       0x0000017bU
+#define _reg_PHY_CS_ACS_ALLOCATION_1                       0x0000017cU
+#define _reg_PHY_CS_ACS_ALLOCATION_2                       0x0000017dU
+#define _reg_PHY_CS_ACS_ALLOCATION_3                       0x0000017eU
+#define _reg_PHY_LP4_BOOT_PLL_CTRL                         0x0000017fU
+#define _reg_PHY_LP4_BOOT_PLL_CTRL_CA                      0x00000180U
+#define _reg_PHY_LP4_BOOT_TOP_PLL_CTRL                     0x00000181U
+#define _reg_PHY_PLL_CTRL_OVERRIDE                         0x00000182U
+#define _reg_PHY_PLL_WAIT                                  0x00000183U
+#define _reg_PHY_PLL_WAIT_TOP                              0x00000184U
+#define _reg_PHY_PLL_OBS_0                                 0x00000185U
+#define _reg_PHY_PLL_OBS_1                                 0x00000186U
+#define _reg_PHY_PLL_OBS_2                                 0x00000187U
+#define _reg_PHY_PLL_OBS_3                                 0x00000188U
+#define _reg_PHY_PLL_OBS_4                                 0x00000189U
+#define _reg_PHY_PLL_TESTOUT_SEL                           0x0000018aU
+#define _reg_PHY_TCKSRE_WAIT                               0x0000018bU
+#define _reg_PHY_LP4_BOOT_LOW_FREQ_SEL                     0x0000018cU
+#define _reg_PHY_LP_WAKEUP                                 0x0000018dU
+#define _reg_PHY_LS_IDLE_EN                                0x0000018eU
+#define _reg_PHY_LP_CTRLUPD_CNTR_CFG                       0x0000018fU
+#define _reg_PHY_TDFI_PHY_WRDELAY                          0x00000190U
+#define _reg_PHY_PAD_FDBK_DRIVE                            0x00000191U
+#define _reg_PHY_PAD_DATA_DRIVE                            0x00000192U
+#define _reg_PHY_PAD_DQS_DRIVE                             0x00000193U
+#define _reg_PHY_PAD_ADDR_DRIVE                            0x00000194U
+#define _reg_PHY_PAD_CLK_DRIVE                             0x00000195U
+#define _reg_PHY_PAD_FDBK_TERM                             0x00000196U
+#define _reg_PHY_PAD_DATA_TERM                             0x00000197U
+#define _reg_PHY_PAD_DQS_TERM                              0x00000198U
+#define _reg_PHY_PAD_ADDR_TERM                             0x00000199U
+#define _reg_PHY_PAD_CLK_TERM                              0x0000019aU
+#define _reg_PHY_PAD_CKE_DRIVE                             0x0000019bU
+#define _reg_PHY_PAD_CKE_TERM                              0x0000019cU
+#define _reg_PHY_PAD_RST_DRIVE                             0x0000019dU
+#define _reg_PHY_PAD_RST_TERM                              0x0000019eU
+#define _reg_PHY_PAD_CS_DRIVE                              0x0000019fU
+#define _reg_PHY_PAD_CS_TERM                               0x000001a0U
+#define _reg_PHY_PAD_ODT_DRIVE                             0x000001a1U
+#define _reg_PHY_PAD_ODT_TERM                              0x000001a2U
+#define _reg_PHY_ADRCTL_RX_CAL                             0x000001a3U
+#define _reg_PHY_ADRCTL_LP3_RX_CAL                         0x000001a4U
+#define _reg_PHY_TST_CLK_PAD_CTRL                          0x000001a5U
+#define _reg_PHY_TST_CLK_PAD_CTRL2                         0x000001a6U
+#define _reg_PHY_CAL_MODE_0                                0x000001a7U
+#define _reg_PHY_CAL_CLEAR_0                               0x000001a8U
+#define _reg_PHY_CAL_START_0                               0x000001a9U
+#define _reg_PHY_CAL_INTERVAL_COUNT_0                      0x000001aaU
+#define _reg_PHY_CAL_SAMPLE_WAIT_0                         0x000001abU
+#define _reg_PHY_LP4_BOOT_CAL_CLK_SELECT_0                 0x000001acU
+#define _reg_PHY_CAL_CLK_SELECT_0                          0x000001adU
+#define _reg_PHY_CAL_RESULT_OBS_0                          0x000001aeU
+#define _reg_PHY_CAL_RESULT2_OBS_0                         0x000001afU
+#define _reg_PHY_CAL_CPTR_CNT_0                            0x000001b0U
+#define _reg_PHY_CAL_SETTLING_PRD_0                        0x000001b1U
+#define _reg_PHY_CAL_PU_FINE_ADJ_0                         0x000001b2U
+#define _reg_PHY_CAL_PD_FINE_ADJ_0                         0x000001b3U
+#define _reg_PHY_CAL_RCV_FINE_ADJ_0                        0x000001b4U
+#define _reg_PHY_CAL_DBG_CFG_0                             0x000001b5U
+#define _reg_SC_PHY_PAD_DBG_CONT_0                         0x000001b6U
+#define _reg_PHY_CAL_RESULT3_OBS_0                         0x000001b7U
+#define _reg_PHY_ADRCTL_PVT_MAP_0                          0x000001b8U
+#define _reg_PHY_CAL_SLOPE_ADJ_0                           0x000001b9U
+#define _reg_PHY_CAL_SLOPE_ADJ_PASS2_0                     0x000001baU
+#define _reg_PHY_CAL_TWO_PASS_CFG_0                        0x000001bbU
+#define _reg_PHY_CAL_SW_CAL_CFG_0                          0x000001bcU
+#define _reg_PHY_CAL_RANGE_MIN_0                           0x000001bdU
+#define _reg_PHY_CAL_RANGE_MAX_0                           0x000001beU
+#define _reg_PHY_PAD_ATB_CTRL                              0x000001bfU
+#define _reg_PHY_ADRCTL_MANUAL_UPDATE                      0x000001c0U
+#define _reg_PHY_AC_LPBK_ERR_CLEAR                         0x000001c1U
+#define _reg_PHY_AC_LPBK_OBS_SELECT                        0x000001c2U
+#define _reg_PHY_AC_LPBK_ENABLE                            0x000001c3U
+#define _reg_PHY_AC_LPBK_CONTROL                           0x000001c4U
+#define _reg_PHY_AC_PRBS_PATTERN_START                     0x000001c5U
+#define _reg_PHY_AC_PRBS_PATTERN_MASK                      0x000001c6U
+#define _reg_PHY_AC_LPBK_RESULT_OBS                        0x000001c7U
+#define _reg_PHY_AC_CLK_LPBK_OBS_SELECT                    0x000001c8U
+#define _reg_PHY_AC_CLK_LPBK_ENABLE                        0x000001c9U
+#define _reg_PHY_AC_CLK_LPBK_CONTROL                       0x000001caU
+#define _reg_PHY_AC_CLK_LPBK_RESULT_OBS                    0x000001cbU
+#define _reg_PHY_AC_PWR_RDC_DISABLE                        0x000001ccU
+#define _reg_PHY_DATA_BYTE_ORDER_SEL                       0x000001cdU
+#define _reg_PHY_DATA_BYTE_ORDER_SEL_HIGH                  0x000001ceU
+#define _reg_PHY_LPDDR4_CONNECT                            0x000001cfU
+#define _reg_PHY_CALVL_DEVICE_MAP                          0x000001d0U
+#define _reg_PHY_ADR_DISABLE                               0x000001d1U
+#define _reg_PHY_ADRCTL_MSTR_DLY_ENC_SEL                   0x000001d2U
+#define _reg_PHY_CS_DLY_UPT_PER_AC_SLICE                   0x000001d3U
+#define _reg_PHY_DDL_AC_ENABLE                             0x000001d4U
+#define _reg_PHY_DDL_AC_MODE                               0x000001d5U
+#define _reg_PHY_PAD_BACKGROUND_CAL                        0x000001d6U
+#define _reg_PHY_INIT_UPDATE_CONFIG                        0x000001d7U
+#define _reg_PHY_DDL_TRACK_UPD_THRESHOLD_AC                0x000001d8U
+#define _reg_PHY_DLL_RST_EN                                0x000001d9U
+#define _reg_PHY_AC_INIT_COMPLETE_OBS                      0x000001daU
+#define _reg_PHY_DS_INIT_COMPLETE_OBS                      0x000001dbU
+#define _reg_PHY_UPDATE_MASK                               0x000001dcU
+#define _reg_PHY_PLL_SWITCH_CNT                            0x000001ddU
+#define _reg_PI_START                                      0x000001deU
+#define _reg_PI_DRAM_CLASS                                 0x000001dfU
+#define _reg_PI_VERSION                                    0x000001e0U
+#define _reg_PI_NORMAL_LVL_SEQ                             0x000001e1U
+#define _reg_PI_INIT_LVL_EN                                0x000001e2U
+#define _reg_PI_NOTCARE_PHYUPD                             0x000001e3U
+#define _reg_PI_ONBUS_MBIST                                0x000001e4U
+#define _reg_PI_TCMD_GAP                                   0x000001e5U
+#define _reg_PI_MASTER_ACK_DURATION_MIN                    0x000001e6U
+#define _reg_PI_DFI_VERSION                                0x000001e7U
+#define _reg_PI_TDFI_PHYMSTR_TYPE0                         0x000001e8U
+#define _reg_PI_TDFI_PHYMSTR_TYPE1                         0x000001e9U
+#define _reg_PI_TDFI_PHYMSTR_TYPE2                         0x000001eaU
+#define _reg_PI_TDFI_PHYMSTR_TYPE3                         0x000001ebU
+#define _reg_PI_DFI_PHYMSTR_TYPE                           0x000001ecU
+#define _reg_PI_DFI_PHYMSTR_CS_STATE_R                     0x000001edU
+#define _reg_PI_DFI_PHYMSTR_STATE_SEL_R                    0x000001eeU
+#define _reg_PI_TDFI_PHYMSTR_MAX_F0                        0x000001efU
+#define _reg_PI_TDFI_PHYMSTR_RESP_F0                       0x000001f0U
+#define _reg_PI_TDFI_PHYMSTR_MAX_F1                        0x000001f1U
+#define _reg_PI_TDFI_PHYMSTR_RESP_F1                       0x000001f2U
+#define _reg_PI_TDFI_PHYMSTR_MAX_F2                        0x000001f3U
+#define _reg_PI_TDFI_PHYMSTR_RESP_F2                       0x000001f4U
+#define _reg_PI_TDFI_PHYUPD_RESP_F0                        0x000001f5U
+#define _reg_PI_TDFI_PHYUPD_TYPE0_F0                       0x000001f6U
+#define _reg_PI_TDFI_PHYUPD_TYPE1_F0                       0x000001f7U
+#define _reg_PI_TDFI_PHYUPD_TYPE2_F0                       0x000001f8U
+#define _reg_PI_TDFI_PHYUPD_TYPE3_F0                       0x000001f9U
+#define _reg_PI_TDFI_PHYUPD_RESP_F1                        0x000001faU
+#define _reg_PI_TDFI_PHYUPD_TYPE0_F1                       0x000001fbU
+#define _reg_PI_TDFI_PHYUPD_TYPE1_F1                       0x000001fcU
+#define _reg_PI_TDFI_PHYUPD_TYPE2_F1                       0x000001fdU
+#define _reg_PI_TDFI_PHYUPD_TYPE3_F1                       0x000001feU
+#define _reg_PI_TDFI_PHYUPD_RESP_F2                        0x000001ffU
+#define _reg_PI_TDFI_PHYUPD_TYPE0_F2                       0x00000200U
+#define _reg_PI_TDFI_PHYUPD_TYPE1_F2                       0x00000201U
+#define _reg_PI_TDFI_PHYUPD_TYPE2_F2                       0x00000202U
+#define _reg_PI_TDFI_PHYUPD_TYPE3_F2                       0x00000203U
+#define _reg_PI_CONTROL_ERROR_STATUS                       0x00000204U
+#define _reg_PI_EXIT_AFTER_INIT_CALVL                      0x00000205U
+#define _reg_PI_FREQ_MAP                                   0x00000206U
+#define _reg_PI_INIT_WORK_FREQ                             0x00000207U
+#define _reg_PI_INIT_DFS_CALVL_ONLY                        0x00000208U
+#define _reg_PI_POWER_ON_SEQ_BYPASS_ARRAY                  0x00000209U
+#define _reg_PI_POWER_ON_SEQ_END_ARRAY                     0x0000020aU
+#define _reg_PI_SEQ1_PAT                                   0x0000020bU
+#define _reg_PI_SEQ1_PAT_MASK                              0x0000020cU
+#define _reg_PI_SEQ2_PAT                                   0x0000020dU
+#define _reg_PI_SEQ2_PAT_MASK                              0x0000020eU
+#define _reg_PI_SEQ3_PAT                                   0x0000020fU
+#define _reg_PI_SEQ3_PAT_MASK                              0x00000210U
+#define _reg_PI_SEQ4_PAT                                   0x00000211U
+#define _reg_PI_SEQ4_PAT_MASK                              0x00000212U
+#define _reg_PI_SEQ5_PAT                                   0x00000213U
+#define _reg_PI_SEQ5_PAT_MASK                              0x00000214U
+#define _reg_PI_SEQ6_PAT                                   0x00000215U
+#define _reg_PI_SEQ6_PAT_MASK                              0x00000216U
+#define _reg_PI_SEQ7_PAT                                   0x00000217U
+#define _reg_PI_SEQ7_PAT_MASK                              0x00000218U
+#define _reg_PI_SEQ8_PAT                                   0x00000219U
+#define _reg_PI_SEQ8_PAT_MASK                              0x0000021aU
+#define _reg_PI_WDT_DISABLE                                0x0000021bU
+#define _reg_PI_SW_RST_N                                   0x0000021cU
+#define _reg_RESERVED_R0                                   0x0000021dU
+#define _reg_PI_CS_MAP                                     0x0000021eU
+#define _reg_PI_TDELAY_RDWR_2_BUS_IDLE_F0                  0x0000021fU
+#define _reg_PI_TDELAY_RDWR_2_BUS_IDLE_F1                  0x00000220U
+#define _reg_PI_TDELAY_RDWR_2_BUS_IDLE_F2                  0x00000221U
+#define _reg_PI_TMRR                                       0x00000222U
+#define _reg_PI_WRLAT_F0                                   0x00000223U
+#define _reg_PI_ADDITIVE_LAT_F0                            0x00000224U
+#define _reg_PI_CASLAT_LIN_F0                              0x00000225U
+#define _reg_PI_WRLAT_F1                                   0x00000226U
+#define _reg_PI_ADDITIVE_LAT_F1                            0x00000227U
+#define _reg_PI_CASLAT_LIN_F1                              0x00000228U
+#define _reg_PI_WRLAT_F2                                   0x00000229U
+#define _reg_PI_ADDITIVE_LAT_F2                            0x0000022aU
+#define _reg_PI_CASLAT_LIN_F2                              0x0000022bU
+#define _reg_PI_PREAMBLE_SUPPORT                           0x0000022cU
+#define _reg_PI_AREFRESH                                   0x0000022dU
+#define _reg_PI_MCAREF_FORWARD_ONLY                        0x0000022eU
+#define _reg_PI_TRFC_F0                                    0x0000022fU
+#define _reg_PI_TREF_F0                                    0x00000230U
+#define _reg_PI_TRFC_F1                                    0x00000231U
+#define _reg_PI_TREF_F1                                    0x00000232U
+#define _reg_PI_TRFC_F2                                    0x00000233U
+#define _reg_PI_TREF_F2                                    0x00000234U
+#define _reg_RESERVED_H3VER2                               0x00000235U
+#define _reg_PI_TREF_INTERVAL                              0x00000236U
+#define _reg_PI_FREQ_CHANGE_REG_COPY                       0x00000237U
+#define _reg_PI_FREQ_SEL_FROM_REGIF                        0x00000238U
+#define _reg_PI_SWLVL_LOAD                                 0x00000239U
+#define _reg_PI_SWLVL_OP_DONE                              0x0000023aU
+#define _reg_PI_SW_WRLVL_RESP_0                            0x0000023bU
+#define _reg_PI_SW_WRLVL_RESP_1                            0x0000023cU
+#define _reg_PI_SW_WRLVL_RESP_2                            0x0000023dU
+#define _reg_PI_SW_WRLVL_RESP_3                            0x0000023eU
+#define _reg_PI_SW_RDLVL_RESP_0                            0x0000023fU
+#define _reg_PI_SW_RDLVL_RESP_1                            0x00000240U
+#define _reg_PI_SW_RDLVL_RESP_2                            0x00000241U
+#define _reg_PI_SW_RDLVL_RESP_3                            0x00000242U
+#define _reg_PI_SW_CALVL_RESP_0                            0x00000243U
+#define _reg_PI_SW_LEVELING_MODE                           0x00000244U
+#define _reg_PI_SWLVL_START                                0x00000245U
+#define _reg_PI_SWLVL_EXIT                                 0x00000246U
+#define _reg_PI_SWLVL_WR_SLICE_0                           0x00000247U
+#define _reg_PI_SWLVL_RD_SLICE_0                           0x00000248U
+#define _reg_PI_SWLVL_VREF_UPDATE_SLICE_0                  0x00000249U
+#define _reg_PI_SW_WDQLVL_RESP_0                           0x0000024aU
+#define _reg_PI_SWLVL_WR_SLICE_1                           0x0000024bU
+#define _reg_PI_SWLVL_RD_SLICE_1                           0x0000024cU
+#define _reg_PI_SWLVL_VREF_UPDATE_SLICE_1                  0x0000024dU
+#define _reg_PI_SW_WDQLVL_RESP_1                           0x0000024eU
+#define _reg_PI_SWLVL_WR_SLICE_2                           0x0000024fU
+#define _reg_PI_SWLVL_RD_SLICE_2                           0x00000250U
+#define _reg_PI_SWLVL_VREF_UPDATE_SLICE_2                  0x00000251U
+#define _reg_PI_SW_WDQLVL_RESP_2                           0x00000252U
+#define _reg_PI_SWLVL_WR_SLICE_3                           0x00000253U
+#define _reg_PI_SWLVL_RD_SLICE_3                           0x00000254U
+#define _reg_PI_SWLVL_VREF_UPDATE_SLICE_3                  0x00000255U
+#define _reg_PI_SW_WDQLVL_RESP_3                           0x00000256U
+#define _reg_PI_SW_WDQLVL_VREF                             0x00000257U
+#define _reg_PI_SWLVL_SM2_START                            0x00000258U
+#define _reg_PI_SWLVL_SM2_WR                               0x00000259U
+#define _reg_PI_SWLVL_SM2_RD                               0x0000025aU
+#define _reg_PI_SEQUENTIAL_LVL_REQ                         0x0000025bU
+#define _reg_PI_DFS_PERIOD_EN                              0x0000025cU
+#define _reg_PI_SRE_PERIOD_EN                              0x0000025dU
+#define _reg_PI_DFI40_POLARITY                             0x0000025eU
+#define _reg_PI_16BIT_DRAM_CONNECT                         0x0000025fU
+#define _reg_PI_TDFI_CTRL_DELAY_F0                         0x00000260U
+#define _reg_PI_TDFI_CTRL_DELAY_F1                         0x00000261U
+#define _reg_PI_TDFI_CTRL_DELAY_F2                         0x00000262U
+#define _reg_PI_WRLVL_REQ                                  0x00000263U
+#define _reg_PI_WRLVL_CS                                   0x00000264U
+#define _reg_PI_WLDQSEN                                    0x00000265U
+#define _reg_PI_WLMRD                                      0x00000266U
+#define _reg_PI_WRLVL_EN_F0                                0x00000267U
+#define _reg_PI_WRLVL_EN_F1                                0x00000268U
+#define _reg_PI_WRLVL_EN_F2                                0x00000269U
+#define _reg_PI_WRLVL_EN                                   0x0000026aU
+#define _reg_PI_WRLVL_INTERVAL                             0x0000026bU
+#define _reg_PI_WRLVL_PERIODIC                             0x0000026cU
+#define _reg_PI_WRLVL_ON_SREF_EXIT                         0x0000026dU
+#define _reg_PI_WRLVL_DISABLE_DFS                          0x0000026eU
+#define _reg_PI_WRLVL_RESP_MASK                            0x0000026fU
+#define _reg_PI_WRLVL_ROTATE                               0x00000270U
+#define _reg_PI_WRLVL_CS_MAP                               0x00000271U
+#define _reg_PI_WRLVL_ERROR_STATUS                         0x00000272U
+#define _reg_PI_TDFI_WRLVL_EN                              0x00000273U
+#define _reg_PI_TDFI_WRLVL_WW_F0                           0x00000274U
+#define _reg_PI_TDFI_WRLVL_WW_F1                           0x00000275U
+#define _reg_PI_TDFI_WRLVL_WW_F2                           0x00000276U
+#define _reg_PI_TDFI_WRLVL_WW                              0x00000277U
+#define _reg_PI_TDFI_WRLVL_RESP                            0x00000278U
+#define _reg_PI_TDFI_WRLVL_MAX                             0x00000279U
+#define _reg_PI_WRLVL_STROBE_NUM                           0x0000027aU
+#define _reg_PI_WRLVL_MRR_DQ_RETURN_HIZ                    0x0000027bU
+#define _reg_PI_WRLVL_EN_DEASSERT_2_MRR                    0x0000027cU
+#define _reg_PI_TODTL_2CMD_F0                              0x0000027dU
+#define _reg_PI_ODT_EN_F0                                  0x0000027eU
+#define _reg_PI_TODTL_2CMD_F1                              0x0000027fU
+#define _reg_PI_ODT_EN_F1                                  0x00000280U
+#define _reg_PI_TODTL_2CMD_F2                              0x00000281U
+#define _reg_PI_ODT_EN_F2                                  0x00000282U
+#define _reg_PI_TODTH_WR                                   0x00000283U
+#define _reg_PI_TODTH_RD                                   0x00000284U
+#define _reg_PI_ODT_RD_MAP_CS0                             0x00000285U
+#define _reg_PI_ODT_WR_MAP_CS0                             0x00000286U
+#define _reg_PI_ODT_RD_MAP_CS1                             0x00000287U
+#define _reg_PI_ODT_WR_MAP_CS1                             0x00000288U
+#define _reg_PI_ODT_RD_MAP_CS2                             0x00000289U
+#define _reg_PI_ODT_WR_MAP_CS2                             0x0000028aU
+#define _reg_PI_ODT_RD_MAP_CS3                             0x0000028bU
+#define _reg_PI_ODT_WR_MAP_CS3                             0x0000028cU
+#define _reg_PI_EN_ODT_ASSERT_EXCEPT_RD                    0x0000028dU
+#define _reg_PI_ODTLON_F0                                  0x0000028eU
+#define _reg_PI_TODTON_MIN_F0                              0x0000028fU
+#define _reg_PI_ODTLON_F1                                  0x00000290U
+#define _reg_PI_TODTON_MIN_F1                              0x00000291U
+#define _reg_PI_ODTLON_F2                                  0x00000292U
+#define _reg_PI_TODTON_MIN_F2                              0x00000293U
+#define _reg_PI_WR_TO_ODTH_F0                              0x00000294U
+#define _reg_PI_WR_TO_ODTH_F1                              0x00000295U
+#define _reg_PI_WR_TO_ODTH_F2                              0x00000296U
+#define _reg_PI_RD_TO_ODTH_F0                              0x00000297U
+#define _reg_PI_RD_TO_ODTH_F1                              0x00000298U
+#define _reg_PI_RD_TO_ODTH_F2                              0x00000299U
+#define _reg_PI_ADDRESS_MIRRORING                          0x0000029aU
+#define _reg_PI_RDLVL_REQ                                  0x0000029bU
+#define _reg_PI_RDLVL_GATE_REQ                             0x0000029cU
+#define _reg_PI_RDLVL_CS                                   0x0000029dU
+#define _reg_PI_RDLVL_PAT_0                                0x0000029eU
+#define _reg_PI_RDLVL_PAT_1                                0x0000029fU
+#define _reg_PI_RDLVL_PAT_2                                0x000002a0U
+#define _reg_PI_RDLVL_PAT_3                                0x000002a1U
+#define _reg_PI_RDLVL_PAT_4                                0x000002a2U
+#define _reg_PI_RDLVL_PAT_5                                0x000002a3U
+#define _reg_PI_RDLVL_PAT_6                                0x000002a4U
+#define _reg_PI_RDLVL_PAT_7                                0x000002a5U
+#define _reg_PI_RDLVL_SEQ_EN                               0x000002a6U
+#define _reg_PI_RDLVL_GATE_SEQ_EN                          0x000002a7U
+#define _reg_PI_RDLVL_PERIODIC                             0x000002a8U
+#define _reg_PI_RDLVL_ON_SREF_EXIT                         0x000002a9U
+#define _reg_PI_RDLVL_DISABLE_DFS                          0x000002aaU
+#define _reg_PI_RDLVL_GATE_PERIODIC                        0x000002abU
+#define _reg_PI_RDLVL_GATE_ON_SREF_EXIT                    0x000002acU
+#define _reg_PI_RDLVL_GATE_DISABLE_DFS                     0x000002adU
+#define _reg_RESERVED_R1                                   0x000002aeU
+#define _reg_PI_RDLVL_ROTATE                               0x000002afU
+#define _reg_PI_RDLVL_GATE_ROTATE                          0x000002b0U
+#define _reg_PI_RDLVL_CS_MAP                               0x000002b1U
+#define _reg_PI_RDLVL_GATE_CS_MAP                          0x000002b2U
+#define _reg_PI_TDFI_RDLVL_RR                              0x000002b3U
+#define _reg_PI_TDFI_RDLVL_RESP                            0x000002b4U
+#define _reg_PI_RDLVL_RESP_MASK                            0x000002b5U
+#define _reg_PI_TDFI_RDLVL_EN                              0x000002b6U
+#define _reg_PI_RDLVL_EN_F0                                0x000002b7U
+#define _reg_PI_RDLVL_GATE_EN_F0                           0x000002b8U
+#define _reg_PI_RDLVL_EN_F1                                0x000002b9U
+#define _reg_PI_RDLVL_GATE_EN_F1                           0x000002baU
+#define _reg_PI_RDLVL_EN_F2                                0x000002bbU
+#define _reg_PI_RDLVL_GATE_EN_F2                           0x000002bcU
+#define _reg_PI_RDLVL_EN                                   0x000002bdU
+#define _reg_PI_RDLVL_GATE_EN                              0x000002beU
+#define _reg_PI_TDFI_RDLVL_MAX                             0x000002bfU
+#define _reg_PI_RDLVL_ERROR_STATUS                         0x000002c0U
+#define _reg_PI_RDLVL_INTERVAL                             0x000002c1U
+#define _reg_PI_RDLVL_GATE_INTERVAL                        0x000002c2U
+#define _reg_PI_RDLVL_PATTERN_START                        0x000002c3U
+#define _reg_PI_RDLVL_PATTERN_NUM                          0x000002c4U
+#define _reg_PI_RDLVL_STROBE_NUM                           0x000002c5U
+#define _reg_PI_RDLVL_GATE_STROBE_NUM                      0x000002c6U
+#define _reg_PI_LPDDR4_RDLVL_PATTERN_8                     0x000002c7U
+#define _reg_PI_LPDDR4_RDLVL_PATTERN_9                     0x000002c8U
+#define _reg_PI_LPDDR4_RDLVL_PATTERN_10                    0x000002c9U
+#define _reg_PI_LPDDR4_RDLVL_PATTERN_11                    0x000002caU
+#define _reg_PI_RD_PREAMBLE_TRAINING_EN                    0x000002cbU
+#define _reg_PI_REG_DIMM_ENABLE                            0x000002ccU
+#define _reg_PI_RDLAT_ADJ_F0                               0x000002cdU
+#define _reg_PI_RDLAT_ADJ_F1                               0x000002ceU
+#define _reg_PI_RDLAT_ADJ_F2                               0x000002cfU
+#define _reg_PI_TDFI_RDDATA_EN                             0x000002d0U
+#define _reg_PI_WRLAT_ADJ_F0                               0x000002d1U
+#define _reg_PI_WRLAT_ADJ_F1                               0x000002d2U
+#define _reg_PI_WRLAT_ADJ_F2                               0x000002d3U
+#define _reg_PI_TDFI_PHY_WRLAT                             0x000002d4U
+#define _reg_PI_TDFI_WRCSLAT_F0                            0x000002d5U
+#define _reg_PI_TDFI_WRCSLAT_F1                            0x000002d6U
+#define _reg_PI_TDFI_WRCSLAT_F2                            0x000002d7U
+#define _reg_PI_TDFI_RDCSLAT_F0                            0x000002d8U
+#define _reg_PI_TDFI_RDCSLAT_F1                            0x000002d9U
+#define _reg_PI_TDFI_RDCSLAT_F2                            0x000002daU
+#define _reg_PI_TDFI_PHY_WRDATA_F0                         0x000002dbU
+#define _reg_PI_TDFI_PHY_WRDATA_F1                         0x000002dcU
+#define _reg_PI_TDFI_PHY_WRDATA_F2                         0x000002ddU
+#define _reg_PI_TDFI_PHY_WRDATA                            0x000002deU
+#define _reg_PI_CALVL_REQ                                  0x000002dfU
+#define _reg_PI_CALVL_CS                                   0x000002e0U
+#define _reg_RESERVED_R2                                   0x000002e1U
+#define _reg_RESERVED_R3                                   0x000002e2U
+#define _reg_PI_CALVL_SEQ_EN                               0x000002e3U
+#define _reg_PI_CALVL_PERIODIC                             0x000002e4U
+#define _reg_PI_CALVL_ON_SREF_EXIT                         0x000002e5U
+#define _reg_PI_CALVL_DISABLE_DFS                          0x000002e6U
+#define _reg_PI_CALVL_ROTATE                               0x000002e7U
+#define _reg_PI_CALVL_CS_MAP                               0x000002e8U
+#define _reg_PI_TDFI_CALVL_EN                              0x000002e9U
+#define _reg_PI_TDFI_CALVL_CC_F0                           0x000002eaU
+#define _reg_PI_TDFI_CALVL_CAPTURE_F0                      0x000002ebU
+#define _reg_PI_TDFI_CALVL_CC_F1                           0x000002ecU
+#define _reg_PI_TDFI_CALVL_CAPTURE_F1                      0x000002edU
+#define _reg_PI_TDFI_CALVL_CC_F2                           0x000002eeU
+#define _reg_PI_TDFI_CALVL_CAPTURE_F2                      0x000002efU
+#define _reg_PI_TDFI_CALVL_RESP                            0x000002f0U
+#define _reg_PI_TDFI_CALVL_MAX                             0x000002f1U
+#define _reg_PI_CALVL_RESP_MASK                            0x000002f2U
+#define _reg_PI_CALVL_EN_F0                                0x000002f3U
+#define _reg_PI_CALVL_EN_F1                                0x000002f4U
+#define _reg_PI_CALVL_EN_F2                                0x000002f5U
+#define _reg_PI_CALVL_EN                                   0x000002f6U
+#define _reg_PI_CALVL_ERROR_STATUS                         0x000002f7U
+#define _reg_PI_CALVL_INTERVAL                             0x000002f8U
+#define _reg_PI_TCACKEL                                    0x000002f9U
+#define _reg_PI_TCAMRD                                     0x000002faU
+#define _reg_PI_TCACKEH                                    0x000002fbU
+#define _reg_PI_TMRZ_F0                                    0x000002fcU
+#define _reg_PI_TCAENT_F0                                  0x000002fdU
+#define _reg_PI_TMRZ_F1                                    0x000002feU
+#define _reg_PI_TCAENT_F1                                  0x000002ffU
+#define _reg_PI_TMRZ_F2                                    0x00000300U
+#define _reg_PI_TCAENT_F2                                  0x00000301U
+#define _reg_PI_TCAEXT                                     0x00000302U
+#define _reg_PI_CA_TRAIN_VREF_EN                           0x00000303U
+#define _reg_PI_TDFI_CACSCA_F0                             0x00000304U
+#define _reg_PI_TDFI_CASEL_F0                              0x00000305U
+#define _reg_PI_TVREF_SHORT_F0                             0x00000306U
+#define _reg_PI_TVREF_LONG_F0                              0x00000307U
+#define _reg_PI_TDFI_CACSCA_F1                             0x00000308U
+#define _reg_PI_TDFI_CASEL_F1                              0x00000309U
+#define _reg_PI_TVREF_SHORT_F1                             0x0000030aU
+#define _reg_PI_TVREF_LONG_F1                              0x0000030bU
+#define _reg_PI_TDFI_CACSCA_F2                             0x0000030cU
+#define _reg_PI_TDFI_CASEL_F2                              0x0000030dU
+#define _reg_PI_TVREF_SHORT_F2                             0x0000030eU
+#define _reg_PI_TVREF_LONG_F2                              0x0000030fU
+#define _reg_PI_CALVL_VREF_INITIAL_START_POINT_F0          0x00000310U
+#define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT_F0           0x00000311U
+#define _reg_PI_CALVL_VREF_INITIAL_START_POINT_F1          0x00000312U
+#define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT_F1           0x00000313U
+#define _reg_PI_CALVL_VREF_INITIAL_START_POINT_F2          0x00000314U
+#define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT_F2           0x00000315U
+#define _reg_PI_CALVL_VREF_INITIAL_START_POINT             0x00000316U
+#define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT              0x00000317U
+#define _reg_PI_CALVL_VREF_INITIAL_STEPSIZE                0x00000318U
+#define _reg_PI_CALVL_VREF_NORMAL_STEPSIZE                 0x00000319U
+#define _reg_PI_CALVL_VREF_DELTA_F0                        0x0000031aU
+#define _reg_PI_CALVL_VREF_DELTA_F1                        0x0000031bU
+#define _reg_PI_CALVL_VREF_DELTA_F2                        0x0000031cU
+#define _reg_PI_CALVL_VREF_DELTA                           0x0000031dU
+#define _reg_PI_TDFI_INIT_START_MIN                        0x0000031eU
+#define _reg_PI_TDFI_INIT_COMPLETE_MIN                     0x0000031fU
+#define _reg_PI_TDFI_CALVL_STROBE_F0                       0x00000320U
+#define _reg_PI_TXP_F0                                     0x00000321U
+#define _reg_PI_TMRWCKEL_F0                                0x00000322U
+#define _reg_PI_TCKELCK_F0                                 0x00000323U
+#define _reg_PI_TDFI_CALVL_STROBE_F1                       0x00000324U
+#define _reg_PI_TXP_F1                                     0x00000325U
+#define _reg_PI_TMRWCKEL_F1                                0x00000326U
+#define _reg_PI_TCKELCK_F1                                 0x00000327U
+#define _reg_PI_TDFI_CALVL_STROBE_F2                       0x00000328U
+#define _reg_PI_TXP_F2                                     0x00000329U
+#define _reg_PI_TMRWCKEL_F2                                0x0000032aU
+#define _reg_PI_TCKELCK_F2                                 0x0000032bU
+#define _reg_PI_TCKCKEH                                    0x0000032cU
+#define _reg_PI_CALVL_STROBE_NUM                           0x0000032dU
+#define _reg_PI_SW_CA_TRAIN_VREF                           0x0000032eU
+#define _reg_PI_TDFI_INIT_START_F0                         0x0000032fU
+#define _reg_PI_TDFI_INIT_COMPLETE_F0                      0x00000330U
+#define _reg_PI_TDFI_INIT_START_F1                         0x00000331U
+#define _reg_PI_TDFI_INIT_COMPLETE_F1                      0x00000332U
+#define _reg_PI_TDFI_INIT_START_F2                         0x00000333U
+#define _reg_PI_TDFI_INIT_COMPLETE_F2                      0x00000334U
+#define _reg_PI_CLKDISABLE_2_INIT_START                    0x00000335U
+#define _reg_PI_INIT_STARTORCOMPLETE_2_CLKDISABLE          0x00000336U
+#define _reg_PI_DRAM_CLK_DISABLE_DEASSERT_SEL              0x00000337U
+#define _reg_PI_REFRESH_BETWEEN_SEGMENT_DISABLE            0x00000338U
+#define _reg_PI_TCKEHDQS_F0                                0x00000339U
+#define _reg_PI_TCKEHDQS_F1                                0x0000033aU
+#define _reg_PI_TCKEHDQS_F2                                0x0000033bU
+#define _reg_PI_MC_DFS_PI_SET_VREF_ENABLE                  0x0000033cU
+#define _reg_PI_WDQLVL_VREF_EN                             0x0000033dU
+#define _reg_PI_WDQLVL_BST_NUM                             0x0000033eU
+#define _reg_PI_TDFI_WDQLVL_WR_F0                          0x0000033fU
+#define _reg_PI_TDFI_WDQLVL_WR_F1                          0x00000340U
+#define _reg_PI_TDFI_WDQLVL_WR_F2                          0x00000341U
+#define _reg_PI_TDFI_WDQLVL_WR                             0x00000342U
+#define _reg_PI_TDFI_WDQLVL_RW                             0x00000343U
+#define _reg_PI_WDQLVL_RESP_MASK                           0x00000344U
+#define _reg_PI_WDQLVL_ROTATE                              0x00000345U
+#define _reg_PI_WDQLVL_CS_MAP                              0x00000346U
+#define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F0         0x00000347U
+#define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F0          0x00000348U
+#define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F1         0x00000349U
+#define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F1          0x0000034aU
+#define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F2         0x0000034bU
+#define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F2          0x0000034cU
+#define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT            0x0000034dU
+#define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT             0x0000034eU
+#define _reg_PI_WDQLVL_VREF_INITIAL_STEPSIZE               0x0000034fU
+#define _reg_PI_WDQLVL_VREF_NORMAL_STEPSIZE                0x00000350U
+#define _reg_PI_WDQLVL_VREF_DELTA_F0                       0x00000351U
+#define _reg_PI_WDQLVL_VREF_DELTA_F1                       0x00000352U
+#define _reg_PI_WDQLVL_VREF_DELTA_F2                       0x00000353U
+#define _reg_PI_WDQLVL_VREF_DELTA                          0x00000354U
+#define _reg_PI_WDQLVL_PERIODIC                            0x00000355U
+#define _reg_PI_WDQLVL_REQ                                 0x00000356U
+#define _reg_PI_WDQLVL_CS                                  0x00000357U
+#define _reg_PI_TDFI_WDQLVL_EN                             0x00000358U
+#define _reg_PI_TDFI_WDQLVL_RESP                           0x00000359U
+#define _reg_PI_TDFI_WDQLVL_MAX                            0x0000035aU
+#define _reg_PI_WDQLVL_INTERVAL                            0x0000035bU
+#define _reg_PI_WDQLVL_EN_F0                               0x0000035cU
+#define _reg_PI_WDQLVL_EN_F1                               0x0000035dU
+#define _reg_PI_WDQLVL_EN_F2                               0x0000035eU
+#define _reg_PI_WDQLVL_EN                                  0x0000035fU
+#define _reg_PI_WDQLVL_ON_SREF_EXIT                        0x00000360U
+#define _reg_PI_WDQLVL_DISABLE_DFS                         0x00000361U
+#define _reg_PI_WDQLVL_ERROR_STATUS                        0x00000362U
+#define _reg_PI_MR1_DATA_F0_0                              0x00000363U
+#define _reg_PI_MR2_DATA_F0_0                              0x00000364U
+#define _reg_PI_MR3_DATA_F0_0                              0x00000365U
+#define _reg_PI_MR11_DATA_F0_0                             0x00000366U
+#define _reg_PI_MR12_DATA_F0_0                             0x00000367U
+#define _reg_PI_MR14_DATA_F0_0                             0x00000368U
+#define _reg_PI_MR22_DATA_F0_0                             0x00000369U
+#define _reg_PI_MR1_DATA_F1_0                              0x0000036aU
+#define _reg_PI_MR2_DATA_F1_0                              0x0000036bU
+#define _reg_PI_MR3_DATA_F1_0                              0x0000036cU
+#define _reg_PI_MR11_DATA_F1_0                             0x0000036dU
+#define _reg_PI_MR12_DATA_F1_0                             0x0000036eU
+#define _reg_PI_MR14_DATA_F1_0                             0x0000036fU
+#define _reg_PI_MR22_DATA_F1_0                             0x00000370U
+#define _reg_PI_MR1_DATA_F2_0                              0x00000371U
+#define _reg_PI_MR2_DATA_F2_0                              0x00000372U
+#define _reg_PI_MR3_DATA_F2_0                              0x00000373U
+#define _reg_PI_MR11_DATA_F2_0                             0x00000374U
+#define _reg_PI_MR12_DATA_F2_0                             0x00000375U
+#define _reg_PI_MR14_DATA_F2_0                             0x00000376U
+#define _reg_PI_MR22_DATA_F2_0                             0x00000377U
+#define _reg_PI_MR13_DATA_0                                0x00000378U
+#define _reg_PI_MR1_DATA_F0_1                              0x00000379U
+#define _reg_PI_MR2_DATA_F0_1                              0x0000037aU
+#define _reg_PI_MR3_DATA_F0_1                              0x0000037bU
+#define _reg_PI_MR11_DATA_F0_1                             0x0000037cU
+#define _reg_PI_MR12_DATA_F0_1                             0x0000037dU
+#define _reg_PI_MR14_DATA_F0_1                             0x0000037eU
+#define _reg_PI_MR22_DATA_F0_1                             0x0000037fU
+#define _reg_PI_MR1_DATA_F1_1                              0x00000380U
+#define _reg_PI_MR2_DATA_F1_1                              0x00000381U
+#define _reg_PI_MR3_DATA_F1_1                              0x00000382U
+#define _reg_PI_MR11_DATA_F1_1                             0x00000383U
+#define _reg_PI_MR12_DATA_F1_1                             0x00000384U
+#define _reg_PI_MR14_DATA_F1_1                             0x00000385U
+#define _reg_PI_MR22_DATA_F1_1                             0x00000386U
+#define _reg_PI_MR1_DATA_F2_1                              0x00000387U
+#define _reg_PI_MR2_DATA_F2_1                              0x00000388U
+#define _reg_PI_MR3_DATA_F2_1                              0x00000389U
+#define _reg_PI_MR11_DATA_F2_1                             0x0000038aU
+#define _reg_PI_MR12_DATA_F2_1                             0x0000038bU
+#define _reg_PI_MR14_DATA_F2_1                             0x0000038cU
+#define _reg_PI_MR22_DATA_F2_1                             0x0000038dU
+#define _reg_PI_MR13_DATA_1                                0x0000038eU
+#define _reg_PI_MR1_DATA_F0_2                              0x0000038fU
+#define _reg_PI_MR2_DATA_F0_2                              0x00000390U
+#define _reg_PI_MR3_DATA_F0_2                              0x00000391U
+#define _reg_PI_MR11_DATA_F0_2                             0x00000392U
+#define _reg_PI_MR12_DATA_F0_2                             0x00000393U
+#define _reg_PI_MR14_DATA_F0_2                             0x00000394U
+#define _reg_PI_MR22_DATA_F0_2                             0x00000395U
+#define _reg_PI_MR1_DATA_F1_2                              0x00000396U
+#define _reg_PI_MR2_DATA_F1_2                              0x00000397U
+#define _reg_PI_MR3_DATA_F1_2                              0x00000398U
+#define _reg_PI_MR11_DATA_F1_2                             0x00000399U
+#define _reg_PI_MR12_DATA_F1_2                             0x0000039aU
+#define _reg_PI_MR14_DATA_F1_2                             0x0000039bU
+#define _reg_PI_MR22_DATA_F1_2                             0x0000039cU
+#define _reg_PI_MR1_DATA_F2_2                              0x0000039dU
+#define _reg_PI_MR2_DATA_F2_2                              0x0000039eU
+#define _reg_PI_MR3_DATA_F2_2                              0x0000039fU
+#define _reg_PI_MR11_DATA_F2_2                             0x000003a0U
+#define _reg_PI_MR12_DATA_F2_2                             0x000003a1U
+#define _reg_PI_MR14_DATA_F2_2                             0x000003a2U
+#define _reg_PI_MR22_DATA_F2_2                             0x000003a3U
+#define _reg_PI_MR13_DATA_2                                0x000003a4U
+#define _reg_PI_MR1_DATA_F0_3                              0x000003a5U
+#define _reg_PI_MR2_DATA_F0_3                              0x000003a6U
+#define _reg_PI_MR3_DATA_F0_3                              0x000003a7U
+#define _reg_PI_MR11_DATA_F0_3                             0x000003a8U
+#define _reg_PI_MR12_DATA_F0_3                             0x000003a9U
+#define _reg_PI_MR14_DATA_F0_3                             0x000003aaU
+#define _reg_PI_MR22_DATA_F0_3                             0x000003abU
+#define _reg_PI_MR1_DATA_F1_3                              0x000003acU
+#define _reg_PI_MR2_DATA_F1_3                              0x000003adU
+#define _reg_PI_MR3_DATA_F1_3                              0x000003aeU
+#define _reg_PI_MR11_DATA_F1_3                             0x000003afU
+#define _reg_PI_MR12_DATA_F1_3                             0x000003b0U
+#define _reg_PI_MR14_DATA_F1_3                             0x000003b1U
+#define _reg_PI_MR22_DATA_F1_3                             0x000003b2U
+#define _reg_PI_MR1_DATA_F2_3                              0x000003b3U
+#define _reg_PI_MR2_DATA_F2_3                              0x000003b4U
+#define _reg_PI_MR3_DATA_F2_3                              0x000003b5U
+#define _reg_PI_MR11_DATA_F2_3                             0x000003b6U
+#define _reg_PI_MR12_DATA_F2_3                             0x000003b7U
+#define _reg_PI_MR14_DATA_F2_3                             0x000003b8U
+#define _reg_PI_MR22_DATA_F2_3                             0x000003b9U
+#define _reg_PI_MR13_DATA_3                                0x000003baU
+#define _reg_PI_BANK_DIFF                                  0x000003bbU
+#define _reg_PI_ROW_DIFF                                   0x000003bcU
+#define _reg_PI_TFC_F0                                     0x000003bdU
+#define _reg_PI_TFC_F1                                     0x000003beU
+#define _reg_PI_TFC_F2                                     0x000003bfU
+#define _reg_PI_TCCD                                       0x000003c0U
+#define _reg_PI_TRTP_F0                                    0x000003c1U
+#define _reg_PI_TRP_F0                                     0x000003c2U
+#define _reg_PI_TRCD_F0                                    0x000003c3U
+#define _reg_PI_TWTR_F0                                    0x000003c4U
+#define _reg_PI_TWR_F0                                     0x000003c5U
+#define _reg_PI_TRAS_MAX_F0                                0x000003c6U
+#define _reg_PI_TRAS_MIN_F0                                0x000003c7U
+#define _reg_PI_TDQSCK_MAX_F0                              0x000003c8U
+#define _reg_PI_TCCDMW_F0                                  0x000003c9U
+#define _reg_PI_TSR_F0                                     0x000003caU
+#define _reg_PI_TMRD_F0                                    0x000003cbU
+#define _reg_PI_TMRW_F0                                    0x000003ccU
+#define _reg_PI_TMOD_F0                                    0x000003cdU
+#define _reg_PI_TRTP_F1                                    0x000003ceU
+#define _reg_PI_TRP_F1                                     0x000003cfU
+#define _reg_PI_TRCD_F1                                    0x000003d0U
+#define _reg_PI_TWTR_F1                                    0x000003d1U
+#define _reg_PI_TWR_F1                                     0x000003d2U
+#define _reg_PI_TRAS_MAX_F1                                0x000003d3U
+#define _reg_PI_TRAS_MIN_F1                                0x000003d4U
+#define _reg_PI_TDQSCK_MAX_F1                              0x000003d5U
+#define _reg_PI_TCCDMW_F1                                  0x000003d6U
+#define _reg_PI_TSR_F1                                     0x000003d7U
+#define _reg_PI_TMRD_F1                                    0x000003d8U
+#define _reg_PI_TMRW_F1                                    0x000003d9U
+#define _reg_PI_TMOD_F1                                    0x000003daU
+#define _reg_PI_TRTP_F2                                    0x000003dbU
+#define _reg_PI_TRP_F2                                     0x000003dcU
+#define _reg_PI_TRCD_F2                                    0x000003ddU
+#define _reg_PI_TWTR_F2                                    0x000003deU
+#define _reg_PI_TWR_F2                                     0x000003dfU
+#define _reg_PI_TRAS_MAX_F2                                0x000003e0U
+#define _reg_PI_TRAS_MIN_F2                                0x000003e1U
+#define _reg_PI_TDQSCK_MAX_F2                              0x000003e2U
+#define _reg_PI_TCCDMW_F2                                  0x000003e3U
+#define _reg_PI_TSR_F2                                     0x000003e4U
+#define _reg_PI_TMRD_F2                                    0x000003e5U
+#define _reg_PI_TMRW_F2                                    0x000003e6U
+#define _reg_PI_TMOD_F2                                    0x000003e7U
+#define _reg_RESERVED_R4                                   0x000003e8U
+#define _reg_RESERVED_R5                                   0x000003e9U
+#define _reg_RESERVED_R6                                   0x000003eaU
+#define _reg_RESERVED_R7                                   0x000003ebU
+#define _reg_RESERVED_R8                                   0x000003ecU
+#define _reg_RESERVED_R9                                   0x000003edU
+#define _reg_RESERVED_R10                                  0x000003eeU
+#define _reg_RESERVED_R11                                  0x000003efU
+#define _reg_RESERVED_R12                                  0x000003f0U
+#define _reg_RESERVED_R13                                  0x000003f1U
+#define _reg_RESERVED_R14                                  0x000003f2U
+#define _reg_RESERVED_R15                                  0x000003f3U
+#define _reg_RESERVED_R16                                  0x000003f4U
+#define _reg_RESERVED_R17                                  0x000003f5U
+#define _reg_RESERVED_R18                                  0x000003f6U
+#define _reg_RESERVED_R19                                  0x000003f7U
+#define _reg_RESERVED_R20                                  0x000003f8U
+#define _reg_RESERVED_R21                                  0x000003f9U
+#define _reg_RESERVED_R22                                  0x000003faU
+#define _reg_RESERVED_R23                                  0x000003fbU
+#define _reg_PI_INT_STATUS                                 0x000003fcU
+#define _reg_PI_INT_ACK                                    0x000003fdU
+#define _reg_PI_INT_MASK                                   0x000003feU
+#define _reg_PI_BIST_EXP_DATA_P0                           0x000003ffU
+#define _reg_PI_BIST_EXP_DATA_P1                           0x00000400U
+#define _reg_PI_BIST_EXP_DATA_P2                           0x00000401U
+#define _reg_PI_BIST_EXP_DATA_P3                           0x00000402U
+#define _reg_PI_BIST_FAIL_DATA_P0                          0x00000403U
+#define _reg_PI_BIST_FAIL_DATA_P1                          0x00000404U
+#define _reg_PI_BIST_FAIL_DATA_P2                          0x00000405U
+#define _reg_PI_BIST_FAIL_DATA_P3                          0x00000406U
+#define _reg_PI_BIST_FAIL_ADDR_P0                          0x00000407U
+#define _reg_PI_BIST_FAIL_ADDR_P1                          0x00000408U
+#define _reg_PI_BSTLEN                                     0x00000409U
+#define _reg_PI_LONG_COUNT_MASK                            0x0000040aU
+#define _reg_PI_CMD_SWAP_EN                                0x0000040bU
+#define _reg_PI_CKE_MUX_0                                  0x0000040cU
+#define _reg_PI_CKE_MUX_1                                  0x0000040dU
+#define _reg_PI_CKE_MUX_2                                  0x0000040eU
+#define _reg_PI_CKE_MUX_3                                  0x0000040fU
+#define _reg_PI_CS_MUX_0                                   0x00000410U
+#define _reg_PI_CS_MUX_1                                   0x00000411U
+#define _reg_PI_CS_MUX_2                                   0x00000412U
+#define _reg_PI_CS_MUX_3                                   0x00000413U
+#define _reg_PI_RAS_N_MUX                                  0x00000414U
+#define _reg_PI_CAS_N_MUX                                  0x00000415U
+#define _reg_PI_WE_N_MUX                                   0x00000416U
+#define _reg_PI_BANK_MUX_0                                 0x00000417U
+#define _reg_PI_BANK_MUX_1                                 0x00000418U
+#define _reg_PI_BANK_MUX_2                                 0x00000419U
+#define _reg_PI_ODT_MUX_0                                  0x0000041aU
+#define _reg_PI_ODT_MUX_1                                  0x0000041bU
+#define _reg_PI_ODT_MUX_2                                  0x0000041cU
+#define _reg_PI_ODT_MUX_3                                  0x0000041dU
+#define _reg_PI_RESET_N_MUX_0                              0x0000041eU
+#define _reg_PI_RESET_N_MUX_1                              0x0000041fU
+#define _reg_PI_RESET_N_MUX_2                              0x00000420U
+#define _reg_PI_RESET_N_MUX_3                              0x00000421U
+#define _reg_PI_DATA_BYTE_SWAP_EN                          0x00000422U
+#define _reg_PI_DATA_BYTE_SWAP_SLICE0                      0x00000423U
+#define _reg_PI_DATA_BYTE_SWAP_SLICE1                      0x00000424U
+#define _reg_PI_DATA_BYTE_SWAP_SLICE2                      0x00000425U
+#define _reg_PI_DATA_BYTE_SWAP_SLICE3                      0x00000426U
+#define _reg_PI_CTRLUPD_REQ_PER_AREF_EN                    0x00000427U
+#define _reg_PI_TDFI_CTRLUPD_MIN                           0x00000428U
+#define _reg_PI_TDFI_CTRLUPD_MAX_F0                        0x00000429U
+#define _reg_PI_TDFI_CTRLUPD_INTERVAL_F0                   0x0000042aU
+#define _reg_PI_TDFI_CTRLUPD_MAX_F1                        0x0000042bU
+#define _reg_PI_TDFI_CTRLUPD_INTERVAL_F1                   0x0000042cU
+#define _reg_PI_TDFI_CTRLUPD_MAX_F2                        0x0000042dU
+#define _reg_PI_TDFI_CTRLUPD_INTERVAL_F2                   0x0000042eU
+#define _reg_PI_UPDATE_ERROR_STATUS                        0x0000042fU
+#define _reg_PI_BIST_GO                                    0x00000430U
+#define _reg_PI_BIST_RESULT                                0x00000431U
+#define _reg_PI_ADDR_SPACE                                 0x00000432U
+#define _reg_PI_BIST_DATA_CHECK                            0x00000433U
+#define _reg_PI_BIST_ADDR_CHECK                            0x00000434U
+#define _reg_PI_BIST_START_ADDRESS_P0                      0x00000435U
+#define _reg_PI_BIST_START_ADDRESS_P1                      0x00000436U
+#define _reg_PI_BIST_DATA_MASK_P0                          0x00000437U
+#define _reg_PI_BIST_DATA_MASK_P1                          0x00000438U
+#define _reg_PI_BIST_ERR_COUNT                             0x00000439U
+#define _reg_PI_BIST_ERR_STOP                              0x0000043aU
+#define _reg_PI_BIST_ADDR_MASK_0_P0                        0x0000043bU
+#define _reg_PI_BIST_ADDR_MASK_0_P1                        0x0000043cU
+#define _reg_PI_BIST_ADDR_MASK_1_P0                        0x0000043dU
+#define _reg_PI_BIST_ADDR_MASK_1_P1                        0x0000043eU
+#define _reg_PI_BIST_ADDR_MASK_2_P0                        0x0000043fU
+#define _reg_PI_BIST_ADDR_MASK_2_P1                        0x00000440U
+#define _reg_PI_BIST_ADDR_MASK_3_P0                        0x00000441U
+#define _reg_PI_BIST_ADDR_MASK_3_P1                        0x00000442U
+#define _reg_PI_BIST_ADDR_MASK_4_P0                        0x00000443U
+#define _reg_PI_BIST_ADDR_MASK_4_P1                        0x00000444U
+#define _reg_PI_BIST_ADDR_MASK_5_P0                        0x00000445U
+#define _reg_PI_BIST_ADDR_MASK_5_P1                        0x00000446U
+#define _reg_PI_BIST_ADDR_MASK_6_P0                        0x00000447U
+#define _reg_PI_BIST_ADDR_MASK_6_P1                        0x00000448U
+#define _reg_PI_BIST_ADDR_MASK_7_P0                        0x00000449U
+#define _reg_PI_BIST_ADDR_MASK_7_P1                        0x0000044aU
+#define _reg_PI_BIST_ADDR_MASK_8_P0                        0x0000044bU
+#define _reg_PI_BIST_ADDR_MASK_8_P1                        0x0000044cU
+#define _reg_PI_BIST_ADDR_MASK_9_P0                        0x0000044dU
+#define _reg_PI_BIST_ADDR_MASK_9_P1                        0x0000044eU
+#define _reg_PI_BIST_MODE                                  0x0000044fU
+#define _reg_PI_BIST_ADDR_MODE                             0x00000450U
+#define _reg_PI_BIST_PAT_MODE                              0x00000451U
+#define _reg_PI_BIST_USER_PAT_P0                           0x00000452U
+#define _reg_PI_BIST_USER_PAT_P1                           0x00000453U
+#define _reg_PI_BIST_USER_PAT_P2                           0x00000454U
+#define _reg_PI_BIST_USER_PAT_P3                           0x00000455U
+#define _reg_PI_BIST_PAT_NUM                               0x00000456U
+#define _reg_PI_BIST_STAGE_0                               0x00000457U
+#define _reg_PI_BIST_STAGE_1                               0x00000458U
+#define _reg_PI_BIST_STAGE_2                               0x00000459U
+#define _reg_PI_BIST_STAGE_3                               0x0000045aU
+#define _reg_PI_BIST_STAGE_4                               0x0000045bU
+#define _reg_PI_BIST_STAGE_5                               0x0000045cU
+#define _reg_PI_BIST_STAGE_6                               0x0000045dU
+#define _reg_PI_BIST_STAGE_7                               0x0000045eU
+#define _reg_PI_COL_DIFF                                   0x0000045fU
+#define _reg_PI_SELF_REFRESH_EN                            0x00000460U
+#define _reg_PI_TXSR_F0                                    0x00000461U
+#define _reg_PI_TXSR_F1                                    0x00000462U
+#define _reg_PI_TXSR_F2                                    0x00000463U
+#define _reg_PI_MONITOR_SRC_SEL_0                          0x00000464U
+#define _reg_PI_MONITOR_CAP_SEL_0                          0x00000465U
+#define _reg_PI_MONITOR_0                                  0x00000466U
+#define _reg_PI_MONITOR_SRC_SEL_1                          0x00000467U
+#define _reg_PI_MONITOR_CAP_SEL_1                          0x00000468U
+#define _reg_PI_MONITOR_1                                  0x00000469U
+#define _reg_PI_MONITOR_SRC_SEL_2                          0x0000046aU
+#define _reg_PI_MONITOR_CAP_SEL_2                          0x0000046bU
+#define _reg_PI_MONITOR_2                                  0x0000046cU
+#define _reg_PI_MONITOR_SRC_SEL_3                          0x0000046dU
+#define _reg_PI_MONITOR_CAP_SEL_3                          0x0000046eU
+#define _reg_PI_MONITOR_3                                  0x0000046fU
+#define _reg_PI_MONITOR_SRC_SEL_4                          0x00000470U
+#define _reg_PI_MONITOR_CAP_SEL_4                          0x00000471U
+#define _reg_PI_MONITOR_4                                  0x00000472U
+#define _reg_PI_MONITOR_SRC_SEL_5                          0x00000473U
+#define _reg_PI_MONITOR_CAP_SEL_5                          0x00000474U
+#define _reg_PI_MONITOR_5                                  0x00000475U
+#define _reg_PI_MONITOR_SRC_SEL_6                          0x00000476U
+#define _reg_PI_MONITOR_CAP_SEL_6                          0x00000477U
+#define _reg_PI_MONITOR_6                                  0x00000478U
+#define _reg_PI_MONITOR_SRC_SEL_7                          0x00000479U
+#define _reg_PI_MONITOR_CAP_SEL_7                          0x0000047aU
+#define _reg_PI_MONITOR_7                                  0x0000047bU
+#define _reg_PI_MONITOR_STROBE                             0x0000047cU
+#define _reg_PI_DLL_LOCK                                   0x0000047dU
+#define _reg_PI_FREQ_NUMBER_STATUS                         0x0000047eU
+#define _reg_RESERVED_R24                                  0x0000047fU
+#define _reg_PI_PHYMSTR_TYPE                               0x00000480U
+#define _reg_PI_POWER_REDUC_EN                             0x00000481U
+#define _reg_RESERVED_R25                                  0x00000482U
+#define _reg_RESERVED_R26                                  0x00000483U
+#define _reg_RESERVED_R27                                  0x00000484U
+#define _reg_RESERVED_R28                                  0x00000485U
+#define _reg_RESERVED_R29                                  0x00000486U
+#define _reg_RESERVED_R30                                  0x00000487U
+#define _reg_RESERVED_R31                                  0x00000488U
+#define _reg_RESERVED_R32                                  0x00000489U
+#define _reg_RESERVED_R33                                  0x0000048aU
+#define _reg_RESERVED_R34                                  0x0000048bU
+#define _reg_RESERVED_R35                                  0x0000048cU
+#define _reg_RESERVED_R36                                  0x0000048dU
+#define _reg_RESERVED_R37                                  0x0000048eU
+#define _reg_RESERVED_R38                                  0x0000048fU
+#define _reg_RESERVED_R39                                  0x00000490U
+#define _reg_PI_WRLVL_MAX_STROBE_PEND                      0x00000491U
+#define _reg_PI_TSDO_F0                                    0x00000492U
+#define _reg_PI_TSDO_F1                                    0x00000493U
+#define _reg_PI_TSDO_F2                                    0x00000494U
+
+#define DDR_REGDEF_ADR(regdef) ((regdef)&0xffff)
+#define DDR_REGDEF_LEN(regdef) (((regdef)>>16)&0xff)
+#define DDR_REGDEF_LSB(regdef) (((regdef)>>24)&0xff)
+
+static const uint32_t DDR_REGDEF_TBL[4][1173] = {
+	{
+/*0000*/ 0xffffffffU,
+/*0001*/ 0xffffffffU,
+/*0002*/ 0x000b0400U,
+/*0003*/ 0xffffffffU,
+/*0004*/ 0xffffffffU,
+/*0005*/ 0x10010400U,
+/*0006*/ 0x18050400U,
+/*0007*/ 0x00050401U,
+/*0008*/ 0x08050401U,
+/*0009*/ 0x10050401U,
+/*000a*/ 0x18050401U,
+/*000b*/ 0x00050402U,
+/*000c*/ 0x08050402U,
+/*000d*/ 0x10050402U,
+/*000e*/ 0x18050402U,
+/*000f*/ 0x00040403U,
+/*0010*/ 0x08030403U,
+/*0011*/ 0x00180404U,
+/*0012*/ 0x18030404U,
+/*0013*/ 0x00180405U,
+/*0014*/ 0x18020405U,
+/*0015*/ 0x00010406U,
+/*0016*/ 0x08020406U,
+/*0017*/ 0x10010406U,
+/*0018*/ 0x18010406U,
+/*0019*/ 0x00020407U,
+/*001a*/ 0x08040407U,
+/*001b*/ 0x10040407U,
+/*001c*/ 0x18040407U,
+/*001d*/ 0x000a0408U,
+/*001e*/ 0x10040408U,
+/*001f*/ 0xffffffffU,
+/*0020*/ 0xffffffffU,
+/*0021*/ 0x18070408U,
+/*0022*/ 0xffffffffU,
+/*0023*/ 0xffffffffU,
+/*0024*/ 0xffffffffU,
+/*0025*/ 0xffffffffU,
+/*0026*/ 0xffffffffU,
+/*0027*/ 0xffffffffU,
+/*0028*/ 0x000a0409U,
+/*0029*/ 0x10040409U,
+/*002a*/ 0x18010409U,
+/*002b*/ 0x0001040aU,
+/*002c*/ 0x0802040aU,
+/*002d*/ 0x1009040aU,
+/*002e*/ 0x0009040bU,
+/*002f*/ 0x1002040bU,
+/*0030*/ 0x0020040cU,
+/*0031*/ 0xffffffffU,
+/*0032*/ 0x0001040dU,
+/*0033*/ 0xffffffffU,
+/*0034*/ 0xffffffffU,
+/*0035*/ 0xffffffffU,
+/*0036*/ 0xffffffffU,
+/*0037*/ 0x0020040eU,
+/*0038*/ 0x0020040fU,
+/*0039*/ 0x00200410U,
+/*003a*/ 0x00200411U,
+/*003b*/ 0x00030412U,
+/*003c*/ 0x08010412U,
+/*003d*/ 0x10030412U,
+/*003e*/ 0x18030412U,
+/*003f*/ 0x00040413U,
+/*0040*/ 0x08040413U,
+/*0041*/ 0x10040413U,
+/*0042*/ 0x18040413U,
+/*0043*/ 0x00010414U,
+/*0044*/ 0x08010414U,
+/*0045*/ 0x10060414U,
+/*0046*/ 0x18040414U,
+/*0047*/ 0xffffffffU,
+/*0048*/ 0x00060415U,
+/*0049*/ 0x08040415U,
+/*004a*/ 0x10060415U,
+/*004b*/ 0x18040415U,
+/*004c*/ 0x00020416U,
+/*004d*/ 0x08050416U,
+/*004e*/ 0x10080416U,
+/*004f*/ 0x00200417U,
+/*0050*/ 0x00060418U,
+/*0051*/ 0x08030418U,
+/*0052*/ 0x100b0418U,
+/*0053*/ 0x00040419U,
+/*0054*/ 0x08040419U,
+/*0055*/ 0x10040419U,
+/*0056*/ 0xffffffffU,
+/*0057*/ 0x18010419U,
+/*0058*/ 0x0009041aU,
+/*0059*/ 0x0020041bU,
+/*005a*/ 0x0020041cU,
+/*005b*/ 0x0020041dU,
+/*005c*/ 0x0020041eU,
+/*005d*/ 0x0010041fU,
+/*005e*/ 0x00200420U,
+/*005f*/ 0x00010421U,
+/*0060*/ 0x08060421U,
+/*0061*/ 0x10080421U,
+/*0062*/ 0x00200422U,
+/*0063*/ 0xffffffffU,
+/*0064*/ 0x000a0423U,
+/*0065*/ 0x10060423U,
+/*0066*/ 0x18070423U,
+/*0067*/ 0x00080424U,
+/*0068*/ 0x08080424U,
+/*0069*/ 0x100a0424U,
+/*006a*/ 0x00070425U,
+/*006b*/ 0x08080425U,
+/*006c*/ 0x10080425U,
+/*006d*/ 0x18030425U,
+/*006e*/ 0x000a0426U,
+/*006f*/ 0x100a0426U,
+/*0070*/ 0x00110427U,
+/*0071*/ 0x00090428U,
+/*0072*/ 0x10090428U,
+/*0073*/ 0x00100429U,
+/*0074*/ 0x100e0429U,
+/*0075*/ 0x000e042aU,
+/*0076*/ 0x100c042aU,
+/*0077*/ 0x000a042bU,
+/*0078*/ 0x100a042bU,
+/*0079*/ 0x0002042cU,
+/*007a*/ 0x0020042dU,
+/*007b*/ 0x000b042eU,
+/*007c*/ 0x100b042eU,
+/*007d*/ 0x0020042fU,
+/*007e*/ 0x00120430U,
+/*007f*/ 0x00200431U,
+/*0080*/ 0x00200432U,
+/*0081*/ 0xffffffffU,
+/*0082*/ 0xffffffffU,
+/*0083*/ 0x00010433U,
+/*0084*/ 0x08010433U,
+/*0085*/ 0x10080433U,
+/*0086*/ 0x000c0434U,
+/*0087*/ 0x100c0434U,
+/*0088*/ 0x000c0435U,
+/*0089*/ 0x100c0435U,
+/*008a*/ 0x000c0436U,
+/*008b*/ 0x100c0436U,
+/*008c*/ 0x000c0437U,
+/*008d*/ 0x100c0437U,
+/*008e*/ 0x000c0438U,
+/*008f*/ 0x100c0438U,
+/*0090*/ 0x000c0439U,
+/*0091*/ 0x100b0439U,
+/*0092*/ 0xffffffffU,
+/*0093*/ 0xffffffffU,
+/*0094*/ 0x000b043aU,
+/*0095*/ 0x100b043aU,
+/*0096*/ 0x000b043bU,
+/*0097*/ 0x100b043bU,
+/*0098*/ 0x000b043cU,
+/*0099*/ 0x100b043cU,
+/*009a*/ 0x000b043dU,
+/*009b*/ 0x100b043dU,
+/*009c*/ 0x000b043eU,
+/*009d*/ 0x100a043eU,
+/*009e*/ 0xffffffffU,
+/*009f*/ 0x000a043fU,
+/*00a0*/ 0x100a043fU,
+/*00a1*/ 0x000a0440U,
+/*00a2*/ 0x100a0440U,
+/*00a3*/ 0x000a0441U,
+/*00a4*/ 0x100a0441U,
+/*00a5*/ 0x000a0442U,
+/*00a6*/ 0x100a0442U,
+/*00a7*/ 0xffffffffU,
+/*00a8*/ 0x000a0443U,
+/*00a9*/ 0x100a0443U,
+/*00aa*/ 0x000a0444U,
+/*00ab*/ 0x100a0444U,
+/*00ac*/ 0x000a0445U,
+/*00ad*/ 0x100a0445U,
+/*00ae*/ 0x000a0446U,
+/*00af*/ 0x100a0446U,
+/*00b0*/ 0x000a0447U,
+/*00b1*/ 0x100a0447U,
+/*00b2*/ 0x000a0448U,
+/*00b3*/ 0x100a0448U,
+/*00b4*/ 0x000a0449U,
+/*00b5*/ 0x100a0449U,
+/*00b6*/ 0x000a044aU,
+/*00b7*/ 0x100a044aU,
+/*00b8*/ 0x000a044bU,
+/*00b9*/ 0x100a044bU,
+/*00ba*/ 0x000a044cU,
+/*00bb*/ 0x1004044cU,
+/*00bc*/ 0x1803044cU,
+/*00bd*/ 0x000a044dU,
+/*00be*/ 0x100a044dU,
+/*00bf*/ 0x0001044eU,
+/*00c0*/ 0x080a044eU,
+/*00c1*/ 0x1804044eU,
+/*00c2*/ 0x000b044fU,
+/*00c3*/ 0x100a044fU,
+/*00c4*/ 0xffffffffU,
+/*00c5*/ 0x00080450U,
+/*00c6*/ 0x08080450U,
+/*00c7*/ 0x10080450U,
+/*00c8*/ 0x18080450U,
+/*00c9*/ 0x00080451U,
+/*00ca*/ 0xffffffffU,
+/*00cb*/ 0x08080451U,
+/*00cc*/ 0x10010451U,
+/*00cd*/ 0x18080451U,
+/*00ce*/ 0x00080452U,
+/*00cf*/ 0x08020452U,
+/*00d0*/ 0x10020452U,
+/*00d1*/ 0x18040452U,
+/*00d2*/ 0x00040453U,
+/*00d3*/ 0xffffffffU,
+/*00d4*/ 0x08040453U,
+/*00d5*/ 0x100a0453U,
+/*00d6*/ 0x00060454U,
+/*00d7*/ 0x08080454U,
+/*00d8*/ 0xffffffffU,
+/*00d9*/ 0x10040454U,
+/*00da*/ 0x18040454U,
+/*00db*/ 0x00050455U,
+/*00dc*/ 0x08040455U,
+/*00dd*/ 0x10050455U,
+/*00de*/ 0x000a0456U,
+/*00df*/ 0x100a0456U,
+/*00e0*/ 0x00080457U,
+/*00e1*/ 0xffffffffU,
+/*00e2*/ 0x08040457U,
+/*00e3*/ 0xffffffffU,
+/*00e4*/ 0xffffffffU,
+/*00e5*/ 0x00050600U,
+/*00e6*/ 0x08050600U,
+/*00e7*/ 0x10050600U,
+/*00e8*/ 0x18050600U,
+/*00e9*/ 0x00050601U,
+/*00ea*/ 0x08050601U,
+/*00eb*/ 0x100b0601U,
+/*00ec*/ 0x00010602U,
+/*00ed*/ 0x08030602U,
+/*00ee*/ 0x00200603U,
+/*00ef*/ 0xffffffffU,
+/*00f0*/ 0x00030604U,
+/*00f1*/ 0x080a0604U,
+/*00f2*/ 0xffffffffU,
+/*00f3*/ 0xffffffffU,
+/*00f4*/ 0x18030604U,
+/*00f5*/ 0x00030605U,
+/*00f6*/ 0x08010605U,
+/*00f7*/ 0x10010605U,
+/*00f8*/ 0x18060605U,
+/*00f9*/ 0xffffffffU,
+/*00fa*/ 0xffffffffU,
+/*00fb*/ 0xffffffffU,
+/*00fc*/ 0x00020606U,
+/*00fd*/ 0x08030606U,
+/*00fe*/ 0x10010606U,
+/*00ff*/ 0x000f0607U,
+/*0100*/ 0x00200608U,
+/*0101*/ 0x00200609U,
+/*0102*/ 0x000b060aU,
+/*0103*/ 0x100b060aU,
+/*0104*/ 0x000b060bU,
+/*0105*/ 0xffffffffU,
+/*0106*/ 0xffffffffU,
+/*0107*/ 0x0018060cU,
+/*0108*/ 0x0018060dU,
+/*0109*/ 0x0018060eU,
+/*010a*/ 0x0018060fU,
+/*010b*/ 0x1804060fU,
+/*010c*/ 0x00050610U,
+/*010d*/ 0x08020610U,
+/*010e*/ 0x10040610U,
+/*010f*/ 0x18040610U,
+/*0110*/ 0x00010611U,
+/*0111*/ 0x08010611U,
+/*0112*/ 0x10010611U,
+/*0113*/ 0x18030611U,
+/*0114*/ 0x00200612U,
+/*0115*/ 0x00200613U,
+/*0116*/ 0x00010614U,
+/*0117*/ 0x08140614U,
+/*0118*/ 0x00140615U,
+/*0119*/ 0x00140616U,
+/*011a*/ 0x00140617U,
+/*011b*/ 0x00140618U,
+/*011c*/ 0x00140619U,
+/*011d*/ 0x0014061aU,
+/*011e*/ 0x0014061bU,
+/*011f*/ 0x0018061cU,
+/*0120*/ 0x000a061dU,
+/*0121*/ 0x1006061dU,
+/*0122*/ 0x1806061dU,
+/*0123*/ 0x0006061eU,
+/*0124*/ 0xffffffffU,
+/*0125*/ 0xffffffffU,
+/*0126*/ 0x0008061fU,
+/*0127*/ 0x080b061fU,
+/*0128*/ 0x000b0620U,
+/*0129*/ 0x100b0620U,
+/*012a*/ 0x000b0621U,
+/*012b*/ 0x100b0621U,
+/*012c*/ 0x000b0622U,
+/*012d*/ 0x10040622U,
+/*012e*/ 0x000a0623U,
+/*012f*/ 0x10060623U,
+/*0130*/ 0x18080623U,
+/*0131*/ 0xffffffffU,
+/*0132*/ 0x00040624U,
+/*0133*/ 0xffffffffU,
+/*0134*/ 0xffffffffU,
+/*0135*/ 0x00010700U,
+/*0136*/ 0x08020700U,
+/*0137*/ 0x10050700U,
+/*0138*/ 0x18050700U,
+/*0139*/ 0x00050701U,
+/*013a*/ 0x08050701U,
+/*013b*/ 0x100b0701U,
+/*013c*/ 0x00050702U,
+/*013d*/ 0x08010702U,
+/*013e*/ 0x10010702U,
+/*013f*/ 0xffffffffU,
+/*0140*/ 0x18010702U,
+/*0141*/ 0x00010703U,
+/*0142*/ 0x08040703U,
+/*0143*/ 0x100b0703U,
+/*0144*/ 0x000b0704U,
+/*0145*/ 0xffffffffU,
+/*0146*/ 0x10040704U,
+/*0147*/ 0x000b0705U,
+/*0148*/ 0x10040705U,
+/*0149*/ 0x18010705U,
+/*014a*/ 0x00010706U,
+/*014b*/ 0x08010706U,
+/*014c*/ 0x00200707U,
+/*014d*/ 0x00200708U,
+/*014e*/ 0x00080709U,
+/*014f*/ 0x080a0709U,
+/*0150*/ 0x18050709U,
+/*0151*/ 0x000a070aU,
+/*0152*/ 0x1003070aU,
+/*0153*/ 0x1803070aU,
+/*0154*/ 0x0001070bU,
+/*0155*/ 0x0802070bU,
+/*0156*/ 0x1001070bU,
+/*0157*/ 0x1801070bU,
+/*0158*/ 0x0001070cU,
+/*0159*/ 0x0802070cU,
+/*015a*/ 0xffffffffU,
+/*015b*/ 0xffffffffU,
+/*015c*/ 0xffffffffU,
+/*015d*/ 0xffffffffU,
+/*015e*/ 0xffffffffU,
+/*015f*/ 0xffffffffU,
+/*0160*/ 0xffffffffU,
+/*0161*/ 0xffffffffU,
+/*0162*/ 0xffffffffU,
+/*0163*/ 0xffffffffU,
+/*0164*/ 0xffffffffU,
+/*0165*/ 0xffffffffU,
+/*0166*/ 0x1001070cU,
+/*0167*/ 0x1801070cU,
+/*0168*/ 0x000d070dU,
+/*0169*/ 0xffffffffU,
+/*016a*/ 0xffffffffU,
+/*016b*/ 0x0005070eU,
+/*016c*/ 0x0001070fU,
+/*016d*/ 0x080e070fU,
+/*016e*/ 0x000e0710U,
+/*016f*/ 0x100e0710U,
+/*0170*/ 0x000e0711U,
+/*0171*/ 0x100e0711U,
+/*0172*/ 0x00040712U,
+/*0173*/ 0xffffffffU,
+/*0174*/ 0xffffffffU,
+/*0175*/ 0xffffffffU,
+/*0176*/ 0xffffffffU,
+/*0177*/ 0x080b0712U,
+/*0178*/ 0x000b0713U,
+/*0179*/ 0x100b0713U,
+/*017a*/ 0x000b0714U,
+/*017b*/ 0xffffffffU,
+/*017c*/ 0xffffffffU,
+/*017d*/ 0xffffffffU,
+/*017e*/ 0xffffffffU,
+/*017f*/ 0x000d0715U,
+/*0180*/ 0xffffffffU,
+/*0181*/ 0xffffffffU,
+/*0182*/ 0x10100715U,
+/*0183*/ 0x00080716U,
+/*0184*/ 0xffffffffU,
+/*0185*/ 0x08100716U,
+/*0186*/ 0x00100717U,
+/*0187*/ 0x10100717U,
+/*0188*/ 0x00100718U,
+/*0189*/ 0x10100718U,
+/*018a*/ 0x00030719U,
+/*018b*/ 0x08040719U,
+/*018c*/ 0x10010719U,
+/*018d*/ 0x18040719U,
+/*018e*/ 0xffffffffU,
+/*018f*/ 0xffffffffU,
+/*0190*/ 0x0001071aU,
+/*0191*/ 0x0812071aU,
+/*0192*/ 0x000a071bU,
+/*0193*/ 0x100c071bU,
+/*0194*/ 0x0012071cU,
+/*0195*/ 0x0014071dU,
+/*0196*/ 0x0012071eU,
+/*0197*/ 0x0011071fU,
+/*0198*/ 0x00110720U,
+/*0199*/ 0x00120721U,
+/*019a*/ 0x00120722U,
+/*019b*/ 0x00120723U,
+/*019c*/ 0x00120724U,
+/*019d*/ 0x00120725U,
+/*019e*/ 0x00120726U,
+/*019f*/ 0x00120727U,
+/*01a0*/ 0x00120728U,
+/*01a1*/ 0xffffffffU,
+/*01a2*/ 0xffffffffU,
+/*01a3*/ 0x00190729U,
+/*01a4*/ 0x0019072aU,
+/*01a5*/ 0x0020072bU,
+/*01a6*/ 0x0017072cU,
+/*01a7*/ 0x1808072cU,
+/*01a8*/ 0x0001072dU,
+/*01a9*/ 0x0801072dU,
+/*01aa*/ 0x0020072eU,
+/*01ab*/ 0x0008072fU,
+/*01ac*/ 0xffffffffU,
+/*01ad*/ 0x0803072fU,
+/*01ae*/ 0x00180730U,
+/*01af*/ 0x00180731U,
+/*01b0*/ 0xffffffffU,
+/*01b1*/ 0xffffffffU,
+/*01b2*/ 0xffffffffU,
+/*01b3*/ 0xffffffffU,
+/*01b4*/ 0xffffffffU,
+/*01b5*/ 0xffffffffU,
+/*01b6*/ 0xffffffffU,
+/*01b7*/ 0xffffffffU,
+/*01b8*/ 0xffffffffU,
+/*01b9*/ 0xffffffffU,
+/*01ba*/ 0xffffffffU,
+/*01bb*/ 0xffffffffU,
+/*01bc*/ 0xffffffffU,
+/*01bd*/ 0xffffffffU,
+/*01be*/ 0xffffffffU,
+/*01bf*/ 0x00100732U,
+/*01c0*/ 0x10010732U,
+/*01c1*/ 0x18010732U,
+/*01c2*/ 0x00050733U,
+/*01c3*/ 0x00200734U,
+/*01c4*/ 0x00090735U,
+/*01c5*/ 0xffffffffU,
+/*01c6*/ 0xffffffffU,
+/*01c7*/ 0x00200736U,
+/*01c8*/ 0x00040737U,
+/*01c9*/ 0x08100737U,
+/*01ca*/ 0x18060737U,
+/*01cb*/ 0x00100738U,
+/*01cc*/ 0xffffffffU,
+/*01cd*/ 0xffffffffU,
+/*01ce*/ 0xffffffffU,
+/*01cf*/ 0xffffffffU,
+/*01d0*/ 0xffffffffU,
+/*01d1*/ 0xffffffffU,
+/*01d2*/ 0xffffffffU,
+/*01d3*/ 0xffffffffU,
+/*01d4*/ 0x00200739U,
+/*01d5*/ 0x000b073aU,
+/*01d6*/ 0xffffffffU,
+/*01d7*/ 0xffffffffU,
+/*01d8*/ 0xffffffffU,
+/*01d9*/ 0xffffffffU,
+/*01da*/ 0xffffffffU,
+/*01db*/ 0xffffffffU,
+/*01dc*/ 0xffffffffU,
+/*01dd*/ 0xffffffffU,
+/*01de*/ 0x00010200U,
+/*01df*/ 0x08040200U,
+/*01e0*/ 0x10100200U,
+/*01e1*/ 0x00010201U,
+/*01e2*/ 0x08010201U,
+/*01e3*/ 0xffffffffU,
+/*01e4*/ 0xffffffffU,
+/*01e5*/ 0x10100201U,
+/*01e6*/ 0xffffffffU,
+/*01e7*/ 0xffffffffU,
+/*01e8*/ 0xffffffffU,
+/*01e9*/ 0xffffffffU,
+/*01ea*/ 0xffffffffU,
+/*01eb*/ 0xffffffffU,
+/*01ec*/ 0xffffffffU,
+/*01ed*/ 0xffffffffU,
+/*01ee*/ 0xffffffffU,
+/*01ef*/ 0x00200202U,
+/*01f0*/ 0x00100203U,
+/*01f1*/ 0x00200204U,
+/*01f2*/ 0x00100205U,
+/*01f3*/ 0x00200206U,
+/*01f4*/ 0x00100207U,
+/*01f5*/ 0x10100207U,
+/*01f6*/ 0x00200208U,
+/*01f7*/ 0x00200209U,
+/*01f8*/ 0x0020020aU,
+/*01f9*/ 0x0020020bU,
+/*01fa*/ 0x0010020cU,
+/*01fb*/ 0x0020020dU,
+/*01fc*/ 0x0020020eU,
+/*01fd*/ 0x0020020fU,
+/*01fe*/ 0x00200210U,
+/*01ff*/ 0x00100211U,
+/*0200*/ 0x00200212U,
+/*0201*/ 0x00200213U,
+/*0202*/ 0x00200214U,
+/*0203*/ 0x00200215U,
+/*0204*/ 0x00090216U,
+/*0205*/ 0x10010216U,
+/*0206*/ 0x00200217U,
+/*0207*/ 0x00050218U,
+/*0208*/ 0x08010218U,
+/*0209*/ 0x10080218U,
+/*020a*/ 0x18080218U,
+/*020b*/ 0x001c0219U,
+/*020c*/ 0x001c021aU,
+/*020d*/ 0x001c021bU,
+/*020e*/ 0x001c021cU,
+/*020f*/ 0x001c021dU,
+/*0210*/ 0x001c021eU,
+/*0211*/ 0x001c021fU,
+/*0212*/ 0x001c0220U,
+/*0213*/ 0x001c0221U,
+/*0214*/ 0x001c0222U,
+/*0215*/ 0x001c0223U,
+/*0216*/ 0x001c0224U,
+/*0217*/ 0x001c0225U,
+/*0218*/ 0x001c0226U,
+/*0219*/ 0x001c0227U,
+/*021a*/ 0x001c0228U,
+/*021b*/ 0x00010229U,
+/*021c*/ 0x08010229U,
+/*021d*/ 0x10010229U,
+/*021e*/ 0x18040229U,
+/*021f*/ 0x0008022aU,
+/*0220*/ 0x0808022aU,
+/*0221*/ 0x1008022aU,
+/*0222*/ 0x1804022aU,
+/*0223*/ 0x0006022bU,
+/*0224*/ 0xffffffffU,
+/*0225*/ 0x0807022bU,
+/*0226*/ 0x1006022bU,
+/*0227*/ 0xffffffffU,
+/*0228*/ 0x1807022bU,
+/*0229*/ 0x0006022cU,
+/*022a*/ 0xffffffffU,
+/*022b*/ 0x0807022cU,
+/*022c*/ 0x1002022cU,
+/*022d*/ 0x1801022cU,
+/*022e*/ 0xffffffffU,
+/*022f*/ 0x000a022dU,
+/*0230*/ 0x1010022dU,
+/*0231*/ 0x000a022eU,
+/*0232*/ 0x1010022eU,
+/*0233*/ 0x000a022fU,
+/*0234*/ 0x1010022fU,
+/*0235*/ 0xffffffffU,
+/*0236*/ 0x00100230U,
+/*0237*/ 0xffffffffU,
+/*0238*/ 0xffffffffU,
+/*0239*/ 0x10010230U,
+/*023a*/ 0x18010230U,
+/*023b*/ 0x00010231U,
+/*023c*/ 0x08010231U,
+/*023d*/ 0x10010231U,
+/*023e*/ 0x18010231U,
+/*023f*/ 0x00020232U,
+/*0240*/ 0x08020232U,
+/*0241*/ 0x10020232U,
+/*0242*/ 0x18020232U,
+/*0243*/ 0x00020233U,
+/*0244*/ 0x08030233U,
+/*0245*/ 0x10010233U,
+/*0246*/ 0x18010233U,
+/*0247*/ 0x00010234U,
+/*0248*/ 0x08010234U,
+/*0249*/ 0xffffffffU,
+/*024a*/ 0x10020234U,
+/*024b*/ 0x18010234U,
+/*024c*/ 0x00010235U,
+/*024d*/ 0xffffffffU,
+/*024e*/ 0x08020235U,
+/*024f*/ 0x10010235U,
+/*0250*/ 0x18010235U,
+/*0251*/ 0xffffffffU,
+/*0252*/ 0x00020236U,
+/*0253*/ 0x08010236U,
+/*0254*/ 0x10010236U,
+/*0255*/ 0xffffffffU,
+/*0256*/ 0x18020236U,
+/*0257*/ 0x00070237U,
+/*0258*/ 0x08010237U,
+/*0259*/ 0x10010237U,
+/*025a*/ 0x18010237U,
+/*025b*/ 0x00010238U,
+/*025c*/ 0x08010238U,
+/*025d*/ 0x10010238U,
+/*025e*/ 0xffffffffU,
+/*025f*/ 0x18010238U,
+/*0260*/ 0x00040239U,
+/*0261*/ 0x08040239U,
+/*0262*/ 0x10040239U,
+/*0263*/ 0x18010239U,
+/*0264*/ 0x0002023aU,
+/*0265*/ 0x0806023aU,
+/*0266*/ 0x1006023aU,
+/*0267*/ 0xffffffffU,
+/*0268*/ 0xffffffffU,
+/*0269*/ 0xffffffffU,
+/*026a*/ 0x1802023aU,
+/*026b*/ 0x0010023bU,
+/*026c*/ 0x1001023bU,
+/*026d*/ 0x1801023bU,
+/*026e*/ 0xffffffffU,
+/*026f*/ 0x0004023cU,
+/*0270*/ 0x0801023cU,
+/*0271*/ 0x1004023cU,
+/*0272*/ 0x1802023cU,
+/*0273*/ 0x0008023dU,
+/*0274*/ 0xffffffffU,
+/*0275*/ 0xffffffffU,
+/*0276*/ 0xffffffffU,
+/*0277*/ 0x080a023dU,
+/*0278*/ 0x0020023eU,
+/*0279*/ 0x0020023fU,
+/*027a*/ 0x00050240U,
+/*027b*/ 0x08010240U,
+/*027c*/ 0x10050240U,
+/*027d*/ 0x18080240U,
+/*027e*/ 0x00010241U,
+/*027f*/ 0x08080241U,
+/*0280*/ 0x10010241U,
+/*0281*/ 0x18080241U,
+/*0282*/ 0x00010242U,
+/*0283*/ 0x08040242U,
+/*0284*/ 0x10040242U,
+/*0285*/ 0x18040242U,
+/*0286*/ 0x00040243U,
+/*0287*/ 0x08040243U,
+/*0288*/ 0x10040243U,
+/*0289*/ 0x18040243U,
+/*028a*/ 0x00040244U,
+/*028b*/ 0x08040244U,
+/*028c*/ 0x10040244U,
+/*028d*/ 0x18010244U,
+/*028e*/ 0x00040245U,
+/*028f*/ 0x08040245U,
+/*0290*/ 0x10040245U,
+/*0291*/ 0x18040245U,
+/*0292*/ 0x00040246U,
+/*0293*/ 0x08040246U,
+/*0294*/ 0x10060246U,
+/*0295*/ 0x18060246U,
+/*0296*/ 0x00060247U,
+/*0297*/ 0x08060247U,
+/*0298*/ 0x10060247U,
+/*0299*/ 0x18060247U,
+/*029a*/ 0xffffffffU,
+/*029b*/ 0x00010248U,
+/*029c*/ 0x08010248U,
+/*029d*/ 0x10020248U,
+/*029e*/ 0xffffffffU,
+/*029f*/ 0xffffffffU,
+/*02a0*/ 0xffffffffU,
+/*02a1*/ 0xffffffffU,
+/*02a2*/ 0xffffffffU,
+/*02a3*/ 0xffffffffU,
+/*02a4*/ 0xffffffffU,
+/*02a5*/ 0xffffffffU,
+/*02a6*/ 0x18040248U,
+/*02a7*/ 0x00040249U,
+/*02a8*/ 0x08010249U,
+/*02a9*/ 0x10010249U,
+/*02aa*/ 0xffffffffU,
+/*02ab*/ 0x18010249U,
+/*02ac*/ 0x0001024aU,
+/*02ad*/ 0xffffffffU,
+/*02ae*/ 0x0801024aU,
+/*02af*/ 0x1001024aU,
+/*02b0*/ 0x1801024aU,
+/*02b1*/ 0x0004024bU,
+/*02b2*/ 0x0804024bU,
+/*02b3*/ 0x100a024bU,
+/*02b4*/ 0x0020024cU,
+/*02b5*/ 0x0004024dU,
+/*02b6*/ 0x0808024dU,
+/*02b7*/ 0xffffffffU,
+/*02b8*/ 0xffffffffU,
+/*02b9*/ 0xffffffffU,
+/*02ba*/ 0xffffffffU,
+/*02bb*/ 0xffffffffU,
+/*02bc*/ 0xffffffffU,
+/*02bd*/ 0x1002024dU,
+/*02be*/ 0x1802024dU,
+/*02bf*/ 0x0020024eU,
+/*02c0*/ 0x0002024fU,
+/*02c1*/ 0x0810024fU,
+/*02c2*/ 0x00100250U,
+/*02c3*/ 0x10040250U,
+/*02c4*/ 0x18040250U,
+/*02c5*/ 0x00050251U,
+/*02c6*/ 0x08050251U,
+/*02c7*/ 0xffffffffU,
+/*02c8*/ 0xffffffffU,
+/*02c9*/ 0xffffffffU,
+/*02ca*/ 0xffffffffU,
+/*02cb*/ 0x10010251U,
+/*02cc*/ 0x18010251U,
+/*02cd*/ 0x00070252U,
+/*02ce*/ 0x08070252U,
+/*02cf*/ 0x10070252U,
+/*02d0*/ 0x18070252U,
+/*02d1*/ 0x00070253U,
+/*02d2*/ 0x08070253U,
+/*02d3*/ 0x10070253U,
+/*02d4*/ 0x18070253U,
+/*02d5*/ 0x00070254U,
+/*02d6*/ 0x08070254U,
+/*02d7*/ 0x10070254U,
+/*02d8*/ 0xffffffffU,
+/*02d9*/ 0xffffffffU,
+/*02da*/ 0xffffffffU,
+/*02db*/ 0xffffffffU,
+/*02dc*/ 0xffffffffU,
+/*02dd*/ 0xffffffffU,
+/*02de*/ 0x18030254U,
+/*02df*/ 0x00010255U,
+/*02e0*/ 0x08020255U,
+/*02e1*/ 0x10010255U,
+/*02e2*/ 0x18040255U,
+/*02e3*/ 0x00020256U,
+/*02e4*/ 0x08010256U,
+/*02e5*/ 0x10010256U,
+/*02e6*/ 0xffffffffU,
+/*02e7*/ 0x18010256U,
+/*02e8*/ 0x00040257U,
+/*02e9*/ 0x08080257U,
+/*02ea*/ 0x100a0257U,
+/*02eb*/ 0x000a0258U,
+/*02ec*/ 0x100a0258U,
+/*02ed*/ 0x000a0259U,
+/*02ee*/ 0x100a0259U,
+/*02ef*/ 0x000a025aU,
+/*02f0*/ 0x0020025bU,
+/*02f1*/ 0x0020025cU,
+/*02f2*/ 0x0001025dU,
+/*02f3*/ 0xffffffffU,
+/*02f4*/ 0xffffffffU,
+/*02f5*/ 0xffffffffU,
+/*02f6*/ 0x0802025dU,
+/*02f7*/ 0x1002025dU,
+/*02f8*/ 0x0010025eU,
+/*02f9*/ 0x1005025eU,
+/*02fa*/ 0x1806025eU,
+/*02fb*/ 0x0005025fU,
+/*02fc*/ 0x0805025fU,
+/*02fd*/ 0x100e025fU,
+/*02fe*/ 0x00050260U,
+/*02ff*/ 0x080e0260U,
+/*0300*/ 0x18050260U,
+/*0301*/ 0x000e0261U,
+/*0302*/ 0x10050261U,
+/*0303*/ 0x18010261U,
+/*0304*/ 0x00050262U,
+/*0305*/ 0x08050262U,
+/*0306*/ 0x100a0262U,
+/*0307*/ 0x000a0263U,
+/*0308*/ 0x10050263U,
+/*0309*/ 0x18050263U,
+/*030a*/ 0x000a0264U,
+/*030b*/ 0x100a0264U,
+/*030c*/ 0x00050265U,
+/*030d*/ 0x08050265U,
+/*030e*/ 0x100a0265U,
+/*030f*/ 0x000a0266U,
+/*0310*/ 0xffffffffU,
+/*0311*/ 0xffffffffU,
+/*0312*/ 0xffffffffU,
+/*0313*/ 0xffffffffU,
+/*0314*/ 0xffffffffU,
+/*0315*/ 0xffffffffU,
+/*0316*/ 0x10070266U,
+/*0317*/ 0x18070266U,
+/*0318*/ 0x00040267U,
+/*0319*/ 0x08040267U,
+/*031a*/ 0xffffffffU,
+/*031b*/ 0xffffffffU,
+/*031c*/ 0xffffffffU,
+/*031d*/ 0x10040267U,
+/*031e*/ 0x18080267U,
+/*031f*/ 0x00080268U,
+/*0320*/ 0x08040268U,
+/*0321*/ 0xffffffffU,
+/*0322*/ 0xffffffffU,
+/*0323*/ 0xffffffffU,
+/*0324*/ 0x10040268U,
+/*0325*/ 0xffffffffU,
+/*0326*/ 0xffffffffU,
+/*0327*/ 0xffffffffU,
+/*0328*/ 0x18040268U,
+/*0329*/ 0xffffffffU,
+/*032a*/ 0xffffffffU,
+/*032b*/ 0xffffffffU,
+/*032c*/ 0x00040269U,
+/*032d*/ 0x08050269U,
+/*032e*/ 0x10070269U,
+/*032f*/ 0x18080269U,
+/*0330*/ 0x0010026aU,
+/*0331*/ 0x1008026aU,
+/*0332*/ 0x0010026bU,
+/*0333*/ 0x1008026bU,
+/*0334*/ 0x0010026cU,
+/*0335*/ 0x1008026cU,
+/*0336*/ 0x1808026cU,
+/*0337*/ 0x0001026dU,
+/*0338*/ 0x0801026dU,
+/*0339*/ 0x1006026dU,
+/*033a*/ 0x1806026dU,
+/*033b*/ 0x0006026eU,
+/*033c*/ 0xffffffffU,
+/*033d*/ 0x0801026eU,
+/*033e*/ 0x1003026eU,
+/*033f*/ 0xffffffffU,
+/*0340*/ 0xffffffffU,
+/*0341*/ 0xffffffffU,
+/*0342*/ 0x000a026fU,
+/*0343*/ 0x100a026fU,
+/*0344*/ 0x00040270U,
+/*0345*/ 0x08010270U,
+/*0346*/ 0x10040270U,
+/*0347*/ 0xffffffffU,
+/*0348*/ 0xffffffffU,
+/*0349*/ 0xffffffffU,
+/*034a*/ 0xffffffffU,
+/*034b*/ 0xffffffffU,
+/*034c*/ 0xffffffffU,
+/*034d*/ 0x18070270U,
+/*034e*/ 0x00070271U,
+/*034f*/ 0x08050271U,
+/*0350*/ 0x10050271U,
+/*0351*/ 0xffffffffU,
+/*0352*/ 0xffffffffU,
+/*0353*/ 0xffffffffU,
+/*0354*/ 0x18040271U,
+/*0355*/ 0x00010272U,
+/*0356*/ 0x08010272U,
+/*0357*/ 0x10020272U,
+/*0358*/ 0x18080272U,
+/*0359*/ 0x00200273U,
+/*035a*/ 0x00200274U,
+/*035b*/ 0x00100275U,
+/*035c*/ 0xffffffffU,
+/*035d*/ 0xffffffffU,
+/*035e*/ 0xffffffffU,
+/*035f*/ 0x10020275U,
+/*0360*/ 0x18010275U,
+/*0361*/ 0xffffffffU,
+/*0362*/ 0x00020276U,
+/*0363*/ 0x08080276U,
+/*0364*/ 0x10080276U,
+/*0365*/ 0x18080276U,
+/*0366*/ 0x00080277U,
+/*0367*/ 0x08080277U,
+/*0368*/ 0x10080277U,
+/*0369*/ 0xffffffffU,
+/*036a*/ 0x18080277U,
+/*036b*/ 0x00080278U,
+/*036c*/ 0x08080278U,
+/*036d*/ 0x10080278U,
+/*036e*/ 0x18080278U,
+/*036f*/ 0x00080279U,
+/*0370*/ 0xffffffffU,
+/*0371*/ 0x08080279U,
+/*0372*/ 0x10080279U,
+/*0373*/ 0x18080279U,
+/*0374*/ 0x0008027aU,
+/*0375*/ 0x0808027aU,
+/*0376*/ 0x1008027aU,
+/*0377*/ 0xffffffffU,
+/*0378*/ 0x1808027aU,
+/*0379*/ 0x0008027bU,
+/*037a*/ 0x0808027bU,
+/*037b*/ 0x1008027bU,
+/*037c*/ 0x1808027bU,
+/*037d*/ 0x0008027cU,
+/*037e*/ 0x0808027cU,
+/*037f*/ 0xffffffffU,
+/*0380*/ 0x1008027cU,
+/*0381*/ 0x1808027cU,
+/*0382*/ 0x0008027dU,
+/*0383*/ 0x0808027dU,
+/*0384*/ 0x1008027dU,
+/*0385*/ 0x1808027dU,
+/*0386*/ 0xffffffffU,
+/*0387*/ 0x0008027eU,
+/*0388*/ 0x0808027eU,
+/*0389*/ 0x1008027eU,
+/*038a*/ 0x1808027eU,
+/*038b*/ 0x0008027fU,
+/*038c*/ 0x0808027fU,
+/*038d*/ 0xffffffffU,
+/*038e*/ 0x1008027fU,
+/*038f*/ 0x1808027fU,
+/*0390*/ 0x00080280U,
+/*0391*/ 0x08080280U,
+/*0392*/ 0x10080280U,
+/*0393*/ 0x18080280U,
+/*0394*/ 0x00080281U,
+/*0395*/ 0xffffffffU,
+/*0396*/ 0x08080281U,
+/*0397*/ 0x10080281U,
+/*0398*/ 0x18080281U,
+/*0399*/ 0x00080282U,
+/*039a*/ 0x08080282U,
+/*039b*/ 0x10080282U,
+/*039c*/ 0xffffffffU,
+/*039d*/ 0x18080282U,
+/*039e*/ 0x00080283U,
+/*039f*/ 0x08080283U,
+/*03a0*/ 0x10080283U,
+/*03a1*/ 0x18080283U,
+/*03a2*/ 0x00080284U,
+/*03a3*/ 0xffffffffU,
+/*03a4*/ 0x08080284U,
+/*03a5*/ 0x10080284U,
+/*03a6*/ 0x18080284U,
+/*03a7*/ 0x00080285U,
+/*03a8*/ 0x08080285U,
+/*03a9*/ 0x10080285U,
+/*03aa*/ 0x18080285U,
+/*03ab*/ 0xffffffffU,
+/*03ac*/ 0x00080286U,
+/*03ad*/ 0x08080286U,
+/*03ae*/ 0x10080286U,
+/*03af*/ 0x18080286U,
+/*03b0*/ 0x00080287U,
+/*03b1*/ 0x08080287U,
+/*03b2*/ 0xffffffffU,
+/*03b3*/ 0x10080287U,
+/*03b4*/ 0x18080287U,
+/*03b5*/ 0x00080288U,
+/*03b6*/ 0x08080288U,
+/*03b7*/ 0x10080288U,
+/*03b8*/ 0x18080288U,
+/*03b9*/ 0xffffffffU,
+/*03ba*/ 0x00080289U,
+/*03bb*/ 0x08020289U,
+/*03bc*/ 0x10030289U,
+/*03bd*/ 0x000a028aU,
+/*03be*/ 0x100a028aU,
+/*03bf*/ 0x000a028bU,
+/*03c0*/ 0x1005028bU,
+/*03c1*/ 0x1804028bU,
+/*03c2*/ 0x0008028cU,
+/*03c3*/ 0x0808028cU,
+/*03c4*/ 0x1006028cU,
+/*03c5*/ 0x1806028cU,
+/*03c6*/ 0x0011028dU,
+/*03c7*/ 0x1808028dU,
+/*03c8*/ 0x0004028eU,
+/*03c9*/ 0x0806028eU,
+/*03ca*/ 0xffffffffU,
+/*03cb*/ 0x1006028eU,
+/*03cc*/ 0x1808028eU,
+/*03cd*/ 0xffffffffU,
+/*03ce*/ 0x0004028fU,
+/*03cf*/ 0x0808028fU,
+/*03d0*/ 0x1008028fU,
+/*03d1*/ 0x1806028fU,
+/*03d2*/ 0x00060290U,
+/*03d3*/ 0x08110290U,
+/*03d4*/ 0x00080291U,
+/*03d5*/ 0x08040291U,
+/*03d6*/ 0x10060291U,
+/*03d7*/ 0xffffffffU,
+/*03d8*/ 0x18060291U,
+/*03d9*/ 0x00080292U,
+/*03da*/ 0xffffffffU,
+/*03db*/ 0x08040292U,
+/*03dc*/ 0x10080292U,
+/*03dd*/ 0x18080292U,
+/*03de*/ 0x00060293U,
+/*03df*/ 0x08060293U,
+/*03e0*/ 0x00110294U,
+/*03e1*/ 0x18080294U,
+/*03e2*/ 0x00040295U,
+/*03e3*/ 0x08060295U,
+/*03e4*/ 0xffffffffU,
+/*03e5*/ 0x10060295U,
+/*03e6*/ 0x18080295U,
+/*03e7*/ 0xffffffffU,
+/*03e8*/ 0x00040296U,
+/*03e9*/ 0x08040296U,
+/*03ea*/ 0x10040296U,
+/*03eb*/ 0x18040296U,
+/*03ec*/ 0x00040297U,
+/*03ed*/ 0x08040297U,
+/*03ee*/ 0x10040297U,
+/*03ef*/ 0x18040297U,
+/*03f0*/ 0x00040298U,
+/*03f1*/ 0x08040298U,
+/*03f2*/ 0x10040298U,
+/*03f3*/ 0x18040298U,
+/*03f4*/ 0x00040299U,
+/*03f5*/ 0x08040299U,
+/*03f6*/ 0x10040299U,
+/*03f7*/ 0x18040299U,
+/*03f8*/ 0x0004029aU,
+/*03f9*/ 0x0804029aU,
+/*03fa*/ 0x1004029aU,
+/*03fb*/ 0x1804029aU,
+/*03fc*/ 0x0011029bU,
+/*03fd*/ 0x0010029cU,
+/*03fe*/ 0x0011029dU,
+/*03ff*/ 0x0020029eU,
+/*0400*/ 0x0020029fU,
+/*0401*/ 0x002002a0U,
+/*0402*/ 0x002002a1U,
+/*0403*/ 0x002002a2U,
+/*0404*/ 0x002002a3U,
+/*0405*/ 0x002002a4U,
+/*0406*/ 0x002002a5U,
+/*0407*/ 0x002002a6U,
+/*0408*/ 0x000202a7U,
+/*0409*/ 0x080502a7U,
+/*040a*/ 0x100502a7U,
+/*040b*/ 0xffffffffU,
+/*040c*/ 0xffffffffU,
+/*040d*/ 0xffffffffU,
+/*040e*/ 0xffffffffU,
+/*040f*/ 0xffffffffU,
+/*0410*/ 0xffffffffU,
+/*0411*/ 0xffffffffU,
+/*0412*/ 0xffffffffU,
+/*0413*/ 0xffffffffU,
+/*0414*/ 0xffffffffU,
+/*0415*/ 0xffffffffU,
+/*0416*/ 0xffffffffU,
+/*0417*/ 0xffffffffU,
+/*0418*/ 0xffffffffU,
+/*0419*/ 0xffffffffU,
+/*041a*/ 0xffffffffU,
+/*041b*/ 0xffffffffU,
+/*041c*/ 0xffffffffU,
+/*041d*/ 0xffffffffU,
+/*041e*/ 0xffffffffU,
+/*041f*/ 0xffffffffU,
+/*0420*/ 0xffffffffU,
+/*0421*/ 0xffffffffU,
+/*0422*/ 0xffffffffU,
+/*0423*/ 0xffffffffU,
+/*0424*/ 0xffffffffU,
+/*0425*/ 0xffffffffU,
+/*0426*/ 0xffffffffU,
+/*0427*/ 0x180102a7U,
+/*0428*/ 0x000402a8U,
+/*0429*/ 0x081002a8U,
+/*042a*/ 0x002002a9U,
+/*042b*/ 0x001002aaU,
+/*042c*/ 0x002002abU,
+/*042d*/ 0x001002acU,
+/*042e*/ 0x002002adU,
+/*042f*/ 0x000702aeU,
+/*0430*/ 0x080102aeU,
+/*0431*/ 0x100202aeU,
+/*0432*/ 0x180602aeU,
+/*0433*/ 0x000102afU,
+/*0434*/ 0x080102afU,
+/*0435*/ 0x002002b0U,
+/*0436*/ 0x000202b1U,
+/*0437*/ 0x002002b2U,
+/*0438*/ 0x002002b3U,
+/*0439*/ 0xffffffffU,
+/*043a*/ 0xffffffffU,
+/*043b*/ 0xffffffffU,
+/*043c*/ 0xffffffffU,
+/*043d*/ 0xffffffffU,
+/*043e*/ 0xffffffffU,
+/*043f*/ 0xffffffffU,
+/*0440*/ 0xffffffffU,
+/*0441*/ 0xffffffffU,
+/*0442*/ 0xffffffffU,
+/*0443*/ 0xffffffffU,
+/*0444*/ 0xffffffffU,
+/*0445*/ 0xffffffffU,
+/*0446*/ 0xffffffffU,
+/*0447*/ 0xffffffffU,
+/*0448*/ 0xffffffffU,
+/*0449*/ 0xffffffffU,
+/*044a*/ 0xffffffffU,
+/*044b*/ 0xffffffffU,
+/*044c*/ 0xffffffffU,
+/*044d*/ 0xffffffffU,
+/*044e*/ 0xffffffffU,
+/*044f*/ 0xffffffffU,
+/*0450*/ 0xffffffffU,
+/*0451*/ 0xffffffffU,
+/*0452*/ 0xffffffffU,
+/*0453*/ 0xffffffffU,
+/*0454*/ 0xffffffffU,
+/*0455*/ 0xffffffffU,
+/*0456*/ 0xffffffffU,
+/*0457*/ 0xffffffffU,
+/*0458*/ 0xffffffffU,
+/*0459*/ 0xffffffffU,
+/*045a*/ 0xffffffffU,
+/*045b*/ 0xffffffffU,
+/*045c*/ 0xffffffffU,
+/*045d*/ 0xffffffffU,
+/*045e*/ 0xffffffffU,
+/*045f*/ 0x000402b4U,
+/*0460*/ 0xffffffffU,
+/*0461*/ 0xffffffffU,
+/*0462*/ 0xffffffffU,
+/*0463*/ 0xffffffffU,
+/*0464*/ 0xffffffffU,
+/*0465*/ 0xffffffffU,
+/*0466*/ 0xffffffffU,
+/*0467*/ 0xffffffffU,
+/*0468*/ 0xffffffffU,
+/*0469*/ 0xffffffffU,
+/*046a*/ 0xffffffffU,
+/*046b*/ 0xffffffffU,
+/*046c*/ 0xffffffffU,
+/*046d*/ 0xffffffffU,
+/*046e*/ 0xffffffffU,
+/*046f*/ 0xffffffffU,
+/*0470*/ 0xffffffffU,
+/*0471*/ 0xffffffffU,
+/*0472*/ 0xffffffffU,
+/*0473*/ 0xffffffffU,
+/*0474*/ 0xffffffffU,
+/*0475*/ 0xffffffffU,
+/*0476*/ 0xffffffffU,
+/*0477*/ 0xffffffffU,
+/*0478*/ 0xffffffffU,
+/*0479*/ 0xffffffffU,
+/*047a*/ 0xffffffffU,
+/*047b*/ 0xffffffffU,
+/*047c*/ 0xffffffffU,
+/*047d*/ 0xffffffffU,
+/*047e*/ 0xffffffffU,
+/*047f*/ 0xffffffffU,
+/*0480*/ 0xffffffffU,
+/*0481*/ 0xffffffffU,
+/*0482*/ 0xffffffffU,
+/*0483*/ 0xffffffffU,
+/*0484*/ 0xffffffffU,
+/*0485*/ 0xffffffffU,
+/*0486*/ 0xffffffffU,
+/*0487*/ 0xffffffffU,
+/*0488*/ 0xffffffffU,
+/*0489*/ 0xffffffffU,
+/*048a*/ 0xffffffffU,
+/*048b*/ 0xffffffffU,
+/*048c*/ 0xffffffffU,
+/*048d*/ 0xffffffffU,
+/*048e*/ 0xffffffffU,
+/*048f*/ 0xffffffffU,
+/*0490*/ 0xffffffffU,
+/*0491*/ 0xffffffffU,
+/*0492*/ 0xffffffffU,
+/*0493*/ 0xffffffffU,
+/*0494*/ 0xffffffffU,
+	 },
+	{
+/*0000*/ 0x00200800U,
+/*0001*/ 0x00040801U,
+/*0002*/ 0x080b0801U,
+/*0003*/ 0xffffffffU,
+/*0004*/ 0xffffffffU,
+/*0005*/ 0x18010801U,
+/*0006*/ 0x00050802U,
+/*0007*/ 0x08050802U,
+/*0008*/ 0x10050802U,
+/*0009*/ 0x18050802U,
+/*000a*/ 0x00050803U,
+/*000b*/ 0x08050803U,
+/*000c*/ 0x10050803U,
+/*000d*/ 0x18050803U,
+/*000e*/ 0x00050804U,
+/*000f*/ 0x08040804U,
+/*0010*/ 0x10030804U,
+/*0011*/ 0x00180805U,
+/*0012*/ 0x18030805U,
+/*0013*/ 0x00180806U,
+/*0014*/ 0x18020806U,
+/*0015*/ 0x00010807U,
+/*0016*/ 0x08020807U,
+/*0017*/ 0x10010807U,
+/*0018*/ 0x18010807U,
+/*0019*/ 0x00020808U,
+/*001a*/ 0x08040808U,
+/*001b*/ 0x10040808U,
+/*001c*/ 0x18040808U,
+/*001d*/ 0x000a0809U,
+/*001e*/ 0x10040809U,
+/*001f*/ 0xffffffffU,
+/*0020*/ 0xffffffffU,
+/*0021*/ 0x18070809U,
+/*0022*/ 0xffffffffU,
+/*0023*/ 0xffffffffU,
+/*0024*/ 0xffffffffU,
+/*0025*/ 0xffffffffU,
+/*0026*/ 0xffffffffU,
+/*0027*/ 0xffffffffU,
+/*0028*/ 0x000a080aU,
+/*0029*/ 0x1005080aU,
+/*002a*/ 0x1801080aU,
+/*002b*/ 0x0001080bU,
+/*002c*/ 0x0802080bU,
+/*002d*/ 0x1009080bU,
+/*002e*/ 0x0009080cU,
+/*002f*/ 0x1002080cU,
+/*0030*/ 0x0020080dU,
+/*0031*/ 0xffffffffU,
+/*0032*/ 0x0001080eU,
+/*0033*/ 0xffffffffU,
+/*0034*/ 0xffffffffU,
+/*0035*/ 0xffffffffU,
+/*0036*/ 0xffffffffU,
+/*0037*/ 0x0020080fU,
+/*0038*/ 0x00200810U,
+/*0039*/ 0x00200811U,
+/*003a*/ 0x00200812U,
+/*003b*/ 0x00030813U,
+/*003c*/ 0x08010813U,
+/*003d*/ 0x10030813U,
+/*003e*/ 0x18030813U,
+/*003f*/ 0x00040814U,
+/*0040*/ 0x08040814U,
+/*0041*/ 0x10040814U,
+/*0042*/ 0x18040814U,
+/*0043*/ 0x00010815U,
+/*0044*/ 0x08010815U,
+/*0045*/ 0x10060815U,
+/*0046*/ 0x18040815U,
+/*0047*/ 0xffffffffU,
+/*0048*/ 0x00060816U,
+/*0049*/ 0x08040816U,
+/*004a*/ 0x10060816U,
+/*004b*/ 0x18040816U,
+/*004c*/ 0x00020817U,
+/*004d*/ 0x08050817U,
+/*004e*/ 0x10080817U,
+/*004f*/ 0x00200818U,
+/*0050*/ 0x00060819U,
+/*0051*/ 0x08030819U,
+/*0052*/ 0x100b0819U,
+/*0053*/ 0x0004081aU,
+/*0054*/ 0x0804081aU,
+/*0055*/ 0x1004081aU,
+/*0056*/ 0xffffffffU,
+/*0057*/ 0x1801081aU,
+/*0058*/ 0x0009081bU,
+/*0059*/ 0x0020081cU,
+/*005a*/ 0x0020081dU,
+/*005b*/ 0x0020081eU,
+/*005c*/ 0x0020081fU,
+/*005d*/ 0x00100820U,
+/*005e*/ 0xffffffffU,
+/*005f*/ 0x10010820U,
+/*0060*/ 0x18060820U,
+/*0061*/ 0x00080821U,
+/*0062*/ 0x00200822U,
+/*0063*/ 0xffffffffU,
+/*0064*/ 0x000a0823U,
+/*0065*/ 0x10060823U,
+/*0066*/ 0x18070823U,
+/*0067*/ 0x00080824U,
+/*0068*/ 0x08080824U,
+/*0069*/ 0x100a0824U,
+/*006a*/ 0x00070825U,
+/*006b*/ 0x08080825U,
+/*006c*/ 0x10080825U,
+/*006d*/ 0x18030825U,
+/*006e*/ 0x000a0826U,
+/*006f*/ 0x100a0826U,
+/*0070*/ 0x00110827U,
+/*0071*/ 0x00090828U,
+/*0072*/ 0x10090828U,
+/*0073*/ 0x00100829U,
+/*0074*/ 0x100e0829U,
+/*0075*/ 0x000e082aU,
+/*0076*/ 0x100c082aU,
+/*0077*/ 0x000a082bU,
+/*0078*/ 0x100a082bU,
+/*0079*/ 0x0002082cU,
+/*007a*/ 0x0020082dU,
+/*007b*/ 0x000b082eU,
+/*007c*/ 0x100b082eU,
+/*007d*/ 0x0020082fU,
+/*007e*/ 0x00120830U,
+/*007f*/ 0x00200831U,
+/*0080*/ 0x00200832U,
+/*0081*/ 0xffffffffU,
+/*0082*/ 0xffffffffU,
+/*0083*/ 0x00010833U,
+/*0084*/ 0x08010833U,
+/*0085*/ 0x10080833U,
+/*0086*/ 0x000c0834U,
+/*0087*/ 0x100c0834U,
+/*0088*/ 0x000c0835U,
+/*0089*/ 0x100c0835U,
+/*008a*/ 0x000c0836U,
+/*008b*/ 0x100c0836U,
+/*008c*/ 0x000c0837U,
+/*008d*/ 0x100c0837U,
+/*008e*/ 0x000c0838U,
+/*008f*/ 0x100c0838U,
+/*0090*/ 0x000c0839U,
+/*0091*/ 0x100b0839U,
+/*0092*/ 0xffffffffU,
+/*0093*/ 0xffffffffU,
+/*0094*/ 0x000b083aU,
+/*0095*/ 0x100b083aU,
+/*0096*/ 0x000b083bU,
+/*0097*/ 0x100b083bU,
+/*0098*/ 0x000b083cU,
+/*0099*/ 0x100b083cU,
+/*009a*/ 0x000b083dU,
+/*009b*/ 0x100b083dU,
+/*009c*/ 0x000b083eU,
+/*009d*/ 0x100a083eU,
+/*009e*/ 0xffffffffU,
+/*009f*/ 0x000a083fU,
+/*00a0*/ 0x100a083fU,
+/*00a1*/ 0x000a0840U,
+/*00a2*/ 0x100a0840U,
+/*00a3*/ 0x000a0841U,
+/*00a4*/ 0x100a0841U,
+/*00a5*/ 0x000a0842U,
+/*00a6*/ 0x100a0842U,
+/*00a7*/ 0x000a0843U,
+/*00a8*/ 0x100a0843U,
+/*00a9*/ 0x000a0844U,
+/*00aa*/ 0x100a0844U,
+/*00ab*/ 0x000a0845U,
+/*00ac*/ 0x100a0845U,
+/*00ad*/ 0x000a0846U,
+/*00ae*/ 0x100a0846U,
+/*00af*/ 0x000a0847U,
+/*00b0*/ 0x100a0847U,
+/*00b1*/ 0x000a0848U,
+/*00b2*/ 0x100a0848U,
+/*00b3*/ 0x000a0849U,
+/*00b4*/ 0x100a0849U,
+/*00b5*/ 0x000a084aU,
+/*00b6*/ 0x100a084aU,
+/*00b7*/ 0x000a084bU,
+/*00b8*/ 0x100a084bU,
+/*00b9*/ 0x000a084cU,
+/*00ba*/ 0x100a084cU,
+/*00bb*/ 0x0004084dU,
+/*00bc*/ 0x0803084dU,
+/*00bd*/ 0x100a084dU,
+/*00be*/ 0x000a084eU,
+/*00bf*/ 0x1001084eU,
+/*00c0*/ 0x000a084fU,
+/*00c1*/ 0x1004084fU,
+/*00c2*/ 0x000b0850U,
+/*00c3*/ 0x100a0850U,
+/*00c4*/ 0xffffffffU,
+/*00c5*/ 0x00080851U,
+/*00c6*/ 0x08080851U,
+/*00c7*/ 0x10080851U,
+/*00c8*/ 0x18080851U,
+/*00c9*/ 0x00080852U,
+/*00ca*/ 0xffffffffU,
+/*00cb*/ 0x08080852U,
+/*00cc*/ 0x10010852U,
+/*00cd*/ 0x18080852U,
+/*00ce*/ 0x00080853U,
+/*00cf*/ 0x08020853U,
+/*00d0*/ 0x10020853U,
+/*00d1*/ 0x18040853U,
+/*00d2*/ 0x00040854U,
+/*00d3*/ 0xffffffffU,
+/*00d4*/ 0x08040854U,
+/*00d5*/ 0x100a0854U,
+/*00d6*/ 0x00060855U,
+/*00d7*/ 0x08080855U,
+/*00d8*/ 0xffffffffU,
+/*00d9*/ 0x10040855U,
+/*00da*/ 0x18040855U,
+/*00db*/ 0x00050856U,
+/*00dc*/ 0x08040856U,
+/*00dd*/ 0x10050856U,
+/*00de*/ 0x000a0857U,
+/*00df*/ 0x100a0857U,
+/*00e0*/ 0x00080858U,
+/*00e1*/ 0xffffffffU,
+/*00e2*/ 0x08040858U,
+/*00e3*/ 0xffffffffU,
+/*00e4*/ 0xffffffffU,
+/*00e5*/ 0x00050a00U,
+/*00e6*/ 0x08050a00U,
+/*00e7*/ 0x10050a00U,
+/*00e8*/ 0x18050a00U,
+/*00e9*/ 0x00050a01U,
+/*00ea*/ 0x08050a01U,
+/*00eb*/ 0x100b0a01U,
+/*00ec*/ 0x00010a02U,
+/*00ed*/ 0x08030a02U,
+/*00ee*/ 0x00200a03U,
+/*00ef*/ 0xffffffffU,
+/*00f0*/ 0x00030a04U,
+/*00f1*/ 0x080a0a04U,
+/*00f2*/ 0xffffffffU,
+/*00f3*/ 0xffffffffU,
+/*00f4*/ 0x18030a04U,
+/*00f5*/ 0x00030a05U,
+/*00f6*/ 0x08010a05U,
+/*00f7*/ 0x10010a05U,
+/*00f8*/ 0x18060a05U,
+/*00f9*/ 0xffffffffU,
+/*00fa*/ 0xffffffffU,
+/*00fb*/ 0xffffffffU,
+/*00fc*/ 0x00020a06U,
+/*00fd*/ 0x08030a06U,
+/*00fe*/ 0x10010a06U,
+/*00ff*/ 0x000f0a07U,
+/*0100*/ 0x00200a08U,
+/*0101*/ 0x00200a09U,
+/*0102*/ 0x000b0a0aU,
+/*0103*/ 0x100b0a0aU,
+/*0104*/ 0x000b0a0bU,
+/*0105*/ 0xffffffffU,
+/*0106*/ 0xffffffffU,
+/*0107*/ 0x00180a0cU,
+/*0108*/ 0x00180a0dU,
+/*0109*/ 0x00180a0eU,
+/*010a*/ 0x00180a0fU,
+/*010b*/ 0x18040a0fU,
+/*010c*/ 0x00020a10U,
+/*010d*/ 0x08020a10U,
+/*010e*/ 0x10040a10U,
+/*010f*/ 0x18040a10U,
+/*0110*/ 0x00010a11U,
+/*0111*/ 0x08010a11U,
+/*0112*/ 0x10010a11U,
+/*0113*/ 0x18030a11U,
+/*0114*/ 0x00200a12U,
+/*0115*/ 0x00200a13U,
+/*0116*/ 0xffffffffU,
+/*0117*/ 0x00140a14U,
+/*0118*/ 0x00140a15U,
+/*0119*/ 0x00140a16U,
+/*011a*/ 0x00140a17U,
+/*011b*/ 0x00140a18U,
+/*011c*/ 0x00140a19U,
+/*011d*/ 0x00140a1aU,
+/*011e*/ 0x00140a1bU,
+/*011f*/ 0x001e0a1cU,
+/*0120*/ 0x000a0a1dU,
+/*0121*/ 0x10060a1dU,
+/*0122*/ 0x18060a1dU,
+/*0123*/ 0x00060a1eU,
+/*0124*/ 0xffffffffU,
+/*0125*/ 0x08060a1eU,
+/*0126*/ 0x00080a1fU,
+/*0127*/ 0x080b0a1fU,
+/*0128*/ 0x000b0a20U,
+/*0129*/ 0x100b0a20U,
+/*012a*/ 0x000b0a21U,
+/*012b*/ 0x100b0a21U,
+/*012c*/ 0x000b0a22U,
+/*012d*/ 0x10040a22U,
+/*012e*/ 0x000a0a23U,
+/*012f*/ 0x10060a23U,
+/*0130*/ 0x18080a23U,
+/*0131*/ 0xffffffffU,
+/*0132*/ 0x00040a24U,
+/*0133*/ 0xffffffffU,
+/*0134*/ 0xffffffffU,
+/*0135*/ 0x00010b80U,
+/*0136*/ 0x08020b80U,
+/*0137*/ 0x10050b80U,
+/*0138*/ 0x18050b80U,
+/*0139*/ 0x00050b81U,
+/*013a*/ 0x08050b81U,
+/*013b*/ 0x100b0b81U,
+/*013c*/ 0x00050b82U,
+/*013d*/ 0x08010b82U,
+/*013e*/ 0x10010b82U,
+/*013f*/ 0xffffffffU,
+/*0140*/ 0x18010b82U,
+/*0141*/ 0x00010b83U,
+/*0142*/ 0x08040b83U,
+/*0143*/ 0x100b0b83U,
+/*0144*/ 0x000b0b84U,
+/*0145*/ 0xffffffffU,
+/*0146*/ 0x10040b84U,
+/*0147*/ 0x000b0b85U,
+/*0148*/ 0x10040b85U,
+/*0149*/ 0x18010b85U,
+/*014a*/ 0x00010b86U,
+/*014b*/ 0x08010b86U,
+/*014c*/ 0x00200b87U,
+/*014d*/ 0x00200b88U,
+/*014e*/ 0x00080b89U,
+/*014f*/ 0x080a0b89U,
+/*0150*/ 0x18050b89U,
+/*0151*/ 0x000a0b8aU,
+/*0152*/ 0x10030b8aU,
+/*0153*/ 0x18030b8aU,
+/*0154*/ 0x00010b8bU,
+/*0155*/ 0x08020b8bU,
+/*0156*/ 0x10010b8bU,
+/*0157*/ 0x18010b8bU,
+/*0158*/ 0x00010b8cU,
+/*0159*/ 0x08030b8cU,
+/*015a*/ 0xffffffffU,
+/*015b*/ 0x10040b8cU,
+/*015c*/ 0x18040b8cU,
+/*015d*/ 0x00040b8dU,
+/*015e*/ 0x08040b8dU,
+/*015f*/ 0xffffffffU,
+/*0160*/ 0xffffffffU,
+/*0161*/ 0xffffffffU,
+/*0162*/ 0xffffffffU,
+/*0163*/ 0xffffffffU,
+/*0164*/ 0xffffffffU,
+/*0165*/ 0xffffffffU,
+/*0166*/ 0xffffffffU,
+/*0167*/ 0xffffffffU,
+/*0168*/ 0x000d0b8eU,
+/*0169*/ 0x100d0b8eU,
+/*016a*/ 0x000d0b8fU,
+/*016b*/ 0x00050b90U,
+/*016c*/ 0x00010b91U,
+/*016d*/ 0x080e0b91U,
+/*016e*/ 0x000e0b92U,
+/*016f*/ 0x100e0b92U,
+/*0170*/ 0x000e0b93U,
+/*0171*/ 0x100e0b93U,
+/*0172*/ 0x00040b94U,
+/*0173*/ 0x08040b94U,
+/*0174*/ 0x10040b94U,
+/*0175*/ 0x18040b94U,
+/*0176*/ 0x00040b95U,
+/*0177*/ 0x080b0b95U,
+/*0178*/ 0x000b0b96U,
+/*0179*/ 0x100b0b96U,
+/*017a*/ 0x000b0b97U,
+/*017b*/ 0xffffffffU,
+/*017c*/ 0xffffffffU,
+/*017d*/ 0xffffffffU,
+/*017e*/ 0xffffffffU,
+/*017f*/ 0x000d0b98U,
+/*0180*/ 0x100d0b98U,
+/*0181*/ 0x000d0b99U,
+/*0182*/ 0x10100b99U,
+/*0183*/ 0x10080b8dU,
+/*0184*/ 0x18080b8dU,
+/*0185*/ 0x00100b9aU,
+/*0186*/ 0x10100b9aU,
+/*0187*/ 0x00100b9bU,
+/*0188*/ 0x10100b9bU,
+/*0189*/ 0x00100b9cU,
+/*018a*/ 0x10030b9cU,
+/*018b*/ 0x18040b9cU,
+/*018c*/ 0x00010b9dU,
+/*018d*/ 0x08040b9dU,
+/*018e*/ 0xffffffffU,
+/*018f*/ 0xffffffffU,
+/*0190*/ 0x10010b9dU,
+/*0191*/ 0x00140b9eU,
+/*0192*/ 0x000a0b9fU,
+/*0193*/ 0x100c0b9fU,
+/*0194*/ 0x00120ba0U,
+/*0195*/ 0x00140ba1U,
+/*0196*/ 0x00120ba2U,
+/*0197*/ 0x00110ba3U,
+/*0198*/ 0x00110ba4U,
+/*0199*/ 0x00120ba5U,
+/*019a*/ 0x00120ba6U,
+/*019b*/ 0x00120ba7U,
+/*019c*/ 0x00120ba8U,
+/*019d*/ 0x00120ba9U,
+/*019e*/ 0x00120baaU,
+/*019f*/ 0x00120babU,
+/*01a0*/ 0x00120bacU,
+/*01a1*/ 0xffffffffU,
+/*01a2*/ 0xffffffffU,
+/*01a3*/ 0x00190badU,
+/*01a4*/ 0x00190baeU,
+/*01a5*/ 0x00200bafU,
+/*01a6*/ 0x00170bb0U,
+/*01a7*/ 0x18080bb0U,
+/*01a8*/ 0x00010bb1U,
+/*01a9*/ 0x08010bb1U,
+/*01aa*/ 0x00200bb2U,
+/*01ab*/ 0x00080bb3U,
+/*01ac*/ 0xffffffffU,
+/*01ad*/ 0x08030bb3U,
+/*01ae*/ 0x00180bb4U,
+/*01af*/ 0x00180bb5U,
+/*01b0*/ 0xffffffffU,
+/*01b1*/ 0xffffffffU,
+/*01b2*/ 0xffffffffU,
+/*01b3*/ 0xffffffffU,
+/*01b4*/ 0xffffffffU,
+/*01b5*/ 0xffffffffU,
+/*01b6*/ 0xffffffffU,
+/*01b7*/ 0xffffffffU,
+/*01b8*/ 0xffffffffU,
+/*01b9*/ 0xffffffffU,
+/*01ba*/ 0xffffffffU,
+/*01bb*/ 0xffffffffU,
+/*01bc*/ 0xffffffffU,
+/*01bd*/ 0xffffffffU,
+/*01be*/ 0xffffffffU,
+/*01bf*/ 0x00100bb6U,
+/*01c0*/ 0x10010bb6U,
+/*01c1*/ 0x18010bb6U,
+/*01c2*/ 0x00050bb7U,
+/*01c3*/ 0x00200bb8U,
+/*01c4*/ 0x00090bb9U,
+/*01c5*/ 0xffffffffU,
+/*01c6*/ 0xffffffffU,
+/*01c7*/ 0x00200bbaU,
+/*01c8*/ 0x00040bbbU,
+/*01c9*/ 0x08100bbbU,
+/*01ca*/ 0x18060bbbU,
+/*01cb*/ 0x00100bbcU,
+/*01cc*/ 0xffffffffU,
+/*01cd*/ 0x10080bbcU,
+/*01ce*/ 0xffffffffU,
+/*01cf*/ 0xffffffffU,
+/*01d0*/ 0xffffffffU,
+/*01d1*/ 0x18030bbcU,
+/*01d2*/ 0x00020bbdU,
+/*01d3*/ 0xffffffffU,
+/*01d4*/ 0x00200bbeU,
+/*01d5*/ 0x000b0bbfU,
+/*01d6*/ 0xffffffffU,
+/*01d7*/ 0xffffffffU,
+/*01d8*/ 0xffffffffU,
+/*01d9*/ 0x10020bbfU,
+/*01da*/ 0xffffffffU,
+/*01db*/ 0xffffffffU,
+/*01dc*/ 0xffffffffU,
+/*01dd*/ 0xffffffffU,
+/*01de*/ 0x00010200U,
+/*01df*/ 0x08040200U,
+/*01e0*/ 0x10100200U,
+/*01e1*/ 0x00010201U,
+/*01e2*/ 0x08010201U,
+/*01e3*/ 0xffffffffU,
+/*01e4*/ 0xffffffffU,
+/*01e5*/ 0x10100201U,
+/*01e6*/ 0xffffffffU,
+/*01e7*/ 0xffffffffU,
+/*01e8*/ 0xffffffffU,
+/*01e9*/ 0xffffffffU,
+/*01ea*/ 0xffffffffU,
+/*01eb*/ 0xffffffffU,
+/*01ec*/ 0xffffffffU,
+/*01ed*/ 0xffffffffU,
+/*01ee*/ 0xffffffffU,
+/*01ef*/ 0x00200202U,
+/*01f0*/ 0x00100203U,
+/*01f1*/ 0x00200204U,
+/*01f2*/ 0x00100205U,
+/*01f3*/ 0x00200206U,
+/*01f4*/ 0x00100207U,
+/*01f5*/ 0x10100207U,
+/*01f6*/ 0x00200208U,
+/*01f7*/ 0x00200209U,
+/*01f8*/ 0x0020020aU,
+/*01f9*/ 0x0020020bU,
+/*01fa*/ 0x0010020cU,
+/*01fb*/ 0x0020020dU,
+/*01fc*/ 0x0020020eU,
+/*01fd*/ 0x0020020fU,
+/*01fe*/ 0x00200210U,
+/*01ff*/ 0x00100211U,
+/*0200*/ 0x00200212U,
+/*0201*/ 0x00200213U,
+/*0202*/ 0x00200214U,
+/*0203*/ 0x00200215U,
+/*0204*/ 0x00090216U,
+/*0205*/ 0x10010216U,
+/*0206*/ 0x00200217U,
+/*0207*/ 0x00050218U,
+/*0208*/ 0x08010218U,
+/*0209*/ 0x10080218U,
+/*020a*/ 0x18080218U,
+/*020b*/ 0x001e0219U,
+/*020c*/ 0x001e021aU,
+/*020d*/ 0x001e021bU,
+/*020e*/ 0x001e021cU,
+/*020f*/ 0x001e021dU,
+/*0210*/ 0x001e021eU,
+/*0211*/ 0x001e021fU,
+/*0212*/ 0x001e0220U,
+/*0213*/ 0x001e0221U,
+/*0214*/ 0x001e0222U,
+/*0215*/ 0x001e0223U,
+/*0216*/ 0x001e0224U,
+/*0217*/ 0x001e0225U,
+/*0218*/ 0x001e0226U,
+/*0219*/ 0x001e0227U,
+/*021a*/ 0x001e0228U,
+/*021b*/ 0x00010229U,
+/*021c*/ 0x08010229U,
+/*021d*/ 0x10010229U,
+/*021e*/ 0x18040229U,
+/*021f*/ 0x0008022aU,
+/*0220*/ 0x0808022aU,
+/*0221*/ 0x1008022aU,
+/*0222*/ 0x1804022aU,
+/*0223*/ 0x0005022bU,
+/*0224*/ 0x0806022bU,
+/*0225*/ 0x1007022bU,
+/*0226*/ 0x1805022bU,
+/*0227*/ 0x0006022cU,
+/*0228*/ 0x0807022cU,
+/*0229*/ 0x1005022cU,
+/*022a*/ 0x1806022cU,
+/*022b*/ 0x0007022dU,
+/*022c*/ 0x0802022dU,
+/*022d*/ 0x1001022dU,
+/*022e*/ 0xffffffffU,
+/*022f*/ 0x000a022eU,
+/*0230*/ 0x1010022eU,
+/*0231*/ 0x000a022fU,
+/*0232*/ 0x1010022fU,
+/*0233*/ 0x000a0230U,
+/*0234*/ 0x10100230U,
+/*0235*/ 0xffffffffU,
+/*0236*/ 0x00100231U,
+/*0237*/ 0xffffffffU,
+/*0238*/ 0xffffffffU,
+/*0239*/ 0x10010231U,
+/*023a*/ 0x18010231U,
+/*023b*/ 0x00010232U,
+/*023c*/ 0x08010232U,
+/*023d*/ 0x10010232U,
+/*023e*/ 0x18010232U,
+/*023f*/ 0x00020233U,
+/*0240*/ 0x08020233U,
+/*0241*/ 0x10020233U,
+/*0242*/ 0x18020233U,
+/*0243*/ 0x00020234U,
+/*0244*/ 0x08030234U,
+/*0245*/ 0x10010234U,
+/*0246*/ 0x18010234U,
+/*0247*/ 0x00010235U,
+/*0248*/ 0x08010235U,
+/*0249*/ 0xffffffffU,
+/*024a*/ 0x10020235U,
+/*024b*/ 0x18010235U,
+/*024c*/ 0x00010236U,
+/*024d*/ 0xffffffffU,
+/*024e*/ 0x08020236U,
+/*024f*/ 0x10010236U,
+/*0250*/ 0x18010236U,
+/*0251*/ 0xffffffffU,
+/*0252*/ 0x00020237U,
+/*0253*/ 0x08010237U,
+/*0254*/ 0x10010237U,
+/*0255*/ 0xffffffffU,
+/*0256*/ 0x18020237U,
+/*0257*/ 0x00070238U,
+/*0258*/ 0x08010238U,
+/*0259*/ 0x10010238U,
+/*025a*/ 0x18010238U,
+/*025b*/ 0x00010239U,
+/*025c*/ 0x08010239U,
+/*025d*/ 0x10010239U,
+/*025e*/ 0xffffffffU,
+/*025f*/ 0x18010239U,
+/*0260*/ 0x0004023aU,
+/*0261*/ 0x0804023aU,
+/*0262*/ 0x1004023aU,
+/*0263*/ 0x1801023aU,
+/*0264*/ 0x0002023bU,
+/*0265*/ 0x0806023bU,
+/*0266*/ 0x1006023bU,
+/*0267*/ 0xffffffffU,
+/*0268*/ 0xffffffffU,
+/*0269*/ 0xffffffffU,
+/*026a*/ 0x1802023bU,
+/*026b*/ 0x0010023cU,
+/*026c*/ 0x1001023cU,
+/*026d*/ 0x1801023cU,
+/*026e*/ 0xffffffffU,
+/*026f*/ 0x0004023dU,
+/*0270*/ 0x0801023dU,
+/*0271*/ 0x1004023dU,
+/*0272*/ 0x1802023dU,
+/*0273*/ 0x0008023eU,
+/*0274*/ 0xffffffffU,
+/*0275*/ 0xffffffffU,
+/*0276*/ 0xffffffffU,
+/*0277*/ 0x080a023eU,
+/*0278*/ 0x0020023fU,
+/*0279*/ 0x00200240U,
+/*027a*/ 0x00050241U,
+/*027b*/ 0x08010241U,
+/*027c*/ 0x10050241U,
+/*027d*/ 0x18080241U,
+/*027e*/ 0x00010242U,
+/*027f*/ 0x08080242U,
+/*0280*/ 0x10010242U,
+/*0281*/ 0x18080242U,
+/*0282*/ 0x00010243U,
+/*0283*/ 0x08040243U,
+/*0284*/ 0x10040243U,
+/*0285*/ 0x18040243U,
+/*0286*/ 0x00040244U,
+/*0287*/ 0x08040244U,
+/*0288*/ 0x10040244U,
+/*0289*/ 0x18040244U,
+/*028a*/ 0x00040245U,
+/*028b*/ 0x08040245U,
+/*028c*/ 0x10040245U,
+/*028d*/ 0x18010245U,
+/*028e*/ 0x00040246U,
+/*028f*/ 0x08040246U,
+/*0290*/ 0x10040246U,
+/*0291*/ 0x18040246U,
+/*0292*/ 0x00040247U,
+/*0293*/ 0x08040247U,
+/*0294*/ 0x10060247U,
+/*0295*/ 0x18060247U,
+/*0296*/ 0x00060248U,
+/*0297*/ 0x08060248U,
+/*0298*/ 0x10060248U,
+/*0299*/ 0x18060248U,
+/*029a*/ 0x00040249U,
+/*029b*/ 0x08010249U,
+/*029c*/ 0x10010249U,
+/*029d*/ 0x18020249U,
+/*029e*/ 0xffffffffU,
+/*029f*/ 0xffffffffU,
+/*02a0*/ 0xffffffffU,
+/*02a1*/ 0xffffffffU,
+/*02a2*/ 0xffffffffU,
+/*02a3*/ 0xffffffffU,
+/*02a4*/ 0xffffffffU,
+/*02a5*/ 0xffffffffU,
+/*02a6*/ 0x0004024aU,
+/*02a7*/ 0x0804024aU,
+/*02a8*/ 0x1001024aU,
+/*02a9*/ 0x1801024aU,
+/*02aa*/ 0xffffffffU,
+/*02ab*/ 0x0001024bU,
+/*02ac*/ 0x0801024bU,
+/*02ad*/ 0xffffffffU,
+/*02ae*/ 0x1001024bU,
+/*02af*/ 0x1801024bU,
+/*02b0*/ 0x0001024cU,
+/*02b1*/ 0x0804024cU,
+/*02b2*/ 0x1004024cU,
+/*02b3*/ 0x000a024dU,
+/*02b4*/ 0x0020024eU,
+/*02b5*/ 0x0004024fU,
+/*02b6*/ 0x0808024fU,
+/*02b7*/ 0xffffffffU,
+/*02b8*/ 0xffffffffU,
+/*02b9*/ 0xffffffffU,
+/*02ba*/ 0xffffffffU,
+/*02bb*/ 0xffffffffU,
+/*02bc*/ 0xffffffffU,
+/*02bd*/ 0x1002024fU,
+/*02be*/ 0x1802024fU,
+/*02bf*/ 0x00200250U,
+/*02c0*/ 0x00020251U,
+/*02c1*/ 0x08100251U,
+/*02c2*/ 0x00100252U,
+/*02c3*/ 0x10040252U,
+/*02c4*/ 0x18040252U,
+/*02c5*/ 0x00050253U,
+/*02c6*/ 0x08050253U,
+/*02c7*/ 0xffffffffU,
+/*02c8*/ 0xffffffffU,
+/*02c9*/ 0xffffffffU,
+/*02ca*/ 0xffffffffU,
+/*02cb*/ 0x10010253U,
+/*02cc*/ 0x18010253U,
+/*02cd*/ 0x00080254U,
+/*02ce*/ 0x08080254U,
+/*02cf*/ 0x10080254U,
+/*02d0*/ 0x18080254U,
+/*02d1*/ 0x00080255U,
+/*02d2*/ 0x08080255U,
+/*02d3*/ 0x10080255U,
+/*02d4*/ 0x18080255U,
+/*02d5*/ 0x00080256U,
+/*02d6*/ 0x08080256U,
+/*02d7*/ 0x10080256U,
+/*02d8*/ 0xffffffffU,
+/*02d9*/ 0xffffffffU,
+/*02da*/ 0xffffffffU,
+/*02db*/ 0xffffffffU,
+/*02dc*/ 0xffffffffU,
+/*02dd*/ 0xffffffffU,
+/*02de*/ 0x18030256U,
+/*02df*/ 0x00010257U,
+/*02e0*/ 0x08020257U,
+/*02e1*/ 0x10010257U,
+/*02e2*/ 0x18040257U,
+/*02e3*/ 0x00020258U,
+/*02e4*/ 0x08010258U,
+/*02e5*/ 0x10010258U,
+/*02e6*/ 0xffffffffU,
+/*02e7*/ 0x18010258U,
+/*02e8*/ 0x00040259U,
+/*02e9*/ 0x08080259U,
+/*02ea*/ 0x100a0259U,
+/*02eb*/ 0x000a025aU,
+/*02ec*/ 0x100a025aU,
+/*02ed*/ 0x000a025bU,
+/*02ee*/ 0x100a025bU,
+/*02ef*/ 0x000a025cU,
+/*02f0*/ 0x0020025dU,
+/*02f1*/ 0x0020025eU,
+/*02f2*/ 0x0001025fU,
+/*02f3*/ 0xffffffffU,
+/*02f4*/ 0xffffffffU,
+/*02f5*/ 0xffffffffU,
+/*02f6*/ 0x0802025fU,
+/*02f7*/ 0x1002025fU,
+/*02f8*/ 0x00100260U,
+/*02f9*/ 0x10050260U,
+/*02fa*/ 0x18060260U,
+/*02fb*/ 0x00050261U,
+/*02fc*/ 0x08050261U,
+/*02fd*/ 0x100e0261U,
+/*02fe*/ 0x00050262U,
+/*02ff*/ 0x080e0262U,
+/*0300*/ 0x18050262U,
+/*0301*/ 0x000e0263U,
+/*0302*/ 0x10050263U,
+/*0303*/ 0x18010263U,
+/*0304*/ 0x00050264U,
+/*0305*/ 0x08050264U,
+/*0306*/ 0x100a0264U,
+/*0307*/ 0x000a0265U,
+/*0308*/ 0x10050265U,
+/*0309*/ 0x18050265U,
+/*030a*/ 0x000a0266U,
+/*030b*/ 0x100a0266U,
+/*030c*/ 0x00050267U,
+/*030d*/ 0x08050267U,
+/*030e*/ 0x100a0267U,
+/*030f*/ 0x000a0268U,
+/*0310*/ 0xffffffffU,
+/*0311*/ 0xffffffffU,
+/*0312*/ 0xffffffffU,
+/*0313*/ 0xffffffffU,
+/*0314*/ 0xffffffffU,
+/*0315*/ 0xffffffffU,
+/*0316*/ 0x10070268U,
+/*0317*/ 0x18070268U,
+/*0318*/ 0x00040269U,
+/*0319*/ 0x08040269U,
+/*031a*/ 0xffffffffU,
+/*031b*/ 0xffffffffU,
+/*031c*/ 0xffffffffU,
+/*031d*/ 0x10040269U,
+/*031e*/ 0x18080269U,
+/*031f*/ 0x0008026aU,
+/*0320*/ 0x0804026aU,
+/*0321*/ 0xffffffffU,
+/*0322*/ 0xffffffffU,
+/*0323*/ 0xffffffffU,
+/*0324*/ 0x1004026aU,
+/*0325*/ 0xffffffffU,
+/*0326*/ 0xffffffffU,
+/*0327*/ 0xffffffffU,
+/*0328*/ 0x1804026aU,
+/*0329*/ 0xffffffffU,
+/*032a*/ 0xffffffffU,
+/*032b*/ 0xffffffffU,
+/*032c*/ 0x0004026bU,
+/*032d*/ 0x0805026bU,
+/*032e*/ 0x1007026bU,
+/*032f*/ 0x1808026bU,
+/*0330*/ 0x0010026cU,
+/*0331*/ 0x1008026cU,
+/*0332*/ 0x0010026dU,
+/*0333*/ 0x1008026dU,
+/*0334*/ 0x0010026eU,
+/*0335*/ 0x1008026eU,
+/*0336*/ 0x1808026eU,
+/*0337*/ 0x0001026fU,
+/*0338*/ 0x0801026fU,
+/*0339*/ 0x1006026fU,
+/*033a*/ 0x1806026fU,
+/*033b*/ 0x00060270U,
+/*033c*/ 0xffffffffU,
+/*033d*/ 0x08010270U,
+/*033e*/ 0x10030270U,
+/*033f*/ 0xffffffffU,
+/*0340*/ 0xffffffffU,
+/*0341*/ 0xffffffffU,
+/*0342*/ 0x000a0271U,
+/*0343*/ 0x100a0271U,
+/*0344*/ 0x00040272U,
+/*0345*/ 0x08010272U,
+/*0346*/ 0x10040272U,
+/*0347*/ 0xffffffffU,
+/*0348*/ 0xffffffffU,
+/*0349*/ 0xffffffffU,
+/*034a*/ 0xffffffffU,
+/*034b*/ 0xffffffffU,
+/*034c*/ 0xffffffffU,
+/*034d*/ 0x18070272U,
+/*034e*/ 0x00070273U,
+/*034f*/ 0x08050273U,
+/*0350*/ 0x10050273U,
+/*0351*/ 0xffffffffU,
+/*0352*/ 0xffffffffU,
+/*0353*/ 0xffffffffU,
+/*0354*/ 0x18040273U,
+/*0355*/ 0x00010274U,
+/*0356*/ 0x08010274U,
+/*0357*/ 0x10020274U,
+/*0358*/ 0x18080274U,
+/*0359*/ 0x00200275U,
+/*035a*/ 0x00200276U,
+/*035b*/ 0x00100277U,
+/*035c*/ 0xffffffffU,
+/*035d*/ 0xffffffffU,
+/*035e*/ 0xffffffffU,
+/*035f*/ 0x10020277U,
+/*0360*/ 0x18010277U,
+/*0361*/ 0xffffffffU,
+/*0362*/ 0x00020278U,
+/*0363*/ 0x08100278U,
+/*0364*/ 0x00100279U,
+/*0365*/ 0x10100279U,
+/*0366*/ 0x0008027aU,
+/*0367*/ 0x0808027aU,
+/*0368*/ 0x1008027aU,
+/*0369*/ 0xffffffffU,
+/*036a*/ 0x0010027bU,
+/*036b*/ 0x1010027bU,
+/*036c*/ 0x0010027cU,
+/*036d*/ 0x1008027cU,
+/*036e*/ 0x1808027cU,
+/*036f*/ 0x0008027dU,
+/*0370*/ 0xffffffffU,
+/*0371*/ 0x0810027dU,
+/*0372*/ 0x0010027eU,
+/*0373*/ 0x1010027eU,
+/*0374*/ 0x0008027fU,
+/*0375*/ 0x0808027fU,
+/*0376*/ 0x1008027fU,
+/*0377*/ 0xffffffffU,
+/*0378*/ 0x1808027fU,
+/*0379*/ 0x00100280U,
+/*037a*/ 0x10100280U,
+/*037b*/ 0x00100281U,
+/*037c*/ 0x10080281U,
+/*037d*/ 0x18080281U,
+/*037e*/ 0x00080282U,
+/*037f*/ 0xffffffffU,
+/*0380*/ 0x08100282U,
+/*0381*/ 0x00100283U,
+/*0382*/ 0x10100283U,
+/*0383*/ 0x00080284U,
+/*0384*/ 0x08080284U,
+/*0385*/ 0x10080284U,
+/*0386*/ 0xffffffffU,
+/*0387*/ 0x00100285U,
+/*0388*/ 0x10100285U,
+/*0389*/ 0x00100286U,
+/*038a*/ 0x10080286U,
+/*038b*/ 0x18080286U,
+/*038c*/ 0x00080287U,
+/*038d*/ 0xffffffffU,
+/*038e*/ 0x08080287U,
+/*038f*/ 0x10100287U,
+/*0390*/ 0x00100288U,
+/*0391*/ 0x10100288U,
+/*0392*/ 0x00080289U,
+/*0393*/ 0x08080289U,
+/*0394*/ 0x10080289U,
+/*0395*/ 0xffffffffU,
+/*0396*/ 0x0010028aU,
+/*0397*/ 0x1010028aU,
+/*0398*/ 0x0010028bU,
+/*0399*/ 0x1008028bU,
+/*039a*/ 0x1808028bU,
+/*039b*/ 0x0008028cU,
+/*039c*/ 0xffffffffU,
+/*039d*/ 0x0810028cU,
+/*039e*/ 0x0010028dU,
+/*039f*/ 0x1010028dU,
+/*03a0*/ 0x0008028eU,
+/*03a1*/ 0x0808028eU,
+/*03a2*/ 0x1008028eU,
+/*03a3*/ 0xffffffffU,
+/*03a4*/ 0x1808028eU,
+/*03a5*/ 0x0010028fU,
+/*03a6*/ 0x1010028fU,
+/*03a7*/ 0x00100290U,
+/*03a8*/ 0x10080290U,
+/*03a9*/ 0x18080290U,
+/*03aa*/ 0x00080291U,
+/*03ab*/ 0xffffffffU,
+/*03ac*/ 0x08100291U,
+/*03ad*/ 0x00100292U,
+/*03ae*/ 0x10100292U,
+/*03af*/ 0x00080293U,
+/*03b0*/ 0x08080293U,
+/*03b1*/ 0x10080293U,
+/*03b2*/ 0xffffffffU,
+/*03b3*/ 0x00100294U,
+/*03b4*/ 0x10100294U,
+/*03b5*/ 0x00100295U,
+/*03b6*/ 0x10080295U,
+/*03b7*/ 0x18080295U,
+/*03b8*/ 0x00080296U,
+/*03b9*/ 0xffffffffU,
+/*03ba*/ 0x08080296U,
+/*03bb*/ 0x10020296U,
+/*03bc*/ 0x18030296U,
+/*03bd*/ 0x000a0297U,
+/*03be*/ 0x100a0297U,
+/*03bf*/ 0x000a0298U,
+/*03c0*/ 0x10050298U,
+/*03c1*/ 0x18040298U,
+/*03c2*/ 0x00080299U,
+/*03c3*/ 0x08080299U,
+/*03c4*/ 0x10060299U,
+/*03c5*/ 0x18060299U,
+/*03c6*/ 0x0011029aU,
+/*03c7*/ 0x1808029aU,
+/*03c8*/ 0x0004029bU,
+/*03c9*/ 0x0806029bU,
+/*03ca*/ 0xffffffffU,
+/*03cb*/ 0x1006029bU,
+/*03cc*/ 0x1808029bU,
+/*03cd*/ 0x0008029cU,
+/*03ce*/ 0x0804029cU,
+/*03cf*/ 0x1008029cU,
+/*03d0*/ 0x1808029cU,
+/*03d1*/ 0x0006029dU,
+/*03d2*/ 0x0806029dU,
+/*03d3*/ 0x0011029eU,
+/*03d4*/ 0x1808029eU,
+/*03d5*/ 0x0004029fU,
+/*03d6*/ 0x0806029fU,
+/*03d7*/ 0xffffffffU,
+/*03d8*/ 0x1006029fU,
+/*03d9*/ 0x1808029fU,
+/*03da*/ 0x000802a0U,
+/*03db*/ 0x080402a0U,
+/*03dc*/ 0x100802a0U,
+/*03dd*/ 0x180802a0U,
+/*03de*/ 0x000602a1U,
+/*03df*/ 0x080602a1U,
+/*03e0*/ 0x001102a2U,
+/*03e1*/ 0x180802a2U,
+/*03e2*/ 0x000402a3U,
+/*03e3*/ 0x080602a3U,
+/*03e4*/ 0xffffffffU,
+/*03e5*/ 0x100602a3U,
+/*03e6*/ 0x180802a3U,
+/*03e7*/ 0x000802a4U,
+/*03e8*/ 0x080402a4U,
+/*03e9*/ 0x100402a4U,
+/*03ea*/ 0x180402a4U,
+/*03eb*/ 0x000402a5U,
+/*03ec*/ 0x080402a5U,
+/*03ed*/ 0x100402a5U,
+/*03ee*/ 0x180402a5U,
+/*03ef*/ 0x000402a6U,
+/*03f0*/ 0x080402a6U,
+/*03f1*/ 0x100402a6U,
+/*03f2*/ 0x180402a6U,
+/*03f3*/ 0x000402a7U,
+/*03f4*/ 0x080402a7U,
+/*03f5*/ 0x100402a7U,
+/*03f6*/ 0x180402a7U,
+/*03f7*/ 0x000402a8U,
+/*03f8*/ 0x080402a8U,
+/*03f9*/ 0x100402a8U,
+/*03fa*/ 0x180402a8U,
+/*03fb*/ 0x000402a9U,
+/*03fc*/ 0x081202a9U,
+/*03fd*/ 0x001102aaU,
+/*03fe*/ 0x001202abU,
+/*03ff*/ 0x002002acU,
+/*0400*/ 0x002002adU,
+/*0401*/ 0x002002aeU,
+/*0402*/ 0x002002afU,
+/*0403*/ 0x002002b0U,
+/*0404*/ 0x002002b1U,
+/*0405*/ 0x002002b2U,
+/*0406*/ 0x002002b3U,
+/*0407*/ 0x002002b4U,
+/*0408*/ 0x000302b5U,
+/*0409*/ 0x080502b5U,
+/*040a*/ 0x100502b5U,
+/*040b*/ 0x180102b5U,
+/*040c*/ 0x000502b6U,
+/*040d*/ 0x080502b6U,
+/*040e*/ 0x100502b6U,
+/*040f*/ 0x180502b6U,
+/*0410*/ 0x000502b7U,
+/*0411*/ 0x080502b7U,
+/*0412*/ 0x100502b7U,
+/*0413*/ 0x180502b7U,
+/*0414*/ 0x000502b8U,
+/*0415*/ 0x080502b8U,
+/*0416*/ 0x100502b8U,
+/*0417*/ 0x180502b8U,
+/*0418*/ 0x000502b9U,
+/*0419*/ 0x080502b9U,
+/*041a*/ 0x100502b9U,
+/*041b*/ 0x180502b9U,
+/*041c*/ 0x000502baU,
+/*041d*/ 0x080502baU,
+/*041e*/ 0x100502baU,
+/*041f*/ 0x180502baU,
+/*0420*/ 0x000502bbU,
+/*0421*/ 0x080502bbU,
+/*0422*/ 0x100102bbU,
+/*0423*/ 0x180202bbU,
+/*0424*/ 0x000202bcU,
+/*0425*/ 0x080202bcU,
+/*0426*/ 0x100202bcU,
+/*0427*/ 0x180102bcU,
+/*0428*/ 0x000402bdU,
+/*0429*/ 0x081002bdU,
+/*042a*/ 0x002002beU,
+/*042b*/ 0x001002bfU,
+/*042c*/ 0x002002c0U,
+/*042d*/ 0x001002c1U,
+/*042e*/ 0x002002c2U,
+/*042f*/ 0x000702c3U,
+/*0430*/ 0x080102c3U,
+/*0431*/ 0x100202c3U,
+/*0432*/ 0x180602c3U,
+/*0433*/ 0x000102c4U,
+/*0434*/ 0x080102c4U,
+/*0435*/ 0x002002c5U,
+/*0436*/ 0x000302c6U,
+/*0437*/ 0x002002c7U,
+/*0438*/ 0x002002c8U,
+/*0439*/ 0xffffffffU,
+/*043a*/ 0xffffffffU,
+/*043b*/ 0xffffffffU,
+/*043c*/ 0xffffffffU,
+/*043d*/ 0xffffffffU,
+/*043e*/ 0xffffffffU,
+/*043f*/ 0xffffffffU,
+/*0440*/ 0xffffffffU,
+/*0441*/ 0xffffffffU,
+/*0442*/ 0xffffffffU,
+/*0443*/ 0xffffffffU,
+/*0444*/ 0xffffffffU,
+/*0445*/ 0xffffffffU,
+/*0446*/ 0xffffffffU,
+/*0447*/ 0xffffffffU,
+/*0448*/ 0xffffffffU,
+/*0449*/ 0xffffffffU,
+/*044a*/ 0xffffffffU,
+/*044b*/ 0xffffffffU,
+/*044c*/ 0xffffffffU,
+/*044d*/ 0xffffffffU,
+/*044e*/ 0xffffffffU,
+/*044f*/ 0xffffffffU,
+/*0450*/ 0xffffffffU,
+/*0451*/ 0xffffffffU,
+/*0452*/ 0xffffffffU,
+/*0453*/ 0xffffffffU,
+/*0454*/ 0xffffffffU,
+/*0455*/ 0xffffffffU,
+/*0456*/ 0xffffffffU,
+/*0457*/ 0xffffffffU,
+/*0458*/ 0xffffffffU,
+/*0459*/ 0xffffffffU,
+/*045a*/ 0xffffffffU,
+/*045b*/ 0xffffffffU,
+/*045c*/ 0xffffffffU,
+/*045d*/ 0xffffffffU,
+/*045e*/ 0xffffffffU,
+/*045f*/ 0x000402c9U,
+/*0460*/ 0xffffffffU,
+/*0461*/ 0xffffffffU,
+/*0462*/ 0xffffffffU,
+/*0463*/ 0xffffffffU,
+/*0464*/ 0xffffffffU,
+/*0465*/ 0xffffffffU,
+/*0466*/ 0xffffffffU,
+/*0467*/ 0xffffffffU,
+/*0468*/ 0xffffffffU,
+/*0469*/ 0xffffffffU,
+/*046a*/ 0xffffffffU,
+/*046b*/ 0xffffffffU,
+/*046c*/ 0xffffffffU,
+/*046d*/ 0xffffffffU,
+/*046e*/ 0xffffffffU,
+/*046f*/ 0xffffffffU,
+/*0470*/ 0xffffffffU,
+/*0471*/ 0xffffffffU,
+/*0472*/ 0xffffffffU,
+/*0473*/ 0xffffffffU,
+/*0474*/ 0xffffffffU,
+/*0475*/ 0xffffffffU,
+/*0476*/ 0xffffffffU,
+/*0477*/ 0xffffffffU,
+/*0478*/ 0xffffffffU,
+/*0479*/ 0xffffffffU,
+/*047a*/ 0xffffffffU,
+/*047b*/ 0xffffffffU,
+/*047c*/ 0xffffffffU,
+/*047d*/ 0xffffffffU,
+/*047e*/ 0xffffffffU,
+/*047f*/ 0xffffffffU,
+/*0480*/ 0xffffffffU,
+/*0481*/ 0xffffffffU,
+/*0482*/ 0xffffffffU,
+/*0483*/ 0xffffffffU,
+/*0484*/ 0xffffffffU,
+/*0485*/ 0xffffffffU,
+/*0486*/ 0xffffffffU,
+/*0487*/ 0xffffffffU,
+/*0488*/ 0xffffffffU,
+/*0489*/ 0xffffffffU,
+/*048a*/ 0xffffffffU,
+/*048b*/ 0xffffffffU,
+/*048c*/ 0xffffffffU,
+/*048d*/ 0xffffffffU,
+/*048e*/ 0xffffffffU,
+/*048f*/ 0xffffffffU,
+/*0490*/ 0xffffffffU,
+/*0491*/ 0xffffffffU,
+/*0492*/ 0xffffffffU,
+/*0493*/ 0xffffffffU,
+/*0494*/ 0xffffffffU,
+	 },
+	{
+/*0000*/ 0x00200400U,
+/*0001*/ 0x00040401U,
+/*0002*/ 0x080b0401U,
+/*0003*/ 0x000a0402U,
+/*0004*/ 0x10020402U,
+/*0005*/ 0x18010402U,
+/*0006*/ 0x00050403U,
+/*0007*/ 0x08050403U,
+/*0008*/ 0x10050403U,
+/*0009*/ 0x18050403U,
+/*000a*/ 0x00050404U,
+/*000b*/ 0x08050404U,
+/*000c*/ 0x10050404U,
+/*000d*/ 0x18050404U,
+/*000e*/ 0x00050405U,
+/*000f*/ 0x08040405U,
+/*0010*/ 0x10030405U,
+/*0011*/ 0x00180406U,
+/*0012*/ 0x18030406U,
+/*0013*/ 0x00180407U,
+/*0014*/ 0x18020407U,
+/*0015*/ 0x00010408U,
+/*0016*/ 0x08020408U,
+/*0017*/ 0x10010408U,
+/*0018*/ 0x18010408U,
+/*0019*/ 0x00020409U,
+/*001a*/ 0x08040409U,
+/*001b*/ 0x10040409U,
+/*001c*/ 0x18040409U,
+/*001d*/ 0xffffffffU,
+/*001e*/ 0x0004040aU,
+/*001f*/ 0xffffffffU,
+/*0020*/ 0xffffffffU,
+/*0021*/ 0x0809040aU,
+/*0022*/ 0x1801040aU,
+/*0023*/ 0x0020040bU,
+/*0024*/ 0x001c040cU,
+/*0025*/ 0x0001040dU,
+/*0026*/ 0x0807040dU,
+/*0027*/ 0x1009040dU,
+/*0028*/ 0x000a040eU,
+/*0029*/ 0x1005040eU,
+/*002a*/ 0x1801040eU,
+/*002b*/ 0x1001040fU,
+/*002c*/ 0x1802040fU,
+/*002d*/ 0x0009040fU,
+/*002e*/ 0x00090410U,
+/*002f*/ 0x10020410U,
+/*0030*/ 0x00200411U,
+/*0031*/ 0x00010412U,
+/*0032*/ 0x08020412U,
+/*0033*/ 0xffffffffU,
+/*0034*/ 0xffffffffU,
+/*0035*/ 0xffffffffU,
+/*0036*/ 0xffffffffU,
+/*0037*/ 0x00200413U,
+/*0038*/ 0x00200414U,
+/*0039*/ 0x00200415U,
+/*003a*/ 0x00200416U,
+/*003b*/ 0x00030417U,
+/*003c*/ 0x08010417U,
+/*003d*/ 0x10040417U,
+/*003e*/ 0x18030417U,
+/*003f*/ 0x00040418U,
+/*0040*/ 0x08040418U,
+/*0041*/ 0x10040418U,
+/*0042*/ 0x18040418U,
+/*0043*/ 0x00010419U,
+/*0044*/ 0x08010419U,
+/*0045*/ 0x10060419U,
+/*0046*/ 0x18040419U,
+/*0047*/ 0xffffffffU,
+/*0048*/ 0x0006041aU,
+/*0049*/ 0x0804041aU,
+/*004a*/ 0x1006041aU,
+/*004b*/ 0x1804041aU,
+/*004c*/ 0x0002041bU,
+/*004d*/ 0x0805041bU,
+/*004e*/ 0x1008041bU,
+/*004f*/ 0xffffffffU,
+/*0050*/ 0x1806041bU,
+/*0051*/ 0x0003041cU,
+/*0052*/ 0x080b041cU,
+/*0053*/ 0x1804041cU,
+/*0054*/ 0x0004041dU,
+/*0055*/ 0x0804041dU,
+/*0056*/ 0x1001041dU,
+/*0057*/ 0xffffffffU,
+/*0058*/ 0x0009041eU,
+/*0059*/ 0x0020041fU,
+/*005a*/ 0x00200420U,
+/*005b*/ 0x00200421U,
+/*005c*/ 0x00200422U,
+/*005d*/ 0x00100423U,
+/*005e*/ 0xffffffffU,
+/*005f*/ 0x10010423U,
+/*0060*/ 0x18060423U,
+/*0061*/ 0x00080424U,
+/*0062*/ 0x00200425U,
+/*0063*/ 0x00100426U,
+/*0064*/ 0x100a0426U,
+/*0065*/ 0x00060427U,
+/*0066*/ 0x08070427U,
+/*0067*/ 0x10080427U,
+/*0068*/ 0x18080427U,
+/*0069*/ 0x000a0428U,
+/*006a*/ 0x10070428U,
+/*006b*/ 0x18080428U,
+/*006c*/ 0x00080429U,
+/*006d*/ 0x08030429U,
+/*006e*/ 0x100a0429U,
+/*006f*/ 0x000a042aU,
+/*0070*/ 0x0011042bU,
+/*0071*/ 0x0009042cU,
+/*0072*/ 0x1009042cU,
+/*0073*/ 0x0010042dU,
+/*0074*/ 0x100e042dU,
+/*0075*/ 0x000e042eU,
+/*0076*/ 0x0012042fU,
+/*0077*/ 0x000a0430U,
+/*0078*/ 0x100a0430U,
+/*0079*/ 0x00020431U,
+/*007a*/ 0x00200432U,
+/*007b*/ 0x000b0433U,
+/*007c*/ 0x100b0433U,
+/*007d*/ 0x00200434U,
+/*007e*/ 0x00120435U,
+/*007f*/ 0x00200436U,
+/*0080*/ 0x00200437U,
+/*0081*/ 0x00080438U,
+/*0082*/ 0x08010438U,
+/*0083*/ 0x10010438U,
+/*0084*/ 0x18010438U,
+/*0085*/ 0x00080439U,
+/*0086*/ 0x080c0439U,
+/*0087*/ 0x000c043aU,
+/*0088*/ 0x100c043aU,
+/*0089*/ 0x000c043bU,
+/*008a*/ 0x100c043bU,
+/*008b*/ 0x000c043cU,
+/*008c*/ 0x100c043cU,
+/*008d*/ 0x000c043dU,
+/*008e*/ 0x100c043dU,
+/*008f*/ 0x000c043eU,
+/*0090*/ 0x100c043eU,
+/*0091*/ 0x000b043fU,
+/*0092*/ 0x1009043fU,
+/*0093*/ 0x00010440U,
+/*0094*/ 0x000b0441U,
+/*0095*/ 0x100b0441U,
+/*0096*/ 0x000b0442U,
+/*0097*/ 0x100b0442U,
+/*0098*/ 0x000b0443U,
+/*0099*/ 0x100b0443U,
+/*009a*/ 0x000b0444U,
+/*009b*/ 0x100b0444U,
+/*009c*/ 0x000b0445U,
+/*009d*/ 0x100a0445U,
+/*009e*/ 0x00020446U,
+/*009f*/ 0x080a0446U,
+/*00a0*/ 0x000a0447U,
+/*00a1*/ 0x100a0447U,
+/*00a2*/ 0x000a0448U,
+/*00a3*/ 0x100a0448U,
+/*00a4*/ 0x000a0449U,
+/*00a5*/ 0x100a0449U,
+/*00a6*/ 0x000a044aU,
+/*00a7*/ 0x100a044aU,
+/*00a8*/ 0x000a044bU,
+/*00a9*/ 0x100a044bU,
+/*00aa*/ 0x000a044cU,
+/*00ab*/ 0x100a044cU,
+/*00ac*/ 0x000a044dU,
+/*00ad*/ 0x100a044dU,
+/*00ae*/ 0x000a044eU,
+/*00af*/ 0x100a044eU,
+/*00b0*/ 0x000a044fU,
+/*00b1*/ 0x100a044fU,
+/*00b2*/ 0x000a0450U,
+/*00b3*/ 0x100a0450U,
+/*00b4*/ 0x000a0451U,
+/*00b5*/ 0x100a0451U,
+/*00b6*/ 0x000a0452U,
+/*00b7*/ 0x100a0452U,
+/*00b8*/ 0x000a0453U,
+/*00b9*/ 0x100a0453U,
+/*00ba*/ 0x000a0454U,
+/*00bb*/ 0x10040454U,
+/*00bc*/ 0x18030454U,
+/*00bd*/ 0x000a0455U,
+/*00be*/ 0x100a0455U,
+/*00bf*/ 0x00010456U,
+/*00c0*/ 0x080a0456U,
+/*00c1*/ 0x18040456U,
+/*00c2*/ 0x000b0457U,
+/*00c3*/ 0x100a0457U,
+/*00c4*/ 0x00030458U,
+/*00c5*/ 0x00080459U,
+/*00c6*/ 0x08080459U,
+/*00c7*/ 0x10080459U,
+/*00c8*/ 0x18080459U,
+/*00c9*/ 0x0008045aU,
+/*00ca*/ 0xffffffffU,
+/*00cb*/ 0x0808045aU,
+/*00cc*/ 0x1001045aU,
+/*00cd*/ 0x1808045aU,
+/*00ce*/ 0x0008045bU,
+/*00cf*/ 0x0802045bU,
+/*00d0*/ 0x1002045bU,
+/*00d1*/ 0x1805045bU,
+/*00d2*/ 0x0005045cU,
+/*00d3*/ 0xffffffffU,
+/*00d4*/ 0x0804045cU,
+/*00d5*/ 0x100a045cU,
+/*00d6*/ 0x0006045dU,
+/*00d7*/ 0x0808045dU,
+/*00d8*/ 0x1008045dU,
+/*00d9*/ 0x1804045dU,
+/*00da*/ 0x0004045eU,
+/*00db*/ 0x0805045eU,
+/*00dc*/ 0x1004045eU,
+/*00dd*/ 0x1805045eU,
+/*00de*/ 0x000a045fU,
+/*00df*/ 0x100a045fU,
+/*00e0*/ 0x00080460U,
+/*00e1*/ 0xffffffffU,
+/*00e2*/ 0x08040460U,
+/*00e3*/ 0xffffffffU,
+/*00e4*/ 0xffffffffU,
+/*00e5*/ 0x00050600U,
+/*00e6*/ 0x08050600U,
+/*00e7*/ 0x10050600U,
+/*00e8*/ 0x18050600U,
+/*00e9*/ 0x00050601U,
+/*00ea*/ 0x08050601U,
+/*00eb*/ 0x100b0601U,
+/*00ec*/ 0x00010602U,
+/*00ed*/ 0x08030602U,
+/*00ee*/ 0x00200603U,
+/*00ef*/ 0x00100604U,
+/*00f0*/ 0x10040604U,
+/*00f1*/ 0x000a0605U,
+/*00f2*/ 0x10090605U,
+/*00f3*/ 0x00080606U,
+/*00f4*/ 0x08030606U,
+/*00f5*/ 0x10030606U,
+/*00f6*/ 0x18010606U,
+/*00f7*/ 0x00010607U,
+/*00f8*/ 0x08070607U,
+/*00f9*/ 0x10070607U,
+/*00fa*/ 0x18050607U,
+/*00fb*/ 0x00010608U,
+/*00fc*/ 0x08020608U,
+/*00fd*/ 0x10030608U,
+/*00fe*/ 0x18010608U,
+/*00ff*/ 0x000f0609U,
+/*0100*/ 0x0020060aU,
+/*0101*/ 0x0020060bU,
+/*0102*/ 0x000b060cU,
+/*0103*/ 0x100b060cU,
+/*0104*/ 0x000b060dU,
+/*0105*/ 0x0018060eU,
+/*0106*/ 0x0018060fU,
+/*0107*/ 0xffffffffU,
+/*0108*/ 0xffffffffU,
+/*0109*/ 0xffffffffU,
+/*010a*/ 0xffffffffU,
+/*010b*/ 0xffffffffU,
+/*010c*/ 0x1802060fU,
+/*010d*/ 0x00020610U,
+/*010e*/ 0x08040610U,
+/*010f*/ 0x10040610U,
+/*0110*/ 0x18010610U,
+/*0111*/ 0x00010611U,
+/*0112*/ 0x08010611U,
+/*0113*/ 0x10030611U,
+/*0114*/ 0x00200612U,
+/*0115*/ 0x00200613U,
+/*0116*/ 0xffffffffU,
+/*0117*/ 0x00140614U,
+/*0118*/ 0x00140615U,
+/*0119*/ 0x00140616U,
+/*011a*/ 0x00140617U,
+/*011b*/ 0x00140618U,
+/*011c*/ 0x00140619U,
+/*011d*/ 0x0014061aU,
+/*011e*/ 0x0014061bU,
+/*011f*/ 0x0018061cU,
+/*0120*/ 0x000a061dU,
+/*0121*/ 0x1006061dU,
+/*0122*/ 0x1806061dU,
+/*0123*/ 0x0006061eU,
+/*0124*/ 0xffffffffU,
+/*0125*/ 0x0806061eU,
+/*0126*/ 0x0008061fU,
+/*0127*/ 0x080b061fU,
+/*0128*/ 0x000b0620U,
+/*0129*/ 0x100b0620U,
+/*012a*/ 0x000b0621U,
+/*012b*/ 0x100b0621U,
+/*012c*/ 0x000b0622U,
+/*012d*/ 0x10040622U,
+/*012e*/ 0x000a0623U,
+/*012f*/ 0x10060623U,
+/*0130*/ 0x18080623U,
+/*0131*/ 0x00080624U,
+/*0132*/ 0x08040624U,
+/*0133*/ 0x00020680U,
+/*0134*/ 0x00010681U,
+/*0135*/ 0x08010681U,
+/*0136*/ 0x10020681U,
+/*0137*/ 0x18050681U,
+/*0138*/ 0x00050682U,
+/*0139*/ 0x08050682U,
+/*013a*/ 0x10050682U,
+/*013b*/ 0x000b0683U,
+/*013c*/ 0x10050683U,
+/*013d*/ 0x18010683U,
+/*013e*/ 0x00010684U,
+/*013f*/ 0xffffffffU,
+/*0140*/ 0x08010684U,
+/*0141*/ 0x10010684U,
+/*0142*/ 0x18040684U,
+/*0143*/ 0x000b0685U,
+/*0144*/ 0x100b0685U,
+/*0145*/ 0x000b0686U,
+/*0146*/ 0x10040686U,
+/*0147*/ 0x000b0687U,
+/*0148*/ 0x10040687U,
+/*0149*/ 0x18010687U,
+/*014a*/ 0x00010688U,
+/*014b*/ 0x08010688U,
+/*014c*/ 0x00200689U,
+/*014d*/ 0x0020068aU,
+/*014e*/ 0x0008068bU,
+/*014f*/ 0x080a068bU,
+/*0150*/ 0x1805068bU,
+/*0151*/ 0x000a068cU,
+/*0152*/ 0x1003068cU,
+/*0153*/ 0x1803068cU,
+/*0154*/ 0x0001068dU,
+/*0155*/ 0x0802068dU,
+/*0156*/ 0x1001068dU,
+/*0157*/ 0x1801068dU,
+/*0158*/ 0x0001068eU,
+/*0159*/ 0x0802068eU,
+/*015a*/ 0x1001068eU,
+/*015b*/ 0x0004068fU,
+/*015c*/ 0x0804068fU,
+/*015d*/ 0x1004068fU,
+/*015e*/ 0x1804068fU,
+/*015f*/ 0x00010690U,
+/*0160*/ 0x08010690U,
+/*0161*/ 0x10010690U,
+/*0162*/ 0x00200691U,
+/*0163*/ 0x00200692U,
+/*0164*/ 0x00200693U,
+/*0165*/ 0x00200694U,
+/*0166*/ 0xffffffffU,
+/*0167*/ 0x1801068eU,
+/*0168*/ 0x000d0696U,
+/*0169*/ 0x100d0696U,
+/*016a*/ 0x000d0697U,
+/*016b*/ 0x00050698U,
+/*016c*/ 0x00010699U,
+/*016d*/ 0x080e0699U,
+/*016e*/ 0x000e069aU,
+/*016f*/ 0x100e069aU,
+/*0170*/ 0x000e069bU,
+/*0171*/ 0x100e069bU,
+/*0172*/ 0x0004069cU,
+/*0173*/ 0x0804069cU,
+/*0174*/ 0x1004069cU,
+/*0175*/ 0x1804069cU,
+/*0176*/ 0x0004069dU,
+/*0177*/ 0x080b069dU,
+/*0178*/ 0x000b069eU,
+/*0179*/ 0x100b069eU,
+/*017a*/ 0x000b069fU,
+/*017b*/ 0xffffffffU,
+/*017c*/ 0xffffffffU,
+/*017d*/ 0xffffffffU,
+/*017e*/ 0xffffffffU,
+/*017f*/ 0x000d06a0U,
+/*0180*/ 0x100d06a0U,
+/*0181*/ 0x000d06a1U,
+/*0182*/ 0x101006a1U,
+/*0183*/ 0x00080695U,
+/*0184*/ 0x08080695U,
+/*0185*/ 0x001006a2U,
+/*0186*/ 0x101006a2U,
+/*0187*/ 0x001006a3U,
+/*0188*/ 0x101006a3U,
+/*0189*/ 0x001006a4U,
+/*018a*/ 0x100306a4U,
+/*018b*/ 0x180406a4U,
+/*018c*/ 0x000106a5U,
+/*018d*/ 0x080806a5U,
+/*018e*/ 0x100106a5U,
+/*018f*/ 0x180506a5U,
+/*0190*/ 0x000106a6U,
+/*0191*/ 0x081406a6U,
+/*0192*/ 0x000a06a7U,
+/*0193*/ 0x100c06a7U,
+/*0194*/ 0x001206a8U,
+/*0195*/ 0x001406a9U,
+/*0196*/ 0x001206aaU,
+/*0197*/ 0x001106abU,
+/*0198*/ 0x001106acU,
+/*0199*/ 0x001206adU,
+/*019a*/ 0x001206aeU,
+/*019b*/ 0x001206afU,
+/*019c*/ 0x001206b0U,
+/*019d*/ 0x001206b1U,
+/*019e*/ 0x001206b2U,
+/*019f*/ 0x001206b3U,
+/*01a0*/ 0x001206b4U,
+/*01a1*/ 0x001206b5U,
+/*01a2*/ 0x001206b6U,
+/*01a3*/ 0x000e06b7U,
+/*01a4*/ 0x100d06b7U,
+/*01a5*/ 0x002006b8U,
+/*01a6*/ 0x001706b9U,
+/*01a7*/ 0x000906baU,
+/*01a8*/ 0x100106baU,
+/*01a9*/ 0x180106baU,
+/*01aa*/ 0x002006bbU,
+/*01ab*/ 0x000806bcU,
+/*01ac*/ 0x080306bcU,
+/*01ad*/ 0x100306bcU,
+/*01ae*/ 0x001806bdU,
+/*01af*/ 0x001806beU,
+/*01b0*/ 0x180706beU,
+/*01b1*/ 0x000506bfU,
+/*01b2*/ 0x080806bfU,
+/*01b3*/ 0x100806bfU,
+/*01b4*/ 0x180806bfU,
+/*01b5*/ 0x000106c0U,
+/*01b6*/ 0x080106c0U,
+/*01b7*/ 0x002006c1U,
+/*01b8*/ 0xffffffffU,
+/*01b9*/ 0xffffffffU,
+/*01ba*/ 0xffffffffU,
+/*01bb*/ 0xffffffffU,
+/*01bc*/ 0xffffffffU,
+/*01bd*/ 0xffffffffU,
+/*01be*/ 0xffffffffU,
+/*01bf*/ 0x001006c2U,
+/*01c0*/ 0x100106c2U,
+/*01c1*/ 0x180106c2U,
+/*01c2*/ 0x000206c3U,
+/*01c3*/ 0x080406c3U,
+/*01c4*/ 0x100906c3U,
+/*01c5*/ 0x000706c4U,
+/*01c6*/ 0x080406c4U,
+/*01c7*/ 0x002006c5U,
+/*01c8*/ 0x000106c6U,
+/*01c9*/ 0x080206c6U,
+/*01ca*/ 0x100606c6U,
+/*01cb*/ 0x001006c7U,
+/*01cc*/ 0x100106c7U,
+/*01cd*/ 0x002006c8U,
+/*01ce*/ 0x000806c9U,
+/*01cf*/ 0x080106c9U,
+/*01d0*/ 0x100506c9U,
+/*01d1*/ 0xffffffffU,
+/*01d2*/ 0x180206c9U,
+/*01d3*/ 0x000106caU,
+/*01d4*/ 0x002006cbU,
+/*01d5*/ 0x000b06ccU,
+/*01d6*/ 0x100106ccU,
+/*01d7*/ 0x180306ccU,
+/*01d8*/ 0x000806cdU,
+/*01d9*/ 0x080206cdU,
+/*01da*/ 0x100c06cdU,
+/*01db*/ 0x000406ceU,
+/*01dc*/ 0x080106ceU,
+/*01dd*/ 0xffffffffU,
+/*01de*/ 0x00010200U,
+/*01df*/ 0x08040200U,
+/*01e0*/ 0x10100200U,
+/*01e1*/ 0x00010201U,
+/*01e2*/ 0x08010201U,
+/*01e3*/ 0x10010201U,
+/*01e4*/ 0xffffffffU,
+/*01e5*/ 0x00100202U,
+/*01e6*/ 0x10080202U,
+/*01e7*/ 0xffffffffU,
+/*01e8*/ 0xffffffffU,
+/*01e9*/ 0xffffffffU,
+/*01ea*/ 0xffffffffU,
+/*01eb*/ 0xffffffffU,
+/*01ec*/ 0xffffffffU,
+/*01ed*/ 0xffffffffU,
+/*01ee*/ 0xffffffffU,
+/*01ef*/ 0x00200203U,
+/*01f0*/ 0x00100204U,
+/*01f1*/ 0x00200205U,
+/*01f2*/ 0x00100206U,
+/*01f3*/ 0x00200207U,
+/*01f4*/ 0x00100208U,
+/*01f5*/ 0x00140209U,
+/*01f6*/ 0x0020020aU,
+/*01f7*/ 0x0020020bU,
+/*01f8*/ 0x0020020cU,
+/*01f9*/ 0x0020020dU,
+/*01fa*/ 0x0014020eU,
+/*01fb*/ 0x0020020fU,
+/*01fc*/ 0x00200210U,
+/*01fd*/ 0x00200211U,
+/*01fe*/ 0x00200212U,
+/*01ff*/ 0x00140213U,
+/*0200*/ 0x00200214U,
+/*0201*/ 0x00200215U,
+/*0202*/ 0x00200216U,
+/*0203*/ 0x00200217U,
+/*0204*/ 0x00090218U,
+/*0205*/ 0x10010218U,
+/*0206*/ 0x00200219U,
+/*0207*/ 0x0005021aU,
+/*0208*/ 0x0801021aU,
+/*0209*/ 0x1008021aU,
+/*020a*/ 0x1808021aU,
+/*020b*/ 0x001c021bU,
+/*020c*/ 0x001c021cU,
+/*020d*/ 0x001c021dU,
+/*020e*/ 0x001c021eU,
+/*020f*/ 0x001c021fU,
+/*0210*/ 0x001c0220U,
+/*0211*/ 0x001c0221U,
+/*0212*/ 0x001c0222U,
+/*0213*/ 0x001c0223U,
+/*0214*/ 0x001c0224U,
+/*0215*/ 0x001c0225U,
+/*0216*/ 0x001c0226U,
+/*0217*/ 0x001c0227U,
+/*0218*/ 0x001c0228U,
+/*0219*/ 0x001c0229U,
+/*021a*/ 0x001c022aU,
+/*021b*/ 0x0001022bU,
+/*021c*/ 0x0801022bU,
+/*021d*/ 0x1001022bU,
+/*021e*/ 0x1804022bU,
+/*021f*/ 0x0008022cU,
+/*0220*/ 0x0808022cU,
+/*0221*/ 0x1008022cU,
+/*0222*/ 0x1804022cU,
+/*0223*/ 0x0007022dU,
+/*0224*/ 0xffffffffU,
+/*0225*/ 0x0807022dU,
+/*0226*/ 0x1007022dU,
+/*0227*/ 0xffffffffU,
+/*0228*/ 0x1807022dU,
+/*0229*/ 0x0007022eU,
+/*022a*/ 0xffffffffU,
+/*022b*/ 0x0807022eU,
+/*022c*/ 0x1002022eU,
+/*022d*/ 0x1801022eU,
+/*022e*/ 0x0001022fU,
+/*022f*/ 0x080a022fU,
+/*0230*/ 0x00140230U,
+/*0231*/ 0x000a0231U,
+/*0232*/ 0x00140232U,
+/*0233*/ 0x000a0233U,
+/*0234*/ 0x00140234U,
+/*0235*/ 0x18010234U,
+/*0236*/ 0x00100235U,
+/*0237*/ 0x10050235U,
+/*0238*/ 0x18010235U,
+/*0239*/ 0x00010236U,
+/*023a*/ 0x08010236U,
+/*023b*/ 0x10010236U,
+/*023c*/ 0x18010236U,
+/*023d*/ 0x00010237U,
+/*023e*/ 0x08010237U,
+/*023f*/ 0x10020237U,
+/*0240*/ 0x18020237U,
+/*0241*/ 0x00020238U,
+/*0242*/ 0x08020238U,
+/*0243*/ 0x10020238U,
+/*0244*/ 0x18030238U,
+/*0245*/ 0x00010239U,
+/*0246*/ 0x08010239U,
+/*0247*/ 0x10010239U,
+/*0248*/ 0x18010239U,
+/*0249*/ 0xffffffffU,
+/*024a*/ 0x0002023aU,
+/*024b*/ 0x0801023aU,
+/*024c*/ 0x1001023aU,
+/*024d*/ 0xffffffffU,
+/*024e*/ 0x1802023aU,
+/*024f*/ 0x0001023bU,
+/*0250*/ 0x0801023bU,
+/*0251*/ 0xffffffffU,
+/*0252*/ 0x1002023bU,
+/*0253*/ 0x1801023bU,
+/*0254*/ 0x0001023cU,
+/*0255*/ 0xffffffffU,
+/*0256*/ 0x0802023cU,
+/*0257*/ 0x1007023cU,
+/*0258*/ 0x1801023cU,
+/*0259*/ 0x0001023dU,
+/*025a*/ 0x0801023dU,
+/*025b*/ 0x1001023dU,
+/*025c*/ 0x1801023dU,
+/*025d*/ 0x0001023eU,
+/*025e*/ 0x0801023eU,
+/*025f*/ 0x1001023eU,
+/*0260*/ 0x1804023eU,
+/*0261*/ 0x0004023fU,
+/*0262*/ 0x0804023fU,
+/*0263*/ 0x1001023fU,
+/*0264*/ 0x1802023fU,
+/*0265*/ 0x00060240U,
+/*0266*/ 0x08060240U,
+/*0267*/ 0x10020240U,
+/*0268*/ 0x18020240U,
+/*0269*/ 0x00020241U,
+/*026a*/ 0xffffffffU,
+/*026b*/ 0x08100241U,
+/*026c*/ 0x18010241U,
+/*026d*/ 0x00010242U,
+/*026e*/ 0x08010242U,
+/*026f*/ 0x10040242U,
+/*0270*/ 0x18010242U,
+/*0271*/ 0x00040243U,
+/*0272*/ 0x08020243U,
+/*0273*/ 0x10080243U,
+/*0274*/ 0xffffffffU,
+/*0275*/ 0xffffffffU,
+/*0276*/ 0xffffffffU,
+/*0277*/ 0x000a0244U,
+/*0278*/ 0x00200245U,
+/*0279*/ 0x00200246U,
+/*027a*/ 0x00050247U,
+/*027b*/ 0x08010247U,
+/*027c*/ 0x10050247U,
+/*027d*/ 0x18080247U,
+/*027e*/ 0x00010248U,
+/*027f*/ 0x08080248U,
+/*0280*/ 0x10010248U,
+/*0281*/ 0x18080248U,
+/*0282*/ 0x00010249U,
+/*0283*/ 0x08040249U,
+/*0284*/ 0x10040249U,
+/*0285*/ 0x18040249U,
+/*0286*/ 0x0004024aU,
+/*0287*/ 0x0804024aU,
+/*0288*/ 0x1004024aU,
+/*0289*/ 0x1804024aU,
+/*028a*/ 0x0004024bU,
+/*028b*/ 0x0804024bU,
+/*028c*/ 0x1004024bU,
+/*028d*/ 0x1801024bU,
+/*028e*/ 0x0004024cU,
+/*028f*/ 0x0804024cU,
+/*0290*/ 0x1004024cU,
+/*0291*/ 0x1804024cU,
+/*0292*/ 0x0004024dU,
+/*0293*/ 0x0804024dU,
+/*0294*/ 0x1006024dU,
+/*0295*/ 0x1806024dU,
+/*0296*/ 0x0006024eU,
+/*0297*/ 0x0806024eU,
+/*0298*/ 0x1006024eU,
+/*0299*/ 0x1806024eU,
+/*029a*/ 0xffffffffU,
+/*029b*/ 0x0001024fU,
+/*029c*/ 0x0801024fU,
+/*029d*/ 0x1002024fU,
+/*029e*/ 0xffffffffU,
+/*029f*/ 0xffffffffU,
+/*02a0*/ 0xffffffffU,
+/*02a1*/ 0xffffffffU,
+/*02a2*/ 0xffffffffU,
+/*02a3*/ 0xffffffffU,
+/*02a4*/ 0xffffffffU,
+/*02a5*/ 0xffffffffU,
+/*02a6*/ 0x1804024fU,
+/*02a7*/ 0x00040250U,
+/*02a8*/ 0x08010250U,
+/*02a9*/ 0x10010250U,
+/*02aa*/ 0x18010250U,
+/*02ab*/ 0x00010251U,
+/*02ac*/ 0x08010251U,
+/*02ad*/ 0x10010251U,
+/*02ae*/ 0x18010251U,
+/*02af*/ 0x00010252U,
+/*02b0*/ 0x08010252U,
+/*02b1*/ 0x10040252U,
+/*02b2*/ 0x18040252U,
+/*02b3*/ 0x000a0253U,
+/*02b4*/ 0x00200254U,
+/*02b5*/ 0x00040255U,
+/*02b6*/ 0x08080255U,
+/*02b7*/ 0x10020255U,
+/*02b8*/ 0x18020255U,
+/*02b9*/ 0x00020256U,
+/*02ba*/ 0x08020256U,
+/*02bb*/ 0x10020256U,
+/*02bc*/ 0x18020256U,
+/*02bd*/ 0xffffffffU,
+/*02be*/ 0xffffffffU,
+/*02bf*/ 0x00200257U,
+/*02c0*/ 0x00020258U,
+/*02c1*/ 0x08100258U,
+/*02c2*/ 0x00100259U,
+/*02c3*/ 0x10040259U,
+/*02c4*/ 0x18040259U,
+/*02c5*/ 0x0005025aU,
+/*02c6*/ 0x0805025aU,
+/*02c7*/ 0x0020025bU,
+/*02c8*/ 0x0020025cU,
+/*02c9*/ 0x0020025dU,
+/*02ca*/ 0x0020025eU,
+/*02cb*/ 0x0001025fU,
+/*02cc*/ 0x0801025fU,
+/*02cd*/ 0x1007025fU,
+/*02ce*/ 0x1807025fU,
+/*02cf*/ 0x00070260U,
+/*02d0*/ 0x08070260U,
+/*02d1*/ 0x10070260U,
+/*02d2*/ 0x18070260U,
+/*02d3*/ 0x00070261U,
+/*02d4*/ 0x08070261U,
+/*02d5*/ 0x10070261U,
+/*02d6*/ 0x18070261U,
+/*02d7*/ 0x00070262U,
+/*02d8*/ 0x08070262U,
+/*02d9*/ 0x10070262U,
+/*02da*/ 0x18070262U,
+/*02db*/ 0x00030263U,
+/*02dc*/ 0x08030263U,
+/*02dd*/ 0x10030263U,
+/*02de*/ 0xffffffffU,
+/*02df*/ 0x18010263U,
+/*02e0*/ 0x00020264U,
+/*02e1*/ 0x08010264U,
+/*02e2*/ 0x10040264U,
+/*02e3*/ 0x18020264U,
+/*02e4*/ 0x00010265U,
+/*02e5*/ 0x08010265U,
+/*02e6*/ 0x10010265U,
+/*02e7*/ 0x18010265U,
+/*02e8*/ 0x00040266U,
+/*02e9*/ 0x08080266U,
+/*02ea*/ 0x100a0266U,
+/*02eb*/ 0x000a0267U,
+/*02ec*/ 0x100a0267U,
+/*02ed*/ 0x000a0268U,
+/*02ee*/ 0x100a0268U,
+/*02ef*/ 0x000a0269U,
+/*02f0*/ 0x0020026aU,
+/*02f1*/ 0x0020026bU,
+/*02f2*/ 0x0001026cU,
+/*02f3*/ 0x0802026cU,
+/*02f4*/ 0x1002026cU,
+/*02f5*/ 0x1802026cU,
+/*02f6*/ 0xffffffffU,
+/*02f7*/ 0x0002026dU,
+/*02f8*/ 0x0810026dU,
+/*02f9*/ 0x1805026dU,
+/*02fa*/ 0x0006026eU,
+/*02fb*/ 0x0805026eU,
+/*02fc*/ 0x1005026eU,
+/*02fd*/ 0x000e026fU,
+/*02fe*/ 0x1005026fU,
+/*02ff*/ 0x000e0270U,
+/*0300*/ 0x10050270U,
+/*0301*/ 0x000e0271U,
+/*0302*/ 0x10050271U,
+/*0303*/ 0x18010271U,
+/*0304*/ 0x00050272U,
+/*0305*/ 0x08050272U,
+/*0306*/ 0x100a0272U,
+/*0307*/ 0x000a0273U,
+/*0308*/ 0x10050273U,
+/*0309*/ 0x18050273U,
+/*030a*/ 0x000a0274U,
+/*030b*/ 0x100a0274U,
+/*030c*/ 0x00050275U,
+/*030d*/ 0x08050275U,
+/*030e*/ 0x100a0275U,
+/*030f*/ 0x000a0276U,
+/*0310*/ 0xffffffffU,
+/*0311*/ 0xffffffffU,
+/*0312*/ 0xffffffffU,
+/*0313*/ 0xffffffffU,
+/*0314*/ 0xffffffffU,
+/*0315*/ 0xffffffffU,
+/*0316*/ 0x10070276U,
+/*0317*/ 0x18070276U,
+/*0318*/ 0x00040277U,
+/*0319*/ 0x08040277U,
+/*031a*/ 0xffffffffU,
+/*031b*/ 0xffffffffU,
+/*031c*/ 0xffffffffU,
+/*031d*/ 0x10040277U,
+/*031e*/ 0x18080277U,
+/*031f*/ 0x00080278U,
+/*0320*/ 0x08040278U,
+/*0321*/ 0xffffffffU,
+/*0322*/ 0xffffffffU,
+/*0323*/ 0xffffffffU,
+/*0324*/ 0x10040278U,
+/*0325*/ 0xffffffffU,
+/*0326*/ 0xffffffffU,
+/*0327*/ 0xffffffffU,
+/*0328*/ 0x18040278U,
+/*0329*/ 0xffffffffU,
+/*032a*/ 0xffffffffU,
+/*032b*/ 0xffffffffU,
+/*032c*/ 0x00040279U,
+/*032d*/ 0x08050279U,
+/*032e*/ 0x10070279U,
+/*032f*/ 0x18080279U,
+/*0330*/ 0x0010027aU,
+/*0331*/ 0x1008027aU,
+/*0332*/ 0x0010027bU,
+/*0333*/ 0x1008027bU,
+/*0334*/ 0x0010027cU,
+/*0335*/ 0x1008027cU,
+/*0336*/ 0x1808027cU,
+/*0337*/ 0x0001027dU,
+/*0338*/ 0x0801027dU,
+/*0339*/ 0x1006027dU,
+/*033a*/ 0x1806027dU,
+/*033b*/ 0x0006027eU,
+/*033c*/ 0x0801027eU,
+/*033d*/ 0x1001027eU,
+/*033e*/ 0x1803027eU,
+/*033f*/ 0x000a027fU,
+/*0340*/ 0x100a027fU,
+/*0341*/ 0x000a0280U,
+/*0342*/ 0xffffffffU,
+/*0343*/ 0x100a0280U,
+/*0344*/ 0x00040281U,
+/*0345*/ 0x08010281U,
+/*0346*/ 0x10040281U,
+/*0347*/ 0xffffffffU,
+/*0348*/ 0xffffffffU,
+/*0349*/ 0xffffffffU,
+/*034a*/ 0xffffffffU,
+/*034b*/ 0xffffffffU,
+/*034c*/ 0xffffffffU,
+/*034d*/ 0x18070281U,
+/*034e*/ 0x00070282U,
+/*034f*/ 0x08050282U,
+/*0350*/ 0x10050282U,
+/*0351*/ 0xffffffffU,
+/*0352*/ 0xffffffffU,
+/*0353*/ 0xffffffffU,
+/*0354*/ 0x18040282U,
+/*0355*/ 0x00010283U,
+/*0356*/ 0x08010283U,
+/*0357*/ 0x10020283U,
+/*0358*/ 0x18080283U,
+/*0359*/ 0x00200284U,
+/*035a*/ 0x00200285U,
+/*035b*/ 0x00100286U,
+/*035c*/ 0x10020286U,
+/*035d*/ 0x18020286U,
+/*035e*/ 0x00020287U,
+/*035f*/ 0xffffffffU,
+/*0360*/ 0x08010287U,
+/*0361*/ 0x10010287U,
+/*0362*/ 0x18020287U,
+/*0363*/ 0x00080288U,
+/*0364*/ 0x08080288U,
+/*0365*/ 0x10080288U,
+/*0366*/ 0x18080288U,
+/*0367*/ 0x00080289U,
+/*0368*/ 0x08080289U,
+/*0369*/ 0xffffffffU,
+/*036a*/ 0x10080289U,
+/*036b*/ 0x18080289U,
+/*036c*/ 0x0008028aU,
+/*036d*/ 0x0808028aU,
+/*036e*/ 0x1008028aU,
+/*036f*/ 0x1808028aU,
+/*0370*/ 0xffffffffU,
+/*0371*/ 0x0008028bU,
+/*0372*/ 0x0808028bU,
+/*0373*/ 0x1008028bU,
+/*0374*/ 0x1808028bU,
+/*0375*/ 0x0008028cU,
+/*0376*/ 0x0808028cU,
+/*0377*/ 0xffffffffU,
+/*0378*/ 0x1008028cU,
+/*0379*/ 0x1808028cU,
+/*037a*/ 0x0008028dU,
+/*037b*/ 0x0808028dU,
+/*037c*/ 0x1008028dU,
+/*037d*/ 0x1808028dU,
+/*037e*/ 0x0008028eU,
+/*037f*/ 0xffffffffU,
+/*0380*/ 0x0808028eU,
+/*0381*/ 0x1008028eU,
+/*0382*/ 0x1808028eU,
+/*0383*/ 0x0008028fU,
+/*0384*/ 0x0808028fU,
+/*0385*/ 0x1008028fU,
+/*0386*/ 0xffffffffU,
+/*0387*/ 0x1808028fU,
+/*0388*/ 0x00080290U,
+/*0389*/ 0x08080290U,
+/*038a*/ 0x10080290U,
+/*038b*/ 0x18080290U,
+/*038c*/ 0x00080291U,
+/*038d*/ 0xffffffffU,
+/*038e*/ 0x08080291U,
+/*038f*/ 0x10080291U,
+/*0390*/ 0x18080291U,
+/*0391*/ 0x00080292U,
+/*0392*/ 0x08080292U,
+/*0393*/ 0x10080292U,
+/*0394*/ 0x18080292U,
+/*0395*/ 0xffffffffU,
+/*0396*/ 0x00080293U,
+/*0397*/ 0x08080293U,
+/*0398*/ 0x10080293U,
+/*0399*/ 0x18080293U,
+/*039a*/ 0x00080294U,
+/*039b*/ 0x08080294U,
+/*039c*/ 0xffffffffU,
+/*039d*/ 0x10080294U,
+/*039e*/ 0x18080294U,
+/*039f*/ 0x00080295U,
+/*03a0*/ 0x08080295U,
+/*03a1*/ 0x10080295U,
+/*03a2*/ 0x18080295U,
+/*03a3*/ 0xffffffffU,
+/*03a4*/ 0x00080296U,
+/*03a5*/ 0x08080296U,
+/*03a6*/ 0x10080296U,
+/*03a7*/ 0x18080296U,
+/*03a8*/ 0x00080297U,
+/*03a9*/ 0x08080297U,
+/*03aa*/ 0x10080297U,
+/*03ab*/ 0xffffffffU,
+/*03ac*/ 0x18080297U,
+/*03ad*/ 0x00080298U,
+/*03ae*/ 0x08080298U,
+/*03af*/ 0x10080298U,
+/*03b0*/ 0x18080298U,
+/*03b1*/ 0x00080299U,
+/*03b2*/ 0xffffffffU,
+/*03b3*/ 0x08080299U,
+/*03b4*/ 0x10080299U,
+/*03b5*/ 0x18080299U,
+/*03b6*/ 0x0008029aU,
+/*03b7*/ 0x0808029aU,
+/*03b8*/ 0x1008029aU,
+/*03b9*/ 0xffffffffU,
+/*03ba*/ 0x1808029aU,
+/*03bb*/ 0x0002029bU,
+/*03bc*/ 0x0803029bU,
+/*03bd*/ 0x100a029bU,
+/*03be*/ 0x000a029cU,
+/*03bf*/ 0x100a029cU,
+/*03c0*/ 0x0005029dU,
+/*03c1*/ 0x0808029dU,
+/*03c2*/ 0x1008029dU,
+/*03c3*/ 0x1808029dU,
+/*03c4*/ 0x0006029eU,
+/*03c5*/ 0x0806029eU,
+/*03c6*/ 0x0011029fU,
+/*03c7*/ 0x1808029fU,
+/*03c8*/ 0x000402a0U,
+/*03c9*/ 0x080602a0U,
+/*03ca*/ 0xffffffffU,
+/*03cb*/ 0x100602a0U,
+/*03cc*/ 0x180802a0U,
+/*03cd*/ 0xffffffffU,
+/*03ce*/ 0x000802a1U,
+/*03cf*/ 0x080802a1U,
+/*03d0*/ 0x100802a1U,
+/*03d1*/ 0x180602a1U,
+/*03d2*/ 0x000602a2U,
+/*03d3*/ 0x081102a2U,
+/*03d4*/ 0x000802a3U,
+/*03d5*/ 0x080402a3U,
+/*03d6*/ 0x100602a3U,
+/*03d7*/ 0xffffffffU,
+/*03d8*/ 0x180602a3U,
+/*03d9*/ 0x000802a4U,
+/*03da*/ 0xffffffffU,
+/*03db*/ 0x080802a4U,
+/*03dc*/ 0x100802a4U,
+/*03dd*/ 0x180802a4U,
+/*03de*/ 0x000602a5U,
+/*03df*/ 0x080602a5U,
+/*03e0*/ 0x001102a6U,
+/*03e1*/ 0x180802a6U,
+/*03e2*/ 0x000402a7U,
+/*03e3*/ 0x080602a7U,
+/*03e4*/ 0xffffffffU,
+/*03e5*/ 0x100602a7U,
+/*03e6*/ 0x180802a7U,
+/*03e7*/ 0xffffffffU,
+/*03e8*/ 0x000402a8U,
+/*03e9*/ 0x080402a8U,
+/*03ea*/ 0x100402a8U,
+/*03eb*/ 0x180402a8U,
+/*03ec*/ 0x000402a9U,
+/*03ed*/ 0x080402a9U,
+/*03ee*/ 0x100402a9U,
+/*03ef*/ 0x180402a9U,
+/*03f0*/ 0x000402aaU,
+/*03f1*/ 0x080402aaU,
+/*03f2*/ 0x100402aaU,
+/*03f3*/ 0x180402aaU,
+/*03f4*/ 0x000402abU,
+/*03f5*/ 0x080402abU,
+/*03f6*/ 0x100402abU,
+/*03f7*/ 0x180402abU,
+/*03f8*/ 0x000402acU,
+/*03f9*/ 0x080402acU,
+/*03fa*/ 0x100402acU,
+/*03fb*/ 0x180402acU,
+/*03fc*/ 0x001202adU,
+/*03fd*/ 0x001102aeU,
+/*03fe*/ 0x001202afU,
+/*03ff*/ 0x002002b0U,
+/*0400*/ 0x002002b1U,
+/*0401*/ 0x002002b2U,
+/*0402*/ 0x002002b3U,
+/*0403*/ 0x002002b4U,
+/*0404*/ 0x002002b5U,
+/*0405*/ 0x002002b6U,
+/*0406*/ 0x002002b7U,
+/*0407*/ 0x002002b8U,
+/*0408*/ 0x000202b9U,
+/*0409*/ 0x080502b9U,
+/*040a*/ 0x100502b9U,
+/*040b*/ 0x180102b9U,
+/*040c*/ 0x000402baU,
+/*040d*/ 0x080402baU,
+/*040e*/ 0x100402baU,
+/*040f*/ 0x180402baU,
+/*0410*/ 0x000402bbU,
+/*0411*/ 0x080402bbU,
+/*0412*/ 0x100402bbU,
+/*0413*/ 0x180402bbU,
+/*0414*/ 0xffffffffU,
+/*0415*/ 0xffffffffU,
+/*0416*/ 0xffffffffU,
+/*0417*/ 0xffffffffU,
+/*0418*/ 0xffffffffU,
+/*0419*/ 0xffffffffU,
+/*041a*/ 0x000402bcU,
+/*041b*/ 0x080402bcU,
+/*041c*/ 0x100402bcU,
+/*041d*/ 0x180402bcU,
+/*041e*/ 0x000402bdU,
+/*041f*/ 0x080402bdU,
+/*0420*/ 0x100402bdU,
+/*0421*/ 0x180402bdU,
+/*0422*/ 0x000102beU,
+/*0423*/ 0x080202beU,
+/*0424*/ 0x100202beU,
+/*0425*/ 0x180202beU,
+/*0426*/ 0x000202bfU,
+/*0427*/ 0x080102bfU,
+/*0428*/ 0x100402bfU,
+/*0429*/ 0x001002c0U,
+/*042a*/ 0x002002c1U,
+/*042b*/ 0x001002c2U,
+/*042c*/ 0x002002c3U,
+/*042d*/ 0x001002c4U,
+/*042e*/ 0x002002c5U,
+/*042f*/ 0x000702c6U,
+/*0430*/ 0x080102c6U,
+/*0431*/ 0x100202c6U,
+/*0432*/ 0x180602c6U,
+/*0433*/ 0x000102c7U,
+/*0434*/ 0x080102c7U,
+/*0435*/ 0x002002c8U,
+/*0436*/ 0x000202c9U,
+/*0437*/ 0x002002caU,
+/*0438*/ 0x002002cbU,
+/*0439*/ 0x000c02ccU,
+/*043a*/ 0x100c02ccU,
+/*043b*/ 0x002002cdU,
+/*043c*/ 0x000302ceU,
+/*043d*/ 0x002002cfU,
+/*043e*/ 0x000302d0U,
+/*043f*/ 0x002002d1U,
+/*0440*/ 0x000302d2U,
+/*0441*/ 0x002002d3U,
+/*0442*/ 0x000302d4U,
+/*0443*/ 0x002002d5U,
+/*0444*/ 0x000302d6U,
+/*0445*/ 0x002002d7U,
+/*0446*/ 0x000302d8U,
+/*0447*/ 0x002002d9U,
+/*0448*/ 0x000302daU,
+/*0449*/ 0x002002dbU,
+/*044a*/ 0x000302dcU,
+/*044b*/ 0x002002ddU,
+/*044c*/ 0x000302deU,
+/*044d*/ 0x002002dfU,
+/*044e*/ 0x000302e0U,
+/*044f*/ 0x080302e0U,
+/*0450*/ 0x100202e0U,
+/*0451*/ 0x180202e0U,
+/*0452*/ 0x002002e1U,
+/*0453*/ 0x002002e2U,
+/*0454*/ 0x002002e3U,
+/*0455*/ 0x002002e4U,
+/*0456*/ 0x000402e5U,
+/*0457*/ 0x001e02e6U,
+/*0458*/ 0x001e02e7U,
+/*0459*/ 0x001e02e8U,
+/*045a*/ 0x001e02e9U,
+/*045b*/ 0x001e02eaU,
+/*045c*/ 0x001e02ebU,
+/*045d*/ 0x001e02ecU,
+/*045e*/ 0x001e02edU,
+/*045f*/ 0x000402eeU,
+/*0460*/ 0xffffffffU,
+/*0461*/ 0xffffffffU,
+/*0462*/ 0xffffffffU,
+/*0463*/ 0xffffffffU,
+/*0464*/ 0x080402eeU,
+/*0465*/ 0x100102eeU,
+/*0466*/ 0x180802eeU,
+/*0467*/ 0x000402efU,
+/*0468*/ 0x080102efU,
+/*0469*/ 0x100802efU,
+/*046a*/ 0x180402efU,
+/*046b*/ 0x000102f0U,
+/*046c*/ 0x080802f0U,
+/*046d*/ 0x100402f0U,
+/*046e*/ 0x180102f0U,
+/*046f*/ 0x000802f1U,
+/*0470*/ 0x080402f1U,
+/*0471*/ 0x100102f1U,
+/*0472*/ 0x180802f1U,
+/*0473*/ 0x000402f2U,
+/*0474*/ 0x080102f2U,
+/*0475*/ 0x100802f2U,
+/*0476*/ 0x180402f2U,
+/*0477*/ 0x000102f3U,
+/*0478*/ 0x080802f3U,
+/*0479*/ 0x100402f3U,
+/*047a*/ 0x180102f3U,
+/*047b*/ 0x000802f4U,
+/*047c*/ 0x080802f4U,
+/*047d*/ 0x100102f4U,
+/*047e*/ 0x180502f4U,
+/*047f*/ 0xffffffffU,
+/*0480*/ 0xffffffffU,
+/*0481*/ 0xffffffffU,
+/*0482*/ 0xffffffffU,
+/*0483*/ 0xffffffffU,
+/*0484*/ 0xffffffffU,
+/*0485*/ 0xffffffffU,
+/*0486*/ 0xffffffffU,
+/*0487*/ 0xffffffffU,
+/*0488*/ 0xffffffffU,
+/*0489*/ 0xffffffffU,
+/*048a*/ 0xffffffffU,
+/*048b*/ 0xffffffffU,
+/*048c*/ 0xffffffffU,
+/*048d*/ 0xffffffffU,
+/*048e*/ 0xffffffffU,
+/*048f*/ 0xffffffffU,
+/*0490*/ 0xffffffffU,
+/*0491*/ 0xffffffffU,
+/*0492*/ 0xffffffffU,
+/*0493*/ 0xffffffffU,
+/*0494*/ 0xffffffffU,
+	 },
+	{
+/*0000*/ 0x00200800U,
+/*0001*/ 0x00040801U,
+/*0002*/ 0x080b0801U,
+/*0003*/ 0x000a0802U,
+/*0004*/ 0x10020802U,
+/*0005*/ 0x18010802U,
+/*0006*/ 0x00060803U,
+/*0007*/ 0x08060803U,
+/*0008*/ 0x10060803U,
+/*0009*/ 0x18060803U,
+/*000a*/ 0x00060804U,
+/*000b*/ 0x08060804U,
+/*000c*/ 0x10050804U,
+/*000d*/ 0x18060804U,
+/*000e*/ 0x00060805U,
+/*000f*/ 0x08040805U,
+/*0010*/ 0x10030805U,
+/*0011*/ 0x00180806U,
+/*0012*/ 0x18030806U,
+/*0013*/ 0x00180807U,
+/*0014*/ 0x18020807U,
+/*0015*/ 0x0801085eU,
+/*0016*/ 0x00020808U,
+/*0017*/ 0x08010808U,
+/*0018*/ 0x10010808U,
+/*0019*/ 0x18020808U,
+/*001a*/ 0x00050809U,
+/*001b*/ 0x08050809U,
+/*001c*/ 0x10040809U,
+/*001d*/ 0xffffffffU,
+/*001e*/ 0x18040809U,
+/*001f*/ 0x0002080aU,
+/*0020*/ 0x0805080aU,
+/*0021*/ 0x1009080aU,
+/*0022*/ 0x0001080bU,
+/*0023*/ 0x0020080cU,
+/*0024*/ 0x001c080dU,
+/*0025*/ 0x0001080eU,
+/*0026*/ 0x0807080eU,
+/*0027*/ 0x1009080eU,
+/*0028*/ 0x000a080fU,
+/*0029*/ 0x1005080fU,
+/*002a*/ 0x1801080fU,
+/*002b*/ 0x10010810U,
+/*002c*/ 0x18020810U,
+/*002d*/ 0x00090810U,
+/*002e*/ 0x00090811U,
+/*002f*/ 0x10020811U,
+/*0030*/ 0x00200812U,
+/*0031*/ 0x00010813U,
+/*0032*/ 0x08020813U,
+/*0033*/ 0x00200814U,
+/*0034*/ 0x00200815U,
+/*0035*/ 0x00200816U,
+/*0036*/ 0x00200817U,
+/*0037*/ 0xffffffffU,
+/*0038*/ 0xffffffffU,
+/*0039*/ 0xffffffffU,
+/*003a*/ 0xffffffffU,
+/*003b*/ 0x00030818U,
+/*003c*/ 0x08010818U,
+/*003d*/ 0x10040818U,
+/*003e*/ 0x18030818U,
+/*003f*/ 0x00040819U,
+/*0040*/ 0x08040819U,
+/*0041*/ 0x10040819U,
+/*0042*/ 0x18040819U,
+/*0043*/ 0x0001081aU,
+/*0044*/ 0x0801081aU,
+/*0045*/ 0x1006081aU,
+/*0046*/ 0x1804081aU,
+/*0047*/ 0x0008081bU,
+/*0048*/ 0x0806081bU,
+/*0049*/ 0x1004081bU,
+/*004a*/ 0x1806081bU,
+/*004b*/ 0x0004081cU,
+/*004c*/ 0x0802081cU,
+/*004d*/ 0x1005081cU,
+/*004e*/ 0x1808081cU,
+/*004f*/ 0xffffffffU,
+/*0050*/ 0x0006081dU,
+/*0051*/ 0x0803081dU,
+/*0052*/ 0x100b081dU,
+/*0053*/ 0x0004081eU,
+/*0054*/ 0x0804081eU,
+/*0055*/ 0x1004081eU,
+/*0056*/ 0x1801081eU,
+/*0057*/ 0xffffffffU,
+/*0058*/ 0x0009081fU,
+/*0059*/ 0x00200820U,
+/*005a*/ 0x00200821U,
+/*005b*/ 0x00200822U,
+/*005c*/ 0x00200823U,
+/*005d*/ 0x00100824U,
+/*005e*/ 0xffffffffU,
+/*005f*/ 0x10010824U,
+/*0060*/ 0x18060824U,
+/*0061*/ 0x00080825U,
+/*0062*/ 0x00200826U,
+/*0063*/ 0x00100827U,
+/*0064*/ 0x100b0827U,
+/*0065*/ 0x00070828U,
+/*0066*/ 0x08070828U,
+/*0067*/ 0x10090828U,
+/*0068*/ 0x00090829U,
+/*0069*/ 0x100b0829U,
+/*006a*/ 0x0007082aU,
+/*006b*/ 0x0808082aU,
+/*006c*/ 0x1009082aU,
+/*006d*/ 0x0003082bU,
+/*006e*/ 0x080a082bU,
+/*006f*/ 0x000a082cU,
+/*0070*/ 0x0011082dU,
+/*0071*/ 0x000a082eU,
+/*0072*/ 0x100a082eU,
+/*0073*/ 0x0010082fU,
+/*0074*/ 0x100e082fU,
+/*0075*/ 0x000e0830U,
+/*0076*/ 0x00120831U,
+/*0077*/ 0x000a0832U,
+/*0078*/ 0x100a0832U,
+/*0079*/ 0x00020833U,
+/*007a*/ 0x00200834U,
+/*007b*/ 0x000b0835U,
+/*007c*/ 0x100b0835U,
+/*007d*/ 0x00200836U,
+/*007e*/ 0x00130837U,
+/*007f*/ 0x00200838U,
+/*0080*/ 0x00200839U,
+/*0081*/ 0x0008083aU,
+/*0082*/ 0x0801083aU,
+/*0083*/ 0x1001083aU,
+/*0084*/ 0x1801083aU,
+/*0085*/ 0x0008083bU,
+/*0086*/ 0x080c083bU,
+/*0087*/ 0x000c083cU,
+/*0088*/ 0x100c083cU,
+/*0089*/ 0x000c083dU,
+/*008a*/ 0x100c083dU,
+/*008b*/ 0x000c083eU,
+/*008c*/ 0x100c083eU,
+/*008d*/ 0x000c083fU,
+/*008e*/ 0x100c083fU,
+/*008f*/ 0x000c0840U,
+/*0090*/ 0x100c0840U,
+/*0091*/ 0x000b0841U,
+/*0092*/ 0x10090841U,
+/*0093*/ 0x00010842U,
+/*0094*/ 0x000b0843U,
+/*0095*/ 0x100b0843U,
+/*0096*/ 0x000b0844U,
+/*0097*/ 0x100b0844U,
+/*0098*/ 0x000b0845U,
+/*0099*/ 0x100b0845U,
+/*009a*/ 0x000b0846U,
+/*009b*/ 0x100b0846U,
+/*009c*/ 0x000b0847U,
+/*009d*/ 0x100a0847U,
+/*009e*/ 0x00020848U,
+/*009f*/ 0x080a0848U,
+/*00a0*/ 0x000a0849U,
+/*00a1*/ 0x100a0849U,
+/*00a2*/ 0x000a084aU,
+/*00a3*/ 0x100a084aU,
+/*00a4*/ 0x000a084bU,
+/*00a5*/ 0x100a084bU,
+/*00a6*/ 0x000a084cU,
+/*00a7*/ 0x100a084cU,
+/*00a8*/ 0x000a084dU,
+/*00a9*/ 0x100a084dU,
+/*00aa*/ 0x000a084eU,
+/*00ab*/ 0x100a084eU,
+/*00ac*/ 0x000a084fU,
+/*00ad*/ 0x100a084fU,
+/*00ae*/ 0x000a0850U,
+/*00af*/ 0x100a0850U,
+/*00b0*/ 0x000a0851U,
+/*00b1*/ 0x100a0851U,
+/*00b2*/ 0x000a0852U,
+/*00b3*/ 0x100a0852U,
+/*00b4*/ 0x000a0853U,
+/*00b5*/ 0x100a0853U,
+/*00b6*/ 0x000a0854U,
+/*00b7*/ 0x100a0854U,
+/*00b8*/ 0x000a0855U,
+/*00b9*/ 0x100a0855U,
+/*00ba*/ 0x000a0856U,
+/*00bb*/ 0x10040856U,
+/*00bc*/ 0x18030856U,
+/*00bd*/ 0x000a0857U,
+/*00be*/ 0x100a0857U,
+/*00bf*/ 0x00010858U,
+/*00c0*/ 0x080a0858U,
+/*00c1*/ 0x18040858U,
+/*00c2*/ 0x000b0859U,
+/*00c3*/ 0x100a0859U,
+/*00c4*/ 0x0003085aU,
+/*00c5*/ 0x0008085bU,
+/*00c6*/ 0x0808085bU,
+/*00c7*/ 0x1008085bU,
+/*00c8*/ 0x1808085bU,
+/*00c9*/ 0x0008085cU,
+/*00ca*/ 0x0808085cU,
+/*00cb*/ 0x1008085cU,
+/*00cc*/ 0x1801085cU,
+/*00cd*/ 0x0008085dU,
+/*00ce*/ 0x0808085dU,
+/*00cf*/ 0x1002085dU,
+/*00d0*/ 0x1802085dU,
+/*00d1*/ 0x0005085eU,
+/*00d2*/ 0x1005085eU,
+/*00d3*/ 0x1805085eU,
+/*00d4*/ 0x0004085fU,
+/*00d5*/ 0x080b085fU,
+/*00d6*/ 0x1806085fU,
+/*00d7*/ 0x00080860U,
+/*00d8*/ 0x08080860U,
+/*00d9*/ 0x10040860U,
+/*00da*/ 0x18040860U,
+/*00db*/ 0x00060861U,
+/*00dc*/ 0x08040861U,
+/*00dd*/ 0x10050861U,
+/*00de*/ 0x000a0862U,
+/*00df*/ 0x100a0862U,
+/*00e0*/ 0x00080863U,
+/*00e1*/ 0x08010863U,
+/*00e2*/ 0x10040863U,
+/*00e3*/ 0x00020864U,
+/*00e4*/ 0x08030864U,
+/*00e5*/ 0x00050a00U,
+/*00e6*/ 0x08050a00U,
+/*00e7*/ 0x10050a00U,
+/*00e8*/ 0x18050a00U,
+/*00e9*/ 0x00050a01U,
+/*00ea*/ 0x08050a01U,
+/*00eb*/ 0x100b0a01U,
+/*00ec*/ 0x00010a02U,
+/*00ed*/ 0x08030a02U,
+/*00ee*/ 0x00200a03U,
+/*00ef*/ 0x00100a04U,
+/*00f0*/ 0x10040a04U,
+/*00f1*/ 0x000b0a05U,
+/*00f2*/ 0x10070a05U,
+/*00f3*/ 0x00090a06U,
+/*00f4*/ 0x10030a06U,
+/*00f5*/ 0x18030a06U,
+/*00f6*/ 0x00010a07U,
+/*00f7*/ 0x08010a07U,
+/*00f8*/ 0x10070a07U,
+/*00f9*/ 0x18070a07U,
+/*00fa*/ 0x00050a08U,
+/*00fb*/ 0x08010a08U,
+/*00fc*/ 0x10020a08U,
+/*00fd*/ 0x18030a08U,
+/*00fe*/ 0x00010a09U,
+/*00ff*/ 0x080f0a09U,
+/*0100*/ 0x00200a0aU,
+/*0101*/ 0x00200a0bU,
+/*0102*/ 0x000b0a0cU,
+/*0103*/ 0x100b0a0cU,
+/*0104*/ 0x000b0a0dU,
+/*0105*/ 0x00180a0eU,
+/*0106*/ 0x00180a0fU,
+/*0107*/ 0xffffffffU,
+/*0108*/ 0xffffffffU,
+/*0109*/ 0xffffffffU,
+/*010a*/ 0xffffffffU,
+/*010b*/ 0xffffffffU,
+/*010c*/ 0x18020a0fU,
+/*010d*/ 0x00020a10U,
+/*010e*/ 0x08040a10U,
+/*010f*/ 0x10040a10U,
+/*0110*/ 0x18010a10U,
+/*0111*/ 0x00010a11U,
+/*0112*/ 0x08010a11U,
+/*0113*/ 0x10030a11U,
+/*0114*/ 0x00200a12U,
+/*0115*/ 0x00200a13U,
+/*0116*/ 0xffffffffU,
+/*0117*/ 0x00140a14U,
+/*0118*/ 0x00140a15U,
+/*0119*/ 0x00140a16U,
+/*011a*/ 0x00140a17U,
+/*011b*/ 0x00140a18U,
+/*011c*/ 0x00140a19U,
+/*011d*/ 0x00140a1aU,
+/*011e*/ 0x00140a1bU,
+/*011f*/ 0x001e0a1cU,
+/*0120*/ 0x000a0a1dU,
+/*0121*/ 0x10060a1dU,
+/*0122*/ 0x18060a1dU,
+/*0123*/ 0x00060a1eU,
+/*0124*/ 0x08060a1eU,
+/*0125*/ 0x10060a1eU,
+/*0126*/ 0x00080a1fU,
+/*0127*/ 0x080b0a1fU,
+/*0128*/ 0x000b0a20U,
+/*0129*/ 0x100b0a20U,
+/*012a*/ 0x000b0a21U,
+/*012b*/ 0x100b0a21U,
+/*012c*/ 0x000b0a22U,
+/*012d*/ 0x10040a22U,
+/*012e*/ 0x000b0a23U,
+/*012f*/ 0x10060a23U,
+/*0130*/ 0x18080a23U,
+/*0131*/ 0x00080a24U,
+/*0132*/ 0x08040a24U,
+/*0133*/ 0x00020b80U,
+/*0134*/ 0x00010b81U,
+/*0135*/ 0x08010b81U,
+/*0136*/ 0x10020b81U,
+/*0137*/ 0x18050b81U,
+/*0138*/ 0x00050b82U,
+/*0139*/ 0x08050b82U,
+/*013a*/ 0x10050b82U,
+/*013b*/ 0x000b0b83U,
+/*013c*/ 0x10050b83U,
+/*013d*/ 0x18010b83U,
+/*013e*/ 0x00010b84U,
+/*013f*/ 0x08010b84U,
+/*0140*/ 0x10010b84U,
+/*0141*/ 0x18010b84U,
+/*0142*/ 0x00040b85U,
+/*0143*/ 0x080b0b85U,
+/*0144*/ 0x000b0b86U,
+/*0145*/ 0x100b0b86U,
+/*0146*/ 0x00040b87U,
+/*0147*/ 0x080b0b87U,
+/*0148*/ 0x18040b87U,
+/*0149*/ 0x00010b88U,
+/*014a*/ 0x08010b88U,
+/*014b*/ 0x10010b88U,
+/*014c*/ 0x00200b89U,
+/*014d*/ 0x00200b8aU,
+/*014e*/ 0x00080b8bU,
+/*014f*/ 0x080a0b8bU,
+/*0150*/ 0x18050b8bU,
+/*0151*/ 0x000b0b8cU,
+/*0152*/ 0x10030b8cU,
+/*0153*/ 0x18030b8cU,
+/*0154*/ 0x00010b8dU,
+/*0155*/ 0x08020b8dU,
+/*0156*/ 0x10010b8dU,
+/*0157*/ 0x18010b8dU,
+/*0158*/ 0x00010b8eU,
+/*0159*/ 0xffffffffU,
+/*015a*/ 0x08010b8eU,
+/*015b*/ 0x18040b8eU,
+/*015c*/ 0x00040b8fU,
+/*015d*/ 0x08040b8fU,
+/*015e*/ 0x10040b8fU,
+/*015f*/ 0x18010b8fU,
+/*0160*/ 0x00010b90U,
+/*0161*/ 0x08010b90U,
+/*0162*/ 0x00200b91U,
+/*0163*/ 0x00200b92U,
+/*0164*/ 0x00200b93U,
+/*0165*/ 0x00200b94U,
+/*0166*/ 0xffffffffU,
+/*0167*/ 0x10010b8eU,
+/*0168*/ 0x000d0b96U,
+/*0169*/ 0x100d0b96U,
+/*016a*/ 0x000d0b97U,
+/*016b*/ 0x00050b98U,
+/*016c*/ 0x00010b99U,
+/*016d*/ 0x080e0b99U,
+/*016e*/ 0x000e0b9aU,
+/*016f*/ 0x100e0b9aU,
+/*0170*/ 0x000e0b9bU,
+/*0171*/ 0x100e0b9bU,
+/*0172*/ 0x00040b9cU,
+/*0173*/ 0x08040b9cU,
+/*0174*/ 0x10040b9cU,
+/*0175*/ 0x18040b9cU,
+/*0176*/ 0x00040b9dU,
+/*0177*/ 0x080b0b9dU,
+/*0178*/ 0x000b0b9eU,
+/*0179*/ 0x100b0b9eU,
+/*017a*/ 0x000b0b9fU,
+/*017b*/ 0x00040ba0U,
+/*017c*/ 0x08040ba0U,
+/*017d*/ 0x10040ba0U,
+/*017e*/ 0x18040ba0U,
+/*017f*/ 0x000d0ba1U,
+/*0180*/ 0x100d0ba1U,
+/*0181*/ 0x000d0ba2U,
+/*0182*/ 0x10100ba2U,
+/*0183*/ 0x00080b95U,
+/*0184*/ 0x08080b95U,
+/*0185*/ 0x00100ba3U,
+/*0186*/ 0x10100ba3U,
+/*0187*/ 0x00100ba4U,
+/*0188*/ 0x10100ba4U,
+/*0189*/ 0x00100ba5U,
+/*018a*/ 0x10030ba5U,
+/*018b*/ 0x18040ba5U,
+/*018c*/ 0x00010ba6U,
+/*018d*/ 0x08080ba6U,
+/*018e*/ 0x10010ba6U,
+/*018f*/ 0x000a0ba7U,
+/*0190*/ 0x10010ba7U,
+/*0191*/ 0x00140ba8U,
+/*0192*/ 0x000b0ba9U,
+/*0193*/ 0x100c0ba9U,
+/*0194*/ 0x00120baaU,
+/*0195*/ 0x00140babU,
+/*0196*/ 0x00120bacU,
+/*0197*/ 0x00110badU,
+/*0198*/ 0x00110baeU,
+/*0199*/ 0x00120bafU,
+/*019a*/ 0x00120bb0U,
+/*019b*/ 0x00120bb1U,
+/*019c*/ 0x00120bb2U,
+/*019d*/ 0x00120bb3U,
+/*019e*/ 0x00120bb4U,
+/*019f*/ 0x00120bb5U,
+/*01a0*/ 0x00120bb6U,
+/*01a1*/ 0x00120bb7U,
+/*01a2*/ 0x00120bb8U,
+/*01a3*/ 0x000e0bb9U,
+/*01a4*/ 0x100d0bb9U,
+/*01a5*/ 0x00200bbaU,
+/*01a6*/ 0x00170bbbU,
+/*01a7*/ 0x000d0bbcU,
+/*01a8*/ 0x10010bbcU,
+/*01a9*/ 0x18010bbcU,
+/*01aa*/ 0x00200bbdU,
+/*01ab*/ 0x00080bbeU,
+/*01ac*/ 0x08030bbeU,
+/*01ad*/ 0x10030bbeU,
+/*01ae*/ 0x00180bbfU,
+/*01af*/ 0x00180bc0U,
+/*01b0*/ 0x18070bc0U,
+/*01b1*/ 0x00070bc1U,
+/*01b2*/ 0x08080bc1U,
+/*01b3*/ 0x10080bc1U,
+/*01b4*/ 0x18080bc1U,
+/*01b5*/ 0x00010bc2U,
+/*01b6*/ 0x08010bc2U,
+/*01b7*/ 0x00200bc3U,
+/*01b8*/ 0x00070bc4U,
+/*01b9*/ 0x08140bc4U,
+/*01ba*/ 0x00140bc5U,
+/*01bb*/ 0x00190bc6U,
+/*01bc*/ 0x00170bc7U,
+/*01bd*/ 0x00110bc8U,
+/*01be*/ 0x00110bc9U,
+/*01bf*/ 0x00100bcaU,
+/*01c0*/ 0x10010bcaU,
+/*01c1*/ 0x18010bcaU,
+/*01c2*/ 0x00020bcbU,
+/*01c3*/ 0x08040bcbU,
+/*01c4*/ 0x10090bcbU,
+/*01c5*/ 0x00070bccU,
+/*01c6*/ 0x08040bccU,
+/*01c7*/ 0x00200bcdU,
+/*01c8*/ 0x00010bceU,
+/*01c9*/ 0x08020bceU,
+/*01ca*/ 0x10060bceU,
+/*01cb*/ 0x00100bcfU,
+/*01cc*/ 0x10010bcfU,
+/*01cd*/ 0x00200bd0U,
+/*01ce*/ 0x00080bd1U,
+/*01cf*/ 0x08010bd1U,
+/*01d0*/ 0x10050bd1U,
+/*01d1*/ 0x18030bd1U,
+/*01d2*/ 0x00020bd2U,
+/*01d3*/ 0xffffffffU,
+/*01d4*/ 0x00200bd3U,
+/*01d5*/ 0x000b0bd4U,
+/*01d6*/ 0xffffffffU,
+/*01d7*/ 0x10030bd4U,
+/*01d8*/ 0x18080bd4U,
+/*01d9*/ 0x00020bd5U,
+/*01da*/ 0x080c0bd5U,
+/*01db*/ 0x18040bd5U,
+/*01dc*/ 0x00010bd6U,
+/*01dd*/ 0x08050bd6U,
+/*01de*/ 0x00010200U,
+/*01df*/ 0x08040200U,
+/*01e0*/ 0x10100200U,
+/*01e1*/ 0x00010201U,
+/*01e2*/ 0x08010201U,
+/*01e3*/ 0x10010201U,
+/*01e4*/ 0x18010201U,
+/*01e5*/ 0x00100202U,
+/*01e6*/ 0x10080202U,
+/*01e7*/ 0x18010202U,
+/*01e8*/ 0x00200203U,
+/*01e9*/ 0x00200204U,
+/*01ea*/ 0x00200205U,
+/*01eb*/ 0x00200206U,
+/*01ec*/ 0x00020207U,
+/*01ed*/ 0x08010207U,
+/*01ee*/ 0x10010207U,
+/*01ef*/ 0x00200208U,
+/*01f0*/ 0x00140209U,
+/*01f1*/ 0x0020020aU,
+/*01f2*/ 0x0014020bU,
+/*01f3*/ 0x0020020cU,
+/*01f4*/ 0x0014020dU,
+/*01f5*/ 0x0014020eU,
+/*01f6*/ 0x0020020fU,
+/*01f7*/ 0x00200210U,
+/*01f8*/ 0x00200211U,
+/*01f9*/ 0x00200212U,
+/*01fa*/ 0x00140213U,
+/*01fb*/ 0x00200214U,
+/*01fc*/ 0x00200215U,
+/*01fd*/ 0x00200216U,
+/*01fe*/ 0x00200217U,
+/*01ff*/ 0x00140218U,
+/*0200*/ 0x00200219U,
+/*0201*/ 0x0020021aU,
+/*0202*/ 0x0020021bU,
+/*0203*/ 0x0020021cU,
+/*0204*/ 0x0009021dU,
+/*0205*/ 0x1001021dU,
+/*0206*/ 0x0020021eU,
+/*0207*/ 0x0005021fU,
+/*0208*/ 0x0801021fU,
+/*0209*/ 0x1008021fU,
+/*020a*/ 0x1808021fU,
+/*020b*/ 0x001e0220U,
+/*020c*/ 0x001e0221U,
+/*020d*/ 0x001e0222U,
+/*020e*/ 0x001e0223U,
+/*020f*/ 0x001e0224U,
+/*0210*/ 0x001e0225U,
+/*0211*/ 0x001e0226U,
+/*0212*/ 0x001e0227U,
+/*0213*/ 0x001e0228U,
+/*0214*/ 0x001e0229U,
+/*0215*/ 0x001e022aU,
+/*0216*/ 0x001e022bU,
+/*0217*/ 0x001e022cU,
+/*0218*/ 0x001e022dU,
+/*0219*/ 0x001e022eU,
+/*021a*/ 0x001e022fU,
+/*021b*/ 0x00010230U,
+/*021c*/ 0x08010230U,
+/*021d*/ 0x10010230U,
+/*021e*/ 0x18040230U,
+/*021f*/ 0x00080231U,
+/*0220*/ 0x08080231U,
+/*0221*/ 0x10080231U,
+/*0222*/ 0x18040231U,
+/*0223*/ 0x00070232U,
+/*0224*/ 0x08060232U,
+/*0225*/ 0x10070232U,
+/*0226*/ 0x18070232U,
+/*0227*/ 0x00060233U,
+/*0228*/ 0x08070233U,
+/*0229*/ 0x10070233U,
+/*022a*/ 0x18060233U,
+/*022b*/ 0x00070234U,
+/*022c*/ 0x08020234U,
+/*022d*/ 0x10010234U,
+/*022e*/ 0x18010234U,
+/*022f*/ 0x000a0235U,
+/*0230*/ 0x00140236U,
+/*0231*/ 0x000a0237U,
+/*0232*/ 0x00140238U,
+/*0233*/ 0x000a0239U,
+/*0234*/ 0x0014023aU,
+/*0235*/ 0xffffffffU,
+/*0236*/ 0xffffffffU,
+/*0237*/ 0x0005023bU,
+/*0238*/ 0x0001023cU,
+/*0239*/ 0x1001023cU,
+/*023a*/ 0x1801023cU,
+/*023b*/ 0x0001023dU,
+/*023c*/ 0x0801023dU,
+/*023d*/ 0x1001023dU,
+/*023e*/ 0x1801023dU,
+/*023f*/ 0x0002023eU,
+/*0240*/ 0x0802023eU,
+/*0241*/ 0x1002023eU,
+/*0242*/ 0x1802023eU,
+/*0243*/ 0x0002023fU,
+/*0244*/ 0x0803023fU,
+/*0245*/ 0x1001023fU,
+/*0246*/ 0x1801023fU,
+/*0247*/ 0x00010240U,
+/*0248*/ 0x08010240U,
+/*0249*/ 0x10010240U,
+/*024a*/ 0x18020240U,
+/*024b*/ 0x00010241U,
+/*024c*/ 0x08010241U,
+/*024d*/ 0x10010241U,
+/*024e*/ 0x18020241U,
+/*024f*/ 0x00010242U,
+/*0250*/ 0x08010242U,
+/*0251*/ 0x10010242U,
+/*0252*/ 0x18020242U,
+/*0253*/ 0x00010243U,
+/*0254*/ 0x08010243U,
+/*0255*/ 0x10010243U,
+/*0256*/ 0x18020243U,
+/*0257*/ 0xffffffffU,
+/*0258*/ 0x00010244U,
+/*0259*/ 0x08010244U,
+/*025a*/ 0x10010244U,
+/*025b*/ 0x18010244U,
+/*025c*/ 0x00010245U,
+/*025d*/ 0x08010245U,
+/*025e*/ 0x10010245U,
+/*025f*/ 0x18010245U,
+/*0260*/ 0x00040246U,
+/*0261*/ 0x08040246U,
+/*0262*/ 0x10040246U,
+/*0263*/ 0x18010246U,
+/*0264*/ 0x00020247U,
+/*0265*/ 0x08060247U,
+/*0266*/ 0x10060247U,
+/*0267*/ 0x18020247U,
+/*0268*/ 0x00020248U,
+/*0269*/ 0x08020248U,
+/*026a*/ 0xffffffffU,
+/*026b*/ 0x10100248U,
+/*026c*/ 0x00010249U,
+/*026d*/ 0x08010249U,
+/*026e*/ 0x10010249U,
+/*026f*/ 0x18040249U,
+/*0270*/ 0x0001024aU,
+/*0271*/ 0x0804024aU,
+/*0272*/ 0x1003024aU,
+/*0273*/ 0x1808024aU,
+/*0274*/ 0x000a024bU,
+/*0275*/ 0x100a024bU,
+/*0276*/ 0x000a024cU,
+/*0277*/ 0xffffffffU,
+/*0278*/ 0x0020024dU,
+/*0279*/ 0x0020024eU,
+/*027a*/ 0x0005024fU,
+/*027b*/ 0x1801023aU,
+/*027c*/ 0x0805023cU,
+/*027d*/ 0x0808024fU,
+/*027e*/ 0x1001024fU,
+/*027f*/ 0x1808024fU,
+/*0280*/ 0x00010250U,
+/*0281*/ 0x08080250U,
+/*0282*/ 0x10010250U,
+/*0283*/ 0x18040250U,
+/*0284*/ 0x00040251U,
+/*0285*/ 0x08040251U,
+/*0286*/ 0x10040251U,
+/*0287*/ 0x18040251U,
+/*0288*/ 0x00040252U,
+/*0289*/ 0x08040252U,
+/*028a*/ 0x10040252U,
+/*028b*/ 0x18040252U,
+/*028c*/ 0x00040253U,
+/*028d*/ 0x08010253U,
+/*028e*/ 0x10040253U,
+/*028f*/ 0x18040253U,
+/*0290*/ 0x00040254U,
+/*0291*/ 0x08040254U,
+/*0292*/ 0x10040254U,
+/*0293*/ 0x18040254U,
+/*0294*/ 0x00060255U,
+/*0295*/ 0x08060255U,
+/*0296*/ 0x10060255U,
+/*0297*/ 0x18060255U,
+/*0298*/ 0x00060256U,
+/*0299*/ 0x08060256U,
+/*029a*/ 0x10040256U,
+/*029b*/ 0x18010256U,
+/*029c*/ 0x00010257U,
+/*029d*/ 0x08020257U,
+/*029e*/ 0x00200258U,
+/*029f*/ 0x00200259U,
+/*02a0*/ 0x0020025aU,
+/*02a1*/ 0x0020025bU,
+/*02a2*/ 0x0020025cU,
+/*02a3*/ 0x0020025dU,
+/*02a4*/ 0x0020025eU,
+/*02a5*/ 0x0020025fU,
+/*02a6*/ 0x00040260U,
+/*02a7*/ 0x08040260U,
+/*02a8*/ 0x10010260U,
+/*02a9*/ 0x18010260U,
+/*02aa*/ 0x00010261U,
+/*02ab*/ 0x08010261U,
+/*02ac*/ 0x10010261U,
+/*02ad*/ 0x18010261U,
+/*02ae*/ 0x00010262U,
+/*02af*/ 0x08010262U,
+/*02b0*/ 0x10010262U,
+/*02b1*/ 0x18040262U,
+/*02b2*/ 0x00040263U,
+/*02b3*/ 0x080a0263U,
+/*02b4*/ 0x00200264U,
+/*02b5*/ 0x00040265U,
+/*02b6*/ 0x08080265U,
+/*02b7*/ 0x10020265U,
+/*02b8*/ 0x18020265U,
+/*02b9*/ 0x00020266U,
+/*02ba*/ 0x08020266U,
+/*02bb*/ 0x10020266U,
+/*02bc*/ 0x18020266U,
+/*02bd*/ 0xffffffffU,
+/*02be*/ 0xffffffffU,
+/*02bf*/ 0x00200267U,
+/*02c0*/ 0x00030268U,
+/*02c1*/ 0x08100268U,
+/*02c2*/ 0x00100269U,
+/*02c3*/ 0x10040269U,
+/*02c4*/ 0x18040269U,
+/*02c5*/ 0x0005026aU,
+/*02c6*/ 0x0805026aU,
+/*02c7*/ 0xffffffffU,
+/*02c8*/ 0xffffffffU,
+/*02c9*/ 0xffffffffU,
+/*02ca*/ 0xffffffffU,
+/*02cb*/ 0x1001026aU,
+/*02cc*/ 0x1801026aU,
+/*02cd*/ 0x0008026bU,
+/*02ce*/ 0x0808026bU,
+/*02cf*/ 0x1008026bU,
+/*02d0*/ 0x1808026bU,
+/*02d1*/ 0x0008026cU,
+/*02d2*/ 0x0808026cU,
+/*02d3*/ 0x1008026cU,
+/*02d4*/ 0x1808026cU,
+/*02d5*/ 0x0008026dU,
+/*02d6*/ 0x0808026dU,
+/*02d7*/ 0x1008026dU,
+/*02d8*/ 0x1808026dU,
+/*02d9*/ 0x0008026eU,
+/*02da*/ 0x0808026eU,
+/*02db*/ 0x1003026eU,
+/*02dc*/ 0x1803026eU,
+/*02dd*/ 0x0003026fU,
+/*02de*/ 0xffffffffU,
+/*02df*/ 0x0801026fU,
+/*02e0*/ 0x1002026fU,
+/*02e1*/ 0x1801026fU,
+/*02e2*/ 0x00040270U,
+/*02e3*/ 0x08020270U,
+/*02e4*/ 0x10010270U,
+/*02e5*/ 0x18010270U,
+/*02e6*/ 0x00010271U,
+/*02e7*/ 0x08010271U,
+/*02e8*/ 0x10040271U,
+/*02e9*/ 0x18080271U,
+/*02ea*/ 0x000a0272U,
+/*02eb*/ 0x100a0272U,
+/*02ec*/ 0x000a0273U,
+/*02ed*/ 0x100a0273U,
+/*02ee*/ 0x000a0274U,
+/*02ef*/ 0x100a0274U,
+/*02f0*/ 0x00200275U,
+/*02f1*/ 0x00200276U,
+/*02f2*/ 0x00010277U,
+/*02f3*/ 0x08020277U,
+/*02f4*/ 0x10020277U,
+/*02f5*/ 0x18020277U,
+/*02f6*/ 0xffffffffU,
+/*02f7*/ 0x00020278U,
+/*02f8*/ 0x08100278U,
+/*02f9*/ 0x18050278U,
+/*02fa*/ 0x00060279U,
+/*02fb*/ 0x08050279U,
+/*02fc*/ 0x10050279U,
+/*02fd*/ 0x000e027aU,
+/*02fe*/ 0x1005027aU,
+/*02ff*/ 0x000e027bU,
+/*0300*/ 0x1005027bU,
+/*0301*/ 0x000e027cU,
+/*0302*/ 0x1005027cU,
+/*0303*/ 0x1801027cU,
+/*0304*/ 0x0005027dU,
+/*0305*/ 0x0805027dU,
+/*0306*/ 0x100a027dU,
+/*0307*/ 0x000a027eU,
+/*0308*/ 0x1005027eU,
+/*0309*/ 0x1805027eU,
+/*030a*/ 0x000a027fU,
+/*030b*/ 0x100a027fU,
+/*030c*/ 0x00050280U,
+/*030d*/ 0x08050280U,
+/*030e*/ 0x100a0280U,
+/*030f*/ 0x000a0281U,
+/*0310*/ 0x10070281U,
+/*0311*/ 0x18070281U,
+/*0312*/ 0x00070282U,
+/*0313*/ 0x08070282U,
+/*0314*/ 0x10070282U,
+/*0315*/ 0x18070282U,
+/*0316*/ 0xffffffffU,
+/*0317*/ 0xffffffffU,
+/*0318*/ 0x00040283U,
+/*0319*/ 0x08040283U,
+/*031a*/ 0x10040283U,
+/*031b*/ 0x18040283U,
+/*031c*/ 0x00040284U,
+/*031d*/ 0xffffffffU,
+/*031e*/ 0x08080284U,
+/*031f*/ 0x10080284U,
+/*0320*/ 0x18040284U,
+/*0321*/ 0x00050285U,
+/*0322*/ 0x08080285U,
+/*0323*/ 0x10050285U,
+/*0324*/ 0x18040285U,
+/*0325*/ 0x00050286U,
+/*0326*/ 0x08080286U,
+/*0327*/ 0x10050286U,
+/*0328*/ 0x18040286U,
+/*0329*/ 0x00050287U,
+/*032a*/ 0x08080287U,
+/*032b*/ 0x10050287U,
+/*032c*/ 0x18040287U,
+/*032d*/ 0x00050288U,
+/*032e*/ 0x08070288U,
+/*032f*/ 0x10080288U,
+/*0330*/ 0x00100289U,
+/*0331*/ 0x10080289U,
+/*0332*/ 0x0010028aU,
+/*0333*/ 0x1008028aU,
+/*0334*/ 0x0010028bU,
+/*0335*/ 0x1008028bU,
+/*0336*/ 0x1808028bU,
+/*0337*/ 0x0001028cU,
+/*0338*/ 0x0801028cU,
+/*0339*/ 0x1006028cU,
+/*033a*/ 0x1806028cU,
+/*033b*/ 0x0006028dU,
+/*033c*/ 0x0801028dU,
+/*033d*/ 0x1001028dU,
+/*033e*/ 0x1803028dU,
+/*033f*/ 0x000a028eU,
+/*0340*/ 0x100a028eU,
+/*0341*/ 0x000a028fU,
+/*0342*/ 0xffffffffU,
+/*0343*/ 0x100a028fU,
+/*0344*/ 0x00040290U,
+/*0345*/ 0x08010290U,
+/*0346*/ 0x10040290U,
+/*0347*/ 0x18070290U,
+/*0348*/ 0x00070291U,
+/*0349*/ 0x08070291U,
+/*034a*/ 0x10070291U,
+/*034b*/ 0x18070291U,
+/*034c*/ 0x00070292U,
+/*034d*/ 0xffffffffU,
+/*034e*/ 0xffffffffU,
+/*034f*/ 0x08050292U,
+/*0350*/ 0x10050292U,
+/*0351*/ 0x18040292U,
+/*0352*/ 0x00040293U,
+/*0353*/ 0x08040293U,
+/*0354*/ 0xffffffffU,
+/*0355*/ 0x10010293U,
+/*0356*/ 0x18010293U,
+/*0357*/ 0x00020294U,
+/*0358*/ 0x08080294U,
+/*0359*/ 0x00200295U,
+/*035a*/ 0x00200296U,
+/*035b*/ 0x00100297U,
+/*035c*/ 0x10020297U,
+/*035d*/ 0x18020297U,
+/*035e*/ 0x00020298U,
+/*035f*/ 0xffffffffU,
+/*0360*/ 0x08010298U,
+/*0361*/ 0x10010298U,
+/*0362*/ 0x18020298U,
+/*0363*/ 0x00100299U,
+/*0364*/ 0x10100299U,
+/*0365*/ 0x0010029aU,
+/*0366*/ 0x1008029aU,
+/*0367*/ 0x1808029aU,
+/*0368*/ 0x0008029bU,
+/*0369*/ 0x0808029bU,
+/*036a*/ 0x1010029bU,
+/*036b*/ 0x0010029cU,
+/*036c*/ 0x1010029cU,
+/*036d*/ 0x0008029dU,
+/*036e*/ 0x0808029dU,
+/*036f*/ 0x1008029dU,
+/*0370*/ 0x1808029dU,
+/*0371*/ 0x0010029eU,
+/*0372*/ 0x1010029eU,
+/*0373*/ 0x0010029fU,
+/*0374*/ 0x1008029fU,
+/*0375*/ 0x1808029fU,
+/*0376*/ 0x000802a0U,
+/*0377*/ 0x080802a0U,
+/*0378*/ 0x100802a0U,
+/*0379*/ 0x001002a1U,
+/*037a*/ 0x101002a1U,
+/*037b*/ 0x001002a2U,
+/*037c*/ 0x100802a2U,
+/*037d*/ 0x180802a2U,
+/*037e*/ 0x000802a3U,
+/*037f*/ 0x080802a3U,
+/*0380*/ 0x101002a3U,
+/*0381*/ 0x001002a4U,
+/*0382*/ 0x101002a4U,
+/*0383*/ 0x000802a5U,
+/*0384*/ 0x080802a5U,
+/*0385*/ 0x100802a5U,
+/*0386*/ 0x180802a5U,
+/*0387*/ 0x001002a6U,
+/*0388*/ 0x101002a6U,
+/*0389*/ 0x001002a7U,
+/*038a*/ 0x100802a7U,
+/*038b*/ 0x180802a7U,
+/*038c*/ 0x000802a8U,
+/*038d*/ 0x080802a8U,
+/*038e*/ 0x100802a8U,
+/*038f*/ 0x001002a9U,
+/*0390*/ 0x101002a9U,
+/*0391*/ 0x001002aaU,
+/*0392*/ 0x100802aaU,
+/*0393*/ 0x180802aaU,
+/*0394*/ 0x000802abU,
+/*0395*/ 0x080802abU,
+/*0396*/ 0x101002abU,
+/*0397*/ 0x001002acU,
+/*0398*/ 0x101002acU,
+/*0399*/ 0x000802adU,
+/*039a*/ 0x080802adU,
+/*039b*/ 0x100802adU,
+/*039c*/ 0x180802adU,
+/*039d*/ 0x001002aeU,
+/*039e*/ 0x101002aeU,
+/*039f*/ 0x001002afU,
+/*03a0*/ 0x100802afU,
+/*03a1*/ 0x180802afU,
+/*03a2*/ 0x000802b0U,
+/*03a3*/ 0x080802b0U,
+/*03a4*/ 0x100802b0U,
+/*03a5*/ 0x001002b1U,
+/*03a6*/ 0x101002b1U,
+/*03a7*/ 0x001002b2U,
+/*03a8*/ 0x100802b2U,
+/*03a9*/ 0x180802b2U,
+/*03aa*/ 0x000802b3U,
+/*03ab*/ 0x080802b3U,
+/*03ac*/ 0x101002b3U,
+/*03ad*/ 0x001002b4U,
+/*03ae*/ 0x101002b4U,
+/*03af*/ 0x000802b5U,
+/*03b0*/ 0x080802b5U,
+/*03b1*/ 0x100802b5U,
+/*03b2*/ 0x180802b5U,
+/*03b3*/ 0x001002b6U,
+/*03b4*/ 0x101002b6U,
+/*03b5*/ 0x001002b7U,
+/*03b6*/ 0x100802b7U,
+/*03b7*/ 0x180802b7U,
+/*03b8*/ 0x000802b8U,
+/*03b9*/ 0x080802b8U,
+/*03ba*/ 0x100802b8U,
+/*03bb*/ 0x180202b8U,
+/*03bc*/ 0x000302b9U,
+/*03bd*/ 0x080a02b9U,
+/*03be*/ 0x000a02baU,
+/*03bf*/ 0x100a02baU,
+/*03c0*/ 0x000502bbU,
+/*03c1*/ 0x080802bbU,
+/*03c2*/ 0x100802bbU,
+/*03c3*/ 0x180802bbU,
+/*03c4*/ 0x000602bcU,
+/*03c5*/ 0x080602bcU,
+/*03c6*/ 0x001102bdU,
+/*03c7*/ 0x180802bdU,
+/*03c8*/ 0x000402beU,
+/*03c9*/ 0x080602beU,
+/*03ca*/ 0x100802beU,
+/*03cb*/ 0x180802beU,
+/*03cc*/ 0x000802bfU,
+/*03cd*/ 0x080802bfU,
+/*03ce*/ 0x100802bfU,
+/*03cf*/ 0x180802bfU,
+/*03d0*/ 0x000802c0U,
+/*03d1*/ 0x080602c0U,
+/*03d2*/ 0x100602c0U,
+/*03d3*/ 0x001102c1U,
+/*03d4*/ 0x180802c1U,
+/*03d5*/ 0x000402c2U,
+/*03d6*/ 0x080602c2U,
+/*03d7*/ 0x100802c2U,
+/*03d8*/ 0x180802c2U,
+/*03d9*/ 0x000802c3U,
+/*03da*/ 0x080802c3U,
+/*03db*/ 0x100802c3U,
+/*03dc*/ 0x180802c3U,
+/*03dd*/ 0x000802c4U,
+/*03de*/ 0x080602c4U,
+/*03df*/ 0x100602c4U,
+/*03e0*/ 0x001102c5U,
+/*03e1*/ 0x180802c5U,
+/*03e2*/ 0x000402c6U,
+/*03e3*/ 0x080602c6U,
+/*03e4*/ 0x100802c6U,
+/*03e5*/ 0x180802c6U,
+/*03e6*/ 0x000802c7U,
+/*03e7*/ 0x080802c7U,
+/*03e8*/ 0x100402c7U,
+/*03e9*/ 0x180402c7U,
+/*03ea*/ 0x000402c8U,
+/*03eb*/ 0x080402c8U,
+/*03ec*/ 0x100402c8U,
+/*03ed*/ 0x180402c8U,
+/*03ee*/ 0x000402c9U,
+/*03ef*/ 0x080402c9U,
+/*03f0*/ 0x100402c9U,
+/*03f1*/ 0x180402c9U,
+/*03f2*/ 0x000402caU,
+/*03f3*/ 0x080402caU,
+/*03f4*/ 0x100402caU,
+/*03f5*/ 0x180402caU,
+/*03f6*/ 0x000402cbU,
+/*03f7*/ 0x080402cbU,
+/*03f8*/ 0x100402cbU,
+/*03f9*/ 0x180402cbU,
+/*03fa*/ 0x000402ccU,
+/*03fb*/ 0x080402ccU,
+/*03fc*/ 0x001702cdU,
+/*03fd*/ 0x001602ceU,
+/*03fe*/ 0x001702cfU,
+/*03ff*/ 0x002002d0U,
+/*0400*/ 0x002002d1U,
+/*0401*/ 0x002002d2U,
+/*0402*/ 0x002002d3U,
+/*0403*/ 0x002002d4U,
+/*0404*/ 0x002002d5U,
+/*0405*/ 0x002002d6U,
+/*0406*/ 0x002002d7U,
+/*0407*/ 0x002002d8U,
+/*0408*/ 0x000202d9U,
+/*0409*/ 0x080502d9U,
+/*040a*/ 0x100502d9U,
+/*040b*/ 0x180102d9U,
+/*040c*/ 0x000502daU,
+/*040d*/ 0x080502daU,
+/*040e*/ 0x100502daU,
+/*040f*/ 0x180502daU,
+/*0410*/ 0x000502dbU,
+/*0411*/ 0x080502dbU,
+/*0412*/ 0x100502dbU,
+/*0413*/ 0x180502dbU,
+/*0414*/ 0x000502dcU,
+/*0415*/ 0x080502dcU,
+/*0416*/ 0x100502dcU,
+/*0417*/ 0x180502dcU,
+/*0418*/ 0x000502ddU,
+/*0419*/ 0x080502ddU,
+/*041a*/ 0x100502ddU,
+/*041b*/ 0x180502ddU,
+/*041c*/ 0x000502deU,
+/*041d*/ 0x080502deU,
+/*041e*/ 0x100502deU,
+/*041f*/ 0x180502deU,
+/*0420*/ 0x000502dfU,
+/*0421*/ 0x080502dfU,
+/*0422*/ 0x100102dfU,
+/*0423*/ 0x180202dfU,
+/*0424*/ 0x000202e0U,
+/*0425*/ 0x080202e0U,
+/*0426*/ 0x100202e0U,
+/*0427*/ 0x180102e0U,
+/*0428*/ 0x000802e1U,
+/*0429*/ 0x081502e1U,
+/*042a*/ 0x002002e2U,
+/*042b*/ 0x001502e3U,
+/*042c*/ 0x002002e4U,
+/*042d*/ 0x001502e5U,
+/*042e*/ 0x002002e6U,
+/*042f*/ 0x000702e7U,
+/*0430*/ 0x080102e7U,
+/*0431*/ 0x100202e7U,
+/*0432*/ 0x180602e7U,
+/*0433*/ 0x000102e8U,
+/*0434*/ 0x080102e8U,
+/*0435*/ 0x002002e9U,
+/*0436*/ 0x000202eaU,
+/*0437*/ 0x002002ebU,
+/*0438*/ 0x002002ecU,
+/*0439*/ 0x000c02edU,
+/*043a*/ 0x100c02edU,
+/*043b*/ 0x002002eeU,
+/*043c*/ 0x000302efU,
+/*043d*/ 0x002002f0U,
+/*043e*/ 0x000302f1U,
+/*043f*/ 0x002002f2U,
+/*0440*/ 0x000302f3U,
+/*0441*/ 0x002002f4U,
+/*0442*/ 0x000302f5U,
+/*0443*/ 0x002002f6U,
+/*0444*/ 0x000302f7U,
+/*0445*/ 0x002002f8U,
+/*0446*/ 0x000302f9U,
+/*0447*/ 0x002002faU,
+/*0448*/ 0x000302fbU,
+/*0449*/ 0x002002fcU,
+/*044a*/ 0x000302fdU,
+/*044b*/ 0x002002feU,
+/*044c*/ 0x000302ffU,
+/*044d*/ 0x00200300U,
+/*044e*/ 0x00030301U,
+/*044f*/ 0x08030301U,
+/*0450*/ 0x10020301U,
+/*0451*/ 0x18020301U,
+/*0452*/ 0x00200302U,
+/*0453*/ 0x00200303U,
+/*0454*/ 0x00200304U,
+/*0455*/ 0x00200305U,
+/*0456*/ 0x00040306U,
+/*0457*/ 0x001e0307U,
+/*0458*/ 0x001e0308U,
+/*0459*/ 0x001e0309U,
+/*045a*/ 0x001e030aU,
+/*045b*/ 0x001e030bU,
+/*045c*/ 0x001e030cU,
+/*045d*/ 0x001e030dU,
+/*045e*/ 0x001e030eU,
+/*045f*/ 0x0004030fU,
+/*0460*/ 0x0801030fU,
+/*0461*/ 0x1010030fU,
+/*0462*/ 0x00100310U,
+/*0463*/ 0x10100310U,
+/*0464*/ 0x00040311U,
+/*0465*/ 0x08010311U,
+/*0466*/ 0x10080311U,
+/*0467*/ 0x18040311U,
+/*0468*/ 0x00010312U,
+/*0469*/ 0x08080312U,
+/*046a*/ 0x10040312U,
+/*046b*/ 0x18010312U,
+/*046c*/ 0x00080313U,
+/*046d*/ 0x08040313U,
+/*046e*/ 0x10010313U,
+/*046f*/ 0x18080313U,
+/*0470*/ 0x00040314U,
+/*0471*/ 0x08010314U,
+/*0472*/ 0x10080314U,
+/*0473*/ 0x18040314U,
+/*0474*/ 0x00010315U,
+/*0475*/ 0x08080315U,
+/*0476*/ 0x10040315U,
+/*0477*/ 0x18010315U,
+/*0478*/ 0x00080316U,
+/*0479*/ 0x08040316U,
+/*047a*/ 0x10010316U,
+/*047b*/ 0x18080316U,
+/*047c*/ 0x00080317U,
+/*047d*/ 0x00010318U,
+/*047e*/ 0x08050318U,
+/*047f*/ 0x10010318U,
+/*0480*/ 0x18020318U,
+/*0481*/ 0x00010319U,
+/*0482*/ 0x08010319U,
+/*0483*/ 0x10010319U,
+/*0484*/ 0x18010319U,
+/*0485*/ 0x0001031aU,
+/*0486*/ 0x0801031aU,
+/*0487*/ 0x1001031aU,
+/*0488*/ 0x1801031aU,
+/*0489*/ 0x0001031bU,
+/*048a*/ 0x0801031bU,
+/*048b*/ 0x1001031bU,
+/*048c*/ 0x1801031bU,
+/*048d*/ 0x0001031cU,
+/*048e*/ 0x0801031cU,
+/*048f*/ 0x1001031cU,
+/*0490*/ 0x1801031cU,
+/*0491*/ 0x0008031dU,
+/*0492*/ 0x0808031dU,
+/*0493*/ 0x1008031dU,
+/*0494*/ 0x1808031dU,
+	 }
+};
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3.h b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3.h
new file mode 100644
index 0000000..6fa9ab9
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define DDR_PHY_SLICE_REGSET_OFS_H3  0x0400
+#define DDR_PHY_ADR_V_REGSET_OFS_H3  0x0600
+#define DDR_PHY_ADR_I_REGSET_OFS_H3  0x0680
+#define DDR_PHY_ADR_G_REGSET_OFS_H3  0x0700
+#define DDR_PI_REGSET_OFS_H3         0x0200
+
+#define DDR_PHY_SLICE_REGSET_SIZE_H3 0x80
+#define DDR_PHY_ADR_V_REGSET_SIZE_H3 0x80
+#define DDR_PHY_ADR_I_REGSET_SIZE_H3 0x80
+#define DDR_PHY_ADR_G_REGSET_SIZE_H3 0x80
+#define DDR_PI_REGSET_SIZE_H3        0x100
+
+#define DDR_PHY_SLICE_REGSET_NUM_H3  88
+#define DDR_PHY_ADR_V_REGSET_NUM_H3  37
+#define DDR_PHY_ADR_I_REGSET_NUM_H3  37
+#define DDR_PHY_ADR_G_REGSET_NUM_H3  59
+#define DDR_PI_REGSET_NUM_H3         181
+
+static const uint32_t DDR_PHY_SLICE_REGSET_H3[DDR_PHY_SLICE_REGSET_NUM_H3] = {
+/*0400*/ 0x000004f0,
+/*0401*/ 0x00000000,
+/*0402*/ 0x00000000,
+/*0403*/ 0x00000100,
+/*0404*/ 0x01003c0c,
+/*0405*/ 0x02003c0c,
+/*0406*/ 0x00010300,
+/*0407*/ 0x04000100,
+/*0408*/ 0x00000300,
+/*0409*/ 0x000700c0,
+/*040a*/ 0x00b00201,
+/*040b*/ 0x00000020,
+/*040c*/ 0x00000000,
+/*040d*/ 0x00000000,
+/*040e*/ 0x00000000,
+/*040f*/ 0x00000000,
+/*0410*/ 0x00000000,
+/*0411*/ 0x00000000,
+/*0412*/ 0x00000000,
+/*0413*/ 0x09000000,
+/*0414*/ 0x04080000,
+/*0415*/ 0x04080400,
+/*0416*/ 0x00000000,
+/*0417*/ 0x32103210,
+/*0418*/ 0x00800708,
+/*0419*/ 0x000f000c,
+/*041a*/ 0x00000100,
+/*041b*/ 0x55aa55aa,
+/*041c*/ 0x33cc33cc,
+/*041d*/ 0x0ff00ff0,
+/*041e*/ 0x0f0ff0f0,
+/*041f*/ 0x00008e38,
+/*0420*/ 0x76543210,
+/*0421*/ 0x00000001,
+/*0422*/ 0x00000000,
+/*0423*/ 0x00000000,
+/*0424*/ 0x00000000,
+/*0425*/ 0x00000000,
+/*0426*/ 0x00000000,
+/*0427*/ 0x00000000,
+/*0428*/ 0x00000000,
+/*0429*/ 0x00000000,
+/*042a*/ 0x00000000,
+/*042b*/ 0x00000000,
+/*042c*/ 0x00000000,
+/*042d*/ 0x00000000,
+/*042e*/ 0x00000000,
+/*042f*/ 0x00000000,
+/*0430*/ 0x00000000,
+/*0431*/ 0x00000000,
+/*0432*/ 0x00000000,
+/*0433*/ 0x00200000,
+/*0434*/ 0x08200820,
+/*0435*/ 0x08200820,
+/*0436*/ 0x08200820,
+/*0437*/ 0x08200820,
+/*0438*/ 0x08200820,
+/*0439*/ 0x00000820,
+/*043a*/ 0x03000300,
+/*043b*/ 0x03000300,
+/*043c*/ 0x03000300,
+/*043d*/ 0x03000300,
+/*043e*/ 0x00000300,
+/*043f*/ 0x00000000,
+/*0440*/ 0x00000000,
+/*0441*/ 0x00000000,
+/*0442*/ 0x00000000,
+/*0443*/ 0x00a000a0,
+/*0444*/ 0x00a000a0,
+/*0445*/ 0x00a000a0,
+/*0446*/ 0x00a000a0,
+/*0447*/ 0x00a000a0,
+/*0448*/ 0x00a000a0,
+/*0449*/ 0x00a000a0,
+/*044a*/ 0x00a000a0,
+/*044b*/ 0x00a000a0,
+/*044c*/ 0x01040109,
+/*044d*/ 0x00000200,
+/*044e*/ 0x01000000,
+/*044f*/ 0x00000200,
+/*0450*/ 0x4041a141,
+/*0451*/ 0xc00141a0,
+/*0452*/ 0x0e0100c0,
+/*0453*/ 0x0010000c,
+/*0454*/ 0x0c064208,
+/*0455*/ 0x000f0c18,
+/*0456*/ 0x00e00140,
+/*0457*/ 0x00000c20
+};
+
+static const uint32_t DDR_PHY_ADR_V_REGSET_H3[DDR_PHY_ADR_V_REGSET_NUM_H3] = {
+/*0600*/ 0x00000000,
+/*0601*/ 0x00000000,
+/*0602*/ 0x00000000,
+/*0603*/ 0x00000000,
+/*0604*/ 0x00000000,
+/*0605*/ 0x00000000,
+/*0606*/ 0x00000002,
+/*0607*/ 0x00000000,
+/*0608*/ 0x00000000,
+/*0609*/ 0x00000000,
+/*060a*/ 0x00400320,
+/*060b*/ 0x00000040,
+/*060c*/ 0x00dcba98,
+/*060d*/ 0x00000000,
+/*060e*/ 0x00dcba98,
+/*060f*/ 0x01000000,
+/*0610*/ 0x00020003,
+/*0611*/ 0x00000000,
+/*0612*/ 0x00000000,
+/*0613*/ 0x00000000,
+/*0614*/ 0x00002a01,
+/*0615*/ 0x00000015,
+/*0616*/ 0x00000015,
+/*0617*/ 0x0000002a,
+/*0618*/ 0x00000033,
+/*0619*/ 0x0000000c,
+/*061a*/ 0x0000000c,
+/*061b*/ 0x00000033,
+/*061c*/ 0x00418820,
+/*061d*/ 0x003f0000,
+/*061e*/ 0x0000003f,
+/*061f*/ 0x0002006e,
+/*0620*/ 0x02000200,
+/*0621*/ 0x02000200,
+/*0622*/ 0x00000200,
+/*0623*/ 0x42080010,
+/*0624*/ 0x00000003
+};
+
+static const uint32_t DDR_PHY_ADR_I_REGSET_H3[DDR_PHY_ADR_I_REGSET_NUM_H3] = {
+/*0680*/ 0x04040404,
+/*0681*/ 0x00000404,
+/*0682*/ 0x00000000,
+/*0683*/ 0x00000000,
+/*0684*/ 0x00000000,
+/*0685*/ 0x00000000,
+/*0686*/ 0x00000002,
+/*0687*/ 0x00000000,
+/*0688*/ 0x00000000,
+/*0689*/ 0x00000000,
+/*068a*/ 0x00400320,
+/*068b*/ 0x00000040,
+/*068c*/ 0x00000000,
+/*068d*/ 0x00000000,
+/*068e*/ 0x00000000,
+/*068f*/ 0x01000000,
+/*0690*/ 0x00020003,
+/*0691*/ 0x00000000,
+/*0692*/ 0x00000000,
+/*0693*/ 0x00000000,
+/*0694*/ 0x00002a01,
+/*0695*/ 0x00000015,
+/*0696*/ 0x00000015,
+/*0697*/ 0x0000002a,
+/*0698*/ 0x00000033,
+/*0699*/ 0x0000000c,
+/*069a*/ 0x0000000c,
+/*069b*/ 0x00000033,
+/*069c*/ 0x00000000,
+/*069d*/ 0x00000000,
+/*069e*/ 0x00000000,
+/*069f*/ 0x0002006e,
+/*06a0*/ 0x02000200,
+/*06a1*/ 0x02000200,
+/*06a2*/ 0x00000200,
+/*06a3*/ 0x42080010,
+/*06a4*/ 0x00000003
+};
+
+static const uint32_t DDR_PHY_ADR_G_REGSET_H3[DDR_PHY_ADR_G_REGSET_NUM_H3] = {
+/*0700*/ 0x00000001,
+/*0701*/ 0x00000000,
+/*0702*/ 0x00000005,
+/*0703*/ 0x04000f00,
+/*0704*/ 0x00020080,
+/*0705*/ 0x00020055,
+/*0706*/ 0x00000000,
+/*0707*/ 0x00000000,
+/*0708*/ 0x00000000,
+/*0709*/ 0x00000050,
+/*070a*/ 0x00000000,
+/*070b*/ 0x01010100,
+/*070c*/ 0x00000200,
+/*070d*/ 0x00001102,
+/*070e*/ 0x00000000,
+/*070f*/ 0x000f1f00,
+/*0710*/ 0x0f1f0f1f,
+/*0711*/ 0x0f1f0f1f,
+/*0712*/ 0x00020003,
+/*0713*/ 0x02000200,
+/*0714*/ 0x00000200,
+/*0715*/ 0x00001102,
+/*0716*/ 0x00000064,
+/*0717*/ 0x00000000,
+/*0718*/ 0x00000000,
+/*0719*/ 0x00000502,
+/*071a*/ 0x027f6e00,
+/*071b*/ 0x007f007f,
+/*071c*/ 0x00007f3c,
+/*071d*/ 0x00047f6e,
+/*071e*/ 0x0003154f,
+/*071f*/ 0x0001154f,
+/*0720*/ 0x0001154f,
+/*0721*/ 0x0001154f,
+/*0722*/ 0x0001154f,
+/*0723*/ 0x00003fee,
+/*0724*/ 0x0001154f,
+/*0725*/ 0x00003fee,
+/*0726*/ 0x0001154f,
+/*0727*/ 0x00007f3c,
+/*0728*/ 0x0001154f,
+/*0729*/ 0x00000000,
+/*072a*/ 0x00000000,
+/*072b*/ 0x00000000,
+/*072c*/ 0x65000000,
+/*072d*/ 0x00000000,
+/*072e*/ 0x00000000,
+/*072f*/ 0x00000201,
+/*0730*/ 0x00000000,
+/*0731*/ 0x00000000,
+/*0732*/ 0x00000000,
+/*0733*/ 0x00000000,
+/*0734*/ 0x00000000,
+/*0735*/ 0x00000000,
+/*0736*/ 0x00000000,
+/*0737*/ 0x00000000,
+/*0738*/ 0x00000000,
+/*0739*/ 0x00000000,
+/*073a*/ 0x00000000
+};
+
+static const uint32_t DDR_PI_REGSET_H3[DDR_PI_REGSET_NUM_H3] = {
+/*0200*/ 0x00000b00,
+/*0201*/ 0x00000100,
+/*0202*/ 0x00000000,
+/*0203*/ 0x0000ffff,
+/*0204*/ 0x00000000,
+/*0205*/ 0x0000ffff,
+/*0206*/ 0x00000000,
+/*0207*/ 0x304cffff,
+/*0208*/ 0x00000200,
+/*0209*/ 0x00000200,
+/*020a*/ 0x00000200,
+/*020b*/ 0x00000200,
+/*020c*/ 0x0000304c,
+/*020d*/ 0x00000200,
+/*020e*/ 0x00000200,
+/*020f*/ 0x00000200,
+/*0210*/ 0x00000200,
+/*0211*/ 0x0000304c,
+/*0212*/ 0x00000200,
+/*0213*/ 0x00000200,
+/*0214*/ 0x00000200,
+/*0215*/ 0x00000200,
+/*0216*/ 0x00010000,
+/*0217*/ 0x00000003,
+/*0218*/ 0x01000001,
+/*0219*/ 0x00000000,
+/*021a*/ 0x00000000,
+/*021b*/ 0x00000000,
+/*021c*/ 0x00000000,
+/*021d*/ 0x00000000,
+/*021e*/ 0x00000000,
+/*021f*/ 0x00000000,
+/*0220*/ 0x00000000,
+/*0221*/ 0x00000000,
+/*0222*/ 0x00000000,
+/*0223*/ 0x00000000,
+/*0224*/ 0x00000000,
+/*0225*/ 0x00000000,
+/*0226*/ 0x00000000,
+/*0227*/ 0x00000000,
+/*0228*/ 0x00000000,
+/*0229*/ 0x0f000101,
+/*022a*/ 0x08492d25,
+/*022b*/ 0x500e0c04,
+/*022c*/ 0x0002500e,
+/*022d*/ 0x00460003,
+/*022e*/ 0x182600cf,
+/*022f*/ 0x182600cf,
+/*0230*/ 0x00000005,
+/*0231*/ 0x00000000,
+/*0232*/ 0x00000000,
+/*0233*/ 0x00000000,
+/*0234*/ 0x00000000,
+/*0235*/ 0x00000000,
+/*0236*/ 0x00000000,
+/*0237*/ 0x00000000,
+/*0238*/ 0x01000000,
+/*0239*/ 0x00040404,
+/*023a*/ 0x01280a00,
+/*023b*/ 0x00000000,
+/*023c*/ 0x000f0000,
+/*023d*/ 0x00001803,
+/*023e*/ 0x00000000,
+/*023f*/ 0x00000000,
+/*0240*/ 0x00060002,
+/*0241*/ 0x00010001,
+/*0242*/ 0x01000101,
+/*0243*/ 0x04020201,
+/*0244*/ 0x00080804,
+/*0245*/ 0x00000000,
+/*0246*/ 0x08030000,
+/*0247*/ 0x15150408,
+/*0248*/ 0x00000000,
+/*0249*/ 0x00000000,
+/*024a*/ 0x00000000,
+/*024b*/ 0x001e0f0f,
+/*024c*/ 0x00000000,
+/*024d*/ 0x01000300,
+/*024e*/ 0x00000000,
+/*024f*/ 0x00000000,
+/*0250*/ 0x01000000,
+/*0251*/ 0x00010101,
+/*0252*/ 0x000e0e0e,
+/*0253*/ 0x000c0c0c,
+/*0254*/ 0x02060601,
+/*0255*/ 0x00000000,
+/*0256*/ 0x00000003,
+/*0257*/ 0x00181703,
+/*0258*/ 0x00280006,
+/*0259*/ 0x00280016,
+/*025a*/ 0x00000016,
+/*025b*/ 0x00000000,
+/*025c*/ 0x00000000,
+/*025d*/ 0x00000000,
+/*025e*/ 0x140a0000,
+/*025f*/ 0x0005010a,
+/*0260*/ 0x03018d03,
+/*0261*/ 0x000a018d,
+/*0262*/ 0x00060100,
+/*0263*/ 0x01000006,
+/*0264*/ 0x018e018e,
+/*0265*/ 0x018e0100,
+/*0266*/ 0x1111018e,
+/*0267*/ 0x10010204,
+/*0268*/ 0x09090650,
+/*0269*/ 0x20110202,
+/*026a*/ 0x00201000,
+/*026b*/ 0x00201000,
+/*026c*/ 0x04041000,
+/*026d*/ 0x18020100,
+/*026e*/ 0x00010118,
+/*026f*/ 0x004b004a,
+/*0270*/ 0x050f0000,
+/*0271*/ 0x0c01021e,
+/*0272*/ 0x34000000,
+/*0273*/ 0x00000000,
+/*0274*/ 0x00000000,
+/*0275*/ 0x00000000,
+/*0276*/ 0x312ed400,
+/*0277*/ 0xd4111132,
+/*0278*/ 0x1132312e,
+/*0279*/ 0x312ed411,
+/*027a*/ 0x00111132,
+/*027b*/ 0x32312ed4,
+/*027c*/ 0x2ed41111,
+/*027d*/ 0x11113231,
+/*027e*/ 0x32312ed4,
+/*027f*/ 0xd4001111,
+/*0280*/ 0x1132312e,
+/*0281*/ 0x312ed411,
+/*0282*/ 0xd4111132,
+/*0283*/ 0x1132312e,
+/*0284*/ 0x2ed40011,
+/*0285*/ 0x11113231,
+/*0286*/ 0x32312ed4,
+/*0287*/ 0x2ed41111,
+/*0288*/ 0x11113231,
+/*0289*/ 0x00020000,
+/*028a*/ 0x018d018d,
+/*028b*/ 0x0c08018d,
+/*028c*/ 0x1f121d22,
+/*028d*/ 0x4301b344,
+/*028e*/ 0x10172006,
+/*028f*/ 0x121d220c,
+/*0290*/ 0x01b3441f,
+/*0291*/ 0x17200643,
+/*0292*/ 0x1d220c10,
+/*0293*/ 0x00001f12,
+/*0294*/ 0x4301b344,
+/*0295*/ 0x10172006,
+/*0296*/ 0x00020002,
+/*0297*/ 0x00020002,
+/*0298*/ 0x00020002,
+/*0299*/ 0x00020002,
+/*029a*/ 0x00020002,
+/*029b*/ 0x00000000,
+/*029c*/ 0x00000000,
+/*029d*/ 0x00000000,
+/*029e*/ 0x00000000,
+/*029f*/ 0x00000000,
+/*02a0*/ 0x00000000,
+/*02a1*/ 0x00000000,
+/*02a2*/ 0x00000000,
+/*02a3*/ 0x00000000,
+/*02a4*/ 0x00000000,
+/*02a5*/ 0x00000000,
+/*02a6*/ 0x00000000,
+/*02a7*/ 0x01000400,
+/*02a8*/ 0x00304c00,
+/*02a9*/ 0x0001e2f8,
+/*02aa*/ 0x0000304c,
+/*02ab*/ 0x0001e2f8,
+/*02ac*/ 0x0000304c,
+/*02ad*/ 0x0001e2f8,
+/*02ae*/ 0x08000000,
+/*02af*/ 0x00000100,
+/*02b0*/ 0x00000000,
+/*02b1*/ 0x00000000,
+/*02b2*/ 0x00000000,
+/*02b3*/ 0x00000000,
+/*02b4*/ 0x00000002
+};
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3ver2.h b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3ver2.h
new file mode 100644
index 0000000..6e4c30e
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3ver2.h
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define DDR_PHY_SLICE_REGSET_OFS_H3VER2  0x0400
+#define DDR_PHY_ADR_V_REGSET_OFS_H3VER2  0x0600
+#define DDR_PHY_ADR_I_REGSET_OFS_H3VER2  0x0640
+#define DDR_PHY_ADR_G_REGSET_OFS_H3VER2  0x0680
+#define DDR_PI_REGSET_OFS_H3VER2         0x0200
+
+#define DDR_PHY_SLICE_REGSET_SIZE_H3VER2 0x80
+#define DDR_PHY_ADR_V_REGSET_SIZE_H3VER2 0x40
+#define DDR_PHY_ADR_I_REGSET_SIZE_H3VER2 0x40
+#define DDR_PHY_ADR_G_REGSET_SIZE_H3VER2 0x80
+#define DDR_PI_REGSET_SIZE_H3VER2        0x100
+
+#define DDR_PHY_SLICE_REGSET_NUM_H3VER2  97
+#define DDR_PHY_ADR_V_REGSET_NUM_H3VER2  37
+#define DDR_PHY_ADR_I_REGSET_NUM_H3VER2  37
+#define DDR_PHY_ADR_G_REGSET_NUM_H3VER2  79
+#define DDR_PI_REGSET_NUM_H3VER2         245
+
+static const uint32_t
+    DDR_PHY_SLICE_REGSET_H3VER2[DDR_PHY_SLICE_REGSET_NUM_H3VER2] = {
+/*0400*/ 0x76543210,
+/*0401*/ 0x0004f008,
+/*0402*/ 0x00020133,
+/*0403*/ 0x00000000,
+/*0404*/ 0x00000000,
+/*0405*/ 0x00010000,
+/*0406*/ 0x016e6e0e,
+/*0407*/ 0x026e6e0e,
+/*0408*/ 0x00010300,
+/*0409*/ 0x04000100,
+/*040a*/ 0x01000000,
+/*040b*/ 0x00000000,
+/*040c*/ 0x00000000,
+/*040d*/ 0x00000100,
+/*040e*/ 0x001700c0,
+/*040f*/ 0x020100b0,
+/*0410*/ 0x00030020,
+/*0411*/ 0x00000000,
+/*0412*/ 0x00000000,
+/*0413*/ 0x00000000,
+/*0414*/ 0x00000000,
+/*0415*/ 0x00000000,
+/*0416*/ 0x00000000,
+/*0417*/ 0x00000000,
+/*0418*/ 0x09000000,
+/*0419*/ 0x04080000,
+/*041a*/ 0x04080400,
+/*041b*/ 0x08000000,
+/*041c*/ 0x0c008007,
+/*041d*/ 0x00000f00,
+/*041e*/ 0x00000100,
+/*041f*/ 0x55aa55aa,
+/*0420*/ 0x33cc33cc,
+/*0421*/ 0x0ff00ff0,
+/*0422*/ 0x0f0ff0f0,
+/*0423*/ 0x00018e38,
+/*0424*/ 0x00000000,
+/*0425*/ 0x00000000,
+/*0426*/ 0x00000000,
+/*0427*/ 0x00000000,
+/*0428*/ 0x00000000,
+/*0429*/ 0x00000000,
+/*042a*/ 0x00000000,
+/*042b*/ 0x00000000,
+/*042c*/ 0x00000000,
+/*042d*/ 0x00000000,
+/*042e*/ 0x00000000,
+/*042f*/ 0x00000000,
+/*0430*/ 0x00000000,
+/*0431*/ 0x00000000,
+/*0432*/ 0x00000000,
+/*0433*/ 0x00000000,
+/*0434*/ 0x00000000,
+/*0435*/ 0x00000000,
+/*0436*/ 0x00000000,
+/*0437*/ 0x00000000,
+/*0438*/ 0x00000104,
+/*0439*/ 0x00082020,
+/*043a*/ 0x08200820,
+/*043b*/ 0x08200820,
+/*043c*/ 0x08200820,
+/*043d*/ 0x08200820,
+/*043e*/ 0x08200820,
+/*043f*/ 0x00000000,
+/*0440*/ 0x00000000,
+/*0441*/ 0x03000300,
+/*0442*/ 0x03000300,
+/*0443*/ 0x03000300,
+/*0444*/ 0x03000300,
+/*0445*/ 0x00000300,
+/*0446*/ 0x00000000,
+/*0447*/ 0x00000000,
+/*0448*/ 0x00000000,
+/*0449*/ 0x00000000,
+/*044a*/ 0x00000000,
+/*044b*/ 0x00a000a0,
+/*044c*/ 0x00a000a0,
+/*044d*/ 0x00a000a0,
+/*044e*/ 0x00a000a0,
+/*044f*/ 0x00a000a0,
+/*0450*/ 0x00a000a0,
+/*0451*/ 0x00a000a0,
+/*0452*/ 0x00a000a0,
+/*0453*/ 0x00a000a0,
+/*0454*/ 0x01040109,
+/*0455*/ 0x00000200,
+/*0456*/ 0x01000000,
+/*0457*/ 0x00000200,
+/*0458*/ 0x00000004,
+/*0459*/ 0x4041a141,
+/*045a*/ 0xc00141a0,
+/*045b*/ 0x0e0000c0,
+/*045c*/ 0x0010000c,
+/*045d*/ 0x063e4208,
+/*045e*/ 0x0f0c180c,
+/*045f*/ 0x00e00140,
+/*0460*/ 0x00000c20
+};
+
+static const uint32_t
+    DDR_PHY_ADR_V_REGSET_H3VER2[DDR_PHY_ADR_V_REGSET_NUM_H3VER2] = {
+/*0600*/ 0x00000000,
+/*0601*/ 0x00000000,
+/*0602*/ 0x00000000,
+/*0603*/ 0x00000000,
+/*0604*/ 0x00000000,
+/*0605*/ 0x00000000,
+/*0606*/ 0x00000000,
+/*0607*/ 0x00010000,
+/*0608*/ 0x00000200,
+/*0609*/ 0x00000000,
+/*060a*/ 0x00000000,
+/*060b*/ 0x00000000,
+/*060c*/ 0x00400320,
+/*060d*/ 0x00000040,
+/*060e*/ 0x00dcba98,
+/*060f*/ 0x03000000,
+/*0610*/ 0x00000200,
+/*0611*/ 0x00000000,
+/*0612*/ 0x00000000,
+/*0613*/ 0x00000000,
+/*0614*/ 0x0000002a,
+/*0615*/ 0x00000015,
+/*0616*/ 0x00000015,
+/*0617*/ 0x0000002a,
+/*0618*/ 0x00000033,
+/*0619*/ 0x0000000c,
+/*061a*/ 0x0000000c,
+/*061b*/ 0x00000033,
+/*061c*/ 0x00418820,
+/*061d*/ 0x003f0000,
+/*061e*/ 0x0000003f,
+/*061f*/ 0x0002c06e,
+/*0620*/ 0x02c002c0,
+/*0621*/ 0x02c002c0,
+/*0622*/ 0x000002c0,
+/*0623*/ 0x42080010,
+/*0624*/ 0x0000033e
+};
+
+static const uint32_t
+    DDR_PHY_ADR_I_REGSET_H3VER2[DDR_PHY_ADR_I_REGSET_NUM_H3VER2] = {
+/*0640*/ 0x00000000,
+/*0641*/ 0x00000000,
+/*0642*/ 0x00000000,
+/*0643*/ 0x00000000,
+/*0644*/ 0x00000000,
+/*0645*/ 0x00000000,
+/*0646*/ 0x00000000,
+/*0647*/ 0x00000000,
+/*0648*/ 0x00000000,
+/*0649*/ 0x00000000,
+/*064a*/ 0x00000000,
+/*064b*/ 0x00000000,
+/*064c*/ 0x00000000,
+/*064d*/ 0x00000000,
+/*064e*/ 0x00000000,
+/*064f*/ 0x00000000,
+/*0650*/ 0x00000000,
+/*0651*/ 0x00000000,
+/*0652*/ 0x00000000,
+/*0653*/ 0x00000000,
+/*0654*/ 0x00000000,
+/*0655*/ 0x00000000,
+/*0656*/ 0x00000000,
+/*0657*/ 0x00000000,
+/*0658*/ 0x00000000,
+/*0659*/ 0x00000000,
+/*065a*/ 0x00000000,
+/*065b*/ 0x00000000,
+/*065c*/ 0x00000000,
+/*065d*/ 0x00000000,
+/*065e*/ 0x00000000,
+/*065f*/ 0x00000000,
+/*0660*/ 0x00000000,
+/*0661*/ 0x00000000,
+/*0662*/ 0x00000000,
+/*0663*/ 0x00000000,
+/*0664*/ 0x00000000
+};
+
+static const uint32_t
+    DDR_PHY_ADR_G_REGSET_H3VER2[DDR_PHY_ADR_G_REGSET_NUM_H3VER2] = {
+/*0680*/ 0x00000000,
+/*0681*/ 0x00000100,
+/*0682*/ 0x00000000,
+/*0683*/ 0x00050000,
+/*0684*/ 0x0f000000,
+/*0685*/ 0x00800400,
+/*0686*/ 0x00020032,
+/*0687*/ 0x00020055,
+/*0688*/ 0x00000000,
+/*0689*/ 0x00000000,
+/*068a*/ 0x00000000,
+/*068b*/ 0x00000050,
+/*068c*/ 0x00000000,
+/*068d*/ 0x01010100,
+/*068e*/ 0x01000200,
+/*068f*/ 0x00000000,
+/*0690*/ 0x00010100,
+/*0691*/ 0x00000000,
+/*0692*/ 0x00000000,
+/*0693*/ 0x00000000,
+/*0694*/ 0x00000000,
+/*0695*/ 0x00005064,
+/*0696*/ 0x01421142,
+/*0697*/ 0x00000142,
+/*0698*/ 0x00000000,
+/*0699*/ 0x000f1100,
+/*069a*/ 0x0f110f11,
+/*069b*/ 0x09000f11,
+/*069c*/ 0x00000003,
+/*069d*/ 0x0002c000,
+/*069e*/ 0x02c002c0,
+/*069f*/ 0x000002c0,
+/*06a0*/ 0x03421342,
+/*06a1*/ 0x00000342,
+/*06a2*/ 0x00000000,
+/*06a3*/ 0x00000000,
+/*06a4*/ 0x05020000,
+/*06a5*/ 0x14000000,
+/*06a6*/ 0x027f6e00,
+/*06a7*/ 0x047f027f,
+/*06a8*/ 0x00027f6e,
+/*06a9*/ 0x00047f6e,
+/*06aa*/ 0x0003554f,
+/*06ab*/ 0x0001554f,
+/*06ac*/ 0x0001554f,
+/*06ad*/ 0x0001554f,
+/*06ae*/ 0x0001554f,
+/*06af*/ 0x00003fee,
+/*06b0*/ 0x0001554f,
+/*06b1*/ 0x00003fee,
+/*06b2*/ 0x0001554f,
+/*06b3*/ 0x00027f6e,
+/*06b4*/ 0x0001554f,
+/*06b5*/ 0x00004011,
+/*06b6*/ 0x00004410,
+/*06b7*/ 0x00000000,
+/*06b8*/ 0x00000000,
+/*06b9*/ 0x00000000,
+/*06ba*/ 0x00000065,
+/*06bb*/ 0x00000000,
+/*06bc*/ 0x00020201,
+/*06bd*/ 0x00000000,
+/*06be*/ 0x03000000,
+/*06bf*/ 0x00000008,
+/*06c0*/ 0x00000000,
+/*06c1*/ 0x00000000,
+/*06c2*/ 0x00000000,
+/*06c3*/ 0x00000000,
+/*06c4*/ 0x00000001,
+/*06c5*/ 0x00000000,
+/*06c6*/ 0x00000000,
+/*06c7*/ 0x00000000,
+/*06c8*/ 0x000000e4,
+/*06c9*/ 0x00010198,
+/*06ca*/ 0x00000000,
+/*06cb*/ 0x00000000,
+/*06cc*/ 0x07010000,
+/*06cd*/ 0x00000104,
+/*06ce*/ 0x00000000
+};
+
+static const uint32_t DDR_PI_REGSET_H3VER2[DDR_PI_REGSET_NUM_H3VER2] = {
+/*0200*/ 0x00000b00,
+/*0201*/ 0x00000100,
+/*0202*/ 0x00640000,
+/*0203*/ 0x00000000,
+/*0204*/ 0x0000ffff,
+/*0205*/ 0x00000000,
+/*0206*/ 0x0000ffff,
+/*0207*/ 0x00000000,
+/*0208*/ 0x0000ffff,
+/*0209*/ 0x0000304c,
+/*020a*/ 0x00000200,
+/*020b*/ 0x00000200,
+/*020c*/ 0x00000200,
+/*020d*/ 0x00000200,
+/*020e*/ 0x0000304c,
+/*020f*/ 0x00000200,
+/*0210*/ 0x00000200,
+/*0211*/ 0x00000200,
+/*0212*/ 0x00000200,
+/*0213*/ 0x0000304c,
+/*0214*/ 0x00000200,
+/*0215*/ 0x00000200,
+/*0216*/ 0x00000200,
+/*0217*/ 0x00000200,
+/*0218*/ 0x00010000,
+/*0219*/ 0x00000003,
+/*021a*/ 0x01000001,
+/*021b*/ 0x00000000,
+/*021c*/ 0x00000000,
+/*021d*/ 0x00000000,
+/*021e*/ 0x00000000,
+/*021f*/ 0x00000000,
+/*0220*/ 0x00000000,
+/*0221*/ 0x00000000,
+/*0222*/ 0x00000000,
+/*0223*/ 0x00000000,
+/*0224*/ 0x00000000,
+/*0225*/ 0x00000000,
+/*0226*/ 0x00000000,
+/*0227*/ 0x00000000,
+/*0228*/ 0x00000000,
+/*0229*/ 0x00000000,
+/*022a*/ 0x00000000,
+/*022b*/ 0x0f000101,
+/*022c*/ 0x08492d25,
+/*022d*/ 0x500e0c04,
+/*022e*/ 0x0002500e,
+/*022f*/ 0x00000301,
+/*0230*/ 0x00000046,
+/*0231*/ 0x000000cf,
+/*0232*/ 0x00001826,
+/*0233*/ 0x000000cf,
+/*0234*/ 0x00001826,
+/*0235*/ 0x00000005,
+/*0236*/ 0x00000000,
+/*0237*/ 0x00000000,
+/*0238*/ 0x00000000,
+/*0239*/ 0x00000000,
+/*023a*/ 0x00000000,
+/*023b*/ 0x00000000,
+/*023c*/ 0x00000000,
+/*023d*/ 0x00000000,
+/*023e*/ 0x04010000,
+/*023f*/ 0x00000404,
+/*0240*/ 0x0101280a,
+/*0241*/ 0x00000000,
+/*0242*/ 0x00000000,
+/*0243*/ 0x0003000f,
+/*0244*/ 0x00000018,
+/*0245*/ 0x00000000,
+/*0246*/ 0x00000000,
+/*0247*/ 0x00060002,
+/*0248*/ 0x00010001,
+/*0249*/ 0x01000101,
+/*024a*/ 0x04020201,
+/*024b*/ 0x00080804,
+/*024c*/ 0x00000000,
+/*024d*/ 0x08030000,
+/*024e*/ 0x15150408,
+/*024f*/ 0x00000000,
+/*0250*/ 0x00000000,
+/*0251*/ 0x00000000,
+/*0252*/ 0x0f0f0000,
+/*0253*/ 0x0000001e,
+/*0254*/ 0x00000000,
+/*0255*/ 0x01000300,
+/*0256*/ 0x00000100,
+/*0257*/ 0x00000000,
+/*0258*/ 0x00000000,
+/*0259*/ 0x01000000,
+/*025a*/ 0x00000101,
+/*025b*/ 0x55555a5a,
+/*025c*/ 0x55555a5a,
+/*025d*/ 0x55555a5a,
+/*025e*/ 0x55555a5a,
+/*025f*/ 0x0e0e0001,
+/*0260*/ 0x0c0c000e,
+/*0261*/ 0x0601000c,
+/*0262*/ 0x17170106,
+/*0263*/ 0x00020202,
+/*0264*/ 0x03000000,
+/*0265*/ 0x00000000,
+/*0266*/ 0x00181703,
+/*0267*/ 0x00280006,
+/*0268*/ 0x00280016,
+/*0269*/ 0x00000016,
+/*026a*/ 0x00000000,
+/*026b*/ 0x00000000,
+/*026c*/ 0x00000000,
+/*026d*/ 0x0a000000,
+/*026e*/ 0x00010a14,
+/*026f*/ 0x00030005,
+/*0270*/ 0x0003018d,
+/*0271*/ 0x000a018d,
+/*0272*/ 0x00060100,
+/*0273*/ 0x01000006,
+/*0274*/ 0x018e018e,
+/*0275*/ 0x018e0100,
+/*0276*/ 0x1111018e,
+/*0277*/ 0x10010204,
+/*0278*/ 0x09090650,
+/*0279*/ 0xff110202,
+/*027a*/ 0x00ff1000,
+/*027b*/ 0x00ff1000,
+/*027c*/ 0x04041000,
+/*027d*/ 0x18020100,
+/*027e*/ 0x01010018,
+/*027f*/ 0x004a004a,
+/*0280*/ 0x004b004a,
+/*0281*/ 0x050f0000,
+/*0282*/ 0x0c01021e,
+/*0283*/ 0x34000000,
+/*0284*/ 0x00000000,
+/*0285*/ 0x00000000,
+/*0286*/ 0x00000000,
+/*0287*/ 0x00000000,
+/*0288*/ 0x36312ed4,
+/*0289*/ 0x2ed41111,
+/*028a*/ 0x11113631,
+/*028b*/ 0x36312ed4,
+/*028c*/ 0xd4001111,
+/*028d*/ 0x1136312e,
+/*028e*/ 0x312ed411,
+/*028f*/ 0xd4111136,
+/*0290*/ 0x1136312e,
+/*0291*/ 0x2ed40011,
+/*0292*/ 0x11113631,
+/*0293*/ 0x36312ed4,
+/*0294*/ 0x2ed41111,
+/*0295*/ 0x11113631,
+/*0296*/ 0x312ed400,
+/*0297*/ 0xd4111136,
+/*0298*/ 0x1136312e,
+/*0299*/ 0x312ed411,
+/*029a*/ 0x00111136,
+/*029b*/ 0x018d0200,
+/*029c*/ 0x018d018d,
+/*029d*/ 0x1d220c08,
+/*029e*/ 0x00001f12,
+/*029f*/ 0x4301b344,
+/*02a0*/ 0x10172006,
+/*02a1*/ 0x121d220c,
+/*02a2*/ 0x01b3441f,
+/*02a3*/ 0x17200643,
+/*02a4*/ 0x1d220c10,
+/*02a5*/ 0x00001f12,
+/*02a6*/ 0x4301b344,
+/*02a7*/ 0x10172006,
+/*02a8*/ 0x00020002,
+/*02a9*/ 0x00020002,
+/*02aa*/ 0x00020002,
+/*02ab*/ 0x00020002,
+/*02ac*/ 0x00020002,
+/*02ad*/ 0x00000000,
+/*02ae*/ 0x00000000,
+/*02af*/ 0x00000000,
+/*02b0*/ 0x00000000,
+/*02b1*/ 0x00000000,
+/*02b2*/ 0x00000000,
+/*02b3*/ 0x00000000,
+/*02b4*/ 0x00000000,
+/*02b5*/ 0x00000000,
+/*02b6*/ 0x00000000,
+/*02b7*/ 0x00000000,
+/*02b8*/ 0x00000000,
+/*02b9*/ 0x00000400,
+/*02ba*/ 0x05040302,
+/*02bb*/ 0x01000f0e,
+/*02bc*/ 0x07060504,
+/*02bd*/ 0x03020100,
+/*02be*/ 0x02010000,
+/*02bf*/ 0x00000103,
+/*02c0*/ 0x0000304c,
+/*02c1*/ 0x0001e2f8,
+/*02c2*/ 0x0000304c,
+/*02c3*/ 0x0001e2f8,
+/*02c4*/ 0x0000304c,
+/*02c5*/ 0x0001e2f8,
+/*02c6*/ 0x08000000,
+/*02c7*/ 0x00000100,
+/*02c8*/ 0x00000000,
+/*02c9*/ 0x00000000,
+/*02ca*/ 0x00000000,
+/*02cb*/ 0x00000000,
+/*02cc*/ 0x00010000,
+/*02cd*/ 0x00000000,
+/*02ce*/ 0x00000000,
+/*02cf*/ 0x00000000,
+/*02d0*/ 0x00000000,
+/*02d1*/ 0x00000000,
+/*02d2*/ 0x00000000,
+/*02d3*/ 0x00000000,
+/*02d4*/ 0x00000000,
+/*02d5*/ 0x00000000,
+/*02d6*/ 0x00000000,
+/*02d7*/ 0x00000000,
+/*02d8*/ 0x00000000,
+/*02d9*/ 0x00000000,
+/*02da*/ 0x00000000,
+/*02db*/ 0x00000000,
+/*02dc*/ 0x00000000,
+/*02dd*/ 0x00000000,
+/*02de*/ 0x00000000,
+/*02df*/ 0x00000000,
+/*02e0*/ 0x00000000,
+/*02e1*/ 0x00000000,
+/*02e2*/ 0x00000000,
+/*02e3*/ 0x00000000,
+/*02e4*/ 0x00000000,
+/*02e5*/ 0x00000000,
+/*02e6*/ 0x00000000,
+/*02e7*/ 0x00000000,
+/*02e8*/ 0x00000000,
+/*02e9*/ 0x00000000,
+/*02ea*/ 0x00000000,
+/*02eb*/ 0x00000000,
+/*02ec*/ 0x00000000,
+/*02ed*/ 0x00000000,
+/*02ee*/ 0x00000002,
+/*02ef*/ 0x00000000,
+/*02f0*/ 0x00000000,
+/*02f1*/ 0x00000000,
+/*02f2*/ 0x00000000,
+/*02f3*/ 0x00000000,
+/*02f4*/ 0x00000000
+};
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3.h b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3.h
new file mode 100644
index 0000000..3c62107
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define DDR_PHY_SLICE_REGSET_OFS_M3  0x0800
+#define DDR_PHY_ADR_V_REGSET_OFS_M3  0x0a00
+#define DDR_PHY_ADR_I_REGSET_OFS_M3  0x0a80
+#define DDR_PHY_ADR_G_REGSET_OFS_M3  0x0b80
+#define DDR_PI_REGSET_OFS_M3         0x0200
+
+#define DDR_PHY_SLICE_REGSET_SIZE_M3 0x80
+#define DDR_PHY_ADR_V_REGSET_SIZE_M3 0x80
+#define DDR_PHY_ADR_I_REGSET_SIZE_M3 0x80
+#define DDR_PHY_ADR_G_REGSET_SIZE_M3 0x80
+#define DDR_PI_REGSET_SIZE_M3        0x100
+
+#define DDR_PHY_SLICE_REGSET_NUM_M3  89
+#define DDR_PHY_ADR_V_REGSET_NUM_M3  37
+#define DDR_PHY_ADR_I_REGSET_NUM_M3  37
+#define DDR_PHY_ADR_G_REGSET_NUM_M3  64
+#define DDR_PI_REGSET_NUM_M3         202
+
+static const uint32_t DDR_PHY_SLICE_REGSET_M3[DDR_PHY_SLICE_REGSET_NUM_M3] = {
+/*0800*/ 0x76543210,
+/*0801*/ 0x0004f008,
+/*0802*/ 0x00000000,
+/*0803*/ 0x00000000,
+/*0804*/ 0x00010000,
+/*0805*/ 0x036e6e0e,
+/*0806*/ 0x026e6e0e,
+/*0807*/ 0x00010300,
+/*0808*/ 0x04000100,
+/*0809*/ 0x00000300,
+/*080a*/ 0x001700c0,
+/*080b*/ 0x00b00201,
+/*080c*/ 0x00030020,
+/*080d*/ 0x00000000,
+/*080e*/ 0x00000000,
+/*080f*/ 0x00000000,
+/*0810*/ 0x00000000,
+/*0811*/ 0x00000000,
+/*0812*/ 0x00000000,
+/*0813*/ 0x00000000,
+/*0814*/ 0x09000000,
+/*0815*/ 0x04080000,
+/*0816*/ 0x04080400,
+/*0817*/ 0x00000000,
+/*0818*/ 0x32103210,
+/*0819*/ 0x00800708,
+/*081a*/ 0x000f000c,
+/*081b*/ 0x00000100,
+/*081c*/ 0x55aa55aa,
+/*081d*/ 0x33cc33cc,
+/*081e*/ 0x0ff00ff0,
+/*081f*/ 0x0f0ff0f0,
+/*0820*/ 0x00018e38,
+/*0821*/ 0x00000000,
+/*0822*/ 0x00000000,
+/*0823*/ 0x00000000,
+/*0824*/ 0x00000000,
+/*0825*/ 0x00000000,
+/*0826*/ 0x00000000,
+/*0827*/ 0x00000000,
+/*0828*/ 0x00000000,
+/*0829*/ 0x00000000,
+/*082a*/ 0x00000000,
+/*082b*/ 0x00000000,
+/*082c*/ 0x00000000,
+/*082d*/ 0x00000000,
+/*082e*/ 0x00000000,
+/*082f*/ 0x00000000,
+/*0830*/ 0x00000000,
+/*0831*/ 0x00000000,
+/*0832*/ 0x00000000,
+/*0833*/ 0x00200000,
+/*0834*/ 0x08200820,
+/*0835*/ 0x08200820,
+/*0836*/ 0x08200820,
+/*0837*/ 0x08200820,
+/*0838*/ 0x08200820,
+/*0839*/ 0x00000820,
+/*083a*/ 0x03000300,
+/*083b*/ 0x03000300,
+/*083c*/ 0x03000300,
+/*083d*/ 0x03000300,
+/*083e*/ 0x00000300,
+/*083f*/ 0x00000000,
+/*0840*/ 0x00000000,
+/*0841*/ 0x00000000,
+/*0842*/ 0x00000000,
+/*0843*/ 0x00a00000,
+/*0844*/ 0x00a000a0,
+/*0845*/ 0x00a000a0,
+/*0846*/ 0x00a000a0,
+/*0847*/ 0x00a000a0,
+/*0848*/ 0x00a000a0,
+/*0849*/ 0x00a000a0,
+/*084a*/ 0x00a000a0,
+/*084b*/ 0x00a000a0,
+/*084c*/ 0x010900a0,
+/*084d*/ 0x02000104,
+/*084e*/ 0x00000000,
+/*084f*/ 0x00010000,
+/*0850*/ 0x00000200,
+/*0851*/ 0x4041a141,
+/*0852*/ 0xc00141a0,
+/*0853*/ 0x0e0100c0,
+/*0854*/ 0x0010000c,
+/*0855*/ 0x0c064208,
+/*0856*/ 0x000f0c18,
+/*0857*/ 0x00e00140,
+/*0858*/ 0x00000c20
+};
+
+static const uint32_t DDR_PHY_ADR_V_REGSET_M3[DDR_PHY_ADR_V_REGSET_NUM_M3] = {
+/*0a00*/ 0x00000000,
+/*0a01*/ 0x00000000,
+/*0a02*/ 0x00000000,
+/*0a03*/ 0x00000000,
+/*0a04*/ 0x00000000,
+/*0a05*/ 0x00000000,
+/*0a06*/ 0x00000002,
+/*0a07*/ 0x00000000,
+/*0a08*/ 0x00000000,
+/*0a09*/ 0x00000000,
+/*0a0a*/ 0x00400320,
+/*0a0b*/ 0x00000040,
+/*0a0c*/ 0x00dcba98,
+/*0a0d*/ 0x00000000,
+/*0a0e*/ 0x00dcba98,
+/*0a0f*/ 0x01000000,
+/*0a10*/ 0x00020003,
+/*0a11*/ 0x00000000,
+/*0a12*/ 0x00000000,
+/*0a13*/ 0x00000000,
+/*0a14*/ 0x0000002a,
+/*0a15*/ 0x00000015,
+/*0a16*/ 0x00000015,
+/*0a17*/ 0x0000002a,
+/*0a18*/ 0x00000033,
+/*0a19*/ 0x0000000c,
+/*0a1a*/ 0x0000000c,
+/*0a1b*/ 0x00000033,
+/*0a1c*/ 0x0a418820,
+/*0a1d*/ 0x003f0000,
+/*0a1e*/ 0x0000003f,
+/*0a1f*/ 0x0002c06e,
+/*0a20*/ 0x02c002c0,
+/*0a21*/ 0x02c002c0,
+/*0a22*/ 0x000002c0,
+/*0a23*/ 0x42080010,
+/*0a24*/ 0x00000003
+};
+
+static const uint32_t DDR_PHY_ADR_I_REGSET_M3[DDR_PHY_ADR_I_REGSET_NUM_M3] = {
+/*0a80*/ 0x04040404,
+/*0a81*/ 0x00000404,
+/*0a82*/ 0x00000000,
+/*0a83*/ 0x00000000,
+/*0a84*/ 0x00000000,
+/*0a85*/ 0x00000000,
+/*0a86*/ 0x00000002,
+/*0a87*/ 0x00000000,
+/*0a88*/ 0x00000000,
+/*0a89*/ 0x00000000,
+/*0a8a*/ 0x00400320,
+/*0a8b*/ 0x00000040,
+/*0a8c*/ 0x00000000,
+/*0a8d*/ 0x00000000,
+/*0a8e*/ 0x00000000,
+/*0a8f*/ 0x01000000,
+/*0a90*/ 0x00020003,
+/*0a91*/ 0x00000000,
+/*0a92*/ 0x00000000,
+/*0a93*/ 0x00000000,
+/*0a94*/ 0x0000002a,
+/*0a95*/ 0x00000015,
+/*0a96*/ 0x00000015,
+/*0a97*/ 0x0000002a,
+/*0a98*/ 0x00000033,
+/*0a99*/ 0x0000000c,
+/*0a9a*/ 0x0000000c,
+/*0a9b*/ 0x00000033,
+/*0a9c*/ 0x00000000,
+/*0a9d*/ 0x00000000,
+/*0a9e*/ 0x00000000,
+/*0a9f*/ 0x0002c06e,
+/*0aa0*/ 0x02c002c0,
+/*0aa1*/ 0x02c002c0,
+/*0aa2*/ 0x000002c0,
+/*0aa3*/ 0x42080010,
+/*0aa4*/ 0x00000003
+};
+
+static const uint32_t DDR_PHY_ADR_G_REGSET_M3[DDR_PHY_ADR_G_REGSET_NUM_M3] = {
+/*0b80*/ 0x00000001,
+/*0b81*/ 0x00000000,
+/*0b82*/ 0x00000005,
+/*0b83*/ 0x04000f00,
+/*0b84*/ 0x00020080,
+/*0b85*/ 0x00020055,
+/*0b86*/ 0x00000000,
+/*0b87*/ 0x00000000,
+/*0b88*/ 0x00000000,
+/*0b89*/ 0x00000050,
+/*0b8a*/ 0x00000000,
+/*0b8b*/ 0x01010100,
+/*0b8c*/ 0x00000600,
+/*0b8d*/ 0x50640000,
+/*0b8e*/ 0x01421142,
+/*0b8f*/ 0x00000142,
+/*0b90*/ 0x00000000,
+/*0b91*/ 0x000f1600,
+/*0b92*/ 0x0f160f16,
+/*0b93*/ 0x0f160f16,
+/*0b94*/ 0x00000003,
+/*0b95*/ 0x0002c000,
+/*0b96*/ 0x02c002c0,
+/*0b97*/ 0x000002c0,
+/*0b98*/ 0x03421342,
+/*0b99*/ 0x00000342,
+/*0b9a*/ 0x00000000,
+/*0b9b*/ 0x00000000,
+/*0b9c*/ 0x05020000,
+/*0b9d*/ 0x00000000,
+/*0b9e*/ 0x00027f6e,
+/*0b9f*/ 0x047f027f,
+/*0ba0*/ 0x00027f6e,
+/*0ba1*/ 0x00047f6e,
+/*0ba2*/ 0x0003554f,
+/*0ba3*/ 0x0001554f,
+/*0ba4*/ 0x0001554f,
+/*0ba5*/ 0x0001554f,
+/*0ba6*/ 0x0001554f,
+/*0ba7*/ 0x00003fee,
+/*0ba8*/ 0x0001554f,
+/*0ba9*/ 0x00003fee,
+/*0baa*/ 0x0001554f,
+/*0bab*/ 0x00027f6e,
+/*0bac*/ 0x0001554f,
+/*0bad*/ 0x00000000,
+/*0bae*/ 0x00000000,
+/*0baf*/ 0x00000000,
+/*0bb0*/ 0x65000000,
+/*0bb1*/ 0x00000000,
+/*0bb2*/ 0x00000000,
+/*0bb3*/ 0x00000201,
+/*0bb4*/ 0x00000000,
+/*0bb5*/ 0x00000000,
+/*0bb6*/ 0x00000000,
+/*0bb7*/ 0x00000000,
+/*0bb8*/ 0x00000000,
+/*0bb9*/ 0x00000000,
+/*0bba*/ 0x00000000,
+/*0bbb*/ 0x00000000,
+/*0bbc*/ 0x06e40000,
+/*0bbd*/ 0x00000000,
+/*0bbe*/ 0x00000000,
+/*0bbf*/ 0x00010000
+};
+
+static const uint32_t DDR_PI_REGSET_M3[DDR_PI_REGSET_NUM_M3] = {
+/*0200*/ 0x00000b00,
+/*0201*/ 0x00000100,
+/*0202*/ 0x00000000,
+/*0203*/ 0x0000ffff,
+/*0204*/ 0x00000000,
+/*0205*/ 0x0000ffff,
+/*0206*/ 0x00000000,
+/*0207*/ 0x304cffff,
+/*0208*/ 0x00000200,
+/*0209*/ 0x00000200,
+/*020a*/ 0x00000200,
+/*020b*/ 0x00000200,
+/*020c*/ 0x0000304c,
+/*020d*/ 0x00000200,
+/*020e*/ 0x00000200,
+/*020f*/ 0x00000200,
+/*0210*/ 0x00000200,
+/*0211*/ 0x0000304c,
+/*0212*/ 0x00000200,
+/*0213*/ 0x00000200,
+/*0214*/ 0x00000200,
+/*0215*/ 0x00000200,
+/*0216*/ 0x00010000,
+/*0217*/ 0x00000003,
+/*0218*/ 0x01000001,
+/*0219*/ 0x00000000,
+/*021a*/ 0x00000000,
+/*021b*/ 0x00000000,
+/*021c*/ 0x00000000,
+/*021d*/ 0x00000000,
+/*021e*/ 0x00000000,
+/*021f*/ 0x00000000,
+/*0220*/ 0x00000000,
+/*0221*/ 0x00000000,
+/*0222*/ 0x00000000,
+/*0223*/ 0x00000000,
+/*0224*/ 0x00000000,
+/*0225*/ 0x00000000,
+/*0226*/ 0x00000000,
+/*0227*/ 0x00000000,
+/*0228*/ 0x00000000,
+/*0229*/ 0x0f000101,
+/*022a*/ 0x08492d25,
+/*022b*/ 0x0e0c0004,
+/*022c*/ 0x000e5000,
+/*022d*/ 0x00000250,
+/*022e*/ 0x00460003,
+/*022f*/ 0x182600cf,
+/*0230*/ 0x182600cf,
+/*0231*/ 0x00000005,
+/*0232*/ 0x00000000,
+/*0233*/ 0x00000000,
+/*0234*/ 0x00000000,
+/*0235*/ 0x00000000,
+/*0236*/ 0x00000000,
+/*0237*/ 0x00000000,
+/*0238*/ 0x00000000,
+/*0239*/ 0x01000000,
+/*023a*/ 0x00040404,
+/*023b*/ 0x01280a00,
+/*023c*/ 0x00000000,
+/*023d*/ 0x000f0000,
+/*023e*/ 0x00001803,
+/*023f*/ 0x00000000,
+/*0240*/ 0x00000000,
+/*0241*/ 0x00060002,
+/*0242*/ 0x00010001,
+/*0243*/ 0x01000101,
+/*0244*/ 0x04020201,
+/*0245*/ 0x00080804,
+/*0246*/ 0x00000000,
+/*0247*/ 0x08030000,
+/*0248*/ 0x15150408,
+/*0249*/ 0x00000000,
+/*024a*/ 0x00000000,
+/*024b*/ 0x00000000,
+/*024c*/ 0x000f0f00,
+/*024d*/ 0x0000001e,
+/*024e*/ 0x00000000,
+/*024f*/ 0x01000300,
+/*0250*/ 0x00000000,
+/*0251*/ 0x00000000,
+/*0252*/ 0x01000000,
+/*0253*/ 0x00010101,
+/*0254*/ 0x000e0e0e,
+/*0255*/ 0x000c0c0c,
+/*0256*/ 0x02060601,
+/*0257*/ 0x00000000,
+/*0258*/ 0x00000003,
+/*0259*/ 0x00181703,
+/*025a*/ 0x00280006,
+/*025b*/ 0x00280016,
+/*025c*/ 0x00000016,
+/*025d*/ 0x00000000,
+/*025e*/ 0x00000000,
+/*025f*/ 0x00000000,
+/*0260*/ 0x140a0000,
+/*0261*/ 0x0005010a,
+/*0262*/ 0x03018d03,
+/*0263*/ 0x000a018d,
+/*0264*/ 0x00060100,
+/*0265*/ 0x01000006,
+/*0266*/ 0x018e018e,
+/*0267*/ 0x018e0100,
+/*0268*/ 0x1111018e,
+/*0269*/ 0x10010204,
+/*026a*/ 0x09090650,
+/*026b*/ 0x20110202,
+/*026c*/ 0x00201000,
+/*026d*/ 0x00201000,
+/*026e*/ 0x04041000,
+/*026f*/ 0x18020100,
+/*0270*/ 0x00010118,
+/*0271*/ 0x004b004a,
+/*0272*/ 0x050f0000,
+/*0273*/ 0x0c01021e,
+/*0274*/ 0x34000000,
+/*0275*/ 0x00000000,
+/*0276*/ 0x00000000,
+/*0277*/ 0x00000000,
+/*0278*/ 0x0000d400,
+/*0279*/ 0x0031002e,
+/*027a*/ 0x00111136,
+/*027b*/ 0x002e00d4,
+/*027c*/ 0x11360031,
+/*027d*/ 0x0000d411,
+/*027e*/ 0x0031002e,
+/*027f*/ 0x00111136,
+/*0280*/ 0x002e00d4,
+/*0281*/ 0x11360031,
+/*0282*/ 0x0000d411,
+/*0283*/ 0x0031002e,
+/*0284*/ 0x00111136,
+/*0285*/ 0x002e00d4,
+/*0286*/ 0x11360031,
+/*0287*/ 0x00d40011,
+/*0288*/ 0x0031002e,
+/*0289*/ 0x00111136,
+/*028a*/ 0x002e00d4,
+/*028b*/ 0x11360031,
+/*028c*/ 0x0000d411,
+/*028d*/ 0x0031002e,
+/*028e*/ 0x00111136,
+/*028f*/ 0x002e00d4,
+/*0290*/ 0x11360031,
+/*0291*/ 0x0000d411,
+/*0292*/ 0x0031002e,
+/*0293*/ 0x00111136,
+/*0294*/ 0x002e00d4,
+/*0295*/ 0x11360031,
+/*0296*/ 0x02000011,
+/*0297*/ 0x018d018d,
+/*0298*/ 0x0c08018d,
+/*0299*/ 0x1f121d22,
+/*029a*/ 0x4301b344,
+/*029b*/ 0x10172006,
+/*029c*/ 0x1d220c10,
+/*029d*/ 0x00001f12,
+/*029e*/ 0x4301b344,
+/*029f*/ 0x10172006,
+/*02a0*/ 0x1d220c10,
+/*02a1*/ 0x00001f12,
+/*02a2*/ 0x4301b344,
+/*02a3*/ 0x10172006,
+/*02a4*/ 0x02000210,
+/*02a5*/ 0x02000200,
+/*02a6*/ 0x02000200,
+/*02a7*/ 0x02000200,
+/*02a8*/ 0x02000200,
+/*02a9*/ 0x00000000,
+/*02aa*/ 0x00000000,
+/*02ab*/ 0x00000000,
+/*02ac*/ 0x00000000,
+/*02ad*/ 0x00000000,
+/*02ae*/ 0x00000000,
+/*02af*/ 0x00000000,
+/*02b0*/ 0x00000000,
+/*02b1*/ 0x00000000,
+/*02b2*/ 0x00000000,
+/*02b3*/ 0x00000000,
+/*02b4*/ 0x00000000,
+/*02b5*/ 0x00000400,
+/*02b6*/ 0x15141312,
+/*02b7*/ 0x11100f0e,
+/*02b8*/ 0x080b0c0d,
+/*02b9*/ 0x05040a09,
+/*02ba*/ 0x01000706,
+/*02bb*/ 0x00000302,
+/*02bc*/ 0x01030201,
+/*02bd*/ 0x00304c00,
+/*02be*/ 0x0001e2f8,
+/*02bf*/ 0x0000304c,
+/*02c0*/ 0x0001e2f8,
+/*02c1*/ 0x0000304c,
+/*02c2*/ 0x0001e2f8,
+/*02c3*/ 0x08000000,
+/*02c4*/ 0x00000100,
+/*02c5*/ 0x00000000,
+/*02c6*/ 0x00000000,
+/*02c7*/ 0x00000000,
+/*02c8*/ 0x00000000,
+/*02c9*/ 0x00000002
+};
diff --git a/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3n.h b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3n.h
new file mode 100644
index 0000000..42c3351
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3n.h
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define DDR_PHY_SLICE_REGSET_OFS_M3N  0x0800
+#define DDR_PHY_ADR_V_REGSET_OFS_M3N  0x0a00
+#define DDR_PHY_ADR_I_REGSET_OFS_M3N  0x0a80
+#define DDR_PHY_ADR_G_REGSET_OFS_M3N  0x0b80
+#define DDR_PI_REGSET_OFS_M3N         0x0200
+
+#define DDR_PHY_SLICE_REGSET_SIZE_M3N 0x80
+#define DDR_PHY_ADR_V_REGSET_SIZE_M3N 0x80
+#define DDR_PHY_ADR_I_REGSET_SIZE_M3N 0x80
+#define DDR_PHY_ADR_G_REGSET_SIZE_M3N 0x80
+#define DDR_PI_REGSET_SIZE_M3N        0x100
+
+#define DDR_PHY_SLICE_REGSET_NUM_M3N  101
+#define DDR_PHY_ADR_V_REGSET_NUM_M3N  37
+#define DDR_PHY_ADR_I_REGSET_NUM_M3N  37
+#define DDR_PHY_ADR_G_REGSET_NUM_M3N  87
+#define DDR_PI_REGSET_NUM_M3N         286
+
+static const uint32_t DDR_PHY_SLICE_REGSET_M3N[DDR_PHY_SLICE_REGSET_NUM_M3N] = {
+/*0800*/ 0x76543210,
+/*0801*/ 0x0004f008,
+/*0802*/ 0x00020200,
+/*0803*/ 0x00000000,
+/*0804*/ 0x00000000,
+/*0805*/ 0x00010000,
+/*0806*/ 0x036e6e0e,
+/*0807*/ 0x026e6e0e,
+/*0808*/ 0x00000103,
+/*0809*/ 0x00040001,
+/*080a*/ 0x00000103,
+/*080b*/ 0x00000001,
+/*080c*/ 0x00000000,
+/*080d*/ 0x00000000,
+/*080e*/ 0x00000100,
+/*080f*/ 0x001800c0,
+/*0810*/ 0x020100b0,
+/*0811*/ 0x00030020,
+/*0812*/ 0x00000000,
+/*0813*/ 0x00000000,
+/*0814*/ 0x0000aaaa,
+/*0815*/ 0x00005555,
+/*0816*/ 0x0000b5b5,
+/*0817*/ 0x00004a4a,
+/*0818*/ 0x00000000,
+/*0819*/ 0x09000000,
+/*081a*/ 0x04080000,
+/*081b*/ 0x08040000,
+/*081c*/ 0x00000004,
+/*081d*/ 0x00800710,
+/*081e*/ 0x000f000c,
+/*081f*/ 0x00000100,
+/*0820*/ 0x55aa55aa,
+/*0821*/ 0x33cc33cc,
+/*0822*/ 0x0ff00ff0,
+/*0823*/ 0x0f0ff0f0,
+/*0824*/ 0x00018e38,
+/*0825*/ 0x00000000,
+/*0826*/ 0x00000000,
+/*0827*/ 0x00000000,
+/*0828*/ 0x00000000,
+/*0829*/ 0x00000000,
+/*082a*/ 0x00000000,
+/*082b*/ 0x00000000,
+/*082c*/ 0x00000000,
+/*082d*/ 0x00000000,
+/*082e*/ 0x00000000,
+/*082f*/ 0x00000000,
+/*0830*/ 0x00000000,
+/*0831*/ 0x00000000,
+/*0832*/ 0x00000000,
+/*0833*/ 0x00000000,
+/*0834*/ 0x00000000,
+/*0835*/ 0x00000000,
+/*0836*/ 0x00000000,
+/*0837*/ 0x00000000,
+/*0838*/ 0x00000000,
+/*0839*/ 0x00000000,
+/*083a*/ 0x00000104,
+/*083b*/ 0x00082020,
+/*083c*/ 0x08200820,
+/*083d*/ 0x08200820,
+/*083e*/ 0x08200820,
+/*083f*/ 0x08200820,
+/*0840*/ 0x08200820,
+/*0841*/ 0x00000000,
+/*0842*/ 0x00000000,
+/*0843*/ 0x03000300,
+/*0844*/ 0x03000300,
+/*0845*/ 0x03000300,
+/*0846*/ 0x03000300,
+/*0847*/ 0x00000300,
+/*0848*/ 0x00000000,
+/*0849*/ 0x00000000,
+/*084a*/ 0x00000000,
+/*084b*/ 0x00000000,
+/*084c*/ 0x00000000,
+/*084d*/ 0x00a000a0,
+/*084e*/ 0x00a000a0,
+/*084f*/ 0x00a000a0,
+/*0850*/ 0x00a000a0,
+/*0851*/ 0x00a000a0,
+/*0852*/ 0x00a000a0,
+/*0853*/ 0x00a000a0,
+/*0854*/ 0x00a000a0,
+/*0855*/ 0x00a000a0,
+/*0856*/ 0x01040119,
+/*0857*/ 0x00000200,
+/*0858*/ 0x01000000,
+/*0859*/ 0x00000200,
+/*085a*/ 0x00000004,
+/*085b*/ 0x4041a141,
+/*085c*/ 0x0141c0a0,
+/*085d*/ 0x0000c0c0,
+/*085e*/ 0x0e0c000e,
+/*085f*/ 0x10001000,
+/*0860*/ 0x0c073e42,
+/*0861*/ 0x000f0c28,
+/*0862*/ 0x00e00140,
+/*0863*/ 0x000c0020,
+/*0864*/ 0x00000203
+};
+
+static const uint32_t DDR_PHY_ADR_V_REGSET_M3N[DDR_PHY_ADR_V_REGSET_NUM_M3N] = {
+/*0a00*/ 0x00000000,
+/*0a01*/ 0x00000000,
+/*0a02*/ 0x00000000,
+/*0a03*/ 0x00000000,
+/*0a04*/ 0x00000000,
+/*0a05*/ 0x00000000,
+/*0a06*/ 0x00000000,
+/*0a07*/ 0x01000000,
+/*0a08*/ 0x00020000,
+/*0a09*/ 0x00000000,
+/*0a0a*/ 0x00000000,
+/*0a0b*/ 0x00000000,
+/*0a0c*/ 0x00400000,
+/*0a0d*/ 0x00000080,
+/*0a0e*/ 0x00dcba98,
+/*0a0f*/ 0x03000000,
+/*0a10*/ 0x00000200,
+/*0a11*/ 0x00000000,
+/*0a12*/ 0x00000000,
+/*0a13*/ 0x00000000,
+/*0a14*/ 0x0000002a,
+/*0a15*/ 0x00000015,
+/*0a16*/ 0x00000015,
+/*0a17*/ 0x0000002a,
+/*0a18*/ 0x00000033,
+/*0a19*/ 0x0000000c,
+/*0a1a*/ 0x0000000c,
+/*0a1b*/ 0x00000033,
+/*0a1c*/ 0x0a418820,
+/*0a1d*/ 0x003f0000,
+/*0a1e*/ 0x0000013f,
+/*0a1f*/ 0x0002c06e,
+/*0a20*/ 0x02c002c0,
+/*0a21*/ 0x02c002c0,
+/*0a22*/ 0x000002c0,
+/*0a23*/ 0x42080010,
+/*0a24*/ 0x0000033e
+};
+
+static const uint32_t DDR_PHY_ADR_I_REGSET_M3N[DDR_PHY_ADR_I_REGSET_NUM_M3N] = {
+/*0a80*/ 0x00000000,
+/*0a81*/ 0x00000000,
+/*0a82*/ 0x00000000,
+/*0a83*/ 0x00000000,
+/*0a84*/ 0x00000000,
+/*0a85*/ 0x00000000,
+/*0a86*/ 0x00000000,
+/*0a87*/ 0x01000000,
+/*0a88*/ 0x00020000,
+/*0a89*/ 0x00000000,
+/*0a8a*/ 0x00000000,
+/*0a8b*/ 0x00000000,
+/*0a8c*/ 0x00400000,
+/*0a8d*/ 0x00000080,
+/*0a8e*/ 0x00000000,
+/*0a8f*/ 0x03000000,
+/*0a90*/ 0x00000200,
+/*0a91*/ 0x00000000,
+/*0a92*/ 0x00000000,
+/*0a93*/ 0x00000000,
+/*0a94*/ 0x0000002a,
+/*0a95*/ 0x00000015,
+/*0a96*/ 0x00000015,
+/*0a97*/ 0x0000002a,
+/*0a98*/ 0x00000033,
+/*0a99*/ 0x0000000c,
+/*0a9a*/ 0x0000000c,
+/*0a9b*/ 0x00000033,
+/*0a9c*/ 0x00000000,
+/*0a9d*/ 0x00000000,
+/*0a9e*/ 0x00000000,
+/*0a9f*/ 0x0002c06e,
+/*0aa0*/ 0x02c002c0,
+/*0aa1*/ 0x02c002c0,
+/*0aa2*/ 0x000002c0,
+/*0aa3*/ 0x42080010,
+/*0aa4*/ 0x0000033e
+};
+
+static const uint32_t DDR_PHY_ADR_G_REGSET_M3N[DDR_PHY_ADR_G_REGSET_NUM_M3N] = {
+/*0b80*/ 0x00000000,
+/*0b81*/ 0x00000100,
+/*0b82*/ 0x00000000,
+/*0b83*/ 0x00050000,
+/*0b84*/ 0x00000000,
+/*0b85*/ 0x0004000f,
+/*0b86*/ 0x00280080,
+/*0b87*/ 0x02005502,
+/*0b88*/ 0x00000000,
+/*0b89*/ 0x00000000,
+/*0b8a*/ 0x00000000,
+/*0b8b*/ 0x00000050,
+/*0b8c*/ 0x00000000,
+/*0b8d*/ 0x01010100,
+/*0b8e*/ 0x00010000,
+/*0b8f*/ 0x00000000,
+/*0b90*/ 0x00000101,
+/*0b91*/ 0x00000000,
+/*0b92*/ 0x00000000,
+/*0b93*/ 0x00000000,
+/*0b94*/ 0x00000000,
+/*0b95*/ 0x00005064,
+/*0b96*/ 0x01421142,
+/*0b97*/ 0x00000142,
+/*0b98*/ 0x00000000,
+/*0b99*/ 0x000f1600,
+/*0b9a*/ 0x0f160f16,
+/*0b9b*/ 0x0f160f16,
+/*0b9c*/ 0x00000003,
+/*0b9d*/ 0x0002c000,
+/*0b9e*/ 0x02c002c0,
+/*0b9f*/ 0x000002c0,
+/*0ba0*/ 0x08040201,
+/*0ba1*/ 0x03421342,
+/*0ba2*/ 0x00000342,
+/*0ba3*/ 0x00000000,
+/*0ba4*/ 0x00000000,
+/*0ba5*/ 0x05030000,
+/*0ba6*/ 0x00010700,
+/*0ba7*/ 0x00000014,
+/*0ba8*/ 0x00027f6e,
+/*0ba9*/ 0x047f027f,
+/*0baa*/ 0x00027f6e,
+/*0bab*/ 0x00047f6e,
+/*0bac*/ 0x0003554f,
+/*0bad*/ 0x0001554f,
+/*0bae*/ 0x0001554f,
+/*0baf*/ 0x0001554f,
+/*0bb0*/ 0x0001554f,
+/*0bb1*/ 0x00003fee,
+/*0bb2*/ 0x0001554f,
+/*0bb3*/ 0x00003fee,
+/*0bb4*/ 0x0001554f,
+/*0bb5*/ 0x00027f6e,
+/*0bb6*/ 0x0001554f,
+/*0bb7*/ 0x00004011,
+/*0bb8*/ 0x00004410,
+/*0bb9*/ 0x00000000,
+/*0bba*/ 0x00000000,
+/*0bbb*/ 0x00000000,
+/*0bbc*/ 0x00000265,
+/*0bbd*/ 0x00000000,
+/*0bbe*/ 0x00040401,
+/*0bbf*/ 0x00000000,
+/*0bc0*/ 0x03000000,
+/*0bc1*/ 0x00000020,
+/*0bc2*/ 0x00000000,
+/*0bc3*/ 0x00000000,
+/*0bc4*/ 0x04102006,
+/*0bc5*/ 0x00041020,
+/*0bc6*/ 0x01c98c98,
+/*0bc7*/ 0x00400000,
+/*0bc8*/ 0x00000000,
+/*0bc9*/ 0x0001ffff,
+/*0bca*/ 0x00000000,
+/*0bcb*/ 0x00000000,
+/*0bcc*/ 0x00000001,
+/*0bcd*/ 0x00000000,
+/*0bce*/ 0x00000000,
+/*0bcf*/ 0x00000000,
+/*0bd0*/ 0x76543210,
+/*0bd1*/ 0x06010198,
+/*0bd2*/ 0x00000000,
+/*0bd3*/ 0x00000000,
+/*0bd4*/ 0x04070000,
+/*0bd5*/ 0x00000001,
+/*0bd6*/ 0x00000f00
+};
+
+static const uint32_t DDR_PI_REGSET_M3N[DDR_PI_REGSET_NUM_M3N] = {
+/*0200*/ 0x00000b00,
+/*0201*/ 0x00000101,
+/*0202*/ 0x01640000,
+/*0203*/ 0x00000014,
+/*0204*/ 0x00000014,
+/*0205*/ 0x00000014,
+/*0206*/ 0x00000014,
+/*0207*/ 0x00000000,
+/*0208*/ 0x00000000,
+/*0209*/ 0x0000ffff,
+/*020a*/ 0x00000000,
+/*020b*/ 0x0000ffff,
+/*020c*/ 0x00000000,
+/*020d*/ 0x0000ffff,
+/*020e*/ 0x0000304c,
+/*020f*/ 0x00000200,
+/*0210*/ 0x00000200,
+/*0211*/ 0x00000200,
+/*0212*/ 0x00000200,
+/*0213*/ 0x0000304c,
+/*0214*/ 0x00000200,
+/*0215*/ 0x00000200,
+/*0216*/ 0x00000200,
+/*0217*/ 0x00000200,
+/*0218*/ 0x0000304c,
+/*0219*/ 0x00000200,
+/*021a*/ 0x00000200,
+/*021b*/ 0x00000200,
+/*021c*/ 0x00000200,
+/*021d*/ 0x00010000,
+/*021e*/ 0x00000003,
+/*021f*/ 0x01000001,
+/*0220*/ 0x00000000,
+/*0221*/ 0x00000000,
+/*0222*/ 0x00000000,
+/*0223*/ 0x00000000,
+/*0224*/ 0x00000000,
+/*0225*/ 0x00000000,
+/*0226*/ 0x00000000,
+/*0227*/ 0x00000000,
+/*0228*/ 0x00000000,
+/*0229*/ 0x00000000,
+/*022a*/ 0x00000000,
+/*022b*/ 0x00000000,
+/*022c*/ 0x00000000,
+/*022d*/ 0x00000000,
+/*022e*/ 0x00000000,
+/*022f*/ 0x00000000,
+/*0230*/ 0x0f000101,
+/*0231*/ 0x084d3129,
+/*0232*/ 0x0e0c0004,
+/*0233*/ 0x000e5000,
+/*0234*/ 0x01000250,
+/*0235*/ 0x00000003,
+/*0236*/ 0x00000046,
+/*0237*/ 0x000000cf,
+/*0238*/ 0x00001826,
+/*0239*/ 0x000000cf,
+/*023a*/ 0x00001826,
+/*023b*/ 0x00000000,
+/*023c*/ 0x00000000,
+/*023d*/ 0x00000000,
+/*023e*/ 0x00000000,
+/*023f*/ 0x00000000,
+/*0240*/ 0x00000000,
+/*0241*/ 0x00000000,
+/*0242*/ 0x00000000,
+/*0243*/ 0x00000000,
+/*0244*/ 0x00000000,
+/*0245*/ 0x01000000,
+/*0246*/ 0x00040404,
+/*0247*/ 0x01280a00,
+/*0248*/ 0x00000001,
+/*0249*/ 0x00000000,
+/*024a*/ 0x03000f00,
+/*024b*/ 0x00200020,
+/*024c*/ 0x00000020,
+/*024d*/ 0x00000000,
+/*024e*/ 0x00000000,
+/*024f*/ 0x00010002,
+/*0250*/ 0x01010001,
+/*0251*/ 0x02010100,
+/*0252*/ 0x08040402,
+/*0253*/ 0x00000008,
+/*0254*/ 0x00000000,
+/*0255*/ 0x04080803,
+/*0256*/ 0x00001515,
+/*0257*/ 0x00000000,
+/*0258*/ 0x000000aa,
+/*0259*/ 0x00000055,
+/*025a*/ 0x000000b5,
+/*025b*/ 0x0000004a,
+/*025c*/ 0x00000056,
+/*025d*/ 0x000000a9,
+/*025e*/ 0x000000a9,
+/*025f*/ 0x000000b5,
+/*0260*/ 0x00000000,
+/*0261*/ 0x00000000,
+/*0262*/ 0x0f000000,
+/*0263*/ 0x00001e0f,
+/*0264*/ 0x000007d0,
+/*0265*/ 0x01000300,
+/*0266*/ 0x00000100,
+/*0267*/ 0x00000000,
+/*0268*/ 0x00000000,
+/*0269*/ 0x01000000,
+/*026a*/ 0x00010101,
+/*026b*/ 0x000e0e0e,
+/*026c*/ 0x000c0c0c,
+/*026d*/ 0x01060601,
+/*026e*/ 0x04041717,
+/*026f*/ 0x00000004,
+/*0270*/ 0x00000300,
+/*0271*/ 0x17030000,
+/*0272*/ 0x00060018,
+/*0273*/ 0x00160028,
+/*0274*/ 0x00160028,
+/*0275*/ 0x00000000,
+/*0276*/ 0x00000000,
+/*0277*/ 0x00000000,
+/*0278*/ 0x0a000000,
+/*0279*/ 0x00010a14,
+/*027a*/ 0x00030005,
+/*027b*/ 0x0003018d,
+/*027c*/ 0x000a018d,
+/*027d*/ 0x00060100,
+/*027e*/ 0x01000006,
+/*027f*/ 0x018e018e,
+/*0280*/ 0x018e0100,
+/*0281*/ 0x1e1a018e,
+/*0282*/ 0x1e1a1e1a,
+/*0283*/ 0x01010204,
+/*0284*/ 0x06501001,
+/*0285*/ 0x090d0a07,
+/*0286*/ 0x090d0a07,
+/*0287*/ 0x0811180f,
+/*0288*/ 0x00ff1102,
+/*0289*/ 0x00ff1000,
+/*028a*/ 0x00ff1000,
+/*028b*/ 0x04041000,
+/*028c*/ 0x18020100,
+/*028d*/ 0x01010018,
+/*028e*/ 0x005f005f,
+/*028f*/ 0x005f005f,
+/*0290*/ 0x050f0000,
+/*0291*/ 0x051e051e,
+/*0292*/ 0x0c01021e,
+/*0293*/ 0x00000c0c,
+/*0294*/ 0x00003400,
+/*0295*/ 0x00000000,
+/*0296*/ 0x00000000,
+/*0297*/ 0x00000000,
+/*0298*/ 0x00000000,
+/*0299*/ 0x002e00d4,
+/*029a*/ 0x11360031,
+/*029b*/ 0x00d41611,
+/*029c*/ 0x0031002e,
+/*029d*/ 0x16111136,
+/*029e*/ 0x002e00d4,
+/*029f*/ 0x11360031,
+/*02a0*/ 0x00001611,
+/*02a1*/ 0x002e00d4,
+/*02a2*/ 0x11360031,
+/*02a3*/ 0x00d41611,
+/*02a4*/ 0x0031002e,
+/*02a5*/ 0x16111136,
+/*02a6*/ 0x002e00d4,
+/*02a7*/ 0x11360031,
+/*02a8*/ 0x00001611,
+/*02a9*/ 0x002e00d4,
+/*02aa*/ 0x11360031,
+/*02ab*/ 0x00d41611,
+/*02ac*/ 0x0031002e,
+/*02ad*/ 0x16111136,
+/*02ae*/ 0x002e00d4,
+/*02af*/ 0x11360031,
+/*02b0*/ 0x00001611,
+/*02b1*/ 0x002e00d4,
+/*02b2*/ 0x11360031,
+/*02b3*/ 0x00d41611,
+/*02b4*/ 0x0031002e,
+/*02b5*/ 0x16111136,
+/*02b6*/ 0x002e00d4,
+/*02b7*/ 0x11360031,
+/*02b8*/ 0x00001611,
+/*02b9*/ 0x00018d00,
+/*02ba*/ 0x018d018d,
+/*02bb*/ 0x1d220c08,
+/*02bc*/ 0x00001f12,
+/*02bd*/ 0x4301b344,
+/*02be*/ 0x17032006,
+/*02bf*/ 0x220c1010,
+/*02c0*/ 0x001f121d,
+/*02c1*/ 0x4301b344,
+/*02c2*/ 0x17062006,
+/*02c3*/ 0x220c1010,
+/*02c4*/ 0x001f121d,
+/*02c5*/ 0x4301b344,
+/*02c6*/ 0x17182006,
+/*02c7*/ 0x00021010,
+/*02c8*/ 0x00020002,
+/*02c9*/ 0x00020002,
+/*02ca*/ 0x00020002,
+/*02cb*/ 0x00020002,
+/*02cc*/ 0x00000002,
+/*02cd*/ 0x00000000,
+/*02ce*/ 0x00000000,
+/*02cf*/ 0x00000000,
+/*02d0*/ 0x00000000,
+/*02d1*/ 0x00000000,
+/*02d2*/ 0x00000000,
+/*02d3*/ 0x00000000,
+/*02d4*/ 0x00000000,
+/*02d5*/ 0x00000000,
+/*02d6*/ 0x00000000,
+/*02d7*/ 0x00000000,
+/*02d8*/ 0x00000000,
+/*02d9*/ 0x00000400,
+/*02da*/ 0x15141312,
+/*02db*/ 0x11100f0e,
+/*02dc*/ 0x080b0c0d,
+/*02dd*/ 0x05040a09,
+/*02de*/ 0x01000706,
+/*02df*/ 0x00000302,
+/*02e0*/ 0x01030201,
+/*02e1*/ 0x00304c08,
+/*02e2*/ 0x0001e2f8,
+/*02e3*/ 0x0000304c,
+/*02e4*/ 0x0001e2f8,
+/*02e5*/ 0x0000304c,
+/*02e6*/ 0x0001e2f8,
+/*02e7*/ 0x08000000,
+/*02e8*/ 0x00000100,
+/*02e9*/ 0x00000000,
+/*02ea*/ 0x00000000,
+/*02eb*/ 0x00000000,
+/*02ec*/ 0x00000000,
+/*02ed*/ 0x00010000,
+/*02ee*/ 0x00000000,
+/*02ef*/ 0x00000000,
+/*02f0*/ 0x00000000,
+/*02f1*/ 0x00000000,
+/*02f2*/ 0x00000000,
+/*02f3*/ 0x00000000,
+/*02f4*/ 0x00000000,
+/*02f5*/ 0x00000000,
+/*02f6*/ 0x00000000,
+/*02f7*/ 0x00000000,
+/*02f8*/ 0x00000000,
+/*02f9*/ 0x00000000,
+/*02fa*/ 0x00000000,
+/*02fb*/ 0x00000000,
+/*02fc*/ 0x00000000,
+/*02fd*/ 0x00000000,
+/*02fe*/ 0x00000000,
+/*02ff*/ 0x00000000,
+/*0300*/ 0x00000000,
+/*0301*/ 0x00000000,
+/*0302*/ 0x00000000,
+/*0303*/ 0x00000000,
+/*0304*/ 0x00000000,
+/*0305*/ 0x00000000,
+/*0306*/ 0x00000000,
+/*0307*/ 0x00000000,
+/*0308*/ 0x00000000,
+/*0309*/ 0x00000000,
+/*030a*/ 0x00000000,
+/*030b*/ 0x00000000,
+/*030c*/ 0x00000000,
+/*030d*/ 0x00000000,
+/*030e*/ 0x00000000,
+/*030f*/ 0x00050002,
+/*0310*/ 0x015c0057,
+/*0311*/ 0x01000100,
+/*0312*/ 0x01020001,
+/*0313*/ 0x00010300,
+/*0314*/ 0x05000104,
+/*0315*/ 0x01060001,
+/*0316*/ 0x00010700,
+/*0317*/ 0x00000000,
+/*0318*/ 0x00000000,
+/*0319*/ 0x00000001,
+/*031a*/ 0x00000000,
+/*031b*/ 0x00000000,
+/*031c*/ 0x00000000,
+/*031d*/ 0x20080101
+};
diff --git a/drivers/staging/renesas/rcar/ddr/dram_sub_func.c b/drivers/staging/renesas/rcar/ddr/dram_sub_func.c
new file mode 100644
index 0000000..6739b0d
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/dram_sub_func.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "dram_sub_func.h"
+
+#define PRR				(0xFFF00044U)
+#define PRR_PRODUCT_MASK		(0x00007F00U)
+#define PRR_CUT_MASK			(0x000000FFU)
+#define PRR_PRODUCT_H3			(0x00004F00U)	/* R-Car H3  */
+#define PRR_PRODUCT_M3			(0x00005200U)	/* R-Car M3  */
+#define PRR_PRODUCT_M3N			(0x00005500U)	/* R-Car M3N */
+#define PRR_PRODUCT_E3			(0x00005700U)	/* R-Car E3  */
+#define PRR_PRODUCT_V3H			(0x00005600U)	/* R-Car V3H */
+
+#if RCAR_SYSTEM_SUSPEND
+/* Local defines */
+#define DRAM_BACKUP_GPIO_USE		(0)
+#include "iic_dvfs.h"
+#if PMIC_ROHM_BD9571
+#define	PMIC_SLAVE_ADDR			(0x30U)
+#define	PMIC_BKUP_MODE_CNT		(0x20U)
+#define	PMIC_QLLM_CNT			(0x27U)
+#define	BIT_BKUP_CTRL_OUT		((uint8_t)(1U << 4U))
+#define	BIT_QLLM_DDR0_EN		((uint8_t)(1U << 0U))
+#define	BIT_QLLM_DDR1_EN		((uint8_t)(1U << 1U))
+#endif
+
+#define	GPIO_OUTDT1			(0xE6051008U)
+#define GPIO_INDT1			(0xE605100CU)
+#define GPIO_OUTDT3			(0xE6053008U)
+#define GPIO_INDT3			(0xE605300CU)
+#define GPIO_OUTDT6			(0xE6055408U)
+#define GPIO_INDT6			(0xE605540CU)
+
+#if DRAM_BACKUP_GPIO_USE == 1
+#define GPIO_BKUP_REQB_SHIFT_SALVATOR	(9U)	/* GP1_9 (BKUP_REQB) */
+#define GPIO_BKUP_REQB_SHIFT_EBISU	(14U)	/* GP6_14(BKUP_REQB) */
+#define GPIO_BKUP_REQB_SHIFT_CONDOR	(1U)	/* GP3_1 (BKUP_REQB) */
+#endif
+#define GPIO_BKUP_TRG_SHIFT_SALVATOR	(8U)	/* GP1_8 (BKUP_TRG) */
+#define GPIO_BKUP_TRG_SHIFT_EBISU	(13U)	/* GP6_13(BKUP_TRG) */
+#define GPIO_BKUP_TRG_SHIFT_CONDOR	(0U)	/* GP3_0 (BKUP_TRG) */
+
+#define DRAM_BKUP_TRG_LOOP_CNT	(1000U)
+#endif
+
+void rcar_dram_get_boot_status(uint32_t * status)
+{
+#if RCAR_SYSTEM_SUSPEND
+
+	uint32_t reg_data;
+	uint32_t product;
+	uint32_t shift;
+	uint32_t gpio;
+
+	product = mmio_read_32(PRR) & PRR_PRODUCT_MASK;
+	if (product == PRR_PRODUCT_V3H) {
+		shift = GPIO_BKUP_TRG_SHIFT_CONDOR;
+		gpio = GPIO_INDT3;
+	} else if (product == PRR_PRODUCT_E3) {
+		shift = GPIO_BKUP_TRG_SHIFT_EBISU;
+		gpio = GPIO_INDT6;
+	} else {
+		shift = GPIO_BKUP_TRG_SHIFT_SALVATOR;
+		gpio = GPIO_INDT1;
+	}
+
+	reg_data = mmio_read_32(gpio);
+	if (0U != (reg_data & ((uint32_t)1U << shift))) {
+		*status = DRAM_BOOT_STATUS_WARM;
+	} else {
+		*status = DRAM_BOOT_STATUS_COLD;
+	}
+#else	/* RCAR_SYSTEM_SUSPEND */
+	*status = DRAM_BOOT_STATUS_COLD;
+#endif	/* RCAR_SYSTEM_SUSPEND */
+}
+
+int32_t rcar_dram_update_boot_status(uint32_t status)
+{
+	int32_t ret = 0;
+#if RCAR_SYSTEM_SUSPEND
+	uint32_t reg_data;
+#if PMIC_ROHM_BD9571
+#if DRAM_BACKUP_GPIO_USE == 0
+	uint8_t bkup_mode_cnt = 0U;
+#else
+	uint32_t reqb, outd;
+#endif
+	uint8_t qllm_cnt = 0U;
+	int32_t i2c_dvfs_ret = -1;
+#endif
+	uint32_t loop_count;
+	uint32_t product;
+	uint32_t trg;
+	uint32_t gpio;
+
+	product = mmio_read_32(PRR) & PRR_PRODUCT_MASK;
+	if (product == PRR_PRODUCT_V3H) {
+#if DRAM_BACKUP_GPIO_USE == 1
+		reqb = GPIO_BKUP_REQB_SHIFT_CONDOR;
+		outd = GPIO_OUTDT3;
+#endif
+		trg = GPIO_BKUP_TRG_SHIFT_CONDOR;
+		gpio = GPIO_INDT3;
+	} else if (product == PRR_PRODUCT_E3) {
+#if DRAM_BACKUP_GPIO_USE == 1
+		reqb = GPIO_BKUP_REQB_SHIFT_EBISU;
+		outd = GPIO_OUTDT6;
+#endif
+		trg = GPIO_BKUP_TRG_SHIFT_EBISU;
+		gpio = GPIO_INDT6;
+	} else {
+#if DRAM_BACKUP_GPIO_USE == 1
+		reqb = GPIO_BKUP_REQB_SHIFT_SALVATOR;
+		outd = GPIO_OUTDT1;
+#endif
+		trg = GPIO_BKUP_TRG_SHIFT_SALVATOR;
+		gpio = GPIO_INDT1;
+	}
+
+	if (status == DRAM_BOOT_STATUS_WARM) {
+#if DRAM_BACKUP_GPIO_USE==1
+	mmio_setbits_32(outd, 1U << reqb);
+#else
+#if PMIC_ROHM_BD9571
+		/* Set BKUP_CRTL_OUT=High (BKUP mode cnt register) */
+		i2c_dvfs_ret = rcar_iic_dvfs_receive(PMIC_SLAVE_ADDR,
+				PMIC_BKUP_MODE_CNT, &bkup_mode_cnt);
+		if (0 != i2c_dvfs_ret) {
+			ERROR("BKUP mode cnt READ ERROR.\n");
+			ret = DRAM_UPDATE_STATUS_ERR;
+		} else {
+			bkup_mode_cnt &= (uint8_t)~BIT_BKUP_CTRL_OUT;
+			i2c_dvfs_ret = rcar_iic_dvfs_send(PMIC_SLAVE_ADDR,
+					PMIC_BKUP_MODE_CNT, bkup_mode_cnt);
+			if (0 != i2c_dvfs_ret) {
+				ERROR("BKUP mode cnt WRITE ERROR. "
+					"value = %d\n", bkup_mode_cnt);
+				ret = DRAM_UPDATE_STATUS_ERR;
+			}
+		}
+#endif /* PMIC_ROHM_BD9571 */
+#endif /* DRAM_BACKUP_GPIO_USE==1 */
+		/* Wait BKUP_TRG=Low */
+		loop_count = DRAM_BKUP_TRG_LOOP_CNT;
+		while (0U < loop_count) {
+			reg_data = mmio_read_32(gpio);
+			if ((reg_data &
+				((uint32_t)1U << trg)) == 0U) {
+				break;
+			}
+			loop_count--;
+		}
+		if (0U == loop_count) {
+			ERROR(	"\nWarm booting...\n" \
+				" The potential of BKUP_TRG did not switch " \
+				"to Low.\n If you expect the operation of " \
+				"cold boot,\n check the board configuration" \
+				" (ex, Dip-SW) and/or the H/W failure.\n");
+			ret = DRAM_UPDATE_STATUS_ERR;
+		}
+	}
+#if PMIC_ROHM_BD9571
+	if(0 == ret) {
+		qllm_cnt = (BIT_QLLM_DDR0_EN | BIT_QLLM_DDR1_EN);
+		i2c_dvfs_ret = rcar_iic_dvfs_send(PMIC_SLAVE_ADDR,
+				PMIC_QLLM_CNT, qllm_cnt);
+		if (0 != i2c_dvfs_ret) {
+			ERROR("QLLM cnt WRITE ERROR. "
+				"value = %d\n", qllm_cnt);
+			ret = DRAM_UPDATE_STATUS_ERR;
+		}
+	}
+#endif
+#endif
+	return ret;
+}
diff --git a/drivers/staging/renesas/rcar/ddr/dram_sub_func.h b/drivers/staging/renesas/rcar/ddr/dram_sub_func.h
new file mode 100644
index 0000000..7e88f42
--- /dev/null
+++ b/drivers/staging/renesas/rcar/ddr/dram_sub_func.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_SUB_FUNC_H
+#define DRAM_SUB_FUNC_H
+
+#define DRAM_UPDATE_STATUS_ERR	(-1)
+#define DRAM_BOOT_STATUS_COLD	(0)
+#define DRAM_BOOT_STATUS_WARM	(1)
+
+int32_t rcar_dram_update_boot_status(uint32_t status);
+void rcar_dram_get_boot_status(uint32_t * status);
+
+#endif /* DRAM_SUB_FUNC_H */
diff --git a/drivers/synopsys/emmc/dw_mmc.c b/drivers/synopsys/emmc/dw_mmc.c
new file mode 100644
index 0000000..04f4673
--- /dev/null
+++ b/drivers/synopsys/emmc/dw_mmc.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/utils_def.h>
+#include <lib/mmio.h>
+
+#define DWMMC_CTRL			(0x00)
+#define CTRL_IDMAC_EN			(1 << 25)
+#define CTRL_DMA_EN			(1 << 5)
+#define CTRL_INT_EN			(1 << 4)
+#define CTRL_DMA_RESET			(1 << 2)
+#define CTRL_FIFO_RESET			(1 << 1)
+#define CTRL_RESET			(1 << 0)
+#define CTRL_RESET_ALL			(CTRL_DMA_RESET | CTRL_FIFO_RESET | \
+					 CTRL_RESET)
+
+#define DWMMC_PWREN			(0x04)
+#define DWMMC_CLKDIV			(0x08)
+#define DWMMC_CLKSRC			(0x0c)
+#define DWMMC_CLKENA			(0x10)
+#define DWMMC_TMOUT			(0x14)
+#define DWMMC_CTYPE			(0x18)
+#define CTYPE_8BIT			(1 << 16)
+#define CTYPE_4BIT			(1)
+#define CTYPE_1BIT			(0)
+
+#define DWMMC_BLKSIZ			(0x1c)
+#define DWMMC_BYTCNT			(0x20)
+#define DWMMC_INTMASK			(0x24)
+#define INT_EBE				(1 << 15)
+#define INT_SBE				(1 << 13)
+#define INT_HLE				(1 << 12)
+#define INT_FRUN			(1 << 11)
+#define INT_DRT				(1 << 9)
+#define INT_RTO				(1 << 8)
+#define INT_DCRC			(1 << 7)
+#define INT_RCRC			(1 << 6)
+#define INT_RXDR			(1 << 5)
+#define INT_TXDR			(1 << 4)
+#define INT_DTO				(1 << 3)
+#define INT_CMD_DONE			(1 << 2)
+#define INT_RE				(1 << 1)
+
+#define DWMMC_CMDARG			(0x28)
+#define DWMMC_CMD			(0x2c)
+#define CMD_START			(U(1) << 31)
+#define CMD_USE_HOLD_REG		(1 << 29)	/* 0 if SDR50/100 */
+#define CMD_UPDATE_CLK_ONLY		(1 << 21)
+#define CMD_SEND_INIT			(1 << 15)
+#define CMD_STOP_ABORT_CMD		(1 << 14)
+#define CMD_WAIT_PRVDATA_COMPLETE	(1 << 13)
+#define CMD_WRITE			(1 << 10)
+#define CMD_DATA_TRANS_EXPECT		(1 << 9)
+#define CMD_CHECK_RESP_CRC		(1 << 8)
+#define CMD_RESP_LEN			(1 << 7)
+#define CMD_RESP_EXPECT			(1 << 6)
+#define CMD(x)				(x & 0x3f)
+
+#define DWMMC_RESP0			(0x30)
+#define DWMMC_RESP1			(0x34)
+#define DWMMC_RESP2			(0x38)
+#define DWMMC_RESP3			(0x3c)
+#define DWMMC_RINTSTS			(0x44)
+#define DWMMC_STATUS			(0x48)
+#define STATUS_DATA_BUSY		(1 << 9)
+
+#define DWMMC_FIFOTH			(0x4c)
+#define FIFOTH_TWMARK(x)		(x & 0xfff)
+#define FIFOTH_RWMARK(x)		((x & 0x1ff) << 16)
+#define FIFOTH_DMA_BURST_SIZE(x)	((x & 0x7) << 28)
+
+#define DWMMC_DEBNCE			(0x64)
+#define DWMMC_BMOD			(0x80)
+#define BMOD_ENABLE			(1 << 7)
+#define BMOD_FB				(1 << 1)
+#define BMOD_SWRESET			(1 << 0)
+
+#define DWMMC_DBADDR			(0x88)
+#define DWMMC_IDSTS			(0x8c)
+#define DWMMC_IDINTEN			(0x90)
+#define DWMMC_CARDTHRCTL		(0x100)
+#define CARDTHRCTL_RD_THR(x)		((x & 0xfff) << 16)
+#define CARDTHRCTL_RD_THR_EN		(1 << 0)
+
+#define IDMAC_DES0_DIC			(1 << 1)
+#define IDMAC_DES0_LD			(1 << 2)
+#define IDMAC_DES0_FS			(1 << 3)
+#define IDMAC_DES0_CH			(1 << 4)
+#define IDMAC_DES0_ER			(1 << 5)
+#define IDMAC_DES0_CES			(1 << 30)
+#define IDMAC_DES0_OWN			(U(1) << 31)
+#define IDMAC_DES1_BS1(x)		((x) & 0x1fff)
+#define IDMAC_DES2_BS2(x)		(((x) & 0x1fff) << 13)
+
+#define DWMMC_DMA_MAX_BUFFER_SIZE	(512 * 8)
+
+#define DWMMC_8BIT_MODE			(1 << 6)
+
+#define DWMMC_ADDRESS_MASK		U(0x0f)
+
+#define TIMEOUT				100000
+
+struct dw_idmac_desc {
+	unsigned int	des0;
+	unsigned int	des1;
+	unsigned int	des2;
+	unsigned int	des3;
+};
+
+static void dw_init(void);
+static int dw_send_cmd(struct mmc_cmd *cmd);
+static int dw_set_ios(unsigned int clk, unsigned int width);
+static int dw_prepare(int lba, uintptr_t buf, size_t size);
+static int dw_read(int lba, uintptr_t buf, size_t size);
+static int dw_write(int lba, uintptr_t buf, size_t size);
+
+static const struct mmc_ops dw_mmc_ops = {
+	.init		= dw_init,
+	.send_cmd	= dw_send_cmd,
+	.set_ios	= dw_set_ios,
+	.prepare	= dw_prepare,
+	.read		= dw_read,
+	.write		= dw_write,
+};
+
+static dw_mmc_params_t dw_params;
+
+static void dw_update_clk(void)
+{
+	unsigned int data;
+
+	mmio_write_32(dw_params.reg_base + DWMMC_CMD,
+		      CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
+		      CMD_START);
+	while (1) {
+		data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
+		if ((data & CMD_START) == 0)
+			break;
+		data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
+		assert((data & INT_HLE) == 0);
+	}
+}
+
+static void dw_set_clk(int clk)
+{
+	unsigned int data;
+	int div;
+
+	assert(clk > 0);
+
+	for (div = 1; div < 256; div++) {
+		if ((dw_params.clk_rate / (2 * div)) <= clk) {
+			break;
+		}
+	}
+	assert(div < 256);
+
+	/* wait until controller is idle */
+	do {
+		data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
+	} while (data & STATUS_DATA_BUSY);
+
+	/* disable clock before change clock rate */
+	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
+	dw_update_clk();
+
+	mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
+	dw_update_clk();
+
+	/* enable clock */
+	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
+	mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
+	dw_update_clk();
+}
+
+static void dw_init(void)
+{
+	unsigned int data;
+	uintptr_t base;
+
+	assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0);
+
+	base = dw_params.reg_base;
+	mmio_write_32(base + DWMMC_PWREN, 1);
+	mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
+	do {
+		data = mmio_read_32(base + DWMMC_CTRL);
+	} while (data);
+
+	/* enable DMA in CTRL */
+	data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
+	mmio_write_32(base + DWMMC_CTRL, data);
+	mmio_write_32(base + DWMMC_RINTSTS, ~0);
+	mmio_write_32(base + DWMMC_INTMASK, 0);
+	mmio_write_32(base + DWMMC_TMOUT, ~0);
+	mmio_write_32(base + DWMMC_IDINTEN, ~0);
+	mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
+	mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
+	mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
+	mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
+	do {
+		data = mmio_read_32(base + DWMMC_BMOD);
+	} while (data & BMOD_SWRESET);
+	/* enable DMA in BMOD */
+	data |= BMOD_ENABLE | BMOD_FB;
+	mmio_write_32(base + DWMMC_BMOD, data);
+
+	udelay(100);
+	dw_set_clk(MMC_BOOT_CLK_RATE);
+	udelay(100);
+}
+
+static int dw_send_cmd(struct mmc_cmd *cmd)
+{
+	unsigned int op, data, err_mask;
+	uintptr_t base;
+	int timeout;
+
+	assert(cmd);
+
+	base = dw_params.reg_base;
+
+	switch (cmd->cmd_idx) {
+	case 0:
+		op = CMD_SEND_INIT;
+		break;
+	case 12:
+		op = CMD_STOP_ABORT_CMD;
+		break;
+	case 13:
+		op = CMD_WAIT_PRVDATA_COMPLETE;
+		break;
+	case 8:
+		if (dw_params.mmc_dev_type == MMC_IS_EMMC)
+			op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
+		else
+			op = CMD_WAIT_PRVDATA_COMPLETE;
+		break;
+	case 17:
+	case 18:
+		op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
+		break;
+	case 24:
+	case 25:
+		op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
+		     CMD_WAIT_PRVDATA_COMPLETE;
+		break;
+	case 51:
+		op = CMD_DATA_TRANS_EXPECT;
+		break;
+	default:
+		op = 0;
+		break;
+	}
+	op |= CMD_USE_HOLD_REG | CMD_START;
+	switch (cmd->resp_type) {
+	case 0:
+		break;
+	case MMC_RESPONSE_R2:
+		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
+		      CMD_RESP_LEN;
+		break;
+	case MMC_RESPONSE_R3:
+		op |= CMD_RESP_EXPECT;
+		break;
+	default:
+		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
+		break;
+	}
+	timeout = TIMEOUT;
+	do {
+		data = mmio_read_32(base + DWMMC_STATUS);
+		if (--timeout <= 0)
+			panic();
+	} while (data & STATUS_DATA_BUSY);
+
+	mmio_write_32(base + DWMMC_RINTSTS, ~0);
+	mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
+	mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
+
+	err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
+		   INT_DCRC | INT_DRT | INT_SBE;
+	timeout = TIMEOUT;
+	do {
+		udelay(500);
+		data = mmio_read_32(base + DWMMC_RINTSTS);
+
+		if (data & err_mask)
+			return -EIO;
+		if (data & INT_DTO)
+			break;
+		if (--timeout == 0) {
+			ERROR("%s, RINTSTS:0x%x\n", __func__, data);
+			panic();
+		}
+	} while (!(data & INT_CMD_DONE));
+
+	if (op & CMD_RESP_EXPECT) {
+		cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
+		if (op & CMD_RESP_LEN) {
+			cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
+			cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
+			cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
+		}
+	}
+	return 0;
+}
+
+static int dw_set_ios(unsigned int clk, unsigned int width)
+{
+	switch (width) {
+	case MMC_BUS_WIDTH_1:
+		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
+		break;
+	case MMC_BUS_WIDTH_4:
+		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
+		break;
+	case MMC_BUS_WIDTH_8:
+		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
+		break;
+	default:
+		assert(0);
+		break;
+	}
+	dw_set_clk(clk);
+	return 0;
+}
+
+static int dw_prepare(int lba, uintptr_t buf, size_t size)
+{
+	struct dw_idmac_desc *desc;
+	int desc_cnt, i, last;
+	uintptr_t base;
+
+	assert(((buf & DWMMC_ADDRESS_MASK) == 0) &&
+	       (dw_params.desc_size > 0) &&
+	       ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) &&
+	       ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) &&
+	       ((dw_params.desc_size & MMC_BLOCK_MASK) == 0));
+
+	flush_dcache_range(buf, size);
+
+	desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
+		   DWMMC_DMA_MAX_BUFFER_SIZE;
+	assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
+
+	base = dw_params.reg_base;
+	desc = (struct dw_idmac_desc *)dw_params.desc_base;
+	mmio_write_32(base + DWMMC_BYTCNT, size);
+
+	if (size < MMC_BLOCK_SIZE)
+		mmio_write_32(base + DWMMC_BLKSIZ, size);
+	else
+		mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
+
+	mmio_write_32(base + DWMMC_RINTSTS, ~0);
+	for (i = 0; i < desc_cnt; i++) {
+		desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
+		desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
+		desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
+		desc[i].des3 = dw_params.desc_base +
+			       (sizeof(struct dw_idmac_desc)) * (i + 1);
+	}
+	/* first descriptor */
+	desc->des0 |= IDMAC_DES0_FS;
+	/* last descriptor */
+	last = desc_cnt - 1;
+	(desc + last)->des0 |= IDMAC_DES0_LD;
+	(desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
+	(desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
+				  DWMMC_DMA_MAX_BUFFER_SIZE));
+	/* set next descriptor address as 0 */
+	(desc + last)->des3 = 0;
+
+	mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
+	flush_dcache_range(dw_params.desc_base,
+			   desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
+
+
+	return 0;
+}
+
+static int dw_read(int lba, uintptr_t buf, size_t size)
+{
+	uint32_t data = 0;
+	int timeout = TIMEOUT;
+
+	do {
+		data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
+		udelay(50);
+	} while (!(data & INT_DTO) && timeout-- > 0);
+
+	inv_dcache_range(buf, size);
+
+	return 0;
+}
+
+static int dw_write(int lba, uintptr_t buf, size_t size)
+{
+	return 0;
+}
+
+void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info)
+{
+	assert((params != 0) &&
+	       ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
+	       ((params->desc_base & MMC_BLOCK_MASK) == 0) &&
+	       ((params->desc_size & MMC_BLOCK_MASK) == 0) &&
+	       (params->desc_size > 0) &&
+	       (params->clk_rate > 0) &&
+	       ((params->bus_width == MMC_BUS_WIDTH_1) ||
+		(params->bus_width == MMC_BUS_WIDTH_4) ||
+		(params->bus_width == MMC_BUS_WIDTH_8)));
+
+	memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
+	dw_params.mmc_dev_type = info->mmc_dev_type;
+	mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
+		 params->flags, info);
+}
diff --git a/drivers/synopsys/ufs/dw_ufs.c b/drivers/synopsys/ufs/dw_ufs.c
new file mode 100644
index 0000000..6bed981
--- /dev/null
+++ b/drivers/synopsys/ufs/dw_ufs.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+
+static int dwufs_phy_init(ufs_params_t *params)
+{
+	uintptr_t base;
+	unsigned int fsm0, fsm1;
+	unsigned int data;
+	int result;
+
+	assert((params != NULL) && (params->reg_base != 0));
+
+	base = params->reg_base;
+
+	/* Unipro VS_MPHY disable */
+	ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, VS_MPHY_DISABLE_MPHYDIS);
+	ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2);
+	/* MPHY CBRATESEL */
+	ufshc_dme_set(0x8114, 0, 1);
+	/* MPHY CBOVRCTRL2 */
+	ufshc_dme_set(0x8121, 0, 0x2d);
+	/* MPHY CBOVRCTRL3 */
+	ufshc_dme_set(0x8122, 0, 0x1);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	/* MPHY RXOVRCTRL4 rx0 */
+	ufshc_dme_set(0x800d, 4, 0x58);
+	/* MPHY RXOVRCTRL4 rx1 */
+	ufshc_dme_set(0x800d, 5, 0x58);
+	/* MPHY RXOVRCTRL5 rx0 */
+	ufshc_dme_set(0x800e, 4, 0xb);
+	/* MPHY RXOVRCTRL5 rx1 */
+	ufshc_dme_set(0x800e, 5, 0xb);
+	/* MPHY RXSQCONTROL rx0 */
+	ufshc_dme_set(0x8009, 4, 0x1);
+	/* MPHY RXSQCONTROL rx1 */
+	ufshc_dme_set(0x8009, 5, 0x1);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	ufshc_dme_set(0x8113, 0, 0x1);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a);
+	ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a);
+	ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a);
+	ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a);
+	ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 4, 0x7);
+	ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 5, 0x7);
+	ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 0, 0x5);
+	ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 1, 0x5);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	result = ufshc_dme_get(VS_MPHY_DISABLE_OFFSET, 0, &data);
+	assert((result == 0) && (data == VS_MPHY_DISABLE_MPHYDIS));
+	/* enable Unipro VS MPHY */
+	ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, 0);
+
+	while (1) {
+		result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 0, &fsm0);
+		assert(result == 0);
+		result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 1, &fsm1);
+		assert(result == 0);
+		if ((fsm0 == TX_FSM_STATE_HIBERN8) &&
+		    (fsm1 == TX_FSM_STATE_HIBERN8))
+			break;
+	}
+
+	mmio_write_32(base + HCLKDIV, 0xE4);
+	mmio_clrbits_32(base + AHIT, 0x3FF);
+
+	ufshc_dme_set(PA_LOCAL_TX_LCC_ENABLE_OFFSET, 0, 0);
+	ufshc_dme_set(VS_MK2_EXTN_SUPPORT_OFFSET, 0, 0);
+
+	result = ufshc_dme_get(VS_MK2_EXTN_SUPPORT_OFFSET, 0, &data);
+	assert((result == 0) && (data == 0));
+
+	ufshc_dme_set(DL_AFC0_CREDIT_THRESHOLD_OFFSET, 0, 0);
+	ufshc_dme_set(DL_TC0_OUT_ACK_THRESHOLD_OFFSET, 0, 0);
+	ufshc_dme_set(DL_TC0_TX_FC_THRESHOLD_OFFSET, 0, 9);
+	(void)result;
+	return 0;
+}
+
+static int dwufs_phy_set_pwr_mode(ufs_params_t *params)
+{
+	int result;
+	unsigned int data, tx_lanes, rx_lanes;
+	uintptr_t base;
+	unsigned int flags;
+
+	assert((params != NULL) && (params->reg_base != 0));
+
+	base = params->reg_base;
+	flags = params->flags;
+	if ((flags & UFS_FLAGS_VENDOR_SKHYNIX) != 0U) {
+		NOTICE("ufs: H**** device must set VS_DebugSaveConfigTime 0x10\n");
+		/* VS_DebugSaveConfigTime */
+		result = ufshc_dme_set(0xd0a0, 0x0, 0x10);
+		assert(result == 0);
+		/* sync length */
+		result = ufshc_dme_set(0x1556, 0x0, 0x48);
+		assert(result == 0);
+	}
+
+	result = ufshc_dme_get(PA_TACTIVATE_OFFSET, 0, &data);
+	assert(result == 0);
+	if (data < 7) {
+		result = ufshc_dme_set(PA_TACTIVATE_OFFSET, 0, 7);
+		assert(result == 0);
+	}
+	result = ufshc_dme_get(PA_CONNECTED_TX_DATA_LANES_OFFSET, 0, &tx_lanes);
+	assert(result == 0);
+	result = ufshc_dme_get(PA_CONNECTED_RX_DATA_LANES_OFFSET, 0, &rx_lanes);
+	assert(result == 0);
+
+	result = ufshc_dme_set(PA_TX_SKIP_OFFSET, 0, 0);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_TX_GEAR_OFFSET, 0, 3);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_RX_GEAR_OFFSET, 0, 3);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_TX_TERMINATION_OFFSET, 0, 1);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_RX_TERMINATION_OFFSET, 0, 1);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_SCRAMBLING_OFFSET, 0, 0);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_ACTIVE_TX_DATA_LANES_OFFSET, 0, tx_lanes);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_ACTIVE_RX_DATA_LANES_OFFSET, 0, rx_lanes);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA0_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA1_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA2_OFFSET, 0, 32767);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_FC0_PROTECTION_TIMEOUT_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_TC0_REPLAY_TIMEOUT_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_AFC0_REQ_TIMEOUT_OFFSET, 0, 32767);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA3_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA4_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA5_OFFSET, 0, 32767);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_FC1_PROTECTION_TIMEOUT_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_TC1_REPLAY_TIMEOUT_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_AFC1_REQ_TIMEOUT_OFFSET, 0, 32767);
+	assert(result == 0);
+
+	result = ufshc_dme_set(PA_PWR_MODE_OFFSET, 0, 0x11);
+	assert(result == 0);
+	do {
+		data = mmio_read_32(base + IS);
+	} while ((data & UFS_INT_UPMS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UPMS);
+	data = mmio_read_32(base + HCS);
+	if ((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL)
+		INFO("ufs: change power mode success\n");
+	else
+		WARN("ufs: HCS.UPMCRS error, HCS:0x%x\n", data);
+	(void)result;
+	return 0;
+}
+
+static const ufs_ops_t dw_ufs_ops = {
+	.phy_init		= dwufs_phy_init,
+	.phy_set_pwr_mode	= dwufs_phy_set_pwr_mode,
+};
+
+int dw_ufs_init(dw_ufs_params_t *params)
+{
+	ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params));
+	ufs_params.reg_base = params->reg_base;
+	ufs_params.desc_base = params->desc_base;
+	ufs_params.desc_size = params->desc_size;
+	ufs_params.flags = params->flags;
+	ufs_init(&dw_ufs_ops, &ufs_params);
+	return 0;
+}
diff --git a/drivers/ti/uart/aarch32/16550_console.S b/drivers/ti/uart/aarch32/16550_console.S
new file mode 100644
index 0000000..6921884
--- /dev/null
+++ b/drivers/ti/uart/aarch32/16550_console.S
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/ti/uart/uart_16550.h>
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_16550_core_init
+	.globl console_16550_core_putc
+	.globl console_16550_core_getc
+	.globl console_16550_core_flush
+
+	.globl console_16550_putc
+	.globl console_16550_getc
+	.globl console_16550_flush
+
+	/* -----------------------------------------------
+	 * int console_16550_core_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: r0 - console base address
+	 *     r1 - Uart clock in Hz
+	 *     r2 - Baud rate
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : r1, r2, r3
+	 * -----------------------------------------------
+	 */
+func console_16550_core_init
+	/* Check the input base address */
+	cmp	r0, #0
+	beq	init_fail
+	/* Check baud rate and uart clock for sanity */
+	cmp	r1, #0
+	beq	init_fail
+	cmp	r2, #0
+	beq	init_fail
+
+	/* Program the baudrate */
+	/* Divisor =  Uart clock / (16 * baudrate) */
+	lsl	r2, r2, #4
+	udiv	r2, r1, r2
+	and	r1, r2, #0xff		/* w1 = DLL */
+	lsr	r2, r2, #8
+	and	r2, r2, #0xff		/* w2 = DLLM */
+	ldr	r3, [r0, #UARTLCR]
+	orr	r3, r3, #UARTLCR_DLAB
+	str	r3, [r0, #UARTLCR]	/* enable DLL, DLLM programming */
+	str	r1, [r0, #UARTDLL]	/* program DLL */
+	str	r2, [r0, #UARTDLLM]	/* program DLLM */
+	mov	r2, #~UARTLCR_DLAB
+	and	r3, r3, r2
+	str	r3, [r0, #UARTLCR]	/* disable DLL, DLLM programming */
+
+	/* 8n1 */
+	mov	r3, #3
+	str	r3, [r0, #UARTLCR]
+	/* no interrupt */
+	mov	r3, #0
+	str	r3, [r0, #UARTIER]
+#ifdef TI_16550_MDR_QUIRK
+	/* UART must be enabled on some platforms via the MDR register */
+	str	r3, [r0, #UARTMDR1]
+#endif /* TI_16550_MDR_QUIRK */
+	/* enable fifo, DMA */
+	mov	r3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN)
+	str	r3, [r0, #UARTFCR]
+	/* DTR + RTS */
+	mov	r3, #3
+	str	r3, [r0, #UARTMCR]
+	mov	r0, #1
+	bx	lr
+init_fail:
+	mov	r0, #0
+	bx	lr
+endfunc console_16550_core_init
+
+	.globl console_16550_register
+
+	/* -------------------------------------------------------
+	 * int console_stm32_register(uintptr_t baseaddr,
+	 *     uint32_t clock, uint32_t baud,
+	 *     struct console_stm32 *console);
+	 * Function to initialize and register a new STM32
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: r0 - UART register base address
+	 *     r1 - UART clock in Hz
+	 *     r2 - Baud rate
+	 *     r3 - pointer to empty console_stm32 struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : r0, r1, r2
+	 * -------------------------------------------------------
+	 */
+func console_16550_register
+	push	{r4, lr}
+	mov	r4, r3
+	cmp	r4, #0
+	beq	register_fail
+	str	r0, [r4, #CONSOLE_T_16550_BASE]
+
+	bl	console_16550_core_init
+	cmp	r0, #0
+	beq	register_fail
+
+	mov	r0, r4
+	pop	{r4, lr}
+	finish_console_register 16550 putc=1, getc=1, flush=1
+
+register_fail:
+	pop	{r4, pc}
+endfunc console_16550_register
+
+	/* --------------------------------------------------------
+	 * int console_16550_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : r0 - character to be printed
+	 *      r1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : r2
+	 * --------------------------------------------------------
+	 */
+func console_16550_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	r1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Prepend '\r' to '\n' */
+	cmp	r0, #0xA
+	bne	2f
+	/* Check if the transmit FIFO is full */
+1:	ldr	r2, [r1, #UARTLSR]
+	and	r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	r2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	bne	1b
+	mov	r2, #0xD		/* '\r' */
+	str	r2, [r1, #UARTTX]
+
+	/* Check if the transmit FIFO is full */
+2:	ldr	r2, [r1, #UARTLSR]
+	and	r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	r2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	bne	2b
+	str	r0, [r1, #UARTTX]
+	bx	lr
+endfunc console_16550_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_16550_putc(int c, console_16550_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : r0 - character to be printed
+	 *      r1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : r2
+	 * --------------------------------------------------------
+	 */
+func console_16550_putc
+#if ENABLE_ASSERTIONS
+	cmp	r1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r1, [r1, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_putc
+endfunc console_16550_putc
+
+	/* ---------------------------------------------
+	 * int console_16550_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  r0 - console base address
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_16550_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Check if the receive FIFO is empty */
+1:	ldr	r1, [r0, #UARTLSR]
+	tst	r1, #UARTLSR_RDR_BIT
+	beq	no_char
+	ldr	r1, [r0, #UARTRX]
+	mov	r0, r1
+	bx	lr
+no_char:
+	mov	r0, #ERROR_NO_PENDING_CHAR
+	bx	lr
+endfunc console_16550_core_getc
+
+	/* ---------------------------------------------
+	 * int console_16550_getc(console_16550_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  r0 - pointer to console_t stucture
+	 * Out : r0 - character if available, else -1
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_16550_getc
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r0, [r0, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_getc
+endfunc console_16550_getc
+
+	/* ---------------------------------------------
+	 * int console_16550_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : r0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_16550_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Loop until the transmit FIFO is empty */
+1:	ldr	r1, [r0, #UARTLSR]
+	and	r1, r1, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	r1, #(UARTLSR_TEMT | UARTLSR_THRE)
+	bne	1b
+
+	mov	r0, #0
+	bx	lr
+endfunc console_16550_core_flush
+
+	/* ---------------------------------------------
+	 * int console_16550_flush(console_pl011_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : r0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0, r1
+	 * ---------------------------------------------
+	 */
+func console_16550_flush
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	r0, [r0, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_flush
+endfunc console_16550_flush
diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S
new file mode 100644
index 0000000..dab46e8
--- /dev/null
+++ b/drivers/ti/uart/aarch64/16550_console.S
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
+#include <drivers/ti/uart/uart_16550.h>
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_16550_core_init
+	.globl console_16550_core_putc
+	.globl console_16550_core_getc
+	.globl console_16550_core_flush
+
+	.globl console_16550_putc
+	.globl console_16550_getc
+	.globl console_16550_flush
+
+	/* -----------------------------------------------
+	 * int console_16550_core_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x1, x2, x3
+	 * -----------------------------------------------
+	 */
+func console_16550_core_init
+	/* Check the input base address */
+	cbz	x0, init_fail
+	/* Check baud rate and uart clock for sanity */
+	cbz	w1, init_fail
+	cbz	w2, init_fail
+
+	/* Program the baudrate */
+	/* Divisor =  Uart clock / (16 * baudrate) */
+	lsl	w2, w2, #4
+	udiv	w2, w1, w2
+	and	w1, w2, #0xff		/* w1 = DLL */
+	lsr	w2, w2, #8
+	and	w2, w2, #0xff		/* w2 = DLLM */
+	ldr	w3, [x0, #UARTLCR]
+	orr	w3, w3, #UARTLCR_DLAB
+	str	w3, [x0, #UARTLCR]	/* enable DLL, DLLM programming */
+	str	w1, [x0, #UARTDLL]	/* program DLL */
+	str	w2, [x0, #UARTDLLM]	/* program DLLM */
+	mov	w2, #~UARTLCR_DLAB
+	and	w3, w3, w2
+	str	w3, [x0, #UARTLCR]	/* disable DLL, DLLM programming */
+
+	/* 8n1 */
+	mov	w3, #3
+	str	w3, [x0, #UARTLCR]
+	/* no interrupt */
+	mov	w3, #0
+	str	w3, [x0, #UARTIER]
+#ifdef TI_16550_MDR_QUIRK
+	/* UART must be enabled on some platforms via the MDR register */
+	str	w3, [x0, #UARTMDR1]
+#endif /* TI_16550_MDR_QUIRK */
+	/* enable fifo, DMA */
+	mov	w3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN)
+	str	w3, [x0, #UARTFCR]
+	/* DTR + RTS */
+	mov	w3, #3
+	str	w3, [x0, #UARTMCR]
+	mov	w0, #1
+	ret
+init_fail:
+	mov	w0, #0
+	ret
+endfunc console_16550_core_init
+
+	.globl console_16550_register
+
+	/* -----------------------------------------------
+	 * int console_16550_register(uintptr_t baseaddr,
+	 *     uint32_t clock, uint32_t baud,
+	 *     console_16550_t *console);
+	 * Function to initialize and register a new 16550
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_16550_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_16550_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_16550_BASE]
+
+	bl	console_16550_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register 16550 putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_16550_register
+
+	/* --------------------------------------------------------
+	 * int console_16550_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_16550_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+	/* Check if the transmit FIFO is full */
+1:	ldr	w2, [x1, #UARTLSR]
+	and	w2, w2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	w2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	b.ne	1b
+	mov	w2, #0xD		/* '\r' */
+	str	w2, [x1, #UARTTX]
+
+	/* Check if the transmit FIFO is full */
+2:	ldr	w2, [x1, #UARTLSR]
+	and	w2, w2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	w2, #(UARTLSR_TEMT | UARTLSR_THRE)
+	b.ne	2b
+	str	w0, [x1, #UARTTX]
+	ret
+endfunc console_16550_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_16550_putc(int c, console_16550_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_16550_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_putc
+endfunc console_16550_putc
+
+	/* ---------------------------------------------
+	 * int console_16550_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  x0 - console base address
+	 * Out : w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_16550_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Check if the receive FIFO is empty */
+1:	ldr	w1, [x0, #UARTLSR]
+	tbz	w1, #UARTLSR_RDR_BIT, no_char
+	ldr	w0, [x0, #UARTRX]
+	ret
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+endfunc console_16550_core_getc
+
+	/* ---------------------------------------------
+	 * int console_16550_getc(console_16550_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  x0 - pointer to console_t stucture
+	 * Out : w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_16550_getc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_getc
+endfunc console_16550_getc
+
+	/* ---------------------------------------------
+	 * int console_16550_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_16550_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Loop until the transmit FIFO is empty */
+1:	ldr	w1, [x0, #UARTLSR]
+	and	w1, w1, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	w1, #(UARTLSR_TEMT | UARTLSR_THRE)
+	b.ne	1b
+
+	mov	w0, #0
+	ret
+endfunc console_16550_core_flush
+
+	/* ---------------------------------------------
+	 * int console_16550_flush(console_pl011_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_16550_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_flush
+endfunc console_16550_flush
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
new file mode 100644
index 0000000..6dbf372
--- /dev/null
+++ b/drivers/ufs/ufs.c
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+
+#define CDB_ADDR_MASK			127
+#define ALIGN_CDB(x)			(((x) + CDB_ADDR_MASK) & ~CDB_ADDR_MASK)
+#define ALIGN_8(x)			(((x) + 7) & ~7)
+
+#define UFS_DESC_SIZE			0x400
+#define MAX_UFS_DESC_SIZE		0x8000		/* 32 descriptors */
+
+#define MAX_PRDT_SIZE			0x40000		/* 256KB */
+
+static ufs_params_t ufs_params;
+static int nutrs;	/* Number of UTP Transfer Request Slots */
+
+int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
+{
+	unsigned int data;
+
+	data = mmio_read_32(base + HCS);
+	if ((data & HCS_UCRDY) == 0)
+		return -EBUSY;
+	mmio_write_32(base + IS, ~0);
+	mmio_write_32(base + UCMDARG1, cmd->arg1);
+	mmio_write_32(base + UCMDARG2, cmd->arg2);
+	mmio_write_32(base + UCMDARG3, cmd->arg3);
+	mmio_write_32(base + UICCMD, cmd->op);
+
+	do {
+		data = mmio_read_32(base + IS);
+	} while ((data & UFS_INT_UCCS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UCCS);
+	return mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
+}
+
+int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
+{
+	uintptr_t base;
+	unsigned int data;
+	int retries;
+
+	assert((ufs_params.reg_base != 0) && (val != NULL));
+
+	base = ufs_params.reg_base;
+	for (retries = 0; retries < 100; retries++) {
+		data = mmio_read_32(base + HCS);
+		if ((data & HCS_UCRDY) != 0)
+			break;
+		mdelay(1);
+	}
+	if (retries >= 100)
+		return -EBUSY;
+
+	mmio_write_32(base + IS, ~0);
+	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
+	mmio_write_32(base + UCMDARG2, 0);
+	mmio_write_32(base + UCMDARG3, 0);
+	mmio_write_32(base + UICCMD, DME_GET);
+	do {
+		data = mmio_read_32(base + IS);
+		if (data & UFS_INT_UE)
+			return -EINVAL;
+	} while ((data & UFS_INT_UCCS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UCCS);
+	data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
+	assert(data == 0);
+
+	*val = mmio_read_32(base + UCMDARG3);
+	return 0;
+}
+
+int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
+{
+	uintptr_t base;
+	unsigned int data;
+
+	assert((ufs_params.reg_base != 0));
+
+	base = ufs_params.reg_base;
+	data = mmio_read_32(base + HCS);
+	if ((data & HCS_UCRDY) == 0)
+		return -EBUSY;
+	mmio_write_32(base + IS, ~0);
+	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
+	mmio_write_32(base + UCMDARG2, 0);
+	mmio_write_32(base + UCMDARG3, val);
+	mmio_write_32(base + UICCMD, DME_SET);
+	do {
+		data = mmio_read_32(base + IS);
+		if (data & UFS_INT_UE)
+			return -EINVAL;
+	} while ((data & UFS_INT_UCCS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UCCS);
+	data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
+	assert(data == 0);
+	return 0;
+}
+
+static void ufshc_reset(uintptr_t base)
+{
+	unsigned int data;
+
+	/* Enable Host Controller */
+	mmio_write_32(base + HCE, HCE_ENABLE);
+	/* Wait until basic initialization sequence completed */
+	do {
+		data = mmio_read_32(base + HCE);
+	} while ((data & HCE_ENABLE) == 0);
+
+	/* Enable Interrupts */
+	data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES |
+	       UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES;
+	mmio_write_32(base + IE, data);
+}
+
+static int ufshc_link_startup(uintptr_t base)
+{
+	uic_cmd_t cmd;
+	int data, result;
+	int retries;
+
+	for (retries = 10; retries > 0; retries--) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.op = DME_LINKSTARTUP;
+		result = ufshc_send_uic_cmd(base, &cmd);
+		if (result != 0)
+			continue;
+		while ((mmio_read_32(base + HCS) & HCS_DP) == 0)
+			;
+		data = mmio_read_32(base + IS);
+		if (data & UFS_INT_ULSS)
+			mmio_write_32(base + IS, UFS_INT_ULSS);
+		return 0;
+	}
+	return -EIO;
+}
+
+/* Check Door Bell register to get an empty slot */
+static int get_empty_slot(int *slot)
+{
+	unsigned int data;
+	int i;
+
+	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
+	for (i = 0; i < nutrs; i++) {
+		if ((data & 1) == 0)
+			break;
+		data = data >> 1;
+	}
+	if (i >= nutrs)
+		return -EBUSY;
+	*slot = i;
+	return 0;
+}
+
+static void get_utrd(utp_utrd_t *utrd)
+{
+	uintptr_t base;
+	int slot = 0, result;
+	utrd_header_t *hd;
+
+	assert(utrd != NULL);
+	result = get_empty_slot(&slot);
+	assert(result == 0);
+
+	/* clear utrd */
+	memset((void *)utrd, 0, sizeof(utp_utrd_t));
+	base = ufs_params.desc_base + (slot * UFS_DESC_SIZE);
+	/* clear the descriptor */
+	memset((void *)base, 0, UFS_DESC_SIZE);
+
+	utrd->header = base;
+	utrd->task_tag = slot + 1;
+	/* CDB address should be aligned with 128 bytes */
+	utrd->upiu = ALIGN_CDB(utrd->header + sizeof(utrd_header_t));
+	utrd->resp_upiu = ALIGN_8(utrd->upiu + sizeof(cmd_upiu_t));
+	utrd->size_upiu = utrd->resp_upiu - utrd->upiu;
+	utrd->size_resp_upiu = ALIGN_8(sizeof(resp_upiu_t));
+	utrd->prdt = utrd->resp_upiu + utrd->size_resp_upiu;
+
+	hd = (utrd_header_t *)utrd->header;
+	hd->ucdba = utrd->upiu & UINT32_MAX;
+	hd->ucdbau = (utrd->upiu >> 32) & UINT32_MAX;
+	/* Both RUL and RUO is based on DWORD */
+	hd->rul = utrd->size_resp_upiu >> 2;
+	hd->ruo = utrd->size_upiu >> 2;
+	(void)result;
+}
+
+/*
+ * Prepare UTRD, Command UPIU, Response UPIU.
+ */
+static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
+			   int lba, uintptr_t buf, size_t length)
+{
+	utrd_header_t *hd;
+	cmd_upiu_t *upiu;
+	prdt_t *prdt;
+	unsigned int ulba;
+	unsigned int lba_cnt;
+	int prdt_size;
+
+
+	mmio_write_32(ufs_params.reg_base + UTRLBA,
+		      utrd->header & UINT32_MAX);
+	mmio_write_32(ufs_params.reg_base + UTRLBAU,
+		      (utrd->upiu >> 32) & UINT32_MAX);
+
+	hd = (utrd_header_t *)utrd->header;
+	upiu = (cmd_upiu_t *)utrd->upiu;
+
+	hd->i = 1;
+	hd->ct = CT_UFS_STORAGE;
+	hd->ocs = OCS_MASK;
+
+	upiu->trans_type = CMD_UPIU;
+	upiu->task_tag = utrd->task_tag;
+	upiu->cdb[0] = op;
+	ulba = (unsigned int)lba;
+	lba_cnt = (unsigned int)(length >> UFS_BLOCK_SHIFT);
+	switch (op) {
+	case CDBCMD_TEST_UNIT_READY:
+		break;
+	case CDBCMD_READ_CAPACITY_10:
+		hd->dd = DD_OUT;
+		upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;
+		upiu->lun = lun;
+		break;
+	case CDBCMD_READ_10:
+		hd->dd = DD_OUT;
+		upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;
+		upiu->lun = lun;
+		upiu->cdb[1] = RW_WITHOUT_CACHE;
+		/* set logical block address */
+		upiu->cdb[2] = (ulba >> 24) & 0xff;
+		upiu->cdb[3] = (ulba >> 16) & 0xff;
+		upiu->cdb[4] = (ulba >> 8) & 0xff;
+		upiu->cdb[5] = ulba & 0xff;
+		/* set transfer length */
+		upiu->cdb[7] = (lba_cnt >> 8) & 0xff;
+		upiu->cdb[8] = lba_cnt & 0xff;
+		break;
+	case CDBCMD_WRITE_10:
+		hd->dd = DD_IN;
+		upiu->flags = UPIU_FLAGS_W | UPIU_FLAGS_ATTR_S;
+		upiu->lun = lun;
+		upiu->cdb[1] = RW_WITHOUT_CACHE;
+		/* set logical block address */
+		upiu->cdb[2] = (ulba >> 24) & 0xff;
+		upiu->cdb[3] = (ulba >> 16) & 0xff;
+		upiu->cdb[4] = (ulba >> 8) & 0xff;
+		upiu->cdb[5] = ulba & 0xff;
+		/* set transfer length */
+		upiu->cdb[7] = (lba_cnt >> 8) & 0xff;
+		upiu->cdb[8] = lba_cnt & 0xff;
+		break;
+	default:
+		assert(0);
+		break;
+	}
+	if (hd->dd == DD_IN)
+		flush_dcache_range(buf, length);
+	else if (hd->dd == DD_OUT)
+		inv_dcache_range(buf, length);
+	if (length) {
+		upiu->exp_data_trans_len = htobe32(length);
+		assert(lba_cnt <= UINT16_MAX);
+		prdt = (prdt_t *)utrd->prdt;
+
+		prdt_size = 0;
+		while (length > 0) {
+			prdt->dba = (unsigned int)(buf & UINT32_MAX);
+			prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);
+			/* prdt->dbc counts from 0 */
+			if (length > MAX_PRDT_SIZE) {
+				prdt->dbc = MAX_PRDT_SIZE - 1;
+				length = length - MAX_PRDT_SIZE;
+			} else {
+				prdt->dbc = length - 1;
+				length = 0;
+			}
+			buf += MAX_PRDT_SIZE;
+			prdt++;
+			prdt_size += sizeof(prdt_t);
+		}
+		utrd->size_prdt = ALIGN_8(prdt_size);
+		hd->prdtl = utrd->size_prdt >> 2;
+		hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2;
+	}
+
+	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+	return 0;
+}
+
+static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn,
+			     uint8_t index, uint8_t sel,
+			     uintptr_t buf, size_t length)
+{
+	utrd_header_t *hd;
+	query_upiu_t *query_upiu;
+
+
+	hd = (utrd_header_t *)utrd->header;
+	query_upiu = (query_upiu_t *)utrd->upiu;
+
+	mmio_write_32(ufs_params.reg_base + UTRLBA,
+		      utrd->header & UINT32_MAX);
+	mmio_write_32(ufs_params.reg_base + UTRLBAU,
+		      (utrd->header >> 32) & UINT32_MAX);
+
+
+	hd->i = 1;
+	hd->ct = CT_UFS_STORAGE;
+	hd->ocs = OCS_MASK;
+
+	query_upiu->trans_type = QUERY_REQUEST_UPIU;
+	query_upiu->task_tag = utrd->task_tag;
+	query_upiu->ts.desc.opcode = op;
+	query_upiu->ts.desc.idn = idn;
+	query_upiu->ts.desc.index = index;
+	query_upiu->ts.desc.selector = sel;
+	switch (op) {
+	case QUERY_READ_DESC:
+		query_upiu->query_func = QUERY_FUNC_STD_READ;
+		query_upiu->ts.desc.length = htobe16(length);
+		break;
+	case QUERY_WRITE_DESC:
+		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
+		query_upiu->ts.desc.length = htobe16(length);
+		memcpy((void *)(utrd->upiu + sizeof(query_upiu_t)),
+		       (void *)buf, length);
+		break;
+	case QUERY_READ_ATTR:
+	case QUERY_READ_FLAG:
+		query_upiu->query_func = QUERY_FUNC_STD_READ;
+		break;
+	case QUERY_CLEAR_FLAG:
+	case QUERY_SET_FLAG:
+		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
+		break;
+	case QUERY_WRITE_ATTR:
+		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
+		memcpy((void *)&query_upiu->ts.attr.value, (void *)buf, length);
+		break;
+	default:
+		assert(0);
+		break;
+	}
+	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+	return 0;
+}
+
+static void ufs_prepare_nop_out(utp_utrd_t *utrd)
+{
+	utrd_header_t *hd;
+	nop_out_upiu_t *nop_out;
+
+	mmio_write_32(ufs_params.reg_base + UTRLBA,
+		      utrd->header & UINT32_MAX);
+	mmio_write_32(ufs_params.reg_base + UTRLBAU,
+		      (utrd->header >> 32) & UINT32_MAX);
+
+	hd = (utrd_header_t *)utrd->header;
+	nop_out = (nop_out_upiu_t *)utrd->upiu;
+
+	hd->i = 1;
+	hd->ct = CT_UFS_STORAGE;
+	hd->ocs = OCS_MASK;
+
+	nop_out->trans_type = 0;
+	nop_out->task_tag = utrd->task_tag;
+	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+}
+
+static void ufs_send_request(int task_tag)
+{
+	unsigned int data;
+	int slot;
+
+	slot = task_tag - 1;
+	/* clear all interrupts */
+	mmio_write_32(ufs_params.reg_base + IS, ~0);
+
+	mmio_write_32(ufs_params.reg_base + UTRLRSR, 1);
+	do {
+		data = mmio_read_32(ufs_params.reg_base + UTRLRSR);
+	} while (data == 0);
+
+	data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) |
+	       UTRIACR_IATOVAL(0xFF);
+	mmio_write_32(ufs_params.reg_base + UTRIACR, data);
+	/* send request */
+	mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
+}
+
+static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
+{
+	utrd_header_t *hd;
+	resp_upiu_t *resp;
+	unsigned int data;
+	int slot;
+
+	hd = (utrd_header_t *)utrd->header;
+	resp = (resp_upiu_t *)utrd->resp_upiu;
+	inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
+	inv_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	do {
+		data = mmio_read_32(ufs_params.reg_base + IS);
+		if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0)
+			return -EIO;
+	} while ((data & UFS_INT_UTRCS) == 0);
+	slot = utrd->task_tag - 1;
+
+	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
+	assert((data & (1 << slot)) == 0);
+	assert(hd->ocs == OCS_SUCCESS);
+	assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
+	(void)resp;
+	(void)slot;
+	return 0;
+}
+
+#ifdef UFS_RESP_DEBUG
+static void dump_upiu(utp_utrd_t *utrd)
+{
+	utrd_header_t *hd;
+	int i;
+
+	hd = (utrd_header_t *)utrd->header;
+	INFO("utrd:0x%x, ruo:0x%x, rul:0x%x, ocs:0x%x, UTRLDBR:0x%x\n",
+		(unsigned int)(uintptr_t)utrd, hd->ruo, hd->rul, hd->ocs,
+		mmio_read_32(ufs_params.reg_base + UTRLDBR));
+	for (i = 0; i < sizeof(utrd_header_t); i += 4) {
+		INFO("[%lx]:0x%x\n",
+			(uintptr_t)utrd->header + i,
+			*(unsigned int *)((uintptr_t)utrd->header + i));
+	}
+
+	for (i = 0; i < sizeof(cmd_upiu_t); i += 4) {
+		INFO("cmd[%lx]:0x%x\n",
+			utrd->upiu + i,
+			*(unsigned int *)(utrd->upiu + i));
+	}
+	for (i = 0; i < sizeof(resp_upiu_t); i += 4) {
+		INFO("resp[%lx]:0x%x\n",
+			utrd->resp_upiu + i,
+			*(unsigned int *)(utrd->resp_upiu + i));
+	}
+	for (i = 0; i < sizeof(prdt_t); i += 4) {
+		INFO("prdt[%lx]:0x%x\n",
+			utrd->prdt + i,
+			*(unsigned int *)(utrd->prdt + i));
+	}
+}
+#endif
+
+static void ufs_verify_init(void)
+{
+	utp_utrd_t utrd;
+	int result;
+
+	get_utrd(&utrd);
+	ufs_prepare_nop_out(&utrd);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, NOP_IN_UPIU);
+	assert(result == 0);
+	(void)result;
+}
+
+static void ufs_verify_ready(void)
+{
+	utp_utrd_t utrd;
+	int result;
+
+	get_utrd(&utrd);
+	ufs_prepare_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+	assert(result == 0);
+	(void)result;
+}
+
+static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
+		      uintptr_t buf, size_t size)
+{
+	utp_utrd_t utrd;
+	query_resp_upiu_t *resp;
+	int result;
+
+	switch (op) {
+	case QUERY_READ_FLAG:
+	case QUERY_READ_ATTR:
+	case QUERY_READ_DESC:
+	case QUERY_WRITE_DESC:
+	case QUERY_WRITE_ATTR:
+		assert(((buf & 3) == 0) && (size != 0));
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+	get_utrd(&utrd);
+	ufs_prepare_query(&utrd, op, idn, index, sel, buf, size);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU);
+	assert(result == 0);
+	resp = (query_resp_upiu_t *)utrd.resp_upiu;
+#ifdef UFS_RESP_DEBUG
+	dump_upiu(&utrd);
+#endif
+	assert(resp->query_resp == QUERY_RESP_SUCCESS);
+
+	switch (op) {
+	case QUERY_READ_FLAG:
+		*(uint32_t *)buf = (uint32_t)resp->ts.flag.value;
+		break;
+	case QUERY_READ_ATTR:
+	case QUERY_READ_DESC:
+		memcpy((void *)buf,
+		       (void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)),
+		       size);
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+	(void)result;
+}
+
+unsigned int ufs_read_attr(int idn)
+{
+	unsigned int value;
+
+	ufs_query(QUERY_READ_ATTR, idn, 0, 0,
+		  (uintptr_t)&value, sizeof(value));
+	return value;
+}
+
+void ufs_write_attr(int idn, unsigned int value)
+{
+	ufs_query(QUERY_WRITE_ATTR, idn, 0, 0,
+		  (uintptr_t)&value, sizeof(value));
+}
+
+unsigned int ufs_read_flag(int idn)
+{
+	unsigned int value;
+
+	ufs_query(QUERY_READ_FLAG, idn, 0, 0,
+		  (uintptr_t)&value, sizeof(value));
+	return value;
+}
+
+void ufs_set_flag(int idn)
+{
+	ufs_query(QUERY_SET_FLAG, idn, 0, 0, 0, 0);
+}
+
+void ufs_clear_flag(int idn)
+{
+	ufs_query(QUERY_CLEAR_FLAG, idn, 0, 0, 0, 0);
+}
+
+void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size)
+{
+	ufs_query(QUERY_READ_DESC, idn, index, 0, buf, size);
+}
+
+void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size)
+{
+	ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
+}
+
+static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
+{
+	utp_utrd_t utrd;
+	resp_upiu_t *resp;
+	sense_data_t *sense;
+	unsigned char data[CACHE_WRITEBACK_GRANULE << 1];
+	uintptr_t buf;
+	int result;
+	int retry;
+
+	assert((ufs_params.reg_base != 0) &&
+	       (ufs_params.desc_base != 0) &&
+	       (ufs_params.desc_size >= UFS_DESC_SIZE) &&
+	       (num != NULL) && (size != NULL));
+
+	/* align buf address */
+	buf = (uintptr_t)data;
+	buf = (buf + CACHE_WRITEBACK_GRANULE - 1) &
+	      ~(CACHE_WRITEBACK_GRANULE - 1);
+	memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE);
+	flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
+	do {
+		get_utrd(&utrd);
+		ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
+				buf, READ_CAPACITY_LENGTH);
+		ufs_send_request(utrd.task_tag);
+		result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+		assert(result == 0);
+#ifdef UFS_RESP_DEBUG
+		dump_upiu(&utrd);
+#endif
+		resp = (resp_upiu_t *)utrd.resp_upiu;
+		retry = 0;
+		sense = &resp->sd.sense;
+		if (sense->resp_code == SENSE_DATA_VALID) {
+			if ((sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
+			    (sense->asc == 0x29) && (sense->ascq == 0)) {
+				retry = 1;
+			}
+		}
+		inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
+		/* last logical block address */
+		*num = be32toh(*(unsigned int *)buf);
+		if (*num)
+			*num += 1;
+		/* logical block length in bytes */
+		*size = be32toh(*(unsigned int *)(buf + 4));
+	} while (retry);
+	(void)result;
+}
+
+size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
+{
+	utp_utrd_t utrd;
+	resp_upiu_t *resp;
+	int result;
+
+	assert((ufs_params.reg_base != 0) &&
+	       (ufs_params.desc_base != 0) &&
+	       (ufs_params.desc_size >= UFS_DESC_SIZE));
+
+	memset((void *)buf, 0, size);
+	get_utrd(&utrd);
+	ufs_prepare_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+	assert(result == 0);
+#ifdef UFS_RESP_DEBUG
+	dump_upiu(&utrd);
+#endif
+	resp = (resp_upiu_t *)utrd.resp_upiu;
+	(void)result;
+	return size - resp->res_trans_cnt;
+}
+
+size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size)
+{
+	utp_utrd_t utrd;
+	resp_upiu_t *resp;
+	int result;
+
+	assert((ufs_params.reg_base != 0) &&
+	       (ufs_params.desc_base != 0) &&
+	       (ufs_params.desc_size >= UFS_DESC_SIZE));
+
+	memset((void *)buf, 0, size);
+	get_utrd(&utrd);
+	ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+	assert(result == 0);
+#ifdef UFS_RESP_DEBUG
+	dump_upiu(&utrd);
+#endif
+	resp = (resp_upiu_t *)utrd.resp_upiu;
+	(void)result;
+	return size - resp->res_trans_cnt;
+}
+
+static void ufs_enum(void)
+{
+	unsigned int blk_num, blk_size;
+	int i;
+
+	/* 0 means 1 slot */
+	nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
+	if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE))
+		nutrs = ufs_params.desc_size / UFS_DESC_SIZE;
+
+	ufs_verify_init();
+	ufs_verify_ready();
+
+	ufs_set_flag(FLAG_DEVICE_INIT);
+	mdelay(200);
+	/* dump available LUNs */
+	for (i = 0; i < UFS_MAX_LUNS; i++) {
+		ufs_read_capacity(i, &blk_num, &blk_size);
+		if (blk_num && blk_size) {
+			INFO("UFS LUN%d contains %d blocks with %d-byte size\n",
+			     i, blk_num, blk_size);
+		}
+	}
+}
+
+static void ufs_get_device_info(struct ufs_dev_desc *card_data)
+{
+	uint8_t desc_buf[DESC_DEVICE_MAX_SIZE];
+
+	ufs_query(QUERY_READ_DESC, DESC_TYPE_DEVICE, 0, 0,
+				(uintptr_t)desc_buf, DESC_DEVICE_MAX_SIZE);
+
+	/*
+	 * getting vendor (manufacturerID) and Bank Index in big endian
+	 * format
+	 */
+	card_data->wmanufacturerid = (uint16_t)((desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8) |
+				     (desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]));
+}
+
+int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
+{
+	int result;
+	unsigned int data;
+	uic_cmd_t cmd;
+	struct ufs_dev_desc card = {0};
+
+	assert((params != NULL) &&
+	       (params->reg_base != 0) &&
+	       (params->desc_base != 0) &&
+	       (params->desc_size >= UFS_DESC_SIZE));
+
+	memcpy(&ufs_params, params, sizeof(ufs_params_t));
+
+	if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {
+		result = ufshc_dme_get(0x1571, 0, &data);
+		assert(result == 0);
+		result = ufshc_dme_get(0x41, 0, &data);
+		assert(result == 0);
+		if (data == 1) {
+			/* prepare to exit hibernate mode */
+			memset(&cmd, 0, sizeof(uic_cmd_t));
+			cmd.op = DME_HIBERNATE_EXIT;
+			result = ufshc_send_uic_cmd(ufs_params.reg_base,
+						    &cmd);
+			assert(result == 0);
+			data = mmio_read_32(ufs_params.reg_base + UCMDARG2);
+			assert(data == 0);
+			do {
+				data = mmio_read_32(ufs_params.reg_base + IS);
+			} while ((data & UFS_INT_UHXS) == 0);
+			mmio_write_32(ufs_params.reg_base + IS, UFS_INT_UHXS);
+			data = mmio_read_32(ufs_params.reg_base + HCS);
+			assert((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL);
+		}
+		result = ufshc_dme_get(0x1568, 0, &data);
+		assert(result == 0);
+		assert((data > 0) && (data <= 3));
+	} else {
+		assert((ops != NULL) && (ops->phy_init != NULL) &&
+		       (ops->phy_set_pwr_mode != NULL));
+
+		ufshc_reset(ufs_params.reg_base);
+		ops->phy_init(&ufs_params);
+		result = ufshc_link_startup(ufs_params.reg_base);
+		assert(result == 0);
+
+		ufs_enum();
+
+		ufs_get_device_info(&card);
+		if (card.wmanufacturerid == UFS_VENDOR_SKHYNIX) {
+			ufs_params.flags |= UFS_FLAGS_VENDOR_SKHYNIX;
+		}
+
+		ops->phy_set_pwr_mode(&ufs_params);
+	}
+
+	(void)result;
+	return 0;
+}
diff --git a/fdts/a5ds.dts b/fdts/a5ds.dts
new file mode 100644
index 0000000..8bc4adf
--- /dev/null
+++ b/fdts/a5ds.dts
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	model = "A5DS";
+	compatible = "arm,A5DS";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <0>;
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x7F000000>;
+	};
+
+	refclk100mhz: refclk100mhz {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <100000000>;
+		clock-output-names = "apb_pclk";
+	};
+
+	smbclk: refclk24mhzx2 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <48000000>;
+		clock-output-names = "smclk";
+	};
+
+
+	rtc@1a220000 {
+		compatible = "arm,pl031", "arm,primecell";
+		reg = <0x1a220000 0x1000>;
+		clocks = <&refclk100mhz>;
+		interrupts = <0 6 0xf04>;
+		clock-names = "apb_pclk";
+	};
+
+	gic: interrupt-controller@1c001000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x1c001000 0x1000>,
+			  <0x1c000100 0x100>;
+		interrupts = <1 9 0xf04>;
+	};
+
+	serial0: uart@1a200000 {
+		compatible = "arm,pl011", "arm,primecell";
+		reg = <0x1a200000 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <0 8 0xf04>;
+		clocks = <&refclk100mhz>;
+		clock-names = "apb_pclk";
+	};
+
+	serial1: uart@1a210000 {
+		compatible = "arm,pl011", "arm,primecell";
+		reg = <0x1a210000 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <0 9 0xf04>;
+		clocks = <&refclk100mhz>;
+		clock-names = "apb_pclk";
+	};
+
+	timer0: timer@1a040000 {
+		compatible = "arm,armv7-timer-mem";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0x1a040000 0x1000>;
+		clock-frequency = <50000000>;
+
+		frame@1a050000 {
+			frame-number = <0>;
+			interrupts = <0 2 0xf04>;
+			reg = <0x1a050000 0x1000>;
+		};
+	};
+};
diff --git a/fdts/fvp-base-gicv2-psci-aarch32.dts b/fdts/fvp-base-gicv2-psci-aarch32.dts
new file mode 100644
index 0000000..87ac68d
--- /dev/null
+++ b/fdts/fvp-base-gicv2-psci-aarch32.dts
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+};
+
+/ {
+	model = "FVP Base";
+	compatible = "arm,vfp-base", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_suspend = <0x84000001>;
+		cpu_off = <0x84000002>;
+		cpu_on = <0x84000003>;
+		sys_poweroff = <0x84000008>;
+		sys_reset = <0x84000009>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "arm,psci";
+
+			CPU_SLEEP_0: cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <40>;
+				exit-latency-us = <100>;
+				min-residency-us = <150>;
+			};
+
+			CLUSTER_SLEEP_0: cluster-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x1010000>;
+				entry-latency-us = <500>;
+				exit-latency-us = <1000>;
+				min-residency-us = <2500>;
+			};
+		};
+
+		CPU0:cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU1:cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU2:cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU3:cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU4:cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x100>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU5:cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x101>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU6:cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x102>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU7:cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x103>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x7F000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+	};
+
+	gic: interrupt-controller@2f000000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,
+		      <0x0 0x2c000000 0 0x2000>,
+		      <0x0 0x2c010000 0 0x2000>,
+		      <0x0 0x2c02F000 0 0x2000>;
+		interrupts = <1 9 0xf04>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xff01>,
+			     <1 14 0xff01>,
+			     <1 11 0xff01>,
+			     <1 10 0xff01>;
+		clock-frequency = <100000000>;
+	};
+
+	timer@2a810000 {
+			compatible = "arm,armv7-timer-mem";
+			reg = <0x0 0x2a810000 0x0 0x10000>;
+			clock-frequency = <100000000>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			frame@2a830000 {
+				frame-number = <1>;
+				interrupts = <0 26 4>;
+				reg = <0x0 0x2a830000 0x0 0x10000>;
+			};
+	};
+
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0  0 4>,
+				<0 0  1 &gic 0  1 4>,
+				<0 0  2 &gic 0  2 4>,
+				<0 0  3 &gic 0  3 4>,
+				<0 0  4 &gic 0  4 4>,
+				<0 0  5 &gic 0  5 4>,
+				<0 0  6 &gic 0  6 4>,
+				<0 0  7 &gic 0  7 4>,
+				<0 0  8 &gic 0  8 4>,
+				<0 0  9 &gic 0  9 4>,
+				<0 0 10 &gic 0 10 4>,
+				<0 0 11 &gic 0 11 4>,
+				<0 0 12 &gic 0 12 4>,
+				<0 0 13 &gic 0 13 4>,
+				<0 0 14 &gic 0 14 4>,
+				<0 0 15 &gic 0 15 4>,
+				<0 0 16 &gic 0 16 4>,
+				<0 0 17 &gic 0 17 4>,
+				<0 0 18 &gic 0 18 4>,
+				<0 0 19 &gic 0 19 4>,
+				<0 0 20 &gic 0 20 4>,
+				<0 0 21 &gic 0 21 4>,
+				<0 0 22 &gic 0 22 4>,
+				<0 0 23 &gic 0 23 4>,
+				<0 0 24 &gic 0 24 4>,
+				<0 0 25 &gic 0 25 4>,
+				<0 0 26 &gic 0 26 4>,
+				<0 0 27 &gic 0 27 4>,
+				<0 0 28 &gic 0 28 4>,
+				<0 0 29 &gic 0 29 4>,
+				<0 0 30 &gic 0 30 4>,
+				<0 0 31 &gic 0 31 4>,
+				<0 0 32 &gic 0 32 4>,
+				<0 0 33 &gic 0 33 4>,
+				<0 0 34 &gic 0 34 4>,
+				<0 0 35 &gic 0 35 4>,
+				<0 0 36 &gic 0 36 4>,
+				<0 0 37 &gic 0 37 4>,
+				<0 0 38 &gic 0 38 4>,
+				<0 0 39 &gic 0 39 4>,
+				<0 0 40 &gic 0 40 4>,
+				<0 0 41 &gic 0 41 4>,
+				<0 0 42 &gic 0 42 4>;
+
+		/include/ "rtsm_ve-motherboard-aarch32.dtsi"
+	};
+
+	panels {
+		panel@0 {
+			compatible	= "panel";
+			mode		= "XVGA";
+			refresh		= <60>;
+			xres		= <1024>;
+			yres		= <768>;
+			pixclock	= <15748>;
+			left_margin	= <152>;
+			right_margin	= <48>;
+			upper_margin	= <23>;
+			lower_margin	= <3>;
+			hsync_len	= <104>;
+			vsync_len	= <4>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+	};
+};
diff --git a/fdts/fvp-base-gicv2-psci.dts b/fdts/fvp-base-gicv2-psci.dts
new file mode 100644
index 0000000..941040d
--- /dev/null
+++ b/fdts/fvp-base-gicv2-psci.dts
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+};
+
+/ {
+	model = "FVP Base";
+	compatible = "arm,vfp-base", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_suspend = <0xc4000001>;
+		cpu_off = <0x84000002>;
+		cpu_on = <0xc4000003>;
+		sys_poweroff = <0x84000008>;
+		sys_reset = <0x84000009>;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "arm,psci";
+
+			CPU_SLEEP_0: cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <40>;
+				exit-latency-us = <100>;
+				min-residency-us = <150>;
+			};
+
+			CLUSTER_SLEEP_0: cluster-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x1010000>;
+				entry-latency-us = <500>;
+				exit-latency-us = <1000>;
+				min-residency-us = <2500>;
+			};
+		};
+
+		CPU0:cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU1:cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU2:cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU3:cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU4:cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x100>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU5:cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x101>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU6:cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x102>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU7:cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x103>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x7F000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+	};
+
+	gic: interrupt-controller@2f000000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,
+		      <0x0 0x2c000000 0 0x2000>,
+		      <0x0 0x2c010000 0 0x2000>,
+		      <0x0 0x2c02F000 0 0x2000>;
+		interrupts = <1 9 0xf04>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xff01>,
+			     <1 14 0xff01>,
+			     <1 11 0xff01>,
+			     <1 10 0xff01>;
+		clock-frequency = <100000000>;
+	};
+
+	timer@2a810000 {
+			compatible = "arm,armv7-timer-mem";
+			reg = <0x0 0x2a810000 0x0 0x10000>;
+			clock-frequency = <100000000>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			frame@2a830000 {
+				frame-number = <1>;
+				interrupts = <0 26 4>;
+				reg = <0x0 0x2a830000 0x0 0x10000>;
+			};
+	};
+
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		/include/ "rtsm_ve-motherboard.dtsi"
+	};
+
+	panels {
+		panel@0 {
+			compatible	= "panel";
+			mode		= "XVGA";
+			refresh		= <60>;
+			xres		= <1024>;
+			yres		= <768>;
+			pixclock	= <15748>;
+			left_margin	= <152>;
+			right_margin	= <48>;
+			upper_margin	= <23>;
+			lower_margin	= <3>;
+			hsync_len	= <104>;
+			vsync_len	= <4>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+	};
+};
diff --git a/fdts/fvp-base-gicv3-psci-1t.dts b/fdts/fvp-base-gicv3-psci-1t.dts
new file mode 100644
index 0000000..36fbd44
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-1t.dts
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/include/ "fvp-base-gicv3-psci-common.dtsi"
+
+&CPU0 {
+	reg = <0x0 0x0>;
+};
+
+&CPU1 {
+	reg = <0x0 0x100>;
+};
+
+&CPU2 {
+	reg = <0x0 0x200>;
+};
+
+&CPU3 {
+	reg = <0x0 0x300>;
+};
+
+&CPU4 {
+	reg = <0x0 0x10000>;
+};
+
+&CPU5 {
+	reg = <0x0 0x10100>;
+};
+
+&CPU6 {
+	reg = <0x0 0x10200>;
+};
+
+&CPU7 {
+	reg = <0x0 0x10300>;
+};
diff --git a/fdts/fvp-base-gicv3-psci-aarch32.dts b/fdts/fvp-base-gicv3-psci-aarch32.dts
new file mode 100644
index 0000000..b914ca0
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-aarch32.dts
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+};
+
+/ {
+	model = "FVP Base";
+	compatible = "arm,vfp-base", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_suspend = <0x84000001>;
+		cpu_off = <0x84000002>;
+		cpu_on = <0x84000003>;
+		sys_poweroff = <0x84000008>;
+		sys_reset = <0x84000009>;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "arm,psci";
+
+			CPU_SLEEP_0: cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <40>;
+				exit-latency-us = <100>;
+				min-residency-us = <150>;
+			};
+
+			CLUSTER_SLEEP_0: cluster-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x1010000>;
+				entry-latency-us = <500>;
+				exit-latency-us = <1000>;
+				min-residency-us = <2500>;
+			};
+		};
+
+		CPU0:cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU1:cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU2:cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU3:cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU4:cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x100>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU5:cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x101>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU6:cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x102>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU7:cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x103>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x7F000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+	};
+
+	gic: interrupt-controller@2f000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,	// GICD
+		      <0x0 0x2f100000 0 0x200000>,	// GICR
+		      <0x0 0x2c000000 0 0x2000>,	// GICC
+		      <0x0 0x2c010000 0 0x2000>,	// GICH
+		      <0x0 0x2c02f000 0 0x2000>;	// GICV
+		interrupts = <1 9 4>;
+
+		its: its@2f020000 {
+			compatible = "arm,gic-v3-its";
+			msi-controller;
+			reg = <0x0 0x2f020000 0x0 0x20000>; // GITS
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xff01>,
+			     <1 14 0xff01>,
+			     <1 11 0xff01>,
+			     <1 10 0xff01>;
+		clock-frequency = <100000000>;
+	};
+
+	timer@2a810000 {
+			compatible = "arm,armv7-timer-mem";
+			reg = <0x0 0x2a810000 0x0 0x10000>;
+			clock-frequency = <100000000>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			frame@2a830000 {
+				frame-number = <1>;
+				interrupts = <0 26 4>;
+				reg = <0x0 0x2a830000 0x0 0x10000>;
+			};
+	};
+
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0 0 0  0 4>,
+				<0 0  1 &gic 0 0 0  1 4>,
+				<0 0  2 &gic 0 0 0  2 4>,
+				<0 0  3 &gic 0 0 0  3 4>,
+				<0 0  4 &gic 0 0 0  4 4>,
+				<0 0  5 &gic 0 0 0  5 4>,
+				<0 0  6 &gic 0 0 0  6 4>,
+				<0 0  7 &gic 0 0 0  7 4>,
+				<0 0  8 &gic 0 0 0  8 4>,
+				<0 0  9 &gic 0 0 0  9 4>,
+				<0 0 10 &gic 0 0 0 10 4>,
+				<0 0 11 &gic 0 0 0 11 4>,
+				<0 0 12 &gic 0 0 0 12 4>,
+				<0 0 13 &gic 0 0 0 13 4>,
+				<0 0 14 &gic 0 0 0 14 4>,
+				<0 0 15 &gic 0 0 0 15 4>,
+				<0 0 16 &gic 0 0 0 16 4>,
+				<0 0 17 &gic 0 0 0 17 4>,
+				<0 0 18 &gic 0 0 0 18 4>,
+				<0 0 19 &gic 0 0 0 19 4>,
+				<0 0 20 &gic 0 0 0 20 4>,
+				<0 0 21 &gic 0 0 0 21 4>,
+				<0 0 22 &gic 0 0 0 22 4>,
+				<0 0 23 &gic 0 0 0 23 4>,
+				<0 0 24 &gic 0 0 0 24 4>,
+				<0 0 25 &gic 0 0 0 25 4>,
+				<0 0 26 &gic 0 0 0 26 4>,
+				<0 0 27 &gic 0 0 0 27 4>,
+				<0 0 28 &gic 0 0 0 28 4>,
+				<0 0 29 &gic 0 0 0 29 4>,
+				<0 0 30 &gic 0 0 0 30 4>,
+				<0 0 31 &gic 0 0 0 31 4>,
+				<0 0 32 &gic 0 0 0 32 4>,
+				<0 0 33 &gic 0 0 0 33 4>,
+				<0 0 34 &gic 0 0 0 34 4>,
+				<0 0 35 &gic 0 0 0 35 4>,
+				<0 0 36 &gic 0 0 0 36 4>,
+				<0 0 37 &gic 0 0 0 37 4>,
+				<0 0 38 &gic 0 0 0 38 4>,
+				<0 0 39 &gic 0 0 0 39 4>,
+				<0 0 40 &gic 0 0 0 40 4>,
+				<0 0 41 &gic 0 0 0 41 4>,
+				<0 0 42 &gic 0 0 0 42 4>;
+
+		/include/ "rtsm_ve-motherboard-aarch32.dtsi"
+	};
+
+	panels {
+		panel@0 {
+			compatible	= "panel";
+			mode		= "XVGA";
+			refresh		= <60>;
+			xres		= <1024>;
+			yres		= <768>;
+			pixclock	= <15748>;
+			left_margin	= <152>;
+			right_margin	= <48>;
+			upper_margin	= <23>;
+			lower_margin	= <3>;
+			hsync_len	= <104>;
+			vsync_len	= <4>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+	};
+};
diff --git a/fdts/fvp-base-gicv3-psci-common.dtsi b/fdts/fvp-base-gicv3-psci-common.dtsi
new file mode 100644
index 0000000..631c4e3
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-common.dtsi
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+};
+
+/ {
+	model = "FVP Base";
+	compatible = "arm,vfp-base", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_suspend = <0xc4000001>;
+		cpu_off = <0x84000002>;
+		cpu_on = <0xc4000003>;
+		sys_poweroff = <0x84000008>;
+		sys_reset = <0x84000009>;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "arm,psci";
+
+			CPU_SLEEP_0: cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <40>;
+				exit-latency-us = <100>;
+				min-residency-us = <150>;
+			};
+
+			CLUSTER_SLEEP_0: cluster-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x1010000>;
+				entry-latency-us = <500>;
+				exit-latency-us = <1000>;
+				min-residency-us = <2500>;
+			};
+		};
+
+		CPU0:cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU1:cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU2:cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU3:cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU4:cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x100>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU5:cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x101>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU6:cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x102>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU7:cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x103>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x7F000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+	};
+
+	gic: interrupt-controller@2f000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,	// GICD
+		      <0x0 0x2f100000 0 0x200000>,	// GICR
+		      <0x0 0x2c000000 0 0x2000>,	// GICC
+		      <0x0 0x2c010000 0 0x2000>,	// GICH
+		      <0x0 0x2c02f000 0 0x2000>;	// GICV
+		interrupts = <1 9 4>;
+
+		its: its@2f020000 {
+			compatible = "arm,gic-v3-its";
+			msi-controller;
+			reg = <0x0 0x2f020000 0x0 0x20000>; // GITS
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xff01>,
+			     <1 14 0xff01>,
+			     <1 11 0xff01>,
+			     <1 10 0xff01>;
+		clock-frequency = <100000000>;
+	};
+
+	timer@2a810000 {
+			compatible = "arm,armv7-timer-mem";
+			reg = <0x0 0x2a810000 0x0 0x10000>;
+			clock-frequency = <100000000>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			frame@2a830000 {
+				frame-number = <1>;
+				interrupts = <0 26 4>;
+				reg = <0x0 0x2a830000 0x0 0x10000>;
+			};
+	};
+
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	smb@0,0 {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		/include/ "rtsm_ve-motherboard.dtsi"
+	};
+
+	panels {
+		panel {
+			compatible	= "panel";
+			mode		= "XVGA";
+			refresh		= <60>;
+			xres		= <1024>;
+			yres		= <768>;
+			pixclock	= <15748>;
+			left_margin	= <152>;
+			right_margin	= <48>;
+			upper_margin	= <23>;
+			lower_margin	= <3>;
+			hsync_len	= <104>;
+			vsync_len	= <4>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+	};
+};
diff --git a/fdts/fvp-base-gicv3-psci-dynamiq.dts b/fdts/fvp-base-gicv3-psci-dynamiq.dts
new file mode 100644
index 0000000..614c5d5
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci-dynamiq.dts
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/include/ "fvp-base-gicv3-psci-common.dtsi"
+
+&CPU0 {
+	reg = <0x0 0x0>;
+};
+
+&CPU1 {
+	reg = <0x0 0x100>;
+};
+
+&CPU2 {
+	reg = <0x0 0x200>;
+};
+
+&CPU3 {
+	reg = <0x0 0x300>;
+};
+
+&CPU4 {
+	reg = <0x0 0x400>;
+};
+
+&CPU5 {
+	reg = <0x0 0x500>;
+};
+
+&CPU6 {
+	reg = <0x0 0x600>;
+};
+
+&CPU7 {
+	reg = <0x0 0x700>;
+};
diff --git a/fdts/fvp-base-gicv3-psci.dts b/fdts/fvp-base-gicv3-psci.dts
new file mode 100644
index 0000000..3ea429c
--- /dev/null
+++ b/fdts/fvp-base-gicv3-psci.dts
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/include/ "fvp-base-gicv3-psci-common.dtsi"
diff --git a/fdts/fvp-foundation-gicv2-psci.dts b/fdts/fvp-foundation-gicv2-psci.dts
new file mode 100644
index 0000000..03b61dd
--- /dev/null
+++ b/fdts/fvp-foundation-gicv2-psci.dts
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+};
+
+/ {
+	model = "FVP Foundation";
+	compatible = "arm,fvp-base", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_suspend = <0xc4000001>;
+		cpu_off = <0x84000002>;
+		cpu_on = <0xc4000003>;
+		sys_poweroff = <0x84000008>;
+		sys_reset = <0x84000009>;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "arm,psci";
+
+			CPU_SLEEP_0: cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <40>;
+				exit-latency-us = <100>;
+				min-residency-us = <150>;
+			};
+
+			CLUSTER_SLEEP_0: cluster-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x1010000>;
+				entry-latency-us = <500>;
+				exit-latency-us = <1000>;
+				min-residency-us = <2500>;
+			};
+		};
+
+		CPU0:cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU1:cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU2:cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU3:cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x7F000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+	};
+
+	gic: interrupt-controller@2f000000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,
+		      <0x0 0x2c000000 0 0x2000>,
+		      <0x0 0x2c010000 0 0x2000>,
+		      <0x0 0x2c02F000 0 0x2000>;
+		interrupts = <1 9 0xf04>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xff01>,
+			     <1 14 0xff01>,
+			     <1 11 0xff01>,
+			     <1 10 0xff01>;
+		clock-frequency = <100000000>;
+	};
+
+	timer@2a810000 {
+			compatible = "arm,armv7-timer-mem";
+			reg = <0x0 0x2a810000 0x0 0x10000>;
+			clock-frequency = <100000000>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			frame@2a830000 {
+				frame-number = <1>;
+				interrupts = <0 26 4>;
+				reg = <0x0 0x2a830000 0x0 0x10000>;
+			};
+	};
+
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		/include/ "fvp-foundation-motherboard.dtsi"
+	};
+};
diff --git a/fdts/fvp-foundation-gicv3-psci.dts b/fdts/fvp-foundation-gicv3-psci.dts
new file mode 100644
index 0000000..1488ed7
--- /dev/null
+++ b/fdts/fvp-foundation-gicv3-psci.dts
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+};
+
+/ {
+	model = "FVP Foundation";
+	compatible = "arm,fvp-base", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	chosen { };
+
+	aliases {
+		serial0 = &v2m_serial0;
+		serial1 = &v2m_serial1;
+		serial2 = &v2m_serial2;
+		serial3 = &v2m_serial3;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_suspend = <0xc4000001>;
+		cpu_off = <0x84000002>;
+		cpu_on = <0xc4000003>;
+		sys_poweroff = <0x84000008>;
+		sys_reset = <0x84000009>;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+		};
+
+		idle-states {
+			entry-method = "arm,psci";
+
+			CPU_SLEEP_0: cpu-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <40>;
+				exit-latency-us = <100>;
+				min-residency-us = <150>;
+			};
+
+			CLUSTER_SLEEP_0: cluster-sleep-0 {
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x1010000>;
+				entry-latency-us = <500>;
+				exit-latency-us = <1000>;
+				min-residency-us = <2500>;
+			};
+		};
+
+		CPU0:cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU1:cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x1>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU2:cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x2>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		CPU3:cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x3>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+			next-level-cache = <&L2_0>;
+		};
+
+		L2_0: l2-cache0 {
+			compatible = "cache";
+		};
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000 0 0x7F000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+	};
+
+	gic: interrupt-controller@2f000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,	// GICD
+		      <0x0 0x2f100000 0 0x200000>,	// GICR
+		      <0x0 0x2c000000 0 0x2000>,	// GICC
+		      <0x0 0x2c010000 0 0x2000>,	// GICH
+		      <0x0 0x2c02f000 0 0x2000>;	// GICV
+		interrupts = <1 9 4>;
+
+		its: its@2f020000 {
+			compatible = "arm,gic-v3-its";
+			msi-controller;
+			reg = <0x0 0x2f020000 0x0 0x20000>; // GITS
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xff01>,
+			     <1 14 0xff01>,
+			     <1 11 0xff01>,
+			     <1 10 0xff01>;
+		clock-frequency = <100000000>;
+	};
+
+	timer@2a810000 {
+			compatible = "arm,armv7-timer-mem";
+			reg = <0x0 0x2a810000 0x0 0x10000>;
+			clock-frequency = <100000000>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+			frame@2a830000 {
+				frame-number = <1>;
+				interrupts = <0 26 4>;
+				reg = <0x0 0x2a830000 0x0 0x10000>;
+			};
+	};
+
+	pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <0 60 4>,
+			     <0 61 4>,
+			     <0 62 4>,
+			     <0 63 4>;
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		/include/ "fvp-foundation-motherboard.dtsi"
+	};
+};
diff --git a/fdts/fvp-foundation-motherboard.dtsi b/fdts/fvp-foundation-motherboard.dtsi
new file mode 100644
index 0000000..9ee5b64
--- /dev/null
+++ b/fdts/fvp-foundation-motherboard.dtsi
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	motherboard {
+		arm,v2m-memory-map = "rs1";
+		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+		#address-cells = <2>; /* SMB chipselect number and offset */
+		#size-cells = <1>;
+		ranges;
+
+		ethernet@2,02000000 {
+			compatible = "smsc,lan91c111";
+			reg = <2 0x02000000 0x10000>;
+			interrupts = <0 15 4>;
+		};
+
+		v2m_clk24mhz: clk24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk24mhz";
+		};
+
+		v2m_refclk1mhz: refclk1mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000>;
+			clock-output-names = "v2m:refclk1mhz";
+		};
+
+		v2m_refclk32khz: refclk32khz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "v2m:refclk32khz";
+		};
+
+		iofpga@3,00000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 3 0 0x200000>;
+
+			v2m_sysreg: sysreg@10000 {
+				compatible = "arm,vexpress-sysreg";
+				reg = <0x010000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			v2m_sysctl: sysctl@20000 {
+				compatible = "arm,sp810", "arm,primecell";
+				reg = <0x020000 0x1000>;
+				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+			};
+
+			v2m_serial0: uart@90000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x090000 0x1000>;
+				interrupts = <0 5 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial1: uart@a0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0a0000 0x1000>;
+				interrupts = <0 6 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial2: uart@b0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0b0000 0x1000>;
+				interrupts = <0 7 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial3: uart@c0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0c0000 0x1000>;
+				interrupts = <0 8 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			wdt@f0000 {
+				compatible = "arm,sp805", "arm,primecell";
+				reg = <0x0f0000 0x1000>;
+				interrupts = <0 0 4>;
+				clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
+				clock-names = "wdogclk", "apb_pclk";
+			};
+
+			v2m_timer01: timer@110000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x110000 0x1000>;
+				interrupts = <0 2 4>;
+				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
+			};
+
+			v2m_timer23: timer@120000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x120000 0x1000>;
+				interrupts = <0 3 4>;
+				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
+			};
+
+			rtc@170000 {
+				compatible = "arm,pl031", "arm,primecell";
+				reg = <0x170000 0x1000>;
+				interrupts = <0 4 4>;
+				clocks = <&v2m_clk24mhz>;
+				clock-names = "apb_pclk";
+			};
+
+			virtio_block@130000 {
+				compatible = "virtio,mmio";
+				reg = <0x130000 0x1000>;
+				interrupts = <0 0x2a 4>;
+			};
+		};
+
+		v2m_fixed_3v3: fixedregulator@0 {
+			compatible = "regulator-fixed";
+			regulator-name = "3V3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+
+		mcc {
+			compatible = "arm,vexpress,config-bus", "simple-bus";
+			arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+			/*
+			 * Not supported in FVP models
+			 *
+			 * reset@0 {
+			 * 	compatible = "arm,vexpress-reset";
+			 * 	arm,vexpress-sysreg,func = <5 0>;
+			 * };
+			 */
+
+			muxfpga@0 {
+				compatible = "arm,vexpress-muxfpga";
+				arm,vexpress-sysreg,func = <7 0>;
+			};
+
+			/*
+			 * Not used - Superseded by PSCI sys_poweroff
+			 *
+			 * shutdown@0 {
+			 * 	compatible = "arm,vexpress-shutdown";
+			 * 	arm,vexpress-sysreg,func = <8 0>;
+			 * };
+			 */
+
+			/*
+			 * Not used - Superseded by PSCI sys_reset
+			 *
+			 * reboot@0 {
+			 * 	compatible = "arm,vexpress-reboot";
+			 * 	arm,vexpress-sysreg,func = <9 0>;
+			 * };
+			 */
+
+			dvimode@0 {
+				compatible = "arm,vexpress-dvimode";
+				arm,vexpress-sysreg,func = <11 0>;
+			};
+		};
+	};
diff --git a/fdts/fvp-ve-Cortex-A5x1.dts b/fdts/fvp-ve-Cortex-A5x1.dts
new file mode 100644
index 0000000..0f76601
--- /dev/null
+++ b/fdts/fvp-ve-Cortex-A5x1.dts
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	model = "V2P-CA5s";
+	compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			reg = <0>;
+		};
+
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x1000000>;
+	};
+
+	hdlcd@2a110000 {
+		compatible = "arm,hdlcd";
+		reg = <0x2a110000 0x1000>;
+		interrupts = <0 85 4>;
+		clocks = <&oscclk3>;
+		clock-names = "pxlclk";
+	};
+
+	scu@2c000000 {
+		compatible = "arm,cortex-a5-scu";
+		reg = <0x2c000000 0x58>;
+	};
+
+	watchdog@2c000620 {
+		compatible = "arm,cortex-a5-twd-wdt";
+		reg = <0x2c000620 0x20>;
+		interrupts = <1 14 0x304>;
+	};
+
+	gic: interrupt-controller@2c001000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0x2c001000 0x1000>,
+		      <0x2c000100 0x100>;
+	};
+
+	dcc {
+		compatible = "arm,vexpress,config-bus";
+		arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+		oscclk0: osc@0 {
+			/* CPU and internal AXI reference clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 0>;
+			freq-range = <50000000 100000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk0";
+		};
+
+		oscclk1: osc@1 {
+			/* Multiplexed AXI master clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 1>;
+			freq-range = <5000000 50000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk1";
+		};
+
+		osc@2 {
+			/* DDR2 */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 2>;
+			freq-range = <80000000 120000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk2";
+		};
+
+		oscclk3: osc@3 {
+			/* HDLCD */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 3>;
+			freq-range = <23750000 165000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk3";
+		};
+
+		osc@4 {
+			/* Test chip gate configuration */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 4>;
+			freq-range = <80000000 80000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk4";
+		};
+
+		smbclk: osc@5 {
+			/* SMB clock */
+			compatible = "arm,vexpress-osc";
+			arm,vexpress-sysreg,func = <1 5>;
+			freq-range = <25000000 60000000>;
+			#clock-cells = <0>;
+			clock-output-names = "oscclk5";
+		};
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0x08000000 0x04000000>,
+			 <1 0 0x14000000 0x04000000>,
+			 <2 0 0x18000000 0x04000000>,
+			 <3 0 0x1c000000 0x04000000>,
+			 <4 0 0x0c000000 0x04000000>,
+			 <5 0 0x10000000 0x04000000>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0  0 4>,
+				<0 0  1 &gic 0  1 4>,
+				<0 0  2 &gic 0  2 4>,
+				<0 0  3 &gic 0  3 4>,
+				<0 0  4 &gic 0  4 4>,
+				<0 0  5 &gic 0  5 4>,
+				<0 0 42 &gic 0 42 4>;
+
+		/include/ "rtsm_ve-motherboard-aarch32.dtsi"
+	};
+};
diff --git a/fdts/fvp-ve-Cortex-A7x1.dts b/fdts/fvp-ve-Cortex-A7x1.dts
new file mode 100644
index 0000000..fca3d90
--- /dev/null
+++ b/fdts/fvp-ve-Cortex-A7x1.dts
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	model = "V2F-1XV7 Cortex-A7x1 SMM";
+	compatible = "arm,vexpress,v2f-1xv7", "arm,vexpress";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0 0>;
+		};
+	};
+
+	memory@0,80000000 {
+		device_type = "memory";
+		reg = <0 0x80000000 0 0x80000000>; /* 2GB @ 2GB */
+	};
+
+	gic: interrupt-controller@2c001000 {
+		compatible = "arm,cortex-a15-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0 0x2c001000 0 0x1000>,
+		      <0 0x2c002000 0 0x1000>,
+		      <0 0x2c004000 0 0x2000>,
+		      <0 0x2c006000 0 0x2000>;
+		interrupts = <1 9 0xf04>;
+	};
+
+	smbclk: refclk24mhzx2 {
+		/* Reference 24MHz clock x 2 */
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <48000000>;
+		clock-output-names = "smclk";
+	};
+
+	smb {
+		compatible = "simple-bus";
+
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0x08000000 0x04000000>,
+			 <1 0 0 0x14000000 0x04000000>,
+			 <2 0 0 0x18000000 0x04000000>,
+			 <3 0 0 0x1c000000 0x04000000>,
+			 <4 0 0 0x0c000000 0x04000000>,
+			 <5 0 0 0x10000000 0x04000000>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 63>;
+		interrupt-map = <0 0  0 &gic 0  0 4>,
+				<0 0  1 &gic 0  1 4>,
+				<0 0  2 &gic 0  2 4>,
+				<0 0  3 &gic 0  3 4>,
+				<0 0  4 &gic 0  4 4>,
+				<0 0  5 &gic 0  5 4>,
+				<0 0 42 &gic 0 42 4>;
+
+		/include/ "rtsm_ve-motherboard-aarch32.dtsi"
+	};
+};
diff --git a/fdts/rtsm_ve-motherboard-aarch32.dtsi b/fdts/rtsm_ve-motherboard-aarch32.dtsi
new file mode 100644
index 0000000..7a8af8e
--- /dev/null
+++ b/fdts/rtsm_ve-motherboard-aarch32.dtsi
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	motherboard {
+		arm,v2m-memory-map = "rs1";
+		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+		#address-cells = <2>; /* SMB chipselect number and offset */
+		#size-cells = <1>;
+		#interrupt-cells = <1>;
+		ranges;
+
+		flash@0,00000000 {
+			compatible = "arm,vexpress-flash", "cfi-flash";
+			reg = <0 0x00000000 0x04000000>,
+			      <4 0x00000000 0x04000000>;
+			bank-width = <4>;
+		};
+
+		vram@2,00000000 {
+			compatible = "arm,vexpress-vram";
+			reg = <2 0x00000000 0x00800000>;
+		};
+
+		ethernet@2,02000000 {
+			compatible = "smsc,lan91c111";
+			reg = <2 0x02000000 0x10000>;
+			interrupts = <15>;
+		};
+
+		v2m_clk24mhz: clk24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk24mhz";
+		};
+
+		v2m_refclk1mhz: refclk1mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000>;
+			clock-output-names = "v2m:refclk1mhz";
+		};
+
+		v2m_refclk32khz: refclk32khz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "v2m:refclk32khz";
+		};
+
+		iofpga@3,00000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 3 0 0x200000>;
+
+			v2m_sysreg: sysreg@10000 {
+				compatible = "arm,vexpress-sysreg";
+				reg = <0x010000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			v2m_sysctl: sysctl@20000 {
+				compatible = "arm,sp810", "arm,primecell";
+				reg = <0x020000 0x1000>;
+				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+			};
+
+			aaci@40000 {
+				compatible = "arm,pl041", "arm,primecell";
+				reg = <0x040000 0x1000>;
+				interrupts = <11>;
+				clocks = <&v2m_clk24mhz>;
+				clock-names = "apb_pclk";
+			};
+
+			mmci@50000 {
+				compatible = "arm,pl180", "arm,primecell";
+				reg = <0x050000 0x1000>;
+				interrupts = <9 10>;
+				cd-gpios = <&v2m_sysreg 0 0>;
+				wp-gpios = <&v2m_sysreg 1 0>;
+				max-frequency = <12000000>;
+				vmmc-supply = <&v2m_fixed_3v3>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "mclk", "apb_pclk";
+			};
+
+			kmi@60000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x060000 0x1000>;
+				interrupts = <12>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "KMIREFCLK", "apb_pclk";
+			};
+
+			kmi@70000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x070000 0x1000>;
+				interrupts = <13>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "KMIREFCLK", "apb_pclk";
+			};
+
+			v2m_serial0: uart@90000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x090000 0x1000>;
+				interrupts = <5>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial1: uart@a0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0a0000 0x1000>;
+				interrupts = <6>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial2: uart@b0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0b0000 0x1000>;
+				interrupts = <7>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial3: uart@c0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0c0000 0x1000>;
+				interrupts = <8>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			wdt@f0000 {
+				compatible = "arm,sp805", "arm,primecell";
+				reg = <0x0f0000 0x1000>;
+				interrupts = <0>;
+				clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
+				clock-names = "wdogclk", "apb_pclk";
+			};
+
+			v2m_timer01: timer@110000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x110000 0x1000>;
+				interrupts = <2>;
+				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
+			};
+
+			v2m_timer23: timer@120000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x120000 0x1000>;
+				interrupts = <3>;
+				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
+			};
+
+			rtc@170000 {
+				compatible = "arm,pl031", "arm,primecell";
+				reg = <0x170000 0x1000>;
+				interrupts = <4>;
+				clocks = <&v2m_clk24mhz>;
+				clock-names = "apb_pclk";
+			};
+
+			clcd@1f0000 {
+				compatible = "arm,pl111", "arm,primecell";
+				reg = <0x1f0000 0x1000>;
+				interrupts = <14>;
+				clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
+				clock-names = "clcdclk", "apb_pclk";
+				mode = "XVGA";
+				use_dma = <0>;
+				framebuffer = <0x18000000 0x00180000>;
+			};
+
+			virtio_block@130000 {
+				compatible = "virtio,mmio";
+				reg = <0x130000 0x1000>;
+				interrupts = <0x2a>;
+			};
+		};
+
+		v2m_fixed_3v3: fixedregulator@0 {
+			compatible = "regulator-fixed";
+			regulator-name = "3V3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		mcc {
+			compatible = "arm,vexpress,config-bus", "simple-bus";
+			arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+			v2m_oscclk1: osc@1 {
+				/* CLCD clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 1>;
+				freq-range = <23750000 63500000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk1";
+			};
+
+			/*
+			 * Not supported in FVP models
+			 *
+			 * reset@0 {
+			 * 	compatible = "arm,vexpress-reset";
+			 * 	arm,vexpress-sysreg,func = <5 0>;
+			 * };
+			 */
+
+			muxfpga@0 {
+				compatible = "arm,vexpress-muxfpga";
+				arm,vexpress-sysreg,func = <7 0>;
+			};
+
+			/*
+			 * Not used - Superseded by PSCI sys_poweroff
+			 *
+			 * shutdown@0 {
+			 * 	compatible = "arm,vexpress-shutdown";
+			 * 	arm,vexpress-sysreg,func = <8 0>;
+			 * };
+			 */
+
+			/*
+			 * Not used - Superseded by PSCI sys_reset
+			 *
+			 * reboot@0 {
+			 * 	compatible = "arm,vexpress-reboot";
+			 * 	arm,vexpress-sysreg,func = <9 0>;
+			 * };
+			 */
+
+			dvimode@0 {
+				compatible = "arm,vexpress-dvimode";
+				arm,vexpress-sysreg,func = <11 0>;
+			};
+		};
+	};
diff --git a/fdts/rtsm_ve-motherboard.dtsi b/fdts/rtsm_ve-motherboard.dtsi
new file mode 100644
index 0000000..486f8a9
--- /dev/null
+++ b/fdts/rtsm_ve-motherboard.dtsi
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	motherboard {
+		arm,v2m-memory-map = "rs1";
+		compatible = "arm,vexpress,v2m-p1", "simple-bus";
+		#address-cells = <2>; /* SMB chipselect number and offset */
+		#size-cells = <1>;
+		ranges;
+
+		flash@0,00000000 {
+			compatible = "arm,vexpress-flash", "cfi-flash";
+			reg = <0 0x00000000 0x04000000>,
+			      <4 0x00000000 0x04000000>;
+			bank-width = <4>;
+		};
+
+		vram@2,00000000 {
+			compatible = "arm,vexpress-vram";
+			reg = <2 0x00000000 0x00800000>;
+		};
+
+		ethernet@2,02000000 {
+			compatible = "smsc,lan91c111";
+			reg = <2 0x02000000 0x10000>;
+			interrupts = <0 15 4>;
+		};
+
+		v2m_clk24mhz: clk24mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <24000000>;
+			clock-output-names = "v2m:clk24mhz";
+		};
+
+		v2m_refclk1mhz: refclk1mhz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <1000000>;
+			clock-output-names = "v2m:refclk1mhz";
+		};
+
+		v2m_refclk32khz: refclk32khz {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "v2m:refclk32khz";
+		};
+
+		iofpga@3,00000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 3 0 0x200000>;
+
+			v2m_sysreg: sysreg@10000 {
+				compatible = "arm,vexpress-sysreg";
+				reg = <0x010000 0x1000>;
+				gpio-controller;
+				#gpio-cells = <2>;
+			};
+
+			v2m_sysctl: sysctl@20000 {
+				compatible = "arm,sp810", "arm,primecell";
+				reg = <0x020000 0x1000>;
+				clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
+				clock-names = "refclk", "timclk", "apb_pclk";
+				#clock-cells = <1>;
+				clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+			};
+
+			aaci@40000 {
+				compatible = "arm,pl041", "arm,primecell";
+				reg = <0x040000 0x1000>;
+				interrupts = <0 11 4>;
+				clocks = <&v2m_clk24mhz>;
+				clock-names = "apb_pclk";
+			};
+
+			mmci@50000 {
+				compatible = "arm,pl180", "arm,primecell";
+				reg = <0x050000 0x1000>;
+				interrupts = <0 9 4 0 10 4>;
+				cd-gpios = <&v2m_sysreg 0 0>;
+				wp-gpios = <&v2m_sysreg 1 0>;
+				max-frequency = <12000000>;
+				vmmc-supply = <&v2m_fixed_3v3>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "mclk", "apb_pclk";
+			};
+
+			kmi@60000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x060000 0x1000>;
+				interrupts = <0 12 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "KMIREFCLK", "apb_pclk";
+			};
+
+			kmi@70000 {
+				compatible = "arm,pl050", "arm,primecell";
+				reg = <0x070000 0x1000>;
+				interrupts = <0 13 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "KMIREFCLK", "apb_pclk";
+			};
+
+			v2m_serial0: uart@90000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x090000 0x1000>;
+				interrupts = <0 5 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial1: uart@a0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0a0000 0x1000>;
+				interrupts = <0 6 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial2: uart@b0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0b0000 0x1000>;
+				interrupts = <0 7 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			v2m_serial3: uart@c0000 {
+				compatible = "arm,pl011", "arm,primecell";
+				reg = <0x0c0000 0x1000>;
+				interrupts = <0 8 4>;
+				clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+				clock-names = "uartclk", "apb_pclk";
+			};
+
+			wdt@f0000 {
+				compatible = "arm,sp805", "arm,primecell";
+				reg = <0x0f0000 0x1000>;
+				interrupts = <0 0 4>;
+				clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
+				clock-names = "wdogclk", "apb_pclk";
+			};
+
+			v2m_timer01: timer@110000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x110000 0x1000>;
+				interrupts = <0 2 4>;
+				clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
+			};
+
+			v2m_timer23: timer@120000 {
+				compatible = "arm,sp804", "arm,primecell";
+				reg = <0x120000 0x1000>;
+				interrupts = <0 3 4>;
+				clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
+				clock-names = "timclken1", "timclken2", "apb_pclk";
+			};
+
+			rtc@170000 {
+				compatible = "arm,pl031", "arm,primecell";
+				reg = <0x170000 0x1000>;
+				interrupts = <0 4 4>;
+				clocks = <&v2m_clk24mhz>;
+				clock-names = "apb_pclk";
+			};
+
+			clcd@1f0000 {
+				compatible = "arm,pl111", "arm,primecell";
+				reg = <0x1f0000 0x1000>;
+				interrupts = <0 14 4>;
+				clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
+				clock-names = "clcdclk", "apb_pclk";
+				mode = "XVGA";
+				use_dma = <0>;
+				framebuffer = <0x18000000 0x00180000>;
+			};
+
+			virtio_block@130000 {
+				compatible = "virtio,mmio";
+				reg = <0x130000 0x1000>;
+				interrupts = <0 0x2a 4>;
+			};
+		};
+
+		v2m_fixed_3v3: fixedregulator {
+			compatible = "regulator-fixed";
+			regulator-name = "3V3";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		mcc {
+			compatible = "arm,vexpress,config-bus", "simple-bus";
+			arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+			v2m_oscclk1: osc {
+				/* CLCD clock */
+				compatible = "arm,vexpress-osc";
+				arm,vexpress-sysreg,func = <1 1>;
+				freq-range = <23750000 63500000>;
+				#clock-cells = <0>;
+				clock-output-names = "v2m:oscclk1";
+			};
+
+			/*
+			 * Not supported in FVP models
+			 *
+			 * reset@0 {
+			 * 	compatible = "arm,vexpress-reset";
+			 * 	arm,vexpress-sysreg,func = <5 0>;
+			 * };
+			 */
+
+			muxfpga {
+				compatible = "arm,vexpress-muxfpga";
+				arm,vexpress-sysreg,func = <7 0>;
+			};
+
+			/*
+			 * Not used - Superseded by PSCI sys_poweroff
+			 *
+			 * shutdown@0 {
+			 * 	compatible = "arm,vexpress-shutdown";
+			 * 	arm,vexpress-sysreg,func = <8 0>;
+			 * };
+			 */
+
+			/*
+			 * Not used - Superseded by PSCI sys_reset
+			 *
+			 * reboot@0 {
+			 * 	compatible = "arm,vexpress-reboot";
+			 * 	arm,vexpress-sysreg,func = <9 0>;
+			 * };
+			 */
+
+			dvimode {
+				compatible = "arm,vexpress-dvimode";
+				arm,vexpress-sysreg,func = <11 0>;
+			};
+		};
+	};
diff --git a/fdts/stm32mp15-ddr.dtsi b/fdts/stm32mp15-ddr.dtsi
new file mode 100644
index 0000000..4825691
--- /dev/null
+++ b/fdts/stm32mp15-ddr.dtsi
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ */
+
+/ {
+	soc {
+		ddr: ddr@5a003000{
+
+			compatible = "st,stm32mp1-ddr";
+
+			reg = <0x5A003000 0x550
+			       0x5A004000 0x234>;
+
+			clocks = <&rcc AXIDCG>,
+				 <&rcc DDRC1>,
+				 <&rcc DDRC2>,
+				 <&rcc DDRPHYC>,
+				 <&rcc DDRCAPB>,
+				 <&rcc DDRPHYCAPB>;
+
+			clock-names = "axidcg",
+				      "ddrc1",
+				      "ddrc2",
+				      "ddrphyc",
+				      "ddrcapb",
+				      "ddrphycapb";
+
+			st,mem-name = DDR_MEM_NAME;
+			st,mem-speed = <DDR_MEM_SPEED>;
+			st,mem-size = <DDR_MEM_SIZE>;
+
+			st,ctl-reg = <
+				DDR_MSTR
+				DDR_MRCTRL0
+				DDR_MRCTRL1
+				DDR_DERATEEN
+				DDR_DERATEINT
+				DDR_PWRCTL
+				DDR_PWRTMG
+				DDR_HWLPCTL
+				DDR_RFSHCTL0
+				DDR_RFSHCTL3
+				DDR_CRCPARCTL0
+				DDR_ZQCTL0
+				DDR_DFITMG0
+				DDR_DFITMG1
+				DDR_DFILPCFG0
+				DDR_DFIUPD0
+				DDR_DFIUPD1
+				DDR_DFIUPD2
+				DDR_DFIPHYMSTR
+				DDR_ODTMAP
+				DDR_DBG0
+				DDR_DBG1
+				DDR_DBGCMD
+				DDR_POISONCFG
+				DDR_PCCFG
+			>;
+
+			st,ctl-timing = <
+				DDR_RFSHTMG
+				DDR_DRAMTMG0
+				DDR_DRAMTMG1
+				DDR_DRAMTMG2
+				DDR_DRAMTMG3
+				DDR_DRAMTMG4
+				DDR_DRAMTMG5
+				DDR_DRAMTMG6
+				DDR_DRAMTMG7
+				DDR_DRAMTMG8
+				DDR_DRAMTMG14
+				DDR_ODTCFG
+			>;
+
+			st,ctl-map = <
+				DDR_ADDRMAP1
+				DDR_ADDRMAP2
+				DDR_ADDRMAP3
+				DDR_ADDRMAP4
+				DDR_ADDRMAP5
+				DDR_ADDRMAP6
+				DDR_ADDRMAP9
+				DDR_ADDRMAP10
+				DDR_ADDRMAP11
+			>;
+
+			st,ctl-perf = <
+				DDR_SCHED
+				DDR_SCHED1
+				DDR_PERFHPR1
+				DDR_PERFLPR1
+				DDR_PERFWR1
+				DDR_PCFGR_0
+				DDR_PCFGW_0
+				DDR_PCFGQOS0_0
+				DDR_PCFGQOS1_0
+				DDR_PCFGWQOS0_0
+				DDR_PCFGWQOS1_0
+				DDR_PCFGR_1
+				DDR_PCFGW_1
+				DDR_PCFGQOS0_1
+				DDR_PCFGQOS1_1
+				DDR_PCFGWQOS0_1
+				DDR_PCFGWQOS1_1
+			>;
+
+			st,phy-reg = <
+				DDR_PGCR
+				DDR_ACIOCR
+				DDR_DXCCR
+				DDR_DSGCR
+				DDR_DCR
+				DDR_ODTCR
+				DDR_ZQ0CR1
+				DDR_DX0GCR
+				DDR_DX1GCR
+				DDR_DX2GCR
+				DDR_DX3GCR
+			>;
+
+			st,phy-timing = <
+				DDR_PTR0
+				DDR_PTR1
+				DDR_PTR2
+				DDR_DTPR0
+				DDR_DTPR1
+				DDR_DTPR2
+				DDR_MR0
+				DDR_MR1
+				DDR_MR2
+				DDR_MR3
+			>;
+
+			st,phy-cal = <
+				DDR_DX0DLLCR
+				DDR_DX0DQTR
+				DDR_DX0DQSTR
+				DDR_DX1DLLCR
+				DDR_DX1DQTR
+				DDR_DX1DQSTR
+				DDR_DX2DLLCR
+				DDR_DX2DQTR
+				DDR_DX2DQSTR
+				DDR_DX3DLLCR
+				DDR_DX3DQTR
+				DDR_DX3DQSTR
+			>;
+
+			status = "okay";
+		};
+	};
+};
diff --git a/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
new file mode 100644
index 0000000..11e8f2b
--- /dev/null
+++ b/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * STM32MP157C DK1/DK2 BOARD configuration
+ * 1x DDR3L 4Gb, 16-bit, 533MHz.
+ * Reference used NT5CC256M16DP-DI from NANYA
+ *
+ * DDR type / Platform	DDR3/3L
+ * freq		533MHz
+ * width	16
+ * datasheet	0  = MT41J256M16-187 / DDR3-1066 bin G
+ * DDR density	4
+ * timing mode	optimized
+ * Scheduling/QoS options : type = 2
+ * address mapping : RBC
+ * Tc > + 85C : N
+ */
+#define DDR_MEM_NAME "DDR3-1066/888 bin G 1x4Gb 533MHz v1.45"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x20000000
+
+#define DDR_MSTR 0x00041401
+#define DDR_MRCTRL0 0x00000010
+#define DDR_MRCTRL1 0x00000000
+#define DDR_DERATEEN 0x00000000
+#define DDR_DERATEINT 0x00800000
+#define DDR_PWRCTL 0x00000000
+#define DDR_PWRTMG 0x00400010
+#define DDR_HWLPCTL 0x00000000
+#define DDR_RFSHCTL0 0x00210000
+#define DDR_RFSHCTL3 0x00000000
+#define DDR_RFSHTMG 0x0081008B
+#define DDR_CRCPARCTL0 0x00000000
+#define DDR_DRAMTMG0 0x121B2414
+#define DDR_DRAMTMG1 0x000A041C
+#define DDR_DRAMTMG2 0x0608090F
+#define DDR_DRAMTMG3 0x0050400C
+#define DDR_DRAMTMG4 0x08040608
+#define DDR_DRAMTMG5 0x06060403
+#define DDR_DRAMTMG6 0x02020002
+#define DDR_DRAMTMG7 0x00000202
+#define DDR_DRAMTMG8 0x00001005
+#define DDR_DRAMTMG14 0x000000A0
+#define DDR_ZQCTL0 0xC2000040
+#define DDR_DFITMG0 0x02060105
+#define DDR_DFITMG1 0x00000202
+#define DDR_DFILPCFG0 0x07000000
+#define DDR_DFIUPD0 0xC0400003
+#define DDR_DFIUPD1 0x00000000
+#define DDR_DFIUPD2 0x00000000
+#define DDR_DFIPHYMSTR 0x00000000
+#define DDR_ADDRMAP1 0x00070707
+#define DDR_ADDRMAP2 0x00000000
+#define DDR_ADDRMAP3 0x1F000000
+#define DDR_ADDRMAP4 0x00001F1F
+#define DDR_ADDRMAP5 0x06060606
+#define DDR_ADDRMAP6 0x0F060606
+#define DDR_ADDRMAP9 0x00000000
+#define DDR_ADDRMAP10 0x00000000
+#define DDR_ADDRMAP11 0x00000000
+#define DDR_ODTCFG 0x06000600
+#define DDR_ODTMAP 0x00000001
+#define DDR_SCHED 0x00000C01
+#define DDR_SCHED1 0x00000000
+#define DDR_PERFHPR1 0x01000001
+#define DDR_PERFLPR1 0x08000200
+#define DDR_PERFWR1 0x08000400
+#define DDR_DBG0 0x00000000
+#define DDR_DBG1 0x00000000
+#define DDR_DBGCMD 0x00000000
+#define DDR_POISONCFG 0x00000000
+#define DDR_PCCFG 0x00000010
+#define DDR_PCFGR_0 0x00010000
+#define DDR_PCFGW_0 0x00000000
+#define DDR_PCFGQOS0_0 0x02100C03
+#define DDR_PCFGQOS1_0 0x00800100
+#define DDR_PCFGWQOS0_0 0x01100C03
+#define DDR_PCFGWQOS1_0 0x01000200
+#define DDR_PCFGR_1 0x00010000
+#define DDR_PCFGW_1 0x00000000
+#define DDR_PCFGQOS0_1 0x02100C03
+#define DDR_PCFGQOS1_1 0x00800040
+#define DDR_PCFGWQOS0_1 0x01100C03
+#define DDR_PCFGWQOS1_1 0x01000200
+#define DDR_PGCR 0x01442E02
+#define DDR_PTR0 0x0022AA5B
+#define DDR_PTR1 0x04841104
+#define DDR_PTR2 0x042DA068
+#define DDR_ACIOCR 0x10400812
+#define DDR_DXCCR 0x00000C40
+#define DDR_DSGCR 0xF200011F
+#define DDR_DCR 0x0000000B
+#define DDR_DTPR0 0x38D488D0
+#define DDR_DTPR1 0x098B00D8
+#define DDR_DTPR2 0x10023600
+#define DDR_MR0 0x00000840
+#define DDR_MR1 0x00000000
+#define DDR_MR2 0x00000208
+#define DDR_MR3 0x00000000
+#define DDR_ODTCR 0x00010000
+#define DDR_ZQ0CR1 0x00000038
+#define DDR_DX0GCR 0x0000CE81
+#define DDR_DX0DLLCR 0x40000000
+#define DDR_DX0DQTR 0xFFFFFFFF
+#define DDR_DX0DQSTR 0x3DB02000
+#define DDR_DX1GCR 0x0000CE81
+#define DDR_DX1DLLCR 0x40000000
+#define DDR_DX1DQTR 0xFFFFFFFF
+#define DDR_DX1DQSTR 0x3DB02000
+#define DDR_DX2GCR 0x0000CE80
+#define DDR_DX2DLLCR 0x40000000
+#define DDR_DX2DQTR 0xFFFFFFFF
+#define DDR_DX2DQSTR 0x3DB02000
+#define DDR_DX3GCR 0x0000CE80
+#define DDR_DX3DLLCR 0x40000000
+#define DDR_DX3DQTR 0xFFFFFFFF
+#define DDR_DX3DQSTR 0x3DB02000
+
+#include "stm32mp15-ddr.dtsi"
diff --git a/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
new file mode 100644
index 0000000..4b70b60
--- /dev/null
+++ b/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * STM32MP157C ED1 BOARD configuration
+ * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology.
+ * Reference used NT5CC256M16DP-DI from NANYA
+ *
+ * DDR type / Platform	DDR3/3L
+ * freq		533MHz
+ * width	32
+ * datasheet	0  = MT41J256M16-187 / DDR3-1066 bin G
+ * DDR density	8
+ * timing mode	optimized
+ * Scheduling/QoS options : type = 2
+ * address mapping : RBC
+ * Tc > + 85C : N
+ */
+#define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.45"
+#define DDR_MEM_SPEED 533000
+#define DDR_MEM_SIZE 0x40000000
+
+#define DDR_MSTR 0x00040401
+#define DDR_MRCTRL0 0x00000010
+#define DDR_MRCTRL1 0x00000000
+#define DDR_DERATEEN 0x00000000
+#define DDR_DERATEINT 0x00800000
+#define DDR_PWRCTL 0x00000000
+#define DDR_PWRTMG 0x00400010
+#define DDR_HWLPCTL 0x00000000
+#define DDR_RFSHCTL0 0x00210000
+#define DDR_RFSHCTL3 0x00000000
+#define DDR_RFSHTMG 0x0081008B
+#define DDR_CRCPARCTL0 0x00000000
+#define DDR_DRAMTMG0 0x121B2414
+#define DDR_DRAMTMG1 0x000A041C
+#define DDR_DRAMTMG2 0x0608090F
+#define DDR_DRAMTMG3 0x0050400C
+#define DDR_DRAMTMG4 0x08040608
+#define DDR_DRAMTMG5 0x06060403
+#define DDR_DRAMTMG6 0x02020002
+#define DDR_DRAMTMG7 0x00000202
+#define DDR_DRAMTMG8 0x00001005
+#define DDR_DRAMTMG14 0x000000A0
+#define DDR_ZQCTL0 0xC2000040
+#define DDR_DFITMG0 0x02060105
+#define DDR_DFITMG1 0x00000202
+#define DDR_DFILPCFG0 0x07000000
+#define DDR_DFIUPD0 0xC0400003
+#define DDR_DFIUPD1 0x00000000
+#define DDR_DFIUPD2 0x00000000
+#define DDR_DFIPHYMSTR 0x00000000
+#define DDR_ADDRMAP1 0x00080808
+#define DDR_ADDRMAP2 0x00000000
+#define DDR_ADDRMAP3 0x00000000
+#define DDR_ADDRMAP4 0x00001F1F
+#define DDR_ADDRMAP5 0x07070707
+#define DDR_ADDRMAP6 0x0F070707
+#define DDR_ADDRMAP9 0x00000000
+#define DDR_ADDRMAP10 0x00000000
+#define DDR_ADDRMAP11 0x00000000
+#define DDR_ODTCFG 0x06000600
+#define DDR_ODTMAP 0x00000001
+#define DDR_SCHED 0x00000C01
+#define DDR_SCHED1 0x00000000
+#define DDR_PERFHPR1 0x01000001
+#define DDR_PERFLPR1 0x08000200
+#define DDR_PERFWR1 0x08000400
+#define DDR_DBG0 0x00000000
+#define DDR_DBG1 0x00000000
+#define DDR_DBGCMD 0x00000000
+#define DDR_POISONCFG 0x00000000
+#define DDR_PCCFG 0x00000010
+#define DDR_PCFGR_0 0x00010000
+#define DDR_PCFGW_0 0x00000000
+#define DDR_PCFGQOS0_0 0x02100C03
+#define DDR_PCFGQOS1_0 0x00800100
+#define DDR_PCFGWQOS0_0 0x01100C03
+#define DDR_PCFGWQOS1_0 0x01000200
+#define DDR_PCFGR_1 0x00010000
+#define DDR_PCFGW_1 0x00000000
+#define DDR_PCFGQOS0_1 0x02100C03
+#define DDR_PCFGQOS1_1 0x00800040
+#define DDR_PCFGWQOS0_1 0x01100C03
+#define DDR_PCFGWQOS1_1 0x01000200
+#define DDR_PGCR 0x01442E02
+#define DDR_PTR0 0x0022AA5B
+#define DDR_PTR1 0x04841104
+#define DDR_PTR2 0x042DA068
+#define DDR_ACIOCR 0x10400812
+#define DDR_DXCCR 0x00000C40
+#define DDR_DSGCR 0xF200011F
+#define DDR_DCR 0x0000000B
+#define DDR_DTPR0 0x38D488D0
+#define DDR_DTPR1 0x098B00D8
+#define DDR_DTPR2 0x10023600
+#define DDR_MR0 0x00000840
+#define DDR_MR1 0x00000000
+#define DDR_MR2 0x00000208
+#define DDR_MR3 0x00000000
+#define DDR_ODTCR 0x00010000
+#define DDR_ZQ0CR1 0x00000038
+#define DDR_DX0GCR 0x0000CE81
+#define DDR_DX0DLLCR 0x40000000
+#define DDR_DX0DQTR 0xFFFFFFFF
+#define DDR_DX0DQSTR 0x3DB02000
+#define DDR_DX1GCR 0x0000CE81
+#define DDR_DX1DLLCR 0x40000000
+#define DDR_DX1DQTR 0xFFFFFFFF
+#define DDR_DX1DQSTR 0x3DB02000
+#define DDR_DX2GCR 0x0000CE81
+#define DDR_DX2DLLCR 0x40000000
+#define DDR_DX2DQTR 0xFFFFFFFF
+#define DDR_DX2DQSTR 0x3DB02000
+#define DDR_DX3GCR 0x0000CE81
+#define DDR_DX3DLLCR 0x40000000
+#define DDR_DX3DQTR 0xFFFFFFFF
+#define DDR_DX3DQSTR 0x3DB02000
+
+#include "stm32mp15-ddr.dtsi"
diff --git a/fdts/stm32mp157-pinctrl.dtsi b/fdts/stm32mp157-pinctrl.dtsi
new file mode 100644
index 0000000..8e480b2
--- /dev/null
+++ b/fdts/stm32mp157-pinctrl.dtsi
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/pinctrl/stm32-pinfunc.h>
+
+/ {
+	soc {
+		pinctrl: pin-controller@50002000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "st,stm32mp157-pinctrl";
+			ranges = <0 0x50002000 0xa400>;
+			pins-are-numbered;
+
+			gpioa: gpio@50002000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x0 0x400>;
+				clocks = <&rcc GPIOA>;
+				st,bank-name = "GPIOA";
+				status = "disabled";
+			};
+
+			gpiob: gpio@50003000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x1000 0x400>;
+				clocks = <&rcc GPIOB>;
+				st,bank-name = "GPIOB";
+				status = "disabled";
+			};
+
+			gpioc: gpio@50004000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x2000 0x400>;
+				clocks = <&rcc GPIOC>;
+				st,bank-name = "GPIOC";
+				status = "disabled";
+			};
+
+			gpiod: gpio@50005000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x3000 0x400>;
+				clocks = <&rcc GPIOD>;
+				st,bank-name = "GPIOD";
+				status = "disabled";
+			};
+
+			gpioe: gpio@50006000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x4000 0x400>;
+				clocks = <&rcc GPIOE>;
+				st,bank-name = "GPIOE";
+				status = "disabled";
+			};
+
+			gpiof: gpio@50007000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x5000 0x400>;
+				clocks = <&rcc GPIOF>;
+				st,bank-name = "GPIOF";
+				status = "disabled";
+			};
+
+			gpiog: gpio@50008000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x6000 0x400>;
+				clocks = <&rcc GPIOG>;
+				st,bank-name = "GPIOG";
+				status = "disabled";
+			};
+
+			gpioh: gpio@50009000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x7000 0x400>;
+				clocks = <&rcc GPIOH>;
+				st,bank-name = "GPIOH";
+				status = "disabled";
+			};
+
+			gpioi: gpio@5000a000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x8000 0x400>;
+				clocks = <&rcc GPIOI>;
+				st,bank-name = "GPIOI";
+				status = "disabled";
+			};
+
+			gpioj: gpio@5000b000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0x9000 0x400>;
+				clocks = <&rcc GPIOJ>;
+				st,bank-name = "GPIOJ";
+				status = "disabled";
+			};
+
+			gpiok: gpio@5000c000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0xa000 0x400>;
+				clocks = <&rcc GPIOK>;
+				st,bank-name = "GPIOK";
+				status = "disabled";
+			};
+
+			qspi_bk1_pins_a: qspi-bk1-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('F', 8, AF10)>, /* QSPI_BK1_IO0 */
+						 <STM32_PINMUX('F', 9, AF10)>, /* QSPI_BK1_IO1 */
+						 <STM32_PINMUX('F', 7, AF9)>, /* QSPI_BK1_IO2 */
+						 <STM32_PINMUX('F', 6, AF9)>; /* QSPI_BK1_IO3 */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <1>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 6, AF10)>; /* QSPI_BK1_NCS */
+					bias-pull-up;
+					drive-push-pull;
+					slew-rate = <1>;
+				};
+			};
+
+			qspi_bk2_pins_a: qspi-bk2-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('H', 2, AF9)>, /* QSPI_BK2_IO0 */
+						 <STM32_PINMUX('H', 3, AF9)>, /* QSPI_BK2_IO1 */
+						 <STM32_PINMUX('G', 10, AF11)>, /* QSPI_BK2_IO2 */
+						 <STM32_PINMUX('G', 7, AF11)>; /* QSPI_BK2_IO3 */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <1>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('C', 0, AF10)>; /* QSPI_BK2_NCS */
+					bias-pull-up;
+					drive-push-pull;
+					slew-rate = <1>;
+				};
+			};
+
+			qspi_clk_pins_a: qspi-clk-0 {
+				pins {
+					pinmux = <STM32_PINMUX('F', 10, AF9)>; /* QSPI_CLK */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <3>;
+				};
+			};
+
+			sdmmc1_b4_pins_a: sdmmc1-b4-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('C', 8, AF12)>, /* SDMMC1_D0 */
+						 <STM32_PINMUX('C', 9, AF12)>, /* SDMMC1_D1 */
+						 <STM32_PINMUX('C', 10, AF12)>, /* SDMMC1_D2 */
+						 <STM32_PINMUX('C', 11, AF12)>, /* SDMMC1_D3 */
+						 <STM32_PINMUX('D', 2, AF12)>; /* SDMMC1_CMD */
+					slew-rate = <1>;
+					drive-push-pull;
+					bias-disable;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('C', 12, AF12)>; /* SDMMC1_CK */
+					slew-rate = <2>;
+					drive-push-pull;
+					bias-disable;
+				};
+			};
+
+			sdmmc1_dir_pins_a: sdmmc1-dir-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('F', 2, AF11)>, /* SDMMC1_D0DIR */
+						 <STM32_PINMUX('C', 7, AF8)>, /* SDMMC1_D123DIR */
+						 <STM32_PINMUX('B', 9, AF11)>; /* SDMMC1_CDIR */
+					slew-rate = <1>;
+					drive-push-pull;
+					bias-pull-up;
+				};
+				pins2{
+					pinmux = <STM32_PINMUX('E', 4, AF8)>; /* SDMMC1_CKIN */
+					bias-pull-up;
+				};
+			};
+
+			sdmmc2_b4_pins_a: sdmmc2-b4-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
+						 <STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
+						 <STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
+						 <STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
+						 <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
+					slew-rate = <1>;
+					drive-push-pull;
+					bias-pull-up;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
+					slew-rate = <2>;
+					drive-push-pull;
+					bias-pull-up;
+				};
+			};
+
+			sdmmc2_d47_pins_a: sdmmc2-d47-0 {
+				pins {
+					pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
+						 <STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
+						 <STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */
+						 <STM32_PINMUX('D', 3, AF9)>; /* SDMMC2_D7 */
+					slew-rate = <1>;
+					drive-push-pull;
+					bias-pull-up;
+				};
+			};
+
+			uart4_pins_a: uart4-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('G', 11, AF6)>; /* UART4_TX */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <0>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+					bias-disable;
+				};
+			};
+
+			uart4_pins_b: uart4-1 {
+				pins1 {
+					pinmux = <STM32_PINMUX('D', 1, AF8)>; /* UART4_TX */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <0>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 2, AF8)>; /* UART4_RX */
+					bias-disable;
+				};
+			};
+
+			uart7_pins_a: uart7-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('E', 8, AF7)>; /* USART7_TX */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <0>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('E', 7, AF7)>; /* USART7_RX */
+					bias-disable;
+				};
+			};
+
+			usart3_pins_a: usart3-0 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+						 <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <0>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+						 <STM32_PINMUX('I', 10, AF8)>; /* USART3_CTS_NSS */
+					bias-disable;
+				};
+			};
+
+			usart3_pins_b: usart3-1 {
+				pins1 {
+					pinmux = <STM32_PINMUX('B', 10, AF7)>, /* USART3_TX */
+						 <STM32_PINMUX('G', 8, AF8)>; /* USART3_RTS */
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <0>;
+				};
+				pins2 {
+					pinmux = <STM32_PINMUX('B', 12, AF8)>, /* USART3_RX */
+						 <STM32_PINMUX('B', 13, AF7)>; /* USART3_CTS_NSS */
+					bias-disable;
+				};
+			};
+		};
+
+		pinctrl_z: pin-controller-z@54004000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "st,stm32mp157-z-pinctrl";
+			ranges = <0 0x54004000 0x400>;
+			pins-are-numbered;
+
+			gpioz: gpio@54004000 {
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				reg = <0 0x400>;
+				clocks = <&rcc GPIOZ>;
+				st,bank-name = "GPIOZ";
+				st,bank-ioport = <11>;
+				status = "disabled";
+			};
+
+			i2c4_pins_a: i2c4-0 {
+				pins {
+					pinmux = <STM32_PINMUX('Z', 4, AF6)>, /* I2C4_SCL */
+						 <STM32_PINMUX('Z', 5, AF6)>; /* I2C4_SDA */
+					bias-disable;
+					drive-open-drain;
+					slew-rate = <0>;
+				};
+			};
+		};
+	};
+};
diff --git a/fdts/stm32mp157a-avenger96.dts b/fdts/stm32mp157a-avenger96.dts
new file mode 100644
index 0000000..9df72b4
--- /dev/null
+++ b/fdts/stm32mp157a-avenger96.dts
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) Arrow Electronics 2019 - All Rights Reserved
+ * Author: Botond Kardos <botond.kardos@arroweurope.com>
+ *
+ * Copyright (C) Linaro Ltd 2019 - All Rights Reserved
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+/dts-v1/;
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cac-pinctrl.dtsi"
+
+/ {
+	model = "Arrow Electronics STM32MP157A Avenger96 board";
+	compatible = "st,stm32mp157a-avenger96", "st,stm32mp157";
+
+	aliases {
+		serial0 = &uart4;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins_a>;
+	i2c-scl-rising-time-ns = <185>;
+	i2c-scl-falling-time-ns = <20>;
+	status = "okay";
+
+	pmic: stpmic@33 {
+		compatible = "st,stpmic1";
+		reg = <0x33>;
+		interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		status = "okay";
+
+		st,main-control-register = <0x04>;
+		st,vin-control-register = <0xc0>;
+		st,usb-control-register = <0x20>;
+
+		regulators {
+			compatible = "st,stpmic1-regulators";
+
+			ldo1-supply = <&v3v3>;
+			ldo2-supply = <&v3v3>;
+			ldo3-supply = <&vdd_ddr>;
+			ldo5-supply = <&v3v3>;
+			ldo6-supply = <&v3v3>;
+
+			vddcore: buck1 {
+				regulator-name = "vddcore";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			vdd_ddr: buck2 {
+				regulator-name = "vdd_ddr";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			vdd: buck3 {
+				regulator-name = "vdd";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				st,mask-reset;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			v3v3: buck4 {
+				regulator-name = "v3v3";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+				regulator-initial-mode = <0>;
+			};
+
+			vdda: ldo1 {
+				regulator-name = "vdda";
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+			};
+
+			v2v8: ldo2 {
+				regulator-name = "v2v8";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+
+			vtt_ddr: ldo3 {
+				regulator-name = "vtt_ddr";
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <750000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+
+			vdd_usb: ldo4 {
+				regulator-name = "vdd_usb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vdd_sd: ldo5 {
+				regulator-name = "vdd_sd";
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+				regulator-boot-on;
+			};
+
+			v1v8: ldo6 {
+				regulator-name = "v1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			vref_ddr: vref_ddr {
+				regulator-name = "vref_ddr";
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+		};
+	};
+};
+
+&iwdg2 {
+	timeout-sec = <32>;
+	status = "okay";
+};
+
+&rng1 {
+	status = "okay";
+};
+
+&rtc {
+	status = "okay";
+};
+
+&sdmmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+	broken-cd;
+	st,sig-dir;
+	st,neg-edge;
+	st,use-ckin;
+	bus-width = <4>;
+	vmmc-supply = <&vdda>;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins_b>;
+	status = "okay";
+};
+
+/* ATF Specific */
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
+#include "stm32mp157c-security.dtsi"
+
+/ {
+	aliases {
+		gpio0 = &gpioa;
+		gpio1 = &gpiob;
+		gpio2 = &gpioc;
+		gpio3 = &gpiod;
+		gpio4 = &gpioe;
+		gpio5 = &gpiof;
+		gpio6 = &gpiog;
+		gpio7 = &gpioh;
+		gpio8 = &gpioi;
+		gpio25 = &gpioz;
+		i2c3 = &i2c4;
+	};
+};
+
+/* CLOCK init */
+&rcc {
+	secure-status = "disabled";
+	st,clksrc = <
+		CLK_MPU_PLL1P
+		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
+		CLK_PLL12_HSE
+		CLK_PLL3_HSE
+		CLK_PLL4_HSE
+		CLK_RTC_LSE
+		CLK_MCO1_DISABLED
+		CLK_MCO2_DISABLED
+	>;
+
+	st,clkdiv = <
+		1 /*MPU*/
+		0 /*AXI*/
+		0 /*MCU*/
+		1 /*APB1*/
+		1 /*APB2*/
+		1 /*APB3*/
+		1 /*APB4*/
+		2 /*APB5*/
+		23 /*RTC*/
+		0 /*MCO1*/
+		0 /*MCO2*/
+	>;
+
+	st,pkcs = <
+		CLK_CKPER_HSE
+		CLK_FMC_ACLK
+		CLK_QSPI_ACLK
+		CLK_ETH_DISABLED
+		CLK_SDMMC12_PLL4P
+		CLK_DSI_DSIPLL
+		CLK_STGEN_HSE
+		CLK_USBPHY_HSE
+		CLK_SPI2S1_PLL3Q
+		CLK_SPI2S23_PLL3Q
+		CLK_SPI45_HSI
+		CLK_SPI6_HSI
+		CLK_I2C46_HSI
+		CLK_SDMMC3_PLL4P
+		CLK_USBO_USBPHY
+		CLK_ADC_CKPER
+		CLK_CEC_LSE
+		CLK_I2C12_HSI
+		CLK_I2C35_HSI
+		CLK_UART1_HSI
+		CLK_UART24_HSI
+		CLK_UART35_HSI
+		CLK_UART6_HSI
+		CLK_UART78_HSI
+		CLK_SPDIF_PLL4P
+		CLK_FDCAN_PLL4Q
+		CLK_SAI1_PLL3Q
+		CLK_SAI2_PLL3Q
+		CLK_SAI3_PLL3Q
+		CLK_SAI4_PLL3Q
+		CLK_RNG1_LSI
+		CLK_RNG2_LSI
+		CLK_LPTIM1_PCLK1
+		CLK_LPTIM23_PCLK3
+		CLK_LPTIM45_LSE
+	>;
+
+	/* VCO = 1300.0 MHz => P = 650 (CPU) */
+	pll1: st,pll@0 {
+		cfg = < 2 80 0 0 0 PQR(1,0,0) >;
+		frac = < 0x800 >;
+	};
+
+	/* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+	pll2: st,pll@1 {
+		cfg = < 2 65 1 0 0 PQR(1,1,1) >;
+		frac = < 0x1400 >;
+	};
+
+	/* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+	pll3: st,pll@2 {
+		cfg = < 1 33 1 16 36 PQR(1,1,1) >;
+		frac = < 0x1a04 >;
+	};
+
+	/* VCO = 480.0 MHz => P = 120, Q = 40, R = 96 */
+	pll4: st,pll@3 {
+		cfg = < 1 39 3 11 4 PQR(1,1,1) >;
+	};
+};
diff --git a/fdts/stm32mp157a-dk1.dts b/fdts/stm32mp157a-dk1.dts
new file mode 100644
index 0000000..b17d501
--- /dev/null
+++ b/fdts/stm32mp157a-dk1.dts
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2018-2019 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157cac-pinctrl.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32MP157A-DK1 Discovery Board";
+	compatible = "st,stm32mp157a-dk1", "st,stm32mp157";
+
+	aliases {
+		serial0 = &uart4;
+		serial1 = &usart3;
+		serial2 = &uart7;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+};
+
+&clk_hse {
+	st,digbypass;
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins_a>;
+	i2c-scl-rising-time-ns = <185>;
+	i2c-scl-falling-time-ns = <20>;
+	status = "okay";
+
+	pmic: stpmic@33 {
+		compatible = "st,stpmic1";
+		reg = <0x33>;
+		interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		status = "okay";
+
+		st,main-control-register = <0x04>;
+		st,vin-control-register = <0xc0>;
+		st,usb-control-register = <0x20>;
+
+		regulators {
+			compatible = "st,stpmic1-regulators";
+
+			ldo1-supply = <&v3v3>;
+			ldo3-supply = <&vdd_ddr>;
+			ldo6-supply = <&v3v3>;
+
+			vddcore: buck1 {
+				regulator-name = "vddcore";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			vdd_ddr: buck2 {
+				regulator-name = "vdd_ddr";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			vdd: buck3 {
+				regulator-name = "vdd";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				st,mask-reset;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			v3v3: buck4 {
+				regulator-name = "v3v3";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+				regulator-initial-mode = <0>;
+			};
+
+			v1v8_audio: ldo1 {
+				regulator-name = "v1v8_audio";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+			};
+
+			v3v3_hdmi: ldo2 {
+				regulator-name = "v3v3_hdmi";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vtt_ddr: ldo3 {
+				regulator-name = "vtt_ddr";
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <750000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+
+			vdd_usb: ldo4 {
+				regulator-name = "vdd_usb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vdda: ldo5 {
+				regulator-name = "vdda";
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+				regulator-boot-on;
+			};
+
+			v1v2_hdmi: ldo6 {
+				regulator-name = "v1v2_hdmi";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-always-on;
+			};
+
+			vref_ddr: vref_ddr {
+				regulator-name = "vref_ddr";
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+		};
+	};
+};
+
+&iwdg2 {
+	timeout-sec = <32>;
+	status = "okay";
+};
+
+&pwr {
+	pwr-regulators {
+		vdd-supply = <&vdd>;
+	};
+};
+
+&rng1 {
+	status = "okay";
+};
+
+&rtc {
+	status = "okay";
+};
+
+&sdmmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc1_b4_pins_a>;
+	broken-cd;
+	st,neg-edge;
+	bus-width = <4>;
+	vmmc-supply = <&v3v3>;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins_a>;
+	status = "okay";
+};
+
+&uart7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart7_pins_a>;
+	status = "disabled";
+};
+
+&usart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usart3_pins_b>;
+	status = "disabled";
+};
+
+/* ATF Specific */
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi"
+#include "stm32mp157c-security.dtsi"
+
+/ {
+	aliases {
+		gpio0 = &gpioa;
+		gpio1 = &gpiob;
+		gpio2 = &gpioc;
+		gpio3 = &gpiod;
+		gpio4 = &gpioe;
+		gpio5 = &gpiof;
+		gpio6 = &gpiog;
+		gpio7 = &gpioh;
+		gpio8 = &gpioi;
+		gpio25 = &gpioz;
+		i2c3 = &i2c4;
+	};
+};
+
+/* CLOCK init */
+&rcc {
+	secure-status = "disabled";
+	st,clksrc = <
+		CLK_MPU_PLL1P
+		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
+		CLK_PLL12_HSE
+		CLK_PLL3_HSE
+		CLK_PLL4_HSE
+		CLK_RTC_LSE
+		CLK_MCO1_DISABLED
+		CLK_MCO2_DISABLED
+	>;
+
+	st,clkdiv = <
+		1 /*MPU*/
+		0 /*AXI*/
+		0 /*MCU*/
+		1 /*APB1*/
+		1 /*APB2*/
+		1 /*APB3*/
+		1 /*APB4*/
+		2 /*APB5*/
+		23 /*RTC*/
+		0 /*MCO1*/
+		0 /*MCO2*/
+	>;
+
+	st,pkcs = <
+		CLK_CKPER_HSE
+		CLK_FMC_ACLK
+		CLK_QSPI_ACLK
+		CLK_ETH_DISABLED
+		CLK_SDMMC12_PLL4P
+		CLK_DSI_DSIPLL
+		CLK_STGEN_HSE
+		CLK_USBPHY_HSE
+		CLK_SPI2S1_PLL3Q
+		CLK_SPI2S23_PLL3Q
+		CLK_SPI45_HSI
+		CLK_SPI6_HSI
+		CLK_I2C46_HSI
+		CLK_SDMMC3_PLL4P
+		CLK_USBO_USBPHY
+		CLK_ADC_CKPER
+		CLK_CEC_LSE
+		CLK_I2C12_HSI
+		CLK_I2C35_HSI
+		CLK_UART1_HSI
+		CLK_UART24_HSI
+		CLK_UART35_HSI
+		CLK_UART6_HSI
+		CLK_UART78_HSI
+		CLK_SPDIF_PLL4P
+		CLK_FDCAN_PLL4Q
+		CLK_SAI1_PLL3Q
+		CLK_SAI2_PLL3Q
+		CLK_SAI3_PLL3Q
+		CLK_SAI4_PLL3Q
+		CLK_RNG1_LSI
+		CLK_RNG2_LSI
+		CLK_LPTIM1_PCLK1
+		CLK_LPTIM23_PCLK3
+		CLK_LPTIM45_LSE
+	>;
+
+	/* VCO = 1300.0 MHz => P = 650 (CPU) */
+	pll1: st,pll@0 {
+		cfg = < 2 80 0 0 0 PQR(1,0,0) >;
+		frac = < 0x800 >;
+	};
+
+	/* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+	pll2: st,pll@1 {
+		cfg = < 2 65 1 0 0 PQR(1,1,1) >;
+		frac = < 0x1400 >;
+	};
+
+	/* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+	pll3: st,pll@2 {
+		cfg = < 1 33 1 16 36 PQR(1,1,1) >;
+		frac = < 0x1a04 >;
+	};
+
+	/* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
+	pll4: st,pll@3 {
+		cfg = < 3 98 5 7 7 PQR(1,1,1) >;
+	};
+};
+
+&bsec {
+	board_id: board_id@ec {
+		reg = <0xec 0x4>;
+		status = "okay";
+		secure-status = "okay";
+	};
+};
diff --git a/fdts/stm32mp157c-dk2.dts b/fdts/stm32mp157c-dk2.dts
new file mode 100644
index 0000000..fdcf4c8
--- /dev/null
+++ b/fdts/stm32mp157c-dk2.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>.
+ */
+
+/dts-v1/;
+
+#include "stm32mp157a-dk1.dts"
+
+/ {
+	model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
+	compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
+
+};
+
diff --git a/fdts/stm32mp157c-ed1.dts b/fdts/stm32mp157c-ed1.dts
new file mode 100644
index 0000000..ed55725
--- /dev/null
+++ b/fdts/stm32mp157c-ed1.dts
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157c.dtsi"
+#include "stm32mp157caa-pinctrl.dtsi"
+
+/ {
+	model = "STMicroelectronics STM32MP157C eval daughter";
+	compatible = "st,stm32mp157c-ed1", "st,stm32mp157";
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	aliases {
+		serial0 = &uart4;
+	};
+};
+
+&clk_hse {
+	st,digbypass;
+};
+
+&i2c4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c4_pins_a>;
+	i2c-scl-rising-time-ns = <185>;
+	i2c-scl-falling-time-ns = <20>;
+	status = "okay";
+
+	pmic: stpmic@33 {
+		compatible = "st,stpmic1";
+		reg = <0x33>;
+		interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		status = "okay";
+
+		st,main-control-register = <0x04>;
+		st,vin-control-register = <0xc0>;
+		st,usb-control-register = <0x20>;
+
+		regulators {
+			compatible = "st,stpmic1-regulators";
+
+			ldo1-supply = <&v3v3>;
+			ldo2-supply = <&v3v3>;
+			ldo3-supply = <&vdd_ddr>;
+			ldo5-supply = <&v3v3>;
+			ldo6-supply = <&v3v3>;
+
+			vddcore: buck1 {
+				regulator-name = "vddcore";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			vdd_ddr: buck2 {
+				regulator-name = "vdd_ddr";
+				regulator-min-microvolt = <1350000>;
+				regulator-max-microvolt = <1350000>;
+				regulator-always-on;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			vdd: buck3 {
+				regulator-name = "vdd";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				st,mask-reset;
+				regulator-initial-mode = <0>;
+				regulator-over-current-protection;
+			};
+
+			v3v3: buck4 {
+				regulator-name = "v3v3";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+				regulator-initial-mode = <0>;
+			};
+
+			vdda: ldo1 {
+				regulator-name = "vdda";
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+			};
+
+			v2v8: ldo2 {
+				regulator-name = "v2v8";
+				regulator-min-microvolt = <2800000>;
+				regulator-max-microvolt = <2800000>;
+			};
+
+			vtt_ddr: ldo3 {
+				regulator-name = "vtt_ddr";
+				regulator-min-microvolt = <500000>;
+				regulator-max-microvolt = <750000>;
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+
+			vdd_usb: ldo4 {
+				regulator-name = "vdd_usb";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vdd_sd: ldo5 {
+				regulator-name = "vdd_sd";
+				regulator-min-microvolt = <2900000>;
+				regulator-max-microvolt = <2900000>;
+				regulator-boot-on;
+			};
+
+			v1v8: ldo6 {
+				regulator-name = "v1v8";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+			};
+
+			vref_ddr: vref_ddr {
+				regulator-name = "vref_ddr";
+				regulator-always-on;
+				regulator-over-current-protection;
+			};
+		};
+	};
+};
+
+&iwdg2 {
+	timeout-sec = <32>;
+	status = "okay";
+};
+
+&pwr {
+	pwr-regulators {
+		vdd-supply = <&vdd>;
+	};
+};
+
+&rng1 {
+	status = "okay";
+};
+
+&rtc {
+	status = "okay";
+};
+
+&sdmmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;
+	broken-cd;
+	st,sig-dir;
+	st,neg-edge;
+	st,use-ckin;
+	bus-width = <4>;
+	vmmc-supply = <&vdd_sd>;
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-ddr50;
+	sd-uhs-sdr104;
+	status = "okay";
+};
+
+&sdmmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	st,neg-edge;
+	bus-width = <8>;
+	vmmc-supply = <&v3v3>;
+	vqmmc-supply = <&v3v3>;
+	mmc-ddr-3_3v;
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart4_pins_a>;
+	status = "okay";
+};
+
+/* ATF Specific */
+#include <dt-bindings/clock/stm32mp1-clksrc.h>
+#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
+#include "stm32mp157c-security.dtsi"
+
+/ {
+	aliases {
+		gpio0 = &gpioa;
+		gpio1 = &gpiob;
+		gpio2 = &gpioc;
+		gpio3 = &gpiod;
+		gpio4 = &gpioe;
+		gpio5 = &gpiof;
+		gpio6 = &gpiog;
+		gpio7 = &gpioh;
+		gpio8 = &gpioi;
+		gpio9 = &gpioj;
+		gpio10 = &gpiok;
+		gpio25 = &gpioz;
+		i2c3 = &i2c4;
+	};
+};
+
+/* CLOCK init */
+&rcc {
+	secure-status = "disabled";
+	st,clksrc = <
+		CLK_MPU_PLL1P
+		CLK_AXI_PLL2P
+		CLK_MCU_PLL3P
+		CLK_PLL12_HSE
+		CLK_PLL3_HSE
+		CLK_PLL4_HSE
+		CLK_RTC_LSE
+		CLK_MCO1_DISABLED
+		CLK_MCO2_DISABLED
+	>;
+
+	st,clkdiv = <
+		1 /*MPU*/
+		0 /*AXI*/
+		0 /*MCU*/
+		1 /*APB1*/
+		1 /*APB2*/
+		1 /*APB3*/
+		1 /*APB4*/
+		2 /*APB5*/
+		23 /*RTC*/
+		0 /*MCO1*/
+		0 /*MCO2*/
+	>;
+
+	st,pkcs = <
+		CLK_CKPER_HSE
+		CLK_FMC_ACLK
+		CLK_QSPI_ACLK
+		CLK_ETH_DISABLED
+		CLK_SDMMC12_PLL4P
+		CLK_DSI_DSIPLL
+		CLK_STGEN_HSE
+		CLK_USBPHY_HSE
+		CLK_SPI2S1_PLL3Q
+		CLK_SPI2S23_PLL3Q
+		CLK_SPI45_HSI
+		CLK_SPI6_HSI
+		CLK_I2C46_HSI
+		CLK_SDMMC3_PLL4P
+		CLK_USBO_USBPHY
+		CLK_ADC_CKPER
+		CLK_CEC_LSE
+		CLK_I2C12_HSI
+		CLK_I2C35_HSI
+		CLK_UART1_HSI
+		CLK_UART24_HSI
+		CLK_UART35_HSI
+		CLK_UART6_HSI
+		CLK_UART78_HSI
+		CLK_SPDIF_PLL4P
+		CLK_FDCAN_PLL4Q
+		CLK_SAI1_PLL3Q
+		CLK_SAI2_PLL3Q
+		CLK_SAI3_PLL3Q
+		CLK_SAI4_PLL3Q
+		CLK_RNG1_LSI
+		CLK_RNG2_LSI
+		CLK_LPTIM1_PCLK1
+		CLK_LPTIM23_PCLK3
+		CLK_LPTIM45_LSE
+	>;
+
+	/* VCO = 1300.0 MHz => P = 650 (CPU) */
+	pll1: st,pll@0 {
+		cfg = < 2 80 0 0 0 PQR(1,0,0) >;
+		frac = < 0x800 >;
+	};
+
+	/* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */
+	pll2: st,pll@1 {
+		cfg = < 2 65 1 0 0 PQR(1,1,1) >;
+		frac = < 0x1400 >;
+	};
+
+	/* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */
+	pll3: st,pll@2 {
+		cfg = < 1 33 1 16 36 PQR(1,1,1) >;
+		frac = < 0x1a04 >;
+	};
+
+	/* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */
+	pll4: st,pll@3 {
+		cfg = < 3 98 5 7 7 PQR(1,1,1) >;
+	};
+};
+
+&bsec {
+	board_id: board_id@ec {
+		reg = <0xec 0x4>;
+		status = "okay";
+		secure-status = "okay";
+	};
+};
diff --git a/fdts/stm32mp157c-ev1.dts b/fdts/stm32mp157c-ev1.dts
new file mode 100644
index 0000000..cfde8ed
--- /dev/null
+++ b/fdts/stm32mp157c-ev1.dts
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+/dts-v1/;
+
+#include "stm32mp157c-ed1.dts"
+
+/ {
+	model = "STMicroelectronics STM32MP157C eval daughter on eval mother";
+	compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157";
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	aliases {
+		serial1 = &usart3;
+	};
+};
+
+&fmc {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	nand: nand@0 {
+		reg = <0>;
+		nand-on-flash-bbt;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&qspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>;
+	reg = <0x58003000 0x1000>, <0x70000000 0x4000000>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "okay";
+
+	flash0: mx66l51235l@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-rx-bus-width = <4>;
+		spi-max-frequency = <108000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+
+	flash1: mx66l51235l@1 {
+		compatible = "jedec,spi-nor";
+		reg = <1>;
+		spi-rx-bus-width = <4>;
+		spi-max-frequency = <108000000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&usart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usart3_pins_a>;
+	status = "disabled";
+};
diff --git a/fdts/stm32mp157c-security.dtsi b/fdts/stm32mp157c-security.dtsi
new file mode 100644
index 0000000..f7e55b3
--- /dev/null
+++ b/fdts/stm32mp157c-security.dtsi
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier:	GPL-2.0+	BSD-3-Clause
+ */
+
+/ {
+	soc {
+		stgen: stgen@5c008000 {
+			compatible = "st,stm32-stgen";
+			reg = <0x5C008000 0x1000>;
+			status = "okay";
+		};
+	};
+};
+
+&bsec {
+	mac_addr: mac_addr@e4 {
+		reg = <0xe4 0x6>;
+		status = "okay";
+		secure-status = "okay";
+	};
+	/* Spare field to align on 32-bit OTP granularity  */
+	spare_ns_ea: spare_ns_ea@ea {
+		reg = <0xea 0x2>;
+		status = "okay";
+		secure-status = "okay";
+	};
+};
+
+&sdmmc1 {
+	compatible = "st,stm32-sdmmc2";
+};
+
+&sdmmc2 {
+	compatible = "st,stm32-sdmmc2";
+};
diff --git a/fdts/stm32mp157c.dtsi b/fdts/stm32mp157c.dtsi
new file mode 100644
index 0000000..0942a91
--- /dev/null
+++ b/fdts/stm32mp157c.dtsi
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@st.com> for STMicroelectronics.
+ */
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/stm32mp1-clks.h>
+#include <dt-bindings/reset/stm32mp1-resets.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	intc: interrupt-controller@a0021000 {
+		compatible = "arm,cortex-a7-gic";
+		#interrupt-cells = <3>;
+		interrupt-controller;
+		reg = <0xa0021000 0x1000>,
+		      <0xa0022000 0x2000>;
+	};
+
+	clocks {
+		clk_hse: clk-hse {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+		};
+
+		clk_hsi: clk-hsi {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <64000000>;
+		};
+
+		clk_lse: clk-lse {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <32768>;
+		};
+
+		clk_lsi: clk-lsi {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <32000>;
+		};
+
+		clk_csi: clk-csi {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <4000000>;
+		};
+
+		clk_i2s_ckin: i2s_ckin {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		clk_dsi_phy: ck_dsi_phy {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-frequency = <0>;
+		};
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-parent = <&intc>;
+		ranges;
+
+		timers12: timer@40006000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "st,stm32-timers";
+			reg = <0x40006000 0x400>;
+			clocks = <&rcc TIM12_K>;
+			clock-names = "int";
+			status = "disabled";
+		};
+
+		usart2: serial@4000e000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x4000e000 0x400>;
+			clocks = <&rcc USART2_K>;
+			resets = <&rcc USART2_R>;
+			status = "disabled";
+		};
+
+		usart3: serial@4000f000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x4000f000 0x400>;
+			clocks = <&rcc USART3_K>;
+			resets = <&rcc USART3_R>;
+			status = "disabled";
+		};
+
+		uart4: serial@40010000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x40010000 0x400>;
+			clocks = <&rcc UART4_K>;
+			resets = <&rcc UART4_R>;
+			status = "disabled";
+		};
+
+		uart5: serial@40011000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x40011000 0x400>;
+			clocks = <&rcc UART5_K>;
+			resets = <&rcc UART5_R>;
+			status = "disabled";
+		};
+
+
+		uart7: serial@40018000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x40018000 0x400>;
+			clocks = <&rcc UART7_K>;
+			resets = <&rcc UART7_R>;
+			status = "disabled";
+		};
+
+		uart8: serial@40019000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x40019000 0x400>;
+			clocks = <&rcc UART8_K>;
+			resets = <&rcc UART8_R>;
+			status = "disabled";
+		};
+
+		usart6: serial@44003000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x44003000 0x400>;
+			clocks = <&rcc USART6_K>;
+			resets = <&rcc USART6_R>;
+			status = "disabled";
+		};
+
+		timers15: timer@44006000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "st,stm32-timers";
+			reg = <0x44006000 0x400>;
+			clocks = <&rcc TIM15_K>;
+			clock-names = "int";
+			status = "disabled";
+		};
+
+		sdmmc3: sdmmc@48004000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			arm,primecell-periphid = <0x00253180>;
+			reg = <0x48004000 0x400>, <0x48005000 0x400>;
+			clocks = <&rcc SDMMC3_K>;
+			clock-names = "apb_pclk";
+			resets = <&rcc SDMMC3_R>;
+			cap-sd-highspeed;
+			cap-mmc-highspeed;
+			max-frequency = <120000000>;
+			status = "disabled";
+		};
+
+		usbotg_hs: usb-otg@49000000 {
+			compatible = "st,stm32mp1-hsotg", "snps,dwc2";
+			reg = <0x49000000 0x10000>;
+			clocks = <&rcc USBO_K>;
+			clock-names = "otg";
+			resets = <&rcc USBO_R>;
+			reset-names = "dwc2";
+			status = "disabled";
+		};
+
+		rcc: rcc@50000000 {
+			compatible = "st,stm32mp1-rcc", "syscon";
+			reg = <0x50000000 0x1000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pwr: pwr@50001000 {
+			compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd";
+			reg = <0x50001000 0x400>;
+		};
+
+		exti: interrupt-controller@5000d000 {
+			compatible = "st,stm32mp1-exti", "syscon";
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			reg = <0x5000d000 0x400>;
+
+			/* exti_pwr is an extra interrupt controller used for
+			 * EXTI 55 to 60. It's mapped on pwr interrupt
+			 * controller.
+			 */
+			exti_pwr: exti-pwr {
+				interrupt-controller;
+				#interrupt-cells = <2>;
+				interrupt-parent = <&pwr>;
+				st,irq-number = <6>;
+			};
+		};
+
+		syscfg: syscon@50020000 {
+			compatible = "st,stm32mp157-syscfg", "syscon";
+			reg = <0x50020000 0x400>;
+			clocks = <&rcc SYSCFG>;
+		};
+
+		cryp1: cryp@54001000 {
+			compatible = "st,stm32mp1-cryp";
+			reg = <0x54001000 0x400>;
+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&rcc CRYP1>;
+			resets = <&rcc CRYP1_R>;
+			status = "disabled";
+		};
+
+		hash1: hash@54002000 {
+			compatible = "st,stm32f756-hash";
+			reg = <0x54002000 0x400>;
+			interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&rcc HASH1>;
+			resets = <&rcc HASH1_R>;
+			status = "disabled";
+		};
+
+		rng1: rng@54003000 {
+			compatible = "st,stm32-rng";
+			reg = <0x54003000 0x400>;
+			clocks = <&rcc RNG1_K>;
+			resets = <&rcc RNG1_R>;
+			status = "disabled";
+		};
+
+		fmc: nand-controller@58002000 {
+			compatible = "st,stm32mp15-fmc2";
+			reg = <0x58002000 0x1000>,
+			      <0x80000000 0x1000>,
+			      <0x88010000 0x1000>,
+			      <0x88020000 0x1000>,
+			      <0x81000000 0x1000>,
+			      <0x89010000 0x1000>,
+			      <0x89020000 0x1000>;
+			clocks = <&rcc FMC_K>;
+			resets = <&rcc FMC_R>;
+			status = "disabled";
+		};
+
+		qspi: qspi@58003000 {
+			compatible = "st,stm32f469-qspi";
+			reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
+			reg-names = "qspi", "qspi_mm";
+			clocks = <&rcc QSPI_K>;
+			resets = <&rcc QSPI_R>;
+			status = "disabled";
+		};
+
+		sdmmc1: sdmmc@58005000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			arm,primecell-periphid = <0x00253180>;
+			reg = <0x58005000 0x1000>, <0x58006000 0x1000>;
+			clocks = <&rcc SDMMC1_K>;
+			clock-names = "apb_pclk";
+			resets = <&rcc SDMMC1_R>;
+			cap-sd-highspeed;
+			cap-mmc-highspeed;
+			max-frequency = <120000000>;
+			status = "disabled";
+		};
+
+		sdmmc2: sdmmc@58007000 {
+			compatible = "arm,pl18x", "arm,primecell";
+			arm,primecell-periphid = <0x00253180>;
+			reg = <0x58007000 0x1000>, <0x58008000 0x1000>;
+			clocks = <&rcc SDMMC2_K>;
+			clock-names = "apb_pclk";
+			resets = <&rcc SDMMC2_R>;
+			cap-sd-highspeed;
+			cap-mmc-highspeed;
+			max-frequency = <120000000>;
+			status = "disabled";
+		};
+
+		iwdg2: watchdog@5a002000 {
+			compatible = "st,stm32mp1-iwdg";
+			reg = <0x5a002000 0x400>;
+			clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
+			clock-names = "pclk", "lsi";
+			status = "disabled";
+		};
+
+		usart1: serial@5c000000 {
+			compatible = "st,stm32h7-uart";
+			reg = <0x5c000000 0x400>;
+			interrupt-names = "event", "wakeup";
+			interrupts-extended = <&intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>,
+					      <&exti 26 1>;
+			clocks = <&rcc USART1_K>;
+			resets = <&rcc USART1_R>;
+			status = "disabled";
+		};
+
+		spi6: spi@5c001000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "st,stm32h7-spi";
+			reg = <0x5c001000 0x400>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&rcc SPI6_K>;
+			resets = <&rcc SPI6_R>;
+			status = "disabled";
+		};
+
+		i2c4: i2c@5c002000 {
+			compatible = "st,stm32f7-i2c";
+			reg = <0x5c002000 0x400>;
+			interrupt-names = "event", "error", "wakeup";
+			interrupts-extended = <&intc GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>,
+					      <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+					      <&exti 24 1>;
+			clocks = <&rcc I2C4_K>;
+			resets = <&rcc I2C4_R>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		rtc: rtc@5c004000 {
+			compatible = "st,stm32mp1-rtc";
+			reg = <0x5c004000 0x400>;
+			clocks = <&rcc RTCAPB>, <&rcc RTC>;
+			clock-names = "pclk", "rtc_ck";
+			interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+					      <&exti 19 1>;
+			status = "disabled";
+		};
+
+		bsec: nvmem@5c005000 {
+			compatible = "st,stm32mp15-bsec";
+			reg = <0x5c005000 0x400>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ts_cal1: calib@5c {
+				reg = <0x5c 0x2>;
+			};
+			ts_cal2: calib@5e {
+				reg = <0x5e 0x2>;
+			};
+		};
+
+		i2c6: i2c@5c009000 {
+			compatible = "st,stm32f7-i2c";
+			reg = <0x5c009000 0x400>;
+			interrupt-names = "event", "error", "wakeup";
+			interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+					      <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
+					      <&exti 54 1>;
+			clocks = <&rcc I2C6_K>;
+			resets = <&rcc I2C6_R>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/fdts/stm32mp157caa-pinctrl.dtsi b/fdts/stm32mp157caa-pinctrl.dtsi
new file mode 100644
index 0000000..9b9cd08
--- /dev/null
+++ b/fdts/stm32mp157caa-pinctrl.dtsi
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+#include "stm32mp157-pinctrl.dtsi"
+/ {
+	soc {
+		pinctrl: pin-controller@50002000 {
+			st,package = <STM32MP157CAA>;
+
+			gpioa: gpio@50002000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 0 16>;
+			};
+
+			gpiob: gpio@50003000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 16 16>;
+			};
+
+			gpioc: gpio@50004000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 32 16>;
+			};
+
+			gpiod: gpio@50005000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 48 16>;
+			};
+
+			gpioe: gpio@50006000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 64 16>;
+			};
+
+			gpiof: gpio@50007000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 80 16>;
+			};
+
+			gpiog: gpio@50008000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 96 16>;
+			};
+
+			gpioh: gpio@50009000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 112 16>;
+			};
+
+			gpioi: gpio@5000a000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 128 16>;
+			};
+
+			gpioj: gpio@5000b000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 144 16>;
+			};
+
+			gpiok: gpio@5000c000 {
+				status = "okay";
+				ngpios = <8>;
+				gpio-ranges = <&pinctrl 0 160 8>;
+			};
+		};
+
+		pinctrl_z: pin-controller-z@54004000 {
+			st,package = <STM32MP157CAA>;
+
+			gpioz: gpio@54004000 {
+				status = "okay";
+				ngpios = <8>;
+				gpio-ranges = <&pinctrl_z 0 400 8>;
+			};
+		};
+	};
+};
diff --git a/fdts/stm32mp157cac-pinctrl.dtsi b/fdts/stm32mp157cac-pinctrl.dtsi
new file mode 100644
index 0000000..777f991
--- /dev/null
+++ b/fdts/stm32mp157cac-pinctrl.dtsi
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Alexandre Torgue <alexandre.torgue@st.com>
+ */
+
+#include "stm32mp157-pinctrl.dtsi"
+/ {
+	soc {
+		pinctrl: pin-controller@50002000 {
+			st,package = <STM32MP157CAC>;
+
+			gpioa: gpio@50002000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 0 16>;
+			};
+
+			gpiob: gpio@50003000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 16 16>;
+			};
+
+			gpioc: gpio@50004000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 32 16>;
+			};
+
+			gpiod: gpio@50005000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 48 16>;
+			};
+
+			gpioe: gpio@50006000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 64 16>;
+			};
+
+			gpiof: gpio@50007000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 80 16>;
+			};
+
+			gpiog: gpio@50008000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 96 16>;
+			};
+
+			gpioh: gpio@50009000 {
+				status = "okay";
+				ngpios = <16>;
+				gpio-ranges = <&pinctrl 0 112 16>;
+			};
+
+			gpioi: gpio@5000a000 {
+				status = "okay";
+				ngpios = <12>;
+				gpio-ranges = <&pinctrl 0 128 12>;
+			};
+		};
+
+		pinctrl_z: pin-controller-z@54004000 {
+			st,package = <STM32MP157CAC>;
+
+			gpioz: gpio@54004000 {
+				status = "okay";
+				ngpios = <8>;
+				gpio-ranges = <&pinctrl_z 0 400 8>;
+			};
+		};
+	};
+};
diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
new file mode 100644
index 0000000..34036d7
--- /dev/null
+++ b/include/arch/aarch32/arch.h
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * MIDR bit definitions
+ ******************************************************************************/
+#define MIDR_IMPL_MASK		U(0xff)
+#define MIDR_IMPL_SHIFT		U(24)
+#define MIDR_VAR_SHIFT		U(20)
+#define MIDR_VAR_BITS		U(4)
+#define MIDR_REV_SHIFT		U(0)
+#define MIDR_REV_BITS		U(4)
+#define MIDR_PN_MASK		U(0xfff)
+#define MIDR_PN_SHIFT		U(4)
+
+/*******************************************************************************
+ * MPIDR macros
+ ******************************************************************************/
+#define MPIDR_MT_MASK		(U(1) << 24)
+#define MPIDR_CPU_MASK		MPIDR_AFFLVL_MASK
+#define MPIDR_CLUSTER_MASK	(MPIDR_AFFLVL_MASK << MPIDR_AFFINITY_BITS)
+#define MPIDR_AFFINITY_BITS	U(8)
+#define MPIDR_AFFLVL_MASK	U(0xff)
+#define MPIDR_AFFLVL_SHIFT	U(3)
+#define MPIDR_AFF0_SHIFT	U(0)
+#define MPIDR_AFF1_SHIFT	U(8)
+#define MPIDR_AFF2_SHIFT	U(16)
+#define MPIDR_AFF_SHIFT(_n)	MPIDR_AFF##_n##_SHIFT
+#define MPIDR_AFFINITY_MASK	U(0x00ffffff)
+#define MPIDR_AFFLVL0		U(0)
+#define MPIDR_AFFLVL1		U(1)
+#define MPIDR_AFFLVL2		U(2)
+#define MPIDR_AFFLVL(_n)	MPIDR_AFFLVL##_n
+
+#define MPIDR_AFFLVL0_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL1_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL2_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL3_VAL(mpidr)	U(0)
+
+#define MPIDR_AFF_ID(mpid, n)					\
+	(((mpid) >> MPIDR_AFF_SHIFT(n)) & MPIDR_AFFLVL_MASK)
+
+#define MPID_MASK		(MPIDR_MT_MASK				|\
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT)|\
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF1_SHIFT)|\
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT))
+
+/*
+ * An invalid MPID. This value can be used by functions that return an MPID to
+ * indicate an error.
+ */
+#define INVALID_MPID		U(0xFFFFFFFF)
+
+/*
+ * The MPIDR_MAX_AFFLVL count starts from 0. Take care to
+ * add one while using this macro to define array sizes.
+ */
+#define MPIDR_MAX_AFFLVL	U(2)
+
+/* Data Cache set/way op type defines */
+#define DC_OP_ISW			U(0x0)
+#define DC_OP_CISW			U(0x1)
+#if ERRATA_A53_827319
+#define DC_OP_CSW			DC_OP_CISW
+#else
+#define DC_OP_CSW			U(0x2)
+#endif
+
+/*******************************************************************************
+ * Generic timer memory mapped registers & offsets
+ ******************************************************************************/
+#define CNTCR_OFF			U(0x000)
+/* Counter Count Value Lower register */
+#define CNTCVL_OFF			U(0x008)
+/* Counter Count Value Upper register */
+#define CNTCVU_OFF			U(0x00C)
+#define CNTFID_OFF			U(0x020)
+
+#define CNTCR_EN			(U(1) << 0)
+#define CNTCR_HDBG			(U(1) << 1)
+#define CNTCR_FCREQ(x)			((x) << 8)
+
+/*******************************************************************************
+ * System register bit definitions
+ ******************************************************************************/
+/* CLIDR definitions */
+#define LOUIS_SHIFT		U(21)
+#define LOC_SHIFT		U(24)
+#define CLIDR_FIELD_WIDTH	U(3)
+
+/* CSSELR definitions */
+#define LEVEL_SHIFT		U(1)
+
+/* ID_MMFR4 definitions */
+#define ID_MMFR4_CNP_SHIFT	U(12)
+#define ID_MMFR4_CNP_LENGTH	U(4)
+#define ID_MMFR4_CNP_MASK	U(0xf)
+
+/* ID_PFR0 definitions */
+#define ID_PFR0_AMU_SHIFT	U(20)
+#define ID_PFR0_AMU_LENGTH	U(4)
+#define ID_PFR0_AMU_MASK	U(0xf)
+
+#define ID_PFR0_DIT_SHIFT	U(24)
+#define ID_PFR0_DIT_LENGTH	U(4)
+#define ID_PFR0_DIT_MASK	U(0xf)
+#define ID_PFR0_DIT_SUPPORTED	(U(1) << ID_PFR0_DIT_SHIFT)
+
+/* ID_PFR1 definitions */
+#define ID_PFR1_VIRTEXT_SHIFT	U(12)
+#define ID_PFR1_VIRTEXT_MASK	U(0xf)
+#define GET_VIRT_EXT(id)	(((id) >> ID_PFR1_VIRTEXT_SHIFT) \
+				 & ID_PFR1_VIRTEXT_MASK)
+#define ID_PFR1_GENTIMER_SHIFT	U(16)
+#define ID_PFR1_GENTIMER_MASK	U(0xf)
+#define ID_PFR1_GIC_SHIFT	U(28)
+#define ID_PFR1_GIC_MASK	U(0xf)
+
+/* SCTLR definitions */
+#define SCTLR_RES1_DEF		((U(1) << 23) | (U(1) << 22) | (U(1) << 4) | \
+				 (U(1) << 3))
+#if ARM_ARCH_MAJOR == 7
+#define SCTLR_RES1		SCTLR_RES1_DEF
+#else
+#define SCTLR_RES1		(SCTLR_RES1_DEF | (U(1) << 11))
+#endif
+#define SCTLR_M_BIT		(U(1) << 0)
+#define SCTLR_A_BIT		(U(1) << 1)
+#define SCTLR_C_BIT		(U(1) << 2)
+#define SCTLR_CP15BEN_BIT	(U(1) << 5)
+#define SCTLR_ITD_BIT		(U(1) << 7)
+#define SCTLR_Z_BIT		(U(1) << 11)
+#define SCTLR_I_BIT		(U(1) << 12)
+#define SCTLR_V_BIT		(U(1) << 13)
+#define SCTLR_RR_BIT		(U(1) << 14)
+#define SCTLR_NTWI_BIT		(U(1) << 16)
+#define SCTLR_NTWE_BIT		(U(1) << 18)
+#define SCTLR_WXN_BIT		(U(1) << 19)
+#define SCTLR_UWXN_BIT		(U(1) << 20)
+#define SCTLR_EE_BIT		(U(1) << 25)
+#define SCTLR_TRE_BIT		(U(1) << 28)
+#define SCTLR_AFE_BIT		(U(1) << 29)
+#define SCTLR_TE_BIT		(U(1) << 30)
+#define SCTLR_DSSBS_BIT		(U(1) << 31)
+#define SCTLR_RESET_VAL         (SCTLR_RES1 | SCTLR_NTWE_BIT |		\
+				SCTLR_NTWI_BIT | SCTLR_CP15BEN_BIT)
+
+/* SDCR definitions */
+#define SDCR_SPD(x)		((x) << 14)
+#define SDCR_SPD_LEGACY		U(0x0)
+#define SDCR_SPD_DISABLE	U(0x2)
+#define SDCR_SPD_ENABLE		U(0x3)
+#define SDCR_SCCD_BIT		(U(1) << 23)
+#define SDCR_RESET_VAL		U(0x0)
+
+/* HSCTLR definitions */
+#define HSCTLR_RES1	((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \
+			 (U(1) << 22) | (U(1) << 18) | (U(1) << 16) | \
+			 (U(1) << 11) | (U(1) << 4) | (U(1) << 3))
+
+#define HSCTLR_M_BIT		(U(1) << 0)
+#define HSCTLR_A_BIT		(U(1) << 1)
+#define HSCTLR_C_BIT		(U(1) << 2)
+#define HSCTLR_CP15BEN_BIT	(U(1) << 5)
+#define HSCTLR_ITD_BIT		(U(1) << 7)
+#define HSCTLR_SED_BIT		(U(1) << 8)
+#define HSCTLR_I_BIT		(U(1) << 12)
+#define HSCTLR_WXN_BIT		(U(1) << 19)
+#define HSCTLR_EE_BIT		(U(1) << 25)
+#define HSCTLR_TE_BIT		(U(1) << 30)
+
+/* CPACR definitions */
+#define CPACR_FPEN(x)		((x) << 20)
+#define CPACR_FP_TRAP_PL0	U(0x1)
+#define CPACR_FP_TRAP_ALL	U(0x2)
+#define CPACR_FP_TRAP_NONE	U(0x3)
+
+/* SCR definitions */
+#define SCR_TWE_BIT		(U(1) << 13)
+#define SCR_TWI_BIT		(U(1) << 12)
+#define SCR_SIF_BIT		(U(1) << 9)
+#define SCR_HCE_BIT		(U(1) << 8)
+#define SCR_SCD_BIT		(U(1) << 7)
+#define SCR_NET_BIT		(U(1) << 6)
+#define SCR_AW_BIT		(U(1) << 5)
+#define SCR_FW_BIT		(U(1) << 4)
+#define SCR_EA_BIT		(U(1) << 3)
+#define SCR_FIQ_BIT		(U(1) << 2)
+#define SCR_IRQ_BIT		(U(1) << 1)
+#define SCR_NS_BIT		(U(1) << 0)
+#define SCR_VALID_BIT_MASK	U(0x33ff)
+#define SCR_RESET_VAL		U(0x0)
+
+#define GET_NS_BIT(scr)		((scr) & SCR_NS_BIT)
+
+/* HCR definitions */
+#define HCR_TGE_BIT		(U(1) << 27)
+#define HCR_AMO_BIT		(U(1) << 5)
+#define HCR_IMO_BIT		(U(1) << 4)
+#define HCR_FMO_BIT		(U(1) << 3)
+#define HCR_RESET_VAL		U(0x0)
+
+/* CNTHCTL definitions */
+#define CNTHCTL_RESET_VAL	U(0x0)
+#define PL1PCEN_BIT		(U(1) << 1)
+#define PL1PCTEN_BIT		(U(1) << 0)
+
+/* CNTKCTL definitions */
+#define PL0PTEN_BIT		(U(1) << 9)
+#define PL0VTEN_BIT		(U(1) << 8)
+#define PL0PCTEN_BIT		(U(1) << 0)
+#define PL0VCTEN_BIT		(U(1) << 1)
+#define EVNTEN_BIT		(U(1) << 2)
+#define EVNTDIR_BIT		(U(1) << 3)
+#define EVNTI_SHIFT		U(4)
+#define EVNTI_MASK		U(0xf)
+
+/* HCPTR definitions */
+#define HCPTR_RES1		((U(1) << 13) | (U(1) << 12) | U(0x3ff))
+#define TCPAC_BIT		(U(1) << 31)
+#define TAM_BIT			(U(1) << 30)
+#define TTA_BIT			(U(1) << 20)
+#define TCP11_BIT		(U(1) << 11)
+#define TCP10_BIT		(U(1) << 10)
+#define HCPTR_RESET_VAL		HCPTR_RES1
+
+/* VTTBR defintions */
+#define VTTBR_RESET_VAL		ULL(0x0)
+#define VTTBR_VMID_MASK		ULL(0xff)
+#define VTTBR_VMID_SHIFT	U(48)
+#define VTTBR_BADDR_MASK	ULL(0xffffffffffff)
+#define VTTBR_BADDR_SHIFT	U(0)
+
+/* HDCR definitions */
+#define HDCR_RESET_VAL		U(0x0)
+
+/* HSTR definitions */
+#define HSTR_RESET_VAL		U(0x0)
+
+/* CNTHP_CTL definitions */
+#define CNTHP_CTL_RESET_VAL	U(0x0)
+
+/* NSACR definitions */
+#define NSASEDIS_BIT		(U(1) << 15)
+#define NSTRCDIS_BIT		(U(1) << 20)
+#define NSACR_CP11_BIT		(U(1) << 11)
+#define NSACR_CP10_BIT		(U(1) << 10)
+#define NSACR_IMP_DEF_MASK	(U(0x7) << 16)
+#define NSACR_ENABLE_FP_ACCESS	(NSACR_CP11_BIT | NSACR_CP10_BIT)
+#define NSACR_RESET_VAL		U(0x0)
+
+/* CPACR definitions */
+#define ASEDIS_BIT		(U(1) << 31)
+#define TRCDIS_BIT		(U(1) << 28)
+#define CPACR_CP11_SHIFT	U(22)
+#define CPACR_CP10_SHIFT	U(20)
+#define CPACR_ENABLE_FP_ACCESS	((U(0x3) << CPACR_CP11_SHIFT) |\
+				 (U(0x3) << CPACR_CP10_SHIFT))
+#define CPACR_RESET_VAL         U(0x0)
+
+/* FPEXC definitions */
+#define FPEXC_RES1		((U(1) << 10) | (U(1) << 9) | (U(1) << 8))
+#define FPEXC_EN_BIT		(U(1) << 30)
+#define FPEXC_RESET_VAL		FPEXC_RES1
+
+/* SPSR/CPSR definitions */
+#define SPSR_FIQ_BIT		(U(1) << 0)
+#define SPSR_IRQ_BIT		(U(1) << 1)
+#define SPSR_ABT_BIT		(U(1) << 2)
+#define SPSR_AIF_SHIFT		U(6)
+#define SPSR_AIF_MASK		U(0x7)
+
+#define SPSR_E_SHIFT		U(9)
+#define SPSR_E_MASK		U(0x1)
+#define SPSR_E_LITTLE		U(0)
+#define SPSR_E_BIG		U(1)
+
+#define SPSR_T_SHIFT		U(5)
+#define SPSR_T_MASK		U(0x1)
+#define SPSR_T_ARM		U(0)
+#define SPSR_T_THUMB		U(1)
+
+#define SPSR_MODE_SHIFT		U(0)
+#define SPSR_MODE_MASK		U(0x7)
+
+#define SPSR_SSBS_BIT		BIT_32(23)
+
+#define DISABLE_ALL_EXCEPTIONS \
+		(SPSR_FIQ_BIT | SPSR_IRQ_BIT | SPSR_ABT_BIT)
+
+#define CPSR_DIT_BIT		(U(1) << 21)
+/*
+ * TTBCR definitions
+ */
+#define TTBCR_EAE_BIT		(U(1) << 31)
+
+#define TTBCR_SH1_NON_SHAREABLE		(U(0x0) << 28)
+#define TTBCR_SH1_OUTER_SHAREABLE	(U(0x2) << 28)
+#define TTBCR_SH1_INNER_SHAREABLE	(U(0x3) << 28)
+
+#define TTBCR_RGN1_OUTER_NC	(U(0x0) << 26)
+#define TTBCR_RGN1_OUTER_WBA	(U(0x1) << 26)
+#define TTBCR_RGN1_OUTER_WT	(U(0x2) << 26)
+#define TTBCR_RGN1_OUTER_WBNA	(U(0x3) << 26)
+
+#define TTBCR_RGN1_INNER_NC	(U(0x0) << 24)
+#define TTBCR_RGN1_INNER_WBA	(U(0x1) << 24)
+#define TTBCR_RGN1_INNER_WT	(U(0x2) << 24)
+#define TTBCR_RGN1_INNER_WBNA	(U(0x3) << 24)
+
+#define TTBCR_EPD1_BIT		(U(1) << 23)
+#define TTBCR_A1_BIT		(U(1) << 22)
+
+#define TTBCR_T1SZ_SHIFT	U(16)
+#define TTBCR_T1SZ_MASK		U(0x7)
+#define TTBCR_TxSZ_MIN		U(0)
+#define TTBCR_TxSZ_MAX		U(7)
+
+#define TTBCR_SH0_NON_SHAREABLE		(U(0x0) << 12)
+#define TTBCR_SH0_OUTER_SHAREABLE	(U(0x2) << 12)
+#define TTBCR_SH0_INNER_SHAREABLE	(U(0x3) << 12)
+
+#define TTBCR_RGN0_OUTER_NC	(U(0x0) << 10)
+#define TTBCR_RGN0_OUTER_WBA	(U(0x1) << 10)
+#define TTBCR_RGN0_OUTER_WT	(U(0x2) << 10)
+#define TTBCR_RGN0_OUTER_WBNA	(U(0x3) << 10)
+
+#define TTBCR_RGN0_INNER_NC	(U(0x0) << 8)
+#define TTBCR_RGN0_INNER_WBA	(U(0x1) << 8)
+#define TTBCR_RGN0_INNER_WT	(U(0x2) << 8)
+#define TTBCR_RGN0_INNER_WBNA	(U(0x3) << 8)
+
+#define TTBCR_EPD0_BIT		(U(1) << 7)
+#define TTBCR_T0SZ_SHIFT	U(0)
+#define TTBCR_T0SZ_MASK		U(0x7)
+
+/*
+ * HTCR definitions
+ */
+#define HTCR_RES1			((U(1) << 31) | (U(1) << 23))
+
+#define HTCR_SH0_NON_SHAREABLE		(U(0x0) << 12)
+#define HTCR_SH0_OUTER_SHAREABLE	(U(0x2) << 12)
+#define HTCR_SH0_INNER_SHAREABLE	(U(0x3) << 12)
+
+#define HTCR_RGN0_OUTER_NC	(U(0x0) << 10)
+#define HTCR_RGN0_OUTER_WBA	(U(0x1) << 10)
+#define HTCR_RGN0_OUTER_WT	(U(0x2) << 10)
+#define HTCR_RGN0_OUTER_WBNA	(U(0x3) << 10)
+
+#define HTCR_RGN0_INNER_NC	(U(0x0) << 8)
+#define HTCR_RGN0_INNER_WBA	(U(0x1) << 8)
+#define HTCR_RGN0_INNER_WT	(U(0x2) << 8)
+#define HTCR_RGN0_INNER_WBNA	(U(0x3) << 8)
+
+#define HTCR_T0SZ_SHIFT		U(0)
+#define HTCR_T0SZ_MASK		U(0x7)
+
+#define MODE_RW_SHIFT		U(0x4)
+#define MODE_RW_MASK		U(0x1)
+#define MODE_RW_32		U(0x1)
+
+#define MODE32_SHIFT		U(0)
+#define MODE32_MASK		U(0x1f)
+#define MODE32_usr		U(0x10)
+#define MODE32_fiq		U(0x11)
+#define MODE32_irq		U(0x12)
+#define MODE32_svc		U(0x13)
+#define MODE32_mon		U(0x16)
+#define MODE32_abt		U(0x17)
+#define MODE32_hyp		U(0x1a)
+#define MODE32_und		U(0x1b)
+#define MODE32_sys		U(0x1f)
+
+#define GET_M32(mode)		(((mode) >> MODE32_SHIFT) & MODE32_MASK)
+
+#define SPSR_MODE32(mode, isa, endian, aif)		\
+	((MODE_RW_32 << MODE_RW_SHIFT |			\
+	((mode) & MODE32_MASK) << MODE32_SHIFT |	\
+	((isa) & SPSR_T_MASK) << SPSR_T_SHIFT |		\
+	((endian) & SPSR_E_MASK) << SPSR_E_SHIFT |	\
+	((aif) & SPSR_AIF_MASK) << SPSR_AIF_SHIFT) &	\
+	(~(SPSR_SSBS_BIT)))
+
+/*
+ * TTBR definitions
+ */
+#define TTBR_CNP_BIT		ULL(0x1)
+
+/*
+ * CTR definitions
+ */
+#define CTR_CWG_SHIFT		U(24)
+#define CTR_CWG_MASK		U(0xf)
+#define CTR_ERG_SHIFT		U(20)
+#define CTR_ERG_MASK		U(0xf)
+#define CTR_DMINLINE_SHIFT	U(16)
+#define CTR_DMINLINE_WIDTH	U(4)
+#define CTR_DMINLINE_MASK	((U(1) << 4) - U(1))
+#define CTR_L1IP_SHIFT		U(14)
+#define CTR_L1IP_MASK		U(0x3)
+#define CTR_IMINLINE_SHIFT	U(0)
+#define CTR_IMINLINE_MASK	U(0xf)
+
+#define MAX_CACHE_LINE_SIZE	U(0x800) /* 2KB */
+
+/* PMCR definitions */
+#define PMCR_N_SHIFT		U(11)
+#define PMCR_N_MASK		U(0x1f)
+#define PMCR_N_BITS		(PMCR_N_MASK << PMCR_N_SHIFT)
+#define PMCR_LC_BIT		(U(1) << 6)
+#define PMCR_DP_BIT		(U(1) << 5)
+
+/*******************************************************************************
+ * Definitions of register offsets, fields and macros for CPU system
+ * instructions.
+ ******************************************************************************/
+
+#define TLBI_ADDR_SHIFT		U(0)
+#define TLBI_ADDR_MASK		U(0xFFFFF000)
+#define TLBI_ADDR(x)		(((x) >> TLBI_ADDR_SHIFT) & TLBI_ADDR_MASK)
+
+/*******************************************************************************
+ * Definitions of register offsets and fields in the CNTCTLBase Frame of the
+ * system level implementation of the Generic Timer.
+ ******************************************************************************/
+#define CNTCTLBASE_CNTFRQ	U(0x0)
+#define CNTNSAR			U(0x4)
+#define CNTNSAR_NS_SHIFT(x)	(x)
+
+#define CNTACR_BASE(x)		(U(0x40) + ((x) << 2))
+#define CNTACR_RPCT_SHIFT	U(0x0)
+#define CNTACR_RVCT_SHIFT	U(0x1)
+#define CNTACR_RFRQ_SHIFT	U(0x2)
+#define CNTACR_RVOFF_SHIFT	U(0x3)
+#define CNTACR_RWVT_SHIFT	U(0x4)
+#define CNTACR_RWPT_SHIFT	U(0x5)
+
+/*******************************************************************************
+ * Definitions of register offsets and fields in the CNTBaseN Frame of the
+ * system level implementation of the Generic Timer.
+ ******************************************************************************/
+/* Physical Count register. */
+#define CNTPCT_LO		U(0x0)
+/* Counter Frequency register. */
+#define CNTBASEN_CNTFRQ		U(0x10)
+/* Physical Timer CompareValue register. */
+#define CNTP_CVAL_LO		U(0x20)
+/* Physical Timer Control register. */
+#define CNTP_CTL		U(0x2c)
+
+/* Physical timer control register bit fields shifts and masks */
+#define CNTP_CTL_ENABLE_SHIFT   0
+#define CNTP_CTL_IMASK_SHIFT    1
+#define CNTP_CTL_ISTATUS_SHIFT  2
+
+#define CNTP_CTL_ENABLE_MASK    U(1)
+#define CNTP_CTL_IMASK_MASK     U(1)
+#define CNTP_CTL_ISTATUS_MASK   U(1)
+
+/* MAIR macros */
+#define MAIR0_ATTR_SET(attr, index)	((attr) << ((index) << U(3)))
+#define MAIR1_ATTR_SET(attr, index)	((attr) << (((index) - U(3)) << U(3)))
+
+/* System register defines The format is: coproc, opt1, CRn, CRm, opt2 */
+#define SCR		p15, 0, c1, c1, 0
+#define SCTLR		p15, 0, c1, c0, 0
+#define ACTLR		p15, 0, c1, c0, 1
+#define SDCR		p15, 0, c1, c3, 1
+#define MPIDR		p15, 0, c0, c0, 5
+#define MIDR		p15, 0, c0, c0, 0
+#define HVBAR		p15, 4, c12, c0, 0
+#define VBAR		p15, 0, c12, c0, 0
+#define MVBAR		p15, 0, c12, c0, 1
+#define NSACR		p15, 0, c1, c1, 2
+#define CPACR		p15, 0, c1, c0, 2
+#define DCCIMVAC	p15, 0, c7, c14, 1
+#define DCCMVAC		p15, 0, c7, c10, 1
+#define DCIMVAC		p15, 0, c7, c6, 1
+#define DCCISW		p15, 0, c7, c14, 2
+#define DCCSW		p15, 0, c7, c10, 2
+#define DCISW		p15, 0, c7, c6, 2
+#define CTR		p15, 0, c0, c0, 1
+#define CNTFRQ		p15, 0, c14, c0, 0
+#define ID_MMFR4	p15, 0, c0, c2, 6
+#define ID_PFR0		p15, 0, c0, c1, 0
+#define ID_PFR1		p15, 0, c0, c1, 1
+#define MAIR0		p15, 0, c10, c2, 0
+#define MAIR1		p15, 0, c10, c2, 1
+#define TTBCR		p15, 0, c2, c0, 2
+#define TTBR0		p15, 0, c2, c0, 0
+#define TTBR1		p15, 0, c2, c0, 1
+#define TLBIALL		p15, 0, c8, c7, 0
+#define TLBIALLH	p15, 4, c8, c7, 0
+#define TLBIALLIS	p15, 0, c8, c3, 0
+#define TLBIMVA		p15, 0, c8, c7, 1
+#define TLBIMVAA	p15, 0, c8, c7, 3
+#define TLBIMVAAIS	p15, 0, c8, c3, 3
+#define TLBIMVAHIS	p15, 4, c8, c3, 1
+#define BPIALLIS	p15, 0, c7, c1, 6
+#define BPIALL		p15, 0, c7, c5, 6
+#define ICIALLU		p15, 0, c7, c5, 0
+#define HSCTLR		p15, 4, c1, c0, 0
+#define HCR		p15, 4, c1, c1, 0
+#define HCPTR		p15, 4, c1, c1, 2
+#define HSTR		p15, 4, c1, c1, 3
+#define CNTHCTL		p15, 4, c14, c1, 0
+#define CNTKCTL		p15, 0, c14, c1, 0
+#define VPIDR		p15, 4, c0, c0, 0
+#define VMPIDR		p15, 4, c0, c0, 5
+#define ISR		p15, 0, c12, c1, 0
+#define CLIDR		p15, 1, c0, c0, 1
+#define CSSELR		p15, 2, c0, c0, 0
+#define CCSIDR		p15, 1, c0, c0, 0
+#define HTCR		p15, 4, c2, c0, 2
+#define HMAIR0		p15, 4, c10, c2, 0
+#define ATS1CPR		p15, 0, c7, c8, 0
+#define ATS1HR		p15, 4, c7, c8, 0
+#define DBGOSDLR	p14, 0, c1, c3, 4
+
+/* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
+#define HDCR		p15, 4, c1, c1, 1
+#define PMCR		p15, 0, c9, c12, 0
+#define CNTHP_TVAL	p15, 4, c14, c2, 0
+#define CNTHP_CTL	p15, 4, c14, c2, 1
+
+/* AArch32 coproc registers for 32bit MMU descriptor support */
+#define PRRR		p15, 0, c10, c2, 0
+#define NMRR		p15, 0, c10, c2, 1
+#define DACR		p15, 0, c3, c0, 0
+
+/* GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
+#define ICC_IAR1	p15, 0, c12, c12, 0
+#define ICC_IAR0	p15, 0, c12, c8, 0
+#define ICC_EOIR1	p15, 0, c12, c12, 1
+#define ICC_EOIR0	p15, 0, c12, c8, 1
+#define ICC_HPPIR1	p15, 0, c12, c12, 2
+#define ICC_HPPIR0	p15, 0, c12, c8, 2
+#define ICC_BPR1	p15, 0, c12, c12, 3
+#define ICC_BPR0	p15, 0, c12, c8, 3
+#define ICC_DIR		p15, 0, c12, c11, 1
+#define ICC_PMR		p15, 0, c4, c6, 0
+#define ICC_RPR		p15, 0, c12, c11, 3
+#define ICC_CTLR	p15, 0, c12, c12, 4
+#define ICC_MCTLR	p15, 6, c12, c12, 4
+#define ICC_SRE		p15, 0, c12, c12, 5
+#define ICC_HSRE	p15, 4, c12, c9, 5
+#define ICC_MSRE	p15, 6, c12, c12, 5
+#define ICC_IGRPEN0	p15, 0, c12, c12, 6
+#define ICC_IGRPEN1	p15, 0, c12, c12, 7
+#define ICC_MGRPEN1	p15, 6, c12, c12, 7
+
+/* 64 bit system register defines The format is: coproc, opt1, CRm */
+#define TTBR0_64	p15, 0, c2
+#define TTBR1_64	p15, 1, c2
+#define CNTVOFF_64	p15, 4, c14
+#define VTTBR_64	p15, 6, c2
+#define CNTPCT_64	p15, 0, c14
+#define HTTBR_64	p15, 4, c2
+#define CNTHP_CVAL_64	p15, 6, c14
+#define PAR_64		p15, 0, c7
+
+/* 64 bit GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRm */
+#define ICC_SGI1R_EL1_64	p15, 0, c12
+#define ICC_ASGI1R_EL1_64	p15, 1, c12
+#define ICC_SGI0R_EL1_64	p15, 2, c12
+
+/*******************************************************************************
+ * Definitions of MAIR encodings for device and normal memory
+ ******************************************************************************/
+/*
+ * MAIR encodings for device memory attributes.
+ */
+#define MAIR_DEV_nGnRnE		U(0x0)
+#define MAIR_DEV_nGnRE		U(0x4)
+#define MAIR_DEV_nGRE		U(0x8)
+#define MAIR_DEV_GRE		U(0xc)
+
+/*
+ * MAIR encodings for normal memory attributes.
+ *
+ * Cache Policy
+ *  WT:	 Write Through
+ *  WB:	 Write Back
+ *  NC:	 Non-Cacheable
+ *
+ * Transient Hint
+ *  NTR: Non-Transient
+ *  TR:	 Transient
+ *
+ * Allocation Policy
+ *  RA:	 Read Allocate
+ *  WA:	 Write Allocate
+ *  RWA: Read and Write Allocate
+ *  NA:	 No Allocation
+ */
+#define MAIR_NORM_WT_TR_WA	U(0x1)
+#define MAIR_NORM_WT_TR_RA	U(0x2)
+#define MAIR_NORM_WT_TR_RWA	U(0x3)
+#define MAIR_NORM_NC		U(0x4)
+#define MAIR_NORM_WB_TR_WA	U(0x5)
+#define MAIR_NORM_WB_TR_RA	U(0x6)
+#define MAIR_NORM_WB_TR_RWA	U(0x7)
+#define MAIR_NORM_WT_NTR_NA	U(0x8)
+#define MAIR_NORM_WT_NTR_WA	U(0x9)
+#define MAIR_NORM_WT_NTR_RA	U(0xa)
+#define MAIR_NORM_WT_NTR_RWA	U(0xb)
+#define MAIR_NORM_WB_NTR_NA	U(0xc)
+#define MAIR_NORM_WB_NTR_WA	U(0xd)
+#define MAIR_NORM_WB_NTR_RA	U(0xe)
+#define MAIR_NORM_WB_NTR_RWA	U(0xf)
+
+#define MAIR_NORM_OUTER_SHIFT	U(4)
+
+#define MAKE_MAIR_NORMAL_MEMORY(inner, outer)	\
+		((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
+
+/* PAR fields */
+#define PAR_F_SHIFT	U(0)
+#define PAR_F_MASK	ULL(0x1)
+#define PAR_ADDR_SHIFT	U(12)
+#define PAR_ADDR_MASK	(BIT_64(40) - ULL(1)) /* 40-bits-wide page address */
+
+/*******************************************************************************
+ * Definitions for system register interface to AMU for ARMv8.4 onwards
+ ******************************************************************************/
+#define AMCR		p15, 0, c13, c2, 0
+#define AMCFGR		p15, 0, c13, c2, 1
+#define AMCGCR		p15, 0, c13, c2, 2
+#define AMUSERENR	p15, 0, c13, c2, 3
+#define AMCNTENCLR0	p15, 0, c13, c2, 4
+#define AMCNTENSET0	p15, 0, c13, c2, 5
+#define AMCNTENCLR1	p15, 0, c13, c3, 0
+#define AMCNTENSET1	p15, 0, c13, c3, 1
+
+/* Activity Monitor Group 0 Event Counter Registers */
+#define AMEVCNTR00	p15, 0, c0
+#define AMEVCNTR01	p15, 1, c0
+#define AMEVCNTR02	p15, 2, c0
+#define AMEVCNTR03	p15, 3, c0
+
+/* Activity Monitor Group 0 Event Type Registers */
+#define AMEVTYPER00	p15, 0, c13, c6, 0
+#define AMEVTYPER01	p15, 0, c13, c6, 1
+#define AMEVTYPER02	p15, 0, c13, c6, 2
+#define AMEVTYPER03	p15, 0, c13, c6, 3
+
+/* Activity Monitor Group 1 Event Counter Registers */
+#define AMEVCNTR10	p15, 0, c4
+#define AMEVCNTR11	p15, 1, c4
+#define AMEVCNTR12	p15, 2, c4
+#define AMEVCNTR13	p15, 3, c4
+#define AMEVCNTR14	p15, 4, c4
+#define AMEVCNTR15	p15, 5, c4
+#define AMEVCNTR16	p15, 6, c4
+#define AMEVCNTR17	p15, 7, c4
+#define AMEVCNTR18	p15, 0, c5
+#define AMEVCNTR19	p15, 1, c5
+#define AMEVCNTR1A	p15, 2, c5
+#define AMEVCNTR1B	p15, 3, c5
+#define AMEVCNTR1C	p15, 4, c5
+#define AMEVCNTR1D	p15, 5, c5
+#define AMEVCNTR1E	p15, 6, c5
+#define AMEVCNTR1F	p15, 7, c5
+
+/* Activity Monitor Group 1 Event Type Registers */
+#define AMEVTYPER10	p15, 0, c13, c14, 0
+#define AMEVTYPER11	p15, 0, c13, c14, 1
+#define AMEVTYPER12	p15, 0, c13, c14, 2
+#define AMEVTYPER13	p15, 0, c13, c14, 3
+#define AMEVTYPER14	p15, 0, c13, c14, 4
+#define AMEVTYPER15	p15, 0, c13, c14, 5
+#define AMEVTYPER16	p15, 0, c13, c14, 6
+#define AMEVTYPER17	p15, 0, c13, c14, 7
+#define AMEVTYPER18	p15, 0, c13, c15, 0
+#define AMEVTYPER19	p15, 0, c13, c15, 1
+#define AMEVTYPER1A	p15, 0, c13, c15, 2
+#define AMEVTYPER1B	p15, 0, c13, c15, 3
+#define AMEVTYPER1C	p15, 0, c13, c15, 4
+#define AMEVTYPER1D	p15, 0, c13, c15, 5
+#define AMEVTYPER1E	p15, 0, c13, c15, 6
+#define AMEVTYPER1F	p15, 0, c13, c15, 7
+
+#endif /* ARCH_H */
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
new file mode 100644
index 0000000..ddf0968
--- /dev/null
+++ b/include/arch/aarch32/arch_features.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_FEATURES_H
+#define ARCH_FEATURES_H
+
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+
+static inline bool is_armv7_gentimer_present(void)
+{
+	return ((read_id_pfr1() >> ID_PFR1_GENTIMER_SHIFT) &
+		ID_PFR1_GENTIMER_MASK) != 0U;
+}
+
+static inline bool is_armv8_2_ttcnp_present(void)
+{
+	return ((read_id_mmfr4() >> ID_MMFR4_CNP_SHIFT) &
+		ID_MMFR4_CNP_MASK) != 0U;
+}
+
+#endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch32/arch_helpers.h b/include/arch/aarch32/arch_helpers.h
new file mode 100644
index 0000000..cbac84b
--- /dev/null
+++ b/include/arch/aarch32/arch_helpers.h
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_HELPERS_H
+#define ARCH_HELPERS_H
+
+#include <cdefs.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch.h>
+
+/**********************************************************************
+ * Macros which create inline functions to read or write CPU system
+ * registers
+ *********************************************************************/
+
+#define _DEFINE_COPROCR_WRITE_FUNC(_name, coproc, opc1, CRn, CRm, opc2)	\
+static inline void write_## _name(u_register_t v)			\
+{									\
+	__asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\
+}
+
+#define _DEFINE_COPROCR_READ_FUNC(_name, coproc, opc1, CRn, CRm, opc2)	\
+static inline u_register_t read_ ## _name(void)				\
+{									\
+	u_register_t v;							\
+	__asm__ volatile ("mrc "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : "=r" (v));\
+	return v;							\
+}
+
+/*
+ *  The undocumented %Q and %R extended asm are used to implemented the below
+ *  64 bit `mrrc` and `mcrr` instructions.
+ */
+
+#define _DEFINE_COPROCR_WRITE_FUNC_64(_name, coproc, opc1, CRm)		\
+static inline void write64_## _name(uint64_t v)				\
+{									\
+	__asm__ volatile ("mcrr "#coproc","#opc1", %Q0, %R0,"#CRm : : "r" (v));\
+}
+
+#define _DEFINE_COPROCR_READ_FUNC_64(_name, coproc, opc1, CRm)		\
+static inline uint64_t read64_## _name(void)				\
+{	uint64_t v;							\
+	__asm__ volatile ("mrrc "#coproc","#opc1", %Q0, %R0,"#CRm : "=r" (v));\
+	return v;							\
+}
+
+#define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name)			\
+static inline u_register_t read_ ## _name(void)				\
+{									\
+	u_register_t v;							\
+	__asm__ volatile ("mrs %0, " #_reg_name : "=r" (v));		\
+	return v;							\
+}
+
+#define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)			\
+static inline void write_ ## _name(u_register_t v)			\
+{									\
+	__asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v));	\
+}
+
+#define _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _reg_name)		\
+static inline void write_ ## _name(const u_register_t v)		\
+{									\
+	__asm__ volatile ("msr " #_reg_name ", %0" : : "i" (v));	\
+}
+
+/* Define read function for coproc register */
+#define DEFINE_COPROCR_READ_FUNC(_name, ...) 				\
+	_DEFINE_COPROCR_READ_FUNC(_name, __VA_ARGS__)
+
+/* Define write function for coproc register */
+#define DEFINE_COPROCR_WRITE_FUNC(_name, ...) 				\
+	_DEFINE_COPROCR_WRITE_FUNC(_name, __VA_ARGS__)
+
+/* Define read & write function for coproc register */
+#define DEFINE_COPROCR_RW_FUNCS(_name, ...) 				\
+	_DEFINE_COPROCR_READ_FUNC(_name, __VA_ARGS__)			\
+	_DEFINE_COPROCR_WRITE_FUNC(_name, __VA_ARGS__)
+
+/* Define 64 bit read function for coproc register */
+#define DEFINE_COPROCR_READ_FUNC_64(_name, ...) 			\
+	_DEFINE_COPROCR_READ_FUNC_64(_name, __VA_ARGS__)
+
+/* Define 64 bit write function for coproc register */
+#define DEFINE_COPROCR_WRITE_FUNC_64(_name, ...) 			\
+	_DEFINE_COPROCR_WRITE_FUNC_64(_name, __VA_ARGS__)
+
+/* Define 64 bit read & write function for coproc register */
+#define DEFINE_COPROCR_RW_FUNCS_64(_name, ...) 				\
+	_DEFINE_COPROCR_READ_FUNC_64(_name, __VA_ARGS__)		\
+	_DEFINE_COPROCR_WRITE_FUNC_64(_name, __VA_ARGS__)
+
+/* Define read & write function for system register */
+#define DEFINE_SYSREG_RW_FUNCS(_name)					\
+	_DEFINE_SYSREG_READ_FUNC(_name, _name)				\
+	_DEFINE_SYSREG_WRITE_FUNC(_name, _name)
+
+/**********************************************************************
+ * Macros to create inline functions for tlbi operations
+ *********************************************************************/
+
+#define _DEFINE_TLBIOP_FUNC(_op, coproc, opc1, CRn, CRm, opc2)		\
+static inline void tlbi##_op(void)					\
+{									\
+	u_register_t v = 0;						\
+	__asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\
+}
+
+#define _DEFINE_BPIOP_FUNC(_op, coproc, opc1, CRn, CRm, opc2)		\
+static inline void bpi##_op(void)					\
+{									\
+	u_register_t v = 0;						\
+	__asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\
+}
+
+#define _DEFINE_TLBIOP_PARAM_FUNC(_op, coproc, opc1, CRn, CRm, opc2)	\
+static inline void tlbi##_op(u_register_t v)				\
+{									\
+	__asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\
+}
+
+/* Define function for simple TLBI operation */
+#define DEFINE_TLBIOP_FUNC(_op, ...)					\
+	_DEFINE_TLBIOP_FUNC(_op, __VA_ARGS__)
+
+/* Define function for TLBI operation with register parameter */
+#define DEFINE_TLBIOP_PARAM_FUNC(_op, ...)				\
+	_DEFINE_TLBIOP_PARAM_FUNC(_op, __VA_ARGS__)
+
+/* Define function for simple BPI operation */
+#define DEFINE_BPIOP_FUNC(_op, ...)					\
+	_DEFINE_BPIOP_FUNC(_op, __VA_ARGS__)
+
+/**********************************************************************
+ * Macros to create inline functions for DC operations
+ *********************************************************************/
+#define _DEFINE_DCOP_PARAM_FUNC(_op, coproc, opc1, CRn, CRm, opc2)	\
+static inline void dc##_op(u_register_t v)				\
+{									\
+	__asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\
+}
+
+/* Define function for DC operation with register parameter */
+#define DEFINE_DCOP_PARAM_FUNC(_op, ...)				\
+	_DEFINE_DCOP_PARAM_FUNC(_op, __VA_ARGS__)
+
+/**********************************************************************
+ * Macros to create inline functions for system instructions
+ *********************************************************************/
+ /* Define function for simple system instruction */
+#define DEFINE_SYSOP_FUNC(_op)						\
+static inline void _op(void)						\
+{									\
+	__asm__ (#_op);							\
+}
+
+
+/* Define function for system instruction with type specifier */
+#define DEFINE_SYSOP_TYPE_FUNC(_op, _type)				\
+static inline void _op ## _type(void)					\
+{									\
+	__asm__ (#_op " " #_type);					\
+}
+
+/* Define function for system instruction with register parameter */
+#define DEFINE_SYSOP_TYPE_PARAM_FUNC(_op, _type)			\
+static inline void _op ## _type(u_register_t v)				\
+{									\
+	 __asm__ (#_op " " #_type ", %0" : : "r" (v));			\
+}
+
+void flush_dcache_range(uintptr_t addr, size_t size);
+void clean_dcache_range(uintptr_t addr, size_t size);
+void inv_dcache_range(uintptr_t addr, size_t size);
+
+void dcsw_op_louis(u_register_t op_type);
+void dcsw_op_all(u_register_t op_type);
+
+void disable_mmu_secure(void);
+void disable_mmu_icache_secure(void);
+
+DEFINE_SYSOP_FUNC(wfi)
+DEFINE_SYSOP_FUNC(wfe)
+DEFINE_SYSOP_FUNC(sev)
+DEFINE_SYSOP_TYPE_FUNC(dsb, sy)
+DEFINE_SYSOP_TYPE_FUNC(dmb, sy)
+DEFINE_SYSOP_TYPE_FUNC(dmb, st)
+
+/* dmb ld is not valid for armv7/thumb machines */
+#if ARM_ARCH_MAJOR != 7
+DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
+#endif
+
+DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
+DEFINE_SYSOP_FUNC(isb)
+
+void __dead2 smc(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3,
+		 uint32_t r4, uint32_t r5, uint32_t r6, uint32_t r7);
+
+DEFINE_SYSREG_RW_FUNCS(spsr)
+DEFINE_SYSREG_RW_FUNCS(cpsr)
+
+/*******************************************************************************
+ * System register accessor prototypes
+ ******************************************************************************/
+DEFINE_COPROCR_READ_FUNC(mpidr, MPIDR)
+DEFINE_COPROCR_READ_FUNC(midr, MIDR)
+DEFINE_COPROCR_READ_FUNC(id_mmfr4, ID_MMFR4)
+DEFINE_COPROCR_READ_FUNC(id_pfr0, ID_PFR0)
+DEFINE_COPROCR_READ_FUNC(id_pfr1, ID_PFR1)
+DEFINE_COPROCR_READ_FUNC(isr, ISR)
+DEFINE_COPROCR_READ_FUNC(clidr, CLIDR)
+DEFINE_COPROCR_READ_FUNC_64(cntpct, CNTPCT_64)
+
+DEFINE_COPROCR_RW_FUNCS(scr, SCR)
+DEFINE_COPROCR_RW_FUNCS(ctr, CTR)
+DEFINE_COPROCR_RW_FUNCS(sctlr, SCTLR)
+DEFINE_COPROCR_RW_FUNCS(actlr, ACTLR)
+DEFINE_COPROCR_RW_FUNCS(hsctlr, HSCTLR)
+DEFINE_COPROCR_RW_FUNCS(hcr, HCR)
+DEFINE_COPROCR_RW_FUNCS(hcptr, HCPTR)
+DEFINE_COPROCR_RW_FUNCS(cntfrq, CNTFRQ)
+DEFINE_COPROCR_RW_FUNCS(cnthctl, CNTHCTL)
+DEFINE_COPROCR_RW_FUNCS(mair0, MAIR0)
+DEFINE_COPROCR_RW_FUNCS(mair1, MAIR1)
+DEFINE_COPROCR_RW_FUNCS(hmair0, HMAIR0)
+DEFINE_COPROCR_RW_FUNCS(ttbcr, TTBCR)
+DEFINE_COPROCR_RW_FUNCS(htcr, HTCR)
+DEFINE_COPROCR_RW_FUNCS(ttbr0, TTBR0)
+DEFINE_COPROCR_RW_FUNCS_64(ttbr0, TTBR0_64)
+DEFINE_COPROCR_RW_FUNCS(ttbr1, TTBR1)
+DEFINE_COPROCR_RW_FUNCS_64(httbr, HTTBR_64)
+DEFINE_COPROCR_RW_FUNCS(vpidr, VPIDR)
+DEFINE_COPROCR_RW_FUNCS(vmpidr, VMPIDR)
+DEFINE_COPROCR_RW_FUNCS_64(vttbr, VTTBR_64)
+DEFINE_COPROCR_RW_FUNCS_64(ttbr1, TTBR1_64)
+DEFINE_COPROCR_RW_FUNCS_64(cntvoff, CNTVOFF_64)
+DEFINE_COPROCR_RW_FUNCS(csselr, CSSELR)
+DEFINE_COPROCR_RW_FUNCS(hstr, HSTR)
+DEFINE_COPROCR_RW_FUNCS(cnthp_ctl_el2, CNTHP_CTL)
+DEFINE_COPROCR_RW_FUNCS(cnthp_tval_el2, CNTHP_TVAL)
+DEFINE_COPROCR_RW_FUNCS_64(cnthp_cval_el2, CNTHP_CVAL_64)
+
+#define get_cntp_ctl_enable(x)  (((x) >> CNTP_CTL_ENABLE_SHIFT) & \
+					 CNTP_CTL_ENABLE_MASK)
+#define get_cntp_ctl_imask(x)   (((x) >> CNTP_CTL_IMASK_SHIFT) & \
+					 CNTP_CTL_IMASK_MASK)
+#define get_cntp_ctl_istatus(x) (((x) >> CNTP_CTL_ISTATUS_SHIFT) & \
+					 CNTP_CTL_ISTATUS_MASK)
+
+#define set_cntp_ctl_enable(x)  ((x) |= U(1) << CNTP_CTL_ENABLE_SHIFT)
+#define set_cntp_ctl_imask(x)   ((x) |= U(1) << CNTP_CTL_IMASK_SHIFT)
+
+#define clr_cntp_ctl_enable(x)  ((x) &= ~(U(1) << CNTP_CTL_ENABLE_SHIFT))
+#define clr_cntp_ctl_imask(x)   ((x) &= ~(U(1) << CNTP_CTL_IMASK_SHIFT))
+
+DEFINE_COPROCR_RW_FUNCS(icc_sre_el1, ICC_SRE)
+DEFINE_COPROCR_RW_FUNCS(icc_sre_el2, ICC_HSRE)
+DEFINE_COPROCR_RW_FUNCS(icc_sre_el3, ICC_MSRE)
+DEFINE_COPROCR_RW_FUNCS(icc_pmr_el1, ICC_PMR)
+DEFINE_COPROCR_RW_FUNCS(icc_rpr_el1, ICC_RPR)
+DEFINE_COPROCR_RW_FUNCS(icc_igrpen1_el3, ICC_MGRPEN1)
+DEFINE_COPROCR_RW_FUNCS(icc_igrpen1_el1, ICC_IGRPEN1)
+DEFINE_COPROCR_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0)
+DEFINE_COPROCR_RW_FUNCS(icc_hppir0_el1, ICC_HPPIR0)
+DEFINE_COPROCR_RW_FUNCS(icc_hppir1_el1, ICC_HPPIR1)
+DEFINE_COPROCR_RW_FUNCS(icc_iar0_el1, ICC_IAR0)
+DEFINE_COPROCR_RW_FUNCS(icc_iar1_el1, ICC_IAR1)
+DEFINE_COPROCR_RW_FUNCS(icc_eoir0_el1, ICC_EOIR0)
+DEFINE_COPROCR_RW_FUNCS(icc_eoir1_el1, ICC_EOIR1)
+DEFINE_COPROCR_RW_FUNCS_64(icc_sgi0r_el1, ICC_SGI0R_EL1_64)
+DEFINE_COPROCR_WRITE_FUNC_64(icc_sgi1r, ICC_SGI1R_EL1_64)
+
+DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
+DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
+DEFINE_COPROCR_READ_FUNC(pmcr, PMCR)
+
+/*
+ * Address translation
+ */
+DEFINE_COPROCR_WRITE_FUNC(ats1cpr, ATS1CPR)
+DEFINE_COPROCR_WRITE_FUNC(ats1hr, ATS1HR)
+DEFINE_COPROCR_RW_FUNCS_64(par, PAR_64)
+
+DEFINE_COPROCR_RW_FUNCS(nsacr, NSACR)
+
+/* AArch32 coproc registers for 32bit MMU descriptor support */
+DEFINE_COPROCR_RW_FUNCS(prrr, PRRR)
+DEFINE_COPROCR_RW_FUNCS(nmrr, NMRR)
+DEFINE_COPROCR_RW_FUNCS(dacr, DACR)
+
+DEFINE_COPROCR_RW_FUNCS(amcntenset0, AMCNTENSET0)
+DEFINE_COPROCR_RW_FUNCS(amcntenset1, AMCNTENSET1)
+DEFINE_COPROCR_RW_FUNCS(amcntenclr0, AMCNTENCLR0)
+DEFINE_COPROCR_RW_FUNCS(amcntenclr1, AMCNTENCLR1)
+
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr00, AMEVCNTR00)
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr01, AMEVCNTR01)
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr02, AMEVCNTR02)
+DEFINE_COPROCR_RW_FUNCS_64(amevcntr03, AMEVCNTR03)
+
+/*
+ * TLBI operation prototypes
+ */
+DEFINE_TLBIOP_FUNC(all, TLBIALL)
+DEFINE_TLBIOP_FUNC(allis, TLBIALLIS)
+DEFINE_TLBIOP_PARAM_FUNC(mva, TLBIMVA)
+DEFINE_TLBIOP_PARAM_FUNC(mvaa, TLBIMVAA)
+DEFINE_TLBIOP_PARAM_FUNC(mvaais, TLBIMVAAIS)
+DEFINE_TLBIOP_PARAM_FUNC(mvahis, TLBIMVAHIS)
+
+/*
+ * BPI operation prototypes.
+ */
+DEFINE_BPIOP_FUNC(allis, BPIALLIS)
+
+/*
+ * DC operation prototypes
+ */
+DEFINE_DCOP_PARAM_FUNC(civac, DCCIMVAC)
+DEFINE_DCOP_PARAM_FUNC(ivac, DCIMVAC)
+#if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319
+DEFINE_DCOP_PARAM_FUNC(cvac, DCCIMVAC)
+#else
+DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
+#endif
+
+/* Previously defined accessor functions with incomplete register names  */
+#define dsb()			dsbsy()
+#define dmb()			dmbsy()
+
+/* dmb ld is not valid for armv7/thumb machines, so alias it to dmb */
+#if ARM_ARCH_MAJOR == 7
+#define	dmbld()			dmb()
+#endif
+
+#define IS_IN_SECURE() \
+	(GET_NS_BIT(read_scr()) == 0)
+
+#define IS_IN_HYP()	(GET_M32(read_cpsr()) == MODE32_hyp)
+#define IS_IN_SVC()	(GET_M32(read_cpsr()) == MODE32_svc)
+#define IS_IN_MON()	(GET_M32(read_cpsr()) == MODE32_mon)
+#define IS_IN_EL2()	IS_IN_HYP()
+/* If EL3 is AArch32, then secure PL1 and monitor mode correspond to EL3 */
+#define IS_IN_EL3() \
+	((GET_M32(read_cpsr()) == MODE32_mon) ||	\
+		(IS_IN_SECURE() && (GET_M32(read_cpsr()) != MODE32_usr)))
+
+static inline unsigned int get_current_el(void)
+{
+	if (IS_IN_EL3()) {
+		return 3U;
+	} else if (IS_IN_EL2()) {
+		return 2U;
+	} else {
+		return 1U;
+	}
+}
+
+/* Macros for compatibility with AArch64 system registers */
+#define read_mpidr_el1()	read_mpidr()
+
+#define read_scr_el3()		read_scr()
+#define write_scr_el3(_v)	write_scr(_v)
+
+#define read_hcr_el2()		read_hcr()
+#define write_hcr_el2(_v)	write_hcr(_v)
+
+#define read_cpacr_el1()	read_cpacr()
+#define write_cpacr_el1(_v)	write_cpacr(_v)
+
+#define read_cntfrq_el0()	read_cntfrq()
+#define write_cntfrq_el0(_v)	write_cntfrq(_v)
+#define read_isr_el1()		read_isr()
+
+#define read_cntpct_el0()	read64_cntpct()
+
+#define read_ctr_el0()		read_ctr()
+
+#define write_icc_sgi0r_el1(_v)	write64_icc_sgi0r_el1(_v)
+
+#define read_daif()		read_cpsr()
+#define write_daif(flags)	write_cpsr(flags)
+
+#define read_cnthp_cval_el2()	read64_cnthp_cval_el2()
+#define write_cnthp_cval_el2(v)	write64_cnthp_cval_el2(v)
+
+#define read_amcntenset0_el0()	read_amcntenset0()
+#define read_amcntenset1_el0()	read_amcntenset1()
+
+/* Helper functions to manipulate CPSR */
+static inline void enable_irq(void)
+{
+	/*
+	 * The compiler memory barrier will prevent the compiler from
+	 * scheduling non-volatile memory access after the write to the
+	 * register.
+	 *
+	 * This could happen if some initialization code issues non-volatile
+	 * accesses to an area used by an interrupt handler, in the assumption
+	 * that it is safe as the interrupts are disabled at the time it does
+	 * that (according to program order). However, non-volatile accesses
+	 * are not necessarily in program order relatively with volatile inline
+	 * assembly statements (and volatile accesses).
+	 */
+	COMPILER_BARRIER();
+	__asm__ volatile ("cpsie	i");
+	isb();
+}
+
+static inline void enable_serror(void)
+{
+	COMPILER_BARRIER();
+	__asm__ volatile ("cpsie	a");
+	isb();
+}
+
+static inline void enable_fiq(void)
+{
+	COMPILER_BARRIER();
+	__asm__ volatile ("cpsie	f");
+	isb();
+}
+
+static inline void disable_irq(void)
+{
+	COMPILER_BARRIER();
+	__asm__ volatile ("cpsid	i");
+	isb();
+}
+
+static inline void disable_serror(void)
+{
+	COMPILER_BARRIER();
+	__asm__ volatile ("cpsid	a");
+	isb();
+}
+
+static inline void disable_fiq(void)
+{
+	COMPILER_BARRIER();
+	__asm__ volatile ("cpsid	f");
+	isb();
+}
+
+#endif /* ARCH_HELPERS_H */
diff --git a/include/arch/aarch32/asm_macros.S b/include/arch/aarch32/asm_macros.S
new file mode 100644
index 0000000..8cfa212
--- /dev/null
+++ b/include/arch/aarch32/asm_macros.S
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ASM_MACROS_S
+#define ASM_MACROS_S
+
+#include <arch.h>
+#include <common/asm_macros_common.S>
+#include <lib/spinlock.h>
+
+/*
+ * TLBI instruction with type specifier that implements the workaround for
+ * errata 813419 of Cortex-A57.
+ */
+#if ERRATA_A57_813419
+#define TLB_INVALIDATE(_reg, _coproc) \
+	stcopr	_reg, _coproc; \
+	dsb	ish; \
+	stcopr	_reg, _coproc
+#else
+#define TLB_INVALIDATE(_reg, _coproc) \
+	stcopr	_reg, _coproc
+#endif
+
+#define WORD_SIZE	4
+
+	/*
+	 * Co processor register accessors
+	 */
+	.macro ldcopr reg, coproc, opc1, CRn, CRm, opc2
+	mrc	\coproc, \opc1, \reg, \CRn, \CRm, \opc2
+	.endm
+
+	.macro ldcopr16 reg1, reg2, coproc, opc1, CRm
+	mrrc	\coproc, \opc1, \reg1, \reg2, \CRm
+	.endm
+
+	.macro stcopr reg, coproc, opc1, CRn, CRm, opc2
+	mcr	\coproc, \opc1, \reg, \CRn, \CRm, \opc2
+	.endm
+
+	.macro stcopr16 reg1, reg2, coproc, opc1, CRm
+	mcrr	\coproc, \opc1, \reg1, \reg2, \CRm
+	.endm
+
+	/* Cache line size helpers */
+	.macro	dcache_line_size  reg, tmp
+	ldcopr	\tmp, CTR
+	ubfx	\tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH
+	mov	\reg, #WORD_SIZE
+	lsl	\reg, \reg, \tmp
+	.endm
+
+	.macro	icache_line_size  reg, tmp
+	ldcopr	\tmp, CTR
+	and	\tmp, \tmp, #CTR_IMINLINE_MASK
+	mov	\reg, #WORD_SIZE
+	lsl	\reg, \reg, \tmp
+	.endm
+
+	/*
+	 * Declare the exception vector table, enforcing it is aligned on a
+	 * 32 byte boundary.
+	 */
+	.macro vector_base  label
+	.section .vectors, "ax"
+	.align 5
+	\label:
+	.endm
+
+	/*
+	 * This macro calculates the base address of the current CPU's multi
+	 * processor(MP) stack using the plat_my_core_pos() index, the name of
+	 * the stack storage and the size of each stack.
+	 * Out: r0 = physical address of stack base
+	 * Clobber: r14, r1, r2
+	 */
+	.macro get_my_mp_stack _name, _size
+	bl	plat_my_core_pos
+	ldr r2, =(\_name + \_size)
+	mov r1, #\_size
+	mla r0, r0, r1, r2
+	.endm
+
+	/*
+	 * This macro calculates the base address of a uniprocessor(UP) stack
+	 * using the name of the stack storage and the size of the stack
+	 * Out: r0 = physical address of stack base
+	 */
+	.macro get_up_stack _name, _size
+	ldr r0, =(\_name + \_size)
+	.endm
+
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+	/*
+	 * ARMv7 cores without Virtualization extension do not support the
+	 * eret instruction.
+	 */
+	.macro eret
+	movs	pc, lr
+	.endm
+#endif
+
+#if (ARM_ARCH_MAJOR == 7)
+	/* ARMv7 does not support stl instruction */
+	.macro stl _reg, _write_lock
+	dmb
+	str	\_reg, \_write_lock
+	dsb
+	.endm
+#endif
+
+	/*
+	 * Helper macro to generate the best mov/movw/movt combinations
+	 * according to the value to be moved.
+	 */
+	.macro mov_imm _reg, _val
+		.if ((\_val) & 0xffff0000) == 0
+			mov	\_reg, #(\_val)
+		.else
+			movw	\_reg, #((\_val) & 0xffff)
+			movt	\_reg, #((\_val) >> 16)
+		.endif
+	.endm
+
+	/*
+	 * Macro to mark instances where we're jumping to a function and don't
+	 * expect a return. To provide the function being jumped to with
+	 * additional information, we use 'bl' instruction to jump rather than
+	 * 'b'.
+         *
+	 * Debuggers infer the location of a call from where LR points to, which
+	 * is usually the instruction after 'bl'. If this macro expansion
+	 * happens to be the last location in a function, that'll cause the LR
+	 * to point a location beyond the function, thereby misleading debugger
+	 * back trace. We therefore insert a 'nop' after the function call for
+	 * debug builds, unless 'skip_nop' parameter is non-zero.
+	 */
+	.macro no_ret _func:req, skip_nop=0
+	bl	\_func
+#if DEBUG
+	.ifeq \skip_nop
+	nop
+	.endif
+#endif
+	.endm
+
+	/*
+	 * Reserve space for a spin lock in assembly file.
+	 */
+	.macro define_asm_spinlock _name:req
+	.align	SPINLOCK_ASM_ALIGN
+	\_name:
+	.space	SPINLOCK_ASM_SIZE
+	.endm
+
+	/*
+	 * Helper macro to OR the bottom 32 bits of `_val` into `_reg_l`
+	 * and the top 32 bits of `_val` into `_reg_h`.  If either the bottom
+	 * or top word of `_val` is zero, the corresponding OR operation
+	 * is skipped.
+	 */
+	.macro orr64_imm _reg_l, _reg_h, _val
+		.if (\_val >> 32)
+			orr \_reg_h, \_reg_h, #(\_val >> 32)
+		.endif
+		.if (\_val & 0xffffffff)
+			orr \_reg_l, \_reg_l, #(\_val & 0xffffffff)
+		.endif
+	.endm
+
+	/*
+	 * Helper macro to bitwise-clear bits in `_reg_l` and
+	 * `_reg_h` given a 64 bit immediate `_val`.  The set bits
+	 * in the bottom word of `_val` dictate which bits from
+	 * `_reg_l` should be cleared.  Similarly, the set bits in
+	 * the top word of `_val` dictate which bits from `_reg_h`
+	 * should be cleared.  If either the bottom or top word of
+	 * `_val` is zero, the corresponding BIC operation is skipped.
+	 */
+	.macro bic64_imm _reg_l, _reg_h, _val
+		.if (\_val >> 32)
+			bic \_reg_h, \_reg_h, #(\_val >> 32)
+		.endif
+		.if (\_val & 0xffffffff)
+			bic \_reg_l, \_reg_l, #(\_val & 0xffffffff)
+		.endif
+	.endm
+
+	/*
+	 * Helper macro for carrying out division in software when
+	 * hardware division is not suported. \top holds the dividend
+	 * in the function call and the remainder after
+	 * the function is executed. \bot holds the divisor. \div holds
+	 * the quotient and \temp is a temporary registed used in calcualtion.
+	 * The division algorithm has been obtained from:
+	 * http://www.keil.com/support/man/docs/armasm/armasm_dom1359731155623.htm
+	 */
+	.macro	softudiv	div:req,top:req,bot:req,temp:req
+
+	mov     \temp, \bot
+	cmp     \temp, \top, lsr #1
+div1:
+	movls   \temp, \temp, lsl #1
+	cmp     \temp, \top, lsr #1
+	bls     div1
+	mov     \div, #0
+
+div2:
+	cmp     \top, \temp
+	subcs   \top, \top,\temp
+	ADC     \div, \div, \div
+	mov     \temp, \temp, lsr #1
+	cmp     \temp, \bot
+	bhs     div2
+	.endm
+#endif /* ASM_MACROS_S */
diff --git a/include/arch/aarch32/assert_macros.S b/include/arch/aarch32/assert_macros.S
new file mode 100644
index 0000000..ab3a2eb
--- /dev/null
+++ b/include/arch/aarch32/assert_macros.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ASSERT_MACROS_S
+#define ASSERT_MACROS_S
+
+	/*
+	 * Assembler macro to enable asm_assert. We assume that the stack is
+	 * initialized prior to invoking this macro.
+	 */
+#define ASM_ASSERT(_cc) \
+.ifndef .L_assert_filename ;\
+	.pushsection .rodata.str1.1, "aS" ;\
+	.L_assert_filename: ;\
+			.string	__FILE__ ;\
+	.popsection ;\
+.endif ;\
+	b##_cc	300f ;\
+	ldr	r0, =.L_assert_filename ;\
+	ldr	r1, =__LINE__ ;\
+	b	asm_assert;\
+300:
+
+#endif /* ASSERT_MACROS_S */
diff --git a/include/arch/aarch32/console_macros.S b/include/arch/aarch32/console_macros.S
new file mode 100644
index 0000000..996cb32
--- /dev/null
+++ b/include/arch/aarch32/console_macros.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CONSOLE_MACROS_S
+#define CONSOLE_MACROS_S
+
+#include <drivers/console.h>
+
+/*
+ * This macro encapsulates the common setup that has to be done at the end of
+ * a console driver's register function. It will register all of the driver's
+ * callbacks in the console_t structure and initialize the flags field (by
+ * default consoles are enabled for the "boot" and "crash" states, this can be
+ * changed after registration with the console_set_scope() function). It ends
+ * with a tail call that will include return to the caller.
+ * REQUIRES console_t pointer in r0 and a valid return address in lr.
+ */
+	.macro	finish_console_register _driver, putc=0, getc=0, flush=0
+	/*
+	 * If any of the callback is not specified or set as 0, then the
+	 * corresponding callback entry in console_t is set to 0.
+	 */
+	.ifne \putc
+	  ldr	r1, =console_\_driver\()_putc
+	.else
+	  mov	r1, #0
+	.endif
+	str	r1, [r0, #CONSOLE_T_PUTC]
+
+	.ifne \getc
+	  ldr	r1, =console_\_driver\()_getc
+	.else
+	  mov	r1, #0
+	.endif
+	str	r1, [r0, #CONSOLE_T_GETC]
+
+	.ifne \flush
+	  ldr	r1, =console_\_driver\()_flush
+	.else
+	  mov	r1, #0
+	.endif
+	str	r1, [r0, #CONSOLE_T_FLUSH]
+
+	mov	r1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH)
+	str	r1, [r0, #CONSOLE_T_FLAGS]
+	b	console_register
+	.endm
+
+#endif /* CONSOLE_MACROS_S */
diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S
new file mode 100644
index 0000000..0bd8978
--- /dev/null
+++ b/include/arch/aarch32/el3_common_macros.S
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EL3_COMMON_MACROS_S
+#define EL3_COMMON_MACROS_S
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+	/*
+	 * Helper macro to initialise EL3 registers we care about.
+	 */
+	.macro el3_arch_init_common
+	/* ---------------------------------------------------------------------
+	 * SCTLR has already been initialised - read current value before
+	 * modifying.
+	 *
+	 * SCTLR.I: Enable the instruction cache.
+	 *
+	 * SCTLR.A: Enable Alignment fault checking. All instructions that load
+	 *  or store one or more registers have an alignment check that the
+	 *  address being accessed is aligned to the size of the data element(s)
+	 *  being accessed.
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r1, =(SCTLR_I_BIT | SCTLR_A_BIT)
+	ldcopr	r0, SCTLR
+	orr	r0, r0, r1
+	stcopr	r0, SCTLR
+	isb
+
+	/* ---------------------------------------------------------------------
+	 * Initialise SCR, setting all fields rather than relying on the hw.
+	 *
+	 * SCR.SIF: Enabled so that Secure state instruction fetches from
+	 *  Non-secure memory are not permitted.
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =(SCR_RESET_VAL | SCR_SIF_BIT)
+	stcopr	r0, SCR
+
+	/* -----------------------------------------------------
+	 * Enable the Asynchronous data abort now that the
+	 * exception vectors have been setup.
+	 * -----------------------------------------------------
+	 */
+	cpsie   a
+	isb
+
+	/* ---------------------------------------------------------------------
+	 * Initialise NSACR, setting all the fields, except for the
+	 * IMPLEMENTATION DEFINED field, rather than relying on the hw. Some
+	 * fields are architecturally UNKNOWN on reset.
+	 *
+	 * NSACR_ENABLE_FP_ACCESS: Represents NSACR.cp11 and NSACR.cp10. The
+	 *  cp11 field is ignored, but is set to same value as cp10. The cp10
+	 *  field is set to allow access to Advanced SIMD and floating point
+	 *  features from both Security states.
+	 * ---------------------------------------------------------------------
+	 */
+	ldcopr	r0, NSACR
+	and	r0, r0, #NSACR_IMP_DEF_MASK
+	orr	r0, r0, #(NSACR_RESET_VAL | NSACR_ENABLE_FP_ACCESS)
+	stcopr	r0, NSACR
+	isb
+
+	/* ---------------------------------------------------------------------
+	 * Initialise CPACR, setting all fields rather than relying on hw. Some
+	 * fields are architecturally UNKNOWN on reset.
+	 *
+	 * CPACR.TRCDIS: Trap control for PL0 and PL1 System register accesses
+	 *  to trace registers. Set to zero to allow access.
+	 *
+	 * CPACR_ENABLE_FP_ACCESS: Represents CPACR.cp11 and CPACR.cp10. The
+	 *  cp11 field is ignored, but is set to same value as cp10. The cp10
+	 *  field is set to allow full access from PL0 and PL1 to floating-point
+	 *  and Advanced SIMD features.
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =((CPACR_RESET_VAL | CPACR_ENABLE_FP_ACCESS) & ~(TRCDIS_BIT))
+	stcopr	r0, CPACR
+	isb
+
+	/* ---------------------------------------------------------------------
+	 * Initialise FPEXC, setting all fields rather than relying on hw. Some
+	 * fields are architecturally UNKNOWN on reset and are set to zero
+	 * except for field(s) listed below.
+	 *
+	 * FPEXC.EN: Enable access to Advanced SIMD and floating point features
+	 *  from all exception levels.
+         *
+         * __SOFTFP__: Predefined macro exposed by soft-float toolchain.
+         *  ARMv7 and Cortex-A32(ARMv8/aarch32) has both soft-float and
+         *  hard-float variants of toolchain, avoid compiling below code with
+         *  soft-float toolchain as "vmsr" instruction will not be recognized.
+	 * ---------------------------------------------------------------------
+	 */
+#if ((ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_VFP)) && !(__SOFTFP__)
+	ldr	r0, =(FPEXC_RESET_VAL | FPEXC_EN_BIT)
+	vmsr	FPEXC, r0
+	isb
+#endif
+
+#if (ARM_ARCH_MAJOR > 7)
+	/* ---------------------------------------------------------------------
+	 * Initialise SDCR, setting all the fields rather than relying on hw.
+	 *
+	 * SDCR.SPD: Disable AArch32 privileged debug. Debug exceptions from
+	 *  Secure EL1 are disabled.
+	 *
+	 * SDCR: Set to one so that cycle counting by PMCCNTR is prohibited in
+	 *  Secure state. This bit is RES0 in versions of the architecture
+	 *  earlier than ARMv8.5, setting it to 1 doesn't have any effect on
+	 *  them.
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =(SDCR_RESET_VAL | SDCR_SPD(SDCR_SPD_DISABLE) | SDCR_SCCD_BIT)
+	stcopr	r0, SDCR
+#endif
+
+	/*
+	 * If Data Independent Timing (DIT) functionality is implemented,
+	 * always enable DIT in EL3
+	 */
+	ldcopr	r0, ID_PFR0
+	and	r0, r0, #(ID_PFR0_DIT_MASK << ID_PFR0_DIT_SHIFT)
+	cmp	r0, #ID_PFR0_DIT_SUPPORTED
+	bne	1f
+	mrs	r0, cpsr
+	orr	r0, r0, #CPSR_DIT_BIT
+	msr	cpsr_cxsf, r0
+1:
+	.endm
+
+/* -----------------------------------------------------------------------------
+ * This is the super set of actions that need to be performed during a cold boot
+ * or a warm boot in EL3. This code is shared by BL1 and BL32 (SP_MIN).
+ *
+ * This macro will always perform reset handling, architectural initialisations
+ * and stack setup. The rest of the actions are optional because they might not
+ * be needed, depending on the context in which this macro is called. This is
+ * why this macro is parameterised ; each parameter allows to enable/disable
+ * some actions.
+ *
+ *  _init_sctlr:
+ *	Whether the macro needs to initialise the SCTLR register including
+ *	configuring the endianness of data accesses.
+ *
+ *  _warm_boot_mailbox:
+ *	Whether the macro needs to detect the type of boot (cold/warm). The
+ *	detection is based on the platform entrypoint address : if it is zero
+ *	then it is a cold boot, otherwise it is a warm boot. In the latter case,
+ *	this macro jumps on the platform entrypoint address.
+ *
+ *  _secondary_cold_boot:
+ *	Whether the macro needs to identify the CPU that is calling it: primary
+ *	CPU or secondary CPU. The primary CPU will be allowed to carry on with
+ *	the platform initialisations, while the secondaries will be put in a
+ *	platform-specific state in the meantime.
+ *
+ *	If the caller knows this macro will only be called by the primary CPU
+ *	then this parameter can be defined to 0 to skip this step.
+ *
+ * _init_memory:
+ *	Whether the macro needs to initialise the memory.
+ *
+ * _init_c_runtime:
+ *	Whether the macro needs to initialise the C runtime environment.
+ *
+ * _exception_vectors:
+ *	Address of the exception vectors to program in the VBAR_EL3 register.
+ * -----------------------------------------------------------------------------
+ */
+	.macro el3_entrypoint_common					\
+		_init_sctlr, _warm_boot_mailbox, _secondary_cold_boot,	\
+		_init_memory, _init_c_runtime, _exception_vectors
+
+	/* Make sure we are in Secure Mode */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCR
+	tst	r0, #SCR_NS_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	.if \_init_sctlr
+		/* -------------------------------------------------------------
+		 * This is the initialisation of SCTLR and so must ensure that
+		 * all fields are explicitly set rather than relying on hw. Some
+		 * fields reset to an IMPLEMENTATION DEFINED value.
+		 *
+		 * SCTLR.TE: Set to zero so that exceptions to an Exception
+		 *  Level executing at PL1 are taken to A32 state.
+		 *
+		 * SCTLR.EE: Set the CPU endianness before doing anything that
+		 *  might involve memory reads or writes. Set to zero to select
+		 *  Little Endian.
+		 *
+		 * SCTLR.V: Set to zero to select the normal exception vectors
+		 *  with base address held in VBAR.
+		 *
+		 * SCTLR.DSSBS: Set to zero to disable speculation store bypass
+		 *  safe behaviour upon exception entry to EL3.
+		 * -------------------------------------------------------------
+		 */
+		ldr     r0, =(SCTLR_RESET_VAL & ~(SCTLR_TE_BIT | SCTLR_EE_BIT | \
+				SCTLR_V_BIT | SCTLR_DSSBS_BIT))
+		stcopr	r0, SCTLR
+		isb
+	.endif /* _init_sctlr */
+
+	/* Switch to monitor mode */
+	cps	#MODE32_mon
+	isb
+
+	.if \_warm_boot_mailbox
+		/* -------------------------------------------------------------
+		 * This code will be executed for both warm and cold resets.
+		 * Now is the time to distinguish between the two.
+		 * Query the platform entrypoint address and if it is not zero
+		 * then it means it is a warm boot so jump to this address.
+		 * -------------------------------------------------------------
+		 */
+		bl	plat_get_my_entrypoint
+		cmp	r0, #0
+		bxne	r0
+	.endif /* _warm_boot_mailbox */
+
+	/* ---------------------------------------------------------------------
+	 * Set the exception vectors (VBAR/MVBAR).
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =\_exception_vectors
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	isb
+
+	/* ---------------------------------------------------------------------
+	 * It is a cold boot.
+	 * Perform any processor specific actions upon reset e.g. cache, TLB
+	 * invalidations etc.
+	 * ---------------------------------------------------------------------
+	 */
+	bl	reset_handler
+
+	el3_arch_init_common
+
+	.if \_secondary_cold_boot
+		/* -------------------------------------------------------------
+		 * Check if this is a primary or secondary CPU cold boot.
+		 * The primary CPU will set up the platform while the
+		 * secondaries are placed in a platform-specific state until the
+		 * primary CPU performs the necessary actions to bring them out
+		 * of that state and allows entry into the OS.
+		 * -------------------------------------------------------------
+		 */
+		bl	plat_is_my_cpu_primary
+		cmp	r0, #0
+		bne	do_primary_cold_boot
+
+		/* This is a cold boot on a secondary CPU */
+		bl	plat_secondary_cold_boot_setup
+		/* plat_secondary_cold_boot_setup() is not supposed to return */
+		no_ret	plat_panic_handler
+
+	do_primary_cold_boot:
+	.endif /* _secondary_cold_boot */
+
+	/* ---------------------------------------------------------------------
+	 * Initialize memory now. Secondary CPU initialization won't get to this
+	 * point.
+	 * ---------------------------------------------------------------------
+	 */
+
+	.if \_init_memory
+		bl	platform_mem_init
+	.endif /* _init_memory */
+
+	/* ---------------------------------------------------------------------
+	 * Init C runtime environment:
+	 *   - Zero-initialise the NOBITS sections. There are 2 of them:
+	 *       - the .bss section;
+	 *       - the coherent memory section (if any).
+	 *   - Relocate the data section from ROM to RAM, if required.
+	 * ---------------------------------------------------------------------
+	 */
+	.if \_init_c_runtime
+#if defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3)
+		/* -----------------------------------------------------------------
+		 * Invalidate the RW memory used by the image. This
+		 * includes the data and NOBITS sections. This is done to
+		 * safeguard against possible corruption of this memory by
+		 * dirty cache lines in a system cache as a result of use by
+		 * an earlier boot loader stage.
+		 * -----------------------------------------------------------------
+		 */
+		ldr	r0, =__RW_START__
+		ldr	r1, =__RW_END__
+		sub	r1, r1, r0
+		bl	inv_dcache_range
+#endif
+
+		ldr	r0, =__BSS_START__
+		ldr	r1, =__BSS_SIZE__
+		bl	zeromem
+
+#if USE_COHERENT_MEM
+		ldr	r0, =__COHERENT_RAM_START__
+		ldr	r1, =__COHERENT_RAM_UNALIGNED_SIZE__
+		bl	zeromem
+#endif
+
+#ifdef IMAGE_BL1
+		/* -----------------------------------------------------
+		 * Copy data from ROM to RAM.
+		 * -----------------------------------------------------
+		 */
+		ldr	r0, =__DATA_RAM_START__
+		ldr	r1, =__DATA_ROM_START__
+		ldr	r2, =__DATA_SIZE__
+		bl	memcpy4
+#endif
+	.endif /* _init_c_runtime */
+
+	/* ---------------------------------------------------------------------
+	 * Allocate a stack whose memory will be marked as Normal-IS-WBWA when
+	 * the MMU is enabled. There is no risk of reading stale stack memory
+	 * after enabling the MMU as only the primary CPU is running at the
+	 * moment.
+	 * ---------------------------------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+#if STACK_PROTECTOR_ENABLED
+	.if \_init_c_runtime
+	bl	update_stack_protector_canary
+	.endif /* _init_c_runtime */
+#endif
+	.endm
+
+#endif /* EL3_COMMON_MACROS_S */
diff --git a/include/arch/aarch32/smccc_helpers.h b/include/arch/aarch32/smccc_helpers.h
new file mode 100644
index 0000000..b2ee3cf
--- /dev/null
+++ b/include/arch/aarch32/smccc_helpers.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMCCC_HELPERS_H
+#define SMCCC_HELPERS_H
+
+#include <lib/smccc.h>
+
+/* These are offsets to registers in smc_ctx_t */
+#define SMC_CTX_GPREG_R0	U(0x0)
+#define SMC_CTX_GPREG_R1	U(0x4)
+#define SMC_CTX_GPREG_R2	U(0x8)
+#define SMC_CTX_GPREG_R3	U(0xC)
+#define SMC_CTX_GPREG_R4	U(0x10)
+#define SMC_CTX_GPREG_R5	U(0x14)
+#define SMC_CTX_SP_USR		U(0x34)
+#define SMC_CTX_SPSR_MON	U(0x78)
+#define SMC_CTX_SP_MON		U(0x7C)
+#define SMC_CTX_LR_MON		U(0x80)
+#define SMC_CTX_SCR		U(0x84)
+#define SMC_CTX_PMCR		U(0x88)
+#define SMC_CTX_SIZE		U(0x90)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * The generic structure to save arguments and callee saved registers during
+ * an SMC. Also this structure is used to store the result return values after
+ * the completion of SMC service.
+ */
+typedef struct smc_ctx {
+	u_register_t r0;
+	u_register_t r1;
+	u_register_t r2;
+	u_register_t r3;
+	u_register_t r4;
+	u_register_t r5;
+	u_register_t r6;
+	u_register_t r7;
+	u_register_t r8;
+	u_register_t r9;
+	u_register_t r10;
+	u_register_t r11;
+	u_register_t r12;
+	/* spsr_usr doesn't exist */
+	u_register_t sp_usr;
+	u_register_t lr_usr;
+	u_register_t spsr_irq;
+	u_register_t sp_irq;
+	u_register_t lr_irq;
+	u_register_t spsr_fiq;
+	u_register_t sp_fiq;
+	u_register_t lr_fiq;
+	u_register_t spsr_svc;
+	u_register_t sp_svc;
+	u_register_t lr_svc;
+	u_register_t spsr_abt;
+	u_register_t sp_abt;
+	u_register_t lr_abt;
+	u_register_t spsr_und;
+	u_register_t sp_und;
+	u_register_t lr_und;
+	u_register_t spsr_mon;
+	/*
+	 * `sp_mon` will point to the C runtime stack in monitor mode. But prior
+	 * to exit from SMC, this will point to the `smc_ctx_t` so that
+	 * on next entry due to SMC, the `smc_ctx_t` can be easily accessed.
+	 */
+	u_register_t sp_mon;
+	u_register_t lr_mon;
+	u_register_t scr;
+	u_register_t pmcr;
+	/*
+	 * The workaround for CVE-2017-5715 requires storing information in
+	 * the bottom 3 bits of the stack pointer.  Add a padding field to
+	 * force the size of the struct to be a multiple of 8.
+	 */
+	u_register_t pad;
+} smc_ctx_t __aligned(8);
+
+/*
+ * Compile time assertions related to the 'smc_context' structure to
+ * ensure that the assembler and the compiler view of the offsets of
+ * the structure members is the same.
+ */
+CASSERT(SMC_CTX_GPREG_R0 == __builtin_offsetof(smc_ctx_t, r0), \
+	assert_smc_ctx_greg_r0_offset_mismatch);
+CASSERT(SMC_CTX_GPREG_R1 == __builtin_offsetof(smc_ctx_t, r1), \
+	assert_smc_ctx_greg_r1_offset_mismatch);
+CASSERT(SMC_CTX_GPREG_R2 == __builtin_offsetof(smc_ctx_t, r2), \
+	assert_smc_ctx_greg_r2_offset_mismatch);
+CASSERT(SMC_CTX_GPREG_R3 == __builtin_offsetof(smc_ctx_t, r3), \
+	assert_smc_ctx_greg_r3_offset_mismatch);
+CASSERT(SMC_CTX_GPREG_R4 == __builtin_offsetof(smc_ctx_t, r4), \
+	assert_smc_ctx_greg_r4_offset_mismatch);
+CASSERT(SMC_CTX_SP_USR == __builtin_offsetof(smc_ctx_t, sp_usr), \
+	assert_smc_ctx_sp_usr_offset_mismatch);
+CASSERT(SMC_CTX_LR_MON == __builtin_offsetof(smc_ctx_t, lr_mon), \
+	assert_smc_ctx_lr_mon_offset_mismatch);
+CASSERT(SMC_CTX_SPSR_MON == __builtin_offsetof(smc_ctx_t, spsr_mon), \
+	assert_smc_ctx_spsr_mon_offset_mismatch);
+
+CASSERT((sizeof(smc_ctx_t) & 0x7U) == 0U, assert_smc_ctx_not_aligned);
+CASSERT(SMC_CTX_SIZE == sizeof(smc_ctx_t), assert_smc_ctx_size_mismatch);
+
+/* Convenience macros to return from SMC handler */
+#define SMC_RET0(_h) {				\
+	return (uintptr_t)(_h);			\
+}
+#define SMC_RET1(_h, _r0) {			\
+	((smc_ctx_t *)(_h))->r0 = (_r0);	\
+	SMC_RET0(_h);				\
+}
+#define SMC_RET2(_h, _r0, _r1) {		\
+	((smc_ctx_t *)(_h))->r1 = (_r1);	\
+	SMC_RET1(_h, (_r0));			\
+}
+#define SMC_RET3(_h, _r0, _r1, _r2) {		\
+	((smc_ctx_t *)(_h))->r2 = (_r2);	\
+	SMC_RET2(_h, (_r0), (_r1));		\
+}
+#define SMC_RET4(_h, _r0, _r1, _r2, _r3) {	\
+	((smc_ctx_t *)(_h))->r3 = (_r3);	\
+	SMC_RET3(_h, (_r0), (_r1), (_r2));	\
+}
+
+/*
+ * Helper macro to retrieve the SMC parameters from smc_ctx_t.
+ */
+#define get_smc_params_from_ctx(_hdl, _r1, _r2, _r3, _r4) {	\
+		_r1 = ((smc_ctx_t *)_hdl)->r1;		\
+		_r2 = ((smc_ctx_t *)_hdl)->r2;		\
+		_r3 = ((smc_ctx_t *)_hdl)->r3;		\
+		_r4 = ((smc_ctx_t *)_hdl)->r4;		\
+		}
+
+/* ------------------------------------------------------------------------
+ * Helper APIs for setting and retrieving appropriate `smc_ctx_t`.
+ * These functions need to implemented by the BL including this library.
+ * ------------------------------------------------------------------------
+ */
+
+/* Get the pointer to `smc_ctx_t` corresponding to the security state. */
+void *smc_get_ctx(unsigned int security_state);
+
+/* Set the next `smc_ctx_t` corresponding to the security state. */
+void smc_set_next_ctx(unsigned int security_state);
+
+/* Get the pointer to next `smc_ctx_t` already set by `smc_set_next_ctx()`. */
+void *smc_get_next_ctx(void);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* SMCCC_HELPERS_H */
diff --git a/include/arch/aarch32/smccc_macros.S b/include/arch/aarch32/smccc_macros.S
new file mode 100644
index 0000000..1fe6c64
--- /dev/null
+++ b/include/arch/aarch32/smccc_macros.S
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SMCCC_MACROS_S
+#define SMCCC_MACROS_S
+
+#include <arch.h>
+
+/*
+ * Macro to save the General purpose registers (r0 - r12), the banked
+ * spsr, lr, sp registers and the `scr` register to the SMC context on entry
+ * due a SMC call. The `lr` of the current mode (monitor) is expected to be
+ * already saved. The `sp` must point to the `smc_ctx_t` to save to.
+ * Additionally, also save the 'pmcr' register as this is updated whilst
+ * executing in the secure world.
+ */
+	.macro smccc_save_gp_mode_regs
+	/* Save r0 - r12 in the SMC context */
+	stm	sp, {r0-r12}
+	mov	r0, sp
+	add	r0, r0, #SMC_CTX_SP_USR
+
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+	/* Must be in secure state to restore Monitor mode */
+	ldcopr	r4, SCR
+	bic	r2, r4, #SCR_NS_BIT
+	stcopr	r2, SCR
+	isb
+
+	cps	#MODE32_sys
+	stm	r0!, {sp, lr}
+
+	cps	#MODE32_irq
+	mrs	r2, spsr
+	stm	r0!, {r2, sp, lr}
+
+	cps	#MODE32_fiq
+	mrs	r2, spsr
+	stm	r0!, {r2, sp, lr}
+
+	cps	#MODE32_svc
+	mrs	r2, spsr
+	stm	r0!, {r2, sp, lr}
+
+	cps	#MODE32_abt
+	mrs	r2, spsr
+	stm	r0!, {r2, sp, lr}
+
+	cps	#MODE32_und
+	mrs	r2, spsr
+	stm	r0!, {r2, sp, lr}
+
+	/* lr_mon is already saved by caller */
+	cps	#MODE32_mon
+	mrs	r2, spsr
+	stm	r0!, {r2}
+
+	stcopr	r4, SCR
+	isb
+#else
+	/* Save the banked registers including the current SPSR and LR */
+	mrs	r4, sp_usr
+	mrs	r5, lr_usr
+	mrs	r6, spsr_irq
+	mrs	r7, sp_irq
+	mrs	r8, lr_irq
+	mrs	r9, spsr_fiq
+	mrs	r10, sp_fiq
+	mrs	r11, lr_fiq
+	mrs	r12, spsr_svc
+	stm	r0!, {r4-r12}
+
+	mrs	r4, sp_svc
+	mrs	r5, lr_svc
+	mrs	r6, spsr_abt
+	mrs	r7, sp_abt
+	mrs	r8, lr_abt
+	mrs	r9, spsr_und
+	mrs	r10, sp_und
+	mrs	r11, lr_und
+	mrs	r12, spsr
+	stm	r0!, {r4-r12}
+	/* lr_mon is already saved by caller */
+
+	ldcopr	r4, SCR
+#endif
+	str	r4, [sp, #SMC_CTX_SCR]
+	ldcopr	r4, PMCR
+	str	r4, [sp, #SMC_CTX_PMCR]
+	.endm
+
+/*
+ * Macro to restore the `smc_ctx_t`, which includes the General purpose
+ * registers and banked mode registers, and exit from the monitor mode.
+ * r0 must point to the `smc_ctx_t` to restore from.
+ */
+	.macro monitor_exit
+	/*
+	 * Save the current sp and restore the smc context
+	 * pointer to sp which will be used for handling the
+	 * next SMC.
+	 */
+	str	sp, [r0, #SMC_CTX_SP_MON]
+	mov	sp, r0
+
+	/*
+	 * Restore SCR first so that we access the right banked register
+	 * when the other mode registers are restored.
+	 */
+	ldr	r1, [r0, #SMC_CTX_SCR]
+	stcopr	r1, SCR
+	isb
+
+	/*
+	 * Restore the PMCR register.
+	 */
+	ldr	r1, [r0, #SMC_CTX_PMCR]
+	stcopr	r1, PMCR
+
+	/* Restore the banked registers including the current SPSR */
+	add	r1, r0, #SMC_CTX_SP_USR
+
+#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
+	/* Must be in secure state to restore Monitor mode */
+	ldcopr	r4, SCR
+	bic	r2, r4, #SCR_NS_BIT
+	stcopr	r2, SCR
+	isb
+
+	cps	#MODE32_sys
+	ldm	r1!, {sp, lr}
+
+	cps	#MODE32_irq
+	ldm	r1!, {r2, sp, lr}
+	msr	spsr_fsxc, r2
+
+	cps	#MODE32_fiq
+	ldm	r1!, {r2, sp, lr}
+	msr	spsr_fsxc, r2
+
+	cps	#MODE32_svc
+	ldm	r1!, {r2, sp, lr}
+	msr	spsr_fsxc, r2
+
+	cps	#MODE32_abt
+	ldm	r1!, {r2, sp, lr}
+	msr	spsr_fsxc, r2
+
+	cps	#MODE32_und
+	ldm	r1!, {r2, sp, lr}
+	msr	spsr_fsxc, r2
+
+	cps	#MODE32_mon
+	ldm	r1!, {r2}
+	msr	spsr_fsxc, r2
+
+	stcopr	r4, SCR
+	isb
+#else
+	ldm	r1!, {r4-r12}
+	msr	sp_usr, r4
+	msr	lr_usr, r5
+	msr	spsr_irq, r6
+	msr	sp_irq, r7
+	msr	lr_irq, r8
+	msr	spsr_fiq, r9
+	msr	sp_fiq, r10
+	msr	lr_fiq, r11
+	msr	spsr_svc, r12
+
+	ldm	r1!, {r4-r12}
+	msr	sp_svc, r4
+	msr	lr_svc, r5
+	msr	spsr_abt, r6
+	msr	sp_abt, r7
+	msr	lr_abt, r8
+	msr	spsr_und, r9
+	msr	sp_und, r10
+	msr	lr_und, r11
+	/*
+	 * Use the `_fsxc` suffix explicitly to instruct the assembler
+	 * to update all the 32 bits of SPSR. Else, by default, the
+	 * assembler assumes `_fc` suffix which only modifies
+	 * f->[31:24] and c->[7:0] bits of SPSR.
+	 */
+	msr	spsr_fsxc, r12
+#endif
+
+	/* Restore the LR */
+	ldr	lr, [r0, #SMC_CTX_LR_MON]
+
+	/* Restore the rest of the general purpose registers */
+	ldm	r0, {r0-r12}
+	eret
+	.endm
+
+#endif /* SMCCC_MACROS_S */
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
new file mode 100644
index 0000000..fa857fb
--- /dev/null
+++ b/include/arch/aarch64/arch.h
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * MIDR bit definitions
+ ******************************************************************************/
+#define MIDR_IMPL_MASK		U(0xff)
+#define MIDR_IMPL_SHIFT		U(0x18)
+#define MIDR_VAR_SHIFT		U(20)
+#define MIDR_VAR_BITS		U(4)
+#define MIDR_VAR_MASK		U(0xf)
+#define MIDR_REV_SHIFT		U(0)
+#define MIDR_REV_BITS		U(4)
+#define MIDR_REV_MASK		U(0xf)
+#define MIDR_PN_MASK		U(0xfff)
+#define MIDR_PN_SHIFT		U(0x4)
+
+/*******************************************************************************
+ * MPIDR macros
+ ******************************************************************************/
+#define MPIDR_MT_MASK		(ULL(1) << 24)
+#define MPIDR_CPU_MASK		MPIDR_AFFLVL_MASK
+#define MPIDR_CLUSTER_MASK	(MPIDR_AFFLVL_MASK << MPIDR_AFFINITY_BITS)
+#define MPIDR_AFFINITY_BITS	U(8)
+#define MPIDR_AFFLVL_MASK	ULL(0xff)
+#define MPIDR_AFF0_SHIFT	U(0)
+#define MPIDR_AFF1_SHIFT	U(8)
+#define MPIDR_AFF2_SHIFT	U(16)
+#define MPIDR_AFF3_SHIFT	U(32)
+#define MPIDR_AFF_SHIFT(_n)	MPIDR_AFF##_n##_SHIFT
+#define MPIDR_AFFINITY_MASK	ULL(0xff00ffffff)
+#define MPIDR_AFFLVL_SHIFT	U(3)
+#define MPIDR_AFFLVL0		ULL(0x0)
+#define MPIDR_AFFLVL1		ULL(0x1)
+#define MPIDR_AFFLVL2		ULL(0x2)
+#define MPIDR_AFFLVL3		ULL(0x3)
+#define MPIDR_AFFLVL(_n)	MPIDR_AFFLVL##_n
+#define MPIDR_AFFLVL0_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL1_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL2_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK)
+#define MPIDR_AFFLVL3_VAL(mpidr) \
+		(((mpidr) >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK)
+/*
+ * The MPIDR_MAX_AFFLVL count starts from 0. Take care to
+ * add one while using this macro to define array sizes.
+ * TODO: Support only the first 3 affinity levels for now.
+ */
+#define MPIDR_MAX_AFFLVL	U(2)
+
+#define MPID_MASK		(MPIDR_MT_MASK				 | \
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT) | \
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT) | \
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF1_SHIFT) | \
+				 (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT))
+
+#define MPIDR_AFF_ID(mpid, n)					\
+	(((mpid) >> MPIDR_AFF_SHIFT(n)) & MPIDR_AFFLVL_MASK)
+
+/*
+ * An invalid MPID. This value can be used by functions that return an MPID to
+ * indicate an error.
+ */
+#define INVALID_MPID		U(0xFFFFFFFF)
+
+/*******************************************************************************
+ * Definitions for CPU system register interface to GICv3
+ ******************************************************************************/
+#define ICC_IGRPEN1_EL1		S3_0_C12_C12_7
+#define ICC_SGI1R		S3_0_C12_C11_5
+#define ICC_SRE_EL1		S3_0_C12_C12_5
+#define ICC_SRE_EL2		S3_4_C12_C9_5
+#define ICC_SRE_EL3		S3_6_C12_C12_5
+#define ICC_CTLR_EL1		S3_0_C12_C12_4
+#define ICC_CTLR_EL3		S3_6_C12_C12_4
+#define ICC_PMR_EL1		S3_0_C4_C6_0
+#define ICC_RPR_EL1		S3_0_C12_C11_3
+#define ICC_IGRPEN1_EL3		S3_6_c12_c12_7
+#define ICC_IGRPEN0_EL1		S3_0_c12_c12_6
+#define ICC_HPPIR0_EL1		S3_0_c12_c8_2
+#define ICC_HPPIR1_EL1		S3_0_c12_c12_2
+#define ICC_IAR0_EL1		S3_0_c12_c8_0
+#define ICC_IAR1_EL1		S3_0_c12_c12_0
+#define ICC_EOIR0_EL1		S3_0_c12_c8_1
+#define ICC_EOIR1_EL1		S3_0_c12_c12_1
+#define ICC_SGI0R_EL1		S3_0_c12_c11_7
+
+/*******************************************************************************
+ * Generic timer memory mapped registers & offsets
+ ******************************************************************************/
+#define CNTCR_OFF			U(0x000)
+#define CNTCV_OFF			U(0x008)
+#define CNTFID_OFF			U(0x020)
+
+#define CNTCR_EN			(U(1) << 0)
+#define CNTCR_HDBG			(U(1) << 1)
+#define CNTCR_FCREQ(x)			((x) << 8)
+
+/*******************************************************************************
+ * System register bit definitions
+ ******************************************************************************/
+/* CLIDR definitions */
+#define LOUIS_SHIFT		U(21)
+#define LOC_SHIFT		U(24)
+#define CLIDR_FIELD_WIDTH	U(3)
+
+/* CSSELR definitions */
+#define LEVEL_SHIFT		U(1)
+
+/* Data cache set/way op type defines */
+#define DCISW			U(0x0)
+#define DCCISW			U(0x1)
+#if ERRATA_A53_827319
+#define DCCSW			DCCISW
+#else
+#define DCCSW			U(0x2)
+#endif
+
+/* ID_AA64PFR0_EL1 definitions */
+#define ID_AA64PFR0_EL0_SHIFT	U(0)
+#define ID_AA64PFR0_EL1_SHIFT	U(4)
+#define ID_AA64PFR0_EL2_SHIFT	U(8)
+#define ID_AA64PFR0_EL3_SHIFT	U(12)
+#define ID_AA64PFR0_AMU_SHIFT	U(44)
+#define ID_AA64PFR0_AMU_LENGTH	U(4)
+#define ID_AA64PFR0_AMU_MASK	ULL(0xf)
+#define ID_AA64PFR0_ELX_MASK	ULL(0xf)
+#define ID_AA64PFR0_SVE_SHIFT	U(32)
+#define ID_AA64PFR0_SVE_MASK	ULL(0xf)
+#define ID_AA64PFR0_SVE_LENGTH	U(4)
+#define ID_AA64PFR0_MPAM_SHIFT	U(40)
+#define ID_AA64PFR0_MPAM_MASK	ULL(0xf)
+#define ID_AA64PFR0_DIT_SHIFT	U(48)
+#define ID_AA64PFR0_DIT_MASK	ULL(0xf)
+#define ID_AA64PFR0_DIT_LENGTH	U(4)
+#define ID_AA64PFR0_DIT_SUPPORTED	U(1)
+#define ID_AA64PFR0_CSV2_SHIFT	U(56)
+#define ID_AA64PFR0_CSV2_MASK	ULL(0xf)
+#define ID_AA64PFR0_CSV2_LENGTH	U(4)
+
+/* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
+#define ID_AA64DFR0_PMS_SHIFT	U(32)
+#define ID_AA64DFR0_PMS_LENGTH	U(4)
+#define ID_AA64DFR0_PMS_MASK	ULL(0xf)
+
+#define EL_IMPL_NONE		ULL(0)
+#define EL_IMPL_A64ONLY		ULL(1)
+#define EL_IMPL_A64_A32		ULL(2)
+
+#define ID_AA64PFR0_GIC_SHIFT	U(24)
+#define ID_AA64PFR0_GIC_WIDTH	U(4)
+#define ID_AA64PFR0_GIC_MASK	ULL(0xf)
+
+/* ID_AA64ISAR1_EL1 definitions */
+#define ID_AA64ISAR1_EL1	S3_0_C0_C6_1
+#define ID_AA64ISAR1_GPI_SHIFT	U(28)
+#define ID_AA64ISAR1_GPI_MASK	ULL(0xf)
+#define ID_AA64ISAR1_GPA_SHIFT	U(24)
+#define ID_AA64ISAR1_GPA_MASK	ULL(0xf)
+#define ID_AA64ISAR1_API_SHIFT	U(8)
+#define ID_AA64ISAR1_API_MASK	ULL(0xf)
+#define ID_AA64ISAR1_APA_SHIFT	U(4)
+#define ID_AA64ISAR1_APA_MASK	ULL(0xf)
+
+/* ID_AA64MMFR0_EL1 definitions */
+#define ID_AA64MMFR0_EL1_PARANGE_SHIFT	U(0)
+#define ID_AA64MMFR0_EL1_PARANGE_MASK	ULL(0xf)
+
+#define PARANGE_0000	U(32)
+#define PARANGE_0001	U(36)
+#define PARANGE_0010	U(40)
+#define PARANGE_0011	U(42)
+#define PARANGE_0100	U(44)
+#define PARANGE_0101	U(48)
+#define PARANGE_0110	U(52)
+
+#define ID_AA64MMFR0_EL1_TGRAN4_SHIFT		U(28)
+#define ID_AA64MMFR0_EL1_TGRAN4_MASK		ULL(0xf)
+#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED	ULL(0x0)
+#define ID_AA64MMFR0_EL1_TGRAN4_NOT_SUPPORTED	ULL(0xf)
+
+#define ID_AA64MMFR0_EL1_TGRAN64_SHIFT		U(24)
+#define ID_AA64MMFR0_EL1_TGRAN64_MASK		ULL(0xf)
+#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED	ULL(0x0)
+#define ID_AA64MMFR0_EL1_TGRAN64_NOT_SUPPORTED	ULL(0xf)
+
+#define ID_AA64MMFR0_EL1_TGRAN16_SHIFT		U(20)
+#define ID_AA64MMFR0_EL1_TGRAN16_MASK		ULL(0xf)
+#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED	ULL(0x1)
+#define ID_AA64MMFR0_EL1_TGRAN16_NOT_SUPPORTED	ULL(0x0)
+
+/* ID_AA64MMFR2_EL1 definitions */
+#define ID_AA64MMFR2_EL1		S3_0_C0_C7_2
+
+#define ID_AA64MMFR2_EL1_ST_SHIFT	U(28)
+#define ID_AA64MMFR2_EL1_ST_MASK	ULL(0xf)
+
+#define ID_AA64MMFR2_EL1_CNP_SHIFT	U(0)
+#define ID_AA64MMFR2_EL1_CNP_MASK	ULL(0xf)
+
+/* ID_AA64PFR1_EL1 definitions */
+#define ID_AA64PFR1_EL1_SSBS_SHIFT	U(4)
+#define ID_AA64PFR1_EL1_SSBS_MASK	ULL(0xf)
+
+#define SSBS_UNAVAILABLE	ULL(0)	/* No architectural SSBS support */
+
+#define ID_AA64PFR1_EL1_BT_SHIFT	U(0)
+#define ID_AA64PFR1_EL1_BT_MASK		ULL(0xf)
+
+#define BTI_IMPLEMENTED		ULL(1)	/* The BTI mechanism is implemented */
+
+#define ID_AA64PFR1_EL1_MTE_SHIFT	U(8)
+#define ID_AA64PFR1_EL1_MTE_MASK	ULL(0xf)
+
+#define MTE_UNIMPLEMENTED	ULL(0)
+#define MTE_IMPLEMENTED_EL0	ULL(1)	/* MTE is only implemented at EL0 */
+#define MTE_IMPLEMENTED_ELX	ULL(2)	/* MTE is implemented at all ELs */
+
+/* ID_PFR1_EL1 definitions */
+#define ID_PFR1_VIRTEXT_SHIFT	U(12)
+#define ID_PFR1_VIRTEXT_MASK	U(0xf)
+#define GET_VIRT_EXT(id)	(((id) >> ID_PFR1_VIRTEXT_SHIFT) \
+				 & ID_PFR1_VIRTEXT_MASK)
+
+/* SCTLR definitions */
+#define SCTLR_EL2_RES1	((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \
+			 (U(1) << 22) | (U(1) << 18) | (U(1) << 16) | \
+			 (U(1) << 11) | (U(1) << 5) | (U(1) << 4))
+
+#define SCTLR_EL1_RES1	((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \
+			 (U(1) << 22) | (U(1) << 20) | (U(1) << 11))
+#define SCTLR_AARCH32_EL1_RES1 \
+			((U(1) << 23) | (U(1) << 22) | (U(1) << 11) | \
+			 (U(1) << 4) | (U(1) << 3))
+
+#define SCTLR_EL3_RES1	((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \
+			(U(1) << 22) | (U(1) << 18) | (U(1) << 16) | \
+			(U(1) << 11) | (U(1) << 5) | (U(1) << 4))
+
+#define SCTLR_M_BIT		(ULL(1) << 0)
+#define SCTLR_A_BIT		(ULL(1) << 1)
+#define SCTLR_C_BIT		(ULL(1) << 2)
+#define SCTLR_SA_BIT		(ULL(1) << 3)
+#define SCTLR_SA0_BIT		(ULL(1) << 4)
+#define SCTLR_CP15BEN_BIT	(ULL(1) << 5)
+#define SCTLR_ITD_BIT		(ULL(1) << 7)
+#define SCTLR_SED_BIT		(ULL(1) << 8)
+#define SCTLR_UMA_BIT		(ULL(1) << 9)
+#define SCTLR_I_BIT		(ULL(1) << 12)
+#define SCTLR_EnDB_BIT		(ULL(1) << 13)
+#define SCTLR_DZE_BIT		(ULL(1) << 14)
+#define SCTLR_UCT_BIT		(ULL(1) << 15)
+#define SCTLR_NTWI_BIT		(ULL(1) << 16)
+#define SCTLR_NTWE_BIT		(ULL(1) << 18)
+#define SCTLR_WXN_BIT		(ULL(1) << 19)
+#define SCTLR_UWXN_BIT		(ULL(1) << 20)
+#define SCTLR_IESB_BIT		(ULL(1) << 21)
+#define SCTLR_E0E_BIT		(ULL(1) << 24)
+#define SCTLR_EE_BIT		(ULL(1) << 25)
+#define SCTLR_UCI_BIT		(ULL(1) << 26)
+#define SCTLR_EnDA_BIT		(ULL(1) << 27)
+#define SCTLR_EnIB_BIT		(ULL(1) << 30)
+#define SCTLR_EnIA_BIT		(ULL(1) << 31)
+#define SCTLR_BT0_BIT		(ULL(1) << 35)
+#define SCTLR_BT1_BIT		(ULL(1) << 36)
+#define SCTLR_BT_BIT		(ULL(1) << 36)
+#define SCTLR_DSSBS_BIT		(ULL(1) << 44)
+#define SCTLR_RESET_VAL		SCTLR_EL3_RES1
+
+/* CPACR_El1 definitions */
+#define CPACR_EL1_FPEN(x)	((x) << 20)
+#define CPACR_EL1_FP_TRAP_EL0	U(0x1)
+#define CPACR_EL1_FP_TRAP_ALL	U(0x2)
+#define CPACR_EL1_FP_TRAP_NONE	U(0x3)
+
+/* SCR definitions */
+#define SCR_RES1_BITS		((U(1) << 4) | (U(1) << 5))
+#define SCR_ATA_BIT		(U(1) << 26)
+#define SCR_FIEN_BIT		(U(1) << 21)
+#define SCR_API_BIT		(U(1) << 17)
+#define SCR_APK_BIT		(U(1) << 16)
+#define SCR_TWE_BIT		(U(1) << 13)
+#define SCR_TWI_BIT		(U(1) << 12)
+#define SCR_ST_BIT		(U(1) << 11)
+#define SCR_RW_BIT		(U(1) << 10)
+#define SCR_SIF_BIT		(U(1) << 9)
+#define SCR_HCE_BIT		(U(1) << 8)
+#define SCR_SMD_BIT		(U(1) << 7)
+#define SCR_EA_BIT		(U(1) << 3)
+#define SCR_FIQ_BIT		(U(1) << 2)
+#define SCR_IRQ_BIT		(U(1) << 1)
+#define SCR_NS_BIT		(U(1) << 0)
+#define SCR_VALID_BIT_MASK	U(0x2f8f)
+#define SCR_RESET_VAL		SCR_RES1_BITS
+
+/* MDCR_EL3 definitions */
+#define MDCR_SPD32(x)		((x) << 14)
+#define MDCR_SPD32_LEGACY	ULL(0x0)
+#define MDCR_SPD32_DISABLE	ULL(0x2)
+#define MDCR_SPD32_ENABLE	ULL(0x3)
+#define MDCR_SDD_BIT		(ULL(1) << 16)
+#define MDCR_NSPB(x)		((x) << 12)
+#define MDCR_NSPB_EL1		ULL(0x3)
+#define MDCR_TDOSA_BIT		(ULL(1) << 10)
+#define MDCR_TDA_BIT		(ULL(1) << 9)
+#define MDCR_TPM_BIT		(ULL(1) << 6)
+#define MDCR_SCCD_BIT		(ULL(1) << 23)
+#define MDCR_EL3_RESET_VAL	ULL(0x0)
+
+/* MDCR_EL2 definitions */
+#define MDCR_EL2_TPMS		(U(1) << 14)
+#define MDCR_EL2_E2PB(x)	((x) << 12)
+#define MDCR_EL2_E2PB_EL1	U(0x3)
+#define MDCR_EL2_TDRA_BIT	(U(1) << 11)
+#define MDCR_EL2_TDOSA_BIT	(U(1) << 10)
+#define MDCR_EL2_TDA_BIT	(U(1) << 9)
+#define MDCR_EL2_TDE_BIT	(U(1) << 8)
+#define MDCR_EL2_HPME_BIT	(U(1) << 7)
+#define MDCR_EL2_TPM_BIT	(U(1) << 6)
+#define MDCR_EL2_TPMCR_BIT	(U(1) << 5)
+#define MDCR_EL2_RESET_VAL	U(0x0)
+
+/* HSTR_EL2 definitions */
+#define HSTR_EL2_RESET_VAL	U(0x0)
+#define HSTR_EL2_T_MASK		U(0xff)
+
+/* CNTHP_CTL_EL2 definitions */
+#define CNTHP_CTL_ENABLE_BIT	(U(1) << 0)
+#define CNTHP_CTL_RESET_VAL	U(0x0)
+
+/* VTTBR_EL2 definitions */
+#define VTTBR_RESET_VAL		ULL(0x0)
+#define VTTBR_VMID_MASK		ULL(0xff)
+#define VTTBR_VMID_SHIFT	U(48)
+#define VTTBR_BADDR_MASK	ULL(0xffffffffffff)
+#define VTTBR_BADDR_SHIFT	U(0)
+
+/* HCR definitions */
+#define HCR_API_BIT		(ULL(1) << 41)
+#define HCR_APK_BIT		(ULL(1) << 40)
+#define HCR_TGE_BIT		(ULL(1) << 27)
+#define HCR_RW_SHIFT		U(31)
+#define HCR_RW_BIT		(ULL(1) << HCR_RW_SHIFT)
+#define HCR_AMO_BIT		(ULL(1) << 5)
+#define HCR_IMO_BIT		(ULL(1) << 4)
+#define HCR_FMO_BIT		(ULL(1) << 3)
+
+/* ISR definitions */
+#define ISR_A_SHIFT		U(8)
+#define ISR_I_SHIFT		U(7)
+#define ISR_F_SHIFT		U(6)
+
+/* CNTHCTL_EL2 definitions */
+#define CNTHCTL_RESET_VAL	U(0x0)
+#define EVNTEN_BIT		(U(1) << 2)
+#define EL1PCEN_BIT		(U(1) << 1)
+#define EL1PCTEN_BIT		(U(1) << 0)
+
+/* CNTKCTL_EL1 definitions */
+#define EL0PTEN_BIT		(U(1) << 9)
+#define EL0VTEN_BIT		(U(1) << 8)
+#define EL0PCTEN_BIT		(U(1) << 0)
+#define EL0VCTEN_BIT		(U(1) << 1)
+#define EVNTEN_BIT		(U(1) << 2)
+#define EVNTDIR_BIT		(U(1) << 3)
+#define EVNTI_SHIFT		U(4)
+#define EVNTI_MASK		U(0xf)
+
+/* CPTR_EL3 definitions */
+#define TCPAC_BIT		(U(1) << 31)
+#define TAM_BIT			(U(1) << 30)
+#define TTA_BIT			(U(1) << 20)
+#define TFP_BIT			(U(1) << 10)
+#define CPTR_EZ_BIT		(U(1) << 8)
+#define CPTR_EL3_RESET_VAL	U(0x0)
+
+/* CPTR_EL2 definitions */
+#define CPTR_EL2_RES1		((U(1) << 13) | (U(1) << 12) | (U(0x3ff)))
+#define CPTR_EL2_TCPAC_BIT	(U(1) << 31)
+#define CPTR_EL2_TAM_BIT	(U(1) << 30)
+#define CPTR_EL2_TTA_BIT	(U(1) << 20)
+#define CPTR_EL2_TFP_BIT	(U(1) << 10)
+#define CPTR_EL2_TZ_BIT		(U(1) << 8)
+#define CPTR_EL2_RESET_VAL	CPTR_EL2_RES1
+
+/* CPSR/SPSR definitions */
+#define DAIF_FIQ_BIT		(U(1) << 0)
+#define DAIF_IRQ_BIT		(U(1) << 1)
+#define DAIF_ABT_BIT		(U(1) << 2)
+#define DAIF_DBG_BIT		(U(1) << 3)
+#define SPSR_DAIF_SHIFT		U(6)
+#define SPSR_DAIF_MASK		U(0xf)
+
+#define SPSR_AIF_SHIFT		U(6)
+#define SPSR_AIF_MASK		U(0x7)
+
+#define SPSR_E_SHIFT		U(9)
+#define SPSR_E_MASK		U(0x1)
+#define SPSR_E_LITTLE		U(0x0)
+#define SPSR_E_BIG		U(0x1)
+
+#define SPSR_T_SHIFT		U(5)
+#define SPSR_T_MASK		U(0x1)
+#define SPSR_T_ARM		U(0x0)
+#define SPSR_T_THUMB		U(0x1)
+
+#define SPSR_M_SHIFT		U(4)
+#define SPSR_M_MASK		U(0x1)
+#define SPSR_M_AARCH64		U(0x0)
+#define SPSR_M_AARCH32		U(0x1)
+
+#define SPSR_SSBS_BIT_AARCH64	BIT_64(12)
+#define SPSR_SSBS_BIT_AARCH32	BIT_64(23)
+
+#define DISABLE_ALL_EXCEPTIONS \
+		(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
+
+#define DISABLE_INTERRUPTS	(DAIF_FIQ_BIT | DAIF_IRQ_BIT)
+
+/*
+ * RMR_EL3 definitions
+ */
+#define RMR_EL3_RR_BIT		(U(1) << 1)
+#define RMR_EL3_AA64_BIT	(U(1) << 0)
+
+/*
+ * HI-VECTOR address for AArch32 state
+ */
+#define HI_VECTOR_BASE		U(0xFFFF0000)
+
+/*
+ * TCR defintions
+ */
+#define TCR_EL3_RES1		((ULL(1) << 31) | (ULL(1) << 23))
+#define TCR_EL2_RES1		((ULL(1) << 31) | (ULL(1) << 23))
+#define TCR_EL1_IPS_SHIFT	U(32)
+#define TCR_EL2_PS_SHIFT	U(16)
+#define TCR_EL3_PS_SHIFT	U(16)
+
+#define TCR_TxSZ_MIN		ULL(16)
+#define TCR_TxSZ_MAX		ULL(39)
+#define TCR_TxSZ_MAX_TTST	ULL(48)
+
+#define TCR_T0SZ_SHIFT		U(0)
+#define TCR_T1SZ_SHIFT		U(16)
+
+/* (internal) physical address size bits in EL3/EL1 */
+#define TCR_PS_BITS_4GB		ULL(0x0)
+#define TCR_PS_BITS_64GB	ULL(0x1)
+#define TCR_PS_BITS_1TB		ULL(0x2)
+#define TCR_PS_BITS_4TB		ULL(0x3)
+#define TCR_PS_BITS_16TB	ULL(0x4)
+#define TCR_PS_BITS_256TB	ULL(0x5)
+
+#define ADDR_MASK_48_TO_63	ULL(0xFFFF000000000000)
+#define ADDR_MASK_44_TO_47	ULL(0x0000F00000000000)
+#define ADDR_MASK_42_TO_43	ULL(0x00000C0000000000)
+#define ADDR_MASK_40_TO_41	ULL(0x0000030000000000)
+#define ADDR_MASK_36_TO_39	ULL(0x000000F000000000)
+#define ADDR_MASK_32_TO_35	ULL(0x0000000F00000000)
+
+#define TCR_RGN_INNER_NC	(ULL(0x0) << 8)
+#define TCR_RGN_INNER_WBA	(ULL(0x1) << 8)
+#define TCR_RGN_INNER_WT	(ULL(0x2) << 8)
+#define TCR_RGN_INNER_WBNA	(ULL(0x3) << 8)
+
+#define TCR_RGN_OUTER_NC	(ULL(0x0) << 10)
+#define TCR_RGN_OUTER_WBA	(ULL(0x1) << 10)
+#define TCR_RGN_OUTER_WT	(ULL(0x2) << 10)
+#define TCR_RGN_OUTER_WBNA	(ULL(0x3) << 10)
+
+#define TCR_SH_NON_SHAREABLE	(ULL(0x0) << 12)
+#define TCR_SH_OUTER_SHAREABLE	(ULL(0x2) << 12)
+#define TCR_SH_INNER_SHAREABLE	(ULL(0x3) << 12)
+
+#define TCR_RGN1_INNER_NC	(ULL(0x0) << 24)
+#define TCR_RGN1_INNER_WBA	(ULL(0x1) << 24)
+#define TCR_RGN1_INNER_WT	(ULL(0x2) << 24)
+#define TCR_RGN1_INNER_WBNA	(ULL(0x3) << 24)
+
+#define TCR_RGN1_OUTER_NC	(ULL(0x0) << 26)
+#define TCR_RGN1_OUTER_WBA	(ULL(0x1) << 26)
+#define TCR_RGN1_OUTER_WT	(ULL(0x2) << 26)
+#define TCR_RGN1_OUTER_WBNA	(ULL(0x3) << 26)
+
+#define TCR_SH1_NON_SHAREABLE	(ULL(0x0) << 28)
+#define TCR_SH1_OUTER_SHAREABLE	(ULL(0x2) << 28)
+#define TCR_SH1_INNER_SHAREABLE	(ULL(0x3) << 28)
+
+#define TCR_TG0_SHIFT		U(14)
+#define TCR_TG0_MASK		ULL(3)
+#define TCR_TG0_4K		(ULL(0) << TCR_TG0_SHIFT)
+#define TCR_TG0_64K		(ULL(1) << TCR_TG0_SHIFT)
+#define TCR_TG0_16K		(ULL(2) << TCR_TG0_SHIFT)
+
+#define TCR_TG1_SHIFT		U(30)
+#define TCR_TG1_MASK		ULL(3)
+#define TCR_TG1_16K		(ULL(1) << TCR_TG1_SHIFT)
+#define TCR_TG1_4K		(ULL(2) << TCR_TG1_SHIFT)
+#define TCR_TG1_64K		(ULL(3) << TCR_TG1_SHIFT)
+
+#define TCR_EPD0_BIT		(ULL(1) << 7)
+#define TCR_EPD1_BIT		(ULL(1) << 23)
+
+#define MODE_SP_SHIFT		U(0x0)
+#define MODE_SP_MASK		U(0x1)
+#define MODE_SP_EL0		U(0x0)
+#define MODE_SP_ELX		U(0x1)
+
+#define MODE_RW_SHIFT		U(0x4)
+#define MODE_RW_MASK		U(0x1)
+#define MODE_RW_64		U(0x0)
+#define MODE_RW_32		U(0x1)
+
+#define MODE_EL_SHIFT		U(0x2)
+#define MODE_EL_MASK		U(0x3)
+#define MODE_EL3		U(0x3)
+#define MODE_EL2		U(0x2)
+#define MODE_EL1		U(0x1)
+#define MODE_EL0		U(0x0)
+
+#define MODE32_SHIFT		U(0)
+#define MODE32_MASK		U(0xf)
+#define MODE32_usr		U(0x0)
+#define MODE32_fiq		U(0x1)
+#define MODE32_irq		U(0x2)
+#define MODE32_svc		U(0x3)
+#define MODE32_mon		U(0x6)
+#define MODE32_abt		U(0x7)
+#define MODE32_hyp		U(0xa)
+#define MODE32_und		U(0xb)
+#define MODE32_sys		U(0xf)
+
+#define GET_RW(mode)		(((mode) >> MODE_RW_SHIFT) & MODE_RW_MASK)
+#define GET_EL(mode)		(((mode) >> MODE_EL_SHIFT) & MODE_EL_MASK)
+#define GET_SP(mode)		(((mode) >> MODE_SP_SHIFT) & MODE_SP_MASK)
+#define GET_M32(mode)		(((mode) >> MODE32_SHIFT) & MODE32_MASK)
+
+#define SPSR_64(el, sp, daif)					\
+	(((MODE_RW_64 << MODE_RW_SHIFT) |			\
+	(((el) & MODE_EL_MASK) << MODE_EL_SHIFT) |		\
+	(((sp) & MODE_SP_MASK) << MODE_SP_SHIFT) |		\
+	(((daif) & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)) &	\
+	(~(SPSR_SSBS_BIT_AARCH64)))
+
+#define SPSR_MODE32(mode, isa, endian, aif)		\
+	(((MODE_RW_32 << MODE_RW_SHIFT) |		\
+	(((mode) & MODE32_MASK) << MODE32_SHIFT) |	\
+	(((isa) & SPSR_T_MASK) << SPSR_T_SHIFT) |	\
+	(((endian) & SPSR_E_MASK) << SPSR_E_SHIFT) |	\
+	(((aif) & SPSR_AIF_MASK) << SPSR_AIF_SHIFT)) &	\
+	(~(SPSR_SSBS_BIT_AARCH32)))
+
+/*
+ * TTBR Definitions
+ */
+#define TTBR_CNP_BIT		ULL(0x1)
+
+/*
+ * CTR_EL0 definitions
+ */
+#define CTR_CWG_SHIFT		U(24)
+#define CTR_CWG_MASK		U(0xf)
+#define CTR_ERG_SHIFT		U(20)
+#define CTR_ERG_MASK		U(0xf)
+#define CTR_DMINLINE_SHIFT	U(16)
+#define CTR_DMINLINE_MASK	U(0xf)
+#define CTR_L1IP_SHIFT		U(14)
+#define CTR_L1IP_MASK		U(0x3)
+#define CTR_IMINLINE_SHIFT	U(0)
+#define CTR_IMINLINE_MASK	U(0xf)
+
+#define MAX_CACHE_LINE_SIZE	U(0x800) /* 2KB */
+
+/* Physical timer control register bit fields shifts and masks */
+#define CNTP_CTL_ENABLE_SHIFT   U(0)
+#define CNTP_CTL_IMASK_SHIFT    U(1)
+#define CNTP_CTL_ISTATUS_SHIFT  U(2)
+
+#define CNTP_CTL_ENABLE_MASK    U(1)
+#define CNTP_CTL_IMASK_MASK     U(1)
+#define CNTP_CTL_ISTATUS_MASK   U(1)
+
+/* Exception Syndrome register bits and bobs */
+#define ESR_EC_SHIFT			U(26)
+#define ESR_EC_MASK			U(0x3f)
+#define ESR_EC_LENGTH			U(6)
+#define EC_UNKNOWN			U(0x0)
+#define EC_WFE_WFI			U(0x1)
+#define EC_AARCH32_CP15_MRC_MCR		U(0x3)
+#define EC_AARCH32_CP15_MRRC_MCRR	U(0x4)
+#define EC_AARCH32_CP14_MRC_MCR		U(0x5)
+#define EC_AARCH32_CP14_LDC_STC		U(0x6)
+#define EC_FP_SIMD			U(0x7)
+#define EC_AARCH32_CP10_MRC		U(0x8)
+#define EC_AARCH32_CP14_MRRC_MCRR	U(0xc)
+#define EC_ILLEGAL			U(0xe)
+#define EC_AARCH32_SVC			U(0x11)
+#define EC_AARCH32_HVC			U(0x12)
+#define EC_AARCH32_SMC			U(0x13)
+#define EC_AARCH64_SVC			U(0x15)
+#define EC_AARCH64_HVC			U(0x16)
+#define EC_AARCH64_SMC			U(0x17)
+#define EC_AARCH64_SYS			U(0x18)
+#define EC_IABORT_LOWER_EL		U(0x20)
+#define EC_IABORT_CUR_EL		U(0x21)
+#define EC_PC_ALIGN			U(0x22)
+#define EC_DABORT_LOWER_EL		U(0x24)
+#define EC_DABORT_CUR_EL		U(0x25)
+#define EC_SP_ALIGN			U(0x26)
+#define EC_AARCH32_FP			U(0x28)
+#define EC_AARCH64_FP			U(0x2c)
+#define EC_SERROR			U(0x2f)
+
+/*
+ * External Abort bit in Instruction and Data Aborts synchronous exception
+ * syndromes.
+ */
+#define ESR_ISS_EABORT_EA_BIT		U(9)
+
+#define EC_BITS(x)			(((x) >> ESR_EC_SHIFT) & ESR_EC_MASK)
+
+/* Reset bit inside the Reset management register for EL3 (RMR_EL3) */
+#define RMR_RESET_REQUEST_SHIFT 	U(0x1)
+#define RMR_WARM_RESET_CPU		(U(1) << RMR_RESET_REQUEST_SHIFT)
+
+/*******************************************************************************
+ * Definitions of register offsets, fields and macros for CPU system
+ * instructions.
+ ******************************************************************************/
+
+#define TLBI_ADDR_SHIFT		U(12)
+#define TLBI_ADDR_MASK		ULL(0x00000FFFFFFFFFFF)
+#define TLBI_ADDR(x)		(((x) >> TLBI_ADDR_SHIFT) & TLBI_ADDR_MASK)
+
+/*******************************************************************************
+ * Definitions of register offsets and fields in the CNTCTLBase Frame of the
+ * system level implementation of the Generic Timer.
+ ******************************************************************************/
+#define CNTCTLBASE_CNTFRQ	U(0x0)
+#define CNTNSAR			U(0x4)
+#define CNTNSAR_NS_SHIFT(x)	(x)
+
+#define CNTACR_BASE(x)		(U(0x40) + ((x) << 2))
+#define CNTACR_RPCT_SHIFT	U(0x0)
+#define CNTACR_RVCT_SHIFT	U(0x1)
+#define CNTACR_RFRQ_SHIFT	U(0x2)
+#define CNTACR_RVOFF_SHIFT	U(0x3)
+#define CNTACR_RWVT_SHIFT	U(0x4)
+#define CNTACR_RWPT_SHIFT	U(0x5)
+
+/*******************************************************************************
+ * Definitions of register offsets and fields in the CNTBaseN Frame of the
+ * system level implementation of the Generic Timer.
+ ******************************************************************************/
+/* Physical Count register. */
+#define CNTPCT_LO		U(0x0)
+/* Counter Frequency register. */
+#define CNTBASEN_CNTFRQ		U(0x10)
+/* Physical Timer CompareValue register. */
+#define CNTP_CVAL_LO		U(0x20)
+/* Physical Timer Control register. */
+#define CNTP_CTL		U(0x2c)
+
+/* PMCR_EL0 definitions */
+#define PMCR_EL0_RESET_VAL	U(0x0)
+#define PMCR_EL0_N_SHIFT	U(11)
+#define PMCR_EL0_N_MASK		U(0x1f)
+#define PMCR_EL0_N_BITS		(PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT)
+#define PMCR_EL0_LC_BIT		(U(1) << 6)
+#define PMCR_EL0_DP_BIT		(U(1) << 5)
+#define PMCR_EL0_X_BIT		(U(1) << 4)
+#define PMCR_EL0_D_BIT		(U(1) << 3)
+
+/*******************************************************************************
+ * Definitions for system register interface to SVE
+ ******************************************************************************/
+#define ZCR_EL3			S3_6_C1_C2_0
+#define ZCR_EL2			S3_4_C1_C2_0
+
+/* ZCR_EL3 definitions */
+#define ZCR_EL3_LEN_MASK	U(0xf)
+
+/* ZCR_EL2 definitions */
+#define ZCR_EL2_LEN_MASK	U(0xf)
+
+/*******************************************************************************
+ * Definitions of MAIR encodings for device and normal memory
+ ******************************************************************************/
+/*
+ * MAIR encodings for device memory attributes.
+ */
+#define MAIR_DEV_nGnRnE		ULL(0x0)
+#define MAIR_DEV_nGnRE		ULL(0x4)
+#define MAIR_DEV_nGRE		ULL(0x8)
+#define MAIR_DEV_GRE		ULL(0xc)
+
+/*
+ * MAIR encodings for normal memory attributes.
+ *
+ * Cache Policy
+ *  WT:	 Write Through
+ *  WB:	 Write Back
+ *  NC:	 Non-Cacheable
+ *
+ * Transient Hint
+ *  NTR: Non-Transient
+ *  TR:	 Transient
+ *
+ * Allocation Policy
+ *  RA:	 Read Allocate
+ *  WA:	 Write Allocate
+ *  RWA: Read and Write Allocate
+ *  NA:	 No Allocation
+ */
+#define MAIR_NORM_WT_TR_WA	ULL(0x1)
+#define MAIR_NORM_WT_TR_RA	ULL(0x2)
+#define MAIR_NORM_WT_TR_RWA	ULL(0x3)
+#define MAIR_NORM_NC		ULL(0x4)
+#define MAIR_NORM_WB_TR_WA	ULL(0x5)
+#define MAIR_NORM_WB_TR_RA	ULL(0x6)
+#define MAIR_NORM_WB_TR_RWA	ULL(0x7)
+#define MAIR_NORM_WT_NTR_NA	ULL(0x8)
+#define MAIR_NORM_WT_NTR_WA	ULL(0x9)
+#define MAIR_NORM_WT_NTR_RA	ULL(0xa)
+#define MAIR_NORM_WT_NTR_RWA	ULL(0xb)
+#define MAIR_NORM_WB_NTR_NA	ULL(0xc)
+#define MAIR_NORM_WB_NTR_WA	ULL(0xd)
+#define MAIR_NORM_WB_NTR_RA	ULL(0xe)
+#define MAIR_NORM_WB_NTR_RWA	ULL(0xf)
+
+#define MAIR_NORM_OUTER_SHIFT	U(4)
+
+#define MAKE_MAIR_NORMAL_MEMORY(inner, outer)	\
+		((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
+
+/* PAR_EL1 fields */
+#define PAR_F_SHIFT	U(0)
+#define PAR_F_MASK	ULL(0x1)
+#define PAR_ADDR_SHIFT	U(12)
+#define PAR_ADDR_MASK	(BIT(40) - ULL(1)) /* 40-bits-wide page address */
+
+/*******************************************************************************
+ * Definitions for system register interface to SPE
+ ******************************************************************************/
+#define PMBLIMITR_EL1		S3_0_C9_C10_0
+
+/*******************************************************************************
+ * Definitions for system register interface to MPAM
+ ******************************************************************************/
+#define MPAMIDR_EL1		S3_0_C10_C4_4
+#define MPAM2_EL2		S3_4_C10_C5_0
+#define MPAMHCR_EL2		S3_4_C10_C4_0
+#define MPAM3_EL3		S3_6_C10_C5_0
+
+/*******************************************************************************
+ * Definitions for system register interface to AMU for ARMv8.4 onwards
+ ******************************************************************************/
+#define AMCR_EL0		S3_3_C13_C2_0
+#define AMCFGR_EL0		S3_3_C13_C2_1
+#define AMCGCR_EL0		S3_3_C13_C2_2
+#define AMUSERENR_EL0		S3_3_C13_C2_3
+#define AMCNTENCLR0_EL0		S3_3_C13_C2_4
+#define AMCNTENSET0_EL0		S3_3_C13_C2_5
+#define AMCNTENCLR1_EL0		S3_3_C13_C3_0
+#define AMCNTENSET1_EL0		S3_3_C13_C3_1
+
+/* Activity Monitor Group 0 Event Counter Registers */
+#define AMEVCNTR00_EL0		S3_3_C13_C4_0
+#define AMEVCNTR01_EL0		S3_3_C13_C4_1
+#define AMEVCNTR02_EL0		S3_3_C13_C4_2
+#define AMEVCNTR03_EL0		S3_3_C13_C4_3
+
+/* Activity Monitor Group 0 Event Type Registers */
+#define AMEVTYPER00_EL0		S3_3_C13_C6_0
+#define AMEVTYPER01_EL0		S3_3_C13_C6_1
+#define AMEVTYPER02_EL0		S3_3_C13_C6_2
+#define AMEVTYPER03_EL0		S3_3_C13_C6_3
+
+/* Activity Monitor Group 1 Event Counter Registers */
+#define AMEVCNTR10_EL0		S3_3_C13_C12_0
+#define AMEVCNTR11_EL0		S3_3_C13_C12_1
+#define AMEVCNTR12_EL0		S3_3_C13_C12_2
+#define AMEVCNTR13_EL0		S3_3_C13_C12_3
+#define AMEVCNTR14_EL0		S3_3_C13_C12_4
+#define AMEVCNTR15_EL0		S3_3_C13_C12_5
+#define AMEVCNTR16_EL0		S3_3_C13_C12_6
+#define AMEVCNTR17_EL0		S3_3_C13_C12_7
+#define AMEVCNTR18_EL0		S3_3_C13_C13_0
+#define AMEVCNTR19_EL0		S3_3_C13_C13_1
+#define AMEVCNTR1A_EL0		S3_3_C13_C13_2
+#define AMEVCNTR1B_EL0		S3_3_C13_C13_3
+#define AMEVCNTR1C_EL0		S3_3_C13_C13_4
+#define AMEVCNTR1D_EL0		S3_3_C13_C13_5
+#define AMEVCNTR1E_EL0		S3_3_C13_C13_6
+#define AMEVCNTR1F_EL0		S3_3_C13_C13_7
+
+/* Activity Monitor Group 1 Event Type Registers */
+#define AMEVTYPER10_EL0		S3_3_C13_C14_0
+#define AMEVTYPER11_EL0		S3_3_C13_C14_1
+#define AMEVTYPER12_EL0		S3_3_C13_C14_2
+#define AMEVTYPER13_EL0		S3_3_C13_C14_3
+#define AMEVTYPER14_EL0		S3_3_C13_C14_4
+#define AMEVTYPER15_EL0		S3_3_C13_C14_5
+#define AMEVTYPER16_EL0		S3_3_C13_C14_6
+#define AMEVTYPER17_EL0		S3_3_C13_C14_7
+#define AMEVTYPER18_EL0		S3_3_C13_C15_0
+#define AMEVTYPER19_EL0		S3_3_C13_C15_1
+#define AMEVTYPER1A_EL0		S3_3_C13_C15_2
+#define AMEVTYPER1B_EL0		S3_3_C13_C15_3
+#define AMEVTYPER1C_EL0		S3_3_C13_C15_4
+#define AMEVTYPER1D_EL0		S3_3_C13_C15_5
+#define AMEVTYPER1E_EL0		S3_3_C13_C15_6
+#define AMEVTYPER1F_EL0		S3_3_C13_C15_7
+
+/* AMCGCR_EL0 definitions */
+#define AMCGCR_EL0_CG1NC_SHIFT	U(8)
+#define AMCGCR_EL0_CG1NC_LENGTH	U(8)
+#define AMCGCR_EL0_CG1NC_MASK	U(0xff)
+
+/* MPAM register definitions */
+#define MPAM3_EL3_MPAMEN_BIT		(ULL(1) << 63)
+#define MPAMHCR_EL2_TRAP_MPAMIDR_EL1	(ULL(1) << 31)
+
+#define MPAM2_EL2_TRAPMPAM0EL1		(ULL(1) << 49)
+#define MPAM2_EL2_TRAPMPAM1EL1		(ULL(1) << 48)
+
+#define MPAMIDR_HAS_HCR_BIT		(ULL(1) << 17)
+
+/*******************************************************************************
+ * RAS system registers
+ ******************************************************************************/
+#define DISR_EL1		S3_0_C12_C1_1
+#define DISR_A_BIT		U(31)
+
+#define ERRIDR_EL1		S3_0_C5_C3_0
+#define ERRIDR_MASK		U(0xffff)
+
+#define ERRSELR_EL1		S3_0_C5_C3_1
+
+/* System register access to Standard Error Record registers */
+#define ERXFR_EL1		S3_0_C5_C4_0
+#define ERXCTLR_EL1		S3_0_C5_C4_1
+#define ERXSTATUS_EL1		S3_0_C5_C4_2
+#define ERXADDR_EL1		S3_0_C5_C4_3
+#define ERXPFGF_EL1		S3_0_C5_C4_4
+#define ERXPFGCTL_EL1		S3_0_C5_C4_5
+#define ERXPFGCDN_EL1		S3_0_C5_C4_6
+#define ERXMISC0_EL1		S3_0_C5_C5_0
+#define ERXMISC1_EL1		S3_0_C5_C5_1
+
+#define ERXCTLR_ED_BIT		(U(1) << 0)
+#define ERXCTLR_UE_BIT		(U(1) << 4)
+
+#define ERXPFGCTL_UC_BIT	(U(1) << 1)
+#define ERXPFGCTL_UEU_BIT	(U(1) << 2)
+#define ERXPFGCTL_CDEN_BIT	(U(1) << 31)
+
+/*******************************************************************************
+ * Armv8.3 Pointer Authentication Registers
+ ******************************************************************************/
+#define APIAKeyLo_EL1		S3_0_C2_C1_0
+#define APIAKeyHi_EL1		S3_0_C2_C1_1
+#define APIBKeyLo_EL1		S3_0_C2_C1_2
+#define APIBKeyHi_EL1		S3_0_C2_C1_3
+#define APDAKeyLo_EL1		S3_0_C2_C2_0
+#define APDAKeyHi_EL1		S3_0_C2_C2_1
+#define APDBKeyLo_EL1		S3_0_C2_C2_2
+#define APDBKeyHi_EL1		S3_0_C2_C2_3
+#define APGAKeyLo_EL1		S3_0_C2_C3_0
+#define APGAKeyHi_EL1		S3_0_C2_C3_1
+
+/*******************************************************************************
+ * Armv8.4 Data Independent Timing Registers
+ ******************************************************************************/
+#define DIT			S3_3_C4_C2_5
+#define DIT_BIT			BIT(24)
+
+/*******************************************************************************
+ * Armv8.5 - new MSR encoding to directly access PSTATE.SSBS field
+ ******************************************************************************/
+#define SSBS			S3_3_C4_C2_6
+
+#endif /* ARCH_H */
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
new file mode 100644
index 0000000..2f29f48
--- /dev/null
+++ b/include/arch/aarch64/arch_features.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_FEATURES_H
+#define ARCH_FEATURES_H
+
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+
+static inline bool is_armv7_gentimer_present(void)
+{
+	/* The Generic Timer is always present in an ARMv8-A implementation */
+	return true;
+}
+
+static inline bool is_armv8_2_ttcnp_present(void)
+{
+	return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_CNP_SHIFT) &
+		ID_AA64MMFR2_EL1_CNP_MASK) != 0U;
+}
+
+static inline bool is_armv8_3_pauth_present(void)
+{
+	uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
+			(ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) |
+			(ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
+			(ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
+
+	/* If any of the fields is not zero, PAuth is present */
+	return (read_id_aa64isar1_el1() & mask) != 0U;
+}
+
+static inline bool is_armv8_3_pauth_apa_api_present(void)
+{
+	uint64_t mask = (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) |
+			(ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT);
+
+	return (read_id_aa64isar1_el1() & mask) != 0U;
+}
+
+static inline bool is_armv8_4_ttst_present(void)
+{
+	return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) &
+		ID_AA64MMFR2_EL1_ST_MASK) == 1U;
+}
+
+static inline bool is_armv8_5_bti_present(void)
+{
+	return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_BT_SHIFT) &
+		ID_AA64PFR1_EL1_BT_MASK) == BTI_IMPLEMENTED;
+}
+
+static inline unsigned int get_armv8_5_mte_support(void)
+{
+	return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_MTE_SHIFT) &
+		ID_AA64PFR1_EL1_MTE_MASK);
+}
+
+#endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
new file mode 100644
index 0000000..c173706
--- /dev/null
+++ b/include/arch/aarch64/arch_helpers.h
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_HELPERS_H
+#define ARCH_HELPERS_H
+
+#include <cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch.h>
+
+/**********************************************************************
+ * Macros which create inline functions to read or write CPU system
+ * registers
+ *********************************************************************/
+
+#define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name)		\
+static inline u_register_t read_ ## _name(void)			\
+{								\
+	u_register_t v;						\
+	__asm__ volatile ("mrs %0, " #_reg_name : "=r" (v));	\
+	return v;						\
+}
+
+#define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)			\
+static inline void write_ ## _name(u_register_t v)			\
+{									\
+	__asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v));	\
+}
+
+#define SYSREG_WRITE_CONST(reg_name, v)				\
+	__asm__ volatile ("msr " #reg_name ", %0" : : "i" (v))
+
+/* Define read function for system register */
+#define DEFINE_SYSREG_READ_FUNC(_name) 			\
+	_DEFINE_SYSREG_READ_FUNC(_name, _name)
+
+/* Define read & write function for system register */
+#define DEFINE_SYSREG_RW_FUNCS(_name)			\
+	_DEFINE_SYSREG_READ_FUNC(_name, _name)		\
+	_DEFINE_SYSREG_WRITE_FUNC(_name, _name)
+
+/* Define read & write function for renamed system register */
+#define DEFINE_RENAME_SYSREG_RW_FUNCS(_name, _reg_name)	\
+	_DEFINE_SYSREG_READ_FUNC(_name, _reg_name)	\
+	_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
+
+/* Define read function for renamed system register */
+#define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name)	\
+	_DEFINE_SYSREG_READ_FUNC(_name, _reg_name)
+
+/* Define write function for renamed system register */
+#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name)	\
+	_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
+
+/**********************************************************************
+ * Macros to create inline functions for system instructions
+ *********************************************************************/
+
+/* Define function for simple system instruction */
+#define DEFINE_SYSOP_FUNC(_op)				\
+static inline void _op(void)				\
+{							\
+	__asm__ (#_op);					\
+}
+
+/* Define function for system instruction with type specifier */
+#define DEFINE_SYSOP_TYPE_FUNC(_op, _type)		\
+static inline void _op ## _type(void)			\
+{							\
+	__asm__ (#_op " " #_type);			\
+}
+
+/* Define function for system instruction with register parameter */
+#define DEFINE_SYSOP_TYPE_PARAM_FUNC(_op, _type)	\
+static inline void _op ## _type(uint64_t v)		\
+{							\
+	 __asm__ (#_op " " #_type ", %0" : : "r" (v));	\
+}
+
+/*******************************************************************************
+ * TLB maintenance accessor prototypes
+ ******************************************************************************/
+
+#if ERRATA_A57_813419 || ERRATA_A76_1286807
+/*
+ * Define function for TLBI instruction with type specifier that implements
+ * the workaround for errata 813419 of Cortex-A57 or errata 1286807 of
+ * Cortex-A76.
+ */
+#define DEFINE_TLBIOP_ERRATA_TYPE_FUNC(_type)\
+static inline void tlbi ## _type(void)			\
+{							\
+	__asm__("tlbi " #_type "\n"			\
+		"dsb ish\n"				\
+		"tlbi " #_type);			\
+}
+
+/*
+ * Define function for TLBI instruction with register parameter that implements
+ * the workaround for errata 813419 of Cortex-A57 or errata 1286807 of
+ * Cortex-A76.
+ */
+#define DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(_type)	\
+static inline void tlbi ## _type(uint64_t v)			\
+{								\
+	__asm__("tlbi " #_type ", %0\n"				\
+		"dsb ish\n"					\
+		"tlbi " #_type ", %0" : : "r" (v));		\
+}
+#endif /* ERRATA_A57_813419 */
+
+#if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319
+/*
+ * Define function for DC instruction with register parameter that enables
+ * the workaround for errata 819472, 824069 and 827319 of Cortex-A53.
+ */
+#define DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(_name, _type)	\
+static inline void dc ## _name(uint64_t v)			\
+{								\
+	__asm__("dc " #_type ", %0" : : "r" (v));		\
+}
+#endif /* ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319 */
+
+#if ERRATA_A57_813419
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1is)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2is)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3is)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, vmalle1)
+#elif ERRATA_A76_1286807
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle1)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle1is)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle2)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle2is)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3is)
+DEFINE_TLBIOP_ERRATA_TYPE_FUNC(vmalle1)
+#else
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1is)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2is)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle3)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, alle3is)
+DEFINE_SYSOP_TYPE_FUNC(tlbi, vmalle1)
+#endif
+
+#if ERRATA_A57_813419
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaae1is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaale1is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae2is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale2is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vae3is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vale3is)
+#elif ERRATA_A76_1286807
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vaae1is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vaale1is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vae2is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vale2is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vae3is)
+DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vale3is)
+#else
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaae1is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaale1is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae2is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale2is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae3is)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale3is)
+#endif
+
+/*******************************************************************************
+ * Cache maintenance accessor prototypes
+ ******************************************************************************/
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, isw)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cisw)
+#if ERRATA_A53_827319
+DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(csw, cisw)
+#else
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, csw)
+#endif
+#if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319
+DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(cvac, civac)
+#else
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvac)
+#endif
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, ivac)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, civac)
+#if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319
+DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(cvau, civac)
+#else
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvau)
+#endif
+DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, zva)
+
+/*******************************************************************************
+ * Address translation accessor prototypes
+ ******************************************************************************/
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1r)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1w)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0r)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0w)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e1r)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e2r)
+DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e3r)
+
+void flush_dcache_range(uintptr_t addr, size_t size);
+void clean_dcache_range(uintptr_t addr, size_t size);
+void inv_dcache_range(uintptr_t addr, size_t size);
+
+void dcsw_op_louis(u_register_t op_type);
+void dcsw_op_all(u_register_t op_type);
+
+void disable_mmu_el1(void);
+void disable_mmu_el3(void);
+void disable_mmu_icache_el1(void);
+void disable_mmu_icache_el3(void);
+
+/*******************************************************************************
+ * Misc. accessor prototypes
+ ******************************************************************************/
+
+#define write_daifclr(val) SYSREG_WRITE_CONST(daifclr, val)
+#define write_daifset(val) SYSREG_WRITE_CONST(daifset, val)
+
+DEFINE_SYSREG_RW_FUNCS(par_el1)
+DEFINE_SYSREG_READ_FUNC(id_pfr1_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64isar1_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64pfr1_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64dfr0_el1)
+DEFINE_SYSREG_READ_FUNC(id_afr0_el1)
+DEFINE_SYSREG_READ_FUNC(CurrentEl)
+DEFINE_SYSREG_READ_FUNC(ctr_el0)
+DEFINE_SYSREG_RW_FUNCS(daif)
+DEFINE_SYSREG_RW_FUNCS(spsr_el1)
+DEFINE_SYSREG_RW_FUNCS(spsr_el2)
+DEFINE_SYSREG_RW_FUNCS(spsr_el3)
+DEFINE_SYSREG_RW_FUNCS(elr_el1)
+DEFINE_SYSREG_RW_FUNCS(elr_el2)
+DEFINE_SYSREG_RW_FUNCS(elr_el3)
+
+DEFINE_SYSOP_FUNC(wfi)
+DEFINE_SYSOP_FUNC(wfe)
+DEFINE_SYSOP_FUNC(sev)
+DEFINE_SYSOP_TYPE_FUNC(dsb, sy)
+DEFINE_SYSOP_TYPE_FUNC(dmb, sy)
+DEFINE_SYSOP_TYPE_FUNC(dmb, st)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ld)
+DEFINE_SYSOP_TYPE_FUNC(dsb, ish)
+DEFINE_SYSOP_TYPE_FUNC(dsb, nsh)
+DEFINE_SYSOP_TYPE_FUNC(dsb, ishst)
+DEFINE_SYSOP_TYPE_FUNC(dmb, oshld)
+DEFINE_SYSOP_TYPE_FUNC(dmb, oshst)
+DEFINE_SYSOP_TYPE_FUNC(dmb, osh)
+DEFINE_SYSOP_TYPE_FUNC(dmb, nshld)
+DEFINE_SYSOP_TYPE_FUNC(dmb, nshst)
+DEFINE_SYSOP_TYPE_FUNC(dmb, nsh)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishld)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ishst)
+DEFINE_SYSOP_TYPE_FUNC(dmb, ish)
+DEFINE_SYSOP_FUNC(isb)
+
+static inline void enable_irq(void)
+{
+	/*
+	 * The compiler memory barrier will prevent the compiler from
+	 * scheduling non-volatile memory access after the write to the
+	 * register.
+	 *
+	 * This could happen if some initialization code issues non-volatile
+	 * accesses to an area used by an interrupt handler, in the assumption
+	 * that it is safe as the interrupts are disabled at the time it does
+	 * that (according to program order). However, non-volatile accesses
+	 * are not necessarily in program order relatively with volatile inline
+	 * assembly statements (and volatile accesses).
+	 */
+	COMPILER_BARRIER();
+	write_daifclr(DAIF_IRQ_BIT);
+	isb();
+}
+
+static inline void enable_fiq(void)
+{
+	COMPILER_BARRIER();
+	write_daifclr(DAIF_FIQ_BIT);
+	isb();
+}
+
+static inline void enable_serror(void)
+{
+	COMPILER_BARRIER();
+	write_daifclr(DAIF_ABT_BIT);
+	isb();
+}
+
+static inline void enable_debug_exceptions(void)
+{
+	COMPILER_BARRIER();
+	write_daifclr(DAIF_DBG_BIT);
+	isb();
+}
+
+static inline void disable_irq(void)
+{
+	COMPILER_BARRIER();
+	write_daifset(DAIF_IRQ_BIT);
+	isb();
+}
+
+static inline void disable_fiq(void)
+{
+	COMPILER_BARRIER();
+	write_daifset(DAIF_FIQ_BIT);
+	isb();
+}
+
+static inline void disable_serror(void)
+{
+	COMPILER_BARRIER();
+	write_daifset(DAIF_ABT_BIT);
+	isb();
+}
+
+static inline void disable_debug_exceptions(void)
+{
+	COMPILER_BARRIER();
+	write_daifset(DAIF_DBG_BIT);
+	isb();
+}
+
+void __dead2 smc(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3,
+		 uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7);
+
+/*******************************************************************************
+ * System register accessor prototypes
+ ******************************************************************************/
+DEFINE_SYSREG_READ_FUNC(midr_el1)
+DEFINE_SYSREG_READ_FUNC(mpidr_el1)
+DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1)
+
+DEFINE_SYSREG_RW_FUNCS(scr_el3)
+DEFINE_SYSREG_RW_FUNCS(hcr_el2)
+
+DEFINE_SYSREG_RW_FUNCS(vbar_el1)
+DEFINE_SYSREG_RW_FUNCS(vbar_el2)
+DEFINE_SYSREG_RW_FUNCS(vbar_el3)
+
+DEFINE_SYSREG_RW_FUNCS(sctlr_el1)
+DEFINE_SYSREG_RW_FUNCS(sctlr_el2)
+DEFINE_SYSREG_RW_FUNCS(sctlr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(actlr_el1)
+DEFINE_SYSREG_RW_FUNCS(actlr_el2)
+DEFINE_SYSREG_RW_FUNCS(actlr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(esr_el1)
+DEFINE_SYSREG_RW_FUNCS(esr_el2)
+DEFINE_SYSREG_RW_FUNCS(esr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(afsr0_el1)
+DEFINE_SYSREG_RW_FUNCS(afsr0_el2)
+DEFINE_SYSREG_RW_FUNCS(afsr0_el3)
+
+DEFINE_SYSREG_RW_FUNCS(afsr1_el1)
+DEFINE_SYSREG_RW_FUNCS(afsr1_el2)
+DEFINE_SYSREG_RW_FUNCS(afsr1_el3)
+
+DEFINE_SYSREG_RW_FUNCS(far_el1)
+DEFINE_SYSREG_RW_FUNCS(far_el2)
+DEFINE_SYSREG_RW_FUNCS(far_el3)
+
+DEFINE_SYSREG_RW_FUNCS(mair_el1)
+DEFINE_SYSREG_RW_FUNCS(mair_el2)
+DEFINE_SYSREG_RW_FUNCS(mair_el3)
+
+DEFINE_SYSREG_RW_FUNCS(amair_el1)
+DEFINE_SYSREG_RW_FUNCS(amair_el2)
+DEFINE_SYSREG_RW_FUNCS(amair_el3)
+
+DEFINE_SYSREG_READ_FUNC(rvbar_el1)
+DEFINE_SYSREG_READ_FUNC(rvbar_el2)
+DEFINE_SYSREG_READ_FUNC(rvbar_el3)
+
+DEFINE_SYSREG_RW_FUNCS(rmr_el1)
+DEFINE_SYSREG_RW_FUNCS(rmr_el2)
+DEFINE_SYSREG_RW_FUNCS(rmr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(tcr_el1)
+DEFINE_SYSREG_RW_FUNCS(tcr_el2)
+DEFINE_SYSREG_RW_FUNCS(tcr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(ttbr0_el1)
+DEFINE_SYSREG_RW_FUNCS(ttbr0_el2)
+DEFINE_SYSREG_RW_FUNCS(ttbr0_el3)
+
+DEFINE_SYSREG_RW_FUNCS(ttbr1_el1)
+
+DEFINE_SYSREG_RW_FUNCS(vttbr_el2)
+
+DEFINE_SYSREG_RW_FUNCS(cptr_el2)
+DEFINE_SYSREG_RW_FUNCS(cptr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(cpacr_el1)
+DEFINE_SYSREG_RW_FUNCS(cntfrq_el0)
+DEFINE_SYSREG_RW_FUNCS(cnthp_ctl_el2)
+DEFINE_SYSREG_RW_FUNCS(cnthp_tval_el2)
+DEFINE_SYSREG_RW_FUNCS(cnthp_cval_el2)
+DEFINE_SYSREG_RW_FUNCS(cntps_ctl_el1)
+DEFINE_SYSREG_RW_FUNCS(cntps_tval_el1)
+DEFINE_SYSREG_RW_FUNCS(cntps_cval_el1)
+DEFINE_SYSREG_RW_FUNCS(cntp_ctl_el0)
+DEFINE_SYSREG_RW_FUNCS(cntp_tval_el0)
+DEFINE_SYSREG_RW_FUNCS(cntp_cval_el0)
+DEFINE_SYSREG_READ_FUNC(cntpct_el0)
+DEFINE_SYSREG_RW_FUNCS(cnthctl_el2)
+
+#define get_cntp_ctl_enable(x)  (((x) >> CNTP_CTL_ENABLE_SHIFT) & \
+					CNTP_CTL_ENABLE_MASK)
+#define get_cntp_ctl_imask(x)   (((x) >> CNTP_CTL_IMASK_SHIFT) & \
+					CNTP_CTL_IMASK_MASK)
+#define get_cntp_ctl_istatus(x) (((x) >> CNTP_CTL_ISTATUS_SHIFT) & \
+					CNTP_CTL_ISTATUS_MASK)
+
+#define set_cntp_ctl_enable(x)  ((x) |= (U(1) << CNTP_CTL_ENABLE_SHIFT))
+#define set_cntp_ctl_imask(x)   ((x) |= (U(1) << CNTP_CTL_IMASK_SHIFT))
+
+#define clr_cntp_ctl_enable(x)  ((x) &= ~(U(1) << CNTP_CTL_ENABLE_SHIFT))
+#define clr_cntp_ctl_imask(x)   ((x) &= ~(U(1) << CNTP_CTL_IMASK_SHIFT))
+
+DEFINE_SYSREG_RW_FUNCS(tpidr_el3)
+
+DEFINE_SYSREG_RW_FUNCS(cntvoff_el2)
+
+DEFINE_SYSREG_RW_FUNCS(vpidr_el2)
+DEFINE_SYSREG_RW_FUNCS(vmpidr_el2)
+
+DEFINE_SYSREG_READ_FUNC(isr_el1)
+
+DEFINE_SYSREG_RW_FUNCS(mdcr_el2)
+DEFINE_SYSREG_RW_FUNCS(mdcr_el3)
+DEFINE_SYSREG_RW_FUNCS(hstr_el2)
+DEFINE_SYSREG_RW_FUNCS(pmcr_el0)
+
+/* GICv3 System Registers */
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_rpr_el1, ICC_RPR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el1, ICC_IGRPEN1_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sgi1r, ICC_SGI1R)
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcgcr_el0, AMCGCR_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr0_el0, AMCNTENCLR0_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset0_el0, AMCNTENSET0_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0)
+DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset1_el0, AMCNTENSET1_EL0)
+
+DEFINE_RENAME_SYSREG_READ_FUNC(mpamidr_el1, MPAMIDR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpam2_el2, MPAM2_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(mpamhcr_el2, MPAMHCR_EL2)
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1)
+
+DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
+
+DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
+DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1)
+
+DEFINE_RENAME_SYSREG_READ_FUNC(erxfr_el1, ERXFR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(erxctlr_el1, ERXCTLR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(erxstatus_el1, ERXSTATUS_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(erxaddr_el1, ERXADDR_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc0_el1, ERXMISC0_EL1)
+DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1)
+
+/* Armv8.2 Registers */
+DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
+
+/* Armv8.3 Pointer Authentication Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeyhi_el1, APIAKeyHi_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeylo_el1, APIAKeyLo_EL1)
+
+#define IS_IN_EL(x) \
+	(GET_EL(read_CurrentEl()) == MODE_EL##x)
+
+#define IS_IN_EL1() IS_IN_EL(1)
+#define IS_IN_EL2() IS_IN_EL(2)
+#define IS_IN_EL3() IS_IN_EL(3)
+
+static inline unsigned int get_current_el(void)
+{
+	return GET_EL(read_CurrentEl());
+}
+
+/*
+ * Check if an EL is implemented from AA64PFR0 register fields.
+ */
+static inline uint64_t el_implemented(unsigned int el)
+{
+	if (el > 3U) {
+		return EL_IMPL_NONE;
+	} else {
+		unsigned int shift = ID_AA64PFR0_EL1_SHIFT * el;
+
+		return (read_id_aa64pfr0_el1() >> shift) & ID_AA64PFR0_ELX_MASK;
+	}
+}
+
+/* Previously defined accesor functions with incomplete register names  */
+
+#define read_current_el()	read_CurrentEl()
+
+#define dsb()			dsbsy()
+
+#define read_midr()		read_midr_el1()
+
+#define read_mpidr()		read_mpidr_el1()
+
+#define read_scr()		read_scr_el3()
+#define write_scr(_v)		write_scr_el3(_v)
+
+#define read_hcr()		read_hcr_el2()
+#define write_hcr(_v)		write_hcr_el2(_v)
+
+#define read_cpacr()		read_cpacr_el1()
+#define write_cpacr(_v)		write_cpacr_el1(_v)
+
+#endif /* ARCH_HELPERS_H */
diff --git a/include/arch/aarch64/asm_macros.S b/include/arch/aarch64/asm_macros.S
new file mode 100644
index 0000000..79e0ad7
--- /dev/null
+++ b/include/arch/aarch64/asm_macros.S
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ASM_MACROS_S
+#define ASM_MACROS_S
+
+#include <arch.h>
+#include <common/asm_macros_common.S>
+#include <lib/spinlock.h>
+
+#if ENABLE_BTI && !ARM_ARCH_AT_LEAST(8, 5)
+#error Branch Target Identification requires ARM_ARCH_MINOR >= 5
+#endif
+
+/*
+ * TLBI instruction with type specifier that implements the workaround for
+ * errata 813419 of Cortex-A57 or errata 1286807 of Cortex-A76.
+ */
+#if ERRATA_A57_813419 || ERRATA_A76_1286807
+#define TLB_INVALIDATE(_type) \
+	tlbi	_type; \
+	dsb	ish; \
+	tlbi	_type
+#else
+#define TLB_INVALIDATE(_type) \
+	tlbi	_type
+#endif
+
+
+	.macro	func_prologue
+	stp	x29, x30, [sp, #-0x10]!
+	mov	x29,sp
+	.endm
+
+	.macro	func_epilogue
+	ldp	x29, x30, [sp], #0x10
+	.endm
+
+
+	.macro	dcache_line_size  reg, tmp
+	mrs	\tmp, ctr_el0
+	ubfx	\tmp, \tmp, #16, #4
+	mov	\reg, #4
+	lsl	\reg, \reg, \tmp
+	.endm
+
+
+	.macro	icache_line_size  reg, tmp
+	mrs	\tmp, ctr_el0
+	and	\tmp, \tmp, #0xf
+	mov	\reg, #4
+	lsl	\reg, \reg, \tmp
+	.endm
+
+
+	.macro	smc_check  label
+	mrs	x0, esr_el3
+	ubfx	x0, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+	cmp	x0, #EC_AARCH64_SMC
+	b.ne	$label
+	.endm
+
+	/*
+	 * Declare the exception vector table, enforcing it is aligned on a
+	 * 2KB boundary, as required by the ARMv8 architecture.
+	 * Use zero bytes as the fill value to be stored in the padding bytes
+	 * so that it inserts illegal AArch64 instructions. This increases
+	 * security, robustness and potentially facilitates debugging.
+	 */
+	.macro vector_base  label, section_name=.vectors
+	.section \section_name, "ax"
+	.align 11, 0
+	\label:
+	.endm
+
+	/*
+	 * Create an entry in the exception vector table, enforcing it is
+	 * aligned on a 128-byte boundary, as required by the ARMv8 architecture.
+	 * Use zero bytes as the fill value to be stored in the padding bytes
+	 * so that it inserts illegal AArch64 instructions. This increases
+	 * security, robustness and potentially facilitates debugging.
+	 */
+	.macro vector_entry  label, section_name=.vectors
+	.cfi_sections .debug_frame
+	.section \section_name, "ax"
+	.align 7, 0
+	.type \label, %function
+	.cfi_startproc
+	\label:
+	.endm
+
+	/*
+	 * Add the bytes until fill the full exception vector, whose size is always
+	 * 32 instructions. If there are more than 32 instructions in the
+	 * exception vector then an error is emitted.
+	 */
+	.macro end_vector_entry label
+	.cfi_endproc
+	.fill	\label + (32 * 4) - .
+	.endm
+
+	/*
+	 * This macro calculates the base address of the current CPU's MP stack
+	 * using the plat_my_core_pos() index, the name of the stack storage
+	 * and the size of each stack
+	 * Out: X0 = physical address of stack base
+	 * Clobber: X30, X1, X2
+	 */
+	.macro get_my_mp_stack _name, _size
+	bl	plat_my_core_pos
+	adrp	x2, (\_name + \_size)
+	add	x2, x2, :lo12:(\_name + \_size)
+	mov x1, #\_size
+	madd x0, x0, x1, x2
+	.endm
+
+	/*
+	 * This macro calculates the base address of a UP stack using the
+	 * name of the stack storage and the size of the stack
+	 * Out: X0 = physical address of stack base
+	 */
+	.macro get_up_stack _name, _size
+	adrp	x0, (\_name + \_size)
+	add	x0, x0, :lo12:(\_name + \_size)
+	.endm
+
+	/*
+	 * Helper macro to generate the best mov/movk combinations according
+	 * the value to be moved. The 16 bits from '_shift' are tested and
+	 * if not zero, they are moved into '_reg' without affecting
+	 * other bits.
+	 */
+	.macro _mov_imm16 _reg, _val, _shift
+		.if (\_val >> \_shift) & 0xffff
+			.if (\_val & (1 << \_shift - 1))
+				movk	\_reg, (\_val >> \_shift) & 0xffff, LSL \_shift
+			.else
+				mov	\_reg, \_val & (0xffff << \_shift)
+			.endif
+		.endif
+	.endm
+
+	/*
+	 * Helper macro to load arbitrary values into 32 or 64-bit registers
+	 * which generates the best mov/movk combinations. Many base addresses
+	 * are 64KB aligned the macro will eliminate updating bits 15:0 in
+	 * that case
+	 */
+	.macro mov_imm _reg, _val
+		.if (\_val) == 0
+			mov	\_reg, #0
+		.else
+			_mov_imm16	\_reg, (\_val), 0
+			_mov_imm16	\_reg, (\_val), 16
+			_mov_imm16	\_reg, (\_val), 32
+			_mov_imm16	\_reg, (\_val), 48
+		.endif
+	.endm
+
+	/*
+	 * Macro to mark instances where we're jumping to a function and don't
+	 * expect a return. To provide the function being jumped to with
+	 * additional information, we use 'bl' instruction to jump rather than
+	 * 'b'.
+         *
+	 * Debuggers infer the location of a call from where LR points to, which
+	 * is usually the instruction after 'bl'. If this macro expansion
+	 * happens to be the last location in a function, that'll cause the LR
+	 * to point a location beyond the function, thereby misleading debugger
+	 * back trace. We therefore insert a 'nop' after the function call for
+	 * debug builds, unless 'skip_nop' parameter is non-zero.
+	 */
+	.macro no_ret _func:req, skip_nop=0
+	bl	\_func
+#if DEBUG
+	.ifeq \skip_nop
+	nop
+	.endif
+#endif
+	.endm
+
+	/*
+	 * Reserve space for a spin lock in assembly file.
+	 */
+	.macro define_asm_spinlock _name:req
+	.align	SPINLOCK_ASM_ALIGN
+	\_name:
+	.space	SPINLOCK_ASM_SIZE
+	.endm
+
+#if RAS_EXTENSION
+	.macro esb
+	.inst	0xd503221f
+	.endm
+#endif
+
+	/*
+	 * Helper macro to read system register value into x0
+	 */
+	.macro	read reg:req
+#if ENABLE_BTI
+	bti	j
+#endif
+	mrs	x0, \reg
+	ret
+	.endm
+
+	/*
+	 * Helper macro to write value from x1 to system register
+	 */
+	.macro	write reg:req
+#if ENABLE_BTI
+	bti	j
+#endif
+	msr	\reg, x1
+	ret
+	.endm
+
+#endif /* ASM_MACROS_S */
diff --git a/include/arch/aarch64/assert_macros.S b/include/arch/aarch64/assert_macros.S
new file mode 100644
index 0000000..06371c4
--- /dev/null
+++ b/include/arch/aarch64/assert_macros.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ASSERT_MACROS_S
+#define ASSERT_MACROS_S
+
+	/*
+	 * Assembler macro to enable asm_assert. Use this macro wherever
+	 * assert is required in assembly. Please note that the macro makes
+	 * use of label '300' to provide the logic and the caller
+	 * should make sure that this label is not used to branch prior
+	 * to calling this macro.
+	 */
+#define ASM_ASSERT(_cc) \
+.ifndef .L_assert_filename ;\
+	.pushsection .rodata.str1.1, "aS" ;\
+	.L_assert_filename: ;\
+			.string	__FILE__ ;\
+	.popsection ;\
+.endif ;\
+	b._cc	300f ;\
+	adr	x0, .L_assert_filename ;\
+	mov	x1, __LINE__ ;\
+	b	asm_assert ;\
+300:
+
+#endif /* ASSERT_MACROS_S */
diff --git a/include/arch/aarch64/console_macros.S b/include/arch/aarch64/console_macros.S
new file mode 100644
index 0000000..3285d85
--- /dev/null
+++ b/include/arch/aarch64/console_macros.S
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CONSOLE_MACROS_S
+#define CONSOLE_MACROS_S
+
+#include <drivers/console.h>
+
+/*
+ * This macro encapsulates the common setup that has to be done at the end of
+ * a console driver's register function. It will register all of the driver's
+ * callbacks in the console_t structure and initialize the flags field (by
+ * default consoles are enabled for the "boot" and "crash" states, this can be
+ * changed after registration with the console_set_scope() function). It ends
+ * with a tail call that will include return to the caller.
+ * REQUIRES console_t pointer in x0 and a valid return address in x30.
+ */
+	.macro	finish_console_register _driver, putc=0, getc=0, flush=0
+	/*
+	 * If any of the callback is not specified or set as 0, then the
+	 * corresponding callback entry in console_t is set to 0.
+	 */
+	.ifne \putc
+	  adrp	x1, console_\_driver\()_putc
+	  add	x1, x1, :lo12:console_\_driver\()_putc
+	  str	x1, [x0, #CONSOLE_T_PUTC]
+	.else
+	  str	xzr, [x0, #CONSOLE_T_PUTC]
+	.endif
+
+	.ifne \getc
+	  adrp	x1, console_\_driver\()_getc
+	  add	x1, x1, :lo12:console_\_driver\()_getc
+	  str	x1, [x0, #CONSOLE_T_GETC]
+	.else
+	  str	xzr, [x0, #CONSOLE_T_GETC]
+	.endif
+
+	.ifne \flush
+	  adrp	x1, console_\_driver\()_flush
+	  add	x1, x1, :lo12:console_\_driver\()_flush
+	  str	x1, [x0, #CONSOLE_T_FLUSH]
+	.else
+	  str	xzr, [x0, #CONSOLE_T_FLUSH]
+	.endif
+
+	mov	x1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH)
+	str	x1, [x0, #CONSOLE_T_FLAGS]
+	b	console_register
+	.endm
+
+#endif /* CONSOLE_MACROS_S */
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
new file mode 100644
index 0000000..22b32b4
--- /dev/null
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EL3_COMMON_MACROS_S
+#define EL3_COMMON_MACROS_S
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	/*
+	 * Helper macro to initialise EL3 registers we care about.
+	 */
+	.macro el3_arch_init_common
+	/* ---------------------------------------------------------------------
+	 * SCTLR_EL3 has already been initialised - read current value before
+	 * modifying.
+	 *
+	 * SCTLR_EL3.I: Enable the instruction cache.
+	 *
+	 * SCTLR_EL3.SA: Enable Stack Alignment check. A SP alignment fault
+	 *  exception is generated if a load or store instruction executed at
+	 *  EL3 uses the SP as the base address and the SP is not aligned to a
+	 *  16-byte boundary.
+	 *
+	 * SCTLR_EL3.A: Enable Alignment fault checking. All instructions that
+	 *  load or store one or more registers have an alignment check that the
+	 *  address being accessed is aligned to the size of the data element(s)
+	 *  being accessed.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
+	mrs	x0, sctlr_el3
+	orr	x0, x0, x1
+	msr	sctlr_el3, x0
+	isb
+
+#ifdef IMAGE_BL31
+	/* ---------------------------------------------------------------------
+	 * Initialise the per-cpu cache pointer to the CPU.
+	 * This is done early to enable crash reporting to have access to crash
+	 * stack. Since crash reporting depends on cpu_data to report the
+	 * unhandled exception, not doing so can lead to recursive exceptions
+	 * due to a NULL TPIDR_EL3.
+	 * ---------------------------------------------------------------------
+	 */
+	bl	init_cpu_data_ptr
+#endif /* IMAGE_BL31 */
+
+	/* ---------------------------------------------------------------------
+	 * Initialise SCR_EL3, setting all fields rather than relying on hw.
+	 * All fields are architecturally UNKNOWN on reset. The following fields
+	 * do not change during the TF lifetime. The remaining fields are set to
+	 * zero here but are updated ahead of transitioning to a lower EL in the
+	 * function cm_init_context_common().
+	 *
+	 * SCR_EL3.TWE: Set to zero so that execution of WFE instructions at
+	 *  EL2, EL1 and EL0 are not trapped to EL3.
+	 *
+	 * SCR_EL3.TWI: Set to zero so that execution of WFI instructions at
+	 *  EL2, EL1 and EL0 are not trapped to EL3.
+	 *
+	 * SCR_EL3.SIF: Set to one to disable instruction fetches from
+	 *  Non-secure memory.
+	 *
+	 * SCR_EL3.SMD: Set to zero to enable SMC calls at EL1 and above, from
+	 *  both Security states and both Execution states.
+	 *
+	 * SCR_EL3.EA: Set to one to route External Aborts and SError Interrupts
+	 *  to EL3 when executing at any EL.
+	 *
+	 * SCR_EL3.{API,APK}: For Armv8.3 pointer authentication feature,
+	 * disable traps to EL3 when accessing key registers or using pointer
+	 * authentication instructions from lower ELs.
+	 * ---------------------------------------------------------------------
+	 */
+	mov_imm	x0, ((SCR_RESET_VAL | SCR_EA_BIT | SCR_SIF_BIT) \
+			& ~(SCR_TWE_BIT | SCR_TWI_BIT | SCR_SMD_BIT))
+#if CTX_INCLUDE_PAUTH_REGS
+	/*
+	 * If the pointer authentication registers are saved during world
+	 * switches, enable pointer authentication everywhere, as it is safe to
+	 * do so.
+	 */
+	orr	x0, x0, #(SCR_API_BIT | SCR_APK_BIT)
+#endif
+	msr	scr_el3, x0
+
+	/* ---------------------------------------------------------------------
+	 * Initialise MDCR_EL3, setting all fields rather than relying on hw.
+	 * Some fields are architecturally UNKNOWN on reset.
+	 *
+	 * MDCR_EL3.SDD: Set to one to disable AArch64 Secure self-hosted debug.
+	 *  Debug exceptions, other than Breakpoint Instruction exceptions, are
+	 *  disabled from all ELs in Secure state.
+	 *
+	 * MDCR_EL3.SPD32: Set to 0b10 to disable AArch32 Secure self-hosted
+	 *  privileged debug from S-EL1.
+	 *
+	 * MDCR_EL3.TDOSA: Set to zero so that EL2 and EL2 System register
+	 *  access to the powerdown debug registers do not trap to EL3.
+	 *
+	 * MDCR_EL3.TDA: Set to zero to allow EL0, EL1 and EL2 access to the
+	 *  debug registers, other than those registers that are controlled by
+	 *  MDCR_EL3.TDOSA.
+	 *
+	 * MDCR_EL3.TPM: Set to zero so that EL0, EL1, and EL2 System register
+	 *  accesses to all Performance Monitors registers do not trap to EL3.
+	 *
+	 * MDCR_EL3.SCCD: Set to one so that cycle counting by PMCCNTR_EL0 is
+	 *  prohibited in Secure state. This bit is RES0 in versions of the
+	 *  architecture earlier than ARMv8.5, setting it to 1 doesn't have any
+	 *  effect on them.
+	 * ---------------------------------------------------------------------
+	 */
+	mov_imm	x0, ((MDCR_EL3_RESET_VAL | MDCR_SDD_BIT | \
+		      MDCR_SPD32(MDCR_SPD32_DISABLE) | MDCR_SCCD_BIT) \
+		    & ~(MDCR_TDOSA_BIT | MDCR_TDA_BIT | MDCR_TPM_BIT))
+
+	msr	mdcr_el3, x0
+
+	/* ---------------------------------------------------------------------
+	 * Enable External Aborts and SError Interrupts now that the exception
+	 * vectors have been setup.
+	 * ---------------------------------------------------------------------
+	 */
+	msr	daifclr, #DAIF_ABT_BIT
+
+	/* ---------------------------------------------------------------------
+	 * Initialise CPTR_EL3, setting all fields rather than relying on hw.
+	 * All fields are architecturally UNKNOWN on reset.
+	 *
+	 * CPTR_EL3.TCPAC: Set to zero so that any accesses to CPACR_EL1,
+	 *  CPTR_EL2, CPACR, or HCPTR do not trap to EL3.
+	 *
+	 * CPTR_EL3.TTA: Set to zero so that System register accesses to the
+	 *  trace registers do not trap to EL3.
+	 *
+	 * CPTR_EL3.TFP: Set to zero so that accesses to the V- or Z- registers
+	 *  by Advanced SIMD, floating-point or SVE instructions (if implemented)
+	 *  do not trap to EL3.
+	 */
+	mov_imm x0, (CPTR_EL3_RESET_VAL & ~(TCPAC_BIT | TTA_BIT | TFP_BIT))
+	msr	cptr_el3, x0
+
+	/*
+	 * If Data Independent Timing (DIT) functionality is implemented,
+	 * always enable DIT in EL3
+	 */
+	mrs	x0, id_aa64pfr0_el1
+	ubfx	x0, x0, #ID_AA64PFR0_DIT_SHIFT, #ID_AA64PFR0_DIT_LENGTH
+	cmp	x0, #ID_AA64PFR0_DIT_SUPPORTED
+	bne	1f
+	mov	x0, #DIT_BIT
+	msr	DIT, x0
+1:
+	.endm
+
+/* -----------------------------------------------------------------------------
+ * This is the super set of actions that need to be performed during a cold boot
+ * or a warm boot in EL3. This code is shared by BL1 and BL31.
+ *
+ * This macro will always perform reset handling, architectural initialisations
+ * and stack setup. The rest of the actions are optional because they might not
+ * be needed, depending on the context in which this macro is called. This is
+ * why this macro is parameterised ; each parameter allows to enable/disable
+ * some actions.
+ *
+ *  _init_sctlr:
+ *	Whether the macro needs to initialise SCTLR_EL3, including configuring
+ *      the endianness of data accesses.
+ *
+ *  _warm_boot_mailbox:
+ *	Whether the macro needs to detect the type of boot (cold/warm). The
+ *	detection is based on the platform entrypoint address : if it is zero
+ *	then it is a cold boot, otherwise it is a warm boot. In the latter case,
+ *	this macro jumps on the platform entrypoint address.
+ *
+ *  _secondary_cold_boot:
+ *	Whether the macro needs to identify the CPU that is calling it: primary
+ *	CPU or secondary CPU. The primary CPU will be allowed to carry on with
+ *	the platform initialisations, while the secondaries will be put in a
+ *	platform-specific state in the meantime.
+ *
+ *	If the caller knows this macro will only be called by the primary CPU
+ *	then this parameter can be defined to 0 to skip this step.
+ *
+ * _init_memory:
+ *	Whether the macro needs to initialise the memory.
+ *
+ * _init_c_runtime:
+ *	Whether the macro needs to initialise the C runtime environment.
+ *
+ * _exception_vectors:
+ *	Address of the exception vectors to program in the VBAR_EL3 register.
+ * -----------------------------------------------------------------------------
+ */
+	.macro el3_entrypoint_common					\
+		_init_sctlr, _warm_boot_mailbox, _secondary_cold_boot,	\
+		_init_memory, _init_c_runtime, _exception_vectors
+
+	.if \_init_sctlr
+		/* -------------------------------------------------------------
+		 * This is the initialisation of SCTLR_EL3 and so must ensure
+		 * that all fields are explicitly set rather than relying on hw.
+		 * Some fields reset to an IMPLEMENTATION DEFINED value and
+		 * others are architecturally UNKNOWN on reset.
+		 *
+		 * SCTLR.EE: Set the CPU endianness before doing anything that
+		 *  might involve memory reads or writes. Set to zero to select
+		 *  Little Endian.
+		 *
+		 * SCTLR_EL3.WXN: For the EL3 translation regime, this field can
+		 *  force all memory regions that are writeable to be treated as
+		 *  XN (Execute-never). Set to zero so that this control has no
+		 *  effect on memory access permissions.
+		 *
+		 * SCTLR_EL3.SA: Set to zero to disable Stack Alignment check.
+		 *
+		 * SCTLR_EL3.A: Set to zero to disable Alignment fault checking.
+		 *
+		 * SCTLR.DSSBS: Set to zero to disable speculation store bypass
+		 *  safe behaviour upon exception entry to EL3.
+		 * -------------------------------------------------------------
+		 */
+		mov_imm	x0, (SCTLR_RESET_VAL & ~(SCTLR_EE_BIT | SCTLR_WXN_BIT \
+				| SCTLR_SA_BIT | SCTLR_A_BIT | SCTLR_DSSBS_BIT))
+		msr	sctlr_el3, x0
+		isb
+	.endif /* _init_sctlr */
+
+	.if \_warm_boot_mailbox
+		/* -------------------------------------------------------------
+		 * This code will be executed for both warm and cold resets.
+		 * Now is the time to distinguish between the two.
+		 * Query the platform entrypoint address and if it is not zero
+		 * then it means it is a warm boot so jump to this address.
+		 * -------------------------------------------------------------
+		 */
+		bl	plat_get_my_entrypoint
+		cbz	x0, do_cold_boot
+		br	x0
+
+	do_cold_boot:
+	.endif /* _warm_boot_mailbox */
+
+	/* ---------------------------------------------------------------------
+	 * Set the exception vectors.
+	 * ---------------------------------------------------------------------
+	 */
+	adr	x0, \_exception_vectors
+	msr	vbar_el3, x0
+	isb
+
+	/* ---------------------------------------------------------------------
+	 * It is a cold boot.
+	 * Perform any processor specific actions upon reset e.g. cache, TLB
+	 * invalidations etc.
+	 * ---------------------------------------------------------------------
+	 */
+	bl	reset_handler
+
+	el3_arch_init_common
+
+	.if \_secondary_cold_boot
+		/* -------------------------------------------------------------
+		 * Check if this is a primary or secondary CPU cold boot.
+		 * The primary CPU will set up the platform while the
+		 * secondaries are placed in a platform-specific state until the
+		 * primary CPU performs the necessary actions to bring them out
+		 * of that state and allows entry into the OS.
+		 * -------------------------------------------------------------
+		 */
+		bl	plat_is_my_cpu_primary
+		cbnz	w0, do_primary_cold_boot
+
+		/* This is a cold boot on a secondary CPU */
+		bl	plat_secondary_cold_boot_setup
+		/* plat_secondary_cold_boot_setup() is not supposed to return */
+		bl	el3_panic
+
+	do_primary_cold_boot:
+	.endif /* _secondary_cold_boot */
+
+	/* ---------------------------------------------------------------------
+	 * Initialize memory now. Secondary CPU initialization won't get to this
+	 * point.
+	 * ---------------------------------------------------------------------
+	 */
+
+	.if \_init_memory
+		bl	platform_mem_init
+	.endif /* _init_memory */
+
+	/* ---------------------------------------------------------------------
+	 * Init C runtime environment:
+	 *   - Zero-initialise the NOBITS sections. There are 2 of them:
+	 *       - the .bss section;
+	 *       - the coherent memory section (if any).
+	 *   - Relocate the data section from ROM to RAM, if required.
+	 * ---------------------------------------------------------------------
+	 */
+	.if \_init_c_runtime
+#if defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3)
+		/* -------------------------------------------------------------
+		 * Invalidate the RW memory used by the BL31 image. This
+		 * includes the data and NOBITS sections. This is done to
+		 * safeguard against possible corruption of this memory by
+		 * dirty cache lines in a system cache as a result of use by
+		 * an earlier boot loader stage.
+		 * -------------------------------------------------------------
+		 */
+		adrp	x0, __RW_START__
+		add	x0, x0, :lo12:__RW_START__
+		adrp	x1, __RW_END__
+		add	x1, x1, :lo12:__RW_END__
+		sub	x1, x1, x0
+		bl	inv_dcache_range
+#endif
+		adrp	x0, __BSS_START__
+		add	x0, x0, :lo12:__BSS_START__
+
+		adrp	x1, __BSS_END__
+		add	x1, x1, :lo12:__BSS_END__
+		sub	x1, x1, x0
+		bl	zeromem
+
+#if USE_COHERENT_MEM
+		adrp	x0, __COHERENT_RAM_START__
+		add	x0, x0, :lo12:__COHERENT_RAM_START__
+		adrp	x1, __COHERENT_RAM_END_UNALIGNED__
+		add	x1, x1, :lo12: __COHERENT_RAM_END_UNALIGNED__
+		sub	x1, x1, x0
+		bl	zeromem
+#endif
+
+#if defined(IMAGE_BL1) || (defined(IMAGE_BL2) && BL2_IN_XIP_MEM)
+		adrp	x0, __DATA_RAM_START__
+		add	x0, x0, :lo12:__DATA_RAM_START__
+		adrp	x1, __DATA_ROM_START__
+		add	x1, x1, :lo12:__DATA_ROM_START__
+		adrp	x2, __DATA_RAM_END__
+		add	x2, x2, :lo12:__DATA_RAM_END__
+		sub	x2, x2, x0
+		bl	memcpy16
+#endif
+	.endif /* _init_c_runtime */
+
+	/* ---------------------------------------------------------------------
+	 * Use SP_EL0 for the C runtime stack.
+	 * ---------------------------------------------------------------------
+	 */
+	msr	spsel, #0
+
+	/* ---------------------------------------------------------------------
+	 * Allocate a stack whose memory will be marked as Normal-IS-WBWA when
+	 * the MMU is enabled. There is no risk of reading stale stack memory
+	 * after enabling the MMU as only the primary CPU is running at the
+	 * moment.
+	 * ---------------------------------------------------------------------
+	 */
+	bl	plat_set_my_stack
+
+#if STACK_PROTECTOR_ENABLED
+	.if \_init_c_runtime
+	bl	update_stack_protector_canary
+	.endif /* _init_c_runtime */
+#endif
+	.endm
+
+#endif /* EL3_COMMON_MACROS_S */
diff --git a/include/arch/aarch64/smccc_helpers.h b/include/arch/aarch64/smccc_helpers.h
new file mode 100644
index 0000000..fac6fd9
--- /dev/null
+++ b/include/arch/aarch64/smccc_helpers.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMCCC_HELPERS_H
+#define SMCCC_HELPERS_H
+
+#include <lib/smccc.h>
+
+#ifndef __ASSEMBLER__
+
+#include <stdbool.h>
+
+#include <context.h>
+
+/* Convenience macros to return from SMC handler */
+#define SMC_RET0(_h)	{					\
+	return (uint64_t) (_h);					\
+}
+#define SMC_RET1(_h, _x0)	{				\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X0), (_x0));	\
+	SMC_RET0(_h);						\
+}
+#define SMC_RET2(_h, _x0, _x1)	{				\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X1), (_x1));	\
+	SMC_RET1(_h, (_x0));					\
+}
+#define SMC_RET3(_h, _x0, _x1, _x2)	{			\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X2), (_x2));	\
+	SMC_RET2(_h, (_x0), (_x1));				\
+}
+#define SMC_RET4(_h, _x0, _x1, _x2, _x3)	{		\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X3), (_x3));	\
+	SMC_RET3(_h, (_x0), (_x1), (_x2));			\
+}
+#define SMC_RET5(_h, _x0, _x1, _x2, _x3, _x4)	{		\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X4), (_x4));	\
+	SMC_RET4(_h, (_x0), (_x1), (_x2), (_x3));		\
+}
+#define SMC_RET6(_h, _x0, _x1, _x2, _x3, _x4, _x5)	{	\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X5), (_x5));	\
+	SMC_RET5(_h, (_x0), (_x1), (_x2), (_x3), (_x4));	\
+}
+#define SMC_RET7(_h, _x0, _x1, _x2, _x3, _x4, _x5, _x6)	{	\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X6), (_x6));	\
+	SMC_RET6(_h, (_x0), (_x1), (_x2), (_x3), (_x4), (_x5));	\
+}
+#define SMC_RET8(_h, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7) {	\
+	write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X7), (_x7));	\
+	SMC_RET7(_h, (_x0), (_x1), (_x2), (_x3), (_x4), (_x5), (_x6));	\
+}
+
+/*
+ * Convenience macros to access general purpose registers using handle provided
+ * to SMC handler. These take the offset values defined in context.h
+ */
+#define SMC_GET_GP(_h, _g)					\
+	read_ctx_reg((get_gpregs_ctx(_h)), (_g))
+#define SMC_SET_GP(_h, _g, _v)					\
+	write_ctx_reg((get_gpregs_ctx(_h)), (_g), (_v))
+
+/*
+ * Convenience macros to access EL3 context registers using handle provided to
+ * SMC handler. These take the offset values defined in context.h
+ */
+#define SMC_GET_EL3(_h, _e)					\
+	read_ctx_reg((get_el3state_ctx(_h)), (_e))
+#define SMC_SET_EL3(_h, _e, _v)					\
+	write_ctx_reg((get_el3state_ctx(_h)), (_e), (_v))
+
+/*
+ * Helper macro to retrieve the SMC parameters from cpu_context_t.
+ */
+#define get_smc_params_from_ctx(_hdl, _x1, _x2, _x3, _x4)	\
+	do {							\
+		const gp_regs_t *regs = get_gpregs_ctx(_hdl);	\
+		_x1 = read_ctx_reg(regs, CTX_GPREG_X1);		\
+		_x2 = read_ctx_reg(regs, CTX_GPREG_X2);		\
+		_x3 = read_ctx_reg(regs, CTX_GPREG_X3);		\
+		_x4 = read_ctx_reg(regs, CTX_GPREG_X4);		\
+	} while (false)
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* SMCCC_HELPERS_H */
diff --git a/include/bl1/bl1.h b/include/bl1/bl1.h
new file mode 100644
index 0000000..d81f434
--- /dev/null
+++ b/include/bl1/bl1.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL1_H
+#define BL1_H
+
+#include <common/bl_common.h>
+
+/*
+ * Defines for BL1 SMC function ids.
+ */
+#define BL1_SMC_CALL_COUNT		0x0
+#define BL1_SMC_UID			0x1
+/* SMC #0x2 reserved */
+#define BL1_SMC_VERSION			0x3
+
+/*
+ * Corresponds to the function ID of the SMC that
+ * the BL1 exception handler service to execute BL31.
+ */
+#define BL1_SMC_RUN_IMAGE		0x4
+
+/*
+ * BL1 SMC version
+ */
+#define BL1_SMC_MAJOR_VER		0x0
+#define BL1_SMC_MINOR_VER		0x1
+
+/*
+ * Defines for FWU SMC function ids.
+ */
+
+#define FWU_SMC_IMAGE_COPY		0x10
+#define FWU_SMC_IMAGE_AUTH		0x11
+#define FWU_SMC_IMAGE_EXECUTE		0x12
+#define FWU_SMC_IMAGE_RESUME		0x13
+#define FWU_SMC_SEC_IMAGE_DONE		0x14
+#define FWU_SMC_UPDATE_DONE		0x15
+#define FWU_SMC_IMAGE_RESET		0x16
+
+/*
+ * Number of FWU calls (above) implemented
+ */
+#define FWU_NUM_SMC_CALLS		7
+
+#if TRUSTED_BOARD_BOOT
+# define BL1_NUM_SMC_CALLS		(FWU_NUM_SMC_CALLS + 4)
+#else
+# define BL1_NUM_SMC_CALLS		4
+#endif
+
+/*
+ * The macros below are used to identify FWU
+ * calls from the SMC function ID
+ */
+#define FWU_SMC_FID_START		FWU_SMC_IMAGE_COPY
+#define FWU_SMC_FID_END			FWU_SMC_IMAGE_RESET
+#define is_fwu_fid(_fid) \
+    ((_fid >= FWU_SMC_FID_START) && (_fid <= FWU_SMC_FID_END))
+
+#ifndef __ASSEMBLER__
+
+#include <lib/cassert.h>
+
+struct entry_point_info;
+
+register_t bl1_smc_wrapper(uint32_t smc_fid,
+	void *cookie,
+	void *handle,
+	unsigned int flags);
+
+register_t bl1_smc_handler(unsigned int smc_fid,
+	register_t x1,
+	register_t x2,
+	register_t x3,
+	register_t x4,
+	void *cookie,
+	void *handle,
+	unsigned int flags);
+
+void bl1_print_next_bl_ep_info(const struct entry_point_info *bl_ep_info);
+
+void bl1_setup(void);
+void bl1_main(void);
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info);
+
+/*
+ * Check if the total number of FWU SMC calls are as expected.
+ */
+CASSERT(FWU_NUM_SMC_CALLS == 	\
+		(FWU_SMC_FID_END - FWU_SMC_FID_START + 1),\
+		assert_FWU_NUM_SMC_CALLS_mismatch);
+
+/* Utility functions */
+void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
+			meminfo_t *bl2_mem_layout);
+
+#endif /* __ASSEMBLER__ */
+#endif /* BL1_H */
diff --git a/include/bl1/tbbr/tbbr_img_desc.h b/include/bl1/tbbr/tbbr_img_desc.h
new file mode 100644
index 0000000..db15cdb
--- /dev/null
+++ b/include/bl1/tbbr/tbbr_img_desc.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_IMG_DESC_H
+#define TBBR_IMG_DESC_H
+
+#include <common/bl_common.h>
+
+extern image_desc_t bl1_tbbr_image_descs[];
+
+#endif /* TBBR_IMG_DESC_H */
diff --git a/include/bl2/bl2.h b/include/bl2/bl2.h
new file mode 100644
index 0000000..73f5ac7
--- /dev/null
+++ b/include/bl2/bl2.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL2_H
+#define BL2_H
+
+#include <stdint.h>
+
+void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+	       u_register_t arg3);
+void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+		   u_register_t arg3);
+void bl2_main(void);
+
+#endif /* BL2_H */
diff --git a/include/bl2u/bl2u.h b/include/bl2u/bl2u.h
new file mode 100644
index 0000000..387eaf8
--- /dev/null
+++ b/include/bl2u/bl2u.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL2U_H
+#define BL2U_H
+
+void bl2u_main(void);
+
+#endif /* BL2U_H */
diff --git a/include/bl31/bl31.h b/include/bl31/bl31.h
new file mode 100644
index 0000000..3deb0a5
--- /dev/null
+++ b/include/bl31/bl31.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL31_H
+#define BL31_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+		u_register_t arg3);
+void bl31_next_el_arch_setup(uint32_t security_state);
+void bl31_set_next_image_type(uint32_t security_state);
+uint32_t bl31_get_next_image_type(void);
+void bl31_prepare_next_image_entry(void);
+void bl31_register_bl32_init(int32_t (*func)(void));
+void bl31_warm_entrypoint(void);
+void bl31_main(void);
+void bl31_lib_init(void);
+
+#endif /* BL31_H */
diff --git a/include/bl31/ea_handle.h b/include/bl31/ea_handle.h
new file mode 100644
index 0000000..68f012c
--- /dev/null
+++ b/include/bl31/ea_handle.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EA_HANDLE_H
+#define EA_HANDLE_H
+
+/* Constants indicating the reason for an External Abort */
+
+/* External Abort received at SError vector */
+#define ERROR_EA_ASYNC		0
+
+/* Synchronous External Abort received at Synchronous exception vector */
+#define ERROR_EA_SYNC		1
+
+/* External Abort synchronized by ESB instruction */
+#define ERROR_EA_ESB		2
+
+/* RAS event signalled as peripheral interrupt */
+#define ERROR_INTERRUPT		3
+
+#endif /* EA_HANDLE_H */
diff --git a/include/bl31/ehf.h b/include/bl31/ehf.h
new file mode 100644
index 0000000..c13d28c
--- /dev/null
+++ b/include/bl31/ehf.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EHF_H
+#define EHF_H
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* Valid priorities set bit 0 of the priority handler. */
+#define EHF_PRI_VALID_	BIT(0)
+
+/* Marker for no handler registered for a valid priority */
+#define EHF_NO_HANDLER_	(0U | EHF_PRI_VALID_)
+
+/* Extract the specified number of top bits from 7 lower bits of priority */
+#define EHF_PRI_TO_IDX(pri, plat_bits) \
+	((((unsigned) (pri)) & 0x7fu) >> (7u - (plat_bits)))
+
+/* Install exception priority descriptor at a suitable index */
+#define EHF_PRI_DESC(plat_bits, priority) \
+	[EHF_PRI_TO_IDX(priority, plat_bits)] = { \
+		.ehf_handler = EHF_NO_HANDLER_, \
+	}
+
+/* Macro for platforms to regiter its exception priorities */
+#define EHF_REGISTER_PRIORITIES(priorities, num, bits) \
+	const ehf_priorities_t exception_data = { \
+		.num_priorities = (num), \
+		.ehf_priorities = (priorities), \
+		.pri_bits = (bits), \
+	}
+
+/*
+ * Priority stack, managed as a bitmap.
+ *
+ * Currently only supports 32 priority levels, allowing platforms to use up to 5
+ * top bits of priority. But the type can be changed to uint64_t should need
+ * arise to support 64 priority levels, allowing platforms to use up to 6 top
+ * bits of priority.
+ */
+typedef uint32_t ehf_pri_bits_t;
+
+/*
+ * Per-PE exception data. The data for each PE is kept as a per-CPU data field.
+ * See cpu_data.h.
+ */
+typedef struct {
+	ehf_pri_bits_t active_pri_bits;
+
+	/* Priority mask value before any priority levels were active */
+	uint8_t init_pri_mask;
+
+	/* Non-secure priority mask value stashed during Secure execution */
+	uint8_t ns_pri_mask;
+} __aligned(sizeof(uint64_t)) pe_exc_data_t;
+
+typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle,
+		void *cookie);
+
+typedef struct ehf_pri_desc {
+	/*
+	 * 4-byte-aligned exception handler. Bit 0 indicates the corresponding
+	 * priority level is valid. This is effectively of ehf_handler_t type,
+	 * but left as uintptr_t in order to make pointer arithmetic convenient.
+	 */
+	uintptr_t ehf_handler;
+} ehf_pri_desc_t;
+
+typedef struct ehf_priority_type {
+	ehf_pri_desc_t *ehf_priorities;
+	unsigned int num_priorities;
+	unsigned int pri_bits;
+} ehf_priorities_t;
+
+void ehf_init(void);
+void ehf_activate_priority(unsigned int priority);
+void ehf_deactivate_priority(unsigned int priority);
+void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler);
+void ehf_allow_ns_preemption(uint64_t preempt_ret_code);
+unsigned int ehf_is_ns_preemption_allowed(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* EHF_H */
diff --git a/include/bl31/interrupt_mgmt.h b/include/bl31/interrupt_mgmt.h
new file mode 100644
index 0000000..8bb1bab
--- /dev/null
+++ b/include/bl31/interrupt_mgmt.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INTERRUPT_MGMT_H
+#define INTERRUPT_MGMT_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Constants for the types of interrupts recognised by the IM framework
+ ******************************************************************************/
+#define INTR_TYPE_S_EL1			U(0)
+#define INTR_TYPE_EL3			U(1)
+#define INTR_TYPE_NS			U(2)
+#define MAX_INTR_TYPES			U(3)
+#define INTR_TYPE_INVAL			MAX_INTR_TYPES
+
+/* Interrupt routing modes */
+#define INTR_ROUTING_MODE_PE		0
+#define INTR_ROUTING_MODE_ANY		1
+
+/*
+ * Constant passed to the interrupt handler in the 'id' field when the
+ * framework does not read the gic registers to determine the interrupt id.
+ */
+#define INTR_ID_UNAVAILABLE		U(0xFFFFFFFF)
+
+
+/*******************************************************************************
+ * Mask for _both_ the routing model bits in the 'flags' parameter and
+ * constants to define the valid routing models for each supported interrupt
+ * type
+ ******************************************************************************/
+#define INTR_RM_FLAGS_SHIFT		U(0x0)
+#define INTR_RM_FLAGS_MASK		U(0x3)
+/* Routed to EL3 from NS. Taken to S-EL1 from Secure */
+#define INTR_SEL1_VALID_RM0		U(0x2)
+/* Routed to EL3 from NS and Secure */
+#define INTR_SEL1_VALID_RM1		U(0x3)
+/* Routed to EL1/EL2 from NS and to S-EL1 from Secure */
+#define INTR_NS_VALID_RM0		U(0x0)
+/* Routed to EL1/EL2 from NS and to EL3 from Secure */
+#define INTR_NS_VALID_RM1		U(0x1)
+/* Routed to EL3 from NS. Taken to S-EL1 from Secure and handed over to EL3 */
+#define INTR_EL3_VALID_RM0		U(0x2)
+/* Routed to EL3 from NS and Secure */
+#define INTR_EL3_VALID_RM1		U(0x3)
+/* This is the default routing model */
+#define INTR_DEFAULT_RM			U(0x0)
+
+/*******************************************************************************
+ * Constants for the _individual_ routing model bits in the 'flags' field for
+ * each interrupt type and mask to validate the 'flags' parameter while
+ * registering an interrupt handler
+ ******************************************************************************/
+#define INTR_TYPE_FLAGS_MASK		U(0xFFFFFFFC)
+
+#define INTR_RM_FROM_SEC_SHIFT		SECURE		/* BIT[0] */
+#define INTR_RM_FROM_NS_SHIFT		NON_SECURE	/* BIT[1] */
+#define INTR_RM_FROM_FLAG_MASK		U(1)
+#define get_interrupt_rm_flag(flag, ss) \
+	((((flag) >> INTR_RM_FLAGS_SHIFT) >> (ss)) & INTR_RM_FROM_FLAG_MASK)
+#define set_interrupt_rm_flag(flag, ss)	((flag) |= U(1) << (ss))
+#define clr_interrupt_rm_flag(flag, ss)	((flag) &= ~(U(1) << (ss)))
+
+/*******************************************************************************
+ * Macros to set the 'flags' parameter passed to an interrupt type handler. Only
+ * the flag to indicate the security state when the exception was generated is
+ * supported.
+ ******************************************************************************/
+#define INTR_SRC_SS_FLAG_SHIFT		U(0)		/* BIT[0] */
+#define INTR_SRC_SS_FLAG_MASK		U(1)
+#define set_interrupt_src_ss(flag, val)	((flag) |= (val) << INTR_SRC_SS_FLAG_SHIFT)
+#define clr_interrupt_src_ss(flag)	((flag) &= ~(U(1) << INTR_SRC_SS_FLAG_SHIFT))
+#define get_interrupt_src_ss(flag)	(((flag) >> INTR_SRC_SS_FLAG_SHIFT) & \
+					 INTR_SRC_SS_FLAG_MASK)
+
+#ifndef __ASSEMBLER__
+
+#include <errno.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Helpers to validate the routing model bits in the 'flags' for a type
+ * of interrupt. If the model does not match one of the valid masks
+ * -EINVAL is returned.
+ ******************************************************************************/
+static inline int32_t validate_sel1_interrupt_rm(uint32_t x)
+{
+	if ((x == INTR_SEL1_VALID_RM0) || (x == INTR_SEL1_VALID_RM1))
+		return 0;
+
+	return -EINVAL;
+}
+
+static inline int32_t validate_ns_interrupt_rm(uint32_t x)
+{
+	if ((x == INTR_NS_VALID_RM0) || (x == INTR_NS_VALID_RM1))
+		return 0;
+
+	return -EINVAL;
+}
+
+static inline int32_t validate_el3_interrupt_rm(uint32_t x)
+{
+#if EL3_EXCEPTION_HANDLING
+	/*
+	 * With EL3 exception handling, EL3 interrupts are always routed to EL3
+	 * from both Secure and Non-secure, and therefore INTR_EL3_VALID_RM1 is
+	 * the only valid routing model.
+	 */
+	if (x == INTR_EL3_VALID_RM1)
+		return 0;
+#else
+	if ((x == INTR_EL3_VALID_RM0) || (x == INTR_EL3_VALID_RM1))
+		return 0;
+#endif
+
+	return -EINVAL;
+}
+
+/*******************************************************************************
+ * Prototype for defining a handler for an interrupt type
+ ******************************************************************************/
+typedef uint64_t (*interrupt_type_handler_t)(uint32_t id,
+					     uint32_t flags,
+					     void *handle,
+					     void *cookie);
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+uint32_t get_scr_el3_from_routing_model(uint32_t security_state);
+int32_t set_routing_model(uint32_t type, uint32_t flags);
+int32_t register_interrupt_type_handler(uint32_t type,
+					interrupt_type_handler_t handler,
+					uint32_t flags);
+interrupt_type_handler_t get_interrupt_type_handler(uint32_t type);
+int disable_intr_rm_local(uint32_t type, uint32_t security_state);
+int enable_intr_rm_local(uint32_t type, uint32_t security_state);
+
+#endif /*__ASSEMBLER__*/
+#endif /* INTERRUPT_MGMT_H */
diff --git a/include/bl32/payloads/tlk.h b/include/bl32/payloads/tlk.h
new file mode 100644
index 0000000..ce8e3e8
--- /dev/null
+++ b/include/bl32/payloads/tlk.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TLK_H
+#define TLK_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Generate function IDs for the Trusted OS/Apps
+ */
+#define TLK_TOS_YIELD_FID(fid)	((fid) | 0x72000000 | (0 << 31))
+#define TLK_TA_YIELD_FID(fid)	((fid) | 0x70000000 | (0 << 31))
+
+/*
+ * Trusted OS specific function IDs
+ */
+#define TLK_REGISTER_LOGBUF	TLK_TOS_YIELD_FID(0x1)
+#define TLK_REGISTER_REQBUF	TLK_TOS_YIELD_FID(0x2)
+#define TLK_SS_REGISTER_HANDLER	TLK_TOS_YIELD_FID(0x3)
+#define TLK_REGISTER_NS_DRAM_RANGES	TLK_TOS_YIELD_FID(0x4)
+#define TLK_SET_ROOT_OF_TRUST	TLK_TOS_YIELD_FID(0x5)
+#define TLK_RESUME_FID		TLK_TOS_YIELD_FID(0x100)
+#define TLK_SYSTEM_SUSPEND	TLK_TOS_YIELD_FID(0xE001)
+#define TLK_SYSTEM_RESUME	TLK_TOS_YIELD_FID(0xE002)
+#define TLK_SYSTEM_OFF		TLK_TOS_YIELD_FID(0xE003)
+
+/*
+ * SMC function IDs that TLK uses to signal various forms of completions
+ * to the secure payload dispatcher.
+ */
+#define TLK_REQUEST_DONE	(0x32000001 | (ULL(1) << 31))
+#define TLK_PREEMPTED		(0x32000002 | (ULL(1) << 31))
+#define TLK_ENTRY_DONE		(0x32000003 | (ULL(1) << 31))
+#define TLK_VA_TRANSLATE	(0x32000004 | (ULL(1) << 31))
+#define TLK_SUSPEND_DONE	(0x32000005 | (ULL(1) << 31))
+#define TLK_RESUME_DONE		(0x32000006 | (ULL(1) << 31))
+#define TLK_SYSTEM_OFF_DONE	(0x32000007 | (ULL(1) << 31))
+
+/*
+ * Trusted Application specific function IDs
+ */
+#define TLK_OPEN_TA_SESSION	TLK_TA_YIELD_FID(0x1)
+#define TLK_CLOSE_TA_SESSION	TLK_TA_YIELD_FID(0x2)
+#define TLK_TA_LAUNCH_OP	TLK_TA_YIELD_FID(0x3)
+#define TLK_TA_SEND_EVENT	TLK_TA_YIELD_FID(0x4)
+
+/*
+ * Total number of function IDs implemented for services offered to NS clients.
+ */
+#define TLK_NUM_FID		7
+
+/* TLK implementation version numbers */
+#define TLK_VERSION_MAJOR	0x0 /* Major version */
+#define TLK_VERSION_MINOR	0x1 /* Minor version */
+
+/*
+ * Standard Trusted OS Function IDs that fall under Trusted OS call range
+ * according to SMC calling convention
+ */
+#define TOS_CALL_COUNT		0xbf00ff00 /* Number of calls implemented */
+#define TOS_UID			0xbf00ff01 /* Implementation UID */
+#define TOS_CALL_VERSION	0xbf00ff03 /* Trusted OS Call Version */
+
+#endif /* TLK_H */
diff --git a/include/bl32/sp_min/platform_sp_min.h b/include/bl32/sp_min/platform_sp_min.h
new file mode 100644
index 0000000..971f661
--- /dev/null
+++ b/include/bl32/sp_min/platform_sp_min.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_SP_MIN_H
+#define PLATFORM_SP_MIN_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Mandatory SP_MIN functions
+ ******************************************************************************/
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3);
+void sp_min_platform_setup(void);
+void sp_min_plat_runtime_setup(void);
+void sp_min_plat_arch_setup(void);
+entry_point_info_t *sp_min_plat_get_bl33_ep_info(void);
+void sp_min_warm_entrypoint(void);
+
+/* Platforms that enable SP_MIN_WITH_SECURE_FIQ shall implement this api */
+void sp_min_plat_fiq_handler(uint32_t id);
+
+#endif /* PLATFORM_SP_MIN_H */
diff --git a/include/bl32/tsp/platform_tsp.h b/include/bl32/tsp/platform_tsp.h
new file mode 100644
index 0000000..fe8a2c9
--- /dev/null
+++ b/include/bl32/tsp/platform_tsp.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_TSP_H
+#define PLATFORM_TSP_H
+
+/*******************************************************************************
+ * Mandatory TSP functions (only if platform contains a TSP)
+ ******************************************************************************/
+void tsp_early_platform_setup(void);
+void tsp_plat_arch_setup(void);
+void tsp_platform_setup(void);
+
+#endif /* PLATFORM_TSP_H */
diff --git a/include/bl32/tsp/tsp.h b/include/bl32/tsp/tsp.h
new file mode 100644
index 0000000..637e14a
--- /dev/null
+++ b/include/bl32/tsp/tsp.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TSP_H
+#define TSP_H
+
+/*
+ * SMC function IDs that TSP uses to signal various forms of completions
+ * to the secure payload dispatcher.
+ */
+#define TSP_ENTRY_DONE		0xf2000000
+#define TSP_ON_DONE		0xf2000001
+#define TSP_OFF_DONE		0xf2000002
+#define TSP_SUSPEND_DONE	0xf2000003
+#define TSP_RESUME_DONE		0xf2000004
+#define TSP_PREEMPTED		0xf2000005
+#define TSP_ABORT_DONE		0xf2000007
+#define TSP_SYSTEM_OFF_DONE	0xf2000008
+#define TSP_SYSTEM_RESET_DONE	0xf2000009
+
+/*
+ * Function identifiers to handle S-EL1 interrupt through the synchronous
+ * handling model. If the TSP was previously interrupted then control has to
+ * be returned to the TSPD after handling the interrupt else execution can
+ * remain in the TSP.
+ */
+#define TSP_HANDLED_S_EL1_INTR		0xf2000006
+
+/* SMC function ID that TSP uses to request service from secure monitor */
+#define TSP_GET_ARGS		0xf2001000
+
+/*
+ * Identifiers for various TSP services. Corresponding function IDs (whether
+ * fast or yielding) are generated by macros defined below
+ */
+#define TSP_ADD		0x2000
+#define TSP_SUB		0x2001
+#define TSP_MUL		0x2002
+#define TSP_DIV		0x2003
+#define TSP_HANDLE_SEL1_INTR_AND_RETURN	0x2004
+
+/*
+ * Identify a TSP service from function ID filtering the last 16 bits from the
+ * SMC function ID
+ */
+#define TSP_BARE_FID(fid)	((fid) & 0xffff)
+
+/*
+ * Generate function IDs for TSP services to be used in SMC calls, by
+ * appropriately setting bit 31 to differentiate yielding and fast SMC calls
+ */
+#define TSP_YIELD_FID(fid)	((TSP_BARE_FID(fid) | 0x72000000))
+#define TSP_FAST_FID(fid)	((TSP_BARE_FID(fid) | 0x72000000) | (1u << 31))
+
+/* SMC function ID to request a previously preempted yielding smc */
+#define TSP_FID_RESUME		TSP_YIELD_FID(0x3000)
+/*
+ * SMC function ID to request abortion of a previously preempted yielding SMC. A
+ * fast SMC is used so that the TSP abort handler does not have to be
+ * reentrant.
+ */
+#define TSP_FID_ABORT		TSP_FAST_FID(0x3001)
+
+/*
+ * Total number of function IDs implemented for services offered to NS clients.
+ * The function IDs are defined above
+ */
+#define TSP_NUM_FID		0x5
+
+/* TSP implementation version numbers */
+#define TSP_VERSION_MAJOR	0x0 /* Major version */
+#define TSP_VERSION_MINOR	0x1 /* Minor version */
+
+/*
+ * Standard Trusted OS Function IDs that fall under Trusted OS call range
+ * according to SMC calling convention
+ */
+#define TOS_CALL_COUNT		0xbf00ff00 /* Number of calls implemented */
+#define TOS_UID			0xbf00ff01 /* Implementation UID */
+/*				0xbf00ff02 is reserved */
+#define TOS_CALL_VERSION	0xbf00ff03 /* Trusted OS Call Version */
+
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+
+typedef uint32_t tsp_vector_isn_t;
+
+typedef struct tsp_vectors {
+	tsp_vector_isn_t yield_smc_entry;
+	tsp_vector_isn_t fast_smc_entry;
+	tsp_vector_isn_t cpu_on_entry;
+	tsp_vector_isn_t cpu_off_entry;
+	tsp_vector_isn_t cpu_resume_entry;
+	tsp_vector_isn_t cpu_suspend_entry;
+	tsp_vector_isn_t sel1_intr_entry;
+	tsp_vector_isn_t system_off_entry;
+	tsp_vector_isn_t system_reset_entry;
+	tsp_vector_isn_t abort_yield_smc_entry;
+} tsp_vectors_t;
+
+void tsp_setup(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* TSP_H */
diff --git a/include/common/asm_macros_common.S b/include/common/asm_macros_common.S
new file mode 100644
index 0000000..fd0ea81
--- /dev/null
+++ b/include/common/asm_macros_common.S
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ASM_MACROS_COMMON_S
+#define ASM_MACROS_COMMON_S
+
+	/*
+	 * This macro is used to create a function label and place the
+	 * code into a separate text section based on the function name
+	 * to enable elimination of unused code during linking. It also adds
+	 * basic debug information to enable call stack printing most of the
+	 * time. The optional _align parameter can be used to force a
+	 * non-standard alignment (indicated in powers of 2). The default is
+	 * _align=2 because both Aarch32 and Aarch64 instructions must be
+	 * word aligned. Do *not* try to use a raw .align directive. Since func
+	 * switches to a new section, this would not have the desired effect.
+	 */
+	.macro func _name, _align=2
+	/*
+	 * Add Call Frame Information entry in the .debug_frame section for
+	 * debugger consumption. This enables callstack printing in debuggers.
+	 * This does not use any space in the final loaded binary, only in the
+	 * ELF file.
+	 * Note that a function manipulating the CFA pointer location (i.e. the
+	 * x29 frame pointer on AArch64) should declare it using the
+	 * appropriate .cfi* directives, or be prepared to have a degraded
+	 * debugging experience.
+	 */
+	.cfi_sections .debug_frame
+	.section .text.asm.\_name, "ax"
+	.type \_name, %function
+	/*
+	 * .cfi_startproc and .cfi_endproc are needed to output entries in
+	 * .debug_frame
+	 */
+	.cfi_startproc
+	.align \_align
+	\_name:
+#if ENABLE_BTI
+	/* When Branch Target Identification is enabled, insert "bti jc"
+	 * instruction to enable indirect calls and branches
+	 */
+	 bti	jc
+#endif
+	.endm
+
+	/*
+	 * This macro is used to mark the end of a function.
+	 */
+	.macro endfunc _name
+	.cfi_endproc
+	.size \_name, . - \_name
+	.endm
+
+	/*
+	 * Theses macros are used to create function labels for deprecated
+	 * APIs. If ERROR_DEPRECATED is non zero, the callers of these APIs
+	 * will fail to link and cause build failure.
+	 */
+#if ERROR_DEPRECATED
+	.macro func_deprecated _name
+	func deprecated\_name
+	.endm
+
+	.macro endfunc_deprecated _name
+	endfunc deprecated\_name
+	.endm
+#else
+	.macro func_deprecated _name
+	func \_name
+	.endm
+
+	.macro endfunc_deprecated _name
+	endfunc \_name
+	.endm
+#endif
+
+	/*
+	 * Helper assembler macro to count trailing zeros. The output is
+	 * populated in the `TZ_COUNT` symbol.
+	 */
+	.macro count_tz _value, _tz_count
+	.if \_value
+	  count_tz "(\_value >> 1)", "(\_tz_count + 1)"
+	.else
+	  .equ TZ_COUNT, (\_tz_count - 1)
+	.endif
+	.endm
+
+	/*
+	 * This macro declares an array of 1 or more stacks, properly
+	 * aligned and in the requested section
+	 */
+#define DEFAULT_STACK_ALIGN	(1 << 6)   /* In case the caller doesnt provide alignment */
+
+	.macro declare_stack _name, _section, _size, _count, _align=DEFAULT_STACK_ALIGN
+	count_tz \_align, 0
+	.if (\_align - (1 << TZ_COUNT))
+	  .error "Incorrect stack alignment specified (Must be a power of 2)."
+	.endif
+	.if ((\_size & ((1 << TZ_COUNT) - 1)) <> 0)
+	  .error "Stack size not correctly aligned"
+	.endif
+	.section    \_section, "aw", %nobits
+	.align TZ_COUNT
+	\_name:
+	.space ((\_count) * (\_size)), 0
+	.endm
+
+
+#endif /* ASM_MACROS_COMMON_S */
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
new file mode 100644
index 0000000..896a03f
--- /dev/null
+++ b/include/common/bl_common.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL_COMMON_H
+#define BL_COMMON_H
+
+#include <common/ep_info.h>
+#include <common/param_header.h>
+#include <lib/utils_def.h>
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+#include <lib/cassert.h>
+#endif /* __ASSEMBLER__ */
+
+#include <export/common/bl_common_exp.h>
+
+#define UP	U(1)
+#define DOWN	U(0)
+
+/*******************************************************************************
+ * Constants to identify the location of a memory region in a given memory
+ * layout.
+******************************************************************************/
+#define TOP	U(0x1)
+#define BOTTOM	U(0x0)
+
+/*******************************************************************************
+ * Constants to indicate type of exception to the common exception handler.
+ ******************************************************************************/
+#define SYNC_EXCEPTION_SP_EL0		U(0x0)
+#define IRQ_SP_EL0			U(0x1)
+#define FIQ_SP_EL0			U(0x2)
+#define SERROR_SP_EL0			U(0x3)
+#define SYNC_EXCEPTION_SP_ELX		U(0x4)
+#define IRQ_SP_ELX			U(0x5)
+#define FIQ_SP_ELX			U(0x6)
+#define SERROR_SP_ELX			U(0x7)
+#define SYNC_EXCEPTION_AARCH64		U(0x8)
+#define IRQ_AARCH64			U(0x9)
+#define FIQ_AARCH64			U(0xa)
+#define SERROR_AARCH64			U(0xb)
+#define SYNC_EXCEPTION_AARCH32		U(0xc)
+#define IRQ_AARCH32			U(0xd)
+#define FIQ_AARCH32			U(0xe)
+#define SERROR_AARCH32			U(0xf)
+
+/*
+ * Mapping to connect linker symbols from .ld.S with their counterparts
+ * from .scat for the BL31 image
+ */
+#if defined(USE_ARM_LINK)
+#define __BL31_END__			Load$$LR$$LR_END$$Base
+#define __BSS_START__			Load$$LR$$LR_BSS$$Base
+#define __BSS_END__			Load$$LR$$LR_BSS$$Limit
+#define __BSS_SIZE__			Load$$LR$$LR_BSS$$Length
+#define __COHERENT_RAM_START__		Load$$LR$$LR_COHERENT_RAM$$Base
+#define __COHERENT_RAM_END_UNALIGNED__	Load$$__COHERENT_RAM_EPILOGUE_UNALIGNED__$$Base
+#define __COHERENT_RAM_END__		Load$$LR$$LR_COHERENT_RAM$$Limit
+#define __COHERENT_RAM_UNALIGNED_SIZE__	Load$$__COHERENT_RAM__$$Length
+#define __CPU_OPS_START__		Load$$__CPU_OPS__$$Base
+#define __CPU_OPS_END__			Load$$__CPU_OPS__$$Limit
+#define __DATA_START__			Load$$__DATA__$$Base
+#define __DATA_END__			Load$$__DATA__$$Limit
+#define __GOT_START__			Load$$__GOT__$$Base
+#define __GOT_END__			Load$$__GOT__$$Limit
+#define __PERCPU_BAKERY_LOCK_START__	Load$$__BAKERY_LOCKS__$$Base
+#define __PERCPU_BAKERY_LOCK_END__	Load$$__BAKERY_LOCKS_EPILOGUE__$$Base
+#define __PMF_SVC_DESCS_START__		Load$$__PMF_SVC_DESCS__$$Base
+#define __PMF_SVC_DESCS_END__		Load$$__PMF_SVC_DESCS__$$Limit
+#define __PMF_TIMESTAMP_START__		Load$$__PMF_TIMESTAMP__$$Base
+#define __PMF_TIMESTAMP_END__		Load$$__PER_CPU_TIMESTAMPS__$$Limit
+#define __PMF_PERCPU_TIMESTAMP_END__	Load$$__PMF_TIMESTAMP_EPILOGUE__$$Base
+#define __RELA_END__			Load$$__RELA__$$Limit
+#define __RELA_START__			Load$$__RELA__$$Base
+#define __RODATA_START__		Load$$__RODATA__$$Base
+#define __RODATA_END__			Load$$__RODATA_EPILOGUE__$$Base
+#define __RT_SVC_DESCS_START__		Load$$__RT_SVC_DESCS__$$Base
+#define __RT_SVC_DESCS_END__		Load$$__RT_SVC_DESCS__$$Limit
+#define __RW_START__			Load$$LR$$LR_RW_DATA$$Base
+#define __RW_END__			Load$$LR$$LR_END$$Base
+#define __SPM_SHIM_EXCEPTIONS_START__	Load$$__SPM_SHIM_EXCEPTIONS__$$Base
+#define __SPM_SHIM_EXCEPTIONS_END__	Load$$__SPM_SHIM_EXCEPTIONS_EPILOGUE__$$Base
+#define __STACKS_START__		Load$$__STACKS__$$Base
+#define __STACKS_END__			Load$$__STACKS__$$Limit
+#define __TEXT_START__			Load$$__TEXT__$$Base
+#define __TEXT_END__			Load$$__TEXT_EPILOGUE__$$Base
+#endif /* USE_ARM_LINK */
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Declarations of linker defined symbols to help determine memory layout of
+ * BL images
+ */
+#if SEPARATE_CODE_AND_RODATA
+IMPORT_SYM(uintptr_t, __TEXT_START__,		BL_CODE_BASE);
+IMPORT_SYM(uintptr_t, __TEXT_END__,		BL_CODE_END);
+IMPORT_SYM(uintptr_t, __RODATA_START__,		BL_RO_DATA_BASE);
+IMPORT_SYM(uintptr_t, __RODATA_END__,		BL_RO_DATA_END);
+#else
+IMPORT_SYM(uintptr_t, __RO_START__,		BL_CODE_BASE);
+IMPORT_SYM(uintptr_t, __RO_END__,		BL_CODE_END);
+#endif
+
+#if defined(IMAGE_BL1)
+IMPORT_SYM(uintptr_t, __BL1_ROM_END__,		BL1_ROM_END);
+
+IMPORT_SYM(uintptr_t, __BL1_RAM_START__,	BL1_RAM_BASE);
+IMPORT_SYM(uintptr_t, __BL1_RAM_END__,		BL1_RAM_LIMIT);
+#elif defined(IMAGE_BL2)
+IMPORT_SYM(uintptr_t, __BL2_END__,		BL2_END);
+#elif defined(IMAGE_BL2U)
+IMPORT_SYM(uintptr_t, __BL2U_END__,		BL2U_END);
+#elif defined(IMAGE_BL31)
+IMPORT_SYM(uintptr_t, __BL31_START__,		BL31_START);
+IMPORT_SYM(uintptr_t, __BL31_END__,		BL31_END);
+#elif defined(IMAGE_BL32)
+IMPORT_SYM(uintptr_t, __BL32_END__,		BL32_END);
+#endif /* IMAGE_BLX */
+
+/* The following symbols are only exported from the BL2 at EL3 linker script. */
+#if BL2_IN_XIP_MEM && defined(IMAGE_BL2)
+IMPORT_SYM(uintptr_t, __BL2_ROM_END__,		BL2_ROM_END);
+
+IMPORT_SYM(uintptr_t, __BL2_RAM_START__,	BL2_RAM_BASE);
+IMPORT_SYM(uintptr_t, __BL2_RAM_END__,		BL2_RAM_END);
+#endif /* BL2_IN_XIP_MEM */
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#if USE_COHERENT_MEM
+IMPORT_SYM(uintptr_t, __COHERENT_RAM_START__,	BL_COHERENT_RAM_BASE);
+IMPORT_SYM(uintptr_t, __COHERENT_RAM_END__,	BL_COHERENT_RAM_END);
+#endif
+
+/*******************************************************************************
+ * Structure used for telling the next BL how much of a particular type of
+ * memory is available for its use and how much is already used.
+ ******************************************************************************/
+typedef struct meminfo {
+	uintptr_t total_base;
+	size_t total_size;
+} meminfo_t;
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+int load_auth_image(unsigned int image_id, image_info_t *image_data);
+
+#if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH)
+/*
+ * API to dynamically disable authentication. Only meant for development
+ * systems.
+ */
+void dyn_disable_auth(void);
+#endif
+
+extern const char build_message[];
+extern const char version_string[];
+
+void print_entry_point_info(const entry_point_info_t *ep_info);
+uintptr_t page_align(uintptr_t value, unsigned dir);
+
+struct mmap_region;
+
+void setup_page_tables(const struct mmap_region *bl_regions,
+			   const struct mmap_region *plat_regions);
+
+void bl_handle_pauth(void);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* BL_COMMON_H */
diff --git a/include/common/debug.h b/include/common/debug.h
new file mode 100644
index 0000000..245e698
--- /dev/null
+++ b/include/common/debug.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <lib/utils_def.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			U(0)
+#define LOG_LEVEL_ERROR			U(10)
+#define LOG_LEVEL_NOTICE		U(20)
+#define LOG_LEVEL_WARNING		U(30)
+#define LOG_LEVEL_INFO			U(40)
+#define LOG_LEVEL_VERBOSE		U(50)
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <drivers/console.h>
+
+/*
+ * Define Log Markers corresponding to each log level which will
+ * be embedded in the format string and is expected by tf_log() to determine
+ * the log level.
+ */
+#define LOG_MARKER_ERROR		"\xa"	/* 10 */
+#define LOG_MARKER_NOTICE		"\x14"	/* 20 */
+#define LOG_MARKER_WARNING		"\x1e"	/* 30 */
+#define LOG_MARKER_INFO			"\x28"	/* 40 */
+#define LOG_MARKER_VERBOSE		"\x32"	/* 50 */
+
+/*
+ * If the log output is too low then this macro is used in place of tf_log()
+ * below. The intent is to get the compiler to evaluate the function call for
+ * type checking and format specifier correctness but let it optimize it out.
+ */
+#define no_tf_log(fmt, ...)				\
+	do {						\
+		if (false) {				\
+			tf_log(fmt, ##__VA_ARGS__);	\
+		}					\
+	} while (false)
+
+#if LOG_LEVEL >= LOG_LEVEL_ERROR
+# define ERROR(...)	tf_log(LOG_MARKER_ERROR __VA_ARGS__)
+#else
+# define ERROR(...)	no_tf_log(LOG_MARKER_ERROR __VA_ARGS__)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+# define NOTICE(...)	tf_log(LOG_MARKER_NOTICE __VA_ARGS__)
+#else
+# define NOTICE(...)	no_tf_log(LOG_MARKER_NOTICE __VA_ARGS__)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_WARNING
+# define WARN(...)	tf_log(LOG_MARKER_WARNING __VA_ARGS__)
+#else
+# define WARN(...)	no_tf_log(LOG_MARKER_WARNING __VA_ARGS__)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+# define INFO(...)	tf_log(LOG_MARKER_INFO __VA_ARGS__)
+#else
+# define INFO(...)	no_tf_log(LOG_MARKER_INFO __VA_ARGS__)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+# define VERBOSE(...)	tf_log(LOG_MARKER_VERBOSE __VA_ARGS__)
+#else
+# define VERBOSE(...)	no_tf_log(LOG_MARKER_VERBOSE __VA_ARGS__)
+#endif
+
+#if ENABLE_BACKTRACE
+void backtrace(const char *cookie);
+#else
+#define backtrace(x)
+#endif
+
+void __dead2 do_panic(void);
+
+#define panic()				\
+	do {				\
+		backtrace(__func__);	\
+		(void)console_flush();	\
+		do_panic();		\
+	} while (false)
+
+/* Function called when stack protection check code detects a corrupted stack */
+void __dead2 __stack_chk_fail(void);
+
+void tf_log(const char *fmt, ...) __printflike(1, 2);
+void tf_log_set_max_level(unsigned int log_level);
+
+#endif /* __ASSEMBLER__ */
+#endif /* DEBUG_H */
diff --git a/include/common/desc_image_load.h b/include/common/desc_image_load.h
new file mode 100644
index 0000000..b044f3e
--- /dev/null
+++ b/include/common/desc_image_load.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef DESC_IMAGE_LOAD_H
+#define DESC_IMAGE_LOAD_H
+
+#include <common/bl_common.h>
+
+/* Following structure is used to store BL ep/image info. */
+typedef struct bl_mem_params_node {
+	unsigned int image_id;
+	image_info_t image_info;
+	entry_point_info_t ep_info;
+	unsigned int next_handoff_image_id;
+	bl_load_info_node_t load_node_mem;
+	bl_params_node_t params_node_mem;
+} bl_mem_params_node_t;
+
+extern bl_mem_params_node_t *bl_mem_params_desc_ptr;
+extern unsigned int bl_mem_params_desc_num;
+
+/*
+ * Macro to register list of BL image descriptors,
+ * defined as an array of bl_mem_params_node_t.
+ */
+#define REGISTER_BL_IMAGE_DESCS(_img_desc)				\
+	bl_mem_params_node_t *bl_mem_params_desc_ptr = &_img_desc[0];	\
+	unsigned int bl_mem_params_desc_num = ARRAY_SIZE(_img_desc);
+
+/* BL image loading utility functions */
+void flush_bl_params_desc(void);
+void flush_bl_params_desc_args(bl_mem_params_node_t *mem_params_desc_ptr,
+	unsigned int mem_params_desc_num,
+	bl_params_t *next_bl_params_ptr);
+int get_bl_params_node_index(unsigned int image_id);
+bl_mem_params_node_t *get_bl_mem_params_node(unsigned int image_id);
+bl_load_info_t *get_bl_load_info_from_mem_params_desc(void);
+bl_params_t *get_next_bl_params_from_mem_params_desc(void);
+void populate_next_bl_params_config(bl_params_t *bl2_to_next_bl_params);
+
+/* Helper to extract BL32/BL33 entry point info from arg0 passed to BL31. */
+void bl31_params_parse_helper(u_register_t param,
+			      entry_point_info_t *bl32_ep_info_out,
+			      entry_point_info_t *bl33_ep_info_out);
+
+#endif /* DESC_IMAGE_LOAD_H */
diff --git a/include/common/ep_info.h b/include/common/ep_info.h
new file mode 100644
index 0000000..4bfa1fa
--- /dev/null
+++ b/include/common/ep_info.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EP_INFO_H
+#define EP_INFO_H
+
+#include <common/param_header.h>
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#include <lib/cassert.h>
+#endif /* __ASSEMBLER__ */
+
+#include <export/common/ep_info_exp.h>
+
+#define SECURE		EP_SECURE
+#define NON_SECURE	EP_NON_SECURE
+#define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
+
+#define PARAM_EP_SECURITY_MASK	EP_SECURITY_MASK
+
+#define NON_EXECUTABLE	EP_NON_EXECUTABLE
+#define EXECUTABLE	EP_EXECUTABLE
+
+/* Secure or Non-secure image */
+#define GET_SECURITY_STATE(x) ((x) & EP_SECURITY_MASK)
+#define SET_SECURITY_STATE(x, security) \
+			((x) = ((x) & ~EP_SECURITY_MASK) | (security))
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Compile time assertions related to the 'entry_point_info' structure to
+ * ensure that the assembler and the compiler view of the offsets of
+ * the structure members is the same.
+ */
+CASSERT(ENTRY_POINT_INFO_PC_OFFSET ==
+		__builtin_offsetof(entry_point_info_t, pc), \
+		assert_BL31_pc_offset_mismatch);
+
+#ifndef __aarch64__
+CASSERT(ENTRY_POINT_INFO_LR_SVC_OFFSET ==
+		__builtin_offsetof(entry_point_info_t, lr_svc),
+		assert_entrypoint_lr_offset_error);
+#endif
+
+CASSERT(ENTRY_POINT_INFO_ARGS_OFFSET == \
+		__builtin_offsetof(entry_point_info_t, args), \
+		assert_BL31_args_offset_mismatch);
+
+CASSERT(sizeof(uintptr_t) ==
+		__builtin_offsetof(entry_point_info_t, spsr) - \
+		__builtin_offsetof(entry_point_info_t, pc), \
+		assert_entrypoint_and_spsr_should_be_adjacent);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* EP_INFO_H */
diff --git a/include/common/fdt_wrappers.h b/include/common/fdt_wrappers.h
new file mode 100644
index 0000000..79d001d
--- /dev/null
+++ b/include/common/fdt_wrappers.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Helper functions to offer easier navigation of Device Tree Blob */
+
+#ifndef FDT_WRAPPERS_H
+#define FDT_WRAPPERS_H
+
+/* Number of cells, given total length in bytes. Each cell is 4 bytes long */
+#define NCELLS(len) ((len) / 4U)
+
+int fdtw_read_cells(const void *dtb, int node, const char *prop,
+		unsigned int cells, void *value);
+int fdtw_read_array(const void *dtb, int node, const char *prop,
+		unsigned int cells, void *value);
+int fdtw_read_string(const void *dtb, int node, const char *prop,
+		char *str, size_t size);
+int fdtw_write_inplace_cells(void *dtb, int node, const char *prop,
+		unsigned int cells, void *value);
+
+#endif /* FDT_WRAPPERS_H */
diff --git a/include/common/image_decompress.h b/include/common/image_decompress.h
new file mode 100644
index 0000000..bb35c3b
--- /dev/null
+++ b/include/common/image_decompress.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMAGE_DECOMPRESS_H
+#define IMAGE_DECOMPRESS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct image_info;
+
+typedef int (decompressor_t)(uintptr_t *in_buf, size_t in_len,
+			     uintptr_t *out_buf, size_t out_len,
+			     uintptr_t work_buf, size_t work_len);
+
+void image_decompress_init(uintptr_t buf_base, uint32_t buf_size,
+			   decompressor_t *decompressor);
+void image_decompress_prepare(struct image_info *info);
+int image_decompress(struct image_info *info);
+
+#endif /* IMAGE_DECOMPRESS_H */
diff --git a/include/common/interrupt_props.h b/include/common/interrupt_props.h
new file mode 100644
index 0000000..07bafaa
--- /dev/null
+++ b/include/common/interrupt_props.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INTERRUPT_PROPS_H
+#define INTERRUPT_PROPS_H
+
+#ifndef __ASSEMBLER__
+
+/* Create an interrupt property descriptor from various interrupt properties */
+#define INTR_PROP_DESC(num, pri, grp, cfg) \
+	{ \
+		.intr_num = (num), \
+		.intr_pri = (pri), \
+		.intr_grp = (grp), \
+		.intr_cfg = (cfg), \
+	}
+
+typedef struct interrupt_prop {
+	unsigned int intr_num:10;
+	unsigned int intr_pri:8;
+	unsigned int intr_grp:2;
+	unsigned int intr_cfg:2;
+} interrupt_prop_t;
+
+#endif /* __ASSEMBLER__ */
+#endif /* INTERRUPT_PROPS_H */
diff --git a/include/common/param_header.h b/include/common/param_header.h
new file mode 100644
index 0000000..4dab4e3
--- /dev/null
+++ b/include/common/param_header.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PARAM_HEADER_H
+#define PARAM_HEADER_H
+
+#include <stdbool.h>
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /*__ASSEMBLER__*/
+
+#include <export/common/param_header_exp.h>
+
+#define VERSION_1	PARAM_VERSION_1
+#define VERSION_2	PARAM_VERSION_2
+
+#define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \
+	(_p)->h.type = (uint8_t)(_type); \
+	(_p)->h.version = (uint8_t)(_ver); \
+	(_p)->h.size = (uint16_t)sizeof(*(_p)); \
+	(_p)->h.attr = (uint32_t)(_attr) ; \
+	} while (false)
+
+/* Following is used for populating structure members statically. */
+#define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr)	\
+	._p.h.type = (uint8_t)(_type), \
+	._p.h.version = (uint8_t)(_ver), \
+	._p.h.size = (uint16_t)sizeof(_p_type), \
+	._p.h.attr = (uint32_t)(_attr)
+
+#endif /* PARAM_HEADER_H */
diff --git a/include/common/romlib.h b/include/common/romlib.h
new file mode 100644
index 0000000..7f53c47
--- /dev/null
+++ b/include/common/romlib.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ROMLIB_H
+#define ROMLIB_H
+
+#define ROMLIB_MAJOR   0
+#define ROMLIB_MINOR   1
+#define ROMLIB_VERSION ((ROMLIB_MAJOR << 8) | ROMLIB_MINOR)
+
+int rom_lib_init(int version);
+
+#endif /* ROMLIB_H */
diff --git a/include/common/runtime_svc.h b/include/common/runtime_svc.h
new file mode 100644
index 0000000..472a32a
--- /dev/null
+++ b/include/common/runtime_svc.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RUNTIME_SVC_H
+#define RUNTIME_SVC_H
+
+#include <common/bl_common.h>		/* to include exception types */
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <smccc_helpers.h>	/* to include SMCCC definitions */
+
+/*******************************************************************************
+ * Structure definition, typedefs & constants for the runtime service framework
+ ******************************************************************************/
+
+/*
+ * Constants to allow the assembler access a runtime service
+ * descriptor
+ */
+#ifdef __aarch64__
+#define RT_SVC_SIZE_LOG2	U(5)
+#define RT_SVC_DESC_INIT	U(16)
+#define RT_SVC_DESC_HANDLE	U(24)
+#else
+#define RT_SVC_SIZE_LOG2	U(4)
+#define RT_SVC_DESC_INIT	U(8)
+#define RT_SVC_DESC_HANDLE	U(12)
+#endif /* __aarch64__ */
+#define SIZEOF_RT_SVC_DESC	(U(1) << RT_SVC_SIZE_LOG2)
+
+
+/*
+ * In SMCCC 1.X, the function identifier has 6 bits for the owning entity number
+ * and a single bit for the type of smc call. When taken together, those values
+ * limit the maximum number of runtime services to 128.
+ */
+#define MAX_RT_SVCS		U(128)
+
+#ifndef __ASSEMBLER__
+
+/* Prototype for runtime service initializing function */
+typedef int32_t (*rt_svc_init_t)(void);
+
+/*
+ * Prototype for runtime service SMC handler function. x0 (SMC Function ID) to
+ * x4 are as passed by the caller. Rest of the arguments to SMC and the context
+ * can be accessed using the handle pointer. The cookie parameter is reserved
+ * for future use
+ */
+typedef uintptr_t (*rt_svc_handle_t)(uint32_t smc_fid,
+				  u_register_t x1,
+				  u_register_t x2,
+				  u_register_t x3,
+				  u_register_t x4,
+				  void *cookie,
+				  void *handle,
+				  u_register_t flags);
+typedef struct rt_svc_desc {
+	uint8_t start_oen;
+	uint8_t end_oen;
+	uint8_t call_type;
+	const char *name;
+	rt_svc_init_t init;
+	rt_svc_handle_t handle;
+} rt_svc_desc_t;
+
+/*
+ * Convenience macros to declare a service descriptor
+ */
+#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch)	\
+	static const rt_svc_desc_t __svc_desc_ ## _name			\
+		__section("rt_svc_descs") __used = {			\
+			.start_oen = (_start),				\
+			.end_oen = (_end),				\
+			.call_type = (_type),				\
+			.name = #_name,					\
+			.init = (_setup),				\
+			.handle = (_smch)				\
+		}
+
+/*
+ * Compile time assertions related to the 'rt_svc_desc' structure to:
+ * 1. ensure that the assembler and the compiler view of the size
+ *    of the structure are the same.
+ * 2. ensure that the assembler and the compiler see the initialisation
+ *    routine at the same offset.
+ * 3. ensure that the assembler and the compiler see the handler
+ *    routine at the same offset.
+ */
+CASSERT((sizeof(rt_svc_desc_t) == SIZEOF_RT_SVC_DESC), \
+	assert_sizeof_rt_svc_desc_mismatch);
+CASSERT(RT_SVC_DESC_INIT == __builtin_offsetof(rt_svc_desc_t, init), \
+	assert_rt_svc_desc_init_offset_mismatch);
+CASSERT(RT_SVC_DESC_HANDLE == __builtin_offsetof(rt_svc_desc_t, handle), \
+	assert_rt_svc_desc_handle_offset_mismatch);
+
+
+/*
+ * This function combines the call type and the owning entity number
+ * corresponding to a runtime service to generate a unique owning entity number.
+ * This unique oen is used to access an entry in the 'rt_svc_descs_indices'
+ * array. The entry contains the index of the service descriptor in the
+ * 'rt_svc_descs' array.
+ */
+static inline uint32_t get_unique_oen(uint32_t oen, uint32_t call_type)
+{
+	return ((call_type & FUNCID_TYPE_MASK) << FUNCID_OEN_WIDTH) |
+		(oen & FUNCID_OEN_MASK);
+}
+
+/*
+ * This function generates the unique owning entity number from the SMC Function
+ * ID. This unique oen is used to access an entry in the 'rt_svc_descs_indices'
+ * array to invoke the corresponding runtime service handler during SMC
+ * handling.
+ */
+static inline uint32_t get_unique_oen_from_smc_fid(uint32_t fid)
+{
+	return get_unique_oen(GET_SMC_OEN(fid), GET_SMC_TYPE(fid));
+}
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+void runtime_svc_init(void);
+uintptr_t handle_runtime_svc(uint32_t smc_fid, void *cookie, void *handle,
+						unsigned int flags);
+IMPORT_SYM(uintptr_t, __RT_SVC_DESCS_START__,		RT_SVC_DESCS_START);
+IMPORT_SYM(uintptr_t, __RT_SVC_DESCS_END__,		RT_SVC_DESCS_END);
+void init_crash_reporting(void);
+
+extern uint8_t rt_svc_descs_indices[MAX_RT_SVCS];
+
+#endif /*__ASSEMBLER__*/
+#endif /* RUNTIME_SVC_H */
diff --git a/include/common/tbbr/cot_def.h b/include/common/tbbr/cot_def.h
new file mode 100644
index 0000000..33350a0
--- /dev/null
+++ b/include/common/tbbr/cot_def.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef COT_DEF_H
+#define COT_DEF_H
+
+/* TBBR CoT definitions */
+
+#define COT_MAX_VERIFIED_PARAMS		4
+
+#endif /* COT_DEF_H */
diff --git a/include/common/tbbr/tbbr_img_def.h b/include/common/tbbr/tbbr_img_def.h
new file mode 100644
index 0000000..1701995
--- /dev/null
+++ b/include/common/tbbr/tbbr_img_def.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_IMG_DEF_H
+#define TBBR_IMG_DEF_H
+
+#include <export/common/tbbr/tbbr_img_def_exp.h>
+
+#endif /* TBBR_IMG_DEF_H */
diff --git a/include/drivers/allwinner/sunxi_rsb.h b/include/drivers/allwinner/sunxi_rsb.h
new file mode 100644
index 0000000..3d003ce
--- /dev/null
+++ b/include/drivers/allwinner/sunxi_rsb.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_RSB_H
+#define SUNXI_RSB_H
+
+#include <stdint.h>
+
+int rsb_init_controller(void);
+int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq);
+int rsb_set_device_mode(uint32_t device_mode);
+int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr);
+
+int rsb_read(uint8_t rt_addr, uint8_t reg_addr);
+int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value);
+
+#endif /* SUNXI_RSB_H */
diff --git a/include/drivers/arm/arm_gicv3_common.h b/include/drivers/arm/arm_gicv3_common.h
new file mode 100644
index 0000000..b88b59f
--- /dev/null
+++ b/include/drivers/arm/arm_gicv3_common.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_GICV3_COMMON_H
+#define ARM_GICV3_COMMON_H
+
+/*******************************************************************************
+ * GIC500/GIC600 Re-distributor interface registers & constants
+ ******************************************************************************/
+
+/* GICR_WAKER implementation-defined bit definitions */
+#define	WAKER_SL_SHIFT		0
+#define	WAKER_QSC_SHIFT		31
+
+#define WAKER_SL_BIT		(1U << WAKER_SL_SHIFT)
+#define WAKER_QSC_BIT		(1U << WAKER_QSC_SHIFT)
+
+#endif /* ARM_GICV3_COMMON_H */
diff --git a/include/drivers/arm/cci.h b/include/drivers/arm/cci.h
new file mode 100644
index 0000000..5aea95a
--- /dev/null
+++ b/include/drivers/arm/cci.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CCI_H
+#define CCI_H
+
+#include <lib/utils_def.h>
+
+/* Slave interface offsets from PERIPHBASE */
+#define SLAVE_IFACE6_OFFSET		UL(0x7000)
+#define SLAVE_IFACE5_OFFSET		UL(0x6000)
+#define SLAVE_IFACE4_OFFSET		UL(0x5000)
+#define SLAVE_IFACE3_OFFSET		UL(0x4000)
+#define SLAVE_IFACE2_OFFSET		UL(0x3000)
+#define SLAVE_IFACE1_OFFSET		UL(0x2000)
+#define SLAVE_IFACE0_OFFSET		UL(0x1000)
+#define SLAVE_IFACE_OFFSET(index)	(SLAVE_IFACE0_OFFSET + \
+					(UL(0x1000) * (index)))
+
+/* Slave interface event and count register offsets from PERIPHBASE */
+#define EVENT_SELECT7_OFFSET		UL(0x80000)
+#define EVENT_SELECT6_OFFSET		UL(0x70000)
+#define EVENT_SELECT5_OFFSET		UL(0x60000)
+#define EVENT_SELECT4_OFFSET		UL(0x50000)
+#define EVENT_SELECT3_OFFSET		UL(0x40000)
+#define EVENT_SELECT2_OFFSET		UL(0x30000)
+#define EVENT_SELECT1_OFFSET		UL(0x20000)
+#define EVENT_SELECT0_OFFSET		UL(0x10000)
+#define EVENT_OFFSET(index)		(EVENT_SELECT0_OFFSET + \
+					(UL(0x10000) * (index)))
+
+/* Control and ID register offsets */
+#define CTRL_OVERRIDE_REG		U(0x0)
+#define SECURE_ACCESS_REG		U(0x8)
+#define STATUS_REG			U(0xc)
+#define IMPRECISE_ERR_REG		U(0x10)
+#define PERFMON_CTRL_REG		U(0x100)
+#define IFACE_MON_CTRL_REG		U(0x104)
+
+/* Component and peripheral ID registers */
+#define PERIPHERAL_ID0			U(0xFE0)
+#define PERIPHERAL_ID1			U(0xFE4)
+#define PERIPHERAL_ID2			U(0xFE8)
+#define PERIPHERAL_ID3			U(0xFEC)
+#define PERIPHERAL_ID4			U(0xFD0)
+#define PERIPHERAL_ID5			U(0xFD4)
+#define PERIPHERAL_ID6			U(0xFD8)
+#define PERIPHERAL_ID7			U(0xFDC)
+
+#define COMPONENT_ID0			U(0xFF0)
+#define COMPONENT_ID1			U(0xFF4)
+#define COMPONENT_ID2			U(0xFF8)
+#define COMPONENT_ID3			U(0xFFC)
+#define COMPONENT_ID4			U(0x1000)
+#define COMPONENT_ID5			U(0x1004)
+#define COMPONENT_ID6			U(0x1008)
+#define COMPONENT_ID7			U(0x100C)
+
+/* Slave interface register offsets */
+#define SNOOP_CTRL_REG			U(0x0)
+#define SH_OVERRIDE_REG			U(0x4)
+#define READ_CHNL_QOS_VAL_OVERRIDE_REG	U(0x100)
+#define WRITE_CHNL_QOS_VAL_OVERRIDE_REG	U(0x104)
+#define MAX_OT_REG			U(0x110)
+
+/* Snoop Control register bit definitions */
+#define DVM_EN_BIT			BIT_32(1)
+#define SNOOP_EN_BIT			BIT_32(0)
+#define SUPPORT_SNOOPS			BIT_32(30)
+#define SUPPORT_DVM			BIT_32(31)
+
+/* Status register bit definitions */
+#define CHANGE_PENDING_BIT		BIT_32(0)
+
+/* Event and count register offsets */
+#define EVENT_SELECT_REG		U(0x0)
+#define EVENT_COUNT_REG			U(0x4)
+#define COUNT_CNTRL_REG			U(0x8)
+#define COUNT_OVERFLOW_REG		U(0xC)
+
+/* Slave interface monitor registers */
+#define INT_MON_REG_SI0			U(0x90000)
+#define INT_MON_REG_SI1			U(0x90004)
+#define INT_MON_REG_SI2			U(0x90008)
+#define INT_MON_REG_SI3			U(0x9000C)
+#define INT_MON_REG_SI4			U(0x90010)
+#define INT_MON_REG_SI5			U(0x90014)
+#define INT_MON_REG_SI6			U(0x90018)
+
+/* Master interface monitor registers */
+#define INT_MON_REG_MI0			U(0x90100)
+#define INT_MON_REG_MI1			U(0x90104)
+#define INT_MON_REG_MI2			U(0x90108)
+#define INT_MON_REG_MI3			U(0x9010c)
+#define INT_MON_REG_MI4			U(0x90110)
+#define INT_MON_REG_MI5			U(0x90114)
+
+#define SLAVE_IF_UNUSED			-1
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/* Function declarations */
+
+/*
+ * The ARM CCI driver needs the following:
+ * 1. Base address of the CCI product
+ * 2. An array  of map between AMBA 4 master ids and ACE/ACE lite slave
+ *    interfaces.
+ * 3. Size of the array.
+ *
+ * SLAVE_IF_UNUSED should be used in the map to represent no AMBA 4 master exists
+ * for that interface.
+ */
+void cci_init(uintptr_t base, const int *map, unsigned int num_cci_masters);
+
+void cci_enable_snoop_dvm_reqs(unsigned int master_id);
+void cci_disable_snoop_dvm_reqs(unsigned int master_id);
+
+#endif /* __ASSEMBLER__ */
+#endif /* CCI_H */
diff --git a/include/drivers/arm/ccn.h b/include/drivers/arm/ccn.h
new file mode 100644
index 0000000..7f73768
--- /dev/null
+++ b/include/drivers/arm/ccn.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CCN_H
+#define CCN_H
+
+/*
+ * This macro defines the maximum number of master interfaces that reside on
+ * Request nodes which the CCN driver can accommodate. The driver APIs to add
+ * and remove Request nodes from snoop/dvm domains take a bit map of master
+ * interfaces as inputs. The largest C data type that can be used is a 64-bit
+ * unsigned integer. Hence the value of 64. The platform will have to ensure
+ * that the master interfaces are numbered from 0-63.
+ */
+#define CCN_MAX_RN_MASTERS	64
+
+/*
+ * The following constants define the various run modes that the platform can
+ * request the CCN driver to place the L3 cache in. These map to the
+ * programmable P-State values in a HN-F P-state register.
+ */
+#define CCN_L3_RUN_MODE_NOL3	0x0	/* HNF_PM_NOL3 */
+#define CCN_L3_RUN_MODE_SFONLY	0x1	/* HNF_PM_SFONLY */
+#define CCN_L3_RUN_MODE_HAM	0x2	/* HNF_PM_HALF */
+#define CCN_L3_RUN_MODE_FAM	0x3	/* HNF_PM_FULL */
+
+/* part 0 IDs for various CCN variants */
+#define CCN_502_PART0_ID	0x30
+#define CCN_504_PART0_ID	0x26
+#define CCN_505_PART0_ID	0x27
+#define CCN_508_PART0_ID	0x28
+#define CCN_512_PART0_ID	0x29
+
+/*
+ * The following macro takes the value returned from a read of a HN-F P-state
+ * status register and returns the retention state value.
+ */
+#define CCN_GET_RETENTION_STATE(pstate)	((pstate >> 4) & 0x3)
+
+/*
+ * The following macro takes the value returned from a read of a HN-F P-state
+ * status register and returns the run state value.
+ */
+#define CCN_GET_RUN_STATE(pstate)	(pstate & 0xf)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+/*
+ * This structure describes some of the implementation defined attributes of the
+ * CCN IP. It is used by the platform port to specify these attributes in order
+ * to initialise the CCN driver. The attributes are described below.
+ *
+ * 1. The 'num_masters' field specifies the total number of master interfaces
+ *    resident on Request nodes.
+ *
+ * 2. The 'master_to_rn_id_map' field is a ponter to an array in which each
+ *    index corresponds to a master interface and its value corresponds to the
+ *    Request node on which the master interface resides.
+ *    This field is not simply defined as an array of size CCN_MAX_RN_MASTERS.
+ *    In reality, a platform will have much fewer master * interfaces than
+ *    CCN_MAX_RN_MASTERS. With an array of this size, it would also have to
+ *    set the unused entries to a suitable value. Zeroing the array would not
+ *    be enough since 0 is also a valid node id. Hence, such an array is not
+ *    used.
+ *
+ * 3. The 'periphbase' field is the base address of the programmer's view of the
+ *    CCN IP.
+ */
+typedef struct ccn_desc {
+	unsigned int num_masters;
+	const unsigned char *master_to_rn_id_map;
+	uintptr_t periphbase;
+} ccn_desc_t;
+
+/* Enum used to loop through all types of nodes in CCN*/
+typedef enum node_types {
+	NODE_TYPE_RNF = 0,
+	NODE_TYPE_RNI,
+	NODE_TYPE_RND,
+	NODE_TYPE_HNF,
+	NODE_TYPE_HNI,
+	NODE_TYPE_SN,
+	NUM_NODE_TYPES
+} node_types_t;
+
+void ccn_init(const ccn_desc_t *plat_ccn_desc);
+void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map);
+void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map);
+void ccn_enter_dvm_domain(unsigned long long master_iface_map);
+void ccn_exit_dvm_domain(unsigned long long master_iface_map);
+void ccn_set_l3_run_mode(unsigned int mode);
+void ccn_program_sys_addrmap(unsigned int sn0_id,
+		 unsigned int sn1_id,
+		 unsigned int sn2_id,
+		 unsigned int top_addr_bit0,
+		 unsigned int top_addr_bit1,
+		 unsigned char three_sn_en);
+unsigned int ccn_get_l3_run_mode(void);
+int ccn_get_part0_id(uintptr_t periphbase);
+
+void ccn_write_node_reg(node_types_t node_type, unsigned int node_id,
+				unsigned int reg_offset,
+				unsigned long long val);
+unsigned long long ccn_read_node_reg(node_types_t node_type,
+					unsigned int node_id,
+					unsigned int reg_offset);
+
+#endif /* __ASSEMBLER__ */
+#endif /* CCN_H */
diff --git a/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h b/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h
new file mode 100644
index 0000000..2cb8938
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CC_CRYPTO_BOOT_DEFS_H
+#define _CC_CRYPTO_BOOT_DEFS_H
+
+/*! @file
+@brief This file contains SBROM definitions
+*/
+
+/*! Version counters value. */
+typedef enum {
+
+	CC_SW_VERSION_COUNTER1 = 1,	/*!< Counter 1 - trusted version. */
+	CC_SW_VERSION_COUNTER2,		/*!< Counter 2 - non trusted version. */
+
+	CC_SW_VERSION_MAX      = 0x7FFFFFFF
+
+} CCSbSwVersionId_t;
+
+/* HASH boot key definition */
+typedef enum {
+	CC_SB_HASH_BOOT_KEY_0_128B 	= 0,		/*!< 128-bit truncated SHA256 digest of public key 0. */
+	CC_SB_HASH_BOOT_KEY_1_128B	= 1,		/*!< 128-bit truncated SHA256 digest of public key 1. */
+	CC_SB_HASH_BOOT_KEY_256B	= 2,		/*!< 256-bit SHA256 digest of public key. */
+	CC_SB_HASH_BOOT_NOT_USED	= 0xFF,
+	CC_SB_HASH_MAX_NUM 		= 0x7FFFFFFF,	/*!\internal use external 128-bit truncated SHA256 digest */
+} CCSbPubKeyIndexType_t;
+
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h b/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h
new file mode 100644
index 0000000..212a710
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+@file
+@brief This file contains the platform-dependent definitions that are used in the SBROM code.
+*/
+
+#ifndef _CC_PAL_SB_PLAT_H
+#define _CC_PAL_SB_PLAT_H
+
+#include "cc_pal_types.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! Definition of DMA address type, can be 32 bits or 64 bits according to CryptoCell's HW. */
+typedef uint64_t		CCDmaAddr_t;
+/*! Definition of CryptoCell address type, can be 32 bits or 64 bits according to platform. */
+typedef uintptr_t		CCAddr_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/cc_pal_types.h b/include/drivers/arm/cryptocell/712/cc_pal_types.h
new file mode 100644
index 0000000..8c09b23
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_pal_types.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CC_PAL_TYPES_H
+#define CC_PAL_TYPES_H
+
+/*!
+@file
+@brief This file contains platform-dependent definitions and types.
+*/
+
+#include "cc_pal_types_plat.h"
+
+typedef enum {
+	CC_FALSE = 0,
+	CC_TRUE = 1
+} CCBool;
+
+#define CC_SUCCESS		0UL
+#define CC_FAIL			1UL
+
+#define CC_1K_SIZE_IN_BYTES	1024
+#define CC_BITS_IN_BYTE		8
+#define CC_BITS_IN_32BIT_WORD	32
+#define CC_32BIT_WORD_SIZE	(sizeof(uint32_t))
+
+#define CC_OK			CC_SUCCESS
+
+#define CC_UNUSED_PARAM(prm)	((void)prm)
+
+#define CC_MAX_UINT32_VAL	(0xFFFFFFFF)
+
+#define CALC_FULL_BYTES(numBits)		(((numBits) + (CC_BITS_IN_BYTE - 1))/CC_BITS_IN_BYTE)
+#define CALC_FULL_32BIT_WORDS(numBits)		(((numBits) + (CC_BITS_IN_32BIT_WORD - 1))/CC_BITS_IN_32BIT_WRD)
+#define CALC_32BIT_WORDS_FROM_BYTES(sizeBytes)	(((sizeBytes) + CC_32BIT_WORD_SIZE - 1)/CC_32BIT_WORD_SIZE)
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h b/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h
new file mode 100644
index 0000000..8410024
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*! @file
+@brief This file contains basic type definitions that are platform-dependent.
+*/
+#ifndef _CC_PAL_TYPES_PLAT_H
+#define _CC_PAL_TYPES_PLAT_H
+/* Host specific types for standard (ISO-C99) compilant platforms */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef uint32_t CCStatus;
+
+#define CCError_t	CCStatus
+#define CC_INFINITE	0xFFFFFFFF
+
+#define CEXPORT_C
+#define CIMPORT_C
+
+#endif /*_CC_PAL_TYPES_PLAT_H*/
diff --git a/include/drivers/arm/cryptocell/712/cc_sec_defs.h b/include/drivers/arm/cryptocell/712/cc_sec_defs.h
new file mode 100644
index 0000000..d419218
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/cc_sec_defs.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CC_SEC_DEFS_H
+#define _CC_SEC_DEFS_H
+
+/*!
+@file
+@brief This file contains general hash definitions and types.
+*/
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! The hashblock size in words. */
+#define HASH_BLOCK_SIZE_IN_WORDS             16
+/*! The hash - SHA2 results in words. */
+#define HASH_RESULT_SIZE_IN_WORDS            8
+#define HASH_RESULT_SIZE_IN_BYTES            32
+
+/*! Definition for hash result array. */
+typedef uint32_t CCHashResult_t[HASH_RESULT_SIZE_IN_WORDS];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/crypto_driver.h b/include/drivers/arm/cryptocell/712/crypto_driver.h
new file mode 100644
index 0000000..18104dd
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/crypto_driver.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CRYPTO_DRIVER_H
+#define _CRYPTO_DRIVER_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_pal_sb_plat.h"
+#include "cc_sec_defs.h"
+
+/*----------------------------
+      PUBLIC FUNCTIONS
+-----------------------------------*/
+/*!
+ * @brief This function gives the functionality of integrated hash
+ *
+ * @param[in] hwBaseAddress	- CryptoCell base address
+ * @param[out] hashResult	- the HASH result.
+ *
+ */
+CCError_t SBROM_CryptoHash(unsigned long hwBaseAddress, CCDmaAddr_t inputDataAddr, uint32_t BlockSize,
+				CCHashResult_t hashResult);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/nvm.h b/include/drivers/arm/cryptocell/712/nvm.h
new file mode 100644
index 0000000..a70289f
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/nvm.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _NVM__H
+#define _NVM__H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_crypto_boot_defs.h"
+#include "cc_pal_types.h"
+#include "cc_sec_defs.h"
+
+/*------------------------------------
+    DEFINES
+-------------------------------------*/
+
+/**
+ * @brief This function reads the LCS from the SRAM/NVM
+ *
+ * @param[in] hwBaseAddress  -  CryptoCell base address
+ *
+ * @param[in/out] lcs_ptr  - pointer to memory to store the LCS
+ *
+ * @return CCError_t - On success the value CC_OK is returned, and on failure   -a value from NVM_error.h
+ */
+CCError_t NVM_GetLCS(unsigned long hwBaseAddress, uint32_t *lcs_ptr);
+
+/**
+ * @brief The NVM_ReadHASHPubKey function is a NVM interface function -
+ *        The function retrieves the HASH of the device Public key from the SRAM/NVM
+ *
+ * @param[in] hwBaseAddress -  CryptoCell base address
+ *
+ * @param[in] pubKeyIndex -  Index of HASH in the OTP
+ *
+ * @param[out] PubKeyHASH   -  the public key HASH.
+ *
+ * @param[in] hashSizeInWords -  hash size (valid values: 4W, 8W)
+ *
+ * @return CCError_t - On success the value CC_OK is returned, and on failure   -a value from NVM_error.h
+ */
+
+CCError_t NVM_ReadHASHPubKey(unsigned long hwBaseAddress, CCSbPubKeyIndexType_t pubKeyIndex, CCHashResult_t PubKeyHASH, uint32_t hashSizeInWords);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/nvm_otp.h b/include/drivers/arm/cryptocell/712/nvm_otp.h
new file mode 100644
index 0000000..390d62b
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/nvm_otp.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _NVM_OTP_H
+#define _NVM_OTP_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_crypto_boot_defs.h"
+#include "cc_pal_types.h"
+
+/*------------------------------------
+    DEFINES
+-------------------------------------*/
+
+
+
+/**
+ * @brief The NVM_GetSwVersion function is a NVM interface function -
+ *        The function retrieves the SW version from the SRAM/NVM.
+ *        In case of OTP, we support up to 16 anti-rollback counters (taken from the certificate)
+ *
+ * @param[in] hwBaseAddress -  CryptoCell base address
+ *
+ * @param[in] counterId -  relevant only for OTP (valid values: 1,2)
+ *
+ * @param[out] swVersion   -  the minimum SW version
+ *
+ * @return CCError_t - On success the value CC_OK is returned, and on failure   -a value from NVM_error.h
+ */
+CCError_t NVM_GetSwVersion(unsigned long hwBaseAddress, CCSbSwVersionId_t counterId, uint32_t *swVersion);
+
+
+/**
+ * @brief The NVM_SetSwVersion function is a NVM interface function -
+ *        The function writes the SW version into the SRAM/NVM.
+ *        In case of OTP, we support up to 16 anti-rollback counters (taken from the certificate)
+ *
+ * @param[in] hwBaseAddress -  CryptoCell base address
+ *
+ * @param[in] counterId -  relevant only for OTP (valid values: 1,2)
+ *
+ * @param[in] swVersion   -  the minimum SW version
+ *
+ * @return CCError_t - On success the value CC_OK is returned, and on failure   -a value from NVM_error.h
+ */
+CCError_t NVM_SetSwVersion(unsigned long hwBaseAddress, CCSbSwVersionId_t counterId, uint32_t swVersion);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/rsa.h b/include/drivers/arm/cryptocell/712/rsa.h
new file mode 100644
index 0000000..cd9925b
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/rsa.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RSA_H
+#define RSA_H
+
+/*
+ * All the includes that are needed for code using this module to
+ * compile correctly should be #included here.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_pal_types.h"
+
+/************************ Defines ******************************/
+
+/* the modulus size ion bits */
+#define RSA_MOD_SIZE_IN_BITS				2048UL
+#define RSA_MOD_SIZE_IN_BYTES				(CALC_FULL_BYTES(RSA_MOD_SIZE_IN_BITS))
+#define RSA_MOD_SIZE_IN_WORDS				(CALC_FULL_32BIT_WORDS(RSA_MOD_SIZE_IN_BITS))
+#define RSA_MOD_SIZE_IN_256BITS				(RSA_MOD_SIZE_IN_WORDS/8)
+#define RSA_EXP_SIZE_IN_BITS				17UL
+#define RSA_EXP_SIZE_IN_BYTES				(CALC_FULL_BYTES(RSA_EXP_SIZE_IN_BITS))
+
+/* size of buffer for Barrett modulus tag NP, used in PKA algorithms */
+#define RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BITS	132
+#define RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BYTES	(CALC_FULL_BYTES(RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BITS))
+#define RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_WORDS	(CALC_FULL_32BIT_WORDS(RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BITS))
+
+/*
+ * @brief The RSA_CalcNp calculates Np value and saves it into Np_ptr:
+ *
+ *
+
+ * @param[in] hwBaseAddress -	HW base address. Relevant for HW
+ *				implementation, for SW it is ignored.
+ * @N_ptr[in]               -	The pointer to the modulus buffer.
+ * @Np_ptr[out]             -	pointer to Np vector buffer. Its size must be >= 160.
+ */
+void RSA_CalcNp(unsigned long hwBaseAddress,
+		uint32_t *N_ptr,
+		uint32_t *Np_ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h b/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h
new file mode 100644
index 0000000..de83546
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _SBROM_BSV_API_H
+#define _SBROM_BSV_API_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! @file
+@brief This file contains all SBROM library APIs and definitions.
+*/
+#include "cc_pal_types.h"
+
+/* Life cycle state definitions */
+#define CC_BSV_CHIP_MANUFACTURE_LCS		0x0 /*!< CM lifecycle value. */
+#define CC_BSV_DEVICE_MANUFACTURE_LCS		0x1 /*!< DM lifecycle value. */
+#define CC_BSV_SECURITY_DISABLED_LCS		0x3 /*!< SD lifecycle value. */
+#define CC_BSV_SECURE_LCS			0x5 /*!< Secure lifecycle value. */
+#define CC_BSV_RMA_LCS				0x7 /*!< RMA lifecycle value. */
+
+/*----------------------------
+      PUBLIC FUNCTIONS
+-----------------------------------*/
+
+/*!
+@brief This function should be the first ARM TrustZone CryptoCell TEE SBROM library API called.
+It verifies the HW product and version numbers.
+
+@return CC_OK	On success.
+@return A non-zero value from sbrom_bsv_error.h on failure.
+*/
+CCError_t CC_BsvSbromInit(
+	unsigned long hwBaseAddress 	/*!< [in] HW registers base address. */
+	);
+
+
+/*!
+@brief This function can be used for checking the LCS value, after CC_BsvLcsGetAndInit was called by the Boot ROM.
+
+@return CC_OK	On success.
+@return A non-zero value from sbrom_bsv_error.h on failure.
+*/
+CCError_t CC_BsvLcsGet(
+	unsigned long hwBaseAddress,	/*!< [in] HW registers base address. */
+	uint32_t *pLcs			/*!< [out] Returned lifecycle state. */
+	);
+
+/*!
+@brief This function retrieves the HW security lifecycle state, performs validity checks,
+and additional initializations in case the LCS is RMA (sets the Kce to fixed value).
+\note	Invalid LCS results in an error returned.
+In this case, the customer's code must completely disable the device.
+
+@return CC_OK	On success.
+@return A non-zero value from sbrom_bsv_error.h on failure.
+*/
+CCError_t CC_BsvLcsGetAndInit(
+	unsigned long hwBaseAddress,	/*!< [in] HW registers base address. */
+	uint32_t *pLcs		/*!< [out] Returned lifecycle state. */
+	);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/secureboot_base_func.h b/include/drivers/arm/cryptocell/712/secureboot_base_func.h
new file mode 100644
index 0000000..6db596e
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/secureboot_base_func.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _SECURE_BOOT_BASE_FUNC_H
+#define _SECURE_BOOT_BASE_FUNC_H
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cc_pal_types.h"
+#include "secureboot_gen_defs.h"
+
+
+/*----------------------------
+      PUBLIC FUNCTIONS
+-----------------------------------*/
+
+/**
+ * @brief This function calculates the HASH over the given data and than verify
+ *	  RSA signature on that hashed data
+ *
+ * @param[in] hwBaseAddr -  CryptoCell base address
+ * @param[in] pData - pointer to the data to be verified
+ * @param[in] pNParams - a pointer to the public key parameters
+ * @param[in] pSignature - a pointer to the signature structure
+ * @param[in] sizeOfData - size of the data to calculate the HASH on (in bytes)
+ * @param[in] RSAAlg - RSA algorithm to use
+ *
+ * @return CCError_t - On success the value CC_OK is returned,
+ *         on failure - a value from BootImagesVerifier_error.h
+ */
+CCError_t CCSbVerifySignature(unsigned long hwBaseAddress,
+				uint32_t *pData,
+				CCSbNParams_t *pNParams,
+				CCSbSignature_t *pSignature,
+				uint32_t sizeOfData,
+				CCSbRsaAlg_t RSAAlg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h b/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h
new file mode 100644
index 0000000..68b9ef8
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _SECURE_BOOT_GEN_DEFS_H
+#define _SECURE_BOOT_GEN_DEFS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*! @file
+@brief This file contains all of the definitions and structures that are used for the secure boot.
+*/
+
+#include "cc_pal_sb_plat.h"
+#include "cc_sec_defs.h"
+
+
+/* General definitions */
+/***********************/
+
+/*RSA definitions*/
+#define SB_RSA_MOD_SIZE_IN_WORDS		 64
+#define SB_RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_WORDS 5
+
+
+/*! Public key data structure. */
+typedef struct {
+	uint32_t N[SB_RSA_MOD_SIZE_IN_WORDS];				/*!< N public key, big endian representation. */
+	uint32_t Np[SB_RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_WORDS];	/*!< Np (Barrett n' value). */
+} CCSbNParams_t;
+
+/*! Signature structure. */
+typedef struct {
+	uint32_t sig[SB_RSA_MOD_SIZE_IN_WORDS];				/*!< RSA PSS signature. */
+} CCSbSignature_t;
+
+
+/********* Supported algorithms definitions ***********/
+
+/*! RSA supported algorithms */
+typedef enum {
+	RSA_PSS_2048           = 0x01,			/*!< RSA PSS 2048 after hash SHA 256 */
+	RSA_PKCS15_2048	       = 0x02,			/*!< RSA PKX15 */
+	RSA_Last               = 0x7FFFFFFF
+} CCSbRsaAlg_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/712/util.h b/include/drivers/arm/cryptocell/712/util.h
new file mode 100644
index 0000000..18fb599
--- /dev/null
+++ b/include/drivers/arm/cryptocell/712/util.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+/*
+ * All the includes that are needed for code using this module to
+ * compile correctly should be #included here.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/************************ Defines ******************************/
+
+/* invers the bytes on a word- used for output from HASH */
+#ifdef BIG__ENDIAN
+#define UTIL_INVERSE_UINT32_BYTES(val)	(val)
+#else
+#define UTIL_INVERSE_UINT32_BYTES(val) \
+	(((val) >> 24) | (((val) & 0x00FF0000) >> 8) | (((val) & 0x0000FF00) << 8) | (((val) & 0x000000FF) << 24))
+#endif
+
+/* invers the bytes on a word - used for input data for HASH */
+#ifdef BIG__ENDIAN
+#define UTIL_REVERT_UINT32_BYTES(val) \
+	(((val) >> 24) | (((val) & 0x00FF0000) >> 8) | (((val) & 0x0000FF00) << 8) | (((val) & 0x000000FF) << 24))
+#else
+#define UTIL_REVERT_UINT32_BYTES(val)	(val)
+#endif
+
+ /* ------------------------------------------------------------
+ **
+ * @brief This function executes a reverse bytes copying from one buffer to another buffer.
+ *
+ * @param[in] dst_ptr - The pointer to destination buffer.
+ * @param[in] src_ptr - The pointer to source buffer.
+ * @param[in] size    - The size in bytes.
+ *
+ */
+
+void UTIL_ReverseMemCopy(uint8_t *dst_ptr, uint8_t *src_ptr, uint32_t size);
+
+
+ /* ------------------------------------------------------------
+  **
+  * @brief This function executes a reversed byte copy on a specified buffer.
+  *
+  *        on a 6 byte byffer:
+  *
+  *        buff[5] <---> buff[0]
+  *        buff[4] <---> buff[1]
+  *        buff[3] <---> buff[2]
+  *
+  * @param[in] dst_ptr - The counter buffer.
+  * @param[in] src_ptr - The counter size in bytes.
+  *
+  */
+void UTIL_ReverseBuff(uint8_t *buff_ptr, uint32_t size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/drivers/arm/cryptocell/cc_rotpk.h b/include/drivers/arm/cryptocell/cc_rotpk.h
new file mode 100644
index 0000000..9398496
--- /dev/null
+++ b/include/drivers/arm/cryptocell/cc_rotpk.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CC_ROTPK_H
+#define _CC_ROTPK_H
+
+int cc_get_rotpk_hash(unsigned char *dst, unsigned int len,
+		      unsigned int *flags);
+
+#endif
diff --git a/include/drivers/arm/css/css_mhu.h b/include/drivers/arm/css/css_mhu.h
new file mode 100644
index 0000000..ff04ae4
--- /dev/null
+++ b/include/drivers/arm/css/css_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_MHU_H
+#define CSS_MHU_H
+
+#include <stdint.h>
+
+void mhu_secure_message_start(unsigned int slot_id);
+void mhu_secure_message_send(unsigned int slot_id);
+uint32_t mhu_secure_message_wait(void);
+void mhu_secure_message_end(unsigned int slot_id);
+
+void mhu_secure_init(void);
+
+#endif /* CSS_MHU_H */
diff --git a/include/drivers/arm/css/css_mhu_doorbell.h b/include/drivers/arm/css/css_mhu_doorbell.h
new file mode 100644
index 0000000..e6f7a1b
--- /dev/null
+++ b/include/drivers/arm/css/css_mhu_doorbell.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_MHU_DOORBELL_H
+#define CSS_MHU_DOORBELL_H
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+/* MHUv2 Base Address */
+#define MHUV2_BASE_ADDR		PLAT_MHUV2_BASE
+
+/* MHUv2 Control Registers Offsets */
+#define MHU_V2_MSG_NO_CAP_OFFSET		0xF80
+#define MHU_V2_ACCESS_REQ_OFFSET		0xF88
+#define MHU_V2_ACCESS_READY_OFFSET		0xF8C
+
+#define SENDER_REG_STAT(_channel)	(0x20 * (_channel))
+#define SENDER_REG_SET(_channel)	((0x20 * (_channel)) + 0xC)
+
+/* Helper macro to ring doorbell */
+#define MHU_RING_DOORBELL(addr, modify_mask, preserve_mask)	do {	\
+		uint32_t db = mmio_read_32(addr) & (preserve_mask);	\
+		mmio_write_32(addr, db | (modify_mask));		\
+	} while (0)
+
+#define MHU_V2_ACCESS_REQUEST(addr)	\
+	mmio_write_32((addr) + MHU_V2_ACCESS_REQ_OFFSET, 0x1)
+
+#define MHU_V2_CLEAR_REQUEST(addr)	\
+	mmio_write_32((addr) + MHU_V2_ACCESS_REQ_OFFSET, 0x0)
+
+#define MHU_V2_IS_ACCESS_READY(addr)	\
+	(mmio_read_32((addr) + MHU_V2_ACCESS_READY_OFFSET) & 0x1)
+
+struct scmi_channel_plat_info;
+void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info);
+void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info);
+
+#endif	/* CSS_MHU_DOORBELL_H */
diff --git a/include/drivers/arm/css/css_scp.h b/include/drivers/arm/css/css_scp.h
new file mode 100644
index 0000000..f3c08c5
--- /dev/null
+++ b/include/drivers/arm/css/css_scp.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_SCP_H
+#define CSS_SCP_H
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+
+/* Forward declarations */
+struct psci_power_state;
+
+/* API for power management by SCP */
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie);
+void css_scp_suspend(const struct psci_power_state *target_state);
+void css_scp_off(const struct psci_power_state *target_state);
+void css_scp_on(u_register_t mpidr);
+int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level);
+void __dead2 css_scp_sys_shutdown(void);
+void __dead2 css_scp_sys_reboot(void);
+void __dead2 css_scp_system_off(int state);
+
+/* API for SCP Boot Image transfer. Return 0 on success, -1 on error */
+int css_scp_boot_image_xfer(void *image, unsigned int image_size);
+
+/*
+ * API to wait for SCP to signal till it's ready after booting the transferred
+ * image.
+ */
+int css_scp_boot_ready(void);
+
+#if CSS_LOAD_SCP_IMAGES
+
+/*
+ * All CSS platforms load SCP_BL2/SCP_BL2U just below BL2 (this is where BL31
+ * usually resides except when ARM_BL31_IN_DRAM is
+ * set). Ensure that SCP_BL2/SCP_BL2U do not overflow into tb_fw_config.
+ */
+CASSERT(SCP_BL2_LIMIT <= BL2_BASE, assert_scp_bl2_overwrite_bl2);
+CASSERT(SCP_BL2U_LIMIT <= BL2_BASE, assert_scp_bl2u_overwrite_bl2);
+
+CASSERT(SCP_BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2_overflow);
+CASSERT(SCP_BL2U_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2u_overflow);
+#endif
+
+#endif /* CSS_SCP_H */
diff --git a/include/drivers/arm/css/css_scpi.h b/include/drivers/arm/css/css_scpi.h
new file mode 100644
index 0000000..68fc60a
--- /dev/null
+++ b/include/drivers/arm/css/css_scpi.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_SCPI_H
+#define CSS_SCPI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * An SCPI command consists of a header and a payload.
+ * The following structure describes the header. It is 64-bit long.
+ */
+typedef struct {
+	/* Command ID */
+	uint32_t id		: 7;
+	/* Set ID. Identifies whether this is a standard or extended command. */
+	uint32_t set		: 1;
+	/* Sender ID to match a reply. The value is sender specific. */
+	uint32_t sender		: 8;
+	/* Size of the payload in bytes (0 - 511) */
+	uint32_t size		: 9;
+	uint32_t reserved	: 7;
+	/*
+	 * Status indicating the success of a command.
+	 * See the enum below.
+	 */
+	uint32_t status;
+} scpi_cmd_t;
+
+typedef enum {
+	SCPI_SET_NORMAL = 0,	/* Normal SCPI commands */
+	SCPI_SET_EXTENDED	/* Extended SCPI commands */
+} scpi_set_t;
+
+enum {
+	SCP_OK = 0,	/* Success */
+	SCP_E_PARAM,	/* Invalid parameter(s) */
+	SCP_E_ALIGN,	/* Invalid alignment */
+	SCP_E_SIZE,	/* Invalid size */
+	SCP_E_HANDLER,	/* Invalid handler or callback */
+	SCP_E_ACCESS,	/* Invalid access or permission denied */
+	SCP_E_RANGE,	/* Value out of range */
+	SCP_E_TIMEOUT,	/* Time out has ocurred */
+	SCP_E_NOMEM,	/* Invalid memory area or pointer */
+	SCP_E_PWRSTATE,	/* Invalid power state */
+	SCP_E_SUPPORT,	/* Feature not supported or disabled */
+	SCPI_E_DEVICE,	/* Device error */
+	SCPI_E_BUSY,	/* Device is busy */
+};
+
+typedef uint32_t scpi_status_t;
+
+typedef enum {
+	SCPI_CMD_SCP_READY = 0x01,
+	SCPI_CMD_SET_CSS_POWER_STATE = 0x03,
+	SCPI_CMD_GET_CSS_POWER_STATE = 0x04,
+	SCPI_CMD_SYS_POWER_STATE = 0x05
+} scpi_command_t;
+
+/*
+ * Macros to parse SCP response to GET_CSS_POWER_STATE command
+ *
+ *   [3:0] : cluster ID
+ *   [7:4] : cluster state: 0 = on; 3 = off; rest are reserved
+ *   [15:8]: on/off state for individual CPUs in the cluster
+ *
+ * Payload is in little-endian
+ */
+#define CLUSTER_ID(_resp)		((_resp) & 0xf)
+#define CLUSTER_POWER_STATE(_resp)	(((_resp) >> 4) & 0xf)
+
+/* Result is a bit mask of CPU on/off states in the cluster */
+#define CPU_POWER_STATE(_resp)		(((_resp) >> 8) & 0xff)
+
+/*
+ * For GET_CSS_POWER_STATE, SCP returns the power states of every cluster. The
+ * size of response depends on the number of clusters in the system. The
+ * SCP-to-AP payload contains 2 bytes per cluster. Make sure the response is
+ * large enough to contain power states of a given cluster
+ */
+#define CHECK_RESPONSE(_resp, _clus) \
+	(_resp.size >= (((_clus) + 1) * 2))
+
+typedef enum {
+	scpi_power_on = 0,
+	scpi_power_retention = 1,
+	scpi_power_off = 3,
+} scpi_power_state_t;
+
+typedef enum {
+	scpi_system_shutdown = 0,
+	scpi_system_reboot = 1,
+	scpi_system_reset = 2
+} scpi_system_state_t;
+
+int scpi_wait_ready(void);
+void scpi_set_css_power_state(unsigned int mpidr,
+				scpi_power_state_t cpu_state,
+				scpi_power_state_t cluster_state,
+				scpi_power_state_t css_state);
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+		unsigned int *cluster_state_p);
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state);
+
+#endif /* CSS_SCPI_H */
diff --git a/include/drivers/arm/css/scmi.h b/include/drivers/arm/css/scmi.h
new file mode 100644
index 0000000..1f8dc6c
--- /dev/null
+++ b/include/drivers/arm/css/scmi.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCMI_H
+#define SCMI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/bakery_lock.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+/* Supported SCMI Protocol Versions */
+#define SCMI_AP_CORE_PROTO_VER			MAKE_SCMI_VERSION(1, 0)
+#define SCMI_PWR_DMN_PROTO_VER			MAKE_SCMI_VERSION(1, 0)
+#define SCMI_SYS_PWR_PROTO_VER			MAKE_SCMI_VERSION(1, 0)
+
+#define GET_SCMI_MAJOR_VER(ver)			(((ver) >> 16) & 0xffff)
+#define GET_SCMI_MINOR_VER(ver)			((ver) & 0xffff)
+
+#define MAKE_SCMI_VERSION(maj, min)	\
+			((((maj) & 0xffff) << 16) | ((min) & 0xffff))
+
+/* Macro to check if the driver is compatible with the SCMI version reported */
+#define is_scmi_version_compatible(drv, scmi)				\
+	((GET_SCMI_MAJOR_VER(drv) == GET_SCMI_MAJOR_VER(scmi)) &&	\
+	(GET_SCMI_MINOR_VER(drv) <= GET_SCMI_MINOR_VER(scmi)))
+
+/* SCMI Protocol identifiers */
+#define SCMI_PWR_DMN_PROTO_ID			0x11
+#define SCMI_SYS_PWR_PROTO_ID			0x12
+/* The AP core protocol is a CSS platform-specific extension */
+#define SCMI_AP_CORE_PROTO_ID			0x90
+
+/* Mandatory messages IDs for all SCMI protocols */
+#define SCMI_PROTO_VERSION_MSG			0x0
+#define SCMI_PROTO_ATTR_MSG			0x1
+#define SCMI_PROTO_MSG_ATTR_MSG			0x2
+
+/* SCMI power domain management protocol message IDs */
+#define SCMI_PWR_STATE_SET_MSG			0x4
+#define SCMI_PWR_STATE_GET_MSG			0x5
+
+/* SCMI system power management protocol message IDs */
+#define SCMI_SYS_PWR_STATE_SET_MSG		0x3
+#define SCMI_SYS_PWR_STATE_GET_MSG		0x4
+
+/* SCMI AP core protocol message IDs */
+#define SCMI_AP_CORE_RESET_ADDR_SET_MSG		0x3
+#define SCMI_AP_CORE_RESET_ADDR_GET_MSG		0x4
+
+/* Helper macros for system power management protocol commands */
+
+/*
+ * Macros to describe the bit-fields of the `attribute` of system power domain
+ * protocol PROTOCOL_MSG_ATTRIBUTE message.
+ */
+#define SYS_PWR_ATTR_WARM_RESET_SHIFT		31
+#define SCMI_SYS_PWR_WARM_RESET_SUPPORTED	(1U << SYS_PWR_ATTR_WARM_RESET_SHIFT)
+
+#define SYS_PWR_ATTR_SUSPEND_SHIFT		30
+#define SCMI_SYS_PWR_SUSPEND_SUPPORTED		(1 << SYS_PWR_ATTR_SUSPEND_SHIFT)
+
+/*
+ * Macros to describe the bit-fields of the `flags` parameter of system power
+ * domain protocol SYSTEM_POWER_STATE_SET message.
+ */
+#define SYS_PWR_SET_GRACEFUL_REQ_SHIFT		0
+#define SCMI_SYS_PWR_GRACEFUL_REQ		(1 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT)
+#define SCMI_SYS_PWR_FORCEFUL_REQ		(0 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT)
+
+/*
+ * Macros to describe the `system_state` parameter of system power
+ * domain protocol SYSTEM_POWER_STATE_SET message.
+ */
+#define SCMI_SYS_PWR_SHUTDOWN			0x0
+#define SCMI_SYS_PWR_COLD_RESET			0x1
+#define SCMI_SYS_PWR_WARM_RESET			0x2
+#define SCMI_SYS_PWR_POWER_UP			0x3
+#define SCMI_SYS_PWR_SUSPEND			0x4
+
+/*
+ * Macros to describe the bit-fields of the `attribute` of AP core protocol
+ * AP_CORE_RESET_ADDR set/get messages.
+ */
+#define SCMI_AP_CORE_LOCK_ATTR_SHIFT		0x0
+#define SCMI_AP_CORE_LOCK_ATTR			(1U << SCMI_AP_CORE_LOCK_ATTR_SHIFT)
+
+/* SCMI Error code definitions */
+#define SCMI_E_QUEUED			1
+#define SCMI_E_SUCCESS			0
+#define SCMI_E_NOT_SUPPORTED		-1
+#define SCMI_E_INVALID_PARAM		-2
+#define SCMI_E_DENIED			-3
+#define SCMI_E_NOT_FOUND		-4
+#define SCMI_E_OUT_OF_RANGE		-5
+#define SCMI_E_BUSY			-6
+
+/*
+ * SCMI driver platform information. The details of the doorbell mechanism
+ * can be found in the SCMI specification.
+ */
+typedef struct scmi_channel_plat_info {
+	/* SCMI mailbox memory */
+	uintptr_t scmi_mbx_mem;
+	/* The door bell register address */
+	uintptr_t db_reg_addr;
+	/* The bit mask that need to be preserved when ringing doorbell */
+	uint32_t db_preserve_mask;
+	/* The bit mask that need to be set to ring doorbell */
+	uint32_t db_modify_mask;
+	/* The handler for ringing doorbell */
+	void (*ring_doorbell)(struct scmi_channel_plat_info *plat_info);
+	/* cookie is unused now. But added for future enhancements. */
+	void *cookie;
+} scmi_channel_plat_info_t;
+
+
+#if HW_ASSISTED_COHERENCY
+typedef spinlock_t scmi_lock_t;
+#else
+typedef bakery_lock_t scmi_lock_t;
+#endif
+
+/*
+ * Structure to represent an SCMI channel.
+ */
+typedef struct scmi_channel {
+	scmi_channel_plat_info_t *info;
+	 /* The lock for channel access */
+	scmi_lock_t *lock;
+	/* Indicate whether the channel is initialized */
+	int is_initialized;
+} scmi_channel_t;
+
+/* External Common API */
+void *scmi_init(scmi_channel_t *ch);
+int scmi_proto_msg_attr(void *p, uint32_t proto_id, uint32_t command_id,
+						uint32_t *attr);
+int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version);
+
+/*
+ * Power domain protocol commands. Refer to the SCMI specification for more
+ * details on these commands.
+ */
+int scmi_pwr_state_set(void *p, uint32_t domain_id, uint32_t scmi_pwr_state);
+int scmi_pwr_state_get(void *p, uint32_t domain_id, uint32_t *scmi_pwr_state);
+
+/*
+ * System power management protocol commands. Refer SCMI specification for more
+ * details on these commands.
+ */
+int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state);
+int scmi_sys_pwr_state_get(void *p, uint32_t *system_state);
+
+/* SCMI AP core configuration protocol commands. */
+int scmi_ap_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t attr);
+int scmi_ap_core_get_reset_addr(void *p, uint64_t *reset_addr, uint32_t *attr);
+
+/* API to get the platform specific SCMI channel information. */
+scmi_channel_plat_info_t *plat_css_get_scmi_info(void);
+
+/* API to override default PSCI callbacks for platforms that support SCMI. */
+const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops);
+
+#endif /* SCMI_H */
diff --git a/include/drivers/arm/css/sds.h b/include/drivers/arm/css/sds.h
new file mode 100644
index 0000000..db4cbaa
--- /dev/null
+++ b/include/drivers/arm/css/sds.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDS_H
+#define SDS_H
+
+/* SDS Structure Identifier defines */
+/* AP CPU INFO defines */
+#define SDS_AP_CPU_INFO_STRUCT_ID		1
+#define SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET	0x0
+#define SDS_AP_CPU_INFO_PRIMARY_CPUID_SIZE	0x4
+
+/* ROM Firmware Version defines */
+#define SDS_ROM_VERSION_STRUCT_ID		2
+#define SDS_ROM_VERSION_OFFSET			0x0
+#define SDS_ROM_VERSION_SIZE 			0x4
+
+/* RAM Firmware version defines */
+#define SDS_RAM_VERSION_STRUCT_ID		3
+#define SDS_RAM_VERSION_OFFSET			0x0
+#define SDS_RAM_VERSION_SIZE			0x4
+
+/* Platform Identity defines */
+#define SDS_PLATFORM_IDENTITY_STRUCT_ID		4
+#define SDS_PLATFORM_IDENTITY_ID_OFFSET		0x0
+#define SDS_PLATFORM_IDENTITY_ID_SIZE		0x4
+#define SDS_PLATFORM_IDENTITY_ID_CONFIG_SHIFT	28
+#define SDS_PLATFORM_IDENTITY_ID_CONFIG_WIDTH	4
+#define SDS_PLATFORM_IDENTITY_ID_CONFIG_MASK	\
+	((1 << SDS_PLATFORM_IDENTITY_ID_CONFIG_WIDTH) - 1)
+
+#define SDS_PLATFORM_IDENTITY_PLAT_TYPE_OFFSET	0x4
+#define SDS_PLATFORM_IDENTITY_PLAT_TYPE_SIZE	0x4
+
+/* Reset Syndrome defines */
+#define SDS_RESET_SYNDROME_STRUCT_ID		5
+#define SDS_RESET_SYNDROME_OFFSET		0
+#define SDS_RESET_SYNDROME_SIZE			4
+#define SDS_RESET_SYNDROME_POW_ON_RESET_BIT	(1 << 0)
+#define SDS_RESET_SYNDROME_SCP_WD_RESET_BIT	(1 << 1)
+#define SDS_RESET_SYNDROME_AP_WD_RESET_BIT	(1 << 2)
+#define SDS_RESET_SYNDROME_SYS_RESET_REQ_BIT	(1 << 3)
+#define SDS_RESET_SYNDROME_M3_LOCKUP_BIT	(1 << 4)
+
+/* SCP Firmware Feature Availability defines */
+#define SDS_FEATURE_AVAIL_STRUCT_ID		6
+#define SDS_FEATURE_AVAIL_OFFSET		0
+#define SDS_FEATURE_AVAIL_SIZE			4
+#define SDS_FEATURE_AVAIL_SCP_RAM_READY_BIT	(1 << 0)
+#define SDS_FEATURE_AVAIL_DMC_READY_BIT		(1 << 1)
+#define SDS_FEATURE_AVAIL_MSG_IF_READY_BIT	(1 << 2)
+
+/* SCP BL2 Image Metadata defines */
+#define SDS_SCP_IMG_STRUCT_ID			9
+#define SDS_SCP_IMG_FLAG_OFFSET			0
+#define SDS_SCP_IMG_FLAG_SIZE			4
+#define SDS_SCP_IMG_VALID_FLAG_BIT		(1 << 0)
+#define SDS_SCP_IMG_ADDR_OFFSET			4
+#define SDS_SCP_IMG_ADDR_SIZE			4
+#define SDS_SCP_IMG_SIZE_OFFSET			8
+#define SDS_SCP_IMG_SIZE_SIZE			4
+
+/* SDS Driver Error Codes */
+#define SDS_OK				0
+#define SDS_ERR_FAIL			-1
+#define SDS_ERR_INVALID_PARAMS		-2
+#define SDS_ERR_STRUCT_NOT_FOUND	-3
+#define SDS_ERR_STRUCT_NOT_FINALIZED	-4
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+typedef enum {
+	SDS_ACCESS_MODE_NON_CACHED,
+	SDS_ACCESS_MODE_CACHED,
+} sds_access_mode_t;
+
+int sds_init(void);
+int sds_struct_exists(unsigned int structure_id);
+int sds_struct_read(uint32_t structure_id, unsigned int fld_off, void *data,
+		size_t size, sds_access_mode_t mode);
+int sds_struct_write(uint32_t structure_id, unsigned int fld_off, void *data,
+		size_t size, sds_access_mode_t mode);
+#endif /*__ASSEMBLER__ */
+
+#endif /* SDS_H */
diff --git a/include/drivers/arm/fvp/fvp_pwrc.h b/include/drivers/arm/fvp/fvp_pwrc.h
new file mode 100644
index 0000000..39e2516
--- /dev/null
+++ b/include/drivers/arm/fvp/fvp_pwrc.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_PWRC_H
+#define FVP_PWRC_H
+
+/* FVP Power controller register offset etc */
+#define PPOFFR_OFF		U(0x0)
+#define PPONR_OFF		U(0x4)
+#define PCOFFR_OFF		U(0x8)
+#define PWKUPR_OFF		U(0xc)
+#define PSYSR_OFF		U(0x10)
+
+#define PWKUPR_WEN		BIT_32(31)
+
+#define PSYSR_AFF_L2		BIT_32(31)
+#define PSYSR_AFF_L1		BIT_32(30)
+#define PSYSR_AFF_L0		BIT_32(29)
+#define PSYSR_WEN		BIT_32(28)
+#define PSYSR_PC		BIT_32(27)
+#define PSYSR_PP		BIT_32(26)
+
+#define PSYSR_WK_SHIFT		24
+#define PSYSR_WK_WIDTH		0x2
+#define PSYSR_WK_MASK		((1U << PSYSR_WK_WIDTH) - 1U)
+#define PSYSR_WK(x)		((x) >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK
+
+#define WKUP_COLD		U(0x0)
+#define WKUP_RESET		U(0x1)
+#define WKUP_PPONR		U(0x2)
+#define WKUP_GICREQ		U(0x3)
+
+#define PSYSR_INVALID		U(0xffffffff)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+void fvp_pwrc_write_pcoffr(u_register_t mpidr);
+void fvp_pwrc_write_ppoffr(u_register_t mpidr);
+void fvp_pwrc_write_pponr(u_register_t mpidr);
+void fvp_pwrc_set_wen(u_register_t mpidr);
+void fvp_pwrc_clr_wen(u_register_t mpidr);
+unsigned int fvp_pwrc_read_psysr(u_register_t mpidr);
+unsigned int fvp_pwrc_get_cpu_wkr(u_register_t mpidr);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* FVP_PWRC_H */
diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h
new file mode 100644
index 0000000..3ac1b43
--- /dev/null
+++ b/include/drivers/arm/gic_common.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GIC_COMMON_H
+#define GIC_COMMON_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * GIC Distributor interface general definitions
+ ******************************************************************************/
+/* Constants to categorise interrupts */
+#define MIN_SGI_ID		U(0)
+#define MIN_SEC_SGI_ID		U(8)
+#define MIN_PPI_ID		U(16)
+#define MIN_SPI_ID		U(32)
+#define MAX_SPI_ID		U(1019)
+
+#define TOTAL_SPI_INTR_NUM	(MAX_SPI_ID - MIN_SPI_ID + U(1))
+#define TOTAL_PCPU_INTR_NUM	(MIN_SPI_ID - MIN_SGI_ID)
+
+/* Mask for the priority field common to all GIC interfaces */
+#define GIC_PRI_MASK			U(0xff)
+
+/* Mask for the configuration field common to all GIC interfaces */
+#define GIC_CFG_MASK			U(0x3)
+
+/* Constant to indicate a spurious interrupt in all GIC versions */
+#define GIC_SPURIOUS_INTERRUPT		U(1023)
+
+/* Interrupt configurations: 2-bit fields with LSB reserved */
+#define GIC_INTR_CFG_LEVEL		(0 << 1)
+#define GIC_INTR_CFG_EDGE		(1 << 1)
+
+/* Highest possible interrupt priorities */
+#define GIC_HIGHEST_SEC_PRIORITY	U(0x00)
+#define GIC_HIGHEST_NS_PRIORITY		U(0x80)
+
+/*******************************************************************************
+ * GIC Distributor interface register offsets that are common to GICv3 & GICv2
+ ******************************************************************************/
+#define GICD_CTLR		U(0x0)
+#define GICD_TYPER		U(0x4)
+#define GICD_IIDR		U(0x8)
+#define GICD_IGROUPR		U(0x80)
+#define GICD_ISENABLER		U(0x100)
+#define GICD_ICENABLER		U(0x180)
+#define GICD_ISPENDR		U(0x200)
+#define GICD_ICPENDR		U(0x280)
+#define GICD_ISACTIVER		U(0x300)
+#define GICD_ICACTIVER		U(0x380)
+#define GICD_IPRIORITYR		U(0x400)
+#define GICD_ICFGR		U(0xc00)
+#define GICD_NSACR		U(0xe00)
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G0_SHIFT		0
+#define CTLR_ENABLE_G0_MASK		U(0x1)
+#define CTLR_ENABLE_G0_BIT		BIT_32(CTLR_ENABLE_G0_SHIFT)
+
+
+/*******************************************************************************
+ * GIC Distributor interface register constants that are common to GICv3 & GICv2
+ ******************************************************************************/
+#define PIDR2_ARCH_REV_SHIFT	4
+#define PIDR2_ARCH_REV_MASK	U(0xf)
+
+/* GICv3 revision as reported by the PIDR2 register */
+#define ARCH_REV_GICV3		U(0x3)
+/* GICv2 revision as reported by the PIDR2 register */
+#define ARCH_REV_GICV2		U(0x2)
+/* GICv1 revision as reported by the PIDR2 register */
+#define ARCH_REV_GICV1		U(0x1)
+
+#define IGROUPR_SHIFT		5
+#define ISENABLER_SHIFT		5
+#define ICENABLER_SHIFT		ISENABLER_SHIFT
+#define ISPENDR_SHIFT		5
+#define ICPENDR_SHIFT		ISPENDR_SHIFT
+#define ISACTIVER_SHIFT		5
+#define ICACTIVER_SHIFT		ISACTIVER_SHIFT
+#define IPRIORITYR_SHIFT	2
+#define ITARGETSR_SHIFT		2
+#define ICFGR_SHIFT		4
+#define NSACR_SHIFT		4
+
+/* GICD_TYPER shifts and masks */
+#define TYPER_IT_LINES_NO_SHIFT	U(0)
+#define TYPER_IT_LINES_NO_MASK	U(0x1f)
+
+/* Value used to initialize Normal world interrupt priorities four at a time */
+#define GICD_IPRIORITYR_DEF_VAL			\
+	(GIC_HIGHEST_NS_PRIORITY	|	\
+	(GIC_HIGHEST_NS_PRIORITY << 8)	|	\
+	(GIC_HIGHEST_NS_PRIORITY << 16)	|	\
+	(GIC_HIGHEST_NS_PRIORITY << 24))
+
+#endif /* GIC_COMMON_H */
diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h
new file mode 100644
index 0000000..ebcb216
--- /dev/null
+++ b/include/drivers/arm/gicv2.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV2_H
+#define GICV2_H
+
+#include <drivers/arm/gic_common.h>
+
+/*******************************************************************************
+ * GICv2 miscellaneous definitions
+ ******************************************************************************/
+
+/* Interrupt group definitions */
+#define GICV2_INTR_GROUP0	U(0)
+#define GICV2_INTR_GROUP1	U(1)
+
+/* Interrupt IDs reported by the HPPIR and IAR registers */
+#define PENDING_G1_INTID	U(1022)
+
+/* GICv2 can only target up to 8 PEs */
+#define GICV2_MAX_TARGET_PE	U(8)
+
+/*******************************************************************************
+ * GICv2 specific Distributor interface register offsets and constants.
+ ******************************************************************************/
+#define GICD_ITARGETSR		U(0x800)
+#define GICD_SGIR		U(0xF00)
+#define GICD_CPENDSGIR		U(0xF10)
+#define GICD_SPENDSGIR		U(0xF20)
+#define GICD_PIDR2_GICV2	U(0xFE8)
+
+#define ITARGETSR_SHIFT		2
+#define GIC_TARGET_CPU_MASK	U(0xff)
+
+#define CPENDSGIR_SHIFT		2
+#define SPENDSGIR_SHIFT		CPENDSGIR_SHIFT
+
+#define SGIR_TGTLSTFLT_SHIFT	24
+#define SGIR_TGTLSTFLT_MASK	U(0x3)
+#define SGIR_TGTLST_SHIFT	16
+#define SGIR_TGTLST_MASK	U(0xff)
+#define SGIR_INTID_MASK		ULL(0xf)
+
+#define SGIR_TGT_SPECIFIC	U(0)
+
+#define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, intid) \
+	((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \
+	 (((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \
+	 ((intid) & SGIR_INTID_MASK))
+
+/*******************************************************************************
+ * GICv2 specific CPU interface register offsets and constants.
+ ******************************************************************************/
+/* Physical CPU Interface registers */
+#define GICC_CTLR		U(0x0)
+#define GICC_PMR		U(0x4)
+#define GICC_BPR		U(0x8)
+#define GICC_IAR		U(0xC)
+#define GICC_EOIR		U(0x10)
+#define GICC_RPR		U(0x14)
+#define GICC_HPPIR		U(0x18)
+#define GICC_AHPPIR		U(0x28)
+#define GICC_IIDR		U(0xFC)
+#define GICC_DIR		U(0x1000)
+#define GICC_PRIODROP		GICC_EOIR
+
+/* GICC_CTLR bit definitions */
+#define EOI_MODE_NS		BIT_32(10)
+#define EOI_MODE_S		BIT_32(9)
+#define IRQ_BYP_DIS_GRP1	BIT_32(8)
+#define FIQ_BYP_DIS_GRP1	BIT_32(7)
+#define IRQ_BYP_DIS_GRP0	BIT_32(6)
+#define FIQ_BYP_DIS_GRP0	BIT_32(5)
+#define CBPR			BIT_32(4)
+#define FIQ_EN_SHIFT		3
+#define FIQ_EN_BIT		BIT_32(FIQ_EN_SHIFT)
+#define ACK_CTL			BIT_32(2)
+
+/* GICC_IIDR bit masks and shifts */
+#define GICC_IIDR_PID_SHIFT	20
+#define GICC_IIDR_ARCH_SHIFT	16
+#define GICC_IIDR_REV_SHIFT	12
+#define GICC_IIDR_IMP_SHIFT	0
+
+#define GICC_IIDR_PID_MASK	U(0xfff)
+#define GICC_IIDR_ARCH_MASK	U(0xf)
+#define GICC_IIDR_REV_MASK	U(0xf)
+#define GICC_IIDR_IMP_MASK	U(0xfff)
+
+/* HYP view virtual CPU Interface registers */
+#define GICH_CTL		U(0x0)
+#define GICH_VTR		U(0x4)
+#define GICH_ELRSR0		U(0x30)
+#define GICH_ELRSR1		U(0x34)
+#define GICH_APR0		U(0xF0)
+#define GICH_LR_BASE		U(0x100)
+
+/* Virtual CPU Interface registers */
+#define GICV_CTL		U(0x0)
+#define GICV_PRIMASK		U(0x4)
+#define GICV_BP			U(0x8)
+#define GICV_INTACK		U(0xC)
+#define GICV_EOI		U(0x10)
+#define GICV_RUNNINGPRI		U(0x14)
+#define GICV_HIGHESTPEND	U(0x18)
+#define GICV_DEACTIVATE		U(0x1000)
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G1_SHIFT		1
+#define CTLR_ENABLE_G1_MASK		U(0x1)
+#define CTLR_ENABLE_G1_BIT		BIT_32(CTLR_ENABLE_G1_SHIFT)
+
+/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
+#define INT_ID_MASK		U(0x3ff)
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <common/interrupt_props.h>
+
+/*******************************************************************************
+ * This structure describes some of the implementation defined attributes of
+ * the GICv2 IP. It is used by the platform port to specify these attributes
+ * in order to initialize the GICv2 driver. The attributes are described
+ * below.
+ *
+ * The 'gicd_base' field contains the base address of the Distributor interface
+ * programmer's view.
+ *
+ * The 'gicc_base' field contains the base address of the CPU Interface
+ * programmer's view.
+ *
+ * The 'target_masks' is a pointer to an array containing 'target_masks_num'
+ * elements. The GIC driver will populate the array with per-PE target mask to
+ * use to when targeting interrupts.
+ *
+ * The 'interrupt_props' field is a pointer to an array that enumerates secure
+ * interrupts and their properties. If this field is not NULL, both
+ * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored.
+ *
+ * The 'interrupt_props_num' field contains the number of entries in the
+ * 'interrupt_props' array. If this field is non-zero, 'g0_interrupt_num' is
+ * ignored.
+ ******************************************************************************/
+typedef struct gicv2_driver_data {
+	uintptr_t gicd_base;
+	uintptr_t gicc_base;
+	unsigned int *target_masks;
+	unsigned int target_masks_num;
+	const interrupt_prop_t *interrupt_props;
+	unsigned int interrupt_props_num;
+} gicv2_driver_data_t;
+
+/*******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data);
+void gicv2_distif_init(void);
+void gicv2_pcpu_distif_init(void);
+void gicv2_cpuif_enable(void);
+void gicv2_cpuif_disable(void);
+unsigned int gicv2_is_fiq_enabled(void);
+unsigned int gicv2_get_pending_interrupt_type(void);
+unsigned int gicv2_get_pending_interrupt_id(void);
+unsigned int gicv2_acknowledge_interrupt(void);
+void gicv2_end_of_interrupt(unsigned int id);
+unsigned int gicv2_get_interrupt_group(unsigned int id);
+unsigned int gicv2_get_running_priority(void);
+void gicv2_set_pe_target_mask(unsigned int proc_num);
+unsigned int gicv2_get_interrupt_active(unsigned int id);
+void gicv2_enable_interrupt(unsigned int id);
+void gicv2_disable_interrupt(unsigned int id);
+void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority);
+void gicv2_set_interrupt_type(unsigned int id, unsigned int type);
+void gicv2_raise_sgi(int sgi_num, int proc_num);
+void gicv2_set_spi_routing(unsigned int id, int proc_num);
+void gicv2_set_interrupt_pending(unsigned int id);
+void gicv2_clear_interrupt_pending(unsigned int id);
+unsigned int gicv2_set_pmr(unsigned int mask);
+void gicv2_interrupt_set_cfg(unsigned int id, unsigned int cfg);
+
+#endif /* __ASSEMBLER__ */
+#endif /* GICV2_H */
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
new file mode 100644
index 0000000..9c72d4d
--- /dev/null
+++ b/include/drivers/arm/gicv3.h
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GICV3_H
+#define GICV3_H
+
+/*******************************************************************************
+ * GICv3 miscellaneous definitions
+ ******************************************************************************/
+/* Interrupt group definitions */
+#define INTR_GROUP1S		U(0)
+#define INTR_GROUP0		U(1)
+#define INTR_GROUP1NS		U(2)
+
+/* Interrupt IDs reported by the HPPIR and IAR registers */
+#define PENDING_G1S_INTID	U(1020)
+#define PENDING_G1NS_INTID	U(1021)
+
+/* Constant to categorize LPI interrupt */
+#define MIN_LPI_ID		U(8192)
+
+/* GICv3 can only target up to 16 PEs with SGI */
+#define GICV3_MAX_SGI_TARGETS	U(16)
+
+/*******************************************************************************
+ * GICv3 specific Distributor interface register offsets and constants.
+ ******************************************************************************/
+#define GICD_STATUSR		U(0x10)
+#define GICD_SETSPI_NSR		U(0x40)
+#define GICD_CLRSPI_NSR		U(0x48)
+#define GICD_SETSPI_SR		U(0x50)
+#define GICD_CLRSPI_SR		U(0x50)
+#define GICD_IGRPMODR		U(0xd00)
+/*
+ * GICD_IROUTER<n> register is at 0x6000 + 8n, where n is the interrupt id and
+ * n >= 32, making the effective offset as 0x6100.
+ */
+#define GICD_IROUTER		U(0x6000)
+#define GICD_PIDR2_GICV3	U(0xffe8)
+
+#define IGRPMODR_SHIFT		5
+
+/* GICD_CTLR bit definitions */
+#define CTLR_ENABLE_G1NS_SHIFT		1
+#define CTLR_ENABLE_G1S_SHIFT		2
+#define CTLR_ARE_S_SHIFT		4
+#define CTLR_ARE_NS_SHIFT		5
+#define CTLR_DS_SHIFT			6
+#define CTLR_E1NWF_SHIFT		7
+#define GICD_CTLR_RWP_SHIFT		31
+
+#define CTLR_ENABLE_G1NS_MASK		U(0x1)
+#define CTLR_ENABLE_G1S_MASK		U(0x1)
+#define CTLR_ARE_S_MASK			U(0x1)
+#define CTLR_ARE_NS_MASK		U(0x1)
+#define CTLR_DS_MASK			U(0x1)
+#define CTLR_E1NWF_MASK			U(0x1)
+#define GICD_CTLR_RWP_MASK		U(0x1)
+
+#define CTLR_ENABLE_G1NS_BIT		BIT_32(CTLR_ENABLE_G1NS_SHIFT)
+#define CTLR_ENABLE_G1S_BIT		BIT_32(CTLR_ENABLE_G1S_SHIFT)
+#define CTLR_ARE_S_BIT			BIT_32(CTLR_ARE_S_SHIFT)
+#define CTLR_ARE_NS_BIT			BIT_32(CTLR_ARE_NS_SHIFT)
+#define CTLR_DS_BIT			BIT_32(CTLR_DS_SHIFT)
+#define CTLR_E1NWF_BIT			BIT_32(CTLR_E1NWF_SHIFT)
+#define GICD_CTLR_RWP_BIT		BIT_32(GICD_CTLR_RWP_SHIFT)
+
+/* GICD_IROUTER shifts and masks */
+#define IROUTER_SHIFT		0
+#define IROUTER_IRM_SHIFT	31
+#define IROUTER_IRM_MASK	U(0x1)
+
+#define GICV3_IRM_PE		U(0)
+#define GICV3_IRM_ANY		U(1)
+
+#define NUM_OF_DIST_REGS	30
+
+/*******************************************************************************
+ * GICv3 Re-distributor interface registers & constants
+ ******************************************************************************/
+#define GICR_PCPUBASE_SHIFT	0x11
+#define GICR_SGIBASE_OFFSET	U(65536)	/* 64 KB */
+#define GICR_CTLR		U(0x0)
+#define GICR_IIDR		U(0x04)
+#define GICR_TYPER		U(0x08)
+#define GICR_WAKER		U(0x14)
+#define GICR_PROPBASER		U(0x70)
+#define GICR_PENDBASER		U(0x78)
+#define GICR_IGROUPR0		(GICR_SGIBASE_OFFSET + U(0x80))
+#define GICR_ISENABLER0		(GICR_SGIBASE_OFFSET + U(0x100))
+#define GICR_ICENABLER0		(GICR_SGIBASE_OFFSET + U(0x180))
+#define GICR_ISPENDR0		(GICR_SGIBASE_OFFSET + U(0x200))
+#define GICR_ICPENDR0		(GICR_SGIBASE_OFFSET + U(0x280))
+#define GICR_ISACTIVER0		(GICR_SGIBASE_OFFSET + U(0x300))
+#define GICR_ICACTIVER0		(GICR_SGIBASE_OFFSET + U(0x380))
+#define GICR_IPRIORITYR		(GICR_SGIBASE_OFFSET + U(0x400))
+#define GICR_ICFGR0		(GICR_SGIBASE_OFFSET + U(0xc00))
+#define GICR_ICFGR1		(GICR_SGIBASE_OFFSET + U(0xc04))
+#define GICR_IGRPMODR0		(GICR_SGIBASE_OFFSET + U(0xd00))
+#define GICR_NSACR		(GICR_SGIBASE_OFFSET + U(0xe00))
+
+/* GICR_CTLR bit definitions */
+#define GICR_CTLR_UWP_SHIFT	31
+#define GICR_CTLR_UWP_MASK	U(0x1)
+#define GICR_CTLR_UWP_BIT	BIT_32(GICR_CTLR_UWP_SHIFT)
+#define GICR_CTLR_RWP_SHIFT	3
+#define GICR_CTLR_RWP_MASK	U(0x1)
+#define GICR_CTLR_RWP_BIT	BIT_32(GICR_CTLR_RWP_SHIFT)
+#define GICR_CTLR_EN_LPIS_BIT	BIT_32(0)
+
+/* GICR_WAKER bit definitions */
+#define WAKER_CA_SHIFT		2
+#define WAKER_PS_SHIFT		1
+
+#define WAKER_CA_MASK		U(0x1)
+#define WAKER_PS_MASK		U(0x1)
+
+#define WAKER_CA_BIT		BIT_32(WAKER_CA_SHIFT)
+#define WAKER_PS_BIT		BIT_32(WAKER_PS_SHIFT)
+
+/* GICR_TYPER bit definitions */
+#define TYPER_AFF_VAL_SHIFT	32
+#define TYPER_PROC_NUM_SHIFT	8
+#define TYPER_LAST_SHIFT	4
+
+#define TYPER_AFF_VAL_MASK	U(0xffffffff)
+#define TYPER_PROC_NUM_MASK	U(0xffff)
+#define TYPER_LAST_MASK		U(0x1)
+
+#define TYPER_LAST_BIT		BIT_32(TYPER_LAST_SHIFT)
+
+#define NUM_OF_REDIST_REGS	30
+
+/*******************************************************************************
+ * GICv3 CPU interface registers & constants
+ ******************************************************************************/
+/* ICC_SRE bit definitions*/
+#define ICC_SRE_EN_BIT		BIT_32(3)
+#define ICC_SRE_DIB_BIT		BIT_32(2)
+#define ICC_SRE_DFB_BIT		BIT_32(1)
+#define ICC_SRE_SRE_BIT		BIT_32(0)
+
+/* ICC_IGRPEN1_EL3 bit definitions */
+#define IGRPEN1_EL3_ENABLE_G1NS_SHIFT	0
+#define IGRPEN1_EL3_ENABLE_G1S_SHIFT	1
+
+#define IGRPEN1_EL3_ENABLE_G1NS_BIT	BIT_32(IGRPEN1_EL3_ENABLE_G1NS_SHIFT)
+#define IGRPEN1_EL3_ENABLE_G1S_BIT	BIT_32(IGRPEN1_EL3_ENABLE_G1S_SHIFT)
+
+/* ICC_IGRPEN0_EL1 bit definitions */
+#define IGRPEN1_EL1_ENABLE_G0_SHIFT	0
+#define IGRPEN1_EL1_ENABLE_G0_BIT	BIT_32(IGRPEN1_EL1_ENABLE_G0_SHIFT)
+
+/* ICC_HPPIR0_EL1 bit definitions */
+#define HPPIR0_EL1_INTID_SHIFT		0
+#define HPPIR0_EL1_INTID_MASK		U(0xffffff)
+
+/* ICC_HPPIR1_EL1 bit definitions */
+#define HPPIR1_EL1_INTID_SHIFT		0
+#define HPPIR1_EL1_INTID_MASK		U(0xffffff)
+
+/* ICC_IAR0_EL1 bit definitions */
+#define IAR0_EL1_INTID_SHIFT		0
+#define IAR0_EL1_INTID_MASK		U(0xffffff)
+
+/* ICC_IAR1_EL1 bit definitions */
+#define IAR1_EL1_INTID_SHIFT		0
+#define IAR1_EL1_INTID_MASK		U(0xffffff)
+
+/* ICC SGI macros */
+#define SGIR_TGT_MASK			ULL(0xffff)
+#define SGIR_AFF1_SHIFT			16
+#define SGIR_INTID_SHIFT		24
+#define SGIR_INTID_MASK			ULL(0xf)
+#define SGIR_AFF2_SHIFT			32
+#define SGIR_IRM_SHIFT			40
+#define SGIR_IRM_MASK			ULL(0x1)
+#define SGIR_AFF3_SHIFT			48
+#define SGIR_AFF_MASK			ULL(0xf)
+
+#define SGIR_IRM_TO_AFF			U(0)
+
+#define GICV3_SGIR_VALUE(_aff3, _aff2, _aff1, _intid, _irm, _tgt)	\
+	((((uint64_t) (_aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) |	\
+	 (((uint64_t) (_irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) |	\
+	 (((uint64_t) (_aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) |	\
+	 (((_intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) |		\
+	 (((_aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) |		\
+	 ((_tgt) & SGIR_TGT_MASK))
+
+/*****************************************************************************
+ * GICv3 ITS registers and constants
+ *****************************************************************************/
+
+#define GITS_CTLR			U(0x0)
+#define GITS_IIDR			U(0x4)
+#define GITS_TYPER			U(0x8)
+#define GITS_CBASER			U(0x80)
+#define GITS_CWRITER			U(0x88)
+#define GITS_CREADR			U(0x90)
+#define GITS_BASER			U(0x100)
+
+/* GITS_CTLR bit definitions */
+#define GITS_CTLR_ENABLED_BIT		BIT_32(0)
+#define GITS_CTLR_QUIESCENT_SHIFT	31
+#define GITS_CTLR_QUIESCENT_BIT		BIT_32(GITS_CTLR_QUIESCENT_SHIFT)
+
+#ifndef __ASSEMBLER__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+static inline bool gicv3_is_intr_id_special_identifier(unsigned int id)
+{
+	return (id >= PENDING_G1S_INTID) && (id <= GIC_SPURIOUS_INTERRUPT);
+}
+
+/*******************************************************************************
+ * Helper GICv3 macros for SEL1
+ ******************************************************************************/
+static inline uint32_t gicv3_acknowledge_interrupt_sel1(void)
+{
+	return (uint32_t)read_icc_iar1_el1() & IAR1_EL1_INTID_MASK;
+}
+
+static inline uint32_t gicv3_get_pending_interrupt_id_sel1(void)
+{
+	return (uint32_t)read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK;
+}
+
+static inline void gicv3_end_of_interrupt_sel1(unsigned int id)
+{
+	write_icc_eoir1_el1(id);
+}
+
+/*******************************************************************************
+ * Helper GICv3 macros for EL3
+ ******************************************************************************/
+static inline uint32_t gicv3_acknowledge_interrupt(void)
+{
+	return (uint32_t)read_icc_iar0_el1() & IAR0_EL1_INTID_MASK;
+}
+
+static inline void gicv3_end_of_interrupt(unsigned int id)
+{
+	return write_icc_eoir0_el1(id);
+}
+
+/*
+ * This macro returns the total number of GICD registers corresponding to
+ * the name.
+ */
+#define GICD_NUM_REGS(reg_name)	\
+	DIV_ROUND_UP_2EVAL(TOTAL_SPI_INTR_NUM, (1 << reg_name ## _SHIFT))
+
+#define GICR_NUM_REGS(reg_name)	\
+	DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT))
+
+/* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */
+#define INT_ID_MASK	U(0xffffff)
+
+/*******************************************************************************
+ * This structure describes some of the implementation defined attributes of the
+ * GICv3 IP. It is used by the platform port to specify these attributes in order
+ * to initialise the GICV3 driver. The attributes are described below.
+ *
+ * The 'gicd_base' field contains the base address of the Distributor interface
+ * programmer's view.
+ *
+ * The 'gicr_base' field contains the base address of the Re-distributor
+ * interface programmer's view.
+ *
+ * The 'interrupt_props' field is a pointer to an array that enumerates secure
+ * interrupts and their properties. If this field is not NULL, both
+ * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored.
+ *
+ * The 'interrupt_props_num' field contains the number of entries in the
+ * 'interrupt_props' array. If this field is non-zero, both 'g0_interrupt_num'
+ * and 'g1s_interrupt_num' are ignored.
+ *
+ * The 'rdistif_num' field contains the number of Redistributor interfaces the
+ * GIC implements. This is equal to the number of CPUs or CPU interfaces
+ * instantiated in the GIC.
+ *
+ * The 'rdistif_base_addrs' field is a pointer to an array that has an entry for
+ * storing the base address of the Redistributor interface frame of each CPU in
+ * the system. The size of the array = 'rdistif_num'. The base addresses are
+ * detected during driver initialisation.
+ *
+ * The 'mpidr_to_core_pos' field is a pointer to a hash function which the
+ * driver will use to convert an MPIDR value to a linear core index. This index
+ * will be used for accessing the 'rdistif_base_addrs' array. This is an
+ * optional field. A GICv3 implementation maps each MPIDR to a linear core index
+ * as well. This mapping can be found by reading the "Affinity Value" and
+ * "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the
+ * "Processor Numbers" are suitable to index into an array to access core
+ * specific information. If this not the case, the platform port must provide a
+ * hash function. Otherwise, the "Processor Number" field will be used to access
+ * the array elements.
+ ******************************************************************************/
+typedef unsigned int (*mpidr_hash_fn)(u_register_t mpidr);
+
+typedef struct gicv3_driver_data {
+	uintptr_t gicd_base;
+	uintptr_t gicr_base;
+	const interrupt_prop_t *interrupt_props;
+	unsigned int interrupt_props_num;
+	unsigned int rdistif_num;
+	uintptr_t *rdistif_base_addrs;
+	mpidr_hash_fn mpidr_to_core_pos;
+} gicv3_driver_data_t;
+
+typedef struct gicv3_redist_ctx {
+	/* 64 bits registers */
+	uint64_t gicr_propbaser;
+	uint64_t gicr_pendbaser;
+
+	/* 32 bits registers */
+	uint32_t gicr_ctlr;
+	uint32_t gicr_igroupr0;
+	uint32_t gicr_isenabler0;
+	uint32_t gicr_ispendr0;
+	uint32_t gicr_isactiver0;
+	uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)];
+	uint32_t gicr_icfgr0;
+	uint32_t gicr_icfgr1;
+	uint32_t gicr_igrpmodr0;
+	uint32_t gicr_nsacr;
+} gicv3_redist_ctx_t;
+
+typedef struct gicv3_dist_ctx {
+	/* 64 bits registers */
+	uint64_t gicd_irouter[TOTAL_SPI_INTR_NUM];
+
+	/* 32 bits registers */
+	uint32_t gicd_ctlr;
+	uint32_t gicd_igroupr[GICD_NUM_REGS(IGROUPR)];
+	uint32_t gicd_isenabler[GICD_NUM_REGS(ISENABLER)];
+	uint32_t gicd_ispendr[GICD_NUM_REGS(ISPENDR)];
+	uint32_t gicd_isactiver[GICD_NUM_REGS(ISACTIVER)];
+	uint32_t gicd_ipriorityr[GICD_NUM_REGS(IPRIORITYR)];
+	uint32_t gicd_icfgr[GICD_NUM_REGS(ICFGR)];
+	uint32_t gicd_igrpmodr[GICD_NUM_REGS(IGRPMODR)];
+	uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)];
+} gicv3_dist_ctx_t;
+
+typedef struct gicv3_its_ctx {
+	/* 64 bits registers */
+	uint64_t gits_cbaser;
+	uint64_t gits_cwriter;
+	uint64_t gits_baser[8];
+
+	/* 32 bits registers */
+	uint32_t gits_ctlr;
+} gicv3_its_ctx_t;
+
+/*******************************************************************************
+ * GICv3 EL3 driver API
+ ******************************************************************************/
+void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data);
+void gicv3_distif_init(void);
+void gicv3_rdistif_init(unsigned int proc_num);
+void gicv3_rdistif_on(unsigned int proc_num);
+void gicv3_rdistif_off(unsigned int proc_num);
+void gicv3_cpuif_enable(unsigned int proc_num);
+void gicv3_cpuif_disable(unsigned int proc_num);
+unsigned int gicv3_get_pending_interrupt_type(void);
+unsigned int gicv3_get_pending_interrupt_id(void);
+unsigned int gicv3_get_interrupt_type(unsigned int id,
+					  unsigned int proc_num);
+void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx);
+void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx);
+/*
+ * gicv3_distif_post_restore and gicv3_distif_pre_save must be implemented if
+ * gicv3_distif_save and gicv3_rdistif_init_restore are used. If no
+ * implementation-defined sequence is needed at these steps, an empty function
+ * can be provided.
+ */
+void gicv3_distif_post_restore(unsigned int proc_num);
+void gicv3_distif_pre_save(unsigned int proc_num);
+void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx);
+void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx);
+void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx);
+void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx);
+
+unsigned int gicv3_get_running_priority(void);
+unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num);
+void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num);
+void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num);
+void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num,
+		unsigned int priority);
+void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num,
+		unsigned int type);
+void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target);
+void gicv3_set_spi_routing(unsigned int id, unsigned int irm,
+		u_register_t mpidr);
+void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num);
+void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num);
+unsigned int gicv3_set_pmr(unsigned int mask);
+
+#endif /* __ASSEMBLER__ */
+#endif /* GICV3_H */
diff --git a/include/drivers/arm/nic_400.h b/include/drivers/arm/nic_400.h
new file mode 100644
index 0000000..bb74982
--- /dev/null
+++ b/include/drivers/arm/nic_400.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NIC_400_H
+#define NIC_400_H
+
+/*
+ * Address of slave 'n' security setting in the NIC-400 address region
+ * control
+ */
+#define NIC400_ADDR_CTRL_SECURITY_REG(n)	(0x8 + (n) * 4)
+
+#endif /* NIC_400_H */
diff --git a/include/drivers/arm/pl011.h b/include/drivers/arm/pl011.h
new file mode 100644
index 0000000..8733d19
--- /dev/null
+++ b/include/drivers/arm/pl011.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PL011_H
+#define PL011_H
+
+#include <drivers/console.h>
+
+/* PL011 Registers */
+#define UARTDR                    0x000
+#define UARTRSR                   0x004
+#define UARTECR                   0x004
+#define UARTFR                    0x018
+#define UARTIMSC                  0x038
+#define UARTRIS                   0x03C
+#define UARTICR                   0x044
+
+/* PL011 registers (out of the SBSA specification) */
+#if !PL011_GENERIC_UART
+#define UARTILPR                  0x020
+#define UARTIBRD                  0x024
+#define UARTFBRD                  0x028
+#define UARTLCR_H                 0x02C
+#define UARTCR                    0x030
+#define UARTIFLS                  0x034
+#define UARTMIS                   0x040
+#define UARTDMACR                 0x048
+#endif /* !PL011_GENERIC_UART */
+
+/* Data status bits */
+#define UART_DATA_ERROR_MASK      0x0F00
+
+/* Status reg bits */
+#define UART_STATUS_ERROR_MASK    0x0F
+
+/* Flag reg bits */
+#define PL011_UARTFR_RI           (1 << 8)	/* Ring indicator */
+#define PL011_UARTFR_TXFE         (1 << 7)	/* Transmit FIFO empty */
+#define PL011_UARTFR_RXFF         (1 << 6)	/* Receive  FIFO full */
+#define PL011_UARTFR_TXFF         (1 << 5)	/* Transmit FIFO full */
+#define PL011_UARTFR_RXFE         (1 << 4)	/* Receive  FIFO empty */
+#define PL011_UARTFR_BUSY         (1 << 3)	/* UART busy */
+#define PL011_UARTFR_DCD          (1 << 2)	/* Data carrier detect */
+#define PL011_UARTFR_DSR          (1 << 1)	/* Data set ready */
+#define PL011_UARTFR_CTS          (1 << 0)	/* Clear to send */
+
+#define PL011_UARTFR_TXFF_BIT	5	/* Transmit FIFO full bit in UARTFR register */
+#define PL011_UARTFR_RXFE_BIT	4	/* Receive FIFO empty bit in UARTFR register */
+#define PL011_UARTFR_BUSY_BIT	3	/* UART busy bit in UARTFR register */
+
+/* Control reg bits */
+#if !PL011_GENERIC_UART
+#define PL011_UARTCR_CTSEN        (1 << 15)	/* CTS hardware flow control enable */
+#define PL011_UARTCR_RTSEN        (1 << 14)	/* RTS hardware flow control enable */
+#define PL011_UARTCR_RTS          (1 << 11)	/* Request to send */
+#define PL011_UARTCR_DTR          (1 << 10)	/* Data transmit ready. */
+#define PL011_UARTCR_RXE          (1 << 9)	/* Receive enable */
+#define PL011_UARTCR_TXE          (1 << 8)	/* Transmit enable */
+#define PL011_UARTCR_LBE          (1 << 7)	/* Loopback enable */
+#define PL011_UARTCR_UARTEN       (1 << 0)	/* UART Enable */
+
+#if !defined(PL011_LINE_CONTROL)
+/* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */
+#define PL011_LINE_CONTROL  (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8)
+#endif
+
+/* Line Control Register Bits */
+#define PL011_UARTLCR_H_SPS       (1 << 7)	/* Stick parity select */
+#define PL011_UARTLCR_H_WLEN_8    (3 << 5)
+#define PL011_UARTLCR_H_WLEN_7    (2 << 5)
+#define PL011_UARTLCR_H_WLEN_6    (1 << 5)
+#define PL011_UARTLCR_H_WLEN_5    (0 << 5)
+#define PL011_UARTLCR_H_FEN       (1 << 4)	/* FIFOs Enable */
+#define PL011_UARTLCR_H_STP2      (1 << 3)	/* Two stop bits select */
+#define PL011_UARTLCR_H_EPS       (1 << 2)	/* Even parity select */
+#define PL011_UARTLCR_H_PEN       (1 << 1)	/* Parity Enable */
+#define PL011_UARTLCR_H_BRK       (1 << 0)	/* Send break */
+
+#endif /* !PL011_GENERIC_UART */
+
+#define CONSOLE_T_PL011_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_pl011_t;
+
+/*
+ * Initialize a new PL011 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_pl011_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_pl011_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* PL011_H */
diff --git a/include/drivers/arm/pl061_gpio.h b/include/drivers/arm/pl061_gpio.h
new file mode 100644
index 0000000..68238c9
--- /dev/null
+++ b/include/drivers/arm/pl061_gpio.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PL061_GPIO_H
+#define PL061_GPIO_H
+
+#include <drivers/gpio.h>
+
+void pl061_gpio_register(uintptr_t base_addr, int gpio_dev);
+void pl061_gpio_init(void);
+
+#endif /* PL061_GPIO_H */
diff --git a/include/drivers/arm/sbsa.h b/include/drivers/arm/sbsa.h
new file mode 100644
index 0000000..9403634
--- /dev/null
+++ b/include/drivers/arm/sbsa.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SBSA_H
+#define SBSA_H
+
+#include <stdint.h>
+
+/* Register Offsets */
+#define SBSA_WDOG_WCS_OFFSET		UL(0x000)
+#define SBSA_WDOG_WOR_LOW_OFFSET	UL(0x008)
+#define SBSA_WDOG_WOR_HIGH_OFFSET	UL(0x00C)
+
+#define SBSA_WDOG_WCS_EN		U(0x1)
+
+#define SBSA_WDOG_WOR_WIDTH		UL(48)
+
+void sbsa_wdog_start(uintptr_t base, uint64_t ms);
+void sbsa_wdog_stop(uintptr_t base);
+
+#endif /* SBSA_H */
diff --git a/include/drivers/arm/smmu_v3.h b/include/drivers/arm/smmu_v3.h
new file mode 100644
index 0000000..a820a44
--- /dev/null
+++ b/include/drivers/arm/smmu_v3.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMMU_V3_H
+#define SMMU_V3_H
+
+#include <stdint.h>
+#include <lib/utils_def.h>
+
+/* SMMUv3 register offsets from device base */
+#define SMMU_GBPA	U(0x0044)
+#define SMMU_S_IDR1	U(0x8004)
+#define SMMU_S_INIT	U(0x803c)
+#define SMMU_S_GBPA	U(0x8044)
+
+/* SMMU_GBPA register fields */
+#define SMMU_GBPA_UPDATE		(1UL << 31)
+#define SMMU_GBPA_ABORT			(1UL << 20)
+
+/* SMMU_S_IDR1 register fields */
+#define SMMU_S_IDR1_SECURE_IMPL		(1UL << 31)
+
+/* SMMU_S_INIT register fields */
+#define SMMU_S_INIT_INV_ALL		(1UL << 0)
+
+/* SMMU_S_GBPA register fields */
+#define SMMU_S_GBPA_UPDATE		(1UL << 31)
+#define SMMU_S_GBPA_ABORT		(1UL << 20)
+
+int smmuv3_init(uintptr_t smmu_base);
+int smmuv3_security_init(uintptr_t smmu_base);
+
+#endif /* SMMU_V3_H */
diff --git a/include/drivers/arm/sp804_delay_timer.h b/include/drivers/arm/sp804_delay_timer.h
new file mode 100644
index 0000000..f8769e8
--- /dev/null
+++ b/include/drivers/arm/sp804_delay_timer.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP804_DELAY_TIMER_H
+#define SP804_DELAY_TIMER_H
+
+#include <stdint.h>
+
+#include <drivers/delay_timer.h>
+
+uint32_t sp804_get_timer_value(void);
+
+void sp804_timer_ops_init(uintptr_t base_addr, const timer_ops_t *ops);
+
+#define sp804_timer_init(base_addr, clk_mult, clk_div)			\
+	do {								\
+		static const timer_ops_t sp804_timer_ops = {		\
+			sp804_get_timer_value,				\
+			(clk_mult),					\
+			(clk_div)					\
+		};							\
+		sp804_timer_ops_init((base_addr), &sp804_timer_ops);	\
+	} while (0)
+
+#endif /* SP804_DELAY_TIMER_H */
diff --git a/include/drivers/arm/sp805.h b/include/drivers/arm/sp805.h
new file mode 100644
index 0000000..b00ede1
--- /dev/null
+++ b/include/drivers/arm/sp805.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP805_H
+#define SP805_H
+
+#include <lib/utils_def.h>
+
+/* SP805 register offset */
+#define SP805_WDOG_LOAD_OFF		UL(0x000)
+#define SP805_WDOG_CTR_OFF		UL(0x008)
+#define SP805_WDOG_LOCK_OFF		UL(0xc00)
+
+/* Magic word to unlock the wd registers */
+#define WDOG_UNLOCK_KEY			U(0x1ACCE551)
+
+/* Register field definitions */
+#define SP805_CTR_RESEN			(U(1) << 1)
+#define SP805_CTR_INTEN			(U(1) << 0)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/* Public high level API */
+
+void sp805_start(uintptr_t base, unsigned int ticks);
+void sp805_stop(uintptr_t base);
+void sp805_refresh(uintptr_t base, unsigned int ticks);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SP805_H */
diff --git a/include/drivers/arm/tzc380.h b/include/drivers/arm/tzc380.h
new file mode 100644
index 0000000..a8098a2
--- /dev/null
+++ b/include/drivers/arm/tzc380.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC380_H
+#define TZC380_H
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/utils_def.h>
+
+#define TZC380_CONFIGURATION_OFF	U(0x000)
+#define ACTION_OFF			U(0x004)
+#define LOCKDOWN_RANGE_OFF		U(0x008)
+#define LOCKDOWN_SELECT_OFF		U(0x00C)
+#define INT_STATUS			U(0x010)
+#define INT_CLEAR			U(0x014)
+
+#define FAIL_ADDRESS_LOW_OFF		U(0x020)
+#define FAIL_ADDRESS_HIGH_OFF		U(0x024)
+#define FAIL_CONTROL_OFF		U(0x028)
+#define FAIL_ID				U(0x02c)
+
+#define SPECULATION_CTRL_OFF		U(0x030)
+#define SECURITY_INV_EN_OFF		U(0x034)
+
+#define REGION_SETUP_LOW_OFF(n)		U(0x100 + (n) * 0x10)
+#define REGION_SETUP_HIGH_OFF(n)	U(0x104 + (n) * 0x10)
+#define REGION_ATTRIBUTES_OFF(n)	U(0x108 + (n) * 0x10)
+
+#define BUILD_CONFIG_AW_SHIFT		8
+#define BUILD_CONFIG_AW_MASK		U(0x3f)
+#define BUILD_CONFIG_NR_SHIFT		0
+#define BUILD_CONFIG_NR_MASK		U(0xf)
+
+#define ACTION_RV_SHIFT			0
+#define ACTION_RV_MASK			U(0x3)
+#define ACTION_RV_LOWOK			U(0x0)
+#define ACTION_RV_LOWERR		U(0x1)
+#define ACTION_RV_HIGHOK		U(0x2)
+#define ACTION_RV_HIGHERR		U(0x3)
+
+/* Speculation is enabled by default. */
+#define SPECULATION_CTRL_WRITE_DISABLE	BIT_32(1)
+#define SPECULATION_CTRL_READ_DISABLE	BIT_32(0)
+
+#define INT_STATUS_OVERRUN_SHIFT	1
+#define INT_STATUS_OVERRUN_MASK		U(0x1)
+#define INT_STATUS_STATUS_SHIFT		0
+#define INT_STATUS_STATUS_MASK		U(0x1)
+
+#define INT_CLEAR_CLEAR_SHIFT		0
+#define INT_CLEAR_CLEAR_MASK		U(0x1)
+
+#define TZC380_COMPONENT_ID		U(0xb105f00d)
+#define TZC380_PERIPH_ID_LOW		U(0x001bb380)
+#define TZC380_PERIPH_ID_HIGH		U(0x00000004)
+
+#define TZC_SP_NS_W			BIT_32(0)
+#define TZC_SP_NS_R			BIT_32(1)
+#define TZC_SP_S_W			BIT_32(2)
+#define TZC_SP_S_R			BIT_32(3)
+
+#define TZC_ATTR_SP_SHIFT		28
+#define TZC_ATTR_SP_ALL			((TZC_SP_S_W | TZC_SP_S_R | TZC_SP_NS_W | \
+					TZC_SP_NS_R) << TZC_ATTR_SP_SHIFT)
+#define TZC_ATTR_SP_S_RW		((TZC_SP_S_W | TZC_SP_S_R) << \
+					 TZC_ATTR_SP_SHIFT)
+#define TZC_ATTR_SP_NS_RW		((TZC_SP_NS_W | TZC_SP_NS_R) << \
+					TZC_ATTR_SP_SHIFT)
+
+#define TZC_REGION_SIZE_32K		U(0xe)
+#define TZC_REGION_SIZE_64K		U(0xf)
+#define TZC_REGION_SIZE_128K		U(0x10)
+#define TZC_REGION_SIZE_256K		U(0x11)
+#define TZC_REGION_SIZE_512K		U(0x12)
+#define TZC_REGION_SIZE_1M		U(0x13)
+#define TZC_REGION_SIZE_2M		U(0x14)
+#define TZC_REGION_SIZE_4M		U(0x15)
+#define TZC_REGION_SIZE_8M		U(0x16)
+#define TZC_REGION_SIZE_16M		U(0x17)
+#define TZC_REGION_SIZE_32M		U(0x18)
+#define TZC_REGION_SIZE_64M		U(0x19)
+#define TZC_REGION_SIZE_128M		U(0x1a)
+#define TZC_REGION_SIZE_256M		U(0x1b)
+#define TZC_REGION_SIZE_512M		U(0x1c)
+#define TZC_REGION_SIZE_1G		U(0x1d)
+#define TZC_REGION_SIZE_2G		U(0x1e)
+#define TZC_REGION_SIZE_4G		U(0x1f)
+#define TZC_REGION_SIZE_8G		U(0x20)
+#define TZC_REGION_SIZE_16G		U(0x21)
+#define TZC_REGION_SIZE_32G		U(0x22)
+#define TZC_REGION_SIZE_64G		U(0x23)
+#define TZC_REGION_SIZE_128G		U(0x24)
+#define TZC_REGION_SIZE_256G		U(0x25)
+#define TZC_REGION_SIZE_512G		U(0x26)
+#define TZC_REGION_SIZE_1T		U(0x27)
+#define TZC_REGION_SIZE_2T		U(0x28)
+#define TZC_REGION_SIZE_4T		U(0x29)
+#define TZC_REGION_SIZE_8T		U(0x2a)
+#define TZC_REGION_SIZE_16T		U(0x2b)
+#define TZC_REGION_SIZE_32T		U(0x2c)
+#define TZC_REGION_SIZE_64T		U(0x2d)
+#define TZC_REGION_SIZE_128T		U(0x2e)
+#define TZC_REGION_SIZE_256T		U(0x2f)
+#define TZC_REGION_SIZE_512T		U(0x30)
+#define TZC_REGION_SIZE_1P		U(0x31)
+#define TZC_REGION_SIZE_2P		U(0x32)
+#define TZC_REGION_SIZE_4P		U(0x33)
+#define TZC_REGION_SIZE_8P		U(0x34)
+#define TZC_REGION_SIZE_16P		U(0x35)
+#define TZC_REGION_SIZE_32P		U(0x36)
+#define TZC_REGION_SIZE_64P		U(0x37)
+#define TZC_REGION_SIZE_128P		U(0x38)
+#define TZC_REGION_SIZE_256P		U(0x39)
+#define TZC_REGION_SIZE_512P		U(0x3a)
+#define TZC_REGION_SIZE_1E		U(0x3b)
+#define TZC_REGION_SIZE_2E		U(0x3c)
+#define TZC_REGION_SIZE_4E		U(0x3d)
+#define TZC_REGION_SIZE_8E		U(0x3e)
+#define TZC_REGION_SIZE_16E		U(0x3f)
+
+#define TZC_REGION_SIZE_SHIFT		0x1
+#define TZC_REGION_SIZE_MASK		U(0x7e)
+#define TZC_ATTR_REGION_SIZE(s)		((s) << TZC_REGION_SIZE_SHIFT)
+
+#define TZC_ATTR_REGION_EN_SHIFT	0x0
+#define TZC_ATTR_REGION_EN_MASK		U(0x1)
+
+#define TZC_ATTR_REGION_EN
+#define TZC_ATTR_REGION_ENABLE		U(0x1)
+#define TZC_ATTR_REGION_DISABLE		U(0x0)
+
+#define	REGION_MAX	16
+
+void tzc380_init(uintptr_t base);
+void tzc380_configure_region(uint8_t region,
+			     uintptr_t region_base,
+			     unsigned int attr);
+void tzc380_set_action(unsigned int action);
+static inline void tzc_init(uintptr_t base)
+{
+	tzc380_init(base);
+}
+
+static inline void tzc_configure_region(uint8_t region,
+					uintptr_t region_base,
+					unsigned int attr)
+{
+	tzc380_configure_region(region, region_base, attr);
+}
+
+static inline void tzc_set_action(unsigned int action)
+{
+	tzc380_set_action(action);
+}
+
+#endif /* TZC380_H */
diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h
new file mode 100644
index 0000000..32aeb03
--- /dev/null
+++ b/include/drivers/arm/tzc400.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC400_H
+#define TZC400_H
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/utils_def.h>
+
+#define BUILD_CONFIG_OFF			U(0x000)
+#define GATE_KEEPER_OFF				U(0x008)
+#define SPECULATION_CTRL_OFF			U(0x00c)
+#define INT_STATUS				U(0x010)
+#define INT_CLEAR				U(0x014)
+
+#define FAIL_ADDRESS_LOW_OFF			U(0x020)
+#define FAIL_ADDRESS_HIGH_OFF			U(0x024)
+#define FAIL_CONTROL_OFF			U(0x028)
+#define FAIL_ID					U(0x02c)
+
+/* ID registers not common across different varieties of TZC */
+#define PID5					U(0xFD4)
+#define PID6					U(0xFD8)
+#define PID7					U(0xFDC)
+
+#define BUILD_CONFIG_NF_SHIFT			24
+#define BUILD_CONFIG_NF_MASK			U(0x3)
+#define BUILD_CONFIG_AW_SHIFT			8
+#define BUILD_CONFIG_AW_MASK			U(0x3f)
+#define BUILD_CONFIG_NR_SHIFT			0
+#define BUILD_CONFIG_NR_MASK			U(0x1f)
+
+/*
+ * Number of gate keepers is implementation defined. But we know the max for
+ * this device is 4. Get implementation details from BUILD_CONFIG.
+ */
+#define GATE_KEEPER_OS_SHIFT			16
+#define GATE_KEEPER_OS_MASK			U(0xf)
+#define GATE_KEEPER_OR_SHIFT			0
+#define GATE_KEEPER_OR_MASK			U(0xf)
+#define GATE_KEEPER_FILTER_MASK			U(0x1)
+
+/* Speculation is enabled by default. */
+#define SPECULATION_CTRL_WRITE_DISABLE		BIT_32(1)
+#define SPECULATION_CTRL_READ_DISABLE		BIT_32(0)
+
+/* Max number of filters allowed is 4. */
+#define INT_STATUS_OVERLAP_SHIFT		16
+#define INT_STATUS_OVERLAP_MASK			U(0xf)
+#define INT_STATUS_OVERRUN_SHIFT		8
+#define INT_STATUS_OVERRUN_MASK			U(0xf)
+#define INT_STATUS_STATUS_SHIFT			0
+#define INT_STATUS_STATUS_MASK			U(0xf)
+
+#define INT_CLEAR_CLEAR_SHIFT			0
+#define INT_CLEAR_CLEAR_MASK			U(0xf)
+
+#define FAIL_CONTROL_DIR_SHIFT			24
+#define FAIL_CONTROL_DIR_READ			U(0)
+#define FAIL_CONTROL_DIR_WRITE			U(1)
+#define FAIL_CONTROL_NS_SHIFT			21
+#define FAIL_CONTROL_NS_SECURE			U(0)
+#define FAIL_CONTROL_NS_NONSECURE		U(1)
+#define FAIL_CONTROL_PRIV_SHIFT			20
+#define FAIL_CONTROL_PRIV_PRIV			U(0)
+#define FAIL_CONTROL_PRIV_UNPRIV		U(1)
+
+/*
+ * FAIL_ID_ID_MASK depends on AID_WIDTH which is platform specific.
+ * Platform should provide the value on initialisation.
+ */
+#define FAIL_ID_VNET_SHIFT			24
+#define FAIL_ID_VNET_MASK			U(0xf)
+#define FAIL_ID_ID_SHIFT			0
+
+#define TZC_400_PERIPHERAL_ID			U(0x460)
+
+/* Filter enable bits in a TZC */
+#define TZC_400_REGION_ATTR_F_EN_MASK		U(0xf)
+#define TZC_400_REGION_ATTR_FILTER_BIT(x)				\
+				((U(1) << (x)) << TZC_REGION_ATTR_F_EN_SHIFT)
+#define TZC_400_REGION_ATTR_FILTER_BIT_ALL				\
+				(TZC_400_REGION_ATTR_F_EN_MASK <<	\
+				TZC_REGION_ATTR_F_EN_SHIFT)
+
+/*
+ * All TZC region configuration registers are placed one after another. It
+ * depicts size of block of registers for programming each region.
+ */
+#define TZC_400_REGION_SIZE			U(0x20)
+#define TZC_400_ACTION_OFF			U(0x4)
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+void tzc400_init(uintptr_t base);
+void tzc400_configure_region0(unsigned int sec_attr,
+			   unsigned int ns_device_access);
+void tzc400_configure_region(unsigned int filters,
+			  unsigned int region,
+			  unsigned long long region_base,
+			  unsigned long long region_top,
+			  unsigned int sec_attr,
+			  unsigned int nsaid_permissions);
+void tzc400_set_action(unsigned int action);
+void tzc400_enable_filters(void);
+void tzc400_disable_filters(void);
+
+static inline void tzc_init(uintptr_t base)
+{
+	tzc400_init(base);
+}
+
+static inline void tzc_configure_region0(
+			unsigned int sec_attr,
+			unsigned int ns_device_access)
+{
+	tzc400_configure_region0(sec_attr, ns_device_access);
+}
+
+static inline void tzc_configure_region(
+			  unsigned int filters,
+			  unsigned int region,
+			  unsigned long long region_base,
+			  unsigned long long region_top,
+			  unsigned int sec_attr,
+			  unsigned int ns_device_access)
+{
+	tzc400_configure_region(filters, region, region_base,
+			region_top, sec_attr, ns_device_access);
+}
+
+static inline void tzc_set_action(unsigned int action)
+{
+	tzc400_set_action(action);
+}
+
+
+static inline void tzc_enable_filters(void)
+{
+	tzc400_enable_filters();
+}
+
+static inline void tzc_disable_filters(void)
+{
+	tzc400_disable_filters();
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* TZC400_H */
diff --git a/include/drivers/arm/tzc_common.h b/include/drivers/arm/tzc_common.h
new file mode 100644
index 0000000..e58201c
--- /dev/null
+++ b/include/drivers/arm/tzc_common.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC_COMMON_H
+#define TZC_COMMON_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Offset of core registers from the start of the base of configuration
+ * registers for each region.
+ */
+
+/* ID Registers */
+#define PID0_OFF					U(0xfe0)
+#define PID1_OFF					U(0xfe4)
+#define PID2_OFF					U(0xfe8)
+#define PID3_OFF					U(0xfec)
+#define PID4_OFF					U(0xfd0)
+#define CID0_OFF					U(0xff0)
+#define CID1_OFF					U(0xff4)
+#define CID2_OFF					U(0xff8)
+#define CID3_OFF					U(0xffc)
+
+/*
+ * What type of action is expected when an access violation occurs.
+ * The memory requested is returned as zero. But we can also raise an event to
+ * let the system know it happened.
+ * We can raise an interrupt(INT) and/or cause an exception(ERR).
+ *  TZC_ACTION_NONE    - No interrupt, no Exception
+ *  TZC_ACTION_ERR     - No interrupt, raise exception -> sync external
+ *                       data abort
+ *  TZC_ACTION_INT     - Raise interrupt, no exception
+ *  TZC_ACTION_ERR_INT - Raise interrupt, raise exception -> sync
+ *                       external data abort
+ */
+#define TZC_ACTION_NONE			U(0)
+#define TZC_ACTION_ERR			U(1)
+#define TZC_ACTION_INT			U(2)
+#define TZC_ACTION_ERR_INT		(TZC_ACTION_ERR | TZC_ACTION_INT)
+
+/* Bit positions of TZC_ACTION registers */
+#define TZC_ACTION_RV_SHIFT				0
+#define TZC_ACTION_RV_MASK				U(0x3)
+#define TZC_ACTION_RV_LOWOK				U(0x0)
+#define TZC_ACTION_RV_LOWERR				U(0x1)
+#define TZC_ACTION_RV_HIGHOK				U(0x2)
+#define TZC_ACTION_RV_HIGHERR				U(0x3)
+
+/*
+ * Controls secure access to a region. If not enabled secure access is not
+ * allowed to region.
+ */
+#define TZC_REGION_S_NONE		U(0)
+#define TZC_REGION_S_RD			U(1)
+#define TZC_REGION_S_WR			U(2)
+#define TZC_REGION_S_RDWR		(TZC_REGION_S_RD | TZC_REGION_S_WR)
+
+#define TZC_REGION_ATTR_S_RD_SHIFT			30
+#define TZC_REGION_ATTR_S_WR_SHIFT			31
+#define TZC_REGION_ATTR_F_EN_SHIFT			0
+#define TZC_REGION_ATTR_SEC_SHIFT			30
+#define TZC_REGION_ATTR_S_RD_MASK			U(0x1)
+#define TZC_REGION_ATTR_S_WR_MASK			U(0x1)
+#define TZC_REGION_ATTR_SEC_MASK			U(0x3)
+
+#define TZC_REGION_ACCESS_WR_EN_SHIFT			16
+#define TZC_REGION_ACCESS_RD_EN_SHIFT			0
+#define TZC_REGION_ACCESS_ID_MASK			U(0xf)
+
+/* Macros for allowing Non-Secure access to a region based on NSAID */
+#define TZC_REGION_ACCESS_RD(nsaid)				\
+	((U(1) << ((nsaid) & TZC_REGION_ACCESS_ID_MASK)) <<	\
+	 TZC_REGION_ACCESS_RD_EN_SHIFT)
+#define TZC_REGION_ACCESS_WR(nsaid)				\
+	((U(1) << ((nsaid) & TZC_REGION_ACCESS_ID_MASK)) <<	\
+	 TZC_REGION_ACCESS_WR_EN_SHIFT)
+#define TZC_REGION_ACCESS_RDWR(nsaid)				\
+	(TZC_REGION_ACCESS_RD(nsaid) |				\
+	TZC_REGION_ACCESS_WR(nsaid))
+
+/* Returns offset of registers to program for a given region no */
+#define TZC_REGION_OFFSET(region_size, region_no)	\
+				((region_size) * (region_no))
+
+#endif /* TZC_COMMON_H */
diff --git a/include/drivers/arm/tzc_dmc500.h b/include/drivers/arm/tzc_dmc500.h
new file mode 100644
index 0000000..cce074c
--- /dev/null
+++ b/include/drivers/arm/tzc_dmc500.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC_DMC500_H
+#define TZC_DMC500_H
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/utils_def.h>
+
+#define SI_STATUS_OFFSET				U(0x000)
+#define SI_STATE_CTRL_OFFSET				U(0x030)
+#define SI_FLUSH_CTRL_OFFSET				U(0x034)
+#define SI_INT_CONTROL_OFFSET				U(0x048)
+
+#define SI_INT_STATUS_OFFSET				U(0x004)
+#define SI_TZ_FAIL_ADDRESS_LOW_OFFSET			U(0x008)
+#define SI_TZ_FAIL_ADDRESS_HIGH_OFFSET			U(0x00c)
+#define SI_FAIL_CONTROL_OFFSET				U(0x010)
+#define SI_FAIL_ID_OFFSET				U(0x014)
+#define SI_INT_CLR_OFFSET				U(0x04c)
+
+/*
+ * DMC-500 has 2 system interfaces each having a similar set of regs
+ * to configure each interface.
+ */
+#define SI0_BASE					U(0x0000)
+#define SI1_BASE					U(0x0200)
+
+/* Bit positions of SIx_SI_STATUS */
+#define SI_EMPTY_SHIFT					1
+#define SI_STALL_ACK_SHIFT				0
+#define SI_EMPTY_MASK					U(0x01)
+#define SI_STALL_ACK_MASK				U(0x01)
+
+/* Bit positions of SIx_SI_INT_STATUS */
+#define PMU_REQ_INT_OVERFLOW_STATUS_SHIFT		18
+#define FAILED_ACCESS_INT_OVERFLOW_STATUS_SHIFT		16
+#define PMU_REQ_INT_STATUS_SHIFT			2
+#define FAILED_ACCESS_INT_INFO_TZ_OVERLAP_STATUS_SHIFT	1
+#define FAILED_ACCESS_INT_STATUS_SHIFT			0
+#define PMU_REQ_INT_OVERFLOW_STATUS_MASK		U(0x1)
+#define FAILED_ACCESS_INT_OVERFLOW_STATUS_MASK		U(0x1)
+#define PMU_REQ_INT_STATUS_MASK				U(0x1)
+#define FAILED_ACCESS_INT_INFO_TZ_OVERLAP_STATUS_MASK	U(0x1)
+#define FAILED_ACCESS_INT_STATUS_MASK			U(0x1)
+
+/* Bit positions of SIx_TZ_FAIL_CONTROL */
+#define DIRECTION_SHIFT					24
+#define NON_SECURE_SHIFT				21
+#define PRIVILEGED_SHIFT				20
+#define FAILED_ACCESS_INT_INFO_RANK_MASKED_SHIFT	3
+#define FAILED_ACCESS_INT_INFO_UNMAPPED_SHIFT		2
+#define FAILED_ACCESS_INT_TZ_FAIL_SHIFT			1
+#define FAILED_ACCESS_INT_INFO_OUTSIDE_DEFAULT_SHIFT	0
+#define DIRECTION_MASK					U(0x1)
+#define NON_SECURE_MASK					U(0x1)
+#define PRIVILEGED_MASK					U(0x1)
+#define FAILED_ACCESS_INT_INFO_RANK_MASKED_MASK		U(0x1)
+#define FAILED_ACCESS_INT_INFO_UNMAPPED_MASK		U(0x1)
+#define FAILED_ACCESS_INT_TZ_FAIL_MASK			U(0x1)
+#define FAILED_ACCESS_INT_INFO_OUTSIDE_DEFAULT_MASK	U(0x1)
+
+/* Bit positions of SIx_FAIL_STATUS */
+#define FAIL_ID_VNET_SHIFT				24
+#define FAIL_ID_ID_SHIFT				0
+#define FAIL_ID_VNET_MASK				U(0xf)
+#define FAIL_ID_ID_MASK					U(0xffffff)
+
+/* Bit positions of SIx_SI_STATE_CONTRL */
+#define SI_STALL_REQ_GO					0x0
+#define SI_STALL_REQ_STALL				0x1
+
+/* Bit positions of SIx_SI_FLUSH_CONTROL */
+#define SI_FLUSH_REQ_INACTIVE				0x0
+#define SI_FLUSH_REQ_ACTIVE				0x1
+#define SI_FLUSH_REQ_MASK				0x1
+
+/* Bit positions of SIx_SI_INT_CONTROL */
+#define PMU_REQ_INT_EN_SHIFT				2
+#define OVERLAP_DETECT_INT_EN_SHIFT			1
+#define FAILED_ACCESS_INT_EN_SHIFT			0
+#define PMU_REQ_INT_EN_MASK				U(0x1)
+#define OVERLAP_DETECT_INT_EN_MASK			U(0x1)
+#define FAILED_ACCESS_INT_EN_MASK			U(0x1)
+#define PMU_REQ_INT_EN					U(0x1)
+#define OVERLAP_DETECT_INT_EN				U(0x1)
+#define FAILED_ACCESS_INT_EN				U(0x1)
+
+/* Bit positions of SIx_SI_INT_CLR */
+#define PMU_REQ_OFLOW_CLR_SHIFT				18
+#define FAILED_ACCESS_OFLOW_CLR_SHIFT			16
+#define PMU_REQ_INT_CLR_SHIFT				2
+#define FAILED_ACCESS_INT_CLR_SHIFT			0
+#define PMU_REQ_OFLOW_CLR_MASK				U(0x1)
+#define FAILED_ACCESS_OFLOW_CLR_MASK			U(0x1)
+#define PMU_REQ_INT_CLR_MASK				U(0x1)
+#define FAILED_ACCESS_INT_CLR_MASK			U(0x1)
+#define PMU_REQ_OFLOW_CLR				U(0x1)
+#define FAILED_ACCESS_OFLOW_CLR				U(0x1)
+#define PMU_REQ_INT_CLR					U(0x1)
+#define FAILED_ACCESS_INT_CLR				U(0x1)
+
+/* Macro to get the correct base register for a system interface */
+#define IFACE_OFFSET(sys_if)	((sys_if) ? SI1_BASE : SI0_BASE)
+
+#define MAX_SYS_IF_COUNT				U(2)
+#define MAX_REGION_VAL					8
+
+/* DMC-500 supports striping across a max of 4 DMC instances */
+#define MAX_DMC_COUNT					4
+
+/* Consist of part_number_1 and part_number_0 */
+#define DMC500_PERIPHERAL_ID				U(0x0450)
+
+/* Filter enable bits in a TZC */
+#define TZC_DMC500_REGION_ATTR_F_EN_MASK		U(0x1)
+
+/* Length of registers for configuring each region */
+#define TZC_DMC500_REGION_SIZE				U(0x018)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/*
+ * Contains the base addresses of all the DMC instances.
+ */
+typedef struct tzc_dmc500_driver_data {
+	uintptr_t dmc_base[MAX_DMC_COUNT];
+	int dmc_count;
+	unsigned int sys_if_count;
+} tzc_dmc500_driver_data_t;
+
+void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data);
+void tzc_dmc500_configure_region0(unsigned int sec_attr,
+				unsigned int nsaid_permissions);
+void tzc_dmc500_configure_region(unsigned int region_no,
+				unsigned long long region_base,
+				unsigned long long region_top,
+				unsigned int sec_attr,
+				unsigned int nsaid_permissions);
+void tzc_dmc500_set_action(unsigned int action);
+void tzc_dmc500_config_complete(void);
+int tzc_dmc500_verify_complete(void);
+
+
+#endif /* __ASSEMBLER__ */
+#endif /* TZC_DMC500_H */
diff --git a/include/drivers/arm/tzc_dmc620.h b/include/drivers/arm/tzc_dmc620.h
new file mode 100644
index 0000000..e0e6760
--- /dev/null
+++ b/include/drivers/arm/tzc_dmc620.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TZC_DMC620_H
+#define TZC_DMC620_H
+
+#include <lib/utils_def.h>
+
+/* DMC-620 memc register offsets */
+#define DMC620_MEMC_STATUS	U(0x0000)
+#define DMC620_MEMC_CMD		U(0x0008)
+
+/* Mask value to check the status of memc_cmd register */
+#define DMC620_MEMC_CMD_MASK	U(0x00000007)
+
+/* memc_cmd register's action values */
+#define DMC620_MEMC_CMD_GO	U(0x00000003)
+#define DMC620_MEMC_CMD_EXECUTE	U(0x00000004)
+
+/* Address offsets of access address next region 0 registers */
+#define DMC620_ACC_ADDR_MIN_31_00_NEXT_BASE	U(0x0080)
+#define DMC620_ACC_ADDR_MIN_47_32_NEXT_BASE	U(0x0084)
+#define DMC620_ACC_ADDR_MAX_31_00_NEXT_BASE	U(0x0088)
+#define DMC620_ACC_ADDR_MAX_47_32_NEXT_BASE	U(0x008c)
+
+/* Length of one block of access address next register region */
+#define DMC620_ACC_ADDR_NEXT_SIZE		U(0x0010)
+
+/* Address offsets of access address next registers */
+#define DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no)	\
+		(DMC620_ACC_ADDR_MIN_31_00_NEXT_BASE +	\
+			(region_no * DMC620_ACC_ADDR_NEXT_SIZE))
+#define DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no)	\
+		(DMC620_ACC_ADDR_MIN_47_32_NEXT_BASE +	\
+			(region_no * DMC620_ACC_ADDR_NEXT_SIZE))
+#define DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no)	\
+		(DMC620_ACC_ADDR_MAX_31_00_NEXT_BASE +	\
+			(region_no * DMC620_ACC_ADDR_NEXT_SIZE))
+#define DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no)	\
+		(DMC620_ACC_ADDR_MAX_47_32_NEXT_BASE +	\
+			(region_no * DMC620_ACC_ADDR_NEXT_SIZE))
+
+/* Number of TZC address regions in DMC-620 */
+#define DMC620_ACC_ADDR_COUNT	U(8)
+/* Width of access address registers */
+#define DMC620_ACC_ADDR_WIDTH	U(32)
+
+/* Peripheral ID registers offsets */
+#define DMC620_PERIPHERAL_ID_0		U(0x1fe0)
+
+/* Default values in id registers */
+#define DMC620_PERIPHERAL_ID_0_VALUE	U(0x00000054)
+
+/* Secure access region attributes. */
+#define TZC_DMC620_REGION_NS_RD		U(0x00000001)
+#define TZC_DMC620_REGION_NS_WR		U(0x00000002)
+#define TZC_DMC620_REGION_NS_RDWR	\
+	(TZC_DMC620_REGION_NS_RD | TZC_DMC620_REGION_NS_WR)
+#define TZC_DMC620_REGION_S_RD		U(0x00000004)
+#define TZC_DMC620_REGION_S_WR		U(0x00000008)
+#define TZC_DMC620_REGION_S_RDWR	\
+	(TZC_DMC620_REGION_S_RD | TZC_DMC620_REGION_S_WR)
+#define TZC_DMC620_REGION_S_NS_RDWR	\
+	(TZC_DMC620_REGION_NS_RDWR | TZC_DMC620_REGION_S_RDWR)
+
+/*
+ * Contains pointer to the base addresses of all the DMC-620 instances.
+ * 'dmc_count' specifies the number of DMC base addresses contained in the
+ * array pointed to by dmc_base.
+ */
+typedef struct tzc_dmc620_driver_data {
+	const uintptr_t *dmc_base;
+	const unsigned int dmc_count;
+} tzc_dmc620_driver_data_t;
+
+/*
+ * Contains region base, region top addresses and corresponding attributes
+ * for configuring TZC access region registers.
+ */
+typedef struct tzc_dmc620_acc_addr_data {
+	const unsigned long long region_base;
+	const unsigned long long region_top;
+	const unsigned int sec_attr;
+} tzc_dmc620_acc_addr_data_t;
+
+/*
+ * Contains platform specific data for configuring TZC region base and
+ * region top address. 'acc_addr_count' specifies the number of
+ * valid entries in 'plat_acc_addr_data' array.
+ */
+typedef struct tzc_dmc620_config_data {
+	const tzc_dmc620_driver_data_t *plat_drv_data;
+	const tzc_dmc620_acc_addr_data_t *plat_acc_addr_data;
+	const uint8_t acc_addr_count;
+} tzc_dmc620_config_data_t;
+
+/* Function prototypes */
+void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data);
+
+#endif /* TZC_DMC620_H */
+
diff --git a/include/drivers/auth/auth_common.h b/include/drivers/auth/auth_common.h
new file mode 100644
index 0000000..e6859fd
--- /dev/null
+++ b/include/drivers/auth/auth_common.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AUTH_COMMON_H
+#define AUTH_COMMON_H
+
+/*
+ * Authentication framework common types
+ */
+
+/*
+ * Type of parameters that can be extracted from an image and
+ * used for authentication
+ */
+typedef enum auth_param_type_enum {
+	AUTH_PARAM_NONE,
+	AUTH_PARAM_RAW_DATA,		/* Raw image data */
+	AUTH_PARAM_SIG,			/* The image signature */
+	AUTH_PARAM_SIG_ALG,		/* The image signature algorithm */
+	AUTH_PARAM_HASH,		/* A hash (including the algorithm) */
+	AUTH_PARAM_PUB_KEY,		/* A public key */
+	AUTH_PARAM_NV_CTR,		/* A non-volatile counter */
+} auth_param_type_t;
+
+/*
+ * Defines an authentication parameter. The cookie will be interpreted by the
+ * image parser module.
+ */
+typedef struct auth_param_type_desc_s {
+	auth_param_type_t type;
+	void *cookie;
+} auth_param_type_desc_t;
+
+/*
+ * Store a pointer to the authentication parameter and its length
+ */
+typedef struct auth_param_data_desc_s {
+	void *ptr;
+	unsigned int len;
+} auth_param_data_desc_t;
+
+/*
+ * Authentication parameter descriptor, including type and value
+ */
+typedef struct auth_param_desc_s {
+	auth_param_type_desc_t *type_desc;
+	auth_param_data_desc_t data;
+} auth_param_desc_t;
+
+/*
+ * The method type defines how an image is authenticated
+ */
+typedef enum auth_method_type_enum {
+	AUTH_METHOD_NONE = 0,
+	AUTH_METHOD_HASH,	/* Authenticate by hash matching */
+	AUTH_METHOD_SIG,	/* Authenticate by PK operation */
+	AUTH_METHOD_NV_CTR,	/* Authenticate by Non-Volatile Counter */
+	AUTH_METHOD_NUM 	/* Number of methods */
+} auth_method_type_t;
+
+/*
+ * Parameters for authentication by hash matching
+ */
+typedef struct auth_method_param_hash_s {
+	auth_param_type_desc_t *data;	/* Data to hash */
+	auth_param_type_desc_t *hash;	/* Hash to match with */
+} auth_method_param_hash_t;
+
+/*
+ * Parameters for authentication by signature
+ */
+typedef struct auth_method_param_sig_s {
+	auth_param_type_desc_t *pk;	/* Public key */
+	auth_param_type_desc_t *sig;	/* Signature to check */
+	auth_param_type_desc_t *alg;	/* Signature algorithm */
+	auth_param_type_desc_t *data;	/* Data signed */
+} auth_method_param_sig_t;
+
+/*
+ * Parameters for authentication by NV counter
+ */
+typedef struct auth_method_param_nv_ctr_s {
+	auth_param_type_desc_t *cert_nv_ctr;	/* NV counter in certificate */
+	auth_param_type_desc_t *plat_nv_ctr;	/* NV counter in platform */
+} auth_method_param_nv_ctr_t;
+
+/*
+ * Authentication method descriptor
+ */
+typedef struct auth_method_desc_s {
+	auth_method_type_t type;
+	union {
+		auth_method_param_hash_t hash;
+		auth_method_param_sig_t sig;
+		auth_method_param_nv_ctr_t nv_ctr;
+	} param;
+} auth_method_desc_t;
+
+/*
+ * Helper macro to define an authentication parameter type descriptor
+ */
+#define AUTH_PARAM_TYPE_DESC(_type, _cookie) \
+	{ \
+		.type = _type, \
+		.cookie = (void *)_cookie \
+	}
+
+/*
+ * Helper macro to define an authentication parameter data descriptor
+ */
+#define AUTH_PARAM_DATA_DESC(_ptr, _len) \
+	{ \
+		.ptr = (void *)_ptr, \
+		.len = (unsigned int)_len \
+	}
+
+#endif /* AUTH_COMMON_H */
diff --git a/include/drivers/auth/auth_mod.h b/include/drivers/auth/auth_mod.h
new file mode 100644
index 0000000..6c48124
--- /dev/null
+++ b/include/drivers/auth/auth_mod.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AUTH_MOD_H
+#define AUTH_MOD_H
+
+#if TRUSTED_BOARD_BOOT
+
+#include <common/tbbr/cot_def.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/auth/auth_common.h>
+#include <drivers/auth/img_parser_mod.h>
+
+/*
+ * Image flags
+ */
+#define IMG_FLAG_AUTHENTICATED		(1 << 0)
+
+
+/*
+ * Authentication image descriptor
+ */
+typedef struct auth_img_desc_s {
+	unsigned int img_id;
+	img_type_t img_type;
+	const struct auth_img_desc_s *parent;
+	const auth_method_desc_t *const img_auth_methods;
+	const auth_param_desc_t *const authenticated_data;
+} auth_img_desc_t;
+
+/* Public functions */
+void auth_mod_init(void);
+int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id);
+int auth_mod_verify_img(unsigned int img_id,
+			void *img_ptr,
+			unsigned int img_len);
+
+/* Macro to register a CoT defined as an array of auth_img_desc_t pointers */
+#define REGISTER_COT(_cot) \
+	const auth_img_desc_t *const *const cot_desc_ptr = (_cot); \
+	unsigned int auth_img_flags[MAX_NUMBER_IDS]
+
+extern const auth_img_desc_t *const *const cot_desc_ptr;
+extern unsigned int auth_img_flags[MAX_NUMBER_IDS];
+
+#endif /* TRUSTED_BOARD_BOOT */
+
+#endif /* AUTH_MOD_H */
diff --git a/include/drivers/auth/crypto_mod.h b/include/drivers/auth/crypto_mod.h
new file mode 100644
index 0000000..3a42105
--- /dev/null
+++ b/include/drivers/auth/crypto_mod.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_MOD_H
+#define CRYPTO_MOD_H
+
+/* Return values */
+enum crypto_ret_value {
+	CRYPTO_SUCCESS = 0,
+	CRYPTO_ERR_INIT,
+	CRYPTO_ERR_HASH,
+	CRYPTO_ERR_SIGNATURE,
+	CRYPTO_ERR_UNKNOWN
+};
+
+/*
+ * Cryptographic library descriptor
+ */
+typedef struct crypto_lib_desc_s {
+	const char *name;
+
+	/* Initialize library. This function is not expected to fail. All errors
+	 * must be handled inside the function, asserting or panicing in case of
+	 * a non-recoverable error */
+	void (*init)(void);
+
+	/* Verify a digital signature. Return one of the
+	 * 'enum crypto_ret_value' options */
+	int (*verify_signature)(void *data_ptr, unsigned int data_len,
+				void *sig_ptr, unsigned int sig_len,
+				void *sig_alg, unsigned int sig_alg_len,
+				void *pk_ptr, unsigned int pk_len);
+
+	/* Verify a hash. Return one of the 'enum crypto_ret_value' options */
+	int (*verify_hash)(void *data_ptr, unsigned int data_len,
+			   void *digest_info_ptr, unsigned int digest_info_len);
+} crypto_lib_desc_t;
+
+/* Public functions */
+void crypto_mod_init(void);
+int crypto_mod_verify_signature(void *data_ptr, unsigned int data_len,
+				void *sig_ptr, unsigned int sig_len,
+				void *sig_alg_ptr, unsigned int sig_alg_len,
+				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);
+
+/* Macro to register a cryptographic library */
+#define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash) \
+	const crypto_lib_desc_t crypto_lib_desc = { \
+		.name = _name, \
+		.init = _init, \
+		.verify_signature = _verify_signature, \
+		.verify_hash = _verify_hash \
+	}
+
+extern const crypto_lib_desc_t crypto_lib_desc;
+
+#endif /* CRYPTO_MOD_H */
diff --git a/include/drivers/auth/img_parser_mod.h b/include/drivers/auth/img_parser_mod.h
new file mode 100644
index 0000000..b2fb60e
--- /dev/null
+++ b/include/drivers/auth/img_parser_mod.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMG_PARSER_MOD_H
+#define IMG_PARSER_MOD_H
+
+#include <drivers/auth/auth_common.h>
+
+/*
+ * Return values
+ */
+enum img_parser_ret_value {
+	IMG_PARSER_OK,
+	IMG_PARSER_ERR,			/* Parser internal error */
+	IMG_PARSER_ERR_FORMAT,		/* Malformed image */
+	IMG_PARSER_ERR_NOT_FOUND	/* Authentication data not found */
+};
+
+/*
+ * Image types. A parser should be instantiated and registered for each type
+ */
+typedef enum img_type_enum {
+	IMG_RAW,			/* Binary image */
+	IMG_PLAT,			/* Platform specific format */
+	IMG_CERT,			/* X509v3 certificate */
+	IMG_MAX_TYPES,
+} img_type_t;
+
+/* Image parser library structure */
+typedef struct img_parser_lib_desc_s {
+	img_type_t img_type;
+	const char *name;
+
+	void (*init)(void);
+	int (*check_integrity)(void *img, unsigned int img_len);
+	int (*get_auth_param)(const auth_param_type_desc_t *type_desc,
+			void *img, unsigned int img_len,
+			void **param, unsigned int *param_len);
+} img_parser_lib_desc_t;
+
+/* Exported functions */
+void img_parser_init(void);
+int img_parser_check_integrity(img_type_t img_type,
+		void *img_ptr, unsigned int img_len);
+int img_parser_get_auth_param(img_type_t img_type,
+		const auth_param_type_desc_t *type_desc,
+		void *img_ptr, unsigned int img_len,
+		void **param_ptr, unsigned int *param_len);
+
+/* Macro to register an image parser library */
+#define REGISTER_IMG_PARSER_LIB(_type, _name, _init, _check_int, _get_param) \
+	static const img_parser_lib_desc_t __img_parser_lib_desc_##_type \
+	__section(".img_parser_lib_descs") __used = { \
+		.img_type = _type, \
+		.name = _name, \
+		.init = _init, \
+		.check_integrity = _check_int, \
+		.get_auth_param = _get_param \
+	}
+
+#endif /* IMG_PARSER_MOD_H */
diff --git a/include/drivers/auth/mbedtls/mbedtls_common.h b/include/drivers/auth/mbedtls/mbedtls_common.h
new file mode 100644
index 0000000..a9c2352
--- /dev/null
+++ b/include/drivers/auth/mbedtls/mbedtls_common.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MBEDTLS_COMMON_H
+#define MBEDTLS_COMMON_H
+
+void mbedtls_init(void);
+
+#endif /* MBEDTLS_COMMON_H */
diff --git a/include/drivers/auth/mbedtls/mbedtls_config.h b/include/drivers/auth/mbedtls/mbedtls_config.h
new file mode 100644
index 0000000..acfde26
--- /dev/null
+++ b/include/drivers/auth/mbedtls/mbedtls_config.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MBEDTLS_CONFIG_H
+#define MBEDTLS_CONFIG_H
+
+/*
+ * Key algorithms currently supported on mbed TLS libraries
+ */
+#define TF_MBEDTLS_RSA			1
+#define TF_MBEDTLS_ECDSA		2
+#define TF_MBEDTLS_RSA_AND_ECDSA	3
+
+/*
+ * Hash algorithms currently supported on mbed TLS libraries
+ */
+#define TF_MBEDTLS_SHA256		1
+#define TF_MBEDTLS_SHA384		2
+#define TF_MBEDTLS_SHA512		3
+
+/*
+ * Configuration file to build mbed TLS with the required features for
+ * Trusted Boot
+ */
+
+#define MBEDTLS_PLATFORM_MEMORY
+#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+/* Prevent mbed TLS from using snprintf so that it can use tf_snprintf. */
+#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+
+#define MBEDTLS_PKCS1_V21
+
+#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+#define MBEDTLS_X509_CHECK_KEY_USAGE
+#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
+
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_ASN1_WRITE_C
+
+#define MBEDTLS_BASE64_C
+#define MBEDTLS_BIGNUM_C
+
+#define MBEDTLS_ERROR_C
+#define MBEDTLS_MD_C
+
+#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
+#define MBEDTLS_OID_C
+
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_PK_WRITE_C
+
+#define MBEDTLS_PLATFORM_C
+
+#if (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA)
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA)
+#define MBEDTLS_RSA_C
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+#elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA)
+#define MBEDTLS_RSA_C
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#endif
+
+#define MBEDTLS_SHA256_C
+#if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256)
+#define MBEDTLS_SHA512_C
+#endif
+
+#define MBEDTLS_VERSION_C
+
+#define MBEDTLS_X509_USE_C
+#define MBEDTLS_X509_CRT_PARSE_C
+
+/* MPI / BIGNUM options */
+#define MBEDTLS_MPI_WINDOW_SIZE              2
+#define MBEDTLS_MPI_MAX_SIZE               256
+
+/* Memory buffer allocator options */
+#define MBEDTLS_MEMORY_ALIGN_MULTIPLE        8
+
+#ifndef __ASSEMBLER__
+/* System headers required to build mbed TLS with the current configuration */
+#include <stdlib.h>
+#include "mbedtls/check_config.h"
+#endif
+
+/*
+ * Determine Mbed TLS heap size
+ * 13312 = 13*1024
+ * 7168 = 7*1024
+ */
+#if (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA) \
+	|| (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA)
+#define TF_MBEDTLS_HEAP_SIZE		U(13312)
+#elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA)
+#define TF_MBEDTLS_HEAP_SIZE		U(7168)
+#endif
+
+#endif /* MBEDTLS_CONFIG_H */
diff --git a/include/drivers/cadence/cdns_uart.h b/include/drivers/cadence/cdns_uart.h
new file mode 100644
index 0000000..64a062c
--- /dev/null
+++ b/include/drivers/cadence/cdns_uart.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CDNS_UART_H
+#define CDNS_UART_H
+
+#include <drivers/console.h>
+
+/* This is very minimalistic and will only work in QEMU.  */
+
+/* CADENCE Registers */
+#define R_UART_CR	0
+#define R_UART_CR_RXRST	(1 << 0) /* RX logic reset */
+#define R_UART_CR_TXRST	(1 << 1) /* TX logic reset */
+#define R_UART_CR_RX_EN	(1 << 2) /* RX enabled */
+#define R_UART_CR_TX_EN	(1 << 4) /* TX enabled */
+
+#define R_UART_SR		0x2C
+#define UART_SR_INTR_REMPTY_BIT	1
+#define UART_SR_INTR_TFUL_BIT	4
+
+#define R_UART_TX	0x30
+#define R_UART_RX	0x30
+
+#define CONSOLE_T_CDNS_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_cdns_t;
+
+/*
+ * Initialize a new Cadence console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_cdns_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			  console_cdns_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* CDNS_UART_H */
diff --git a/include/drivers/cfi/v2m_flash.h b/include/drivers/cfi/v2m_flash.h
new file mode 100644
index 0000000..6beec50
--- /dev/null
+++ b/include/drivers/cfi/v2m_flash.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef V2M_FLASH_H
+#define V2M_FLASH_H
+
+#include <stdint.h>
+
+/* First bus cycle */
+#define NOR_CMD_READ_ARRAY		0xFF
+#define NOR_CMD_READ_ID_CODE		0x90
+#define NOR_CMD_READ_QUERY		0x98
+#define NOR_CMD_READ_STATUS_REG		0x70
+#define NOR_CMD_CLEAR_STATUS_REG	0x50
+#define NOR_CMD_WRITE_TO_BUFFER		0xE8
+#define NOR_CMD_WORD_PROGRAM		0x40
+#define NOR_CMD_BLOCK_ERASE		0x20
+#define NOR_CMD_LOCK_UNLOCK		0x60
+#define NOR_CMD_BLOCK_ERASE_ACK		0xD0
+
+/* Second bus cycle */
+#define NOR_LOCK_BLOCK			0x01
+#define NOR_UNLOCK_BLOCK		0xD0
+
+/* Status register bits */
+#define NOR_DWS				(1 << 7)
+#define NOR_ESS				(1 << 6)
+#define NOR_ES				(1 << 5)
+#define NOR_PS				(1 << 4)
+#define NOR_VPPS			(1 << 3)
+#define NOR_PSS				(1 << 2)
+#define NOR_BLS				(1 << 1)
+#define NOR_BWS				(1 << 0)
+
+/* Public API */
+void nor_send_cmd(uintptr_t base_addr, unsigned long cmd);
+int nor_word_program(uintptr_t base_addr, unsigned long data);
+int nor_lock(uintptr_t base_addr);
+int nor_unlock(uintptr_t base_addr);
+int nor_erase(uintptr_t base_addr);
+
+#endif /* V2M_FLASH_H*/
diff --git a/include/drivers/console.h b/include/drivers/console.h
new file mode 100644
index 0000000..cada771
--- /dev/null
+++ b/include/drivers/console.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+#include <lib/utils_def.h>
+
+#define CONSOLE_T_NEXT			(U(0) * REGSZ)
+#define CONSOLE_T_FLAGS			(U(1) * REGSZ)
+#define CONSOLE_T_PUTC			(U(2) * REGSZ)
+#define CONSOLE_T_GETC			(U(3) * REGSZ)
+#define CONSOLE_T_FLUSH			(U(4) * REGSZ)
+#define CONSOLE_T_DRVDATA		(U(5) * REGSZ)
+
+#define CONSOLE_FLAG_BOOT		(U(1) << 0)
+#define CONSOLE_FLAG_RUNTIME		(U(1) << 1)
+#define CONSOLE_FLAG_CRASH		(U(1) << 2)
+/* Bits 3 to 7 reserved for additional scopes in future expansion. */
+#define CONSOLE_FLAG_SCOPE_MASK		((U(1) << 8) - 1)
+/* Bits 8 to 31 reserved for non-scope use in future expansion. */
+
+/* Returned by getc callbacks when receive FIFO is empty. */
+#define ERROR_NO_PENDING_CHAR		(-1)
+/* Returned by console_xxx() if no registered console implements xxx. */
+#define ERROR_NO_VALID_CONSOLE		(-128)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct console {
+	struct console *next;
+	/*
+	 * Only the low 32 bits are used. The type is u_register_t to align the
+	 * fields of the struct to 64 bits in AArch64 and 32 bits in AArch32
+	 */
+	u_register_t flags;
+	int (*const putc)(int character, struct console *console);
+	int (*const getc)(struct console *console);
+	int (*const flush)(struct console *console);
+	/* Additional private driver data may follow here. */
+} console_t;
+
+/* offset macro assertions for console_t */
+#include <drivers/console_assertions.h>
+
+/*
+ * Add a console_t instance to the console list. This should only be called by
+ * console drivers after they have initialized all fields in the console
+ * structure. Platforms seeking to register a new console need to call the
+ * respective console__register() function instead.
+ */
+int console_register(console_t *console);
+/* Remove a single console_t instance from the console list. Return a pointer to
+ * the console that was removed if it was found, or NULL if not. */
+console_t *console_unregister(console_t *console);
+/* Returns 1 if this console is already registered, 0 if not */
+int console_is_registered(console_t *console);
+/*
+ * Set scope mask of a console that determines in what states it is active.
+ * By default they are registered with (CONSOLE_FLAG_BOOT|CONSOLE_FLAG_CRASH).
+ */
+void console_set_scope(console_t *console, unsigned int scope);
+
+/* Switch to a new global console state (CONSOLE_FLAG_BOOT/RUNTIME/CRASH). */
+void console_switch_state(unsigned int new_state);
+/* Output a character on all consoles registered for the current state. */
+int console_putc(int c);
+/* Read a character (blocking) from any console registered for current state. */
+int console_getc(void);
+/* Flush all consoles registered for the current state. */
+int console_flush(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CONSOLE_H */
diff --git a/include/drivers/console_assertions.h b/include/drivers/console_assertions.h
new file mode 100644
index 0000000..00caa31
--- /dev/null
+++ b/include/drivers/console_assertions.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONSOLE_ASSERTIONS_H
+#define CONSOLE_ASSERTIONS_H
+
+#include <lib/cassert.h>
+
+/*
+ * This file contains some separate assertions about console_t, moved here to
+ * keep them out of the way. Should only be included from <console.h>.
+ */
+CASSERT(CONSOLE_T_NEXT == __builtin_offsetof(console_t, next),
+	assert_console_t_next_offset_mismatch);
+CASSERT(CONSOLE_T_FLAGS == __builtin_offsetof(console_t, flags),
+	assert_console_t_flags_offset_mismatch);
+CASSERT(CONSOLE_T_PUTC == __builtin_offsetof(console_t, putc),
+	assert_console_t_putc_offset_mismatch);
+CASSERT(CONSOLE_T_GETC == __builtin_offsetof(console_t, getc),
+	assert_console_t_getc_offset_mismatch);
+CASSERT(CONSOLE_T_FLUSH == __builtin_offsetof(console_t, flush),
+	assert_console_t_flush_offset_mismatch);
+CASSERT(CONSOLE_T_DRVDATA == sizeof(console_t),
+	assert_console_t_drvdata_offset_mismatch);
+
+#endif /* CONSOLE_ASSERTIONS_H */
diff --git a/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h
new file mode 100644
index 0000000..40c90e6
--- /dev/null
+++ b/include/drivers/coreboot/cbmem_console.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CBMEM_CONSOLE_H
+#define CBMEM_CONSOLE_H
+
+#include <drivers/console.h>
+
+#define CONSOLE_T_CBMC_BASE	CONSOLE_T_DRVDATA
+#define CONSOLE_T_CBMC_SIZE	(CONSOLE_T_DRVDATA + REGSZ)
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+	uint32_t size;
+} console_cbmc_t;
+
+int console_cbmc_register(uintptr_t base, console_cbmc_t *console);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CBMEM_CONSOLE_H */
diff --git a/include/drivers/delay_timer.h b/include/drivers/delay_timer.h
new file mode 100644
index 0000000..684f1c3
--- /dev/null
+++ b/include/drivers/delay_timer.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DELAY_TIMER_H
+#define DELAY_TIMER_H
+
+#include <stdint.h>
+
+/********************************************************************
+ * A simple timer driver providing synchronous delay functionality.
+ * The driver must be initialized with a structure that provides a
+ * function pointer to return the timer value and a clock
+ * multiplier/divider. The ratio of the multiplier and the divider is
+ * the clock period in microseconds.
+ ********************************************************************/
+
+typedef struct timer_ops {
+	uint32_t (*get_timer_value)(void);
+	uint32_t clk_mult;
+	uint32_t clk_div;
+} timer_ops_t;
+
+void mdelay(uint32_t msec);
+void udelay(uint32_t usec);
+void timer_init(const timer_ops_t *ops_ptr);
+
+#endif /* DELAY_TIMER_H */
diff --git a/include/drivers/dw_ufs.h b/include/drivers/dw_ufs.h
new file mode 100644
index 0000000..13e53f1
--- /dev/null
+++ b/include/drivers/dw_ufs.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DW_UFS_H
+#define DW_UFS_H
+
+#include <stdint.h>
+
+/* Bus Throtting */
+#define BUSTHRTL				0xC0
+/* Outstanding OCP Requests */
+#define OOCPR					0xC4
+/* Fatal Error Interrupt Enable */
+#define FEIE					0xC8
+/* C-Port Direct Access Configuration register */
+#define CDACFG					0xD0
+/* C-Port Direct Access Transmit 1 register */
+#define CDATX1					0xD4
+/* C-Port Direct Access Transmit 2 register */
+#define CDATX2					0xD8
+/* C-Port Direct Access Receive 1 register */
+#define CDARX1					0xDC
+/* C-Port Direct Access Receive 2 register */
+#define CDARX2					0xE0
+/* C-Port Direct Access Status register */
+#define CDASTA					0xE4
+/* UPIU Loopback Configuration register */
+#define LBMCFG					0xF0
+/* UPIU Loopback Status */
+#define LBMSTA					0xF4
+/* Debug register */
+#define DBG					0xF8
+/* HClk Divider register */
+#define HCLKDIV					0xFC
+
+#define TX_HIBERN8TIME_CAP_OFFSET		0x000F
+#define TX_FSM_STATE_OFFSET			0x0041
+#define TX_FSM_STATE_LINE_RESET			7
+#define TX_FSM_STATE_LINE_CFG			6
+#define TX_FSM_STATE_HS_BURST			5
+#define TX_FSM_STATE_LS_BURST			4
+#define TX_FSM_STATE_STALL			3
+#define TX_FSM_STATE_SLEEP			2
+#define TX_FSM_STATE_HIBERN8			1
+#define TX_FSM_STATE_DISABLE			0
+
+#define RX_MIN_ACTIVATETIME_CAP_OFFSET		0x008F
+#define RX_HS_G2_SYNC_LENGTH_CAP_OFFSET		0x0094
+#define RX_HS_G3_SYNC_LENGTH_CAP_OFFSET		0x0095
+
+#define PA_AVAIL_TX_DATA_LANES_OFFSET		0x1520
+#define PA_TX_SKIP_OFFSET			0x155C
+#define PA_TX_SKIP_PERIOD_OFFSET		0x155D
+#define PA_LOCAL_TX_LCC_ENABLE_OFFSET		0x155E
+#define PA_ACTIVE_TX_DATA_LANES_OFFSET		0x1560
+#define PA_CONNECTED_TX_DATA_LANES_OFFSET	0x1561
+#define PA_TX_TRAILING_CLOCKS_OFFSET		0x1564
+#define PA_TX_GEAR_OFFSET			0x1568
+#define PA_TX_TERMINATION_OFFSET		0x1569
+#define PA_HS_SERIES_OFFSET			0x156A
+#define PA_PWR_MODE_OFFSET			0x1571
+#define PA_ACTIVE_RX_DATA_LANES_OFFSET		0x1580
+#define PA_CONNECTED_RX_DATA_LANES_OFFSET	0x1581
+#define PA_RX_PWR_STATUS_OFFSET			0x1582
+#define PA_RX_GEAR_OFFSET			0x1583
+#define PA_RX_TERMINATION_OFFSET		0x1584
+#define PA_SCRAMBLING_OFFSET			0x1585
+#define PA_MAX_RX_PWM_GEAR_OFFSET		0x1586
+#define PA_MAX_RX_HS_GEAR_OFFSET		0x1587
+#define PA_PACP_REQ_TIMEOUT_OFFSET		0x1590
+#define PA_PACP_REQ_EOB_TIMEOUT_OFFSET		0x1591
+#define PA_REMOTE_VER_INFO_OFFSET		0x15A0
+#define PA_LOGICAL_LANE_MAP_OFFSET		0x15A1
+#define PA_TACTIVATE_OFFSET			0x15A8
+#define PA_PWR_MODE_USER_DATA0_OFFSET		0x15B0
+#define PA_PWR_MODE_USER_DATA1_OFFSET		0x15B1
+#define PA_PWR_MODE_USER_DATA2_OFFSET		0x15B2
+#define PA_PWR_MODE_USER_DATA3_OFFSET		0x15B3
+#define PA_PWR_MODE_USER_DATA4_OFFSET		0x15B4
+#define PA_PWR_MODE_USER_DATA5_OFFSET		0x15B5
+
+#define DL_TC0_TX_FC_THRESHOLD_OFFSET		0x2040
+#define DL_AFC0_CREDIT_THRESHOLD_OFFSET		0x2044
+#define DL_TC0_OUT_ACK_THRESHOLD_OFFSET		0x2045
+
+#define DME_FC0_PROTECTION_TIMEOUT_OFFSET	0xD041
+#define DME_TC0_REPLAY_TIMEOUT_OFFSET		0xD042
+#define DME_AFC0_REQ_TIMEOUT_OFFSET		0xD043
+#define DME_FC1_PROTECTION_TIMEOUT_OFFSET	0xD044
+#define DME_TC1_REPLAY_TIMEOUT_OFFSET		0xD045
+#define DME_AFC1_REQ_TIMEOUT_OFFSET		0xD046
+
+#define VS_MPHY_CFG_UPDT_OFFSET			0xD085
+#define VS_MK2_EXTN_SUPPORT_OFFSET		0xD0AB
+#define VS_MPHY_DISABLE_OFFSET			0xD0C1
+#define VS_MPHY_DISABLE_MPHYDIS			(1 << 0)
+
+typedef struct dw_ufs_params {
+	uintptr_t		reg_base;
+	uintptr_t		desc_base;
+	size_t			desc_size;
+	unsigned long		flags;
+} dw_ufs_params_t;
+
+int dw_ufs_init(dw_ufs_params_t *params);
+
+#endif /* DW_UFS_H */
diff --git a/include/drivers/generic_delay_timer.h b/include/drivers/generic_delay_timer.h
new file mode 100644
index 0000000..adba10f
--- /dev/null
+++ b/include/drivers/generic_delay_timer.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GENERIC_DELAY_TIMER_H
+#define GENERIC_DELAY_TIMER_H
+
+#include <stdint.h>
+
+void generic_delay_timer_init_args(uint32_t mult, uint32_t div);
+
+void generic_delay_timer_init(void);
+
+#endif /* GENERIC_DELAY_TIMER_H */
diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h
new file mode 100644
index 0000000..99c18a4
--- /dev/null
+++ b/include/drivers/gpio.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPIO_H
+#define GPIO_H
+
+#include <export/drivers/gpio_exp.h>
+
+#define GPIO_DIR_OUT		ARM_TF_GPIO_DIR_OUT
+#define GPIO_DIR_IN		ARM_TF_GPIO_DIR_IN
+
+#define GPIO_LEVEL_LOW		ARM_TF_GPIO_LEVEL_LOW
+#define GPIO_LEVEL_HIGH		ARM_TF_GPIO_LEVEL_HIGH
+
+#define GPIO_PULL_NONE		ARM_TF_GPIO_PULL_NONE
+#define GPIO_PULL_UP		ARM_TF_GPIO_PULL_UP
+#define GPIO_PULL_DOWN		ARM_TF_GPIO_PULL_DOWN
+
+typedef struct gpio_ops {
+	int (*get_direction)(int gpio);
+	void (*set_direction)(int gpio, int direction);
+	int (*get_value)(int gpio);
+	void (*set_value)(int gpio, int value);
+	void (*set_pull)(int gpio, int pull);
+	int (*get_pull)(int gpio);
+} gpio_ops_t;
+
+int gpio_get_direction(int gpio);
+void gpio_set_direction(int gpio, int direction);
+int gpio_get_value(int gpio);
+void gpio_set_value(int gpio, int value);
+void gpio_set_pull(int gpio, int pull);
+int gpio_get_pull(int gpio);
+void gpio_init(const gpio_ops_t *ops);
+
+#endif /* GPIO_H */
diff --git a/include/drivers/io/io_block.h b/include/drivers/io/io_block.h
new file mode 100644
index 0000000..c99e8c7
--- /dev/null
+++ b/include/drivers/io/io_block.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_BLOCK_H
+#define IO_BLOCK_H
+
+#include <drivers/io/io_storage.h>
+
+/* block devices ops */
+typedef struct io_block_ops {
+	size_t	(*read)(int lba, uintptr_t buf, size_t size);
+	size_t	(*write)(int lba, const uintptr_t buf, size_t size);
+} io_block_ops_t;
+
+typedef struct io_block_dev_spec {
+	io_block_spec_t	buffer;
+	io_block_ops_t	ops;
+	size_t		block_size;
+} io_block_dev_spec_t;
+
+struct io_dev_connector;
+
+int register_io_dev_block(const struct io_dev_connector **dev_con);
+
+#endif /* IO_BLOCK_H */
diff --git a/include/drivers/io/io_driver.h b/include/drivers/io/io_driver.h
new file mode 100644
index 0000000..2b704f4
--- /dev/null
+++ b/include/drivers/io/io_driver.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_DRIVER_H
+#define IO_DRIVER_H
+
+#include <stdint.h>
+
+#include <drivers/io/io_storage.h>
+
+/* Generic IO entity structure,representing an accessible IO construct on the
+ * device, such as a file */
+typedef struct io_entity {
+	struct io_dev_info *dev_handle;
+	uintptr_t info;
+} io_entity_t;
+
+
+/* Device info structure, providing device-specific functions and a means of
+ * adding driver-specific state */
+typedef struct io_dev_info {
+	const struct io_dev_funcs *funcs;
+	uintptr_t info;
+} io_dev_info_t;
+
+
+/* Structure used to create a connection to a type of device */
+typedef struct io_dev_connector {
+	/* dev_open opens a connection to a particular device driver */
+	int (*dev_open)(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+} io_dev_connector_t;
+
+
+/* Structure to hold device driver function pointers */
+typedef struct io_dev_funcs {
+	io_type_t (*type)(void);
+	int (*open)(io_dev_info_t *dev_info, const uintptr_t spec,
+			io_entity_t *entity);
+	int (*seek)(io_entity_t *entity, int mode, ssize_t offset);
+	int (*size)(io_entity_t *entity, size_t *length);
+	int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length,
+			size_t *length_read);
+	int (*write)(io_entity_t *entity, const uintptr_t buffer,
+			size_t length, size_t *length_written);
+	int (*close)(io_entity_t *entity);
+	int (*dev_init)(io_dev_info_t *dev_info, const uintptr_t init_params);
+	int (*dev_close)(io_dev_info_t *dev_info);
+} io_dev_funcs_t;
+
+
+/* Operations intended to be performed during platform initialisation */
+
+/* Register an IO device */
+int io_register_device(const io_dev_info_t *dev_info);
+
+#endif /* IO_DRIVER_H */
diff --git a/include/drivers/io/io_dummy.h b/include/drivers/io/io_dummy.h
new file mode 100644
index 0000000..edfc699
--- /dev/null
+++ b/include/drivers/io/io_dummy.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_DUMMY_H
+#define IO_DUMMY_H
+
+int register_io_dev_dummy(const struct io_dev_connector **dev_con);
+
+#endif /* IO_DUMMY_H */
diff --git a/include/drivers/io/io_fip.h b/include/drivers/io/io_fip.h
new file mode 100644
index 0000000..e0b5746
--- /dev/null
+++ b/include/drivers/io/io_fip.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_FIP_H
+#define IO_FIP_H
+
+struct io_dev_connector;
+
+int register_io_dev_fip(const struct io_dev_connector **dev_con);
+
+#endif /* IO_FIP_H */
diff --git a/include/drivers/io/io_memmap.h b/include/drivers/io/io_memmap.h
new file mode 100644
index 0000000..87e3466
--- /dev/null
+++ b/include/drivers/io/io_memmap.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MEMMAP_H
+#define IO_MEMMAP_H
+
+struct io_dev_connector;
+
+int register_io_dev_memmap(const struct io_dev_connector **dev_con);
+
+#endif /* IO_MEMMAP_H */
diff --git a/include/drivers/io/io_semihosting.h b/include/drivers/io/io_semihosting.h
new file mode 100644
index 0000000..e90ea5c
--- /dev/null
+++ b/include/drivers/io/io_semihosting.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_SEMIHOSTING_H
+#define IO_SEMIHOSTING_H
+
+struct io_dev_connector;
+
+int register_io_dev_sh(const struct io_dev_connector **dev_con);
+
+#endif /* IO_SEMIHOSTING_H */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
new file mode 100644
index 0000000..084c67c
--- /dev/null
+++ b/include/drivers/io/io_storage.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_STORAGE_H
+#define IO_STORAGE_H
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h> /* For ssize_t */
+
+#include <tools_share/uuid.h>
+
+/* Device type which can be used to enable policy decisions about which device
+ * to access */
+typedef enum {
+	IO_TYPE_INVALID,
+	IO_TYPE_SEMIHOSTING,
+	IO_TYPE_MEMMAP,
+	IO_TYPE_DUMMY,
+	IO_TYPE_FIRMWARE_IMAGE_PACKAGE,
+	IO_TYPE_BLOCK,
+	IO_TYPE_MMC,
+	IO_TYPE_STM32IMAGE,
+	IO_TYPE_MAX
+} io_type_t;
+
+
+/* Modes used when seeking data on a supported device */
+typedef enum {
+	IO_SEEK_INVALID,
+	IO_SEEK_SET,
+	IO_SEEK_END,
+	IO_SEEK_CUR,
+	IO_SEEK_MAX
+} io_seek_mode_t;
+
+
+/* Connector type, providing a means of identifying a device to open */
+struct io_dev_connector;
+
+
+/* File specification - used to refer to data on a device supporting file-like
+ * entities */
+typedef struct io_file_spec {
+	const char *path;
+	unsigned int mode;
+} io_file_spec_t;
+
+/* UUID specification - used to refer to data accessed using UUIDs (i.e. FIP
+ * images) */
+typedef struct io_uuid_spec {
+	const uuid_t uuid;
+} io_uuid_spec_t;
+
+/* Block specification - used to refer to data on a device supporting
+ * block-like entities */
+typedef struct io_block_spec {
+	size_t offset;
+	size_t length;
+} io_block_spec_t;
+
+
+/* Access modes used when accessing data on a device */
+#define IO_MODE_INVALID (0)
+#define IO_MODE_RO	(1 << 0)
+#define IO_MODE_RW	(1 << 1)
+
+
+/* Open a connection to a device */
+int io_dev_open(const struct io_dev_connector *dev_con,
+		const uintptr_t dev_spec,
+		uintptr_t *handle);
+
+
+/* Initialise a device explicitly - to permit lazy initialisation or
+ * re-initialisation */
+int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params);
+
+/* Close a connection to a device */
+int io_dev_close(uintptr_t dev_handle);
+
+
+/* Synchronous operations */
+int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle);
+
+int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset);
+
+int io_size(uintptr_t handle, size_t *length);
+
+int io_read(uintptr_t handle, uintptr_t buffer, size_t length,
+		size_t *length_read);
+
+int io_write(uintptr_t handle, const uintptr_t buffer, size_t length,
+		size_t *length_written);
+
+int io_close(uintptr_t handle);
+
+
+#endif /* IO_STORAGE_H */
diff --git a/include/drivers/marvell/addr_map.h b/include/drivers/marvell/addr_map.h
new file mode 100644
index 0000000..0d219f2
--- /dev/null
+++ b/include/drivers/marvell/addr_map.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Address map types for Marvell address translation unit drivers */
+
+#ifndef ADDR_MAP_H
+#define ADDR_MAP_H
+
+#include <stdint.h>
+
+struct addr_map_win {
+	uint64_t base_addr;
+	uint64_t win_size;
+	uint32_t target_id;
+};
+
+#endif /* ADDR_MAP_H */
diff --git a/include/drivers/marvell/amb_adec.h b/include/drivers/marvell/amb_adec.h
new file mode 100644
index 0000000..a92db5b
--- /dev/null
+++ b/include/drivers/marvell/amb_adec.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */
+
+#ifndef AMB_ADEC_H
+#define AMB_ADEC_H
+
+#include <stdint.h>
+
+enum amb_attribute_ids {
+	AMB_SPI0_CS0_ID = 0x1E,
+	AMB_SPI0_CS1_ID = 0x5E,
+	AMB_SPI0_CS2_ID = 0x9E,
+	AMB_SPI0_CS3_ID = 0xDE,
+	AMB_SPI1_CS0_ID = 0x1A,
+	AMB_SPI1_CS1_ID = 0x5A,
+	AMB_SPI1_CS2_ID = 0x9A,
+	AMB_SPI1_CS3_ID = 0xDA,
+	AMB_DEV_CS0_ID = 0x3E,
+	AMB_DEV_CS1_ID = 0x3D,
+	AMB_DEV_CS2_ID = 0x3B,
+	AMB_DEV_CS3_ID = 0x37,
+	AMB_BOOT_CS_ID = 0x2f,
+	AMB_BOOT_ROM_ID = 0x1D,
+};
+
+#define AMB_MAX_WIN_ID		7
+
+int init_amb_adec(uintptr_t base);
+
+#endif /* AMB_ADEC_H */
diff --git a/include/drivers/marvell/ap807_clocks_init.h b/include/drivers/marvell/ap807_clocks_init.h
new file mode 100644
index 0000000..4353b83
--- /dev/null
+++ b/include/drivers/marvell/ap807_clocks_init.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef AP807_INIT_CLOCKS_H
+#define AP807_INIT_CLOCKS_H
+
+void ap807_clocks_init(unsigned int freq_option);
+
+#endif /* AP807_INIT_CLOCKS_H */
+
diff --git a/include/drivers/marvell/aro.h b/include/drivers/marvell/aro.h
new file mode 100644
index 0000000..c16f625
--- /dev/null
+++ b/include/drivers/marvell/aro.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+#ifndef ARO_H
+#define ARO_H
+
+enum hws_freq {
+	CPU_FREQ_2000,
+	CPU_FREQ_1800,
+	CPU_FREQ_1600,
+	CPU_FREQ_1400,
+	CPU_FREQ_1300,
+	CPU_FREQ_1200,
+	CPU_FREQ_1000,
+	CPU_FREQ_600,
+	CPU_FREQ_800,
+	DDR_FREQ_LAST,
+	DDR_FREQ_SAR
+};
+
+enum cpu_clock_freq_mode {
+	CPU_2000_DDR_1200_RCLK_1200 = 0x0,
+	CPU_2000_DDR_1050_RCLK_1050 = 0x1,
+	CPU_1600_DDR_800_RCLK_800   = 0x4,
+	CPU_1800_DDR_1200_RCLK_1200 = 0x6,
+	CPU_1800_DDR_1050_RCLK_1050 = 0x7,
+	CPU_1600_DDR_900_RCLK_900   = 0x0B,
+	CPU_1600_DDR_1050_RCLK_1050 = 0x0D,
+	CPU_1600_DDR_1200_RCLK_1200 = 0x0D,
+	CPU_1600_DDR_900_RCLK_900_2 = 0x0E,
+	CPU_1000_DDR_650_RCLK_650   = 0x13,
+	CPU_1300_DDR_800_RCLK_800   = 0x14,
+	CPU_1300_DDR_650_RCLK_650   = 0x17,
+	CPU_1200_DDR_800_RCLK_800   = 0x19,
+	CPU_1400_DDR_800_RCLK_800   = 0x1a,
+	CPU_600_DDR_800_RCLK_800    = 0x1B,
+	CPU_800_DDR_800_RCLK_800    = 0x1C,
+	CPU_1000_DDR_800_RCLK_800   = 0x1D,
+	CPU_DDR_RCLK_INVALID
+};
+
+int init_aro(void);
+
+#endif /* ARO_H */
diff --git a/include/drivers/marvell/cache_llc.h b/include/drivers/marvell/cache_llc.h
new file mode 100644
index 0000000..85babb8
--- /dev/null
+++ b/include/drivers/marvell/cache_llc.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* LLC driver is the Last Level Cache (L3C) driver
+ * for Marvell SoCs in AP806, AP807, and AP810
+ */
+
+#ifndef CACHE_LLC_H
+#define CACHE_LLC_H
+
+#define LLC_CTRL(ap)			(MVEBU_LLC_BASE(ap) + 0x100)
+#define LLC_SYNC(ap)			(MVEBU_LLC_BASE(ap) + 0x700)
+#define L2X0_INV_WAY(ap)		(MVEBU_LLC_BASE(ap) + 0x77C)
+#define L2X0_CLEAN_WAY(ap)		(MVEBU_LLC_BASE(ap) + 0x7BC)
+#define L2X0_CLEAN_INV_WAY(ap)		(MVEBU_LLC_BASE(ap) + 0x7FC)
+#define LLC_TC0_LOCK(ap)		(MVEBU_LLC_BASE(ap) + 0x920)
+
+#define MASTER_LLC_CTRL			LLC_CTRL(MVEBU_AP0)
+#define MASTER_L2X0_INV_WAY		L2X0_INV_WAY(MVEBU_AP0)
+#define MASTER_LLC_TC0_LOCK		LLC_TC0_LOCK(MVEBU_AP0)
+
+#define LLC_CTRL_EN			1
+#define LLC_EXCLUSIVE_EN		0x100
+#define LLC_WAY_MASK			0xFFFFFFFF
+
+#ifndef __ASSEMBLER__
+void llc_cache_sync(int ap_index);
+void llc_flush_all(int ap_index);
+void llc_clean_all(int ap_index);
+void llc_inv_all(int ap_index);
+void llc_disable(int ap_index);
+void llc_enable(int ap_index, int excl_mode);
+int llc_is_exclusive(int ap_index);
+void llc_runtime_enable(int ap_index);
+#endif
+
+#endif /* CACHE_LLC_H */
diff --git a/include/drivers/marvell/ccu.h b/include/drivers/marvell/ccu.h
new file mode 100644
index 0000000..b0d1ec9
--- /dev/null
+++ b/include/drivers/marvell/ccu.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#ifndef CCU_H
+#define CCU_H
+
+#ifndef __ASSEMBLER__
+#include <drivers/marvell/addr_map.h>
+#endif
+
+/* CCU registers definitions */
+#define CCU_WIN_CR_OFFSET(ap, win)		(MVEBU_CCU_BASE(ap) + 0x0 + \
+						(0x10 * win))
+#define CCU_TARGET_ID_OFFSET			(8)
+#define CCU_TARGET_ID_MASK			(0x7F)
+
+#define CCU_WIN_SCR_OFFSET(ap, win)		(MVEBU_CCU_BASE(ap) + 0x4 + \
+						(0x10 * win))
+#define CCU_WIN_ENA_WRITE_SECURE		(0x1)
+#define CCU_WIN_ENA_READ_SECURE			(0x2)
+
+#define CCU_WIN_ALR_OFFSET(ap, win)		(MVEBU_CCU_BASE(ap) + 0x8 + \
+						(0x10 * win))
+#define CCU_WIN_AHR_OFFSET(ap, win)		(MVEBU_CCU_BASE(ap) + 0xC + \
+						(0x10 * win))
+
+#define CCU_WIN_GCR_OFFSET(ap)			(MVEBU_CCU_BASE(ap) + 0xD0)
+#define CCU_GCR_TARGET_OFFSET			(8)
+#define CCU_GCR_TARGET_MASK			(0xFF)
+
+#define CCU_SRAM_WIN_CR				CCU_WIN_CR_OFFSET(MVEBU_AP0, 1)
+
+#ifndef __ASSEMBLER__
+int init_ccu(int);
+void ccu_win_check(struct addr_map_win *win);
+void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id);
+void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
+void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
+void ccu_dram_win_config(int ap_index, struct addr_map_win *win);
+void ccu_dram_target_set(int ap_index, uint32_t target);
+void ccu_save_win_all(int ap_id);
+void ccu_restore_win_all(int ap_id);
+#endif
+
+#endif /* CCU_H */
diff --git a/include/drivers/marvell/gwin.h b/include/drivers/marvell/gwin.h
new file mode 100644
index 0000000..1b874a7
--- /dev/null
+++ b/include/drivers/marvell/gwin.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* GWIN unit device driver for Marvell AP810 SoC */
+
+#ifndef GWIN_H
+#define GWIN_H
+
+#include <drivers/marvell/addr_map.h>
+
+int init_gwin(int ap_index);
+void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
+void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
+
+#endif /* GWIN_H */
diff --git a/include/drivers/marvell/i2c.h b/include/drivers/marvell/i2c.h
new file mode 100644
index 0000000..06c5114
--- /dev/null
+++ b/include/drivers/marvell/i2c.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef I2C_H
+#define I2C_H
+
+
+void i2c_init(void);
+
+int i2c_read(uint8_t chip,
+	     unsigned int addr, int alen, uint8_t *buffer, int len);
+
+int i2c_write(uint8_t chip,
+	      unsigned int addr, int alen, uint8_t *buffer, int len);
+
+#endif /* I2C_H */
diff --git a/include/drivers/marvell/io_win.h b/include/drivers/marvell/io_win.h
new file mode 100644
index 0000000..7438d6b
--- /dev/null
+++ b/include/drivers/marvell/io_win.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */
+
+#ifndef IO_WIN_H
+#define IO_WIN_H
+
+#include <drivers/marvell/addr_map.h>
+
+int init_io_win(int ap_index);
+void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size);
+void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size);
+void iow_save_win_all(int ap_id);
+void iow_restore_win_all(int ap_id);
+
+#endif /* IO_WIN_H */
diff --git a/include/drivers/marvell/iob.h b/include/drivers/marvell/iob.h
new file mode 100644
index 0000000..9b5e515
--- /dev/null
+++ b/include/drivers/marvell/iob.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* IOW unit device driver for Marvell CP110 and CP115 SoCs */
+
+#ifndef IOB_H
+#define IOB_H
+
+#include <drivers/marvell/addr_map.h>
+
+enum target_ids_iob {
+	INTERNAL_TID	= 0x0,
+	MCI0_TID	= 0x1,
+	PEX1_TID	= 0x2,
+	PEX2_TID	= 0x3,
+	PEX0_TID	= 0x4,
+	NAND_TID	= 0x5,
+	RUNIT_TID	= 0x6,
+	MCI1_TID	= 0x7,
+	IOB_MAX_TID
+};
+
+int init_iob(uintptr_t base);
+void iob_cfg_space_update(int ap_idx, int cp_idx,
+			  uintptr_t base, uintptr_t new_base);
+
+#endif /* IOB_H */
diff --git a/include/drivers/marvell/mci.h b/include/drivers/marvell/mci.h
new file mode 100644
index 0000000..8ef0234
--- /dev/null
+++ b/include/drivers/marvell/mci.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* MCI bus driver for Marvell ARMADA 8K and 8K+ SoCs */
+
+#ifndef MCI_H
+#define MCI_H
+
+int mci_initialize(int mci_index);
+void mci_turn_link_down(void);
+void mci_turn_link_on(void);
+int mci_get_link_status(void);
+
+#endif /* MCI_H */
diff --git a/include/drivers/marvell/mochi/ap_setup.h b/include/drivers/marvell/mochi/ap_setup.h
new file mode 100644
index 0000000..eff4473
--- /dev/null
+++ b/include/drivers/marvell/mochi/ap_setup.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* AP8xx Marvell SoC driver */
+
+#ifndef AP_SETUP_H
+#define AP_SETUP_H
+
+void ap_init(void);
+void ap_ble_init(void);
+int ap_get_count(void);
+
+#endif /* AP_SETUP_H */
diff --git a/include/drivers/marvell/mochi/cp110_setup.h b/include/drivers/marvell/mochi/cp110_setup.h
new file mode 100644
index 0000000..3686257
--- /dev/null
+++ b/include/drivers/marvell/mochi/cp110_setup.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* CP110 Marvell SoC driver */
+
+#ifndef CP110_SETUP_H
+#define CP110_SETUP_H
+
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#define MVEBU_DEVICE_ID_REG		(MVEBU_CP_DFX_OFFSET + 0x40)
+#define MVEBU_DEVICE_ID_OFFSET		(0)
+#define MVEBU_DEVICE_ID_MASK		(0xffff << MVEBU_DEVICE_ID_OFFSET)
+#define MVEBU_DEVICE_REV_OFFSET		(16)
+#define MVEBU_DEVICE_REV_MASK		(0xf << MVEBU_DEVICE_REV_OFFSET)
+#define MVEBU_70X0_DEV_ID		(0x7040)
+#define MVEBU_70X0_CP115_DEV_ID		(0x7045)
+#define MVEBU_3900_DEV_ID		(0x6025)
+#define MVEBU_80X0_DEV_ID		(0x8040)
+#define MVEBU_80X0_CP115_DEV_ID		(0x8045)
+#define MVEBU_CP110_SA_DEV_ID		(0x110)
+#define MVEBU_CP110_REF_ID_A1		1
+#define MVEBU_CP110_REF_ID_A2		2
+#define MAX_STREAM_ID_PER_CP		(0x10)
+#define STREAM_ID_BASE			(0x40)
+
+static inline uint32_t cp110_device_id_get(uintptr_t base)
+{
+	/* Returns:
+	 * - MVEBU_70X0_DEV_ID for A70X0 family
+	 * - MVEBU_80X0_DEV_ID for A80X0 family
+	 * - MVEBU_CP110_SA_DEV_ID for CP that connected stand alone
+	 */
+	return (mmio_read_32(base + MVEBU_DEVICE_ID_REG) >>
+		MVEBU_DEVICE_ID_OFFSET) &
+		MVEBU_DEVICE_ID_MASK;
+}
+
+static inline uint32_t cp110_rev_id_get(uintptr_t base)
+{
+	return (mmio_read_32(base + MVEBU_DEVICE_ID_REG) &
+		MVEBU_DEVICE_REV_MASK) >>
+		MVEBU_DEVICE_REV_OFFSET;
+}
+
+void cp110_init(uintptr_t cp110_base, uint32_t stream_id);
+void cp110_ble_init(uintptr_t cp110_base);
+
+#endif /* CP110_SETUP_H */
diff --git a/include/drivers/marvell/thermal.h b/include/drivers/marvell/thermal.h
new file mode 100644
index 0000000..48376a7
--- /dev/null
+++ b/include/drivers/marvell/thermal.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* Driver for thermal unit located in Marvell ARMADA 8K and compatible SoCs */
+
+#ifndef THERMAL_H
+#define THERMAL_H
+
+struct tsen_config {
+	/* thermal temperature parameters */
+	int tsen_offset;
+	int tsen_gain;
+	int tsen_divisor;
+	/* thermal data */
+	int tsen_ready;
+	void *regs_base;
+	/* thermal functionality */
+	int (*ptr_tsen_probe)(struct tsen_config *cfg);
+	int (*ptr_tsen_read)(struct tsen_config *cfg, int *temp);
+};
+
+/* Thermal driver APIs */
+int marvell_thermal_init(struct tsen_config *tsen_cfg);
+int marvell_thermal_read(struct tsen_config *tsen_cfg, int *temp);
+struct tsen_config *marvell_thermal_config_get(void);
+
+#endif /* THERMAL_H */
diff --git a/include/drivers/marvell/uart/a3700_console.h b/include/drivers/marvell/uart/a3700_console.h
new file mode 100644
index 0000000..517f01a
--- /dev/null
+++ b/include/drivers/marvell/uart/a3700_console.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef A3700_CONSOLE_H
+#define A3700_CONSOLE_H
+
+#include <drivers/console.h>
+
+/* MVEBU UART Registers */
+#define UART_RX_REG		0x00
+#define UART_TX_REG		0x04
+#define UART_CTRL_REG		0x08
+#define UART_STATUS_REG		0x0c
+#define UART_BAUD_REG		0x10
+#define UART_POSSR_REG		0x14
+
+/* FIFO Control Register bits */
+#define UARTFCR_FIFOMD_16450	(0 << 6)
+#define UARTFCR_FIFOMD_16550	(1 << 6)
+#define UARTFCR_RXTRIG_1	(0 << 6)
+#define UARTFCR_RXTRIG_4	(1 << 6)
+#define UARTFCR_RXTRIG_8	(2 << 6)
+#define UARTFCR_RXTRIG_16	(3 << 6)
+#define UARTFCR_TXTRIG_1	(0 << 4)
+#define UARTFCR_TXTRIG_4	(1 << 4)
+#define UARTFCR_TXTRIG_8	(2 << 4)
+#define UARTFCR_TXTRIG_16	(3 << 4)
+#define UARTFCR_DMAEN		(1 << 3)	/* Enable DMA mode */
+#define UARTFCR_TXCLR		(1 << 2)	/* Clear contents of Tx FIFO */
+#define UARTFCR_RXCLR		(1 << 1)	/* Clear contents of Rx FIFO */
+#define UARTFCR_FIFOEN		(1 << 0)	/* Enable the Tx/Rx FIFO */
+
+/* Line Control Register bits */
+#define UARTLCR_DLAB		(1 << 7)	/* Divisor Latch Access */
+#define UARTLCR_SETB		(1 << 6)	/* Set BREAK Condition */
+#define UARTLCR_SETP		(1 << 5)	/* Set Parity to LCR[4] */
+#define UARTLCR_EVEN		(1 << 4)	/* Even Parity Format */
+#define UARTLCR_PAR		(1 << 3)	/* Parity */
+#define UARTLCR_STOP		(1 << 2)	/* Stop Bit */
+#define UARTLCR_WORDSZ_5	0		/* Word Length of 5 */
+#define UARTLCR_WORDSZ_6	1		/* Word Length of 6 */
+#define UARTLCR_WORDSZ_7	2		/* Word Length of 7 */
+#define UARTLCR_WORDSZ_8	3		/* Word Length of 8 */
+
+/* Line Status Register bits */
+#define UARTLSR_TXFIFOFULL	(1 << 11)	/* Tx Fifo Full */
+
+/* UART Control Register bits */
+#define UART_CTRL_RXFIFO_RESET	(1 << 14)
+#define UART_CTRL_TXFIFO_RESET	(1 << 15)
+#define UARTLSR_TXFIFOEMPTY	(1 << 6)
+
+#define CONSOLE_T_A3700_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_a3700_t;
+
+/*
+ * Initialize a new a3700 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_a3700_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_a3700_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif	/* A3700_CONSOLE_H */
diff --git a/include/drivers/mentor/mi2cv.h b/include/drivers/mentor/mi2cv.h
new file mode 100644
index 0000000..85b733b
--- /dev/null
+++ b/include/drivers/mentor/mi2cv.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* This driver provides support for Mentor Graphics MI2CV IP core */
+
+#ifndef MI2CV_H
+#define MI2CV_H
+
+#include <stdint.h>
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(void *i2c_base);
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uint8_t chip,
+	     unsigned int addr, int alen, uint8_t *buffer, int len);
+
+int i2c_write(uint8_t chip,
+	      unsigned int addr, int alen, uint8_t *buffer, int len);
+
+#endif /* MI2CV_H */
diff --git a/include/drivers/meson/gxl/crypto/sha_dma.h b/include/drivers/meson/gxl/crypto/sha_dma.h
new file mode 100644
index 0000000..52129a6
--- /dev/null
+++ b/include/drivers/meson/gxl/crypto/sha_dma.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SHA_DMA_H
+#define SHA_DMA_H
+
+#define SHA256_HASHSZ 32
+#define SHA256_BLOCKSZ 0x40
+
+enum ASD_MODE {
+	ASM_INVAL,
+	ASM_SHA256,
+	ASM_SHA224,
+};
+
+struct asd_ctx {
+	uint8_t digest[SHA256_HASHSZ];
+	uint8_t block[SHA256_BLOCKSZ];
+	size_t blocksz;
+	enum ASD_MODE mode;
+	uint8_t started;
+};
+
+static inline void asd_sha_init(struct asd_ctx *ctx, enum ASD_MODE mode)
+{
+	ctx->started = 0;
+	ctx->mode = mode;
+	ctx->blocksz = 0;
+}
+
+void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len);
+void asd_sha_finalize(struct asd_ctx *ctx);
+
+#endif
diff --git a/include/drivers/meson/meson_console.h b/include/drivers/meson/meson_console.h
new file mode 100644
index 0000000..70e3b0b
--- /dev/null
+++ b/include/drivers/meson/meson_console.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MESON_CONSOLE_H
+#define MESON_CONSOLE_H
+
+#include <drivers/console.h>
+
+#define CONSOLE_T_MESON_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_meson_t;
+
+/*
+ * Initialize a new meson console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ *
+ * NOTE: The clock is actually fixed to 24 MHz. The argument is only there in
+ * order to make this function future-proof.
+ */
+int console_meson_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_meson_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* MESON_CONSOLE_H */
diff --git a/include/drivers/mmc.h b/include/drivers/mmc.h
new file mode 100644
index 0000000..7611f01
--- /dev/null
+++ b/include/drivers/mmc.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMC_H
+#define MMC_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+#define MMC_BLOCK_SIZE			U(512)
+#define MMC_BLOCK_MASK			(MMC_BLOCK_SIZE - U(1))
+#define MMC_BOOT_CLK_RATE		(400 * 1000)
+
+#define MMC_CMD(_x)			U(_x)
+
+#define MMC_ACMD(_x)			U(_x)
+
+#define OCR_POWERUP			BIT(31)
+#define OCR_HCS				BIT(30)
+#define OCR_BYTE_MODE			(U(0) << 29)
+#define OCR_SECTOR_MODE			(U(2) << 29)
+#define OCR_ACCESS_MODE_MASK		(U(3) << 29)
+#define OCR_3_5_3_6			BIT(23)
+#define OCR_3_4_3_5			BIT(22)
+#define OCR_3_3_3_4			BIT(21)
+#define OCR_3_2_3_3			BIT(20)
+#define OCR_3_1_3_2			BIT(19)
+#define OCR_3_0_3_1			BIT(18)
+#define OCR_2_9_3_0			BIT(17)
+#define OCR_2_8_2_9			BIT(16)
+#define OCR_2_7_2_8			BIT(15)
+#define OCR_VDD_MIN_2V7			GENMASK(23, 15)
+#define OCR_VDD_MIN_2V0			GENMASK(14, 8)
+#define OCR_VDD_MIN_1V7			BIT(7)
+
+#define MMC_RSP_48			BIT(0)
+#define MMC_RSP_136			BIT(1)		/* 136 bit response */
+#define MMC_RSP_CRC			BIT(2)		/* expect valid crc */
+#define MMC_RSP_CMD_IDX			BIT(3)		/* response contains cmd idx */
+#define MMC_RSP_BUSY			BIT(4)		/* device may be busy */
+
+/* JEDEC 4.51 chapter 6.12 */
+#define MMC_RESPONSE_R1			(MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC)
+#define MMC_RESPONSE_R1B		(MMC_RESPONSE_R1 | MMC_RSP_BUSY)
+#define MMC_RESPONSE_R2			(MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC)
+#define MMC_RESPONSE_R3			(MMC_RSP_48)
+#define MMC_RESPONSE_R4			(MMC_RSP_48)
+#define MMC_RESPONSE_R5			(MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX)
+#define MMC_RESPONSE_R6			(MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX)
+#define MMC_RESPONSE_R7			(MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX)
+
+/* Value randomly chosen for eMMC RCA, it should be > 1 */
+#define MMC_FIX_RCA			6
+#define RCA_SHIFT_OFFSET		16
+
+#define CMD_EXTCSD_PARTITION_CONFIG	179
+#define CMD_EXTCSD_BUS_WIDTH		183
+#define CMD_EXTCSD_HS_TIMING		185
+#define CMD_EXTCSD_SEC_CNT		212
+
+#define PART_CFG_BOOT_PARTITION1_ENABLE	(U(1) << 3)
+#define PART_CFG_PARTITION1_ACCESS	(U(1) << 0)
+
+/* Values in EXT CSD register */
+#define MMC_BUS_WIDTH_1			U(0)
+#define MMC_BUS_WIDTH_4			U(1)
+#define MMC_BUS_WIDTH_8			U(2)
+#define MMC_BUS_WIDTH_DDR_4		U(5)
+#define MMC_BUS_WIDTH_DDR_8		U(6)
+#define MMC_BOOT_MODE_BACKWARD		(U(0) << 3)
+#define MMC_BOOT_MODE_HS_TIMING		(U(1) << 3)
+#define MMC_BOOT_MODE_DDR		(U(2) << 3)
+
+#define EXTCSD_SET_CMD			(U(0) << 24)
+#define EXTCSD_SET_BITS			(U(1) << 24)
+#define EXTCSD_CLR_BITS			(U(2) << 24)
+#define EXTCSD_WRITE_BYTES		(U(3) << 24)
+#define EXTCSD_CMD(x)			(((x) & 0xff) << 16)
+#define EXTCSD_VALUE(x)			(((x) & 0xff) << 8)
+#define EXTCSD_CMD_SET_NORMAL		U(1)
+
+#define CSD_TRAN_SPEED_UNIT_MASK	GENMASK(2, 0)
+#define CSD_TRAN_SPEED_MULT_MASK	GENMASK(6, 3)
+#define CSD_TRAN_SPEED_MULT_SHIFT	3
+
+#define STATUS_CURRENT_STATE(x)		(((x) & 0xf) << 9)
+#define STATUS_READY_FOR_DATA		BIT(8)
+#define STATUS_SWITCH_ERROR		BIT(7)
+#define MMC_GET_STATE(x)		(((x) >> 9) & 0xf)
+#define MMC_STATE_IDLE			0
+#define MMC_STATE_READY			1
+#define MMC_STATE_IDENT			2
+#define MMC_STATE_STBY			3
+#define MMC_STATE_TRAN			4
+#define MMC_STATE_DATA			5
+#define MMC_STATE_RCV			6
+#define MMC_STATE_PRG			7
+#define MMC_STATE_DIS			8
+#define MMC_STATE_BTST			9
+#define MMC_STATE_SLP			10
+
+#define MMC_FLAG_CMD23			(U(1) << 0)
+
+#define CMD8_CHECK_PATTERN		U(0xAA)
+#define VHS_2_7_3_6_V			BIT(8)
+
+#define SD_SCR_BUS_WIDTH_1		BIT(8)
+#define SD_SCR_BUS_WIDTH_4		BIT(10)
+
+struct mmc_cmd {
+	unsigned int	cmd_idx;
+	unsigned int	cmd_arg;
+	unsigned int	resp_type;
+	unsigned int	resp_data[4];
+};
+
+struct mmc_ops {
+	void (*init)(void);
+	int (*send_cmd)(struct mmc_cmd *cmd);
+	int (*set_ios)(unsigned int clk, unsigned int width);
+	int (*prepare)(int lba, uintptr_t buf, size_t size);
+	int (*read)(int lba, uintptr_t buf, size_t size);
+	int (*write)(int lba, const uintptr_t buf, size_t size);
+};
+
+struct mmc_csd_emmc {
+	unsigned int		not_used:		1;
+	unsigned int		crc:			7;
+	unsigned int		ecc:			2;
+	unsigned int		file_format:		2;
+	unsigned int		tmp_write_protect:	1;
+	unsigned int		perm_write_protect:	1;
+	unsigned int		copy:			1;
+	unsigned int		file_format_grp:	1;
+
+	unsigned int		reserved_1:		5;
+	unsigned int		write_bl_partial:	1;
+	unsigned int		write_bl_len:		4;
+	unsigned int		r2w_factor:		3;
+	unsigned int		default_ecc:		2;
+	unsigned int		wp_grp_enable:		1;
+
+	unsigned int		wp_grp_size:		5;
+	unsigned int		erase_grp_mult:		5;
+	unsigned int		erase_grp_size:		5;
+	unsigned int		c_size_mult:		3;
+	unsigned int		vdd_w_curr_max:		3;
+	unsigned int		vdd_w_curr_min:		3;
+	unsigned int		vdd_r_curr_max:		3;
+	unsigned int		vdd_r_curr_min:		3;
+	unsigned int		c_size_low:		2;
+
+	unsigned int		c_size_high:		10;
+	unsigned int		reserved_2:		2;
+	unsigned int		dsr_imp:		1;
+	unsigned int		read_blk_misalign:	1;
+	unsigned int		write_blk_misalign:	1;
+	unsigned int		read_bl_partial:	1;
+	unsigned int		read_bl_len:		4;
+	unsigned int		ccc:			12;
+
+	unsigned int		tran_speed:		8;
+	unsigned int		nsac:			8;
+	unsigned int		taac:			8;
+	unsigned int		reserved_3:		2;
+	unsigned int		spec_vers:		4;
+	unsigned int		csd_structure:		2;
+};
+
+struct mmc_csd_sd_v2 {
+	unsigned int		not_used:		1;
+	unsigned int		crc:			7;
+	unsigned int		reserved_1:		2;
+	unsigned int		file_format:		2;
+	unsigned int		tmp_write_protect:	1;
+	unsigned int		perm_write_protect:	1;
+	unsigned int		copy:			1;
+	unsigned int		file_format_grp:	1;
+
+	unsigned int		reserved_2:		5;
+	unsigned int		write_bl_partial:	1;
+	unsigned int		write_bl_len:		4;
+	unsigned int		r2w_factor:		3;
+	unsigned int		reserved_3:		2;
+	unsigned int		wp_grp_enable:		1;
+
+	unsigned int		wp_grp_size:		7;
+	unsigned int		sector_size:		7;
+	unsigned int		erase_block_en:		1;
+	unsigned int		reserved_4:		1;
+	unsigned int		c_size_low:		16;
+
+	unsigned int		c_size_high:		6;
+	unsigned int		reserved_5:		6;
+	unsigned int		dsr_imp:		1;
+	unsigned int		read_blk_misalign:	1;
+	unsigned int		write_blk_misalign:	1;
+	unsigned int		read_bl_partial:	1;
+	unsigned int		read_bl_len:		4;
+	unsigned int		ccc:			12;
+
+	unsigned int		tran_speed:		8;
+	unsigned int		nsac:			8;
+	unsigned int		taac:			8;
+	unsigned int		reserved_6:		6;
+	unsigned int		csd_structure:		2;
+};
+
+enum mmc_device_type {
+	MMC_IS_EMMC,
+	MMC_IS_SD,
+	MMC_IS_SD_HC,
+};
+
+struct mmc_device_info {
+	unsigned long long	device_size;	/* Size of device in bytes */
+	unsigned int		block_size;	/* Block size in bytes */
+	unsigned int		max_bus_freq;	/* Max bus freq in Hz */
+	unsigned int		ocr_voltage;	/* OCR voltage */
+	enum mmc_device_type	mmc_dev_type;	/* Type of MMC */
+};
+
+size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size);
+size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size);
+size_t mmc_erase_blocks(int lba, size_t size);
+size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size);
+size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size);
+size_t mmc_rpmb_erase_blocks(int lba, size_t size);
+int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
+	     unsigned int width, unsigned int flags,
+	     struct mmc_device_info *device_info);
+
+#endif /* MMC_H */
diff --git a/include/drivers/partition/gpt.h b/include/drivers/partition/gpt.h
new file mode 100644
index 0000000..3ae160f
--- /dev/null
+++ b/include/drivers/partition/gpt.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_H
+#define GPT_H
+
+#include <drivers/partition/partition.h>
+
+#define PARTITION_TYPE_GPT		0xee
+#define GPT_HEADER_OFFSET		PARTITION_BLOCK_SIZE
+#define GPT_ENTRY_OFFSET		(GPT_HEADER_OFFSET +		\
+					 PARTITION_BLOCK_SIZE)
+#define GUID_LEN			16
+
+#define GPT_SIGNATURE			"EFI PART"
+
+typedef struct gpt_entry {
+	unsigned char		type_uuid[GUID_LEN];
+	unsigned char		unique_uuid[GUID_LEN];
+	unsigned long long	first_lba;
+	unsigned long long	last_lba;
+	unsigned long long	attr;
+	unsigned short		name[EFI_NAMELEN];
+} gpt_entry_t;
+
+typedef struct gpt_header {
+	unsigned char		signature[8];
+	unsigned int		revision;
+	unsigned int		size;
+	unsigned int		header_crc;
+	unsigned int		reserved;
+	unsigned long long	current_lba;
+	unsigned long long	backup_lba;
+	unsigned long long	first_lba;
+	unsigned long long	last_lba;
+	unsigned char		disk_uuid[16];
+	/* starting LBA of array of partition entries */
+	unsigned long long	part_lba;
+	/* number of partition entries in array */
+	unsigned int		list_num;
+	/* size of a single partition entry (usually 128) */
+	unsigned int		part_size;
+	unsigned int		part_crc;
+} gpt_header_t;
+
+int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry);
+
+#endif /* GPT_H */
diff --git a/include/drivers/partition/mbr.h b/include/drivers/partition/mbr.h
new file mode 100644
index 0000000..1452c02
--- /dev/null
+++ b/include/drivers/partition/mbr.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MBR_H
+#define MBR_H
+
+#define MBR_OFFSET			0
+
+#define MBR_PRIMARY_ENTRY_OFFSET	0x1be
+#define MBR_PRIMARY_ENTRY_SIZE		0x10
+#define MBR_PRIMARY_ENTRY_NUMBER	4
+#define MBR_CHS_ADDRESS_LEN		3
+
+#define MBR_SIGNATURE_FIRST		0x55
+#define MBR_SIGNATURE_SECOND		0xAA
+
+typedef struct mbr_entry {
+	unsigned char		status;
+	unsigned char		first_sector[MBR_CHS_ADDRESS_LEN];
+	unsigned char		type;
+	unsigned char		last_sector[MBR_CHS_ADDRESS_LEN];
+	unsigned int		first_lba;
+	unsigned int		sector_nums;
+} mbr_entry_t;
+
+#endif /* MBR_H */
diff --git a/include/drivers/partition/partition.h b/include/drivers/partition/partition.h
new file mode 100644
index 0000000..d94c782
--- /dev/null
+++ b/include/drivers/partition/partition.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PARTITION_H
+#define PARTITION_H
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+#if !PLAT_PARTITION_MAX_ENTRIES
+# define PLAT_PARTITION_MAX_ENTRIES	128
+#endif	/* PLAT_PARTITION_MAX_ENTRIES */
+
+CASSERT(PLAT_PARTITION_MAX_ENTRIES <= 128, assert_plat_partition_max_entries);
+
+#define PARTITION_BLOCK_SIZE		512
+
+#define EFI_NAMELEN			36
+
+typedef struct partition_entry {
+	uint64_t		start;
+	uint64_t		length;
+	char			name[EFI_NAMELEN];
+} partition_entry_t;
+
+typedef struct partition_entry_list {
+	partition_entry_t	list[PLAT_PARTITION_MAX_ENTRIES];
+	int			entry_count;
+} partition_entry_list_t;
+
+int load_partition_table(unsigned int image_id);
+const partition_entry_t *get_partition_entry(const char *name);
+const partition_entry_list_t *get_partition_entry_list(void);
+void partition_init(unsigned int image_id);
+
+#endif /* PARTITION_H */
diff --git a/include/drivers/renesas/rcar/console/console.h b/include/drivers/renesas/rcar/console/console.h
new file mode 100644
index 0000000..0e4ed8f
--- /dev/null
+++ b/include/drivers/renesas/rcar/console/console.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PRINTF_H
+#define RCAR_PRINTF_H
+
+#define CONSOLE_T_RCAR_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_rcar_t;
+
+/*
+ * Initialize a new rcar console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_rcar_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			  console_rcar_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* RCAR_PRINTF_H */
diff --git a/include/drivers/rpi3/gpio/rpi3_gpio.h b/include/drivers/rpi3/gpio/rpi3_gpio.h
new file mode 100644
index 0000000..159a2e0
--- /dev/null
+++ b/include/drivers/rpi3/gpio/rpi3_gpio.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_GPIO_H
+#define RPI3_GPIO_H
+
+#include <stdint.h>
+#include <drivers/gpio.h>
+
+struct rpi3_gpio_params {
+	uintptr_t       reg_base;
+};
+
+void rpi3_gpio_init(struct rpi3_gpio_params *params);
+int rpi3_gpio_get_select(int gpio);
+void rpi3_gpio_set_select(int gpio, int fsel);
+
+#define RPI3_GPIO_GPFSEL(n)	((n) * U(0x04))
+#define RPI3_GPIO_GPSET(n)	(((n) * U(0x04)) + U(0x1C))
+#define RPI3_GPIO_GPCLR(n)	(((n) * U(0x04)) + U(0x28))
+#define RPI3_GPIO_GPLEV(n) 	(((n) * U(0x04)) + U(0x34))
+#define RPI3_GPIO_GPPUD		U(0x94)
+#define RPI3_GPIO_GPPUDCLK(n)	(((n) * U(0x04)) + U(0x98))
+
+#define RPI3_GPIO_FUNC_INPUT	U(0)
+#define RPI3_GPIO_FUNC_OUTPUT	U(1)
+#define RPI3_GPIO_FUNC_ALT0	U(4)
+#define RPI3_GPIO_FUNC_ALT1	U(5)
+#define RPI3_GPIO_FUNC_ALT2	U(6)
+#define RPI3_GPIO_FUNC_ALT3	U(7)
+#define RPI3_GPIO_FUNC_ALT4	U(3)
+#define RPI3_GPIO_FUNC_ALT5	U(2)
+
+#endif  /* RPI3_GPIO_H */
diff --git a/include/drivers/rpi3/sdhost/rpi3_sdhost.h b/include/drivers/rpi3/sdhost/rpi3_sdhost.h
new file mode 100644
index 0000000..1653240
--- /dev/null
+++ b/include/drivers/rpi3/sdhost/rpi3_sdhost.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_SDHOST_H
+#define	RPI3_SDHOST_H
+
+#include <drivers/mmc.h>
+#include <stdint.h>
+#include <platform_def.h>
+
+struct rpi3_sdhost_params {
+	uintptr_t	reg_base;
+	uint32_t	clk_rate;
+	uint32_t	bus_width;
+	uint32_t        flags;
+	uint32_t	current_cmd;
+	uint8_t		cmdbusy;
+	uint8_t		mmc_app_cmd;
+	uint32_t	ns_per_fifo_word;
+
+	uint32_t	sdcard_rca;
+	uint32_t	gpio48_pinselect[6];
+};
+
+void rpi3_sdhost_init(struct rpi3_sdhost_params *params,
+		      struct mmc_device_info *mmc_dev_info);
+void rpi3_sdhost_stop(void);
+
+/* Registers */
+#define HC_COMMAND			0x00        /* Command and flags */
+#define HC_ARGUMENT			0x04
+#define HC_TIMEOUTCOUNTER		0x08
+#define HC_CLOCKDIVISOR			0x0c
+#define HC_RESPONSE_0			0x10
+#define HC_RESPONSE_1			0x14
+#define HC_RESPONSE_2			0x18
+#define HC_RESPONSE_3			0x1c
+#define HC_HOSTSTATUS			0x20
+#define HC_POWER			0x30
+#define HC_DEBUG			0x34
+#define HC_HOSTCONFIG			0x38
+#define HC_BLOCKSIZE			0x3c
+#define HC_DATAPORT			0x40
+#define HC_BLOCKCOUNT			0x50
+
+/* Flags for HC_COMMAND register */
+#define HC_CMD_ENABLE			0x8000
+#define HC_CMD_FAILED			0x4000
+#define HC_CMD_BUSY			0x0800
+#define HC_CMD_RESPONSE_NONE		0x0400
+#define HC_CMD_RESPONSE_LONG		0x0200
+#define HC_CMD_WRITE			0x0080
+#define HC_CMD_READ			0x0040
+#define HC_CMD_COMMAND_MASK		0x003f
+
+#define HC_CLOCKDIVISOR_MAXVAL		0x07ff
+#define HC_CLOCKDIVISOR_PREFERVAL	0x027b
+#define HC_CLOCKDIVISOR_SLOWVAL		0x0148
+#define HC_CLOCKDIVISOR_STOPVAL		0x01fb
+
+/* Flags for HC_HOSTSTATUS register */
+#define HC_HSTST_HAVEDATA		0x0001
+#define HC_HSTST_ERROR_FIFO		0x0008
+#define HC_HSTST_ERROR_CRC7		0x0010
+#define HC_HSTST_ERROR_CRC16		0x0020
+#define HC_HSTST_TIMEOUT_CMD		0x0040
+#define HC_HSTST_TIMEOUT_DATA		0x0080
+#define HC_HSTST_INT_BLOCK		0x0200
+#define HC_HSTST_INT_BUSY		0x0400
+
+#define HC_HSTST_RESET			0xffff
+
+#define HC_HSTST_MASK_ERROR_DATA	(HC_HSTST_ERROR_FIFO | \
+					 HC_HSTST_ERROR_CRC7 | \
+					 HC_HSTST_ERROR_CRC16 | \
+					 HC_HSTST_TIMEOUT_DATA)
+
+#define HC_HSTST_MASK_ERROR_ALL		(HC_HSTST_MASK_ERROR_DATA | \
+					 HC_HSTST_TIMEOUT_CMD)
+
+/* Flags for HC_HOSTCONFIG register */
+#define HC_HSTCF_INTBUS_WIDE		0x0002
+#define HC_HSTCF_EXTBUS_4BIT		0x0004
+#define HC_HSTCF_SLOW_CARD		0x0008
+#define HC_HSTCF_INT_DATA		0x0010
+#define HC_HSTCF_INT_BLOCK		0x0100
+#define HC_HSTCF_INT_BUSY		0x0400
+
+/* Flags for HC_DEBUG register */
+#define HC_DBG_FIFO_THRESH_WRITE_SHIFT	9
+#define HC_DBG_FIFO_THRESH_READ_SHIFT	14
+#define HC_DBG_FIFO_THRESH_MASK		0x001f
+#define HC_DBG_FSM_MASK			0xf
+#define HC_DBG_FSM_IDENTMODE		0x0
+#define HC_DBG_FSM_DATAMODE		0x1
+#define HC_DBG_FSM_READDATA		0x2
+#define HC_DBG_FSM_WRITEDATA		0x3
+#define HC_DBG_FSM_READWAIT		0x4
+#define HC_DBG_FSM_READCRC		0x5
+#define HC_DBG_FSM_WRITECRC		0x6
+#define HC_DBG_FSM_WRITEWAIT1		0x7
+#define HC_DBG_FSM_POWERDOWN		0x8
+#define HC_DBG_FSM_POWERUP		0x9
+#define HC_DBG_FSM_WRITESTART1		0xa
+#define HC_DBG_FSM_WRITESTART2		0xb
+#define HC_DBG_FSM_GENPULSES		0xc
+#define HC_DBG_FSM_WRITEWAIT2		0xd
+#define HC_DBG_FSM_STARTPOWDOWN		0xf
+#define HC_DBG_FORCE_DATA_MODE		0x40000
+
+/* Settings */
+#define HC_FIFO_SIZE			16
+#define HC_FIFO_THRESH_READ		4
+#define HC_FIFO_THRESH_WRITE		4
+
+#define HC_TIMEOUT_DEFAULT		0x00f00000
+#define HC_TIMEOUT_IDLE			0x00a00000
+
+#endif  /* RPI3_SDHOST_H */
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
new file mode 100644
index 0000000..2171550
--- /dev/null
+++ b/include/drivers/st/bsec.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BSEC_H
+#define BSEC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*
+ * IP configuration
+ */
+#define BSEC_OTP_MASK			GENMASK(4, 0)
+#define BSEC_OTP_BANK_SHIFT		5
+#define BSEC_TIMEOUT_VALUE		0xFFFF
+
+#define ADDR_LOWER_OTP_PERLOCK_SHIFT	0x03
+#define DATA_LOWER_OTP_PERLOCK_BIT	0x03U /* 2 significants bits are used */
+#define DATA_LOWER_OTP_PERLOCK_MASK	GENMASK(2, 0)
+#define ADDR_UPPER_OTP_PERLOCK_SHIFT	0x04
+#define DATA_UPPER_OTP_PERLOCK_BIT	0x01U /* 1 significants bits are used */
+#define DATA_UPPER_OTP_PERLOCK_MASK	GENMASK(3, 0)
+
+/*
+ * Return status
+ */
+#define BSEC_OK				0U
+#define BSEC_ERROR			0xFFFFFFFFU
+#define BSEC_DISTURBED			0xFFFFFFFEU
+#define BSEC_INVALID_PARAM		0xFFFFFFFCU
+#define BSEC_PROG_FAIL			0xFFFFFFFBU
+#define BSEC_LOCK_FAIL			0xFFFFFFFAU
+#define BSEC_WRITE_FAIL			0xFFFFFFF9U
+#define BSEC_SHADOW_FAIL		0xFFFFFFF8U
+#define BSEC_TIMEOUT			0xFFFFFFF7U
+
+/*
+ * BSEC REGISTER OFFSET (base relative)
+ */
+#define BSEC_OTP_CONF_OFF		0x000U
+#define BSEC_OTP_CTRL_OFF		0x004U
+#define BSEC_OTP_WRDATA_OFF		0x008U
+#define BSEC_OTP_STATUS_OFF		0x00CU
+#define BSEC_OTP_LOCK_OFF		0x010U
+#define BSEC_DEN_OFF			0x014U
+#define BSEC_DISTURBED_OFF		0x01CU
+#define BSEC_DISTURBED1_OFF		0x020U
+#define BSEC_DISTURBED2_OFF		0x024U
+#define BSEC_ERROR_OFF			0x034U
+#define BSEC_ERROR1_OFF			0x038U
+#define BSEC_ERROR2_OFF			0x03CU
+#define BSEC_WRLOCK_OFF			0x04CU /* Safmem permanent lock */
+#define BSEC_WRLOCK1_OFF		0x050U
+#define BSEC_WRLOCK2_OFF		0x054U
+#define BSEC_SPLOCK_OFF			0x064U /* Program safmem sticky lock */
+#define BSEC_SPLOCK1_OFF		0x068U
+#define BSEC_SPLOCK2_OFF		0x06CU
+#define BSEC_SWLOCK_OFF			0x07CU /* Write in OTP sticky lock */
+#define BSEC_SWLOCK1_OFF		0x080U
+#define BSEC_SWLOCK2_OFF		0x084U
+#define BSEC_SRLOCK_OFF			0x094U /* Shadowing sticky lock */
+#define BSEC_SRLOCK1_OFF		0x098U
+#define BSEC_SRLOCK2_OFF		0x09CU
+#define BSEC_JTAG_IN_OFF		0x0ACU
+#define BSEC_JTAG_OUT_OFF		0x0B0U
+#define BSEC_SCRATCH_OFF		0x0B4U
+#define BSEC_OTP_DATA_OFF		0x200U
+#define BSEC_IPHW_CFG_OFF		0xFF0U
+#define BSEC_IPVR_OFF			0xFF4U
+#define BSEC_IP_ID_OFF			0xFF8U
+#define BSEC_IP_MAGIC_ID_OFF		0xFFCU
+
+/*
+ * BSEC_CONFIGURATION Register
+ */
+#define BSEC_CONF_POWER_UP_MASK		BIT(0)
+#define BSEC_CONF_POWER_UP_SHIFT	0
+#define BSEC_CONF_FRQ_MASK		GENMASK(2, 1)
+#define BSEC_CONF_FRQ_SHIFT		1
+#define BSEC_CONF_PRG_WIDTH_MASK	GENMASK(6, 3)
+#define BSEC_CONF_PRG_WIDTH_SHIFT	3
+#define BSEC_CONF_TREAD_MASK		GENMASK(8, 7)
+#define BSEC_CONF_TREAD_SHIFT		7
+
+/*
+ * BSEC_CONTROL Register
+ */
+#define BSEC_READ			0x000U
+#define BSEC_WRITE			0x100U
+#define BSEC_LOCK			0x200U
+
+/*
+ * BSEC_OTP_LOCK register
+ */
+#define UPPER_OTP_LOCK_MASK		BIT(0)
+#define UPPER_OTP_LOCK_SHIFT		0
+#define DENREG_LOCK_MASK		BIT(2)
+#define DENREG_LOCK_SHIFT		2
+#define GPLOCK_LOCK_MASK		BIT(4)
+#define GPLOCK_LOCK_SHIFT		4
+
+/*
+ * BSEC_OTP_STATUS Register
+ */
+#define BSEC_MODE_STATUS_MASK		GENMASK(2, 0)
+#define BSEC_MODE_BUSY_MASK		BIT(3)
+#define BSEC_MODE_PROGFAIL_MASK		BIT(4)
+#define BSEC_MODE_PWR_MASK		BIT(5)
+#define BSEC_MODE_BIST1_LOCK_MASK	BIT(6)
+#define BSEC_MODE_BIST2_LOCK_MASK	BIT(7)
+
+/* OTP MODE*/
+#define BSEC_MODE_OPEN1			0x00
+#define BSEC_MODE_SECURED		0x01
+#define BSEC_MODE_OPEN2			0x02
+#define BSEC_MODE_INVALID		0x04
+
+/* BSEC_DENABLE Register */
+#define BSEC_HDPEN			BIT(4)
+#define BSEC_SPIDEN			BIT(5)
+#define BSEC_SPINDEN			BIT(6)
+#define BSEC_DBGSWGEN			BIT(10)
+#define BSEC_DEN_ALL_MSK		GENMASK(10, 0)
+
+/* BSEC_FENABLE Register */
+#define BSEC_FEN_ALL_MSK		GENMASK(14, 0)
+
+/*
+ * OTP Lock services definition
+ * Value must corresponding to the bit number in the register
+ */
+#define BSEC_LOCK_UPPER_OTP		0x00
+#define BSEC_LOCK_DEBUG			0x02
+#define BSEC_LOCK_PROGRAM		0x03
+
+/* Values for struct bsec_config::freq */
+#define FREQ_10_20_MHZ			0x0
+#define FREQ_20_30_MHZ			0x1
+#define FREQ_30_45_MHZ			0x2
+#define FREQ_45_67_MHZ			0x3
+
+/*
+ * Device info structure, providing device-specific functions and a means of
+ * adding driver-specific state
+ */
+struct bsec_config {
+	uint8_t tread;		/* SAFMEM Reading current level default 0 */
+	uint8_t pulse_width;	/* SAFMEM Programming pulse width default 1 */
+	uint8_t freq;		/* SAFMEM CLOCK see freq value define
+				 * default FREQ_45_67_MHZ
+				 */
+	uint8_t power;		/* Power up SAFMEM. 1 power up, 0 power off */
+	uint8_t prog_lock;	/* Programming Sticky lock
+				 * 1 programming is locked until next reset
+				 */
+	uint8_t den_lock;	/* Debug enable sticky lock
+				 * 1 debug enable is locked until next reset
+				 */
+	uint8_t upper_otp_lock;	/* Shadowing of upper OTP sticky lock
+				 * 1 shadowing of upper OTP is locked
+				 * until next reset
+				 */
+};
+
+uint32_t bsec_probe(void);
+uint32_t bsec_get_base(void);
+
+uint32_t bsec_set_config(struct bsec_config *cfg);
+uint32_t bsec_get_config(struct bsec_config *cfg);
+
+uint32_t bsec_shadow_register(uint32_t otp);
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp);
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp);
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp);
+uint32_t bsec_permanent_lock_otp(uint32_t otp);
+
+uint32_t bsec_write_debug_conf(uint32_t val);
+uint32_t bsec_read_debug_conf(void);
+uint32_t bsec_write_feature_conf(uint32_t val);
+uint32_t bsec_read_feature_conf(uint32_t *val);
+
+uint32_t bsec_get_status(void);
+uint32_t bsec_get_hw_conf(void);
+uint32_t bsec_get_version(void);
+uint32_t bsec_get_id(void);
+uint32_t bsec_get_magic_id(void);
+
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value);
+bool bsec_read_sr_lock(uint32_t otp);
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value);
+bool bsec_read_sw_lock(uint32_t otp);
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value);
+bool bsec_read_sp_lock(uint32_t otp);
+bool bsec_wr_lock(uint32_t otp);
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value);
+
+bool bsec_mode_is_closed_device(void);
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
+uint32_t bsec_check_nsec_access_rights(uint32_t otp);
+
+#endif /* BSEC_H */
diff --git a/include/drivers/st/io_mmc.h b/include/drivers/st/io_mmc.h
new file mode 100644
index 0000000..b35b4b5
--- /dev/null
+++ b/include/drivers/st/io_mmc.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_MMC_H
+#define IO_MMC_H
+
+#include <drivers/io/io_driver.h>
+
+int register_io_dev_mmc(const io_dev_connector_t **dev_con);
+
+#endif /* IO_MMC_H */
diff --git a/include/drivers/st/io_stm32image.h b/include/drivers/st/io_stm32image.h
new file mode 100644
index 0000000..6806055
--- /dev/null
+++ b/include/drivers/st/io_stm32image.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_STM32IMAGE_H
+#define IO_STM32IMAGE_H
+
+#include <drivers/io/io_driver.h>
+#include <drivers/partition/partition.h>
+
+#define MAX_LBA_SIZE		512
+#define MAX_PART_NAME_SIZE	(EFI_NAMELEN + 1)
+#define STM32_PART_NUM		(PLAT_PARTITION_MAX_ENTRIES - STM32_TF_A_COPIES)
+
+struct stm32image_part_info {
+	char name[MAX_PART_NAME_SIZE];
+	uint32_t binary_type;
+	uintptr_t part_offset;
+	uint32_t bkp_offset;
+};
+
+struct stm32image_device_info {
+	struct stm32image_part_info part_info[STM32_PART_NUM];
+	uint32_t device_size;
+	uint32_t lba_size;
+};
+
+int register_io_dev_stm32image(const io_dev_connector_t **dev_con);
+
+#endif /* IO_STM32IMAGE_H */
diff --git a/include/drivers/st/stm32_console.h b/include/drivers/st/stm32_console.h
new file mode 100644
index 0000000..a2ad87c
--- /dev/null
+++ b/include/drivers/st/stm32_console.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_CONSOLE_H
+#define STM32_CONSOLE_H
+
+#include <drivers/console.h>
+
+#define CONSOLE_T_STM32_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+struct console_stm32 {
+	console_t console;
+	uintptr_t base;
+};
+
+/*
+ * Initialize a new STM32 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_stm32_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   struct console_stm32 *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* STM32_CONSOLE_H */
diff --git a/include/drivers/st/stm32_gpio.h b/include/drivers/st/stm32_gpio.h
new file mode 100644
index 0000000..e241f58
--- /dev/null
+++ b/include/drivers/st/stm32_gpio.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_GPIO_H
+#define STM32_GPIO_H
+
+#include <lib/utils_def.h>
+
+#define GPIO_MODE_OFFSET	U(0x00)
+#define GPIO_TYPE_OFFSET	U(0x04)
+#define GPIO_SPEED_OFFSET	U(0x08)
+#define GPIO_PUPD_OFFSET	U(0x0C)
+#define GPIO_BSRR_OFFSET	U(0x18)
+#define GPIO_AFRL_OFFSET	U(0x20)
+#define GPIO_AFRH_OFFSET	U(0x24)
+#define GPIO_SECR_OFFSET	U(0x30)
+
+#define GPIO_ALT_LOWER_LIMIT	U(0x08)
+
+#define GPIO_PIN_(_x)		U(_x)
+#define GPIO_PIN_MAX		GPIO_PIN_(15)
+
+#define GPIO_ALTERNATE_(_x)	U(_x)
+#define GPIO_ALTERNATE_MASK	U(0x0F)
+
+#define GPIO_MODE_INPUT		0x00
+#define GPIO_MODE_OUTPUT	0x01
+#define GPIO_MODE_ALTERNATE	0x02
+#define GPIO_MODE_ANALOG	0x03
+#define GPIO_MODE_MASK		U(0x03)
+
+#define GPIO_OPEN_DRAIN		U(0x10)
+
+#define GPIO_SPEED_LOW		0x00
+#define GPIO_SPEED_MEDIUM	0x01
+#define GPIO_SPEED_HIGH		0x02
+#define GPIO_SPEED_VERY_HIGH	0x03
+#define GPIO_SPEED_MASK		U(0x03)
+
+#define GPIO_NO_PULL		0x00
+#define GPIO_PULL_UP		0x01
+#define GPIO_PULL_DOWN		0x02
+#define GPIO_PULL_MASK		U(0x03)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+int dt_set_pinctrl_config(int node);
+void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
+	      uint32_t pull, uint32_t alternate, uint8_t status);
+void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure);
+#endif /*__ASSEMBLER__*/
+
+#endif /* STM32_GPIO_H */
diff --git a/include/drivers/st/stm32_i2c.h b/include/drivers/st/stm32_i2c.h
new file mode 100644
index 0000000..170d4cf
--- /dev/null
+++ b/include/drivers/st/stm32_i2c.h
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_I2C_H
+#define STM32_I2C_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* Bit definition for I2C_CR1 register */
+#define I2C_CR1_PE			BIT(0)
+#define I2C_CR1_TXIE			BIT(1)
+#define I2C_CR1_RXIE			BIT(2)
+#define I2C_CR1_ADDRIE			BIT(3)
+#define I2C_CR1_NACKIE			BIT(4)
+#define I2C_CR1_STOPIE			BIT(5)
+#define I2C_CR1_TCIE			BIT(6)
+#define I2C_CR1_ERRIE			BIT(7)
+#define I2C_CR1_DNF			GENMASK(11, 8)
+#define I2C_CR1_ANFOFF			BIT(12)
+#define I2C_CR1_SWRST			BIT(13)
+#define I2C_CR1_TXDMAEN			BIT(14)
+#define I2C_CR1_RXDMAEN			BIT(15)
+#define I2C_CR1_SBC			BIT(16)
+#define I2C_CR1_NOSTRETCH		BIT(17)
+#define I2C_CR1_WUPEN			BIT(18)
+#define I2C_CR1_GCEN			BIT(19)
+#define I2C_CR1_SMBHEN			BIT(22)
+#define I2C_CR1_SMBDEN			BIT(21)
+#define I2C_CR1_ALERTEN			BIT(22)
+#define I2C_CR1_PECEN			BIT(23)
+
+/* Bit definition for I2C_CR2 register */
+#define I2C_CR2_SADD			GENMASK(9, 0)
+#define I2C_CR2_RD_WRN			BIT(10)
+#define I2C_CR2_RD_WRN_OFFSET		10U
+#define I2C_CR2_ADD10			BIT(11)
+#define I2C_CR2_HEAD10R			BIT(12)
+#define I2C_CR2_START			BIT(13)
+#define I2C_CR2_STOP			BIT(14)
+#define I2C_CR2_NACK			BIT(15)
+#define I2C_CR2_NBYTES			GENMASK(23, 16)
+#define I2C_CR2_NBYTES_OFFSET		16U
+#define I2C_CR2_RELOAD			BIT(24)
+#define I2C_CR2_AUTOEND			BIT(25)
+#define I2C_CR2_PECBYTE			BIT(26)
+
+/* Bit definition for I2C_OAR1 register */
+#define I2C_OAR1_OA1			GENMASK(9, 0)
+#define I2C_OAR1_OA1MODE		BIT(10)
+#define I2C_OAR1_OA1EN			BIT(15)
+
+/* Bit definition for I2C_OAR2 register */
+#define I2C_OAR2_OA2			GENMASK(7, 1)
+#define I2C_OAR2_OA2MSK			GENMASK(10, 8)
+#define I2C_OAR2_OA2NOMASK		0
+#define I2C_OAR2_OA2MASK01		BIT(8)
+#define I2C_OAR2_OA2MASK02		BIT(9)
+#define I2C_OAR2_OA2MASK03		GENMASK(9, 8)
+#define I2C_OAR2_OA2MASK04		BIT(10)
+#define I2C_OAR2_OA2MASK05		(BIT(8) | BIT(10))
+#define I2C_OAR2_OA2MASK06		(BIT(9) | BIT(10))
+#define I2C_OAR2_OA2MASK07		GENMASK(10, 8)
+#define I2C_OAR2_OA2EN			BIT(15)
+
+/* Bit definition for I2C_TIMINGR register */
+#define I2C_TIMINGR_SCLL		GENMASK(7, 0)
+#define I2C_TIMINGR_SCLH		GENMASK(15, 8)
+#define I2C_TIMINGR_SDADEL		GENMASK(19, 16)
+#define I2C_TIMINGR_SCLDEL		GENMASK(23, 20)
+#define I2C_TIMINGR_PRESC		GENMASK(31, 28)
+
+/* Bit definition for I2C_TIMEOUTR register */
+#define I2C_TIMEOUTR_TIMEOUTA		GENMASK(11, 0)
+#define I2C_TIMEOUTR_TIDLE		BIT(12)
+#define I2C_TIMEOUTR_TIMOUTEN		BIT(15)
+#define I2C_TIMEOUTR_TIMEOUTB		GENMASK(27, 16)
+#define I2C_TIMEOUTR_TEXTEN		BIT(31)
+
+/* Bit definition for I2C_ISR register */
+#define I2C_ISR_TXE			BIT(0)
+#define I2C_ISR_TXIS			BIT(1)
+#define I2C_ISR_RXNE			BIT(2)
+#define I2C_ISR_ADDR			BIT(3)
+#define I2C_ISR_NACKF			BIT(4)
+#define I2C_ISR_STOPF			BIT(5)
+#define I2C_ISR_TC			BIT(6)
+#define I2C_ISR_TCR			BIT(7)
+#define I2C_ISR_BERR			BIT(8)
+#define I2C_ISR_ARLO			BIT(9)
+#define I2C_ISR_OVR			BIT(10)
+#define I2C_ISR_PECERR			BIT(11)
+#define I2C_ISR_TIMEOUT			BIT(12)
+#define I2C_ISR_ALERT			BIT(13)
+#define I2C_ISR_BUSY			BIT(15)
+#define I2C_ISR_DIR			BIT(16)
+#define I2C_ISR_ADDCODE			GENMASK(23, 17)
+
+/* Bit definition for I2C_ICR register */
+#define I2C_ICR_ADDRCF			BIT(3)
+#define I2C_ICR_NACKCF			BIT(4)
+#define I2C_ICR_STOPCF			BIT(5)
+#define I2C_ICR_BERRCF			BIT(8)
+#define I2C_ICR_ARLOCF			BIT(9)
+#define I2C_ICR_OVRCF			BIT(10)
+#define I2C_ICR_PECCF			BIT(11)
+#define I2C_ICR_TIMOUTCF		BIT(12)
+#define I2C_ICR_ALERTCF			BIT(13)
+
+enum i2c_speed_e {
+	I2C_SPEED_STANDARD,	/* 100 kHz */
+	I2C_SPEED_FAST,		/* 400 kHz */
+	I2C_SPEED_FAST_PLUS,	/* 1 MHz   */
+};
+
+#define STANDARD_RATE				100000
+#define FAST_RATE				400000
+#define FAST_PLUS_RATE				1000000
+
+struct stm32_i2c_init_s {
+	uint32_t own_address1;		/*
+					 * Specifies the first device own
+					 * address. This parameter can be a
+					 * 7-bit or 10-bit address.
+					 */
+
+	uint32_t addressing_mode;	/*
+					 * Specifies if 7-bit or 10-bit
+					 * addressing mode is selected.
+					 * This parameter can be a value of
+					 * @ref I2C_ADDRESSING_MODE.
+					 */
+
+	uint32_t dual_address_mode;	/*
+					 * Specifies if dual addressing mode is
+					 * selected.
+					 * This parameter can be a value of @ref
+					 * I2C_DUAL_ADDRESSING_MODE.
+					 */
+
+	uint32_t own_address2;		/*
+					 * Specifies the second device own
+					 * address if dual addressing mode is
+					 * selected. This parameter can be a
+					 * 7-bit address.
+					 */
+
+	uint32_t own_address2_masks;	/*
+					 * Specifies the acknowledge mask
+					 * address second device own address
+					 * if dual addressing mode is selected
+					 * This parameter can be a value of @ref
+					 * I2C_OWN_ADDRESS2_MASKS.
+					 */
+
+	uint32_t general_call_mode;	/*
+					 * Specifies if general call mode is
+					 * selected.
+					 * This parameter can be a value of @ref
+					 * I2C_GENERAL_CALL_ADDRESSING_MODE.
+					 */
+
+	uint32_t no_stretch_mode;	/*
+					 * Specifies if nostretch mode is
+					 * selected.
+					 * This parameter can be a value of @ref
+					 * I2C_NOSTRETCH_MODE.
+					 */
+
+	uint32_t rise_time;		/*
+					 * Specifies the SCL clock pin rising
+					 * time in nanoseconds.
+					 */
+
+	uint32_t fall_time;		/*
+					 * Specifies the SCL clock pin falling
+					 * time in nanoseconds.
+					 */
+
+	enum i2c_speed_e speed_mode;	/*
+					 * Specifies the I2C clock source
+					 * frequency mode.
+					 * This parameter can be a value of @ref
+					 * i2c_speed_mode_e.
+					 */
+
+	int analog_filter;		/*
+					 * Specifies if the I2C analog noise
+					 * filter is selected.
+					 * This parameter can be 0 (filter
+					 * off), all other values mean filter
+					 * on.
+					 */
+
+	uint8_t digital_filter_coef;	/*
+					 * Specifies the I2C digital noise
+					 * filter coefficient.
+					 * This parameter can be a value
+					 * between 0 and
+					 * STM32_I2C_DIGITAL_FILTER_MAX.
+					 */
+};
+
+enum i2c_state_e {
+	I2C_STATE_RESET          = 0x00U,	/* Not yet initialized       */
+	I2C_STATE_READY          = 0x20U,	/* Ready for use             */
+	I2C_STATE_BUSY           = 0x24U,	/* Internal process ongoing  */
+	I2C_STATE_BUSY_TX        = 0x21U,	/* Data Transmission ongoing */
+	I2C_STATE_BUSY_RX        = 0x22U,	/* Data Reception ongoing    */
+};
+
+enum i2c_mode_e {
+	I2C_MODE_NONE   = 0x00U,	/* No active communication      */
+	I2C_MODE_MASTER = 0x10U,	/* Communication in Master Mode */
+	I2C_MODE_SLAVE  = 0x20U,	/* Communication in Slave Mode  */
+	I2C_MODE_MEM    = 0x40U		/* Communication in Memory Mode */
+
+};
+
+#define I2C_ERROR_NONE		0x00000000U	/* No error              */
+#define I2C_ERROR_BERR		0x00000001U	/* BERR error            */
+#define I2C_ERROR_ARLO		0x00000002U	/* ARLO error            */
+#define I2C_ERROR_AF		0x00000004U	/* ACKF error            */
+#define I2C_ERROR_OVR		0x00000008U	/* OVR error             */
+#define I2C_ERROR_DMA		0x00000010U	/* DMA transfer error    */
+#define I2C_ERROR_TIMEOUT	0x00000020U	/* Timeout error         */
+#define I2C_ERROR_SIZE		0x00000040U	/* Size Management error */
+
+struct i2c_handle_s {
+	uint32_t i2c_base_addr;			/* Registers base address */
+	unsigned int dt_status;			/* DT nsec/sec status     */
+	unsigned int clock;			/* Clock reference        */
+	uint8_t lock;				/* Locking object         */
+	enum i2c_state_e i2c_state;		/* Communication state    */
+	enum i2c_mode_e i2c_mode;		/* Communication mode     */
+	uint32_t i2c_err;			/* Error code             */
+};
+
+#define I2C_ADDRESSINGMODE_7BIT		0x00000001U
+#define I2C_ADDRESSINGMODE_10BIT	0x00000002U
+
+#define I2C_DUALADDRESS_DISABLE		0x00000000U
+#define I2C_DUALADDRESS_ENABLE		I2C_OAR2_OA2EN
+
+#define I2C_GENERALCALL_DISABLE		0x00000000U
+#define I2C_GENERALCALL_ENABLE		I2C_CR1_GCEN
+
+#define I2C_NOSTRETCH_DISABLE		0x00000000U
+#define I2C_NOSTRETCH_ENABLE		I2C_CR1_NOSTRETCH
+
+#define I2C_MEMADD_SIZE_8BIT		0x00000001U
+#define I2C_MEMADD_SIZE_16BIT		0x00000002U
+
+#define I2C_RELOAD_MODE			I2C_CR2_RELOAD
+#define I2C_AUTOEND_MODE		I2C_CR2_AUTOEND
+#define I2C_SOFTEND_MODE		0x00000000U
+
+#define I2C_NO_STARTSTOP		0x00000000U
+#define I2C_GENERATE_STOP		(BIT(31) | I2C_CR2_STOP)
+#define I2C_GENERATE_START_READ		(BIT(31) | I2C_CR2_START | \
+					 I2C_CR2_RD_WRN)
+#define I2C_GENERATE_START_WRITE	(BIT(31) | I2C_CR2_START)
+
+#define I2C_FLAG_TXE			I2C_ISR_TXE
+#define I2C_FLAG_TXIS			I2C_ISR_TXIS
+#define I2C_FLAG_RXNE			I2C_ISR_RXNE
+#define I2C_FLAG_ADDR			I2C_ISR_ADDR
+#define I2C_FLAG_AF			I2C_ISR_NACKF
+#define I2C_FLAG_STOPF			I2C_ISR_STOPF
+#define I2C_FLAG_TC			I2C_ISR_TC
+#define I2C_FLAG_TCR			I2C_ISR_TCR
+#define I2C_FLAG_BERR			I2C_ISR_BERR
+#define I2C_FLAG_ARLO			I2C_ISR_ARLO
+#define I2C_FLAG_OVR			I2C_ISR_OVR
+#define I2C_FLAG_PECERR			I2C_ISR_PECERR
+#define I2C_FLAG_TIMEOUT		I2C_ISR_TIMEOUT
+#define I2C_FLAG_ALERT			I2C_ISR_ALERT
+#define I2C_FLAG_BUSY			I2C_ISR_BUSY
+#define I2C_FLAG_DIR			I2C_ISR_DIR
+
+#define I2C_RESET_CR2			(I2C_CR2_SADD | I2C_CR2_HEAD10R | \
+					 I2C_CR2_NBYTES | I2C_CR2_RELOAD  | \
+					 I2C_CR2_RD_WRN)
+
+#define I2C_TIMEOUT_BUSY_MS		25U
+
+#define I2C_ANALOGFILTER_ENABLE		0x00000000U
+#define I2C_ANALOGFILTER_DISABLE	I2C_CR1_ANFOFF
+
+/* STM32 specific defines */
+#define STM32_I2C_RISE_TIME_DEFAULT		25	/* ns */
+#define STM32_I2C_FALL_TIME_DEFAULT		10	/* ns */
+#define STM32_I2C_SPEED_DEFAULT			I2C_SPEED_STANDARD
+#define STM32_I2C_ANALOG_FILTER_DELAY_MIN	50	/* ns */
+#define STM32_I2C_ANALOG_FILTER_DELAY_MAX	260	/* ns */
+#define STM32_I2C_DIGITAL_FILTER_MAX		16
+
+int stm32_i2c_get_setup_from_fdt(void *fdt, int node,
+				 struct stm32_i2c_init_s *init);
+int stm32_i2c_init(struct i2c_handle_s *hi2c,
+		   struct stm32_i2c_init_s *init_data);
+int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			uint16_t mem_addr, uint16_t mem_add_size,
+			uint8_t *p_data, uint16_t size, uint32_t timeout_ms);
+int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+		       uint16_t mem_addr, uint16_t mem_add_size,
+		       uint8_t *p_data, uint16_t size, uint32_t timeout_ms);
+int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			      uint8_t *p_data, uint16_t size,
+			      uint32_t timeout_ms);
+int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			     uint8_t *p_data, uint16_t size,
+			     uint32_t timeout_ms);
+bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr,
+			       uint32_t trials, uint32_t timeout_ms);
+
+#endif /* STM32_I2C_H */
diff --git a/include/drivers/st/stm32_sdmmc2.h b/include/drivers/st/stm32_sdmmc2.h
new file mode 100644
index 0000000..aa9472c
--- /dev/null
+++ b/include/drivers/st/stm32_sdmmc2.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_SDMMC2_H
+#define STM32_SDMMC2_H
+
+#include <stdbool.h>
+
+#include <drivers/mmc.h>
+
+struct stm32_sdmmc2_params {
+	uintptr_t		reg_base;
+	unsigned int		clk_rate;
+	unsigned int		bus_width;
+	unsigned int		flags;
+	struct mmc_device_info	*device_info;
+	unsigned int		pin_ckin;
+	unsigned int		negedge;
+	unsigned int		dirpol;
+	unsigned int		clock_id;
+	unsigned int		reset_id;
+	bool			use_dma;
+};
+
+unsigned long long stm32_sdmmc2_mmc_get_device_size(void);
+int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params);
+bool plat_sdmmc2_use_dma(unsigned int instance, unsigned int memory);
+
+#endif /* STM32_SDMMC2_H */
diff --git a/include/drivers/st/stm32_uart_regs.h b/include/drivers/st/stm32_uart_regs.h
new file mode 100644
index 0000000..14b296c
--- /dev/null
+++ b/include/drivers/st/stm32_uart_regs.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_UART_REGS_H
+#define STM32_UART_REGS_H
+
+#include <lib/utils_def.h>
+
+#define USART_CR1		U(0x00)
+#define USART_CR2		U(0x04)
+#define USART_CR3		U(0x08)
+#define USART_BRR		U(0x0C)
+#define USART_GTPR		U(0x10)
+#define USART_RTOR		U(0x14)
+#define USART_RQR		U(0x18)
+#define USART_ISR		U(0x1C)
+#define USART_ICR		U(0x20)
+#define USART_RDR		U(0x24)
+#define USART_TDR		U(0x28)
+#define USART_PRESC		U(0x2C)
+
+/* USART_CR1 register fields */
+#define USART_CR1_UE		BIT(0)
+#define USART_CR1_UESM		BIT(1)
+#define USART_CR1_RE		BIT(2)
+#define USART_CR1_TE		BIT(3)
+#define USART_CR1_IDLEIE	BIT(4)
+#define USART_CR1_RXNEIE	BIT(5)
+#define USART_CR1_TCIE		BIT(6)
+#define USART_CR1_TXEIE		BIT(7)
+#define USART_CR1_PEIE		BIT(8)
+#define USART_CR1_PS		BIT(9)
+#define USART_CR1_PCE		BIT(10)
+#define USART_CR1_WAKE		BIT(11)
+#define USART_CR1_M		(BIT(28) | BIT(12))
+#define USART_CR1_M0		BIT(12)
+#define USART_CR1_MME		BIT(13)
+#define USART_CR1_CMIE		BIT(14)
+#define USART_CR1_OVER8		BIT(15)
+#define USART_CR1_DEDT		GENMASK(20, 16)
+#define USART_CR1_DEDT_0	BIT(16)
+#define USART_CR1_DEDT_1	BIT(17)
+#define USART_CR1_DEDT_2	BIT(18)
+#define USART_CR1_DEDT_3	BIT(19)
+#define USART_CR1_DEDT_4	BIT(20)
+#define USART_CR1_DEAT		GENMASK(25, 21)
+#define USART_CR1_DEAT_0	BIT(21)
+#define USART_CR1_DEAT_1	BIT(22)
+#define USART_CR1_DEAT_2	BIT(23)
+#define USART_CR1_DEAT_3	BIT(24)
+#define USART_CR1_DEAT_4	BIT(25)
+#define USART_CR1_RTOIE		BIT(26)
+#define USART_CR1_EOBIE		BIT(27)
+#define USART_CR1_M1		BIT(28)
+#define USART_CR1_FIFOEN	BIT(29)
+#define USART_CR1_TXFEIE	BIT(30)
+#define USART_CR1_RXFFIE	BIT(31)
+
+/* USART_CR2 register fields */
+#define USART_CR2_SLVEN		BIT(0)
+#define USART_CR2_DIS_NSS	BIT(3)
+#define USART_CR2_ADDM7		BIT(4)
+#define USART_CR2_LBDL		BIT(5)
+#define USART_CR2_LBDIE		BIT(6)
+#define USART_CR2_LBCL		BIT(8)
+#define USART_CR2_CPHA		BIT(9)
+#define USART_CR2_CPOL		BIT(10)
+#define USART_CR2_CLKEN		BIT(11)
+#define USART_CR2_STOP		GENMASK(13, 12)
+#define USART_CR2_STOP_0	BIT(12)
+#define USART_CR2_STOP_1	BIT(13)
+#define USART_CR2_LINEN		BIT(14)
+#define USART_CR2_SWAP		BIT(15)
+#define USART_CR2_RXINV		BIT(16)
+#define USART_CR2_TXINV		BIT(17)
+#define USART_CR2_DATAINV	BIT(18)
+#define USART_CR2_MSBFIRST	BIT(19)
+#define USART_CR2_ABREN		BIT(20)
+#define USART_CR2_ABRMODE	GENMASK(22, 21)
+#define USART_CR2_ABRMODE_0	BIT(21)
+#define USART_CR2_ABRMODE_1	BIT(22)
+#define USART_CR2_RTOEN		BIT(23)
+#define USART_CR2_ADD		GENMASK(31, 24)
+
+/* USART_CR3 register fields */
+#define USART_CR3_EIE		BIT(0)
+#define USART_CR3_IREN		BIT(1)
+#define USART_CR3_IRLP		BIT(2)
+#define USART_CR3_HDSEL		BIT(3)
+#define USART_CR3_NACK		BIT(4)
+#define USART_CR3_SCEN		BIT(5)
+#define USART_CR3_DMAR		BIT(6)
+#define USART_CR3_DMAT		BIT(7)
+#define USART_CR3_RTSE		BIT(8)
+#define USART_CR3_CTSE		BIT(9)
+#define USART_CR3_CTSIE		BIT(10)
+#define USART_CR3_ONEBIT	BIT(11)
+#define USART_CR3_OVRDIS	BIT(12)
+#define USART_CR3_DDRE		BIT(13)
+#define USART_CR3_DEM		BIT(14)
+#define USART_CR3_DEP		BIT(15)
+#define USART_CR3_SCARCNT	GENMASK(19, 17)
+#define USART_CR3_SCARCNT_0	BIT(17)
+#define USART_CR3_SCARCNT_1	BIT(18)
+#define USART_CR3_SCARCNT_2	BIT(19)
+#define USART_CR3_WUS		GENMASK(21, 20)
+#define USART_CR3_WUS_0		BIT(20)
+#define USART_CR3_WUS_1		BIT(21)
+#define USART_CR3_WUFIE		BIT(22)
+#define USART_CR3_TXFTIE	BIT(23)
+#define USART_CR3_TCBGTIE	BIT(24)
+#define USART_CR3_RXFTCFG	GENMASK(27, 25)
+#define USART_CR3_RXFTCFG_0	BIT(25)
+#define USART_CR3_RXFTCFG_1	BIT(26)
+#define USART_CR3_RXFTCFG_2	BIT(27)
+#define USART_CR3_RXFTIE	BIT(28)
+#define USART_CR3_TXFTCFG	GENMASK(31, 29)
+#define USART_CR3_TXFTCFG_0	BIT(29)
+#define USART_CR3_TXFTCFG_1	BIT(30)
+#define USART_CR3_TXFTCFG_2	BIT(31)
+
+/* USART_BRR register fields */
+#define USART_BRR_DIV_FRACTION	GENMASK(3, 0)
+#define USART_BRR_DIV_MANTISSA	GENMASK(15, 4)
+
+/* USART_GTPR register fields */
+#define USART_GTPR_PSC		GENMASK(7, 0)
+#define USART_GTPR_GT		GENMASK(15, 8)
+
+/* USART_RTOR register fields */
+#define USART_RTOR_RTO		GENMASK(23, 0)
+#define USART_RTOR_BLEN		GENMASK(31, 24)
+
+/* USART_RQR register fields */
+#define USART_RQR_ABRRQ		BIT(0)
+#define USART_RQR_SBKRQ		BIT(1)
+#define USART_RQR_MMRQ		BIT(2)
+#define USART_RQR_RXFRQ		BIT(3)
+#define USART_RQR_TXFRQ		BIT(4)
+
+/* USART_ISR register fields */
+#define USART_ISR_PE		BIT(0)
+#define USART_ISR_FE		BIT(1)
+#define USART_ISR_NE		BIT(2)
+#define USART_ISR_ORE		BIT(3)
+#define USART_ISR_IDLE		BIT(4)
+#define USART_ISR_RXNE		BIT(5)
+#define USART_ISR_TC		BIT(6)
+#define USART_ISR_TXE		BIT(7)
+#define USART_ISR_LBDF		BIT(8)
+#define USART_ISR_CTSIF		BIT(9)
+#define USART_ISR_CTS		BIT(10)
+#define USART_ISR_RTOF		BIT(11)
+#define USART_ISR_EOBF		BIT(12)
+#define USART_ISR_UDR		BIT(13)
+#define USART_ISR_ABRE		BIT(14)
+#define USART_ISR_ABRF		BIT(15)
+#define USART_ISR_BUSY		BIT(16)
+#define USART_ISR_CMF		BIT(17)
+#define USART_ISR_SBKF		BIT(18)
+#define USART_ISR_RWU		BIT(19)
+#define USART_ISR_WUF		BIT(20)
+#define USART_ISR_TEACK		BIT(21)
+#define USART_ISR_REACK		BIT(22)
+#define USART_ISR_TXFE		BIT(23)
+#define USART_ISR_RXFF		BIT(24)
+#define USART_ISR_TCBGT		BIT(25)
+#define USART_ISR_RXFT		BIT(26)
+#define USART_ISR_TXFT		BIT(27)
+
+/* USART_ICR register fields */
+#define USART_ICR_PECF		BIT(0)
+#define USART_ICR_FECF		BIT(1)
+#define USART_ICR_NCF		BIT(2)
+#define USART_ICR_ORECF		BIT(3)
+#define USART_ICR_IDLECF	BIT(4)
+#define USART_ICR_TCCF		BIT(6)
+#define USART_ICR_TCBGT		BIT(7)
+#define USART_ICR_LBDCF		BIT(8)
+#define USART_ICR_CTSCF		BIT(9)
+#define USART_ICR_RTOCF		BIT(11)
+#define USART_ICR_EOBCF		BIT(12)
+#define USART_ICR_UDRCF		BIT(13)
+#define USART_ICR_CMCF		BIT(17)
+#define USART_ICR_WUCF		BIT(20)
+
+/* USART_RDR register fields */
+#define USART_RDR_RDR		GENMASK(8, 0)
+
+/* USART_TDR register fields */
+#define USART_TDR_TDR		GENMASK(8, 0)
+
+/* USART_PRESC register fields */
+#define USART_PRESC_PRESCALER	GENMASK(3, 0)
+
+#endif /* STM32_UART_REGS_H */
diff --git a/include/drivers/st/stm32mp1_clk.h b/include/drivers/st/stm32mp1_clk.h
new file mode 100644
index 0000000..1ebd39f
--- /dev/null
+++ b/include/drivers/st/stm32mp1_clk.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_CLK_H
+#define STM32MP1_CLK_H
+
+#include <arch_helpers.h>
+
+enum stm32mp_osc_id {
+	_HSI,
+	_HSE,
+	_CSI,
+	_LSI,
+	_LSE,
+	_I2S_CKIN,
+	NB_OSC,
+	_UNKNOWN_OSC_ID = 0xFF
+};
+
+extern const char *stm32mp_osc_node_label[NB_OSC];
+
+int stm32mp1_clk_probe(void);
+int stm32mp1_clk_init(void);
+
+bool stm32mp1_rcc_is_secure(void);
+bool stm32mp1_rcc_is_mckprot(void);
+
+void __stm32mp1_clk_enable(unsigned long id, bool caller_is_secure);
+void __stm32mp1_clk_disable(unsigned long id, bool caller_is_secure);
+
+static inline void stm32mp1_clk_enable_non_secure(unsigned long id)
+{
+	__stm32mp1_clk_enable(id, false);
+}
+
+static inline void stm32mp1_clk_enable_secure(unsigned long id)
+{
+	__stm32mp1_clk_enable(id, true);
+}
+
+static inline void stm32mp1_clk_disable_non_secure(unsigned long id)
+{
+	__stm32mp1_clk_disable(id, false);
+}
+
+static inline void stm32mp1_clk_disable_secure(unsigned long id)
+{
+	__stm32mp1_clk_disable(id, true);
+}
+
+unsigned int stm32mp1_clk_get_refcount(unsigned long id);
+
+/* SMP protection on RCC registers access */
+void stm32mp1_clk_rcc_regs_lock(void);
+void stm32mp1_clk_rcc_regs_unlock(void);
+
+void stm32mp1_stgen_increment(unsigned long long offset_in_ms);
+
+#endif /* STM32MP1_CLK_H */
diff --git a/include/drivers/st/stm32mp1_ddr.h b/include/drivers/st/stm32mp1_ddr.h
new file mode 100644
index 0000000..4ab37d6
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ddr.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32MP1_DDR_H
+#define STM32MP1_DDR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define DT_DDR_COMPAT	"st,stm32mp1-ddr"
+
+struct stm32mp1_ddr_size {
+	uint64_t base;
+	uint64_t size;
+};
+
+/**
+ * struct ddr_info
+ *
+ * @dev: pointer for the device
+ * @info: UCLASS RAM information
+ * @ctl: DDR controleur base address
+ * @phy: DDR PHY base address
+ * @syscfg: syscfg base address
+ */
+struct ddr_info {
+	struct stm32mp1_ddr_size info;
+	struct stm32mp1_ddrctl *ctl;
+	struct stm32mp1_ddrphy *phy;
+	uintptr_t pwr;
+	uintptr_t rcc;
+};
+
+struct stm32mp1_ddrctrl_reg {
+	uint32_t mstr;
+	uint32_t mrctrl0;
+	uint32_t mrctrl1;
+	uint32_t derateen;
+	uint32_t derateint;
+	uint32_t pwrctl;
+	uint32_t pwrtmg;
+	uint32_t hwlpctl;
+	uint32_t rfshctl0;
+	uint32_t rfshctl3;
+	uint32_t crcparctl0;
+	uint32_t zqctl0;
+	uint32_t dfitmg0;
+	uint32_t dfitmg1;
+	uint32_t dfilpcfg0;
+	uint32_t dfiupd0;
+	uint32_t dfiupd1;
+	uint32_t dfiupd2;
+	uint32_t dfiphymstr;
+	uint32_t odtmap;
+	uint32_t dbg0;
+	uint32_t dbg1;
+	uint32_t dbgcmd;
+	uint32_t poisoncfg;
+	uint32_t pccfg;
+};
+
+struct stm32mp1_ddrctrl_timing {
+	uint32_t rfshtmg;
+	uint32_t dramtmg0;
+	uint32_t dramtmg1;
+	uint32_t dramtmg2;
+	uint32_t dramtmg3;
+	uint32_t dramtmg4;
+	uint32_t dramtmg5;
+	uint32_t dramtmg6;
+	uint32_t dramtmg7;
+	uint32_t dramtmg8;
+	uint32_t dramtmg14;
+	uint32_t odtcfg;
+};
+
+struct stm32mp1_ddrctrl_map {
+	uint32_t addrmap1;
+	uint32_t addrmap2;
+	uint32_t addrmap3;
+	uint32_t addrmap4;
+	uint32_t addrmap5;
+	uint32_t addrmap6;
+	uint32_t addrmap9;
+	uint32_t addrmap10;
+	uint32_t addrmap11;
+};
+
+struct stm32mp1_ddrctrl_perf {
+	uint32_t sched;
+	uint32_t sched1;
+	uint32_t perfhpr1;
+	uint32_t perflpr1;
+	uint32_t perfwr1;
+	uint32_t pcfgr_0;
+	uint32_t pcfgw_0;
+	uint32_t pcfgqos0_0;
+	uint32_t pcfgqos1_0;
+	uint32_t pcfgwqos0_0;
+	uint32_t pcfgwqos1_0;
+	uint32_t pcfgr_1;
+	uint32_t pcfgw_1;
+	uint32_t pcfgqos0_1;
+	uint32_t pcfgqos1_1;
+	uint32_t pcfgwqos0_1;
+	uint32_t pcfgwqos1_1;
+};
+
+struct stm32mp1_ddrphy_reg {
+	uint32_t pgcr;
+	uint32_t aciocr;
+	uint32_t dxccr;
+	uint32_t dsgcr;
+	uint32_t dcr;
+	uint32_t odtcr;
+	uint32_t zq0cr1;
+	uint32_t dx0gcr;
+	uint32_t dx1gcr;
+	uint32_t dx2gcr;
+	uint32_t dx3gcr;
+};
+
+struct stm32mp1_ddrphy_timing {
+	uint32_t ptr0;
+	uint32_t ptr1;
+	uint32_t ptr2;
+	uint32_t dtpr0;
+	uint32_t dtpr1;
+	uint32_t dtpr2;
+	uint32_t mr0;
+	uint32_t mr1;
+	uint32_t mr2;
+	uint32_t mr3;
+};
+
+struct stm32mp1_ddrphy_cal {
+	uint32_t dx0dllcr;
+	uint32_t dx0dqtr;
+	uint32_t dx0dqstr;
+	uint32_t dx1dllcr;
+	uint32_t dx1dqtr;
+	uint32_t dx1dqstr;
+	uint32_t dx2dllcr;
+	uint32_t dx2dqtr;
+	uint32_t dx2dqstr;
+	uint32_t dx3dllcr;
+	uint32_t dx3dqtr;
+	uint32_t dx3dqstr;
+};
+
+struct stm32mp1_ddr_info {
+	const char *name;
+	uint32_t speed; /* in kHZ */
+	uint32_t size;  /* Memory size in byte = col * row * width */
+};
+
+struct stm32mp1_ddr_config {
+	struct stm32mp1_ddr_info info;
+	struct stm32mp1_ddrctrl_reg c_reg;
+	struct stm32mp1_ddrctrl_timing c_timing;
+	struct stm32mp1_ddrctrl_map c_map;
+	struct stm32mp1_ddrctrl_perf c_perf;
+	struct stm32mp1_ddrphy_reg p_reg;
+	struct stm32mp1_ddrphy_timing p_timing;
+	struct stm32mp1_ddrphy_cal p_cal;
+};
+
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed);
+void stm32mp1_ddr_init(struct ddr_info *priv,
+		       struct stm32mp1_ddr_config *config);
+#endif /* STM32MP1_DDR_H */
diff --git a/include/drivers/st/stm32mp1_ddr_helpers.h b/include/drivers/st/stm32mp1_ddr_helpers.h
new file mode 100644
index 0000000..38f2415
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ddr_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_DDR_HELPERS_H
+#define STM32MP1_DDR_HELPERS_H
+
+void ddr_enable_clock(void);
+
+#endif /* STM32MP1_DDR_HELPERS_H */
diff --git a/include/drivers/st/stm32mp1_ddr_regs.h b/include/drivers/st/stm32mp1_ddr_regs.h
new file mode 100644
index 0000000..342239a
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ddr_regs.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+ */
+
+#ifndef STM32MP1_DDR_REGS_H
+#define STM32MP1_DDR_REGS_H
+
+#include <lib/utils_def.h>
+
+/* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */
+struct stm32mp1_ddrctl {
+	uint32_t mstr ;		/* 0x0 Master */
+	uint32_t stat;		/* 0x4 Operating Mode Status */
+	uint8_t reserved008[0x10 - 0x8];
+	uint32_t mrctrl0;	/* 0x10 Control 0 */
+	uint32_t mrctrl1;	/* 0x14 Control 1 */
+	uint32_t mrstat;	/* 0x18 Status */
+	uint32_t reserved01c;	/* 0x1c */
+	uint32_t derateen;	/* 0x20 Temperature Derate Enable */
+	uint32_t derateint;	/* 0x24 Temperature Derate Interval */
+	uint8_t reserved028[0x30 - 0x28];
+	uint32_t pwrctl;	/* 0x30 Low Power Control */
+	uint32_t pwrtmg;	/* 0x34 Low Power Timing */
+	uint32_t hwlpctl;	/* 0x38 Hardware Low Power Control */
+	uint8_t reserved03c[0x50 - 0x3C];
+	uint32_t rfshctl0;	/* 0x50 Refresh Control 0 */
+	uint32_t reserved054;	/* 0x54 Refresh Control 1 */
+	uint32_t reserved058;	/* 0x58 Refresh Control 2 */
+	uint32_t reserved05C;
+	uint32_t rfshctl3;	/* 0x60 Refresh Control 0 */
+	uint32_t rfshtmg;	/* 0x64 Refresh Timing */
+	uint8_t reserved068[0xc0 - 0x68];
+	uint32_t crcparctl0;		/* 0xc0 CRC Parity Control0 */
+	uint32_t reserved0c4;	/* 0xc4 CRC Parity Control1 */
+	uint32_t reserved0c8;	/* 0xc8 CRC Parity Control2 */
+	uint32_t crcparstat;		/* 0xcc CRC Parity Status */
+	uint32_t init0;		/* 0xd0 SDRAM Initialization 0 */
+	uint32_t init1;		/* 0xd4 SDRAM Initialization 1 */
+	uint32_t init2;		/* 0xd8 SDRAM Initialization 2 */
+	uint32_t init3;		/* 0xdc SDRAM Initialization 3 */
+	uint32_t init4;		/* 0xe0 SDRAM Initialization 4 */
+	uint32_t init5;		/* 0xe4 SDRAM Initialization 5 */
+	uint32_t reserved0e8;
+	uint32_t reserved0ec;
+	uint32_t dimmctl;	/* 0xf0 DIMM Control */
+	uint8_t reserved0f4[0x100 - 0xf4];
+	uint32_t dramtmg0;	/* 0x100 SDRAM Timing 0 */
+	uint32_t dramtmg1;	/* 0x104 SDRAM Timing 1 */
+	uint32_t dramtmg2;	/* 0x108 SDRAM Timing 2 */
+	uint32_t dramtmg3;	/* 0x10c SDRAM Timing 3 */
+	uint32_t dramtmg4;	/* 0x110 SDRAM Timing 4 */
+	uint32_t dramtmg5;	/* 0x114 SDRAM Timing 5 */
+	uint32_t dramtmg6;	/* 0x118 SDRAM Timing 6 */
+	uint32_t dramtmg7;	/* 0x11c SDRAM Timing 7 */
+	uint32_t dramtmg8;	/* 0x120 SDRAM Timing 8 */
+	uint8_t reserved124[0x138 - 0x124];
+	uint32_t dramtmg14;	/* 0x138 SDRAM Timing 14 */
+	uint32_t dramtmg15;	/* 0x13C SDRAM Timing 15 */
+	uint8_t reserved140[0x180 - 0x140];
+	uint32_t zqctl0;	/* 0x180 ZQ Control 0 */
+	uint32_t zqctl1;	/* 0x184 ZQ Control 1 */
+	uint32_t zqctl2;	/* 0x188 ZQ Control 2 */
+	uint32_t zqstat;	/* 0x18c ZQ Status */
+	uint32_t dfitmg0;	/* 0x190 DFI Timing 0 */
+	uint32_t dfitmg1;	/* 0x194 DFI Timing 1 */
+	uint32_t dfilpcfg0;	/* 0x198 DFI Low Power Configuration 0 */
+	uint32_t reserved19c;
+	uint32_t dfiupd0;	/* 0x1a0 DFI Update 0 */
+	uint32_t dfiupd1;	/* 0x1a4 DFI Update 1 */
+	uint32_t dfiupd2;	/* 0x1a8 DFI Update 2 */
+	uint32_t reserved1ac;
+	uint32_t dfimisc;	/* 0x1b0 DFI Miscellaneous Control */
+	uint8_t reserved1b4[0x1bc - 0x1b4];
+	uint32_t dfistat;	/* 0x1bc DFI Miscellaneous Control */
+	uint8_t reserved1c0[0x1c4 - 0x1c0];
+	uint32_t dfiphymstr;	/* 0x1c4 DFI PHY Master interface */
+	uint8_t reserved1c8[0x204 - 0x1c8];
+	uint32_t addrmap1;	/* 0x204 Address Map 1 */
+	uint32_t addrmap2;	/* 0x208 Address Map 2 */
+	uint32_t addrmap3;	/* 0x20c Address Map 3 */
+	uint32_t addrmap4;	/* 0x210 Address Map 4 */
+	uint32_t addrmap5;	/* 0x214 Address Map 5 */
+	uint32_t addrmap6;	/* 0x218 Address Map 6 */
+	uint8_t reserved21c[0x224 - 0x21c];
+	uint32_t addrmap9;	/* 0x224 Address Map 9 */
+	uint32_t addrmap10;	/* 0x228 Address Map 10 */
+	uint32_t addrmap11;	/* 0x22C Address Map 11 */
+	uint8_t reserved230[0x240 - 0x230];
+	uint32_t odtcfg;	/* 0x240 ODT Configuration */
+	uint32_t odtmap;	/* 0x244 ODT/Rank Map */
+	uint8_t reserved248[0x250 - 0x248];
+	uint32_t sched;		/* 0x250 Scheduler Control */
+	uint32_t sched1;	/* 0x254 Scheduler Control 1 */
+	uint32_t reserved258;
+	uint32_t perfhpr1;	/* 0x25c High Priority Read CAM 1 */
+	uint32_t reserved260;
+	uint32_t perflpr1;	/* 0x264 Low Priority Read CAM 1 */
+	uint32_t reserved268;
+	uint32_t perfwr1;	/* 0x26c Write CAM 1 */
+	uint8_t reserved27c[0x300 - 0x270];
+	uint32_t dbg0;		/* 0x300 Debug 0 */
+	uint32_t dbg1;		/* 0x304 Debug 1 */
+	uint32_t dbgcam;	/* 0x308 CAM Debug */
+	uint32_t dbgcmd;	/* 0x30c Command Debug */
+	uint32_t dbgstat;	/* 0x310 Status Debug */
+	uint8_t reserved314[0x320 - 0x314];
+	uint32_t swctl;		/* 0x320 Software Programming Control Enable */
+	uint32_t swstat;	/* 0x324 Software Programming Control Status */
+	uint8_t reserved328[0x36c - 0x328];
+	uint32_t poisoncfg;	/* 0x36c AXI Poison Configuration Register */
+	uint32_t poisonstat;	/* 0x370 AXI Poison Status Register */
+	uint8_t reserved374[0x3fc - 0x374];
+
+	/* Multi Port registers */
+	uint32_t pstat;		/* 0x3fc Port Status */
+	uint32_t pccfg;		/* 0x400 Port Common Configuration */
+
+	/* PORT 0 */
+	uint32_t pcfgr_0;	/* 0x404 Configuration Read */
+	uint32_t pcfgw_0;	/* 0x408 Configuration Write */
+	uint8_t reserved40c[0x490 - 0x40c];
+	uint32_t pctrl_0;	/* 0x490 Port Control Register */
+	uint32_t pcfgqos0_0;	/* 0x494 Read QoS Configuration 0 */
+	uint32_t pcfgqos1_0;	/* 0x498 Read QoS Configuration 1 */
+	uint32_t pcfgwqos0_0;	/* 0x49c Write QoS Configuration 0 */
+	uint32_t pcfgwqos1_0;	/* 0x4a0 Write QoS Configuration 1 */
+	uint8_t reserved4a4[0x4b4 - 0x4a4];
+
+	/* PORT 1 */
+	uint32_t pcfgr_1;	/* 0x4b4 Configuration Read */
+	uint32_t pcfgw_1;	/* 0x4b8 Configuration Write */
+	uint8_t reserved4bc[0x540 - 0x4bc];
+	uint32_t pctrl_1;	/* 0x540 Port 2 Control Register */
+	uint32_t pcfgqos0_1;	/* 0x544 Read QoS Configuration 0 */
+	uint32_t pcfgqos1_1;	/* 0x548 Read QoS Configuration 1 */
+	uint32_t pcfgwqos0_1;	/* 0x54c Write QoS Configuration 0 */
+	uint32_t pcfgwqos1_1;	/* 0x550 Write QoS Configuration 1 */
+} __packed;
+
+/* DDR Physical Interface Control (DDRPHYC) registers*/
+struct stm32mp1_ddrphy {
+	uint32_t ridr;		/* 0x00 R Revision Identification */
+	uint32_t pir;		/* 0x04 R/W PHY Initialization */
+	uint32_t pgcr;		/* 0x08 R/W PHY General Configuration */
+	uint32_t pgsr;		/* 0x0C PHY General Status */
+	uint32_t dllgcr;	/* 0x10 R/W DLL General Control */
+	uint32_t acdllcr;	/* 0x14 R/W AC DLL Control */
+	uint32_t ptr0;		/* 0x18 R/W PHY Timing 0 */
+	uint32_t ptr1;		/* 0x1C R/W PHY Timing 1 */
+	uint32_t ptr2;		/* 0x20 R/W PHY Timing 2 */
+	uint32_t aciocr;	/* 0x24 AC I/O Configuration */
+	uint32_t dxccr;		/* 0x28 DATX8 Common Configuration */
+	uint32_t dsgcr;		/* 0x2C DDR System General Configuration */
+	uint32_t dcr;		/* 0x30 DRAM Configuration */
+	uint32_t dtpr0;		/* 0x34 DRAM Timing Parameters0 */
+	uint32_t dtpr1;		/* 0x38 DRAM Timing Parameters1 */
+	uint32_t dtpr2;		/* 0x3C DRAM Timing Parameters2 */
+	uint32_t mr0;		/* 0x40 Mode 0 */
+	uint32_t mr1;		/* 0x44 Mode 1 */
+	uint32_t mr2;		/* 0x48 Mode 2 */
+	uint32_t mr3;		/* 0x4C Mode 3 */
+	uint32_t odtcr;		/* 0x50 ODT Configuration */
+	uint32_t dtar;		/* 0x54 data training address */
+	uint32_t dtdr0;		/* 0x58 */
+	uint32_t dtdr1;		/* 0x5c */
+	uint8_t res1[0x0c0 - 0x060];	/* 0x60 */
+	uint32_t dcuar;		/* 0xc0 Address */
+	uint32_t dcudr;		/* 0xc4 DCU Data */
+	uint32_t dcurr;		/* 0xc8 DCU Run */
+	uint32_t dculr;		/* 0xcc DCU Loop */
+	uint32_t dcugcr;	/* 0xd0 DCU General Configuration */
+	uint32_t dcutpr;	/* 0xd4 DCU Timing Parameters */
+	uint32_t dcusr0;	/* 0xd8 DCU Status 0 */
+	uint32_t dcusr1;	/* 0xdc DCU Status 1 */
+	uint8_t res2[0x100 - 0xe0];	/* 0xe0 */
+	uint32_t bistrr;	/* 0x100 BIST Run */
+	uint32_t bistmskr0;	/* 0x104 BIST Mask 0 */
+	uint32_t bistmskr1;	/* 0x108 BIST Mask 0 */
+	uint32_t bistwcr;	/* 0x10c BIST Word Count */
+	uint32_t bistlsr;	/* 0x110 BIST LFSR Seed */
+	uint32_t bistar0;	/* 0x114 BIST Address 0 */
+	uint32_t bistar1;	/* 0x118 BIST Address 1 */
+	uint32_t bistar2;	/* 0x11c BIST Address 2 */
+	uint32_t bistupdr;	/* 0x120 BIST User Data Pattern */
+	uint32_t bistgsr;	/* 0x124 BIST General Status */
+	uint32_t bistwer;	/* 0x128 BIST Word Error */
+	uint32_t bistber0;	/* 0x12c BIST Bit Error 0 */
+	uint32_t bistber1;	/* 0x130 BIST Bit Error 1 */
+	uint32_t bistber2;	/* 0x134 BIST Bit Error 2 */
+	uint32_t bistwcsr;	/* 0x138 BIST Word Count Status */
+	uint32_t bistfwr0;	/* 0x13c BIST Fail Word 0 */
+	uint32_t bistfwr1;	/* 0x140 BIST Fail Word 1 */
+	uint8_t res3[0x178 - 0x144];	/* 0x144 */
+	uint32_t gpr0;		/* 0x178 General Purpose 0 (GPR0) */
+	uint32_t gpr1;		/* 0x17C General Purpose 1 (GPR1) */
+	uint32_t zq0cr0;	/* 0x180 zq 0 control 0 */
+	uint32_t zq0cr1;	/* 0x184 zq 0 control 1 */
+	uint32_t zq0sr0;	/* 0x188 zq 0 status 0 */
+	uint32_t zq0sr1;	/* 0x18C zq 0 status 1 */
+	uint8_t res4[0x1C0 - 0x190];	/* 0x190 */
+	uint32_t dx0gcr;	/* 0x1c0 Byte lane 0 General Configuration */
+	uint32_t dx0gsr0;	/* 0x1c4 Byte lane 0 General Status 0 */
+	uint32_t dx0gsr1;	/* 0x1c8 Byte lane 0 General Status 1 */
+	uint32_t dx0dllcr;	/* 0x1cc Byte lane 0 DLL Control */
+	uint32_t dx0dqtr;	/* 0x1d0 Byte lane 0 DQ Timing */
+	uint32_t dx0dqstr;	/* 0x1d4 Byte lane 0 DQS Timing */
+	uint8_t res5[0x200 - 0x1d8];	/* 0x1d8 */
+	uint32_t dx1gcr;	/* 0x200 Byte lane 1 General Configuration */
+	uint32_t dx1gsr0;	/* 0x204 Byte lane 1 General Status 0 */
+	uint32_t dx1gsr1;	/* 0x208 Byte lane 1 General Status 1 */
+	uint32_t dx1dllcr;	/* 0x20c Byte lane 1 DLL Control */
+	uint32_t dx1dqtr;	/* 0x210 Byte lane 1 DQ Timing */
+	uint32_t dx1dqstr;	/* 0x214 Byte lane 1 QS Timing */
+	uint8_t res6[0x240 - 0x218];	/* 0x218 */
+	uint32_t dx2gcr;	/* 0x240 Byte lane 2 General Configuration */
+	uint32_t dx2gsr0;	/* 0x244 Byte lane 2 General Status 0 */
+	uint32_t dx2gsr1;	/* 0x248 Byte lane 2 General Status 1 */
+	uint32_t dx2dllcr;	/* 0x24c Byte lane 2 DLL Control */
+	uint32_t dx2dqtr;	/* 0x250 Byte lane 2 DQ Timing */
+	uint32_t dx2dqstr;	/* 0x254 Byte lane 2 QS Timing */
+	uint8_t res7[0x280 - 0x258];	/* 0x258 */
+	uint32_t dx3gcr;	/* 0x280 Byte lane 3 General Configuration */
+	uint32_t dx3gsr0;	/* 0x284 Byte lane 3 General Status 0 */
+	uint32_t dx3gsr1;	/* 0x288 Byte lane 3 General Status 1 */
+	uint32_t dx3dllcr;	/* 0x28c Byte lane 3 DLL Control */
+	uint32_t dx3dqtr;	/* 0x290 Byte lane 3 DQ Timing */
+	uint32_t dx3dqstr;	/* 0x294 Byte lane 3 QS Timing */
+} __packed;
+
+/* DDR Controller registers offsets */
+#define DDRCTRL_MSTR				0x000
+#define DDRCTRL_STAT				0x004
+#define DDRCTRL_MRCTRL0				0x010
+#define DDRCTRL_MRSTAT				0x018
+#define DDRCTRL_PWRCTL				0x030
+#define DDRCTRL_PWRTMG				0x034
+#define DDRCTRL_HWLPCTL				0x038
+#define DDRCTRL_RFSHCTL3			0x060
+#define DDRCTRL_RFSHTMG				0x064
+#define DDRCTRL_INIT0				0x0D0
+#define DDRCTRL_DFIMISC				0x1B0
+#define DDRCTRL_DBG1				0x304
+#define DDRCTRL_DBGCAM				0x308
+#define DDRCTRL_DBGCMD				0x30C
+#define DDRCTRL_DBGSTAT				0x310
+#define DDRCTRL_SWCTL				0x320
+#define DDRCTRL_SWSTAT				0x324
+#define DDRCTRL_PSTAT				0x3FC
+#define DDRCTRL_PCTRL_0				0x490
+#define DDRCTRL_PCTRL_1				0x540
+
+/* DDR Controller Register fields */
+#define DDRCTRL_MSTR_DDR3			BIT(0)
+#define DDRCTRL_MSTR_LPDDR2			BIT(2)
+#define DDRCTRL_MSTR_LPDDR3			BIT(3)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK	GENMASK(13, 12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL	0
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF	BIT(12)
+#define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER	BIT(13)
+#define DDRCTRL_MSTR_DLL_OFF_MODE		BIT(15)
+
+#define DDRCTRL_STAT_OPERATING_MODE_MASK	GENMASK(2, 0)
+#define DDRCTRL_STAT_OPERATING_MODE_NORMAL	BIT(0)
+#define DDRCTRL_STAT_OPERATING_MODE_SR		(BIT(0) | BIT(1))
+#define DDRCTRL_STAT_SELFREF_TYPE_MASK		GENMASK(5, 4)
+#define DDRCTRL_STAT_SELFREF_TYPE_ASR		(BIT(4) | BIT(5))
+#define DDRCTRL_STAT_SELFREF_TYPE_SR		BIT(5)
+
+#define DDRCTRL_MRCTRL0_MR_TYPE_WRITE		U(0)
+/* Only one rank supported */
+#define DDRCTRL_MRCTRL0_MR_RANK_SHIFT		4
+#define DDRCTRL_MRCTRL0_MR_RANK_ALL \
+					BIT(DDRCTRL_MRCTRL0_MR_RANK_SHIFT)
+#define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT		12
+#define DDRCTRL_MRCTRL0_MR_ADDR_MASK		GENMASK(15, 12)
+#define DDRCTRL_MRCTRL0_MR_WR			BIT(31)
+
+#define DDRCTRL_MRSTAT_MR_WR_BUSY		BIT(0)
+
+#define DDRCTRL_PWRCTL_SELFREF_EN		BIT(0)
+#define DDRCTRL_PWRCTL_POWERDOWN_EN		BIT(1)
+#define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE	BIT(3)
+#define DDRCTRL_PWRCTL_SELFREF_SW		BIT(5)
+
+#define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK	GENMASK(19, 12)
+#define DDRCTRL_PWRTMG_SELFREF_TO_X32_0		BIT(16)
+
+#define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH	BIT(0)
+
+#define DDRCTRL_HWLPCTL_HW_LP_EN		BIT(0)
+
+#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK	GENMASK(27, 16)
+#define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT	16
+
+#define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK	GENMASK(31, 30)
+#define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL	BIT(30)
+
+#define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN	BIT(0)
+
+#define DDRCTRL_DBG1_DIS_HIF			BIT(1)
+
+#define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY	BIT(29)
+#define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY	BIT(28)
+#define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY		BIT(26)
+#define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH		GENMASK(12, 8)
+#define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH		GENMASK(4, 0)
+#define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \
+		(DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \
+		 DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY)
+#define DDRCTRL_DBGCAM_DBG_Q_DEPTH \
+		(DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \
+		 DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \
+		 DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH)
+
+#define DDRCTRL_DBGCMD_RANK0_REFRESH		BIT(0)
+
+#define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY	BIT(0)
+
+#define DDRCTRL_SWCTL_SW_DONE			BIT(0)
+
+#define DDRCTRL_SWSTAT_SW_DONE_ACK		BIT(0)
+
+#define DDRCTRL_PCTRL_N_PORT_EN			BIT(0)
+
+/* DDR PHY registers offsets */
+#define DDRPHYC_PIR				0x004
+#define DDRPHYC_PGCR				0x008
+#define DDRPHYC_PGSR				0x00C
+#define DDRPHYC_DLLGCR				0x010
+#define DDRPHYC_ACDLLCR				0x014
+#define DDRPHYC_PTR0				0x018
+#define DDRPHYC_ACIOCR				0x024
+#define DDRPHYC_DXCCR				0x028
+#define DDRPHYC_DSGCR				0x02C
+#define DDRPHYC_ZQ0CR0				0x180
+#define DDRPHYC_DX0GCR				0x1C0
+#define DDRPHYC_DX0DLLCR			0x1CC
+#define DDRPHYC_DX1GCR				0x200
+#define DDRPHYC_DX1DLLCR			0x20C
+#define DDRPHYC_DX2GCR				0x240
+#define DDRPHYC_DX2DLLCR			0x24C
+#define DDRPHYC_DX3GCR				0x280
+#define DDRPHYC_DX3DLLCR			0x28C
+
+/* DDR PHY Register fields */
+#define DDRPHYC_PIR_INIT			BIT(0)
+#define DDRPHYC_PIR_DLLSRST			BIT(1)
+#define DDRPHYC_PIR_DLLLOCK			BIT(2)
+#define DDRPHYC_PIR_ZCAL			BIT(3)
+#define DDRPHYC_PIR_ITMSRST			BIT(4)
+#define DDRPHYC_PIR_DRAMRST			BIT(5)
+#define DDRPHYC_PIR_DRAMINIT			BIT(6)
+#define DDRPHYC_PIR_QSTRN			BIT(7)
+#define DDRPHYC_PIR_ICPC			BIT(16)
+#define DDRPHYC_PIR_ZCALBYP			BIT(30)
+#define DDRPHYC_PIR_INITSTEPS_MASK		GENMASK(31, 7)
+
+#define DDRPHYC_PGCR_DFTCMP			BIT(2)
+#define DDRPHYC_PGCR_PDDISDX			BIT(24)
+#define DDRPHYC_PGCR_RFSHDT_MASK		GENMASK(28, 25)
+
+#define DDRPHYC_PGSR_IDONE			BIT(0)
+#define DDRPHYC_PGSR_DTERR			BIT(5)
+#define DDRPHYC_PGSR_DTIERR			BIT(6)
+#define DDRPHYC_PGSR_DFTERR			BIT(7)
+#define DDRPHYC_PGSR_RVERR			BIT(8)
+#define DDRPHYC_PGSR_RVEIRR			BIT(9)
+
+#define DDRPHYC_DLLGCR_BPS200			BIT(23)
+
+#define DDRPHYC_ACDLLCR_DLLSRST			BIT(30)
+#define DDRPHYC_ACDLLCR_DLLDIS			BIT(31)
+
+#define DDRPHYC_PTR0_TDLLSRST_OFFSET		0
+#define DDRPHYC_PTR0_TDLLSRST_MASK		GENMASK(5, 0)
+#define DDRPHYC_PTR0_TDLLLOCK_OFFSET		6
+#define DDRPHYC_PTR0_TDLLLOCK_MASK		GENMASK(17, 6)
+#define DDRPHYC_PTR0_TITMSRST_OFFSET		18
+#define DDRPHYC_PTR0_TITMSRST_MASK		GENMASK(21, 18)
+
+#define DDRPHYC_ACIOCR_ACPDD			BIT(3)
+#define DDRPHYC_ACIOCR_ACPDR			BIT(4)
+#define DDRPHYC_ACIOCR_CKPDD_MASK		GENMASK(10, 8)
+#define DDRPHYC_ACIOCR_CKPDD_0			BIT(8)
+#define DDRPHYC_ACIOCR_CKPDR_MASK		GENMASK(13, 11)
+#define DDRPHYC_ACIOCR_CKPDR_0			BIT(11)
+#define DDRPHYC_ACIOCR_CSPDD_MASK		GENMASK(21, 18)
+#define DDRPHYC_ACIOCR_CSPDD_0			BIT(18)
+#define DDRPHYC_ACIOCR_RSTPDD			BIT(27)
+#define DDRPHYC_ACIOCR_RSTPDR			BIT(28)
+
+#define DDRPHYC_DXCCR_DXPDD			BIT(2)
+#define DDRPHYC_DXCCR_DXPDR			BIT(3)
+
+#define DDRPHYC_DSGCR_CKEPDD_MASK		GENMASK(19, 16)
+#define DDRPHYC_DSGCR_CKEPDD_0			BIT(16)
+#define DDRPHYC_DSGCR_ODTPDD_MASK		GENMASK(23, 20)
+#define DDRPHYC_DSGCR_ODTPDD_0			BIT(20)
+#define DDRPHYC_DSGCR_NL2PD			BIT(24)
+
+#define DDRPHYC_ZQ0CRN_ZDATA_MASK		GENMASK(27, 0)
+#define DDRPHYC_ZQ0CRN_ZDATA_SHIFT		0
+#define DDRPHYC_ZQ0CRN_ZDEN			BIT(28)
+#define DDRPHYC_ZQ0CRN_ZQPD			BIT(31)
+
+#define DDRPHYC_DXNGCR_DXEN			BIT(0)
+
+#define DDRPHYC_DXNDLLCR_DLLSRST		BIT(30)
+#define DDRPHYC_DXNDLLCR_DLLDIS			BIT(31)
+#define DDRPHYC_DXNDLLCR_SDPHASE_MASK		GENMASK(17, 14)
+#define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT		14
+
+#endif /* STM32MP1_DDR_REGS_H */
diff --git a/include/drivers/st/stm32mp1_pwr.h b/include/drivers/st/stm32mp1_pwr.h
new file mode 100644
index 0000000..e17df44
--- /dev/null
+++ b/include/drivers/st/stm32mp1_pwr.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_PWR_H
+#define STM32MP1_PWR_H
+
+#include <lib/utils_def.h>
+
+#define PWR_CR1			U(0x00)
+#define PWR_CR2			U(0x08)
+#define PWR_CR3			U(0x0C)
+#define PWR_MPUCR		U(0x10)
+#define PWR_WKUPCR		U(0x20)
+#define PWR_MPUWKUPENR		U(0x28)
+
+#define PWR_CR1_LPDS		BIT(0)
+#define PWR_CR1_LPCFG		BIT(1)
+#define PWR_CR1_LVDS		BIT(2)
+#define PWR_CR1_DBP		BIT(8)
+
+#define PWR_CR3_DDRSREN		BIT(10)
+#define PWR_CR3_DDRSRDIS	BIT(11)
+#define PWR_CR3_DDRRETEN	BIT(12)
+
+#define PWR_MPUCR_PDDS		BIT(0)
+#define PWR_MPUCR_CSTDBYDIS	BIT(3)
+#define PWR_MPUCR_CSSF		BIT(9)
+
+#endif /* STM32MP1_PWR_H */
diff --git a/include/drivers/st/stm32mp1_ram.h b/include/drivers/st/stm32mp1_ram.h
new file mode 100644
index 0000000..38360e7
--- /dev/null
+++ b/include/drivers/st/stm32mp1_ram.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_RAM_H
+#define STM32MP1_RAM_H
+
+int stm32mp1_ddr_probe(void);
+
+#endif /* STM32MP1_RAM_H */
diff --git a/include/drivers/st/stm32mp1_rcc.h b/include/drivers/st/stm32mp1_rcc.h
new file mode 100644
index 0000000..4b4aac8
--- /dev/null
+++ b/include/drivers/st/stm32mp1_rcc.h
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP1_RCC_H
+#define STM32MP1_RCC_H
+
+#include <lib/utils_def.h>
+
+#define RCC_TZCR			U(0x00)
+#define RCC_OCENSETR			U(0x0C)
+#define RCC_OCENCLRR			U(0x10)
+#define RCC_HSICFGR			U(0x18)
+#define RCC_CSICFGR			U(0x1C)
+#define RCC_MPCKSELR			U(0x20)
+#define RCC_ASSCKSELR			U(0x24)
+#define RCC_RCK12SELR			U(0x28)
+#define RCC_MPCKDIVR			U(0x2C)
+#define RCC_AXIDIVR			U(0x30)
+#define RCC_APB4DIVR			U(0x3C)
+#define RCC_APB5DIVR			U(0x40)
+#define RCC_RTCDIVR			U(0x44)
+#define RCC_MSSCKSELR			U(0x48)
+#define RCC_PLL1CR			U(0x80)
+#define RCC_PLL1CFGR1			U(0x84)
+#define RCC_PLL1CFGR2			U(0x88)
+#define RCC_PLL1FRACR			U(0x8C)
+#define RCC_PLL1CSGR			U(0x90)
+#define RCC_PLL2CR			U(0x94)
+#define RCC_PLL2CFGR1			U(0x98)
+#define RCC_PLL2CFGR2			U(0x9C)
+#define RCC_PLL2FRACR			U(0xA0)
+#define RCC_PLL2CSGR			U(0xA4)
+#define RCC_I2C46CKSELR			U(0xC0)
+#define RCC_SPI6CKSELR			U(0xC4)
+#define RCC_UART1CKSELR			U(0xC8)
+#define RCC_RNG1CKSELR			U(0xCC)
+#define RCC_CPERCKSELR			U(0xD0)
+#define RCC_STGENCKSELR			U(0xD4)
+#define RCC_DDRITFCR			U(0xD8)
+#define RCC_MP_BOOTCR			U(0x100)
+#define RCC_MP_SREQSETR			U(0x104)
+#define RCC_MP_SREQCLRR			U(0x108)
+#define RCC_MP_GCR			U(0x10C)
+#define RCC_MP_APRSTCR			U(0x110)
+#define RCC_MP_APRSTSR			U(0x114)
+#define RCC_BDCR			U(0x140)
+#define RCC_RDLSICR			U(0x144)
+#define RCC_APB4RSTSETR			U(0x180)
+#define RCC_APB4RSTCLRR			U(0x184)
+#define RCC_APB5RSTSETR			U(0x188)
+#define RCC_APB5RSTCLRR			U(0x18C)
+#define RCC_AHB5RSTSETR			U(0x190)
+#define RCC_AHB5RSTCLRR			U(0x194)
+#define RCC_AHB6RSTSETR			U(0x198)
+#define RCC_AHB6RSTCLRR			U(0x19C)
+#define RCC_TZAHB6RSTSETR		U(0x1A0)
+#define RCC_TZAHB6RSTCLRR		U(0x1A4)
+#define RCC_MP_APB4ENSETR		U(0x200)
+#define RCC_MP_APB4ENCLRR		U(0x204)
+#define RCC_MP_APB5ENSETR		U(0x208)
+#define RCC_MP_APB5ENCLRR		U(0x20C)
+#define RCC_MP_AHB5ENSETR		U(0x210)
+#define RCC_MP_AHB5ENCLRR		U(0x214)
+#define RCC_MP_AHB6ENSETR		U(0x218)
+#define RCC_MP_AHB6ENCLRR		U(0x21C)
+#define RCC_MP_TZAHB6ENSETR		U(0x220)
+#define RCC_MP_TZAHB6ENCLRR		U(0x224)
+#define RCC_MC_APB4ENSETR		U(0x280)
+#define RCC_MC_APB4ENCLRR		U(0x284)
+#define RCC_MC_APB5ENSETR		U(0x288)
+#define RCC_MC_APB5ENCLRR		U(0x28C)
+#define RCC_MC_AHB5ENSETR		U(0x290)
+#define RCC_MC_AHB5ENCLRR		U(0x294)
+#define RCC_MC_AHB6ENSETR		U(0x298)
+#define RCC_MC_AHB6ENCLRR		U(0x29C)
+#define RCC_MP_APB4LPENSETR		U(0x300)
+#define RCC_MP_APB4LPENCLRR		U(0x304)
+#define RCC_MP_APB5LPENSETR		U(0x308)
+#define RCC_MP_APB5LPENCLRR		U(0x30C)
+#define RCC_MP_AHB5LPENSETR		U(0x310)
+#define RCC_MP_AHB5LPENCLRR		U(0x314)
+#define RCC_MP_AHB6LPENSETR		U(0x318)
+#define RCC_MP_AHB6LPENCLRR		U(0x31C)
+#define RCC_MP_TZAHB6LPENSETR		U(0x320)
+#define RCC_MP_TZAHB6LPENCLRR		U(0x324)
+#define RCC_MC_APB4LPENSETR		U(0x380)
+#define RCC_MC_APB4LPENCLRR		U(0x384)
+#define RCC_MC_APB5LPENSETR		U(0x388)
+#define RCC_MC_APB5LPENCLRR		U(0x38C)
+#define RCC_MC_AHB5LPENSETR		U(0x390)
+#define RCC_MC_AHB5LPENCLRR		U(0x394)
+#define RCC_MC_AHB6LPENSETR		U(0x398)
+#define RCC_MC_AHB6LPENCLRR		U(0x39C)
+#define RCC_BR_RSTSCLRR			U(0x400)
+#define RCC_MP_GRSTCSETR		U(0x404)
+#define RCC_MP_RSTSCLRR			U(0x408)
+#define RCC_MP_IWDGFZSETR		U(0x40C)
+#define RCC_MP_IWDGFZCLRR		U(0x410)
+#define RCC_MP_CIER			U(0x414)
+#define RCC_MP_CIFR			U(0x418)
+#define RCC_PWRLPDLYCR			U(0x41C)
+#define RCC_MP_RSTSSETR			U(0x420)
+#define RCC_MCO1CFGR			U(0x800)
+#define RCC_MCO2CFGR			U(0x804)
+#define RCC_OCRDYR			U(0x808)
+#define RCC_DBGCFGR			U(0x80C)
+#define RCC_RCK3SELR			U(0x820)
+#define RCC_RCK4SELR			U(0x824)
+#define RCC_TIMG1PRER			U(0x828)
+#define RCC_TIMG2PRER			U(0x82C)
+#define RCC_MCUDIVR			U(0x830)
+#define RCC_APB1DIVR			U(0x834)
+#define RCC_APB2DIVR			U(0x838)
+#define RCC_APB3DIVR			U(0x83C)
+#define RCC_PLL3CR			U(0x880)
+#define RCC_PLL3CFGR1			U(0x884)
+#define RCC_PLL3CFGR2			U(0x888)
+#define RCC_PLL3FRACR			U(0x88C)
+#define RCC_PLL3CSGR			U(0x890)
+#define RCC_PLL4CR			U(0x894)
+#define RCC_PLL4CFGR1			U(0x898)
+#define RCC_PLL4CFGR2			U(0x89C)
+#define RCC_PLL4FRACR			U(0x8A0)
+#define RCC_PLL4CSGR			U(0x8A4)
+#define RCC_I2C12CKSELR			U(0x8C0)
+#define RCC_I2C35CKSELR			U(0x8C4)
+#define RCC_SAI1CKSELR			U(0x8C8)
+#define RCC_SAI2CKSELR			U(0x8CC)
+#define RCC_SAI3CKSELR			U(0x8D0)
+#define RCC_SAI4CKSELR			U(0x8D4)
+#define RCC_SPI2S1CKSELR		U(0x8D8)
+#define RCC_SPI2S23CKSELR		U(0x8DC)
+#define RCC_SPI45CKSELR			U(0x8E0)
+#define RCC_UART6CKSELR			U(0x8E4)
+#define RCC_UART24CKSELR		U(0x8E8)
+#define RCC_UART35CKSELR		U(0x8EC)
+#define RCC_UART78CKSELR		U(0x8F0)
+#define RCC_SDMMC12CKSELR		U(0x8F4)
+#define RCC_SDMMC3CKSELR		U(0x8F8)
+#define RCC_ETHCKSELR			U(0x8FC)
+#define RCC_QSPICKSELR			U(0x900)
+#define RCC_FMCCKSELR			U(0x904)
+#define RCC_FDCANCKSELR			U(0x90C)
+#define RCC_SPDIFCKSELR			U(0x914)
+#define RCC_CECCKSELR			U(0x918)
+#define RCC_USBCKSELR			U(0x91C)
+#define RCC_RNG2CKSELR			U(0x920)
+#define RCC_DSICKSELR			U(0x924)
+#define RCC_ADCCKSELR			U(0x928)
+#define RCC_LPTIM45CKSELR		U(0x92C)
+#define RCC_LPTIM23CKSELR		U(0x930)
+#define RCC_LPTIM1CKSELR		U(0x934)
+#define RCC_APB1RSTSETR			U(0x980)
+#define RCC_APB1RSTCLRR			U(0x984)
+#define RCC_APB2RSTSETR			U(0x988)
+#define RCC_APB2RSTCLRR			U(0x98C)
+#define RCC_APB3RSTSETR			U(0x990)
+#define RCC_APB3RSTCLRR			U(0x994)
+#define RCC_AHB2RSTSETR			U(0x998)
+#define RCC_AHB2RSTCLRR			U(0x99C)
+#define RCC_AHB3RSTSETR			U(0x9A0)
+#define RCC_AHB3RSTCLRR			U(0x9A4)
+#define RCC_AHB4RSTSETR			U(0x9A8)
+#define RCC_AHB4RSTCLRR			U(0x9AC)
+#define RCC_MP_APB1ENSETR		U(0xA00)
+#define RCC_MP_APB1ENCLRR		U(0xA04)
+#define RCC_MP_APB2ENSETR		U(0xA08)
+#define RCC_MP_APB2ENCLRR		U(0xA0C)
+#define RCC_MP_APB3ENSETR		U(0xA10)
+#define RCC_MP_APB3ENCLRR		U(0xA14)
+#define RCC_MP_AHB2ENSETR		U(0xA18)
+#define RCC_MP_AHB2ENCLRR		U(0xA1C)
+#define RCC_MP_AHB3ENSETR		U(0xA20)
+#define RCC_MP_AHB3ENCLRR		U(0xA24)
+#define RCC_MP_AHB4ENSETR		U(0xA28)
+#define RCC_MP_AHB4ENCLRR		U(0xA2C)
+#define RCC_MP_MLAHBENSETR		U(0xA38)
+#define RCC_MP_MLAHBENCLRR		U(0xA3C)
+#define RCC_MC_APB1ENSETR		U(0xA80)
+#define RCC_MC_APB1ENCLRR		U(0xA84)
+#define RCC_MC_APB2ENSETR		U(0xA88)
+#define RCC_MC_APB2ENCLRR		U(0xA8C)
+#define RCC_MC_APB3ENSETR		U(0xA90)
+#define RCC_MC_APB3ENCLRR		U(0xA94)
+#define RCC_MC_AHB2ENSETR		U(0xA98)
+#define RCC_MC_AHB2ENCLRR		U(0xA9C)
+#define RCC_MC_AHB3ENSETR		U(0xAA0)
+#define RCC_MC_AHB3ENCLRR		U(0xAA4)
+#define RCC_MC_AHB4ENSETR		U(0xAA8)
+#define RCC_MC_AHB4ENCLRR		U(0xAAC)
+#define RCC_MC_AXIMENSETR		U(0xAB0)
+#define RCC_MC_AXIMENCLRR		U(0xAB4)
+#define RCC_MC_MLAHBENSETR		U(0xAB8)
+#define RCC_MC_MLAHBENCLRR		U(0xABC)
+#define RCC_MP_APB1LPENSETR		U(0xB00)
+#define RCC_MP_APB1LPENCLRR		U(0xB04)
+#define RCC_MP_APB2LPENSETR		U(0xB08)
+#define RCC_MP_APB2LPENCLRR		U(0xB0C)
+#define RCC_MP_APB3LPENSETR		U(0xB10)
+#define RCC_MP_APB3LPENCLRR		U(0xB14)
+#define RCC_MP_AHB2LPENSETR		U(0xB18)
+#define RCC_MP_AHB2LPENCLRR		U(0xB1C)
+#define RCC_MP_AHB3LPENSETR		U(0xB20)
+#define RCC_MP_AHB3LPENCLRR		U(0xB24)
+#define RCC_MP_AHB4LPENSETR		U(0xB28)
+#define RCC_MP_AHB4LPENCLRR		U(0xB2C)
+#define RCC_MP_AXIMLPENSETR		U(0xB30)
+#define RCC_MP_AXIMLPENCLRR		U(0xB34)
+#define RCC_MP_MLAHBLPENSETR		U(0xB38)
+#define RCC_MP_MLAHBLPENCLRR		U(0xB3C)
+#define RCC_MC_APB1LPENSETR		U(0xB80)
+#define RCC_MC_APB1LPENCLRR		U(0xB84)
+#define RCC_MC_APB2LPENSETR		U(0xB88)
+#define RCC_MC_APB2LPENCLRR		U(0xB8C)
+#define RCC_MC_APB3LPENSETR		U(0xB90)
+#define RCC_MC_APB3LPENCLRR		U(0xB94)
+#define RCC_MC_AHB2LPENSETR		U(0xB98)
+#define RCC_MC_AHB2LPENCLRR		U(0xB9C)
+#define RCC_MC_AHB3LPENSETR		U(0xBA0)
+#define RCC_MC_AHB3LPENCLRR		U(0xBA4)
+#define RCC_MC_AHB4LPENSETR		U(0xBA8)
+#define RCC_MC_AHB4LPENCLRR		U(0xBAC)
+#define RCC_MC_AXIMLPENSETR		U(0xBB0)
+#define RCC_MC_AXIMLPENCLRR		U(0xBB4)
+#define RCC_MC_MLAHBLPENSETR		U(0xBB8)
+#define RCC_MC_MLAHBLPENCLRR		U(0xBBC)
+#define RCC_MC_RSTSCLRR			U(0xC00)
+#define RCC_MC_CIER			U(0xC14)
+#define RCC_MC_CIFR			U(0xC18)
+#define RCC_VERR			U(0xFF4)
+#define RCC_IDR				U(0xFF8)
+#define RCC_SIDR			U(0xFFC)
+
+#define RCC_OFFSET_MASK			GENMASK(11, 0)
+
+/* Values for RCC_TZCR register */
+#define RCC_TZCR_TZEN			BIT(0)
+#define RCC_TZCR_MCKPROT		BIT(1)
+
+/* Used for most of RCC_<x>SELR registers */
+#define RCC_SELR_SRC_MASK		GENMASK(2, 0)
+#define RCC_SELR_REFCLK_SRC_MASK	GENMASK(1, 0)
+#define RCC_SELR_SRCRDY			BIT(31)
+
+/* Values of RCC_MPCKSELR register */
+#define RCC_MPCKSELR_HSI		0x00000000
+#define RCC_MPCKSELR_HSE		0x00000001
+#define RCC_MPCKSELR_PLL		0x00000002
+#define RCC_MPCKSELR_PLL_MPUDIV		0x00000003
+
+/* Values of RCC_ASSCKSELR register */
+#define RCC_ASSCKSELR_HSI		0x00000000
+#define RCC_ASSCKSELR_HSE		0x00000001
+#define RCC_ASSCKSELR_PLL		0x00000002
+
+/* Values of RCC_MSSCKSELR register */
+#define RCC_MSSCKSELR_HSI		0x00000000
+#define RCC_MSSCKSELR_HSE		0x00000001
+#define RCC_MSSCKSELR_CSI		0x00000002
+#define RCC_MSSCKSELR_PLL		0x00000003
+
+/* Values of RCC_CPERCKSELR register */
+#define RCC_CPERCKSELR_HSI		0x00000000
+#define RCC_CPERCKSELR_CSI		0x00000001
+#define RCC_CPERCKSELR_HSE		0x00000002
+
+/* Used for most of DIVR register: max div for RTC */
+#define RCC_DIVR_DIV_MASK		GENMASK(5, 0)
+#define RCC_DIVR_DIVRDY			BIT(31)
+
+/* Masks for specific DIVR registers */
+#define RCC_APBXDIV_MASK		GENMASK(2, 0)
+#define RCC_MPUDIV_MASK			GENMASK(2, 0)
+#define RCC_AXIDIV_MASK			GENMASK(2, 0)
+#define RCC_MCUDIV_MASK			GENMASK(3, 0)
+
+/* Used for TIMER Prescaler */
+#define RCC_TIMGXPRER_TIMGXPRE		BIT(0)
+
+/* Offset between RCC_MP_xxxENSETR and RCC_MP_xxxENCLRR registers */
+#define RCC_MP_ENCLRR_OFFSET		U(4)
+
+/* Offset between RCC_xxxRSTSETR and RCC_xxxRSTCLRR registers */
+#define RCC_RSTCLRR_OFFSET		U(4)
+
+/* Fields of RCC_BDCR register */
+#define RCC_BDCR_LSEON			BIT(0)
+#define RCC_BDCR_LSEBYP			BIT(1)
+#define RCC_BDCR_LSERDY			BIT(2)
+#define RCC_BDCR_DIGBYP			BIT(3)
+#define RCC_BDCR_LSEDRV_MASK		GENMASK(5, 4)
+#define RCC_BDCR_LSEDRV_SHIFT		4
+#define RCC_BDCR_LSECSSON		BIT(8)
+#define RCC_BDCR_RTCCKEN		BIT(20)
+#define RCC_BDCR_RTCSRC_MASK		GENMASK(17, 16)
+#define RCC_BDCR_RTCSRC_SHIFT		16
+#define RCC_BDCR_VSWRST			BIT(31)
+
+/* Fields of RCC_RDLSICR register */
+#define RCC_RDLSICR_LSION		BIT(0)
+#define RCC_RDLSICR_LSIRDY		BIT(1)
+
+/* Used for all RCC_PLL<n>CR registers */
+#define RCC_PLLNCR_PLLON		BIT(0)
+#define RCC_PLLNCR_PLLRDY		BIT(1)
+#define RCC_PLLNCR_SSCG_CTRL		BIT(2)
+#define RCC_PLLNCR_DIVPEN		BIT(4)
+#define RCC_PLLNCR_DIVQEN		BIT(5)
+#define RCC_PLLNCR_DIVREN		BIT(6)
+#define RCC_PLLNCR_DIVEN_SHIFT		4
+
+/* Used for all RCC_PLL<n>CFGR1 registers */
+#define RCC_PLLNCFGR1_DIVM_SHIFT	16
+#define RCC_PLLNCFGR1_DIVM_MASK		GENMASK(21, 16)
+#define RCC_PLLNCFGR1_DIVN_SHIFT	0
+#define RCC_PLLNCFGR1_DIVN_MASK		GENMASK(8, 0)
+/* Only for PLL3 and PLL4 */
+#define RCC_PLLNCFGR1_IFRGE_SHIFT	24
+#define RCC_PLLNCFGR1_IFRGE_MASK	GENMASK(25, 24)
+
+/* Used for all RCC_PLL<n>CFGR2 registers */
+#define RCC_PLLNCFGR2_DIVX_MASK		GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVP_SHIFT	0
+#define RCC_PLLNCFGR2_DIVP_MASK		GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVQ_SHIFT	8
+#define RCC_PLLNCFGR2_DIVQ_MASK		GENMASK(14, 8)
+#define RCC_PLLNCFGR2_DIVR_SHIFT	16
+#define RCC_PLLNCFGR2_DIVR_MASK		GENMASK(22, 16)
+
+/* Used for all RCC_PLL<n>FRACR registers */
+#define RCC_PLLNFRACR_FRACV_SHIFT	3
+#define RCC_PLLNFRACR_FRACV_MASK	GENMASK(15, 3)
+#define RCC_PLLNFRACR_FRACLE		BIT(16)
+
+/* Used for all RCC_PLL<n>CSGR registers */
+#define RCC_PLLNCSGR_INC_STEP_SHIFT	16
+#define RCC_PLLNCSGR_INC_STEP_MASK	GENMASK(30, 16)
+#define RCC_PLLNCSGR_MOD_PER_SHIFT	0
+#define RCC_PLLNCSGR_MOD_PER_MASK	GENMASK(12, 0)
+#define RCC_PLLNCSGR_SSCG_MODE_SHIFT	15
+#define RCC_PLLNCSGR_SSCG_MODE_MASK	BIT(15)
+
+/* Used for RCC_OCENSETR and RCC_OCENCLRR registers */
+#define RCC_OCENR_HSION			BIT(0)
+#define RCC_OCENR_HSIKERON		BIT(1)
+#define RCC_OCENR_CSION			BIT(4)
+#define RCC_OCENR_CSIKERON		BIT(5)
+#define RCC_OCENR_DIGBYP		BIT(7)
+#define RCC_OCENR_HSEON			BIT(8)
+#define RCC_OCENR_HSEKERON		BIT(9)
+#define RCC_OCENR_HSEBYP		BIT(10)
+#define RCC_OCENR_HSECSSON		BIT(11)
+
+/* Fields of RCC_OCRDYR register */
+#define RCC_OCRDYR_HSIRDY		BIT(0)
+#define RCC_OCRDYR_HSIDIVRDY		BIT(2)
+#define RCC_OCRDYR_CSIRDY		BIT(4)
+#define RCC_OCRDYR_HSERDY		BIT(8)
+
+/* Fields of RCC_DDRITFCR register */
+#define RCC_DDRITFCR_DDRC1EN		BIT(0)
+#define RCC_DDRITFCR_DDRC1LPEN		BIT(1)
+#define RCC_DDRITFCR_DDRC2EN		BIT(2)
+#define RCC_DDRITFCR_DDRC2LPEN		BIT(3)
+#define RCC_DDRITFCR_DDRPHYCEN		BIT(4)
+#define RCC_DDRITFCR_DDRPHYCLPEN	BIT(5)
+#define RCC_DDRITFCR_DDRCAPBEN		BIT(6)
+#define RCC_DDRITFCR_DDRCAPBLPEN	BIT(7)
+#define RCC_DDRITFCR_AXIDCGEN		BIT(8)
+#define RCC_DDRITFCR_DDRPHYCAPBEN	BIT(9)
+#define RCC_DDRITFCR_DDRPHYCAPBLPEN	BIT(10)
+#define RCC_DDRITFCR_DDRCAPBRST		BIT(14)
+#define RCC_DDRITFCR_DDRCAXIRST		BIT(15)
+#define RCC_DDRITFCR_DDRCORERST		BIT(16)
+#define RCC_DDRITFCR_DPHYAPBRST		BIT(17)
+#define RCC_DDRITFCR_DPHYRST		BIT(18)
+#define RCC_DDRITFCR_DPHYCTLRST		BIT(19)
+#define RCC_DDRITFCR_DDRCKMOD_MASK	GENMASK(22, 20)
+#define RCC_DDRITFCR_DDRCKMOD_SHIFT	20
+#define RCC_DDRITFCR_DDRCKMOD_SSR	0
+#define RCC_DDRITFCR_DDRCKMOD_ASR1	BIT(20)
+#define RCC_DDRITFCR_DDRCKMOD_HSR1	BIT(21)
+#define RCC_DDRITFCR_GSKPCTRL		BIT(24)
+
+/* Fields of RCC_HSICFGR register */
+#define RCC_HSICFGR_HSIDIV_MASK		GENMASK(1, 0)
+#define RCC_HSICFGR_HSITRIM_SHIFT	8
+#define RCC_HSICFGR_HSITRIM_MASK	GENMASK(14, 8)
+#define RCC_HSICFGR_HSICAL_SHIFT	16
+#define RCC_HSICFGR_HSICAL_MASK		GENMASK(27, 16)
+
+/* Fields of RCC_CSICFGR register */
+#define RCC_CSICFGR_CSITRIM_SHIFT	8
+#define RCC_CSICFGR_CSITRIM_MASK	GENMASK(12, 8)
+#define RCC_CSICFGR_CSICAL_SHIFT	16
+#define RCC_CSICFGR_CSICAL_MASK		GENMASK(23, 16)
+
+/* Used for RCC_MCO related operations */
+#define RCC_MCOCFG_MCOON		BIT(12)
+#define RCC_MCOCFG_MCODIV_MASK		GENMASK(7, 4)
+#define RCC_MCOCFG_MCODIV_SHIFT		4
+#define RCC_MCOCFG_MCOSRC_MASK		GENMASK(2, 0)
+
+/* Fields of RCC_DBGCFGR register */
+#define RCC_DBGCFGR_DBGCKEN		BIT(8)
+
+/* RCC register fields for reset reasons */
+#define RCC_MP_RSTSCLRR_PORRSTF		BIT(0)
+#define RCC_MP_RSTSCLRR_BORRSTF		BIT(1)
+#define RCC_MP_RSTSCLRR_PADRSTF		BIT(2)
+#define RCC_MP_RSTSCLRR_HCSSRSTF	BIT(3)
+#define RCC_MP_RSTSCLRR_VCORERSTF	BIT(4)
+#define RCC_MP_RSTSCLRR_MPSYSRSTF	BIT(6)
+#define RCC_MP_RSTSCLRR_MCSYSRSTF	BIT(7)
+#define RCC_MP_RSTSCLRR_IWDG1RSTF	BIT(8)
+#define RCC_MP_RSTSCLRR_IWDG2RSTF	BIT(9)
+#define RCC_MP_RSTSCLRR_STDBYRSTF	BIT(11)
+#define RCC_MP_RSTSCLRR_CSTDBYRSTF	BIT(12)
+#define RCC_MP_RSTSCLRR_MPUP0RSTF	BIT(13)
+#define RCC_MP_RSTSCLRR_MPUP1RSTF	BIT(14)
+
+/* Global Reset Register */
+#define RCC_MP_GRSTCSETR_MPSYSRST	BIT(0)
+#define RCC_MP_GRSTCSETR_MCURST		BIT(1)
+#define RCC_MP_GRSTCSETR_MPUP0RST	BIT(4)
+#define RCC_MP_GRSTCSETR_MPUP1RST	BIT(5)
+
+/* Clock Source Interrupt Flag Register */
+#define RCC_MP_CIFR_MASK		U(0x110F1F)
+#define RCC_MP_CIFR_LSIRDYF		BIT(0)
+#define RCC_MP_CIFR_LSERDYF		BIT(1)
+#define RCC_MP_CIFR_HSIRDYF		BIT(2)
+#define RCC_MP_CIFR_HSERDYF		BIT(3)
+#define RCC_MP_CIFR_CSIRDYF		BIT(4)
+#define RCC_MP_CIFR_PLL1DYF		BIT(8)
+#define RCC_MP_CIFR_PLL2DYF		BIT(9)
+#define RCC_MP_CIFR_PLL3DYF		BIT(10)
+#define RCC_MP_CIFR_PLL4DYF		BIT(11)
+#define RCC_MP_CIFR_WKUPF		BIT(20)
+
+/* Stop Request Set Register */
+#define RCC_MP_SREQSETR_STPREQ_P0	BIT(0)
+#define RCC_MP_SREQSETR_STPREQ_P1	BIT(1)
+
+/* Stop Request Clear Register */
+#define RCC_MP_SREQCLRR_STPREQ_P0	BIT(0)
+#define RCC_MP_SREQCLRR_STPREQ_P1	BIT(1)
+
+/* Values of RCC_UART24CKSELR register */
+#define RCC_UART24CKSELR_HSI		0x00000002
+
+/* Values of RCC_MP_APB1ENSETR register */
+#define RCC_MP_APB1ENSETR_UART4EN	BIT(16)
+
+/* Values of RCC_MP_APB5ENSETR register */
+#define RCC_MP_APB5ENSETR_SPI6EN	BIT(0)
+#define RCC_MP_APB5ENSETR_I2C4EN	BIT(2)
+#define RCC_MP_APB5ENSETR_I2C6EN	BIT(3)
+#define RCC_MP_APB5ENSETR_USART1EN	BIT(4)
+#define RCC_MP_APB5ENSETR_RTCAPBEN	BIT(8)
+#define RCC_MP_APB5ENSETR_IWDG1APBEN	BIT(15)
+
+/* Values of RCC_MP_AHB4ENSETR register */
+#define RCC_MP_AHB4ENSETR_GPIOGEN	BIT(6)
+#define RCC_MP_AHB4ENSETR_GPIOHEN	BIT(7)
+
+/* Values of RCC_MP_AHB5ENSETR register */
+#define RCC_MP_AHB5ENSETR_GPIOZEN	BIT(0)
+#define RCC_MP_AHB5ENSETR_CRYP1EN	BIT(4)
+#define RCC_MP_AHB5ENSETR_HASH1EN	BIT(5)
+#define RCC_MP_AHB5ENSETR_RNG1EN	BIT(6)
+
+/* Values of RCC_MP_IWDGFZSETR register */
+#define RCC_MP_IWDGFZSETR_IWDG1		BIT(0)
+#define RCC_MP_IWDGFZSETR_IWDG2		BIT(1)
+
+/* Values of RCC_PWRLPDLYCR register */
+#define RCC_PWRLPDLYCR_PWRLP_DLY_MASK	GENMASK(21, 0)
+
+/* RCC_ASSCKSELR register fields */
+#define RCC_ASSCKSELR_AXISSRC_MASK		GENMASK(2, 0)
+#define RCC_ASSCKSELR_AXISSRC_SHIFT		0
+
+/* RCC_MSSCKSELR register fields */
+#define RCC_MSSCKSELR_MCUSSRC_MASK		GENMASK(1, 0)
+#define RCC_MSSCKSELR_MCUSSRC_SHIFT		0
+
+/* RCC_I2C46CKSELR register fields */
+#define RCC_I2C46CKSELR_I2C46SRC_MASK		GENMASK(2, 0)
+#define RCC_I2C46CKSELR_I2C46SRC_SHIFT		0
+
+/* RCC_SPI6CKSELR register fields */
+#define RCC_SPI6CKSELR_SPI6SRC_MASK		GENMASK(2, 0)
+#define RCC_SPI6CKSELR_SPI6SRC_SHIFT		0
+
+/* RCC_UART1CKSELR register fields */
+#define RCC_UART1CKSELR_UART1SRC_MASK		GENMASK(2, 0)
+#define RCC_UART1CKSELR_UART1SRC_SHIFT		0
+
+/* RCC_RNG1CKSELR register fields */
+#define RCC_RNG1CKSELR_RNG1SRC_MASK		GENMASK(1, 0)
+#define RCC_RNG1CKSELR_RNG1SRC_SHIFT		0
+
+/* RCC_STGENCKSELR register fields */
+#define RCC_STGENCKSELR_STGENSRC_MASK		GENMASK(1, 0)
+#define RCC_STGENCKSELR_STGENSRC_SHIFT		0
+
+/* RCC_I2C12CKSELR register fields */
+#define RCC_I2C12CKSELR_I2C12SRC_MASK		GENMASK(2, 0)
+#define RCC_I2C12CKSELR_I2C12SRC_SHIFT		0
+
+/* RCC_I2C35CKSELR register fields */
+#define RCC_I2C35CKSELR_I2C35SRC_MASK		GENMASK(2, 0)
+#define RCC_I2C35CKSELR_I2C35SRC_SHIFT		0
+
+/* RCC_UART6CKSELR register fields */
+#define RCC_UART6CKSELR_UART6SRC_MASK		GENMASK(2, 0)
+#define RCC_UART6CKSELR_UART6SRC_SHIFT		0
+
+/* RCC_UART24CKSELR register fields */
+#define RCC_UART24CKSELR_UART24SRC_MASK		GENMASK(2, 0)
+#define RCC_UART24CKSELR_UART24SRC_SHIFT	0
+
+/* RCC_UART35CKSELR register fields */
+#define RCC_UART35CKSELR_UART35SRC_MASK		GENMASK(2, 0)
+#define RCC_UART35CKSELR_UART35SRC_SHIFT	0
+
+/* RCC_UART78CKSELR register fields */
+#define RCC_UART78CKSELR_UART78SRC_MASK		GENMASK(2, 0)
+#define RCC_UART78CKSELR_UART78SRC_SHIFT	0
+
+/* RCC_SDMMC12CKSELR register fields */
+#define RCC_SDMMC12CKSELR_SDMMC12SRC_MASK	GENMASK(2, 0)
+#define RCC_SDMMC12CKSELR_SDMMC12SRC_SHIFT	0
+
+/* RCC_SDMMC3CKSELR register fields */
+#define RCC_SDMMC3CKSELR_SDMMC3SRC_MASK		GENMASK(2, 0)
+#define RCC_SDMMC3CKSELR_SDMMC3SRC_SHIFT	0
+
+/* RCC_ETHCKSELR register fields */
+#define RCC_ETHCKSELR_ETHSRC_MASK		GENMASK(1, 0)
+#define RCC_ETHCKSELR_ETHSRC_SHIFT		0
+
+/* RCC_QSPICKSELR register fields */
+#define RCC_QSPICKSELR_QSPISRC_MASK		GENMASK(1, 0)
+#define RCC_QSPICKSELR_QSPISRC_SHIFT		0
+
+/* RCC_FMCCKSELR register fields */
+#define RCC_FMCCKSELR_FMCSRC_MASK		GENMASK(1, 0)
+#define RCC_FMCCKSELR_FMCSRC_SHIFT		0
+
+/* RCC_USBCKSELR register fields */
+#define RCC_USBCKSELR_USBPHYSRC_MASK		GENMASK(1, 0)
+#define RCC_USBCKSELR_USBPHYSRC_SHIFT		0
+#define RCC_USBCKSELR_USBOSRC_MASK		BIT(4)
+#define RCC_USBCKSELR_USBOSRC_SHIFT		4
+
+#endif /* STM32MP1_RCC_H */
diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h
new file mode 100644
index 0000000..0769167
--- /dev/null
+++ b/include/drivers/st/stm32mp_clkfunc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_CLKFUNC_H
+#define STM32MP_CLKFUNC_H
+
+#include <stdbool.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+int fdt_osc_read_freq(const char *name, uint32_t *freq);
+bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name);
+uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
+				     const char *prop_name,
+				     uint32_t dflt_value);
+
+int fdt_get_rcc_node(void *fdt);
+uint32_t fdt_rcc_read_addr(void);
+int fdt_rcc_read_uint32_array(const char *prop_name,
+			      uint32_t *array, uint32_t count);
+int fdt_rcc_subnode_offset(const char *name);
+const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp);
+bool fdt_get_rcc_secure_status(void);
+
+uintptr_t fdt_get_stgen_base(void);
+int fdt_get_clock_id(int node);
+
+#endif /* STM32MP_CLKFUNC_H */
diff --git a/include/drivers/st/stm32mp_pmic.h b/include/drivers/st/stm32mp_pmic.h
new file mode 100644
index 0000000..984cd60
--- /dev/null
+++ b/include/drivers/st/stm32mp_pmic.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_PMIC_H
+#define STM32MP_PMIC_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+/*
+ * dt_pmic_status - Check PMIC status from device tree
+ *
+ * Returns the status of the PMIC (secure, non-secure), or a negative value on
+ * error
+ */
+int dt_pmic_status(void);
+
+/*
+ * dt_pmic_configure_boot_on_regulators - Configure boot-on and always-on
+ * regulators from device tree configuration
+ *
+ * Returns 0 on success, and negative values on errors
+ */
+int dt_pmic_configure_boot_on_regulators(void);
+
+/*
+ * initialize_pmic_i2c - Initialize I2C for the PMIC control
+ *
+ * Returns true if PMIC is available, false if not found, panics on errors
+ */
+bool initialize_pmic_i2c(void);
+
+/*
+ * initialize_pmic - Main PMIC initialization function, called at platform init
+ *
+ * Panics on errors
+ */
+void initialize_pmic(void);
+
+/*
+ * pmic_ddr_power_init - Initialize regulators required for DDR
+ *
+ * Returns 0 on success, and negative values on errors
+ */
+int pmic_ddr_power_init(enum ddr_type ddr_type);
+
+#endif /* STM32MP_PMIC_H */
diff --git a/include/drivers/st/stm32mp_reset.h b/include/drivers/st/stm32mp_reset.h
new file mode 100644
index 0000000..2da5adf
--- /dev/null
+++ b/include/drivers/st/stm32mp_reset.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_RESET_H
+#define STM32MP_RESET_H
+
+#include <stdint.h>
+
+void stm32mp_reset_assert(uint32_t reset_id);
+void stm32mp_reset_deassert(uint32_t reset_id);
+
+#endif /* STM32MP_RESET_H */
diff --git a/include/drivers/st/stpmic1.h b/include/drivers/st/stpmic1.h
new file mode 100644
index 0000000..f7e293b
--- /dev/null
+++ b/include/drivers/st/stpmic1.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STPMIC1_H
+#define STPMIC1_H
+
+#include <drivers/st/stm32_i2c.h>
+#include <lib/utils_def.h>
+
+#define TURN_ON_REG			0x1U
+#define TURN_OFF_REG			0x2U
+#define ICC_LDO_TURN_OFF_REG		0x3U
+#define ICC_BUCK_TURN_OFF_REG		0x4U
+#define RESET_STATUS_REG		0x5U
+#define VERSION_STATUS_REG		0x6U
+#define MAIN_CONTROL_REG		0x10U
+#define PADS_PULL_REG			0x11U
+#define BUCK_PULL_DOWN_REG		0x12U
+#define LDO14_PULL_DOWN_REG		0x13U
+#define LDO56_PULL_DOWN_REG		0x14U
+#define VIN_CONTROL_REG			0x15U
+#define PONKEY_TIMER_REG		0x16U
+#define MASK_RANK_BUCK_REG		0x17U
+#define MASK_RESET_BUCK_REG		0x18U
+#define MASK_RANK_LDO_REG		0x19U
+#define MASK_RESET_LDO_REG		0x1AU
+#define WATCHDOG_CONTROL_REG		0x1BU
+#define WATCHDOG_TIMER_REG		0x1CU
+#define BUCK_ICC_TURNOFF_REG		0x1DU
+#define LDO_ICC_TURNOFF_REG		0x1EU
+#define BUCK_APM_CONTROL_REG		0x1FU
+#define BUCK1_CONTROL_REG		0x20U
+#define BUCK2_CONTROL_REG		0x21U
+#define BUCK3_CONTROL_REG		0x22U
+#define BUCK4_CONTROL_REG		0x23U
+#define VREF_DDR_CONTROL_REG		0x24U
+#define LDO1_CONTROL_REG		0x25U
+#define LDO2_CONTROL_REG		0x26U
+#define LDO3_CONTROL_REG		0x27U
+#define LDO4_CONTROL_REG		0x28U
+#define LDO5_CONTROL_REG		0x29U
+#define LDO6_CONTROL_REG		0x2AU
+#define BUCK1_PWRCTRL_REG		0x30U
+#define BUCK2_PWRCTRL_REG		0x31U
+#define BUCK3_PWRCTRL_REG		0x32U
+#define BUCK4_PWRCTRL_REG		0x33U
+#define VREF_DDR_PWRCTRL_REG		0x34U
+#define LDO1_PWRCTRL_REG		0x35U
+#define LDO2_PWRCTRL_REG		0x36U
+#define LDO3_PWRCTRL_REG		0x37U
+#define LDO4_PWRCTRL_REG		0x38U
+#define LDO5_PWRCTRL_REG		0x39U
+#define LDO6_PWRCTRL_REG		0x3AU
+#define FREQUENCY_SPREADING_REG		0x3BU
+#define USB_CONTROL_REG			0x40U
+#define ITLATCH1_REG			0x50U
+#define ITLATCH2_REG			0x51U
+#define ITLATCH3_REG			0x52U
+#define ITLATCH4_REG			0x53U
+#define ITSETLATCH1_REG			0x60U
+#define ITSETLATCH2_REG			0x61U
+#define ITSETLATCH3_REG			0x62U
+#define ITSETLATCH4_REG			0x63U
+#define ITCLEARLATCH1_REG		0x70U
+#define ITCLEARLATCH2_REG		0x71U
+#define ITCLEARLATCH3_REG		0x72U
+#define ITCLEARLATCH4_REG		0x73U
+#define ITMASK1_REG			0x80U
+#define ITMASK2_REG			0x81U
+#define ITMASK3_REG			0x82U
+#define ITMASK4_REG			0x83U
+#define ITSETMASK1_REG			0x90U
+#define ITSETMASK2_REG			0x91U
+#define ITSETMASK3_REG			0x92U
+#define ITSETMASK4_REG			0x93U
+#define ITCLEARMASK1_REG		0xA0U
+#define ITCLEARMASK2_REG		0xA1U
+#define ITCLEARMASK3_REG		0xA2U
+#define ITCLEARMASK4_REG		0xA3U
+#define ITSOURCE1_REG			0xB0U
+#define ITSOURCE2_REG			0xB1U
+#define ITSOURCE3_REG			0xB2U
+#define ITSOURCE4_REG			0xB3U
+
+/* Registers masks */
+#define LDO_VOLTAGE_MASK		0x7CU
+#define BUCK_VOLTAGE_MASK		0xFCU
+#define LDO_BUCK_VOLTAGE_SHIFT		2
+#define LDO_BUCK_ENABLE_MASK		0x01U
+#define LDO_BUCK_HPLP_ENABLE_MASK	0x02U
+#define LDO_BUCK_HPLP_SHIFT		1
+#define LDO_BUCK_RANK_MASK		0x01U
+#define LDO_BUCK_RESET_MASK		0x01U
+#define LDO_BUCK_PULL_DOWN_MASK		0x03U
+
+/* Pull down register */
+#define BUCK1_PULL_DOWN_SHIFT		0
+#define BUCK2_PULL_DOWN_SHIFT		2
+#define BUCK3_PULL_DOWN_SHIFT		4
+#define BUCK4_PULL_DOWN_SHIFT		6
+#define VREF_DDR_PULL_DOWN_SHIFT	4
+
+/* Buck Mask reset register */
+#define BUCK1_MASK_RESET		0
+#define BUCK2_MASK_RESET		1
+#define BUCK3_MASK_RESET		2
+#define BUCK4_MASK_RESET		3
+
+/* LDO Mask reset register */
+#define LDO1_MASK_RESET			0
+#define LDO2_MASK_RESET			1
+#define LDO3_MASK_RESET			2
+#define LDO4_MASK_RESET			3
+#define LDO5_MASK_RESET			4
+#define LDO6_MASK_RESET			5
+#define VREF_DDR_MASK_RESET		6
+
+/* Main PMIC Control Register (MAIN_CONTROL_REG) */
+#define ICC_EVENT_ENABLED		BIT(4)
+#define PWRCTRL_POLARITY_HIGH		BIT(3)
+#define PWRCTRL_PIN_VALID		BIT(2)
+#define RESTART_REQUEST_ENABLED		BIT(1)
+#define SOFTWARE_SWITCH_OFF_ENABLED	BIT(0)
+
+/* Main PMIC PADS Control Register (PADS_PULL_REG) */
+#define WAKEUP_DETECTOR_DISABLED	BIT(4)
+#define PWRCTRL_PD_ACTIVE		BIT(3)
+#define PWRCTRL_PU_ACTIVE		BIT(2)
+#define WAKEUP_PD_ACTIVE		BIT(1)
+#define PONKEY_PU_ACTIVE		BIT(0)
+
+/* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */
+#define SWIN_DETECTOR_ENABLED		BIT(7)
+#define SWOUT_DETECTOR_ENABLED          BIT(6)
+#define VINLOW_HYST_MASK		0x3
+#define VINLOW_HYST_SHIFT		4
+#define VINLOW_THRESHOLD_MASK		0x7
+#define VINLOW_THRESHOLD_SHIFT		1
+#define VINLOW_ENABLED			0x01
+#define VINLOW_CTRL_REG_MASK		0xFF
+
+/* USB Control Register */
+#define BOOST_OVP_DISABLED		BIT(7)
+#define VBUS_OTG_DETECTION_DISABLED	BIT(6)
+#define OCP_LIMIT_HIGH			BIT(3)
+#define SWIN_SWOUT_ENABLED		BIT(2)
+#define USBSW_OTG_SWITCH_ENABLED	BIT(1)
+
+int stpmic1_powerctrl_on(void);
+int stpmic1_switch_off(void);
+int stpmic1_register_read(uint8_t register_id, uint8_t *value);
+int stpmic1_register_write(uint8_t register_id, uint8_t value);
+int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask);
+int stpmic1_regulator_enable(const char *name);
+int stpmic1_regulator_disable(const char *name);
+uint8_t stpmic1_is_regulator_enabled(const char *name);
+int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts);
+int stpmic1_regulator_voltage_get(const char *name);
+int stpmic1_regulator_pull_down_set(const char *name);
+int stpmic1_regulator_mask_reset_set(const char *name);
+void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr);
+
+int stpmic1_get_version(unsigned long *version);
+void stpmic1_dump_regulators(void);
+
+#endif /* STPMIC1_H */
diff --git a/include/drivers/synopsys/dw_mmc.h b/include/drivers/synopsys/dw_mmc.h
new file mode 100644
index 0000000..2004355
--- /dev/null
+++ b/include/drivers/synopsys/dw_mmc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DW_MMC_H
+#define DW_MMC_H
+
+#include <drivers/mmc.h>
+
+typedef struct dw_mmc_params {
+	uintptr_t	reg_base;
+	uintptr_t	desc_base;
+	size_t		desc_size;
+	int		clk_rate;
+	int		bus_width;
+	unsigned int	flags;
+	enum mmc_device_type	mmc_dev_type;
+} dw_mmc_params_t;
+
+void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info);
+
+#endif /* DW_MMC_H */
diff --git a/include/drivers/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h
new file mode 100644
index 0000000..32e38f0
--- /dev/null
+++ b/include/drivers/ti/uart/uart_16550.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UART_16550_H
+#define UART_16550_H
+
+#include <drivers/console.h>
+
+/* UART16550 Registers */
+#define UARTTX			0x0
+#define UARTRX			0x0
+#define UARTDLL			0x0
+#define UARTIER			0x4
+#define UARTDLLM		0x4
+#define UARTIIR			0x8
+#define UARTFCR			0x8
+#define UARTLCR			0xc
+#define UARTMCR			0x10
+#define UARTLSR			0x14
+#define UARTMSR			0x18
+#define UARTSPR			0x1c
+#define UARTCSR			0x20
+/* Some instances have MDR1 defined as well */
+#define UARTMDR1		0x20
+#define UARTRXFIFOCFG		0x24
+#define UARTMIE			0x28
+#define UARTVNDR		0x2c
+#define UARTASR			0x3c
+
+/* FIFO Control Register bits */
+#define UARTFCR_FIFOMD_16450	(0 << 6)
+#define UARTFCR_FIFOMD_16550	(1 << 6)
+#define UARTFCR_RXTRIG_1	(0 << 6)
+#define UARTFCR_RXTRIG_4	(1 << 6)
+#define UARTFCR_RXTRIG_8	(2 << 6)
+#define UARTFCR_RXTRIG_16	(3 << 6)
+#define UARTFCR_TXTRIG_1	(0 << 4)
+#define UARTFCR_TXTRIG_4	(1 << 4)
+#define UARTFCR_TXTRIG_8	(2 << 4)
+#define UARTFCR_TXTRIG_16	(3 << 4)
+#define UARTFCR_DMAEN		(1 << 3)	/* Enable DMA mode */
+#define UARTFCR_TXCLR		(1 << 2)	/* Clear contents of Tx FIFO */
+#define UARTFCR_RXCLR		(1 << 1)	/* Clear contents of Rx FIFO */
+#define UARTFCR_FIFOEN		(1 << 0)	/* Enable the Tx/Rx FIFO */
+
+/* Line Control Register bits */
+#define UARTLCR_DLAB		(1 << 7)	/* Divisor Latch Access */
+#define UARTLCR_SETB		(1 << 6)	/* Set BREAK Condition */
+#define UARTLCR_SETP		(1 << 5)	/* Set Parity to LCR[4] */
+#define UARTLCR_EVEN		(1 << 4)	/* Even Parity Format */
+#define UARTLCR_PAR		(1 << 3)	/* Parity */
+#define UARTLCR_STOP		(1 << 2)	/* Stop Bit */
+#define UARTLCR_WORDSZ_5	0		/* Word Length of 5 */
+#define UARTLCR_WORDSZ_6	1		/* Word Length of 6 */
+#define UARTLCR_WORDSZ_7	2		/* Word Length of 7 */
+#define UARTLCR_WORDSZ_8	3		/* Word Length of 8 */
+
+/* Line Status Register bits */
+#define UARTLSR_RXFIFOEMT	(1 << 9)	/* Rx Fifo Empty */
+#define UARTLSR_TXFIFOFULL	(1 << 8)	/* Tx Fifo Full */
+#define UARTLSR_RXFIFOERR	(1 << 7)	/* Rx Fifo Error */
+#define UARTLSR_TEMT		(1 << 6)	/* Tx Shift Register Empty */
+#define UARTLSR_THRE		(1 << 5)	/* Tx Holding Register Empty */
+#define UARTLSR_BRK		(1 << 4)	/* Break Condition Detected */
+#define UARTLSR_FERR		(1 << 3)	/* Framing Error */
+#define UARTLSR_PERR		(1 << 3)	/* Parity Error */
+#define UARTLSR_OVRF		(1 << 2)	/* Rx Overrun Error */
+#define UARTLSR_RDR_BIT		(0)		/* Rx Data Ready Bit */
+#define UARTLSR_RDR		(1 << UARTLSR_RDR_BIT)	/* Rx Data Ready */
+
+#define CONSOLE_T_16550_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_16550_t;
+
+/*
+ * Initialize a new 16550 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_16550_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* UART_16550_H */
diff --git a/include/drivers/ufs.h b/include/drivers/ufs.h
new file mode 100644
index 0000000..574c4ea
--- /dev/null
+++ b/include/drivers/ufs.h
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UFS_H
+#define UFS_H
+
+#include <lib/utils_def.h>
+
+/* register map of UFSHCI */
+/* Controller Capabilities */
+#define CAP				0x00
+#define CAP_NUTRS_MASK			0x1F
+
+/* UFS Version */
+#define VER				0x08
+/* Host Controller Identification - Product ID */
+#define HCDDID				0x10
+/* Host Controller Identification Descriptor - Manufacturer ID */
+#define HCPMID				0x14
+/* Auto-Hibernate Idle Timer */
+#define AHIT				0x18
+/* Interrupt Status */
+#define IS				0x20
+/* Interrupt Enable */
+#define IE				0x24
+/* System Bus Fatal Error Status */
+#define UFS_INT_SBFES			(1 << 17)
+/* Host Controller Fatal Error Status */
+#define UFS_INT_HCFES			(1 << 16)
+/* UTP Error Status */
+#define UFS_INT_UTPES			(1 << 12)
+/* Device Fatal Error Status */
+#define UFS_INT_DFES			(1 << 11)
+/* UIC Command Completion Status */
+#define UFS_INT_UCCS			(1 << 10)
+/* UTP Task Management Request Completion Status */
+#define UFS_INT_UTMRCS			(1 << 9)
+/* UIC Link Startup Status */
+#define UFS_INT_ULSS			(1 << 8)
+/* UIC Link Lost Status */
+#define UFS_INT_ULLS			(1 << 7)
+/* UIC Hibernate Enter Status */
+#define UFS_INT_UHES			(1 << 6)
+/* UIC Hibernate Exit Status */
+#define UFS_INT_UHXS			(1 << 5)
+/* UIC Power Mode Status */
+#define UFS_INT_UPMS			(1 << 4)
+/* UIC Test Mode Status */
+#define UFS_INT_UTMS			(1 << 3)
+/* UIC Error */
+#define UFS_INT_UE			(1 << 2)
+/* UIC DME_ENDPOINTRESET Indication */
+#define UFS_INT_UDEPRI			(1 << 1)
+/* UTP Transfer Request Completion Status */
+#define UFS_INT_UTRCS			(1 << 0)
+
+/* Host Controller Status */
+#define HCS				0x30
+#define HCS_UPMCRS_MASK			(7 << 8)
+#define HCS_PWR_LOCAL			(1 << 8)
+#define HCS_UCRDY			(1 << 3)
+#define HCS_UTMRLRDY			(1 << 2)
+#define HCS_UTRLRDY			(1 << 1)
+#define HCS_DP				(1 << 0)
+
+/* Host Controller Enable */
+#define HCE				0x34
+#define HCE_ENABLE			1
+
+/* Host UIC Error Code PHY Adapter Layer */
+#define UECPA				0x38
+/* Host UIC Error Code Data Link Layer */
+#define UECDL				0x3C
+/* Host UIC Error Code Network Layer */
+#define UECN				0x40
+/* Host UIC Error Code Transport Layer */
+#define UECT				0x44
+/* Host UIC Error Code */
+#define UECDME				0x48
+/* UTP Transfer Request Interrupt Aggregation Control Register */
+#define UTRIACR				0x4C
+#define UTRIACR_IAEN			(1U << 31)
+#define UTRIACR_IAPWEN			(1 << 24)
+#define UTRIACR_IASB			(1 << 20)
+#define UTRIACR_CTR			(1 << 16)
+#define UTRIACR_IACTH(x)		(((x) & 0x1F) << 8)
+#define UTRIACR_IATOVAL(x)		((x) & 0xFF)
+
+/* UTP Transfer Request List Base Address */
+#define UTRLBA				0x50
+/* UTP Transfer Request List Base Address Upper 32-bits */
+#define UTRLBAU				0x54
+/* UTP Transfer Request List Door Bell Register */
+#define UTRLDBR				0x58
+/* UTP Transfer Request List Clear Register */
+#define UTRLCLR				0x5C
+/* UTP Transfer Request List Run Stop Register */
+#define UTRLRSR				0x60
+#define UTMRLBA				0x70
+#define UTMRLBAU			0x74
+#define UTMRLDBR			0x78
+#define UTMRLCLR			0x7C
+#define UTMRLRSR			0x80
+/* UIC Command */
+#define UICCMD				0x90
+/* UIC Command Argument 1 */
+#define UCMDARG1			0x94
+/* UIC Command Argument 2 */
+#define UCMDARG2			0x98
+/* UIC Command Argument 3 */
+#define UCMDARG3			0x9C
+
+#define UFS_BLOCK_SHIFT			12		/* 4KB */
+#define UFS_BLOCK_SIZE			(1 << UFS_BLOCK_SHIFT)
+#define UFS_BLOCK_MASK			(UFS_BLOCK_SIZE - 1)
+#define UFS_MAX_LUNS			8
+
+/* UTP Transfer Request Descriptor */
+/* Command Type */
+#define CT_UFS_STORAGE			1
+#define CT_SCSI				0
+
+/* Data Direction */
+#define DD_OUT				2		/* Device --> Host */
+#define DD_IN				1		/* Host --> Device */
+#define DD_NO_DATA_TRANSFER		0
+
+#define UTP_TRD_SIZE			32
+
+/* Transaction Type */
+#define TRANS_TYPE_HD			(1 << 7)	/* E2ECRC */
+#define TRANS_TYPE_DD			(1 << 6)
+#define TRANS_TYPE_CODE_MASK		0x3F
+#define QUERY_RESPONSE_UPIU		(0x36 << 0)
+#define READY_TO_TRANSACTION_UPIU	(0x31 << 0)
+#define DATA_IN_UPIU			(0x22 << 0)
+#define RESPONSE_UPIU			(0x21 << 0)
+#define NOP_IN_UPIU			(0x20 << 0)
+#define QUERY_REQUEST_UPIU		(0x16 << 0)
+#define DATA_OUT_UPIU			(0x02 << 0)
+#define CMD_UPIU			(0x01 << 0)
+#define NOP_OUT_UPIU			(0x00 << 0)
+
+#define OCS_SUCCESS			0x0
+#define OCS_INVALID_FUNC_ATTRIBUTE	0x1
+#define OCS_MISMATCH_REQUEST_SIZE	0x2
+#define OCS_MISMATCH_RESPONSE_SIZE	0x3
+#define OCS_PEER_COMMUNICATION_FAILURE	0x4
+#define OCS_ABORTED			0x5
+#define OCS_FATAL_ERROR			0x6
+#define OCS_MASK			0xF
+
+/* UIC Command */
+#define DME_GET				0x01
+#define DME_SET				0x02
+#define DME_PEER_GET			0x03
+#define DME_PEER_SET			0x04
+#define DME_POWERON			0x10
+#define DME_POWEROFF			0x11
+#define DME_ENABLE			0x12
+#define DME_RESET			0x14
+#define DME_ENDPOINTRESET		0x15
+#define DME_LINKSTARTUP			0x16
+#define DME_HIBERNATE_ENTER		0x17
+#define DME_HIBERNATE_EXIT		0x18
+#define DME_TEST_MODE			0x1A
+
+#define GEN_SELECTOR_IDX(x)		((x) & 0xFFFF)
+
+#define CONFIG_RESULT_CODE_MASK		0xFF
+
+#define CDBCMD_TEST_UNIT_READY		0x00
+#define CDBCMD_READ_6			0x08
+#define CDBCMD_WRITE_6			0x0A
+#define CDBCMD_START_STOP_UNIT		0x1B
+#define CDBCMD_READ_CAPACITY_10		0x25
+#define CDBCMD_READ_10			0x28
+#define CDBCMD_WRITE_10			0x2A
+#define CDBCMD_READ_16			0x88
+#define CDBCMD_WRITE_16			0x8A
+#define CDBCMD_READ_CAPACITY_16		0x9E
+#define CDBCMD_REPORT_LUNS		0xA0
+
+#define UPIU_FLAGS_R			(1 << 6)
+#define UPIU_FLAGS_W			(1 << 5)
+#define UPIU_FLAGS_ATTR_MASK		(3 << 0)
+#define UPIU_FLAGS_ATTR_S		(0 << 0)	/* Simple */
+#define UPIU_FLAGS_ATTR_O		(1 << 0)	/* Ordered */
+#define UPIU_FLAGS_ATTR_HQ		(2 << 0)	/* Head of Queue */
+#define UPIU_FLAGS_ATTR_ACA		(3 << 0)
+#define UPIU_FLAGS_O			(1 << 6)
+#define UPIU_FLAGS_U			(1 << 5)
+#define UPIU_FLAGS_D			(1 << 4)
+
+#define QUERY_FUNC_STD_READ		0x01
+#define QUERY_FUNC_STD_WRITE		0x81
+
+#define QUERY_NOP			0x00
+#define QUERY_READ_DESC			0x01
+#define QUERY_WRITE_DESC		0x02
+#define QUERY_READ_ATTR			0x03
+#define QUERY_WRITE_ATTR		0x04
+#define QUERY_READ_FLAG			0x05
+#define QUERY_SET_FLAG			0x06
+#define QUERY_CLEAR_FLAG		0x07
+#define QUERY_TOGGLE_FLAG		0x08
+
+#define RW_WITHOUT_CACHE		0x18
+
+#define DESC_TYPE_DEVICE		0x00
+#define DESC_TYPE_CONFIGURATION		0x01
+#define DESC_TYPE_UNIT			0x02
+#define DESC_TYPE_INTERCONNECT		0x04
+#define DESC_TYPE_STRING		0x05
+
+#define DESC_DEVICE_MAX_SIZE		0x1F
+#define DEVICE_DESC_PARAM_MANF_ID	0x18
+
+#define ATTR_CUR_PWR_MODE		0x02	/* bCurrentPowerMode */
+#define ATTR_ACTIVECC			0x03	/* bActiveICCLevel */
+
+#define DEVICE_DESCRIPTOR_LEN		0x40
+#define UNIT_DESCRIPTOR_LEN		0x23
+
+#define QUERY_RESP_SUCCESS		0x00
+#define QUERY_RESP_OPCODE		0xFE
+#define QUERY_RESP_GENERAL_FAIL		0xFF
+
+#define SENSE_KEY_NO_SENSE		0x00
+#define SENSE_KEY_RECOVERED_ERROR	0x01
+#define SENSE_KEY_NOT_READY		0x02
+#define SENSE_KEY_MEDIUM_ERROR		0x03
+#define SENSE_KEY_HARDWARE_ERROR	0x04
+#define SENSE_KEY_ILLEGAL_REQUEST	0x05
+#define SENSE_KEY_UNIT_ATTENTION	0x06
+#define SENSE_KEY_DATA_PROTECT		0x07
+#define SENSE_KEY_BLANK_CHECK		0x08
+#define SENSE_KEY_VENDOR_SPECIFIC	0x09
+#define SENSE_KEY_COPY_ABORTED		0x0A
+#define SENSE_KEY_ABORTED_COMMAND	0x0B
+#define SENSE_KEY_VOLUME_OVERFLOW	0x0D
+#define SENSE_KEY_MISCOMPARE		0x0E
+
+#define SENSE_DATA_VALID		0x70
+#define SENSE_DATA_LENGTH		18
+
+#define READ_CAPACITY_LENGTH		8
+
+#define FLAG_DEVICE_INIT		0x01
+
+#define UFS_VENDOR_SKHYNIX		U(0x1AD)
+
+#define MAX_MODEL_LEN 16
+/**
+ * ufs_dev_desc - ufs device details from the device descriptor
+ * @wmanufacturerid: card details
+ * @model: card model
+ */
+struct ufs_dev_desc {
+	uint16_t wmanufacturerid;
+	int8_t model[MAX_MODEL_LEN + 1];
+};
+
+/* UFS Driver Flags */
+#define UFS_FLAGS_SKIPINIT		(1 << 0)
+#define UFS_FLAGS_VENDOR_SKHYNIX	(U(1) << 2)
+
+typedef struct sense_data {
+	uint8_t		resp_code : 7;
+	uint8_t		valid : 1;
+	uint8_t		reserved0;
+	uint8_t		sense_key : 4;
+	uint8_t		reserved1 : 1;
+	uint8_t		ili : 1;
+	uint8_t		eom : 1;
+	uint8_t		file_mark : 1;
+	uint8_t		info[4];
+	uint8_t		asl;
+	uint8_t		cmd_spec_len[4];
+	uint8_t		asc;
+	uint8_t		ascq;
+	uint8_t		fruc;
+	uint8_t		sense_key_spec0 : 7;
+	uint8_t		sksv : 1;
+	uint8_t		sense_key_spec1;
+	uint8_t		sense_key_spec2;
+} sense_data_t;
+
+/* UTP Transfer Request Descriptor */
+typedef struct utrd_header {
+	uint32_t	reserved0 : 24;
+	uint32_t	i : 1;		/* interrupt */
+	uint32_t	dd : 2;		/* data direction */
+	uint32_t	reserved1 : 1;
+	uint32_t	ct : 4;		/* command type */
+	uint32_t	reserved2;
+	uint32_t	ocs : 8;	/* Overall Command Status */
+	uint32_t	reserved3 : 24;
+	uint32_t	reserved4;
+	uint32_t	ucdba;		/* aligned to 128-byte */
+	uint32_t	ucdbau;		/* Upper 32-bits */
+	uint32_t	rul : 16;	/* Response UPIU Length */
+	uint32_t	ruo : 16;	/* Response UPIU Offset */
+	uint32_t	prdtl : 16;	/* PRDT Length */
+	uint32_t	prdto : 16;	/* PRDT Offset */
+} utrd_header_t;	/* 8 words with little endian */
+
+/* UTP Task Management Request Descriptor */
+typedef struct utp_utmrd {
+	/* 4 words with little endian */
+	uint32_t	reserved0 : 24;
+	uint32_t	i : 1;		/* interrupt */
+	uint32_t	reserved1 : 7;
+	uint32_t	reserved2;
+	uint32_t	ocs : 8;	/* Overall Command Status */
+	uint32_t	reserved3 : 24;
+	uint32_t	reserved4;
+
+	/* followed by 8 words UPIU with big endian */
+
+	/* followed by 8 words Response UPIU with big endian */
+} utp_utmrd_t;
+
+/* NOP OUT UPIU */
+typedef struct nop_out_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		reserved2;
+	uint8_t		reserved3;
+	uint8_t		reserved4;
+	uint8_t		total_ehs_len;
+	uint8_t		reserved5;
+	uint16_t	data_segment_len;
+	uint32_t	reserved6;
+	uint32_t	reserved7;
+	uint32_t	reserved8;
+	uint32_t	reserved9;
+	uint32_t	reserved10;
+	uint32_t	e2ecrc;
+} nop_out_upiu_t;	/* 36 bytes with big endian */
+
+/* NOP IN UPIU */
+typedef struct nop_in_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		reserved2;
+	uint8_t		response;
+	uint8_t		reserved3;
+	uint8_t		total_ehs_len;
+	uint8_t		dev_info;
+	uint16_t	data_segment_len;
+	uint32_t	reserved4;
+	uint32_t	reserved5;
+	uint32_t	reserved6;
+	uint32_t	reserved7;
+	uint32_t	reserved8;
+	uint32_t	e2ecrc;
+} nop_in_upiu_t;	/* 36 bytes with big endian */
+
+/* Command UPIU */
+typedef struct cmd_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		lun;
+	uint8_t		task_tag;
+	uint8_t		cmd_set_type;
+	uint8_t		reserved0;
+	uint8_t		reserved1;
+	uint8_t		reserved2;
+	uint8_t		total_ehs_len;
+	uint8_t		reserved3;
+	uint16_t	data_segment_len;
+	uint32_t	exp_data_trans_len;
+	/*
+	 * A CDB has a fixed length of 16bytes or a variable length
+	 * of between 12 and 260 bytes
+	 */
+	uint8_t		cdb[16];	/* little endian */
+} cmd_upiu_t;	/* 32 bytes with big endian except for cdb[] */
+
+typedef struct query_desc {
+	uint8_t		opcode;
+	uint8_t		idn;
+	uint8_t		index;
+	uint8_t		selector;
+	uint8_t		reserved0[2];
+	uint16_t	length;
+	uint32_t	reserved2[2];
+} query_desc_t;		/* 16 bytes with big endian */
+
+typedef struct query_flag {
+	uint8_t		opcode;
+	uint8_t		idn;
+	uint8_t		index;
+	uint8_t		selector;
+	uint8_t		reserved0[7];
+	uint8_t		value;
+	uint32_t	reserved8;
+} query_flag_t;		/* 16 bytes with big endian */
+
+typedef struct query_attr {
+	uint8_t		opcode;
+	uint8_t		idn;
+	uint8_t		index;
+	uint8_t		selector;
+	uint8_t		reserved0[4];
+	uint32_t	value;	/* little endian */
+	uint32_t	reserved4;
+} query_attr_t;		/* 16 bytes with big endian except for value */
+
+/* Query Request UPIU */
+typedef struct query_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		query_func;
+	uint8_t		reserved2;
+	uint8_t		reserved3;
+	uint8_t		total_ehs_len;
+	uint8_t		reserved4;
+	uint16_t	data_segment_len;
+	/* Transaction Specific Fields */
+	union {
+		query_desc_t	desc;
+		query_flag_t	flag;
+		query_attr_t	attr;
+	} ts;
+	uint32_t	reserved5;
+} query_upiu_t; /* 32 bytes with big endian */
+
+/* Query Response UPIU */
+typedef struct query_resp_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		query_func;
+	uint8_t		query_resp;
+	uint8_t		reserved2;
+	uint8_t		total_ehs_len;
+	uint8_t		dev_info;
+	uint16_t	data_segment_len;
+	union {
+		query_desc_t	desc;
+		query_flag_t	flag;
+		query_attr_t	attr;
+	} ts;
+	uint32_t	reserved3;
+} query_resp_upiu_t;	/* 32 bytes with big endian */
+
+/* Response UPIU */
+typedef struct resp_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		lun;
+	uint8_t		task_tag;
+	uint8_t		cmd_set_type;
+	uint8_t		reserved0;
+	uint8_t		reserved1;
+	uint8_t		status;
+	uint8_t		total_ehs_len;
+	uint8_t		dev_info;
+	uint16_t	data_segment_len;
+	uint32_t	res_trans_cnt;	/* Residual Transfer Count */
+	uint32_t	reserved2[4];
+	uint16_t	sense_data_len;
+	union {
+		uint8_t		sense_data[18];
+		sense_data_t	sense;
+	} sd;
+} resp_upiu_t;		/* 52 bytes with big endian */
+
+typedef struct cmd_info {
+	uintptr_t	buf;
+	size_t		length;
+	int		lba;
+	uint8_t		op;
+	uint8_t		direction;
+	uint8_t		lun;
+} cmd_info_t;
+
+typedef struct utp_utrd {
+	uintptr_t	header;		/* utrd_header_t */
+	uintptr_t	upiu;
+	uintptr_t	resp_upiu;
+	uintptr_t	prdt;
+	size_t		size_upiu;
+	size_t		size_resp_upiu;
+	size_t		size_prdt;
+	int		task_tag;
+} utp_utrd_t;
+
+/* Physical Region Description Table */
+typedef struct prdt {
+	uint32_t	dba;		/* Data Base Address */
+	uint32_t	dbau;		/* Data Base Address Upper 32-bits */
+	uint32_t	reserved0;
+	uint32_t	dbc : 18;	/* Data Byte Count */
+	uint32_t	reserved1 : 14;
+} prdt_t;
+
+typedef struct uic_cmd {
+	uint32_t	op;
+	uint32_t	arg1;
+	uint32_t	arg2;
+	uint32_t	arg3;
+} uic_cmd_t;
+
+typedef struct ufs_params {
+	uintptr_t	reg_base;
+	uintptr_t	desc_base;
+	size_t		desc_size;
+	unsigned long	flags;
+} ufs_params_t;
+
+typedef struct ufs_ops {
+	int		(*phy_init)(ufs_params_t *params);
+	int		(*phy_set_pwr_mode)(ufs_params_t *params);
+} ufs_ops_t;
+
+int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd);
+int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val);
+int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val);
+
+unsigned int ufs_read_attr(int idn);
+void ufs_write_attr(int idn, unsigned int value);
+unsigned int ufs_read_flag(int idn);
+void ufs_set_flag(int idn);
+void ufs_clear_flag(int idn);
+void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size);
+void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size);
+size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size);
+size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size);
+int ufs_init(const ufs_ops_t *ops, ufs_params_t *params);
+
+#endif /* UFS_H */
diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h
new file mode 100644
index 0000000..18bdb57
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp1-clks.h
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP1_CLKS_H_
+#define _DT_BINDINGS_STM32MP1_CLKS_H_
+
+/* OSCILLATOR clocks */
+#define CK_HSE		0
+#define CK_CSI		1
+#define CK_LSI		2
+#define CK_LSE		3
+#define CK_HSI		4
+#define CK_HSE_DIV2	5
+
+/* Bus clocks */
+#define TIM2		6
+#define TIM3		7
+#define TIM4		8
+#define TIM5		9
+#define TIM6		10
+#define TIM7		11
+#define TIM12		12
+#define TIM13		13
+#define TIM14		14
+#define LPTIM1		15
+#define SPI2		16
+#define SPI3		17
+#define USART2		18
+#define USART3		19
+#define UART4		20
+#define UART5		21
+#define UART7		22
+#define UART8		23
+#define I2C1		24
+#define I2C2		25
+#define I2C3		26
+#define I2C5		27
+#define SPDIF		28
+#define CEC		29
+#define DAC12		30
+#define MDIO		31
+#define TIM1		32
+#define TIM8		33
+#define TIM15		34
+#define TIM16		35
+#define TIM17		36
+#define SPI1		37
+#define SPI4		38
+#define SPI5		39
+#define USART6		40
+#define SAI1		41
+#define SAI2		42
+#define SAI3		43
+#define DFSDM		44
+#define FDCAN		45
+#define LPTIM2		46
+#define LPTIM3		47
+#define LPTIM4		48
+#define LPTIM5		49
+#define SAI4		50
+#define SYSCFG		51
+#define VREF		52
+#define TMPSENS		53
+#define PMBCTRL		54
+#define HDP		55
+#define LTDC		56
+#define DSI		57
+#define IWDG2		58
+#define USBPHY		59
+#define STGENRO		60
+#define SPI6		61
+#define I2C4		62
+#define I2C6		63
+#define USART1		64
+#define RTCAPB		65
+#define TZC1		66
+#define TZPC		67
+#define IWDG1		68
+#define BSEC		69
+#define STGEN		70
+#define DMA1		71
+#define DMA2		72
+#define DMAMUX		73
+#define ADC12		74
+#define USBO		75
+#define SDMMC3		76
+#define DCMI		77
+#define CRYP2		78
+#define HASH2		79
+#define RNG2		80
+#define CRC2		81
+#define HSEM		82
+#define IPCC		83
+#define GPIOA		84
+#define GPIOB		85
+#define GPIOC		86
+#define GPIOD		87
+#define GPIOE		88
+#define GPIOF		89
+#define GPIOG		90
+#define GPIOH		91
+#define GPIOI		92
+#define GPIOJ		93
+#define GPIOK		94
+#define GPIOZ		95
+#define CRYP1		96
+#define HASH1		97
+#define RNG1		98
+#define BKPSRAM		99
+#define MDMA		100
+#define GPU		101
+#define ETHCK		102
+#define ETHTX		103
+#define ETHRX		104
+#define ETHMAC		105
+#define FMC		106
+#define QSPI		107
+#define SDMMC1		108
+#define SDMMC2		109
+#define CRC1		110
+#define USBH		111
+#define ETHSTP		112
+#define TZC2		113
+
+/* Kernel clocks */
+#define SDMMC1_K	118
+#define SDMMC2_K	119
+#define SDMMC3_K	120
+#define FMC_K		121
+#define QSPI_K		122
+#define ETHCK_K		123
+#define RNG1_K		124
+#define RNG2_K		125
+#define GPU_K		126
+#define USBPHY_K	127
+#define STGEN_K		128
+#define SPDIF_K		129
+#define SPI1_K		130
+#define SPI2_K		131
+#define SPI3_K		132
+#define SPI4_K		133
+#define SPI5_K		134
+#define SPI6_K		135
+#define CEC_K		136
+#define I2C1_K		137
+#define I2C2_K		138
+#define I2C3_K		139
+#define I2C4_K		140
+#define I2C5_K		141
+#define I2C6_K		142
+#define LPTIM1_K	143
+#define LPTIM2_K	144
+#define LPTIM3_K	145
+#define LPTIM4_K	146
+#define LPTIM5_K	147
+#define USART1_K	148
+#define USART2_K	149
+#define USART3_K	150
+#define UART4_K		151
+#define UART5_K		152
+#define USART6_K	153
+#define UART7_K		154
+#define UART8_K		155
+#define DFSDM_K		156
+#define FDCAN_K		157
+#define SAI1_K		158
+#define SAI2_K		159
+#define SAI3_K		160
+#define SAI4_K		161
+#define ADC12_K		162
+#define DSI_K		163
+#define DSI_PX		164
+#define ADFSDM_K	165
+#define USBO_K		166
+#define LTDC_PX		167
+#define DAC12_K		168
+#define ETHPTP_K	169
+
+/* PLL */
+#define PLL1		176
+#define PLL2		177
+#define PLL3		178
+#define PLL4		179
+
+/* ODF */
+#define PLL1_P		180
+#define PLL1_Q		181
+#define PLL1_R		182
+#define PLL2_P		183
+#define PLL2_Q		184
+#define PLL2_R		185
+#define PLL3_P		186
+#define PLL3_Q		187
+#define PLL3_R		188
+#define PLL4_P		189
+#define PLL4_Q		190
+#define PLL4_R		191
+
+/* AUX */
+#define RTC		192
+
+/* MCLK */
+#define CK_PER		193
+#define CK_MPU		194
+#define CK_AXI		195
+#define CK_MCU		196
+
+/* Time base */
+#define TIM2_K		197
+#define TIM3_K		198
+#define TIM4_K		199
+#define TIM5_K		200
+#define TIM6_K		201
+#define TIM7_K		202
+#define TIM12_K		203
+#define TIM13_K		204
+#define TIM14_K		205
+#define TIM1_K		206
+#define TIM8_K		207
+#define TIM15_K		208
+#define TIM16_K		209
+#define TIM17_K		210
+
+/* MCO clocks */
+#define CK_MCO1		211
+#define CK_MCO2		212
+
+/* TRACE & DEBUG clocks */
+#define CK_DBG		214
+#define CK_TRACE	215
+
+/* DDR */
+#define DDRC1		220
+#define DDRC1LP		221
+#define DDRC2		222
+#define DDRC2LP		223
+#define DDRPHYC		224
+#define DDRPHYCLP	225
+#define DDRCAPB		226
+#define DDRCAPBLP	227
+#define AXIDCG		228
+#define DDRPHYCAPB	229
+#define DDRPHYCAPBLP	230
+#define DDRPERFM	231
+
+#define STM32MP1_LAST_CLK 232
+
+#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */
diff --git a/include/dt-bindings/clock/stm32mp1-clksrc.h b/include/dt-bindings/clock/stm32mp1-clksrc.h
new file mode 100644
index 0000000..818f4b7
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp1-clksrc.h
@@ -0,0 +1,283 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_
+#define _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_
+
+/* PLL output is enable when x=1, with x=p,q or r */
+#define PQR(p, q, r)	(((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2))
+
+/* st,clksrc: mandatory clock source */
+
+#define CLK_MPU_HSI		0x00000200
+#define CLK_MPU_HSE		0x00000201
+#define CLK_MPU_PLL1P		0x00000202
+#define CLK_MPU_PLL1P_DIV	0x00000203
+
+#define CLK_AXI_HSI		0x00000240
+#define CLK_AXI_HSE		0x00000241
+#define CLK_AXI_PLL2P		0x00000242
+
+#define CLK_MCU_HSI		0x00000480
+#define CLK_MCU_HSE		0x00000481
+#define CLK_MCU_CSI		0x00000482
+#define CLK_MCU_PLL3P		0x00000483
+
+#define CLK_PLL12_HSI		0x00000280
+#define CLK_PLL12_HSE		0x00000281
+
+#define CLK_PLL3_HSI		0x00008200
+#define CLK_PLL3_HSE		0x00008201
+#define CLK_PLL3_CSI		0x00008202
+
+#define CLK_PLL4_HSI		0x00008240
+#define CLK_PLL4_HSE		0x00008241
+#define CLK_PLL4_CSI		0x00008242
+#define CLK_PLL4_I2SCKIN	0x00008243
+
+#define CLK_RTC_DISABLED	0x00001400
+#define CLK_RTC_LSE		0x00001401
+#define CLK_RTC_LSI		0x00001402
+#define CLK_RTC_HSE		0x00001403
+
+#define CLK_MCO1_HSI		0x00008000
+#define CLK_MCO1_HSE		0x00008001
+#define CLK_MCO1_CSI		0x00008002
+#define CLK_MCO1_LSI		0x00008003
+#define CLK_MCO1_LSE		0x00008004
+#define CLK_MCO1_DISABLED	0x0000800F
+
+#define CLK_MCO2_MPU		0x00008040
+#define CLK_MCO2_AXI		0x00008041
+#define CLK_MCO2_MCU		0x00008042
+#define CLK_MCO2_PLL4P		0x00008043
+#define CLK_MCO2_HSE		0x00008044
+#define CLK_MCO2_HSI		0x00008045
+#define CLK_MCO2_DISABLED	0x0000804F
+
+/* st,pkcs: peripheral kernel clock source */
+
+#define CLK_I2C12_PCLK1		0x00008C00
+#define CLK_I2C12_PLL4R		0x00008C01
+#define CLK_I2C12_HSI		0x00008C02
+#define CLK_I2C12_CSI		0x00008C03
+#define CLK_I2C12_DISABLED	0x00008C07
+
+#define CLK_I2C35_PCLK1		0x00008C40
+#define CLK_I2C35_PLL4R		0x00008C41
+#define CLK_I2C35_HSI		0x00008C42
+#define CLK_I2C35_CSI		0x00008C43
+#define CLK_I2C35_DISABLED	0x00008C47
+
+#define CLK_I2C46_PCLK5		0x00000C00
+#define CLK_I2C46_PLL3Q		0x00000C01
+#define CLK_I2C46_HSI		0x00000C02
+#define CLK_I2C46_CSI		0x00000C03
+#define CLK_I2C46_DISABLED	0x00000C07
+
+#define CLK_SAI1_PLL4Q		0x00008C80
+#define CLK_SAI1_PLL3Q		0x00008C81
+#define CLK_SAI1_I2SCKIN	0x00008C82
+#define CLK_SAI1_CKPER		0x00008C83
+#define CLK_SAI1_PLL3R		0x00008C84
+#define CLK_SAI1_DISABLED	0x00008C87
+
+#define CLK_SAI2_PLL4Q		0x00008CC0
+#define CLK_SAI2_PLL3Q		0x00008CC1
+#define CLK_SAI2_I2SCKIN	0x00008CC2
+#define CLK_SAI2_CKPER		0x00008CC3
+#define CLK_SAI2_SPDIF		0x00008CC4
+#define CLK_SAI2_PLL3R		0x00008CC5
+#define CLK_SAI2_DISABLED	0x00008CC7
+
+#define CLK_SAI3_PLL4Q		0x00008D00
+#define CLK_SAI3_PLL3Q		0x00008D01
+#define CLK_SAI3_I2SCKIN	0x00008D02
+#define CLK_SAI3_CKPER		0x00008D03
+#define CLK_SAI3_PLL3R		0x00008D04
+#define CLK_SAI3_DISABLED	0x00008D07
+
+#define CLK_SAI4_PLL4Q		0x00008D40
+#define CLK_SAI4_PLL3Q		0x00008D41
+#define CLK_SAI4_I2SCKIN	0x00008D42
+#define CLK_SAI4_CKPER		0x00008D43
+#define CLK_SAI4_PLL3R		0x00008D44
+#define CLK_SAI4_DISABLED	0x00008D47
+
+#define CLK_SPI2S1_PLL4P	0x00008D80
+#define CLK_SPI2S1_PLL3Q	0x00008D81
+#define CLK_SPI2S1_I2SCKIN	0x00008D82
+#define CLK_SPI2S1_CKPER	0x00008D83
+#define CLK_SPI2S1_PLL3R	0x00008D84
+#define CLK_SPI2S1_DISABLED	0x00008D87
+
+#define CLK_SPI2S23_PLL4P	0x00008DC0
+#define CLK_SPI2S23_PLL3Q	0x00008DC1
+#define CLK_SPI2S23_I2SCKIN	0x00008DC2
+#define CLK_SPI2S23_CKPER	0x00008DC3
+#define CLK_SPI2S23_PLL3R	0x00008DC4
+#define CLK_SPI2S23_DISABLED	0x00008DC7
+
+#define CLK_SPI45_PCLK2		0x00008E00
+#define CLK_SPI45_PLL4Q		0x00008E01
+#define CLK_SPI45_HSI		0x00008E02
+#define CLK_SPI45_CSI		0x00008E03
+#define CLK_SPI45_HSE		0x00008E04
+#define CLK_SPI45_DISABLED	0x00008E07
+
+#define CLK_SPI6_PCLK5		0x00000C40
+#define CLK_SPI6_PLL4Q		0x00000C41
+#define CLK_SPI6_HSI		0x00000C42
+#define CLK_SPI6_CSI		0x00000C43
+#define CLK_SPI6_HSE		0x00000C44
+#define CLK_SPI6_PLL3Q		0x00000C45
+#define CLK_SPI6_DISABLED	0x00000C47
+
+#define CLK_UART6_PCLK2		0x00008E40
+#define CLK_UART6_PLL4Q		0x00008E41
+#define CLK_UART6_HSI		0x00008E42
+#define CLK_UART6_CSI		0x00008E43
+#define CLK_UART6_HSE		0x00008E44
+#define CLK_UART6_DISABLED	0x00008E47
+
+#define CLK_UART24_PCLK1	0x00008E80
+#define CLK_UART24_PLL4Q	0x00008E81
+#define CLK_UART24_HSI		0x00008E82
+#define CLK_UART24_CSI		0x00008E83
+#define CLK_UART24_HSE		0x00008E84
+#define CLK_UART24_DISABLED	0x00008E87
+
+#define CLK_UART35_PCLK1	0x00008EC0
+#define CLK_UART35_PLL4Q	0x00008EC1
+#define CLK_UART35_HSI		0x00008EC2
+#define CLK_UART35_CSI		0x00008EC3
+#define CLK_UART35_HSE		0x00008EC4
+#define CLK_UART35_DISABLED	0x00008EC7
+
+#define CLK_UART78_PCLK1	0x00008F00
+#define CLK_UART78_PLL4Q	0x00008F01
+#define CLK_UART78_HSI		0x00008F02
+#define CLK_UART78_CSI		0x00008F03
+#define CLK_UART78_HSE		0x00008F04
+#define CLK_UART78_DISABLED	0x00008F07
+
+#define CLK_UART1_PCLK5		0x00000C80
+#define CLK_UART1_PLL3Q		0x00000C81
+#define CLK_UART1_HSI		0x00000C82
+#define CLK_UART1_CSI		0x00000C83
+#define CLK_UART1_PLL4Q		0x00000C84
+#define CLK_UART1_HSE		0x00000C85
+#define CLK_UART1_DISABLED	0x00000C87
+
+#define CLK_SDMMC12_HCLK6	0x00008F40
+#define CLK_SDMMC12_PLL3R	0x00008F41
+#define CLK_SDMMC12_PLL4P	0x00008F42
+#define CLK_SDMMC12_HSI		0x00008F43
+#define CLK_SDMMC12_DISABLED	0x00008F47
+
+#define CLK_SDMMC3_HCLK2	0x00008F80
+#define CLK_SDMMC3_PLL3R	0x00008F81
+#define CLK_SDMMC3_PLL4P	0x00008F82
+#define CLK_SDMMC3_HSI		0x00008F83
+#define CLK_SDMMC3_DISABLED	0x00008F87
+
+#define CLK_ETH_PLL4P		0x00008FC0
+#define CLK_ETH_PLL3Q		0x00008FC1
+#define CLK_ETH_DISABLED	0x00008FC3
+
+#define CLK_QSPI_ACLK		0x00009000
+#define CLK_QSPI_PLL3R		0x00009001
+#define CLK_QSPI_PLL4P		0x00009002
+#define CLK_QSPI_CKPER		0x00009003
+
+#define CLK_FMC_ACLK		0x00009040
+#define CLK_FMC_PLL3R		0x00009041
+#define CLK_FMC_PLL4P		0x00009042
+#define CLK_FMC_CKPER		0x00009043
+
+#define CLK_FDCAN_HSE		0x000090C0
+#define CLK_FDCAN_PLL3Q		0x000090C1
+#define CLK_FDCAN_PLL4Q		0x000090C2
+#define CLK_FDCAN_PLL4R		0x000090C3
+
+#define CLK_SPDIF_PLL4P		0x00009140
+#define CLK_SPDIF_PLL3Q		0x00009141
+#define CLK_SPDIF_HSI		0x00009142
+#define CLK_SPDIF_DISABLED	0x00009143
+
+#define CLK_CEC_LSE		0x00009180
+#define CLK_CEC_LSI		0x00009181
+#define CLK_CEC_CSI_DIV122	0x00009182
+#define CLK_CEC_DISABLED	0x00009183
+
+#define CLK_USBPHY_HSE		0x000091C0
+#define CLK_USBPHY_PLL4R	0x000091C1
+#define CLK_USBPHY_HSE_DIV2	0x000091C2
+#define CLK_USBPHY_DISABLED	0x000091C3
+
+#define CLK_USBO_PLL4R		0x800091C0
+#define CLK_USBO_USBPHY		0x800091C1
+
+#define CLK_RNG1_CSI		0x00000CC0
+#define CLK_RNG1_PLL4R		0x00000CC1
+#define CLK_RNG1_LSE		0x00000CC2
+#define CLK_RNG1_LSI		0x00000CC3
+
+#define CLK_RNG2_CSI		0x00009200
+#define CLK_RNG2_PLL4R		0x00009201
+#define CLK_RNG2_LSE		0x00009202
+#define CLK_RNG2_LSI		0x00009203
+
+#define CLK_CKPER_HSI		0x00000D00
+#define CLK_CKPER_CSI		0x00000D01
+#define CLK_CKPER_HSE		0x00000D02
+#define CLK_CKPER_DISABLED	0x00000D03
+
+#define CLK_STGEN_HSI		0x00000D40
+#define CLK_STGEN_HSE		0x00000D41
+#define CLK_STGEN_DISABLED	0x00000D43
+
+#define CLK_DSI_DSIPLL		0x00009240
+#define CLK_DSI_PLL4P		0x00009241
+
+#define CLK_ADC_PLL4R		0x00009280
+#define CLK_ADC_CKPER		0x00009281
+#define CLK_ADC_PLL3Q		0x00009282
+#define CLK_ADC_DISABLED	0x00009283
+
+#define CLK_LPTIM45_PCLK3	0x000092C0
+#define CLK_LPTIM45_PLL4P	0x000092C1
+#define CLK_LPTIM45_PLL3Q	0x000092C2
+#define CLK_LPTIM45_LSE		0x000092C3
+#define CLK_LPTIM45_LSI		0x000092C4
+#define CLK_LPTIM45_CKPER	0x000092C5
+#define CLK_LPTIM45_DISABLED	0x000092C7
+
+#define CLK_LPTIM23_PCLK3	0x00009300
+#define CLK_LPTIM23_PLL4Q	0x00009301
+#define CLK_LPTIM23_CKPER	0x00009302
+#define CLK_LPTIM23_LSE		0x00009303
+#define CLK_LPTIM23_LSI		0x00009304
+#define CLK_LPTIM23_DISABLED	0x00009307
+
+#define CLK_LPTIM1_PCLK1	0x00009340
+#define CLK_LPTIM1_PLL4P	0x00009341
+#define CLK_LPTIM1_PLL3Q	0x00009342
+#define CLK_LPTIM1_LSE		0x00009343
+#define CLK_LPTIM1_LSI		0x00009344
+#define CLK_LPTIM1_CKPER	0x00009345
+#define CLK_LPTIM1_DISABLED	0x00009347
+
+/* define for st,pll /csg */
+#define SSCG_MODE_CENTER_SPREAD	0
+#define SSCG_MODE_DOWN_SPREAD	1
+
+/* define for st,drive */
+#define LSEDRV_LOWEST		0
+#define LSEDRV_MEDIUM_LOW	1
+#define LSEDRV_MEDIUM_HIGH	2
+#define LSEDRV_HIGHEST		3
+
+#endif
diff --git a/include/dt-bindings/interrupt-controller/arm-gic.h b/include/dt-bindings/interrupt-controller/arm-gic.h
new file mode 100644
index 0000000..aa9158c
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/arm-gic.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+/*
+ * This header provides constants for the ARM GIC.
+ */
+
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
+
+/* interrupt specifier cell 0 */
+
+#define GIC_SPI 0
+#define GIC_PPI 1
+
+#define IRQ_TYPE_NONE		0
+#define IRQ_TYPE_EDGE_RISING	1
+#define IRQ_TYPE_EDGE_FALLING	2
+#define IRQ_TYPE_EDGE_BOTH	(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
+#define IRQ_TYPE_LEVEL_HIGH	4
+#define IRQ_TYPE_LEVEL_LOW	8
+
+#endif
diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h
new file mode 100644
index 0000000..7f6e4b9
--- /dev/null
+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
+ * Author: Torgue Alexandre <alexandre.torgue@st.com> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32_PINFUNC_H
+#define _DT_BINDINGS_STM32_PINFUNC_H
+
+/*  define PIN modes */
+#define GPIO	0x0
+#define AF0	0x1
+#define AF1	0x2
+#define AF2	0x3
+#define AF3	0x4
+#define AF4	0x5
+#define AF5	0x6
+#define AF6	0x7
+#define AF7	0x8
+#define AF8	0x9
+#define AF9	0xa
+#define AF10	0xb
+#define AF11	0xc
+#define AF12	0xd
+#define AF13	0xe
+#define AF14	0xf
+#define AF15	0x10
+#define ANALOG	0x11
+
+/* define Pins number*/
+#define PIN_NO(port, line)	(((port) - 'A') * 0x10 + (line))
+
+#define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode))
+
+/*  package information */
+#define STM32MP157CAA	0x1
+#define STM32MP157CAB	0x2
+#define STM32MP157CAC	0x4
+#define STM32MP157CAD	0x8
+
+#endif /* _DT_BINDINGS_STM32_PINFUNC_H */
diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h
new file mode 100644
index 0000000..f0c3aae
--- /dev/null
+++ b/include/dt-bindings/reset/stm32mp1-resets.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP1_RESET_H_
+#define _DT_BINDINGS_STM32MP1_RESET_H_
+
+#define LTDC_R		3072
+#define DSI_R		3076
+#define DDRPERFM_R	3080
+#define USBPHY_R	3088
+#define SPI6_R		3136
+#define I2C4_R		3138
+#define I2C6_R		3139
+#define USART1_R	3140
+#define STGEN_R		3156
+#define GPIOZ_R		3200
+#define CRYP1_R		3204
+#define HASH1_R		3205
+#define RNG1_R		3206
+#define AXIM_R		3216
+#define GPU_R		3269
+#define ETHMAC_R	3274
+#define FMC_R		3276
+#define QSPI_R		3278
+#define SDMMC1_R	3280
+#define SDMMC2_R	3281
+#define CRC1_R		3284
+#define USBH_R		3288
+#define MDMA_R		3328
+#define MCU_R		8225
+#define TIM2_R		19456
+#define TIM3_R		19457
+#define TIM4_R		19458
+#define TIM5_R		19459
+#define TIM6_R		19460
+#define TIM7_R		19461
+#define TIM12_R		16462
+#define TIM13_R		16463
+#define TIM14_R		16464
+#define LPTIM1_R	19465
+#define SPI2_R		19467
+#define SPI3_R		19468
+#define USART2_R	19470
+#define USART3_R	19471
+#define UART4_R		19472
+#define UART5_R		19473
+#define UART7_R		19474
+#define UART8_R		19475
+#define I2C1_R		19477
+#define I2C2_R		19478
+#define I2C3_R		19479
+#define I2C5_R		19480
+#define SPDIF_R		19482
+#define CEC_R		19483
+#define DAC12_R		19485
+#define MDIO_R		19847
+#define TIM1_R		19520
+#define TIM8_R		19521
+#define TIM15_R		19522
+#define TIM16_R		19523
+#define TIM17_R		19524
+#define SPI1_R		19528
+#define SPI4_R		19529
+#define SPI5_R		19530
+#define USART6_R	19533
+#define SAI1_R		19536
+#define SAI2_R		19537
+#define SAI3_R		19538
+#define DFSDM_R		19540
+#define FDCAN_R		19544
+#define LPTIM2_R	19584
+#define LPTIM3_R	19585
+#define LPTIM4_R	19586
+#define LPTIM5_R	19587
+#define SAI4_R		19592
+#define SYSCFG_R	19595
+#define VREF_R		19597
+#define TMPSENS_R	19600
+#define PMBCTRL_R	19601
+#define DMA1_R		19648
+#define DMA2_R		19649
+#define DMAMUX_R	19650
+#define ADC12_R		19653
+#define USBO_R		19656
+#define SDMMC3_R	19664
+#define CAMITF_R	19712
+#define CRYP2_R		19716
+#define HASH2_R		19717
+#define RNG2_R		19718
+#define CRC2_R		19719
+#define HSEM_R		19723
+#define MBOX_R		19724
+#define GPIOA_R		19776
+#define GPIOB_R		19777
+#define GPIOC_R		19778
+#define GPIOD_R		19779
+#define GPIOE_R		19780
+#define GPIOF_R		19781
+#define GPIOG_R		19782
+#define GPIOH_R		19783
+#define GPIOI_R		19784
+#define GPIOJ_R		19785
+#define GPIOK_R		19786
+
+#endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */
diff --git a/include/export/README b/include/export/README
new file mode 100644
index 0000000..2de8d6b
--- /dev/null
+++ b/include/export/README
@@ -0,0 +1,33 @@
+All headers under include/export/ are export headers that are intended for
+inclusion in third-party code which needs to interact with TF-A data structures
+or interfaces. They must follow these special rules:
+
+- Header guards should start with ARM_TRUSTED_FIRMWARE_ to reduce clash risk.
+
+- All definitions should be sufficiently namespaced (e.g. with BL_ or TF_) to
+  make name clashes with third-party code unlikely.
+
+- They must not #include any headers except other export headers, and those
+  includes must use relative paths with "../double_quotes.h" notation.
+
+- They must not rely on any type definitions other that <stdint.h> types defined
+  in the ISO C standard (i.e. uint64_t is fine, but not u_register_t). They
+  should still not #include <stdint.h>. Instead, wrapper headers including
+  export headers need to ensure that they #include <stdint.h> earlier in their
+  include order.
+
+- They must not rely on any macro definitions other than those which are
+  pre-defined by all common compilers (e.g. __ASSEMBLER__ or __aarch64__).
+
+- They must only contain macro, type and structure definitions, no prototypes.
+
+- They should avoid using integer types with architecture-dependent widths
+  (e.g. long, uintptr_t, pointer types) where possible. (Some existing export
+  headers are violating this for now.)
+
+- Their names should always end in "_exp.h".
+
+- Normal TF-A code should never include export headers directly. Instead, it
+  should include a wrapper header that ensures the export header is included in
+  the right manner. (The wrapper header for include/export/x/y/z_exp.h should
+  normally be placed at include/x/y/z.h.)
diff --git a/include/export/common/bl_common_exp.h b/include/export/common/bl_common_exp.h
new file mode 100644
index 0000000..8f09017
--- /dev/null
+++ b/include/export/common/bl_common_exp.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_BL_COMMON_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_BL_COMMON_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#include "ep_info_exp.h"
+#include "tbbr/tbbr_img_def_exp.h"
+
+/*
+ * The following are used for image state attributes.
+ * Image can only be in one of the following state.
+ */
+#define IMAGE_STATE_RESET		U(0)
+#define IMAGE_STATE_COPIED		U(1)
+#define IMAGE_STATE_COPYING		U(2)
+#define IMAGE_STATE_AUTHENTICATED	U(3)
+#define IMAGE_STATE_EXECUTED		U(4)
+#define IMAGE_STATE_INTERRUPTED		U(5)
+
+#define IMAGE_ATTRIB_SKIP_LOADING	U(0x02)
+#define IMAGE_ATTRIB_PLAT_SETUP		U(0x04)
+
+#define INVALID_IMAGE_ID		U(0xFFFFFFFF)
+
+#ifndef __ASSEMBLER__
+
+/*****************************************************************************
+ * Image info binary provides information from the image loader that
+ * can be used by the firmware to manage available trusted RAM.
+ * More advanced firmware image formats can provide additional
+ * information that enables optimization or greater flexibility in the
+ * common firmware code
+ *****************************************************************************/
+typedef struct image_info {
+	param_header_t h;
+	uintptr_t image_base;   /* physical address of base of image */
+	uint32_t image_size;    /* bytes read from image file */
+	uint32_t image_max_size;
+} image_info_t;
+
+/* BL image node in the BL image execution sequence */
+typedef struct bl_params_node {
+	unsigned int image_id;
+	image_info_t *image_info;
+	entry_point_info_t *ep_info;
+	struct bl_params_node *next_params_info;
+} bl_params_node_t;
+
+/*
+ * BL image head node in the BL image execution sequence
+ * It is also used to pass information to next BL image.
+ */
+typedef struct bl_params {
+	param_header_t h;
+	bl_params_node_t *head;
+} bl_params_t;
+
+/*****************************************************************************
+ * The image descriptor struct definition.
+ *****************************************************************************/
+typedef struct image_desc {
+	/* Contains unique image id for the image. */
+	unsigned int image_id;
+	/*
+	 * This member contains Image state information.
+	 * Refer IMAGE_STATE_XXX defined above.
+	 */
+	unsigned int state;
+	uint32_t copied_size;	/* image size copied in blocks */
+	image_info_t image_info;
+	entry_point_info_t ep_info;
+} image_desc_t;
+
+/* BL image node in the BL image loading sequence */
+typedef struct bl_load_info_node {
+	unsigned int image_id;
+	image_info_t *image_info;
+	struct bl_load_info_node *next_load_info;
+} bl_load_info_node_t;
+
+/* BL image head node in the BL image loading sequence */
+typedef struct bl_load_info {
+	param_header_t h;
+	bl_load_info_node_t *head;
+} bl_load_info_t;
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_BL_COMMON_EXP_H */
diff --git a/include/export/common/ep_info_exp.h b/include/export/common/ep_info_exp.h
new file mode 100644
index 0000000..4c703e6
--- /dev/null
+++ b/include/export/common/ep_info_exp.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_EP_INFO_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_EP_INFO_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#include "../lib/utils_def_exp.h"
+#include "param_header_exp.h"
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the
+ * 'entry_point_info' structure at their correct offsets.
+ ******************************************************************************/
+#define ENTRY_POINT_INFO_PC_OFFSET	U(0x08)
+#ifdef __aarch64__
+#define ENTRY_POINT_INFO_ARGS_OFFSET	U(0x18)
+#else
+#define ENTRY_POINT_INFO_LR_SVC_OFFSET	U(0x10)
+#define ENTRY_POINT_INFO_ARGS_OFFSET	U(0x14)
+#endif
+
+/* Security state of the image. */
+#define EP_SECURITY_MASK	U(0x1)
+#define EP_SECURITY_SHIFT	U(0)
+#define EP_SECURE		U(0x0)
+#define EP_NON_SECURE		U(0x1)
+
+/* Endianness of the image. */
+#define EP_EE_MASK		U(0x2)
+#define EP_EE_SHIFT		U(1)
+#define EP_EE_LITTLE		U(0x0)
+#define EP_EE_BIG		U(0x2)
+#define EP_GET_EE(x)		((x) & EP_EE_MASK)
+#define EP_SET_EE(x, ee)	((x) = ((x) & ~EP_EE_MASK) | (ee))
+
+/* Enable or disable access to the secure timer from secure images. */
+#define EP_ST_MASK		U(0x4)
+#define EP_ST_SHIFT		U(2)
+#define EP_ST_DISABLE		U(0x0)
+#define EP_ST_ENABLE		U(0x4)
+#define EP_GET_ST(x)		((x) & EP_ST_MASK)
+#define EP_SET_ST(x, ee)	((x) = ((x) & ~EP_ST_MASK) | (ee))
+
+/* Determine if an image is executable or not. */
+#define EP_EXE_MASK		U(0x8)
+#define EP_EXE_SHIFT		U(3)
+#define EP_NON_EXECUTABLE	U(0x0)
+#define EP_EXECUTABLE		U(0x8)
+#define EP_GET_EXE(x)		((x) & EP_EXE_MASK)
+#define EP_SET_EXE(x, ee)	((x) = ((x) & ~EP_EXE_MASK) | (ee))
+
+/* Flag to indicate the first image that is executed. */
+#define EP_FIRST_EXE_MASK	U(0x10)
+#define EP_FIRST_EXE_SHIFT	U(4)
+#define EP_FIRST_EXE		U(0x10)
+#define EP_GET_FIRST_EXE(x)	((x) & EP_FIRST_EXE_MASK)
+#define EP_SET_FIRST_EXE(x, ee)	((x) = ((x) & ~EP_FIRST_EXE_MASK) | (ee))
+
+#ifndef __ASSEMBLER__
+
+typedef struct aapcs64_params {
+	uint64_t arg0;
+	uint64_t arg1;
+	uint64_t arg2;
+	uint64_t arg3;
+	uint64_t arg4;
+	uint64_t arg5;
+	uint64_t arg6;
+	uint64_t arg7;
+} aapcs64_params_t;
+
+typedef struct aapcs32_params {
+	uint32_t arg0;
+	uint32_t arg1;
+	uint32_t arg2;
+	uint32_t arg3;
+} aapcs32_params_t;
+
+/*****************************************************************************
+ * This structure represents the superset of information needed while
+ * switching exception levels. The only two mechanisms to do so are
+ * ERET & SMC. Security state is indicated using bit zero of header
+ * attribute
+ * NOTE: BL1 expects entrypoint followed by spsr at an offset from the start
+ * of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while
+ * processing SMC to jump to BL31.
+ *****************************************************************************/
+typedef struct entry_point_info {
+	param_header_t h;
+	uintptr_t pc;
+	uint32_t spsr;
+#ifdef __aarch64__
+	aapcs64_params_t args;
+#else
+	uintptr_t lr_svc;
+	aapcs32_params_t args;
+#endif
+} entry_point_info_t;
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_EP_INFO_EXP_H */
diff --git a/include/export/common/param_header_exp.h b/include/export/common/param_header_exp.h
new file mode 100644
index 0000000..15bb6f2
--- /dev/null
+++ b/include/export/common/param_header_exp.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_PARAM_HEADER_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_PARAM_HEADER_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#include "../lib/utils_def_exp.h"
+
+/* Param header types */
+#define PARAM_EP			U(0x01)
+#define PARAM_IMAGE_BINARY		U(0x02)
+#define PARAM_BL31			U(0x03)
+#define PARAM_BL_LOAD_INFO		U(0x04)
+#define PARAM_BL_PARAMS			U(0x05)
+#define PARAM_PSCI_LIB_ARGS		U(0x06)
+#define PARAM_SP_IMAGE_BOOT_INFO	U(0x07)
+
+/* Param header version */
+#define PARAM_VERSION_1			U(0x01)
+#define PARAM_VERSION_2			U(0x02)
+
+#ifndef __ASSEMBLER__
+
+/***************************************************************************
+ * This structure provides version information and the size of the
+ * structure, attributes for the structure it represents
+ ***************************************************************************/
+typedef struct param_header {
+	uint8_t type;		/* type of the structure */
+	uint8_t version;	/* version of this structure */
+	uint16_t size;		/* size of this structure in bytes */
+	uint32_t attr;		/* attributes: unused bits SBZ */
+} param_header_t;
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_PARAM_HEADER_EXP_H */
diff --git a/include/export/common/tbbr/tbbr_img_def_exp.h b/include/export/common/tbbr/tbbr_img_def_exp.h
new file mode 100644
index 0000000..ff0d16c
--- /dev/null
+++ b/include/export/common/tbbr/tbbr_img_def_exp.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#include "../../lib/utils_def_exp.h"
+
+/* Firmware Image Package */
+#define FIP_IMAGE_ID			U(0)
+
+/* Trusted Boot Firmware BL2 */
+#define BL2_IMAGE_ID			U(1)
+
+/* SCP Firmware SCP_BL2 */
+#define SCP_BL2_IMAGE_ID		U(2)
+
+/* EL3 Runtime Firmware BL31 */
+#define BL31_IMAGE_ID			U(3)
+
+/* Secure Payload BL32 (Trusted OS) */
+#define BL32_IMAGE_ID			U(4)
+
+/* Non-Trusted Firmware BL33 */
+#define BL33_IMAGE_ID			U(5)
+
+/* Certificates */
+#define TRUSTED_BOOT_FW_CERT_ID		U(6)
+#define TRUSTED_KEY_CERT_ID		U(7)
+
+#define SCP_FW_KEY_CERT_ID		U(8)
+#define SOC_FW_KEY_CERT_ID		U(9)
+#define TRUSTED_OS_FW_KEY_CERT_ID	U(10)
+#define NON_TRUSTED_FW_KEY_CERT_ID	U(11)
+
+#define SCP_FW_CONTENT_CERT_ID		U(12)
+#define SOC_FW_CONTENT_CERT_ID		U(13)
+#define TRUSTED_OS_FW_CONTENT_CERT_ID	U(14)
+#define NON_TRUSTED_FW_CONTENT_CERT_ID	U(15)
+
+/* Non-Trusted ROM Firmware NS_BL1U */
+#define NS_BL1U_IMAGE_ID		U(16)
+
+/* Trusted FWU Certificate */
+#define FWU_CERT_ID			U(17)
+
+/* Trusted FWU SCP Firmware SCP_BL2U */
+#define SCP_BL2U_IMAGE_ID		U(18)
+
+/* Trusted FWU Boot Firmware BL2U */
+#define BL2U_IMAGE_ID			U(19)
+
+/* Non-Trusted FWU Firmware NS_BL2U */
+#define NS_BL2U_IMAGE_ID		U(20)
+
+/* Secure Payload BL32_EXTRA1 (Trusted OS Extra1) */
+#define BL32_EXTRA1_IMAGE_ID		U(21)
+
+/* Secure Payload BL32_EXTRA2 (Trusted OS Extra2) */
+#define BL32_EXTRA2_IMAGE_ID		U(22)
+
+/* HW_CONFIG (e.g. Kernel DT) */
+#define HW_CONFIG_ID			U(23)
+
+/* TB_FW_CONFIG */
+#define TB_FW_CONFIG_ID			U(24)
+
+/* SOC_FW_CONFIG */
+#define SOC_FW_CONFIG_ID		U(25)
+
+/* TOS_FW_CONFIG */
+#define TOS_FW_CONFIG_ID		U(26)
+
+/* NT_FW_CONFIG */
+#define NT_FW_CONFIG_ID			U(27)
+
+/* GPT Partition */
+#define GPT_IMAGE_ID			U(28)
+
+/* Binary with STM32 header */
+#define STM32_IMAGE_ID			U(29)
+
+/* Define size of the array */
+#define MAX_NUMBER_IDS			U(30)
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H */
diff --git a/include/export/drivers/gpio_exp.h b/include/export/drivers/gpio_exp.h
new file mode 100644
index 0000000..a37f190
--- /dev/null
+++ b/include/export/drivers/gpio_exp.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#define ARM_TF_GPIO_DIR_OUT		0
+#define ARM_TF_GPIO_DIR_IN		1
+
+#define ARM_TF_GPIO_LEVEL_LOW		0
+#define ARM_TF_GPIO_LEVEL_HIGH		1
+
+#define ARM_TF_GPIO_PULL_NONE		0
+#define ARM_TF_GPIO_PULL_UP		1
+#define ARM_TF_GPIO_PULL_DOWN		2
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H */
diff --git a/include/export/lib/bl_aux_params/bl_aux_params_exp.h b/include/export/lib/bl_aux_params/bl_aux_params_exp.h
new file mode 100644
index 0000000..7391dec
--- /dev/null
+++ b/include/export/lib/bl_aux_params/bl_aux_params_exp.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_LIB_BL_AUX_PARAMS_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_LIB_BL_AUX_PARAMS_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#include "../../drivers/gpio_exp.h"
+
+/*
+ * This API implements a lightweight parameter passing mechanism that can be
+ * used to pass SoC Firmware configuration data from BL2 to BL31 by platforms or
+ * configurations that do not want to depend on libfdt. It is structured as a
+ * singly-linked list of parameter structures that all share the same common
+ * header but may have different (and differently-sized) structure bodies after
+ * that. The header contains a type field to indicate the parameter type (which
+ * is used to infer the structure length and how to interpret its contents) and
+ * a next pointer which contains the absolute physical address of the next
+ * parameter structure. The next pointer in the last structure block is set to
+ * NULL. The picture below shows how the parameters are kept in memory.
+ *
+ * head of list  ---> +----------------+ --+
+ *                    |      type      |   |
+ *                    +----------------+   |--> struct bl_aux_param
+ *               +----|      next      |   |
+ *               |    +----------------+ --+
+ *               |    | parameter data |
+ *               |    +----------------+
+ *               |
+ *               +--> +----------------+ --+
+ *                    |      type      |   |
+ *                    +----------------+   |--> struct bl_aux_param
+ *           NULL <---|      next      |   |
+ *                    +----------------+ --+
+ *                    | parameter data |
+ *                    +----------------+
+ *
+ * Note: The SCTLR_EL3.A bit (Alignment fault check enable) is set in TF-A, so
+ * BL2 must ensure that each parameter struct starts on a 64-bit aligned address
+ * to avoid alignment faults. Parameters may be allocated in any address range
+ * accessible at the time of BL31 handoff (e.g. SRAM, DRAM, SoC-internal scratch
+ * registers, etc.), in particular address ranges that may not be mapped in
+ * BL31's page tables, so the parameter list must be parsed before the MMU is
+ * enabled and any information that is required at a later point should be
+ * deep-copied out into BL31-internal data structures.
+ */
+
+enum bl_aux_param_type {
+	BL_AUX_PARAM_NONE = 0,
+	BL_AUX_PARAM_VENDOR_SPECIFIC_FIRST = 0x1,
+	/* 0x1 - 0x7fffffff can be used by vendor-specific handlers. */
+	BL_AUX_PARAM_VENDOR_SPECIFIC_LAST = 0x7fffffff,
+	BL_AUX_PARAM_GENERIC_FIRST = 0x80000001,
+	BL_AUX_PARAM_COREBOOT_TABLE = BL_AUX_PARAM_GENERIC_FIRST,
+	/* 0x80000001 - 0xffffffff are reserved for the generic handler. */
+	BL_AUX_PARAM_GENERIC_LAST = 0xffffffff,
+	/* Top 32 bits of the type field are reserved for future use. */
+};
+
+/* common header for all BL aux parameters */
+struct bl_aux_param_header {
+	uint64_t type;
+	uint64_t next;
+};
+
+/* commonly useful parameter structures that can be shared by multiple types */
+struct bl_aux_param_uint64 {
+	struct bl_aux_param_header h;
+	uint64_t value;
+};
+
+struct bl_aux_gpio_info {
+	uint8_t polarity;
+	uint8_t direction;
+	uint8_t pull_mode;
+	uint8_t reserved;
+	uint32_t index;
+};
+
+struct bl_aux_param_gpio {
+	struct bl_aux_param_header h;
+	struct bl_aux_gpio_info gpio;
+};
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_LIB_BL_AUX_PARAMS_EXP_H */
diff --git a/include/export/lib/utils_def_exp.h b/include/export/lib/utils_def_exp.h
new file mode 100644
index 0000000..86c409c
--- /dev/null
+++ b/include/export/lib/utils_def_exp.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef	ARM_TRUSTED_FIRMWARE_EXPORT_LIB_UTILS_DEF_EXP_H
+#define	ARM_TRUSTED_FIRMWARE_EXPORT_LIB_UTILS_DEF_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+/*
+ * For those constants to be shared between C and other sources, apply a 'U',
+ * 'UL', 'ULL', 'L' or 'LL' suffix to the argument only in C, to avoid
+ * undefined or unintended behaviour.
+ *
+ * The GNU assembler and linker do not support these suffixes (it causes the
+ * build process to fail) therefore the suffix is omitted when used in linker
+ * scripts and assembler files.
+*/
+#if defined(__ASSEMBLER__)
+# define   U(_x)	(_x)
+# define  UL(_x)	(_x)
+# define ULL(_x)	(_x)
+# define   L(_x)	(_x)
+# define  LL(_x)	(_x)
+#else
+# define   U(_x)	(_x##U)
+# define  UL(_x)	(_x##UL)
+# define ULL(_x)	(_x##ULL)
+# define   L(_x)	(_x##L)
+# define  LL(_x)	(_x##LL)
+#endif
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_LIB_UTILS_DEF_EXP_H */
diff --git a/include/export/plat/rockchip/common/plat_params_exp.h b/include/export/plat/rockchip/common/plat_params_exp.h
new file mode 100644
index 0000000..ccc9cd9
--- /dev/null
+++ b/include/export/plat/rockchip/common/plat_params_exp.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_ROCKCHIP_COMMON_PLAT_PARAMS_EXP_H
+#define ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_ROCKCHIP_COMMON_PLAT_PARAMS_EXP_H
+
+/* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */
+
+#include "../../../lib/bl_aux_params/bl_aux_params_exp.h"
+
+/* param type */
+enum bl_aux_rk_param_type {
+	BL_AUX_PARAM_RK_RESET_GPIO = BL_AUX_PARAM_VENDOR_SPECIFIC_FIRST,
+	BL_AUX_PARAM_RK_POWEROFF_GPIO,
+	BL_AUX_PARAM_RK_SUSPEND_GPIO,
+	BL_AUX_PARAM_RK_SUSPEND_APIO,
+};
+
+struct bl_aux_rk_apio_info {
+	uint8_t apio1 : 1;
+	uint8_t apio2 : 1;
+	uint8_t apio3 : 1;
+	uint8_t apio4 : 1;
+	uint8_t apio5 : 1;
+};
+
+struct bl_aux_param_rk_apio {
+	struct bl_aux_param_header h;
+	struct bl_aux_rk_apio_info apio;
+};
+
+#endif /* ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_ROCKCHIP_COMMON_PLAT_PARAMS_EXP_H */
diff --git a/include/lib/bakery_lock.h b/include/lib/bakery_lock.h
new file mode 100644
index 0000000..1fece01
--- /dev/null
+++ b/include/lib/bakery_lock.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BAKERY_LOCK_H
+#define BAKERY_LOCK_H
+
+#include <platform_def.h>
+
+#define BAKERY_LOCK_MAX_CPUS		PLATFORM_CORE_COUNT
+
+#ifndef __ASSEMBLER__
+#include <cdefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*****************************************************************************
+ * Internal helpers used by the bakery lock implementation.
+ ****************************************************************************/
+
+/* Convert a ticket to priority */
+static inline unsigned int bakery_get_priority(unsigned int t, unsigned int pos)
+{
+	return (t << 8) | pos;
+}
+
+#define CHOOSING_TICKET		U(0x1)
+#define CHOSEN_TICKET		U(0x0)
+
+static inline bool bakery_is_choosing(unsigned int info)
+{
+	return (info & 1U) == CHOOSING_TICKET;
+}
+
+static inline unsigned int bakery_ticket_number(unsigned int info)
+{
+	return (info >> 1) & 0x7FFFU;
+}
+
+static inline uint16_t make_bakery_data(unsigned int choosing, unsigned int num)
+{
+	unsigned int val = (choosing & 0x1U) | (num << 1);
+
+	return (uint16_t) val;
+}
+
+/*****************************************************************************
+ * External bakery lock interface.
+ ****************************************************************************/
+#if USE_COHERENT_MEM
+/*
+ * Bakery locks are stored in coherent memory
+ *
+ * Each lock's data is contiguous and fully allocated by the compiler
+ */
+
+typedef struct bakery_lock {
+	/*
+	 * The lock_data is a bit-field of 2 members:
+	 * Bit[0]       : choosing. This field is set when the CPU is
+	 *                choosing its bakery number.
+	 * Bits[1 - 15] : number. This is the bakery number allocated.
+	 */
+	volatile uint16_t lock_data[BAKERY_LOCK_MAX_CPUS];
+} bakery_lock_t;
+
+#else
+/*
+ * Bakery locks are stored in normal .bss memory
+ *
+ * Each lock's data is spread across multiple cache lines, one per CPU,
+ * but multiple locks can share the same cache line.
+ * The compiler will allocate enough memory for one CPU's bakery locks,
+ * the remaining cache lines are allocated by the linker script
+ */
+
+typedef struct bakery_info {
+	/*
+	 * The lock_data is a bit-field of 2 members:
+	 * Bit[0]       : choosing. This field is set when the CPU is
+	 *                choosing its bakery number.
+	 * Bits[1 - 15] : number. This is the bakery number allocated.
+	 */
+	volatile uint16_t lock_data;
+} bakery_info_t;
+
+typedef bakery_info_t bakery_lock_t;
+
+#endif /* __USE_COHERENT_MEM__ */
+
+static inline void bakery_lock_init(bakery_lock_t *bakery) {}
+void bakery_lock_get(bakery_lock_t *bakery);
+void bakery_lock_release(bakery_lock_t *bakery);
+
+#define DEFINE_BAKERY_LOCK(_name) bakery_lock_t _name __section("bakery_lock")
+
+#define DECLARE_BAKERY_LOCK(_name) extern bakery_lock_t _name
+
+
+#endif /* __ASSEMBLER__ */
+#endif /* BAKERY_LOCK_H */
diff --git a/include/lib/bl_aux_params/bl_aux_params.h b/include/lib/bl_aux_params/bl_aux_params.h
new file mode 100644
index 0000000..f6ce802
--- /dev/null
+++ b/include/lib/bl_aux_params/bl_aux_params.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef LIB_BL_AUX_PARAMS_H
+#define LIB_BL_AUX_PARAMS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <export/lib/bl_aux_params/bl_aux_params_exp.h>
+
+/*
+ * Handler function that handles an individual aux parameter. Return true if
+ * the parameter was handled, and flase if bl_aux_params_parse() should make its
+ * own attempt at handling it (for generic parameters).
+ */
+typedef bool (*bl_aux_param_handler_t)(struct bl_aux_param_header *param);
+
+/*
+ * Interprets head as the start of an aux parameter list, and passes the
+ * parameters individually to handler(). Handles generic parameters directly if
+ * handler() hasn't already done so. If only generic parameters are expected,
+ * handler() can be NULL.
+ */
+void bl_aux_params_parse(u_register_t head,
+			 bl_aux_param_handler_t handler);
+
+#endif /* LIB_BL_AUX_PARAMS_H */
diff --git a/include/lib/cassert.h b/include/lib/cassert.h
new file mode 100644
index 0000000..bbfdfdb
--- /dev/null
+++ b/include/lib/cassert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CASSERT_H
+#define CASSERT_H
+
+#include <cdefs.h>
+
+/*******************************************************************************
+ * Macro to flag a compile time assertion. It uses the preprocessor to generate
+ * an invalid C construct if 'cond' evaluates to false.
+ * The following compilation error is triggered if the assertion fails:
+ * "error: size of array 'msg' is negative"
+ * The 'unused' attribute ensures that the unused typedef does not emit a
+ * compiler warning.
+ ******************************************************************************/
+#define CASSERT(cond, msg)	\
+	typedef char msg[(cond) ? 1 : -1] __unused
+
+#endif /* CASSERT_H */
diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h
new file mode 100644
index 0000000..88212c3
--- /dev/null
+++ b/include/lib/coreboot.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef COREBOOT_H
+#define COREBOOT_H
+
+#include <stdint.h>
+
+typedef struct {
+	uint32_t type;			/* always 2 (memory-mapped) on ARM */
+	uint32_t baseaddr;
+	uint32_t baud;
+	uint32_t regwidth;		/* in bytes, i.e. usually 4 */
+	uint32_t input_hertz;
+	uint32_t uart_pci_addr;		/* unused on current ARM systems */
+} coreboot_serial_t;
+extern coreboot_serial_t coreboot_serial;
+
+void coreboot_table_setup(void *base);
+
+#endif /* COREBOOT_H */
diff --git a/include/lib/cpus/aarch32/aem_generic.h b/include/lib/cpus/aarch32/aem_generic.h
new file mode 100644
index 0000000..1d40cec
--- /dev/null
+++ b/include/lib/cpus/aarch32/aem_generic.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AEM_GENERIC_H
+#define AEM_GENERIC_H
+
+#include <lib/utils_def.h>
+
+/* BASE AEM midr for revision 0 */
+#define BASE_AEM_MIDR		U(0x410FD0F0)
+
+#endif /* AEM_GENERIC_H */
diff --git a/include/lib/cpus/aarch32/cortex_a12.h b/include/lib/cpus/aarch32/cortex_a12.h
new file mode 100644
index 0000000..abacdba
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a12.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A12_H
+#define CORTEX_A12_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Cortex-A12 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A12_MIDR			U(0x410FC0D0)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A12_ACTLR_SMP_BIT	(U(1) << 6)
+
+#endif /* CORTEX_A12_H */
diff --git a/include/lib/cpus/aarch32/cortex_a15.h b/include/lib/cpus/aarch32/cortex_a15.h
new file mode 100644
index 0000000..9526a9c
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a15.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A15_H
+#define CORTEX_A15_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Auxiliary Control Register 2 specific definitions.
+ ******************************************************************************/
+#define CORTEX_A15_ACTLR2			p15, 1, c15, c0, 4
+
+#define CORTEX_A15_ACTLR2_INV_DCC_BIT		(U(1) << 0)
+
+/*******************************************************************************
+ * Cortex-A15 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A15_MIDR			U(0x410FC0F0)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A15_ACTLR_INV_BTB_BIT	(U(1) << 0)
+#define CORTEX_A15_ACTLR_SMP_BIT	(U(1) << 6)
+
+#endif /* CORTEX_A15_H */
diff --git a/include/lib/cpus/aarch32/cortex_a17.h b/include/lib/cpus/aarch32/cortex_a17.h
new file mode 100644
index 0000000..89a8eb6
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a17.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A17_H
+#define CORTEX_A17_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Cortex-A17 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A17_MIDR			U(0x410FC0E0)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A17_ACTLR_SMP_BIT	(U(1) << 6)
+
+/*******************************************************************************
+ * Implementation defined register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A17_IMP_DEF_REG1		p15, 0, c15, c0, 1
+
+#endif /* CORTEX_A17_H */
diff --git a/include/lib/cpus/aarch32/cortex_a32.h b/include/lib/cpus/aarch32/cortex_a32.h
new file mode 100644
index 0000000..6ddd533
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a32.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A32_H
+#define CORTEX_A32_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A32 Main ID register for revision 0 */
+#define CORTEX_A32_MIDR				U(0x410FD010)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ * CPUECTLR_EL1 is an implementation-specific register.
+ ******************************************************************************/
+#define CORTEX_A32_CPUECTLR_EL1			p15, 1, c15
+#define CORTEX_A32_CPUECTLR_SMPEN_BIT		(ULL(1) << 6)
+
+#endif /* CORTEX_A32_H */
diff --git a/include/lib/cpus/aarch32/cortex_a5.h b/include/lib/cpus/aarch32/cortex_a5.h
new file mode 100644
index 0000000..76703b7
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a5.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A5_H
+#define CORTEX_A5_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Cortex-A8 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A5_MIDR			U(0x410FC050)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A5_ACTLR_SMP_BIT		(U(1) << 6)
+
+#endif /* CORTEX_A5_H */
diff --git a/include/lib/cpus/aarch32/cortex_a53.h b/include/lib/cpus/aarch32/cortex_a53.h
new file mode 100644
index 0000000..8dd0192
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a53.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A53_H
+#define CORTEX_A53_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A53 midr for revision 0 */
+#define CORTEX_A53_MIDR			U(0x410FD030)
+
+/* Retention timer tick definitions */
+#define RETENTION_ENTRY_TICKS_2		U(0x1)
+#define RETENTION_ENTRY_TICKS_8		U(0x2)
+#define RETENTION_ENTRY_TICKS_32	U(0x3)
+#define RETENTION_ENTRY_TICKS_64	U(0x4)
+#define RETENTION_ENTRY_TICKS_128	U(0x5)
+#define RETENTION_ENTRY_TICKS_256	U(0x6)
+#define RETENTION_ENTRY_TICKS_512	U(0x7)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_ECTLR			p15, 1, c15
+
+#define CORTEX_A53_ECTLR_SMP_BIT		(U(1) << 6)
+
+#define CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT	U(0)
+#define CORTEX_A53_ECTLR_CPU_RET_CTRL_MASK	(ULL(0x7) << CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT)
+
+#define CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT	U(3)
+#define CORTEX_A53_ECTLR_FPU_RET_CTRL_MASK	(ULL(0x7) << CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_MERRSR			p15, 2, c15
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_CPUACTLR			p15, 0, c15
+
+#define CORTEX_A53_CPUACTLR_ENDCCASCI_SHIFT	U(44)
+#define CORTEX_A53_CPUACTLR_ENDCCASCI		(ULL(1) << CORTEX_A53_CPUACTLR_ENDCCASCI_SHIFT)
+#define CORTEX_A53_CPUACTLR_DTAH_SHIFT		U(24)
+#define CORTEX_A53_CPUACTLR_DTAH		(ULL(1) << CORTEX_A53_CPUACTLR_DTAH_SHIFT)
+
+/*******************************************************************************
+ * L2 Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_L2ACTLR			p15, 1, c15, c0, 0
+
+#define CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN	(U(1) << 14)
+#define CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH	(U(1) << 3)
+
+/*******************************************************************************
+ * L2 Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_L2ECTLR			p15, 1, c9, c0, 3
+
+#define CORTEX_A53_L2ECTLR_RET_CTRL_SHIFT	U(0)
+#define CORTEX_A53_L2ECTLR_RET_CTRL_MASK	(U(0x7) << L2ECTLR_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_L2MERRSR			p15, 3, c15
+
+#endif /* CORTEX_A53_H */
diff --git a/include/lib/cpus/aarch32/cortex_a57.h b/include/lib/cpus/aarch32/cortex_a57.h
new file mode 100644
index 0000000..ffabd61
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a57.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A57_H
+#define CORTEX_A57_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A57 midr for revision 0 */
+#define CORTEX_A57_MIDR			U(0x410FD070)
+
+/* Retention timer tick definitions */
+#define RETENTION_ENTRY_TICKS_2		U(0x1)
+#define RETENTION_ENTRY_TICKS_8		U(0x2)
+#define RETENTION_ENTRY_TICKS_32	U(0x3)
+#define RETENTION_ENTRY_TICKS_64	U(0x4)
+#define RETENTION_ENTRY_TICKS_128	U(0x5)
+#define RETENTION_ENTRY_TICKS_256	U(0x6)
+#define RETENTION_ENTRY_TICKS_512	U(0x7)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_ECTLR			p15, 1, c15
+
+#define CORTEX_A57_ECTLR_SMP_BIT		(ULL(1) << 6)
+#define CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT	(ULL(1) << 38)
+#define CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK	(ULL(0x3) << 35)
+#define CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK	(ULL(0x3) << 32)
+
+#define CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT	U(0)
+#define CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK	(ULL(0x7) << CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_CPUMERRSR			p15, 2, c15
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_CPUACTLR				p15, 0, c15
+
+#define CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_DMB		(ULL(1) << 59)
+#define CORTEX_A57_CPUACTLR_DIS_DMB_NULLIFICATION	(ULL(1) << 58)
+#define CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_STORE		(ULL(1) << 55)
+#define CORTEX_A57_CPUACTLR_GRE_NGRE_AS_NGNRE		(ULL(1) << 54)
+#define CORTEX_A57_CPUACTLR_DIS_OVERREAD		(ULL(1) << 52)
+#define CORTEX_A57_CPUACTLR_NO_ALLOC_WBWA		(ULL(1) << 49)
+#define CORTEX_A57_CPUACTLR_DCC_AS_DCCI			(ULL(1) << 44)
+#define CORTEX_A57_CPUACTLR_FORCE_FPSCR_FLUSH		(ULL(1) << 38)
+#define CORTEX_A57_CPUACTLR_DIS_INSTR_PREFETCH		(ULL(1) << 32)
+#define CORTEX_A57_CPUACTLR_DIS_STREAMING		(ULL(3) << 27)
+#define CORTEX_A57_CPUACTLR_DIS_L1_STREAMING		(ULL(3) << 25)
+#define CORTEX_A57_CPUACTLR_DIS_INDIRECT_PREDICTOR	(ULL(1) << 4)
+
+/*******************************************************************************
+ * L2 Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_L2CTLR				p15, 1, c9, c0, 2
+
+#define CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT	U(0)
+#define CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT		U(6)
+
+#define CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES		U(0x2)
+#define CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES		U(0x2)
+
+/*******************************************************************************
+ * L2 Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_L2ECTLR			p15, 1, c9, c0, 3
+
+#define CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT	U(0)
+#define CORTEX_A57_L2ECTLR_RET_CTRL_MASK	(U(0x7) << CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_L2MERRSR			p15, 3, c15
+
+#endif /* CORTEX_A57_H */
diff --git a/include/lib/cpus/aarch32/cortex_a7.h b/include/lib/cpus/aarch32/cortex_a7.h
new file mode 100644
index 0000000..730fdb5
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a7.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A7_H
+#define CORTEX_A7_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Cortex-A7 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A7_MIDR			U(0x410FC070)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A7_ACTLR_SMP_BIT		(U(1) << 6)
+
+#endif /* CORTEX_A7_H */
diff --git a/include/lib/cpus/aarch32/cortex_a72.h b/include/lib/cpus/aarch32/cortex_a72.h
new file mode 100644
index 0000000..4b1af61
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a72.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A72_H
+#define CORTEX_A72_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A72 midr for revision 0 */
+#define CORTEX_A72_MIDR		U(0x410FD080)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_ECTLR				p15, 1, c15
+
+#define CORTEX_A72_ECTLR_SMP_BIT			(ULL(1) << 6)
+#define CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT		(ULL(1) << 38)
+#define CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK		(ULL(0x3) << 35)
+#define CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK		(ULL(0x3) << 32)
+
+/*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_MERRSR				p15, 2, c15
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_CPUACTLR				p15, 0, c15
+
+#define CORTEX_A72_CPUACTLR_DISABLE_L1_DCACHE_HW_PFTCH	(ULL(1) << 56)
+#define CORTEX_A72_CPUACTLR_DIS_LOAD_PASS_STORE		(ULL(1) << 55)
+#define CORTEX_A72_CPUACTLR_NO_ALLOC_WBWA		(ULL(1) << 49)
+#define CORTEX_A72_CPUACTLR_DCC_AS_DCCI			(ULL(1) << 44)
+#define CORTEX_A72_CPUACTLR_DIS_INSTR_PREFETCH		(ULL(1) << 32)
+
+/*******************************************************************************
+ * L2 Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_L2CTLR				p15, 1, c9, c0, 2
+
+#define CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT	U(0)
+#define CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT		U(6)
+
+#define CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES		U(0x2)
+#define CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES		U(0x1)
+#define CORTEX_A72_L2_TAG_RAM_LATENCY_3_CYCLES		U(0x2)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_L2MERRSR				p15, 3, c15
+
+#endif /* CORTEX_A72_H */
diff --git a/include/lib/cpus/aarch32/cortex_a9.h b/include/lib/cpus/aarch32/cortex_a9.h
new file mode 100644
index 0000000..a8c978a
--- /dev/null
+++ b/include/lib/cpus/aarch32/cortex_a9.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A9_H
+#define CORTEX_A9_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Cortex-A9 midr with version/revision set to 0
+ ******************************************************************************/
+#define CORTEX_A9_MIDR			U(0x410FC090)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A9_ACTLR_SMP_BIT		(U(1) << 6)
+#define CORTEX_A9_ACTLR_FLZW_BIT	(U(1) << 3)
+
+/*******************************************************************************
+ * CPU Power Control Register
+ ******************************************************************************/
+#define PCR		p15, 0, c15, c0, 0
+
+#ifndef __ASSEMBLER__
+#include <arch_helpers.h>
+DEFINE_COPROCR_RW_FUNCS(pcr, PCR)
+#endif
+
+#endif /* CORTEX_A9_H */
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S
new file mode 100644
index 0000000..a5ae6a4
--- /dev/null
+++ b/include/lib/cpus/aarch32/cpu_macros.S
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CPU_MACROS_S
+#define CPU_MACROS_S
+
+#include <arch.h>
+#include <lib/cpus/errata_report.h>
+
+#if defined(IMAGE_BL1) || defined(IMAGE_BL32)  || (defined(IMAGE_BL2) && BL2_AT_EL3)
+#define IMAGE_AT_EL3
+#endif
+
+#define CPU_IMPL_PN_MASK	(MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
+				(MIDR_PN_MASK << MIDR_PN_SHIFT)
+
+/* The number of CPU operations allowed */
+#define CPU_MAX_PWR_DWN_OPS		2
+
+/* Special constant to specify that CPU has no reset function */
+#define CPU_NO_RESET_FUNC		0
+
+/* Word size for 32-bit CPUs */
+#define CPU_WORD_SIZE			4
+
+/*
+ * Whether errata status needs reporting. Errata status is printed in debug
+ * builds for both BL1 and BL32 images.
+ */
+#if (defined(IMAGE_BL1) || defined(IMAGE_BL32)) && DEBUG
+# define REPORT_ERRATA	1
+#else
+# define REPORT_ERRATA	0
+#endif
+
+
+	.equ	CPU_MIDR_SIZE, CPU_WORD_SIZE
+	.equ	CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE
+	.equ	CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
+	.equ	CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE
+	.equ	CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE
+	.equ	CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE
+
+#ifndef IMAGE_AT_EL3
+	.equ	CPU_RESET_FUNC_SIZE, 0
+#endif
+
+/* The power down core and cluster is needed only in BL32 */
+#ifndef IMAGE_BL32
+	.equ	CPU_PWR_DWN_OPS_SIZE, 0
+#endif
+
+/* Fields required to print errata status  */
+#if !REPORT_ERRATA
+	.equ	CPU_ERRATA_FUNC_SIZE, 0
+#endif
+
+/* Only BL32 requires mutual exclusion and printed flag. */
+#if !(REPORT_ERRATA && defined(IMAGE_BL32))
+	.equ	CPU_ERRATA_LOCK_SIZE, 0
+	.equ	CPU_ERRATA_PRINTED_SIZE, 0
+#endif
+
+
+/*
+ * Define the offsets to the fields in cpu_ops structure.
+ * Every offset is defined based on the offset and size of the previous
+ * field.
+ */
+	.equ	CPU_MIDR, 0
+	.equ	CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE
+	.equ	CPU_PWR_DWN_OPS, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
+	.equ	CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
+	.equ	CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
+	.equ	CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
+	.equ	CPU_OPS_SIZE, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+
+	/*
+	 * Write given expressions as words
+	 *
+	 * _count:
+	 *	Write at least _count words. If the given number of expressions
+	 *	is less than _count, repeat the last expression to fill _count
+	 *	words in total
+	 * _rest:
+	 *	Optional list of expressions. _this is for parameter extraction
+	 *	only, and has no significance to the caller
+	 *
+	 * Invoked as:
+	 *	fill_constants 2, foo, bar, blah, ...
+	 */
+	.macro fill_constants _count:req, _this, _rest:vararg
+	  .ifgt \_count
+	    /* Write the current expression */
+	    .ifb \_this
+	      .error "Nothing to fill"
+	    .endif
+	    .word \_this
+
+	    /* Invoke recursively for remaining expressions */
+	    .ifnb \_rest
+	      fill_constants \_count-1, \_rest
+	    .else
+	      fill_constants \_count-1, \_this
+	    .endif
+	  .endif
+	.endm
+
+	/*
+	 * Declare CPU operations
+	 *
+	 * _name:
+	 *	Name of the CPU for which operations are being specified
+	 * _midr:
+	 *	Numeric value expected to read from CPU's MIDR
+	 * _resetfunc:
+	 *	Reset function for the CPU. If there's no CPU reset function,
+	 *	specify CPU_NO_RESET_FUNC
+	 * _power_down_ops:
+	 *	Comma-separated list of functions to perform power-down
+	 *	operatios on the CPU. At least one, and up to
+	 *	CPU_MAX_PWR_DWN_OPS number of functions may be specified.
+	 *	Starting at power level 0, these functions shall handle power
+	 *	down at subsequent power levels. If there aren't exactly
+	 *	CPU_MAX_PWR_DWN_OPS functions, the last specified one will be
+	 *	used to handle power down at subsequent levels
+	 */
+	.macro declare_cpu_ops _name:req, _midr:req, _resetfunc:req, \
+		_power_down_ops:vararg
+	.section cpu_ops, "a"
+	.align 2
+	.type cpu_ops_\_name, %object
+	.word \_midr
+#if defined(IMAGE_AT_EL3)
+	.word \_resetfunc
+#endif
+#ifdef IMAGE_BL32
+	/* Insert list of functions */
+	fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
+#endif
+
+#if REPORT_ERRATA
+	.ifndef \_name\()_cpu_str
+	  /*
+	   * Place errata reported flag, and the spinlock to arbitrate access to
+	   * it in the data section.
+	   */
+	  .pushsection .data
+	  define_asm_spinlock \_name\()_errata_lock
+	  \_name\()_errata_reported:
+	  .word	0
+	  .popsection
+
+	  /* Place CPU string in rodata */
+	  .pushsection .rodata
+	  \_name\()_cpu_str:
+	  .asciz "\_name"
+	  .popsection
+	.endif
+
+	/*
+	 * Mandatory errata status printing function for CPUs of
+	 * this class.
+	 */
+	.word \_name\()_errata_report
+
+#ifdef IMAGE_BL32
+	/* Pointers to errata lock and reported flag */
+	.word \_name\()_errata_lock
+	.word \_name\()_errata_reported
+#endif
+#endif
+	.endm
+
+#if REPORT_ERRATA
+	/*
+	 * Print status of a CPU errata
+	 *
+	 * _chosen:
+	 *	Identifier indicating whether or not a CPU errata has been
+	 *	compiled in.
+	 * _cpu:
+	 *	Name of the CPU
+	 * _id:
+	 *	Errata identifier
+	 * _rev_var:
+	 *	Register containing the combined value CPU revision and variant
+	 *	- typically the return value of cpu_get_rev_var
+	 */
+	.macro report_errata _chosen, _cpu, _id, _rev_var=r4
+	/* Stash a string with errata ID */
+	.pushsection .rodata
+	\_cpu\()_errata_\_id\()_str:
+	.asciz	"\_id"
+	.popsection
+
+	/* Check whether errata applies */
+	mov	r0, \_rev_var
+	bl	check_errata_\_id
+
+	.ifeq \_chosen
+	/*
+	 * Errata workaround has not been compiled in. If the errata would have
+	 * applied had it been compiled in, print its status as missing.
+	 */
+	cmp	r0, #0
+	movne	r0, #ERRATA_MISSING
+	.endif
+	ldr	r1, =\_cpu\()_cpu_str
+	ldr	r2, =\_cpu\()_errata_\_id\()_str
+	bl	errata_print_msg
+	.endm
+#endif
+	/*
+	 * Helper macro that reads the part number of the current CPU and jumps
+	 * to the given label if it matches the CPU MIDR provided.
+	 *
+	 * Clobbers: r0-r1
+	 */
+	.macro  jump_if_cpu_midr _cpu_midr, _label
+	ldcopr	r0, MIDR
+	ubfx	r0, r0, #MIDR_PN_SHIFT, #12
+	ldr	r1, =((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+	cmp	r0, r1
+	beq	\_label
+	.endm
+
+#endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/aarch64/aem_generic.h b/include/lib/cpus/aarch64/aem_generic.h
new file mode 100644
index 0000000..6bb30a2
--- /dev/null
+++ b/include/lib/cpus/aarch64/aem_generic.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AEM_GENERIC_H
+#define AEM_GENERIC_H
+
+#include <lib/utils_def.h>
+
+/* BASE AEM midr for revision 0 */
+#define BASE_AEM_MIDR		U(0x410FD0F0)
+
+/* Foundation AEM midr for revision 0 */
+#define FOUNDATION_AEM_MIDR	U(0x410FD000)
+
+#endif /* AEM_GENERIC_H */
diff --git a/include/lib/cpus/aarch64/cortex_a35.h b/include/lib/cpus/aarch64/cortex_a35.h
new file mode 100644
index 0000000..5421478
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a35.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A35_H
+#define CORTEX_A35_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A35 Main ID register for revision 0 */
+#define CORTEX_A35_MIDR				U(0x410FD040)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ * CPUECTLR_EL1 is an implementation-specific register.
+ ******************************************************************************/
+#define CORTEX_A35_CPUECTLR_EL1			S3_1_C15_C2_1
+#define CORTEX_A35_CPUECTLR_SMPEN_BIT		(ULL(1) << 6)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A35_CPUACTLR_EL1			S3_1_C15_C2_0
+
+#define CORTEX_A35_CPUACTLR_EL1_ENDCCASCI	(ULL(1) << 44)
+
+#endif /* CORTEX_A35_H */
diff --git a/include/lib/cpus/aarch64/cortex_a53.h b/include/lib/cpus/aarch64/cortex_a53.h
new file mode 100644
index 0000000..09db12b
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a53.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A53_H
+#define CORTEX_A53_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A53 midr for revision 0 */
+#define CORTEX_A53_MIDR			U(0x410FD030)
+
+/* Retention timer tick definitions */
+#define RETENTION_ENTRY_TICKS_2		U(0x1)
+#define RETENTION_ENTRY_TICKS_8		U(0x2)
+#define RETENTION_ENTRY_TICKS_32	U(0x3)
+#define RETENTION_ENTRY_TICKS_64	U(0x4)
+#define RETENTION_ENTRY_TICKS_128	U(0x5)
+#define RETENTION_ENTRY_TICKS_256	U(0x6)
+#define RETENTION_ENTRY_TICKS_512	U(0x7)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_ECTLR_EL1				S3_1_C15_C2_1
+
+#define CORTEX_A53_ECTLR_SMP_BIT			(ULL(1) << 6)
+
+#define CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT		U(0)
+#define CORTEX_A53_ECTLR_CPU_RET_CTRL_MASK		(ULL(0x7) << CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT)
+
+#define CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT		U(3)
+#define CORTEX_A53_ECTLR_FPU_RET_CTRL_MASK		(ULL(0x7) << CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_MERRSR_EL1				S3_1_C15_C2_2
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_CPUACTLR_EL1				S3_1_C15_C2_0
+
+#define CORTEX_A53_CPUACTLR_EL1_ENDCCASCI_SHIFT		U(44)
+#define CORTEX_A53_CPUACTLR_EL1_ENDCCASCI		(ULL(1) << CORTEX_A53_CPUACTLR_EL1_ENDCCASCI_SHIFT)
+#define CORTEX_A53_CPUACTLR_EL1_RADIS_SHIFT		U(27)
+#define CORTEX_A53_CPUACTLR_EL1_RADIS			(ULL(3) << CORTEX_A53_CPUACTLR_EL1_RADIS_SHIFT)
+#define CORTEX_A53_CPUACTLR_EL1_L1RADIS_SHIFT		U(25)
+#define CORTEX_A53_CPUACTLR_EL1_L1RADIS			(ULL(3) << CORTEX_A53_CPUACTLR_EL1_L1RADIS_SHIFT)
+#define CORTEX_A53_CPUACTLR_EL1_DTAH_SHIFT		U(24)
+#define CORTEX_A53_CPUACTLR_EL1_DTAH			(ULL(1) << CORTEX_A53_CPUACTLR_EL1_DTAH_SHIFT)
+
+/*******************************************************************************
+ * L2 Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_L2ACTLR_EL1				S3_1_C15_C0_0
+
+#define CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN		(U(1) << 14)
+#define CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH		(U(1) << 3)
+/*******************************************************************************
+ * L2 Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_L2ECTLR_EL1				S3_1_C11_C0_3
+
+#define CORTEX_A53_L2ECTLR_RET_CTRL_SHIFT		U(0)
+#define CORTEX_A53_L2ECTLR_RET_CTRL_MASK		(U(0x7) << L2ECTLR_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A53_L2MERRSR_EL1				S3_1_C15_C2_3
+
+#endif /* CORTEX_A53_H */
diff --git a/include/lib/cpus/aarch64/cortex_a55.h b/include/lib/cpus/aarch64/cortex_a55.h
new file mode 100644
index 0000000..60ed957
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a55.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A55_H
+#define CORTEX_A55_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A55 MIDR for revision 0 */
+#define CORTEX_A55_MIDR			U(0x410fd050)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A55_CPUPWRCTLR_EL1	S3_0_C15_C2_7
+#define CORTEX_A55_CPUECTLR_EL1		S3_0_C15_C1_4
+
+#define CORTEX_A55_CPUECTLR_EL1_L1WSCTL	(ULL(3) << 25)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A55_CPUACTLR_EL1				S3_0_C15_C1_0
+
+#define CORTEX_A55_CPUACTLR_EL1_DISABLE_WRITE_STREAMING	(ULL(1) << 24)
+#define CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE	(ULL(1) << 31)
+#define CORTEX_A55_CPUACTLR_EL1_DISABLE_L1_PAGEWALKS	(ULL(1) << 49)
+
+/*******************************************************************************
+ * CPU Identification register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A55_CLIDR_EL1				S3_1_C0_C0_1
+
+#define CORTEX_A55_CLIDR_EL1_CTYPE3			(ULL(7) << 6)
+
+/* Definitions of register field mask in CORTEX_A55_CPUPWRCTLR_EL1 */
+#define CORTEX_A55_CORE_PWRDN_EN_MASK	U(0x1)
+
+/* Instruction patching registers */
+#define CPUPSELR_EL3	S3_6_C15_C8_0
+#define CPUPCR_EL3	S3_6_C15_C8_1
+#define CPUPOR_EL3	S3_6_C15_C8_2
+#define CPUPMR_EL3	S3_6_C15_C8_3
+
+#endif /* CORTEX_A55_H */
diff --git a/include/lib/cpus/aarch64/cortex_a57.h b/include/lib/cpus/aarch64/cortex_a57.h
new file mode 100644
index 0000000..102ff60
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a57.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A57_H
+#define CORTEX_A57_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A57 midr for revision 0 */
+#define CORTEX_A57_MIDR			U(0x410FD070)
+
+/* Retention timer tick definitions */
+#define RETENTION_ENTRY_TICKS_2		U(0x1)
+#define RETENTION_ENTRY_TICKS_8		U(0x2)
+#define RETENTION_ENTRY_TICKS_32	U(0x3)
+#define RETENTION_ENTRY_TICKS_64	U(0x4)
+#define RETENTION_ENTRY_TICKS_128	U(0x5)
+#define RETENTION_ENTRY_TICKS_256	U(0x6)
+#define RETENTION_ENTRY_TICKS_512	U(0x7)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_ECTLR_EL1			S3_1_C15_C2_1
+
+#define CORTEX_A57_ECTLR_SMP_BIT		(ULL(1) << 6)
+#define CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT	(ULL(1) << 38)
+#define CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK	(ULL(0x3) << 35)
+#define CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK	(ULL(0x3) << 32)
+
+#define CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT	U(0)
+#define CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK	(ULL(0x7) << CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_MERRSR_EL1			S3_1_C15_C2_2
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_CPUACTLR_EL1				S3_1_C15_C2_0
+
+#define CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_DMB	(ULL(1) << 59)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_DMB_NULLIFICATION	(ULL(1) << 58)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_STORE	(ULL(1) << 55)
+#define CORTEX_A57_CPUACTLR_EL1_GRE_NGRE_AS_NGNRE	(ULL(1) << 54)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_OVERREAD		(ULL(1) << 52)
+#define CORTEX_A57_CPUACTLR_EL1_NO_ALLOC_WBWA		(ULL(1) << 49)
+#define CORTEX_A57_CPUACTLR_EL1_DCC_AS_DCCI		(ULL(1) << 44)
+#define CORTEX_A57_CPUACTLR_EL1_FORCE_FPSCR_FLUSH	(ULL(1) << 38)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_INSTR_PREFETCH	(ULL(1) << 32)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_STREAMING		(ULL(3) << 27)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_L1_STREAMING	(ULL(3) << 25)
+#define CORTEX_A57_CPUACTLR_EL1_DIS_INDIRECT_PREDICTOR	(ULL(1) << 4)
+
+/*******************************************************************************
+ * L2 Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_L2CTLR_EL1				S3_1_C11_C0_2
+
+#define CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT	U(0)
+#define CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT		U(6)
+
+#define CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES		U(0x2)
+#define CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES		U(0x2)
+
+#define CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT		(U(1) << 21)
+
+/*******************************************************************************
+ * L2 Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_L2ECTLR_EL1			S3_1_C11_C0_3
+
+#define CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT	U(0)
+#define CORTEX_A57_L2ECTLR_RET_CTRL_MASK	(U(0x7) << CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A57_L2MERRSR_EL1			S3_1_C15_C2_3
+
+#endif /* CORTEX_A57_H */
diff --git a/include/lib/cpus/aarch64/cortex_a72.h b/include/lib/cpus/aarch64/cortex_a72.h
new file mode 100644
index 0000000..4a444c6
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a72.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A72_H
+#define CORTEX_A72_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A72 midr for revision 0 */
+#define CORTEX_A72_MIDR 				U(0x410FD080)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_ECTLR_EL1				S3_1_C15_C2_1
+
+#define CORTEX_A72_ECTLR_SMP_BIT			(ULL(1) << 6)
+#define CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT		(ULL(1) << 38)
+#define CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK		(ULL(0x3) << 35)
+#define CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK		(ULL(0x3) << 32)
+
+/*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_MERRSR_EL1				S3_1_C15_C2_2
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_CPUACTLR_EL1					S3_1_C15_C2_0
+
+#define CORTEX_A72_CPUACTLR_EL1_DISABLE_L1_DCACHE_HW_PFTCH	(ULL(1) << 56)
+#define CORTEX_A72_CPUACTLR_EL1_DIS_LOAD_PASS_STORE		(ULL(1) << 55)
+#define CORTEX_A72_CPUACTLR_EL1_NO_ALLOC_WBWA			(ULL(1) << 49)
+#define CORTEX_A72_CPUACTLR_EL1_DCC_AS_DCCI			(ULL(1) << 44)
+#define CORTEX_A72_CPUACTLR_EL1_DIS_INSTR_PREFETCH		(ULL(1) << 32)
+
+/*******************************************************************************
+ *  L2 Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_L2ACTLR_EL1					S3_1_C15_C0_0
+
+#define CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN			(ULL(1) << 14)
+
+/*******************************************************************************
+ * L2 Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_L2CTLR_EL1				S3_1_C11_C0_2
+
+#define CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT	U(0)
+#define CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT		U(6)
+
+#define CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES		U(0x2)
+#define CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES		U(0x1)
+#define CORTEX_A72_L2_TAG_RAM_LATENCY_3_CYCLES		U(0x2)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A72_L2MERRSR_EL1				S3_1_C15_C2_3
+
+#endif /* CORTEX_A72_H */
diff --git a/include/lib/cpus/aarch64/cortex_a73.h b/include/lib/cpus/aarch64/cortex_a73.h
new file mode 100644
index 0000000..1238c0e
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a73.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A73_H
+#define CORTEX_A73_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A73 midr for revision 0 */
+#define CORTEX_A73_MIDR			U(0x410FD090)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A73_CPUECTLR_EL1		S3_1_C15_C2_1	/* Instruction def. */
+
+#define CORTEX_A73_CPUECTLR_SMP_BIT	(ULL(1) << 6)
+
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A73_L2MERRSR_EL1		S3_1_C15_C2_3   /* Instruction def. */
+
+/*******************************************************************************
+ * CPU implementation defined register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A73_IMP_DEF_REG1		S3_0_C15_C0_0
+
+#define CORTEX_A73_IMP_DEF_REG1_DISABLE_LOAD_PASS_STORE	(ULL(1) << 3)
+
+#define CORTEX_A73_DIAGNOSTIC_REGISTER	S3_0_C15_C0_1
+
+#define CORTEX_A73_IMP_DEF_REG2		S3_0_C15_C0_2
+
+#endif /* CORTEX_A73_H */
diff --git a/include/lib/cpus/aarch64/cortex_a75.h b/include/lib/cpus/aarch64/cortex_a75.h
new file mode 100644
index 0000000..e5ca1ba
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a75.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A75_H
+#define CORTEX_A75_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A75 MIDR */
+#define CORTEX_A75_MIDR		U(0x410fd0a0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A75_CPUPWRCTLR_EL1	S3_0_C15_C2_7
+#define CORTEX_A75_CPUECTLR_EL1		S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A75_CPUACTLR_EL1		S3_0_C15_C1_0
+
+#define CORTEX_A75_CPUACTLR_EL1_DISABLE_LOAD_PASS_STORE	(ULL(1) << 35)
+
+/* Definitions of register field mask in CORTEX_A75_CPUPWRCTLR_EL1 */
+#define CORTEX_A75_CORE_PWRDN_EN_MASK	U(0x1)
+
+#define CORTEX_A75_ACTLR_AMEN_BIT	(ULL(1) << 4)
+
+/*
+ * The Cortex-A75 core implements five counters, 0-4. Events 0, 1, 2, are
+ * fixed and are enabled (Group 0). Events 3 and 4 (Group 1) are
+ * programmable by programming the appropriate Event count bits in
+ * CPUAMEVTYPER<n> register and are disabled by default. Platforms may
+ * enable this with suitable programming.
+ */
+#define CORTEX_A75_AMU_NR_COUNTERS	U(5)
+#define CORTEX_A75_AMU_GROUP0_MASK	U(0x7)
+#define CORTEX_A75_AMU_GROUP1_MASK	(U(0) << 3)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+uint64_t cortex_a75_amu_cnt_read(int idx);
+void cortex_a75_amu_cnt_write(int idx, uint64_t val);
+unsigned int cortex_a75_amu_read_cpuamcntenset_el0(void);
+unsigned int cortex_a75_amu_read_cpuamcntenclr_el0(void);
+void cortex_a75_amu_write_cpuamcntenset_el0(unsigned int mask);
+void cortex_a75_amu_write_cpuamcntenclr_el0(unsigned int mask);
+#endif /* __ASSEMBLER__ */
+
+#endif /* CORTEX_A75_H */
diff --git a/include/lib/cpus/aarch64/cortex_a76.h b/include/lib/cpus/aarch64/cortex_a76.h
new file mode 100644
index 0000000..7dc7e06
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a76.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A76_H
+#define CORTEX_A76_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A76 MIDR for revision 0 */
+#define CORTEX_A76_MIDR		U(0x410fd0b0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A76_CPUPWRCTLR_EL1	S3_0_C15_C2_7
+#define CORTEX_A76_CPUECTLR_EL1		S3_0_C15_C1_4
+
+#define CORTEX_A76_CPUECTLR_EL1_WS_THR_L2	(ULL(3) << 24)
+#define CORTEX_A76_CPUECTLR_EL1_BIT_51		(ULL(1) << 51)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A76_CPUACTLR_EL1		S3_0_C15_C1_0
+
+#define CORTEX_A76_CPUACTLR_EL1_DISABLE_STATIC_PREDICTION	(ULL(1) << 6)
+
+#define CORTEX_A76_CPUACTLR_EL1_BIT_13	(ULL(1) << 13)
+
+#define CORTEX_A76_CPUACTLR2_EL1	S3_0_C15_C1_1
+
+#define CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE	(ULL(1) << 16)
+
+#define CORTEX_A76_CPUACTLR3_EL1	S3_0_C15_C1_2
+
+#define CORTEX_A76_CPUACTLR3_EL1_BIT_10	(ULL(1) << 10)
+
+
+/* Definitions of register field mask in CORTEX_A76_CPUPWRCTLR_EL1 */
+#define CORTEX_A76_CORE_PWRDN_EN_MASK	U(0x1)
+
+#endif /* CORTEX_A76_H */
diff --git a/include/lib/cpus/aarch64/cortex_a76ae.h b/include/lib/cpus/aarch64/cortex_a76ae.h
new file mode 100644
index 0000000..9e34efb
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a76ae.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A76AE_H
+#define CORTEX_A76AE_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A76AE MIDR for revision 0 */
+#define CORTEX_A76AE_MIDR		U(0x410FD0E0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A76AE_CPUPWRCTLR_EL1	S3_0_C15_C2_7
+
+/* Definitions of register field mask in CORTEX_A76AE_CPUPWRCTLR_EL1 */
+#define CORTEX_A76AE_CORE_PWRDN_EN_MASK	U(0x1)
+
+#define CORTEX_A76AE_CPUECTLR_EL1	S3_0_C15_C1_4
+
+#endif /* CORTEX_A76AE_H */
diff --git a/include/lib/cpus/aarch64/cortex_a77.h b/include/lib/cpus/aarch64/cortex_a77.h
new file mode 100644
index 0000000..0467ef3
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a77.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_A77_H
+#define CORTEX_A77_H
+
+#include <lib/utils_def.h>
+
+/* Cortex-A77 MIDR */
+#define CORTEX_A77_MIDR					U(0x410FD0D0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A77_CPUECTLR_EL1				S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A77_CPUPWRCTLR_EL1			S3_0_C15_C2_7
+#define CORTEX_A77_CPUPWRCTLR_EL1_CORE_PWRDN_BIT	(U(1) << 0)
+
+#endif /* CORTEX_A77_H */
diff --git a/include/lib/cpus/aarch64/cortex_hercules.h b/include/lib/cpus/aarch64/cortex_hercules.h
new file mode 100644
index 0000000..b943e7a
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_hercules.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CORTEX_HERCULES_H
+#define CORTEX_HERCULES_H
+
+#include <lib/utils_def.h>
+
+#define CORTEX_HERCULES_MIDR					U(0x410FD410)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_HERCULES_CPUECTLR_EL1				S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define CORTEX_HERCULES_CPUPWRCTLR_EL1				S3_0_C15_C2_7
+#define CORTEX_HERCULES_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT	U(1)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_HERCULES_ACTLR_TAM_BIT				(ULL(1) << 30)
+
+/*******************************************************************************
+ * CPU Activity Monitor Unit register specific definitions.
+ ******************************************************************************/
+#define CPUAMCNTENCLR0_EL0					S3_3_C15_C2_4
+#define CPUAMCNTENSET0_EL0					S3_3_C15_C2_5
+#define CPUAMCNTENCLR1_EL0					S3_3_C15_C3_0
+#define CPUAMCNTENSET1_EL0					S3_3_C15_C3_1
+
+#define CORTEX_HERCULES_AMU_GROUP0_MASK				U(0xF)
+#define CORTEX_HERCULES_AMU_GROUP1_MASK				U(0x7)
+
+#endif /* CORTEX_HERCULES_H */
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
new file mode 100644
index 0000000..044aaca
--- /dev/null
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CPU_MACROS_S
+#define CPU_MACROS_S
+
+#include <arch.h>
+#include <assert_macros.S>
+#include <lib/cpus/errata_report.h>
+
+#define CPU_IMPL_PN_MASK	(MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
+				(MIDR_PN_MASK << MIDR_PN_SHIFT)
+
+/* The number of CPU operations allowed */
+#define CPU_MAX_PWR_DWN_OPS		2
+
+/* Special constant to specify that CPU has no reset function */
+#define CPU_NO_RESET_FUNC		0
+
+#define CPU_NO_EXTRA1_FUNC		0
+#define CPU_NO_EXTRA2_FUNC		0
+
+/* Word size for 64-bit CPUs */
+#define CPU_WORD_SIZE			8
+
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) ||(defined(IMAGE_BL2) && BL2_AT_EL3)
+#define IMAGE_AT_EL3
+#endif
+
+/*
+ * Whether errata status needs reporting. Errata status is printed in debug
+ * builds for both BL1 and BL31 images.
+ */
+#if (defined(IMAGE_BL1) || defined(IMAGE_BL31)) && DEBUG
+# define REPORT_ERRATA	1
+#else
+# define REPORT_ERRATA	0
+#endif
+
+
+	.equ	CPU_MIDR_SIZE, CPU_WORD_SIZE
+	.equ	CPU_EXTRA1_FUNC_SIZE, CPU_WORD_SIZE
+	.equ	CPU_EXTRA2_FUNC_SIZE, CPU_WORD_SIZE
+	.equ	CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE
+	.equ	CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS
+	.equ	CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE
+	.equ	CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE
+	.equ	CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE
+	.equ	CPU_REG_DUMP_SIZE, CPU_WORD_SIZE
+
+#ifndef IMAGE_AT_EL3
+	.equ	CPU_RESET_FUNC_SIZE, 0
+#endif
+
+/* The power down core and cluster is needed only in BL31 */
+#ifndef IMAGE_BL31
+	.equ	CPU_PWR_DWN_OPS_SIZE, 0
+#endif
+
+/* Fields required to print errata status. */
+#if !REPORT_ERRATA
+	.equ	CPU_ERRATA_FUNC_SIZE, 0
+#endif
+
+/* Only BL31 requieres mutual exclusion and printed flag.  */
+#if !(REPORT_ERRATA && defined(IMAGE_BL31))
+	.equ	CPU_ERRATA_LOCK_SIZE, 0
+	.equ	CPU_ERRATA_PRINTED_SIZE, 0
+#endif
+
+#if !defined(IMAGE_BL31) || !CRASH_REPORTING
+	.equ	CPU_REG_DUMP_SIZE, 0
+#endif
+
+/*
+ * Define the offsets to the fields in cpu_ops structure.
+ * Every offset is defined based in the offset and size of the previous
+ * field.
+ */
+	.equ	CPU_MIDR, 0
+	.equ	CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE
+	.equ	CPU_EXTRA1_FUNC, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE
+	.equ	CPU_EXTRA2_FUNC, CPU_EXTRA1_FUNC + CPU_EXTRA1_FUNC_SIZE
+	.equ	CPU_PWR_DWN_OPS, CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE
+	.equ	CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE
+	.equ	CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE
+	.equ	CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE
+	.equ	CPU_REG_DUMP, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE
+	.equ	CPU_OPS_SIZE, CPU_REG_DUMP + CPU_REG_DUMP_SIZE
+
+	/*
+	 * Write given expressions as quad words
+	 *
+	 * _count:
+	 *	Write at least _count quad words. If the given number of
+	 *	expressions is less than _count, repeat the last expression to
+	 *	fill _count quad words in total
+	 * _rest:
+	 *	Optional list of expressions. _this is for parameter extraction
+	 *	only, and has no significance to the caller
+	 *
+	 * Invoked as:
+	 *	fill_constants 2, foo, bar, blah, ...
+	 */
+	.macro fill_constants _count:req, _this, _rest:vararg
+	  .ifgt \_count
+	    /* Write the current expression */
+	    .ifb \_this
+	      .error "Nothing to fill"
+	    .endif
+	    .quad \_this
+
+	    /* Invoke recursively for remaining expressions */
+	    .ifnb \_rest
+	      fill_constants \_count-1, \_rest
+	    .else
+	      fill_constants \_count-1, \_this
+	    .endif
+	  .endif
+	.endm
+
+	/*
+	 * Declare CPU operations
+	 *
+	 * _name:
+	 *	Name of the CPU for which operations are being specified
+	 * _midr:
+	 *	Numeric value expected to read from CPU's MIDR
+	 * _resetfunc:
+	 *	Reset function for the CPU. If there's no CPU reset function,
+	 *	specify CPU_NO_RESET_FUNC
+	 * _extra1:
+	 *	This is a placeholder for future per CPU operations.  Currently,
+	 *	some CPUs use this entry to set a test function to determine if
+	 *	the workaround for CVE-2017-5715 needs to be applied or not.
+	 * _extra2:
+	 *	This is a placeholder for future per CPU operations.  Currently
+	 *	some CPUs use this entry to set a function to disable the
+	 *	workaround for CVE-2018-3639.
+	 * _power_down_ops:
+	 *	Comma-separated list of functions to perform power-down
+	 *	operatios on the CPU. At least one, and up to
+	 *	CPU_MAX_PWR_DWN_OPS number of functions may be specified.
+	 *	Starting at power level 0, these functions shall handle power
+	 *	down at subsequent power levels. If there aren't exactly
+	 *	CPU_MAX_PWR_DWN_OPS functions, the last specified one will be
+	 *	used to handle power down at subsequent levels
+	 */
+	.macro declare_cpu_ops_base _name:req, _midr:req, _resetfunc:req, \
+		_extra1:req, _extra2:req, _power_down_ops:vararg
+	.section cpu_ops, "a"
+	.align 3
+	.type cpu_ops_\_name, %object
+	.quad \_midr
+#if defined(IMAGE_AT_EL3)
+	.quad \_resetfunc
+#endif
+	.quad \_extra1
+	.quad \_extra2
+#ifdef IMAGE_BL31
+	/* Insert list of functions */
+	fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops
+#endif
+
+#if REPORT_ERRATA
+	.ifndef \_name\()_cpu_str
+	  /*
+	   * Place errata reported flag, and the spinlock to arbitrate access to
+	   * it in the data section.
+	   */
+	  .pushsection .data
+	  define_asm_spinlock \_name\()_errata_lock
+	  \_name\()_errata_reported:
+	  .word	0
+	  .popsection
+
+	  /* Place CPU string in rodata */
+	  .pushsection .rodata
+	  \_name\()_cpu_str:
+	  .asciz "\_name"
+	  .popsection
+	.endif
+
+	/*
+	 * Mandatory errata status printing function for CPUs of
+	 * this class.
+	 */
+	.quad \_name\()_errata_report
+
+#ifdef IMAGE_BL31
+	/* Pointers to errata lock and reported flag */
+	.quad \_name\()_errata_lock
+	.quad \_name\()_errata_reported
+#endif
+#endif
+
+#if defined(IMAGE_BL31) && CRASH_REPORTING
+	.quad \_name\()_cpu_reg_dump
+#endif
+	.endm
+
+	.macro declare_cpu_ops _name:req, _midr:req, _resetfunc:req, \
+		_power_down_ops:vararg
+		declare_cpu_ops_base \_name, \_midr, \_resetfunc, 0, 0, \
+			\_power_down_ops
+	.endm
+
+	.macro declare_cpu_ops_wa _name:req, _midr:req, \
+		_resetfunc:req, _extra1:req, _extra2:req, \
+		_power_down_ops:vararg
+		declare_cpu_ops_base \_name, \_midr, \_resetfunc, \
+			\_extra1, \_extra2, \_power_down_ops
+	.endm
+
+#if REPORT_ERRATA
+	/*
+	 * Print status of a CPU errata
+	 *
+	 * _chosen:
+	 *	Identifier indicating whether or not a CPU errata has been
+	 *	compiled in.
+	 * _cpu:
+	 *	Name of the CPU
+	 * _id:
+	 *	Errata identifier
+	 * _rev_var:
+	 *	Register containing the combined value CPU revision and variant
+	 *	- typically the return value of cpu_get_rev_var
+	 */
+	.macro report_errata _chosen, _cpu, _id, _rev_var=x8
+	/* Stash a string with errata ID */
+	.pushsection .rodata
+	\_cpu\()_errata_\_id\()_str:
+	.asciz	"\_id"
+	.popsection
+
+	/* Check whether errata applies */
+	mov	x0, \_rev_var
+	/* Shall clobber: x0-x7 */
+	bl	check_errata_\_id
+
+	.ifeq \_chosen
+	/*
+	 * Errata workaround has not been compiled in. If the errata would have
+	 * applied had it been compiled in, print its status as missing.
+	 */
+	cbz	x0, 900f
+	mov	x0, #ERRATA_MISSING
+	.endif
+900:
+	adr	x1, \_cpu\()_cpu_str
+	adr	x2, \_cpu\()_errata_\_id\()_str
+	bl	errata_print_msg
+	.endm
+#endif
+
+	/*
+	 * This macro is used on some CPUs to detect if they are vulnerable
+	 * to CVE-2017-5715.
+	 */
+	.macro	cpu_check_csv2 _reg _label
+	mrs	\_reg, id_aa64pfr0_el1
+	ubfx	\_reg, \_reg, #ID_AA64PFR0_CSV2_SHIFT, #ID_AA64PFR0_CSV2_LENGTH
+	/*
+	 * If the field equals 1, branch targets trained in one context cannot
+	 * affect speculative execution in a different context.
+	 *
+	 * If the field equals 2, it means that the system is also aware of
+	 * SCXTNUM_ELx register contexts. We aren't using them in the TF, so we
+	 * expect users of the registers to do the right thing.
+	 *
+	 * Only apply mitigations if the value of this field is 0.
+	 */
+#if ENABLE_ASSERTIONS
+	cmp	\_reg, #3 /* Only values 0 to 2 are expected */
+	ASM_ASSERT(lo)
+#endif
+
+	cmp	\_reg, #0
+	bne	\_label
+	.endm
+
+	/*
+	 * Helper macro that reads the part number of the current
+	 * CPU and jumps to the given label if it matches the CPU
+	 * MIDR provided.
+	 *
+	 * Clobbers x0.
+	 */
+	.macro  jump_if_cpu_midr _cpu_midr, _label
+	mrs	x0, midr_el1
+	ubfx	x0, x0, MIDR_PN_SHIFT, #12
+	cmp	w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+	b.eq	\_label
+	.endm
+
+#endif /* CPU_MACROS_S */
diff --git a/include/lib/cpus/aarch64/cpuamu.h b/include/lib/cpus/aarch64/cpuamu.h
new file mode 100644
index 0000000..463f890
--- /dev/null
+++ b/include/lib/cpus/aarch64/cpuamu.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CPUAMU_H
+#define CPUAMU_H
+
+/*******************************************************************************
+ * CPU Activity Monitor Unit register specific definitions.
+ ******************************************************************************/
+#define CPUAMCNTENCLR_EL0	S3_3_C15_C9_7
+#define CPUAMCNTENSET_EL0	S3_3_C15_C9_6
+#define CPUAMCFGR_EL0		S3_3_C15_C10_6
+#define CPUAMUSERENR_EL0	S3_3_C15_C10_7
+
+/* Activity Monitor Event Counter Registers */
+#define CPUAMEVCNTR0_EL0	S3_3_C15_C9_0
+#define CPUAMEVCNTR1_EL0	S3_3_C15_C9_1
+#define CPUAMEVCNTR2_EL0	S3_3_C15_C9_2
+#define CPUAMEVCNTR3_EL0	S3_3_C15_C9_3
+#define CPUAMEVCNTR4_EL0	S3_3_C15_C9_4
+
+/* Activity Monitor Event Type Registers */
+#define CPUAMEVTYPER0_EL0	S3_3_C15_C10_0
+#define CPUAMEVTYPER1_EL0	S3_3_C15_C10_1
+#define CPUAMEVTYPER2_EL0	S3_3_C15_C10_2
+#define CPUAMEVTYPER3_EL0	S3_3_C15_C10_3
+#define CPUAMEVTYPER4_EL0	S3_3_C15_C10_4
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+uint64_t cpuamu_cnt_read(unsigned int idx);
+void cpuamu_cnt_write(unsigned int idx, uint64_t val);
+unsigned int cpuamu_read_cpuamcntenset_el0(void);
+unsigned int cpuamu_read_cpuamcntenclr_el0(void);
+void cpuamu_write_cpuamcntenset_el0(unsigned int mask);
+void cpuamu_write_cpuamcntenclr_el0(unsigned int mask);
+
+int midr_match(unsigned int cpu_midr);
+void cpuamu_context_save(unsigned int nr_counters);
+void cpuamu_context_restore(unsigned int nr_counters);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CPUAMU_H */
diff --git a/include/lib/cpus/aarch64/denver.h b/include/lib/cpus/aarch64/denver.h
new file mode 100644
index 0000000..02657a0
--- /dev/null
+++ b/include/lib/cpus/aarch64/denver.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DENVER_H
+#define DENVER_H
+
+/* MIDR values for Denver */
+#define DENVER_MIDR_PN0			U(0x4E0F0000)
+#define DENVER_MIDR_PN1			U(0x4E0F0010)
+#define DENVER_MIDR_PN2			U(0x4E0F0020)
+#define DENVER_MIDR_PN3			U(0x4E0F0030)
+#define DENVER_MIDR_PN4			U(0x4E0F0040)
+
+/* Implementer code in the MIDR register */
+#define DENVER_IMPL			U(0x4E)
+
+/* CPU state ids - implementation defined */
+#define DENVER_CPU_STATE_POWER_DOWN	U(0x3)
+
+/* Speculative store buffering */
+#define DENVER_CPU_DIS_SSB_EL3		(U(1) << 11)
+#define DENVER_PN4_CPU_DIS_SSB_EL3	(U(1) << 18)
+
+/* Speculative memory disambiguation */
+#define DENVER_CPU_DIS_MD_EL3		(U(1) << 9)
+#define DENVER_PN4_CPU_DIS_MD_EL3	(U(1) << 17)
+
+/* Core power management states */
+#define DENVER_CPU_PMSTATE_C1		U(0x1)
+#define DENVER_CPU_PMSTATE_C6		U(0x6)
+#define DENVER_CPU_PMSTATE_C7		U(0x7)
+#define DENVER_CPU_PMSTATE_MASK		U(0xF)
+
+#ifndef __ASSEMBLER__
+
+/* Disable Dynamic Code Optimisation */
+void denver_disable_dco(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* DENVER_H */
diff --git a/include/lib/cpus/aarch64/dsu_def.h b/include/lib/cpus/aarch64/dsu_def.h
new file mode 100644
index 0000000..0969acf
--- /dev/null
+++ b/include/lib/cpus/aarch64/dsu_def.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DSU_DEF_H
+#define DSU_DEF_H
+
+#include <lib/utils_def.h>
+
+/********************************************************************
+ * DSU Cluster Configuration registers definitions
+ ********************************************************************/
+#define CLUSTERCFR_EL1		S3_0_C15_C3_0
+
+#define CLUSTERCFR_ACP_SHIFT	U(11)
+
+/********************************************************************
+ * DSU Cluster Main Revision ID registers definitions
+ ********************************************************************/
+#define CLUSTERIDR_EL1		S3_0_C15_C3_1
+
+#define CLUSTERIDR_REV_SHIFT	U(0)
+#define CLUSTERIDR_REV_BITS	U(4)
+#define CLUSTERIDR_VAR_SHIFT	U(4)
+#define CLUSTERIDR_VAR_BITS	U(4)
+
+/********************************************************************
+ * DSU Cluster Auxiliary Control registers definitions
+ ********************************************************************/
+#define CLUSTERACTLR_EL1	S3_0_C15_C3_3
+
+#define CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING	(ULL(1) << 15)
+
+/********************************************************************
+ * Masks applied for DSU errata workarounds
+ ********************************************************************/
+#define DSU_ERRATA_936184_MASK	(U(0x3) << 15)
+
+#endif /* DSU_DEF_H */
diff --git a/include/lib/cpus/aarch64/neoverse_e1.h b/include/lib/cpus/aarch64/neoverse_e1.h
new file mode 100644
index 0000000..96b4661
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_e1.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_E1_H
+#define NEOVERSE_E1_H
+
+#include <lib/utils_def.h>
+
+#define NEOVERSE_E1_MIDR		U(0x410FD4A0)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_E1_ECTLR_EL1		S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_E1_CPUACTLR_EL1	S3_0_C15_C1_0
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions.
+ ******************************************************************************/
+
+#define NEOVERSE_E1_CPUPWRCTLR_EL1				S3_0_C15_C2_7
+#define NEOVERSE_E1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		(U(1) << 0)
+
+#endif /* NEOVERSE_E1_H */
diff --git a/include/lib/cpus/aarch64/neoverse_n1.h b/include/lib/cpus/aarch64/neoverse_n1.h
new file mode 100644
index 0000000..f90aa2e
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_n1.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_N1_H
+#define NEOVERSE_N1_H
+
+#include <lib/utils_def.h>
+
+/* Neoverse N1 MIDR for revision 0 */
+#define NEOVERSE_N1_MIDR		U(0x410fd0c0)
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N1_CPUPWRCTLR_EL1	S3_0_C15_C2_7
+
+/* Definitions of register field mask in NEOVERSE_N1_CPUPWRCTLR_EL1 */
+#define NEOVERSE_N1_CORE_PWRDN_EN_MASK	U(0x1)
+
+#define NEOVERSE_N1_ACTLR_AMEN_BIT	(U(1) << 4)
+
+#define NEOVERSE_N1_AMU_NR_COUNTERS	U(5)
+#define NEOVERSE_N1_AMU_GROUP0_MASK	U(0x1f)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N1_CPUECTLR_EL1	S3_0_C15_C1_4
+
+#define NEOVERSE_N1_WS_THR_L2_MASK	(ULL(3) << 24)
+#define NEOVERSE_N1_CPUECTLR_EL1_MM_TLBPF_DIS_BIT	(ULL(1) << 51)
+
+/*******************************************************************************
+ * CPU Auxiliary Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_N1_CPUACTLR_EL1	S3_0_C15_C1_0
+
+#define NEOVERSE_N1_CPUACTLR_EL1_BIT_6	(ULL(1) << 6)
+#define NEOVERSE_N1_CPUACTLR_EL1_BIT_13	(ULL(1) << 13)
+
+#define NEOVERSE_N1_CPUACTLR2_EL1	S3_0_C15_C1_1
+
+#define NEOVERSE_N1_CPUACTLR2_EL1_BIT_0		(ULL(1) << 0)
+#define NEOVERSE_N1_CPUACTLR2_EL1_BIT_2		(ULL(1) << 2)
+#define NEOVERSE_N1_CPUACTLR2_EL1_BIT_11	(ULL(1) << 11)
+#define NEOVERSE_N1_CPUACTLR2_EL1_BIT_15	(ULL(1) << 15)
+#define NEOVERSE_N1_CPUACTLR2_EL1_BIT_16	(ULL(1) << 16)
+#define NEOVERSE_N1_CPUACTLR2_EL1_BIT_59	(ULL(1) << 59)
+
+#define NEOVERSE_N1_CPUACTLR3_EL1	S3_0_C15_C1_2
+
+#define NEOVERSE_N1_CPUACTLR3_EL1_BIT_10	(ULL(1) << 10)
+
+/* Instruction patching registers */
+#define CPUPSELR_EL3	S3_6_C15_C8_0
+#define CPUPCR_EL3	S3_6_C15_C8_1
+#define CPUPOR_EL3	S3_6_C15_C8_2
+#define CPUPMR_EL3	S3_6_C15_C8_3
+
+#endif /* NEOVERSE_N1_H */
diff --git a/include/lib/cpus/aarch64/neoverse_zeus.h b/include/lib/cpus/aarch64/neoverse_zeus.h
new file mode 100644
index 0000000..f094727
--- /dev/null
+++ b/include/lib/cpus/aarch64/neoverse_zeus.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NEOVERSE_ZEUS_H
+#define NEOVERSE_ZEUS_H
+
+#define NEOVERSE_ZEUS_MIDR					U(0x410FD400)
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define NEOVERSE_ZEUS_CPUECTLR_EL1				S3_0_C15_C1_4
+
+/*******************************************************************************
+ * CPU Power Control register specific definitions
+ ******************************************************************************/
+#define NEOVERSE_ZEUS_CPUPWRCTLR_EL1				S3_0_C15_C2_7
+#define NEOVERSE_ZEUS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT		U(1)
+
+#endif /* NEOVERSE_ZEUS_H */
diff --git a/include/lib/cpus/errata_report.h b/include/lib/cpus/errata_report.h
new file mode 100644
index 0000000..7cac77e
--- /dev/null
+++ b/include/lib/cpus/errata_report.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ERRATA_REPORT_H
+#define ERRATA_REPORT_H
+
+#ifndef __ASSEMBLER__
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+
+#if DEBUG
+void print_errata_status(void);
+#else
+static inline void print_errata_status(void) {}
+#endif
+
+void errata_print_msg(unsigned int status, const char *cpu, const char *id);
+int errata_needs_reporting(spinlock_t *lock, uint32_t *reported);
+
+#endif /* __ASSEMBLER__ */
+
+/* Errata status */
+#define ERRATA_NOT_APPLIES	0
+#define ERRATA_APPLIES		1
+#define ERRATA_MISSING		2
+
+#endif /* ERRATA_REPORT_H */
diff --git a/include/lib/cpus/wa_cve_2017_5715.h b/include/lib/cpus/wa_cve_2017_5715.h
new file mode 100644
index 0000000..940fc65
--- /dev/null
+++ b/include/lib/cpus/wa_cve_2017_5715.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef WA_CVE_2017_5715_H
+#define WA_CVE_2017_5715_H
+
+int check_wa_cve_2017_5715(void);
+
+#endif /* WA_CVE_2017_5715_H */
diff --git a/include/lib/cpus/wa_cve_2018_3639.h b/include/lib/cpus/wa_cve_2018_3639.h
new file mode 100644
index 0000000..e37db37
--- /dev/null
+++ b/include/lib/cpus/wa_cve_2018_3639.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef WA_CVE_2018_3639_H
+#define WA_CVE_2018_3639_H
+
+void *wa_cve_2018_3639_get_disable_ptr(void);
+
+#endif /* WA_CVE_2018_3639_H */
diff --git a/include/lib/el3_runtime/aarch32/context.h b/include/lib/el3_runtime/aarch32/context.h
new file mode 100644
index 0000000..c5567c9
--- /dev/null
+++ b/include/lib/el3_runtime/aarch32/context.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the 'regs'
+ * structure at their correct offsets.
+ ******************************************************************************/
+#define CTX_REGS_OFFSET		U(0x0)
+#define CTX_GPREG_R0		U(0x0)
+#define CTX_GPREG_R1		U(0x4)
+#define CTX_GPREG_R2		U(0x8)
+#define CTX_GPREG_R3		U(0xC)
+#define CTX_LR			U(0x10)
+#define CTX_SCR			U(0x14)
+#define CTX_SPSR		U(0x18)
+#define CTX_NS_SCTLR		U(0x1C)
+#define CTX_REGS_END		U(0x20)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * Common constants to help define the 'cpu_context' structure and its
+ * members below.
+ */
+#define WORD_SHIFT		U(2)
+#define DEFINE_REG_STRUCT(name, num_regs)	\
+	typedef struct name {			\
+		uint32_t _regs[num_regs];	\
+	}  __aligned(8) name##_t
+
+/* Constants to determine the size of individual context structures */
+#define CTX_REG_ALL		(CTX_REGS_END >> WORD_SHIFT)
+
+DEFINE_REG_STRUCT(regs, CTX_REG_ALL);
+
+#undef CTX_REG_ALL
+
+#define read_ctx_reg(ctx, offset)	((ctx)->_regs[offset >> WORD_SHIFT])
+#define write_ctx_reg(ctx, offset, val)	(((ctx)->_regs[offset >> WORD_SHIFT]) \
+					 = val)
+typedef struct cpu_context {
+	regs_t regs_ctx;
+} cpu_context_t;
+
+/* Macros to access members of the 'cpu_context_t' structure */
+#define get_regs_ctx(h)		(&((cpu_context_t *) h)->regs_ctx)
+
+/*
+ * Compile time assertions related to the 'cpu_context' structure to
+ * ensure that the assembler and the compiler view of the offsets of
+ * the structure members is the same.
+ */
+CASSERT(CTX_REGS_OFFSET == __builtin_offsetof(cpu_context_t, regs_ctx), \
+	assert_core_context_regs_offset_mismatch);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CONTEXT_H */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
new file mode 100644
index 0000000..a76a59b
--- /dev/null
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the 'gp_regs'
+ * structure at their correct offsets.
+ ******************************************************************************/
+#define CTX_GPREGS_OFFSET	U(0x0)
+#define CTX_GPREG_X0		U(0x0)
+#define CTX_GPREG_X1		U(0x8)
+#define CTX_GPREG_X2		U(0x10)
+#define CTX_GPREG_X3		U(0x18)
+#define CTX_GPREG_X4		U(0x20)
+#define CTX_GPREG_X5		U(0x28)
+#define CTX_GPREG_X6		U(0x30)
+#define CTX_GPREG_X7		U(0x38)
+#define CTX_GPREG_X8		U(0x40)
+#define CTX_GPREG_X9		U(0x48)
+#define CTX_GPREG_X10		U(0x50)
+#define CTX_GPREG_X11		U(0x58)
+#define CTX_GPREG_X12		U(0x60)
+#define CTX_GPREG_X13		U(0x68)
+#define CTX_GPREG_X14		U(0x70)
+#define CTX_GPREG_X15		U(0x78)
+#define CTX_GPREG_X16		U(0x80)
+#define CTX_GPREG_X17		U(0x88)
+#define CTX_GPREG_X18		U(0x90)
+#define CTX_GPREG_X19		U(0x98)
+#define CTX_GPREG_X20		U(0xa0)
+#define CTX_GPREG_X21		U(0xa8)
+#define CTX_GPREG_X22		U(0xb0)
+#define CTX_GPREG_X23		U(0xb8)
+#define CTX_GPREG_X24		U(0xc0)
+#define CTX_GPREG_X25		U(0xc8)
+#define CTX_GPREG_X26		U(0xd0)
+#define CTX_GPREG_X27		U(0xd8)
+#define CTX_GPREG_X28		U(0xe0)
+#define CTX_GPREG_X29		U(0xe8)
+#define CTX_GPREG_LR		U(0xf0)
+#define CTX_GPREG_SP_EL0	U(0xf8)
+#define CTX_GPREGS_END		U(0x100)
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the 'el3_state'
+ * structure at their correct offsets. Note that some of the registers are only
+ * 32-bits wide but are stored as 64-bit values for convenience
+ ******************************************************************************/
+#define CTX_EL3STATE_OFFSET	(CTX_GPREGS_OFFSET + CTX_GPREGS_END)
+#define CTX_SCR_EL3		U(0x0)
+#define CTX_ESR_EL3		U(0x8)
+#define CTX_RUNTIME_SP		U(0x10)
+#define CTX_SPSR_EL3		U(0x18)
+#define CTX_ELR_EL3		U(0x20)
+#define CTX_UNUSED		U(0x28)
+#define CTX_EL3STATE_END	U(0x30)
+
+/*******************************************************************************
+ * Constants that allow assembler code to access members of and the
+ * 'el1_sys_regs' structure at their correct offsets. Note that some of the
+ * 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_SPSR_EL1		U(0x0)
+#define CTX_ELR_EL1		U(0x8)
+#define CTX_SCTLR_EL1		U(0x10)
+#define CTX_ACTLR_EL1		U(0x18)
+#define CTX_CPACR_EL1		U(0x20)
+#define CTX_CSSELR_EL1		U(0x28)
+#define CTX_SP_EL1		U(0x30)
+#define CTX_ESR_EL1		U(0x38)
+#define CTX_TTBR0_EL1		U(0x40)
+#define CTX_TTBR1_EL1		U(0x48)
+#define CTX_MAIR_EL1		U(0x50)
+#define CTX_AMAIR_EL1		U(0x58)
+#define CTX_TCR_EL1		U(0x60)
+#define CTX_TPIDR_EL1		U(0x68)
+#define CTX_TPIDR_EL0		U(0x70)
+#define CTX_TPIDRRO_EL0		U(0x78)
+#define CTX_PAR_EL1		U(0x80)
+#define CTX_FAR_EL1		U(0x88)
+#define CTX_AFSR0_EL1		U(0x90)
+#define CTX_AFSR1_EL1		U(0x98)
+#define CTX_CONTEXTIDR_EL1	U(0xa0)
+#define CTX_VBAR_EL1		U(0xa8)
+#define CTX_PMCR_EL0		U(0xb0)
+
+/*
+ * If the platform is AArch64-only, there is no need to save and restore these
+ * AArch32 registers.
+ */
+#if CTX_INCLUDE_AARCH32_REGS
+#define CTX_SPSR_ABT		U(0xc0)  /* Align to the next 16 byte boundary */
+#define CTX_SPSR_UND		U(0xc8)
+#define CTX_SPSR_IRQ		U(0xd0)
+#define CTX_SPSR_FIQ		U(0xd8)
+#define CTX_DACR32_EL2		U(0xe0)
+#define CTX_IFSR32_EL2		U(0xe8)
+#define CTX_AARCH32_END		U(0xf0) /* Align to the next 16 byte boundary */
+#else
+#define CTX_AARCH32_END		U(0xc0)  /* Align to the next 16 byte boundary */
+#endif /* CTX_INCLUDE_AARCH32_REGS */
+
+/*
+ * If the timer registers aren't saved and restored, we don't have to reserve
+ * space for them in the context
+ */
+#if NS_TIMER_SWITCH
+#define CTX_CNTP_CTL_EL0	(CTX_AARCH32_END + U(0x0))
+#define CTX_CNTP_CVAL_EL0	(CTX_AARCH32_END + U(0x8))
+#define CTX_CNTV_CTL_EL0	(CTX_AARCH32_END + U(0x10))
+#define CTX_CNTV_CVAL_EL0	(CTX_AARCH32_END + U(0x18))
+#define CTX_CNTKCTL_EL1		(CTX_AARCH32_END + U(0x20))
+#define CTX_TIMER_SYSREGS_END	(CTX_AARCH32_END + U(0x30)) /* Align to the next 16 byte boundary */
+#else
+#define CTX_TIMER_SYSREGS_END	CTX_AARCH32_END
+#endif /* NS_TIMER_SWITCH */
+
+/*
+ * End of system registers.
+ */
+#define CTX_SYSREGS_END		CTX_TIMER_SYSREGS_END
+
+/*******************************************************************************
+ * 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_FPREGS
+#define CTX_FP_Q0		U(0x0)
+#define CTX_FP_Q1		U(0x10)
+#define CTX_FP_Q2		U(0x20)
+#define CTX_FP_Q3		U(0x30)
+#define CTX_FP_Q4		U(0x40)
+#define CTX_FP_Q5		U(0x50)
+#define CTX_FP_Q6		U(0x60)
+#define CTX_FP_Q7		U(0x70)
+#define CTX_FP_Q8		U(0x80)
+#define CTX_FP_Q9		U(0x90)
+#define CTX_FP_Q10		U(0xa0)
+#define CTX_FP_Q11		U(0xb0)
+#define CTX_FP_Q12		U(0xc0)
+#define CTX_FP_Q13		U(0xd0)
+#define CTX_FP_Q14		U(0xe0)
+#define CTX_FP_Q15		U(0xf0)
+#define CTX_FP_Q16		U(0x100)
+#define CTX_FP_Q17		U(0x110)
+#define CTX_FP_Q18		U(0x120)
+#define CTX_FP_Q19		U(0x130)
+#define CTX_FP_Q20		U(0x140)
+#define CTX_FP_Q21		U(0x150)
+#define CTX_FP_Q22		U(0x160)
+#define CTX_FP_Q23		U(0x170)
+#define CTX_FP_Q24		U(0x180)
+#define CTX_FP_Q25		U(0x190)
+#define CTX_FP_Q26		U(0x1a0)
+#define CTX_FP_Q27		U(0x1b0)
+#define CTX_FP_Q28		U(0x1c0)
+#define CTX_FP_Q29		U(0x1d0)
+#define CTX_FP_Q30		U(0x1e0)
+#define CTX_FP_Q31		U(0x1f0)
+#define CTX_FP_FPSR		U(0x200)
+#define CTX_FP_FPCR		U(0x208)
+#if CTX_INCLUDE_AARCH32_REGS
+#define CTX_FP_FPEXC32_EL2	U(0x210)
+#define CTX_FPREGS_END		U(0x220) /* Align to the next 16 byte boundary */
+#else
+#define CTX_FPREGS_END		U(0x210) /* Align to the next 16 byte boundary */
+#endif
+#else
+#define CTX_FPREGS_END		U(0)
+#endif
+
+/*******************************************************************************
+ * Registers related to CVE-2018-3639
+ ******************************************************************************/
+#define CTX_CVE_2018_3639_OFFSET	(CTX_FPREGS_OFFSET + CTX_FPREGS_END)
+#define CTX_CVE_2018_3639_DISABLE	U(0)
+#define CTX_CVE_2018_3639_END		U(0x10) /* Align to the next 16 byte boundary */
+
+/*******************************************************************************
+ * Registers related to ARMv8.3-PAuth.
+ ******************************************************************************/
+#define CTX_PAUTH_REGS_OFFSET	(CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_END)
+#if CTX_INCLUDE_PAUTH_REGS
+#define CTX_PACIAKEY_LO		U(0x0)
+#define CTX_PACIAKEY_HI		U(0x8)
+#define CTX_PACIBKEY_LO		U(0x10)
+#define CTX_PACIBKEY_HI		U(0x18)
+#define CTX_PACDAKEY_LO		U(0x20)
+#define CTX_PACDAKEY_HI		U(0x28)
+#define CTX_PACDBKEY_LO		U(0x30)
+#define CTX_PACDBKEY_HI		U(0x38)
+#define CTX_PACGAKEY_LO		U(0x40)
+#define CTX_PACGAKEY_HI		U(0x48)
+#define CTX_PACGAKEY_END	U(0x50)
+#define CTX_PAUTH_REGS_END	U(0x60) /* Align to the next 16 byte boundary */
+#else
+#define CTX_PAUTH_REGS_END	U(0)
+#endif /* CTX_INCLUDE_PAUTH_REGS */
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * Common constants to help define the 'cpu_context' structure and its
+ * members below.
+ */
+#define DWORD_SHIFT		U(3)
+#define DEFINE_REG_STRUCT(name, num_regs)	\
+	typedef struct name {			\
+		uint64_t _regs[num_regs];	\
+	}  __aligned(16) name##_t
+
+/* 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)
+#if CTX_INCLUDE_FPREGS
+# define CTX_FPREG_ALL		(CTX_FPREGS_END >> DWORD_SHIFT)
+#endif
+#define CTX_EL3STATE_ALL	(CTX_EL3STATE_END >> DWORD_SHIFT)
+#define CTX_CVE_2018_3639_ALL	(CTX_CVE_2018_3639_END >> DWORD_SHIFT)
+#if CTX_INCLUDE_PAUTH_REGS
+# define CTX_PAUTH_REGS_ALL	(CTX_PAUTH_REGS_END >> DWORD_SHIFT)
+#endif
+
+/*
+ * AArch64 general purpose register context structure. Usually x0-x18,
+ * lr are saved as the compiler is expected to preserve the remaining
+ * callee saved registers if used by the C runtime and the assembler
+ * does not touch the remaining. But in case of world switch during
+ * exception handling, we need to save the callee registers too.
+ */
+DEFINE_REG_STRUCT(gp_regs, CTX_GPREG_ALL);
+
+/*
+ * AArch64 EL1 system register context structure for preserving the
+ * architectural state during switches from one security state to
+ * another in EL1.
+ */
+DEFINE_REG_STRUCT(el1_sys_regs, CTX_SYSREG_ALL);
+
+/*
+ * AArch64 floating point register context structure for preserving
+ * the floating point state during switches from one security state to
+ * another.
+ */
+#if CTX_INCLUDE_FPREGS
+DEFINE_REG_STRUCT(fp_regs, CTX_FPREG_ALL);
+#endif
+
+/*
+ * Miscellaneous registers used by EL3 firmware to maintain its state
+ * across exception entries and exits
+ */
+DEFINE_REG_STRUCT(el3_state, CTX_EL3STATE_ALL);
+
+/* Function pointer used by CVE-2018-3639 dynamic mitigation */
+DEFINE_REG_STRUCT(cve_2018_3639, CTX_CVE_2018_3639_ALL);
+
+/* Registers associated to ARMv8.3-PAuth */
+#if CTX_INCLUDE_PAUTH_REGS
+DEFINE_REG_STRUCT(pauth, CTX_PAUTH_REGS_ALL);
+#endif
+
+/*
+ * Macros to access members of any of the above structures using their
+ * offsets
+ */
+#define read_ctx_reg(ctx, offset)	((ctx)->_regs[(offset) >> DWORD_SHIFT])
+#define write_ctx_reg(ctx, offset, val)	(((ctx)->_regs[(offset) >> DWORD_SHIFT]) \
+					 = (uint64_t) (val))
+
+/*
+ * Top-level context structure which is used by EL3 firmware to
+ * preserve the state of a core at EL1 in one of the two security
+ * states and save enough EL3 meta data to be able to return to that
+ * EL and security state. The context management library will be used
+ * to ensure that SP_EL3 always points to an instance of this
+ * structure at exception entry and exit. Each instance will
+ * correspond to either the secure or the non-secure state.
+ */
+typedef struct cpu_context {
+	gp_regs_t gpregs_ctx;
+	el3_state_t el3state_ctx;
+	el1_sys_regs_t sysregs_ctx;
+#if CTX_INCLUDE_FPREGS
+	fp_regs_t fpregs_ctx;
+#endif
+	cve_2018_3639_t cve_2018_3639_ctx;
+#if CTX_INCLUDE_PAUTH_REGS
+	pauth_t pauth_ctx;
+#endif
+} cpu_context_t;
+
+/* Macros to access members of the 'cpu_context_t' structure */
+#define get_el3state_ctx(h)	(&((cpu_context_t *) h)->el3state_ctx)
+#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_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
+# define get_pauth_ctx(h)	(&((cpu_context_t *) h)->pauth_ctx)
+#endif
+
+/*
+ * Compile time assertions related to the 'cpu_context' structure to
+ * ensure that the assembler and the compiler view of the offsets of
+ * the structure members is the same.
+ */
+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);
+#if CTX_INCLUDE_FPREGS
+CASSERT(CTX_FPREGS_OFFSET == __builtin_offsetof(cpu_context_t, fpregs_ctx), \
+	assert_core_context_fp_offset_mismatch);
+#endif
+CASSERT(CTX_EL3STATE_OFFSET == __builtin_offsetof(cpu_context_t, el3state_ctx), \
+	assert_core_context_el3state_offset_mismatch);
+CASSERT(CTX_CVE_2018_3639_OFFSET == __builtin_offsetof(cpu_context_t, cve_2018_3639_ctx), \
+	assert_core_context_cve_2018_3639_offset_mismatch);
+#if CTX_INCLUDE_PAUTH_REGS
+CASSERT(CTX_PAUTH_REGS_OFFSET == __builtin_offsetof(cpu_context_t, pauth_ctx), \
+	assert_core_context_pauth_offset_mismatch);
+#endif
+
+/*
+ * Helper macro to set the general purpose registers that correspond to
+ * parameters in an aapcs_64 call i.e. x0-x7
+ */
+#define set_aapcs_args0(ctx, x0)				do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0, x0);	\
+	} while (0)
+#define set_aapcs_args1(ctx, x0, x1)				do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1, x1);	\
+		set_aapcs_args0(ctx, x0);				\
+	} while (0)
+#define set_aapcs_args2(ctx, x0, x1, x2)			do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2, x2);	\
+		set_aapcs_args1(ctx, x0, x1);				\
+	} while (0)
+#define set_aapcs_args3(ctx, x0, x1, x2, x3)			do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3, x3);	\
+		set_aapcs_args2(ctx, x0, x1, x2);			\
+	} while (0)
+#define set_aapcs_args4(ctx, x0, x1, x2, x3, x4)		do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X4, x4);	\
+		set_aapcs_args3(ctx, x0, x1, x2, x3);			\
+	} while (0)
+#define set_aapcs_args5(ctx, x0, x1, x2, x3, x4, x5)		do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X5, x5);	\
+		set_aapcs_args4(ctx, x0, x1, x2, x3, x4);		\
+	} while (0)
+#define set_aapcs_args6(ctx, x0, x1, x2, x3, x4, x5, x6)	do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X6, x6);	\
+		set_aapcs_args5(ctx, x0, x1, x2, x3, x4, x5);		\
+	} while (0)
+#define set_aapcs_args7(ctx, x0, x1, x2, x3, x4, x5, x6, x7)	do {	\
+		write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X7, x7);	\
+		set_aapcs_args6(ctx, x0, x1, x2, x3, x4, x5, x6);	\
+	} while (0)
+
+/*******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+void el1_sysregs_context_save(el1_sys_regs_t *regs);
+void el1_sysregs_context_restore(el1_sys_regs_t *regs);
+#if CTX_INCLUDE_FPREGS
+void fpregs_context_save(fp_regs_t *regs);
+void fpregs_context_restore(fp_regs_t *regs);
+#endif
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* CONTEXT_H */
diff --git a/include/lib/el3_runtime/context_mgmt.h b/include/lib/el3_runtime/context_mgmt.h
new file mode 100644
index 0000000..7c996d1
--- /dev/null
+++ b/include/lib/el3_runtime/context_mgmt.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CONTEXT_MGMT_H
+#define CONTEXT_MGMT_H
+
+#include <assert.h>
+#include <context.h>
+#include <stdint.h>
+
+#include <arch.h>
+
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+struct entry_point_info;
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+void cm_init(void);
+void *cm_get_context_by_index(unsigned int cpu_idx,
+			      unsigned int security_state);
+void cm_set_context_by_index(unsigned int cpu_idx,
+			     void *context,
+			     unsigned int security_state);
+void *cm_get_context(uint32_t security_state);
+void cm_set_context(void *context, uint32_t security_state);
+void cm_init_my_context(const struct entry_point_info *ep);
+void cm_init_context_by_index(unsigned int cpu_idx,
+			      const struct entry_point_info *ep);
+void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep);
+void cm_prepare_el3_exit(uint32_t security_state);
+
+#ifdef __aarch64__
+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);
+void cm_set_elr_spsr_el3(uint32_t security_state,
+			uintptr_t entrypoint, uint32_t spsr);
+void cm_write_scr_el3_bit(uint32_t security_state,
+			  uint32_t bit_pos,
+			  uint32_t value);
+void cm_set_next_eret_context(uint32_t security_state);
+uint32_t cm_get_scr_el3(uint32_t security_state);
+
+/* Inline definitions */
+
+/*******************************************************************************
+ * This function is used to program the context that's used for exception
+ * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for
+ * the required security state
+ ******************************************************************************/
+static inline void cm_set_next_context(void *context)
+{
+#if ENABLE_ASSERTIONS
+	uint64_t sp_mode;
+
+	/*
+	 * Check that this function is called with SP_EL0 as the stack
+	 * pointer
+	 */
+	__asm__ volatile("mrs	%0, SPSel\n"
+			 : "=r" (sp_mode));
+
+	assert(sp_mode == MODE_SP_EL0);
+#endif /* ENABLE_ASSERTIONS */
+
+	__asm__ volatile("msr	spsel, #1\n"
+			 "mov	sp, %0\n"
+			 "msr	spsel, #0\n"
+			 : : "r" (context));
+}
+
+#else
+void *cm_get_next_context(void);
+void cm_set_next_context(void *context);
+#endif /* __aarch64__ */
+
+#endif /* CONTEXT_MGMT_H */
diff --git a/include/lib/el3_runtime/cpu_data.h b/include/lib/el3_runtime/cpu_data.h
new file mode 100644
index 0000000..55db4cf
--- /dev/null
+++ b/include/lib/el3_runtime/cpu_data.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CPU_DATA_H
+#define CPU_DATA_H
+
+#include <platform_def.h>	/* CACHE_WRITEBACK_GRANULE required */
+
+#include <bl31/ehf.h>
+
+#ifdef __aarch64__
+
+/* Offsets for the cpu_data structure */
+#define CPU_DATA_CRASH_BUF_OFFSET	0x18
+/* need enough space in crash buffer to save 8 registers */
+#define CPU_DATA_CRASH_BUF_SIZE		64
+#define CPU_DATA_CPU_OPS_PTR		0x10
+
+#else /* __aarch64__ */
+
+#if CRASH_REPORTING
+#error "Crash reporting is not supported in AArch32"
+#endif
+#define CPU_DATA_CPU_OPS_PTR		0x0
+#define CPU_DATA_CRASH_BUF_OFFSET	0x4
+
+#endif /* __aarch64__ */
+
+#if CRASH_REPORTING
+#define CPU_DATA_CRASH_BUF_END		(CPU_DATA_CRASH_BUF_OFFSET + \
+						CPU_DATA_CRASH_BUF_SIZE)
+#else
+#define CPU_DATA_CRASH_BUF_END		CPU_DATA_CRASH_BUF_OFFSET
+#endif
+
+/* cpu_data size is the data size rounded up to the platform cache line size */
+#define CPU_DATA_SIZE			(((CPU_DATA_CRASH_BUF_END + \
+					CACHE_WRITEBACK_GRANULE - 1) / \
+						CACHE_WRITEBACK_GRANULE) * \
+							CACHE_WRITEBACK_GRANULE)
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+/* Temporary space to store PMF timestamps from assembly code */
+#define CPU_DATA_PMF_TS_COUNT		1
+#define CPU_DATA_PMF_TS0_OFFSET		CPU_DATA_CRASH_BUF_END
+#define CPU_DATA_PMF_TS0_IDX		0
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/* Offsets for the cpu_data structure */
+#define CPU_DATA_PSCI_LOCK_OFFSET	__builtin_offsetof\
+		(cpu_data_t, psci_svc_cpu_data.pcpu_bakery_info)
+
+#if PLAT_PCPU_DATA_SIZE
+#define CPU_DATA_PLAT_PCPU_OFFSET	__builtin_offsetof\
+		(cpu_data_t, platform_cpu_data)
+#endif
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Cache of frequently used per-cpu data:
+ *   Pointers to non-secure and secure security state contexts
+ *   Address of the crash stack
+ * It is aligned to the cache line boundary to allow efficient concurrent
+ * manipulation of these pointers on different cpus
+ *
+ * TODO: Add other commonly used variables to this (tf_issues#90)
+ *
+ * The data structure and the _cpu_data accessors should not be used directly
+ * by components that have per-cpu members. The member access macros should be
+ * used for this.
+ ******************************************************************************/
+typedef struct cpu_data {
+#ifdef __aarch64__
+	void *cpu_context[2];
+#endif
+	uintptr_t cpu_ops_ptr;
+#if CRASH_REPORTING
+	u_register_t crash_buf[CPU_DATA_CRASH_BUF_SIZE >> 3];
+#endif
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	uint64_t cpu_data_pmf_ts[CPU_DATA_PMF_TS_COUNT];
+#endif
+	struct psci_cpu_data psci_svc_cpu_data;
+#if PLAT_PCPU_DATA_SIZE
+	uint8_t platform_cpu_data[PLAT_PCPU_DATA_SIZE];
+#endif
+#if defined(IMAGE_BL31) && EL3_EXCEPTION_HANDLING
+	pe_exc_data_t ehf_data;
+#endif
+} __aligned(CACHE_WRITEBACK_GRANULE) cpu_data_t;
+
+extern cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
+
+#if CRASH_REPORTING
+/* verify assembler offsets match data structures */
+CASSERT(CPU_DATA_CRASH_BUF_OFFSET == __builtin_offsetof
+	(cpu_data_t, crash_buf),
+	assert_cpu_data_crash_stack_offset_mismatch);
+#endif
+
+CASSERT(CPU_DATA_SIZE == sizeof(cpu_data_t),
+		assert_cpu_data_size_mismatch);
+
+CASSERT(CPU_DATA_CPU_OPS_PTR == __builtin_offsetof
+		(cpu_data_t, cpu_ops_ptr),
+		assert_cpu_data_cpu_ops_ptr_offset_mismatch);
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+CASSERT(CPU_DATA_PMF_TS0_OFFSET == __builtin_offsetof
+		(cpu_data_t, cpu_data_pmf_ts[0]),
+		assert_cpu_data_pmf_ts0_offset_mismatch);
+#endif
+
+struct cpu_data *_cpu_data_by_index(uint32_t cpu_index);
+
+#ifdef __aarch64__
+/* Return the cpu_data structure for the current CPU. */
+static inline struct cpu_data *_cpu_data(void)
+{
+	return (cpu_data_t *)read_tpidr_el3();
+}
+#else
+struct cpu_data *_cpu_data(void);
+#endif
+
+/**************************************************************************
+ * APIs for initialising and accessing per-cpu data
+ *************************************************************************/
+
+void init_cpu_data_ptr(void);
+void init_cpu_ops(void);
+
+#define get_cpu_data(_m)		   _cpu_data()->_m
+#define set_cpu_data(_m, _v)		   _cpu_data()->_m = (_v)
+#define get_cpu_data_by_index(_ix, _m)	   _cpu_data_by_index(_ix)->_m
+#define set_cpu_data_by_index(_ix, _m, _v) _cpu_data_by_index(_ix)->_m = (_v)
+/* ((cpu_data_t *)0)->_m is a dummy to get the sizeof the struct member _m */
+#define flush_cpu_data(_m)	   flush_dcache_range((uintptr_t)	  \
+						&(_cpu_data()->_m), \
+						sizeof(((cpu_data_t *)0)->_m))
+#define inv_cpu_data(_m)	   inv_dcache_range((uintptr_t)	  	  \
+						&(_cpu_data()->_m), \
+						sizeof(((cpu_data_t *)0)->_m))
+#define flush_cpu_data_by_index(_ix, _m)	\
+				   flush_dcache_range((uintptr_t)	  \
+					 &(_cpu_data_by_index(_ix)->_m),  \
+						sizeof(((cpu_data_t *)0)->_m))
+
+
+#endif /* __ASSEMBLER__ */
+#endif /* CPU_DATA_H */
diff --git a/include/lib/el3_runtime/pubsub.h b/include/lib/el3_runtime/pubsub.h
new file mode 100644
index 0000000..64fe5cc
--- /dev/null
+++ b/include/lib/el3_runtime/pubsub.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PUBSUB_H
+#define PUBSUB_H
+
+#ifdef __LINKER__
+
+/* For the linker ... */
+#define __pubsub_start_sym(event)	__pubsub_##event##_start
+#define __pubsub_end_sym(event)		__pubsub_##event##_end
+#define __pubsub_section(event)		__pubsub_##event
+
+/*
+ * REGISTER_PUBSUB_EVENT has a different definition between linker and compiler
+ * contexts. In linker context, this collects pubsub sections for each event,
+ * placing guard symbols around each.
+ */
+#if defined(USE_ARM_LINK)
+#define REGISTER_PUBSUB_EVENT(event) \
+	__pubsub_start_sym(event) +0 FIXED \
+	{ \
+		*(__pubsub_section(event)) \
+	} \
+	__pubsub_end_sym(event) +0 FIXED EMPTY 0 \
+	{ \
+		/* placeholder */ \
+	}
+#else
+#define REGISTER_PUBSUB_EVENT(event) \
+	__pubsub_start_sym(event) = .; \
+	KEEP(*(__pubsub_section(event))); \
+	__pubsub_end_sym(event) = .
+#endif
+
+#else /* __LINKER__ */
+
+/* For the compiler ... */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+
+#if defined(USE_ARM_LINK)
+#define __pubsub_start_sym(event)	Load$$__pubsub_##event##_start$$Base
+#define __pubsub_end_sym(event)		Load$$__pubsub_##event##_end$$Base
+#else
+#define __pubsub_start_sym(event)	__pubsub_##event##_start
+#define __pubsub_end_sym(event)		__pubsub_##event##_end
+#endif
+
+#define __pubsub_section(event)		__section("__pubsub_" #event)
+
+/*
+ * In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols
+ * exported by the linker required for the other pubsub macros to work.
+ */
+#define REGISTER_PUBSUB_EVENT(event) \
+	extern pubsub_cb_t __pubsub_start_sym(event)[]; \
+	extern pubsub_cb_t __pubsub_end_sym(event)[]
+
+/*
+ * Have the function func called back when the specified event happens. This
+ * macro places the function address into the pubsub section, which is picked up
+ * and invoked by the invoke_pubsubs() function via the PUBLISH_EVENT* macros.
+ *
+ * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
+ */
+#define SUBSCRIBE_TO_EVENT(event, func) \
+	extern pubsub_cb_t __cb_func_##func##event __pubsub_section(event); \
+	pubsub_cb_t __cb_func_##func##event __pubsub_section(event) = (func)
+
+/*
+ * Iterate over subscribed handlers for a defined event. 'event' is the name of
+ * the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'.
+ */
+#define for_each_subscriber(event, subscriber) \
+	for (subscriber = __pubsub_start_sym(event); \
+			subscriber < __pubsub_end_sym(event); \
+			subscriber++)
+
+/*
+ * Publish a defined event supplying an argument. All subscribed handlers are
+ * invoked, but the return value of handlers are ignored for now.
+ */
+#define PUBLISH_EVENT_ARG(event, arg) \
+	do { \
+		pubsub_cb_t *subscriber; \
+		for_each_subscriber(event, subscriber) { \
+			(*subscriber)(arg); \
+		} \
+	} while (0)
+
+/* Publish a defined event with NULL argument */
+#define PUBLISH_EVENT(event)	PUBLISH_EVENT_ARG(event, NULL)
+
+/* Subscriber callback type */
+typedef void* (*pubsub_cb_t)(const void *arg);
+
+#endif	/* __LINKER__ */
+#endif /* PUBSUB_H */
diff --git a/include/lib/el3_runtime/pubsub_events.h b/include/lib/el3_runtime/pubsub_events.h
new file mode 100644
index 0000000..5012082
--- /dev/null
+++ b/include/lib/el3_runtime/pubsub_events.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/el3_runtime/pubsub.h>
+
+/*
+ * This file defines a list of pubsub events, declared using
+ * REGISTER_PUBSUB_EVENT() macro.
+ */
+
+/*
+ * Event published after a CPU has been powered up and finished its
+ * initialization.
+ */
+REGISTER_PUBSUB_EVENT(psci_cpu_on_finish);
+
+/*
+ * These events are published before/after a CPU has been powered down/up
+ * via the PSCI CPU SUSPEND API.
+ */
+REGISTER_PUBSUB_EVENT(psci_suspend_pwrdown_start);
+REGISTER_PUBSUB_EVENT(psci_suspend_pwrdown_finish);
+
+#ifdef __aarch64__
+/*
+ * These events are published by the AArch64 context management framework
+ * after the secure context is restored/saved via
+ * cm_el1_sysregs_context_{restore,save}() API.
+ */
+REGISTER_PUBSUB_EVENT(cm_entering_secure_world);
+REGISTER_PUBSUB_EVENT(cm_exited_secure_world);
+
+/*
+ * These events are published by the AArch64 context management framework
+ * after the normal context is restored/saved via
+ * cm_el1_sysregs_context_{restore,save}() API.
+ */
+REGISTER_PUBSUB_EVENT(cm_entering_normal_world);
+REGISTER_PUBSUB_EVENT(cm_exited_normal_world);
+#endif /* __aarch64__ */
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
new file mode 100644
index 0000000..99ecfcc
--- /dev/null
+++ b/include/lib/extensions/amu.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AMU_H
+#define AMU_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+
+/* All group 0 counters */
+#define AMU_GROUP0_COUNTERS_MASK	U(0xf)
+
+#ifdef PLAT_AMU_GROUP1_COUNTERS_MASK
+#define AMU_GROUP1_COUNTERS_MASK	PLAT_AMU_GROUP1_COUNTERS_MASK
+#else
+#define AMU_GROUP1_COUNTERS_MASK	U(0)
+#endif
+
+#ifdef PLAT_AMU_GROUP1_NR_COUNTERS
+#define AMU_GROUP1_NR_COUNTERS		PLAT_AMU_GROUP1_NR_COUNTERS
+#else
+#define AMU_GROUP1_NR_COUNTERS		U(0)
+#endif
+
+CASSERT(AMU_GROUP1_COUNTERS_MASK <= 0xffff, invalid_amu_group1_counters_mask);
+CASSERT(AMU_GROUP1_NR_COUNTERS <= 16, invalid_amu_group1_nr_counters);
+
+bool amu_supported(void);
+void amu_enable(bool el2_unused);
+
+/* Group 0 configuration helpers */
+uint64_t amu_group0_cnt_read(int idx);
+void amu_group0_cnt_write(int idx, uint64_t val);
+
+/* Group 1 configuration helpers */
+uint64_t amu_group1_cnt_read(int idx);
+void amu_group1_cnt_write(int idx, uint64_t val);
+void amu_group1_set_evtype(int idx, unsigned int val);
+
+#endif /* AMU_H */
diff --git a/include/lib/extensions/amu_private.h b/include/lib/extensions/amu_private.h
new file mode 100644
index 0000000..ab4e6aa
--- /dev/null
+++ b/include/lib/extensions/amu_private.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AMU_PRIVATE_H
+#define AMU_PRIVATE_H
+
+#include <stdint.h>
+
+uint64_t amu_group0_cnt_read_internal(int idx);
+void amu_group0_cnt_write_internal(int idx, uint64_t val);
+
+uint64_t amu_group1_cnt_read_internal(int idx);
+void amu_group1_cnt_write_internal(int idx, uint64_t val);
+void amu_group1_set_evtype_internal(int idx, unsigned int val);
+
+#endif /* AMU_PRIVATE_H */
diff --git a/include/lib/extensions/mpam.h b/include/lib/extensions/mpam.h
new file mode 100644
index 0000000..ac8c00a
--- /dev/null
+++ b/include/lib/extensions/mpam.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MPAM_H
+#define MPAM_H
+
+#include <stdbool.h>
+
+bool mpam_supported(void);
+void mpam_enable(bool el2_unused);
+
+#endif /* MPAM_H */
diff --git a/include/lib/extensions/ras.h b/include/lib/extensions/ras.h
new file mode 100644
index 0000000..4fc8f04
--- /dev/null
+++ b/include/lib/extensions/ras.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RAS_H
+#define RAS_H
+
+#define ERR_HANDLER_VERSION	1U
+
+/* Error record access mechanism */
+#define ERR_ACCESS_SYSREG	0
+#define ERR_ACCESS_MEMMAP	1
+
+/*
+ * Register all error records on the platform.
+ *
+ * This macro must be used in the same file as the array of error record info
+ * are declared. Only then would ARRAY_SIZE() yield a meaningful value.
+ */
+#define REGISTER_ERR_RECORD_INFO(_records) \
+	const struct err_record_mapping err_record_mappings = { \
+		.err_records = (_records), \
+		.num_err_records = ARRAY_SIZE(_records), \
+	}
+
+/* Error record info iterator */
+#define for_each_err_record_info(_i, _info) \
+	for ((_i) = 0, (_info) = err_record_mappings.err_records; \
+		(_i) < err_record_mappings.num_err_records; \
+		(_i)++, (_info)++)
+
+#define ERR_RECORD_COMMON_(_probe, _handler, _aux) \
+	.probe = _probe, \
+	.handler = _handler, \
+	.aux_data = _aux,
+
+#define ERR_RECORD_SYSREG_V1(_idx_start, _num_idx, _probe, _handler, _aux) \
+	{ \
+		.version = 1, \
+		.sysreg.idx_start = _idx_start, \
+		.sysreg.num_idx = _num_idx, \
+		.access = ERR_ACCESS_SYSREG, \
+		ERR_RECORD_COMMON_(_probe, _handler, _aux) \
+	}
+
+#define ERR_RECORD_MEMMAP_V1(_base_addr, _size_num_k, _probe, _handler, _aux) \
+	{ \
+		.version = 1, \
+		.memmap.base_addr = _base_addr, \
+		.memmap.size_num_k = _size_num_k, \
+		.access = ERR_ACCESS_MEMMAP, \
+		ERR_RECORD_COMMON_(_probe, _handler, _aux) \
+	}
+
+/*
+ * Macro to be used to name and declare an array of RAS interrupts along with
+ * their handlers.
+ *
+ * This macro must be used in the same file as the array of interrupts are
+ * declared. Only then would ARRAY_SIZE() yield a meaningful value. Also, the
+ * array is expected to be sorted in the increasing order of interrupt number.
+ */
+#define REGISTER_RAS_INTERRUPTS(_array) \
+	const struct ras_interrupt_mapping ras_interrupt_mappings = { \
+		.intrs = (_array), \
+		.num_intrs = ARRAY_SIZE(_array), \
+	}
+
+#ifndef __ASSEMBLER__
+
+#include <assert.h>
+
+#include <lib/extensions/ras_arch.h>
+
+struct err_record_info;
+
+struct ras_interrupt {
+	/* Interrupt number, and the associated error record info */
+	unsigned int intr_number;
+	struct err_record_info *err_record;
+	void *cookie;
+};
+
+/* Function to probe a error record group for error */
+typedef int (*err_record_probe_t)(const struct err_record_info *info,
+		int *probe_data);
+
+/* Data passed to error record group handler */
+struct err_handler_data {
+	/* Info passed on from top-level exception handler */
+	uint64_t flags;
+	void *cookie;
+	void *handle;
+
+	/* Data structure version */
+	unsigned int version;
+
+	/* Reason for EA: one the ERROR_* constants */
+	unsigned int ea_reason;
+
+	/*
+	 * For EAs received at vector, the value read from ESR; for an EA
+	 * synchronized by ESB, the value of DISR.
+	 */
+	uint32_t syndrome;
+
+	/* For errors signalled via interrupt, the raw interrupt ID; otherwise, 0. */
+	unsigned int interrupt;
+};
+
+/* Function to handle error from an error record group */
+typedef int (*err_record_handler_t)(const struct err_record_info *info,
+		int probe_data, const struct err_handler_data *const data);
+
+/* Error record information */
+struct err_record_info {
+	/* Function to probe error record group for errors */
+	err_record_probe_t probe;
+
+	/* Function to handle error record group errors */
+	err_record_handler_t handler;
+
+	/* Opaque group-specific data */
+	void *aux_data;
+
+	/* Additional information for Standard Error Records */
+	union {
+		struct {
+			/*
+			 * For a group accessed via memory-mapped register,
+			 * base address of the page hosting error records, and
+			 * the size of the record group.
+			 */
+			uintptr_t base_addr;
+
+			/* Size of group in number of KBs */
+			unsigned int size_num_k;
+		} memmap;
+
+		struct {
+			/*
+			 * For error records accessed via system register, index of
+			 * the error record.
+			 */
+			unsigned int idx_start;
+			unsigned int num_idx;
+		} sysreg;
+	};
+
+	/* Data structure version */
+	unsigned int version;
+
+	/* Error record access mechanism */
+	unsigned int access:1;
+};
+
+struct err_record_mapping {
+	struct err_record_info *err_records;
+	size_t num_err_records;
+};
+
+struct ras_interrupt_mapping {
+	struct ras_interrupt *intrs;
+	size_t num_intrs;
+};
+
+extern const struct err_record_mapping err_record_mappings;
+extern const struct ras_interrupt_mapping ras_interrupt_mappings;
+
+
+/*
+ * Helper functions to probe memory-mapped and system registers implemented in
+ * Standard Error Record format
+ */
+static inline int ras_err_ser_probe_memmap(const struct err_record_info *info,
+		int *probe_data)
+{
+	assert(info->version == ERR_HANDLER_VERSION);
+
+	return ser_probe_memmap(info->memmap.base_addr, info->memmap.size_num_k,
+		probe_data);
+}
+
+static inline int ras_err_ser_probe_sysreg(const struct err_record_info *info,
+		int *probe_data)
+{
+	assert(info->version == ERR_HANDLER_VERSION);
+
+	return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx,
+			probe_data);
+}
+
+int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+		void *handle, uint64_t flags);
+void ras_init(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* RAS_H */
diff --git a/include/lib/extensions/ras_arch.h b/include/lib/extensions/ras_arch.h
new file mode 100644
index 0000000..0c98c4a
--- /dev/null
+++ b/include/lib/extensions/ras_arch.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RAS_ARCH_H
+#define RAS_ARCH_H
+
+/*
+ * Size of nodes implementing Standard Error Records - currently only 4k is
+ * supported.
+ */
+#define STD_ERR_NODE_SIZE_NUM_K		4U
+
+/*
+ * Individual register offsets within an error record in Standard Error Record
+ * format when error records are accessed through memory-mapped registers.
+ */
+#define ERR_FR(n)	(0x0ULL + (64ULL * (n)))
+#define ERR_CTLR(n)	(0x8ULL + (64ULL * (n)))
+#define ERR_STATUS(n)	(0x10ULL + (64ULL * (n)))
+#define ERR_ADDR(n)	(0x18ULL + (64ULL * (n)))
+#define ERR_MISC0(n)	(0x20ULL + (64ULL * (n)))
+#define ERR_MISC1(n)	(0x28ULL + (64ULL * (n)))
+
+/* Group Status Register (ERR_STATUS) offset */
+#define ERR_GSR(base, size_num_k, n) \
+	((base) + (0x380ULL * (size_num_k)) + (8ULL * (n)))
+
+/* Management register offsets */
+#define ERR_DEVID(base, size_num_k) \
+	((base) + ((0x400ULL * (size_num_k)) - 0x100ULL) + 0xc8ULL)
+
+#define ERR_DEVID_MASK	0xffffUL
+
+/* Standard Error Record status register fields */
+#define ERR_STATUS_AV_SHIFT	31
+#define ERR_STATUS_AV_MASK	U(0x1)
+
+#define ERR_STATUS_V_SHIFT	30
+#define ERR_STATUS_V_MASK	U(0x1)
+
+#define ERR_STATUS_UE_SHIFT	29
+#define ERR_STATUS_UE_MASK	U(0x1)
+
+#define ERR_STATUS_ER_SHIFT	28
+#define ERR_STATUS_ER_MASK	U(0x1)
+
+#define ERR_STATUS_OF_SHIFT	27
+#define ERR_STATUS_OF_MASK	U(0x1)
+
+#define ERR_STATUS_MV_SHIFT	26
+#define ERR_STATUS_MV_MASK	U(0x1)
+
+#define ERR_STATUS_CE_SHIFT	24
+#define ERR_STATUS_CE_MASK	U(0x3)
+
+#define ERR_STATUS_DE_SHIFT	23
+#define ERR_STATUS_DE_MASK	U(0x1)
+
+#define ERR_STATUS_PN_SHIFT	22
+#define ERR_STATUS_PN_MASK	U(0x1)
+
+#define ERR_STATUS_UET_SHIFT	20
+#define ERR_STATUS_UET_MASK	U(0x3)
+
+#define ERR_STATUS_IERR_SHIFT	8
+#define ERR_STATUS_IERR_MASK	U(0xff)
+
+#define ERR_STATUS_SERR_SHIFT	0
+#define ERR_STATUS_SERR_MASK	U(0xff)
+
+#define ERR_STATUS_GET_FIELD(_status, _field) \
+	(((_status) >> ERR_STATUS_ ##_field ##_SHIFT) & ERR_STATUS_ ##_field ##_MASK)
+
+#define ERR_STATUS_CLR_FIELD(_status, _field) \
+	(_status) &= ~(ERR_STATUS_ ##_field ##_MASK << ERR_STATUS_ ##_field ##_SHIFT)
+
+#define ERR_STATUS_SET_FIELD(_status, _field, _value) \
+	(_status) |= (((_value) & ERR_STATUS_ ##_field ##_MASK) << ERR_STATUS_ ##_field ##_SHIFT)
+
+#define ERR_STATUS_WRITE_FIELD(_status, _field, _value) do { \
+		ERR_STATUS_CLR_FIELD(_status, _field, _value); \
+		ERR_STATUS_SET_FIELD(_status, _field, _value); \
+	} while (0)
+
+
+/* Standard Error Record control register fields */
+#define ERR_CTLR_WDUI_SHIFT	11
+#define ERR_CTLR_WDUI_MASK	0x1
+
+#define ERR_CTLR_RDUI_SHIFT	10
+#define ERR_CTLR_RDUI_MASK	0x1
+#define ERR_CTLR_DUI_SHIFT	ERR_CTLR_RDUI_SHIFT
+#define ERR_CTLR_DUI_MASK	ERR_CTLR_RDUI_MASK
+
+#define ERR_CTLR_WCFI_SHIFT	9
+#define ERR_CTLR_WCFI_MASK	0x1
+
+#define ERR_CTLR_RCFI_SHIFT	8
+#define ERR_CTLR_RCFI_MASK	0x1
+#define ERR_CTLR_CFI_SHIFT	ERR_CTLR_RCFI_SHIFT
+#define ERR_CTLR_CFI_MASK	ERR_CTLR_RCFI_MASK
+
+#define ERR_CTLR_WUE_SHIFT	7
+#define ERR_CTLR_WUE_MASK	0x1
+
+#define ERR_CTLR_WFI_SHIFT	6
+#define ERR_CTLR_WFI_MASK	0x1
+
+#define ERR_CTLR_WUI_SHIFT	5
+#define ERR_CTLR_WUI_MASK	0x1
+
+#define ERR_CTLR_RUE_SHIFT	4
+#define ERR_CTLR_RUE_MASK	0x1
+#define ERR_CTLR_UE_SHIFT	ERR_CTLR_RUE_SHIFT
+#define ERR_CTLR_UE_MASK	ERR_CTLR_RUE_MASK
+
+#define ERR_CTLR_RFI_SHIFT	3
+#define ERR_CTLR_RFI_MASK	0x1
+#define ERR_CTLR_FI_SHIFT	ERR_CTLR_RFI_SHIFT
+#define ERR_CTLR_FI_MASK	ERR_CTLR_RFI_MASK
+
+#define ERR_CTLR_RUI_SHIFT	2
+#define ERR_CTLR_RUI_MASK	0x1
+#define ERR_CTLR_UI_SHIFT	ERR_CTLR_RUI_SHIFT
+#define ERR_CTLR_UI_MASK	ERR_CTLR_RUI_MASK
+
+#define ERR_CTLR_ED_SHIFT	0
+#define ERR_CTLR_ED_MASK	0x1
+
+#define ERR_CTLR_CLR_FIELD(_ctlr, _field) \
+	(_ctlr) &= ~(ERR_CTLR_ ##_field _MASK << ERR_CTLR_ ##_field ##_SHIFT)
+
+#define ERR_CTLR_SET_FIELD(_ctlr, _field, _value) \
+	(_ctlr) |= (((_value) & ERR_CTLR_ ##_field ##_MASK) << ERR_CTLR_ ##_field ##_SHIFT)
+
+#define ERR_CTLR_ENABLE_FIELD(_ctlr, _field) \
+	ERR_CTLR_SET_FIELD(_ctlr, _field, ERR_CTLR_ ##_field ##_MASK)
+
+/* Uncorrected error types for Asynchronous exceptions */
+#define ERROR_STATUS_UET_UC	0x0	/* Uncontainable */
+#define ERROR_STATUS_UET_UEU	0x1	/* Unrecoverable */
+#define ERROR_STATUS_UET_UEO	0x2	/* Restable */
+#define ERROR_STATUS_UET_UER	0x3	/* Recoverable */
+
+/* Error types for Synchronous exceptions */
+#define ERROR_STATUS_SET_UER	0x0	/* Recoverable */
+#define ERROR_STATUS_SET_UEO	0x1	/* Restable */
+#define ERROR_STATUS_SET_UC	0x2     /* Uncontainable */
+#define ERROR_STATUS_SET_CE	0x3     /* Corrected */
+
+/* Implementation Defined Syndrome bit in ESR */
+#define SERROR_IDS_BIT		U(24)
+
+/*
+ * Asynchronous Error Type in exception syndrome. The field has same values in
+ * both DISR_EL1 and ESR_EL3 for SError.
+ */
+#define EABORT_AET_SHIFT	U(10)
+#define EABORT_AET_WIDTH	U(3)
+#define EABORT_AET_MASK		U(0x7)
+
+/* DFSC field in Asynchronous exception syndrome */
+#define EABORT_DFSC_SHIFT	U(0)
+#define EABORT_DFSC_WIDTH	U(6)
+#define EABORT_DFSC_MASK	U(0x3f)
+
+/* Synchronous Error Type in exception syndrome. */
+#define EABORT_SET_SHIFT	U(11)
+#define EABORT_SET_WIDTH	U(2)
+#define EABORT_SET_MASK		U(0x3)
+
+/* DFSC code for SErrors */
+#define DFSC_SERROR		0x11
+
+/* I/DFSC code for synchronous external abort */
+#define SYNC_EA_FSC		0x10
+
+#ifndef __ASSEMBLER__
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <context.h>
+#include <lib/mmio.h>
+#include <stdint.h>
+
+/*
+ * Standard Error Record accessors for memory-mapped registers.
+ */
+
+static inline uint64_t ser_get_feature(uintptr_t base, unsigned int idx)
+{
+	return mmio_read_64(base + ERR_FR(idx));
+}
+
+static inline uint64_t ser_get_control(uintptr_t base, unsigned int idx)
+{
+	return mmio_read_64(base + ERR_CTLR(idx));
+}
+
+static inline uint64_t ser_get_status(uintptr_t base, unsigned int idx)
+{
+	return mmio_read_64(base + ERR_STATUS(idx));
+}
+
+/*
+ * Error handling agent would write to the status register to clear an
+ * identified/handled error. Most fields in the status register are
+ * conditional write-one-to-clear.
+ *
+ * Typically, to clear the status, it suffices to write back the same value
+ * previously read. However, if there were new, higher-priority errors recorded
+ * on the node since status was last read, writing read value won't clear the
+ * status. Therefore, an error handling agent must wait on and verify the status
+ * has indeed been cleared.
+ */
+static inline void ser_set_status(uintptr_t base, unsigned int idx,
+		uint64_t status)
+{
+	mmio_write_64(base + ERR_STATUS(idx), status);
+}
+
+static inline uint64_t ser_get_addr(uintptr_t base, unsigned int idx)
+{
+	return mmio_read_64(base + ERR_ADDR(idx));
+}
+
+static inline uint64_t ser_get_misc0(uintptr_t base, unsigned int idx)
+{
+	return mmio_read_64(base + ERR_MISC0(idx));
+}
+
+static inline uint64_t ser_get_misc1(uintptr_t base, unsigned int idx)
+{
+	return mmio_read_64(base + ERR_MISC1(idx));
+}
+
+
+/*
+ * Standard Error Record helpers for System registers.
+ */
+static inline void ser_sys_select_record(unsigned int idx)
+{
+	unsigned int max_idx __unused =
+		(unsigned int) read_erridr_el1() & ERRIDR_MASK;
+
+	assert(idx < max_idx);
+
+	write_errselr_el1(idx);
+	isb();
+}
+
+/* Library functions to probe Standard Error Record */
+int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data);
+int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data);
+#endif /* __ASSEMBLER__ */
+
+#endif /* RAS_ARCH_H */
diff --git a/include/lib/extensions/spe.h b/include/lib/extensions/spe.h
new file mode 100644
index 0000000..d4b925f
--- /dev/null
+++ b/include/lib/extensions/spe.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPE_H
+#define SPE_H
+
+#include <stdbool.h>
+
+bool spe_supported(void);
+void spe_enable(bool el2_unused);
+void spe_disable(void);
+
+#endif /* SPE_H */
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
new file mode 100644
index 0000000..83df177
--- /dev/null
+++ b/include/lib/extensions/sve.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SVE_H
+#define SVE_H
+
+#include <stdbool.h>
+
+bool sve_supported(void);
+void sve_enable(bool el2_unused);
+
+#endif /* SVE_H */
diff --git a/include/lib/libc/aarch32/endian_.h b/include/lib/libc/aarch32/endian_.h
new file mode 100644
index 0000000..0cf2c75
--- /dev/null
+++ b/include/lib/libc/aarch32/endian_.h
@@ -0,0 +1,146 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 David E. O'Brien
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)endian.h	8.1 (Berkeley) 6/10/93
+ * $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $
+ * $FreeBSD$
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef ENDIAN__H
+#define ENDIAN__H
+
+#include <stdint.h>
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define _LITTLE_ENDIAN  1234    /* LSB first: i386, vax */
+#define _BIG_ENDIAN     4321    /* MSB first: 68000, ibm, net */
+#define _PDP_ENDIAN     3412    /* LSB first in word, MSW first in long */
+
+#ifdef __ARMEB__
+#define _BYTE_ORDER	_BIG_ENDIAN
+#else
+#define	_BYTE_ORDER	_LITTLE_ENDIAN
+#endif /* __ARMEB__ */
+
+#if __BSD_VISIBLE
+#define LITTLE_ENDIAN   _LITTLE_ENDIAN
+#define BIG_ENDIAN      _BIG_ENDIAN
+#define PDP_ENDIAN      _PDP_ENDIAN
+#define BYTE_ORDER      _BYTE_ORDER
+#endif
+
+#ifdef __ARMEB__
+#define _QUAD_HIGHWORD 0
+#define _QUAD_LOWWORD 1
+#define __ntohl(x)	((uint32_t)(x))
+#define __ntohs(x)	((uint16_t)(x))
+#define __htonl(x)	((uint32_t)(x))
+#define __htons(x)	((uint16_t)(x))
+#else
+#define _QUAD_HIGHWORD  1
+#define _QUAD_LOWWORD 0
+#define __ntohl(x)        (__bswap32(x))
+#define __ntohs(x)        (__bswap16(x))
+#define __htonl(x)        (__bswap32(x))
+#define __htons(x)        (__bswap16(x))
+#endif /* __ARMEB__ */
+
+static __inline uint64_t
+__bswap64(uint64_t _x)
+{
+
+	return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) |
+	    ((_x >> 8) & 0xff000000) | ((_x << 8) & ((uint64_t)0xff << 32)) |
+	    ((_x << 24) & ((uint64_t)0xff << 40)) |
+	    ((_x << 40) & ((uint64_t)0xff << 48)) | ((_x << 56)));
+}
+
+static __inline uint32_t
+__bswap32_var(uint32_t v)
+{
+	uint32_t t1;
+
+	__asm __volatile("eor %1, %0, %0, ror #16\n"
+	    		"bic %1, %1, #0x00ff0000\n"
+			"mov %0, %0, ror #8\n"
+			"eor %0, %0, %1, lsr #8\n"
+			 : "+r" (v), "=r" (t1));
+
+	return (v);
+}
+
+static __inline uint16_t
+__bswap16_var(uint16_t v)
+{
+	uint32_t ret = v & 0xffff;
+
+	__asm __volatile(
+	    "mov    %0, %0, ror #8\n"
+	    "orr    %0, %0, %0, lsr #16\n"
+	    "bic    %0, %0, %0, lsl #16"
+	    : "+r" (ret));
+
+	return ((uint16_t)ret);
+}
+
+#ifdef __OPTIMIZE__
+
+#define __bswap32_constant(x)	\
+    ((((x) & 0xff000000U) >> 24) |	\
+     (((x) & 0x00ff0000U) >>  8) |	\
+     (((x) & 0x0000ff00U) <<  8) |	\
+     (((x) & 0x000000ffU) << 24))
+
+#define __bswap16_constant(x)	\
+    ((((x) & 0xff00) >> 8) |		\
+     (((x) & 0x00ff) << 8))
+
+#define __bswap16(x)	\
+    ((uint16_t)(__builtin_constant_p(x) ?	\
+     __bswap16_constant(x) :			\
+     __bswap16_var(x)))
+
+#define __bswap32(x)	\
+    ((uint32_t)(__builtin_constant_p(x) ? 	\
+     __bswap32_constant(x) :			\
+     __bswap32_var(x)))
+
+#else
+#define __bswap16(x)	__bswap16_var(x)
+#define __bswap32(x)	__bswap32_var(x)
+
+#endif /* __OPTIMIZE__ */
+#endif /* ENDIAN__H */
diff --git a/include/lib/libc/aarch32/limits_.h b/include/lib/libc/aarch32/limits_.h
new file mode 100644
index 0000000..26cec17
--- /dev/null
+++ b/include/lib/libc/aarch32/limits_.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define SCHAR_MAX  0x7F
+#define SCHAR_MIN  (-SCHAR_MIN - 1)
+#define CHAR_MAX   0x7F
+#define CHAR_MIN   (-CHAR_MAX - 1)
+#define UCHAR_MAX  0xFFU
+#define SHRT_MAX   0x7FFF
+#define SHRT_MIN   (-SHRT_MAX - 1)
+#define USHRT_MAX  0xFFFFU
+#define INT_MAX    0x7FFFFFFF
+#define INT_MIN    (-INT_MAX - 1)
+#define UINT_MAX   0xFFFFFFFFU
+#define LONG_MAX   0x7FFFFFFFL
+#define LONG_MIN   (-LONG_MAX - 1L)
+#define ULONG_MAX  0xFFFFFFFFUL
+#define LLONG_MAX  0x7FFFFFFFFFFFFFFFLL
+#define LLONG_MIN  (-LLONG_MAX - 1LL)
+#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
+
+#define __LONG_BIT 32
+#define __WORD_BIT 32
diff --git a/include/lib/libc/aarch32/stddef_.h b/include/lib/libc/aarch32/stddef_.h
new file mode 100644
index 0000000..1babfad
--- /dev/null
+++ b/include/lib/libc/aarch32/stddef_.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDDEF__H
+#define STDDEF__H
+
+#ifndef SIZET_
+typedef unsigned int size_t;
+#define SIZET_
+#endif
+
+#ifndef _PTRDIFF_T
+typedef long ptrdiff_t;
+#define _PTRDIFF_T
+#endif
+
+#endif /* STDDEF__H */
diff --git a/include/lib/libc/aarch32/stdint_.h b/include/lib/libc/aarch32/stdint_.h
new file mode 100644
index 0000000..4f49485
--- /dev/null
+++ b/include/lib/libc/aarch32/stdint_.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define INT8_MAX  0x7F
+#define INT8_MIN  (-INT8_MAX - 1)
+#define UINT8_MAX 0xFFU
+
+#define INT16_MAX  0x7FFF
+#define INT16_MIN  (-INT16_MAX - 1)
+#define UINT16_MAX 0xFFFFU
+
+#define INT32_MAX  0x7FFFFFFF
+#define INT32_MIN  (-INT32_MAX - 1)
+#define UINT32_MAX 0xFFFFFFFFU
+
+#define INT64_MAX  0x7FFFFFFFFFFFFFFFLL
+#define INT64_MIN  (-INT64_MAX - 1LL)
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
+
+#define INT_LEAST8_MIN  INT8_MIN
+#define INT_LEAST8_MAX  INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+
+#define INT_LEAST16_MIN  INT16_MIN
+#define INT_LEAST16_MAX  INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+
+#define INT_LEAST32_MIN  INT32_MIN
+#define INT_LEAST32_MAX  INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+
+#define INT_LEAST64_MIN  INT64_MIN
+#define INT_LEAST64_MAX  INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT_FAST8_MIN  INT32_MIN
+#define INT_FAST8_MAX  INT32_MAX
+#define UINT_FAST8_MAX UINT32_MAX
+
+#define INT_FAST16_MIN  INT32_MIN
+#define INT_FAST16_MAX  INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+
+#define INT_FAST32_MIN  INT32_MIN
+#define INT_FAST32_MAX  INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INT_FAST64_MIN  INT64_MIN
+#define INT_FAST64_MAX  INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INTPTR_MIN  INT32_MIN
+#define INTPTR_MAX  INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+
+#define INTMAX_MIN  INT64_MIN
+#define INTMAX_MAX  INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+
+#define SIZE_MAX UINT32_MAX
+
+#define INT8_C(x)  x
+#define INT16_C(x) x
+#define INT32_C(x) x
+#define INT64_C(x) x ## LL
+
+#define UINT8_C(x)  x
+#define UINT16_C(x) x
+#define UINT32_C(x) x ## U
+#define UINT64_C(x) x ## ULL
+
+#define INTMAX_C(x)  x ## LL
+#define UINTMAX_C(x) x ## ULL
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_least_t;
+typedef short int16_least_t;
+typedef int int32_least_t;
+typedef long long int64_least_t;
+
+typedef unsigned char uint8_least_t;
+typedef unsigned short uint16_least_t;
+typedef unsigned int uint32_least_t;
+typedef unsigned long long uint64_least_t;
+
+typedef int int8_fast_t;
+typedef int int16_fast_t;
+typedef int int32_fast_t;
+typedef long long int64_fast_t;
+
+typedef unsigned int uint8_fast_t;
+typedef unsigned int uint16_fast_t;
+typedef unsigned int uint32_fast_t;
+typedef unsigned long long uint64_fast_t;
+
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+
+typedef long long intmax_t;
+typedef unsigned long long uintmax_t;
+
+typedef long register_t;
+typedef unsigned long u_register_t;
diff --git a/include/lib/libc/aarch32/stdio_.h b/include/lib/libc/aarch32/stdio_.h
new file mode 100644
index 0000000..50d3cc2
--- /dev/null
+++ b/include/lib/libc/aarch32/stdio_.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDIO__H
+#define STDIO__H
+
+#ifndef SIZET_
+typedef unsigned int size_t;
+#define SIZET_
+#endif
+
+#ifndef SSIZET_
+typedef int ssize_t;
+#define SSIZET_
+#endif
+
+#endif /* STDIO__H */
diff --git a/include/lib/libc/aarch32/stdlib_.h b/include/lib/libc/aarch32/stdlib_.h
new file mode 100644
index 0000000..9c07857
--- /dev/null
+++ b/include/lib/libc/aarch32/stdlib_.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDLIB__H
+#define STDLIB__H
+
+#ifndef SIZET_
+typedef unsigned int size_t;
+#define SIZET_
+#endif
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+#endif /* STDLIB__H */
diff --git a/include/lib/libc/aarch32/string_.h b/include/lib/libc/aarch32/string_.h
new file mode 100644
index 0000000..4e139b0
--- /dev/null
+++ b/include/lib/libc/aarch32/string_.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STRING__H
+#define STRING__H
+
+#ifndef SIZET_
+typedef unsigned int size_t;
+#define SIZET_
+#endif
+
+#endif /* STRING__H */
diff --git a/include/lib/libc/aarch32/time_.h b/include/lib/libc/aarch32/time_.h
new file mode 100644
index 0000000..a9169c2
--- /dev/null
+++ b/include/lib/libc/aarch32/time_.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TIME__H
+#define TIME__H
+
+#ifndef SIZET_
+typedef unsigned int size_t;
+#define SIZET_
+#endif
+
+typedef long int time_t;
+
+#endif /* TIME__H */
diff --git a/include/lib/libc/aarch64/endian_.h b/include/lib/libc/aarch64/endian_.h
new file mode 100644
index 0000000..7c79fd4
--- /dev/null
+++ b/include/lib/libc/aarch64/endian_.h
@@ -0,0 +1,128 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2001 David E. O'Brien
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)endian.h	8.1 (Berkeley) 6/10/93
+ * $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $
+ * $FreeBSD$
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef ENDIAN__H
+#define ENDIAN__H
+
+#include <stdint.h>
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define	_LITTLE_ENDIAN  1234    /* LSB first: i386, vax */
+#define	_BIG_ENDIAN     4321    /* MSB first: 68000, ibm, net */
+#define	_PDP_ENDIAN     3412    /* LSB first in word, MSW first in long */
+
+#define	_BYTE_ORDER	_LITTLE_ENDIAN
+
+#if __BSD_VISIBLE
+#define	LITTLE_ENDIAN   _LITTLE_ENDIAN
+#define	BIG_ENDIAN      _BIG_ENDIAN
+#define	PDP_ENDIAN      _PDP_ENDIAN
+#define	BYTE_ORDER      _BYTE_ORDER
+#endif
+
+#define	_QUAD_HIGHWORD  1
+#define	_QUAD_LOWWORD 0
+#define	__ntohl(x)        (__bswap32(x))
+#define	__ntohs(x)        (__bswap16(x))
+#define	__htonl(x)        (__bswap32(x))
+#define	__htons(x)        (__bswap16(x))
+
+static __inline uint64_t
+__bswap64(uint64_t x)
+{
+	uint64_t ret;
+
+	__asm __volatile("rev %0, %1\n"
+			 : "=&r" (ret), "+r" (x));
+
+	return (ret);
+}
+
+static __inline uint32_t
+__bswap32_var(uint32_t v)
+{
+	uint32_t ret;
+
+	__asm __volatile("rev32 %x0, %x1\n"
+			 : "=&r" (ret), "+r" (v));
+
+	return (ret);
+}
+
+static __inline uint16_t
+__bswap16_var(uint16_t v)
+{
+	uint32_t ret;
+
+	__asm __volatile("rev16 %w0, %w1\n"
+			 : "=&r" (ret), "+r" (v));
+
+	return ((uint16_t)ret);
+}
+
+#ifdef __OPTIMIZE__
+
+#define	__bswap32_constant(x)	\
+    ((((x) & 0xff000000U) >> 24) |	\
+     (((x) & 0x00ff0000U) >>  8) |	\
+     (((x) & 0x0000ff00U) <<  8) |	\
+     (((x) & 0x000000ffU) << 24))
+
+#define	__bswap16_constant(x)	\
+    ((((x) & 0xff00) >> 8) |		\
+     (((x) & 0x00ff) << 8))
+
+#define	__bswap16(x)	\
+    ((uint16_t)(__builtin_constant_p(x) ?	\
+     __bswap16_constant((uint16_t)(x)) :	\
+     __bswap16_var(x)))
+
+#define	__bswap32(x)	\
+    ((uint32_t)(__builtin_constant_p(x) ? 	\
+     __bswap32_constant((uint32_t)(x)) :	\
+     __bswap32_var(x)))
+
+#else
+#define	__bswap16(x)	__bswap16_var(x)
+#define	__bswap32(x)	__bswap32_var(x)
+
+#endif /* __OPTIMIZE__ */
+#endif /* ENDIAN__H */
diff --git a/include/lib/libc/aarch64/limits_.h b/include/lib/libc/aarch64/limits_.h
new file mode 100644
index 0000000..e36cfe7
--- /dev/null
+++ b/include/lib/libc/aarch64/limits_.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define SCHAR_MAX  0x7F
+#define SCHAR_MIN  (-SCHAR_MIN - 1)
+#define CHAR_MAX   0x7F
+#define CHAR_MIN   (-CHAR_MAX - 1)
+#define UCHAR_MAX  0xFFU
+#define SHRT_MAX   0x7FFF
+#define SHRT_MIN   (-SHRT_MAX - 1)
+#define USHRT_MAX  0xFFFFU
+#define INT_MAX    0x7FFFFFFF
+#define INT_MIN    (-INT_MAX - 1)
+#define UINT_MAX   0xFFFFFFFFU
+#define LONG_MAX   0x7FFFFFFFFFFFFFFFL
+#define LONG_MIN   (-LONG_MAX - 1L)
+#define ULONG_MAX  0xFFFFFFFFFFFFFFFFUL
+#define LLONG_MAX  0x7FFFFFFFFFFFFFFFLL
+#define LLONG_MIN  (-LLONG_MAX - 1LL)
+#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
+
+#define __LONG_BIT 64
+#define __WORD_BIT 32
diff --git a/include/lib/libc/aarch64/setjmp_.h b/include/lib/libc/aarch64/setjmp_.h
new file mode 100644
index 0000000..f880a17
--- /dev/null
+++ b/include/lib/libc/aarch64/setjmp_.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SETJMP__H
+#define SETJMP__H
+
+#define JMP_CTX_X19	0x0
+#define JMP_CTX_X21	0x10
+#define JMP_CTX_X23	0x20
+#define JMP_CTX_X25	0x30
+#define JMP_CTX_X27	0x40
+#define JMP_CTX_X29	0x50
+#define JMP_CTX_SP	0x60
+#define JMP_CTX_END	0x70 /* Aligned to 16 bytes */
+
+#define JMP_SIZE	(JMP_CTX_END >> 3)
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+
+/* Jump buffer hosting x18 - x30 and sp_el0 registers */
+typedef uint64_t jmp_buf[JMP_SIZE] __aligned(16);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SETJMP__H */
diff --git a/include/lib/libc/aarch64/stddef_.h b/include/lib/libc/aarch64/stddef_.h
new file mode 100644
index 0000000..b7d8209
--- /dev/null
+++ b/include/lib/libc/aarch64/stddef_.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDDEF__H
+#define STDDEF__H
+
+#ifndef SIZET_
+typedef unsigned long size_t;
+#define SIZET_
+#endif
+
+#ifndef _PTRDIFF_T
+typedef long ptrdiff_t;
+#define _PTRDIFF_T
+#endif
+
+#endif /* STDDEF__H */
diff --git a/include/lib/libc/aarch64/stdint_.h b/include/lib/libc/aarch64/stdint_.h
new file mode 100644
index 0000000..b17a435
--- /dev/null
+++ b/include/lib/libc/aarch64/stdint_.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define INT8_MAX  0x7F
+#define INT8_MIN  (-INT8_MAX - 1)
+#define UINT8_MAX 0xFFU
+
+#define INT16_MAX  0x7FFF
+#define INT16_MIN  (-INT16_MAX - 1)
+#define UINT16_MAX 0xFFFFU
+
+#define INT32_MAX  0x7FFFFFFF
+#define INT32_MIN  (-INT32_MAX - 1)
+#define UINT32_MAX 0xFFFFFFFFU
+
+#define INT64_MAX  0x7FFFFFFFFFFFFFFFLL
+#define INT64_MIN  (-INT64_MAX - 1LL)
+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
+
+#define INT_LEAST8_MIN  INT8_MIN
+#define INT_LEAST8_MAX  INT8_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+
+#define INT_LEAST16_MIN  INT16_MIN
+#define INT_LEAST16_MAX  INT16_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+
+#define INT_LEAST32_MIN  INT32_MIN
+#define INT_LEAST32_MAX  INT32_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+
+#define INT_LEAST64_MIN  INT64_MIN
+#define INT_LEAST64_MAX  INT64_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT_FAST8_MIN  INT32_MIN
+#define INT_FAST8_MAX  INT32_MAX
+#define UINT_FAST8_MAX UINT32_MAX
+
+#define INT_FAST16_MIN  INT32_MIN
+#define INT_FAST16_MAX  INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+
+#define INT_FAST32_MIN  INT32_MIN
+#define INT_FAST32_MAX  INT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INT_FAST64_MIN  INT64_MIN
+#define INT_FAST64_MAX  INT64_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INTPTR_MIN  INT64_MIN
+#define INTPTR_MAX  INT64_MAX
+#define UINTPTR_MAX UINT64_MAX
+
+#define INTMAX_MIN  INT64_MIN
+#define INTMAX_MAX  INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#define PTRDIFF_MIN INT64_MIN
+#define PTRDIFF_MAX INT64_MAX
+
+#define SIZE_MAX UINT64_MAX
+
+#define INT8_C(x)  x
+#define INT16_C(x) x
+#define INT32_C(x) x
+#define INT64_C(x) x ## LL
+
+#define UINT8_C(x)  x
+#define UINT16_C(x) x
+#define UINT32_C(x) x ## U
+#define UINT64_C(x) x ## ULL
+
+#define INTMAX_C(x)  x ## L
+#define UINTMAX_C(x) x ## ULL
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_least_t;
+typedef short int16_least_t;
+typedef int int32_least_t;
+typedef long long int64_least_t;
+
+typedef unsigned char uint8_least_t;
+typedef unsigned short uint16_least_t;
+typedef unsigned int uint32_least_t;
+typedef unsigned long long uint64_least_t;
+
+typedef int int8_fast_t;
+typedef int int16_fast_t;
+typedef int int32_fast_t;
+typedef long long int64_fast_t;
+
+typedef unsigned int uint8_fast_t;
+typedef unsigned int uint16_fast_t;
+typedef unsigned int uint32_fast_t;
+typedef unsigned long long uint64_fast_t;
+
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+
+typedef long intmax_t;
+typedef unsigned long uintmax_t;
+
+typedef long register_t;
+typedef unsigned long u_register_t;
+
+typedef __int128 int128_t;
+typedef unsigned __int128 uint128_t;
diff --git a/include/lib/libc/aarch64/stdio_.h b/include/lib/libc/aarch64/stdio_.h
new file mode 100644
index 0000000..09b0172
--- /dev/null
+++ b/include/lib/libc/aarch64/stdio_.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDIO__H
+#define STDIO__H
+
+#ifndef SIZET_
+typedef unsigned long size_t;
+#define SIZET_
+#endif
+
+#ifndef SSIZET_
+typedef long ssize_t;
+#define SSIZET_
+#endif
+
+#endif /* STDIO__H */
diff --git a/include/lib/libc/aarch64/stdlib_.h b/include/lib/libc/aarch64/stdlib_.h
new file mode 100644
index 0000000..81a39d1
--- /dev/null
+++ b/include/lib/libc/aarch64/stdlib_.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDLIB__H
+#define STDLIB__H
+
+#ifndef SIZET_
+typedef unsigned long size_t;
+#define SIZET_
+#endif
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+#endif /* STDLIB__H */
diff --git a/include/lib/libc/aarch64/string_.h b/include/lib/libc/aarch64/string_.h
new file mode 100644
index 0000000..71c51a6
--- /dev/null
+++ b/include/lib/libc/aarch64/string_.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STRING__H
+#define STRING__H
+
+#ifndef SIZET_
+typedef unsigned long size_t;
+#define SIZET_
+#endif
+
+#endif /* STRING__H */
diff --git a/include/lib/libc/aarch64/time_.h b/include/lib/libc/aarch64/time_.h
new file mode 100644
index 0000000..68ab1b8
--- /dev/null
+++ b/include/lib/libc/aarch64/time_.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TIME__H
+#define TIME__H
+
+#ifndef SIZET_
+typedef unsigned long size_t;
+#define SIZET_
+#endif
+
+typedef long int time_t;
+
+#endif /* TIME__H */
diff --git a/include/lib/libc/assert.h b/include/lib/libc/assert.h
new file mode 100644
index 0000000..d04f9dc
--- /dev/null
+++ b/include/lib/libc/assert.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ASSERT_H
+#define ASSERT_H
+
+#include <cdefs.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+
+#ifndef PLAT_LOG_LEVEL_ASSERT
+#define PLAT_LOG_LEVEL_ASSERT	LOG_LEVEL
+#endif
+
+#if ENABLE_ASSERTIONS
+# if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE
+#  define assert(e)	((e) ? (void)0 : __assert(__FILE__, __LINE__, #e))
+# elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO
+#  define assert(e)	((e) ? (void)0 : __assert(__FILE__, __LINE__))
+# else
+#  define assert(e)	((e) ? (void)0 : __assert())
+# endif
+#else
+#define assert(e)	((void)0)
+#endif /* ENABLE_ASSERTIONS */
+
+#if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE
+__dead2 void __assert(const char *file, unsigned int line,
+		      const char *assertion);
+#elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO
+__dead2 void __assert(const char *file, unsigned int line);
+#else
+__dead2 void __assert(void);
+#endif
+
+#endif /* ASSERT_H */
diff --git a/include/lib/libc/cdefs.h b/include/lib/libc/cdefs.h
new file mode 100644
index 0000000..0d00722
--- /dev/null
+++ b/include/lib/libc/cdefs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CDEFS_H
+#define CDEFS_H
+
+#define __dead2		__attribute__((__noreturn__))
+#define __deprecated	__attribute__((__deprecated__))
+#define __packed	__attribute__((__packed__))
+#define __used		__attribute__((__used__))
+#define __unused	__attribute__((__unused__))
+#define __aligned(x)	__attribute__((__aligned__(x)))
+#define __section(x)	__attribute__((__section__(x)))
+#if RECLAIM_INIT_CODE
+/*
+ * Add each function to a section that is unique so the functions can still
+ * be garbage collected
+ */
+#define __init		__section(".text.init." __FILE__ "." __XSTRING(__LINE__))
+#else
+#define __init
+#endif
+
+#define __printflike(fmtarg, firstvararg) \
+		__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
+
+#define __weak_reference(sym, alias)	\
+	__asm__(".weak alias");		\
+	__asm__(".equ alias, sym")
+
+#define __STRING(x)	#x
+#define __XSTRING(x)	__STRING(x)
+
+#endif /* CDEFS_H */
diff --git a/include/lib/libc/endian.h b/include/lib/libc/endian.h
new file mode 100644
index 0000000..4100f57
--- /dev/null
+++ b/include/lib/libc/endian.h
@@ -0,0 +1,191 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef ENDIAN_H
+#define ENDIAN_H
+
+#include <cdefs.h>
+#include <stdint.h>
+#include <endian_.h>
+
+/*
+ * General byte order swapping functions.
+ */
+#define	bswap16(x)	__bswap16(x)
+#define	bswap32(x)	__bswap32(x)
+#define	bswap64(x)	__bswap64(x)
+
+/*
+ * Host to big endian, host to little endian, big endian to host, and little
+ * endian to host byte order functions as detailed in byteorder(9).
+ */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define	htobe16(x)	bswap16((x))
+#define	htobe32(x)	bswap32((x))
+#define	htobe64(x)	bswap64((x))
+#define	htole16(x)	((uint16_t)(x))
+#define	htole32(x)	((uint32_t)(x))
+#define	htole64(x)	((uint64_t)(x))
+
+#define	be16toh(x)	bswap16((x))
+#define	be32toh(x)	bswap32((x))
+#define	be64toh(x)	bswap64((x))
+#define	le16toh(x)	((uint16_t)(x))
+#define	le32toh(x)	((uint32_t)(x))
+#define	le64toh(x)	((uint64_t)(x))
+#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
+#define	htobe16(x)	((uint16_t)(x))
+#define	htobe32(x)	((uint32_t)(x))
+#define	htobe64(x)	((uint64_t)(x))
+#define	htole16(x)	bswap16((x))
+#define	htole32(x)	bswap32((x))
+#define	htole64(x)	bswap64((x))
+
+#define	be16toh(x)	((uint16_t)(x))
+#define	be32toh(x)	((uint32_t)(x))
+#define	be64toh(x)	((uint64_t)(x))
+#define	le16toh(x)	bswap16((x))
+#define	le32toh(x)	bswap32((x))
+#define	le64toh(x)	bswap64((x))
+#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
+
+/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
+
+static __inline uint16_t
+be16dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return ((p[0] << 8) | p[1]);
+}
+
+static __inline uint32_t
+be32dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static __inline uint64_t
+be64dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
+}
+
+static __inline uint16_t
+le16dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return ((p[1] << 8) | p[0]);
+}
+
+static __inline uint32_t
+le32dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+}
+
+static __inline uint64_t
+le64dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
+}
+
+static __inline void
+be16enc(void *pp, uint16_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = (u >> 8) & 0xff;
+	p[1] = u & 0xff;
+}
+
+static __inline void
+be32enc(void *pp, uint32_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = (u >> 24) & 0xff;
+	p[1] = (u >> 16) & 0xff;
+	p[2] = (u >> 8) & 0xff;
+	p[3] = u & 0xff;
+}
+
+static __inline void
+be64enc(void *pp, uint64_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	be32enc(p, (uint32_t)(u >> 32));
+	be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
+}
+
+static __inline void
+le16enc(void *pp, uint16_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+}
+
+static __inline void
+le32enc(void *pp, uint32_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+	p[2] = (u >> 16) & 0xff;
+	p[3] = (u >> 24) & 0xff;
+}
+
+static __inline void
+le64enc(void *pp, uint64_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	le32enc(p, (uint32_t)(u & 0xffffffffU));
+	le32enc(p + 4, (uint32_t)(u >> 32));
+}
+
+#endif /* ENDIAN_H */
diff --git a/include/lib/libc/errno.h b/include/lib/libc/errno.h
new file mode 100644
index 0000000..029912f
--- /dev/null
+++ b/include/lib/libc/errno.h
@@ -0,0 +1,169 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)errno.h	8.5 (Berkeley) 1/21/94
+ * $FreeBSD$
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef ERRNO_H
+#define ERRNO_H
+
+#define	EPERM		1		/* Operation not permitted */
+#define	ENOENT		2		/* No such file or directory */
+#define	ESRCH		3		/* No such process */
+#define	EINTR		4		/* Interrupted system call */
+#define	EIO		5		/* Input/output error */
+#define	ENXIO		6		/* Device not configured */
+#define	E2BIG		7		/* Argument list too long */
+#define	ENOEXEC		8		/* Exec format error */
+#define	EBADF		9		/* Bad file descriptor */
+#define	ECHILD		10		/* No child processes */
+#define	EDEADLK		11		/* Resource deadlock avoided */
+					/* 11 was EAGAIN */
+#define	ENOMEM		12		/* Cannot allocate memory */
+#define	EACCES		13		/* Permission denied */
+#define	EFAULT		14		/* Bad address */
+#define	ENOTBLK		15		/* Block device required */
+#define	EBUSY		16		/* Device busy */
+#define	EEXIST		17		/* File exists */
+#define	EXDEV		18		/* Cross-device link */
+#define	ENODEV		19		/* Operation not supported by device */
+#define	ENOTDIR		20		/* Not a directory */
+#define	EISDIR		21		/* Is a directory */
+#define	EINVAL		22		/* Invalid argument */
+#define	ENFILE		23		/* Too many open files in system */
+#define	EMFILE		24		/* Too many open files */
+#define	ENOTTY		25		/* Inappropriate ioctl for device */
+#define	ETXTBSY		26		/* Text file busy */
+#define	EFBIG		27		/* File too large */
+#define	ENOSPC		28		/* No space left on device */
+#define	ESPIPE		29		/* Illegal seek */
+#define	EROFS		30		/* Read-only filesystem */
+#define	EMLINK		31		/* Too many links */
+#define	EPIPE		32		/* Broken pipe */
+
+/* math software */
+#define	EDOM		33		/* Numerical argument out of domain */
+#define	ERANGE		34		/* Result too large */
+
+/* non-blocking and interrupt i/o */
+#define	EAGAIN		35		/* Resource temporarily unavailable */
+#define	EWOULDBLOCK	EAGAIN		/* Operation would block */
+#define	EINPROGRESS	36		/* Operation now in progress */
+#define	EALREADY	37		/* Operation already in progress */
+
+/* ipc/network software -- argument errors */
+#define	ENOTSOCK	38		/* Socket operation on non-socket */
+#define	EDESTADDRREQ	39		/* Destination address required */
+#define	EMSGSIZE	40		/* Message too long */
+#define	EPROTOTYPE	41		/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	42		/* Protocol not available */
+#define	EPROTONOSUPPORT	43		/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	44		/* Socket type not supported */
+#define	EOPNOTSUPP	45		/* Operation not supported */
+#define	ENOTSUP		EOPNOTSUPP	/* Operation not supported */
+#define	EPFNOSUPPORT	46		/* Protocol family not supported */
+#define	EAFNOSUPPORT	47		/* Address family not supported by protocol family */
+#define	EADDRINUSE	48		/* Address already in use */
+#define	EADDRNOTAVAIL	49		/* Can't assign requested address */
+
+/* ipc/network software -- operational errors */
+#define	ENETDOWN	50		/* Network is down */
+#define	ENETUNREACH	51		/* Network is unreachable */
+#define	ENETRESET	52		/* Network dropped connection on reset */
+#define	ECONNABORTED	53		/* Software caused connection abort */
+#define	ECONNRESET	54		/* Connection reset by peer */
+#define	ENOBUFS		55		/* No buffer space available */
+#define	EISCONN		56		/* Socket is already connected */
+#define	ENOTCONN	57		/* Socket is not connected */
+#define	ESHUTDOWN	58		/* Can't send after socket shutdown */
+#define	ETOOMANYREFS	59		/* Too many references: can't splice */
+#define	ETIMEDOUT	60		/* Operation timed out */
+#define	ECONNREFUSED	61		/* Connection refused */
+
+#define	ELOOP		62		/* Too many levels of symbolic links */
+#define	ENAMETOOLONG	63		/* File name too long */
+
+/* should be rearranged */
+#define	EHOSTDOWN	64		/* Host is down */
+#define	EHOSTUNREACH	65		/* No route to host */
+#define	ENOTEMPTY	66		/* Directory not empty */
+
+/* quotas & mush */
+#define	EPROCLIM	67		/* Too many processes */
+#define	EUSERS		68		/* Too many users */
+#define	EDQUOT		69		/* Disc quota exceeded */
+
+/* Network File System */
+#define	ESTALE		70		/* Stale NFS file handle */
+#define	EREMOTE		71		/* Too many levels of remote in path */
+#define	EBADRPC		72		/* RPC struct is bad */
+#define	ERPCMISMATCH	73		/* RPC version wrong */
+#define	EPROGUNAVAIL	74		/* RPC prog. not avail */
+#define	EPROGMISMATCH	75		/* Program version wrong */
+#define	EPROCUNAVAIL	76		/* Bad procedure for program */
+
+#define	ENOLCK		77		/* No locks available */
+#define	ENOSYS		78		/* Function not implemented */
+
+#define	EFTYPE		79		/* Inappropriate file type or format */
+#define	EAUTH		80		/* Authentication error */
+#define	ENEEDAUTH	81		/* Need authenticator */
+#define	EIDRM		82		/* Identifier removed */
+#define	ENOMSG		83		/* No message of desired type */
+#define	EOVERFLOW	84		/* Value too large to be stored in data type */
+#define	ECANCELED	85		/* Operation canceled */
+#define	EILSEQ		86		/* Illegal byte sequence */
+#define	ENOATTR		87		/* Attribute not found */
+
+#define	EDOOFUS		88		/* Programming error */
+
+#define	EBADMSG		89		/* Bad message */
+#define	EMULTIHOP	90		/* Multihop attempted */
+#define	ENOLINK		91		/* Link has been severed */
+#define	EPROTO		92		/* Protocol error */
+
+#define	ENOTCAPABLE	93		/* Capabilities insufficient */
+#define	ECAPMODE	94		/* Not permitted in capability mode */
+#define	ENOTRECOVERABLE	95		/* State not recoverable */
+#define	EOWNERDEAD	96		/* Previous owner died */
+
+#define	ELAST		96		/* Must be equal largest errno */
+
+#endif /* ERRNO_H */
diff --git a/include/lib/libc/limits.h b/include/lib/libc/limits.h
new file mode 100644
index 0000000..41bb658
--- /dev/null
+++ b/include/lib/libc/limits.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef LIMITS_H
+#define LIMITS_H
+
+#include <limits_.h>
+
+#define CHAR_BIT   8
+#define MB_LEN_MAX 1
+
+#endif /* LIMITS_H */
diff --git a/include/lib/libc/setjmp.h b/include/lib/libc/setjmp.h
new file mode 100644
index 0000000..be8e2c0
--- /dev/null
+++ b/include/lib/libc/setjmp.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SETJMP_H
+#define SETJMP_H
+
+#include <setjmp_.h>
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+
+int setjmp(jmp_buf env);
+__dead2 void longjmp(jmp_buf env, int val);
+
+#endif /* __ASSEMBLER__ */
+#endif /* SETJMP_H */
diff --git a/include/lib/libc/stdarg.h b/include/lib/libc/stdarg.h
new file mode 100644
index 0000000..e260b9b
--- /dev/null
+++ b/include/lib/libc/stdarg.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDARG_H
+#define STDARG_H
+
+#define va_list __builtin_va_list
+#define va_start(ap, last) __builtin_va_start(ap, last)
+#define va_end(ap) __builtin_va_end(ap)
+#define va_copy(to, from) __builtin_va_copy(to, from)
+#define va_arg(to, type) __builtin_va_arg(to, type)
+
+#endif /* STDARG_H */
diff --git a/include/lib/libc/stdbool.h b/include/lib/libc/stdbool.h
new file mode 100644
index 0000000..e39aef7
--- /dev/null
+++ b/include/lib/libc/stdbool.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STDBOOL_H
+#define STDBOOL_H
+
+#define bool	_Bool
+
+#define true	1
+#define false	0
+
+#define __bool_true_false_are_defined	1
+
+#endif /* STDBOOL_H */
diff --git a/include/lib/libc/stddef.h b/include/lib/libc/stddef.h
new file mode 100644
index 0000000..c9957bd
--- /dev/null
+++ b/include/lib/libc/stddef.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDDEF_H
+#define STDDEF_H
+
+#include <stddef_.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define offsetof(st, m) __builtin_offsetof(st, m)
+
+#endif /* STDDEF_H */
diff --git a/include/lib/libc/stdint.h b/include/lib/libc/stdint.h
new file mode 100644
index 0000000..d44a973
--- /dev/null
+++ b/include/lib/libc/stdint.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDINT_H
+#define STDINT_H
+
+#include <stdint_.h>
+
+#endif /* STDINT_H */
diff --git a/include/lib/libc/stdio.h b/include/lib/libc/stdio.h
new file mode 100644
index 0000000..3d9323e
--- /dev/null
+++ b/include/lib/libc/stdio.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDIO_H
+#define STDIO_H
+
+#include <cdefs.h>
+#include <stdio_.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define EOF            -1
+
+int printf(const char *fmt, ...) __printflike(1, 2);
+int snprintf(char *s, size_t n, const char *fmt, ...) __printflike(3, 4);
+
+#ifdef STDARG_H
+int vprintf(const char *fmt, va_list args);
+#endif
+
+int putchar(int c);
+int puts(const char *s);
+
+#endif /* STDIO_H */
diff --git a/include/lib/libc/stdlib.h b/include/lib/libc/stdlib.h
new file mode 100644
index 0000000..edd6265
--- /dev/null
+++ b/include/lib/libc/stdlib.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STDLIB_H
+#define STDLIB_H
+
+#include <stdlib_.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define _ATEXIT_MAX 1
+
+extern void abort(void);
+extern int atexit(void (*func)(void));
+extern void exit(int status);
+
+#endif /* STDLIB_H */
diff --git a/include/lib/libc/string.h b/include/lib/libc/string.h
new file mode 100644
index 0000000..ee6eeac
--- /dev/null
+++ b/include/lib/libc/string.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef STRING_H
+#define STRING_H
+
+#include <string_.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+void *memcpy(void *dst, const void *src, size_t len);
+void *memmove(void *dst, const void *src, size_t len);
+int memcmp(const void *s1, const void *s2, size_t len);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t n);
+void *memchr(const void *src, int c, size_t len);
+char *strchr(const char *s, int c);
+void *memset(void *dst, int val, size_t count);
+size_t strlen(const char *s);
+size_t strnlen(const char *s, size_t maxlen);
+char *strrchr(const char *p, int ch);
+size_t strlcpy(char * dst, const char * src, size_t dsize);
+
+#endif /* STRING_H */
diff --git a/include/lib/libc/time.h b/include/lib/libc/time.h
new file mode 100644
index 0000000..71d3e7e
--- /dev/null
+++ b/include/lib/libc/time.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012-2017 Roberto E. Vargas Caballero
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef TIME_H
+#define TIME_H
+
+#include <time_.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#endif /* TIME_H */
diff --git a/include/lib/libfdt/fdt.h b/include/lib/libfdt/fdt.h
new file mode 100644
index 0000000..ef7c86b
--- /dev/null
+++ b/include/lib/libfdt/fdt.h
@@ -0,0 +1,111 @@
+#ifndef FDT_H
+#define FDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASSEMBLER__
+
+struct fdt_header {
+	fdt32_t magic;			 /* magic word FDT_MAGIC */
+	fdt32_t totalsize;		 /* total size of DT block */
+	fdt32_t off_dt_struct;		 /* offset to structure */
+	fdt32_t off_dt_strings;		 /* offset to strings */
+	fdt32_t off_mem_rsvmap;		 /* offset to memory reserve map */
+	fdt32_t version;		 /* format version */
+	fdt32_t last_comp_version;	 /* last compatible version */
+
+	/* version 2 fields below */
+	fdt32_t boot_cpuid_phys;	 /* Which physical CPU id we're
+					    booting on */
+	/* version 3 fields below */
+	fdt32_t size_dt_strings;	 /* size of the strings block */
+
+	/* version 17 fields below */
+	fdt32_t size_dt_struct;		 /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+	fdt64_t address;
+	fdt64_t size;
+};
+
+struct fdt_node_header {
+	fdt32_t tag;
+	char name[0];
+};
+
+struct fdt_property {
+	fdt32_t tag;
+	fdt32_t len;
+	fdt32_t nameoff;
+	char data[0];
+};
+
+#endif /* !__ASSEMBLER__ */
+
+#define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
+#define FDT_TAGSIZE	sizeof(fdt32_t)
+
+#define FDT_BEGIN_NODE	0x1		/* Start node: full name */
+#define FDT_END_NODE	0x2		/* End node */
+#define FDT_PROP	0x3		/* Property: name off,
+					   size, content */
+#define FDT_NOP		0x4		/* nop */
+#define FDT_END		0x9
+
+#define FDT_V1_SIZE	(7*sizeof(fdt32_t))
+#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(fdt32_t))
+#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(fdt32_t))
+#define FDT_V16_SIZE	FDT_V3_SIZE
+#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(fdt32_t))
+
+#endif /* FDT_H */
diff --git a/include/lib/libfdt/libfdt.h b/include/lib/libfdt/libfdt.h
new file mode 100644
index 0000000..c8c00fa
--- /dev/null
+++ b/include/lib/libfdt/libfdt.h
@@ -0,0 +1,1902 @@
+#ifndef LIBFDT_H
+#define LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION	0x02
+#define FDT_LAST_SUPPORTED_VERSION	0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND	1
+	/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS		2
+	/* FDT_ERR_EXISTS: Attempted to create a node or property which
+	 * already exists */
+#define FDT_ERR_NOSPACE		3
+	/* FDT_ERR_NOSPACE: Operation needed to expand the device
+	 * tree, but its buffer did not have sufficient space to
+	 * contain the expanded tree. Use fdt_open_into() to move the
+	 * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET	4
+	/* FDT_ERR_BADOFFSET: Function was passed a structure block
+	 * offset which is out-of-bounds, or which points to an
+	 * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH		5
+	/* FDT_ERR_BADPATH: Function was passed a badly formatted path
+	 * (e.g. missing a leading / for a function which requires an
+	 * absolute path) */
+#define FDT_ERR_BADPHANDLE	6
+	/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
+	 * This can be caused either by an invalid phandle property
+	 * length, or the phandle value was either 0 or -1, which are
+	 * not permitted. */
+#define FDT_ERR_BADSTATE	7
+	/* FDT_ERR_BADSTATE: Function was passed an incomplete device
+	 * tree created by the sequential-write functions, which is
+	 * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED	8
+	/* FDT_ERR_TRUNCATED: Structure block of the given device tree
+	 * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC	9
+	/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+	 * device tree at all - it is missing the flattened device
+	 * tree magic number. */
+#define FDT_ERR_BADVERSION	10
+	/* FDT_ERR_BADVERSION: Given device tree has a version which
+	 * can't be handled by the requested operation.  For
+	 * read-write functions, this may mean that fdt_open_into() is
+	 * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE	11
+	/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+	 * structure block or other serious error (e.g. misnested
+	 * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT	12
+	/* FDT_ERR_BADLAYOUT: For read-write functions, the given
+	 * device tree has it's sub-blocks in an order that the
+	 * function can't handle (memory reserve map, then structure,
+	 * then strings).  Use fdt_open_into() to reorganize the tree
+	 * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL	13
+	/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+	 * Should never be returned, if it is, it indicates a bug in
+	 * libfdt itself. */
+
+/* Errors in device tree content */
+#define FDT_ERR_BADNCELLS	14
+	/* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
+	 * or similar property with a bad format or value */
+
+#define FDT_ERR_BADVALUE	15
+	/* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
+	 * value. For example: a property expected to contain a string list
+	 * is not NUL-terminated within the length of its value. */
+
+#define FDT_ERR_BADOVERLAY	16
+	/* FDT_ERR_BADOVERLAY: The device tree overlay, while
+	 * correctly structured, cannot be applied due to some
+	 * unexpected or missing value, property or node. */
+
+#define FDT_ERR_NOPHANDLES	17
+	/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
+	 * phandle available anymore without causing an overflow */
+
+#define FDT_ERR_MAX		17
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+#endif
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+	return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt:	FDT blob
+ * @offset:	Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt:	FDT blob
+ * @offset:	Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_subnode - iterate over all subnodes of a parent
+ *
+ * @node:	child node (int, lvalue)
+ * @fdt:	FDT blob (const void *)
+ * @parent:	parent node (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *	fdt_for_each_subnode(node, fdt, parent) {
+ *		Use node
+ *		...
+ *	}
+ *
+ *	if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
+ *		Error handling
+ *	}
+ *
+ * Note that this is implemented as a macro and @node is used as
+ * iterator in the loop. The parent variable be constant or even a
+ * literal.
+ *
+ */
+#define fdt_for_each_subnode(node, fdt, parent)		\
+	for (node = fdt_first_subnode(fdt, parent);	\
+	     node >= 0;					\
+	     node = fdt_next_subnode(fdt, node))
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+#define fdt_get_header(fdt, field) \
+	(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt)			(fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)		(fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt)	(fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt)	(fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt)	(fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+
+#define fdt_set_hdr_(name) \
+	static inline void fdt_set_##name(void *fdt, uint32_t val) \
+	{ \
+		struct fdt_header *fdth = (struct fdt_header *)fdt; \
+		fdth->name = cpu_to_fdt32(val); \
+	}
+fdt_set_hdr_(magic);
+fdt_set_hdr_(totalsize);
+fdt_set_hdr_(off_dt_struct);
+fdt_set_hdr_(off_dt_strings);
+fdt_set_hdr_(off_mem_rsvmap);
+fdt_set_hdr_(version);
+fdt_set_hdr_(last_comp_version);
+fdt_set_hdr_(boot_cpuid_phys);
+fdt_set_hdr_(size_dt_strings);
+fdt_set_hdr_(size_dt_struct);
+#undef fdt_set_hdr_
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_get_max_phandle - retrieves the highest phandle in a tree
+ * @fdt: pointer to the device tree blob
+ *
+ * fdt_get_max_phandle retrieves the highest phandle in the given
+ * device tree. This will ignore badly formatted phandles, or phandles
+ * with a value of 0 or -1.
+ *
+ * returns:
+ *      the highest phandle on success
+ *      0, if no phandle was found in the device tree
+ *      -1, if an error occurred
+ */
+uint32_t fdt_get_max_phandle(const void *fdt);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+			       const char *name, int namelen);
+#endif
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *	structure block offset of the requested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *		tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset_namelen - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ * @namelen: number of characters of path to consider
+ *
+ * Identical to fdt_path_offset(), but only consider the first namelen
+ * characters of path as the path name.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+#endif
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *	structure block offset of the node with the requested path (>=0), on
+ *		success
+ *	-FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *	-FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the node's name, on success
+ *		If lenp is non-NULL, *lenp contains the length of that name
+ *			(>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ *	structure block offset of the property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested node has no properties
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset.  This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ *	structure block offset of the next property (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the given property is the last in its node
+ *	-FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_property_offset - iterate over all properties of a node
+ *
+ * @property_offset:	property offset (int, lvalue)
+ * @fdt:		FDT blob (const void *)
+ * @node:		node offset (int)
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *	fdt_for_each_property_offset(property, fdt, node) {
+ *		Use property
+ *		...
+ *	}
+ *
+ *	if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
+ *		Error handling
+ *	}
+ *
+ * Note that this is implemented as a macro and property is used as
+ * iterator in the loop. The node variable can be constant or even a
+ * literal.
+ */
+#define fdt_for_each_property_offset(property, fdt, node)	\
+	for (property = fdt_first_property_offset(fdt, node);	\
+	     property >= 0;					\
+	     property = fdt_next_property_offset(fdt, property))
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset.  If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * Note that this code only works on device tree versions >= 16. fdt_getprop()
+ * works on all versions.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+						      int offset,
+						      int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+						    int nodeoffset,
+						    const char *name,
+						    int namelen, int *lenp);
+#endif
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the structure representing the property
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+					    const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+						      const char *name,
+						      int *lenp)
+{
+	return (struct fdt_property *)(uintptr_t)
+		fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @ffset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value).  If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.  If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *		if namep is non-NULL *namep contiains a pointer to the property
+ *		name.
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* This function is not useful in Python */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+				  const char **namep, int *lenp);
+#endif
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+#ifndef SWIG /* Not available in Python */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+				const char *name, int namelen, int *lenp);
+static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
+					  const char *name, int namelen,
+					  int *lenp)
+{
+	return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
+						      namelen, lenp);
+}
+#endif
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *	pointer to the property's value
+ *		if lenp is non-NULL, *lenp contains the length of the property
+ *		value (>=0)
+ *	NULL, on error
+ *		if lenp is non-NULL, *lenp contains an error code (<0):
+ *		-FDT_ERR_NOTFOUND, node does not have named property
+ *		-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
+ *			tag
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+			const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+				  const char *name, int *lenp)
+{
+	return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *	the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ *	0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+#ifndef SWIG /* Not available in Python */
+const char *fdt_get_alias_namelen(const void *fdt,
+				  const char *name, int namelen);
+#endif
+
+/**
+ * fdt_get_alias - retrieve the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias.  That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ *	a pointer to the expansion of the alias named 'name', if it exists
+ *	NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	0, on success
+ *		buf contains the absolute path of the node at
+ *		nodeoffset, as a NUL-terminated string.
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *		characters and will not fit in the given buffer.
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *	fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	structure block offset of the node at node offset's ancestor
+ *		of depth supernodedepth (>=0), on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
+ *		nodeoffset
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+				 int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *	depth of the node at nodeoffset (>=0), on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *	structure block offset of the parent of the node at nodeoffset
+ *		(>=0), on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *					       propval, proplen);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *						       propval, proplen);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+				  const char *propname,
+				  const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0), on success
+ *	-FDT_ERR_NOTFOUND, no node with that phandle exists
+ *	-FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *	0, if the node has a 'compatible' property listing the given string
+ *	1, if the node has a 'compatible' property, but it does not list
+ *		the given string
+ *	-FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ *	-FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+			      const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *	offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *	while (offset != -FDT_ERR_NOTFOUND) {
+ *		// other code here
+ *		offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *	}
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *	structure block offset of the located node (>= 0, >startoffset),
+ *		 on success
+ *	-FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *		tree after startoffset
+ *	-FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+				  const char *compatible);
+
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**
+ * fdt_stringlist_count - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @return:
+ *   the number of strings in the given property
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist
+ */
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
+
+/**
+ * fdt_stringlist_search - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ *
+ * Note that it is possible for this function to succeed on property values
+ * that are not NUL-terminated. That's because the function will stop after
+ * finding the first occurrence of @string. This can for example happen with
+ * small-valued cell properties, such as #address-cells, when searching for
+ * the empty string.
+ *
+ * @return:
+ *   the index of the string in the list of strings
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist or does not contain
+ *                     the given string
+ */
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+			  const char *string);
+
+/**
+ * fdt_stringlist_get() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @lenp: return location for the string length or an error code on failure
+ *
+ * Note that this will successfully extract strings from properties with
+ * non-NUL-terminated values. For example on small-valued cell properties
+ * this function will return the empty string.
+ *
+ * If non-NULL, the length of the string (on success) or a negative error-code
+ * (on failure) will be stored in the integer pointer to by lenp.
+ *
+ * @return:
+ *   A pointer to the string at the given index in the string list or NULL on
+ *   failure. On success the length of the string will be stored in the memory
+ *   location pointed to by the lenp parameter, if non-NULL. On failure one of
+ *   the following negative error codes will be returned in the lenp parameter
+ *   (if non-NULL):
+ *     -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *     -FDT_ERR_NOTFOUND if the property does not exist
+ */
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+			       const char *property, int index,
+			       int *lenp);
+
+/**********************************************************************/
+/* Read-only functions (addressing related)                           */
+/**********************************************************************/
+
+/**
+ * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
+ *
+ * This is the maximum value for #address-cells, #size-cells and
+ * similar properties that will be processed by libfdt.  IEE1275
+ * requires that OF implementations handle values up to 4.
+ * Implementations may support larger values, but in practice higher
+ * values aren't used.
+ */
+#define FDT_MAX_NCELLS		4
+
+/**
+ * fdt_address_cells - retrieve address size for a bus represented in the tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address size for
+ *
+ * When the node has a valid #address-cells property, returns its value.
+ *
+ * returns:
+ *	0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#address-cells property
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_address_cells(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_size_cells - retrieve address range size for a bus represented in the
+ *                  tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address range size for
+ *
+ * When the node has a valid #size-cells property, returns its value.
+ *
+ * returns:
+ *	0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *		#size-cells property
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_size_cells(const void *fdt, int nodeoffset);
+
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace_namelen_partial - change a property's value,
+ *                                       but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @namelen: number of characters of name to consider
+ * @idx: index of the property to change in the array
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * Identical to fdt_setprop_inplace(), but modifies the given property
+ * starting from the given index, and using only the first characters
+ * of the name. It is useful when you want to manipulate only one value of
+ * an array and you have a string that doesn't end with \0.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
+					const char *name, int namelen,
+					uint32_t idx, const void *val,
+					int len);
+#endif
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+			const void *val, int len);
+#endif
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+					  const char *name, uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+					  const char *name, uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+					   const char *name, uint32_t val)
+{
+	return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_resize(void *fdt, void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+	return fdt_property_u32(fdt, name, val);
+}
+
+/**
+ * fdt_property_placeholder - add a new property and return a ptr to its value
+ *
+ * @fdt: pointer to the device tree blob
+ * @name: name of property to add
+ * @len: length of property value in bytes
+ * @valp: returns a pointer to where where the value should be placed
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_NOSPACE, standard meanings
+ */
+int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
+
+#define fdt_property_string(fdt, name, str) \
+	fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new reservation entry
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *		are less than n+1 reserve map entries)
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+		const void *val, int len);
+
+/**
+ * fdt_setprop_placeholder - allocate space for a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @len: length of the property value
+ * @prop_data: return pointer to property data
+ *
+ * fdt_setprop_placeholer() allocates the named property in the given node.
+ * If the property exists it is resized. In either case a pointer to the
+ * property data is returned.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
+			    int len, void **prop_data);
+
+/**
+ * fdt_setprop_u32 - set a property to a 32-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+				  uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+				  uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+				   uint32_t val)
+{
+	return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+
+/**
+ * fdt_setprop_empty - set a property to an empty value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ *
+ * fdt_setprop_empty() sets the value of the named property in the
+ * given node to an empty (zero length) value, or creates a new empty
+ * property if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_empty(fdt, nodeoffset, name) \
+	fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+		   const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+				     const char *name, uint32_t val)
+{
+	fdt32_t tmp = cpu_to_fdt32(val);
+	return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+				     const char *name, uint64_t val)
+{
+	fdt64_t tmp = cpu_to_fdt64(val);
+	return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+				      const char *name, uint32_t val)
+{
+	return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string to the value of
+ * the named property in the given node, or creates a new property
+ * with that value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+	fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOTFOUND, node does not have the named property
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+#ifndef SWIG /* Not available in Python */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+			    const char *name, int namelen);
+#endif
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on
+ *		success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
+ *		tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE
+ *	-FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**
+ * fdt_overlay_apply - Applies a DT overlay on a base DT
+ * @fdt: pointer to the base device tree blob
+ * @fdto: pointer to the device tree overlay blob
+ *
+ * fdt_overlay_apply() will apply the given device tree overlay on the
+ * given base device tree.
+ *
+ * Expect the base device tree to be modified, even if the function
+ * returns an error.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there's not enough space in the base device tree
+ *	-FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
+ *		properties in the base DT
+ *	-FDT_ERR_BADPHANDLE,
+ *	-FDT_ERR_BADOVERLAY,
+ *	-FDT_ERR_NOPHANDLES,
+ *	-FDT_ERR_INTERNAL,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADOFFSET,
+ *	-FDT_ERR_BADPATH,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_overlay_apply(void *fdt, void *fdto);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* LIBFDT_H */
diff --git a/include/lib/libfdt/libfdt_env.h b/include/lib/libfdt/libfdt_env.h
new file mode 100644
index 0000000..bd24746
--- /dev/null
+++ b/include/lib/libfdt/libfdt_env.h
@@ -0,0 +1,139 @@
+#ifndef LIBFDT_ENV_H
+#define LIBFDT_ENV_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __CHECKER__
+#define FDT_FORCE __attribute__((force))
+#define FDT_BITWISE __attribute__((bitwise))
+#else
+#define FDT_FORCE
+#define FDT_BITWISE
+#endif
+
+typedef uint16_t FDT_BITWISE fdt16_t;
+typedef uint32_t FDT_BITWISE fdt32_t;
+typedef uint64_t FDT_BITWISE fdt64_t;
+
+#define EXTRACT_BYTE(x, n)	((unsigned long long)((uint8_t *)&x)[n])
+#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
+			 (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
+			 (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
+			 (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
+			 (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+static inline uint16_t fdt16_to_cpu(fdt16_t x)
+{
+	return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
+}
+static inline fdt16_t cpu_to_fdt16(uint16_t x)
+{
+	return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
+}
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+	return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
+}
+static inline fdt32_t cpu_to_fdt32(uint32_t x)
+{
+	return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+	return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
+}
+static inline fdt64_t cpu_to_fdt64(uint64_t x)
+{
+	return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
+}
+#undef CPU_TO_FDT64
+#undef CPU_TO_FDT32
+#undef CPU_TO_FDT16
+#undef EXTRACT_BYTE
+
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+
+/* strnlen() is not available on Mac OS < 10.7 */
+# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
+                                         MAC_OS_X_VERSION_10_7)
+
+#define strnlen fdt_strnlen
+
+/*
+ * fdt_strnlen: returns the length of a string or max_count - which ever is
+ * smallest.
+ * Input 1 string: the string whose size is to be determined
+ * Input 2 max_count: the maximum value returned by this function
+ * Output: length of the string or max_count (the smallest of the two)
+ */
+static inline size_t fdt_strnlen(const char *string, size_t max_count)
+{
+    const char *p = memchr(string, 0, max_count);
+    return p ? p - string : max_count;
+}
+
+#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
+          MAC_OS_X_VERSION_10_7) */
+
+#endif /* __APPLE__ */
+
+#endif /* LIBFDT_ENV_H */
diff --git a/include/lib/mmio.h b/include/lib/mmio.h
new file mode 100644
index 0000000..3242a7c
--- /dev/null
+++ b/include/lib/mmio.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MMIO_H
+#define MMIO_H
+
+#include <stdint.h>
+
+static inline void mmio_write_8(uintptr_t addr, uint8_t value)
+{
+	*(volatile uint8_t*)addr = value;
+}
+
+static inline uint8_t mmio_read_8(uintptr_t addr)
+{
+	return *(volatile uint8_t*)addr;
+}
+
+static inline void mmio_write_16(uintptr_t addr, uint16_t value)
+{
+	*(volatile uint16_t*)addr = value;
+}
+
+static inline uint16_t mmio_read_16(uintptr_t addr)
+{
+	return *(volatile uint16_t*)addr;
+}
+
+static inline void mmio_clrsetbits_16(uintptr_t addr,
+				uint16_t clear,
+				uint16_t set)
+{
+	mmio_write_16(addr, (mmio_read_16(addr) & ~clear) | set);
+}
+
+static inline void mmio_write_32(uintptr_t addr, uint32_t value)
+{
+	*(volatile uint32_t*)addr = value;
+}
+
+static inline uint32_t mmio_read_32(uintptr_t addr)
+{
+	return *(volatile uint32_t*)addr;
+}
+
+static inline void mmio_write_64(uintptr_t addr, uint64_t value)
+{
+	*(volatile uint64_t*)addr = value;
+}
+
+static inline uint64_t mmio_read_64(uintptr_t addr)
+{
+	return *(volatile uint64_t*)addr;
+}
+
+static inline void mmio_clrbits_32(uintptr_t addr, uint32_t clear)
+{
+	mmio_write_32(addr, mmio_read_32(addr) & ~clear);
+}
+
+static inline void mmio_setbits_32(uintptr_t addr, uint32_t set)
+{
+	mmio_write_32(addr, mmio_read_32(addr) | set);
+}
+
+static inline void mmio_clrsetbits_32(uintptr_t addr,
+				uint32_t clear,
+				uint32_t set)
+{
+	mmio_write_32(addr, (mmio_read_32(addr) & ~clear) | set);
+}
+
+#endif /* MMIO_H */
diff --git a/include/lib/object_pool.h b/include/lib/object_pool.h
new file mode 100644
index 0000000..0f85331
--- /dev/null
+++ b/include/lib/object_pool.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OBJECT_POOL_H
+#define OBJECT_POOL_H
+
+#include <stdlib.h>
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+
+/*
+ * Pool of statically allocated objects.
+ *
+ * Objects can be reserved but not freed. This is by design and it is not a
+ * limitation. We do not want to introduce complexity induced by memory freeing,
+ * such as use-after-free bugs, memory fragmentation and so on.
+ *
+ * The object size and capacity of the pool are fixed at build time. So is the
+ * address of the objects back store.
+ */
+struct object_pool {
+	/* Size of 1 object in the pool in byte unit. */
+	const size_t obj_size;
+
+	/* Number of objects in the pool. */
+	const size_t capacity;
+
+	/* Objects back store. */
+	void *const objects;
+
+	/* How many objects are currently allocated. */
+	size_t used;
+};
+
+/* Create a static pool of objects. */
+#define OBJECT_POOL(_pool_name, _obj_backstore, _obj_size, _obj_count)	\
+	struct object_pool _pool_name = {				\
+		.objects = (_obj_backstore),				\
+		.obj_size = (_obj_size),				\
+		.capacity = (_obj_count),				\
+		.used = 0U,						\
+	}
+
+/* Create a static pool of objects out of an array of pre-allocated objects. */
+#define OBJECT_POOL_ARRAY(_pool_name, _obj_array)			\
+	OBJECT_POOL(_pool_name, (_obj_array),				\
+		    sizeof((_obj_array)[0]), ARRAY_SIZE(_obj_array))
+
+/*
+ * Allocate 'count' objects from a pool.
+ * Return the address of the first object. Panic on error.
+ */
+static inline void *pool_alloc_n(struct object_pool *pool, size_t count)
+{
+	if (pool->used + count > pool->capacity) {
+		ERROR("Cannot allocate %zu objects out of pool (%zu objects left).\n",
+		      count, pool->capacity - pool->used);
+		panic();
+	}
+
+	void *obj = (char *)(pool->objects) + pool->obj_size * pool->used;
+	pool->used += count;
+	return obj;
+}
+
+/*
+ * Allocate 1 object from a pool.
+ * Return the address of the object. Panic on error.
+ */
+static inline void *pool_alloc(struct object_pool *pool)
+{
+	return pool_alloc_n(pool, 1U);
+}
+
+#endif /* OBJECT_POOL_H */
diff --git a/include/lib/optee_utils.h b/include/lib/optee_utils.h
new file mode 100644
index 0000000..6067caf
--- /dev/null
+++ b/include/lib/optee_utils.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OPTEE_UTILS_H
+#define OPTEE_UTILS_H
+
+#include <common/bl_common.h>
+
+int parse_optee_header(entry_point_info_t *header_ep,
+	image_info_t *pager_image_info,
+	image_info_t *paged_image_info);
+
+#endif /* OPTEE_UTILS_H */
diff --git a/include/lib/pmf/pmf.h b/include/lib/pmf/pmf.h
new file mode 100644
index 0000000..df7c9ff
--- /dev/null
+++ b/include/lib/pmf/pmf.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMF_H
+#define PMF_H
+
+#include <lib/cassert.h>
+#include <lib/pmf/pmf_helpers.h>
+#include <lib/utils_def.h>
+
+/*
+ * Constants used for/by PMF services.
+ */
+#define PMF_ARM_TIF_IMPL_ID	U(0x41)
+#define PMF_TID_SHIFT		0
+#define PMF_TID_MASK		(U(0xFF) << PMF_TID_SHIFT)
+#define PMF_SVC_ID_SHIFT	10
+#define PMF_SVC_ID_MASK		(U(0x3F) << PMF_SVC_ID_SHIFT)
+#define PMF_IMPL_ID_SHIFT	24
+#define PMF_IMPL_ID_MASK	(U(0xFF) << PMF_IMPL_ID_SHIFT)
+
+/*
+ * Flags passed to PMF_REGISTER_SERVICE
+ */
+#define PMF_STORE_ENABLE	(1 << 0)
+#define PMF_DUMP_ENABLE		(1 << 1)
+
+/*
+ * Flags passed to PMF_GET_TIMESTAMP_XXX
+ * and PMF_CAPTURE_TIMESTAMP
+ */
+#define PMF_CACHE_MAINT		(U(1) << 0)
+#define PMF_NO_CACHE_MAINT	U(0)
+
+/*
+ * Defines for PMF SMC function ids.
+ */
+#define PMF_SMC_GET_TIMESTAMP_32	U(0x82000010)
+#define PMF_SMC_GET_TIMESTAMP_64	U(0xC2000010)
+#define PMF_NUM_SMC_CALLS		2
+
+/*
+ * The macros below are used to identify
+ * PMF calls from the SMC function ID.
+ */
+#define PMF_FID_MASK	U(0xffe0)
+#define PMF_FID_VALUE	U(0)
+#define is_pmf_fid(_fid)	(((_fid) & PMF_FID_MASK) == PMF_FID_VALUE)
+
+/* Following are the supported PMF service IDs */
+#define PMF_PSCI_STAT_SVC_ID	0
+#define PMF_RT_INSTR_SVC_ID	1
+
+#if ENABLE_PMF
+/*
+ * Convenience macros for capturing time-stamp.
+ */
+#define PMF_DECLARE_CAPTURE_TIMESTAMP(_name)			\
+	void pmf_capture_timestamp_with_cache_maint_ ## _name(	\
+				unsigned int tid,		\
+				unsigned long long ts);		\
+	void pmf_capture_timestamp_ ## _name(			\
+				unsigned int tid,		\
+				unsigned long long ts);
+
+#define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags)			\
+	do {								\
+		unsigned long long ts = read_cntpct_el0();		\
+		if (((_flags) & PMF_CACHE_MAINT) != 0U)			\
+			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), ts);\
+		else							\
+			pmf_capture_timestamp_ ## _name((_tid), ts);	\
+	} while (0)
+
+#define PMF_CAPTURE_AND_GET_TIMESTAMP(_name, _tid, _flags, _tsval)	\
+	do {								\
+		(_tsval) = read_cntpct_el0();				\
+		CASSERT(sizeof(_tsval) == sizeof(unsigned long long), invalid_tsval_size);\
+		if (((_flags) & PMF_CACHE_MAINT) != 0U)			\
+			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_tsval));\
+		else							\
+			pmf_capture_timestamp_ ## _name((_tid), (_tsval));\
+	} while (0)
+
+#define PMF_WRITE_TIMESTAMP(_name, _tid, _flags, _wrval)		\
+	do {								\
+		CASSERT(sizeof(_wrval) == sizeof(unsigned long long), invalid_wrval_size);\
+		if (((_flags) & PMF_CACHE_MAINT) != 0U)			\
+			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_wrval));\
+		else							\
+			pmf_capture_timestamp_ ## _name((_tid), (_wrval));\
+	} while (0)
+
+/*
+ * Convenience macros for retrieving time-stamp.
+ */
+#define PMF_DECLARE_GET_TIMESTAMP(_name)			\
+	unsigned long long pmf_get_timestamp_by_index_ ## _name(\
+		unsigned int tid,				\
+		unsigned int cpuid,				\
+		unsigned int flags);				\
+	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(\
+		unsigned int tid,				\
+		u_register_t mpidr,				\
+		unsigned int flags);
+
+#define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)\
+	_tsval = pmf_get_timestamp_by_mpidr_ ## _name(_tid, _mpidr, _flags)
+
+#define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)\
+	_tsval = pmf_get_timestamp_by_index_ ## _name(_tid, _cpuid, _flags)
+
+/* Convenience macros to register a PMF service.*/
+/*
+ * This macro is used to register a PMF Service. It allocates PMF memory
+ * and defines default service-specific PMF functions.
+ */
+#define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)	\
+	PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _totalid)		\
+	PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags)		\
+	PMF_DEFINE_GET_TIMESTAMP(_name)
+
+/*
+ * This macro is used to register a PMF service, including an
+ * SMC interface to that service.
+ */
+#define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)\
+	PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)	\
+	PMF_DEFINE_SERVICE_DESC(_name, PMF_ARM_TIF_IMPL_ID,	\
+			_svcid, _totalid, NULL,			\
+			pmf_get_timestamp_by_mpidr_ ## _name)
+
+/*
+ * This macro is used to register a PMF service that has an SMC interface
+ * but provides its own service-specific PMF functions.
+ */
+#define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid,	\
+		 _init, _getts)						\
+	PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid,	\
+		 _init, _getts)
+
+#else
+
+#define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)
+#define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)
+#define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid,	\
+				_init, _getts)
+#define PMF_DECLARE_CAPTURE_TIMESTAMP(_name)
+#define PMF_DECLARE_GET_TIMESTAMP(_name)
+#define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags)
+#define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)
+#define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)
+
+#endif /* ENABLE_PMF */
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+/* PMF common functions */
+int pmf_get_timestamp_smc(unsigned int tid,
+		u_register_t mpidr,
+		unsigned int flags,
+		unsigned long long *ts_value);
+int pmf_setup(void);
+uintptr_t pmf_smc_handler(unsigned int smc_fid,
+		u_register_t x1,
+		u_register_t x2,
+		u_register_t x3,
+		u_register_t x4,
+		void *cookie,
+		void *handle,
+		u_register_t flags);
+
+#endif /* PMF_H */
diff --git a/include/lib/pmf/pmf_asm_macros.S b/include/lib/pmf/pmf_asm_macros.S
new file mode 100644
index 0000000..5f3e6b7
--- /dev/null
+++ b/include/lib/pmf/pmf_asm_macros.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMF_ASM_MACROS_S
+#define PMF_ASM_MACROS_S
+
+#define PMF_TS_SIZE	8
+
+	/*
+	 * This macro calculates the address of the per-cpu timestamp
+	 * for the given service name and local timestamp id.
+	 * Clobbers: x0 - x9
+	 */
+	.macro pmf_calc_timestamp_addr _name, _tid
+	mov	x9, x30
+	bl	plat_my_core_pos
+	mov	x30, x9
+	adr	x2, __PMF_PERCPU_TIMESTAMP_END__
+	adr	x1, __PMF_TIMESTAMP_START__
+	sub	x1, x2, x1
+	mov	x2, #(\_tid * PMF_TS_SIZE)
+	madd	x0, x0, x1, x2
+	adr	x1, pmf_ts_mem_\_name
+	add	x0, x0, x1
+	.endm
+
+#endif /* PMF_ASM_MACROS_S */
diff --git a/include/lib/pmf/pmf_helpers.h b/include/lib/pmf/pmf_helpers.h
new file mode 100644
index 0000000..e6798a7
--- /dev/null
+++ b/include/lib/pmf/pmf_helpers.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMF_HELPERS_H
+#define PMF_HELPERS_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <plat/common/platform.h>
+
+/*
+ * Prototype for PMF service functions.
+ */
+typedef int (*pmf_svc_init_t)(void);
+typedef unsigned long long (*pmf_svc_get_ts_t)(unsigned int tid,
+		 u_register_t mpidr,
+		 unsigned int flags);
+
+/*
+ * This is the definition of PMF service desc.
+ */
+typedef struct pmf_svc_desc {
+	/* Structure version information */
+	param_header_t h;
+
+	/* Name of the PMF service */
+	const char *name;
+
+	/* PMF service config: Implementer id, Service id and total id*/
+	unsigned int svc_config;
+
+	/* PMF service initialization handler */
+	pmf_svc_init_t init;
+
+	/* PMF service time-stamp retrieval handler */
+	pmf_svc_get_ts_t get_ts;
+} pmf_svc_desc_t;
+
+/*
+ * Convenience macro to allocate memory for a PMF service.
+ *
+ * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
+ */
+#define PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _total_id)		\
+	extern unsigned long long pmf_ts_mem_ ## _name[_total_id];	\
+	unsigned long long pmf_ts_mem_ ## _name[_total_id]	\
+	__aligned(CACHE_WRITEBACK_GRANULE)			\
+	__section("pmf_timestamp_array")			\
+	__used;
+
+/*
+ * Convenience macro to validate tid index for the given TS array.
+ */
+#define PMF_VALIDATE_TID(_name, _tid)	\
+	assert((_tid & PMF_TID_MASK) < (ARRAY_SIZE(pmf_ts_mem_ ## _name)))
+
+/*
+ * Convenience macros for capturing time-stamp.
+ *
+ * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
+ */
+#define PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags)			\
+	void pmf_capture_timestamp_ ## _name(				\
+			unsigned int tid,				\
+			unsigned long long ts);				\
+	void pmf_capture_timestamp_ ## _name(				\
+			unsigned int tid,				\
+			unsigned long long ts)				\
+	{								\
+		CASSERT(_flags, select_proper_config);			\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		if (((_flags) & PMF_STORE_ENABLE) != 0)			\
+			__pmf_store_timestamp(base_addr, tid, ts);	\
+		if (((_flags) & PMF_DUMP_ENABLE) != 0)			\
+			__pmf_dump_timestamp(tid, ts);			\
+	}								\
+	void pmf_capture_timestamp_with_cache_maint_ ## _name(		\
+			unsigned int tid,				\
+			unsigned long long ts);				\
+	void pmf_capture_timestamp_with_cache_maint_ ## _name(		\
+			unsigned int tid,				\
+			unsigned long long ts)				\
+	{								\
+		CASSERT(_flags, select_proper_config);			\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		if (((_flags) & PMF_STORE_ENABLE) != 0)			\
+			__pmf_store_timestamp_with_cache_maint(base_addr, tid, ts);\
+		if (((_flags) & PMF_DUMP_ENABLE) != 0)			\
+			__pmf_dump_timestamp(tid, ts);			\
+	}
+
+/*
+ * Convenience macros for retrieving time-stamp.
+ *
+ * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
+ */
+#define PMF_DEFINE_GET_TIMESTAMP(_name)					\
+	unsigned long long pmf_get_timestamp_by_index_ ## _name(	\
+		unsigned int tid, unsigned int cpuid, unsigned int flags);\
+	unsigned long long pmf_get_timestamp_by_index_ ## _name(	\
+		unsigned int tid, unsigned int cpuid, unsigned int flags)\
+	{								\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		return __pmf_get_timestamp(base_addr, tid, cpuid, flags);\
+	}								\
+	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(	\
+		unsigned int tid, u_register_t mpidr, unsigned int flags);\
+	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(	\
+		unsigned int tid, u_register_t mpidr, unsigned int flags)\
+	{								\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		return __pmf_get_timestamp(base_addr, tid,		\
+			plat_core_pos_by_mpidr(mpidr), flags);		\
+	}
+
+/*
+ * Convenience macro to register a PMF service.
+ * This is needed for services that require SMC handling.
+ */
+#define PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid,	\
+		_init, _getts_by_mpidr) 				\
+	static const pmf_svc_desc_t __pmf_desc_ ## _name 		\
+	__section("pmf_svc_descs") __used = {		 		\
+		.h.type = PARAM_EP, 					\
+		.h.version = VERSION_1, 				\
+		.h.size = sizeof(pmf_svc_desc_t),			\
+		.h.attr = 0,						\
+		.name = #_name, 					\
+		.svc_config = ((((_implid) << PMF_IMPL_ID_SHIFT) &	\
+						PMF_IMPL_ID_MASK) |	\
+				(((_svcid) << PMF_SVC_ID_SHIFT) &	\
+						PMF_SVC_ID_MASK) |	\
+				(((_totalid) << PMF_TID_SHIFT) &	\
+						PMF_TID_MASK)),		\
+		.init = _init,						\
+		.get_ts = _getts_by_mpidr				\
+	};
+
+/* PMF internal functions */
+void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts);
+void __pmf_store_timestamp(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned long long ts);
+void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned long long ts);
+unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned int cpuid,
+		unsigned int flags);
+#endif /* PMF_HELPERS_H */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
new file mode 100644
index 0000000..04e5e3d
--- /dev/null
+++ b/include/lib/psci/psci.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSCI_H
+#define PSCI_H
+
+#include <platform_def.h>	/* for PLAT_NUM_PWR_DOMAINS */
+
+#include <common/bl_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/psci/psci_lib.h>	/* To maintain compatibility for SPDs */
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Number of power domains whose state this PSCI implementation can track
+ ******************************************************************************/
+#ifdef PLAT_NUM_PWR_DOMAINS
+#define PSCI_NUM_PWR_DOMAINS	PLAT_NUM_PWR_DOMAINS
+#else
+#define PSCI_NUM_PWR_DOMAINS	(2 * PLATFORM_CORE_COUNT)
+#endif
+
+#define PSCI_NUM_NON_CPU_PWR_DOMAINS	(PSCI_NUM_PWR_DOMAINS - \
+					 PLATFORM_CORE_COUNT)
+
+/* This is the power level corresponding to a CPU */
+#define PSCI_CPU_PWR_LVL	U(0)
+
+/*
+ * The maximum power level supported by PSCI. Since PSCI CPU_SUSPEND
+ * uses the old power_state parameter format which has 2 bits to specify the
+ * power level, this constant is defined to be 3.
+ */
+#define PSCI_MAX_PWR_LVL	U(3)
+
+/*******************************************************************************
+ * Defines for runtime services function ids
+ ******************************************************************************/
+#define PSCI_VERSION			U(0x84000000)
+#define PSCI_CPU_SUSPEND_AARCH32	U(0x84000001)
+#define PSCI_CPU_SUSPEND_AARCH64	U(0xc4000001)
+#define PSCI_CPU_OFF			U(0x84000002)
+#define PSCI_CPU_ON_AARCH32		U(0x84000003)
+#define PSCI_CPU_ON_AARCH64		U(0xc4000003)
+#define PSCI_AFFINITY_INFO_AARCH32	U(0x84000004)
+#define PSCI_AFFINITY_INFO_AARCH64	U(0xc4000004)
+#define PSCI_MIG_AARCH32		U(0x84000005)
+#define PSCI_MIG_AARCH64		U(0xc4000005)
+#define PSCI_MIG_INFO_TYPE		U(0x84000006)
+#define PSCI_MIG_INFO_UP_CPU_AARCH32	U(0x84000007)
+#define PSCI_MIG_INFO_UP_CPU_AARCH64	U(0xc4000007)
+#define PSCI_SYSTEM_OFF			U(0x84000008)
+#define PSCI_SYSTEM_RESET		U(0x84000009)
+#define PSCI_FEATURES			U(0x8400000A)
+#define PSCI_NODE_HW_STATE_AARCH32	U(0x8400000d)
+#define PSCI_NODE_HW_STATE_AARCH64	U(0xc400000d)
+#define PSCI_SYSTEM_SUSPEND_AARCH32	U(0x8400000E)
+#define PSCI_SYSTEM_SUSPEND_AARCH64	U(0xc400000E)
+#define PSCI_STAT_RESIDENCY_AARCH32	U(0x84000010)
+#define PSCI_STAT_RESIDENCY_AARCH64	U(0xc4000010)
+#define PSCI_STAT_COUNT_AARCH32		U(0x84000011)
+#define PSCI_STAT_COUNT_AARCH64		U(0xc4000011)
+#define PSCI_SYSTEM_RESET2_AARCH32	U(0x84000012)
+#define PSCI_SYSTEM_RESET2_AARCH64	U(0xc4000012)
+#define PSCI_MEM_PROTECT		U(0x84000013)
+#define PSCI_MEM_CHK_RANGE_AARCH32	U(0x84000014)
+#define PSCI_MEM_CHK_RANGE_AARCH64	U(0xc4000014)
+
+/*
+ * Number of PSCI calls (above) implemented
+ */
+#if ENABLE_PSCI_STAT
+#define PSCI_NUM_CALLS			U(22)
+#else
+#define PSCI_NUM_CALLS			U(18)
+#endif
+
+/* The macros below are used to identify PSCI calls from the SMC function ID */
+#define PSCI_FID_MASK			U(0xffe0)
+#define PSCI_FID_VALUE			U(0)
+#define is_psci_fid(_fid) \
+	(((_fid) & PSCI_FID_MASK) == PSCI_FID_VALUE)
+
+/*******************************************************************************
+ * PSCI Migrate and friends
+ ******************************************************************************/
+#define PSCI_TOS_UP_MIG_CAP	0
+#define PSCI_TOS_NOT_UP_MIG_CAP	1
+#define PSCI_TOS_NOT_PRESENT_MP	2
+
+/*******************************************************************************
+ * PSCI CPU_SUSPEND 'power_state' parameter specific defines
+ ******************************************************************************/
+#define PSTATE_ID_SHIFT		U(0)
+
+#if PSCI_EXTENDED_STATE_ID
+#define PSTATE_VALID_MASK	U(0xB0000000)
+#define PSTATE_TYPE_SHIFT	U(30)
+#define PSTATE_ID_MASK		U(0xfffffff)
+#else
+#define PSTATE_VALID_MASK	U(0xFCFE0000)
+#define PSTATE_TYPE_SHIFT	U(16)
+#define PSTATE_PWR_LVL_SHIFT	U(24)
+#define PSTATE_ID_MASK		U(0xffff)
+#define PSTATE_PWR_LVL_MASK	U(0x3)
+
+#define psci_get_pstate_pwrlvl(pstate)	(((pstate) >> PSTATE_PWR_LVL_SHIFT) & \
+					PSTATE_PWR_LVL_MASK)
+#define psci_make_powerstate(state_id, type, pwrlvl) \
+			(((state_id) & PSTATE_ID_MASK) << PSTATE_ID_SHIFT) |\
+			(((type) & PSTATE_TYPE_MASK) << PSTATE_TYPE_SHIFT) |\
+			(((pwrlvl) & PSTATE_PWR_LVL_MASK) << PSTATE_PWR_LVL_SHIFT)
+#endif /* __PSCI_EXTENDED_STATE_ID__ */
+
+#define PSTATE_TYPE_STANDBY	U(0x0)
+#define PSTATE_TYPE_POWERDOWN	U(0x1)
+#define PSTATE_TYPE_MASK	U(0x1)
+
+/*******************************************************************************
+ * PSCI CPU_FEATURES feature flag specific defines
+ ******************************************************************************/
+/* Features flags for CPU SUSPEND power state parameter format. Bits [1:1] */
+#define FF_PSTATE_SHIFT		U(1)
+#define FF_PSTATE_ORIG		U(0)
+#define FF_PSTATE_EXTENDED	U(1)
+#if PSCI_EXTENDED_STATE_ID
+#define FF_PSTATE		FF_PSTATE_EXTENDED
+#else
+#define FF_PSTATE		FF_PSTATE_ORIG
+#endif
+
+/* Features flags for CPU SUSPEND OS Initiated mode support. Bits [0:0] */
+#define FF_MODE_SUPPORT_SHIFT		U(0)
+#define FF_SUPPORTS_OS_INIT_MODE	U(1)
+
+/*******************************************************************************
+ * PSCI version
+ ******************************************************************************/
+#define PSCI_MAJOR_VER		(U(1) << 16)
+#define PSCI_MINOR_VER		U(0x1)
+
+/*******************************************************************************
+ * PSCI error codes
+ ******************************************************************************/
+#define PSCI_E_SUCCESS		0
+#define PSCI_E_NOT_SUPPORTED	-1
+#define PSCI_E_INVALID_PARAMS	-2
+#define PSCI_E_DENIED		-3
+#define PSCI_E_ALREADY_ON	-4
+#define PSCI_E_ON_PENDING	-5
+#define PSCI_E_INTERN_FAIL	-6
+#define PSCI_E_NOT_PRESENT	-7
+#define PSCI_E_DISABLED		-8
+#define PSCI_E_INVALID_ADDRESS	-9
+
+#define PSCI_INVALID_MPIDR	~((u_register_t)0)
+
+/*
+ * SYSTEM_RESET2 macros
+ */
+#define PSCI_RESET2_TYPE_VENDOR_SHIFT	U(31)
+#define PSCI_RESET2_TYPE_VENDOR		(U(1) << PSCI_RESET2_TYPE_VENDOR_SHIFT)
+#define PSCI_RESET2_TYPE_ARCH		(U(0) << PSCI_RESET2_TYPE_VENDOR_SHIFT)
+#define PSCI_RESET2_SYSTEM_WARM_RESET	(PSCI_RESET2_TYPE_ARCH | U(0))
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/* Function to help build the psci capabilities bitfield */
+
+static inline unsigned int define_psci_cap(unsigned int x)
+{
+	return U(1) << (x & U(0x1f));
+}
+
+
+/* Power state helper functions */
+
+static inline unsigned int psci_get_pstate_id(unsigned int power_state)
+{
+	return ((power_state) >> PSTATE_ID_SHIFT) & PSTATE_ID_MASK;
+}
+
+static inline unsigned int psci_get_pstate_type(unsigned int power_state)
+{
+	return ((power_state) >> PSTATE_TYPE_SHIFT) & PSTATE_TYPE_MASK;
+}
+
+static inline unsigned int psci_check_power_state(unsigned int power_state)
+{
+	return ((power_state) & PSTATE_VALID_MASK);
+}
+
+/*
+ * These are the states reported by the PSCI_AFFINITY_INFO API for the specified
+ * CPU. The definitions of these states can be found in Section 5.7.1 in the
+ * PSCI specification (ARM DEN 0022C).
+ */
+typedef enum {
+	AFF_STATE_ON = U(0),
+	AFF_STATE_OFF = U(1),
+	AFF_STATE_ON_PENDING = U(2)
+} aff_info_state_t;
+
+/*
+ * These are the power states reported by PSCI_NODE_HW_STATE API for the
+ * specified CPU. The definitions of these states can be found in Section 5.15.3
+ * of PSCI specification (ARM DEN 0022C).
+ */
+#define HW_ON		0
+#define HW_OFF		1
+#define HW_STANDBY	2
+
+/*
+ * Macro to represent invalid affinity level within PSCI.
+ */
+#define PSCI_INVALID_PWR_LVL	(PLAT_MAX_PWR_LVL + U(1))
+
+/*
+ * Type for representing the local power state at a particular level.
+ */
+typedef uint8_t plat_local_state_t;
+
+/* The local state macro used to represent RUN state. */
+#define PSCI_LOCAL_STATE_RUN	U(0)
+
+/*
+ * Function to test whether the plat_local_state is RUN state
+ */
+static inline int is_local_state_run(unsigned int plat_local_state)
+{
+	return (plat_local_state == PSCI_LOCAL_STATE_RUN) ? 1 : 0;
+}
+
+/*
+ * Function to test whether the plat_local_state is RETENTION state
+ */
+static inline int is_local_state_retn(unsigned int plat_local_state)
+{
+	return ((plat_local_state > PSCI_LOCAL_STATE_RUN) &&
+		(plat_local_state <= PLAT_MAX_RET_STATE)) ? 1 : 0;
+}
+
+/*
+ * Function to test whether the plat_local_state is OFF state
+ */
+static inline int is_local_state_off(unsigned int plat_local_state)
+{
+	return ((plat_local_state > PLAT_MAX_RET_STATE) &&
+		(plat_local_state <= PLAT_MAX_OFF_STATE)) ? 1 : 0;
+}
+
+/*****************************************************************************
+ * This data structure defines the representation of the power state parameter
+ * for its exchange between the generic PSCI code and the platform port. For
+ * example, it is used by the platform port to specify the requested power
+ * states during a power management operation. It is used by the generic code to
+ * inform the platform about the target power states that each level should
+ * enter.
+ ****************************************************************************/
+typedef struct psci_power_state {
+	/*
+	 * The pwr_domain_state[] stores the local power state at each level
+	 * for the CPU.
+	 */
+	plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + U(1)];
+} psci_power_state_t;
+
+/*******************************************************************************
+ * Structure used to store per-cpu information relevant to the PSCI service.
+ * It is populated in the per-cpu data array. In return we get a guarantee that
+ * this information will not reside on a cache line shared with another cpu.
+ ******************************************************************************/
+typedef struct psci_cpu_data {
+	/* State as seen by PSCI Affinity Info API */
+	aff_info_state_t aff_info_state;
+
+	/*
+	 * Highest power level which takes part in a power management
+	 * operation.
+	 */
+	unsigned int target_pwrlvl;
+
+	/* The local power state of this CPU */
+	plat_local_state_t local_state;
+} psci_cpu_data_t;
+
+/*******************************************************************************
+ * Structure populated by platform specific code to export routines which
+ * perform common low level power management functions
+ ******************************************************************************/
+typedef struct plat_psci_ops {
+	void (*cpu_standby)(plat_local_state_t cpu_state);
+	int (*pwr_domain_on)(u_register_t mpidr);
+	void (*pwr_domain_off)(const psci_power_state_t *target_state);
+	void (*pwr_domain_suspend_pwrdown_early)(
+				const psci_power_state_t *target_state);
+	void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
+	void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
+	void (*pwr_domain_suspend_finish)(
+				const psci_power_state_t *target_state);
+	void __dead2 (*pwr_domain_pwr_down_wfi)(
+				const psci_power_state_t *target_state);
+	void __dead2 (*system_off)(void);
+	void __dead2 (*system_reset)(void);
+	int (*validate_power_state)(unsigned int power_state,
+				    psci_power_state_t *req_state);
+	int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
+	void (*get_sys_suspend_power_state)(
+				    psci_power_state_t *req_state);
+	int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,
+				    int pwrlvl);
+	int (*translate_power_state_by_mpidr)(u_register_t mpidr,
+				    unsigned int power_state,
+				    psci_power_state_t *output_state);
+	int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
+	int (*mem_protect_chk)(uintptr_t base, u_register_t length);
+	int (*read_mem_protect)(int *val);
+	int (*write_mem_protect)(int val);
+	int (*system_reset2)(int is_vendor,
+				int reset_type, u_register_t cookie);
+} plat_psci_ops_t;
+
+/*******************************************************************************
+ * Function & Data prototypes
+ ******************************************************************************/
+unsigned int psci_version(void);
+int psci_cpu_on(u_register_t target_cpu,
+		uintptr_t entrypoint,
+		u_register_t context_id);
+int psci_cpu_suspend(unsigned int power_state,
+		     uintptr_t entrypoint,
+		     u_register_t context_id);
+int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id);
+int psci_cpu_off(void);
+int psci_affinity_info(u_register_t target_affinity,
+		       unsigned int lowest_affinity_level);
+int psci_migrate(u_register_t target_cpu);
+int psci_migrate_info_type(void);
+u_register_t psci_migrate_info_up_cpu(void);
+int psci_node_hw_state(u_register_t target_cpu,
+		       unsigned int power_level);
+int psci_features(unsigned int psci_fid);
+void __dead2 psci_power_down_wfi(void);
+void psci_arch_setup(void);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* PSCI_H */
diff --git a/include/lib/psci/psci_lib.h b/include/lib/psci/psci_lib.h
new file mode 100644
index 0000000..76c1a8d
--- /dev/null
+++ b/include/lib/psci/psci_lib.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSCI_LIB_H
+#define PSCI_LIB_H
+
+#include <common/ep_info.h>
+
+#ifndef __ASSEMBLER__
+
+#include <cdefs.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Optional structure populated by the Secure Payload Dispatcher to be given a
+ * chance to perform any bookkeeping before PSCI executes a power management
+ * operation. It also allows PSCI to determine certain properties of the SP e.g.
+ * migrate capability etc.
+ ******************************************************************************/
+typedef struct spd_pm_ops {
+	void (*svc_on)(u_register_t target_cpu);
+	int32_t (*svc_off)(u_register_t __unused unused);
+	void (*svc_suspend)(u_register_t max_off_pwrlvl);
+	void (*svc_on_finish)(u_register_t __unused unused);
+	void (*svc_suspend_finish)(u_register_t max_off_pwrlvl);
+	int32_t (*svc_migrate)(u_register_t from_cpu, u_register_t to_cpu);
+	int32_t (*svc_migrate_info)(u_register_t *resident_cpu);
+	void (*svc_system_off)(void);
+	void (*svc_system_reset)(void);
+} spd_pm_ops_t;
+
+/*
+ * Function prototype for the warmboot entrypoint function which will be
+ * programmed in the mailbox by the platform.
+ */
+typedef void (*mailbox_entrypoint_t)(void);
+
+/******************************************************************************
+ * Structure to pass PSCI Library arguments.
+ *****************************************************************************/
+typedef struct psci_lib_args {
+	/* The version information of PSCI Library Interface */
+	param_header_t		h;
+	/* The warm boot entrypoint function */
+	mailbox_entrypoint_t	mailbox_ep;
+} psci_lib_args_t;
+
+/* Helper macro to set the psci_lib_args_t structure at runtime */
+#define SET_PSCI_LIB_ARGS_V1(_p, _entry)	do {			\
+	SET_PARAM_HEAD(_p, PARAM_PSCI_LIB_ARGS, VERSION_1, 0);		\
+	(_p)->mailbox_ep = (_entry);					\
+	} while (0)
+
+/* Helper macro to define the psci_lib_args_t statically */
+#define DEFINE_STATIC_PSCI_LIB_ARGS_V1(_name, _entry)		\
+	static const psci_lib_args_t (_name) = {		\
+		.h.type = (uint8_t)PARAM_PSCI_LIB_ARGS,		\
+		.h.version = (uint8_t)VERSION_1,		\
+		.h.size = (uint16_t)sizeof(_name),		\
+		.h.attr = 0U,					\
+		.mailbox_ep = (_entry)				\
+	}
+
+/* Helper macro to verify the pointer to psci_lib_args_t structure */
+#define VERIFY_PSCI_LIB_ARGS_V1(_p)	(((_p) != NULL)		\
+		&& ((_p)->h.type == PARAM_PSCI_LIB_ARGS)	\
+		&& ((_p)->h.version == VERSION_1)		\
+		&& ((_p)->h.size == sizeof(*(_p)))		\
+		&& ((_p)->h.attr == 0)				\
+		&& ((_p)->mailbox_ep != NULL))
+
+/******************************************************************************
+ * PSCI Library Interfaces
+ *****************************************************************************/
+u_register_t psci_smc_handler(uint32_t smc_fid,
+			  u_register_t x1,
+			  u_register_t x2,
+			  u_register_t x3,
+			  u_register_t x4,
+			  void *cookie,
+			  void *handle,
+			  u_register_t flags);
+int psci_setup(const psci_lib_args_t *lib_args);
+int psci_secondaries_brought_up(void);
+void psci_warmboot_entrypoint(void);
+void psci_register_spd_pm_hook(const spd_pm_ops_t *pm);
+void psci_prepare_next_non_secure_ctx(
+			  entry_point_info_t *next_image_info);
+#endif /* __ASSEMBLER__ */
+
+#endif /* PSCI_LIB_H */
diff --git a/include/lib/runtime_instr.h b/include/lib/runtime_instr.h
new file mode 100644
index 0000000..303f27e
--- /dev/null
+++ b/include/lib/runtime_instr.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RUNTIME_INSTR_H
+#define RUNTIME_INSTR_H
+
+#include <lib/utils_def.h>
+
+#define RT_INSTR_ENTER_PSCI		U(0)
+#define RT_INSTR_EXIT_PSCI		U(1)
+#define RT_INSTR_ENTER_HW_LOW_PWR	U(2)
+#define RT_INSTR_EXIT_HW_LOW_PWR	U(3)
+#define RT_INSTR_ENTER_CFLUSH		U(4)
+#define RT_INSTR_EXIT_CFLUSH		U(5)
+#define RT_INSTR_TOTAL_IDS		U(6)
+
+#ifndef __ASSEMBLER__
+PMF_DECLARE_CAPTURE_TIMESTAMP(rt_instr_svc)
+PMF_DECLARE_GET_TIMESTAMP(rt_instr_svc)
+#endif /* __ASSEMBLER__ */
+
+#endif /* RUNTIME_INSTR_H */
diff --git a/include/lib/semihosting.h b/include/lib/semihosting.h
new file mode 100644
index 0000000..006c7b7
--- /dev/null
+++ b/include/lib/semihosting.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SEMIHOSTING_H
+#define SEMIHOSTING_H
+
+#include <stdint.h>
+#include <stdio.h> /* For ssize_t */
+
+
+#define SEMIHOSTING_SYS_OPEN            0x01
+#define SEMIHOSTING_SYS_CLOSE           0x02
+#define SEMIHOSTING_SYS_WRITE0          0x04
+#define SEMIHOSTING_SYS_WRITEC          0x03
+#define SEMIHOSTING_SYS_WRITE           0x05
+#define SEMIHOSTING_SYS_READ            0x06
+#define SEMIHOSTING_SYS_READC           0x07
+#define SEMIHOSTING_SYS_SEEK            0x0A
+#define SEMIHOSTING_SYS_FLEN            0x0C
+#define SEMIHOSTING_SYS_REMOVE          0x0E
+#define SEMIHOSTING_SYS_SYSTEM          0x12
+#define SEMIHOSTING_SYS_ERRNO           0x13
+
+#define FOPEN_MODE_R			0x0
+#define FOPEN_MODE_RB			0x1
+#define FOPEN_MODE_RPLUS		0x2
+#define FOPEN_MODE_RPLUSB		0x3
+#define FOPEN_MODE_W			0x4
+#define FOPEN_MODE_WB			0x5
+#define FOPEN_MODE_WPLUS		0x6
+#define FOPEN_MODE_WPLUSB		0x7
+#define FOPEN_MODE_A			0x8
+#define FOPEN_MODE_AB			0x9
+#define FOPEN_MODE_APLUS		0xa
+#define FOPEN_MODE_APLUSB		0xb
+
+long semihosting_connection_supported(void);
+long semihosting_file_open(const char *file_name, size_t mode);
+long semihosting_file_seek(long file_handle, ssize_t offset);
+long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer);
+long semihosting_file_write(long file_handle,
+			    size_t *length,
+			    const uintptr_t buffer);
+long semihosting_file_close(long file_handle);
+long semihosting_file_length(long file_handle);
+long semihosting_system(char *command_line);
+long semihosting_get_flen(const char *file_name);
+long semihosting_download_file(const char *file_name,
+			       size_t buf_size,
+			       uintptr_t buf);
+void semihosting_write_char(char character);
+void semihosting_write_string(char *string);
+char semihosting_read_char(void);
+
+#endif /* SEMIHOSTING_H */
diff --git a/include/lib/smccc.h b/include/lib/smccc.h
new file mode 100644
index 0000000..76e6023
--- /dev/null
+++ b/include/lib/smccc.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMCCC_H
+#define SMCCC_H
+
+#include <lib/utils_def.h>
+
+#define SMCCC_VERSION_MAJOR_SHIFT	U(16)
+#define SMCCC_VERSION_MAJOR_MASK	U(0x7FFF)
+#define SMCCC_VERSION_MINOR_SHIFT	U(0)
+#define SMCCC_VERSION_MINOR_MASK	U(0xFFFF)
+#define MAKE_SMCCC_VERSION(_major, _minor) \
+	((((uint32_t)(_major) & SMCCC_VERSION_MAJOR_MASK) << \
+						SMCCC_VERSION_MAJOR_SHIFT) \
+	| (((uint32_t)(_minor) & SMCCC_VERSION_MINOR_MASK) << \
+						SMCCC_VERSION_MINOR_SHIFT))
+
+#define SMCCC_MAJOR_VERSION U(1)
+#define SMCCC_MINOR_VERSION U(1)
+
+/*******************************************************************************
+ * Bit definitions inside the function id as per the SMC calling convention
+ ******************************************************************************/
+#define FUNCID_TYPE_SHIFT		U(31)
+#define FUNCID_TYPE_MASK		U(0x1)
+#define FUNCID_TYPE_WIDTH		U(1)
+
+#define FUNCID_CC_SHIFT			U(30)
+#define FUNCID_CC_MASK			U(0x1)
+#define FUNCID_CC_WIDTH			U(1)
+
+#define FUNCID_OEN_SHIFT		U(24)
+#define FUNCID_OEN_MASK			U(0x3f)
+#define FUNCID_OEN_WIDTH		U(6)
+
+#define FUNCID_NUM_SHIFT		U(0)
+#define FUNCID_NUM_MASK			U(0xffff)
+#define FUNCID_NUM_WIDTH		U(16)
+
+#define GET_SMC_TYPE(id)		(((id) >> FUNCID_TYPE_SHIFT) & \
+					 FUNCID_TYPE_MASK)
+#define GET_SMC_CC(id)			(((id) >> FUNCID_CC_SHIFT) & \
+					 FUNCID_CC_MASK)
+#define GET_SMC_OEN(id)			(((id) >> FUNCID_OEN_SHIFT) & \
+					 FUNCID_OEN_MASK)
+
+/*******************************************************************************
+ * Owning entity number definitions inside the function id as per the SMC
+ * calling convention
+ ******************************************************************************/
+#define OEN_ARM_START			U(0)
+#define OEN_ARM_END			U(0)
+#define OEN_CPU_START			U(1)
+#define OEN_CPU_END			U(1)
+#define OEN_SIP_START			U(2)
+#define OEN_SIP_END			U(2)
+#define OEN_OEM_START			U(3)
+#define OEN_OEM_END			U(3)
+#define OEN_STD_START			U(4)	/* Standard Service Calls */
+#define OEN_STD_END			U(4)
+#define OEN_STD_HYP_START		U(5)	/* Standard Hypervisor Service calls */
+#define OEN_STD_HYP_END			U(5)
+#define OEN_VEN_HYP_START		U(6)	/* Vendor Hypervisor Service calls */
+#define OEN_VEN_HYP_END			U(6)
+#define OEN_TAP_START			U(48)	/* Trusted Applications */
+#define OEN_TAP_END			U(49)
+#define OEN_TOS_START			U(50)	/* Trusted OS */
+#define OEN_TOS_END			U(63)
+#define OEN_LIMIT			U(64)
+
+/* Flags and error codes */
+#define SMC_64				U(1)
+#define SMC_32				U(0)
+
+#define SMC_TYPE_FAST			ULL(1)
+#define SMC_TYPE_YIELD			ULL(0)
+
+#define SMC_OK				ULL(0)
+#define SMC_UNK				-1
+#define SMC_PREEMPTED			-2	/* Not defined by the SMCCC */
+
+/* Various flags passed to SMC handlers */
+#define SMC_FROM_SECURE		(U(0) << 0)
+#define SMC_FROM_NON_SECURE	(U(1) << 0)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+#define is_caller_non_secure(_f)	(((_f) & SMC_FROM_NON_SECURE) != U(0))
+#define is_caller_secure(_f)		(!is_caller_non_secure(_f))
+
+/* The macro below is used to identify a Standard Service SMC call */
+#define is_std_svc_call(_fid)		(GET_SMC_OEN(_fid) == OEN_STD_START)
+
+/* The macro below is used to identify a Arm Architectural Service SMC call */
+#define is_arm_arch_svc_call(_fid)	(GET_SMC_OEN(_fid) == OEN_ARM_START)
+
+/* The macro below is used to identify a valid Fast SMC call */
+#define is_valid_fast_smc(_fid)		((!(((_fid) >> 16) & U(0xff))) && \
+					   (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST))
+
+/*
+ * Macro to define UUID for services. Apart from defining and initializing a
+ * uuid_t structure, this macro verifies that the first word of the defined UUID
+ * does not equal SMC_UNK. This is to ensure that the caller won't mistake the
+ * returned UUID in x0 for an invalid SMC error return
+ */
+#define DEFINE_SVC_UUID2(_name, _tl, _tm, _th, _cl, _ch,		\
+		_n0, _n1, _n2, _n3, _n4, _n5)				\
+	CASSERT((uint32_t)(_tl) != (uint32_t) SMC_UNK, invalid_svc_uuid);\
+	static const uuid_t _name = {					\
+		{(_tl >> 24) & 0xFF,					\
+		 (_tl >> 16) & 0xFF,					\
+		 (_tl >> 8)  & 0xFF,					\
+		 (_tl & 0xFF)},						\
+		{(_tm >> 8) & 0xFF,					\
+		 (_tm  & 0xFF)},					\
+		{(_th >> 8) & 0xFF,					\
+		 (_th & 0xFF)},						\
+		_cl, _ch,						\
+		{ _n0, _n1, _n2, _n3, _n4, _n5 }			\
+	}
+
+/*
+ * Return a UUID in the SMC return registers.
+ *
+ * Acccording to section 5.3 of the SMCCC, UUIDs are returned as a single
+ * 128-bit value using the SMC32 calling convention. This value is mapped to
+ * argument registers x0-x3 on AArch64 (resp. r0-r3 on AArch32). x0 for example
+ * shall hold bytes 0 to 3, with byte 0 in the low-order bits.
+ */
+static inline uint32_t smc_uuid_word(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3)
+{
+	return ((uint32_t) b0) | (((uint32_t) b1) << 8) |
+		(((uint32_t) b2) << 16) | (((uint32_t) b3) << 24);
+}
+
+#define SMC_UUID_RET(_h, _uuid)							\
+	SMC_RET4(handle,							\
+		smc_uuid_word((_uuid).time_low[0], (_uuid).time_low[1],		\
+			      (_uuid).time_low[2], (_uuid).time_low[3]),	\
+		smc_uuid_word((_uuid).time_mid[0], (_uuid).time_mid[1],		\
+			      (_uuid).time_hi_and_version[0],			\
+			      (_uuid).time_hi_and_version[1]),			\
+		smc_uuid_word((_uuid).clock_seq_hi_and_reserved,		\
+			      (_uuid).clock_seq_low, (_uuid).node[0],		\
+			      (_uuid).node[1]),					\
+		smc_uuid_word((_uuid).node[2], (_uuid).node[3],			\
+			      (_uuid).node[4], (_uuid).node[5]))
+
+#endif /*__ASSEMBLER__*/
+#endif /* SMCCC_H */
diff --git a/include/lib/spinlock.h b/include/lib/spinlock.h
new file mode 100644
index 0000000..0bf3ee0
--- /dev/null
+++ b/include/lib/spinlock.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPINLOCK_H
+#define SPINLOCK_H
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct spinlock {
+	volatile uint32_t lock;
+} spinlock_t;
+
+void spin_lock(spinlock_t *lock);
+void spin_unlock(spinlock_t *lock);
+
+#else
+
+/* Spin lock definitions for use in assembly */
+#define SPINLOCK_ASM_ALIGN	2
+#define SPINLOCK_ASM_SIZE	4
+
+#endif
+
+#endif /* SPINLOCK_H */
diff --git a/include/lib/sprt/sprt_common.h b/include/lib/sprt/sprt_common.h
new file mode 100644
index 0000000..27d5027
--- /dev/null
+++ b/include/lib/sprt/sprt_common.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPRT_COMMON_H
+#define SPRT_COMMON_H
+
+#define SPRT_MAX_MSG_ARGS	6
+
+/*
+ * Message types supported.
+ */
+#define SPRT_MSG_TYPE_SERVICE_HANDLE_OPEN		1
+#define SPRT_MSG_TYPE_SERVICE_HANDLE_CLOSE		2
+/* TODO: Add other types of SPRT messages. */
+#define SPRT_MSG_TYPE_SERVICE_TUN_REQUEST		10
+
+/*
+ * Struct that defines the layout of the fields corresponding to a request in
+ * shared memory.
+ */
+struct __attribute__((__packed__)) sprt_queue_entry_message {
+	uint32_t type;		/* Type of message (result of an SPCI call). */
+	uint16_t client_id;	/* SPCI client ID */
+	uint16_t service_handle;/* SPCI service handle */
+	uint32_t session_id;	/* Optional SPCI session ID */
+	uint32_t token;		/* SPCI request token */
+	uint64_t args[SPRT_MAX_MSG_ARGS];
+};
+
+#define SPRT_QUEUE_ENTRY_MSG_SIZE	(sizeof(struct sprt_queue_entry_message))
+
+#define SPRT_QUEUE_NUM_BLOCKING		0
+#define SPRT_QUEUE_NUM_NON_BLOCKING	1
+
+#endif /* SPRT_COMMON_H */
diff --git a/include/lib/sprt/sprt_host.h b/include/lib/sprt/sprt_host.h
new file mode 100644
index 0000000..f888141
--- /dev/null
+++ b/include/lib/sprt/sprt_host.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SPRT_HOST_H
+#define SPRT_HOST_H
+
+#include <stddef.h>
+
+#include "sprt_common.h"
+
+/*
+ * Initialize the specified buffer to be used by SPM.
+ */
+void sprt_initialize_queues(void *buffer_base, size_t buffer_size);
+
+/*
+ * Push a message to the queue number `queue_num` in a buffer that has been
+ * initialized by `sprt_initialize_queues`.
+ */
+int sprt_push_message(void *buffer_base,
+		      const struct sprt_queue_entry_message *message,
+		      int queue_num);
+
+#endif /* SPRT_HOST_H */
diff --git a/include/lib/utils.h b/include/lib/utils.h
new file mode 100644
index 0000000..cdb125c
--- /dev/null
+++ b/include/lib/utils.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+/*
+ * C code should be put in this part of the header to avoid breaking ASM files
+ * or linker scripts including it.
+ */
+#if !(defined(__LINKER__) || defined(__ASSEMBLER__))
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct mem_region {
+	uintptr_t base;
+	size_t nbytes;
+} mem_region_t;
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions);
+
+/*
+ * zero_normalmem all the regions defined in region. It dynamically
+ * maps chunks of 'chunk_size' in 'va' virtual address and clears them.
+ * For this reason memory regions must be multiple of chunk_size and
+ * must be aligned to it as well. chunk_size and va can be selected
+ * in a way that they minimize the number of entries used in the
+ * translation tables.
+ */
+void clear_map_dyn_mem_regions(struct mem_region *regions,
+			       size_t nregions,
+			       uintptr_t va,
+			       size_t chunk);
+
+/*
+ * checks that a region (addr + nbytes-1) of memory is totally covered by
+ * one of the regions defined in tbl. Caller must ensure that (addr+nbytes-1)
+ * doesn't overflow.
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+			    uintptr_t addr, size_t nbytes);
+
+/*
+ * Fill a region of normal memory of size "length" in bytes with zero bytes.
+ *
+ * WARNING: This function can only operate on normal memory. This means that
+ *          the MMU must be enabled when using this function. Otherwise, use
+ *          zeromem.
+ */
+void zero_normalmem(void *mem, u_register_t length);
+
+/*
+ * Fill a region of memory of size "length" in bytes with null bytes.
+ *
+ * Unlike zero_normalmem, this function has no restriction on the type of
+ * memory targeted and can be used for any device memory as well as normal
+ * memory. This function must be used instead of zero_normalmem when MMU is
+ * disabled.
+ *
+ * NOTE: When data cache and MMU are enabled, prefer zero_normalmem for faster
+ *       zeroing.
+ */
+void zeromem(void *mem, u_register_t length);
+
+/*
+ * Utility function to return the address of a symbol. By default, the
+ * compiler generates adr/adrp instruction pair to return the reference
+ * to the symbol and this utility is used to override this compiler
+ * generated to code to use `ldr` instruction.
+ *
+ * This helps when Position Independent Executable needs to reference a symbol
+ * which is constant and does not depend on the execute address of the binary.
+ */
+#define DEFINE_LOAD_SYM_ADDR(_name)		\
+static inline u_register_t load_addr_## _name(void)		\
+{								\
+	u_register_t v;						\
+	/* Create a void reference to silence compiler */	\
+	(void) _name;						\
+	__asm__ volatile ("ldr %0, =" #_name : "=r" (v));	\
+	return v;						\
+}
+
+/* Helper to invoke the function defined by DEFINE_LOAD_SYM_ADDR() */
+#define LOAD_ADDR_OF(_name)	(typeof(_name) *) load_addr_## _name()
+
+#endif /* !(defined(__LINKER__) || defined(__ASSEMBLER__)) */
+
+#endif /* UTILS_H */
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
new file mode 100644
index 0000000..35ae33a
--- /dev/null
+++ b/include/lib/utils_def.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UTILS_DEF_H
+#define UTILS_DEF_H
+
+#include <export/lib/utils_def_exp.h>
+
+/* Compute the number of elements in the given array */
+#define ARRAY_SIZE(a)				\
+	(sizeof(a) / sizeof((a)[0]))
+
+#define IS_POWER_OF_TWO(x)			\
+	(((x) & ((x) - 1)) == 0)
+
+#define SIZE_FROM_LOG2_WORDS(n)		(4 << (n))
+
+#define BIT_32(nr)			(U(1) << (nr))
+#define BIT_64(nr)			(ULL(1) << (nr))
+
+#ifdef __aarch64__
+#define BIT				BIT_64
+#else
+#define BIT				BIT_32
+#endif
+
+/*
+ * Create a contiguous bitmask starting at bit position @l and ending at
+ * position @h. For example
+ * GENMASK_64(39, 21) gives us the 64bit vector 0x000000ffffe00000.
+ */
+#if defined(__LINKER__) || defined(__ASSEMBLER__)
+#define GENMASK_32(h, l) \
+	(((0xFFFFFFFF) << (l)) & (0xFFFFFFFF >> (32 - 1 - (h))))
+
+#define GENMASK_64(h, l) \
+	((~0 << (l)) & (~0 >> (64 - 1 - (h))))
+#else
+#define GENMASK_32(h, l) \
+	(((~UINT32_C(0)) << (l)) & (~UINT32_C(0) >> (32 - 1 - (h))))
+
+#define GENMASK_64(h, l) \
+	(((~UINT64_C(0)) << (l)) & (~UINT64_C(0) >> (64 - 1 - (h))))
+#endif
+
+#ifdef __aarch64__
+#define GENMASK				GENMASK_64
+#else
+#define GENMASK				GENMASK_32
+#endif
+
+/*
+ * This variant of div_round_up can be used in macro definition but should not
+ * be used in C code as the `div` parameter is evaluated twice.
+ */
+#define DIV_ROUND_UP_2EVAL(n, d)	(((n) + (d) - 1) / (d))
+
+#define div_round_up(val, div) __extension__ ({	\
+	__typeof__(div) _div = (div);		\
+	((val) + _div - (__typeof__(div)) 1) / _div;		\
+})
+
+#define MIN(x, y) __extension__ ({	\
+	__typeof__(x) _x = (x);		\
+	__typeof__(y) _y = (y);		\
+	(void)(&_x == &_y);		\
+	_x < _y ? _x : _y;		\
+})
+
+#define MAX(x, y) __extension__ ({	\
+	__typeof__(x) _x = (x);		\
+	__typeof__(y) _y = (y);		\
+	(void)(&_x == &_y);		\
+	_x > _y ? _x : _y;		\
+})
+
+/*
+ * The round_up() macro rounds up a value to the given boundary in a
+ * type-agnostic yet type-safe manner. The boundary must be a power of two.
+ * In other words, it computes the smallest multiple of boundary which is
+ * greater than or equal to value.
+ *
+ * round_down() is similar but rounds the value down instead.
+ */
+#define round_boundary(value, boundary)		\
+	((__typeof__(value))((boundary) - 1))
+
+#define round_up(value, boundary)		\
+	((((value) - 1) | round_boundary(value, boundary)) + 1)
+
+#define round_down(value, boundary)		\
+	((value) & ~round_boundary(value, boundary))
+
+/*
+ * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise.
+ * Both arguments must be unsigned pointer values (i.e. uintptr_t).
+ */
+#define check_uptr_overflow(_ptr, _inc)		\
+	((_ptr) > (UINTPTR_MAX - (_inc)))
+
+/*
+ * Evaluates to 1 if (u32 + inc) overflows, 0 otherwise.
+ * Both arguments must be 32-bit unsigned integers (i.e. effectively uint32_t).
+ */
+#define check_u32_overflow(_u32, _inc) \
+	((_u32) > (UINT32_MAX - (_inc)))
+
+/* Register size of the current architecture. */
+#ifdef __aarch64__
+#define REGSZ		U(8)
+#else
+#define REGSZ		U(4)
+#endif
+
+/*
+ * Test for the current architecture version to be at least the version
+ * expected.
+ */
+#define ARM_ARCH_AT_LEAST(_maj, _min) \
+	((ARM_ARCH_MAJOR > (_maj)) || \
+	 ((ARM_ARCH_MAJOR == (_maj)) && (ARM_ARCH_MINOR >= (_min))))
+
+/*
+ * Import an assembly or linker symbol as a C expression with the specified
+ * type
+ */
+#define IMPORT_SYM(type, sym, name) \
+	extern char sym[];\
+	static const __attribute__((unused)) type name = (type) sym;
+
+/*
+ * When the symbol is used to hold a pointer, its alignment can be asserted
+ * with this macro. For example, if there is a linker symbol that is going to
+ * be used as a 64-bit pointer, the value of the linker symbol must also be
+ * aligned to 64 bit. This macro makes sure this is the case.
+ */
+#define ASSERT_SYM_PTR_ALIGN(sym) assert(((size_t)(sym) % __alignof__(*(sym))) == 0)
+
+#define COMPILER_BARRIER() __asm__ volatile ("" ::: "memory")
+
+/* Compiler builtin of GCC >= 9 and planned in llvm */
+#ifdef __HAVE_SPECULATION_SAFE_VALUE
+# define SPECULATION_SAFE_VALUE(var) __builtin_speculation_safe_value(var)
+#else
+# define SPECULATION_SAFE_VALUE(var) var
+#endif
+
+#endif /* UTILS_DEF_H */
diff --git a/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
new file mode 100644
index 0000000..30eb5e9
--- /dev/null
+++ b/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_AARCH32_H
+#define XLAT_TABLES_AARCH32_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#if !defined(PAGE_SIZE)
+#error "PAGE_SIZE is not defined."
+#endif
+
+/*
+ * In AArch32 state, the MMU only supports 4KB page granularity, which means
+ * that the first translation table level is either 1 or 2. Both of them are
+ * allowed to have block and table descriptors. See section G4.5.6 of the
+ * ARMv8-A Architecture Reference Manual (DDI 0487A.k) for more information.
+ *
+ * The define below specifies the first table level that allows block
+ * descriptors.
+ */
+#if PAGE_SIZE != PAGE_SIZE_4KB
+#error "Invalid granule size. AArch32 supports 4KB pages only."
+#endif
+
+#define MIN_LVL_BLOCK_DESC	U(1)
+
+#define XLAT_TABLE_LEVEL_MIN	U(1)
+
+/*
+ * Define the architectural limits of the virtual address space in AArch32
+ * state.
+ *
+ * TTBCR.TxSZ is calculated as 32 minus the width of said address space. The
+ * value of TTBCR.TxSZ must be in the range 0 to 7 [1], which means that the
+ * virtual address space width must be in the range 32 to 25 bits.
+ *
+ * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more
+ * information, Section G4.6.5
+ */
+#define MIN_VIRT_ADDR_SPACE_SIZE	(ULL(1) << (U(32) - TTBCR_TxSZ_MAX))
+#define MAX_VIRT_ADDR_SPACE_SIZE	(ULL(1) << (U(32) - TTBCR_TxSZ_MIN))
+
+/*
+ * Here we calculate the initial lookup level from the value of the given
+ * virtual address space size. For a 4 KB page size,
+ * - level 1 supports virtual address spaces of widths 32 to 31 bits;
+ * - level 2 from 30 to 25.
+ *
+ * Wider or narrower address spaces are not supported. As a result, level 3
+ * cannot be used as the initial lookup level with 4 KB granularity.
+ * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more
+ * information, Section G4.6.5
+ *
+ * For example, for a 31-bit address space (i.e. virt_addr_space_size ==
+ * 1 << 31), TTBCR.TxSZ will be programmed to (32 - 31) = 1. According to Table
+ * G4-5 in the ARM ARM, the initial lookup level for an address space like that
+ * is 1.
+ *
+ * Note that this macro assumes that the given virtual address space size is
+ * valid.
+ */
+#define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz)			\
+	(((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) ?	\
+	 U(1) : U(2))
+
+#endif /* XLAT_TABLES_AARCH32_H */
diff --git a/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
new file mode 100644
index 0000000..3014c8f
--- /dev/null
+++ b/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_AARCH64_H
+#define XLAT_TABLES_AARCH64_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#if !defined(PAGE_SIZE)
+#error "PAGE_SIZE is not defined."
+#endif
+
+/*
+ * Encode a Physical Address Space size for its use in TCR_ELx.
+ */
+unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr);
+
+/*
+ * In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page
+ * granularity. For 4KB granularity, a level 0 table descriptor doesn't support
+ * block translation. For 16KB, the same thing happens to levels 0 and 1. For
+ * 64KB, same for level 1. See section D4.3.1 of the ARMv8-A Architecture
+ * Reference Manual (DDI 0487A.k) for more information.
+ *
+ * The define below specifies the first table level that allows block
+ * descriptors.
+ */
+#if PAGE_SIZE == PAGE_SIZE_4KB
+# define MIN_LVL_BLOCK_DESC	U(1)
+#elif (PAGE_SIZE == PAGE_SIZE_16KB) || (PAGE_SIZE == PAGE_SIZE_64KB)
+# define MIN_LVL_BLOCK_DESC	U(2)
+#endif
+
+#define XLAT_TABLE_LEVEL_MIN	U(0)
+
+/*
+ * Define the architectural limits of the virtual address space in AArch64
+ * state.
+ *
+ * TCR.TxSZ is calculated as 64 minus the width of said address space.
+ * The value of TCR.TxSZ must be in the range 16 to 39 [1] or 48 [2],
+ * depending on Small Translation Table Support which means that
+ * the virtual address space width must be in the range 48 to 25 or 16 bits.
+ *
+ * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more
+ * information:
+ * Page 1730: 'Input address size', 'For all translation stages'.
+ * [2] See section 12.2.55 in the ARMv8-A Architecture Reference Manual
+ * (DDI 0487D.a)
+ */
+/* Maximum value of TCR_ELx.T(0,1)SZ is 39 */
+#define MIN_VIRT_ADDR_SPACE_SIZE	(ULL(1) << (U(64) - TCR_TxSZ_MAX))
+
+/* Maximum value of TCR_ELx.T(0,1)SZ is 48 */
+#define MIN_VIRT_ADDR_SPACE_SIZE_TTST	\
+				(ULL(1) << (U(64) - TCR_TxSZ_MAX_TTST))
+#define MAX_VIRT_ADDR_SPACE_SIZE	(ULL(1) << (U(64) - TCR_TxSZ_MIN))
+
+/*
+ * Here we calculate the initial lookup level from the value of the given
+ * virtual address space size. For a 4 KB page size,
+ * - level 0 supports virtual address spaces of widths 48 to 40 bits;
+ * - level 1 from 39 to 31;
+ * - level 2 from 30 to 22.
+ * - level 3 from 21 to 16.
+ *
+ * Small Translation Table (Armv8.4-TTST) support allows the starting level
+ * of the translation table from 3 for 4KB granularity. See section 12.2.55 in
+ * the ARMv8-A Architecture Reference Manual (DDI 0487D.a). In Armv8.3 and below
+ * wider or narrower address spaces are not supported. As a result, level 3
+ * cannot be used as initial lookup level with 4 KB granularity. See section
+ * D4.2.5 in the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more
+ * information.
+ *
+ * For example, for a 35-bit address space (i.e. virt_addr_space_size ==
+ * 1 << 35), TCR.TxSZ will be programmed to (64 - 35) = 29. According to Table
+ * D4-11 in the ARM ARM, the initial lookup level for an address space like that
+ * is 1.
+ *
+ * Note that this macro assumes that the given virtual address space size is
+ * valid.
+ */
+#define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz)		\
+	(((_virt_addr_space_sz) > (ULL(1) << L0_XLAT_ADDRESS_SHIFT))	\
+	? 0U								\
+	: (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT))	\
+	? 1U								\
+	: (((_virt_addr_space_sz) > (ULL(1) << L2_XLAT_ADDRESS_SHIFT))	\
+	? 2U : 3U)))
+
+#endif /* XLAT_TABLES_AARCH64_H */
diff --git a/include/lib/xlat_tables/xlat_mmu_helpers.h b/include/lib/xlat_tables/xlat_mmu_helpers.h
new file mode 100644
index 0000000..abdf1b6
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_mmu_helpers.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_MMU_HELPERS_H
+#define XLAT_MMU_HELPERS_H
+
+/*
+ * The following flags are passed to enable_mmu_xxx() to override the default
+ * values used to program system registers while enabling the MMU.
+ */
+
+/*
+ * When this flag is used, all data access to Normal memory from this EL and all
+ * Normal memory accesses to the translation tables of this EL are non-cacheable
+ * for all levels of data and unified cache until the caches are enabled by
+ * setting the bit SCTLR_ELx.C.
+ */
+#define DISABLE_DCACHE			(U(1) << 0)
+
+/*
+ * Mark the translation tables as non-cacheable for the MMU table walker, which
+ * is a different observer from the PE/CPU. If the flag is not specified, the
+ * tables are cacheable for the MMU table walker.
+ *
+ * Note that, as far as the PE/CPU observer is concerned, the attributes used
+ * are the ones specified in the translation tables themselves. The MAIR
+ * register specifies the cacheability through the field AttrIndx of the lower
+ * attributes of the translation tables. The shareability is specified in the SH
+ * field of the lower attributes.
+ *
+ * The MMU table walker uses the attributes specified in the fields ORGNn, IRGNn
+ * and SHn of the TCR register to access the translation tables.
+ *
+ * The attributes specified in the TCR register and the tables can be different
+ * as there are no checks to prevent that. Special care must be taken to ensure
+ * that there aren't mismatches. The behaviour in that case is described in the
+ * sections 'Mismatched memory attributes' in the ARMv8 ARM.
+ */
+#define XLAT_TABLE_NC			(U(1) << 1)
+
+/*
+ * Offsets into a mmu_cfg_params array generated by setup_mmu_cfg(). All
+ * parameters are 64 bits wide.
+ */
+#define MMU_CFG_MAIR		0
+#define MMU_CFG_TCR		1
+#define MMU_CFG_TTBR0		2
+#define MMU_CFG_PARAM_MAX	3
+
+#ifndef __ASSEMBLER__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Return the values that the MMU configuration registers must contain for the
+ * specified translation context. `params` must be a pointer to array of size
+ * MMU_CFG_PARAM_MAX.
+ */
+void setup_mmu_cfg(uint64_t *params, unsigned int flags,
+		   const uint64_t *base_table, unsigned long long max_pa,
+		   uintptr_t max_va, int xlat_regime);
+
+#ifdef __aarch64__
+/* AArch64 specific translation table APIs */
+void enable_mmu_el1(unsigned int flags);
+void enable_mmu_el2(unsigned int flags);
+void enable_mmu_el3(unsigned int flags);
+
+void enable_mmu_direct_el1(unsigned int flags);
+void enable_mmu_direct_el2(unsigned int flags);
+void enable_mmu_direct_el3(unsigned int flags);
+#else
+/* AArch32 specific translation table API */
+void enable_mmu_svc_mon(unsigned int flags);
+void enable_mmu_hyp(unsigned int flags);
+
+void enable_mmu_direct_svc_mon(unsigned int flags);
+void enable_mmu_direct_hyp(unsigned int flags);
+#endif /* __aarch64__ */
+
+bool xlat_arch_is_granule_size_supported(size_t size);
+size_t xlat_arch_get_max_supported_granule_size(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* XLAT_MMU_HELPERS_H */
diff --git a/include/lib/xlat_tables/xlat_tables.h b/include/lib/xlat_tables/xlat_tables.h
new file mode 100644
index 0000000..082bb5e
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_H
+#define XLAT_TABLES_H
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+/* Helper macro to define entries for mmap_region_t. It creates
+ * identity mappings for each region.
+ */
+#define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr)
+
+/* Helper macro to define entries for mmap_region_t. It allows to
+ * re-map address mappings from 'pa' to 'va' for each region.
+ */
+#define MAP_REGION(pa, va, sz, attr) {(pa), (va), (sz), (attr)}
+
+/*
+ * Shifts and masks to access fields of an mmap attribute
+ */
+#define MT_TYPE_MASK	U(0x7)
+#define MT_TYPE(_attr)	((_attr) & MT_TYPE_MASK)
+/* Access permissions (RO/RW) */
+#define MT_PERM_SHIFT	U(3)
+/* Security state (SECURE/NS) */
+#define MT_SEC_SHIFT	U(4)
+/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */
+#define MT_EXECUTE_SHIFT	U(5)
+
+/*
+ * Memory mapping attributes
+ */
+
+/*
+ * Memory types supported.
+ * These are organised so that, going down the list, the memory types are
+ * getting weaker; conversely going up the list the memory types are getting
+ * stronger.
+ */
+#define MT_DEVICE		U(0)
+#define MT_NON_CACHEABLE	U(1)
+#define MT_MEMORY		U(2)
+/* Values up to 7 are reserved to add new memory types in the future */
+
+#define MT_RO			(U(0) << MT_PERM_SHIFT)
+#define MT_RW			(U(1) << MT_PERM_SHIFT)
+
+#define MT_SECURE		(U(0) << MT_SEC_SHIFT)
+#define MT_NS			(U(1) << MT_SEC_SHIFT)
+
+/*
+ * Access permissions for instruction execution are only relevant for normal
+ * read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored (and potentially
+ * overridden) otherwise:
+ *  - Device memory is always marked as execute-never.
+ *  - Read-write normal memory is always marked as execute-never.
+ */
+#define MT_EXECUTE		(U(0) << MT_EXECUTE_SHIFT)
+#define MT_EXECUTE_NEVER	(U(1) << MT_EXECUTE_SHIFT)
+
+/* Compound attributes for most common usages */
+#define MT_CODE			(MT_MEMORY | MT_RO | MT_EXECUTE)
+#define MT_RO_DATA		(MT_MEMORY | MT_RO | MT_EXECUTE_NEVER)
+
+/*
+ * Structure for specifying a single region of memory.
+ */
+typedef struct mmap_region {
+	unsigned long long	base_pa;
+	uintptr_t		base_va;
+	size_t			size;
+	unsigned int		attr;
+} mmap_region_t;
+
+/* Generic translation table APIs */
+void init_xlat_tables(void);
+void mmap_add_region(unsigned long long base_pa, uintptr_t base_va,
+		     size_t size, unsigned int attr);
+void mmap_add(const mmap_region_t *mm);
+
+#endif /*__ASSEMBLER__*/
+#endif /* XLAT_TABLES_H */
diff --git a/include/lib/xlat_tables/xlat_tables_arch.h b/include/lib/xlat_tables/xlat_tables_arch.h
new file mode 100644
index 0000000..0ce0cac
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_arch.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_ARCH_H
+#define XLAT_TABLES_ARCH_H
+
+#ifdef __aarch64__
+#include "aarch64/xlat_tables_aarch64.h"
+#else
+#include "aarch32/xlat_tables_aarch32.h"
+#endif
+
+/*
+ * Evaluates to 1 if the given physical address space size is a power of 2,
+ * or 0 if it's not.
+ */
+#define CHECK_PHY_ADDR_SPACE_SIZE(size)				\
+	(IS_POWER_OF_TWO(size))
+
+/*
+ * Compute the number of entries required at the initial lookup level to address
+ * the whole virtual address space.
+ */
+#define GET_NUM_BASE_LEVEL_ENTRIES(addr_space_size)			\
+	((addr_space_size) >>						\
+		XLAT_ADDR_SHIFT(GET_XLAT_TABLE_LEVEL_BASE(addr_space_size)))
+
+#endif /* XLAT_TABLES_ARCH_H */
diff --git a/include/lib/xlat_tables/xlat_tables_compat.h b/include/lib/xlat_tables/xlat_tables_compat.h
new file mode 100644
index 0000000..90768db
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_compat.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if XLAT_TABLES_LIB_V2
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#else
+#include <lib/xlat_tables/xlat_tables.h>
+#endif
diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h
new file mode 100644
index 0000000..76cfc0b
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_defs.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_DEFS_H
+#define XLAT_TABLES_DEFS_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+/* Miscellaneous MMU related constants */
+#define NUM_2MB_IN_GB		(U(1) << 9)
+#define NUM_4K_IN_2MB		(U(1) << 9)
+#define NUM_GB_IN_4GB		(U(1) << 2)
+
+#define TWO_MB_SHIFT		U(21)
+#define ONE_GB_SHIFT		U(30)
+#define FOUR_KB_SHIFT		U(12)
+
+#define ONE_GB_INDEX(x)		((x) >> ONE_GB_SHIFT)
+#define TWO_MB_INDEX(x)		((x) >> TWO_MB_SHIFT)
+#define FOUR_KB_INDEX(x)	((x) >> FOUR_KB_SHIFT)
+
+#define PAGE_SIZE_4KB		U(4096)
+#define PAGE_SIZE_16KB		U(16384)
+#define PAGE_SIZE_64KB		U(65536)
+
+#define INVALID_DESC		U(0x0)
+/*
+ * A block descriptor points to a region of memory bigger than the granule size
+ * (e.g. a 2MB region when the granule size is 4KB).
+ */
+#define BLOCK_DESC		U(0x1) /* Table levels 0-2 */
+/* A table descriptor points to the next level of translation table. */
+#define TABLE_DESC		U(0x3) /* Table levels 0-2 */
+/*
+ * A page descriptor points to a page, i.e. a memory region whose size is the
+ * translation granule size (e.g. 4KB).
+ */
+#define PAGE_DESC		U(0x3) /* Table level 3 */
+
+#define DESC_MASK		U(0x3)
+
+#define FIRST_LEVEL_DESC_N	ONE_GB_SHIFT
+#define SECOND_LEVEL_DESC_N	TWO_MB_SHIFT
+#define THIRD_LEVEL_DESC_N	FOUR_KB_SHIFT
+
+/* XN: Translation regimes that support one VA range (EL2 and EL3). */
+#define XN			(ULL(1) << 2)
+/* UXN, PXN: Translation regimes that support two VA ranges (EL1&0). */
+#define UXN			(ULL(1) << 2)
+#define PXN			(ULL(1) << 1)
+#define CONT_HINT		(ULL(1) << 0)
+#define UPPER_ATTRS(x)		(((x) & ULL(0x7)) << 52)
+
+#define NON_GLOBAL		(U(1) << 9)
+#define ACCESS_FLAG		(U(1) << 8)
+#define NSH			(U(0x0) << 6)
+#define OSH			(U(0x2) << 6)
+#define ISH			(U(0x3) << 6)
+
+#ifdef __aarch64__
+/* Guarded Page bit */
+#define GP			(ULL(1) << 50)
+#endif
+
+#define TABLE_ADDR_MASK		ULL(0x0000FFFFFFFFF000)
+
+/*
+ * The ARMv8-A architecture allows translation granule sizes of 4KB, 16KB or
+ * 64KB. However, only 4KB are supported at the moment.
+ */
+#define PAGE_SIZE_SHIFT		FOUR_KB_SHIFT
+#define PAGE_SIZE		(U(1) << PAGE_SIZE_SHIFT)
+#define PAGE_SIZE_MASK		(PAGE_SIZE - U(1))
+#define IS_PAGE_ALIGNED(addr)	(((addr) & PAGE_SIZE_MASK) == U(0))
+
+#if (ARM_ARCH_MAJOR == 7) && !ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING
+#define XLAT_ENTRY_SIZE_SHIFT	U(2)	/* Each MMU table entry is 4 bytes */
+#else
+#define XLAT_ENTRY_SIZE_SHIFT	U(3)	/* Each MMU table entry is 8 bytes */
+#endif
+#define XLAT_ENTRY_SIZE		(U(1) << XLAT_ENTRY_SIZE_SHIFT)
+
+#define XLAT_TABLE_SIZE_SHIFT	PAGE_SIZE_SHIFT /* Size of one complete table */
+#define XLAT_TABLE_SIZE		(U(1) << XLAT_TABLE_SIZE_SHIFT)
+
+#define XLAT_TABLE_LEVEL_MAX	U(3)
+
+/* Values for number of entries in each MMU translation table */
+#define XLAT_TABLE_ENTRIES_SHIFT (XLAT_TABLE_SIZE_SHIFT - XLAT_ENTRY_SIZE_SHIFT)
+#define XLAT_TABLE_ENTRIES	(U(1) << XLAT_TABLE_ENTRIES_SHIFT)
+#define XLAT_TABLE_ENTRIES_MASK	(XLAT_TABLE_ENTRIES - U(1))
+
+/* Values to convert a memory address to an index into a translation table */
+#define L3_XLAT_ADDRESS_SHIFT	PAGE_SIZE_SHIFT
+#define L2_XLAT_ADDRESS_SHIFT	(L3_XLAT_ADDRESS_SHIFT + XLAT_TABLE_ENTRIES_SHIFT)
+#define L1_XLAT_ADDRESS_SHIFT	(L2_XLAT_ADDRESS_SHIFT + XLAT_TABLE_ENTRIES_SHIFT)
+#define L0_XLAT_ADDRESS_SHIFT	(L1_XLAT_ADDRESS_SHIFT + XLAT_TABLE_ENTRIES_SHIFT)
+#define XLAT_ADDR_SHIFT(level)	(PAGE_SIZE_SHIFT + \
+		  ((XLAT_TABLE_LEVEL_MAX - (level)) * XLAT_TABLE_ENTRIES_SHIFT))
+
+#define XLAT_BLOCK_SIZE(level)	(UL(1) << XLAT_ADDR_SHIFT(level))
+/* Mask to get the bits used to index inside a block of a certain level */
+#define XLAT_BLOCK_MASK(level)	(XLAT_BLOCK_SIZE(level) - UL(1))
+/* Mask to get the address bits common to a block of a certain table level*/
+#define XLAT_ADDR_MASK(level)	(~XLAT_BLOCK_MASK(level))
+/*
+ * Extract from the given virtual address the index into the given lookup level.
+ * This macro assumes the system is using the 4KB translation granule.
+ */
+#define XLAT_TABLE_IDX(virtual_addr, level)	\
+	(((virtual_addr) >> XLAT_ADDR_SHIFT(level)) & ULL(0x1FF))
+
+/*
+ * The ARMv8 translation table descriptor format defines AP[2:1] as the Access
+ * Permissions bits, and does not define an AP[0] bit.
+ *
+ * AP[1] is valid only for a stage 1 translation that supports two VA ranges
+ * (i.e. in the ARMv8A.0 architecture, that is the S-EL1&0 regime). It is RES1
+ * when stage 1 translations can only support one VA range.
+ */
+#define AP2_SHIFT			U(0x7)
+#define AP2_RO				ULL(0x1)
+#define AP2_RW				ULL(0x0)
+
+#define AP1_SHIFT			U(0x6)
+#define AP1_ACCESS_UNPRIVILEGED		ULL(0x1)
+#define AP1_NO_ACCESS_UNPRIVILEGED	ULL(0x0)
+#define AP1_RES1			ULL(0x1)
+
+/*
+ * The following definitions must all be passed to the LOWER_ATTRS() macro to
+ * get the right bitmask.
+ */
+#define AP_RO				(AP2_RO << 5)
+#define AP_RW				(AP2_RW << 5)
+#define AP_ACCESS_UNPRIVILEGED		(AP1_ACCESS_UNPRIVILEGED    << 4)
+#define AP_NO_ACCESS_UNPRIVILEGED	(AP1_NO_ACCESS_UNPRIVILEGED << 4)
+#define AP_ONE_VA_RANGE_RES1		(AP1_RES1 << 4)
+#define NS				(U(0x1) << 3)
+#define ATTR_NON_CACHEABLE_INDEX	ULL(0x2)
+#define ATTR_DEVICE_INDEX		ULL(0x1)
+#define ATTR_IWBWA_OWBWA_NTR_INDEX	ULL(0x0)
+#define LOWER_ATTRS(x)			(((x) & U(0xfff)) << 2)
+
+/* Normal Memory, Outer Write-Through non-transient, Inner Non-cacheable */
+#define ATTR_NON_CACHEABLE		MAKE_MAIR_NORMAL_MEMORY(MAIR_NORM_NC, MAIR_NORM_NC)
+/* Device-nGnRE */
+#define ATTR_DEVICE			MAIR_DEV_nGnRE
+/* Normal Memory, Outer Write-Back non-transient, Inner Write-Back non-transient */
+#define ATTR_IWBWA_OWBWA_NTR		MAKE_MAIR_NORMAL_MEMORY(MAIR_NORM_WB_NTR_RWA, MAIR_NORM_WB_NTR_RWA)
+#define MAIR_ATTR_SET(attr, index)	((attr) << ((index) << 3))
+#define ATTR_INDEX_MASK			U(0x3)
+#define ATTR_INDEX_GET(attr)		(((attr) >> 2) & ATTR_INDEX_MASK)
+
+/*
+ * Shift values for the attributes fields in a block or page descriptor.
+ * See section D4.3.3 in the ARMv8-A ARM (issue B.a).
+ */
+
+/* Memory attributes index field, AttrIndx[2:0]. */
+#define ATTR_INDEX_SHIFT		2
+/* Non-secure bit, NS. */
+#define NS_SHIFT			5
+/* Shareability field, SH[1:0] */
+#define SHAREABILITY_SHIFT		8
+/* The Access Flag, AF. */
+#define ACCESS_FLAG_SHIFT		10
+/* The not global bit, nG. */
+#define NOT_GLOBAL_SHIFT		11
+/* Contiguous hint bit. */
+#define CONT_HINT_SHIFT			52
+/* Execute-never bits, XN. */
+#define PXN_SHIFT			53
+#define XN_SHIFT			54
+#define UXN_SHIFT			XN_SHIFT
+
+#endif /* XLAT_TABLES_DEFS_H */
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
new file mode 100644
index 0000000..0e09998
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_V2_H
+#define XLAT_TABLES_V2_H
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2_helpers.h>
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+/*
+ * Default granularity size for an mmap_region_t.
+ * Useful when no specific granularity is required.
+ *
+ * By default, choose the biggest possible block size allowed by the
+ * architectural state and granule size in order to minimize the number of page
+ * tables required for the mapping.
+ */
+#define REGION_DEFAULT_GRANULARITY	XLAT_BLOCK_SIZE(MIN_LVL_BLOCK_DESC)
+
+/* Helper macro to define an mmap_region_t. */
+#define MAP_REGION(_pa, _va, _sz, _attr)	\
+	MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, REGION_DEFAULT_GRANULARITY)
+
+/* Helper macro to define an mmap_region_t with an identity mapping. */
+#define MAP_REGION_FLAT(_adr, _sz, _attr)			\
+	MAP_REGION(_adr, _adr, _sz, _attr)
+
+/*
+ * Helper macro to define entries for mmap_region_t. It allows to define 'pa'
+ * and sets 'va' to 0 for each region. To be used with mmap_add_alloc_va().
+ */
+#define MAP_REGION_ALLOC_VA(pa, sz, attr)	MAP_REGION(pa, 0, sz, attr)
+
+/*
+ * Helper macro to define an mmap_region_t to map with the desired granularity
+ * of translation tables.
+ *
+ * The granularity value passed to this macro must be a valid block or page
+ * size. When using a 4KB translation granule, this might be 4KB, 2MB or 1GB.
+ * Passing REGION_DEFAULT_GRANULARITY is also allowed and means that the library
+ * is free to choose the granularity for this region. In this case, it is
+ * equivalent to the MAP_REGION() macro.
+ */
+#define MAP_REGION2(_pa, _va, _sz, _attr, _gr)			\
+	MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr)
+
+/*
+ * Shifts and masks to access fields of an mmap attribute
+ */
+#define MT_TYPE_MASK		U(0x7)
+#define MT_TYPE(_attr)		((_attr) & MT_TYPE_MASK)
+/* Access permissions (RO/RW) */
+#define MT_PERM_SHIFT		U(3)
+/* Security state (SECURE/NS) */
+#define MT_SEC_SHIFT		U(4)
+/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */
+#define MT_EXECUTE_SHIFT	U(5)
+/* In the EL1&0 translation regime, User (EL0) or Privileged (EL1). */
+#define MT_USER_SHIFT		U(6)
+/* All other bits are reserved */
+
+/*
+ * Memory mapping attributes
+ */
+
+/*
+ * Memory types supported.
+ * These are organised so that, going down the list, the memory types are
+ * getting weaker; conversely going up the list the memory types are getting
+ * stronger.
+ */
+#define MT_DEVICE		U(0)
+#define MT_NON_CACHEABLE	U(1)
+#define MT_MEMORY		U(2)
+/* Values up to 7 are reserved to add new memory types in the future */
+
+#define MT_RO			(U(0) << MT_PERM_SHIFT)
+#define MT_RW			(U(1) << MT_PERM_SHIFT)
+
+#define MT_SECURE		(U(0) << MT_SEC_SHIFT)
+#define MT_NS			(U(1) << MT_SEC_SHIFT)
+
+/*
+ * Access permissions for instruction execution are only relevant for normal
+ * read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored (and potentially
+ * overridden) otherwise:
+ *  - Device memory is always marked as execute-never.
+ *  - Read-write normal memory is always marked as execute-never.
+ */
+#define MT_EXECUTE		(U(0) << MT_EXECUTE_SHIFT)
+#define MT_EXECUTE_NEVER	(U(1) << MT_EXECUTE_SHIFT)
+
+/*
+ * When mapping a region at EL0 or EL1, this attribute will be used to determine
+ * if a User mapping (EL0) will be created or a Privileged mapping (EL1).
+ */
+#define MT_USER			(U(1) << MT_USER_SHIFT)
+#define MT_PRIVILEGED		(U(0) << MT_USER_SHIFT)
+
+/* Compound attributes for most common usages */
+#define MT_CODE			(MT_MEMORY | MT_RO | MT_EXECUTE)
+#define MT_RO_DATA		(MT_MEMORY | MT_RO | MT_EXECUTE_NEVER)
+#define MT_RW_DATA		(MT_MEMORY | MT_RW | MT_EXECUTE_NEVER)
+
+/*
+ * Structure for specifying a single region of memory.
+ */
+typedef struct mmap_region {
+	unsigned long long	base_pa;
+	uintptr_t		base_va;
+	size_t			size;
+	unsigned int		attr;
+	/* Desired granularity. See the MAP_REGION2() macro for more details. */
+	size_t			granularity;
+} mmap_region_t;
+
+/*
+ * Translation regimes supported by this library. EL_REGIME_INVALID tells the
+ * library to detect it at runtime.
+ */
+#define EL1_EL0_REGIME		1
+#define EL2_REGIME		2
+#define EL3_REGIME		3
+#define EL_REGIME_INVALID	-1
+
+/*
+ * Declare the translation context type.
+ * Its definition is private.
+ */
+typedef struct xlat_ctx xlat_ctx_t;
+
+/*
+ * Statically allocate a translation context and associated structures. Also
+ * initialize them.
+ *
+ * _ctx_name:
+ *   Prefix for the translation context variable.
+ *   E.g. If _ctx_name is 'foo', the variable will be called 'foo_xlat_ctx'.
+ *   Useful to distinguish multiple contexts from one another.
+ *
+ * _mmap_count:
+ *   Number of mmap_region_t to allocate.
+ *   Would typically be MAX_MMAP_REGIONS for the translation context describing
+ *   the BL image currently executing.
+ *
+ * _xlat_tables_count:
+ *   Number of sub-translation tables to allocate.
+ *   Would typically be MAX_XLAT_TABLES for the translation context describing
+ *   the BL image currently executing.
+ *   Note that this is only for sub-tables ; at the initial lookup level, there
+ *   is always a single table.
+ *
+ * _virt_addr_space_size, _phy_addr_space_size:
+ *   Size (in bytes) of the virtual (resp. physical) address space.
+ *   Would typically be PLAT_VIRT_ADDR_SPACE_SIZE
+ *   (resp. PLAT_PHY_ADDR_SPACE_SIZE) for the translation context describing the
+ *   BL image currently executing.
+ */
+#define REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \
+			_virt_addr_space_size, _phy_addr_space_size)	\
+	REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, (_mmap_count),	\
+					 (_xlat_tables_count),		\
+					 (_virt_addr_space_size),	\
+					 (_phy_addr_space_size),	\
+					 EL_REGIME_INVALID, "xlat_table")
+
+/*
+ * Same as REGISTER_XLAT_CONTEXT plus the additional parameters:
+ *
+ * _xlat_regime:
+ *   Specify the translation regime managed by this xlat_ctx_t instance. The
+ *   values are the one from the EL*_REGIME definitions.
+ *
+ * _section_name:
+ *   Specify the name of the section where the translation tables have to be
+ *   placed by the linker.
+ */
+#define REGISTER_XLAT_CONTEXT2(_ctx_name, _mmap_count, _xlat_tables_count, \
+			_virt_addr_space_size, _phy_addr_space_size,	\
+			_xlat_regime, _section_name)			\
+	REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, (_mmap_count),	\
+					 (_xlat_tables_count),		\
+					 (_virt_addr_space_size),	\
+					 (_phy_addr_space_size),	\
+					 (_xlat_regime), (_section_name))
+
+/******************************************************************************
+ * Generic translation table APIs.
+ * Each API comes in 2 variants:
+ * - one that acts on the current translation context for this BL image
+ * - another that acts on the given translation context instead. This variant
+ *   is named after the 1st version, with an additional '_ctx' suffix.
+ *****************************************************************************/
+
+/*
+ * Initialize translation tables from the current list of mmap regions. Calling
+ * this function marks the transition point after which static regions can no
+ * longer be added.
+ */
+void init_xlat_tables(void);
+void init_xlat_tables_ctx(xlat_ctx_t *ctx);
+
+/*
+ * Fill all fields of a dynamic translation tables context. It must be done
+ * either statically with REGISTER_XLAT_CONTEXT() or at runtime with this
+ * function.
+ */
+void xlat_setup_dynamic_ctx(xlat_ctx_t *ctx, unsigned long long pa_max,
+			    uintptr_t va_max, struct mmap_region *mmap,
+			    unsigned int mmap_num, uint64_t **tables,
+			    unsigned int tables_num, uint64_t *base_table,
+			    int xlat_regime, int *mapped_regions);
+
+/*
+ * Add a static region with defined base PA and base VA. This function can only
+ * be used before initializing the translation tables. The region cannot be
+ * removed afterwards.
+ */
+void mmap_add_region(unsigned long long base_pa, uintptr_t base_va,
+		     size_t size, unsigned int attr);
+void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm);
+
+/*
+ * Add an array of static regions with defined base PA and base VA. This
+ * function can only be used before initializing the translation tables. The
+ * regions cannot be removed afterwards.
+ */
+void mmap_add(const mmap_region_t *mm);
+void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm);
+
+/*
+ * Add a region with defined base PA. Returns base VA calculated using the
+ * highest existing region in the mmap array even if it fails to allocate the
+ * region.
+ */
+void mmap_add_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va,
+			      size_t size, unsigned int attr);
+void mmap_add_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm);
+
+/*
+ * Add an array of static regions with defined base PA, and fill the base VA
+ * field on the array of structs. This function can only be used before
+ * initializing the translation tables. The regions cannot be removed afterwards.
+ */
+void mmap_add_alloc_va(mmap_region_t *mm);
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+/*
+ * Add a dynamic region with defined base PA and base VA. This type of region
+ * can be added and removed even after the translation tables are initialized.
+ *
+ * Returns:
+ *        0: Success.
+ *   EINVAL: Invalid values were used as arguments.
+ *   ERANGE: Memory limits were surpassed.
+ *   ENOMEM: Not enough space in the mmap array or not enough free xlat tables.
+ *    EPERM: It overlaps another region in an invalid way.
+ */
+int mmap_add_dynamic_region(unsigned long long base_pa, uintptr_t base_va,
+			    size_t size, unsigned int attr);
+int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm);
+
+/*
+ * Add a dynamic region with defined base PA. Returns base VA calculated using
+ * the highest existing region in the mmap array even if it fails to allocate
+ * the region.
+ *
+ * mmap_add_dynamic_region_alloc_va() returns the allocated VA in 'base_va'.
+ * mmap_add_dynamic_region_alloc_va_ctx() returns it in 'mm->base_va'.
+ *
+ * It returns the same error values as mmap_add_dynamic_region().
+ */
+int mmap_add_dynamic_region_alloc_va(unsigned long long base_pa,
+				     uintptr_t *base_va,
+				     size_t size, unsigned int attr);
+int mmap_add_dynamic_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm);
+
+/*
+ * Remove a region with the specified base VA and size. Only dynamic regions can
+ * be removed, and they can be removed even if the translation tables are
+ * initialized.
+ *
+ * Returns:
+ *        0: Success.
+ *   EINVAL: The specified region wasn't found.
+ *    EPERM: Trying to remove a static region.
+ */
+int mmap_remove_dynamic_region(uintptr_t base_va, size_t size);
+int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx,
+				uintptr_t base_va,
+				size_t size);
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+/*
+ * Change the memory attributes of the memory region starting from a given
+ * virtual address in a set of translation tables.
+ *
+ * This function can only be used after the translation tables have been
+ * initialized.
+ *
+ * The base address of the memory region must be aligned on a page boundary.
+ * The size of this memory region must be a multiple of a page size.
+ * The memory region must be already mapped by the given translation tables
+ * and it must be mapped at the granularity of a page.
+ *
+ * Return 0 on success, a negative value on error.
+ *
+ * In case of error, the memory attributes remain unchanged and this function
+ * has no effect.
+ *
+ * ctx
+ *   Translation context to work on.
+ * base_va:
+ *   Virtual address of the 1st page to change the attributes of.
+ * size:
+ *   Size in bytes of the memory region.
+ * attr:
+ *   New attributes of the page tables. The attributes that can be changed are
+ *   data access (MT_RO/MT_RW), instruction access (MT_EXECUTE_NEVER/MT_EXECUTE)
+ *   and user/privileged access (MT_USER/MT_PRIVILEGED) in the case of contexts
+ *   that are used in the EL1&0 translation regime. Also, note that this
+ *   function doesn't allow to remap a region as RW and executable, or to remap
+ *   device memory as executable.
+ *
+ * NOTE: The caller of this function must be able to write to the translation
+ * tables, i.e. the memory where they are stored must be mapped with read-write
+ * access permissions. This function assumes it is the case. If this is not
+ * the case then this function might trigger a data abort exception.
+ *
+ * NOTE2: The caller is responsible for making sure that the targeted
+ * translation tables are not modified by any other code while this function is
+ * executing.
+ */
+int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				   size_t size, uint32_t attr);
+int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr);
+
+/*
+ * Query the memory attributes of a memory page in a set of translation tables.
+ *
+ * Return 0 on success, a negative error code on error.
+ * On success, the attributes are stored into *attr.
+ *
+ * ctx
+ *   Translation context to work on.
+ * base_va
+ *   Virtual address of the page to get the attributes of.
+ *   There are no alignment restrictions on this address. The attributes of the
+ *   memory page it lies within are returned.
+ * attr
+ *   Output parameter where to store the attributes of the targeted memory page.
+ */
+int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				uint32_t *attr);
+int xlat_get_mem_attributes(uintptr_t base_va, uint32_t *attr);
+
+#endif /*__ASSEMBLER__*/
+#endif /* XLAT_TABLES_V2_H */
diff --git a/include/lib/xlat_tables/xlat_tables_v2_helpers.h b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
new file mode 100644
index 0000000..b17b71a
--- /dev/null
+++ b/include/lib/xlat_tables/xlat_tables_v2_helpers.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * This header file contains internal definitions that are not supposed to be
+ * used outside of this library code.
+ */
+
+#ifndef XLAT_TABLES_V2_HELPERS_H
+#define XLAT_TABLES_V2_HELPERS_H
+
+#ifndef XLAT_TABLES_V2_H
+#error "Do not include this header file directly. Include xlat_tables_v2.h instead."
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/* Forward declaration */
+struct mmap_region;
+
+/*
+ * Helper macro to define an mmap_region_t.  This macro allows to specify all
+ * the fields of the structure but its parameter list is not guaranteed to
+ * remain stable as we add members to mmap_region_t.
+ */
+#define MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr)		\
+	{							\
+		.base_pa = (_pa),				\
+		.base_va = (_va),				\
+		.size = (_sz),					\
+		.attr = (_attr),				\
+		.granularity = (_gr),				\
+	}
+
+/* Struct that holds all information about the translation tables. */
+struct xlat_ctx {
+	/*
+	 * Max allowed Virtual and Physical Addresses.
+	 */
+	unsigned long long pa_max_address;
+	uintptr_t va_max_address;
+
+	/*
+	 * Array of all memory regions stored in order of ascending end address
+	 * and ascending size to simplify the code that allows overlapping
+	 * regions. The list is terminated by the first entry with size == 0.
+	 * The max size of the list is stored in `mmap_num`. `mmap` points to an
+	 * array of mmap_num + 1 elements, so that there is space for the final
+	 * null entry.
+	 */
+	struct mmap_region *mmap;
+	int mmap_num;
+
+	/*
+	 * Array of finer-grain translation tables.
+	 * For example, if the initial lookup level is 1 then this array would
+	 * contain both level-2 and level-3 entries.
+	 */
+	uint64_t (*tables)[XLAT_TABLE_ENTRIES];
+	int tables_num;
+	/*
+	 * Keep track of how many regions are mapped in each table. The base
+	 * table can't be unmapped so it isn't needed to keep track of it.
+	 */
+#if PLAT_XLAT_TABLES_DYNAMIC
+	int *tables_mapped_regions;
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+	int next_table;
+
+	/*
+	 * Base translation table. It doesn't need to have the same amount of
+	 * entries as the ones used for other levels.
+	 */
+	uint64_t *base_table;
+	unsigned int base_table_entries;
+
+	/*
+	* Max Physical and Virtual addresses currently in use by the
+	* translation tables. These might get updated as we map/unmap memory
+	* regions but they will never go beyond pa/va_max_address.
+	*/
+	unsigned long long max_pa;
+	uintptr_t max_va;
+
+	/* Level of the base translation table. */
+	unsigned int base_level;
+
+	/* Set to true when the translation tables are initialized. */
+	bool initialized;
+
+	/*
+	 * Translation regime managed by this xlat_ctx_t. It should be one of
+	 * the EL*_REGIME defines.
+	 */
+	int xlat_regime;
+};
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+#define XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count)		\
+	static int _ctx_name##_mapped_regions[_xlat_tables_count];
+
+#define XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name)				\
+	.tables_mapped_regions = _ctx_name##_mapped_regions,
+#else
+#define XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count)		\
+	/* do nothing */
+
+#define XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name)				\
+	/* do nothing */
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+#define REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, _mmap_count,		\
+			_xlat_tables_count, _virt_addr_space_size,	\
+			_phy_addr_space_size, _xlat_regime, _section_name)\
+	CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(_phy_addr_space_size),	\
+		assert_invalid_physical_addr_space_sizefor_##_ctx_name);\
+									\
+	static mmap_region_t _ctx_name##_mmap[_mmap_count + 1];		\
+									\
+	static uint64_t _ctx_name##_xlat_tables[_xlat_tables_count]	\
+		[XLAT_TABLE_ENTRIES]					\
+		__aligned(XLAT_TABLE_SIZE) __section(_section_name);	\
+									\
+	static uint64_t _ctx_name##_base_xlat_table			\
+		[GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)]	\
+		__aligned(GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size)\
+			* sizeof(uint64_t));				\
+									\
+	XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count)		\
+									\
+	static xlat_ctx_t _ctx_name##_xlat_ctx = {			\
+		.va_max_address = (_virt_addr_space_size) - 1UL,	\
+		.pa_max_address = (_phy_addr_space_size) - 1ULL,	\
+		.mmap = _ctx_name##_mmap,				\
+		.mmap_num = (_mmap_count),				\
+		.base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size),\
+		.base_table = _ctx_name##_base_xlat_table,		\
+		.base_table_entries =					\
+			GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size),\
+		.tables = _ctx_name##_xlat_tables,			\
+		.tables_num = _xlat_tables_count,			\
+		 XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name)			\
+		.xlat_regime = (_xlat_regime),				\
+		.max_pa = 0U,						\
+		.max_va = 0U,						\
+		.next_table = 0,					\
+		.initialized = false,					\
+	}
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* XLAT_TABLES_V2_HELPERS_H */
diff --git a/include/lib/zlib/tf_gunzip.h b/include/lib/zlib/tf_gunzip.h
new file mode 100644
index 0000000..741ba50
--- /dev/null
+++ b/include/lib/zlib/tf_gunzip.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TF_GUNZIP_H
+#define TF_GUNZIP_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+int gunzip(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf,
+	   size_t out_len, uintptr_t work_buf, size_t work_len);
+
+#endif /* TF_GUNZIP_H */
diff --git a/include/plat/arm/board/common/board_css_def.h b/include/plat/arm/board/common/board_css_def.h
new file mode 100644
index 0000000..4637b67
--- /dev/null
+++ b/include/plat/arm/board/common/board_css_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_CSS_DEF_H
+#define BOARD_CSS_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * Definitions common to all ARM CSS-based development platforms
+ */
+
+/* Platform ID address */
+#define BOARD_CSS_PLAT_ID_REG_ADDR		0x7ffe00e0
+
+/* Platform ID related accessors */
+#define BOARD_CSS_PLAT_ID_REG_ID_MASK		0x0f
+#define BOARD_CSS_PLAT_ID_REG_ID_SHIFT		0x0
+#define BOARD_CSS_PLAT_ID_REG_VERSION_MASK	0xf00
+#define BOARD_CSS_PLAT_ID_REG_VERSION_SHIFT	0x8
+#define BOARD_CSS_PLAT_TYPE_RTL			0x00
+#define BOARD_CSS_PLAT_TYPE_FPGA		0x01
+#define BOARD_CSS_PLAT_TYPE_EMULATOR		0x02
+#define BOARD_CSS_PLAT_TYPE_FVP			0x03
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+
+#define BOARD_CSS_GET_PLAT_TYPE(addr)					\
+	((mmio_read_32(addr) & BOARD_CSS_PLAT_ID_REG_ID_MASK)		\
+	>> BOARD_CSS_PLAT_ID_REG_ID_SHIFT)
+
+#endif /* __ASSEMBLER__ */
+
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FIP_BASE		V2M_FLASH0_BASE
+#define PLAT_ARM_FIP_MAX_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*
+ * Required platform porting definitions common to all ARM CSS-based
+ * development platforms
+ */
+#define PLAT_ARM_DRAM2_BASE			ULL(0x880000000)
+#define PLAT_ARM_DRAM2_SIZE			ULL(0x180000000)
+
+/* UART related constants */
+#define PLAT_ARM_BOOT_UART_BASE			SOC_CSS_UART0_BASE
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ		SOC_CSS_UART0_CLK_IN_HZ
+
+#define PLAT_ARM_RUN_UART_BASE		SOC_CSS_UART1_BASE
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ	SOC_CSS_UART1_CLK_IN_HZ
+
+#define PLAT_ARM_SP_MIN_RUN_UART_BASE		SOC_CSS_UART1_BASE
+#define PLAT_ARM_SP_MIN_RUN_UART_CLK_IN_HZ	SOC_CSS_UART1_CLK_IN_HZ
+
+#define PLAT_ARM_CRASH_UART_BASE		PLAT_ARM_RUN_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ		PLAT_ARM_RUN_UART_CLK_IN_HZ
+
+#define PLAT_ARM_TSP_UART_BASE			V2M_IOFPGA_UART0_BASE
+#define PLAT_ARM_TSP_UART_CLK_IN_HZ		V2M_IOFPGA_UART0_CLK_IN_HZ
+
+#endif /* BOARD_CSS_DEF_H */
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
new file mode 100644
index 0000000..6a6979c
--- /dev/null
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef V2M_DEF_H
+#define V2M_DEF_H
+
+#include <lib/utils_def.h>
+
+/* V2M motherboard system registers & offsets */
+#define V2M_SYSREGS_BASE		UL(0x1c010000)
+#define V2M_SYS_ID			UL(0x0)
+#define V2M_SYS_SWITCH			UL(0x4)
+#define V2M_SYS_LED			UL(0x8)
+#define V2M_SYS_NVFLAGS			UL(0x38)
+#define V2M_SYS_NVFLAGSSET		UL(0x38)
+#define V2M_SYS_NVFLAGSCLR		UL(0x3c)
+#define V2M_SYS_CFGDATA			UL(0xa0)
+#define V2M_SYS_CFGCTRL			UL(0xa4)
+#define V2M_SYS_CFGSTATUS		UL(0xa8)
+
+#define V2M_CFGCTRL_START		BIT_32(31)
+#define V2M_CFGCTRL_RW			BIT_32(30)
+#define V2M_CFGCTRL_FUNC_SHIFT		20
+#define V2M_CFGCTRL_FUNC(fn)		((fn) << V2M_CFGCTRL_FUNC_SHIFT)
+#define V2M_FUNC_CLK_GEN		U(0x01)
+#define V2M_FUNC_TEMP			U(0x04)
+#define V2M_FUNC_DB_RESET		U(0x05)
+#define V2M_FUNC_SCC_CFG		U(0x06)
+#define V2M_FUNC_SHUTDOWN		U(0x08)
+#define V2M_FUNC_REBOOT			U(0x09)
+
+/* NVFLAGS in the V2M motherboard which is preserved after a watchdog reset */
+ #define V2M_SYS_NVFLAGS_ADDR		(V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS)
+
+/*
+ * V2M sysled bit definitions. The values written to this
+ * register are defined in arch.h & runtime_svc.h. Only
+ * used by the primary cpu to diagnose any cold boot issues.
+ *
+ * SYS_LED[0]   - Security state (S=0/NS=1)
+ * SYS_LED[2:1] - Exception Level (EL3-EL0)
+ * SYS_LED[7:3] - Exception Class (Sync/Async & origin)
+ *
+ */
+#define V2M_SYS_LED_SS_SHIFT		0x0
+#define V2M_SYS_LED_EL_SHIFT		0x1
+#define V2M_SYS_LED_EC_SHIFT		0x3
+
+#define V2M_SYS_LED_SS_MASK		U(0x1)
+#define V2M_SYS_LED_EL_MASK		U(0x3)
+#define V2M_SYS_LED_EC_MASK		U(0x1f)
+
+/* V2M sysid register bits */
+#define V2M_SYS_ID_REV_SHIFT		28
+#define V2M_SYS_ID_HBI_SHIFT		16
+#define V2M_SYS_ID_BLD_SHIFT		12
+#define V2M_SYS_ID_ARCH_SHIFT		8
+#define V2M_SYS_ID_FPGA_SHIFT		0
+
+#define V2M_SYS_ID_REV_MASK		U(0xf)
+#define V2M_SYS_ID_HBI_MASK		U(0xfff)
+#define V2M_SYS_ID_BLD_MASK		U(0xf)
+#define V2M_SYS_ID_ARCH_MASK		U(0xf)
+#define V2M_SYS_ID_FPGA_MASK		U(0xff)
+
+#define V2M_SYS_ID_BLD_LENGTH		4
+
+
+/* NOR Flash */
+#define V2M_FLASH0_BASE			UL(0x08000000)
+#define V2M_FLASH0_SIZE			UL(0x04000000)
+#define V2M_FLASH_BLOCK_SIZE		UL(0x00040000)	/* 256 KB */
+
+#define V2M_IOFPGA_BASE			UL(0x1c000000)
+#define V2M_IOFPGA_SIZE			UL(0x03000000)
+
+/* PL011 UART related constants */
+#define V2M_IOFPGA_UART0_BASE		UL(0x1c090000)
+#define V2M_IOFPGA_UART1_BASE		UL(0x1c0a0000)
+#define V2M_IOFPGA_UART2_BASE		UL(0x1c0b0000)
+#define V2M_IOFPGA_UART3_BASE		UL(0x1c0c0000)
+
+#define V2M_IOFPGA_UART0_CLK_IN_HZ	24000000
+#define V2M_IOFPGA_UART1_CLK_IN_HZ	24000000
+#define V2M_IOFPGA_UART2_CLK_IN_HZ	24000000
+#define V2M_IOFPGA_UART3_CLK_IN_HZ	24000000
+
+/* SP804 timer related constants */
+#define V2M_SP804_TIMER0_BASE		UL(0x1C110000)
+#define V2M_SP804_TIMER1_BASE		UL(0x1C120000)
+
+/* SP810 controller */
+#define V2M_SP810_BASE			UL(0x1c020000)
+#define V2M_SP810_CTRL_TIM0_SEL		BIT_32(15)
+#define V2M_SP810_CTRL_TIM1_SEL		BIT_32(17)
+#define V2M_SP810_CTRL_TIM2_SEL		BIT_32(19)
+#define V2M_SP810_CTRL_TIM3_SEL		BIT_32(21)
+
+/*
+ * The flash can be mapped either as read-only or read-write.
+ *
+ * If it is read-write then it should also be mapped as device memory because
+ * NOR flash programming involves sending a fixed, ordered sequence of commands.
+ *
+ * If it is read-only then it should also be mapped as:
+ * - Normal memory, because reading from NOR flash is transparent, it is like
+ *   reading from RAM.
+ * - Non-executable by default. If some parts of the flash need to be executable
+ *   then platform code is responsible for re-mapping the appropriate portion
+ *   of it as executable.
+ */
+#define V2M_MAP_FLASH0_RW		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define V2M_MAP_FLASH0_RO		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_RO_DATA | MT_SECURE)
+
+#define V2M_MAP_IOFPGA			MAP_REGION_FLAT(V2M_IOFPGA_BASE,\
+						V2M_IOFPGA_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+/* Region equivalent to V2M_MAP_IOFPGA suitable for mapping at EL0 */
+#define V2M_MAP_IOFPGA_EL0		MAP_REGION_FLAT(		\
+						V2M_IOFPGA_BASE,	\
+						V2M_IOFPGA_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
+
+
+#endif /* V2M_DEF_H */
diff --git a/include/plat/arm/common/aarch64/arm_macros.S b/include/plat/arm/common/aarch64/arm_macros.S
new file mode 100644
index 0000000..d47e4e0
--- /dev/null
+++ b/include/plat/arm/common/aarch64/arm_macros.S
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_MACROS_S
+#define ARM_MACROS_S
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+	.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200-0x278)\nOffset\t\t\tValue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t 0x"
+prefix:
+	.asciz "0x"
+
+	/* ---------------------------------------------
+	 * The below utility macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL31 on ARM standard platforms.
+	 * Expects: GICD base in x16, GICC base in x17
+	 * Clobbers: x0 - x10, sp
+	 * ---------------------------------------------
+	 */
+	.macro arm_print_gic_regs
+	/* Check for GICv3 system register access */
+	mrs	x7, id_aa64pfr0_el1
+	ubfx	x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x7, #1
+	b.ne	print_gicv2
+
+	/* Check for SRE enable */
+	mrs	x8, ICC_SRE_EL3
+	tst	x8, #ICC_SRE_SRE_BIT
+	b.eq	print_gicv2
+
+	/* Load the icc reg list to x6 */
+	adr	x6, icc_regs
+	/* Load the icc regs to gp regs used by str_in_crash_buf_print */
+	mrs	x8, ICC_HPPIR0_EL1
+	mrs	x9, ICC_HPPIR1_EL1
+	mrs	x10, ICC_CTLR_EL3
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	b	print_gic_common
+
+print_gicv2:
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+print_gic_common:
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+
+	/* Print "0x" */
+	adr	x4, prefix
+	bl	asm_print_str
+
+	/* Print offset */
+	sub	x4, x7, x16
+	mov	x5, #12
+	bl	asm_print_hex_bits
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+#endif /* ARM_MACROS_S */
diff --git a/include/plat/arm/common/aarch64/cci_macros.S b/include/plat/arm/common/aarch64/cci_macros.S
new file mode 100644
index 0000000..07f7cd3
--- /dev/null
+++ b/include/plat/arm/common/aarch64/cci_macros.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CCI_MACROS_S
+#define CCI_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <platform_def.h>
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ------------------------------------------------
+	 * The below required platform porting macro prints
+	 * out relevant interconnect registers whenever an
+	 * unhandled exception is taken in BL31.
+	 * Clobbers: x0 - x9, sp
+	 * ------------------------------------------------
+	 */
+	.macro print_cci_regs
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_ARM_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_ARM_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
+
+#endif /* CCI_MACROS_S */
diff --git a/include/plat/arm/common/arm_config.h b/include/plat/arm/common/arm_config.h
new file mode 100644
index 0000000..c2b28df
--- /dev/null
+++ b/include/plat/arm/common/arm_config.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_CONFIG_H
+#define ARM_CONFIG_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* Whether Base memory map is in use */
+#define ARM_CONFIG_BASE_MMAP		BIT(1)
+
+/* Whether TZC should be configured */
+#define ARM_CONFIG_HAS_TZC		BIT(2)
+
+/* FVP model has shifted affinity */
+#define ARM_CONFIG_FVP_SHIFTED_AFF	BIT(3)
+
+/* FVP model has SMMUv3 affinity */
+#define ARM_CONFIG_FVP_HAS_SMMUV3	BIT(4)
+
+/* FVP model has CCI (400 or 500/550) devices */
+#define ARM_CONFIG_FVP_HAS_CCI400	BIT(5)
+#define ARM_CONFIG_FVP_HAS_CCI5XX	BIT(6)
+
+typedef struct arm_config {
+	unsigned long flags;
+} arm_config_t;
+
+
+/* If used, arm_config must be defined and populated in the platform port */
+extern arm_config_t arm_config;
+
+static inline const arm_config_t *get_arm_config(void)
+{
+	return &arm_config;
+}
+
+
+#endif /* ARM_CONFIG_H */
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
new file mode 100644
index 0000000..53bd13f
--- /dev/null
+++ b/include/plat/arm/common/arm_def.h
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_DEF_H
+#define ARM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/common_def.h>
+
+/******************************************************************************
+ * Definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define ARM_BL31_PLAT_PARAM_VAL		ULL(0x0f1e2d3c4b5a6978)
+
+#define ARM_SYSTEM_COUNT		1
+
+#define ARM_CACHE_WRITEBACK_SHIFT	6
+
+/*
+ * Macros mapping the MPIDR Affinity levels to ARM Platform Power levels. The
+ * power levels have a 1:1 mapping with the MPIDR affinity levels.
+ */
+#define ARM_PWR_LVL0		MPIDR_AFFLVL0
+#define ARM_PWR_LVL1		MPIDR_AFFLVL1
+#define ARM_PWR_LVL2		MPIDR_AFFLVL2
+#define ARM_PWR_LVL3		MPIDR_AFFLVL3
+
+/*
+ *  Macros for local power states in ARM platforms encoded by State-ID field
+ *  within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define ARM_LOCAL_STATE_RUN	U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define ARM_LOCAL_STATE_RET	U(1)
+/* Local power state for OFF/power-down. Valid for CPU and cluster power
+   domains */
+#define ARM_LOCAL_STATE_OFF	U(2)
+
+/* Memory location options for TSP */
+#define ARM_TRUSTED_SRAM_ID		0
+#define ARM_TRUSTED_DRAM_ID		1
+#define ARM_DRAM_ID			2
+
+/* The first 4KB of Trusted SRAM are used as shared memory */
+#define ARM_TRUSTED_SRAM_BASE		UL(0x04000000)
+#define ARM_SHARED_RAM_BASE		ARM_TRUSTED_SRAM_BASE
+#define ARM_SHARED_RAM_SIZE		UL(0x00001000)	/* 4 KB */
+
+/* The remaining Trusted SRAM is used to load the BL images */
+#define ARM_BL_RAM_BASE			(ARM_SHARED_RAM_BASE +	\
+					 ARM_SHARED_RAM_SIZE)
+#define ARM_BL_RAM_SIZE			(PLAT_ARM_TRUSTED_SRAM_SIZE -	\
+					 ARM_SHARED_RAM_SIZE)
+
+/*
+ * The top 16MB of DRAM1 is configured as secure access only using the TZC
+ *   - SCP TZC DRAM: If present, DRAM reserved for SCP use
+ *   - AP TZC DRAM: The remaining TZC secured DRAM reserved for AP use
+ */
+#define ARM_TZC_DRAM1_SIZE		UL(0x01000000)
+
+#define ARM_SCP_TZC_DRAM1_BASE		(ARM_DRAM1_BASE +		\
+					 ARM_DRAM1_SIZE -		\
+					 ARM_SCP_TZC_DRAM1_SIZE)
+#define ARM_SCP_TZC_DRAM1_SIZE		PLAT_ARM_SCP_TZC_DRAM1_SIZE
+#define ARM_SCP_TZC_DRAM1_END		(ARM_SCP_TZC_DRAM1_BASE +	\
+					 ARM_SCP_TZC_DRAM1_SIZE - 1)
+
+/*
+ * Define a 2MB region within the TZC secured DRAM for use by EL3 runtime
+ * firmware. This region is meant to be NOLOAD and will not be zero
+ * initialized. Data sections with the attribute `arm_el3_tzc_dram` will be
+ * placed here.
+ */
+#define ARM_EL3_TZC_DRAM1_BASE		(ARM_SCP_TZC_DRAM1_BASE - ARM_EL3_TZC_DRAM1_SIZE)
+#define ARM_EL3_TZC_DRAM1_SIZE		UL(0x00200000) /* 2 MB */
+#define ARM_EL3_TZC_DRAM1_END		(ARM_EL3_TZC_DRAM1_BASE +	\
+					ARM_EL3_TZC_DRAM1_SIZE - 1)
+
+#define ARM_AP_TZC_DRAM1_BASE		(ARM_DRAM1_BASE +		\
+					 ARM_DRAM1_SIZE -		\
+					 ARM_TZC_DRAM1_SIZE)
+#define ARM_AP_TZC_DRAM1_SIZE		(ARM_TZC_DRAM1_SIZE -		\
+					 (ARM_SCP_TZC_DRAM1_SIZE +	\
+					 ARM_EL3_TZC_DRAM1_SIZE))
+#define ARM_AP_TZC_DRAM1_END		(ARM_AP_TZC_DRAM1_BASE +	\
+					 ARM_AP_TZC_DRAM1_SIZE - 1)
+
+/* Define the Access permissions for Secure peripherals to NS_DRAM */
+#if ARM_CRYPTOCELL_INTEG
+/*
+ * Allow Secure peripheral to read NS DRAM when integrated with CryptoCell.
+ * This is required by CryptoCell to authenticate BL33 which is loaded
+ * into the Non Secure DDR.
+ */
+#define ARM_TZC_NS_DRAM_S_ACCESS	TZC_REGION_S_RD
+#else
+#define ARM_TZC_NS_DRAM_S_ACCESS	TZC_REGION_S_NONE
+#endif
+
+#ifdef SPD_opteed
+/*
+ * BL2 needs to map 4MB at the end of TZC_DRAM1 in order to
+ * load/authenticate the trusted os extra image. The first 512KB of
+ * TZC_DRAM1 are reserved for trusted os (OPTEE). The extra image loading
+ * for OPTEE is paged image which only include the paging part using
+ * virtual memory but without "init" data. OPTEE will copy the "init" data
+ * (from pager image) to the first 512KB of TZC_DRAM, and then copy the
+ * extra image behind the "init" data.
+ */
+#define ARM_OPTEE_PAGEABLE_LOAD_BASE	(ARM_AP_TZC_DRAM1_BASE + \
+					 ARM_AP_TZC_DRAM1_SIZE - \
+					 ARM_OPTEE_PAGEABLE_LOAD_SIZE)
+#define ARM_OPTEE_PAGEABLE_LOAD_SIZE	UL(0x400000)
+#define ARM_OPTEE_PAGEABLE_LOAD_MEM	MAP_REGION_FLAT(		\
+					ARM_OPTEE_PAGEABLE_LOAD_BASE,	\
+					ARM_OPTEE_PAGEABLE_LOAD_SIZE,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * Map the memory for the OP-TEE core (also known as OP-TEE pager when paging
+ * support is enabled).
+ */
+#define ARM_MAP_OPTEE_CORE_MEM		MAP_REGION_FLAT(		\
+						BL32_BASE,		\
+						BL32_LIMIT - BL32_BASE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+#endif /* SPD_opteed */
+
+#define ARM_NS_DRAM1_BASE		ARM_DRAM1_BASE
+#define ARM_NS_DRAM1_SIZE		(ARM_DRAM1_SIZE -		\
+					 ARM_TZC_DRAM1_SIZE)
+#define ARM_NS_DRAM1_END		(ARM_NS_DRAM1_BASE +		\
+					 ARM_NS_DRAM1_SIZE - 1)
+
+#define ARM_DRAM1_BASE			ULL(0x80000000)
+#define ARM_DRAM1_SIZE			ULL(0x80000000)
+#define ARM_DRAM1_END			(ARM_DRAM1_BASE +		\
+					 ARM_DRAM1_SIZE - 1)
+
+#define ARM_DRAM2_BASE			PLAT_ARM_DRAM2_BASE
+#define ARM_DRAM2_SIZE			PLAT_ARM_DRAM2_SIZE
+#define ARM_DRAM2_END			(ARM_DRAM2_BASE +		\
+					 ARM_DRAM2_SIZE - 1)
+
+#define ARM_IRQ_SEC_PHY_TIMER		29
+
+#define ARM_IRQ_SEC_SGI_0		8
+#define ARM_IRQ_SEC_SGI_1		9
+#define ARM_IRQ_SEC_SGI_2		10
+#define ARM_IRQ_SEC_SGI_3		11
+#define ARM_IRQ_SEC_SGI_4		12
+#define ARM_IRQ_SEC_SGI_5		13
+#define ARM_IRQ_SEC_SGI_6		14
+#define ARM_IRQ_SEC_SGI_7		15
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE)
+
+#define ARM_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE)
+
+#define ARM_MAP_SHARED_RAM		MAP_REGION_FLAT(		\
+						ARM_SHARED_RAM_BASE,	\
+						ARM_SHARED_RAM_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define ARM_MAP_NS_DRAM1		MAP_REGION_FLAT(		\
+						ARM_NS_DRAM1_BASE,	\
+						ARM_NS_DRAM1_SIZE,	\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define ARM_MAP_DRAM2			MAP_REGION_FLAT(		\
+						ARM_DRAM2_BASE,		\
+						ARM_DRAM2_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define ARM_MAP_TSP_SEC_MEM		MAP_REGION_FLAT(		\
+						TSP_SEC_MEM_BASE,	\
+						TSP_SEC_MEM_SIZE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+#if ARM_BL31_IN_DRAM
+#define ARM_MAP_BL31_SEC_DRAM		MAP_REGION_FLAT(		\
+						BL31_BASE,		\
+						PLAT_ARM_MAX_BL31_SIZE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+#define ARM_MAP_EL3_TZC_DRAM		MAP_REGION_FLAT(			\
+						ARM_EL3_TZC_DRAM1_BASE,	\
+						ARM_EL3_TZC_DRAM1_SIZE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * Mapping for the BL1 RW region. This mapping is needed by BL2 in order to
+ * share the Mbed TLS heap. Since the heap is allocated inside BL1, it resides
+ * in the BL1 RW region. Hence, BL2 needs access to the BL1 RW region in order
+ * to be able to access the heap.
+ */
+#define ARM_MAP_BL1_RW		MAP_REGION_FLAT(	\
+					BL1_RW_BASE,	\
+					BL1_RW_LIMIT - BL1_RW_BASE, \
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * If SEPARATE_CODE_AND_RODATA=1 we define a region for each section
+ * otherwise one region is defined containing both.
+ */
+#if SEPARATE_CODE_AND_RODATA
+#define ARM_MAP_BL_RO			MAP_REGION_FLAT(			\
+						BL_CODE_BASE,			\
+						BL_CODE_END - BL_CODE_BASE,	\
+						MT_CODE | MT_SECURE),		\
+					MAP_REGION_FLAT(			\
+						BL_RO_DATA_BASE,		\
+						BL_RO_DATA_END			\
+							- BL_RO_DATA_BASE,	\
+						MT_RO_DATA | MT_SECURE)
+#else
+#define ARM_MAP_BL_RO			MAP_REGION_FLAT(			\
+						BL_CODE_BASE,			\
+						BL_CODE_END - BL_CODE_BASE,	\
+						MT_CODE | MT_SECURE)
+#endif
+#if USE_COHERENT_MEM
+#define ARM_MAP_BL_COHERENT_RAM		MAP_REGION_FLAT(			\
+						BL_COHERENT_RAM_BASE,		\
+						BL_COHERENT_RAM_END		\
+							- BL_COHERENT_RAM_BASE, \
+						MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+#if USE_ROMLIB
+#define ARM_MAP_ROMLIB_CODE		MAP_REGION_FLAT(			\
+						ROMLIB_RO_BASE,			\
+						ROMLIB_RO_LIMIT	- ROMLIB_RO_BASE,\
+						MT_CODE | MT_SECURE)
+
+#define ARM_MAP_ROMLIB_DATA		MAP_REGION_FLAT(			\
+						ROMLIB_RW_BASE,			\
+						ROMLIB_RW_END	- ROMLIB_RW_BASE,\
+						MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+/*
+ * Map mem_protect flash region with read and write permissions
+ */
+#define ARM_V2M_MAP_MEM_PROTECT		MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR,	\
+						V2M_FLASH_BLOCK_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * The max number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+#define ARM_BL_REGIONS			5
+
+#define MAX_MMAP_REGIONS		(PLAT_ARM_MMAP_ENTRIES +	\
+					 ARM_BL_REGIONS)
+
+/* Memory mapped Generic timer interfaces  */
+#define ARM_SYS_CNTCTL_BASE		UL(0x2a430000)
+#define ARM_SYS_CNTREAD_BASE		UL(0x2a800000)
+#define ARM_SYS_TIMCTL_BASE		UL(0x2a810000)
+#define ARM_SYS_CNT_BASE_S		UL(0x2a820000)
+#define ARM_SYS_CNT_BASE_NS		UL(0x2a830000)
+
+#define ARM_CONSOLE_BAUDRATE		115200
+
+/* Trusted Watchdog constants */
+#define ARM_SP805_TWDG_BASE		UL(0x2a490000)
+#define ARM_SP805_TWDG_CLK_HZ		32768
+/* The TBBR document specifies a watchdog timeout of 256 seconds. SP805
+ * asserts reset after two consecutive countdowns (2 x 128 = 256 sec) */
+#define ARM_TWDG_TIMEOUT_SEC		128
+#define ARM_TWDG_LOAD_VAL		(ARM_SP805_TWDG_CLK_HZ * 	\
+					 ARM_TWDG_TIMEOUT_SEC)
+
+/******************************************************************************
+ * Required platform porting definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		ARM_LOCAL_STATE_RET
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		ARM_LOCAL_STATE_OFF
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE		(U(1) << ARM_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space of BL2 meminfo.
+ */
+#define ARM_TB_FW_CONFIG_BASE		(ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_TB_FW_CONFIG_LIMIT		(ARM_BL_RAM_BASE + (PAGE_SIZE / 2U))
+
+/*
+ * Boot parameters passed from BL2 to BL31/BL32 are stored here
+ */
+#define ARM_BL2_MEM_DESC_BASE		ARM_TB_FW_CONFIG_LIMIT
+#define ARM_BL2_MEM_DESC_LIMIT		(ARM_BL2_MEM_DESC_BASE +	\
+							(PAGE_SIZE / 2U))
+
+/*
+ * Define limit of firmware configuration memory:
+ * ARM_TB_FW_CONFIG + ARM_BL2_MEM_DESC memory
+ */
+#define ARM_FW_CONFIG_LIMIT		(ARM_BL_RAM_BASE + PAGE_SIZE)
+
+/*******************************************************************************
+ * BL1 specific defines.
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ ******************************************************************************/
+#define BL1_RO_BASE			PLAT_ARM_TRUSTED_ROM_BASE
+#define BL1_RO_LIMIT			(PLAT_ARM_TRUSTED_ROM_BASE	\
+					 + (PLAT_ARM_TRUSTED_ROM_SIZE - \
+					    PLAT_ARM_MAX_ROMLIB_RO_SIZE))
+/*
+ * Put BL1 RW at the top of the Trusted SRAM.
+ */
+#define BL1_RW_BASE			(ARM_BL_RAM_BASE +		\
+						ARM_BL_RAM_SIZE -	\
+						(PLAT_ARM_MAX_BL1_RW_SIZE +\
+						 PLAT_ARM_MAX_ROMLIB_RW_SIZE))
+#define BL1_RW_LIMIT			(ARM_BL_RAM_BASE + 		\
+					    (ARM_BL_RAM_SIZE - PLAT_ARM_MAX_ROMLIB_RW_SIZE))
+
+#define ROMLIB_RO_BASE			BL1_RO_LIMIT
+#define ROMLIB_RO_LIMIT			(PLAT_ARM_TRUSTED_ROM_BASE + PLAT_ARM_TRUSTED_ROM_SIZE)
+
+#define ROMLIB_RW_BASE			(BL1_RW_BASE + PLAT_ARM_MAX_BL1_RW_SIZE)
+#define ROMLIB_RW_END			(ROMLIB_RW_BASE + PLAT_ARM_MAX_ROMLIB_RW_SIZE)
+
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+#if BL2_AT_EL3
+/* Put BL2 towards the middle of the Trusted SRAM */
+#define BL2_BASE			(ARM_TRUSTED_SRAM_BASE + \
+						(PLAT_ARM_TRUSTED_SRAM_SIZE >> 1) + 0x2000)
+#define BL2_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+
+#else
+/*
+ * Put BL2 just below BL1.
+ */
+#define BL2_BASE			(BL1_RW_BASE - PLAT_ARM_MAX_BL2_SIZE)
+#define BL2_LIMIT			BL1_RW_BASE
+#endif
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+#if ARM_BL31_IN_DRAM
+/*
+ * Put BL31 at the bottom of TZC secured DRAM
+ */
+#define BL31_BASE			ARM_AP_TZC_DRAM1_BASE
+#define BL31_LIMIT			(ARM_AP_TZC_DRAM1_BASE +	\
+						PLAT_ARM_MAX_BL31_SIZE)
+#elif (RESET_TO_BL31)
+
+# if ENABLE_PIE
+/*
+ * Since this is PIE, we can define BL31_BASE to 0x0 since this macro is solely
+ * used for building BL31 and not used for loading BL31.
+ */
+#  define BL31_BASE			0x0
+#  define BL31_LIMIT			PLAT_ARM_MAX_BL31_SIZE
+# else
+/* Put BL31_BASE in the middle of the Trusted SRAM.*/
+#  define BL31_BASE			(ARM_TRUSTED_SRAM_BASE + \
+					(PLAT_ARM_TRUSTED_SRAM_SIZE >> 1))
+#  define BL31_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+# endif /* ENABLE_PIE */
+
+#else
+/* Put BL31 below BL2 in the Trusted SRAM.*/
+#define BL31_BASE			((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\
+						- PLAT_ARM_MAX_BL31_SIZE)
+#define BL31_PROGBITS_LIMIT		BL2_BASE
+/*
+ * For BL2_AT_EL3 make sure the BL31 can grow up until BL2_BASE. This is
+ * because in the BL2_AT_EL3 configuration, BL2 is always resident.
+ */
+#if BL2_AT_EL3
+#define BL31_LIMIT			BL2_BASE
+#else
+#define BL31_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+#endif
+#endif
+
+#if !defined(__aarch64__) || JUNO_AARCH32_EL3_RUNTIME
+/*******************************************************************************
+ * BL32 specific defines for EL3 runtime in AArch32 mode
+ ******************************************************************************/
+# if RESET_TO_SP_MIN && !JUNO_AARCH32_EL3_RUNTIME
+/*
+ * SP_MIN is the only BL image in SRAM. Allocate the whole of SRAM (excluding
+ * the page reserved for fw_configs) to BL32
+ */
+#  define BL32_BASE			ARM_FW_CONFIG_LIMIT
+#  define BL32_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+# else
+/* Put BL32 below BL2 in the Trusted SRAM.*/
+#  define BL32_BASE			((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\
+						- PLAT_ARM_MAX_BL32_SIZE)
+#  define BL32_PROGBITS_LIMIT		BL2_BASE
+#  define BL32_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+# endif /* RESET_TO_SP_MIN && !JUNO_AARCH32_EL3_RUNTIME */
+
+#else
+/*******************************************************************************
+ * BL32 specific defines for EL3 runtime in AArch64 mode
+ ******************************************************************************/
+/*
+ * On ARM standard platforms, the TSP can execute from Trusted SRAM,
+ * Trusted DRAM (if available) or the DRAM region secured by the TrustZone
+ * controller.
+ */
+# if ENABLE_SPM
+#  define TSP_SEC_MEM_BASE		(ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
+#  define TSP_SEC_MEM_SIZE		(ARM_AP_TZC_DRAM1_SIZE - ULL(0x200000))
+#  define BL32_BASE			(ARM_AP_TZC_DRAM1_BASE + ULL(0x200000))
+#  define BL32_LIMIT			(ARM_AP_TZC_DRAM1_BASE +	\
+						ARM_AP_TZC_DRAM1_SIZE)
+# elif ARM_BL31_IN_DRAM
+#  define TSP_SEC_MEM_BASE		(ARM_AP_TZC_DRAM1_BASE +	\
+						PLAT_ARM_MAX_BL31_SIZE)
+#  define TSP_SEC_MEM_SIZE		(ARM_AP_TZC_DRAM1_SIZE -	\
+						PLAT_ARM_MAX_BL31_SIZE)
+#  define BL32_BASE			(ARM_AP_TZC_DRAM1_BASE +	\
+						PLAT_ARM_MAX_BL31_SIZE)
+#  define BL32_LIMIT			(ARM_AP_TZC_DRAM1_BASE +	\
+						ARM_AP_TZC_DRAM1_SIZE)
+# elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_SRAM_ID
+#  define TSP_SEC_MEM_BASE		ARM_BL_RAM_BASE
+#  define TSP_SEC_MEM_SIZE		ARM_BL_RAM_SIZE
+#  define TSP_PROGBITS_LIMIT		BL31_BASE
+#  define BL32_BASE			ARM_FW_CONFIG_LIMIT
+#  define BL32_LIMIT			BL31_BASE
+# elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_DRAM_ID
+#  define TSP_SEC_MEM_BASE		PLAT_ARM_TRUSTED_DRAM_BASE
+#  define TSP_SEC_MEM_SIZE		PLAT_ARM_TRUSTED_DRAM_SIZE
+#  define BL32_BASE			PLAT_ARM_TRUSTED_DRAM_BASE
+#  define BL32_LIMIT			(PLAT_ARM_TRUSTED_DRAM_BASE	\
+						+ (UL(1) << 21))
+# elif ARM_TSP_RAM_LOCATION_ID == ARM_DRAM_ID
+#  define TSP_SEC_MEM_BASE		ARM_AP_TZC_DRAM1_BASE
+#  define TSP_SEC_MEM_SIZE		ARM_AP_TZC_DRAM1_SIZE
+#  define BL32_BASE			ARM_AP_TZC_DRAM1_BASE
+#  define BL32_LIMIT			(ARM_AP_TZC_DRAM1_BASE +	\
+						ARM_AP_TZC_DRAM1_SIZE)
+# else
+#  error "Unsupported ARM_TSP_RAM_LOCATION_ID value"
+# endif
+#endif /* !__aarch64__ || JUNO_AARCH32_EL3_RUNTIME */
+
+/*
+ * BL32 is mandatory in AArch32. In AArch64, undefine BL32_BASE if there is no
+ * SPD and no SPM, as they are the only ones that can be used as BL32.
+ */
+#if defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME
+# if defined(SPD_none) && !ENABLE_SPM
+#  undef BL32_BASE
+# endif /* defined(SPD_none) && !ENABLE_SPM */
+#endif /* defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME */
+
+/*******************************************************************************
+ * FWU Images: NS_BL1U, BL2U & NS_BL2U defines.
+ ******************************************************************************/
+#define BL2U_BASE			BL2_BASE
+#define BL2U_LIMIT			BL2_LIMIT
+
+#define NS_BL2U_BASE			ARM_NS_DRAM1_BASE
+#define NS_BL1U_BASE			(PLAT_ARM_NVM_BASE + UL(0x03EB8000))
+
+/*
+ * ID of the secure physical generic timer interrupt used by the TSP.
+ */
+#define TSP_IRQ_SEC_PHY_TIMER		ARM_IRQ_SEC_PHY_TIMER
+
+
+/*
+ * One cache line needed for bakery locks on ARM platforms
+ */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE		(1 * CACHE_WRITEBACK_GRANULE)
+
+/* Priority levels for ARM platforms */
+#define PLAT_RAS_PRI			0x10
+#define PLAT_SDEI_CRITICAL_PRI		0x60
+#define PLAT_SDEI_NORMAL_PRI		0x70
+
+/* ARM platforms use 3 upper bits of secure interrupt priority */
+#define ARM_PRI_BITS			3
+
+/* SGI used for SDEI signalling */
+#define ARM_SDEI_SGI			ARM_IRQ_SEC_SGI_0
+
+/* ARM SDEI dynamic private event numbers */
+#define ARM_SDEI_DP_EVENT_0		1000
+#define ARM_SDEI_DP_EVENT_1		1001
+#define ARM_SDEI_DP_EVENT_2		1002
+
+/* ARM SDEI dynamic shared event numbers */
+#define ARM_SDEI_DS_EVENT_0		2000
+#define ARM_SDEI_DS_EVENT_1		2001
+#define ARM_SDEI_DS_EVENT_2		2002
+
+#define ARM_SDEI_PRIVATE_EVENTS \
+	SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI), \
+	SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \
+	SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \
+	SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+
+#define ARM_SDEI_SHARED_EVENTS \
+	SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \
+	SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \
+	SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
+
+#endif /* ARM_DEF_H */
diff --git a/include/plat/arm/common/arm_dyn_cfg_helpers.h b/include/plat/arm/common/arm_dyn_cfg_helpers.h
new file mode 100644
index 0000000..3ad6d54
--- /dev/null
+++ b/include/plat/arm/common/arm_dyn_cfg_helpers.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_DYN_CFG_HELPERS_H
+#define ARM_DYN_CFG_HELPERS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Function declarations */
+int arm_dyn_get_config_load_info(void *dtb, int node, unsigned int config_id,
+		uint64_t *config_addr, uint32_t *config_size);
+int arm_dyn_tb_fw_cfg_init(void *dtb, int *node);
+int arm_dyn_get_disable_auth(void *dtb, int node, uint32_t *disable_auth);
+int arm_get_dtb_mbedtls_heap_info(void *dtb, void **heap_addr,
+	size_t *heap_size);
+int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr,
+	size_t heap_size);
+
+#endif /* ARM_DYN_CFG_HELPERS_H */
diff --git a/include/plat/arm/common/arm_reclaim_init.ld.S b/include/plat/arm/common/arm_reclaim_init.ld.S
new file mode 100644
index 0000000..8f22170
--- /dev/null
+++ b/include/plat/arm/common/arm_reclaim_init.ld.S
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_RECLAIM_INIT_LD_S
+#define ARM_RECLAIM_INIT_LD_S
+
+SECTIONS
+{
+        .init __STACKS_START__ : {
+            . = . + PLATFORM_STACK_SIZE;
+            . = ALIGN(PAGE_SIZE);
+            __INIT_CODE_START__ = .;
+            /*
+             * Exclude PSCI initialization functions to ensure the init section
+             * does not become larger than the overlaid stack region
+             */
+            *(EXCLUDE_FILE (*psci_setup.o).text.init*)
+            __INIT_CODE_UNALIGNED__ = .;
+            .  = ALIGN(PAGE_SIZE);
+            __INIT_CODE_END__ = .;
+        } >RAM
+
+#ifdef BL31_PROGBITS_LIMIT
+    ASSERT(__INIT_CODE_END__ <= BL31_PROGBITS_LIMIT,
+            "BL31 init has exceeded progbits limit.")
+#endif
+
+#if RECLAIM_INIT_CODE
+    ASSERT(__INIT_CODE_END__ <= __STACKS_END__,
+        "Init code ends past the end of the stacks")
+#endif
+}
+
+#endif /* ARM_RECLAIM_INIT_LD_S */
diff --git a/include/plat/arm/common/arm_sip_svc.h b/include/plat/arm/common/arm_sip_svc.h
new file mode 100644
index 0000000..16573ce
--- /dev/null
+++ b/include/plat/arm/common/arm_sip_svc.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_SIP_SVC_H
+#define ARM_SIP_SVC_H
+
+#include <lib/utils_def.h>
+
+/* SMC function IDs for SiP Service queries */
+
+#define ARM_SIP_SVC_CALL_COUNT		U(0x8200ff00)
+#define ARM_SIP_SVC_UID			U(0x8200ff01)
+/*					U(0x8200ff02) is reserved */
+#define ARM_SIP_SVC_VERSION		U(0x8200ff03)
+
+/* Function ID for requesting state switch of lower EL */
+#define ARM_SIP_SVC_EXE_STATE_SWITCH	U(0x82000020)
+
+/* ARM SiP Service Calls version numbers */
+#define ARM_SIP_SVC_VERSION_MAJOR		U(0x0)
+#define ARM_SIP_SVC_VERSION_MINOR		U(0x2)
+
+#endif /* ARM_SIP_SVC_H */
diff --git a/include/plat/arm/common/arm_spm_def.h b/include/plat/arm/common/arm_spm_def.h
new file mode 100644
index 0000000..16c806b
--- /dev/null
+++ b/include/plat/arm/common/arm_spm_def.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_SPM_DEF_H
+#define ARM_SPM_DEF_H
+
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/*
+ * Reserve 4 MiB for binaries of Secure Partitions and Resource Description
+ * blobs.
+ */
+#define PLAT_SP_PACKAGE_BASE	BL32_BASE
+#define PLAT_SP_PACKAGE_SIZE	ULL(0x400000)
+
+#define PLAT_MAP_SP_PACKAGE_MEM_RO	MAP_REGION_FLAT(		\
+						PLAT_SP_PACKAGE_BASE,	\
+						PLAT_SP_PACKAGE_SIZE,	\
+						MT_MEMORY | MT_RO | MT_SECURE)
+#define PLAT_MAP_SP_PACKAGE_MEM_RW	MAP_REGION_FLAT(		\
+						PLAT_SP_PACKAGE_BASE,	\
+						PLAT_SP_PACKAGE_SIZE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * The rest of the memory reserved for BL32 is free for SPM to use it as memory
+ * pool to allocate memory regions requested in the resource description.
+ */
+#define PLAT_SPM_HEAP_BASE	(PLAT_SP_PACKAGE_BASE + PLAT_SP_PACKAGE_SIZE)
+#define PLAT_SPM_HEAP_SIZE	(BL32_LIMIT - BL32_BASE - PLAT_SP_PACKAGE_SIZE)
+
+#if SPM_MM
+
+/*
+ * If BL31 is placed in DRAM, place the Secure Partition in DRAM right after the
+ * region used by BL31. If BL31 it is placed in SRAM, put the Secure Partition
+ * at the base of DRAM.
+ */
+#define ARM_SP_IMAGE_BASE		BL32_BASE
+#define ARM_SP_IMAGE_LIMIT		BL32_LIMIT
+/* The maximum size of the S-EL0 payload can be 3MB */
+#define ARM_SP_IMAGE_SIZE		ULL(0x300000)
+
+#ifdef IMAGE_BL2
+/* SPM Payload memory. Mapped as RW in BL2. */
+#define ARM_SP_IMAGE_MMAP		MAP_REGION_FLAT(			\
+						ARM_SP_IMAGE_BASE,		\
+						ARM_SP_IMAGE_SIZE,		\
+						MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+#ifdef IMAGE_BL31
+/* SPM Payload memory. Mapped as code in S-EL1 */
+#define ARM_SP_IMAGE_MMAP		MAP_REGION2(				\
+						ARM_SP_IMAGE_BASE,		\
+						ARM_SP_IMAGE_BASE,		\
+						ARM_SP_IMAGE_SIZE,		\
+						MT_CODE | MT_SECURE | MT_USER,	\
+						PAGE_SIZE)
+#endif
+
+/*
+ * Memory shared between EL3 and S-EL0. It is used by EL3 to push data into
+ * S-EL0, so it is mapped with RW permission from EL3 and with RO permission
+ * from S-EL0. Placed after SPM Payload memory.
+ */
+#define PLAT_SPM_BUF_BASE		(ARM_SP_IMAGE_BASE + ARM_SP_IMAGE_SIZE)
+#define PLAT_SPM_BUF_SIZE		ULL(0x100000)
+
+#define ARM_SPM_BUF_EL3_MMAP		MAP_REGION_FLAT(			\
+						PLAT_SPM_BUF_BASE,		\
+						PLAT_SPM_BUF_SIZE,		\
+						MT_RW_DATA | MT_SECURE)
+#define ARM_SPM_BUF_EL0_MMAP		MAP_REGION2(			\
+						PLAT_SPM_BUF_BASE,		\
+						PLAT_SPM_BUF_BASE,		\
+						PLAT_SPM_BUF_SIZE,		\
+						MT_RO_DATA | MT_SECURE | MT_USER,\
+						PAGE_SIZE)
+
+/*
+ * Memory shared between Normal world and S-EL0 for passing data during service
+ * requests. Mapped as RW and NS. Placed after the shared memory between EL3 and
+ * S-EL0.
+ */
+#define PLAT_SP_IMAGE_NS_BUF_BASE	(PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE)
+#define PLAT_SP_IMAGE_NS_BUF_SIZE	ULL(0x10000)
+#define ARM_SP_IMAGE_NS_BUF_MMAP	MAP_REGION2(				\
+						PLAT_SP_IMAGE_NS_BUF_BASE,	\
+						PLAT_SP_IMAGE_NS_BUF_BASE,	\
+						PLAT_SP_IMAGE_NS_BUF_SIZE,	\
+						MT_RW_DATA | MT_NS | MT_USER,	\
+						PAGE_SIZE)
+
+/*
+ * RW memory, which uses the remaining Trusted DRAM. Placed after the memory
+ * shared between Secure and Non-secure worlds, or after the platform specific
+ * buffers, if defined. First there is the stack memory for all CPUs and then
+ * there is the common heap memory. Both are mapped with RW permissions.
+ */
+#define PLAT_SP_IMAGE_STACK_BASE	PLAT_ARM_SP_IMAGE_STACK_BASE
+#define PLAT_SP_IMAGE_STACK_PCPU_SIZE	ULL(0x2000)
+#define ARM_SP_IMAGE_STACK_TOTAL_SIZE	(PLATFORM_CORE_COUNT *			\
+					 PLAT_SP_IMAGE_STACK_PCPU_SIZE)
+
+#define ARM_SP_IMAGE_HEAP_BASE		(PLAT_SP_IMAGE_STACK_BASE +		\
+					 ARM_SP_IMAGE_STACK_TOTAL_SIZE)
+#define ARM_SP_IMAGE_HEAP_SIZE		(ARM_SP_IMAGE_LIMIT - ARM_SP_IMAGE_HEAP_BASE)
+
+#define ARM_SP_IMAGE_RW_MMAP		MAP_REGION2(				\
+						PLAT_SP_IMAGE_STACK_BASE,	\
+						PLAT_SP_IMAGE_STACK_BASE,	\
+						(ARM_SP_IMAGE_LIMIT -		\
+						 PLAT_SP_IMAGE_STACK_BASE),	\
+						MT_RW_DATA | MT_SECURE | MT_USER,\
+						PAGE_SIZE)
+
+/* Total number of memory regions with distinct properties */
+#define ARM_SP_IMAGE_NUM_MEM_REGIONS	6
+
+#endif /* SPM_MM */
+
+/* Cookies passed to the Secure Partition at boot. Not used by ARM platforms. */
+#define PLAT_SPM_COOKIE_0		ULL(0)
+#define PLAT_SPM_COOKIE_1		ULL(0)
+
+/*
+ * Max number of elements supported by SPM in this platform. The defines below
+ * are used to allocate memory at compile time for different arrays in SPM.
+ */
+#define PLAT_SPM_MAX_PARTITIONS		U(2)
+
+#define PLAT_SPM_MEM_REGIONS_MAX	U(80)
+#define PLAT_SPM_NOTIFICATIONS_MAX	U(30)
+#define PLAT_SPM_SERVICES_MAX		U(30)
+
+#define PLAT_SPCI_HANDLES_MAX_NUM	U(20)
+#define PLAT_SPM_RESPONSES_MAX		U(30)
+
+#endif /* ARM_SPM_DEF_H */
diff --git a/include/plat/arm/common/arm_tzc_dram.ld.S b/include/plat/arm/common/arm_tzc_dram.ld.S
new file mode 100644
index 0000000..6dcea0b
--- /dev/null
+++ b/include/plat/arm/common/arm_tzc_dram.ld.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_TZC_DRAM_LD_S
+#define ARM_TZC_DRAM_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+MEMORY {
+    EL3_SEC_DRAM (rw): ORIGIN = ARM_EL3_TZC_DRAM1_BASE, LENGTH = ARM_EL3_TZC_DRAM1_SIZE
+}
+
+SECTIONS
+{
+	. = ARM_EL3_TZC_DRAM1_BASE;
+	ASSERT(. == ALIGN(PAGE_SIZE),
+	"ARM_EL3_TZC_DRAM_BASE address is not aligned on a page boundary.")
+	el3_tzc_dram (NOLOAD) : ALIGN(PAGE_SIZE) {
+	__EL3_SEC_DRAM_START__ = .;
+	*(arm_el3_tzc_dram)
+	__EL3_SEC_DRAM_UNALIGNED_END__ = .;
+
+	. = ALIGN(PAGE_SIZE);
+	__EL3_SEC_DRAM_END__ = .;
+	} >EL3_SEC_DRAM
+}
+
+#endif /* ARM_TZC_DRAM_LD_S */
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
new file mode 100644
index 0000000..07a46c5
--- /dev/null
+++ b/include/plat/arm/common/plat_arm.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_ARM_H
+#define PLAT_ARM_H
+
+#include <stdint.h>
+
+#include <drivers/arm/tzc_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+struct meminfo;
+struct image_info;
+struct bl_params;
+
+typedef struct arm_tzc_regions_info {
+	unsigned long long base;
+	unsigned long long end;
+	unsigned int sec_attr;
+	unsigned int nsaid_permissions;
+} arm_tzc_regions_info_t;
+
+/*******************************************************************************
+ * Default mapping definition of the TrustZone Controller for ARM standard
+ * platforms.
+ * Configure:
+ *   - Region 0 with no access;
+ *   - Region 1 with secure access only;
+ *   - the remaining DRAM regions access from the given Non-Secure masters.
+ ******************************************************************************/
+#if ENABLE_SPM && SPM_MM
+#define ARM_TZC_REGIONS_DEF						\
+	{ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END,			\
+		TZC_REGION_S_RDWR, 0},					\
+	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \
+		PLAT_ARM_TZC_NS_DEV_ACCESS}, 				\
+	{ARM_DRAM2_BASE, ARM_DRAM2_END, ARM_TZC_NS_DRAM_S_ACCESS,	\
+		PLAT_ARM_TZC_NS_DEV_ACCESS},				\
+	{PLAT_SP_IMAGE_NS_BUF_BASE, (PLAT_SP_IMAGE_NS_BUF_BASE +	\
+		PLAT_SP_IMAGE_NS_BUF_SIZE) - 1, TZC_REGION_S_NONE,	\
+		PLAT_ARM_TZC_NS_DEV_ACCESS}
+
+#else
+#define ARM_TZC_REGIONS_DEF						\
+	{ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END,			\
+		TZC_REGION_S_RDWR, 0},					\
+	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \
+		PLAT_ARM_TZC_NS_DEV_ACCESS},	 			\
+	{ARM_DRAM2_BASE, ARM_DRAM2_END, ARM_TZC_NS_DRAM_S_ACCESS,	\
+		PLAT_ARM_TZC_NS_DEV_ACCESS}
+#endif
+
+#define ARM_CASSERT_MMAP						  \
+	CASSERT((ARRAY_SIZE(plat_arm_mmap) - 1) <= PLAT_ARM_MMAP_ENTRIES, \
+		assert_plat_arm_mmap_mismatch);				  \
+	CASSERT((PLAT_ARM_MMAP_ENTRIES + ARM_BL_REGIONS)		  \
+		<= MAX_MMAP_REGIONS,					  \
+		assert_max_mmap_regions);
+
+void arm_setup_romlib(void);
+
+#if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
+/*
+ * Use this macro to instantiate lock before it is used in below
+ * arm_lock_xxx() macros
+ */
+#define ARM_INSTANTIATE_LOCK	static DEFINE_BAKERY_LOCK(arm_lock)
+#define ARM_LOCK_GET_INSTANCE	(&arm_lock)
+
+#if !HW_ASSISTED_COHERENCY
+#define ARM_SCMI_INSTANTIATE_LOCK	DEFINE_BAKERY_LOCK(arm_scmi_lock)
+#else
+#define ARM_SCMI_INSTANTIATE_LOCK	spinlock_t arm_scmi_lock
+#endif
+#define ARM_SCMI_LOCK_GET_INSTANCE	(&arm_scmi_lock)
+
+/*
+ * These are wrapper macros to the Coherent Memory Bakery Lock API.
+ */
+#define arm_lock_init()		bakery_lock_init(&arm_lock)
+#define arm_lock_get()		bakery_lock_get(&arm_lock)
+#define arm_lock_release()	bakery_lock_release(&arm_lock)
+
+#else
+
+/*
+ * Empty macros for all other BL stages other than BL31 and BL32
+ */
+#define ARM_INSTANTIATE_LOCK	static int arm_lock __unused
+#define ARM_LOCK_GET_INSTANCE	0
+#define arm_lock_init()
+#define arm_lock_get()
+#define arm_lock_release()
+
+#endif /* defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32)) */
+
+#if ARM_RECOM_STATE_ID_ENC
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define ARM_LOCAL_PSTATE_WIDTH		4
+#define ARM_LOCAL_PSTATE_MASK		((1 << ARM_LOCAL_PSTATE_WIDTH) - 1)
+
+/* Macros to construct the composite power state */
+
+/* Make composite power state parameter till power level 0 */
+#if PSCI_EXTENDED_STATE_ID
+
+#define arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT))
+#else
+#define arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+		((type) << PSTATE_TYPE_SHIFT))
+#endif /* __PSCI_EXTENDED_STATE_ID__ */
+
+/* Make composite power state parameter till power level 1 */
+#define arm_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl1_state) << ARM_LOCAL_PSTATE_WIDTH) | \
+		arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
+
+/* Make composite power state parameter till power level 2 */
+#define arm_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl2_state) << (ARM_LOCAL_PSTATE_WIDTH * 2)) | \
+		arm_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type))
+
+#endif /* __ARM_RECOM_STATE_ID_ENC__ */
+
+/* ARM State switch error codes */
+#define STATE_SW_E_PARAM		(-2)
+#define STATE_SW_E_DENIED		(-3)
+
+/* IO storage utility functions */
+void arm_io_setup(void);
+
+/* Security utility functions */
+void arm_tzc400_setup(const arm_tzc_regions_info_t *tzc_regions);
+struct tzc_dmc500_driver_data;
+void arm_tzc_dmc500_setup(struct tzc_dmc500_driver_data *plat_driver_data,
+			const arm_tzc_regions_info_t *tzc_regions);
+
+/* Console utility functions */
+void arm_console_boot_init(void);
+void arm_console_boot_end(void);
+void arm_console_runtime_init(void);
+void arm_console_runtime_end(void);
+
+/* Systimer utility function */
+void arm_configure_sys_timer(void);
+
+/* PM utility functions */
+int arm_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state);
+int arm_validate_psci_entrypoint(uintptr_t entrypoint);
+int arm_validate_ns_entrypoint(uintptr_t entrypoint);
+void arm_system_pwr_domain_save(void);
+void arm_system_pwr_domain_resume(void);
+int arm_psci_read_mem_protect(int *enabled);
+int arm_nor_psci_write_mem_protect(int val);
+void arm_nor_psci_do_static_mem_protect(void);
+void arm_nor_psci_do_dyn_mem_protect(void);
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length);
+
+/* Topology utility function */
+int arm_check_mpidr(u_register_t mpidr);
+
+/* BL1 utility functions */
+void arm_bl1_early_platform_setup(void);
+void arm_bl1_platform_setup(void);
+void arm_bl1_plat_arch_setup(void);
+
+/* BL2 utility functions */
+void arm_bl2_early_platform_setup(uintptr_t tb_fw_config, struct meminfo *mem_layout);
+void arm_bl2_platform_setup(void);
+void arm_bl2_plat_arch_setup(void);
+uint32_t arm_get_spsr_for_bl32_entry(void);
+uint32_t arm_get_spsr_for_bl33_entry(void);
+int arm_bl2_plat_handle_post_image_load(unsigned int image_id);
+int arm_bl2_handle_post_image_load(unsigned int image_id);
+struct bl_params *arm_get_next_bl_params(void);
+
+/* BL2 at EL3 functions */
+void arm_bl2_el3_early_platform_setup(void);
+void arm_bl2_el3_plat_arch_setup(void);
+
+/* BL2U utility functions */
+void arm_bl2u_early_platform_setup(struct meminfo *mem_layout,
+				void *plat_info);
+void arm_bl2u_platform_setup(void);
+void arm_bl2u_plat_arch_setup(void);
+
+/* BL31 utility functions */
+void arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config,
+				uintptr_t hw_config, void *plat_params_from_bl2);
+void arm_bl31_platform_setup(void);
+void arm_bl31_plat_runtime_setup(void);
+void arm_bl31_plat_arch_setup(void);
+
+/* TSP utility functions */
+void arm_tsp_early_platform_setup(void);
+
+/* SP_MIN utility functions */
+void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config,
+				uintptr_t hw_config, void *plat_params_from_bl2);
+void arm_sp_min_plat_runtime_setup(void);
+
+/* FIP TOC validity check */
+int arm_io_is_toc_valid(void);
+
+/* Utility functions for Dynamic Config */
+void arm_load_tb_fw_config(void);
+void arm_bl2_set_tb_cfg_addr(void *dtb);
+void arm_bl2_dyn_cfg_init(void);
+void arm_bl1_set_mbedtls_heap(void);
+int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size);
+
+/*
+ * Free the memory storing initialization code only used during an images boot
+ * time so it can be reclaimed for runtime data
+ */
+void arm_free_init_memory(void);
+
+/*
+ * Mandatory functions required in ARM standard platforms
+ */
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr);
+void plat_arm_gic_driver_init(void);
+void plat_arm_gic_init(void);
+void plat_arm_gic_cpuif_enable(void);
+void plat_arm_gic_cpuif_disable(void);
+void plat_arm_gic_redistif_on(void);
+void plat_arm_gic_redistif_off(void);
+void plat_arm_gic_pcpu_init(void);
+void plat_arm_gic_save(void);
+void plat_arm_gic_resume(void);
+void plat_arm_security_setup(void);
+void plat_arm_pwrc_setup(void);
+void plat_arm_interconnect_init(void);
+void plat_arm_interconnect_enter_coherency(void);
+void plat_arm_interconnect_exit_coherency(void);
+void plat_arm_program_trusted_mailbox(uintptr_t address);
+int plat_arm_bl1_fwu_needed(void);
+__dead2 void plat_arm_error_handler(int err);
+
+#if ARM_PLAT_MT
+unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr);
+#endif
+
+/*
+ * This function is called after loading SCP_BL2 image and it is used to perform
+ * any platform-specific actions required to handle the SCP firmware.
+ */
+int plat_arm_bl2_handle_scp_bl2(struct image_info *scp_bl2_image_info);
+
+/*
+ * Optional functions required in ARM standard platforms
+ */
+void plat_arm_io_setup(void);
+int plat_arm_get_alt_image_source(
+	unsigned int image_id,
+	uintptr_t *dev_handle,
+	uintptr_t *image_spec);
+unsigned int plat_arm_calc_core_pos(u_register_t mpidr);
+const mmap_region_t *plat_arm_get_mmap(void);
+
+/* Allow platform to override psci_pm_ops during runtime */
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops);
+
+/* Execution state switch in ARM platforms */
+int arm_execution_state_switch(unsigned int smc_fid,
+		uint32_t pc_hi,
+		uint32_t pc_lo,
+		uint32_t cookie_hi,
+		uint32_t cookie_lo,
+		void *handle);
+
+/* Optional functions for SP_MIN */
+void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3);
+
+/* global variables */
+extern plat_psci_ops_t plat_arm_psci_pm_ops;
+extern const mmap_region_t plat_arm_mmap[];
+extern const unsigned int arm_pm_idle_states[];
+
+/* secure watchdog */
+void plat_arm_secure_wdt_start(void);
+void plat_arm_secure_wdt_stop(void);
+
+#endif /* PLAT_ARM_H */
diff --git a/include/plat/arm/css/common/aarch64/css_macros.S b/include/plat/arm/css/common/aarch64/css_macros.S
new file mode 100644
index 0000000..85a7044
--- /dev/null
+++ b/include/plat/arm/css/common/aarch64/css_macros.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CSS_MACROS_S
+#define CSS_MACROS_S
+
+#include <arm_macros.S>
+#include <platform_def.h>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC registers whenever an
+	 * unhandled exception is taken in BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro css_print_gic_regs
+	mov_imm	x16, PLAT_ARM_GICD_BASE
+	mov_imm	x17, PLAT_ARM_GICC_BASE
+	arm_print_gic_regs
+	.endm
+
+#endif /* CSS_MACROS_S */
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
new file mode 100644
index 0000000..2adf11d
--- /dev/null
+++ b/include/plat/arm/css/common/css_def.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_DEF_H
+#define CSS_DEF_H
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/tzc400.h>
+
+/*************************************************************************
+ * Definitions common to all ARM Compute SubSystems (CSS)
+ *************************************************************************/
+#define NSROM_BASE			0x1f000000
+#define NSROM_SIZE			0x00001000
+
+/* Following covers CSS Peripherals excluding NSROM and NSRAM  */
+#define CSS_DEVICE_BASE			0x20000000
+#define CSS_DEVICE_SIZE			0x0e000000
+
+/* System Security Control Registers */
+#define SSC_REG_BASE			0x2a420000
+#define SSC_GPRETN			(SSC_REG_BASE + 0x030)
+
+/* System ID Registers Unit */
+#define SID_REG_BASE			0x2a4a0000
+#define SID_SYSTEM_ID_OFFSET		0x40
+#define SID_SYSTEM_CFG_OFFSET		0x70
+
+/* The slave_bootsecure controls access to GPU, DMC and CS. */
+#define CSS_NIC400_SLAVE_BOOTSECURE	8
+
+/* Interrupt handling constants */
+#define CSS_IRQ_MHU			69
+#define CSS_IRQ_GPU_SMMU_0		71
+#define CSS_IRQ_TZC			80
+#define CSS_IRQ_TZ_WDOG			86
+#define CSS_IRQ_SEC_SYS_TIMER		91
+
+/* MHU register offsets */
+#define MHU_CPU_INTR_S_SET_OFFSET	0x308
+
+/*
+ * Define a list of Group 1 Secure interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the interrupts will be treated as
+ * Group 0 interrupts.
+ */
+#define CSS_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(CSS_IRQ_MHU, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(CSS_IRQ_GPU_SMMU_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(CSS_IRQ_TZC, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(CSS_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(CSS_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#if CSS_USE_SCMI_SDS_DRIVER
+/* Memory region for shared data storage */
+#define PLAT_ARM_SDS_MEM_BASE		ARM_SHARED_RAM_BASE
+#define PLAT_ARM_SDS_MEM_SIZE_MAX	0xDC0 /* 3520 bytes */
+/*
+ * The SCMI Channel is placed right after the SDS region
+ */
+#define CSS_SCMI_PAYLOAD_BASE		(PLAT_ARM_SDS_MEM_BASE + PLAT_ARM_SDS_MEM_SIZE_MAX)
+#define CSS_SCMI_MHU_DB_REG_OFF		MHU_CPU_INTR_S_SET_OFFSET
+
+/* Trusted mailbox base address common to all CSS */
+/* If SDS is present, then mailbox is at top of SRAM */
+#define PLAT_ARM_TRUSTED_MAILBOX_BASE	(ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE - 0x8)
+
+/* Number of retries for SCP_RAM_READY flag */
+#define CSS_SCP_READY_10US_RETRIES		1000000 /* Effective timeout of 10000 ms */
+
+#else
+/*
+ * SCP <=> AP boot configuration
+ *
+ * The SCP/AP boot configuration is a 32-bit word located at a known offset from
+ * the start of the Trusted SRAM.
+ *
+ * Note that the value stored at this address is only valid at boot time, before
+ * the SCP_BL2 image is transferred to SCP.
+ */
+#define SCP_BOOT_CFG_ADDR		PLAT_CSS_SCP_COM_SHARED_MEM_BASE
+
+/* Trusted mailbox base address common to all CSS */
+/* If SDS is not present, then the mailbox is at the bottom of SRAM */
+#define PLAT_ARM_TRUSTED_MAILBOX_BASE	ARM_TRUSTED_SRAM_BASE
+
+#endif /* CSS_USE_SCMI_SDS_DRIVER */
+
+#define CSS_MAP_DEVICE			MAP_REGION_FLAT(		\
+						CSS_DEVICE_BASE,	\
+						CSS_DEVICE_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define CSS_MAP_NSRAM			MAP_REGION_FLAT(		\
+						NSRAM_BASE,	\
+						NSRAM_SIZE,	\
+						MT_DEVICE | MT_RW | MT_NS)
+
+#if defined(IMAGE_BL2U)
+#define CSS_MAP_SCP_BL2U		MAP_REGION_FLAT(		\
+						SCP_BL2U_BASE,		\
+						SCP_BL2U_LIMIT		\
+							- SCP_BL2U_BASE,\
+						MT_RW_DATA | MT_SECURE)
+#endif
+
+/* Platform ID address */
+#define SSC_VERSION_OFFSET			0x040
+
+#define SSC_VERSION_CONFIG_SHIFT		28
+#define SSC_VERSION_MAJOR_REV_SHIFT		24
+#define SSC_VERSION_MINOR_REV_SHIFT		20
+#define SSC_VERSION_DESIGNER_ID_SHIFT		12
+#define SSC_VERSION_PART_NUM_SHIFT		0x0
+#define SSC_VERSION_CONFIG_MASK			0xf
+#define SSC_VERSION_MAJOR_REV_MASK		0xf
+#define SSC_VERSION_MINOR_REV_MASK		0xf
+#define SSC_VERSION_DESIGNER_ID_MASK		0xff
+#define SSC_VERSION_PART_NUM_MASK		0xfff
+
+#define SID_SYSTEM_ID_PART_NUM_MASK		0xfff
+
+/* SSC debug configuration registers */
+#define SSC_DBGCFG_SET		0x14
+#define SSC_DBGCFG_CLR		0x18
+
+#define SPIDEN_INT_CLR_SHIFT	6
+#define SPIDEN_SEL_SET_SHIFT	7
+
+#ifndef __ASSEMBLER__
+
+/* SSC_VERSION related accessors */
+
+/* Returns the part number of the platform */
+#define GET_SSC_VERSION_PART_NUM(val)				\
+		(((val) >> SSC_VERSION_PART_NUM_SHIFT) &	\
+		SSC_VERSION_PART_NUM_MASK)
+
+/* Returns the configuration number of the platform */
+#define GET_SSC_VERSION_CONFIG(val)				\
+		(((val) >> SSC_VERSION_CONFIG_SHIFT) &		\
+		SSC_VERSION_CONFIG_MASK)
+
+#endif /* __ASSEMBLER__ */
+
+/*************************************************************************
+ * Required platform porting definitions common to all
+ * ARM Compute SubSystems (CSS)
+ ************************************************************************/
+
+/*
+ * The loading of SCP images(SCP_BL2 or SCP_BL2U) is done if there
+ * respective base addresses are defined (i.e SCP_BL2_BASE, SCP_BL2U_BASE).
+ * Hence, `CSS_LOAD_SCP_IMAGES` needs to be set to 1 if BL2 needs to load
+ * an SCP_BL2/SCP_BL2U image.
+ */
+#if CSS_LOAD_SCP_IMAGES
+
+#if ARM_BL31_IN_DRAM
+#error "SCP_BL2 is not expected to be loaded by BL2 for ARM_BL31_IN_DRAM config"
+#endif
+
+/*
+ * Load address of SCP_BL2 in CSS platform ports
+ * SCP_BL2 is loaded to the same place as BL31 but it shouldn't overwrite BL1
+ * rw data or BL2.  Once SCP_BL2 is transferred to the SCP, it is discarded and
+ * BL31 is loaded over the top.
+ */
+#define SCP_BL2_BASE			(BL2_BASE - PLAT_CSS_MAX_SCP_BL2_SIZE)
+#define SCP_BL2_LIMIT			BL2_BASE
+
+#define SCP_BL2U_BASE			(BL2_BASE - PLAT_CSS_MAX_SCP_BL2U_SIZE)
+#define SCP_BL2U_LIMIT			BL2_BASE
+#endif /* CSS_LOAD_SCP_IMAGES */
+
+/* Load address of Non-Secure Image for CSS platform ports */
+#define PLAT_ARM_NS_IMAGE_BASE		U(0xE0000000)
+
+/* TZC related constants */
+#define PLAT_ARM_TZC_FILTERS		TZC_400_REGION_ATTR_FILTER_BIT_ALL
+
+/*
+ * Parsing of CPU and Cluster states, as returned by 'Get CSS Power State' SCP
+ * command
+ */
+#define CSS_CLUSTER_PWR_STATE_ON	0
+#define CSS_CLUSTER_PWR_STATE_OFF	3
+
+#define CSS_CPU_PWR_STATE_ON		1
+#define CSS_CPU_PWR_STATE_OFF		0
+#define CSS_CPU_PWR_STATE(state, n)	(((state) >> (n)) & 1)
+
+#endif /* CSS_DEF_H */
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
new file mode 100644
index 0000000..b82ff47
--- /dev/null
+++ b/include/plat/arm/css/common/css_pm.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CSS_PM_H
+#define CSS_PM_H
+
+#include <cdefs.h>
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+
+/* Macros to read the CSS power domain state */
+#define CSS_CORE_PWR_STATE(state)	(state)->pwr_domain_state[ARM_PWR_LVL0]
+#define CSS_CLUSTER_PWR_STATE(state)	(state)->pwr_domain_state[ARM_PWR_LVL1]
+
+static inline unsigned int css_system_pwr_state(const psci_power_state_t *state)
+{
+#if (PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL)
+	return state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL];
+#else
+	return 0;
+#endif
+}
+
+int css_pwr_domain_on(u_register_t mpidr);
+void css_pwr_domain_on_finish(const psci_power_state_t *target_state);
+void css_pwr_domain_off(const psci_power_state_t *target_state);
+void css_pwr_domain_suspend(const psci_power_state_t *target_state);
+void css_pwr_domain_suspend_finish(
+				const psci_power_state_t *target_state);
+void __dead2 css_system_off(void);
+void __dead2 css_system_reset(void);
+void css_cpu_standby(plat_local_state_t cpu_state);
+void css_get_sys_suspend_power_state(psci_power_state_t *req_state);
+int css_node_hw_state(u_register_t mpidr, unsigned int power_level);
+
+/*
+ * This mapping array has to be exported by the platform. Each element at
+ * a given index maps that core to an SCMI power domain.
+ */
+extern const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[];
+
+#endif /* CSS_PM_H */
diff --git a/include/plat/arm/soc/common/soc_css.h b/include/plat/arm/soc/common/soc_css.h
new file mode 100644
index 0000000..469928d
--- /dev/null
+++ b/include/plat/arm/soc/common/soc_css.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_CSS_H
+#define SOC_CSS_H
+
+/*
+ * Utility functions for ARM CSS SoCs
+ */
+void soc_css_init_nic400(void);
+void soc_css_init_pcie(void);
+
+static inline void soc_css_security_setup(void)
+{
+	soc_css_init_nic400();
+	soc_css_init_pcie();
+}
+
+#endif /* SOC_CSS_H */
diff --git a/include/plat/arm/soc/common/soc_css_def.h b/include/plat/arm/soc/common/soc_css_def.h
new file mode 100644
index 0000000..b4b6ba8
--- /dev/null
+++ b/include/plat/arm/soc/common/soc_css_def.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_CSS_DEF_H
+#define SOC_CSS_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/*
+ * Definitions common to all ARM CSS SoCs
+ */
+
+/* Following covers ARM CSS SoC Peripherals and PCIe expansion area */
+#define SOC_CSS_DEVICE_BASE		0x40000000
+#define SOC_CSS_DEVICE_SIZE		0x40000000
+#define SOC_CSS_PCIE_CONTROL_BASE	0x7ff20000
+
+/* PL011 UART related constants */
+#define SOC_CSS_UART0_BASE		0x7ff80000
+#define SOC_CSS_UART1_BASE		0x7ff70000
+
+#define SOC_CSS_UART0_CLK_IN_HZ		7372800
+#define SOC_CSS_UART1_CLK_IN_HZ		7372800
+
+/* SoC NIC-400 Global Programmers View (GPV) */
+#define SOC_CSS_NIC400_BASE		0x7fd00000
+
+#define SOC_CSS_NIC400_USB_EHCI		0
+#define SOC_CSS_NIC400_TLX_MASTER	1
+#define SOC_CSS_NIC400_USB_OHCI		2
+#define SOC_CSS_NIC400_PL354_SMC	3
+/*
+ * The apb4_bridge controls access to:
+ *   - the PCIe configuration registers
+ *   - the MMU units for USB, HDLCD and DMA
+ */
+#define SOC_CSS_NIC400_APB4_BRIDGE	4
+
+/* Non-volatile counters */
+#define SOC_TRUSTED_NVCTR_BASE		0x7fe70000
+#define TFW_NVCTR_BASE			(SOC_TRUSTED_NVCTR_BASE + 0x0000)
+#define TFW_NVCTR_SIZE			4
+#define NTFW_CTR_BASE			(SOC_TRUSTED_NVCTR_BASE + 0x0004)
+#define NTFW_CTR_SIZE			4
+
+/* Keys */
+#define SOC_KEYS_BASE			0x7fe80000
+#define TZ_PUB_KEY_HASH_BASE		(SOC_KEYS_BASE + 0x0000)
+#define TZ_PUB_KEY_HASH_SIZE		32
+#define HU_KEY_BASE			(SOC_KEYS_BASE + 0x0020)
+#define HU_KEY_SIZE			16
+#define END_KEY_BASE			(SOC_KEYS_BASE + 0x0044)
+#define END_KEY_SIZE			32
+
+#define SOC_CSS_MAP_DEVICE		MAP_REGION_FLAT(		\
+						SOC_CSS_DEVICE_BASE,	\
+						SOC_CSS_DEVICE_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+
+/*
+ * The bootsec_bridge controls access to a bunch of peripherals, e.g. the UARTs.
+ */
+#define SOC_CSS_NIC400_BOOTSEC_BRIDGE	5
+#define SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1	(1 << 12)
+
+/*
+ * Required platform porting definitions common to all ARM CSS SoCs
+ */
+#if JUNO_AARCH32_EL3_RUNTIME
+/*
+ * Following change is required to initialize TZC
+ * for enabling access to the HI_VECTOR (0xFFFF0000)
+ * location needed for JUNO AARCH32 support.
+ */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE	ULL(0x8000)
+#else
+/* 2MB used for SCP DDR retraining */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE	ULL(0x00200000)
+#endif
+
+#endif /* SOC_CSS_DEF_H */
diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h
new file mode 100644
index 0000000..14ae603
--- /dev/null
+++ b/include/plat/common/common_def.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef COMMON_DEF_H
+#define COMMON_DEF_H
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/******************************************************************************
+ * Required platform porting definitions that are expected to be common to
+ * all platforms
+ *****************************************************************************/
+
+/*
+ * Platform binary types for linking
+ */
+#ifdef __aarch64__
+#define PLATFORM_LINKER_FORMAT          "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH            aarch64
+#else
+#define PLATFORM_LINKER_FORMAT          "elf32-littlearm"
+#define PLATFORM_LINKER_ARCH            arm
+#endif /* __aarch64__ */
+
+/*
+ * Generic platform constants
+ */
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define BL2_IMAGE_DESC {				\
+	.image_id = BL2_IMAGE_ID,			\
+	SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,	\
+		VERSION_2, image_info_t, 0),		\
+	.image_info.image_base = BL2_BASE,		\
+	.image_info.image_max_size = BL2_LIMIT - BL2_BASE,\
+	SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,	\
+		VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),\
+	.ep_info.pc = BL2_BASE,				\
+}
+
+/*
+ * The following constants identify the extents of the code & read-only data
+ * regions. These addresses are used by the MMU setup code and therefore they
+ * must be page-aligned.
+ *
+ * When the code and read-only data are mapped as a single atomic section
+ * (i.e. when SEPARATE_CODE_AND_RODATA=0) then we treat the whole section as
+ * code by specifying the read-only data section as empty.
+ *
+ * BL1 is different than the other images in the sense that its read-write data
+ * originally lives in Trusted ROM and needs to be relocated in Trusted SRAM at
+ * run-time. Therefore, the read-write data in ROM can be mapped with the same
+ * memory attributes as the read-only data region. For this reason, BL1 uses
+ * different macros.
+ *
+ * Note that BL1_ROM_END is not necessarily aligned on a page boundary as it
+ * just points to the end of BL1's actual content in Trusted ROM. Therefore it
+ * needs to be rounded up to the next page size in order to map the whole last
+ * page of it with the right memory attributes.
+ */
+#if SEPARATE_CODE_AND_RODATA
+
+#define BL1_CODE_END		BL_CODE_END
+#define BL1_RO_DATA_BASE	BL_RO_DATA_BASE
+#define BL1_RO_DATA_END		round_up(BL1_ROM_END, PAGE_SIZE)
+#if BL2_IN_XIP_MEM
+#define BL2_CODE_END		BL_CODE_END
+#define BL2_RO_DATA_BASE	BL_RO_DATA_BASE
+#define BL2_RO_DATA_END		round_up(BL2_ROM_END, PAGE_SIZE)
+#endif /* BL2_IN_XIP_MEM */
+#else
+#define BL_RO_DATA_BASE		UL(0)
+#define BL_RO_DATA_END		UL(0)
+#define BL1_CODE_END		round_up(BL1_ROM_END, PAGE_SIZE)
+#if BL2_IN_XIP_MEM
+#define BL2_RO_DATA_BASE	UL(0)
+#define BL2_RO_DATA_END		UL(0)
+#define BL2_CODE_END		round_up(BL2_ROM_END, PAGE_SIZE)
+#endif /* BL2_IN_XIP_MEM */
+#endif /* SEPARATE_CODE_AND_RODATA */
+
+#endif /* COMMON_DEF_H */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
new file mode 100644
index 0000000..3f9ab1b
--- /dev/null
+++ b/include/plat/common/platform.h
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+struct auth_img_desc_s;
+struct meminfo;
+struct image_info;
+struct entry_point_info;
+struct image_desc;
+struct bl_load_info;
+struct bl_params;
+struct mmap_region;
+struct secure_partition_boot_info;
+struct sp_res_desc;
+
+/*******************************************************************************
+ * plat_get_rotpk_info() flags
+ ******************************************************************************/
+#define ROTPK_IS_HASH			(1 << 0)
+/* Flag used to skip verification of the certificate ROTPK while the platform
+   ROTPK is not deployed */
+#define ROTPK_NOT_DEPLOYED		(1 << 1)
+
+/*******************************************************************************
+ * Function declarations
+ ******************************************************************************/
+/*******************************************************************************
+ * Mandatory common functions
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void);
+
+int plat_get_image_source(unsigned int image_id,
+			uintptr_t *dev_handle,
+			uintptr_t *image_spec);
+uintptr_t plat_get_ns_image_entrypoint(void);
+unsigned int plat_my_core_pos(void);
+int plat_core_pos_by_mpidr(u_register_t mpidr);
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size);
+
+#if STACK_PROTECTOR_ENABLED
+/*
+ * Return a new value to be used for the stack protection's canary.
+ *
+ * Ideally, this value is a random number that is impossible to predict by an
+ * attacker.
+ */
+u_register_t plat_get_stack_protector_canary(void);
+#endif /* STACK_PROTECTOR_ENABLED */
+
+/*******************************************************************************
+ * Mandatory interrupt management functions
+ ******************************************************************************/
+uint32_t plat_ic_get_pending_interrupt_id(void);
+uint32_t plat_ic_get_pending_interrupt_type(void);
+uint32_t plat_ic_acknowledge_interrupt(void);
+uint32_t plat_ic_get_interrupt_type(uint32_t id);
+void plat_ic_end_of_interrupt(uint32_t id);
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+				     uint32_t security_state);
+
+/*******************************************************************************
+ * Optional interrupt management functions, depending on chosen EL3 components.
+ ******************************************************************************/
+unsigned int plat_ic_get_running_priority(void);
+int plat_ic_is_spi(unsigned int id);
+int plat_ic_is_ppi(unsigned int id);
+int plat_ic_is_sgi(unsigned int id);
+unsigned int plat_ic_get_interrupt_active(unsigned int id);
+void plat_ic_disable_interrupt(unsigned int id);
+void plat_ic_enable_interrupt(unsigned int id);
+int plat_ic_has_interrupt_type(unsigned int type);
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type);
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority);
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target);
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+		u_register_t mpidr);
+void plat_ic_set_interrupt_pending(unsigned int id);
+void plat_ic_clear_interrupt_pending(unsigned int id);
+unsigned int plat_ic_set_priority_mask(unsigned int mask);
+unsigned int plat_ic_get_interrupt_id(unsigned int raw);
+
+/*******************************************************************************
+ * Optional common functions (may be overridden)
+ ******************************************************************************/
+uintptr_t plat_get_my_stack(void);
+void plat_report_exception(unsigned int exception_type);
+int plat_crash_console_init(void);
+int plat_crash_console_putc(int c);
+int plat_crash_console_flush(void);
+void plat_error_handler(int err) __dead2;
+void plat_panic_handler(void) __dead2;
+const char *plat_log_get_prefix(unsigned int log_level);
+void bl2_plat_preload_setup(void);
+int plat_try_next_boot_source(void);
+uint64_t *plat_init_apiakey(void);
+
+/*******************************************************************************
+ * Mandatory BL1 functions
+ ******************************************************************************/
+void bl1_early_platform_setup(void);
+void bl1_plat_arch_setup(void);
+void bl1_platform_setup(void);
+struct meminfo *bl1_plat_sec_mem_layout(void);
+
+/*******************************************************************************
+ * Optional EL3 component functions in BL31
+ ******************************************************************************/
+
+/* SDEI platform functions */
+#if SDEI_SUPPORT
+int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode);
+void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr);
+#endif
+
+void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+		void *handle, uint64_t flags);
+
+/*
+ * The following function is mandatory when the
+ * firmware update feature is used.
+ */
+int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size,
+		unsigned int flags);
+
+/*******************************************************************************
+ * Optional BL1 functions (may be overridden)
+ ******************************************************************************/
+/*
+ * The following functions are used for image loading process in BL1.
+ */
+void bl1_plat_set_ep_info(unsigned int image_id,
+		struct entry_point_info *ep_info);
+/*
+ * The following functions are mandatory when firmware update
+ * feature is used and optional otherwise.
+ */
+unsigned int bl1_plat_get_next_image_id(void);
+struct image_desc *bl1_plat_get_image_desc(unsigned int image_id);
+
+/*
+ * The following functions are used by firmware update
+ * feature and may optionally be overridden.
+ */
+__dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved);
+
+/*
+ * This BL1 function can be used by the platforms to update/use image
+ * information for a given `image_id`.
+ */
+int bl1_plat_handle_pre_image_load(unsigned int image_id);
+int bl1_plat_handle_post_image_load(unsigned int image_id);
+
+/*******************************************************************************
+ * Mandatory BL2 functions
+ ******************************************************************************/
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3);
+void bl2_plat_arch_setup(void);
+void bl2_platform_setup(void);
+struct meminfo *bl2_plat_sec_mem_layout(void);
+
+/*
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ */
+int bl2_plat_handle_pre_image_load(unsigned int image_id);
+int bl2_plat_handle_post_image_load(unsigned int image_id);
+
+
+/*******************************************************************************
+ * Optional BL2 functions (may be overridden)
+ ******************************************************************************/
+
+
+/*******************************************************************************
+ * Mandatory BL2 at EL3 functions: Must be implemented if BL2_AT_EL3 image is
+ * supported
+ ******************************************************************************/
+void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1,
+				  u_register_t arg2, u_register_t arg3);
+void bl2_el3_plat_arch_setup(void);
+
+
+/*******************************************************************************
+ * Optional BL2 at EL3 functions (may be overridden)
+ ******************************************************************************/
+void bl2_el3_plat_prepare_exit(void);
+
+/*******************************************************************************
+ * Mandatory BL2U functions.
+ ******************************************************************************/
+void bl2u_early_platform_setup(struct meminfo *mem_layout,
+		void *plat_info);
+void bl2u_plat_arch_setup(void);
+void bl2u_platform_setup(void);
+
+/*******************************************************************************
+ * Conditionally mandatory BL2U functions for CSS platforms.
+ ******************************************************************************/
+/*
+ * This function is used to perform any platform-specific actions required to
+ * handle the BL2U_SCP firmware.
+ */
+int bl2u_plat_handle_scp_bl2u(void);
+
+/*******************************************************************************
+ * Mandatory BL31 functions
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3);
+void bl31_plat_arch_setup(void);
+void bl31_platform_setup(void);
+void bl31_plat_runtime_setup(void);
+struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type);
+
+/*******************************************************************************
+ * Mandatory PSCI functions (BL31)
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops);
+const unsigned char *plat_get_power_domain_tree_desc(void);
+
+/*******************************************************************************
+ * Optional PSCI functions (BL31).
+ ******************************************************************************/
+void plat_psci_stat_accounting_start(const psci_power_state_t *state_info);
+void plat_psci_stat_accounting_stop(const psci_power_state_t *state_info);
+u_register_t plat_psci_stat_get_residency(unsigned int lvl,
+			const psci_power_state_t *state_info,
+			int last_cpu_idx);
+plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
+			const plat_local_state_t *states,
+			unsigned int ncpu);
+
+/*******************************************************************************
+ * Optional BL31 functions (may be overridden)
+ ******************************************************************************/
+void bl31_plat_enable_mmu(uint32_t flags);
+
+/*******************************************************************************
+ * Optional BL32 functions (may be overridden)
+ ******************************************************************************/
+void bl32_plat_enable_mmu(uint32_t flags);
+
+/*******************************************************************************
+ * Trusted Board Boot functions
+ ******************************************************************************/
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags);
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr);
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr);
+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);
+
+/*******************************************************************************
+ * Secure Partitions functions
+ ******************************************************************************/
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie);
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie);
+int plat_spm_sp_rd_load(struct sp_res_desc *rd, const void *ptr, size_t size);
+int plat_spm_sp_get_next_address(void **sp_base, size_t *sp_size,
+				 void **rd_base, size_t *rd_size);
+
+/*******************************************************************************
+ * Mandatory BL image load functions(may be overridden).
+ ******************************************************************************/
+/*
+ * This function returns pointer to the list of images that the
+ * platform has populated to load.
+ */
+struct bl_load_info *plat_get_bl_image_load_info(void);
+
+/*
+ * This function returns a pointer to the shared memory that the
+ * platform has kept aside to pass trusted firmware related
+ * information that next BL image could need.
+ */
+struct bl_params *plat_get_next_bl_params(void);
+
+/*
+ * This function flushes to main memory all the params that are
+ * passed to next image.
+ */
+void plat_flush_next_bl_params(void);
+
+/*
+ * The below function enable Trusted Firmware components like SPDs which
+ * haven't migrated to the new platform API to compile on platforms which
+ * have the compatibility layer disabled.
+ */
+unsigned int platform_core_pos_helper(unsigned long mpidr);
+
+#endif /* PLATFORM_H */
diff --git a/include/plat/marvell/a3700/common/armada_common.h b/include/plat/marvell/a3700/common/armada_common.h
new file mode 100644
index 0000000..c6953fb
--- /dev/null
+++ b/include/plat/marvell/a3700/common/armada_common.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef ARMADA_COMMON_H
+#define ARMADA_COMMON_H
+
+#include <stdint.h>
+
+#include <io_addr_dec.h>
+
+int marvell_get_io_dec_win_conf(struct dec_win_config **win, uint32_t *size);
+
+#endif /* ARMADA_COMMON_H */
diff --git a/include/plat/marvell/a3700/common/board_marvell_def.h b/include/plat/marvell/a3700/common/board_marvell_def.h
new file mode 100644
index 0000000..1782596
--- /dev/null
+++ b/include/plat/marvell/a3700/common/board_marvell_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef BOARD_MARVELL_DEF_H
+#define BOARD_MARVELL_DEF_H
+
+/*
+ * Required platform porting definitions common to all ARM
+ * development platforms
+ */
+
+/* Size of cacheable stacks */
+#if IMAGE_BL1
+#if TRUSTED_BOARD_BOOT
+# define PLATFORM_STACK_SIZE 0x1000
+#else
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+#elif IMAGE_BL2
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif IMAGE_BL31
+# define PLATFORM_STACK_SIZE 0x400
+#elif IMAGE_BL32
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/*
+ * PLAT_MARVELL_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if IMAGE_BLE
+#  define PLAT_MARVELL_MMAP_ENTRIES	3
+#endif
+#if IMAGE_BL1
+#  if TRUSTED_BOARD_BOOT
+#   define PLAT_MARVELL_MMAP_ENTRIES	7
+#  else
+#   define PLAT_MARVELL_MMAP_ENTRIES	6
+#  endif	/* TRUSTED_BOARD_BOOT */
+#endif
+#if IMAGE_BL2
+#  define PLAT_MARVELL_MMAP_ENTRIES	8
+#endif
+#if IMAGE_BL31
+#define PLAT_MARVELL_MMAP_ENTRIES	5
+#endif
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#if IMAGE_BL1
+#define MAX_XLAT_TABLES			4
+#elif IMAGE_BLE
+#  define MAX_XLAT_TABLES		4
+#elif IMAGE_BL2
+#  define MAX_XLAT_TABLES		4
+#elif IMAGE_BL31
+# define MAX_XLAT_TABLES		4
+#elif IMAGE_BL32
+#  define MAX_XLAT_TABLES		4
+#endif
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+#define PLAT_MARVELL_TRUSTED_SRAM_SIZE	0x80000	/* 512 KB */
+
+#endif /* BOARD_MARVELL_DEF_H */
diff --git a/include/plat/marvell/a3700/common/marvell_def.h b/include/plat/marvell/a3700/common/marvell_def.h
new file mode 100644
index 0000000..eb13ba8
--- /dev/null
+++ b/include/plat/marvell/a3700/common/marvell_def.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MARVELL_DEF_H
+#define MARVELL_DEF_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+
+/****************************************************************************
+ * Definitions common to all MARVELL standard platforms
+ ****************************************************************************
+ */
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define MARVELL_BL31_PLAT_PARAM_VAL		0x0f1e2d3c4b5a6978ULL
+
+#define PLAT_MARVELL_NORTHB_COUNT		1
+
+#define PLAT_MARVELL_CLUSTER_COUNT		1
+
+#define MARVELL_CACHE_WRITEBACK_SHIFT		6
+
+/*
+ * Macros mapping the MPIDR Affinity levels to MARVELL Platform Power levels.
+ * The power levels have a 1:1 mapping with the MPIDR affinity levels.
+ */
+#define MARVELL_PWR_LVL0		MPIDR_AFFLVL0
+#define MARVELL_PWR_LVL1		MPIDR_AFFLVL1
+#define MARVELL_PWR_LVL2		MPIDR_AFFLVL2
+
+/*
+ *  Macros for local power states in Marvell platforms encoded by State-ID field
+ *  within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define MARVELL_LOCAL_STATE_RUN	0
+/* Local power state for retention. Valid only for CPU power domains */
+#define MARVELL_LOCAL_STATE_RET	1
+/* Local power state for OFF/power-down.
+ * Valid for CPU and cluster power domains
+ */
+#define MARVELL_LOCAL_STATE_OFF	2
+
+/* The first 4KB of Trusted SRAM are used as shared memory */
+#define MARVELL_TRUSTED_SRAM_BASE	PLAT_MARVELL_ATF_BASE
+#define MARVELL_SHARED_RAM_BASE		MARVELL_TRUSTED_SRAM_BASE
+#define MARVELL_SHARED_RAM_SIZE		0x00001000	/* 4 KB */
+
+/* The remaining Trusted SRAM is used to load the BL images */
+#define MARVELL_BL_RAM_BASE		(MARVELL_SHARED_RAM_BASE + \
+					 MARVELL_SHARED_RAM_SIZE)
+#define MARVELL_BL_RAM_SIZE		(PLAT_MARVELL_TRUSTED_SRAM_SIZE - \
+					 MARVELL_SHARED_RAM_SIZE)
+
+#define MARVELL_DRAM_BASE		ULL(0x0)
+#define MARVELL_DRAM_SIZE		ULL(0x20000000)
+#define MARVELL_DRAM_END		(MARVELL_DRAM_BASE + \
+					 MARVELL_DRAM_SIZE - 1)
+
+#define MARVELL_IRQ_SEC_PHY_TIMER		29
+
+#define MARVELL_IRQ_SEC_SGI_0		8
+#define MARVELL_IRQ_SEC_SGI_1		9
+#define MARVELL_IRQ_SEC_SGI_2		10
+#define MARVELL_IRQ_SEC_SGI_3		11
+#define MARVELL_IRQ_SEC_SGI_4		12
+#define MARVELL_IRQ_SEC_SGI_5		13
+#define MARVELL_IRQ_SEC_SGI_6		14
+#define MARVELL_IRQ_SEC_SGI_7		15
+
+#define MARVELL_MAP_SHARED_RAM		MAP_REGION_FLAT(		 \
+						MARVELL_SHARED_RAM_BASE, \
+						MARVELL_SHARED_RAM_SIZE, \
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MARVELL_MAP_DRAM		MAP_REGION_FLAT(		\
+						MARVELL_DRAM_BASE,	\
+						MARVELL_DRAM_SIZE,	\
+						MT_MEMORY | MT_RW | MT_NS)
+
+
+/*
+ * The number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+#if USE_COHERENT_MEM
+#define MARVELL_BL_REGIONS		3
+#else
+#define MARVELL_BL_REGIONS		2
+#endif
+
+#define MAX_MMAP_REGIONS		(PLAT_MARVELL_MMAP_ENTRIES + \
+					 MARVELL_BL_REGIONS)
+
+#define MARVELL_CONSOLE_BAUDRATE	115200
+
+/****************************************************************************
+ * Required platform porting definitions common to all MARVELL std. platforms
+ ****************************************************************************
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		MARVELL_LOCAL_STATE_RET
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		MARVELL_LOCAL_STATE_OFF
+
+
+#define PLATFORM_CORE_COUNT		PLAT_MARVELL_CLUSTER_CORE_COUNT
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE		(1 << MARVELL_CACHE_WRITEBACK_SHIFT)
+
+
+/*****************************************************************************
+ * BL1 specific defines.
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ *****************************************************************************
+ */
+#define BL1_RO_BASE		PLAT_MARVELL_TRUSTED_ROM_BASE
+#define BL1_RO_LIMIT		(PLAT_MARVELL_TRUSTED_ROM_BASE	\
+					+ PLAT_MARVELL_TRUSTED_ROM_SIZE)
+/*
+ * Put BL1 RW at the top of the Trusted SRAM.
+ */
+#define BL1_RW_BASE		(MARVELL_BL_RAM_BASE +		\
+					MARVELL_BL_RAM_SIZE -	\
+					PLAT_MARVELL_MAX_BL1_RW_SIZE)
+#define BL1_RW_LIMIT		(MARVELL_BL_RAM_BASE + MARVELL_BL_RAM_SIZE)
+
+/*****************************************************************************
+ * BL2 specific defines.
+ *****************************************************************************
+ */
+/*
+ * Put BL2 just below BL31.
+ */
+#define BL2_BASE		(BL31_BASE - PLAT_MARVELL_MAX_BL2_SIZE)
+#define BL2_LIMIT		BL31_BASE
+
+/*****************************************************************************
+ * BL31 specific defines.
+ *****************************************************************************
+ */
+/*
+ * Put BL31 at the top of the Trusted SRAM.
+ */
+#define BL31_BASE		(MARVELL_BL_RAM_BASE + \
+					MARVELL_BL_RAM_SIZE - \
+					PLAT_MARVEL_MAX_BL31_SIZE)
+#define BL31_PROGBITS_LIMIT	BL1_RW_BASE
+#define BL31_LIMIT			(MARVELL_BL_RAM_BASE +	\
+					 MARVELL_BL_RAM_SIZE)
+
+
+#endif /* MARVELL_DEF_H */
diff --git a/include/plat/marvell/a3700/common/plat_marvell.h b/include/plat/marvell/a3700/common/plat_marvell.h
new file mode 100644
index 0000000..ea7cdcd
--- /dev/null
+++ b/include/plat/marvell/a3700/common/plat_marvell.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLAT_MARVELL_H
+#define PLAT_MARVELL_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * Extern declarations common to Marvell standard platforms
+ */
+extern const mmap_region_t plat_marvell_mmap[];
+
+#define MARVELL_CASSERT_MMAP						\
+	CASSERT((ARRAY_SIZE(plat_marvell_mmap) + MARVELL_BL_REGIONS)	\
+		<= MAX_MMAP_REGIONS,					\
+		assert_max_mmap_regions)
+
+/*
+ * Utility functions common to Marvell standard platforms
+ */
+void marvell_setup_page_tables(uintptr_t total_base,
+			       size_t total_size,
+			       uintptr_t code_start,
+			       uintptr_t code_limit,
+			       uintptr_t rodata_start,
+			       uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			     , uintptr_t coh_start,
+			       uintptr_t coh_limit
+#endif
+);
+
+/* Console utility functions */
+void marvell_console_boot_init(void);
+void marvell_console_boot_end(void);
+void marvell_console_runtime_init(void);
+void marvell_console_runtime_end(void);
+
+/* IO storage utility functions */
+void marvell_io_setup(void);
+
+/* Systimer utility function */
+void marvell_configure_sys_timer(void);
+
+/* Topology utility function */
+int marvell_check_mpidr(u_register_t mpidr);
+
+/* BL1 utility functions */
+void marvell_bl1_early_platform_setup(void);
+void marvell_bl1_platform_setup(void);
+void marvell_bl1_plat_arch_setup(void);
+
+/* BL2 utility functions */
+void marvell_bl2_early_platform_setup(meminfo_t *mem_layout);
+void marvell_bl2_platform_setup(void);
+void marvell_bl2_plat_arch_setup(void);
+uint32_t marvell_get_spsr_for_bl32_entry(void);
+uint32_t marvell_get_spsr_for_bl33_entry(void);
+
+/* BL31 utility functions */
+void marvell_bl31_early_platform_setup(void *from_bl2,
+				       uintptr_t soc_fw_config,
+				       uintptr_t hw_config,
+				       void *plat_params_from_bl2);
+void marvell_bl31_platform_setup(void);
+void marvell_bl31_plat_runtime_setup(void);
+void marvell_bl31_plat_arch_setup(void);
+
+/* FIP TOC validity check */
+int marvell_io_is_toc_valid(void);
+
+/*
+ * PSCI functionality
+ */
+void marvell_psci_arch_init(int idx);
+void plat_marvell_system_reset(void);
+
+/*
+ * Optional functions required in Marvell standard platforms
+ */
+void plat_marvell_io_setup(void);
+int plat_marvell_get_alt_image_source(
+	unsigned int image_id,
+	uintptr_t *dev_handle,
+	uintptr_t *image_spec);
+unsigned int plat_marvell_calc_core_pos(u_register_t mpidr);
+
+void plat_marvell_interconnect_init(void);
+void plat_marvell_interconnect_enter_coherency(void);
+
+const mmap_region_t *plat_marvell_get_mmap(void);
+
+#endif /* PLAT_MARVELL_H */
diff --git a/include/plat/marvell/a8k/common/armada_common.h b/include/plat/marvell/a8k/common/armada_common.h
new file mode 100644
index 0000000..dd2a24a
--- /dev/null
+++ b/include/plat/marvell/a8k/common/armada_common.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef ARMADA_COMMON_H
+#define ARMADA_COMMON_H
+
+#include <drivers/marvell/amb_adec.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/iob.h>
+
+/*
+ * This struct supports skip image request
+ * detection_method: the method used to detect the request "signal".
+ * info:
+ *	GPIO:
+ *		detection_method: HIGH (pressed button), LOW (unpressed button),
+ *		num (button mpp number).
+ *	i2c:
+ *		i2c_addr: the address of the i2c chosen.
+ *		i2d_reg: the i2c register chosen.
+ *	test:
+ *		choose the DIE you picked the button in (AP or CP).
+ *		in case of CP(cp_index = 0 if CP0, cp_index = 1 if CP1)
+ */
+struct skip_image {
+	enum {
+		GPIO,
+		I2C,
+		USER_DEFINED
+	} detection_method;
+
+	struct {
+		struct {
+			int num;
+			enum {
+				HIGH,
+				LOW
+			} button_state;
+
+		} gpio;
+
+		struct {
+			int i2c_addr;
+			int i2c_reg;
+		} i2c;
+
+		struct {
+			enum {
+				CP,
+				AP
+			} cp_ap;
+			int cp_index;
+		} test;
+	} info;
+};
+
+/*
+ * This struct supports SoC power off method
+ * type: the method used to power off the SoC
+ * cfg:
+ *	PMIC_GPIO:
+ *	pin_count: current GPIO pin number used for toggling the signal for
+ *		   notifying external PMIC
+ *	info:	   holds the GPIOs information, CP GPIO should be used and
+ *		   all GPIOs should be within same GPIO config. register
+ *	step_count: current step number to toggle the GPIO for PMIC
+ *	seq:       GPIO toggling values in sequence, each bit represents a GPIO.
+ *		   For example, bit0 represents first GPIO used for toggling
+ *		   the GPIO the last step is used to trigger the power off
+ *		   signal
+ *	delay_ms:  transition interval for the GPIO setting to take effect
+ *		   in unit of ms
+ */
+/* Max GPIO number used to notify PMIC to power off the SoC */
+#define PMIC_GPIO_MAX_NUMBER		8
+/* Max GPIO toggling steps in sequence to power off the SoC */
+#define PMIC_GPIO_MAX_TOGGLE_STEP	8
+
+enum gpio_output_state {
+	GPIO_LOW = 0,
+	GPIO_HIGH
+};
+
+typedef struct gpio_info {
+	int cp_index;
+	int gpio_index;
+} gpio_info_t;
+
+struct power_off_method {
+	enum {
+		PMIC_GPIO,
+	} type;
+
+	struct {
+		struct {
+			int pin_count;
+			struct gpio_info info[PMIC_GPIO_MAX_NUMBER];
+			int step_count;
+			uint32_t seq[PMIC_GPIO_MAX_TOGGLE_STEP];
+			int delay_ms;
+		} gpio;
+	} cfg;
+};
+
+int marvell_gpio_config(void);
+uint32_t marvell_get_io_win_gcr_target(int ap_idx);
+uint32_t marvell_get_ccu_gcr_target(int ap_idx);
+
+
+/*
+ * The functions below are defined as Weak and may be overridden
+ * in specific Marvell standard platform
+ */
+int marvell_get_amb_memory_map(struct addr_map_win **win,
+			       uint32_t *size, uintptr_t base);
+int marvell_get_io_win_memory_map(int ap_idx, struct addr_map_win **win,
+				  uint32_t *size);
+int marvell_get_iob_memory_map(struct addr_map_win **win,
+			       uint32_t *size, uintptr_t base);
+int marvell_get_ccu_memory_map(int ap_idx, struct addr_map_win **win,
+			       uint32_t *size);
+
+#endif /* ARMADA_COMMON_H */
diff --git a/include/plat/marvell/a8k/common/board_marvell_def.h b/include/plat/marvell/a8k/common/board_marvell_def.h
new file mode 100644
index 0000000..0da56e7
--- /dev/null
+++ b/include/plat/marvell/a8k/common/board_marvell_def.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef BOARD_MARVELL_DEF_H
+#define BOARD_MARVELL_DEF_H
+
+/*
+ * Required platform porting definitions common to all ARM
+ * development platforms
+ */
+
+/* Size of cacheable stacks */
+#if IMAGE_BL1
+#if TRUSTED_BOARD_BOOT
+# define PLATFORM_STACK_SIZE 0x1000
+#else
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+#elif IMAGE_BL2
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif IMAGE_BL31
+# define PLATFORM_STACK_SIZE 0x400
+#elif IMAGE_BL32
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/*
+ * PLAT_MARVELL_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if IMAGE_BLE
+#  define PLAT_MARVELL_MMAP_ENTRIES	3
+#endif
+#if IMAGE_BL1
+#  if TRUSTED_BOARD_BOOT
+#   define PLAT_MARVELL_MMAP_ENTRIES	7
+#  else
+#   define PLAT_MARVELL_MMAP_ENTRIES	6
+#  endif	/* TRUSTED_BOARD_BOOT */
+#endif
+#if IMAGE_BL2
+#  define PLAT_MARVELL_MMAP_ENTRIES		8
+#endif
+#if IMAGE_BL31
+#define PLAT_MARVELL_MMAP_ENTRIES		5
+#endif
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#if IMAGE_BL1
+#define MAX_XLAT_TABLES			4
+#elif IMAGE_BLE
+#  define MAX_XLAT_TABLES		4
+#elif IMAGE_BL2
+#  define MAX_XLAT_TABLES		4
+#elif IMAGE_BL31
+# define MAX_XLAT_TABLES		4
+#elif IMAGE_BL32
+#  define MAX_XLAT_TABLES               4
+#endif
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+#define PLAT_MARVELL_TRUSTED_SRAM_SIZE	0x80000	/* 512 KB */
+
+
+#endif /* BOARD_MARVELL_DEF_H */
diff --git a/include/plat/marvell/a8k/common/marvell_def.h b/include/plat/marvell/a8k/common/marvell_def.h
new file mode 100644
index 0000000..4eda01f
--- /dev/null
+++ b/include/plat/marvell/a8k/common/marvell_def.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MARVELL_DEF_H
+#define MARVELL_DEF_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+
+/******************************************************************************
+ * Definitions common to all MARVELL standard platforms
+ *****************************************************************************/
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define MARVELL_BL31_PLAT_PARAM_VAL		0x0f1e2d3c4b5a6978ULL
+
+
+#define MARVELL_CACHE_WRITEBACK_SHIFT	6
+
+/*
+ * Macros mapping the MPIDR Affinity levels to MARVELL Platform Power levels.
+ * The power levels have a 1:1 mapping with the MPIDR affinity levels.
+ */
+#define MARVELL_PWR_LVL0		MPIDR_AFFLVL0
+#define MARVELL_PWR_LVL1		MPIDR_AFFLVL1
+#define MARVELL_PWR_LVL2		MPIDR_AFFLVL2
+
+/*
+ *  Macros for local power states in Marvell platforms encoded by
+ *  State-ID field within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define MARVELL_LOCAL_STATE_RUN	0
+/* Local power state for retention. Valid only for CPU power domains */
+#define MARVELL_LOCAL_STATE_RET	1
+/*
+ * Local power state for OFF/power-down. Valid for CPU
+ * and cluster power domains
+ */
+#define MARVELL_LOCAL_STATE_OFF	2
+
+/* The first 4KB of Trusted SRAM are used as shared memory */
+#define MARVELL_TRUSTED_SRAM_BASE	PLAT_MARVELL_ATF_BASE
+#define MARVELL_SHARED_RAM_BASE		MARVELL_TRUSTED_SRAM_BASE
+#define MARVELL_SHARED_RAM_SIZE		0x00001000	/* 4 KB */
+
+/* The remaining Trusted SRAM is used to load the BL images */
+#define MARVELL_BL_RAM_BASE		(MARVELL_SHARED_RAM_BASE +	\
+					 MARVELL_SHARED_RAM_SIZE)
+#define MARVELL_BL_RAM_SIZE		(PLAT_MARVELL_TRUSTED_SRAM_SIZE - \
+					 MARVELL_SHARED_RAM_SIZE)
+/* Non-shared DRAM */
+#define MARVELL_DRAM_BASE		ULL(0x0)
+#define MARVELL_DRAM_SIZE		ULL(0x80000000)
+#define MARVELL_DRAM_END		(MARVELL_DRAM_BASE + \
+					 MARVELL_DRAM_SIZE - 1)
+
+#define MARVELL_IRQ_PIC0		28
+#define MARVELL_IRQ_SEC_PHY_TIMER	29
+
+#define MARVELL_IRQ_SEC_SGI_0		8
+#define MARVELL_IRQ_SEC_SGI_1		9
+#define MARVELL_IRQ_SEC_SGI_2		10
+#define MARVELL_IRQ_SEC_SGI_3		11
+#define MARVELL_IRQ_SEC_SGI_4		12
+#define MARVELL_IRQ_SEC_SGI_5		13
+#define MARVELL_IRQ_SEC_SGI_6		14
+#define MARVELL_IRQ_SEC_SGI_7		15
+
+#define MARVELL_MAP_SHARED_RAM		MAP_REGION_FLAT(		\
+						MARVELL_SHARED_RAM_BASE,\
+						MARVELL_SHARED_RAM_SIZE,\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MARVELL_MAP_DRAM		MAP_REGION_FLAT(		\
+						MARVELL_DRAM_BASE,	\
+						MARVELL_DRAM_SIZE,	\
+						MT_MEMORY | MT_RW | MT_NS)
+
+
+/*
+ * The number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+#if USE_COHERENT_MEM
+#define MARVELL_BL_REGIONS		3
+#else
+#define MARVELL_BL_REGIONS		2
+#endif
+
+#define MAX_MMAP_REGIONS		(PLAT_MARVELL_MMAP_ENTRIES +	\
+					 MARVELL_BL_REGIONS)
+
+#define MARVELL_CONSOLE_BAUDRATE	115200
+
+/******************************************************************************
+ * Required platform porting definitions common to all MARVELL std. platforms
+ *****************************************************************************/
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		MARVELL_LOCAL_STATE_RET
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		MARVELL_LOCAL_STATE_OFF
+
+
+#define PLATFORM_CORE_COUNT		PLAT_MARVELL_CORE_COUNT
+#define PLAT_NUM_PWR_DOMAINS		(PLAT_MARVELL_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE		(1 << MARVELL_CACHE_WRITEBACK_SHIFT)
+
+
+/*******************************************************************************
+ * BL1 specific defines.
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ ******************************************************************************/
+#define BL1_RO_BASE			PLAT_MARVELL_TRUSTED_ROM_BASE
+#define BL1_RO_LIMIT			(PLAT_MARVELL_TRUSTED_ROM_BASE	\
+					 + PLAT_MARVELL_TRUSTED_ROM_SIZE)
+/*
+ * Put BL1 RW at the top of the Trusted SRAM.
+ */
+#define BL1_RW_BASE		(MARVELL_BL_RAM_BASE +		\
+					MARVELL_BL_RAM_SIZE -	\
+					PLAT_MARVELL_MAX_BL1_RW_SIZE)
+#define BL1_RW_LIMIT		(MARVELL_BL_RAM_BASE + MARVELL_BL_RAM_SIZE)
+
+/*******************************************************************************
+ * BLE specific defines.
+ ******************************************************************************/
+#define BLE_BASE			PLAT_MARVELL_SRAM_BASE
+#define BLE_LIMIT			PLAT_MARVELL_SRAM_END
+
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL2 just below BL31.
+ */
+#define BL2_BASE			(BL31_BASE - PLAT_MARVELL_MAX_BL2_SIZE)
+#define BL2_LIMIT			BL31_BASE
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM.
+ */
+#define BL31_BASE			(MARVELL_BL_RAM_BASE +		\
+						MARVELL_BL_RAM_SIZE -	\
+						PLAT_MARVEL_MAX_BL31_SIZE)
+#define BL31_PROGBITS_LIMIT		BL1_RW_BASE
+#define BL31_LIMIT			(MARVELL_BL_RAM_BASE +	\
+					 MARVELL_BL_RAM_SIZE)
+
+
+#endif /* MARVELL_DEF_H */
diff --git a/include/plat/marvell/a8k/common/plat_marvell.h b/include/plat/marvell/a8k/common/plat_marvell.h
new file mode 100644
index 0000000..5d805a7
--- /dev/null
+++ b/include/plat/marvell/a8k/common/plat_marvell.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLAT_MARVELL_H
+#define PLAT_MARVELL_H
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * Extern declarations common to Marvell standard platforms
+ */
+extern const mmap_region_t plat_marvell_mmap[];
+
+#define MARVELL_CASSERT_MMAP						\
+	CASSERT((ARRAY_SIZE(plat_marvell_mmap) + MARVELL_BL_REGIONS)	\
+		<= MAX_MMAP_REGIONS,					\
+		assert_max_mmap_regions)
+
+struct marvell_bl31_params {
+       param_header_t h;
+       image_info_t *bl31_image_info;
+       entry_point_info_t *bl32_ep_info;
+       image_info_t *bl32_image_info;
+       entry_point_info_t *bl33_ep_info;
+       image_info_t *bl33_image_info;
+};
+
+/*
+ * Utility functions common to Marvell standard platforms
+ */
+void marvell_setup_page_tables(uintptr_t total_base,
+			       size_t total_size,
+			       uintptr_t code_start,
+			       uintptr_t code_limit,
+			       uintptr_t rodata_start,
+			       uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			     , uintptr_t coh_start,
+			       uintptr_t coh_limit
+#endif
+);
+
+/* Console utility functions */
+void marvell_console_boot_init(void);
+void marvell_console_boot_end(void);
+void marvell_console_runtime_init(void);
+void marvell_console_runtime_end(void);
+
+/* IO storage utility functions */
+void marvell_io_setup(void);
+
+/* Systimer utility function */
+void marvell_configure_sys_timer(void);
+
+/* Topology utility function */
+int marvell_check_mpidr(u_register_t mpidr);
+
+/* BLE utility functions */
+int ble_plat_setup(int *skip);
+void plat_marvell_dram_update_topology(void);
+void ble_plat_pcie_ep_setup(void);
+struct pci_hw_cfg *plat_get_pcie_hw_data(void);
+
+/* BL1 utility functions */
+void marvell_bl1_early_platform_setup(void);
+void marvell_bl1_platform_setup(void);
+void marvell_bl1_plat_arch_setup(void);
+
+/* BL2 utility functions */
+void marvell_bl2_early_platform_setup(meminfo_t *mem_layout);
+void marvell_bl2_platform_setup(void);
+void marvell_bl2_plat_arch_setup(void);
+uint32_t marvell_get_spsr_for_bl32_entry(void);
+uint32_t marvell_get_spsr_for_bl33_entry(void);
+
+/* BL31 utility functions */
+void marvell_bl31_early_platform_setup(void *from_bl2,
+				       uintptr_t soc_fw_config,
+				       uintptr_t hw_config,
+				       void *plat_params_from_bl2);
+void marvell_bl31_platform_setup(void);
+void marvell_bl31_plat_runtime_setup(void);
+void marvell_bl31_plat_arch_setup(void);
+
+/* Power management config to power off the SoC */
+void *plat_marvell_get_pm_cfg(void);
+
+/* Check if MSS AP CM3 firmware contains PM support */
+_Bool is_pm_fw_running(void);
+
+/* Bootrom image recovery utility functions */
+void *plat_marvell_get_skip_image_data(void);
+
+/* FIP TOC validity check */
+int marvell_io_is_toc_valid(void);
+
+/*
+ * PSCI functionality
+ */
+void marvell_psci_arch_init(int ap_idx);
+void plat_marvell_system_reset(void);
+
+/*
+ * Miscellaneous platform SMC routines
+ */
+#ifdef MVEBU_PMU_IRQ_WA
+void mvebu_pmu_interrupt_enable(void);
+void mvebu_pmu_interrupt_disable(void);
+#endif
+
+/*
+ * Optional functions required in Marvell standard platforms
+ */
+void plat_marvell_io_setup(void);
+int plat_marvell_get_alt_image_source(
+	unsigned int image_id,
+	uintptr_t *dev_handle,
+	uintptr_t *image_spec);
+unsigned int plat_marvell_calc_core_pos(u_register_t mpidr);
+
+const mmap_region_t *plat_marvell_get_mmap(void);
+void marvell_ble_prepare_exit(void);
+void marvell_exit_bootrom(uintptr_t base);
+
+int plat_marvell_early_cpu_powerdown(void);
+int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info);
+
+#endif /* PLAT_MARVELL_H */
diff --git a/include/plat/marvell/a8k/common/plat_pm_trace.h b/include/plat/marvell/a8k/common/plat_pm_trace.h
new file mode 100644
index 0000000..a954914
--- /dev/null
+++ b/include/plat/marvell/a8k/common/plat_pm_trace.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLAT_PM_TRACE_H
+#define PLAT_PM_TRACE_H
+
+/*
+ * PM Trace is for Debug purpose only!!!
+ * It should not be enabled during System Run time
+ */
+#undef PM_TRACE_ENABLE
+
+
+/* trace entry time */
+struct pm_trace_entry {
+	/* trace entry time stamp */
+	unsigned int timestamp;
+
+	/* trace info
+	 * [16-31] - API Trace Id
+	 * [00-15] - API Step Id
+	 */
+	unsigned int trace_info;
+};
+
+struct pm_trace_ctrl {
+	/* trace pointer - points to next free entry in trace cyclic queue */
+	unsigned int trace_pointer;
+
+	/* trace count - number of entries in the queue, clear upon read */
+	unsigned int trace_count;
+};
+
+/* trace size definition */
+#define AP_MSS_ATF_CORE_INFO_SIZE	(256)
+#define AP_MSS_ATF_CORE_ENTRY_SIZE	(8)
+#define AP_MSS_ATF_TRACE_SIZE_MASK	(0xFF)
+
+/* trace address definition */
+#define AP_MSS_TIMER_BASE		(MVEBU_REGS_BASE_MASK + 0x580110)
+
+#define AP_MSS_ATF_CORE_0_CTRL_BASE	(MVEBU_REGS_BASE_MASK + 0x520140)
+#define AP_MSS_ATF_CORE_1_CTRL_BASE	(MVEBU_REGS_BASE_MASK + 0x520150)
+#define AP_MSS_ATF_CORE_2_CTRL_BASE	(MVEBU_REGS_BASE_MASK + 0x520160)
+#define AP_MSS_ATF_CORE_3_CTRL_BASE	(MVEBU_REGS_BASE_MASK + 0x520170)
+#define AP_MSS_ATF_CORE_CTRL_BASE	(AP_MSS_ATF_CORE_0_CTRL_BASE)
+
+#define AP_MSS_ATF_CORE_0_INFO_BASE	(MVEBU_REGS_BASE_MASK + 0x5201C0)
+#define AP_MSS_ATF_CORE_0_INFO_TRACE	(MVEBU_REGS_BASE_MASK + 0x5201C4)
+#define AP_MSS_ATF_CORE_1_INFO_BASE	(MVEBU_REGS_BASE_MASK + 0x5209C0)
+#define AP_MSS_ATF_CORE_1_INFO_TRACE	(MVEBU_REGS_BASE_MASK + 0x5209C4)
+#define AP_MSS_ATF_CORE_2_INFO_BASE	(MVEBU_REGS_BASE_MASK + 0x5211C0)
+#define AP_MSS_ATF_CORE_2_INFO_TRACE	(MVEBU_REGS_BASE_MASK + 0x5211C4)
+#define AP_MSS_ATF_CORE_3_INFO_BASE	(MVEBU_REGS_BASE_MASK + 0x5219C0)
+#define AP_MSS_ATF_CORE_3_INFO_TRACE	(MVEBU_REGS_BASE_MASK + 0x5219C4)
+#define AP_MSS_ATF_CORE_INFO_BASE	(AP_MSS_ATF_CORE_0_INFO_BASE)
+
+/* trace info definition */
+#define TRACE_PWR_DOMAIN_OFF		(0x10000)
+#define TRACE_PWR_DOMAIN_SUSPEND	(0x20000)
+#define TRACE_PWR_DOMAIN_SUSPEND_FINISH	(0x30000)
+#define TRACE_PWR_DOMAIN_ON		(0x40000)
+#define TRACE_PWR_DOMAIN_ON_FINISH	(0x50000)
+
+#define TRACE_PWR_DOMAIN_ON_MASK	(0xFF)
+
+#ifdef PM_TRACE_ENABLE
+
+/* trace API definition */
+void pm_core_0_trace(unsigned int trace);
+void pm_core_1_trace(unsigned int trace);
+void pm_core_2_trace(unsigned int trace);
+void pm_core_3_trace(unsigned int trace);
+
+typedef void (*core_trace_func)(unsigned int);
+
+extern core_trace_func funcTbl[PLATFORM_CORE_COUNT];
+
+#define PM_TRACE(trace) funcTbl[plat_my_core_pos()](trace)
+
+#else
+
+#define PM_TRACE(trace)
+
+#endif
+
+/*******************************************************************************
+ * pm_trace_add
+ *
+ * DESCRIPTION: Add PM trace
+ ******************************************************************************
+ */
+void pm_trace_add(unsigned int trace, unsigned int core);
+
+#endif /* PLAT_PM_TRACE_H */
diff --git a/include/plat/marvell/common/aarch64/cci_macros.S b/include/plat/marvell/common/aarch64/cci_macros.S
new file mode 100644
index 0000000..b0a909b
--- /dev/null
+++ b/include/plat/marvell/common/aarch64/cci_macros.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef CCI_MACROS_S
+#define CCI_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <platform_def.h>
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ------------------------------------------------
+	 * The below required platform porting macro prints
+	 * out relevant interconnect registers whenever an
+	 * unhandled exception is taken in BL31.
+	 * Clobbers: x0 - x9, sp
+	 * ------------------------------------------------
+	 */
+	.macro print_cci_regs
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
+
+#endif /* CCI_MACROS_S */
diff --git a/include/plat/marvell/common/aarch64/marvell_macros.S b/include/plat/marvell/common/aarch64/marvell_macros.S
new file mode 100644
index 0000000..bfe2d41
--- /dev/null
+++ b/include/plat/marvell/common/aarch64/marvell_macros.S
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MARVELL_MACROS_S
+#define MARVELL_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+/*
+ *	These Macros are required by ATF
+ */
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+#ifdef USE_CCI
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+	.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+#endif
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below utility macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL31 on ARM standard platforms.
+	 * Expects: GICD base in x16, GICC base in x17
+	 * Clobbers: x0 - x10, sp
+	 * ---------------------------------------------
+	 */
+	.macro marvell_print_gic_regs
+	/* Check for GICv3 system register access */
+	mrs	x7, id_aa64pfr0_el1
+	ubfx	x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x7, #1
+	b.ne	print_gicv2
+
+	/* Check for SRE enable */
+	mrs	x8, ICC_SRE_EL3
+	tst	x8, #ICC_SRE_SRE_BIT
+	b.eq	print_gicv2
+
+#ifdef USE_CCI
+	/* Load the icc reg list to x6 */
+	adr	x6, icc_regs
+	/* Load the icc regs to gp regs used by str_in_crash_buf_print */
+	mrs	x8, ICC_HPPIR0_EL1
+	mrs	x9, ICC_HPPIR1_EL1
+	mrs	x10, ICC_CTLR_EL3
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+#endif
+	b	print_gic_common
+
+print_gicv2:
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+print_gic_common:
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ------------------------------------------------
+	 * The below required platform porting macro prints
+	 * out relevant interconnect registers whenever an
+	 * unhandled exception is taken in BL31.
+	 * Clobbers: x0 - x9, sp
+	 * ------------------------------------------------
+	 */
+	.macro print_cci_regs
+#ifdef USE_CCI
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+#endif
+	.endm
+
+
+#endif /* MARVELL_MACROS_S */
diff --git a/include/plat/marvell/common/marvell_plat_priv.h b/include/plat/marvell/common/marvell_plat_priv.h
new file mode 100644
index 0000000..78b5331
--- /dev/null
+++ b/include/plat/marvell/common/marvell_plat_priv.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MARVELL_PLAT_PRIV_H
+#define MARVELL_PLAT_PRIV_H
+
+#include <lib/utils.h>
+
+/*****************************************************************************
+ * Function and variable prototypes
+ *****************************************************************************
+ */
+void plat_delay_timer_init(void);
+
+uint64_t mvebu_get_dram_size(uint64_t ap_base_addr);
+
+/*
+ * GIC operation, mandatory functions required in Marvell standard platforms
+ */
+void plat_marvell_gic_driver_init(void);
+void plat_marvell_gic_init(void);
+void plat_marvell_gic_cpuif_enable(void);
+void plat_marvell_gic_cpuif_disable(void);
+void plat_marvell_gic_pcpu_init(void);
+void plat_marvell_gic_irq_save(void);
+void plat_marvell_gic_irq_restore(void);
+void plat_marvell_gic_irq_pcpu_save(void);
+void plat_marvell_gic_irq_pcpu_restore(void);
+
+#endif /* MARVELL_PLAT_PRIV_H */
diff --git a/include/plat/marvell/common/marvell_pm.h b/include/plat/marvell/common/marvell_pm.h
new file mode 100644
index 0000000..8f16607
--- /dev/null
+++ b/include/plat/marvell/common/marvell_pm.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MARVELL_PM_H
+#define MARVELL_PM_H
+
+#define MVEBU_MAILBOX_MAGIC_NUM		PLAT_MARVELL_MAILBOX_MAGIC_NUM
+#define MVEBU_MAILBOX_SUSPEND_STATE	0xb007de7c
+
+/* Mailbox entry indexes */
+/* Magic number for validity check */
+#define	MBOX_IDX_MAGIC			0
+/* Recovery from suspend entry point */
+#define	MBOX_IDX_SEC_ADDR		1
+/* Suspend state magic number */
+#define	MBOX_IDX_SUSPEND_MAGIC		2
+/* Recovery jump address for ROM bypass */
+#define	MBOX_IDX_ROM_EXIT_ADDR		3
+/* BLE execution start counter value */
+#define	MBOX_IDX_START_CNT		4
+
+#endif /* MARVELL_PM_H */
diff --git a/include/plat/marvell/common/mvebu.h b/include/plat/marvell/common/mvebu.h
new file mode 100644
index 0000000..35a0200
--- /dev/null
+++ b/include/plat/marvell/common/mvebu.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C)  2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_H
+#define MVEBU_H
+
+/* Use this functions only when printf is allowed */
+#define debug_enter()	VERBOSE("----> Enter %s\n", __func__)
+#define debug_exit()	VERBOSE("<---- Exit  %s\n", __func__)
+
+/* Macro for testing alignment. Positive if number is NOT aligned */
+#define IS_NOT_ALIGN(number, align)	((number) & ((align) - 1))
+
+/* Macro for alignment up. For example, ALIGN_UP(0x0330, 0x20) = 0x0340 */
+#define ALIGN_UP(number, align) (((number) & ((align) - 1)) ? \
+		(((number) + (align)) & ~((align)-1)) : (number))
+
+/* Macro for testing whether a number is a power of 2. Positive if so */
+#define IS_POWER_OF_2(number)	((number) != 0 && \
+				(((number) & ((number) - 1)) == 0))
+
+/*
+ * Macro for ronding up to next power of 2
+ * it is done by count leading 0 (clz assembly opcode) and see msb set bit.
+ * then you can shift it left and get number which power of 2
+ * Note: this Macro is for 32 bit number
+ */
+#define ROUND_UP_TO_POW_OF_2(number)	(1 << \
+					(32 - __builtin_clz((number) - 1)))
+
+#define _1MB_				(1024ULL * 1024ULL)
+#define _1GB_				(_1MB_ * 1024ULL)
+#define _2GB_				(2 * _1GB_)
+
+#endif /* MVEBU_H */
diff --git a/include/services/arm_arch_svc.h b/include/services/arm_arch_svc.h
new file mode 100644
index 0000000..23c6f56
--- /dev/null
+++ b/include/services/arm_arch_svc.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARM_ARCH_SVC_H
+#define ARM_ARCH_SVC_H
+
+#define SMCCC_VERSION			U(0x80000000)
+#define SMCCC_ARCH_FEATURES		U(0x80000001)
+#define SMCCC_ARCH_WORKAROUND_1		U(0x80008000)
+#define SMCCC_ARCH_WORKAROUND_2		U(0x80007FFF)
+
+#define SMCCC_ARCH_NOT_REQUIRED		-2
+
+#endif /* ARM_ARCH_SVC_H */
diff --git a/include/services/mm_svc.h b/include/services/mm_svc.h
new file mode 100644
index 0000000..c111326
--- /dev/null
+++ b/include/services/mm_svc.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MM_SVC_H
+#define MM_SVC_H
+
+#if SPM_MM
+
+#include <lib/utils_def.h>
+
+#define MM_VERSION_MAJOR	U(1)
+#define MM_VERSION_MAJOR_SHIFT	16
+#define MM_VERSION_MAJOR_MASK	U(0x7FFF)
+#define MM_VERSION_MINOR	U(0)
+#define MM_VERSION_MINOR_SHIFT	0
+#define MM_VERSION_MINOR_MASK	U(0xFFFF)
+#define MM_VERSION_FORM(major, minor)	((major << MM_VERSION_MAJOR_SHIFT) | (minor))
+#define MM_VERSION_COMPILED	MM_VERSION_FORM(MM_VERSION_MAJOR, MM_VERSION_MINOR)
+
+/*
+ * SMC IDs defined in [1] for accessing MM services from the Non-secure world.
+ * These FIDs occupy the range 0x40 - 0x5f.
+ * [1] DEN0060A_ARM_MM_Interface_Specification.pdf
+ */
+#define MM_VERSION_AARCH32		U(0x84000040)
+
+#define MM_COMMUNICATE_AARCH64		U(0xC4000041)
+#define MM_COMMUNICATE_AARCH32		U(0x84000041)
+
+#endif /* SPM_MM */
+
+#endif /* MM_SVC_H */
diff --git a/include/services/sdei.h b/include/services/sdei.h
new file mode 100644
index 0000000..ae8c7e4
--- /dev/null
+++ b/include/services/sdei.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDEI_H
+#define SDEI_H
+
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+
+/* Range 0xC4000020 - 0xC400003F reserved for SDE 64bit smc calls */
+#define SDEI_VERSION				0xC4000020U
+#define SDEI_EVENT_REGISTER			0xC4000021U
+#define SDEI_EVENT_ENABLE			0xC4000022U
+#define SDEI_EVENT_DISABLE			0xC4000023U
+#define SDEI_EVENT_CONTEXT			0xC4000024U
+#define SDEI_EVENT_COMPLETE			0xC4000025U
+#define SDEI_EVENT_COMPLETE_AND_RESUME		0xC4000026U
+
+#define SDEI_EVENT_UNREGISTER			0xC4000027U
+#define SDEI_EVENT_STATUS			0xC4000028U
+#define SDEI_EVENT_GET_INFO			0xC4000029U
+#define SDEI_EVENT_ROUTING_SET			0xC400002AU
+#define SDEI_PE_MASK				0xC400002BU
+#define SDEI_PE_UNMASK				0xC400002CU
+
+#define SDEI_INTERRUPT_BIND			0xC400002DU
+#define SDEI_INTERRUPT_RELEASE			0xC400002EU
+#define SDEI_EVENT_SIGNAL			0xC400002FU
+#define SDEI_FEATURES				0xC4000030U
+#define SDEI_PRIVATE_RESET			0xC4000031U
+#define SDEI_SHARED_RESET			0xC4000032U
+
+/* SDEI_EVENT_REGISTER flags */
+#define SDEI_REGF_RM_ANY	0ULL
+#define SDEI_REGF_RM_PE		1ULL
+
+/* SDEI_EVENT_COMPLETE status flags */
+#define SDEI_EV_HANDLED		0U
+#define SDEI_EV_FAILED		1U
+
+/* Internal: SDEI flag bit positions */
+#define SDEI_MAPF_DYNAMIC_SHIFT_	1U
+#define SDEI_MAPF_BOUND_SHIFT_		2U
+#define SDEI_MAPF_SIGNALABLE_SHIFT_	3U
+#define SDEI_MAPF_PRIVATE_SHIFT_	4U
+#define SDEI_MAPF_CRITICAL_SHIFT_	5U
+#define SDEI_MAPF_EXPLICIT_SHIFT_	6U
+
+/* SDEI event 0 */
+#define SDEI_EVENT_0	0
+
+/* Placeholder interrupt for dynamic mapping */
+#define SDEI_DYN_IRQ	0U
+
+/* SDEI flags */
+
+/*
+ * These flags determine whether or not an event can be associated with an
+ * interrupt. Static events are permanently associated with an interrupt, and
+ * can't be changed at runtime.  Association of dynamic events with interrupts
+ * can be changed at run time using the SDEI_INTERRUPT_BIND and
+ * SDEI_INTERRUPT_RELEASE calls.
+ *
+ * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as
+ * SDEI_MAPF_BOUND indicates interrupt association. For example:
+ *
+ *  - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both
+ *    SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set.
+ *
+ *  - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither
+ *    SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them.
+ *
+ * See also the is_map_bound() macro.
+ */
+#define SDEI_MAPF_DYNAMIC	BIT(SDEI_MAPF_DYNAMIC_SHIFT_)
+#define SDEI_MAPF_BOUND		BIT(SDEI_MAPF_BOUND_SHIFT_)
+#define SDEI_MAPF_EXPLICIT	BIT(SDEI_MAPF_EXPLICIT_SHIFT_)
+
+#define SDEI_MAPF_SIGNALABLE	BIT(SDEI_MAPF_SIGNALABLE_SHIFT_)
+#define SDEI_MAPF_PRIVATE	BIT(SDEI_MAPF_PRIVATE_SHIFT_)
+
+#define SDEI_MAPF_NORMAL	0
+#define SDEI_MAPF_CRITICAL	BIT(SDEI_MAPF_CRITICAL_SHIFT_)
+
+/* Indices of private and shared mappings */
+#define SDEI_MAP_IDX_PRIV_	0U
+#define SDEI_MAP_IDX_SHRD_	1U
+#define SDEI_MAP_IDX_MAX_	2U
+
+/* The macros below are used to identify SDEI calls from the SMC function ID */
+#define SDEI_FID_MASK		U(0xffe0)
+#define SDEI_FID_VALUE		U(0x20)
+#define is_sdei_fid(_fid) \
+	((((_fid) & SDEI_FID_MASK) == SDEI_FID_VALUE) && \
+	 (((_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64))
+
+#define SDEI_EVENT_MAP(_event, _intr, _flags) \
+	{ \
+		.ev_num = (_event), \
+		.intr = (_intr), \
+		.map_flags = (_flags) \
+	}
+
+#define SDEI_SHARED_EVENT(_event, _intr, _flags) \
+	SDEI_EVENT_MAP(_event, _intr, _flags)
+
+#define SDEI_PRIVATE_EVENT(_event, _intr, _flags) \
+	SDEI_EVENT_MAP(_event, _intr, (_flags) | SDEI_MAPF_PRIVATE)
+
+#define SDEI_DEFINE_EVENT_0(_intr) \
+	SDEI_PRIVATE_EVENT(SDEI_EVENT_0, (_intr), SDEI_MAPF_SIGNALABLE)
+
+#define SDEI_EXPLICIT_EVENT(_event, _pri) \
+	SDEI_EVENT_MAP((_event), 0, (_pri) | SDEI_MAPF_EXPLICIT | SDEI_MAPF_PRIVATE)
+
+/*
+ * Declare shared and private entries for each core. Also declare a global
+ * structure containing private and share entries.
+ *
+ * This macro must be used in the same file as the platform SDEI mappings are
+ * declared. Only then would ARRAY_SIZE() yield a meaningful value.
+ */
+#define REGISTER_SDEI_MAP(_private, _shared) \
+	sdei_entry_t sdei_private_event_table \
+		[PLATFORM_CORE_COUNT * ARRAY_SIZE(_private)]; \
+	sdei_entry_t sdei_shared_event_table[ARRAY_SIZE(_shared)]; \
+	const sdei_mapping_t sdei_global_mappings[] = { \
+		[SDEI_MAP_IDX_PRIV_] = { \
+			.map = (_private), \
+			.num_maps = ARRAY_SIZE(_private) \
+		}, \
+		[SDEI_MAP_IDX_SHRD_] = { \
+			.map = (_shared), \
+			.num_maps = ARRAY_SIZE(_shared) \
+		}, \
+	}
+
+typedef uint8_t sdei_state_t;
+
+/* Runtime data of SDEI event */
+typedef struct sdei_entry {
+	uint64_t ep;		/* Entry point */
+	uint64_t arg;		/* Entry point argument */
+	uint64_t affinity;	/* Affinity of shared event */
+	unsigned int reg_flags;	/* Registration flags */
+
+	/* Event handler states: registered, enabled, running */
+	sdei_state_t state;
+} sdei_entry_t;
+
+/* Mapping of SDEI events to interrupts, and associated data */
+typedef struct sdei_ev_map {
+	int32_t ev_num;		/* Event number */
+	unsigned int intr;	/* Physical interrupt number for a bound map */
+	unsigned int map_flags;	/* Mapping flags, see SDEI_MAPF_* */
+	int reg_count;		/* Registration count */
+	spinlock_t lock;	/* Per-event lock */
+} sdei_ev_map_t;
+
+typedef struct sdei_mapping {
+	sdei_ev_map_t *map;
+	size_t num_maps;
+} sdei_mapping_t;
+
+/* Handler to be called to handle SDEI smc calls */
+uint64_t sdei_smc_handler(uint32_t smc_fid,
+		uint64_t x1,
+		uint64_t x2,
+		uint64_t x3,
+		uint64_t x4,
+		void *cookie,
+		void *handle,
+		uint64_t flags);
+
+void sdei_init(void);
+
+/* Public API to dispatch an event to Normal world */
+int sdei_dispatch_event(int ev_num);
+
+#endif /* SDEI_H */
diff --git a/include/services/secure_partition.h b/include/services/secure_partition.h
new file mode 100644
index 0000000..0510f80
--- /dev/null
+++ b/include/services/secure_partition.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_PARTITION_H
+#define SECURE_PARTITION_H
+
+#if SPM_MM
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/*
+ * Flags used by the secure_partition_mp_info structure to describe the
+ * characteristics of a cpu. Only a single flag is defined at the moment to
+ * indicate the primary cpu.
+ */
+#define MP_INFO_FLAG_PRIMARY_CPU	U(0x00000001)
+
+/*
+ * This structure is used to provide information required to initialise a S-EL0
+ * partition.
+ */
+typedef struct secure_partition_mp_info {
+	uint64_t		mpidr;
+	uint32_t		linear_id;
+	uint32_t		flags;
+} secure_partition_mp_info_t;
+
+typedef struct secure_partition_boot_info {
+	param_header_t		h;
+	uint64_t		sp_mem_base;
+	uint64_t		sp_mem_limit;
+	uint64_t		sp_image_base;
+	uint64_t		sp_stack_base;
+	uint64_t		sp_heap_base;
+	uint64_t		sp_ns_comm_buf_base;
+	uint64_t		sp_shared_buf_base;
+	uint64_t		sp_image_size;
+	uint64_t		sp_pcpu_stack_size;
+	uint64_t		sp_heap_size;
+	uint64_t		sp_ns_comm_buf_size;
+	uint64_t		sp_shared_buf_size;
+	uint32_t		num_sp_mem_regions;
+	uint32_t		num_cpus;
+	secure_partition_mp_info_t	*mp_info;
+} secure_partition_boot_info_t;
+
+#endif /* SPM_MM */
+
+#endif /* SECURE_PARTITION_H */
diff --git a/include/services/sp_res_desc.h b/include/services/sp_res_desc.h
new file mode 100644
index 0000000..b8be72e
--- /dev/null
+++ b/include/services/sp_res_desc.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_RES_DESC_H
+#define SPM_RES_DESC_H
+
+#include <stdint.h>
+
+#include <services/sp_res_desc_def.h>
+
+/*******************************************************************************
+ * Attribute Section
+ ******************************************************************************/
+
+struct sp_rd_sect_attribute {
+	/*
+	 * Version of the resource description.
+	 */
+	uint16_t version;
+
+	/*
+	 * Type of the Secure Partition:
+	 * - bit[0]: SP Type
+	 *   - b'0: UP SP
+	 *   - b'1: MP SP
+	 * If UP SP:
+	 * - bit[1]: Type of UP SP
+	 *   - b'0: Migratable UP SP
+	 *   - b'1: Pinned UP SP
+	 */
+	uint16_t sp_type;
+
+	/*
+	 * If this is a Pinned UP SP, PE on which the Pinned UP SP will run.
+	 */
+	uint32_t pe_mpidr;
+
+	/*
+	 * Run-Time Exception Level:
+	 * - 0: SEL0 SP
+	 * - 1: SEL1 SP
+	 */
+	uint8_t runtime_el;
+
+	/*
+	 * Type of Execution:
+	 * - 0: Init-time only
+	 * - 1: Run-time Execution
+	 */
+	uint8_t exec_type;
+
+	/*
+	 * Expected behavior upon failure:
+	 * - 0: Restartable
+	 * - 1: One-Shot
+	 */
+	uint8_t panic_policy;
+
+	/*
+	 * Translation Granule to use in the SP translation regime:
+	 * - 0: 4KB
+	 * - 1: 16KB
+	 * - 2: 64KB
+	 */
+	uint8_t xlat_granule;
+
+	/*
+	 * Size of the SP binary in bytes.
+	 */
+	uint32_t binary_size;
+
+	/*
+	 * - If SP is NOT PIE:
+	 *   - VA Address where the SP expects to be loaded.
+	 * - If SP is PIE:
+	 *   - Ignored.
+	 */
+	uint64_t load_address;
+
+	/*
+	 * Initial execution address. This is a VA as the SP sees it.
+	 */
+	uint64_t entrypoint;
+};
+
+/*******************************************************************************
+ * Memory Region Section
+ ******************************************************************************/
+
+struct sp_rd_sect_mem_region {
+	/*
+	 * Name of a Memory region, including null terminator. Reserved names:
+	 * - "Client Shared Memory Region":
+	 *   Memory region where memory shared by clients shall be mapped.
+	 * - "Queue Memory Region":
+	 *   Memory region shared with SPM for SP queue management.
+	 */
+	char name[RD_MEM_REGION_NAME_LEN];
+
+	/*
+	 * Memory Attributes:
+	 * - bits[3:0]: Type of memory
+	 *   - 0: Device
+	 *   - 1: Code
+	 *   - 2: Data
+	 *   - 3: BSS
+	 *   - 4: Read-only Data
+	 *   - 5: SPM-to-SP Shared Memory Region
+	 *   - 6: Client Shared Memory Region
+	 *   - 7: Miscellaneous
+	 * - If memory is { SPM-to-SP shared Memory, Client Shared Memory,
+	 *   Miscellaneous }
+	 *   - bits[4]: Position Independent
+	 *     - b'0: Position Dependent
+	 *     - b'1: Position Independent
+	 */
+	uint32_t attr;
+
+	/*
+	 * Base address of the memory region.
+	 */
+	uint64_t base;
+
+	/*
+	 * Size of the memory region.
+	 */
+	uint64_t size;
+
+	/*
+	 * Pointer to next memory region (or NULL if this is the last one).
+	 */
+	struct sp_rd_sect_mem_region *next;
+};
+
+/*******************************************************************************
+ * Notification Section
+ ******************************************************************************/
+
+struct sp_rd_sect_notification {
+	/*
+	 * Notification attributes:
+	 * - bit[31]: Notification Type
+	 *   - b'0: Platform Notification
+	 *   - b'1: Interrupt
+	 * If Notification Type == Platform Notification
+	 * - bits[15:0]: Implementation-defined Notification ID
+	 * If Notification Type == Interrupt
+	 * - bits[15:0]: IRQ number
+	 * - bits[23:16]: Interrupt Priority
+	 * - bit[24]: Trigger Type
+	 *   - b'0: Edge Triggered
+	 *   - b'1: Level Triggered
+	 * - bit[25]: Trigger Level
+	 *   - b'0: Falling or Low
+	 *   - b'1: Rising or High
+	 */
+	uint32_t attr;
+
+	/*
+	 * Processing Element.
+	 * If Notification Type == Interrupt && IRQ number is { SGI, LPI }
+	 * - PE ID to which IRQ will be forwarded
+	 */
+	uint32_t pe;
+
+	/*
+	 * Pointer to next notification (or NULL if this is the last one).
+	 */
+	struct sp_rd_sect_notification *next;
+};
+
+/*******************************************************************************
+ * Service Description Section
+ ******************************************************************************/
+
+struct sp_rd_sect_service {
+	/*
+	 * Service identifier.
+	 */
+	uint32_t uuid[4];
+
+	/*
+	 * Accessibility Options:
+	 * - bit[0]: Accessibility by secure-world clients
+	 *   - b'0: Not Accessible
+	 *   - b'1: Accessible
+	 * - bit[1]: Accessible by EL3
+	 *   - b'0: Not Accessible
+	 *   - b'1: Accessible
+	 * - bit[2]: Accessible by normal-world clients
+	 *   - b'0: Not Accessible
+	 *   - b'1: Accessible
+	 */
+	uint8_t accessibility;
+
+	/*
+	 * Request type supported:
+	 * - bit[0]: Blocking request
+	 *   - b'0: Not Enable
+	 *   - b'1: Enable
+	 * - bit[1]: Non-blocking request
+	 *   - b'0: Not Enable
+	 *   - b'1: Enable
+	 */
+	uint8_t request_type;
+
+	/*
+	 * Maximum number of client connections that the service can support.
+	 */
+	uint16_t connection_quota;
+
+	/*
+	 * If the service requires secure world memory to be shared with its
+	 * clients:
+	 * - Maximum amount of secure world memory in bytes to reserve from the
+	 *   secure world memory pool for the service.
+	 */
+	uint32_t secure_mem_size;
+
+	/*
+	 * Interrupt number used to notify the SP for the service.
+	 * - Should also be enabled in the Notification Section.
+	 */
+	uint32_t interrupt_num;
+
+	/*
+	 * Pointer to next service (or NULL if this is the last one).
+	 */
+	struct sp_rd_sect_service *next;
+};
+
+/*******************************************************************************
+ * Complete resource description struct
+ ******************************************************************************/
+
+struct sp_res_desc {
+
+	/* Attribute Section */
+	struct sp_rd_sect_attribute attribute;
+
+	/* System Resource Section */
+	struct sp_rd_sect_mem_region *mem_region;
+
+	struct sp_rd_sect_notification *notification;
+
+	/* Service Section */
+	struct sp_rd_sect_service *service;
+};
+
+#endif /* SPM_RES_DESC_H */
diff --git a/include/services/sp_res_desc_def.h b/include/services/sp_res_desc_def.h
new file mode 100644
index 0000000..5a3c50d
--- /dev/null
+++ b/include/services/sp_res_desc_def.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_RES_DESC_DEFS_H
+#define SPM_RES_DESC_DEFS_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Attribute Section
+ ******************************************************************************/
+
+#define RD_ATTR_TYPE_UP_MIGRATABLE	U(0)
+#define RD_ATTR_TYPE_UP_PINNED		U(2)
+#define RD_ATTR_TYPE_MP			U(1)
+
+#define RD_ATTR_RUNTIME_SEL0		U(0)
+#define RD_ATTR_RUNTIME_SEL1		U(1)
+
+#define RD_ATTR_INIT_ONLY		U(0)
+#define RD_ATTR_RUNTIME			U(1)
+
+#define RD_ATTR_PANIC_RESTART		U(0)
+#define RD_ATTR_PANIC_ONESHOT		U(1)
+
+#define RD_ATTR_XLAT_GRANULE_4KB	U(0)
+#define RD_ATTR_XLAT_GRANULE_16KB	U(1)
+#define RD_ATTR_XLAT_GRANULE_64KB	U(2)
+
+/*******************************************************************************
+ * Memory Region Section
+ ******************************************************************************/
+
+#define RD_MEM_REGION_NAME_LEN		U(32)
+
+#define RD_MEM_DEVICE			U(0)
+#define RD_MEM_NORMAL_CODE		U(1)
+#define RD_MEM_NORMAL_DATA		U(2)
+#define RD_MEM_NORMAL_BSS		U(3)
+#define RD_MEM_NORMAL_RODATA		U(4)
+#define RD_MEM_NORMAL_SPM_SP_SHARED_MEM	U(5)
+#define RD_MEM_NORMAL_CLIENT_SHARED_MEM	U(6)
+#define RD_MEM_NORMAL_MISCELLANEOUS	U(7)
+
+#define RD_MEM_MASK			U(15)
+
+#define RD_MEM_IS_PIE			(U(1) << 4)
+
+/*******************************************************************************
+ * Notification Section
+ ******************************************************************************/
+
+#define RD_NOTIF_TYPE_PLATFORM		(U(0) << 31)
+#define RD_NOTIF_TYPE_INTERRUPT		(U(1) << 31)
+
+#define RD_NOTIF_PLAT_ID_MASK		U(0xFFFF)
+#define RD_NOTIF_PLAT_ID_SHIFT		U(0)
+
+#define RD_NOTIF_PLATFORM(id)						\
+	(RD_NOTIF_TYPE_PLATFORM						\
+	| (((id) & RD_NOTIF_PLAT_ID_MASK) << RD_NOTIF_PLAT_ID_SHIFT))
+
+#define RD_NOTIF_IRQ_NUM_MASK		U(0xFFFF)
+#define RD_NOTIF_IRQ_NUM_SHIFT		U(0)
+#define RD_NOTIF_IRQ_PRIO_MASK		U(0xFF)
+#define RD_NOTIF_IRQ_PRIO_SHIFT		U(16)
+
+#define RD_NOTIF_IRQ_EDGE_FALLING	U(0)
+#define RD_NOTIF_IRQ_EDGE_RISING	U(2)
+#define RD_NOTIF_IRQ_LEVEL_LOW		U(1)
+#define RD_NOTIF_IRQ_LEVEL_HIGH		U(3)
+#define RD_NOTIF_IRQ_TRIGGER_SHIFT	U(24)
+
+#define RD_NOTIF_IRQ(num, prio, trig)					\
+	(RD_NOTIF_TYPE_IRQ						\
+	| (((num) & RD_NOTIF_IRQ_NUM_MASK) << RD_NOTIF_IRQ_NUM_SHIFT)	\
+	| (((prio) & RD_NOTIF_IRQ_PRIO_MASK) << RD_NOTIF_IRQ_PRIO_SHIFT) \
+	| (((trig) << RD_NOTIF_IRQ_TRIGGER_SHIFT)))
+
+/*******************************************************************************
+ * Service Description Section
+ ******************************************************************************/
+
+#define RD_SERV_ACCESS_SECURE		(U(1) << 0)
+#define RD_SERV_ACCESS_EL3		(U(1) << 1)
+#define RD_SERV_ACCESS_NORMAL		(U(1) << 2)
+
+#define RD_SERV_SUPPORT_BLOCKING	(U(1) << 0)
+#define RD_SERV_SUPPORT_NON_BLOCKING	(U(1) << 0)
+
+#endif /* SPM_RES_DESC_DEFS_H */
diff --git a/include/services/spci_svc.h b/include/services/spci_svc.h
new file mode 100644
index 0000000..1d02bfa
--- /dev/null
+++ b/include/services/spci_svc.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPCI_SVC_H
+#define SPCI_SVC_H
+
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+
+/* SPCI_VERSION helpers */
+
+#define SPCI_VERSION_MAJOR		U(0)
+#define SPCI_VERSION_MAJOR_SHIFT	16
+#define SPCI_VERSION_MAJOR_MASK		U(0x7FFF)
+#define SPCI_VERSION_MINOR		U(1)
+#define SPCI_VERSION_MINOR_SHIFT	0
+#define SPCI_VERSION_MINOR_MASK		U(0xFFFF)
+#define SPCI_VERSION_FORM(major, minor)	((((major) & SPCI_VERSION_MAJOR_MASK)  \
+						<< SPCI_VERSION_MAJOR_SHIFT) | \
+					((minor) & SPCI_VERSION_MINOR_MASK))
+#define SPCI_VERSION_COMPILED		SPCI_VERSION_FORM(SPCI_VERSION_MAJOR, \
+							  SPCI_VERSION_MINOR)
+
+/* Definitions to build the complete SMC ID */
+
+#define SPCI_FID_MISC_FLAG		(U(0) << 27)
+#define SPCI_FID_MISC_SHIFT		U(20)
+#define SPCI_FID_MISC_MASK		U(0x7F)
+
+#define SPCI_FID_TUN_FLAG		(U(1) << 27)
+#define SPCI_FID_TUN_SHIFT		U(24)
+#define SPCI_FID_TUN_MASK		U(0x7)
+
+#define OEN_SPCI_START			U(0x30)
+#define OEN_SPCI_END			U(0x3F)
+
+#define SPCI_SMC(spci_fid)	((OEN_SPCI_START << FUNCID_OEN_SHIFT) | \
+				 (U(1) << 31) | (spci_fid))
+#define SPCI_MISC_32(misc_fid)	((SMC_32 << FUNCID_CC_SHIFT) |	\
+				 SPCI_FID_MISC_FLAG |		\
+				 SPCI_SMC((misc_fid) << SPCI_FID_MISC_SHIFT))
+#define SPCI_MISC_64(misc_fid)	((SMC_64 << FUNCID_CC_SHIFT) |	\
+				 SPCI_FID_MISC_FLAG |		\
+				 SPCI_SMC((misc_fid) << SPCI_FID_MISC_SHIFT))
+#define SPCI_TUN_32(tun_fid)	((SMC_32 << FUNCID_CC_SHIFT) |	\
+				 SPCI_FID_TUN_FLAG |		\
+				 SPCI_SMC((tun_fid) << SPCI_FID_TUN_SHIFT))
+#define SPCI_TUN_64(tun_fid)	((SMC_64 << FUNCID_CC_SHIFT) |	\
+				 SPCI_FID_TUN_FLAG |		\
+				 SPCI_SMC((tun_fid) << SPCI_FID_TUN_SHIFT))
+
+/* SPCI miscellaneous functions */
+
+#define SPCI_FID_VERSION			U(0x0)
+#define SPCI_FID_SERVICE_HANDLE_OPEN		U(0x2)
+#define SPCI_FID_SERVICE_HANDLE_CLOSE		U(0x3)
+#define SPCI_FID_SERVICE_MEM_REGISTER		U(0x4)
+#define SPCI_FID_SERVICE_MEM_UNREGISTER		U(0x5)
+#define SPCI_FID_SERVICE_MEM_PUBLISH		U(0x6)
+#define SPCI_FID_SERVICE_REQUEST_BLOCKING	U(0x7)
+#define SPCI_FID_SERVICE_REQUEST_START		U(0x8)
+#define SPCI_FID_SERVICE_GET_RESPONSE		U(0x9)
+#define SPCI_FID_SERVICE_RESET_CLIENT_STATE	U(0xA)
+
+/* SPCI tunneling functions */
+
+#define SPCI_FID_SERVICE_TUN_REQUEST_START	U(0x0)
+#define SPCI_FID_SERVICE_REQUEST_RESUME		U(0x1)
+#define SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING	U(0x2)
+
+/* Complete SMC IDs and associated values */
+
+#define SPCI_VERSION				SPCI_MISC_32(SPCI_FID_VERSION)
+
+#define SPCI_SERVICE_HANDLE_OPEN		SPCI_MISC_32(SPCI_FID_SERVICE_HANDLE_OPEN)
+#define SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT	U(1)
+
+#define SPCI_SERVICE_HANDLE_CLOSE		SPCI_MISC_32(SPCI_FID_SERVICE_HANDLE_CLOSE)
+
+#define SPCI_SERVICE_MEM_REGISTER_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_MEM_REGISTER)
+#define SPCI_SERVICE_MEM_REGISTER_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_MEM_REGISTER)
+
+#define SPCI_SERVICE_MEM_UNREGISTER_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_MEM_UNREGISTER)
+#define SPCI_SERVICE_MEM_UNREGISTER_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_MEM_UNREGISTER)
+
+#define SPCI_SERVICE_MEM_PUBLISH_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_MEM_PUBLISH)
+#define SPCI_SERVICE_MEM_PUBLISH_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_MEM_PUBLISH)
+
+#define SPCI_SERVICE_REQUEST_BLOCKING_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_REQUEST_BLOCKING)
+#define SPCI_SERVICE_REQUEST_BLOCKING_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_REQUEST_BLOCKING)
+
+#define SPCI_SERVICE_REQUEST_START_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_REQUEST_START)
+#define SPCI_SERVICE_REQUEST_START_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_REQUEST_START)
+
+#define SPCI_SERVICE_GET_RESPONSE_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_GET_RESPONSE)
+#define SPCI_SERVICE_GET_RESPONSE_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_GET_RESPONSE)
+
+#define SPCI_SERVICE_RESET_CLIENT_STATE_AARCH32	SPCI_MISC_32(SPCI_FID_SERVICE_RESET_CLIENT_STATE)
+#define SPCI_SERVICE_RESET_CLIENT_STATE_AARCH64	SPCI_MISC_64(SPCI_FID_SERVICE_RESET_CLIENT_STATE)
+
+#define SPCI_SERVICE_TUN_REQUEST_START_AARCH32	SPCI_TUN_32(SPCI_FID_SERVICE_TUN_REQUEST_START)
+#define SPCI_SERVICE_TUN_REQUEST_START_AARCH64	SPCI_TUN_64(SPCI_FID_SERVICE_TUN_REQUEST_START)
+
+#define SPCI_SERVICE_REQUEST_RESUME_AARCH32	SPCI_TUN_32(SPCI_FID_SERVICE_REQUEST_RESUME)
+#define SPCI_SERVICE_REQUEST_RESUME_AARCH64	SPCI_TUN_64(SPCI_FID_SERVICE_REQUEST_RESUME)
+
+#define SPCI_SERVICE_TUN_REQUEST_BLOCKING_AARCH32 SPCI_TUN_32(SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING)
+#define SPCI_SERVICE_TUN_REQUEST_BLOCKING_AARCH64 SPCI_TUN_64(SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING)
+
+/* SPCI error codes. */
+
+#define SPCI_SUCCESS		 0
+#define SPCI_NOT_SUPPORTED	-1
+#define SPCI_INVALID_PARAMETER	-2
+#define SPCI_NO_MEMORY		-3
+#define SPCI_BUSY		-4
+#define SPCI_QUEUED		-5
+#define SPCI_DENIED		-6
+#define SPCI_NOT_PRESENT	-7
+
+#endif /* SPCI_SVC_H */
diff --git a/include/services/spm_svc.h b/include/services/spm_svc.h
new file mode 100644
index 0000000..a3723a0
--- /dev/null
+++ b/include/services/spm_svc.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_SVC_H
+#define SPM_SVC_H
+
+#if SPM_MM
+
+#include <lib/utils_def.h>
+
+#define SPM_VERSION_MAJOR	U(0)
+#define SPM_VERSION_MAJOR_SHIFT	16
+#define SPM_VERSION_MAJOR_MASK	U(0x7FFF)
+#define SPM_VERSION_MINOR	U(1)
+#define SPM_VERSION_MINOR_SHIFT	0
+#define SPM_VERSION_MINOR_MASK	U(0xFFFF)
+#define SPM_VERSION_FORM(major, minor)	((major << SPM_VERSION_MAJOR_SHIFT) | (minor))
+#define SPM_VERSION_COMPILED	SPM_VERSION_FORM(SPM_VERSION_MAJOR, SPM_VERSION_MINOR)
+
+/* The macros below are used to identify SPM calls from the SMC function ID */
+#define SPM_FID_MASK			U(0xffff)
+#define SPM_FID_MIN_VALUE		U(0x40)
+#define SPM_FID_MAX_VALUE		U(0x7f)
+#define is_spm_fid(_fid)						\
+		((((_fid) & SPM_FID_MASK) >= SPM_FID_MIN_VALUE) &&	\
+		 (((_fid) & SPM_FID_MASK) <= SPM_FID_MAX_VALUE))
+
+/*
+ * SMC IDs defined for accessing services implemented by the Secure Partition
+ * Manager from the Secure Partition(s). These services enable a partition to
+ * handle delegated events and request privileged operations from the manager.
+ * They occupy the range 0x60-0x7f.
+ */
+#define SPM_VERSION_AARCH32			U(0x84000060)
+#define SP_EVENT_COMPLETE_AARCH64		U(0xC4000061)
+#define SP_MEMORY_ATTRIBUTES_GET_AARCH64	U(0xC4000064)
+#define SP_MEMORY_ATTRIBUTES_SET_AARCH64	U(0xC4000065)
+
+/*
+ * Macros used by SP_MEMORY_ATTRIBUTES_SET_AARCH64.
+ */
+
+#define SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS	U(0)
+#define SP_MEMORY_ATTRIBUTES_ACCESS_RW		U(1)
+/* Value U(2) is reserved. */
+#define SP_MEMORY_ATTRIBUTES_ACCESS_RO		U(3)
+#define SP_MEMORY_ATTRIBUTES_ACCESS_MASK	U(3)
+#define SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT	0
+
+#define SP_MEMORY_ATTRIBUTES_EXEC		(U(0) << 2)
+#define SP_MEMORY_ATTRIBUTES_NON_EXEC		(U(1) << 2)
+
+
+/* SPM error codes. */
+#define SPM_SUCCESS		0
+#define SPM_NOT_SUPPORTED	-1
+#define SPM_INVALID_PARAMETER	-2
+#define SPM_DENIED		-3
+#define SPM_NO_MEMORY		-5
+
+#endif /* SPM_MM */
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+int32_t spm_setup(void);
+
+#if SPM_MM
+
+uint64_t spm_smc_handler(uint32_t smc_fid,
+			 uint64_t x1,
+			 uint64_t x2,
+			 uint64_t x3,
+			 uint64_t x4,
+			 void *cookie,
+			 void *handle,
+			 uint64_t flags);
+
+/* Helper to enter a Secure Partition */
+uint64_t spm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3);
+
+#endif /* SPM_MM */
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPM_SVC_H */
diff --git a/include/services/sprt_svc.h b/include/services/sprt_svc.h
new file mode 100644
index 0000000..2421ea2
--- /dev/null
+++ b/include/services/sprt_svc.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPRT_SVC_H
+#define SPRT_SVC_H
+
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+
+/* SPRT_VERSION helpers */
+
+#define SPRT_VERSION_MAJOR		U(0)
+#define SPRT_VERSION_MAJOR_SHIFT	16
+#define SPRT_VERSION_MAJOR_MASK		U(0x7FFF)
+#define SPRT_VERSION_MINOR		U(1)
+#define SPRT_VERSION_MINOR_SHIFT	0
+#define SPRT_VERSION_MINOR_MASK		U(0xFFFF)
+#define SPRT_VERSION_FORM(major, minor)	((((major) & SPRT_VERSION_MAJOR_MASK)  \
+						<< SPRT_VERSION_MAJOR_SHIFT) | \
+					((minor) & SPRT_VERSION_MINOR_MASK))
+#define SPRT_VERSION_COMPILED		SPRT_VERSION_FORM(SPRT_VERSION_MAJOR, \
+							  SPRT_VERSION_MINOR)
+
+/* SPRT function IDs */
+
+#define SPRT_FID_VERSION		U(0x0)
+#define SPRT_FID_PUT_RESPONSE		U(0x1)
+#define SPRT_FID_YIELD			U(0x5)
+#define SPRT_FID_PANIC			U(0x7)
+#define SPRT_FID_MEMORY_PERM_ATTR_GET	U(0xB)
+#define SPRT_FID_MEMORY_PERM_ATTR_SET	U(0xC)
+
+#define SPRT_FID_MASK			U(0xFF)
+
+/* Definitions to build the complete SMC ID */
+
+#define OEN_SPRT_START			U(0x20)
+#define OEN_SPRT_END			U(0x2F)
+
+#define SPRT_SMC_64(sprt_fid)	((OEN_SPRT_START << FUNCID_OEN_SHIFT) | \
+				 (U(1) << 31) | ((sprt_fid) & SPRT_FID_MASK) | \
+				 (SMC_64 << FUNCID_CC_SHIFT))
+#define SPRT_SMC_32(sprt_fid)	((OEN_SPRT_START << FUNCID_OEN_SHIFT) | \
+				 (U(1) << 31) | ((sprt_fid) & SPRT_FID_MASK) | \
+				 (SMC_32 << FUNCID_CC_SHIFT))
+
+/* Complete SMC IDs */
+
+#define SPRT_VERSION				SPRT_SMC_32(SPRT_FID_VERSION)
+#define SPRT_PUT_RESPONSE_AARCH64		SPRT_SMC_64(SPRT_FID_PUT_RESPONSE)
+#define SPRT_YIELD_AARCH64			SPRT_SMC_64(SPRT_FID_YIELD)
+#define SPRT_PANIC_AARCH64			SPRT_SMC_64(SPRT_FID_PANIC)
+#define SPRT_MEMORY_PERM_ATTR_GET_AARCH64	SPRT_SMC_64(SPRT_FID_MEMORY_PERM_ATTR_GET)
+#define SPRT_MEMORY_PERM_ATTR_SET_AARCH64	SPRT_SMC_64(SPRT_FID_MEMORY_PERM_ATTR_SET)
+
+/* Defines used by SPRT_MEMORY_PERM_ATTR_{GET,SET}_AARCH64 */
+
+#define SPRT_MEMORY_PERM_ATTR_RO	U(0)
+#define SPRT_MEMORY_PERM_ATTR_RW	U(1)
+#define SPRT_MEMORY_PERM_ATTR_RO_EXEC	U(2)
+/* U(3) is reserved */
+#define SPRT_MEMORY_PERM_ATTR_MASK	U(3)
+#define SPRT_MEMORY_PERM_ATTR_SHIFT	3
+
+/* SPRT error codes. */
+
+#define SPRT_SUCCESS		 0
+#define SPRT_NOT_SUPPORTED	-1
+#define SPRT_INVALID_PARAMETER	-2
+
+#endif /* SPRT_SVC_H */
diff --git a/include/services/std_svc.h b/include/services/std_svc.h
new file mode 100644
index 0000000..b0614fb
--- /dev/null
+++ b/include/services/std_svc.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STD_SVC_H
+#define STD_SVC_H
+
+/* SMC function IDs for Standard Service queries */
+
+#define ARM_STD_SVC_CALL_COUNT		0x8400ff00
+#define ARM_STD_SVC_UID			0x8400ff01
+/*					0x8400ff02 is reserved */
+#define ARM_STD_SVC_VERSION		0x8400ff03
+
+/* ARM Standard Service Calls version numbers */
+#define STD_SVC_VERSION_MAJOR		0x0
+#define STD_SVC_VERSION_MINOR		0x1
+
+/*
+ * Get the ARM Standard Service argument from EL3 Runtime.
+ * This function must be implemented by EL3 Runtime and the
+ * `svc_mask` identifies the service. `svc_mask` is a bit
+ * mask identifying the range of SMC function IDs available
+ * to the service.
+ */
+uintptr_t get_arm_std_svc_args(unsigned int svc_mask);
+
+#endif /* STD_SVC_H */
diff --git a/include/tools_share/firmware_image_package.h b/include/tools_share/firmware_image_package.h
new file mode 100644
index 0000000..598d5c2
--- /dev/null
+++ b/include/tools_share/firmware_image_package.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIRMWARE_IMAGE_PACKAGE_H
+#define FIRMWARE_IMAGE_PACKAGE_H
+
+#include <stdint.h>
+
+#include "uuid.h"
+
+/* This is used as a signature to validate the blob header */
+#define TOC_HEADER_NAME	0xAA640001
+
+
+/* ToC Entry UUIDs */
+#define UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U \
+	{{0x65, 0x92, 0x27, 0x03}, {0x2f, 0x74}, {0xe6, 0x44}, 0x8d, 0xff, {0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10} }
+#define UUID_TRUSTED_UPDATE_FIRMWARE_BL2U \
+	{{0x60, 0xb3, 0xeb, 0x37}, {0xc1, 0xe5}, {0xea, 0x41}, 0x9d, 0xf3, {0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01} }
+#define UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U \
+	{{0x4f, 0x51, 0x1d, 0x11}, {0x2b, 0xe5}, {0x4e, 0x49}, 0xb4, 0xc5, {0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a} }
+#define UUID_TRUSTED_FWU_CERT \
+	{{0x71, 0x40, 0x8a, 0xb2}, {0x18, 0xd6}, {0x87, 0x4c}, 0x8b, 0x2e, {0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96} }
+#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \
+	{{0x5f, 0xf9, 0xec, 0x0b}, {0x4d, 0x22}, {0x3e, 0x4d}, 0xa5, 0x44, {0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a} }
+#define UUID_SCP_FIRMWARE_SCP_BL2 \
+	{{0x97,  0x66, 0xfd, 0x3d}, {0x89, 0xbe}, {0xe8, 0x49}, 0xae, 0x5d, {0x78, 0xa1, 0x40, 0x60, 0x82, 0x13} }
+#define UUID_EL3_RUNTIME_FIRMWARE_BL31 \
+	{{0x47,  0xd4, 0x08, 0x6d}, {0x4c, 0xfe}, {0x98, 0x46}, 0x9b, 0x95, {0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00} }
+#define UUID_SECURE_PAYLOAD_BL32 \
+	{{0x05,  0xd0, 0xe1, 0x89}, {0x53, 0xdc}, {0x13, 0x47}, 0x8d, 0x2b, {0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38} }
+#define UUID_SECURE_PAYLOAD_BL32_EXTRA1 \
+	{{0x0b,  0x70, 0xc2, 0x9b}, {0x2a, 0x5a}, {0x78, 0x40}, 0x9f, 0x65, {0x0a, 0x56, 0x82, 0x73, 0x82, 0x88} }
+#define UUID_SECURE_PAYLOAD_BL32_EXTRA2 \
+	{{0x8e,  0xa8, 0x7b, 0xb1}, {0xcf, 0xa2}, {0x3f, 0x4d}, 0x85, 0xfd, {0xe7, 0xbb, 0xa5, 0x02, 0x20, 0xd9} }
+#define UUID_NON_TRUSTED_FIRMWARE_BL33 \
+	{{0xd6,  0xd0, 0xee, 0xa7}, {0xfc, 0xea}, {0xd5, 0x4b}, 0x97, 0x82, {0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4} }
+/* Key certificates */
+#define UUID_ROT_KEY_CERT \
+	{{0x86,  0x2d, 0x1d, 0x72}, {0xf8, 0x60}, {0xe4, 0x11}, 0x92, 0x0b, {0x8b, 0xe7, 0x62, 0x16, 0x0f, 0x24} }
+#define UUID_TRUSTED_KEY_CERT \
+	{{0x82,  0x7e, 0xe8, 0x90}, {0xf8, 0x60}, {0xe4, 0x11}, 0xa1, 0xb4, {0x77, 0x7a, 0x21, 0xb4, 0xf9, 0x4c} }
+#define UUID_NON_TRUSTED_WORLD_KEY_CERT \
+	{{0x1c,  0x67, 0x87, 0x3d}, {0x5f, 0x63}, {0xe4, 0x11}, 0x97, 0x8d, {0x27, 0xc0, 0xc7, 0x14, 0x8a, 0xbd} }
+#define UUID_SCP_FW_KEY_CERT \
+	{{0x02,  0x42, 0x21, 0xa1}, {0xf8, 0x60}, {0xe4, 0x11}, 0x8d, 0x9b, {0xf3, 0x3c, 0x0e, 0x15, 0xa0, 0x14} }
+#define UUID_SOC_FW_KEY_CERT \
+	{{0x8a,  0xb8, 0xbe, 0xcc}, {0xf9, 0x60}, {0xe4, 0x11}, 0x9a, 0xd0, {0xeb, 0x48, 0x22, 0xd8, 0xdc, 0xf8} }
+#define UUID_TRUSTED_OS_FW_KEY_CERT \
+	{{0x94,  0x77, 0xd6, 0x03}, {0xfb, 0x60}, {0xe4, 0x11}, 0x85, 0xdd, {0xb7, 0x10, 0x5b, 0x8c, 0xee, 0x04} }
+#define UUID_NON_TRUSTED_FW_KEY_CERT \
+	{{0x8a,  0xd5, 0x83, 0x2a}, {0xfb, 0x60}, {0xe4, 0x11}, 0x8a, 0xaf, {0xdf, 0x30, 0xbb, 0xc4, 0x98, 0x59} }
+/* Content certificates */
+#define UUID_TRUSTED_BOOT_FW_CERT \
+	{{0xd6,  0xe2, 0x69, 0xea}, {0x5d, 0x63}, {0xe4, 0x11}, 0x8d, 0x8c, {0x9f, 0xba, 0xbe, 0x99, 0x56, 0xa5} }
+#define UUID_SCP_FW_CONTENT_CERT \
+	{{0x44,  0xbe, 0x6f, 0x04}, {0x5e, 0x63}, {0xe4, 0x11}, 0xb2, 0x8b, {0x73, 0xd8, 0xea, 0xae, 0x96, 0x56} }
+#define UUID_SOC_FW_CONTENT_CERT \
+	{{0xe2,  0xb2, 0x0c, 0x20}, {0x5e, 0x63}, {0xe4, 0x11}, 0x9c, 0xe8, {0xab, 0xcc, 0xf9, 0x2b, 0xb6, 0x66} }
+#define UUID_TRUSTED_OS_FW_CONTENT_CERT \
+	{{0xa4,  0x9f, 0x44, 0x11}, {0x5e, 0x63}, {0xe4, 0x11}, 0x87, 0x28, {0x3f, 0x05, 0x72, 0x2a, 0xf3, 0x3d} }
+#define UUID_NON_TRUSTED_FW_CONTENT_CERT \
+	{{0x8e,  0xc4, 0xc1, 0xf3}, {0x5d, 0x63}, {0xe4, 0x11}, 0xa7, 0xa9, {0x87, 0xee, 0x40, 0xb2, 0x3f, 0xa7} }
+/* Dynamic configs */
+#define UUID_HW_CONFIG \
+	{{0x08,  0xb8, 0xf1, 0xd9}, {0xc9, 0xcf}, {0x93, 0x49}, 0xa9, 0x62, {0x6f, 0xbc, 0x6b, 0x72, 0x65, 0xcc} }
+#define UUID_TB_FW_CONFIG \
+	{{0x6c,  0x04, 0x58, 0xff}, {0xaf, 0x6b}, {0x7d, 0x4f}, 0x82, 0xed, {0xaa, 0x27, 0xbc, 0x69, 0xbf, 0xd2} }
+#define UUID_SOC_FW_CONFIG \
+	{{0x99,  0x79, 0x81, 0x4b}, {0x03, 0x76}, {0xfb, 0x46}, 0x8c, 0x8e, {0x8d, 0x26, 0x7f, 0x78, 0x59, 0xe0} }
+#define UUID_TOS_FW_CONFIG \
+	{{0x26,  0x25, 0x7c, 0x1a}, {0xdb, 0xc6}, {0x7f, 0x47}, 0x8d, 0x96, {0xc4, 0xc4, 0xb0, 0x24, 0x80, 0x21} }
+#define UUID_NT_FW_CONFIG \
+	{{0x28,  0xda, 0x98, 0x15}, {0x93, 0xe8}, {0x7e, 0x44}, 0xac, 0x66, {0x1a, 0xaf, 0x80, 0x15, 0x50, 0xf9} }
+
+typedef struct fip_toc_header {
+	uint32_t	name;
+	uint32_t	serial_number;
+	uint64_t	flags;
+} fip_toc_header_t;
+
+typedef struct fip_toc_entry {
+	uuid_t		uuid;
+	uint64_t	offset_address;
+	uint64_t	size;
+	uint64_t	flags;
+} fip_toc_entry_t;
+
+#endif /* FIRMWARE_IMAGE_PACKAGE_H */
diff --git a/include/tools_share/sptool.h b/include/tools_share/sptool.h
new file mode 100644
index 0000000..67a2cf0
--- /dev/null
+++ b/include/tools_share/sptool.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPTOOL_H
+#define SPTOOL_H
+
+#include <stdint.h>
+
+/* Header for a secure partition package. There is one per package. */
+struct sp_pkg_header {
+	uint64_t version;
+	uint64_t number_of_sp;
+};
+
+/*
+ * Entry descriptor in a secure partition package. Each entry comprises a
+ * secure partition and its resource description.
+ */
+struct sp_pkg_entry {
+	uint64_t sp_offset;
+	uint64_t sp_size;
+	uint64_t rd_offset;
+	uint64_t rd_size;
+};
+
+#endif /* SPTOOL_H */
diff --git a/include/tools_share/tbbr_oid.h b/include/tools_share/tbbr_oid.h
new file mode 100644
index 0000000..6bccfdd
--- /dev/null
+++ b/include/tools_share/tbbr_oid.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_OID_H
+#define TBBR_OID_H
+
+/*
+ * The following is a list of OID values defined and reserved by ARM, which
+ * are used to define the extension fields of the certificate structure, as
+ * defined in the Trusted Board Boot Requirements (TBBR) specification,
+ * ARM DEN0006C-1.
+ */
+
+
+/* TrustedFirmwareNVCounter - Non-volatile counter extension */
+#define TRUSTED_FW_NVCOUNTER_OID		"1.3.6.1.4.1.4128.2100.1"
+/* NonTrustedFirmwareNVCounter - Non-volatile counter extension */
+#define NON_TRUSTED_FW_NVCOUNTER_OID		"1.3.6.1.4.1.4128.2100.2"
+
+
+/*
+ * Non-Trusted Firmware Updater Certificate
+ */
+
+/* APFirmwareUpdaterConfigHash - BL2U */
+#define AP_FWU_CFG_HASH_OID			"1.3.6.1.4.1.4128.2100.101"
+/* SCPFirmwareUpdaterConfigHash - SCP_BL2U */
+#define SCP_FWU_CFG_HASH_OID			"1.3.6.1.4.1.4128.2100.102"
+/* FirmwareUpdaterHash - NS_BL2U */
+#define FWU_HASH_OID				"1.3.6.1.4.1.4128.2100.103"
+/* TrustedWatchdogRefreshTime */
+#define TRUSTED_WATCHDOG_TIME_OID		"1.3.6.1.4.1.4128.2100.104"
+
+
+/*
+ * Trusted Boot Firmware Certificate
+ */
+
+/* TrustedBootFirmwareHash - BL2 */
+#define TRUSTED_BOOT_FW_HASH_OID		"1.3.6.1.4.1.4128.2100.201"
+#define TRUSTED_BOOT_FW_CONFIG_HASH_OID		"1.3.6.1.4.1.4128.2100.202"
+#define HW_CONFIG_HASH_OID			"1.3.6.1.4.1.4128.2100.203"
+
+/*
+ * Trusted Key Certificate
+ */
+
+/* PrimaryDebugCertificatePK */
+#define PRIMARY_DEBUG_PK_OID			"1.3.6.1.4.1.4128.2100.301"
+/* TrustedWorldPK */
+#define TRUSTED_WORLD_PK_OID			"1.3.6.1.4.1.4128.2100.302"
+/* NonTrustedWorldPK */
+#define NON_TRUSTED_WORLD_PK_OID		"1.3.6.1.4.1.4128.2100.303"
+
+
+/*
+ * Trusted Debug Certificate
+ */
+
+/* DebugScenario */
+#define TRUSTED_DEBUG_SCENARIO_OID		"1.3.6.1.4.1.4128.2100.401"
+/* SoC Specific */
+#define TRUSTED_DEBUG_SOC_SPEC_OID		"1.3.6.1.4.1.4128.2100.402"
+/* SecondaryDebugCertPK */
+#define SECONDARY_DEBUG_PK_OID			"1.3.6.1.4.1.4128.2100.403"
+
+
+/*
+ * SoC Firmware Key Certificate
+ */
+
+/* SoCFirmwareContentCertPK */
+#define SOC_FW_CONTENT_CERT_PK_OID		"1.3.6.1.4.1.4128.2100.501"
+
+/*
+ * SoC Firmware Content Certificate
+ */
+
+/* APRomPatchHash - BL1_PATCH */
+#define APROM_PATCH_HASH_OID			"1.3.6.1.4.1.4128.2100.601"
+/* SoCConfigHash */
+#define SOC_CONFIG_HASH_OID			"1.3.6.1.4.1.4128.2100.602"
+/* SoCAPFirmwareHash - BL31 */
+#define SOC_AP_FW_HASH_OID			"1.3.6.1.4.1.4128.2100.603"
+/* SoCFirmwareConfigHash = SOC_FW_CONFIG */
+#define SOC_FW_CONFIG_HASH_OID			"1.3.6.1.4.1.4128.2100.604"
+
+/*
+ * SCP Firmware Key Certificate
+ */
+
+/* SCPFirmwareContentCertPK */
+#define SCP_FW_CONTENT_CERT_PK_OID		"1.3.6.1.4.1.4128.2100.701"
+
+
+/*
+ * SCP Firmware Content Certificate
+ */
+
+/* SCPFirmwareHash - SCP_BL2 */
+#define SCP_FW_HASH_OID				"1.3.6.1.4.1.4128.2100.801"
+/* SCPRomPatchHash - SCP_BL1_PATCH */
+#define SCP_ROM_PATCH_HASH_OID			"1.3.6.1.4.1.4128.2100.802"
+
+
+/*
+ * Trusted OS Firmware Key Certificate
+ */
+
+/* TrustedOSFirmwareContentCertPK */
+#define TRUSTED_OS_FW_CONTENT_CERT_PK_OID	"1.3.6.1.4.1.4128.2100.901"
+
+
+/*
+ * Trusted OS Firmware Content Certificate
+ */
+
+/* TrustedOSFirmwareHash - BL32 */
+#define TRUSTED_OS_FW_HASH_OID			"1.3.6.1.4.1.4128.2100.1001"
+/* TrustedOSExtra1FirmwareHash - BL32 Extra1 */
+#define TRUSTED_OS_FW_EXTRA1_HASH_OID		"1.3.6.1.4.1.4128.2100.1002"
+/* TrustedOSExtra2FirmwareHash - BL32 Extra2 */
+#define TRUSTED_OS_FW_EXTRA2_HASH_OID		"1.3.6.1.4.1.4128.2100.1003"
+/* TrustedOSFirmwareConfigHash - TOS_FW_CONFIG */
+#define TRUSTED_OS_FW_CONFIG_HASH_OID		"1.3.6.1.4.1.4128.2100.1004"
+
+
+/*
+ * Non-Trusted Firmware Key Certificate
+ */
+
+/* NonTrustedFirmwareContentCertPK */
+#define NON_TRUSTED_FW_CONTENT_CERT_PK_OID	"1.3.6.1.4.1.4128.2100.1101"
+
+
+/*
+ * Non-Trusted Firmware Content Certificate
+ */
+
+/* NonTrustedWorldBootloaderHash - BL33 */
+#define NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID	"1.3.6.1.4.1.4128.2100.1201"
+/* NonTrustedFirmwareConfigHash - NT_FW_CONFIG */
+#define NON_TRUSTED_FW_CONFIG_HASH_OID		"1.3.6.1.4.1.4128.2100.1202"
+
+#endif /* TBBR_OID_H */
diff --git a/include/tools_share/uuid.h b/include/tools_share/uuid.h
new file mode 100644
index 0000000..7d00432
--- /dev/null
+++ b/include/tools_share/uuid.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Portions copyright (c) 2014, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef UUID_H
+#define UUID_H
+
+/* Length of a node address (an IEEE 802 address). */
+#define	_UUID_NODE_LEN		6
+
+/* Length of UUID string including dashes. */
+#define _UUID_STR_LEN		36
+
+/*
+ * See also:
+ *      http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
+ *      http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
+ *
+ * A DCE 1.1 compatible source representation of UUIDs.
+ */
+struct uuid {
+	uint8_t		time_low[4];
+	uint8_t		time_mid[2];
+	uint8_t		time_hi_and_version[2];
+	uint8_t		clock_seq_hi_and_reserved;
+	uint8_t		clock_seq_low;
+	uint8_t		node[_UUID_NODE_LEN];
+};
+
+/* XXX namespace pollution? */
+typedef struct uuid uuid_t;
+
+#endif /* UUID_H */
diff --git a/lib/aarch32/arm32_aeabi_divmod.c b/lib/aarch32/arm32_aeabi_divmod.c
new file mode 100644
index 0000000..ea8e2bb
--- /dev/null
+++ b/lib/aarch32/arm32_aeabi_divmod.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Form ABI specifications:
+ *      int __aeabi_idiv(int numerator, int denominator);
+ *     unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
+ *
+ *     typedef struct { int quot; int rem; } idiv_return;
+ *     typedef struct { unsigned quot; unsigned rem; } uidiv_return;
+ *
+ *     __value_in_regs idiv_return __aeabi_idivmod(int numerator,
+ *     int *denominator);
+ *     __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
+ *     unsigned denominator);
+ */
+
+/* struct qr - stores quotient/remainder to handle divmod EABI interfaces. */
+struct qr {
+	unsigned int q;		/* computed quotient */
+	unsigned int r;		/* computed remainder */
+	unsigned int q_n;	/* specifies if quotient shall be negative */
+	unsigned int r_n;	/* specifies if remainder shall be negative */
+};
+
+static void uint_div_qr(unsigned int numerator, unsigned int denominator,
+			struct qr *qr);
+
+/* returns in R0 and R1 by tail calling an asm function */
+unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);
+
+unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator);
+
+/* returns in R0 and R1 by tail calling an asm function */
+signed int __aeabi_idivmod(signed int numerator, signed int denominator);
+
+signed int __aeabi_idiv(signed int numerator, signed int denominator);
+
+/*
+ * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
+ * Numerator and Denominator are received in R0 and R1.
+ * Where __ste_idivmod_ret_t is returned in R0 and R1.
+ *
+ * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
+ *                                       unsigned denominator)
+ * Numerator and Denominator are received in R0 and R1.
+ * Where __ste_uidivmod_ret_t is returned in R0 and R1.
+ */
+#ifdef __GNUC__
+signed int ret_idivmod_values(signed int quotient, signed int remainder);
+unsigned int ret_uidivmod_values(unsigned int quotient, unsigned int remainder);
+#else
+#error "Compiler not supported"
+#endif
+
+static void division_qr(unsigned int n, unsigned int p, struct qr *qr)
+{
+	unsigned int i = 1, q = 0;
+
+	if (p == 0) {
+		qr->r = 0xFFFFFFFF;	/* division by 0 */
+		return;
+	}
+
+	while ((p >> 31) == 0) {
+		i = i << 1;	/* count the max division steps */
+		p = p << 1;     /* increase p until it has maximum size*/
+	}
+
+	while (i > 0) {
+		q = q << 1;	/* write bit in q at index (size-1) */
+		if (n >= p) {
+			n -= p;
+			q++;
+		}
+		p = p >> 1;	/* decrease p */
+		i = i >> 1;	/* decrease remaining size in q */
+	}
+	qr->r = n;
+	qr->q = q;
+}
+
+static void uint_div_qr(unsigned int numerator, unsigned int denominator,
+			struct qr *qr)
+{
+	division_qr(numerator, denominator, qr);
+
+	/* negate quotient and/or remainder according to requester */
+	if (qr->q_n)
+		qr->q = -qr->q;
+	if (qr->r_n)
+		qr->r = -qr->r;
+}
+
+unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator)
+{
+	struct qr qr = { .q_n = 0, .r_n = 0 };
+
+	uint_div_qr(numerator, denominator, &qr);
+
+	return qr.q;
+}
+
+unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator)
+{
+	struct qr qr = { .q_n = 0, .r_n = 0 };
+
+	uint_div_qr(numerator, denominator, &qr);
+
+	return ret_uidivmod_values(qr.q, qr.r);
+}
+
+signed int __aeabi_idiv(signed int numerator, signed int denominator)
+{
+	struct qr qr = { .q_n = 0, .r_n = 0 };
+
+	if (((numerator < 0) && (denominator > 0)) ||
+	    ((numerator > 0) && (denominator < 0)))
+		qr.q_n = 1;	/* quotient shall be negate */
+
+	if (numerator < 0) {
+		numerator = -numerator;
+		qr.r_n = 1;	/* remainder shall be negate */
+	}
+
+	if (denominator < 0)
+		denominator = -denominator;
+
+	uint_div_qr(numerator, denominator, &qr);
+
+	return qr.q;
+}
+
+signed int __aeabi_idivmod(signed int numerator, signed int denominator)
+{
+	struct qr qr = { .q_n = 0, .r_n = 0 };
+
+	if (((numerator < 0) && (denominator > 0)) ||
+	    ((numerator > 0) && (denominator < 0)))
+		qr.q_n = 1;	/* quotient shall be negate */
+
+	if (numerator < 0) {
+		numerator = -numerator;
+		qr.r_n = 1;	/* remainder shall be negate */
+	}
+
+	if (denominator < 0)
+		denominator = -denominator;
+
+	uint_div_qr(numerator, denominator, &qr);
+
+	return ret_idivmod_values(qr.q, qr.r);
+}
diff --git a/lib/aarch32/arm32_aeabi_divmod_a32.S b/lib/aarch32/arm32_aeabi_divmod_a32.S
new file mode 100644
index 0000000..6915dcd
--- /dev/null
+++ b/lib/aarch32/arm32_aeabi_divmod_a32.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/*
+ * EABI wrappers from the udivmod and idivmod functions
+ */
+
+	.globl ret_uidivmod_values
+	.globl ret_idivmod_values
+
+/*
+ * signed ret_idivmod_values(signed quot, signed rem);
+ * return quotient and remaining the EABI way (regs r0,r1)
+ */
+func ret_idivmod_values
+        bx lr
+endfunc ret_idivmod_values
+
+/*
+ * unsigned ret_uidivmod_values(unsigned quot, unsigned rem);
+ * return quotient and remaining the EABI way (regs r0,r1)
+ */
+func ret_uidivmod_values
+        bx      lr
+endfunc ret_uidivmod_values
diff --git a/lib/aarch32/armclang_printf.S b/lib/aarch32/armclang_printf.S
new file mode 100644
index 0000000..2b87bf7
--- /dev/null
+++ b/lib/aarch32/armclang_printf.S
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/* Symbols needed by armclang */
+
+	.globl __0printf
+	.globl __1printf
+	.globl __2printf
+
+func __0printf
+__1printf:
+__2printf:
+        b	printf
+endfunc __0printf
diff --git a/lib/aarch32/cache_helpers.S b/lib/aarch32/cache_helpers.S
new file mode 100644
index 0000000..7cbefe6
--- /dev/null
+++ b/lib/aarch32/cache_helpers.S
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	flush_dcache_range
+	.globl	clean_dcache_range
+	.globl	inv_dcache_range
+	.globl	dcsw_op_louis
+	.globl	dcsw_op_all
+	.globl	dcsw_op_level1
+	.globl	dcsw_op_level2
+	.globl	dcsw_op_level3
+
+/*
+ * This macro can be used for implementing various data cache operations `op`
+ */
+.macro do_dcache_maintenance_by_mva op, coproc, opc1, CRn, CRm, opc2
+	/* Exit early if size is zero */
+	cmp	r1, #0
+	beq	exit_loop_\op
+	dcache_line_size r2, r3
+	add	r1, r0, r1
+	sub	r3, r2, #1
+	bic	r0, r0, r3
+loop_\op:
+	stcopr	r0, \coproc, \opc1, \CRn, \CRm, \opc2
+	add	r0, r0, r2
+	cmp	r0, r1
+	blo	loop_\op
+	dsb	sy
+exit_loop_\op:
+	bx	lr
+.endm
+
+	/* ------------------------------------------
+	 * Clean+Invalidate from base address till
+	 * size. 'r0' = addr, 'r1' = size
+	 * ------------------------------------------
+	 */
+func flush_dcache_range
+	do_dcache_maintenance_by_mva cimvac, DCCIMVAC
+endfunc flush_dcache_range
+
+	/* ------------------------------------------
+	 * Clean from base address till size.
+	 * 'r0' = addr, 'r1' = size
+	 * ------------------------------------------
+	 */
+func clean_dcache_range
+	do_dcache_maintenance_by_mva cmvac, DCCMVAC
+endfunc clean_dcache_range
+
+	/* ------------------------------------------
+	 * Invalidate from base address till
+	 * size. 'r0' = addr, 'r1' = size
+	 * ------------------------------------------
+	 */
+func inv_dcache_range
+	do_dcache_maintenance_by_mva imvac, DCIMVAC
+endfunc inv_dcache_range
+
+	/* ----------------------------------------------------------------
+	 * Data cache operations by set/way to the level specified
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
+	 * as defined in arch.h
+	 * r1: The cache level to begin operation from
+	 * r2: clidr_el1
+	 * r3: The last cache level to operate on
+	 * and will carry out the operation on each data cache from level 0
+	 * to the level in r3 in sequence
+	 *
+	 * The dcsw_op macro sets up the r2 and r3 parameters based on
+	 * clidr_el1 cache information before invoking the main function
+	 * ----------------------------------------------------------------
+	 */
+
+	.macro	dcsw_op shift, fw, ls
+	ldcopr	r2, CLIDR
+	ubfx	r3, r2, \shift, \fw
+	lsl	r3, r3, \ls
+	mov	r1, #0
+	b	do_dcsw_op
+	.endm
+
+func do_dcsw_op
+	push	{r4-r12, lr}
+	adr	r11, dcsw_loop_table	// compute cache op based on the operation type
+	add	r6, r11, r0, lsl #3	// cache op is 2x32-bit instructions
+loop1:
+	add	r10, r1, r1, LSR #1	// Work out 3x current cache level
+	mov	r12, r2, LSR r10	// extract cache type bits from clidr
+	and	r12, r12, #7		// mask the bits for current cache only
+	cmp	r12, #2			// see what cache we have at this level
+	blo	level_done		// no cache or only instruction cache at this level
+
+	stcopr	r1, CSSELR		// select current cache level in csselr
+	isb				// isb to sych the new cssr&csidr
+	ldcopr	r12, CCSIDR		// read the new ccsidr
+	and	r10, r12, #7		// extract the length of the cache lines
+	add	r10, r10, #4		// add 4 (r10 = line length offset)
+	ubfx	r4, r12, #3, #10	// r4 = maximum way number (right aligned)
+	clz	r5, r4			// r5 = the bit position of the way size increment
+	mov	r9, r4			// r9 working copy of the aligned max way number
+
+loop2:
+	ubfx	r7, r12, #13, #15	// r7 = max set number (right aligned)
+
+loop3:
+	orr	r0, r1, r9, LSL r5	// factor in the way number and cache level into r0
+	orr	r0, r0, r7, LSL r10	// factor in the set number
+
+	blx	r6
+	subs	r7, r7, #1		// decrement the set number
+	bhs	loop3
+	subs	r9, r9, #1		// decrement the way number
+	bhs	loop2
+level_done:
+	add	r1, r1, #2		// increment the cache number
+	cmp	r3, r1
+	// Ensure completion of previous cache maintenance instruction. Note
+	// this also mitigates erratum 814220 on Cortex-A7
+	dsb	sy
+	bhi	loop1
+
+	mov	r6, #0
+	stcopr	r6, CSSELR		//select cache level 0 in csselr
+	dsb	sy
+	isb
+	pop	{r4-r12, pc}
+
+dcsw_loop_table:
+	stcopr	r0, DCISW
+	bx	lr
+	stcopr	r0, DCCISW
+	bx	lr
+	stcopr	r0, DCCSW
+	bx	lr
+
+endfunc do_dcsw_op
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way till PoU.
+	 *
+	 * The function requires :
+	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
+	 * as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_louis
+	dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
+endfunc	dcsw_op_louis
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way till PoC.
+	 *
+	 * The function requires :
+	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
+	 * as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_all
+	dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
+endfunc	dcsw_op_all
+
+
+	/* ---------------------------------------------------------------
+	 *  Helper macro for data cache operations by set/way for the
+	 *  level specified
+	 * ---------------------------------------------------------------
+	 */
+	.macro	dcsw_op_level level
+	ldcopr	r2, CLIDR
+	mov	r3, \level
+	sub	r1, r3, #2
+	b	do_dcsw_op
+	.endm
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way for level 1 cache
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
+	 * as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_level1
+	dcsw_op_level #(1 << LEVEL_SHIFT)
+endfunc dcsw_op_level1
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way for level 2 cache
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
+	 * as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_level2
+	dcsw_op_level #(2 << LEVEL_SHIFT)
+endfunc dcsw_op_level2
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way for level 3 cache
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
+	 * as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_level3
+	dcsw_op_level #(3 << LEVEL_SHIFT)
+endfunc dcsw_op_level3
diff --git a/lib/aarch32/misc_helpers.S b/lib/aarch32/misc_helpers.S
new file mode 100644
index 0000000..6d2ec1c
--- /dev/null
+++ b/lib/aarch32/misc_helpers.S
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+	.globl	smc
+	.globl	zeromem
+	.globl	zero_normalmem
+	.globl	memcpy4
+	.globl	disable_mmu_icache_secure
+	.globl	disable_mmu_secure
+
+func smc
+	/*
+	 * For AArch32 only r0-r3 will be in the registers;
+	 * rest r4-r6 will be pushed on to the stack. So here, we'll
+	 * have to load them from the stack to registers r4-r6 explicitly.
+	 * Clobbers: r4-r6
+	 */
+	ldm	sp, {r4, r5, r6}
+	smc	#0
+endfunc smc
+
+/* -----------------------------------------------------------------------
+ * void zeromem(void *mem, unsigned int length)
+ *
+ * Initialise a region in normal memory to 0. This functions complies with the
+ * AAPCS and can be called from C code.
+ *
+ * -----------------------------------------------------------------------
+ */
+func zeromem
+	/*
+	 * Readable names for registers
+	 *
+	 * Registers r0, r1 and r2 are also set by zeromem which
+	 * branches into the fallback path directly, so cursor, length and
+	 * stop_address should not be retargeted to other registers.
+	 */
+	cursor       .req r0 /* Start address and then current address */
+	length       .req r1 /* Length in bytes of the region to zero out */
+	/*
+	 * Reusing the r1 register as length is only used at the beginning of
+	 * the function.
+	 */
+	stop_address .req r1  /* Address past the last zeroed byte */
+	zeroreg1     .req r2  /* Source register filled with 0 */
+	zeroreg2     .req r3  /* Source register filled with 0 */
+	tmp	     .req r12 /* Temporary scratch register */
+
+	mov	zeroreg1, #0
+
+	/* stop_address is the address past the last to zero */
+	add	stop_address, cursor, length
+
+	/*
+	 * Length cannot be used anymore as it shares the same register with
+	 * stop_address.
+	 */
+	.unreq	length
+
+	/*
+	 * If the start address is already aligned to 8 bytes, skip this loop.
+	 */
+	tst	cursor, #(8-1)
+	beq	.Lzeromem_8bytes_aligned
+
+	/* Calculate the next address aligned to 8 bytes */
+	orr	tmp, cursor, #(8-1)
+	adds	tmp, tmp, #1
+	/* If it overflows, fallback to byte per byte zeroing */
+	beq	.Lzeromem_1byte_aligned
+	/* If the next aligned address is after the stop address, fall back */
+	cmp	tmp, stop_address
+	bhs	.Lzeromem_1byte_aligned
+
+	/* zero byte per byte */
+1:
+	strb	zeroreg1, [cursor], #1
+	cmp	cursor, tmp
+	bne	1b
+
+	/* zero 8 bytes at a time */
+.Lzeromem_8bytes_aligned:
+
+	/* Calculate the last 8 bytes aligned address. */
+	bic	tmp, stop_address, #(8-1)
+
+	cmp	cursor, tmp
+	bhs	2f
+
+	mov	zeroreg2, #0
+1:
+	stmia	cursor!, {zeroreg1, zeroreg2}
+	cmp	cursor, tmp
+	blo	1b
+2:
+
+	/* zero byte per byte */
+.Lzeromem_1byte_aligned:
+	cmp	cursor, stop_address
+	beq	2f
+1:
+	strb	zeroreg1, [cursor], #1
+	cmp	cursor, stop_address
+	bne	1b
+2:
+	bx	lr
+
+	.unreq	cursor
+	/*
+	 * length is already unreq'ed to reuse the register for another
+	 * variable.
+	 */
+	.unreq	stop_address
+	.unreq	zeroreg1
+	.unreq	zeroreg2
+	.unreq	tmp
+endfunc zeromem
+
+/*
+ * AArch32 does not have special ways of zeroing normal memory as AArch64 does
+ * using the DC ZVA instruction, so we just alias zero_normalmem to zeromem.
+ */
+.equ	zero_normalmem, zeromem
+
+/* --------------------------------------------------------------------------
+ * void memcpy4(void *dest, const void *src, unsigned int length)
+ *
+ * Copy length bytes from memory area src to memory area dest.
+ * The memory areas should not overlap.
+ * Destination and source addresses must be 4-byte aligned.
+ * --------------------------------------------------------------------------
+ */
+func memcpy4
+#if ENABLE_ASSERTIONS
+	orr	r3, r0, r1
+	tst	r3, #0x3
+	ASM_ASSERT(eq)
+#endif
+/* copy 4 bytes at a time */
+m_loop4:
+	cmp	r2, #4
+	blo	m_loop1
+	ldr	r3, [r1], #4
+	str	r3, [r0], #4
+	sub	r2, r2, #4
+	b	m_loop4
+/* copy byte per byte */
+m_loop1:
+	cmp	r2,#0
+	beq	m_end
+	ldrb	r3, [r1], #1
+	strb	r3, [r0], #1
+	subs	r2, r2, #1
+	bne	m_loop1
+m_end:
+	bx	lr
+endfunc memcpy4
+
+/* ---------------------------------------------------------------------------
+ * Disable the MMU in Secure State
+ * ---------------------------------------------------------------------------
+ */
+
+func disable_mmu_secure
+	mov	r1, #(SCTLR_M_BIT | SCTLR_C_BIT)
+do_disable_mmu:
+#if ERRATA_A9_794073
+	stcopr	r0, BPIALL
+	dsb
+#endif
+	ldcopr	r0, SCTLR
+	bic	r0, r0, r1
+	stcopr	r0, SCTLR
+	isb				// ensure MMU is off
+	dsb	sy
+	bx	lr
+endfunc disable_mmu_secure
+
+
+func disable_mmu_icache_secure
+	ldr	r1, =(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+	b	do_disable_mmu
+endfunc disable_mmu_icache_secure
diff --git a/lib/aarch64/armclang_printf.S b/lib/aarch64/armclang_printf.S
new file mode 100644
index 0000000..52a6976
--- /dev/null
+++ b/lib/aarch64/armclang_printf.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+/* Symbols needed by armclang */
+
+	.globl __0printf
+	.globl __1printf
+	.globl __2printf
+
+func __0printf
+	b	printf
+endfunc __0printf
+
+func __1printf
+	b	printf
+endfunc __1printf
+
+func __2printf
+	b	printf
+endfunc __2printf
diff --git a/lib/aarch64/cache_helpers.S b/lib/aarch64/cache_helpers.S
new file mode 100644
index 0000000..9ef8ca7
--- /dev/null
+++ b/lib/aarch64/cache_helpers.S
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	flush_dcache_range
+	.globl	clean_dcache_range
+	.globl	inv_dcache_range
+	.globl	dcsw_op_louis
+	.globl	dcsw_op_all
+	.globl	dcsw_op_level1
+	.globl	dcsw_op_level2
+	.globl	dcsw_op_level3
+
+/*
+ * This macro can be used for implementing various data cache operations `op`
+ */
+.macro do_dcache_maintenance_by_mva op
+	/* Exit early if size is zero */
+	cbz	x1, exit_loop_\op
+	dcache_line_size x2, x3
+	add	x1, x0, x1
+	sub	x3, x2, #1
+	bic	x0, x0, x3
+loop_\op:
+	dc	\op, x0
+	add	x0, x0, x2
+	cmp	x0, x1
+	b.lo    loop_\op
+	dsb	sy
+exit_loop_\op:
+	ret
+.endm
+	/* ------------------------------------------
+	 * Clean+Invalidate from base address till
+	 * size. 'x0' = addr, 'x1' = size
+	 * ------------------------------------------
+	 */
+func flush_dcache_range
+	do_dcache_maintenance_by_mva civac
+endfunc flush_dcache_range
+
+	/* ------------------------------------------
+	 * Clean from base address till size.
+	 * 'x0' = addr, 'x1' = size
+	 * ------------------------------------------
+	 */
+func clean_dcache_range
+	do_dcache_maintenance_by_mva cvac
+endfunc clean_dcache_range
+
+	/* ------------------------------------------
+	 * Invalidate from base address till
+	 * size. 'x0' = addr, 'x1' = size
+	 * ------------------------------------------
+	 */
+func inv_dcache_range
+	do_dcache_maintenance_by_mva ivac
+endfunc inv_dcache_range
+
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way to the level specified
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * x0: The operation type (0-2), as defined in arch.h
+	 * x3: The last cache level to operate on
+	 * x9: clidr_el1
+	 * x10: The cache level to begin operation from
+	 * and will carry out the operation on each data cache from level 0
+	 * to the level in x3 in sequence
+	 *
+	 * The dcsw_op macro sets up the x3 and x9 parameters based on
+	 * clidr_el1 cache information before invoking the main function
+	 * ---------------------------------------------------------------
+	 */
+
+	.macro	dcsw_op shift, fw, ls
+	mrs	x9, clidr_el1
+	ubfx	x3, x9, \shift, \fw
+	lsl	x3, x3, \ls
+	mov	x10, xzr
+	b	do_dcsw_op
+	.endm
+
+func do_dcsw_op
+	cbz	x3, exit
+	adr	x14, dcsw_loop_table	// compute inner loop address
+	add	x14, x14, x0, lsl #5	// inner loop is 8x32-bit instructions
+#if ENABLE_BTI
+	add	x14, x14, x0, lsl #2	// inner loop is + "bti j" instruction
+#endif
+	mov	x0, x9
+	mov	w8, #1
+loop1:
+	add	x2, x10, x10, lsr #1	// work out 3x current cache level
+	lsr	x1, x0, x2		// extract cache type bits from clidr
+	and	x1, x1, #7		// mask the bits for current cache only
+	cmp	x1, #2			// see what cache we have at this level
+	b.lo	level_done		// nothing to do if no cache or icache
+
+	msr	csselr_el1, x10		// select current cache level in csselr
+	isb				// isb to sych the new cssr&csidr
+	mrs	x1, ccsidr_el1		// read the new ccsidr
+	and	x2, x1, #7		// extract the length of the cache lines
+	add	x2, x2, #4		// add 4 (line length offset)
+	ubfx	x4, x1, #3, #10		// maximum way number
+	clz	w5, w4			// bit position of way size increment
+	lsl	w9, w4, w5		// w9 = aligned max way number
+	lsl	w16, w8, w5		// w16 = way number loop decrement
+	orr	w9, w10, w9		// w9 = combine way and cache number
+	ubfx	w6, w1, #13, #15	// w6 = max set number
+	lsl	w17, w8, w2		// w17 = set number loop decrement
+	dsb	sy			// barrier before we start this level
+	br	x14			// jump to DC operation specific loop
+
+	.macro	dcsw_loop _op
+#if ENABLE_BTI
+	bti	j
+#endif
+loop2_\_op:
+	lsl	w7, w6, w2		// w7 = aligned max set number
+
+loop3_\_op:
+	orr	w11, w9, w7		// combine cache, way and set number
+	dc	\_op, x11
+	subs	w7, w7, w17		// decrement set number
+	b.hs	loop3_\_op
+
+	subs	x9, x9, x16		// decrement way number
+	b.hs	loop2_\_op
+
+	b	level_done
+	.endm
+
+level_done:
+	add	x10, x10, #2		// increment cache number
+	cmp	x3, x10
+	b.hi    loop1
+	msr	csselr_el1, xzr		// select cache level 0 in csselr
+	dsb	sy			// barrier to complete final cache operation
+	isb
+exit:
+	ret
+endfunc do_dcsw_op
+
+dcsw_loop_table:
+	dcsw_loop isw
+	dcsw_loop cisw
+	dcsw_loop csw
+
+
+func dcsw_op_louis
+	dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
+endfunc dcsw_op_louis
+
+
+func dcsw_op_all
+	dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
+endfunc dcsw_op_all
+
+	/* ---------------------------------------------------------------
+	 *  Helper macro for data cache operations by set/way for the
+	 *  level specified
+	 * ---------------------------------------------------------------
+	 */
+	.macro dcsw_op_level level
+	mrs	x9, clidr_el1
+	mov	x3, \level
+	sub	x10, x3, #2
+	b	do_dcsw_op
+	.endm
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way for level 1 cache
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * x0: The operation type (0-2), as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_level1
+	dcsw_op_level #(1 << LEVEL_SHIFT)
+endfunc dcsw_op_level1
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way for level 2 cache
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * x0: The operation type (0-2), as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_level2
+	dcsw_op_level #(2 << LEVEL_SHIFT)
+endfunc dcsw_op_level2
+
+	/* ---------------------------------------------------------------
+	 * Data cache operations by set/way for level 3 cache
+	 *
+	 * The main function, do_dcsw_op requires:
+	 * x0: The operation type (0-2), as defined in arch.h
+	 * ---------------------------------------------------------------
+	 */
+func dcsw_op_level3
+	dcsw_op_level #(3 << LEVEL_SHIFT)
+endfunc dcsw_op_level3
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
new file mode 100644
index 0000000..d298f2b
--- /dev/null
+++ b/lib/aarch64/misc_helpers.S
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+	.globl	smc
+
+	.globl	zero_normalmem
+	.globl	zeromem
+	.globl	memcpy16
+
+	.globl	disable_mmu_el1
+	.globl	disable_mmu_el3
+	.globl	disable_mmu_icache_el1
+	.globl	disable_mmu_icache_el3
+	.globl	fixup_gdt_reloc
+#if SUPPORT_VFP
+	.globl	enable_vfp
+#endif
+
+func smc
+	smc	#0
+endfunc smc
+
+/* -----------------------------------------------------------------------
+ * void zero_normalmem(void *mem, unsigned int length);
+ *
+ * Initialise a region in normal memory to 0. This functions complies with the
+ * AAPCS and can be called from C code.
+ *
+ * NOTE: MMU must be enabled when using this function as it can only operate on
+ *       normal memory. It is intended to be mainly used from C code when MMU
+ *       is usually enabled.
+ * -----------------------------------------------------------------------
+ */
+.equ	zero_normalmem, zeromem_dczva
+
+/* -----------------------------------------------------------------------
+ * void zeromem(void *mem, unsigned int length);
+ *
+ * Initialise a region of device memory to 0. This functions complies with the
+ * AAPCS and can be called from C code.
+ *
+ * NOTE: When data caches and MMU are enabled, zero_normalmem can usually be
+ *       used instead for faster zeroing.
+ *
+ * -----------------------------------------------------------------------
+ */
+func zeromem
+	/* x2 is the address past the last zeroed address */
+	add	x2, x0, x1
+	/*
+	 * Uses the fallback path that does not use DC ZVA instruction and
+	 * therefore does not need enabled MMU
+	 */
+	b	.Lzeromem_dczva_fallback_entry
+endfunc zeromem
+
+/* -----------------------------------------------------------------------
+ * void zeromem_dczva(void *mem, unsigned int length);
+ *
+ * Fill a region of normal memory of size "length" in bytes with null bytes.
+ * MMU must be enabled and the memory be of
+ * normal type. This is because this function internally uses the DC ZVA
+ * instruction, which generates an Alignment fault if used on any type of
+ * Device memory (see section D3.4.9 of the ARMv8 ARM, issue k). When the MMU
+ * is disabled, all memory behaves like Device-nGnRnE memory (see section
+ * D4.2.8), hence the requirement on the MMU being enabled.
+ * NOTE: The code assumes that the block size as defined in DCZID_EL0
+ *       register is at least 16 bytes.
+ *
+ * -----------------------------------------------------------------------
+ */
+func zeromem_dczva
+
+	/*
+	 * The function consists of a series of loops that zero memory one byte
+	 * at a time, 16 bytes at a time or using the DC ZVA instruction to
+	 * zero aligned block of bytes, which is assumed to be more than 16.
+	 * In the case where the DC ZVA instruction cannot be used or if the
+	 * first 16 bytes loop would overflow, there is fallback path that does
+	 * not use DC ZVA.
+	 * Note: The fallback path is also used by the zeromem function that
+	 *       branches to it directly.
+	 *
+	 *              +---------+   zeromem_dczva
+	 *              |  entry  |
+	 *              +----+----+
+	 *                   |
+	 *                   v
+	 *              +---------+
+	 *              | checks  |>o-------+ (If any check fails, fallback)
+	 *              +----+----+         |
+	 *                   |              |---------------+
+	 *                   v              | Fallback path |
+	 *            +------+------+       |---------------+
+	 *            | 1 byte loop |       |
+	 *            +------+------+ .Lzeromem_dczva_initial_1byte_aligned_end
+	 *                   |              |
+	 *                   v              |
+	 *           +-------+-------+      |
+	 *           | 16 bytes loop |      |
+	 *           +-------+-------+      |
+	 *                   |              |
+	 *                   v              |
+	 *            +------+------+ .Lzeromem_dczva_blocksize_aligned
+	 *            | DC ZVA loop |       |
+	 *            +------+------+       |
+	 *       +--------+  |              |
+	 *       |        |  |              |
+	 *       |        v  v              |
+	 *       |   +-------+-------+ .Lzeromem_dczva_final_16bytes_aligned
+	 *       |   | 16 bytes loop |      |
+	 *       |   +-------+-------+      |
+	 *       |           |              |
+	 *       |           v              |
+	 *       |    +------+------+ .Lzeromem_dczva_final_1byte_aligned
+	 *       |    | 1 byte loop |       |
+	 *       |    +-------------+       |
+	 *       |           |              |
+	 *       |           v              |
+	 *       |       +---+--+           |
+	 *       |       | exit |           |
+	 *       |       +------+           |
+	 *       |			    |
+	 *       |           +--------------+    +------------------+ zeromem
+	 *       |           |  +----------------| zeromem function |
+	 *       |           |  |                +------------------+
+	 *       |           v  v
+	 *       |    +-------------+ .Lzeromem_dczva_fallback_entry
+	 *       |    | 1 byte loop |
+	 *       |    +------+------+
+	 *       |           |
+	 *       +-----------+
+	 */
+
+	/*
+	 * Readable names for registers
+	 *
+	 * Registers x0, x1 and x2 are also set by zeromem which
+	 * branches into the fallback path directly, so cursor, length and
+	 * stop_address should not be retargeted to other registers.
+	 */
+	cursor       .req x0 /* Start address and then current address */
+	length       .req x1 /* Length in bytes of the region to zero out */
+	/* Reusing x1 as length is never used after block_mask is set */
+	block_mask   .req x1 /* Bitmask of the block size read in DCZID_EL0 */
+	stop_address .req x2 /* Address past the last zeroed byte */
+	block_size   .req x3 /* Size of a block in bytes as read in DCZID_EL0 */
+	tmp1         .req x4
+	tmp2         .req x5
+
+#if ENABLE_ASSERTIONS
+	/*
+	 * Check for M bit (MMU enabled) of the current SCTLR_EL(1|3)
+	 * register value and panic if the MMU is disabled.
+	 */
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3)
+	mrs	tmp1, sctlr_el3
+#else
+	mrs	tmp1, sctlr_el1
+#endif
+
+	tst	tmp1, #SCTLR_M_BIT
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* stop_address is the address past the last to zero */
+	add	stop_address, cursor, length
+
+	/*
+	 * Get block_size = (log2(<block size>) >> 2) (see encoding of
+	 * dczid_el0 reg)
+	 */
+	mrs	block_size, dczid_el0
+
+	/*
+	 * Select the 4 lowest bits and convert the extracted log2(<block size
+	 * in words>) to <block size in bytes>
+	 */
+	ubfx	block_size, block_size, #0, #4
+	mov	tmp2, #(1 << 2)
+	lsl	block_size, tmp2, block_size
+
+#if ENABLE_ASSERTIONS
+	/*
+	 * Assumes block size is at least 16 bytes to avoid manual realignment
+	 * of the cursor at the end of the DCZVA loop.
+	 */
+	cmp	block_size, #16
+	ASM_ASSERT(hs)
+#endif
+	/*
+	 * Not worth doing all the setup for a region less than a block and
+	 * protects against zeroing a whole block when the area to zero is
+	 * smaller than that. Also, as it is assumed that the block size is at
+	 * least 16 bytes, this also protects the initial aligning loops from
+	 * trying to zero 16 bytes when length is less than 16.
+	 */
+	cmp	length, block_size
+	b.lo	.Lzeromem_dczva_fallback_entry
+
+	/*
+	 * Calculate the bitmask of the block alignment. It will never
+	 * underflow as the block size is between 4 bytes and 2kB.
+	 * block_mask = block_size - 1
+	 */
+	sub	block_mask, block_size, #1
+
+	/*
+	 * length alias should not be used after this point unless it is
+	 * defined as a register other than block_mask's.
+	 */
+	 .unreq length
+
+	/*
+	 * If the start address is already aligned to zero block size, go
+	 * straight to the cache zeroing loop. This is safe because at this
+	 * point, the length cannot be smaller than a block size.
+	 */
+	tst	cursor, block_mask
+	b.eq	.Lzeromem_dczva_blocksize_aligned
+
+	/*
+	 * Calculate the first block-size-aligned address. It is assumed that
+	 * the zero block size is at least 16 bytes. This address is the last
+	 * address of this initial loop.
+	 */
+	orr	tmp1, cursor, block_mask
+	add	tmp1, tmp1, #1
+
+	/*
+	 * If the addition overflows, skip the cache zeroing loops. This is
+	 * quite unlikely however.
+	 */
+	cbz	tmp1, .Lzeromem_dczva_fallback_entry
+
+	/*
+	 * If the first block-size-aligned address is past the last address,
+	 * fallback to the simpler code.
+	 */
+	cmp	tmp1, stop_address
+	b.hi	.Lzeromem_dczva_fallback_entry
+
+	/*
+	 * If the start address is already aligned to 16 bytes, skip this loop.
+	 * It is safe to do this because tmp1 (the stop address of the initial
+	 * 16 bytes loop) will never be greater than the final stop address.
+	 */
+	tst	cursor, #0xf
+	b.eq	.Lzeromem_dczva_initial_1byte_aligned_end
+
+	/* Calculate the next address aligned to 16 bytes */
+	orr	tmp2, cursor, #0xf
+	add	tmp2, tmp2, #1
+	/* If it overflows, fallback to the simple path (unlikely) */
+	cbz	tmp2, .Lzeromem_dczva_fallback_entry
+	/*
+	 * Next aligned address cannot be after the stop address because the
+	 * length cannot be smaller than 16 at this point.
+	 */
+
+	/* First loop: zero byte per byte */
+1:
+	strb	wzr, [cursor], #1
+	cmp	cursor, tmp2
+	b.ne	1b
+.Lzeromem_dczva_initial_1byte_aligned_end:
+
+	/*
+	 * Second loop: we need to zero 16 bytes at a time from cursor to tmp1
+	 * before being able to use the code that deals with block-size-aligned
+	 * addresses.
+	 */
+	cmp	cursor, tmp1
+	b.hs	2f
+1:
+	stp	xzr, xzr, [cursor], #16
+	cmp	cursor, tmp1
+	b.lo	1b
+2:
+
+	/*
+	 * Third loop: zero a block at a time using DC ZVA cache block zeroing
+	 * instruction.
+	 */
+.Lzeromem_dczva_blocksize_aligned:
+	/*
+	 * Calculate the last block-size-aligned address. If the result equals
+	 * to the start address, the loop will exit immediately.
+	 */
+	bic	tmp1, stop_address, block_mask
+
+	cmp	cursor, tmp1
+	b.hs	2f
+1:
+	/* Zero the block containing the cursor */
+	dc	zva, cursor
+	/* Increment the cursor by the size of a block */
+	add	cursor, cursor, block_size
+	cmp	cursor, tmp1
+	b.lo	1b
+2:
+
+	/*
+	 * Fourth loop: zero 16 bytes at a time and then byte per byte the
+	 * remaining area
+	 */
+.Lzeromem_dczva_final_16bytes_aligned:
+	/*
+	 * Calculate the last 16 bytes aligned address. It is assumed that the
+	 * block size will never be smaller than 16 bytes so that the current
+	 * cursor is aligned to at least 16 bytes boundary.
+	 */
+	bic	tmp1, stop_address, #15
+
+	cmp	cursor, tmp1
+	b.hs	2f
+1:
+	stp	xzr, xzr, [cursor], #16
+	cmp	cursor, tmp1
+	b.lo	1b
+2:
+
+	/* Fifth and final loop: zero byte per byte */
+.Lzeromem_dczva_final_1byte_aligned:
+	cmp	cursor, stop_address
+	b.eq	2f
+1:
+	strb	wzr, [cursor], #1
+	cmp	cursor, stop_address
+	b.ne	1b
+2:
+	ret
+
+	/* Fallback for unaligned start addresses */
+.Lzeromem_dczva_fallback_entry:
+	/*
+	 * If the start address is already aligned to 16 bytes, skip this loop.
+	 */
+	tst	cursor, #0xf
+	b.eq	.Lzeromem_dczva_final_16bytes_aligned
+
+	/* Calculate the next address aligned to 16 bytes */
+	orr	tmp1, cursor, #15
+	add	tmp1, tmp1, #1
+	/* If it overflows, fallback to byte per byte zeroing */
+	cbz	tmp1, .Lzeromem_dczva_final_1byte_aligned
+	/* If the next aligned address is after the stop address, fall back */
+	cmp	tmp1, stop_address
+	b.hs	.Lzeromem_dczva_final_1byte_aligned
+
+	/* Fallback entry loop: zero byte per byte */
+1:
+	strb	wzr, [cursor], #1
+	cmp	cursor, tmp1
+	b.ne	1b
+
+	b	.Lzeromem_dczva_final_16bytes_aligned
+
+	.unreq	cursor
+	/*
+	 * length is already unreq'ed to reuse the register for another
+	 * variable.
+	 */
+	.unreq	stop_address
+	.unreq	block_size
+	.unreq	block_mask
+	.unreq	tmp1
+	.unreq	tmp2
+endfunc zeromem_dczva
+
+/* --------------------------------------------------------------------------
+ * void memcpy16(void *dest, const void *src, unsigned int length)
+ *
+ * Copy length bytes from memory area src to memory area dest.
+ * The memory areas should not overlap.
+ * Destination and source addresses must be 16-byte aligned.
+ * --------------------------------------------------------------------------
+ */
+func memcpy16
+#if ENABLE_ASSERTIONS
+	orr	x3, x0, x1
+	tst	x3, #0xf
+	ASM_ASSERT(eq)
+#endif
+/* copy 16 bytes at a time */
+m_loop16:
+	cmp	x2, #16
+	b.lo	m_loop1
+	ldp	x3, x4, [x1], #16
+	stp	x3, x4, [x0], #16
+	sub	x2, x2, #16
+	b	m_loop16
+/* copy byte per byte */
+m_loop1:
+	cbz	x2, m_end
+	ldrb	w3, [x1], #1
+	strb	w3, [x0], #1
+	subs	x2, x2, #1
+	b.ne	m_loop1
+m_end:
+	ret
+endfunc memcpy16
+
+/* ---------------------------------------------------------------------------
+ * Disable the MMU at EL3
+ * ---------------------------------------------------------------------------
+ */
+
+func disable_mmu_el3
+	mov	x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
+do_disable_mmu_el3:
+	mrs	x0, sctlr_el3
+	bic	x0, x0, x1
+	msr	sctlr_el3, x0
+	isb	/* ensure MMU is off */
+	dsb	sy
+	ret
+endfunc disable_mmu_el3
+
+
+func disable_mmu_icache_el3
+	mov	x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+	b	do_disable_mmu_el3
+endfunc disable_mmu_icache_el3
+
+/* ---------------------------------------------------------------------------
+ * Disable the MMU at EL1
+ * ---------------------------------------------------------------------------
+ */
+
+func disable_mmu_el1
+	mov	x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
+do_disable_mmu_el1:
+	mrs	x0, sctlr_el1
+	bic	x0, x0, x1
+	msr	sctlr_el1, x0
+	isb	/* ensure MMU is off */
+	dsb	sy
+	ret
+endfunc disable_mmu_el1
+
+
+func disable_mmu_icache_el1
+	mov	x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
+	b	do_disable_mmu_el1
+endfunc disable_mmu_icache_el1
+
+/* ---------------------------------------------------------------------------
+ * Enable the use of VFP at EL3
+ * ---------------------------------------------------------------------------
+ */
+#if SUPPORT_VFP
+func enable_vfp
+	mrs	x0, cpacr_el1
+	orr	x0, x0, #CPACR_VFP_BITS
+	msr	cpacr_el1, x0
+	mrs	x0, cptr_el3
+	mov	x1, #AARCH64_CPTR_TFP
+	bic	x0, x0, x1
+	msr	cptr_el3, x0
+	isb
+	ret
+endfunc enable_vfp
+#endif
+
+/* ---------------------------------------------------------------------------
+ * Helper to fixup Global Descriptor table (GDT) and dynamic relocations
+ * (.rela.dyn) at runtime.
+ *
+ * This function is meant to be used when the firmware is compiled with -fpie
+ * and linked with -pie options. We rely on the linker script exporting
+ * appropriate markers for start and end of the section. For GOT, we
+ * expect __GOT_START__ and __GOT_END__. Similarly for .rela.dyn, we expect
+ * __RELA_START__ and __RELA_END__.
+ *
+ * The function takes the limits of the memory to apply fixups to as
+ * arguments (which is usually the limits of the relocable BL image).
+ *   x0 -  the start of the fixup region
+ *   x1 -  the limit of the fixup region
+ * These addresses have to be page (4KB aligned).
+ * ---------------------------------------------------------------------------
+ */
+func fixup_gdt_reloc
+	mov	x6, x0
+	mov	x7, x1
+
+	/* Test if the limits are 4K aligned */
+#if ENABLE_ASSERTIONS
+	orr	x0, x0, x1
+	tst	x0, #(PAGE_SIZE - 1)
+	ASM_ASSERT(eq)
+#endif
+	/*
+	 * Calculate the offset based on return address in x30.
+	 * Assume that this function is called within a page at the start of
+	 * fixup region.
+	 */
+	and	x2, x30, #~(PAGE_SIZE - 1)
+	sub	x0, x2, x6	/* Diff(S) = Current Address - Compiled Address */
+
+	adrp	x1, __GOT_START__
+	add	x1, x1, :lo12:__GOT_START__
+	adrp	x2, __GOT_END__
+	add	x2, x2, :lo12:__GOT_END__
+
+	/*
+	 * GOT is an array of 64_bit addresses which must be fixed up as
+	 * new_addr = old_addr + Diff(S).
+	 * The new_addr is the address currently the binary is executing from
+	 * and old_addr is the address at compile time.
+	 */
+1:
+	ldr	x3, [x1]
+	/* Skip adding offset if address is < lower limit */
+	cmp	x3, x6
+	b.lo	2f
+	/* Skip adding offset if address is >= upper limit */
+	cmp	x3, x7
+	b.ge	2f
+	add	x3, x3, x0
+	str	x3, [x1]
+2:
+	add	x1, x1, #8
+	cmp	x1, x2
+	b.lo	1b
+
+	/* Starting dynamic relocations. Use adrp/adr to get RELA_START and END */
+	adrp	x1, __RELA_START__
+	add	x1, x1, :lo12:__RELA_START__
+	adrp	x2, __RELA_END__
+	add	x2, x2, :lo12:__RELA_END__
+	/*
+	 * According to ELF-64 specification, the RELA data structure is as
+	 * follows:
+	 *	typedef struct
+	 * 	{
+	 *		Elf64_Addr r_offset;
+	 *		Elf64_Xword r_info;
+	 *		Elf64_Sxword r_addend;
+	 *	} Elf64_Rela;
+	 *
+	 * r_offset is address of reference
+	 * r_info is symbol index and type of relocation (in this case
+	 * 0x403 which corresponds to R_AARCH64_RELATIVE).
+	 * r_addend is constant part of expression.
+	 *
+	 * Size of Elf64_Rela structure is 24 bytes.
+	 */
+1:
+	/* Assert that the relocation type is R_AARCH64_RELATIVE */
+#if ENABLE_ASSERTIONS
+	ldr	x3, [x1, #8]
+	cmp	x3, #0x403
+	ASM_ASSERT(eq)
+#endif
+	ldr	x3, [x1]	/* r_offset */
+	add	x3, x0, x3
+	ldr	x4, [x1, #16]	/* r_addend */
+
+	/* Skip adding offset if r_addend is < lower limit */
+	cmp	x4, x6
+	b.lo	2f
+	/* Skip adding offset if r_addend entry is >= upper limit */
+	cmp	x4, x7
+	b.ge	2f
+
+	add	x4, x0, x4	/* Diff(S) + r_addend */
+	str	x4, [x3]
+
+2:	add	x1, x1, #24
+	cmp	x1, x2
+	b.lo	1b
+
+	ret
+endfunc fixup_gdt_reloc
diff --git a/lib/bl_aux_params/bl_aux_params.c b/lib/bl_aux_params/bl_aux_params.c
new file mode 100644
index 0000000..7a8115c
--- /dev/null
+++ b/lib/bl_aux_params/bl_aux_params.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/coreboot.h>
+#include <lib/bl_aux_params/bl_aux_params.h>
+
+void bl_aux_params_parse(u_register_t head,
+			 bl_aux_param_handler_t handler)
+{
+	struct bl_aux_param_header *p;
+
+	for (p = (void *)head; p; p = (void *)(uintptr_t)p->next) {
+		if (handler && handler(p))
+			continue;
+
+		switch (p->type) {
+#if COREBOOT
+		case BL_AUX_PARAM_COREBOOT_TABLE:
+			coreboot_table_setup((void *)(uintptr_t)
+				((struct bl_aux_param_uint64 *)p)->value);
+			break;
+#endif
+		default:
+			ERROR("Ignoring unknown BL aux parameter: 0x%llx",
+			      p->type);
+			break;
+		}
+	}
+}
diff --git a/lib/compiler-rt/LICENSE.TXT b/lib/compiler-rt/LICENSE.TXT
new file mode 100644
index 0000000..a17dc12
--- /dev/null
+++ b/lib/compiler-rt/LICENSE.TXT
@@ -0,0 +1,91 @@
+==============================================================================
+compiler_rt License
+==============================================================================
+
+The compiler_rt library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license.  As a user of this code you may choose
+to use it under either license.  As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+    LLVM Team
+
+    University of Illinois at Urbana-Champaign
+
+    http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimers.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimers in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the names of the LLVM Team, University of Illinois at
+      Urbana-Champaign, nor the names of its contributors may be used to
+      endorse or promote products derived from this Software without specific
+      prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+==============================================================================
+Copyrights and Licenses for Third Party Software Distributed with LLVM:
+==============================================================================
+The LLVM software contains code written by third parties.  Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
diff --git a/lib/compiler-rt/builtins b/lib/compiler-rt/builtins
new file mode 120000
index 0000000..b2f8a74
--- /dev/null
+++ b/lib/compiler-rt/builtins
@@ -0,0 +1 @@
+../../../compiler-rt/lib/builtins
\ No newline at end of file
diff --git a/lib/compiler-rt/compiler-rt.mk b/lib/compiler-rt/compiler-rt.mk
new file mode 100644
index 0000000..49e497e
--- /dev/null
+++ b/lib/compiler-rt/compiler-rt.mk
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# Neither the name of ARM nor the names of its contributors may be used
+# to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+ifeq (${ARCH},aarch32)
+COMPILER_RT_SRCS	:=	lib/compiler-rt/builtins/arm/aeabi_uldivmod.S	\
+				lib/compiler-rt/builtins/udivmoddi4.c		\
+				lib/compiler-rt/builtins/ctzdi2.c		\
+				lib/compiler-rt/builtins/lshrdi3.c
+endif
diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk
new file mode 100644
index 0000000..4201823
--- /dev/null
+++ b/lib/coreboot/coreboot.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+COREBOOT := 0
+$(eval $(call assert_boolean,COREBOOT))
+$(eval $(call add_define,COREBOOT))
+
+ifeq (${COREBOOT},1)
+
+ifneq (${ARCH},aarch64)
+$(error "coreboot only supports Trusted Firmware on AArch64.")
+endif
+
+BL31_SOURCES	+=	$(addprefix lib/coreboot/,	\
+			coreboot_table.c)
+
+BL31_SOURCES	+=	drivers/coreboot/cbmem_console/${ARCH}/cbmem_console.S
+
+endif	# COREBOOT
diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c
new file mode 100644
index 0000000..63bdc63
--- /dev/null
+++ b/lib/coreboot/coreboot_table.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <drivers/coreboot/cbmem_console.h>
+#include <common/debug.h>
+#include <lib/coreboot.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*
+ * Structures describing coreboot's in-memory descriptor tables. See
+ * <coreboot>/src/commonlib/include/commonlib/coreboot_tables.h for
+ * canonical implementation.
+ */
+
+typedef struct {
+	char signature[4];
+	uint32_t header_bytes;
+	uint32_t header_checksum;
+	uint32_t table_bytes;
+	uint32_t table_checksum;
+	uint32_t table_entries;
+} cb_header_t;
+
+typedef enum {
+	CB_TAG_SERIAL = 0xf,
+	CB_TAG_CBMEM_CONSOLE = 0x17,
+} cb_tag_t;
+
+typedef struct {
+	uint32_t tag;
+	uint32_t size;
+	union {
+		coreboot_serial_t serial;
+		uint64_t uint64;
+	};
+} cb_entry_t;
+
+coreboot_serial_t coreboot_serial;
+
+/*
+ * The coreboot table is parsed before the MMU is enabled (i.e. with strongly
+ * ordered memory), so we cannot make unaligned accesses. The table entries
+ * immediately follow one another without padding, so nothing after the header
+ * is guaranteed to be naturally aligned. Therefore, we need to define safety
+ * functions that can read unaligned integers.
+ */
+static uint32_t read_le32(uint32_t *p)
+{
+	uintptr_t addr = (uintptr_t)p;
+	return mmio_read_8(addr)		|
+	       mmio_read_8(addr + 1) << 8	|
+	       mmio_read_8(addr + 2) << 16	|
+	       mmio_read_8(addr + 3) << 24;
+}
+static uint64_t read_le64(uint64_t *p)
+{
+	return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32;
+}
+
+static void expand_and_mmap(uintptr_t baseaddr, size_t size)
+{
+	uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE);
+	size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE);
+	mmap_add_region(pageaddr, pageaddr, expanded,
+			MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER);
+}
+
+static void setup_cbmem_console(uintptr_t baseaddr)
+{
+	static console_cbmc_t console;
+	assert(!console.base);		/* should only have one CBMEM console */
+
+	/* CBMEM console structure stores its size in first header field. */
+	uint32_t size = *(uint32_t *)baseaddr;
+	expand_and_mmap(baseaddr, size);
+	console_cbmc_register(baseaddr, &console);
+	console_set_scope(&console.console, CONSOLE_FLAG_BOOT |
+					    CONSOLE_FLAG_RUNTIME |
+					    CONSOLE_FLAG_CRASH);
+}
+
+void coreboot_table_setup(void *base)
+{
+	cb_header_t *header = base;
+	void *ptr;
+	int i;
+
+	if (strncmp(header->signature, "LBIO", 4)) {
+		ERROR("coreboot table signature corrupt!\n");
+		return;
+	}
+
+	ptr = base + header->header_bytes;
+	for (i = 0; i < header->table_entries; i++) {
+		cb_entry_t *entry = ptr;
+
+		if (ptr - base >= header->header_bytes + header->table_bytes) {
+			ERROR("coreboot table exceeds its bounds!\n");
+			break;
+		}
+
+		switch (read_le32(&entry->tag)) {
+		case CB_TAG_SERIAL:
+			memcpy(&coreboot_serial, &entry->serial,
+			       sizeof(coreboot_serial));
+			break;
+		case CB_TAG_CBMEM_CONSOLE:
+			setup_cbmem_console(read_le64(&entry->uint64));
+			break;
+		default:
+			/* There are many tags TF doesn't need to care about. */
+			break;
+		}
+
+		ptr += read_le32(&entry->size);
+	}
+}
diff --git a/lib/cpus/aarch32/aem_generic.S b/lib/cpus/aarch32/aem_generic.S
new file mode 100644
index 0000000..7bd586a
--- /dev/null
+++ b/lib/cpus/aarch32/aem_generic.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <aem_generic.h>
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+
+func aem_generic_core_pwr_dwn
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+	/* ---------------------------------------------
+	 * Flush L1 cache to PoU.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	b	dcsw_op_louis
+endfunc aem_generic_core_pwr_dwn
+
+
+func aem_generic_cluster_pwr_dwn
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+	/* ---------------------------------------------
+	 * Flush L1 and L2 caches to PoC.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	b	dcsw_op_all
+endfunc aem_generic_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for AEM. Must follow AAPCS.
+ */
+func aem_generic_errata_report
+	bx	lr
+endfunc aem_generic_errata_report
+#endif
+
+/* cpu_ops for Base AEM FVP */
+declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \
+	aem_generic_core_pwr_dwn, \
+	aem_generic_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a12.S b/lib/cpus/aarch32/cortex_a12.S
new file mode 100644
index 0000000..5300fe0
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a12.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a12.h>
+#include <cpu_macros.S>
+
+	.macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+		ldcopr	r0, SCTLR
+		tst	r0, #SCTLR_C_BIT
+		ASM_ASSERT(eq)
+#endif
+	.endm
+
+func cortex_a12_disable_smp
+	ldcopr	r0, ACTLR
+	bic	r0, #CORTEX_A12_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a12_disable_smp
+
+func cortex_a12_enable_smp
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A12_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	bx	lr
+endfunc cortex_a12_enable_smp
+
+func cortex_a12_reset_func
+	b	cortex_a12_enable_smp
+endfunc cortex_a12_reset_func
+
+func cortex_a12_core_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 cache */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a12_disable_smp
+endfunc cortex_a12_core_pwr_dwn
+
+func cortex_a12_cluster_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 caches */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	bl	plat_disable_acp
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a12_disable_smp
+endfunc cortex_a12_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex-A12. Must follow AAPCS.
+ */
+func cortex_a12_errata_report
+	bx	lr
+endfunc cortex_a12_errata_report
+#endif
+
+declare_cpu_ops cortex_a12, CORTEX_A12_MIDR, \
+	cortex_a12_reset_func, \
+	cortex_a12_core_pwr_dwn, \
+	cortex_a12_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a15.S b/lib/cpus/aarch32/cortex_a15.S
new file mode 100644
index 0000000..ab136ad
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a15.S
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a15.h>
+#include <cpu_macros.S>
+
+/*
+ * Cortex-A15 support LPAE and Virtualization Extensions.
+ * Don't care if confiugration uses or not LPAE and VE.
+ * Therefore, where we don't check ARCH_IS_ARMV7_WITH_LPAE/VE
+ */
+
+	.macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+		ldcopr	r0, SCTLR
+		tst	r0, #SCTLR_C_BIT
+		ASM_ASSERT(eq)
+#endif
+	.endm
+
+func cortex_a15_disable_smp
+	ldcopr	r0, ACTLR
+	bic	r0, #CORTEX_A15_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+#if ERRATA_A15_816470
+	/*
+	 * Invalidate any TLB address
+	 */
+	mov	r0, #0
+	stcopr	r0, TLBIMVA
+#endif
+	dsb	sy
+	bx	lr
+endfunc cortex_a15_disable_smp
+
+func cortex_a15_enable_smp
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A15_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	bx	lr
+endfunc cortex_a15_enable_smp
+
+	/* ----------------------------------------------------
+	 * Errata Workaround for Cortex A15 Errata #816470.
+	 * This applies only to revision >= r3p0 of Cortex A15.
+	 * ----------------------------------------------------
+	 */
+func check_errata_816470
+	/*
+	 * Even though this is only needed for revision >= r3p0, it is always
+	 * applied because of the low cost of the workaround.
+	 */
+	mov	r0, #ERRATA_APPLIES
+	bx	lr
+endfunc check_errata_816470
+
+	/* ----------------------------------------------------
+	 * Errata Workaround for Cortex A15 Errata #827671.
+	 * This applies only to revision >= r3p0 of Cortex A15.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ----------------------------------------------------
+	 */
+func errata_a15_827671_wa
+	/*
+	 * Compare r0 against revision r3p0
+	 */
+	mov	r2, lr
+	bl	check_errata_827671
+	cmp	r0, #ERRATA_NOT_APPLIES
+	beq	1f
+	ldcopr	r0, CORTEX_A15_ACTLR2
+	orr	r0, #CORTEX_A15_ACTLR2_INV_DCC_BIT
+	stcopr	r0, CORTEX_A15_ACTLR2
+	isb
+1:
+	bx	r2
+endfunc errata_a15_827671_wa
+
+func check_errata_827671
+	mov	r1, #0x30
+	b	cpu_rev_var_hs
+endfunc check_errata_827671
+
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A15. Must follow AAPCS.
+ */
+func cortex_a15_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A15_816470, cortex_a15, 816470
+	report_errata ERRATA_A15_827671, cortex_a15, 827671
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a15, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a15_errata_report
+#endif
+
+func cortex_a15_reset_func
+	mov	r5, lr
+	bl	cpu_get_rev_var
+
+#if ERRATA_A15_827671
+	bl	errata_a15_827671_wa
+#endif
+
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A15_ACTLR_INV_BTB_BIT
+	stcopr	r0, ACTLR
+	ldr	r0, =workaround_icache_inv_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
+
+	mov	lr, r5
+	b	cortex_a15_enable_smp
+endfunc cortex_a15_reset_func
+
+func cortex_a15_core_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 cache */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a15_disable_smp
+endfunc cortex_a15_core_pwr_dwn
+
+func cortex_a15_cluster_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 caches */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	bl	plat_disable_acp
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a15_disable_smp
+endfunc cortex_a15_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a15, CORTEX_A15_MIDR, \
+	cortex_a15_reset_func, \
+	cortex_a15_core_pwr_dwn, \
+	cortex_a15_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a17.S b/lib/cpus/aarch32/cortex_a17.S
new file mode 100644
index 0000000..b8abd33
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a17.S
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a17.h>
+#include <cpu_macros.S>
+
+	.macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+		ldcopr	r0, SCTLR
+		tst	r0, #SCTLR_C_BIT
+		ASM_ASSERT(eq)
+#endif
+	.endm
+
+func cortex_a17_disable_smp
+	ldcopr	r0, ACTLR
+	bic	r0, #CORTEX_A17_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a17_disable_smp
+
+func cortex_a17_enable_smp
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A17_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	bx	lr
+endfunc cortex_a17_enable_smp
+
+	/* ----------------------------------------------------
+	 * Errata Workaround for Cortex A17 Errata #852421.
+	 * This applies only to revision <= r1p2 of Cortex A17.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ----------------------------------------------------
+	 */
+func errata_a17_852421_wa
+	/*
+	 * Compare r0 against revision r1p2
+	 */
+	mov	r2, lr
+	bl	check_errata_852421
+	cmp	r0, #ERRATA_NOT_APPLIES
+	beq	1f
+	ldcopr	r0, CORTEX_A17_IMP_DEF_REG1
+	orr	r0, r0, #(1<<24)
+	stcopr	r0, CORTEX_A17_IMP_DEF_REG1
+1:
+	bx	r2
+endfunc errata_a17_852421_wa
+
+func check_errata_852421
+	mov	r1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_852421
+
+	/* ----------------------------------------------------
+	 * Errata Workaround for Cortex A17 Errata #852423.
+	 * This applies only to revision <= r1p2 of Cortex A17.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ----------------------------------------------------
+	 */
+func errata_a17_852423_wa
+	/*
+	 * Compare r0 against revision r1p2
+	 */
+	mov	r2, lr
+	bl	check_errata_852423
+	cmp	r0, #ERRATA_NOT_APPLIES
+	beq	1f
+	ldcopr	r0, CORTEX_A17_IMP_DEF_REG1
+	orr	r0, r0, #(1<<12)
+	stcopr	r0, CORTEX_A17_IMP_DEF_REG1
+1:
+	bx	r2
+endfunc errata_a17_852423_wa
+
+func check_errata_852423
+	mov	r1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_852423
+
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A17. Must follow AAPCS.
+ */
+func cortex_a17_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A17_852421, cortex_a17, 852421
+	report_errata ERRATA_A17_852423, cortex_a17, 852423
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a17, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a17_errata_report
+#endif
+
+func cortex_a17_reset_func
+	mov	r5, lr
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+#if ERRATA_A17_852421
+	mov	r0, r4
+	bl	errata_a17_852421_wa
+#endif
+
+#if ERRATA_A17_852423
+	mov	r0, r4
+	bl	errata_a17_852423_wa
+#endif
+
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldr	r0, =workaround_bpiall_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
+
+	mov	lr, r5
+	b	cortex_a17_enable_smp
+endfunc cortex_a17_reset_func
+
+func cortex_a17_core_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 cache */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a17_disable_smp
+endfunc cortex_a17_core_pwr_dwn
+
+func cortex_a17_cluster_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 caches */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	bl	plat_disable_acp
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a17_disable_smp
+endfunc cortex_a17_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a17, CORTEX_A17_MIDR, \
+	cortex_a17_reset_func, \
+	cortex_a17_core_pwr_dwn, \
+	cortex_a17_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a32.S b/lib/cpus/aarch32/cortex_a32.S
new file mode 100644
index 0000000..c262276
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a32.S
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a32.h>
+#include <cpu_macros.S>
+
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * Clobbers: r0-r1
+	 * ---------------------------------------------
+	 */
+func cortex_a32_disable_smp
+	ldcopr16	r0, r1, CORTEX_A32_CPUECTLR_EL1
+	bic	r0, r0, #CORTEX_A32_CPUECTLR_SMPEN_BIT
+	stcopr16	r0, r1, CORTEX_A32_CPUECTLR_EL1
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a32_disable_smp
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A32.
+	 * Clobbers: r0-r1
+	 * -------------------------------------------------
+	 */
+func cortex_a32_reset_func
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	ldcopr16	r0, r1, CORTEX_A32_CPUECTLR_EL1
+	orr	r0, r0, #CORTEX_A32_CPUECTLR_SMPEN_BIT
+	stcopr16	r0, r1, CORTEX_A32_CPUECTLR_EL1
+	isb
+	bx	lr
+endfunc cortex_a32_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Cortex-A32.
+	 * Clobbers: r0-r3
+	 * ----------------------------------------------------
+	 */
+func cortex_a32_core_pwr_dwn
+	/* r12 is pushed to meet the 8 byte stack alignment requirement */
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a32_disable_smp
+endfunc cortex_a32_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Cortex-A32.
+	 * Clobbers: r0-r3
+	 * -------------------------------------------------------
+	 */
+func cortex_a32_cluster_pwr_dwn
+	/* r12 is pushed to meet the 8 byte stack alignment requirement */
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Flush L1 cache.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* ---------------------------------------------
+	 * Flush L2 cache.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a32_disable_smp
+endfunc cortex_a32_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex-A32. Must follow AAPCS.
+ */
+func cortex_a32_errata_report
+	bx	lr
+endfunc cortex_a32_errata_report
+#endif
+
+declare_cpu_ops cortex_a32, CORTEX_A32_MIDR, \
+	cortex_a32_reset_func, \
+	cortex_a32_core_pwr_dwn, \
+	cortex_a32_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a5.S b/lib/cpus/aarch32/cortex_a5.S
new file mode 100644
index 0000000..8abb66f
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a5.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a5.h>
+#include <cpu_macros.S>
+
+	.macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+		ldcopr	r0, SCTLR
+		tst	r0, #SCTLR_C_BIT
+		ASM_ASSERT(eq)
+#endif
+	.endm
+
+func cortex_a5_disable_smp
+	ldcopr	r0, ACTLR
+	bic	r0, #CORTEX_A5_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a5_disable_smp
+
+func cortex_a5_enable_smp
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A5_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	bx	lr
+endfunc cortex_a5_enable_smp
+
+func cortex_a5_reset_func
+	b	cortex_a5_enable_smp
+endfunc cortex_a5_reset_func
+
+func cortex_a5_core_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 cache */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a5_disable_smp
+endfunc cortex_a5_core_pwr_dwn
+
+func cortex_a5_cluster_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 caches */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	bl	plat_disable_acp
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a5_disable_smp
+endfunc cortex_a5_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex-A5. Must follow AAPCS.
+ */
+func cortex_a5_errata_report
+	bx	lr
+endfunc cortex_a5_errata_report
+#endif
+
+declare_cpu_ops cortex_a5, CORTEX_A5_MIDR, \
+	cortex_a5_reset_func, \
+	cortex_a5_core_pwr_dwn, \
+	cortex_a5_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a53.S b/lib/cpus/aarch32/cortex_a53.S
new file mode 100644
index 0000000..6e3ff81
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a53.S
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <cpu_macros.S>
+
+#if A53_DISABLE_NON_TEMPORAL_HINT
+#undef ERRATA_A53_836870
+#define ERRATA_A53_836870	1
+#endif
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * ---------------------------------------------
+	 */
+func cortex_a53_disable_smp
+	ldcopr16	r0, r1, CORTEX_A53_ECTLR
+	bic64_imm	r0, r1, CORTEX_A53_ECTLR_SMP_BIT
+	stcopr16	r0, r1, CORTEX_A53_ECTLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a53_disable_smp
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #819472.
+	 * This applies only to revision <= r0p1 of Cortex A53.
+	 * ---------------------------------------------------
+	 */
+func check_errata_819472
+	/*
+	 * Even though this is only needed for revision <= r0p1, it
+	 * is always applied due to limitations of the current
+	 * errata framework.
+	 */
+	mov	r0, #ERRATA_APPLIES
+	bx	lr
+endfunc check_errata_819472
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #824069.
+	 * This applies only to revision <= r0p2 of Cortex A53.
+	 * ---------------------------------------------------
+	 */
+func check_errata_824069
+	/*
+	 * Even though this is only needed for revision <= r0p2, it
+	 * is always applied due to limitations of the current
+	 * errata framework.
+	 */
+	mov	r0, #ERRATA_APPLIES
+	bx	lr
+endfunc check_errata_824069
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #826319.
+	 * This applies only to revision <= r0p2 of Cortex A53.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * --------------------------------------------------
+	 */
+func errata_a53_826319_wa
+	/*
+	 * Compare r0 against revision r0p2
+	 */
+	mov	r2, lr
+	bl	check_errata_826319
+	mov	lr, r2
+	cmp	r0, #ERRATA_NOT_APPLIES
+	beq	1f
+	ldcopr	r0, CORTEX_A53_L2ACTLR
+	bic	r0, #CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN
+	orr	r0, #CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH
+	stcopr	r0, CORTEX_A53_L2ACTLR
+1:
+	bx	lr
+endfunc errata_a53_826319_wa
+
+func check_errata_826319
+	mov	r1, #0x02
+	b	cpu_rev_var_ls
+endfunc check_errata_826319
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #827319.
+	 * This applies only to revision <= r0p2 of Cortex A53.
+	 * ---------------------------------------------------
+	 */
+func check_errata_827319
+	/*
+	 * Even though this is only needed for revision <= r0p2, it
+	 * is always applied due to limitations of the current
+	 * errata framework.
+	 */
+	mov	r0, #ERRATA_APPLIES
+	bx	lr
+endfunc check_errata_827319
+
+	/* ---------------------------------------------------------------------
+	 * Disable the cache non-temporal hint.
+	 *
+	 * This ignores the Transient allocation hint in the MAIR and treats
+	 * allocations the same as non-transient allocation types. As a result,
+	 * the LDNP and STNP instructions in AArch64 behave the same as the
+	 * equivalent LDP and STP instructions.
+	 *
+	 * This is relevant only for revisions <= r0p3 of Cortex-A53.
+	 * From r0p4 and onwards, the bit to disable the hint is enabled by
+	 * default at reset.
+	 *
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------------------------
+	 */
+func a53_disable_non_temporal_hint
+	/*
+	 * Compare r0 against revision r0p3
+	 */
+	mov		r2, lr
+	bl		check_errata_disable_non_temporal_hint
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A53_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A53_CPUACTLR_DTAH
+	stcopr16	r0, r1, CORTEX_A53_CPUACTLR
+1:
+	bx		lr
+endfunc a53_disable_non_temporal_hint
+
+func check_errata_disable_non_temporal_hint
+	mov	r1, #0x03
+	b	cpu_rev_var_ls
+endfunc check_errata_disable_non_temporal_hint
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #855873.
+	 *
+	 * This applies only to revisions >= r0p3 of Cortex A53.
+	 * Earlier revisions of the core are affected as well, but don't
+	 * have the chicken bit in the CPUACTLR register. It is expected that
+	 * the rich OS takes care of that, especially as the workaround is
+	 * shared with other erratas in those revisions of the CPU.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * --------------------------------------------------
+	 */
+func errata_a53_855873_wa
+	/*
+	 * Compare r0 against revision r0p3 and higher
+	 */
+	mov		r2, lr
+	bl		check_errata_855873
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A53_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A53_CPUACTLR_ENDCCASCI
+	stcopr16	r0, r1, CORTEX_A53_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a53_855873_wa
+
+func check_errata_855873
+	mov	r1, #0x03
+	b	cpu_rev_var_hs
+endfunc check_errata_855873
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A53.
+	 * Shall clobber: r0-r6
+	 * -------------------------------------------------
+	 */
+func cortex_a53_reset_func
+	mov	r5, lr
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+#if ERRATA_A53_826319
+	mov	r0, r4
+	bl	errata_a53_826319_wa
+#endif
+
+#if ERRATA_A53_836870
+	mov	r0, r4
+	bl	a53_disable_non_temporal_hint
+#endif
+
+#if ERRATA_A53_855873
+	mov	r0, r4
+	bl	errata_a53_855873_wa
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	ldcopr16	r0, r1, CORTEX_A53_ECTLR
+	orr64_imm	r0, r1, CORTEX_A53_ECTLR_SMP_BIT
+	stcopr16	r0, r1,	CORTEX_A53_ECTLR
+	isb
+	bx	r5
+endfunc cortex_a53_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Cortex-A53.
+	 * ----------------------------------------------------
+	 */
+func cortex_a53_core_pwr_dwn
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a53_disable_smp
+endfunc cortex_a53_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Cortex-A53.
+	 * Clobbers: r0-r3
+	 * -------------------------------------------------------
+	 */
+func cortex_a53_cluster_pwr_dwn
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* ---------------------------------------------
+	 * Flush L2 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a53_disable_smp
+endfunc cortex_a53_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A53. Must follow AAPCS.
+ */
+func cortex_a53_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A53_819472, cortex_a53, 819472
+	report_errata ERRATA_A53_824069, cortex_a53, 824069
+	report_errata ERRATA_A53_826319, cortex_a53, 826319
+	report_errata ERRATA_A53_827319, cortex_a53, 827319
+	report_errata ERRATA_A53_836870, cortex_a53, disable_non_temporal_hint
+	report_errata ERRATA_A53_855873, cortex_a53, 855873
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a53_errata_report
+#endif
+
+declare_cpu_ops cortex_a53, CORTEX_A53_MIDR, \
+	cortex_a53_reset_func, \
+	cortex_a53_core_pwr_dwn, \
+	cortex_a53_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a57.S b/lib/cpus/aarch32/cortex_a57.S
new file mode 100644
index 0000000..2e97abb
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a57.S
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/debug.h>
+#include <cortex_a57.h>
+#include <cpu_macros.S>
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * Clobbers: r0-r1
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_smp
+	ldcopr16	r0, r1, CORTEX_A57_ECTLR
+	bic64_imm	r0, r1, CORTEX_A57_ECTLR_SMP_BIT
+	stcopr16	r0, r1, CORTEX_A57_ECTLR
+	bx	lr
+endfunc cortex_a57_disable_smp
+
+	/* ---------------------------------------------
+	 * Disable all types of L2 prefetches.
+	 * Clobbers: r0-r2
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_l2_prefetch
+	ldcopr16	r0, r1, CORTEX_A57_ECTLR
+	orr64_imm	r0, r1, CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT
+	bic64_imm	r0, r1, (CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK | \
+				 CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK)
+	stcopr16	r0, r1, CORTEX_A57_ECTLR
+	isb
+	dsb	ish
+	bx	lr
+endfunc cortex_a57_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable debug interfaces
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_ext_debug
+	mov	r0, #1
+	stcopr	r0, DBGOSDLR
+	isb
+#if ERRATA_A57_817169
+	/*
+	 * Invalidate any TLB address
+	 */
+	mov	r0, #0
+	stcopr	r0, TLBIMVA
+#endif
+	dsb	sy
+	bx	lr
+endfunc cortex_a57_disable_ext_debug
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #806969.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * --------------------------------------------------
+	 */
+func errata_a57_806969_wa
+	/*
+	 * Compare r0 against revision r0p0
+	 */
+	mov		r2, lr
+	bl		check_errata_806969
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_NO_ALLOC_WBWA
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx	lr
+endfunc errata_a57_806969_wa
+
+func check_errata_806969
+	mov	r1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_806969
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #813419.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * ---------------------------------------------------
+	 */
+func check_errata_813419
+	/*
+	 * Even though this is only needed for revision r0p0, it
+	 * is always applied due to limitations of the current
+	 * errata framework.
+	 */
+	mov	r0, #ERRATA_APPLIES
+	bx	lr
+endfunc check_errata_813419
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #813420.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_813420_wa
+	/*
+	 * Compare r0 against revision r0p0
+	 */
+	mov		r2, lr
+	bl		check_errata_813420
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_DCC_AS_DCCI
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_813420_wa
+
+func check_errata_813420
+	mov	r1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_813420
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #814670.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_814670_wa
+	/*
+	 * Compare r0 against revision r0p0
+	 */
+	mov		r2, lr
+	bl		check_errata_814670
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_DIS_DMB_NULLIFICATION
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	isb
+1:
+	bx		r2
+endfunc errata_a57_814670_wa
+
+func check_errata_814670
+	mov	r1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_814670
+
+	/* ----------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #817169.
+	 * This applies only to revision <= r0p1 of Cortex A57.
+	 * ----------------------------------------------------
+	 */
+func check_errata_817169
+	/*
+	 * Even though this is only needed for revision <= r0p1, it
+	 * is always applied because of the low cost of the workaround.
+	 */
+	mov	r0, #ERRATA_APPLIES
+	bx	lr
+endfunc check_errata_817169
+
+	/* --------------------------------------------------------------------
+	 * Disable the over-read from the LDNP instruction.
+	 *
+	 * This applies to all revisions <= r1p2. The performance degradation
+	 * observed with LDNP/STNP has been fixed on r1p3 and onwards.
+	 *
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------------------------
+	 */
+func a57_disable_ldnp_overread
+	/*
+	 * Compare r0 against revision r1p2
+	 */
+	mov		r2, lr
+	bl		check_errata_disable_ldnp_overread
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_DIS_OVERREAD
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc a57_disable_ldnp_overread
+
+func check_errata_disable_ldnp_overread
+	mov	r1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_disable_ldnp_overread
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #826974.
+	 * This applies only to revision <= r1p1 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_826974_wa
+	/*
+	 * Compare r0 against revision r1p1
+	 */
+	mov		r2, lr
+	bl		check_errata_826974
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_DMB
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_826974_wa
+
+func check_errata_826974
+	mov	r1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_826974
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #826977.
+	 * This applies only to revision <= r1p1 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_826977_wa
+	/*
+	 * Compare r0 against revision r1p1
+	 */
+	mov		r2, lr
+	bl		check_errata_826977
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_GRE_NGRE_AS_NGNRE
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_826977_wa
+
+func check_errata_826977
+	mov	r1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_826977
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #828024.
+	 * This applies only to revision <= r1p1 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_828024_wa
+	/*
+	 * Compare r0 against revision r1p1
+	 */
+	mov		r2, lr
+	bl		check_errata_828024
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	/*
+	 * Setting the relevant bits in CORTEX_A57_CPUACTLR has to be done in 2
+	 * instructions here because the resulting bitmask doesn't fit in a
+	 * 16-bit value so it cannot be encoded in a single instruction.
+	 */
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_NO_ALLOC_WBWA
+	orr64_imm	r0, r1, (CORTEX_A57_CPUACTLR_DIS_L1_STREAMING | CORTEX_A57_CPUACTLR_DIS_STREAMING)
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_828024_wa
+
+func check_errata_828024
+	mov	r1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_828024
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #829520.
+	 * This applies only to revision <= r1p2 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_829520_wa
+	/*
+	 * Compare r0 against revision r1p2
+	 */
+	mov		r2, lr
+	bl		check_errata_829520
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_DIS_INDIRECT_PREDICTOR
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_829520_wa
+
+func check_errata_829520
+	mov	r1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_829520
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #833471.
+	 * This applies only to revision <= r1p2 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_833471_wa
+	/*
+	 * Compare r0 against revision r1p2
+	 */
+	mov		r2, lr
+	bl		check_errata_833471
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r1, r1, CORTEX_A57_CPUACTLR_FORCE_FPSCR_FLUSH
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_833471_wa
+
+func check_errata_833471
+	mov	r1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_833471
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #859972.
+	 * This applies only to revision <= r1p3 of Cortex A57.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a57_859972_wa
+	mov		r2, lr
+	bl		check_errata_859972
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r1, r1, CORTEX_A57_CPUACTLR_DIS_INSTR_PREFETCH
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+1:
+	bx		lr
+endfunc errata_a57_859972_wa
+
+func check_errata_859972
+	mov	r1, #0x13
+	b	cpu_rev_var_ls
+endfunc check_errata_859972
+
+func check_errata_cve_2017_5715
+	mov	r0, #ERRATA_MISSING
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2018_3639
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A57.
+	 * Shall clobber: r0-r6
+	 * -------------------------------------------------
+	 */
+func cortex_a57_reset_func
+	mov	r5, lr
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+#if ERRATA_A57_806969
+	mov	r0, r4
+	bl	errata_a57_806969_wa
+#endif
+
+#if ERRATA_A57_813420
+	mov	r0, r4
+	bl	errata_a57_813420_wa
+#endif
+
+#if ERRATA_A57_814670
+	mov	r0, r4
+	bl	errata_a57_814670_wa
+#endif
+
+#if A57_DISABLE_NON_TEMPORAL_HINT
+	mov	r0, r4
+	bl	a57_disable_ldnp_overread
+#endif
+
+#if ERRATA_A57_826974
+	mov	r0, r4
+	bl	errata_a57_826974_wa
+#endif
+
+#if ERRATA_A57_826977
+	mov	r0, r4
+	bl	errata_a57_826977_wa
+#endif
+
+#if ERRATA_A57_828024
+	mov	r0, r4
+	bl	errata_a57_828024_wa
+#endif
+
+#if ERRATA_A57_829520
+	mov	r0, r4
+	bl	errata_a57_829520_wa
+#endif
+
+#if ERRATA_A57_833471
+	mov	r0, r4
+	bl	errata_a57_833471_wa
+#endif
+
+#if ERRATA_A57_859972
+	mov	r0, r4
+	bl	errata_a57_859972_wa
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	ldcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_STORE
+	stcopr16	r0, r1, CORTEX_A57_CPUACTLR
+	isb
+	dsb	sy
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	ldcopr16	r0, r1, CORTEX_A57_ECTLR
+	orr64_imm	r0, r1, CORTEX_A57_ECTLR_SMP_BIT
+	stcopr16	r0, r1,	CORTEX_A57_ECTLR
+	isb
+	bx	r5
+endfunc cortex_a57_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Cortex-A57.
+	 * ----------------------------------------------------
+	 */
+func cortex_a57_core_pwr_dwn
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a57_disable_ext_debug
+endfunc cortex_a57_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Cortex-A57.
+	 * Clobbers: r0-r3
+	 * -------------------------------------------------------
+	 */
+func cortex_a57_cluster_pwr_dwn
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* ---------------------------------------------
+	 * Flush L2 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a57_disable_ext_debug
+endfunc cortex_a57_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A57. Must follow AAPCS.
+ */
+func cortex_a57_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A57_806969, cortex_a57, 806969
+	report_errata ERRATA_A57_813419, cortex_a57, 813419
+	report_errata ERRATA_A57_813420, cortex_a57, 813420
+	report_errata ERRATA_A57_814670, cortex_a57, 814670
+	report_errata ERRATA_A57_817169, cortex_a57, 817169
+	report_errata A57_DISABLE_NON_TEMPORAL_HINT, cortex_a57, \
+		disable_ldnp_overread
+	report_errata ERRATA_A57_826974, cortex_a57, 826974
+	report_errata ERRATA_A57_826977, cortex_a57, 826977
+	report_errata ERRATA_A57_828024, cortex_a57, 828024
+	report_errata ERRATA_A57_829520, cortex_a57, 829520
+	report_errata ERRATA_A57_833471, cortex_a57, 833471
+	report_errata ERRATA_A57_859972, cortex_a57, 859972
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a57, cve_2018_3639
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a57_errata_report
+#endif
+
+declare_cpu_ops cortex_a57, CORTEX_A57_MIDR, \
+	cortex_a57_reset_func, \
+	cortex_a57_core_pwr_dwn, \
+	cortex_a57_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a7.S b/lib/cpus/aarch32/cortex_a7.S
new file mode 100644
index 0000000..4d4bb77
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a7.S
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a7.h>
+#include <cpu_macros.S>
+
+	.macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+		ldcopr	r0, SCTLR
+		tst	r0, #SCTLR_C_BIT
+		ASM_ASSERT(eq)
+#endif
+	.endm
+
+func cortex_a7_disable_smp
+	ldcopr	r0, ACTLR
+	bic	r0, #CORTEX_A7_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a7_disable_smp
+
+func cortex_a7_enable_smp
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A7_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	bx	lr
+endfunc cortex_a7_enable_smp
+
+func cortex_a7_reset_func
+	b	cortex_a7_enable_smp
+endfunc cortex_a7_reset_func
+
+func cortex_a7_core_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 cache */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a7_disable_smp
+endfunc cortex_a7_core_pwr_dwn
+
+func cortex_a7_cluster_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 caches */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	bl	plat_disable_acp
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a7_disable_smp
+endfunc cortex_a7_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex-A7. Must follow AAPCS.
+ */
+func cortex_a7_errata_report
+	bx	lr
+endfunc cortex_a7_errata_report
+#endif
+
+declare_cpu_ops cortex_a7, CORTEX_A7_MIDR, \
+	cortex_a7_reset_func, \
+	cortex_a7_core_pwr_dwn, \
+	cortex_a7_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a72.S b/lib/cpus/aarch32/cortex_a72.S
new file mode 100644
index 0000000..ff2b0e6
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a72.S
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/debug.h>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+
+	/* ---------------------------------------------
+	 * Disable all types of L2 prefetches.
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_l2_prefetch
+	ldcopr16	r0, r1, CORTEX_A72_ECTLR
+	orr64_imm	r0, r1, CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT
+	bic64_imm	r0, r1, (CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK | \
+				CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK)
+	stcopr16	r0, r1, CORTEX_A72_ECTLR
+	isb
+	bx	lr
+endfunc cortex_a72_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable the load-store hardware prefetcher.
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_hw_prefetcher
+	ldcopr16	r0, r1, CORTEX_A72_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A72_CPUACTLR_DISABLE_L1_DCACHE_HW_PFTCH
+	stcopr16	r0, r1, CORTEX_A72_CPUACTLR
+	isb
+	dsb	ish
+	bx	lr
+endfunc cortex_a72_disable_hw_prefetcher
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * Clobbers: r0-r1
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_smp
+	ldcopr16	r0, r1, CORTEX_A72_ECTLR
+	bic64_imm	r0, r1, CORTEX_A72_ECTLR_SMP_BIT
+	stcopr16	r0, r1, CORTEX_A72_ECTLR
+	bx	lr
+endfunc cortex_a72_disable_smp
+
+	/* ---------------------------------------------
+	 * Disable debug interfaces
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_ext_debug
+	mov	r0, #1
+	stcopr	r0, DBGOSDLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a72_disable_ext_debug
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A72 Errata #859971.
+	 * This applies only to revision <= r0p3 of Cortex A72.
+	 * Inputs:
+	 * r0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: r0-r3
+	 * ---------------------------------------------------
+	 */
+func errata_a72_859971_wa
+	mov		r2,lr
+	bl		check_errata_859971
+	mov		lr, r2
+	cmp		r0, #ERRATA_NOT_APPLIES
+	beq		1f
+	ldcopr16	r0, r1, CORTEX_A72_CPUACTLR
+	orr64_imm	r1, r1, CORTEX_A72_CPUACTLR_DIS_INSTR_PREFETCH
+	stcopr16	r0, r1, CORTEX_A72_CPUACTLR
+1:
+	bx   		lr
+endfunc errata_a72_859971_wa
+
+func check_errata_859971
+	mov		r1, #0x03
+	b		cpu_rev_var_ls
+endfunc check_errata_859971
+
+func check_errata_cve_2017_5715
+	mov	r0, #ERRATA_MISSING
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2018_3639
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A72.
+	 * -------------------------------------------------
+	 */
+func cortex_a72_reset_func
+	mov	r5, lr
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+#if ERRATA_A72_859971
+	mov	r0, r4
+	bl	errata_a72_859971_wa
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	ldcopr16	r0, r1, CORTEX_A72_CPUACTLR
+	orr64_imm	r0, r1, CORTEX_A72_CPUACTLR_DIS_LOAD_PASS_STORE
+	stcopr16	r0, r1, CORTEX_A72_CPUACTLR
+	isb
+	dsb	sy
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	ldcopr16	r0, r1, CORTEX_A72_ECTLR
+	orr64_imm	r0, r1, CORTEX_A72_ECTLR_SMP_BIT
+	stcopr16	r0, r1,	CORTEX_A72_ECTLR
+	isb
+	bx	r5
+endfunc cortex_a72_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Cortex-A72.
+	 * ----------------------------------------------------
+	 */
+func cortex_a72_core_pwr_dwn
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable the load-store hardware prefetcher.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_hw_prefetcher
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a72_disable_ext_debug
+endfunc cortex_a72_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Cortex-A72.
+	 * -------------------------------------------------------
+	 */
+func cortex_a72_cluster_pwr_dwn
+	push	{r12, lr}
+
+	/* Assert if cache is enabled */
+#if ENABLE_ASSERTIONS
+	ldcopr	r0, SCTLR
+	tst	r0, #SCTLR_C_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable the load-store hardware prefetcher.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_hw_prefetcher
+
+#if !SKIP_A72_L1_FLUSH_PWR_DWN
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+#endif
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* -------------------------------------------------
+	 * Flush the L2 caches.
+	 * -------------------------------------------------
+	 */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	pop	{r12, lr}
+	b	cortex_a72_disable_ext_debug
+endfunc cortex_a72_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A72. Must follow AAPCS.
+ */
+func cortex_a72_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A72_859971, cortex_a72, 859971
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a72, cve_2018_3639
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a72_errata_report
+#endif
+
+declare_cpu_ops cortex_a72, CORTEX_A72_MIDR, \
+	cortex_a72_reset_func, \
+	cortex_a72_core_pwr_dwn, \
+	cortex_a72_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cortex_a9.S b/lib/cpus/aarch32/cortex_a9.S
new file mode 100644
index 0000000..7200343
--- /dev/null
+++ b/lib/cpus/aarch32/cortex_a9.S
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a9.h>
+#include <cpu_macros.S>
+
+	.macro assert_cache_enabled
+#if ENABLE_ASSERTIONS
+		ldcopr	r0, SCTLR
+		tst	r0, #SCTLR_C_BIT
+		ASM_ASSERT(eq)
+#endif
+	.endm
+
+func cortex_a9_disable_smp
+	ldcopr	r0, ACTLR
+	bic	r0, #CORTEX_A9_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	dsb	sy
+	bx	lr
+endfunc cortex_a9_disable_smp
+
+func cortex_a9_enable_smp
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A9_ACTLR_SMP_BIT
+	stcopr	r0, ACTLR
+	isb
+	bx	lr
+endfunc cortex_a9_enable_smp
+
+func check_errata_a9_794073
+#if ERRATA_A9_794073
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A9. Must follow AAPCS.
+ */
+func cortex_a9_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a9, cve_2017_5715
+	report_errata ERRATA_A9_794073, cortex_a9, a9_79407
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a9_errata_report
+#endif
+
+func cortex_a9_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldr	r0, =workaround_bpiall_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
+	b	cortex_a9_enable_smp
+endfunc cortex_a9_reset_func
+
+func cortex_a9_core_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 cache */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a9_disable_smp
+endfunc cortex_a9_core_pwr_dwn
+
+func cortex_a9_cluster_pwr_dwn
+	push	{r12, lr}
+
+	assert_cache_enabled
+
+	/* Flush L1 caches */
+	mov	r0, #DC_OP_CISW
+	bl	dcsw_op_level1
+
+	bl	plat_disable_acp
+
+	/* Exit cluster coherency */
+	pop	{r12, lr}
+	b	cortex_a9_disable_smp
+endfunc cortex_a9_cluster_pwr_dwn
+
+declare_cpu_ops cortex_a9, CORTEX_A9_MIDR, \
+	cortex_a9_reset_func, \
+	cortex_a9_core_pwr_dwn, \
+	cortex_a9_cluster_pwr_dwn
diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S
new file mode 100644
index 0000000..9b5d787
--- /dev/null
+++ b/lib/cpus/aarch32/cpu_helpers.S
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+#if defined(IMAGE_BL1) || defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3)
+	/*
+	 * The reset handler common to all platforms.  After a matching
+	 * cpu_ops structure entry is found, the correponding reset_handler
+	 * in the cpu_ops is invoked. The reset handler is invoked very early
+	 * in the boot sequence and it is assumed that we can clobber r0 - r10
+	 * without the need to follow AAPCS.
+	 * Clobbers: r0 - r10
+	 */
+	.globl	reset_handler
+func reset_handler
+	mov	r8, lr
+
+	/* The plat_reset_handler can clobber r0 - r7 */
+	bl	plat_reset_handler
+
+	/* Get the matching cpu_ops pointer (clobbers: r0 - r5) */
+	bl	get_cpu_ops_ptr
+
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif
+
+	/* Get the cpu_ops reset handler */
+	ldr	r1, [r0, #CPU_RESET_FUNC]
+	cmp	r1, #0
+	mov	lr, r8
+	bxne	r1
+	bx	lr
+endfunc reset_handler
+
+#endif
+
+#ifdef IMAGE_BL32 /* The power down core and cluster is needed only in  BL32 */
+	/*
+	 * void prepare_cpu_pwr_dwn(unsigned int power_level)
+	 *
+	 * Prepare CPU power down function for all platforms. The function takes
+	 * a domain level to be powered down as its parameter. After the cpu_ops
+	 * pointer is retrieved from cpu_data, the handler for requested power
+	 * level is called.
+	 */
+	.globl	prepare_cpu_pwr_dwn
+func prepare_cpu_pwr_dwn
+	/*
+	 * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the
+	 * power down handler for the last power level
+	 */
+	mov	r2, #(CPU_MAX_PWR_DWN_OPS - 1)
+	cmp	r0, r2
+	movhi	r0, r2
+
+	push	{r0, lr}
+	bl	_cpu_data
+	pop	{r2, lr}
+
+	ldr	r0, [r0, #CPU_DATA_CPU_OPS_PTR]
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif
+
+	/* Get the appropriate power down handler */
+	mov	r1, #CPU_PWR_DWN_OPS
+	add	r1, r1, r2, lsl #2
+	ldr	r1, [r0, r1]
+	bx	r1
+endfunc prepare_cpu_pwr_dwn
+
+	/*
+	 * Initializes the cpu_ops_ptr if not already initialized
+	 * in cpu_data. This must only be called after the data cache
+	 * is enabled. AAPCS is followed.
+	 */
+	.globl	init_cpu_ops
+func init_cpu_ops
+	push	{r4 - r6, lr}
+	bl	_cpu_data
+	mov	r6, r0
+	ldr	r1, [r0, #CPU_DATA_CPU_OPS_PTR]
+	cmp	r1, #0
+	bne	1f
+	bl	get_cpu_ops_ptr
+#if ENABLE_ASSERTIONS
+	cmp	r0, #0
+	ASM_ASSERT(ne)
+#endif
+	str	r0, [r6, #CPU_DATA_CPU_OPS_PTR]!
+1:
+	pop	{r4 - r6, pc}
+endfunc init_cpu_ops
+
+#endif /* IMAGE_BL32 */
+
+	/*
+	 * The below function returns the cpu_ops structure matching the
+	 * midr of the core. It reads the MIDR and finds the matching
+	 * entry in cpu_ops entries. Only the implementation and part number
+	 * are used to match the entries.
+	 * Return :
+	 *     r0 - The matching cpu_ops pointer on Success
+	 *     r0 - 0 on failure.
+	 * Clobbers: r0 - r5
+	 */
+	.globl	get_cpu_ops_ptr
+func get_cpu_ops_ptr
+	/* Get the cpu_ops start and end locations */
+	ldr	r4, =(__CPU_OPS_START__ + CPU_MIDR)
+	ldr	r5, =(__CPU_OPS_END__ + CPU_MIDR)
+
+	/* Initialize the return parameter */
+	mov	r0, #0
+
+	/* Read the MIDR_EL1 */
+	ldcopr	r2, MIDR
+	ldr	r3, =CPU_IMPL_PN_MASK
+
+	/* Retain only the implementation and part number using mask */
+	and	r2, r2, r3
+1:
+	/* Check if we have reached end of list */
+	cmp	r4, r5
+	bhs	error_exit
+
+	/* load the midr from the cpu_ops */
+	ldr	r1, [r4], #CPU_OPS_SIZE
+	and	r1, r1, r3
+
+	/* Check if midr matches to midr of this core */
+	cmp	r1, r2
+	bne	1b
+
+	/* Subtract the increment and offset to get the cpu-ops pointer */
+	sub	r0, r4, #(CPU_OPS_SIZE + CPU_MIDR)
+error_exit:
+	bx	lr
+endfunc get_cpu_ops_ptr
+
+/*
+ * Extract CPU revision and variant, and combine them into a single numeric for
+ * easier comparison.
+ */
+	.globl	cpu_get_rev_var
+func cpu_get_rev_var
+	ldcopr	r1, MIDR
+
+	/*
+	 * Extract the variant[23:20] and revision[3:0] from r1 and pack it in
+	 * r0[0:7] as variant[7:4] and revision[3:0]:
+	 *
+	 * First extract r1[23:16] to r0[7:0] and zero fill the rest. Then
+	 * extract r1[3:0] into r0[3:0] retaining other bits.
+	 */
+	ubfx	r0, r1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
+	bfi	r0, r1, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+	bx	lr
+endfunc cpu_get_rev_var
+
+/*
+ * Compare the CPU's revision-variant (r0) with a given value (r1), for errata
+ * application purposes. If the revision-variant is less than or same as a given
+ * value, indicates that errata applies; otherwise not.
+ */
+	.globl	cpu_rev_var_ls
+func cpu_rev_var_ls
+	cmp	r0, r1
+	movls	r0, #ERRATA_APPLIES
+	movhi	r0, #ERRATA_NOT_APPLIES
+	bx	lr
+endfunc cpu_rev_var_ls
+
+/*
+ * Compare the CPU's revision-variant (r0) with a given value (r1), for errata
+ * application purposes. If the revision-variant is higher than or same as a
+ * given value, indicates that errata applies; otherwise not.
+ */
+	.globl	cpu_rev_var_hs
+func cpu_rev_var_hs
+	cmp	r0, r1
+	movge	r0, #ERRATA_APPLIES
+	movlt	r0, #ERRATA_NOT_APPLIES
+	bx	lr
+endfunc cpu_rev_var_hs
+
+#if REPORT_ERRATA
+/*
+ * void print_errata_status(void);
+ *
+ * Function to print errata status for CPUs of its class. Must be called only:
+ *
+ *   - with MMU and data caches are enabled;
+ *   - after cpu_ops have been initialized in per-CPU data.
+ */
+	.globl print_errata_status
+func print_errata_status
+	/* r12 is pushed only for the sake of 8-byte stack alignment */
+	push	{r4, r5, r12, lr}
+#ifdef IMAGE_BL1
+	/*
+	 * BL1 doesn't have per-CPU data. So retrieve the CPU operations
+	 * directly.
+	 */
+	bl	get_cpu_ops_ptr
+	ldr	r0, [r0, #CPU_ERRATA_FUNC]
+	cmp	r0, #0
+	blxne	r0
+#else
+	/*
+	 * Retrieve pointer to cpu_ops, and further, the errata printing
+	 * function. If it's non-NULL, jump to the function in turn.
+	 */
+	bl	_cpu_data
+	ldr	r1, [r0, #CPU_DATA_CPU_OPS_PTR]
+	ldr	r0, [r1, #CPU_ERRATA_FUNC]
+	cmp	r0, #0
+	beq	1f
+
+	mov	r4, r0
+
+	/*
+	 * Load pointers to errata lock and printed flag. Call
+	 * errata_needs_reporting to check whether this CPU needs to report
+	 * errata status pertaining to its class.
+	 */
+	ldr	r0, [r1, #CPU_ERRATA_LOCK]
+	ldr	r1, [r1, #CPU_ERRATA_PRINTED]
+	bl	errata_needs_reporting
+	cmp	r0, #0
+	blxne	r4
+1:
+#endif
+	pop	{r4, r5, r12, pc}
+endfunc print_errata_status
+#endif
diff --git a/lib/cpus/aarch64/aem_generic.S b/lib/cpus/aarch64/aem_generic.S
new file mode 100644
index 0000000..51b5ce9
--- /dev/null
+++ b/lib/cpus/aarch64/aem_generic.S
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <aem_generic.h>
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+
+func aem_generic_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Disable the Data Cache.
+	 * ---------------------------------------------
+	 */
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+
+	mov	x0, #DCCISW
+
+	/* ---------------------------------------------
+	 * Flush L1 cache to PoU.
+	 * ---------------------------------------------
+	 */
+	b	dcsw_op_louis
+endfunc aem_generic_core_pwr_dwn
+
+
+func aem_generic_cluster_pwr_dwn
+	/* ---------------------------------------------
+	 * Disable the Data Cache.
+	 * ---------------------------------------------
+	 */
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+
+	/* ---------------------------------------------
+	 * Flush L1 and L2 caches to PoC.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	b	dcsw_op_all
+endfunc aem_generic_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for AEM. Must follow AAPCS.
+ */
+func aem_generic_errata_report
+	ret
+endfunc aem_generic_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cpu specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.aem_generic_regs, "aS"
+aem_generic_regs:  /* The ascii list of register names to be reported */
+	.asciz	"" /* no registers to report */
+
+func aem_generic_cpu_reg_dump
+	adr	x6, aem_generic_regs
+	ret
+endfunc aem_generic_cpu_reg_dump
+
+
+/* cpu_ops for Base AEM FVP */
+declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \
+	aem_generic_core_pwr_dwn, \
+	aem_generic_cluster_pwr_dwn
+
+/* cpu_ops for Foundation FVP */
+declare_cpu_ops aem_generic, FOUNDATION_AEM_MIDR, CPU_NO_RESET_FUNC, \
+	aem_generic_core_pwr_dwn, \
+	aem_generic_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a35.S b/lib/cpus/aarch64/cortex_a35.S
new file mode 100644
index 0000000..be3c652
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a35.S
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a35.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+	/* ---------------------------------------------
+	 * Disable L1 data cache and unified L2 cache
+	 * ---------------------------------------------
+	 */
+func cortex_a35_disable_dcache
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+	ret
+endfunc cortex_a35_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * ---------------------------------------------
+	 */
+func cortex_a35_disable_smp
+	mrs	x0, CORTEX_A35_CPUECTLR_EL1
+	bic	x0, x0, #CORTEX_A35_CPUECTLR_SMPEN_BIT
+	msr	CORTEX_A35_CPUECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc cortex_a35_disable_smp
+
+	 /* ---------------------------------------------------
+	 * Errata Workaround for Cortex A35 Errata #855472.
+	 * This applies to revisions r0p0 of Cortex A35.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a35_855472_wa
+	 /*
+	  * Compare x0 against revision r0p0
+	  */
+	 mov	x17, x30
+	 bl	check_errata_855472
+	 cbz	x0, 1f
+	 mrs	x1, CORTEX_A35_CPUACTLR_EL1
+	 orr	x1, x1, #CORTEX_A35_CPUACTLR_EL1_ENDCCASCI
+	 msr	CORTEX_A35_CPUACTLR_EL1, x1
+	 isb
+1:
+	ret	x17
+endfunc errata_a35_855472_wa
+
+func check_errata_855472
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_855472
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A35.
+	 * Clobbers: x0
+	 * -------------------------------------------------
+	 */
+func cortex_a35_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+
+#if ERRATA_A35_855472
+	bl	errata_a35_855472_wa
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A35_CPUECTLR_EL1
+	orr	x0, x0, #CORTEX_A35_CPUECTLR_SMPEN_BIT
+	msr	CORTEX_A35_CPUECTLR_EL1, x0
+	isb
+	ret	x19
+endfunc cortex_a35_reset_func
+
+func cortex_a35_core_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a35_disable_dcache
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a35_disable_smp
+endfunc cortex_a35_core_pwr_dwn
+
+func cortex_a35_cluster_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a35_disable_dcache
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* ---------------------------------------------
+	 * Flush L2 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a35_disable_smp
+endfunc cortex_a35_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A35. Must follow AAPCS.
+ */
+func cortex_a35_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A35_855472, cortex_a35, 855472
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a35_errata_report
+#endif
+
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a35 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a35_regs, "aS"
+cortex_a35_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a35_cpu_reg_dump
+	adr	x6, cortex_a35_regs
+	mrs	x8, CORTEX_A35_CPUECTLR_EL1
+	ret
+endfunc cortex_a35_cpu_reg_dump
+
+declare_cpu_ops cortex_a35, CORTEX_A35_MIDR, \
+	cortex_a35_reset_func, \
+	cortex_a35_core_pwr_dwn, \
+	cortex_a35_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
new file mode 100644
index 0000000..b105de2
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <cpu_macros.S>
+#include <lib/cpus/errata_report.h>
+#include <plat_macros.S>
+
+#if A53_DISABLE_NON_TEMPORAL_HINT
+#undef ERRATA_A53_836870
+#define ERRATA_A53_836870	1
+#endif
+
+	/* ---------------------------------------------
+	 * Disable L1 data cache and unified L2 cache
+	 * ---------------------------------------------
+	 */
+func cortex_a53_disable_dcache
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+	ret
+endfunc cortex_a53_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * ---------------------------------------------
+	 */
+func cortex_a53_disable_smp
+	mrs	x0, CORTEX_A53_ECTLR_EL1
+	bic	x0, x0, #CORTEX_A53_ECTLR_SMP_BIT
+	msr	CORTEX_A53_ECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc cortex_a53_disable_smp
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #819472.
+	 * This applies only to revision <= r0p1 of Cortex A53.
+	 * Due to the nature of the errata it is applied unconditionally
+	 * when built in, report it as applicable in this case
+	 * ---------------------------------------------------
+	 */
+func check_errata_819472
+#if ERRATA_A53_819472
+	mov x0, #ERRATA_APPLIES
+	ret
+#else
+	mov	x1, #0x01
+	b	cpu_rev_var_ls
+#endif
+endfunc check_errata_819472
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #824069.
+	 * This applies only to revision <= r0p2 of Cortex A53.
+	 * Due to the nature of the errata it is applied unconditionally
+	 * when built in, report it as applicable in this case
+	 * ---------------------------------------------------
+	 */
+func check_errata_824069
+#if ERRATA_A53_824069
+	mov x0, #ERRATA_APPLIES
+	ret
+#else
+	mov	x1, #0x02
+	b	cpu_rev_var_ls
+#endif
+endfunc check_errata_824069
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #826319.
+	 * This applies only to revision <= r0p2 of Cortex A53.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a53_826319_wa
+	/*
+	 * Compare x0 against revision r0p2
+	 */
+	mov	x17, x30
+	bl	check_errata_826319
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A53_L2ACTLR_EL1
+	bic	x1, x1, #CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN
+	orr	x1, x1, #CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH
+	msr	CORTEX_A53_L2ACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a53_826319_wa
+
+func check_errata_826319
+	mov	x1, #0x02
+	b	cpu_rev_var_ls
+endfunc check_errata_826319
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #827319.
+	 * This applies only to revision <= r0p2 of Cortex A53.
+	 * Due to the nature of the errata it is applied unconditionally
+	 * when built in, report it as applicable in this case
+	 * ---------------------------------------------------
+	 */
+func check_errata_827319
+#if ERRATA_A53_827319
+	mov x0, #ERRATA_APPLIES
+	ret
+#else
+	mov	x1, #0x02
+	b	cpu_rev_var_ls
+#endif
+endfunc check_errata_827319
+
+	/* ---------------------------------------------------------------------
+	 * Disable the cache non-temporal hint.
+	 *
+	 * This ignores the Transient allocation hint in the MAIR and treats
+	 * allocations the same as non-transient allocation types. As a result,
+	 * the LDNP and STNP instructions in AArch64 behave the same as the
+	 * equivalent LDP and STP instructions.
+	 *
+	 * This is relevant only for revisions <= r0p3 of Cortex-A53.
+	 * From r0p4 and onwards, the bit to disable the hint is enabled by
+	 * default at reset.
+	 *
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------------------------
+	 */
+func a53_disable_non_temporal_hint
+	/*
+	 * Compare x0 against revision r0p3
+	 */
+	mov	x17, x30
+	bl	check_errata_disable_non_temporal_hint
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A53_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A53_CPUACTLR_EL1_DTAH
+	msr	CORTEX_A53_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc a53_disable_non_temporal_hint
+
+func check_errata_disable_non_temporal_hint
+	mov	x1, #0x03
+	b	cpu_rev_var_ls
+endfunc check_errata_disable_non_temporal_hint
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A53 Errata #855873.
+	 *
+	 * This applies only to revisions >= r0p3 of Cortex A53.
+	 * Earlier revisions of the core are affected as well, but don't
+	 * have the chicken bit in the CPUACTLR register. It is expected that
+	 * the rich OS takes care of that, especially as the workaround is
+	 * shared with other erratas in those revisions of the CPU.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a53_855873_wa
+	/*
+	 * Compare x0 against revision r0p3 and higher
+	 */
+        mov     x17, x30
+        bl      check_errata_855873
+        cbz     x0, 1f
+
+	mrs	x1, CORTEX_A53_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A53_CPUACTLR_EL1_ENDCCASCI
+	msr	CORTEX_A53_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a53_855873_wa
+
+func check_errata_855873
+	mov	x1, #0x03
+	b	cpu_rev_var_hs
+endfunc check_errata_855873
+
+/*
+ * Errata workaround for Cortex A53 Errata #835769.
+ * This applies to revisions <= r0p4 of Cortex A53.
+ * This workaround is statically enabled at build time.
+ */
+func check_errata_835769
+	cmp	x0, #0x04
+	b.hi	errata_not_applies
+	/*
+	 * Fix potentially available for revisions r0p2, r0p3 and r0p4.
+	 * If r0p2, r0p3 or r0p4; check for fix in REVIDR, else exit.
+	 */
+	cmp	x0, #0x01
+	mov	x0, #ERRATA_APPLIES
+	b.ls	exit_check_errata_835769
+	/* Load REVIDR. */
+	mrs	x1, revidr_el1
+	/* If REVIDR[7] is set (fix exists) set ERRATA_NOT_APPLIES, else exit. */
+	tbz	x1, #7, exit_check_errata_835769
+errata_not_applies:
+	mov	x0, #ERRATA_NOT_APPLIES
+exit_check_errata_835769:
+	ret
+endfunc check_errata_835769
+
+/*
+ * Errata workaround for Cortex A53 Errata #843419.
+ * This applies to revisions <= r0p4 of Cortex A53.
+ * This workaround is statically enabled at build time.
+ */
+func check_errata_843419
+	mov	x1, #ERRATA_APPLIES
+	mov	x2, #ERRATA_NOT_APPLIES
+	cmp	x0, #0x04
+	csel	x0, x1, x2, ls
+	/*
+	 * Fix potentially available for revision r0p4.
+	 * If r0p4 check for fix in REVIDR, else exit.
+	 */
+	b.ne	exit_check_errata_843419
+	/* Load REVIDR. */
+	mrs	x3, revidr_el1
+	/* If REVIDR[8] is set (fix exists) set ERRATA_NOT_APPLIES, else exit. */
+	tbz	x3, #8, exit_check_errata_843419
+	mov	x0, x2
+exit_check_errata_843419:
+	ret
+endfunc check_errata_843419
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A53.
+	 * Shall clobber: x0-x19
+	 * -------------------------------------------------
+	 */
+func cortex_a53_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+
+#if ERRATA_A53_826319
+	mov	x0, x18
+	bl	errata_a53_826319_wa
+#endif
+
+#if ERRATA_A53_836870
+	mov	x0, x18
+	bl	a53_disable_non_temporal_hint
+#endif
+
+#if ERRATA_A53_855873
+	mov	x0, x18
+	bl	errata_a53_855873_wa
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A53_ECTLR_EL1
+	orr	x0, x0, #CORTEX_A53_ECTLR_SMP_BIT
+	msr	CORTEX_A53_ECTLR_EL1, x0
+	isb
+	ret	x19
+endfunc cortex_a53_reset_func
+
+func cortex_a53_core_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a53_disable_dcache
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a53_disable_smp
+endfunc cortex_a53_core_pwr_dwn
+
+func cortex_a53_cluster_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a53_disable_dcache
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* ---------------------------------------------
+	 * Flush L2 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a53_disable_smp
+endfunc cortex_a53_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A53. Must follow AAPCS.
+ */
+func cortex_a53_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A53_819472, cortex_a53, 819472
+	report_errata ERRATA_A53_824069, cortex_a53, 824069
+	report_errata ERRATA_A53_826319, cortex_a53, 826319
+	report_errata ERRATA_A53_827319, cortex_a53, 827319
+	report_errata ERRATA_A53_835769, cortex_a53, 835769
+	report_errata ERRATA_A53_836870, cortex_a53, disable_non_temporal_hint
+	report_errata ERRATA_A53_843419, cortex_a53, 843419
+	report_errata ERRATA_A53_855873, cortex_a53, 855873
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a53_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a53 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a53_regs, "aS"
+cortex_a53_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", \
+		"cpuactlr_el1", ""
+
+func cortex_a53_cpu_reg_dump
+	adr	x6, cortex_a53_regs
+	mrs	x8, CORTEX_A53_ECTLR_EL1
+	mrs	x9, CORTEX_A53_MERRSR_EL1
+	mrs	x10, CORTEX_A53_L2MERRSR_EL1
+	mrs	x11, CORTEX_A53_CPUACTLR_EL1
+	ret
+endfunc cortex_a53_cpu_reg_dump
+
+declare_cpu_ops cortex_a53, CORTEX_A53_MIDR, \
+	cortex_a53_reset_func, \
+	cortex_a53_core_pwr_dwn, \
+	cortex_a53_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a55.S b/lib/cpus/aarch64/cortex_a55.S
new file mode 100644
index 0000000..8e13824
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a55.S
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a55.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A55 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A55 Errata #768277.
+	 * This applies only to revision r0p0 of Cortex A55.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a55_768277_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_768277
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A55_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE
+	msr	CORTEX_A55_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a55_768277_wa
+
+func check_errata_768277
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_768277
+
+	/* ------------------------------------------------------------------
+	 * Errata Workaround for Cortex A55 Errata #778703.
+	 * This applies only to revision r0p0 of Cortex A55 where L2 cache is
+	 * not configured.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ------------------------------------------------------------------
+	 */
+func errata_a55_778703_wa
+	/*
+	 * Compare x0 against revision r0p0 and check that no private L2 cache
+	 * is configured
+	 */
+	mov	x17, x30
+	bl	check_errata_778703
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A55_CPUECTLR_EL1
+	orr	x1, x1, #CORTEX_A55_CPUECTLR_EL1_L1WSCTL
+	msr	CORTEX_A55_CPUECTLR_EL1, x1
+	mrs	x1, CORTEX_A55_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_WRITE_STREAMING
+	msr	CORTEX_A55_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a55_778703_wa
+
+func check_errata_778703
+	mov	x16, x30
+	mov	x1, #0x00
+	bl	cpu_rev_var_ls
+	/*
+	 * Check that no private L2 cache is configured
+	 */
+	mrs	x1, CORTEX_A55_CLIDR_EL1
+	and	x1, x1, CORTEX_A55_CLIDR_EL1_CTYPE3
+	cmp	x1, #0
+	mov	x2, #ERRATA_NOT_APPLIES
+	csel	x0, x0, x2, eq
+	ret	x16
+endfunc check_errata_778703
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A55 Errata #798797.
+	 * This applies only to revision r0p0 of Cortex A55.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a55_798797_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_798797
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A55_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_L1_PAGEWALKS
+	msr	CORTEX_A55_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a55_798797_wa
+
+func check_errata_798797
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_798797
+
+	/* --------------------------------------------------------------------
+	 * Errata Workaround for Cortex A55 Errata #846532.
+	 * This applies only to revisions <= r0p1 of Cortex A55.
+	 * Disabling dual-issue has a small impact on performance. Disabling a
+	 * power optimization feature is an alternate workaround with no impact
+	 * on performance but with an increase in power consumption (see errata
+	 * notice).
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------------------------
+	 */
+func errata_a55_846532_wa
+	/*
+	 * Compare x0 against revision r0p1
+	 */
+	mov	x17, x30
+	bl	check_errata_846532
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A55_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE
+	msr	CORTEX_A55_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a55_846532_wa
+
+func check_errata_846532
+	mov	x1, #0x01
+	b	cpu_rev_var_ls
+endfunc check_errata_846532
+
+	/* -----------------------------------------------------
+	 * Errata Workaround for Cortex A55 Errata #903758.
+	 * This applies only to revisions <= r0p1 of Cortex A55.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * -----------------------------------------------------
+	 */
+func errata_a55_903758_wa
+	/*
+	 * Compare x0 against revision r0p1
+	 */
+	mov	x17, x30
+	bl	check_errata_903758
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A55_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_L1_PAGEWALKS
+	msr	CORTEX_A55_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a55_903758_wa
+
+func check_errata_903758
+	mov	x1, #0x01
+	b	cpu_rev_var_ls
+endfunc check_errata_903758
+
+	/* -----------------------------------------------------
+	 * Errata Workaround for Cortex A55 Errata #1221012.
+	 * This applies only to revisions <= r1p0 of Cortex A55.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * -----------------------------------------------------
+	 */
+func errata_a55_1221012_wa
+	/*
+	 * Compare x0 against revision r1p0
+	 */
+	mov	x17, x30
+	bl	check_errata_1221012
+	cbz	x0, 1f
+	mov	x0, #0x0020
+	movk	x0, #0x0850, lsl #16
+	msr	CPUPOR_EL3, x0
+	mov	x0, #0x0000
+	movk	x0, #0x1FF0, lsl #16
+	movk	x0, #0x2, lsl #32
+	msr	CPUPMR_EL3, x0
+	mov	x0, #0x03fd
+	movk	x0, #0x0110, lsl #16
+	msr	CPUPCR_EL3, x0
+	mov	x0, #0x1
+	msr	CPUPSELR_EL3, x0
+	mov	x0, #0x0040
+	movk	x0, #0x08D0, lsl #16
+	msr	CPUPOR_EL3, x0
+	mov	x0, #0x0040
+	movk	x0, #0x1FF0, lsl #16
+	movk	x0, #0x2, lsl #32
+	msr	CPUPMR_EL3, x0
+	mov	x0, #0x03fd
+	movk	x0, #0x0110, lsl #16
+	msr	CPUPCR_EL3, x0
+	isb
+1:
+	ret	x17
+endfunc errata_a55_1221012_wa
+
+func check_errata_1221012
+	mov	x1, #0x10
+	b	cpu_rev_var_ls
+endfunc check_errata_1221012
+
+func cortex_a55_reset_func
+	mov	x19, x30
+
+#if ERRATA_DSU_798953
+	bl	errata_dsu_798953_wa
+#endif
+
+#if ERRATA_DSU_936184
+	bl	errata_dsu_936184_wa
+#endif
+
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_A55_768277
+	mov	x0, x18
+	bl	errata_a55_768277_wa
+#endif
+
+#if ERRATA_A55_778703
+	mov	x0, x18
+	bl	errata_a55_778703_wa
+#endif
+
+#if ERRATA_A55_798797
+	mov	x0, x18
+	bl	errata_a55_798797_wa
+#endif
+
+#if ERRATA_A55_846532
+	mov	x0, x18
+	bl	errata_a55_846532_wa
+#endif
+
+#if ERRATA_A55_903758
+	mov	x0, x18
+	bl	errata_a55_903758_wa
+#endif
+
+#if ERRATA_A55_1221012
+	mov	x0, x18
+	bl	errata_a55_1221012_wa
+#endif
+
+	ret	x19
+endfunc cortex_a55_reset_func
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a55_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A55_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A55_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A55_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a55_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A55. Must follow AAPCS & can use stack.
+ */
+func cortex_a55_errata_report
+	stp	x8, x30, [sp, #-16]!
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision variant information is at x8, where
+	 * "report_errata" is expecting it and it doesn't corrupt it.
+	 */
+	report_errata ERRATA_DSU_798953, cortex_a55, dsu_798953
+	report_errata ERRATA_DSU_936184, cortex_a55, dsu_936184
+	report_errata ERRATA_A55_768277, cortex_a55, 768277
+	report_errata ERRATA_A55_778703, cortex_a55, 778703
+	report_errata ERRATA_A55_798797, cortex_a55, 798797
+	report_errata ERRATA_A55_846532, cortex_a55, 846532
+	report_errata ERRATA_A55_903758, cortex_a55, 903758
+	report_errata ERRATA_A55_1221012, cortex_a55, 1221012
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a55_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a55 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a55_regs, "aS"
+cortex_a55_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a55_cpu_reg_dump
+	adr	x6, cortex_a55_regs
+	mrs	x8, CORTEX_A55_CPUECTLR_EL1
+	ret
+endfunc cortex_a55_cpu_reg_dump
+
+declare_cpu_ops cortex_a55, CORTEX_A55_MIDR, \
+	cortex_a55_reset_func, \
+	cortex_a55_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
new file mode 100644
index 0000000..dd03c0f
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a57.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+	/* ---------------------------------------------
+	 * Disable L1 data cache and unified L2 cache
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_dcache
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+	ret
+endfunc cortex_a57_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable all types of L2 prefetches.
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_l2_prefetch
+	mrs	x0, CORTEX_A57_ECTLR_EL1
+	orr	x0, x0, #CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT
+	mov	x1, #CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK
+	orr	x1, x1, #CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK
+	bic	x0, x0, x1
+	msr	CORTEX_A57_ECTLR_EL1, x0
+	isb
+	dsb	ish
+	ret
+endfunc cortex_a57_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_smp
+	mrs	x0, CORTEX_A57_ECTLR_EL1
+	bic	x0, x0, #CORTEX_A57_ECTLR_SMP_BIT
+	msr	CORTEX_A57_ECTLR_EL1, x0
+	ret
+endfunc cortex_a57_disable_smp
+
+	/* ---------------------------------------------
+	 * Disable debug interfaces
+	 * ---------------------------------------------
+	 */
+func cortex_a57_disable_ext_debug
+	mov	x0, #1
+	msr	osdlr_el1, x0
+	isb
+#if ERRATA_A57_817169
+	/*
+	 * Invalidate any TLB address
+	 */
+	mov	x0, #0
+	tlbi	vae3, x0
+#endif
+	dsb	sy
+	ret
+endfunc cortex_a57_disable_ext_debug
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #806969.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a57_806969_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_806969
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_NO_ALLOC_WBWA
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_806969_wa
+
+func check_errata_806969
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_806969
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #813419.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * ---------------------------------------------------
+	 */
+func check_errata_813419
+	/*
+	 * Even though this is only needed for revision r0p0, it
+	 * is always applied due to limitations of the current
+	 * errata framework.
+	 */
+	mov	x0, #ERRATA_APPLIES
+	ret
+endfunc check_errata_813419
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #813420.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_813420_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_813420
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_DCC_AS_DCCI
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_813420_wa
+
+func check_errata_813420
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_813420
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #814670.
+	 * This applies only to revision r0p0 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_814670_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_814670
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_DMB_NULLIFICATION
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a57_814670_wa
+
+func check_errata_814670
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_814670
+
+	/* ----------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #817169.
+	 * This applies only to revision <= r0p1 of Cortex A57.
+	 * ----------------------------------------------------
+	 */
+func check_errata_817169
+	/*
+	 * Even though this is only needed for revision <= r0p1, it
+	 * is always applied because of the low cost of the workaround.
+	 */
+	mov	x0, #ERRATA_APPLIES
+	ret
+endfunc check_errata_817169
+
+	/* --------------------------------------------------------------------
+	 * Disable the over-read from the LDNP instruction.
+	 *
+	 * This applies to all revisions <= r1p2. The performance degradation
+	 * observed with LDNP/STNP has been fixed on r1p3 and onwards.
+	 *
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------------------------
+	 */
+func a57_disable_ldnp_overread
+	/*
+	 * Compare x0 against revision r1p2
+	 */
+	mov	x17, x30
+	bl	check_errata_disable_ldnp_overread
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_OVERREAD
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc a57_disable_ldnp_overread
+
+func check_errata_disable_ldnp_overread
+	mov	x1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_disable_ldnp_overread
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #826974.
+	 * This applies only to revision <= r1p1 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_826974_wa
+	/*
+	 * Compare x0 against revision r1p1
+	 */
+	mov	x17, x30
+	bl	check_errata_826974
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_DMB
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_826974_wa
+
+func check_errata_826974
+	mov	x1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_826974
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #826977.
+	 * This applies only to revision <= r1p1 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_826977_wa
+	/*
+	 * Compare x0 against revision r1p1
+	 */
+	mov	x17, x30
+	bl	check_errata_826977
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_GRE_NGRE_AS_NGNRE
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_826977_wa
+
+func check_errata_826977
+	mov	x1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_826977
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #828024.
+	 * This applies only to revision <= r1p1 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_828024_wa
+	/*
+	 * Compare x0 against revision r1p1
+	 */
+	mov	x17, x30
+	bl	check_errata_828024
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	/*
+	 * Setting the relevant bits in CPUACTLR_EL1 has to be done in 2
+	 * instructions here because the resulting bitmask doesn't fit in a
+	 * 16-bit value so it cannot be encoded in a single instruction.
+	 */
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_NO_ALLOC_WBWA
+	orr	x1, x1, #(CORTEX_A57_CPUACTLR_EL1_DIS_L1_STREAMING | \
+			  CORTEX_A57_CPUACTLR_EL1_DIS_STREAMING)
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_828024_wa
+
+func check_errata_828024
+	mov	x1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_828024
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #829520.
+	 * This applies only to revision <= r1p2 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_829520_wa
+	/*
+	 * Compare x0 against revision r1p2
+	 */
+	mov	x17, x30
+	bl	check_errata_829520
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_INDIRECT_PREDICTOR
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_829520_wa
+
+func check_errata_829520
+	mov	x1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_829520
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #833471.
+	 * This applies only to revision <= r1p2 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a57_833471_wa
+	/*
+	 * Compare x0 against revision r1p2
+	 */
+	mov	x17, x30
+	bl	check_errata_833471
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_FORCE_FPSCR_FLUSH
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_833471_wa
+
+func check_errata_833471
+	mov	x1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_833471
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A57 Errata #859972.
+	 * This applies only to revision <= r1p3 of Cortex A57.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber:
+	 * --------------------------------------------------
+	 */
+func errata_a57_859972_wa
+	mov	x17, x30
+	bl	check_errata_859972
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A57_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_INSTR_PREFETCH
+	msr	CORTEX_A57_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a57_859972_wa
+
+func check_errata_859972
+	mov	x1, #0x13
+	b	cpu_rev_var_ls
+endfunc check_errata_859972
+
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2018_3639
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A57.
+	 * Shall clobber: x0-x19
+	 * -------------------------------------------------
+	 */
+func cortex_a57_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_A57_806969
+	mov	x0, x18
+	bl	errata_a57_806969_wa
+#endif
+
+#if ERRATA_A57_813420
+	mov	x0, x18
+	bl	errata_a57_813420_wa
+#endif
+
+#if ERRATA_A57_814670
+	mov	x0, x18
+	bl	errata_a57_814670_wa
+#endif
+
+#if A57_DISABLE_NON_TEMPORAL_HINT
+	mov	x0, x18
+	bl	a57_disable_ldnp_overread
+#endif
+
+#if ERRATA_A57_826974
+	mov	x0, x18
+	bl	errata_a57_826974_wa
+#endif
+
+#if ERRATA_A57_826977
+	mov	x0, x18
+	bl	errata_a57_826977_wa
+#endif
+
+#if ERRATA_A57_828024
+	mov	x0, x18
+	bl	errata_a57_828024_wa
+#endif
+
+#if ERRATA_A57_829520
+	mov	x0, x18
+	bl	errata_a57_829520_wa
+#endif
+
+#if ERRATA_A57_833471
+	mov	x0, x18
+	bl	errata_a57_833471_wa
+#endif
+
+#if ERRATA_A57_859972
+	mov	x0, x18
+	bl	errata_a57_859972_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+	adr	x0, wa_cve_2017_5715_mmu_vbar
+	msr	vbar_el3, x0
+	/* isb will be performed before returning from this function */
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	mrs	x0, CORTEX_A57_CPUACTLR_EL1
+	orr	x0, x0, #CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_STORE
+	msr	CORTEX_A57_CPUACTLR_EL1, x0
+	isb
+	dsb	sy
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A57_ECTLR_EL1
+	orr	x0, x0, #CORTEX_A57_ECTLR_SMP_BIT
+	msr	CORTEX_A57_ECTLR_EL1, x0
+	isb
+	ret	x19
+endfunc cortex_a57_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Cortex-A57.
+	 * ----------------------------------------------------
+	 */
+func cortex_a57_core_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a57_disable_ext_debug
+endfunc cortex_a57_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Cortex-A57.
+	 * -------------------------------------------------------
+	 */
+func cortex_a57_cluster_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_l2_prefetch
+
+#if !SKIP_A57_L1_FLUSH_PWR_DWN
+	/* -------------------------------------------------
+	 * Flush the L1 caches.
+	 * -------------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+#endif
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* -------------------------------------------------
+	 * Flush the L2 caches.
+	 * -------------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a57_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a57_disable_ext_debug
+endfunc cortex_a57_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A57. Must follow AAPCS.
+ */
+func cortex_a57_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A57_806969, cortex_a57, 806969
+	report_errata ERRATA_A57_813419, cortex_a57, 813419
+	report_errata ERRATA_A57_813420, cortex_a57, 813420
+	report_errata ERRATA_A57_814670, cortex_a57, 814670
+	report_errata ERRATA_A57_817169, cortex_a57, 817169
+	report_errata A57_DISABLE_NON_TEMPORAL_HINT, cortex_a57, \
+		disable_ldnp_overread
+	report_errata ERRATA_A57_826974, cortex_a57, 826974
+	report_errata ERRATA_A57_826977, cortex_a57, 826977
+	report_errata ERRATA_A57_828024, cortex_a57, 828024
+	report_errata ERRATA_A57_829520, cortex_a57, 829520
+	report_errata ERRATA_A57_833471, cortex_a57, 833471
+	report_errata ERRATA_A57_859972, cortex_a57, 859972
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a57, cve_2018_3639
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a57_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a57 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a57_regs, "aS"
+cortex_a57_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", ""
+
+func cortex_a57_cpu_reg_dump
+	adr	x6, cortex_a57_regs
+	mrs	x8, CORTEX_A57_ECTLR_EL1
+	mrs	x9, CORTEX_A57_MERRSR_EL1
+	mrs	x10, CORTEX_A57_L2MERRSR_EL1
+	ret
+endfunc cortex_a57_cpu_reg_dump
+
+declare_cpu_ops_wa cortex_a57, CORTEX_A57_MIDR, \
+	cortex_a57_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	cortex_a57_core_pwr_dwn, \
+	cortex_a57_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
new file mode 100644
index 0000000..38b76b9
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+	/* ---------------------------------------------
+	 * Disable L1 data cache and unified L2 cache
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_dcache
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+	ret
+endfunc cortex_a72_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable all types of L2 prefetches.
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_l2_prefetch
+	mrs	x0, CORTEX_A72_ECTLR_EL1
+	orr	x0, x0, #CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT
+	mov	x1, #CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK
+	orr	x1, x1, #CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK
+	bic	x0, x0, x1
+	msr	CORTEX_A72_ECTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a72_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable the load-store hardware prefetcher.
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_hw_prefetcher
+	mrs	x0, CORTEX_A72_CPUACTLR_EL1
+	orr	x0, x0, #CORTEX_A72_CPUACTLR_EL1_DISABLE_L1_DCACHE_HW_PFTCH
+	msr	CORTEX_A72_CPUACTLR_EL1, x0
+	isb
+	dsb	ish
+	ret
+endfunc cortex_a72_disable_hw_prefetcher
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_smp
+	mrs	x0, CORTEX_A72_ECTLR_EL1
+	bic	x0, x0, #CORTEX_A72_ECTLR_SMP_BIT
+	msr	CORTEX_A72_ECTLR_EL1, x0
+	ret
+endfunc cortex_a72_disable_smp
+
+	/* ---------------------------------------------
+	 * Disable debug interfaces
+	 * ---------------------------------------------
+	 */
+func cortex_a72_disable_ext_debug
+	mov	x0, #1
+	msr	osdlr_el1, x0
+	isb
+	dsb	sy
+	ret
+endfunc cortex_a72_disable_ext_debug
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A72 Errata #859971.
+	 * This applies only to revision <= r0p3 of Cortex A72.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber:
+	 * --------------------------------------------------
+	 */
+func errata_a72_859971_wa
+	mov	x17,x30
+	bl	check_errata_859971
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A72_CPUACTLR_EL1
+	orr	x1, x1, #CORTEX_A72_CPUACTLR_EL1_DIS_INSTR_PREFETCH
+	msr	CORTEX_A72_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_a72_859971_wa
+
+func check_errata_859971
+	mov	x1, #0x03
+	b	cpu_rev_var_ls
+endfunc check_errata_859971
+
+func check_errata_cve_2017_5715
+	cpu_check_csv2	x0, 1f
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+1:
+	mov	x0, #ERRATA_NOT_APPLIES
+	ret
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2018_3639
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A72.
+	 * -------------------------------------------------
+	 */
+func cortex_a72_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_A72_859971
+	mov	x0, x18
+	bl	errata_a72_859971_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+	cpu_check_csv2	x0, 1f
+	adr	x0, wa_cve_2017_5715_mmu_vbar
+	msr	vbar_el3, x0
+	/* isb will be performed before returning from this function */
+1:
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	mrs	x0, CORTEX_A72_CPUACTLR_EL1
+	orr	x0, x0, #CORTEX_A72_CPUACTLR_EL1_DIS_LOAD_PASS_STORE
+	msr	CORTEX_A72_CPUACTLR_EL1, x0
+	isb
+	dsb	sy
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A72_ECTLR_EL1
+	orr	x0, x0, #CORTEX_A72_ECTLR_SMP_BIT
+	msr	CORTEX_A72_ECTLR_EL1, x0
+	isb
+	ret x19
+endfunc cortex_a72_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Cortex-A72.
+	 * ----------------------------------------------------
+	 */
+func cortex_a72_core_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable the load-store hardware prefetcher.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_hw_prefetcher
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a72_disable_ext_debug
+endfunc cortex_a72_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Cortex-A72.
+	 * -------------------------------------------------------
+	 */
+func cortex_a72_cluster_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable the L2 prefetches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_l2_prefetch
+
+	/* ---------------------------------------------
+	 * Disable the load-store hardware prefetcher.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_hw_prefetcher
+
+#if !SKIP_A72_L1_FLUSH_PWR_DWN
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+#endif
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* -------------------------------------------------
+	 * Flush the L2 caches.
+	 * -------------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a72_disable_smp
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a72_disable_ext_debug
+endfunc cortex_a72_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A72. Must follow AAPCS.
+ */
+func cortex_a72_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A72_859971, cortex_a72, 859971
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a72, cve_2018_3639
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a72_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a72 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a72_regs, "aS"
+cortex_a72_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", ""
+
+func cortex_a72_cpu_reg_dump
+	adr	x6, cortex_a72_regs
+	mrs	x8, CORTEX_A72_ECTLR_EL1
+	mrs	x9, CORTEX_A72_MERRSR_EL1
+	mrs	x10, CORTEX_A72_L2MERRSR_EL1
+	ret
+endfunc cortex_a72_cpu_reg_dump
+
+declare_cpu_ops_wa cortex_a72, CORTEX_A72_MIDR, \
+	cortex_a72_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	cortex_a72_core_pwr_dwn, \
+	cortex_a72_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
new file mode 100644
index 0000000..5c8a887
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a73.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+	/* ---------------------------------------------
+	 * Disable L1 data cache
+	 * ---------------------------------------------
+	 */
+func cortex_a73_disable_dcache
+	mrs	x1, sctlr_el3
+	bic	x1, x1, #SCTLR_C_BIT
+	msr	sctlr_el3, x1
+	isb
+	ret
+endfunc cortex_a73_disable_dcache
+
+	/* ---------------------------------------------
+	 * Disable intra-cluster coherency
+	 * ---------------------------------------------
+	 */
+func cortex_a73_disable_smp
+	mrs	x0, CORTEX_A73_CPUECTLR_EL1
+	bic	x0, x0, #CORTEX_A73_CPUECTLR_SMP_BIT
+	msr	CORTEX_A73_CPUECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc cortex_a73_disable_smp
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A73 Errata #852427.
+	 * This applies only to revision r0p0 of Cortex A73.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a73_852427_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_852427
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A73_DIAGNOSTIC_REGISTER
+	orr	x1, x1, #(1 << 12)
+	msr	CORTEX_A73_DIAGNOSTIC_REGISTER, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a73_852427_wa
+
+func check_errata_852427
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_852427
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A73 Errata #855423.
+	 * This applies only to revision <= r0p1 of Cortex A73.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * ---------------------------------------------------
+	 */
+func errata_a73_855423_wa
+	/*
+	 * Compare x0 against revision r0p1
+	 */
+	mov	x17, x30
+	bl	check_errata_855423
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A73_IMP_DEF_REG2
+	orr	x1, x1, #(1 << 7)
+	msr	CORTEX_A73_IMP_DEF_REG2, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a73_855423_wa
+
+func check_errata_855423
+	mov	x1, #0x01
+	b	cpu_rev_var_ls
+endfunc check_errata_855423
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A73.
+	 * -------------------------------------------------
+	 */
+
+func cortex_a73_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_A73_852427
+	mov	x0, x18
+	bl	errata_a73_852427_wa
+#endif
+
+#if ERRATA_A73_855423
+	mov	x0, x18
+	bl	errata_a73_855423_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+	cpu_check_csv2	x0, 1f
+	adr	x0, wa_cve_2017_5715_bpiall_vbar
+	msr	vbar_el3, x0
+	/* isb will be performed before returning from this function */
+1:
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	mrs	x0, CORTEX_A73_IMP_DEF_REG1
+	orr	x0, x0, #CORTEX_A73_IMP_DEF_REG1_DISABLE_LOAD_PASS_STORE
+	msr	CORTEX_A73_IMP_DEF_REG1, x0
+	isb
+#endif
+
+	/* ---------------------------------------------
+	 * Enable the SMP bit.
+	 * Clobbers : x0
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A73_CPUECTLR_EL1
+	orr	x0, x0, #CORTEX_A73_CPUECTLR_SMP_BIT
+	msr	CORTEX_A73_CPUECTLR_EL1, x0
+	isb
+	ret	x19
+endfunc cortex_a73_reset_func
+
+func cortex_a73_core_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a73_disable_dcache
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a73_disable_smp
+endfunc cortex_a73_core_pwr_dwn
+
+func cortex_a73_cluster_pwr_dwn
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Turn off caches.
+	 * ---------------------------------------------
+	 */
+	bl	cortex_a73_disable_dcache
+
+	/* ---------------------------------------------
+	 * Flush L1 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level1
+
+	/* ---------------------------------------------
+	 * Disable the optional ACP.
+	 * ---------------------------------------------
+	 */
+	bl	plat_disable_acp
+
+	/* ---------------------------------------------
+	 * Flush L2 caches.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	bl	dcsw_op_level2
+
+	/* ---------------------------------------------
+	 * Come out of intra cluster coherency
+	 * ---------------------------------------------
+	 */
+	mov	x30, x18
+	b	cortex_a73_disable_smp
+endfunc cortex_a73_cluster_pwr_dwn
+
+func check_errata_cve_2017_5715
+	cpu_check_csv2	x0, 1f
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+1:
+	mov	x0, #ERRATA_NOT_APPLIES
+	ret
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2018_3639
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A75. Must follow AAPCS.
+ */
+func cortex_a73_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A73_852427, cortex_a73, 852427
+	report_errata ERRATA_A73_855423, cortex_a73, 855423
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a73, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a73, cve_2018_3639
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a73_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a73 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a73_regs, "aS"
+cortex_a73_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", "l2merrsr_el1", ""
+
+func cortex_a73_cpu_reg_dump
+	adr	x6, cortex_a73_regs
+	mrs	x8, CORTEX_A73_CPUECTLR_EL1
+	mrs	x9, CORTEX_A73_L2MERRSR_EL1
+	ret
+endfunc cortex_a73_cpu_reg_dump
+
+declare_cpu_ops_wa cortex_a73, CORTEX_A73_MIDR, \
+	cortex_a73_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	cortex_a73_core_pwr_dwn, \
+	cortex_a73_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
new file mode 100644
index 0000000..657457e
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a75.h>
+#include <cpuamu.h>
+#include <cpu_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A75 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A75 Errata #764081.
+	 * This applies only to revision r0p0 of Cortex A75.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a75_764081_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_764081
+	cbz	x0, 1f
+	mrs	x1, sctlr_el3
+	orr	x1, x1 ,#SCTLR_IESB_BIT
+	msr	sctlr_el3, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a75_764081_wa
+
+func check_errata_764081
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_764081
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A75 Errata #790748.
+	 * This applies only to revision r0p0 of Cortex A75.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a75_790748_wa
+	/*
+	 * Compare x0 against revision r0p0
+	 */
+	mov	x17, x30
+	bl	check_errata_790748
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A75_CPUACTLR_EL1
+	orr	x1, x1 ,#(1 << 13)
+	msr	CORTEX_A75_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a75_790748_wa
+
+func check_errata_790748
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_790748
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A75.
+	 * -------------------------------------------------
+	 */
+func cortex_a75_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_A75_764081
+	mov	x0, x18
+	bl	errata_a75_764081_wa
+#endif
+
+#if ERRATA_A75_790748
+	mov	x0, x18
+	bl	errata_a75_790748_wa
+#endif
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+	cpu_check_csv2	x0, 1f
+	adr	x0, wa_cve_2017_5715_bpiall_vbar
+	msr	vbar_el3, x0
+	isb
+1:
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	mrs	x0, CORTEX_A75_CPUACTLR_EL1
+	orr	x0, x0, #CORTEX_A75_CPUACTLR_EL1_DISABLE_LOAD_PASS_STORE
+	msr	CORTEX_A75_CPUACTLR_EL1, x0
+	isb
+#endif
+
+#if ERRATA_DSU_798953
+	bl	errata_dsu_798953_wa
+#endif
+
+#if ERRATA_DSU_936184
+	bl	errata_dsu_936184_wa
+#endif
+
+#if ENABLE_AMU
+	/* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+	mrs	x0, actlr_el3
+	orr	x0, x0, #CORTEX_A75_ACTLR_AMEN_BIT
+	msr	actlr_el3, x0
+	isb
+
+	/* Make sure accesses from EL0/EL1 are not trapped to EL2 */
+	mrs	x0, actlr_el2
+	orr	x0, x0, #CORTEX_A75_ACTLR_AMEN_BIT
+	msr	actlr_el2, x0
+	isb
+
+	/* Enable group0 counters */
+	mov	x0, #CORTEX_A75_AMU_GROUP0_MASK
+	msr	CPUAMCNTENSET_EL0, x0
+	isb
+
+	/* Enable group1 counters */
+	mov	x0, #CORTEX_A75_AMU_GROUP1_MASK
+	msr	CPUAMCNTENSET_EL0, x0
+	isb
+#endif
+	ret	x19
+endfunc cortex_a75_reset_func
+
+func check_errata_cve_2017_5715
+	cpu_check_csv2	x0, 1f
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+1:
+	mov	x0, #ERRATA_NOT_APPLIES
+	ret
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2018_3639
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a75_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A75_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A75_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a75_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A75. Must follow AAPCS.
+ */
+func cortex_a75_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A75_764081, cortex_a75, 764081
+	report_errata ERRATA_A75_790748, cortex_a75, 790748
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a75, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a75, cve_2018_3639
+	report_errata ERRATA_DSU_798953, cortex_a75, dsu_798953
+	report_errata ERRATA_DSU_936184, cortex_a75, dsu_936184
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a75_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a75 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a75_regs, "aS"
+cortex_a75_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a75_cpu_reg_dump
+	adr	x6, cortex_a75_regs
+	mrs	x8, CORTEX_A75_CPUECTLR_EL1
+	ret
+endfunc cortex_a75_cpu_reg_dump
+
+declare_cpu_ops_wa cortex_a75, CORTEX_A75_MIDR, \
+	cortex_a75_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	cortex_a75_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a75_pubsub.c b/lib/cpus/aarch64/cortex_a75_pubsub.c
new file mode 100644
index 0000000..bd2c697
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a75_pubsub.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cortex_a75.h>
+#include <cpuamu.h>
+#include <lib/el3_runtime/pubsub_events.h>
+
+static void *cortex_a75_context_save(const void *arg)
+{
+	if (midr_match(CORTEX_A75_MIDR) != 0)
+		cpuamu_context_save(CORTEX_A75_AMU_NR_COUNTERS);
+
+	return (void *)0;
+}
+
+static void *cortex_a75_context_restore(const void *arg)
+{
+	if (midr_match(CORTEX_A75_MIDR) != 0)
+		cpuamu_context_restore(CORTEX_A75_AMU_NR_COUNTERS);
+
+	return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, cortex_a75_context_save);
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, cortex_a75_context_restore);
diff --git a/lib/cpus/aarch64/cortex_a76.S b/lib/cpus/aarch64/cortex_a76.S
new file mode 100644
index 0000000..868667e
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a76.S
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <context.h>
+#include <cortex_a76.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include <services/arm_arch_svc.h>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A76 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-A76 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+#define ESR_EL3_A64_SMC0	0x5e000000
+#define ESR_EL3_A32_SMC0	0x4e000000
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+	/*
+	 * This macro applies the mitigation for CVE-2018-3639.
+	 * It implements a fast path where `SMCCC_ARCH_WORKAROUND_2`
+	 * SMC calls from a lower EL running in AArch32 or AArch64
+	 * will go through the fast and return early.
+	 *
+	 * The macro saves x2-x3 to the context. In the fast path
+	 * x0-x3 registers do not need to be restored as the calling
+	 * context will have saved them.
+	 */
+	.macro apply_cve_2018_3639_wa _is_sync_exception _esr_el3_val
+	stp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+
+	.if \_is_sync_exception
+		/*
+		 * Ensure SMC is coming from A64/A32 state on #0
+		 * with W0 = SMCCC_ARCH_WORKAROUND_2
+		 *
+		 * This sequence evaluates as:
+		 *    (W0==SMCCC_ARCH_WORKAROUND_2) ? (ESR_EL3==SMC#0) : (NE)
+		 * allowing use of a single branch operation
+		 */
+		orr	w2, wzr, #SMCCC_ARCH_WORKAROUND_2
+		cmp	x0, x2
+		mrs	x3, esr_el3
+		mov_imm	w2, \_esr_el3_val
+		ccmp	w2, w3, #0, eq
+		/*
+		 * Static predictor will predict a fall-through, optimizing
+		 * the `SMCCC_ARCH_WORKAROUND_2` fast path.
+		 */
+		bne	1f
+
+		/*
+		 * The sequence below implements the `SMCCC_ARCH_WORKAROUND_2`
+		 * fast path.
+		 */
+		cmp	x1, xzr /* enable/disable check */
+
+		/*
+		 * When the calling context wants mitigation disabled,
+		 * we program the mitigation disable function in the
+		 * CPU context, which gets invoked on subsequent exits from
+		 * EL3 via the `el3_exit` function. Otherwise NULL is
+		 * programmed in the CPU context, which results in caller's
+		 * inheriting the EL3 mitigation state (enabled) on subsequent
+		 * `el3_exit`.
+		 */
+		mov	x0, xzr
+		adr	x1, cortex_a76_disable_wa_cve_2018_3639
+		csel	x1, x1, x0, eq
+		str	x1, [sp, #CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_DISABLE]
+
+		mrs	x2, CORTEX_A76_CPUACTLR2_EL1
+		orr	x1, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE
+		bic	x3, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE
+		csel	x3, x3, x1, eq
+		msr	CORTEX_A76_CPUACTLR2_EL1, x3
+		eret	/* ERET implies ISB */
+	.endif
+1:
+	/*
+	 * Always enable v4 mitigation during EL3 execution. This is not
+	 * required for the fast path above because it does not perform any
+	 * memory loads.
+	 */
+	mrs	x2, CORTEX_A76_CPUACTLR2_EL1
+	orr	x2, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE
+	msr	CORTEX_A76_CPUACTLR2_EL1, x2
+	isb
+
+	/*
+	 * The caller may have passed arguments to EL3 via x2-x3.
+	 * Restore these registers from the context before jumping to the
+	 * main runtime vector table entry.
+	 */
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	.endm
+
+vector_base cortex_a76_wa_cve_2018_3639_a76_vbar
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_EL0 : 0x0 - 0x200
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry cortex_a76_sync_exception_sp_el0
+	b	sync_exception_sp_el0
+end_vector_entry cortex_a76_sync_exception_sp_el0
+
+vector_entry cortex_a76_irq_sp_el0
+	b	irq_sp_el0
+end_vector_entry cortex_a76_irq_sp_el0
+
+vector_entry cortex_a76_fiq_sp_el0
+	b	fiq_sp_el0
+end_vector_entry cortex_a76_fiq_sp_el0
+
+vector_entry cortex_a76_serror_sp_el0
+	b	serror_sp_el0
+end_vector_entry cortex_a76_serror_sp_el0
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_ELx: 0x200 - 0x400
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry cortex_a76_sync_exception_sp_elx
+	b	sync_exception_sp_elx
+end_vector_entry cortex_a76_sync_exception_sp_elx
+
+vector_entry cortex_a76_irq_sp_elx
+	b	irq_sp_elx
+end_vector_entry cortex_a76_irq_sp_elx
+
+vector_entry cortex_a76_fiq_sp_elx
+	b	fiq_sp_elx
+end_vector_entry cortex_a76_fiq_sp_elx
+
+vector_entry cortex_a76_serror_sp_elx
+	b	serror_sp_elx
+end_vector_entry cortex_a76_serror_sp_elx
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry cortex_a76_sync_exception_aarch64
+	apply_cve_2018_3639_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	sync_exception_aarch64
+end_vector_entry cortex_a76_sync_exception_aarch64
+
+vector_entry cortex_a76_irq_aarch64
+	apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	irq_aarch64
+end_vector_entry cortex_a76_irq_aarch64
+
+vector_entry cortex_a76_fiq_aarch64
+	apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	fiq_aarch64
+end_vector_entry cortex_a76_fiq_aarch64
+
+vector_entry cortex_a76_serror_aarch64
+	apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	serror_aarch64
+end_vector_entry cortex_a76_serror_aarch64
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry cortex_a76_sync_exception_aarch32
+	apply_cve_2018_3639_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	sync_exception_aarch32
+end_vector_entry cortex_a76_sync_exception_aarch32
+
+vector_entry cortex_a76_irq_aarch32
+	apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	irq_aarch32
+end_vector_entry cortex_a76_irq_aarch32
+
+vector_entry cortex_a76_fiq_aarch32
+	apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	fiq_aarch32
+end_vector_entry cortex_a76_fiq_aarch32
+
+vector_entry cortex_a76_serror_aarch32
+	apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	serror_aarch32
+end_vector_entry cortex_a76_serror_aarch32
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 */
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1073348.
+	 * This applies only to revision <= r1p0 of Cortex A76.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a76_1073348_wa
+	/*
+	 * Compare x0 against revision r1p0
+	 */
+	mov	x17, x30
+	bl	check_errata_1073348
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A76_CPUACTLR_EL1
+	orr	x1, x1 ,#CORTEX_A76_CPUACTLR_EL1_DISABLE_STATIC_PREDICTION
+	msr	CORTEX_A76_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1073348_wa
+
+func check_errata_1073348
+	mov	x1, #0x10
+	b	cpu_rev_var_ls
+endfunc check_errata_1073348
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1130799.
+	 * This applies only to revision <= r2p0 of Cortex A76.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a76_1130799_wa
+	/*
+	 * Compare x0 against revision r2p0
+	 */
+	mov	x17, x30
+	bl	check_errata_1130799
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A76_CPUACTLR2_EL1
+	orr	x1, x1 ,#(1 << 59)
+	msr	CORTEX_A76_CPUACTLR2_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1130799_wa
+
+func check_errata_1130799
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_1130799
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1220197.
+	 * This applies only to revision <= r2p0 of Cortex A76.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a76_1220197_wa
+/*
+ * Compare x0 against revision r2p0
+ */
+	mov	x17, x30
+	bl	check_errata_1220197
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A76_CPUECTLR_EL1
+	orr	x1, x1, #CORTEX_A76_CPUECTLR_EL1_WS_THR_L2
+	msr	CORTEX_A76_CPUECTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1220197_wa
+
+func check_errata_1220197
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_1220197
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1257314.
+	 * This applies only to revision <= r3p0 of Cortex A76.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a76_1257314_wa
+	/*
+	 * Compare x0 against revision r3p0
+	 */
+	mov	x17, x30
+	bl	check_errata_1257314
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A76_CPUACTLR3_EL1
+	orr	x1, x1, CORTEX_A76_CPUACTLR3_EL1_BIT_10
+	msr	CORTEX_A76_CPUACTLR3_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1257314_wa
+
+func check_errata_1257314
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1257314
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1262888.
+	 * This applies only to revision <= r3p0 of Cortex A76.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a76_1262888_wa
+	/*
+	 * Compare x0 against revision r3p0
+	 */
+	mov	x17, x30
+	bl	check_errata_1262888
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A76_CPUECTLR_EL1
+	orr	x1, x1, CORTEX_A76_CPUECTLR_EL1_BIT_51
+	msr	CORTEX_A76_CPUECTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1262888_wa
+
+func check_errata_1262888
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1262888
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1275112
+	 * and Errata #1262606.
+	 * This applies only to revision <= r3p0 of Cortex A76.
+	 * Inputs:
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_a76_1275112_1262606_wa
+	/*
+	 * Compare x0 against revision r3p0
+	 */
+	mov	x17, x30
+	/*
+	 * Since both errata #1275112 and #1262606 have the same check, we can
+	 * invoke any one of them for the check here.
+	 */
+	bl	check_errata_1275112
+	cbz	x0, 1f
+	mrs	x1, CORTEX_A76_CPUACTLR_EL1
+	orr	x1, x1, CORTEX_A76_CPUACTLR_EL1_BIT_13
+	msr	CORTEX_A76_CPUACTLR_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1275112_1262606_wa
+
+func check_errata_1262606
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1262606
+
+func check_errata_1275112
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1275112
+
+	/* ---------------------------------------------------
+	 * Errata Workaround for Cortex A76 Errata #1286807.
+	 * This applies only to revision <= r3p0 of Cortex A76.
+	 * Due to the nature of the errata it is applied unconditionally
+	 * when built in, report it as applicable in this case
+	 * ---------------------------------------------------
+	 */
+func check_errata_1286807
+#if ERRATA_A76_1286807
+	mov x0, #ERRATA_APPLIES
+	ret
+#else
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+#endif
+endfunc check_errata_1286807
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2018_3639
+
+func cortex_a76_disable_wa_cve_2018_3639
+	mrs	x0, CORTEX_A76_CPUACTLR2_EL1
+	bic	x0, x0, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE
+	msr	CORTEX_A76_CPUACTLR2_EL1, x0
+	isb
+	ret
+endfunc cortex_a76_disable_wa_cve_2018_3639
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-A76.
+	 * Shall clobber: x0-x19
+	 * -------------------------------------------------
+	 */
+func cortex_a76_reset_func
+	mov	x19, x30
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_A76_1073348
+	mov	x0, x18
+	bl	errata_a76_1073348_wa
+#endif
+
+#if ERRATA_A76_1130799
+	mov	x0, x18
+	bl	errata_a76_1130799_wa
+#endif
+
+#if ERRATA_A76_1220197
+	mov	x0, x18
+	bl	errata_a76_1220197_wa
+#endif
+
+#if ERRATA_A76_1257314
+	mov	x0, x18
+	bl	errata_a76_1257314_wa
+#endif
+
+#if ERRATA_A76_1262606 || ERRATA_A76_1275112
+	mov	x0, x18
+	bl	errata_a76_1275112_1262606_wa
+#endif
+
+#if ERRATA_A76_1262888
+	mov	x0, x18
+	bl	errata_a76_1262888_wa
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	/* If the PE implements SSBS, we don't need the dynamic workaround */
+	mrs	x0, id_aa64pfr1_el1
+	lsr	x0, x0, #ID_AA64PFR1_EL1_SSBS_SHIFT
+	and	x0, x0, #ID_AA64PFR1_EL1_SSBS_MASK
+#if !DYNAMIC_WORKAROUND_CVE_2018_3639 && ENABLE_ASSERTIONS
+	cmp	x0, 0
+	ASM_ASSERT(ne)
+#endif
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+	cbnz	x0, 1f
+	mrs	x0, CORTEX_A76_CPUACTLR2_EL1
+	orr	x0, x0, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE
+	msr	CORTEX_A76_CPUACTLR2_EL1, x0
+	isb
+
+#ifdef IMAGE_BL31
+	/*
+	 * The Cortex-A76 generic vectors are overwritten to use the vectors
+	 * defined above. This is required in order to apply mitigation
+	 * against CVE-2018-3639 on exception entry from lower ELs.
+	 */
+	adr	x0, cortex_a76_wa_cve_2018_3639_a76_vbar
+	msr	vbar_el3, x0
+	isb
+#endif /* IMAGE_BL31 */
+
+1:
+#endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 */
+#endif /* WORKAROUND_CVE_2018_3639 */
+
+#if ERRATA_DSU_798953
+	bl	errata_dsu_798953_wa
+#endif
+
+#if ERRATA_DSU_936184
+	bl	errata_dsu_936184_wa
+#endif
+
+	ret	x19
+endfunc cortex_a76_reset_func
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a76_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A76_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A76_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A76_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a76_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A76. Must follow AAPCS.
+ */
+func cortex_a76_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A76_1073348, cortex_a76, 1073348
+	report_errata ERRATA_A76_1130799, cortex_a76, 1130799
+	report_errata ERRATA_A76_1220197, cortex_a76, 1220197
+	report_errata ERRATA_A76_1257314, cortex_a76, 1257314
+	report_errata ERRATA_A76_1262606, cortex_a76, 1262606
+	report_errata ERRATA_A76_1262888, cortex_a76, 1262888
+	report_errata ERRATA_A76_1275112, cortex_a76, 1275112
+	report_errata ERRATA_A76_1286807, cortex_a76, 1286807
+	report_errata WORKAROUND_CVE_2018_3639, cortex_a76, cve_2018_3639
+	report_errata ERRATA_DSU_798953, cortex_a76, dsu_798953
+	report_errata ERRATA_DSU_936184, cortex_a76, dsu_936184
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a76_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a76 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a76_regs, "aS"
+cortex_a76_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a76_cpu_reg_dump
+	adr	x6, cortex_a76_regs
+	mrs	x8, CORTEX_A76_CPUECTLR_EL1
+	ret
+endfunc cortex_a76_cpu_reg_dump
+
+declare_cpu_ops_wa cortex_a76, CORTEX_A76_MIDR, \
+	cortex_a76_reset_func, \
+	CPU_NO_EXTRA1_FUNC, \
+	cortex_a76_disable_wa_cve_2018_3639, \
+	cortex_a76_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a76ae.S b/lib/cpus/aarch64/cortex_a76ae.S
new file mode 100644
index 0000000..888f98b
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a76ae.S
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <cortex_a76ae.h>
+#include <cpu_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A76AE must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-A76AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a76ae_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A76AE_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A76AE_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A76AE_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a76ae_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex-A76AE. Must follow AAPCS.
+ */
+func cortex_a76ae_errata_report
+	ret
+endfunc cortex_a76ae_errata_report
+#endif	/* REPORT_ERRATA */
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a76ae specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a76ae_regs, "aS"
+cortex_a76ae_regs:  /* The ASCII list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a76ae_cpu_reg_dump
+	adr	x6, cortex_a76ae_regs
+	mrs	x8, CORTEX_A76AE_CPUECTLR_EL1
+	ret
+endfunc cortex_a76ae_cpu_reg_dump
+
+declare_cpu_ops cortex_a76ae, CORTEX_A76AE_MIDR, CPU_NO_RESET_FUNC, \
+	cortex_a76ae_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a77.S b/lib/cpus/aarch64/cortex_a77.S
new file mode 100644
index 0000000..f3fd5e1
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a77.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a77.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Cortex-A77 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Cortex-A77 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a77_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A77_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A77_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	CORTEX_A77_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a77_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex-A77. Must follow AAPCS.
+ */
+func cortex_a77_errata_report
+	ret
+endfunc cortex_a77_errata_report
+#endif
+
+
+	/* ---------------------------------------------
+	 * This function provides Cortex-A77 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a77_regs, "aS"
+cortex_a77_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a77_cpu_reg_dump
+	adr	x6, cortex_a77_regs
+	mrs	x8, CORTEX_A77_CPUECTLR_EL1
+	ret
+endfunc cortex_a77_cpu_reg_dump
+
+declare_cpu_ops cortex_a77, CORTEX_A77_MIDR, \
+	CPU_NO_RESET_FUNC, \
+	cortex_a77_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_hercules.S b/lib/cpus/aarch64/cortex_hercules.S
new file mode 100644
index 0000000..4e04814
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_hercules.S
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_hercules.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "cortex_hercules must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Cortex-Hercules
+	 * -------------------------------------------------
+	 */
+#if ENABLE_AMU
+func cortex_hercules_reset_func
+	/* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+	mrs	x0, actlr_el3
+	bic	x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT
+	msr	actlr_el3, x0
+
+	/* Make sure accesses from non-secure EL0/EL1 are not trapped to EL2 */
+	mrs	x0, actlr_el2
+	bic	x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT
+	msr	actlr_el2, x0
+
+	/* Enable group0 counters */
+	mov	x0, #CORTEX_HERCULES_AMU_GROUP0_MASK
+	msr	CPUAMCNTENSET0_EL0, x0
+
+	/* Enable group1 counters */
+	mov	x0, #CORTEX_HERCULES_AMU_GROUP1_MASK
+	msr	CPUAMCNTENSET1_EL0, x0
+	isb
+
+	ret
+endfunc cortex_hercules_reset_func
+#endif
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_hercules_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_HERCULES_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_HERCULES_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
+	msr	CORTEX_HERCULES_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_hercules_core_pwr_dwn
+
+	/*
+	 * Errata printing function for cortex_hercules. Must follow AAPCS.
+	 */
+#if REPORT_ERRATA
+func cortex_hercules_errata_report
+	ret
+endfunc cortex_hercules_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides cortex_hercules specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_hercules_regs, "aS"
+cortex_hercules_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_hercules_cpu_reg_dump
+	adr	x6, cortex_hercules_regs
+	mrs	x8, CORTEX_HERCULES_CPUECTLR_EL1
+	ret
+endfunc cortex_hercules_cpu_reg_dump
+
+#if ENABLE_AMU
+#define HERCULES_RESET_FUNC cortex_hercules_reset_func
+#else
+#define HERCULES_RESET_FUNC CPU_NO_RESET_FUNC
+#endif
+
+declare_cpu_ops cortex_hercules, CORTEX_HERCULES_MIDR, \
+	HERCULES_RESET_FUNC, \
+	cortex_hercules_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
new file mode 100644
index 0000000..de1177c
--- /dev/null
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cpu_macros.S>
+#include <lib/cpus/errata_report.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+ /* Reset fn is needed in BL at reset vector */
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3)
+	/*
+	 * The reset handler common to all platforms.  After a matching
+	 * cpu_ops structure entry is found, the correponding reset_handler
+	 * in the cpu_ops is invoked.
+	 * Clobbers: x0 - x19, x30
+	 */
+	.globl	reset_handler
+func reset_handler
+	mov	x19, x30
+
+	/* The plat_reset_handler can clobber x0 - x18, x30 */
+	bl	plat_reset_handler
+
+	/* Get the matching cpu_ops pointer */
+	bl	get_cpu_ops_ptr
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+
+	/* Get the cpu_ops reset handler */
+	ldr	x2, [x0, #CPU_RESET_FUNC]
+	mov	x30, x19
+	cbz	x2, 1f
+
+	/* The cpu_ops reset handler can clobber x0 - x19, x30 */
+	br	x2
+1:
+	ret
+endfunc reset_handler
+
+#endif
+
+#ifdef IMAGE_BL31 /* The power down core and cluster is needed only in  BL31 */
+	/*
+	 * void prepare_cpu_pwr_dwn(unsigned int power_level)
+	 *
+	 * Prepare CPU power down function for all platforms. The function takes
+	 * a domain level to be powered down as its parameter. After the cpu_ops
+	 * pointer is retrieved from cpu_data, the handler for requested power
+	 * level is called.
+	 */
+	.globl	prepare_cpu_pwr_dwn
+func prepare_cpu_pwr_dwn
+	/*
+	 * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the
+	 * power down handler for the last power level
+	 */
+	mov_imm	x2, (CPU_MAX_PWR_DWN_OPS - 1)
+	cmp	x0, x2
+	csel	x2, x2, x0, hi
+
+	mrs	x1, tpidr_el3
+	ldr	x0, [x1, #CPU_DATA_CPU_OPS_PTR]
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+
+	/* Get the appropriate power down handler */
+	mov	x1, #CPU_PWR_DWN_OPS
+	add	x1, x1, x2, lsl #3
+	ldr	x1, [x0, x1]
+	br	x1
+endfunc prepare_cpu_pwr_dwn
+
+
+	/*
+	 * Initializes the cpu_ops_ptr if not already initialized
+	 * in cpu_data. This can be called without a runtime stack, but may
+	 * only be called after the MMU is enabled.
+	 * clobbers: x0 - x6, x10
+	 */
+	.globl	init_cpu_ops
+func init_cpu_ops
+	mrs	x6, tpidr_el3
+	ldr	x0, [x6, #CPU_DATA_CPU_OPS_PTR]
+	cbnz	x0, 1f
+	mov	x10, x30
+	bl	get_cpu_ops_ptr
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+	str	x0, [x6, #CPU_DATA_CPU_OPS_PTR]!
+	mov x30, x10
+1:
+	ret
+endfunc init_cpu_ops
+#endif /* IMAGE_BL31 */
+
+#if defined(IMAGE_BL31) && CRASH_REPORTING
+	/*
+	 * The cpu specific registers which need to be reported in a crash
+	 * are reported via cpu_ops cpu_reg_dump function. After a matching
+	 * cpu_ops structure entry is found, the correponding cpu_reg_dump
+	 * in the cpu_ops is invoked.
+	 */
+	.globl	do_cpu_reg_dump
+func do_cpu_reg_dump
+	mov	x16, x30
+
+	/* Get the matching cpu_ops pointer */
+	bl	get_cpu_ops_ptr
+	cbz	x0, 1f
+
+	/* Get the cpu_ops cpu_reg_dump */
+	ldr	x2, [x0, #CPU_REG_DUMP]
+	cbz	x2, 1f
+	blr	x2
+1:
+	mov	x30, x16
+	ret
+endfunc do_cpu_reg_dump
+#endif
+
+	/*
+	 * The below function returns the cpu_ops structure matching the
+	 * midr of the core. It reads the MIDR_EL1 and finds the matching
+	 * entry in cpu_ops entries. Only the implementation and part number
+	 * are used to match the entries.
+	 * Return :
+	 *     x0 - The matching cpu_ops pointer on Success
+	 *     x0 - 0 on failure.
+	 * Clobbers : x0 - x5
+	 */
+	.globl	get_cpu_ops_ptr
+func get_cpu_ops_ptr
+	/* Get the cpu_ops start and end locations */
+	adr	x4, (__CPU_OPS_START__ + CPU_MIDR)
+	adr	x5, (__CPU_OPS_END__ + CPU_MIDR)
+
+	/* Initialize the return parameter */
+	mov	x0, #0
+
+	/* Read the MIDR_EL1 */
+	mrs	x2, midr_el1
+	mov_imm	x3, CPU_IMPL_PN_MASK
+
+	/* Retain only the implementation and part number using mask */
+	and	w2, w2, w3
+1:
+	/* Check if we have reached end of list */
+	cmp	x4, x5
+	b.eq	error_exit
+
+	/* load the midr from the cpu_ops */
+	ldr	x1, [x4], #CPU_OPS_SIZE
+	and	w1, w1, w3
+
+	/* Check if midr matches to midr of this core */
+	cmp	w1, w2
+	b.ne	1b
+
+	/* Subtract the increment and offset to get the cpu-ops pointer */
+	sub	x0, x4, #(CPU_OPS_SIZE + CPU_MIDR)
+error_exit:
+	ret
+endfunc get_cpu_ops_ptr
+
+/*
+ * Extract CPU revision and variant, and combine them into a single numeric for
+ * easier comparison.
+ */
+	.globl	cpu_get_rev_var
+func cpu_get_rev_var
+	mrs	x1, midr_el1
+
+	/*
+	 * Extract the variant[23:20] and revision[3:0] from MIDR, and pack them
+	 * as variant[7:4] and revision[3:0] of x0.
+	 *
+	 * First extract x1[23:16] to x0[7:0] and zero fill the rest. Then
+	 * extract x1[3:0] into x0[3:0] retaining other bits.
+	 */
+	ubfx	x0, x1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
+	bfxil	x0, x1, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+	ret
+endfunc cpu_get_rev_var
+
+/*
+ * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
+ * application purposes. If the revision-variant is less than or same as a given
+ * value, indicates that errata applies; otherwise not.
+ *
+ * Shall clobber: x0-x3
+ */
+	.globl	cpu_rev_var_ls
+func cpu_rev_var_ls
+	mov	x2, #ERRATA_APPLIES
+	mov	x3, #ERRATA_NOT_APPLIES
+	cmp	x0, x1
+	csel	x0, x2, x3, ls
+	ret
+endfunc cpu_rev_var_ls
+
+/*
+ * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
+ * application purposes. If the revision-variant is higher than or same as a
+ * given value, indicates that errata applies; otherwise not.
+ *
+ * Shall clobber: x0-x3
+ */
+	.globl	cpu_rev_var_hs
+func cpu_rev_var_hs
+	mov	x2, #ERRATA_APPLIES
+	mov	x3, #ERRATA_NOT_APPLIES
+	cmp	x0, x1
+	csel	x0, x2, x3, hs
+	ret
+endfunc cpu_rev_var_hs
+
+#if REPORT_ERRATA
+/*
+ * void print_errata_status(void);
+ *
+ * Function to print errata status for CPUs of its class. Must be called only:
+ *
+ *   - with MMU and data caches are enabled;
+ *   - after cpu_ops have been initialized in per-CPU data.
+ */
+	.globl print_errata_status
+func print_errata_status
+#ifdef IMAGE_BL1
+	/*
+	 * BL1 doesn't have per-CPU data. So retrieve the CPU operations
+	 * directly.
+	 */
+	stp	xzr, x30, [sp, #-16]!
+	bl	get_cpu_ops_ptr
+	ldp	xzr, x30, [sp], #16
+	ldr	x1, [x0, #CPU_ERRATA_FUNC]
+	cbnz	x1, .Lprint
+#else
+	/*
+	 * Retrieve pointer to cpu_ops from per-CPU data, and further, the
+	 * errata printing function. If it's non-NULL, jump to the function in
+	 * turn.
+	 */
+	mrs	x0, tpidr_el3
+	ldr	x1, [x0, #CPU_DATA_CPU_OPS_PTR]
+	ldr	x0, [x1, #CPU_ERRATA_FUNC]
+	cbz	x0, .Lnoprint
+
+	/*
+	 * Printing errata status requires atomically testing the printed flag.
+	 */
+	stp	x19, x30, [sp, #-16]!
+	mov	x19, x0
+
+	/*
+	 * Load pointers to errata lock and printed flag. Call
+	 * errata_needs_reporting to check whether this CPU needs to report
+	 * errata status pertaining to its class.
+	 */
+	ldr	x0, [x1, #CPU_ERRATA_LOCK]
+	ldr	x1, [x1, #CPU_ERRATA_PRINTED]
+	bl	errata_needs_reporting
+	mov	x1, x19
+	ldp	x19, x30, [sp], #16
+	cbnz	x0, .Lprint
+#endif
+.Lnoprint:
+	ret
+.Lprint:
+	/* Jump to errata reporting function for this CPU */
+	br	x1
+endfunc print_errata_status
+#endif
+
+/*
+ * int check_wa_cve_2017_5715(void);
+ *
+ * This function returns:
+ *  - ERRATA_APPLIES when firmware mitigation is required.
+ *  - ERRATA_NOT_APPLIES when firmware mitigation is _not_ required.
+ *  - ERRATA_MISSING when firmware mitigation would be required but
+ *    is not compiled in.
+ *
+ * NOTE: Must be called only after cpu_ops have been initialized
+ *       in per-CPU data.
+ */
+	.globl	check_wa_cve_2017_5715
+func check_wa_cve_2017_5715
+	mrs	x0, tpidr_el3
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+	ldr	x0, [x0, #CPU_DATA_CPU_OPS_PTR]
+	ldr	x0, [x0, #CPU_EXTRA1_FUNC]
+	/*
+	 * If the reserved function pointer is NULL, this CPU
+	 * is unaffected by CVE-2017-5715 so bail out.
+	 */
+	cmp	x0, #0
+	beq	1f
+	br	x0
+1:
+	mov	x0, #ERRATA_NOT_APPLIES
+	ret
+endfunc check_wa_cve_2017_5715
+
+/*
+ * void *wa_cve_2018_3639_get_disable_ptr(void);
+ *
+ * Returns a function pointer which is used to disable mitigation
+ * for CVE-2018-3639.
+ * The function pointer is only returned on cores that employ
+ * dynamic mitigation.  If the core uses static mitigation or is
+ * unaffected by CVE-2018-3639 this function returns NULL.
+ *
+ * NOTE: Must be called only after cpu_ops have been initialized
+ *       in per-CPU data.
+ */
+	.globl	wa_cve_2018_3639_get_disable_ptr
+func wa_cve_2018_3639_get_disable_ptr
+	mrs	x0, tpidr_el3
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif
+	ldr	x0, [x0, #CPU_DATA_CPU_OPS_PTR]
+	ldr	x0, [x0, #CPU_EXTRA2_FUNC]
+	ret
+endfunc wa_cve_2018_3639_get_disable_ptr
diff --git a/lib/cpus/aarch64/cpuamu.c b/lib/cpus/aarch64/cpuamu.c
new file mode 100644
index 0000000..3a2fa81
--- /dev/null
+++ b/lib/cpus/aarch64/cpuamu.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cpuamu.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <plat/common/platform.h>
+
+#define CPUAMU_NR_COUNTERS	5U
+
+struct cpuamu_ctx {
+	uint64_t cnts[CPUAMU_NR_COUNTERS];
+	unsigned int mask;
+};
+
+static struct cpuamu_ctx cpuamu_ctxs[PLATFORM_CORE_COUNT];
+
+int midr_match(unsigned int cpu_midr)
+{
+	unsigned int midr, midr_mask;
+
+	midr = (unsigned int)read_midr();
+	midr_mask = (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) |
+		(MIDR_PN_MASK << MIDR_PN_SHIFT);
+	return ((midr & midr_mask) == (cpu_midr & midr_mask));
+}
+
+void cpuamu_context_save(unsigned int nr_counters)
+{
+	struct cpuamu_ctx *ctx = &cpuamu_ctxs[plat_my_core_pos()];
+	unsigned int i;
+
+	assert(nr_counters <= CPUAMU_NR_COUNTERS);
+
+	/* Save counter configuration */
+	ctx->mask = cpuamu_read_cpuamcntenset_el0();
+
+	/* Disable counters */
+	cpuamu_write_cpuamcntenclr_el0(ctx->mask);
+	isb();
+
+	/* Save counters */
+	for (i = 0; i < nr_counters; i++)
+		ctx->cnts[i] = cpuamu_cnt_read(i);
+}
+
+void cpuamu_context_restore(unsigned int nr_counters)
+{
+	struct cpuamu_ctx *ctx = &cpuamu_ctxs[plat_my_core_pos()];
+	unsigned int i;
+
+	assert(nr_counters <= CPUAMU_NR_COUNTERS);
+
+	/*
+	 * Disable counters.  They were enabled early in the
+	 * CPU reset function.
+	 */
+	cpuamu_write_cpuamcntenclr_el0(ctx->mask);
+	isb();
+
+	/* Restore counters */
+	for (i = 0; i < nr_counters; i++)
+		cpuamu_cnt_write(i, ctx->cnts[i]);
+	isb();
+
+	/* Restore counter configuration */
+	cpuamu_write_cpuamcntenset_el0(ctx->mask);
+}
diff --git a/lib/cpus/aarch64/cpuamu_helpers.S b/lib/cpus/aarch64/cpuamu_helpers.S
new file mode 100644
index 0000000..5a77fc7
--- /dev/null
+++ b/lib/cpus/aarch64/cpuamu_helpers.S
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpuamu.h>
+
+	.globl	cpuamu_cnt_read
+	.globl	cpuamu_cnt_write
+	.globl	cpuamu_read_cpuamcntenset_el0
+	.globl	cpuamu_read_cpuamcntenclr_el0
+	.globl	cpuamu_write_cpuamcntenset_el0
+	.globl	cpuamu_write_cpuamcntenclr_el0
+
+/*
+ * uint64_t cpuamu_cnt_read(unsigned int idx);
+ *
+ * Given `idx`, read the corresponding AMU counter
+ * and return it in `x0`.
+ */
+func cpuamu_cnt_read
+	adr	x1, 1f
+	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x1
+
+1:	read	CPUAMEVCNTR0_EL0
+	read	CPUAMEVCNTR1_EL0
+	read	CPUAMEVCNTR2_EL0
+	read	CPUAMEVCNTR3_EL0
+	read	CPUAMEVCNTR4_EL0
+endfunc cpuamu_cnt_read
+
+/*
+ * void cpuamu_cnt_write(unsigned int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU counter.
+ */
+func cpuamu_cnt_write
+	adr	x2, 1f
+	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x2
+
+1:	write	CPUAMEVCNTR0_EL0
+	write	CPUAMEVCNTR1_EL0
+	write	CPUAMEVCNTR2_EL0
+	write	CPUAMEVCNTR3_EL0
+	write	CPUAMEVCNTR4_EL0
+endfunc cpuamu_cnt_write
+
+/*
+ * unsigned int cpuamu_read_cpuamcntenset_el0(void);
+ *
+ * Read the `CPUAMCNTENSET_EL0` CPU register and return
+ * it in `x0`.
+ */
+func cpuamu_read_cpuamcntenset_el0
+	mrs	x0, CPUAMCNTENSET_EL0
+	ret
+endfunc cpuamu_read_cpuamcntenset_el0
+
+/*
+ * unsigned int cpuamu_read_cpuamcntenclr_el0(void);
+ *
+ * Read the `CPUAMCNTENCLR_EL0` CPU register and return
+ * it in `x0`.
+ */
+func cpuamu_read_cpuamcntenclr_el0
+	mrs	x0, CPUAMCNTENCLR_EL0
+	ret
+endfunc cpuamu_read_cpuamcntenclr_el0
+
+/*
+ * void cpuamu_write_cpuamcntenset_el0(unsigned int mask);
+ *
+ * Write `mask` to the `CPUAMCNTENSET_EL0` CPU register.
+ */
+func cpuamu_write_cpuamcntenset_el0
+	msr	CPUAMCNTENSET_EL0, x0
+	ret
+endfunc cpuamu_write_cpuamcntenset_el0
+
+/*
+ * void cpuamu_write_cpuamcntenclr_el0(unsigned int mask);
+ *
+ * Write `mask` to the `CPUAMCNTENCLR_EL0` CPU register.
+ */
+func cpuamu_write_cpuamcntenclr_el0
+	msr	CPUAMCNTENCLR_EL0, x0
+	ret
+endfunc cpuamu_write_cpuamcntenclr_el0
diff --git a/lib/cpus/aarch64/denver.S b/lib/cpus/aarch64/denver.S
new file mode 100644
index 0000000..c377b28
--- /dev/null
+++ b/lib/cpus/aarch64/denver.S
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <context.h>
+#include <denver.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+	/* -------------------------------------------------
+	 * CVE-2017-5715 mitigation
+	 *
+	 * Flush the indirect branch predictor and RSB on
+	 * entry to EL3 by issuing a newly added instruction
+	 * for Denver CPUs.
+	 *
+	 * To achieve this without performing any branch
+	 * instruction, a per-cpu vbar is installed which
+	 * executes the workaround and then branches off to
+	 * the corresponding vector entry in the main vector
+	 * table.
+	 * -------------------------------------------------
+	 */
+	.globl	workaround_bpflush_runtime_exceptions
+
+vector_base workaround_bpflush_runtime_exceptions
+
+	.macro	apply_workaround
+	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+
+	/* -------------------------------------------------
+	 * A new write-only system register where a write of
+	 * 1 to bit 0 will cause the indirect branch predictor
+	 * and RSB to be flushed.
+	 *
+	 * A write of 0 to bit 0 will be ignored. A write of
+	 * 1 to any other bit will cause an MCA.
+	 * -------------------------------------------------
+	 */
+	mov	x0, #1
+	msr	s3_0_c15_c0_6, x0
+	isb
+
+	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	.endm
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_EL0 : 0x0 - 0x200
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry workaround_bpflush_sync_exception_sp_el0
+	b	sync_exception_sp_el0
+end_vector_entry workaround_bpflush_sync_exception_sp_el0
+
+vector_entry workaround_bpflush_irq_sp_el0
+	b	irq_sp_el0
+end_vector_entry workaround_bpflush_irq_sp_el0
+
+vector_entry workaround_bpflush_fiq_sp_el0
+	b	fiq_sp_el0
+end_vector_entry workaround_bpflush_fiq_sp_el0
+
+vector_entry workaround_bpflush_serror_sp_el0
+	b	serror_sp_el0
+end_vector_entry workaround_bpflush_serror_sp_el0
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_ELx: 0x200 - 0x400
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry workaround_bpflush_sync_exception_sp_elx
+	b	sync_exception_sp_elx
+end_vector_entry workaround_bpflush_sync_exception_sp_elx
+
+vector_entry workaround_bpflush_irq_sp_elx
+	b	irq_sp_elx
+end_vector_entry workaround_bpflush_irq_sp_elx
+
+vector_entry workaround_bpflush_fiq_sp_elx
+	b	fiq_sp_elx
+end_vector_entry workaround_bpflush_fiq_sp_elx
+
+vector_entry workaround_bpflush_serror_sp_elx
+	b	serror_sp_elx
+end_vector_entry workaround_bpflush_serror_sp_elx
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry workaround_bpflush_sync_exception_aarch64
+	apply_workaround
+	b	sync_exception_aarch64
+end_vector_entry workaround_bpflush_sync_exception_aarch64
+
+vector_entry workaround_bpflush_irq_aarch64
+	apply_workaround
+	b	irq_aarch64
+end_vector_entry workaround_bpflush_irq_aarch64
+
+vector_entry workaround_bpflush_fiq_aarch64
+	apply_workaround
+	b	fiq_aarch64
+end_vector_entry workaround_bpflush_fiq_aarch64
+
+vector_entry workaround_bpflush_serror_aarch64
+	apply_workaround
+	b	serror_aarch64
+end_vector_entry workaround_bpflush_serror_aarch64
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry workaround_bpflush_sync_exception_aarch32
+	apply_workaround
+	b	sync_exception_aarch32
+end_vector_entry workaround_bpflush_sync_exception_aarch32
+
+vector_entry workaround_bpflush_irq_aarch32
+	apply_workaround
+	b	irq_aarch32
+end_vector_entry workaround_bpflush_irq_aarch32
+
+vector_entry workaround_bpflush_fiq_aarch32
+	apply_workaround
+	b	fiq_aarch32
+end_vector_entry workaround_bpflush_fiq_aarch32
+
+vector_entry workaround_bpflush_serror_aarch32
+	apply_workaround
+	b	serror_aarch32
+end_vector_entry workaround_bpflush_serror_aarch32
+
+	.global	denver_disable_dco
+
+	/* ---------------------------------------------
+	 * Disable debug interfaces
+	 * ---------------------------------------------
+	 */
+func denver_disable_ext_debug
+	mov	x0, #1
+	msr	osdlr_el1, x0
+	isb
+	dsb	sy
+	ret
+endfunc denver_disable_ext_debug
+
+	/* ----------------------------------------------------
+	 * Enable dynamic code optimizer (DCO)
+	 * ----------------------------------------------------
+	 */
+func denver_enable_dco
+	mov	x3, x30
+	bl	plat_my_core_pos
+	mov	x1, #1
+	lsl	x1, x1, x0
+	msr	s3_0_c15_c0_2, x1
+	mov	x30, x3
+	ret
+endfunc denver_enable_dco
+
+	/* ----------------------------------------------------
+	 * Disable dynamic code optimizer (DCO)
+	 * ----------------------------------------------------
+	 */
+func denver_disable_dco
+
+	mov	x3, x30
+
+	/* turn off background work */
+	bl	plat_my_core_pos
+	mov	x1, #1
+	lsl	x1, x1, x0
+	lsl	x2, x1, #16
+	msr	s3_0_c15_c0_2, x2
+	isb
+
+	/* wait till the background work turns off */
+1:	mrs	x2, s3_0_c15_c0_2
+	lsr	x2, x2, #32
+	and	w2, w2, 0xFFFF
+	and	x2, x2, x1
+	cbnz	x2, 1b
+
+	mov	x30, x3
+	ret
+endfunc denver_disable_dco
+
+func check_errata_cve_2017_5715
+	mov	x0, #ERRATA_MISSING
+#if WORKAROUND_CVE_2017_5715
+	/*
+	 * Check if the CPU supports the special instruction
+	 * required to flush the indirect branch predictor and
+	 * RSB. Support for this operation can be determined by
+	 * comparing bits 19:16 of ID_AFR0_EL1 with 0b0001.
+	 */
+	mrs	x1, id_afr0_el1
+	mov	x2, #0x10000
+	and	x1, x1, x2
+	cbz	x1, 1f
+	mov	x0, #ERRATA_APPLIES
+1:
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
+func check_errata_cve_2018_3639
+#if WORKAROUND_CVE_2018_3639
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2018_3639
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Denver.
+	 * -------------------------------------------------
+	 */
+func denver_reset_func
+
+	mov	x19, x30
+
+#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
+	/*
+	 * Check if the CPU supports the special instruction
+	 * required to flush the indirect branch predictor and
+	 * RSB. Support for this operation can be determined by
+	 * comparing bits 19:16 of ID_AFR0_EL1 with 0b0001.
+	 */
+	mrs	x0, id_afr0_el1
+	mov	x1, #0x10000
+	and	x0, x0, x1
+	cmp	x0, #0
+	adr	x1, workaround_bpflush_runtime_exceptions
+	mrs	x2, vbar_el3
+	csel	x0, x1, x2, ne
+	msr	vbar_el3, x0
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	/*
+	 * Denver CPUs with DENVER_MIDR_PN3 or earlier, use different
+	 * bits in the ACTLR_EL3 register to disable speculative
+	 * store buffer and memory disambiguation.
+	 */
+	mrs	x0, midr_el1
+	mov_imm	x1, DENVER_MIDR_PN4
+	cmp	x0, x1
+	mrs	x0, actlr_el3
+	mov	x1, #(DENVER_CPU_DIS_MD_EL3 | DENVER_CPU_DIS_SSB_EL3)
+	mov	x2, #(DENVER_PN4_CPU_DIS_MD_EL3 | DENVER_PN4_CPU_DIS_SSB_EL3)
+	csel	x3, x1, x2, ne
+	orr	x0, x0, x3
+	msr	actlr_el3, x0
+	isb
+	dsb	sy
+#endif
+
+	/* ----------------------------------------------------
+	 * Reset ACTLR.PMSTATE to C1 state
+	 * ----------------------------------------------------
+	 */
+	mrs	x0, actlr_el1
+	bic	x0, x0, #DENVER_CPU_PMSTATE_MASK
+	orr	x0, x0, #DENVER_CPU_PMSTATE_C1
+	msr	actlr_el1, x0
+
+	/* ----------------------------------------------------
+	 * Enable dynamic code optimizer (DCO)
+	 * ----------------------------------------------------
+	 */
+	bl	denver_enable_dco
+
+	ret	x19
+endfunc denver_reset_func
+
+	/* ----------------------------------------------------
+	 * The CPU Ops core power down function for Denver.
+	 * ----------------------------------------------------
+	 */
+func denver_core_pwr_dwn
+
+	mov	x19, x30
+
+	/* ---------------------------------------------
+	 * Force the debug interfaces to be quiescent
+	 * ---------------------------------------------
+	 */
+	bl	denver_disable_ext_debug
+
+	ret	x19
+endfunc denver_core_pwr_dwn
+
+	/* -------------------------------------------------------
+	 * The CPU Ops cluster power down function for Denver.
+	 * -------------------------------------------------------
+	 */
+func denver_cluster_pwr_dwn
+	ret
+endfunc denver_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+	/*
+	 * Errata printing function for Denver. Must follow AAPCS.
+	 */
+func denver_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, denver, cve_2017_5715
+	report_errata WORKAROUND_CVE_2018_3639, denver, cve_2018_3639
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc denver_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides Denver specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.denver_regs, "aS"
+denver_regs:  /* The ascii list of register names to be reported */
+	.asciz	"actlr_el1", ""
+
+func denver_cpu_reg_dump
+	adr	x6, denver_regs
+	mrs	x8, ACTLR_EL1
+	ret
+endfunc denver_cpu_reg_dump
+
+declare_cpu_ops_wa denver, DENVER_MIDR_PN0, \
+	denver_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops_wa denver, DENVER_MIDR_PN1, \
+	denver_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops_wa denver, DENVER_MIDR_PN2, \
+	denver_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops_wa denver, DENVER_MIDR_PN3, \
+	denver_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops_wa denver, DENVER_MIDR_PN4, \
+	denver_reset_func, \
+	check_errata_cve_2017_5715, \
+	CPU_NO_EXTRA2_FUNC, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
new file mode 100644
index 0000000..100ffaa
--- /dev/null
+++ b/lib/cpus/aarch64/dsu_helpers.S
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <dsu_def.h>
+#include <lib/cpus/errata_report.h>
+
+	/* -----------------------------------------------------------------------
+	 * DSU erratum 798953 check function
+	 * Checks the DSU variant, revision and configuration to determine if
+	 * the erratum applies. Erratum applies on all configurations of the
+	 * DSU and if revision-variant is r0p0.
+	 *
+	 * The erratum was fixed in r0p1.
+	 *
+	 * This function is called from both assembly and C environment. So it
+	 * follows AAPCS.
+	 *
+	 * Clobbers: x0-x3
+	 * -----------------------------------------------------------------------
+	 */
+	.globl	check_errata_dsu_798953
+	.globl	errata_dsu_798953_wa
+
+func check_errata_dsu_798953
+	mov	x2, #ERRATA_APPLIES
+	mov	x3, #ERRATA_NOT_APPLIES
+
+	/* Check if DSU is equal to r0p0 */
+	mrs	x1, CLUSTERIDR_EL1
+
+	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
+	ubfx	x0, x1, #CLUSTERIDR_REV_SHIFT,\
+			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
+	mov	x1, #(0x0 << CLUSTERIDR_REV_SHIFT)
+	cmp	x0, x1
+	csel	x0, x2, x3, EQ
+	ret
+endfunc check_errata_dsu_798953
+
+	/* --------------------------------------------------
+	 * Errata Workaround for DSU erratum #798953.
+	 *
+	 * Can clobber only: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_dsu_798953_wa
+	mov	x17, x30
+	bl	check_errata_dsu_798953
+	cbz	x0, 1f
+
+	/* If erratum applies, disable high-level clock gating */
+	mrs	x0, CLUSTERACTLR_EL1
+	orr	x0, x0, #CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING
+	msr	CLUSTERACTLR_EL1, x0
+	isb
+1:
+	ret	x17
+endfunc errata_dsu_798953_wa
+
+	/* -----------------------------------------------------------------------
+	 * DSU erratum 936184 check function
+	 * Checks the DSU variant, revision and configuration to determine if
+	 * the erratum applies. Erratum applies if ACP interface is present
+	 * in the DSU and revision-variant < r2p0.
+	 *
+	 * The erratum was fixed in r2p0.
+	 *
+	 * This function is called from both assembly and C environment. So it
+	 * follows AAPCS.
+	 *
+	 * Clobbers: x0-x3
+	 * -----------------------------------------------------------------------
+	 */
+	.globl	check_errata_dsu_936184
+	.globl	errata_dsu_936184_wa
+
+func check_errata_dsu_936184
+	mov	x2, #ERRATA_NOT_APPLIES
+	mov	x3, #ERRATA_APPLIES
+
+	/* Erratum applies only if DSU has the ACP interface */
+	mov	x0, x2
+	mrs	x1, CLUSTERCFR_EL1
+	ubfx	x1, x1, #CLUSTERCFR_ACP_SHIFT, #1
+	cbz	x1, 1f
+
+	/* If ACP is present, check if DSU is older than r2p0 */
+	mrs	x1, CLUSTERIDR_EL1
+
+	/* DSU variant and revision bitfields in CLUSTERIDR are adjacent */
+	ubfx	x0, x1, #CLUSTERIDR_REV_SHIFT,\
+			#(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS)
+	mov	x1, #(0x2 << CLUSTERIDR_VAR_SHIFT)
+	cmp	x0, x1
+	csel	x0, x2, x3, hs
+1:
+	ret
+endfunc check_errata_dsu_936184
+
+	/* --------------------------------------------------
+	 * Errata Workaround for DSU erratum #936184.
+	 *
+	 * Can clobber only: x0-x17
+	 * --------------------------------------------------
+	 */
+func errata_dsu_936184_wa
+	mov	x17, x30
+	bl	check_errata_dsu_936184
+	cbz	x0, 1f
+
+	/* If erratum applies, we set a mask to a DSU control register */
+	mrs	x0, CLUSTERACTLR_EL1
+	ldr	x1, =DSU_ERRATA_936184_MASK
+	orr	x0, x0, x1
+	msr	CLUSTERACTLR_EL1, x0
+	isb
+1:
+	ret	x17
+endfunc errata_dsu_936184_wa
diff --git a/lib/cpus/aarch64/neoverse_e1.S b/lib/cpus/aarch64/neoverse_e1.S
new file mode 100644
index 0000000..96b63cf
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_e1.S
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <neoverse_e1.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse E1 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse-E1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+	/* -------------------------------------------------
+	 * The CPU Ops reset function for Neoverse-E1.
+	 * Shall clobber: x0-x19
+	 * -------------------------------------------------
+	 */
+func neoverse_e1_reset_func
+	mov	x19, x30
+
+#if ERRATA_DSU_936184
+	bl	errata_dsu_936184_wa
+#endif
+
+	ret	x19
+endfunc neoverse_e1_reset_func
+
+func neoverse_e1_cpu_pwr_dwn
+	mrs	x0, NEOVERSE_E1_CPUPWRCTLR_EL1
+	orr	x0, x0, #NEOVERSE_E1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	NEOVERSE_E1_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc neoverse_e1_cpu_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Neoverse N1. Must follow AAPCS.
+ */
+func neoverse_e1_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_DSU_936184, neoverse_e1, dsu_936184
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc neoverse_e1_errata_report
+#endif
+
+
+.section .rodata.neoverse_e1_regs, "aS"
+neoverse_e1_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func neoverse_e1_cpu_reg_dump
+	adr	x6, neoverse_e1_regs
+	mrs	x8, NEOVERSE_E1_ECTLR_EL1
+	ret
+endfunc neoverse_e1_cpu_reg_dump
+
+declare_cpu_ops neoverse_e1, NEOVERSE_E1_MIDR, \
+	neoverse_e1_reset_func, \
+	neoverse_e1_cpu_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_n1.S b/lib/cpus/aarch64/neoverse_n1.S
new file mode 100644
index 0000000..b143a2e
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_n1.S
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <neoverse_n1.h>
+#include <cpuamu.h>
+#include <cpu_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse N1 must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse-N1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Erratum 1043202.
+ * This applies to revision r0p0 and r1p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1043202_wa
+	/* Compare x0 against revision r1p0 */
+	mov	x17, x30
+	bl	check_errata_1043202
+	cbz	x0, 1f
+
+	/* Apply instruction patching sequence */
+	ldr	x0, =0x0
+	msr	CPUPSELR_EL3, x0
+	ldr	x0, =0xF3BF8F2F
+	msr	CPUPOR_EL3, x0
+	ldr	x0, =0xFFFFFFFF
+	msr	CPUPMR_EL3, x0
+	ldr	x0, =0x800200071
+	msr	CPUPCR_EL3, x0
+1:
+	ret	x17
+endfunc errata_n1_1043202_wa
+
+func check_errata_1043202
+	/* Applies to r0p0 and r1p0 */
+	mov	x1, #0x10
+	b	cpu_rev_var_ls
+endfunc check_errata_1043202
+
+/* --------------------------------------------------
+ * Disable speculative loads if Neoverse N1 supports
+ * SSBS.
+ *
+ * Shall clobber: x0.
+ * --------------------------------------------------
+ */
+func neoverse_n1_disable_speculative_loads
+	/* Check if the PE implements SSBS */
+	mrs	x0, id_aa64pfr1_el1
+	tst	x0, #(ID_AA64PFR1_EL1_SSBS_MASK << ID_AA64PFR1_EL1_SSBS_SHIFT)
+	b.eq	1f
+
+	/* Disable speculative loads */
+	msr	SSBS, xzr
+
+1:
+	ret
+endfunc neoverse_n1_disable_speculative_loads
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1073348
+ * This applies to revision r0p0 and r1p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1073348_wa
+	/* Compare x0 against revision r1p0 */
+	mov	x17, x30
+	bl	check_errata_1073348
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_6
+	msr	NEOVERSE_N1_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1073348_wa
+
+func check_errata_1073348
+	/* Applies to r0p0 and r1p0 */
+	mov	x1, #0x10
+	b	cpu_rev_var_ls
+endfunc check_errata_1073348
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1130799
+ * This applies to revision <=r2p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1130799_wa
+	/* Compare x0 against revision r2p0 */
+	mov	x17, x30
+	bl	check_errata_1130799
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR2_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_59
+	msr	NEOVERSE_N1_CPUACTLR2_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1130799_wa
+
+func check_errata_1130799
+	/* Applies to <=r2p0 */
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_1130799
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1165347
+ * This applies to revision <=r2p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1165347_wa
+	/* Compare x0 against revision r2p0 */
+	mov	x17, x30
+	bl	check_errata_1165347
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR2_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_0
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_15
+	msr	NEOVERSE_N1_CPUACTLR2_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1165347_wa
+
+func check_errata_1165347
+	/* Applies to <=r2p0 */
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_1165347
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1207823
+ * This applies to revision <=r2p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1207823_wa
+	/* Compare x0 against revision r2p0 */
+	mov	x17, x30
+	bl	check_errata_1207823
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR2_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_11
+	msr	NEOVERSE_N1_CPUACTLR2_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1207823_wa
+
+func check_errata_1207823
+	/* Applies to <=r2p0 */
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_1207823
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1220197
+ * This applies to revision <=r2p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1220197_wa
+	/* Compare x0 against revision r2p0 */
+	mov	x17, x30
+	bl	check_errata_1220197
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUECTLR_EL1
+	orr	x1, x1, NEOVERSE_N1_WS_THR_L2_MASK
+	msr	NEOVERSE_N1_CPUECTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1220197_wa
+
+func check_errata_1220197
+	/* Applies to <=r2p0 */
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_1220197
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1257314
+ * This applies to revision <=r3p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1257314_wa
+	/* Compare x0 against revision r3p0 */
+	mov	x17, x30
+	bl	check_errata_1257314
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR3_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR3_EL1_BIT_10
+	msr	NEOVERSE_N1_CPUACTLR3_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1257314_wa
+
+func check_errata_1257314
+	/* Applies to <=r3p0 */
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1257314
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1262606
+ * This applies to revision <=r3p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1262606_wa
+	/* Compare x0 against revision r3p0 */
+	mov	x17, x30
+	bl	check_errata_1262606
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_13
+	msr	NEOVERSE_N1_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1262606_wa
+
+func check_errata_1262606
+	/* Applies to <=r3p0 */
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1262606
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1262888
+ * This applies to revision <=r3p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1262888_wa
+	/* Compare x0 against revision r3p0 */
+	mov	x17, x30
+	bl	check_errata_1262888
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUECTLR_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUECTLR_EL1_MM_TLBPF_DIS_BIT
+	msr	NEOVERSE_N1_CPUECTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1262888_wa
+
+func check_errata_1262888
+	/* Applies to <=r3p0 */
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1262888
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Errata #1275112
+ * This applies to revision <=r3p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1275112_wa
+	/* Compare x0 against revision r3p0 */
+	mov	x17, x30
+	bl	check_errata_1275112
+	cbz	x0, 1f
+	mrs	x1, NEOVERSE_N1_CPUACTLR_EL1
+	orr	x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_13
+	msr	NEOVERSE_N1_CPUACTLR_EL1, x1
+1:
+	ret	x17
+endfunc errata_n1_1275112_wa
+
+func check_errata_1275112
+	/* Applies to <=r3p0 */
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1275112
+
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N1 Erratum 1315703.
+ * This applies to revision <= r3p0 of Neoverse N1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_n1_1315703_wa
+	/* Compare x0 against revision r3p1 */
+	mov	x17, x30
+	bl	check_errata_1315703
+	cbz	x0, 1f
+
+	mrs	x0, NEOVERSE_N1_CPUACTLR2_EL1
+	orr	x0, x0, #NEOVERSE_N1_CPUACTLR2_EL1_BIT_16
+	msr	NEOVERSE_N1_CPUACTLR2_EL1, x0
+
+1:
+	ret	x17
+endfunc errata_n1_1315703_wa
+
+func check_errata_1315703
+	/* Applies to everything <= r3p0. */
+	mov	x1, #0x30
+	b	cpu_rev_var_ls
+endfunc check_errata_1315703
+
+func neoverse_n1_reset_func
+	mov	x19, x30
+
+	bl neoverse_n1_disable_speculative_loads
+
+	/* Forces all cacheable atomic instructions to be near */
+	mrs	x0, NEOVERSE_N1_CPUACTLR2_EL1
+	orr	x0, x0, #NEOVERSE_N1_CPUACTLR2_EL1_BIT_2
+	msr	NEOVERSE_N1_CPUACTLR2_EL1, x0
+	isb
+
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_N1_1043202
+	mov	x0, x18
+	bl	errata_n1_1043202_wa
+#endif
+
+#if ERRATA_N1_1073348
+	mov	x0, x18
+	bl	errata_n1_1073348_wa
+#endif
+
+#if ERRATA_N1_1130799
+	mov	x0, x18
+	bl	errata_n1_1130799_wa
+#endif
+
+#if ERRATA_N1_1165347
+	mov	x0, x18
+	bl	errata_n1_1165347_wa
+#endif
+
+#if ERRATA_N1_1207823
+	mov	x0, x18
+	bl	errata_n1_1207823_wa
+#endif
+
+#if ERRATA_N1_1220197
+	mov	x0, x18
+	bl	errata_n1_1220197_wa
+#endif
+
+#if ERRATA_N1_1257314
+	mov	x0, x18
+	bl	errata_n1_1257314_wa
+#endif
+
+#if ERRATA_N1_1262606
+	mov	x0, x18
+	bl	errata_n1_1262606_wa
+#endif
+
+#if ERRATA_N1_1262888
+	mov	x0, x18
+	bl	errata_n1_1262888_wa
+#endif
+
+#if ERRATA_N1_1275112
+	mov	x0, x18
+	bl	errata_n1_1275112_wa
+#endif
+
+#if ERRATA_N1_1315703
+	mov	x0, x18
+	bl	errata_n1_1315703_wa
+#endif
+
+#if ENABLE_AMU
+	/* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
+	mrs	x0, actlr_el3
+	orr	x0, x0, #NEOVERSE_N1_ACTLR_AMEN_BIT
+	msr	actlr_el3, x0
+
+	/* Make sure accesses from EL0/EL1 are not trapped to EL2 */
+	mrs	x0, actlr_el2
+	orr	x0, x0, #NEOVERSE_N1_ACTLR_AMEN_BIT
+	msr	actlr_el2, x0
+
+	/* Enable group0 counters */
+	mov	x0, #NEOVERSE_N1_AMU_GROUP0_MASK
+	msr	CPUAMCNTENSET_EL0, x0
+#endif
+
+#if ERRATA_DSU_936184
+	bl	errata_dsu_936184_wa
+#endif
+
+	isb
+	ret	x19
+endfunc neoverse_n1_reset_func
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func neoverse_n1_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, NEOVERSE_N1_CPUPWRCTLR_EL1
+	orr	x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK
+	msr	NEOVERSE_N1_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc neoverse_n1_core_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Neoverse N1. Must follow AAPCS.
+ */
+func neoverse_n1_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_N1_1043202, neoverse_n1, 1043202
+	report_errata ERRATA_N1_1073348, neoverse_n1, 1073348
+	report_errata ERRATA_N1_1130799, neoverse_n1, 1130799
+	report_errata ERRATA_N1_1165347, neoverse_n1, 1165347
+	report_errata ERRATA_N1_1207823, neoverse_n1, 1207823
+	report_errata ERRATA_N1_1220197, neoverse_n1, 1220197
+	report_errata ERRATA_N1_1257314, neoverse_n1, 1257314
+	report_errata ERRATA_N1_1262606, neoverse_n1, 1262606
+	report_errata ERRATA_N1_1262888, neoverse_n1, 1262888
+	report_errata ERRATA_N1_1275112, neoverse_n1, 1275112
+	report_errata ERRATA_N1_1315703, neoverse_n1, 1315703
+	report_errata ERRATA_DSU_936184, neoverse_n1, dsu_936184
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc neoverse_n1_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides neoverse_n1 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.neoverse_n1_regs, "aS"
+neoverse_n1_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func neoverse_n1_cpu_reg_dump
+	adr	x6, neoverse_n1_regs
+	mrs	x8, NEOVERSE_N1_CPUECTLR_EL1
+	ret
+endfunc neoverse_n1_cpu_reg_dump
+
+declare_cpu_ops neoverse_n1, NEOVERSE_N1_MIDR, \
+	neoverse_n1_reset_func, \
+	neoverse_n1_core_pwr_dwn
diff --git a/lib/cpus/aarch64/neoverse_n1_pubsub.c b/lib/cpus/aarch64/neoverse_n1_pubsub.c
new file mode 100644
index 0000000..b1b7bb8
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_n1_pubsub.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <neoverse_n1.h>
+#include <cpuamu.h>
+#include <lib/el3_runtime/pubsub_events.h>
+
+static void *neoverse_n1_context_save(const void *arg)
+{
+	if (midr_match(NEOVERSE_N1_MIDR) != 0)
+		cpuamu_context_save(NEOVERSE_N1_AMU_NR_COUNTERS);
+
+	return (void *)0;
+}
+
+static void *neoverse_n1_context_restore(const void *arg)
+{
+	if (midr_match(NEOVERSE_N1_MIDR) != 0)
+		cpuamu_context_restore(NEOVERSE_N1_AMU_NR_COUNTERS);
+
+	return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, neoverse_n1_context_save);
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, neoverse_n1_context_restore);
diff --git a/lib/cpus/aarch64/neoverse_zeus.S b/lib/cpus/aarch64/neoverse_zeus.S
new file mode 100644
index 0000000..3d85013
--- /dev/null
+++ b/lib/cpus/aarch64/neoverse_zeus.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <neoverse_zeus.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+/* Hardware handled coherency */
+#if HW_ASSISTED_COHERENCY == 0
+#error "Neoverse Zeus must be compiled with HW_ASSISTED_COHERENCY enabled"
+#endif
+
+/* 64-bit only core */
+#if CTX_INCLUDE_AARCH32_REGS == 1
+#error "Neoverse-Zeus supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
+#endif
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func neoverse_zeus_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, NEOVERSE_ZEUS_CPUPWRCTLR_EL1
+	orr	x0, x0, #NEOVERSE_ZEUS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
+	msr	NEOVERSE_ZEUS_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc neoverse_zeus_core_pwr_dwn
+
+	/*
+	 * Errata printing function for Neoverse Zeus. Must follow AAPCS.
+	 */
+#if REPORT_ERRATA
+func neoverse_zeus_errata_report
+	ret
+endfunc neoverse_zeus_errata_report
+#endif
+
+	/* ---------------------------------------------
+	 * This function provides Neoverse-Zeus specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.neoverse_zeus_regs, "aS"
+neoverse_zeus_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func neoverse_zeus_cpu_reg_dump
+	adr	x6, neoverse_zeus_regs
+	mrs	x8, NEOVERSE_ZEUS_CPUECTLR_EL1
+	ret
+endfunc neoverse_zeus_cpu_reg_dump
+
+declare_cpu_ops neoverse_zeus, NEOVERSE_ZEUS_MIDR, \
+	CPU_NO_RESET_FUNC, \
+	neoverse_zeus_core_pwr_dwn
diff --git a/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S b/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S
new file mode 100644
index 0000000..c9a9544
--- /dev/null
+++ b/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <services/arm_arch_svc.h>
+
+	.globl	wa_cve_2017_5715_bpiall_vbar
+
+#define EMIT_BPIALL		0xee070fd5
+#define EMIT_SMC		0xe1600070
+#define ESR_EL3_A64_SMC0	0x5e000000
+
+	.macro	apply_cve_2017_5715_wa _from_vector
+	/*
+	 * Save register state to enable a call to AArch32 S-EL1 and return
+	 * Identify the original calling vector in w2 (==_from_vector)
+	 * Use w3-w6 for additional register state preservation while in S-EL1
+	 */
+
+	/* Save GP regs */
+	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	stp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	stp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
+	stp	x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6]
+	stp	x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8]
+	stp	x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10]
+	stp	x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12]
+	stp	x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14]
+	stp	x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16]
+	stp	x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18]
+	stp	x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20]
+	stp	x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22]
+	stp	x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24]
+	stp	x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26]
+	stp	x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+
+	/* Identify the original exception vector */
+	mov	w2, \_from_vector
+
+	/* Preserve 32-bit system registers in GP registers through the workaround */
+	mrs	x3, esr_el3
+	mrs	x4, spsr_el3
+	mrs	x5, scr_el3
+	mrs	x6, sctlr_el1
+
+	/*
+	 * Preserve LR and ELR_EL3 registers in the GP regs context.
+	 * Temporarily use the CTX_GPREG_SP_EL0 slot to preserve ELR_EL3
+	 * through the workaround. This is OK because at this point the
+	 * current state for this context's SP_EL0 is in the live system
+	 * register, which is unmodified by the workaround.
+	 */
+	mrs	x7, elr_el3
+	stp	x30, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	/*
+	 * Load system registers for entry to S-EL1.
+	 */
+
+	/* Mask all interrupts and set AArch32 Supervisor mode */
+	movz	w8, SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, SPSR_AIF_MASK)
+
+	/* Switch EL3 exception vectors while the workaround is executing. */
+	adr	x9, wa_cve_2017_5715_bpiall_ret_vbar
+
+	/* Setup SCTLR_EL1 with MMU off and I$ on */
+	ldr	x10, stub_sel1_sctlr
+
+	/* Land at the S-EL1 workaround stub */
+	adr	x11, aarch32_stub
+
+	/*
+	 * Setting SCR_EL3 to all zeroes means that the NS, RW
+	 * and SMD bits are configured as expected.
+	 */
+	msr	scr_el3, xzr
+	msr	spsr_el3, x8
+	msr	vbar_el3, x9
+	msr	sctlr_el1, x10
+	msr	elr_el3, x11
+
+	eret
+	.endm
+
+	/* ---------------------------------------------------------------------
+	 * This vector table is used at runtime to enter the workaround at
+	 * AArch32 S-EL1 for Sync/IRQ/FIQ/SError exceptions.  If the workaround
+	 * is not enabled, the existing runtime exception vector table is used.
+	 * ---------------------------------------------------------------------
+	 */
+vector_base wa_cve_2017_5715_bpiall_vbar
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_EL0 : 0x0 - 0x200
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_sync_exception_sp_el0
+	b	sync_exception_sp_el0
+	nop	/* to force 8 byte alignment for the following stub */
+
+	/*
+	 * Since each vector table entry is 128 bytes, we can store the
+	 * stub context in the unused space to minimize memory footprint.
+	 */
+stub_sel1_sctlr:
+	.quad	SCTLR_AARCH32_EL1_RES1 | SCTLR_I_BIT
+
+aarch32_stub:
+	.word	EMIT_BPIALL
+	.word	EMIT_SMC
+
+end_vector_entry bpiall_sync_exception_sp_el0
+
+vector_entry bpiall_irq_sp_el0
+	b	irq_sp_el0
+end_vector_entry bpiall_irq_sp_el0
+
+vector_entry bpiall_fiq_sp_el0
+	b	fiq_sp_el0
+end_vector_entry bpiall_fiq_sp_el0
+
+vector_entry bpiall_serror_sp_el0
+	b	serror_sp_el0
+end_vector_entry bpiall_serror_sp_el0
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_ELx: 0x200 - 0x400
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_sync_exception_sp_elx
+	b	sync_exception_sp_elx
+end_vector_entry bpiall_sync_exception_sp_elx
+
+vector_entry bpiall_irq_sp_elx
+	b	irq_sp_elx
+end_vector_entry bpiall_irq_sp_elx
+
+vector_entry bpiall_fiq_sp_elx
+	b	fiq_sp_elx
+end_vector_entry bpiall_fiq_sp_elx
+
+vector_entry bpiall_serror_sp_elx
+	b	serror_sp_elx
+end_vector_entry bpiall_serror_sp_elx
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_sync_exception_aarch64
+	apply_cve_2017_5715_wa 1
+end_vector_entry bpiall_sync_exception_aarch64
+
+vector_entry bpiall_irq_aarch64
+	apply_cve_2017_5715_wa 2
+end_vector_entry bpiall_irq_aarch64
+
+vector_entry bpiall_fiq_aarch64
+	apply_cve_2017_5715_wa 4
+end_vector_entry bpiall_fiq_aarch64
+
+vector_entry bpiall_serror_aarch64
+	apply_cve_2017_5715_wa 8
+end_vector_entry bpiall_serror_aarch64
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_sync_exception_aarch32
+	apply_cve_2017_5715_wa 1
+end_vector_entry bpiall_sync_exception_aarch32
+
+vector_entry bpiall_irq_aarch32
+	apply_cve_2017_5715_wa 2
+end_vector_entry bpiall_irq_aarch32
+
+vector_entry bpiall_fiq_aarch32
+	apply_cve_2017_5715_wa 4
+end_vector_entry bpiall_fiq_aarch32
+
+vector_entry bpiall_serror_aarch32
+	apply_cve_2017_5715_wa 8
+end_vector_entry bpiall_serror_aarch32
+
+	/* ---------------------------------------------------------------------
+	 * This vector table is used while the workaround is executing.  It
+	 * installs a simple SMC handler to allow the Sync/IRQ/FIQ/SError
+	 * workaround stubs to enter EL3 from S-EL1.  It restores the previous
+	 * EL3 state before proceeding with the normal runtime exception vector.
+	 * ---------------------------------------------------------------------
+	 */
+vector_base wa_cve_2017_5715_bpiall_ret_vbar
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_EL0 : 0x0 - 0x200 (UNUSED)
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_ret_sync_exception_sp_el0
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_sync_exception_sp_el0
+
+vector_entry bpiall_ret_irq_sp_el0
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_irq_sp_el0
+
+vector_entry bpiall_ret_fiq_sp_el0
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_fiq_sp_el0
+
+vector_entry bpiall_ret_serror_sp_el0
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_serror_sp_el0
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_ELx: 0x200 - 0x400 (UNUSED)
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_ret_sync_exception_sp_elx
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_sync_exception_sp_elx
+
+vector_entry bpiall_ret_irq_sp_elx
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_irq_sp_elx
+
+vector_entry bpiall_ret_fiq_sp_elx
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_fiq_sp_elx
+
+vector_entry bpiall_ret_serror_sp_elx
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_serror_sp_elx
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600 (UNUSED)
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_ret_sync_exception_aarch64
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_sync_exception_aarch64
+
+vector_entry bpiall_ret_irq_aarch64
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_irq_aarch64
+
+vector_entry bpiall_ret_fiq_aarch64
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_fiq_aarch64
+
+vector_entry bpiall_ret_serror_aarch64
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_serror_aarch64
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry bpiall_ret_sync_exception_aarch32
+	/*
+	 * w2 indicates which SEL1 stub was run and thus which original vector was used
+	 * w3-w6 contain saved system register state (esr_el3 in w3)
+	 * Restore LR and ELR_EL3 register state from the GP regs context
+	 */
+	ldp	x30, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+	/* Apply the restored system register state */
+	msr	esr_el3, x3
+	msr	spsr_el3, x4
+	msr	scr_el3, x5
+	msr	sctlr_el1, x6
+	msr	elr_el3, x7
+
+	/*
+	 * Workaround is complete, so swap VBAR_EL3 to point
+	 * to workaround entry table in preparation for subsequent
+	 * Sync/IRQ/FIQ/SError exceptions.
+	 */
+	adr	x0, wa_cve_2017_5715_bpiall_vbar
+	msr	vbar_el3, x0
+
+	/*
+	 * Restore all GP regs except x2 and x3 (esr).  The value in x2
+	 * indicates the type of the original exception.
+	 */
+	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	ldp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
+	ldp	x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6]
+	ldp	x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8]
+	ldp	x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10]
+	ldp	x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12]
+	ldp	x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14]
+	ldp	x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16]
+	ldp	x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18]
+	ldp	x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20]
+	ldp	x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22]
+	ldp	x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24]
+	ldp	x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26]
+	ldp	x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+
+	/* Fast path Sync exceptions.  Static predictor will fall through. */
+	tbz	w2, #0, workaround_not_sync
+
+	/*
+	 * Check if SMC is coming from A64 state on #0
+	 * with W0 = SMCCC_ARCH_WORKAROUND_1
+	 *
+	 * This sequence evaluates as:
+	 *    (W0==SMCCC_ARCH_WORKAROUND_1) ? (ESR_EL3==SMC#0) : (NE)
+	 * allowing use of a single branch operation
+	 */
+	orr	w2, wzr, #SMCCC_ARCH_WORKAROUND_1
+	cmp	w0, w2
+	mov_imm	w2, ESR_EL3_A64_SMC0
+	ccmp	w3, w2, #0, eq
+	/* Static predictor will predict a fall through */
+	bne	1f
+	eret
+1:
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	b	sync_exception_aarch64
+end_vector_entry bpiall_ret_sync_exception_aarch32
+
+vector_entry bpiall_ret_irq_aarch32
+	b	report_unhandled_interrupt
+
+	/*
+	 * Post-workaround fan-out for non-sync exceptions
+	 */
+workaround_not_sync:
+	tbnz	w2, #3, bpiall_ret_serror
+	tbnz	w2, #2, bpiall_ret_fiq
+	/* IRQ */
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	b	irq_aarch64
+
+bpiall_ret_fiq:
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	b	fiq_aarch64
+
+bpiall_ret_serror:
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	b	serror_aarch64
+end_vector_entry bpiall_ret_irq_aarch32
+
+vector_entry bpiall_ret_fiq_aarch32
+	b	report_unhandled_interrupt
+end_vector_entry bpiall_ret_fiq_aarch32
+
+vector_entry bpiall_ret_serror_aarch32
+	b	report_unhandled_exception
+end_vector_entry bpiall_ret_serror_aarch32
diff --git a/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S b/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
new file mode 100644
index 0000000..9277cc6
--- /dev/null
+++ b/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+#include <services/arm_arch_svc.h>
+
+	.globl	wa_cve_2017_5715_mmu_vbar
+
+#define ESR_EL3_A64_SMC0	0x5e000000
+#define ESR_EL3_A32_SMC0	0x4e000000
+
+vector_base wa_cve_2017_5715_mmu_vbar
+
+	.macro	apply_cve_2017_5715_wa _is_sync_exception _esr_el3_val
+	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	mrs	x1, sctlr_el3
+	/* Disable MMU */
+	bic	x1, x1, #SCTLR_M_BIT
+	msr	sctlr_el3, x1
+	isb
+	/* Enable MMU */
+	orr	x1, x1, #SCTLR_M_BIT
+	msr	sctlr_el3, x1
+	/*
+	 * Defer ISB to avoid synchronizing twice in case we hit
+	 * the workaround SMC call which will implicitly synchronize
+	 * because of the ERET instruction.
+	 */
+
+	/*
+	 * Ensure SMC is coming from A64/A32 state on #0
+	 * with W0 = SMCCC_ARCH_WORKAROUND_1
+	 *
+	 * This sequence evaluates as:
+	 *    (W0==SMCCC_ARCH_WORKAROUND_1) ? (ESR_EL3==SMC#0) : (NE)
+	 * allowing use of a single branch operation
+	 */
+	.if \_is_sync_exception
+		orr	w1, wzr, #SMCCC_ARCH_WORKAROUND_1
+		cmp	w0, w1
+		mrs	x0, esr_el3
+		mov_imm	w1, \_esr_el3_val
+		ccmp	w0, w1, #0, eq
+		/* Static predictor will predict a fall through */
+		bne	1f
+		eret
+1:
+	.endif
+
+	/*
+	 * Synchronize now to enable the MMU.  This is required
+	 * to ensure the load pair below reads the data stored earlier.
+	 */
+	isb
+	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	.endm
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_EL0 : 0x0 - 0x200
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry mmu_sync_exception_sp_el0
+	b	sync_exception_sp_el0
+end_vector_entry mmu_sync_exception_sp_el0
+
+vector_entry mmu_irq_sp_el0
+	b	irq_sp_el0
+end_vector_entry mmu_irq_sp_el0
+
+vector_entry mmu_fiq_sp_el0
+	b	fiq_sp_el0
+end_vector_entry mmu_fiq_sp_el0
+
+vector_entry mmu_serror_sp_el0
+	b	serror_sp_el0
+end_vector_entry mmu_serror_sp_el0
+
+	/* ---------------------------------------------------------------------
+	 * Current EL with SP_ELx: 0x200 - 0x400
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry mmu_sync_exception_sp_elx
+	b	sync_exception_sp_elx
+end_vector_entry mmu_sync_exception_sp_elx
+
+vector_entry mmu_irq_sp_elx
+	b	irq_sp_elx
+end_vector_entry mmu_irq_sp_elx
+
+vector_entry mmu_fiq_sp_elx
+	b	fiq_sp_elx
+end_vector_entry mmu_fiq_sp_elx
+
+vector_entry mmu_serror_sp_elx
+	b	serror_sp_elx
+end_vector_entry mmu_serror_sp_elx
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry mmu_sync_exception_aarch64
+	apply_cve_2017_5715_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	sync_exception_aarch64
+end_vector_entry mmu_sync_exception_aarch64
+
+vector_entry mmu_irq_aarch64
+	apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	irq_aarch64
+end_vector_entry mmu_irq_aarch64
+
+vector_entry mmu_fiq_aarch64
+	apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	fiq_aarch64
+end_vector_entry mmu_fiq_aarch64
+
+vector_entry mmu_serror_aarch64
+	apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0
+	b	serror_aarch64
+end_vector_entry mmu_serror_aarch64
+
+	/* ---------------------------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * ---------------------------------------------------------------------
+	 */
+vector_entry mmu_sync_exception_aarch32
+	apply_cve_2017_5715_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	sync_exception_aarch32
+end_vector_entry mmu_sync_exception_aarch32
+
+vector_entry mmu_irq_aarch32
+	apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	irq_aarch32
+end_vector_entry mmu_irq_aarch32
+
+vector_entry mmu_fiq_aarch32
+	apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	fiq_aarch32
+end_vector_entry mmu_fiq_aarch32
+
+vector_entry mmu_serror_aarch32
+	apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0
+	b	serror_aarch32
+end_vector_entry mmu_serror_aarch32
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
new file mode 100644
index 0000000..2604023
--- /dev/null
+++ b/lib/cpus/cpu-ops.mk
@@ -0,0 +1,526 @@
+#
+# Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Cortex A57 specific optimisation to skip L1 cache flush when
+# cluster is powered down.
+SKIP_A57_L1_FLUSH_PWR_DWN	?=0
+
+# Flag to disable the cache non-temporal hint.
+# It is enabled by default.
+A53_DISABLE_NON_TEMPORAL_HINT	?=1
+
+# Flag to disable the cache non-temporal hint.
+# It is enabled by default.
+A57_DISABLE_NON_TEMPORAL_HINT	?=1
+
+WORKAROUND_CVE_2017_5715	?=1
+WORKAROUND_CVE_2018_3639	?=1
+DYNAMIC_WORKAROUND_CVE_2018_3639	?=0
+
+# Process SKIP_A57_L1_FLUSH_PWR_DWN flag
+$(eval $(call assert_boolean,SKIP_A57_L1_FLUSH_PWR_DWN))
+$(eval $(call add_define,SKIP_A57_L1_FLUSH_PWR_DWN))
+
+# Process A53_DISABLE_NON_TEMPORAL_HINT flag
+$(eval $(call assert_boolean,A53_DISABLE_NON_TEMPORAL_HINT))
+$(eval $(call add_define,A53_DISABLE_NON_TEMPORAL_HINT))
+
+# Process A57_DISABLE_NON_TEMPORAL_HINT flag
+$(eval $(call assert_boolean,A57_DISABLE_NON_TEMPORAL_HINT))
+$(eval $(call add_define,A57_DISABLE_NON_TEMPORAL_HINT))
+
+# Process WORKAROUND_CVE_2017_5715 flag
+$(eval $(call assert_boolean,WORKAROUND_CVE_2017_5715))
+$(eval $(call add_define,WORKAROUND_CVE_2017_5715))
+
+# Process WORKAROUND_CVE_2018_3639 flag
+$(eval $(call assert_boolean,WORKAROUND_CVE_2018_3639))
+$(eval $(call add_define,WORKAROUND_CVE_2018_3639))
+
+$(eval $(call assert_boolean,DYNAMIC_WORKAROUND_CVE_2018_3639))
+$(eval $(call add_define,DYNAMIC_WORKAROUND_CVE_2018_3639))
+
+ifneq (${DYNAMIC_WORKAROUND_CVE_2018_3639},0)
+    ifeq (${WORKAROUND_CVE_2018_3639},0)
+        $(error "Error: WORKAROUND_CVE_2018_3639 must be 1 if DYNAMIC_WORKAROUND_CVE_2018_3639 is 1")
+    endif
+endif
+
+# CPU Errata Build flags.
+# These should be enabled by the platform if the erratum workaround needs to be
+# applied.
+
+# Flag to apply erratum 794073 workaround when disabling mmu.
+ERRATA_A9_794073	?=0
+
+# Flag to apply erratum 816470 workaround during power down. This erratum
+# applies only to revision >= r3p0 of the Cortex A15 cpu.
+ERRATA_A15_816470	?=0
+
+# Flag to apply erratum 827671 workaround during reset. This erratum applies
+# only to revision >= r3p0 of the Cortex A15 cpu.
+ERRATA_A15_827671	?=0
+
+# Flag to apply erratum 852421 workaround during reset. This erratum applies
+# only to revision <= r1p2 of the Cortex A17 cpu.
+ERRATA_A17_852421	?=0
+
+# Flag to apply erratum 852423 workaround during reset. This erratum applies
+# only to revision <= r1p2 of the Cortex A17 cpu.
+ERRATA_A17_852423	?=0
+
+# Flag to apply erratum 855472 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A35 cpu.
+ERRATA_A35_855472	?=0
+
+# Flag to apply erratum 819472 workaround during reset. This erratum applies
+# only to revision <= r0p1 of the Cortex A53 cpu.
+ERRATA_A53_819472	?=0
+
+# Flag to apply erratum 824069 workaround during reset. This erratum applies
+# only to revision <= r0p2 of the Cortex A53 cpu.
+ERRATA_A53_824069	?=0
+
+# Flag to apply erratum 826319 workaround during reset. This erratum applies
+# only to revision <= r0p2 of the Cortex A53 cpu.
+ERRATA_A53_826319	?=0
+
+# Flag to apply erratum 827319 workaround during reset. This erratum applies
+# only to revision <= r0p2 of the Cortex A53 cpu.
+ERRATA_A53_827319	?=0
+
+# Flag to apply erratum 835769 workaround at compile and link time.  This
+# erratum applies to revision <= r0p4 of the Cortex A53 cpu. Enabling this
+# workaround can lead the linker to create "*.stub" sections.
+ERRATA_A53_835769	?=0
+
+# Flag to apply erratum 836870 workaround during reset. This erratum applies
+# only to revision <= r0p3 of the Cortex A53 cpu. From r0p4 and onwards, this
+# erratum workaround is enabled by default in hardware.
+ERRATA_A53_836870	?=0
+
+# Flag to apply erratum 843419 workaround at link time.
+# This erratum applies to revision <= r0p4 of the Cortex A53 cpu. Enabling this
+# workaround could lead the linker to emit "*.stub" sections which are 4kB
+# aligned.
+ERRATA_A53_843419	?=0
+
+# Flag to apply errata 855873 during reset. This errata applies to all
+# revisions of the Cortex A53 CPU, but this firmware workaround only works
+# for revisions r0p3 and higher. Earlier revisions are taken care
+# of by the rich OS.
+ERRATA_A53_855873	?=0
+
+# Flag to apply erratum 768277 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A55 cpu.
+ERRATA_A55_768277	?=0
+
+# Flag to apply erratum 778703 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A55 cpu.
+ERRATA_A55_778703	?=0
+
+# Flag to apply erratum 798797 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A55 cpu.
+ERRATA_A55_798797	?=0
+
+# Flag to apply erratum 846532 workaround during reset. This erratum applies
+# only to revision <= r0p1 of the Cortex A55 cpu.
+ERRATA_A55_846532	?=0
+
+# Flag to apply erratum 903758 workaround during reset. This erratum applies
+# only to revision <= r0p1 of the Cortex A55 cpu.
+ERRATA_A55_903758	?=0
+
+# Flag to apply erratum 1221012 workaround during reset. This erratum applies
+# only to revision <= r1p0 of the Cortex A55 cpu.
+ERRATA_A55_1221012	?=0
+
+# Flag to apply erratum 806969 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A57 cpu.
+ERRATA_A57_806969	?=0
+
+# Flag to apply erratum 813419 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A57 cpu.
+ERRATA_A57_813419	?=0
+
+# Flag to apply erratum 813420  workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A57 cpu.
+ERRATA_A57_813420	?=0
+
+# Flag to apply erratum 814670  workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A57 cpu.
+ERRATA_A57_814670	?=0
+
+# Flag to apply erratum 817169 workaround during power down. This erratum
+# applies only to revision <= r0p1 of the Cortex A57 cpu.
+ERRATA_A57_817169	?=0
+
+# Flag to apply erratum 826974 workaround during reset. This erratum applies
+# only to revision <= r1p1 of the Cortex A57 cpu.
+ERRATA_A57_826974	?=0
+
+# Flag to apply erratum 826977 workaround during reset. This erratum applies
+# only to revision <= r1p1 of the Cortex A57 cpu.
+ERRATA_A57_826977	?=0
+
+# Flag to apply erratum 828024 workaround during reset. This erratum applies
+# only to revision <= r1p1 of the Cortex A57 cpu.
+ERRATA_A57_828024	?=0
+
+# Flag to apply erratum 829520 workaround during reset. This erratum applies
+# only to revision <= r1p2 of the Cortex A57 cpu.
+ERRATA_A57_829520	?=0
+
+# Flag to apply erratum 833471 workaround during reset. This erratum applies
+# only to revision <= r1p2 of the Cortex A57 cpu.
+ERRATA_A57_833471	?=0
+
+# Flag to apply erratum 855972 workaround during reset. This erratum applies
+# only to revision <= r1p3 of the Cortex A57 cpu.
+ERRATA_A57_859972	?=0
+
+# Flag to apply erratum 855971 workaround during reset. This erratum applies
+# only to revision <= r0p3 of the Cortex A72 cpu.
+ERRATA_A72_859971	?=0
+
+# Flag to apply erratum 852427 workaround during reset. This erratum applies
+# only to revision r0p0 of the Cortex A73 cpu.
+ERRATA_A73_852427	?=0
+
+# Flag to apply erratum 855423 workaround during reset. This erratum applies
+# only to revision <= r0p1 of the Cortex A73 cpu.
+ERRATA_A73_855423	?=0
+
+# Flag to apply erratum 764081 workaround during reset. This erratum applies
+# only to revision <= r0p0 of the Cortex A75 cpu.
+ERRATA_A75_764081	?=0
+
+# Flag to apply erratum 790748 workaround during reset. This erratum applies
+# only to revision <= r0p0 of the Cortex A75 cpu.
+ERRATA_A75_790748	?=0
+
+# Flag to apply erratum 1073348 workaround during reset. This erratum applies
+# only to revision <= r1p0 of the Cortex A76 cpu.
+ERRATA_A76_1073348	?=0
+
+# Flag to apply erratum 1130799 workaround during reset. This erratum applies
+# only to revision <= r2p0 of the Cortex A76 cpu.
+ERRATA_A76_1130799	?=0
+
+# Flag to apply erratum 1220197 workaround during reset. This erratum applies
+# only to revision <= r2p0 of the Cortex A76 cpu.
+ERRATA_A76_1220197	?=0
+
+# Flag to apply erratum 1257314 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Cortex A76 cpu.
+ERRATA_A76_1257314	?=0
+
+# Flag to apply erratum 1262606 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Cortex A76 cpu.
+ERRATA_A76_1262606	?=0
+
+# Flag to apply erratum 1262888 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Cortex A76 cpu.
+ERRATA_A76_1262888	?=0
+
+# Flag to apply erratum 1275112 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Cortex A76 cpu.
+ERRATA_A76_1275112	?=0
+
+# Flag to apply erratum 1286807 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Cortex A76 cpu.
+ERRATA_A76_1286807	?=0
+
+# Flag to apply T32 CLREX workaround during reset. This erratum applies
+# only to r0p0 and r1p0 of the Neoverse N1 cpu.
+ERRATA_N1_1043202	?=1
+
+# Flag to apply erratum 1073348 workaround during reset. This erratum applies
+# only to revision r0p0 and r1p0 of the Neoverse N1 cpu.
+ERRATA_N1_1073348	?=0
+
+# Flag to apply erratum 1130799 workaround during reset. This erratum applies
+# only to revision <= r2p0 of the Neoverse N1 cpu.
+ERRATA_N1_1130799	?=0
+
+# Flag to apply erratum 1165347 workaround during reset. This erratum applies
+# only to revision <= r2p0 of the Neoverse N1 cpu.
+ERRATA_N1_1165347	?=0
+
+# Flag to apply erratum 1207823 workaround during reset. This erratum applies
+# only to revision <= r2p0 of the Neoverse N1 cpu.
+ERRATA_N1_1207823	?=0
+
+# Flag to apply erratum 1220197 workaround during reset. This erratum applies
+# only to revision <= r2p0 of the Neoverse N1 cpu.
+ERRATA_N1_1220197	?=0
+
+# Flag to apply erratum 1257314 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Neoverse N1 cpu.
+ERRATA_N1_1257314	?=0
+
+# Flag to apply erratum 1262606 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Neoverse N1 cpu.
+ERRATA_N1_1262606	?=0
+
+# Flag to apply erratum 1262888 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Neoverse N1 cpu.
+ERRATA_N1_1262888	?=0
+
+# Flag to apply erratum 1275112 workaround during reset. This erratum applies
+# only to revision <= r3p0 of the Neoverse N1 cpu.
+ERRATA_N1_1275112	?=0
+
+# Flag to apply erratum 1315703 workaround during reset. This erratum applies
+# to revisions before r3p1 of the Neoverse N1 cpu.
+ERRATA_N1_1315703	?=1
+
+# Flag to apply DSU erratum 798953. This erratum applies to DSUs revision r0p0.
+# Applying the workaround results in higher DSU power consumption on idle.
+ERRATA_DSU_798953	?=0
+
+# Flag to apply DSU erratum 936184. This erratum applies to DSUs containing
+# the ACP interface and revision < r2p0. Applying the workaround results in
+# higher DSU power consumption on idle.
+ERRATA_DSU_936184	?=0
+
+# Process ERRATA_A9_794073 flag
+$(eval $(call assert_boolean,ERRATA_A9_794073))
+$(eval $(call add_define,ERRATA_A9_794073))
+
+# Process ERRATA_A15_816470 flag
+$(eval $(call assert_boolean,ERRATA_A15_816470))
+$(eval $(call add_define,ERRATA_A15_816470))
+
+# Process ERRATA_A15_827671 flag
+$(eval $(call assert_boolean,ERRATA_A15_827671))
+$(eval $(call add_define,ERRATA_A15_827671))
+
+# Process ERRATA_A17_852421 flag
+$(eval $(call assert_boolean,ERRATA_A17_852421))
+$(eval $(call add_define,ERRATA_A17_852421))
+
+# Process ERRATA_A17_852423 flag
+$(eval $(call assert_boolean,ERRATA_A17_852423))
+$(eval $(call add_define,ERRATA_A17_852423))
+
+# Process ERRATA_A35_855472 flag
+$(eval $(call assert_boolean,ERRATA_A35_855472))
+$(eval $(call add_define,ERRATA_A35_855472))
+
+# Process ERRATA_A53_819472 flag
+$(eval $(call assert_boolean,ERRATA_A53_819472))
+$(eval $(call add_define,ERRATA_A53_819472))
+
+# Process ERRATA_A53_824069 flag
+$(eval $(call assert_boolean,ERRATA_A53_824069))
+$(eval $(call add_define,ERRATA_A53_824069))
+
+# Process ERRATA_A53_826319 flag
+$(eval $(call assert_boolean,ERRATA_A53_826319))
+$(eval $(call add_define,ERRATA_A53_826319))
+
+# Process ERRATA_A53_827319 flag
+$(eval $(call assert_boolean,ERRATA_A53_827319))
+$(eval $(call add_define,ERRATA_A53_827319))
+
+# Process ERRATA_A53_835769 flag
+$(eval $(call assert_boolean,ERRATA_A53_835769))
+$(eval $(call add_define,ERRATA_A53_835769))
+
+# Process ERRATA_A53_836870 flag
+$(eval $(call assert_boolean,ERRATA_A53_836870))
+$(eval $(call add_define,ERRATA_A53_836870))
+
+# Process ERRATA_A53_843419 flag
+$(eval $(call assert_boolean,ERRATA_A53_843419))
+$(eval $(call add_define,ERRATA_A53_843419))
+
+# Process ERRATA_A53_855873 flag
+$(eval $(call assert_boolean,ERRATA_A53_855873))
+$(eval $(call add_define,ERRATA_A53_855873))
+
+# Process ERRATA_A55_768277 flag
+$(eval $(call assert_boolean,ERRATA_A55_768277))
+$(eval $(call add_define,ERRATA_A55_768277))
+
+# Process ERRATA_A55_778703 flag
+$(eval $(call assert_boolean,ERRATA_A55_778703))
+$(eval $(call add_define,ERRATA_A55_778703))
+
+# Process ERRATA_A55_798797 flag
+$(eval $(call assert_boolean,ERRATA_A55_798797))
+$(eval $(call add_define,ERRATA_A55_798797))
+
+# Process ERRATA_A55_846532 flag
+$(eval $(call assert_boolean,ERRATA_A55_846532))
+$(eval $(call add_define,ERRATA_A55_846532))
+
+# Process ERRATA_A55_903758 flag
+$(eval $(call assert_boolean,ERRATA_A55_903758))
+$(eval $(call add_define,ERRATA_A55_903758))
+
+# Process ERRATA_A55_1221012 flag
+$(eval $(call assert_boolean,ERRATA_A55_1221012))
+$(eval $(call add_define,ERRATA_A55_1221012))
+
+# Process ERRATA_A57_806969 flag
+$(eval $(call assert_boolean,ERRATA_A57_806969))
+$(eval $(call add_define,ERRATA_A57_806969))
+
+# Process ERRATA_A57_813419 flag
+$(eval $(call assert_boolean,ERRATA_A57_813419))
+$(eval $(call add_define,ERRATA_A57_813419))
+
+# Process ERRATA_A57_813420 flag
+$(eval $(call assert_boolean,ERRATA_A57_813420))
+$(eval $(call add_define,ERRATA_A57_813420))
+
+# Process ERRATA_A57_814670 flag
+$(eval $(call assert_boolean,ERRATA_A57_814670))
+$(eval $(call add_define,ERRATA_A57_814670))
+
+# Process ERRATA_A57_817169 flag
+$(eval $(call assert_boolean,ERRATA_A57_817169))
+$(eval $(call add_define,ERRATA_A57_817169))
+
+# Process ERRATA_A57_826974 flag
+$(eval $(call assert_boolean,ERRATA_A57_826974))
+$(eval $(call add_define,ERRATA_A57_826974))
+
+# Process ERRATA_A57_826977 flag
+$(eval $(call assert_boolean,ERRATA_A57_826977))
+$(eval $(call add_define,ERRATA_A57_826977))
+
+# Process ERRATA_A57_828024 flag
+$(eval $(call assert_boolean,ERRATA_A57_828024))
+$(eval $(call add_define,ERRATA_A57_828024))
+
+# Process ERRATA_A57_829520 flag
+$(eval $(call assert_boolean,ERRATA_A57_829520))
+$(eval $(call add_define,ERRATA_A57_829520))
+
+# Process ERRATA_A57_833471 flag
+$(eval $(call assert_boolean,ERRATA_A57_833471))
+$(eval $(call add_define,ERRATA_A57_833471))
+
+# Process ERRATA_A57_859972 flag
+$(eval $(call assert_boolean,ERRATA_A57_859972))
+$(eval $(call add_define,ERRATA_A57_859972))
+
+# Process ERRATA_A72_859971 flag
+$(eval $(call assert_boolean,ERRATA_A72_859971))
+$(eval $(call add_define,ERRATA_A72_859971))
+
+# Process ERRATA_A73_852427 flag
+$(eval $(call assert_boolean,ERRATA_A73_852427))
+$(eval $(call add_define,ERRATA_A73_852427))
+
+# Process ERRATA_A73_855423 flag
+$(eval $(call assert_boolean,ERRATA_A73_855423))
+$(eval $(call add_define,ERRATA_A73_855423))
+
+# Process ERRATA_A75_764081 flag
+$(eval $(call assert_boolean,ERRATA_A75_764081))
+$(eval $(call add_define,ERRATA_A75_764081))
+
+# Process ERRATA_A75_790748 flag
+$(eval $(call assert_boolean,ERRATA_A75_790748))
+$(eval $(call add_define,ERRATA_A75_790748))
+
+# Process ERRATA_A76_1073348 flag
+$(eval $(call assert_boolean,ERRATA_A76_1073348))
+$(eval $(call add_define,ERRATA_A76_1073348))
+
+# Process ERRATA_A76_1130799 flag
+$(eval $(call assert_boolean,ERRATA_A76_1130799))
+$(eval $(call add_define,ERRATA_A76_1130799))
+
+# Process ERRATA_A76_1220197 flag
+$(eval $(call assert_boolean,ERRATA_A76_1220197))
+$(eval $(call add_define,ERRATA_A76_1220197))
+
+# Process ERRATA_A76_1257314 flag
+$(eval $(call assert_boolean,ERRATA_A76_1257314))
+$(eval $(call add_define,ERRATA_A76_1257314))
+
+# Process ERRATA_A76_1262606 flag
+$(eval $(call assert_boolean,ERRATA_A76_1262606))
+$(eval $(call add_define,ERRATA_A76_1262606))
+
+# Process ERRATA_A76_1262888 flag
+$(eval $(call assert_boolean,ERRATA_A76_1262888))
+$(eval $(call add_define,ERRATA_A76_1262888))
+
+# Process ERRATA_A76_1275112 flag
+$(eval $(call assert_boolean,ERRATA_A76_1275112))
+$(eval $(call add_define,ERRATA_A76_1275112))
+
+# Process ERRATA_A76_1286807 flag
+$(eval $(call assert_boolean,ERRATA_A76_1286807))
+$(eval $(call add_define,ERRATA_A76_1286807))
+
+# Process ERRATA_N1_1043202 flag
+$(eval $(call assert_boolean,ERRATA_N1_1043202))
+$(eval $(call add_define,ERRATA_N1_1043202))
+
+# Process ERRATA_N1_1073348 flag
+$(eval $(call assert_boolean,ERRATA_N1_1073348))
+$(eval $(call add_define,ERRATA_N1_1073348))
+
+# Process ERRATA_N1_1130799 flag
+$(eval $(call assert_boolean,ERRATA_N1_1130799))
+$(eval $(call add_define,ERRATA_N1_1130799))
+
+# Process ERRATA_N1_1165347 flag
+$(eval $(call assert_boolean,ERRATA_N1_1165347))
+$(eval $(call add_define,ERRATA_N1_1165347))
+
+# Process ERRATA_N1_1207823 flag
+$(eval $(call assert_boolean,ERRATA_N1_1207823))
+$(eval $(call add_define,ERRATA_N1_1207823))
+
+# Process ERRATA_N1_1220197 flag
+$(eval $(call assert_boolean,ERRATA_N1_1220197))
+$(eval $(call add_define,ERRATA_N1_1220197))
+
+# Process ERRATA_N1_1257314 flag
+$(eval $(call assert_boolean,ERRATA_N1_1257314))
+$(eval $(call add_define,ERRATA_N1_1257314))
+
+# Process ERRATA_N1_1262606 flag
+$(eval $(call assert_boolean,ERRATA_N1_1262606))
+$(eval $(call add_define,ERRATA_N1_1262606))
+
+# Process ERRATA_N1_1262888 flag
+$(eval $(call assert_boolean,ERRATA_N1_1262888))
+$(eval $(call add_define,ERRATA_N1_1262888))
+
+# Process ERRATA_N1_1275112 flag
+$(eval $(call assert_boolean,ERRATA_N1_1275112))
+$(eval $(call add_define,ERRATA_N1_1275112))
+
+# Process ERRATA_N1_1315703 flag
+$(eval $(call assert_boolean,ERRATA_N1_1315703))
+$(eval $(call add_define,ERRATA_N1_1315703))
+
+# Process ERRATA_DSU_798953 flag
+$(eval $(call assert_boolean,ERRATA_DSU_798953))
+$(eval $(call add_define,ERRATA_DSU_798953))
+
+# Process ERRATA_DSU_936184 flag
+$(eval $(call assert_boolean,ERRATA_DSU_936184))
+$(eval $(call add_define,ERRATA_DSU_936184))
+
+# Errata build flags
+ifneq (${ERRATA_A53_843419},0)
+TF_LDFLAGS_aarch64	+= --fix-cortex-a53-843419
+endif
+
+ifneq (${ERRATA_A53_835769},0)
+TF_CFLAGS_aarch64	+= -mfix-cortex-a53-835769
+TF_LDFLAGS_aarch64	+= --fix-cortex-a53-835769
+endif
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
new file mode 100644
index 0000000..f43b217
--- /dev/null
+++ b/lib/cpus/errata_report.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Runtime firmware routines to report errata status for the current CPU. */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+
+#ifdef IMAGE_BL1
+# define BL_STRING	"BL1"
+#elif defined(__aarch64__) && defined(IMAGE_BL31)
+# define BL_STRING	"BL31"
+#elif !defined(__arch64__) && defined(IMAGE_BL32)
+# define BL_STRING	"BL32"
+#elif defined(IMAGE_BL2) && BL2_AT_EL3
+# define BL_STRING "BL2"
+#else
+# error This image should not be printing errata status
+#endif
+
+/* Errata format: BL stage, CPU, errata ID, message */
+#define ERRATA_FORMAT	"%s: %s: CPU workaround for %s was %s\n"
+
+/*
+ * Returns whether errata needs to be reported. Passed arguments are private to
+ * a CPU type.
+ */
+int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
+{
+	bool report_now;
+
+	/* If already reported, return false. */
+	if (*reported != 0U)
+		return 0;
+
+	/*
+	 * Acquire lock. Determine whether status needs reporting, and then mark
+	 * report status to true.
+	 */
+	spin_lock(lock);
+	report_now = (*reported == 0U);
+	if (report_now)
+		*reported = 1;
+	spin_unlock(lock);
+
+	return report_now;
+}
+
+/*
+ * Print errata status message.
+ *
+ * Unknown: WARN
+ * Missing: WARN
+ * Applied: INFO
+ * Not applied: VERBOSE
+ */
+void errata_print_msg(unsigned int status, const char *cpu, const char *id)
+{
+	/* Errata status strings */
+	static const char *const errata_status_str[] = {
+		[ERRATA_NOT_APPLIES] = "not applied",
+		[ERRATA_APPLIES] = "applied",
+		[ERRATA_MISSING] = "missing!"
+	};
+	static const char *const __unused bl_str = BL_STRING;
+	const char *msg __unused;
+
+
+	assert(status < ARRAY_SIZE(errata_status_str));
+	assert(cpu != NULL);
+	assert(id != NULL);
+
+	msg = errata_status_str[status];
+
+	switch (status) {
+	case ERRATA_NOT_APPLIES:
+		VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg);
+		break;
+
+	case ERRATA_APPLIES:
+		INFO(ERRATA_FORMAT, bl_str, cpu, id, msg);
+		break;
+
+	case ERRATA_MISSING:
+		WARN(ERRATA_FORMAT, bl_str, cpu, id, msg);
+		break;
+
+	default:
+		WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown");
+		break;
+	}
+}
diff --git a/lib/el3_runtime/aarch32/context_mgmt.c b/lib/el3_runtime/aarch32/context_mgmt.c
new file mode 100644
index 0000000..a4702fc
--- /dev/null
+++ b/lib/el3_runtime/aarch32/context_mgmt.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/extensions/amu.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+/*******************************************************************************
+ * Context management library initialisation routine. This library is used by
+ * runtime services to share pointers to 'cpu_context' structures for the secure
+ * and non-secure states. Management of the structures and their associated
+ * memory is not done by the context management library e.g. the PSCI service
+ * manages the cpu context used for entry from and exit to the non-secure state.
+ * The Secure payload manages the context(s) corresponding to the secure state.
+ * It also uses this library to get access to the non-secure
+ * state cpu context pointers.
+ ******************************************************************************/
+void cm_init(void)
+{
+	/*
+	 * The context management library has only global data to initialize, but
+	 * that will be done when the BSS is zeroed out
+	 */
+}
+
+/*******************************************************************************
+ * The following function initializes the cpu_context 'ctx' for
+ * first use, and sets the initial entrypoint state as specified by the
+ * entry_point_info structure.
+ *
+ * The security state to initialize is determined by the SECURE attribute
+ * of the entry_point_info.
+ *
+ * The EE and ST attributes are used to configure the endianness and secure
+ * timer availability for the new execution context.
+ *
+ * To prepare the register state for entry call cm_prepare_el3_exit() and
+ * el3_exit(). For Secure-EL1 cm_prepare_el3_exit() is equivalent to
+ * cm_e1_sysreg_context_restore().
+ ******************************************************************************/
+void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
+{
+	unsigned int security_state;
+	uint32_t scr, sctlr;
+	regs_t *reg_ctx;
+
+	assert(ctx != NULL);
+
+	security_state = GET_SECURITY_STATE(ep->h.attr);
+
+	/* Clear any residual register values from the context */
+	zeromem(ctx, sizeof(*ctx));
+
+	reg_ctx = get_regs_ctx(ctx);
+
+	/*
+	 * Base the context SCR on the current value, adjust for entry point
+	 * specific requirements
+	 */
+	scr = read_scr();
+	scr &= ~(SCR_NS_BIT | SCR_HCE_BIT);
+
+	if (security_state != SECURE)
+		scr |= SCR_NS_BIT;
+
+	if (security_state != SECURE) {
+		/*
+		 * Set up SCTLR for the Non-secure context.
+		 *
+		 * SCTLR.EE: Endianness is taken from the entrypoint attributes.
+		 *
+		 * SCTLR.M, SCTLR.C and SCTLR.I: These fields must be zero (as
+		 *  required by PSCI specification)
+		 *
+		 * Set remaining SCTLR fields to their architecturally defined
+		 * values. Some fields reset to an IMPLEMENTATION DEFINED value:
+		 *
+		 * SCTLR.TE: Set to zero so that exceptions to an Exception
+		 *  Level executing at PL1 are taken to A32 state.
+		 *
+		 * SCTLR.V: Set to zero to select the normal exception vectors
+		 *  with base address held in VBAR.
+		 */
+		assert(((ep->spsr >> SPSR_E_SHIFT) & SPSR_E_MASK) ==
+			(EP_GET_EE(ep->h.attr) >> EP_EE_SHIFT));
+
+		sctlr = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U;
+		sctlr |= (SCTLR_RESET_VAL & ~(SCTLR_TE_BIT | SCTLR_V_BIT));
+		write_ctx_reg(reg_ctx, CTX_NS_SCTLR, sctlr);
+	}
+
+	/*
+	 * The target exception level is based on the spsr mode requested. If
+	 * execution is requested to hyp mode, HVC is enabled via SCR.HCE.
+	 */
+	if (GET_M32(ep->spsr) == MODE32_hyp)
+		scr |= SCR_HCE_BIT;
+
+	/*
+	 * Store the initialised values for SCTLR and SCR in the cpu_context.
+	 * The Hyp mode registers are not part of the saved context and are
+	 * set-up in cm_prepare_el3_exit().
+	 */
+	write_ctx_reg(reg_ctx, CTX_SCR, scr);
+	write_ctx_reg(reg_ctx, CTX_LR, ep->pc);
+	write_ctx_reg(reg_ctx, CTX_SPSR, ep->spsr);
+
+	/*
+	 * Store the r0-r3 value from the entrypoint into the context
+	 * Use memcpy as we are in control of the layout of the structures
+	 */
+	memcpy((void *)reg_ctx, (void *)&ep->args, sizeof(aapcs32_params_t));
+}
+
+/*******************************************************************************
+ * Enable architecture extensions on first entry to Non-secure world.
+ * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
+ * it is zero.
+ ******************************************************************************/
+static void enable_extensions_nonsecure(bool el2_unused)
+{
+#if IMAGE_BL32
+#if ENABLE_AMU
+	amu_enable(el2_unused);
+#endif
+#endif
+}
+
+/*******************************************************************************
+ * The following function initializes the cpu_context for a CPU specified by
+ * its `cpu_idx` for first use, and sets the initial entrypoint state as
+ * specified by the entry_point_info structure.
+ ******************************************************************************/
+void cm_init_context_by_index(unsigned int cpu_idx,
+			      const entry_point_info_t *ep)
+{
+	cpu_context_t *ctx;
+	ctx = cm_get_context_by_index(cpu_idx, GET_SECURITY_STATE(ep->h.attr));
+	cm_setup_context(ctx, ep);
+}
+
+/*******************************************************************************
+ * The following function initializes the cpu_context for the current CPU
+ * for first use, and sets the initial entrypoint state as specified by the
+ * entry_point_info structure.
+ ******************************************************************************/
+void cm_init_my_context(const entry_point_info_t *ep)
+{
+	cpu_context_t *ctx;
+	ctx = cm_get_context(GET_SECURITY_STATE(ep->h.attr));
+	cm_setup_context(ctx, ep);
+}
+
+/*******************************************************************************
+ * Prepare the CPU system registers for first entry into secure or normal world
+ *
+ * If execution is requested to hyp mode, HSCTLR is initialized
+ * If execution is requested to non-secure PL1, and the CPU supports
+ * HYP mode then HYP mode is disabled by configuring all necessary HYP mode
+ * registers.
+ ******************************************************************************/
+void cm_prepare_el3_exit(uint32_t security_state)
+{
+	uint32_t hsctlr, scr;
+	cpu_context_t *ctx = cm_get_context(security_state);
+	bool el2_unused = false;
+
+	assert(ctx != NULL);
+
+	if (security_state == NON_SECURE) {
+		scr = read_ctx_reg(get_regs_ctx(ctx), CTX_SCR);
+		if ((scr & SCR_HCE_BIT) != 0U) {
+			/* Use SCTLR value to initialize HSCTLR */
+			hsctlr = read_ctx_reg(get_regs_ctx(ctx),
+						 CTX_NS_SCTLR);
+			hsctlr |= HSCTLR_RES1;
+			/* Temporarily set the NS bit to access HSCTLR */
+			write_scr(read_scr() | SCR_NS_BIT);
+			/*
+			 * Make sure the write to SCR is complete so that
+			 * we can access HSCTLR
+			 */
+			isb();
+			write_hsctlr(hsctlr);
+			isb();
+
+			write_scr(read_scr() & ~SCR_NS_BIT);
+			isb();
+		} else if ((read_id_pfr1() &
+			(ID_PFR1_VIRTEXT_MASK << ID_PFR1_VIRTEXT_SHIFT)) != 0U) {
+			el2_unused = true;
+
+			/*
+			 * Set the NS bit to access NS copies of certain banked
+			 * registers
+			 */
+			write_scr(read_scr() | SCR_NS_BIT);
+			isb();
+
+			/*
+			 * Hyp / PL2 present but unused, need to disable safely.
+			 * HSCTLR can be ignored in this case.
+			 *
+			 * Set HCR to its architectural reset value so that
+			 * Non-secure operations do not trap to Hyp mode.
+			 */
+			write_hcr(HCR_RESET_VAL);
+
+			/*
+			 * Set HCPTR to its architectural reset value so that
+			 * Non-secure access from EL1 or EL0 to trace and to
+			 * Advanced SIMD and floating point functionality does
+			 * not trap to Hyp mode.
+			 */
+			write_hcptr(HCPTR_RESET_VAL);
+
+			/*
+			 * Initialise CNTHCTL. All fields are architecturally
+			 * UNKNOWN on reset and are set to zero except for
+			 * field(s) listed below.
+			 *
+			 * CNTHCTL.PL1PCEN: Disable traps to Hyp mode of
+			 *  Non-secure EL0 and EL1 accessed to the physical
+			 *  timer registers.
+			 *
+			 * CNTHCTL.PL1PCTEN: Disable traps to Hyp mode of
+			 *  Non-secure EL0 and EL1 accessed to the physical
+			 *  counter registers.
+			 */
+			write_cnthctl(CNTHCTL_RESET_VAL |
+					PL1PCEN_BIT | PL1PCTEN_BIT);
+
+			/*
+			 * Initialise CNTVOFF to zero as it resets to an
+			 * IMPLEMENTATION DEFINED value.
+			 */
+			write64_cntvoff(0);
+
+			/*
+			 * Set VPIDR and VMPIDR to match MIDR_EL1 and MPIDR
+			 * respectively.
+			 */
+			write_vpidr(read_midr());
+			write_vmpidr(read_mpidr());
+
+			/*
+			 * Initialise VTTBR, setting all fields rather than
+			 * relying on the hw. Some fields are architecturally
+			 * UNKNOWN at reset.
+			 *
+			 * VTTBR.VMID: Set to zero which is the architecturally
+			 *  defined reset value. Even though EL1&0 stage 2
+			 *  address translation is disabled, cache maintenance
+			 *  operations depend on the VMID.
+			 *
+			 * VTTBR.BADDR: Set to zero as EL1&0 stage 2 address
+			 *  translation is disabled.
+			 */
+			write64_vttbr(VTTBR_RESET_VAL &
+				~((VTTBR_VMID_MASK << VTTBR_VMID_SHIFT)
+				| (VTTBR_BADDR_MASK << VTTBR_BADDR_SHIFT)));
+
+			/*
+			 * Initialise HDCR, setting all the fields rather than
+			 * relying on hw.
+			 *
+			 * HDCR.HPMN: Set to value of PMCR.N which is the
+			 *  architecturally-defined reset value.
+			 */
+			write_hdcr(HDCR_RESET_VAL |
+				((read_pmcr() & PMCR_N_BITS) >> PMCR_N_SHIFT));
+
+			/*
+			 * Set HSTR to its architectural reset value so that
+			 * access to system registers in the cproc=1111
+			 * encoding space do not trap to Hyp mode.
+			 */
+			write_hstr(HSTR_RESET_VAL);
+			/*
+			 * Set CNTHP_CTL to its architectural reset value to
+			 * disable the EL2 physical timer and prevent timer
+			 * interrupts. Some fields are architecturally UNKNOWN
+			 * on reset and are set to zero.
+			 */
+			write_cnthp_ctl(CNTHP_CTL_RESET_VAL);
+			isb();
+
+			write_scr(read_scr() & ~SCR_NS_BIT);
+			isb();
+		}
+		enable_extensions_nonsecure(el2_unused);
+	}
+}
diff --git a/lib/el3_runtime/aarch32/cpu_data.S b/lib/el3_runtime/aarch32/cpu_data.S
new file mode 100644
index 0000000..bdad2c1
--- /dev/null
+++ b/lib/el3_runtime/aarch32/cpu_data.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+
+	.globl	_cpu_data
+	.globl	_cpu_data_by_index
+
+/* -----------------------------------------------------------------
+ * cpu_data_t *_cpu_data(void)
+ *
+ * Return the cpu_data structure for the current CPU.
+ * -----------------------------------------------------------------
+ */
+func _cpu_data
+	/* r12 is pushed to meet the 8 byte stack alignment requirement */
+	push	{r12, lr}
+	bl	plat_my_core_pos
+	pop	{r12, lr}
+	b	_cpu_data_by_index
+endfunc _cpu_data
+
+/* -----------------------------------------------------------------
+ * cpu_data_t *_cpu_data_by_index(uint32_t cpu_index)
+ *
+ * Return the cpu_data structure for the CPU with given linear index
+ *
+ * This can be called without a valid stack.
+ * clobbers: r0, r1
+ * -----------------------------------------------------------------
+ */
+func _cpu_data_by_index
+	mov_imm	r1, CPU_DATA_SIZE
+	mul	r0, r0, r1
+	ldr	r1, =percpu_data
+	add	r0, r0, r1
+	bx	lr
+endfunc _cpu_data_by_index
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
new file mode 100644
index 0000000..e6ab19b
--- /dev/null
+++ b/lib/el3_runtime/aarch64/context.S
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <context.h>
+
+	.global	el1_sysregs_context_save
+	.global	el1_sysregs_context_restore
+#if CTX_INCLUDE_FPREGS
+	.global	fpregs_context_save
+	.global	fpregs_context_restore
+#endif
+#if CTX_INCLUDE_PAUTH_REGS
+	.global	pauth_context_restore
+	.global	pauth_context_save
+#endif
+#if ENABLE_PAUTH
+	.global	pauth_load_bl_apiakey
+#endif
+	.global	save_gp_registers
+	.global	restore_gp_registers
+	.global	restore_gp_registers_eret
+	.global	el3_exit
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to save EL1 system register context. It assumes that
+ * 'x0' is pointing to a 'el1_sys_regs' structure where
+ * the register context will be saved.
+ * -----------------------------------------------------
+ */
+func el1_sysregs_context_save
+
+	mrs	x9, spsr_el1
+	mrs	x10, elr_el1
+	stp	x9, x10, [x0, #CTX_SPSR_EL1]
+
+	mrs	x15, sctlr_el1
+	mrs	x16, actlr_el1
+	stp	x15, x16, [x0, #CTX_SCTLR_EL1]
+
+	mrs	x17, cpacr_el1
+	mrs	x9, csselr_el1
+	stp	x17, x9, [x0, #CTX_CPACR_EL1]
+
+	mrs	x10, sp_el1
+	mrs	x11, esr_el1
+	stp	x10, x11, [x0, #CTX_SP_EL1]
+
+	mrs	x12, ttbr0_el1
+	mrs	x13, ttbr1_el1
+	stp	x12, x13, [x0, #CTX_TTBR0_EL1]
+
+	mrs	x14, mair_el1
+	mrs	x15, amair_el1
+	stp	x14, x15, [x0, #CTX_MAIR_EL1]
+
+	mrs	x16, tcr_el1
+	mrs	x17, tpidr_el1
+	stp	x16, x17, [x0, #CTX_TCR_EL1]
+
+	mrs	x9, tpidr_el0
+	mrs	x10, tpidrro_el0
+	stp	x9, x10, [x0, #CTX_TPIDR_EL0]
+
+	mrs	x13, par_el1
+	mrs	x14, far_el1
+	stp	x13, x14, [x0, #CTX_PAR_EL1]
+
+	mrs	x15, afsr0_el1
+	mrs	x16, afsr1_el1
+	stp	x15, x16, [x0, #CTX_AFSR0_EL1]
+
+	mrs	x17, contextidr_el1
+	mrs	x9, vbar_el1
+	stp	x17, x9, [x0, #CTX_CONTEXTIDR_EL1]
+
+	mrs	x10, pmcr_el0
+	str	x10, [x0, #CTX_PMCR_EL0]
+
+	/* Save AArch32 system registers if the build has instructed so */
+#if CTX_INCLUDE_AARCH32_REGS
+	mrs	x11, spsr_abt
+	mrs	x12, spsr_und
+	stp	x11, x12, [x0, #CTX_SPSR_ABT]
+
+	mrs	x13, spsr_irq
+	mrs	x14, spsr_fiq
+	stp	x13, x14, [x0, #CTX_SPSR_IRQ]
+
+	mrs	x15, dacr32_el2
+	mrs	x16, ifsr32_el2
+	stp	x15, x16, [x0, #CTX_DACR32_EL2]
+#endif
+
+	/* Save NS timer registers if the build has instructed so */
+#if NS_TIMER_SWITCH
+	mrs	x10, cntp_ctl_el0
+	mrs	x11, cntp_cval_el0
+	stp	x10, x11, [x0, #CTX_CNTP_CTL_EL0]
+
+	mrs	x12, cntv_ctl_el0
+	mrs	x13, cntv_cval_el0
+	stp	x12, x13, [x0, #CTX_CNTV_CTL_EL0]
+
+	mrs	x14, cntkctl_el1
+	str	x14, [x0, #CTX_CNTKCTL_EL1]
+#endif
+
+	ret
+endfunc el1_sysregs_context_save
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to restore EL1 system register context.  It assumes
+ * that 'x0' is pointing to a 'el1_sys_regs' structure
+ * from where the register context will be restored
+ * -----------------------------------------------------
+ */
+func el1_sysregs_context_restore
+
+	ldp	x9, x10, [x0, #CTX_SPSR_EL1]
+	msr	spsr_el1, x9
+	msr	elr_el1, x10
+
+	ldp	x15, x16, [x0, #CTX_SCTLR_EL1]
+	msr	sctlr_el1, x15
+	msr	actlr_el1, x16
+
+	ldp	x17, x9, [x0, #CTX_CPACR_EL1]
+	msr	cpacr_el1, x17
+	msr	csselr_el1, x9
+
+	ldp	x10, x11, [x0, #CTX_SP_EL1]
+	msr	sp_el1, x10
+	msr	esr_el1, x11
+
+	ldp	x12, x13, [x0, #CTX_TTBR0_EL1]
+	msr	ttbr0_el1, x12
+	msr	ttbr1_el1, x13
+
+	ldp	x14, x15, [x0, #CTX_MAIR_EL1]
+	msr	mair_el1, x14
+	msr	amair_el1, x15
+
+	ldp	x16, x17, [x0, #CTX_TCR_EL1]
+	msr	tcr_el1, x16
+	msr	tpidr_el1, x17
+
+	ldp	x9, x10, [x0, #CTX_TPIDR_EL0]
+	msr	tpidr_el0, x9
+	msr	tpidrro_el0, x10
+
+	ldp	x13, x14, [x0, #CTX_PAR_EL1]
+	msr	par_el1, x13
+	msr	far_el1, x14
+
+	ldp	x15, x16, [x0, #CTX_AFSR0_EL1]
+	msr	afsr0_el1, x15
+	msr	afsr1_el1, x16
+
+	ldp	x17, x9, [x0, #CTX_CONTEXTIDR_EL1]
+	msr	contextidr_el1, x17
+	msr	vbar_el1, x9
+
+	ldr	x10, [x0, #CTX_PMCR_EL0]
+	msr	pmcr_el0, x10
+
+	/* Restore AArch32 system registers if the build has instructed so */
+#if CTX_INCLUDE_AARCH32_REGS
+	ldp	x11, x12, [x0, #CTX_SPSR_ABT]
+	msr	spsr_abt, x11
+	msr	spsr_und, x12
+
+	ldp	x13, x14, [x0, #CTX_SPSR_IRQ]
+	msr	spsr_irq, x13
+	msr	spsr_fiq, x14
+
+	ldp	x15, x16, [x0, #CTX_DACR32_EL2]
+	msr	dacr32_el2, x15
+	msr	ifsr32_el2, x16
+#endif
+	/* Restore NS timer registers if the build has instructed so */
+#if NS_TIMER_SWITCH
+	ldp	x10, x11, [x0, #CTX_CNTP_CTL_EL0]
+	msr	cntp_ctl_el0, x10
+	msr	cntp_cval_el0, x11
+
+	ldp	x12, x13, [x0, #CTX_CNTV_CTL_EL0]
+	msr	cntv_ctl_el0, x12
+	msr	cntv_cval_el0, x13
+
+	ldr	x14, [x0, #CTX_CNTKCTL_EL1]
+	msr	cntkctl_el1, x14
+#endif
+
+	/* No explict ISB required here as ERET covers it */
+	ret
+endfunc el1_sysregs_context_restore
+
+/* -----------------------------------------------------
+ * The following function follows the aapcs_64 strictly
+ * to use x9-x17 (temporary caller-saved registers
+ * according to AArch64 PCS) to save floating point
+ * register context. It assumes that 'x0' is pointing to
+ * a 'fp_regs' structure where the register context will
+ * be saved.
+ *
+ * Access to VFP registers will trap if CPTR_EL3.TFP is
+ * set.  However currently we don't use VFP registers
+ * nor set traps in Trusted Firmware, and assume it's
+ * cleared
+ *
+ * TODO: Revisit when VFP is used in secure world
+ * -----------------------------------------------------
+ */
+#if CTX_INCLUDE_FPREGS
+func fpregs_context_save
+	stp	q0, q1, [x0, #CTX_FP_Q0]
+	stp	q2, q3, [x0, #CTX_FP_Q2]
+	stp	q4, q5, [x0, #CTX_FP_Q4]
+	stp	q6, q7, [x0, #CTX_FP_Q6]
+	stp	q8, q9, [x0, #CTX_FP_Q8]
+	stp	q10, q11, [x0, #CTX_FP_Q10]
+	stp	q12, q13, [x0, #CTX_FP_Q12]
+	stp	q14, q15, [x0, #CTX_FP_Q14]
+	stp	q16, q17, [x0, #CTX_FP_Q16]
+	stp	q18, q19, [x0, #CTX_FP_Q18]
+	stp	q20, q21, [x0, #CTX_FP_Q20]
+	stp	q22, q23, [x0, #CTX_FP_Q22]
+	stp	q24, q25, [x0, #CTX_FP_Q24]
+	stp	q26, q27, [x0, #CTX_FP_Q26]
+	stp	q28, q29, [x0, #CTX_FP_Q28]
+	stp	q30, q31, [x0, #CTX_FP_Q30]
+
+	mrs	x9, fpsr
+	str	x9, [x0, #CTX_FP_FPSR]
+
+	mrs	x10, fpcr
+	str	x10, [x0, #CTX_FP_FPCR]
+
+#if CTX_INCLUDE_AARCH32_REGS
+	mrs	x11, fpexc32_el2
+	str	x11, [x0, #CTX_FP_FPEXC32_EL2]
+#endif
+	ret
+endfunc fpregs_context_save
+
+/* -----------------------------------------------------
+ * The following function follows the aapcs_64 strictly
+ * to use x9-x17 (temporary caller-saved registers
+ * according to AArch64 PCS) to restore floating point
+ * register context. It assumes that 'x0' is pointing to
+ * a 'fp_regs' structure from where the register context
+ * will be restored.
+ *
+ * Access to VFP registers will trap if CPTR_EL3.TFP is
+ * set.  However currently we don't use VFP registers
+ * nor set traps in Trusted Firmware, and assume it's
+ * cleared
+ *
+ * TODO: Revisit when VFP is used in secure world
+ * -----------------------------------------------------
+ */
+func fpregs_context_restore
+	ldp	q0, q1, [x0, #CTX_FP_Q0]
+	ldp	q2, q3, [x0, #CTX_FP_Q2]
+	ldp	q4, q5, [x0, #CTX_FP_Q4]
+	ldp	q6, q7, [x0, #CTX_FP_Q6]
+	ldp	q8, q9, [x0, #CTX_FP_Q8]
+	ldp	q10, q11, [x0, #CTX_FP_Q10]
+	ldp	q12, q13, [x0, #CTX_FP_Q12]
+	ldp	q14, q15, [x0, #CTX_FP_Q14]
+	ldp	q16, q17, [x0, #CTX_FP_Q16]
+	ldp	q18, q19, [x0, #CTX_FP_Q18]
+	ldp	q20, q21, [x0, #CTX_FP_Q20]
+	ldp	q22, q23, [x0, #CTX_FP_Q22]
+	ldp	q24, q25, [x0, #CTX_FP_Q24]
+	ldp	q26, q27, [x0, #CTX_FP_Q26]
+	ldp	q28, q29, [x0, #CTX_FP_Q28]
+	ldp	q30, q31, [x0, #CTX_FP_Q30]
+
+	ldr	x9, [x0, #CTX_FP_FPSR]
+	msr	fpsr, x9
+
+	ldr	x10, [x0, #CTX_FP_FPCR]
+	msr	fpcr, x10
+
+#if CTX_INCLUDE_AARCH32_REGS
+	ldr	x11, [x0, #CTX_FP_FPEXC32_EL2]
+	msr	fpexc32_el2, x11
+#endif
+	/*
+	 * No explict ISB required here as ERET to
+	 * switch to secure EL1 or non-secure world
+	 * covers it
+	 */
+
+	ret
+endfunc fpregs_context_restore
+#endif /* CTX_INCLUDE_FPREGS */
+
+#if CTX_INCLUDE_PAUTH_REGS
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to save the ARMv8.3-PAuth register context. It assumes
+ * that 'sp' is pointing to a 'cpu_context_t' structure
+ * to where the register context will be saved.
+ * -----------------------------------------------------
+ */
+func pauth_context_save
+	add	x11, sp, #CTX_PAUTH_REGS_OFFSET
+
+	mrs	x9, APIAKeyLo_EL1
+	mrs	x10, APIAKeyHi_EL1
+	stp	x9, x10, [x11, #CTX_PACIAKEY_LO]
+
+	mrs	x9, APIBKeyLo_EL1
+	mrs	x10, APIBKeyHi_EL1
+	stp	x9, x10, [x11, #CTX_PACIBKEY_LO]
+
+	mrs	x9, APDAKeyLo_EL1
+	mrs	x10, APDAKeyHi_EL1
+	stp	x9, x10, [x11, #CTX_PACDAKEY_LO]
+
+	mrs	x9, APDBKeyLo_EL1
+	mrs	x10, APDBKeyHi_EL1
+	stp	x9, x10, [x11, #CTX_PACDBKEY_LO]
+
+	mrs	x9, APGAKeyLo_EL1
+	mrs	x10, APGAKeyHi_EL1
+	stp	x9, x10, [x11, #CTX_PACGAKEY_LO]
+
+	ret
+endfunc pauth_context_save
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to restore the ARMv8.3-PAuth register context. It assumes
+ * that 'sp' is pointing to a 'cpu_context_t' structure
+ * from where the register context will be restored.
+ * -----------------------------------------------------
+ */
+func pauth_context_restore
+	add	x11, sp, #CTX_PAUTH_REGS_OFFSET
+
+	ldp	x9, x10, [x11, #CTX_PACIAKEY_LO]
+	msr	APIAKeyLo_EL1, x9
+	msr	APIAKeyHi_EL1, x10
+
+	ldp	x9, x10, [x11, #CTX_PACIBKEY_LO]
+	msr	APIBKeyLo_EL1, x9
+	msr	APIBKeyHi_EL1, x10
+
+	ldp	x9, x10, [x11, #CTX_PACDAKEY_LO]
+	msr	APDAKeyLo_EL1, x9
+	msr	APDAKeyHi_EL1, x10
+
+	ldp	x9, x10, [x11, #CTX_PACDBKEY_LO]
+	msr	APDBKeyLo_EL1, x9
+	msr	APDBKeyHi_EL1, x10
+
+	ldp	x9, x10, [x11, #CTX_PACGAKEY_LO]
+	msr	APGAKeyLo_EL1, x9
+	msr	APGAKeyHi_EL1, x10
+
+	ret
+endfunc pauth_context_restore
+#endif /* CTX_INCLUDE_PAUTH_REGS */
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to load the APIA key used by the firmware.
+ * -----------------------------------------------------
+ */
+#if ENABLE_PAUTH
+func pauth_load_bl_apiakey
+	/* Load instruction key A used by the Trusted Firmware. */
+	adrp	x11, plat_apiakey
+	add	x11, x11, :lo12:plat_apiakey
+	ldp	x9, x10, [x11, #0]
+
+	msr	APIAKeyLo_EL1, x9
+	msr	APIAKeyHi_EL1, x10
+
+	ret
+endfunc pauth_load_bl_apiakey
+#endif /* ENABLE_PAUTH */
+
+/* -----------------------------------------------------
+ * The following functions are used to save and restore
+ * all the general purpose registers. Ideally we would
+ * only save and restore the callee saved registers when
+ * a world switch occurs but that type of implementation
+ * is more complex. So currently we will always save and
+ * restore these registers on entry and exit of EL3.
+ * These are not macros to ensure their invocation fits
+ * within the 32 instructions per exception vector.
+ * clobbers: x18
+ * -----------------------------------------------------
+ */
+func save_gp_registers
+	stp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	stp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	stp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
+	stp	x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6]
+	stp	x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8]
+	stp	x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10]
+	stp	x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12]
+	stp	x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14]
+	stp	x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16]
+	stp	x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18]
+	stp	x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20]
+	stp	x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22]
+	stp	x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24]
+	stp	x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26]
+	stp	x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+	mrs	x18, sp_el0
+	str	x18, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0]
+	ret
+endfunc save_gp_registers
+
+/* -----------------------------------------------------
+ * This function restores all general purpose registers except x30 from the
+ * CPU context. x30 register must be explicitly restored by the caller.
+ * -----------------------------------------------------
+ */
+func restore_gp_registers
+	ldp	x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
+	ldp	x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
+	ldp	x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
+	ldp	x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6]
+	ldp	x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8]
+	ldp	x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10]
+	ldp	x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12]
+	ldp	x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14]
+	ldp	x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16]
+	ldp	x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18]
+	ldp	x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20]
+	ldp	x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22]
+	ldp	x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24]
+	ldp	x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26]
+	ldr	x28, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0]
+	msr	sp_el0, x28
+	ldp	x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
+	ret
+endfunc restore_gp_registers
+
+/* -----------------------------------------------------
+ * Restore general purpose registers (including x30), and exit EL3 via ERET to
+ * a lower exception level.
+ * -----------------------------------------------------
+ */
+func restore_gp_registers_eret
+	bl	restore_gp_registers
+	ldr	x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
+
+#if IMAGE_BL31 && RAS_EXTENSION
+	/*
+	 * Issue Error Synchronization Barrier to synchronize SErrors before
+	 * exiting EL3. We're running with EAs unmasked, so any synchronized
+	 * errors would be taken immediately; therefore no need to inspect
+	 * DISR_EL1 register.
+	 */
+	esb
+#endif
+	eret
+endfunc	restore_gp_registers_eret
+
+/* -----------------------------------------------------
+ * This routine assumes that the SP_EL3 is pointing to
+ * a valid context structure from where the gp regs and
+ * other special registers can be retrieved.
+ * -----------------------------------------------------
+ */
+func el3_exit
+	/* -----------------------------------------------------
+	 * Save the current SP_EL0 i.e. the EL3 runtime stack
+	 * which will be used for handling the next SMC. Then
+	 * switch to SP_EL3
+	 * -----------------------------------------------------
+	 */
+	mov	x17, sp
+	msr	spsel, #1
+	str	x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
+
+	/* -----------------------------------------------------
+	 * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET
+	 * -----------------------------------------------------
+	 */
+	ldr	x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
+	ldp	x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
+	msr	scr_el3, x18
+	msr	spsr_el3, x16
+	msr	elr_el3, x17
+
+#if IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639
+	/* Restore mitigation state as it was on entry to EL3 */
+	ldr	x17, [sp, #CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_DISABLE]
+	cmp	x17, xzr
+	beq	1f
+	blr	x17
+1:
+#endif
+
+#if CTX_INCLUDE_PAUTH_REGS
+	/* Restore ARMv8.3-PAuth registers */
+	bl	pauth_context_restore
+#endif
+
+	/* Restore saved general purpose registers and return */
+	b	restore_gp_registers_eret
+endfunc el3_exit
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
new file mode 100644
index 0000000..05ba5ed
--- /dev/null
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/extensions/amu.h>
+#include <lib/extensions/mpam.h>
+#include <lib/extensions/spe.h>
+#include <lib/extensions/sve.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+
+/*******************************************************************************
+ * Context management library initialisation routine. This library is used by
+ * runtime services to share pointers to 'cpu_context' structures for the secure
+ * and non-secure states. Management of the structures and their associated
+ * memory is not done by the context management library e.g. the PSCI service
+ * manages the cpu context used for entry from and exit to the non-secure state.
+ * The Secure payload dispatcher service manages the context(s) corresponding to
+ * the secure state. It also uses this library to get access to the non-secure
+ * state cpu context pointers.
+ * Lastly, this library provides the api to make SP_EL3 point to the cpu context
+ * which will used for programming an entry into a lower EL. The same context
+ * will used to save state upon exception entry from that EL.
+ ******************************************************************************/
+void __init cm_init(void)
+{
+	/*
+	 * The context management library has only global data to intialize, but
+	 * that will be done when the BSS is zeroed out
+	 */
+}
+
+/*******************************************************************************
+ * The following function initializes the cpu_context 'ctx' for
+ * first use, and sets the initial entrypoint state as specified by the
+ * entry_point_info structure.
+ *
+ * The security state to initialize is determined by the SECURE attribute
+ * of the entry_point_info.
+ *
+ * The EE and ST attributes are used to configure the endianness and secure
+ * timer availability for the new execution context.
+ *
+ * To prepare the register state for entry call cm_prepare_el3_exit() and
+ * el3_exit(). For Secure-EL1 cm_prepare_el3_exit() is equivalent to
+ * cm_e1_sysreg_context_restore().
+ ******************************************************************************/
+void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep)
+{
+	unsigned int security_state;
+	uint32_t scr_el3, pmcr_el0;
+	el3_state_t *state;
+	gp_regs_t *gp_regs;
+	unsigned long sctlr_elx, actlr_elx;
+
+	assert(ctx != NULL);
+
+	security_state = GET_SECURITY_STATE(ep->h.attr);
+
+	/* Clear any residual register values from the context */
+	zeromem(ctx, sizeof(*ctx));
+
+	/*
+	 * SCR_EL3 was initialised during reset sequence in macro
+	 * el3_arch_init_common. This code modifies the SCR_EL3 fields that
+	 * affect the next EL.
+	 *
+	 * The following fields are initially set to zero and then updated to
+	 * the required value depending on the state of the SPSR_EL3 and the
+	 * Security state and entrypoint attributes of the next EL.
+	 */
+	scr_el3 = (uint32_t)read_scr();
+	scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
+			SCR_ST_BIT | SCR_HCE_BIT);
+	/*
+	 * SCR_NS: Set the security state of the next EL.
+	 */
+	if (security_state != SECURE)
+		scr_el3 |= SCR_NS_BIT;
+	/*
+	 * SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next
+	 *  Exception level as specified by SPSR.
+	 */
+	if (GET_RW(ep->spsr) == MODE_RW_64)
+		scr_el3 |= SCR_RW_BIT;
+	/*
+	 * SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical
+	 *  Secure timer registers to EL3, from AArch64 state only, if specified
+	 *  by the entrypoint attributes.
+	 */
+	if (EP_GET_ST(ep->h.attr) != 0U)
+		scr_el3 |= SCR_ST_BIT;
+
+#if !HANDLE_EA_EL3_FIRST
+	/*
+	 * SCR_EL3.EA: Do not route External Abort and SError Interrupt External
+	 *  to EL3 when executing at a lower EL. When executing at EL3, External
+	 *  Aborts are taken to EL3.
+	 */
+	scr_el3 &= ~SCR_EA_BIT;
+#endif
+
+#if FAULT_INJECTION_SUPPORT
+	/* Enable fault injection from lower ELs */
+	scr_el3 |= SCR_FIEN_BIT;
+#endif
+
+#if !CTX_INCLUDE_PAUTH_REGS
+	/*
+	 * If the pointer authentication registers aren't saved during world
+	 * switches the value of the registers can be leaked from the Secure to
+	 * the Non-secure world. To prevent this, rather than enabling pointer
+	 * authentication everywhere, we only enable it in the Non-secure world.
+	 *
+	 * If the Secure world wants to use pointer authentication,
+	 * CTX_INCLUDE_PAUTH_REGS must be set to 1.
+	 */
+	if (security_state == NON_SECURE)
+		scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
+#endif /* !CTX_INCLUDE_PAUTH_REGS */
+
+	unsigned int mte = get_armv8_5_mte_support();
+
+	/*
+	 * Enable MTE support unilaterally for normal world if the CPU supports
+	 * it.
+	 */
+	if (mte != MTE_UNIMPLEMENTED) {
+		if (security_state == NON_SECURE) {
+			scr_el3 |= SCR_ATA_BIT;
+		}
+	}
+
+#ifdef IMAGE_BL31
+	/*
+	 * SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as
+	 *  indicated by the interrupt routing model for BL31.
+	 */
+	scr_el3 |= get_scr_el3_from_routing_model(security_state);
+#endif
+
+	/*
+	 * SCR_EL3.HCE: Enable HVC instructions if next execution state is
+	 * AArch64 and next EL is EL2, or if next execution state is AArch32 and
+	 * next mode is Hyp.
+	 */
+	if (((GET_RW(ep->spsr) == MODE_RW_64) && (GET_EL(ep->spsr) == MODE_EL2))
+	    || ((GET_RW(ep->spsr) != MODE_RW_64)
+		&& (GET_M32(ep->spsr) == MODE32_hyp))) {
+		scr_el3 |= SCR_HCE_BIT;
+	}
+
+	/*
+	 * Initialise SCTLR_EL1 to the reset value corresponding to the target
+	 * execution state setting all fields rather than relying of the hw.
+	 * Some fields have architecturally UNKNOWN reset values and these are
+	 * set to zero.
+	 *
+	 * SCTLR.EE: Endianness is taken from the entrypoint attributes.
+	 *
+	 * SCTLR.M, SCTLR.C and SCTLR.I: These fields must be zero (as
+	 *  required by PSCI specification)
+	 */
+	sctlr_elx = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U;
+	if (GET_RW(ep->spsr) == MODE_RW_64)
+		sctlr_elx |= SCTLR_EL1_RES1;
+	else {
+		/*
+		 * If the target execution state is AArch32 then the following
+		 * fields need to be set.
+		 *
+		 * SCTRL_EL1.nTWE: Set to one so that EL0 execution of WFE
+		 *  instructions are not trapped to EL1.
+		 *
+		 * SCTLR_EL1.nTWI: Set to one so that EL0 execution of WFI
+		 *  instructions are not trapped to EL1.
+		 *
+		 * SCTLR_EL1.CP15BEN: Set to one to enable EL0 execution of the
+		 *  CP15DMB, CP15DSB, and CP15ISB instructions.
+		 */
+		sctlr_elx |= SCTLR_AARCH32_EL1_RES1 | SCTLR_CP15BEN_BIT
+					| SCTLR_NTWI_BIT | SCTLR_NTWE_BIT;
+	}
+
+#if ERRATA_A75_764081
+	/*
+	 * If workaround of errata 764081 for Cortex-A75 is used then set
+	 * SCTLR_EL1.IESB to enable Implicit Error Synchronization Barrier.
+	 */
+	sctlr_elx |= SCTLR_IESB_BIT;
+#endif
+
+	/*
+	 * Store the initialised SCTLR_EL1 value in the cpu_context - SCTLR_EL2
+	 * 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);
+
+	/*
+	 * Base the context ACTLR_EL1 on the current value, as it is
+	 * implementation defined. The context restore process will write
+	 * the value from the context to the actual register and can cause
+	 * problems for processor cores that don't expect certain bits to
+	 * be zero.
+	 */
+	actlr_elx = read_actlr_el1();
+	write_ctx_reg((get_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
+
+	if (security_state == SECURE) {
+		/*
+		 * Initialise PMCR_EL0 for secure context only, setting all
+		 * fields rather than relying on hw. Some fields are
+		 * architecturally UNKNOWN on reset.
+		 *
+		 * PMCR_EL0.LC: Set to one so that cycle counter overflow, that
+		 *  is recorded in PMOVSCLR_EL0[31], occurs on the increment
+		 *  that changes PMCCNTR_EL0[63] from 1 to 0.
+		 *
+		 * PMCR_EL0.DP: Set to one so that the cycle counter,
+		 *  PMCCNTR_EL0 does not count when event counting is prohibited.
+		 *
+		 * PMCR_EL0.X: Set to zero to disable export of events.
+		 *
+		 * PMCR_EL0.D: Set to zero so that, when enabled, PMCCNTR_EL0
+		 *  counts on every clock cycle.
+		 */
+		pmcr_el0 = ((PMCR_EL0_RESET_VAL | PMCR_EL0_LC_BIT
+				| PMCR_EL0_DP_BIT)
+				& ~(PMCR_EL0_X_BIT | PMCR_EL0_D_BIT));
+		write_ctx_reg(get_sysregs_ctx(ctx), CTX_PMCR_EL0, pmcr_el0);
+	}
+
+	/* Populate EL3 state so that we've the right context before doing ERET */
+	state = get_el3state_ctx(ctx);
+	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+	write_ctx_reg(state, CTX_ELR_EL3, ep->pc);
+	write_ctx_reg(state, CTX_SPSR_EL3, ep->spsr);
+
+	/*
+	 * Store the X0-X7 value from the entrypoint into the context
+	 * Use memcpy as we are in control of the layout of the structures
+	 */
+	gp_regs = get_gpregs_ctx(ctx);
+	memcpy(gp_regs, (void *)&ep->args, sizeof(aapcs64_params_t));
+}
+
+/*******************************************************************************
+ * Enable architecture extensions on first entry to Non-secure world.
+ * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise
+ * it is zero.
+ ******************************************************************************/
+static void enable_extensions_nonsecure(bool el2_unused)
+{
+#if IMAGE_BL31
+#if ENABLE_SPE_FOR_LOWER_ELS
+	spe_enable(el2_unused);
+#endif
+
+#if ENABLE_AMU
+	amu_enable(el2_unused);
+#endif
+
+#if ENABLE_SVE_FOR_NS
+	sve_enable(el2_unused);
+#endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	mpam_enable(el2_unused);
+#endif
+#endif
+}
+
+/*******************************************************************************
+ * The following function initializes the cpu_context for a CPU specified by
+ * its `cpu_idx` for first use, and sets the initial entrypoint state as
+ * specified by the entry_point_info structure.
+ ******************************************************************************/
+void cm_init_context_by_index(unsigned int cpu_idx,
+			      const entry_point_info_t *ep)
+{
+	cpu_context_t *ctx;
+	ctx = cm_get_context_by_index(cpu_idx, GET_SECURITY_STATE(ep->h.attr));
+	cm_setup_context(ctx, ep);
+}
+
+/*******************************************************************************
+ * The following function initializes the cpu_context for the current CPU
+ * for first use, and sets the initial entrypoint state as specified by the
+ * entry_point_info structure.
+ ******************************************************************************/
+void cm_init_my_context(const entry_point_info_t *ep)
+{
+	cpu_context_t *ctx;
+	ctx = cm_get_context(GET_SECURITY_STATE(ep->h.attr));
+	cm_setup_context(ctx, ep);
+}
+
+/*******************************************************************************
+ * Prepare the CPU system registers for first entry into secure or normal world
+ *
+ * If execution is requested to EL2 or hyp mode, SCTLR_EL2 is initialized
+ * If execution is requested to non-secure EL1 or svc mode, and the CPU supports
+ * EL2 then EL2 is disabled by configuring all necessary EL2 registers.
+ * For all entries, the EL1 registers are initialized from the cpu_context
+ ******************************************************************************/
+void cm_prepare_el3_exit(uint32_t security_state)
+{
+	uint32_t sctlr_elx, scr_el3, mdcr_el2;
+	cpu_context_t *ctx = cm_get_context(security_state);
+	bool el2_unused = false;
+	uint64_t hcr_el2 = 0U;
+
+	assert(ctx != NULL);
+
+	if (security_state == NON_SECURE) {
+		scr_el3 = (uint32_t)read_ctx_reg(get_el3state_ctx(ctx),
+						 CTX_SCR_EL3);
+		if ((scr_el3 & SCR_HCE_BIT) != 0U) {
+			/* Use SCTLR_EL1.EE value to initialise sctlr_el2 */
+			sctlr_elx = (uint32_t)read_ctx_reg(get_sysregs_ctx(ctx),
+							   CTX_SCTLR_EL1);
+			sctlr_elx &= SCTLR_EE_BIT;
+			sctlr_elx |= SCTLR_EL2_RES1;
+#if ERRATA_A75_764081
+			/*
+			 * If workaround of errata 764081 for Cortex-A75 is used
+			 * then set SCTLR_EL2.IESB to enable Implicit Error
+			 * Synchronization Barrier.
+			 */
+			sctlr_elx |= SCTLR_IESB_BIT;
+#endif
+			write_sctlr_el2(sctlr_elx);
+		} else if (el_implemented(2) != EL_IMPL_NONE) {
+			el2_unused = true;
+
+			/*
+			 * EL2 present but unused, need to disable safely.
+			 * SCTLR_EL2 can be ignored in this case.
+			 *
+			 * Set EL2 register width appropriately: Set HCR_EL2
+			 * field to match SCR_EL3.RW.
+			 */
+			if ((scr_el3 & SCR_RW_BIT) != 0U)
+				hcr_el2 |= HCR_RW_BIT;
+
+			/*
+			 * For Armv8.3 pointer authentication feature, disable
+			 * traps to EL2 when accessing key registers or using
+			 * pointer authentication instructions from lower ELs.
+			 */
+			hcr_el2 |= (HCR_API_BIT | HCR_APK_BIT);
+
+			write_hcr_el2(hcr_el2);
+
+			/*
+			 * Initialise CPTR_EL2 setting all fields rather than
+			 * relying on the hw. All fields have architecturally
+			 * UNKNOWN reset values.
+			 *
+			 * CPTR_EL2.TCPAC: Set to zero so that Non-secure EL1
+			 *  accesses to the CPACR_EL1 or CPACR from both
+			 *  Execution states do not trap to EL2.
+			 *
+			 * CPTR_EL2.TTA: Set to zero so that Non-secure System
+			 *  register accesses to the trace registers from both
+			 *  Execution states do not trap to EL2.
+			 *
+			 * CPTR_EL2.TFP: Set to zero so that Non-secure accesses
+			 *  to SIMD and floating-point functionality from both
+			 *  Execution states do not trap to EL2.
+			 */
+			write_cptr_el2(CPTR_EL2_RESET_VAL &
+					~(CPTR_EL2_TCPAC_BIT | CPTR_EL2_TTA_BIT
+					| CPTR_EL2_TFP_BIT));
+
+			/*
+			 * Initialise CNTHCTL_EL2. All fields are
+			 * architecturally UNKNOWN on reset and are set to zero
+			 * except for field(s) listed below.
+			 *
+			 * CNTHCTL_EL2.EL1PCEN: Set to one to disable traps to
+			 *  Hyp mode of Non-secure EL0 and EL1 accesses to the
+			 *  physical timer registers.
+			 *
+			 * CNTHCTL_EL2.EL1PCTEN: Set to one to disable traps to
+			 *  Hyp mode of  Non-secure EL0 and EL1 accesses to the
+			 *  physical counter registers.
+			 */
+			write_cnthctl_el2(CNTHCTL_RESET_VAL |
+						EL1PCEN_BIT | EL1PCTEN_BIT);
+
+			/*
+			 * Initialise CNTVOFF_EL2 to zero as it resets to an
+			 * architecturally UNKNOWN value.
+			 */
+			write_cntvoff_el2(0);
+
+			/*
+			 * Set VPIDR_EL2 and VMPIDR_EL2 to match MIDR_EL1 and
+			 * MPIDR_EL1 respectively.
+			 */
+			write_vpidr_el2(read_midr_el1());
+			write_vmpidr_el2(read_mpidr_el1());
+
+			/*
+			 * Initialise VTTBR_EL2. All fields are architecturally
+			 * UNKNOWN on reset.
+			 *
+			 * VTTBR_EL2.VMID: Set to zero. Even though EL1&0 stage
+			 *  2 address translation is disabled, cache maintenance
+			 *  operations depend on the VMID.
+			 *
+			 * VTTBR_EL2.BADDR: Set to zero as EL1&0 stage 2 address
+			 *  translation is disabled.
+			 */
+			write_vttbr_el2(VTTBR_RESET_VAL &
+				~((VTTBR_VMID_MASK << VTTBR_VMID_SHIFT)
+				| (VTTBR_BADDR_MASK << VTTBR_BADDR_SHIFT)));
+
+			/*
+			 * Initialise MDCR_EL2, setting all fields rather than
+			 * relying on hw. Some fields are architecturally
+			 * UNKNOWN on reset.
+			 *
+			 * MDCR_EL2.TDRA: Set to zero so that Non-secure EL0 and
+			 *  EL1 System register accesses to the Debug ROM
+			 *  registers are not trapped to EL2.
+			 *
+			 * MDCR_EL2.TDOSA: Set to zero so that Non-secure EL1
+			 *  System register accesses to the powerdown debug
+			 *  registers are not trapped to EL2.
+			 *
+			 * MDCR_EL2.TDA: Set to zero so that System register
+			 *  accesses to the debug registers do not trap to EL2.
+			 *
+			 * MDCR_EL2.TDE: Set to zero so that debug exceptions
+			 *  are not routed to EL2.
+			 *
+			 * MDCR_EL2.HPME: Set to zero to disable EL2 Performance
+			 *  Monitors.
+			 *
+			 * MDCR_EL2.TPM: Set to zero so that Non-secure EL0 and
+			 *  EL1 accesses to all Performance Monitors registers
+			 *  are not trapped to EL2.
+			 *
+			 * MDCR_EL2.TPMCR: Set to zero so that Non-secure EL0
+			 *  and EL1 accesses to the PMCR_EL0 or PMCR are not
+			 *  trapped to EL2.
+			 *
+			 * MDCR_EL2.HPMN: Set to value of PMCR_EL0.N which is the
+			 *  architecturally-defined reset value.
+			 */
+			mdcr_el2 = ((MDCR_EL2_RESET_VAL |
+					((read_pmcr_el0() & PMCR_EL0_N_BITS)
+					>> PMCR_EL0_N_SHIFT)) &
+					~(MDCR_EL2_TDRA_BIT | MDCR_EL2_TDOSA_BIT
+					| MDCR_EL2_TDA_BIT | MDCR_EL2_TDE_BIT
+					| MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT
+					| MDCR_EL2_TPMCR_BIT));
+
+			write_mdcr_el2(mdcr_el2);
+
+			/*
+			 * Initialise HSTR_EL2. All fields are architecturally
+			 * UNKNOWN on reset.
+			 *
+			 * HSTR_EL2.T<n>: Set all these fields to zero so that
+			 *  Non-secure EL0 or EL1 accesses to System registers
+			 *  do not trap to EL2.
+			 */
+			write_hstr_el2(HSTR_EL2_RESET_VAL & ~(HSTR_EL2_T_MASK));
+			/*
+			 * Initialise CNTHP_CTL_EL2. All fields are
+			 * architecturally UNKNOWN on reset.
+			 *
+			 * CNTHP_CTL_EL2:ENABLE: Set to zero to disable the EL2
+			 *  physical timer and prevent timer interrupts.
+			 */
+			write_cnthp_ctl_el2(CNTHP_CTL_RESET_VAL &
+						~(CNTHP_CTL_ENABLE_BIT));
+		}
+		enable_extensions_nonsecure(el2_unused);
+	}
+
+	cm_el1_sysregs_context_restore(security_state);
+	cm_set_next_eret_context(security_state);
+}
+
+/*******************************************************************************
+ * The next four functions are used by runtime services to save and restore
+ * EL1 context on the 'cpu_context' structure for the specified security
+ * state.
+ ******************************************************************************/
+void cm_el1_sysregs_context_save(uint32_t security_state)
+{
+	cpu_context_t *ctx;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	el1_sysregs_context_save(get_sysregs_ctx(ctx));
+
+#if IMAGE_BL31
+	if (security_state == SECURE)
+		PUBLISH_EVENT(cm_exited_secure_world);
+	else
+		PUBLISH_EVENT(cm_exited_normal_world);
+#endif
+}
+
+void cm_el1_sysregs_context_restore(uint32_t security_state)
+{
+	cpu_context_t *ctx;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	el1_sysregs_context_restore(get_sysregs_ctx(ctx));
+
+#if IMAGE_BL31
+	if (security_state == SECURE)
+		PUBLISH_EVENT(cm_entering_secure_world);
+	else
+		PUBLISH_EVENT(cm_entering_normal_world);
+#endif
+}
+
+/*******************************************************************************
+ * This function populates ELR_EL3 member of 'cpu_context' pertaining to the
+ * given security state with the given entrypoint
+ ******************************************************************************/
+void cm_set_elr_el3(uint32_t security_state, uintptr_t entrypoint)
+{
+	cpu_context_t *ctx;
+	el3_state_t *state;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	/* Populate EL3 state so that ERET jumps to the correct entry */
+	state = get_el3state_ctx(ctx);
+	write_ctx_reg(state, CTX_ELR_EL3, entrypoint);
+}
+
+/*******************************************************************************
+ * This function populates ELR_EL3 and SPSR_EL3 members of 'cpu_context'
+ * pertaining to the given security state
+ ******************************************************************************/
+void cm_set_elr_spsr_el3(uint32_t security_state,
+			uintptr_t entrypoint, uint32_t spsr)
+{
+	cpu_context_t *ctx;
+	el3_state_t *state;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	/* Populate EL3 state so that ERET jumps to the correct entry */
+	state = get_el3state_ctx(ctx);
+	write_ctx_reg(state, CTX_ELR_EL3, entrypoint);
+	write_ctx_reg(state, CTX_SPSR_EL3, spsr);
+}
+
+/*******************************************************************************
+ * This function updates a single bit in the SCR_EL3 member of the 'cpu_context'
+ * pertaining to the given security state using the value and bit position
+ * specified in the parameters. It preserves all other bits.
+ ******************************************************************************/
+void cm_write_scr_el3_bit(uint32_t security_state,
+			  uint32_t bit_pos,
+			  uint32_t value)
+{
+	cpu_context_t *ctx;
+	el3_state_t *state;
+	uint32_t scr_el3;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	/* Ensure that the bit position is a valid one */
+	assert(((1U << bit_pos) & SCR_VALID_BIT_MASK) != 0U);
+
+	/* Ensure that the 'value' is only a bit wide */
+	assert(value <= 1U);
+
+	/*
+	 * Get the SCR_EL3 value from the cpu context, clear the desired bit
+	 * and set it to its new value.
+	 */
+	state = get_el3state_ctx(ctx);
+	scr_el3 = (uint32_t)read_ctx_reg(state, CTX_SCR_EL3);
+	scr_el3 &= ~(1U << bit_pos);
+	scr_el3 |= value << bit_pos;
+	write_ctx_reg(state, CTX_SCR_EL3, scr_el3);
+}
+
+/*******************************************************************************
+ * This function retrieves SCR_EL3 member of 'cpu_context' pertaining to the
+ * given security state.
+ ******************************************************************************/
+uint32_t cm_get_scr_el3(uint32_t security_state)
+{
+	cpu_context_t *ctx;
+	el3_state_t *state;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	/* Populate EL3 state so that ERET jumps to the correct entry */
+	state = get_el3state_ctx(ctx);
+	return (uint32_t)read_ctx_reg(state, CTX_SCR_EL3);
+}
+
+/*******************************************************************************
+ * This function is used to program the context that's used for exception
+ * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for
+ * the required security state
+ ******************************************************************************/
+void cm_set_next_eret_context(uint32_t security_state)
+{
+	cpu_context_t *ctx;
+
+	ctx = cm_get_context(security_state);
+	assert(ctx != NULL);
+
+	cm_set_next_context(ctx);
+}
diff --git a/lib/el3_runtime/aarch64/cpu_data.S b/lib/el3_runtime/aarch64/cpu_data.S
new file mode 100644
index 0000000..2edf225
--- /dev/null
+++ b/lib/el3_runtime/aarch64/cpu_data.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <lib/el3_runtime/cpu_data.h>
+
+.globl	init_cpu_data_ptr
+.globl	_cpu_data_by_index
+
+/* -----------------------------------------------------------------
+ * void init_cpu_data_ptr(void)
+ *
+ * Initialise the TPIDR_EL3 register to refer to the cpu_data_t
+ * for the calling CPU. This must be called before cm_get_cpu_data()
+ *
+ * This can be called without a valid stack. It assumes that
+ * plat_my_core_pos() does not clobber register x10.
+ * clobbers: x0, x1, x10
+ * -----------------------------------------------------------------
+ */
+func init_cpu_data_ptr
+	mov	x10, x30
+	bl	plat_my_core_pos
+	bl	_cpu_data_by_index
+	msr	tpidr_el3, x0
+	ret	x10
+endfunc init_cpu_data_ptr
+
+/* -----------------------------------------------------------------
+ * cpu_data_t *_cpu_data_by_index(uint32_t cpu_index)
+ *
+ * Return the cpu_data structure for the CPU with given linear index
+ *
+ * This can be called without a valid stack.
+ * clobbers: x0, x1
+ * -----------------------------------------------------------------
+ */
+func _cpu_data_by_index
+	mov_imm	x1, CPU_DATA_SIZE
+	mul	x0, x0, x1
+	adr	x1, percpu_data
+	add	x0, x0, x1
+	ret
+endfunc _cpu_data_by_index
diff --git a/lib/el3_runtime/cpu_data_array.c b/lib/el3_runtime/cpu_data_array.c
new file mode 100644
index 0000000..13d464c
--- /dev/null
+++ b/lib/el3_runtime/cpu_data_array.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+/* The per_cpu_ptr_cache_t space allocation */
+cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
new file mode 100644
index 0000000..82d2e18
--- /dev/null
+++ b/lib/extensions/amu/aarch32/amu.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/extensions/amu.h>
+#include <lib/extensions/amu_private.h>
+#include <plat/common/platform.h>
+
+#define AMU_GROUP0_NR_COUNTERS	4
+
+struct amu_ctx {
+	uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS];
+	uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS];
+};
+
+static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
+
+bool amu_supported(void)
+{
+	uint64_t features;
+
+	features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT;
+	return (features & ID_PFR0_AMU_MASK) == 1U;
+}
+
+void amu_enable(bool el2_unused)
+{
+	if (!amu_supported())
+		return;
+
+	if (el2_unused) {
+		uint64_t v;
+		/*
+		 * Non-secure access from EL0 or EL1 to the Activity Monitor
+		 * registers do not trap to EL2.
+		 */
+		v = read_hcptr();
+		v &= ~TAM_BIT;
+		write_hcptr(v);
+	}
+
+	/* Enable group 0 counters */
+	write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
+
+	/* Enable group 1 counters */
+	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
+}
+
+/* Read the group 0 counter identified by the given `idx`. */
+uint64_t amu_group0_cnt_read(int idx)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS));
+
+	return amu_group0_cnt_read_internal(idx);
+}
+
+/* Write the group 0 counter identified by the given `idx` with `val`. */
+void amu_group0_cnt_write(int idx, uint64_t val)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS));
+
+	amu_group0_cnt_write_internal(idx, val);
+	isb();
+}
+
+/* Read the group 1 counter identified by the given `idx`. */
+uint64_t amu_group1_cnt_read(int idx)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
+
+	return amu_group1_cnt_read_internal(idx);
+}
+
+/* Write the group 1 counter identified by the given `idx` with `val`. */
+void amu_group1_cnt_write(int idx, uint64_t val)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
+
+	amu_group1_cnt_write_internal(idx, val);
+	isb();
+}
+
+void amu_group1_set_evtype(int idx, unsigned int val)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
+
+	amu_group1_set_evtype_internal(idx, val);
+	isb();
+}
+
+static void *amu_context_save(const void *arg)
+{
+	struct amu_ctx *ctx;
+	int i;
+
+	if (!amu_supported())
+		return (void *)-1;
+
+	ctx = &amu_ctxs[plat_my_core_pos()];
+
+	/* Assert that group 0 counter configuration is what we expect */
+	assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK &&
+	       read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK);
+
+	/*
+	 * Disable group 0 counters to avoid other observers like SCP sampling
+	 * counter values from the future via the memory mapped view.
+	 */
+	write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK);
+	write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK);
+	isb();
+
+	for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
+		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
+
+	for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
+		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
+
+	return (void *)0;
+}
+
+static void *amu_context_restore(const void *arg)
+{
+	struct amu_ctx *ctx;
+	int i;
+
+	if (!amu_supported())
+		return (void *)-1;
+
+	ctx = &amu_ctxs[plat_my_core_pos()];
+
+	/* Counters were disabled in `amu_context_save()` */
+	assert((read_amcntenset0() == 0U) && (read_amcntenset1() == 0U));
+
+	/* Restore group 0 counters */
+	for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
+		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
+	for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
+		amu_group1_cnt_write(i, ctx->group1_cnts[i]);
+
+	/* Enable group 0 counters */
+	write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
+
+	/* Enable group 1 counters */
+	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
+	return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
diff --git a/lib/extensions/amu/aarch32/amu_helpers.S b/lib/extensions/amu/aarch32/amu_helpers.S
new file mode 100644
index 0000000..effb8e5
--- /dev/null
+++ b/lib/extensions/amu/aarch32/amu_helpers.S
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert_macros.S>
+#include <asm_macros.S>
+
+	.globl	amu_group0_cnt_read_internal
+	.globl	amu_group0_cnt_write_internal
+	.globl	amu_group1_cnt_read_internal
+	.globl	amu_group1_cnt_write_internal
+	.globl	amu_group1_set_evtype_internal
+
+/*
+ * uint64_t amu_group0_cnt_read_internal(int idx);
+ *
+ * Given `idx`, read the corresponding AMU counter
+ * and return it in `r0` and `r1`.
+ */
+func amu_group0_cnt_read_internal
+#if ENABLE_ASSERTIONS
+	/* `idx` should be between [0, 3] */
+	mov	r1, r0
+	lsr	r1, r1, #2
+	cmp	r1, #0
+	ASM_ASSERT(eq)
+#endif
+
+	/*
+	 * Given `idx` calculate address of ldcopr16/bx lr instruction pair
+	 * in the table below.
+	 */
+	adr	r1, 1f
+	lsl	r0, r0, #3	/* each ldcopr16/bx lr sequence is 8 bytes */
+	add	r1, r1, r0
+	bx	r1
+1:
+	ldcopr16	r0, r1, AMEVCNTR00	/* index 0 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR01	/* index 1 */
+	bx 		lr
+	ldcopr16	r0, r1, AMEVCNTR02	/* index 2 */
+	bx 		lr
+	ldcopr16	r0, r1, AMEVCNTR03	/* index 3 */
+	bx 		lr
+endfunc amu_group0_cnt_read_internal
+
+/*
+ * void amu_group0_cnt_write_internal(int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU counter.
+ * `idx` is passed in `r0` and `val` is passed in `r2` and `r3`.
+ * `r1` is used as a scratch register.
+ */
+func amu_group0_cnt_write_internal
+#if ENABLE_ASSERTIONS
+	/* `idx` should be between [0, 3] */
+	mov	r1, r0
+	lsr	r1, r1, #2
+	cmp	r1, #0
+	ASM_ASSERT(eq)
+#endif
+
+	/*
+	 * Given `idx` calculate address of stcopr16/bx lr instruction pair
+	 * in the table below.
+	 */
+	adr	r1, 1f
+	lsl	r0, r0, #3	/* each stcopr16/bx lr sequence is 8 bytes */
+	add	r1, r1, r0
+	bx	r1
+
+1:
+	stcopr16	r2, r3, AMEVCNTR00	/* index 0 */
+	bx 		lr
+	stcopr16	r2, r3, AMEVCNTR01	/* index 1 */
+	bx 		lr
+	stcopr16	r2, r3, AMEVCNTR02	/* index 2 */
+	bx 		lr
+	stcopr16	r2, r3, AMEVCNTR03	/* index 3 */
+	bx 		lr
+endfunc amu_group0_cnt_write_internal
+
+/*
+ * uint64_t amu_group1_cnt_read_internal(int idx);
+ *
+ * Given `idx`, read the corresponding AMU counter
+ * and return it in `r0` and `r1`.
+ */
+func amu_group1_cnt_read_internal
+#if ENABLE_ASSERTIONS
+	/* `idx` should be between [0, 15] */
+	mov	r1, r0
+	lsr	r1, r1, #4
+	cmp	r1, #0
+	ASM_ASSERT(eq)
+#endif
+
+	/*
+	 * Given `idx` calculate address of ldcopr16/bx lr instruction pair
+	 * in the table below.
+	 */
+	adr	r1, 1f
+	lsl	r0, r0, #3	/* each ldcopr16/bx lr sequence is 8 bytes */
+	add	r1, r1, r0
+	bx	r1
+
+1:
+	ldcopr16	r0, r1, AMEVCNTR10	/* index 0 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR11	/* index 1 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR12	/* index 2 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR13	/* index 3 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR14	/* index 4 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR15	/* index 5 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR16	/* index 6 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR17	/* index 7 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR18	/* index 8 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR19	/* index 9 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR1A	/* index 10 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR1B	/* index 11 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR1C	/* index 12 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR1D	/* index 13 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR1E	/* index 14 */
+	bx		lr
+	ldcopr16	r0, r1, AMEVCNTR1F	/* index 15 */
+	bx		lr
+endfunc amu_group1_cnt_read_internal
+
+/*
+ * void amu_group1_cnt_write_internal(int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU counter.
+ * `idx` is passed in `r0` and `val` is passed in `r2` and `r3`.
+ * `r1` is used as a scratch register.
+ */
+func amu_group1_cnt_write_internal
+#if ENABLE_ASSERTIONS
+	/* `idx` should be between [0, 15] */
+	mov	r1, r0
+	lsr	r1, r1, #4
+	cmp	r1, #0
+	ASM_ASSERT(eq)
+#endif
+
+	/*
+	 * Given `idx` calculate address of ldcopr16/bx lr instruction pair
+	 * in the table below.
+	 */
+	adr	r1, 1f
+	lsl	r0, r0, #3	/* each stcopr16/bx lr sequence is 8 bytes */
+	add	r1, r1, r0
+	bx	r1
+
+1:
+	stcopr16	r2, r3,	AMEVCNTR10	/* index 0 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR11	/* index 1 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR12	/* index 2 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR13	/* index 3 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR14	/* index 4 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR15	/* index 5 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR16	/* index 6 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR17	/* index 7 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR18	/* index 8 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR19	/* index 9 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR1A	/* index 10 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR1B	/* index 11 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR1C	/* index 12 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR1D	/* index 13 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR1E	/* index 14 */
+	bx		lr
+	stcopr16	r2, r3,	AMEVCNTR1F	/* index 15 */
+	bx		lr
+endfunc amu_group1_cnt_write_internal
+
+/*
+ * void amu_group1_set_evtype_internal(int idx, unsigned int val);
+ *
+ * Program the AMU event type register indexed by `idx`
+ * with the value `val`.
+ */
+func amu_group1_set_evtype_internal
+#if ENABLE_ASSERTIONS
+	/* `idx` should be between [0, 15] */
+	mov	r2, r0
+	lsr	r2, r2, #4
+	cmp	r2, #0
+	ASM_ASSERT(eq)
+
+	/* val should be between [0, 65535] */
+	mov	r2, r1
+	lsr	r2, r2, #16
+	cmp	r2, #0
+	ASM_ASSERT(eq)
+#endif
+
+	/*
+	 * Given `idx` calculate address of stcopr/bx lr instruction pair
+	 * in the table below.
+	 */
+	adr	r2, 1f
+	lsl	r0, r0, #3	/* each stcopr/bx lr sequence is 8 bytes */
+	add	r2, r2, r0
+	bx	r2
+
+1:
+	stcopr	r1,	AMEVTYPER10 /* index 0 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER11 /* index 1 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER12 /* index 2 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER13 /* index 3 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER14 /* index 4 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER15 /* index 5 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER16 /* index 6 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER17 /* index 7 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER18 /* index 8 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER19 /* index 9 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER1A /* index 10 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER1B /* index 11 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER1C /* index 12 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER1D /* index 13 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER1E /* index 14 */
+	bx	lr
+	stcopr	r1,	AMEVTYPER1F /* index 15 */
+	bx	lr
+endfunc amu_group1_set_evtype_internal
diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c
new file mode 100644
index 0000000..85f7007
--- /dev/null
+++ b/lib/extensions/amu/aarch64/amu.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/extensions/amu.h>
+#include <lib/extensions/amu_private.h>
+#include <plat/common/platform.h>
+
+#define AMU_GROUP0_NR_COUNTERS	4
+
+struct amu_ctx {
+	uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS];
+	uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS];
+};
+
+static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
+
+bool amu_supported(void)
+{
+	uint64_t features;
+
+	features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT;
+	return (features & ID_AA64PFR0_AMU_MASK) == 1U;
+}
+
+/*
+ * Enable counters.  This function is meant to be invoked
+ * by the context management library before exiting from EL3.
+ */
+void amu_enable(bool el2_unused)
+{
+	uint64_t v;
+
+	if (!amu_supported())
+		return;
+
+	if (el2_unused) {
+		/*
+		 * CPTR_EL2.TAM: Set to zero so any accesses to
+		 * the Activity Monitor registers do not trap to EL2.
+		 */
+		v = read_cptr_el2();
+		v &= ~CPTR_EL2_TAM_BIT;
+		write_cptr_el2(v);
+	}
+
+	/*
+	 * CPTR_EL3.TAM: Set to zero so that any accesses to
+	 * the Activity Monitor registers do not trap to EL3.
+	 */
+	v = read_cptr_el3();
+	v &= ~TAM_BIT;
+	write_cptr_el3(v);
+
+	/* Enable group 0 counters */
+	write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK);
+	/* Enable group 1 counters */
+	write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK);
+}
+
+/* Read the group 0 counter identified by the given `idx`. */
+uint64_t amu_group0_cnt_read(int idx)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS));
+
+	return amu_group0_cnt_read_internal(idx);
+}
+
+/* Write the group 0 counter identified by the given `idx` with `val`. */
+void amu_group0_cnt_write(int idx, uint64_t val)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS));
+
+	amu_group0_cnt_write_internal(idx, val);
+	isb();
+}
+
+/* Read the group 1 counter identified by the given `idx`. */
+uint64_t amu_group1_cnt_read(int idx)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
+
+	return amu_group1_cnt_read_internal(idx);
+}
+
+/* Write the group 1 counter identified by the given `idx` with `val`. */
+void amu_group1_cnt_write(int idx, uint64_t val)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
+
+	amu_group1_cnt_write_internal(idx, val);
+	isb();
+}
+
+/*
+ * Program the event type register for the given `idx` with
+ * the event number `val`.
+ */
+void amu_group1_set_evtype(int idx, unsigned int val)
+{
+	assert(amu_supported());
+	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
+
+	amu_group1_set_evtype_internal(idx, val);
+	isb();
+}
+
+static void *amu_context_save(const void *arg)
+{
+	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
+	int i;
+
+	if (!amu_supported())
+		return (void *)-1;
+
+	/* Assert that group 0/1 counter configuration is what we expect */
+	assert((read_amcntenset0_el0() == AMU_GROUP0_COUNTERS_MASK) &&
+	       (read_amcntenset1_el0() == AMU_GROUP1_COUNTERS_MASK));
+
+	assert(((sizeof(int) * 8) - __builtin_clz(AMU_GROUP1_COUNTERS_MASK))
+		<= AMU_GROUP1_NR_COUNTERS);
+
+	/*
+	 * Disable group 0/1 counters to avoid other observers like SCP sampling
+	 * counter values from the future via the memory mapped view.
+	 */
+	write_amcntenclr0_el0(AMU_GROUP0_COUNTERS_MASK);
+	write_amcntenclr1_el0(AMU_GROUP1_COUNTERS_MASK);
+	isb();
+
+	/* Save group 0 counters */
+	for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
+		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
+
+	/* Save group 1 counters */
+	for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
+		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
+
+	return (void *)0;
+}
+
+static void *amu_context_restore(const void *arg)
+{
+	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
+	int i;
+
+	if (!amu_supported())
+		return (void *)-1;
+
+	/* Counters were disabled in `amu_context_save()` */
+	assert((read_amcntenset0_el0() == 0U) && (read_amcntenset1_el0() == 0U));
+
+	assert(((sizeof(int) * 8U) - __builtin_clz(AMU_GROUP1_COUNTERS_MASK))
+		<= AMU_GROUP1_NR_COUNTERS);
+
+	/* Restore group 0 counters */
+	for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
+		if ((AMU_GROUP0_COUNTERS_MASK & (1U << i)) != 0U)
+			amu_group0_cnt_write(i, ctx->group0_cnts[i]);
+
+	/* Restore group 1 counters */
+	for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
+		if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U)
+			amu_group1_cnt_write(i, ctx->group1_cnts[i]);
+
+	/* Restore group 0/1 counter configuration */
+	write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK);
+	write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK);
+
+	return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
diff --git a/lib/extensions/amu/aarch64/amu_helpers.S b/lib/extensions/amu/aarch64/amu_helpers.S
new file mode 100644
index 0000000..89007a3
--- /dev/null
+++ b/lib/extensions/amu/aarch64/amu_helpers.S
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert_macros.S>
+#include <asm_macros.S>
+
+	.globl	amu_group0_cnt_read_internal
+	.globl	amu_group0_cnt_write_internal
+	.globl	amu_group1_cnt_read_internal
+	.globl	amu_group1_cnt_write_internal
+	.globl	amu_group1_set_evtype_internal
+
+/*
+ * uint64_t amu_group0_cnt_read_internal(int idx);
+ *
+ * Given `idx`, read the corresponding AMU counter
+ * and return it in `x0`.
+ */
+func amu_group0_cnt_read_internal
+	adr	x1, 1f
+#if ENABLE_ASSERTIONS
+	/*
+	 * It can be dangerous to call this function with an
+	 * out of bounds index.  Ensure `idx` is valid.
+	 */
+	tst	x0, #~3
+	ASM_ASSERT(eq)
+#endif
+	/*
+	 * Given `idx` calculate address of mrs/ret instruction pair
+	 * in the table below.
+	 */
+	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x1
+
+1:	read	AMEVCNTR00_EL0		/* index 0 */
+	read	AMEVCNTR01_EL0		/* index 1 */
+	read	AMEVCNTR02_EL0		/* index 2 */
+	read	AMEVCNTR03_EL0		/* index 3 */
+endfunc amu_group0_cnt_read_internal
+
+/*
+ * void amu_group0_cnt_write_internal(int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU counter.
+ */
+func amu_group0_cnt_write_internal
+	adr	x2, 1f
+#if ENABLE_ASSERTIONS
+	/*
+	 * It can be dangerous to call this function with an
+	 * out of bounds index.  Ensure `idx` is valid.
+	 */
+	tst	x0, #~3
+	ASM_ASSERT(eq)
+#endif
+	/*
+	 * Given `idx` calculate address of mrs/ret instruction pair
+	 * in the table below.
+	 */
+	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x2
+
+1:	write	AMEVCNTR00_EL0		/* index 0 */
+	write	AMEVCNTR01_EL0		/* index 1 */
+	write	AMEVCNTR02_EL0		/* index 2 */
+	write	AMEVCNTR03_EL0		/* index 3 */
+endfunc amu_group0_cnt_write_internal
+
+/*
+ * uint64_t amu_group1_cnt_read_internal(int idx);
+ *
+ * Given `idx`, read the corresponding AMU counter
+ * and return it in `x0`.
+ */
+func amu_group1_cnt_read_internal
+	adr	x1, 1f
+#if ENABLE_ASSERTIONS
+	/*
+	 * It can be dangerous to call this function with an
+	 * out of bounds index.  Ensure `idx` is valid.
+	 */
+	tst	x0, #~0xF
+	ASM_ASSERT(eq)
+#endif
+	/*
+	 * Given `idx` calculate address of mrs/ret instruction pair
+	 * in the table below.
+	 */
+	add	x1, x1, x0, lsl #3	/* each mrs/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x1, x1, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x1
+
+1:	read	AMEVCNTR10_EL0		/* index 0 */
+	read	AMEVCNTR11_EL0		/* index 1 */
+	read	AMEVCNTR12_EL0		/* index 2 */
+	read	AMEVCNTR13_EL0		/* index 3 */
+	read	AMEVCNTR14_EL0		/* index 4 */
+	read	AMEVCNTR15_EL0		/* index 5 */
+	read	AMEVCNTR16_EL0		/* index 6 */
+	read	AMEVCNTR17_EL0		/* index 7 */
+	read	AMEVCNTR18_EL0		/* index 8 */
+	read	AMEVCNTR19_EL0		/* index 9 */
+	read	AMEVCNTR1A_EL0		/* index 10 */
+	read	AMEVCNTR1B_EL0		/* index 11 */
+	read	AMEVCNTR1C_EL0		/* index 12 */
+	read	AMEVCNTR1D_EL0		/* index 13 */
+	read	AMEVCNTR1E_EL0		/* index 14 */
+	read	AMEVCNTR1F_EL0		/* index 15 */
+endfunc amu_group1_cnt_read_internal
+
+/*
+ * void amu_group1_cnt_write_internal(int idx, uint64_t val);
+ *
+ * Given `idx`, write `val` to the corresponding AMU counter.
+ */
+func amu_group1_cnt_write_internal
+	adr	x2, 1f
+#if ENABLE_ASSERTIONS
+	/*
+	 * It can be dangerous to call this function with an
+	 * out of bounds index.  Ensure `idx` is valid.
+	 */
+	tst	x0, #~0xF
+	ASM_ASSERT(eq)
+#endif
+	/*
+	 * Given `idx` calculate address of mrs/ret instruction pair
+	 * in the table below.
+	 */
+	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x2
+
+1:	write	AMEVCNTR10_EL0		/* index 0 */
+	write	AMEVCNTR11_EL0		/* index 1 */
+	write	AMEVCNTR12_EL0		/* index 2 */
+	write	AMEVCNTR13_EL0		/* index 3 */
+	write	AMEVCNTR14_EL0		/* index 4 */
+	write	AMEVCNTR15_EL0		/* index 5 */
+	write	AMEVCNTR16_EL0		/* index 6 */
+	write	AMEVCNTR17_EL0		/* index 7 */
+	write	AMEVCNTR18_EL0		/* index 8 */
+	write	AMEVCNTR19_EL0		/* index 9 */
+	write	AMEVCNTR1A_EL0		/* index 10 */
+	write	AMEVCNTR1B_EL0		/* index 11 */
+	write	AMEVCNTR1C_EL0		/* index 12 */
+	write	AMEVCNTR1D_EL0		/* index 13 */
+	write	AMEVCNTR1E_EL0		/* index 14 */
+	write	AMEVCNTR1F_EL0		/* index 15 */
+endfunc amu_group1_cnt_write_internal
+
+/*
+ * void amu_group1_set_evtype_internal(int idx, unsigned int val);
+ *
+ * Program the AMU event type register indexed by `idx`
+ * with the value `val`.
+ */
+func amu_group1_set_evtype_internal
+	adr	x2, 1f
+#if ENABLE_ASSERTIONS
+	/*
+	 * It can be dangerous to call this function with an
+	 * out of bounds index.  Ensure `idx` is valid.
+	 */
+	tst	x0, #~0xF
+	ASM_ASSERT(eq)
+
+	/* val should be between [0, 65535] */
+	tst	x1, #~0xFFFF
+	ASM_ASSERT(eq)
+#endif
+	/*
+	 * Given `idx` calculate address of msr/ret instruction pair
+	 * in the table below.
+	 */
+	add	x2, x2, x0, lsl #3	/* each msr/ret sequence is 8 bytes */
+#if ENABLE_BTI
+	add	x2, x2, x0, lsl #2	/* + "bti j" instruction */
+#endif
+	br	x2
+
+1:	write	AMEVTYPER10_EL0		/* index 0 */
+	write	AMEVTYPER11_EL0		/* index 1 */
+	write	AMEVTYPER12_EL0		/* index 2 */
+	write	AMEVTYPER13_EL0		/* index 3 */
+	write	AMEVTYPER14_EL0		/* index 4 */
+	write	AMEVTYPER15_EL0		/* index 5 */
+	write	AMEVTYPER16_EL0		/* index 6 */
+	write	AMEVTYPER17_EL0		/* index 7 */
+	write	AMEVTYPER18_EL0		/* index 8 */
+	write	AMEVTYPER19_EL0		/* index 9 */
+	write	AMEVTYPER1A_EL0		/* index 10 */
+	write	AMEVTYPER1B_EL0		/* index 11 */
+	write	AMEVTYPER1C_EL0		/* index 12 */
+	write	AMEVTYPER1D_EL0		/* index 13 */
+	write	AMEVTYPER1E_EL0		/* index 14 */
+	write	AMEVTYPER1F_EL0		/* index 15 */
+endfunc amu_group1_set_evtype_internal
diff --git a/lib/extensions/mpam/mpam.c b/lib/extensions/mpam/mpam.c
new file mode 100644
index 0000000..e794f01
--- /dev/null
+++ b/lib/extensions/mpam/mpam.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/extensions/mpam.h>
+
+bool mpam_supported(void)
+{
+	uint64_t features = read_id_aa64dfr0_el1() >> ID_AA64PFR0_MPAM_SHIFT;
+
+	return ((features & ID_AA64PFR0_MPAM_MASK) != 0U);
+}
+
+void mpam_enable(bool el2_unused)
+{
+	if (!mpam_supported())
+		return;
+
+	/*
+	 * Enable MPAM, and disable trapping to EL3 when lower ELs access their
+	 * own MPAM registers.
+	 */
+	write_mpam3_el3(MPAM3_EL3_MPAMEN_BIT);
+
+	/*
+	 * If EL2 is implemented but unused, disable trapping to EL2 when lower
+	 * ELs access their own MPAM registers.
+	 * If EL2 is implemented and used, enable trapping to EL2.
+	 */
+	if (el2_unused) {
+		write_mpam2_el2(0);
+
+		if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U)
+			write_mpamhcr_el2(0);
+	} else {
+		write_mpam2_el2(MPAM2_EL2_TRAPMPAM0EL1 |
+				MPAM2_EL2_TRAPMPAM1EL1);
+
+		if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U) {
+			write_mpamhcr_el2(MPAMHCR_EL2_TRAP_MPAMIDR_EL1);
+		}
+	}
+}
diff --git a/lib/extensions/ras/ras_common.c b/lib/extensions/ras/ras_common.c
new file mode 100644
index 0000000..64a4852
--- /dev/null
+++ b/lib/extensions/ras/ras_common.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <bl31/ea_handle.h>
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <lib/extensions/ras.h>
+#include <lib/extensions/ras_arch.h>
+#include <plat/common/platform.h>
+
+#ifndef PLAT_RAS_PRI
+# error Platform must define RAS priority value
+#endif
+
+/* Handler that receives External Aborts on RAS-capable systems */
+int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+		void *handle, uint64_t flags)
+{
+	unsigned int i, n_handled = 0;
+	int probe_data, ret;
+	struct err_record_info *info;
+
+	const struct err_handler_data err_data = {
+		.version = ERR_HANDLER_VERSION,
+		.ea_reason = ea_reason,
+		.interrupt = 0,
+		.syndrome = (uint32_t) syndrome,
+		.flags = flags,
+		.cookie = cookie,
+		.handle = handle
+	};
+
+	for_each_err_record_info(i, info) {
+		assert(info->probe != NULL);
+		assert(info->handler != NULL);
+
+		/* Continue probing until the record group signals no error */
+		while (true) {
+			if (info->probe(info, &probe_data) == 0)
+				break;
+
+			/* Handle error */
+			ret = info->handler(info, probe_data, &err_data);
+			if (ret != 0)
+				return ret;
+
+			n_handled++;
+		}
+	}
+
+	return (n_handled != 0U) ? 1 : 0;
+}
+
+#if ENABLE_ASSERTIONS
+static void assert_interrupts_sorted(void)
+{
+	unsigned int i, last;
+	struct ras_interrupt *start = ras_interrupt_mappings.intrs;
+
+	if (ras_interrupt_mappings.num_intrs == 0UL)
+		return;
+
+	last = start[0].intr_number;
+	for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
+		assert(start[i].intr_number > last);
+		last = start[i].intr_number;
+	}
+}
+#endif
+
+/*
+ * Given an RAS interrupt number, locate the registered handler and call it. If
+ * no handler was found for the interrupt number, this function panics.
+ */
+static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
+		void *handle, void *cookie)
+{
+	struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
+	struct ras_interrupt *selected = NULL;
+	int probe_data = 0;
+	int start, end, mid, ret __unused;
+
+	const struct err_handler_data err_data = {
+		.version = ERR_HANDLER_VERSION,
+		.interrupt = intr_raw,
+		.flags = flags,
+		.cookie = cookie,
+		.handle = handle
+	};
+
+	assert(ras_interrupt_mappings.num_intrs > 0UL);
+
+	start = 0;
+	end = (int) ras_interrupt_mappings.num_intrs;
+	while (start <= end) {
+		mid = ((end + start) / 2);
+		if (intr_raw == ras_inrs[mid].intr_number) {
+			selected = &ras_inrs[mid];
+			break;
+		} else if (intr_raw < ras_inrs[mid].intr_number) {
+			/* Move left */
+			end = mid - 1;
+		} else {
+			/* Move right */
+			start = mid + 1;
+		}
+	}
+
+	if (selected == NULL) {
+		ERROR("RAS interrupt %u has no handler!\n", intr_raw);
+		panic();
+	}
+
+	if (selected->err_record->probe != NULL) {
+		ret = selected->err_record->probe(selected->err_record, &probe_data);
+		assert(ret != 0);
+	}
+
+	/* Call error handler for the record group */
+	assert(selected->err_record->handler != NULL);
+	(void) selected->err_record->handler(selected->err_record, probe_data,
+			&err_data);
+
+	return 0;
+}
+
+void __init ras_init(void)
+{
+#if ENABLE_ASSERTIONS
+	/* Check RAS interrupts are sorted */
+	assert_interrupts_sorted();
+#endif
+
+	/* Register RAS priority handler */
+	ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
+}
diff --git a/lib/extensions/ras/std_err_record.c b/lib/extensions/ras/std_err_record.c
new file mode 100644
index 0000000..c03fbbe
--- /dev/null
+++ b/lib/extensions/ras/std_err_record.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/extensions/ras_arch.h>
+#include <lib/utils_def.h>
+
+/*
+ * Probe for error in memory-mapped registers containing error records
+ * implemented Standard Error Record format. Upon detecting an error, set probe
+ * data to the index of the record in error, and return 1; otherwise, return 0.
+ */
+int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data)
+{
+	unsigned int num_records, num_group_regs, i;
+	uint64_t gsr;
+
+	assert(base != 0UL);
+
+	/* Only 4K supported for now */
+	assert(size_num_k == STD_ERR_NODE_SIZE_NUM_K);
+
+	num_records = (unsigned int)
+		(mmio_read_32(ERR_DEVID(base, size_num_k)) & ERR_DEVID_MASK);
+
+	/* A group register shows error status for 2^6 error records */
+	num_group_regs = (num_records >> 6U) + 1U;
+
+	/* Iterate through group registers to find a record in error */
+	for (i = 0; i < num_group_regs; i++) {
+		gsr = mmio_read_64(ERR_GSR(base, size_num_k, i));
+		if (gsr == 0ULL)
+			continue;
+
+		/* Return the index of the record in error */
+		if (probe_data != NULL)
+			*probe_data = (((int) (i << 6U)) + __builtin_ctzll(gsr));
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Probe for error in System Registers where error records are implemented in
+ * Standard Error Record format. Upon detecting an error, set probe data to the
+ * index of the record in error, and return 1; otherwise, return 0.
+ */
+int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data)
+{
+	unsigned int i;
+	uint64_t status;
+	unsigned int max_idx __unused =
+		((unsigned int) read_erridr_el1()) & ERRIDR_MASK;
+
+	assert(idx_start < max_idx);
+	assert(check_u32_overflow(idx_start, num_idx) == 0);
+	assert((idx_start + num_idx - 1U) < max_idx);
+
+	for (i = 0; i < num_idx; i++) {
+		/* Select the error record */
+		ser_sys_select_record(idx_start + i);
+
+		/* Retrieve status register from the error record */
+		status = read_erxstatus_el1();
+
+		/* Check for valid field in status */
+		if (ERR_STATUS_GET_FIELD(status, V) != 0U) {
+			if (probe_data != NULL)
+				*probe_data = (int) i;
+			return 1;
+		}
+	}
+
+	return 0;
+}
diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c
new file mode 100644
index 0000000..78876c6
--- /dev/null
+++ b/lib/extensions/spe/spe.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/extensions/spe.h>
+
+static inline void psb_csync(void)
+{
+	/*
+	 * The assembler does not yet understand the psb csync mnemonic
+	 * so use the equivalent hint instruction.
+	 */
+	__asm__ volatile("hint #17");
+}
+
+bool spe_supported(void)
+{
+	uint64_t features;
+
+	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT;
+	return (features & ID_AA64DFR0_PMS_MASK) == 1U;
+}
+
+void spe_enable(bool el2_unused)
+{
+	uint64_t v;
+
+	if (!spe_supported())
+		return;
+
+	if (el2_unused) {
+		/*
+		 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
+		 * profiling controls to EL2.
+		 *
+		 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
+		 * state. Accesses to profiling buffer controls at
+		 * Non-secure EL1 are not trapped to EL2.
+		 */
+		v = read_mdcr_el2();
+		v &= ~MDCR_EL2_TPMS;
+		v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
+		write_mdcr_el2(v);
+	}
+
+	/*
+	 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state
+	 * and disabled in secure state. Accesses to SPE registers at
+	 * S-EL1 generate trap exceptions to EL3.
+	 */
+	v = read_mdcr_el3();
+	v |= MDCR_NSPB(MDCR_NSPB_EL1);
+	write_mdcr_el3(v);
+}
+
+void spe_disable(void)
+{
+	uint64_t v;
+
+	if (!spe_supported())
+		return;
+
+	/* Drain buffered data */
+	psb_csync();
+	dsbnsh();
+
+	/* Disable profiling buffer */
+	v = read_pmblimitr_el1();
+	v &= ~(1ULL << 0);
+	write_pmblimitr_el1(v);
+	isb();
+}
+
+static void *spe_drain_buffers_hook(const void *arg)
+{
+	if (!spe_supported())
+		return (void *)-1;
+
+	/* Drain buffered data */
+	psb_csync();
+	dsbnsh();
+
+	return (void *)0;
+}
+
+SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);
diff --git a/lib/extensions/sve/sve.c b/lib/extensions/sve/sve.c
new file mode 100644
index 0000000..fa4ac77
--- /dev/null
+++ b/lib/extensions/sve/sve.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/extensions/sve.h>
+
+bool sve_supported(void)
+{
+	uint64_t features;
+
+	features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+	return (features & ID_AA64PFR0_SVE_MASK) == 1U;
+}
+
+static void *disable_sve_hook(const void *arg)
+{
+	uint64_t cptr;
+
+	if (!sve_supported())
+		return (void *)-1;
+
+	/*
+	 * Disable SVE, SIMD and FP access for the Secure world.
+	 * As the SIMD/FP registers are part of the SVE Z-registers, any
+	 * use of SIMD/FP functionality will corrupt the SVE registers.
+	 * Therefore it is necessary to prevent use of SIMD/FP support
+	 * in the Secure world as well as SVE functionality.
+	 */
+	cptr = read_cptr_el3();
+	cptr = (cptr | TFP_BIT) & ~(CPTR_EZ_BIT);
+	write_cptr_el3(cptr);
+
+	/*
+	 * No explicit ISB required here as ERET to switch to Secure
+	 * world covers it
+	 */
+	return (void *)0;
+}
+
+static void *enable_sve_hook(const void *arg)
+{
+	uint64_t cptr;
+
+	if (!sve_supported())
+		return (void *)-1;
+
+	/*
+	 * Enable SVE, SIMD and FP access for the Non-secure world.
+	 */
+	cptr = read_cptr_el3();
+	cptr = (cptr | CPTR_EZ_BIT) & ~(TFP_BIT);
+	write_cptr_el3(cptr);
+
+	/*
+	 * No explicit ISB required here as ERET to switch to Non-secure
+	 * world covers it
+	 */
+	return (void *)0;
+}
+
+void sve_enable(bool el2_unused)
+{
+	uint64_t cptr;
+
+	if (!sve_supported())
+		return;
+
+#if CTX_INCLUDE_FPREGS
+	/*
+	 * CTX_INCLUDE_FPREGS is not supported on SVE enabled systems.
+	 */
+	assert(0);
+#endif
+	/*
+	 * Update CPTR_EL3 to enable access to SVE functionality for the
+	 * Non-secure world.
+	 * NOTE - assumed that CPTR_EL3.TFP is set to allow access to
+	 * the SIMD, floating-point and SVE support.
+	 *
+	 * CPTR_EL3.EZ: Set to 1 to enable access to SVE  functionality
+	 *  in the Non-secure world.
+	 */
+	cptr = read_cptr_el3();
+	cptr |= CPTR_EZ_BIT;
+	write_cptr_el3(cptr);
+
+	/*
+	 * Need explicit ISB here to guarantee that update to ZCR_ELx
+	 * and CPTR_EL2.TZ do not result in trap to EL3.
+	 */
+	isb();
+
+	/*
+	 * Ensure lower ELs have access to full vector length.
+	 */
+	write_zcr_el3(ZCR_EL3_LEN_MASK);
+
+	if (el2_unused) {
+		/*
+		 * Update CPTR_EL2 to enable access to SVE functionality
+		 * for Non-secure world, EL2 and Non-secure EL1 and EL0.
+		 * NOTE - assumed that CPTR_EL2.TFP is set to allow
+		 * access to the SIMD, floating-point and SVE support.
+		 *
+		 * CPTR_EL2.TZ: Set to 0 to enable access to SVE support
+		 *  for EL2 and Non-secure EL1 and EL0.
+		 */
+		cptr = read_cptr_el2();
+		cptr &= ~(CPTR_EL2_TZ_BIT);
+		write_cptr_el2(cptr);
+
+		/*
+		 * Ensure lower ELs have access to full vector length.
+		 */
+		write_zcr_el2(ZCR_EL2_LEN_MASK);
+	}
+	/*
+	 * No explicit ISB required here as ERET to switch to
+	 * Non-secure world covers it.
+	 */
+}
+
+SUBSCRIBE_TO_EVENT(cm_exited_normal_world, disable_sve_hook);
+SUBSCRIBE_TO_EVENT(cm_entering_normal_world, enable_sve_hook);
diff --git a/lib/libc/aarch64/setjmp.S b/lib/libc/aarch64/setjmp.S
new file mode 100644
index 0000000..9d9eb49
--- /dev/null
+++ b/lib/libc/aarch64/setjmp.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <setjmp.h>
+
+	.globl	setjmp
+	.globl	longjmp
+
+/*
+ * int setjmp(jmp_buf env);
+ */
+func setjmp
+	mov	x7, sp
+
+	stp	x19, x20, [x0, #JMP_CTX_X19]
+	stp	x21, x22, [x0, #JMP_CTX_X21]
+	stp	x23, x24, [x0, #JMP_CTX_X23]
+	stp	x25, x26, [x0, #JMP_CTX_X25]
+	stp	x27, x28, [x0, #JMP_CTX_X27]
+	stp	x29, x30, [x0, #JMP_CTX_X29]
+	stp	x7, xzr, [x0, #JMP_CTX_SP]
+
+	mov	x0, #0
+	ret
+endfunc setjmp
+
+
+/*
+ * void longjmp(jmp_buf env, int val);
+ */
+func longjmp
+	ldp	x7, xzr, [x0, #JMP_CTX_SP]
+
+#if ENABLE_ASSERTIONS
+	/*
+	 * Since we're unwinding the stack, assert that the stack being reset to
+	 * is shallower.
+	 */
+	mov	x19, sp
+	cmp	x7, x19
+	ASM_ASSERT(ge)
+#endif
+
+	ldp	x19, x20, [x0, #JMP_CTX_X19]
+	ldp	x21, x22, [x0, #JMP_CTX_X21]
+	ldp	x23, x24, [x0, #JMP_CTX_X23]
+	ldp	x25, x26, [x0, #JMP_CTX_X25]
+	ldp	x27, x28, [x0, #JMP_CTX_X27]
+	ldp	x29, x30, [x0, #JMP_CTX_X29]
+
+	mov	sp, x7
+
+	ands	x0, x1, x1 /* Move val to x0 and set flags */
+	cinc	x0, x0, eq /* If val is 0, return 1 */
+	ret
+endfunc longjmp
diff --git a/lib/libc/abort.c b/lib/libc/abort.c
new file mode 100644
index 0000000..432b1d0
--- /dev/null
+++ b/lib/libc/abort.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <common/debug.h>
+
+void abort(void)
+{
+	ERROR("ABORT\n");
+	panic();
+}
diff --git a/lib/libc/assert.c b/lib/libc/assert.c
new file mode 100644
index 0000000..60f1a86
--- /dev/null
+++ b/lib/libc/assert.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+/*
+ * Only print the output if PLAT_LOG_LEVEL_ASSERT is higher or equal to
+ * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1.
+ */
+
+#if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE
+void __assert(const char *file, unsigned int line, const char *assertion)
+{
+	printf("ASSERT: %s:%d:%s\n", file, line, assertion);
+	backtrace("assert");
+	(void)console_flush();
+	plat_panic_handler();
+}
+#elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO
+void __assert(const char *file, unsigned int line)
+{
+	printf("ASSERT: %s:%d\n", file, line);
+	backtrace("assert");
+	(void)console_flush();
+	plat_panic_handler();
+}
+#else
+void __assert(void)
+{
+	backtrace("assert");
+	(void)console_flush();
+	plat_panic_handler();
+}
+#endif
diff --git a/lib/libc/exit.c b/lib/libc/exit.c
new file mode 100644
index 0000000..f4ffe27
--- /dev/null
+++ b/lib/libc/exit.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+static void (*exitfun)(void);
+
+void exit(int status)
+{
+	if (exitfun != NULL)
+		(*exitfun)();
+	for (;;)
+		;
+}
+
+int atexit(void (*fun)(void))
+{
+	if (exitfun != NULL)
+		return -1;
+	exitfun = fun;
+
+	return 0;
+}
diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk
new file mode 100644
index 0000000..e1b5560
--- /dev/null
+++ b/lib/libc/libc.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LIBC_SRCS	:=	$(addprefix lib/libc/,		\
+			abort.c				\
+			assert.c			\
+			exit.c				\
+			memchr.c			\
+			memcmp.c			\
+			memcpy.c			\
+			memmove.c			\
+			memset.c			\
+			printf.c			\
+			putchar.c			\
+			puts.c				\
+			snprintf.c			\
+			strchr.c			\
+			strcmp.c			\
+			strlcpy.c			\
+			strlen.c			\
+			strncmp.c			\
+			strnlen.c			\
+			strrchr.c)
+
+ifeq (${ARCH},aarch64)
+LIBC_SRCS	+=	$(addprefix lib/libc/aarch64/,	\
+			setjmp.S)
+endif
+
+INCLUDES	+=	-Iinclude/lib/libc		\
+			-Iinclude/lib/libc/$(ARCH)	\
diff --git a/lib/libc/memchr.c b/lib/libc/memchr.c
new file mode 100644
index 0000000..8cbb715
--- /dev/null
+++ b/lib/libc/memchr.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memchr(const void *src, int c, size_t len)
+{
+	const unsigned char *s = src;
+
+	while (len--) {
+		if (*s == (unsigned char)c)
+			return (void *) s;
+		s++;
+	}
+
+	return NULL;
+}
diff --git a/lib/libc/memcmp.c b/lib/libc/memcmp.c
new file mode 100644
index 0000000..cd5f0df
--- /dev/null
+++ b/lib/libc/memcmp.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+	const unsigned char *s = s1;
+	const unsigned char *d = s2;
+	unsigned char sc;
+	unsigned char dc;
+
+	while (len--) {
+		sc = *s++;
+		dc = *d++;
+		if (sc - dc)
+			return (sc - dc);
+	}
+
+	return 0;
+}
diff --git a/lib/libc/memcpy.c b/lib/libc/memcpy.c
new file mode 100644
index 0000000..158df9b
--- /dev/null
+++ b/lib/libc/memcpy.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+	const char *s = src;
+	char *d = dst;
+
+	while (len--)
+		*d++ = *s++;
+
+	return dst;
+}
diff --git a/lib/libc/memmove.c b/lib/libc/memmove.c
new file mode 100644
index 0000000..63acf26
--- /dev/null
+++ b/lib/libc/memmove.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t len)
+{
+	/*
+	 * The following test makes use of unsigned arithmetic overflow to
+	 * more efficiently test the condition !(src <= dst && dst < str+len).
+	 * It also avoids the situation where the more explicit test would give
+	 * incorrect results were the calculation str+len to overflow (though
+	 * that issue is probably moot as such usage is probably undefined
+	 * behaviour and a bug anyway.
+	 */
+	if ((size_t)dst - (size_t)src >= len) {
+		/* destination not in source data, so can safely use memcpy */
+		return memcpy(dst, src, len);
+	} else {
+		/* copy backwards... */
+		const char *end = dst;
+		const char *s = (const char *)src + len;
+		char *d = (char *)dst + len;
+		while (d != end)
+			*--d = *--s;
+	}
+	return dst;
+}
diff --git a/lib/libc/memset.c b/lib/libc/memset.c
new file mode 100644
index 0000000..d8007d8
--- /dev/null
+++ b/lib/libc/memset.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memset(void *dst, int val, size_t count)
+{
+	char *ptr = dst;
+
+	while (count--)
+		*ptr++ = val;
+
+	return dst;
+}
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
new file mode 100644
index 0000000..2715a72
--- /dev/null
+++ b/lib/libc/printf.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#define get_num_va_args(_args, _lcount)				\
+	(((_lcount) > 1)  ? va_arg(_args, long long int) :	\
+	(((_lcount) == 1) ? va_arg(_args, long int) :		\
+			    va_arg(_args, int)))
+
+#define get_unum_va_args(_args, _lcount)				\
+	(((_lcount) > 1)  ? va_arg(_args, unsigned long long int) :	\
+	(((_lcount) == 1) ? va_arg(_args, unsigned long int) :		\
+			    va_arg(_args, unsigned int)))
+
+static int string_print(const char *str)
+{
+	int count = 0;
+
+	assert(str != NULL);
+
+	for ( ; *str != '\0'; str++) {
+		(void)putchar(*str);
+		count++;
+	}
+
+	return count;
+}
+
+static int unsigned_num_print(unsigned long long int unum, unsigned int radix,
+			      char padc, int padn)
+{
+	/* Just need enough space to store 64 bit decimal integer */
+	char num_buf[20];
+	int i = 0, count = 0;
+	unsigned int rem;
+
+	do {
+		rem = unum % radix;
+		if (rem < 0xa)
+			num_buf[i] = '0' + rem;
+		else
+			num_buf[i] = 'a' + (rem - 0xa);
+		i++;
+		unum /= radix;
+	} while (unum > 0U);
+
+	if (padn > 0) {
+		while (i < padn) {
+			(void)putchar(padc);
+			count++;
+			padn--;
+		}
+	}
+
+	while (--i >= 0) {
+		(void)putchar(num_buf[i]);
+		count++;
+	}
+
+	return count;
+}
+
+/*******************************************************************
+ * Reduced format print for Trusted firmware.
+ * The following type specifiers are supported by this print
+ * %x - hexadecimal format
+ * %s - string format
+ * %d or %i - signed decimal format
+ * %u - unsigned decimal format
+ * %p - pointer format
+ *
+ * The following length specifiers are supported by this print
+ * %l - long int (64-bit on AArch64)
+ * %ll - long long int (64-bit on AArch64)
+ * %z - size_t sized integer formats (64 bit on AArch64)
+ *
+ * The following padding specifiers are supported by this print
+ * %0NN - Left-pad the number with 0s (NN is a decimal number)
+ *
+ * The print exits on all other formats specifiers other than valid
+ * combinations of the above specifiers.
+ *******************************************************************/
+int vprintf(const char *fmt, va_list args)
+{
+	int l_count;
+	long long int num;
+	unsigned long long int unum;
+	char *str;
+	char padc = '\0'; /* Padding character */
+	int padn; /* Number of characters to pad */
+	int count = 0; /* Number of printed characters */
+
+	while (*fmt != '\0') {
+		l_count = 0;
+		padn = 0;
+
+		if (*fmt == '%') {
+			fmt++;
+			/* Check the format specifier */
+loop:
+			switch (*fmt) {
+			case 'i': /* Fall through to next one */
+			case 'd':
+				num = get_num_va_args(args, l_count);
+				if (num < 0) {
+					(void)putchar('-');
+					unum = (unsigned long long int)-num;
+					padn--;
+				} else
+					unum = (unsigned long long int)num;
+
+				count += unsigned_num_print(unum, 10,
+							    padc, padn);
+				break;
+			case 's':
+				str = va_arg(args, char *);
+				count += string_print(str);
+				break;
+			case 'p':
+				unum = (uintptr_t)va_arg(args, void *);
+				if (unum > 0U) {
+					count += string_print("0x");
+					padn -= 2;
+				}
+
+				count += unsigned_num_print(unum, 16,
+							    padc, padn);
+				break;
+			case 'x':
+				unum = get_unum_va_args(args, l_count);
+				count += unsigned_num_print(unum, 16,
+							    padc, padn);
+				break;
+			case 'z':
+				if (sizeof(size_t) == 8U)
+					l_count = 2;
+
+				fmt++;
+				goto loop;
+			case 'l':
+				l_count++;
+				fmt++;
+				goto loop;
+			case 'u':
+				unum = get_unum_va_args(args, l_count);
+				count += unsigned_num_print(unum, 10,
+							    padc, padn);
+				break;
+			case '0':
+				padc = '0';
+				padn = 0;
+				fmt++;
+
+				for (;;) {
+					char ch = *fmt;
+					if ((ch < '0') || (ch > '9')) {
+						goto loop;
+					}
+					padn = (padn * 10) + (ch - '0');
+					fmt++;
+				}
+				assert(0); /* Unreachable */
+			default:
+				/* Exit on any other format specifier */
+				return -1;
+			}
+			fmt++;
+			continue;
+		}
+		(void)putchar(*fmt);
+		fmt++;
+		count++;
+	}
+
+	return count;
+}
+
+int printf(const char *fmt, ...)
+{
+	int count;
+	va_list va;
+
+	va_start(va, fmt);
+	count = vprintf(fmt, va);
+	va_end(va);
+
+	return count;
+}
diff --git a/lib/libc/putchar.c b/lib/libc/putchar.c
new file mode 100644
index 0000000..037e28a
--- /dev/null
+++ b/lib/libc/putchar.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+#include <drivers/console.h>
+
+int putchar(int c)
+{
+	int res;
+	if (console_putc((unsigned char)c) >= 0)
+		res = c;
+	else
+		res = EOF;
+
+	return res;
+}
diff --git a/lib/libc/puts.c b/lib/libc/puts.c
new file mode 100644
index 0000000..2a0ca11
--- /dev/null
+++ b/lib/libc/puts.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+int puts(const char *s)
+{
+	int count = 0;
+
+	while (*s != '\0') {
+		if (putchar(*s) == EOF)
+			return EOF;
+		s++;
+		count++;
+	}
+
+	if (putchar('\n') == EOF)
+		return EOF;
+
+	return count + 1;
+}
diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c
new file mode 100644
index 0000000..38ad1c7
--- /dev/null
+++ b/lib/libc/snprintf.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+static void string_print(char **s, size_t n, size_t *chars_printed,
+			 const char *str)
+{
+	while (*str != '\0') {
+		if (*chars_printed < n) {
+			*(*s) = *str;
+			(*s)++;
+		}
+
+		(*chars_printed)++;
+		str++;
+	}
+}
+
+static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
+			       unsigned int unum)
+{
+	/* Enough for a 32-bit unsigned decimal integer (4294967295). */
+	char num_buf[10];
+	int i = 0;
+	unsigned int rem;
+
+	do {
+		rem = unum % 10U;
+		num_buf[i++] = '0' + rem;
+		unum /= 10U;
+	} while (unum > 0U);
+
+	while (--i >= 0) {
+		if (*chars_printed < n) {
+			*(*s) = num_buf[i];
+			(*s)++;
+		}
+
+		(*chars_printed)++;
+	}
+}
+
+/*******************************************************************
+ * Reduced snprintf to be used for Trusted firmware.
+ * The following type specifiers are supported:
+ *
+ * %d or %i - signed decimal format
+ * %s - string format
+ * %u - unsigned decimal format
+ *
+ * The function panics on all other formats specifiers.
+ *
+ * It returns the number of characters that would be written if the
+ * buffer was big enough. If it returns a value lower than n, the
+ * whole string has been written.
+ *******************************************************************/
+int snprintf(char *s, size_t n, const char *fmt, ...)
+{
+	va_list args;
+	int num;
+	unsigned int unum;
+	char *str;
+	size_t chars_printed = 0U;
+
+	if (n == 0U) {
+		/* There isn't space for anything. */
+	} else if (n == 1U) {
+		/* Buffer is too small to actually write anything else. */
+		*s = '\0';
+		n = 0U;
+	} else {
+		/* Reserve space for the terminator character. */
+		n--;
+	}
+
+	va_start(args, fmt);
+	while (*fmt != '\0') {
+
+		if (*fmt == '%') {
+			fmt++;
+			/* Check the format specifier. */
+			switch (*fmt) {
+			case 'i':
+			case 'd':
+				num = va_arg(args, int);
+
+				if (num < 0) {
+					if (chars_printed < n) {
+						*s = '-';
+						s++;
+					}
+					chars_printed++;
+
+					unum = (unsigned int)-num;
+				} else {
+					unum = (unsigned int)num;
+				}
+
+				unsigned_dec_print(&s, n, &chars_printed, unum);
+				break;
+			case 's':
+				str = va_arg(args, char *);
+				string_print(&s, n, &chars_printed, str);
+				break;
+			case 'u':
+				unum = va_arg(args, unsigned int);
+				unsigned_dec_print(&s, n, &chars_printed, unum);
+				break;
+			default:
+				/* Panic on any other format specifier. */
+				ERROR("snprintf: specifier with ASCII code '%d' not supported.",
+				      *fmt);
+				plat_panic_handler();
+				assert(0); /* Unreachable */
+			}
+			fmt++;
+			continue;
+		}
+
+		if (chars_printed < n) {
+			*s = *fmt;
+			s++;
+		}
+
+		fmt++;
+		chars_printed++;
+	}
+
+	va_end(args);
+
+	if (n > 0U)
+		*s = '\0';
+
+	return (int)chars_printed;
+}
diff --git a/lib/libc/strchr.c b/lib/libc/strchr.c
new file mode 100644
index 0000000..d94bb9e
--- /dev/null
+++ b/lib/libc/strchr.c
@@ -0,0 +1,53 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+char *
+strchr(const char *p, int ch)
+{
+	char c;
+
+	c = ch;
+	for (;; ++p) {
+		if (*p == c)
+			return ((char *)p);
+		if (*p == '\0')
+			return (NULL);
+	}
+	/* NOTREACHED */
+}
diff --git a/lib/libc/strcmp.c b/lib/libc/strcmp.c
new file mode 100644
index 0000000..b742f9b
--- /dev/null
+++ b/lib/libc/strcmp.c
@@ -0,0 +1,52 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#include <string.h>
+
+/*
+ * Compare strings.
+ */
+int
+strcmp(const char *s1, const char *s2)
+{
+	while (*s1 == *s2++)
+		if (*s1++ == '\0')
+			return (0);
+	return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
+}
diff --git a/lib/libc/strlcpy.c b/lib/libc/strlcpy.c
new file mode 100644
index 0000000..c4f39bb
--- /dev/null
+++ b/lib/libc/strlcpy.c
@@ -0,0 +1,52 @@
+/*	$OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $	*/
+
+/*
+ * SPDX-License-Identifier: ISC
+ *
+ * Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Copy string src to buffer dst of size dsize.  At most dsize-1
+ * chars will be copied.  Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
+ */
+size_t
+strlcpy(char * dst, const char * src, size_t dsize)
+{
+	const char *osrc = src;
+	size_t nleft = dsize;
+
+	/* Copy as many bytes as will fit. */
+	if (nleft != 0) {
+		while (--nleft != 0) {
+			if ((*dst++ = *src++) == '\0')
+				break;
+		}
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src. */
+	if (nleft == 0) {
+		if (dsize != 0)
+			*dst = '\0';		/* NUL-terminate dst */
+		while (*src++)
+			;
+	}
+
+	return(src - osrc - 1);	/* count does not include NUL */
+}
diff --git a/lib/libc/strlen.c b/lib/libc/strlen.c
new file mode 100644
index 0000000..3c27630
--- /dev/null
+++ b/lib/libc/strlen.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+size_t strlen(const char *s)
+{
+	const char *cursor = s;
+
+	while (*cursor)
+		cursor++;
+
+	return cursor - s;
+}
diff --git a/lib/libc/strncmp.c b/lib/libc/strncmp.c
new file mode 100644
index 0000000..ce9e5ed
--- /dev/null
+++ b/lib/libc/strncmp.c
@@ -0,0 +1,53 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#include <string.h>
+
+int
+strncmp(const char *s1, const char *s2, size_t n)
+{
+
+	if (n == 0)
+		return (0);
+	do {
+		if (*s1 != *s2++)
+			return (*(const unsigned char *)s1 -
+				*(const unsigned char *)(s2 - 1));
+		if (*s1++ == '\0')
+			break;
+	} while (--n != 0);
+	return (0);
+}
diff --git a/lib/libc/strnlen.c b/lib/libc/strnlen.c
new file mode 100644
index 0000000..b944e95
--- /dev/null
+++ b/lib/libc/strnlen.c
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2009 David Schultz <das@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions copyright (c) 2018, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#include <string.h>
+
+size_t
+strnlen(const char *s, size_t maxlen)
+{
+	size_t len;
+
+	for (len = 0; len < maxlen; len++, s++) {
+		if (!*s)
+			break;
+	}
+	return (len);
+}
diff --git a/lib/libc/strrchr.c b/lib/libc/strrchr.c
new file mode 100644
index 0000000..cd435ff
--- /dev/null
+++ b/lib/libc/strrchr.c
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1988, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+char *
+strrchr(const char *p, int ch)
+{
+	char *save;
+	char c;
+
+	c = ch;
+	for (save = NULL;; ++p) {
+		if (*p == c)
+			save = (char *)p;
+		if (*p == '\0')
+			return (save);
+	}
+	/* NOTREACHED */
+}
diff --git a/lib/libfdt/libfdt b/lib/libfdt/libfdt
new file mode 120000
index 0000000..b5668df
--- /dev/null
+++ b/lib/libfdt/libfdt
@@ -0,0 +1 @@
+../../../dtc/libfdt
\ No newline at end of file
diff --git a/lib/libfdt/libfdt.mk b/lib/libfdt/libfdt.mk
new file mode 100644
index 0000000..ff49b66
--- /dev/null
+++ b/lib/libfdt/libfdt.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LIBFDT_SRCS	:=	$(addprefix lib/libfdt/libfdt/,	\
+			fdt.c				\
+			fdt_addresses.c			\
+			fdt_empty_tree.c		\
+			fdt_ro.c			\
+			fdt_rw.c			\
+			fdt_strerror.c			\
+			fdt_sw.c			\
+			fdt_wip.c)			\
+
+INCLUDES	+=	-Ilib/libfdt/libfdt
+
+$(eval $(call MAKE_LIB,fdt))
diff --git a/lib/locks/bakery/bakery_lock_coherent.c b/lib/locks/bakery/bakery_lock_coherent.c
new file mode 100644
index 0000000..1634e3a
--- /dev/null
+++ b/lib/locks/bakery/bakery_lock_coherent.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <plat/common/platform.h>
+
+/*
+ * Functions in this file implement Bakery Algorithm for mutual exclusion with the
+ * bakery lock data structures in coherent memory.
+ *
+ * ARM architecture offers a family of exclusive access instructions to
+ * efficiently implement mutual exclusion with hardware support. However, as
+ * well as depending on external hardware, the these instructions have defined
+ * behavior only on certain memory types (cacheable and Normal memory in
+ * particular; see ARMv8 Architecture Reference Manual section B2.10). Use cases
+ * in trusted firmware are such that mutual exclusion implementation cannot
+ * expect that accesses to the lock have the specific type required by the
+ * architecture for these primitives to function (for example, not all
+ * contenders may have address translation enabled).
+ *
+ * This implementation does not use mutual exclusion primitives. It expects
+ * memory regions where the locks reside to be fully ordered and coherent
+ * (either by disabling address translation, or by assigning proper attributes
+ * when translation is enabled).
+ *
+ * Note that the ARM architecture guarantees single-copy atomicity for aligned
+ * accesses regardless of status of address translation.
+ */
+
+#define assert_bakery_entry_valid(_entry, _bakery) do {	\
+	assert((_bakery) != NULL);			\
+	assert((_entry) < BAKERY_LOCK_MAX_CPUS);	\
+} while (false)
+
+/* Obtain a ticket for a given CPU */
+static unsigned int bakery_get_ticket(bakery_lock_t *bakery, unsigned int me)
+{
+	unsigned int my_ticket, their_ticket;
+	unsigned int they;
+
+	/* Prevent recursive acquisition */
+	assert(bakery_ticket_number(bakery->lock_data[me]) == 0U);
+
+	/*
+	 * Flag that we're busy getting our ticket. All CPUs are iterated in the
+	 * order of their ordinal position to decide the maximum ticket value
+	 * observed so far. Our priority is set to be greater than the maximum
+	 * observed priority
+	 *
+	 * Note that it's possible that more than one contender gets the same
+	 * ticket value. That's OK as the lock is acquired based on the priority
+	 * value, not the ticket value alone.
+	 */
+	my_ticket = 0U;
+	bakery->lock_data[me] = make_bakery_data(CHOOSING_TICKET, my_ticket);
+	for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) {
+		their_ticket = bakery_ticket_number(bakery->lock_data[they]);
+		if (their_ticket > my_ticket)
+			my_ticket = their_ticket;
+	}
+
+	/*
+	 * Compute ticket; then signal to other contenders waiting for us to
+	 * finish calculating our ticket value that we're done
+	 */
+	++my_ticket;
+	bakery->lock_data[me] = make_bakery_data(CHOSEN_TICKET, my_ticket);
+
+	return my_ticket;
+}
+
+
+/*
+ * Acquire bakery lock
+ *
+ * Contending CPUs need first obtain a non-zero ticket and then calculate
+ * priority value. A contending CPU iterate over all other CPUs in the platform,
+ * which may be contending for the same lock, in the order of their ordinal
+ * position (CPU0, CPU1 and so on). A non-contending CPU will have its ticket
+ * (and priority) value as 0. The contending CPU compares its priority with that
+ * of others'. The CPU with the highest priority (lowest numerical value)
+ * acquires the lock
+ */
+void bakery_lock_get(bakery_lock_t *bakery)
+{
+	unsigned int they, me;
+	unsigned int my_ticket, my_prio, their_ticket;
+	unsigned int their_bakery_data;
+
+	me = plat_my_core_pos();
+
+	assert_bakery_entry_valid(me, bakery);
+
+	/* Get a ticket */
+	my_ticket = bakery_get_ticket(bakery, me);
+
+	/*
+	 * Now that we got our ticket, compute our priority value, then compare
+	 * with that of others, and proceed to acquire the lock
+	 */
+	my_prio = bakery_get_priority(my_ticket, me);
+	for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) {
+		if (me == they)
+			continue;
+
+		/* Wait for the contender to get their ticket */
+		do {
+			their_bakery_data = bakery->lock_data[they];
+		} while (bakery_is_choosing(their_bakery_data));
+
+		/*
+		 * If the other party is a contender, they'll have non-zero
+		 * (valid) ticket value. If they do, compare priorities
+		 */
+		their_ticket = bakery_ticket_number(their_bakery_data);
+		if ((their_ticket != 0U) &&
+		    (bakery_get_priority(their_ticket, they) < my_prio)) {
+			/*
+			 * They have higher priority (lower value). Wait for
+			 * their ticket value to change (either release the lock
+			 * to have it dropped to 0; or drop and probably content
+			 * again for the same lock to have an even higher value)
+			 */
+			do {
+				wfe();
+			} while (their_ticket ==
+				bakery_ticket_number(bakery->lock_data[they]));
+		}
+	}
+
+	/*
+	 * Lock acquired. Ensure that any reads from a shared resource in the
+	 * critical section read values after the lock is acquired.
+	 */
+	dmbld();
+}
+
+
+/* Release the lock and signal contenders */
+void bakery_lock_release(bakery_lock_t *bakery)
+{
+	unsigned int me = plat_my_core_pos();
+
+	assert_bakery_entry_valid(me, bakery);
+	assert(bakery_ticket_number(bakery->lock_data[me]) != 0U);
+
+	/*
+	 * Ensure that other observers see any stores in the critical section
+	 * before releasing the lock. Release the lock by resetting ticket.
+	 * Then signal other waiting contenders.
+	 */
+	dmbst();
+	bakery->lock_data[me] = 0U;
+	dsb();
+	sev();
+}
diff --git a/lib/locks/bakery/bakery_lock_normal.c b/lib/locks/bakery/bakery_lock_normal.c
new file mode 100644
index 0000000..f906f51
--- /dev/null
+++ b/lib/locks/bakery/bakery_lock_normal.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+/*
+ * Functions in this file implement Bakery Algorithm for mutual exclusion with the
+ * bakery lock data structures in cacheable and Normal memory.
+ *
+ * ARM architecture offers a family of exclusive access instructions to
+ * efficiently implement mutual exclusion with hardware support. However, as
+ * well as depending on external hardware, these instructions have defined
+ * behavior only on certain memory types (cacheable and Normal memory in
+ * particular; see ARMv8 Architecture Reference Manual section B2.10). Use cases
+ * in trusted firmware are such that mutual exclusion implementation cannot
+ * expect that accesses to the lock have the specific type required by the
+ * architecture for these primitives to function (for example, not all
+ * contenders may have address translation enabled).
+ *
+ * This implementation does not use mutual exclusion primitives. It expects
+ * memory regions where the locks reside to be cacheable and Normal.
+ *
+ * Note that the ARM architecture guarantees single-copy atomicity for aligned
+ * accesses regardless of status of address translation.
+ */
+
+#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
+/*
+ * Verify that the platform defined value for the per-cpu space for bakery locks is
+ * a multiple of the cache line size, to prevent multiple CPUs writing to the same
+ * bakery lock cache line
+ *
+ * Using this value, if provided, rather than the linker generated value results in
+ * more efficient code
+ */
+CASSERT((PLAT_PERCPU_BAKERY_LOCK_SIZE & (CACHE_WRITEBACK_GRANULE - 1)) == 0, \
+	PLAT_PERCPU_BAKERY_LOCK_SIZE_not_cacheline_multiple);
+#define PERCPU_BAKERY_LOCK_SIZE (PLAT_PERCPU_BAKERY_LOCK_SIZE)
+#else
+/*
+ * Use the linker defined symbol which has evaluated the size reqiurement.
+ * This is not as efficient as using a platform defined constant
+ */
+IMPORT_SYM(uintptr_t, __PERCPU_BAKERY_LOCK_START__, BAKERY_LOCK_START);
+IMPORT_SYM(uintptr_t, __PERCPU_BAKERY_LOCK_END__, BAKERY_LOCK_END);
+#define PERCPU_BAKERY_LOCK_SIZE (BAKERY_LOCK_END - BAKERY_LOCK_START)
+#endif
+
+static inline bakery_lock_t *get_bakery_info(unsigned int cpu_ix,
+					     bakery_lock_t *lock)
+{
+	return (bakery_info_t *)((uintptr_t)lock +
+				cpu_ix * PERCPU_BAKERY_LOCK_SIZE);
+}
+
+static inline void write_cache_op(uintptr_t addr, bool cached)
+{
+	if (cached)
+		dccvac(addr);
+	else
+		dcivac(addr);
+
+	dsbish();
+}
+
+static inline void read_cache_op(uintptr_t addr, bool cached)
+{
+	if (cached)
+		dccivac(addr);
+}
+
+/* Helper function to check if the lock is acquired */
+static inline bool is_lock_acquired(const bakery_info_t *my_bakery_info,
+							int is_cached)
+{
+	/*
+	 * Even though lock data is updated only by the owning cpu and
+	 * appropriate cache maintenance operations are performed,
+	 * if the previous update was done when the cpu was not participating
+	 * in coherency, then there is a chance that cache maintenance
+	 * operations were not propagated to all the caches in the system.
+	 * Hence do a `read_cache_op()` prior to read.
+	 */
+	read_cache_op((uintptr_t)my_bakery_info, is_cached);
+	return bakery_ticket_number(my_bakery_info->lock_data) != 0U;
+}
+
+static unsigned int bakery_get_ticket(bakery_lock_t *lock,
+						unsigned int me, int is_cached)
+{
+	unsigned int my_ticket, their_ticket;
+	unsigned int they;
+	bakery_info_t *my_bakery_info, *their_bakery_info;
+
+	/*
+	 * Obtain a reference to the bakery information for this cpu and ensure
+	 * it is not NULL.
+	 */
+	my_bakery_info = get_bakery_info(me, lock);
+	assert(my_bakery_info != NULL);
+
+	/* Prevent recursive acquisition.*/
+	assert(!is_lock_acquired(my_bakery_info, is_cached));
+
+	/*
+	 * Tell other contenders that we are through the bakery doorway i.e.
+	 * going to allocate a ticket for this cpu.
+	 */
+	my_ticket = 0U;
+	my_bakery_info->lock_data = make_bakery_data(CHOOSING_TICKET, my_ticket);
+
+	write_cache_op((uintptr_t)my_bakery_info, is_cached);
+
+	/*
+	 * Iterate through the bakery information of each contender to allocate
+	 * the highest ticket number for this cpu.
+	 */
+	for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) {
+		if (me == they)
+			continue;
+
+		/*
+		 * Get a reference to the other contender's bakery info and
+		 * ensure that a stale copy is not read.
+		 */
+		their_bakery_info = get_bakery_info(they, lock);
+		assert(their_bakery_info != NULL);
+
+		read_cache_op((uintptr_t)their_bakery_info, is_cached);
+
+		/*
+		 * Update this cpu's ticket number if a higher ticket number is
+		 * seen
+		 */
+		their_ticket = bakery_ticket_number(their_bakery_info->lock_data);
+		if (their_ticket > my_ticket)
+			my_ticket = their_ticket;
+	}
+
+	/*
+	 * Compute ticket; then signal to other contenders waiting for us to
+	 * finish calculating our ticket value that we're done
+	 */
+	++my_ticket;
+	my_bakery_info->lock_data = make_bakery_data(CHOSEN_TICKET, my_ticket);
+
+	write_cache_op((uintptr_t)my_bakery_info, is_cached);
+
+	return my_ticket;
+}
+
+void bakery_lock_get(bakery_lock_t *lock)
+{
+	unsigned int they, me, is_cached;
+	unsigned int my_ticket, my_prio, their_ticket;
+	bakery_info_t *their_bakery_info;
+	unsigned int their_bakery_data;
+
+	me = plat_my_core_pos();
+#ifdef __aarch64__
+	is_cached = read_sctlr_el3() & SCTLR_C_BIT;
+#else
+	is_cached = read_sctlr() & SCTLR_C_BIT;
+#endif
+
+	/* Get a ticket */
+	my_ticket = bakery_get_ticket(lock, me, is_cached);
+
+	/*
+	 * Now that we got our ticket, compute our priority value, then compare
+	 * with that of others, and proceed to acquire the lock
+	 */
+	my_prio = bakery_get_priority(my_ticket, me);
+	for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) {
+		if (me == they)
+			continue;
+
+		/*
+		 * Get a reference to the other contender's bakery info and
+		 * ensure that a stale copy is not read.
+		 */
+		their_bakery_info = get_bakery_info(they, lock);
+		assert(their_bakery_info != NULL);
+
+		/* Wait for the contender to get their ticket */
+		do {
+			read_cache_op((uintptr_t)their_bakery_info, is_cached);
+			their_bakery_data = their_bakery_info->lock_data;
+		} while (bakery_is_choosing(their_bakery_data));
+
+		/*
+		 * If the other party is a contender, they'll have non-zero
+		 * (valid) ticket value. If they do, compare priorities
+		 */
+		their_ticket = bakery_ticket_number(their_bakery_data);
+		if (their_ticket && (bakery_get_priority(their_ticket, they) < my_prio)) {
+			/*
+			 * They have higher priority (lower value). Wait for
+			 * their ticket value to change (either release the lock
+			 * to have it dropped to 0; or drop and probably content
+			 * again for the same lock to have an even higher value)
+			 */
+			do {
+				wfe();
+				read_cache_op((uintptr_t)their_bakery_info, is_cached);
+			} while (their_ticket
+				== bakery_ticket_number(their_bakery_info->lock_data));
+		}
+	}
+
+	/*
+	 * Lock acquired. Ensure that any reads from a shared resource in the
+	 * critical section read values after the lock is acquired.
+	 */
+	dmbld();
+}
+
+void bakery_lock_release(bakery_lock_t *lock)
+{
+	bakery_info_t *my_bakery_info;
+#ifdef __aarch64__
+	unsigned int is_cached = read_sctlr_el3() & SCTLR_C_BIT;
+#else
+	unsigned int is_cached = read_sctlr() & SCTLR_C_BIT;
+#endif
+
+	my_bakery_info = get_bakery_info(plat_my_core_pos(), lock);
+
+	assert(is_lock_acquired(my_bakery_info, is_cached));
+
+	/*
+	 * Ensure that other observers see any stores in the critical section
+	 * before releasing the lock. Release the lock by resetting ticket.
+	 * Then signal other waiting contenders.
+	 */
+	dmbst();
+	my_bakery_info->lock_data = 0U;
+	write_cache_op((uintptr_t)my_bakery_info, is_cached);
+	sev();
+}
diff --git a/lib/locks/exclusive/aarch32/spinlock.S b/lib/locks/exclusive/aarch32/spinlock.S
new file mode 100644
index 0000000..9492cc0
--- /dev/null
+++ b/lib/locks/exclusive/aarch32/spinlock.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	spin_lock
+	.globl	spin_unlock
+
+#if ARM_ARCH_AT_LEAST(8, 0)
+/*
+ * According to the ARMv8-A Architecture Reference Manual, "when the global
+ * monitor for a PE changes from Exclusive Access state to Open Access state,
+ * an event is generated.". This applies to both AArch32 and AArch64 modes of
+ * ARMv8-A. As a result, no explicit SEV with unlock is required.
+ */
+#define COND_SEV()
+#else
+#define COND_SEV()	sev
+#endif
+
+func spin_lock
+	mov	r2, #1
+1:
+	ldrex	r1, [r0]
+	cmp	r1, #0
+	wfene
+	strexeq	r1, r2, [r0]
+	cmpeq	r1, #0
+	bne	1b
+	dmb
+	bx	lr
+endfunc spin_lock
+
+
+func spin_unlock
+	mov	r1, #0
+	stl	r1, [r0]
+	COND_SEV()
+	bx	lr
+endfunc spin_unlock
diff --git a/lib/locks/exclusive/aarch64/spinlock.S b/lib/locks/exclusive/aarch64/spinlock.S
new file mode 100644
index 0000000..d0569f1
--- /dev/null
+++ b/lib/locks/exclusive/aarch64/spinlock.S
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	spin_lock
+	.globl	spin_unlock
+
+#if ARM_ARCH_AT_LEAST(8, 1)
+
+/*
+ * When compiled for ARMv8.1 or later, choose spin locks based on Compare and
+ * Swap instruction.
+ */
+# define USE_CAS	1
+
+/*
+ * Lock contenders using CAS, upon failing to acquire the lock, wait with the
+ * monitor in open state. Therefore, a normal store upon unlocking won't
+ * generate an SEV. Use explicit SEV instruction with CAS unlock.
+ */
+# define COND_SEV()	sev
+
+#else
+
+# define USE_CAS	0
+
+/*
+ * Lock contenders using exclusive pairs, upon failing to acquire the lock, wait
+ * with the monitor in exclusive state. A normal store upon unlocking will
+ * implicitly generate an envent; so, no explicit SEV with unlock is required.
+ */
+# define COND_SEV()
+
+#endif
+
+#if USE_CAS
+
+/*
+ * Acquire lock using Compare and Swap instruction.
+ *
+ * Compare for 0 with acquire semantics, and swap 1. Wait until CAS returns
+ * 0.
+ *
+ * void spin_lock(spinlock_t *lock);
+ */
+func spin_lock
+	mov	w2, #1
+	sevl
+1:
+	wfe
+	mov	w1, wzr
+	casa	w1, w2, [x0]
+	cbnz	w1, 1b
+	ret
+endfunc spin_lock
+
+#else /* !USE_CAS */
+
+/*
+ * Acquire lock using load-/store-exclusive instruction pair.
+ *
+ * void spin_lock(spinlock_t *lock);
+ */
+func spin_lock
+	mov	w2, #1
+	sevl
+l1:	wfe
+l2:	ldaxr	w1, [x0]
+	cbnz	w1, l1
+	stxr	w1, w2, [x0]
+	cbnz	w1, l2
+	ret
+endfunc spin_lock
+
+#endif /* USE_CAS */
+
+/*
+ * Release lock previously acquired by spin_lock.
+ *
+ * Unconditionally write 0, and conditionally generate an event.
+ *
+ * void spin_unlock(spinlock_t *lock);
+ */
+func spin_unlock
+	stlr	wzr, [x0]
+	COND_SEV()
+	ret
+endfunc spin_unlock
diff --git a/lib/optee/optee_utils.c b/lib/optee/optee_utils.c
new file mode 100644
index 0000000..2a40793
--- /dev/null
+++ b/lib/optee/optee_utils.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <lib/optee_utils.h>
+
+/*
+ * load_addr_hi and load_addr_lo: image load address.
+ * image_id: 0 - pager, 1 - paged
+ * size: image size in bytes.
+ */
+typedef struct optee_image {
+	uint32_t load_addr_hi;
+	uint32_t load_addr_lo;
+	uint32_t image_id;
+	uint32_t size;
+} optee_image_t;
+
+#define OPTEE_PAGER_IMAGE_ID		0
+#define OPTEE_PAGED_IMAGE_ID		1
+
+#define OPTEE_MAX_NUM_IMAGES		2u
+
+#define TEE_MAGIC_NUM_OPTEE		0x4554504f
+/*
+ * magic: header magic number.
+ * version: OPTEE header version:
+ *		1 - not supported
+ *		2 - supported
+ * arch: OPTEE os architecture type: 0 - AARCH32, 1 - AARCH64.
+ * flags: unused currently.
+ * nb_images: number of images.
+ */
+typedef struct optee_header {
+	uint32_t magic;
+	uint8_t version;
+	uint8_t arch;
+	uint16_t flags;
+	uint32_t nb_images;
+	optee_image_t optee_image_list[];
+} optee_header_t;
+
+/*******************************************************************************
+ * Check if it is a valid tee header
+ * Return 1 if valid
+ * Return 0 if invalid
+ ******************************************************************************/
+static inline int tee_validate_header(optee_header_t *header)
+{
+	int valid = 0;
+
+	if ((header->magic == TEE_MAGIC_NUM_OPTEE) &&
+		(header->version == 2u) &&
+		(header->nb_images > 0u) &&
+		(header->nb_images <= OPTEE_MAX_NUM_IMAGES)) {
+		valid = 1;
+	}
+
+	else {
+		WARN("Not a known TEE, use default loading options.\n");
+	}
+
+	return valid;
+}
+
+/*******************************************************************************
+ * Parse the OPTEE image
+ * Return 0 on success or a negative error code otherwise.
+ ******************************************************************************/
+static int parse_optee_image(image_info_t *image_info,
+		optee_image_t *image)
+{
+	uintptr_t init_load_addr, free_end, requested_end;
+	size_t init_size;
+
+	init_load_addr = ((uint64_t)image->load_addr_hi << 32) |
+					image->load_addr_lo;
+	init_size = image->size;
+
+	/*
+	 * -1 indicates loader decided address; take our pre-mapped area
+	 * for current image since arm-tf could not allocate memory dynamically
+	 */
+	if (init_load_addr == -1)
+		init_load_addr = image_info->image_base;
+
+	/* Check that the default end address doesn't overflow */
+	if (check_uptr_overflow(image_info->image_base,
+				image_info->image_max_size - 1))
+		return -1;
+	free_end = image_info->image_base + (image_info->image_max_size - 1);
+
+	/* Check that the image end address doesn't overflow */
+	if (check_uptr_overflow(init_load_addr, init_size - 1))
+		return -1;
+	requested_end = init_load_addr + (init_size - 1);
+	/*
+	 * Check that the requested RAM location is within reserved
+	 * space for OPTEE.
+	 */
+	if (!((init_load_addr >= image_info->image_base) &&
+			(requested_end <= free_end))) {
+		WARN("The load address in optee header %p - %p is not in reserved area: %p - %p.\n",
+				(void *)init_load_addr,
+				(void *)(init_load_addr + init_size),
+				(void *)image_info->image_base,
+				(void *)(image_info->image_base +
+					image_info->image_max_size));
+		return -1;
+	}
+
+	/*
+	 * Remove the skip attr from image_info, the image will be loaded.
+	 * The default attr in image_info is "IMAGE_ATTRIB_SKIP_LOADING", which
+	 * mean the image will not be loaded. Here, we parse the header image to
+	 * know that the extra image need to be loaded, so remove the skip attr.
+	 */
+	image_info->h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+
+	/* Update image base and size of image_info */
+	image_info->image_base = init_load_addr;
+	image_info->image_size = init_size;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Parse the OPTEE header
+ * Return 0 on success or a negative error code otherwise.
+ ******************************************************************************/
+int parse_optee_header(entry_point_info_t *header_ep,
+		image_info_t *pager_image_info,
+		image_info_t *paged_image_info)
+
+{
+	optee_header_t *header;
+	int num, ret;
+
+	assert(header_ep);
+	header = (optee_header_t *)header_ep->pc;
+	assert(header);
+
+	/* Print the OPTEE header information */
+	INFO("OPTEE ep=0x%x\n", (unsigned int)header_ep->pc);
+	INFO("OPTEE header info:\n");
+	INFO("      magic=0x%x\n", header->magic);
+	INFO("      version=0x%x\n", header->version);
+	INFO("      arch=0x%x\n", header->arch);
+	INFO("      flags=0x%x\n", header->flags);
+	INFO("      nb_images=0x%x\n", header->nb_images);
+
+	/*
+	 * OPTEE image has 3 types:
+	 *
+	 * 1. Plain OPTEE bin without header.
+	 *	Original bin without header, return directly,
+	 *	BL32_EXTRA1_IMAGE_ID and BL32_EXTRA2_IMAGE_ID will be skipped.
+	 *
+	 * 2. OPTEE bin with header bin, but no paging.
+	 *	Header available and nb_images = 1, remove skip attr for
+	 *	BL32_EXTRA1_IMAGE_ID. BL32_EXTRA1_IMAGE_ID will be loaded,
+	 *	and BL32_EXTRA2_IMAGE_ID be skipped.
+	 *
+	 * 3. OPTEE image with paging support.
+	 *	Header available and nb_images = 2, there are 3 bins: header,
+	 *	pager and pageable. Remove skip attr for BL32_EXTRA1_IMAGE_ID
+	 *	and BL32_EXTRA2_IMAGE_ID to load pager and paged bin.
+	 */
+	if (!tee_validate_header(header)) {
+		INFO("Invalid OPTEE header, set legacy mode.\n");
+#ifdef __aarch64__
+		header_ep->args.arg0 = MODE_RW_64;
+#else
+		header_ep->args.arg0 = MODE_RW_32;
+#endif
+		return 0;
+	}
+
+	/* Parse OPTEE image */
+	for (num = 0; num < header->nb_images; num++) {
+		if (header->optee_image_list[num].image_id ==
+				OPTEE_PAGER_IMAGE_ID) {
+			ret = parse_optee_image(pager_image_info,
+				&header->optee_image_list[num]);
+		} else if (header->optee_image_list[num].image_id ==
+				OPTEE_PAGED_IMAGE_ID) {
+			ret = parse_optee_image(paged_image_info,
+				&header->optee_image_list[num]);
+		} else {
+			ERROR("Parse optee image failed.\n");
+			return -1;
+		}
+
+		if (ret != 0)
+			return -1;
+	}
+
+	/*
+	 * Update "pc" value which should comes from pager image. After the
+	 * header image is parsed, it will be unuseful, and the actual
+	 * execution image after BL31 is pager image.
+	 */
+	header_ep->pc =	pager_image_info->image_base;
+
+	/*
+	 * The paged load address and size are populated in
+	 * header image arguments so that can be read by the
+	 * BL32 SPD.
+	 */
+	header_ep->args.arg1 = paged_image_info->image_base;
+	header_ep->args.arg2 = paged_image_info->image_size;
+
+	/* Set OPTEE runtime arch - aarch32/aarch64 */
+	if (header->arch == 0) {
+		header_ep->args.arg0 = MODE_RW_32;
+	} else {
+#ifdef __aarch64__
+		header_ep->args.arg0 = MODE_RW_64;
+#else
+		ERROR("Cannot boot an AArch64 OP-TEE\n");
+		return -1;
+#endif
+	}
+
+	return 0;
+}
diff --git a/lib/pmf/pmf_main.c b/lib/pmf/pmf_main.c
new file mode 100644
index 0000000..131a055
--- /dev/null
+++ b/lib/pmf/pmf_main.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * The 'pmf_svc_descs' array holds the PMF service descriptors exported by
+ * services by placing them in the 'pmf_svc_descs' linker section.
+ * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the
+ * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used
+ * to get an index into the 'pmf_svc_descs_indices' array. This gives the
+ * index of the descriptor in the 'pmf_svc_descs' array  which contains the
+ * service function pointers.
+ ******************************************************************************/
+
+IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_START__,		PMF_SVC_DESCS_START);
+IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_END__,		PMF_SVC_DESCS_END);
+IMPORT_SYM(uintptr_t, __PMF_PERCPU_TIMESTAMP_END__,	PMF_PERCPU_TIMESTAMP_END);
+IMPORT_SYM(uintptr_t,  __PMF_TIMESTAMP_START__,		PMF_TIMESTAMP_ARRAY_START);
+
+#define PMF_PERCPU_TIMESTAMP_SIZE	(PMF_PERCPU_TIMESTAMP_END - PMF_TIMESTAMP_ARRAY_START)
+
+#define PMF_SVC_DESCS_MAX		10
+
+/*
+ * This is used to traverse through registered PMF services.
+ */
+static pmf_svc_desc_t *pmf_svc_descs;
+
+/*
+ * This array is used to store registered PMF services in sorted order.
+ */
+static int pmf_svc_descs_indices[PMF_SVC_DESCS_MAX];
+
+/*
+ * This is used to track total number of successfully registered PMF services.
+ */
+static int pmf_num_services;
+
+/*
+ * This is the main PMF function that initialize registered
+ * PMF services and also sort them in ascending order.
+ */
+int pmf_setup(void)
+{
+	int rc, ii, jj = 0;
+	int pmf_svc_descs_num, temp_val;
+
+	/* If no PMF services are registered then simply bail out */
+	pmf_svc_descs_num = (PMF_SVC_DESCS_END - PMF_SVC_DESCS_START)/
+				 sizeof(pmf_svc_desc_t);
+	if (pmf_svc_descs_num == 0)
+		return 0;
+
+	assert(pmf_svc_descs_num < PMF_SVC_DESCS_MAX);
+
+	pmf_svc_descs = (pmf_svc_desc_t *) PMF_SVC_DESCS_START;
+	for (ii = 0; ii < pmf_svc_descs_num; ii++) {
+
+		assert(pmf_svc_descs[ii].get_ts != NULL);
+
+		/*
+		 * Call the initialization routine for this
+		 * PMF service, if it is defined.
+		 */
+		if (pmf_svc_descs[ii].init != NULL) {
+			rc = pmf_svc_descs[ii].init();
+			if (rc != 0) {
+				WARN("Could not initialize PMF"
+					"service %s - skipping \n",
+					pmf_svc_descs[ii].name);
+				continue;
+			}
+		}
+
+		/* Update the pmf_svc_descs_indices array */
+		pmf_svc_descs_indices[jj++] = ii;
+	}
+
+	pmf_num_services = jj;
+
+	/*
+	 * Sort the successfully registered PMF services
+	 * according to service ID
+	 */
+	for (ii = 1; ii < pmf_num_services; ii++) {
+		for (jj = 0; jj < (pmf_num_services - ii); jj++) {
+			if ((pmf_svc_descs[jj].svc_config & PMF_SVC_ID_MASK) >
+				(pmf_svc_descs[jj + 1].svc_config &
+						PMF_SVC_ID_MASK)) {
+				temp_val = pmf_svc_descs_indices[jj];
+				pmf_svc_descs_indices[jj] =
+						pmf_svc_descs_indices[jj+1];
+				pmf_svc_descs_indices[jj+1] = temp_val;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function implements binary search to find registered
+ * PMF service based on Service ID provided in `tid` argument.
+ */
+static pmf_svc_desc_t *get_service(unsigned int tid)
+{
+	int low = 0;
+	int mid;
+	int high = pmf_num_services;
+	unsigned int svc_id = tid & PMF_SVC_ID_MASK;
+	int index;
+	unsigned int desc_svc_id;
+
+	if (pmf_num_services == 0)
+		return NULL;
+
+	assert(pmf_svc_descs != NULL);
+
+	do {
+		mid = (low + high) / 2;
+		index = pmf_svc_descs_indices[mid];
+
+		desc_svc_id = pmf_svc_descs[index].svc_config & PMF_SVC_ID_MASK;
+		if (svc_id < desc_svc_id)
+			high = mid - 1;
+		if (svc_id > desc_svc_id)
+			low = mid + 1;
+	} while ((svc_id != desc_svc_id) && (low <= high));
+
+	/*
+	 * Make sure the Service found supports the tid range.
+	 */
+	if ((svc_id == desc_svc_id) && ((tid & PMF_TID_MASK) <
+		(pmf_svc_descs[index].svc_config & PMF_TID_MASK)))
+		return (pmf_svc_desc_t *)&pmf_svc_descs[index];
+
+	return NULL;
+}
+
+/*
+ * This function gets the time-stamp value for the PMF services
+ * registered for SMC interface based on `tid` and `mpidr`.
+ */
+int pmf_get_timestamp_smc(unsigned int tid,
+		u_register_t mpidr,
+		unsigned int flags,
+		unsigned long long *ts_value)
+{
+	pmf_svc_desc_t *svc_desc;
+	assert(ts_value != NULL);
+
+	/* Search for registered service. */
+	svc_desc = get_service(tid);
+
+	if ((svc_desc == NULL) || (plat_core_pos_by_mpidr(mpidr) < 0)) {
+		*ts_value = 0;
+		return -EINVAL;
+	} else {
+		/* Call the service time-stamp handler. */
+		*ts_value = svc_desc->get_ts(tid, mpidr, flags);
+		return 0;
+	}
+}
+
+/*
+ * This function can be used to dump `ts` value for given `tid`.
+ * Assumption is that the console is already initialized.
+ */
+void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts)
+{
+	printf("PMF:cpu %u	tid %u	ts %llu\n",
+		plat_my_core_pos(), tid, ts);
+}
+
+/*
+ * This function calculate the address identified by
+ * `base_addr`, `tid` and `cpuid`.
+ */
+static inline uintptr_t calc_ts_addr(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned int cpuid)
+{
+	assert(cpuid < PLATFORM_CORE_COUNT);
+	assert(base_addr >= PMF_TIMESTAMP_ARRAY_START);
+	assert(base_addr < ((PMF_TIMESTAMP_ARRAY_START +
+		PMF_PERCPU_TIMESTAMP_SIZE) - ((tid & PMF_TID_MASK) *
+		sizeof(unsigned long long))));
+
+	base_addr += ((cpuid * PMF_PERCPU_TIMESTAMP_SIZE) +
+		((tid & PMF_TID_MASK) * sizeof(unsigned long long)));
+
+	return base_addr;
+}
+
+/*
+ * This function stores the `ts` value to the storage identified by
+ * `base_addr`, `tid` and current cpu id.
+ * Note: The timestamp addresses are cache line aligned per cpu
+ * and only the owning CPU would ever write into it.
+ */
+void __pmf_store_timestamp(uintptr_t base_addr,
+			unsigned int tid,
+			unsigned long long ts)
+{
+	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
+				 tid, plat_my_core_pos());
+	*ts_addr = ts;
+}
+
+/*
+ * This is the cached version of `pmf_store_my_timestamp`
+ * Note: The timestamp addresses are cache line aligned per cpu
+ * and only the owning CPU would ever write into it.
+ */
+void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
+			unsigned int tid,
+			unsigned long long ts)
+{
+	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
+				 tid, plat_my_core_pos());
+	*ts_addr = ts;
+	flush_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
+}
+
+/*
+ * This function retrieves the `ts` value from the storage identified by
+ * `base_addr`, `tid` and `cpuid`.
+ * Note: The timestamp addresses are cache line aligned per cpu.
+ */
+unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
+			unsigned int tid,
+			unsigned int cpuid,
+			unsigned int flags)
+{
+	assert(cpuid < PLATFORM_CORE_COUNT);
+	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
+				tid, cpuid);
+
+	if ((flags & PMF_CACHE_MAINT) != 0U)
+		inv_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
+
+	return *ts_addr;
+}
diff --git a/lib/pmf/pmf_smc.c b/lib/pmf/pmf_smc.c
new file mode 100644
index 0000000..6d79502
--- /dev/null
+++ b/lib/pmf/pmf_smc.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <plat/common/platform.h>
+#include <smccc_helpers.h>
+
+/*
+ * This function is responsible for handling all PMF SMC calls.
+ */
+uintptr_t pmf_smc_handler(unsigned int smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	int rc;
+	unsigned long long ts_value;
+
+	if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
+
+		x1 = (uint32_t)x1;
+		x2 = (uint32_t)x2;
+		x3 = (uint32_t)x3;
+
+		if (smc_fid == PMF_SMC_GET_TIMESTAMP_32) {
+			/*
+			 * Return error code and the captured
+			 * time-stamp to the caller.
+			 * x0 --> error code.
+			 * x1 - x2 --> time-stamp value.
+			 */
+			rc = pmf_get_timestamp_smc((unsigned int)x1, x2,
+					(unsigned int)x3, &ts_value);
+			SMC_RET3(handle, rc, (uint32_t)ts_value,
+					(uint32_t)(ts_value >> 32));
+		}
+	} else {
+		if (smc_fid == PMF_SMC_GET_TIMESTAMP_64) {
+			/*
+			 * Return error code and the captured
+			 * time-stamp to the caller.
+			 * x0 --> error code.
+			 * x1 --> time-stamp value.
+			 */
+			rc = pmf_get_timestamp_smc((unsigned int)x1, x2,
+					(unsigned int)x3, &ts_value);
+			SMC_RET2(handle, rc, ts_value);
+		}
+	}
+
+	WARN("Unimplemented PMF Call: 0x%x \n", smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/lib/psci/aarch32/psci_helpers.S b/lib/psci/aarch32/psci_helpers.S
new file mode 100644
index 0000000..5cc192e
--- /dev/null
+++ b/lib/psci/aarch32/psci_helpers.S
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+	.globl	psci_do_pwrdown_cache_maintenance
+	.globl	psci_do_pwrup_cache_maintenance
+	.globl	psci_power_down_wfi
+
+/* -----------------------------------------------------------------------
+ * void psci_do_pwrdown_cache_maintenance(unsigned int power level);
+ *
+ * This function performs cache maintenance for the specified power
+ * level. The levels of cache affected are determined by the power
+ * level which is passed as the argument i.e. level 0 results
+ * in a flush of the L1 cache. Both the L1 and L2 caches are flushed
+ * for a higher power level.
+ *
+ * Additionally, this function also ensures that stack memory is correctly
+ * flushed out to avoid coherency issues due to a change in its memory
+ * attributes after the data cache is disabled.
+ * -----------------------------------------------------------------------
+ */
+func psci_do_pwrdown_cache_maintenance
+	push	{r4, lr}
+
+	/* ----------------------------------------------
+	 * Turn OFF cache and do stack maintenance
+	 * prior to cpu operations . This sequence is
+	 * different from AArch64 because in AArch32 the
+	 * assembler routines for cpu operations utilize
+	 * the stack whereas in AArch64 it doesn't.
+	 * ----------------------------------------------
+	 */
+	mov	r4, r0
+	bl	do_stack_maintenance
+
+	/* ---------------------------------------------
+	 * Invoke CPU-specifc power down operations for
+	 * the appropriate level
+	 * ---------------------------------------------
+	 */
+	mov	r0, r4
+	pop	{r4, lr}
+	b	prepare_cpu_pwr_dwn
+endfunc psci_do_pwrdown_cache_maintenance
+
+
+/* -----------------------------------------------------------------------
+ * void psci_do_pwrup_cache_maintenance(void);
+ *
+ * This function performs cache maintenance after this cpu is powered up.
+ * Currently, this involves managing the used stack memory before turning
+ * on the data cache.
+ * -----------------------------------------------------------------------
+ */
+func psci_do_pwrup_cache_maintenance
+	/* r12 is pushed to meet the 8 byte stack alignment requirement */
+	push	{r12, lr}
+
+	/* ---------------------------------------------
+	 * Ensure any inflight stack writes have made it
+	 * to main memory.
+	 * ---------------------------------------------
+	 */
+	dmb	st
+
+	/* ---------------------------------------------
+	 * Calculate and store the size of the used
+	 * stack memory in r1. Calculate and store the
+	 * stack base address in r0.
+	 * ---------------------------------------------
+	 */
+	bl	plat_get_my_stack
+	mov	r1, sp
+	sub	r1, r0, r1
+	mov	r0, sp
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Enable the data cache.
+	 * ---------------------------------------------
+	 */
+	ldcopr	r0, SCTLR
+	orr	r0, r0, #SCTLR_C_BIT
+	stcopr	r0, SCTLR
+	isb
+
+	pop	{r12, pc}
+endfunc psci_do_pwrup_cache_maintenance
+
+	/* ---------------------------------------------
+	 * void do_stack_maintenance(void)
+	 * Do stack maintenance by flushing the used
+	 * stack to the main memory and invalidating the
+	 * remainder.
+	 * ---------------------------------------------
+	 */
+func do_stack_maintenance
+	push	{r4, lr}
+	bl	plat_get_my_stack
+
+	/* Turn off the D-cache */
+	ldcopr	r1, SCTLR
+	bic	r1, #SCTLR_C_BIT
+	stcopr	r1, SCTLR
+	isb
+
+	/* ---------------------------------------------
+	 * Calculate and store the size of the used
+	 * stack memory in r1.
+	 * ---------------------------------------------
+	 */
+	mov	r4, r0
+	mov	r1, sp
+	sub	r1, r0, r1
+	mov	r0, sp
+	bl	flush_dcache_range
+
+	/* ---------------------------------------------
+	 * Calculate and store the size of the unused
+	 * stack memory in r1. Calculate and store the
+	 * stack base address in r0.
+	 * ---------------------------------------------
+	 */
+	sub	r0, r4, #PLATFORM_STACK_SIZE
+	sub	r1, sp, r0
+	bl	inv_dcache_range
+
+	pop	{r4, pc}
+endfunc do_stack_maintenance
+
+/* -----------------------------------------------------------------------
+ * This function is called to indicate to the power controller that it
+ * is safe to power down this cpu. It should not exit the wfi and will
+ * be released from reset upon power up.
+ * -----------------------------------------------------------------------
+ */
+func psci_power_down_wfi
+	dsb	sy		// ensure write buffer empty
+	wfi
+	no_ret	plat_panic_handler
+endfunc psci_power_down_wfi
diff --git a/lib/psci/aarch64/psci_helpers.S b/lib/psci/aarch64/psci_helpers.S
new file mode 100644
index 0000000..add968a
--- /dev/null
+++ b/lib/psci/aarch64/psci_helpers.S
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+	.globl	psci_do_pwrdown_cache_maintenance
+	.globl	psci_do_pwrup_cache_maintenance
+	.globl	psci_power_down_wfi
+
+/* -----------------------------------------------------------------------
+ * void psci_do_pwrdown_cache_maintenance(unsigned int power level);
+ *
+ * This function performs cache maintenance for the specified power
+ * level. The levels of cache affected are determined by the power
+ * level which is passed as the argument i.e. level 0 results
+ * in a flush of the L1 cache. Both the L1 and L2 caches are flushed
+ * for a higher power level.
+ *
+ * Additionally, this function also ensures that stack memory is correctly
+ * flushed out to avoid coherency issues due to a change in its memory
+ * attributes after the data cache is disabled.
+ * -----------------------------------------------------------------------
+ */
+func psci_do_pwrdown_cache_maintenance
+	stp     x29, x30, [sp,#-16]!
+	stp     x19, x20, [sp,#-16]!
+
+	/* ---------------------------------------------
+	 * Invoke CPU-specific power down operations for
+	 * the appropriate level
+	 * ---------------------------------------------
+	 */
+	bl	prepare_cpu_pwr_dwn
+
+	/* ---------------------------------------------
+	 * Do stack maintenance by flushing the used
+	 * stack to the main memory and invalidating the
+	 * remainder.
+	 * ---------------------------------------------
+	 */
+	bl	plat_get_my_stack
+
+	/* ---------------------------------------------
+	 * Calculate and store the size of the used
+	 * stack memory in x1.
+	 * ---------------------------------------------
+	 */
+	mov	x19, x0
+	mov	x1, sp
+	sub	x1, x0, x1
+	mov	x0, sp
+	bl	flush_dcache_range
+
+	/* ---------------------------------------------
+	 * Calculate and store the size of the unused
+	 * stack memory in x1. Calculate and store the
+	 * stack base address in x0.
+	 * ---------------------------------------------
+	 */
+	sub	x0, x19, #PLATFORM_STACK_SIZE
+	sub	x1, sp, x0
+	bl	inv_dcache_range
+
+	ldp	x19, x20, [sp], #16
+	ldp	x29, x30, [sp], #16
+	ret
+endfunc psci_do_pwrdown_cache_maintenance
+
+
+/* -----------------------------------------------------------------------
+ * void psci_do_pwrup_cache_maintenance(void);
+ *
+ * This function performs cache maintenance after this cpu is powered up.
+ * Currently, this involves managing the used stack memory before turning
+ * on the data cache.
+ * -----------------------------------------------------------------------
+ */
+func psci_do_pwrup_cache_maintenance
+	stp	x29, x30, [sp,#-16]!
+
+	/* ---------------------------------------------
+	 * Ensure any inflight stack writes have made it
+	 * to main memory.
+	 * ---------------------------------------------
+	 */
+	dmb	st
+
+	/* ---------------------------------------------
+	 * Calculate and store the size of the used
+	 * stack memory in x1. Calculate and store the
+	 * stack base address in x0.
+	 * ---------------------------------------------
+	 */
+	bl	plat_get_my_stack
+	mov	x1, sp
+	sub	x1, x0, x1
+	mov	x0, sp
+	bl	inv_dcache_range
+
+	/* ---------------------------------------------
+	 * Enable the data cache.
+	 * ---------------------------------------------
+	 */
+	mrs	x0, sctlr_el3
+	orr	x0, x0, #SCTLR_C_BIT
+	msr	sctlr_el3, x0
+	isb
+
+	ldp	x29, x30, [sp], #16
+	ret
+endfunc psci_do_pwrup_cache_maintenance
+
+/* -----------------------------------------------------------------------
+ * void psci_power_down_wfi(void);
+ * This function is called to indicate to the power controller that it
+ * is safe to power down this cpu. It should not exit the wfi and will
+ * be released from reset upon power up.
+ * -----------------------------------------------------------------------
+ */
+func psci_power_down_wfi
+	dsb	sy		// ensure write buffer empty
+	wfi
+	no_ret	plat_panic_handler
+endfunc psci_power_down_wfi
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
new file mode 100644
index 0000000..5d24356
--- /dev/null
+++ b/lib/psci/psci_common.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/*
+ * SPD power management operations, expected to be supplied by the registered
+ * SPD on successful SP initialization
+ */
+const spd_pm_ops_t *psci_spd_pm;
+
+/*
+ * PSCI requested local power state map. This array is used to store the local
+ * power states requested by a CPU for power levels from level 1 to
+ * PLAT_MAX_PWR_LVL. It does not store the requested local power state for power
+ * level 0 (PSCI_CPU_PWR_LVL) as the requested and the target power state for a
+ * CPU are the same.
+ *
+ * During state coordination, the platform is passed an array containing the
+ * local states requested for a particular non cpu power domain by each cpu
+ * within the domain.
+ *
+ * TODO: Dense packing of the requested states will cause cache thrashing
+ * when multiple power domains write to it. If we allocate the requested
+ * states at each power level in a cache-line aligned per-domain memory,
+ * the cache thrashing can be avoided.
+ */
+static plat_local_state_t
+	psci_req_local_pwr_states[PLAT_MAX_PWR_LVL][PLATFORM_CORE_COUNT];
+
+
+/*******************************************************************************
+ * Arrays that hold the platform's power domain tree information for state
+ * management of power domains.
+ * Each node in the array 'psci_non_cpu_pd_nodes' corresponds to a power domain
+ * which is an ancestor of a CPU power domain.
+ * Each node in the array 'psci_cpu_pd_nodes' corresponds to a cpu power domain
+ ******************************************************************************/
+non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]
+#if USE_COHERENT_MEM
+__section("tzfw_coherent_mem")
+#endif
+;
+
+/* Lock for PSCI state coordination */
+DEFINE_PSCI_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]);
+
+cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * Pointer to functions exported by the platform to complete power mgmt. ops
+ ******************************************************************************/
+const plat_psci_ops_t *psci_plat_pm_ops;
+
+/******************************************************************************
+ * Check that the maximum power level supported by the platform makes sense
+ *****************************************************************************/
+CASSERT((PLAT_MAX_PWR_LVL <= PSCI_MAX_PWR_LVL) &&
+	(PLAT_MAX_PWR_LVL >= PSCI_CPU_PWR_LVL),
+	assert_platform_max_pwrlvl_check);
+
+/*
+ * The plat_local_state used by the platform is one of these types: RUN,
+ * RETENTION and OFF. The platform can define further sub-states for each type
+ * apart from RUN. This categorization is done to verify the sanity of the
+ * psci_power_state passed by the platform and to print debug information. The
+ * categorization is done on the basis of the following conditions:
+ *
+ * 1. If (plat_local_state == 0) then the category is STATE_TYPE_RUN.
+ *
+ * 2. If (0 < plat_local_state <= PLAT_MAX_RET_STATE), then the category is
+ *    STATE_TYPE_RETN.
+ *
+ * 3. If (plat_local_state > PLAT_MAX_RET_STATE), then the category is
+ *    STATE_TYPE_OFF.
+ */
+typedef enum plat_local_state_type {
+	STATE_TYPE_RUN = 0,
+	STATE_TYPE_RETN,
+	STATE_TYPE_OFF
+} plat_local_state_type_t;
+
+/* Function used to categorize plat_local_state. */
+static plat_local_state_type_t find_local_state_type(plat_local_state_t state)
+{
+	if (state != 0U) {
+		if (state > PLAT_MAX_RET_STATE) {
+			return STATE_TYPE_OFF;
+		} else {
+			return STATE_TYPE_RETN;
+		}
+	} else {
+		return STATE_TYPE_RUN;
+	}
+}
+
+/******************************************************************************
+ * Check that the maximum retention level supported by the platform is less
+ * than the maximum off level.
+ *****************************************************************************/
+CASSERT(PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE,
+		assert_platform_max_off_and_retn_state_check);
+
+/******************************************************************************
+ * This function ensures that the power state parameter in a CPU_SUSPEND request
+ * is valid. If so, it returns the requested states for each power level.
+ *****************************************************************************/
+int psci_validate_power_state(unsigned int power_state,
+			      psci_power_state_t *state_info)
+{
+	/* Check SBZ bits in power state are zero */
+	if (psci_check_power_state(power_state) != 0U)
+		return PSCI_E_INVALID_PARAMS;
+
+	assert(psci_plat_pm_ops->validate_power_state != NULL);
+
+	/* Validate the power_state using platform pm_ops */
+	return psci_plat_pm_ops->validate_power_state(power_state, state_info);
+}
+
+/******************************************************************************
+ * This function retrieves the `psci_power_state_t` for system suspend from
+ * the platform.
+ *****************************************************************************/
+void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info)
+{
+	/*
+	 * Assert that the required pm_ops hook is implemented to ensure that
+	 * the capability detected during psci_setup() is valid.
+	 */
+	assert(psci_plat_pm_ops->get_sys_suspend_power_state != NULL);
+
+	/*
+	 * Query the platform for the power_state required for system suspend
+	 */
+	psci_plat_pm_ops->get_sys_suspend_power_state(state_info);
+}
+
+/*******************************************************************************
+ * This function verifies that the all the other cores in the system have been
+ * turned OFF and the current CPU is the last running CPU in the system.
+ * Returns 1 (true) if the current CPU is the last ON CPU or 0 (false)
+ * otherwise.
+ ******************************************************************************/
+unsigned int psci_is_last_on_cpu(void)
+{
+	int cpu_idx, my_idx = (int) plat_my_core_pos();
+
+	for (cpu_idx = 0; cpu_idx < PLATFORM_CORE_COUNT; cpu_idx++) {
+		if (cpu_idx == my_idx) {
+			assert(psci_get_aff_info_state() == AFF_STATE_ON);
+			continue;
+		}
+
+		if (psci_get_aff_info_state_by_idx(cpu_idx) != AFF_STATE_OFF)
+			return 0;
+	}
+
+	return 1;
+}
+
+/*******************************************************************************
+ * Routine to return the maximum power level to traverse to after a cpu has
+ * been physically powered up. It is expected to be called immediately after
+ * reset from assembler code.
+ ******************************************************************************/
+static unsigned int get_power_on_target_pwrlvl(void)
+{
+	unsigned int pwrlvl;
+
+	/*
+	 * Assume that this cpu was suspended and retrieve its target power
+	 * level. If it is invalid then it could only have been turned off
+	 * earlier. PLAT_MAX_PWR_LVL will be the highest power level a
+	 * cpu can be turned off to.
+	 */
+	pwrlvl = psci_get_suspend_pwrlvl();
+	if (pwrlvl == PSCI_INVALID_PWR_LVL)
+		pwrlvl = PLAT_MAX_PWR_LVL;
+	return pwrlvl;
+}
+
+/******************************************************************************
+ * Helper function to update the requested local power state array. This array
+ * does not store the requested state for the CPU power level. Hence an
+ * assertion is added to prevent us from accessing the wrong index.
+ *****************************************************************************/
+static void psci_set_req_local_pwr_state(unsigned int pwrlvl,
+					 unsigned int cpu_idx,
+					 plat_local_state_t req_pwr_state)
+{
+	/*
+	 * This should never happen, we have this here to avoid
+	 * "array subscript is above array bounds" errors in GCC.
+	 */
+	assert(pwrlvl > PSCI_CPU_PWR_LVL);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+	psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx] = req_pwr_state;
+#pragma GCC diagnostic pop
+}
+
+/******************************************************************************
+ * This function initializes the psci_req_local_pwr_states.
+ *****************************************************************************/
+void __init psci_init_req_local_pwr_states(void)
+{
+	/* Initialize the requested state of all non CPU power domains as OFF */
+	unsigned int pwrlvl;
+	int core;
+
+	for (pwrlvl = 0U; pwrlvl < PLAT_MAX_PWR_LVL; pwrlvl++) {
+		for (core = 0; core < PLATFORM_CORE_COUNT; core++) {
+			psci_req_local_pwr_states[pwrlvl][core] =
+				PLAT_MAX_OFF_STATE;
+		}
+	}
+}
+
+/******************************************************************************
+ * Helper function to return a reference to an array containing the local power
+ * states requested by each cpu for a power domain at 'pwrlvl'. The size of the
+ * array will be the number of cpu power domains of which this power domain is
+ * an ancestor. These requested states will be used to determine a suitable
+ * target state for this power domain during psci state coordination. An
+ * assertion is added to prevent us from accessing the CPU power level.
+ *****************************************************************************/
+static plat_local_state_t *psci_get_req_local_pwr_states(unsigned int pwrlvl,
+							 int cpu_idx)
+{
+	assert(pwrlvl > PSCI_CPU_PWR_LVL);
+
+	return &psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx];
+}
+
+/*
+ * psci_non_cpu_pd_nodes can be placed either in normal memory or coherent
+ * memory.
+ *
+ * With !USE_COHERENT_MEM, psci_non_cpu_pd_nodes is placed in normal memory,
+ * it's accessed by both cached and non-cached participants. To serve the common
+ * minimum, perform a cache flush before read and after write so that non-cached
+ * participants operate on latest data in main memory.
+ *
+ * When USE_COHERENT_MEM is used, psci_non_cpu_pd_nodes is placed in coherent
+ * memory. With HW_ASSISTED_COHERENCY, all PSCI participants are cache-coherent.
+ * In both cases, no cache operations are required.
+ */
+
+/*
+ * Retrieve local state of non-CPU power domain node from a non-cached CPU,
+ * after any required cache maintenance operation.
+ */
+static plat_local_state_t get_non_cpu_pd_node_local_state(
+		unsigned int parent_idx)
+{
+#if !(USE_COHERENT_MEM || HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+	flush_dcache_range(
+			(uintptr_t) &psci_non_cpu_pd_nodes[parent_idx],
+			sizeof(psci_non_cpu_pd_nodes[parent_idx]));
+#endif
+	return psci_non_cpu_pd_nodes[parent_idx].local_state;
+}
+
+/*
+ * Update local state of non-CPU power domain node from a cached CPU; perform
+ * any required cache maintenance operation afterwards.
+ */
+static void set_non_cpu_pd_node_local_state(unsigned int parent_idx,
+		plat_local_state_t state)
+{
+	psci_non_cpu_pd_nodes[parent_idx].local_state = state;
+#if !(USE_COHERENT_MEM || HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+	flush_dcache_range(
+			(uintptr_t) &psci_non_cpu_pd_nodes[parent_idx],
+			sizeof(psci_non_cpu_pd_nodes[parent_idx]));
+#endif
+}
+
+/******************************************************************************
+ * Helper function to return the current local power state of each power domain
+ * from the current cpu power domain to its ancestor at the 'end_pwrlvl'. This
+ * function will be called after a cpu is powered on to find the local state
+ * each power domain has emerged from.
+ *****************************************************************************/
+void psci_get_target_local_pwr_states(unsigned int end_pwrlvl,
+				      psci_power_state_t *target_state)
+{
+	unsigned int parent_idx, lvl;
+	plat_local_state_t *pd_state = target_state->pwr_domain_state;
+
+	pd_state[PSCI_CPU_PWR_LVL] = psci_get_cpu_local_state();
+	parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node;
+
+	/* Copy the local power state from node to state_info */
+	for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) {
+		pd_state[lvl] = get_non_cpu_pd_node_local_state(parent_idx);
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+	/* Set the the higher levels to RUN */
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+		target_state->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN;
+}
+
+/******************************************************************************
+ * Helper function to set the target local power state that each power domain
+ * from the current cpu power domain to its ancestor at the 'end_pwrlvl' will
+ * enter. This function will be called after coordination of requested power
+ * states has been done for each power level.
+ *****************************************************************************/
+static void psci_set_target_local_pwr_states(unsigned int end_pwrlvl,
+					const psci_power_state_t *target_state)
+{
+	unsigned int parent_idx, lvl;
+	const plat_local_state_t *pd_state = target_state->pwr_domain_state;
+
+	psci_set_cpu_local_state(pd_state[PSCI_CPU_PWR_LVL]);
+
+	/*
+	 * Need to flush as local_state might be accessed with Data Cache
+	 * disabled during power on
+	 */
+	psci_flush_cpu_data(psci_svc_cpu_data.local_state);
+
+	parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node;
+
+	/* Copy the local_state from state_info */
+	for (lvl = 1U; lvl <= end_pwrlvl; lvl++) {
+		set_non_cpu_pd_node_local_state(parent_idx, pd_state[lvl]);
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+}
+
+
+/*******************************************************************************
+ * PSCI helper function to get the parent nodes corresponding to a cpu_index.
+ ******************************************************************************/
+void psci_get_parent_pwr_domain_nodes(int cpu_idx,
+				      unsigned int end_lvl,
+				      unsigned int *node_index)
+{
+	unsigned int parent_node = psci_cpu_pd_nodes[cpu_idx].parent_node;
+	unsigned int i;
+	unsigned int *node = node_index;
+
+	for (i = PSCI_CPU_PWR_LVL + 1U; i <= end_lvl; i++) {
+		*node = parent_node;
+		node++;
+		parent_node = psci_non_cpu_pd_nodes[parent_node].parent_node;
+	}
+}
+
+/******************************************************************************
+ * This function is invoked post CPU power up and initialization. It sets the
+ * affinity info state, target power state and requested power state for the
+ * current CPU and all its ancestor power domains to RUN.
+ *****************************************************************************/
+void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl)
+{
+	unsigned int parent_idx, cpu_idx = plat_my_core_pos(), lvl;
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+
+	/* Reset the local_state to RUN for the non cpu power domains. */
+	for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) {
+		set_non_cpu_pd_node_local_state(parent_idx,
+				PSCI_LOCAL_STATE_RUN);
+		psci_set_req_local_pwr_state(lvl,
+					     cpu_idx,
+					     PSCI_LOCAL_STATE_RUN);
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+	/* Set the affinity info state to ON */
+	psci_set_aff_info_state(AFF_STATE_ON);
+
+	psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
+	psci_flush_cpu_data(psci_svc_cpu_data);
+}
+
+/******************************************************************************
+ * This function is passed the local power states requested for each power
+ * domain (state_info) between the current CPU domain and its ancestors until
+ * the target power level (end_pwrlvl). It updates the array of requested power
+ * states with this information.
+ *
+ * Then, for each level (apart from the CPU level) until the 'end_pwrlvl', it
+ * retrieves the states requested by all the cpus of which the power domain at
+ * that level is an ancestor. It passes this information to the platform to
+ * coordinate and return the target power state. If the target state for a level
+ * is RUN then subsequent levels are not considered. At the CPU level, state
+ * coordination is not required. Hence, the requested and the target states are
+ * the same.
+ *
+ * The 'state_info' is updated with the target state for each level between the
+ * CPU and the 'end_pwrlvl' and returned to the caller.
+ *
+ * This function will only be invoked with data cache enabled and while
+ * powering down a core.
+ *****************************************************************************/
+void psci_do_state_coordination(unsigned int end_pwrlvl,
+				psci_power_state_t *state_info)
+{
+	unsigned int lvl, parent_idx, cpu_idx = plat_my_core_pos();
+	int start_idx;
+	unsigned int ncpus;
+	plat_local_state_t target_state, *req_states;
+
+	assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+
+	/* For level 0, the requested state will be equivalent
+	   to target state */
+	for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) {
+
+		/* First update the requested power state */
+		psci_set_req_local_pwr_state(lvl, cpu_idx,
+					     state_info->pwr_domain_state[lvl]);
+
+		/* Get the requested power states for this power level */
+		start_idx = psci_non_cpu_pd_nodes[parent_idx].cpu_start_idx;
+		req_states = psci_get_req_local_pwr_states(lvl, start_idx);
+
+		/*
+		 * Let the platform coordinate amongst the requested states at
+		 * this power level and return the target local power state.
+		 */
+		ncpus = psci_non_cpu_pd_nodes[parent_idx].ncpus;
+		target_state = plat_get_target_pwr_state(lvl,
+							 req_states,
+							 ncpus);
+
+		state_info->pwr_domain_state[lvl] = target_state;
+
+		/* Break early if the negotiated target power state is RUN */
+		if (is_local_state_run(state_info->pwr_domain_state[lvl]) != 0)
+			break;
+
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+	/*
+	 * This is for cases when we break out of the above loop early because
+	 * the target power state is RUN at a power level < end_pwlvl.
+	 * We update the requested power state from state_info and then
+	 * set the target state as RUN.
+	 */
+	for (lvl = lvl + 1U; lvl <= end_pwrlvl; lvl++) {
+		psci_set_req_local_pwr_state(lvl, cpu_idx,
+					     state_info->pwr_domain_state[lvl]);
+		state_info->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN;
+
+	}
+
+	/* Update the target state in the power domain nodes */
+	psci_set_target_local_pwr_states(end_pwrlvl, state_info);
+}
+
+/******************************************************************************
+ * This function validates a suspend request by making sure that if a standby
+ * state is requested then no power level is turned off and the highest power
+ * level is placed in a standby/retention state.
+ *
+ * It also ensures that the state level X will enter is not shallower than the
+ * state level X + 1 will enter.
+ *
+ * This validation will be enabled only for DEBUG builds as the platform is
+ * expected to perform these validations as well.
+ *****************************************************************************/
+int psci_validate_suspend_req(const psci_power_state_t *state_info,
+			      unsigned int is_power_down_state)
+{
+	unsigned int max_off_lvl, target_lvl, max_retn_lvl;
+	plat_local_state_t state;
+	plat_local_state_type_t req_state_type, deepest_state_type;
+	int i;
+
+	/* Find the target suspend power level */
+	target_lvl = psci_find_target_suspend_lvl(state_info);
+	if (target_lvl == PSCI_INVALID_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* All power domain levels are in a RUN state to begin with */
+	deepest_state_type = STATE_TYPE_RUN;
+
+	for (i = (int) target_lvl; i >= (int) PSCI_CPU_PWR_LVL; i--) {
+		state = state_info->pwr_domain_state[i];
+		req_state_type = find_local_state_type(state);
+
+		/*
+		 * While traversing from the highest power level to the lowest,
+		 * the state requested for lower levels has to be the same or
+		 * deeper i.e. equal to or greater than the state at the higher
+		 * levels. If this condition is true, then the requested state
+		 * becomes the deepest state encountered so far.
+		 */
+		if (req_state_type < deepest_state_type)
+			return PSCI_E_INVALID_PARAMS;
+		deepest_state_type = req_state_type;
+	}
+
+	/* Find the highest off power level */
+	max_off_lvl = psci_find_max_off_lvl(state_info);
+
+	/* The target_lvl is either equal to the max_off_lvl or max_retn_lvl */
+	max_retn_lvl = PSCI_INVALID_PWR_LVL;
+	if (target_lvl != max_off_lvl)
+		max_retn_lvl = target_lvl;
+
+	/*
+	 * If this is not a request for a power down state then max off level
+	 * has to be invalid and max retention level has to be a valid power
+	 * level.
+	 */
+	if ((is_power_down_state == 0U) &&
+			((max_off_lvl != PSCI_INVALID_PWR_LVL) ||
+			 (max_retn_lvl == PSCI_INVALID_PWR_LVL)))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+/******************************************************************************
+ * This function finds the highest power level which will be powered down
+ * amongst all the power levels specified in the 'state_info' structure
+ *****************************************************************************/
+unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info)
+{
+	int i;
+
+	for (i = (int) PLAT_MAX_PWR_LVL; i >= (int) PSCI_CPU_PWR_LVL; i--) {
+		if (is_local_state_off(state_info->pwr_domain_state[i]) != 0)
+			return (unsigned int) i;
+	}
+
+	return PSCI_INVALID_PWR_LVL;
+}
+
+/******************************************************************************
+ * This functions finds the level of the highest power domain which will be
+ * placed in a low power state during a suspend operation.
+ *****************************************************************************/
+unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info)
+{
+	int i;
+
+	for (i = (int) PLAT_MAX_PWR_LVL; i >= (int) PSCI_CPU_PWR_LVL; i--) {
+		if (is_local_state_run(state_info->pwr_domain_state[i]) == 0)
+			return (unsigned int) i;
+	}
+
+	return PSCI_INVALID_PWR_LVL;
+}
+
+/*******************************************************************************
+ * This function is passed the highest level in the topology tree that the
+ * operation should be applied to and a list of node indexes. It picks up locks
+ * from the node index list in order of increasing power domain level in the
+ * range specified.
+ ******************************************************************************/
+void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl,
+				   const unsigned int *parent_nodes)
+{
+	unsigned int parent_idx;
+	unsigned int level;
+
+	/* No locking required for level 0. Hence start locking from level 1 */
+	for (level = PSCI_CPU_PWR_LVL + 1U; level <= end_pwrlvl; level++) {
+		parent_idx = parent_nodes[level - 1U];
+		psci_lock_get(&psci_non_cpu_pd_nodes[parent_idx]);
+	}
+}
+
+/*******************************************************************************
+ * This function is passed the highest level in the topology tree that the
+ * operation should be applied to and a list of node indexes. It releases the
+ * locks in order of decreasing power domain level in the range specified.
+ ******************************************************************************/
+void psci_release_pwr_domain_locks(unsigned int end_pwrlvl,
+				   const unsigned int *parent_nodes)
+{
+	unsigned int parent_idx;
+	unsigned int level;
+
+	/* Unlock top down. No unlocking required for level 0. */
+	for (level = end_pwrlvl; level >= PSCI_CPU_PWR_LVL + 1U; level--) {
+		parent_idx = parent_nodes[level - 1U];
+		psci_lock_release(&psci_non_cpu_pd_nodes[parent_idx]);
+	}
+}
+
+/*******************************************************************************
+ * Simple routine to determine whether a mpidr is valid or not.
+ ******************************************************************************/
+int psci_validate_mpidr(u_register_t mpidr)
+{
+	if (plat_core_pos_by_mpidr(mpidr) < 0)
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * This function determines the full entrypoint information for the requested
+ * PSCI entrypoint on power on/resume and returns it.
+ ******************************************************************************/
+#ifdef __aarch64__
+static int psci_get_ns_ep_info(entry_point_info_t *ep,
+			       uintptr_t entrypoint,
+			       u_register_t context_id)
+{
+	u_register_t ep_attr, sctlr;
+	unsigned int daif, ee, mode;
+	u_register_t ns_scr_el3 = read_scr_el3();
+	u_register_t ns_sctlr_el1 = read_sctlr_el1();
+
+	sctlr = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ?
+		read_sctlr_el2() : ns_sctlr_el1;
+	ee = 0;
+
+	ep_attr = NON_SECURE | EP_ST_DISABLE;
+	if ((sctlr & SCTLR_EE_BIT) != 0U) {
+		ep_attr |= EP_EE_BIG;
+		ee = 1;
+	}
+	SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
+
+	ep->pc = entrypoint;
+	zeromem(&ep->args, sizeof(ep->args));
+	ep->args.arg0 = context_id;
+
+	/*
+	 * Figure out whether the cpu enters the non-secure address space
+	 * in aarch32 or aarch64
+	 */
+	if ((ns_scr_el3 & SCR_RW_BIT) != 0U) {
+
+		/*
+		 * Check whether a Thumb entry point has been provided for an
+		 * aarch64 EL
+		 */
+		if ((entrypoint & 0x1UL) != 0UL)
+			return PSCI_E_INVALID_ADDRESS;
+
+		mode = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ? MODE_EL2 : MODE_EL1;
+
+		ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	} else {
+
+		mode = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ?
+			MODE32_hyp : MODE32_svc;
+
+		/*
+		 * TODO: Choose async. exception bits if HYP mode is not
+		 * implemented according to the values of SCR.{AW, FW} bits
+		 */
+		daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
+
+		ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+#else /* !__aarch64__ */
+static int psci_get_ns_ep_info(entry_point_info_t *ep,
+			       uintptr_t entrypoint,
+			       u_register_t context_id)
+{
+	u_register_t ep_attr;
+	unsigned int aif, ee, mode;
+	u_register_t scr = read_scr();
+	u_register_t ns_sctlr, sctlr;
+
+	/* Switch to non secure state */
+	write_scr(scr | SCR_NS_BIT);
+	isb();
+	ns_sctlr = read_sctlr();
+
+	sctlr = scr & SCR_HCE_BIT ? read_hsctlr() : ns_sctlr;
+
+	/* Return to original state */
+	write_scr(scr);
+	isb();
+	ee = 0;
+
+	ep_attr = NON_SECURE | EP_ST_DISABLE;
+	if (sctlr & SCTLR_EE_BIT) {
+		ep_attr |= EP_EE_BIG;
+		ee = 1;
+	}
+	SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
+
+	ep->pc = entrypoint;
+	zeromem(&ep->args, sizeof(ep->args));
+	ep->args.arg0 = context_id;
+
+	mode = scr & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc;
+
+	/*
+	 * TODO: Choose async. exception bits if HYP mode is not
+	 * implemented according to the values of SCR.{AW, FW} bits
+	 */
+	aif = SPSR_ABT_BIT | SPSR_IRQ_BIT | SPSR_FIQ_BIT;
+
+	ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, aif);
+
+	return PSCI_E_SUCCESS;
+}
+
+#endif /* __aarch64__ */
+
+/*******************************************************************************
+ * This function validates the entrypoint with the platform layer if the
+ * appropriate pm_ops hook is exported by the platform and returns the
+ * 'entry_point_info'.
+ ******************************************************************************/
+int psci_validate_entry_point(entry_point_info_t *ep,
+			      uintptr_t entrypoint,
+			      u_register_t context_id)
+{
+	int rc;
+
+	/* Validate the entrypoint using platform psci_ops */
+	if (psci_plat_pm_ops->validate_ns_entrypoint != NULL) {
+		rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint);
+		if (rc != PSCI_E_SUCCESS)
+			return PSCI_E_INVALID_ADDRESS;
+	}
+
+	/*
+	 * Verify and derive the re-entry information for
+	 * the non-secure world from the non-secure state from
+	 * where this call originated.
+	 */
+	rc = psci_get_ns_ep_info(ep, entrypoint, context_id);
+	return rc;
+}
+
+/*******************************************************************************
+ * Generic handler which is called when a cpu is physically powered on. It
+ * traverses the node information and finds the highest power level powered
+ * off and performs generic, architectural, platform setup and state management
+ * to power on that power level and power levels below it.
+ * e.g. For a cpu that's been powered on, it will call the platform specific
+ * code to enable the gic cpu interface and for a cluster it will enable
+ * coherency at the interconnect level in addition to gic cpu interface.
+ ******************************************************************************/
+void psci_warmboot_entrypoint(void)
+{
+	unsigned int end_pwrlvl;
+	int cpu_idx = (int) plat_my_core_pos();
+	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
+
+	/*
+	 * Verify that we have been explicitly turned ON or resumed from
+	 * suspend.
+	 */
+	if (psci_get_aff_info_state() == AFF_STATE_OFF) {
+		ERROR("Unexpected affinity info state");
+		panic();
+	}
+
+	/*
+	 * Get the maximum power domain level to traverse to after this cpu
+	 * has been physically powered up.
+	 */
+	end_pwrlvl = get_power_on_target_pwrlvl();
+
+	/* Get the parent nodes */
+	psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
+
+	/*
+	 * This function acquires the lock corresponding to each power level so
+	 * that by the time all locks are taken, the system topology is snapshot
+	 * and state management can be done safely.
+	 */
+	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
+	psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
+
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_stop(&state_info);
+#endif
+
+	/*
+	 * This CPU could be resuming from suspend or it could have just been
+	 * turned on. To distinguish between these 2 cases, we examine the
+	 * affinity state of the CPU:
+	 *  - If the affinity state is ON_PENDING then it has just been
+	 *    turned on.
+	 *  - Else it is resuming from suspend.
+	 *
+	 * Depending on the type of warm reset identified, choose the right set
+	 * of power management handler and perform the generic, architecture
+	 * and platform specific handling.
+	 */
+	if (psci_get_aff_info_state() == AFF_STATE_ON_PENDING)
+		psci_cpu_on_finish(cpu_idx, &state_info);
+	else
+		psci_cpu_suspend_finish(cpu_idx, &state_info);
+
+	/*
+	 * Set the requested and target state of this CPU and all the higher
+	 * power domains which are ancestors of this CPU to run.
+	 */
+	psci_set_pwr_domains_to_run(end_pwrlvl);
+
+#if ENABLE_PSCI_STAT
+	/*
+	 * Update PSCI stats.
+	 * Caches are off when writing stats data on the power down path.
+	 * Since caches are now enabled, it's necessary to do cache
+	 * maintenance before reading that same data.
+	 */
+	psci_stats_update_pwr_up(end_pwrlvl, &state_info);
+#endif
+
+	/*
+	 * This loop releases the lock corresponding to each power level
+	 * in the reverse order to which they were acquired.
+	 */
+	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
+}
+
+/*******************************************************************************
+ * This function initializes the set of hooks that PSCI invokes as part of power
+ * management operation. The power management hooks are expected to be provided
+ * by the SPD, after it finishes all its initialization
+ ******************************************************************************/
+void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
+{
+	assert(pm != NULL);
+	psci_spd_pm = pm;
+
+	if (pm->svc_migrate != NULL)
+		psci_caps |= define_psci_cap(PSCI_MIG_AARCH64);
+
+	if (pm->svc_migrate_info != NULL)
+		psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64)
+				| define_psci_cap(PSCI_MIG_INFO_TYPE);
+}
+
+/*******************************************************************************
+ * This function invokes the migrate info hook in the spd_pm_ops. It performs
+ * the necessary return value validation. If the Secure Payload is UP and
+ * migrate capable, it returns the mpidr of the CPU on which the Secure payload
+ * is resident through the mpidr parameter. Else the value of the parameter on
+ * return is undefined.
+ ******************************************************************************/
+int psci_spd_migrate_info(u_register_t *mpidr)
+{
+	int rc;
+
+	if ((psci_spd_pm == NULL) || (psci_spd_pm->svc_migrate_info == NULL))
+		return PSCI_E_NOT_SUPPORTED;
+
+	rc = psci_spd_pm->svc_migrate_info(mpidr);
+
+	assert((rc == PSCI_TOS_UP_MIG_CAP) || (rc == PSCI_TOS_NOT_UP_MIG_CAP) ||
+	       (rc == PSCI_TOS_NOT_PRESENT_MP) || (rc == PSCI_E_NOT_SUPPORTED));
+
+	return rc;
+}
+
+
+/*******************************************************************************
+ * This function prints the state of all power domains present in the
+ * system
+ ******************************************************************************/
+void psci_print_power_domain_map(void)
+{
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+	int idx;
+	plat_local_state_t state;
+	plat_local_state_type_t state_type;
+
+	/* This array maps to the PSCI_STATE_X definitions in psci.h */
+	static const char * const psci_state_type_str[] = {
+		"ON",
+		"RETENTION",
+		"OFF",
+	};
+
+	INFO("PSCI Power Domain Map:\n");
+	for (idx = 0; idx < (PSCI_NUM_PWR_DOMAINS - PLATFORM_CORE_COUNT);
+							idx++) {
+		state_type = find_local_state_type(
+				psci_non_cpu_pd_nodes[idx].local_state);
+		INFO("  Domain Node : Level %u, parent_node %d,"
+				" State %s (0x%x)\n",
+				psci_non_cpu_pd_nodes[idx].level,
+				psci_non_cpu_pd_nodes[idx].parent_node,
+				psci_state_type_str[state_type],
+				psci_non_cpu_pd_nodes[idx].local_state);
+	}
+
+	for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++) {
+		state = psci_get_cpu_local_state_by_idx(idx);
+		state_type = find_local_state_type(state);
+		INFO("  CPU Node : MPID 0x%llx, parent_node %d,"
+				" State %s (0x%x)\n",
+				(unsigned long long)psci_cpu_pd_nodes[idx].mpidr,
+				psci_cpu_pd_nodes[idx].parent_node,
+				psci_state_type_str[state_type],
+				psci_get_cpu_local_state_by_idx(idx));
+	}
+#endif
+}
+
+/******************************************************************************
+ * Return whether any secondaries were powered up with CPU_ON call. A CPU that
+ * have ever been powered up would have set its MPDIR value to something other
+ * than PSCI_INVALID_MPIDR. Note that MPDIR isn't reset back to
+ * PSCI_INVALID_MPIDR when a CPU is powered down later, so the return value is
+ * meaningful only when called on the primary CPU during early boot.
+ *****************************************************************************/
+int psci_secondaries_brought_up(void)
+{
+	unsigned int idx, n_valid = 0U;
+
+	for (idx = 0U; idx < ARRAY_SIZE(psci_cpu_pd_nodes); idx++) {
+		if (psci_cpu_pd_nodes[idx].mpidr != PSCI_INVALID_MPIDR)
+			n_valid++;
+	}
+
+	assert(n_valid > 0U);
+
+	return (n_valid > 1U) ? 1 : 0;
+}
+
+/*******************************************************************************
+ * Initiate power down sequence, by calling power down operations registered for
+ * this CPU.
+ ******************************************************************************/
+void psci_do_pwrdown_sequence(unsigned int power_level)
+{
+#if HW_ASSISTED_COHERENCY
+	/*
+	 * With hardware-assisted coherency, the CPU drivers only initiate the
+	 * power down sequence, without performing cache-maintenance operations
+	 * in software. Data caches enabled both before and after this call.
+	 */
+	prepare_cpu_pwr_dwn(power_level);
+#else
+	/*
+	 * Without hardware-assisted coherency, the CPU drivers disable data
+	 * caches, then perform cache-maintenance operations in software.
+	 *
+	 * This also calls prepare_cpu_pwr_dwn() to initiate power down
+	 * sequence, but that function will return with data caches disabled.
+	 * We must ensure that the stack memory is flushed out to memory before
+	 * we start popping from it again.
+	 */
+	psci_do_pwrdown_cache_maintenance(power_level);
+#endif
+}
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk
new file mode 100644
index 0000000..1d4aac4
--- /dev/null
+++ b/lib/psci/psci_lib.mk
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PSCI_LIB_SOURCES	:=	lib/el3_runtime/cpu_data_array.c	\
+				lib/el3_runtime/${ARCH}/cpu_data.S	\
+				lib/el3_runtime/${ARCH}/context_mgmt.c	\
+				lib/cpus/${ARCH}/cpu_helpers.S		\
+				lib/cpus/errata_report.c		\
+				lib/locks/exclusive/${ARCH}/spinlock.S	\
+				lib/psci/psci_off.c			\
+				lib/psci/psci_on.c			\
+				lib/psci/psci_suspend.c			\
+				lib/psci/psci_common.c			\
+				lib/psci/psci_main.c			\
+				lib/psci/psci_setup.c			\
+				lib/psci/psci_system_off.c		\
+				lib/psci/psci_mem_protect.c		\
+				lib/psci/${ARCH}/psci_helpers.S
+
+ifeq (${ARCH}, aarch64)
+PSCI_LIB_SOURCES	+=	lib/el3_runtime/aarch64/context.S
+endif
+
+ifeq (${USE_COHERENT_MEM}, 1)
+PSCI_LIB_SOURCES		+=	lib/locks/bakery/bakery_lock_coherent.c
+else
+PSCI_LIB_SOURCES		+=	lib/locks/bakery/bakery_lock_normal.c
+endif
+
+ifeq (${ENABLE_PSCI_STAT}, 1)
+PSCI_LIB_SOURCES		+=	lib/psci/psci_stat.c
+endif
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
new file mode 100644
index 0000000..5c0e952
--- /dev/null
+++ b/lib/psci/psci_main.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <lib/smccc.h>
+#include <plat/common/platform.h>
+#include <services/arm_arch_svc.h>
+
+#include "psci_private.h"
+
+/*******************************************************************************
+ * PSCI frontend api for servicing SMCs. Described in the PSCI spec.
+ ******************************************************************************/
+int psci_cpu_on(u_register_t target_cpu,
+		uintptr_t entrypoint,
+		u_register_t context_id)
+
+{
+	int rc;
+	entry_point_info_t ep;
+
+	/* Determine if the cpu exists of not */
+	rc = psci_validate_mpidr(target_cpu);
+	if (rc != PSCI_E_SUCCESS)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Validate the entry point and get the entry_point_info */
+	rc = psci_validate_entry_point(&ep, entrypoint, context_id);
+	if (rc != PSCI_E_SUCCESS)
+		return rc;
+
+	/*
+	 * To turn this cpu on, specify which power
+	 * levels need to be turned on
+	 */
+	return psci_cpu_on_start(target_cpu, &ep);
+}
+
+unsigned int psci_version(void)
+{
+	return PSCI_MAJOR_VER | PSCI_MINOR_VER;
+}
+
+int psci_cpu_suspend(unsigned int power_state,
+		     uintptr_t entrypoint,
+		     u_register_t context_id)
+{
+	int rc;
+	unsigned int target_pwrlvl, is_power_down_state;
+	entry_point_info_t ep;
+	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
+	plat_local_state_t cpu_pd_state;
+
+	/* Validate the power_state parameter */
+	rc = psci_validate_power_state(power_state, &state_info);
+	if (rc != PSCI_E_SUCCESS) {
+		assert(rc == PSCI_E_INVALID_PARAMS);
+		return rc;
+	}
+
+	/*
+	 * Get the value of the state type bit from the power state parameter.
+	 */
+	is_power_down_state = psci_get_pstate_type(power_state);
+
+	/* Sanity check the requested suspend levels */
+	assert(psci_validate_suspend_req(&state_info, is_power_down_state)
+			== PSCI_E_SUCCESS);
+
+	target_pwrlvl = psci_find_target_suspend_lvl(&state_info);
+	if (target_pwrlvl == PSCI_INVALID_PWR_LVL) {
+		ERROR("Invalid target power level for suspend operation\n");
+		panic();
+	}
+
+	/* Fast path for CPU standby.*/
+	if (is_cpu_standby_req(is_power_down_state, target_pwrlvl)) {
+		if  (psci_plat_pm_ops->cpu_standby == NULL)
+			return PSCI_E_INVALID_PARAMS;
+
+		/*
+		 * Set the state of the CPU power domain to the platform
+		 * specific retention state and enter the standby state.
+		 */
+		cpu_pd_state = state_info.pwr_domain_state[PSCI_CPU_PWR_LVL];
+		psci_set_cpu_local_state(cpu_pd_state);
+
+#if ENABLE_PSCI_STAT
+		plat_psci_stat_accounting_start(&state_info);
+#endif
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		    RT_INSTR_ENTER_HW_LOW_PWR,
+		    PMF_NO_CACHE_MAINT);
+#endif
+
+		psci_plat_pm_ops->cpu_standby(cpu_pd_state);
+
+		/* Upon exit from standby, set the state back to RUN. */
+		psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		    RT_INSTR_EXIT_HW_LOW_PWR,
+		    PMF_NO_CACHE_MAINT);
+#endif
+
+#if ENABLE_PSCI_STAT
+		plat_psci_stat_accounting_stop(&state_info);
+
+		/* Update PSCI stats */
+		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info);
+#endif
+
+		return PSCI_E_SUCCESS;
+	}
+
+	/*
+	 * If a power down state has been requested, we need to verify entry
+	 * point and program entry information.
+	 */
+	if (is_power_down_state != 0U) {
+		rc = psci_validate_entry_point(&ep, entrypoint, context_id);
+		if (rc != PSCI_E_SUCCESS)
+			return rc;
+	}
+
+	/*
+	 * Do what is needed to enter the power down state. Upon success,
+	 * enter the final wfi which will power down this CPU. This function
+	 * might return if the power down was abandoned for any reason, e.g.
+	 * arrival of an interrupt
+	 */
+	psci_cpu_suspend_start(&ep,
+			    target_pwrlvl,
+			    &state_info,
+			    is_power_down_state);
+
+	return PSCI_E_SUCCESS;
+}
+
+
+int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id)
+{
+	int rc;
+	psci_power_state_t state_info;
+	entry_point_info_t ep;
+
+	/* Check if the current CPU is the last ON CPU in the system */
+	if (psci_is_last_on_cpu() == 0U)
+		return PSCI_E_DENIED;
+
+	/* Validate the entry point and get the entry_point_info */
+	rc = psci_validate_entry_point(&ep, entrypoint, context_id);
+	if (rc != PSCI_E_SUCCESS)
+		return rc;
+
+	/* Query the psci_power_state for system suspend */
+	psci_query_sys_suspend_pwrstate(&state_info);
+
+	/*
+	 * Check if platform allows suspend to Highest power level
+	 * (System level)
+	 */
+	if (psci_find_target_suspend_lvl(&state_info) < PLAT_MAX_PWR_LVL)
+		return PSCI_E_DENIED;
+
+	/* Ensure that the psci_power_state makes sense */
+	assert(psci_validate_suspend_req(&state_info, PSTATE_TYPE_POWERDOWN)
+						== PSCI_E_SUCCESS);
+	assert(is_local_state_off(
+			state_info.pwr_domain_state[PLAT_MAX_PWR_LVL]) != 0);
+
+	/*
+	 * Do what is needed to enter the system suspend state. This function
+	 * might return if the power down was abandoned for any reason, e.g.
+	 * arrival of an interrupt
+	 */
+	psci_cpu_suspend_start(&ep,
+			    PLAT_MAX_PWR_LVL,
+			    &state_info,
+			    PSTATE_TYPE_POWERDOWN);
+
+	return PSCI_E_SUCCESS;
+}
+
+int psci_cpu_off(void)
+{
+	int rc;
+	unsigned int target_pwrlvl = PLAT_MAX_PWR_LVL;
+
+	/*
+	 * Do what is needed to power off this CPU and possible higher power
+	 * levels if it able to do so. Upon success, enter the final wfi
+	 * which will power down this CPU.
+	 */
+	rc = psci_do_cpu_off(target_pwrlvl);
+
+	/*
+	 * The only error cpu_off can return is E_DENIED. So check if that's
+	 * indeed the case.
+	 */
+	assert(rc == PSCI_E_DENIED);
+
+	return rc;
+}
+
+int psci_affinity_info(u_register_t target_affinity,
+		       unsigned int lowest_affinity_level)
+{
+	int target_idx;
+
+	/* We dont support level higher than PSCI_CPU_PWR_LVL */
+	if (lowest_affinity_level > PSCI_CPU_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Calculate the cpu index of the target */
+	target_idx = plat_core_pos_by_mpidr(target_affinity);
+	if (target_idx == -1)
+		return PSCI_E_INVALID_PARAMS;
+
+	/*
+	 * Generic management:
+	 * Perform cache maintanence ahead of reading the target CPU state to
+	 * ensure that the data is not stale.
+	 * There is a theoretical edge case where the cache may contain stale
+	 * data for the target CPU data - this can occur under the following
+	 * conditions:
+	 * - the target CPU is in another cluster from the current
+	 * - the target CPU was the last CPU to shutdown on its cluster
+	 * - the cluster was removed from coherency as part of the CPU shutdown
+	 *
+	 * In this case the cache maintenace that was performed as part of the
+	 * target CPUs shutdown was not seen by the current CPU's cluster. And
+	 * so the cache may contain stale data for the target CPU.
+	 */
+	flush_cpu_data_by_index((unsigned int)target_idx,
+				psci_svc_cpu_data.aff_info_state);
+
+	return psci_get_aff_info_state_by_idx(target_idx);
+}
+
+int psci_migrate(u_register_t target_cpu)
+{
+	int rc;
+	u_register_t resident_cpu_mpidr;
+
+	rc = psci_spd_migrate_info(&resident_cpu_mpidr);
+	if (rc != PSCI_TOS_UP_MIG_CAP)
+		return (rc == PSCI_TOS_NOT_UP_MIG_CAP) ?
+			  PSCI_E_DENIED : PSCI_E_NOT_SUPPORTED;
+
+	/*
+	 * Migrate should only be invoked on the CPU where
+	 * the Secure OS is resident.
+	 */
+	if (resident_cpu_mpidr != read_mpidr_el1())
+		return PSCI_E_NOT_PRESENT;
+
+	/* Check the validity of the specified target cpu */
+	rc = psci_validate_mpidr(target_cpu);
+	if (rc != PSCI_E_SUCCESS)
+		return PSCI_E_INVALID_PARAMS;
+
+	assert((psci_spd_pm != NULL) && (psci_spd_pm->svc_migrate != NULL));
+
+	rc = psci_spd_pm->svc_migrate(read_mpidr_el1(), target_cpu);
+	assert((rc == PSCI_E_SUCCESS) || (rc == PSCI_E_INTERN_FAIL));
+
+	return rc;
+}
+
+int psci_migrate_info_type(void)
+{
+	u_register_t resident_cpu_mpidr;
+
+	return psci_spd_migrate_info(&resident_cpu_mpidr);
+}
+
+u_register_t psci_migrate_info_up_cpu(void)
+{
+	u_register_t resident_cpu_mpidr;
+	int rc;
+
+	/*
+	 * Return value of this depends upon what
+	 * psci_spd_migrate_info() returns.
+	 */
+	rc = psci_spd_migrate_info(&resident_cpu_mpidr);
+	if ((rc != PSCI_TOS_NOT_UP_MIG_CAP) && (rc != PSCI_TOS_UP_MIG_CAP))
+		return (u_register_t)(register_t) PSCI_E_INVALID_PARAMS;
+
+	return resident_cpu_mpidr;
+}
+
+int psci_node_hw_state(u_register_t target_cpu,
+		       unsigned int power_level)
+{
+	int rc;
+
+	/* Validate target_cpu */
+	rc = psci_validate_mpidr(target_cpu);
+	if (rc != PSCI_E_SUCCESS)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Validate power_level against PLAT_MAX_PWR_LVL */
+	if (power_level > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/*
+	 * Dispatch this call to platform to query power controller, and pass on
+	 * to the caller what it returns
+	 */
+	assert(psci_plat_pm_ops->get_node_hw_state != NULL);
+	rc = psci_plat_pm_ops->get_node_hw_state(target_cpu, power_level);
+	assert(((rc >= HW_ON) && (rc <= HW_STANDBY))
+		|| (rc == PSCI_E_NOT_SUPPORTED)
+		|| (rc == PSCI_E_INVALID_PARAMS));
+	return rc;
+}
+
+int psci_features(unsigned int psci_fid)
+{
+	unsigned int local_caps = psci_caps;
+
+	if (psci_fid == SMCCC_VERSION)
+		return PSCI_E_SUCCESS;
+
+	/* Check if it is a 64 bit function */
+	if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)
+		local_caps &= PSCI_CAP_64BIT_MASK;
+
+	/* Check for invalid fid */
+	if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid)
+			&& is_psci_fid(psci_fid)))
+		return PSCI_E_NOT_SUPPORTED;
+
+
+	/* Check if the psci fid is supported or not */
+	if ((local_caps & define_psci_cap(psci_fid)) == 0U)
+		return PSCI_E_NOT_SUPPORTED;
+
+	/* Format the feature flags */
+	if ((psci_fid == PSCI_CPU_SUSPEND_AARCH32) ||
+	    (psci_fid == PSCI_CPU_SUSPEND_AARCH64)) {
+		/*
+		 * The trusted firmware does not support OS Initiated Mode.
+		 */
+		unsigned int ret = ((FF_PSTATE << FF_PSTATE_SHIFT) |
+			(((FF_SUPPORTS_OS_INIT_MODE == 1U) ? 0U : 1U)
+				<< FF_MODE_SUPPORT_SHIFT));
+		return (int) ret;
+	}
+
+	/* Return 0 for all other fid's */
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * PSCI top level handler for servicing SMCs.
+ ******************************************************************************/
+u_register_t psci_smc_handler(uint32_t smc_fid,
+			  u_register_t x1,
+			  u_register_t x2,
+			  u_register_t x3,
+			  u_register_t x4,
+			  void *cookie,
+			  void *handle,
+			  u_register_t flags)
+{
+	u_register_t ret;
+
+	if (is_caller_secure(flags))
+		return (u_register_t)SMC_UNK;
+
+	/* Check the fid against the capabilities */
+	if ((psci_caps & define_psci_cap(smc_fid)) == 0U)
+		return (u_register_t)SMC_UNK;
+
+	if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
+		/* 32-bit PSCI function, clear top parameter bits */
+
+		uint32_t r1 = (uint32_t)x1;
+		uint32_t r2 = (uint32_t)x2;
+		uint32_t r3 = (uint32_t)x3;
+
+		switch (smc_fid) {
+		case PSCI_VERSION:
+			ret = (u_register_t)psci_version();
+			break;
+
+		case PSCI_CPU_OFF:
+			ret = (u_register_t)psci_cpu_off();
+			break;
+
+		case PSCI_CPU_SUSPEND_AARCH32:
+			ret = (u_register_t)psci_cpu_suspend(r1, r2, r3);
+			break;
+
+		case PSCI_CPU_ON_AARCH32:
+			ret = (u_register_t)psci_cpu_on(r1, r2, r3);
+			break;
+
+		case PSCI_AFFINITY_INFO_AARCH32:
+			ret = (u_register_t)psci_affinity_info(r1, r2);
+			break;
+
+		case PSCI_MIG_AARCH32:
+			ret = (u_register_t)psci_migrate(r1);
+			break;
+
+		case PSCI_MIG_INFO_TYPE:
+			ret = (u_register_t)psci_migrate_info_type();
+			break;
+
+		case PSCI_MIG_INFO_UP_CPU_AARCH32:
+			ret = psci_migrate_info_up_cpu();
+			break;
+
+		case PSCI_NODE_HW_STATE_AARCH32:
+			ret = (u_register_t)psci_node_hw_state(r1, r2);
+			break;
+
+		case PSCI_SYSTEM_SUSPEND_AARCH32:
+			ret = (u_register_t)psci_system_suspend(r1, r2);
+			break;
+
+		case PSCI_SYSTEM_OFF:
+			psci_system_off();
+			/* We should never return from psci_system_off() */
+			break;
+
+		case PSCI_SYSTEM_RESET:
+			psci_system_reset();
+			/* We should never return from psci_system_reset() */
+			break;
+
+		case PSCI_FEATURES:
+			ret = (u_register_t)psci_features(r1);
+			break;
+
+#if ENABLE_PSCI_STAT
+		case PSCI_STAT_RESIDENCY_AARCH32:
+			ret = psci_stat_residency(r1, r2);
+			break;
+
+		case PSCI_STAT_COUNT_AARCH32:
+			ret = psci_stat_count(r1, r2);
+			break;
+#endif
+		case PSCI_MEM_PROTECT:
+			ret = psci_mem_protect(r1);
+			break;
+
+		case PSCI_MEM_CHK_RANGE_AARCH32:
+			ret = psci_mem_chk_range(r1, r2);
+			break;
+
+		case PSCI_SYSTEM_RESET2_AARCH32:
+			/* We should never return from psci_system_reset2() */
+			ret = psci_system_reset2(r1, r2);
+			break;
+
+		default:
+			WARN("Unimplemented PSCI Call: 0x%x\n", smc_fid);
+			ret = (u_register_t)SMC_UNK;
+			break;
+		}
+	} else {
+		/* 64-bit PSCI function */
+
+		switch (smc_fid) {
+		case PSCI_CPU_SUSPEND_AARCH64:
+			ret = (u_register_t)
+				psci_cpu_suspend((unsigned int)x1, x2, x3);
+			break;
+
+		case PSCI_CPU_ON_AARCH64:
+			ret = (u_register_t)psci_cpu_on(x1, x2, x3);
+			break;
+
+		case PSCI_AFFINITY_INFO_AARCH64:
+			ret = (u_register_t)
+				psci_affinity_info(x1, (unsigned int)x2);
+			break;
+
+		case PSCI_MIG_AARCH64:
+			ret = (u_register_t)psci_migrate(x1);
+			break;
+
+		case PSCI_MIG_INFO_UP_CPU_AARCH64:
+			ret = psci_migrate_info_up_cpu();
+			break;
+
+		case PSCI_NODE_HW_STATE_AARCH64:
+			ret = (u_register_t)psci_node_hw_state(
+					x1, (unsigned int) x2);
+			break;
+
+		case PSCI_SYSTEM_SUSPEND_AARCH64:
+			ret = (u_register_t)psci_system_suspend(x1, x2);
+			break;
+
+#if ENABLE_PSCI_STAT
+		case PSCI_STAT_RESIDENCY_AARCH64:
+			ret = psci_stat_residency(x1, (unsigned int) x2);
+			break;
+
+		case PSCI_STAT_COUNT_AARCH64:
+			ret = psci_stat_count(x1, (unsigned int) x2);
+			break;
+#endif
+
+		case PSCI_MEM_CHK_RANGE_AARCH64:
+			ret = psci_mem_chk_range(x1, x2);
+			break;
+
+		case PSCI_SYSTEM_RESET2_AARCH64:
+			/* We should never return from psci_system_reset2() */
+			ret = psci_system_reset2((uint32_t) x1, x2);
+			break;
+
+		default:
+			WARN("Unimplemented PSCI Call: 0x%x\n", smc_fid);
+			ret = (u_register_t)SMC_UNK;
+			break;
+		}
+	}
+
+	return ret;
+}
diff --git a/lib/psci/psci_mem_protect.c b/lib/psci/psci_mem_protect.c
new file mode 100644
index 0000000..481051f
--- /dev/null
+++ b/lib/psci/psci_mem_protect.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <lib/utils.h>
+
+#include "psci_private.h"
+
+u_register_t psci_mem_protect(unsigned int enable)
+{
+	int val;
+
+	assert(psci_plat_pm_ops->read_mem_protect != NULL);
+	assert(psci_plat_pm_ops->write_mem_protect != NULL);
+
+	if (psci_plat_pm_ops->read_mem_protect(&val) < 0)
+		return (u_register_t) PSCI_E_NOT_SUPPORTED;
+	if (psci_plat_pm_ops->write_mem_protect(enable) < 0)
+		return (u_register_t) PSCI_E_NOT_SUPPORTED;
+
+	return (val != 0) ? 1U : 0U;
+}
+
+u_register_t psci_mem_chk_range(uintptr_t base, u_register_t length)
+{
+	int ret;
+
+	assert(psci_plat_pm_ops->mem_protect_chk != NULL);
+
+	if ((length == 0U) || check_uptr_overflow(base, length - 1U))
+		return (u_register_t) PSCI_E_DENIED;
+
+	ret = psci_plat_pm_ops->mem_protect_chk(base, length);
+	return (ret < 0) ?
+	       (u_register_t) PSCI_E_DENIED : (u_register_t) PSCI_E_SUCCESS;
+}
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
new file mode 100644
index 0000000..e8cd8fe
--- /dev/null
+++ b/lib/psci/psci_off.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/******************************************************************************
+ * Construct the psci_power_state to request power OFF at all power levels.
+ ******************************************************************************/
+static void psci_set_power_off_state(psci_power_state_t *state_info)
+{
+	unsigned int lvl;
+
+	for (lvl = PSCI_CPU_PWR_LVL; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+		state_info->pwr_domain_state[lvl] = PLAT_MAX_OFF_STATE;
+}
+
+/******************************************************************************
+ * Top level handler which is called when a cpu wants to power itself down.
+ * It's assumed that along with turning the cpu power domain off, power
+ * domains at higher levels will be turned off as far as possible. It finds
+ * the highest level where a domain has to be powered off by traversing the
+ * node information and then performs generic, architectural, platform setup
+ * and state management required to turn OFF that power domain and domains
+ * below it. e.g. For a cpu that's to be powered OFF, it could mean programming
+ * the power controller whereas for a cluster that's to be powered off, it will
+ * call the platform specific code which will disable coherency at the
+ * interconnect level if the cpu is the last in the cluster and also the
+ * program the power controller.
+ ******************************************************************************/
+int psci_do_cpu_off(unsigned int end_pwrlvl)
+{
+	int rc = PSCI_E_SUCCESS;
+	int idx = (int) plat_my_core_pos();
+	psci_power_state_t state_info;
+	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+
+	/*
+	 * This function must only be called on platforms where the
+	 * CPU_OFF platform hooks have been implemented.
+	 */
+	assert(psci_plat_pm_ops->pwr_domain_off != NULL);
+
+	/* Construct the psci_power_state for CPU_OFF */
+	psci_set_power_off_state(&state_info);
+
+	/*
+	 * Get the parent nodes here, this is important to do before we
+	 * initiate the power down sequence as after that point the core may
+	 * have exited coherency and its cache may be disabled, any access to
+	 * shared memory after that (such as the parent node lookup in
+	 * psci_cpu_pd_nodes) can cause coherency issues on some platforms.
+	 */
+	psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes);
+
+	/*
+	 * This function acquires the lock corresponding to each power
+	 * level so that by the time all locks are taken, the system topology
+	 * is snapshot and state management can be done safely.
+	 */
+	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
+	/*
+	 * Call the cpu off handler registered by the Secure Payload Dispatcher
+	 * to let it do any bookkeeping. Assume that the SPD always reports an
+	 * E_DENIED error if SP refuse to power down
+	 */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_off != NULL)) {
+		rc = psci_spd_pm->svc_off(0);
+		if (rc != 0)
+			goto exit;
+	}
+
+	/*
+	 * This function is passed the requested state info and
+	 * it returns the negotiated state info for each power level upto
+	 * the end level specified.
+	 */
+	psci_do_state_coordination(end_pwrlvl, &state_info);
+
+#if ENABLE_PSCI_STAT
+	/* Update the last cpu for each level till end_pwrlvl */
+	psci_stats_update_pwr_down(end_pwrlvl, &state_info);
+#endif
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+	/*
+	 * Flush cache line so that even if CPU power down happens
+	 * the timestamp update is reflected in memory.
+	 */
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		RT_INSTR_ENTER_CFLUSH,
+		PMF_CACHE_MAINT);
+#endif
+
+	/*
+	 * Arch. management. Initiate power down sequence.
+	 */
+	psci_do_pwrdown_sequence(psci_find_max_off_lvl(&state_info));
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		RT_INSTR_EXIT_CFLUSH,
+		PMF_NO_CACHE_MAINT);
+#endif
+
+	/*
+	 * Plat. management: Perform platform specific actions to turn this
+	 * cpu off e.g. exit cpu coherency, program the power controller etc.
+	 */
+	psci_plat_pm_ops->pwr_domain_off(&state_info);
+
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_start(&state_info);
+#endif
+
+exit:
+	/*
+	 * Release the locks corresponding to each power level in the
+	 * reverse order to which they were acquired.
+	 */
+	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
+	/*
+	 * Check if all actions needed to safely power down this cpu have
+	 * successfully completed.
+	 */
+	if (rc == PSCI_E_SUCCESS) {
+		/*
+		 * Set the affinity info state to OFF. When caches are disabled,
+		 * this writes directly to main memory, so cache maintenance is
+		 * required to ensure that later cached reads of aff_info_state
+		 * return AFF_STATE_OFF. A dsbish() ensures ordering of the
+		 * update to the affinity info state prior to cache line
+		 * invalidation.
+		 */
+		psci_flush_cpu_data(psci_svc_cpu_data.aff_info_state);
+		psci_set_aff_info_state(AFF_STATE_OFF);
+		psci_dsbish();
+		psci_inv_cpu_data(psci_svc_cpu_data.aff_info_state);
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+		/*
+		 * Update the timestamp with cache off.  We assume this
+		 * timestamp can only be read from the current CPU and the
+		 * timestamp cache line will be flushed before return to
+		 * normal world on wakeup.
+		 */
+		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		    RT_INSTR_ENTER_HW_LOW_PWR,
+		    PMF_NO_CACHE_MAINT);
+#endif
+
+		if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL) {
+			/* This function must not return */
+			psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info);
+		} else {
+			/*
+			 * Enter a wfi loop which will allow the power
+			 * controller to physically power down this cpu.
+			 */
+			psci_power_down_wfi();
+		}
+	}
+
+	return rc;
+}
diff --git a/lib/psci/psci_on.c b/lib/psci/psci_on.c
new file mode 100644
index 0000000..aa6b324
--- /dev/null
+++ b/lib/psci/psci_on.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/*
+ * Helper functions for the CPU level spinlocks
+ */
+static inline void psci_spin_lock_cpu(int idx)
+{
+	spin_lock(&psci_cpu_pd_nodes[idx].cpu_lock);
+}
+
+static inline void psci_spin_unlock_cpu(int idx)
+{
+	spin_unlock(&psci_cpu_pd_nodes[idx].cpu_lock);
+}
+
+/*******************************************************************************
+ * This function checks whether a cpu which has been requested to be turned on
+ * is OFF to begin with.
+ ******************************************************************************/
+static int cpu_on_validate_state(aff_info_state_t aff_state)
+{
+	if (aff_state == AFF_STATE_ON)
+		return PSCI_E_ALREADY_ON;
+
+	if (aff_state == AFF_STATE_ON_PENDING)
+		return PSCI_E_ON_PENDING;
+
+	assert(aff_state == AFF_STATE_OFF);
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Generic handler which is called to physically power on a cpu identified by
+ * its mpidr. It performs the generic, architectural, platform setup and state
+ * management to power on the target cpu e.g. it will ensure that
+ * enough information is stashed for it to resume execution in the non-secure
+ * security state.
+ *
+ * The state of all the relevant power domains are changed after calling the
+ * platform handler as it can return error.
+ ******************************************************************************/
+int psci_cpu_on_start(u_register_t target_cpu,
+		      const entry_point_info_t *ep)
+{
+	int rc;
+	aff_info_state_t target_aff_state;
+	int target_idx = plat_core_pos_by_mpidr(target_cpu);
+
+	/* Calling function must supply valid input arguments */
+	assert(target_idx >= 0);
+	assert(ep != NULL);
+
+	/*
+	 * This function must only be called on platforms where the
+	 * CPU_ON platform hooks have been implemented.
+	 */
+	assert((psci_plat_pm_ops->pwr_domain_on != NULL) &&
+	       (psci_plat_pm_ops->pwr_domain_on_finish != NULL));
+
+	/* Protect against multiple CPUs trying to turn ON the same target CPU */
+	psci_spin_lock_cpu(target_idx);
+
+	/*
+	 * Generic management: Ensure that the cpu is off to be
+	 * turned on.
+	 * Perform cache maintanence ahead of reading the target CPU state to
+	 * ensure that the data is not stale.
+	 * There is a theoretical edge case where the cache may contain stale
+	 * data for the target CPU data - this can occur under the following
+	 * conditions:
+	 * - the target CPU is in another cluster from the current
+	 * - the target CPU was the last CPU to shutdown on its cluster
+	 * - the cluster was removed from coherency as part of the CPU shutdown
+	 *
+	 * In this case the cache maintenace that was performed as part of the
+	 * target CPUs shutdown was not seen by the current CPU's cluster. And
+	 * so the cache may contain stale data for the target CPU.
+	 */
+	flush_cpu_data_by_index((unsigned int)target_idx,
+				psci_svc_cpu_data.aff_info_state);
+	rc = cpu_on_validate_state(psci_get_aff_info_state_by_idx(target_idx));
+	if (rc != PSCI_E_SUCCESS)
+		goto exit;
+
+	/*
+	 * Call the cpu on handler registered by the Secure Payload Dispatcher
+	 * to let it do any bookeeping. If the handler encounters an error, it's
+	 * expected to assert within
+	 */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_on != NULL))
+		psci_spd_pm->svc_on(target_cpu);
+
+	/*
+	 * Set the Affinity info state of the target cpu to ON_PENDING.
+	 * Flush aff_info_state as it will be accessed with caches
+	 * turned OFF.
+	 */
+	psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING);
+	flush_cpu_data_by_index((unsigned int)target_idx,
+				psci_svc_cpu_data.aff_info_state);
+
+	/*
+	 * The cache line invalidation by the target CPU after setting the
+	 * state to OFF (see psci_do_cpu_off()), could cause the update to
+	 * aff_info_state to be invalidated. Retry the update if the target
+	 * CPU aff_info_state is not ON_PENDING.
+	 */
+	target_aff_state = psci_get_aff_info_state_by_idx(target_idx);
+	if (target_aff_state != AFF_STATE_ON_PENDING) {
+		assert(target_aff_state == AFF_STATE_OFF);
+		psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING);
+		flush_cpu_data_by_index((unsigned int)target_idx,
+					psci_svc_cpu_data.aff_info_state);
+
+		assert(psci_get_aff_info_state_by_idx(target_idx) ==
+		       AFF_STATE_ON_PENDING);
+	}
+
+	/*
+	 * Perform generic, architecture and platform specific handling.
+	 */
+	/*
+	 * Plat. management: Give the platform the current state
+	 * of the target cpu to allow it to perform the necessary
+	 * steps to power on.
+	 */
+	rc = psci_plat_pm_ops->pwr_domain_on(target_cpu);
+	assert((rc == PSCI_E_SUCCESS) || (rc == PSCI_E_INTERN_FAIL));
+
+	if (rc == PSCI_E_SUCCESS)
+		/* Store the re-entry information for the non-secure world. */
+		cm_init_context_by_index((unsigned int)target_idx, ep);
+	else {
+		/* Restore the state on error. */
+		psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_OFF);
+		flush_cpu_data_by_index((unsigned int)target_idx,
+					psci_svc_cpu_data.aff_info_state);
+	}
+
+exit:
+	psci_spin_unlock_cpu(target_idx);
+	return rc;
+}
+
+/*******************************************************************************
+ * The following function finish an earlier power on request. They
+ * are called by the common finisher routine in psci_common.c. The `state_info`
+ * is the psci_power_state from which this CPU has woken up from.
+ ******************************************************************************/
+void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info)
+{
+	/*
+	 * Plat. management: Perform the platform specific actions
+	 * for this cpu e.g. enabling the gic or zeroing the mailbox
+	 * register. The actual state of this cpu has already been
+	 * changed.
+	 */
+	psci_plat_pm_ops->pwr_domain_on_finish(state_info);
+
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+	/*
+	 * Arch. management: Enable data cache and manage stack memory
+	 */
+	psci_do_pwrup_cache_maintenance();
+#endif
+
+	/*
+	 * All the platform specific actions for turning this cpu
+	 * on have completed. Perform enough arch.initialization
+	 * to run in the non-secure address space.
+	 */
+	psci_arch_setup();
+
+	/*
+	 * Lock the CPU spin lock to make sure that the context initialization
+	 * is done. Since the lock is only used in this function to create
+	 * a synchronization point with cpu_on_start(), it can be released
+	 * immediately.
+	 */
+	psci_spin_lock_cpu(cpu_idx);
+	psci_spin_unlock_cpu(cpu_idx);
+
+	/* Ensure we have been explicitly woken up by another cpu */
+	assert(psci_get_aff_info_state() == AFF_STATE_ON_PENDING);
+
+	/*
+	 * Call the cpu on finish handler registered by the Secure Payload
+	 * Dispatcher to let it do any bookeeping. If the handler encounters an
+	 * error, it's expected to assert within
+	 */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_on_finish != NULL))
+		psci_spd_pm->svc_on_finish(0);
+
+	PUBLISH_EVENT(psci_cpu_on_finish);
+
+	/* Populate the mpidr field within the cpu node array */
+	/* This needs to be done only once */
+	psci_cpu_pd_nodes[cpu_idx].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK;
+
+	/*
+	 * Generic management: Now we just need to retrieve the
+	 * information that we had stashed away during the cpu_on
+	 * call to set this cpu on its way.
+	 */
+	cm_prepare_el3_exit(NON_SECURE);
+}
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
new file mode 100644
index 0000000..bbcc5cf
--- /dev/null
+++ b/lib/psci/psci_private.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSCI_PRIVATE_H
+#define PSCI_PRIVATE_H
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+/*
+ * The PSCI capability which are provided by the generic code but does not
+ * depend on the platform or spd capabilities.
+ */
+#define PSCI_GENERIC_CAP	\
+			(define_psci_cap(PSCI_VERSION) |		\
+			define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) |	\
+			define_psci_cap(PSCI_FEATURES))
+
+/*
+ * The PSCI capabilities mask for 64 bit functions.
+ */
+#define PSCI_CAP_64BIT_MASK	\
+			(define_psci_cap(PSCI_CPU_SUSPEND_AARCH64) |	\
+			define_psci_cap(PSCI_CPU_ON_AARCH64) |		\
+			define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) |	\
+			define_psci_cap(PSCI_MIG_AARCH64) |		\
+			define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) |	\
+			define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) |	\
+			define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) |	\
+			define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) |	\
+			define_psci_cap(PSCI_STAT_COUNT_AARCH64) |	\
+			define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) |	\
+			define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64))
+
+/*
+ * Helper functions to get/set the fields of PSCI per-cpu data.
+ */
+static inline void psci_set_aff_info_state(aff_info_state_t aff_state)
+{
+	set_cpu_data(psci_svc_cpu_data.aff_info_state, aff_state);
+}
+
+static inline aff_info_state_t psci_get_aff_info_state(void)
+{
+	return get_cpu_data(psci_svc_cpu_data.aff_info_state);
+}
+
+static inline aff_info_state_t psci_get_aff_info_state_by_idx(int idx)
+{
+	return get_cpu_data_by_index((unsigned int)idx,
+				     psci_svc_cpu_data.aff_info_state);
+}
+
+static inline void psci_set_aff_info_state_by_idx(int idx,
+						  aff_info_state_t aff_state)
+{
+	set_cpu_data_by_index((unsigned int)idx,
+			      psci_svc_cpu_data.aff_info_state, aff_state);
+}
+
+static inline unsigned int psci_get_suspend_pwrlvl(void)
+{
+	return get_cpu_data(psci_svc_cpu_data.target_pwrlvl);
+}
+
+static inline void psci_set_suspend_pwrlvl(unsigned int target_lvl)
+{
+	set_cpu_data(psci_svc_cpu_data.target_pwrlvl, target_lvl);
+}
+
+static inline void psci_set_cpu_local_state(plat_local_state_t state)
+{
+	set_cpu_data(psci_svc_cpu_data.local_state, state);
+}
+
+static inline plat_local_state_t psci_get_cpu_local_state(void)
+{
+	return get_cpu_data(psci_svc_cpu_data.local_state);
+}
+
+static inline plat_local_state_t psci_get_cpu_local_state_by_idx(int idx)
+{
+	return get_cpu_data_by_index((unsigned int)idx,
+				     psci_svc_cpu_data.local_state);
+}
+
+/* Helper function to identify a CPU standby request in PSCI Suspend call */
+static inline bool is_cpu_standby_req(unsigned int is_power_down_state,
+				      unsigned int retn_lvl)
+{
+	return (is_power_down_state == 0U) && (retn_lvl == 0U);
+}
+
+/*******************************************************************************
+ * The following two data structures implement the power domain tree. The tree
+ * is used to track the state of all the nodes i.e. power domain instances
+ * described by the platform. The tree consists of nodes that describe CPU power
+ * domains i.e. leaf nodes and all other power domains which are parents of a
+ * CPU power domain i.e. non-leaf nodes.
+ ******************************************************************************/
+typedef struct non_cpu_pwr_domain_node {
+	/*
+	 * Index of the first CPU power domain node level 0 which has this node
+	 * as its parent.
+	 */
+	int cpu_start_idx;
+
+	/*
+	 * Number of CPU power domains which are siblings of the domain indexed
+	 * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
+	 * -> cpu_start_idx + ncpus' have this node as their parent.
+	 */
+	unsigned int ncpus;
+
+	/*
+	 * Index of the parent power domain node.
+	 * TODO: Figure out whether to whether using pointer is more efficient.
+	 */
+	unsigned int parent_node;
+
+	plat_local_state_t local_state;
+
+	unsigned char level;
+
+	/* For indexing the psci_lock array*/
+	unsigned char lock_index;
+} non_cpu_pd_node_t;
+
+typedef struct cpu_pwr_domain_node {
+	u_register_t mpidr;
+
+	/*
+	 * Index of the parent power domain node.
+	 * TODO: Figure out whether to whether using pointer is more efficient.
+	 */
+	unsigned int parent_node;
+
+	/*
+	 * A CPU power domain does not require state coordination like its
+	 * parent power domains. Hence this node does not include a bakery
+	 * lock. A spinlock is required by the CPU_ON handler to prevent a race
+	 * when multiple CPUs try to turn ON the same target CPU.
+	 */
+	spinlock_t cpu_lock;
+} cpu_pd_node_t;
+
+/*******************************************************************************
+ * The following are helpers and declarations of locks.
+ ******************************************************************************/
+#if HW_ASSISTED_COHERENCY
+/*
+ * On systems where participant CPUs are cache-coherent, we can use spinlocks
+ * instead of bakery locks.
+ */
+#define DEFINE_PSCI_LOCK(_name)		spinlock_t _name
+#define DECLARE_PSCI_LOCK(_name)	extern DEFINE_PSCI_LOCK(_name)
+
+/* One lock is required per non-CPU power domain node */
+DECLARE_PSCI_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]);
+
+/*
+ * On systems with hardware-assisted coherency, make PSCI cache operations NOP,
+ * as PSCI participants are cache-coherent, and there's no need for explicit
+ * cache maintenance operations or barriers to coordinate their state.
+ */
+static inline void psci_flush_dcache_range(uintptr_t __unused addr,
+					   size_t __unused size)
+{
+	/* Empty */
+}
+
+#define psci_flush_cpu_data(member)
+#define psci_inv_cpu_data(member)
+
+static inline void psci_dsbish(void)
+{
+	/* Empty */
+}
+
+static inline void psci_lock_get(non_cpu_pd_node_t *non_cpu_pd_node)
+{
+	spin_lock(&psci_locks[non_cpu_pd_node->lock_index]);
+}
+
+static inline void psci_lock_release(non_cpu_pd_node_t *non_cpu_pd_node)
+{
+	spin_unlock(&psci_locks[non_cpu_pd_node->lock_index]);
+}
+
+#else /* if HW_ASSISTED_COHERENCY == 0 */
+/*
+ * Use bakery locks for state coordination as not all PSCI participants are
+ * cache coherent.
+ */
+#define DEFINE_PSCI_LOCK(_name)		DEFINE_BAKERY_LOCK(_name)
+#define DECLARE_PSCI_LOCK(_name)	DECLARE_BAKERY_LOCK(_name)
+
+/* One lock is required per non-CPU power domain node */
+DECLARE_PSCI_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]);
+
+/*
+ * If not all PSCI participants are cache-coherent, perform cache maintenance
+ * and issue barriers wherever required to coordinate state.
+ */
+static inline void psci_flush_dcache_range(uintptr_t addr, size_t size)
+{
+	flush_dcache_range(addr, size);
+}
+
+#define psci_flush_cpu_data(member)		flush_cpu_data(member)
+#define psci_inv_cpu_data(member)		inv_cpu_data(member)
+
+static inline void psci_dsbish(void)
+{
+	dsbish();
+}
+
+static inline void psci_lock_get(non_cpu_pd_node_t *non_cpu_pd_node)
+{
+	bakery_lock_get(&psci_locks[non_cpu_pd_node->lock_index]);
+}
+
+static inline void psci_lock_release(non_cpu_pd_node_t *non_cpu_pd_node)
+{
+	bakery_lock_release(&psci_locks[non_cpu_pd_node->lock_index]);
+}
+
+#endif /* HW_ASSISTED_COHERENCY */
+
+static inline void psci_lock_init(non_cpu_pd_node_t *non_cpu_pd_node,
+				  unsigned char idx)
+{
+	non_cpu_pd_node[idx].lock_index = idx;
+}
+
+/*******************************************************************************
+ * Data prototypes
+ ******************************************************************************/
+extern const plat_psci_ops_t *psci_plat_pm_ops;
+extern non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
+extern cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
+extern unsigned int psci_caps;
+
+/*******************************************************************************
+ * SPD's power management hooks registered with PSCI
+ ******************************************************************************/
+extern const spd_pm_ops_t *psci_spd_pm;
+
+/*******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+/* Private exported functions from psci_common.c */
+int psci_validate_power_state(unsigned int power_state,
+			      psci_power_state_t *state_info);
+void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info);
+int psci_validate_mpidr(u_register_t mpidr);
+void psci_init_req_local_pwr_states(void);
+void psci_get_target_local_pwr_states(unsigned int end_pwrlvl,
+				      psci_power_state_t *target_state);
+int psci_validate_entry_point(entry_point_info_t *ep,
+			uintptr_t entrypoint, u_register_t context_id);
+void psci_get_parent_pwr_domain_nodes(int cpu_idx,
+				      unsigned int end_lvl,
+				      unsigned int *node_index);
+void psci_do_state_coordination(unsigned int end_pwrlvl,
+				psci_power_state_t *state_info);
+void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl,
+				   const unsigned int *parent_nodes);
+void psci_release_pwr_domain_locks(unsigned int end_pwrlvl,
+				   const unsigned int *parent_nodes);
+int psci_validate_suspend_req(const psci_power_state_t *state_info,
+			      unsigned int is_power_down_state);
+unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info);
+unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info);
+void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl);
+void psci_print_power_domain_map(void);
+unsigned int psci_is_last_on_cpu(void);
+int psci_spd_migrate_info(u_register_t *mpidr);
+void psci_do_pwrdown_sequence(unsigned int power_level);
+
+/*
+ * CPU power down is directly called only when HW_ASSISTED_COHERENCY is
+ * available. Otherwise, this needs post-call stack maintenance, which is
+ * handled in assembly.
+ */
+void prepare_cpu_pwr_dwn(unsigned int power_level);
+
+/* Private exported functions from psci_on.c */
+int psci_cpu_on_start(u_register_t target_cpu,
+		      const entry_point_info_t *ep);
+
+void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info);
+
+/* Private exported functions from psci_off.c */
+int psci_do_cpu_off(unsigned int end_pwrlvl);
+
+/* Private exported functions from psci_suspend.c */
+void psci_cpu_suspend_start(const entry_point_info_t *ep,
+			unsigned int end_pwrlvl,
+			psci_power_state_t *state_info,
+			unsigned int is_power_down_state);
+
+void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info);
+
+/* Private exported functions from psci_helpers.S */
+void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level);
+void psci_do_pwrup_cache_maintenance(void);
+
+/* Private exported functions from psci_system_off.c */
+void __dead2 psci_system_off(void);
+void __dead2 psci_system_reset(void);
+u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie);
+
+/* Private exported functions from psci_stat.c */
+void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
+			const psci_power_state_t *state_info);
+void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
+			const psci_power_state_t *state_info);
+u_register_t psci_stat_residency(u_register_t target_cpu,
+			unsigned int power_state);
+u_register_t psci_stat_count(u_register_t target_cpu,
+			unsigned int power_state);
+
+/* Private exported functions from psci_mem_protect.c */
+u_register_t psci_mem_protect(unsigned int enable);
+u_register_t psci_mem_chk_range(uintptr_t base, u_register_t length);
+
+#endif /* PSCI_PRIVATE_H */
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
new file mode 100644
index 0000000..b9467d3
--- /dev/null
+++ b/lib/psci/psci_setup.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/cpus/errata_report.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/*******************************************************************************
+ * Per cpu non-secure contexts used to program the architectural state prior
+ * return to the normal world.
+ * TODO: Use the memory allocator to set aside memory for the contexts instead
+ * of relying on platform defined constants.
+ ******************************************************************************/
+static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT];
+
+/******************************************************************************
+ * Define the psci capability variable.
+ *****************************************************************************/
+unsigned int psci_caps;
+
+/*******************************************************************************
+ * Function which initializes the 'psci_non_cpu_pd_nodes' or the
+ * 'psci_cpu_pd_nodes' corresponding to the power level.
+ ******************************************************************************/
+static void __init psci_init_pwr_domain_node(unsigned char node_idx,
+					unsigned int parent_idx,
+					unsigned char level)
+{
+	if (level > PSCI_CPU_PWR_LVL) {
+		psci_non_cpu_pd_nodes[node_idx].level = level;
+		psci_lock_init(psci_non_cpu_pd_nodes, node_idx);
+		psci_non_cpu_pd_nodes[node_idx].parent_node = parent_idx;
+		psci_non_cpu_pd_nodes[node_idx].local_state =
+							 PLAT_MAX_OFF_STATE;
+	} else {
+		psci_cpu_data_t *svc_cpu_data;
+
+		psci_cpu_pd_nodes[node_idx].parent_node = parent_idx;
+
+		/* Initialize with an invalid mpidr */
+		psci_cpu_pd_nodes[node_idx].mpidr = PSCI_INVALID_MPIDR;
+
+		svc_cpu_data =
+			&(_cpu_data_by_index(node_idx)->psci_svc_cpu_data);
+
+		/* Set the Affinity Info for the cores as OFF */
+		svc_cpu_data->aff_info_state = AFF_STATE_OFF;
+
+		/* Invalidate the suspend level for the cpu */
+		svc_cpu_data->target_pwrlvl = PSCI_INVALID_PWR_LVL;
+
+		/* Set the power state to OFF state */
+		svc_cpu_data->local_state = PLAT_MAX_OFF_STATE;
+
+		psci_flush_dcache_range((uintptr_t)svc_cpu_data,
+						 sizeof(*svc_cpu_data));
+
+		cm_set_context_by_index(node_idx,
+					(void *) &psci_ns_context[node_idx],
+					NON_SECURE);
+	}
+}
+
+/*******************************************************************************
+ * This functions updates cpu_start_idx and ncpus field for each of the node in
+ * psci_non_cpu_pd_nodes[]. It does so by comparing the parent nodes of each of
+ * the CPUs and check whether they match with the parent of the previous
+ * CPU. The basic assumption for this work is that children of the same parent
+ * are allocated adjacent indices. The platform should ensure this though proper
+ * mapping of the CPUs to indices via plat_core_pos_by_mpidr() and
+ * plat_my_core_pos() APIs.
+ *******************************************************************************/
+static void __init psci_update_pwrlvl_limits(void)
+{
+	int j, cpu_idx;
+	unsigned int nodes_idx[PLAT_MAX_PWR_LVL] = {0};
+	unsigned int temp_index[PLAT_MAX_PWR_LVL];
+
+	for (cpu_idx = 0; cpu_idx < PLATFORM_CORE_COUNT; cpu_idx++) {
+		psci_get_parent_pwr_domain_nodes(cpu_idx,
+						 (unsigned int)PLAT_MAX_PWR_LVL,
+						 temp_index);
+		for (j = (int) PLAT_MAX_PWR_LVL - 1; j >= 0; j--) {
+			if (temp_index[j] != nodes_idx[j]) {
+				nodes_idx[j] = temp_index[j];
+				psci_non_cpu_pd_nodes[nodes_idx[j]].cpu_start_idx
+					= cpu_idx;
+			}
+			psci_non_cpu_pd_nodes[nodes_idx[j]].ncpus++;
+		}
+	}
+}
+
+/*******************************************************************************
+ * Core routine to populate the power domain tree. The tree descriptor passed by
+ * the platform is populated breadth-first and the first entry in the map
+ * informs the number of root power domains. The parent nodes of the root nodes
+ * will point to an invalid entry(-1).
+ ******************************************************************************/
+static void __init populate_power_domain_tree(const unsigned char *topology)
+{
+	unsigned int i, j = 0U, num_nodes_at_lvl = 1U, num_nodes_at_next_lvl;
+	unsigned int node_index = 0U, num_children;
+	int parent_node_index = 0;
+	int level = (int) PLAT_MAX_PWR_LVL;
+
+	/*
+	 * For each level the inputs are:
+	 * - number of nodes at this level in plat_array i.e. num_nodes_at_level
+	 *   This is the sum of values of nodes at the parent level.
+	 * - Index of first entry at this level in the plat_array i.e.
+	 *   parent_node_index.
+	 * - Index of first free entry in psci_non_cpu_pd_nodes[] or
+	 *   psci_cpu_pd_nodes[] i.e. node_index depending upon the level.
+	 */
+	while (level >= (int) PSCI_CPU_PWR_LVL) {
+		num_nodes_at_next_lvl = 0U;
+		/*
+		 * For each entry (parent node) at this level in the plat_array:
+		 * - Find the number of children
+		 * - Allocate a node in a power domain array for each child
+		 * - Set the parent of the child to the parent_node_index - 1
+		 * - Increment parent_node_index to point to the next parent
+		 * - Accumulate the number of children at next level.
+		 */
+		for (i = 0U; i < num_nodes_at_lvl; i++) {
+			assert(parent_node_index <=
+					PSCI_NUM_NON_CPU_PWR_DOMAINS);
+			num_children = topology[parent_node_index];
+
+			for (j = node_index;
+				j < (node_index + num_children); j++)
+				psci_init_pwr_domain_node((unsigned char)j,
+							  parent_node_index - 1,
+							  (unsigned char)level);
+
+			node_index = j;
+			num_nodes_at_next_lvl += num_children;
+			parent_node_index++;
+		}
+
+		num_nodes_at_lvl = num_nodes_at_next_lvl;
+		level--;
+
+		/* Reset the index for the cpu power domain array */
+		if (level == (int) PSCI_CPU_PWR_LVL)
+			node_index = 0;
+	}
+
+	/* Validate the sanity of array exported by the platform */
+	assert((int) j == PLATFORM_CORE_COUNT);
+}
+
+/*******************************************************************************
+ * This function does the architectural setup and takes the warm boot
+ * entry-point `mailbox_ep` as an argument. The function also initializes the
+ * power domain topology tree by querying the platform. The power domain nodes
+ * higher than the CPU are populated in the array psci_non_cpu_pd_nodes[] and
+ * the CPU power domains are populated in psci_cpu_pd_nodes[]. The platform
+ * exports its static topology map through the
+ * populate_power_domain_topology_tree() API. The algorithm populates the
+ * psci_non_cpu_pd_nodes and psci_cpu_pd_nodes iteratively by using this
+ * topology map.  On a platform that implements two clusters of 2 cpus each,
+ * and supporting 3 domain levels, the populated psci_non_cpu_pd_nodes would
+ * look like this:
+ *
+ * ---------------------------------------------------
+ * | system node | cluster 0 node  | cluster 1 node  |
+ * ---------------------------------------------------
+ *
+ * And populated psci_cpu_pd_nodes would look like this :
+ * <-    cpus cluster0   -><-   cpus cluster1   ->
+ * ------------------------------------------------
+ * |   CPU 0   |   CPU 1   |   CPU 2   |   CPU 3  |
+ * ------------------------------------------------
+ ******************************************************************************/
+int __init psci_setup(const psci_lib_args_t *lib_args)
+{
+	const unsigned char *topology_tree;
+
+	assert(VERIFY_PSCI_LIB_ARGS_V1(lib_args));
+
+	/* Do the Architectural initialization */
+	psci_arch_setup();
+
+	/* Query the topology map from the platform */
+	topology_tree = plat_get_power_domain_tree_desc();
+
+	/* Populate the power domain arrays using the platform topology map */
+	populate_power_domain_tree(topology_tree);
+
+	/* Update the CPU limits for each node in psci_non_cpu_pd_nodes */
+	psci_update_pwrlvl_limits();
+
+	/* Populate the mpidr field of cpu node for this CPU */
+	psci_cpu_pd_nodes[plat_my_core_pos()].mpidr =
+		read_mpidr() & MPIDR_AFFINITY_MASK;
+
+	psci_init_req_local_pwr_states();
+
+	/*
+	 * Set the requested and target state of this CPU and all the higher
+	 * power domain levels for this CPU to run.
+	 */
+	psci_set_pwr_domains_to_run(PLAT_MAX_PWR_LVL);
+
+	(void) plat_setup_psci_ops((uintptr_t)lib_args->mailbox_ep,
+				   &psci_plat_pm_ops);
+	assert(psci_plat_pm_ops != NULL);
+
+	/*
+	 * Flush `psci_plat_pm_ops` as it will be accessed by secondary CPUs
+	 * during warm boot, possibly before data cache is enabled.
+	 */
+	psci_flush_dcache_range((uintptr_t)&psci_plat_pm_ops,
+					sizeof(psci_plat_pm_ops));
+
+	/* Initialize the psci capability */
+	psci_caps = PSCI_GENERIC_CAP;
+
+	if (psci_plat_pm_ops->pwr_domain_off != NULL)
+		psci_caps |=  define_psci_cap(PSCI_CPU_OFF);
+	if ((psci_plat_pm_ops->pwr_domain_on != NULL) &&
+	    (psci_plat_pm_ops->pwr_domain_on_finish != NULL))
+		psci_caps |=  define_psci_cap(PSCI_CPU_ON_AARCH64);
+	if ((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
+	    (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL)) {
+		psci_caps |=  define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
+		if (psci_plat_pm_ops->get_sys_suspend_power_state != NULL)
+			psci_caps |=  define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64);
+	}
+	if (psci_plat_pm_ops->system_off != NULL)
+		psci_caps |=  define_psci_cap(PSCI_SYSTEM_OFF);
+	if (psci_plat_pm_ops->system_reset != NULL)
+		psci_caps |=  define_psci_cap(PSCI_SYSTEM_RESET);
+	if (psci_plat_pm_ops->get_node_hw_state != NULL)
+		psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
+	if ((psci_plat_pm_ops->read_mem_protect != NULL) &&
+			(psci_plat_pm_ops->write_mem_protect != NULL))
+		psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
+	if (psci_plat_pm_ops->mem_protect_chk != NULL)
+		psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
+	if (psci_plat_pm_ops->system_reset2 != NULL)
+		psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64);
+
+#if ENABLE_PSCI_STAT
+	psci_caps |=  define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
+	psci_caps |=  define_psci_cap(PSCI_STAT_COUNT_AARCH64);
+#endif
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This duplicates what the primary cpu did after a cold boot in BL1. The same
+ * needs to be done when a cpu is hotplugged in. This function could also over-
+ * ride any EL3 setup done by BL1 as this code resides in rw memory.
+ ******************************************************************************/
+void psci_arch_setup(void)
+{
+#if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER)
+	/* Program the counter frequency */
+	write_cntfrq_el0(plat_get_syscnt_freq2());
+#endif
+
+	/* Initialize the cpu_ops pointer. */
+	init_cpu_ops();
+
+	/* Having initialized cpu_ops, we can now print errata status */
+	print_errata_status();
+}
+
+/******************************************************************************
+ * PSCI Library interface to initialize the cpu context for the next non
+ * secure image during cold boot. The relevant registers in the cpu context
+ * need to be retrieved and programmed on return from this interface.
+ *****************************************************************************/
+void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info)
+{
+	assert(GET_SECURITY_STATE(next_image_info->h.attr) == NON_SECURE);
+	cm_init_my_context(next_image_info);
+	cm_prepare_el3_exit(NON_SECURE);
+}
diff --git a/lib/psci/psci_stat.c b/lib/psci/psci_stat.c
new file mode 100644
index 0000000..772a184
--- /dev/null
+++ b/lib/psci/psci_stat.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+#ifndef PLAT_MAX_PWR_LVL_STATES
+#define PLAT_MAX_PWR_LVL_STATES		2U
+#endif
+
+/* Following structure is used for PSCI STAT */
+typedef struct psci_stat {
+	u_register_t residency;
+	u_register_t count;
+} psci_stat_t;
+
+/*
+ * Following is used to keep track of the last cpu
+ * that goes to power down in non cpu power domains.
+ */
+static int last_cpu_in_non_cpu_pd[PSCI_NUM_NON_CPU_PWR_DOMAINS] = {
+		[0 ... PSCI_NUM_NON_CPU_PWR_DOMAINS - 1] = -1};
+
+/*
+ * Following are used to store PSCI STAT values for
+ * CPU and non CPU power domains.
+ */
+static psci_stat_t psci_cpu_stat[PLATFORM_CORE_COUNT]
+				[PLAT_MAX_PWR_LVL_STATES];
+static psci_stat_t psci_non_cpu_stat[PSCI_NUM_NON_CPU_PWR_DOMAINS]
+				[PLAT_MAX_PWR_LVL_STATES];
+
+/*
+ * This functions returns the index into the `psci_stat_t` array given the
+ * local power state and power domain level. If the platform implements the
+ * `get_pwr_lvl_state_idx` pm hook, then that will be used to return the index.
+ */
+static int get_stat_idx(plat_local_state_t local_state, unsigned int pwr_lvl)
+{
+	int idx;
+
+	if (psci_plat_pm_ops->get_pwr_lvl_state_idx == NULL) {
+		assert(PLAT_MAX_PWR_LVL_STATES == 2U);
+		if (is_local_state_retn(local_state) != 0)
+			return 0;
+
+		assert(is_local_state_off(local_state) != 0);
+		return 1;
+	}
+
+	idx = psci_plat_pm_ops->get_pwr_lvl_state_idx(local_state, pwr_lvl);
+	assert((idx >= 0) && (idx < (int) PLAT_MAX_PWR_LVL_STATES));
+	return idx;
+}
+
+/*******************************************************************************
+ * This function is passed the target local power states for each power
+ * domain (state_info) between the current CPU domain and its ancestors until
+ * the target power level (end_pwrlvl).
+ *
+ * Then, for each level (apart from the CPU level) until the 'end_pwrlvl', it
+ * updates the `last_cpu_in_non_cpu_pd[]` with last power down cpu id.
+ *
+ * This function will only be invoked with data cache enabled and while
+ * powering down a core.
+ ******************************************************************************/
+void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
+			const psci_power_state_t *state_info)
+{
+	unsigned int lvl, parent_idx;
+	int cpu_idx = (int) plat_my_core_pos();
+
+	assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
+	assert(state_info != NULL);
+
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+
+	for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) {
+
+		/* Break early if the target power state is RUN */
+		if (is_local_state_run(state_info->pwr_domain_state[lvl]) != 0)
+			break;
+
+		/*
+		 * The power domain is entering a low power state, so this is
+		 * the last CPU for this power domain
+		 */
+		last_cpu_in_non_cpu_pd[parent_idx] = cpu_idx;
+
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+}
+
+/*******************************************************************************
+ * This function updates the PSCI STATS(residency time and count) for CPU
+ * and NON-CPU power domains.
+ * It is called with caches enabled and locks acquired(for NON-CPU domain)
+ ******************************************************************************/
+void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
+			const psci_power_state_t *state_info)
+{
+	unsigned int lvl, parent_idx;
+	int cpu_idx = (int) plat_my_core_pos();
+	int stat_idx;
+	plat_local_state_t local_state;
+	u_register_t residency;
+
+	assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
+	assert(state_info != NULL);
+
+	/* Get the index into the stats array */
+	local_state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
+	stat_idx = get_stat_idx(local_state, PSCI_CPU_PWR_LVL);
+
+	/* Call into platform interface to calculate residency. */
+	residency = plat_psci_stat_get_residency(PSCI_CPU_PWR_LVL,
+	    state_info, cpu_idx);
+
+	/* Update CPU stats. */
+	psci_cpu_stat[cpu_idx][stat_idx].residency += residency;
+	psci_cpu_stat[cpu_idx][stat_idx].count++;
+
+	/*
+	 * Check what power domains above CPU were off
+	 * prior to this CPU powering on.
+	 */
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+	/* Return early if this is the first power up. */
+	if (last_cpu_in_non_cpu_pd[parent_idx] == -1)
+		return;
+
+	for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) {
+		local_state = state_info->pwr_domain_state[lvl];
+		if (is_local_state_run(local_state) != 0) {
+			/* Break early */
+			break;
+		}
+
+		assert(last_cpu_in_non_cpu_pd[parent_idx] != -1);
+
+		/* Call into platform interface to calculate residency. */
+		residency = plat_psci_stat_get_residency(lvl, state_info,
+					last_cpu_in_non_cpu_pd[parent_idx]);
+
+		/* Initialize back to reset value */
+		last_cpu_in_non_cpu_pd[parent_idx] = -1;
+
+		/* Get the index into the stats array */
+		stat_idx = get_stat_idx(local_state, lvl);
+
+		/* Update non cpu stats */
+		psci_non_cpu_stat[parent_idx][stat_idx].residency += residency;
+		psci_non_cpu_stat[parent_idx][stat_idx].count++;
+
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+}
+
+/*******************************************************************************
+ * This function returns the appropriate count and residency time of the
+ * local state for the highest power level expressed in the `power_state`
+ * for the node represented by `target_cpu`.
+ ******************************************************************************/
+static int psci_get_stat(u_register_t target_cpu, unsigned int power_state,
+			 psci_stat_t *psci_stat)
+{
+	int rc;
+	unsigned int pwrlvl, lvl, parent_idx, target_idx;
+	int stat_idx;
+	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
+	plat_local_state_t local_state;
+
+	/* Validate the target_cpu parameter and determine the cpu index */
+	target_idx = (unsigned int) plat_core_pos_by_mpidr(target_cpu);
+	if (target_idx == (unsigned int) -1)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Validate the power_state parameter */
+	if (psci_plat_pm_ops->translate_power_state_by_mpidr == NULL)
+		rc = psci_validate_power_state(power_state, &state_info);
+	else
+		rc = psci_plat_pm_ops->translate_power_state_by_mpidr(
+				target_cpu, power_state, &state_info);
+
+	if (rc != PSCI_E_SUCCESS)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Find the highest power level */
+	pwrlvl = psci_find_target_suspend_lvl(&state_info);
+	if (pwrlvl == PSCI_INVALID_PWR_LVL) {
+		ERROR("Invalid target power level for PSCI statistics operation\n");
+		panic();
+	}
+
+	/* Get the index into the stats array */
+	local_state = state_info.pwr_domain_state[pwrlvl];
+	stat_idx = get_stat_idx(local_state, pwrlvl);
+
+	if (pwrlvl > PSCI_CPU_PWR_LVL) {
+		/* Get the power domain index */
+		parent_idx = SPECULATION_SAFE_VALUE(psci_cpu_pd_nodes[target_idx].parent_node);
+		for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl < pwrlvl; lvl++)
+			parent_idx = SPECULATION_SAFE_VALUE(psci_non_cpu_pd_nodes[parent_idx].parent_node);
+
+		/* Get the non cpu power domain stats */
+		*psci_stat = psci_non_cpu_stat[parent_idx][stat_idx];
+	} else {
+		/* Get the cpu power domain stats */
+		*psci_stat = psci_cpu_stat[target_idx][stat_idx];
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/* This is the top level function for PSCI_STAT_RESIDENCY SMC. */
+u_register_t psci_stat_residency(u_register_t target_cpu,
+		unsigned int power_state)
+{
+	psci_stat_t psci_stat;
+	int rc = psci_get_stat(target_cpu, power_state, &psci_stat);
+
+	if (rc == PSCI_E_SUCCESS)
+		return psci_stat.residency;
+	else
+		return 0;
+}
+
+/* This is the top level function for PSCI_STAT_COUNT SMC. */
+u_register_t psci_stat_count(u_register_t target_cpu,
+	unsigned int power_state)
+{
+	psci_stat_t psci_stat;
+	int rc = psci_get_stat(target_cpu, power_state, &psci_stat);
+
+	if (rc == PSCI_E_SUCCESS)
+		return psci_stat.count;
+	else
+		return 0;
+}
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
new file mode 100644
index 0000000..6d5c099
--- /dev/null
+++ b/lib/psci/psci_suspend.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/el3_runtime/pubsub_events.h>
+#include <lib/pmf/pmf.h>
+#include <lib/runtime_instr.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+/*******************************************************************************
+ * This function does generic and platform specific operations after a wake-up
+ * from standby/retention states at multiple power levels.
+ ******************************************************************************/
+static void psci_suspend_to_standby_finisher(int cpu_idx,
+					     unsigned int end_pwrlvl)
+{
+	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+	psci_power_state_t state_info;
+
+	/* Get the parent nodes */
+	psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes);
+
+	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
+	/*
+	 * Find out which retention states this CPU has exited from until the
+	 * 'end_pwrlvl'. The exit retention state could be deeper than the entry
+	 * state as a result of state coordination amongst other CPUs post wfi.
+	 */
+	psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
+
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_stop(&state_info);
+	psci_stats_update_pwr_up(end_pwrlvl, &state_info);
+#endif
+
+	/*
+	 * Plat. management: Allow the platform to do operations
+	 * on waking up from retention.
+	 */
+	psci_plat_pm_ops->pwr_domain_suspend_finish(&state_info);
+
+	/*
+	 * Set the requested and target state of this CPU and all the higher
+	 * power domain levels for this CPU to run.
+	 */
+	psci_set_pwr_domains_to_run(end_pwrlvl);
+
+	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
+}
+
+/*******************************************************************************
+ * This function does generic and platform specific suspend to power down
+ * operations.
+ ******************************************************************************/
+static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl,
+					  const entry_point_info_t *ep,
+					  const psci_power_state_t *state_info)
+{
+	unsigned int max_off_lvl = psci_find_max_off_lvl(state_info);
+
+	PUBLISH_EVENT(psci_suspend_pwrdown_start);
+
+	/* Save PSCI target power level for the suspend finisher handler */
+	psci_set_suspend_pwrlvl(end_pwrlvl);
+
+	/*
+	 * Flush the target power level as it might be accessed on power up with
+	 * Data cache disabled.
+	 */
+	psci_flush_cpu_data(psci_svc_cpu_data.target_pwrlvl);
+
+	/*
+	 * Call the cpu suspend handler registered by the Secure Payload
+	 * Dispatcher to let it do any book-keeping. If the handler encounters an
+	 * error, it's expected to assert within
+	 */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend != NULL))
+		psci_spd_pm->svc_suspend(max_off_lvl);
+
+#if !HW_ASSISTED_COHERENCY
+	/*
+	 * Plat. management: Allow the platform to perform any early
+	 * actions required to power down the CPU. This might be useful for
+	 * HW_ASSISTED_COHERENCY = 0 platforms that can safely perform these
+	 * actions with data caches enabled.
+	 */
+	if (psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early != NULL)
+		psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early(state_info);
+#endif
+
+	/*
+	 * Store the re-entry information for the non-secure world.
+	 */
+	cm_init_my_context(ep);
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+	/*
+	 * Flush cache line so that even if CPU power down happens
+	 * the timestamp update is reflected in memory.
+	 */
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		RT_INSTR_ENTER_CFLUSH,
+		PMF_CACHE_MAINT);
+#endif
+
+	/*
+	 * Arch. management. Initiate power down sequence.
+	 * TODO : Introduce a mechanism to query the cache level to flush
+	 * and the cpu-ops power down to perform from the platform.
+	 */
+	psci_do_pwrdown_sequence(max_off_lvl);
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		RT_INSTR_EXIT_CFLUSH,
+		PMF_NO_CACHE_MAINT);
+#endif
+}
+
+/*******************************************************************************
+ * Top level handler which is called when a cpu wants to suspend its execution.
+ * It is assumed that along with suspending the cpu power domain, power domains
+ * at higher levels until the target power level will be suspended as well. It
+ * coordinates with the platform to negotiate the target state for each of
+ * the power domain level till the target power domain level. It then performs
+ * generic, architectural, platform setup and state management required to
+ * suspend that power domain level and power domain levels below it.
+ * e.g. For a cpu that's to be suspended, it could mean programming the
+ * power controller whereas for a cluster that's to be suspended, it will call
+ * the platform specific code which will disable coherency at the interconnect
+ * level if the cpu is the last in the cluster and also the program the power
+ * controller.
+ *
+ * All the required parameter checks are performed at the beginning and after
+ * the state transition has been done, no further error is expected and it is
+ * not possible to undo any of the actions taken beyond that point.
+ ******************************************************************************/
+void psci_cpu_suspend_start(const entry_point_info_t *ep,
+			    unsigned int end_pwrlvl,
+			    psci_power_state_t *state_info,
+			    unsigned int is_power_down_state)
+{
+	int skip_wfi = 0;
+	int idx = (int) plat_my_core_pos();
+	unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
+
+	/*
+	 * This function must only be called on platforms where the
+	 * CPU_SUSPEND platform hooks have been implemented.
+	 */
+	assert((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
+	       (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL));
+
+	/* Get the parent nodes */
+	psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes);
+
+	/*
+	 * This function acquires the lock corresponding to each power
+	 * level so that by the time all locks are taken, the system topology
+	 * is snapshot and state management can be done safely.
+	 */
+	psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
+	/*
+	 * We check if there are any pending interrupts after the delay
+	 * introduced by lock contention to increase the chances of early
+	 * detection that a wake-up interrupt has fired.
+	 */
+	if (read_isr_el1() != 0U) {
+		skip_wfi = 1;
+		goto exit;
+	}
+
+	/*
+	 * This function is passed the requested state info and
+	 * it returns the negotiated state info for each power level upto
+	 * the end level specified.
+	 */
+	psci_do_state_coordination(end_pwrlvl, state_info);
+
+#if ENABLE_PSCI_STAT
+	/* Update the last cpu for each level till end_pwrlvl */
+	psci_stats_update_pwr_down(end_pwrlvl, state_info);
+#endif
+
+	if (is_power_down_state != 0U)
+		psci_suspend_to_pwrdown_start(end_pwrlvl, ep, state_info);
+
+	/*
+	 * Plat. management: Allow the platform to perform the
+	 * necessary actions to turn off this cpu e.g. set the
+	 * platform defined mailbox with the psci entrypoint,
+	 * program the power controller etc.
+	 */
+	psci_plat_pm_ops->pwr_domain_suspend(state_info);
+
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_start(state_info);
+#endif
+
+exit:
+	/*
+	 * Release the locks corresponding to each power level in the
+	 * reverse order to which they were acquired.
+	 */
+	psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
+
+	if (skip_wfi == 1)
+		return;
+
+	if (is_power_down_state != 0U) {
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+		/*
+		 * Update the timestamp with cache off.  We assume this
+		 * timestamp can only be read from the current CPU and the
+		 * timestamp cache line will be flushed before return to
+		 * normal world on wakeup.
+		 */
+		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		    RT_INSTR_ENTER_HW_LOW_PWR,
+		    PMF_NO_CACHE_MAINT);
+#endif
+
+		/* The function calls below must not return */
+		if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL)
+			psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info);
+		else
+			psci_power_down_wfi();
+	}
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+	    RT_INSTR_ENTER_HW_LOW_PWR,
+	    PMF_NO_CACHE_MAINT);
+#endif
+
+	/*
+	 * We will reach here if only retention/standby states have been
+	 * requested at multiple power levels. This means that the cpu
+	 * context will be preserved.
+	 */
+	wfi();
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+	    RT_INSTR_EXIT_HW_LOW_PWR,
+	    PMF_NO_CACHE_MAINT);
+#endif
+
+	/*
+	 * After we wake up from context retaining suspend, call the
+	 * context retaining suspend finisher.
+	 */
+	psci_suspend_to_standby_finisher(idx, end_pwrlvl);
+}
+
+/*******************************************************************************
+ * The following functions finish an earlier suspend request. They
+ * are called by the common finisher routine in psci_common.c. The `state_info`
+ * is the psci_power_state from which this CPU has woken up from.
+ ******************************************************************************/
+void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info)
+{
+	unsigned int counter_freq;
+	unsigned int max_off_lvl;
+
+	/* Ensure we have been woken up from a suspended state */
+	assert((psci_get_aff_info_state() == AFF_STATE_ON) &&
+		(is_local_state_off(
+			state_info->pwr_domain_state[PSCI_CPU_PWR_LVL]) != 0));
+
+	/*
+	 * Plat. management: Perform the platform specific actions
+	 * before we change the state of the cpu e.g. enabling the
+	 * gic or zeroing the mailbox register. If anything goes
+	 * wrong then assert as there is no way to recover from this
+	 * situation.
+	 */
+	psci_plat_pm_ops->pwr_domain_suspend_finish(state_info);
+
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+	/* Arch. management: Enable the data cache, stack memory maintenance. */
+	psci_do_pwrup_cache_maintenance();
+#endif
+
+	/* Re-init the cntfrq_el0 register */
+	counter_freq = plat_get_syscnt_freq2();
+	write_cntfrq_el0(counter_freq);
+
+	/*
+	 * Call the cpu suspend finish handler registered by the Secure Payload
+	 * Dispatcher to let it do any bookeeping. If the handler encounters an
+	 * error, it's expected to assert within
+	 */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend_finish != NULL)) {
+		max_off_lvl = psci_find_max_off_lvl(state_info);
+		assert(max_off_lvl != PSCI_INVALID_PWR_LVL);
+		psci_spd_pm->svc_suspend_finish(max_off_lvl);
+	}
+
+	/* Invalidate the suspend level for the cpu */
+	psci_set_suspend_pwrlvl(PSCI_INVALID_PWR_LVL);
+
+	PUBLISH_EVENT(psci_suspend_pwrdown_finish);
+
+	/*
+	 * Generic management: Now we just need to retrieve the
+	 * information that we had stashed away during the suspend
+	 * call to set this cpu on its way.
+	 */
+	cm_prepare_el3_exit(NON_SECURE);
+}
diff --git a/lib/psci/psci_system_off.c b/lib/psci/psci_system_off.c
new file mode 100644
index 0000000..141d69e
--- /dev/null
+++ b/lib/psci/psci_system_off.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#include "psci_private.h"
+
+void __dead2 psci_system_off(void)
+{
+	psci_print_power_domain_map();
+
+	assert(psci_plat_pm_ops->system_off != NULL);
+
+	/* Notify the Secure Payload Dispatcher */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_off != NULL)) {
+		psci_spd_pm->svc_system_off();
+	}
+
+	(void) console_flush();
+
+	/* Call the platform specific hook */
+	psci_plat_pm_ops->system_off();
+
+	/* This function does not return. We should never get here */
+}
+
+void __dead2 psci_system_reset(void)
+{
+	psci_print_power_domain_map();
+
+	assert(psci_plat_pm_ops->system_reset != NULL);
+
+	/* Notify the Secure Payload Dispatcher */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_reset != NULL)) {
+		psci_spd_pm->svc_system_reset();
+	}
+
+	(void) console_flush();
+
+	/* Call the platform specific hook */
+	psci_plat_pm_ops->system_reset();
+
+	/* This function does not return. We should never get here */
+}
+
+u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie)
+{
+	unsigned int is_vendor;
+
+	psci_print_power_domain_map();
+
+	assert(psci_plat_pm_ops->system_reset2 != NULL);
+
+	is_vendor = (reset_type >> PSCI_RESET2_TYPE_VENDOR_SHIFT) & 1U;
+	if (is_vendor == 0U) {
+		/*
+		 * Only WARM_RESET is allowed for architectural type resets.
+		 */
+		if (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)
+			return (u_register_t) PSCI_E_INVALID_PARAMS;
+		if ((psci_plat_pm_ops->write_mem_protect != NULL) &&
+		    (psci_plat_pm_ops->write_mem_protect(0) < 0)) {
+			return (u_register_t) PSCI_E_NOT_SUPPORTED;
+		}
+	}
+
+	/* Notify the Secure Payload Dispatcher */
+	if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_reset != NULL)) {
+		psci_spd_pm->svc_system_reset();
+	}
+	(void) console_flush();
+
+	return (u_register_t)
+		psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type,
+						cookie);
+}
diff --git a/lib/romlib/Makefile b/lib/romlib/Makefile
new file mode 100644
index 0000000..cec9404
--- /dev/null
+++ b/lib/romlib/Makefile
@@ -0,0 +1,98 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+AS          = $(CROSS_COMPILE)as
+AR          = $(CROSS_COMPILE)ar
+LD          = $(CROSS_COMPILE)ld
+OC          = $(CROSS_COMPILE)objcopy
+CPP         = $(CROSS_COMPILE)cpp
+ROMLIB_GEN  = ./romlib_generator.py
+BUILD_DIR   = ../../$(BUILD_PLAT)/romlib
+LIB_DIR     = ../../$(BUILD_PLAT)/lib
+WRAPPER_DIR = ../../$(BUILD_PLAT)/libwrapper
+LIBS        = -lmbedtls -lfdt -lc
+INC         = $(INCLUDES:-I%=-I../../%)
+PPFLAGS     = $(INC) $(DEFINES) -P -x assembler-with-cpp -D__LINKER__ -MD -MP -MT $(BUILD_DIR)/romlib.ld
+OBJS        = $(BUILD_DIR)/jmptbl.o $(BUILD_DIR)/init.o
+MAPFILE     = ../../$(BUILD_PLAT)/romlib/romlib.map
+
+ifneq ($(PLAT_DIR),)
+  WRAPPER_SOURCES   = $(shell $(ROMLIB_GEN) genwrappers -b $(WRAPPER_DIR) --list ../../$(PLAT_DIR)/jmptbl.i)
+  WRAPPER_OBJS      = $(WRAPPER_SOURCES:.s=.o)
+endif
+
+V ?= 0
+ifeq ($(V),0)
+  Q := @
+else
+  Q :=
+endif
+
+LDFLAGS := --gc-sections -O1
+ifeq ($(DEBUG),1)
+   LDFLAGS += -Map=$(MAPFILE)
+endif
+
+ifeq (${ARM_ARCH_MINOR},0)
+	ASFLAGS = -march=armv8-a
+else
+	ASFLAGS = -march=armv8.${ARM_ARCH_MINOR}-a
+endif
+
+.PHONY: all clean distclean
+
+all: $(BUILD_DIR)/romlib.bin $(LIB_DIR)/libwrappers.a
+
+%.o: %.s
+	@echo "  AS      $@"
+	$(Q)$(AS) $(ASFLAGS) -o $@ $<
+
+$(BUILD_DIR)/%.o: %.s
+	@echo "  AS      $@"
+	$(Q)$(AS) $(ASFLAGS) -o $@ $<
+
+$(BUILD_DIR)/romlib.ld: romlib.ld.S
+	@echo "  PP      $@"
+	$(Q)$(CPP) $(PPFLAGS) -o $@ romlib.ld.S
+
+$(BUILD_DIR)/romlib.elf: $(OBJS) $(BUILD_DIR)/romlib.ld
+	@echo "  LD      $@"
+	$(Q)$(LD) -T $(BUILD_DIR)/romlib.ld -L$(LIB_DIR) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+$(BUILD_DIR)/romlib.bin: $(BUILD_DIR)/romlib.elf
+	@echo "  BIN     $@"
+	$(Q)$(OC) -O binary $(BUILD_DIR)/romlib.elf $@
+
+$(WRAPPER_DIR)/jmpvar.s: $(BUILD_DIR)/romlib.elf
+	@echo "  VAR     $@"
+	$(Q)$(ROMLIB_GEN) genvar --output $@ $<
+
+$(LIB_DIR)/libwrappers.a: $(WRAPPER_DIR)/jmpvar.o $(WRAPPER_OBJS)
+	@echo "  AR      $@"
+	$(Q)$(AR) -rc $@ $(WRAPPER_DIR)/jmpvar.o $(WRAPPER_OBJS)
+
+$(BUILD_DIR)/jmptbl.i: ../../$(PLAT_DIR)/jmptbl.i
+	@echo "  PRE     $@"
+	$(Q)$(ROMLIB_GEN) pre --output $@ --deps $(BUILD_DIR)/jmptbl.d $<
+
+$(BUILD_DIR)/wrappers.stamp: $(BUILD_DIR)/jmptbl.i
+	@echo "  WRP     $<"
+	$(Q)$(ROMLIB_GEN) genwrappers --bti=$(ENABLE_BTI) -b $(WRAPPER_DIR) $<
+	@touch $@
+
+$(WRAPPER_SOURCES): $(BUILD_DIR)/wrappers.stamp
+
+$(WRAPPER_OBJS): $(WRAPPER_SOURCES) $(BUILD_DIR)/wrappers.stamp
+
+$(BUILD_DIR)/jmptbl.s: $(BUILD_DIR)/jmptbl.i
+	@echo "  TBL     $@"
+	$(Q)$(ROMLIB_GEN) gentbl --output $@ --bti=$(ENABLE_BTI) $<
+
+clean:
+	@rm -f $(BUILD_DIR)/*
+
+-include $(BUILD_DIR)/romlib.d
+-include $(BUILD_DIR)/jmptbl.d
diff --git a/lib/romlib/gen_combined_bl1_romlib.sh b/lib/romlib/gen_combined_bl1_romlib.sh
new file mode 100755
index 0000000..1e3f73a
--- /dev/null
+++ b/lib/romlib/gen_combined_bl1_romlib.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+set -e
+
+output="bl1_romlib.bin"
+
+# Set trap for removing temporary file
+trap 'r=$?;rm -f $bin_path/$$.tmp;exit $r' EXIT HUP QUIT INT TERM
+
+# Read input parameters
+for i
+do
+	case $i in
+	-o)
+		output=$2
+		shift 2
+		;;
+	--)
+		shift
+		break
+		;;
+	-*)
+		echo usage: gen_combined_bl1_romlib.sh [-o output] path_to_build_directory >&2
+		;;
+	esac
+done
+
+
+bin_path=$1
+romlib_path=$1/romlib
+bl1_file="$1/bl1/bl1.elf"
+romlib_file="$1/romlib/romlib.elf"
+bl1_end=""
+romlib_begin=""
+
+# Get address of __BL1_ROM_END__
+bl1_end=`nm -a "$bl1_file" |
+awk '$3 == "__BL1_ROM_END__" {print "0x"$1}'`
+
+# Get start address of romlib "text" section
+romlib_begin=`nm -a "$romlib_file" |
+awk '$3 == ".text" {print "0x"$1}'`
+
+# Character "U" will be read as "55" in hex when it is
+# concatenated with bl1.bin. Generate combined BL1 and ROMLIB
+# binary with filler bytes for juno
+(cat $bin_path/bl1.bin
+ yes U | sed $(($romlib_begin - $bl1_end))q | tr -d '\n'
+ cat $bin_path/romlib/romlib.bin) > $bin_path/$$.tmp &&
+mv $bin_path/$$.tmp $bin_path/$output
diff --git a/lib/romlib/init.s b/lib/romlib/init.s
new file mode 100644
index 0000000..7d97e4d
--- /dev/null
+++ b/lib/romlib/init.s
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.globl	rom_lib_init
+	.extern	__DATA_RAM_START__, __DATA_ROM_START__, __DATA_RAM_END__
+	.extern	memset, memcpy
+
+rom_lib_init:
+	cmp	w0, #1
+	mov	w0, #0
+	b.le	1f
+	ret
+
+1:	stp	x29, x30, [sp, #-16]!
+	adrp	x0, __DATA_RAM_START__
+	adrp	x1, __DATA_ROM_START__
+	add	x1, x1, :lo12:__DATA_ROM_START__
+	adrp	x2, __DATA_RAM_END__
+	add	x2, x2, :lo12:__DATA_RAM_END__
+	sub	x2, x2, x0
+	bl	memcpy
+
+	adrp	x0,__BSS_START__
+	add	x0, x0, :lo12:__BSS_START__
+	mov	x1, #0
+	adrp	x2, __BSS_END__
+	add	x2, x2, :lo12:__BSS_END__
+	sub	x2, x2, x0
+	bl	memset
+	ldp	x29, x30, [sp], #16
+
+	mov	w0, #1
+	ret
diff --git a/lib/romlib/jmptbl.i b/lib/romlib/jmptbl.i
new file mode 100644
index 0000000..a7280d0
--- /dev/null
+++ b/lib/romlib/jmptbl.i
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Format:
+# lib	function	[patch]
+# Add "patch" at the end of the line to patch a function. For example:
+# mbedtls	mbedtls_memory_buffer_alloc_init	patch
+# Holes can be introduced in the table by using a special keyword "reserved".
+# Example:
+# reserved	reserved
+# The jump table will contain an invalid instruction instead of branch
+
+rom	rom_lib_init
+fdt	fdt_getprop_namelen
+fdt	fdt_setprop_inplace
+fdt	fdt_check_header
+fdt	fdt_node_offset_by_compatible
+mbedtls	mbedtls_asn1_get_alg
+mbedtls	mbedtls_asn1_get_alg_null
+mbedtls	mbedtls_asn1_get_bitstring_null
+mbedtls	mbedtls_asn1_get_bool
+mbedtls	mbedtls_asn1_get_int
+mbedtls	mbedtls_asn1_get_tag
+mbedtls	mbedtls_free
+mbedtls	mbedtls_md
+mbedtls	mbedtls_md_get_size
+mbedtls	mbedtls_memory_buffer_alloc_init
+mbedtls	mbedtls_oid_get_md_alg
+mbedtls	mbedtls_oid_get_numeric_string
+mbedtls	mbedtls_oid_get_pk_alg
+mbedtls	mbedtls_oid_get_sig_alg
+mbedtls	mbedtls_pk_free
+mbedtls	mbedtls_pk_init
+mbedtls	mbedtls_pk_parse_subpubkey
+mbedtls	mbedtls_pk_verify_ext
+mbedtls	mbedtls_platform_set_snprintf
+mbedtls	mbedtls_x509_get_rsassa_pss_params
+mbedtls	mbedtls_x509_get_sig_alg
+mbedtls	mbedtls_md_info_from_type
+c	exit
+c	atexit
diff --git a/lib/romlib/romlib.ld.S b/lib/romlib/romlib.ld.S
new file mode 100644
index 0000000..2aac4ad
--- /dev/null
+++ b/lib/romlib/romlib.ld.S
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+MEMORY {
+	ROM (rx): ORIGIN = ROMLIB_RO_BASE, LENGTH = ROMLIB_RO_LIMIT - ROMLIB_RO_BASE
+	RAM (rwx): ORIGIN = ROMLIB_RW_BASE, LENGTH = ROMLIB_RW_END - ROMLIB_RW_BASE
+}
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(jmptbl)
+
+SECTIONS
+{
+	. = ROMLIB_RO_BASE;
+	.text : {
+		*jmptbl.o(.text)
+		*(.text*)
+		*(.rodata*)
+	} >ROM
+
+	__DATA_ROM_START__ = LOADADDR(.data);
+
+	.data : {
+		__DATA_RAM_START__ = .;
+		*(.data*)
+		__DATA_RAM_END__ = .;
+	} >RAM AT>ROM
+
+	__DATA_SIZE__ = SIZEOF(.data);
+
+	.bss : {
+		__BSS_START__ = .;
+		*(.bss*)
+		__BSS_END__ = .;
+	 } >RAM
+	__BSS_SIZE__ = SIZEOF(.bss);
+}
diff --git a/lib/romlib/romlib_generator.py b/lib/romlib/romlib_generator.py
new file mode 100755
index 0000000..0682dd4
--- /dev/null
+++ b/lib/romlib/romlib_generator.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python3
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+"""
+This module contains a set of classes and a runner that can generate code for the romlib module
+based on the templates in the 'templates' directory.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import string
+import sys
+
+class IndexFileParser:
+    """
+    Parses the contents of the index file into the items and dependencies variables. It
+    also resolves included files in the index files recursively with circular inclusion detection.
+    """
+
+    def __init__(self):
+        self.items = []
+        self.dependencies = {}
+        self.include_chain = []
+
+    def add_dependency(self, parent, dependency):
+        """ Adds a dependency into the dependencies variable. """
+        if parent in self.dependencies:
+            self.dependencies[parent].append(dependency)
+        else:
+            self.dependencies[parent] = [dependency]
+
+    def get_dependencies(self, parent):
+        """ Gets all the recursive dependencies of a parent file. """
+        parent = os.path.normpath(parent)
+        if parent in self.dependencies:
+            direct_deps = self.dependencies[parent]
+            deps = direct_deps
+            for direct_dep in direct_deps:
+                deps += self.get_dependencies(direct_dep)
+            return deps
+
+        return []
+
+    def parse(self, file_name):
+        """ Opens and parses index file. """
+        file_name = os.path.normpath(file_name)
+
+        if file_name not in self.include_chain:
+            self.include_chain.append(file_name)
+            self.dependencies[file_name] = []
+        else:
+            raise Exception("Circular dependency detected: " + file_name)
+
+        with open(file_name, "r") as index_file:
+            for line in index_file.readlines():
+                line_elements = line.split()
+
+                if line.startswith("#") or not line_elements:
+                    # Comment or empty line
+                    continue
+
+                if line_elements[0] == "reserved":
+                    # Reserved slot in the jump table
+                    self.items.append({"type": "reserved"})
+                elif line_elements[0] == "include" and len(line_elements) > 1:
+                    # Include other index file
+                    included_file = os.path.normpath(line_elements[1])
+                    self.add_dependency(file_name, included_file)
+                    self.parse(included_file)
+                elif len(line_elements) > 1:
+                    # Library function
+                    library_name = line_elements[0]
+                    function_name = line_elements[1]
+                    patch = bool(len(line_elements) > 2 and line_elements[2] == "patch")
+
+                    self.items.append({"type": "function", "library_name": library_name,
+                                       "function_name": function_name, "patch": patch})
+                else:
+                    raise Exception("Invalid line: '" + line + "'")
+
+        self.include_chain.pop()
+
+class RomlibApplication:
+    """ Base class of romlib applications. """
+    TEMPLATE_DIR = os.path.dirname(os.path.realpath(__file__)) + "/templates/"
+
+    def __init__(self, prog):
+        self.args = argparse.ArgumentParser(prog=prog, description=self.__doc__)
+        self.config = None
+
+    def parse_arguments(self, argv):
+        """ Parses the arguments that should come from the command line arguments. """
+        self.config = self.args.parse_args(argv)
+
+    def build_template(self, name, mapping=None, remove_comment=False):
+        """
+        Loads a template and builds it with the defined mapping. Template paths are always relative
+        to this script.
+        """
+
+        with open(self.TEMPLATE_DIR + name, "r") as template_file:
+            if remove_comment:
+                # Removing copyright comment to make the generated code more readable when the
+                # template is inserted multiple times into the output.
+                template_lines = template_file.readlines()
+                end_of_comment_line = 0
+                for index, line in enumerate(template_lines):
+                    if line.find("*/") != -1:
+                        end_of_comment_line = index
+                        break
+                template_data = "".join(template_lines[end_of_comment_line + 1:])
+            else:
+                template_data = template_file.read()
+
+            template = string.Template(template_data)
+            return template.substitute(mapping)
+
+class IndexPreprocessor(RomlibApplication):
+    """ Removes empty and comment lines from the index file and resolves includes. """
+
+    def __init__(self, prog):
+        RomlibApplication.__init__(self, prog)
+
+        self.args.add_argument("-o", "--output", help="Output file", metavar="output",
+                               default="jmpvar.s")
+        self.args.add_argument("--deps", help="Dependency file")
+        self.args.add_argument("file", help="Input file")
+
+    def main(self):
+        """
+        After parsing the input index file it generates a clean output with all includes resolved.
+        Using --deps option it also outputs the dependencies in makefile format like gcc's with -M.
+        """
+
+        index_file_parser = IndexFileParser()
+        index_file_parser.parse(self.config.file)
+
+        with open(self.config.output, "w") as output_file:
+            for item in index_file_parser.items:
+                if item["type"] == "function":
+                    patch = "\tpatch" if item["patch"] else ""
+                    output_file.write(
+                        item["library_name"] + "\t" + item["function_name"] + patch + "\n")
+                else:
+                    output_file.write("reserved\n")
+
+        if self.config.deps:
+            with open(self.config.deps, "w") as deps_file:
+                deps = [self.config.file] + index_file_parser.get_dependencies(self.config.file)
+                deps_file.write(self.config.output + ": " + " \\\n".join(deps) + "\n")
+
+class TableGenerator(RomlibApplication):
+    """ Generates the jump table by parsing the index file. """
+
+    def __init__(self, prog):
+        RomlibApplication.__init__(self, prog)
+
+        self.args.add_argument("-o", "--output", help="Output file", metavar="output",
+                               default="jmpvar.s")
+        self.args.add_argument("--bti", help="Branch Target Identification", type=int)
+        self.args.add_argument("file", help="Input file")
+
+    def main(self):
+        """
+        Inserts the jmptbl definition and the jump entries into the output file. Also can insert
+        BTI related code before entries if --bti option set. It can output a dependency file of the
+        included index files. This can be directly included in makefiles.
+        """
+
+        index_file_parser = IndexFileParser()
+        index_file_parser.parse(self.config.file)
+
+        with open(self.config.output, "w") as output_file:
+            output_file.write(self.build_template("jmptbl_header.S"))
+            bti = "_bti" if self.config.bti == 1 else ""
+
+            for item in index_file_parser.items:
+                template_name = "jmptbl_entry_" + item["type"] + bti + ".S"
+                output_file.write(self.build_template(template_name, item, True))
+
+class WrapperGenerator(RomlibApplication):
+    """
+    Generates a wrapper function for each entry in the index file except for the ones that contain
+    the keyword patch. The generated wrapper file is called <lib>_<fn_name>.s.
+    """
+
+    def __init__(self, prog):
+        RomlibApplication.__init__(self, prog)
+
+        self.args.add_argument("-b", help="Build directory", default=".", metavar="build")
+        self.args.add_argument("--bti", help="Branch Target Identification", type=int)
+        self.args.add_argument("--list", help="Only list assembly files", action="store_true")
+        self.args.add_argument("file", help="Input file")
+
+    def main(self):
+        """
+        Iterates through the items in the parsed index file and builds the template for each entry.
+        """
+
+        index_file_parser = IndexFileParser()
+        index_file_parser.parse(self.config.file)
+
+        bti = "_bti" if self.config.bti == 1 else ""
+        function_offset = 0
+        files = []
+
+        for item_index in range(0, len(index_file_parser.items)):
+            item = index_file_parser.items[item_index]
+
+            if item["type"] == "reserved" or item["patch"]:
+                continue
+
+            asm = self.config.b + "/" + item["function_name"] + ".s"
+            if self.config.list:
+                # Only listing files
+                files.append(asm)
+            else:
+                with open(asm, "w") as asm_file:
+                    # The jump instruction is 4 bytes but BTI requires and extra instruction so
+                    # this makes it 8 bytes per entry.
+                    function_offset = item_index * (8 if self.config.bti else 4)
+
+                    item["function_offset"] = function_offset
+                    asm_file.write(self.build_template("wrapper" + bti + ".S", item))
+
+        if self.config.list:
+            print(" ".join(files))
+
+class VariableGenerator(RomlibApplication):
+    """ Generates the jump table global variable with the absolute address in ROM. """
+
+    def __init__(self, prog):
+        RomlibApplication.__init__(self, prog)
+
+        self.args.add_argument("-o", "--output", help="Output file", metavar="output",
+                               default="jmpvar.s")
+        self.args.add_argument("file", help="Input file")
+
+    def main(self):
+        """
+        Runs nm -a command on the input file and inserts the address of the .text section into the
+        template as the ROM address of the jmp_table.
+        """
+        symbols = subprocess.check_output(["nm", "-a", self.config.file])
+
+        matching_symbol = re.search("([0-9A-Fa-f]+) . \\.text", str(symbols))
+        if not matching_symbol:
+            raise Exception("No '.text' section was found in %s" % self.config.file)
+
+        mapping = {"jmptbl_address": matching_symbol.group(1)}
+
+        with open(self.config.output, "w") as output_file:
+            output_file.write(self.build_template("jmptbl_glob_var.S", mapping))
+
+if __name__ == "__main__":
+    APPS = {"genvar": VariableGenerator, "pre": IndexPreprocessor,
+            "gentbl": TableGenerator, "genwrappers": WrapperGenerator}
+
+    if len(sys.argv) < 2 or sys.argv[1] not in APPS:
+        print("usage: romlib_generator.py [%s] [args]" % "|".join(APPS.keys()), file=sys.stderr)
+        sys.exit(1)
+
+    APP = APPS[sys.argv[1]]("romlib_generator.py " + sys.argv[1])
+    APP.parse_arguments(sys.argv[2:])
+    try:
+        APP.main()
+        sys.exit(0)
+    except FileNotFoundError as file_not_found_error:
+        print(file_not_found_error, file=sys.stderr)
+    except subprocess.CalledProcessError as called_process_error:
+        print(called_process_error.output, file=sys.stderr)
+
+    sys.exit(1)
diff --git a/lib/romlib/templates/jmptbl_entry_function.S b/lib/romlib/templates/jmptbl_entry_function.S
new file mode 100644
index 0000000..a0f8456
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_function.S
@@ -0,0 +1,6 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	b	${function_name}
diff --git a/lib/romlib/templates/jmptbl_entry_function_bti.S b/lib/romlib/templates/jmptbl_entry_function_bti.S
new file mode 100644
index 0000000..d96ee94
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_function_bti.S
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	bti	j
+	b	${function_name}
diff --git a/lib/romlib/templates/jmptbl_entry_reserved.S b/lib/romlib/templates/jmptbl_entry_reserved.S
new file mode 100644
index 0000000..a9b5f18
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_reserved.S
@@ -0,0 +1,6 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	b	.
diff --git a/lib/romlib/templates/jmptbl_entry_reserved_bti.S b/lib/romlib/templates/jmptbl_entry_reserved_bti.S
new file mode 100644
index 0000000..a9f0375
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_entry_reserved_bti.S
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	bti	j
+	b	.
diff --git a/lib/romlib/templates/jmptbl_glob_var.S b/lib/romlib/templates/jmptbl_glob_var.S
new file mode 100644
index 0000000..d306512
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_glob_var.S
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	.data
+	.globl	jmptbl
+	.align	4
+jmptbl:	.quad	0x${jmptbl_address}
diff --git a/lib/romlib/templates/jmptbl_header.S b/lib/romlib/templates/jmptbl_header.S
new file mode 100644
index 0000000..72b8ce5
--- /dev/null
+++ b/lib/romlib/templates/jmptbl_header.S
@@ -0,0 +1,8 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	.text
+	.globl	jmptbl
+jmptbl:
diff --git a/lib/romlib/templates/wrapper.S b/lib/romlib/templates/wrapper.S
new file mode 100644
index 0000000..734a68a
--- /dev/null
+++ b/lib/romlib/templates/wrapper.S
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	.globl	${function_name}
+${function_name}:
+	ldr	x17, =jmptbl
+	mov	x16, #${function_offset}
+	ldr	x17, [x17]
+	add	x16, x16, x17
+	br	x16
diff --git a/lib/romlib/templates/wrapper_bti.S b/lib/romlib/templates/wrapper_bti.S
new file mode 100644
index 0000000..ba9b11c
--- /dev/null
+++ b/lib/romlib/templates/wrapper_bti.S
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+	.globl	${function_name}
+${function_name}:
+	bti	jc
+	ldr	x17, =jmptbl
+	mov	x16, #${function_offset}
+	ldr	x17, [x17]
+	add	x16, x16, x17
+	br	x16
diff --git a/lib/semihosting/aarch32/semihosting_call.S b/lib/semihosting/aarch32/semihosting_call.S
new file mode 100644
index 0000000..aced3d1
--- /dev/null
+++ b/lib/semihosting/aarch32/semihosting_call.S
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	semihosting_call
+
+func semihosting_call
+	svc	#0x123456
+	bx	lr
+endfunc semihosting_call
diff --git a/lib/semihosting/aarch64/semihosting_call.S b/lib/semihosting/aarch64/semihosting_call.S
new file mode 100644
index 0000000..97d2bca
--- /dev/null
+++ b/lib/semihosting/aarch64/semihosting_call.S
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	semihosting_call
+
+func semihosting_call
+	hlt	#0xf000
+	ret
+endfunc semihosting_call
diff --git a/lib/semihosting/semihosting.c b/lib/semihosting/semihosting.c
new file mode 100644
index 0000000..051dd00
--- /dev/null
+++ b/lib/semihosting/semihosting.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <lib/semihosting.h>
+
+#ifndef SEMIHOSTING_SUPPORTED
+#define SEMIHOSTING_SUPPORTED  1
+#endif
+
+long semihosting_call(unsigned long operation,
+			void *system_block_address);
+
+typedef struct {
+	const char *file_name;
+	unsigned long mode;
+	size_t name_length;
+} smh_file_open_block_t;
+
+typedef struct {
+	long handle;
+	uintptr_t buffer;
+	size_t length;
+} smh_file_read_write_block_t;
+
+typedef struct {
+	long handle;
+	ssize_t location;
+} smh_file_seek_block_t;
+
+typedef struct {
+	char *command_line;
+	size_t command_length;
+} smh_system_block_t;
+
+long semihosting_connection_supported(void)
+{
+	return SEMIHOSTING_SUPPORTED;
+}
+
+long semihosting_file_open(const char *file_name, size_t mode)
+{
+	smh_file_open_block_t open_block;
+
+	open_block.file_name = file_name;
+	open_block.mode = mode;
+	open_block.name_length = strlen(file_name);
+
+	return semihosting_call(SEMIHOSTING_SYS_OPEN,
+				(void *) &open_block);
+}
+
+long semihosting_file_seek(long file_handle, ssize_t offset)
+{
+	smh_file_seek_block_t seek_block;
+	long result;
+
+	seek_block.handle = file_handle;
+	seek_block.location = offset;
+
+	result = semihosting_call(SEMIHOSTING_SYS_SEEK,
+				  (void *) &seek_block);
+
+	if (result)
+		result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0);
+
+	return result;
+}
+
+long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer)
+{
+	smh_file_read_write_block_t read_block;
+	long result = -EINVAL;
+
+	if ((length == NULL) || (buffer == (uintptr_t)NULL))
+		return result;
+
+	read_block.handle = file_handle;
+	read_block.buffer = buffer;
+	read_block.length = *length;
+
+	result = semihosting_call(SEMIHOSTING_SYS_READ,
+				  (void *) &read_block);
+
+	if (result == *length) {
+		return -EINVAL;
+	} else if (result < *length) {
+		*length -= result;
+		return 0;
+	} else
+		return result;
+}
+
+long semihosting_file_write(long file_handle,
+			    size_t *length,
+			    const uintptr_t buffer)
+{
+	smh_file_read_write_block_t write_block;
+	long result = -EINVAL;
+
+	if ((length == NULL) || (buffer == (uintptr_t)NULL))
+		return -EINVAL;
+
+	write_block.handle = file_handle;
+	write_block.buffer = (uintptr_t)buffer; /* cast away const */
+	write_block.length = *length;
+
+	result = semihosting_call(SEMIHOSTING_SYS_WRITE,
+				   (void *) &write_block);
+
+	*length = result;
+
+	return (result == 0) ? 0 : -EINVAL;
+}
+
+long semihosting_file_close(long file_handle)
+{
+	return semihosting_call(SEMIHOSTING_SYS_CLOSE,
+				(void *) &file_handle);
+}
+
+long semihosting_file_length(long file_handle)
+{
+	return semihosting_call(SEMIHOSTING_SYS_FLEN,
+				(void *) &file_handle);
+}
+
+char semihosting_read_char(void)
+{
+	return semihosting_call(SEMIHOSTING_SYS_READC, NULL);
+}
+
+void semihosting_write_char(char character)
+{
+	semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character);
+}
+
+void semihosting_write_string(char *string)
+{
+	semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string);
+}
+
+long semihosting_system(char *command_line)
+{
+	smh_system_block_t system_block;
+
+	system_block.command_line = command_line;
+	system_block.command_length = strlen(command_line);
+
+	return semihosting_call(SEMIHOSTING_SYS_SYSTEM,
+				(void *) &system_block);
+}
+
+long semihosting_get_flen(const char *file_name)
+{
+	long file_handle;
+	long length;
+
+	assert(semihosting_connection_supported());
+
+	file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
+	if (file_handle == -1)
+		return file_handle;
+
+	/* Find the length of the file */
+	length = semihosting_file_length(file_handle);
+
+	return semihosting_file_close(file_handle) ? -1 : length;
+}
+
+long semihosting_download_file(const char *file_name,
+			      size_t buf_size,
+			      uintptr_t buf)
+{
+	long ret = -EINVAL;
+	size_t length;
+	long file_handle;
+
+	/* Null pointer check */
+	if (!buf)
+		return ret;
+
+	assert(semihosting_connection_supported());
+
+	file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB);
+	if (file_handle == -1)
+		return ret;
+
+	/* Find the actual length of the file */
+	length = semihosting_file_length(file_handle);
+	if (length == -1)
+		goto semihosting_fail;
+
+	/* Signal error if we do not have enough space for the file */
+	if (length > buf_size)
+		goto semihosting_fail;
+
+	/*
+	 * A successful read will return 0 in which case we pass back
+	 * the actual number of bytes read. Else we pass a negative
+	 * value indicating an error.
+	 */
+	ret = semihosting_file_read(file_handle, &length, buf);
+	if (ret)
+		goto semihosting_fail;
+	else
+		ret = length;
+
+semihosting_fail:
+	semihosting_file_close(file_handle);
+	return ret;
+}
diff --git a/lib/sprt/sprt_host.c b/lib/sprt/sprt_host.c
new file mode 100644
index 0000000..c4d436e
--- /dev/null
+++ b/lib/sprt/sprt_host.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sprt_common.h"
+#include "sprt_queue.h"
+
+void sprt_initialize_queues(void *buffer_base, size_t buffer_size)
+{
+	/* Initialize queue for blocking messages */
+
+	void *blocking_base = buffer_base;
+	uint32_t blocking_num = 4U;
+	size_t blocking_size = SPRT_QUEUE_HEADER_SIZE +
+			       SPRT_QUEUE_ENTRY_MSG_SIZE * blocking_num;
+
+	sprt_queue_init(blocking_base, blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE);
+
+	/* Initialize queue for non-blocking messages */
+
+	void *non_blocking_base = (void *)((uintptr_t)blocking_base + blocking_size);
+	size_t non_blocking_size = buffer_size - blocking_size;
+	uint32_t non_blocking_num = (non_blocking_size - SPRT_QUEUE_HEADER_SIZE) /
+		SPRT_QUEUE_ENTRY_MSG_SIZE;
+
+	sprt_queue_init(non_blocking_base, non_blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE);
+}
+
+int sprt_push_message(void *buffer_base,
+		      const struct sprt_queue_entry_message *message,
+		      int queue_num)
+{
+	struct sprt_queue *q = buffer_base;
+
+	while (queue_num-- > 0) {
+		uintptr_t next_addr = (uintptr_t)q + sizeof(struct sprt_queue) +
+				      q->entry_num * q->entry_size;
+		q = (struct sprt_queue *) next_addr;
+	}
+
+	return sprt_queue_push(q, message);
+}
diff --git a/lib/sprt/sprt_host.mk b/lib/sprt/sprt_host.mk
new file mode 100644
index 0000000..abcfe5e
--- /dev/null
+++ b/lib/sprt/sprt_host.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+SPRT_LIB_SOURCES	:=	$(addprefix lib/sprt/,			\
+					sprt_host.c			\
+					sprt_queue.c)
+
+SPRT_LIB_INCLUDES	:=	-Iinclude/lib/sprt/
diff --git a/lib/sprt/sprt_queue.c b/lib/sprt/sprt_queue.c
new file mode 100644
index 0000000..2bd4139
--- /dev/null
+++ b/lib/sprt/sprt_queue.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "sprt_queue.h"
+
+void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size)
+{
+	assert(queue_base != NULL);
+	assert(entry_size > 0U);
+	assert(entry_num > 0U);
+
+	struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+	queue->entry_num = entry_num;
+	queue->entry_size = entry_size;
+	queue->idx_write = 0U;
+	queue->idx_read = 0U;
+
+	memset(queue->data, 0, entry_num * entry_size);
+}
+
+int sprt_queue_is_empty(void *queue_base)
+{
+	assert(queue_base != NULL);
+
+	struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+	return (queue->idx_write == queue->idx_read);
+}
+
+int sprt_queue_is_full(void *queue_base)
+{
+	assert(queue_base != NULL);
+
+	struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+	uint32_t idx_next_write = (queue->idx_write + 1) % queue->entry_num;
+
+	return (idx_next_write == queue->idx_read);
+}
+
+int sprt_queue_push(void *queue_base, const void *entry)
+{
+	assert(entry != NULL);
+	assert(queue_base != NULL);
+
+	if (sprt_queue_is_full(queue_base) != 0) {
+		return -ENOMEM;
+	}
+
+	struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+	uint8_t *dst_entry = &queue->data[queue->entry_size * queue->idx_write];
+
+	memcpy(dst_entry, entry, queue->entry_size);
+
+	/*
+	 * Make sure that the message data is visible before increasing the
+	 * counter of available messages.
+	 */
+	__asm__ volatile("dmb st" ::: "memory");
+
+	queue->idx_write = (queue->idx_write + 1) % queue->entry_num;
+
+	__asm__ volatile("dmb st" ::: "memory");
+
+	return 0;
+}
+
+int sprt_queue_pop(void *queue_base, void *entry)
+{
+	assert(entry != NULL);
+	assert(queue_base != NULL);
+
+	if (sprt_queue_is_empty(queue_base) != 0) {
+		return -ENOENT;
+	}
+
+	struct sprt_queue *queue = (struct sprt_queue *)queue_base;
+
+	uint8_t *src_entry = &queue->data[queue->entry_size * queue->idx_read];
+
+	memcpy(entry, src_entry, queue->entry_size);
+
+	/*
+	 * Make sure that the message data is visible before increasing the
+	 * counter of read messages.
+	 */
+	__asm__ volatile("dmb st" ::: "memory");
+
+	queue->idx_read = (queue->idx_read + 1) % queue->entry_num;
+
+	__asm__ volatile("dmb st" ::: "memory");
+
+	return 0;
+}
diff --git a/lib/sprt/sprt_queue.h b/lib/sprt/sprt_queue.h
new file mode 100644
index 0000000..4ea1bc2
--- /dev/null
+++ b/lib/sprt/sprt_queue.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPRT_QUEUE_H
+#define SPRT_QUEUE_H
+
+#include <stdint.h>
+
+/* Struct that defines a queue. Not to be used directly. */
+struct __attribute__((__packed__)) sprt_queue {
+	uint32_t entry_num;	/* Number of entries */
+	uint32_t entry_size;	/* Size of an entry */
+	uint32_t idx_write;	/* Index of first empty entry */
+	uint32_t idx_read;	/* Index of first entry to read */
+	uint8_t  data[0];	/* Start of data */
+};
+
+#define SPRT_QUEUE_HEADER_SIZE	(sizeof(struct sprt_queue))
+
+/*
+ * Initializes a memory region to be used as a queue of the given number of
+ * entries with the specified size.
+ */
+void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size);
+
+/* Returns 1 if the queue is empty, 0 otherwise */
+int sprt_queue_is_empty(void *queue_base);
+
+/* Returns 1 if the queue is full, 0 otherwise */
+int sprt_queue_is_full(void *queue_base);
+
+/*
+ * Pushes a new entry intro the queue. Returns 0 on success, -ENOMEM if the
+ * queue is full.
+ */
+int sprt_queue_push(void *queue_base, const void *entry);
+
+/*
+ * Pops an entry from the queue. Returns 0 on success, -ENOENT if the queue is
+ * empty.
+ */
+int sprt_queue_pop(void *queue_base, void *entry);
+
+#endif /* SPRT_QUEUE_H */
diff --git a/lib/stack_protector/aarch32/asm_stack_protector.S b/lib/stack_protector/aarch32/asm_stack_protector.S
new file mode 100644
index 0000000..19b7525
--- /dev/null
+++ b/lib/stack_protector/aarch32/asm_stack_protector.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+	.globl	update_stack_protector_canary
+
+/* -----------------------------------------------------------------------
+ * void update_stack_protector_canary(void)
+ *
+ * Change the value of the canary used for stack smashing attacks protection.
+ * Note: This must be called when it is safe to call C code, but this cannot be
+ * called by C code. Doing this will make the check fail when the calling
+ * function returns.
+ * -----------------------------------------------------------------------
+ */
+
+func update_stack_protector_canary
+	/* Use r4 as it is callee-saved */
+	mov	r4, lr
+	bl	plat_get_stack_protector_canary
+
+	/* Update the canary with the returned value */
+	ldr	r1,  =__stack_chk_guard
+	str	r0, [r1]
+	bx	r4
+endfunc update_stack_protector_canary
+
+
diff --git a/lib/stack_protector/aarch64/asm_stack_protector.S b/lib/stack_protector/aarch64/asm_stack_protector.S
new file mode 100644
index 0000000..c2245d3
--- /dev/null
+++ b/lib/stack_protector/aarch64/asm_stack_protector.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+
+	.globl	update_stack_protector_canary
+
+/* -----------------------------------------------------------------------
+ * void update_stack_protector_canary(void)
+ *
+ * Change the value of the canary used for stack smashing attacks protection.
+ * Note: This must be called when it is safe to call C code, but this cannot be
+ * called by C code. Doing this will make the check fail when the calling
+ * function returns.
+ * -----------------------------------------------------------------------
+ */
+
+func update_stack_protector_canary
+	/* Use x19 as it is callee-saved */
+	mov	x19, x30
+	bl	plat_get_stack_protector_canary
+
+	/* Update the canary with the returned value */
+	adrp	x1,  __stack_chk_guard
+	str	x0, [x1, #:lo12:__stack_chk_guard]
+	ret	x19
+endfunc update_stack_protector_canary
+
+
diff --git a/lib/stack_protector/stack_protector.c b/lib/stack_protector/stack_protector.c
new file mode 100644
index 0000000..3ff74fc
--- /dev/null
+++ b/lib/stack_protector/stack_protector.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/*
+ * Canary value used by the compiler runtime checks to detect stack corruption.
+ *
+ * Force the canary to be in .data to allow predictable memory layout relatively
+ * to the stacks.
+ */
+u_register_t  __attribute__((section(".data.stack_protector_canary")))
+	__stack_chk_guard = (u_register_t) 3288484550995823360ULL;
+
+/*
+ * Function called when the stack's canary check fails, which means the stack
+ * was corrupted. It must not return.
+ */
+void __dead2 __stack_chk_fail(void)
+{
+#if DEBUG
+	ERROR("Stack corruption detected\n");
+#endif
+	panic();
+}
+
diff --git a/lib/stack_protector/stack_protector.mk b/lib/stack_protector/stack_protector.mk
new file mode 100644
index 0000000..94e804b
--- /dev/null
+++ b/lib/stack_protector/stack_protector.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Boolean macro to be used in C code
+STACK_PROTECTOR_ENABLED := 0
+
+ifeq (${ENABLE_STACK_PROTECTOR},0)
+  ENABLE_STACK_PROTECTOR := none
+endif
+
+ifneq (${ENABLE_STACK_PROTECTOR},none)
+  STACK_PROTECTOR_ENABLED := 1
+  BL_COMMON_SOURCES	+=	lib/stack_protector/stack_protector.c	\
+				lib/stack_protector/${ARCH}/asm_stack_protector.S
+
+  ifeq (${ENABLE_STACK_PROTECTOR},default)
+    TF_CFLAGS		+=	-fstack-protector
+  else
+    TF_CFLAGS		+=	-fstack-protector-${ENABLE_STACK_PROTECTOR}
+  endif
+endif
+
+$(eval $(call add_define,STACK_PROTECTOR_ENABLED))
diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c
new file mode 100644
index 0000000..08bccf6
--- /dev/null
+++ b/lib/utils/mem_region.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+/*
+ * All the regions defined in mem_region_t must have the following properties
+ *
+ * - Any contiguous regions must be merged into a single entry.
+ * - The number of bytes of each region must be greater than zero.
+ * - The calculation of the highest address within the region (base + nbytes-1)
+ *   doesn't produce an overflow.
+ *
+ * These conditions must be fulfilled by the caller and they aren't checked
+ * at runtime.
+ */
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * tbl must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions)
+{
+	size_t i;
+
+	assert(tbl);
+	assert(nregions > 0);
+
+	for (i = 0; i < nregions; i++) {
+		assert(tbl->nbytes > 0);
+		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+		zero_normalmem((void *) (tbl->base), tbl->nbytes);
+		tbl++;
+	}
+}
+
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+/*
+ * zero_normalmem all the regions defined in regions.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * regions must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array. va is the virtual address
+ * where we want to map the physical pages that are going to
+ * be cleared, and chunk is the amount of memory mapped and
+ * cleared in every iteration.
+ */
+void clear_map_dyn_mem_regions(struct mem_region *regions,
+			       size_t nregions,
+			       uintptr_t va,
+			       size_t chunk)
+{
+	uintptr_t begin;
+	int r;
+	size_t size;
+	const unsigned int attr = MT_MEMORY | MT_RW | MT_NS;
+
+	assert(regions != NULL);
+	assert(nregions > 0 && chunk > 0);
+
+	for ( ; nregions--; regions++) {
+		begin = regions->base;
+		size = regions->nbytes;
+		if ((begin & (chunk-1)) != 0 || (size & (chunk-1)) != 0) {
+			INFO("PSCI: Not correctly aligned region\n");
+			panic();
+		}
+
+		while (size > 0) {
+			r = mmap_add_dynamic_region(begin, va, chunk, attr);
+			if (r != 0) {
+				INFO("PSCI: mmap_add_dynamic_region failed with %d\n", r);
+				panic();
+			}
+
+			zero_normalmem((void *) va, chunk);
+
+			r = mmap_remove_dynamic_region(va, chunk);
+			if (r != 0) {
+				INFO("PSCI: mmap_remove_dynamic_region failed with %d\n", r);
+				panic();
+			}
+
+			begin += chunk;
+			size -= chunk;
+		}
+	}
+}
+#endif
+
+/*
+ * This function checks that a region (addr + nbytes-1) of memory is totally
+ * covered by one of the regions defined in tbl.
+ * tbl must be a valid pointer to a memory mem_region_t array, nregions
+ * is the size of the array and the region described by addr and nbytes must
+ * not generate an overflow.
+ * Returns:
+ *  -1 means that the region is not covered by any of the regions
+ *     described in tbl.
+ *   0 the region (addr + nbytes-1) is covered by one of the regions described
+ *     in tbl
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+			    uintptr_t addr, size_t nbytes)
+{
+	uintptr_t region_start, region_end, start, end;
+	size_t i;
+
+	assert(tbl);
+	assert(nbytes > 0);
+	assert(!check_uptr_overflow(addr, nbytes-1));
+
+	region_start = addr;
+	region_end = addr + (nbytes - 1);
+	for (i = 0; i < nregions; i++) {
+		assert(tbl->nbytes > 0);
+		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+		start = tbl->base;
+		end = start + (tbl->nbytes - 1);
+		if (region_start >= start && region_end <= end)
+			return 0;
+		tbl++;
+	}
+
+	return -1;
+}
diff --git a/lib/xlat_tables/aarch32/nonlpae_tables.c b/lib/xlat_tables/aarch32/nonlpae_tables.c
new file mode 100644
index 0000000..bd6b152
--- /dev/null
+++ b/lib/xlat_tables/aarch32/nonlpae_tables.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited. All rights reserved.
+ * Copyright (c) 2014-2019, Arm Limited. All rights reserved.
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/cassert.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "../xlat_tables_private.h"
+
+#ifdef ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING
+#error "ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING flag is set. \
+This module is to be used when LPAE is not supported"
+#endif
+
+CASSERT(PLAT_VIRT_ADDR_SPACE_SIZE == (1ULL << 32), invalid_vaddr_space_size);
+CASSERT(PLAT_PHY_ADDR_SPACE_SIZE == (1ULL << 32), invalid_paddr_space_size);
+
+#define MMU32B_UNSET_DESC	~0ul
+#define MMU32B_INVALID_DESC	0ul
+
+#define MT_UNKNOWN	~0U
+
+/*
+ * MMU related values
+ */
+
+/* Sharable */
+#define MMU32B_TTB_S           (1 << 1)
+
+/* Not Outer Sharable */
+#define MMU32B_TTB_NOS         (1 << 5)
+
+/* Normal memory, Inner Non-cacheable */
+#define MMU32B_TTB_IRGN_NC     0
+
+/* Normal memory, Inner Write-Back Write-Allocate Cacheable */
+#define MMU32B_TTB_IRGN_WBWA   (1 << 6)
+
+/* Normal memory, Inner Write-Through Cacheable */
+#define MMU32B_TTB_IRGN_WT     1
+
+/* Normal memory, Inner Write-Back no Write-Allocate Cacheable */
+#define MMU32B_TTB_IRGN_WB     (1 | (1 << 6))
+
+/* Normal memory, Outer Write-Back Write-Allocate Cacheable */
+#define MMU32B_TTB_RNG_WBWA    (1 << 3)
+
+#define MMU32B_DEFAULT_ATTRS \
+		(MMU32B_TTB_S | MMU32B_TTB_NOS | \
+		 MMU32B_TTB_IRGN_WBWA | MMU32B_TTB_RNG_WBWA)
+
+/* armv7 memory mapping attributes: section mapping */
+#define SECTION_SECURE			(0 << 19)
+#define SECTION_NOTSECURE		(1 << 19)
+#define SECTION_SHARED			(1 << 16)
+#define SECTION_NOTGLOBAL		(1 << 17)
+#define SECTION_ACCESS_FLAG		(1 << 10)
+#define SECTION_UNPRIV			(1 << 11)
+#define SECTION_RO			(1 << 15)
+#define SECTION_TEX(tex)		((((tex) >> 2) << 12) | \
+					((((tex) >> 1) & 0x1) << 3) | \
+					(((tex) & 0x1) << 2))
+#define SECTION_DEVICE			SECTION_TEX(MMU32B_ATTR_DEVICE_INDEX)
+#define SECTION_NORMAL			SECTION_TEX(MMU32B_ATTR_DEVICE_INDEX)
+#define SECTION_NORMAL_CACHED		\
+				SECTION_TEX(MMU32B_ATTR_IWBWA_OWBWA_INDEX)
+
+#define SECTION_XN			(1 << 4)
+#define SECTION_PXN			(1 << 0)
+#define SECTION_SECTION			(2 << 0)
+
+#define SECTION_PT_NOTSECURE		(1 << 3)
+#define SECTION_PT_PT			(1 << 0)
+
+#define SMALL_PAGE_SMALL_PAGE		(1 << 1)
+#define SMALL_PAGE_SHARED		(1 << 10)
+#define SMALL_PAGE_NOTGLOBAL		(1 << 11)
+#define SMALL_PAGE_TEX(tex)		((((tex) >> 2) << 6) | \
+					((((tex) >> 1) & 0x1) << 3) | \
+					(((tex) & 0x1) << 2))
+#define SMALL_PAGE_DEVICE		\
+				SMALL_PAGE_TEX(MMU32B_ATTR_DEVICE_INDEX)
+#define SMALL_PAGE_NORMAL		\
+				SMALL_PAGE_TEX(MMU32B_ATTR_DEVICE_INDEX)
+#define SMALL_PAGE_NORMAL_CACHED	\
+				SMALL_PAGE_TEX(MMU32B_ATTR_IWBWA_OWBWA_INDEX)
+#define SMALL_PAGE_ACCESS_FLAG		(1 << 4)
+#define SMALL_PAGE_UNPRIV		(1 << 5)
+#define SMALL_PAGE_RO			(1 << 9)
+#define SMALL_PAGE_XN			(1 << 0)
+
+/* The TEX, C and B bits concatenated */
+#define MMU32B_ATTR_DEVICE_INDEX		0x0
+#define MMU32B_ATTR_IWBWA_OWBWA_INDEX		0x1
+
+#define MMU32B_PRRR_IDX(idx, tr, nos)	(((tr) << (2 * (idx))) | \
+					 ((uint32_t)(nos) << ((idx) + 24)))
+#define MMU32B_NMRR_IDX(idx, ir, or)	(((ir) << (2 * (idx))) | \
+					 ((uint32_t)(or) << (2 * (idx) + 16)))
+#define MMU32B_PRRR_DS0			(1 << 16)
+#define MMU32B_PRRR_DS1			(1 << 17)
+#define MMU32B_PRRR_NS0			(1 << 18)
+#define MMU32B_PRRR_NS1			(1 << 19)
+
+#define DACR_DOMAIN(num, perm)		((perm) << ((num) * 2))
+#define DACR_DOMAIN_PERM_NO_ACCESS	0x0
+#define DACR_DOMAIN_PERM_CLIENT		0x1
+#define DACR_DOMAIN_PERM_MANAGER	0x3
+
+#define NUM_1MB_IN_4GB		(1U << 12)
+#define NUM_4K_IN_1MB		(1U << 8)
+
+#define ONE_MB_SHIFT		20
+
+/* mmu 32b integration */
+#define MMU32B_L1_TABLE_SIZE		(NUM_1MB_IN_4GB * 4)
+#define MMU32B_L2_TABLE_SIZE		(NUM_4K_IN_1MB * 4)
+#define MMU32B_L1_TABLE_ALIGN		(1 << 14)
+#define MMU32B_L2_TABLE_ALIGN		(1 << 10)
+
+static unsigned int next_xlat;
+static unsigned long long xlat_max_pa;
+static uintptr_t xlat_max_va;
+
+static uint32_t mmu_l1_base[NUM_1MB_IN_4GB]
+	__aligned(MMU32B_L1_TABLE_ALIGN) __attribute__((section("xlat_table")));
+
+static uint32_t mmu_l2_base[MAX_XLAT_TABLES][NUM_4K_IN_1MB]
+	__aligned(MMU32B_L2_TABLE_ALIGN) __attribute__((section("xlat_table")));
+
+/*
+ * Array of all memory regions stored in order of ascending base address.
+ * The list is terminated by the first entry with size == 0.
+ */
+static mmap_region_t mmap[MAX_MMAP_REGIONS + 1];
+
+void print_mmap(void)
+{
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	mmap_region_t *mm = mmap;
+
+	printf("init xlat - l1:%p  l2:%p (%d)\n",
+		    (void *)mmu_l1_base, (void *)mmu_l2_base, MAX_XLAT_TABLES);
+	printf("mmap:\n");
+	while (mm->size) {
+		printf(" VA:%p  PA:0x%llx  size:0x%zx  attr:0x%x\n",
+				(void *)mm->base_va, mm->base_pa,
+				mm->size, mm->attr);
+		++mm;
+	};
+	printf("\n");
+#endif
+}
+
+void mmap_add(const mmap_region_t *mm)
+{
+	const mmap_region_t *mm_cursor = mm;
+
+	while ((mm_cursor->size != 0U) || (mm_cursor->attr != 0U)) {
+		mmap_add_region(mm_cursor->base_pa, mm_cursor->base_va,
+				mm_cursor->size, mm_cursor->attr);
+		mm_cursor++;
+	}
+}
+
+void mmap_add_region(unsigned long long base_pa, uintptr_t base_va,
+		     size_t size, unsigned int attr)
+{
+	mmap_region_t *mm = mmap;
+	const mmap_region_t *mm_last = mm + ARRAY_SIZE(mmap) - 1U;
+	unsigned long long end_pa = base_pa + size - 1U;
+	uintptr_t end_va = base_va + size - 1U;
+
+	assert(IS_PAGE_ALIGNED(base_pa));
+	assert(IS_PAGE_ALIGNED(base_va));
+	assert(IS_PAGE_ALIGNED(size));
+
+	if (size == 0U)
+		return;
+
+	assert(base_pa < end_pa); /* Check for overflows */
+	assert(base_va < end_va);
+
+	assert((base_va + (uintptr_t)size - (uintptr_t)1) <=
+					(PLAT_VIRT_ADDR_SPACE_SIZE - 1U));
+	assert((base_pa + (unsigned long long)size - 1ULL) <=
+					(PLAT_PHY_ADDR_SPACE_SIZE - 1U));
+
+#if ENABLE_ASSERTIONS
+
+	/* Check for PAs and VAs overlaps with all other regions */
+	for (mm = mmap; mm->size; ++mm) {
+
+		uintptr_t mm_end_va = mm->base_va + mm->size - 1U;
+
+		/*
+		 * Check if one of the regions is completely inside the other
+		 * one.
+		 */
+		bool fully_overlapped_va =
+			((base_va >= mm->base_va) && (end_va <= mm_end_va)) ||
+			((mm->base_va >= base_va) && (mm_end_va <= end_va));
+
+		/*
+		 * Full VA overlaps are only allowed if both regions are
+		 * identity mapped (zero offset) or have the same VA to PA
+		 * offset. Also, make sure that it's not the exact same area.
+		 */
+		if (fully_overlapped_va) {
+			assert((mm->base_va - mm->base_pa) ==
+			       (base_va - base_pa));
+			assert((base_va != mm->base_va) || (size != mm->size));
+		} else {
+			/*
+			 * If the regions do not have fully overlapping VAs,
+			 * then they must have fully separated VAs and PAs.
+			 * Partial overlaps are not allowed
+			 */
+
+			unsigned long long mm_end_pa =
+						     mm->base_pa + mm->size - 1;
+
+			bool separated_pa = (end_pa < mm->base_pa) ||
+				(base_pa > mm_end_pa);
+			bool separated_va = (end_va < mm->base_va) ||
+				(base_va > mm_end_va);
+
+			assert(separated_va && separated_pa);
+		}
+	}
+
+	mm = mmap; /* Restore pointer to the start of the array */
+
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Find correct place in mmap to insert new region */
+	while ((mm->base_va < base_va) && (mm->size != 0U))
+		++mm;
+
+	/*
+	 * If a section is contained inside another one with the same base
+	 * address, it must be placed after the one it is contained in:
+	 *
+	 * 1st |-----------------------|
+	 * 2nd |------------|
+	 * 3rd |------|
+	 *
+	 * This is required for mmap_region_attr() to get the attributes of the
+	 * small region correctly.
+	 */
+	while ((mm->base_va == base_va) && (mm->size > size))
+		++mm;
+
+	/* Make room for new region by moving other regions up by one place */
+	(void)memmove(mm + 1, mm, (uintptr_t)mm_last - (uintptr_t)mm);
+
+	/* Check we haven't lost the empty sentinal from the end of the array */
+	assert(mm_last->size == 0U);
+
+	mm->base_pa = base_pa;
+	mm->base_va = base_va;
+	mm->size = size;
+	mm->attr = attr;
+
+	if (end_pa > xlat_max_pa)
+		xlat_max_pa = end_pa;
+	if (end_va > xlat_max_va)
+		xlat_max_va = end_va;
+}
+
+/* map all memory as shared/global/domain0/no-usr access */
+static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa,
+					unsigned int level)
+{
+	unsigned long desc;
+
+	switch (level) {
+	case 1:
+		assert(!(addr_pa & (MMU32B_L1_TABLE_ALIGN - 1)));
+
+		desc = SECTION_SECTION | SECTION_SHARED;
+
+		desc |= attr & MT_NS ? SECTION_NOTSECURE : 0;
+
+		desc |= SECTION_ACCESS_FLAG;
+		desc |= attr & MT_RW ? 0 : SECTION_RO;
+
+		desc |= attr & MT_MEMORY ?
+			SECTION_NORMAL_CACHED : SECTION_DEVICE;
+
+		if ((attr & MT_RW) || !(attr & MT_MEMORY))
+			desc |= SECTION_XN;
+		break;
+	case 2:
+		assert(!(addr_pa & (MMU32B_L2_TABLE_ALIGN - 1)));
+
+		desc = SMALL_PAGE_SMALL_PAGE | SMALL_PAGE_SHARED;
+
+		desc |= SMALL_PAGE_ACCESS_FLAG;
+		desc |= attr & MT_RW ? 0 : SMALL_PAGE_RO;
+
+		desc |= attr & MT_MEMORY ?
+			SMALL_PAGE_NORMAL_CACHED : SMALL_PAGE_DEVICE;
+
+		if ((attr & MT_RW) || !(attr & MT_MEMORY))
+			desc |= SMALL_PAGE_XN;
+		break;
+	default:
+		panic();
+	}
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	/* dump only the non-lpae level 2 tables */
+	if (level == 2) {
+		printf(attr & MT_MEMORY ? "MEM" : "dev");
+		printf(attr & MT_RW ? "-rw" : "-RO");
+		printf(attr & MT_NS ? "-NS" : "-S");
+	}
+#endif
+	return desc | addr_pa;
+}
+
+static unsigned int mmap_region_attr(const mmap_region_t *mm, uintptr_t base_va,
+				     size_t size, unsigned int *attr)
+{
+	/* Don't assume that the area is contained in the first region */
+	unsigned int ret = MT_UNKNOWN;
+
+	/*
+	 * Get attributes from last (innermost) region that contains the
+	 * requested area. Don't stop as soon as one region doesn't contain it
+	 * because there may be other internal regions that contain this area:
+	 *
+	 * |-----------------------------1-----------------------------|
+	 * |----2----|     |-------3-------|    |----5----|
+	 *                   |--4--|
+	 *
+	 *                   |---| <- Area we want the attributes of.
+	 *
+	 * In this example, the area is contained in regions 1, 3 and 4 but not
+	 * in region 2. The loop shouldn't stop at region 2 as inner regions
+	 * have priority over outer regions, it should stop at region 5.
+	 */
+	for ( ; ; ++mm) {
+
+		if (mm->size == 0U)
+			return ret; /* Reached end of list */
+
+		if (mm->base_va > (base_va + size - 1U))
+			return ret; /* Next region is after area so end */
+
+		if ((mm->base_va + mm->size - 1U) < base_va)
+			continue; /* Next region has already been overtaken */
+
+		if ((ret == 0U) && (mm->attr == *attr))
+			continue; /* Region doesn't override attribs so skip */
+
+		if ((mm->base_va > base_va) ||
+			((mm->base_va + mm->size - 1U) < (base_va + size - 1U)))
+			return MT_UNKNOWN; /* Region doesn't fully cover area */
+
+		*attr = mm->attr;
+		ret = 0U;
+	}
+	return ret;
+}
+
+static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm,
+						unsigned long base_va,
+						unsigned long *table,
+						unsigned int level)
+{
+	unsigned int level_size_shift = (level == 1) ?
+					ONE_MB_SHIFT : FOUR_KB_SHIFT;
+	unsigned int level_size = 1 << level_size_shift;
+	unsigned long level_index_mask = (level == 1) ?
+					(NUM_1MB_IN_4GB - 1) << ONE_MB_SHIFT :
+					(NUM_4K_IN_1MB - 1) << FOUR_KB_SHIFT;
+
+	assert(level == 1 || level == 2);
+
+	VERBOSE("init xlat table at %p (level%1d)\n", (void *)table, level);
+
+	do  {
+		unsigned long desc = MMU32B_UNSET_DESC;
+
+		if (mm->base_va + mm->size <= base_va) {
+			/* Area now after the region so skip it */
+			++mm;
+			continue;
+		}
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+		/* dump only non-lpae level 2 tables content */
+		if (level == 2)
+			printf("      0x%lx %x " + 6 - 2 * level,
+						base_va, level_size);
+#endif
+		if (mm->base_va >= base_va + level_size) {
+			/* Next region is after area so nothing to map yet */
+			desc = MMU32B_INVALID_DESC;
+		} else if (mm->base_va <= base_va && mm->base_va + mm->size >=
+				base_va + level_size) {
+			/* Next region covers all of area */
+			unsigned int attr = mm->attr;
+			unsigned int r = mmap_region_attr(mm, base_va,
+							  level_size, &attr);
+
+			if (r == 0U) {
+				desc = mmap_desc(attr,
+					base_va - mm->base_va + mm->base_pa,
+					level);
+			}
+		}
+
+		if (desc == MMU32B_UNSET_DESC) {
+			unsigned long xlat_table;
+
+			/*
+			 * Area not covered by a region so need finer table
+			 * Reuse next level table if any (assert attrib matching).
+			 * Otherwise allocate a xlat table.
+			 */
+			if (*table) {
+				assert((*table & 3) == SECTION_PT_PT);
+				assert(!(*table & SECTION_PT_NOTSECURE) ==
+							!(mm->attr & MT_NS));
+
+				xlat_table = (*table) &
+						~(MMU32B_L1_TABLE_ALIGN - 1);
+				desc = *table;
+			} else {
+				xlat_table = (unsigned long)mmu_l2_base +
+					next_xlat * MMU32B_L2_TABLE_SIZE;
+				next_xlat++;
+				assert(next_xlat <= MAX_XLAT_TABLES);
+				memset((char *)xlat_table, 0,
+					MMU32B_L2_TABLE_SIZE);
+
+				desc = xlat_table | SECTION_PT_PT;
+				desc |= mm->attr & MT_NS ?
+					SECTION_PT_NOTSECURE : 0;
+			}
+			/* Recurse to fill in new table */
+			mm = init_xlation_table_inner(mm, base_va,
+						(unsigned long *)xlat_table,
+						level + 1);
+		}
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+		/* dump only non-lpae level 2 tables content */
+		if (level == 2)
+			printf("\n");
+#endif
+		*table++ = desc;
+		base_va += level_size;
+	} while (mm->size && (base_va & level_index_mask));
+
+	return mm;
+}
+
+void init_xlat_tables(void)
+{
+	print_mmap();
+
+	assert(!((unsigned int)mmu_l1_base & (MMU32B_L1_TABLE_ALIGN - 1)));
+	assert(!((unsigned int)mmu_l2_base & (MMU32B_L2_TABLE_ALIGN - 1)));
+
+	memset(mmu_l1_base, 0, MMU32B_L1_TABLE_SIZE);
+
+	init_xlation_table_inner(mmap, 0, (unsigned long *)mmu_l1_base, 1);
+
+	VERBOSE("init xlat - max_va=%p, max_pa=%llx\n",
+			(void *)xlat_max_va, xlat_max_pa);
+	assert(xlat_max_va <= PLAT_VIRT_ADDR_SPACE_SIZE - 1);
+	assert(xlat_max_pa <= PLAT_VIRT_ADDR_SPACE_SIZE - 1);
+}
+
+/*******************************************************************************
+ * Function for enabling the MMU in Secure PL1, assuming that the
+ * page-tables have already been created.
+ ******************************************************************************/
+void enable_mmu_svc_mon(unsigned int flags)
+{
+	unsigned int prrr;
+	unsigned int nmrr;
+	unsigned int sctlr;
+
+	assert(IS_IN_SECURE());
+	assert((read_sctlr() & SCTLR_M_BIT) == 0);
+
+	/* Enable Access flag (simplified access permissions) and TEX remap */
+	write_sctlr(read_sctlr() | SCTLR_AFE_BIT | SCTLR_TRE_BIT);
+
+	prrr = MMU32B_PRRR_IDX(MMU32B_ATTR_DEVICE_INDEX, 1, 0) \
+			| MMU32B_PRRR_IDX(MMU32B_ATTR_IWBWA_OWBWA_INDEX, 2, 1);
+	nmrr = MMU32B_NMRR_IDX(MMU32B_ATTR_DEVICE_INDEX, 0, 0) \
+			| MMU32B_NMRR_IDX(MMU32B_ATTR_IWBWA_OWBWA_INDEX, 1, 1);
+
+	prrr |= MMU32B_PRRR_NS1 | MMU32B_PRRR_DS1;
+
+	write_prrr(prrr);
+	write_nmrr(nmrr);
+
+	/* Program Domain access control register: domain 0 only */
+	write_dacr(DACR_DOMAIN(0, DACR_DOMAIN_PERM_CLIENT));
+
+	/* Invalidate TLBs at the current exception level */
+	tlbiall();
+
+	/* set MMU base xlat table entry (use only TTBR0) */
+	write_ttbr0((uint32_t)mmu_l1_base | MMU32B_DEFAULT_ATTRS);
+	write_ttbr1(0);
+
+	/*
+	 * Ensure all translation table writes have drained
+	 * into memory, the TLB invalidation is complete,
+	 * and translation register writes are committed
+	 * before enabling the MMU
+	 */
+	dsb();
+	isb();
+
+	sctlr = read_sctlr();
+	sctlr |= SCTLR_M_BIT;
+#if ARMV7_SUPPORTS_VIRTUALIZATION
+	sctlr |= SCTLR_WXN_BIT;
+#endif
+
+	if (flags & DISABLE_DCACHE)
+		sctlr &= ~SCTLR_C_BIT;
+	else
+		sctlr |= SCTLR_C_BIT;
+
+	write_sctlr(sctlr);
+
+	/* Ensure the MMU enable takes effect immediately */
+	isb();
+}
diff --git a/lib/xlat_tables/aarch32/xlat_tables.c b/lib/xlat_tables/aarch32/xlat_tables.c
new file mode 100644
index 0000000..4b01b9b
--- /dev/null
+++ b/lib/xlat_tables/aarch32/xlat_tables.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "../xlat_tables_private.h"
+
+#if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)
+#error ARMv7 target does not support LPAE MMU descriptors
+#endif
+
+#define XLAT_TABLE_LEVEL_BASE	\
+       GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE)
+
+#define NUM_BASE_LEVEL_ENTRIES	\
+       GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE)
+
+static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES]
+		__aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t));
+
+#if ENABLE_ASSERTIONS
+static unsigned long long get_max_supported_pa(void)
+{
+	/* Physical address space size for long descriptor format. */
+	return (1ULL << 40) - 1ULL;
+}
+#endif /* ENABLE_ASSERTIONS */
+
+unsigned int xlat_arch_current_el(void)
+{
+	/*
+	 * If EL3 is in AArch32 mode, all secure PL1 modes (Monitor, System,
+	 * SVC, Abort, UND, IRQ and FIQ modes) execute at EL3.
+	 */
+	return 3U;
+}
+
+uint64_t xlat_arch_get_xn_desc(unsigned int el __unused)
+{
+	return UPPER_ATTRS(XN);
+}
+
+void init_xlat_tables(void)
+{
+	unsigned long long max_pa;
+	uintptr_t max_va;
+
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE >= MIN_VIRT_ADDR_SPACE_SIZE);
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE);
+	assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE));
+
+	print_mmap();
+	init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE,
+						&max_va, &max_pa);
+
+	assert(max_va <= (PLAT_VIRT_ADDR_SPACE_SIZE - 1U));
+	assert(max_pa <= (PLAT_PHY_ADDR_SPACE_SIZE - 1U));
+	assert((PLAT_PHY_ADDR_SPACE_SIZE - 1U) <= get_max_supported_pa());
+}
+
+void enable_mmu_svc_mon(unsigned int flags)
+{
+	unsigned int mair0, ttbcr, sctlr;
+	uint64_t ttbr0;
+
+	assert(IS_IN_SECURE());
+	assert((read_sctlr() & SCTLR_M_BIT) == 0U);
+
+	/* Set attributes in the right indices of the MAIR */
+	mair0 = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
+	mair0 |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,
+			ATTR_IWBWA_OWBWA_NTR_INDEX);
+	mair0 |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE,
+			ATTR_NON_CACHEABLE_INDEX);
+	write_mair0(mair0);
+
+	/* Invalidate TLBs at the current exception level */
+	tlbiall();
+
+	/*
+	 * Set TTBCR bits as well. Set TTBR0 table properties. Disable TTBR1.
+	 */
+	int t0sz = 32 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE);
+
+	if ((flags & XLAT_TABLE_NC) != 0U) {
+		/* Inner & outer non-cacheable non-shareable. */
+		ttbcr = TTBCR_EAE_BIT |
+			TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
+			TTBCR_RGN0_INNER_NC | (uint32_t) t0sz;
+	} else {
+		/* Inner & outer WBWA & shareable. */
+		ttbcr = TTBCR_EAE_BIT |
+			TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
+			TTBCR_RGN0_INNER_WBA | (uint32_t) t0sz;
+	}
+	ttbcr |= TTBCR_EPD1_BIT;
+	write_ttbcr(ttbcr);
+
+	/* Set TTBR0 bits as well */
+	ttbr0 = (uintptr_t) base_xlation_table;
+	write64_ttbr0(ttbr0);
+	write64_ttbr1(0U);
+
+	/*
+	 * Ensure all translation table writes have drained
+	 * into memory, the TLB invalidation is complete,
+	 * and translation register writes are committed
+	 * before enabling the MMU
+	 */
+	dsbish();
+	isb();
+
+	sctlr = read_sctlr();
+	sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT;
+
+	if ((flags & DISABLE_DCACHE) != 0U)
+		sctlr &= ~SCTLR_C_BIT;
+	else
+		sctlr |= SCTLR_C_BIT;
+
+	write_sctlr(sctlr);
+
+	/* Ensure the MMU enable takes effect immediately */
+	isb();
+}
+
+void enable_mmu_direct_svc_mon(unsigned int flags)
+{
+	enable_mmu_svc_mon(flags);
+}
diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c
new file mode 100644
index 0000000..c86412c
--- /dev/null
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <common/bl_common.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+#include <plat/common/common_def.h>
+
+#include "../xlat_tables_private.h"
+
+#define XLAT_TABLE_LEVEL_BASE	\
+       GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE)
+
+#define NUM_BASE_LEVEL_ENTRIES	\
+       GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE)
+
+static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES]
+		__aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t));
+
+static unsigned long long tcr_ps_bits;
+
+static unsigned long long calc_physical_addr_size_bits(
+					unsigned long long max_addr)
+{
+	/* Physical address can't exceed 48 bits */
+	assert((max_addr & ADDR_MASK_48_TO_63) == 0U);
+
+	/* 48 bits address */
+	if ((max_addr & ADDR_MASK_44_TO_47) != 0U)
+		return TCR_PS_BITS_256TB;
+
+	/* 44 bits address */
+	if ((max_addr & ADDR_MASK_42_TO_43) != 0U)
+		return TCR_PS_BITS_16TB;
+
+	/* 42 bits address */
+	if ((max_addr & ADDR_MASK_40_TO_41) != 0U)
+		return TCR_PS_BITS_4TB;
+
+	/* 40 bits address */
+	if ((max_addr & ADDR_MASK_36_TO_39) != 0U)
+		return TCR_PS_BITS_1TB;
+
+	/* 36 bits address */
+	if ((max_addr & ADDR_MASK_32_TO_35) != 0U)
+		return TCR_PS_BITS_64GB;
+
+	return TCR_PS_BITS_4GB;
+}
+
+#if ENABLE_ASSERTIONS
+/*
+ * Physical Address ranges supported in the AArch64 Memory Model. Value 0b110 is
+ * supported in ARMv8.2 onwards.
+ */
+static const unsigned int pa_range_bits_arr[] = {
+	PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100,
+	PARANGE_0101, PARANGE_0110
+};
+
+static unsigned long long get_max_supported_pa(void)
+{
+	u_register_t pa_range = read_id_aa64mmfr0_el1() &
+						ID_AA64MMFR0_EL1_PARANGE_MASK;
+
+	/* All other values are reserved */
+	assert(pa_range < ARRAY_SIZE(pa_range_bits_arr));
+
+	return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL;
+}
+
+/*
+ * Return minimum virtual address space size supported by the architecture
+ */
+static uintptr_t xlat_get_min_virt_addr_space_size(void)
+{
+	uintptr_t ret;
+
+	if (is_armv8_4_ttst_present())
+		ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST;
+	else
+		ret = MIN_VIRT_ADDR_SPACE_SIZE;
+
+	return ret;
+}
+#endif /* ENABLE_ASSERTIONS */
+
+unsigned int xlat_arch_current_el(void)
+{
+	unsigned int el = (unsigned int)GET_EL(read_CurrentEl());
+
+	assert(el > 0U);
+
+	return el;
+}
+
+uint64_t xlat_arch_get_xn_desc(unsigned int el)
+{
+	if (el == 3U) {
+		return UPPER_ATTRS(XN);
+	} else {
+		assert(el == 1U);
+		return UPPER_ATTRS(PXN);
+	}
+}
+
+void init_xlat_tables(void)
+{
+	unsigned long long max_pa;
+	uintptr_t max_va;
+
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE >=
+		(xlat_get_min_virt_addr_space_size() - 1U));
+	assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE);
+	assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE));
+
+	print_mmap();
+	init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE,
+			   &max_va, &max_pa);
+
+	assert(max_va <= (PLAT_VIRT_ADDR_SPACE_SIZE - 1U));
+	assert(max_pa <= (PLAT_PHY_ADDR_SPACE_SIZE - 1U));
+	assert((PLAT_PHY_ADDR_SPACE_SIZE - 1U) <= get_max_supported_pa());
+
+	tcr_ps_bits = calc_physical_addr_size_bits(max_pa);
+}
+
+/*******************************************************************************
+ * Macro generating the code for the function enabling the MMU in the given
+ * exception level, assuming that the pagetables have already been created.
+ *
+ *   _el:		Exception level at which the function will run
+ *   _tcr_extra:	Extra bits to set in the TCR register. This mask will
+ *			be OR'ed with the default TCR value.
+ *   _tlbi_fct:		Function to invalidate the TLBs at the current
+ *			exception level
+ ******************************************************************************/
+#define DEFINE_ENABLE_MMU_EL(_el, _tcr_extra, _tlbi_fct)		\
+	void enable_mmu_el##_el(unsigned int flags)				\
+	{								\
+		uint64_t mair, tcr, ttbr;				\
+		uint32_t sctlr;						\
+									\
+		assert(IS_IN_EL(_el));					\
+		assert((read_sctlr_el##_el() & SCTLR_M_BIT) == 0U);	\
+									\
+		/* Set attributes in the right indices of the MAIR */	\
+		mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);	\
+		mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,		\
+				ATTR_IWBWA_OWBWA_NTR_INDEX);		\
+		mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE,		\
+				ATTR_NON_CACHEABLE_INDEX);		\
+		write_mair_el##_el(mair);				\
+									\
+		/* Invalidate TLBs at the current exception level */	\
+		_tlbi_fct();						\
+									\
+		/* Set TCR bits as well. */				\
+		/* Set T0SZ to (64 - width of virtual address space) */	\
+		int t0sz = 64 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE);\
+									\
+		if ((flags & XLAT_TABLE_NC) != 0U) {			\
+			/* Inner & outer non-cacheable non-shareable. */\
+			tcr = TCR_SH_NON_SHAREABLE |			\
+				TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC |	\
+				((uint64_t)t0sz << TCR_T0SZ_SHIFT);	\
+		} else {						\
+			/* Inner & outer WBWA & shareable. */		\
+			tcr = TCR_SH_INNER_SHAREABLE |			\
+				TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA |	\
+				((uint64_t)t0sz << TCR_T0SZ_SHIFT);	\
+		}							\
+		tcr |= _tcr_extra;					\
+		write_tcr_el##_el(tcr);					\
+									\
+		/* Set TTBR bits as well */				\
+		ttbr = (uint64_t) base_xlation_table;			\
+		write_ttbr0_el##_el(ttbr);				\
+									\
+		/* Ensure all translation table writes have drained */	\
+		/* into memory, the TLB invalidation is complete, */	\
+		/* and translation register writes are committed */	\
+		/* before enabling the MMU */				\
+		dsbish();						\
+		isb();							\
+									\
+		sctlr = read_sctlr_el##_el();				\
+		sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT;			\
+									\
+		if ((flags & DISABLE_DCACHE) != 0U)			\
+			sctlr &= ~SCTLR_C_BIT;				\
+		else							\
+			sctlr |= SCTLR_C_BIT;				\
+									\
+		write_sctlr_el##_el(sctlr);				\
+									\
+		/* Ensure the MMU enable takes effect immediately */	\
+		isb();							\
+	}								\
+									\
+	void enable_mmu_direct_el##_el(unsigned int flags)		\
+	{								\
+		enable_mmu_el##_el(flags);				\
+	}
+
+/* Define EL1 and EL3 variants of the function enabling the MMU */
+DEFINE_ENABLE_MMU_EL(1,
+		/*
+		 * TCR_EL1.EPD1: Disable translation table walk for addresses
+		 * that are translated using TTBR1_EL1.
+		 */
+		TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
+		tlbivmalle1)
+DEFINE_ENABLE_MMU_EL(3,
+		TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
+		tlbialle3)
diff --git a/lib/xlat_tables/xlat_tables_common.c b/lib/xlat_tables/xlat_tables_common.c
new file mode 100644
index 0000000..23fe3f0
--- /dev/null
+++ b/lib/xlat_tables/xlat_tables_common.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/cassert.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/common_def.h>
+
+#include "xlat_tables_private.h"
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+#define LVL0_SPACER ""
+#define LVL1_SPACER "  "
+#define LVL2_SPACER "    "
+#define LVL3_SPACER "      "
+#define get_level_spacer(level)		\
+			(((level) == U(0)) ? LVL0_SPACER : \
+			(((level) == U(1)) ? LVL1_SPACER : \
+			(((level) == U(2)) ? LVL2_SPACER : LVL3_SPACER)))
+#define debug_print(...) printf(__VA_ARGS__)
+#else
+#define debug_print(...) ((void)0)
+#endif
+
+#define UNSET_DESC	~0ULL
+#define MT_UNKNOWN	~0U
+
+static uint64_t xlat_tables[MAX_XLAT_TABLES][XLAT_TABLE_ENTRIES]
+			__aligned(XLAT_TABLE_SIZE) __section("xlat_table");
+
+static unsigned int next_xlat;
+static unsigned long long xlat_max_pa;
+static uintptr_t xlat_max_va;
+
+static uint64_t execute_never_mask;
+static uint64_t ap1_mask;
+
+/*
+ * Array of all memory regions stored in order of ascending base address.
+ * The list is terminated by the first entry with size == 0.
+ */
+static mmap_region_t mmap[MAX_MMAP_REGIONS + 1];
+
+
+void print_mmap(void)
+{
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	debug_print("mmap:\n");
+	mmap_region_t *mm = mmap;
+	while (mm->size != 0U) {
+		debug_print(" VA:%p  PA:0x%llx  size:0x%zx  attr:0x%x\n",
+				(void *)mm->base_va, mm->base_pa,
+				mm->size, mm->attr);
+		++mm;
+	};
+	debug_print("\n");
+#endif
+}
+
+void mmap_add_region(unsigned long long base_pa, uintptr_t base_va,
+		     size_t size, unsigned int attr)
+{
+	mmap_region_t *mm = mmap;
+	const mmap_region_t *mm_last = mm + ARRAY_SIZE(mmap) - 1U;
+	unsigned long long end_pa = base_pa + size - 1U;
+	uintptr_t end_va = base_va + size - 1U;
+
+	assert(IS_PAGE_ALIGNED(base_pa));
+	assert(IS_PAGE_ALIGNED(base_va));
+	assert(IS_PAGE_ALIGNED(size));
+
+	if (size == 0U)
+		return;
+
+	assert(base_pa < end_pa); /* Check for overflows */
+	assert(base_va < end_va);
+
+	assert((base_va + (uintptr_t)size - (uintptr_t)1) <=
+					(PLAT_VIRT_ADDR_SPACE_SIZE - 1U));
+	assert((base_pa + (unsigned long long)size - 1ULL) <=
+					(PLAT_PHY_ADDR_SPACE_SIZE - 1U));
+
+#if ENABLE_ASSERTIONS
+
+	/* Check for PAs and VAs overlaps with all other regions */
+	for (mm = mmap; mm->size; ++mm) {
+
+		uintptr_t mm_end_va = mm->base_va + mm->size - 1U;
+
+		/*
+		 * Check if one of the regions is completely inside the other
+		 * one.
+		 */
+		bool fully_overlapped_va =
+			((base_va >= mm->base_va) && (end_va <= mm_end_va)) ||
+			((mm->base_va >= base_va) && (mm_end_va <= end_va));
+
+		/*
+		 * Full VA overlaps are only allowed if both regions are
+		 * identity mapped (zero offset) or have the same VA to PA
+		 * offset. Also, make sure that it's not the exact same area.
+		 */
+		if (fully_overlapped_va) {
+			assert((mm->base_va - mm->base_pa) ==
+			       (base_va - base_pa));
+			assert((base_va != mm->base_va) || (size != mm->size));
+		} else {
+			/*
+			 * If the regions do not have fully overlapping VAs,
+			 * then they must have fully separated VAs and PAs.
+			 * Partial overlaps are not allowed
+			 */
+
+			unsigned long long mm_end_pa =
+						     mm->base_pa + mm->size - 1;
+
+			bool separated_pa = (end_pa < mm->base_pa) ||
+				(base_pa > mm_end_pa);
+			bool separated_va = (end_va < mm->base_va) ||
+				(base_va > mm_end_va);
+
+			assert(separated_va && separated_pa);
+		}
+	}
+
+	mm = mmap; /* Restore pointer to the start of the array */
+
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Find correct place in mmap to insert new region */
+	while ((mm->base_va < base_va) && (mm->size != 0U))
+		++mm;
+
+	/*
+	 * If a section is contained inside another one with the same base
+	 * address, it must be placed after the one it is contained in:
+	 *
+	 * 1st |-----------------------|
+	 * 2nd |------------|
+	 * 3rd |------|
+	 *
+	 * This is required for mmap_region_attr() to get the attributes of the
+	 * small region correctly.
+	 */
+	while ((mm->base_va == base_va) && (mm->size > size))
+		++mm;
+
+	/* Make room for new region by moving other regions up by one place */
+	(void)memmove(mm + 1, mm, (uintptr_t)mm_last - (uintptr_t)mm);
+
+	/* Check we haven't lost the empty sentinal from the end of the array */
+	assert(mm_last->size == 0U);
+
+	mm->base_pa = base_pa;
+	mm->base_va = base_va;
+	mm->size = size;
+	mm->attr = attr;
+
+	if (end_pa > xlat_max_pa)
+		xlat_max_pa = end_pa;
+	if (end_va > xlat_max_va)
+		xlat_max_va = end_va;
+}
+
+void mmap_add(const mmap_region_t *mm)
+{
+	const mmap_region_t *mm_cursor = mm;
+
+	while ((mm_cursor->size != 0U) || (mm_cursor->attr != 0U)) {
+		mmap_add_region(mm_cursor->base_pa, mm_cursor->base_va,
+				mm_cursor->size, mm_cursor->attr);
+		mm_cursor++;
+	}
+}
+
+static uint64_t mmap_desc(unsigned int attr, unsigned long long addr_pa,
+			  unsigned int level)
+{
+	uint64_t desc;
+	int mem_type;
+
+	/* Make sure that the granularity is fine enough to map this address. */
+	assert((addr_pa & XLAT_BLOCK_MASK(level)) == 0U);
+
+	desc = addr_pa;
+	/*
+	 * There are different translation table descriptors for level 3 and the
+	 * rest.
+	 */
+	desc |= (level == XLAT_TABLE_LEVEL_MAX) ? PAGE_DESC : BLOCK_DESC;
+	desc |= ((attr & MT_NS) != 0U) ? LOWER_ATTRS(NS) : 0U;
+	desc |= ((attr & MT_RW) != 0U) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO);
+	/*
+	 * Always set the access flag, as this library assumes access flag
+	 * faults aren't managed.
+	 */
+	desc |= LOWER_ATTRS(ACCESS_FLAG);
+	desc |= ap1_mask;
+
+	/*
+	 * Deduce shareability domain and executability of the memory region
+	 * from the memory type.
+	 *
+	 * Data accesses to device memory and non-cacheable normal memory are
+	 * coherent for all observers in the system, and correspondingly are
+	 * always treated as being Outer Shareable. Therefore, for these 2 types
+	 * of memory, it is not strictly needed to set the shareability field
+	 * in the translation tables.
+	 */
+	mem_type = MT_TYPE(attr);
+	if (mem_type == MT_DEVICE) {
+		desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH);
+		/*
+		 * Always map device memory as execute-never.
+		 * This is to avoid the possibility of a speculative instruction
+		 * fetch, which could be an issue if this memory region
+		 * corresponds to a read-sensitive peripheral.
+		 */
+		desc |= execute_never_mask;
+
+	} else { /* Normal memory */
+		/*
+		 * Always map read-write normal memory as execute-never.
+		 * This library assumes that it is used by software that does
+		 * not self-modify its code, therefore R/W memory is reserved
+		 * for data storage, which must not be executable.
+		 *
+		 * Note that setting the XN bit here is for consistency only.
+		 * The function that enables the MMU sets the SCTLR_ELx.WXN bit,
+		 * which makes any writable memory region to be treated as
+		 * execute-never, regardless of the value of the XN bit in the
+		 * translation table.
+		 *
+		 * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER
+		 * attribute to figure out the value of the XN bit.
+		 */
+		if (((attr & MT_RW) != 0U) || ((attr & MT_EXECUTE_NEVER) != 0U)) {
+			desc |= execute_never_mask;
+		}
+
+		if (mem_type == MT_MEMORY) {
+			desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH);
+		} else {
+			assert(mem_type == MT_NON_CACHEABLE);
+			desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH);
+		}
+	}
+
+	debug_print((mem_type == MT_MEMORY) ? "MEM" :
+		((mem_type == MT_NON_CACHEABLE) ? "NC" : "DEV"));
+	debug_print(((attr & MT_RW) != 0U) ? "-RW" : "-RO");
+	debug_print(((attr & MT_NS) != 0U) ? "-NS" : "-S");
+	debug_print(((attr & MT_EXECUTE_NEVER) != 0U) ? "-XN" : "-EXEC");
+	return desc;
+}
+
+/*
+ * Look for the innermost region that contains the area at `base_va` with size
+ * `size`. Populate *attr with the attributes of this region.
+ *
+ * On success, this function returns 0.
+ * If there are partial overlaps (meaning that a smaller size is needed) or if
+ * the region can't be found in the given area, it returns MT_UNKNOWN. In this
+ * case the value pointed by attr should be ignored by the caller.
+ */
+static unsigned int mmap_region_attr(const mmap_region_t *mm, uintptr_t base_va,
+				     size_t size, unsigned int *attr)
+{
+	/* Don't assume that the area is contained in the first region */
+	unsigned int ret = MT_UNKNOWN;
+
+	/*
+	 * Get attributes from last (innermost) region that contains the
+	 * requested area. Don't stop as soon as one region doesn't contain it
+	 * because there may be other internal regions that contain this area:
+	 *
+	 * |-----------------------------1-----------------------------|
+	 * |----2----|     |-------3-------|    |----5----|
+	 *                   |--4--|
+	 *
+	 *                   |---| <- Area we want the attributes of.
+	 *
+	 * In this example, the area is contained in regions 1, 3 and 4 but not
+	 * in region 2. The loop shouldn't stop at region 2 as inner regions
+	 * have priority over outer regions, it should stop at region 5.
+	 */
+	for ( ; ; ++mm) {
+
+		if (mm->size == 0U)
+			return ret; /* Reached end of list */
+
+		if (mm->base_va > (base_va + size - 1U))
+			return ret; /* Next region is after area so end */
+
+		if ((mm->base_va + mm->size - 1U) < base_va)
+			continue; /* Next region has already been overtaken */
+
+		if ((ret == 0U) && (mm->attr == *attr))
+			continue; /* Region doesn't override attribs so skip */
+
+		if ((mm->base_va > base_va) ||
+			((mm->base_va + mm->size - 1U) < (base_va + size - 1U)))
+			return MT_UNKNOWN; /* Region doesn't fully cover area */
+
+		*attr = mm->attr;
+		ret = 0U;
+	}
+	return ret;
+}
+
+static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm,
+					uintptr_t base_va,
+					uint64_t *table,
+					unsigned int level)
+{
+	assert((level >= XLAT_TABLE_LEVEL_MIN) &&
+	       (level <= XLAT_TABLE_LEVEL_MAX));
+
+	unsigned int level_size_shift =
+		       L0_XLAT_ADDRESS_SHIFT - level * XLAT_TABLE_ENTRIES_SHIFT;
+	u_register_t level_size = (u_register_t)1 << level_size_shift;
+	u_register_t level_index_mask =
+		((u_register_t)XLAT_TABLE_ENTRIES_MASK) << level_size_shift;
+
+	debug_print("New xlat table:\n");
+
+	do  {
+		uint64_t desc = UNSET_DESC;
+
+		if (mm->size == 0U) {
+			/* Done mapping regions; finish zeroing the table */
+			desc = INVALID_DESC;
+		} else if ((mm->base_va + mm->size - 1U) < base_va) {
+			/* This area is after the region so get next region */
+			++mm;
+			continue;
+		}
+
+		debug_print("%s VA:%p size:0x%llx ", get_level_spacer(level),
+			(void *)base_va, (unsigned long long)level_size);
+
+		if (mm->base_va > (base_va + level_size - 1U)) {
+			/* Next region is after this area. Nothing to map yet */
+			desc = INVALID_DESC;
+		/* Make sure that the current level allows block descriptors */
+		} else if (level >= XLAT_BLOCK_LEVEL_MIN) {
+			/*
+			 * Try to get attributes of this area. It will fail if
+			 * there are partially overlapping regions. On success,
+			 * it will return the innermost region's attributes.
+			 */
+			unsigned int attr;
+			unsigned int r = mmap_region_attr(mm, base_va,
+							  level_size, &attr);
+
+			if (r == 0U) {
+				desc = mmap_desc(attr,
+					base_va - mm->base_va + mm->base_pa,
+					level);
+			}
+		}
+
+		if (desc == UNSET_DESC) {
+			/* Area not covered by a region so need finer table */
+			uint64_t *new_table = xlat_tables[next_xlat];
+
+			next_xlat++;
+			assert(next_xlat <= MAX_XLAT_TABLES);
+			desc = TABLE_DESC | (uintptr_t)new_table;
+
+			/* Recurse to fill in new table */
+			mm = init_xlation_table_inner(mm, base_va,
+						new_table, level + 1U);
+		}
+
+		debug_print("\n");
+
+		*table++ = desc;
+		base_va += level_size;
+	} while ((base_va & level_index_mask) &&
+		 ((base_va - 1U) < (PLAT_VIRT_ADDR_SPACE_SIZE - 1U)));
+
+	return mm;
+}
+
+void init_xlation_table(uintptr_t base_va, uint64_t *table,
+			unsigned int level, uintptr_t *max_va,
+			unsigned long long *max_pa)
+{
+	unsigned int el = xlat_arch_current_el();
+
+	execute_never_mask = xlat_arch_get_xn_desc(el);
+
+	if (el == 3U) {
+		ap1_mask = LOWER_ATTRS(AP_ONE_VA_RANGE_RES1);
+	} else {
+		assert(el == 1U);
+		ap1_mask = 0ULL;
+	}
+
+	init_xlation_table_inner(mmap, base_va, table, level);
+	*max_va = xlat_max_va;
+	*max_pa = xlat_max_pa;
+}
diff --git a/lib/xlat_tables/xlat_tables_private.h b/lib/xlat_tables/xlat_tables_private.h
new file mode 100644
index 0000000..82bc70c
--- /dev/null
+++ b/lib/xlat_tables/xlat_tables_private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_PRIVATE_H
+#define XLAT_TABLES_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <lib/cassert.h>
+#include <lib/xlat_tables/xlat_tables_arch.h>
+
+#if HW_ASSISTED_COHERENCY
+#error xlat tables v2 must be used with HW_ASSISTED_COHERENCY
+#endif
+
+CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE),
+	assert_valid_phy_addr_space_size);
+
+/* Alias to retain compatibility with the old #define name */
+#define XLAT_BLOCK_LEVEL_MIN	MIN_LVL_BLOCK_DESC
+
+void print_mmap(void);
+
+/* Returns the current Exception Level. The returned EL must be 1 or higher. */
+unsigned int xlat_arch_current_el(void);
+
+/*
+ * Returns the bit mask that has to be ORed to the rest of a translation table
+ * descriptor so that execution of code is prohibited at the given Exception
+ * Level.
+ */
+uint64_t xlat_arch_get_xn_desc(unsigned int el);
+
+void init_xlation_table(uintptr_t base_va, uint64_t *table,
+			unsigned int level, uintptr_t *max_va,
+			unsigned long long *max_pa);
+
+#endif /* XLAT_TABLES_PRIVATE_H */
diff --git a/lib/xlat_tables_v2/aarch32/enable_mmu.S b/lib/xlat_tables_v2/aarch32/enable_mmu.S
new file mode 100644
index 0000000..f2fff36
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch32/enable_mmu.S
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+	.global	enable_mmu_direct_svc_mon
+	.global	enable_mmu_direct_hyp
+
+	/* void enable_mmu_direct_svc_mon(unsigned int flags) */
+func enable_mmu_direct_svc_mon
+	/* Assert that MMU is turned off */
+#if ENABLE_ASSERTIONS
+	ldcopr  r1, SCTLR
+	tst	r1, #SCTLR_M_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* Invalidate TLB entries */
+	TLB_INVALIDATE(r0, TLBIALL)
+
+	mov	r3, r0
+	ldr	r0, =mmu_cfg_params
+
+	/* MAIR0. Only the lower 32 bits are used. */
+	ldr	r1, [r0, #(MMU_CFG_MAIR << 3)]
+	stcopr	r1, MAIR0
+
+	/* TTBCR. Only the lower 32 bits are used. */
+	ldr	r2, [r0, #(MMU_CFG_TCR << 3)]
+	stcopr	r2, TTBCR
+
+	/* TTBR0 */
+	ldr	r1, [r0, #(MMU_CFG_TTBR0 << 3)]
+	ldr	r2, [r0, #((MMU_CFG_TTBR0 << 3) + 4)]
+	stcopr16	r1, r2, TTBR0_64
+
+	/* TTBR1 is unused right now; set it to 0. */
+	mov	r1, #0
+	mov	r2, #0
+	stcopr16	r1, r2, TTBR1_64
+
+	/*
+	 * Ensure all translation table writes have drained into memory, the TLB
+	 * invalidation is complete, and translation register writes are
+	 * committed before enabling the MMU
+	 */
+	dsb	ish
+	isb
+
+	/* Enable enable MMU by honoring flags */
+	ldcopr  r1, SCTLR
+	ldr	r2, =(SCTLR_WXN_BIT | SCTLR_C_BIT | SCTLR_M_BIT)
+	orr	r1, r1, r2
+
+	/* Clear C bit if requested */
+	tst	r3, #DISABLE_DCACHE
+	bicne	r1, r1, #SCTLR_C_BIT
+
+	stcopr	r1, SCTLR
+	isb
+
+	bx	lr
+endfunc enable_mmu_direct_svc_mon
+
+
+	/* void enable_mmu_direct_hyp(unsigned int flags) */
+func enable_mmu_direct_hyp
+	/* Assert that MMU is turned off */
+#if ENABLE_ASSERTIONS
+	ldcopr  r1, HSCTLR
+	tst	r1, #HSCTLR_M_BIT
+	ASM_ASSERT(eq)
+#endif
+
+	/* Invalidate TLB entries */
+	TLB_INVALIDATE(r0, TLBIALL)
+
+	mov	r3, r0
+	ldr	r0, =mmu_cfg_params
+
+	/* HMAIR0 */
+	ldr	r1, [r0, #(MMU_CFG_MAIR << 3)]
+	stcopr	r1, HMAIR0
+
+	/* HTCR */
+	ldr	r2, [r0, #(MMU_CFG_TCR << 3)]
+	stcopr	r2, HTCR
+
+	/* HTTBR */
+	ldr	r1, [r0, #(MMU_CFG_TTBR0 << 3)]
+	ldr	r2, [r0, #((MMU_CFG_TTBR0 << 3) + 4)]
+	stcopr16	r1, r2, HTTBR_64
+
+	/*
+	 * Ensure all translation table writes have drained into memory, the TLB
+	 * invalidation is complete, and translation register writes are
+	 * committed before enabling the MMU
+	 */
+	dsb	ish
+	isb
+
+	/* Enable enable MMU by honoring flags */
+	ldcopr  r1, HSCTLR
+	ldr	r2, =(HSCTLR_WXN_BIT | HSCTLR_C_BIT | HSCTLR_M_BIT)
+	orr	r1, r1, r2
+
+	/* Clear C bit if requested */
+	tst	r3, #DISABLE_DCACHE
+	bicne	r1, r1, #HSCTLR_C_BIT
+
+	stcopr	r1, HSCTLR
+	isb
+
+	bx	lr
+endfunc enable_mmu_direct_hyp
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
new file mode 100644
index 0000000..b69c670
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "../xlat_tables_private.h"
+
+#if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)
+#error ARMv7 target does not support LPAE MMU descriptors
+#endif
+
+/*
+ * Returns true if the provided granule size is supported, false otherwise.
+ */
+bool xlat_arch_is_granule_size_supported(size_t size)
+{
+	/*
+	 * The library uses the long descriptor translation table format, which
+	 * supports 4 KiB pages only.
+	 */
+	return size == PAGE_SIZE_4KB;
+}
+
+size_t xlat_arch_get_max_supported_granule_size(void)
+{
+	return PAGE_SIZE_4KB;
+}
+
+#if ENABLE_ASSERTIONS
+unsigned long long xlat_arch_get_max_supported_pa(void)
+{
+	/* Physical address space size for long descriptor format. */
+	return (1ULL << 40) - 1ULL;
+}
+
+/*
+ * Return minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void)
+{
+	return MIN_VIRT_ADDR_SPACE_SIZE;
+}
+#endif /* ENABLE_ASSERTIONS*/
+
+bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx)
+{
+	if (ctx->xlat_regime == EL1_EL0_REGIME) {
+		assert(xlat_arch_current_el() == 1U);
+		return (read_sctlr() & SCTLR_M_BIT) != 0U;
+	} else {
+		assert(ctx->xlat_regime == EL2_REGIME);
+		assert(xlat_arch_current_el() == 2U);
+		return (read_hsctlr() & HSCTLR_M_BIT) != 0U;
+	}
+}
+
+bool is_dcache_enabled(void)
+{
+	if (IS_IN_EL2()) {
+		return (read_hsctlr() & HSCTLR_C_BIT) != 0U;
+	} else {
+		return (read_sctlr() & SCTLR_C_BIT) != 0U;
+	}
+}
+
+uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime)
+{
+	if (xlat_regime == EL1_EL0_REGIME) {
+		return UPPER_ATTRS(XN) | UPPER_ATTRS(PXN);
+	} else {
+		assert(xlat_regime == EL2_REGIME);
+		return UPPER_ATTRS(XN);
+	}
+}
+
+void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime)
+{
+	/*
+	 * Ensure the translation table write has drained into memory before
+	 * invalidating the TLB entry.
+	 */
+	dsbishst();
+
+	if (xlat_regime == EL1_EL0_REGIME) {
+		tlbimvaais(TLBI_ADDR(va));
+	} else {
+		assert(xlat_regime == EL2_REGIME);
+		tlbimvahis(TLBI_ADDR(va));
+	}
+}
+
+void xlat_arch_tlbi_va_sync(void)
+{
+	/* Invalidate all entries from branch predictors. */
+	bpiallis();
+
+	/*
+	 * A TLB maintenance instruction can complete at any time after
+	 * it is issued, but is only guaranteed to be complete after the
+	 * execution of DSB by the PE that executed the TLB maintenance
+	 * instruction. After the TLB invalidate instruction is
+	 * complete, no new memory accesses using the invalidated TLB
+	 * entries will be observed by any observer of the system
+	 * domain. See section D4.8.2 of the ARMv8 (issue k), paragraph
+	 * "Ordering and completion of TLB maintenance instructions".
+	 */
+	dsbish();
+
+	/*
+	 * The effects of a completed TLB maintenance instruction are
+	 * only guaranteed to be visible on the PE that executed the
+	 * instruction after the execution of an ISB instruction by the
+	 * PE that executed the TLB maintenance instruction.
+	 */
+	isb();
+}
+
+unsigned int xlat_arch_current_el(void)
+{
+	if (IS_IN_HYP()) {
+		return 2U;
+	} else {
+		assert(IS_IN_SVC() || IS_IN_MON());
+		/*
+		 * If EL3 is in AArch32 mode, all secure PL1 modes (Monitor,
+		 * System, SVC, Abort, UND, IRQ and FIQ modes) execute at EL3.
+		 *
+		 * The PL1&0 translation regime in AArch32 behaves like the
+		 * EL1&0 regime in AArch64 except for the XN bits, but we set
+		 * and unset them at the same time, so there's no difference in
+		 * practice.
+		 */
+		return 1U;
+	}
+}
+
+/*******************************************************************************
+ * Function for enabling the MMU in PL1 or PL2, assuming that the page tables
+ * have already been created.
+ ******************************************************************************/
+void setup_mmu_cfg(uint64_t *params, unsigned int flags,
+		   const uint64_t *base_table, unsigned long long max_pa,
+		   uintptr_t max_va, __unused int xlat_regime)
+{
+	uint64_t mair, ttbr0;
+	uint32_t ttbcr;
+
+	/* Set attributes in the right indices of the MAIR */
+	mair = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
+	mair |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR,
+			ATTR_IWBWA_OWBWA_NTR_INDEX);
+	mair |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE,
+			ATTR_NON_CACHEABLE_INDEX);
+
+	/*
+	 * Configure the control register for stage 1 of the PL1&0 or EL2
+	 * translation regimes.
+	 */
+
+	/* Use the Long-descriptor translation table format. */
+	ttbcr = TTBCR_EAE_BIT;
+
+	if (xlat_regime == EL1_EL0_REGIME) {
+		assert(IS_IN_SVC() || IS_IN_MON());
+		/*
+		 * Disable translation table walk for addresses that are
+		 * translated using TTBR1. Therefore, only TTBR0 is used.
+		 */
+		ttbcr |= TTBCR_EPD1_BIT;
+	} else {
+		assert(xlat_regime == EL2_REGIME);
+		assert(IS_IN_HYP());
+
+		/*
+		 * Set HTCR bits as well. Set HTTBR table properties
+		 * as Inner & outer WBWA & shareable.
+		 */
+		ttbcr |= HTCR_RES1 |
+			 HTCR_SH0_INNER_SHAREABLE | HTCR_RGN0_OUTER_WBA |
+			 HTCR_RGN0_INNER_WBA;
+	}
+
+	/*
+	 * Limit the input address ranges and memory region sizes translated
+	 * using TTBR0 to the given virtual address space size, if smaller than
+	 * 32 bits.
+	 */
+	if (max_va != UINT32_MAX) {
+		uintptr_t virtual_addr_space_size = max_va + 1U;
+
+		assert(virtual_addr_space_size >=
+			xlat_get_min_virt_addr_space_size());
+		assert(virtual_addr_space_size <=
+			MAX_VIRT_ADDR_SPACE_SIZE);
+		assert(IS_POWER_OF_TWO(virtual_addr_space_size));
+
+		/*
+		 * __builtin_ctzll(0) is undefined but here we are guaranteed
+		 * that virtual_addr_space_size is in the range [1, UINT32_MAX].
+		 */
+		int t0sz = 32 - __builtin_ctzll(virtual_addr_space_size);
+
+		ttbcr |= (uint32_t) t0sz;
+	}
+
+	/*
+	 * Set the cacheability and shareability attributes for memory
+	 * associated with translation table walks using TTBR0.
+	 */
+	if ((flags & XLAT_TABLE_NC) != 0U) {
+		/* Inner & outer non-cacheable non-shareable. */
+		ttbcr |= TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC |
+			TTBCR_RGN0_INNER_NC;
+	} else {
+		/* Inner & outer WBWA & shareable. */
+		ttbcr |= TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA |
+			TTBCR_RGN0_INNER_WBA;
+	}
+
+	/* Set TTBR0 bits as well */
+	ttbr0 = (uint64_t)(uintptr_t) base_table;
+
+	if (is_armv8_2_ttcnp_present()) {
+		/* Enable CnP bit so as to share page tables with all PEs. */
+		ttbr0 |= TTBR_CNP_BIT;
+	}
+
+	/* Now populate MMU configuration */
+	params[MMU_CFG_MAIR] = mair;
+	params[MMU_CFG_TCR] = (uint64_t) ttbcr;
+	params[MMU_CFG_TTBR0] = ttbr0;
+}
diff --git a/lib/xlat_tables_v2/aarch64/enable_mmu.S b/lib/xlat_tables_v2/aarch64/enable_mmu.S
new file mode 100644
index 0000000..9f075e4
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch64/enable_mmu.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+	.global	enable_mmu_direct_el1
+	.global	enable_mmu_direct_el2
+	.global	enable_mmu_direct_el3
+
+	/* Macros to read and write to system register for a given EL. */
+	.macro _msr reg_name, el, gp_reg
+	msr	\reg_name\()_el\()\el, \gp_reg
+	.endm
+
+	.macro _mrs gp_reg, reg_name, el
+	mrs	\gp_reg, \reg_name\()_el\()\el
+	.endm
+
+	.macro tlbi_invalidate_all el
+	.if \el == 1
+		TLB_INVALIDATE(vmalle1)
+	.elseif \el == 2
+		TLB_INVALIDATE(alle2)
+	.elseif \el == 3
+		TLB_INVALIDATE(alle3)
+	.else
+		.error "EL must be 1, 2 or 3"
+	.endif
+	.endm
+
+	/* void enable_mmu_direct_el<x>(unsigned int flags) */
+	.macro define_mmu_enable_func el
+	func enable_mmu_direct_\()el\el
+#if ENABLE_ASSERTIONS
+		_mrs	x1, sctlr, \el
+		tst	x1, #SCTLR_M_BIT
+		ASM_ASSERT(eq)
+#endif
+		/* Invalidate all TLB entries */
+		tlbi_invalidate_all \el
+
+		mov	x7, x0
+		adrp	x0, mmu_cfg_params
+		add	x0, x0, :lo12:mmu_cfg_params
+
+		/* MAIR */
+		ldr	x1, [x0, #(MMU_CFG_MAIR << 3)]
+		_msr	mair, \el, x1
+
+		/* TCR */
+		ldr	x2, [x0, #(MMU_CFG_TCR << 3)]
+		_msr	tcr, \el, x2
+
+		/* TTBR */
+		ldr	x3, [x0, #(MMU_CFG_TTBR0 << 3)]
+		_msr	ttbr0, \el, x3
+
+		/*
+		 * Ensure all translation table writes have drained into memory, the TLB
+		 * invalidation is complete, and translation register writes are
+		 * committed before enabling the MMU
+		 */
+		dsb	ish
+		isb
+
+		/* Set and clear required fields of SCTLR */
+		_mrs	x4, sctlr, \el
+		mov_imm	x5, SCTLR_WXN_BIT | SCTLR_C_BIT | SCTLR_M_BIT
+		orr	x4, x4, x5
+
+		/* Additionally, amend SCTLR fields based on flags */
+		bic	x5, x4, #SCTLR_C_BIT
+		tst	x7, #DISABLE_DCACHE
+		csel	x4, x5, x4, ne
+
+		_msr	sctlr, \el, x4
+		isb
+
+		ret
+	endfunc enable_mmu_direct_\()el\el
+	.endm
+
+	/*
+	 * Define MMU-enabling functions for EL1, EL2 and EL3:
+	 *
+	 *  enable_mmu_direct_el1
+	 *  enable_mmu_direct_el2
+	 *  enable_mmu_direct_el3
+	 */
+	define_mmu_enable_func 1
+	define_mmu_enable_func 2
+	define_mmu_enable_func 3
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
new file mode 100644
index 0000000..8eeeea1
--- /dev/null
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <lib/cassert.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "../xlat_tables_private.h"
+
+/*
+ * Returns true if the provided granule size is supported, false otherwise.
+ */
+bool xlat_arch_is_granule_size_supported(size_t size)
+{
+	u_register_t id_aa64mmfr0_el1 = read_id_aa64mmfr0_el1();
+
+	if (size == PAGE_SIZE_4KB) {
+		return ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN4_SHIFT) &
+			 ID_AA64MMFR0_EL1_TGRAN4_MASK) ==
+			 ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED;
+	} else if (size == PAGE_SIZE_16KB) {
+		return ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN16_SHIFT) &
+			 ID_AA64MMFR0_EL1_TGRAN16_MASK) ==
+			 ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED;
+	} else if (size == PAGE_SIZE_64KB) {
+		return ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN64_SHIFT) &
+			 ID_AA64MMFR0_EL1_TGRAN64_MASK) ==
+			 ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED;
+	} else {
+		return 0;
+	}
+}
+
+size_t xlat_arch_get_max_supported_granule_size(void)
+{
+	if (xlat_arch_is_granule_size_supported(PAGE_SIZE_64KB)) {
+		return PAGE_SIZE_64KB;
+	} else if (xlat_arch_is_granule_size_supported(PAGE_SIZE_16KB)) {
+		return PAGE_SIZE_16KB;
+	} else {
+		assert(xlat_arch_is_granule_size_supported(PAGE_SIZE_4KB));
+		return PAGE_SIZE_4KB;
+	}
+}
+
+unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr)
+{
+	/* Physical address can't exceed 48 bits */
+	assert((max_addr & ADDR_MASK_48_TO_63) == 0U);
+
+	/* 48 bits address */
+	if ((max_addr & ADDR_MASK_44_TO_47) != 0U)
+		return TCR_PS_BITS_256TB;
+
+	/* 44 bits address */
+	if ((max_addr & ADDR_MASK_42_TO_43) != 0U)
+		return TCR_PS_BITS_16TB;
+
+	/* 42 bits address */
+	if ((max_addr & ADDR_MASK_40_TO_41) != 0U)
+		return TCR_PS_BITS_4TB;
+
+	/* 40 bits address */
+	if ((max_addr & ADDR_MASK_36_TO_39) != 0U)
+		return TCR_PS_BITS_1TB;
+
+	/* 36 bits address */
+	if ((max_addr & ADDR_MASK_32_TO_35) != 0U)
+		return TCR_PS_BITS_64GB;
+
+	return TCR_PS_BITS_4GB;
+}
+
+#if ENABLE_ASSERTIONS
+/*
+ * Physical Address ranges supported in the AArch64 Memory Model. Value 0b110 is
+ * supported in ARMv8.2 onwards.
+ */
+static const unsigned int pa_range_bits_arr[] = {
+	PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100,
+	PARANGE_0101, PARANGE_0110
+};
+
+unsigned long long xlat_arch_get_max_supported_pa(void)
+{
+	u_register_t pa_range = read_id_aa64mmfr0_el1() &
+						ID_AA64MMFR0_EL1_PARANGE_MASK;
+
+	/* All other values are reserved */
+	assert(pa_range < ARRAY_SIZE(pa_range_bits_arr));
+
+	return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL;
+}
+
+/*
+ * Return minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void)
+{
+	uintptr_t ret;
+
+	if (is_armv8_4_ttst_present())
+		ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST;
+	else
+		ret = MIN_VIRT_ADDR_SPACE_SIZE;
+
+	return ret;
+}
+#endif /* ENABLE_ASSERTIONS*/
+
+bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx)
+{
+	if (ctx->xlat_regime == EL1_EL0_REGIME) {
+		assert(xlat_arch_current_el() >= 1U);
+		return (read_sctlr_el1() & SCTLR_M_BIT) != 0U;
+	} else if (ctx->xlat_regime == EL2_REGIME) {
+		assert(xlat_arch_current_el() >= 2U);
+		return (read_sctlr_el2() & SCTLR_M_BIT) != 0U;
+	} else {
+		assert(ctx->xlat_regime == EL3_REGIME);
+		assert(xlat_arch_current_el() >= 3U);
+		return (read_sctlr_el3() & SCTLR_M_BIT) != 0U;
+	}
+}
+
+bool is_dcache_enabled(void)
+{
+	unsigned int el = (unsigned int)GET_EL(read_CurrentEl());
+
+	if (el == 1U) {
+		return (read_sctlr_el1() & SCTLR_C_BIT) != 0U;
+	} else if (el == 2U) {
+		return (read_sctlr_el2() & SCTLR_C_BIT) != 0U;
+	} else {
+		return (read_sctlr_el3() & SCTLR_C_BIT) != 0U;
+	}
+}
+
+uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime)
+{
+	if (xlat_regime == EL1_EL0_REGIME) {
+		return UPPER_ATTRS(UXN) | UPPER_ATTRS(PXN);
+	} else {
+		assert((xlat_regime == EL2_REGIME) ||
+		       (xlat_regime == EL3_REGIME));
+		return UPPER_ATTRS(XN);
+	}
+}
+
+void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime)
+{
+	/*
+	 * Ensure the translation table write has drained into memory before
+	 * invalidating the TLB entry.
+	 */
+	dsbishst();
+
+	/*
+	 * This function only supports invalidation of TLB entries for the EL3
+	 * and EL1&0 translation regimes.
+	 *
+	 * Also, it is architecturally UNDEFINED to invalidate TLBs of a higher
+	 * exception level (see section D4.9.2 of the ARM ARM rev B.a).
+	 */
+	if (xlat_regime == EL1_EL0_REGIME) {
+		assert(xlat_arch_current_el() >= 1U);
+		tlbivaae1is(TLBI_ADDR(va));
+	} else if (xlat_regime == EL2_REGIME) {
+		assert(xlat_arch_current_el() >= 2U);
+		tlbivae2is(TLBI_ADDR(va));
+	} else {
+		assert(xlat_regime == EL3_REGIME);
+		assert(xlat_arch_current_el() >= 3U);
+		tlbivae3is(TLBI_ADDR(va));
+	}
+}
+
+void xlat_arch_tlbi_va_sync(void)
+{
+	/*
+	 * A TLB maintenance instruction can complete at any time after
+	 * it is issued, but is only guaranteed to be complete after the
+	 * execution of DSB by the PE that executed the TLB maintenance
+	 * instruction. After the TLB invalidate instruction is
+	 * complete, no new memory accesses using the invalidated TLB
+	 * entries will be observed by any observer of the system
+	 * domain. See section D4.8.2 of the ARMv8 (issue k), paragraph
+	 * "Ordering and completion of TLB maintenance instructions".
+	 */
+	dsbish();
+
+	/*
+	 * The effects of a completed TLB maintenance instruction are
+	 * only guaranteed to be visible on the PE that executed the
+	 * instruction after the execution of an ISB instruction by the
+	 * PE that executed the TLB maintenance instruction.
+	 */
+	isb();
+}
+
+unsigned int xlat_arch_current_el(void)
+{
+	unsigned int el = (unsigned int)GET_EL(read_CurrentEl());
+
+	assert(el > 0U);
+
+	return el;
+}
+
+void setup_mmu_cfg(uint64_t *params, unsigned int flags,
+		   const uint64_t *base_table, unsigned long long max_pa,
+		   uintptr_t max_va, int xlat_regime)
+{
+	uint64_t mair, ttbr0, tcr;
+	uintptr_t virtual_addr_space_size;
+
+	/* Set attributes in the right indices of the MAIR. */
+	mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX);
+	mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX);
+	mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX);
+
+	/*
+	 * Limit the input address ranges and memory region sizes translated
+	 * using TTBR0 to the given virtual address space size.
+	 */
+	assert(max_va < ((uint64_t)UINTPTR_MAX));
+
+	virtual_addr_space_size = (uintptr_t)max_va + 1U;
+
+	assert(virtual_addr_space_size >=
+		xlat_get_min_virt_addr_space_size());
+	assert(virtual_addr_space_size <= MAX_VIRT_ADDR_SPACE_SIZE);
+	assert(IS_POWER_OF_TWO(virtual_addr_space_size));
+
+	/*
+	 * __builtin_ctzll(0) is undefined but here we are guaranteed that
+	 * virtual_addr_space_size is in the range [1,UINTPTR_MAX].
+	 */
+	int t0sz = 64 - __builtin_ctzll(virtual_addr_space_size);
+
+	tcr = (uint64_t)t0sz << TCR_T0SZ_SHIFT;
+
+	/*
+	 * Set the cacheability and shareability attributes for memory
+	 * associated with translation table walks.
+	 */
+	if ((flags & XLAT_TABLE_NC) != 0U) {
+		/* Inner & outer non-cacheable non-shareable. */
+		tcr |= TCR_SH_NON_SHAREABLE |
+			TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC;
+	} else {
+		/* Inner & outer WBWA & shareable. */
+		tcr |= TCR_SH_INNER_SHAREABLE |
+			TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA;
+	}
+
+	/*
+	 * It is safer to restrict the max physical address accessible by the
+	 * hardware as much as possible.
+	 */
+	unsigned long long tcr_ps_bits = tcr_physical_addr_size_bits(max_pa);
+
+	if (xlat_regime == EL1_EL0_REGIME) {
+		/*
+		 * TCR_EL1.EPD1: Disable translation table walk for addresses
+		 * that are translated using TTBR1_EL1.
+		 */
+		tcr |= TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT);
+	} else if (xlat_regime == EL2_REGIME) {
+		tcr |= TCR_EL2_RES1 | (tcr_ps_bits << TCR_EL2_PS_SHIFT);
+	} else {
+		assert(xlat_regime == EL3_REGIME);
+		tcr |= TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT);
+	}
+
+	/* Set TTBR bits as well */
+	ttbr0 = (uint64_t) base_table;
+
+	if (is_armv8_2_ttcnp_present()) {
+		/* Enable CnP bit so as to share page tables with all PEs. */
+		ttbr0 |= TTBR_CNP_BIT;
+	}
+
+	params[MMU_CFG_MAIR] = mair;
+	params[MMU_CFG_TCR] = tcr;
+	params[MMU_CFG_TTBR0] = ttbr0;
+}
diff --git a/lib/xlat_tables_v2/xlat_tables.mk b/lib/xlat_tables_v2/xlat_tables.mk
new file mode 100644
index 0000000..c946315
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+XLAT_TABLES_LIB_SRCS	:=	$(addprefix lib/xlat_tables_v2/,	\
+				${ARCH}/enable_mmu.S			\
+				${ARCH}/xlat_tables_arch.c		\
+				xlat_tables_context.c			\
+				xlat_tables_core.c			\
+				xlat_tables_utils.c)
+
+XLAT_TABLES_LIB_V2	:=	1
+$(eval $(call add_define,XLAT_TABLES_LIB_V2))
diff --git a/lib/xlat_tables_v2/xlat_tables_context.c b/lib/xlat_tables_v2/xlat_tables_context.c
new file mode 100644
index 0000000..f4b64b3
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_context.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "xlat_tables_private.h"
+
+/*
+ * MMU configuration register values for the active translation context. Used
+ * from the MMU assembly helpers.
+ */
+uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
+
+/*
+ * Allocate and initialise the default translation context for the BL image
+ * currently executing.
+ */
+REGISTER_XLAT_CONTEXT(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES,
+		PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE);
+
+void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size,
+		     unsigned int attr)
+{
+	mmap_region_t mm = MAP_REGION(base_pa, base_va, size, attr);
+
+	mmap_add_region_ctx(&tf_xlat_ctx, &mm);
+}
+
+void mmap_add(const mmap_region_t *mm)
+{
+	mmap_add_ctx(&tf_xlat_ctx, mm);
+}
+
+void mmap_add_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va,
+			      size_t size, unsigned int attr)
+{
+	mmap_region_t mm = MAP_REGION_ALLOC_VA(base_pa, size, attr);
+
+	mmap_add_region_alloc_va_ctx(&tf_xlat_ctx, &mm);
+
+	*base_va = mm.base_va;
+}
+
+void mmap_add_alloc_va(mmap_region_t *mm)
+{
+	while (mm->granularity != 0U) {
+		assert(mm->base_va == 0U);
+		mmap_add_region_alloc_va_ctx(&tf_xlat_ctx, mm);
+		mm++;
+	}
+}
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+
+int mmap_add_dynamic_region(unsigned long long base_pa, uintptr_t base_va,
+			    size_t size, unsigned int attr)
+{
+	mmap_region_t mm = MAP_REGION(base_pa, base_va, size, attr);
+
+	return mmap_add_dynamic_region_ctx(&tf_xlat_ctx, &mm);
+}
+
+int mmap_add_dynamic_region_alloc_va(unsigned long long base_pa,
+				     uintptr_t *base_va, size_t size,
+				     unsigned int attr)
+{
+	mmap_region_t mm = MAP_REGION_ALLOC_VA(base_pa, size, attr);
+
+	int rc = mmap_add_dynamic_region_alloc_va_ctx(&tf_xlat_ctx, &mm);
+
+	*base_va = mm.base_va;
+
+	return rc;
+}
+
+
+int mmap_remove_dynamic_region(uintptr_t base_va, size_t size)
+{
+	return mmap_remove_dynamic_region_ctx(&tf_xlat_ctx,
+					base_va, size);
+}
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+void __init init_xlat_tables(void)
+{
+	assert(tf_xlat_ctx.xlat_regime == EL_REGIME_INVALID);
+
+	unsigned int current_el = xlat_arch_current_el();
+
+	if (current_el == 1U) {
+		tf_xlat_ctx.xlat_regime = EL1_EL0_REGIME;
+	} else if (current_el == 2U) {
+		tf_xlat_ctx.xlat_regime = EL2_REGIME;
+	} else {
+		assert(current_el == 3U);
+		tf_xlat_ctx.xlat_regime = EL3_REGIME;
+	}
+
+	init_xlat_tables_ctx(&tf_xlat_ctx);
+}
+
+int xlat_get_mem_attributes(uintptr_t base_va, uint32_t *attr)
+{
+	return xlat_get_mem_attributes_ctx(&tf_xlat_ctx, base_va, attr);
+}
+
+int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr)
+{
+	return xlat_change_mem_attributes_ctx(&tf_xlat_ctx, base_va, size, attr);
+}
+
+/*
+ * If dynamic allocation of new regions is disabled then by the time we call the
+ * function enabling the MMU, we'll have registered all the memory regions to
+ * map for the system's lifetime. Therefore, at this point we know the maximum
+ * physical address that will ever be mapped.
+ *
+ * If dynamic allocation is enabled then we can't make any such assumption
+ * because the maximum physical address could get pushed while adding a new
+ * region. Therefore, in this case we have to assume that the whole address
+ * space size might be mapped.
+ */
+#ifdef PLAT_XLAT_TABLES_DYNAMIC
+#define MAX_PHYS_ADDR	tf_xlat_ctx.pa_max_address
+#else
+#define MAX_PHYS_ADDR	tf_xlat_ctx.max_pa
+#endif
+
+#ifdef __aarch64__
+
+void enable_mmu_el1(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL1_EL0_REGIME);
+	enable_mmu_direct_el1(flags);
+}
+
+void enable_mmu_el2(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL2_REGIME);
+	enable_mmu_direct_el2(flags);
+}
+
+void enable_mmu_el3(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL3_REGIME);
+	enable_mmu_direct_el3(flags);
+}
+
+#else /* !__aarch64__ */
+
+void enable_mmu_svc_mon(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL1_EL0_REGIME);
+	enable_mmu_direct_svc_mon(flags);
+}
+
+void enable_mmu_hyp(unsigned int flags)
+{
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags,
+		      tf_xlat_ctx.base_table, MAX_PHYS_ADDR,
+		      tf_xlat_ctx.va_max_address, EL2_REGIME);
+	enable_mmu_direct_hyp(flags);
+}
+
+#endif /* __aarch64__ */
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
new file mode 100644
index 0000000..4f62f46
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -0,0 +1,1231 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "xlat_tables_private.h"
+
+/* Helper function that cleans the data cache only if it is enabled. */
+static inline __attribute__((unused)) void xlat_clean_dcache_range(uintptr_t addr, size_t size)
+{
+	if (is_dcache_enabled())
+		clean_dcache_range(addr, size);
+}
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+
+/*
+ * The following functions assume that they will be called using subtables only.
+ * The base table can't be unmapped, so it is not needed to do any special
+ * handling for it.
+ */
+
+/*
+ * Returns the index of the array corresponding to the specified translation
+ * table.
+ */
+static int xlat_table_get_index(const xlat_ctx_t *ctx, const uint64_t *table)
+{
+	for (int i = 0; i < ctx->tables_num; i++)
+		if (ctx->tables[i] == table)
+			return i;
+
+	/*
+	 * Maybe we were asked to get the index of the base level table, which
+	 * should never happen.
+	 */
+	assert(false);
+
+	return -1;
+}
+
+/* Returns a pointer to an empty translation table. */
+static uint64_t *xlat_table_get_empty(const xlat_ctx_t *ctx)
+{
+	for (int i = 0; i < ctx->tables_num; i++)
+		if (ctx->tables_mapped_regions[i] == 0)
+			return ctx->tables[i];
+
+	return NULL;
+}
+
+/* Increments region count for a given table. */
+static void xlat_table_inc_regions_count(const xlat_ctx_t *ctx,
+					 const uint64_t *table)
+{
+	int idx = xlat_table_get_index(ctx, table);
+
+	ctx->tables_mapped_regions[idx]++;
+}
+
+/* Decrements region count for a given table. */
+static void xlat_table_dec_regions_count(const xlat_ctx_t *ctx,
+					 const uint64_t *table)
+{
+	int idx = xlat_table_get_index(ctx, table);
+
+	ctx->tables_mapped_regions[idx]--;
+}
+
+/* Returns 0 if the specified table isn't empty, otherwise 1. */
+static bool xlat_table_is_empty(const xlat_ctx_t *ctx, const uint64_t *table)
+{
+	return ctx->tables_mapped_regions[xlat_table_get_index(ctx, table)] == 0;
+}
+
+#else /* PLAT_XLAT_TABLES_DYNAMIC */
+
+/* Returns a pointer to the first empty translation table. */
+static uint64_t *xlat_table_get_empty(xlat_ctx_t *ctx)
+{
+	assert(ctx->next_table < ctx->tables_num);
+
+	return ctx->tables[ctx->next_table++];
+}
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+/*
+ * Returns a block/page table descriptor for the given level and attributes.
+ */
+uint64_t xlat_desc(const xlat_ctx_t *ctx, uint32_t attr,
+		   unsigned long long addr_pa, unsigned int level)
+{
+	uint64_t desc;
+	uint32_t mem_type;
+
+	/* Make sure that the granularity is fine enough to map this address. */
+	assert((addr_pa & XLAT_BLOCK_MASK(level)) == 0U);
+
+	desc = addr_pa;
+	/*
+	 * There are different translation table descriptors for level 3 and the
+	 * rest.
+	 */
+	desc |= (level == XLAT_TABLE_LEVEL_MAX) ? PAGE_DESC : BLOCK_DESC;
+	/*
+	 * Always set the access flag, as this library assumes access flag
+	 * faults aren't managed.
+	 */
+	desc |= LOWER_ATTRS(ACCESS_FLAG);
+	/*
+	 * Deduce other fields of the descriptor based on the MT_NS and MT_RW
+	 * memory region attributes.
+	 */
+	desc |= ((attr & MT_NS) != 0U) ? LOWER_ATTRS(NS) : 0U;
+	desc |= ((attr & MT_RW) != 0U) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO);
+
+	/*
+	 * Do not allow unprivileged access when the mapping is for a privileged
+	 * EL. For translation regimes that do not have mappings for access for
+	 * lower exception levels, set AP[2] to AP_NO_ACCESS_UNPRIVILEGED.
+	 */
+	if (ctx->xlat_regime == EL1_EL0_REGIME) {
+		if ((attr & MT_USER) != 0U) {
+			/* EL0 mapping requested, so we give User access */
+			desc |= LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED);
+		} else {
+			/* EL1 mapping requested, no User access granted */
+			desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED);
+		}
+	} else {
+		assert((ctx->xlat_regime == EL2_REGIME) ||
+		       (ctx->xlat_regime == EL3_REGIME));
+		desc |= LOWER_ATTRS(AP_ONE_VA_RANGE_RES1);
+	}
+
+	/*
+	 * Deduce shareability domain and executability of the memory region
+	 * from the memory type of the attributes (MT_TYPE).
+	 *
+	 * Data accesses to device memory and non-cacheable normal memory are
+	 * coherent for all observers in the system, and correspondingly are
+	 * always treated as being Outer Shareable. Therefore, for these 2 types
+	 * of memory, it is not strictly needed to set the shareability field
+	 * in the translation tables.
+	 */
+	mem_type = MT_TYPE(attr);
+	if (mem_type == MT_DEVICE) {
+		desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH);
+		/*
+		 * Always map device memory as execute-never.
+		 * This is to avoid the possibility of a speculative instruction
+		 * fetch, which could be an issue if this memory region
+		 * corresponds to a read-sensitive peripheral.
+		 */
+		desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
+
+	} else { /* Normal memory */
+		/*
+		 * Always map read-write normal memory as execute-never.
+		 * This library assumes that it is used by software that does
+		 * not self-modify its code, therefore R/W memory is reserved
+		 * for data storage, which must not be executable.
+		 *
+		 * Note that setting the XN bit here is for consistency only.
+		 * The function that enables the MMU sets the SCTLR_ELx.WXN bit,
+		 * which makes any writable memory region to be treated as
+		 * execute-never, regardless of the value of the XN bit in the
+		 * translation table.
+		 *
+		 * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER
+		 * attribute to figure out the value of the XN bit.  The actual
+		 * XN bit(s) to set in the descriptor depends on the context's
+		 * translation regime and the policy applied in
+		 * xlat_arch_regime_get_xn_desc().
+		 */
+		if (((attr & MT_RW) != 0U) || ((attr & MT_EXECUTE_NEVER) != 0U)) {
+			desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
+		}
+
+		if (mem_type == MT_MEMORY) {
+			desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH);
+
+			/* Check if Branch Target Identification is enabled */
+#if ENABLE_BTI
+			/* Set GP bit for block and page code entries
+			 * if BTI mechanism is implemented.
+			 */
+			if (is_armv8_5_bti_present() &&
+			   ((attr & (MT_TYPE_MASK | MT_RW |
+				MT_EXECUTE_NEVER)) == MT_CODE)) {
+				desc |= GP;
+			}
+#endif
+		} else {
+			assert(mem_type == MT_NON_CACHEABLE);
+			desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH);
+		}
+	}
+
+	return desc;
+}
+
+/*
+ * Enumeration of actions that can be made when mapping table entries depending
+ * on the previous value in that entry and information about the region being
+ * mapped.
+ */
+typedef enum {
+
+	/* Do nothing */
+	ACTION_NONE,
+
+	/* Write a block (or page, if in level 3) entry. */
+	ACTION_WRITE_BLOCK_ENTRY,
+
+	/*
+	 * Create a new table and write a table entry pointing to it. Recurse
+	 * into it for further processing.
+	 */
+	ACTION_CREATE_NEW_TABLE,
+
+	/*
+	 * There is a table descriptor in this entry, read it and recurse into
+	 * that table for further processing.
+	 */
+	ACTION_RECURSE_INTO_TABLE,
+
+} action_t;
+
+/*
+ * Function that returns the first VA of the table affected by the specified
+ * mmap region.
+ */
+static uintptr_t xlat_tables_find_start_va(mmap_region_t *mm,
+				   const uintptr_t table_base_va,
+				   const unsigned int level)
+{
+	uintptr_t table_idx_va;
+
+	if (mm->base_va > table_base_va) {
+		/* Find the first index of the table affected by the region. */
+		table_idx_va = mm->base_va & ~XLAT_BLOCK_MASK(level);
+	} else {
+		/* Start from the beginning of the table. */
+		table_idx_va = table_base_va;
+	}
+
+	return table_idx_va;
+}
+
+/*
+ * Function that returns table index for the given VA and level arguments.
+ */
+static inline unsigned int  xlat_tables_va_to_index(const uintptr_t table_base_va,
+						const uintptr_t va,
+						const unsigned int level)
+{
+	return (unsigned int)((va - table_base_va) >> XLAT_ADDR_SHIFT(level));
+}
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+
+/*
+ * From the given arguments, it decides which action to take when unmapping the
+ * specified region.
+ */
+static action_t xlat_tables_unmap_region_action(const mmap_region_t *mm,
+		const uintptr_t table_idx_va, const uintptr_t table_idx_end_va,
+		const unsigned int level, const uint64_t desc_type)
+{
+	action_t action;
+	uintptr_t region_end_va = mm->base_va + mm->size - 1U;
+
+	if ((mm->base_va <= table_idx_va) &&
+	    (region_end_va >= table_idx_end_va)) {
+		/* Region covers all block */
+
+		if (level == 3U) {
+			/*
+			 * Last level, only page descriptors allowed,
+			 * erase it.
+			 */
+			assert(desc_type == PAGE_DESC);
+
+			action = ACTION_WRITE_BLOCK_ENTRY;
+		} else {
+			/*
+			 * Other levels can have table descriptors. If
+			 * so, recurse into it and erase descriptors
+			 * inside it as needed. If there is a block
+			 * descriptor, just erase it. If an invalid
+			 * descriptor is found, this table isn't
+			 * actually mapped, which shouldn't happen.
+			 */
+			if (desc_type == TABLE_DESC) {
+				action = ACTION_RECURSE_INTO_TABLE;
+			} else {
+				assert(desc_type == BLOCK_DESC);
+				action = ACTION_WRITE_BLOCK_ENTRY;
+			}
+		}
+
+	} else if ((mm->base_va <= table_idx_end_va) ||
+		   (region_end_va >= table_idx_va)) {
+		/*
+		 * Region partially covers block.
+		 *
+		 * It can't happen in level 3.
+		 *
+		 * There must be a table descriptor here, if not there
+		 * was a problem when mapping the region.
+		 */
+		assert(level < 3U);
+		assert(desc_type == TABLE_DESC);
+
+		action = ACTION_RECURSE_INTO_TABLE;
+	} else {
+		/* The region doesn't cover the block at all */
+		action = ACTION_NONE;
+	}
+
+	return action;
+}
+/*
+ * Recursive function that writes to the translation tables and unmaps the
+ * specified region.
+ */
+static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm,
+				     const uintptr_t table_base_va,
+				     uint64_t *const table_base,
+				     const unsigned int table_entries,
+				     const unsigned int level)
+{
+	assert((level >= ctx->base_level) && (level <= XLAT_TABLE_LEVEL_MAX));
+
+	uint64_t *subtable;
+	uint64_t desc;
+
+	uintptr_t table_idx_va;
+	uintptr_t table_idx_end_va; /* End VA of this entry */
+
+	uintptr_t region_end_va = mm->base_va + mm->size - 1U;
+
+	unsigned int table_idx;
+
+	table_idx_va = xlat_tables_find_start_va(mm, table_base_va, level);
+	table_idx = xlat_tables_va_to_index(table_base_va, table_idx_va, level);
+
+	while (table_idx < table_entries) {
+
+		table_idx_end_va = table_idx_va + XLAT_BLOCK_SIZE(level) - 1U;
+
+		desc = table_base[table_idx];
+		uint64_t desc_type = desc & DESC_MASK;
+
+		action_t action = xlat_tables_unmap_region_action(mm,
+				table_idx_va, table_idx_end_va, level,
+				desc_type);
+
+		if (action == ACTION_WRITE_BLOCK_ENTRY) {
+
+			table_base[table_idx] = INVALID_DESC;
+			xlat_arch_tlbi_va(table_idx_va, ctx->xlat_regime);
+
+		} else if (action == ACTION_RECURSE_INTO_TABLE) {
+
+			subtable = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
+
+			/* Recurse to write into subtable */
+			xlat_tables_unmap_region(ctx, mm, table_idx_va,
+						 subtable, XLAT_TABLE_ENTRIES,
+						 level + 1U);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)subtable,
+				XLAT_TABLE_ENTRIES * sizeof(uint64_t));
+#endif
+			/*
+			 * If the subtable is now empty, remove its reference.
+			 */
+			if (xlat_table_is_empty(ctx, subtable)) {
+				table_base[table_idx] = INVALID_DESC;
+				xlat_arch_tlbi_va(table_idx_va,
+						  ctx->xlat_regime);
+			}
+
+		} else {
+			assert(action == ACTION_NONE);
+		}
+
+		table_idx++;
+		table_idx_va += XLAT_BLOCK_SIZE(level);
+
+		/* If reached the end of the region, exit */
+		if (region_end_va <= table_idx_va)
+			break;
+	}
+
+	if (level > ctx->base_level)
+		xlat_table_dec_regions_count(ctx, table_base);
+}
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+/*
+ * From the given arguments, it decides which action to take when mapping the
+ * specified region.
+ */
+static action_t xlat_tables_map_region_action(const mmap_region_t *mm,
+		unsigned int desc_type, unsigned long long dest_pa,
+		uintptr_t table_entry_base_va, unsigned int level)
+{
+	uintptr_t mm_end_va = mm->base_va + mm->size - 1U;
+	uintptr_t table_entry_end_va =
+			table_entry_base_va + XLAT_BLOCK_SIZE(level) - 1U;
+
+	/*
+	 * The descriptor types allowed depend on the current table level.
+	 */
+
+	if ((mm->base_va <= table_entry_base_va) &&
+	    (mm_end_va >= table_entry_end_va)) {
+
+		/*
+		 * Table entry is covered by region
+		 * --------------------------------
+		 *
+		 * This means that this table entry can describe the whole
+		 * translation with this granularity in principle.
+		 */
+
+		if (level == 3U) {
+			/*
+			 * Last level, only page descriptors are allowed.
+			 */
+			if (desc_type == PAGE_DESC) {
+				/*
+				 * There's another region mapped here, don't
+				 * overwrite.
+				 */
+				return ACTION_NONE;
+			} else {
+				assert(desc_type == INVALID_DESC);
+				return ACTION_WRITE_BLOCK_ENTRY;
+			}
+
+		} else {
+
+			/*
+			 * Other levels. Table descriptors are allowed. Block
+			 * descriptors too, but they have some limitations.
+			 */
+
+			if (desc_type == TABLE_DESC) {
+				/* There's already a table, recurse into it. */
+				return ACTION_RECURSE_INTO_TABLE;
+
+			} else if (desc_type == INVALID_DESC) {
+				/*
+				 * There's nothing mapped here, create a new
+				 * entry.
+				 *
+				 * Check if the destination granularity allows
+				 * us to use a block descriptor or we need a
+				 * finer table for it.
+				 *
+				 * Also, check if the current level allows block
+				 * descriptors. If not, create a table instead.
+				 */
+				if (((dest_pa & XLAT_BLOCK_MASK(level)) != 0U)
+				    || (level < MIN_LVL_BLOCK_DESC) ||
+				    (mm->granularity < XLAT_BLOCK_SIZE(level)))
+					return ACTION_CREATE_NEW_TABLE;
+				else
+					return ACTION_WRITE_BLOCK_ENTRY;
+
+			} else {
+				/*
+				 * There's another region mapped here, don't
+				 * overwrite.
+				 */
+				assert(desc_type == BLOCK_DESC);
+
+				return ACTION_NONE;
+			}
+		}
+
+	} else if ((mm->base_va <= table_entry_end_va) ||
+		   (mm_end_va >= table_entry_base_va)) {
+
+		/*
+		 * Region partially covers table entry
+		 * -----------------------------------
+		 *
+		 * This means that this table entry can't describe the whole
+		 * translation, a finer table is needed.
+
+		 * There cannot be partial block overlaps in level 3. If that
+		 * happens, some of the preliminary checks when adding the
+		 * mmap region failed to detect that PA and VA must at least be
+		 * aligned to PAGE_SIZE.
+		 */
+		assert(level < 3U);
+
+		if (desc_type == INVALID_DESC) {
+			/*
+			 * The block is not fully covered by the region. Create
+			 * a new table, recurse into it and try to map the
+			 * region with finer granularity.
+			 */
+			return ACTION_CREATE_NEW_TABLE;
+
+		} else {
+			assert(desc_type == TABLE_DESC);
+			/*
+			 * The block is not fully covered by the region, but
+			 * there is already a table here. Recurse into it and
+			 * try to map with finer granularity.
+			 *
+			 * PAGE_DESC for level 3 has the same value as
+			 * TABLE_DESC, but this code can't run on a level 3
+			 * table because there can't be overlaps in level 3.
+			 */
+			return ACTION_RECURSE_INTO_TABLE;
+		}
+	} else {
+
+		/*
+		 * This table entry is outside of the region specified in the
+		 * arguments, don't write anything to it.
+		 */
+		return ACTION_NONE;
+	}
+}
+
+/*
+ * Recursive function that writes to the translation tables and maps the
+ * specified region. On success, it returns the VA of the last byte that was
+ * successfully mapped. On error, it returns the VA of the next entry that
+ * should have been mapped.
+ */
+static uintptr_t xlat_tables_map_region(xlat_ctx_t *ctx, mmap_region_t *mm,
+				   uintptr_t table_base_va,
+				   uint64_t *const table_base,
+				   unsigned int table_entries,
+				   unsigned int level)
+{
+	assert((level >= ctx->base_level) && (level <= XLAT_TABLE_LEVEL_MAX));
+
+	uintptr_t mm_end_va = mm->base_va + mm->size - 1U;
+
+	uintptr_t table_idx_va;
+	unsigned long long table_idx_pa;
+
+	uint64_t *subtable;
+	uint64_t desc;
+
+	unsigned int table_idx;
+
+	table_idx_va = xlat_tables_find_start_va(mm, table_base_va, level);
+	table_idx = xlat_tables_va_to_index(table_base_va, table_idx_va, level);
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+	if (level > ctx->base_level)
+		xlat_table_inc_regions_count(ctx, table_base);
+#endif
+
+	while (table_idx < table_entries) {
+
+		desc = table_base[table_idx];
+
+		table_idx_pa = mm->base_pa + table_idx_va - mm->base_va;
+
+		action_t action = xlat_tables_map_region_action(mm,
+			(uint32_t)(desc & DESC_MASK), table_idx_pa,
+			table_idx_va, level);
+
+		if (action == ACTION_WRITE_BLOCK_ENTRY) {
+
+			table_base[table_idx] =
+				xlat_desc(ctx, (uint32_t)mm->attr, table_idx_pa,
+					  level);
+
+		} else if (action == ACTION_CREATE_NEW_TABLE) {
+			uintptr_t end_va;
+
+			subtable = xlat_table_get_empty(ctx);
+			if (subtable == NULL) {
+				/* Not enough free tables to map this region */
+				return table_idx_va;
+			}
+
+			/* Point to new subtable from this one. */
+			table_base[table_idx] = TABLE_DESC | (unsigned long)subtable;
+
+			/* Recurse to write into subtable */
+			end_va = xlat_tables_map_region(ctx, mm, table_idx_va,
+					       subtable, XLAT_TABLE_ENTRIES,
+					       level + 1U);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)subtable,
+				XLAT_TABLE_ENTRIES * sizeof(uint64_t));
+#endif
+			if (end_va !=
+				(table_idx_va + XLAT_BLOCK_SIZE(level) - 1U))
+				return end_va;
+
+		} else if (action == ACTION_RECURSE_INTO_TABLE) {
+			uintptr_t end_va;
+
+			subtable = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
+			/* Recurse to write into subtable */
+			end_va = xlat_tables_map_region(ctx, mm, table_idx_va,
+					       subtable, XLAT_TABLE_ENTRIES,
+					       level + 1U);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)subtable,
+				XLAT_TABLE_ENTRIES * sizeof(uint64_t));
+#endif
+			if (end_va !=
+				(table_idx_va + XLAT_BLOCK_SIZE(level) - 1U))
+				return end_va;
+
+		} else {
+
+			assert(action == ACTION_NONE);
+
+		}
+
+		table_idx++;
+		table_idx_va += XLAT_BLOCK_SIZE(level);
+
+		/* If reached the end of the region, exit */
+		if (mm_end_va <= table_idx_va)
+			break;
+	}
+
+	return table_idx_va - 1U;
+}
+
+/*
+ * Function that verifies that a region can be mapped.
+ * Returns:
+ *        0: Success, the mapping is allowed.
+ *   EINVAL: Invalid values were used as arguments.
+ *   ERANGE: The memory limits were surpassed.
+ *   ENOMEM: There is not enough memory in the mmap array.
+ *    EPERM: Region overlaps another one in an invalid way.
+ */
+static int mmap_add_region_check(const xlat_ctx_t *ctx, const mmap_region_t *mm)
+{
+	unsigned long long base_pa = mm->base_pa;
+	uintptr_t base_va = mm->base_va;
+	size_t size = mm->size;
+	size_t granularity = mm->granularity;
+
+	unsigned long long end_pa = base_pa + size - 1U;
+	uintptr_t end_va = base_va + size - 1U;
+
+	if (!IS_PAGE_ALIGNED(base_pa) || !IS_PAGE_ALIGNED(base_va) ||
+			!IS_PAGE_ALIGNED(size))
+		return -EINVAL;
+
+	if ((granularity != XLAT_BLOCK_SIZE(1U)) &&
+		(granularity != XLAT_BLOCK_SIZE(2U)) &&
+		(granularity != XLAT_BLOCK_SIZE(3U))) {
+		return -EINVAL;
+	}
+
+	/* Check for overflows */
+	if ((base_pa > end_pa) || (base_va > end_va))
+		return -ERANGE;
+
+	if ((base_va + (uintptr_t)size - (uintptr_t)1) > ctx->va_max_address)
+		return -ERANGE;
+
+	if ((base_pa + (unsigned long long)size - 1ULL) > ctx->pa_max_address)
+		return -ERANGE;
+
+	/* Check that there is space in the ctx->mmap array */
+	if (ctx->mmap[ctx->mmap_num - 1].size != 0U)
+		return -ENOMEM;
+
+	/* Check for PAs and VAs overlaps with all other regions */
+	for (const mmap_region_t *mm_cursor = ctx->mmap;
+	     mm_cursor->size != 0U; ++mm_cursor) {
+
+		uintptr_t mm_cursor_end_va = mm_cursor->base_va
+							+ mm_cursor->size - 1U;
+
+		/*
+		 * Check if one of the regions is completely inside the other
+		 * one.
+		 */
+		bool fully_overlapped_va =
+			((base_va >= mm_cursor->base_va) &&
+					(end_va <= mm_cursor_end_va)) ||
+			((mm_cursor->base_va >= base_va) &&
+						(mm_cursor_end_va <= end_va));
+
+		/*
+		 * Full VA overlaps are only allowed if both regions are
+		 * identity mapped (zero offset) or have the same VA to PA
+		 * offset. Also, make sure that it's not the exact same area.
+		 * This can only be done with static regions.
+		 */
+		if (fully_overlapped_va) {
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+			if (((mm->attr & MT_DYNAMIC) != 0U) ||
+			    ((mm_cursor->attr & MT_DYNAMIC) != 0U))
+				return -EPERM;
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+			if ((mm_cursor->base_va - mm_cursor->base_pa) !=
+							(base_va - base_pa))
+				return -EPERM;
+
+			if ((base_va == mm_cursor->base_va) &&
+						(size == mm_cursor->size))
+				return -EPERM;
+
+		} else {
+			/*
+			 * If the regions do not have fully overlapping VAs,
+			 * then they must have fully separated VAs and PAs.
+			 * Partial overlaps are not allowed
+			 */
+
+			unsigned long long mm_cursor_end_pa =
+				     mm_cursor->base_pa + mm_cursor->size - 1U;
+
+			bool separated_pa = (end_pa < mm_cursor->base_pa) ||
+				(base_pa > mm_cursor_end_pa);
+			bool separated_va = (end_va < mm_cursor->base_va) ||
+				(base_va > mm_cursor_end_va);
+
+			if (!separated_va || !separated_pa)
+				return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm)
+{
+	mmap_region_t *mm_cursor = ctx->mmap, *mm_destination;
+	const mmap_region_t *mm_end = ctx->mmap + ctx->mmap_num;
+	const mmap_region_t *mm_last;
+	unsigned long long end_pa = mm->base_pa + mm->size - 1U;
+	uintptr_t end_va = mm->base_va + mm->size - 1U;
+	int ret;
+
+	/* Ignore empty regions */
+	if (mm->size == 0U)
+		return;
+
+	/* Static regions must be added before initializing the xlat tables. */
+	assert(!ctx->initialized);
+
+	ret = mmap_add_region_check(ctx, mm);
+	if (ret != 0) {
+		ERROR("mmap_add_region_check() failed. error %d\n", ret);
+		assert(false);
+		return;
+	}
+
+	/*
+	 * Find correct place in mmap to insert new region.
+	 *
+	 * 1 - Lower region VA end first.
+	 * 2 - Smaller region size first.
+	 *
+	 * VA  0                                   0xFF
+	 *
+	 * 1st |------|
+	 * 2nd |------------|
+	 * 3rd                 |------|
+	 * 4th                            |---|
+	 * 5th                                   |---|
+	 * 6th                            |----------|
+	 * 7th |-------------------------------------|
+	 *
+	 * This is required for overlapping regions only. It simplifies adding
+	 * regions with the loop in xlat_tables_init_internal because the outer
+	 * ones won't overwrite block or page descriptors of regions added
+	 * previously.
+	 *
+	 * Overlapping is only allowed for static regions.
+	 */
+
+	while (((mm_cursor->base_va + mm_cursor->size - 1U) < end_va)
+	       && (mm_cursor->size != 0U)) {
+		++mm_cursor;
+	}
+
+	while (((mm_cursor->base_va + mm_cursor->size - 1U) == end_va) &&
+	       (mm_cursor->size != 0U) && (mm_cursor->size < mm->size)) {
+		++mm_cursor;
+	}
+
+	/*
+	 * Find the last entry marker in the mmap
+	 */
+	mm_last = ctx->mmap;
+	while ((mm_last->size != 0U) && (mm_last < mm_end)) {
+		++mm_last;
+	}
+
+	/*
+	 * Check if we have enough space in the memory mapping table.
+	 * This shouldn't happen as we have checked in mmap_add_region_check
+	 * that there is free space.
+	 */
+	assert(mm_last->size == 0U);
+
+	/* Make room for new region by moving other regions up by one place */
+	mm_destination = mm_cursor + 1;
+	(void)memmove(mm_destination, mm_cursor,
+		(uintptr_t)mm_last - (uintptr_t)mm_cursor);
+
+	/*
+	 * Check we haven't lost the empty sentinel from the end of the array.
+	 * This shouldn't happen as we have checked in mmap_add_region_check
+	 * that there is free space.
+	 */
+	assert(mm_end->size == 0U);
+
+	*mm_cursor = *mm;
+
+	if (end_pa > ctx->max_pa)
+		ctx->max_pa = end_pa;
+	if (end_va > ctx->max_va)
+		ctx->max_va = end_va;
+}
+
+/*
+ * Determine the table level closest to the initial lookup level that
+ * can describe this translation. Then, align base VA to the next block
+ * at the determined level.
+ */
+static void mmap_alloc_va_align_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
+{
+	/*
+	 * By or'ing the size and base PA the alignment will be the one
+	 * corresponding to the smallest boundary of the two of them.
+	 *
+	 * There are three different cases. For example (for 4 KiB page size):
+	 *
+	 * +--------------+------------------++--------------+
+	 * | PA alignment | Size multiple of || VA alignment |
+	 * +--------------+------------------++--------------+
+	 * |     2 MiB    |       2 MiB      ||     2 MiB    | (1)
+	 * |     2 MiB    |       4 KiB      ||     4 KiB    | (2)
+	 * |     4 KiB    |       2 MiB      ||     4 KiB    | (3)
+	 * +--------------+------------------++--------------+
+	 *
+	 * - In (1), it is possible to take advantage of the alignment of the PA
+	 *   and the size of the region to use a level 2 translation table
+	 *   instead of a level 3 one.
+	 *
+	 * - In (2), the size is smaller than a block entry of level 2, so it is
+	 *   needed to use a level 3 table to describe the region or the library
+	 *   will map more memory than the desired one.
+	 *
+	 * - In (3), even though the region has the size of one level 2 block
+	 *   entry, it isn't possible to describe the translation with a level 2
+	 *   block entry because of the alignment of the base PA.
+	 *
+	 *   Only bits 47:21 of a level 2 block descriptor are used by the MMU,
+	 *   bits 20:0 of the resulting address are 0 in this case. Because of
+	 *   this, the PA generated as result of this translation is aligned to
+	 *   2 MiB. The PA that was requested to be mapped is aligned to 4 KiB,
+	 *   though, which means that the resulting translation is incorrect.
+	 *   The only way to prevent this is by using a finer granularity.
+	 */
+	unsigned long long align_check;
+
+	align_check = mm->base_pa | (unsigned long long)mm->size;
+
+	/*
+	 * Assume it is always aligned to level 3. There's no need to check that
+	 * level because its block size is PAGE_SIZE. The checks to verify that
+	 * the addresses and size are aligned to PAGE_SIZE are inside
+	 * mmap_add_region.
+	 */
+	for (unsigned int level = ctx->base_level; level <= 2U; ++level) {
+
+		if ((align_check & XLAT_BLOCK_MASK(level)) != 0U)
+			continue;
+
+		mm->base_va = round_up(mm->base_va, XLAT_BLOCK_SIZE(level));
+		return;
+	}
+}
+
+void mmap_add_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
+{
+	mm->base_va = ctx->max_va + 1UL;
+
+	assert(mm->size > 0U);
+
+	mmap_alloc_va_align_ctx(ctx, mm);
+
+	/* Detect overflows. More checks are done in mmap_add_region_check(). */
+	assert(mm->base_va > ctx->max_va);
+
+	mmap_add_region_ctx(ctx, mm);
+}
+
+void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm)
+{
+	const mmap_region_t *mm_cursor = mm;
+
+	while (mm_cursor->granularity != 0U) {
+		mmap_add_region_ctx(ctx, mm_cursor);
+		mm_cursor++;
+	}
+}
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+
+int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
+{
+	mmap_region_t *mm_cursor = ctx->mmap;
+	const mmap_region_t *mm_last = mm_cursor + ctx->mmap_num;
+	unsigned long long end_pa = mm->base_pa + mm->size - 1U;
+	uintptr_t end_va = mm->base_va + mm->size - 1U;
+	int ret;
+
+	/* Nothing to do */
+	if (mm->size == 0U)
+		return 0;
+
+	/* Now this region is a dynamic one */
+	mm->attr |= MT_DYNAMIC;
+
+	ret = mmap_add_region_check(ctx, mm);
+	if (ret != 0)
+		return ret;
+
+	/*
+	 * Find the adequate entry in the mmap array in the same way done for
+	 * static regions in mmap_add_region_ctx().
+	 */
+
+	while (((mm_cursor->base_va + mm_cursor->size - 1U) < end_va)
+	       && (mm_cursor->size != 0U)) {
+		++mm_cursor;
+	}
+
+	while (((mm_cursor->base_va + mm_cursor->size - 1U) == end_va) &&
+	       (mm_cursor->size != 0U) && (mm_cursor->size < mm->size)) {
+		++mm_cursor;
+	}
+
+	/* Make room for new region by moving other regions up by one place */
+	(void)memmove(mm_cursor + 1U, mm_cursor,
+		     (uintptr_t)mm_last - (uintptr_t)mm_cursor);
+
+	/*
+	 * Check we haven't lost the empty sentinal from the end of the array.
+	 * This shouldn't happen as we have checked in mmap_add_region_check
+	 * that there is free space.
+	 */
+	assert(mm_last->size == 0U);
+
+	*mm_cursor = *mm;
+
+	/*
+	 * Update the translation tables if the xlat tables are initialized. If
+	 * not, this region will be mapped when they are initialized.
+	 */
+	if (ctx->initialized) {
+		end_va = xlat_tables_map_region(ctx, mm_cursor,
+				0U, ctx->base_table, ctx->base_table_entries,
+				ctx->base_level);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+				   ctx->base_table_entries * sizeof(uint64_t));
+#endif
+		/* Failed to map, remove mmap entry, unmap and return error. */
+		if (end_va != (mm_cursor->base_va + mm_cursor->size - 1U)) {
+			(void)memmove(mm_cursor, mm_cursor + 1U,
+				(uintptr_t)mm_last - (uintptr_t)mm_cursor);
+
+			/*
+			 * Check if the mapping function actually managed to map
+			 * anything. If not, just return now.
+			 */
+			if (mm->base_va >= end_va)
+				return -ENOMEM;
+
+			/*
+			 * Something went wrong after mapping some table
+			 * entries, undo every change done up to this point.
+			 */
+			mmap_region_t unmap_mm = {
+					.base_pa = 0U,
+					.base_va = mm->base_va,
+					.size = end_va - mm->base_va,
+					.attr = 0U
+			};
+			xlat_tables_unmap_region(ctx, &unmap_mm, 0U,
+				ctx->base_table, ctx->base_table_entries,
+				ctx->base_level);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+			xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+				ctx->base_table_entries * sizeof(uint64_t));
+#endif
+			return -ENOMEM;
+		}
+
+		/*
+		 * Make sure that all entries are written to the memory. There
+		 * is no need to invalidate entries when mapping dynamic regions
+		 * because new table/block/page descriptors only replace old
+		 * invalid descriptors, that aren't TLB cached.
+		 */
+		dsbishst();
+	}
+
+	if (end_pa > ctx->max_pa)
+		ctx->max_pa = end_pa;
+	if (end_va > ctx->max_va)
+		ctx->max_va = end_va;
+
+	return 0;
+}
+
+int mmap_add_dynamic_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm)
+{
+	mm->base_va = ctx->max_va + 1UL;
+
+	if (mm->size == 0U)
+		return 0;
+
+	mmap_alloc_va_align_ctx(ctx, mm);
+
+	/* Detect overflows. More checks are done in mmap_add_region_check(). */
+	if (mm->base_va < ctx->max_va) {
+		return -ENOMEM;
+	}
+
+	return mmap_add_dynamic_region_ctx(ctx, mm);
+}
+
+/*
+ * Removes the region with given base Virtual Address and size from the given
+ * context.
+ *
+ * Returns:
+ *        0: Success.
+ *   EINVAL: Invalid values were used as arguments (region not found).
+ *    EPERM: Tried to remove a static region.
+ */
+int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, uintptr_t base_va,
+				   size_t size)
+{
+	mmap_region_t *mm = ctx->mmap;
+	const mmap_region_t *mm_last = mm + ctx->mmap_num;
+	int update_max_va_needed = 0;
+	int update_max_pa_needed = 0;
+
+	/* Check sanity of mmap array. */
+	assert(mm[ctx->mmap_num].size == 0U);
+
+	while (mm->size != 0U) {
+		if ((mm->base_va == base_va) && (mm->size == size))
+			break;
+		++mm;
+	}
+
+	/* Check that the region was found */
+	if (mm->size == 0U)
+		return -EINVAL;
+
+	/* If the region is static it can't be removed */
+	if ((mm->attr & MT_DYNAMIC) == 0U)
+		return -EPERM;
+
+	/* Check if this region is using the top VAs or PAs. */
+	if ((mm->base_va + mm->size - 1U) == ctx->max_va)
+		update_max_va_needed = 1;
+	if ((mm->base_pa + mm->size - 1U) == ctx->max_pa)
+		update_max_pa_needed = 1;
+
+	/* Update the translation tables if needed */
+	if (ctx->initialized) {
+		xlat_tables_unmap_region(ctx, mm, 0U, ctx->base_table,
+					 ctx->base_table_entries,
+					 ctx->base_level);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+			ctx->base_table_entries * sizeof(uint64_t));
+#endif
+		xlat_arch_tlbi_va_sync();
+	}
+
+	/* Remove this region by moving the rest down by one place. */
+	(void)memmove(mm, mm + 1U, (uintptr_t)mm_last - (uintptr_t)mm);
+
+	/* Check if we need to update the max VAs and PAs */
+	if (update_max_va_needed == 1) {
+		ctx->max_va = 0U;
+		mm = ctx->mmap;
+		while (mm->size != 0U) {
+			if ((mm->base_va + mm->size - 1U) > ctx->max_va)
+				ctx->max_va = mm->base_va + mm->size - 1U;
+			++mm;
+		}
+	}
+
+	if (update_max_pa_needed == 1) {
+		ctx->max_pa = 0U;
+		mm = ctx->mmap;
+		while (mm->size != 0U) {
+			if ((mm->base_pa + mm->size - 1U) > ctx->max_pa)
+				ctx->max_pa = mm->base_pa + mm->size - 1U;
+			++mm;
+		}
+	}
+
+	return 0;
+}
+
+void xlat_setup_dynamic_ctx(xlat_ctx_t *ctx, unsigned long long pa_max,
+			    uintptr_t va_max, struct mmap_region *mmap,
+			    unsigned int mmap_num, uint64_t **tables,
+			    unsigned int tables_num, uint64_t *base_table,
+			    int xlat_regime, int *mapped_regions)
+{
+	ctx->xlat_regime = xlat_regime;
+
+	ctx->pa_max_address = pa_max;
+	ctx->va_max_address = va_max;
+
+	ctx->mmap = mmap;
+	ctx->mmap_num = mmap_num;
+	memset(ctx->mmap, 0, sizeof(struct mmap_region) * mmap_num);
+
+	ctx->tables = (void *) tables;
+	ctx->tables_num = tables_num;
+
+	uintptr_t va_space_size = va_max + 1;
+	ctx->base_level = GET_XLAT_TABLE_LEVEL_BASE(va_space_size);
+	ctx->base_table = base_table;
+	ctx->base_table_entries = GET_NUM_BASE_LEVEL_ENTRIES(va_space_size);
+
+	ctx->tables_mapped_regions = mapped_regions;
+
+	ctx->max_pa = 0;
+	ctx->max_va = 0;
+	ctx->initialized = 0;
+}
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+void __init init_xlat_tables_ctx(xlat_ctx_t *ctx)
+{
+	assert(ctx != NULL);
+	assert(!ctx->initialized);
+	assert((ctx->xlat_regime == EL3_REGIME) ||
+	       (ctx->xlat_regime == EL2_REGIME) ||
+	       (ctx->xlat_regime == EL1_EL0_REGIME));
+	assert(!is_mmu_enabled_ctx(ctx));
+
+	mmap_region_t *mm = ctx->mmap;
+
+	assert(ctx->va_max_address >=
+		(xlat_get_min_virt_addr_space_size() - 1U));
+	assert(ctx->va_max_address <= (MAX_VIRT_ADDR_SPACE_SIZE - 1U));
+	assert(IS_POWER_OF_TWO(ctx->va_max_address + 1U));
+
+	xlat_mmap_print(mm);
+
+	/* All tables must be zeroed before mapping any region. */
+
+	for (unsigned int i = 0U; i < ctx->base_table_entries; i++)
+		ctx->base_table[i] = INVALID_DESC;
+
+	for (int j = 0; j < ctx->tables_num; j++) {
+#if PLAT_XLAT_TABLES_DYNAMIC
+		ctx->tables_mapped_regions[j] = 0;
+#endif
+		for (unsigned int i = 0U; i < XLAT_TABLE_ENTRIES; i++)
+			ctx->tables[j][i] = INVALID_DESC;
+	}
+
+	while (mm->size != 0U) {
+		uintptr_t end_va = xlat_tables_map_region(ctx, mm, 0U,
+				ctx->base_table, ctx->base_table_entries,
+				ctx->base_level);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		xlat_clean_dcache_range((uintptr_t)ctx->base_table,
+				   ctx->base_table_entries * sizeof(uint64_t));
+#endif
+		if (end_va != (mm->base_va + mm->size - 1U)) {
+			ERROR("Not enough memory to map region:\n"
+			      " VA:0x%lx  PA:0x%llx  size:0x%zx  attr:0x%x\n",
+			      mm->base_va, mm->base_pa, mm->size, mm->attr);
+			panic();
+		}
+
+		mm++;
+	}
+
+	assert(ctx->pa_max_address <= xlat_arch_get_max_supported_pa());
+	assert(ctx->max_va <= ctx->va_max_address);
+	assert(ctx->max_pa <= ctx->pa_max_address);
+
+	ctx->initialized = true;
+
+	xlat_tables_print(ctx);
+}
diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h
new file mode 100644
index 0000000..70ef395
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_private.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef XLAT_TABLES_PRIVATE_H
+#define XLAT_TABLES_PRIVATE_H
+
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+/*
+ * Private shifts and masks to access fields of an mmap attribute
+ */
+/* Dynamic or static */
+#define MT_DYN_SHIFT		U(31)
+
+/*
+ * Memory mapping private attributes
+ *
+ * Private attributes not exposed in the public header.
+ */
+
+/*
+ * Regions mapped before the MMU can't be unmapped dynamically (they are
+ * static) and regions mapped with MMU enabled can be unmapped. This
+ * behaviour can't be overridden.
+ *
+ * Static regions can overlap each other, dynamic regions can't.
+ */
+#define MT_STATIC	(U(0) << MT_DYN_SHIFT)
+#define MT_DYNAMIC	(U(1) << MT_DYN_SHIFT)
+
+#endif /* PLAT_XLAT_TABLES_DYNAMIC */
+
+extern uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
+
+/*
+ * Return the execute-never mask that will prevent instruction fetch at the
+ * given translation regime.
+ */
+uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime);
+
+/*
+ * Invalidate all TLB entries that match the given virtual address. This
+ * operation applies to all PEs in the same Inner Shareable domain as the PE
+ * that executes this function. This functions must be called for every
+ * translation table entry that is modified. It only affects the specified
+ * translation regime.
+ *
+ * Note, however, that it is architecturally UNDEFINED to invalidate TLB entries
+ * pertaining to a higher exception level, e.g. invalidating EL3 entries from
+ * S-EL1.
+ */
+void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime);
+
+/*
+ * This function has to be called at the end of any code that uses the function
+ * xlat_arch_tlbi_va().
+ */
+void xlat_arch_tlbi_va_sync(void);
+
+/* Print VA, PA, size and attributes of all regions in the mmap array. */
+void xlat_mmap_print(const mmap_region_t *mmap);
+
+/*
+ * Print the current state of the translation tables by reading them from
+ * memory.
+ */
+void xlat_tables_print(xlat_ctx_t *ctx);
+
+/*
+ * Returns a block/page table descriptor for the given level and attributes.
+ */
+uint64_t xlat_desc(const xlat_ctx_t *ctx, uint32_t attr,
+		   unsigned long long addr_pa, unsigned int level);
+
+/*
+ * Architecture-specific initialization code.
+ */
+
+/* Returns the current Exception Level. The returned EL must be 1 or higher. */
+unsigned int xlat_arch_current_el(void);
+
+/*
+ * Return the maximum physical address supported by the hardware.
+ * This value depends on the execution state (AArch32/AArch64).
+ */
+unsigned long long xlat_arch_get_max_supported_pa(void);
+
+/*
+ * Returns true if the MMU of the translation regime managed by the given
+ * xlat_ctx_t is enabled, false otherwise.
+ */
+bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx);
+
+/* Returns true if the data cache is enabled at the current EL. */
+bool is_dcache_enabled(void);
+
+/*
+ * Returns minimum virtual address space size supported by the architecture
+ */
+uintptr_t xlat_get_min_virt_addr_space_size(void);
+
+#endif /* XLAT_TABLES_PRIVATE_H */
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
new file mode 100644
index 0000000..232142e
--- /dev/null
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "xlat_tables_private.h"
+
+#if LOG_LEVEL < LOG_LEVEL_VERBOSE
+
+void xlat_mmap_print(__unused const mmap_region_t *mmap)
+{
+	/* Empty */
+}
+
+void xlat_tables_print(__unused xlat_ctx_t *ctx)
+{
+	/* Empty */
+}
+
+#else /* if LOG_LEVEL >= LOG_LEVEL_VERBOSE */
+
+void xlat_mmap_print(const mmap_region_t *mmap)
+{
+	printf("mmap:\n");
+	const mmap_region_t *mm = mmap;
+
+	while (mm->size != 0U) {
+		printf(" VA:0x%lx  PA:0x%llx  size:0x%zx  attr:0x%x  granularity:0x%zx\n",
+		       mm->base_va, mm->base_pa, mm->size, mm->attr,
+		       mm->granularity);
+		++mm;
+	};
+	printf("\n");
+}
+
+/* Print the attributes of the specified block descriptor. */
+static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_t desc)
+{
+	uint64_t mem_type_index = ATTR_INDEX_GET(desc);
+	int xlat_regime = ctx->xlat_regime;
+
+	if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {
+		printf("MEM");
+	} else if (mem_type_index == ATTR_NON_CACHEABLE_INDEX) {
+		printf("NC");
+	} else {
+		assert(mem_type_index == ATTR_DEVICE_INDEX);
+		printf("DEV");
+	}
+
+	if ((xlat_regime == EL3_REGIME) || (xlat_regime == EL2_REGIME)) {
+		/* For EL3 and EL2 only check the AP[2] and XN bits. */
+		printf(((desc & LOWER_ATTRS(AP_RO)) != 0ULL) ? "-RO" : "-RW");
+		printf(((desc & UPPER_ATTRS(XN)) != 0ULL) ? "-XN" : "-EXEC");
+	} else {
+		assert(xlat_regime == EL1_EL0_REGIME);
+		/*
+		 * For EL0 and EL1:
+		 * - In AArch64 PXN and UXN can be set independently but in
+		 *   AArch32 there is no UXN (XN affects both privilege levels).
+		 *   For consistency, we set them simultaneously in both cases.
+		 * - RO and RW permissions must be the same in EL1 and EL0. If
+		 *   EL0 can access that memory region, so can EL1, with the
+		 *   same permissions.
+		 */
+#if ENABLE_ASSERTIONS
+		uint64_t xn_mask = xlat_arch_regime_get_xn_desc(EL1_EL0_REGIME);
+		uint64_t xn_perm = desc & xn_mask;
+
+		assert((xn_perm == xn_mask) || (xn_perm == 0ULL));
+#endif
+		printf(((desc & LOWER_ATTRS(AP_RO)) != 0ULL) ? "-RO" : "-RW");
+		/* Only check one of PXN and UXN, the other one is the same. */
+		printf(((desc & UPPER_ATTRS(PXN)) != 0ULL) ? "-XN" : "-EXEC");
+		/*
+		 * Privileged regions can only be accessed from EL1, user
+		 * regions can be accessed from EL1 and EL0.
+		 */
+		printf(((desc & LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED)) != 0ULL)
+			  ? "-USER" : "-PRIV");
+	}
+
+	printf(((LOWER_ATTRS(NS) & desc) != 0ULL) ? "-NS" : "-S");
+
+#ifdef __aarch64__
+	/* Check Guarded Page bit */
+	if ((desc & GP) != 0ULL) {
+		printf("-GP");
+	}
+#endif
+}
+
+static const char * const level_spacers[] = {
+	"[LV0] ",
+	"  [LV1] ",
+	"    [LV2] ",
+	"      [LV3] "
+};
+
+static const char *invalid_descriptors_ommited =
+		"%s(%d invalid descriptors omitted)\n";
+
+/*
+ * Recursive function that reads the translation tables passed as an argument
+ * and prints their status.
+ */
+static void xlat_tables_print_internal(xlat_ctx_t *ctx, uintptr_t table_base_va,
+		const uint64_t *table_base, unsigned int table_entries,
+		unsigned int level)
+{
+	assert(level <= XLAT_TABLE_LEVEL_MAX);
+
+	uint64_t desc;
+	uintptr_t table_idx_va = table_base_va;
+	unsigned int table_idx = 0U;
+	size_t level_size = XLAT_BLOCK_SIZE(level);
+
+	/*
+	 * Keep track of how many invalid descriptors are counted in a row.
+	 * Whenever multiple invalid descriptors are found, only the first one
+	 * is printed, and a line is added to inform about how many descriptors
+	 * have been omitted.
+	 */
+	int invalid_row_count = 0;
+
+	while (table_idx < table_entries) {
+
+		desc = table_base[table_idx];
+
+		if ((desc & DESC_MASK) == INVALID_DESC) {
+
+			if (invalid_row_count == 0) {
+				printf("%sVA:0x%lx size:0x%zx\n",
+				       level_spacers[level],
+				       table_idx_va, level_size);
+			}
+			invalid_row_count++;
+
+		} else {
+
+			if (invalid_row_count > 1) {
+				printf(invalid_descriptors_ommited,
+				       level_spacers[level],
+				       invalid_row_count - 1);
+			}
+			invalid_row_count = 0;
+
+			/*
+			 * Check if this is a table or a block. Tables are only
+			 * allowed in levels other than 3, but DESC_PAGE has the
+			 * same value as DESC_TABLE, so we need to check.
+			 */
+			if (((desc & DESC_MASK) == TABLE_DESC) &&
+					(level < XLAT_TABLE_LEVEL_MAX)) {
+				/*
+				 * Do not print any PA for a table descriptor,
+				 * as it doesn't directly map physical memory
+				 * but instead points to the next translation
+				 * table in the translation table walk.
+				 */
+				printf("%sVA:0x%lx size:0x%zx\n",
+				       level_spacers[level],
+				       table_idx_va, level_size);
+
+				uintptr_t addr_inner = desc & TABLE_ADDR_MASK;
+
+				xlat_tables_print_internal(ctx, table_idx_va,
+					(uint64_t *)addr_inner,
+					XLAT_TABLE_ENTRIES, level + 1U);
+			} else {
+				printf("%sVA:0x%lx PA:0x%llx size:0x%zx ",
+				       level_spacers[level], table_idx_va,
+				       (uint64_t)(desc & TABLE_ADDR_MASK),
+				       level_size);
+				xlat_desc_print(ctx, desc);
+				printf("\n");
+			}
+		}
+
+		table_idx++;
+		table_idx_va += level_size;
+	}
+
+	if (invalid_row_count > 1) {
+		printf(invalid_descriptors_ommited,
+		       level_spacers[level], invalid_row_count - 1);
+	}
+}
+
+void xlat_tables_print(xlat_ctx_t *ctx)
+{
+	const char *xlat_regime_str;
+	int used_page_tables;
+
+	if (ctx->xlat_regime == EL1_EL0_REGIME) {
+		xlat_regime_str = "1&0";
+	} else if (ctx->xlat_regime == EL2_REGIME) {
+		xlat_regime_str = "2";
+	} else {
+		assert(ctx->xlat_regime == EL3_REGIME);
+		xlat_regime_str = "3";
+	}
+	VERBOSE("Translation tables state:\n");
+	VERBOSE("  Xlat regime:     EL%s\n", xlat_regime_str);
+	VERBOSE("  Max allowed PA:  0x%llx\n", ctx->pa_max_address);
+	VERBOSE("  Max allowed VA:  0x%lx\n", ctx->va_max_address);
+	VERBOSE("  Max mapped PA:   0x%llx\n", ctx->max_pa);
+	VERBOSE("  Max mapped VA:   0x%lx\n", ctx->max_va);
+
+	VERBOSE("  Initial lookup level: %u\n", ctx->base_level);
+	VERBOSE("  Entries @initial lookup level: %u\n",
+		ctx->base_table_entries);
+
+#if PLAT_XLAT_TABLES_DYNAMIC
+	used_page_tables = 0;
+	for (int i = 0; i < ctx->tables_num; ++i) {
+		if (ctx->tables_mapped_regions[i] != 0)
+			++used_page_tables;
+	}
+#else
+	used_page_tables = ctx->next_table;
+#endif
+	VERBOSE("  Used %d sub-tables out of %d (spare: %d)\n",
+		used_page_tables, ctx->tables_num,
+		ctx->tables_num - used_page_tables);
+
+	xlat_tables_print_internal(ctx, 0U, ctx->base_table,
+				   ctx->base_table_entries, ctx->base_level);
+}
+
+#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
+
+/*
+ * Do a translation table walk to find the block or page descriptor that maps
+ * virtual_addr.
+ *
+ * On success, return the address of the descriptor within the translation
+ * table. Its lookup level is stored in '*out_level'.
+ * On error, return NULL.
+ *
+ * xlat_table_base
+ *   Base address for the initial lookup level.
+ * xlat_table_base_entries
+ *   Number of entries in the translation table for the initial lookup level.
+ * virt_addr_space_size
+ *   Size in bytes of the virtual address space.
+ */
+static uint64_t *find_xlat_table_entry(uintptr_t virtual_addr,
+				       void *xlat_table_base,
+				       unsigned int xlat_table_base_entries,
+				       unsigned long long virt_addr_space_size,
+				       unsigned int *out_level)
+{
+	unsigned int start_level;
+	uint64_t *table;
+	unsigned int entries;
+
+	start_level = GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size);
+
+	table = xlat_table_base;
+	entries = xlat_table_base_entries;
+
+	for (unsigned int level = start_level;
+	     level <= XLAT_TABLE_LEVEL_MAX;
+	     ++level) {
+		uint64_t idx, desc, desc_type;
+
+		idx = XLAT_TABLE_IDX(virtual_addr, level);
+		if (idx >= entries) {
+			WARN("Missing xlat table entry at address 0x%lx\n",
+			     virtual_addr);
+			return NULL;
+		}
+
+		desc = table[idx];
+		desc_type = desc & DESC_MASK;
+
+		if (desc_type == INVALID_DESC) {
+			VERBOSE("Invalid entry (memory not mapped)\n");
+			return NULL;
+		}
+
+		if (level == XLAT_TABLE_LEVEL_MAX) {
+			/*
+			 * Only page descriptors allowed at the final lookup
+			 * level.
+			 */
+			assert(desc_type == PAGE_DESC);
+			*out_level = level;
+			return &table[idx];
+		}
+
+		if (desc_type == BLOCK_DESC) {
+			*out_level = level;
+			return &table[idx];
+		}
+
+		assert(desc_type == TABLE_DESC);
+		table = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
+		entries = XLAT_TABLE_ENTRIES;
+	}
+
+	/*
+	 * This shouldn't be reached, the translation table walk should end at
+	 * most at level XLAT_TABLE_LEVEL_MAX and return from inside the loop.
+	 */
+	assert(false);
+
+	return NULL;
+}
+
+
+static int xlat_get_mem_attributes_internal(const xlat_ctx_t *ctx,
+		uintptr_t base_va, uint32_t *attributes, uint64_t **table_entry,
+		unsigned long long *addr_pa, unsigned int *table_level)
+{
+	uint64_t *entry;
+	uint64_t desc;
+	unsigned int level;
+	unsigned long long virt_addr_space_size;
+
+	/*
+	 * Sanity-check arguments.
+	 */
+	assert(ctx != NULL);
+	assert(ctx->initialized);
+	assert((ctx->xlat_regime == EL1_EL0_REGIME) ||
+	       (ctx->xlat_regime == EL2_REGIME) ||
+	       (ctx->xlat_regime == EL3_REGIME));
+
+	virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1ULL;
+	assert(virt_addr_space_size > 0U);
+
+	entry = find_xlat_table_entry(base_va,
+				ctx->base_table,
+				ctx->base_table_entries,
+				virt_addr_space_size,
+				&level);
+	if (entry == NULL) {
+		WARN("Address 0x%lx is not mapped.\n", base_va);
+		return -EINVAL;
+	}
+
+	if (addr_pa != NULL) {
+		*addr_pa = *entry & TABLE_ADDR_MASK;
+	}
+
+	if (table_entry != NULL) {
+		*table_entry = entry;
+	}
+
+	if (table_level != NULL) {
+		*table_level = level;
+	}
+
+	desc = *entry;
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	VERBOSE("Attributes: ");
+	xlat_desc_print(ctx, desc);
+	printf("\n");
+#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
+
+	assert(attributes != NULL);
+	*attributes = 0U;
+
+	uint64_t attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
+
+	if (attr_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {
+		*attributes |= MT_MEMORY;
+	} else if (attr_index == ATTR_NON_CACHEABLE_INDEX) {
+		*attributes |= MT_NON_CACHEABLE;
+	} else {
+		assert(attr_index == ATTR_DEVICE_INDEX);
+		*attributes |= MT_DEVICE;
+	}
+
+	uint64_t ap2_bit = (desc >> AP2_SHIFT) & 1U;
+
+	if (ap2_bit == AP2_RW)
+		*attributes |= MT_RW;
+
+	if (ctx->xlat_regime == EL1_EL0_REGIME) {
+		uint64_t ap1_bit = (desc >> AP1_SHIFT) & 1U;
+
+		if (ap1_bit == AP1_ACCESS_UNPRIVILEGED)
+			*attributes |= MT_USER;
+	}
+
+	uint64_t ns_bit = (desc >> NS_SHIFT) & 1U;
+
+	if (ns_bit == 1U)
+		*attributes |= MT_NS;
+
+	uint64_t xn_mask = xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
+
+	if ((desc & xn_mask) == xn_mask) {
+		*attributes |= MT_EXECUTE_NEVER;
+	} else {
+		assert((desc & xn_mask) == 0U);
+	}
+
+	return 0;
+}
+
+
+int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				uint32_t *attr)
+{
+	return xlat_get_mem_attributes_internal(ctx, base_va, attr,
+				NULL, NULL, NULL);
+}
+
+
+int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va,
+				   size_t size, uint32_t attr)
+{
+	/* Note: This implementation isn't optimized. */
+
+	assert(ctx != NULL);
+	assert(ctx->initialized);
+
+	unsigned long long virt_addr_space_size =
+		(unsigned long long)ctx->va_max_address + 1U;
+	assert(virt_addr_space_size > 0U);
+
+	if (!IS_PAGE_ALIGNED(base_va)) {
+		WARN("%s: Address 0x%lx is not aligned on a page boundary.\n",
+		     __func__, base_va);
+		return -EINVAL;
+	}
+
+	if (size == 0U) {
+		WARN("%s: Size is 0.\n", __func__);
+		return -EINVAL;
+	}
+
+	if ((size % PAGE_SIZE) != 0U) {
+		WARN("%s: Size 0x%zx is not a multiple of a page size.\n",
+		     __func__, size);
+		return -EINVAL;
+	}
+
+	if (((attr & MT_EXECUTE_NEVER) == 0U) && ((attr & MT_RW) != 0U)) {
+		WARN("%s: Mapping memory as read-write and executable not allowed.\n",
+		     __func__);
+		return -EINVAL;
+	}
+
+	size_t pages_count = size / PAGE_SIZE;
+
+	VERBOSE("Changing memory attributes of %zu pages starting from address 0x%lx...\n",
+		pages_count, base_va);
+
+	uintptr_t base_va_original = base_va;
+
+	/*
+	 * Sanity checks.
+	 */
+	for (size_t i = 0U; i < pages_count; ++i) {
+		const uint64_t *entry;
+		uint64_t desc, attr_index;
+		unsigned int level;
+
+		entry = find_xlat_table_entry(base_va,
+					      ctx->base_table,
+					      ctx->base_table_entries,
+					      virt_addr_space_size,
+					      &level);
+		if (entry == NULL) {
+			WARN("Address 0x%lx is not mapped.\n", base_va);
+			return -EINVAL;
+		}
+
+		desc = *entry;
+
+		/*
+		 * Check that all the required pages are mapped at page
+		 * granularity.
+		 */
+		if (((desc & DESC_MASK) != PAGE_DESC) ||
+			(level != XLAT_TABLE_LEVEL_MAX)) {
+			WARN("Address 0x%lx is not mapped at the right granularity.\n",
+			     base_va);
+			WARN("Granularity is 0x%llx, should be 0x%x.\n",
+			     (unsigned long long)XLAT_BLOCK_SIZE(level), PAGE_SIZE);
+			return -EINVAL;
+		}
+
+		/*
+		 * If the region type is device, it shouldn't be executable.
+		 */
+		attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
+		if (attr_index == ATTR_DEVICE_INDEX) {
+			if ((attr & MT_EXECUTE_NEVER) == 0U) {
+				WARN("Setting device memory as executable at address 0x%lx.",
+				     base_va);
+				return -EINVAL;
+			}
+		}
+
+		base_va += PAGE_SIZE;
+	}
+
+	/* Restore original value. */
+	base_va = base_va_original;
+
+	for (unsigned int i = 0U; i < pages_count; ++i) {
+
+		uint32_t old_attr = 0U, new_attr;
+		uint64_t *entry = NULL;
+		unsigned int level = 0U;
+		unsigned long long addr_pa = 0ULL;
+
+		(void) xlat_get_mem_attributes_internal(ctx, base_va, &old_attr,
+					    &entry, &addr_pa, &level);
+
+		/*
+		 * From attr, only MT_RO/MT_RW, MT_EXECUTE/MT_EXECUTE_NEVER and
+		 * MT_USER/MT_PRIVILEGED are taken into account. Any other
+		 * information is ignored.
+		 */
+
+		/* Clean the old attributes so that they can be rebuilt. */
+		new_attr = old_attr & ~(MT_RW | MT_EXECUTE_NEVER | MT_USER);
+
+		/*
+		 * Update attributes, but filter out the ones this function
+		 * isn't allowed to change.
+		 */
+		new_attr |= attr & (MT_RW | MT_EXECUTE_NEVER | MT_USER);
+
+		/*
+		 * The break-before-make sequence requires writing an invalid
+		 * descriptor and making sure that the system sees the change
+		 * before writing the new descriptor.
+		 */
+		*entry = INVALID_DESC;
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		dccvac((uintptr_t)entry);
+#endif
+		/* Invalidate any cached copy of this mapping in the TLBs. */
+		xlat_arch_tlbi_va(base_va, ctx->xlat_regime);
+
+		/* Ensure completion of the invalidation. */
+		xlat_arch_tlbi_va_sync();
+
+		/* Write new descriptor */
+		*entry = xlat_desc(ctx, new_attr, addr_pa, level);
+#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
+		dccvac((uintptr_t)entry);
+#endif
+		base_va += PAGE_SIZE;
+	}
+
+	/* Ensure that the last descriptor writen is seen by the system. */
+	dsbish();
+
+	return 0;
+}
diff --git a/lib/zlib/tf_gunzip.c b/lib/zlib/tf_gunzip.c
new file mode 100644
index 0000000..fd56dfc
--- /dev/null
+++ b/lib/zlib/tf_gunzip.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <tf_gunzip.h>
+
+#include "zutil.h"
+
+/*
+ * memory allocated by malloc() is supposed to be aligned for any built-in type
+ */
+#define ZALLOC_ALIGNMENT	sizeof(void *)
+
+static uintptr_t zalloc_start;
+static uintptr_t zalloc_end;
+static uintptr_t zalloc_current;
+
+static void * ZLIB_INTERNAL zcalloc(void *opaque, unsigned int items,
+				    unsigned int size)
+{
+	uintptr_t p, p_end;
+
+	size *= items;
+
+	p = round_up(zalloc_current, ZALLOC_ALIGNMENT);
+	p_end = p + size;
+
+	if (p_end > zalloc_end)
+		return NULL;
+
+	memset((void *)p, 0, size);
+
+	zalloc_current = p_end;
+
+	return (void *)p;
+}
+
+static void ZLIB_INTERNAL zfree(void *opaque, void *ptr)
+{
+}
+
+/*
+ * gunzip - decompress gzip data
+ * @in_buf: source of compressed input. Upon exit, the end of input.
+ * @in_len: length of in_buf
+ * @out_buf: destination of decompressed output. Upon exit, the end of output.
+ * @out_len: length of out_buf
+ * @work_buf: workspace
+ * @work_len: length of workspace
+ */
+int gunzip(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf,
+	   size_t out_len, uintptr_t work_buf, size_t work_len)
+{
+	z_stream stream;
+	int zret, ret;
+
+	zalloc_start = work_buf;
+	zalloc_end = work_buf + work_len;
+	zalloc_current = zalloc_start;
+
+	stream.next_in = (typeof(stream.next_in))*in_buf;
+	stream.avail_in = in_len;
+	stream.next_out = (typeof(stream.next_out))*out_buf;
+	stream.avail_out = out_len;
+	stream.zalloc = zcalloc;
+	stream.zfree = zfree;
+	stream.opaque = (voidpf)0;
+
+	zret = inflateInit(&stream);
+	if (zret != Z_OK) {
+		ERROR("zlib: inflate init failed (ret = %d)\n", zret);
+		return (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO;
+	}
+
+	zret = inflate(&stream, Z_NO_FLUSH);
+	if (zret == Z_STREAM_END) {
+		ret = 0;
+	} else {
+		if (stream.msg)
+			ERROR("%s\n", stream.msg);
+		ERROR("zlib: inflate failed (ret = %d)\n", zret);
+		ret = (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO;
+	}
+
+	VERBOSE("zlib: %lu byte input\n", stream.total_in);
+	VERBOSE("zlib: %lu byte output\n", stream.total_out);
+
+	*in_buf = (uintptr_t)stream.next_in;
+	*out_buf = (uintptr_t)stream.next_out;
+
+	inflateEnd(&stream);
+
+	return ret;
+}
diff --git a/lib/zlib/zlib b/lib/zlib/zlib
new file mode 120000
index 0000000..b286462
--- /dev/null
+++ b/lib/zlib/zlib
@@ -0,0 +1 @@
+../../../zlib
\ No newline at end of file
diff --git a/lib/zlib/zlib.mk b/lib/zlib/zlib.mk
new file mode 100644
index 0000000..fda7766
--- /dev/null
+++ b/lib/zlib/zlib.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ZLIB_PATH	:=	lib/zlib
+
+# Imported from zlib 1.2.11 (do not modify them)
+ZLIB_SOURCES	:=	$(addprefix $(ZLIB_PATH)/zlib/,	\
+					adler32.c	\
+					crc32.c		\
+					inffast.c	\
+					inflate.c	\
+					inftrees.c	\
+					zutil.c)
+
+# Implemented for TF
+ZLIB_SOURCES	+=	$(addprefix $(ZLIB_PATH)/,	\
+					tf_gunzip.c)
+
+INCLUDES	+=	-Iinclude/lib/zlib
+
+# REVISIT: the following flags need not be given globally
+TF_CFLAGS	+=	-DZ_SOLO -DDEF_WBITS=31
diff --git a/license.rst b/license.rst
new file mode 100644
index 0000000..9743134
--- /dev/null
+++ b/license.rst
@@ -0,0 +1,38 @@
+Copyright (c) [XXXX-]YYYY, <OWNER>. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+-  Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+-  Redistributions in binary form must reproduce the above copyright notice, this
+   list of conditions and the following disclaimer in the documentation and/or
+   other materials provided with the distribution.
+
+-  Neither the name of Arm nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific prior
+   written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------
+
+.. note::
+   Individual files contain the following tag instead of the full license text.
+
+::
+
+    SPDX-License-Identifier:    BSD-3-Clause
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
diff --git a/make_helpers/armv7-a-cpus.mk b/make_helpers/armv7-a-cpus.mk
new file mode 100644
index 0000000..5571ab0
--- /dev/null
+++ b/make_helpers/armv7-a-cpus.mk
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch32)
+$(error ARM_ARCH_MAJOR=7 mandates ARCH=aarch32)
+endif
+
+# For ARMv7, set march32 from platform directive ARMV7_CORTEX_Ax=yes
+# and ARM_WITH_NEON=yes/no.
+#
+# GCC and Clang require -march=armv7-a for C-A9 and -march=armv7ve for C-A15.
+# armClang requires -march=armv7-a for all ARMv7 Cortex-A. To comply with
+# all, just drop -march and supply only -mcpu.
+
+# Platform can override march32-directive through MARCH32_DIRECTIVE
+ifdef MARCH32_DIRECTIVE
+march32-directive		:= $(MARCH32_DIRECTIVE)
+else
+march32-set-${ARM_CORTEX_A5}	:= -mcpu=cortex-a5
+march32-set-${ARM_CORTEX_A7}	:= -mcpu=cortex-a7
+march32-set-${ARM_CORTEX_A9}	:= -mcpu=cortex-a9
+march32-set-${ARM_CORTEX_A12}	:= -mcpu=cortex-a12
+march32-set-${ARM_CORTEX_A15}	:= -mcpu=cortex-a15
+march32-set-${ARM_CORTEX_A17}	:= -mcpu=cortex-a17
+march32-neon-$(ARM_WITH_NEON)	:= -mfpu=neon
+
+# default to -march=armv7-a as target directive
+march32-set-yes			?= -march=armv7-a
+march32-directive		:= ${march32-set-yes} ${march32-neon-yes}
+endif
+
+# Platform may override these extension support directives:
+#
+# ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING
+# Defined if core supports the Large Page Addressing extension.
+#
+# ARMV7_SUPPORTS_VIRTUALIZATION
+# Defined if ARMv7 core supports the Virtualization extension.
+#
+# ARMV7_SUPPORTS_GENERIC_TIMER
+# Defined if ARMv7 core supports the Generic Timer extension.
+
+ifeq ($(filter yes,$(ARM_CORTEX_A7) $(ARM_CORTEX_A12) $(ARM_CORTEX_A15) $(ARM_CORTEX_A17)),yes)
+$(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING))
+$(eval $(call add_define,ARMV7_SUPPORTS_VIRTUALIZATION))
+$(eval $(call add_define,ARMV7_SUPPORTS_GENERIC_TIMER))
+$(eval $(call add_define,ARMV7_SUPPORTS_VFP))
+endif
+
+ifeq ($(ARM_CORTEX_A5),yes)
+$(eval $(call add_define,ARM_CORTEX_A5))
+endif
diff --git a/make_helpers/build_env.mk b/make_helpers/build_env.mk
new file mode 100644
index 0000000..83093bd
--- /dev/null
+++ b/make_helpers/build_env.mk
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# This file contains the logic to identify and include any relevant
+# build environment specific make include files.
+
+ifndef BUILD_ENV_MK
+    BUILD_ENV_MK        :=      $(lastword $(MAKEFILE_LIST))
+
+    # Block possible built-in command definitions that are not fully portable.
+    # This traps occurences that need replacing with our OS portable macros
+    COPY                :=      $$(error "Replace COPY with call to SHELL_COPY or SHELL_COPY_TREE.")
+    CP                  :=      $$(error "Replace CP with call to SHELL_COPY or SHELL_COPY_TREE.")
+    DEL                 :=      $$(error "Replace DEL with call to SHELL_DELETE.")
+    MD                  :=      $$(error "Replace MD with call to MAKE_PREREQ_DIR.")
+    MKDIR               :=      $$(error "Replace MKDIR with call to MAKE_PREREQ_DIR.")
+    RD                  :=      $$(error "Replace RD with call to SHELL_REMOVE_DIR.")
+    RM                  :=      $$(error "Replace RM with call to SHELL_DELETE.")
+    RMDIR               :=      $$(error "Replace RMDIR with call to SHELL_REMOVE_DIR.")
+
+    ENV_FILE_TO_INCLUDE := unix.mk
+    ifdef OSTYPE
+        ifneq ($(findstring ${OSTYPE}, cygwin),)
+            ENV_FILE_TO_INCLUDE := cygwin.mk
+        else
+            ifneq ($(findstring ${OSTYPE}, MINGW32 mingw msys),)
+                ENV_FILE_TO_INCLUDE := msys.mk
+            endif
+        endif
+    else
+        ifdef MSYSTEM
+            # Although the MINGW MSYS shell sets OSTYPE as msys in its environment,
+            # it does not appear in the GNU make view of environment variables.
+            # We use MSYSTEM as an alternative, as that is seen by make
+            ifneq ($(findstring ${MSYSTEM}, MINGW32 mingw msys),)
+                OSTYPE ?= msys
+                ENV_FILE_TO_INCLUDE := msys.mk
+            endif
+        else
+            ifdef OS
+                ifneq ($(findstring ${OS}, Windows_NT),)
+                    ENV_FILE_TO_INCLUDE := windows.mk
+                endif
+            endif
+        endif
+    endif
+    include ${MAKE_HELPERS_DIRECTORY}${ENV_FILE_TO_INCLUDE}
+    ENV_FILE_TO_INCLUDE :=
+
+    ifndef SHELL_COPY
+        $(error "SHELL_COPY not defined for build environment.")
+    endif
+    ifndef SHELL_COPY_TREE
+        $(error "SHELL_COPY_TREE not defined for build environment.")
+    endif
+    ifndef SHELL_DELETE_ALL
+        $(error "SHELL_DELETE_ALL not defined for build environment.")
+    endif
+    ifndef SHELL_DELETE
+        $(error "SHELL_DELETE not defined for build environment.")
+    endif
+    ifndef MAKE_PREREQ_DIR
+        $(error "MAKE_PREREQ_DIR not defined for build environment.")
+    endif
+    ifndef SHELL_REMOVE_DIR
+        $(error "SHELL_REMOVE_DIR not defined for build environment.")
+    endif
+
+endif
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
new file mode 100644
index 0000000..b89d87e
--- /dev/null
+++ b/make_helpers/build_macros.mk
@@ -0,0 +1,532 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Report an error if the eval make function is not available.
+$(eval eval_available := T)
+ifneq (${eval_available},T)
+    $(error This makefile only works with a Make program that supports $$(eval))
+endif
+
+# Some utility macros for manipulating awkward (whitespace) characters.
+blank			:=
+space			:=${blank} ${blank}
+
+# A user defined function to recursively search for a filename below a directory
+#    $1 is the directory root of the recursive search (blank for current directory).
+#    $2 is the file name to search for.
+define rwildcard
+$(strip $(foreach d,$(wildcard ${1}*),$(call rwildcard,${d}/,${2}) $(filter $(subst *,%,%${2}),${d})))
+endef
+
+# This table is used in converting lower case to upper case.
+uppercase_table:=a,A b,B c,C d,D e,E f,F g,G h,H i,I j,J k,K l,L m,M n,N o,O p,P q,Q r,R s,S t,T u,U v,V w,W x,X y,Y z,Z
+
+# Internal macro used for converting lower case to upper case.
+#   $(1) = upper case table
+#   $(2) = String to convert
+define uppercase_internal
+$(if $(1),$$(subst $(firstword $(1)),$(call uppercase_internal,$(wordlist 2,$(words $(1)),$(1)),$(2))),$(2))
+endef
+
+# A macro for converting a string to upper case
+#   $(1) = String to convert
+define uppercase
+$(eval uppercase_result:=$(call uppercase_internal,$(uppercase_table),$(1)))$(uppercase_result)
+endef
+
+# Convenience function for adding build definitions
+# $(eval $(call add_define,FOO)) will have:
+# -DFOO if $(FOO) is empty; -DFOO=$(FOO) otherwise
+define add_define
+    DEFINES			+=	-D$(1)$(if $(value $(1)),=$(value $(1)),)
+endef
+
+# Convenience function for adding build definitions
+# $(eval $(call add_define_val,FOO,BAR)) will have:
+# -DFOO=BAR
+define add_define_val
+    DEFINES			+=	-D$(1)=$(2)
+endef
+
+# Convenience function for verifying option has a boolean value
+# $(eval $(call assert_boolean,FOO)) will assert FOO is 0 or 1
+define assert_boolean
+    $(if $(filter-out 0 1,$($1)),$(error $1 must be boolean))
+endef
+
+0-9 := 0 1 2 3 4 5 6 7 8 9
+
+# Function to verify that a given option $(1) contains a numeric value
+define assert_numeric
+$(if $($(1)),,$(error $(1) must not be empty))
+$(eval __numeric := $($(1)))
+$(foreach d,$(0-9),$(eval __numeric := $(subst $(d),,$(__numeric))))
+$(if $(__numeric),$(error $(1) must be numeric))
+endef
+
+# IMG_LINKERFILE defines the linker script corresponding to a BL stage
+#   $(1) = BL stage (2, 30, 31, 32, 33)
+define IMG_LINKERFILE
+    ${BUILD_DIR}/bl$(1).ld
+endef
+
+# IMG_MAPFILE defines the output file describing the memory map corresponding
+# to a BL stage
+#   $(1) = BL stage (2, 30, 31, 32, 33)
+define IMG_MAPFILE
+    ${BUILD_DIR}/bl$(1).map
+endef
+
+# IMG_ELF defines the elf file corresponding to a BL stage
+#   $(1) = BL stage (2, 30, 31, 32, 33)
+define IMG_ELF
+    ${BUILD_DIR}/bl$(1).elf
+endef
+
+# IMG_DUMP defines the symbols dump file corresponding to a BL stage
+#   $(1) = BL stage (2, 30, 31, 32, 33)
+define IMG_DUMP
+    ${BUILD_DIR}/bl$(1).dump
+endef
+
+# IMG_BIN defines the default image file corresponding to a BL stage
+#   $(1) = BL stage (2, 30, 31, 32, 33)
+define IMG_BIN
+    ${BUILD_PLAT}/bl$(1).bin
+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
+#   $(1) = payload filename (i.e. bl31.bin)
+#   $(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)
+define TOOL_ADD_PAYLOAD
+    $(4)FIP_ARGS += $(2) $(1)
+    $(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
+# before passing them to host tools if BL*_PRE_TOOL_FILTER is defined.
+#   $(1) = image_type (scp_bl2, bl33, etc.)
+#   $(2) = payload filepath (ex. build/fvp/release/bl31.bin)
+#   $(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)
+
+define TOOL_ADD_IMG_PAYLOAD
+
+$(eval PRE_TOOL_FILTER := $($(call uppercase,$(1))_PRE_TOOL_FILTER))
+
+ifneq ($(PRE_TOOL_FILTER),)
+
+$(eval PROCESSED_PATH := $(BUILD_PLAT)/$(1).bin$($(PRE_TOOL_FILTER)_SUFFIX))
+
+$(call $(PRE_TOOL_FILTER)_RULE,$(PROCESSED_PATH),$(2))
+
+$(PROCESSED_PATH): $(4)
+
+$(call TOOL_ADD_PAYLOAD,$(PROCESSED_PATH),$(3),$(PROCESSED_PATH),$(5))
+
+else
+$(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5))
+endif
+endef
+
+# CERT_ADD_CMD_OPT adds a new command line option to the cert_create invocation
+#   $(1) = parameter filename
+#   $(2) = cert_create command line option for the specified parameter
+#   $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
+define CERT_ADD_CMD_OPT
+    $(3)CRT_ARGS += $(2) $(1)
+endef
+
+# TOOL_ADD_IMG allows the platform to specify an external image to be packed
+# in the FIP and/or for which certificate is generated. It also adds a
+# dependency on the image file, aborting the build if the file does not exist.
+#   $(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)
+# Example:
+#   $(eval $(call TOOL_ADD_IMG,bl33,--nt-fw))
+define TOOL_ADD_IMG
+    # Build option to specify the image filename (SCP_BL2, BL33, etc)
+    # This is the uppercase form of the first parameter
+    $(eval _V := $(call uppercase,$(1)))
+
+    $(3)CRT_DEPS += check_$(1)
+    $(3)FIP_DEPS += check_$(1)
+    $(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),,$(3))
+
+.PHONY: check_$(1)
+check_$(1):
+	$$(if $(value $(_V)),,$$(error "Platform '${PLAT}' requires $(_V). Please set $(_V) to point to the right file"))
+	$$(if $(wildcard $(value $(_V))),,$$(error '$(_V)=$(value $(_V))' was specified, but '$(value $(_V))' does not exist))
+endef
+
+################################################################################
+# Generic image processing filters
+################################################################################
+
+# GZIP
+define GZIP_RULE
+$(1): $(2)
+	$(ECHO) "  GZIP    $$@"
+	$(Q)gzip -n -f -9 $$< --stdout > $$@
+endef
+
+GZIP_SUFFIX := .gz
+
+################################################################################
+# Auxiliary macros to build TF images from sources
+################################################################################
+
+MAKE_DEP = -Wp,-MD,$(DEP) -MT $$@ -MP
+
+
+# MAKE_C_LIB builds a C source file and generates the dependency file
+#   $(1) = output directory
+#   $(2) = source file (%.c)
+#   $(3) = library name
+define MAKE_C_LIB
+$(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2))))
+$(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
+
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | lib$(3)_dirs
+	$$(ECHO) "  CC      $$<"
+	$$(Q)$$(CC) $$(TF_CFLAGS) $$(CFLAGS) $(MAKE_DEP) -c $$< -o $$@
+
+-include $(DEP)
+
+endef
+
+# MAKE_S_LIB builds an assembly source file and generates the dependency file
+#   $(1) = output directory
+#   $(2) = source file (%.S)
+#   $(3) = library name
+define MAKE_S_LIB
+$(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2))))
+$(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
+
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | lib$(3)_dirs
+	$$(ECHO) "  AS      $$<"
+	$$(Q)$$(AS) $$(ASFLAGS) $(MAKE_DEP) -c $$< -o $$@
+
+-include $(DEP)
+
+endef
+
+
+# MAKE_C builds a C source file and generates the dependency file
+#   $(1) = output directory
+#   $(2) = source file (%.c)
+#   $(3) = BL stage (2, 2u, 30, 31, 32, 33)
+define MAKE_C
+
+$(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2))))
+$(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
+$(eval IMAGE := IMAGE_BL$(call uppercase,$(3)))
+$(eval BL_CFLAGS := $(BL$(call uppercase,$(3))_CFLAGS))
+
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
+	$$(ECHO) "  CC      $$<"
+	$$(Q)$$(CC) $$(TF_CFLAGS) $$(CFLAGS) $(BL_CFLAGS) -D$(IMAGE) $(MAKE_DEP) -c $$< -o $$@
+
+-include $(DEP)
+
+endef
+
+
+# MAKE_S builds an assembly source file and generates the dependency file
+#   $(1) = output directory
+#   $(2) = assembly file (%.S)
+#   $(3) = BL stage (2, 2u, 30, 31, 32, 33)
+define MAKE_S
+
+$(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2))))
+$(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
+$(eval IMAGE := IMAGE_BL$(call uppercase,$(3)))
+
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
+	$$(ECHO) "  AS      $$<"
+	$$(Q)$$(AS) $$(ASFLAGS) -D$(IMAGE) $(MAKE_DEP) -c $$< -o $$@
+
+-include $(DEP)
+
+endef
+
+
+# MAKE_LD generate the linker script using the C preprocessor
+#   $(1) = output linker script
+#   $(2) = input template
+#   $(3) = BL stage (2, 2u, 30, 31, 32, 33)
+define MAKE_LD
+
+$(eval DEP := $(1).d)
+$(eval IMAGE := IMAGE_BL$(call uppercase,$(3)))
+
+$(1): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
+	$$(ECHO) "  PP      $$<"
+	$$(Q)$$(CPP) $$(CPPFLAGS) $(TF_CFLAGS_$(ARCH)) -P -x assembler-with-cpp -D__LINKER__ $(MAKE_DEP) -D$(IMAGE) -o $$@ $$<
+
+-include $(DEP)
+
+endef
+
+# MAKE_LIB_OBJS builds both C and assembly source files
+#   $(1) = output directory
+#   $(2) = list of source files
+#   $(3) = name of the library
+define MAKE_LIB_OBJS
+        $(eval C_OBJS := $(filter %.c,$(2)))
+        $(eval REMAIN := $(filter-out %.c,$(2)))
+        $(eval $(foreach obj,$(C_OBJS),$(call MAKE_C_LIB,$(1),$(obj),$(3))))
+
+        $(eval S_OBJS := $(filter %.S,$(REMAIN)))
+        $(eval REMAIN := $(filter-out %.S,$(REMAIN)))
+        $(eval $(foreach obj,$(S_OBJS),$(call MAKE_S_LIB,$(1),$(obj),$(3))))
+
+        $(and $(REMAIN),$(error Unexpected source files present: $(REMAIN)))
+endef
+
+
+# MAKE_OBJS builds both C and assembly source files
+#   $(1) = output directory
+#   $(2) = list of source files (both C and assembly)
+#   $(3) = BL stage (2, 30, 31, 32, 33)
+define MAKE_OBJS
+        $(eval C_OBJS := $(filter %.c,$(2)))
+        $(eval REMAIN := $(filter-out %.c,$(2)))
+        $(eval $(foreach obj,$(C_OBJS),$(call MAKE_C,$(1),$(obj),$(3))))
+
+        $(eval S_OBJS := $(filter %.S,$(REMAIN)))
+        $(eval REMAIN := $(filter-out %.S,$(REMAIN)))
+        $(eval $(foreach obj,$(S_OBJS),$(call MAKE_S,$(1),$(obj),$(3))))
+
+        $(and $(REMAIN),$(error Unexpected source files present: $(REMAIN)))
+endef
+
+
+# NOTE: The line continuation '\' is required in the next define otherwise we
+# end up with a line-feed characer at the end of the last c filename.
+# Also bear this issue in mind if extending the list of supported filetypes.
+define SOURCES_TO_OBJS
+        $(notdir $(patsubst %.c,%.o,$(filter %.c,$(1)))) \
+        $(notdir $(patsubst %.S,%.o,$(filter %.S,$(1))))
+endef
+
+# Allow overriding the timestamp, for example for reproducible builds, or to
+# synchronize timestamps across multiple projects.
+# This must be set to a C string (including quotes where applicable).
+BUILD_MESSAGE_TIMESTAMP ?= __TIME__", "__DATE__
+
+.PHONY: libraries
+
+# MAKE_LIB_DIRS macro defines the target for the directory where
+# libraries are created
+define MAKE_LIB_DIRS
+        $(eval LIB_DIR    := ${BUILD_PLAT}/lib)
+        $(eval ROMLIB_DIR    := ${BUILD_PLAT}/romlib)
+        $(eval LIBWRAPPER_DIR := ${BUILD_PLAT}/libwrapper)
+        $(eval $(call MAKE_PREREQ_DIR,${LIB_DIR},${BUILD_PLAT}))
+        $(eval $(call MAKE_PREREQ_DIR,${ROMLIB_DIR},${BUILD_PLAT}))
+        $(eval $(call MAKE_PREREQ_DIR,${LIBWRAPPER_DIR},${BUILD_PLAT}))
+endef
+
+# MAKE_LIB macro defines the targets and options to build each BL image.
+# Arguments:
+#   $(1) = Library name
+define MAKE_LIB
+        $(eval BUILD_DIR  := ${BUILD_PLAT}/lib$(1))
+        $(eval LIB_DIR    := ${BUILD_PLAT}/lib)
+        $(eval ROMLIB_DIR    := ${BUILD_PLAT}/romlib)
+        $(eval SOURCES    := $(LIB$(call uppercase,$(1))_SRCS))
+        $(eval OBJS       := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES))))
+
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},${BUILD_PLAT}))
+$(eval $(call MAKE_LIB_OBJS,$(BUILD_DIR),$(SOURCES),$(1)))
+
+.PHONY : lib${1}_dirs
+lib${1}_dirs: | ${BUILD_DIR} ${LIB_DIR}  ${ROMLIB_DIR} ${LIBWRAPPER_DIR}
+libraries: ${LIB_DIR}/lib$(1).a
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+LDPATHS = --userlibpath=${LIB_DIR}
+LDLIBS += --library=$(1)
+else
+LDPATHS = -L${LIB_DIR}
+LDLIBS += -l$(1)
+endif
+
+ifeq ($(USE_ROMLIB),1)
+LIBWRAPPER = -lwrappers
+endif
+
+all: ${LIB_DIR}/lib$(1).a
+
+${LIB_DIR}/lib$(1).a: $(OBJS)
+	$$(ECHO) "  AR      $$@"
+	$$(Q)$$(AR) cr $$@ $$?
+endef
+
+# MAKE_BL macro defines the targets and options to build each BL image.
+# Arguments:
+#   $(1) = BL stage (2, 2u, 30, 31, 32, 33)
+#   $(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)
+define MAKE_BL
+        $(eval BUILD_DIR  := ${BUILD_PLAT}/bl$(1))
+        $(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES))
+        $(eval SOURCES    := $(BL_SOURCES) $(BL_COMMON_SOURCES) $(PLAT_BL_COMMON_SOURCES))
+        $(eval OBJS       := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES))))
+        $(eval LINKERFILE := $(call IMG_LINKERFILE,$(1)))
+        $(eval MAPFILE    := $(call IMG_MAPFILE,$(1)))
+        $(eval ELF        := $(call IMG_ELF,$(1)))
+        $(eval DUMP       := $(call IMG_DUMP,$(1)))
+        $(eval BIN        := $(call IMG_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.
+        # ordering is not relevant but sort removes duplicates.
+        $(eval TEMP_OBJ_DIRS := $(sort $(dir ${OBJS} ${LINKERFILE})))
+        # The $(dir ) function leaves a trailing / on the directory names
+        # Rip off the / to match directory names with make rule targets.
+        $(eval OBJ_DIRS   := $(patsubst %/,%,$(TEMP_OBJ_DIRS)))
+
+# Create generators for object directory structure
+
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},${BUILD_PLAT}))
+
+$(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
+
+.PHONY : bl${1}_dirs
+
+# We use order-only prerequisites to ensure that directories are created,
+# but do not cause re-builds every time a file is written.
+bl${1}_dirs: | ${OBJ_DIRS}
+
+$(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1)))
+$(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE),$(1)))
+
+ifeq ($(USE_ROMLIB),1)
+$(ELF): romlib.bin
+endif
+
+$(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs libraries $(BL_LIBS)
+	$$(ECHO) "  LD      $$@"
+ifdef MAKE_BUILD_STRINGS
+	$(call MAKE_BUILD_STRINGS, $(BUILD_DIR)/build_message.o)
+else
+	@echo 'const char build_message[] = "Built : "$(BUILD_MESSAGE_TIMESTAMP); \
+	       const char version_string[] = "${VERSION_STRING}";' | \
+		$$(CC) $$(TF_CFLAGS) $$(CFLAGS) -xc -c - -o $(BUILD_DIR)/build_message.o
+endif
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+	$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) --entry=bl${1}_entrypoint \
+		--predefine="-D__LINKER__=$(__LINKER__)" \
+		--predefine="-DTF_CFLAGS=$(TF_CFLAGS)" \
+		--map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/bl${1}.scat \
+		$(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) \
+		$(BUILD_DIR)/build_message.o $(OBJS)
+else
+	$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Map=$(MAPFILE) \
+		--script $(LINKERFILE) $(BUILD_DIR)/build_message.o \
+		$(OBJS) $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS)
+endif
+ifeq ($(DISABLE_BIN_GENERATION),1)
+	@${ECHO_BLANK_LINE}
+	@echo "Built $$@ successfully"
+	@${ECHO_BLANK_LINE}
+endif
+
+$(DUMP): $(ELF)
+	$${ECHO} "  OD      $$@"
+	$${Q}$${OD} -dx $$< > $$@
+
+$(BIN): $(ELF)
+	$${ECHO} "  BIN     $$@"
+	$$(Q)$$(OC) -O binary $$< $$@
+	@${ECHO_BLANK_LINE}
+	@echo "Built $$@ successfully"
+	@${ECHO_BLANK_LINE}
+
+.PHONY: bl$(1)
+ifeq ($(DISABLE_BIN_GENERATION),1)
+bl$(1): $(ELF) $(DUMP)
+else
+bl$(1): $(BIN) $(DUMP)
+endif
+
+all: bl$(1)
+
+$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(BIN),$(3)))
+
+endef
+
+# Convert device tree source file names to matching blobs
+#   $(1) = input dts
+define SOURCES_TO_DTBS
+        $(notdir $(patsubst %.dts,%.dtb,$(filter %.dts,$(1))))
+endef
+
+# MAKE_FDT_DIRS macro creates the prerequisite directories that host the
+# FDT binaries
+#   $(1) = output directory
+#   $(2) = input dts
+define MAKE_FDT_DIRS
+        $(eval DTBS       := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
+        $(eval TEMP_DTB_DIRS := $(sort $(dir ${DTBS})))
+        # The $(dir ) function leaves a trailing / on the directory names
+        # Rip off the / to match directory names with make rule targets.
+        $(eval DTB_DIRS   := $(patsubst %/,%,$(TEMP_DTB_DIRS)))
+
+$(eval $(foreach objd,${DTB_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
+
+fdt_dirs: ${DTB_DIRS}
+endef
+
+# MAKE_DTB generate the Flattened device tree binary
+#   $(1) = output directory
+#   $(2) = input dts
+define MAKE_DTB
+
+# List of DTB file(s) to generate, based on DTS file basename list
+$(eval DOBJ := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
+# List of the pre-compiled DTS file(s)
+$(eval DPRE := $(addprefix $(1)/,$(patsubst %.dts,%.pre.dts,$(notdir $(2)))))
+# Dependencies of the pre-compiled DTS file(s) on its source and included files
+$(eval DTSDEP := $(patsubst %.dtb,%.o.d,$(DOBJ)))
+# Dependencies of the DT compilation on its pre-compiled DTS
+$(eval DTBDEP := $(patsubst %.dtb,%.d,$(DOBJ)))
+
+$(DOBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | fdt_dirs
+	$${ECHO} "  CPP     $$<"
+	$(eval DTBS       := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
+	$$(Q)$$(PP) $$(DTC_CPPFLAGS) -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$<
+	$${ECHO} "  DTC     $$<"
+	$$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DTBDEP) -o $$@ $(DPRE)
+
+-include $(DTBDEP)
+-include $(DTSDEP)
+
+endef
+
+# MAKE_DTBS builds flattened device tree sources
+#   $(1) = output directory
+#   $(2) = list of flattened device tree source files
+define MAKE_DTBS
+        $(eval DOBJS := $(filter %.dts,$(2)))
+        $(eval REMAIN := $(filter-out %.dts,$(2)))
+        $(and $(REMAIN),$(error FDT_SOURCES contain non-DTS files: $(REMAIN)))
+        $(eval $(foreach obj,$(DOBJS),$(call MAKE_DTB,$(1),$(obj))))
+
+        $(eval $(call MAKE_FDT_DIRS,$(1),$(2)))
+
+dtbs: $(DTBS)
+all: dtbs
+endef
diff --git a/make_helpers/cygwin.mk b/make_helpers/cygwin.mk
new file mode 100644
index 0000000..04a963f
--- /dev/null
+++ b/make_helpers/cygwin.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+# OS specific definitions for builds in a Cygwin environment.
+# Cygwin allows us to use unix style commands on a windows platform.
+
+ifndef CYGWIN_MK
+    CYGWIN_MK := $(lastword $(MAKEFILE_LIST))
+
+    include ${MAKE_HELPERS_DIRECTORY}unix.mk
+
+    # In cygwin executable files have the Windows .exe extension type.
+    BIN_EXT := .exe
+
+endif
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
new file mode 100644
index 0000000..f63e46f
--- /dev/null
+++ b/make_helpers/defaults.mk
@@ -0,0 +1,226 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Default, static values for build variables, listed in alphabetic order.
+# Dependencies between build options, if any, are handled in the top-level
+# Makefile, after this file is included. This ensures that the former is better
+# poised to handle dependencies, as all build variables would have a default
+# value by then.
+
+# Use T32 by default
+AARCH32_INSTRUCTION_SET		:= T32
+
+# The AArch32 Secure Payload to be built as BL32 image
+AARCH32_SP			:= none
+
+# The Target build architecture. Supported values are: aarch64, aarch32.
+ARCH				:= aarch64
+
+# ARM Architecture major and minor versions: 8.0 by default.
+ARM_ARCH_MAJOR			:= 8
+ARM_ARCH_MINOR			:= 0
+
+# Base commit to perform code check on
+BASE_COMMIT			:= origin/master
+
+# Execute BL2 at EL3
+BL2_AT_EL3			:= 0
+
+# BL2 image is stored in XIP memory, for now, this option is only supported
+# when BL2_AT_EL3 is 1.
+BL2_IN_XIP_MEM			:= 0
+
+# Select the branch protection features to use.
+BRANCH_PROTECTION		:= 0
+
+# By default, consider that the platform may release several CPUs out of reset.
+# The platform Makefile is free to override this value.
+COLD_BOOT_SINGLE_CPU		:= 0
+
+# Flag to compile in coreboot support code. Exclude by default. The coreboot
+# Makefile system will set this when compiling TF as part of a coreboot image.
+COREBOOT			:= 0
+
+# For Chain of Trust
+CREATE_KEYS			:= 1
+
+# Build flag to include AArch32 registers in cpu context save and restore during
+# world switch. This flag must be set to 0 for AArch64-only platforms.
+CTX_INCLUDE_AARCH32_REGS	:= 1
+
+# Include FP registers in cpu context
+CTX_INCLUDE_FPREGS		:= 0
+
+# Include pointer authentication (ARMv8.3-PAuth) registers in cpu context. This
+# must be set to 1 if the platform wants to use this feature in the Secure
+# world. It is not needed to use it in the Non-secure world.
+CTX_INCLUDE_PAUTH_REGS		:= 0
+
+# Debug build
+DEBUG				:= 0
+
+# Build platform
+DEFAULT_PLAT			:= fvp
+
+# Disable the generation of the binary image (ELF only).
+DISABLE_BIN_GENERATION		:= 0
+
+# Enable capability to disable authentication dynamically. Only meant for
+# development platforms.
+DYN_DISABLE_AUTH		:= 0
+
+# Build option to enable MPAM for lower ELs
+ENABLE_MPAM_FOR_LOWER_ELS	:= 0
+
+# Flag to Enable Position Independant support (PIE)
+ENABLE_PIE			:= 0
+
+# Flag to enable Performance Measurement Framework
+ENABLE_PMF			:= 0
+
+# Flag to enable PSCI STATs functionality
+ENABLE_PSCI_STAT		:= 0
+
+# Flag to enable runtime instrumentation using PMF
+ENABLE_RUNTIME_INSTRUMENTATION	:= 0
+
+# Flag to enable stack corruption protection
+ENABLE_STACK_PROTECTOR		:= 0
+
+# Flag to enable exception handling in EL3
+EL3_EXCEPTION_HANDLING		:= 0
+
+# Flag to enable Branch Target Identification.
+# Internal flag not meant for direct setting.
+# Use BRANCH_PROTECTION to enable BTI.
+ENABLE_BTI			:= 0
+
+# Flag to enable Pointer Authentication.
+# Internal flag not meant for direct setting.
+# Use BRANCH_PROTECTION to enable PAUTH.
+ENABLE_PAUTH			:= 0
+
+# Build flag to treat usage of deprecated platform and framework APIs as error.
+ERROR_DEPRECATED		:= 0
+
+# Fault injection support
+FAULT_INJECTION_SUPPORT		:= 0
+
+# Byte alignment that each component in FIP is aligned to
+FIP_ALIGN			:= 0
+
+# Default FIP file name
+FIP_NAME			:= fip.bin
+
+# Default FWU_FIP file name
+FWU_FIP_NAME			:= fwu_fip.bin
+
+# For Chain of Trust
+GENERATE_COT			:= 0
+
+# Hint platform interrupt control layer that Group 0 interrupts are for EL3. By
+# default, they are for Secure EL1.
+GICV2_G0_FOR_EL3		:= 0
+
+# Route External Aborts to EL3. Disabled by default; External Aborts are handled
+# by lower ELs.
+HANDLE_EA_EL3_FIRST		:= 0
+
+# Whether system coherency is managed in hardware, without explicit software
+# operations.
+HW_ASSISTED_COHERENCY		:= 0
+
+# Set the default algorithm for the generation of Trusted Board Boot keys
+KEY_ALG				:= rsa
+
+# NS timer register save and restore
+NS_TIMER_SWITCH			:= 0
+
+# Include lib/libc in the final image
+OVERRIDE_LIBC			:= 0
+
+# Build PL011 UART driver in minimal generic UART mode
+PL011_GENERIC_UART		:= 0
+
+# By default, consider that the platform's reset address is not programmable.
+# The platform Makefile is free to override this value.
+PROGRAMMABLE_RESET_ADDRESS	:= 0
+
+# Flag used to choose the power state format: Extended State-ID or Original
+PSCI_EXTENDED_STATE_ID		:= 0
+
+# Enable RAS support
+RAS_EXTENSION			:= 0
+
+# By default, BL1 acts as the reset handler, not BL31
+RESET_TO_BL31			:= 0
+
+# For Chain of Trust
+SAVE_KEYS			:= 0
+
+# Software Delegated Exception support
+SDEI_SUPPORT            	:= 0
+
+# Whether code and read-only data should be put on separate memory pages. The
+# platform Makefile is free to override this value.
+SEPARATE_CODE_AND_RODATA	:= 0
+
+# If the BL31 image initialisation code is recalimed after use for the secondary
+# cores stack
+RECLAIM_INIT_CODE		:= 0
+
+# SPD choice
+SPD				:= none
+
+# For including the Secure Partition Manager
+ENABLE_SPM			:= 0
+
+# Use the SPM based on MM
+SPM_MM				:= 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
+
+# Flags to build TF with Trusted Boot support
+TRUSTED_BOARD_BOOT		:= 0
+
+# Build option to choose whether Trusted Firmware uses Coherent memory or not.
+USE_COHERENT_MEM		:= 1
+
+# Build option to choose whether Trusted Firmware uses library at ROM
+USE_ROMLIB			:= 0
+
+# Use tbbr_oid.h instead of platform_oid.h
+USE_TBBR_DEFS			:= 1
+
+# Build verbosity
+V				:= 0
+
+# Whether to enable D-Cache early during warm boot. This is usually
+# applicable for platforms wherein interconnect programming is not
+# required to enable cache coherency after warm reset (eg: single cluster
+# platforms).
+WARMBOOT_ENABLE_DCACHE_EARLY	:= 0
+
+# Build option to enable/disable the Statistical Profiling Extensions
+ENABLE_SPE_FOR_LOWER_ELS	:= 1
+
+# SPE is only supported on AArch64 so disable it on AArch32.
+ifeq (${ARCH},aarch32)
+    override ENABLE_SPE_FOR_LOWER_ELS := 0
+endif
+
+ENABLE_AMU			:= 0
+
+# By default, enable Scalable Vector Extension if implemented for Non-secure
+# lower ELs
+# Note SVE is only supported on AArch64 - therefore do not enable in AArch32
+ifneq (${ARCH},aarch32)
+    ENABLE_SVE_FOR_NS		:= 1
+else
+    override ENABLE_SVE_FOR_NS	:= 0
+endif
diff --git a/make_helpers/msys.mk b/make_helpers/msys.mk
new file mode 100644
index 0000000..7e60d57
--- /dev/null
+++ b/make_helpers/msys.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+# OS specific definitions for builds in a Mingw32 MSYS environment.
+# Mingw32 allows us to use some unix style commands on a windows platform.
+
+ifndef MSYS_MK
+    MSYS_MK := $(lastword $(MAKEFILE_LIST))
+
+    include ${MAKE_HELPERS_DIRECTORY}unix.mk
+
+    # In MSYS executable files have the Windows .exe extension type.
+    BIN_EXT := .exe
+
+endif
+
diff --git a/make_helpers/plat_helpers.mk b/make_helpers/plat_helpers.mk
new file mode 100644
index 0000000..a7ae9a2
--- /dev/null
+++ b/make_helpers/plat_helpers.mk
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+################################################################################
+# Helpers for finding and referencing platform directories
+################################################################################
+
+ifndef PLAT_HELPERS_MK
+    PLAT_HELPERS_MK := $(lastword $(MAKEFILE_LIST))
+
+    ifeq (${PLAT},)
+        $(error "Error: Unknown platform. Please use PLAT=<platform name> to specify the platform")
+    endif
+
+    # TF_PLATFORM_ROOT can be overridden for when building tools directly
+    TF_PLATFORM_ROOT               ?= plat/
+    PLAT_MAKEFILE               := platform.mk
+
+    # Generate the platforms list by recursively searching for all directories
+    # under /plat containing a PLAT_MAKEFILE. Append each platform with a `|`
+    # char and strip out the final '|'.
+    ALL_PLATFORM_MK_FILES       := $(call rwildcard,${TF_PLATFORM_ROOT},${PLAT_MAKEFILE})
+    ALL_PLATFORM_DIRS           := $(patsubst %/,%,$(dir ${ALL_PLATFORM_MK_FILES}))
+    ALL_PLATFORMS               := $(sort $(notdir ${ALL_PLATFORM_DIRS}))
+
+    PLAT_MAKEFILE_FULL          := $(filter %/${PLAT}/${PLAT_MAKEFILE},${ALL_PLATFORM_MK_FILES})
+    PLATFORM_LIST               := $(subst ${space},|,${ALL_PLATFORMS})
+    ifeq ($(PLAT_MAKEFILE_FULL),)
+        $(error "Error: Invalid platform. The following platforms are available: ${PLATFORM_LIST}")
+    endif
+
+    # Record the directory where the platform make file was found.
+    PLAT_DIR                    := $(dir ${PLAT_MAKEFILE_FULL})
+
+endif
diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk
new file mode 100644
index 0000000..afc007a
--- /dev/null
+++ b/make_helpers/tbbr/tbbr_tools.mk
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# This file defines the keys and certificates that must be created to establish
+# a Chain of Trust following the TBBR document. These definitions include the
+# command line options passed to the cert_create and fiptool commands.
+#
+# Expected environment:
+#
+#   BUILD_PLAT: output directory
+#   NEED_BL32: indicates whether BL32 is needed by the platform
+#   BL2: image filename (optional). Default is IMG_BIN(2) (see macro IMG_BIN)
+#   SCP_BL2: image filename (optional). Default is IMG_BIN(30)
+#   BL31: image filename (optional). Default is IMG_BIN(31)
+#   BL32: image filename (optional). Default is IMG_BIN(32)
+#   BL33: image filename (optional). Default is IMG_BIN(33)
+#
+# Build options added by this file:
+#
+#   KEY_ALG
+#   ROT_KEY
+#   TRUSTED_WORLD_KEY
+#   NON_TRUSTED_WORLD_KEY
+#   SCP_BL2_KEY
+#   BL31_KEY
+#   BL32_KEY
+#   BL33_KEY
+#
+
+# Certificate generation tool default parameters
+TRUSTED_KEY_CERT	:=	${BUILD_PLAT}/trusted_key.crt
+FWU_CERT		:=	${BUILD_PLAT}/fwu_cert.crt
+
+# Default non-volatile counter values (overridable by the platform)
+TFW_NVCTR_VAL		?=	0
+NTFW_NVCTR_VAL		?=	0
+
+# Pass the non-volatile counters to the cert_create tool
+$(eval $(call CERT_ADD_CMD_OPT,${TFW_NVCTR_VAL},--tfw-nvctr))
+$(eval $(call CERT_ADD_CMD_OPT,${NTFW_NVCTR_VAL},--ntfw-nvctr))
+
+# Add Trusted Key certificate to the fiptool and cert_create command line options
+$(eval $(call TOOL_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert))
+
+# Add fwu certificate to the fiptool and cert_create command line options
+$(eval $(call TOOL_ADD_PAYLOAD,${FWU_CERT},--fwu-cert,,FWU_))
+
+# Add the keys to the cert_create command line options (private keys are NOT
+# packed in the FIP). Developers can use their own keys by specifying the proper
+# build option in the command line when building the Trusted Firmware
+$(if ${KEY_ALG},$(eval $(call CERT_ADD_CMD_OPT,${KEY_ALG},--key-alg)))
+$(if ${HASH_ALG},$(eval $(call CERT_ADD_CMD_OPT,${HASH_ALG},--hash-alg)))
+$(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key)))
+$(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key,FWU_)))
+$(if ${TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_WORLD_KEY},--trusted-world-key)))
+$(if ${NON_TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${NON_TRUSTED_WORLD_KEY},--non-trusted-world-key)))
+
+
+# Add the BL2 CoT (image cert)
+ifeq (${BL2_AT_EL3}, 0)
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert))
+endif
+
+# Add the SCP_BL2 CoT (key cert + img cert)
+ifneq (${SCP_BL2},)
+    $(if ${SCP_BL2_KEY},$(eval $(call CERT_ADD_CMD_OPT,${SCP_BL2_KEY},--scp-fw-key)))
+    $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/scp_fw_content.crt,--scp-fw-cert))
+    $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/scp_fw_key.crt,--scp-fw-key-cert))
+endif
+
+ifeq (${ARCH},aarch64)
+ifeq (${NEED_BL31},yes)
+# Add the BL31 CoT (key cert + img cert)
+$(if ${BL31_KEY},$(eval $(call CERT_ADD_CMD_OPT,${BL31_KEY},--soc-fw-key)))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/soc_fw_content.crt,--soc-fw-cert))
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/soc_fw_key.crt,--soc-fw-key-cert))
+endif
+endif
+
+# Add the BL32 CoT (key cert + img cert)
+ifeq (${NEED_BL32},yes)
+    $(if ${BL32_KEY},$(eval $(call CERT_ADD_CMD_OPT,${BL32_KEY},--tos-fw-key)))
+    $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tos_fw_content.crt,--tos-fw-cert))
+    $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tos_fw_key.crt,--tos-fw-key-cert))
+endif
+
+# Add the BL33 CoT (key cert + img cert)
+ifneq (${BL33},)
+    $(if ${BL33_KEY},$(eval $(call CERT_ADD_CMD_OPT,${BL33_KEY},--nt-fw-key)))
+    $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/nt_fw_content.crt,--nt-fw-cert))
+    $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/nt_fw_key.crt,--nt-fw-key-cert))
+endif
diff --git a/make_helpers/unix.mk b/make_helpers/unix.mk
new file mode 100644
index 0000000..545ddfd
--- /dev/null
+++ b/make_helpers/unix.mk
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Trusted Firmware shell command definitions for a Unix style environment.
+
+ifndef UNIX_MK
+    UNIX_MK := $(lastword $(MAKEFILE_LIST))
+
+    ECHO_BLANK_LINE := echo
+    ECHO_QUIET := @\#
+
+    DIR_DELIM := /
+    PATH_SEP := :
+
+    # These defines provide Unix style equivalents of the shell commands
+    # required by the Trusted Firmware build environment.
+
+    # ${1} is the file to be copied.
+    # ${2} is the destination file name.
+    define SHELL_COPY
+	${Q}cp -f  "${1}"  "${2}"
+    endef
+
+    # ${1} is the directory to be copied.
+    # ${2} is the destination directory path.
+    define SHELL_COPY_TREE
+	${Q}cp -rf  "${1}"  "${2}"
+    endef
+
+    # ${1} is the file to be deleted.
+    define SHELL_DELETE
+	-${Q}rm -f  "${1}"
+    endef
+
+    # ${1} is a space delimited list of files to be deleted.
+    # Note that we do not quote ${1}, as multiple parameters may be passed.
+    define SHELL_DELETE_ALL
+	-${Q}rm -rf  ${1}
+    endef
+
+    # ${1} is the directory to be generated.
+    # ${2} is optional, and allows a prerequisite to be specified.
+    # Do nothing if $1 == $2, to ignore self dependencies.
+    define MAKE_PREREQ_DIR
+        ifneq (${1},${2})
+
+${1} : ${2}
+	${Q}mkdir -p  "${1}"
+
+        endif
+    endef
+
+    define SHELL_REMOVE_DIR
+	-${Q}rm -rf  "${1}"
+    endef
+
+endif
diff --git a/make_helpers/windows.mk b/make_helpers/windows.mk
new file mode 100644
index 0000000..5ab8bdc
--- /dev/null
+++ b/make_helpers/windows.mk
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# OS specific parts for builds in a Windows_NT environment. The
+# environment variable OS is set to Windows_NT on all modern Windows platforms
+
+# Include generic windows command definitions.
+
+ifndef WINDOWS_MK
+    WINDOWS_MK := $(lastword $(MAKEFILE_LIST))
+
+    ECHO_BLANK_LINE := @cmd /c echo.
+    ECHO_QUIET := @rem
+    DIR_DELIM := $(strip \)
+    BIN_EXT   := .exe
+    PATH_SEP  := ;
+
+    # For some Windows native commands there is a problem with the directory delimiter.
+    # Make uses / (slash) and the commands expect \ (backslash)
+    # We have to provide a means of translating these, so we define local functions.
+
+    # ${1} is the file to be copied.
+    # ${2} is the destination file name.
+    define SHELL_COPY
+	$(eval tmp_from_file:=$(subst /,\,${1}))
+	$(eval tmp_to_file:=$(subst /,\,${2}))
+	copy "${tmp_from_file}" "${tmp_to_file}"
+    endef
+
+    # ${1} is the directory to be copied.
+    # ${2} is the destination directory path.
+    define SHELL_COPY_TREE
+	$(eval tmp_from_dir:=$(subst /,\,${1}))
+	$(eval tmp_to_dir:=$(subst /,\,${2}))
+	xcopy /HIVE "${tmp_from_dir}" "${tmp_to_dir}"
+    endef
+
+    # ${1} is the file to be deleted.
+    define SHELL_DELETE
+	$(eval tmp_del_file:=$(subst /,\,${*}))
+	-@if exist $(tmp_del_file)  del /Q $(tmp_del_file)
+    endef
+
+    # ${1} is a space delimited list of files to be deleted.
+    define SHELL_DELETE_ALL
+	$(eval $(foreach filename,$(wildcard ${1}),$(call DELETE_IF_THERE,${filename})))
+    endef
+
+    # ${1} is the directory to be generated.
+    # ${2} is optional, and allows prerequisites to be specified.
+    # Do nothing if $1 == $2, to ignore self dependencies.
+    define MAKE_PREREQ_DIR
+        ifneq (${1},${2})
+
+${1} : ${2}
+	$(eval tmp_dir:=$(subst /,\,${1}))
+	-@if not exist "$(tmp_dir)"  mkdir "${tmp_dir}"
+
+        endif
+    endef
+
+    # ${1} is the directory to be removed.
+    define SHELL_REMOVE_DIR
+	$(eval tmp_dir:=$(subst /,\,${1}))
+	-@if exist "$(tmp_dir)"  rd /Q /S "$(tmp_dir)"
+    endef
+
+endif
+
+# Because git is not available from CMD.EXE, we need to avoid
+# the BUILD_STRING generation which uses git.
+# For now we use "development build".
+# This can be overridden from the command line or environment.
+BUILD_STRING ?= development build
+
+# The DOS echo shell command does not strip ' characters from the command
+# parameters before printing. We therefore use an alternative method invoked
+# by defining the MAKE_BUILD_STRINGS macro.
+BUILT_TIME_DATE_STRING = const char build_message[] = "Built : "${BUILD_MESSAGE_TIMESTAMP};
+VERSION_STRING_MESSAGE = const char version_string[] = "${VERSION_STRING}";
+define MAKE_BUILD_STRINGS
+	@echo $$(BUILT_TIME_DATE_STRING) $$(VERSION_STRING_MESSAGE) | \
+		$$(CC) $$(TF_CFLAGS) $$(CFLAGS) -x c -c - -o $1
+endef
+
diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
new file mode 100644
index 0000000..6866bd6
--- /dev/null
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+AW_PLAT			:=	plat/allwinner
+
+PLAT_INCLUDES		:=	-Iinclude/plat/arm/common		\
+				-Iinclude/plat/arm/common/aarch64	\
+				-I${AW_PLAT}/common/include		\
+				-I${AW_PLAT}/${PLAT}/include
+
+include lib/libfdt/libfdt.mk
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/${ARCH}/16550_console.S	\
+				${XLAT_TABLES_LIB_SRCS}			\
+				${AW_PLAT}/common/plat_helpers.S	\
+				${AW_PLAT}/common/sunxi_common.c
+
+BL31_SOURCES		+=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				lib/cpus/${ARCH}/cortex_a53.S		\
+				plat/common/plat_gicv2.c		\
+				plat/common/plat_psci_common.c		\
+				${AW_PLAT}/common/sunxi_bl31_setup.c	\
+				${AW_PLAT}/common/sunxi_cpu_ops.c	\
+				${AW_PLAT}/common/sunxi_pm.c		\
+				${AW_PLAT}/${PLAT}/sunxi_power.c	\
+				${AW_PLAT}/common/sunxi_security.c	\
+				${AW_PLAT}/common/sunxi_topology.c
+
+# The bootloader is guaranteed to only run on CPU 0 by the boot ROM.
+COLD_BOOT_SINGLE_CPU		:=	1
+
+# Do not enable SPE (not supported on ARM v8.0).
+ENABLE_SPE_FOR_LOWER_ELS	:=	0
+
+# Do not enable SVE (not supported on ARM v8.0).
+ENABLE_SVE_FOR_NS		:=	0
+
+# Enable workarounds for Cortex-A53 errata. Allwinner uses at least r0p4.
+ERRATA_A53_835769		:=	1
+ERRATA_A53_843419		:=	1
+ERRATA_A53_855873		:=	1
+
+# The reset vector can be changed for each CPU.
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+
+# Allow mapping read-only data as execute-never.
+SEPARATE_CODE_AND_RODATA	:=	1
+
+# BL31 gets loaded alongside BL33 (U-Boot) by U-Boot's SPL
+RESET_TO_BL31			:=	1
+
+# We are short on memory, so save 3.5KB by not having an extra coherent page.
+USE_COHERENT_MEM		:=	0
+
+# This platform is single-cluster and does not require coherency setup.
+WARMBOOT_ENABLE_DCACHE_EARLY	:=	1
diff --git a/plat/allwinner/common/arisc_off.S b/plat/allwinner/common/arisc_off.S
new file mode 100644
index 0000000..ed10832
--- /dev/null
+++ b/plat/allwinner/common/arisc_off.S
@@ -0,0 +1,115 @@
+# turn_off_core.S
+#
+# Copyright (c) 2018, Andre Przywara <osp@andrep.de>
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# OpenRISC assembly to turn off an ARM core on an Allwinner SoC from
+# the arisc management controller.
+# Generate a binary representation with:
+# $ or1k-elf-as -c -o turn_off_core.o turn_off_core.S
+# $ or1k-elf-objcopy -O binary --reverse-bytes=4 turn_off_core.o \
+#   turn_off_core.bin
+# The encoded instructions go into an array defined in
+# plat/allwinner/sun50i_*/include/core_off_arisc.h, to be handed off to
+# the arisc processor.
+#
+# This routine is meant to be called directly from arisc reset (put the
+# start address in the reset vector), to be actually triggered by that
+# very ARM core to be turned off.
+# It expects the core number presented as a mask in the upper half of
+# r3, so to be patched in the lower 16 bits of the first instruction,
+# overwriting the 0 in this code here.
+# The code will do the following:
+# - Read the C_CPU_STATUS register, which contains the status of the WFI
+#   lines of each of the four A53 cores.
+# - Loop until the core in question reaches WFI.
+# - Using that mask, activate the core output clamps by setting the
+#   respective core bit in CPUX_PWROFF_GATING_REG (0x1f01500).
+#   Note that the clamp for core 0 covers more than just the core, activating
+#   it hangs the whole system. So we skip this step for core 0.
+# - Using the negated mask, assert the core's reset line by clearing the
+#   respective bit in C_RST_CTRL (0x1f01c30).
+# - Finally turn off the core's power switch by writing 0xff to the
+#   respective CPUx_PWR_SWITCH_REG (0x1f01540 ff.)
+# - Assert the arisc's own reset to end execution.
+#   This also signals other arisc users that the chip is free again.
+# So in C this would look like:
+#	while (!(readl(0x1700030) & (1U << core_nr)))
+#		;
+#	if (core_nr != 0)
+#		writel(readl(0x1f01500) | (1U << core_nr), 0x1f01500);
+#	writel(readl(0x1f01c30) & ~(1U << core_nr), 0x1f01c30);
+#	writel(0xff, 0x1f01540 + (core_nr * 4));
+# (using A64/H5 addresses)
+
+.text
+_start:
+	l.movhi	r3, 0				# FIXUP! with core mask
+	l.movhi r0, 0				# clear r0
+	l.movhi	r13, 0x170			# r13: CPU_CFG_BASE=0x01700000
+wait_wfi:
+	l.lwz	r5, 0x30(r13)			# load C_CPU_STATUS
+	l.and	r5, r5, r3			# mask requested core
+	l.sfeq	r5, r0				# is it not yet in WFI?
+	l.bf	wait_wfi			# try again
+
+	l.srli	r6, r3, 16			# move mask to lower 16 bits
+	l.sfeqi	r6, 1				# core 0 is special
+	l.bf	1f				# don't touch the bit for core 0
+	l.movhi	r13, 0x1f0			# address of R_CPUCFG (delay)
+	l.lwz	r5, 0x1500(r13)			# core output clamps
+	l.or	r5, r5, r6			# set bit to ...
+	l.sw	0x1500(r13), r5			# ... activate for our core
+
+1:	l.lwz	r5, 0x1c30(r13)			# CPU power-on reset
+	l.xori	r6, r6, -1			# negate core mask
+	l.and	r5, r5, r6			# clear bit to ...
+	l.sw	0x1c30(r13), r5			# ... assert for our core
+
+	l.ff1	r6, r3				# get core number from high mask
+	l.addi	r6, r6, -17			# convert to 0-3
+	l.slli	r6, r6, 2			# r5: core number*4 (0-12)
+	l.add	r6, r6, r13			# add to base address
+	l.ori	r5, r0, 0xff			# 0xff means all switches off
+	l.sw	0x1540(r6), r5			# core power switch registers
+
+reset:	l.sw	0x1c00(r13),r0			# pull down our own reset line
+
+	l.j	reset				# just in case ....
+	l.nop	0x0				# (delay slot)
+
+# same as above, but with the MMIO addresses matching the H6 SoC
+_start_h6:
+	l.movhi	r3, 0				# FIXUP! with core mask
+	l.movhi r0, 0				# clear r0
+	l.movhi	r13, 0x901			# r13: CPU_CFG_BASE=0x09010000
+1:
+	l.lwz	r5, 0x80(r13)			# load C_CPU_STATUS
+	l.and	r5, r5, r3			# mask requested core
+	l.sfeq	r5, r0				# is it not yet in WFI?
+	l.bf	1b				# try again
+
+	l.srli	r6, r3, 16			# move mask to lower 16 bits(ds)
+	l.sfeqi	r6, 1				# core 0 is special
+	l.bf	1f				# don't touch the bit for core 0
+	l.movhi	r13, 0x700			# address of R_CPUCFG (ds)
+	l.lwz	r5, 0x0444(r13)			# core output clamps
+	l.or	r5, r5, r6			# set bit to ...
+	l.sw	0x0444(r13), r5			# ... activate for our core
+
+1:	l.lwz	r5, 0x0440(r13)			# CPU power-on reset
+	l.xori	r6, r6, -1			# negate core mask
+	l.and	r5, r5, r6			# clear bit to ...
+	l.sw	0x0440(r13), r5			# ... assert for our core
+
+	l.ff1	r6, r3				# get core number from high mask
+	l.addi	r6, r6, -17			# convert to 0-3
+	l.slli	r6, r6, 2			# r5: core number*4 (0-12)
+	l.add	r6, r6, r13			# add to base address
+	l.ori	r5, r0, 0xff			# 0xff means all switches off
+	l.sw	0x0450(r6), r5			# core power switch registers
+
+1:	l.sw	0x0400(r13),r0			# pull down our own reset line
+
+	l.j	1b				# just in case ...
+	l.nop	0x0				# (delay slot)
diff --git a/plat/allwinner/common/include/mentor_i2c_plat.h b/plat/allwinner/common/include/mentor_i2c_plat.h
new file mode 100644
index 0000000..d03f2d1
--- /dev/null
+++ b/plat/allwinner/common/include/mentor_i2c_plat.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+/* This driver provides I2C support for Allwinner sunXi SoCs */
+
+#ifndef MENTOR_I2C_PLAT_H
+#define MENTOR_I2C_PLAT_H
+
+#define CONFIG_SYS_TCLK			24000000
+#define CONFIG_SYS_I2C_SPEED		100000
+#define CONFIG_SYS_I2C_SLAVE		0
+
+#define I2C_INTERRUPT_CLEAR_INVERTED
+
+struct  mentor_i2c_regs {
+	uint32_t slave_address;
+	uint32_t xtnd_slave_addr;
+	uint32_t data;
+	uint32_t control;
+	uint32_t status;
+	uint32_t baudrate;
+	uint32_t soft_reset;
+};
+
+#endif /* MENTOR_I2C_PLAT_H */
diff --git a/plat/allwinner/common/include/plat_macros.S b/plat/allwinner/common/include/plat_macros.S
new file mode 100644
index 0000000..77f183d
--- /dev/null
+++ b/plat/allwinner/common/include/plat_macros.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+#include <sunxi_mmap.h>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm	x17, SUNXI_GICC_BASE
+	mov_imm	x16, SUNXI_GICD_BASE
+	arm_print_gic_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/allwinner/common/include/platform_def.h b/plat/allwinner/common/include/platform_def.h
new file mode 100644
index 0000000..ede3881
--- /dev/null
+++ b/plat/allwinner/common/include/platform_def.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <sunxi_mmap.h>
+
+#define BL31_BASE			SUNXI_SRAM_A2_BASE
+#define BL31_LIMIT			(SUNXI_SRAM_A2_BASE + SUNXI_SRAM_A2_SIZE)
+
+/* The traditional U-Boot load address is 160MB into DRAM, so at 0x4a000000 */
+#define PLAT_SUNXI_NS_IMAGE_OFFSET	(SUNXI_DRAM_BASE + (160U << 20))
+
+/* How much memory to reserve as secure for BL32, if configured */
+#define SUNXI_DRAM_SEC_SIZE		(32U << 20)
+
+/* How much DRAM to map (to map BL33, for fetching the DTB from U-Boot) */
+#define SUNXI_DRAM_MAP_SIZE		(64U << 20)
+
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#define MAX_MMAP_REGIONS		(3 + PLATFORM_MMAP_REGIONS)
+#define MAX_XLAT_TABLES			1
+
+#define PLAT_MAX_PWR_LVL_STATES		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+#define PLAT_MAX_PWR_LVL		U(2)
+#define PLAT_NUM_PWR_DOMAINS		(1 + \
+					 PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 28)
+
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_MAX_CPUS_PER_CLUSTER)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_MMAP_REGIONS		4
+#define PLATFORM_STACK_SIZE		(0x1000 / PLATFORM_CORE_COUNT)
+
+#ifndef SPD_none
+#ifndef BL32_BASE
+#define BL32_BASE			SUNXI_DRAM_BASE
+#endif
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/allwinner/common/include/sunxi_def.h b/plat/allwinner/common/include/sunxi_def.h
new file mode 100644
index 0000000..73c4453
--- /dev/null
+++ b/plat/allwinner/common/include/sunxi_def.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_DEF_H
+#define SUNXI_DEF_H
+
+/* Clock configuration */
+#define SUNXI_OSC24M_CLK_IN_HZ		24000000
+
+/* UART configuration */
+#define SUNXI_UART0_BAUDRATE		115200
+#define SUNXI_UART0_CLK_IN_HZ		SUNXI_OSC24M_CLK_IN_HZ
+
+#define SUNXI_SOC_A64			0x1689
+#define SUNXI_SOC_H5			0x1718
+#define SUNXI_SOC_H6			0x1728
+
+#endif /* SUNXI_DEF_H */
diff --git a/plat/allwinner/common/include/sunxi_private.h b/plat/allwinner/common/include/sunxi_private.h
new file mode 100644
index 0000000..1166879
--- /dev/null
+++ b/plat/allwinner/common/include/sunxi_private.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_PRIVATE_H
+#define SUNXI_PRIVATE_H
+
+void sunxi_configure_mmu_el3(int flags);
+
+void sunxi_cpu_on(u_register_t mpidr);
+void sunxi_cpu_off(u_register_t mpidr);
+void sunxi_disable_secondary_cpus(u_register_t primary_mpidr);
+void __dead2 sunxi_power_down(void);
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt);
+void sunxi_security_setup(void);
+
+uint16_t sunxi_read_soc_id(void);
+void sunxi_set_gpio_out(char port, int pin, bool level_high);
+int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb);
+void sunxi_execute_arisc_code(uint32_t *code, size_t size,
+			      int patch_offset, uint16_t param);
+
+#endif /* SUNXI_PRIVATE_H */
diff --git a/plat/allwinner/common/plat_helpers.S b/plat/allwinner/common/plat_helpers.S
new file mode 100644
index 0000000..b00c7ae
--- /dev/null
+++ b/plat/allwinner/common/plat_helpers.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	plat_my_core_pos
+	.globl	platform_mem_init
+	.globl	plat_report_exception
+
+func plat_crash_console_init
+	mov_imm x0, SUNXI_UART0_BASE
+	mov_imm x1, SUNXI_UART0_CLK_IN_HZ
+	mov_imm x2, SUNXI_UART0_BAUDRATE
+	b	console_16550_core_init
+endfunc plat_crash_console_init
+
+func plat_crash_console_putc
+	mov_imm x1, SUNXI_UART0_BASE
+	b	console_16550_core_putc
+endfunc plat_crash_console_putc
+
+func plat_crash_console_flush
+	ret
+endfunc plat_crash_console_flush
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CLUSTER_MASK
+	and	x0, x0, #MPIDR_CPU_MASK
+	add	x0, x0, x1, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+func plat_report_exception
+	ret
+endfunc plat_report_exception
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
new file mode 100644
index 0000000..a24527c
--- /dev/null
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static console_16550_t console;
+
+static const gicv2_driver_data_t sunxi_gic_data = {
+	.gicd_base = SUNXI_GICD_BASE,
+	.gicc_base = SUNXI_GICC_BASE,
+};
+
+/*
+ * Try to find a DTB loaded in memory by previous stages.
+ *
+ * At the moment we implement a heuristic to find the DTB attached to U-Boot:
+ * U-Boot appends its DTB to the end of the image. Assuming that BL33 is
+ * U-Boot, try to find the size of the U-Boot image to learn the DTB address.
+ * The generic ARMv8 U-Boot image contains the load address and its size
+ * as u64 variables at the beginning of the image. There might be padding
+ * or other headers before that data, so scan the first 2KB after the BL33
+ * entry point to find the load address, which should be followed by the
+ * size. Adding those together gives us the address of the DTB.
+ */
+static void *sunxi_find_dtb(void)
+{
+	uint64_t *u_boot_base;
+	int i;
+
+	u_boot_base = (void *)(SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE);
+
+	for (i = 0; i < 2048 / sizeof(uint64_t); i++) {
+		uint32_t *dtb_base;
+
+		if (u_boot_base[i] != PLAT_SUNXI_NS_IMAGE_OFFSET)
+			continue;
+
+		/* Does the suspected U-Boot size look anyhow reasonable? */
+		if (u_boot_base[i + 1] >= 256 * 1024 * 1024)
+			continue;
+
+		/* end of the image: base address + size */
+		dtb_base = (void *)((char *)u_boot_base + u_boot_base[i + 1]);
+
+		if (fdt_check_header(dtb_base) != 0)
+			continue;
+
+		return dtb_base;
+	}
+
+	return NULL;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	/* Initialize the debug console as soon as possible */
+	console_16550_register(SUNXI_UART0_BASE, SUNXI_UART0_CLK_IN_HZ,
+			       SUNXI_UART0_BAUDRATE, &console);
+
+#ifdef BL32_BASE
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+#endif
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+	/*
+	 * Tell BL31 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+					  DISABLE_ALL_EXCEPTIONS);
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+	/* Turn off all secondary CPUs */
+	sunxi_disable_secondary_cpus(read_mpidr());
+}
+
+void bl31_plat_arch_setup(void)
+{
+	sunxi_configure_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	const char *soc_name;
+	uint16_t soc_id = sunxi_read_soc_id();
+	void *fdt;
+
+	switch (soc_id) {
+	case SUNXI_SOC_A64:
+		soc_name = "A64/H64/R18";
+		break;
+	case SUNXI_SOC_H5:
+		soc_name = "H5";
+		break;
+	case SUNXI_SOC_H6:
+		soc_name = "H6";
+		break;
+	default:
+		soc_name = "unknown";
+		break;
+	}
+	NOTICE("BL31: Detected Allwinner %s SoC (%04x)\n", soc_name, soc_id);
+
+	generic_delay_timer_init();
+
+	fdt = sunxi_find_dtb();
+	if (fdt) {
+		const char *model;
+		int length;
+
+		model = fdt_getprop(fdt, 0, "model", &length);
+		NOTICE("BL31: Found U-Boot DTB at %p, model: %s\n", fdt,
+		     model ?: "unknown");
+	} else {
+		NOTICE("BL31: No DTB found.\n");
+	}
+
+	/* Configure the interrupt controller */
+	gicv2_driver_init(&sunxi_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	sunxi_security_setup();
+
+	/*
+	 * On the A64 U-Boot's SPL sets the bus clocks to some conservative
+	 * values, to work around FEL mode instabilities with SRAM C accesses.
+	 * FEL mode is gone when we reach ATF, so bring the AHB1 bus
+	 * (the "main" bus) clock frequency back to the recommended 200MHz,
+	 * for improved performance.
+	 */
+	if (soc_id == SUNXI_SOC_A64)
+		mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x00003180);
+
+	/*
+	 * U-Boot or the kernel don't setup AHB2, which leaves it at the
+	 * AHB1 frequency (200 MHz, see above). However Allwinner recommends
+	 * 300 MHz, for improved Ethernet and USB performance. Switch the
+	 * clock to use "PLL_PERIPH0 / 2".
+	 */
+	if (soc_id == SUNXI_SOC_A64 || soc_id == SUNXI_SOC_H5)
+		mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0x1);
+
+	sunxi_pmic_setup(soc_id, fdt);
+
+	INFO("BL31: Platform setup done\n");
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type) != 0);
+
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+
+	if ((type == SECURE) && bl32_image_ep_info.pc)
+		return &bl32_image_ep_info;
+
+	return NULL;
+}
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
new file mode 100644
index 0000000..3b44aab
--- /dev/null
+++ b/plat/allwinner/common/sunxi_common.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+static const mmap_region_t sunxi_mmap[PLATFORM_MMAP_REGIONS + 1] = {
+	MAP_REGION_FLAT(SUNXI_SRAM_BASE, SUNXI_SRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SUNXI_DEV_BASE, SUNXI_DEV_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION(SUNXI_DRAM_BASE, SUNXI_DRAM_VIRT_BASE, SUNXI_DRAM_SEC_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION(PLAT_SUNXI_NS_IMAGE_OFFSET,
+		   SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE,
+		   SUNXI_DRAM_MAP_SIZE,
+		   MT_MEMORY | MT_RO | MT_NS),
+	{},
+};
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SUNXI_OSC24M_CLK_IN_HZ;
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return PLAT_SUNXI_NS_IMAGE_OFFSET;
+#endif
+}
+
+void sunxi_configure_mmu_el3(int flags)
+{
+	mmap_add_region(BL31_BASE, BL31_BASE,
+			BL31_LIMIT - BL31_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE);
+	mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
+			BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE);
+	mmap_add(sunxi_mmap);
+	init_xlat_tables();
+
+	enable_mmu_el3(0);
+}
+
+#define SRAM_VER_REG (SUNXI_SYSCON_BASE + 0x24)
+uint16_t sunxi_read_soc_id(void)
+{
+	uint32_t reg = mmio_read_32(SRAM_VER_REG);
+
+	/* Set bit 15 to prepare for the SOCID read. */
+	mmio_write_32(SRAM_VER_REG, reg | BIT(15));
+
+	reg = mmio_read_32(SRAM_VER_REG);
+
+	/* deactivate the SOCID access again */
+	mmio_write_32(SRAM_VER_REG, reg & ~BIT(15));
+
+	return reg >> 16;
+}
+
+/*
+ * Configure a given pin to the GPIO-OUT function and sets its level.
+ * The port is given as a capital letter, the pin is the number within
+ * this port group.
+ * So to set pin PC7 to high, use: sunxi_set_gpio_out('C', 7, true);
+ */
+void sunxi_set_gpio_out(char port, int pin, bool level_high)
+{
+	uintptr_t port_base;
+
+	if (port < 'A' || port > 'L')
+		return;
+	if (port == 'L')
+		port_base = SUNXI_R_PIO_BASE;
+	else
+		port_base = SUNXI_PIO_BASE + (port - 'A') * 0x24;
+
+	/* Set the new level first before configuring the pin. */
+	if (level_high)
+		mmio_setbits_32(port_base + 0x10, BIT(pin));
+	else
+		mmio_clrbits_32(port_base + 0x10, BIT(pin));
+
+	/* configure pin as GPIO out (4(3) bits per pin, 1: GPIO out */
+	mmio_clrsetbits_32(port_base + (pin / 8) * 4,
+			   0x7 << ((pin % 8) * 4),
+			   0x1 << ((pin % 8) * 4));
+}
+
+int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb)
+{
+	uint32_t pin_func = 0x77;
+	uint32_t device_bit;
+	unsigned int reset_offset = 0xb0;
+
+	switch (socid) {
+	case SUNXI_SOC_H5:
+		if (use_rsb)
+			return -ENODEV;
+		pin_func = 0x22;
+		device_bit = BIT(6);
+		break;
+	case SUNXI_SOC_H6:
+		if (use_rsb)
+			return -ENODEV;
+		pin_func = 0x33;
+		device_bit = BIT(16);
+		reset_offset = 0x19c;
+		break;
+	case SUNXI_SOC_A64:
+		pin_func = use_rsb ? 0x22 : 0x33;
+		device_bit = use_rsb ? BIT(3) : BIT(6);
+		break;
+	default:
+		INFO("R_I2C/RSB on Allwinner 0x%x SoC not supported\n", socid);
+		return -ENODEV;
+	}
+
+	/* un-gate R_PIO clock */
+	if (socid != SUNXI_SOC_H6)
+		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, BIT(0));
+
+	/* switch pins PL0 and PL1 to the desired function */
+	mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x00, 0xffU, pin_func);
+
+	/* level 2 drive strength */
+	mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x14, 0x0fU, 0xaU);
+
+	/* set both pins to pull-up */
+	mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x1c, 0x0fU, 0x5U);
+
+	/* assert, then de-assert reset of I2C/RSB controller */
+	mmio_clrbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit);
+	mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit);
+
+	/* un-gate clock */
+	if (socid != SUNXI_SOC_H6)
+		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, device_bit);
+	else
+		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x19c, device_bit | BIT(0));
+
+	return 0;
+}
+
+/* This lock synchronises access to the arisc management processor. */
+DEFINE_BAKERY_LOCK(arisc_lock);
+
+/*
+ * Tell the "arisc" SCP core (an OpenRISC core) to execute some code.
+ * We don't have any service running there, so we place some OpenRISC code
+ * in SRAM, put the address of that into the reset vector and release the
+ * arisc reset line. The SCP will execute that code and pull the line up again.
+ */
+void sunxi_execute_arisc_code(uint32_t *code, size_t size,
+			      int patch_offset, uint16_t param)
+{
+	uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE - 0x4000 + 0x100;
+
+	do {
+		bakery_lock_get(&arisc_lock);
+		/* Wait until the arisc is in reset state. */
+		if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
+			break;
+
+		bakery_lock_release(&arisc_lock);
+	} while (1);
+
+	/* Patch up the code to feed in an input parameter. */
+	if (patch_offset >= 0 && patch_offset <= (size - 4))
+		code[patch_offset] = (code[patch_offset] & ~0xffff) | param;
+	clean_dcache_range((uintptr_t)code, size);
+
+	/*
+	 * The OpenRISC unconditional branch has opcode 0, the branch offset
+	 * is in the lower 26 bits, containing the distance to the target,
+	 * in instruction granularity (32 bits).
+	 */
+	mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
+	clean_dcache_range(arisc_reset_vec, 4);
+
+	/* De-assert the arisc reset line to let it run. */
+	mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
+
+	/*
+	 * We release the lock here, although the arisc is still busy.
+	 * But as long as it runs, the reset line is high, so other users
+	 * won't leave the loop above.
+	 * Once it has finished, the code is supposed to clear the reset line,
+	 * to signal this to other users.
+	 */
+	bakery_lock_release(&arisc_lock);
+}
diff --git a/plat/allwinner/common/sunxi_cpu_ops.c b/plat/allwinner/common/sunxi_cpu_ops.c
new file mode 100644
index 0000000..b4c9fcc
--- /dev/null
+++ b/plat/allwinner/common/sunxi_cpu_ops.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <core_off_arisc.h>
+#include <sunxi_cpucfg.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core)
+{
+	if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff)
+		return;
+
+	VERBOSE("PSCI: Disabling power to cluster %d core %d\n", cluster, core);
+
+	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xff);
+}
+
+static void sunxi_cpu_enable_power(unsigned int cluster, unsigned int core)
+{
+	if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0)
+		return;
+
+	VERBOSE("PSCI: Enabling power to cluster %d core %d\n", cluster, core);
+
+	/* Power enable sequence from original Allwinner sources */
+	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xfe);
+	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xf8);
+	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xe0);
+	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x80);
+	mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00);
+}
+
+void sunxi_cpu_off(u_register_t mpidr)
+{
+	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int core    = MPIDR_AFFLVL0_VAL(mpidr);
+
+	VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core);
+
+	/* Deassert DBGPWRDUP */
+	mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
+
+	/* We can't turn ourself off like this, but it works for other cores. */
+	if (read_mpidr() != mpidr) {
+		/* Activate the core output clamps, but not for core 0. */
+		if (core != 0)
+			mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster),
+					BIT(core));
+		/* Assert CPU power-on reset */
+		mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
+		/* Remove power from the CPU */
+		sunxi_cpu_disable_power(cluster, core);
+
+		return;
+	}
+
+	/* Simplifies assembly, all SoCs so far are single cluster anyway. */
+	assert(cluster == 0);
+
+	/*
+	 * If we are supposed to turn ourself off, tell the arisc SCP
+	 * to do that work for us. The code expects the core mask to be
+	 * patched into the first instruction.
+	 */
+	sunxi_execute_arisc_code(arisc_core_off, sizeof(arisc_core_off),
+				 0, BIT_32(core));
+}
+
+void sunxi_cpu_on(u_register_t mpidr)
+{
+	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int core    = MPIDR_AFFLVL0_VAL(mpidr);
+
+	VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core);
+
+	/* Assert CPU core reset */
+	mmio_clrbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
+	/* Assert CPU power-on reset */
+	mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
+	/* Set CPU to start in AArch64 mode */
+	mmio_setbits_32(SUNXI_CPUCFG_CLS_CTRL_REG0(cluster), BIT(24 + core));
+	/* Apply power to the CPU */
+	sunxi_cpu_enable_power(cluster, core);
+	/* Release the core output clamps */
+	mmio_clrbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core));
+	/* Deassert CPU power-on reset */
+	mmio_setbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
+	/* Deassert CPU core reset */
+	mmio_setbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core));
+	/* Assert DBGPWRDUP */
+	mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
+}
+
+void sunxi_disable_secondary_cpus(u_register_t primary_mpidr)
+{
+	unsigned int cluster;
+	unsigned int core;
+
+	for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) {
+		for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) {
+			u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
+					     (core    << MPIDR_AFF0_SHIFT) |
+					     BIT(31);
+			if (mpidr != primary_mpidr)
+				sunxi_cpu_off(mpidr);
+		}
+	}
+}
diff --git a/plat/allwinner/common/sunxi_pm.c b/plat/allwinner/common/sunxi_pm.c
new file mode 100644
index 0000000..13e1353
--- /dev/null
+++ b/plat/allwinner/common/sunxi_pm.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <sunxi_cpucfg.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define SUNXI_WDOG0_CTRL_REG		(SUNXI_R_WDOG_BASE + 0x0010)
+#define SUNXI_WDOG0_CFG_REG		(SUNXI_R_WDOG_BASE + 0x0014)
+#define SUNXI_WDOG0_MODE_REG		(SUNXI_R_WDOG_BASE + 0x0018)
+
+#define mpidr_is_valid(mpidr) ( \
+	MPIDR_AFFLVL3_VAL(mpidr) == 0 && \
+	MPIDR_AFFLVL2_VAL(mpidr) == 0 && \
+	MPIDR_AFFLVL1_VAL(mpidr) < PLATFORM_CLUSTER_COUNT && \
+	MPIDR_AFFLVL0_VAL(mpidr) < PLATFORM_MAX_CPUS_PER_CLUSTER)
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+	if (mpidr_is_valid(mpidr) == 0)
+		return PSCI_E_INTERN_FAIL;
+
+	sunxi_cpu_on(mpidr);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	gicv2_cpuif_disable();
+}
+
+static void __dead2 sunxi_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+	sunxi_cpu_off(read_mpidr());
+
+	while (1)
+		wfi();
+}
+
+static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+static void __dead2 sunxi_system_off(void)
+{
+	/* Turn off all secondary CPUs */
+	sunxi_disable_secondary_cpus(read_mpidr());
+
+	sunxi_power_down();
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+	/* Reset the whole system when the watchdog times out */
+	mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
+	/* Enable the watchdog with the shortest timeout (0.5 seconds) */
+	mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1);
+	/* Wait for twice the watchdog timeout before panicking */
+	mdelay(1000);
+
+	ERROR("PSCI: System reset failed\n");
+	wfi();
+	panic();
+}
+
+static int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+	/* The non-secure entry point must be in DRAM */
+	if (ns_entrypoint >= SUNXI_DRAM_BASE)
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+static plat_psci_ops_t sunxi_psci_ops = {
+	.pwr_domain_on			= sunxi_pwr_domain_on,
+	.pwr_domain_off			= sunxi_pwr_domain_off,
+	.pwr_domain_pwr_down_wfi	= sunxi_pwr_down_wfi,
+	.pwr_domain_on_finish		= sunxi_pwr_domain_on_finish,
+	.system_off			= sunxi_system_off,
+	.system_reset			= sunxi_system_reset,
+	.validate_ns_entrypoint		= sunxi_validate_ns_entrypoint,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	assert(psci_ops);
+
+	for (int cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu += 1) {
+		mmio_write_32(SUNXI_CPUCFG_RVBAR_LO_REG(cpu),
+			      sec_entrypoint & 0xffffffff);
+		mmio_write_32(SUNXI_CPUCFG_RVBAR_HI_REG(cpu),
+			      sec_entrypoint >> 32);
+	}
+
+	*psci_ops = &sunxi_psci_ops;
+
+	return 0;
+}
diff --git a/plat/allwinner/common/sunxi_security.c b/plat/allwinner/common/sunxi_security.c
new file mode 100644
index 0000000..1f16a0b
--- /dev/null
+++ b/plat/allwinner/common/sunxi_security.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#ifdef SUNXI_SPC_BASE
+#define SPC_DECPORT_STA_REG(p)	(SUNXI_SPC_BASE + ((p) * 0x0c) + 0x4)
+#define SPC_DECPORT_SET_REG(p)	(SUNXI_SPC_BASE + ((p) * 0x0c) + 0x8)
+#define SPC_DECPORT_CLR_REG(p)	(SUNXI_SPC_BASE + ((p) * 0x0c) + 0xc)
+#endif
+
+#define R_PRCM_SEC_SWITCH_REG	0x1d0
+#define DMA_SEC_REG		0x20
+
+/*
+ * Setup the peripherals to be accessible by non-secure world.
+ * This will not work for the Secure Peripherals Controller (SPC) unless
+ * a fuse it burnt (seems to be an erratum), but we do it nevertheless,
+ * to allow booting on boards using secure boot.
+ */
+void sunxi_security_setup(void)
+{
+#ifdef SUNXI_SPC_BASE
+	int i;
+
+	INFO("Configuring SPC Controller\n");
+	/* SPC setup: set all devices to non-secure */
+	for (i = 0; i < 6; i++)
+		mmio_write_32(SPC_DECPORT_SET_REG(i), 0xff);
+#endif
+
+	/* set MBUS clocks, bus clocks (AXI/AHB/APB) and PLLs to non-secure */
+	mmio_write_32(SUNXI_CCU_SEC_SWITCH_REG, 0x7);
+
+	/* set R_PRCM clocks to non-secure */
+	mmio_write_32(SUNXI_R_PRCM_BASE + R_PRCM_SEC_SWITCH_REG, 0x7);
+
+	/* Set all DMA channels (16 max.) to non-secure */
+	mmio_write_32(SUNXI_DMA_BASE + DMA_SEC_REG, 0xffff);
+}
diff --git a/plat/allwinner/common/sunxi_topology.c b/plat/allwinner/common/sunxi_topology.c
new file mode 100644
index 0000000..45be1e0
--- /dev/null
+++ b/plat/allwinner/common/sunxi_topology.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = {
+	/* One root node for the SoC */
+	1,
+	/* One node for each cluster */
+	PLATFORM_CLUSTER_COUNT,
+	/* One set of CPUs per cluster */
+	PLATFORM_MAX_CPUS_PER_CLUSTER,
+};
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (MPIDR_AFFLVL3_VAL(mpidr) > 0 ||
+	    MPIDR_AFFLVL2_VAL(mpidr) > 0 ||
+	    cluster >= PLATFORM_CLUSTER_COUNT ||
+	    core >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+		return -1;
+	}
+
+	return cluster * PLATFORM_MAX_CPUS_PER_CLUSTER + core;
+}
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return plat_power_domain_tree_desc;
+}
diff --git a/plat/allwinner/sun50i_a64/include/core_off_arisc.h b/plat/allwinner/sun50i_a64/include/core_off_arisc.h
new file mode 100644
index 0000000..ae436ca
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/core_off_arisc.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint32_t arisc_core_off[] = {
+	0x18600000, /* l.movhi	r3, <corenr>	*/
+	0x18000000, /* l.movhi	r0, 0x0		*/
+	0x19a00170, /* l.movhi	r13, 0x170	*/
+	0x84ad0030, /* l.lwz	r5, 0x30(r13)	*/
+	0xe0a51803, /* l.and	r5, r5, r3	*/
+	0xe4050000, /* l.sfeq	r5, r0		*/
+	0x13fffffd, /* l.bf	-12		*/
+
+	0xb8c30050, /* l.srli	r6, r3, 16	*/
+	0xbc060001, /* l.sfeqi	r6, 1		*/
+	0x10000005, /* l.bf	+20		*/
+	0x19a001f0, /* l.movhi	r13, 0x1f0	*/
+	0x84ad1500, /* l.lwz	r5, 0x1500(r13)	*/
+	0xe0a53004, /* l.or	r5, r5, r6	*/
+	0xd44d2d00, /* l.sw	0x1500(r13), r5	*/
+
+	0x84ad1c30, /* l.lwz	r5, 0x1c30(r13)	*/
+	0xacc6ffff, /* l.xori	r6, r6, -1	*/
+	0xe0a53003, /* l.and	r5, r5, r6	*/
+	0xd46d2c30, /* l.sw	0x1c30(r13), r5	*/
+
+	0xe0c3000f, /* l.ff1	r6, r3		*/
+	0x9cc6ffef, /* l.addi	r6, r6, -17	*/
+	0xb8c60002, /* l.slli	r6, r6, 2	*/
+	0xe0c66800, /* l.add	r6, r6, r13	*/
+	0xa8a000ff, /* l.ori	r5, r0, 0xff	*/
+	0xd4462d40, /* l.sw	0x1540(r6), r5	*/
+
+	0xd46d0400, /* l.sw	0x1c00(r13), r0	*/
+	0x03ffffff, /* l.j	-1		*/
+	0x15000000, /* l.nop			*/
+};
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..c3eeadb
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CPUCFG_H
+#define SUNXI_CPUCFG_H
+
+#include <sunxi_mmap.h>
+
+/* c = cluster, n = core */
+#define SUNXI_CPUCFG_CLS_CTRL_REG0(c)	(SUNXI_CPUCFG_BASE + 0x0000 + (c) * 16)
+#define SUNXI_CPUCFG_CLS_CTRL_REG1(c)	(SUNXI_CPUCFG_BASE + 0x0004 + (c) * 16)
+#define SUNXI_CPUCFG_CACHE_CFG_REG0	(SUNXI_CPUCFG_BASE + 0x0008)
+#define SUNXI_CPUCFG_CACHE_CFG_REG1	(SUNXI_CPUCFG_BASE + 0x000c)
+#define SUNXI_CPUCFG_DBG_REG0		(SUNXI_CPUCFG_BASE + 0x0020)
+#define SUNXI_CPUCFG_GLB_CTRL_REG	(SUNXI_CPUCFG_BASE + 0x0028)
+#define SUNXI_CPUCFG_CPU_STS_REG(c)	(SUNXI_CPUCFG_BASE + 0x0030 + (c) * 4)
+#define SUNXI_CPUCFG_L2_STS_REG		(SUNXI_CPUCFG_BASE + 0x003c)
+#define SUNXI_CPUCFG_RST_CTRL_REG(c)	(SUNXI_CPUCFG_BASE + 0x0080 + (c) * 4)
+#define SUNXI_CPUCFG_RVBAR_LO_REG(n)	(SUNXI_CPUCFG_BASE + 0x00a0 + (n) * 8)
+#define SUNXI_CPUCFG_RVBAR_HI_REG(n)	(SUNXI_CPUCFG_BASE + 0x00a4 + (n) * 8)
+
+#define SUNXI_CPU_POWER_CLAMP_REG(c, n)	(SUNXI_R_PRCM_BASE + 0x0140 + \
+					 (c) * 16 + (n) * 4)
+#define SUNXI_POWEROFF_GATING_REG(c)	(SUNXI_R_PRCM_BASE + 0x0100 + (c) * 4)
+#define SUNXI_R_CPUCFG_CPUS_RST_REG	(SUNXI_R_CPUCFG_BASE + 0x0000)
+#define SUNXI_POWERON_RST_REG(c)	(SUNXI_R_CPUCFG_BASE + 0x0030 + (c) * 4)
+#define SUNXI_R_CPUCFG_SYS_RST_REG	(SUNXI_R_CPUCFG_BASE + 0x0140)
+#define SUNXI_R_CPUCFG_SS_FLAG_REG	(SUNXI_R_CPUCFG_BASE + 0x01a0)
+#define SUNXI_R_CPUCFG_CPU_ENTRY_REG	(SUNXI_R_CPUCFG_BASE + 0x01a4)
+#define SUNXI_R_CPUCFG_SS_ENTRY_REG	(SUNXI_R_CPUCFG_BASE + 0x01a8)
+#define SUNXI_R_CPUCFG_HP_FLAG_REG	(SUNXI_R_CPUCFG_BASE + 0x01ac)
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_mmap.h b/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
new file mode 100644
index 0000000..db44091
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_MMAP_H
+#define SUNXI_MMAP_H
+
+/* Memory regions */
+#define SUNXI_ROM_BASE			0x00000000
+#define SUNXI_ROM_SIZE			0x00010000
+#define SUNXI_SRAM_BASE			0x00010000
+#define SUNXI_SRAM_SIZE			0x00044000
+#define SUNXI_SRAM_A1_BASE		0x00010000
+#define SUNXI_SRAM_A1_SIZE		0x00008000
+#define SUNXI_SRAM_A2_BASE		0x00044000
+#define SUNXI_SRAM_A2_SIZE		0x00010000
+#define SUNXI_SRAM_C_BASE		0x00018000
+#define SUNXI_SRAM_C_SIZE		0x0001c000
+#define SUNXI_DEV_BASE			0x01000000
+#define SUNXI_DEV_SIZE			0x01000000
+#define SUNXI_DRAM_BASE			0x40000000
+#define SUNXI_DRAM_VIRT_BASE		0x02000000
+
+/* Memory-mapped devices */
+#define SUNXI_CPU_MBIST_BASE		0x01502000
+#define SUNXI_CPUCFG_BASE		0x01700000
+#define SUNXI_SYSCON_BASE		0x01c00000
+#define SUNXI_DMA_BASE			0x01c02000
+#define SUNXI_KEYMEM_BASE		0x01c0b000
+#define SUNXI_SMHC0_BASE		0x01c0f000
+#define SUNXI_SMHC1_BASE		0x01c10000
+#define SUNXI_SMHC2_BASE		0x01c11000
+#define SUNXI_SID_BASE			0x01c14000
+#define SUNXI_MSGBOX_BASE		0x01c17000
+#define SUNXI_SPINLOCK_BASE		0x01c18000
+#define SUNXI_CCU_BASE			0x01c20000
+#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0x2f0)
+#define SUNXI_PIO_BASE			0x01c20800
+#define SUNXI_TIMER_BASE		0x01c20c00
+#define SUNXI_WDOG_BASE			0x01c20ca0
+#define SUNXI_SPC_BASE			0x01c23400
+#define SUNXI_THS_BASE			0x01c25000
+#define SUNXI_UART0_BASE		0x01c28000
+#define SUNXI_UART1_BASE		0x01c28400
+#define SUNXI_UART2_BASE		0x01c28800
+#define SUNXI_UART3_BASE		0x01c28c00
+#define SUNXI_I2C0_BASE			0x01c2ac00
+#define SUNXI_I2C1_BASE			0x01c2b000
+#define SUNXI_I2C2_BASE			0x01c2b400
+#define SUNXI_DRAMCOM_BASE		0x01c62000
+#define SUNXI_DRAMCTL_BASE		0x01c63000
+#define SUNXI_DRAMPHY_BASE		0x01c65000
+#define SUNXI_SPI0_BASE			0x01c68000
+#define SUNXI_SPI1_BASE			0x01c69000
+#define SUNXI_SCU_BASE			0x01c80000
+#define SUNXI_GICD_BASE			0x01c81000
+#define SUNXI_GICC_BASE			0x01c82000
+#define SUNXI_RTC_BASE			0x01f00000
+#define SUNXI_R_TIMER_BASE		0x01f00800
+#define SUNXI_R_INTC_BASE		0x01f00c00
+#define SUNXI_R_WDOG_BASE		0x01f01000
+#define SUNXI_R_PRCM_BASE		0x01f01400
+#define SUNXI_R_TWD_BASE		0x01f01800
+#define SUNXI_R_CPUCFG_BASE		0x01f01c00
+#define SUNXI_R_CIR_BASE		0x01f02000
+#define SUNXI_R_I2C_BASE		0x01f02400
+#define SUNXI_R_UART_BASE		0x01f02800
+#define SUNXI_R_PIO_BASE		0x01f02c00
+#define SUNXI_R_RSB_BASE		0x01f03400
+#define SUNXI_R_PWM_BASE		0x01f03800
+
+#endif /* SUNXI_MMAP_H */
diff --git a/plat/allwinner/sun50i_a64/platform.mk b/plat/allwinner/sun50i_a64/platform.mk
new file mode 100644
index 0000000..b46fbc2
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/platform.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# The differences between the platform are covered by the include files.
+include plat/allwinner/common/allwinner-common.mk
+
+PLAT_BL_COMMON_SOURCES	+=	drivers/allwinner/sunxi_rsb.c
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
new file mode 100644
index 0000000..07a3716
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/allwinner/sunxi_rsb.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+static enum pmic_type {
+	GENERIC_H5,
+	GENERIC_A64,
+	REF_DESIGN_H5,	/* regulators controlled by GPIO pins on port L */
+	AXP803_RSB,	/* PMIC connected via RSB on most A64 boards */
+} pmic;
+
+#define AXP803_HW_ADDR	0x3a3
+#define AXP803_RT_ADDR	0x2d
+
+/*
+ * On boards without a proper PMIC we struggle to turn off the system properly.
+ * Try to turn off as much off the system as we can, to reduce power
+ * consumption. This should be entered with only one core running and SMP
+ * disabled.
+ * This function only cares about peripherals.
+ */
+void sunxi_turn_off_soc(uint16_t socid)
+{
+	int i;
+
+	/** Turn off most peripherals, most importantly DRAM users. **/
+	/* Keep DRAM controller running for now. */
+	mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14));
+	mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14));
+	/* Contains msgbox (bit 21) and spinlock (bit 22) */
+	mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0);
+	mmio_write_32(SUNXI_CCU_BASE + 0x64, 0);
+	mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0);
+	/* Keep PIO controller running for now. */
+	mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5)));
+	mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0);
+	/* Contains UART0 (bit 16) */
+	mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0);
+	mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0);
+	mmio_write_32(SUNXI_CCU_BASE + 0x70, 0);
+
+	/** Turn off DRAM controller. **/
+	mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14));
+	mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14));
+
+	/** Migrate CPU and bus clocks away from the PLLs. **/
+	/* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */
+	mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000);
+	/* APB2: use OSC24M */
+	mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000);
+	/* AHB2: use AHB1 clock */
+	mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0);
+	/* CPU: use OSC24M */
+	mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000);
+
+	/** Turn off PLLs. **/
+	for (i = 0; i < 6; i++)
+		mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31));
+	switch (socid) {
+	case SUNXI_SOC_H5:
+		mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31));
+		break;
+	case SUNXI_SOC_A64:
+		mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31));
+		mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31));
+		break;
+	}
+}
+
+static int rsb_init(void)
+{
+	int ret;
+
+	ret = rsb_init_controller();
+	if (ret)
+		return ret;
+
+	/* Start with 400 KHz to issue the I2C->RSB switch command. */
+	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 400000);
+	if (ret)
+		return ret;
+
+	/*
+	 * Initiate an I2C transaction to write 0x7c into register 0x3e,
+	 * switching the PMIC to RSB mode.
+	 */
+	ret = rsb_set_device_mode(0x7c3e00);
+	if (ret)
+		return ret;
+
+	/* Now in RSB mode, switch to the recommended 3 MHz. */
+	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
+	if (ret)
+		return ret;
+
+	/* Associate the 8-bit runtime address with the 12-bit bus address. */
+	return rsb_assign_runtime_address(AXP803_HW_ADDR,
+					  AXP803_RT_ADDR);
+}
+
+static int axp_write(uint8_t reg, uint8_t val)
+{
+	return rsb_write(AXP803_RT_ADDR, reg, val);
+}
+
+static int axp_clrsetbits(uint8_t reg, uint8_t clr_mask, uint8_t set_mask)
+{
+	uint8_t regval;
+	int ret;
+
+	ret = rsb_read(AXP803_RT_ADDR, reg);
+	if (ret < 0)
+		return ret;
+
+	regval = (ret & ~clr_mask) | set_mask;
+
+	return rsb_write(AXP803_RT_ADDR, reg, regval);
+}
+
+#define axp_clrbits(reg, clr_mask) axp_clrsetbits(reg, clr_mask, 0)
+#define axp_setbits(reg, set_mask) axp_clrsetbits(reg, 0, set_mask)
+
+static bool should_enable_regulator(const void *fdt, int node)
+{
+	if (fdt_getprop(fdt, node, "phandle", NULL) != NULL)
+		return true;
+	if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL)
+		return true;
+	return false;
+}
+
+/*
+ * Retrieve the voltage from a given regulator DTB node.
+ * Both the regulator-{min,max}-microvolt properties must be present and
+ * have the same value. Return that value in millivolts.
+ */
+static int fdt_get_regulator_millivolt(const void *fdt, int node)
+{
+	const fdt32_t *prop;
+	uint32_t min_volt;
+
+	prop = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
+	if (prop == NULL)
+		return -EINVAL;
+	min_volt = fdt32_to_cpu(*prop);
+
+	prop = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
+	if (prop == NULL)
+		return -EINVAL;
+
+	if (fdt32_to_cpu(*prop) != min_volt)
+		return -EINVAL;
+
+	return min_volt / 1000;
+}
+
+#define NO_SPLIT 0xff
+
+static const struct axp_regulator {
+	char *dt_name;
+	uint16_t min_volt;
+	uint16_t max_volt;
+	uint16_t step;
+	unsigned char split;
+	unsigned char volt_reg;
+	unsigned char switch_reg;
+	unsigned char switch_bit;
+} regulators[] = {
+	{"dcdc1", 1600, 3400, 100, NO_SPLIT, 0x20, 0x10, 0},
+	{"dcdc5",  800, 1840,  10,       32, 0x24, 0x10, 4},
+	{"dcdc6",  600, 1520,  10,       50, 0x25, 0x10, 5},
+	{"dldo1",  700, 3300, 100, NO_SPLIT, 0x15, 0x12, 3},
+	{"dldo2",  700, 4200, 100,       27, 0x16, 0x12, 4},
+	{"dldo3",  700, 3300, 100, NO_SPLIT, 0x17, 0x12, 5},
+	{"fldo1",  700, 1450,  50, NO_SPLIT, 0x1c, 0x13, 2},
+	{}
+};
+
+static int setup_regulator(const void *fdt, int node,
+			   const struct axp_regulator *reg)
+{
+	int mvolt;
+	uint8_t regval;
+
+	if (!should_enable_regulator(fdt, node))
+		return -ENOENT;
+
+	mvolt = fdt_get_regulator_millivolt(fdt, node);
+	if (mvolt < reg->min_volt || mvolt > reg->max_volt)
+		return -EINVAL;
+
+	regval = (mvolt / reg->step) - (reg->min_volt / reg->step);
+	if (regval > reg->split)
+		regval = ((regval - reg->split) / 2) + reg->split;
+
+	axp_write(reg->volt_reg, regval);
+	if (reg->switch_reg < 0xff)
+		axp_setbits(reg->switch_reg, BIT(reg->switch_bit));
+
+	INFO("PMIC: AXP803: %s voltage: %d.%03dV\n", reg->dt_name,
+	     mvolt / 1000, mvolt % 1000);
+
+	return 0;
+}
+
+static void setup_axp803_rails(const void *fdt)
+{
+	int node;
+	bool dc1sw = false;
+
+	/* locate the PMIC DT node, bail out if not found */
+	node = fdt_node_offset_by_compatible(fdt, -1, "x-powers,axp803");
+	if (node < 0) {
+		WARN("BL31: PMIC: Cannot find AXP803 DT node, skipping initial setup.\n");
+		return;
+	}
+
+	if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) {
+		axp_clrbits(0x8f, BIT(4));
+		axp_setbits(0x30, BIT(2));
+		INFO("PMIC: AXP803: Enabling DRIVEVBUS\n");
+	}
+
+	/* descend into the "regulators" subnode */
+	node = fdt_subnode_offset(fdt, node, "regulators");
+	if (node < 0) {
+		WARN("BL31: PMIC: Cannot find regulators subnode, skipping initial setup.\n");
+		return;
+	}
+
+	/* iterate over all regulators to find used ones */
+	for (node = fdt_first_subnode(fdt, node);
+	     node >= 0;
+	     node = fdt_next_subnode(fdt, node)) {
+		const struct axp_regulator *reg;
+		const char *name;
+		int length;
+
+		/* We only care if it's always on or referenced. */
+		if (!should_enable_regulator(fdt, node))
+			continue;
+
+		name = fdt_get_name(fdt, node, &length);
+		for (reg = regulators; reg->dt_name; reg++) {
+			if (!strncmp(name, reg->dt_name, length)) {
+				setup_regulator(fdt, node, reg);
+				break;
+			}
+		}
+
+		if (!strncmp(name, "dc1sw", length)) {
+			/* Delay DC1SW enablement to avoid overheating. */
+			dc1sw = true;
+			continue;
+		}
+	}
+	/*
+	 * If DLDO2 is enabled after DC1SW, the PMIC overheats and shuts
+	 * down. So always enable DC1SW as the very last regulator.
+	 */
+	if (dc1sw) {
+		INFO("PMIC: AXP803: Enabling DC1SW\n");
+		axp_setbits(0x12, BIT(7));
+	}
+}
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+	int ret;
+
+	switch (socid) {
+	case SUNXI_SOC_H5:
+		pmic = REF_DESIGN_H5;
+		NOTICE("BL31: PMIC: Defaulting to PortL GPIO according to H5 reference design.\n");
+		break;
+	case SUNXI_SOC_A64:
+		pmic = GENERIC_A64;
+		ret = sunxi_init_platform_r_twi(socid, true);
+		if (ret)
+			return ret;
+
+		ret = rsb_init();
+		if (ret)
+			return ret;
+
+		pmic = AXP803_RSB;
+		NOTICE("BL31: PMIC: Detected AXP803 on RSB.\n");
+
+		if (fdt)
+			setup_axp803_rails(fdt);
+
+		break;
+	default:
+		NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+void __dead2 sunxi_power_down(void)
+{
+	switch (pmic) {
+	case GENERIC_H5:
+		/* Turn off as many peripherals and clocks as we can. */
+		sunxi_turn_off_soc(SUNXI_SOC_H5);
+		/* Turn off the pin controller now. */
+		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
+		break;
+	case GENERIC_A64:
+		/* Turn off as many peripherals and clocks as we can. */
+		sunxi_turn_off_soc(SUNXI_SOC_A64);
+		/* Turn off the pin controller now. */
+		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
+		break;
+	case REF_DESIGN_H5:
+		sunxi_turn_off_soc(SUNXI_SOC_H5);
+
+		/*
+		 * Switch PL pins to power off the board:
+		 * - PL5 (VCC_IO) -> high
+		 * - PL8 (PWR-STB = CPU power supply) -> low
+		 * - PL9 (PWR-DRAM) ->low
+		 * - PL10 (power LED) -> low
+		 * Note: Clearing PL8 will reset the board, so keep it up.
+		 */
+		sunxi_set_gpio_out('L', 5, 1);
+		sunxi_set_gpio_out('L', 9, 0);
+		sunxi_set_gpio_out('L', 10, 0);
+
+		/* Turn off pin controller now. */
+		mmio_write_32(SUNXI_CCU_BASE + 0x68, 0);
+
+		break;
+	case AXP803_RSB:
+		/* (Re-)init RSB in case the rich OS has disabled it. */
+		sunxi_init_platform_r_twi(SUNXI_SOC_A64, true);
+		rsb_init();
+
+		/* Set "power disable control" bit */
+		axp_setbits(0x32, BIT(7));
+		break;
+	default:
+		break;
+	}
+
+	udelay(1000);
+	ERROR("PSCI: Cannot turn off system, halting.\n");
+	wfi();
+	panic();
+}
diff --git a/plat/allwinner/sun50i_h6/include/core_off_arisc.h b/plat/allwinner/sun50i_h6/include/core_off_arisc.h
new file mode 100644
index 0000000..63a5d8d
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/core_off_arisc.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static uint32_t arisc_core_off[] = {
+	0x18600000, /* l.movhi	r3, <corenr>	*/
+	0x18000000, /* l.movhi	r0, 0x0		*/
+	0x19a00901, /* l.movhi	r13, 0x901	*/
+	0x84ad0080, /* l.lwz	r5, 0x80(r13)	*/
+	0xe0a51803, /* l.and	r5, r5, r3	*/
+	0xe4050000, /* l.sfeq	r5, r0		*/
+	0x13fffffd, /* l.bf	-12		*/
+	0xb8c30050, /* l.srli	r6, r3, 16	*/
+
+	0xbc060001, /* l.sfeqi	r6, 1		*/
+	0x10000005, /* l.bf	+20		*/
+	0x19a00700, /* l.movhi	r13, 0x700	*/
+	0x84ad0444, /* l.lwz	r5, 0x0444(r13)	*/
+	0xe0a53004, /* l.or	r5, r5, r6	*/
+	0xd40d2c44, /* l.sw	0x0444(r13), r5	*/
+
+	0x84ad0440, /* l.lwz	r5, 0x0440(r13)	*/
+	0xacc6ffff, /* l.xori	r6, r6, -1	*/
+	0xe0a53003, /* l.and	r5, r5, r6	*/
+	0xd40d2c40, /* l.sw	0x0440(r13), r5	*/
+
+	0xe0c3000f, /* l.ff1	r6, r3		*/
+	0x9cc6ffef, /* l.addi	r6, r6, -17	*/
+	0xb8c60002, /* l.slli	r6, r6, 2	*/
+	0xe0c66800, /* l.add	r6, r6, r13	*/
+	0xa8a000ff, /* l.ori	r5, r0, 0xff	*/
+	0xd4062c50, /* l.sw	0x0450(r6), r5	*/
+
+	0xd40d0400, /* l.sw	0x0400(r13), r0	*/
+	0x03ffffff, /* l.j	-1		*/
+	0x15000000, /* l.nop			*/
+};
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h b/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h
new file mode 100644
index 0000000..556fb97
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CPUCFG_H
+#define SUNXI_CPUCFG_H
+
+#include <sunxi_mmap.h>
+
+/* c = cluster, n = core */
+#define SUNXI_CPUCFG_CLS_CTRL_REG0(c)	(SUNXI_CPUCFG_BASE + 0x0010 + (c) * 0x10)
+#define SUNXI_CPUCFG_CLS_CTRL_REG1(c)	(SUNXI_CPUCFG_BASE + 0x0014 + (c) * 0x10)
+#define SUNXI_CPUCFG_CACHE_CFG_REG	(SUNXI_CPUCFG_BASE + 0x0024)
+#define SUNXI_CPUCFG_DBG_REG0		(SUNXI_CPUCFG_BASE + 0x00c0)
+
+#define SUNXI_CPUCFG_RST_CTRL_REG(c)	(SUNXI_CPUCFG_BASE + 0x0000 + (c) * 4)
+#define SUNXI_CPUCFG_RVBAR_LO_REG(n)	(SUNXI_CPUCFG_BASE + 0x0040 + (n) * 8)
+#define SUNXI_CPUCFG_RVBAR_HI_REG(n)	(SUNXI_CPUCFG_BASE + 0x0044 + (n) * 8)
+
+#define SUNXI_POWERON_RST_REG(c)	(SUNXI_R_CPUCFG_BASE + 0x0040 + (c) * 4)
+#define SUNXI_POWEROFF_GATING_REG(c)	(SUNXI_R_CPUCFG_BASE + 0x0044 + (c) * 4)
+#define SUNXI_CPU_POWER_CLAMP_REG(c, n)	(SUNXI_R_CPUCFG_BASE + 0x0050 + \
+					(c) * 0x10 + (n) * 4)
+
+#endif /* SUNXI_CPUCFG_H */
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_mmap.h b/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
new file mode 100644
index 0000000..f36491a
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_MMAP_H
+#define SUNXI_MMAP_H
+
+/* Memory regions */
+#define SUNXI_ROM_BASE			0x00000000
+#define SUNXI_ROM_SIZE			0x00010000
+#define SUNXI_SRAM_BASE			0x00020000
+#define SUNXI_SRAM_SIZE			0x000f8000
+#define SUNXI_SRAM_A1_BASE		0x00020000
+#define SUNXI_SRAM_A1_SIZE		0x00008000
+#define SUNXI_SRAM_A2_BASE		0x00104000
+#define SUNXI_SRAM_A2_SIZE		0x00014000
+#define SUNXI_SRAM_C_BASE		0x00028000
+#define SUNXI_SRAM_C_SIZE		0x0001e000
+#define SUNXI_DEV_BASE			0x01000000
+#define SUNXI_DEV_SIZE			0x09000000
+#define SUNXI_DRAM_BASE			0x40000000
+#define SUNXI_DRAM_VIRT_BASE		0x0a000000
+
+/* Memory-mapped devices */
+#define SUNXI_SYSCON_BASE		0x03000000
+#define SUNXI_CPUCFG_BASE		0x09010000
+#define SUNXI_SID_BASE			0x03006000
+#define SUNXI_DMA_BASE			0x03002000
+#define SUNXI_MSGBOX_BASE		0x03003000
+#define SUNXI_CCU_BASE			0x03010000
+#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0xf00)
+#define SUNXI_PIO_BASE			0x030b0000
+#define SUNXI_TIMER_BASE		0x03009000
+#define SUNXI_WDOG_BASE			0x030090a0
+#define SUNXI_THS_BASE			0x05070400
+#define SUNXI_UART0_BASE		0x05000000
+#define SUNXI_UART1_BASE		0x05000400
+#define SUNXI_UART2_BASE		0x05000800
+#define SUNXI_UART3_BASE		0x05000c00
+#define SUNXI_I2C0_BASE			0x05002000
+#define SUNXI_I2C1_BASE			0x05002400
+#define SUNXI_I2C2_BASE			0x05002800
+#define SUNXI_I2C3_BASE			0x05002c00
+#define SUNXI_SPI0_BASE			0x05010000
+#define SUNXI_SPI1_BASE			0x05011000
+#define SUNXI_SCU_BASE			0x03020000
+#define SUNXI_GICD_BASE			0x03021000
+#define SUNXI_GICC_BASE			0x03022000
+#define SUNXI_R_TIMER_BASE		0x07020000
+#define SUNXI_R_INTC_BASE		0x07021000
+#define SUNXI_R_WDOG_BASE		0x07020400
+#define SUNXI_R_PRCM_BASE		0x07010000
+#define SUNXI_R_TWD_BASE		0x07020800
+#define SUNXI_R_CPUCFG_BASE		0x07000400
+#define SUNXI_R_I2C_BASE		0x07081400
+#define SUNXI_R_UART_BASE		0x07080000
+#define SUNXI_R_PIO_BASE		0x07022000
+
+#endif /* SUNXI_MMAP_H */
diff --git a/plat/allwinner/sun50i_h6/platform.mk b/plat/allwinner/sun50i_h6/platform.mk
new file mode 100644
index 0000000..5c21ead
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/platform.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# The differences between the platform are covered by the include files.
+include plat/allwinner/common/allwinner-common.mk
+
+PLAT_BL_COMMON_SOURCES	+=	drivers/mentor/i2c/mi2cv.c
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
new file mode 100644
index 0000000..5b5bad1
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <sunxi_def.h>
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define AXP805_ADDR	0x36
+#define AXP805_ID	0x03
+
+enum pmic_type {
+	NO_PMIC,
+	AXP805,
+};
+
+enum pmic_type pmic;
+
+int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
+{
+	int ret;
+
+	ret = i2c_write(chip, 0, 0, &reg, 1);
+	if (ret)
+		return ret;
+
+	return i2c_read(chip, 0, 0, val, 1);
+}
+
+int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
+{
+	return i2c_write(chip, reg, 1, &val, 1);
+}
+
+static int axp805_probe(void)
+{
+	int ret;
+	uint8_t val;
+
+	ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
+	if (ret) {
+		ERROR("PMIC: Cannot put AXP805 to master mode.\n");
+		return -EPERM;
+	}
+
+	ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
+
+	if (!ret && ((val & 0xcf) == 0x40))
+		NOTICE("PMIC: AXP805 detected\n");
+	else if (ret) {
+		ERROR("PMIC: Cannot communicate with AXP805.\n");
+		return -EPERM;
+	} else {
+		ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int sunxi_pmic_setup(uint16_t socid, const void *fdt)
+{
+	int ret;
+
+	sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
+	/* initialise mi2cv driver */
+	i2c_init((void *)SUNXI_R_I2C_BASE);
+
+	NOTICE("PMIC: Probing AXP805\n");
+	pmic = AXP805;
+
+	ret = axp805_probe();
+	if (ret)
+		pmic = NO_PMIC;
+	else
+		pmic = AXP805;
+
+	return 0;
+}
+
+void __dead2 sunxi_power_down(void)
+{
+	uint8_t val;
+
+	switch (pmic) {
+	case AXP805:
+		/* Re-initialise after rich OS might have used it. */
+		sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
+		/* initialise mi2cv driver */
+		i2c_init((void *)SUNXI_R_I2C_BASE);
+		axp_i2c_read(AXP805_ADDR, 0x32, &val);
+		axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80);
+		break;
+	default:
+		break;
+	}
+
+	udelay(1000);
+	ERROR("PSCI: Cannot communicate with PMIC, halting\n");
+	wfi();
+	panic();
+}
diff --git a/plat/arm/board/a5ds/a5ds_bl1_setup.c b/plat/arm/board/a5ds/a5ds_bl1_setup.c
new file mode 100644
index 0000000..629c928
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_bl1_setup.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	arm_bl1_early_platform_setup();
+}
+
+void bl1_platform_setup(void)
+{
+	arm_bl1_platform_setup();
+}
diff --git a/plat/arm/board/a5ds/a5ds_bl2_setup.c b/plat/arm/board/a5ds/a5ds_bl2_setup.c
new file mode 100644
index 0000000..1979c50
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_bl2_setup.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+	u_register_t arg2, u_register_t arg3)
+{
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+}
+
+void bl2_platform_setup(void)
+{
+	arm_bl2_platform_setup();
+}
diff --git a/plat/arm/board/a5ds/a5ds_common.c b/plat/arm/board/a5ds/a5ds_common.c
new file mode 100644
index 0000000..e462fa1
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_common.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+
+#define MAP_PERIPHBASE	MAP_REGION_FLAT(PERIPHBASE,\
+					PERIPH_SIZE,\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_A5_PERIPHERALS	MAP_REGION_FLAT(A5_PERIPHERALS_BASE,\
+					A5_PERIPHERALS_SIZE,\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#ifdef IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	MAP_FLASH1_RW,
+	MAP_PERIPHBASE,
+	MAP_A5_PERIPHERALS,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	MAP_FLASH1_RW,
+	MAP_PERIPHBASE,
+	MAP_A5_PERIPHERALS,
+	ARM_MAP_NS_DRAM1,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL32
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	MAP_PERIPHBASE,
+	MAP_A5_PERIPHERALS,
+	{0}
+};
+#endif
+
+ARM_CASSERT_MMAP
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return A5DS_TIMER_BASE_FREQUENCY;
+}
diff --git a/plat/arm/board/a5ds/a5ds_err.c b/plat/arm/board/a5ds/a5ds_err.c
new file mode 100644
index 0000000..65b41dd
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * a5ds error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	while (1) {
+		wfi();
+	}
+}
diff --git a/plat/arm/board/a5ds/a5ds_pm.c b/plat/arm/board/a5ds/a5ds_pm.c
new file mode 100644
index 0000000..5fd443b
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_pm.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Export the platform handlers via a5ds_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+plat_psci_ops_t a5ds_psci_pm_ops = {
+	/* dummy struct */
+	.validate_ns_entrypoint = NULL,
+};
+
+int __init plat_setup_psci_ops(uintptr_t sec_entrypoint,
+				const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &a5ds_psci_pm_ops;
+
+	return 0;
+}
diff --git a/plat/arm/board/a5ds/a5ds_private.h b/plat/arm/board/a5ds/a5ds_private.h
new file mode 100644
index 0000000..f577249
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_private.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef A5DS_PRIVATE_H
+#define A5DS_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void a5ds_config_setup(void);
+
+#endif /* A5DS_PRIVATE_H */
diff --git a/plat/arm/board/a5ds/a5ds_security.c b/plat/arm/board/a5ds/a5ds_security.c
new file mode 100644
index 0000000..5593ae0
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_security.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * We assume that all security programming is done by the primary core.
+ */
+void plat_arm_security_setup(void)
+{
+	/*
+	 * The platform currently does not have any security setup.
+	 */
+}
diff --git a/plat/arm/board/a5ds/a5ds_topology.c b/plat/arm/board/a5ds/a5ds_topology.c
new file mode 100644
index 0000000..94fa71f
--- /dev/null
+++ b/plat/arm/board/a5ds/a5ds_topology.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+/* The A5DS power domain tree descriptor */
+static const unsigned char a5ds_power_domain_tree_desc[] = {
+	1,
+	/* No of children for the root node */
+	A5DS_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	A5DS_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the topology according to A5DS_CLUSTER_COUNT.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return a5ds_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * Get core position using mpidr
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= A5DS_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= A5DS_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+
+}
diff --git a/plat/arm/board/a5ds/aarch32/a5ds_helpers.S b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
new file mode 100644
index 0000000..23a22d9
--- /dev/null
+++ b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+
+	/* --------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * For AArch32, cold-booting secondary CPUs is not yet
+	 * implemented and they panic.
+	 * --------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+cb_panic:
+	wfi
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and warm
+	 * boot.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* TODO support warm boot */
+	/* Cold reset */
+	mov	r0, #0
+	bx	lr
+
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	ldcopr	r0, MPIDR
+	ldr	r1, =MPIDR_AFFINITY_MASK
+	and	r0, r1
+	cmp	r0, #0
+	moveq	r0, #1
+	movne	r0, #0
+	bx	lr
+endfunc plat_is_my_cpu_primary
diff --git a/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts b/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts
new file mode 100644
index 0000000..9ab2d96
--- /dev/null
+++ b/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	plat_arm_bl2 {
+		compatible = "arm,tb_fw";
+		hw_config_addr = <0x0 0x82000000>;
+		hw_config_max_size = <0x01000000>;
+		/* Disable authentication for development */
+		disable_auth = <0x0>;
+	};
+};
diff --git a/plat/arm/board/a5ds/include/platform_def.h b/plat/arm/board/a5ds/include/platform_def.h
new file mode 100644
index 0000000..db65c37
--- /dev/null
+++ b/plat/arm/board/a5ds/include/platform_def.h
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/common/common_def.h>
+
+/* Memory location options for TSP */
+#define ARM_DRAM_ID			2
+
+#define ARM_DRAM1_BASE			UL(0x80000000)
+#define ARM_DRAM1_SIZE			UL(0x80000000)
+#define ARM_DRAM1_END			(ARM_DRAM1_BASE +		\
+					 ARM_DRAM1_SIZE - 1)
+
+#define ARM_NS_DRAM1_BASE		ARM_DRAM1_BASE
+/*
+ * The last 2MB is meant to be NOLOAD and will not be zero
+ * initialized.
+ */
+#define ARM_NS_DRAM1_SIZE		(ARM_DRAM1_SIZE -		\
+					 0x00200000)
+
+#define SRAM_BASE	0x2000000
+#define SRAM_SIZE	0x200000
+
+/* The first 4KB of NS DRAM1 are used as shared memory */
+#define A5DS_SHARED_RAM_BASE		SRAM_BASE
+#define A5DS_SHARED_RAM_SIZE		UL(0x00001000)	/* 4 KB */
+
+/* The next 252 kB of NS DRAM is used to load the BL images */
+#define ARM_BL_RAM_BASE	(A5DS_SHARED_RAM_BASE +	\
+					 A5DS_SHARED_RAM_SIZE)
+#define ARM_BL_RAM_SIZE	(PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE -	\
+					 A5DS_SHARED_RAM_SIZE)
+
+#define PERIPHBASE 0x1a000000
+#define PERIPH_SIZE  0x00240000
+#define A5_PERIPHERALS_BASE 0x1c000000
+#define A5_PERIPHERALS_SIZE  0x10000
+
+#define ARM_CACHE_WRITEBACK_SHIFT	6
+
+#define ARM_IRQ_SEC_PHY_TIMER		29
+
+#define ARM_IRQ_SEC_SGI_0		8
+#define ARM_IRQ_SEC_SGI_1		9
+#define ARM_IRQ_SEC_SGI_2		10
+#define ARM_IRQ_SEC_SGI_3		11
+#define ARM_IRQ_SEC_SGI_4		12
+#define ARM_IRQ_SEC_SGI_5		13
+#define ARM_IRQ_SEC_SGI_6		14
+#define ARM_IRQ_SEC_SGI_7		15
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE)
+
+#define ARM_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE)
+
+#define A5DS_IRQ_TZ_WDOG			56
+#define A5DS_IRQ_SEC_SYS_TIMER		57
+
+/* Default cluster count for A5DS */
+#define A5DS_CLUSTER_COUNT	1
+
+/* Default number of CPUs per cluster on A5DS */
+#define A5DS_MAX_CPUS_PER_CLUSTER	4
+
+/* Default number of threads per CPU on A5DS */
+#define A5DS_MAX_PE_PER_CPU	1
+
+#define A5DS_CORE_COUNT 1
+
+#define A5DS_PRIMARY_CPU			0x0
+
+#define FLASH1_BASE			UL(0x8000000)
+#define FLASH1_SIZE			UL(0x2800000)
+
+#define MAP_FLASH1_RW		MAP_REGION_FLAT(FLASH1_BASE,\
+						FLASH1_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_FLASH1_RO		MAP_REGION_FLAT(FLASH1_BASE,\
+						FLASH1_SIZE,	\
+						MT_RO_DATA | MT_SECURE)
+
+#define ARM_MAP_SHARED_RAM		MAP_REGION_FLAT(		\
+						A5DS_SHARED_RAM_BASE,	\
+						A5DS_SHARED_RAM_SIZE,	\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+#define ARM_MAP_NS_DRAM1		MAP_REGION_FLAT(		\
+						ARM_NS_DRAM1_BASE,	\
+						ARM_NS_DRAM1_SIZE,	\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define ARM_MAP_SRAM		MAP_REGION_FLAT(		\
+						SRAM_BASE,	\
+						SRAM_SIZE,	\
+						MT_MEMORY | MT_RW | MT_NS)
+
+/*
+ * Mapping for the BL1 RW region. This mapping is needed by BL2 in order to
+ * share the Mbed TLS heap. Since the heap is allocated inside BL1, it resides
+ * in the BL1 RW region. Hence, BL2 needs access to the BL1 RW region in order
+ * to be able to access the heap.
+ */
+
+#define ARM_MAP_BL_RO	MAP_REGION_FLAT(\
+						BL_CODE_BASE,\
+						BL_CODE_END - BL_CODE_BASE,\
+						MT_CODE | MT_SECURE),\
+					MAP_REGION_FLAT(\
+						BL_RO_DATA_BASE,\
+						BL_RO_DATA_END\
+						- BL_RO_DATA_BASE,	\
+						MT_RO_DATA | MT_SECURE)
+
+#if USE_COHERENT_MEM
+#define ARM_MAP_BL_COHERENT_RAM		MAP_REGION_FLAT(\
+						BL_COHERENT_RAM_BASE,\
+						BL_COHERENT_RAM_END	\
+						- BL_COHERENT_RAM_BASE, \
+						MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+/*
+ * The max number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+#define ARM_BL_REGIONS			5
+
+#define MAX_MMAP_REGIONS		(PLAT_ARM_MMAP_ENTRIES +	\
+					 ARM_BL_REGIONS)
+
+/* Memory mapped Generic timer interfaces  */
+#define A5DS_TIMER_BASE_FREQUENCY		UL(24000000)
+
+#define ARM_CONSOLE_BAUDRATE		115200
+
+#define PLAT_PHY_ADDR_SPACE_SIZE			(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE			(1ULL << 32)
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		1
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		2
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE		(U(1) << ARM_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space of BL2 meminfo.
+ */
+#define ARM_TB_FW_CONFIG_BASE		(ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_TB_FW_CONFIG_LIMIT		(ARM_BL_RAM_BASE + PAGE_SIZE)
+
+/*******************************************************************************
+ * BL1 specific defines.
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ ******************************************************************************/
+#define BL1_RO_BASE			0x00000000
+#define BL1_RO_LIMIT			PLAT_ARM_TRUSTED_ROM_SIZE
+/*
+ * Put BL1 RW at the top of the memory allocated for BL images in NS DRAM.
+ */
+#define BL1_RW_BASE	(ARM_BL_RAM_BASE + \
+						ARM_BL_RAM_SIZE - \
+						(PLAT_ARM_MAX_BL1_RW_SIZE))
+#define BL1_RW_LIMIT (ARM_BL_RAM_BASE + \
+					    (ARM_BL_RAM_SIZE))
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+
+/*
+ * Put BL2 just below BL1.
+ */
+#define BL2_BASE			(BL1_RW_BASE - A5DS_MAX_BL2_SIZE)
+#define BL2_LIMIT			BL1_RW_BASE
+
+/* Put BL32 below BL2 in NS DRAM.*/
+#define ARM_BL2_MEM_DESC_BASE		ARM_TB_FW_CONFIG_LIMIT
+
+#define BL32_BASE			((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\
+						- PLAT_ARM_MAX_BL32_SIZE)
+#define BL32_PROGBITS_LIMIT		BL2_BASE
+#define BL32_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+
+/* Required platform porting definitions */
+#define PLATFORM_CORE_COUNT 1
+#define PLAT_NUM_PWR_DOMAINS		(A5DS_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT) + 1
+
+#define PLAT_MAX_PWR_LVL		2
+
+/*
+ * Other platform porting definitions are provided by included headers
+ */
+
+/*
+ * Required ARM standard platform porting definitions
+ */
+
+#define PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE	0x00040000	/* 256 KB */
+
+#define PLAT_ARM_TRUSTED_ROM_BASE	0x00000000
+#define PLAT_ARM_TRUSTED_ROM_SIZE	0x10000	/* 64KB */
+
+#define PLAT_ARM_DRAM2_SIZE		ULL(0x80000000)
+
+/*
+ * Load address of BL33 for this platform port
+ */
+#define PLAT_ARM_NS_IMAGE_BASE	(ARM_DRAM1_BASE + U(0x8000000))
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		6
+#else
+# define PLAT_ARM_MMAP_ENTRIES		12
+# define MAX_XLAT_TABLES		6
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_ARM_MAX_BL1_RW_SIZE	0xB000
+
+/*
+ * A5DS_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#define A5DS_MAX_BL2_SIZE		0x11000
+
+/*
+ * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is
+ * calculated using the current SP_MIN PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW
+ */
+#define PLAT_ARM_MAX_BL32_SIZE		0x3B000
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+#  define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#  define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FIP_BASE		FLASH1_BASE
+#define PLAT_ARM_FIP_MAX_SIZE		(FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#define PLAT_ARM_NVM_BASE		FLASH1_BASE
+#define PLAT_ARM_NVM_SIZE		(FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_ARM_BOOT_UART_BASE		0x1A200000
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ	24000000
+
+#define PLAT_ARM_RUN_UART_BASE		0x1A210000
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ	24000000
+
+#define PLAT_ARM_CRASH_UART_BASE	PLAT_ARM_RUN_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ	PLAT_ARM_RUN_UART_CLK_IN_HZ
+
+#define A5DS_TIMER_BASE_FREQUENCY	UL(24000000)
+
+/* System timer related constants */
+#define PLAT_ARM_NSTIMER_FRAME_ID		1
+
+/* Mailbox base address */
+#define A5DS_TRUSTED_MAILBOX_BASE	A5DS_SHARED_RAM_BASE
+
+/*
+ * GIC related constants to cater for GICv2
+ */
+#define PLAT_ARM_GICD_BASE		0x1C001000
+#define PLAT_ARM_GICC_BASE		0x1C000100
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	ARM_G1S_IRQ_PROPS(grp), \
+	INTR_PROP_DESC(A5DS_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(A5DS_IRQ_SEC_SYS_TIMER,\
+		 GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/a5ds/platform.mk b/plat/arm/board/a5ds/platform.mk
new file mode 100644
index 0000000..d42b2bf
--- /dev/null
+++ b/plat/arm/board/a5ds/platform.mk
@@ -0,0 +1,96 @@
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Add `libfdt` and Arm common helpers required for Dynamic Config
+include lib/libfdt/libfdt.mk
+
+DYN_CFG_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
+				plat/arm/common/arm_dyn_cfg_helpers.c	\
+				common/fdt_wrappers.c
+
+A5DS_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c		\
+				plat/arm/common/arm_gicv2.c
+
+A5DS_SECURITY_SOURCES	:=	plat/arm/board/a5ds/a5ds_security.c
+
+PLAT_INCLUDES		:=	-Iplat/arm/board/a5ds/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/arm/pl011/${ARCH}/pl011_console.S	\
+				plat/arm/board/a5ds/a5ds_common.c		\
+				plat/arm/common/${ARCH}/arm_helpers.S		\
+				plat/arm/common/arm_common.c			\
+				plat/arm/common/arm_console.c			\
+				plat/arm/board/common/${ARCH}/board_arm_helpers.S
+
+A5DS_CPU_LIBS		:=	lib/cpus/aarch32/cortex_a5.S
+
+BL1_SOURCES		+=	drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				drivers/cfi/v2m/v2m_flash.c			\
+				plat/arm/common/arm_bl1_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/board/a5ds/a5ds_err.c			\
+				plat/arm/common/arm_io_storage.c		\
+				plat/arm/board/a5ds/${ARCH}/a5ds_helpers.S	\
+				plat/arm/board/a5ds/a5ds_bl1_setup.c		\
+				lib/aarch32/arm32_aeabi_divmod.c		\
+				lib/aarch32/arm32_aeabi_divmod_a32.S		\
+				${A5DS_CPU_LIBS}				\
+				${DYN_CFG_SOURCES}
+
+BL2_SOURCES		+=	lib/aarch32/arm32_aeabi_divmod.c		\
+				lib/aarch32/arm32_aeabi_divmod_a32.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/cfi/v2m/v2m_flash.c			\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/arm/board/a5ds/a5ds_bl2_setup.c		\
+				plat/arm/common/arm_bl2_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/board/a5ds/a5ds_err.c			\
+				plat/arm/common/arm_io_storage.c		\
+				plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c	\
+				plat/arm/common/arm_image_load.c		\
+				common/desc_image_load.c			\
+				${DYN_CFG_SOURCES}				\
+				${A5DS_SECURITY_SOURCES}
+
+# Add the FDT_SOURCES and options for Dynamic Config (only for Unix env)
+ifdef UNIX_MK
+
+FVP_TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/a5ds_tb_fw_config.dtb
+
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config))
+
+$(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb, \
+	fdts/$(notdir ${FVP_HW_CONFIG_DTS})))
+# Add the HW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config))
+
+FDT_SOURCES		+=	plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts \
+					${FVP_HW_CONFIG_DTS}
+endif
+
+NEED_BL32 := yes
+
+MULTI_CONSOLE_API		:=	1
+
+PLAT_BL_COMMON_SOURCES	+=	lib/xlat_tables/aarch32/nonlpae_tables.c
+
+# Use translation tables library v1 when using Cortex-A5
+ARM_XLAT_TABLES_LIB_V1		:=	1
+$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
+$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
+
+$(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG))
+$(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG))
diff --git a/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
new file mode 100644
index 0000000..8b45af8
--- /dev/null
+++ b/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+}
+
+/*
+ * A5DS will only have one always-on power domain and there
+ * is no power control present.
+ */
+void plat_arm_pwrc_setup(void)
+{
+}
+
diff --git a/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk b/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
new file mode 100644
index 0000000..da1d785
--- /dev/null
+++ b/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2019, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SP_MIN source files specific to A5DS platform
+BL32_SOURCES	+=	drivers/cfi/v2m/v2m_flash.c			\
+			lib/utils/mem_region.c				\
+			lib/aarch32/arm32_aeabi_divmod.c		\
+			lib/aarch32/arm32_aeabi_divmod_a32.S		\
+			plat/arm/board/a5ds/aarch32/a5ds_helpers.S	\
+			plat/arm/board/a5ds/a5ds_pm.c			\
+			plat/arm/board/a5ds/a5ds_topology.c		\
+			plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c	\
+			plat/arm/common/sp_min/arm_sp_min_setup.c	\
+			plat/common/aarch32/platform_mp_stack.S		\
+			plat/common/plat_psci_common.c			\
+			${A5DS_CPU_LIBS}				\
+			${A5DS_GIC_SOURCES}				\
+			${A5DS_SECURITY_SOURCES}
diff --git a/plat/arm/board/common/aarch32/board_arm_helpers.S b/plat/arm/board/common/aarch32/board_arm_helpers.S
new file mode 100644
index 0000000..8c63693
--- /dev/null
+++ b/plat/arm/board/common/aarch32/board_arm_helpers.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <platform_def.h>
+
+	.globl  plat_report_exception
+
+
+	/* -------------------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * On FVP platform, it updates the LEDs
+	 * to indicate where we are.
+	 * SYS_LED[0]   - 0x0
+	 * SYS_LED[2:1] - 0x0
+	 * SYS_LED[7:3] - Exception Mode.
+	 * Clobbers: r0-r1
+	 * -------------------------------------------------------
+	 */
+func plat_report_exception
+	lsl	r0, r0, #V2M_SYS_LED_EC_SHIFT
+	ldr	r1, =V2M_SYSREGS_BASE
+	add	r1, r1, #V2M_SYS_LED
+	str	r0, [r1]
+	bx	lr
+endfunc plat_report_exception
diff --git a/plat/arm/board/common/aarch64/board_arm_helpers.S b/plat/arm/board/common/aarch64/board_arm_helpers.S
new file mode 100644
index 0000000..cde6b00
--- /dev/null
+++ b/plat/arm/board/common/aarch64/board_arm_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <platform_def.h>
+
+	.globl  plat_report_exception
+
+
+	/* ---------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * On FVP platform, it updates the LEDs
+	 * to indicate where we are
+	 * ---------------------------------------------
+	 */
+func plat_report_exception
+	mrs	x1, CurrentEl
+	lsr	x1, x1, #MODE_EL_SHIFT
+	lsl	x1, x1, #V2M_SYS_LED_EL_SHIFT
+	lsl	x0, x0, #V2M_SYS_LED_EC_SHIFT
+	mov	x2, #(SECURE << V2M_SYS_LED_SS_SHIFT)
+	orr	x0, x0, x2
+	orr	x0, x0, x1
+	mov	x1, #V2M_SYSREGS_BASE
+	add	x1, x1, #V2M_SYS_LED
+	str	w0, [x1]
+	ret
+endfunc plat_report_exception
diff --git a/plat/arm/board/common/board_arm_trusted_boot.c b/plat/arm/board/common/board_arm_trusted_boot.c
new file mode 100644
index 0000000..c71e932
--- /dev/null
+++ b/plat/arm/board/common/board_arm_trusted_boot.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/cassert.h>
+#include <plat/common/platform.h>
+#include <tools_share/tbbr_oid.h>
+#include <platform_def.h>
+
+/* SHA256 algorithm */
+#define SHA256_BYTES			32
+
+/* ROTPK locations */
+#define ARM_ROTPK_REGS_ID		1
+#define ARM_ROTPK_DEVEL_RSA_ID		2
+#define ARM_ROTPK_DEVEL_ECDSA_ID	3
+
+static const unsigned char rotpk_hash_hdr[] =		\
+		"\x30\x31\x30\x0D\x06\x09\x60\x86\x48"	\
+		"\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20";
+static const unsigned int rotpk_hash_hdr_len = sizeof(rotpk_hash_hdr) - 1;
+static unsigned char rotpk_hash_der[sizeof(rotpk_hash_hdr) - 1 + SHA256_BYTES];
+
+/* Use the cryptocell variants if Cryptocell is present */
+#if !ARM_CRYPTOCELL_INTEG
+#if !ARM_ROTPK_LOCATION_ID
+  #error "ARM_ROTPK_LOCATION_ID not defined"
+#endif
+
+/* Weak definition may be overridden in specific platform */
+#pragma weak plat_get_nv_ctr
+#pragma weak plat_set_nv_ctr
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID)
+static const unsigned char arm_devel_rotpk_hash[] =	\
+		"\xB0\xF3\x82\x09\x12\x97\xD8\x3A"	\
+		"\x37\x7A\x72\x47\x1B\xEC\x32\x73"	\
+		"\xE9\x92\x32\xE2\x49\x59\xF6\x5E"	\
+		"\x8B\x4A\x4A\x46\xD8\x22\x9A\xDA";
+#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
+static const unsigned char arm_devel_rotpk_hash[] =	\
+		"\x2E\x40\xBF\x6E\xF9\x12\xBB\x98"	\
+		"\x31\x71\x09\x0E\x1E\x15\x3D\x0B"	\
+		"\xFD\xD1\xCC\x69\x4A\x98\xEB\x8B"	\
+		"\xA0\xB0\x20\x86\x4E\x6C\x07\x17";
+#endif
+
+/*
+ * Return the ROTPK hash in the following ASN.1 structure in DER format:
+ *
+ * AlgorithmIdentifier  ::=  SEQUENCE  {
+ *     algorithm         OBJECT IDENTIFIER,
+ *     parameters        ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm   AlgorithmIdentifier,
+ *     digest            OCTET STRING
+ * }
+ */
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	uint8_t *dst;
+
+	assert(key_ptr != NULL);
+	assert(key_len != NULL);
+	assert(flags != NULL);
+
+	/* Copy the DER header */
+	memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len);
+	dst = (uint8_t *)&rotpk_hash_der[rotpk_hash_hdr_len];
+
+#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) \
+	|| (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID)
+	memcpy(dst, arm_devel_rotpk_hash, SHA256_BYTES);
+#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
+	uint32_t *src, tmp;
+	unsigned int words, i;
+
+	/*
+	 * Append the hash from Trusted Root-Key Storage registers. The hash has
+	 * not been written linearly into the registers, so we have to do a bit
+	 * of byte swapping:
+	 *
+	 *     0x00    0x04    0x08    0x0C    0x10    0x14    0x18    0x1C
+	 * +---------------------------------------------------------------+
+	 * | Reg0  | Reg1  | Reg2  | Reg3  | Reg4  | Reg5  | Reg6  | Reg7  |
+	 * +---------------------------------------------------------------+
+	 *  | ...                    ... |   | ...                   ...  |
+	 *  |       +--------------------+   |                    +-------+
+	 *  |       |                        |                    |
+	 *  +----------------------------+   +----------------------------+
+	 *          |                    |                        |       |
+	 *  +-------+                    |   +--------------------+       |
+	 *  |                            |   |                            |
+	 *  v                            v   v                            v
+	 * +---------------------------------------------------------------+
+	 * |                               |                               |
+	 * +---------------------------------------------------------------+
+	 *  0                           15  16                           31
+	 *
+	 * Additionally, we have to access the registers in 32-bit words
+	 */
+	words = SHA256_BYTES >> 3;
+
+	/* Swap bytes 0-15 (first four registers) */
+	src = (uint32_t *)TZ_PUB_KEY_HASH_BASE;
+	for (i = 0 ; i < words ; i++) {
+		tmp = src[words - 1 - i];
+		/* Words are read in little endian */
+		*dst++ = (uint8_t)((tmp >> 24) & 0xFF);
+		*dst++ = (uint8_t)((tmp >> 16) & 0xFF);
+		*dst++ = (uint8_t)((tmp >> 8) & 0xFF);
+		*dst++ = (uint8_t)(tmp & 0xFF);
+	}
+
+	/* Swap bytes 16-31 (last four registers) */
+	src = (uint32_t *)(TZ_PUB_KEY_HASH_BASE + SHA256_BYTES / 2);
+	for (i = 0 ; i < words ; i++) {
+		tmp = src[words - 1 - i];
+		*dst++ = (uint8_t)((tmp >> 24) & 0xFF);
+		*dst++ = (uint8_t)((tmp >> 16) & 0xFF);
+		*dst++ = (uint8_t)((tmp >> 8) & 0xFF);
+		*dst++ = (uint8_t)(tmp & 0xFF);
+	}
+#endif /* (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) \
+		  || (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID) */
+
+	*key_ptr = (void *)rotpk_hash_der;
+	*key_len = (unsigned int)sizeof(rotpk_hash_der);
+	*flags = ROTPK_IS_HASH;
+	return 0;
+}
+
+/*
+ * Return the non-volatile counter value stored in the platform. The cookie
+ * will contain the OID of the counter in the certificate.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	const char *oid;
+	uint32_t *nv_ctr_addr;
+
+	assert(cookie != NULL);
+	assert(nv_ctr != NULL);
+
+	oid = (const char *)cookie;
+	if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		nv_ctr_addr = (uint32_t *)TFW_NVCTR_BASE;
+	} else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		nv_ctr_addr = (uint32_t *)NTFW_CTR_BASE;
+	} else {
+		return 1;
+	}
+
+	*nv_ctr = (unsigned int)(*nv_ctr_addr);
+
+	return 0;
+}
+
+/*
+ * Store a new non-volatile counter value. By default on ARM development
+ * platforms, the non-volatile counters are RO and cannot be modified. We expect
+ * the values in the certificates to always match the RO values so that this
+ * function is never called.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+#else /* ARM_CRYPTOCELL_INTEG */
+
+#include <drivers/arm/cryptocell/cc_rotpk.h>
+
+/*
+ * Return the ROTPK hash in the following ASN.1 structure in DER format:
+ *
+ * AlgorithmIdentifier  ::=  SEQUENCE  {
+ *     algorithm         OBJECT IDENTIFIER,
+ *     parameters        ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm   AlgorithmIdentifier,
+ *     digest            OCTET STRING
+ * }
+ */
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	unsigned char *dst;
+
+	assert(key_ptr != NULL);
+	assert(key_len != NULL);
+	assert(flags != NULL);
+
+	/* Copy the DER header */
+	memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len);
+	dst = &rotpk_hash_der[rotpk_hash_hdr_len];
+	*key_ptr = rotpk_hash_der;
+	*key_len = sizeof(rotpk_hash_der);
+	return cc_get_rotpk_hash(dst, SHA256_BYTES, flags);
+}
+#endif /* ARM_CRYPTOCELL_INTEG */
diff --git a/plat/arm/board/common/board_common.mk b/plat/arm/board/common/board_common.mk
new file mode 100644
index 0000000..b98dfd4
--- /dev/null
+++ b/plat/arm/board/common/board_common.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_BL_COMMON_SOURCES	+=	drivers/arm/pl011/${ARCH}/pl011_console.S	\
+				plat/arm/board/common/${ARCH}/board_arm_helpers.S
+
+BL1_SOURCES		+=	drivers/cfi/v2m/v2m_flash.c
+
+BL2_SOURCES		+=	drivers/cfi/v2m/v2m_flash.c
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+  ifneq (${ARM_CRYPTOCELL_INTEG}, 1)
+    # ROTPK hash location
+    ifeq (${ARM_ROTPK_LOCATION}, regs)
+        ARM_ROTPK_LOCATION_ID = ARM_ROTPK_REGS_ID
+    else ifeq (${ARM_ROTPK_LOCATION}, devel_rsa)
+        KEY_ALG := rsa
+        ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_RSA_ID
+    else ifeq (${ARM_ROTPK_LOCATION}, devel_ecdsa)
+        KEY_ALG := ecdsa
+        ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_ECDSA_ID
+    else
+        $(error "Unsupported ARM_ROTPK_LOCATION value")
+    endif
+    $(eval $(call add_define,ARM_ROTPK_LOCATION_ID))
+
+    # Certificate NV-Counters. Use values corresponding to tied off values in
+    # ARM development platforms
+    TFW_NVCTR_VAL	?=	31
+    NTFW_NVCTR_VAL	?=	223
+  else
+    # Certificate NV-Counters when CryptoCell is integrated. For development
+    # platforms we set the counter to first valid value.
+    TFW_NVCTR_VAL	?=	0
+    NTFW_NVCTR_VAL	?=	0
+  endif
+    BL1_SOURCES		+=	plat/arm/board/common/board_arm_trusted_boot.c
+    BL2_SOURCES		+=	plat/arm/board/common/board_arm_trusted_boot.c
+endif
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
new file mode 100644
index 0000000..2547877
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
new file mode 100644
index 0000000..c5e123a
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin
@@ -0,0 +1 @@
+.@¿nù»Â˜1q	=ýÑÌiJ˜ë‹ ° †Nl
\ No newline at end of file
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_rsa.der b/plat/arm/board/common/rotpk/arm_rotpk_rsa.der
new file mode 100644
index 0000000..661f899
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_rsa.der
Binary files differ
diff --git a/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin b/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin
new file mode 100644
index 0000000..7653f7e
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin
@@ -0,0 +1 @@
+°ó‚	—Ø:7zrGì2séÂ’2âIYö^‹JJFØ"šÚ
\ No newline at end of file
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem b/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
new file mode 100644
index 0000000..fb328e3
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINSaX6nvzS3teiBJA7WlTLRKJOajpy29o2cArLbUXoZBoAoGCCqGSM49
+AwEHoUQDQgAEm+ZIvTQ44aKk83DhVLsvsFpKDP/Ch9vA+4Hp+fmVfX6gDH8K1OBi
+SpRf7FJ9RGPIn2H6xst+a1OtLMWUDRqGkQ==
+-----END EC PRIVATE KEY-----
diff --git a/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem b/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
new file mode 100644
index 0000000..71410ec
--- /dev/null
+++ b/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDLLGDVjWPUB3l+
+xxaWvU0kTqyG5rdx48VUC+cUHL0pGsE/erYCqqs2xNk2aWziZcObsb89qFYmy/0E
+AbqsPlQyynleu7IF6gZY8nS64fSHwBkKH2YHd4SDoRzv/yhZ58NofSYgQ+tWY/M5
+MdgrUam8T9D23pXcX1vB7ZBv7CiRfhfteJD0YKfEx09Q7V0TOiErcMVhewghZTrN
+glaMekesieilSEgx2R1G5YWGmKDlwKZqvQfkkldhB499Wk3Krja5VgQQ8my+9jts
+gD6+DqNNx9R+p0nU8tK8zzCo53SPZN+8XEdozEBM+IPMy0A1BGDKs6QXnwPKHVr6
+0a8hVxDTAgMBAAECggEAfwsc8ewbhDW4TwIGqfNtDUr0rtYN13VpqohW0ki2L8G/
+HQaKUViO/wxQFqoNn/OqQO0AfHmKhXAAokTCiXngBHJ/OjF7vB7+IRhazZEE6u2/
+uoivr/OYNQbFpXyTqsQ1eFzpPju6KKcPK7BzT4Mc89ek/vloFAi8w6LdMl8lbvOg
+LBWqX+5A+UQoenPUTvYM4U22YNcEAWubkpsYAmViiWiac+a+uPRk39aKyfOedDNu
++ty9MtCwekivoUTfP/1+O+jFlDnPMJUOEkBmcBqxseYYAHu7blBpdHxYpAItC2pv
+YwJJSvsE+HLBLPk177Jahg7sOUqcP0F/X+T65yuvIQKBgQDxdjXdJT5K8j7rG2fv
+2bvF2H1GPaHaTYRk0EGI2Ql6Nn+ddfeCE6gaT7aPPgg87wAhNu93coFuYHw0p/sc
+ZkXMJ+BmlstPV555cWXmwcxZLsni0fOXrt4YxwWkZwmh74m0NVM/cSFw56PU0oj1
+yDNeq3fgmsJocmuNTe1eG9qA7QKBgQDXaAGrNA5Xel5mqqMYTHHQWI6l2uzdNtt7
+eDn3K9+Eh3ywTqrwP845MAjKDU2Lq61I6t2H89dEifHq823VIcLCHd9BF04MrAH7
+qDPzrmPP2iB9g+YFmGBKe+K0HFE1t1KrTlo9VV6ZAC6RJNLAgwD4kvfIVYNkCGwe
++hoZBdhgvwKBgBrOsPQ4ak4PzwRzKnrqhXpVqrLdrNZ7vLMkm+IBlpfG7SwiKLR8
+UjF5oB8PGAML1cvaOYPdZplGhQOjkrF4eU9NLhC1tSS96Y46FMIlyfYsx6UzAgRZ
+GbdOgUXbWqpr2bH0KaXlfXz3eqzqIuKGs41TJB//jo3iBibN/AhytzORAoGAeGov
+5KDpE4XYl9Pz8HVremjG9Xh4yQENmOwQm1fvT4rd7UFM1ZkVk2qCv1DIdLe32vdQ
+d9ucDzh+ADWsxGRnF1TTpPN+Mh9FzISu5h4qtdreJsxBHgecbIbsqHrb+wdMM29N
+itPaWfV8Eq9fETcqp8qgsWD8XkNHDdoKFMrrtskCgYAoSt/Je1D3ZE/3HEjez7bq
+fenS3J6KG2SEn2PNFn+R0R5vBo4DaV/cQysKh44GD2+sh0QDyh6nuWJufyhPzROP
+DU6DCLbwNePj/yaGuzi36oLt6bBgfPWCiJY7jIdK8DmTLW25m7fRtCC5pxZlSzgl
+KBf7R6cbaTvaFe05Y2FJXA==
+-----END PRIVATE KEY-----
diff --git a/plat/arm/board/fvp/aarch32/fvp_helpers.S b/plat/arm/board/fvp/aarch32/fvp_helpers.S
new file mode 100644
index 0000000..9985c1d
--- /dev/null
+++ b/plat/arm/board/fvp/aarch32/fvp_helpers.S
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_arm_calc_core_pos
+
+	/* --------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * For AArch32, cold-booting secondary CPUs is not yet
+	 * implemented and they panic.
+	 * --------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and warm
+	 * boot. On FVP, this information can be queried from the power
+	 * controller. The Power Control SYS Status Register (PSYSR) indicates
+	 * the wake-up reason for the CPU.
+	 *
+	 * For a cold boot, return 0.
+	 * For a warm boot, read the mailbox and return the address it contains.
+	 *
+	 * TODO: PSYSR is a common register and should be
+	 * 	accessed using locks. Since it is not possible
+	 * 	to use locks immediately after a cold reset
+	 * 	we are relying on the fact that after a cold
+	 * 	reset all cpus will read the same WK field
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* ---------------------------------------------------------------------
+	 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
+	 * WakeRequest signal" then it is a warm boot.
+	 * ---------------------------------------------------------------------
+	 */
+	ldcopr	r2, MPIDR
+	ldr	r1, =PWRC_BASE
+	str	r2, [r1, #PSYSR_OFF]
+	ldr	r2, [r1, #PSYSR_OFF]
+	ubfx	r2, r2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH
+	cmp	r2, #WKUP_PPONR
+	beq	warm_reset
+	cmp	r2, #WKUP_GICREQ
+	beq	warm_reset
+
+	/* Cold reset */
+	mov	r0, #0
+	bx	lr
+
+warm_reset:
+	/* ---------------------------------------------------------------------
+	 * A mailbox is maintained in the trusted SRAM. It is flushed out of the
+	 * caches after every update using normal memory so it is safe to read
+	 * it here with SO attributes.
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE
+	ldr	r0, [r0]
+	cmp	r0, #0
+	beq	_panic
+	bx	lr
+
+	/* ---------------------------------------------------------------------
+	 * The power controller indicates this is a warm reset but the mailbox
+	 * is empty. This should never happen!
+	 * ---------------------------------------------------------------------
+	 */
+_panic:
+	b	_panic
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	ldcopr	r0, MPIDR
+	ldr	r1, =MPIDR_AFFINITY_MASK
+	and	r0, r1
+	cmp	r0, #FVP_PRIMARY_CPU
+	moveq	r0, #1
+	movne	r0, #0
+	bx	lr
+endfunc plat_is_my_cpu_primary
+
+	/* ---------------------------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Function to calculate the core position on FVP.
+	 *
+	 * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) +
+	 * (CPUId * FVP_MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU)
+	 * + ThreadId
+	 * ---------------------------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	mov	r3, r0
+
+	/*
+	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+	 * look as if in a multi-threaded implementation
+	 */
+	tst	r0, #MPIDR_MT_MASK
+	lsleq	r3, r0, #MPIDR_AFFINITY_BITS
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx	r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov	r3, #FVP_MAX_CPUS_PER_CLUSTER
+	mla	r1, r2, r3, r1
+	mov	r3, #FVP_MAX_PE_PER_CPU
+	mla	r0, r1, r3, r0
+
+	bx	lr
+endfunc plat_arm_calc_core_pos
diff --git a/plat/arm/board/fvp/aarch64/fvp_helpers.S b/plat/arm/board/fvp/aarch64/fvp_helpers.S
new file mode 100644
index 0000000..8efc238
--- /dev/null
+++ b/plat/arm/board/fvp/aarch64/fvp_helpers.S
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_arm_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * TODO: Should we read the PSYS register to make sure
+	 * that the request has gone through.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+#ifndef EL3_PAYLOAD_BASE
+	/* ---------------------------------------------
+	 * Power down this cpu.
+	 * TODO: Do we need to worry about powering the
+	 * cluster down as well here. That will need
+	 * locks which we won't have unless an elf-
+	 * loader zeroes out the zi section.
+	 * ---------------------------------------------
+	 */
+	mrs	x0, mpidr_el1
+	mov_imm	x1, PWRC_BASE
+	str	w0, [x1, #PPOFFR_OFF]
+
+	/* ---------------------------------------------
+	 * There is no sane reason to come out of this
+	 * wfi so panic if we do. This cpu will be pow-
+	 * ered on and reset by the cpu_on pm api
+	 * ---------------------------------------------
+	 */
+	dsb	sy
+	wfi
+	no_ret	plat_panic_handler
+#else
+	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
+
+	/* Wait until the entrypoint gets populated */
+poll_mailbox:
+	ldr	x1, [x0]
+	cbz	x1, 1f
+	br	x1
+1:
+	wfe
+	b	poll_mailbox
+#endif /* EL3_PAYLOAD_BASE */
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and warm
+	 * boot. On FVP, this information can be queried from the power
+	 * controller. The Power Control SYS Status Register (PSYSR) indicates
+	 * the wake-up reason for the CPU.
+	 *
+	 * For a cold boot, return 0.
+	 * For a warm boot, read the mailbox and return the address it contains.
+	 *
+	 * TODO: PSYSR is a common register and should be
+	 * 	accessed using locks. Since it is not possible
+	 * 	to use locks immediately after a cold reset
+	 * 	we are relying on the fact that after a cold
+	 * 	reset all cpus will read the same WK field
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* ---------------------------------------------------------------------
+	 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
+	 * WakeRequest signal" then it is a warm boot.
+	 * ---------------------------------------------------------------------
+	 */
+	mrs	x2, mpidr_el1
+	mov_imm	x1, PWRC_BASE
+	str	w2, [x1, #PSYSR_OFF]
+	ldr	w2, [x1, #PSYSR_OFF]
+	ubfx	w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH
+	cmp	w2, #WKUP_PPONR
+	beq	warm_reset
+	cmp	w2, #WKUP_GICREQ
+	beq	warm_reset
+
+	/* Cold reset */
+	mov	x0, #0
+	ret
+
+warm_reset:
+	/* ---------------------------------------------------------------------
+	 * A mailbox is maintained in the trusted SRAM. It is flushed out of the
+	 * caches after every update using normal memory so it is safe to read
+	 * it here with SO attributes.
+	 * ---------------------------------------------------------------------
+	 */
+	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
+	ldr	x0, [x0]
+	cbz	x0, _panic_handler
+	ret
+
+	/* ---------------------------------------------------------------------
+	 * The power controller indicates this is a warm reset but the mailbox
+	 * is empty. This should never happen!
+	 * ---------------------------------------------------------------------
+	 */
+_panic_handler:
+	no_ret	plat_panic_handler
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	mov_imm	x1, MPIDR_AFFINITY_MASK
+	and	x0, x0, x1
+	cmp	x0, #FVP_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* ---------------------------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Function to calculate the core position on FVP.
+	 *
+	 * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) +
+	 * (CPUId * FVP_MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU)
+	 * + ThreadId
+	 * ---------------------------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	/*
+	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+	 * look as if in a multi-threaded implementation.
+	 */
+	tst	x0, #MPIDR_MT_MASK
+	lsl	x3, x0, #MPIDR_AFFINITY_BITS
+	csel	x3, x3, x0, eq
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx	x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov	x4, #FVP_MAX_CPUS_PER_CLUSTER
+	madd	x1, x2, x4, x1
+	mov	x5, #FVP_MAX_PE_PER_CPU
+	madd	x0, x1, x5, x0
+	ret
+endfunc plat_arm_calc_core_pos
diff --git a/plat/arm/board/fvp/aarch64/fvp_ras.c b/plat/arm/board/fvp/aarch64/fvp_ras.c
new file mode 100644
index 0000000..759f6d0
--- /dev/null
+++ b/plat/arm/board/fvp/aarch64/fvp_ras.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/extensions/ras.h>
+
+struct ras_interrupt fvp_ras_interrupts[] = {
+};
+
+struct err_record_info fvp_err_records[] = {
+};
+
+REGISTER_ERR_RECORD_INFO(fvp_err_records);
+REGISTER_RAS_INTERRUPTS(fvp_ras_interrupts);
diff --git a/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts
new file mode 100644
index 0000000..7ab980b
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts
new file mode 100644
index 0000000..7ab980b
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
new file mode 100644
index 0000000..ce58938
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	plat_arm_bl2 {
+		compatible = "arm,tb_fw";
+		hw_config_addr = <0x0 0x82000000>;
+		hw_config_max_size = <0x01000000>;
+		/* Disable authentication for development */
+		disable_auth = <0x0>;
+		/*
+		 * Load SoC and TOS firmware configs at the base of
+		 * non shared SRAM. The runtime checks ensure we don't
+		 * overlap BL2, BL31 or BL32. The NT firmware config
+		 * is loaded at base of DRAM.
+		 */
+		soc_fw_config_addr = <0x0 0x04001000>;
+		soc_fw_config_max_size = <0x200>;
+		tos_fw_config_addr = <0x0 0x04001200>;
+		tos_fw_config_max_size = <0x200>;
+		nt_fw_config_addr = <0x0 0x80000000>;
+		nt_fw_config_max_size = <0x200>;
+		/*
+		 * The following two entries are placeholders for Mbed TLS
+		 * heap information. The default values don't matter since
+		 * they will be overwritten by BL1.
+		 * In case of having shared Mbed TLS heap between BL1 and BL2,
+		 * BL1 will populate these two properties with the respective
+		 * info about the shared heap. This info will be available for
+		 * BL2 in order to locate and re-use the heap.
+		 */
+		mbedtls_heap_addr = <0x0 0x0>;
+		mbedtls_heap_size = <0x0>;
+	};
+};
diff --git a/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts
new file mode 100644
index 0000000..7ab980b
--- /dev/null
+++ b/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+
+};
diff --git a/plat/arm/board/fvp/fvp_bl1_setup.c b/plat/arm/board/fvp/fvp_bl1_setup.c
new file mode 100644
index 0000000..b90ddcd
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl1_setup.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/smmu_v3.h>
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/common/platform.h>
+#include "fvp_private.h"
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	arm_bl1_early_platform_setup();
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	fvp_interconnect_init();
+	/*
+	 * Enable coherency in Interconnect for the primary CPU's cluster.
+	 */
+	fvp_interconnect_enable();
+}
+
+void plat_arm_secure_wdt_start(void)
+{
+	sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sp805_stop(ARM_SP805_TWDG_BASE);
+}
+
+void bl1_platform_setup(void)
+{
+	arm_bl1_platform_setup();
+
+	/* On FVP RevC, initialize SMMUv3 */
+	if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U)
+		smmuv3_security_init(PLAT_FVP_SMMUV3_BASE);
+}
+
+__dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved)
+{
+	/* Setup the watchdog to reset the system as soon as possible */
+	sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+	while (1)
+		wfi();
+}
diff --git a/plat/arm/board/fvp/fvp_bl2_el3_setup.c b/plat/arm/board/fvp/fvp_bl2_el3_setup.c
new file mode 100644
index 0000000..7def56a
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2_el3_setup.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#include "fvp_private.h"
+
+void bl2_el3_early_platform_setup(u_register_t arg0 __unused,
+				  u_register_t arg1 __unused,
+				  u_register_t arg2 __unused,
+				  u_register_t arg3 __unused)
+{
+	arm_bl2_el3_early_platform_setup();
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	fvp_interconnect_init();
+	/*
+	 * Enable coherency in Interconnect for the primary CPU's cluster.
+	 */
+	fvp_interconnect_enable();
+}
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
new file mode 100644
index 0000000..d280949
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "fvp_private.h"
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
+{
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+}
+
+void bl2_platform_setup(void)
+{
+	arm_bl2_platform_setup();
+
+#if FVP_USE_SP804_TIMER
+	/* Enable the clock override for SP804 timer 0, which means that no
+	 * clock dividers are applied and the raw (35 MHz) clock will be used */
+	mmio_write_32(V2M_SP810_BASE, FVP_SP810_CTRL_TIM0_OV);
+
+	/* Initialize delay timer driver using SP804 dual timer 0 */
+	sp804_timer_init(V2M_SP804_TIMER0_BASE,
+			SP804_TIMER_CLKMULT, SP804_TIMER_CLKDIV);
+#else
+	generic_delay_timer_init();
+#endif /* FVP_USE_SP804_TIMER */
+}
diff --git a/plat/arm/board/fvp/fvp_bl2u_setup.c b/plat/arm/board/fvp/fvp_bl2u_setup.c
new file mode 100644
index 0000000..a8db055
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2u_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "fvp_private.h"
+
+void bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info)
+{
+	arm_bl2u_early_platform_setup(mem_layout, plat_info);
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+}
diff --git a/plat/arm/board/fvp/fvp_bl31_setup.c b/plat/arm/board/fvp/fvp_bl31_setup.c
new file mode 100644
index 0000000..3f92d37
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl31_setup.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/smmu_v3.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include "fvp_private.h"
+
+void __init bl31_early_platform_setup2(u_register_t arg0,
+		u_register_t arg1, u_register_t arg2, u_register_t arg3)
+{
+	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+
+	/*
+	 * Initialize the correct interconnect for this cluster during cold
+	 * boot. No need for locks as no other CPU is active.
+	 */
+	fvp_interconnect_init();
+
+	/*
+	 * Enable coherency in interconnect for the primary CPU's cluster.
+	 * Earlier bootloader stages might already do this (e.g. Trusted
+	 * Firmware's BL1 does it) but we can't assume so. There is no harm in
+	 * executing this code twice anyway.
+	 * FVP PSCI code will enable coherency for other clusters.
+	 */
+	fvp_interconnect_enable();
+
+	/* On FVP RevC, initialize SMMUv3 */
+	if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U)
+		smmuv3_init(PLAT_FVP_SMMUV3_BASE);
+}
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
new file mode 100644
index 0000000..36cd500
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/ccn.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <services/secure_partition.h>
+
+#include "fvp_private.h"
+
+/* Defines for GIC Driver build time selection */
+#define FVP_GICV2		1
+#define FVP_GICV3		2
+
+/*******************************************************************************
+ * arm_config holds the characteristics of the differences between the three FVP
+ * platforms (Base, A53_A57 & Foundation). It will be populated during cold boot
+ * at each boot stage by the primary before enabling the MMU (to allow
+ * interconnect configuration) & used thereafter. Each BL will have its own copy
+ * to allow independent operation.
+ ******************************************************************************/
+arm_config_t arm_config;
+
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_DEVICE1	MAP_REGION_FLAT(DEVICE1_BASE,			\
+					DEVICE1_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * Need to be mapped with write permissions in order to set a new non-volatile
+ * counter value.
+ */
+#define MAP_DEVICE2	MAP_REGION_FLAT(DEVICE2_BASE,			\
+					DEVICE2_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * Table of memory regions for various BL stages to map using the MMU.
+ * This doesn't include Trusted SRAM as setup_page_tables() already takes care
+ * of mapping it.
+ *
+ * The flash needs to be mapped as writable in order to erase the FIP's Table of
+ * Contents in case of unrecoverable error (see plat_error_handler()).
+ */
+#ifdef IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH0_RW,
+	V2M_MAP_IOFPGA,
+	MAP_DEVICE0,
+	MAP_DEVICE1,
+#if TRUSTED_BOARD_BOOT
+	/* To access the Root of Trust Public Key registers. */
+	MAP_DEVICE2,
+	/* Map DRAM to authenticate NS_BL2U image. */
+	ARM_MAP_NS_DRAM1,
+#endif
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH0_RW,
+	V2M_MAP_IOFPGA,
+	MAP_DEVICE0,
+	MAP_DEVICE1,
+	ARM_MAP_NS_DRAM1,
+#ifdef __aarch64__
+	ARM_MAP_DRAM2,
+#endif
+#ifdef SPD_tspd
+	ARM_MAP_TSP_SEC_MEM,
+#endif
+#if TRUSTED_BOARD_BOOT
+	/* To access the Root of Trust Public Key registers. */
+	MAP_DEVICE2,
+#if !BL2_AT_EL3
+	ARM_MAP_BL1_RW,
+#endif
+#endif /* TRUSTED_BOARD_BOOT */
+#if ENABLE_SPM && SPM_MM
+	ARM_SP_IMAGE_MMAP,
+#endif
+#if ENABLE_SPM && !SPM_MM
+	PLAT_MAP_SP_PACKAGE_MEM_RW,
+#endif
+#if ARM_BL31_IN_DRAM
+	ARM_MAP_BL31_SEC_DRAM,
+#endif
+#ifdef SPD_opteed
+	ARM_MAP_OPTEE_CORE_MEM,
+	ARM_OPTEE_PAGEABLE_LOAD_MEM,
+#endif
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2U
+const mmap_region_t plat_arm_mmap[] = {
+	MAP_DEVICE0,
+	V2M_MAP_IOFPGA,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	ARM_MAP_EL3_TZC_DRAM,
+	V2M_MAP_IOFPGA,
+	MAP_DEVICE0,
+	MAP_DEVICE1,
+	ARM_V2M_MAP_MEM_PROTECT,
+#if ENABLE_SPM && SPM_MM
+	ARM_SPM_BUF_EL3_MMAP,
+#endif
+#if ENABLE_SPM && !SPM_MM
+	PLAT_MAP_SP_PACKAGE_MEM_RO,
+#endif
+	{0}
+};
+
+#if ENABLE_SPM && defined(IMAGE_BL31) && SPM_MM
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+	V2M_MAP_IOFPGA_EL0, /* for the UART */
+	MAP_REGION_FLAT(DEVICE0_BASE,				\
+			DEVICE0_SIZE,				\
+			MT_DEVICE | MT_RO | MT_SECURE | MT_USER),
+	ARM_SP_IMAGE_MMAP,
+	ARM_SP_IMAGE_NS_BUF_MMAP,
+	ARM_SP_IMAGE_RW_MMAP,
+	ARM_SPM_BUF_EL0_MMAP,
+	{0}
+};
+#endif
+#endif
+#ifdef IMAGE_BL32
+const mmap_region_t plat_arm_mmap[] = {
+#ifndef __aarch64__
+	ARM_MAP_SHARED_RAM,
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	V2M_MAP_IOFPGA,
+	MAP_DEVICE0,
+	MAP_DEVICE1,
+	{0}
+};
+#endif
+
+ARM_CASSERT_MMAP
+
+#if FVP_INTERCONNECT_DRIVER != FVP_CCN
+static const int fvp_cci400_map[] = {
+	PLAT_FVP_CCI400_CLUS0_SL_PORT,
+	PLAT_FVP_CCI400_CLUS1_SL_PORT,
+};
+
+static const int fvp_cci5xx_map[] = {
+	PLAT_FVP_CCI5XX_CLUS0_SL_PORT,
+	PLAT_FVP_CCI5XX_CLUS1_SL_PORT,
+};
+
+static unsigned int get_interconnect_master(void)
+{
+	unsigned int master;
+	u_register_t mpidr;
+
+	mpidr = read_mpidr_el1();
+	master = ((arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) != 0U) ?
+		MPIDR_AFFLVL2_VAL(mpidr) : MPIDR_AFFLVL1_VAL(mpidr);
+
+	assert(master < FVP_CLUSTER_COUNT);
+	return master;
+}
+#endif
+
+#if ENABLE_SPM && defined(IMAGE_BL31) && SPM_MM
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static secure_partition_mp_info_t sp_mp_info[] = {
+	[0] = {0x80000000, 0},
+	[1] = {0x80000001, 0},
+	[2] = {0x80000002, 0},
+	[3] = {0x80000003, 0},
+	[4] = {0x80000100, 0},
+	[5] = {0x80000101, 0},
+	[6] = {0x80000102, 0},
+	[7] = {0x80000103, 0},
+};
+
+const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = {
+	.h.type              = PARAM_SP_IMAGE_BOOT_INFO,
+	.h.version           = VERSION_1,
+	.h.size              = sizeof(secure_partition_boot_info_t),
+	.h.attr              = 0,
+	.sp_mem_base         = ARM_SP_IMAGE_BASE,
+	.sp_mem_limit        = ARM_SP_IMAGE_LIMIT,
+	.sp_image_base       = ARM_SP_IMAGE_BASE,
+	.sp_stack_base       = PLAT_SP_IMAGE_STACK_BASE,
+	.sp_heap_base        = ARM_SP_IMAGE_HEAP_BASE,
+	.sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE,
+	.sp_shared_buf_base  = PLAT_SPM_BUF_BASE,
+	.sp_image_size       = ARM_SP_IMAGE_SIZE,
+	.sp_pcpu_stack_size  = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+	.sp_heap_size        = ARM_SP_IMAGE_HEAP_SIZE,
+	.sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE,
+	.sp_shared_buf_size  = PLAT_SPM_BUF_SIZE,
+	.num_sp_mem_regions  = ARM_SP_IMAGE_NUM_MEM_REGIONS,
+	.num_cpus            = PLATFORM_CORE_COUNT,
+	.mp_info             = &sp_mp_info[0],
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+	return plat_arm_secure_partition_mmap;
+}
+
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie)
+{
+	return &plat_arm_secure_partition_boot_info;
+}
+#endif
+
+/*******************************************************************************
+ * A single boot loader stack is expected to work on both the Foundation FVP
+ * models and the two flavours of the Base FVP models (AEMv8 & Cortex). The
+ * SYS_ID register provides a mechanism for detecting the differences between
+ * these platforms. This information is stored in a per-BL array to allow the
+ * code to take the correct path.Per BL platform configuration.
+ ******************************************************************************/
+void __init fvp_config_setup(void)
+{
+	unsigned int rev, hbi, bld, arch, sys_id;
+
+	sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID);
+	rev = (sys_id >> V2M_SYS_ID_REV_SHIFT) & V2M_SYS_ID_REV_MASK;
+	hbi = (sys_id >> V2M_SYS_ID_HBI_SHIFT) & V2M_SYS_ID_HBI_MASK;
+	bld = (sys_id >> V2M_SYS_ID_BLD_SHIFT) & V2M_SYS_ID_BLD_MASK;
+	arch = (sys_id >> V2M_SYS_ID_ARCH_SHIFT) & V2M_SYS_ID_ARCH_MASK;
+
+	if (arch != ARCH_MODEL) {
+		ERROR("This firmware is for FVP models\n");
+		panic();
+	}
+
+	/*
+	 * The build field in the SYS_ID tells which variant of the GIC
+	 * memory is implemented by the model.
+	 */
+	switch (bld) {
+	case BLD_GIC_VE_MMAP:
+		ERROR("Legacy Versatile Express memory map for GIC peripheral"
+				" is not supported\n");
+		panic();
+		break;
+	case BLD_GIC_A53A57_MMAP:
+		break;
+	default:
+		ERROR("Unsupported board build %x\n", bld);
+		panic();
+	}
+
+	/*
+	 * The hbi field in the SYS_ID is 0x020 for the Base FVP & 0x010
+	 * for the Foundation FVP.
+	 */
+	switch (hbi) {
+	case HBI_FOUNDATION_FVP:
+		arm_config.flags = 0;
+
+		/*
+		 * Check for supported revisions of Foundation FVP
+		 * Allow future revisions to run but emit warning diagnostic
+		 */
+		switch (rev) {
+		case REV_FOUNDATION_FVP_V2_0:
+		case REV_FOUNDATION_FVP_V2_1:
+		case REV_FOUNDATION_FVP_v9_1:
+		case REV_FOUNDATION_FVP_v9_6:
+			break;
+		default:
+			WARN("Unrecognized Foundation FVP revision %x\n", rev);
+			break;
+		}
+		break;
+	case HBI_BASE_FVP:
+		arm_config.flags |= (ARM_CONFIG_BASE_MMAP | ARM_CONFIG_HAS_TZC);
+
+		/*
+		 * Check for supported revisions
+		 * Allow future revisions to run but emit warning diagnostic
+		 */
+		switch (rev) {
+		case REV_BASE_FVP_V0:
+			arm_config.flags |= ARM_CONFIG_FVP_HAS_CCI400;
+			break;
+		case REV_BASE_FVP_REVC:
+			arm_config.flags |= (ARM_CONFIG_FVP_HAS_SMMUV3 |
+					ARM_CONFIG_FVP_HAS_CCI5XX);
+			break;
+		default:
+			WARN("Unrecognized Base FVP revision %x\n", rev);
+			break;
+		}
+		break;
+	default:
+		ERROR("Unsupported board HBI number 0x%x\n", hbi);
+		panic();
+	}
+
+	/*
+	 * We assume that the presence of MT bit, and therefore shifted
+	 * affinities, is uniform across the platform: either all CPUs, or no
+	 * CPUs implement it.
+	 */
+	if ((read_mpidr_el1() & MPIDR_MT_MASK) != 0U)
+		arm_config.flags |= ARM_CONFIG_FVP_SHIFTED_AFF;
+}
+
+
+void __init fvp_interconnect_init(void)
+{
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+	if (ccn_get_part0_id(PLAT_ARM_CCN_BASE) != CCN_502_PART0_ID) {
+		ERROR("Unrecognized CCN variant detected. Only CCN-502 is supported");
+		panic();
+	}
+
+	plat_arm_interconnect_init();
+#else
+	uintptr_t cci_base = 0U;
+	const int *cci_map = NULL;
+	unsigned int map_size = 0U;
+
+	/* Initialize the right interconnect */
+	if ((arm_config.flags & ARM_CONFIG_FVP_HAS_CCI5XX) != 0U) {
+		cci_base = PLAT_FVP_CCI5XX_BASE;
+		cci_map = fvp_cci5xx_map;
+		map_size = ARRAY_SIZE(fvp_cci5xx_map);
+	} else if ((arm_config.flags & ARM_CONFIG_FVP_HAS_CCI400) != 0U) {
+		cci_base = PLAT_FVP_CCI400_BASE;
+		cci_map = fvp_cci400_map;
+		map_size = ARRAY_SIZE(fvp_cci400_map);
+	} else {
+		return;
+	}
+
+	assert(cci_base != 0U);
+	assert(cci_map != NULL);
+	cci_init(cci_base, cci_map, map_size);
+#endif
+}
+
+void fvp_interconnect_enable(void)
+{
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+	plat_arm_interconnect_enter_coherency();
+#else
+	unsigned int master;
+
+	if ((arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 |
+				 ARM_CONFIG_FVP_HAS_CCI5XX)) != 0U) {
+		master = get_interconnect_master();
+		cci_enable_snoop_dvm_reqs(master);
+	}
+#endif
+}
+
+void fvp_interconnect_disable(void)
+{
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+	plat_arm_interconnect_exit_coherency();
+#else
+	unsigned int master;
+
+	if ((arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 |
+				 ARM_CONFIG_FVP_HAS_CCI5XX)) != 0U) {
+		master = get_interconnect_master();
+		cci_disable_snoop_dvm_reqs(master);
+	}
+#endif
+}
+
+#if TRUSTED_BOARD_BOOT
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	assert(heap_addr != NULL);
+	assert(heap_size != NULL);
+
+	return arm_get_mbedtls_heap(heap_addr, heap_size);
+}
+#endif
diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h
new file mode 100644
index 0000000..1b9f84b
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_def.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_DEF_H
+#define FVP_DEF_H
+
+#include <lib/utils_def.h>
+
+#ifndef FVP_CLUSTER_COUNT
+#define FVP_CLUSTER_COUNT		2
+#endif
+
+#ifndef FVP_MAX_CPUS_PER_CLUSTER
+#define FVP_MAX_CPUS_PER_CLUSTER	4
+#endif
+
+#ifndef FVP_MAX_PE_PER_CPU
+# define FVP_MAX_PE_PER_CPU		1
+#endif
+
+#define FVP_PRIMARY_CPU			0x0
+
+/* Defines for the Interconnect build selection */
+#define FVP_CCI			1
+#define FVP_CCN			2
+
+/*******************************************************************************
+ * FVP memory map related constants
+ ******************************************************************************/
+
+#define FLASH1_BASE			UL(0x0c000000)
+#define FLASH1_SIZE			UL(0x04000000)
+
+#define PSRAM_BASE			UL(0x14000000)
+#define PSRAM_SIZE			UL(0x04000000)
+
+#define VRAM_BASE			UL(0x18000000)
+#define VRAM_SIZE			UL(0x02000000)
+
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE			UL(0x20000000)
+#define DEVICE0_SIZE			UL(0x0c200000)
+
+/*
+ *  In case of FVP models with CCN, the CCN register space overlaps into
+ *  the NSRAM area.
+ */
+#if FVP_INTERCONNECT_DRIVER == FVP_CCN
+#define DEVICE1_BASE			UL(0x2e000000)
+#define DEVICE1_SIZE			UL(0x1A00000)
+#else
+#define DEVICE1_BASE			UL(0x2f000000)
+#define DEVICE1_SIZE			UL(0x200000)
+#define NSRAM_BASE			UL(0x2e000000)
+#define NSRAM_SIZE			UL(0x10000)
+#endif
+/* Devices in the second GB */
+#define DEVICE2_BASE			UL(0x7fe00000)
+#define DEVICE2_SIZE			UL(0x00200000)
+
+#define PCIE_EXP_BASE			UL(0x40000000)
+#define TZRNG_BASE			UL(0x7fe60000)
+
+/* Non-volatile counters */
+#define TRUSTED_NVCTR_BASE		UL(0x7fe70000)
+#define TFW_NVCTR_BASE			(TRUSTED_NVCTR_BASE + UL(0x0000))
+#define TFW_NVCTR_SIZE			UL(4)
+#define NTFW_CTR_BASE			(TRUSTED_NVCTR_BASE + UL(0x0004))
+#define NTFW_CTR_SIZE			UL(4)
+
+/* Keys */
+#define SOC_KEYS_BASE			UL(0x7fe80000)
+#define TZ_PUB_KEY_HASH_BASE		(SOC_KEYS_BASE + UL(0x0000))
+#define TZ_PUB_KEY_HASH_SIZE		UL(32)
+#define HU_KEY_BASE			(SOC_KEYS_BASE + UL(0x0020))
+#define HU_KEY_SIZE			UL(16)
+#define END_KEY_BASE			(SOC_KEYS_BASE + UL(0x0044))
+#define END_KEY_SIZE			UL(32)
+
+/* Constants to distinguish FVP type */
+#define HBI_BASE_FVP			U(0x020)
+#define REV_BASE_FVP_V0			U(0x0)
+#define REV_BASE_FVP_REVC		U(0x2)
+
+#define HBI_FOUNDATION_FVP		U(0x010)
+#define REV_FOUNDATION_FVP_V2_0		U(0x0)
+#define REV_FOUNDATION_FVP_V2_1		U(0x1)
+#define REV_FOUNDATION_FVP_v9_1		U(0x2)
+#define REV_FOUNDATION_FVP_v9_6		U(0x3)
+
+#define BLD_GIC_VE_MMAP			U(0x0)
+#define BLD_GIC_A53A57_MMAP		U(0x1)
+
+#define ARCH_MODEL			U(0x1)
+
+/* FVP Power controller base address*/
+#define PWRC_BASE			UL(0x1c100000)
+
+/* FVP SP804 timer frequency is 35 MHz*/
+#define SP804_TIMER_CLKMULT		1
+#define SP804_TIMER_CLKDIV		35
+
+/* SP810 controller. FVP specific flags */
+#define FVP_SP810_CTRL_TIM0_OV		BIT_32(16)
+#define FVP_SP810_CTRL_TIM1_OV		BIT_32(18)
+#define FVP_SP810_CTRL_TIM2_OV		BIT_32(20)
+#define FVP_SP810_CTRL_TIM3_OV		BIT_32(22)
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+/* VE compatible GIC memory map */
+#define VE_GICD_BASE			UL(0x2c001000)
+#define VE_GICC_BASE			UL(0x2c002000)
+#define VE_GICH_BASE			UL(0x2c004000)
+#define VE_GICV_BASE			UL(0x2c006000)
+
+/* Base FVP compatible GIC memory map */
+#define BASE_GICD_BASE			UL(0x2f000000)
+#define BASE_GICR_BASE			UL(0x2f100000)
+#define BASE_GICC_BASE			UL(0x2c000000)
+#define BASE_GICH_BASE			UL(0x2c010000)
+#define BASE_GICV_BASE			UL(0x2c02f000)
+
+#define FVP_IRQ_TZ_WDOG			56
+#define FVP_IRQ_SEC_SYS_TIMER		57
+
+
+/*******************************************************************************
+ * TrustZone address space controller related constants
+ ******************************************************************************/
+
+/* NSAIDs used by devices in TZC filter 0 on FVP */
+#define FVP_NSAID_DEFAULT		0
+#define FVP_NSAID_PCI			1
+#define FVP_NSAID_VIRTIO		8  /* from FVP v5.6 onwards */
+#define FVP_NSAID_AP			9  /* Application Processors */
+#define FVP_NSAID_VIRTIO_OLD		15 /* until FVP v5.5 */
+
+/* NSAIDs used by devices in TZC filter 2 on FVP */
+#define FVP_NSAID_HDLCD0		2
+#define FVP_NSAID_CLCD			7
+
+/*******************************************************************************
+ * Memprotect definitions
+ ******************************************************************************/
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#endif /* FVP_DEF_H */
diff --git a/plat/arm/board/fvp/fvp_err.c b/plat/arm/board/fvp/fvp_err.c
new file mode 100644
index 0000000..2437cd4
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_err.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/cfi/v2m_flash.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*
+ * FVP error handler
+ */
+__dead2 void plat_arm_error_handler(int err)
+{
+	int ret;
+
+	switch (err) {
+	case -ENOENT:
+	case -EAUTH:
+		/* Image load or authentication error. Erase the ToC */
+		INFO("Erasing FIP ToC from flash...\n");
+		(void)nor_unlock(PLAT_ARM_FIP_BASE);
+		ret = nor_word_program(PLAT_ARM_FIP_BASE, 0);
+		if (ret != 0) {
+			ERROR("Cannot erase ToC\n");
+		} else {
+			INFO("Done\n");
+		}
+		break;
+	default:
+		/* Unexpected error */
+		break;
+	}
+
+	(void)console_flush();
+
+	/* Setup the watchdog to reset the system as soon as possible */
+	sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+	for (;;)
+		wfi();
+}
diff --git a/plat/arm/board/fvp/fvp_io_storage.c b/plat/arm/board/fvp/fvp_io_storage.c
new file mode 100644
index 0000000..9c4c1d5
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_io_storage.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+
+/* Semihosting filenames */
+#define BL2_IMAGE_NAME			"bl2.bin"
+#define BL31_IMAGE_NAME			"bl31.bin"
+#define BL32_IMAGE_NAME			"bl32.bin"
+#define BL33_IMAGE_NAME			"bl33.bin"
+#define TB_FW_CONFIG_NAME		"fvp_tb_fw_config.dtb"
+#define HW_CONFIG_NAME			"hw_config.dtb"
+
+#if TRUSTED_BOARD_BOOT
+#define TRUSTED_BOOT_FW_CERT_NAME	"tb_fw.crt"
+#define TRUSTED_KEY_CERT_NAME		"trusted_key.crt"
+#define SOC_FW_KEY_CERT_NAME		"soc_fw_key.crt"
+#define TOS_FW_KEY_CERT_NAME		"tos_fw_key.crt"
+#define NT_FW_KEY_CERT_NAME		"nt_fw_key.crt"
+#define SOC_FW_CONTENT_CERT_NAME	"soc_fw_content.crt"
+#define TOS_FW_CONTENT_CERT_NAME	"tos_fw_content.crt"
+#define NT_FW_CONTENT_CERT_NAME		"nt_fw_content.crt"
+#endif /* TRUSTED_BOARD_BOOT */
+
+/* IO devices */
+static const io_dev_connector_t *sh_dev_con;
+static uintptr_t sh_dev_handle;
+
+static const io_file_spec_t sh_file_spec[] = {
+	[BL2_IMAGE_ID] = {
+		.path = BL2_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL31_IMAGE_ID] = {
+		.path = BL31_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL32_IMAGE_ID] = {
+		.path = BL32_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL33_IMAGE_ID] = {
+		.path = BL33_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TB_FW_CONFIG_ID] = {
+		.path = TB_FW_CONFIG_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[HW_CONFIG_ID] = {
+		.path = HW_CONFIG_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		.path = TRUSTED_BOOT_FW_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		.path = TRUSTED_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		.path = SOC_FW_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		.path = TOS_FW_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		.path = NT_FW_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		.path = SOC_FW_CONTENT_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		.path = TOS_FW_CONTENT_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		.path = NT_FW_CONTENT_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+
+static int open_semihosting(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if the file exists on semi-hosting.*/
+	result = io_dev_init(sh_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(sh_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Semi-hosting IO\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void plat_arm_io_setup(void)
+{
+	int io_result;
+
+	arm_io_setup();
+
+	/* Register the additional IO devices on this platform */
+	io_result = register_io_dev_sh(&sh_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+/*
+ * FVP provides semihosting as an alternative to load images
+ */
+int plat_arm_get_alt_image_source(unsigned int image_id, uintptr_t *dev_handle,
+				  uintptr_t *image_spec)
+{
+	int result = open_semihosting((const uintptr_t)&sh_file_spec[image_id]);
+	if (result == 0) {
+		*dev_handle = sh_dev_handle;
+		*image_spec = (uintptr_t)&sh_file_spec[image_id];
+	}
+
+	return result;
+}
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
new file mode 100644
index 0000000..42dec8d
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <lib/extensions/spe.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "fvp_private.h"
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+
+
+#if ARM_RECOM_STATE_ID_ENC
+/*
+ *  The table storing the valid idle power states. Ensure that the
+ *  array entries are populated in ascending order of state-id to
+ *  enable us to use binary search during power state validation.
+ *  The table must be terminated by a NULL entry.
+ */
+const unsigned int arm_pm_idle_states[] = {
+	/* State-id - 0x01 */
+	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET,
+			ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x02 */
+	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
+			ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x22 */
+	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
+			ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x222 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
+	0,
+};
+#endif
+
+/*******************************************************************************
+ * Function which implements the common FVP specific operations to power down a
+ * cluster in response to a CPU_OFF or CPU_SUSPEND request.
+ ******************************************************************************/
+static void fvp_cluster_pwrdwn_common(void)
+{
+	uint64_t mpidr = read_mpidr_el1();
+
+#if ENABLE_SPE_FOR_LOWER_ELS
+	/*
+	 * On power down we need to disable statistical profiling extensions
+	 * before exiting coherency.
+	 */
+	spe_disable();
+#endif
+
+	/* Disable coherency if this cluster is to be turned off */
+	fvp_interconnect_disable();
+
+	/* Program the power controller to turn the cluster off */
+	fvp_pwrc_write_pcoffr(mpidr);
+}
+
+/*
+ * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit
+ * on ARM GICv3 implementations on FVP. This is required, because FVP does not
+ * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up
+ * from `fake` system suspend the GIC must not be powered off.
+ */
+void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num)
+{}
+
+void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num)
+{}
+
+static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+					ARM_LOCAL_STATE_OFF);
+
+	/* Get the mpidr for this cpu */
+	mpidr = read_mpidr_el1();
+
+	/* Perform the common cluster specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
+					ARM_LOCAL_STATE_OFF) {
+		/*
+		 * This CPU might have woken up whilst the cluster was
+		 * attempting to power down. In this case the FVP power
+		 * controller will have a pending cluster power off request
+		 * which needs to be cleared by writing to the PPONR register.
+		 * This prevents the power controller from interpreting a
+		 * subsequent entry of this cpu into a simple wfi as a power
+		 * down request.
+		 */
+		fvp_pwrc_write_pponr(mpidr);
+
+		/* Enable coherency if this cluster was off */
+		fvp_interconnect_enable();
+	}
+	/* Perform the common system specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+						ARM_LOCAL_STATE_OFF)
+		arm_system_pwr_domain_resume();
+
+	/*
+	 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
+	 * with a cpu power down unless the bit is set again
+	 */
+	fvp_pwrc_clr_wen(mpidr);
+}
+
+
+/*******************************************************************************
+ * FVP handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+static void fvp_cpu_standby(plat_local_state_t cpu_state)
+{
+
+	assert(cpu_state == ARM_LOCAL_STATE_RET);
+
+	/*
+	 * Enter standby state
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	dsb();
+	wfi();
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int fvp_pwr_domain_on(u_register_t mpidr)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned int psysr;
+
+	/*
+	 * Ensure that we do not cancel an inflight power off request for the
+	 * target cpu. That would leave it in a zombie wfi. Wait for it to power
+	 * off and then program the power controller to turn that CPU on.
+	 */
+	do {
+		psysr = fvp_pwrc_read_psysr(mpidr);
+	} while ((psysr & PSYSR_AFF_L0) != 0U);
+
+	fvp_pwrc_write_pponr(mpidr);
+	return rc;
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+static void fvp_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+					ARM_LOCAL_STATE_OFF);
+
+	/*
+	 * If execution reaches this stage then this power domain will be
+	 * suspended. Perform at least the cpu specific actions followed
+	 * by the cluster specific operations if applicable.
+	 */
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_arm_gic_cpuif_disable();
+
+	/* Turn redistributor off */
+	plat_arm_gic_redistif_off();
+
+	/* Program the power controller to power off this cpu. */
+	fvp_pwrc_write_ppoffr(read_mpidr_el1());
+
+	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
+					ARM_LOCAL_STATE_OFF)
+		fvp_cluster_pwrdwn_common();
+
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+
+	/*
+	 * FVP has retention only at cpu level. Just return
+	 * as nothing is to be done for retention.
+	 */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+					ARM_LOCAL_STATE_RET)
+		return;
+
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+					ARM_LOCAL_STATE_OFF);
+
+	/* Get the mpidr for this cpu */
+	mpidr = read_mpidr_el1();
+
+	/* Program the power controller to enable wakeup interrupts. */
+	fvp_pwrc_set_wen(mpidr);
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_arm_gic_cpuif_disable();
+
+	/*
+	 * The Redistributor is not powered off as it can potentially prevent
+	 * wake up events reaching the CPUIF and/or might lead to losing
+	 * register context.
+	 */
+
+	/* Perform the common cluster specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
+					ARM_LOCAL_STATE_OFF)
+		fvp_cluster_pwrdwn_common();
+
+	/* Perform the common system specific operations */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+						ARM_LOCAL_STATE_OFF)
+		arm_system_pwr_domain_save();
+
+	/* Program the power controller to power off this cpu. */
+	fvp_pwrc_write_ppoffr(read_mpidr_el1());
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+static void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	fvp_power_domain_on_finish_common(target_state);
+
+	/* Enable the gic cpu interface */
+	plat_arm_gic_pcpu_init();
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_arm_gic_cpuif_enable();
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ ******************************************************************************/
+static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	/*
+	 * Nothing to be done on waking up from retention from CPU level.
+	 */
+	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+					ARM_LOCAL_STATE_RET)
+		return;
+
+	fvp_power_domain_on_finish_common(target_state);
+
+	/* Enable the gic cpu interface */
+	plat_arm_gic_cpuif_enable();
+}
+
+/*******************************************************************************
+ * FVP handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 fvp_system_off(void)
+{
+	/* Write the System Configuration Control Register */
+	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
+		V2M_CFGCTRL_START |
+		V2M_CFGCTRL_RW |
+		V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN));
+	wfi();
+	ERROR("FVP System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 fvp_system_reset(void)
+{
+	/* Write the System Configuration Control Register */
+	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
+		V2M_CFGCTRL_START |
+		V2M_CFGCTRL_RW |
+		V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT));
+	wfi();
+	ERROR("FVP System Reset: operation not handled.\n");
+	panic();
+}
+
+static int fvp_node_hw_state(u_register_t target_cpu,
+			     unsigned int power_level)
+{
+	unsigned int psysr;
+	int ret;
+
+	/*
+	 * The format of 'power_level' is implementation-defined, but 0 must
+	 * mean a CPU. We also allow 1 to denote the cluster
+	 */
+	if ((power_level != ARM_PWR_LVL0) && (power_level != ARM_PWR_LVL1))
+		return PSCI_E_INVALID_PARAMS;
+
+	/*
+	 * Read the status of the given MPDIR from FVP power controller. The
+	 * power controller only gives us on/off status, so map that to expected
+	 * return values of the PSCI call
+	 */
+	psysr = fvp_pwrc_read_psysr(target_cpu);
+	if (psysr == PSYSR_INVALID)
+		return PSCI_E_INVALID_PARAMS;
+
+	if (power_level == ARM_PWR_LVL0) {
+		ret = ((psysr & PSYSR_AFF_L0) != 0U) ? HW_ON : HW_OFF;
+	} else {
+		/* power_level == ARM_PWR_LVL1 */
+		ret = ((psysr & PSYSR_AFF_L1) != 0U) ? HW_ON : HW_OFF;
+	}
+
+	return ret;
+}
+
+/*
+ * The FVP doesn't truly support power management at SYSTEM power domain. The
+ * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform
+ * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver
+ * save and restore sequences on FVP.
+ */
+#if !ARM_BL31_IN_DRAM
+static void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
+}
+#endif
+
+/*******************************************************************************
+ * Handler to filter PSCI requests.
+ ******************************************************************************/
+/*
+ * The system power domain suspend is only supported only via
+ * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
+ * will be downgraded to the lower level.
+ */
+static int fvp_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state)
+{
+	int rc;
+	rc = arm_validate_power_state(power_state, req_state);
+
+	/*
+	 * Ensure that the system power domain level is never suspended
+	 * via PSCI CPU SUSPEND API. Currently system suspend is only
+	 * supported via PSCI SYSTEM SUSPEND API.
+	 */
+	req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
+	return rc;
+}
+
+/*
+ * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the
+ * `fvp_validate_power_state`, we do not downgrade the system power
+ * domain level request in `power_state` as it will be used to query the
+ * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
+ */
+static int fvp_translate_power_state_by_mpidr(u_register_t mpidr,
+		unsigned int power_state,
+		psci_power_state_t *output_state)
+{
+	return arm_validate_power_state(power_state, output_state);
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+plat_psci_ops_t plat_arm_psci_pm_ops = {
+	.cpu_standby = fvp_cpu_standby,
+	.pwr_domain_on = fvp_pwr_domain_on,
+	.pwr_domain_off = fvp_pwr_domain_off,
+	.pwr_domain_suspend = fvp_pwr_domain_suspend,
+	.pwr_domain_on_finish = fvp_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
+	.system_off = fvp_system_off,
+	.system_reset = fvp_system_reset,
+	.validate_power_state = fvp_validate_power_state,
+	.validate_ns_entrypoint = arm_validate_psci_entrypoint,
+	.translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr,
+	.get_node_hw_state = fvp_node_hw_state,
+#if !ARM_BL31_IN_DRAM
+	/*
+	 * The TrustZone Controller is set up during the warmboot sequence after
+	 * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM
+	 * this is  not a problem but, if it is in TZC-secured DRAM, it tries to
+	 * reconfigure the same memory it is running on, causing an exception.
+	 */
+	.get_sys_suspend_power_state = fvp_get_sys_suspend_power_state,
+#endif
+	.mem_protect_chk	= arm_psci_mem_protect_chk,
+	.read_mem_protect	= arm_psci_read_mem_protect,
+	.write_mem_protect	= arm_nor_psci_write_mem_protect,
+};
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+	return ops;
+}
diff --git a/plat/arm/board/fvp/fvp_private.h b/plat/arm/board/fvp/fvp_private.h
new file mode 100644
index 0000000..5067d3a
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_private.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_PRIVATE_H
+#define FVP_PRIVATE_H
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+void fvp_config_setup(void);
+
+void fvp_interconnect_init(void);
+void fvp_interconnect_enable(void);
+void fvp_interconnect_disable(void);
+void tsp_early_platform_setup(void);
+
+#endif /* FVP_PRIVATE_H */
diff --git a/plat/arm/board/fvp/fvp_security.c b/plat/arm/board/fvp/fvp_security.c
new file mode 100644
index 0000000..80ec217
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_security.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * We assume that all security programming is done by the primary core.
+ */
+void plat_arm_security_setup(void)
+{
+	/*
+	 * The Base FVP has a TrustZone address space controller, the Foundation
+	 * FVP does not. Trying to program the device on the foundation FVP will
+	 * cause an abort.
+	 *
+	 * If the platform had additional peripheral specific security
+	 * configurations, those would be configured here.
+	 */
+
+	if ((get_arm_config()->flags & ARM_CONFIG_HAS_TZC) != 0U)
+		arm_tzc400_setup(NULL);
+}
diff --git a/plat/arm/board/fvp/fvp_stack_protector.c b/plat/arm/board/fvp/fvp_stack_protector.c
new file mode 100644
index 0000000..e940a12
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_stack_protector.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL)
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+	/*
+	 * Ideally, a random number should be returned instead of the
+	 * combination of a timer's value and a compile-time constant. As the
+	 * FVP does not have any random number generator, this is better than
+	 * nothing but not necessarily really secure.
+	 */
+	return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
+
diff --git a/plat/arm/board/fvp/fvp_topology.c b/plat/arm/board/fvp/fvp_topology.c
new file mode 100644
index 0000000..9823fb3
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_topology.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <lib/cassert.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* The FVP power domain tree descriptor */
+static unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 2];
+
+
+CASSERT(((FVP_CLUSTER_COUNT > 0) && (FVP_CLUSTER_COUNT <= 256)),
+			assert_invalid_fvp_cluster_count);
+
+/*******************************************************************************
+ * This function dynamically constructs the topology according to
+ * FVP_CLUSTER_COUNT and returns it.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	int i;
+
+	/*
+	 * The highest level is the system level. The next level is constituted
+	 * by clusters and then cores in clusters.
+	 */
+	fvp_power_domain_tree_desc[0] = 1;
+	fvp_power_domain_tree_desc[1] = FVP_CLUSTER_COUNT;
+
+	for (i = 0; i < FVP_CLUSTER_COUNT; i++)
+		fvp_power_domain_tree_desc[i + 2] = FVP_MAX_CPUS_PER_CLUSTER;
+
+
+	return fvp_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
+{
+	return FVP_MAX_CPUS_PER_CLUSTER;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int clus_id, cpu_id, thread_id;
+
+	/* Validate affinity fields */
+	if ((arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) != 0U) {
+		thread_id = MPIDR_AFFLVL0_VAL(mpidr);
+		cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
+		clus_id = MPIDR_AFFLVL2_VAL(mpidr);
+	} else {
+		thread_id = 0;
+		cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+		clus_id = MPIDR_AFFLVL1_VAL(mpidr);
+	}
+
+	if (clus_id >= FVP_CLUSTER_COUNT)
+		return -1;
+	if (cpu_id >= FVP_MAX_CPUS_PER_CLUSTER)
+		return -1;
+	if (thread_id >= FVP_MAX_PE_PER_CPU)
+		return -1;
+
+	if (fvp_pwrc_read_psysr(mpidr) == PSYSR_INVALID)
+		return -1;
+
+	/*
+	 * Core position calculation for FVP platform depends on the MT bit in
+	 * MPIDR. This function cannot assume that the supplied MPIDR has the MT
+	 * bit set even if the implementation has. For example, PSCI clients
+	 * might supply MPIDR values without the MT bit set. Therefore, we
+	 * inject the current PE's MT bit so as to get the calculation correct.
+	 * This of course assumes that none or all CPUs on the platform has MT
+	 * bit set.
+	 */
+	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+	return (int) plat_arm_calc_core_pos(mpidr);
+}
diff --git a/plat/arm/board/fvp/fvp_trusted_boot.c b/plat/arm/board/fvp/fvp_trusted_boot.c
new file mode 100644
index 0000000..0d160cb
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_trusted_boot.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <tools_share/tbbr_oid.h>
+
+/*
+ * Store a new non-volatile counter value. On some FVP versions, the
+ * non-volatile counters are RO. On these versions we expect the values in the
+ * certificates to always match the RO values so that this function is never
+ * called.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	const char *oid;
+	uint32_t *nv_ctr_addr;
+
+	assert(cookie != NULL);
+
+	oid = (const char *)cookie;
+	if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		nv_ctr_addr = (uint32_t *)TFW_NVCTR_BASE;
+	} else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) {
+		nv_ctr_addr = (uint32_t *)NTFW_CTR_BASE;
+	} else {
+		return 1;
+	}
+
+	*(unsigned int *)nv_ctr_addr = nv_ctr;
+
+	/* Verify that the current value is the one we just wrote. */
+	if (nv_ctr != (unsigned int)(*nv_ctr_addr))
+		return 1;
+
+	return 0;
+}
diff --git a/plat/arm/board/fvp/include/plat.ld.S b/plat/arm/board/fvp/include/plat.ld.S
new file mode 100644
index 0000000..f024f55
--- /dev/null
+++ b/plat/arm/board/fvp/include/plat.ld.S
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_LD_S
+#define PLAT_LD_S
+
+#include <plat/arm/common/arm_tzc_dram.ld.S>
+#include <plat/arm/common/arm_reclaim_init.ld.S>
+
+#endif /* PLAT_LD_S */
diff --git a/plat/arm/board/fvp/include/plat_macros.S b/plat/arm/board/fvp/include/plat_macros.S
new file mode 100644
index 0000000..57f5924
--- /dev/null
+++ b/plat/arm/board/fvp/include/plat_macros.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+#include <platform_def.h>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC registers whenever an
+	 * unhandled exception is taken in BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	/*
+	 * Detect if we're using the base memory map or
+	 * the legacy VE memory map
+	 */
+	mov_imm	x0, (V2M_SYSREGS_BASE + V2M_SYS_ID)
+	ldr	w16, [x0]
+	/* Extract BLD (12th - 15th bits) from the SYS_ID */
+	ubfx	x16, x16, #V2M_SYS_ID_BLD_SHIFT, #4
+	/* Check if VE mmap */
+	cmp	w16, #BLD_GIC_VE_MMAP
+	b.eq	use_ve_mmap
+	/* Assume Base Cortex mmap */
+	mov_imm	x17, BASE_GICC_BASE
+	mov_imm	x16, BASE_GICD_BASE
+	b	print_gic_regs
+use_ve_mmap:
+	mov_imm	x17, VE_GICC_BASE
+	mov_imm	x16, VE_GICD_BASE
+print_gic_regs:
+	arm_print_gic_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
new file mode 100644
index 0000000..4f26277
--- /dev/null
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <drivers/arm/tzc400.h>
+#include <lib/utils_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/common/common_def.h>
+
+#include "../fvp_def.h"
+
+/* Required platform porting definitions */
+#define PLATFORM_CORE_COUNT \
+	(FVP_CLUSTER_COUNT * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU)
+
+#define PLAT_NUM_PWR_DOMAINS		(FVP_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT) + 1
+
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
+
+/*
+ * Other platform porting definitions are provided by included headers
+ */
+
+/*
+ * Required ARM standard platform porting definitions
+ */
+#define PLAT_ARM_CLUSTER_COUNT		FVP_CLUSTER_COUNT
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE	UL(0x00040000)	/* 256 KB */
+
+#define PLAT_ARM_TRUSTED_ROM_BASE	UL(0x00000000)
+#define PLAT_ARM_TRUSTED_ROM_SIZE	UL(0x04000000)	/* 64 MB */
+
+#define PLAT_ARM_TRUSTED_DRAM_BASE	UL(0x06000000)
+#define PLAT_ARM_TRUSTED_DRAM_SIZE	UL(0x02000000)	/* 32 MB */
+
+/* virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xc0000000)
+
+/* No SCP in FVP */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE	UL(0x0)
+
+#define PLAT_ARM_DRAM2_BASE		ULL(0x880000000)
+#define PLAT_ARM_DRAM2_SIZE		UL(0x80000000)
+
+/*
+ * Load address of BL33 for this platform port
+ */
+#define PLAT_ARM_NS_IMAGE_BASE		(ARM_DRAM1_BASE + UL(0x8000000))
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if defined(IMAGE_BL31)
+# if ENABLE_SPM
+#  define PLAT_ARM_MMAP_ENTRIES		9
+#  define MAX_XLAT_TABLES		9
+#  define PLAT_SP_IMAGE_MMAP_REGIONS	30
+#  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
+# else
+#  define PLAT_ARM_MMAP_ENTRIES		8
+#  define MAX_XLAT_TABLES		5
+# endif
+#elif defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		5
+#elif !USE_ROMLIB
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		5
+#else
+# define PLAT_ARM_MMAP_ENTRIES		12
+# define MAX_XLAT_TABLES		6
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0xB000)
+
+/*
+ * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page
+ */
+
+#if USE_ROMLIB
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	UL(0x1000)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	UL(0xe000)
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	UL(0)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	UL(0)
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#if TRUSTED_BOARD_BOOT
+# define PLAT_ARM_MAX_BL2_SIZE		UL(0x1D000)
+#else
+# define PLAT_ARM_MAX_BL2_SIZE		UL(0x11000)
+#endif
+
+/*
+ * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
+ * calculated using the current BL31 PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW
+ */
+#if ENABLE_SPM && !SPM_MM
+#define PLAT_ARM_MAX_BL31_SIZE		UL(0x60000)
+#else
+#define PLAT_ARM_MAX_BL31_SIZE		UL(0x3B000)
+#endif
+
+#ifndef __aarch64__
+/*
+ * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is
+ * calculated using the current SP_MIN PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW
+ */
+# define PLAT_ARM_MAX_BL32_SIZE		UL(0x3B000)
+#endif
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE		UL(0x1000)
+# else
+#  define PLATFORM_STACK_SIZE		UL(0x440)
+# endif
+#elif defined(IMAGE_BL2)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE		UL(0x1000)
+# else
+#  define PLATFORM_STACK_SIZE		UL(0x400)
+# endif
+#elif defined(IMAGE_BL2U)
+# define PLATFORM_STACK_SIZE		UL(0x400)
+#elif defined(IMAGE_BL31)
+#  define PLATFORM_STACK_SIZE		UL(0x800)
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE		UL(0x440)
+#endif
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FIP_BASE		V2M_FLASH0_BASE
+#define PLAT_ARM_FIP_MAX_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#define PLAT_ARM_NVM_BASE		V2M_FLASH0_BASE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_ARM_BOOT_UART_BASE		V2M_IOFPGA_UART0_BASE
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ	V2M_IOFPGA_UART0_CLK_IN_HZ
+
+#define PLAT_ARM_RUN_UART_BASE		V2M_IOFPGA_UART1_BASE
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ	V2M_IOFPGA_UART1_CLK_IN_HZ
+
+#define PLAT_ARM_CRASH_UART_BASE	PLAT_ARM_RUN_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ	PLAT_ARM_RUN_UART_CLK_IN_HZ
+
+#define PLAT_ARM_TSP_UART_BASE		V2M_IOFPGA_UART2_BASE
+#define PLAT_ARM_TSP_UART_CLK_IN_HZ	V2M_IOFPGA_UART2_CLK_IN_HZ
+
+#define PLAT_FVP_SMMUV3_BASE		UL(0x2b400000)
+
+/* CCI related constants */
+#define PLAT_FVP_CCI400_BASE		UL(0x2c090000)
+#define PLAT_FVP_CCI400_CLUS0_SL_PORT	3
+#define PLAT_FVP_CCI400_CLUS1_SL_PORT	4
+
+/* CCI-500/CCI-550 on Base platform */
+#define PLAT_FVP_CCI5XX_BASE		UL(0x2a000000)
+#define PLAT_FVP_CCI5XX_CLUS0_SL_PORT	5
+#define PLAT_FVP_CCI5XX_CLUS1_SL_PORT	6
+
+/* CCN related constants. Only CCN 502 is currently supported */
+#define PLAT_ARM_CCN_BASE		UL(0x2e000000)
+#define PLAT_ARM_CLUSTER_TO_CCN_ID_MAP	1, 5, 7, 11
+
+/* System timer related constants */
+#define PLAT_ARM_NSTIMER_FRAME_ID		U(1)
+
+/* Mailbox base address */
+#define PLAT_ARM_TRUSTED_MAILBOX_BASE	ARM_TRUSTED_SRAM_BASE
+
+
+/* TrustZone controller related constants
+ *
+ * Currently only filters 0 and 2 are connected on Base FVP.
+ * Filter 0 : CPU clusters (no access to DRAM by default)
+ * Filter 1 : not connected
+ * Filter 2 : LCDs (access to VRAM allowed by default)
+ * Filter 3 : not connected
+ * Programming unconnected filters will have no effect at the
+ * moment. These filter could, however, be connected in future.
+ * So care should be taken not to configure the unused filters.
+ *
+ * Allow only non-secure access to all DRAM to supported devices.
+ * Give access to the CPUs and Virtio. Some devices
+ * would normally use the default ID so allow that too.
+ */
+#define PLAT_ARM_TZC_BASE		UL(0x2a4a0000)
+#define PLAT_ARM_TZC_FILTERS		TZC_400_REGION_ATTR_FILTER_BIT(0)
+
+#define PLAT_ARM_TZC_NS_DEV_ACCESS	(				\
+		TZC_REGION_ACCESS_RDWR(FVP_NSAID_DEFAULT)	|	\
+		TZC_REGION_ACCESS_RDWR(FVP_NSAID_PCI)		|	\
+		TZC_REGION_ACCESS_RDWR(FVP_NSAID_AP)		|	\
+		TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO)	|	\
+		TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD))
+
+/*
+ * GIC related constants to cater for both GICv2 and GICv3 instances of an
+ * FVP. They could be overriden at runtime in case the FVP implements the legacy
+ * VE memory map.
+ */
+#define PLAT_ARM_GICD_BASE		BASE_GICD_BASE
+#define PLAT_ARM_GICR_BASE		BASE_GICR_BASE
+#define PLAT_ARM_GICC_BASE		BASE_GICC_BASE
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	ARM_G1S_IRQ_PROPS(grp), \
+	INTR_PROP_DESC(FVP_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(FVP_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+#define PLAT_ARM_PRIVATE_SDEI_EVENTS	ARM_SDEI_PRIVATE_EVENTS
+#define PLAT_ARM_SHARED_SDEI_EVENTS	ARM_SDEI_SHARED_EVENTS
+
+#define PLAT_ARM_SP_IMAGE_STACK_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE +	\
+					 PLAT_SP_IMAGE_NS_BUF_SIZE)
+
+#define PLAT_SP_PRI			PLAT_RAS_PRI
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/fvp/jmptbl.i b/plat/arm/board/fvp/jmptbl.i
new file mode 100644
index 0000000..bfa9b56
--- /dev/null
+++ b/plat/arm/board/fvp/jmptbl.i
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform specific romlib functions can be added or included here.
+# The index in the output file will be generated cumulatively in the same
+# order as it is given in this file.
+# Output file can be found at: $BUILD_DIR/jmptbl.i
+#
+# Format:
+# lib	function	[patch]
+# Example:
+# rom	rom_lib_init
+# fdt	fdt_getprop_namelen	patch
+
+rom     rom_lib_init
+fdt     fdt_getprop_namelen
+fdt     fdt_setprop_inplace
+fdt     fdt_check_header
+fdt     fdt_node_offset_by_compatible
+mbedtls mbedtls_asn1_get_alg
+mbedtls mbedtls_asn1_get_alg_null
+mbedtls mbedtls_asn1_get_bitstring_null
+mbedtls mbedtls_asn1_get_bool
+mbedtls mbedtls_asn1_get_int
+mbedtls mbedtls_asn1_get_tag
+mbedtls mbedtls_free
+mbedtls mbedtls_md
+mbedtls mbedtls_md_get_size
+mbedtls mbedtls_memory_buffer_alloc_init
+mbedtls mbedtls_oid_get_md_alg
+mbedtls mbedtls_oid_get_numeric_string
+mbedtls mbedtls_oid_get_pk_alg
+mbedtls mbedtls_oid_get_sig_alg
+mbedtls mbedtls_pk_free
+mbedtls mbedtls_pk_init
+mbedtls mbedtls_pk_parse_subpubkey
+mbedtls mbedtls_pk_verify_ext
+mbedtls mbedtls_platform_set_snprintf
+mbedtls mbedtls_x509_get_rsassa_pss_params
+mbedtls mbedtls_x509_get_sig_alg
+mbedtls mbedtls_md_info_from_type
+c       exit
+c       atexit
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
new file mode 100644
index 0000000..0eb62c4
--- /dev/null
+++ b/plat/arm/board/fvp/platform.mk
@@ -0,0 +1,291 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Use the GICv3 driver on the FVP by default
+FVP_USE_GIC_DRIVER	:= FVP_GICV3
+
+# Use the SP804 timer instead of the generic one
+FVP_USE_SP804_TIMER	:= 0
+
+# Default cluster count for FVP
+FVP_CLUSTER_COUNT	:= 2
+
+# Default number of CPUs per cluster on FVP
+FVP_MAX_CPUS_PER_CLUSTER	:= 4
+
+# Default number of threads per CPU on FVP
+FVP_MAX_PE_PER_CPU	:= 1
+
+FVP_DT_PREFIX		:= fvp-base-gicv3-psci
+
+$(eval $(call assert_boolean,FVP_USE_SP804_TIMER))
+$(eval $(call add_define,FVP_USE_SP804_TIMER))
+
+# The FVP platform depends on this macro to build with correct GIC driver.
+$(eval $(call add_define,FVP_USE_GIC_DRIVER))
+
+# Pass FVP_CLUSTER_COUNT to the build system.
+$(eval $(call add_define,FVP_CLUSTER_COUNT))
+
+# Pass FVP_MAX_CPUS_PER_CLUSTER to the build system.
+$(eval $(call add_define,FVP_MAX_CPUS_PER_CLUSTER))
+
+# Pass FVP_MAX_PE_PER_CPU to the build system.
+$(eval $(call add_define,FVP_MAX_PE_PER_CPU))
+
+# Sanity check the cluster count and if FVP_CLUSTER_COUNT <= 2,
+# choose the CCI driver , else the CCN driver
+ifeq ($(FVP_CLUSTER_COUNT), 0)
+$(error "Incorrect cluster count specified for FVP port")
+else ifeq ($(FVP_CLUSTER_COUNT),$(filter $(FVP_CLUSTER_COUNT),1 2))
+FVP_INTERCONNECT_DRIVER := FVP_CCI
+else
+FVP_INTERCONNECT_DRIVER := FVP_CCN
+endif
+
+$(eval $(call add_define,FVP_INTERCONNECT_DRIVER))
+
+FVP_GICV3_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				plat/arm/common/arm_gicv3.c
+
+# Choose the GIC sources depending upon the how the FVP will be invoked
+ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
+FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}			\
+				drivers/arm/gic/v3/gic500.c
+else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600)
+FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}			\
+				drivers/arm/gic/v3/gic600.c
+else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
+FVP_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c		\
+				plat/arm/common/arm_gicv2.c
+
+FVP_DT_PREFIX		:=	fvp-base-gicv2-psci
+else
+$(error "Incorrect GIC driver chosen on FVP port")
+endif
+
+ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCI)
+FVP_INTERCONNECT_SOURCES	:= 	drivers/arm/cci/cci.c
+else ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCN)
+FVP_INTERCONNECT_SOURCES	:= 	drivers/arm/ccn/ccn.c		\
+					plat/arm/common/arm_ccn.c
+else
+$(error "Incorrect CCN driver chosen on FVP port")
+endif
+
+FVP_SECURITY_SOURCES	:=	drivers/arm/tzc/tzc400.c		\
+				plat/arm/board/fvp/fvp_security.c	\
+				plat/arm/common/arm_tzc400.c
+
+
+PLAT_INCLUDES		:=	-Iplat/arm/board/fvp/include
+
+
+PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/fvp/fvp_common.c
+
+FVP_CPU_LIBS		:=	lib/cpus/${ARCH}/aem_generic.S
+
+ifeq (${ARCH}, aarch64)
+
+# select a different set of CPU files, depending on whether we compile for
+# hardware assisted coherency cores or not
+ifeq (${HW_ASSISTED_COHERENCY}, 0)
+	FVP_CPU_LIBS	+=	lib/cpus/aarch64/cortex_a35.S			\
+				lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a57.S			\
+				lib/cpus/aarch64/cortex_a72.S			\
+				lib/cpus/aarch64/cortex_a73.S
+else
+	# AArch64-only cores
+	ifeq (${CTX_INCLUDE_AARCH32_REGS}, 0)
+		FVP_CPU_LIBS	+=	lib/cpus/aarch64/cortex_a76.S		\
+					lib/cpus/aarch64/cortex_a76ae.S		\
+					lib/cpus/aarch64/cortex_a77.S		\
+					lib/cpus/aarch64/neoverse_n1.S		\
+					lib/cpus/aarch64/neoverse_e1.S		\
+					lib/cpus/aarch64/neoverse_zeus.S	\
+					lib/cpus/aarch64/cortex_hercules.S
+	# AArch64/AArch32
+	else
+		FVP_CPU_LIBS	+=	lib/cpus/aarch64/cortex_a55.S		\
+					lib/cpus/aarch64/cortex_a75.S
+	endif
+endif
+
+else
+FVP_CPU_LIBS		+=	lib/cpus/aarch32/cortex_a32.S
+endif
+
+BL1_SOURCES		+=	drivers/arm/smmu/smmu_v3.c			\
+				drivers/arm/sp805/sp805.c			\
+				drivers/io/io_semihosting.c			\
+				lib/semihosting/semihosting.c			\
+				lib/semihosting/${ARCH}/semihosting_call.S	\
+				plat/arm/board/fvp/${ARCH}/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_bl1_setup.c		\
+				plat/arm/board/fvp/fvp_err.c			\
+				plat/arm/board/fvp/fvp_io_storage.c		\
+				plat/arm/board/fvp/fvp_trusted_boot.c		\
+				${FVP_CPU_LIBS}					\
+				${FVP_INTERCONNECT_SOURCES}
+
+
+BL2_SOURCES		+=	drivers/arm/sp805/sp805.c			\
+				drivers/io/io_semihosting.c			\
+				lib/utils/mem_region.c				\
+				lib/semihosting/semihosting.c			\
+				lib/semihosting/${ARCH}/semihosting_call.S	\
+				plat/arm/board/fvp/fvp_bl2_setup.c		\
+				plat/arm/board/fvp/fvp_err.c			\
+				plat/arm/board/fvp/fvp_io_storage.c		\
+				plat/arm/board/fvp/fvp_trusted_boot.c		\
+				plat/arm/common/arm_nor_psci_mem_protect.c	\
+				${FVP_SECURITY_SOURCES}
+
+
+
+ifeq (${BL2_AT_EL3},1)
+BL2_SOURCES		+=	plat/arm/board/fvp/${ARCH}/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_bl2_el3_setup.c		\
+				${FVP_CPU_LIBS}					\
+				${FVP_INTERCONNECT_SOURCES}
+endif
+
+ifeq (${FVP_USE_SP804_TIMER},1)
+BL2_SOURCES		+=	drivers/arm/sp804/sp804_delay_timer.c
+endif
+
+BL2U_SOURCES		+=	plat/arm/board/fvp/fvp_bl2u_setup.c		\
+				${FVP_SECURITY_SOURCES}
+
+BL31_SOURCES		+=	drivers/arm/fvp/fvp_pwrc.c			\
+				drivers/arm/smmu/smmu_v3.c			\
+				drivers/cfi/v2m/v2m_flash.c			\
+				lib/utils/mem_region.c				\
+				plat/arm/board/fvp/fvp_bl31_setup.c		\
+				plat/arm/board/fvp/fvp_pm.c			\
+				plat/arm/board/fvp/fvp_topology.c		\
+				plat/arm/board/fvp/aarch64/fvp_helpers.S	\
+				plat/arm/common/arm_nor_psci_mem_protect.c	\
+				${FVP_CPU_LIBS}					\
+				${FVP_GIC_SOURCES}				\
+				${FVP_INTERCONNECT_SOURCES}			\
+				${FVP_SECURITY_SOURCES}
+
+# Add the FDT_SOURCES and options for Dynamic Config (only for Unix env)
+ifdef UNIX_MK
+FVP_HW_CONFIG_DTS	:=	fdts/${FVP_DT_PREFIX}.dts
+FDT_SOURCES		+=	$(addprefix plat/arm/board/fvp/fdts/,	\
+					${PLAT}_tb_fw_config.dts	\
+					${PLAT}_soc_fw_config.dts	\
+					${PLAT}_nt_fw_config.dts	\
+				)
+
+FVP_TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+FVP_SOC_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_soc_fw_config.dtb
+FVP_NT_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
+
+ifeq (${SPD},tspd)
+FDT_SOURCES		+=	plat/arm/board/fvp/fdts/${PLAT}_tsp_fw_config.dts
+FVP_TOS_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_tsp_fw_config.dtb
+
+# Add the TOS_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_TOS_FW_CONFIG},--tos-fw-config))
+endif
+
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config))
+# Add the SOC_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_SOC_FW_CONFIG},--soc-fw-config))
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_NT_FW_CONFIG},--nt-fw-config))
+
+FDT_SOURCES		+=	${FVP_HW_CONFIG_DTS}
+$(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS)))
+
+# Add the HW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config))
+endif
+
+# Enable Activity Monitor Unit extensions by default
+ENABLE_AMU			:=	1
+
+# Enable dynamic mitigation support by default
+DYNAMIC_WORKAROUND_CVE_2018_3639	:=	1
+
+ifneq (${RESET_TO_BL31},1)
+# Enable reclaiming of BL31 initialisation code for secondary cores stacks for
+# FVP. We cannot enable PIE for this case because the overlayed init section
+# creates some dynamic relocations which cannot be handled by the fixup
+# logic currently.
+RECLAIM_INIT_CODE	:=	1
+else
+# Enable PIE support when RESET_TO_BL31=1
+ENABLE_PIE		:=	1
+endif
+
+ifeq (${ENABLE_AMU},1)
+BL31_SOURCES		+=	lib/cpus/aarch64/cpuamu.c		\
+				lib/cpus/aarch64/cpuamu_helpers.S
+
+ifeq (${HW_ASSISTED_COHERENCY}, 1)
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a75_pubsub.c	\
+				lib/cpus/aarch64/neoverse_n1_pubsub.c
+endif
+endif
+
+ifeq (${RAS_EXTENSION},1)
+BL31_SOURCES		+=	plat/arm/board/fvp/aarch64/fvp_ras.c
+endif
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/board/fvp/fvp_stack_protector.c
+endif
+
+ifeq (${ARCH},aarch32)
+    NEED_BL32 := yes
+endif
+
+# Enable the dynamic translation tables library.
+ifeq (${ARCH},aarch32)
+    ifeq (${RESET_TO_SP_MIN},1)
+        BL32_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+    endif
+else # if AArch64
+    ifeq (${RESET_TO_BL31},1)
+        BL31_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+    endif
+    ifeq (${ENABLE_SPM},1)
+        ifeq (${SPM_MM},0)
+            BL31_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+        endif
+    endif
+    ifeq (${SPD},trusty)
+        BL31_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+    endif
+endif
+
+# Add support for platform supplied linker script for BL31 build
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+ifneq (${BL2_AT_EL3}, 0)
+    override BL1_SOURCES =
+endif
+
+include plat/arm/board/common/board_common.mk
+include plat/arm/common/arm_common.mk
+
+# FVP being a development platform, enable capability to disable Authentication
+# dynamically if TRUSTED_BOARD_BOOT is set.
+ifeq (${TRUSTED_BOARD_BOOT}, 1)
+        DYN_DISABLE_AUTH	:=	1
+endif
diff --git a/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
new file mode 100644
index 0000000..88c91e6
--- /dev/null
+++ b/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#include "../fvp_private.h"
+
+void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+
+	/*
+	 * Initialize the correct interconnect for this cluster during cold
+	 * boot. No need for locks as no other CPU is active.
+	 */
+	fvp_interconnect_init();
+
+	/*
+	 * Enable coherency in interconnect for the primary CPU's cluster.
+	 * Earlier bootloader stages might already do this (e.g. Trusted
+	 * Firmware's BL1 does it) but we can't assume so. There is no harm in
+	 * executing this code twice anyway.
+	 * FVP PSCI code will enable coherency for other clusters.
+	 */
+	fvp_interconnect_enable();
+}
diff --git a/plat/arm/board/fvp/sp_min/sp_min-fvp.mk b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
new file mode 100644
index 0000000..0250a5f
--- /dev/null
+++ b/plat/arm/board/fvp/sp_min/sp_min-fvp.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SP_MIN source files specific to FVP platform
+BL32_SOURCES		+=	drivers/arm/fvp/fvp_pwrc.c			\
+				drivers/cfi/v2m/v2m_flash.c			\
+				lib/utils/mem_region.c				\
+				plat/arm/board/fvp/aarch32/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_pm.c			\
+				plat/arm/board/fvp/fvp_topology.c		\
+				plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c	\
+				${FVP_CPU_LIBS}					\
+				${FVP_GIC_SOURCES}				\
+				${FVP_INTERCONNECT_SOURCES}			\
+				${FVP_SECURITY_SOURCES}
+
+include plat/arm/common/sp_min/arm_sp_min.mk
diff --git a/plat/arm/board/fvp/tsp/fvp_tsp_setup.c b/plat/arm/board/fvp/tsp/fvp_tsp_setup.c
new file mode 100644
index 0000000..3c8a963
--- /dev/null
+++ b/plat/arm/board/fvp/tsp/fvp_tsp_setup.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#include "../fvp_private.h"
+
+void tsp_early_platform_setup(void)
+{
+	arm_tsp_early_platform_setup();
+
+	/* Initialize the platform config for future decision making */
+	fvp_config_setup();
+}
diff --git a/plat/arm/board/fvp/tsp/tsp-fvp.mk b/plat/arm/board/fvp/tsp/tsp-fvp.mk
new file mode 100644
index 0000000..ab3f225
--- /dev/null
+++ b/plat/arm/board/fvp/tsp/tsp-fvp.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TSP source files specific to FVP platform
+BL32_SOURCES		+=	drivers/arm/fvp/fvp_pwrc.c			\
+				plat/arm/board/fvp/aarch64/fvp_helpers.S	\
+				plat/arm/board/fvp/fvp_topology.c		\
+				plat/arm/board/fvp/tsp/fvp_tsp_setup.c		\
+				${FVP_GIC_SOURCES}
+
+include plat/arm/common/tsp/arm_tsp.mk
diff --git a/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S b/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S
new file mode 100644
index 0000000..78f6c68
--- /dev/null
+++ b/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+
+	/* --------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * For AArch32, cold-booting secondary CPUs is not yet
+	 * implemented and they panic.
+	 * --------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and warm
+	 * boot. On FVP, this information can be queried from the power
+	 * controller. The Power Control SYS Status Register (PSYSR) indicates
+	 * the wake-up reason for the CPU.
+	 *
+	 * For a cold boot, return 0.
+	 * For a warm boot, read the mailbox and return the address it contains.
+	 *
+	 * TODO: PSYSR is a common register and should be
+	 * 	accessed using locks. Since it is not possible
+	 * 	to use locks immediately after a cold reset
+	 * 	we are relying on the fact that after a cold
+	 * 	reset all cpus will read the same WK field
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* TODO support warm boot */
+	/* Cold reset */
+	mov	r0, #0
+	bx	lr
+
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Currently configured for a sigle CPU
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mov	r0, #1
+	bx	lr
+endfunc plat_is_my_cpu_primary
diff --git a/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts b/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts
new file mode 100644
index 0000000..9ab2d96
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	plat_arm_bl2 {
+		compatible = "arm,tb_fw";
+		hw_config_addr = <0x0 0x82000000>;
+		hw_config_max_size = <0x01000000>;
+		/* Disable authentication for development */
+		disable_auth = <0x0>;
+	};
+};
diff --git a/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c b/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c
new file mode 100644
index 0000000..736cf42
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	arm_bl1_early_platform_setup();
+}
+
+void plat_arm_secure_wdt_start(void)
+{
+	sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sp805_stop(ARM_SP805_TWDG_BASE);
+}
+
+void bl1_platform_setup(void)
+{
+	arm_bl1_platform_setup();
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c b/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c
new file mode 100644
index 0000000..25e0964
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "fvp_ve_private.h"
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
+{
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+
+	/* Initialize the platform config for future decision making */
+	fvp_ve_config_setup();
+}
+
+void bl2_platform_setup(void)
+{
+	arm_bl2_platform_setup();
+
+#ifdef FVP_VE_USE_SP804_TIMER
+	/*
+	 * Enable the clock override for SP804 timer 0, which means that no
+	 * clock dividers are applied and the raw (35 MHz) clock will be used
+	 */
+	mmio_write_32(V2M_SP810_BASE, FVP_SP810_CTRL_TIM0_OV);
+
+	/* Initialize delay timer driver using SP804 dual timer 0 */
+	sp804_timer_init(V2M_SP804_TIMER0_BASE,
+			SP804_TIMER_CLKMULT, SP804_TIMER_CLKDIV);
+#else
+	generic_delay_timer_init();
+#endif /* FVP_VE_USE_SP804_TIMER */
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_common.c b/plat/arm/board/fvp_ve/fvp_ve_common.c
new file mode 100644
index 0000000..768dad5
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_common.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#ifdef IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH1_RW,
+	V2M_MAP_IOFPGA,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH1_RW,
+	V2M_MAP_IOFPGA,
+	ARM_MAP_NS_DRAM1,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL32
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_IOFPGA,
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+
+ARM_CASSERT_MMAP
+
+void __init fvp_ve_config_setup(void)
+{
+	unsigned int sys_id, arch;
+
+	sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID);
+	arch = (sys_id >> V2M_SYS_ID_ARCH_SHIFT) & V2M_SYS_ID_ARCH_MASK;
+
+	if (arch != ARCH_MODEL_VE) {
+		ERROR("This firmware is for FVP VE models\n");
+		panic();
+	}
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return FVP_VE_TIMER_BASE_FREQUENCY;
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_def.h b/plat/arm/board/fvp_ve/fvp_ve_def.h
new file mode 100644
index 0000000..565753a
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_def.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_VE_DEF_H
+#define FVP_VE_DEF_H
+
+#include <lib/utils_def.h>
+
+/* Default cluster count for FVP VE */
+#define FVP_VE_CLUSTER_COUNT	1
+
+/* Default number of CPUs per cluster on FVP VE */
+#define FVP_VE_MAX_CPUS_PER_CLUSTER	1
+
+/* Default number of threads per CPU on FVP VE */
+#define FVP_VE_MAX_PE_PER_CPU	1
+
+#define FVP_VE_CORE_COUNT 1
+
+#define FVP_VE_PRIMARY_CPU			0x0
+
+/*******************************************************************************
+ * FVP memory map related constants
+ ******************************************************************************/
+
+#define FLASH1_BASE			0x0c000000
+#define FLASH1_SIZE			0x04000000
+
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE			0x20000000
+#define DEVICE0_SIZE			0x0c200000
+
+#define NSRAM_BASE			0x2e000000
+#define NSRAM_SIZE			0x10000
+
+#define PCIE_EXP_BASE			0x40000000
+#define TZRNG_BASE			0x7fe60000
+
+#define ARCH_MODEL_VE			0x5
+
+/* FVP Power controller base address*/
+#define PWRC_BASE			UL(0x1c100000)
+
+/* FVP SP804 timer frequency is 35 MHz*/
+#define SP804_TIMER_CLKMULT		1
+#define SP804_TIMER_CLKDIV		35
+
+/* SP810 controller. FVP specific flags */
+#define FVP_SP810_CTRL_TIM0_OV		(1 << 16)
+#define FVP_SP810_CTRL_TIM1_OV		(1 << 18)
+#define FVP_SP810_CTRL_TIM2_OV		(1 << 20)
+#define FVP_SP810_CTRL_TIM3_OV		(1 << 22)
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+/* VE compatible GIC memory map */
+#define VE_GICD_BASE			0x2c001000
+#ifdef ARM_CORTEX_A5
+#define VE_GICC_BASE			0x2c000100
+#else
+#define VE_GICC_BASE			0x2c002000
+#endif
+#define VE_GICH_BASE			0x2c004000
+#define VE_GICV_BASE			0x2c006000
+
+#define FVP_VE_IRQ_TZ_WDOG			56
+#define FVP_VE_IRQ_SEC_SYS_TIMER		57
+
+#define V2M_FLASH1_BASE			UL(0x0C000000)
+#define V2M_FLASH1_SIZE			UL(0x04000000)
+
+#define V2M_MAP_FLASH1_RW		MAP_REGION_FLAT(V2M_FLASH1_BASE,\
+						V2M_FLASH1_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define V2M_MAP_FLASH1_RO		MAP_REGION_FLAT(V2M_FLASH1_BASE,\
+						V2M_FLASH1_SIZE,	\
+						MT_RO_DATA | MT_SECURE)
+
+#endif /* FVP_VE_DEF_H */
diff --git a/plat/arm/board/fvp_ve/fvp_ve_err.c b/plat/arm/board/fvp_ve/fvp_ve_err.c
new file mode 100644
index 0000000..7f9d2f7
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * FVP VE error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	while (1) {
+		wfi();
+	}
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_pm.c b/plat/arm/board/fvp_ve/fvp_ve_pm.c
new file mode 100644
index 0000000..a4d627b
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_pm.c
@@ -0,0 +1,25 @@
+/*
+* Copyright (c) 2019, Arm Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-3-Clause
+*/
+
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Export the platform handlers via fvp_ve_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+plat_psci_ops_t fvp_ve_psci_pm_ops = {
+	/* dummy struct */
+	.validate_ns_entrypoint = NULL,
+};
+
+int __init plat_setup_psci_ops(uintptr_t sec_entrypoint,
+				const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &fvp_ve_psci_pm_ops;
+
+	return 0;
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_private.h b/plat/arm/board/fvp_ve/fvp_ve_private.h
new file mode 100644
index 0000000..5d396bc
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FVP_VE_PRIVATE_H
+#define FVP_VE_PRIVATE_H
+
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+void fvp_ve_config_setup(void);
+
+#endif /* FVP_VE_PRIVATE_H */
diff --git a/plat/arm/board/fvp_ve/fvp_ve_security.c b/plat/arm/board/fvp_ve/fvp_ve_security.c
new file mode 100644
index 0000000..24465cb
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_security.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * We assume that all security programming is done by the primary core.
+ */
+void plat_arm_security_setup(void)
+{
+	/*
+	 * The Base FVP has a TrustZone address space controller, the Foundation
+	 * FVP does not. Trying to program the device on the foundation FVP will
+	 * cause an abort.
+	 *
+	 * If the platform had additional peripheral specific security
+	 * configurations, those would be configured here.
+	 */
+
+	return;
+}
diff --git a/plat/arm/board/fvp_ve/fvp_ve_topology.c b/plat/arm/board/fvp_ve/fvp_ve_topology.c
new file mode 100644
index 0000000..51cc9da
--- /dev/null
+++ b/plat/arm/board/fvp_ve/fvp_ve_topology.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <plat/arm/common/arm_config.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* The FVP VE power domain tree descriptor */
+static const unsigned char fvp_ve_power_domain_tree_desc[] = {
+	1,
+	/* No of children for the root node */
+	FVP_VE_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	FVP_VE_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the topology according to FVP_VE_CLUSTER_COUNT.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return fvp_ve_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * Currently FVP VE has only been tested with one core, therefore 0 is returned.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	return 0;
+}
diff --git a/plat/arm/board/fvp_ve/include/platform_def.h b/plat/arm/board/fvp_ve/include/platform_def.h
new file mode 100644
index 0000000..4e575e1
--- /dev/null
+++ b/plat/arm/board/fvp_ve/include/platform_def.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/common/common_def.h>
+
+#include "../fvp_ve_def.h"
+
+#define ARM_CACHE_WRITEBACK_SHIFT	6
+
+/* Memory location options for TSP */
+#define ARM_DRAM_ID			2
+
+#define ARM_DRAM1_BASE			UL(0x80000000)
+#define ARM_DRAM1_SIZE			UL(0x80000000)
+#define ARM_DRAM1_END			(ARM_DRAM1_BASE +		\
+					 ARM_DRAM1_SIZE - 1)
+
+#define ARM_DRAM2_BASE			PLAT_ARM_DRAM2_BASE
+#define ARM_DRAM2_SIZE			PLAT_ARM_DRAM2_SIZE
+#define ARM_DRAM2_END			(ARM_DRAM2_BASE +		\
+					 ARM_DRAM2_SIZE - 1)
+
+#define ARM_NS_DRAM1_BASE		ARM_DRAM1_BASE
+/*
+ * The last 2MB is meant to be NOLOAD and will not be zero
+ * initialized.
+ */
+#define ARM_NS_DRAM1_SIZE		(ARM_DRAM1_SIZE -		\
+					 0x00200000)
+
+
+/* The first 4KB of NS DRAM1 are used as shared memory */
+#define FVP_VE_SHARED_RAM_BASE		ARM_NS_DRAM1_BASE
+#define FVP_VE_SHARED_RAM_SIZE		UL(0x00001000)	/* 4 KB */
+
+/* The next 252 kB of NS DRAM is used to load the BL images */
+#define ARM_BL_RAM_BASE			(FVP_VE_SHARED_RAM_BASE +	\
+					 FVP_VE_SHARED_RAM_SIZE)
+#define ARM_BL_RAM_SIZE			(PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE -	\
+					 FVP_VE_SHARED_RAM_SIZE)
+
+
+#define ARM_IRQ_SEC_PHY_TIMER		29
+
+#define ARM_IRQ_SEC_SGI_0		8
+#define ARM_IRQ_SEC_SGI_1		9
+#define ARM_IRQ_SEC_SGI_2		10
+#define ARM_IRQ_SEC_SGI_3		11
+#define ARM_IRQ_SEC_SGI_4		12
+#define ARM_IRQ_SEC_SGI_5		13
+#define ARM_IRQ_SEC_SGI_6		14
+#define ARM_IRQ_SEC_SGI_7		15
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE)
+
+#define ARM_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_EDGE)
+
+#define ARM_MAP_SHARED_RAM		MAP_REGION_FLAT(		\
+						FVP_VE_SHARED_RAM_BASE,	\
+						FVP_VE_SHARED_RAM_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define ARM_MAP_NS_DRAM1		MAP_REGION_FLAT(		\
+						ARM_NS_DRAM1_BASE,	\
+						ARM_NS_DRAM1_SIZE,	\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define ARM_MAP_DRAM2			MAP_REGION_FLAT(		\
+						ARM_DRAM2_BASE,		\
+						ARM_DRAM2_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define ARM_MAP_BL_RO			MAP_REGION_FLAT(			\
+						BL_CODE_BASE,			\
+						BL_CODE_END - BL_CODE_BASE,	\
+						MT_CODE | MT_SECURE),		\
+					MAP_REGION_FLAT(			\
+						BL_RO_DATA_BASE,		\
+						BL_RO_DATA_END			\
+							- BL_RO_DATA_BASE,	\
+						MT_RO_DATA | MT_SECURE)
+
+#if USE_COHERENT_MEM
+#define ARM_MAP_BL_COHERENT_RAM		MAP_REGION_FLAT(			\
+						BL_COHERENT_RAM_BASE,		\
+						BL_COHERENT_RAM_END		\
+							- BL_COHERENT_RAM_BASE, \
+						MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+/*
+ * The max number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+#define ARM_BL_REGIONS			5
+
+#define MAX_MMAP_REGIONS		(PLAT_ARM_MMAP_ENTRIES +	\
+					 ARM_BL_REGIONS)
+
+/* Memory mapped Generic timer interfaces  */
+#define FVP_VE_TIMER_BASE_FREQUENCY		UL(24000000)
+#define ARM_SYS_CNTREAD_BASE	UL(0x2a800000)
+#define ARM_SYS_CNT_BASE_S		UL(0x2a820000)
+#define ARM_SYS_CNT_BASE_NS		UL(0x2a830000)
+
+#define ARM_CONSOLE_BAUDRATE		115200
+
+/* Trusted Watchdog constants */
+#define ARM_SP805_TWDG_BASE		UL(0x1C0F0000)
+#define ARM_SP805_TWDG_CLK_HZ		32768
+/* The TBBR document specifies a watchdog timeout of 256 seconds. SP805
+ * asserts reset after two consecutive countdowns (2 x 128 = 256 sec) */
+#define ARM_TWDG_TIMEOUT_SEC		128
+#define ARM_TWDG_LOAD_VAL		(ARM_SP805_TWDG_CLK_HZ * 	\
+					 ARM_TWDG_TIMEOUT_SEC)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE			(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE			(1ULL << 32)
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		1
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		2
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE		(U(1) << ARM_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base
+ * and limit. Leave enough space of BL2 meminfo.
+ */
+#define ARM_TB_FW_CONFIG_BASE		(ARM_BL_RAM_BASE + sizeof(meminfo_t))
+#define ARM_TB_FW_CONFIG_LIMIT		(ARM_BL_RAM_BASE + PAGE_SIZE)
+
+/*******************************************************************************
+ * BL1 specific defines.
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ ******************************************************************************/
+#define BL1_RO_BASE			0x00000000
+#define BL1_RO_LIMIT			PLAT_ARM_TRUSTED_ROM_SIZE
+/*
+ * Put BL1 RW at the top of the memory allocated for BL images in NS DRAM.
+ */
+#define BL1_RW_BASE			(ARM_BL_RAM_BASE +		\
+						ARM_BL_RAM_SIZE -	\
+						(PLAT_ARM_MAX_BL1_RW_SIZE))
+#define BL1_RW_LIMIT			(ARM_BL_RAM_BASE + 		\
+					    (ARM_BL_RAM_SIZE))
+
+
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+
+/*
+ * Put BL2 just below BL1.
+ */
+#define BL2_BASE			(BL1_RW_BASE - FVP_VE_MAX_BL2_SIZE)
+#define BL2_LIMIT			BL1_RW_BASE
+
+
+/* Put BL32 below BL2 in NS DRAM.*/
+#define ARM_BL2_MEM_DESC_BASE		ARM_TB_FW_CONFIG_LIMIT
+
+#define BL32_BASE			((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\
+						- PLAT_ARM_MAX_BL32_SIZE)
+#define BL32_PROGBITS_LIMIT		BL2_BASE
+#define BL32_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
+
+/* Required platform porting definitions */
+#define PLATFORM_CORE_COUNT		1
+#define PLAT_NUM_PWR_DOMAINS		((FVP_VE_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT) + 1)
+
+#define PLAT_MAX_PWR_LVL		2
+
+/*
+ * Other platform porting definitions are provided by included headers
+ */
+
+/*
+ * Required ARM standard platform porting definitions
+ */
+
+#define PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE	0x00040000	/* 256 KB */
+
+#define PLAT_ARM_TRUSTED_ROM_BASE	0x00000000
+#define PLAT_ARM_TRUSTED_ROM_SIZE	0x04000000	/* 64 MB */
+
+#define PLAT_ARM_DRAM2_BASE		ULL(0x880000000)
+#define PLAT_ARM_DRAM2_SIZE		ULL(0x80000000)
+
+/*
+ * Load address of BL33 for this platform port
+ */
+#define PLAT_ARM_NS_IMAGE_BASE	(ARM_DRAM1_BASE + U(0x8000000))
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		6
+#else
+# define PLAT_ARM_MMAP_ENTRIES		12
+# define MAX_XLAT_TABLES		6
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_ARM_MAX_BL1_RW_SIZE	0xB000
+
+/*
+ * FVP_VE_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#define FVP_VE_MAX_BL2_SIZE		0x11000
+
+/*
+ * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is
+ * calculated using the current SP_MIN PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW
+ */
+#define PLAT_ARM_MAX_BL32_SIZE		0x3B000
+/*
+
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+#  define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#  define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+/* Reserve the last block of flash for PSCI MEM PROTECT flag */
+#define PLAT_ARM_FIP_BASE		V2M_FLASH1_BASE
+#define PLAT_ARM_FIP_MAX_SIZE		(V2M_FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#define PLAT_ARM_NVM_BASE		V2M_FLASH1_BASE
+#define PLAT_ARM_NVM_SIZE		(V2M_FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_ARM_BOOT_UART_BASE		V2M_IOFPGA_UART0_BASE
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ	V2M_IOFPGA_UART0_CLK_IN_HZ
+
+#define PLAT_ARM_RUN_UART_BASE		V2M_IOFPGA_UART1_BASE
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ	V2M_IOFPGA_UART1_CLK_IN_HZ
+
+#define PLAT_ARM_CRASH_UART_BASE	PLAT_ARM_RUN_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ	PLAT_ARM_RUN_UART_CLK_IN_HZ
+
+/* System timer related constants */
+#define PLAT_ARM_NSTIMER_FRAME_ID		1
+
+/* Mailbox base address */
+#define FVP_VE_TRUSTED_MAILBOX_BASE	FVP_VE_SHARED_RAM_BASE
+
+/*
+ * GIC related constants to cater for GICv2
+ */
+#define PLAT_ARM_GICD_BASE		VE_GICD_BASE
+#define PLAT_ARM_GICC_BASE		VE_GICC_BASE
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	ARM_G1S_IRQ_PROPS(grp), \
+	INTR_PROP_DESC(FVP_VE_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(FVP_VE_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_H */
diff --git a/plat/arm/board/fvp_ve/platform.mk b/plat/arm/board/fvp_ve/platform.mk
new file mode 100644
index 0000000..4d21f4b
--- /dev/null
+++ b/plat/arm/board/fvp_ve/platform.mk
@@ -0,0 +1,125 @@
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifdef ARM_CORTEX_A5
+# Use the SP804 timer instead of the generic one
+FVP_VE_USE_SP804_TIMER	:= 1
+$(eval $(call add_define,FVP_VE_USE_SP804_TIMER))
+BL2_SOURCES		+=	drivers/arm/sp804/sp804_delay_timer.c
+endif
+
+FVP_VE_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c		\
+				plat/arm/common/arm_gicv2.c
+
+FVP_VE_SECURITY_SOURCES	:=	plat/arm/board/fvp_ve/fvp_ve_security.c
+
+PLAT_INCLUDES		:=	-Iplat/arm/board/fvp_ve/include
+
+PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/fvp_ve/fvp_ve_common.c		\
+				plat/arm/common/${ARCH}/arm_helpers.S		\
+				plat/arm/common/arm_common.c			\
+				plat/arm/common/arm_console.c			\
+				drivers/arm/pl011/${ARCH}/pl011_console.S	\
+				plat/arm/board/common/${ARCH}/board_arm_helpers.S
+
+ifdef ARM_CORTEX_A5
+FVP_VE_CPU_LIBS		:=	lib/cpus/aarch32/cortex_a5.S
+else
+FVP_VE_CPU_LIBS		:=	lib/cpus/aarch32/cortex_a7.S
+endif
+
+BL1_SOURCES		+=	drivers/arm/sp805/sp805.c			\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/arm/common/arm_bl1_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/board/fvp_ve/fvp_ve_err.c		\
+				plat/arm/common/arm_io_storage.c		\
+				drivers/cfi/v2m/v2m_flash.c			\
+				plat/arm/board/fvp_ve/${ARCH}/fvp_ve_helpers.S	\
+				plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c	\
+				lib/aarch32/arm32_aeabi_divmod.c		\
+				lib/aarch32/arm32_aeabi_divmod_a32.S		\
+				${FVP_VE_CPU_LIBS}					\
+				${DYN_CFG_SOURCES}
+
+BL2_SOURCES		+=	plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c		\
+				lib/aarch32/arm32_aeabi_divmod.c		\
+				lib/aarch32/arm32_aeabi_divmod_a32.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/cfi/v2m/v2m_flash.c			\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/arm/common/arm_bl2_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/board/fvp_ve/fvp_ve_err.c		\
+				plat/arm/common/arm_io_storage.c		\
+				plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c	\
+				plat/arm/common/arm_image_load.c		\
+				common/desc_image_load.c			\
+				${DYN_CFG_SOURCES}				\
+				${FVP_VE_SECURITY_SOURCES}
+
+# Add the FDT_SOURCES and options for Dynamic Config (only for Unix env)
+ifdef UNIX_MK
+
+FDT_SOURCES		+=	plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts
+
+FVP_TB_FW_CONFIG	:=	${BUILD_PLAT}/fdts/fvp_ve_tb_fw_config.dtb
+
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config))
+
+FDT_SOURCES		+=	${FVP_HW_CONFIG_DTS}
+$(eval FVP_HW_CONFIG	:=	${BUILD_PLAT}/$(patsubst %.dts,%.dtb, \
+	fdts/$(notdir ${FVP_HW_CONFIG_DTS})))
+# Add the HW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config))
+endif
+
+NEED_BL32 := yes
+
+# Modification of arm_common.mk
+
+# Process ARM_DISABLE_TRUSTED_WDOG flag
+# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set
+ARM_DISABLE_TRUSTED_WDOG	:=	0
+ifeq (${SPIN_ON_BL1_EXIT}, 1)
+ARM_DISABLE_TRUSTED_WDOG	:=	1
+endif
+$(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG))
+$(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG))
+
+# Use translation tables library v1 if using Cortex-A5
+ifdef ARM_CORTEX_A5
+ARM_XLAT_TABLES_LIB_V1		:=	1
+else
+ARM_XLAT_TABLES_LIB_V1		:=	0
+endif
+$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
+$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
+
+ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
+	# Only use nonlpae version of xlatv1 otherwise use xlat v2
+	PLAT_BL_COMMON_SOURCES	+=	lib/xlat_tables/${ARCH}/nonlpae_tables.c
+else
+	include lib/xlat_tables_v2/xlat_tables.mk
+	PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}
+endif
+
+# Add `libfdt` and Arm common helpers required for Dynamic Config
+include lib/libfdt/libfdt.mk
+
+DYN_CFG_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
+				plat/arm/common/arm_dyn_cfg_helpers.c	\
+				common/fdt_wrappers.c
+
diff --git a/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c b/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
new file mode 100644
index 0000000..e6a1bbe
--- /dev/null
+++ b/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <plat/arm/common/plat_arm.h>
+
+void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+}
diff --git a/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk b/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk
new file mode 100644
index 0000000..4ca810d
--- /dev/null
+++ b/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SP_MIN source files specific to FVP platform
+BL32_SOURCES		+=	drivers/cfi/v2m/v2m_flash.c			\
+				lib/utils/mem_region.c				\
+				plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S	\
+				drivers/arm/fvp/fvp_pwrc.c			\
+				plat/arm/board/fvp_ve/fvp_ve_pm.c		\
+				plat/arm/board/fvp_ve/fvp_ve_topology.c		\
+				plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c	\
+				lib/aarch32/arm32_aeabi_divmod.c		\
+				lib/aarch32/arm32_aeabi_divmod_a32.S		\
+				plat/arm/common/sp_min/arm_sp_min_setup.c	\
+				plat/common/aarch32/platform_mp_stack.S		\
+				plat/common/plat_psci_common.c			\
+				${FVP_VE_CPU_LIBS}				\
+				${FVP_VE_GIC_SOURCES}				\
+				${FVP_VE_SECURITY_SOURCES}
diff --git a/plat/arm/board/juno/aarch32/juno_helpers.S b/plat/arm/board/juno/aarch32/juno_helpers.S
new file mode 100644
index 0000000..8f9561c
--- /dev/null
+++ b/plat/arm/board/juno/aarch32/juno_helpers.S
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_reset_handler
+	.globl	plat_arm_calc_core_pos
+
+#define JUNO_REVISION(rev)	REV_JUNO_R##rev
+#define JUNO_HANDLER(rev)	plat_reset_handler_juno_r##rev
+#define JUMP_TO_HANDLER_IF_JUNO_R(revision)	\
+	jump_to_handler JUNO_REVISION(revision), JUNO_HANDLER(revision)
+
+	/* --------------------------------------------------------------------
+	 * Helper macro to jump to the given handler if the board revision
+	 * matches.
+	 * Expects the Juno board revision in x0.
+	 * --------------------------------------------------------------------
+	 */
+	.macro jump_to_handler _revision, _handler
+	cmp	r0, #\_revision
+	beq	\_handler
+	.endm
+
+	/* --------------------------------------------------------------------
+	 * Platform reset handler for Juno R0.
+	 *
+	 * Juno R0 has the following topology:
+	 * - Quad core Cortex-A53 processor cluster;
+	 * - Dual core Cortex-A57 processor cluster.
+	 *
+	 * This handler does the following:
+	 * - Implement workaround for defect id 831273 by enabling an event
+	 *   stream every 65536 cycles.
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 * --------------------------------------------------------------------
+	 */
+func JUNO_HANDLER(0)
+	/* --------------------------------------------------------------------
+	 * Enable the event stream every 65536 cycles
+	 * --------------------------------------------------------------------
+	 */
+	mov	r0, #(0xf << EVNTI_SHIFT)
+	orr	r0, r0, #EVNTEN_BIT
+	stcopr	r0, CNTKCTL
+
+	/* --------------------------------------------------------------------
+	 * Nothing else to do on Cortex-A53.
+	 * --------------------------------------------------------------------
+	 */
+	jump_if_cpu_midr CORTEX_A53_MIDR, 1f
+
+	/* --------------------------------------------------------------------
+	 * Cortex-A57 specific settings
+	 * --------------------------------------------------------------------
+	 */
+	mov	r0, #((CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
+		      (CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT))
+	stcopr	r0, CORTEX_A57_L2CTLR
+1:
+	isb
+	bx	lr
+endfunc JUNO_HANDLER(0)
+
+	/* --------------------------------------------------------------------
+	 * Platform reset handler for Juno R1.
+	 *
+	 * Juno R1 has the following topology:
+	 * - Quad core Cortex-A53 processor cluster;
+	 * - Dual core Cortex-A57 processor cluster.
+	 *
+	 * This handler does the following:
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 *
+	 * Note that:
+	 * - The default value for the L2 Tag RAM latency for Cortex-A57 is
+	 *   suitable.
+	 * - Defect #831273 doesn't affect Juno R1.
+	 * --------------------------------------------------------------------
+	 */
+func JUNO_HANDLER(1)
+	/* --------------------------------------------------------------------
+	 * Nothing to do on Cortex-A53.
+	 * --------------------------------------------------------------------
+	 */
+	jump_if_cpu_midr CORTEX_A57_MIDR, A57
+	bx	lr
+
+A57:
+	/* --------------------------------------------------------------------
+	 * Cortex-A57 specific settings
+	 * --------------------------------------------------------------------
+	 */
+	mov	r0, #(CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT)
+	stcopr	r0, CORTEX_A57_L2CTLR
+	isb
+	bx	lr
+endfunc JUNO_HANDLER(1)
+
+	/* --------------------------------------------------------------------
+	 * Platform reset handler for Juno R2.
+	 *
+	 * Juno R2 has the following topology:
+	 * - Quad core Cortex-A53 processor cluster;
+	 * - Dual core Cortex-A72 processor cluster.
+	 *
+	 * This handler does the following:
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A72
+	 * - Set the L2 Tag RAM latency to 1 (i.e. 2 cycles) for Cortex-A72
+	 *
+	 * Note that:
+	 * - Defect #831273 doesn't affect Juno R2.
+	 * --------------------------------------------------------------------
+	 */
+func JUNO_HANDLER(2)
+	/* --------------------------------------------------------------------
+	 * Nothing to do on Cortex-A53.
+	 * --------------------------------------------------------------------
+	 */
+	jump_if_cpu_midr CORTEX_A72_MIDR, A72
+	bx	lr
+
+A72:
+	/* --------------------------------------------------------------------
+	 * Cortex-A72 specific settings
+	 * --------------------------------------------------------------------
+	 */
+	mov	r0, #((CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
+		      (CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES << CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT))
+	stcopr	r0, CORTEX_A72_L2CTLR
+	isb
+	bx	lr
+endfunc JUNO_HANDLER(2)
+
+	/* --------------------------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the Juno board revision and call the appropriate reset
+	 * handler.
+	 * --------------------------------------------------------------------
+	 */
+func plat_reset_handler
+	/* Read the V2M SYS_ID register */
+	ldr	r0, =(V2M_SYSREGS_BASE + V2M_SYS_ID)
+	ldr	r1, [r0]
+	/* Extract board revision from the SYS_ID */
+	ubfx	r0, r1, #V2M_SYS_ID_REV_SHIFT, #4
+
+	JUMP_TO_HANDLER_IF_JUNO_R(0)
+	JUMP_TO_HANDLER_IF_JUNO_R(1)
+	JUMP_TO_HANDLER_IF_JUNO_R(2)
+
+	/* Board revision is not supported */
+	no_ret	plat_panic_handler
+
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *  Helper function to calculate the core position.
+	 * -----------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	b	css_calc_core_pos_swap_cluster
+endfunc plat_arm_calc_core_pos
diff --git a/plat/arm/board/juno/aarch64/juno_helpers.S b/plat/arm/board/juno/aarch64/juno_helpers.S
new file mode 100644
index 0000000..c94fa3e
--- /dev/null
+++ b/plat/arm/board/juno/aarch64/juno_helpers.S
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_reset_handler
+	.globl	plat_arm_calc_core_pos
+#if JUNO_AARCH32_EL3_RUNTIME
+	.globl	plat_get_my_entrypoint
+	.globl	juno_reset_to_aarch32_state
+#endif
+
+#define JUNO_REVISION(rev)	REV_JUNO_R##rev
+#define JUNO_HANDLER(rev)	plat_reset_handler_juno_r##rev
+#define JUMP_TO_HANDLER_IF_JUNO_R(revision)	\
+	jump_to_handler JUNO_REVISION(revision), JUNO_HANDLER(revision)
+
+	/* --------------------------------------------------------------------
+	 * Helper macro to jump to the given handler if the board revision
+	 * matches.
+	 * Expects the Juno board revision in x0.
+	 * --------------------------------------------------------------------
+	 */
+	.macro jump_to_handler _revision, _handler
+	cmp	x0, #\_revision
+	b.eq	\_handler
+	.endm
+
+	/* --------------------------------------------------------------------
+	 * Platform reset handler for Juno R0.
+	 *
+	 * Juno R0 has the following topology:
+	 * - Quad core Cortex-A53 processor cluster;
+	 * - Dual core Cortex-A57 processor cluster.
+	 *
+	 * This handler does the following:
+	 * - Implement workaround for defect id 831273 by enabling an event
+	 *   stream every 65536 cycles.
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 * --------------------------------------------------------------------
+	 */
+func JUNO_HANDLER(0)
+	/* --------------------------------------------------------------------
+	 * Enable the event stream every 65536 cycles
+	 * --------------------------------------------------------------------
+	 */
+	mov     x0, #(0xf << EVNTI_SHIFT)
+	orr     x0, x0, #EVNTEN_BIT
+	msr     CNTKCTL_EL1, x0
+
+	/* --------------------------------------------------------------------
+	 * Nothing else to do on Cortex-A53.
+	 * --------------------------------------------------------------------
+	 */
+	jump_if_cpu_midr CORTEX_A53_MIDR, 1f
+
+	/* --------------------------------------------------------------------
+	 * Cortex-A57 specific settings
+	 * --------------------------------------------------------------------
+	 */
+	mov	x0, #((CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
+		      (CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT))
+	msr     CORTEX_A57_L2CTLR_EL1, x0
+1:
+	isb
+	ret
+endfunc JUNO_HANDLER(0)
+
+	/* --------------------------------------------------------------------
+	 * Platform reset handler for Juno R1.
+	 *
+	 * Juno R1 has the following topology:
+	 * - Quad core Cortex-A53 processor cluster;
+	 * - Dual core Cortex-A57 processor cluster.
+	 *
+	 * This handler does the following:
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 *
+	 * Note that:
+	 * - The default value for the L2 Tag RAM latency for Cortex-A57 is
+	 *   suitable.
+	 * - Defect #831273 doesn't affect Juno R1.
+	 * --------------------------------------------------------------------
+	 */
+func JUNO_HANDLER(1)
+	/* --------------------------------------------------------------------
+	 * Nothing to do on Cortex-A53.
+	 * --------------------------------------------------------------------
+	 */
+	jump_if_cpu_midr CORTEX_A57_MIDR, A57
+	ret
+
+A57:
+	/* --------------------------------------------------------------------
+	 * Cortex-A57 specific settings
+	 * --------------------------------------------------------------------
+	 */
+	mov	x0, #(CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT)
+	msr     CORTEX_A57_L2CTLR_EL1, x0
+	isb
+	ret
+endfunc JUNO_HANDLER(1)
+
+	/* --------------------------------------------------------------------
+	 * Platform reset handler for Juno R2.
+	 *
+	 * Juno R2 has the following topology:
+	 * - Quad core Cortex-A53 processor cluster;
+	 * - Dual core Cortex-A72 processor cluster.
+	 *
+	 * This handler does the following:
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A72
+	 * - Set the L2 Tag RAM latency to 1 (i.e. 2 cycles) for Cortex-A72
+	 *
+	 * Note that:
+	 * - Defect #831273 doesn't affect Juno R2.
+	 * --------------------------------------------------------------------
+	 */
+func JUNO_HANDLER(2)
+	/* --------------------------------------------------------------------
+	 * Nothing to do on Cortex-A53.
+	 * --------------------------------------------------------------------
+	 */
+	jump_if_cpu_midr CORTEX_A72_MIDR, A72
+	ret
+
+A72:
+	/* --------------------------------------------------------------------
+	 * Cortex-A72 specific settings
+	 * --------------------------------------------------------------------
+	 */
+	mov	x0, #((CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
+		      (CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES << CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT))
+	msr     CORTEX_A57_L2CTLR_EL1, x0
+	isb
+	ret
+endfunc JUNO_HANDLER(2)
+
+	/* --------------------------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the Juno board revision and call the appropriate reset
+	 * handler.
+	 * --------------------------------------------------------------------
+	 */
+func plat_reset_handler
+	/* Read the V2M SYS_ID register */
+	mov_imm	x0, (V2M_SYSREGS_BASE + V2M_SYS_ID)
+	ldr	w1, [x0]
+	/* Extract board revision from the SYS_ID */
+	ubfx	x0, x1, #V2M_SYS_ID_REV_SHIFT, #4
+
+	JUMP_TO_HANDLER_IF_JUNO_R(0)
+	JUMP_TO_HANDLER_IF_JUNO_R(1)
+	JUMP_TO_HANDLER_IF_JUNO_R(2)
+
+	/* Board revision is not supported */
+	no_ret	plat_panic_handler
+
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 *  void juno_do_reset_to_aarch32_state(void);
+	 *
+	 *  Request warm reset to AArch32 mode.
+	 * -----------------------------------------------------
+	 */
+func juno_do_reset_to_aarch32_state
+	mov	x0, #RMR_EL3_RR_BIT
+	dsb	sy
+	msr	rmr_el3, x0
+	isb
+	wfi
+	b	plat_panic_handler
+endfunc juno_do_reset_to_aarch32_state
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *  Helper function to calculate the core position.
+	 * -----------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	b	css_calc_core_pos_swap_cluster
+endfunc plat_arm_calc_core_pos
+
+#if JUNO_AARCH32_EL3_RUNTIME
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and a warm
+	 * boot. On JUNO platform, this distinction is based on the contents of
+	 * the Trusted Mailbox. It is initialised to zero by the SCP before the
+	 * AP cores are released from reset. Therefore, a zero mailbox means
+	 * it's a cold reset. If it is a warm boot then a request to reset to
+	 * AArch32 state is issued. This is the only way to reset to AArch32
+	 * in EL3 on Juno. A trampoline located at the high vector address
+	 * has already been prepared by BL1.
+	 *
+	 * This functions returns the contents of the mailbox, i.e.:
+	 *  - 0 for a cold boot;
+	 *  - request warm reset in AArch32 state for warm boot case;
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
+	ldr	x0, [x0]
+	cbz	x0, return
+	b	juno_do_reset_to_aarch32_state
+return:
+	ret
+endfunc plat_get_my_entrypoint
+
+/*
+ * Emit a "movw r0, #imm16" which moves the lower
+ * 16 bits of `_val` into r0.
+ */
+.macro emit_movw _reg_d, _val
+	mov_imm	\_reg_d, (0xe3000000 | \
+			((\_val & 0xfff) | \
+			((\_val & 0xf000) << 4)))
+.endm
+
+/*
+ * Emit a "movt r0, #imm16" which moves the upper
+ * 16 bits of `_val` into r0.
+ */
+.macro emit_movt _reg_d, _val
+	mov_imm	\_reg_d, (0xe3400000 | \
+			(((\_val & 0x0fff0000) >> 16) | \
+			((\_val & 0xf0000000) >> 12)))
+.endm
+
+/*
+ * This function writes the trampoline code at HI-VEC (0xFFFF0000)
+ * address which loads r0 with the entrypoint address for
+ * BL32 (a.k.a SP_MIN) when EL3 is in AArch32 mode. A warm reset
+ * to AArch32 mode is then requested by writing into RMR_EL3.
+ */
+func juno_reset_to_aarch32_state
+	/*
+	 * Invalidate all caches before the warm reset to AArch32 state.
+	 * This is required on the Juno AArch32 boot flow because the L2
+	 * unified cache may contain code and data from when the processor
+	 * was still executing in AArch64 state.  This code only runs on
+	 * the primary core, all other cores are powered down.
+	 */
+	mov	x0, #DCISW
+	bl	dcsw_op_all
+
+	emit_movw	w0, BL32_BASE
+	emit_movt	w1, BL32_BASE
+	/* opcode "bx r0" to branch using r0 in AArch32 mode */
+	mov_imm	w2, 0xe12fff10
+
+	/* Write the above opcodes at HI-VECTOR location */
+	mov_imm	x3, HI_VECTOR_BASE
+	str	w0, [x3], #4
+	str	w1, [x3], #4
+	str	w2, [x3]
+
+	b	juno_do_reset_to_aarch32_state
+endfunc juno_reset_to_aarch32_state
+
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/include/plat_macros.S b/plat/arm/board/juno/include/plat_macros.S
new file mode 100644
index 0000000..ec94a4f
--- /dev/null
+++ b/plat/arm/board/juno/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <cci_macros.S>
+#include <css_macros.S>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant platform registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	css_print_gic_regs
+	print_cci_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
new file mode 100644
index 0000000..83aeeb4
--- /dev/null
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <drivers/arm/tzc400.h>
+#if TRUSTED_BOARD_BOOT
+#include <drivers/auth/mbedtls/mbedtls_config.h>
+#endif
+#include <plat/arm/board/common/board_css_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+#include "../juno_def.h"
+
+/* Required platform porting definitions */
+/* Juno supports system power domain */
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
+#define PLAT_NUM_PWR_DOMAINS		(ARM_SYSTEM_COUNT + \
+					JUNO_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+#define PLATFORM_CORE_COUNT		(JUNO_CLUSTER0_CORE_COUNT + \
+					JUNO_CLUSTER1_CORE_COUNT)
+
+/* Cryptocell HW Base address */
+#define PLAT_CRYPTOCELL_BASE		UL(0x60050000)
+
+/*
+ * Other platform porting definitions are provided by included headers
+ */
+
+/*
+ * Required ARM standard platform porting definitions
+ */
+#define PLAT_ARM_CLUSTER_COUNT		JUNO_CLUSTER_COUNT
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE	UL(0x00040000)	/* 256 KB */
+
+/* Use the bypass address */
+#define PLAT_ARM_TRUSTED_ROM_BASE	(V2M_FLASH0_BASE + \
+					BL1_ROM_BYPASS_OFFSET)
+
+#define NSRAM_BASE			UL(0x2e000000)
+#define NSRAM_SIZE			UL(0x00008000)	/* 32KB */
+
+/* virtual address used by dynamic mem_protect for chunk_base */
+#define PLAT_ARM_MEM_PROTEC_VA_FRAME	UL(0xc0000000)
+
+/*
+ * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page
+ */
+
+#if USE_ROMLIB
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	UL(0x1000)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	UL(0xe000)
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	UL(0)
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	UL(0)
+#endif
+
+/*
+ * Actual ROM size on Juno is 64 KB, but TBB currently requires at least 80 KB
+ * in debug mode. We can test TBB on Juno bypassing the ROM and using 128 KB of
+ * flash
+ */
+
+#if TRUSTED_BOARD_BOOT
+#define PLAT_ARM_TRUSTED_ROM_SIZE	UL(0x00020000)
+#else
+#define PLAT_ARM_TRUSTED_ROM_SIZE	UL(0x00010000)
+#endif /* TRUSTED_BOARD_BOOT */
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#ifdef IMAGE_BL1
+# define PLAT_ARM_MMAP_ENTRIES		7
+# define MAX_XLAT_TABLES		4
+#endif
+
+#ifdef IMAGE_BL2
+#ifdef SPD_opteed
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		5
+#else
+# define PLAT_ARM_MMAP_ENTRIES		10
+# define MAX_XLAT_TABLES		4
+#endif
+#endif
+
+#ifdef IMAGE_BL2U
+# define PLAT_ARM_MMAP_ENTRIES		5
+# define MAX_XLAT_TABLES		3
+#endif
+
+#ifdef IMAGE_BL31
+#  define PLAT_ARM_MMAP_ENTRIES		7
+#  define MAX_XLAT_TABLES		3
+#endif
+
+#ifdef IMAGE_BL32
+# define PLAT_ARM_MMAP_ENTRIES		6
+# define MAX_XLAT_TABLES		4
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#if TRUSTED_BOARD_BOOT
+# define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0xB000)
+#else
+# define PLAT_ARM_MAX_BL1_RW_SIZE	UL(0x6000)
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#if TRUSTED_BOARD_BOOT
+#if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA
+# define PLAT_ARM_MAX_BL2_SIZE		UL(0x1F000)
+#elif TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA
+# define PLAT_ARM_MAX_BL2_SIZE		UL(0x1D000)
+#else
+# define PLAT_ARM_MAX_BL2_SIZE		UL(0x1D000)
+#endif
+#else
+# define PLAT_ARM_MAX_BL2_SIZE		UL(0xF000)
+#endif
+
+/*
+ * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
+ * calculated using the current BL31 PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW.  SCP_BL2 image is loaded into the space BL31 -> BL2_BASE.
+ * Hence the BL31 PROGBITS size should be >= PLAT_CSS_MAX_SCP_BL2_SIZE.
+ */
+#define PLAT_ARM_MAX_BL31_SIZE		UL(0x3E000)
+
+#if JUNO_AARCH32_EL3_RUNTIME
+/*
+ * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is
+ * calculated using the current BL32 PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW.  SCP_BL2 image is loaded into the space BL32 -> BL2_BASE.
+ * Hence the BL32 PROGBITS size should be >= PLAT_CSS_MAX_SCP_BL2_SIZE.
+ */
+#define PLAT_ARM_MAX_BL32_SIZE		UL(0x3E000)
+#endif
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE		UL(0x1000)
+# else
+#  define PLATFORM_STACK_SIZE		UL(0x440)
+# endif
+#elif defined(IMAGE_BL2)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE		UL(0x1000)
+# else
+#  define PLATFORM_STACK_SIZE		UL(0x400)
+# endif
+#elif defined(IMAGE_BL2U)
+# define PLATFORM_STACK_SIZE		UL(0x400)
+#elif defined(IMAGE_BL31)
+# if PLAT_XLAT_TABLES_DYNAMIC
+#  define PLATFORM_STACK_SIZE		UL(0x800)
+# else
+#  define PLATFORM_STACK_SIZE		UL(0x400)
+# endif
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE		UL(0x440)
+#endif
+
+/*
+ * Since free SRAM space is scant, enable the ASSERTION message size
+ * optimization by fixing the PLAT_LOG_LEVEL_ASSERT to LOG_LEVEL_INFO (40).
+ */
+#define PLAT_LOG_LEVEL_ASSERT		40
+
+/* CCI related constants */
+#define PLAT_ARM_CCI_BASE		UL(0x2c090000)
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX	4
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX	3
+
+/* System timer related constants */
+#define PLAT_ARM_NSTIMER_FRAME_ID		U(1)
+
+/* TZC related constants */
+#define PLAT_ARM_TZC_BASE		UL(0x2a4a0000)
+#define PLAT_ARM_TZC_NS_DEV_ACCESS	(				\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_CCI400)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_PCIE)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_HDLCD0)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_HDLCD1)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_USB)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_DMA330)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_THINLINKS)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_AP)		|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_GPU)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC400_NSAID_CORESIGHT))
+
+/*
+ * Required ARM CSS based platform porting definitions
+ */
+
+/* GIC related constants (no GICR in GIC-400) */
+#define PLAT_ARM_GICD_BASE		UL(0x2c010000)
+#define PLAT_ARM_GICC_BASE		UL(0x2c02f000)
+#define PLAT_ARM_GICH_BASE		UL(0x2c04f000)
+#define PLAT_ARM_GICV_BASE		UL(0x2c06f000)
+
+/* MHU related constants */
+#define PLAT_CSS_MHU_BASE		UL(0x2b1f0000)
+#define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
+
+/*
+ * Base address of the first memory region used for communication between AP
+ * and SCP. Used by the BOM and SCPI protocols.
+ */
+#if !CSS_USE_SCMI_SDS_DRIVER
+/*
+ * Note that this is located at the same address as SCP_BOOT_CFG_ADDR, which
+ * means the SCP/AP configuration data gets overwritten when the AP initiates
+ * communication with the SCP. The configuration data is expected to be a
+ * 32-bit word on all CSS platforms. On Juno, part of this configuration is
+ * which CPU is the primary, according to the shift and mask definitions below.
+ */
+#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE	(ARM_TRUSTED_SRAM_BASE + UL(0x80))
+#define PLAT_CSS_PRIMARY_CPU_SHIFT		8
+#define PLAT_CSS_PRIMARY_CPU_BIT_WIDTH		4
+#endif
+
+/*
+ * PLAT_CSS_MAX_SCP_BL2_SIZE is calculated using the current
+ * SCP_BL2 size plus a little space for growth.
+ */
+#define PLAT_CSS_MAX_SCP_BL2_SIZE	UL(0x14000)
+
+/*
+ * PLAT_CSS_MAX_SCP_BL2U_SIZE is calculated using the current
+ * SCP_BL2U size plus a little space for growth.
+ */
+#define PLAT_CSS_MAX_SCP_BL2U_SIZE	UL(0x14000)
+
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	CSS_G1S_IRQ_PROPS(grp), \
+	ARM_G1S_IRQ_PROPS(grp), \
+	INTR_PROP_DESC(JUNO_IRQ_DMA_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_HDLCD0_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_HDLCD1_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_USB_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_THIN_LINKS_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_SEC_I2C, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_GPU_SMMU_1, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(JUNO_IRQ_ETR_SMMU, GIC_HIGHEST_SEC_PRIORITY, \
+		(grp), GIC_INTR_CFG_LEVEL)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+/*
+ * Required ARM CSS SoC based platform porting definitions
+ */
+
+/* CSS SoC NIC-400 Global Programmers View (GPV) */
+#define PLAT_SOC_CSS_NIC400_BASE	UL(0x2a000000)
+
+#define PLAT_ARM_PRIVATE_SDEI_EVENTS	ARM_SDEI_PRIVATE_EVENTS
+#define PLAT_ARM_SHARED_SDEI_EVENTS	ARM_SDEI_SHARED_EVENTS
+
+/* System power domain level */
+#define CSS_SYSTEM_PWR_DMN_LVL		ARM_PWR_LVL2
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/juno/jmptbl.i b/plat/arm/board/juno/jmptbl.i
new file mode 100644
index 0000000..bfa9b56
--- /dev/null
+++ b/plat/arm/board/juno/jmptbl.i
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform specific romlib functions can be added or included here.
+# The index in the output file will be generated cumulatively in the same
+# order as it is given in this file.
+# Output file can be found at: $BUILD_DIR/jmptbl.i
+#
+# Format:
+# lib	function	[patch]
+# Example:
+# rom	rom_lib_init
+# fdt	fdt_getprop_namelen	patch
+
+rom     rom_lib_init
+fdt     fdt_getprop_namelen
+fdt     fdt_setprop_inplace
+fdt     fdt_check_header
+fdt     fdt_node_offset_by_compatible
+mbedtls mbedtls_asn1_get_alg
+mbedtls mbedtls_asn1_get_alg_null
+mbedtls mbedtls_asn1_get_bitstring_null
+mbedtls mbedtls_asn1_get_bool
+mbedtls mbedtls_asn1_get_int
+mbedtls mbedtls_asn1_get_tag
+mbedtls mbedtls_free
+mbedtls mbedtls_md
+mbedtls mbedtls_md_get_size
+mbedtls mbedtls_memory_buffer_alloc_init
+mbedtls mbedtls_oid_get_md_alg
+mbedtls mbedtls_oid_get_numeric_string
+mbedtls mbedtls_oid_get_pk_alg
+mbedtls mbedtls_oid_get_sig_alg
+mbedtls mbedtls_pk_free
+mbedtls mbedtls_pk_init
+mbedtls mbedtls_pk_parse_subpubkey
+mbedtls mbedtls_pk_verify_ext
+mbedtls mbedtls_platform_set_snprintf
+mbedtls mbedtls_x509_get_rsassa_pss_params
+mbedtls mbedtls_x509_get_sig_alg
+mbedtls mbedtls_md_info_from_type
+c       exit
+c       atexit
diff --git a/plat/arm/board/juno/juno_bl1_setup.c b/plat/arm/board/juno/juno_bl1_setup.c
new file mode 100644
index 0000000..89398d6
--- /dev/null
+++ b/plat/arm/board/juno/juno_bl1_setup.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+void juno_reset_to_aarch32_state(void);
+
+static int is_watchdog_reset(void)
+{
+#if !CSS_USE_SCMI_SDS_DRIVER
+	#define RESET_REASON_WDOG_RESET		(0x2)
+	const uint32_t *reset_flags_ptr = (const uint32_t *)SSC_GPRETN;
+
+	if ((*reset_flags_ptr & RESET_REASON_WDOG_RESET) != 0)
+		return 1;
+
+	return 0;
+#else
+	int ret;
+	uint32_t scp_reset_synd_flags;
+
+	ret = sds_init();
+	if (ret != SDS_OK) {
+		ERROR("SCP SDS initialization failed\n");
+		panic();
+	}
+
+	ret = sds_struct_read(SDS_RESET_SYNDROME_STRUCT_ID,
+					SDS_RESET_SYNDROME_OFFSET,
+					&scp_reset_synd_flags,
+					SDS_RESET_SYNDROME_SIZE,
+					SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("Getting reset reason from SDS failed\n");
+		panic();
+	}
+
+	/* Check if the WATCHDOG_RESET_BIT is set in the reset syndrome */
+	if (scp_reset_synd_flags & SDS_RESET_SYNDROME_AP_WD_RESET_BIT)
+		return 1;
+
+	return 0;
+#endif
+}
+
+/*******************************************************************************
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or watchdog reset happened.
+ ******************************************************************************/
+int plat_arm_bl1_fwu_needed(void)
+{
+	const int32_t *nv_flags_ptr = (const int32_t *)V2M_SYS_NVFLAGS_ADDR;
+
+	/* Check if TOC is invalid or watchdog reset happened. */
+	if ((arm_io_is_toc_valid() != 1) ||
+		(((*nv_flags_ptr == -EAUTH) || (*nv_flags_ptr == -ENOENT))
+		&& is_watchdog_reset()))
+		return 1;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * On JUNO update the arg2 with address of SCP_BL2U image info.
+ ******************************************************************************/
+void bl1_plat_set_ep_info(unsigned int image_id,
+		entry_point_info_t *ep_info)
+{
+	if (image_id == BL2U_IMAGE_ID) {
+		image_desc_t *image_desc = bl1_plat_get_image_desc(SCP_BL2U_IMAGE_ID);
+		ep_info->args.arg2 = (unsigned long)&image_desc->image_info;
+	}
+}
+
+/*******************************************************************************
+ * On Juno clear SYS_NVFLAGS and wait for watchdog reset.
+ ******************************************************************************/
+__dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved)
+{
+	unsigned int *nv_flags_clr = (unsigned int *)
+			(V2M_SYSREGS_BASE + V2M_SYS_NVFLAGSCLR);
+	unsigned int *nv_flags_ptr = (unsigned int *)
+			(V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS);
+
+	/* Clear the NV flags register. */
+	*nv_flags_clr = *nv_flags_ptr;
+
+	/* Setup the watchdog to reset the system as soon as possible */
+	sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+	while (1)
+		wfi();
+}
+
+#if JUNO_AARCH32_EL3_RUNTIME
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
+{
+#if !ARM_DISABLE_TRUSTED_WDOG
+	/* Disable watchdog before leaving BL1 */
+	sp805_stop(ARM_SP805_TWDG_BASE);
+#endif
+
+	juno_reset_to_aarch32_state();
+}
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
+
+void plat_arm_secure_wdt_start(void)
+{
+	sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sp805_stop(ARM_SP805_TWDG_BASE);
+}
diff --git a/plat/arm/board/juno/juno_bl2_setup.c b/plat/arm/board/juno/juno_bl2_setup.c
new file mode 100644
index 0000000..95ef77c
--- /dev/null
+++ b/plat/arm/board/juno/juno_bl2_setup.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/arm/common/plat_arm.h>
+
+#if JUNO_AARCH32_EL3_RUNTIME
+/*******************************************************************************
+ * This function changes the spsr for BL32 image to bypass
+ * the check in BL1 AArch64 exception handler. This is needed in the aarch32
+ * boot flow as the core comes up in aarch64 and to enter the BL32 image a warm
+ * reset in aarch32 state is required.
+ ******************************************************************************/
+int arm_bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	int err = arm_bl2_handle_post_image_load(image_id);
+
+	if (!err && (image_id == BL32_IMAGE_ID)) {
+		bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+		assert(bl_mem_params);
+		bl_mem_params->ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+			DISABLE_ALL_EXCEPTIONS);
+	}
+
+	return err;
+}
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/juno_common.c b/plat/arm/board/juno/juno_common.c
new file mode 100644
index 0000000..98c5d3c
--- /dev/null
+++ b/plat/arm/board/juno/juno_common.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * Table of memory regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted SRAM as setup_page_tables() already takes care
+ * of mapping it.
+ */
+#ifdef IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH0_RW,
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+#if TRUSTED_BOARD_BOOT
+	/* Map DRAM to authenticate NS_BL2U image. */
+	ARM_MAP_NS_DRAM1,
+#endif
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH0_RW,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	ARM_MAP_NS_DRAM1,
+#ifdef __aarch64__
+	ARM_MAP_DRAM2,
+#endif
+#ifdef SPD_tspd
+	ARM_MAP_TSP_SEC_MEM,
+#endif
+#ifdef SPD_opteed
+	ARM_MAP_OPTEE_CORE_MEM,
+	ARM_OPTEE_PAGEABLE_LOAD_MEM,
+#endif
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2U
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	CSS_MAP_DEVICE,
+	CSS_MAP_SCP_BL2U,
+	V2M_MAP_IOFPGA,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL32
+const mmap_region_t plat_arm_mmap[] = {
+#ifndef __aarch64__
+	ARM_MAP_SHARED_RAM,
+#ifdef PLAT_ARM_MEM_PROT_ADDR
+	ARM_V2M_MAP_MEM_PROTECT,
+#endif
+#endif
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+
+ARM_CASSERT_MMAP
diff --git a/plat/arm/board/juno/juno_decl.h b/plat/arm/board/juno/juno_decl.h
new file mode 100644
index 0000000..cd87c3b
--- /dev/null
+++ b/plat/arm/board/juno/juno_decl.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef JUNO_DECL_H
+#define JUNO_DECL_H
+
+int juno_getentropy(void *buf, size_t len);
+
+#endif /* JUNO_DECL_H */
diff --git a/plat/arm/board/juno/juno_def.h b/plat/arm/board/juno/juno_def.h
new file mode 100644
index 0000000..7a8bedf
--- /dev/null
+++ b/plat/arm/board/juno/juno_def.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef JUNO_DEF_H
+#define JUNO_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Juno memory map related constants
+ ******************************************************************************/
+
+/* Board revisions */
+#define REV_JUNO_R0			U(0x1)	/* Rev B */
+#define REV_JUNO_R1			U(0x2)	/* Rev C */
+#define REV_JUNO_R2			U(0x3)	/* Rev D */
+
+/* Bypass offset from start of NOR flash */
+#define BL1_ROM_BYPASS_OFFSET		UL(0x03EC0000)
+
+#define EMMC_BASE			UL(0x0c000000)
+#define EMMC_SIZE			UL(0x04000000)
+
+#define PSRAM_BASE			UL(0x14000000)
+#define PSRAM_SIZE			UL(0x02000000)
+
+#define JUNO_SSC_VER_PART_NUM		U(0x030)
+
+/*******************************************************************************
+ * Juno topology related constants
+ ******************************************************************************/
+#define JUNO_CLUSTER_COUNT		2
+#define JUNO_CLUSTER0_CORE_COUNT	2
+#define JUNO_CLUSTER1_CORE_COUNT	4
+
+/*******************************************************************************
+ * TZC-400 related constants
+ ******************************************************************************/
+#define TZC400_NSAID_CCI400		0  /* Note: Same as default NSAID!! */
+#define TZC400_NSAID_PCIE		1
+#define TZC400_NSAID_HDLCD0		2
+#define TZC400_NSAID_HDLCD1		3
+#define TZC400_NSAID_USB		4
+#define TZC400_NSAID_DMA330		5
+#define TZC400_NSAID_THINLINKS		6
+#define TZC400_NSAID_AP			9
+#define TZC400_NSAID_GPU		10
+#define TZC400_NSAID_SCP		11
+#define TZC400_NSAID_CORESIGHT		12
+
+/*******************************************************************************
+ * TRNG related constants
+ ******************************************************************************/
+#define TRNG_BASE	UL(0x7FE60000)
+#define TRNG_NOUTPUTS	4
+#define TRNG_STATUS	UL(0x10)
+#define TRNG_INTMASK	UL(0x14)
+#define TRNG_CONFIG	UL(0x18)
+#define TRNG_CONTROL	UL(0x1C)
+#define TRNG_NBYTES	16	/* Number of bytes generated per round. */
+
+/*******************************************************************************
+ * MMU-401 related constants
+ ******************************************************************************/
+#define MMU401_SSD_OFFSET		UL(0x4000)
+#define MMU401_DMA330_BASE		UL(0x7fb00000)
+
+/*******************************************************************************
+ * Interrupt handling constants
+ ******************************************************************************/
+#define JUNO_IRQ_DMA_SMMU		126
+#define JUNO_IRQ_HDLCD0_SMMU		128
+#define JUNO_IRQ_HDLCD1_SMMU		130
+#define JUNO_IRQ_USB_SMMU		132
+#define JUNO_IRQ_THIN_LINKS_SMMU	134
+#define JUNO_IRQ_SEC_I2C		137
+#define JUNO_IRQ_GPU_SMMU_1		73
+#define JUNO_IRQ_ETR_SMMU		75
+
+/*******************************************************************************
+ * Memprotect definitions
+ ******************************************************************************/
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+#endif /* JUNO_DEF_H */
diff --git a/plat/arm/board/juno/juno_err.c b/plat/arm/board/juno/juno_err.c
new file mode 100644
index 0000000..961bfda
--- /dev/null
+++ b/plat/arm/board/juno/juno_err.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/sp805.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*
+ * Juno error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	uint32_t *flags_ptr = (uint32_t *)V2M_SYS_NVFLAGS_ADDR;
+
+	/* Propagate the err code in the NV-flags register */
+	*flags_ptr = err;
+
+	/* Setup the watchdog to reset the system as soon as possible */
+	sp805_refresh(ARM_SP805_TWDG_BASE, 1U);
+
+	for (;;)
+		wfi();
+}
diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c
new file mode 100644
index 0000000..cc80651
--- /dev/null
+++ b/plat/arm/board/juno/juno_pm.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+#if CSS_USE_SCMI_SDS_DRIVER
+	return css_scmi_override_pm_ops(ops);
+#else
+	return ops;
+#endif /* CSS_USE_SCMI_SDS_DRIVER */
+}
diff --git a/plat/arm/board/juno/juno_security.c b/plat/arm/board/juno/juno_security.c
new file mode 100644
index 0000000..6566b15
--- /dev/null
+++ b/plat/arm/board/juno/juno_security.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/nic_400.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/soc/common/soc_css.h>
+#include <plat/common/platform.h>
+
+#include "juno_tzmp1_def.h"
+
+#ifdef JUNO_TZMP1
+/*
+ * Protect buffer for VPU/GPU/DPU memory usage with hardware protection
+ * enabled. Propose 224MB video output, 96 MB video input and 32MB video
+ * private.
+ *
+ * Ind	Memory Range			Caption			  S_ATTR  NS_ATTR
+ * 1	0x080000000 - 0x0E7FFFFFF	ARM_NS_DRAM1		  NONE	  RDWR | MEDIA_RW
+ * 2	0x0E8000000 - 0x0F5FFFFFF	JUNO_MEDIA_TZC_PROT_DRAM1 NONE	  MEDIA_RW | AP_WR
+ * 3	0x0F6000000 - 0x0FBFFFFFF	JUNO_VPU_TZC_PROT_DRAM1	  RDWR	  VPU_PROT_RW
+ * 4	0x0FC000000 - 0x0FDFFFFFF	JUNO_VPU_TZC_PRIV_DRAM1	  RDWR	  VPU_PRIV_RW
+ * 5	0x0FE000000 - 0x0FEFFFFFF	JUNO_AP_TZC_SHARE_DRAM1	  NONE	  RDWR | MEDIA_RW
+ * 6	0x0FF000000 - 0x0FFFFFFFF	ARM_AP_TZC_DRAM1	  RDWR	  NONE
+ * 7	0x880000000 - 0x9FFFFFFFF	ARM_DRAM2		  NONE	  RDWR | MEDIA_RW
+ *
+ * Memory regions are neighbored to save limited TZC regions. Calculation
+ * started from ARM_TZC_SHARE_DRAM1 since it is known and fixed for both
+ * protected-enabled and protected-disabled settings.
+ *
+ * Video private buffer aheads of ARM_TZC_SHARE_DRAM1
+ */
+
+static const arm_tzc_regions_info_t juno_tzmp1_tzc_regions[] = {
+	{ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END, TZC_REGION_S_RDWR, 0},
+	{JUNO_NS_DRAM1_PT1_BASE, JUNO_NS_DRAM1_PT1_END,
+			TZC_REGION_S_NONE, JUNO_MEDIA_TZC_NS_DEV_ACCESS},
+	{JUNO_MEDIA_TZC_PROT_DRAM1_BASE, JUNO_MEDIA_TZC_PROT_DRAM1_END,
+			TZC_REGION_S_NONE, JUNO_MEDIA_TZC_PROT_ACCESS},
+	{JUNO_VPU_TZC_PROT_DRAM1_BASE, JUNO_VPU_TZC_PROT_DRAM1_END,
+			TZC_REGION_S_RDWR, JUNO_VPU_TZC_PROT_ACCESS},
+	{JUNO_VPU_TZC_PRIV_DRAM1_BASE, JUNO_VPU_TZC_PRIV_DRAM1_END,
+			TZC_REGION_S_RDWR, JUNO_VPU_TZC_PRIV_ACCESS},
+	{JUNO_AP_TZC_SHARE_DRAM1_BASE, JUNO_AP_TZC_SHARE_DRAM1_END,
+			TZC_REGION_S_NONE, JUNO_MEDIA_TZC_NS_DEV_ACCESS},
+	{ARM_DRAM2_BASE, ARM_DRAM2_END,
+			TZC_REGION_S_NONE, JUNO_MEDIA_TZC_NS_DEV_ACCESS},
+	{},
+};
+
+/*******************************************************************************
+ * Program dp650 to configure NSAID value for protected mode.
+ ******************************************************************************/
+static void init_dp650(void)
+{
+	mmio_write_32(DP650_BASE + DP650_PROT_NSAID_OFFSET,
+		      DP650_PROT_NSAID_CONFIG);
+}
+
+/*******************************************************************************
+ * Program v550 to configure NSAID value for protected mode.
+ ******************************************************************************/
+static void init_v550(void)
+{
+	/*
+	 * bits[31:28] is for PRIVATE,
+	 * bits[27:24] is for OUTBUF,
+	 * bits[23:20] is for PROTECTED.
+	 */
+	mmio_write_32(V550_BASE + V550_PROTCTRL_OFFSET, V550_PROTCTRL_CONFIG);
+}
+
+#endif /* JUNO_TZMP1 */
+
+/*******************************************************************************
+ * Set up the MMU-401 SSD tables. The power-on configuration has all stream IDs
+ * assigned to Non-Secure except some for the DMA-330. Assign those back to the
+ * Non-Secure world as well, otherwise EL1 may end up erroneously generating
+ * (untranslated) Secure transactions if it turns the SMMU on.
+ ******************************************************************************/
+static void init_mmu401(void)
+{
+	uint32_t reg = mmio_read_32(MMU401_DMA330_BASE + MMU401_SSD_OFFSET);
+	reg |= 0x1FF;
+	mmio_write_32(MMU401_DMA330_BASE + MMU401_SSD_OFFSET, reg);
+}
+
+/*******************************************************************************
+ * Program CSS-NIC400 to allow non-secure access to some CSS regions.
+ ******************************************************************************/
+static void css_init_nic400(void)
+{
+	/* Note: This is the NIC-400 device on the CSS */
+	mmio_write_32(PLAT_SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(CSS_NIC400_SLAVE_BOOTSECURE),
+		~0);
+}
+
+/*******************************************************************************
+ * Initialize debug configuration.
+ ******************************************************************************/
+static void init_debug_cfg(void)
+{
+#if !DEBUG
+	/* Set internal drive selection for SPIDEN. */
+	mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_SET,
+		1U << SPIDEN_SEL_SET_SHIFT);
+
+	/* Drive SPIDEN LOW to disable invasive debug of secure state. */
+	mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_CLR,
+		1U << SPIDEN_INT_CLR_SHIFT);
+#endif
+}
+
+/*******************************************************************************
+ * Initialize the secure environment.
+ ******************************************************************************/
+void plat_arm_security_setup(void)
+{
+	/* Initialize debug configuration */
+	init_debug_cfg();
+	/* Initialize the TrustZone Controller */
+#ifdef JUNO_TZMP1
+	arm_tzc400_setup(juno_tzmp1_tzc_regions);
+	INFO("TZC protected shared memory base address for TZMP usecase: %p\n",
+	     (void *)JUNO_AP_TZC_SHARE_DRAM1_BASE);
+	INFO("TZC protected shared memory end address for TZMP usecase: %p\n",
+	     (void *)JUNO_AP_TZC_SHARE_DRAM1_END);
+#else
+	arm_tzc400_setup(NULL);
+#endif
+	/* Do ARM CSS internal NIC setup */
+	css_init_nic400();
+	/* Do ARM CSS SoC security setup */
+	soc_css_security_setup();
+	/* Initialize the SMMU SSD tables */
+	init_mmu401();
+#ifdef JUNO_TZMP1
+	init_dp650();
+	init_v550();
+#endif
+}
+
+#if TRUSTED_BOARD_BOOT
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
+#endif
diff --git a/plat/arm/board/juno/juno_stack_protector.c b/plat/arm/board/juno/juno_stack_protector.c
new file mode 100644
index 0000000..236eb5b
--- /dev/null
+++ b/plat/arm/board/juno/juno_stack_protector.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <platform_def.h>
+
+#include "juno_decl.h"
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+	u_register_t c[TRNG_NBYTES / sizeof(u_register_t)];
+	u_register_t ret = 0;
+	size_t i;
+
+	if (juno_getentropy(c, sizeof(c)) != 0) {
+		ERROR("Not enough entropy to initialize canary value\n");
+		panic();
+	}
+
+	/*
+	 * On Juno we get 128-bits of entropy in one round.
+	 * Fuse the values together to form the canary.
+	 */
+	for (i = 0; i < ARRAY_SIZE(c); i++)
+		ret ^= c[i];
+	return ret;
+}
diff --git a/plat/arm/board/juno/juno_topology.c b/plat/arm/board/juno/juno_topology.c
new file mode 100644
index 0000000..052ab9f
--- /dev/null
+++ b/plat/arm/board/juno/juno_topology.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#if CSS_USE_SCMI_SDS_DRIVER
+static scmi_channel_plat_info_t juno_scmi_plat_info = {
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhu_ring_doorbell,
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info(void)
+{
+	return &juno_scmi_plat_info;
+}
+
+#endif
+/*
+ * On Juno, the system power level is the highest power level.
+ * The first entry in the power domain descriptor specifies the
+ * number of system power domains i.e. 1.
+ */
+#define JUNO_PWR_DOMAINS_AT_MAX_PWR_LVL	 ARM_SYSTEM_COUNT
+
+/*
+ * The Juno power domain tree descriptor. The cluster power domains
+ * are arranged so that when the PSCI generic code creates the power
+ * domain tree, the indices of the CPU power domain nodes it allocates
+ * match the linear indices returned by plat_core_pos_by_mpidr()
+ * i.e. CLUSTER1 CPUs are allocated indices from 0 to 3 and the higher
+ * indices for CLUSTER0 CPUs.
+ */
+static const unsigned char juno_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	JUNO_PWR_DOMAINS_AT_MAX_PWR_LVL,
+	/* No of children for the root node */
+	JUNO_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	JUNO_CLUSTER1_CORE_COUNT,
+	/* No of children for the second cluster node */
+	JUNO_CLUSTER0_CORE_COUNT
+};
+
+/*******************************************************************************
+ * This function returns the Juno topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return juno_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
+{
+	return (((mpidr & (u_register_t) 0x100) != 0U) ?
+			JUNO_CLUSTER1_CORE_COUNT : JUNO_CLUSTER0_CORE_COUNT);
+}
+
+/*
+ * The array mapping platform core position (implemented by plat_my_core_pos())
+ * to the SCMI power domain ID implemented by SCP.
+ */
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
+			2, 3, 4, 5, 0, 1 };
diff --git a/plat/arm/board/juno/juno_trng.c b/plat/arm/board/juno/juno_trng.c
new file mode 100644
index 0000000..7869d3e
--- /dev/null
+++ b/plat/arm/board/juno/juno_trng.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+#include "juno_decl.h"
+
+#define NSAMPLE_CLOCKS	1 /* min 1 cycle, max 231 cycles */
+#define NRETRIES	5
+
+static inline int output_valid(void)
+{
+	int i;
+
+	for (i = 0; i < NRETRIES; i++) {
+		uint32_t val;
+
+		val = mmio_read_32(TRNG_BASE + TRNG_STATUS);
+		if (val & 1U)
+			break;
+	}
+	if (i >= NRETRIES)
+		return 0; /* No output data available. */
+	return 1;
+}
+
+/*
+ * This function fills `buf` with `len` bytes of entropy.
+ * It uses the Trusted Entropy Source peripheral on Juno.
+ * Returns 0 when the buffer has been filled with entropy
+ * successfully and -1 otherwise.
+ */
+int juno_getentropy(void *buf, size_t len)
+{
+	uint8_t *bp = buf;
+
+	assert(buf);
+	assert(len);
+	assert(!check_uptr_overflow((uintptr_t)bp, len));
+
+	/* Disable interrupt mode. */
+	mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0);
+	/* Program TRNG to sample for `NSAMPLE_CLOCKS`. */
+	mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS);
+
+	while (len > 0) {
+		int i;
+
+		/* Start TRNG. */
+		mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
+
+		/* Check if output is valid. */
+		if (!output_valid())
+			return -1;
+
+		/* Fill entropy buffer. */
+		for (i = 0; i < TRNG_NOUTPUTS; i++) {
+			size_t n;
+			uint32_t val;
+
+			val = mmio_read_32(TRNG_BASE + i * sizeof(uint32_t));
+			n = MIN(len, sizeof(uint32_t));
+			memcpy(bp, &val, n);
+			bp += n;
+			len -= n;
+			if (len == 0)
+				break;
+		}
+
+		/* Reset TRNG outputs. */
+		mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
+	}
+
+	return 0;
+}
diff --git a/plat/arm/board/juno/juno_tzmp1_def.h b/plat/arm/board/juno/juno_tzmp1_def.h
new file mode 100644
index 0000000..4186d02
--- /dev/null
+++ b/plat/arm/board/juno/juno_tzmp1_def.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef JUNO_TZMP1_DEF_H
+#define JUNO_TZMP1_DEF_H
+
+/*
+ * Public memory regions for both protected and non-protected mode
+ *
+ * OPTEE shared memory 0xFEE00000 - 0xFEFFFFFF
+ */
+#define JUNO_AP_TZC_SHARE_DRAM1_SIZE		ULL(0x02000000)
+#define JUNO_AP_TZC_SHARE_DRAM1_BASE		(ARM_AP_TZC_DRAM1_BASE - \
+						 JUNO_AP_TZC_SHARE_DRAM1_SIZE)
+#define JUNO_AP_TZC_SHARE_DRAM1_END		(ARM_AP_TZC_DRAM1_BASE - 1)
+
+/* ARM_MEDIA_FEATURES for MEDIA GPU Protect Mode Test */
+#define JUNO_TZC400_NSAID_FPGA_MEDIA_SECURE	8	/* GPU/DPU protected, VPU outbuf */
+#define JUNO_TZC400_NSAID_FPGA_VIDEO_PROTECTED	7	/* VPU protected */
+#define JUNO_TZC400_NSAID_FPGA_VIDEO_PRIVATE	10	/* VPU private (firmware) */
+
+#define JUNO_VPU_TZC_PRIV_DRAM1_SIZE	ULL(0x02000000)
+#define JUNO_VPU_TZC_PRIV_DRAM1_BASE	(JUNO_AP_TZC_SHARE_DRAM1_BASE - \
+					 JUNO_VPU_TZC_PRIV_DRAM1_SIZE)
+#define JUNO_VPU_TZC_PRIV_DRAM1_END	(JUNO_AP_TZC_SHARE_DRAM1_BASE - 1)
+
+/* Video input protected buffer follows upper item */
+#define JUNO_VPU_TZC_PROT_DRAM1_SIZE	ULL(0x06000000)
+#define JUNO_VPU_TZC_PROT_DRAM1_BASE	(JUNO_VPU_TZC_PRIV_DRAM1_BASE - \
+					 JUNO_VPU_TZC_PROT_DRAM1_SIZE)
+#define JUNO_VPU_TZC_PROT_DRAM1_END	(JUNO_VPU_TZC_PRIV_DRAM1_BASE - 1)
+
+/* Video, graphics and display shares same NSAID and same protected buffer */
+#define JUNO_MEDIA_TZC_PROT_DRAM1_SIZE	ULL(0x0e000000)
+#define JUNO_MEDIA_TZC_PROT_DRAM1_BASE	(JUNO_VPU_TZC_PROT_DRAM1_BASE - \
+					 JUNO_MEDIA_TZC_PROT_DRAM1_SIZE)
+#define JUNO_MEDIA_TZC_PROT_DRAM1_END	(JUNO_VPU_TZC_PROT_DRAM1_BASE - 1)
+
+/* Rest of DRAM1 are Non-Secure public buffer */
+#define JUNO_NS_DRAM1_PT1_BASE		ARM_DRAM1_BASE
+#define JUNO_NS_DRAM1_PT1_END		(JUNO_MEDIA_TZC_PROT_DRAM1_BASE - 1)
+#define JUNO_NS_DRAM1_PT1_SIZE		(JUNO_NS_DRAM1_PT1_END -	\
+					 JUNO_NS_DRAM1_PT1_BASE + 1)
+
+/* TZC filter flags */
+#define JUNO_MEDIA_TZC_NS_DEV_ACCESS	(PLAT_ARM_TZC_NS_DEV_ACCESS |	\
+		TZC_REGION_ACCESS_RD(JUNO_TZC400_NSAID_FPGA_MEDIA_SECURE))
+
+/* VPU / GPU /DPU protected access */
+#define JUNO_MEDIA_TZC_PROT_ACCESS \
+		(TZC_REGION_ACCESS_RDWR(JUNO_TZC400_NSAID_FPGA_MEDIA_SECURE) | \
+		TZC_REGION_ACCESS_WR(TZC400_NSAID_AP))
+
+#define JUNO_VPU_TZC_PROT_ACCESS \
+		(TZC_REGION_ACCESS_RDWR(JUNO_TZC400_NSAID_FPGA_VIDEO_PROTECTED))
+
+#define JUNO_VPU_TZC_PRIV_ACCESS \
+		(TZC_REGION_ACCESS_RDWR(JUNO_TZC400_NSAID_FPGA_VIDEO_PRIVATE))
+
+/*******************************************************************************
+ * Mali-DP650 related constants
+ ******************************************************************************/
+/* Base address of DP650 */
+#define DP650_BASE			0x6f200000
+/* offset to PROT_NSAID register */
+#define DP650_PROT_NSAID_OFFSET		0x10004
+/* config to PROT_NSAID register */
+#define DP650_PROT_NSAID_CONFIG		0x08008888
+
+/*******************************************************************************
+ * Mali-V550 related constants
+ ******************************************************************************/
+/* Base address of V550 */
+#define V550_BASE			0x6f030000
+/* offset to PROTCTRL register */
+#define V550_PROTCTRL_OFFSET		0x0040
+/* config to PROTCTRL register */
+#define V550_PROTCTRL_CONFIG		0xa8700000
+
+#endif /* JUNO_TZMP1_DEF_H */
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
new file mode 100644
index 0000000..ea7f851
--- /dev/null
+++ b/plat/arm/board/juno/platform.mk
@@ -0,0 +1,157 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+JUNO_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c		\
+				plat/arm/common/arm_gicv2.c
+
+JUNO_INTERCONNECT_SOURCES	:=	drivers/arm/cci/cci.c		\
+					plat/arm/common/arm_cci.c
+
+JUNO_SECURITY_SOURCES	:=	drivers/arm/tzc/tzc400.c		\
+				plat/arm/board/juno/juno_security.c	\
+				plat/arm/board/juno/juno_trng.c		\
+				plat/arm/common/arm_tzc400.c
+
+ifneq (${ENABLE_STACK_PROTECTOR}, 0)
+JUNO_SECURITY_SOURCES	+=	plat/arm/board/juno/juno_stack_protector.c
+endif
+
+# Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the
+# SCP during power management operations and for SCP RAM Firmware transfer.
+CSS_USE_SCMI_SDS_DRIVER		:=	1
+
+PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include
+
+PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/${ARCH}/juno_helpers.S \
+				plat/arm/board/juno/juno_common.c
+
+# Flag to enable support for AArch32 state on JUNO
+JUNO_AARCH32_EL3_RUNTIME	:=	0
+$(eval $(call assert_boolean,JUNO_AARCH32_EL3_RUNTIME))
+$(eval $(call add_define,JUNO_AARCH32_EL3_RUNTIME))
+
+# Flag to enable support for TZMP1 on JUNO
+JUNO_TZMP1		:=	0
+$(eval $(call assert_boolean,JUNO_TZMP1))
+ifeq (${JUNO_TZMP1}, 1)
+$(eval $(call add_define,JUNO_TZMP1))
+endif
+
+ifeq (${JUNO_AARCH32_EL3_RUNTIME}, 1)
+# Include BL32 in FIP
+NEED_BL32		:= yes
+# BL31 is not required
+override BL31_SOURCES =
+
+# The BL32 needs to be built separately invoking the AARCH32 compiler and
+# be specifed via `BL32` build option.
+  ifneq (${ARCH}, aarch32)
+    override BL32_SOURCES =
+  endif
+endif
+
+ifeq (${ARCH},aarch64)
+BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a57.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				plat/arm/board/juno/juno_err.c		\
+				plat/arm/board/juno/juno_bl1_setup.c	\
+				drivers/arm/sp805/sp805.c		\
+				${JUNO_INTERCONNECT_SOURCES}		\
+				${JUNO_SECURITY_SOURCES}
+
+BL2_SOURCES		+=	drivers/arm/sp805/sp805.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/board/juno/juno_err.c		\
+				plat/arm/board/juno/juno_bl2_setup.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c \
+				${JUNO_SECURITY_SOURCES}
+
+BL2U_SOURCES		+=	${JUNO_SECURITY_SOURCES}
+
+BL31_SOURCES		+=	drivers/cfi/v2m/v2m_flash.c		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a57.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				lib/utils/mem_region.c			\
+				plat/arm/board/juno/juno_pm.c		\
+				plat/arm/board/juno/juno_topology.c	\
+				plat/arm/common/arm_nor_psci_mem_protect.c \
+				${JUNO_GIC_SOURCES}			\
+				${JUNO_INTERCONNECT_SOURCES}		\
+				${JUNO_SECURITY_SOURCES}
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
+BL1_SOURCES		+=	drivers/arm/css/sds/sds.c
+endif
+
+endif
+
+ifneq (${RESET_TO_BL31},0)
+  $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \
+  Please set RESET_TO_BL31 to 0.")
+endif
+
+ifeq ($(USE_ROMLIB),1)
+all : bl1_romlib.bin
+endif
+
+bl1_romlib.bin : $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/romlib/romlib.bin
+	@echo "Building combined BL1 and ROMLIB binary for Juno $@"
+	./lib/romlib/gen_combined_bl1_romlib.sh -o bl1_romlib.bin $(BUILD_PLAT)
+
+# Errata workarounds for Cortex-A53:
+ERRATA_A53_819472		:=	1
+ERRATA_A53_824069		:=	1
+ERRATA_A53_826319		:=	1
+ERRATA_A53_827319		:=	1
+ERRATA_A53_835769		:=	1
+ERRATA_A53_836870		:=	1
+ERRATA_A53_843419		:=	1
+ERRATA_A53_855873		:=	1
+
+# Errata workarounds for Cortex-A57:
+ERRATA_A57_806969		:=	0
+ERRATA_A57_813419		:=	1
+ERRATA_A57_813420		:=	1
+ERRATA_A57_814670		:=	1
+ERRATA_A57_817169		:=	1
+ERRATA_A57_826974		:=	1
+ERRATA_A57_826977		:=	1
+ERRATA_A57_828024		:=	1
+ERRATA_A57_829520		:=	1
+ERRATA_A57_833471		:=	1
+ERRATA_A57_859972		:=	0
+
+# Errata workarounds for Cortex-A72:
+ERRATA_A72_859971		:=	0
+
+# Enable option to skip L1 data cache flush during the Cortex-A57 cluster
+# power down sequence
+SKIP_A57_L1_FLUSH_PWR_DWN	:=	 1
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS		:=	0
+
+# Enable the dynamic translation tables library.
+ifeq (${ARCH},aarch32)
+    ifeq (${RESET_TO_SP_MIN},1)
+        BL32_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+    endif
+else
+    ifeq (${RESET_TO_BL31},1)
+        BL31_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+    endif
+endif
+
+include plat/arm/board/common/board_common.mk
+include plat/arm/common/arm_common.mk
+include plat/arm/soc/common/soc_css.mk
+include plat/arm/css/common/css_common.mk
+
diff --git a/plat/arm/board/juno/sp_min/sp_min-juno.mk b/plat/arm/board/juno/sp_min/sp_min-juno.mk
new file mode 100644
index 0000000..b3471c1
--- /dev/null
+++ b/plat/arm/board/juno/sp_min/sp_min-juno.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SP_MIN source files specific to JUNO platform
+BL32_SOURCES	+=	drivers/cfi/v2m/v2m_flash.c		\
+			lib/cpus/aarch32/cortex_a53.S		\
+			lib/cpus/aarch32/cortex_a57.S		\
+			lib/cpus/aarch32/cortex_a72.S		\
+			lib/utils/mem_region.c			\
+			plat/arm/board/juno/juno_pm.c		\
+			plat/arm/board/juno/juno_topology.c	\
+			plat/arm/common/arm_nor_psci_mem_protect.c	\
+			plat/arm/soc/common/soc_css_security.c	\
+			${JUNO_GIC_SOURCES}			\
+			${JUNO_INTERCONNECT_SOURCES}		\
+			${JUNO_SECURITY_SOURCES}
+
+include plat/arm/common/sp_min/arm_sp_min.mk
+include plat/arm/css/common/sp_min/css_sp_min.mk
diff --git a/plat/arm/board/juno/tsp/tsp-juno.mk b/plat/arm/board/juno/tsp/tsp-juno.mk
new file mode 100644
index 0000000..be75c4d
--- /dev/null
+++ b/plat/arm/board/juno/tsp/tsp-juno.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES		+=	plat/arm/board/juno/juno_topology.c	\
+				plat/arm/css/common/css_topology.c	\
+				${JUNO_GIC_SOURCES}			\
+				${JUNO_SECURITY_SOURCES}
+
+include plat/arm/common/tsp/arm_tsp.mk
diff --git a/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S b/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
new file mode 100644
index 0000000..c03185a
--- /dev/null
+++ b/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <neoverse_n1.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_arm_calc_core_pos
+	.globl	plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Helper function to calculate the core position.
+	 * (ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER * N1SDP_MAX_PE_PER_CPU) +
+	 * (CPUId * N1SDP_MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER + CPUId) *
+	 * N1SDP_MAX_PE_PER_CPU) + ThreadId
+	 * ------------------------------------------------------
+	 */
+
+func plat_arm_calc_core_pos
+	mov	x3, x0
+
+	/*
+	 * The MT bit in MPIDR is always set for n1sdp and the
+	 * affinity level 0 corresponds to thread affinity level.
+	 */
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx	x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov	x4, #N1SDP_MAX_CPUS_PER_CLUSTER
+	madd	x1, x2, x4, x1
+	mov	x5, #N1SDP_MAX_PE_PER_CPU
+	madd	x0, x1, x5, x0
+	ret
+endfunc plat_arm_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the CPU MIDR and disable power down bit for
+	 * that CPU.
+	 * -----------------------------------------------------
+	 */
+
+func plat_reset_handler
+	jump_if_cpu_midr NEOVERSE_N1_MIDR, N1
+	ret
+
+	/* -----------------------------------------------------
+	 * Disable CPU power down bit in power control register
+	 * -----------------------------------------------------
+	 */
+N1:
+	mrs	x0, NEOVERSE_N1_CPUPWRCTLR_EL1
+	bic	x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK
+	msr	NEOVERSE_N1_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc plat_reset_handler
diff --git a/plat/arm/board/n1sdp/include/plat_macros.S b/plat/arm/board/n1sdp/include/plat_macros.S
new file mode 100644
index 0000000..521bcc3
--- /dev/null
+++ b/plat/arm/board/n1sdp/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <css_macros.S>
+
+/* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant platform registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ *
+ * There are currently no platform specific regs
+ * to print.
+ * ---------------------------------------------
+ */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/board/n1sdp/include/platform_def.h b/plat/arm/board/n1sdp/include/platform_def.h
new file mode 100644
index 0000000..7348bf5
--- /dev/null
+++ b/plat/arm/board/n1sdp/include/platform_def.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/css/common/css_def.h>
+
+/* UART related constants */
+#define PLAT_ARM_BOOT_UART_BASE			0x2A400000
+#define PLAT_ARM_BOOT_UART_CLK_IN_HZ		50000000
+
+#define PLAT_ARM_RUN_UART_BASE		0x2A410000
+#define PLAT_ARM_RUN_UART_CLK_IN_HZ	50000000
+
+#define PLAT_ARM_SP_MIN_RUN_UART_BASE		0x2A410000
+#define PLAT_ARM_SP_MIN_RUN_UART_CLK_IN_HZ	50000000
+
+#define PLAT_ARM_CRASH_UART_BASE		PLAT_ARM_RUN_UART_BASE
+#define PLAT_ARM_CRASH_UART_CLK_IN_HZ		PLAT_ARM_RUN_UART_CLK_IN_HZ
+
+#define PLAT_ARM_DRAM2_BASE			ULL(0x8080000000)
+#define PLAT_ARM_DRAM2_SIZE			ULL(0xF80000000)
+
+/*
+ * N1SDP platform supports RDIMMs with ECC capability. To use the ECC
+ * capability, the entire DDR memory space has to be zeroed out before
+ * enabling the ECC bits in DMC620. The access the complete DDR memory
+ * space the physical & virtual address space limits are extended to
+ * 40-bits.
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 40)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 32)
+#endif
+
+#if CSS_USE_SCMI_SDS_DRIVER
+#define N1SDP_SCMI_PAYLOAD_BASE			0x45400000
+#else
+#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE	0x45400000
+#endif
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE		0x00080000	/* 512 KB */
+#define PLAT_ARM_MAX_BL31_SIZE			0X20000
+
+
+/*******************************************************************************
+ * N1SDP topology related constants
+ ******************************************************************************/
+#define N1SDP_MAX_CPUS_PER_CLUSTER		2
+#define PLAT_ARM_CLUSTER_COUNT			2
+#define N1SDP_MAX_PE_PER_CPU			1
+
+#define PLATFORM_CORE_COUNT			(PLAT_ARM_CLUSTER_COUNT *	\
+						N1SDP_MAX_CPUS_PER_CLUSTER *	\
+						N1SDP_MAX_PE_PER_CPU)
+
+/* System power domain level */
+#define CSS_SYSTEM_PWR_DMN_LVL			ARM_PWR_LVL2
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#define PLAT_ARM_MMAP_ENTRIES			6
+#define MAX_XLAT_TABLES				7
+
+#define PLATFORM_STACK_SIZE			0x400
+
+#define PLAT_ARM_NSTIMER_FRAME_ID		0
+#define PLAT_CSS_MHU_BASE			0x45000000
+#define PLAT_MHUV2_BASE				PLAT_CSS_MHU_BASE
+#define PLAT_MAX_PWR_LVL			1
+
+#define PLAT_ARM_G1S_IRQS			ARM_G1S_IRQS,			\
+						CSS_IRQ_MHU
+#define PLAT_ARM_G0_IRQS			ARM_G0_IRQS
+
+#define PLAT_ARM_G1S_IRQ_PROPS(grp)		CSS_G1S_IRQ_PROPS(grp)
+#define PLAT_ARM_G0_IRQ_PROPS(grp)		ARM_G0_IRQ_PROPS(grp)
+
+
+#define N1SDP_DEVICE_BASE			(0x08000000)
+#define N1SDP_DEVICE_SIZE			(0x48000000)
+#define N1SDP_MAP_DEVICE			MAP_REGION_FLAT(	\
+						N1SDP_DEVICE_BASE,	\
+						N1SDP_DEVICE_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define ARM_MAP_DRAM1				MAP_REGION_FLAT(	\
+						ARM_DRAM1_BASE,		\
+						ARM_DRAM1_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE			0x30000000
+#define PLAT_ARM_GICC_BASE			0x2C000000
+#define PLAT_ARM_GICR_BASE			0x300C0000
+
+/* Platform ID address */
+#define SSC_VERSION				(SSC_REG_BASE + SSC_VERSION_OFFSET)
+
+/* Secure Watchdog Constants */
+#define SBSA_SECURE_WDOG_BASE			UL(0x2A480000)
+#define SBSA_SECURE_WDOG_TIMEOUT		UL(100)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
new file mode 100644
index 0000000..632af7b
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <drivers/arm/css/sds.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "n1sdp_def.h"
+
+/*
+ * Memory information structure stored in SDS.
+ * This structure holds the total DDR memory size which will be
+ * used when zeroing out the entire DDR memory before enabling
+ * the ECC capability in DMCs.
+ */
+struct n1sdp_mem_info {
+	uint32_t ddr_size_gb;
+};
+
+/*
+ * BL33 image information structure stored in SDS.
+ * This structure holds the source & destination addresses and
+ * the size of the BL33 image which will be loaded by BL31.
+ */
+struct n1sdp_bl33_info {
+	uint32_t bl33_src_addr;
+	uint32_t bl33_dst_addr;
+	uint32_t bl33_size;
+};
+
+static scmi_channel_plat_info_t n1sdp_scmi_plat_info = {
+		.scmi_mbx_mem = N1SDP_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhu_ring_doorbell,
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info()
+{
+	return &n1sdp_scmi_plat_info;
+}
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+	return css_scmi_override_pm_ops(ops);
+}
+
+/*
+ * N1SDP platform supports RDIMMs with ECC capability. To use the ECC
+ * capability, the entire DDR memory space has to be zeroed out before
+ * enabling the ECC bits in DMC620. Zeroing out several gigabytes of
+ * memory from SCP is quite time consuming so the following function
+ * is added to zero out the DDR memory from application processor which is
+ * much faster compared to SCP. BL33 binary cannot be copied to DDR memory
+ * before enabling ECC so copy_bl33 function is added to copy BL33 binary
+ * from IOFPGA-DDR3 memory to main DDR4 memory.
+ */
+
+void dmc_ecc_setup(uint32_t ddr_size_gb)
+{
+	uint64_t dram2_size;
+
+	dram2_size = (ddr_size_gb * 1024UL * 1024UL * 1024UL) -
+			ARM_DRAM1_SIZE;
+
+	INFO("Zeroing DDR memories\n");
+	zero_normalmem((void *)ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
+	flush_dcache_range(ARM_DRAM1_BASE, ARM_DRAM1_SIZE);
+	zero_normalmem((void *)ARM_DRAM2_BASE, dram2_size);
+	flush_dcache_range(ARM_DRAM2_BASE, dram2_size);
+
+	INFO("Enabling ECC on DMCs\n");
+	/* Set DMCs to CONFIG state before writing ERR0CTLR0 register */
+	mmio_write_32(N1SDP_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_CONFIG);
+	mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_CONFIG);
+
+	/* Enable ECC in DMCs */
+	mmio_setbits_32(N1SDP_DMC0_ERR0CTLR0_REG, N1SDP_DMC_ERR0CTLR0_ECC_EN);
+	mmio_setbits_32(N1SDP_DMC1_ERR0CTLR0_REG, N1SDP_DMC_ERR0CTLR0_ECC_EN);
+
+	/* Set DMCs to READY state */
+	mmio_write_32(N1SDP_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
+	mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY);
+}
+
+void copy_bl33(uint32_t src, uint32_t dst, uint32_t size)
+{
+	uint32_t i;
+
+	INFO("Copying BL33 to DDR memory\n");
+	for (i = 0; i < size; i = i + 8)
+		mmio_write_64((dst + i), mmio_read_64(src + i));
+
+	for (i = 0; i < size; i = i + 8) {
+		if (mmio_read_64(src + i) != mmio_read_64(dst + i)) {
+			ERROR("Copy failed!\n");
+			panic();
+		}
+	}
+}
+
+void bl31_platform_setup(void)
+{
+	int ret;
+	struct n1sdp_mem_info mem_info;
+	struct n1sdp_bl33_info bl33_info;
+
+	arm_bl31_platform_setup();
+
+	ret = sds_init();
+	if (ret != SDS_OK) {
+		ERROR("SDS initialization failed\n");
+		panic();
+	}
+
+	ret = sds_struct_read(N1SDP_SDS_MEM_INFO_STRUCT_ID,
+				N1SDP_SDS_MEM_INFO_OFFSET,
+				&mem_info,
+				N1SDP_SDS_MEM_INFO_SIZE,
+				SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("Error getting memory info from SDS\n");
+		panic();
+	}
+	dmc_ecc_setup(mem_info.ddr_size_gb);
+
+	ret = sds_struct_read(N1SDP_SDS_BL33_INFO_STRUCT_ID,
+				N1SDP_SDS_BL33_INFO_OFFSET,
+				&bl33_info,
+				N1SDP_SDS_BL33_INFO_SIZE,
+				SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("Error getting BL33 info from SDS\n");
+		panic();
+	}
+	copy_bl33(bl33_info.bl33_src_addr,
+			bl33_info.bl33_dst_addr,
+			bl33_info.bl33_size);
+	/*
+	 * Pass DDR memory size info to BL33. This method is followed as
+	 * currently there is no BL1/BL2 involved in boot flow of N1SDP.
+	 * When TBBR is implemented for N1SDP, this method should be removed
+	 * and DDR memory size shoule be passed to BL33 using NT_FW_CONFIG
+	 * passing mechanism.
+	 */
+	mmio_write_32(N1SDP_DDR_MEM_INFO_BASE, mem_info.ddr_size_gb);
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_def.h b/plat/arm/board/n1sdp/n1sdp_def.h
new file mode 100644
index 0000000..d43c5a4
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_def.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef N1SDP_DEF_H
+#define N1SDP_DEF_H
+
+/* Non-secure SRAM MMU mapping */
+#define N1SDP_NS_SRAM_BASE			(0x06000000)
+#define N1SDP_NS_SRAM_SIZE			(0x00010000)
+#define N1SDP_MAP_NS_SRAM			MAP_REGION_FLAT(	\
+						N1SDP_NS_SRAM_BASE,	\
+						N1SDP_NS_SRAM_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+/* SDS memory information defines */
+#define N1SDP_SDS_MEM_INFO_STRUCT_ID		8
+#define N1SDP_SDS_MEM_INFO_OFFSET		0
+#define N1SDP_SDS_MEM_INFO_SIZE			4
+
+/* SDS BL33 image information defines */
+#define N1SDP_SDS_BL33_INFO_STRUCT_ID		9
+#define N1SDP_SDS_BL33_INFO_OFFSET		0
+#define N1SDP_SDS_BL33_INFO_SIZE		12
+
+/* DMC memory command registers */
+#define N1SDP_DMC0_MEMC_CMD_REG			0x4E000008
+#define N1SDP_DMC1_MEMC_CMD_REG			0x4E100008
+
+/* DMC ERR0CTLR0 registers */
+#define N1SDP_DMC0_ERR0CTLR0_REG		0x4E000708
+#define N1SDP_DMC1_ERR0CTLR0_REG		0x4E100708
+
+/* DMC memory commands */
+#define N1SDP_DMC_MEMC_CMD_CONFIG		0
+#define N1SDP_DMC_MEMC_CMD_READY		3
+
+/* DMC ECC enable bit in ERR0CTLR0 register */
+#define N1SDP_DMC_ERR0CTLR0_ECC_EN		0x1
+
+/* Base address of non-secure SRAM where DDR memory size will be filled */
+#define N1SDP_DDR_MEM_INFO_BASE			0x06008000
+
+#endif /* N1SDP_DEF_H */
diff --git a/plat/arm/board/n1sdp/n1sdp_interconnect.c b/plat/arm/board/n1sdp/n1sdp_interconnect.c
new file mode 100644
index 0000000..908f41c
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_interconnect.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+/*
+ * For N1SDP which support FCM (with automatic interconnect enter/exit),
+ * we should not do anything in these interface functions.
+ * They are used to override the weak functions in cci drivers.
+ */
+
+/******************************************************************************
+ * Helper function to initialize ARM interconnect driver.
+ *****************************************************************************/
+void plat_arm_interconnect_init(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_arm_interconnect_enter_coherency(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_arm_interconnect_exit_coherency(void)
+{
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_plat.c b/plat/arm/board/n1sdp/n1sdp_plat.c
new file mode 100644
index 0000000..a32ca72
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_plat.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+
+#include "n1sdp_def.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * Replace or extend the below regions as required
+ */
+
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	N1SDP_MAP_DEVICE,
+	N1SDP_MAP_NS_SRAM,
+	ARM_MAP_DRAM1,
+	ARM_MAP_DRAM2,
+	{0}
+};
+
+void plat_arm_secure_wdt_start(void)
+{
+	sbsa_wdog_start(SBSA_SECURE_WDOG_BASE, SBSA_SECURE_WDOG_TIMEOUT);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE);
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_security.c b/plat/arm/board/n1sdp/n1sdp_security.c
new file mode 100644
index 0000000..d2a187b
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_security.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * TZC programming is currently not done.
+ */
+void plat_arm_security_setup(void)
+{
+}
diff --git a/plat/arm/board/n1sdp/n1sdp_topology.c b/plat/arm/board/n1sdp/n1sdp_topology.c
new file mode 100644
index 0000000..edf1170
--- /dev/null
+++ b/plat/arm/board/n1sdp/n1sdp_topology.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/* Topology */
+typedef struct n1sdp_topology {
+	const unsigned char *power_tree;
+	unsigned int plat_cluster_core_count;
+} n1sdp_topology_t;
+
+/*
+ * The power domain tree descriptor. The cluster power domains are
+ * arranged so that when the PSCI generic code creates the power domain tree,
+ * the indices of the CPU power domain nodes it allocates match the linear
+ * indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char n1sdp_pd_tree_desc[] = {
+	PLAT_ARM_CLUSTER_COUNT,
+	N1SDP_MAX_CPUS_PER_CLUSTER,
+	N1SDP_MAX_CPUS_PER_CLUSTER
+};
+
+/* Topology configuration for n1sdp */
+const n1sdp_topology_t n1sdp_topology = {
+	.power_tree = n1sdp_pd_tree_desc,
+	.plat_cluster_core_count = N1SDP_MAX_CPUS_PER_CLUSTER
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return n1sdp_topology.power_tree;
+}
+
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
+{
+	return n1sdp_topology.plat_cluster_core_count;
+}
+
+/*******************************************************************************
+ * The array mapping platform core position (implemented by plat_my_core_pos())
+ * to the SCMI power domain ID implemented by SCP.
+ ******************************************************************************/
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
+	0, 1, 2, 3};
diff --git a/plat/arm/board/n1sdp/platform.mk b/plat/arm/board/n1sdp/platform.mk
new file mode 100644
index 0000000..986bd70
--- /dev/null
+++ b/plat/arm/board/n1sdp/platform.mk
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+N1SDP_BASE		:=	plat/arm/board/n1sdp
+
+INTERCONNECT_SOURCES	:=	${N1SDP_BASE}/n1sdp_interconnect.c
+
+PLAT_INCLUDES		:=	-I${N1SDP_BASE}/include
+
+
+N1SDP_CPU_SOURCES	:=	lib/cpus/aarch64/neoverse_n1.S
+
+
+N1SDP_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				plat/arm/common/arm_gicv3.c		\
+				drivers/arm/gic/v3/gic600.c
+
+PLAT_BL_COMMON_SOURCES	:=	${N1SDP_BASE}/n1sdp_plat.c	        \
+				${N1SDP_BASE}/aarch64/n1sdp_helper.S
+
+BL1_SOURCES		+=	drivers/arm/sbsa/sbsa.c
+
+BL31_SOURCES		:=	${N1SDP_CPU_SOURCES}			\
+				${INTERCONNECT_SOURCES}			\
+				${N1SDP_GIC_SOURCES}			\
+				${N1SDP_BASE}/n1sdp_bl31_setup.c	        \
+				${N1SDP_BASE}/n1sdp_topology.c	        \
+				${N1SDP_BASE}/n1sdp_security.c		\
+				drivers/arm/css/sds/sds.c
+
+
+# TF-A not required to load the SCP Images
+override CSS_LOAD_SCP_IMAGES	  	:=	0
+
+# BL1/BL2 Image not a part of the capsule Image for n1sdp
+override NEED_BL1		  	:=	no
+override NEED_BL2		  	:=	no
+override NEED_BL2U		  	:=	no
+
+#TFA for n1sdp starts from BL31
+override RESET_TO_BL31            	:=	1
+
+# 32 bit mode not supported
+override CTX_INCLUDE_AARCH32_REGS 	:=	0
+
+override ARM_PLAT_MT              	:=	1
+
+# Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the
+# SCP during power management operations and for SCP RAM Firmware transfer.
+CSS_USE_SCMI_SDS_DRIVER		  	:=	1
+
+# System coherency is managed in hardware
+HW_ASSISTED_COHERENCY			:=	1
+
+# When building for systems with hardware-assisted coherency, there's no need to
+# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
+USE_COHERENT_MEM			:=	0
+include plat/arm/common/arm_common.mk
+include plat/arm/css/common/css_common.mk
+include plat/arm/board/common/board_common.mk
+
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts
new file mode 100644
index 0000000..4176921
--- /dev/null
+++ b/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+	/* compatible string */
+	compatible = "arm,rd-e1edge";
+
+	/*
+	 * Place holder for system-id node with default values. The
+	 * value of platform-id and config-id will be set to the
+	 * correct values during the BL2 stage of boot.
+	 */
+	system-id {
+		platform-id = <0x0>;
+		config-id = <0x0>;
+	};
+
+};
diff --git a/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts b/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts
new file mode 100644
index 0000000..766dc00
--- /dev/null
+++ b/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	compatible = "arm,tb_fw";
+	nt_fw_config_addr = <0x0 0xFEF00000>;
+	nt_fw_config_max_size = <0x0100000>;
+	/*
+	 * The following two entries are placeholders for Mbed TLS
+	 * heap information. The default values don't matter since
+	 * they will be overwritten by BL1.
+	 * In case of having shared Mbed TLS heap between BL1 and BL2,
+	 * BL1 will populate these two properties with the respective
+	 * info about the shared heap. This info will be available for
+	 * BL2 in order to locate and re-use the heap.
+	 */
+	mbedtls_heap_addr = <0x0 0x0>;
+	mbedtls_heap_size = <0x0>;
+};
diff --git a/plat/arm/board/rde1edge/include/platform_def.h b/plat/arm/board/rde1edge/include/platform_def.h
new file mode 100644
index 0000000..50b04f0
--- /dev/null
+++ b/plat/arm/board/rde1edge/include/platform_def.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_base_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT		2
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER	8
+#define CSS_SGI_MAX_PE_PER_CPU		2
+
+#define PLAT_CSS_MHU_BASE		UL(0x45400000)
+#define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
+
+/* Base address of DMC-620 instances */
+#define RDE1EDGE_DMC620_BASE0		UL(0x4e000000)
+#define RDE1EDGE_DMC620_BASE1		UL(0x4e100000)
+
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
+
+#define CSS_SYSTEM_PWR_DMN_LVL		ARM_PWR_LVL3
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rde1edge/platform.mk b/plat/arm/board/rde1edge/platform.mk
new file mode 100644
index 0000000..db41e0e
--- /dev/null
+++ b/plat/arm/board/rde1edge/platform.mk
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/css/sgi/sgi-common.mk
+
+RDE1EDGE_BASE		=	plat/arm/board/rde1edge
+
+PLAT_INCLUDES		+=	-I${RDE1EDGE_BASE}/include/
+
+SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_e1.S
+
+BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+				${RDE1EDGE_BASE}/rde1edge_err.c
+
+BL2_SOURCES		+=	${RDE1EDGE_BASE}/rde1edge_plat.c	\
+				${RDE1EDGE_BASE}/rde1edge_security.c	\
+				${RDE1EDGE_BASE}/rde1edge_err.c		\
+				drivers/arm/tzc/tzc_dmc620.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+				${RDE1EDGE_BASE}/rde1edge_plat.c	\
+				drivers/cfi/v2m/v2m_flash.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES		+=	${RDE1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts
+TB_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config))
+
+FDT_SOURCES		+=	${RDE1EDGE_BASE}/fdts/${PLAT}_nt_fw_config.dts
+NT_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
+
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config))
+
+override CTX_INCLUDE_AARCH32_REGS	:= 0
diff --git a/plat/arm/board/rde1edge/rde1edge_err.c b/plat/arm/board/rde1edge/rde1edge_err.c
new file mode 100644
index 0000000..e344d82
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rde1edge error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	while (1) {
+		wfi();
+	}
+}
diff --git a/plat/arm/board/rde1edge/rde1edge_plat.c b/plat/arm/board/rde1edge/rde1edge_plat.c
new file mode 100644
index 0000000..a1b8d62
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_plat.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+unsigned int plat_arm_sgi_get_platform_id(void)
+{
+	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
+				& SID_SYSTEM_ID_PART_NUM_MASK;
+}
+
+unsigned int plat_arm_sgi_get_config_id(void)
+{
+	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
+}
diff --git a/plat/arm/board/rde1edge/rde1edge_security.c b/plat/arm/board/rde1edge/rde1edge_security.c
new file mode 100644
index 0000000..2123e09
--- /dev/null
+++ b/plat/arm/board/rde1edge/rde1edge_security.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc620.h>
+
+uintptr_t rde1edge_dmc_base[] = {
+	RDE1EDGE_DMC620_BASE0,
+	RDE1EDGE_DMC620_BASE1
+};
+
+static const tzc_dmc620_driver_data_t rde1edge_plat_driver_data = {
+	.dmc_base = rde1edge_dmc_base,
+	.dmc_count = ARRAY_SIZE(rde1edge_dmc_base)
+};
+
+static const tzc_dmc620_acc_addr_data_t rde1edge_acc_addr_data[] = {
+	{
+		.region_base = ARM_AP_TZC_DRAM1_BASE,
+		.region_top = ARM_AP_TZC_DRAM1_BASE + ARM_TZC_DRAM1_SIZE - 1,
+		.sec_attr = TZC_DMC620_REGION_S_RDWR
+	}
+};
+
+static const tzc_dmc620_config_data_t rde1edge_plat_config_data = {
+	.plat_drv_data = &rde1edge_plat_driver_data,
+	.plat_acc_addr_data = rde1edge_acc_addr_data,
+	.acc_addr_count = ARRAY_SIZE(rde1edge_acc_addr_data)
+};
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+	arm_tzc_dmc620_setup(&rde1edge_plat_config_data);
+}
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts b/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
new file mode 100644
index 0000000..fff5874
--- /dev/null
+++ b/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+	/* compatible string */
+	compatible = "arm,rd-n1edge";
+
+	/*
+	 * Place holder for system-id node with default values. The
+	 * value of platform-id and config-id will be set to the
+	 * correct values during the BL2 stage of boot.
+	 */
+	system-id {
+		platform-id = <0x0>;
+		config-id = <0x0>;
+	};
+};
diff --git a/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts b/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
new file mode 100644
index 0000000..b14d7ad
--- /dev/null
+++ b/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	compatible = "arm,tb_fw";
+	nt_fw_config_addr = <0x0 0xFEF00000>;
+	nt_fw_config_max_size = <0x0100000>;
+	/*
+	 * The following two entries are placeholders for Mbed TLS
+	 * heap information. The default values don't matter since
+	 * they will be overwritten by BL1.
+	 * In case of having shared Mbed TLS heap between BL1 and BL2,
+	 * BL1 will populate these two properties with the respective
+	 * info about the shared heap. This info will be available for
+	 * BL2 in order to locate and re-use the heap.
+	 */
+	mbedtls_heap_addr = <0x0 0x0>;
+	mbedtls_heap_size = <0x0>;
+};
diff --git a/plat/arm/board/rdn1edge/include/platform_def.h b/plat/arm/board/rdn1edge/include/platform_def.h
new file mode 100644
index 0000000..580ab8e
--- /dev/null
+++ b/plat/arm/board/rdn1edge/include/platform_def.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_base_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT		2
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER	4
+#define CSS_SGI_MAX_PE_PER_CPU		1
+
+#define PLAT_CSS_MHU_BASE		UL(0x45400000)
+#define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
+
+/* Base address of DMC-620 instances */
+#define RDN1EDGE_DMC620_BASE0		UL(0x4e000000)
+#define RDN1EDGE_DMC620_BASE1		UL(0x4e100000)
+
+/* System power domain level */
+#define CSS_SYSTEM_PWR_DMN_LVL		ARM_PWR_LVL2
+
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/rdn1edge/platform.mk b/plat/arm/board/rdn1edge/platform.mk
new file mode 100644
index 0000000..b44c70a
--- /dev/null
+++ b/plat/arm/board/rdn1edge/platform.mk
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/css/sgi/sgi-common.mk
+
+RDN1EDGE_BASE		=	plat/arm/board/rdn1edge
+
+PLAT_INCLUDES		+=	-I${RDN1EDGE_BASE}/include/
+
+SGI_CPU_SOURCES		:=	lib/cpus/aarch64/neoverse_n1.S
+
+BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+				${RDN1EDGE_BASE}/rdn1edge_err.c
+
+BL2_SOURCES		+=	${RDN1EDGE_BASE}/rdn1edge_plat.c	\
+				${RDN1EDGE_BASE}/rdn1edge_security.c	\
+				${RDN1EDGE_BASE}/rdn1edge_err.c		\
+				drivers/arm/tzc/tzc_dmc620.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+				${RDN1EDGE_BASE}/rdn1edge_plat.c	\
+				drivers/cfi/v2m/v2m_flash.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES		+=	${RDN1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts
+TB_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config))
+
+FDT_SOURCES		+=	${RDN1EDGE_BASE}/fdts/${PLAT}_nt_fw_config.dts
+NT_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
+
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config))
+
+override CTX_INCLUDE_AARCH32_REGS	:= 0
diff --git a/plat/arm/board/rdn1edge/rdn1edge_err.c b/plat/arm/board/rdn1edge/rdn1edge_err.c
new file mode 100644
index 0000000..cdcbf25
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * rdn1edge error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	while (1) {
+		wfi();
+	}
+}
diff --git a/plat/arm/board/rdn1edge/rdn1edge_plat.c b/plat/arm/board/rdn1edge/rdn1edge_plat.c
new file mode 100644
index 0000000..3b7e5ee
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_plat.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+unsigned int plat_arm_sgi_get_platform_id(void)
+{
+	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET)
+				& SID_SYSTEM_ID_PART_NUM_MASK;
+}
+
+unsigned int plat_arm_sgi_get_config_id(void)
+{
+	return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET);
+}
diff --git a/plat/arm/board/rdn1edge/rdn1edge_security.c b/plat/arm/board/rdn1edge/rdn1edge_security.c
new file mode 100644
index 0000000..ffa8935
--- /dev/null
+++ b/plat/arm/board/rdn1edge/rdn1edge_security.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc620.h>
+
+uintptr_t rdn1edge_dmc_base[] = {
+	RDN1EDGE_DMC620_BASE0,
+	RDN1EDGE_DMC620_BASE1
+};
+
+static const tzc_dmc620_driver_data_t rdn1edge_plat_driver_data = {
+	.dmc_base = rdn1edge_dmc_base,
+	.dmc_count = ARRAY_SIZE(rdn1edge_dmc_base)
+};
+
+static const tzc_dmc620_acc_addr_data_t rdn1edge_acc_addr_data[] = {
+	{
+		.region_base = ARM_AP_TZC_DRAM1_BASE,
+		.region_top = ARM_AP_TZC_DRAM1_BASE + ARM_TZC_DRAM1_SIZE - 1,
+		.sec_attr = TZC_DMC620_REGION_S_RDWR
+	}
+};
+
+static const tzc_dmc620_config_data_t rdn1edge_plat_config_data = {
+	.plat_drv_data = &rdn1edge_plat_driver_data,
+	.plat_acc_addr_data = rdn1edge_acc_addr_data,
+	.acc_addr_count = ARRAY_SIZE(rdn1edge_acc_addr_data)
+};
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+	arm_tzc_dmc620_setup(&rdn1edge_plat_config_data);
+}
diff --git a/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts b/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts
new file mode 100644
index 0000000..1e1ea14
--- /dev/null
+++ b/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+/ {
+	/* compatible string */
+	compatible = "arm,sgi575";
+
+	/*
+	 * Place holder for system-id node with default values. The
+	 * value of platform-id and config-id will be set to the
+	 * correct values during the BL2 stage of boot.
+	 */
+	system-id {
+		platform-id = <0x0>;
+		config-id = <0x0>;
+	};
+};
diff --git a/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts b/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts
new file mode 100644
index 0000000..b14d7ad
--- /dev/null
+++ b/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	compatible = "arm,tb_fw";
+	nt_fw_config_addr = <0x0 0xFEF00000>;
+	nt_fw_config_max_size = <0x0100000>;
+	/*
+	 * The following two entries are placeholders for Mbed TLS
+	 * heap information. The default values don't matter since
+	 * they will be overwritten by BL1.
+	 * In case of having shared Mbed TLS heap between BL1 and BL2,
+	 * BL1 will populate these two properties with the respective
+	 * info about the shared heap. This info will be available for
+	 * BL2 in order to locate and re-use the heap.
+	 */
+	mbedtls_heap_addr = <0x0 0x0>;
+	mbedtls_heap_size = <0x0>;
+};
diff --git a/plat/arm/board/sgi575/include/platform_def.h b/plat/arm/board/sgi575/include/platform_def.h
new file mode 100644
index 0000000..f00146f
--- /dev/null
+++ b/plat/arm/board/sgi575/include/platform_def.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#include <sgi_base_platform_def.h>
+
+#define PLAT_ARM_CLUSTER_COUNT		2
+#define CSS_SGI_MAX_CPUS_PER_CLUSTER	4
+#define CSS_SGI_MAX_PE_PER_CPU		1
+
+#define PLAT_CSS_MHU_BASE		UL(0x45000000)
+#define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
+
+/* Base address of DMC-620 instances */
+#define SGI575_DMC620_BASE0		UL(0x4e000000)
+#define SGI575_DMC620_BASE1		UL(0x4e100000)
+
+/* System power domain level */
+#define CSS_SYSTEM_PWR_DMN_LVL		ARM_PWR_LVL2
+
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/sgi575/platform.mk b/plat/arm/board/sgi575/platform.mk
new file mode 100644
index 0000000..b9fa099
--- /dev/null
+++ b/plat/arm/board/sgi575/platform.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/css/sgi/sgi-common.mk
+
+SGI575_BASE		=	plat/arm/board/sgi575
+
+PLAT_INCLUDES		+=	-I${SGI575_BASE}/include/
+
+SGI_CPU_SOURCES		:=	lib/cpus/aarch64/cortex_a75.S
+
+BL1_SOURCES		+=	${SGI_CPU_SOURCES}			\
+				${SGI575_BASE}/sgi575_err.c
+
+BL2_SOURCES		+=	${SGI575_BASE}/sgi575_plat.c		\
+				${SGI575_BASE}/sgi575_security.c	\
+				${SGI575_BASE}/sgi575_err.c		\
+				drivers/arm/tzc/tzc_dmc620.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES		+=	${SGI_CPU_SOURCES}			\
+				${SGI575_BASE}/sgi575_plat.c		\
+				drivers/cfi/v2m/v2m_flash.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+# Add the FDT_SOURCES and options for Dynamic Config
+FDT_SOURCES		+=	${SGI575_BASE}/fdts/${PLAT}_tb_fw_config.dts
+TB_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb
+
+# Add the TB_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config))
+
+FDT_SOURCES		+=	${SGI575_BASE}/fdts/${PLAT}_nt_fw_config.dts
+NT_FW_CONFIG		:=	${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb
+
+# Add the NT_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config))
diff --git a/plat/arm/board/sgi575/sgi575_err.c b/plat/arm/board/sgi575/sgi575_err.c
new file mode 100644
index 0000000..c1cc1a7
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * sgi575 error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	while (1) {
+		wfi();
+	}
+}
diff --git a/plat/arm/board/sgi575/sgi575_plat.c b/plat/arm/board/sgi575/sgi575_plat.c
new file mode 100644
index 0000000..0d3fd16
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_plat.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include <sgi_variant.h>
+
+unsigned int plat_arm_sgi_get_platform_id(void)
+{
+	return mmio_read_32(SSC_VERSION) & SSC_VERSION_PART_NUM_MASK;
+}
+
+unsigned int plat_arm_sgi_get_config_id(void)
+{
+	return (mmio_read_32(SSC_VERSION) >> SSC_VERSION_CONFIG_SHIFT)
+			& SSC_VERSION_CONFIG_MASK;
+}
diff --git a/plat/arm/board/sgi575/sgi575_security.c b/plat/arm/board/sgi575/sgi575_security.c
new file mode 100644
index 0000000..440f18d
--- /dev/null
+++ b/plat/arm/board/sgi575/sgi575_security.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc620.h>
+#include <plat/arm/common/plat_arm.h>
+
+uintptr_t sgi575_dmc_base[] = {
+	SGI575_DMC620_BASE0,
+	SGI575_DMC620_BASE1
+};
+
+static const tzc_dmc620_driver_data_t sgi575_plat_driver_data = {
+	.dmc_base = sgi575_dmc_base,
+	.dmc_count = ARRAY_SIZE(sgi575_dmc_base)
+};
+
+static const tzc_dmc620_acc_addr_data_t sgi575_acc_addr_data[] = {
+	{
+		.region_base = ARM_AP_TZC_DRAM1_BASE,
+		.region_top = ARM_AP_TZC_DRAM1_BASE + ARM_TZC_DRAM1_SIZE - 1,
+		.sec_attr = TZC_DMC620_REGION_S_RDWR
+	}
+};
+
+static const tzc_dmc620_config_data_t sgi575_plat_config_data = {
+	.plat_drv_data = &sgi575_plat_driver_data,
+	.plat_acc_addr_data = sgi575_acc_addr_data,
+	.acc_addr_count = ARRAY_SIZE(sgi575_acc_addr_data)
+};
+
+/* Initialize the secure environment */
+void plat_arm_security_setup(void)
+{
+	arm_tzc_dmc620_setup(&sgi575_plat_config_data);
+}
diff --git a/plat/arm/board/sgm775/fdts/sgm775_tb_fw_config.dts b/plat/arm/board/sgm775/fdts/sgm775_tb_fw_config.dts
new file mode 100644
index 0000000..9502549
--- /dev/null
+++ b/plat/arm/board/sgm775/fdts/sgm775_tb_fw_config.dts
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	plat_arm_bl2 {
+		compatible = "arm,tb_fw";
+		hw_config_addr = <0x0 0x83000000>;
+		hw_config_max_size = <0x01000000>;
+	};
+};
diff --git a/plat/arm/board/sgm775/include/platform_def.h b/plat/arm/board/sgm775/include/platform_def.h
new file mode 100644
index 0000000..27d1b33
--- /dev/null
+++ b/plat/arm/board/sgm775/include/platform_def.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <sgm_base_platform_def.h>
+
+#define PLAT_MAX_CPUS_PER_CLUSTER	8
+#define PLAT_MAX_PE_PER_CPU		1
+
+/*
+ * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes
+ */
+#ifdef __aarch64__
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 36)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/sgm775/platform.mk b/plat/arm/board/sgm775/platform.mk
new file mode 100644
index 0000000..7a843c3
--- /dev/null
+++ b/plat/arm/board/sgm775/platform.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/css/sgm/sgm-common.mk
+
+SGM775_BASE= plat/arm/board/sgm775
+
+FDT_SOURCES += ${SGM775_BASE}/fdts/sgm775_tb_fw_config.dts
+
+PLAT_INCLUDES +=-I${SGM775_BASE}/include/
+
+BL1_SOURCES		+=	${SGM775_BASE}/sgm775_err.c
+
+BL2_SOURCES		+=	lib/utils/mem_region.c                  \
+				${SGM775_BASE}/sgm775_err.c		\
+				plat/arm/common/arm_nor_psci_mem_protect.c
+
+BL31_SOURCES		+=	drivers/cfi/v2m/v2m_flash.c		\
+				lib/utils/mem_region.c			\
+				plat/arm/common/arm_nor_psci_mem_protect.c
diff --git a/plat/arm/board/sgm775/sgm775_err.c b/plat/arm/board/sgm775/sgm775_err.c
new file mode 100644
index 0000000..e1e0586
--- /dev/null
+++ b/plat/arm/board/sgm775/sgm775_err.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * sgm775 error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	while (1) {
+		wfi();
+	}
+}
diff --git a/plat/arm/board/sgm775/tsp/tsp-sgm775.mk b/plat/arm/board/sgm775/tsp/tsp-sgm775.mk
new file mode 100644
index 0000000..129b586
--- /dev/null
+++ b/plat/arm/board/sgm775/tsp/tsp-sgm775.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include plat/arm/css/sgm/tsp/tsp-sgm.mk
\ No newline at end of file
diff --git a/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
new file mode 100644
index 0000000..7aeeb2a
--- /dev/null
+++ b/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+    {
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = PLAT_CSS_MAX_SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+#endif /* SCP_BL2_BASE */
+
+	/* Fill BL32 related information */
+    {
+	    .image_id = BL32_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL32_BASE,
+	    .ep_info.spsr = SPSR_MODE32(MODE32_mon, SPSR_T_ARM,
+		    SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+    },
+	/* Fill HW_CONFIG related information if it exists */
+    {
+	    .image_id = HW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+	/* Fill BL33 related information */
+    {
+	    .image_id = BL33_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+#ifdef PRELOADED_BL33_BASE
+	    .ep_info.pc = PRELOADED_BL33_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+#else
+	    .ep_info.pc = PLAT_ARM_NS_IMAGE_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = PLAT_ARM_NS_IMAGE_BASE,
+	    .image_info.image_max_size = ARM_DRAM1_BASE + ARM_DRAM1_SIZE
+		    - PLAT_ARM_NS_IMAGE_BASE,
+#endif /* PRELOADED_BL33_BASE */
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    }
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/arm/common/aarch32/arm_helpers.S b/plat/arm/common/aarch32/arm_helpers.S
new file mode 100644
index 0000000..badddd3
--- /dev/null
+++ b/plat/arm/common/aarch32/arm_helpers.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.weak	plat_arm_calc_core_pos
+	.weak	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_arm_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	ldcopr	r0, MPIDR
+	b	plat_arm_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_arm_calc_core_pos(uint64_t mpidr)
+	 *  Helper function to calculate the core position.
+	 *  With this function: CorePos = (ClusterId * 4) +
+	 *  				  CoreId
+	 * -----------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	and	r1, r0, #MPIDR_CPU_MASK
+	and	r0, r0, #MPIDR_CLUSTER_MASK
+	add	r0, r1, r0, LSR #6
+	bx	lr
+endfunc plat_arm_calc_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : r0 - r3
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	ldr	r0, =PLAT_ARM_CRASH_UART_BASE
+	ldr	r1, =PLAT_ARM_CRASH_UART_CLK_IN_HZ
+	ldr	r2, =ARM_CONSOLE_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : r1 - r2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	ldr	r1, =PLAT_ARM_CRASH_UART_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	ldr	r0, =PLAT_ARM_CRASH_UART_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
new file mode 100644
index 0000000..0514b39
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+    {
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = PLAT_CSS_MAX_SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+#endif /* SCP_BL2_BASE */
+
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = EL3_PAYLOAD_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t,
+		    IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL31_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+	    .ep_info.args.arg3 = ARM_BL31_PLAT_PARAM_VAL,
+#endif
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL31_BASE,
+	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+	    .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+    },
+	/* Fill HW_CONFIG related information */
+    {
+	    .image_id = HW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+	/* Fill SOC_FW_CONFIG related information */
+    {
+	    .image_id = SOC_FW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+    {
+	    .image_id = BL32_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
+	    .ep_info.pc = BL32_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+    },
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the pager image.
+	 */
+    {
+	    .image_id = BL32_EXTRA1_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the paged image.
+	 */
+    {
+	    .image_id = BL32_EXTRA2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+#ifdef SPD_opteed
+	    .image_info.image_base = ARM_OPTEE_PAGEABLE_LOAD_BASE,
+	    .image_info.image_max_size = ARM_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+	/* Fill TOS_FW_CONFIG related information */
+    {
+	    .image_id = TOS_FW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+    {
+	    .image_id = BL33_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+	    .ep_info.pc = PRELOADED_BL33_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+# else
+	    .ep_info.pc = PLAT_ARM_NS_IMAGE_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = PLAT_ARM_NS_IMAGE_BASE,
+	    .image_info.image_max_size = ARM_DRAM1_BASE + ARM_DRAM1_SIZE
+		    - PLAT_ARM_NS_IMAGE_BASE,
+# endif /* PRELOADED_BL33_BASE */
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+	/* Fill NT_FW_CONFIG related information */
+    {
+	    .image_id = NT_FW_CONFIG_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE),
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    }
+#endif /* EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/arm/common/aarch64/arm_ehf.c b/plat/arm/common/aarch64/arm_ehf.c
new file mode 100644
index 0000000..4ae992c
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_ehf.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+
+/*
+ * Enumeration of priority levels on ARM platforms.
+ */
+ehf_pri_desc_t arm_exceptions[] = {
+#if RAS_EXTENSION
+	/* RAS Priority */
+	EHF_PRI_DESC(ARM_PRI_BITS, PLAT_RAS_PRI),
+#endif
+
+#if SDEI_SUPPORT
+	/* Critical priority SDEI */
+	EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),
+
+	/* Normal priority SDEI */
+	EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
+#endif
+#if ENABLE_SPM
+	EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SP_PRI),
+#endif
+};
+
+/* Plug in ARM exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(arm_exceptions, ARRAY_SIZE(arm_exceptions), ARM_PRI_BITS);
diff --git a/plat/arm/common/aarch64/arm_helpers.S b/plat/arm/common/aarch64/arm_helpers.S
new file mode 100644
index 0000000..0672058
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_helpers.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.weak	plat_arm_calc_core_pos
+	.weak	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	platform_mem_init
+
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_arm_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_arm_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *  Helper function to calculate the core position.
+	 *  With this function: CorePos = (ClusterId * 4) +
+	 *  				  CoreId
+	 * -----------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_arm_calc_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, PLAT_ARM_CRASH_UART_BASE
+	mov_imm	x1, PLAT_ARM_CRASH_UART_CLK_IN_HZ
+	mov_imm	x2, ARM_CONSOLE_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, PLAT_ARM_CRASH_UART_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, PLAT_ARM_CRASH_UART_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on ARM
+	 * platforms. The Secure RAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+/*
+ * Need to use coherent stack when ARM Cryptocell is used to autheticate images
+ * since Cryptocell uses DMA to transfer data and it is not coherent with the
+ * AP CPU.
+ */
+#if ARM_CRYPTOCELL_INTEG
+#if defined(IMAGE_BL1) || defined(IMAGE_BL2)
+	.globl	plat_get_my_stack
+	.globl	plat_set_my_stack
+	.local	platform_coherent_stacks
+
+	/* -------------------------------------------------------
+	 * uintptr_t plat_get_my_stack ()
+	 *
+	 * For cold-boot BL images, only the primary CPU needs a
+	 * stack. This function returns the stack pointer for a
+	 * stack allocated in coherent memory.
+	 * -------------------------------------------------------
+	 */
+func plat_get_my_stack
+	get_up_stack platform_coherent_stacks, PLATFORM_STACK_SIZE
+	ret
+endfunc plat_get_my_stack
+
+	/* -------------------------------------------------------
+	 * void plat_set_my_stack ()
+	 *
+	 * For cold-boot BL images, only the primary CPU needs a
+	 * stack. This function sets the stack pointer to a stack
+	 * allocated in coherent memory.
+	 * -------------------------------------------------------
+	 */
+func plat_set_my_stack
+	get_up_stack platform_coherent_stacks, PLATFORM_STACK_SIZE
+	mov sp, x0
+	ret
+endfunc plat_set_my_stack
+
+	/* ----------------------------------------------------
+	 * Single cpu stack in coherent memory.
+	 * ----------------------------------------------------
+	 */
+declare_stack platform_coherent_stacks, tzfw_coherent_mem, \
+		PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE
+
+#endif	/* defined(IMAGE_BL1) || defined(IMAGE_BL2) */
+#endif	/* ARM_CRYPTOCELL_INTEG */
diff --git a/plat/arm/common/aarch64/arm_pauth.c b/plat/arm/common/aarch64/arm_pauth.c
new file mode 100644
index 0000000..a685c31
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_pauth.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+#include <stdint.h>
+
+/*
+ * Instruction pointer authentication key A. The low 64-bit are at [0], and the
+ * high bits at [1].
+ */
+uint64_t plat_apiakey[2];
+
+/*
+ * This is only a toy implementation to generate a seemingly random 128-bit key
+ * from sp and x30 values. A production system must re-implement this function
+ * to generate keys from a reliable randomness source.
+ */
+uint64_t *plat_init_apiakey(void)
+{
+	uintptr_t return_addr = (uintptr_t)__builtin_return_address(0U);
+	uintptr_t frame_addr = (uintptr_t)__builtin_frame_address(0U);
+
+	plat_apiakey[0] = (return_addr << 13) ^ frame_addr;
+	plat_apiakey[1] = (frame_addr << 15) ^ return_addr;
+
+	return plat_apiakey;
+}
diff --git a/plat/arm/common/aarch64/arm_sdei.c b/plat/arm/common/aarch64/arm_sdei.c
new file mode 100644
index 0000000..493134b
--- /dev/null
+++ b/plat/arm/common/aarch64/arm_sdei.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+#include <services/sdei.h>
+
+/* Private event mappings */
+static sdei_ev_map_t arm_sdei_private[] = {
+	PLAT_ARM_PRIVATE_SDEI_EVENTS
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t arm_sdei_shared[] = {
+	PLAT_ARM_SHARED_SDEI_EVENTS
+};
+
+/* Export ARM SDEI events */
+REGISTER_SDEI_MAP(arm_sdei_private, arm_sdei_shared);
diff --git a/plat/arm/common/arm_bl1_fwu.c b/plat/arm/common/arm_bl1_fwu.c
new file mode 100644
index 0000000..124c1af
--- /dev/null
+++ b/plat/arm/common/arm_bl1_fwu.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Struct to keep track of usable memory */
+typedef struct bl1_mem_info {
+	uintptr_t mem_base;
+	unsigned int mem_size;
+} bl1_mem_info_t;
+
+static bl1_mem_info_t fwu_addr_map_secure[] = {
+	{
+		.mem_base = ARM_SHARED_RAM_BASE,
+		.mem_size = ARM_SHARED_RAM_SIZE
+	},
+	{
+		.mem_size = 0
+	}
+};
+
+static bl1_mem_info_t fwu_addr_map_non_secure[] = {
+	{
+		.mem_base = ARM_NS_DRAM1_BASE,
+		.mem_size = ARM_NS_DRAM1_SIZE
+	},
+	{
+		.mem_base = PLAT_ARM_NVM_BASE,
+		.mem_size = PLAT_ARM_NVM_SIZE
+	},
+	{
+		.mem_size = 0
+	}
+};
+
+int bl1_plat_mem_check(uintptr_t mem_base,
+		unsigned int mem_size,
+		unsigned int flags)
+{
+	unsigned int index = 0;
+	bl1_mem_info_t *mmap;
+
+	assert(mem_base);
+	assert(mem_size);
+	/*
+	 * The caller of this function is responsible for checking upfront that
+	 * the end address doesn't overflow. We double-check this in debug
+	 * builds.
+	 */
+	assert(!check_uptr_overflow(mem_base, mem_size - 1));
+
+	/*
+	 * Check the given image source and size.
+	 */
+	if (GET_SECURITY_STATE(flags) == SECURE)
+		mmap = fwu_addr_map_secure;
+	else
+		mmap = fwu_addr_map_non_secure;
+
+	while (mmap[index].mem_size) {
+		if ((mem_base >= mmap[index].mem_base) &&
+			((mem_base + mem_size)
+			<= (mmap[index].mem_base +
+			mmap[index].mem_size)))
+			return 0;
+
+		index++;
+	}
+
+	return -ENOMEM;
+}
+
+/*******************************************************************************
+ * This function does linear search for image_id and returns image_desc.
+ ******************************************************************************/
+image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
+{
+	unsigned int index = 0;
+
+	while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
+		if (bl1_tbbr_image_descs[index].image_id == image_id)
+			return &bl1_tbbr_image_descs[index];
+		index++;
+	}
+
+	return NULL;
+}
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
new file mode 100644
index 0000000..b19a7c3
--- /dev/null
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak bl1_early_platform_setup
+#pragma weak bl1_plat_arch_setup
+#pragma weak bl1_plat_sec_mem_layout
+#pragma weak bl1_plat_prepare_exit
+#pragma weak bl1_plat_get_next_image_id
+#pragma weak plat_arm_bl1_fwu_needed
+
+#define MAP_BL1_TOTAL		MAP_REGION_FLAT(			\
+					bl1_tzram_layout.total_base,	\
+					bl1_tzram_layout.total_size,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+/*
+ * If SEPARATE_CODE_AND_RODATA=1 we define a region for each section
+ * otherwise one region is defined containing both
+ */
+#if SEPARATE_CODE_AND_RODATA
+#define MAP_BL1_RO		MAP_REGION_FLAT(			\
+					BL_CODE_BASE,			\
+					BL1_CODE_END - BL_CODE_BASE,	\
+					MT_CODE | MT_SECURE),		\
+				MAP_REGION_FLAT(			\
+					BL1_RO_DATA_BASE,		\
+					BL1_RO_DATA_END			\
+						- BL_RO_DATA_BASE,	\
+					MT_RO_DATA | MT_SECURE)
+#else
+#define MAP_BL1_RO		MAP_REGION_FLAT(			\
+					BL_CODE_BASE,			\
+					BL1_CODE_END - BL_CODE_BASE,	\
+					MT_CODE | MT_SECURE)
+#endif
+
+/* Data structure which holds the extents of the trusted SRAM for BL1*/
+static meminfo_t bl1_tzram_layout;
+
+struct meminfo *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*******************************************************************************
+ * BL1 specific platform actions shared between ARM standard platforms.
+ ******************************************************************************/
+void arm_bl1_early_platform_setup(void)
+{
+
+#if !ARM_DISABLE_TRUSTED_WDOG
+	/* Enable watchdog */
+	plat_arm_secure_wdt_start();
+#endif
+
+	/* Initialize the console to provide early debug support */
+	arm_console_boot_init();
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = ARM_BL_RAM_BASE;
+	bl1_tzram_layout.total_size = ARM_BL_RAM_SIZE;
+}
+
+void bl1_early_platform_setup(void)
+{
+	arm_bl1_early_platform_setup();
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_arm_interconnect_init();
+	/*
+	 * Enable Interconnect coherency for the primary CPU's cluster.
+	 */
+	plat_arm_interconnect_enter_coherency();
+}
+
+/******************************************************************************
+ * Perform the very early platform specific architecture setup shared between
+ * ARM standard platforms. This only does basic initialization. Later
+ * architectural setup (bl1_arch_setup()) does not do anything platform
+ * specific.
+ *****************************************************************************/
+void arm_bl1_plat_arch_setup(void)
+{
+#if USE_COHERENT_MEM && !ARM_CRYPTOCELL_INTEG
+	/*
+	 * Ensure ARM platforms don't use coherent memory in BL1 unless
+	 * cryptocell integration is enabled.
+	 */
+	assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U);
+#endif
+
+	const mmap_region_t bl_regions[] = {
+		MAP_BL1_TOTAL,
+		MAP_BL1_RO,
+#if USE_ROMLIB
+		ARM_MAP_ROMLIB_CODE,
+		ARM_MAP_ROMLIB_DATA,
+#endif
+#if ARM_CRYPTOCELL_INTEG
+		ARM_MAP_BL_COHERENT_RAM,
+#endif
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+#ifdef __aarch64__
+	enable_mmu_el3(0);
+#else
+	enable_mmu_svc_mon(0);
+#endif /* __aarch64__ */
+
+	arm_setup_romlib();
+}
+
+void bl1_plat_arch_setup(void)
+{
+	arm_bl1_plat_arch_setup();
+}
+
+/*
+ * Perform the platform specific architecture setup shared between
+ * ARM standard platforms.
+ */
+void arm_bl1_platform_setup(void)
+{
+	/* Initialise the IO layer and register platform IO devices */
+	plat_arm_io_setup();
+	arm_load_tb_fw_config();
+#if TRUSTED_BOARD_BOOT
+	/* Share the Mbed TLS heap info with other images */
+	arm_bl1_set_mbedtls_heap();
+#endif /* TRUSTED_BOARD_BOOT */
+
+	/*
+	 * Allow access to the System counter timer module and program
+	 * counter frequency for non secure images during FWU
+	 */
+#ifdef ARM_SYS_TIMCTL_BASE
+	arm_configure_sys_timer();
+#endif
+#if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER)
+	write_cntfrq_el0(plat_get_syscnt_freq2());
+#endif
+}
+
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
+{
+#if !ARM_DISABLE_TRUSTED_WDOG
+	/* Disable watchdog before leaving BL1 */
+	plat_arm_secure_wdt_stop();
+#endif
+
+#ifdef EL3_PAYLOAD_BASE
+	/*
+	 * Program the EL3 payload's entry point address into the CPUs mailbox
+	 * in order to release secondary CPUs from their holding pen and make
+	 * them jump there.
+	 */
+	plat_arm_program_trusted_mailbox(ep_info->pc);
+	dsbsy();
+	sev();
+#endif
+}
+
+/*
+ * On Arm platforms, the FWU process is triggered when the FIP image has
+ * been tampered with.
+ */
+int plat_arm_bl1_fwu_needed(void)
+{
+	return (arm_io_is_toc_valid() != 1);
+}
+
+/*******************************************************************************
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or not.
+ ******************************************************************************/
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	if (plat_arm_bl1_fwu_needed() != 0)
+		return NS_BL1U_IMAGE_ID;
+
+	return BL2_IMAGE_ID;
+}
diff --git a/plat/arm/common/arm_bl2_el3_setup.c b/plat/arm/common/arm_bl2_el3_setup.c
new file mode 100644
index 0000000..97b5a88
--- /dev/null
+++ b/plat/arm/common/arm_bl2_el3_setup.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/generic_delay_timer.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#pragma weak bl2_el3_early_platform_setup
+#pragma weak bl2_el3_plat_arch_setup
+#pragma weak bl2_el3_plat_prepare_exit
+
+#define MAP_BL2_EL3_TOTAL	MAP_REGION_FLAT(				\
+					bl2_el3_tzram_layout.total_base,	\
+					bl2_el3_tzram_layout.total_size,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+static meminfo_t bl2_el3_tzram_layout;
+
+/*
+ * Perform arm specific early platform setup. At this moment we only initialize
+ * the console and the memory layout.
+ */
+void arm_bl2_el3_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	arm_console_boot_init();
+
+	/*
+	 * Allow BL2 to see the whole Trusted RAM. This is determined
+	 * statically since we cannot rely on BL1 passing this information
+	 * in the BL2_AT_EL3 case.
+	 */
+	bl2_el3_tzram_layout.total_base = ARM_BL_RAM_BASE;
+	bl2_el3_tzram_layout.total_size = ARM_BL_RAM_SIZE;
+
+	/* Initialise the IO layer and register platform IO devices */
+	plat_arm_io_setup();
+}
+
+void bl2_el3_early_platform_setup(u_register_t arg0 __unused,
+				  u_register_t arg1 __unused,
+				  u_register_t arg2 __unused,
+				  u_register_t arg3 __unused)
+{
+	arm_bl2_el3_early_platform_setup();
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_arm_interconnect_init();
+	/*
+	 * Enable Interconnect coherency for the primary CPU's cluster.
+	 */
+	plat_arm_interconnect_enter_coherency();
+
+	generic_delay_timer_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void arm_bl2_el3_plat_arch_setup(void)
+{
+
+#if USE_COHERENT_MEM
+	/* Ensure ARM platforms dont use coherent memory in BL2_AT_EL3 */
+	assert(BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE == 0U);
+#endif
+
+	const mmap_region_t bl_regions[] = {
+		MAP_BL2_EL3_TOTAL,
+		ARM_MAP_BL_RO,
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+
+#ifdef __aarch64__
+	enable_mmu_el3(0);
+#else
+	enable_mmu_svc_mon(0);
+#endif
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+	arm_bl2_el3_plat_arch_setup();
+}
+
+void bl2_el3_plat_prepare_exit(void)
+{
+}
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
new file mode 100644
index 0000000..cdf87ca
--- /dev/null
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#ifdef SPD_opteed
+#include <lib/optee_utils.h>
+#endif
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/*
+ * Check that BL2_BASE is above ARM_TB_FW_CONFIG_LIMIT. This reserved page is
+ * for `meminfo_t` data structure and fw_configs passed from BL1.
+ */
+CASSERT(BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_bl2_base_overflows);
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak bl2_early_platform_setup2
+#pragma weak bl2_platform_setup
+#pragma weak bl2_plat_arch_setup
+#pragma weak bl2_plat_sec_mem_layout
+
+#define MAP_BL2_TOTAL		MAP_REGION_FLAT(			\
+					bl2_tzram_layout.total_base,	\
+					bl2_tzram_layout.total_size,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+
+#pragma weak arm_bl2_plat_handle_post_image_load
+
+/*******************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ ******************************************************************************/
+void arm_bl2_early_platform_setup(uintptr_t tb_fw_config,
+				  struct meminfo *mem_layout)
+{
+	/* Initialize the console to provide early debug support */
+	arm_console_boot_init();
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+
+	/* Initialise the IO layer and register platform IO devices */
+	plat_arm_io_setup();
+
+	if (tb_fw_config != 0U)
+		arm_bl2_set_tb_cfg_addr((void *)tb_fw_config);
+}
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3)
+{
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+
+	generic_delay_timer_init();
+}
+
+/*
+ * Perform  BL2 preload setup. Currently we initialise the dynamic
+ * configuration here.
+ */
+void bl2_plat_preload_setup(void)
+{
+	arm_bl2_dyn_cfg_init();
+}
+
+/*
+ * Perform ARM standard platform setup.
+ */
+void arm_bl2_platform_setup(void)
+{
+	/* Initialize the secure environment */
+	plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_static_mem_protect();
+#endif
+}
+
+void bl2_platform_setup(void)
+{
+	arm_bl2_platform_setup();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void arm_bl2_plat_arch_setup(void)
+{
+#if USE_COHERENT_MEM && !ARM_CRYPTOCELL_INTEG
+	/*
+	 * Ensure ARM platforms don't use coherent memory in BL2 unless
+	 * cryptocell integration is enabled.
+	 */
+	assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U);
+#endif
+
+	const mmap_region_t bl_regions[] = {
+		MAP_BL2_TOTAL,
+		ARM_MAP_BL_RO,
+#if USE_ROMLIB
+		ARM_MAP_ROMLIB_CODE,
+		ARM_MAP_ROMLIB_DATA,
+#endif
+#if ARM_CRYPTOCELL_INTEG
+		ARM_MAP_BL_COHERENT_RAM,
+#endif
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+
+#ifdef __aarch64__
+	enable_mmu_el1(0);
+#else
+	enable_mmu_svc_mon(0);
+#endif
+
+	arm_setup_romlib();
+}
+
+void bl2_plat_arch_setup(void)
+{
+	arm_bl2_plat_arch_setup();
+}
+
+int arm_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#ifdef SPD_opteed
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+	assert(bl_mem_params);
+
+	switch (image_id) {
+#ifdef __aarch64__
+	case BL32_IMAGE_ID:
+#ifdef SPD_opteed
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+				&pager_mem_params->image_info,
+				&paged_mem_params->image_info);
+		if (err != 0) {
+			WARN("OPTEE header parse error.\n");
+		}
+#endif
+		bl_mem_params->ep_info.spsr = arm_get_spsr_for_bl32_entry();
+		break;
+#endif
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = arm_get_spsr_for_bl33_entry();
+		break;
+
+#ifdef SCP_BL2_BASE
+	case SCP_BL2_IMAGE_ID:
+		/* The subsequent handling of SCP_BL2 is platform specific */
+		err = plat_arm_bl2_handle_scp_bl2(&bl_mem_params->image_info);
+		if (err) {
+			WARN("Failure in platform-specific handling of SCP_BL2 image.\n");
+		}
+		break;
+#endif
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int arm_bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return arm_bl2_handle_post_image_load(image_id);
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return arm_bl2_plat_handle_post_image_load(image_id);
+}
diff --git a/plat/arm/common/arm_bl2u_setup.c b/plat/arm/common/arm_bl2u_setup.c
new file mode 100644
index 0000000..3614c7d
--- /dev/null
+++ b/plat/arm/common/arm_bl2u_setup.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <drivers/generic_delay_timer.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak bl2u_platform_setup
+#pragma weak bl2u_early_platform_setup
+#pragma weak bl2u_plat_arch_setup
+
+#define MAP_BL2U_TOTAL		MAP_REGION_FLAT(			\
+					BL2U_BASE,			\
+					BL2U_LIMIT - BL2U_BASE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * Perform ARM standard platform setup for BL2U
+ */
+void arm_bl2u_platform_setup(void)
+{
+	/* Initialize the secure environment */
+	plat_arm_security_setup();
+}
+
+void bl2u_platform_setup(void)
+{
+	arm_bl2u_platform_setup();
+}
+
+void arm_bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info)
+{
+	/* Initialize the console to provide early debug support */
+	arm_console_boot_init();
+
+	generic_delay_timer_init();
+}
+
+/*******************************************************************************
+ * BL1 can pass platform dependent information to BL2U in x1.
+ * In case of ARM CSS platforms x1 contains SCP_BL2U image info.
+ * In case of ARM FVP platforms x1 is not used.
+ * In both cases, x0 contains the extents of the memory available to BL2U
+ ******************************************************************************/
+void bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info)
+{
+	arm_bl2u_early_platform_setup(mem_layout, plat_info);
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ * The memory that is used by BL2U is only mapped.
+ ******************************************************************************/
+void arm_bl2u_plat_arch_setup(void)
+{
+
+#if USE_COHERENT_MEM
+	/* Ensure ARM platforms dont use coherent memory in BL2U */
+	assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U);
+#endif
+
+	const mmap_region_t bl_regions[] = {
+		MAP_BL2U_TOTAL,
+		ARM_MAP_BL_RO,
+#if USE_ROMLIB
+		ARM_MAP_ROMLIB_CODE,
+		ARM_MAP_ROMLIB_DATA,
+#endif
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+
+#ifdef __aarch64__
+	enable_mmu_el1(0);
+#else
+	enable_mmu_svc_mon(0);
+#endif
+	arm_setup_romlib();
+}
+
+void bl2u_plat_arch_setup(void)
+{
+	arm_bl2u_plat_arch_setup();
+}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
new file mode 100644
index 0000000..ab90f46
--- /dev/null
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/extensions/ras.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+#if !RESET_TO_BL31
+/*
+ * Check that BL31_BASE is above ARM_TB_FW_CONFIG_LIMIT. The reserved page
+ * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2.
+ */
+CASSERT(BL31_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_bl31_base_overflows);
+#endif
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak bl31_early_platform_setup2
+#pragma weak bl31_platform_setup
+#pragma weak bl31_plat_arch_setup
+#pragma weak bl31_plat_get_next_image_ep_info
+
+#define MAP_BL31_TOTAL		MAP_REGION_FLAT(			\
+					BL31_START,			\
+					BL31_END - BL31_START,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+#if RECLAIM_INIT_CODE
+IMPORT_SYM(unsigned long, __INIT_CODE_START__, BL_INIT_CODE_BASE);
+IMPORT_SYM(unsigned long, __INIT_CODE_END__, BL_INIT_CODE_END);
+
+#define MAP_BL_INIT_CODE	MAP_REGION_FLAT(			\
+					BL_INIT_CODE_BASE,		\
+					BL_INIT_CODE_END		\
+						- BL_INIT_CODE_BASE,	\
+					MT_CODE | MT_SECURE)
+#endif
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for the
+ * security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type));
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+	/*
+	 * None of the images on the ARM development platforms can have 0x0
+	 * as the entrypoint
+	 */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup common to ARM standard platforms.
+ * Here is an opportunity to copy parameters passed by the calling EL (S-EL1
+ * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be
+ * done before the MMU is initialized so that the memory layout can be used
+ * while creating page tables. BL2 has flushed this information to memory, so
+ * we are guaranteed to pick up good data.
+ ******************************************************************************/
+void __init arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config,
+				uintptr_t hw_config, void *plat_params_from_bl2)
+{
+	/* Initialize the console to provide early debug support */
+	arm_console_boot_init();
+
+#if RESET_TO_BL31
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(from_bl2 == NULL);
+	assert(plat_params_from_bl2 == NULL);
+
+# ifdef BL32_BASE
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+# endif /* BL32_BASE */
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell BL31 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+
+	bl33_image_ep_info.spsr = arm_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+# if ARM_LINUX_KERNEL_AS_BL33
+	/*
+	 * According to the file ``Documentation/arm64/booting.txt`` of the
+	 * Linux kernel tree, Linux expects the physical address of the device
+	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
+	 * must be 0.
+	 */
+	bl33_image_ep_info.args.arg0 = (u_register_t)ARM_PRELOADED_DTB_BASE;
+	bl33_image_ep_info.args.arg1 = 0U;
+	bl33_image_ep_info.args.arg2 = 0U;
+	bl33_image_ep_info.args.arg3 = 0U;
+# endif
+
+#else /* RESET_TO_BL31 */
+
+	/*
+	 * In debug builds, we pass a special value in 'plat_params_from_bl2'
+	 * to verify platform parameters from BL2 to BL31.
+	 * In release builds, it's not used.
+	 */
+	assert(((unsigned long long)plat_params_from_bl2) ==
+		ARM_BL31_PLAT_PARAM_VAL);
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params != NULL) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_image_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0U)
+		panic();
+#endif /* RESET_TO_BL31 */
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3)
+{
+	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_arm_interconnect_init();
+
+	/*
+	 * Enable Interconnect coherency for the primary CPU's cluster.
+	 * Earlier bootloader stages might already do this (e.g. Trusted
+	 * Firmware's BL1 does it) but we can't assume so. There is no harm in
+	 * executing this code twice anyway.
+	 * Platform specific PSCI code will enable coherency for other
+	 * clusters.
+	 */
+	plat_arm_interconnect_enter_coherency();
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ ******************************************************************************/
+void arm_bl31_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	plat_arm_gic_driver_init();
+	plat_arm_gic_init();
+
+#if RESET_TO_BL31
+	/*
+	 * Do initial security configuration to allow DRAM/device access
+	 * (if earlier BL has not already done so).
+	 */
+	plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_dyn_mem_protect();
+#endif /* PLAT_ARM_MEM_PROT_ADDR */
+
+#endif /* RESET_TO_BL31 */
+
+	/* Enable and initialize the System level generic timer */
+	mmio_write_32(ARM_SYS_CNTCTL_BASE + CNTCR_OFF,
+			CNTCR_FCREQ(0U) | CNTCR_EN);
+
+	/* Allow access to the System counter timer module */
+	arm_configure_sys_timer();
+
+	/* Initialize power controller before setting up topology */
+	plat_arm_pwrc_setup();
+
+#if RAS_EXTENSION
+	ras_init();
+#endif
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM
+ * standard platforms
+ * Perform BL31 platform setup
+ ******************************************************************************/
+void arm_bl31_plat_runtime_setup(void)
+{
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
+
+	/* Initialize the runtime console */
+	arm_console_runtime_init();
+#if RECLAIM_INIT_CODE
+	arm_free_init_memory();
+#endif
+}
+
+#if RECLAIM_INIT_CODE
+/*
+ * Zero out and make RW memory used to store image boot time code so it can
+ * be reclaimed during runtime
+ */
+void arm_free_init_memory(void)
+{
+	int ret = xlat_change_mem_attributes(BL_INIT_CODE_BASE,
+				BL_INIT_CODE_END - BL_INIT_CODE_BASE,
+				MT_RW_DATA);
+
+	if (ret != 0) {
+		ERROR("Could not reclaim initialization code");
+		panic();
+	}
+}
+#endif
+
+void __init bl31_platform_setup(void)
+{
+	arm_bl31_platform_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	arm_bl31_plat_runtime_setup();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup shared between
+ * ARM standard platforms. This only does basic initialization. Later
+ * architectural setup (bl31_arch_setup()) does not do anything platform
+ * specific.
+ ******************************************************************************/
+void __init arm_bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_BL31_TOTAL,
+#if RECLAIM_INIT_CODE
+		MAP_BL_INIT_CODE,
+#endif
+		ARM_MAP_BL_RO,
+#if USE_ROMLIB
+		ARM_MAP_ROMLIB_CODE,
+		ARM_MAP_ROMLIB_DATA,
+#endif
+#if USE_COHERENT_MEM
+		ARM_MAP_BL_COHERENT_RAM,
+#endif
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+
+	enable_mmu_el3(0);
+
+	arm_setup_romlib();
+}
+
+void __init bl31_plat_arch_setup(void)
+{
+	arm_bl31_plat_arch_setup();
+}
diff --git a/plat/arm/common/arm_cci.c b/plat/arm/common/arm_cci.c
new file mode 100644
index 0000000..3795fc5
--- /dev/null
+++ b/plat/arm/common/arm_cci.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+static const int cci_map[] = {
+	PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way ARM CCI driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_interconnect_init
+#pragma weak plat_arm_interconnect_enter_coherency
+#pragma weak plat_arm_interconnect_exit_coherency
+
+
+/******************************************************************************
+ * Helper function to initialize ARM CCI driver.
+ *****************************************************************************/
+void __init plat_arm_interconnect_init(void)
+{
+	cci_init(PLAT_ARM_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_arm_interconnect_enter_coherency(void)
+{
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_arm_interconnect_exit_coherency(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/arm/common/arm_ccn.c b/plat/arm/common/arm_ccn.c
new file mode 100644
index 0000000..2e681ca
--- /dev/null
+++ b/plat/arm/common/arm_ccn.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <drivers/arm/ccn.h>
+#include <plat/arm/common/plat_arm.h>
+
+static const unsigned char master_to_rn_id_map[] = {
+	PLAT_ARM_CLUSTER_TO_CCN_ID_MAP
+};
+
+static const ccn_desc_t arm_ccn_desc = {
+	.periphbase = PLAT_ARM_CCN_BASE,
+	.num_masters = ARRAY_SIZE(master_to_rn_id_map),
+	.master_to_rn_id_map = master_to_rn_id_map
+};
+
+CASSERT(PLAT_ARM_CLUSTER_COUNT == ARRAY_SIZE(master_to_rn_id_map),
+		assert_invalid_cluster_count_for_ccn_variant);
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way ARM CCN driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_interconnect_init
+#pragma weak plat_arm_interconnect_enter_coherency
+#pragma weak plat_arm_interconnect_exit_coherency
+
+
+/******************************************************************************
+ * Helper function to initialize ARM CCN driver.
+ *****************************************************************************/
+void __init plat_arm_interconnect_init(void)
+{
+	ccn_init(&arm_ccn_desc);
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_arm_interconnect_enter_coherency(void)
+{
+	ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_arm_interconnect_exit_coherency(void)
+{
+	ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/arm/common/arm_common.c b/plat/arm/common/arm_common.c
new file mode 100644
index 0000000..bc0cf9a
--- /dev/null
+++ b/plat/arm/common/arm_common.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/romlib.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <services/secure_partition.h>
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_get_ns_image_entrypoint
+#pragma weak plat_arm_get_mmap
+
+/* Conditionally provide a weak definition of plat_get_syscnt_freq2 to avoid
+ * conflicts with the definition in plat/common. */
+#pragma weak plat_get_syscnt_freq2
+
+
+void arm_setup_romlib(void)
+{
+#if USE_ROMLIB
+	if (!rom_lib_init(ROMLIB_VERSION))
+		panic();
+#endif
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return PLAT_ARM_NS_IMAGE_BASE;
+#endif
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t arm_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+#ifdef __aarch64__
+uint32_t arm_get_spsr_for_bl33_entry(void)
+{
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#else
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t arm_get_spsr_for_bl33_entry(void)
+{
+	unsigned int hyp_status, mode, spsr;
+
+	hyp_status = GET_VIRT_EXT(read_id_pfr1());
+
+	mode = (hyp_status) ? MODE32_hyp : MODE32_svc;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1,
+			SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#endif /* __aarch64__ */
+
+/*******************************************************************************
+ * Configures access to the system counter timer module.
+ ******************************************************************************/
+#ifdef ARM_SYS_TIMCTL_BASE
+void arm_configure_sys_timer(void)
+{
+	unsigned int reg_val;
+
+	/* Read the frequency of the system counter */
+	unsigned int freq_val = plat_get_syscnt_freq2();
+
+#if ARM_CONFIG_CNTACR
+	reg_val = (1U << CNTACR_RPCT_SHIFT) | (1U << CNTACR_RVCT_SHIFT);
+	reg_val |= (1U << CNTACR_RFRQ_SHIFT) | (1U << CNTACR_RVOFF_SHIFT);
+	reg_val |= (1U << CNTACR_RWVT_SHIFT) | (1U << CNTACR_RWPT_SHIFT);
+	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_ARM_NSTIMER_FRAME_ID), reg_val);
+#endif /* ARM_CONFIG_CNTACR */
+
+	reg_val = (1U << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID));
+	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val);
+
+	/*
+	 * Initialize CNTFRQ register in CNTCTLBase frame. The CNTFRQ
+	 * system register initialized during psci_arch_setup() is different
+	 * from this and has to be updated independently.
+	 */
+	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTCTLBASE_CNTFRQ, freq_val);
+
+#if defined(PLAT_juno) || defined(PLAT_n1sdp)
+	/*
+	 * Initialize CNTFRQ register in Non-secure CNTBase frame.
+	 * This is only required for Juno and N1SDP, because they do not
+	 * follow ARM ARM in that the value updated in CNTFRQ is not
+	 * reflected in CNTBASEN_CNTFRQ. Hence update the value manually.
+	 */
+	mmio_write_32(ARM_SYS_CNT_BASE_NS + CNTBASEN_CNTFRQ, freq_val);
+#endif
+}
+#endif /* ARM_SYS_TIMCTL_BASE */
+
+/*******************************************************************************
+ * Returns ARM platform specific memory map regions.
+ ******************************************************************************/
+const mmap_region_t *plat_arm_get_mmap(void)
+{
+	return plat_arm_mmap;
+}
+
+#ifdef ARM_SYS_CNTCTL_BASE
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	unsigned int counter_base_frequency;
+
+	/* Read the frequency from Frequency modes table */
+	counter_base_frequency = mmio_read_32(ARM_SYS_CNTCTL_BASE + CNTFID_OFF);
+
+	/* The first entry of the frequency modes table must not be 0 */
+	if (counter_base_frequency == 0U)
+		panic();
+
+	return counter_base_frequency;
+}
+
+#endif /* ARM_SYS_CNTCTL_BASE */
+
+#if SDEI_SUPPORT
+/*
+ * Translate SDEI entry point to PA, and perform standard ARM entry point
+ * validation on it.
+ */
+int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode)
+{
+	uint64_t par, pa;
+	uint32_t scr_el3;
+
+	/* Doing Non-secure address translation requires SCR_EL3.NS set */
+	scr_el3 = read_scr_el3();
+	write_scr_el3(scr_el3 | SCR_NS_BIT);
+	isb();
+
+	assert((client_mode == MODE_EL2) || (client_mode == MODE_EL1));
+	if (client_mode == MODE_EL2) {
+		/*
+		 * Translate entry point to Physical Address using the EL2
+		 * translation regime.
+		 */
+		ats1e2r(ep);
+	} else {
+		/*
+		 * Translate entry point to Physical Address using the EL1&0
+		 * translation regime, including stage 2.
+		 */
+		ats12e1r(ep);
+	}
+	isb();
+	par = read_par_el1();
+
+	/* Restore original SCRL_EL3 */
+	write_scr_el3(scr_el3);
+	isb();
+
+	/* If the translation resulted in fault, return failure */
+	if ((par & PAR_F_MASK) != 0)
+		return -1;
+
+	/* Extract Physical Address from PAR */
+	pa = (par & (PAR_ADDR_MASK << PAR_ADDR_SHIFT));
+
+	/* Perform NS entry point validation on the physical address */
+	return arm_validate_ns_entrypoint(pa);
+}
+#endif
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
new file mode 100644
index 0000000..10b6e51
--- /dev/null
+++ b/plat/arm/common/arm_common.mk
@@ -0,0 +1,288 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ARCH}, aarch64)
+  # On ARM standard platorms, the TSP can execute from Trusted SRAM, Trusted
+  # DRAM (if available) or the TZC secured area of DRAM.
+  # TZC secured DRAM is the default.
+
+  ARM_TSP_RAM_LOCATION	?=	dram
+
+  ifeq (${ARM_TSP_RAM_LOCATION}, tsram)
+    ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID
+  else ifeq (${ARM_TSP_RAM_LOCATION}, tdram)
+    ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_DRAM_ID
+  else ifeq (${ARM_TSP_RAM_LOCATION}, dram)
+    ARM_TSP_RAM_LOCATION_ID = ARM_DRAM_ID
+  else
+    $(error "Unsupported ARM_TSP_RAM_LOCATION value")
+  endif
+
+  # Process flags
+  # Process ARM_BL31_IN_DRAM flag
+  ARM_BL31_IN_DRAM		:=	0
+  $(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
+  $(eval $(call add_define,ARM_BL31_IN_DRAM))
+else
+  ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID
+endif
+
+$(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID))
+
+
+# For the original power-state parameter format, the State-ID can be encoded
+# according to the recommended encoding or zero. This flag determines which
+# State-ID encoding to be parsed.
+ARM_RECOM_STATE_ID_ENC := 0
+
+# If the PSCI_EXTENDED_STATE_ID is set, then ARM_RECOM_STATE_ID_ENC need to
+# be set. Else throw a build error.
+ifeq (${PSCI_EXTENDED_STATE_ID}, 1)
+  ifeq (${ARM_RECOM_STATE_ID_ENC}, 0)
+    $(error Build option ARM_RECOM_STATE_ID_ENC needs to be set if \
+            PSCI_EXTENDED_STATE_ID is set for ARM platforms)
+  endif
+endif
+
+# Process ARM_RECOM_STATE_ID_ENC flag
+$(eval $(call assert_boolean,ARM_RECOM_STATE_ID_ENC))
+$(eval $(call add_define,ARM_RECOM_STATE_ID_ENC))
+
+# Process ARM_DISABLE_TRUSTED_WDOG flag
+# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set
+ARM_DISABLE_TRUSTED_WDOG	:=	0
+ifeq (${SPIN_ON_BL1_EXIT}, 1)
+ARM_DISABLE_TRUSTED_WDOG	:=	1
+endif
+$(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG))
+$(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG))
+
+# Process ARM_CONFIG_CNTACR
+ARM_CONFIG_CNTACR		:=	1
+$(eval $(call assert_boolean,ARM_CONFIG_CNTACR))
+$(eval $(call add_define,ARM_CONFIG_CNTACR))
+
+# Process ARM_BL31_IN_DRAM flag
+ARM_BL31_IN_DRAM		:=	0
+$(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
+$(eval $(call add_define,ARM_BL31_IN_DRAM))
+
+# Process ARM_PLAT_MT flag
+ARM_PLAT_MT			:=	0
+$(eval $(call assert_boolean,ARM_PLAT_MT))
+$(eval $(call add_define,ARM_PLAT_MT))
+
+# Use translation tables library v2 by default
+ARM_XLAT_TABLES_LIB_V1		:=	0
+$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
+$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
+
+# Don't have the Linux kernel as a BL33 image by default
+ARM_LINUX_KERNEL_AS_BL33	:=	0
+$(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33))
+$(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33))
+
+ifeq (${ARM_LINUX_KERNEL_AS_BL33},1)
+  ifeq (${ARCH},aarch64)
+    ifneq (${RESET_TO_BL31},1)
+      $(error "ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_BL31=1.")
+    endif
+  else
+    ifneq (${RESET_TO_SP_MIN},1)
+      $(error "ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_SP_MIN=1.")
+    endif
+  endif
+  ifndef PRELOADED_BL33_BASE
+    $(error "PRELOADED_BL33_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.")
+  endif
+  ifndef ARM_PRELOADED_DTB_BASE
+    $(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.")
+  endif
+  $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
+endif
+
+# Use an implementation of SHA-256 with a smaller memory footprint but reduced
+# speed.
+$(eval $(call add_define,MBEDTLS_SHA256_SMALLER))
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
+endif
+
+# Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms
+ENABLE_PSCI_STAT		:=	1
+ENABLE_PMF			:=	1
+
+# On ARM platforms, separate the code and read-only data sections to allow
+# mapping the former as executable and the latter as execute-never.
+SEPARATE_CODE_AND_RODATA	:=	1
+
+# Disable ARM Cryptocell by default
+ARM_CRYPTOCELL_INTEG		:=	0
+$(eval $(call assert_boolean,ARM_CRYPTOCELL_INTEG))
+$(eval $(call add_define,ARM_CRYPTOCELL_INTEG))
+
+# CryptoCell integration relies on coherent buffers for passing data from
+# the AP CPU to the CryptoCell
+ifeq (${ARM_CRYPTOCELL_INTEG},1)
+    ifeq (${USE_COHERENT_MEM},0)
+        $(error "ARM_CRYPTOCELL_INTEG needs USE_COHERENT_MEM to be set.")
+    endif
+endif
+
+ifeq (${ARCH}, aarch64)
+PLAT_INCLUDES		+=	-Iinclude/plat/arm/common/aarch64
+endif
+
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/${ARCH}/arm_helpers.S		\
+				plat/arm/common/arm_common.c			\
+				plat/arm/common/arm_console.c
+
+ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
+PLAT_BL_COMMON_SOURCES	+=	lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/${ARCH}/xlat_tables.c
+else
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}
+endif
+
+BL1_SOURCES		+=	drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/arm/common/arm_bl1_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/common/arm_io_storage.c
+ifdef EL3_PAYLOAD_BASE
+# Need the plat_arm_program_trusted_mailbox() function to release secondary CPUs from
+# their holding pen
+BL1_SOURCES		+=	plat/arm/common/arm_pm.c
+endif
+
+BL2_SOURCES		+=	drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/arm/common/arm_bl2_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/common/arm_io_storage.c
+
+# Add `libfdt` and Arm common helpers required for Dynamic Config
+include lib/libfdt/libfdt.mk
+
+DYN_CFG_SOURCES		+=	plat/arm/common/arm_dyn_cfg.c		\
+				plat/arm/common/arm_dyn_cfg_helpers.c	\
+				common/fdt_wrappers.c
+
+BL1_SOURCES		+=	${DYN_CFG_SOURCES}
+BL2_SOURCES		+=	${DYN_CFG_SOURCES}
+
+ifeq (${BL2_AT_EL3},1)
+BL2_SOURCES		+=	plat/arm/common/arm_bl2_el3_setup.c
+endif
+
+# Because BL1/BL2 execute in AArch64 mode but BL32 in AArch32 we need to use
+# the AArch32 descriptors.
+ifeq (${JUNO_AARCH32_EL3_RUNTIME},1)
+BL2_SOURCES		+=	plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
+else
+BL2_SOURCES		+=	plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c
+endif
+BL2_SOURCES		+=	plat/arm/common/arm_image_load.c		\
+				common/desc_image_load.c
+ifeq (${SPD},opteed)
+BL2_SOURCES		+=	lib/optee/optee_utils.c
+endif
+
+BL2U_SOURCES		+=	drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				plat/arm/common/arm_bl2u_setup.c
+
+BL31_SOURCES		+=	plat/arm/common/arm_bl31_setup.c		\
+				plat/arm/common/arm_pm.c			\
+				plat/arm/common/arm_topology.c			\
+				plat/arm/common/execution_state_switch.c	\
+				plat/common/plat_psci_common.c
+
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES		+=	plat/arm/common/arm_sip_svc.c			\
+				lib/pmf/pmf_smc.c
+endif
+
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES		+=	plat/arm/common/aarch64/arm_ehf.c
+endif
+
+ifeq (${SDEI_SUPPORT},1)
+BL31_SOURCES		+=	plat/arm/common/aarch64/arm_sdei.c
+endif
+
+# RAS sources
+ifeq (${RAS_EXTENSION},1)
+BL31_SOURCES		+=	lib/extensions/ras/std_err_record.c		\
+				lib/extensions/ras/ras_common.c
+endif
+
+# Pointer Authentication sources
+ifeq (${ENABLE_PAUTH}, 1)
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/common/aarch64/arm_pauth.c
+endif
+
+# SPM uses libfdt in Arm platforms
+ifeq (${SPM_MM},0)
+ifeq (${ENABLE_SPM},1)
+BL31_SOURCES		+=	common/fdt_wrappers.c			\
+				plat/common/plat_spm_rd.c		\
+				plat/common/plat_spm_sp.c		\
+				${LIBFDT_SRCS}
+endif
+endif
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+    # Include common TBB sources
+    AUTH_SOURCES	:=	drivers/auth/auth_mod.c				\
+				drivers/auth/crypto_mod.c			\
+				drivers/auth/img_parser_mod.c			\
+				drivers/auth/tbbr/tbbr_cot.c			\
+
+    BL1_SOURCES		+=	${AUTH_SOURCES}					\
+				bl1/tbbr/tbbr_img_desc.c			\
+				plat/arm/common/arm_bl1_fwu.c			\
+				plat/common/tbbr/plat_tbbr.c
+
+    BL2_SOURCES		+=	${AUTH_SOURCES}					\
+				plat/common/tbbr/plat_tbbr.c
+
+    $(eval $(call TOOL_ADD_IMG,ns_bl2u,--fwu,FWU_))
+
+    # We expect to locate the *.mk files under the directories specified below
+ifeq (${ARM_CRYPTOCELL_INTEG},0)
+    CRYPTO_LIB_MK := drivers/auth/mbedtls/mbedtls_crypto.mk
+else
+    CRYPTO_LIB_MK := drivers/auth/cryptocell/cryptocell_crypto.mk
+endif
+    IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk
+
+    $(info Including ${CRYPTO_LIB_MK})
+    include ${CRYPTO_LIB_MK}
+
+    $(info Including ${IMG_PARSER_LIB_MK})
+    include ${IMG_PARSER_LIB_MK}
+
+endif
+
+ifeq (${RECLAIM_INIT_CODE}, 1)
+    ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
+        $(error "To reclaim init code xlat tables v2 must be used")
+    endif
+endif
diff --git a/plat/arm/common/arm_console.c b/plat/arm/common/arm_console.c
new file mode 100644
index 0000000..123811d
--- /dev/null
+++ b/plat/arm/common/arm_console.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Functions that set up the console
+ ******************************************************************************/
+static console_pl011_t arm_boot_console;
+static console_pl011_t arm_runtime_console;
+
+/* Initialize the console to provide early debug support */
+void __init arm_console_boot_init(void)
+{
+	int rc = console_pl011_register(PLAT_ARM_BOOT_UART_BASE,
+					PLAT_ARM_BOOT_UART_CLK_IN_HZ,
+					ARM_CONSOLE_BAUDRATE,
+					&arm_boot_console);
+	if (rc == 0) {
+		/*
+		 * The crash console doesn't use the multi console API, it uses
+		 * the core console functions directly. It is safe to call panic
+		 * and let it print debug information.
+		 */
+		panic();
+	}
+
+	console_set_scope(&arm_boot_console.console, CONSOLE_FLAG_BOOT);
+}
+
+void arm_console_boot_end(void)
+{
+	(void)console_flush();
+	(void)console_unregister(&arm_boot_console.console);
+}
+
+/* Initialize the runtime console */
+void arm_console_runtime_init(void)
+{
+	int rc = console_pl011_register(PLAT_ARM_RUN_UART_BASE,
+					PLAT_ARM_RUN_UART_CLK_IN_HZ,
+					ARM_CONSOLE_BAUDRATE,
+					&arm_runtime_console);
+	if (rc == 0)
+		panic();
+
+	console_set_scope(&arm_runtime_console.console, CONSOLE_FLAG_RUNTIME);
+}
+
+void arm_console_runtime_end(void)
+{
+	(void)console_flush();
+}
diff --git a/plat/arm/common/arm_dyn_cfg.c b/plat/arm/common/arm_dyn_cfg.c
new file mode 100644
index 0000000..9a53649
--- /dev/null
+++ b/plat/arm/common/arm_dyn_cfg.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/tbbr/tbbr_img_def.h>
+#if TRUSTED_BOARD_BOOT
+#include <drivers/auth/mbedtls/mbedtls_config.h>
+#endif
+#include <plat/arm/common/arm_dyn_cfg_helpers.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Variable to store the address to TB_FW_CONFIG passed from BL1 */
+static void *tb_fw_cfg_dtb;
+static size_t tb_fw_cfg_dtb_size;
+
+
+#if TRUSTED_BOARD_BOOT
+
+static void *mbedtls_heap_addr;
+static size_t mbedtls_heap_size;
+
+/*
+ * This function is the implementation of the shared Mbed TLS heap between
+ * BL1 and BL2 for Arm platforms. The shared heap address is passed from BL1
+ * to BL2 with a pointer. This pointer resides inside the TB_FW_CONFIG file
+ * which is a DTB.
+ *
+ * This function is placed inside an #if directive for the below reasons:
+ *   - To allocate space for the Mbed TLS heap --only if-- Trusted Board Boot
+ *     is enabled.
+ *   - This implementation requires the DTB to be present so that BL1 has a
+ *     mechanism to pass the pointer to BL2.
+ */
+int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	assert(heap_addr != NULL);
+	assert(heap_size != NULL);
+
+#if defined(IMAGE_BL1) || BL2_AT_EL3
+
+	/* If in BL1 or BL2_AT_EL3 define a heap */
+	static unsigned char heap[TF_MBEDTLS_HEAP_SIZE];
+
+	*heap_addr = heap;
+	*heap_size = sizeof(heap);
+	mbedtls_heap_addr = heap;
+	mbedtls_heap_size = sizeof(heap);
+
+#elif defined(IMAGE_BL2)
+
+	int err;
+
+	/* If in BL2, retrieve the already allocated heap's info from DTB */
+	if (tb_fw_cfg_dtb != NULL) {
+		err = arm_get_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, heap_addr,
+			heap_size);
+		if (err < 0) {
+			ERROR("BL2: unable to retrieve shared Mbed TLS heap information from DTB\n");
+			panic();
+		}
+	} else {
+		ERROR("BL2: DTB missing, cannot get Mbed TLS heap\n");
+		panic();
+	}
+#endif
+
+	return 0;
+}
+
+/*
+ * Puts the shared Mbed TLS heap information to the DTB.
+ * Executed only from BL1.
+ */
+void arm_bl1_set_mbedtls_heap(void)
+{
+	int err;
+
+	/*
+	 * If tb_fw_cfg_dtb==NULL then DTB is not present for the current
+	 * platform. As such, we don't attempt to write to the DTB at all.
+	 *
+	 * If mbedtls_heap_addr==NULL, then it means we are using the default
+	 * heap implementation. As such, BL2 will have its own heap for sure
+	 * and hence there is no need to pass any information to the DTB.
+	 *
+	 * In the latter case, if we still wanted to write in the DTB the heap
+	 * information, we would need to call plat_get_mbedtls_heap to retrieve
+	 * the default heap's address and size.
+	 */
+	if ((tb_fw_cfg_dtb != NULL) && (mbedtls_heap_addr != NULL)) {
+		err = arm_set_dtb_mbedtls_heap_info(tb_fw_cfg_dtb,
+			mbedtls_heap_addr, mbedtls_heap_size);
+		if (err < 0) {
+			ERROR("BL1: unable to write shared Mbed TLS heap information to DTB\n");
+			panic();
+		}
+		/*
+		 * Ensure that the info written to the DTB is visible to other
+		 * images. It's critical because BL2 won't be able to proceed
+		 * without the heap info.
+		 */
+		flush_dcache_range((uintptr_t)tb_fw_cfg_dtb,
+			tb_fw_cfg_dtb_size);
+	}
+}
+
+#endif /* TRUSTED_BOARD_BOOT */
+
+/*
+ * Helper function to load TB_FW_CONFIG and populate the load information to
+ * arg0 of BL2 entrypoint info.
+ */
+void arm_load_tb_fw_config(void)
+{
+	int err;
+	uintptr_t config_base = 0UL;
+	image_desc_t *desc;
+
+	image_desc_t arm_tb_fw_info = {
+		.image_id = TB_FW_CONFIG_ID,
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+				VERSION_2, image_info_t, 0),
+		.image_info.image_base = ARM_TB_FW_CONFIG_BASE,
+		.image_info.image_max_size =
+			ARM_TB_FW_CONFIG_LIMIT - ARM_TB_FW_CONFIG_BASE
+	};
+
+	VERBOSE("BL1: Loading TB_FW_CONFIG\n");
+	err = load_auth_image(TB_FW_CONFIG_ID, &arm_tb_fw_info.image_info);
+	if (err != 0) {
+		/* Return if TB_FW_CONFIG is not loaded */
+		VERBOSE("Failed to load TB_FW_CONFIG\n");
+		return;
+	}
+
+	/* At this point we know that a DTB is indeed available */
+	config_base = arm_tb_fw_info.image_info.image_base;
+	tb_fw_cfg_dtb = (void *)config_base;
+	tb_fw_cfg_dtb_size = (size_t)arm_tb_fw_info.image_info.image_max_size;
+
+	/* The BL2 ep_info arg0 is modified to point to TB_FW_CONFIG */
+	desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+	assert(desc != NULL);
+	desc->ep_info.args.arg0 = config_base;
+
+	INFO("BL1: TB_FW_CONFIG loaded at address = 0x%lx\n", config_base);
+
+#if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH)
+	int tb_fw_node;
+	uint32_t disable_auth = 0;
+
+	err = arm_dyn_tb_fw_cfg_init((void *)config_base, &tb_fw_node);
+	if (err < 0) {
+		ERROR("Invalid TB_FW_CONFIG loaded\n");
+		panic();
+	}
+
+	err = arm_dyn_get_disable_auth((void *)config_base, tb_fw_node, &disable_auth);
+	if (err < 0)
+		return;
+
+	if (disable_auth == 1)
+		dyn_disable_auth();
+#endif
+}
+
+/*
+ * BL2 utility function to set the address of TB_FW_CONFIG passed from BL1.
+ */
+void arm_bl2_set_tb_cfg_addr(void *dtb)
+{
+	assert(dtb != NULL);
+	tb_fw_cfg_dtb = dtb;
+}
+
+/*
+ * BL2 utility function to initialize dynamic configuration specified by
+ * TB_FW_CONFIG. Populate the bl_mem_params_node_t of other FW_CONFIGs if
+ * specified in TB_FW_CONFIG.
+ */
+void arm_bl2_dyn_cfg_init(void)
+{
+	int err = 0, tb_fw_node;
+	unsigned int i;
+	bl_mem_params_node_t *cfg_mem_params = NULL;
+	uint64_t image_base;
+	uint32_t image_size;
+	const unsigned int config_ids[] = {
+			HW_CONFIG_ID,
+			SOC_FW_CONFIG_ID,
+			NT_FW_CONFIG_ID,
+#ifdef SPD_tspd
+			/* Currently tos_fw_config is only present for TSP */
+			TOS_FW_CONFIG_ID
+#endif
+	};
+
+	if (tb_fw_cfg_dtb == NULL) {
+		VERBOSE("No TB_FW_CONFIG specified\n");
+		return;
+	}
+
+	err = arm_dyn_tb_fw_cfg_init(tb_fw_cfg_dtb, &tb_fw_node);
+	if (err < 0) {
+		ERROR("Invalid TB_FW_CONFIG passed from BL1\n");
+		panic();
+	}
+
+	/* Iterate through all the fw config IDs */
+	for (i = 0; i < ARRAY_SIZE(config_ids); i++) {
+		/* Get the config load address and size from TB_FW_CONFIG */
+		cfg_mem_params = get_bl_mem_params_node(config_ids[i]);
+		if (cfg_mem_params == NULL) {
+			VERBOSE("Couldn't find HW_CONFIG in bl_mem_params_node\n");
+			continue;
+		}
+
+		err = arm_dyn_get_config_load_info(tb_fw_cfg_dtb, tb_fw_node,
+				config_ids[i], &image_base, &image_size);
+		if (err < 0) {
+			VERBOSE("Couldn't find config_id %d load info in TB_FW_CONFIG\n",
+					config_ids[i]);
+			continue;
+		}
+
+		/*
+		 * Do some runtime checks on the load addresses of soc_fw_config,
+		 * tos_fw_config, nt_fw_config. This is not a comprehensive check
+		 * of all invalid addresses but to prevent trivial porting errors.
+		 */
+		if (config_ids[i] != HW_CONFIG_ID) {
+
+			if (check_uptr_overflow(image_base, image_size))
+				continue;
+
+#ifdef	BL31_BASE
+			/* Ensure the configs don't overlap with BL31 */
+			if ((image_base > BL31_BASE) || ((image_base + image_size) > BL31_BASE))
+				continue;
+#endif
+			/* Ensure the configs are loaded in a valid address */
+			if (image_base < ARM_BL_RAM_BASE)
+				continue;
+#ifdef BL32_BASE
+			/*
+			 * If BL32 is present, ensure that the configs don't
+			 * overlap with it.
+			 */
+			if (image_base >= BL32_BASE && image_base <= BL32_LIMIT)
+				continue;
+#endif
+		}
+
+
+		cfg_mem_params->image_info.image_base = (uintptr_t)image_base;
+		cfg_mem_params->image_info.image_max_size = image_size;
+
+		/* Remove the IMAGE_ATTRIB_SKIP_LOADING attribute from HW_CONFIG node */
+		cfg_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING;
+	}
+
+#if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH)
+	uint32_t disable_auth = 0;
+
+	err = arm_dyn_get_disable_auth(tb_fw_cfg_dtb, tb_fw_node,
+					&disable_auth);
+	if (err < 0)
+		return;
+
+	if (disable_auth == 1)
+		dyn_disable_auth();
+#endif
+}
diff --git a/plat/arm/common/arm_dyn_cfg_helpers.c b/plat/arm/common/arm_dyn_cfg_helpers.c
new file mode 100644
index 0000000..36d37f8
--- /dev/null
+++ b/plat/arm/common/arm_dyn_cfg_helpers.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <common/desc_image_load.h>
+#include <common/fdt_wrappers.h>
+#include <plat/arm/common/arm_dyn_cfg_helpers.h>
+#include <plat/arm/common/plat_arm.h>
+
+#define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr"
+#define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"
+
+typedef struct config_load_info_prop {
+	unsigned int config_id;
+	const char *config_addr;
+	const char *config_max_size;
+} config_load_info_prop_t;
+
+static const config_load_info_prop_t prop_names[] = {
+	{HW_CONFIG_ID, "hw_config_addr", "hw_config_max_size"},
+	{SOC_FW_CONFIG_ID, "soc_fw_config_addr", "soc_fw_config_max_size"},
+	{TOS_FW_CONFIG_ID, "tos_fw_config_addr", "tos_fw_config_max_size"},
+	{NT_FW_CONFIG_ID, "nt_fw_config_addr", "nt_fw_config_max_size"}
+};
+
+/*******************************************************************************
+ * Helper to read the load information corresponding to the `config_id` in
+ * TB_FW_CONFIG. This function expects the following properties to be defined :
+ *	<config>_addr		size : 2 cells
+ *	<config>_max_size	size : 1 cell
+ *
+ * Arguments:
+ *	void *dtb		 - pointer to the TB_FW_CONFIG in memory
+ *	int node		 - The node offset to appropriate node in the
+ *					 DTB.
+ *	unsigned int config_id	 - The configuration id
+ *	uint64_t *config_addr	 - Returns the `config` load address if read
+ *					 is successful.
+ *	uint32_t *config_size	 - Returns the `config` size if read is
+ *					 successful.
+ *
+ * Returns 0 on success and -1 on error.
+ ******************************************************************************/
+int arm_dyn_get_config_load_info(void *dtb, int node, unsigned int config_id,
+		uint64_t *config_addr, uint32_t *config_size)
+{
+	int err;
+	unsigned int i;
+
+	assert(dtb != NULL);
+	assert(config_addr != NULL);
+	assert(config_size != NULL);
+
+	for (i = 0; i < ARRAY_SIZE(prop_names); i++) {
+		if (prop_names[i].config_id == config_id)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(prop_names)) {
+		WARN("Invalid config id %d\n", config_id);
+		return -1;
+	}
+
+	/* Check if the pointer to DT is correct */
+	assert(fdt_check_header(dtb) == 0);
+
+	/* Assert the node offset point to "arm,tb_fw" compatible property */
+	assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"));
+
+	err = fdtw_read_cells(dtb, node, prop_names[i].config_addr, 2,
+				(void *) config_addr);
+	if (err < 0) {
+		WARN("Read cell failed for %s\n", prop_names[i].config_addr);
+		return -1;
+	}
+
+	err = fdtw_read_cells(dtb, node, prop_names[i].config_max_size, 1,
+				(void *) config_size);
+	if (err < 0) {
+		WARN("Read cell failed for %s\n", prop_names[i].config_max_size);
+		return -1;
+	}
+
+	VERBOSE("Dyn cfg: Read config_id %d load info from TB_FW_CONFIG 0x%llx 0x%x\n",
+				config_id, (unsigned long long)*config_addr, *config_size);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Helper to read the `disable_auth` property in config DTB. This function
+ * expects the following properties to be present in the config DTB.
+ *	name : disable_auth		size : 1 cell
+ *
+ * Arguments:
+ *	void *dtb		 - pointer to the TB_FW_CONFIG in memory
+ *	int node		 - The node offset to appropriate node in the
+ *				   DTB.
+ *	uint64_t *disable_auth	 - The value of `disable_auth` property on
+ *				   successful read. Must be 0 or 1.
+ *
+ * Returns 0 on success and -1 on error.
+ ******************************************************************************/
+int arm_dyn_get_disable_auth(void *dtb, int node, uint32_t *disable_auth)
+{
+	int err;
+
+	assert(dtb != NULL);
+	assert(disable_auth != NULL);
+
+	/* Check if the pointer to DT is correct */
+	assert(fdt_check_header(dtb) == 0);
+
+	/* Assert the node offset point to "arm,tb_fw" compatible property */
+	assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"));
+
+	/* Locate the disable_auth cell and read the value */
+	err = fdtw_read_cells(dtb, node, "disable_auth", 1, disable_auth);
+	if (err < 0) {
+		WARN("Read cell failed for `disable_auth`\n");
+		return -1;
+	}
+
+	/* Check if the value is boolean */
+	if ((*disable_auth != 0U) && (*disable_auth != 1U)) {
+		WARN("Invalid value for `disable_auth` cell %d\n", *disable_auth);
+		return -1;
+	}
+
+	VERBOSE("Dyn cfg: `disable_auth` cell found with value = %d\n",
+					*disable_auth);
+	return 0;
+}
+
+/*******************************************************************************
+ * Validate the tb_fw_config is a valid DTB file and returns the node offset
+ * to "arm,tb_fw" property.
+ * Arguments:
+ *	void *dtb - pointer to the TB_FW_CONFIG in memory
+ *	int *node - Returns the node offset to "arm,tb_fw" property if found.
+ *
+ * Returns 0 on success and -1 on error.
+ ******************************************************************************/
+int arm_dyn_tb_fw_cfg_init(void *dtb, int *node)
+{
+	assert(dtb != NULL);
+	assert(node != NULL);
+
+	/* Check if the pointer to DT is correct */
+	if (fdt_check_header(dtb) != 0) {
+		WARN("Invalid DTB file passed as TB_FW_CONFIG\n");
+		return -1;
+	}
+
+	/* Assert the node offset point to "arm,tb_fw" compatible property */
+	*node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw");
+	if (*node < 0) {
+		WARN("The compatible property `arm,tb_fw` not found in the config\n");
+		return -1;
+	}
+
+	VERBOSE("Dyn cfg: Found \"arm,tb_fw\" in the config\n");
+	return 0;
+}
+
+/*
+ * Reads and returns the Mbed TLS shared heap information from the DTB.
+ * This function is supposed to be called *only* when a DTB is present.
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ *	0 = success
+ *	-1 = error. In this case the values of heap_addr, heap_size should be
+ *	    considered as garbage by the caller.
+ */
+int arm_get_dtb_mbedtls_heap_info(void *dtb, void **heap_addr,
+	size_t *heap_size)
+{
+	int err, dtb_root;
+
+	/* Verify the DTB is valid and get the root node */
+	err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
+	if (err < 0) {
+		ERROR("Invalid TB_FW_CONFIG. Cannot retrieve Mbed TLS heap information from DTB\n");
+		return -1;
+	}
+
+	/* Retrieve the Mbed TLS heap details from the DTB */
+	err = fdtw_read_cells(dtb, dtb_root,
+		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, heap_addr);
+	if (err < 0) {
+		ERROR("Error while reading %s from DTB\n",
+			DTB_PROP_MBEDTLS_HEAP_ADDR);
+		return -1;
+	}
+	err = fdtw_read_cells(dtb, dtb_root,
+		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, heap_size);
+	if (err < 0) {
+		ERROR("Error while reading %s from DTB\n",
+			DTB_PROP_MBEDTLS_HEAP_SIZE);
+		return -1;
+	}
+	return 0;
+}
+
+
+/*
+ * This function writes the Mbed TLS heap address and size in the DTB. When it
+ * is called, it is guaranteed that a DTB is available. However it is not
+ * guaranteed that the shared Mbed TLS heap implementation is used. Thus we
+ * return error code from here and it's the responsibility of the caller to
+ * determine the action upon error.
+ *
+ * This function is supposed to be called only by BL1.
+ *
+ * Returns:
+ *	0 = success
+ *	1 = error
+ */
+int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size)
+{
+	int err, dtb_root;
+
+	/*
+	 * Verify that the DTB is valid, before attempting to write to it,
+	 * and get the DTB root node.
+	 */
+	err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
+	if (err < 0) {
+		ERROR("Invalid TB_FW_CONFIG loaded. Unable to get root node\n");
+		return -1;
+	}
+
+	/*
+	 * Write the heap address and size in the DTB.
+	 *
+	 * NOTE: The variables heap_addr and heap_size are corrupted
+	 * by the "fdtw_write_inplace_cells" function. After the
+	 * function calls they must NOT be reused.
+	 */
+	err = fdtw_write_inplace_cells(dtb, dtb_root,
+		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr);
+	if (err < 0) {
+		ERROR("Unable to write DTB property %s\n",
+			DTB_PROP_MBEDTLS_HEAP_ADDR);
+		return -1;
+	}
+
+	err = fdtw_write_inplace_cells(dtb, dtb_root,
+		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size);
+	if (err < 0) {
+		ERROR("Unable to write DTB property %s\n",
+			DTB_PROP_MBEDTLS_HEAP_SIZE);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/plat/arm/common/arm_err.c b/plat/arm/common/arm_err.c
new file mode 100644
index 0000000..f80ba78
--- /dev/null
+++ b/plat/arm/common/arm_err.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+void __dead2 plat_error_handler(int err)
+{
+	plat_arm_error_handler(err);
+}
diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c
new file mode 100644
index 0000000..80a845f
--- /dev/null
+++ b/plat/arm/common/arm_gicv2.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv2.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv2 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_gic_driver_init
+#pragma weak plat_arm_gic_init
+#pragma weak plat_arm_gic_cpuif_enable
+#pragma weak plat_arm_gic_cpuif_disable
+#pragma weak plat_arm_gic_pcpu_init
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t arm_interrupt_props[] = {
+	PLAT_ARM_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+	PLAT_ARM_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+static const gicv2_driver_data_t arm_gic_data = {
+	.gicd_base = PLAT_ARM_GICD_BASE,
+	.gicc_base = PLAT_ARM_GICC_BASE,
+	.interrupt_props = arm_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/******************************************************************************
+ * ARM common helper to initialize the GICv2 only driver.
+ *****************************************************************************/
+void plat_arm_gic_driver_init(void)
+{
+	gicv2_driver_init(&arm_gic_data);
+}
+
+void plat_arm_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_enable(void)
+{
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_disable(void)
+{
+	gicv2_cpuif_disable();
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the per cpu distributor interface in GICv2
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Stubs for Redistributor power management. Although GICv2 doesn't have
+ * Redistributor interface, these are provided for the sake of uniform GIC API
+ *****************************************************************************/
+void plat_arm_gic_redistif_on(void)
+{
+	return;
+}
+
+void plat_arm_gic_redistif_off(void)
+{
+	return;
+}
+
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend.
+ * The normal world currently takes care of saving and restoring the GICv2
+ * registers due to legacy reasons. Hence we just initialize the Distributor
+ * on resume from system suspend.
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+	return;
+}
+
+void plat_arm_gic_resume(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+}
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
new file mode 100644
index 0000000..7f4957f
--- /dev/null
+++ b/plat/arm/common/arm_gicv3.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_arm_gic_driver_init
+#pragma weak plat_arm_gic_init
+#pragma weak plat_arm_gic_cpuif_enable
+#pragma weak plat_arm_gic_cpuif_disable
+#pragma weak plat_arm_gic_pcpu_init
+#pragma weak plat_arm_gic_redistif_on
+#pragma weak plat_arm_gic_redistif_off
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t arm_interrupt_props[] = {
+	PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
+	PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory. The `volatile`
+ * is used to prevent the compiler from removing the gicv3 contexts even
+ * though the DEFINE_LOAD_SYM_ADDR creates a dummy reference to it.
+ */
+static volatile gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+static volatile gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+
+/* Define accessor function to get reference to the GICv3 context */
+DEFINE_LOAD_SYM_ADDR(rdist_ctx)
+DEFINE_LOAD_SYM_ADDR(dist_ctx)
+
+/*
+ * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
+ * to core position.
+ *
+ * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
+ * values read from GICR_TYPER don't have an MT field. To reuse the same
+ * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
+ * that read from GICR_TYPER.
+ *
+ * Assumptions:
+ *
+ *   - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
+ *   - No CPUs implemented in the system use affinity level 3.
+ */
+static unsigned int arm_gicv3_mpidr_hash(u_register_t mpidr)
+{
+	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+	return plat_arm_calc_core_pos(mpidr);
+}
+
+static const gicv3_driver_data_t arm_gic_data __unused = {
+	.gicd_base = PLAT_ARM_GICD_BASE,
+	.gicr_base = PLAT_ARM_GICR_BASE,
+	.interrupt_props = arm_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = arm_gicv3_mpidr_hash
+};
+
+void __init plat_arm_gic_driver_init(void)
+{
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \
+	(defined(__aarch64__) && defined(IMAGE_BL31))
+	gicv3_driver_init(&arm_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void __init plat_arm_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_arm_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to initialize the per-cpu redistributor interface in GICv3
+ *****************************************************************************/
+void plat_arm_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_arm_gic_redistif_on(void)
+{
+	gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_arm_gic_redistif_off(void)
+{
+	gicv3_rdistif_off(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * ARM common helper to save & restore the GICv3 on resume from system suspend
+ *****************************************************************************/
+void plat_arm_gic_save(void)
+{
+	gicv3_redist_ctx_t * const rdist_context =
+			(gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
+	gicv3_dist_ctx_t * const dist_context =
+			(gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
+
+	/*
+	 * If an ITS is available, save its context before
+	 * the Redistributor using:
+	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
+	 * Additionally, an implementation-defined sequence may
+	 * be required to save the whole ITS state.
+	 */
+
+	/*
+	 * Save the GIC Redistributors and ITS contexts before the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to save the context of the CPU that is issuing
+	 * the SYSTEM SUSPEND call, i.e. the current CPU.
+	 */
+	gicv3_rdistif_save(plat_my_core_pos(), rdist_context);
+
+	/* Save the GIC Distributor context */
+	gicv3_distif_save(dist_context);
+
+	/*
+	 * From here, all the components of the GIC can be safely powered down
+	 * as long as there is an alternate way to handle wakeup interrupt
+	 * sources.
+	 */
+}
+
+void plat_arm_gic_resume(void)
+{
+	const gicv3_redist_ctx_t *rdist_context =
+			(gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx);
+	const gicv3_dist_ctx_t *dist_context =
+			(gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx);
+
+	/* Restore the GIC Distributor context */
+	gicv3_distif_init_restore(dist_context);
+
+	/*
+	 * Restore the GIC Redistributor and ITS contexts after the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to restore the context of the CPU that issued
+	 * the SYSTEM SUSPEND call.
+	 */
+	gicv3_rdistif_init_restore(plat_my_core_pos(), rdist_context);
+
+	/*
+	 * If an ITS is available, restore its context after
+	 * the Redistributor using:
+	 * gicv3_its_restore(gits_base, &its_ctx[i])
+	 * An implementation-defined sequence may be required to
+	 * restore the whole ITS state. The ITS must also be
+	 * re-enabled after this sequence has been executed.
+	 */
+}
diff --git a/plat/arm/common/arm_image_load.c b/plat/arm/common/arm_image_load.c
new file mode 100644
index 0000000..2faaa76
--- /dev/null
+++ b/plat/arm/common/arm_image_load.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#pragma weak plat_flush_next_bl_params
+#pragma weak plat_get_bl_image_load_info
+#pragma weak plat_get_next_bl_params
+
+static bl_params_t *next_bl_params_cpy_ptr;
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	assert(next_bl_params_cpy_ptr != NULL);
+
+	flush_bl_params_desc_args(bl_mem_params_desc_ptr,
+		bl_mem_params_desc_num,
+		next_bl_params_cpy_ptr);
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+struct bl_load_info *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * ARM helper function to return the list of executable images.Since the default
+ * descriptors are allocated within BL2 RW memory, this prevents BL31/BL32
+ * overlay of BL2 memory. Hence this function also copies the descriptors to a
+ * pre-allocated memory indicated by ARM_BL2_MEM_DESC_BASE.
+ ******************************************************************************/
+struct bl_params *arm_get_next_bl_params(void)
+{
+	bl_mem_params_node_t *bl2_mem_params_descs_cpy
+			= (bl_mem_params_node_t *)ARM_BL2_MEM_DESC_BASE;
+	const bl_params_t *next_bl_params;
+
+	next_bl_params_cpy_ptr =
+		(bl_params_t *)(ARM_BL2_MEM_DESC_BASE +
+		(bl_mem_params_desc_num * sizeof(bl_mem_params_node_t)));
+
+	/*
+	 * Copy the memory descriptors to ARM_BL2_MEM_DESC_BASE area.
+	 */
+	(void) memcpy(bl2_mem_params_descs_cpy, bl_mem_params_desc_ptr,
+		(bl_mem_params_desc_num * sizeof(bl_mem_params_node_t)));
+
+	/*
+	 * Modify the global 'bl_mem_params_desc_ptr' to point to the
+	 * copied location.
+	 */
+	bl_mem_params_desc_ptr = bl2_mem_params_descs_cpy;
+
+	next_bl_params = get_next_bl_params_from_mem_params_desc();
+	assert(next_bl_params != NULL);
+
+	/*
+	 * Copy 'next_bl_params' to the reserved location after the copied
+	 * memory descriptors.
+	 */
+	(void) memcpy(next_bl_params_cpy_ptr, next_bl_params,
+						(sizeof(bl_params_t)));
+
+	populate_next_bl_params_config(next_bl_params_cpy_ptr);
+
+	return next_bl_params_cpy_ptr;
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images
+ ******************************************************************************/
+struct bl_params *plat_get_next_bl_params(void)
+{
+	return arm_get_next_bl_params();
+}
+
diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c
new file mode 100644
index 0000000..fc1eb49
--- /dev/null
+++ b/plat/arm/common/arm_io_storage.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_image_package.h>
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = PLAT_ARM_FIP_BASE,
+	.length = PLAT_ARM_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static const io_uuid_spec_t tb_fw_config_uuid_spec = {
+	.uuid = UUID_TB_FW_CONFIG,
+};
+
+static const io_uuid_spec_t hw_config_uuid_spec = {
+	.uuid = UUID_HW_CONFIG,
+};
+
+static const io_uuid_spec_t soc_fw_config_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONFIG,
+};
+
+static const io_uuid_spec_t tos_fw_config_uuid_spec = {
+	.uuid = UUID_TOS_FW_CONFIG,
+};
+
+static const io_uuid_spec_t nt_fw_config_uuid_spec = {
+	.uuid = UUID_NT_FW_CONFIG,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+/* By default, ARM platforms load images from the FIP */
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+	[TB_FW_CONFIG_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_config_uuid_spec,
+		open_fip
+	},
+	[HW_CONFIG_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&hw_config_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_CONFIG_ID] = {
+			&fip_dev_handle,
+			(uintptr_t)&soc_fw_config_uuid_spec,
+			open_fip
+	},
+	[TOS_FW_CONFIG_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_config_uuid_spec,
+		open_fip
+	},
+	[NT_FW_CONFIG_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_config_uuid_spec,
+		open_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		open_fip
+	},
+	[SCP_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[SCP_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		open_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_arm_io_setup
+#pragma weak plat_arm_get_alt_image_source
+
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+
+void arm_io_setup(void)
+{
+	int io_result;
+
+	io_result = register_io_dev_fip(&fip_dev_con);
+	assert(io_result == 0);
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&memmap_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+void plat_arm_io_setup(void)
+{
+	arm_io_setup();
+}
+
+int plat_arm_get_alt_image_source(
+	unsigned int image_id __unused,
+	uintptr_t *dev_handle __unused,
+	uintptr_t *image_spec __unused)
+{
+	/* By default do not try an alternative */
+	return -ENOENT;
+}
+
+/* Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	if (result == 0) {
+		*image_spec = policy->image_spec;
+		*dev_handle = *(policy->dev_handle);
+	} else {
+		VERBOSE("Trying alternative IO\n");
+		result = plat_arm_get_alt_image_source(image_id, dev_handle,
+						       image_spec);
+	}
+
+	return result;
+}
+
+/*
+ * See if a Firmware Image Package is available,
+ * by checking if TOC is valid or not.
+ */
+int arm_io_is_toc_valid(void)
+{
+	int result;
+
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+
+	return (result == 0);
+}
+
diff --git a/plat/arm/common/arm_nor_psci_mem_protect.c b/plat/arm/common/arm_nor_psci_mem_protect.c
new file mode 100644
index 0000000..b9181eb
--- /dev/null
+++ b/plat/arm/common/arm_nor_psci_mem_protect.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/cfi/v2m_flash.h>
+#include <lib/psci/psci.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * DRAM1 is used also to load the NS boot loader. For this reason we
+ * cannot clear the full DRAM1, because in that case we would clear
+ * the NS images (especially for RESET_TO_BL31 and RESET_TO_SPMIN cases).
+ * For this reason we reserve 64 MB for the NS images and protect the RAM
+ * until the end of DRAM1.
+ * We limit the size of DRAM2 to 1 GB to avoid big delays while booting
+ */
+#define DRAM1_NS_IMAGE_LIMIT  (PLAT_ARM_NS_IMAGE_BASE + (32 << TWO_MB_SHIFT))
+#define DRAM1_PROTECTED_SIZE  (ARM_NS_DRAM1_END+1u - DRAM1_NS_IMAGE_LIMIT)
+
+static mem_region_t arm_ram_ranges[] = {
+	{DRAM1_NS_IMAGE_LIMIT, DRAM1_PROTECTED_SIZE},
+#ifdef __aarch64__
+	{ARM_DRAM2_BASE, 1u << ONE_GB_SHIFT},
+#endif
+};
+
+/*******************************************************************************
+ * Function that reads the content of the memory protect variable that
+ * enables clearing of non secure memory when system boots. This variable
+ * should be stored in a secure NVRAM.
+ ******************************************************************************/
+int arm_psci_read_mem_protect(int *enabled)
+{
+	int tmp;
+
+	tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
+	*enabled = (tmp == 1) ? 1 : 0;
+	return 0;
+}
+
+/*******************************************************************************
+ * Function that writes the content of the memory protect variable that
+ * enables overwritten of non secure memory when system boots.
+ ******************************************************************************/
+int arm_nor_psci_write_mem_protect(int val)
+{
+	unsigned long enable = (val != 0) ? 1UL : 0UL;
+
+	if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+		ERROR("unlocking memory protect variable\n");
+		return -1;
+	}
+
+	if (enable == 1UL) {
+		/*
+		 * If we want to write a value different than 0
+		 * then we have to erase the full block because
+		 * otherwise we cannot ensure that the value programmed
+		 * into the flash is going to be the same than the value
+		 * requested by the caller
+		 */
+		if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) {
+			ERROR("erasing block containing memory protect variable\n");
+			return -1;
+		}
+	}
+
+	if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) {
+		ERROR("programming memory protection variable\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*******************************************************************************
+ * Function used for required psci operations performed when
+ * system boots
+ ******************************************************************************/
+/*
+ * PLAT_MEM_PROTECT_VA_FRAME is a address specifically
+ * selected in a way that is not needed an additional
+ * translation table for memprotect. It happens because
+ * we use a chunk of size 2MB and it means that it can
+ * be mapped in a level 2 table and the level 2 table
+ * for 0xc0000000 is already used and the entry for
+ * 0xc0000000 is not used.
+ */
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+void arm_nor_psci_do_dyn_mem_protect(void)
+{
+	int enable;
+
+	arm_psci_read_mem_protect(&enable);
+	if (enable == 0)
+		return;
+
+	INFO("PSCI: Overwriting non secure memory\n");
+	clear_map_dyn_mem_regions(arm_ram_ranges,
+				  ARRAY_SIZE(arm_ram_ranges),
+				  PLAT_ARM_MEM_PROTEC_VA_FRAME,
+				  1 << TWO_MB_SHIFT);
+}
+#endif
+
+/*******************************************************************************
+ * Function used for required psci operations performed when
+ * system boots and dynamic memory is not used.
+ ******************************************************************************/
+void arm_nor_psci_do_static_mem_protect(void)
+{
+	int enable;
+
+	(void) arm_psci_read_mem_protect(&enable);
+	if (enable == 0)
+		return;
+
+	INFO("PSCI: Overwriting non secure memory\n");
+	clear_mem_regions(arm_ram_ranges,
+			  ARRAY_SIZE(arm_ram_ranges));
+	(void) arm_nor_psci_write_mem_protect(0);
+}
+
+/*******************************************************************************
+ * Function that checks if a region is protected by the memory protect
+ * mechanism
+ ******************************************************************************/
+int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length)
+{
+	return mem_region_in_array_chk(arm_ram_ranges,
+				       ARRAY_SIZE(arm_ram_ranges),
+				       base, length);
+}
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
new file mode 100644
index 0000000..c95f452
--- /dev/null
+++ b/plat/arm/common/arm_pm.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Allow ARM Standard platforms to override these functions */
+#pragma weak plat_arm_program_trusted_mailbox
+
+#if !ARM_RECOM_STATE_ID_ENC
+/*******************************************************************************
+ * ARM standard platform handler called to check the validity of the power state
+ * parameter.
+ ******************************************************************************/
+int arm_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state)
+{
+	unsigned int pstate = psci_get_pstate_type(power_state);
+	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	unsigned int i;
+
+	assert(req_state != NULL);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != ARM_PWR_LVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[ARM_PWR_LVL0] =
+					ARM_LOCAL_STATE_RET;
+	} else {
+		for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					ARM_LOCAL_STATE_OFF;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state) != 0U)
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+#else
+/*******************************************************************************
+ * ARM standard platform handler called to check the validity of the power
+ * state parameter. The power state parameter has to be a composite power
+ * state.
+ ******************************************************************************/
+int arm_validate_power_state(unsigned int power_state,
+				psci_power_state_t *req_state)
+{
+	unsigned int state_id;
+	int i;
+
+	assert(req_state != NULL);
+
+	/*
+	 *  Currently we are using a linear search for finding the matching
+	 *  entry in the idle power state array. This can be made a binary
+	 *  search if the number of entries justify the additional complexity.
+	 */
+	for (i = 0; !!arm_pm_idle_states[i]; i++) {
+		if (power_state == arm_pm_idle_states[i])
+			break;
+	}
+
+	/* Return error if entry not found in the idle state array */
+	if (!arm_pm_idle_states[i])
+		return PSCI_E_INVALID_PARAMS;
+
+	i = 0;
+	state_id = psci_get_pstate_id(power_state);
+
+	/* Parse the State ID and populate the state info parameter */
+	while (state_id) {
+		req_state->pwr_domain_state[i++] = state_id &
+						ARM_LOCAL_PSTATE_MASK;
+		state_id >>= ARM_LOCAL_PSTATE_WIDTH;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+#endif /* __ARM_RECOM_STATE_ID_ENC__ */
+
+/*******************************************************************************
+ * ARM standard platform handler called to check the validity of the non secure
+ * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise.
+ ******************************************************************************/
+int arm_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint <
+			(ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) {
+		return 0;
+	}
+#ifdef __aarch64__
+	if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint <
+			(ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) {
+		return 0;
+	}
+#endif
+
+	return -1;
+}
+
+int arm_validate_psci_entrypoint(uintptr_t entrypoint)
+{
+	return (arm_validate_ns_entrypoint(entrypoint) == 0) ? PSCI_E_SUCCESS :
+		PSCI_E_INVALID_ADDRESS;
+}
+
+/******************************************************************************
+ * Helper function to save the platform state before a system suspend. Save the
+ * state of the system components which are not in the Always ON power domain.
+ *****************************************************************************/
+void arm_system_pwr_domain_save(void)
+{
+	/* Assert system power domain is available on the platform */
+	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+
+	plat_arm_gic_save();
+
+	/*
+	 * Unregister console now so that it is not registered for a second
+	 * time during resume.
+	 */
+	arm_console_runtime_end();
+
+	/*
+	 * All the other peripheral which are configured by ARM TF are
+	 * re-initialized on resume from system suspend. Hence we
+	 * don't save their state here.
+	 */
+}
+
+/******************************************************************************
+ * Helper function to resume the platform from system suspend. Reinitialize
+ * the system components which are not in the Always ON power domain.
+ * TODO: Unify the platform setup when waking up from cold boot and system
+ * resume in arm_bl31_platform_setup().
+ *****************************************************************************/
+void arm_system_pwr_domain_resume(void)
+{
+	/* Initialize the console */
+	arm_console_runtime_init();
+
+	/* Assert system power domain is available on the platform */
+	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+
+	plat_arm_gic_resume();
+
+	plat_arm_security_setup();
+	arm_configure_sys_timer();
+}
+
+/*******************************************************************************
+ * ARM platform function to program the mailbox for a cpu before it is released
+ * from reset. This function assumes that the Trusted mail box base is within
+ * the ARM_SHARED_RAM region
+ ******************************************************************************/
+void plat_arm_program_trusted_mailbox(uintptr_t address)
+{
+	uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE;
+
+	*mailbox = address;
+
+	/*
+	 * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within
+	 * ARM_SHARED_RAM region.
+	 */
+	assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) &&
+		((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= \
+				(ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE)));
+}
+
+/*******************************************************************************
+ * The ARM Standard platform definition of platform porting API
+ * `plat_setup_psci_ops`.
+ ******************************************************************************/
+int __init plat_setup_psci_ops(uintptr_t sec_entrypoint,
+				const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops);
+
+	/* Setup mailbox with entry point. */
+	plat_arm_program_trusted_mailbox(sec_entrypoint);
+	return 0;
+}
diff --git a/plat/arm/common/arm_sip_svc.c b/plat/arm/common/arm_sip_svc.c
new file mode 100644
index 0000000..3d308a3
--- /dev/null
+++ b/plat/arm/common/arm_sip_svc.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/pmf/pmf.h>
+#include <plat/arm/common/arm_sip_svc.h>
+#include <plat/arm/common/plat_arm.h>
+#include <tools_share/uuid.h>
+
+/* ARM SiP Service UUID */
+DEFINE_SVC_UUID2(arm_sip_svc_uid,
+	0x556d75e2, 0x6033, 0xb54b, 0xb5, 0x75,
+	0x62, 0x79, 0xfd, 0x11, 0x37, 0xff);
+
+static int arm_sip_setup(void)
+{
+	if (pmf_setup() != 0)
+		return 1;
+	return 0;
+}
+
+/*
+ * This function handles ARM defined SiP Calls
+ */
+static uintptr_t arm_sip_handler(unsigned int smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	int call_count = 0;
+
+	/*
+	 * Dispatch PMF calls to PMF SMC handler and return its return
+	 * value
+	 */
+	if (is_pmf_fid(smc_fid)) {
+		return pmf_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+				handle, flags);
+	}
+
+	switch (smc_fid) {
+	case ARM_SIP_SVC_EXE_STATE_SWITCH: {
+		u_register_t pc;
+
+		/* Allow calls from non-secure only */
+		if (!is_caller_non_secure(flags))
+			SMC_RET1(handle, STATE_SW_E_DENIED);
+
+		/* Validate supplied entry point */
+		pc = (u_register_t) ((x1 << 32) | (uint32_t) x2);
+		if (arm_validate_ns_entrypoint(pc) != 0)
+			SMC_RET1(handle, STATE_SW_E_PARAM);
+
+		/*
+		 * Pointers used in execution state switch are all 32 bits wide
+		 */
+		return (uintptr_t) arm_execution_state_switch(smc_fid,
+				(uint32_t) x1, (uint32_t) x2, (uint32_t) x3,
+				(uint32_t) x4, handle);
+		}
+
+	case ARM_SIP_SVC_CALL_COUNT:
+		/* PMF calls */
+		call_count += PMF_NUM_SMC_CALLS;
+
+		/* State switch call */
+		call_count += 1;
+
+		SMC_RET1(handle, call_count);
+
+	case ARM_SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, arm_sip_svc_uid);
+
+	case ARM_SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, ARM_SIP_SVC_VERSION_MAJOR, ARM_SIP_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented ARM SiP Service Call: 0x%x \n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+}
+
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	arm_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	arm_sip_setup,
+	arm_sip_handler
+);
diff --git a/plat/arm/common/arm_topology.c b/plat/arm/common/arm_topology.c
new file mode 100644
index 0000000..37047bc
--- /dev/null
+++ b/plat/arm/common/arm_topology.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * This function validates an MPIDR by checking whether it falls within the
+ * acceptable bounds. An error code (-1) is returned if an incorrect mpidr
+ * is passed.
+ ******************************************************************************/
+int arm_check_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+	uint64_t valid_mask;
+
+#if ARM_PLAT_MT
+	unsigned int pe_id;
+
+	valid_mask = ~(MPIDR_AFFLVL_MASK |
+			(MPIDR_AFFLVL_MASK << MPIDR_AFF1_SHIFT) |
+			(MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT));
+	cluster_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	pe_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+#else
+	valid_mask = ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK);
+	cluster_id = (unsigned int) ((mpidr >> MPIDR_AFF1_SHIFT) &
+						MPIDR_AFFLVL_MASK);
+	cpu_id = (unsigned int) ((mpidr >> MPIDR_AFF0_SHIFT) &
+						MPIDR_AFFLVL_MASK);
+#endif /* ARM_PLAT_MT */
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if ((mpidr & valid_mask) != 0U)
+		return -1;
+
+	if (cluster_id >= PLAT_ARM_CLUSTER_COUNT)
+		return -1;
+
+	/* Validate cpu_id by checking whether it represents a CPU in
+	   one of the two clusters present on the platform. */
+	if (cpu_id >= plat_arm_get_cluster_core_count(mpidr))
+		return -1;
+
+#if ARM_PLAT_MT
+	if (pe_id >= plat_arm_get_cpu_pe_count(mpidr))
+		return -1;
+#endif /* ARM_PLAT_MT */
+
+	return 0;
+}
diff --git a/plat/arm/common/arm_tzc400.c b/plat/arm/common/arm_tzc400.c
new file mode 100644
index 0000000..34e650f
--- /dev/null
+++ b/plat/arm/common/arm_tzc400.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc400.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_arm_security_setup
+
+
+/*******************************************************************************
+ * Initialize the TrustZone Controller for ARM standard platforms.
+ * When booting an EL3 payload, this is simplified: we configure region 0 with
+ * secure access only and do not enable any other region.
+ ******************************************************************************/
+void arm_tzc400_setup(const arm_tzc_regions_info_t *tzc_regions)
+{
+#ifndef EL3_PAYLOAD_BASE
+	unsigned int region_index = 1U;
+	const arm_tzc_regions_info_t *p;
+	const arm_tzc_regions_info_t init_tzc_regions[] = {
+		ARM_TZC_REGIONS_DEF,
+		{0}
+	};
+#endif
+
+	INFO("Configuring TrustZone Controller\n");
+
+	tzc400_init(PLAT_ARM_TZC_BASE);
+
+	/* Disable filters. */
+	tzc400_disable_filters();
+
+#ifndef EL3_PAYLOAD_BASE
+	if (tzc_regions == NULL)
+		p = init_tzc_regions;
+	else
+		p = tzc_regions;
+
+	/* Region 0 set to no access by default */
+	tzc400_configure_region0(TZC_REGION_S_NONE, 0);
+
+	/* Rest Regions set according to tzc_regions array */
+	for (; p->base != 0ULL; p++) {
+		tzc400_configure_region(PLAT_ARM_TZC_FILTERS, region_index,
+			p->base, p->end, p->sec_attr, p->nsaid_permissions);
+		region_index++;
+	}
+
+	INFO("Total %u regions set.\n", region_index);
+
+#else /* if defined(EL3_PAYLOAD_BASE) */
+
+	/* Allow Secure and Non-secure access to DRAM for EL3 payloads */
+	tzc400_configure_region0(TZC_REGION_S_RDWR, PLAT_ARM_TZC_NS_DEV_ACCESS);
+
+#endif /* EL3_PAYLOAD_BASE */
+
+	/*
+	 * Raise an exception if a NS device tries to access secure memory
+	 * TODO: Add interrupt handling support.
+	 */
+	tzc400_set_action(TZC_ACTION_ERR);
+
+	/* Enable filters. */
+	tzc400_enable_filters();
+}
+
+void plat_arm_security_setup(void)
+{
+	arm_tzc400_setup(NULL);
+}
diff --git a/plat/arm/common/arm_tzc_dmc500.c b/plat/arm/common/arm_tzc_dmc500.c
new file mode 100644
index 0000000..e9f897f
--- /dev/null
+++ b/plat/arm/common/arm_tzc_dmc500.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc500.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*******************************************************************************
+ * Initialize the DMC500-TrustZone Controller for ARM standard platforms.
+ * When booting an EL3 payload, this is simplified: we configure region 0 with
+ * secure access only and do not enable any other region.
+ ******************************************************************************/
+void arm_tzc_dmc500_setup(tzc_dmc500_driver_data_t *plat_driver_data,
+			const arm_tzc_regions_info_t *tzc_regions)
+{
+#ifndef EL3_PAYLOAD_BASE
+	unsigned int region_index = 1U;
+	const arm_tzc_regions_info_t *p;
+	const arm_tzc_regions_info_t init_tzc_regions[] = {
+		ARM_TZC_REGIONS_DEF,
+		{0}
+	};
+#endif
+
+	assert(plat_driver_data);
+
+	INFO("Configuring DMC-500 TZ Settings\n");
+
+	tzc_dmc500_driver_init(plat_driver_data);
+
+#ifndef EL3_PAYLOAD_BASE
+	if (tzc_regions == NULL)
+		p = init_tzc_regions;
+	else
+		p = tzc_regions;
+
+	/* Region 0 set to no access by default */
+	tzc_dmc500_configure_region0(TZC_REGION_S_NONE, 0);
+
+	/* Rest Regions set according to tzc_regions array */
+	for (; p->base != 0ULL; p++) {
+		tzc_dmc500_configure_region(region_index, p->base, p->end,
+					    p->sec_attr, p->nsaid_permissions);
+		region_index++;
+	}
+
+	INFO("Total %u regions set.\n", region_index);
+
+#else
+	/* Allow secure access only to DRAM for EL3 payloads */
+	tzc_dmc500_configure_region0(TZC_REGION_S_RDWR, 0);
+#endif
+	/*
+	 * Raise an exception if a NS device tries to access secure memory
+	 * TODO: Add interrupt handling support.
+	 */
+	tzc_dmc500_set_action(TZC_ACTION_RV_LOWERR);
+
+	/*
+	 * Flush the configuration settings to have an affect. Validate
+	 * flush by checking FILTER_EN is set on region 1 attributes
+	 * register.
+	 */
+	tzc_dmc500_config_complete();
+
+	/*
+	 * Wait for the flush to complete.
+	 * TODO: Have a timeout for this loop
+	 */
+	while (tzc_dmc500_verify_complete())
+		;
+}
diff --git a/plat/arm/common/execution_state_switch.c b/plat/arm/common/execution_state_switch.c
new file mode 100644
index 0000000..00ac16e
--- /dev/null
+++ b/plat/arm/common/execution_state_switch.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+#include <lib/utils.h>
+#include <plat/arm/common/arm_sip_svc.h>
+#include <plat/arm/common/plat_arm.h>
+#include <smccc_helpers.h>
+
+/*
+ * Handle SMC from a lower exception level to switch its execution state
+ * (either from AArch64 to AArch32, or vice versa).
+ *
+ * smc_fid:
+ *	SMC function ID - either ARM_SIP_SVC_STATE_SWITCH_64 or
+ *	ARM_SIP_SVC_STATE_SWITCH_32.
+ * pc_hi, pc_lo:
+ *	PC upon re-entry to the calling exception level; width dependent on the
+ *	calling exception level.
+ * cookie_hi, cookie_lo:
+ *	Opaque pointer pairs received from the caller to pass it back, upon
+ *	re-entry.
+ * handle:
+ *	Handle to saved context.
+ */
+int arm_execution_state_switch(unsigned int smc_fid,
+		uint32_t pc_hi,
+		uint32_t pc_lo,
+		uint32_t cookie_hi,
+		uint32_t cookie_lo,
+		void *handle)
+{
+	/* Execution state can be switched only if EL3 is AArch64 */
+#ifdef __aarch64__
+	bool caller_64, thumb = false, from_el2;
+	unsigned int el, endianness;
+	u_register_t spsr, pc, scr, sctlr;
+	entry_point_info_t ep;
+	cpu_context_t *ctx = (cpu_context_t *) handle;
+	el3_state_t *el3_ctx = get_el3state_ctx(ctx);
+
+	/* That the SMC originated from NS is already validated by the caller */
+
+	/*
+	 * Disallow state switch if any of the secondaries have been brought up.
+	 */
+	if (psci_secondaries_brought_up() != 0)
+		goto exec_denied;
+
+	spsr = read_ctx_reg(el3_ctx, CTX_SPSR_EL3);
+	caller_64 = (GET_RW(spsr) == MODE_RW_64);
+
+	if (caller_64) {
+		/*
+		 * If the call originated from AArch64, expect 32-bit pointers when
+		 * switching to AArch32.
+		 */
+		if ((pc_hi != 0U) || (cookie_hi != 0U))
+			goto invalid_param;
+
+		pc = pc_lo;
+
+		/* Instruction state when entering AArch32 */
+		thumb = (pc & 1U) != 0U;
+	} else {
+		/* Construct AArch64 PC */
+		pc = (((u_register_t) pc_hi) << 32) | pc_lo;
+	}
+
+	/* Make sure PC is 4-byte aligned, except for Thumb */
+	if (((pc & 0x3U) != 0U) && !thumb)
+		goto invalid_param;
+
+	/*
+	 * EL3 controls register width of the immediate lower EL only. Expect
+	 * this request from EL2/Hyp unless:
+	 *
+	 * - EL2 is not implemented;
+	 * - EL2 is implemented, but was disabled. This can be inferred from
+	 *   SCR_EL3.HCE.
+	 */
+	from_el2 = caller_64 ? (GET_EL(spsr) == MODE_EL2) :
+		(GET_M32(spsr) == MODE32_hyp);
+	scr = read_ctx_reg(el3_ctx, CTX_SCR_EL3);
+	if (!from_el2) {
+		/* The call is from NS privilege level other than HYP */
+
+		/*
+		 * Disallow switching state if there's a Hypervisor in place;
+		 * this request must be taken up with the Hypervisor instead.
+		 */
+		if ((scr & SCR_HCE_BIT) != 0U)
+			goto exec_denied;
+	}
+
+	/*
+	 * Return to the caller using the same endianness. Extract
+	 * endianness bit from the respective system control register
+	 * directly.
+	 */
+	sctlr = from_el2 ? read_sctlr_el2() : read_sctlr_el1();
+	endianness = ((sctlr & SCTLR_EE_BIT) != 0U) ? 1U : 0U;
+
+	/* Construct SPSR for the exception state we're about to switch to */
+	if (caller_64) {
+		unsigned long long impl;
+
+		/*
+		 * Switching from AArch64 to AArch32. Ensure this CPU implements
+		 * the target EL in AArch32.
+		 */
+		impl = from_el2 ? el_implemented(2) : el_implemented(1);
+		if (impl != EL_IMPL_A64_A32)
+			goto exec_denied;
+
+		/* Return to the equivalent AArch32 privilege level */
+		el = from_el2 ? MODE32_hyp : MODE32_svc;
+		spsr = SPSR_MODE32((u_register_t) el,
+				thumb ? SPSR_T_THUMB : SPSR_T_ARM,
+				endianness, DISABLE_ALL_EXCEPTIONS);
+	} else {
+		/*
+		 * Switching from AArch32 to AArch64. Since it's not possible to
+		 * implement an EL as AArch32-only (from which this call was
+		 * raised), it's safe to assume AArch64 is also implemented.
+		 */
+		el = from_el2 ? MODE_EL2 : MODE_EL1;
+		spsr = SPSR_64((u_register_t) el, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS);
+	}
+
+	/*
+	 * Use the context management library to re-initialize the existing
+	 * context with the execution state flipped. Since the library takes
+	 * entry_point_info_t pointer as the argument, construct a dummy one
+	 * with PC, state width, endianness, security etc. appropriately set.
+	 * Other entries in the entry point structure are irrelevant for
+	 * purpose.
+	 */
+	zeromem(&ep, sizeof(ep));
+	ep.pc = pc;
+	ep.spsr = (uint32_t) spsr;
+	SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1,
+			((unsigned int) ((endianness != 0U) ? EP_EE_BIG :
+				EP_EE_LITTLE)
+			 | NON_SECURE | EP_ST_DISABLE));
+
+	/*
+	 * Re-initialize the system register context, and exit EL3 as if for the
+	 * first time. State switch is effectively a soft reset of the
+	 * calling EL.
+	 */
+	cm_init_my_context(&ep);
+	cm_prepare_el3_exit(NON_SECURE);
+
+	/*
+	 * State switch success. The caller of SMC wouldn't see the SMC
+	 * returning. Instead, execution starts at the supplied entry point,
+	 * with context pointers populated in registers 0 and 1.
+	 */
+	SMC_RET2(handle, cookie_hi, cookie_lo);
+
+invalid_param:
+	SMC_RET1(handle, STATE_SW_E_PARAM);
+
+exec_denied:
+#endif /* __aarch64__ */
+	/* State switch denied */
+	SMC_RET1(handle, STATE_SW_E_DENIED);
+}
diff --git a/plat/arm/common/sp_min/arm_sp_min.mk b/plat/arm/common/sp_min/arm_sp_min.mk
new file mode 100644
index 0000000..dbd451c
--- /dev/null
+++ b/plat/arm/common/sp_min/arm_sp_min.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SP MIN source files common to ARM standard platforms
+
+# Skip building BL1, BL2 and BL2U if RESET_TO_SP_MIN flag is set.
+ifeq (${RESET_TO_SP_MIN},1)
+    BL1_SOURCES =
+    BL2_SOURCES =
+    BL2U_SOURCES =
+endif
+
+BL32_SOURCES		+=	plat/arm/common/arm_pm.c			\
+				plat/arm/common/arm_topology.c			\
+				plat/arm/common/sp_min/arm_sp_min_setup.c	\
+				plat/common/aarch32/platform_mp_stack.S		\
+				plat/common/plat_psci_common.c
diff --git a/plat/arm/common/sp_min/arm_sp_min_setup.c b/plat/arm/common/sp_min/arm_sp_min_setup.c
new file mode 100644
index 0000000..bb69914
--- /dev/null
+++ b/plat/arm/common/sp_min/arm_sp_min_setup.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl32/sp_min/platform_sp_min.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+static entry_point_info_t bl33_image_ep_info;
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak sp_min_platform_setup
+#pragma weak sp_min_plat_arch_setup
+#pragma weak plat_arm_sp_min_early_platform_setup
+
+#define MAP_BL_SP_MIN_TOTAL	MAP_REGION_FLAT(			\
+					BL32_BASE,			\
+					BL32_END - BL32_BASE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * Check that BL32_BASE is above ARM_TB_FW_CONFIG_LIMIT. The reserved page
+ * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2.
+ */
+CASSERT(BL32_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_bl32_base_overflows);
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for the
+ * security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = &bl33_image_ep_info;
+
+	/*
+	 * None of the images on the ARM development platforms can have 0x0
+	 * as the entrypoint
+	 */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Utility function to perform early platform setup.
+ ******************************************************************************/
+void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config,
+			uintptr_t hw_config, void *plat_params_from_bl2)
+{
+	/* Initialize the console to provide early debug support */
+	arm_console_boot_init();
+
+#if RESET_TO_SP_MIN
+	/* There are no parameters from BL2 if SP_MIN is a reset vector */
+	assert(from_bl2 == NULL);
+	assert(plat_params_from_bl2 == NULL);
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell SP_MIN where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = arm_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+# if ARM_LINUX_KERNEL_AS_BL33
+	/*
+	 * According to the file ``Documentation/arm/Booting`` of the Linux
+	 * kernel tree, Linux expects:
+	 * r0 = 0
+	 * r1 = machine type number, optional in DT-only platforms (~0 if so)
+	 * r2 = Physical address of the device tree blob
+	 */
+	bl33_image_ep_info.args.arg0 = 0U;
+	bl33_image_ep_info.args.arg1 = ~0U;
+	bl33_image_ep_info.args.arg2 = (u_register_t)ARM_PRELOADED_DTB_BASE;
+# endif
+
+#else /* RESET_TO_SP_MIN */
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL33_IMAGE_ID) {
+			bl33_image_ep_info = *bl_params->ep_info;
+			break;
+		}
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0)
+		panic();
+
+#endif /* RESET_TO_SP_MIN */
+
+}
+
+/*******************************************************************************
+ * Default implementation for sp_min_platform_setup2() for ARM platforms
+ ******************************************************************************/
+void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_arm_interconnect_init();
+
+	/*
+	 * Enable Interconnect coherency for the primary CPU's cluster.
+	 * Earlier bootloader stages might already do this (e.g. Trusted
+	 * Firmware's BL1 does it) but we can't assume so. There is no harm in
+	 * executing this code twice anyway.
+	 * Platform specific PSCI code will enable coherency for other
+	 * clusters.
+	 */
+	plat_arm_interconnect_enter_coherency();
+}
+
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	plat_arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3);
+}
+
+/*******************************************************************************
+ * Perform any SP_MIN platform runtime setup prior to SP_MIN exit.
+ * Common to ARM standard platforms.
+ ******************************************************************************/
+void arm_sp_min_plat_runtime_setup(void)
+{
+	/* Initialize the runtime console */
+	arm_console_runtime_init();
+}
+
+/*******************************************************************************
+ * Perform platform specific setup for SP_MIN
+ ******************************************************************************/
+void sp_min_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	plat_arm_gic_driver_init();
+	plat_arm_gic_init();
+
+	/*
+	 * Do initial security configuration to allow DRAM/device access
+	 * (if earlier BL has not already done so).
+	 */
+#if RESET_TO_SP_MIN
+	plat_arm_security_setup();
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	arm_nor_psci_do_dyn_mem_protect();
+#endif /* PLAT_ARM_MEM_PROT_ADDR */
+
+#endif
+
+	/* Enable and initialize the System level generic timer */
+#ifdef ARM_SYS_CNTCTL_BASE
+	mmio_write_32(ARM_SYS_CNTCTL_BASE + CNTCR_OFF,
+			CNTCR_FCREQ(0U) | CNTCR_EN);
+#endif
+#ifdef ARM_SYS_TIMCTL_BASE
+	/* Allow access to the System counter timer module */
+	arm_configure_sys_timer();
+#endif
+	/* Initialize power controller before setting up topology */
+	plat_arm_pwrc_setup();
+}
+
+void sp_min_plat_runtime_setup(void)
+{
+	arm_sp_min_plat_runtime_setup();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this only initializes the MMU
+ ******************************************************************************/
+void sp_min_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_BL_SP_MIN_TOTAL,
+		ARM_MAP_BL_RO,
+#if USE_COHERENT_MEM
+		ARM_MAP_BL_COHERENT_RAM,
+#endif
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+
+	enable_mmu_svc_mon(0);
+}
diff --git a/plat/arm/common/tsp/arm_tsp.mk b/plat/arm/common/tsp/arm_tsp.mk
new file mode 100644
index 0000000..4ad77c6
--- /dev/null
+++ b/plat/arm/common/tsp/arm_tsp.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TSP source files common to ARM standard platforms
+BL32_SOURCES		+=	plat/arm/common/arm_topology.c			\
+				plat/arm/common/tsp/arm_tsp_setup.c		\
+				plat/common/aarch64/platform_mp_stack.S
diff --git a/plat/arm/common/tsp/arm_tsp_setup.c b/plat/arm/common/tsp/arm_tsp_setup.c
new file mode 100644
index 0000000..aefdf89
--- /dev/null
+++ b/plat/arm/common/tsp/arm_tsp_setup.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl32/tsp/platform_tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak tsp_early_platform_setup
+#pragma weak tsp_platform_setup
+#pragma weak tsp_plat_arch_setup
+
+#define MAP_BL_TSP_TOTAL	MAP_REGION_FLAT(			\
+					BL32_BASE,			\
+					BL32_END - BL32_BASE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+static console_pl011_t arm_tsp_runtime_console;
+
+void arm_tsp_early_platform_setup(void)
+{
+	/*
+	 * Initialize a different console than already in use to display
+	 * messages from TSP
+	 */
+	int rc = console_pl011_register(PLAT_ARM_TSP_UART_BASE,
+					PLAT_ARM_TSP_UART_CLK_IN_HZ,
+					ARM_CONSOLE_BAUDRATE,
+					&arm_tsp_runtime_console);
+	if (rc == 0)
+		panic();
+
+	console_set_scope(&arm_tsp_runtime_console.console,
+			  CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+}
+
+void tsp_early_platform_setup(void)
+{
+	arm_tsp_early_platform_setup();
+}
+
+/*******************************************************************************
+ * Perform platform specific setup placeholder
+ ******************************************************************************/
+void tsp_platform_setup(void)
+{
+	plat_arm_gic_driver_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the MMU
+ ******************************************************************************/
+void tsp_plat_arch_setup(void)
+{
+#if USE_COHERENT_MEM
+	/* Ensure ARM platforms don't use coherent memory in TSP */
+	assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U);
+#endif
+
+	const mmap_region_t bl_regions[] = {
+		MAP_BL_TSP_TOTAL,
+		ARM_MAP_BL_RO,
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+	enable_mmu_el1(0);
+}
diff --git a/plat/arm/css/common/aarch32/css_helpers.S b/plat/arm/css/common/aarch32/css_helpers.S
new file mode 100644
index 0000000..d47e13d
--- /dev/null
+++ b/plat/arm/css/common/aarch32/css_helpers.S
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+	.weak	plat_secondary_cold_boot_setup
+	.weak	plat_get_my_entrypoint
+	.globl	css_calc_core_pos_swap_cluster
+	.weak	plat_is_my_cpu_primary
+
+	/* ---------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup(void);
+	 * In the normal boot flow, cold-booting secondary
+	 * CPUs is not yet implemented and they panic.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* TODO: Implement secondary CPU cold boot setup on CSS platforms */
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and a warm
+	 * boot. On CSS platforms, this distinction is based on the contents of
+	 * the Trusted Mailbox. It is initialised to zero by the SCP before the
+	 * AP cores are released from reset. Therefore, a zero mailbox means
+	 * it's a cold reset.
+	 *
+	 * This functions returns the contents of the mailbox, i.e.:
+	 *  - 0 for a cold boot;
+	 *  - the warm boot entrypoint for a warm boot.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	ldr	r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE
+	ldr	r0, [r0]
+	bx	lr
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------------
+	 * unsigned int css_calc_core_pos_swap_cluster(u_register_t mpidr)
+	 * Utility function to calculate the core position by
+	 * swapping the cluster order. This is necessary in order to
+	 * match the format of the boot information passed by the SCP
+	 * and read in plat_is_my_cpu_primary below.
+	 * -----------------------------------------------------------
+	 */
+func css_calc_core_pos_swap_cluster
+	and	r1, r0, #MPIDR_CPU_MASK
+	and	r0, r0, #MPIDR_CLUSTER_MASK
+	eor	r0, r0, #(1 << MPIDR_AFFINITY_BITS)  // swap cluster order
+	add	r0, r1, r0, LSR #6
+	bx	lr
+endfunc css_calc_core_pos_swap_cluster
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu (applicable ony after a cold boot)
+	 * -----------------------------------------------------
+	 */
+#if CSS_USE_SCMI_SDS_DRIVER
+func plat_is_my_cpu_primary
+	mov	r10, lr
+	bl	plat_my_core_pos
+	mov	r4, r0
+	bl	sds_get_primary_cpu_id
+	/* Check for error */
+	mov	r1, #0xffffffff
+	cmp	r0, r1
+	beq	1f
+	cmp	r0, r4
+	moveq	r0, #1
+	movne	r0, #0
+	bx	r10
+1:
+	no_ret	plat_panic_handler
+endfunc plat_is_my_cpu_primary
+#else
+func plat_is_my_cpu_primary
+	mov	r10, lr
+	bl	plat_my_core_pos
+	ldr	r1, =SCP_BOOT_CFG_ADDR
+	ldr	r1, [r1]
+	ubfx	r1, r1, #PLAT_CSS_PRIMARY_CPU_SHIFT, \
+			#PLAT_CSS_PRIMARY_CPU_BIT_WIDTH
+	cmp	r0, r1
+	moveq	r0, #1
+	movne	r0, #0
+	bx	r10
+endfunc plat_is_my_cpu_primary
+#endif
diff --git a/plat/arm/css/common/aarch64/css_helpers.S b/plat/arm/css/common/aarch64/css_helpers.S
new file mode 100644
index 0000000..01669be
--- /dev/null
+++ b/plat/arm/css/common/aarch64/css_helpers.S
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+	.weak	plat_secondary_cold_boot_setup
+	.weak	plat_get_my_entrypoint
+	.globl	css_calc_core_pos_swap_cluster
+	.weak	plat_is_my_cpu_primary
+
+	/* ---------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup(void);
+	 *
+	 * In the normal boot flow, cold-booting secondary CPUs is not yet
+	 * implemented and they panic.
+	 *
+	 * When booting an EL3 payload, secondary CPUs are placed in a holding
+	 * pen, waiting for their mailbox to be populated. Note that all CPUs
+	 * share the same mailbox ; therefore, populating it will release all
+	 * CPUs from their holding pen. If finer-grained control is needed then
+	 * this should be handled in the code that secondary CPUs jump to.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+#ifndef EL3_PAYLOAD_BASE
+	/* TODO: Implement secondary CPU cold boot setup on CSS platforms */
+cb_panic:
+	b	cb_panic
+#else
+	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
+
+	/* Wait until the mailbox gets populated */
+poll_mailbox:
+	ldr	x1, [x0]
+	cbz	x1, 1f
+	br	x1
+1:
+	wfe
+	b	poll_mailbox
+#endif /* EL3_PAYLOAD_BASE */
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and a warm
+	 * boot. On CSS platforms, this distinction is based on the contents of
+	 * the Trusted Mailbox. It is initialised to zero by the SCP before the
+	 * AP cores are released from reset. Therefore, a zero mailbox means
+	 * it's a cold reset.
+	 *
+	 * This functions returns the contents of the mailbox, i.e.:
+	 *  - 0 for a cold boot;
+	 *  - the warm boot entrypoint for a warm boot.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
+	ldr	x0, [x0]
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------------
+	 * unsigned int css_calc_core_pos_swap_cluster(u_register_t mpidr)
+	 * Utility function to calculate the core position by
+	 * swapping the cluster order. This is necessary in order to
+	 * match the format of the boot information passed by the SCP
+	 * and read in plat_is_my_cpu_primary below.
+	 * -----------------------------------------------------------
+	 */
+func css_calc_core_pos_swap_cluster
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	eor	x0, x0, #(1 << MPIDR_AFFINITY_BITS)  // swap cluster order
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc css_calc_core_pos_swap_cluster
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu (applicable ony after a cold boot)
+	 * -----------------------------------------------------
+	 */
+#if CSS_USE_SCMI_SDS_DRIVER
+func plat_is_my_cpu_primary
+	mov	x9, x30
+	bl	plat_my_core_pos
+	mov	x4, x0
+	bl	sds_get_primary_cpu_id
+	/* Check for error */
+	mov	x1, #0xffffffff
+	cmp	x0, x1
+	b.eq	1f
+	cmp	x0, x4
+	cset	w0, eq
+	ret	x9
+1:
+	no_ret	plat_panic_handler
+endfunc plat_is_my_cpu_primary
+#else
+func plat_is_my_cpu_primary
+	mov	x9, x30
+	bl	plat_my_core_pos
+	mov_imm	x1, SCP_BOOT_CFG_ADDR
+	ldr	x1, [x1]
+	ubfx	x1, x1, #PLAT_CSS_PRIMARY_CPU_SHIFT, \
+			#PLAT_CSS_PRIMARY_CPU_BIT_WIDTH
+	cmp	x0, x1
+	cset	w0, eq
+	ret	x9
+endfunc plat_is_my_cpu_primary
+#endif
diff --git a/plat/arm/css/common/css_bl1_setup.c b/plat/arm/css/common/css_bl1_setup.c
new file mode 100644
index 0000000..596cc3d
--- /dev/null
+++ b/plat/arm/css/common/css_bl1_setup.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/soc/common/soc_css.h>
+#include <plat/common/platform.h>
+
+void bl1_platform_setup(void)
+{
+	arm_bl1_platform_setup();
+	/*
+	 * Do ARM CSS SoC security setup.
+	 * BL1 needs to enable normal world access to memory.
+	 */
+	soc_css_security_setup();
+}
+
diff --git a/plat/arm/css/common/css_bl2_setup.c b/plat/arm/css/common/css_bl2_setup.c
new file mode 100644
index 0000000..002c6eb
--- /dev/null
+++ b/plat/arm/css/common/css_bl2_setup.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/* Weak definition may be overridden in specific CSS based platform */
+#pragma weak plat_arm_bl2_handle_scp_bl2
+
+/*******************************************************************************
+ * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
+ * Return 0 on success, -1 otherwise.
+ ******************************************************************************/
+int plat_arm_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	int ret;
+
+	INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
+
+	ret = css_scp_boot_image_xfer((void *)scp_bl2_image_info->image_base,
+		scp_bl2_image_info->image_size);
+
+	if (ret == 0)
+		ret = css_scp_boot_ready();
+
+	if (ret == 0)
+		INFO("BL2: SCP_BL2 transferred to SCP\n");
+	else
+		ERROR("BL2: SCP_BL2 transfer failure\n");
+
+	return ret;
+}
+
+#if !CSS_USE_SCMI_SDS_DRIVER
+# if defined(EL3_PAYLOAD_BASE) || JUNO_AARCH32_EL3_RUNTIME
+
+/*
+ * We need to override some of the platform functions when booting an EL3
+ * payload or SP_MIN on Juno AArch32. This needs to be done only for
+ * SCPI/BOM SCP systems as in case of SDS, the structures remain in memory and
+ * don't need to be overwritten.
+ */
+
+static unsigned int scp_boot_config;
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1);
+
+	/* Save SCP Boot config before it gets overwritten by SCP_BL2 loading */
+	scp_boot_config = mmio_read_32(SCP_BOOT_CFG_ADDR);
+	VERBOSE("BL2: Saved SCP Boot config = 0x%x\n", scp_boot_config);
+}
+
+void bl2_platform_setup(void)
+{
+	arm_bl2_platform_setup();
+
+	/*
+	 * Before releasing the AP cores out of reset, the SCP writes some data
+	 * at the beginning of the Trusted SRAM. It is is overwritten before
+	 * reaching this function. We need to restore this data, as if the
+	 * target had just come out of reset. This implies:
+	 *  - zeroing the first 128 bytes of Trusted SRAM using zeromem instead
+	 *    of zero_normalmem since this is device memory.
+	 *  - restoring the SCP boot configuration.
+	 */
+	VERBOSE("BL2: Restoring SCP reset data in Trusted SRAM\n");
+	zeromem((void *) ARM_SHARED_RAM_BASE, 128);
+	mmio_write_32(SCP_BOOT_CFG_ADDR, scp_boot_config);
+}
+
+# endif /* EL3_PAYLOAD_BASE */
+
+#endif /* CSS_USE_SCMI_SDS_DRIVER */
diff --git a/plat/arm/css/common/css_bl2u_setup.c b/plat/arm/css/common/css_bl2u_setup.c
new file mode 100644
index 0000000..15cf4f6
--- /dev/null
+++ b/plat/arm/css/common/css_bl2u_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+/* Weak definition may be overridden in specific CSS based platform */
+#pragma weak bl2u_plat_handle_scp_bl2u
+
+/* Data structure which holds the SCP_BL2U image info for BL2U */
+static image_info_t scp_bl2u_image_info;
+
+/*******************************************************************************
+ * BL1 can pass platform dependent information to BL2U in x1.
+ * In case of ARM CSS platforms x1 contains SCP_BL2U image info.
+ * In case of ARM FVP platforms x1 is not used.
+ * In both cases, x0 contains the extents of the memory available to BL2U
+ ******************************************************************************/
+void bl2u_early_platform_setup(meminfo_t *mem_layout, void *plat_info)
+{
+	if (!plat_info)
+		panic();
+
+	arm_bl2u_early_platform_setup(mem_layout, plat_info);
+
+	scp_bl2u_image_info = *(image_info_t *)plat_info;
+}
+
+/*******************************************************************************
+ * Transfer SCP_BL2U from Trusted RAM using the SCP Download protocol.
+ ******************************************************************************/
+int bl2u_plat_handle_scp_bl2u(void)
+{
+	int ret;
+
+	INFO("BL2U: Initiating SCP_BL2U transfer to SCP\n");
+
+	ret = css_scp_boot_image_xfer((void *)scp_bl2u_image_info.image_base,
+		scp_bl2u_image_info.image_size);
+
+	if (ret == 0)
+		ret = css_scp_boot_ready();
+
+	if (ret == 0)
+		INFO("BL2U: SCP_BL2U transferred to SCP\n");
+	else
+		ERROR("BL2U: SCP_BL2U transfer failure\n");
+
+	return ret;
+}
diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk
new file mode 100644
index 0000000..2fbbe45
--- /dev/null
+++ b/plat/arm/css/common/css_common.mk
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+# By default, SCP images are needed by CSS platforms.
+CSS_LOAD_SCP_IMAGES	?=	1
+
+# By default, SCMI driver is disabled for CSS platforms
+CSS_USE_SCMI_SDS_DRIVER	?=	0
+
+PLAT_INCLUDES		+=	-Iinclude/plat/arm/css/common/aarch64
+
+
+PLAT_BL_COMMON_SOURCES	+=	plat/arm/css/common/${ARCH}/css_helpers.S
+
+BL1_SOURCES		+=	plat/arm/css/common/css_bl1_setup.c
+
+BL2_SOURCES		+=	plat/arm/css/common/css_bl2_setup.c
+
+BL2U_SOURCES		+=	plat/arm/css/common/css_bl2u_setup.c
+
+BL31_SOURCES		+=	plat/arm/css/common/css_pm.c			\
+				plat/arm/css/common/css_topology.c
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},0)
+BL31_SOURCES		+=	drivers/arm/css/mhu/css_mhu.c			\
+				drivers/arm/css/scp/css_pm_scpi.c		\
+				drivers/arm/css/scpi/css_scpi.c
+else
+BL31_SOURCES		+=	drivers/arm/css/mhu/css_mhu_doorbell.c		\
+				drivers/arm/css/scmi/scmi_ap_core_proto.c	\
+				drivers/arm/css/scmi/scmi_common.c		\
+				drivers/arm/css/scmi/scmi_pwr_dmn_proto.c	\
+				drivers/arm/css/scmi/scmi_sys_pwr_proto.c	\
+				drivers/arm/css/scp/css_pm_scmi.c
+endif
+
+# Process CSS_LOAD_SCP_IMAGES flag
+$(eval $(call assert_boolean,CSS_LOAD_SCP_IMAGES))
+$(eval $(call add_define,CSS_LOAD_SCP_IMAGES))
+
+ifeq (${CSS_LOAD_SCP_IMAGES},1)
+  NEED_SCP_BL2 := yes
+  ifneq (${TRUSTED_BOARD_BOOT},0)
+    $(eval $(call TOOL_ADD_IMG,scp_bl2u,--scp-fwu-cfg,FWU_))
+  endif
+
+  ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
+    BL2U_SOURCES	+=	drivers/arm/css/scp/css_sds.c			\
+				drivers/arm/css/sds/sds.c
+
+    BL2_SOURCES		+=	drivers/arm/css/scp/css_sds.c			\
+				drivers/arm/css/sds/sds.c
+  else
+    BL2U_SOURCES	+=	drivers/arm/css/mhu/css_mhu.c			\
+				drivers/arm/css/scp/css_bom_bootloader.c	\
+				drivers/arm/css/scpi/css_scpi.c
+
+    BL2_SOURCES		+=	drivers/arm/css/mhu/css_mhu.c			\
+				drivers/arm/css/scp/css_bom_bootloader.c	\
+				drivers/arm/css/scpi/css_scpi.c
+    # Enable option to detect whether the SCP ROM firmware in use predates version
+    # 1.7.0 and therefore, is incompatible.
+    CSS_DETECT_PRE_1_7_0_SCP	:=	1
+
+    # Process CSS_DETECT_PRE_1_7_0_SCP flag
+    $(eval $(call assert_boolean,CSS_DETECT_PRE_1_7_0_SCP))
+    $(eval $(call add_define,CSS_DETECT_PRE_1_7_0_SCP))
+  endif
+endif
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
+  PLAT_BL_COMMON_SOURCES	+=	drivers/arm/css/sds/${ARCH}/sds_helpers.S
+endif
+
+# Process CSS_USE_SCMI_SDS_DRIVER flag
+$(eval $(call assert_boolean,CSS_USE_SCMI_SDS_DRIVER))
+$(eval $(call add_define,CSS_USE_SCMI_SDS_DRIVER))
+
+# Process CSS_NON_SECURE_UART flag
+# This undocumented build option is only to enable debug access to the UART
+# from non secure code, which is useful on some platforms.
+# Default (obviously) is off.
+CSS_NON_SECURE_UART		:= 0
+$(eval $(call assert_boolean,CSS_NON_SECURE_UART))
+$(eval $(call add_define,CSS_NON_SECURE_UART))
+
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
new file mode 100644
index 0000000..f6fc6aa
--- /dev/null
+++ b/plat/arm/css/common/css_pm.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <lib/cassert.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+
+/* Allow CSS platforms to override `plat_arm_psci_pm_ops` */
+#pragma weak plat_arm_psci_pm_ops
+
+#if ARM_RECOM_STATE_ID_ENC
+/*
+ *  The table storing the valid idle power states. Ensure that the
+ *  array entries are populated in ascending order of state-id to
+ *  enable us to use binary search during power state validation.
+ *  The table must be terminated by a NULL entry.
+ */
+const unsigned int arm_pm_idle_states[] = {
+	/* State-id - 0x001 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN,
+		ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x002 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x022 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+#if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1
+	/* State-id - 0x222 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
+#endif
+	0,
+};
+#endif /* __ARM_RECOM_STATE_ID_ENC__ */
+
+/*
+ * All the power management helpers in this file assume at least cluster power
+ * level is supported.
+ */
+CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1,
+		assert_max_pwr_lvl_supported_mismatch);
+
+/*
+ * Ensure that the PLAT_MAX_PWR_LVL is not greater than CSS_SYSTEM_PWR_DMN_LVL
+ * assumed by the CSS layer.
+ */
+CASSERT(PLAT_MAX_PWR_LVL <= CSS_SYSTEM_PWR_DMN_LVL,
+		assert_max_pwr_lvl_higher_than_css_sys_lvl);
+
+/*******************************************************************************
+ * Handler called when a power domain is about to be turned on. The
+ * level and mpidr determine the affinity instance.
+ ******************************************************************************/
+int css_pwr_domain_on(u_register_t mpidr)
+{
+	css_scp_on(mpidr);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void css_pwr_domain_on_finisher_common(
+		const psci_power_state_t *target_state)
+{
+	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
+
+	/* Enable the gic cpu interface */
+	plat_arm_gic_cpuif_enable();
+
+	/*
+	 * Perform the common cluster specific operations i.e enable coherency
+	 * if this cluster was off.
+	 */
+	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+		plat_arm_interconnect_enter_coherency();
+}
+
+/*******************************************************************************
+ * Handler called when a power level has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from. This handler would never be invoked with
+ * the system power domain uninitialized as either the primary would have taken
+ * care of it as part of cold boot or the first core awakened from system
+ * suspend would have already initialized it.
+ ******************************************************************************/
+void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* Assert that the system power domain need not be initialized */
+	assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_arm_gic_pcpu_init();
+
+	css_pwr_domain_on_finisher_common(target_state);
+}
+
+/*******************************************************************************
+ * Common function called while turning a cpu off or suspending it. It is called
+ * from css_off() or css_suspend() when these functions in turn are called for
+ * power domain at the highest power level which will be powered down. It
+ * performs the actions common to the OFF and SUSPEND calls.
+ ******************************************************************************/
+static void css_power_down_common(const psci_power_state_t *target_state)
+{
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_arm_gic_cpuif_disable();
+
+	/* Cluster is to be turned off, so disable coherency */
+	if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+		plat_arm_interconnect_exit_coherency();
+}
+
+/*******************************************************************************
+ * Handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void css_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
+	css_power_down_common(target_state);
+	css_scp_off(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void css_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	/*
+	 * CSS currently supports retention only at cpu level. Just return
+	 * as nothing is to be done for retention.
+	 */
+	if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
+		return;
+
+
+	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
+	css_power_down_common(target_state);
+
+	/* Perform system domain state saving if issuing system suspend */
+	if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) {
+		arm_system_pwr_domain_save();
+
+		/* Power off the Redistributor after having saved its context */
+		plat_arm_gic_redistif_off();
+	}
+
+	css_scp_suspend(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ ******************************************************************************/
+void css_pwr_domain_suspend_finish(
+				const psci_power_state_t *target_state)
+{
+	/* Return as nothing is to be done on waking up from retention. */
+	if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
+		return;
+
+	/* Perform system domain restore if woken up from system suspend */
+	if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF)
+		/*
+		 * At this point, the Distributor must be powered on to be ready
+		 * to have its state restored. The Redistributor will be powered
+		 * on as part of gicv3_rdistif_init_restore.
+		 */
+		arm_system_pwr_domain_resume();
+
+	css_pwr_domain_on_finisher_common(target_state);
+}
+
+/*******************************************************************************
+ * Handlers to shutdown/reboot the system
+ ******************************************************************************/
+void __dead2 css_system_off(void)
+{
+	css_scp_sys_shutdown();
+}
+
+void __dead2 css_system_reset(void)
+{
+	css_scp_sys_reboot();
+}
+
+/*******************************************************************************
+ * Handler called when the CPU power domain is about to enter standby.
+ ******************************************************************************/
+void css_cpu_standby(plat_local_state_t cpu_state)
+{
+	unsigned int scr;
+
+	assert(cpu_state == ARM_LOCAL_STATE_RET);
+
+	scr = read_scr_el3();
+	/*
+	 * Enable the Non secure interrupt to wake the CPU.
+	 * In GICv3 affinity routing mode, the non secure group1 interrupts use
+	 * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ.
+	 * Enabling both the bits works for both GICv2 mode and GICv3 affinity
+	 * routing mode.
+	 */
+	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+	isb();
+	dsb();
+	wfi();
+
+	/*
+	 * Restore SCR to the original value, synchronisation of scr_el3 is
+	 * done by eret while el3_exit to save some execution cycles.
+	 */
+	write_scr_el3(scr);
+}
+
+/*******************************************************************************
+ * Handler called to return the 'req_state' for system suspend.
+ ******************************************************************************/
+void css_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	/*
+	 * System Suspend is supported only if the system power domain node
+	 * is implemented.
+	 */
+	assert(PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL);
+
+	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
+}
+
+/*******************************************************************************
+ * Handler to query CPU/cluster power states from SCP
+ ******************************************************************************/
+int css_node_hw_state(u_register_t mpidr, unsigned int power_level)
+{
+	return css_scp_get_power_state(mpidr, power_level);
+}
+
+/*
+ * The system power domain suspend is only supported only via
+ * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
+ * will be downgraded to the lower level.
+ */
+static int css_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state)
+{
+	int rc;
+	rc = arm_validate_power_state(power_state, req_state);
+
+	/*
+	 * Ensure that we don't overrun the pwr_domain_state array in the case
+	 * where the platform supported max power level is less than the system
+	 * power level
+	 */
+
+#if (PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL)
+
+	/*
+	 * Ensure that the system power domain level is never suspended
+	 * via PSCI CPU SUSPEND API. Currently system suspend is only
+	 * supported via PSCI SYSTEM SUSPEND API.
+	 */
+
+	req_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] =
+							ARM_LOCAL_STATE_RUN;
+#endif
+
+	return rc;
+}
+
+/*
+ * Custom `translate_power_state_by_mpidr` handler for CSS. Unlike in the
+ * `css_validate_power_state`, we do not downgrade the system power
+ * domain level request in `power_state` as it will be used to query the
+ * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
+ */
+static int css_translate_power_state_by_mpidr(u_register_t mpidr,
+		unsigned int power_state,
+		psci_power_state_t *output_state)
+{
+	return arm_validate_power_state(power_state, output_state);
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+plat_psci_ops_t plat_arm_psci_pm_ops = {
+	.pwr_domain_on		= css_pwr_domain_on,
+	.pwr_domain_on_finish	= css_pwr_domain_on_finish,
+	.pwr_domain_off		= css_pwr_domain_off,
+	.cpu_standby		= css_cpu_standby,
+	.pwr_domain_suspend	= css_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= css_pwr_domain_suspend_finish,
+	.system_off		= css_system_off,
+	.system_reset		= css_system_reset,
+	.validate_power_state	= css_validate_power_state,
+	.validate_ns_entrypoint = arm_validate_psci_entrypoint,
+	.translate_power_state_by_mpidr = css_translate_power_state_by_mpidr,
+	.get_node_hw_state	= css_node_hw_state,
+	.get_sys_suspend_power_state = css_get_sys_suspend_power_state,
+
+#if defined(PLAT_ARM_MEM_PROT_ADDR)
+	.mem_protect_chk	= arm_psci_mem_protect_chk,
+	.read_mem_protect	= arm_psci_read_mem_protect,
+	.write_mem_protect	= arm_nor_psci_write_mem_protect,
+#endif
+#if CSS_USE_SCMI_SDS_DRIVER
+	.system_reset2		= css_system_reset2,
+#endif
+};
diff --git a/plat/arm/css/common/css_topology.c b/plat/arm/css/common/css_topology.c
new file mode 100644
index 0000000..8aca744
--- /dev/null
+++ b/plat/arm/css/common/css_topology.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#if ARM_PLAT_MT
+#pragma weak plat_arm_get_cpu_pe_count
+#endif
+
+/******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is
+ * returned in case the MPIDR is invalid.
+ *****************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	if (arm_check_mpidr(mpidr) == 0) {
+#if ARM_PLAT_MT
+		assert((read_mpidr_el1() & MPIDR_MT_MASK) != 0);
+
+		/*
+		 * The DTB files don't provide the MT bit in the mpidr argument
+		 * so set it manually before calculating core position
+		 */
+		mpidr |= MPIDR_MT_MASK;
+#endif
+		return plat_arm_calc_core_pos(mpidr);
+	}
+	return -1;
+}
+
+#if ARM_PLAT_MT
+/******************************************************************************
+ * This function returns the PE count within the physical cpu corresponding to
+ * `mpidr`. Now one cpu only have one thread, so just return 1.
+ *****************************************************************************/
+unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr)
+{
+	return 1;
+}
+#endif /* ARM_PLAT_MT */
diff --git a/plat/arm/css/common/sp_min/css_sp_min.mk b/plat/arm/css/common/sp_min/css_sp_min.mk
new file mode 100644
index 0000000..6523a16
--- /dev/null
+++ b/plat/arm/css/common/sp_min/css_sp_min.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# SP MIN source files common to CSS platforms
+BL32_SOURCES		+=	plat/arm/css/common/css_pm.c			\
+				plat/arm/css/common/css_topology.c
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},0)
+BL32_SOURCES		+=	drivers/arm/css/mhu/css_mhu.c			\
+				drivers/arm/css/scp/css_pm_scpi.c		\
+				drivers/arm/css/scpi/css_scpi.c
+else
+BL32_SOURCES		+=	drivers/arm/css/mhu/css_mhu_doorbell.c		\
+				drivers/arm/css/scp/css_pm_scmi.c		\
+				drivers/arm/css/scmi/scmi_common.c		\
+				drivers/arm/css/scmi/scmi_pwr_dmn_proto.c	\
+				drivers/arm/css/scmi/scmi_sys_pwr_proto.c
+endif
diff --git a/plat/arm/css/sgi/aarch64/sgi_helper.S b/plat/arm/css/sgi/aarch64/sgi_helper.S
new file mode 100644
index 0000000..b80903d
--- /dev/null
+++ b/plat/arm/css/sgi/aarch64/sgi_helper.S
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cortex_a75.h>
+#include <neoverse_n1.h>
+#include <cpu_macros.S>
+
+	.globl	plat_arm_calc_core_pos
+	.globl	plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Helper function to calculate the core position.
+	 * (ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) +
+	 * (CPUId * CSS_SGI_MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER + CPUId) *
+	 * CSS_SGI_MAX_PE_PER_CPU) + ThreadId
+	 * ------------------------------------------------------
+	 */
+
+func plat_arm_calc_core_pos
+	mov	x3, x0
+
+	/*
+	 * The MT bit in MPIDR is always set for SGI platforms
+	 * and the affinity level 0 corresponds to thread affinity level.
+	 */
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx    x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx    x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx    x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov     x4, #CSS_SGI_MAX_CPUS_PER_CLUSTER
+	madd    x1, x2, x4, x1
+	mov     x5, #CSS_SGI_MAX_PE_PER_CPU
+	madd    x0, x1, x5, x0
+	ret
+endfunc plat_arm_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the CPU MIDR and disable power down bit for
+	 * that CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	jump_if_cpu_midr CORTEX_A75_MIDR, A75
+	jump_if_cpu_midr NEOVERSE_N1_MIDR, N1
+	ret
+
+	/* -----------------------------------------------------
+	 * Disable CPU power down bit in power control register
+	 * -----------------------------------------------------
+	 */
+A75:
+	mrs	x0, CORTEX_A75_CPUPWRCTLR_EL1
+	bic	x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A75_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+
+N1:
+	mrs	x0, NEOVERSE_N1_CPUPWRCTLR_EL1
+	bic	x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK
+	msr	NEOVERSE_N1_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc plat_reset_handler
diff --git a/plat/arm/css/sgi/include/plat_macros.S b/plat/arm/css/sgi/include/plat_macros.S
new file mode 100644
index 0000000..521bcc3
--- /dev/null
+++ b/plat/arm/css/sgi/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <css_macros.S>
+
+/* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant platform registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ *
+ * There are currently no platform specific regs
+ * to print.
+ * ---------------------------------------------
+ */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/css/sgi/include/sgi_base_platform_def.h b/plat/arm/css/sgi/include/sgi_base_platform_def.h
new file mode 100644
index 0000000..a9cc852
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_base_platform_def.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_BASE_PLATFORM_DEF_H
+#define SGI_BASE_PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/arm/board/common/board_css_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_CORE_COUNT		(PLAT_ARM_CLUSTER_COUNT *	\
+					CSS_SGI_MAX_CPUS_PER_CLUSTER * \
+					CSS_SGI_MAX_PE_PER_CPU)
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE	0x00040000	/* 256 KB */
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if defined(IMAGE_BL31)
+# if ENABLE_SPM
+#  define PLAT_ARM_MMAP_ENTRIES		9
+#  define MAX_XLAT_TABLES		7
+#  define PLAT_SP_IMAGE_MMAP_REGIONS	7
+#  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
+# else
+#  define PLAT_ARM_MMAP_ENTRIES		8
+#  define MAX_XLAT_TABLES		5
+# endif
+#elif defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		5
+#elif !USE_ROMLIB
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		5
+#else
+# define PLAT_ARM_MMAP_ENTRIES		12
+# define MAX_XLAT_TABLES		6
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_ARM_MAX_BL1_RW_SIZE	0xB000
+
+/*
+ * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page
+ */
+
+#if USE_ROMLIB
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	0x1000
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	0xe000
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	0
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	0
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#if TRUSTED_BOARD_BOOT
+# define PLAT_ARM_MAX_BL2_SIZE		0x1D000
+#else
+# define PLAT_ARM_MAX_BL2_SIZE		0x11000
+#endif
+
+/*
+ * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
+ * calculated using the current BL31 PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW
+ */
+#define PLAT_ARM_MAX_BL31_SIZE		0x3B000
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x440
+# endif
+#elif defined(IMAGE_BL2)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL2U)
+# define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+# if ENABLE_SPM
+#  define PLATFORM_STACK_SIZE 0x500
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+
+#define PLAT_ARM_NSTIMER_FRAME_ID	0
+
+#define PLAT_ARM_TRUSTED_ROM_BASE	0x0
+#define PLAT_ARM_TRUSTED_ROM_SIZE	0x00080000	/* 512KB */
+
+#define PLAT_ARM_NSRAM_BASE		0x06000000
+#define PLAT_ARM_NSRAM_SIZE		0x00080000	/* 512KB */
+
+#define PLAT_ARM_G1S_IRQ_PROPS(grp)	CSS_G1S_IRQ_PROPS(grp)
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+#define CSS_SGI_DEVICE_BASE	(0x20000000)
+#define CSS_SGI_DEVICE_SIZE	(0x20000000)
+#define CSS_SGI_MAP_DEVICE	MAP_REGION_FLAT(		\
+					CSS_SGI_DEVICE_BASE,	\
+					CSS_SGI_DEVICE_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE		0x30000000
+#define PLAT_ARM_GICC_BASE		0x2C000000
+#define PLAT_ARM_GICR_BASE		0x300C0000
+
+/* Map the secure region for access from S-EL0 */
+#define PLAT_ARM_SECURE_MAP_DEVICE	MAP_REGION_FLAT(	\
+					SOC_CSS_DEVICE_BASE,	\
+					SOC_CSS_DEVICE_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE | MT_USER)
+
+#define PLAT_SP_PRI				PLAT_RAS_PRI
+
+#if RAS_EXTENSION
+/* Allocate 128KB for CPER buffers */
+#define PLAT_SP_BUF_BASE			ULL(0x20000)
+
+#define PLAT_ARM_SP_IMAGE_STACK_BASE		(PLAT_SP_IMAGE_NS_BUF_BASE + \
+						PLAT_SP_IMAGE_NS_BUF_SIZE + \
+						PLAT_SP_BUF_BASE)
+
+/* Platform specific SMC FID's used for RAS */
+#define SP_DMC_ERROR_INJECT_EVENT_AARCH64	0xC4000042
+#define SP_DMC_ERROR_INJECT_EVENT_AARCH32	0x84000042
+
+#define SP_DMC_ERROR_OVERFLOW_EVENT_AARCH64	0xC4000043
+#define SP_DMC_ERROR_OVERFLOW_EVENT_AARCH32	0x84000043
+
+#define SP_DMC_ERROR_ECC_EVENT_AARCH64		0xC4000044
+#define SP_DMC_ERROR_ECC_EVENT_AARCH32		0x84000044
+
+/* ARM SDEI dynamic shared event numbers */
+#define SGI_SDEI_DS_EVENT_0			804
+#define SGI_SDEI_DS_EVENT_1			805
+
+#define PLAT_ARM_PRIVATE_SDEI_EVENTS	\
+	SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI), \
+	SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_0, SDEI_MAPF_CRITICAL), \
+	SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_1, SDEI_MAPF_CRITICAL),
+#define PLAT_ARM_SHARED_SDEI_EVENTS
+
+#define ARM_SP_CPER_BUF_BASE			(PLAT_SP_IMAGE_NS_BUF_BASE + \
+						PLAT_SP_IMAGE_NS_BUF_SIZE)
+#define ARM_SP_CPER_BUF_SIZE			ULL(0x20000)
+#define ARM_SP_CPER_BUF_MMAP			MAP_REGION2(		\
+						ARM_SP_CPER_BUF_BASE,	\
+						ARM_SP_CPER_BUF_BASE,	\
+						ARM_SP_CPER_BUF_SIZE,	\
+						MT_RW_DATA | MT_NS | MT_USER, \
+						PAGE_SIZE)
+
+#else
+#define PLAT_ARM_SP_IMAGE_STACK_BASE	(PLAT_SP_IMAGE_NS_BUF_BASE +	\
+					 PLAT_SP_IMAGE_NS_BUF_SIZE)
+#endif /* RAS_EXTENSION */
+
+/* Platform ID address */
+#define SSC_VERSION                     (SSC_REG_BASE + SSC_VERSION_OFFSET)
+#ifndef __ASSEMBLER__
+/* SSC_VERSION related accessors */
+/* Returns the part number of the platform */
+#define GET_SGI_PART_NUM                                       \
+		GET_SSC_VERSION_PART_NUM(mmio_read_32(SSC_VERSION))
+/* Returns the configuration number of the platform */
+#define GET_SGI_CONFIG_NUM                                     \
+		GET_SSC_VERSION_CONFIG(mmio_read_32(SSC_VERSION))
+#endif /* __ASSEMBLER__ */
+
+/*******************************************************************************
+ * Memprotect definitions
+ ******************************************************************************/
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/*Secure Watchdog Constants */
+#define SBSA_SECURE_WDOG_BASE		UL(0x2A480000)
+#define SBSA_SECURE_WDOG_TIMEOUT	UL(100)
+
+#endif /* SGI_BASE_PLATFORM_DEF_H */
diff --git a/plat/arm/css/sgi/include/sgi_ras.h b/plat/arm/css/sgi/include/sgi_ras.h
new file mode 100644
index 0000000..a449eae
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_ras.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_RAS_H
+#define SGI_RAS_H
+
+/*
+ * Mapping the RAS interrupt with SDEI event number and the event
+ * id used with Standalone MM code
+ */
+struct sgi_ras_ev_map {
+	int ras_ev_num;		/* RAS Event number */
+	int sdei_ev_num;	/* SDEI Event number */
+	int intr;		/* Physical intr number */
+};
+
+int sgi_ras_intr_handler_setup(void);
+
+#endif /* SGI_RAS_H */
diff --git a/plat/arm/css/sgi/include/sgi_variant.h b/plat/arm/css/sgi/include/sgi_variant.h
new file mode 100644
index 0000000..c75f213
--- /dev/null
+++ b/plat/arm/css/sgi/include/sgi_variant.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGI_VARIANT_H
+#define SGI_VARIANT_H
+
+/* SSC_VERSION values for SGI575 */
+#define SGI575_SSC_VER_PART_NUM		0x0783
+
+/* SID Version values for RD-N1E1-Edge */
+#define RD_N1E1_EDGE_SID_VER_PART_NUM		0x0786
+#define RD_E1_EDGE_CONFIG_ID			0x2
+
+/* Structure containing SGI platform variant information */
+typedef struct sgi_platform_info {
+	unsigned int platform_id;	/* Part Number of the platform */
+	unsigned int config_id;		/* Config Id of the platform */
+} sgi_platform_info_t;
+
+extern sgi_platform_info_t sgi_plat_info;
+
+/* returns the part number of the platform*/
+unsigned int plat_arm_sgi_get_platform_id(void);
+
+/* returns the configuration id of the platform */
+unsigned int plat_arm_sgi_get_config_id(void);
+
+#endif /* SGI_VARIANT_H */
diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/css/sgi/sgi-common.mk
new file mode 100644
index 0000000..b736b0b
--- /dev/null
+++ b/plat/arm/css/sgi/sgi-common.mk
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CSS_USE_SCMI_SDS_DRIVER		:=	1
+
+CSS_ENT_BASE			:=	plat/arm/css/sgi
+
+RAS_EXTENSION			:=	0
+
+ENABLE_SPM			:=	0
+
+SDEI_SUPPORT			:=	0
+
+EL3_EXCEPTION_HANDLING		:=	0
+
+HANDLE_EA_EL3_FIRST		:=	0
+
+INTERCONNECT_SOURCES	:=	${CSS_ENT_BASE}/sgi_interconnect.c
+
+PLAT_INCLUDES		+=	-I${CSS_ENT_BASE}/include
+
+ENT_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				plat/arm/common/arm_gicv3.c		\
+				drivers/arm/gic/v3/gic600.c
+
+
+PLAT_BL_COMMON_SOURCES	+=	${CSS_ENT_BASE}/sgi_plat.c	\
+				${CSS_ENT_BASE}/aarch64/sgi_helper.S
+
+BL1_SOURCES		+=	${INTERCONNECT_SOURCES}			\
+				drivers/arm/sbsa/sbsa.c
+
+BL2_SOURCES		+=	${CSS_ENT_BASE}/sgi_image_load.c
+
+BL31_SOURCES		+=	${INTERCONNECT_SOURCES}			\
+				${ENT_GIC_SOURCES}			\
+				${CSS_ENT_BASE}/sgi_bl31_setup.c	\
+				${CSS_ENT_BASE}/sgi_topology.c
+
+ifeq (${RAS_EXTENSION},1)
+BL31_SOURCES		+=	${CSS_ENT_BASE}/sgi_ras.c
+endif
+
+ifneq (${RESET_TO_BL31},0)
+  $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \
+  Please set RESET_TO_BL31 to 0.")
+endif
+
+$(eval $(call add_define,SGI_PLAT))
+
+override CSS_LOAD_SCP_IMAGES	:=	0
+override NEED_BL2U		:=	no
+override ARM_BL31_IN_DRAM	:=	1
+override ARM_PLAT_MT		:=	1
+
+# System coherency is managed in hardware
+HW_ASSISTED_COHERENCY	:=	1
+
+# When building for systems with hardware-assisted coherency, there's no need to
+# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
+USE_COHERENT_MEM	:=	0
+
+include plat/arm/common/arm_common.mk
+include plat/arm/css/common/css_common.mk
+include plat/arm/soc/common/soc_css.mk
+include plat/arm/board/common/board_common.mk
diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/css/sgi/sgi_bl31_setup.c
new file mode 100644
index 0000000..ba050d5
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_bl31_setup.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <sgi_ras.h>
+#include <sgi_variant.h>
+
+sgi_platform_info_t sgi_plat_info;
+
+static scmi_channel_plat_info_t sgi575_scmi_plat_info = {
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhu_ring_doorbell,
+};
+
+static scmi_channel_plat_info_t rd_n1e1_edge_scmi_plat_info = {
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + SENDER_REG_SET(0),
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhuv2_ring_doorbell,
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info(void)
+{
+	if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM)
+		return &rd_n1e1_edge_scmi_plat_info;
+	else if (sgi_plat_info.platform_id == SGI575_SSC_VER_PART_NUM)
+		return &sgi575_scmi_plat_info;
+	else
+		panic();
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	sgi_plat_info.platform_id = plat_arm_sgi_get_platform_id();
+	sgi_plat_info.config_id = plat_arm_sgi_get_config_id();
+
+	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+}
+
+void bl31_platform_setup(void)
+{
+	arm_bl31_platform_setup();
+
+#if RAS_EXTENSION
+	sgi_ras_intr_handler_setup();
+#endif
+}
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+	/* For RD-E1-Edge platform only CPU ON/OFF is supported */
+	if ((sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) &&
+	    (sgi_plat_info.config_id == RD_E1_EDGE_CONFIG_ID)) {
+		ops->cpu_standby = NULL;
+		ops->system_off = NULL;
+		ops->system_reset = NULL;
+		ops->get_sys_suspend_power_state = NULL;
+		ops->pwr_domain_suspend = NULL;
+		ops->pwr_domain_suspend_finish = NULL;
+	}
+
+	return css_scmi_override_pm_ops(ops);
+}
diff --git a/plat/arm/css/sgi/sgi_image_load.c b/plat/arm/css/sgi/sgi_image_load.c
new file mode 100644
index 0000000..a2f10dc
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_image_load.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <libfdt.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <sgi_variant.h>
+
+/*******************************************************************************
+ * This function inserts Platform information via device tree nodes as,
+ * system-id {
+ *    platform-id = <0>;
+ *    config-id = <0>;
+ * }
+ ******************************************************************************/
+static int plat_sgi_append_config_node(void)
+{
+	bl_mem_params_node_t *mem_params;
+	void *fdt;
+	int nodeoffset, err;
+	unsigned int platid = 0, platcfg = 0;
+
+	mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
+	if (mem_params == NULL) {
+		ERROR("NT_FW CONFIG base address is NULL");
+		return -1;
+	}
+
+	fdt = (void *)(mem_params->image_info.image_base);
+
+	/* Check the validity of the fdt */
+	if (fdt_check_header(fdt) != 0) {
+		ERROR("Invalid NT_FW_CONFIG DTB passed\n");
+		return -1;
+	}
+
+	nodeoffset = fdt_subnode_offset(fdt, 0, "system-id");
+	if (nodeoffset < 0) {
+		ERROR("Failed to get system-id node offset\n");
+		return -1;
+	}
+
+	platid = plat_arm_sgi_get_platform_id();
+	err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid);
+	if (err < 0) {
+		ERROR("Failed to set platform-id\n");
+		return -1;
+	}
+
+	platcfg = plat_arm_sgi_get_config_id();
+	err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg);
+	if (err < 0) {
+		ERROR("Failed to set config-id\n");
+		return -1;
+	}
+
+	flush_dcache_range((uintptr_t)fdt, mem_params->image_info.image_size);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	int ret;
+
+	ret = plat_sgi_append_config_node();
+	if (ret != 0)
+		panic();
+
+	return arm_get_next_bl_params();
+}
+
diff --git a/plat/arm/css/sgi/sgi_interconnect.c b/plat/arm/css/sgi/sgi_interconnect.c
new file mode 100644
index 0000000..e9cd812
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_interconnect.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+
+/*
+ * For SGI575 which support FCM (with automatic interconnect enter/exit),
+ * we should not do anything in these interface functions.
+ * They are used to override the weak functions in cci drivers.
+ */
+
+/******************************************************************************
+ * Helper function to initialize ARM interconnect driver.
+ *****************************************************************************/
+void __init plat_arm_interconnect_init(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_arm_interconnect_enter_coherency(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_arm_interconnect_exit_coherency(void)
+{
+}
diff --git a/plat/arm/css/sgi/sgi_plat.c b/plat/arm/css/sgi/sgi_plat.c
new file mode 100644
index 0000000..3e207ec
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_plat.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/ccn.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/sbsa.h>
+#include <sgi_base_platform_def.h>
+#include <services/secure_partition.h>
+
+#define SGI_MAP_FLASH0_RO	MAP_REGION_FLAT(V2M_FLASH0_BASE,\
+						V2M_FLASH0_SIZE,	\
+						MT_DEVICE | MT_RO | MT_SECURE)
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * arm_configure_mmu_elx() will give the available subset of that.
+ *
+ * Replace or extend the below regions as required
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	SGI_MAP_FLASH0_RO,
+	CSS_SGI_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	SGI_MAP_FLASH0_RO,
+	CSS_SGI_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	ARM_MAP_NS_DRAM1,
+#if ARM_BL31_IN_DRAM
+	ARM_MAP_BL31_SEC_DRAM,
+#endif
+#if ENABLE_SPM
+	ARM_SP_IMAGE_MMAP,
+#endif
+#if TRUSTED_BOARD_BOOT && !BL2_AT_EL3
+	ARM_MAP_BL1_RW,
+#endif
+	{0}
+};
+#endif
+#if IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_IOFPGA,
+	CSS_SGI_MAP_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+#if ENABLE_SPM
+	ARM_SPM_BUF_EL3_MMAP,
+#endif
+	{0}
+};
+
+#if ENABLE_SPM && defined(IMAGE_BL31)
+const mmap_region_t plat_arm_secure_partition_mmap[] = {
+	PLAT_ARM_SECURE_MAP_DEVICE,
+	ARM_SP_IMAGE_MMAP,
+	ARM_SP_IMAGE_NS_BUF_MMAP,
+	ARM_SP_CPER_BUF_MMAP,
+	ARM_SP_IMAGE_RW_MMAP,
+	ARM_SPM_BUF_EL0_MMAP,
+	{0}
+};
+#endif /* ENABLE_SPM && defined(IMAGE_BL31) */
+#endif
+
+ARM_CASSERT_MMAP
+
+#if ENABLE_SPM && defined(IMAGE_BL31)
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static secure_partition_mp_info_t sp_mp_info[] = {
+	[0] = {0x81000000, 0},
+	[1] = {0x81000100, 0},
+	[2] = {0x81000200, 0},
+	[3] = {0x81000300, 0},
+	[4] = {0x81010000, 0},
+	[5] = {0x81010100, 0},
+	[6] = {0x81010200, 0},
+	[7] = {0x81010300, 0},
+};
+
+const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = {
+	.h.type              = PARAM_SP_IMAGE_BOOT_INFO,
+	.h.version           = VERSION_1,
+	.h.size              = sizeof(secure_partition_boot_info_t),
+	.h.attr              = 0,
+	.sp_mem_base         = ARM_SP_IMAGE_BASE,
+	.sp_mem_limit        = ARM_SP_IMAGE_LIMIT,
+	.sp_image_base       = ARM_SP_IMAGE_BASE,
+	.sp_stack_base       = PLAT_SP_IMAGE_STACK_BASE,
+	.sp_heap_base        = ARM_SP_IMAGE_HEAP_BASE,
+	.sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE,
+	.sp_shared_buf_base  = PLAT_SPM_BUF_BASE,
+	.sp_image_size       = ARM_SP_IMAGE_SIZE,
+	.sp_pcpu_stack_size  = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+	.sp_heap_size        = ARM_SP_IMAGE_HEAP_SIZE,
+	.sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE,
+	.sp_shared_buf_size  = PLAT_SPM_BUF_SIZE,
+	.num_sp_mem_regions  = ARM_SP_IMAGE_NUM_MEM_REGIONS,
+	.num_cpus            = PLATFORM_CORE_COUNT,
+	.mp_info             = &sp_mp_info[0],
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+	return plat_arm_secure_partition_mmap;
+}
+
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie)
+{
+	return &plat_arm_secure_partition_boot_info;
+}
+#endif /* ENABLE_SPM && defined(IMAGE_BL31) */
+
+#if TRUSTED_BOARD_BOOT
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	assert(heap_addr != NULL);
+	assert(heap_size != NULL);
+
+	return arm_get_mbedtls_heap(heap_addr, heap_size);
+}
+#endif
+
+void plat_arm_secure_wdt_start(void)
+{
+	sbsa_wdog_start(SBSA_SECURE_WDOG_BASE, SBSA_SECURE_WDOG_TIMEOUT);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE);
+}
diff --git a/plat/arm/css/sgi/sgi_ras.c b/plat/arm/css/sgi/sgi_ras.c
new file mode 100644
index 0000000..0001ffd
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_ras.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/extensions/ras.h>
+#include <plat/arm/common/arm_spm_def.h>
+#include <plat/common/platform.h>
+#include <services/mm_svc.h>
+#include <services/sdei.h>
+#include <services/spm_svc.h>
+
+#include <sgi_ras.h>
+
+static int sgi_ras_intr_handler(const struct err_record_info *err_rec,
+				int probe_data,
+				const struct err_handler_data *const data);
+struct efi_guid {
+	uint32_t	data1;
+	uint16_t	data2;
+	uint16_t	data3;
+	uint8_t		data4[8];
+};
+
+typedef struct mm_communicate_header {
+	struct efi_guid	header_guid;
+	size_t		message_len;
+	uint8_t		data[8];
+} mm_communicate_header_t;
+
+struct sgi_ras_ev_map sgi575_ras_map[] = {
+
+	/* DMC620 error overflow interrupt*/
+	{SP_DMC_ERROR_OVERFLOW_EVENT_AARCH64, SGI_SDEI_DS_EVENT_1, 33},
+
+	/* DMC620 error ECC error interrupt*/
+	{SP_DMC_ERROR_ECC_EVENT_AARCH64, SGI_SDEI_DS_EVENT_0, 35},
+};
+
+#define SGI575_RAS_MAP_SIZE	ARRAY_SIZE(sgi575_ras_map)
+
+struct err_record_info sgi_err_records[] = {
+	{
+		.handler = &sgi_ras_intr_handler,
+	},
+};
+
+struct ras_interrupt sgi_ras_interrupts[] = {
+	{
+		.intr_number = 33,
+		.err_record = &sgi_err_records[0],
+	},
+	{
+		.intr_number = 35,
+		.err_record = &sgi_err_records[0],
+	}
+};
+
+REGISTER_ERR_RECORD_INFO(sgi_err_records);
+REGISTER_RAS_INTERRUPTS(sgi_ras_interrupts);
+
+static struct sgi_ras_ev_map *plat_sgi_get_ras_ev_map(void)
+{
+	return sgi575_ras_map;
+}
+
+static int plat_sgi_get_ras_ev_map_size(void)
+{
+	return SGI575_RAS_MAP_SIZE;
+}
+
+/*
+ * Find event mapping for a given interrupt number: On success, returns pointer
+ * to the event mapping. On error, returns NULL.
+ */
+static struct sgi_ras_ev_map *find_ras_event_map_by_intr(uint32_t intr_num)
+{
+	struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map();
+	int i;
+	int size = plat_sgi_get_ras_ev_map_size();
+
+	for (i = 0; i < size; i++) {
+		if (map->intr == intr_num)
+			return map;
+
+		map++;
+	}
+
+	return NULL;
+}
+
+static void sgi_ras_intr_configure(int intr)
+{
+	plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3);
+	plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI);
+	plat_ic_clear_interrupt_pending(intr);
+	plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY,
+				(u_register_t)read_mpidr_el1());
+	plat_ic_enable_interrupt(intr);
+}
+
+static int sgi_ras_intr_handler(const struct err_record_info *err_rec,
+				int probe_data,
+				const struct err_handler_data *const data)
+{
+	struct sgi_ras_ev_map *ras_map;
+	mm_communicate_header_t *header;
+	uint32_t intr;
+
+	cm_el1_sysregs_context_save(NON_SECURE);
+	intr = data->interrupt;
+
+	/*
+	 * Find if this is a RAS interrupt. There must be an event against
+	 * this interrupt
+	 */
+	ras_map = find_ras_event_map_by_intr(intr);
+	assert(ras_map);
+
+	/*
+	 * Populate the MM_COMMUNICATE payload to share the
+	 * event info with StandaloneMM code. This allows us to use
+	 * MM_COMMUNICATE as a common entry mechanism into S-EL0. The
+	 * header data will be parsed in StandaloneMM to process the
+	 * corresponding event.
+	 *
+	 * TBD - Currently, the buffer allocated by SPM for communication
+	 * between EL3 and S-EL0 is being used(PLAT_SPM_BUF_BASE). But this
+	 * should happen via a dynamic mem allocation, which should be
+	 * managed by SPM -- the individual platforms then call the mem
+	 * alloc api to get memory for the payload.
+	 */
+	header = (void *) PLAT_SPM_BUF_BASE;
+	memset(header, 0, sizeof(*header));
+	memcpy(&header->data, &ras_map->ras_ev_num,
+	       sizeof(ras_map->ras_ev_num));
+	header->message_len = 4;
+
+	spm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0,
+		    plat_my_core_pos());
+
+	/*
+	 * Do an EOI of the RAS interuupt. This allows the
+	 * sdei event to be dispatched at the SDEI event's
+	 * priority.
+	 */
+	plat_ic_end_of_interrupt(intr);
+
+	/* Dispatch the event to the SDEI client */
+	sdei_dispatch_event(ras_map->sdei_ev_num);
+
+	return 0;
+}
+
+int sgi_ras_intr_handler_setup(void)
+{
+	int i;
+	struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map();
+	int size = plat_sgi_get_ras_ev_map_size();
+
+	for (i = 0; i < size; i++) {
+		sgi_ras_intr_configure(map->intr);
+		map++;
+	}
+
+	INFO("SGI: RAS Interrupt Handler successfully registered\n");
+
+	return 0;
+}
diff --git a/plat/arm/css/sgi/sgi_topology.c b/plat/arm/css/sgi/sgi_topology.c
new file mode 100644
index 0000000..7aa9e40
--- /dev/null
+++ b/plat/arm/css/sgi/sgi_topology.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <sgi_variant.h>
+
+/* Topology */
+/*
+ * The power domain tree descriptor. The cluster power domains are
+ * arranged so that when the PSCI generic code creates the power domain tree,
+ * the indices of the CPU power domain nodes it allocates match the linear
+ * indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char sgi_pd_tree_desc[] = {
+	PLAT_ARM_CLUSTER_COUNT,
+	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	CSS_SGI_MAX_CPUS_PER_CLUSTER
+};
+
+/* RD-E1-Edge platform consists of 16 physical CPUS and 32 threads */
+const unsigned char rd_e1_edge_pd_tree_desc[] = {
+	PLAT_ARM_CLUSTER_COUNT,
+	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	CSS_SGI_MAX_CPUS_PER_CLUSTER,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU,
+	CSS_SGI_MAX_PE_PER_CPU
+};
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM &&
+	    sgi_plat_info.config_id == RD_E1_EDGE_CONFIG_ID)
+		return rd_e1_edge_pd_tree_desc;
+	else
+		return sgi_pd_tree_desc;
+}
+
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
+{
+	return CSS_SGI_MAX_CPUS_PER_CLUSTER;
+}
+
+/*******************************************************************************
+ * The array mapping platform core position (implemented by plat_my_core_pos())
+ * to the SCMI power domain ID implemented by SCP.
+ ******************************************************************************/
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[32] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,		\
+	16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
+};
+
+/******************************************************************************
+ * Return the number of PE's supported by the CPU.
+ *****************************************************************************/
+unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr)
+{
+	return CSS_SGI_MAX_PE_PER_CPU;
+}
diff --git a/plat/arm/css/sgm/aarch64/css_sgm_helpers.S b/plat/arm/css/sgm/aarch64/css_sgm_helpers.S
new file mode 100644
index 0000000..32ca1bb
--- /dev/null
+++ b/plat/arm/css/sgm/aarch64/css_sgm_helpers.S
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cortex_a75.h>
+#include <cortex_a55.h>
+#include <cpu_macros.S>
+
+	.globl	plat_arm_calc_core_pos
+	.globl	plat_reset_handler
+
+	/* ---------------------------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Function to calculate the core position on FVP.
+	 *
+	 * (ClusterId * MAX_CPUS_PER_CLUSTER * MAX_PE_PER_CPU) +
+	 * (CPUId * MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((ClusterId * MAX_CPUS_PER_CLUSTER + CPUId) * MAX_PE_PER_CPU)
+	 * + ThreadId
+	 * ---------------------------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	/*
+	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+	 * look as if in a multi-threaded implementation.
+	 */
+	tst	x0, #MPIDR_MT_MASK
+	lsr	x3, x0, #MPIDR_AFFINITY_BITS
+	csel	x3, x3, x0, eq
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx	x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov	x4, #PLAT_MAX_CPUS_PER_CLUSTER
+	madd	x1, x2, x4, x1
+	mov	x5, #PLAT_MAX_PE_PER_CPU
+	madd	x0, x1, x5, x0
+	ret
+endfunc plat_arm_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the CPU MIDR and disable power down bit for
+	 * that CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	jump_if_cpu_midr CORTEX_A75_MIDR, A75
+	jump_if_cpu_midr CORTEX_A55_MIDR, A55
+	ret
+
+	/* -----------------------------------------------------
+	 * Disable CPU power down bit in power control register
+	 * -----------------------------------------------------
+	 */
+A75:
+	mrs	x0, CORTEX_A75_CPUPWRCTLR_EL1
+	bic	x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A75_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+A55:
+	mrs	x0, CORTEX_A55_CPUPWRCTLR_EL1
+	bic	x0, x0, #CORTEX_A55_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A55_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc plat_reset_handler
diff --git a/plat/arm/css/sgm/fdts/sgm_tb_fw_config.dts b/plat/arm/css/sgm/fdts/sgm_tb_fw_config.dts
new file mode 100644
index 0000000..d481018
--- /dev/null
+++ b/plat/arm/css/sgm/fdts/sgm_tb_fw_config.dts
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+	/* Platform Config */
+	plat_arm_bl2 {
+		compatible = "arm,tb_fw";
+		hw_config_addr = <0x0 0x83000000>;
+		hw_config_max_size = <0x01000000>;
+		/*
+		 * The following two entries are placeholders for Mbed TLS
+		 * heap information. The default values don't matter since
+		 * they will be overwritten by BL1.
+		 * In case of having shared Mbed TLS heap between BL1 and BL2,
+		 * BL1 will populate these two properties with the respective
+		 * info about the shared heap. This info will be available for
+		 * BL2 in order to locate and re-use the heap.
+		 */
+		mbedtls_heap_addr = <0x0 0x0>;
+		mbedtls_heap_size = <0x0>;
+	};
+};
diff --git a/plat/arm/css/sgm/include/plat_macros.S b/plat/arm/css/sgm/include/plat_macros.S
new file mode 100644
index 0000000..715ded2
--- /dev/null
+++ b/plat/arm/css/sgm/include/plat_macros.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <cci_macros.S>
+#include <css_macros.S>
+
+/* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant platform registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+css_print_gic_regs
+print_cci_regs
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/arm/css/sgm/include/sgm_base_platform_def.h b/plat/arm/css/sgm/include/sgm_base_platform_def.h
new file mode 100644
index 0000000..f349c19
--- /dev/null
+++ b/plat/arm/css/sgm/include/sgm_base_platform_def.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGM_BASE_PLATFORM_DEF_H
+#define SGM_BASE_PLATFORM_DEF_H
+
+#include <drivers/arm/tzc400.h>
+#include <drivers/arm/tzc_common.h>
+#include <plat/arm/board/common/board_css_def.h>
+#include <plat/arm/board/common/v2m_def.h>
+#include <plat/arm/common/arm_def.h>
+#include <plat/arm/css/common/css_def.h>
+#include <plat/arm/soc/common/soc_css_def.h>
+#include <plat/common/common_def.h>
+
+/* CPU topology */
+#define PLAT_ARM_CLUSTER_COUNT		1
+#define PLAT_ARM_CLUSTER_CORE_COUNT	8
+#define PLATFORM_CORE_COUNT		PLAT_ARM_CLUSTER_CORE_COUNT
+
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
+#define PLAT_NUM_PWR_DOMAINS		(ARM_SYSTEM_COUNT + \
+					PLAT_ARM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+			CSS_G1S_IRQ_PROPS(grp), \
+			ARM_G1S_IRQ_PROPS(grp)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)	ARM_G0_IRQ_PROPS(grp)
+
+/* GIC related constants */
+#define PLAT_ARM_GICD_BASE		0x30000000
+#define PLAT_ARM_GICR_BASE		0x300C0000
+#define PLAT_ARM_GICC_BASE		0x2c000000
+
+#define CSS_GIC_SIZE			0x00200000
+
+#define CSS_MAP_GIC_DEVICE		MAP_REGION_FLAT(	\
+					PLAT_ARM_GICD_BASE,	\
+					CSS_GIC_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/* Platform ID address */
+#define SSC_VERSION                     (SSC_REG_BASE + SSC_VERSION_OFFSET)
+#ifndef __ASSEMBLER__
+/* SSC_VERSION related accessors */
+/* Returns the part number of the platform */
+#define GET_PLAT_PART_NUM                                       \
+		GET_SSC_VERSION_PART_NUM(mmio_read_32(SSC_VERSION))
+/* Returns the configuration number of the platform */
+#define GET_PLAT_CONFIG_NUM                                     \
+		GET_SSC_VERSION_CONFIG(mmio_read_32(SSC_VERSION))
+#endif /* __ASSEMBLER__ */
+
+
+/*************************************************************************
+ * Definitions common to all SGM CSS based platforms
+ *************************************************************************/
+
+/* TZC-400 related constants */
+#define PLAT_ARM_TZC_BASE		0x2a500000
+#define TZC_NSAID_ALL_AP		0  /* Note: Same as default NSAID!! */
+#define TZC_NSAID_HDLCD0		2
+#define TZC_NSAID_HDLCD1		3
+#define TZC_NSAID_GPU			9
+#define TZC_NSAID_VIDEO			10
+#define TZC_NSAID_DISP0			11
+#define TZC_NSAID_DISP1			12
+
+
+/*************************************************************************
+ * Required platform porting definitions common to all SGM CSS based
+ * platforms
+ *************************************************************************/
+
+#define PLAT_ARM_TRUSTED_SRAM_SIZE	0x00040000	/* 256 KB */
+
+/* MHU related constants */
+#define PLAT_CSS_MHU_BASE		0x2b1f0000
+#define PLAT_MHUV2_BASE			PLAT_CSS_MHU_BASE
+
+#define PLAT_ARM_TRUSTED_ROM_BASE	0x00000000
+#define PLAT_ARM_TRUSTED_ROM_SIZE	0x00080000
+
+#define PLAT_ARM_CCI_BASE		0x2a000000
+
+/* Cluster to CCI slave mapping */
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX	6
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX	5
+
+/* System timer related constants */
+#define PLAT_ARM_NSTIMER_FRAME_ID	0
+
+/* TZC related constants */
+#define PLAT_ARM_TZC_NS_DEV_ACCESS	(				\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_ALL_AP)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_HDLCD0)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_HDLCD1)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_GPU)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_VIDEO)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_DISP0)	|	\
+		TZC_REGION_ACCESS_RDWR(TZC_NSAID_DISP1))
+
+/* Display Processor register definitions to setup the NSAIDs */
+#define MALI_DP_BASE           0x2cc00000
+#define DP_NPROT_NSAID_OFFSET     0x1000c
+#define W_NPROT_NSAID_SHIFT            24
+#define LS_NPORT_NSAID_SHIFT           12
+
+/*
+ * Base address of the first memory region used for communication between AP
+ * and SCP. Used by the BootOverMHU and SCPI protocols.
+ */
+#if !CSS_USE_SCMI_SDS_DRIVER
+/*
+ * Note that this is located at the same address as SCP_BOOT_CFG_ADDR, which
+ * means the SCP/AP configuration data gets overwritten when the AP initiates
+ * communication with the SCP. The configuration data is expected to be a
+ * 32-bit word on all CSS platforms. Part of this configuration is
+ * which CPU is the primary, according to the shift and mask definitions below.
+ */
+#define PLAT_CSS_SCP_COM_SHARED_MEM_BASE	(ARM_TRUSTED_SRAM_BASE + 0x80)
+#define PLAT_CSS_PRIMARY_CPU_SHIFT		8
+#define PLAT_CSS_PRIMARY_CPU_BIT_WIDTH		4
+#endif
+
+/*
+ * PLAT_CSS_MAX_SCP_BL2_SIZE is calculated using the current
+ * SCP_BL2 size plus a little space for growth.
+ */
+#define PLAT_CSS_MAX_SCP_BL2_SIZE	0x15000
+
+/*
+ * PLAT_CSS_MAX_SCP_BL2U_SIZE is calculated using the current
+ * SCP_BL2U size plus a little space for growth.
+ */
+#define PLAT_CSS_MAX_SCP_BL2U_SIZE	0x15000
+
+/*
+ * Most platform porting definitions provided by included headers
+ */
+
+/*
+ * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the
+ * plat_arm_mmap array defined for each BL stage.
+ */
+#if defined(IMAGE_BL31)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		5
+#elif defined(IMAGE_BL32)
+# define PLAT_ARM_MMAP_ENTRIES		8
+# define MAX_XLAT_TABLES		5
+#elif !USE_ROMLIB
+# define PLAT_ARM_MMAP_ENTRIES		11
+# define MAX_XLAT_TABLES		5
+#else
+# define PLAT_ARM_MMAP_ENTRIES		12
+# define MAX_XLAT_TABLES		6
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_ARM_MAX_BL1_RW_SIZE	0xB000
+
+/*
+ * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page
+ */
+
+#if USE_ROMLIB
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	0x1000
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	0xe000
+#else
+#define PLAT_ARM_MAX_ROMLIB_RW_SIZE	0
+#define PLAT_ARM_MAX_ROMLIB_RO_SIZE	0
+#endif
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#if TRUSTED_BOARD_BOOT
+# define PLAT_ARM_MAX_BL2_SIZE		0x1D000
+#else
+# define PLAT_ARM_MAX_BL2_SIZE		0x11000
+#endif
+
+/*
+ * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
+ * calculated using the current BL31 PROGBITS debug size plus the sizes of
+ * BL2 and BL1-RW
+ */
+#define PLAT_ARM_MAX_BL31_SIZE		0x3B000
+
+/*
+ * Size of cacheable stacks
+ */
+#if defined(IMAGE_BL1)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x440
+# endif
+#elif defined(IMAGE_BL2)
+# if TRUSTED_BOARD_BOOT
+#  define PLATFORM_STACK_SIZE 0x1000
+# else
+#  define PLATFORM_STACK_SIZE 0x400
+# endif
+#elif defined(IMAGE_BL2U)
+# define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+# define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL32)
+# define PLATFORM_STACK_SIZE 0x440
+#endif
+
+/*******************************************************************************
+ * Memprotect definitions
+ ******************************************************************************/
+/* PSCI memory protect definitions:
+ * This variable is stored in a non-secure flash because some ARM reference
+ * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
+ * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
+ */
+#define PLAT_ARM_MEM_PROT_ADDR		(V2M_FLASH0_BASE + \
+					 V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
+
+/* System power domain level */
+#define CSS_SYSTEM_PWR_DMN_LVL		ARM_PWR_LVL2
+
+#endif /* SGM_BASE_PLATFORM_DEF_H */
diff --git a/plat/arm/css/sgm/include/sgm_plat_config.h b/plat/arm/css/sgm/include/sgm_plat_config.h
new file mode 100644
index 0000000..29b98d4
--- /dev/null
+++ b/plat/arm/css/sgm/include/sgm_plat_config.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGM_PLAT_CONFIG_H
+#define SGM_PLAT_CONFIG_H
+
+#include <drivers/arm/ccn.h>
+#include <drivers/arm/gicv3.h>
+
+/* The type of interconnect */
+typedef enum {
+	ARM_CCI = 0,
+	ARM_CCN,
+	ARM_CMN
+} css_inteconn_type_t;
+
+typedef ccn_desc_t inteconn_desc_t;
+
+/* Interconnect configurations */
+typedef struct css_inteconn_config {
+	css_inteconn_type_t ip_type;
+	const inteconn_desc_t *plat_inteconn_desc;
+} css_inteconn_config_t;
+
+/* Topology configurations */
+typedef struct css_topology {
+	const unsigned char *power_tree;
+	unsigned int plat_cluster_core_count;
+} css_topology_t;
+
+typedef struct css_plat_config {
+	const gicv3_driver_data_t *gic_data;
+	const css_inteconn_config_t *inteconn;
+	const css_topology_t *topology;
+} css_plat_config_t;
+
+void plat_config_init(void);
+css_plat_config_t *get_plat_config(void);
+
+#endif /* SGM_PLAT_CONFIG_H */
diff --git a/plat/arm/css/sgm/include/sgm_variant.h b/plat/arm/css/sgm/include/sgm_variant.h
new file mode 100644
index 0000000..859ddb5
--- /dev/null
+++ b/plat/arm/css/sgm/include/sgm_variant.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SGM_VARIANT_H
+#define SGM_VARIANT_H
+
+/* SSC_VERSION values for sgm */
+#define SGM775_SSC_VER_PART_NUM		0x0790
+
+/* DMC configuration for sgm */
+#define SGM_DMC_SIZE			0x40000
+#define SGM775_DMC_COUNT		4
+
+#endif /* SGM_VARIANT_H */
diff --git a/plat/arm/css/sgm/sgm-common.mk b/plat/arm/css/sgm/sgm-common.mk
new file mode 100644
index 0000000..34e78b2
--- /dev/null
+++ b/plat/arm/css/sgm/sgm-common.mk
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CSS_SGM_BASE		:=	plat/arm/css/sgm
+
+PLAT_INCLUDES		:=	-I${CSS_SGM_BASE}/include
+
+PLAT_BL_COMMON_SOURCES	:=	${CSS_SGM_BASE}/sgm_mmap_config.c	\
+				${CSS_SGM_BASE}/aarch64/css_sgm_helpers.S
+
+SECURITY_SOURCES	:=	drivers/arm/tzc/tzc_dmc500.c		\
+				plat/arm/common/arm_tzc_dmc500.c	\
+				${CSS_SGM_BASE}/sgm_security.c
+
+SGM_CPU_SOURCES		:=	lib/cpus/aarch64/cortex_a55.S		\
+				lib/cpus/aarch64/cortex_a75.S
+
+INTERCONNECT_SOURCES	:=	${CSS_SGM_BASE}/sgm_interconnect.c
+
+SGM_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				plat/arm/common/arm_gicv3.c		\
+				drivers/arm/gic/v3/gic600.c		\
+				drivers/arm/gic/v3/arm_gicv3_common.c
+
+BL1_SOURCES		+=	$(SGM_CPU_SOURCES)			\
+				${INTERCONNECT_SOURCES}			\
+				${CSS_SGM_BASE}/sgm_bl1_setup.c		\
+				${CSS_SGM_BASE}/sgm_plat_config.c	\
+				drivers/arm/sp805/sp805.c
+
+BL2_SOURCES		+=	${SECURITY_SOURCES}			\
+				${CSS_SGM_BASE}/sgm_plat_config.c
+
+BL2U_SOURCES		+=	${SECURITY_SOURCES}
+
+BL31_SOURCES		+=	$(SGM_CPU_SOURCES)			\
+				${INTERCONNECT_SOURCES}			\
+				${SECURITY_SOURCES}			\
+				${SGM_GIC_SOURCES}			\
+				${CSS_SGM_BASE}/sgm_topology.c		\
+				${CSS_SGM_BASE}/sgm_bl31_setup.c	\
+				${CSS_SGM_BASE}/sgm_plat_config.c
+
+ifneq (${RESET_TO_BL31},0)
+  $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \
+  Please set RESET_TO_BL31 to 0.")
+endif
+
+# sgm uses CCI-500 as Cache Coherent Interconnect
+ARM_CCI_PRODUCT_ID	:=	500
+
+# System coherency is managed in hardware
+HW_ASSISTED_COHERENCY	:=	1
+
+# When building for systems with hardware-assisted coherency, there's no need to
+# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
+USE_COHERENT_MEM	:=	0
+
+override ARM_PLAT_MT	:=	1
+
+$(eval $(call add_define,SGM_PLAT))
+
+include plat/arm/common/arm_common.mk
+include plat/arm/board/common/board_common.mk
+include plat/arm/css/common/css_common.mk
+include plat/arm/soc/common/soc_css.mk
diff --git a/plat/arm/css/sgm/sgm_bl1_setup.c b/plat/arm/css/sgm/sgm_bl1_setup.c
new file mode 100644
index 0000000..5fd9655
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_bl1_setup.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/soc/common/soc_css.h>
+#include <plat/arm/common/arm_def.h>
+#include <drivers/arm/sp805.h>
+#include <sgm_plat_config.h>
+
+void bl1_early_platform_setup(void)
+{
+
+	/* Initialize the console before anything else */
+	arm_bl1_early_platform_setup();
+
+	/* Initialize the platform configuration structure */
+	plat_config_init();
+
+#if !HW_ASSISTED_COHERENCY
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_arm_interconnect_init();
+	/*
+	 * Enable Interconnect coherency for the primary CPU's cluster.
+	 */
+	plat_arm_interconnect_enter_coherency();
+#endif
+}
+
+void plat_arm_secure_wdt_start(void)
+{
+	sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
+}
+
+void plat_arm_secure_wdt_stop(void)
+{
+	sp805_stop(ARM_SP805_TWDG_BASE);
+}
diff --git a/plat/arm/css/sgm/sgm_bl31_setup.c b/plat/arm/css/sgm/sgm_bl31_setup.c
new file mode 100644
index 0000000..7e92ac8
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_bl31_setup.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <sgm_plat_config.h>
+
+static scmi_channel_plat_info_t sgm775_scmi_plat_info = {
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhu_ring_doorbell,
+};
+
+scmi_channel_plat_info_t *plat_css_get_scmi_info()
+{
+	return &sgm775_scmi_plat_info;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	uint32_t plat_version;
+	bl_params_node_t *bl_params;
+
+	bl_params = ((bl_params_t *)arg0)->head;
+
+	/* Initialize the platform configuration structure */
+	plat_config_init();
+
+	while (bl_params) {
+		if (bl_params->image_id == BL33_IMAGE_ID) {
+			plat_version = mmio_read_32(SSC_VERSION);
+			bl_params->ep_info->args.arg2 = plat_version;
+			break;
+		}
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3);
+}
+
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+	return css_scmi_override_pm_ops(ops);
+}
diff --git a/plat/arm/css/sgm/sgm_interconnect.c b/plat/arm/css/sgm/sgm_interconnect.c
new file mode 100644
index 0000000..5b45341
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_interconnect.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+
+/*
+ * As the SGM platform supports FCM (with automatic interconnect
+ * enter/exit), we should not do anything in these interface functions.
+ * They are used to override the weak functions in cci drivers.
+ */
+
+/******************************************************************************
+ * Helper function to initialize ARM interconnect driver.
+ *****************************************************************************/
+void __init plat_arm_interconnect_init(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_arm_interconnect_enter_coherency(void)
+{
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_arm_interconnect_exit_coherency(void)
+{
+}
diff --git a/plat/arm/css/sgm/sgm_mmap_config.c b/plat/arm/css/sgm/sgm_mmap_config.c
new file mode 100644
index 0000000..e5b4b03
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_mmap_config.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <sgm_variant.h>
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * arm_configure_mmu_elx() will give the available subset of that.
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH0_RO,
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	CSS_MAP_GIC_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+#if TRUSTED_BOARD_BOOT
+	ARM_MAP_NS_DRAM1,
+#endif
+	{0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_FLASH0_RO,
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	CSS_MAP_GIC_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	ARM_MAP_NS_DRAM1,
+#ifdef SPD_tspd
+	ARM_MAP_TSP_SEC_MEM,
+#endif
+#ifdef SPD_opteed
+	ARM_OPTEE_PAGEABLE_LOAD_MEM,
+#endif
+#if TRUSTED_BOARD_BOOT && !BL2_AT_EL3
+	ARM_MAP_BL1_RW,
+#endif
+	{0}
+};
+#endif
+#if IMAGE_BL2U
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	CSS_MAP_DEVICE,
+	CSS_MAP_GIC_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+#if IMAGE_BL31
+const mmap_region_t plat_arm_mmap[] = {
+	ARM_MAP_SHARED_RAM,
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	CSS_MAP_GIC_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+#if IMAGE_BL32
+const mmap_region_t plat_arm_mmap[] = {
+	V2M_MAP_IOFPGA,
+	CSS_MAP_DEVICE,
+	CSS_MAP_GIC_DEVICE,
+	SOC_CSS_MAP_DEVICE,
+	{0}
+};
+#endif
+
+ARM_CASSERT_MMAP
+
+const mmap_region_t *plat_arm_get_mmap(void)
+{
+	return plat_arm_mmap;
+}
diff --git a/plat/arm/css/sgm/sgm_plat_config.c b/plat/arm/css/sgm/sgm_plat_config.c
new file mode 100644
index 0000000..eed3631
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_plat_config.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <sgm_plat_config.h>
+#include <sgm_variant.h>
+
+static css_plat_config_t *css_plat_info;
+
+/* Interconnect */
+const css_inteconn_config_t sgm_inteconn = {
+	.ip_type = ARM_CCI,
+	.plat_inteconn_desc = NULL
+};
+
+/* Special definition for SGM775 */
+/* Topology configuration for SGM775 */
+const unsigned char sgm775_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	ARM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLAT_ARM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLAT_ARM_CLUSTER_CORE_COUNT,
+};
+
+const css_topology_t sgm775_topology = {
+	.power_tree = sgm775_power_domain_tree_desc,
+	.plat_cluster_core_count = PLAT_ARM_CLUSTER_CORE_COUNT
+};
+
+/* Configuration structure for SGM775 */
+css_plat_config_t sgm775_config = {
+	.inteconn = &sgm_inteconn,
+	.topology = &sgm775_topology
+};
+
+/*******************************************************************************
+ * This function initializes the platform structure.
+ ******************************************************************************/
+void plat_config_init(void)
+{
+	/* Get the platform configurations */
+	switch (GET_PLAT_PART_NUM) {
+	case SGM775_SSC_VER_PART_NUM:
+		css_plat_info = &sgm775_config;
+
+		break;
+	default:
+		ERROR("Not a valid sgm variant!\n");
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * This function returns the platform structure pointer.
+ ******************************************************************************/
+css_plat_config_t *get_plat_config(void)
+{
+	assert(css_plat_info != NULL);
+	return css_plat_info;
+}
+
+#if TRUSTED_BOARD_BOOT
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
+#endif
diff --git a/plat/arm/css/sgm/sgm_security.c b/plat/arm/css/sgm/sgm_security.c
new file mode 100644
index 0000000..21d5306
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_security.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/tzc_dmc500.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/soc/common/soc_css.h>
+
+#include <sgm_variant.h>
+
+/* Is populated with the DMC-500 controllers base addresses */
+static tzc_dmc500_driver_data_t plat_driver_data;
+
+void plat_sgm_dp_security_setup(void)
+{
+	unsigned int nprot_nsaid;
+
+	/*
+	 * At reset the Mali display processors start with NSAIDs set to zero
+	 * so the firmware must set them up to the expected values for ARM sgm
+	 * platforms.
+	 */
+
+	nprot_nsaid = mmio_read_32(MALI_DP_BASE + DP_NPROT_NSAID_OFFSET);
+	nprot_nsaid &= ~((0xF << W_NPROT_NSAID_SHIFT) |
+			(0xF << LS_NPORT_NSAID_SHIFT));
+	nprot_nsaid |= ((TZC_NSAID_DISP1 << W_NPROT_NSAID_SHIFT) |
+			(TZC_NSAID_DISP0 << LS_NPORT_NSAID_SHIFT));
+	mmio_write_32(MALI_DP_BASE + DP_NPROT_NSAID_OFFSET, nprot_nsaid);
+}
+
+void plat_arm_security_setup(void)
+{
+	unsigned int i;
+	unsigned int part_num = GET_PLAT_PART_NUM;
+
+	INFO("part_num: 0x%x\n", part_num);
+
+	/*
+	 * Initialise plat_driver_data with platform specific DMC_BASE
+	 * addresses
+	 */
+	switch (part_num) {
+	case SGM775_SSC_VER_PART_NUM:
+		for (i = 0; i < SGM775_DMC_COUNT; i++)
+			plat_driver_data.dmc_base[i] = PLAT_ARM_TZC_BASE
+					+ SGM_DMC_SIZE * i;
+		plat_driver_data.dmc_count = SGM775_DMC_COUNT;
+		break;
+	default:
+		/* Unexpected platform */
+		ERROR("Unexpected platform\n");
+		panic();
+	}
+	/* Initialize the TrustZone Controller in DMC-500 */
+	arm_tzc_dmc500_setup(&plat_driver_data, NULL);
+
+	/* Do DP NSAID setup */
+	plat_sgm_dp_security_setup();
+	/* Do ARM CSS SoC security setup */
+	soc_css_security_setup();
+}
diff --git a/plat/arm/css/sgm/sgm_topology.c b/plat/arm/css/sgm/sgm_topology.c
new file mode 100644
index 0000000..2d9552d
--- /dev/null
+++ b/plat/arm/css/sgm/sgm_topology.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#include <sgm_plat_config.h>
+
+/*******************************************************************************
+ * This function returns the topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return get_plat_config()->topology->power_tree;
+}
+
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr)
+{
+	return get_plat_config()->topology->plat_cluster_core_count;
+}
+
+/*
+ * The array mapping platform core position (implemented by plat_my_core_pos())
+ * to the SCMI power domain ID implemented by SCP.
+ */
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
+			0, 1, 2, 3, 4, 5, 6, 7 };
diff --git a/plat/arm/css/sgm/tsp/sgm_tsp_setup.c b/plat/arm/css/sgm/tsp/sgm_tsp_setup.c
new file mode 100644
index 0000000..5f40c4c
--- /dev/null
+++ b/plat/arm/css/sgm/tsp/sgm_tsp_setup.c
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/arm/common/plat_arm.h>
+
+#include <sgm_plat_config.h>
+
+void tsp_early_platform_setup(void)
+{
+	/* Initialize the platform configuration structure */
+	plat_config_init();
+
+	arm_tsp_early_platform_setup();
+}
diff --git a/plat/arm/css/sgm/tsp/tsp-sgm.mk b/plat/arm/css/sgm/tsp/tsp-sgm.mk
new file mode 100644
index 0000000..de5e5b7
--- /dev/null
+++ b/plat/arm/css/sgm/tsp/tsp-sgm.mk
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES		+= 	${SGM_GIC_SOURCES}			\
+				${CSS_SGM_BASE}/sgm_plat_config.c	\
+				plat/arm/css/sgm/tsp/sgm_tsp_setup.c
+
+include plat/arm/common/tsp/arm_tsp.mk
diff --git a/plat/arm/soc/common/soc_css.mk b/plat/arm/soc/common/soc_css.mk
new file mode 100644
index 0000000..8cad2a5
--- /dev/null
+++ b/plat/arm/soc/common/soc_css.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+#PLAT_BL_COMMON_SOURCES	+=
+
+BL1_SOURCES		+=	plat/arm/soc/common/soc_css_security.c
+
+BL2_SOURCES		+=	plat/arm/soc/common/soc_css_security.c
+
+BL2U_SOURCES		+=	plat/arm/soc/common/soc_css_security.c
+
+BL31_SOURCES		+=	plat/arm/soc/common/soc_css_security.c
diff --git a/plat/arm/soc/common/soc_css_security.c b/plat/arm/soc/common/soc_css_security.c
new file mode 100644
index 0000000..4f6bf61
--- /dev/null
+++ b/plat/arm/soc/common/soc_css_security.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/nic_400.h>
+#include <lib/mmio.h>
+#include <plat/arm/soc/common/soc_css.h>
+
+void soc_css_init_nic400(void)
+{
+	/*
+	 * NIC-400 Access Control Initialization
+	 *
+	 * Define access privileges by setting each corresponding bit to:
+	 *   0 = Secure access only
+	 *   1 = Non-secure access allowed
+	 */
+
+	/*
+	 * Allow non-secure access to some SOC regions, excluding UART1, which
+	 * remains secure (unless CSS_NON_SECURE_UART is set).
+	 * Note: This is the NIC-400 device on the SOC
+	 */
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_USB_EHCI), ~0);
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_TLX_MASTER), ~0);
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_USB_OHCI), ~0);
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_PL354_SMC), ~0);
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_APB4_BRIDGE), ~0);
+#if  CSS_NON_SECURE_UART
+	/* Configure UART for non-secure access */
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_BOOTSEC_BRIDGE), ~0);
+#else
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_BOOTSEC_BRIDGE),
+		~SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1);
+#endif /* CSS_NON_SECURE_UART */
+
+}
+
+
+#define PCIE_SECURE_REG		0x3000
+/* Mask uses REG and MEM access bits */
+#define PCIE_SEC_ACCESS_MASK	((1 << 0) | (1 << 1))
+
+void soc_css_init_pcie(void)
+{
+#if !PLAT_juno
+	/*
+	 * Do not initialize PCIe in emulator environment.
+	 * Platform ID register not supported on Juno
+	 */
+	if (BOARD_CSS_GET_PLAT_TYPE(BOARD_CSS_PLAT_ID_REG_ADDR) ==
+			BOARD_CSS_PLAT_TYPE_EMULATOR)
+		return;
+#endif /* PLAT_juno */
+
+	/*
+	 * PCIE Root Complex Security settings to enable non-secure
+	 * access to config registers.
+	 */
+	mmio_write_32(SOC_CSS_PCIE_CONTROL_BASE + PCIE_SECURE_REG,
+			PCIE_SEC_ACCESS_MASK);
+}
diff --git a/plat/common/aarch32/crash_console_helpers.S b/plat/common/aarch32/crash_console_helpers.S
new file mode 100644
index 0000000..ea04f56
--- /dev/null
+++ b/plat/common/aarch32/crash_console_helpers.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * If a platform wishes to use the functions in this file it has to be added to
+ * the Makefile of the platform. It is not included in the common Makefile.
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+
+	/* -----------------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Use normal console by default. Switch it to crash
+	 * mode so serial consoles become active again.
+	 * NOTE: This default implementation will only work for
+	 * crashes that occur after a normal console (marked
+	 * valid for the crash state) has been registered with
+	 * the console framework. To debug crashes that occur
+	 * earlier, the platform has to override these functions
+	 * with an implementation that initializes a console
+	 * driver with hardcoded parameters. See
+	 * docs/porting-guide.rst for more information.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_init
+#if defined(IMAGE_BL1)
+	/*
+	 * BL1 code can possibly crash so early that the data segment is not yet
+	 * accessible. Don't risk undefined behavior by trying to run the normal
+	 * console framework. Platforms that want to debug BL1 will need to
+	 * override this with custom functions that can run from registers only.
+	 */
+	mov	r0, #0
+	bx	lr
+#else	/* IMAGE_BL1 */
+	mov	r3, lr
+	mov	r0, #CONSOLE_FLAG_CRASH
+	bl	console_switch_state
+	mov	r0, #1
+	bx	r3
+#endif
+endfunc plat_crash_console_init
+
+	/* -----------------------------------------------------
+	 * void plat_crash_console_putc(int character)
+	 * Output through the normal console by default.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_putc
+	b	console_putc
+endfunc plat_crash_console_putc
+
+	/* -----------------------------------------------------
+	 * void plat_crash_console_flush(void)
+	 * Flush normal console by default.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_flush
+	b	console_flush
+endfunc plat_crash_console_flush
diff --git a/plat/common/aarch32/plat_common.c b/plat/common/aarch32/plat_common.c
new file mode 100644
index 0000000..2c1a8fa
--- /dev/null
+++ b/plat/common/aarch32/plat_common.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+/*
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak bl32_plat_enable_mmu
+
+
+void bl32_plat_enable_mmu(uint32_t flags)
+{
+	enable_mmu_svc_mon(flags);
+}
diff --git a/plat/common/aarch32/plat_sp_min_common.c b/plat/common/aarch32/plat_sp_min_common.c
new file mode 100644
index 0000000..9493587
--- /dev/null
+++ b/plat/common/aarch32/plat_sp_min_common.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+#include <platform_sp_min.h>
+
+/*
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak sp_min_plat_runtime_setup
+
+void sp_min_plat_runtime_setup(void)
+{
+	/*
+	 * Finish the use of console driver in SP_MIN so that any runtime logs
+	 * from SP_MIN will be suppressed.
+	 */
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
+}
diff --git a/plat/common/aarch32/platform_helpers.S b/plat/common/aarch32/platform_helpers.S
new file mode 100644
index 0000000..5b9cb59
--- /dev/null
+++ b/plat/common/aarch32/platform_helpers.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.weak	plat_report_exception
+	.weak	plat_reset_handler
+	.weak	plat_disable_acp
+	.weak	bl1_plat_prepare_exit
+	.weak	platform_mem_init
+	.weak	plat_panic_handler
+
+	/* -----------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform.
+	 * -----------------------------------------------------
+	 */
+func plat_report_exception
+	bx	lr
+endfunc plat_report_exception
+
+	/* -----------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform.
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	bx	lr
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform.
+	 * -----------------------------------------------------
+	 */
+func plat_disable_acp
+	bx	lr
+endfunc plat_disable_acp
+
+	/* ---------------------------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	bx	lr
+endfunc platform_mem_init
+
+	/* -----------------------------------------------------
+	 * void bl1_plat_prepare_exit(entry_point_info_t *ep_info);
+	 * Called before exiting BL1. Default: do nothing
+	 * -----------------------------------------------------
+	 */
+func bl1_plat_prepare_exit
+	bx	lr
+endfunc bl1_plat_prepare_exit
+
+	/* -----------------------------------------------------
+	 * void plat_panic_handler(void) __dead2;
+	 * Endless loop by default.
+	 * -----------------------------------------------------
+	 */
+func plat_panic_handler
+	b	plat_panic_handler
+endfunc plat_panic_handler
diff --git a/plat/common/aarch32/platform_mp_stack.S b/plat/common/aarch32/platform_mp_stack.S
new file mode 100644
index 0000000..6c3d08d
--- /dev/null
+++ b/plat/common/aarch32/platform_mp_stack.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.weak	plat_get_my_stack
+	.weak	plat_set_my_stack
+
+	/* -----------------------------------------------------
+	 * uintptr_t plat_get_my_stack (u_register_t mpidr)
+	 *
+	 * For a given CPU, this function returns the stack
+	 * pointer for a stack allocated in device memory.
+	 * -----------------------------------------------------
+	 */
+func plat_get_my_stack
+	push	{r4, lr}
+	get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	pop	{r4, pc}
+endfunc	plat_get_my_stack
+
+	/* -----------------------------------------------------
+	 * void plat_set_my_stack ()
+	 *
+	 * For the current CPU, this function sets the stack
+	 * pointer to a stack allocated in normal memory.
+	 * -----------------------------------------------------
+	 */
+func plat_set_my_stack
+	mov	r4, lr
+	get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	mov	sp, r0
+	bx	r4
+endfunc plat_set_my_stack
+
+	/* -----------------------------------------------------
+	 * Per-cpu stacks in normal memory. Each cpu gets a
+	 * stack of PLATFORM_STACK_SIZE bytes.
+	 * -----------------------------------------------------
+	 */
+declare_stack platform_normal_stacks, tzfw_normal_stacks, \
+		PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT
diff --git a/plat/common/aarch32/platform_up_stack.S b/plat/common/aarch32/platform_up_stack.S
new file mode 100644
index 0000000..836c13a
--- /dev/null
+++ b/plat/common/aarch32/platform_up_stack.S
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.weak	plat_get_my_stack
+	.weak	plat_set_my_stack
+
+	/* -----------------------------------------------------
+	 * unsigned long plat_get_my_stack ()
+	 *
+	 * For cold-boot BL images, only the primary CPU needs
+	 * a stack. This function returns the stack pointer for
+	 * a stack allocated in normal memory.
+	 * -----------------------------------------------------
+	 */
+func plat_get_my_stack
+	get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	bx	lr
+endfunc	plat_get_my_stack
+
+	/* -----------------------------------------------------
+	 * void plat_set_my_stack ()
+	 *
+	 * For cold-boot BL images, only the primary CPU needs
+	 * a stack. This function sets the stack pointer to a
+	 * stack allocated in normal memory.
+	 * -----------------------------------------------------
+	 */
+func plat_set_my_stack
+	get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	mov	sp, r0
+	bx	lr
+endfunc plat_set_my_stack
+
+	/* -----------------------------------------------------
+	 * Per-cpu stacks in normal memory. Each cpu gets a
+	 * stack of PLATFORM_STACK_SIZE bytes.
+	 * -----------------------------------------------------
+	 */
+declare_stack platform_normal_stacks, tzfw_normal_stacks, \
+		PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE
diff --git a/plat/common/aarch64/crash_console_helpers.S b/plat/common/aarch64/crash_console_helpers.S
new file mode 100644
index 0000000..2a48baf
--- /dev/null
+++ b/plat/common/aarch64/crash_console_helpers.S
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * If a platform wishes to use the functions in this file it has to be added to
+ * the Makefile of the platform. It is not included in the common Makefile.
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+
+	/*
+	 * Spinlock to syncronize access to crash_console_triggered. We cannot
+	 * acquire spinlocks when the cache is disabled, so in some cases (like
+	 * late during CPU suspend) some risk remains.
+	 */
+.section .data.crash_console_spinlock
+	define_asm_spinlock crash_console_spinlock
+
+	/*
+	 * Flag to make sure that only one CPU can write a crash dump even if
+	 * multiple crash at the same time. Interleaving crash dumps on the same
+	 * console would just make the output unreadable, so it's better to only
+	 * get a single but uncorrupted dump. This also means that we don't have
+	 * to duplicate the reg_stash below for each CPU.
+	 */
+.section .data.crash_console_triggered
+	crash_console_triggered: .byte 0
+
+	/*
+	 * Space to stash away some register values while we're calling into
+	 * console drivers and don't have a real stack available. We need x14,
+	 * x15 and x30 for bookkeeping within the plat_crash_console functions
+	 * themselves, and some console drivers use x16 and x17 as additional
+	 * scratch space that is not preserved by the main crash reporting
+	 * framework. (Note that x16 and x17 should really never be expected to
+	 * retain their values across any function call, even between carefully
+	 * designed assembly functions, since the linker is always free to
+	 * insert a function call veneer that uses these registers as scratch
+	 * space at any time. The current crash reporting framework doesn't
+	 * really respect that, but since TF is usually linked as a single
+	 * contiguous binary of less than 128MB, it seems to work in practice.)
+	 */
+.section .data.crash_console_reg_stash
+	.align 3
+	crash_console_reg_stash: .quad 0, 0, 0, 0, 0
+
+	/* --------------------------------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Takes the crash console spinlock (if possible) and checks the trigger
+	 * flag to make sure we're the first CPU to dump. If not, return an
+	 * error (so crash dumping will fail but the CPU will still call
+	 * plat_panic_handler() which may do important platform-specific tasks
+	 * that may be needed on all crashing CPUs). In either case, the lock
+	 * will be released so other CPUs can make forward progress on this.
+	 * Clobbers: x0 - x4, x30
+	 * --------------------------------------------------------------------
+	 */
+func plat_crash_console_init
+#if defined(IMAGE_BL31)
+	mov	x4, x30		/* x3 and x4 are not clobbered by spin_lock() */
+	mov	x3, #0		/* return value */
+
+	mrs	x1, sctlr_el3
+	tst	x1, #SCTLR_C_BIT
+	beq	skip_spinlock	/* can't synchronize when cache disabled */
+
+	adrp	x0, crash_console_spinlock
+	add	x0, x0, :lo12:crash_console_spinlock
+	bl	spin_lock
+
+skip_spinlock:
+	adrp	x1, crash_console_triggered
+	add	x1, x1, :lo12:crash_console_triggered
+	ldarb	w2, [x1]
+	cmp	w2, #0
+	bne	init_error
+
+	mov	x3, #1		/* set return value to success */
+	stlrb	w3, [x1]
+
+init_error:
+	bl	spin_unlock	/* harmless if we didn't acquire the lock */
+	mov	x0, x3
+	ret	x4
+#else	/* Only one CPU in BL1/BL2, no need to synchronize anything */
+	mov	x0, #1
+	ret
+#endif
+endfunc plat_crash_console_init
+
+	/* --------------------------------------------------------------------
+	 * int plat_crash_console_putc(char c)
+	 * Prints the character on all consoles registered with the console
+	 * framework that have CONSOLE_FLAG_CRASH set. Note that this is only
+	 * helpful for crashes that occur after the platform intialization code
+	 * has registered a console. Platforms using this implementation need to
+	 * ensure that all console drivers they use that have the CRASH flag set
+	 * support this (i.e. are written in assembly and comply to the register
+	 * clobber requirements of plat_crash_console_putc().
+	 * --------------------------------------------------------------------
+	 */
+func plat_crash_console_putc
+	adrp	x1, crash_console_reg_stash
+	add	x1, x1, :lo12:crash_console_reg_stash
+	stp	x14, x15, [x1]
+	stp	x16, x17, [x1, #16]
+	str	x30, [x1, #32]
+
+	mov	w14, w0				/* W14 = character to print */
+	adrp	x15, console_list
+	ldr	x15, [x15, :lo12:console_list]	/* X15 = first console struct */
+
+putc_loop:
+	cbz	x15, putc_done
+	ldr	w1, [x15, #CONSOLE_T_FLAGS]
+	tst	w1, #CONSOLE_FLAG_CRASH
+	b.eq	putc_continue
+	ldr	x2, [x15, #CONSOLE_T_PUTC]
+	cbz	x2, putc_continue
+	mov	x1, x15
+	blr	x2
+	mov	w0, w14
+putc_continue:
+	ldr	x15, [x15]			/* X15 = next struct */
+	b	putc_loop
+
+putc_done:
+	adrp	x1, crash_console_reg_stash
+	add	x1, x1, :lo12:crash_console_reg_stash
+	ldp	x14, x15, [x1]
+	ldp	x16, x17, [x1, #16]
+	ldr	x30, [x1, #32]
+	ret
+endfunc plat_crash_console_putc
+
+	/* --------------------------------------------------------------------
+	 * int plat_crash_console_flush(char c)
+	 * Flushes all consoles registered with the console framework that have
+	 * CONSOLE_FLAG_CRASH set. Same requirements as putc().
+	 * --------------------------------------------------------------------
+	 */
+func plat_crash_console_flush
+	adrp	x1, crash_console_reg_stash
+	add	x1, x1, :lo12:crash_console_reg_stash
+	stp	x30, x15, [x1]
+	stp	x16, x17, [x1, #16]
+
+	adrp	x15, console_list
+	ldr	x15, [x15, :lo12:console_list]	/* X15 = first console struct */
+
+flush_loop:
+	cbz	x15, flush_done
+	ldr	w1, [x15, #CONSOLE_T_FLAGS]
+	tst	w1, #CONSOLE_FLAG_CRASH
+	b.eq	flush_continue
+	ldr	x2, [x15, #CONSOLE_T_FLUSH]
+	cbz	x2, flush_continue
+	mov	x0, x15
+	blr	x2
+flush_continue:
+	ldr	x15, [x15]			/* X15 = next struct */
+	b	flush_loop
+
+flush_done:
+	adrp	x1, crash_console_reg_stash
+	add	x1, x1, :lo12:crash_console_reg_stash
+	ldp	x30, x15, [x1]
+	ldp	x16, x17, [x1, #16]
+	ret
+endfunc plat_crash_console_flush
diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
new file mode 100644
index 0000000..f8d3129
--- /dev/null
+++ b/plat/common/aarch64/plat_common.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/console.h>
+#if RAS_EXTENSION
+#include <lib/extensions/ras.h>
+#endif
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+/*
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak bl31_plat_runtime_setup
+
+#if SDEI_SUPPORT
+#pragma weak plat_sdei_handle_masked_trigger
+#pragma weak plat_sdei_validate_entry_point
+#endif
+
+#pragma weak plat_ea_handler
+
+void bl31_plat_runtime_setup(void)
+{
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
+}
+
+/*
+ * Helper function for platform_get_pos() when platform compatibility is
+ * disabled. This is to enable SPDs using the older platform API to continue
+ * to work.
+ */
+unsigned int platform_core_pos_helper(unsigned long mpidr)
+{
+	int idx = plat_core_pos_by_mpidr(mpidr);
+	assert(idx >= 0);
+	return idx;
+}
+
+#if SDEI_SUPPORT
+/*
+ * Function that handles spurious SDEI interrupts while events are masked.
+ */
+void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr)
+{
+	WARN("Spurious SDEI interrupt %u on masked PE %llx\n", intr, mpidr);
+}
+
+/*
+ * Default Function to validate SDEI entry point, which returns success.
+ * Platforms may override this with their own validation mechanism.
+ */
+int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode)
+{
+	return 0;
+}
+#endif
+
+/* RAS functions common to AArch64 ARM platforms */
+void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+		void *handle, uint64_t flags)
+{
+#if RAS_EXTENSION
+	/* Call RAS EA handler */
+	int handled = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
+	if (handled != 0)
+		return;
+#endif
+
+	ERROR("Unhandled External Abort received on 0x%lx at EL3!\n",
+			read_mpidr_el1());
+	ERROR(" exception reason=%u syndrome=0x%llx\n", ea_reason, syndrome);
+	panic();
+}
diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S
new file mode 100644
index 0000000..bc650c9
--- /dev/null
+++ b/plat/common/aarch64/platform_helpers.S
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/console.h>
+#include <platform_def.h>
+
+	.weak	plat_report_exception
+	.weak	plat_reset_handler
+	.weak	plat_disable_acp
+	.weak	bl1_plat_prepare_exit
+	.weak	plat_panic_handler
+	.weak	bl31_plat_enable_mmu
+	.weak	bl32_plat_enable_mmu
+
+	.weak	plat_handle_uncontainable_ea
+	.weak	plat_handle_double_fault
+	.weak	plat_handle_el3_ea
+
+#define MPIDR_RES_BIT_MASK	0xff000000
+
+	/* -----------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform.
+	 * -----------------------------------------------------
+	 */
+func plat_report_exception
+	ret
+endfunc plat_report_exception
+
+	/* -----------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform. This function should preserve x19 - x29.
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * Placeholder function which should be redefined by
+	 * each platform. This function is allowed to use
+	 * registers x0 - x17.
+	 * -----------------------------------------------------
+	 */
+func plat_disable_acp
+	ret
+endfunc plat_disable_acp
+
+	/* -----------------------------------------------------
+	 * void bl1_plat_prepare_exit(entry_point_info_t *ep_info);
+	 * Called before exiting BL1. Default: do nothing
+	 * -----------------------------------------------------
+	 */
+func bl1_plat_prepare_exit
+	ret
+endfunc bl1_plat_prepare_exit
+
+	/* -----------------------------------------------------
+	 * void plat_panic_handler(void) __dead2;
+	 * Endless loop by default.
+	 * -----------------------------------------------------
+	 */
+func plat_panic_handler
+	wfi
+	b	plat_panic_handler
+endfunc plat_panic_handler
+
+	/* -----------------------------------------------------
+	 * void bl31_plat_enable_mmu(uint32_t flags);
+	 *
+	 * Enable MMU in BL31.
+	 * -----------------------------------------------------
+	 */
+func bl31_plat_enable_mmu
+	b	enable_mmu_direct_el3
+endfunc bl31_plat_enable_mmu
+
+	/* -----------------------------------------------------
+	 * void bl32_plat_enable_mmu(uint32_t flags);
+	 *
+	 * Enable MMU in BL32.
+	 * -----------------------------------------------------
+	 */
+func bl32_plat_enable_mmu
+	b	enable_mmu_direct_el1
+endfunc bl32_plat_enable_mmu
+
+
+	/* -----------------------------------------------------
+	 * Platform handler for Uncontainable External Abort.
+	 *
+	 * x0: EA reason
+	 * x1: EA syndrome
+	 * -----------------------------------------------------
+	 */
+func plat_handle_uncontainable_ea
+	b	report_unhandled_exception
+endfunc plat_handle_uncontainable_ea
+
+	/* -----------------------------------------------------
+	 * Platform handler for Double Fault.
+	 *
+	 * x0: EA reason
+	 * x1: EA syndrome
+	 * -----------------------------------------------------
+	 */
+func plat_handle_double_fault
+	b	report_unhandled_exception
+endfunc plat_handle_double_fault
+
+	/* -----------------------------------------------------
+	 * Platform handler for EL3 External Abort.
+	 * -----------------------------------------------------
+	 */
+func plat_handle_el3_ea
+	b	report_unhandled_exception
+endfunc plat_handle_el3_ea
diff --git a/plat/common/aarch64/platform_mp_stack.S b/plat/common/aarch64/platform_mp_stack.S
new file mode 100644
index 0000000..f9780e8
--- /dev/null
+++ b/plat/common/aarch64/platform_mp_stack.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+	.local	platform_normal_stacks
+	.weak	plat_get_my_stack
+	.weak	plat_set_my_stack
+
+	/* ---------------------------------------------------------------------
+	 * When the compatility layer is disabled, the platform APIs
+	 * plat_get_my_stack() and plat_set_my_stack() are supported by the
+	 * platform and the previous APIs platform_get_stack() and
+	 * platform_set_stack() are defined in terms of new APIs making use of
+	 * the fact that they are only ever invoked for the current CPU.  This
+	 * is to enable components of Trusted Firmware like SPDs using the old
+	 * platform APIs to continue to work.
+	 * --------------------------------------------------------------------
+	 */
+
+	/* -----------------------------------------------------
+	 * uintptr_t plat_get_my_stack ()
+	 *
+	 * For the current CPU, this function returns the stack
+	 * pointer for a stack allocated in device memory.
+	 * -----------------------------------------------------
+	 */
+func plat_get_my_stack
+	mov	x10, x30 // lr
+	get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	ret	x10
+endfunc plat_get_my_stack
+
+	/* -----------------------------------------------------
+	 * void plat_set_my_stack ()
+	 *
+	 * For the current CPU, this function sets the stack
+	 * pointer to a stack allocated in normal memory.
+	 * -----------------------------------------------------
+	 */
+func plat_set_my_stack
+	mov	x9, x30 // lr
+	bl 	plat_get_my_stack
+	mov	sp, x0
+	ret	x9
+endfunc plat_set_my_stack
+
+	/* -----------------------------------------------------
+	 * Per-cpu stacks in normal memory. Each cpu gets a
+	 * stack of PLATFORM_STACK_SIZE bytes.
+	 * -----------------------------------------------------
+	 */
+declare_stack platform_normal_stacks, tzfw_normal_stacks, \
+		PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT, \
+		CACHE_WRITEBACK_GRANULE
diff --git a/plat/common/aarch64/platform_up_stack.S b/plat/common/aarch64/platform_up_stack.S
new file mode 100644
index 0000000..c6e5e2d
--- /dev/null
+++ b/plat/common/aarch64/platform_up_stack.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+
+	.local	platform_normal_stacks
+	.weak	plat_set_my_stack
+	.weak	plat_get_my_stack
+
+	/* -----------------------------------------------------
+	 * uintptr_t plat_get_my_stack ()
+	 *
+	 * For cold-boot BL images, only the primary CPU needs a
+	 * stack. This function returns the stack pointer for a
+	 * stack allocated in device memory.
+	 * -----------------------------------------------------
+	 */
+func plat_get_my_stack
+	get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	ret
+endfunc plat_get_my_stack
+
+	/* -----------------------------------------------------
+	 * void plat_set_my_stack ()
+	 *
+	 * For cold-boot BL images, only the primary CPU needs a
+	 * stack. This function sets the stack pointer to a stack
+	 * allocated in normal memory.
+	 * -----------------------------------------------------
+	 */
+func plat_set_my_stack
+	get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE
+	mov sp, x0
+	ret
+endfunc plat_set_my_stack
+
+	/* -----------------------------------------------------
+	 * Single cpu stack in normal memory.
+	 * Used for C code during boot, PLATFORM_STACK_SIZE bytes
+	 * are allocated
+	 * -----------------------------------------------------
+	 */
+declare_stack platform_normal_stacks, tzfw_normal_stacks, \
+		PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE
diff --git a/plat/common/plat_bl1_common.c b/plat/common/plat_bl1_common.c
new file mode 100644
index 0000000..5733781
--- /dev/null
+++ b/plat/common/plat_bl1_common.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/*
+ * The following platform functions are weakly defined. They
+ * are default implementations that allow BL1 to compile in
+ * absence of real definitions. The Platforms may override
+ * with more complex definitions.
+ */
+#pragma weak bl1_plat_get_next_image_id
+#pragma weak bl1_plat_set_ep_info
+#pragma weak bl1_plat_get_image_desc
+#pragma weak bl1_plat_fwu_done
+#pragma weak bl1_plat_handle_pre_image_load
+#pragma weak bl1_plat_handle_post_image_load
+
+
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	/* BL2 load will be done by default. */
+	return BL2_IMAGE_ID;
+}
+
+void bl1_plat_set_ep_info(unsigned int image_id,
+		struct entry_point_info *ep_info)
+{
+
+}
+
+int bl1_plat_handle_pre_image_load(unsigned int image_id)
+{
+	return 0;
+}
+
+/*
+ * Following is the default definition that always
+ * returns BL2 image details.
+ */
+struct image_desc *bl1_plat_get_image_desc(unsigned int image_id)
+{
+	static image_desc_t bl2_img_desc = BL2_IMAGE_DESC;
+	return &bl2_img_desc;
+}
+
+__dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved)
+{
+	while (1)
+		wfi();
+}
+
+/*
+ * The Platforms must override with real definition.
+ */
+#pragma weak bl1_plat_mem_check
+
+int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size,
+		unsigned int flags)
+{
+	assert(0);
+	return -ENOMEM;
+}
+
+/*
+ * Default implementation for bl1_plat_handle_post_image_load(). This function
+ * populates the default arguments to BL2. The BL2 memory layout structure
+ * is allocated and the calculated layout is populated in arg1 to BL2.
+ */
+int bl1_plat_handle_post_image_load(unsigned int image_id)
+{
+	meminfo_t *bl2_tzram_layout;
+	meminfo_t *bl1_tzram_layout;
+	image_desc_t *image_desc;
+	entry_point_info_t *ep_info;
+
+	if (image_id != BL2_IMAGE_ID)
+		return 0;
+
+	/* Get the image descriptor */
+	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+	assert(image_desc != NULL);
+
+	/* Get the entry point info */
+	ep_info = &image_desc->ep_info;
+
+	/* Find out how much free trusted ram remains after BL1 load */
+	bl1_tzram_layout = bl1_plat_sec_mem_layout();
+
+	/*
+	 * Create a new layout of memory for BL2 as seen by BL1 i.e.
+	 * tell it the amount of total and free memory available.
+	 * This layout is created at the first free address visible
+	 * to BL2. BL2 will read the memory layout before using its
+	 * memory for other purposes.
+	 */
+	bl2_tzram_layout = (meminfo_t *) bl1_tzram_layout->total_base;
+
+	bl1_calc_bl2_mem_layout(bl1_tzram_layout, bl2_tzram_layout);
+
+	ep_info->args.arg1 = (uintptr_t)bl2_tzram_layout;
+
+	VERBOSE("BL1: BL2 memory layout address = %p\n",
+		(void *) bl2_tzram_layout);
+	return 0;
+}
diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c
new file mode 100644
index 0000000..b46656c
--- /dev/null
+++ b/plat/common/plat_bl_common.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+#include <plat/common/platform.h>
+
+/*
+ * The following platform functions are weakly defined. The Platforms
+ * may redefine with strong definition.
+ */
+#pragma weak bl2_el3_plat_prepare_exit
+#pragma weak plat_error_handler
+#pragma weak bl2_plat_preload_setup
+#pragma weak bl2_plat_handle_pre_image_load
+#pragma weak bl2_plat_handle_post_image_load
+#pragma weak plat_try_next_boot_source
+
+void bl2_el3_plat_prepare_exit(void)
+{
+}
+
+void __dead2 plat_error_handler(int err)
+{
+	while (1)
+		wfi();
+}
+
+void bl2_plat_preload_setup(void)
+{
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+	return 0;
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return 0;
+}
+
+int plat_try_next_boot_source(void)
+{
+	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;
+ * - Code section;
+ * - Read-only data section;
+ * - Init code section, if applicable
+ * - Coherent memory region, if applicable.
+ */
+
+void __init setup_page_tables(const mmap_region_t *bl_regions,
+			      const mmap_region_t *plat_regions)
+{
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	const mmap_region_t *regions = bl_regions;
+
+	while (regions->size != 0U) {
+		VERBOSE("Region: 0x%lx - 0x%lx has attributes 0x%x\n",
+				regions->base_va,
+				regions->base_va + regions->size,
+				regions->attr);
+		regions++;
+	}
+#endif
+	/*
+	 * Map the Trusted SRAM with appropriate memory attributes.
+	 * Subsequent mappings will adjust the attributes for specific regions.
+	 */
+	mmap_add(bl_regions);
+
+	/* Now (re-)map the platform-specific memory regions */
+	mmap_add(plat_regions);
+
+	/* Create the page tables to reflect the above mappings */
+	init_xlat_tables();
+}
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
new file mode 100644
index 0000000..4c76f1b
--- /dev/null
+++ b/plat/common/plat_gicv2.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <plat/common/platform.h>
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+#pragma weak plat_ic_get_running_priority
+#pragma weak plat_ic_is_spi
+#pragma weak plat_ic_is_ppi
+#pragma weak plat_ic_is_sgi
+#pragma weak plat_ic_get_interrupt_active
+#pragma weak plat_ic_enable_interrupt
+#pragma weak plat_ic_disable_interrupt
+#pragma weak plat_ic_set_interrupt_priority
+#pragma weak plat_ic_set_interrupt_type
+#pragma weak plat_ic_raise_el3_sgi
+#pragma weak plat_ic_set_spi_routing
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+	unsigned int id;
+
+	id = gicv2_get_pending_interrupt_id();
+	if (id == GIC_SPURIOUS_INTERRUPT)
+		return INTR_ID_UNAVAILABLE;
+
+	return id;
+}
+
+/*
+ * This function returns the type of the highest priority pending interrupt
+ * at the Interrupt controller. In the case of GICv2, the Highest Priority
+ * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
+ * the pending interrupt. The type of interrupt depends upon the id value
+ * as follows.
+ *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
+ *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
+ *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
+ *           type.
+ */
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+	unsigned int id;
+
+	id = gicv2_get_pending_interrupt_type();
+
+	/* Assume that all secure interrupts are S-EL1 interrupts */
+	if (id < PENDING_G1_INTID) {
+#if GICV2_G0_FOR_EL3
+		return INTR_TYPE_EL3;
+#else
+		return INTR_TYPE_S_EL1;
+#endif
+	}
+
+	if (id == GIC_SPURIOUS_INTERRUPT)
+		return INTR_TYPE_INVAL;
+
+	return INTR_TYPE_NS;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+	return gicv2_acknowledge_interrupt();
+}
+
+/*
+ * This function returns the type of the interrupt `id`, depending on how
+ * the interrupt has been configured in the interrupt controller
+ */
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+	unsigned int type;
+
+	type = gicv2_get_interrupt_group(id);
+
+	/* Assume that all secure interrupts are S-EL1 interrupts */
+	return (type == GICV2_INTR_GROUP1) ? INTR_TYPE_NS :
+#if GICV2_G0_FOR_EL3
+		INTR_TYPE_EL3;
+#else
+		INTR_TYPE_S_EL1;
+#endif
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+	gicv2_end_of_interrupt(id);
+}
+
+/*
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. It lets the interrupt management framework determine
+ * for a type of interrupt and security state, which line should be used in the
+ * SCR_EL3 to control its routing to EL3. The interrupt line is represented
+ * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
+ */
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+				uint32_t security_state)
+{
+	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
+	       (type == INTR_TYPE_NS));
+
+	assert(sec_state_is_valid(security_state));
+
+	/* Non-secure interrupts are signaled on the IRQ line always */
+	if (type == INTR_TYPE_NS)
+		return __builtin_ctz(SCR_IRQ_BIT);
+
+	/*
+	 * Secure interrupts are signaled using the IRQ line if the FIQ is
+	 * not enabled else they are signaled using the FIQ line.
+	 */
+	return ((gicv2_is_fiq_enabled() != 0U) ? __builtin_ctz(SCR_FIQ_BIT) :
+						 __builtin_ctz(SCR_IRQ_BIT));
+}
+
+unsigned int plat_ic_get_running_priority(void)
+{
+	return gicv2_get_running_priority();
+}
+
+int plat_ic_is_spi(unsigned int id)
+{
+	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
+}
+
+int plat_ic_is_ppi(unsigned int id)
+{
+	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
+}
+
+int plat_ic_is_sgi(unsigned int id)
+{
+	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
+}
+
+unsigned int plat_ic_get_interrupt_active(unsigned int id)
+{
+	return gicv2_get_interrupt_active(id);
+}
+
+void plat_ic_enable_interrupt(unsigned int id)
+{
+	gicv2_enable_interrupt(id);
+}
+
+void plat_ic_disable_interrupt(unsigned int id)
+{
+	gicv2_disable_interrupt(id);
+}
+
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+	gicv2_set_interrupt_priority(id, priority);
+}
+
+int plat_ic_has_interrupt_type(unsigned int type)
+{
+	int has_interrupt_type = 0;
+
+	switch (type) {
+#if GICV2_G0_FOR_EL3
+	case INTR_TYPE_EL3:
+#else
+	case INTR_TYPE_S_EL1:
+#endif
+	case INTR_TYPE_NS:
+		has_interrupt_type = 1;
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return has_interrupt_type;
+}
+
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
+{
+	unsigned int gicv2_type = 0U;
+
+	/* Map canonical interrupt type to GICv2 type */
+	switch (type) {
+#if GICV2_G0_FOR_EL3
+	case INTR_TYPE_EL3:
+#else
+	case INTR_TYPE_S_EL1:
+#endif
+		gicv2_type = GICV2_INTR_GROUP0;
+		break;
+	case INTR_TYPE_NS:
+		gicv2_type = GICV2_INTR_GROUP1;
+		break;
+	default:
+		assert(0); /* Unreachable */
+		break;
+	}
+
+	gicv2_set_interrupt_type(id, gicv2_type);
+}
+
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
+{
+#if GICV2_G0_FOR_EL3
+	int id;
+
+	/* Target must be a valid MPIDR in the system */
+	id = plat_core_pos_by_mpidr(target);
+	assert(id >= 0);
+
+	/* Verify that this is a secure SGI */
+	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
+
+	gicv2_raise_sgi(sgi_num, id);
+#else
+	assert(false);
+#endif
+}
+
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+		u_register_t mpidr)
+{
+	int proc_num = 0;
+
+	switch (routing_mode) {
+	case INTR_ROUTING_MODE_PE:
+		proc_num = plat_core_pos_by_mpidr(mpidr);
+		assert(proc_num >= 0);
+		break;
+	case INTR_ROUTING_MODE_ANY:
+		/* Bit mask selecting all 8 CPUs as candidates */
+		proc_num = -1;
+		break;
+	default:
+		assert(0); /* Unreachable */
+		break;
+	}
+
+	gicv2_set_spi_routing(id, proc_num);
+}
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+	gicv2_set_interrupt_pending(id);
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+	gicv2_clear_interrupt_pending(id);
+}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+	return gicv2_set_pmr(mask);
+}
+
+unsigned int plat_ic_get_interrupt_id(unsigned int raw)
+{
+	unsigned int id = (raw & INT_ID_MASK);
+
+	if (id == GIC_SPURIOUS_INTERRUPT)
+		id = INTR_ID_UNAVAILABLE;
+
+	return id;
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
new file mode 100644
index 0000000..4a8a7ee
--- /dev/null
+++ b/plat/common/plat_gicv3.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/cassert.h>
+#include <plat/common/platform.h>
+
+#ifdef IMAGE_BL31
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+#pragma weak plat_ic_get_running_priority
+#pragma weak plat_ic_is_spi
+#pragma weak plat_ic_is_ppi
+#pragma weak plat_ic_is_sgi
+#pragma weak plat_ic_get_interrupt_active
+#pragma weak plat_ic_enable_interrupt
+#pragma weak plat_ic_disable_interrupt
+#pragma weak plat_ic_set_interrupt_priority
+#pragma weak plat_ic_set_interrupt_type
+#pragma weak plat_ic_raise_el3_sgi
+#pragma weak plat_ic_set_spi_routing
+#pragma weak plat_ic_set_interrupt_pending
+#pragma weak plat_ic_clear_interrupt_pending
+
+CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
+	(INTR_TYPE_NS == INTR_GROUP1NS) &&
+	(INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+	unsigned int irqnr;
+
+	assert(IS_IN_EL3());
+	irqnr = gicv3_get_pending_interrupt_id();
+	return gicv3_is_intr_id_special_identifier(irqnr) ?
+				INTR_ID_UNAVAILABLE : irqnr;
+}
+
+/*
+ * This function returns the type of the highest priority pending interrupt
+ * at the Interrupt controller. In the case of GICv3, the Highest Priority
+ * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine
+ * the id of the pending interrupt. The type of interrupt depends upon the
+ * id value as follows.
+ *   1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt
+ *   2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.
+ *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
+ *           type.
+ *   4. All other interrupt id's are reported as EL3 interrupt.
+ */
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+	unsigned int irqnr;
+	uint32_t type;
+
+	assert(IS_IN_EL3());
+	irqnr = gicv3_get_pending_interrupt_type();
+
+	switch (irqnr) {
+	case PENDING_G1S_INTID:
+		type = INTR_TYPE_S_EL1;
+		break;
+	case PENDING_G1NS_INTID:
+		type = INTR_TYPE_NS;
+		break;
+	case GIC_SPURIOUS_INTERRUPT:
+		type = INTR_TYPE_INVAL;
+		break;
+	default:
+		type = INTR_TYPE_EL3;
+		break;
+	}
+
+	return type;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+	assert(IS_IN_EL3());
+	return gicv3_acknowledge_interrupt();
+}
+
+/*
+ * This function returns the type of the interrupt `id`, depending on how
+ * the interrupt has been configured in the interrupt controller
+ */
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+	assert(IS_IN_EL3());
+	return gicv3_get_interrupt_type(id, plat_my_core_pos());
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+	assert(IS_IN_EL3());
+	gicv3_end_of_interrupt(id);
+}
+
+/*
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. It lets the interrupt management framework determine for a type of
+ * interrupt and security state, which line should be used in the SCR_EL3 to
+ * control its routing to EL3. The interrupt line is represented as the bit
+ * position of the IRQ or FIQ bit in the SCR_EL3.
+ */
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+				uint32_t security_state)
+{
+	assert((type == INTR_TYPE_S_EL1) ||
+	       (type == INTR_TYPE_EL3) ||
+	       (type == INTR_TYPE_NS));
+
+	assert(sec_state_is_valid(security_state));
+	assert(IS_IN_EL3());
+
+	switch (type) {
+	case INTR_TYPE_S_EL1:
+		/*
+		 * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts
+		 * and as FIQ in the NS-EL0/1/2 contexts
+		 */
+		if (security_state == SECURE)
+			return __builtin_ctz(SCR_IRQ_BIT);
+		else
+			return __builtin_ctz(SCR_FIQ_BIT);
+		assert(0); /* Unreachable */
+	case INTR_TYPE_NS:
+		/*
+		 * The Non secure interrupts will be signaled as FIQ in S-EL0/1
+		 * contexts and as IRQ in the NS-EL0/1/2 contexts.
+		 */
+		if (security_state == SECURE)
+			return __builtin_ctz(SCR_FIQ_BIT);
+		else
+			return __builtin_ctz(SCR_IRQ_BIT);
+		assert(0); /* Unreachable */
+	case INTR_TYPE_EL3:
+		/*
+		 * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and
+		 * NS-EL0/1/2 contexts
+		 */
+		return __builtin_ctz(SCR_FIQ_BIT);
+	default:
+		panic();
+	}
+}
+
+unsigned int plat_ic_get_running_priority(void)
+{
+	return gicv3_get_running_priority();
+}
+
+int plat_ic_is_spi(unsigned int id)
+{
+	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
+}
+
+int plat_ic_is_ppi(unsigned int id)
+{
+	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
+}
+
+int plat_ic_is_sgi(unsigned int id)
+{
+	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
+}
+
+unsigned int plat_ic_get_interrupt_active(unsigned int id)
+{
+	return gicv3_get_interrupt_active(id, plat_my_core_pos());
+}
+
+void plat_ic_enable_interrupt(unsigned int id)
+{
+	gicv3_enable_interrupt(id, plat_my_core_pos());
+}
+
+void plat_ic_disable_interrupt(unsigned int id)
+{
+	gicv3_disable_interrupt(id, plat_my_core_pos());
+}
+
+void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
+{
+	gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority);
+}
+
+int plat_ic_has_interrupt_type(unsigned int type)
+{
+	assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) ||
+			(type == INTR_TYPE_NS));
+	return 1;
+}
+
+void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
+{
+	gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
+}
+
+void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
+{
+	/* Target must be a valid MPIDR in the system */
+	assert(plat_core_pos_by_mpidr(target) >= 0);
+
+	/* Verify that this is a secure EL3 SGI */
+	assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) ==
+					  INTR_TYPE_EL3);
+
+	gicv3_raise_secure_g0_sgi((unsigned int)sgi_num, target);
+}
+
+void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
+		u_register_t mpidr)
+{
+	unsigned int irm = 0;
+
+	switch (routing_mode) {
+	case INTR_ROUTING_MODE_PE:
+		assert(plat_core_pos_by_mpidr(mpidr) >= 0);
+		irm = GICV3_IRM_PE;
+		break;
+	case INTR_ROUTING_MODE_ANY:
+		irm = GICV3_IRM_ANY;
+		break;
+	default:
+		assert(0); /* Unreachable */
+		break;
+	}
+
+	gicv3_set_spi_routing(id, irm, mpidr);
+}
+
+void plat_ic_set_interrupt_pending(unsigned int id)
+{
+	/* Disallow setting SGIs pending */
+	assert(id >= MIN_PPI_ID);
+	gicv3_set_interrupt_pending(id, plat_my_core_pos());
+}
+
+void plat_ic_clear_interrupt_pending(unsigned int id)
+{
+	/* Disallow setting SGIs pending */
+	assert(id >= MIN_PPI_ID);
+	gicv3_clear_interrupt_pending(id, plat_my_core_pos());
+}
+
+unsigned int plat_ic_set_priority_mask(unsigned int mask)
+{
+	return gicv3_set_pmr(mask);
+}
+
+unsigned int plat_ic_get_interrupt_id(unsigned int raw)
+{
+	unsigned int id = raw & INT_ID_MASK;
+
+	return gicv3_is_intr_id_special_identifier(id) ?
+			INTR_ID_UNAVAILABLE : id;
+}
+#endif
+#ifdef IMAGE_BL32
+
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_end_of_interrupt
+
+/* In AArch32, the secure group1 interrupts are targeted to Secure PL1 */
+#ifndef __aarch64__
+#define IS_IN_EL1()	IS_IN_SECURE()
+#endif
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+	unsigned int irqnr;
+
+	assert(IS_IN_EL1());
+	irqnr = gicv3_get_pending_interrupt_id_sel1();
+	return (irqnr == GIC_SPURIOUS_INTERRUPT) ?
+				INTR_ID_UNAVAILABLE : irqnr;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+	assert(IS_IN_EL1());
+	return gicv3_acknowledge_interrupt_sel1();
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+	assert(IS_IN_EL1());
+	gicv3_end_of_interrupt_sel1(id);
+}
+#endif
diff --git a/plat/common/plat_log_common.c b/plat/common/plat_log_common.c
new file mode 100644
index 0000000..66b9758
--- /dev/null
+++ b/plat/common/plat_log_common.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+/* Allow platforms to override the log prefix string */
+#pragma weak plat_log_get_prefix
+
+static const char *plat_prefix_str[] = {
+	"ERROR:   ", "NOTICE:  ", "WARNING: ", "INFO:    ", "VERBOSE: "};
+
+const char *plat_log_get_prefix(unsigned int log_level)
+{
+	unsigned int level;
+
+	if (log_level < LOG_LEVEL_ERROR) {
+		level = LOG_LEVEL_ERROR;
+	} else if (log_level > LOG_LEVEL_VERBOSE) {
+		level = LOG_LEVEL_VERBOSE;
+	} else {
+		level = log_level;
+	}
+
+	return plat_prefix_str[(level / 10U) - 1U];
+}
diff --git a/plat/common/plat_psci_common.c b/plat/common/plat_psci_common.c
new file mode 100644
index 0000000..16bec79
--- /dev/null
+++ b/plat/common/plat_psci_common.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <lib/pmf/pmf.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#if ENABLE_PSCI_STAT && ENABLE_PMF
+#pragma weak plat_psci_stat_accounting_start
+#pragma weak plat_psci_stat_accounting_stop
+#pragma weak plat_psci_stat_get_residency
+
+/* Ticks elapsed in one second by a signal of 1 MHz */
+#define MHZ_TICKS_PER_SEC 1000000U
+
+/* Maximum time-stamp value read from architectural counters */
+#ifdef __aarch64__
+#define MAX_TS	UINT64_MAX
+#else
+#define MAX_TS	UINT32_MAX
+#endif
+
+/* Following are used as ID's to capture time-stamp */
+#define PSCI_STAT_ID_ENTER_LOW_PWR		0
+#define PSCI_STAT_ID_EXIT_LOW_PWR		1
+#define PSCI_STAT_TOTAL_IDS			2
+
+PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS,
+	PMF_STORE_ENABLE)
+
+/*
+ * This function calculates the stats residency in microseconds,
+ * taking in account the wrap around condition.
+ */
+static u_register_t calc_stat_residency(unsigned long long pwrupts,
+	unsigned long long pwrdnts)
+{
+	/* The divisor to use to convert raw timestamp into microseconds. */
+	u_register_t residency_div;
+	u_register_t res;
+
+	/*
+	 * Calculate divisor so that it can be directly used to
+	 * convert time-stamp into microseconds.
+	 */
+	residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC;
+	assert(residency_div > 0U);
+
+	if (pwrupts < pwrdnts)
+		res = MAX_TS - pwrdnts + pwrupts;
+	else
+		res = pwrupts - pwrdnts;
+
+	return res / residency_div;
+}
+
+/*
+ * Capture timestamp before entering a low power state.
+ * No cache maintenance is required when capturing the timestamp.
+ * Cache maintenance may be needed when reading these timestamps.
+ */
+void plat_psci_stat_accounting_start(
+	__unused const psci_power_state_t *state_info)
+{
+	assert(state_info != NULL);
+	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
+		PMF_NO_CACHE_MAINT);
+}
+
+/*
+ * Capture timestamp after exiting a low power state.
+ * No cache maintenance is required when capturing the timestamp.
+ * Cache maintenance may be needed when reading these timestamps.
+ */
+void plat_psci_stat_accounting_stop(
+	__unused const psci_power_state_t *state_info)
+{
+	assert(state_info != NULL);
+	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
+		PMF_NO_CACHE_MAINT);
+}
+
+/*
+ * Calculate the residency for the given level and power state
+ * information.
+ */
+u_register_t plat_psci_stat_get_residency(unsigned int lvl,
+	const psci_power_state_t *state_info,
+	int last_cpu_idx)
+{
+	plat_local_state_t state;
+	unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
+	unsigned int pmf_flags;
+
+	assert((lvl >= PSCI_CPU_PWR_LVL) && (lvl <= PLAT_MAX_PWR_LVL));
+	assert(state_info != NULL);
+	assert(last_cpu_idx <= PLATFORM_CORE_COUNT);
+
+	if (lvl == PSCI_CPU_PWR_LVL)
+		assert((unsigned int)last_cpu_idx == plat_my_core_pos());
+
+	/*
+	 * If power down is requested, then timestamp capture will
+	 * be with caches OFF.  Hence we have to do cache maintenance
+	 * when reading the timestamp.
+	 */
+	state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
+	if (is_local_state_off(state) != 0) {
+		pmf_flags = PMF_CACHE_MAINT;
+	} else {
+		assert(is_local_state_retn(state) == 1);
+		pmf_flags = PMF_NO_CACHE_MAINT;
+	}
+
+	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
+		PSCI_STAT_ID_ENTER_LOW_PWR,
+		last_cpu_idx,
+		pmf_flags,
+		pwrdn_ts);
+
+	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
+		PSCI_STAT_ID_EXIT_LOW_PWR,
+		plat_my_core_pos(),
+		pmf_flags,
+		pwrup_ts);
+
+	return calc_stat_residency(pwrup_ts, pwrdn_ts);
+}
+#endif /* ENABLE_PSCI_STAT && ENABLE_PMF */
+
+/*
+ * The PSCI generic code uses this API to let the platform participate in state
+ * coordination during a power management operation. It compares the platform
+ * specific local power states requested by each cpu for a given power domain
+ * and returns the coordinated target power state that the domain should
+ * enter. A platform assigns a number to a local power state. This default
+ * implementation assumes that the platform assigns these numbers in order of
+ * increasing depth of the power state i.e. for two power states X & Y, if X < Y
+ * then X represents a shallower power state than Y. As a result, the
+ * coordinated target local power state for a power domain will be the minimum
+ * of the requested local power states.
+ */
+plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	plat_local_state_t target = PLAT_MAX_OFF_STATE, temp;
+	const plat_local_state_t *st = states;
+	unsigned int n = ncpu;
+
+	assert(ncpu > 0U);
+
+	do {
+		temp = *st;
+		st++;
+		if (temp < target)
+			target = temp;
+		n--;
+	} while (n > 0U);
+
+	return target;
+}
diff --git a/plat/common/plat_spm_rd.c b/plat/common/plat_spm_rd.c
new file mode 100644
index 0000000..ebd3e6d
--- /dev/null
+++ b/plat/common/plat_spm_rd.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <lib/object_pool.h>
+#include <plat/common/platform.h>
+#include <services/sp_res_desc.h>
+
+/*******************************************************************************
+ * Resource pool
+ ******************************************************************************/
+static struct sp_rd_sect_mem_region rd_mem_regions[PLAT_SPM_MEM_REGIONS_MAX];
+static OBJECT_POOL_ARRAY(rd_mem_regions_pool, rd_mem_regions);
+
+static struct sp_rd_sect_notification rd_notifs[PLAT_SPM_NOTIFICATIONS_MAX];
+static OBJECT_POOL_ARRAY(rd_notifs_pool, rd_notifs);
+
+static struct sp_rd_sect_service rd_services[PLAT_SPM_SERVICES_MAX];
+static OBJECT_POOL_ARRAY(rd_services_pool, rd_services);
+
+/*******************************************************************************
+ * Attribute section handler
+ ******************************************************************************/
+static void rd_parse_attribute(struct sp_rd_sect_attribute *attr,
+			       const void *fdt, int node)
+{
+	int rc = 0;
+
+	/* The minimum size that can be read from the DTB is 32-bit. */
+	uint32_t version, sp_type, runtime_el, exec_type;
+	uint32_t panic_policy, xlat_granule;
+
+	rc |= fdtw_read_cells(fdt, node, "version", 1, &version);
+
+	if (version != 1) {
+		ERROR("Unsupported resource description version: 0x%x\n",
+		      version);
+		panic();
+	}
+
+	rc |= fdtw_read_cells(fdt, node, "sp_type", 1, &sp_type);
+	rc |= fdtw_read_cells(fdt, node, "pe_mpidr", 1, &attr->pe_mpidr);
+	rc |= fdtw_read_cells(fdt, node, "runtime_el", 1, &runtime_el);
+	rc |= fdtw_read_cells(fdt, node, "exec_type", 1, &exec_type);
+	rc |= fdtw_read_cells(fdt, node, "panic_policy", 1, &panic_policy);
+	rc |= fdtw_read_cells(fdt, node, "xlat_granule", 1, &xlat_granule);
+	rc |= fdtw_read_cells(fdt, node, "binary_size", 1, &attr->binary_size);
+	rc |= fdtw_read_cells(fdt, node, "load_address", 2, &attr->load_address);
+	rc |= fdtw_read_cells(fdt, node, "entrypoint", 2, &attr->entrypoint);
+
+	attr->version = version;
+	attr->sp_type = sp_type;
+	attr->runtime_el = runtime_el;
+	attr->exec_type = exec_type;
+	attr->panic_policy = panic_policy;
+	attr->xlat_granule = xlat_granule;
+
+	VERBOSE(" Attribute Section:\n");
+	VERBOSE("  version: 0x%x\n", version);
+	VERBOSE("  sp_type: 0x%x\n", sp_type);
+	VERBOSE("  pe_mpidr: 0x%x\n", attr->pe_mpidr);
+	VERBOSE("  runtime_el: 0x%x\n", runtime_el);
+	VERBOSE("  exec_type: 0x%x\n", exec_type);
+	VERBOSE("  panic_policy: 0x%x\n", panic_policy);
+	VERBOSE("  xlat_granule: 0x%x\n", xlat_granule);
+	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);
+
+	if (rc) {
+		ERROR("Failed to read attribute node elements.\n");
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * Memory regions section handlers
+ ******************************************************************************/
+static void rd_parse_memory_region(struct sp_rd_sect_mem_region *rdmem,
+				   const void *fdt, int node)
+{
+	int rc = 0;
+	char name[RD_MEM_REGION_NAME_LEN];
+
+	rc |= fdtw_read_string(fdt, node, "str", (char *)&name, sizeof(name));
+	rc |= fdtw_read_cells(fdt, node, "attr", 1, &rdmem->attr);
+	rc |= fdtw_read_cells(fdt, node, "base", 2, &rdmem->base);
+	rc |= fdtw_read_cells(fdt, node, "size", 2, &rdmem->size);
+
+	size_t len = strlcpy(rdmem->name, name, RD_MEM_REGION_NAME_LEN);
+
+	if (len >= RD_MEM_REGION_NAME_LEN) {
+		WARN("Memory region name truncated: '%s'\n", name);
+	}
+
+	VERBOSE(" Memory Region:\n");
+	VERBOSE("  name: '%s'\n", rdmem->name);
+	VERBOSE("  attr: 0x%x\n", rdmem->attr);
+	VERBOSE("  base: 0x%llx\n", rdmem->base);
+	VERBOSE("  size: 0x%llx\n", rdmem->size);
+
+	if (rc) {
+		ERROR("Failed to read mem_region node elements.\n");
+		panic();
+	}
+}
+
+static void rd_parse_memory_regions(struct sp_res_desc *rd, const void *fdt,
+				    int node)
+{
+	int child;
+	struct sp_rd_sect_mem_region *rdmem, *old_rdmem;
+
+	fdt_for_each_subnode(child, fdt, node) {
+		rdmem = pool_alloc(&rd_mem_regions_pool);
+
+		/* Add element to the start of the list */
+		old_rdmem = rd->mem_region;
+		rd->mem_region = rdmem;
+		rdmem->next = old_rdmem;
+
+		rd_parse_memory_region(rdmem, fdt, child);
+	}
+
+	if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
+		ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * Notifications section handlers
+ ******************************************************************************/
+static void rd_parse_notification(struct sp_rd_sect_notification *rdnot,
+				   const void *fdt, int node)
+{
+	int rc = 0;
+
+	rc |= fdtw_read_cells(fdt, node, "attr", 1, &rdnot->attr);
+	rc |= fdtw_read_cells(fdt, node, "pe", 1, &rdnot->pe);
+
+	VERBOSE(" Notification:\n");
+	VERBOSE("  attr: 0x%x\n", rdnot->attr);
+	VERBOSE("  pe: 0x%x\n", rdnot->pe);
+
+	if (rc) {
+		ERROR("Failed to read notification node elements.\n");
+		panic();
+	}
+}
+
+static void rd_parse_notifications(struct sp_res_desc *rd, const void *fdt, int node)
+{
+	int child;
+	struct sp_rd_sect_notification *rdnot, *old_rdnot;
+
+	fdt_for_each_subnode(child, fdt, node) {
+		rdnot = pool_alloc(&rd_notifs_pool);
+
+		/* Add element to the start of the list */
+		old_rdnot = rd->notification;
+		rd->notification = rdnot;
+		rdnot->next = old_rdnot;
+
+		rd_parse_notification(rdnot, fdt, child);
+	}
+
+	if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
+		ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, child);
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * Services section handlers
+ ******************************************************************************/
+static void rd_parse_service(struct sp_rd_sect_service *rdsvc, const void *fdt,
+			     int node)
+{
+	int rc = 0;
+
+	/* The minimum size that can be read from the DTB is 32-bit. */
+	uint32_t accessibility, request_type, connection_quota;
+
+	rc |= fdtw_read_array(fdt, node, "uuid", 4, &rdsvc->uuid);
+	rc |= fdtw_read_cells(fdt, node, "accessibility", 1, &accessibility);
+	rc |= fdtw_read_cells(fdt, node, "request_type", 1, &request_type);
+	rc |= fdtw_read_cells(fdt, node, "connection_quota", 1, &connection_quota);
+	rc |= fdtw_read_cells(fdt, node, "sec_mem_size", 1, &rdsvc->secure_mem_size);
+	rc |= fdtw_read_cells(fdt, node, "interrupt_num", 1, &rdsvc->interrupt_num);
+
+	rdsvc->accessibility = accessibility;
+	rdsvc->request_type = request_type;
+	rdsvc->connection_quota = connection_quota;
+
+	VERBOSE(" Service:\n");
+	VERBOSE("  uuid: 0x%08x 0x%08x 0x%08x 0x%08x\n", rdsvc->uuid[0],
+		rdsvc->uuid[1], rdsvc->uuid[2], rdsvc->uuid[3]);
+	VERBOSE("  accessibility: 0x%x\n", accessibility);
+	VERBOSE("  request_type: 0x%x\n", request_type);
+	VERBOSE("  connection_quota: 0x%x\n", connection_quota);
+	VERBOSE("  secure_memory_size: 0x%x\n", rdsvc->secure_mem_size);
+	VERBOSE("  interrupt_num: 0x%x\n", rdsvc->interrupt_num);
+
+	if (rc) {
+		ERROR("Failed to read attribute node elements.\n");
+		panic();
+	}
+}
+
+static void rd_parse_services(struct sp_res_desc *rd, const void *fdt, int node)
+{
+	int child;
+	struct sp_rd_sect_service *rdsvc, *old_rdsvc;
+
+	fdt_for_each_subnode(child, fdt, node) {
+		rdsvc = pool_alloc(&rd_services_pool);
+
+		/* Add element to the start of the list */
+		old_rdsvc = rd->service;
+		rd->service = rdsvc;
+		rdsvc->next = old_rdsvc;
+
+		rd_parse_service(rdsvc, fdt, child);
+	}
+
+	if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) {
+		ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * Root node handler
+ ******************************************************************************/
+static void rd_parse_root(struct sp_res_desc *rd, const void *fdt, int root)
+{
+	int node;
+	char *str;
+
+	str = "attribute";
+	node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
+	if (node < 0) {
+		ERROR("Root node doesn't contain subnode '%s'\n", str);
+		panic();
+	} else {
+		rd_parse_attribute(&rd->attribute, fdt, node);
+	}
+
+	str = "memory_regions";
+	node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
+	if (node < 0) {
+		ERROR("Root node doesn't contain subnode '%s'\n", str);
+		panic();
+	} else {
+		rd_parse_memory_regions(rd, fdt, node);
+	}
+
+	str = "notifications";
+	node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
+	if (node < 0) {
+		WARN("Root node doesn't contain subnode '%s'\n", str);
+	} else {
+		rd_parse_notifications(rd, fdt, node);
+	}
+
+	str = "services";
+	node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str));
+	if (node < 0) {
+		WARN("Root node doesn't contain subnode '%s'\n", str);
+	} else {
+		rd_parse_services(rd, fdt, node);
+	}
+}
+
+/*******************************************************************************
+ * Platform handler to load resource descriptor blobs into the active Secure
+ * Partition context.
+ ******************************************************************************/
+int plat_spm_sp_rd_load(struct sp_res_desc *rd, const void *ptr, size_t size)
+{
+	int rc;
+	int root_node;
+
+	assert(rd != NULL);
+	assert(ptr != NULL);
+
+	INFO("Reading RD blob at address %p\n", ptr);
+
+	rc = fdt_check_header(ptr);
+	if (rc != 0) {
+		ERROR("Wrong format for resource descriptor blob (%d).\n", rc);
+		return -1;
+	}
+
+	root_node = fdt_node_offset_by_compatible(ptr, -1, "arm,sp_rd");
+	if (root_node < 0) {
+		ERROR("Unrecognized resource descriptor blob (%d)\n", rc);
+		return -1;
+	}
+
+	rd_parse_root(rd, ptr, root_node);
+
+	return 0;
+}
diff --git a/plat/common/plat_spm_sp.c b/plat/common/plat_spm_sp.c
new file mode 100644
index 0000000..bc3d6a0
--- /dev/null
+++ b/plat/common/plat_spm_sp.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+#include <tools_share/sptool.h>
+
+static unsigned int sp_next;
+
+/*******************************************************************************
+ * Platform handler get the address of a Secure Partition and its resource
+ * description blob. It iterates through all SPs detected by the platform. If
+ * there is information for another SP, it returns 0. If there are no more SPs,
+ * it returns -1.
+ ******************************************************************************/
+int plat_spm_sp_get_next_address(void **sp_base, size_t *sp_size,
+				 void **rd_base, size_t *rd_size)
+{
+	assert((sp_base != NULL) && (sp_size != NULL));
+	assert((rd_base != NULL) && (rd_base != NULL));
+
+	const uint64_t *pkg_base = (uint64_t *)PLAT_SP_PACKAGE_BASE;
+
+	struct sp_pkg_header *pkg_header = (struct sp_pkg_header *)pkg_base;
+
+	if (sp_next == 0) {
+		if (pkg_header->version != 0x1) {
+			ERROR("SP package has an unsupported version 0x%llx\n",
+			      pkg_header->version);
+			panic();
+		}
+	}
+
+	if (sp_next >= pkg_header->number_of_sp) {
+		/* No more partitions in the package */
+		return -1;
+	}
+
+	const struct sp_pkg_entry *entry_list =
+		(const struct sp_pkg_entry *)((uintptr_t)pkg_base
+					       + sizeof(struct sp_pkg_header));
+
+	const struct sp_pkg_entry *entry = &(entry_list[sp_next]);
+
+	uint64_t sp_offset = entry->sp_offset;
+	uint64_t rd_offset = entry->rd_offset;
+
+	uintptr_t pkg_sp_base = ((uintptr_t)PLAT_SP_PACKAGE_BASE + sp_offset);
+	uintptr_t pkg_rd_base = ((uintptr_t)PLAT_SP_PACKAGE_BASE + rd_offset);
+
+	uint64_t pkg_sp_size = entry->sp_size;
+	uint64_t pkg_rd_size = entry->rd_size;
+
+	uintptr_t pkg_end = (uintptr_t)PLAT_SP_PACKAGE_BASE
+			  + (uintptr_t)PLAT_SP_PACKAGE_SIZE - 1U;
+
+	/*
+	 * Check for overflows. The package header isn't trusted, so assert()
+	 * can't be used here.
+	 */
+
+	uintptr_t pkg_sp_end = pkg_sp_base + pkg_sp_size - 1U;
+	uintptr_t pkg_rd_end = pkg_rd_base + pkg_rd_size - 1U;
+
+	if ((pkg_sp_end > pkg_end) || (pkg_sp_end < pkg_sp_base)) {
+		ERROR("Invalid Secure Partition size (0x%llx)\n", pkg_sp_size);
+		panic();
+	}
+
+	if ((pkg_rd_end > pkg_end) || (pkg_rd_end < pkg_rd_base)) {
+		ERROR("Invalid Resource Description blob size (0x%llx)\n",
+		      pkg_rd_size);
+		panic();
+	}
+
+	/* Return location of the binaries. */
+
+	*sp_base = (void *)pkg_sp_base;
+	*sp_size = pkg_sp_size;
+	*rd_base = (void *)pkg_rd_base;
+	*rd_size = pkg_rd_size;
+
+	sp_next++;
+
+	return 0;
+}
diff --git a/plat/common/tbbr/plat_tbbr.c b/plat/common/tbbr/plat_tbbr.c
new file mode 100644
index 0000000..12ab0a9
--- /dev/null
+++ b/plat/common/tbbr/plat_tbbr.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <drivers/auth/auth_mod.h>
+#include <plat/common/platform.h>
+#if USE_TBBR_DEFS
+#include <tools_share/tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+/*
+ * Store a new non-volatile counter value. This implementation
+ * only allows updating of the platform's Trusted NV counter when a
+ * certificate protected by the Trusted NV counter is signed with
+ * the ROT key. This avoids a compromised secondary certificate from
+ * updating the platform's Trusted NV counter, which could lead to the
+ * platform becoming unusable. The function is suitable for all TBBR
+ * compliant platforms.
+ *
+ * Return: 0 = success, Otherwise = error
+ */
+int plat_set_nv_ctr2(void *cookie, const auth_img_desc_t *img_desc,
+		unsigned int nv_ctr)
+{
+	int trusted_nv_ctr;
+
+	assert(cookie != NULL);
+	assert(img_desc != NULL);
+
+	trusted_nv_ctr = strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0;
+
+	/*
+	 * Only update the Trusted NV Counter if the certificate
+	 * has been signed with the ROT key. Non Trusted NV counter
+	 * updates are unconditional.
+	 */
+	if (!trusted_nv_ctr || img_desc->parent == NULL)
+		return plat_set_nv_ctr(cookie, nv_ctr);
+
+	/*
+	 * Trusted certificates not signed with the ROT key are not
+	 * allowed to update the Trusted NV Counter.
+	 */
+	return 1;
+}
diff --git a/plat/hisilicon/hikey/aarch64/hikey_common.c b/plat/hisilicon/hikey/aarch64/hikey_common.c
new file mode 100644
index 0000000..702fc2d
--- /dev/null
+++ b/plat/hisilicon/hikey/aarch64/hikey_common.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <hikey_def.h>
+#include <hikey_layout.h>
+
+#define MAP_DDR		MAP_REGION_FLAT(DDR_BASE,			\
+					DDR_SIZE - DDR_SEC_SIZE,	\
+					MT_DEVICE | MT_RW | MT_NS)
+
+#define MAP_DEVICE	MAP_REGION_FLAT(DEVICE_BASE,			\
+					DEVICE_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_TSP_MEM	MAP_REGION_FLAT(TSP_SEC_MEM_BASE,		\
+					TSP_SEC_MEM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_ROM_PARAM	MAP_REGION_FLAT(XG2RAM0_BASE,			\
+					BL1_XG2RAM0_OFFSET,		\
+					MT_DEVICE | MT_RO | MT_SECURE)
+
+#define MAP_SRAM	MAP_REGION_FLAT(SRAM_BASE,			\
+					SRAM_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * BL1 needs to access the areas of MMC_SRAM.
+ * BL1 loads BL2 from eMMC into SRAM before DDR initialized.
+ */
+#define MAP_MMC_SRAM	MAP_REGION_FLAT(HIKEY_BL1_MMC_DESC_BASE,	\
+					HIKEY_BL1_MMC_DESC_SIZE +	\
+					HIKEY_BL1_MMC_DATA_SIZE,	\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * hikey_init_mmu_elx() will give the available subset of that,
+ */
+#ifdef IMAGE_BL1
+static const mmap_region_t hikey_mmap[] = {
+	MAP_DEVICE,
+	MAP_ROM_PARAM,
+	MAP_MMC_SRAM,
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL2
+static const mmap_region_t hikey_mmap[] = {
+	MAP_DDR,
+	MAP_DEVICE,
+	MAP_TSP_MEM,
+	MAP_SRAM,
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL31
+static const mmap_region_t hikey_mmap[] = {
+	MAP_DEVICE,
+	MAP_SRAM,
+	MAP_TSP_MEM,
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL32
+static const mmap_region_t hikey_mmap[] = {
+	MAP_DEVICE,
+	MAP_DDR,
+	{0}
+};
+#endif
+
+/*
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ */
+#define HIKEY_CONFIGURE_MMU_EL(_el)				\
+	void hikey_init_mmu_el##_el(unsigned long total_base,	\
+				  unsigned long total_size,	\
+				  unsigned long ro_start,	\
+				  unsigned long ro_limit,	\
+				  unsigned long coh_start,	\
+				  unsigned long coh_limit)	\
+	{							\
+	       mmap_add_region(total_base, total_base,		\
+			       total_size,			\
+			       MT_MEMORY | MT_RW | MT_SECURE);	\
+	       mmap_add_region(ro_start, ro_start,		\
+			       ro_limit - ro_start,		\
+			       MT_MEMORY | MT_RO | MT_SECURE);	\
+	       mmap_add_region(coh_start, coh_start,		\
+			       coh_limit - coh_start,		\
+			       MT_DEVICE | MT_RW | MT_SECURE);	\
+	       mmap_add(hikey_mmap);				\
+	       init_xlat_tables();				\
+								\
+	       enable_mmu_el##_el(0);				\
+	}
+
+/* Define EL1 and EL3 variants of the function initialising the MMU */
+HIKEY_CONFIGURE_MMU_EL(1)
+HIKEY_CONFIGURE_MMU_EL(3)
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+	return HIKEY_NS_IMAGE_OFFSET;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 1200000;
+}
diff --git a/plat/hisilicon/hikey/aarch64/hikey_helpers.S b/plat/hisilicon/hikey/aarch64/hikey_helpers.S
new file mode 100644
index 0000000..1752d3b
--- /dev/null
+++ b/plat/hisilicon/hikey/aarch64/hikey_helpers.S
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <hikey_def.h>
+
+	.globl	plat_my_core_pos
+	.globl	platform_mem_init
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	plat_report_exception
+	.globl	plat_reset_handler
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void platform_mem_init(void);
+	 *
+	 * We don't need to carry out any memory initialization
+	 * on HIKEY. The Secure RAM is accessible straight away.
+	 * -----------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	mov_imm	x1, PL011_UART_CLK_IN_HZ
+	mov_imm	x2, PL011_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, CRASH_CONSOLE_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * On HIKEY platform, it updates the LEDs
+	 * to indicate where we are
+	 * ---------------------------------------------
+	 */
+func plat_report_exception
+	mov	x8, x30
+
+	/* Turn on LED according to x0 (0 -- f) */
+	ldr	x2, =0xf7020000
+	and	x1, x0, #1
+	str	w1, [x2, #4]
+	and	x1, x0, #2
+	str	w1, [x2, #8]
+	and	x1, x0, #4
+	str	w1, [x2, #16]
+	and	x1, x0, #8
+	str	w1, [x2, #32]
+
+	mrs	x2, currentel
+	and	x2, x2, #0xc0
+	/* Check EL1 */
+	cmp	x2, #0x04
+	beq	plat_report_el1
+
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el3
+	bl	asm_print_hex
+
+	adr	x4, elr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el3
+	bl	asm_print_hex
+	b	plat_report_end
+
+plat_report_el1:
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el1
+	bl	asm_print_hex
+
+	adr	x4, elr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el1
+	bl	asm_print_hex
+plat_report_end:
+	mov	x30, x8
+	ret
+endfunc plat_report_exception
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
+
+.section .rodata.rev_err_str, "aS"
+plat_err_str:
+	.asciz "\nPlatform exception reporting:"
+esr_el3_str:
+	.asciz "\nESR_EL3: "
+elr_el3_str:
+	.asciz "\nELR_EL3: "
+esr_el1_str:
+	.asciz "\nESR_EL1: "
+elr_el1_str:
+	.asciz "\nELR_EL1: "
diff --git a/plat/hisilicon/hikey/hikey_bl1_setup.c b/plat/hisilicon/hikey/hikey_bl1_setup.c
new file mode 100644
index 0000000..a97d763
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl1_setup.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+#include <hikey_def.h>
+#include <hikey_layout.h>
+
+#include "hikey_private.h"
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+static console_pl011_t console;
+
+enum {
+	BOOT_NORMAL = 0,
+	BOOT_USB_DOWNLOAD,
+	BOOT_UART_DOWNLOAD,
+};
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*
+ * Perform any BL1 specific platform actions.
+ */
+void bl1_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(CONSOLE_BASE, PL011_UART_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL1_RW_BASE;
+	bl1_tzram_layout.total_size = BL1_RW_SIZE;
+
+	INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+	     BL1_RAM_LIMIT - BL1_RAM_BASE); /* bl1_size */
+}
+
+/*
+ * Perform the very early platform specific architecture setup here. At the
+ * moment this only does basic initialization. Later architectural setup
+ * (bl1_arch_setup()) does not do anything platform specific.
+ */
+void bl1_plat_arch_setup(void)
+{
+	hikey_init_mmu_el3(bl1_tzram_layout.total_base,
+			   bl1_tzram_layout.total_size,
+			   BL1_RO_BASE,
+			   BL1_RO_LIMIT,
+			   BL_COHERENT_RAM_BASE,
+			   BL_COHERENT_RAM_END);
+}
+
+/*
+ * Function which will perform any remaining platform-specific setup that can
+ * occur after the MMU and data cache have been enabled.
+ */
+void bl1_platform_setup(void)
+{
+	dw_mmc_params_t params;
+	struct mmc_device_info info;
+
+	assert((HIKEY_BL1_MMC_DESC_BASE >= SRAM_BASE) &&
+	       ((SRAM_BASE + SRAM_SIZE) >=
+		(HIKEY_BL1_MMC_DATA_BASE + HIKEY_BL1_MMC_DATA_SIZE)));
+	hikey_sp804_init();
+	hikey_gpio_init();
+	hikey_pmussi_init();
+	hikey_hi6553_init();
+
+	hikey_rtc_init();
+
+	hikey_mmc_pll_init();
+
+	memset(&params, 0, sizeof(dw_mmc_params_t));
+	params.reg_base = DWMMC0_BASE;
+	params.desc_base = HIKEY_BL1_MMC_DESC_BASE;
+	params.desc_size = 1 << 20;
+	params.clk_rate = 24 * 1000 * 1000;
+	params.bus_width = MMC_BUS_WIDTH_8;
+	params.flags = MMC_FLAG_CMD23;
+	info.mmc_dev_type = MMC_IS_EMMC;
+	dw_mmc_init(&params, &info);
+
+	hikey_io_setup();
+}
+
+/*
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or not.
+ */
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	int32_t boot_mode;
+	unsigned int ret;
+
+	boot_mode = mmio_read_32(ONCHIPROM_PARAM_BASE);
+	switch (boot_mode) {
+	case BOOT_USB_DOWNLOAD:
+	case BOOT_UART_DOWNLOAD:
+		ret = NS_BL1U_IMAGE_ID;
+		break;
+	default:
+		WARN("Invalid boot mode is found:%d\n", boot_mode);
+		panic();
+	}
+	return ret;
+}
+
+image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
+{
+	unsigned int index = 0;
+
+	while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
+		if (bl1_tbbr_image_descs[index].image_id == image_id)
+			return &bl1_tbbr_image_descs[index];
+
+		index++;
+	}
+
+	return NULL;
+}
+
+void bl1_plat_set_ep_info(unsigned int image_id,
+		entry_point_info_t *ep_info)
+{
+	uint64_t data = 0;
+
+	if (image_id == BL2_IMAGE_ID)
+		panic();
+	inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE);
+	__asm__ volatile ("mrs	%0, cpacr_el1" : "=r"(data));
+	do {
+		data |= 3 << 20;
+		__asm__ volatile ("msr	cpacr_el1, %0" : : "r"(data));
+		__asm__ volatile ("mrs	%0, cpacr_el1" : "=r"(data));
+	} while ((data & (3 << 20)) != (3 << 20));
+	INFO("cpacr_el1:0x%llx\n", data);
+
+	ep_info->args.arg0 = 0xffff & read_mpidr();
+	ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS);
+}
diff --git a/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c b/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c
new file mode 100644
index 0000000..4e013a0
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>	/* also includes hikey_def.h and hikey_layout.h*/
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+    {
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+#endif /* SCP_BL2_BASE */
+
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = EL3_PAYLOAD_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t,
+		    IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL31_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+	    .ep_info.args.arg1 = HIKEY_BL31_PLAT_PARAM_VAL,
+#endif
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL31_BASE,
+	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+	    .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+    },
+
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+    {
+	    .image_id = BL32_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
+	    .ep_info.pc = BL32_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+    },
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the pager image.
+	 */
+    {
+	    .image_id = BL32_EXTRA1_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the paged image.
+	 */
+    {
+	    .image_id = BL32_EXTRA2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+#ifdef SPD_opteed
+	    .image_info.image_base = HIKEY_OPTEE_PAGEABLE_LOAD_BASE,
+	    .image_info.image_max_size = HIKEY_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+    {
+	    .image_id = BL33_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+	    .ep_info.pc = PRELOADED_BL33_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+# else
+	    .ep_info.pc = HIKEY_NS_IMAGE_OFFSET,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = HIKEY_NS_IMAGE_OFFSET,
+	    .image_info.image_max_size = 0x200000 /* 2MB */,
+# endif /* PRELOADED_BL33_BASE */
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    }
+#endif /* EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/hisilicon/hikey/hikey_bl2_setup.c b/plat/hisilicon/hikey/hikey_bl2_setup.c
new file mode 100644
index 0000000..2f96efc
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl2_setup.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>	/* also includes hikey_def.h and hikey_layout.h*/
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#ifdef SPD_opteed
+#include <lib/optee_utils.h>
+#endif
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+#include <hisi_mcu.h>
+#include <hisi_sram_map.h>
+#include "hikey_private.h"
+
+#define BL2_RW_BASE		(BL_CODE_END)
+
+static meminfo_t bl2_el3_tzram_layout;
+static console_pl011_t console;
+
+enum {
+	BOOT_MODE_RECOVERY = 0,
+	BOOT_MODE_NORMAL,
+	BOOT_MODE_MASK = 1,
+};
+
+/*******************************************************************************
+ * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
+ * Return 0 on success, -1 otherwise.
+ ******************************************************************************/
+int plat_hikey_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	/* Enable MCU SRAM */
+	hisi_mcu_enable_sram();
+
+	/* Load MCU binary into SRAM */
+	hisi_mcu_load_image(scp_bl2_image_info->image_base,
+			    scp_bl2_image_info->image_size);
+	/* Let MCU running */
+	hisi_mcu_start_run();
+
+	INFO("%s: MCU PC is at 0x%x\n",
+	     __func__, mmio_read_32(AO_SC_MCU_SUBSYS_STAT2));
+	INFO("%s: AO_SC_PERIPH_CLKSTAT4 is 0x%x\n",
+	     __func__, mmio_read_32(AO_SC_PERIPH_CLKSTAT4));
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t hikey_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL3-2 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+#ifdef __aarch64__
+uint32_t hikey_get_spsr_for_bl33_entry(void)
+{
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#else
+uint32_t hikey_get_spsr_for_bl33_entry(void)
+{
+	unsigned int hyp_status, mode, spsr;
+
+	hyp_status = GET_VIRT_EXT(read_id_pfr1());
+
+	mode = (hyp_status) ? MODE32_hyp : MODE32_svc;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1,
+			SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#endif /* __aarch64__ */
+
+int hikey_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#ifdef SPD_opteed
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+	assert(bl_mem_params);
+
+	switch (image_id) {
+#ifdef __aarch64__
+	case BL32_IMAGE_ID:
+#ifdef SPD_opteed
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+				&pager_mem_params->image_info,
+				&paged_mem_params->image_info);
+		if (err != 0) {
+			WARN("OPTEE header parse error.\n");
+		}
+#endif
+		bl_mem_params->ep_info.spsr = hikey_get_spsr_for_bl32_entry();
+		break;
+#endif
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = hikey_get_spsr_for_bl33_entry();
+		break;
+
+#ifdef SCP_BL2_BASE
+	case SCP_BL2_IMAGE_ID:
+		/* The subsequent handling of SCP_BL2 is platform specific */
+		err = plat_hikey_bl2_handle_scp_bl2(&bl_mem_params->image_info);
+		if (err) {
+			WARN("Failure in platform-specific handling of SCP_BL2 image.\n");
+		}
+		break;
+#endif
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return hikey_bl2_handle_post_image_load(image_id);
+}
+
+static void reset_dwmmc_clk(void)
+{
+	unsigned int data;
+
+	/* disable mmc0 bus clock */
+	mmio_write_32(PERI_SC_PERIPH_CLKDIS0, PERI_CLK0_MMC0);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (data & PERI_CLK0_MMC0);
+	/* enable mmc0 bus clock */
+	mmio_write_32(PERI_SC_PERIPH_CLKEN0, PERI_CLK0_MMC0);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (!(data & PERI_CLK0_MMC0));
+	/* reset mmc0 clock domain */
+	mmio_write_32(PERI_SC_PERIPH_RSTEN0, PERI_RST0_MMC0);
+
+	/* bypass mmc0 clock phase */
+	data = mmio_read_32(PERI_SC_PERIPH_CTRL2);
+	data |= 3;
+	mmio_write_32(PERI_SC_PERIPH_CTRL2, data);
+
+	/* disable low power */
+	data = mmio_read_32(PERI_SC_PERIPH_CTRL13);
+	data |= 1 << 3;
+	mmio_write_32(PERI_SC_PERIPH_CTRL13, data);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0);
+	} while (!(data & PERI_RST0_MMC0));
+
+	/* unreset mmc0 clock domain */
+	mmio_write_32(PERI_SC_PERIPH_RSTDIS0, PERI_RST0_MMC0);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0);
+	} while (data & PERI_RST0_MMC0);
+}
+
+static void hikey_boardid_init(void)
+{
+	u_register_t midr;
+
+	midr = read_midr();
+	mmio_write_32(MEMORY_AXI_CHIP_ADDR, midr);
+	INFO("[BDID] [%x] midr: 0x%x\n", MEMORY_AXI_CHIP_ADDR,
+	     (unsigned int)midr);
+
+	mmio_write_32(MEMORY_AXI_BOARD_TYPE_ADDR, 0);
+	mmio_write_32(MEMORY_AXI_BOARD_ID_ADDR, 0x2b);
+
+	mmio_write_32(ACPU_ARM64_FLAGA, 0x1234);
+	mmio_write_32(ACPU_ARM64_FLAGB, 0x5678);
+}
+
+static void hikey_sd_init(void)
+{
+	/* switch pinmux to SD */
+	mmio_write_32(IOMG_SD_CLK, IOMG_MUX_FUNC0);
+	mmio_write_32(IOMG_SD_CMD, IOMG_MUX_FUNC0);
+	mmio_write_32(IOMG_SD_DATA0, IOMG_MUX_FUNC0);
+	mmio_write_32(IOMG_SD_DATA1, IOMG_MUX_FUNC0);
+	mmio_write_32(IOMG_SD_DATA2, IOMG_MUX_FUNC0);
+	mmio_write_32(IOMG_SD_DATA3, IOMG_MUX_FUNC0);
+
+	mmio_write_32(IOCG_SD_CLK, IOCG_INPUT_16MA);
+	mmio_write_32(IOCG_SD_CMD, IOCG_INPUT_12MA);
+	mmio_write_32(IOCG_SD_DATA0, IOCG_INPUT_12MA);
+	mmio_write_32(IOCG_SD_DATA1, IOCG_INPUT_12MA);
+	mmio_write_32(IOCG_SD_DATA2, IOCG_INPUT_12MA);
+	mmio_write_32(IOCG_SD_DATA3, IOCG_INPUT_12MA);
+
+	/* set SD Card detect as nopull */
+	mmio_write_32(IOCG_GPIO8, 0);
+}
+
+static void hikey_jumper_init(void)
+{
+	/* set jumper detect as nopull */
+	mmio_write_32(IOCG_GPIO24, 0);
+	/* set jumper detect as GPIO */
+	mmio_write_32(IOMG_GPIO24, IOMG_MUX_FUNC0);
+}
+
+void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2,
+				  u_register_t arg3, u_register_t arg4)
+{
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(CONSOLE_BASE, PL011_UART_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+	/*
+	 * Allow BL2 to see the whole Trusted RAM.
+	 */
+	bl2_el3_tzram_layout.total_base = BL2_RW_BASE;
+	bl2_el3_tzram_layout.total_size = BL31_LIMIT - BL2_RW_BASE;
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+	hikey_init_mmu_el3(bl2_el3_tzram_layout.total_base,
+			   bl2_el3_tzram_layout.total_size,
+			   BL_CODE_BASE,
+			   BL_CODE_END,
+			   BL_COHERENT_RAM_BASE,
+			   BL_COHERENT_RAM_END);
+}
+
+void bl2_platform_setup(void)
+{
+	dw_mmc_params_t params;
+	struct mmc_device_info info;
+
+	hikey_sp804_init();
+	hikey_gpio_init();
+	hikey_pmussi_init();
+	hikey_hi6553_init();
+	/* Clear SRAM since it'll be used by MCU right now. */
+	memset((void *)SRAM_BASE, 0, SRAM_SIZE);
+
+	dsb();
+	hikey_ddr_init(DDR_FREQ_800M);
+	hikey_security_setup();
+
+	hikey_boardid_init();
+	init_acpu_dvfs();
+	hikey_rtc_init();
+	hikey_sd_init();
+	hikey_jumper_init();
+
+	hikey_mmc_pll_init();
+
+	/* Clean SRAM before MCU used */
+	clean_dcache_range(SRAM_BASE, SRAM_SIZE);
+
+	reset_dwmmc_clk();
+	memset(&params, 0, sizeof(dw_mmc_params_t));
+	params.reg_base = DWMMC0_BASE;
+	params.desc_base = HIKEY_MMC_DESC_BASE;
+	params.desc_size = 1 << 20;
+	params.clk_rate = 24 * 1000 * 1000;
+	params.bus_width = MMC_BUS_WIDTH_8;
+	params.flags = MMC_FLAG_CMD23;
+	info.mmc_dev_type = MMC_IS_EMMC;
+	dw_mmc_init(&params, &info);
+
+	hikey_io_setup();
+}
diff --git a/plat/hisilicon/hikey/hikey_bl31_setup.c b/plat/hisilicon/hikey/hikey_bl31_setup.c
new file mode 100644
index 0000000..0326e9f
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl31_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+#include <hikey_def.h>
+#include <hisi_ipc.h>
+#include <hisi_pwrc.h>
+
+#include "hikey_private.h"
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+static console_pl011_t console;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t g0_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+/*
+ * Ideally `arm_gic_data` structure definition should be a `const` but it is
+ * kept as modifiable for overwriting with different GICD and GICC base when
+ * running on FVP with VE memory map.
+ */
+gicv2_driver_data_t hikey_gic_data = {
+	.gicd_base = PLAT_ARM_GICD_BASE,
+	.gicc_base = PLAT_ARM_GICC_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+static const int cci_map[] = {
+	CCI400_SL_IFACE3_CLUSTER_IX,
+	CCI400_SL_IFACE4_CLUSTER_IX
+};
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	return NULL;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	void *from_bl2;
+
+	from_bl2 = (void *) arg0;
+
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(CONSOLE_BASE, PL011_UART_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Initialize CCI driver */
+	cci_init(CCI400_BASE, cci_map, ARRAY_SIZE(cci_map));
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_ep_info.pc == 0)
+		panic();
+}
+
+void bl31_plat_arch_setup(void)
+{
+	hikey_init_mmu_el3(BL31_BASE,
+			   BL31_LIMIT - BL31_BASE,
+			   BL_CODE_BASE,
+			   BL_CODE_END,
+			   BL_COHERENT_RAM_BASE,
+			   BL_COHERENT_RAM_END);
+}
+
+/* Initialize EDMAC controller with non-secure mode. */
+static void hikey_edma_init(void)
+{
+	int i;
+	uint32_t non_secure;
+
+	non_secure = EDMAC_SEC_CTRL_INTR_SEC | EDMAC_SEC_CTRL_GLOBAL_SEC;
+	mmio_write_32(EDMAC_SEC_CTRL, non_secure);
+
+	for (i = 0; i < EDMAC_CHANNEL_NUMS; i++) {
+		mmio_write_32(EDMAC_AXI_CONF(i), (1 << 6) | (1 << 18));
+	}
+}
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	hikey_edma_init();
+
+	hisi_ipc_init();
+	hisi_pwrc_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+}
diff --git a/plat/hisilicon/hikey/hikey_bl_common.c b/plat/hisilicon/hikey/hikey_bl_common.c
new file mode 100644
index 0000000..d062de4
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_bl_common.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+#include <hi6553.h>
+#include "hikey_private.h"
+
+void hikey_sp804_init(void)
+{
+	uint32_t data;
+
+	/* select the clock of dual timer0 */
+	data = mmio_read_32(AO_SC_TIMER_EN0);
+	while (data & 3) {
+		data &= ~3;
+		data |= 3 << 16;
+		mmio_write_32(AO_SC_TIMER_EN0, data);
+		data = mmio_read_32(AO_SC_TIMER_EN0);
+	}
+	/* enable the pclk of dual timer0 */
+	data = mmio_read_32(AO_SC_PERIPH_CLKSTAT4);
+	while (!(data & PCLK_TIMER1) || !(data & PCLK_TIMER0)) {
+		mmio_write_32(AO_SC_PERIPH_CLKEN4, PCLK_TIMER1 | PCLK_TIMER0);
+		data = mmio_read_32(AO_SC_PERIPH_CLKSTAT4);
+	}
+	/* reset dual timer0 */
+	data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4);
+	mmio_write_32(AO_SC_PERIPH_RSTEN4, PCLK_TIMER1 | PCLK_TIMER0);
+	do {
+		data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4);
+	} while (!(data & PCLK_TIMER1) || !(data & PCLK_TIMER0));
+	/* unreset dual timer0 */
+	mmio_write_32(AO_SC_PERIPH_RSTDIS4, PCLK_TIMER1 | PCLK_TIMER0);
+	do {
+		data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4);
+	} while ((data & PCLK_TIMER1) || (data & PCLK_TIMER0));
+
+	sp804_timer_init(SP804_TIMER0_BASE, 10, 192);
+}
+
+void hikey_gpio_init(void)
+{
+	pl061_gpio_init();
+	pl061_gpio_register(GPIO0_BASE, 0);
+	pl061_gpio_register(GPIO1_BASE, 1);
+	pl061_gpio_register(GPIO2_BASE, 2);
+	pl061_gpio_register(GPIO3_BASE, 3);
+	pl061_gpio_register(GPIO4_BASE, 4);
+	pl061_gpio_register(GPIO5_BASE, 5);
+	pl061_gpio_register(GPIO6_BASE, 6);
+	pl061_gpio_register(GPIO7_BASE, 7);
+	pl061_gpio_register(GPIO8_BASE, 8);
+	pl061_gpio_register(GPIO9_BASE, 9);
+	pl061_gpio_register(GPIO10_BASE, 10);
+	pl061_gpio_register(GPIO11_BASE, 11);
+	pl061_gpio_register(GPIO12_BASE, 12);
+	pl061_gpio_register(GPIO13_BASE, 13);
+	pl061_gpio_register(GPIO14_BASE, 14);
+	pl061_gpio_register(GPIO15_BASE, 15);
+	pl061_gpio_register(GPIO16_BASE, 16);
+	pl061_gpio_register(GPIO17_BASE, 17);
+	pl061_gpio_register(GPIO18_BASE, 18);
+	pl061_gpio_register(GPIO19_BASE, 19);
+
+	/* Power on indicator LED (USER_LED1). */
+	gpio_set_direction(32, GPIO_DIR_OUT);	/* LED1 */
+	gpio_set_value(32, GPIO_LEVEL_HIGH);
+	gpio_set_direction(33, GPIO_DIR_OUT);	/* LED2 */
+	gpio_set_value(33, GPIO_LEVEL_LOW);
+	gpio_set_direction(34, GPIO_DIR_OUT);	/* LED3 */
+	gpio_set_direction(35, GPIO_DIR_OUT);	/* LED4 */
+}
+
+void hikey_pmussi_init(void)
+{
+	uint32_t data;
+
+	/* Initialize PWR_HOLD GPIO */
+	gpio_set_direction(0, GPIO_DIR_OUT);
+	gpio_set_value(0, GPIO_LEVEL_LOW);
+
+	/*
+	 * After reset, PMUSSI stays in reset mode.
+	 * Now make it out of reset.
+	 */
+	mmio_write_32(AO_SC_PERIPH_RSTDIS4,
+		      AO_SC_PERIPH_RSTDIS4_PRESET_PMUSSI_N);
+	do {
+		data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4);
+	} while (data & AO_SC_PERIPH_RSTDIS4_PRESET_PMUSSI_N);
+
+	/* Set PMUSSI clock latency for read operation. */
+	data = mmio_read_32(AO_SC_MCU_SUBSYS_CTRL3);
+	data &= ~AO_SC_MCU_SUBSYS_CTRL3_RCLK_MASK;
+	data |= AO_SC_MCU_SUBSYS_CTRL3_RCLK_3;
+	mmio_write_32(AO_SC_MCU_SUBSYS_CTRL3, data);
+
+	/* enable PMUSSI clock */
+	data = AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_CCPU |
+	       AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_MCU;
+	mmio_write_32(AO_SC_PERIPH_CLKEN5, data);
+	data = AO_SC_PERIPH_CLKEN4_PCLK_PMUSSI;
+	mmio_write_32(AO_SC_PERIPH_CLKEN4, data);
+
+	gpio_set_value(0, GPIO_LEVEL_HIGH);
+}
+
+void hikey_hi6553_init(void)
+{
+	uint8_t data;
+
+	mmio_write_8(HI6553_PERI_EN_MARK, 0x1e);
+	mmio_write_8(HI6553_NP_REG_ADJ1, 0);
+	data = DISABLE6_XO_CLK_CONN | DISABLE6_XO_CLK_NFC |
+		DISABLE6_XO_CLK_RF1 | DISABLE6_XO_CLK_RF2;
+	mmio_write_8(HI6553_DISABLE6_XO_CLK, data);
+
+	/* configure BUCK0 & BUCK1 */
+	mmio_write_8(HI6553_BUCK01_CTRL2, 0x5e);
+	mmio_write_8(HI6553_BUCK0_CTRL7, 0x10);
+	mmio_write_8(HI6553_BUCK1_CTRL7, 0x10);
+	mmio_write_8(HI6553_BUCK0_CTRL5, 0x1e);
+	mmio_write_8(HI6553_BUCK1_CTRL5, 0x1e);
+	mmio_write_8(HI6553_BUCK0_CTRL1, 0xfc);
+	mmio_write_8(HI6553_BUCK1_CTRL1, 0xfc);
+
+	/* configure BUCK2 */
+	mmio_write_8(HI6553_BUCK2_REG1, 0x4f);
+	mmio_write_8(HI6553_BUCK2_REG5, 0x99);
+	mmio_write_8(HI6553_BUCK2_REG6, 0x45);
+	mdelay(1);
+	mmio_write_8(HI6553_VSET_BUCK2_ADJ, 0x22);
+	mdelay(1);
+
+	/* configure BUCK3 */
+	mmio_write_8(HI6553_BUCK3_REG3, 0x02);
+	mmio_write_8(HI6553_BUCK3_REG5, 0x99);
+	mmio_write_8(HI6553_BUCK3_REG6, 0x41);
+	mmio_write_8(HI6553_VSET_BUCK3_ADJ, 0x02);
+	mdelay(1);
+
+	/* configure BUCK4 */
+	mmio_write_8(HI6553_BUCK4_REG2, 0x9a);
+	mmio_write_8(HI6553_BUCK4_REG5, 0x99);
+	mmio_write_8(HI6553_BUCK4_REG6, 0x45);
+
+	/* configure LDO20 */
+	mmio_write_8(HI6553_LDO20_REG_ADJ, 0x50);
+
+	mmio_write_8(HI6553_NP_REG_CHG, 0x0f);
+	mmio_write_8(HI6553_CLK_TOP0, 0x06);
+	mmio_write_8(HI6553_CLK_TOP3, 0xc0);
+	mmio_write_8(HI6553_CLK_TOP4, 0x00);
+
+	/* configure LDO7 & LDO10 for SD slot */
+	/* enable LDO7 */
+	data = mmio_read_8(HI6553_LDO7_REG_ADJ);
+	data = (data & 0xf8) | 0x2;
+	mmio_write_8(HI6553_LDO7_REG_ADJ, data);
+	mdelay(5);
+	mmio_write_8(HI6553_ENABLE2_LDO1_8, 1 << 6);
+	mdelay(5);
+	/* enable LDO10 */
+	data = mmio_read_8(HI6553_LDO10_REG_ADJ);
+	data = (data & 0xf8) | 0x5;
+	mmio_write_8(HI6553_LDO10_REG_ADJ, data);
+	mdelay(5);
+	mmio_write_8(HI6553_ENABLE3_LDO9_16, 1 << 1);
+	mdelay(5);
+	/* enable LDO15 */
+	data = mmio_read_8(HI6553_LDO15_REG_ADJ);
+	data = (data & 0xf8) | 0x4;
+	mmio_write_8(HI6553_LDO15_REG_ADJ, data);
+	mmio_write_8(HI6553_ENABLE3_LDO9_16, 1 << 6);
+	mdelay(5);
+	/* enable LDO19 */
+	data = mmio_read_8(HI6553_LDO19_REG_ADJ);
+	data |= 0x7;
+	mmio_write_8(HI6553_LDO19_REG_ADJ, data);
+	mmio_write_8(HI6553_ENABLE4_LDO17_22, 1 << 2);
+	mdelay(5);
+	/* enable LDO21 */
+	data = mmio_read_8(HI6553_LDO21_REG_ADJ);
+	data = (data & 0xf8) | 0x3;
+	mmio_write_8(HI6553_LDO21_REG_ADJ, data);
+	mmio_write_8(HI6553_ENABLE4_LDO17_22, 1 << 4);
+	mdelay(5);
+	/* enable LDO22 */
+	data = mmio_read_8(HI6553_LDO22_REG_ADJ);
+	data = (data & 0xf8) | 0x7;
+	mmio_write_8(HI6553_LDO22_REG_ADJ, data);
+	mmio_write_8(HI6553_ENABLE4_LDO17_22, 1 << 5);
+	mdelay(5);
+
+	/* select 32.764KHz */
+	mmio_write_8(HI6553_CLK19M2_600_586_EN, 0x01);
+
+	/* Disable vbus_det interrupts */
+	data = mmio_read_8(HI6553_IRQ2_MASK);
+	data = data | 0x3;
+	mmio_write_8(HI6553_IRQ2_MASK, data);
+}
+
+void init_mmc0_pll(void)
+{
+	unsigned int data;
+
+	/* select SYSPLL as the source of MMC0 */
+	/* select SYSPLL as the source of MUX1 (SC_CLK_SEL0) */
+	mmio_write_32(PERI_SC_CLK_SEL0, 1 << 5 | 1 << 21);
+	do {
+		data = mmio_read_32(PERI_SC_CLK_SEL0);
+	} while (!(data & (1 << 5)));
+	/* select MUX1 as the source of MUX2 (SC_CLK_SEL0) */
+	mmio_write_32(PERI_SC_CLK_SEL0, 1 << 29);
+	do {
+		data = mmio_read_32(PERI_SC_CLK_SEL0);
+	} while (data & (1 << 13));
+
+	mmio_write_32(PERI_SC_PERIPH_CLKEN0, (1 << 0));
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (!(data & (1 << 0)));
+
+	data = mmio_read_32(PERI_SC_PERIPH_CLKEN12);
+	data |= 1 << 1;
+	mmio_write_32(PERI_SC_PERIPH_CLKEN12, data);
+
+	do {
+		mmio_write_32(PERI_SC_CLKCFG8BIT1, (1 << 7) | 0xb);
+		data = mmio_read_32(PERI_SC_CLKCFG8BIT1);
+	} while ((data & 0xb) != 0xb);
+}
+
+void reset_mmc0_clk(void)
+{
+	unsigned int data;
+
+	/* disable mmc0 bus clock */
+	mmio_write_32(PERI_SC_PERIPH_CLKDIS0, PERI_CLK0_MMC0);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (data & PERI_CLK0_MMC0);
+	/* enable mmc0 bus clock */
+	mmio_write_32(PERI_SC_PERIPH_CLKEN0, PERI_CLK0_MMC0);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (!(data & PERI_CLK0_MMC0));
+	/* reset mmc0 clock domain */
+	mmio_write_32(PERI_SC_PERIPH_RSTEN0, PERI_RST0_MMC0);
+
+	/* bypass mmc0 clock phase */
+	data = mmio_read_32(PERI_SC_PERIPH_CTRL2);
+	data |= 3;
+	mmio_write_32(PERI_SC_PERIPH_CTRL2, data);
+
+	/* disable low power */
+	data = mmio_read_32(PERI_SC_PERIPH_CTRL13);
+	data |= 1 << 3;
+	mmio_write_32(PERI_SC_PERIPH_CTRL13, data);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0);
+	} while (!(data & PERI_RST0_MMC0));
+
+	/* unreset mmc0 clock domain */
+	mmio_write_32(PERI_SC_PERIPH_RSTDIS0, PERI_RST0_MMC0);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0);
+	} while (data & PERI_RST0_MMC0);
+}
+
+void init_media_clk(void)
+{
+	unsigned int data, value;
+
+	data = mmio_read_32(PMCTRL_MEDPLLCTRL);
+	data |= 1;
+	mmio_write_32(PMCTRL_MEDPLLCTRL, data);
+
+	for (;;) {
+		data = mmio_read_32(PMCTRL_MEDPLLCTRL);
+		value = 1 << 28;
+		if ((data & value) == value)
+			break;
+	}
+
+	data = mmio_read_32(PERI_SC_PERIPH_CLKEN12);
+	data = 1 << 10;
+	mmio_write_32(PERI_SC_PERIPH_CLKEN12, data);
+}
+
+void init_mmc1_pll(void)
+{
+	uint32_t data;
+
+	/* select SYSPLL as the source of MMC1 */
+	/* select SYSPLL as the source of MUX1 (SC_CLK_SEL0) */
+	mmio_write_32(PERI_SC_CLK_SEL0, 1 << 11 | 1 << 27);
+	do {
+		data = mmio_read_32(PERI_SC_CLK_SEL0);
+	} while (!(data & (1 << 11)));
+	/* select MUX1 as the source of MUX2 (SC_CLK_SEL0) */
+	mmio_write_32(PERI_SC_CLK_SEL0, 1 << 30);
+	do {
+		data = mmio_read_32(PERI_SC_CLK_SEL0);
+	} while (data & (1 << 14));
+
+	mmio_write_32(PERI_SC_PERIPH_CLKEN0, (1 << 1));
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (!(data & (1 << 1)));
+
+	data = mmio_read_32(PERI_SC_PERIPH_CLKEN12);
+	data |= 1 << 2;
+	mmio_write_32(PERI_SC_PERIPH_CLKEN12, data);
+
+	do {
+		/* 1.2GHz / 50 = 24MHz */
+		mmio_write_32(PERI_SC_CLKCFG8BIT2, 0x31 | (1 << 7));
+		data = mmio_read_32(PERI_SC_CLKCFG8BIT2);
+	} while ((data & 0x31) != 0x31);
+}
+
+void reset_mmc1_clk(void)
+{
+	unsigned int data;
+
+	/* disable mmc1 bus clock */
+	mmio_write_32(PERI_SC_PERIPH_CLKDIS0, PERI_CLK0_MMC1);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (data & PERI_CLK0_MMC1);
+	/* enable mmc1 bus clock */
+	mmio_write_32(PERI_SC_PERIPH_CLKEN0, PERI_CLK0_MMC1);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0);
+	} while (!(data & PERI_CLK0_MMC1));
+	/* reset mmc1 clock domain */
+	mmio_write_32(PERI_SC_PERIPH_RSTEN0, PERI_RST0_MMC1);
+
+	/* bypass mmc1 clock phase */
+	data = mmio_read_32(PERI_SC_PERIPH_CTRL2);
+	data |= 3 << 2;
+	mmio_write_32(PERI_SC_PERIPH_CTRL2, data);
+
+	/* disable low power */
+	data = mmio_read_32(PERI_SC_PERIPH_CTRL13);
+	data |= 1 << 4;
+	mmio_write_32(PERI_SC_PERIPH_CTRL13, data);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0);
+	} while (!(data & PERI_RST0_MMC1));
+
+	/* unreset mmc0 clock domain */
+	mmio_write_32(PERI_SC_PERIPH_RSTDIS0, PERI_RST0_MMC1);
+	do {
+		data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0);
+	} while (data & PERI_RST0_MMC1);
+}
+
+/* Initialize PLL of both eMMC and SD controllers. */
+void hikey_mmc_pll_init(void)
+{
+	init_mmc0_pll();
+	reset_mmc0_clk();
+	init_media_clk();
+
+	dsb();
+
+	init_mmc1_pll();
+	reset_mmc1_clk();
+}
+
+void hikey_rtc_init(void)
+{
+	uint32_t data;
+
+	data = mmio_read_32(AO_SC_PERIPH_CLKEN4);
+	data |= AO_SC_PERIPH_RSTDIS4_RESET_RTC0_N;
+	mmio_write_32(AO_SC_PERIPH_CLKEN4, data);
+}
diff --git a/plat/hisilicon/hikey/hikey_ddr.c b/plat/hisilicon/hikey/hikey_ddr.c
new file mode 100644
index 0000000..cd9e9a2
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_ddr.c
@@ -0,0 +1,1451 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+#include <hi6553.h>
+#include <hisi_sram_map.h>
+#include "hikey_private.h"
+
+static void init_pll(void)
+{
+	unsigned int data;
+
+	data = mmio_read_32((0xf7032000 + 0x000));
+	data |= 0x1;
+	mmio_write_32((0xf7032000 + 0x000), data);
+	do {
+		data = mmio_read_32((0xf7032000 + 0x000));
+	} while (!(data & (1 << 28)));
+
+	data = mmio_read_32((0xf7800000 + 0x000));
+	data &= ~0x007;
+	data |= 0x004;
+	mmio_write_32((0xf7800000 + 0x000), data);
+	do {
+		data = mmio_read_32((0xf7800000 + 0x014));
+		data &= 0x007;
+	} while (data != 0x004);
+
+	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101);
+	dsb();
+	isb();
+	udelay(10);
+	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2001);
+	dsb();
+	isb();
+	udelay(10);
+	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2201);
+	dsb();
+	isb();
+	udelay(10);
+	mmio_write_32(0xf7032000 + 0x02c, 0x5110103e);
+	dsb();
+	isb();
+	udelay(10);
+	data = mmio_read_32(0xf7032000 + 0x050);
+	data |= 1 << 28;
+	mmio_write_32(0xf7032000 + 0x050, data);
+	dsb();
+	isb();
+	udelay(10);
+	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101);
+	dsb();
+	isb();
+	udelay(10);
+	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2001);
+	dsb();
+	isb();
+	udelay(10);
+	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2201);
+	dsb();
+	isb();
+	udelay(10);
+}
+
+static void init_freq(void)
+{
+	unsigned int data, tmp;
+	unsigned int cpuext_cfg, ddr_cfg;
+
+	mmio_write_32((0xf7032000 + 0x374), 0x4a);
+	mmio_write_32((0xf7032000 + 0x368), 0xda);
+	mmio_write_32((0xf7032000 + 0x36c), 0x01);
+	mmio_write_32((0xf7032000 + 0x370), 0x01);
+	mmio_write_32((0xf7032000 + 0x360), 0x60);
+	mmio_write_32((0xf7032000 + 0x364), 0x60);
+
+	mmio_write_32((0xf7032000 + 0x114), 0x1000);
+
+	data = mmio_read_32((0xf7032000 + 0x110));
+	data |= (3 << 12);
+	mmio_write_32((0xf7032000 + 0x110), data);
+
+	data = mmio_read_32((0xf7032000 + 0x110));
+	data |= (1 << 4);
+	mmio_write_32((0xf7032000 + 0x110), data);
+
+
+	data = mmio_read_32((0xf7032000 + 0x110));
+	data &= ~0x7;
+	data |= 0x5;
+	mmio_write_32((0xf7032000 + 0x110), data);
+	dsb();
+	mdelay(10);
+
+
+	do {
+		data = mmio_read_32((0xf6504000 + 0x008));
+		data &= (3 << 20);
+	} while (data != (3 << 20));
+	dsb();
+	mdelay(10);
+
+
+	data = mmio_read_32((0xf6504000 + 0x054));
+	data &= ~((1 << 0) | (1 << 11));
+	mmio_write_32((0xf6504000 + 0x054), data);
+	mdelay(10);
+
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data &= ~(3 << 8);
+	data |= (1 << 8);
+	mmio_write_32((0xf7032000 + 0x104), data);
+
+	data = mmio_read_32((0xf7032000 + 0x100));
+	data |= (1 << 0);
+	mmio_write_32((0xf7032000 + 0x100), data);
+	dsb();
+
+	do {
+		data = mmio_read_32((0xf7032000 + 0x100));
+		data &= (1 << 2);
+	} while (data != (1 << 2));
+
+	data = mmio_read_32((0xf6504000 + 0x06c));
+	data &= ~0xffff;
+	data |= 0x56;
+	mmio_write_32((0xf6504000 + 0x06c), data);
+
+	data = mmio_read_32((0xf6504000 + 0x06c));
+	data &= ~(0xffffffu << 8);
+	data |= 0xc7a << 8;
+	mmio_write_32((0xf6504000 + 0x06c), data);
+
+	data = mmio_read_32((0xf6504000 + 0x058));
+	data &= ((1 << 13) - 1);
+	data |= 0xccb;
+	mmio_write_32((0xf6504000 + 0x058), data);
+
+	mmio_write_32((0xf6504000 + 0x060), 0x1fff);
+	mmio_write_32((0xf6504000 + 0x064), 0x1ffffff);
+	mmio_write_32((0xf6504000 + 0x068), 0x7fffffff);
+	mmio_write_32((0xf6504000 + 0x05c), 0x1);
+
+	data = mmio_read_32((0xf6504000 + 0x054));
+	data &= ~(0xf << 12);
+	data |= 1 << 12;
+	mmio_write_32((0xf6504000 + 0x054), data);
+	dsb();
+
+
+	data = mmio_read_32((0xf7032000 + 0x000));
+	data &= ~(1 << 0);
+	mmio_write_32((0xf7032000 + 0x000), data);
+
+	mmio_write_32((0xf7032000 + 0x004), 0x5110207d);
+	mmio_write_32((0xf7032000 + 0x134), 0x10000005);
+	data = mmio_read_32((0xf7032000 + 0x134));
+
+
+	data = mmio_read_32((0xf7032000 + 0x000));
+	data |= (1 << 0);
+	mmio_write_32((0xf7032000 + 0x000), data);
+
+	mmio_write_32((0xf7032000 + 0x368), 0x100da);
+	data = mmio_read_32((0xf7032000 + 0x378));
+	data &= ~((1 << 7) - 1);
+	data |= 0x6b;
+	mmio_write_32((0xf7032000 + 0x378), data);
+	dsb();
+	do {
+		data = mmio_read_32((0xf7032000 + 0x378));
+		tmp = data & 0x7f;
+		data = (data & (0x7f << 8)) >> 8;
+		if (data != tmp)
+			continue;
+		data = mmio_read_32((0xf7032000 + 0x37c));
+	} while (!(data & 1));
+
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data &= ~((3 << 0) |
+			(3 << 8));
+	cpuext_cfg = 1;
+	ddr_cfg = 1;
+	data |= cpuext_cfg | (ddr_cfg << 8);
+	mmio_write_32((0xf7032000 + 0x104), data);
+	dsb();
+
+	do {
+		data = mmio_read_32((0xf7032000 + 0x104));
+		tmp = (data & (3 << 16)) >> 16;
+		if (cpuext_cfg != tmp)
+			continue;
+		tmp = (data & (3 << 24)) >> 24;
+		if (ddr_cfg != tmp)
+			continue;
+		data = mmio_read_32((0xf7032000 + 0x000));
+		data &= 1 << 28;
+	} while (!data);
+
+	data = mmio_read_32((0xf7032000 + 0x100));
+	data &= ~(1 << 0);
+	mmio_write_32((0xf7032000 + 0x100), data);
+	dsb();
+	do {
+		data = mmio_read_32((0xf7032000 + 0x100));
+		data &= (1 << 1);
+	} while (data != (1 << 1));
+	mdelay(1000);
+
+	data = mmio_read_32((0xf6504000 + 0x054));
+	data &= ~(1 << 28);
+	mmio_write_32((0xf6504000 + 0x054), data);
+	dsb();
+
+	data = mmio_read_32((0xf7032000 + 0x110));
+	data &= ~((1 << 4) |
+			(3 << 12));
+	mmio_write_32((0xf7032000 + 0x110), data);
+}
+
+int cat_533mhz_800mhz(void)
+{
+	unsigned int data, i;
+	unsigned int bdl[5];
+
+
+	data = mmio_read_32((0xf712c000 + 0x1c8));
+	data &= 0xfffff0f0;
+	data |= 0x100f01;
+	mmio_write_32((0xf712c000 + 0x1c8), data);
+
+	for (i = 0; i < 0x20; i++) {
+		mmio_write_32((0xf712c000 + 0x1d4), 0xc0000);
+		data = (i << 0x10) + i;
+		mmio_write_32((0xf712c000 + 0x140), data);
+		mmio_write_32((0xf712c000 + 0x144), data);
+		mmio_write_32((0xf712c000 + 0x148), data);
+		mmio_write_32((0xf712c000 + 0x14c), data);
+		mmio_write_32((0xf712c000 + 0x150), data);
+
+
+		data = mmio_read_32((0xf712c000 + 0x070));
+		data |= 0x80000;
+		mmio_write_32((0xf712c000 + 0x070), data);
+		data = mmio_read_32((0xf712c000 + 0x070));
+		data &= 0xfff7ffff;
+		mmio_write_32((0xf712c000 + 0x070), data);
+
+
+		mmio_write_32((0xf712c000 + 0x004), 0x8000);
+		mmio_write_32((0xf712c000 + 0x004), 0x0);
+		mmio_write_32((0xf712c000 + 0x004), 0x801);
+		do {
+			data = mmio_read_32((0xf712c000 + 0x004));
+		} while (data & 1);
+
+		data = mmio_read_32((0xf712c000 + 0x008));
+		if ((data & 0x400) == 0) {
+			mdelay(10);
+			return 0;
+		}
+		WARN("lpddr3 cat fail\n");
+		data = mmio_read_32((0xf712c000 + 0x1d4));
+		if ((data & 0x1f00) && ((data & 0x1f) == 0)) {
+			bdl[0] = mmio_read_32((0xf712c000 + 0x140));
+			bdl[1] = mmio_read_32((0xf712c000 + 0x144));
+			bdl[2] = mmio_read_32((0xf712c000 + 0x148));
+			bdl[3] = mmio_read_32((0xf712c000 + 0x14c));
+			bdl[4] = mmio_read_32((0xf712c000 + 0x150));
+			if ((!(bdl[0] & 0x1f001f)) || (!(bdl[1] & 0x1f001f)) ||
+					(!(bdl[2] & 0x1f001f)) || (!(bdl[3] & 0x1f001f)) ||
+					(!(bdl[4] & 0x1f001f))) {
+				WARN("lpddr3 cat deskew error\n");
+				if (i == 0x1f) {
+					WARN("addrnbdl is max\n");
+					return -EINVAL;
+				}
+				mmio_write_32((0xf712c000 + 0x008), 0x400);
+			} else {
+				WARN("lpddr3 cat other error1\n");
+				return -EINVAL;
+			}
+		} else {
+			WARN("lpddr3 cat other error2\n");
+			return -EINVAL;
+		}
+	}
+	return -EINVAL;
+}
+
+static void ddrx_rdet(void)
+{
+	unsigned int data, rdet, bdl[4];
+
+	data = mmio_read_32((0xf712c000 + 0x0d0));
+	data &= 0xf800ffff;
+	data |= 0x8f0000;
+	mmio_write_32((0xf712c000 + 0x0d0), data);
+
+	data = mmio_read_32((0xf712c000 + 0x0dc));
+	data &= 0xfffffff0;
+	data |= 0xf;
+	mmio_write_32((0xf712c000 + 0x0dc), data);
+
+
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data |= 0x80000;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= 0xfff7ffff;
+	mmio_write_32((0xf712c000 + 0x070), data);
+
+	mmio_write_32((0xf712c000 + 0x004), 0x8000);
+	mmio_write_32((0xf712c000 + 0x004), 0);
+
+	data = mmio_read_32((0xf712c000 + 0x0d0));
+	data &= ~0xf0000000;
+	data |= 0x80000000;
+	mmio_write_32((0xf712c000 + 0x0d0), data);
+
+	mmio_write_32((0xf712c000 + 0x004), 0x101);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (!(data & 1));
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x100)
+		WARN("rdet lbs fail\n");
+
+	bdl[0] = mmio_read_32((0xf712c000 + 0x22c)) & 0x7f;
+	bdl[1] = mmio_read_32((0xf712c000 + 0x2ac)) & 0x7f;
+	bdl[2] = mmio_read_32((0xf712c000 + 0x32c)) & 0x7f;
+	bdl[3] = mmio_read_32((0xf712c000 + 0x3ac)) & 0x7f;
+	do {
+		data = mmio_read_32((0xf712c000 + 0x22c));
+		data &= ~0x7f;
+		data |= bdl[0];
+		mmio_write_32((0xf712c000 + 0x22c), data);
+		data = mmio_read_32((0xf712c000 + 0x2ac));
+		data &= ~0x7f;
+		data |= bdl[1];
+		mmio_write_32((0xf712c000 + 0x2ac), data);
+		data = mmio_read_32((0xf712c000 + 0x32c));
+		data &= ~0x7f;
+		data |= bdl[2];
+		mmio_write_32((0xf712c000 + 0x32c), data);
+		data = mmio_read_32((0xf712c000 + 0x3ac));
+		data &= ~0x7f;
+		data |= bdl[3];
+		mmio_write_32((0xf712c000 + 0x3ac), data);
+
+
+		data = mmio_read_32((0xf712c000 + 0x070));
+		data |= 0x80000;
+		mmio_write_32((0xf712c000 + 0x070), data);
+		data = mmio_read_32((0xf712c000 + 0x070));
+		data &= 0xfff7ffff;
+		mmio_write_32((0xf712c000 + 0x070), data);
+
+		mmio_write_32((0xf712c000 + 0x004), 0x8000);
+		mmio_write_32((0xf712c000 + 0x004), 0);
+
+		data = mmio_read_32((0xf712c000 + 0x0d0));
+		data &= ~0xf0000000;
+		data |= 0x40000000;
+		mmio_write_32((0xf712c000 + 0x0d0), data);
+		mmio_write_32((0xf712c000 + 0x004), 0x101);
+		do {
+			data = mmio_read_32((0xf712c000 + 0x004));
+		} while (data & 1);
+
+		data = mmio_read_32((0xf712c000 + 0x008));
+		rdet = data & 0x100;
+		if (rdet) {
+			INFO("rdet ds fail\n");
+			mmio_write_32((0xf712c000 + 0x008), 0x100);
+		}
+		bdl[0]++;
+		bdl[1]++;
+		bdl[2]++;
+		bdl[3]++;
+	} while (rdet);
+
+	data = mmio_read_32((0xf712c000 + 0x0d0));
+	data &= ~0xf0000000;
+	data |= 0x30000000;
+	mmio_write_32((0xf712c000 + 0x0d0), data);
+
+	mmio_write_32((0xf712c000 + 0x004), 0x101);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x100)
+		INFO("rdet rbs av fail\n");
+}
+
+static void ddrx_wdet(void)
+{
+	unsigned int data, wdet, zero_bdl = 0, dq[4];
+	int i;
+
+	data = mmio_read_32((0xf712c000 + 0x0d0));
+	data &= ~0xf;
+	data |= 0xf;
+	mmio_write_32((0xf712c000 + 0x0d0), data);
+
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data |= 0x80000;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= ~0x80000;
+	mmio_write_32((0xf712c000 + 0x070), data);
+
+	mmio_write_32((0xf712c000 + 0x004), 0x8000);
+	mmio_write_32((0xf712c000 + 0x004), 0);
+	data = mmio_read_32((0xf712c000 + 0x0d0));
+	data &= ~0xf000;
+	data |= 0x8000;
+	mmio_write_32((0xf712c000 + 0x0d0), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x201);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x200)
+		INFO("wdet lbs fail\n");
+
+	dq[0] = mmio_read_32((0xf712c000 + 0x234)) & 0x1f00;
+	dq[1] = mmio_read_32((0xf712c000 + 0x2b4)) & 0x1f00;
+	dq[2] = mmio_read_32((0xf712c000 + 0x334)) & 0x1f00;
+	dq[3] = mmio_read_32((0xf712c000 + 0x3b4)) & 0x1f00;
+
+	do {
+		mmio_write_32((0xf712c000 + 0x234), dq[0]);
+		mmio_write_32((0xf712c000 + 0x2b4), dq[1]);
+		mmio_write_32((0xf712c000 + 0x334), dq[2]);
+		mmio_write_32((0xf712c000 + 0x3b4), dq[3]);
+
+		data = mmio_read_32((0xf712c000 + 0x070));
+		data |= 0x80000;
+		mmio_write_32((0xf712c000 + 0x070), data);
+		data = mmio_read_32((0xf712c000 + 0x070));
+		data &= ~0x80000;
+		mmio_write_32((0xf712c000 + 0x070), data);
+		mmio_write_32((0xf712c000 + 0x004), 0x8000);
+		mmio_write_32((0xf712c000 + 0x004), 0);
+
+		data = mmio_read_32((0xf712c000 + 0x0d0));
+		data &= ~0xf000;
+		data |= 0x4000;
+		mmio_write_32((0xf712c000 + 0x0d0), data);
+		mmio_write_32((0xf712c000 + 0x004), 0x201);
+		do {
+			data = mmio_read_32((0xf712c000 + 0x004));
+		} while (data & 1);
+
+		data = mmio_read_32((0xf712c000 + 0x008));
+		wdet = data & 0x200;
+		if (wdet) {
+			INFO("wdet ds fail\n");
+			mmio_write_32((0xf712c000 + 0x008), 0x200);
+		}
+		mdelay(10);
+
+		for (i = 0; i < 4; i++) {
+			data = mmio_read_32((0xf712c000 + 0x210 + i * 0x80));
+			if ((!(data & 0x1f)) || (!(data & 0x1f00)) ||
+			    (!(data & 0x1f0000)) || (!(data & 0x1f000000)))
+				zero_bdl = 1;
+			data = mmio_read_32((0xf712c000 + 0x214 + i * 0x80));
+			if ((!(data & 0x1f)) || (!(data & 0x1f00)) ||
+			    (!(data & 0x1f0000)) || (!(data & 0x1f000000)))
+				zero_bdl = 1;
+			data = mmio_read_32((0xf712c000 + 0x218 + i * 0x80));
+			if (!(data & 0x1f))
+				zero_bdl = 1;
+			if (zero_bdl) {
+				if (i == 0)
+					dq[0] = dq[0] - 0x100;
+				if (i == 1)
+					dq[1] = dq[1] - 0x100;
+				if (i == 2)
+					dq[2] = dq[2] - 0x100;
+				if (i == 3)
+					dq[3] = dq[3] - 0x100;
+			}
+		}
+	} while (wdet);
+
+	data = mmio_read_32((0xf712c000 + 0x0d0));
+	data &= ~0xf000;
+	data |= 0x3000;
+	mmio_write_32((0xf712c000 + 0x0d0), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x201);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x200)
+		INFO("wdet rbs av fail\n");
+}
+
+void set_ddrc_150mhz(void)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7032000 + 0x580), 0x1);
+	mmio_write_32((0xf7032000 + 0x5a8), 0x7);
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data &= 0xfffffcff;
+	mmio_write_32((0xf7032000 + 0x104), data);
+
+	mmio_write_32((0xf7030000 + 0x050), 0x31);
+	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
+	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
+	mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f);
+	mmio_write_32((0xf712c000 + 0x00c), 0xf0f);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x090), 0x7200000);
+	mmio_write_32((0xf712c000 + 0x258), 0x720);
+	mmio_write_32((0xf712c000 + 0x2d8), 0x720);
+	mmio_write_32((0xf712c000 + 0x358), 0x720);
+	mmio_write_32((0xf712c000 + 0x3d8), 0x720);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f);
+	mmio_write_32((0xf712c000 + 0x0b4), 0xf);
+	mmio_write_32((0xf712c000 + 0x088), 0x3fff801);
+	mmio_write_32((0xf712c000 + 0x070), 0x8940000);
+
+	data = mmio_read_32((0xf712c000 + 0x078));
+	data |= 4;
+	mmio_write_32((0xf712c000 + 0x078), data);
+	mmio_write_32((0xf712c000 + 0x01c), 0x8000080);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= 0xfffffffe;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	mmio_write_32((0xf712c000 + 0x1d4), 0xc0000);
+	mmio_write_32((0xf712c000 + 0x010), 0x500000f);
+	mmio_write_32((0xf712c000 + 0x014), 0x10);
+	data = mmio_read_32((0xf712c000 + 0x1e4));
+	data &= 0xffffff00;
+	mmio_write_32((0xf712c000 + 0x1e4), data);
+	mmio_write_32((0xf712c000 + 0x030), 0x30c82355);
+	mmio_write_32((0xf712c000 + 0x034), 0x62112bb);
+	mmio_write_32((0xf712c000 + 0x038), 0x20041022);
+	mmio_write_32((0xf712c000 + 0x03c), 0x63177497);
+	mmio_write_32((0xf712c000 + 0x040), 0x3008407);
+	mmio_write_32((0xf712c000 + 0x064), 0x10483);
+	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= 0xffff0000;
+	data |= 0x184;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= 0xbfffffff;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= ~0x10;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	data = mmio_read_32((0xf712c000 + 0x080));
+	data &= ~0x2000;
+	mmio_write_32((0xf712c000 + 0x080), data);
+	mmio_write_32((0xf712c000 + 0x270), 0x3);
+	mmio_write_32((0xf712c000 + 0x2f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x370), 0x3);
+	mmio_write_32((0xf712c000 + 0x3f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x048), 0x90420880);
+
+	mmio_write_32((0xf7128000 + 0x040), 0x0);
+	mmio_write_32((0xf712c000 + 0x004), 0x146d);
+	mmio_write_32((0xf7128000 + 0x050), 0x100123);
+	mmio_write_32((0xf7128000 + 0x060), 0x133);
+	mmio_write_32((0xf7128000 + 0x064), 0x133);
+	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
+
+	mmio_write_32((0xf7128000 + 0x100), 0xb3290d08);
+	mmio_write_32((0xf7128000 + 0x104), 0x9621821);
+	mmio_write_32((0xf7128000 + 0x108), 0x45009023);
+	mmio_write_32((0xf7128000 + 0x10c), 0xaf44c145);
+	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
+	mmio_write_32((0xf7128000 + 0x114), 0x11080806);
+	mmio_write_32((0xf7128000 + 0x118), 0x44);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 8) {
+		NOTICE("fail to init ddr3 rank0\n");
+		return;
+	}
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 1;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x21);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x8)
+		NOTICE("ddr3 rank1 init failure\n");
+	else
+		INFO("ddr3 rank1 init pass\n");
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= ~0xf;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	INFO("succeed to set ddrc 150mhz\n");
+}
+
+void set_ddrc_266mhz(void)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7032000 + 0x580), 0x3);
+	mmio_write_32((0xf7032000 + 0x5a8), 0x1003);
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data &= 0xfffffcff;
+	mmio_write_32((0xf7032000 + 0x104), data);
+
+	mmio_write_32((0xf7030000 + 0x050), 0x31);
+	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
+	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
+	mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f);
+	mmio_write_32((0xf712c000 + 0x00c), 0xf0f);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x090), 0x7200000);
+	mmio_write_32((0xf712c000 + 0x258), 0x720);
+	mmio_write_32((0xf712c000 + 0x2d8), 0x720);
+	mmio_write_32((0xf712c000 + 0x358), 0x720);
+	mmio_write_32((0xf712c000 + 0x3d8), 0x720);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f);
+	mmio_write_32((0xf712c000 + 0x0b4), 0xf);
+	mmio_write_32((0xf712c000 + 0x088), 0x3fff801);
+	mmio_write_32((0xf712c000 + 0x070), 0x8940000);
+
+	data = mmio_read_32((0xf712c000 + 0x078));
+	data |= 4;
+	mmio_write_32((0xf712c000 + 0x078), data);
+	mmio_write_32((0xf712c000 + 0x01c), 0x8000080);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= 0xfffffffe;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	mmio_write_32((0xf712c000 + 0x1d4), 0xc0000);
+	mmio_write_32((0xf712c000 + 0x010), 0x500000f);
+	mmio_write_32((0xf712c000 + 0x014), 0x10);
+	data = mmio_read_32((0xf712c000 + 0x1e4));
+	data &= 0xffffff00;
+	mmio_write_32((0xf712c000 + 0x1e4), data);
+	mmio_write_32((0xf712c000 + 0x030), 0x510d4455);
+	mmio_write_32((0xf712c000 + 0x034), 0x8391ebb);
+	mmio_write_32((0xf712c000 + 0x038), 0x2005103c);
+	mmio_write_32((0xf712c000 + 0x03c), 0x6329950b);
+	mmio_write_32((0xf712c000 + 0x040), 0x300858c);
+	mmio_write_32((0xf712c000 + 0x064), 0x10483);
+	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= 0xffff0000;
+	data |= 0x184;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= 0xbfffffff;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= ~0x10;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	data = mmio_read_32((0xf712c000 + 0x080));
+	data &= ~0x2000;
+	mmio_write_32((0xf712c000 + 0x080), data);
+	mmio_write_32((0xf712c000 + 0x270), 0x3);
+	mmio_write_32((0xf712c000 + 0x2f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x370), 0x3);
+	mmio_write_32((0xf712c000 + 0x3f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x048), 0x90420880);
+
+	mmio_write_32((0xf7128000 + 0x040), 0x0);
+	mmio_write_32((0xf712c000 + 0x004), 0x146d);
+	mmio_write_32((0xf7128000 + 0x050), 0x100123);
+	mmio_write_32((0xf7128000 + 0x060), 0x133);
+	mmio_write_32((0xf7128000 + 0x064), 0x133);
+	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
+
+	mmio_write_32((0xf7128000 + 0x100), 0xb441d50d);
+	mmio_write_32((0xf7128000 + 0x104), 0xf721839);
+	mmio_write_32((0xf7128000 + 0x108), 0x5500f03f);
+	mmio_write_32((0xf7128000 + 0x10c), 0xaf486145);
+	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
+	mmio_write_32((0xf7128000 + 0x114), 0x12080d06);
+	mmio_write_32((0xf7128000 + 0x118), 0x44);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 8) {
+		NOTICE("fail to init ddr3 rank0\n");
+		return;
+	}
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 1;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x21);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x8)
+		NOTICE("ddr3 rank1 init failure\n");
+	else
+		INFO("ddr3 rank1 init pass\n");
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= ~0xf;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	INFO("succeed to set ddrc 266mhz\n");
+}
+
+void set_ddrc_400mhz(void)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7032000 + 0x580), 0x2);
+	mmio_write_32((0xf7032000 + 0x5a8), 0x1003);
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data &= 0xfffffcff;
+	mmio_write_32((0xf7032000 + 0x104), data);
+
+	mmio_write_32((0xf7030000 + 0x050), 0x31);
+	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
+	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
+	mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f);
+	mmio_write_32((0xf712c000 + 0x00c), 0xf0f);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x090), 0x7200000);
+	mmio_write_32((0xf712c000 + 0x258), 0x720);
+	mmio_write_32((0xf712c000 + 0x2d8), 0x720);
+	mmio_write_32((0xf712c000 + 0x358), 0x720);
+	mmio_write_32((0xf712c000 + 0x3d8), 0x720);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f);
+	mmio_write_32((0xf712c000 + 0x0b4), 0xf);
+	mmio_write_32((0xf712c000 + 0x088), 0x3fff801);
+	mmio_write_32((0xf712c000 + 0x070), 0x8940000);
+
+	data = mmio_read_32((0xf712c000 + 0x078));
+	data |= 4;
+	mmio_write_32((0xf712c000 + 0x078), data);
+	mmio_write_32((0xf712c000 + 0x01c), 0x8000080);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= 0xfffffffe;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	mmio_write_32((0xf712c000 + 0x1d4), 0xc0000);
+	mmio_write_32((0xf712c000 + 0x010), 0x500000f);
+	mmio_write_32((0xf712c000 + 0x014), 0x10);
+	data = mmio_read_32((0xf712c000 + 0x1e4));
+	data &= 0xffffff00;
+	mmio_write_32((0xf712c000 + 0x1e4), data);
+	mmio_write_32((0xf712c000 + 0x030), 0x75525655);
+	mmio_write_32((0xf712c000 + 0x034), 0xa552abb);
+	mmio_write_32((0xf712c000 + 0x038), 0x20071059);
+	mmio_write_32((0xf712c000 + 0x03c), 0x633e8591);
+	mmio_write_32((0xf712c000 + 0x040), 0x3008691);
+	mmio_write_32((0xf712c000 + 0x064), 0x10483);
+	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= 0xffff0000;
+	data |= 0x184;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= 0xbfffffff;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= ~0x10;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	data = mmio_read_32((0xf712c000 + 0x080));
+	data &= ~0x2000;
+	mmio_write_32((0xf712c000 + 0x080), data);
+	mmio_write_32((0xf712c000 + 0x270), 0x3);
+	mmio_write_32((0xf712c000 + 0x2f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x370), 0x3);
+	mmio_write_32((0xf712c000 + 0x3f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x048), 0x90420880);
+
+	mmio_write_32((0xf7128000 + 0x040), 0x0);
+	mmio_write_32((0xf712c000 + 0x004), 0x146d);
+	mmio_write_32((0xf7128000 + 0x050), 0x100123);
+	mmio_write_32((0xf7128000 + 0x060), 0x133);
+	mmio_write_32((0xf7128000 + 0x064), 0x133);
+	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
+
+	mmio_write_32((0xf7128000 + 0x100), 0xb55a9d12);
+	mmio_write_32((0xf7128000 + 0x104), 0x17721855);
+	mmio_write_32((0xf7128000 + 0x108), 0x7501505f);
+	mmio_write_32((0xf7128000 + 0x10c), 0xaf4ca245);
+	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
+	mmio_write_32((0xf7128000 + 0x114), 0x13081306);
+	mmio_write_32((0xf7128000 + 0x118), 0x44);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 8) {
+		NOTICE("fail to init ddr3 rank0\n");
+		return;
+	}
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 1;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x21);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x8)
+		NOTICE("ddr3 rank1 init failure\n");
+	else
+		INFO("ddr3 rank1 init pass\n");
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= ~0xf;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	INFO("succeed to set ddrc 400mhz\n");
+}
+
+void set_ddrc_533mhz(void)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7032000 + 0x580), 0x3);
+	mmio_write_32((0xf7032000 + 0x5a8), 0x11111);
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data |= 0x100;
+	mmio_write_32((0xf7032000 + 0x104), data);
+
+	mmio_write_32((0xf7030000 + 0x050), 0x30);
+	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
+	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
+	mmio_write_32((0xf712c000 + 0x00c), 0x400);
+	mmio_write_32((0xf712c000 + 0x00c), 0x400);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x090), 0x6400000);
+	mmio_write_32((0xf712c000 + 0x258), 0x640);
+	mmio_write_32((0xf712c000 + 0x2d8), 0x640);
+	mmio_write_32((0xf712c000 + 0x358), 0x640);
+	mmio_write_32((0xf712c000 + 0x3d8), 0x640);
+	mmio_write_32((0xf712c000 + 0x018), 0x0);
+	mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f);
+	mmio_write_32((0xf712c000 + 0x0b4), 0xf);
+	mmio_write_32((0xf712c000 + 0x088), 0x3fff801);
+	mmio_write_32((0xf712c000 + 0x070), 0x8940000);
+
+	data = mmio_read_32((0xf712c000 + 0x078));
+	data |= 4;
+	mmio_write_32((0xf712c000 + 0x078), data);
+	mmio_write_32((0xf712c000 + 0x01c), 0x8000080);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= 0xfffffffe;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	mmio_write_32((0xf712c000 + 0x1d4), 0xc0000);
+	mmio_write_32((0xf712c000 + 0x010), 0x500000f);
+	mmio_write_32((0xf712c000 + 0x014), 0x10);
+	data = mmio_read_32((0xf712c000 + 0x1e4));
+	data &= 0xffffff00;
+	mmio_write_32((0xf712c000 + 0x1e4), data);
+	mmio_write_32((0xf712c000 + 0x030), 0x9dd87855);
+	mmio_write_32((0xf712c000 + 0x034), 0xa7138bb);
+	mmio_write_32((0xf712c000 + 0x038), 0x20091477);
+	mmio_write_32((0xf712c000 + 0x03c), 0x84534e16);
+	mmio_write_32((0xf712c000 + 0x040), 0x3008817);
+	mmio_write_32((0xf712c000 + 0x064), 0x106c3);
+	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= 0xffff0000;
+	data |= 0x305;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 0x40000000;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= ~0x10;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	data = mmio_read_32((0xf712c000 + 0x080));
+	data &= ~0x2000;
+	mmio_write_32((0xf712c000 + 0x080), data);
+	mmio_write_32((0xf712c000 + 0x270), 0x3);
+	mmio_write_32((0xf712c000 + 0x2f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x370), 0x3);
+	mmio_write_32((0xf712c000 + 0x3f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x048), 0xd0420900);
+
+	mmio_write_32((0xf7128000 + 0x040), 0x0);
+	mmio_write_32((0xf712c000 + 0x004), 0x140f);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x7fe) {
+		NOTICE("failed to init lpddr3 rank0 dram phy\n");
+		return;
+	}
+	cat_533mhz_800mhz();
+
+	mmio_write_32((0xf712c000 + 0x004), 0xf1);
+	mmio_write_32((0xf7128000 + 0x050), 0x100123);
+	mmio_write_32((0xf7128000 + 0x060), 0x133);
+	mmio_write_32((0xf7128000 + 0x064), 0x133);
+	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
+
+	mmio_write_32((0xf7128000 + 0x100), 0xb77b6718);
+	mmio_write_32((0xf7128000 + 0x104), 0x1e82a071);
+	mmio_write_32((0xf7128000 + 0x108), 0x9501c07e);
+	mmio_write_32((0xf7128000 + 0x10c), 0xaf50c255);
+	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
+	mmio_write_32((0xf7128000 + 0x114), 0x13181908);
+	mmio_write_32((0xf7128000 + 0x118), 0x44);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x7fe) {
+		NOTICE("fail to init ddr3 rank0\n");
+		return;
+	}
+	ddrx_rdet();
+	ddrx_wdet();
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 1;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x21);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x7fe)
+		NOTICE("ddr3 rank1 init failure\n");
+	else
+		INFO("ddr3 rank1 init pass\n");
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= ~0xf;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	INFO("succeed to set ddrc 533mhz\n");
+}
+
+void set_ddrc_800mhz(void)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7032000 + 0x580), 0x2);
+	mmio_write_32((0xf7032000 + 0x5a8), 0x1003);
+	data = mmio_read_32((0xf7032000 + 0x104));
+	data &= 0xfffffcff;
+	mmio_write_32((0xf7032000 + 0x104), data);
+
+	mmio_write_32((0xf7030000 + 0x050), 0x30);
+	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
+	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
+	mmio_write_32((0xf712c000 + 0x00c), 0x400);
+	mmio_write_32((0xf712c000 + 0x00c), 0x400);
+	mmio_write_32((0xf712c000 + 0x018), 0x7);
+	mmio_write_32((0xf712c000 + 0x090), 0x5400000);
+	mmio_write_32((0xf712c000 + 0x258), 0x540);
+	mmio_write_32((0xf712c000 + 0x2d8), 0x540);
+	mmio_write_32((0xf712c000 + 0x358), 0x540);
+	mmio_write_32((0xf712c000 + 0x3d8), 0x540);
+	mmio_write_32((0xf712c000 + 0x018), 0x0);
+	mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f);
+	mmio_write_32((0xf712c000 + 0x0b4), 0xf);
+	mmio_write_32((0xf712c000 + 0x088), 0x3fff801);
+	mmio_write_32((0xf712c000 + 0x070), 0x8940000);
+
+	data = mmio_read_32((0xf712c000 + 0x078));
+	data |= 4;
+	mmio_write_32((0xf712c000 + 0x078), data);
+	mmio_write_32((0xf712c000 + 0x01c), 0x8000080);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= 0xfffffffe;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	mmio_write_32((0xf712c000 + 0x1d4), 0xc0000);
+	mmio_write_32((0xf712c000 + 0x010), 0x500000f);
+	mmio_write_32((0xf712c000 + 0x014), 0x10);
+	data = mmio_read_32((0xf712c000 + 0x1e4));
+	data &= 0xffffff00;
+	mmio_write_32((0xf712c000 + 0x1e4), data);
+	mmio_write_32((0xf712c000 + 0x030), 0xe663ab77);
+	mmio_write_32((0xf712c000 + 0x034), 0xea952db);
+	mmio_write_32((0xf712c000 + 0x038), 0x200d1cb1);
+	mmio_write_32((0xf712c000 + 0x03c), 0xc67d0721);
+	mmio_write_32((0xf712c000 + 0x040), 0x3008aa1);
+	mmio_write_32((0xf712c000 + 0x064), 0x11a43);
+	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
+	data = mmio_read_32((0xf712c000 + 0x070));
+	data &= 0xffff0000;
+	data |= 0x507;
+	mmio_write_32((0xf712c000 + 0x070), data);
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 0x40000000;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	data = mmio_read_32((0xf712c000 + 0x020));
+	data &= 0xffffffef;
+	mmio_write_32((0xf712c000 + 0x020), data);
+	data = mmio_read_32((0xf712c000 + 0x080));
+	data &= 0xffffdfff;
+	mmio_write_32((0xf712c000 + 0x080), data);
+	mmio_write_32((0xf712c000 + 0x270), 0x3);
+	mmio_write_32((0xf712c000 + 0x2f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x370), 0x3);
+	mmio_write_32((0xf712c000 + 0x3f0), 0x3);
+	mmio_write_32((0xf712c000 + 0x048), 0xd0420900);
+
+	mmio_write_32((0xf7128000 + 0x040), 0x2001);
+	mmio_write_32((0xf712c000 + 0x004), 0x140f);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x7fe) {
+		WARN("failed to init lpddr3 rank0 dram phy\n");
+		return;
+	}
+	cat_533mhz_800mhz();
+
+	mmio_write_32((0xf712c000 + 0x004), 0xf1);
+	mmio_write_32((0xf7128000 + 0x050), 0x100023);
+	mmio_write_32((0xf7128000 + 0x060), 0x133);
+	mmio_write_32((0xf7128000 + 0x064), 0x133);
+	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
+
+	mmio_write_32((0xf7128000 + 0x100), 0x755a9d12);
+	mmio_write_32((0xf7128000 + 0x104), 0x1753b055);
+	mmio_write_32((0xf7128000 + 0x108), 0x7401505f);
+	mmio_write_32((0xf7128000 + 0x10c), 0x578ca244);
+	mmio_write_32((0xf7128000 + 0x110), 0x10700000);
+	mmio_write_32((0xf7128000 + 0x114), 0x13141306);
+	mmio_write_32((0xf7128000 + 0x118), 0x44);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x7fe) {
+		NOTICE("fail to init ddr3 rank0\n");
+		return;
+	}
+	ddrx_rdet();
+	ddrx_wdet();
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data |= 1;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	mmio_write_32((0xf712c000 + 0x004), 0x21);
+	do {
+		data = mmio_read_32((0xf712c000 + 0x004));
+	} while (data & 1);
+
+	data = mmio_read_32((0xf712c000 + 0x008));
+	if (data & 0x7fe)
+		NOTICE("ddr3 rank1 init failure\n");
+	else
+		INFO("ddr3 rank1 init pass\n");
+
+	data = mmio_read_32((0xf712c000 + 0x048));
+	data &= ~0xf;
+	mmio_write_32((0xf712c000 + 0x048), data);
+	INFO("succeed to set ddrc 800mhz\n");
+}
+
+static void ddrc_common_init(int freq)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7120000 + 0x020), 0x1);
+	mmio_write_32((0xf7120000 + 0x100), 0x1700);
+	mmio_write_32((0xf7120000 + 0x104), 0x71040004);
+	mmio_write_32((0xf7121400 + 0x104), 0xf);
+	mmio_write_32((0xf7121800 + 0x104), 0xf);
+	mmio_write_32((0xf7121c00 + 0x104), 0xf);
+	mmio_write_32((0xf7122000 + 0x104), 0xf);
+	mmio_write_32((0xf7128000 + 0x02c), 0x6);
+	mmio_write_32((0xf7128000 + 0x020), 0x30003);
+	mmio_write_32((0xf7128000 + 0x028), 0x310201);
+	mmio_write_32((0xf712c000 + 0x1e4), 0xfe007600);
+	mmio_write_32((0xf7128000 + 0x01c), 0xaf001);
+
+
+	data = mmio_read_32((0xf7128000 + 0x280));
+	data |= 1 << 7;
+	mmio_write_32((0xf7128000 + 0x280), data);
+	mmio_write_32((0xf7128000 + 0x244), 0x3);
+
+	if (freq == DDR_FREQ_800M)
+		mmio_write_32((0xf7128000 + 0x240), 167 * (freq / 2) / 1024);
+	else
+		mmio_write_32((0xf7128000 + 0x240), 167 * freq / 1024);
+
+	data = mmio_read_32((0xf712c000 + 0x080));
+	data &= 0xffff;
+	data |= 0x4002000;
+	mmio_write_32((0xf712c000 + 0x080), data);
+	mmio_write_32((0xf7128000 + 0x000), 0x0);
+	do {
+		data = mmio_read_32((0xf7128000 + 0x294));
+	} while (data & 1);
+	mmio_write_32((0xf7128000 + 0x000), 0x2);
+}
+
+
+static int dienum_det_and_rowcol_cfg(void)
+{
+	unsigned int data;
+
+	mmio_write_32((0xf7128000 + 0x210), 0x87);
+	mmio_write_32((0xf7128000 + 0x218), 0x10000);
+	mmio_write_32((0xf7128000 + 0x00c), 0x1);
+	do {
+		data = mmio_read_32((0xf7128000 + 0x00c));
+	} while (data & 1);
+	data = mmio_read_32((0xf7128000 + 0x4a8)) & 0xfc;
+	switch (data) {
+	case 0x18:
+		mmio_write_32((0xf7128000 + 0x060), 0x132);
+		mmio_write_32((0xf7128000 + 0x064), 0x132);
+		mmio_write_32((0xf7120000 + 0x100), 0x1600);
+		mmio_write_32((0xf7120000 + 0x104), 0x71040004);
+		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x40000000);
+		break;
+	case 0x1c:
+		mmio_write_32((0xf7128000 + 0x060), 0x142);
+		mmio_write_32((0xf7128000 + 0x064), 0x142);
+		mmio_write_32((0xf7120000 + 0x100), 0x1700);
+		mmio_write_32((0xf7120000 + 0x104), 0x71040004);
+		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000);
+		break;
+	case 0x58:
+		mmio_write_32((0xf7128000 + 0x060), 0x133);
+		mmio_write_32((0xf7128000 + 0x064), 0x133);
+		mmio_write_32((0xf7120000 + 0x100), 0x1700);
+		mmio_write_32((0xf7120000 + 0x104), 0x71040004);
+		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000);
+		break;
+	default:
+		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000);
+		break;
+	}
+	if (!data)
+		return -EINVAL;
+	return 0;
+}
+
+static int detect_ddr_chip_info(void)
+{
+	unsigned int data, mr5, mr6, mr7;
+
+	mmio_write_32((0xf7128000 + 0x210), 0x57);
+	mmio_write_32((0xf7128000 + 0x218), 0x10000);
+	mmio_write_32((0xf7128000 + 0x00c), 0x1);
+
+	do {
+		data = mmio_read_32((0xf7128000 + 0x00c));
+	} while (data & 1);
+
+	data = mmio_read_32((0xf7128000 + 0x4a8));
+	mr5 = data & 0xff;
+	switch (mr5) {
+	case 1:
+		INFO("Samsung DDR\n");
+		break;
+	case 6:
+		INFO("Hynix DDR\n");
+		break;
+	case 3:
+		INFO("Elpida DDR\n");
+		break;
+	default:
+		INFO("DDR from other vendors\n");
+		break;
+	}
+
+	mmio_write_32((0xf7128000 + 0x210), 0x67);
+	mmio_write_32((0xf7128000 + 0x218), 0x10000);
+	mmio_write_32((0xf7128000 + 0x00c), 0x1);
+	do {
+		data = mmio_read_32((0xf7128000 + 0x00c));
+	} while (data & 1);
+	data = mmio_read_32((0xf7128000 + 0x4a8));
+	mr6 = data & 0xff;
+	mmio_write_32((0xf7128000 + 0x210), 0x77);
+	mmio_write_32((0xf7128000 + 0x218), 0x10000);
+	mmio_write_32((0xf7128000 + 0x00c), 0x1);
+	do {
+		data = mmio_read_32((0xf7128000 + 0x00c));
+	} while (data & 1);
+	data = mmio_read_32((0xf7128000 + 0x4a8));
+	mr7 = data & 0xff;
+	data = mr5 + (mr6 << 8) + (mr7 << 16);
+	return data;
+}
+
+void ddr_phy_reset(void)
+{
+	mmio_write_32(0xf7030340, 0xa000);
+	mmio_write_32(0xf7030344, 0xa000);
+}
+
+void lpddrx_save_ddl_para_bypass(uint32_t *ddr_ddl_para, unsigned int index)
+{
+	uint32_t value;
+	uint32_t cnt = index;
+	uint32_t i;
+
+	for (i = 0; i < 4; i++) {
+		value = mmio_read_32(0xf712c000 + 0x22c + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x23c + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x240 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x640 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+	}
+}
+
+void lpddrx_save_ddl_para_mission(uint32_t *ddr_ddl_para, unsigned int index)
+{
+	uint32_t value;
+	uint32_t cnt = index;
+	uint32_t i;
+
+	value = mmio_read_32(0xf712c000 + 0x140);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x144);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x148);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x14c);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x150);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x1d4);
+	ddr_ddl_para[cnt++] = value;
+	for (i = 0; i < 4; i++) {
+		value = mmio_read_32(0xf712c000 + 0x210 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x214 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x218 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x21c + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x220 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x224 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x228 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x22c + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x230 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x234 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x238 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x23c + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x240 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+		value = mmio_read_32(0xf712c000 + 0x640 + i * 0x80);
+		ddr_ddl_para[cnt++] = value;
+	}
+	value = mmio_read_32(0xf712c000 + 0x168);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x24c + 0 * 0x80);
+	ddr_ddl_para[cnt++] = value;
+	value = mmio_read_32(0xf712c000 + 0x24c + 2 * 0x80);
+	ddr_ddl_para[cnt++] = value;
+}
+
+int lpddr3_freq_init(int freq)
+{
+	set_ddrc_150mhz();
+	lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 0);
+	if (freq > DDR_FREQ_150M) {
+		ddr_phy_reset();
+		set_ddrc_266mhz();
+		lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
+					    16);
+	}
+	if (freq > DDR_FREQ_266M) {
+		ddr_phy_reset();
+		set_ddrc_400mhz();
+		lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
+					    16 * 2);
+	}
+	if (freq > DDR_FREQ_400M) {
+		ddr_phy_reset();
+		set_ddrc_533mhz();
+		lpddrx_save_ddl_para_mission((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
+					     16 * 3);
+	}
+	if (freq > DDR_FREQ_533M) {
+		ddr_phy_reset();
+		set_ddrc_800mhz();
+		lpddrx_save_ddl_para_mission((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
+					     16 * 3 + 61);
+	}
+	return 0;
+}
+
+static void init_ddr(int freq)
+{
+	unsigned int data;
+	int ret;
+
+
+	data = mmio_read_32((0xf7032000 + 0x030));
+	data |= 1;
+	mmio_write_32((0xf7032000 + 0x030), data);
+	data = mmio_read_32((0xf7032000 + 0x010));
+	data |= 1;
+	mmio_write_32((0xf7032000 + 0x010), data);
+
+	udelay(300);
+	do {
+		data = mmio_read_32((0xf7032000 + 0x030));
+		data &= 3 << 28;
+	} while (data != (3 << 28));
+	do {
+		data = mmio_read_32((0xf7032000 + 0x010));
+		data &= 3 << 28;
+	} while (data != (3 << 28));
+
+	ret = lpddr3_freq_init(freq);
+	if (ret)
+		return;
+}
+
+static void init_ddrc_qos(void)
+{
+	unsigned int port, data;
+
+	mmio_write_32((0xf7124000 + 0x088), 1);
+
+	port = 0;
+	mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x1210);
+	mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x11111111);
+	mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x11111111);
+	mmio_write_32((0xf7120000 + 0x400 + 0 * 0x10), 0x001d0007);
+
+	for (port = 3; port <= 4; port++) {
+		mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x1210);
+		mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x77777777);
+		mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x77777777);
+	}
+
+	port = 1;
+	mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x30000);
+	mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x1234567);
+	mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x1234567);
+
+	mmio_write_32((0xf7124000 + 0x1f0), 0);
+	mmio_write_32((0xf7124000 + 0x0bc), 0x3020100);
+	mmio_write_32((0xf7124000 + 0x0d0), 0x3020100);
+	mmio_write_32((0xf7124000 + 0x1f4), 0x01000100);
+	mmio_write_32((0xf7124000 + 0x08c + 0 * 4), 0xd0670402);
+	mmio_write_32((0xf7124000 + 0x068 + 0 * 4), 0x31);
+	mmio_write_32((0xf7124000 + 0x000), 0x7);
+
+	data = mmio_read_32((0xf7124000 + 0x09c));
+	data &= ~0xff0000;
+	data |= 0x400000;
+	mmio_write_32((0xf7124000 + 0x09c), data);
+	data = mmio_read_32((0xf7124000 + 0x0ac));
+	data &= ~0xff0000;
+	data |= 0x400000;
+	mmio_write_32((0xf7124000 + 0x0ac), data);
+	port = 2;
+	mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x30000);
+	mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x1234567);
+	mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x1234567);
+
+
+	mmio_write_32((0xf7124000 + 0x09c), 0xff7fff);
+	mmio_write_32((0xf7124000 + 0x0a0), 0xff);
+	mmio_write_32((0xf7124000 + 0x0ac), 0xff7fff);
+	mmio_write_32((0xf7124000 + 0x0b0), 0xff);
+	mmio_write_32((0xf7124000 + 0x0bc), 0x3020100);
+	mmio_write_32((0xf7124000 + 0x0d0), 0x3020100);
+}
+
+void hikey_ddr_init(unsigned int ddr_freq)
+{
+	uint32_t data;
+
+	assert((ddr_freq == DDR_FREQ_150M) || (ddr_freq == DDR_FREQ_266M) ||
+	       (ddr_freq == DDR_FREQ_400M) || (ddr_freq == DDR_FREQ_533M) ||
+	       (ddr_freq == DDR_FREQ_800M));
+	init_pll();
+	init_freq();
+
+	init_ddr(ddr_freq);
+
+	ddrc_common_init(ddr_freq);
+	dienum_det_and_rowcol_cfg();
+	detect_ddr_chip_info();
+
+	if ((ddr_freq == DDR_FREQ_400M) || (ddr_freq == DDR_FREQ_800M)) {
+		data = mmio_read_32(0xf7032000 + 0x010);
+		data &= ~0x1;
+		mmio_write_32(0xf7032000 + 0x010, data);
+	} else if ((ddr_freq == DDR_FREQ_266M) || (ddr_freq == DDR_FREQ_533M)) {
+		data = mmio_read_32(0xf7032000 + 0x030);
+		data &= ~0x1;
+		mmio_write_32(0xf7032000 + 0x030, data);
+	} else {
+		data = mmio_read_32(0xf7032000 + 0x010);
+		data &= ~0x1;
+		mmio_write_32(0xf7032000 + 0x010, data);
+		data = mmio_read_32(0xf7032000 + 0x030);
+		data &= ~0x1;
+		mmio_write_32(0xf7032000 + 0x030, data);
+	}
+	dsb();
+	isb();
+
+	/*
+	 * Test memory access. Do not use address 0x0 because the compiler
+	 * may assume it is not a valid address and generate incorrect code
+	 * (GCC 4.9.1 without -fno-delete-null-pointer-checks for instance).
+	 */
+	mmio_write_32(0x4, 0xa5a55a5a);
+	INFO("ddr test value:0x%x\n", mmio_read_32(0x4));
+	init_ddrc_qos();
+}
diff --git a/plat/hisilicon/hikey/hikey_image_load.c b/plat/hisilicon/hikey/hikey_image_load.c
new file mode 100644
index 0000000..0ab1ca4
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/hisilicon/hikey/hikey_io_storage.c b/plat/hisilicon/hikey/hikey_io_storage.c
new file mode 100644
index 0000000..11dd973
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_io_storage.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+#include <lib/semihosting.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "hikey_private.h"
+
+#define EMMC_BLOCK_SHIFT			9
+
+/* Page 1024, since only a few pages before 2048 are used as partition table */
+#define SERIALNO_EMMC_OFFSET			(1024 * 512)
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+static const io_dev_connector_t *emmc_dev_con;
+static uintptr_t emmc_dev_handle;
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+
+static int check_emmc(const uintptr_t spec);
+static int check_fip(const uintptr_t spec);
+
+static const io_block_spec_t emmc_fip_spec = {
+	.offset		= HIKEY_FIP_BASE,
+	.length		= HIKEY_FIP_MAX_SIZE,
+};
+
+static const io_block_dev_spec_t emmc_dev_spec = {
+	/* It's used as temp buffer in block driver. */
+#ifdef IMAGE_BL1
+	.buffer		= {
+		.offset	= HIKEY_BL1_MMC_DATA_BASE,
+		.length	= HIKEY_BL1_MMC_DATA_SIZE,
+	},
+#else
+	.buffer		= {
+		.offset	= HIKEY_MMC_DATA_BASE,
+		.length	= HIKEY_MMC_DATA_SIZE,
+	},
+#endif
+	.ops		= {
+		.read	= mmc_read_blocks,
+		.write	= mmc_write_blocks,
+	},
+	.block_size	= MMC_BLOCK_SIZE,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&emmc_dev_handle,
+		(uintptr_t)&emmc_fip_spec,
+		check_emmc
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_bl2_uuid_spec,
+		check_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		check_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		check_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		check_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		check_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		check_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		check_fip
+	},
+	[SCP_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[SCP_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_cert_uuid_spec,
+		check_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		check_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		check_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		check_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int check_emmc(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(emmc_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(emmc_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void hikey_io_setup(void)
+{
+	int result;
+
+	result = register_io_dev_block(&emmc_dev_con);
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec,
+			     &emmc_dev_handle);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+	assert(result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)result;
+}
+
+/* Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
diff --git a/plat/hisilicon/hikey/hikey_pm.c b/plat/hisilicon/hikey/hikey_pm.c
new file mode 100644
index 0000000..05c1e7f
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_pm.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/sp804_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <hi6220.h>
+#include <hikey_def.h>
+#include <hisi_ipc.h>
+#include <hisi_pwrc.h>
+#include <hisi_sram_map.h>
+
+#define CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+static uintptr_t hikey_sec_entrypoint;
+
+static int hikey_pwr_domain_on(u_register_t mpidr)
+{
+	int cpu, cluster;
+	int curr_cluster;
+
+	cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	cpu = MPIDR_AFFLVL0_VAL(mpidr);
+	curr_cluster = MPIDR_AFFLVL1_VAL(read_mpidr());
+	if (cluster != curr_cluster)
+		hisi_ipc_cluster_on(cpu, cluster);
+
+	hisi_pwrc_set_core_bx_addr(cpu, cluster, hikey_sec_entrypoint);
+	hisi_pwrc_enable_debug(cpu, cluster);
+	hisi_ipc_cpu_on(cpu, cluster);
+
+	return 0;
+}
+
+static void hikey_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+	int cpu, cluster;
+
+	mpidr = read_mpidr();
+	cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	cpu = MPIDR_AFFLVL0_VAL(mpidr);
+
+
+	/*
+	 * Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+	/* Zero the jump address in the mailbox for this cpu */
+	hisi_pwrc_set_core_bx_addr(cpu, cluster, 0);
+
+	/* Program the GIC per-cpu distributor or re-distributor interface */
+	gicv2_pcpu_distif_init();
+	/* Enable the GIC cpu interface */
+	gicv2_cpuif_enable();
+}
+
+void hikey_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+	int cpu, cluster;
+
+	mpidr = read_mpidr();
+	cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	cpu = MPIDR_AFFLVL0_VAL(mpidr);
+
+	gicv2_cpuif_disable();
+	hisi_ipc_cpu_off(cpu, cluster);
+
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+		hisi_ipc_cluster_off(cpu, cluster);
+	}
+}
+
+static void hikey_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cpu = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+
+		/* Program the jump address for the target cpu */
+		hisi_pwrc_set_core_bx_addr(cpu, cluster, hikey_sec_entrypoint);
+
+		gicv2_cpuif_disable();
+
+		if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+			hisi_ipc_cpu_suspend(cpu, cluster);
+	}
+
+	/* Perform the common cluster specific operations */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+		if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+			hisi_pwrc_set_cluster_wfi(1);
+			hisi_pwrc_set_cluster_wfi(0);
+			hisi_ipc_psci_system_off();
+		} else
+			hisi_ipc_cluster_suspend(cpu, cluster);
+	}
+}
+
+static void hikey_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+	unsigned int cluster, cpu;
+
+	/* Nothing to be done on waking up from retention from CPU level */
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	/* Get the mpidr for this cpu */
+	mpidr = read_mpidr_el1();
+	cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT;
+	cpu = mpidr & MPIDR_CPU_MASK;
+
+	/* Enable CCI coherency for cluster */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+	hisi_pwrc_set_core_bx_addr(cpu, cluster, 0);
+
+	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		gicv2_distif_init();
+		gicv2_pcpu_distif_init();
+		gicv2_cpuif_enable();
+	} else {
+		gicv2_pcpu_distif_init();
+		gicv2_cpuif_enable();
+	}
+}
+
+static void hikey_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static void __dead2 hikey_system_off(void)
+{
+	NOTICE("%s: off system\n", __func__);
+
+	/* Pull down GPIO_0_0 to trigger PMIC shutdown */
+	mmio_write_32(0xF8001810, 0x2); /* Pinmux */
+	mmio_write_8(0xF8011400, 1);	/* Pin direction */
+	mmio_write_8(0xF8011004, 0);	/* Pin output value */
+
+	/* Wait for 2s to power off system by PMIC */
+	sp804_timer_init(SP804_TIMER0_BASE, 10, 192);
+	mdelay(2000);
+
+	/*
+	 * PMIC shutdown depends on two conditions: GPIO_0_0 (PWR_HOLD) low,
+	 * and VBUS_DET < 3.6V. For HiKey, VBUS_DET is connected to VDD_4V2
+	 * through Jumper 1-2. So, to complete shutdown, user needs to manually
+	 * remove Jumper 1-2.
+	 */
+	NOTICE("+------------------------------------------+\n");
+	NOTICE("| IMPORTANT: Remove Jumper 1-2 to shutdown |\n");
+	NOTICE("| DANGER:    SoC is still burning. DANGER! |\n");
+	NOTICE("| Board will be reboot to avoid overheat   |\n");
+	NOTICE("+------------------------------------------+\n");
+
+	/* Send the system reset request */
+	mmio_write_32(AO_SC_SYS_STAT0, 0x48698284);
+
+	wfi();
+	panic();
+}
+
+static void __dead2 hikey_system_reset(void)
+{
+	/* Send the system reset request */
+	mmio_write_32(AO_SC_SYS_STAT0, 0x48698284);
+	isb();
+	dsb();
+
+	wfi();
+	panic();
+}
+
+int hikey_validate_power_state(unsigned int power_state,
+			       psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
+					PLAT_MAX_RET_STATE;
+	} else {
+		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					PLAT_MAX_OFF_STATE;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+static int hikey_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+static const plat_psci_ops_t hikey_psci_ops = {
+	.cpu_standby			= NULL,
+	.pwr_domain_on			= hikey_pwr_domain_on,
+	.pwr_domain_on_finish		= hikey_pwr_domain_on_finish,
+	.pwr_domain_off			= hikey_pwr_domain_off,
+	.pwr_domain_suspend		= hikey_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= hikey_pwr_domain_suspend_finish,
+	.system_off			= hikey_system_off,
+	.system_reset			= hikey_system_reset,
+	.validate_power_state		= hikey_validate_power_state,
+	.validate_ns_entrypoint		= hikey_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= hikey_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	hikey_sec_entrypoint = sec_entrypoint;
+
+	/*
+	 * Initialize PSCI ops struct
+	 */
+	*psci_ops = &hikey_psci_ops;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey/hikey_private.h b/plat/hisilicon/hikey/hikey_private.h
new file mode 100644
index 0000000..d82a079
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_private.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY_PRIVATE_H
+#define HIKEY_PRIVATE_H
+
+#include <common/bl_common.h>
+
+#define RANDOM_MAX		0x7fffffffffffffff
+#define RANDOM_MAGIC		0x9a4dbeaf
+
+enum {
+	DDR_FREQ_150M = 150 * 1000,
+	DDR_FREQ_266M = 266 * 1000,
+	DDR_FREQ_400M = 400 * 1000,
+	DDR_FREQ_533M = 533 * 1000,
+	DDR_FREQ_800M = 800 * 1000
+};
+
+struct random_serial_num {
+	uint64_t	magic;
+	uint64_t	data;
+	char		serialno[32];
+};
+
+/*
+ * Function and variable prototypes
+ */
+void hikey_init_mmu_el1(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey_init_mmu_el3(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+
+void hikey_ddr_init(unsigned int ddr_freq);
+void hikey_io_setup(void);
+
+void hikey_sp804_init(void);
+void hikey_gpio_init(void);
+void hikey_pmussi_init(void);
+void hikey_hi6553_init(void);
+void init_mmc0_pll(void);
+void reset_mmc0_clk(void);
+void init_media_clk(void);
+void init_mmc1_pll(void);
+void reset_mmc1_clk(void);
+void hikey_mmc_pll_init(void);
+void hikey_rtc_init(void);
+
+int hikey_get_partition_size(const char *arg, int left, char *response);
+int hikey_get_partition_type(const char *arg, int left, char *response);
+
+int hikey_erase(const char *arg);
+int hikey_flash(const char *arg);
+int hikey_oem(const char *arg);
+int hikey_reboot(const char *arg);
+void hikey_security_setup(void);
+
+const char *hikey_init_serialno(void);
+int hikey_read_serialno(struct random_serial_num *serialno);
+int hikey_write_serialno(struct random_serial_num *serialno);
+
+void init_acpu_dvfs(void);
+
+#endif /* HIKEY_PRIVATE_H */
diff --git a/plat/hisilicon/hikey/hikey_rotpk.S b/plat/hisilicon/hikey/hikey_rotpk.S
new file mode 100644
index 0000000..f308eee
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global hikey_rotpk_hash
+	.global hikey_rotpk_hash_end
+	.section .rodata.hikey_rotpk_hash, "a"
+hikey_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+hikey_rotpk_hash_end:
diff --git a/plat/hisilicon/hikey/hikey_security.c b/plat/hisilicon/hikey/hikey_security.c
new file mode 100644
index 0000000..4b95939
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_security.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/utils_def.h>
+
+#include "hikey_private.h"
+
+#define PORTNUM_MAX		5
+
+#define MDDRC_SECURITY_BASE	0xF7121000
+
+struct int_en_reg {
+	unsigned in_en:1;
+	unsigned reserved:31;
+};
+
+struct rgn_map_reg {
+	unsigned rgn_base_addr:24;
+	unsigned rgn_size:6;
+	unsigned reserved:1;
+	unsigned rgn_en:1;
+};
+
+struct rgn_attr_reg {
+	unsigned sp:4;
+	unsigned security_inv:1;
+	unsigned reserved_0:3;
+	unsigned mid_en:1;
+	unsigned mid_inv:1;
+	unsigned reserved_1:6;
+	unsigned rgn_en:1;
+	unsigned subrgn_disable:16;
+};
+
+static volatile struct int_en_reg *get_int_en_reg(uint32_t base)
+{
+	uint64_t addr = base + 0x20;
+	return (struct int_en_reg *)addr;
+}
+
+static volatile struct rgn_map_reg *get_rgn_map_reg(uint32_t base, int region, int port)
+{
+	uint64_t addr = base + 0x100 + 0x10 * region + 0x400 * (uint64_t)port;
+	return (struct rgn_map_reg *)addr;
+}
+
+static volatile struct rgn_attr_reg *get_rgn_attr_reg(uint32_t base, int region,
+					     int port)
+{
+	uint64_t addr = base + 0x104 + 0x10 * region + 0x400 * (uint64_t)port;
+	return (struct rgn_attr_reg *)addr;
+}
+
+/*
+ * Configure secure memory region
+ * region_size must be a power of 2 and at least 64KB
+ * region_base must be region_size aligned
+ */
+static void sec_protect(uint32_t region_base, uint32_t region_size,
+			int region)
+{
+	volatile struct int_en_reg *int_en;
+	volatile struct rgn_map_reg *rgn_map;
+	volatile struct rgn_attr_reg *rgn_attr;
+	uint32_t i = 0;
+
+	/* ensure secure region number is between 1-15 */
+	assert(region > 0 && region < 16);
+	/* ensure secure region size is a power of 2 >= 64KB */
+	assert(IS_POWER_OF_TWO(region_size) && region_size >= 0x10000);
+	/* ensure secure region address is aligned to region size */
+	assert(!(region_base & (region_size - 1)));
+
+	INFO("BL2: TrustZone: protecting %u bytes of memory at 0x%x\n", region_size,
+	     region_base);
+
+	int_en = get_int_en_reg(MDDRC_SECURITY_BASE);
+	int_en->in_en = 0x1;
+
+	for (i = 0; i < PORTNUM_MAX; i++) {
+		rgn_map = get_rgn_map_reg(MDDRC_SECURITY_BASE, region, i);
+		rgn_attr = get_rgn_attr_reg(MDDRC_SECURITY_BASE, region, i);
+		rgn_map->rgn_base_addr = region_base >> 16;
+		rgn_attr->subrgn_disable = 0x0;
+		rgn_attr->sp = (i == 3) ? 0xC : 0x0;
+		rgn_map->rgn_size = __builtin_ffs(region_size) - 2;
+		rgn_map->rgn_en = 0x1;
+	}
+}
+
+/*******************************************************************************
+ * Initialize the secure environment.
+ ******************************************************************************/
+void hikey_security_setup(void)
+{
+	sec_protect(DDR_SEC_BASE, DDR_SEC_SIZE, 1);
+	sec_protect(DDR_SDP_BASE, DDR_SDP_SIZE, 2);
+}
diff --git a/plat/hisilicon/hikey/hikey_tbbr.c b/plat/hisilicon/hikey/hikey_tbbr.c
new file mode 100644
index 0000000..b7dda8d
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_tbbr.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char hikey_rotpk_hash[], hikey_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = hikey_rotpk_hash;
+	*key_len = hikey_rotpk_hash_end - hikey_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/hisilicon/hikey/hikey_topology.c b/plat/hisilicon/hikey/hikey_topology.c
new file mode 100644
index 0000000..7890eb7
--- /dev/null
+++ b/plat/hisilicon/hikey/hikey_topology.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+/*
+ * The HiKey power domain tree descriptor. The cluster power domains
+ * are arranged so that when the PSCI generic code creates the power
+ * domain tree, the indices of the CPU power domain nodes it allocates
+ * match the linear indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char hikey_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	1,
+	/* Number of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the second cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+/*******************************************************************************
+ * This function returns the HiKey topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return hikey_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/hisilicon/hikey/hisi_dvfs.c b/plat/hisilicon/hikey/hisi_dvfs.c
new file mode 100644
index 0000000..22a67fd
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_dvfs.c
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+#include <hi6553.h>
+#include <hisi_sram_map.h>
+
+#define ACPU_FREQ_MAX_NUM		5
+#define	ACPU_OPP_NUM			7
+
+#define ACPU_VALID_VOLTAGE_MAGIC	(0x5A5AC5C5)
+
+#define ACPU_WAIT_TIMEOUT		(200)
+#define ACPU_WAIT_FOR_WFI_TIMOUT	(2000)
+#define ACPU_DFS_STATE_CNT		(0x10000)
+
+struct acpu_dvfs_sram_stru {
+	unsigned int magic;
+	unsigned int support_freq_num;
+	unsigned int support_freq_max;
+	unsigned int start_prof;
+	unsigned int vol[ACPU_OPP_NUM];
+};
+
+struct acpu_volt_cal_para {
+	unsigned int freq;
+	unsigned int ul_vol;
+	unsigned int dl_vol;
+	unsigned int core_ref_hpm;
+};
+
+struct ddr_volt_cal_para {
+	unsigned int freq;
+	unsigned int ul_vol;
+	unsigned int dl_vol;
+	unsigned int ddr_ref_hpm;
+};
+
+struct acpu_dvfs_opp_para {
+	unsigned int freq;
+	unsigned int acpu_clk_profile0;
+	unsigned int acpu_clk_profile1;
+	unsigned int acpu_vol_profile;
+	unsigned int acpu_pll_freq;
+	unsigned int acpu_pll_frac;
+};
+
+unsigned int efuse_acpu_freq[] = {
+	1200000, 1250000, 1300000, 1350000,
+	1400000, 1450000, 1500000, 1550000,
+	1600000, 1650000, 1700000, 1750000,
+	1800000, 1850000, 1900000, 1950000,
+};
+
+struct acpu_dvfs_opp_para hi6220_acpu_profile[] = {
+	{ 208000,  0x61E5, 0x022, 0x3A, 0x5220102B, 0x05555555 },
+	{ 432000,  0x10A6, 0x121, 0x3A, 0x5120102D, 0x10000005 },
+	{ 729000,  0x2283, 0x100, 0x4A, 0x51101026, 0x10000005 },
+	{ 960000,  0x1211, 0x100, 0x5B, 0x51101032, 0x10000005 },
+	{ 1200000, 0x1211, 0x100, 0x6B, 0x5110207D, 0x10000005 },
+	{ 1400000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
+	{ 1500000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 },
+};
+
+struct acpu_dvfs_opp_para *acpu_dvfs_profile = hi6220_acpu_profile;
+struct acpu_dvfs_sram_stru *acpu_dvfs_sram_buf =
+	(struct acpu_dvfs_sram_stru *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
+
+static inline void write_reg_mask(uintptr_t addr,
+				  uint32_t val, uint32_t mask)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(addr);
+	reg = (reg & ~(mask)) | val;
+	mmio_write_32(addr, reg);
+}
+
+static inline uint32_t read_reg_mask(uintptr_t addr,
+				     uint32_t mask, uint32_t offset)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(addr);
+	reg &= (mask << offset);
+	return (reg >> offset);
+}
+
+static int acpu_dvfs_syspll_cfg(unsigned int prof_id)
+{
+	uint32_t reg0 = 0;
+	uint32_t count = 0;
+	uint32_t clk_div_status = 0;
+
+	/*
+	 * step 1:
+	 *  - ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
+	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
+	 */
+	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x3 << 12, 0x3 << 12);
+	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 4,  0x1 << 4);
+
+	/*
+	 * step 2:
+	 *  - ACPUSYSPLLCFG.acpu_syspll_div_cfg:
+	 *     208MHz, set to 0x5;
+	 *     500MHz, set to 0x2;
+	 *     other opps set to 0x1
+	 */
+	if (prof_id == 0)
+		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x5 << 0, 0x7 << 0);
+	else if (prof_id == 1)
+		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x2 << 0, 0x7 << 0);
+	else
+		write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 0, 0x7 << 0);
+
+	/*
+	 * step 3:
+	 *  - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x3;
+	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0
+	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0
+	 *  - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1
+	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
+	 */
+	clk_div_status = 0x3;
+	do {
+		reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3, 20);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: clk div status timeout!\n", __func__);
+			return -1;
+		}
+	} while (clk_div_status != reg0);
+
+	write_reg_mask(ACPU_SC_VD_CTRL, 0x0, (0x1 << 0) | (0x1 << 11));
+	write_reg_mask(PMCTRL_ACPUCLKDIV, 0x1 << 8, 0x3 << 8);
+	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x1 << 0, 0x1 << 0);
+
+	return 0;
+}
+
+static void acpu_dvfs_clk_div_cfg(unsigned int prof_id,
+				  unsigned int *cpuext_cfg,
+				  unsigned int *acpu_ddr_cfg)
+{
+	if (prof_id == 0) {
+		write_reg_mask(PMCTRL_ACPUCLKDIV,
+			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
+			(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
+			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
+			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
+		*cpuext_cfg = 0x1;
+		*acpu_ddr_cfg = 0x1;
+	} else if (prof_id == 1) {
+		write_reg_mask(PMCTRL_ACPUCLKDIV,
+			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
+			(0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
+			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
+			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
+		*cpuext_cfg = 0x1;
+		*acpu_ddr_cfg = 0x1;
+	} else {
+		/* ddr has not been inited */
+		write_reg_mask(PMCTRL_ACPUCLKDIV,
+			(0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
+			(0x0 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START),
+			(0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) |
+			(0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START));
+		*cpuext_cfg = 0x1;
+		*acpu_ddr_cfg = 0x0;
+	}
+}
+
+static int acpu_dvfs_freq_ascend(unsigned int cur_prof, unsigned int tar_prof)
+{
+	unsigned int reg0 = 0;
+	unsigned int reg1 = 0;
+	unsigned int reg2 = 0;
+	unsigned int count = 0;
+	unsigned int cpuext_cfg_val = 0;
+	unsigned int acpu_ddr_cfg_val = 0;
+	int ret = 0;
+
+	/*
+	 * step 1:
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3;
+	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1;
+	 *
+	 * step 2:
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x5 (208MHz)
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x2 (500MHz)
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x1 (Other OPPs)
+	 *
+	 * step 3:
+	 *  - ACPU_SC_CPU_STAT.clk_div_status_vd = 0x3;
+	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x0;
+	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x0;
+	 *  - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1;
+	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1
+	 */
+	ret = acpu_dvfs_syspll_cfg(cur_prof);
+	if (ret)
+		return -1;
+
+	/*
+	 * step 4:
+	 *  - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
+			SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: syspll sw status timeout\n", __func__);
+			return -1;
+		}
+	} while (reg0 != 0x1);
+
+	/* Enable VD functionality if > 800MHz */
+	if (acpu_dvfs_profile[tar_prof].freq > 800000) {
+
+		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
+			HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
+
+		/*
+		 * step 5:
+		 *  - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
+		 *  - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
+		 */
+		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
+			HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
+		write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
+			ACPU_SC_VD_MASK_PATTERN_VAL,
+			ACPU_SC_VD_MASK_PATTERN_MASK);
+
+		/*
+		 * step 6:
+		 *  - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
+		 *  - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
+		 *  - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
+		 *  - ACPU_SC_VD_DLY_FIXED_CTRL  = 0x1;
+		 */
+		mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
+		mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
+		mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
+		mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
+
+		/*
+		 * step 7:
+		 *  - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
+		 *  - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
+		 *  - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
+		 *  - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
+		 *
+		 * step 8:
+		 *  - ACPU_SC_VD_CTRL.tune = 0x7;
+		 */
+		write_reg_mask(ACPU_SC_VD_CTRL,
+			ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
+			ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
+	}
+
+	/* step 9: ACPUPLLCTRL.acpupll_en_cfg = 0x0 */
+	write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0,
+		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
+
+	/* step 10: set PMCTRL_ACPUPLLFREQ and PMCTRL_ACPUPLLFRAC */
+	mmio_write_32(PMCTRL_ACPUPLLFREQ,
+		acpu_dvfs_profile[tar_prof].acpu_pll_freq);
+	mmio_write_32(PMCTRL_ACPUPLLFRAC,
+		acpu_dvfs_profile[tar_prof].acpu_pll_frac);
+
+	/*
+	 * step 11:
+	 *  - wait for 1us;
+	 *  - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
+	 */
+	count = 0;
+	while (count < ACPU_WAIT_TIMEOUT)
+		count++;
+
+	write_reg_mask(PMCTRL_ACPUPLLCTRL,
+		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
+		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
+
+	/* step 12: PMCTRL_ACPUVOLPMUADDR = 0x100da */
+	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
+
+	/*
+	 * step 13:
+	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (208MHz);
+	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (500MHz);
+	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x20 (798MHz);
+	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1300MHz);
+	 *  - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1500MHz);
+	 */
+	write_reg_mask(PMCTRL_ACPUDESTVOL,
+		acpu_dvfs_profile[tar_prof].acpu_vol_profile,
+		((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
+
+	/*
+	 * step 14:
+	 *  - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
+	 *  - Polling ACPUVOLTIMEOUT.acpu_vol_timeout == 0x1
+	 *  - Config PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg
+	 *  - Config ACPUCLKDIV.cpuext_clk_div_cfg;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
+			SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
+		reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
+			SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
+		reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
+			SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpu destvol cfg timeout.\n", __func__);
+			return -1;
+		}
+	} while ((reg0 != reg1) || (reg2 != 0x1));
+
+	acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
+
+	/*
+	 * step 15:
+	 *  - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
+	 *  - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
+	 *  - ACPUPLLCTRL.acpupll_timeout = 0x1;
+	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
+			SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
+		reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
+			SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
+		reg2 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
+			SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpu clk div cfg timeout.\n", __func__);
+			return -1;
+		}
+	} while ((reg1 != cpuext_cfg_val) ||
+		(reg0 != acpu_ddr_cfg_val) ||
+		(reg2 != 0x1));
+
+	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
+		0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
+
+	/*
+	 * step 16:
+	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
+	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
+	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
+	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
+	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
+	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
+	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
+	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
+	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
+			SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpu pll sw status timeout.\n", __func__);
+			return -1;
+		}
+	} while (reg0 != 0x1);
+
+	if (acpu_dvfs_profile[tar_prof].freq > 800000)
+		write_reg_mask(ACPU_SC_VD_CTRL,
+			ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
+
+	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
+		(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
+		(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
+
+	return 0;
+}
+
+static int acpu_dvfs_freq_descend(unsigned int cur_prof, unsigned int tar_prof)
+{
+	unsigned int reg0 = 0;
+	unsigned int reg1 = 0;
+	unsigned int reg2 = 0;
+	unsigned int count = 0;
+	unsigned int cpuext_cfg_val = 0;
+	unsigned int acpu_ddr_cfg_val = 0;
+	int ret = 0;
+
+	ret = acpu_dvfs_syspll_cfg(tar_prof);
+	if (ret)
+		return -1;
+
+	/*
+	 * step 4:
+	 *  - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, 2);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: syspll sw status timeout.\n", __func__);
+			return -1;
+		}
+	} while (reg0 != 0x1);
+
+	/*
+	 * Step 5:
+	 *  - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x0
+	 */
+	write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0, 0x1 << 0);
+
+	/*
+	 * step 6
+	 *  - Config PMCTRL_ACPUPLLFREQ and ACPUPLLFRAC
+	 */
+	mmio_write_32(PMCTRL_ACPUPLLFREQ, acpu_dvfs_profile[tar_prof].acpu_pll_freq);
+	mmio_write_32(PMCTRL_ACPUPLLFRAC, acpu_dvfs_profile[tar_prof].acpu_pll_frac);
+
+	/*
+	 * step 7:
+	 *  - Wait 1us;
+	 *  - Config PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1
+	 */
+	count = 0;
+	while (count < ACPU_WAIT_TIMEOUT)
+		count++;
+
+	write_reg_mask(PMCTRL_ACPUPLLCTRL,
+		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START,
+		0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START);
+
+	/* Enable VD functionality if > 800MHz */
+	if (acpu_dvfs_profile[tar_prof].freq > 800000) {
+
+		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
+			HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK);
+
+		/*
+		 * step 9:
+		 *  - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A;
+		 *  - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB;
+		 */
+		write_reg_mask(ACPU_SC_VD_HPM_CTRL,
+			HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK);
+		write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL,
+			ACPU_SC_VD_MASK_PATTERN_VAL,
+			ACPU_SC_VD_MASK_PATTERN_MASK);
+
+		/*
+		 * step 10:
+		 *  - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF;
+		 *  - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF;
+		 *  - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF;
+		 *  - ACPU_SC_VD_DLY_FIXED_CTRL  = 0x1;
+		 */
+		mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF);
+		mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF);
+		mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF);
+		mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1);
+
+		/*
+		 * step 11:
+		 *  - ACPU_SC_VD_CTRL.shift_table0 = 0x1;
+		 *  - ACPU_SC_VD_CTRL.shift_table1 = 0x3;
+		 *  - ACPU_SC_VD_CTRL.shift_table2 = 0x5;
+		 *  - ACPU_SC_VD_CTRL.shift_table3 = 0x6;
+		 *
+		 * step 12:
+		 *  - ACPU_SC_VD_CTRL.tune = 0x7;
+		 */
+		write_reg_mask(ACPU_SC_VD_CTRL,
+			ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL,
+			ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK);
+	}
+
+	/*
+	 * step 13:
+	 *  - Pollig PMCTRL_ACPUPLLCTRL.acpupll_timeout == 0x1;
+	 *  - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1,
+			SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpupll timeout.\n", __func__);
+			return -1;
+		}
+	} while (reg0 != 0x1);
+
+	write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0,
+		0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START);
+
+	/*
+	 * step 14:
+	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
+	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
+	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
+	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
+	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
+	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
+	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
+	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1,
+			SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpupll sw status timeout.\n", __func__);
+			return -1;
+		}
+	} while (reg0 != 0x1);
+
+	if (acpu_dvfs_profile[tar_prof].freq > 800000)
+		write_reg_mask(ACPU_SC_VD_CTRL,
+			ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK);
+
+	/*
+	 * step 15:
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
+	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
+	 */
+	write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0,
+		(0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) |
+		(0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START));
+
+	/*
+	 * step 16:
+	 *  - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x0;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3,
+			ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: clk div status timeout.\n", __func__);
+			return -1;
+		}
+	} while (reg0 != 0x0);
+
+	acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val);
+
+	/*
+	 * step 17:
+	 *  - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat;
+	 *  - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat;
+	 *  - PMCTRL_ACPUVOLPMUADDR = 0x1006C;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
+			SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START);
+		reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3,
+			SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpu clk div cfg timeout.\n", __func__);
+			return -1;
+		}
+	} while ((reg0 != cpuext_cfg_val) || (reg1 != acpu_ddr_cfg_val));
+
+	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da);
+
+	/*
+	 * step 16:
+	 *  - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1;
+	 *  - ACPU_SC_VD_CTRL.force_clk_en = 0x0;
+	 *  - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0;
+	 *  - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0;
+	 *  - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0;
+	 *  - ACPU_SC_VD_CTRL.div_en_dif = 0x1;
+	 *  - ACPU_SC_VD_CTRL.tune_en_int = 0x1;
+	 *  - ACPU_SC_VD_CTRL.tune_en_dif = 0x1;
+	 *  - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0;
+	 *  - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0;
+	 */
+	write_reg_mask(PMCTRL_ACPUDESTVOL,
+		acpu_dvfs_profile[tar_prof].acpu_vol_profile,
+		((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1));
+
+	/*
+	 * step 19:
+	 *  - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol
+	 *  - ACPUVOLTIMEOUT.acpu_vol_timeout = 0x1;
+	 */
+	count = 0;
+	do {
+		reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
+			SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START);
+		reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F,
+			SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START);
+		reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1,
+			SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START);
+		if ((count++) > ACPU_DFS_STATE_CNT) {
+			ERROR("%s: acpu destvol cfg timeout.\n", __func__);
+			return -1;
+		}
+	} while ((reg0 != reg1) || (reg2 != 0x1));
+
+	return 0;
+}
+
+int acpu_dvfs_target(unsigned int curr_prof, unsigned int target_prof)
+{
+	int ret = 0;
+
+	if (curr_prof == target_prof) {
+		INFO("%s: target_prof is equal curr_prof: is %d!\n",
+			__func__, curr_prof);
+		return 0;
+	}
+
+	if ((curr_prof >= ACPU_FREQ_MAX_NUM) ||
+	    (target_prof >= ACPU_FREQ_MAX_NUM)) {
+		INFO("%s: invalid parameter %d %d\n",
+			__func__, curr_prof, target_prof);
+		return -1;
+	}
+
+	if (target_prof > acpu_dvfs_sram_buf->support_freq_num)
+		target_prof = acpu_dvfs_sram_buf->support_freq_num;
+
+	if (target_prof < curr_prof)
+		ret = acpu_dvfs_freq_descend(curr_prof, target_prof);
+	else if (target_prof > curr_prof)
+		ret = acpu_dvfs_freq_ascend(curr_prof, target_prof);
+
+	if (ret) {
+		ERROR("%s: acpu_dvfs_target failed!\n", __func__);
+		return -1;
+	}
+
+	/* Complete acpu dvfs setting and set magic number */
+	acpu_dvfs_sram_buf->start_prof = target_prof;
+	acpu_dvfs_sram_buf->magic = ACPU_VALID_VOLTAGE_MAGIC;
+
+	mmio_write_32(DDR_DFS_FREQ_ADDR, 800000);
+	return 0;
+}
+
+static int acpu_dvfs_set_freq(void)
+{
+	unsigned int i;
+	unsigned int curr_prof;
+	unsigned int target_prof;
+	unsigned int max_freq = 0;
+
+	max_freq = acpu_dvfs_sram_buf->support_freq_max;
+
+	for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++) {
+
+		if (max_freq == hi6220_acpu_profile[i].freq) {
+			target_prof = i;
+			break;
+		}
+	}
+
+	if (i == acpu_dvfs_sram_buf->support_freq_num) {
+		ERROR("%s: cannot found max freq profile\n", __func__);
+		return -1;
+	}
+
+	curr_prof = 0;
+	target_prof = i;
+
+	/* if max freq is 208MHz, do nothing */
+	if (curr_prof == target_prof)
+		return 0;
+
+	if (acpu_dvfs_target(curr_prof, target_prof)) {
+		ERROR("%s: set acpu freq failed!", __func__);
+		return -1;
+	}
+
+	INFO("%s: support freq num is %d\n",
+		__func__, acpu_dvfs_sram_buf->support_freq_num);
+	INFO("%s: start prof is 0x%x\n",
+		__func__,  acpu_dvfs_sram_buf->start_prof);
+	INFO("%s: magic is 0x%x\n",
+		__func__, acpu_dvfs_sram_buf->magic);
+	INFO("%s: voltage:\n", __func__);
+	for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++)
+		INFO("  - %d: 0x%x\n", i, acpu_dvfs_sram_buf->vol[i]);
+
+	NOTICE("%s: set acpu freq success!", __func__);
+	return 0;
+}
+
+struct acpu_dvfs_volt_setting {
+	unsigned int magic;
+	unsigned int support_freq_num;
+	unsigned int support_freq_max;
+	unsigned int start_prof;
+	unsigned int vol[7];
+	unsigned int hmp_dly_threshold[7];
+};
+
+static void acpu_dvfs_volt_init(void)
+{
+	struct acpu_dvfs_volt_setting *volt;
+
+	/*
+	 * - set default voltage;
+	 * - set pmu address;
+	 * - set voltage up and down step;
+	 * - set voltage stable time;
+	 */
+	mmio_write_32(PMCTRL_ACPUDFTVOL, 0x4a);
+	mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0xda);
+	mmio_write_32(PMCTRL_ACPUVOLUPSTEP, 0x1);
+	mmio_write_32(PMCTRL_ACPUVOLDNSTEP, 0x1);
+	mmio_write_32(PMCTRL_ACPUPMUVOLUPTIME, 0x60);
+	mmio_write_32(PMCTRL_ACPUPMUVOLDNTIME, 0x60);
+	mmio_write_32(PMCTRL_ACPUCLKOFFCFG, 0x1000);
+
+	volt = (void *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR;
+	volt->magic = 0x5a5ac5c5;
+	volt->support_freq_num = 5;
+	volt->support_freq_max = 1200000;
+	volt->start_prof = 4;
+	volt->vol[0] = 0x49;
+	volt->vol[1] = 0x49;
+	volt->vol[2] = 0x50;
+	volt->vol[3] = 0x60;
+	volt->vol[4] = 0x78;
+	volt->vol[5] = 0x78;
+	volt->vol[6] = 0x78;
+
+	volt->hmp_dly_threshold[0] = 0x0;
+	volt->hmp_dly_threshold[1] = 0x0;
+	volt->hmp_dly_threshold[2] = 0x0;
+	volt->hmp_dly_threshold[3] = 0x0e8b0e45;
+	volt->hmp_dly_threshold[4] = 0x10691023;
+	volt->hmp_dly_threshold[5] = 0x10691023;
+	volt->hmp_dly_threshold[6] = 0x10691023;
+
+	INFO("%s: success!\n", __func__);
+}
+
+void init_acpu_dvfs(void)
+{
+	unsigned int i = 0;
+
+	INFO("%s: pmic version %d\n", __func__,
+	     mmio_read_8(HI6553_VERSION_REG));
+
+	/* init parameters */
+	mmio_write_32(ACPU_CHIP_MAX_FREQ, efuse_acpu_freq[8]);
+	INFO("%s: ACPU_CHIP_MAX_FREQ=0x%x.\n",
+		__func__, mmio_read_32(ACPU_CHIP_MAX_FREQ));
+
+	/* set maximum support frequency to 1.2GHz */
+	for (i = 0; i < ACPU_FREQ_MAX_NUM; i++)
+		acpu_dvfs_sram_buf->vol[i] = hi6220_acpu_profile[i].acpu_vol_profile;
+
+	acpu_dvfs_sram_buf->support_freq_num = ACPU_FREQ_MAX_NUM;
+	acpu_dvfs_sram_buf->support_freq_max = 1200000;
+
+	/* init acpu dvfs */
+	acpu_dvfs_volt_init();
+	acpu_dvfs_set_freq();
+}
diff --git a/plat/hisilicon/hikey/hisi_ipc.c b/plat/hisilicon/hikey/hisi_ipc.c
new file mode 100644
index 0000000..43ee0b2
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_ipc.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <hisi_ipc.h>
+#include <hisi_sram_map.h>
+
+static int ipc_init;
+
+static unsigned int cpu_ipc_num[PLATFORM_CLUSTER_COUNT][PLATFORM_CORE_COUNT_PER_CLUSTER] = {
+	{
+		HISI_IPC_MCU_INT_SRC_ACPU0_PD,
+		HISI_IPC_MCU_INT_SRC_ACPU1_PD,
+		HISI_IPC_MCU_INT_SRC_ACPU2_PD,
+		HISI_IPC_MCU_INT_SRC_ACPU3_PD,
+	},
+	{
+		HISI_IPC_MCU_INT_SRC_ACPU4_PD,
+		HISI_IPC_MCU_INT_SRC_ACPU5_PD,
+		HISI_IPC_MCU_INT_SRC_ACPU6_PD,
+		HISI_IPC_MCU_INT_SRC_ACPU7_PD,
+	}
+};
+
+int hisi_cpus_pd_in_cluster_besides_curr(unsigned int cpu,
+					 unsigned int cluster)
+{
+	unsigned int val = 0, cpu_val = 0;
+	int i;
+
+	val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR);
+	val = val >> (cluster * 16);
+
+	for (i = 0; i < PLATFORM_CORE_COUNT_PER_CLUSTER; i++) {
+
+		if (cpu == i)
+			continue;
+
+		cpu_val = (val >> (i * 4)) & 0xF;
+		if (cpu_val == 0x8)
+			return 0;
+	}
+
+	return 1;
+}
+
+int hisi_cpus_powered_off_besides_curr(unsigned int cpu)
+{
+	unsigned int val;
+
+	val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR);
+	return (val == (0x8 << (cpu * 4)));
+}
+
+static void hisi_ipc_send(unsigned int ipc_num)
+{
+	if (!ipc_init) {
+		printf("error ipc base is null!!!\n");
+		return;
+	}
+
+	mmio_write_32(HISI_IPC_CPU_RAW_INT_ADDR, 1 << ipc_num);
+}
+
+void hisi_ipc_spin_lock(unsigned int signal)
+{
+	unsigned int hs_ctrl;
+
+	if (signal >= HISI_IPC_INT_SRC_NUM)
+		return;
+
+	do {
+		hs_ctrl = mmio_read_32(HISI_IPC_ACPU_CTRL(signal));
+	} while (hs_ctrl);
+}
+
+void hisi_ipc_spin_unlock(unsigned int signal)
+{
+	if (signal >= HISI_IPC_INT_SRC_NUM)
+		return;
+
+	mmio_write_32(HISI_IPC_ACPU_CTRL(signal), 0);
+}
+
+void hisi_ipc_cpu_on_off(unsigned int cpu, unsigned int cluster,
+			 unsigned int mode)
+{
+	unsigned int val = 0;
+	unsigned int offset;
+
+	if (mode == HISI_IPC_PM_ON)
+		offset = cluster * 16 + cpu * 4;
+	else
+		offset = cluster * 16 + cpu * 4 + 1;
+
+	hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+	val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR);
+	val |= (0x01 << offset);
+	mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val);
+	isb();
+	dsb();
+	hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+	hisi_ipc_send(cpu_ipc_num[cluster][cpu]);
+}
+
+void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster)
+{
+	hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_ON);
+}
+
+void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster)
+{
+	hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_OFF);
+}
+
+void hisi_ipc_cluster_on_off(unsigned int cpu, unsigned int cluster,
+			     unsigned int mode)
+{
+	unsigned int val = 0;
+	unsigned int offset;
+
+	if (mode == HISI_IPC_PM_ON)
+		offset = cluster * 4;
+	else
+		offset = cluster * 4 + 1;
+
+	hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+	val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR);
+	val |= (0x01 << offset);
+	mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val);
+	isb();
+	dsb();
+	hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+	hisi_ipc_send(cpu_ipc_num[cluster][cpu]);
+}
+
+void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster)
+{
+	hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_ON);
+}
+
+void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster)
+{
+	hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_OFF);
+}
+
+void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int val = 0;
+	unsigned int offset;
+
+	offset = cluster * 16 + cpu * 4 + 2;
+
+	hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+	val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR);
+	val |= (0x01 << offset);
+	mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val);
+	hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+	hisi_ipc_send(cpu_ipc_num[cluster][cpu]);
+}
+
+void hisi_ipc_cluster_suspend(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int val;
+	unsigned int offset;
+
+	offset = cluster * 4 + 1;
+
+	hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+	if (hisi_cpus_pd_in_cluster_besides_curr(cpu, cluster)) {
+		val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR);
+		val |= (0x01 << offset);
+		mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val);
+	}
+	hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+	hisi_ipc_send(cpu_ipc_num[cluster][cpu]);
+}
+
+void hisi_ipc_psci_system_off(void)
+{
+	hisi_ipc_send(HISI_IPC_MCU_INT_SRC_ACPU_PD);
+}
+
+int hisi_ipc_init(void)
+{
+	ipc_init = 1;
+
+	mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, 0x8);
+	mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, 0x8);
+	return 0;
+}
diff --git a/plat/hisilicon/hikey/hisi_mcu.c b/plat/hisilicon/hikey/hisi_mcu.c
new file mode 100644
index 0000000..ac83bd8
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_mcu.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi6220.h>
+
+#define MCU_SECTION_MAX		30
+
+enum MCU_IMAGE_SEC_TYPE_ENUM {
+	MCU_IMAGE_SEC_TYPE_TEXT = 0,	/* text section */
+	MCU_IMAGE_SEC_TYPE_DATA,	/* data section */
+	MCU_IMAGE_SEC_TYPE_BUTT
+};
+
+enum MCU_IMAGE_SEC_LOAD_ENUM {
+	MCU_IMAGE_SEC_LOAD_STATIC = 0,
+	MCU_IMAGE_SEC_LOAD_DYNAMIC,
+	MCU_IMAGE_SEC_LOAD_BUFFER,
+	MCU_IMAGE_SEC_LOAD_MODEM_ENTRY,
+	MCU_IMAGE_SEC_LOAD_BUTT
+};
+
+struct mcu_image_sec {
+	unsigned short serial;
+	char type;
+	char load_attr;
+	uint32_t src_offset;		/* offset in image */
+	uint32_t dst_offset;		/* offset in memory */
+	uint32_t size;
+};
+
+struct mcu_image_head {
+	char time_stamp[24];
+	uint32_t image_size;
+	uint32_t secs_num;
+	struct mcu_image_sec secs[MCU_SECTION_MAX];
+};
+
+#define SOC_SRAM_M3_BASE_ADDR		(0xF6000000)
+
+#define MCU_SRAM_SIZE			(0x0000C000)
+#define MCU_CACHE_SIZE			(0x00004000)
+#define MCU_CODE_SIZE			(MCU_SRAM_SIZE - MCU_CACHE_SIZE)
+
+#define MCU_SYS_MEM_ADDR		(0x05E00000)
+#define MCU_SYS_MEM_SIZE		(0x00100000)
+
+static uint32_t mcu2ap_addr(uint32_t mcu_addr)
+{
+	if (mcu_addr < MCU_CODE_SIZE)
+		return (mcu_addr + SOC_SRAM_M3_BASE_ADDR);
+	else if ((mcu_addr >= MCU_SRAM_SIZE) &&
+		 (mcu_addr < MCU_SRAM_SIZE + MCU_SYS_MEM_SIZE))
+		return mcu_addr - MCU_SRAM_SIZE + MCU_SYS_MEM_ADDR;
+	else
+		return mcu_addr;
+}
+
+static int is_binary_header_invalid(struct mcu_image_head *head,
+				    unsigned int length)
+{
+	/* invalid cases */
+	if ((head->image_size == 0) ||
+	    (head->image_size > length) ||
+	    (head->secs_num > MCU_SECTION_MAX) ||
+	    (head->secs_num == 0))
+		return 1;
+
+	return 0;
+}
+
+static int is_binary_section_invalid(struct mcu_image_sec *sec,
+				     struct mcu_image_head *head)
+{
+	unsigned long ap_dst_offset = 0;
+
+	if ((sec->serial >= head->secs_num) ||
+	    (sec->src_offset + sec->size > head->image_size))
+		return 1;
+
+	if ((sec->type >= MCU_IMAGE_SEC_TYPE_BUTT) ||
+	    (sec->load_attr >= MCU_IMAGE_SEC_LOAD_BUTT))
+		return 1;
+
+	ap_dst_offset = mcu2ap_addr(sec->dst_offset);
+	if ((ap_dst_offset >= SOC_SRAM_M3_BASE_ADDR) &&
+	    (ap_dst_offset < SOC_SRAM_M3_BASE_ADDR + 0x20000 - sec->size))
+		return 0;
+	else if ((ap_dst_offset >= MCU_SYS_MEM_ADDR) &&
+		 (ap_dst_offset < MCU_SYS_MEM_ADDR + MCU_SYS_MEM_SIZE - sec->size))
+		return 0;
+	else if ((ap_dst_offset >= 0xfff8e000) &&
+		 (ap_dst_offset < 0xfff91c00 - sec->size))
+		return 0;
+
+	ERROR("%s: mcu destination address invalid.\n", __func__);
+	ERROR("%s: number=%d, dst offset=%d size=%d\n",
+		__func__, sec->serial, sec->dst_offset, sec->size);
+	return 1;
+}
+
+void hisi_mcu_enable_sram(void)
+{
+	mmio_write_32(AO_SC_PERIPH_CLKEN4,
+		      AO_SC_PERIPH_CLKEN4_HCLK_IPC_S |
+		      AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS);
+
+	/* set register to enable dvfs which is used by mcu */
+	mmio_write_32(PERI_SC_RESERVED8_ADDR, 0x0A001022);
+
+	/* mcu mem is powered on, need de-assert reset */
+	mmio_write_32(AO_SC_PERIPH_RSTDIS4,
+		      AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N);
+
+	/* enable mcu hclk */
+	mmio_write_32(AO_SC_PERIPH_CLKEN4,
+		      AO_SC_PERIPH_CLKEN4_HCLK_MCU |
+		      AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP);
+}
+
+void hisi_mcu_start_run(void)
+{
+	unsigned int val;
+
+	/* set mcu ddr remap configuration */
+	mmio_write_32(AO_SC_MCU_SUBSYS_CTRL2, MCU_SYS_MEM_ADDR);
+
+	/* de-assert reset for mcu and to run */
+	mmio_write_32(AO_SC_PERIPH_RSTDIS4,
+		AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N |
+		AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N |
+		AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N |
+		AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N);
+
+	val = mmio_read_32(AO_SC_SYS_CTRL2);
+	mmio_write_32(AO_SC_SYS_CTRL2,
+		val | AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR);
+
+	INFO("%s: AO_SC_SYS_CTRL2=%x\n", __func__,
+		mmio_read_32(AO_SC_SYS_CTRL2));
+}
+
+int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size)
+{
+	unsigned int i;
+	struct mcu_image_head *head;
+	char *buf;
+
+	head = (struct mcu_image_head *)image_base;
+	if (is_binary_header_invalid(head, image_size)) {
+		ERROR("Invalid %s image header.\n", head->time_stamp);
+		return -1;
+	}
+
+	buf = (char *)head;
+	for (i = 0; i < head->secs_num; i++) {
+
+		int *src, *dst;
+
+		/* check the sections */
+		if (is_binary_section_invalid(&head->secs[i], head)) {
+			ERROR("Invalid mcu section.\n");
+			return -1;
+		}
+
+		/* check if the section is static-loaded */
+		if (head->secs[i].load_attr != MCU_IMAGE_SEC_LOAD_STATIC)
+			continue;
+
+		/* copy the sections */
+		src = (int *)(intptr_t)(buf + head->secs[i].src_offset);
+		dst = (int *)(intptr_t)mcu2ap_addr(head->secs[i].dst_offset);
+
+		memcpy((void *)dst, (void *)src, head->secs[i].size);
+
+		INFO("%s: mcu sections %d:\n", __func__, i);
+		INFO("%s:  src  = 0x%x\n",
+		     __func__, (unsigned int)(uintptr_t)src);
+		INFO("%s:  dst  = 0x%x\n",
+		     __func__, (unsigned int)(uintptr_t)dst);
+		INFO("%s:  size = %d\n", __func__, head->secs[i].size);
+
+		INFO("%s:  [SRC 0x%x] 0x%x 0x%x 0x%x 0x%x\n",
+		     __func__, (unsigned int)(uintptr_t)src,
+		     src[0], src[1], src[2], src[3]);
+		INFO("%s:  [DST 0x%x] 0x%x 0x%x 0x%x 0x%x\n",
+		     __func__, (unsigned int)(uintptr_t)dst,
+		     dst[0], dst[1], dst[2], dst[3]);
+	}
+
+	return 0;
+}
diff --git a/plat/hisilicon/hikey/hisi_pwrc.c b/plat/hisilicon/hikey/hisi_pwrc.c
new file mode 100644
index 0000000..e2e3db7
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_pwrc.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <hi6220_regs_acpu.h>
+#include <hi6220_regs_ao.h>
+#include <hisi_ipc.h>
+#include <hisi_pwrc.h>
+#include <hisi_sram_map.h>
+
+#define CLUSTER_CORE_COUNT		(4)
+#define CLUSTER_CORE_MASK		((1 << CLUSTER_CORE_COUNT) - 1)
+
+void hisi_pwrc_set_core_bx_addr(unsigned int core, unsigned int cluster,
+				uintptr_t entry_point)
+{
+	uintptr_t *core_entry = (uintptr_t *)PWRCTRL_ACPU_ASM_D_ARM_PARA_AD;
+	unsigned int i;
+
+	if (!core_entry) {
+		INFO("%s: core entry point is null!\n", __func__);
+		return;
+	}
+
+	i = cluster * CLUSTER_CORE_COUNT + core;
+	mmio_write_64((uintptr_t)(core_entry + i), entry_point);
+}
+
+void hisi_pwrc_set_cluster_wfi(unsigned int cluster)
+{
+	unsigned int reg = 0;
+
+	if (cluster == 0) {
+		reg = mmio_read_32(ACPU_SC_SNOOP_PWD);
+		reg |= PD_DETECT_START0;
+		mmio_write_32(ACPU_SC_SNOOP_PWD, reg);
+	} else if (cluster == 1) {
+		reg = mmio_read_32(ACPU_SC_SNOOP_PWD);
+		reg |= PD_DETECT_START1;
+		mmio_write_32(ACPU_SC_SNOOP_PWD, reg);
+	}
+}
+
+void hisi_pwrc_enable_debug(unsigned int core, unsigned int cluster)
+{
+	unsigned int val, enable;
+
+	enable = 1U << (core + PDBGUP_CLUSTER1_SHIFT * cluster);
+
+	/* Enable debug module */
+	val = mmio_read_32(ACPU_SC_PDBGUP_MBIST);
+	mmio_write_32(ACPU_SC_PDBGUP_MBIST, val | enable);
+	do {
+		/* RAW barrier */
+		val = mmio_read_32(ACPU_SC_PDBGUP_MBIST);
+	} while (!(val & enable));
+}
+
+int hisi_pwrc_setup(void)
+{
+	unsigned int reg, sec_entrypoint;
+	extern char pm_asm_code[], pm_asm_code_end[];
+	extern char v7_asm[], v7_asm_end[];
+
+	sec_entrypoint = PWRCTRL_ACPU_ASM_CODE_BASE;
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(0), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(1), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(2), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(3), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(4), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(5), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(6), sec_entrypoint >> 2);
+	mmio_write_32(ACPU_SC_CPUx_RVBARADDR(7), sec_entrypoint >> 2);
+
+	memset((void *)PWRCTRL_ACPU_ASM_SPACE_ADDR, 0, 0x400);
+	memcpy((void *)PWRCTRL_ACPU_ASM_SPACE_ADDR, (void *)v7_asm,
+	       v7_asm_end - v7_asm);
+
+	memcpy((void *)PWRCTRL_ACPU_ASM_CODE_BASE, (void *)pm_asm_code,
+	       pm_asm_code_end - pm_asm_code);
+
+	reg = mmio_read_32(AO_SC_SYS_CTRL1);
+	/* Remap SRAM address for ACPU */
+	reg |= AO_SC_SYS_CTRL1_REMAP_SRAM_AARM |
+	       AO_SC_SYS_CTRL1_REMAP_SRAM_AARM_MSK;
+
+	/* Enable reset signal for watchdog */
+	reg |= AO_SC_SYS_CTRL1_AARM_WD_RST_CFG |
+	       AO_SC_SYS_CTRL1_AARM_WD_RST_CFG_MSK;
+	mmio_write_32(AO_SC_SYS_CTRL1, reg);
+
+	return 0;
+}
diff --git a/plat/hisilicon/hikey/hisi_pwrc_sram.S b/plat/hisilicon/hikey/hisi_pwrc_sram.S
new file mode 100644
index 0000000..62542f2
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_pwrc_sram.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <hi6220.h>
+#include <hisi_sram_map.h>
+
+	.global pm_asm_code
+	.global pm_asm_code_end
+	.global v7_asm
+	.global v7_asm_end
+
+func pm_asm_code _align=3
+	mov	x0, 0
+	msr	oslar_el1, x0
+
+	mrs	x0, CORTEX_A53_CPUACTLR_EL1
+	bic	x0, x0, #(CORTEX_A53_CPUACTLR_EL1_RADIS | \
+				CORTEX_A53_CPUACTLR_EL1_L1RADIS)
+	orr	x0, x0, #0x180000
+	orr	x0, x0, #0xe000
+	msr	CORTEX_A53_CPUACTLR_EL1, x0
+
+	mrs	x3, actlr_el3
+	orr	x3, x3, #ACTLR_EL3_L2ECTLR_BIT
+	msr	actlr_el3, x3
+
+	mrs	x3, actlr_el2
+	orr	x3, x3, #ACTLR_EL2_L2ECTLR_BIT
+	msr	actlr_el2, x3
+
+	ldr	x3, =PWRCTRL_ACPU_ASM_D_ARM_PARA_AD
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+pen:	ldr	x4, [x3, x0, LSL #3]
+	cbz	x4, pen
+
+	mov	x0, #0x0
+	mov	x1, #0x0
+	mov	x2, #0x0
+	mov	x3, #0x0
+	br	x4
+
+	.ltorg
+
+pm_asm_code_end:
+endfunc pm_asm_code
+
+	/*
+	 * By default, all cores in Hi6220 reset with aarch32 mode.
+	 * Now hardcode ARMv7 instructions to execute warm reset for
+	 * switching aarch64 mode.
+	 */
+	.align	3
+	.section .rodata.v7_asm, "aS"
+v7_asm:
+	.word	0xE1A00000	// nop
+	.word	0xE3A02003	// mov r2, #3
+	.word	0xEE0C2F50	// mcr 15, 0, r2, cr12, cr0, {2}
+	.word	0xE320F003	// wfi
+
+	.ltorg
+v7_asm_end:
diff --git a/plat/hisilicon/hikey/hisi_sip_svc.c b/plat/hisilicon/hikey/hisi_sip_svc.c
new file mode 100644
index 0000000..3cd1bd0
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_sip_svc.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/pmf/pmf.h>
+#include <tools_share/uuid.h>
+
+#include <hisi_sip_svc.h>
+
+/* Hisi SiP Service UUID */
+DEFINE_SVC_UUID2(hisi_sip_svc_uid,
+	0x74df99e5, 0x8276, 0xaa40, 0x9f, 0xf8,
+	0xc0, 0x85, 0x52, 0xbc, 0x39, 0x3f);
+
+static int hisi_sip_setup(void)
+{
+	if (pmf_setup() != 0)
+		return 1;
+	return 0;
+}
+
+/*
+ * This function handles Hisi defined SiP Calls
+ */
+static uintptr_t hisi_sip_handler(unsigned int smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	int call_count = 0;
+
+	/*
+	 * Dispatch PMF calls to PMF SMC handler and return its return
+	 * value
+	 */
+	if (is_pmf_fid(smc_fid)) {
+		return pmf_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+				handle, flags);
+	}
+
+	switch (smc_fid) {
+	case HISI_SIP_SVC_CALL_COUNT:
+		/* PMF calls */
+		call_count += PMF_NUM_SMC_CALLS;
+
+		/* State switch call */
+		call_count += 1;
+
+		SMC_RET1(handle, call_count);
+
+	case HISI_SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, hisi_sip_svc_uid);
+
+	case HISI_SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, HISI_SIP_SVC_VERSION_MAJOR, HISI_SIP_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented HISI SiP Service Call: 0x%x \n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+}
+
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	hisi_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	hisi_sip_setup,
+	hisi_sip_handler
+);
diff --git a/plat/hisilicon/hikey/include/hi6220.h b/plat/hisilicon/hikey/include/hi6220.h
new file mode 100644
index 0000000..f67ee5c
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_H
+#define HI6220_H
+
+#include <hi6220_regs_acpu.h>
+#include <hi6220_regs_ao.h>
+#include <hi6220_regs_peri.h>
+#include <hi6220_regs_pin.h>
+#include <hi6220_regs_pmctrl.h>
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL2 bit definitions
+ ******************************************************************************/
+#define ACTLR_EL2_L2ACTLR_BIT		(1 << 6)
+#define ACTLR_EL2_L2ECTLR_BIT		(1 << 5)
+#define ACTLR_EL2_L2CTLR_BIT		(1 << 4)
+#define ACTLR_EL2_CPUECTLR_BIT		(1 << 1)
+#define ACTLR_EL2_CPUACTLR_BIT		(1 << 0)
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL3 bit definitions
+ ******************************************************************************/
+#define ACTLR_EL3_L2ACTLR_BIT		(1 << 6)
+#define ACTLR_EL3_L2ECTLR_BIT		(1 << 5)
+#define ACTLR_EL3_L2CTLR_BIT		(1 << 4)
+#define ACTLR_EL3_CPUECTLR_BIT		(1 << 1)
+#define ACTLR_EL3_CPUACTLR_BIT		(1 << 0)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define CCI400_BASE				0xF6E90000
+#define CCI400_SL_IFACE3_CLUSTER_IX		3
+#define CCI400_SL_IFACE4_CLUSTER_IX		4
+
+#define DWMMC0_BASE				0xF723D000
+
+#define DWUSB_BASE				0xF72C0000
+
+#define EDMAC_BASE				0xf7370000
+#define EDMAC_SEC_CTRL				(EDMAC_BASE + 0x694)
+#define EDMAC_AXI_CONF(x)			(EDMAC_BASE + 0x820 + (x << 6))
+#define EDMAC_SEC_CTRL_INTR_SEC			(1 << 1)
+#define EDMAC_SEC_CTRL_GLOBAL_SEC		(1 << 0)
+#define EDMAC_CHANNEL_NUMS			16
+
+#define PMUSSI_BASE				0xF8000000
+
+#define SP804_TIMER0_BASE			0xF8008000
+
+#define GPIO0_BASE				0xF8011000
+#define GPIO1_BASE				0xF8012000
+#define GPIO2_BASE				0xF8013000
+#define GPIO3_BASE				0xF8014000
+#define GPIO4_BASE				0xF7020000
+#define GPIO5_BASE				0xF7021000
+#define GPIO6_BASE				0xF7022000
+#define GPIO7_BASE				0xF7023000
+#define GPIO8_BASE				0xF7024000
+#define GPIO9_BASE				0xF7025000
+#define GPIO10_BASE				0xF7026000
+#define GPIO11_BASE				0xF7027000
+#define GPIO12_BASE				0xF7028000
+#define GPIO13_BASE				0xF7029000
+#define GPIO14_BASE				0xF702A000
+#define GPIO15_BASE				0xF702B000
+#define GPIO16_BASE				0xF702C000
+#define GPIO17_BASE				0xF702D000
+#define GPIO18_BASE				0xF702E000
+#define GPIO19_BASE				0xF702F000
+
+#endif /* HI6220_H */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_acpu.h b/plat/hisilicon/hikey/include/hi6220_regs_acpu.h
new file mode 100644
index 0000000..a43db68
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_acpu.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_REGS_ACPU_H
+#define HI6220_REGS_ACPU_H
+
+#define ACPU_CTRL_BASE				0xF6504000
+
+#define ACPU_SC_CPU_CTRL			(ACPU_CTRL_BASE + 0x000)
+#define ACPU_SC_CPU_STAT			(ACPU_CTRL_BASE + 0x008)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFIL2		(1 << 0)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFIL2_SHIFT		(0)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI0			(1 << 1)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI0_SHIFT		(1)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI1			(1 << 2)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI1_SHIFT		(2)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI2			(1 << 3)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI2_SHIFT		(3)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI3			(1 << 4)
+#define ACPU_SC_CPU_STAT_SC_STANDBYWFI3_SHIFT		(4)
+#define ACPU_SC_CPU_STAT_A53_1_STANDBYWFIL2		(1 << 8)
+#define ACPU_SC_CPU_STAT_A53_1_STANDBYWFIL2_SHIFT	(8)
+#define ACPU_SC_CPU_STAT_A53_1_STANDBYWFI		(1 << 9)
+#define ACPU_SC_CPU_STAT_A53_1_STANDBYWFI_SHIFT		(9)
+#define ACPU_SC_CPU_STAT_L2FLSHUDONE0			(1 << 16)
+#define ACPU_SC_CPU_STAT_L2FLSHUDONE0_SHIFT		(16)
+#define ACPU_SC_CPU_STAT_L2FLSHUDONE1			(1 << 17)
+#define ACPU_SC_CPU_STAT_L2FLSHUDONE1_SHIFT		(17)
+#define ACPU_SC_CPU_STAT_CCI400_ACTIVE			(1 << 18)
+#define ACPU_SC_CPU_STAT_CCI400_ACTIVE_SHIFT		(18)
+#define ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD		(1 << 20)
+#define ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT	(20)
+
+#define ACPU_SC_CLKEN				(ACPU_CTRL_BASE + 0x00c)
+#define HPM_L2_1_CLKEN				(1 << 9)
+#define G_CPU_1_CLKEN				(1 << 8)
+#define HPM_L2_CLKEN				(1 << 1)
+#define G_CPU_CLKEN				(1 << 0)
+
+#define ACPU_SC_CLKDIS				(ACPU_CTRL_BASE + 0x010)
+#define ACPU_SC_CLK_STAT			(ACPU_CTRL_BASE + 0x014)
+#define ACPU_SC_RSTEN				(ACPU_CTRL_BASE + 0x018)
+#define SRST_PRESET1_RSTEN			(1 << 11)
+#define SRST_PRESET0_RSTEN			(1 << 10)
+#define SRST_CLUSTER1_RSTEN			(1 << 9)
+#define SRST_CLUSTER0_RSTEN			(1 << 8)
+#define SRST_L2_HPM_1_RSTEN			(1 << 5)
+#define SRST_AARM_L2_1_RSTEN			(1 << 4)
+#define SRST_L2_HPM_0_RSTEN			(1 << 3)
+#define SRST_AARM_L2_0_RSTEN			(1 << 1)
+#define SRST_CLUSTER1				(SRST_PRESET1_RSTEN | \
+						 SRST_CLUSTER1_RSTEN | \
+						 SRST_L2_HPM_1_RSTEN | \
+						 SRST_AARM_L2_1_RSTEN)
+#define SRST_CLUSTER0				(SRST_PRESET0_RSTEN | \
+						 SRST_CLUSTER0_RSTEN | \
+						 SRST_L2_HPM_0_RSTEN | \
+						 SRST_AARM_L2_0_RSTEN)
+
+#define ACPU_SC_RSTDIS				(ACPU_CTRL_BASE + 0x01c)
+#define ACPU_SC_RST_STAT			(ACPU_CTRL_BASE + 0x020)
+#define ACPU_SC_PDBGUP_MBIST			(ACPU_CTRL_BASE + 0x02c)
+#define PDBGUP_CLUSTER1_SHIFT			8
+
+#define ACPU_SC_VD_CTRL				(ACPU_CTRL_BASE + 0x054)
+#define ACPU_SC_VD_MASK_PATTERN_CTRL		(ACPU_CTRL_BASE + 0x058)
+#define ACPU_SC_VD_MASK_PATTERN_VAL		(0xCCB << 12)
+#define ACPU_SC_VD_MASK_PATTERN_MASK		((0x1 << 13) - 1)
+
+#define ACPU_SC_VD_DLY_FIXED_CTRL		(ACPU_CTRL_BASE + 0x05c)
+#define ACPU_SC_VD_DLY_TABLE0_CTRL		(ACPU_CTRL_BASE + 0x060)
+#define ACPU_SC_VD_DLY_TABLE1_CTRL		(ACPU_CTRL_BASE + 0x064)
+#define ACPU_SC_VD_DLY_TABLE2_CTRL		(ACPU_CTRL_BASE + 0x068)
+#define ACPU_SC_VD_HPM_CTRL			(ACPU_CTRL_BASE + 0x06c)
+#define ACPU_SC_A53_CLUSTER_MTCMOS_EN		(ACPU_CTRL_BASE + 0x088)
+#define PW_MTCMOS_EN_A53_1_EN			(1 << 1)
+#define PW_MTCMOS_EN_A53_0_EN			(1 << 0)
+
+#define ACPU_SC_A53_CLUSTER_MTCMOS_STA		(ACPU_CTRL_BASE + 0x090)
+#define ACPU_SC_A53_CLUSTER_ISO_EN		(ACPU_CTRL_BASE + 0x098)
+#define PW_ISO_A53_1_EN				(1 << 1)
+#define PW_ISO_A53_0_EN				(1 << 0)
+
+#define ACPU_SC_A53_CLUSTER_ISO_DIS		(ACPU_CTRL_BASE + 0x09c)
+#define ACPU_SC_A53_CLUSTER_ISO_STA		(ACPU_CTRL_BASE + 0x0a0)
+#define ACPU_SC_A53_1_MTCMOS_TIMER		(ACPU_CTRL_BASE + 0x0b4)
+#define ACPU_SC_A53_0_MTCMOS_TIMER		(ACPU_CTRL_BASE + 0x0bc)
+#define ACPU_SC_A53_x_MTCMOS_TIMER(x)		((x) ? ACPU_SC_A53_1_MTCMOS_TIMER : ACPU_SC_A53_0_MTCMOS_TIMER)
+
+#define ACPU_SC_SNOOP_PWD			(ACPU_CTRL_BASE + 0xe4)
+#define PD_DETECT_START1			(1 << 16)
+#define PD_DETECT_START0			(1 << 0)
+
+#define ACPU_SC_CPU0_CTRL			(ACPU_CTRL_BASE + 0x100)
+#define CPU_CTRL_AARCH64_MODE			(1 << 7)
+
+#define ACPU_SC_CPU0_STAT			(ACPU_CTRL_BASE + 0x104)
+#define ACPU_SC_CPU0_CLKEN			(ACPU_CTRL_BASE + 0x108)
+#define CPU_CLKEN_HPM				(1 << 1)
+
+#define ACPU_SC_CPU0_CLK_STAT			(ACPU_CTRL_BASE + 0x110)
+
+#define ACPU_SC_CPU0_RSTEN			(ACPU_CTRL_BASE + 0x114)
+#define ACPU_SC_CPU0_RSTDIS			(ACPU_CTRL_BASE + 0x118)
+#define ACPU_SC_CPU0_MTCMOS_EN			(ACPU_CTRL_BASE + 0x120)
+#define CPU_MTCMOS_PW				(1 << 0)
+
+#define ACPU_SC_CPU0_PW_ISOEN			(ACPU_CTRL_BASE + 0x130)
+#define CPU_PW_ISO				(1 << 0)
+
+#define ACPU_SC_CPU0_PW_ISODIS			(ACPU_CTRL_BASE + 0x134)
+#define ACPU_SC_CPU0_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x138)
+#define ACPU_SC_CPU0_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x154)
+#define CPU_MTCMOS_TIMER_STA			(1 << 0)
+
+#define ACPU_SC_CPU0_RVBARADDR			(ACPU_CTRL_BASE + 0x158)
+#define ACPU_SC_CPU1_CTRL			(ACPU_CTRL_BASE + 0x200)
+#define ACPU_SC_CPU1_STAT			(ACPU_CTRL_BASE + 0x204)
+#define ACPU_SC_CPU1_CLKEN			(ACPU_CTRL_BASE + 0x208)
+#define ACPU_SC_CPU1_CLK_STAT			(ACPU_CTRL_BASE + 0x210)
+#define ACPU_SC_CPU1_RSTEN			(ACPU_CTRL_BASE + 0x214)
+#define ACPU_SC_CPU1_RSTDIS			(ACPU_CTRL_BASE + 0x218)
+#define ACPU_SC_CPU1_MTCMOS_EN			(ACPU_CTRL_BASE + 0x220)
+#define ACPU_SC_CPU1_PW_ISODIS			(ACPU_CTRL_BASE + 0x234)
+#define ACPU_SC_CPU1_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x238)
+#define ACPU_SC_CPU1_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x254)
+#define ACPU_SC_CPU1_RVBARADDR			(ACPU_CTRL_BASE + 0x258)
+#define ACPU_SC_CPU2_CTRL			(ACPU_CTRL_BASE + 0x300)
+#define ACPU_SC_CPU2_STAT			(ACPU_CTRL_BASE + 0x304)
+#define ACPU_SC_CPU2_CLKEN			(ACPU_CTRL_BASE + 0x308)
+#define ACPU_SC_CPU2_CLK_STAT			(ACPU_CTRL_BASE + 0x310)
+#define ACPU_SC_CPU2_RSTEN			(ACPU_CTRL_BASE + 0x314)
+#define ACPU_SC_CPU2_RSTDIS			(ACPU_CTRL_BASE + 0x318)
+#define ACPU_SC_CPU2_MTCMOS_EN			(ACPU_CTRL_BASE + 0x320)
+#define ACPU_SC_CPU2_PW_ISODIS			(ACPU_CTRL_BASE + 0x334)
+#define ACPU_SC_CPU2_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x338)
+#define ACPU_SC_CPU2_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x354)
+#define ACPU_SC_CPU2_RVBARADDR			(ACPU_CTRL_BASE + 0x358)
+#define ACPU_SC_CPU3_CTRL			(ACPU_CTRL_BASE + 0x400)
+#define ACPU_SC_CPU3_STAT			(ACPU_CTRL_BASE + 0x404)
+#define ACPU_SC_CPU3_CLKEN			(ACPU_CTRL_BASE + 0x408)
+#define ACPU_SC_CPU3_CLK_STAT			(ACPU_CTRL_BASE + 0x410)
+#define ACPU_SC_CPU3_RSTEN			(ACPU_CTRL_BASE + 0x414)
+#define ACPU_SC_CPU3_RSTDIS			(ACPU_CTRL_BASE + 0x418)
+#define ACPU_SC_CPU3_MTCMOS_EN			(ACPU_CTRL_BASE + 0x420)
+#define ACPU_SC_CPU3_PW_ISODIS			(ACPU_CTRL_BASE + 0x434)
+#define ACPU_SC_CPU3_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x438)
+#define ACPU_SC_CPU3_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x454)
+#define ACPU_SC_CPU3_RVBARADDR			(ACPU_CTRL_BASE + 0x458)
+#define ACPU_SC_CPU4_CTRL			(ACPU_CTRL_BASE + 0x500)
+#define ACPU_SC_CPU4_STAT			(ACPU_CTRL_BASE + 0x504)
+#define ACPU_SC_CPU4_CLKEN			(ACPU_CTRL_BASE + 0x508)
+#define ACPU_SC_CPU4_CLK_STAT			(ACPU_CTRL_BASE + 0x510)
+#define ACPU_SC_CPU4_RSTEN			(ACPU_CTRL_BASE + 0x514)
+#define ACPU_SC_CPU4_RSTDIS			(ACPU_CTRL_BASE + 0x518)
+#define ACPU_SC_CPU4_MTCMOS_EN			(ACPU_CTRL_BASE + 0x520)
+#define ACPU_SC_CPU4_PW_ISODIS			(ACPU_CTRL_BASE + 0x534)
+#define ACPU_SC_CPU4_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x538)
+#define ACPU_SC_CPU4_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x554)
+#define ACPU_SC_CPU4_RVBARADDR			(ACPU_CTRL_BASE + 0x558)
+#define ACPU_SC_CPU5_CTRL			(ACPU_CTRL_BASE + 0x600)
+#define ACPU_SC_CPU5_STAT			(ACPU_CTRL_BASE + 0x604)
+#define ACPU_SC_CPU5_CLKEN			(ACPU_CTRL_BASE + 0x608)
+#define ACPU_SC_CPU5_CLK_STAT			(ACPU_CTRL_BASE + 0x610)
+#define ACPU_SC_CPU5_RSTEN			(ACPU_CTRL_BASE + 0x614)
+#define ACPU_SC_CPU5_RSTDIS			(ACPU_CTRL_BASE + 0x618)
+#define ACPU_SC_CPU5_MTCMOS_EN			(ACPU_CTRL_BASE + 0x620)
+#define ACPU_SC_CPU5_PW_ISODIS			(ACPU_CTRL_BASE + 0x634)
+#define ACPU_SC_CPU5_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x638)
+#define ACPU_SC_CPU5_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x654)
+#define ACPU_SC_CPU5_RVBARADDR			(ACPU_CTRL_BASE + 0x658)
+#define ACPU_SC_CPU6_CTRL			(ACPU_CTRL_BASE + 0x700)
+#define ACPU_SC_CPU6_STAT			(ACPU_CTRL_BASE + 0x704)
+#define ACPU_SC_CPU6_CLKEN			(ACPU_CTRL_BASE + 0x708)
+#define ACPU_SC_CPU6_CLK_STAT			(ACPU_CTRL_BASE + 0x710)
+#define ACPU_SC_CPU6_RSTEN			(ACPU_CTRL_BASE + 0x714)
+#define ACPU_SC_CPU6_RSTDIS			(ACPU_CTRL_BASE + 0x718)
+#define ACPU_SC_CPU6_MTCMOS_EN			(ACPU_CTRL_BASE + 0x720)
+#define ACPU_SC_CPU6_PW_ISODIS			(ACPU_CTRL_BASE + 0x734)
+#define ACPU_SC_CPU6_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x738)
+#define ACPU_SC_CPU6_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x754)
+#define ACPU_SC_CPU6_RVBARADDR			(ACPU_CTRL_BASE + 0x758)
+#define ACPU_SC_CPU7_CTRL			(ACPU_CTRL_BASE + 0x800)
+#define ACPU_SC_CPU7_STAT			(ACPU_CTRL_BASE + 0x804)
+#define ACPU_SC_CPU7_CLKEN			(ACPU_CTRL_BASE + 0x808)
+#define ACPU_SC_CPU7_CLK_STAT			(ACPU_CTRL_BASE + 0x810)
+#define ACPU_SC_CPU7_RSTEN			(ACPU_CTRL_BASE + 0x814)
+#define ACPU_SC_CPU7_RSTDIS			(ACPU_CTRL_BASE + 0x818)
+#define ACPU_SC_CPU7_MTCMOS_EN			(ACPU_CTRL_BASE + 0x820)
+#define ACPU_SC_CPU7_PW_ISODIS			(ACPU_CTRL_BASE + 0x834)
+#define ACPU_SC_CPU7_PW_ISO_STAT		(ACPU_CTRL_BASE + 0x838)
+#define ACPU_SC_CPU7_MTCMOS_TIMER_STAT		(ACPU_CTRL_BASE + 0x854)
+#define ACPU_SC_CPU7_RVBARADDR			(ACPU_CTRL_BASE + 0x858)
+#define ACPU_SC_CPUx_CTRL(x)			((x < 8) ? (ACPU_SC_CPU0_CTRL + 0x100 * x) : ACPU_SC_CPU0_CTRL)
+#define ACPU_SC_CPUx_STAT(x)			((x < 8) ? (ACPU_SC_CPU0_STAT + 0x100 * x) : ACPU_SC_CPU0_STAT)
+#define ACPU_SC_CPUx_CLKEN(x)			((x < 8) ? (ACPU_SC_CPU0_CLKEN + 0x100 * x) : ACPU_SC_CPU0_CLKEN)
+#define ACPU_SC_CPUx_CLK_STAT(x)		((x < 8) ? (ACPU_SC_CPU0_CLK_STAT + 0x100 * x) : ACPU_SC_CPU0_CLK_STAT)
+#define ACPU_SC_CPUx_RSTEN(x)			((x < 8) ? (ACPU_SC_CPU0_RSTEN + 0x100 * x) : ACPU_SC_CPU0_RSTEN)
+#define ACPU_SC_CPUx_RSTDIS(x)			((x < 8) ? (ACPU_SC_CPU0_RSTDIS + 0x100 * x) : ACPU_SC_CPU0_RSTDIS)
+#define ACPU_SC_CPUx_MTCMOS_EN(x)		((x < 8) ? (ACPU_SC_CPU0_MTCMOS_EN + 0x100 * x) : ACPU_SC_CPU0_MTCMOS_EN)
+#define ACPU_SC_CPUx_PW_ISODIS(x)		((x < 8) ? (ACPU_SC_CPU0_PW_ISODIS + 0x100 * x) : ACPU_SC_CPU0_PW_ISODIS)
+#define ACPU_SC_CPUx_PW_ISO_STAT(x)		((x < 8) ? (ACPU_SC_CPU0_PW_ISO_STAT + 0x100 * x) : ACPU_SC_CPU0_PW_ISO_STAT)
+#define ACPU_SC_CPUx_MTCMOS_TIMER_STAT(x)	((x < 8) ? (ACPU_SC_CPU0_MTCMOS_TIMER_STAT + 0x100 * x) : ACPU_SC_CPU0_MTCMOS_TIMER_STAT)
+#define ACPU_SC_CPUx_RVBARADDR(x)		((x < 8) ? (ACPU_SC_CPU0_RVBARADDR + 0x100 * x) : ACPU_SC_CPU0_RVBARADDR)
+
+#define ACPU_SC_CPU_STAT_CLKDIV_VD_MASK		(3 << 20)
+
+#define ACPU_SC_VD_CTRL_TUNE_EN_DIF		(1 << 0)
+#define ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT	(0)
+#define ACPU_SC_VD_CTRL_TUNE			(1 << 1)
+#define ACPU_SC_VD_CTRL_TUNE_SHIFT		(1)
+#define ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF	(1 << 7)
+#define ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT	(7)
+#define ACPU_SC_VD_CTRL_CALIBRATE_EN_INI	(1 << 8)
+#define ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT	(8)
+#define ACPU_SC_VD_CTRL_CLK_DIS_CNT_CLR		(1 << 9)
+#define ACPU_SC_VD_CTRL_CLK_DIS_CNT_CLR_SHIFT	(9)
+#define ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN		(1 << 10)
+#define ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT	(10)
+#define ACPU_SC_VD_CTRL_TUNE_EN_INT		(1 << 11)
+#define ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT	(11)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE0		(1 << 12)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE0_MASK	(0xf << 12)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE0_SHIFT	(12)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE1		(1 << 16)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE1_MASK	(0xf << 16)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE1_SHIFT	(16)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE2		(1 << 20)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE2_MASK	(0xf << 20)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE2_SHIFT	(20)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE3		(1 << 24)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE3_MASK	(0xf << 24)
+#define ACPU_SC_VD_CTRL_SHIFT_TABLE3_SHIFT	(24)
+#define ACPU_SC_VD_CTRL_FORCE_CLK_EN		(1 << 28)
+#define ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT	(28)
+#define ACPU_SC_VD_CTRL_DIV_EN_DIF		(1 << 29)
+#define ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT	(29)
+
+#define ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL			\
+	((0x1 << ACPU_SC_VD_CTRL_SHIFT_TABLE0_SHIFT) |	\
+	 (0x3 << ACPU_SC_VD_CTRL_SHIFT_TABLE1_SHIFT) |	\
+	 (0x5 << ACPU_SC_VD_CTRL_SHIFT_TABLE2_SHIFT) |	\
+	 (0x6 << ACPU_SC_VD_CTRL_SHIFT_TABLE3_SHIFT) |	\
+	 (0x7 << ACPU_SC_VD_CTRL_TUNE_SHIFT))
+
+#define ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK		\
+	((0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE0_SHIFT) |	\
+	 (0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE1_SHIFT) |	\
+	 (0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE2_SHIFT) |	\
+	 (0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE3_SHIFT) |	\
+	 (0x3F << ACPU_SC_VD_CTRL_TUNE_SHIFT))
+
+#define ACPU_SC_VD_HPM_CTRL_OSC_DIV		(1 << 0)
+#define ACPU_SC_VD_HPM_CTRL_OSC_DIV_SHIFT	(0)
+#define ACPU_SC_VD_HPM_CTRL_OSC_DIV_MASK	(0x000000FF)
+#define ACPU_SC_VD_HPM_CTRL_DLY_EXP		(1 << 8)
+#define ACPU_SC_VD_HPM_CTRL_DLY_EXP_SHIFT	(8)
+#define ACPU_SC_VD_HPM_CTRL_DLY_EXP_MASK	(0x001FFF00)
+
+#define HPM_OSC_DIV_VAL \
+	(0x56 << ACPU_SC_VD_HPM_CTRL_OSC_DIV_SHIFT)
+#define HPM_OSC_DIV_MASK \
+	(ACPU_SC_VD_HPM_CTRL_OSC_DIV_MASK)
+
+#define HPM_DLY_EXP_VAL \
+	(0xC7A << ACPU_SC_VD_HPM_CTRL_DLY_EXP_SHIFT)
+#define HPM_DLY_EXP_MASK \
+	(ACPU_SC_VD_HPM_CTRL_DLY_EXP_MASK)
+
+#define ACPU_SC_VD_EN_ASIC_VAL					\
+	((0x0 << ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT) |		\
+	 (0x0 << ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT) |	\
+	 (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT) |	\
+	 (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT) |	\
+	 (0X0 << ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT) |		\
+	 (0X0 << ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT) |		\
+	 (0x0 << ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT))
+
+#define ACPU_SC_VD_EN_SFT_VAL					\
+	((0x0 << ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT) |		\
+	 (0x0 << ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT) |	\
+	 (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT) |	\
+	 (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT) |	\
+	 (0x0 << ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT) |		\
+	 (0x0 << ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT) |		\
+	 (0x0 << ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT))
+
+#define ACPU_SC_VD_EN_MASK					\
+	((0x1 << ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT) |		\
+	 (0x1 << ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT) |	\
+	 (0x1 << ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT) |	\
+	 (0x1 << ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT) |	\
+	 (0x1 << ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT) |		\
+	 (0x1 << ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT) |		\
+	 (0x1 << ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT))
+
+#endif /* HI6220_REGS_ACPU_H */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_ao.h b/plat/hisilicon/hikey/include/hi6220_regs_ao.h
new file mode 100644
index 0000000..614eba2
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_ao.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_REGS_AO_H
+#define HI6220_REGS_AO_H
+
+#define AO_CTRL_BASE				0xF7800000
+
+#define AO_SC_SYS_CTRL0				(AO_CTRL_BASE + 0x000)
+#define AO_SC_SYS_CTRL1				(AO_CTRL_BASE + 0x004)
+#define AO_SC_SYS_CTRL2				(AO_CTRL_BASE + 0x008)
+#define AO_SC_SYS_STAT0				(AO_CTRL_BASE + 0x010)
+#define AO_SC_SYS_STAT1				(AO_CTRL_BASE + 0x014)
+#define AO_SC_MCU_IMCTRL			(AO_CTRL_BASE + 0x018)
+#define AO_SC_MCU_IMSTAT			(AO_CTRL_BASE + 0x01C)
+#define AO_SC_SECONDRY_INT_EN0			(AO_CTRL_BASE + 0x044)
+#define AO_SC_SECONDRY_INT_STATR0		(AO_CTRL_BASE + 0x048)
+#define AO_SC_SECONDRY_INT_STATM0		(AO_CTRL_BASE + 0x04C)
+#define AO_SC_MCU_WKUP_INT_EN6			(AO_CTRL_BASE + 0x054)
+#define AO_SC_MCU_WKUP_INT_STATR6		(AO_CTRL_BASE + 0x058)
+#define AO_SC_MCU_WKUP_INT_STATM6		(AO_CTRL_BASE + 0x05C)
+#define AO_SC_MCU_WKUP_INT_EN5			(AO_CTRL_BASE + 0x064)
+#define AO_SC_MCU_WKUP_INT_STATR5		(AO_CTRL_BASE + 0x068)
+#define AO_SC_MCU_WKUP_INT_STATM5		(AO_CTRL_BASE + 0x06C)
+#define AO_SC_MCU_WKUP_INT_EN4			(AO_CTRL_BASE + 0x094)
+#define AO_SC_MCU_WKUP_INT_STATR4		(AO_CTRL_BASE + 0x098)
+#define AO_SC_MCU_WKUP_INT_STATM4		(AO_CTRL_BASE + 0x09C)
+#define AO_SC_MCU_WKUP_INT_EN0			(AO_CTRL_BASE + 0x0A8)
+#define AO_SC_MCU_WKUP_INT_STATR0		(AO_CTRL_BASE + 0x0AC)
+#define AO_SC_MCU_WKUP_INT_STATM0		(AO_CTRL_BASE + 0x0B0)
+#define AO_SC_MCU_WKUP_INT_EN1			(AO_CTRL_BASE + 0x0B4)
+#define AO_SC_MCU_WKUP_INT_STATR1		(AO_CTRL_BASE + 0x0B8)
+#define AO_SC_MCU_WKUP_INT_STATM1		(AO_CTRL_BASE + 0x0BC)
+#define AO_SC_INT_STATR				(AO_CTRL_BASE + 0x0C4)
+#define AO_SC_INT_STATM				(AO_CTRL_BASE + 0x0C8)
+#define AO_SC_INT_CLEAR				(AO_CTRL_BASE + 0x0CC)
+#define AO_SC_INT_EN_SET			(AO_CTRL_BASE + 0x0D0)
+#define AO_SC_INT_EN_DIS			(AO_CTRL_BASE + 0x0D4)
+#define AO_SC_INT_EN_STAT			(AO_CTRL_BASE + 0x0D8)
+#define AO_SC_INT_STATR1			(AO_CTRL_BASE + 0x0E4)
+#define AO_SC_INT_STATM1			(AO_CTRL_BASE + 0x0E8)
+#define AO_SC_INT_CLEAR1			(AO_CTRL_BASE + 0x0EC)
+#define AO_SC_INT_EN_SET1			(AO_CTRL_BASE + 0x0F0)
+#define AO_SC_INT_EN_DIS1			(AO_CTRL_BASE + 0x0F4)
+#define AO_SC_INT_EN_STAT1			(AO_CTRL_BASE + 0x0F8)
+#define AO_SC_TIMER_EN0				(AO_CTRL_BASE + 0x1D0)
+#define AO_SC_TIMER_EN1				(AO_CTRL_BASE + 0x1D4)
+#define AO_SC_TIMER_EN4				(AO_CTRL_BASE + 0x1F0)
+#define AO_SC_TIMER_EN5				(AO_CTRL_BASE + 0x1F4)
+#define AO_SC_MCU_SUBSYS_CTRL0			(AO_CTRL_BASE + 0x400)
+#define AO_SC_MCU_SUBSYS_CTRL1			(AO_CTRL_BASE + 0x404)
+#define AO_SC_MCU_SUBSYS_CTRL2			(AO_CTRL_BASE + 0x408)
+#define AO_SC_MCU_SUBSYS_CTRL3			(AO_CTRL_BASE + 0x40C)
+#define AO_SC_MCU_SUBSYS_CTRL4			(AO_CTRL_BASE + 0x410)
+#define AO_SC_MCU_SUBSYS_CTRL5			(AO_CTRL_BASE + 0x414)
+#define AO_SC_MCU_SUBSYS_CTRL6			(AO_CTRL_BASE + 0x418)
+#define AO_SC_MCU_SUBSYS_CTRL7			(AO_CTRL_BASE + 0x41C)
+#define AO_SC_MCU_SUBSYS_STAT0			(AO_CTRL_BASE + 0x440)
+#define AO_SC_MCU_SUBSYS_STAT1			(AO_CTRL_BASE + 0x444)
+#define AO_SC_MCU_SUBSYS_STAT2			(AO_CTRL_BASE + 0x448)
+#define AO_SC_MCU_SUBSYS_STAT3			(AO_CTRL_BASE + 0x44C)
+#define AO_SC_MCU_SUBSYS_STAT4			(AO_CTRL_BASE + 0x450)
+#define AO_SC_MCU_SUBSYS_STAT5			(AO_CTRL_BASE + 0x454)
+#define AO_SC_MCU_SUBSYS_STAT6			(AO_CTRL_BASE + 0x458)
+#define AO_SC_MCU_SUBSYS_STAT7			(AO_CTRL_BASE + 0x45C)
+#define AO_SC_PERIPH_CLKEN4			(AO_CTRL_BASE + 0x630)
+#define AO_SC_PERIPH_CLKDIS4			(AO_CTRL_BASE + 0x634)
+#define AO_SC_PERIPH_CLKSTAT4			(AO_CTRL_BASE + 0x638)
+#define AO_SC_PERIPH_CLKEN5			(AO_CTRL_BASE + 0x63C)
+#define AO_SC_PERIPH_CLKDIS5			(AO_CTRL_BASE + 0x640)
+#define AO_SC_PERIPH_CLKSTAT5			(AO_CTRL_BASE + 0x644)
+#define AO_SC_PERIPH_RSTEN4			(AO_CTRL_BASE + 0x6F0)
+#define AO_SC_PERIPH_RSTDIS4			(AO_CTRL_BASE + 0x6F4)
+#define AO_SC_PERIPH_RSTSTAT4			(AO_CTRL_BASE + 0x6F8)
+#define AO_SC_PERIPH_RSTEN5			(AO_CTRL_BASE + 0x6FC)
+#define AO_SC_PERIPH_RSTDIS5			(AO_CTRL_BASE + 0x700)
+#define AO_SC_PERIPH_RSTSTAT5			(AO_CTRL_BASE + 0x704)
+#define AO_SC_PW_CLKEN0				(AO_CTRL_BASE + 0x800)
+#define AO_SC_PW_CLKDIS0			(AO_CTRL_BASE + 0x804)
+#define AO_SC_PW_CLK_STAT0			(AO_CTRL_BASE + 0x808)
+#define AO_SC_PW_RSTEN0				(AO_CTRL_BASE + 0x810)
+#define AO_SC_PW_RSTDIS0			(AO_CTRL_BASE + 0x814)
+#define AO_SC_PW_RST_STAT0			(AO_CTRL_BASE + 0x818)
+#define AO_SC_PW_ISOEN0				(AO_CTRL_BASE + 0x820)
+#define AO_SC_PW_ISODIS0			(AO_CTRL_BASE + 0x824)
+#define AO_SC_PW_ISO_STAT0			(AO_CTRL_BASE + 0x828)
+#define AO_SC_PW_MTCMOS_EN0			(AO_CTRL_BASE + 0x830)
+#define AO_SC_PW_MTCMOS_DIS0			(AO_CTRL_BASE + 0x834)
+#define AO_SC_PW_MTCMOS_STAT0			(AO_CTRL_BASE + 0x838)
+#define AO_SC_PW_MTCMOS_ACK_STAT0		(AO_CTRL_BASE + 0x83C)
+#define AO_SC_PW_MTCMOS_TIMEOUT_STAT0		(AO_CTRL_BASE + 0x840)
+#define AO_SC_PW_STAT0				(AO_CTRL_BASE + 0x850)
+#define AO_SC_PW_STAT1				(AO_CTRL_BASE + 0x854)
+#define AO_SC_SYSTEST_STAT			(AO_CTRL_BASE + 0x880)
+#define AO_SC_SYSTEST_SLICER_CNT0		(AO_CTRL_BASE + 0x890)
+#define AO_SC_SYSTEST_SLICER_CNT1		(AO_CTRL_BASE + 0x894)
+#define AO_SC_PW_CTRL1				(AO_CTRL_BASE + 0x8C8)
+#define AO_SC_PW_CTRL				(AO_CTRL_BASE + 0x8CC)
+#define AO_SC_MCPU_VOTEEN			(AO_CTRL_BASE + 0x8D0)
+#define AO_SC_MCPU_VOTEDIS			(AO_CTRL_BASE + 0x8D4)
+#define AO_SC_MCPU_VOTESTAT			(AO_CTRL_BASE + 0x8D8)
+#define AO_SC_MCPU_VOTE_MSK0			(AO_CTRL_BASE + 0x8E0)
+#define AO_SC_MCPU_VOTE_MSK1			(AO_CTRL_BASE + 0x8E4)
+#define AO_SC_MCPU_VOTESTAT0_MSK		(AO_CTRL_BASE + 0x8E8)
+#define AO_SC_MCPU_VOTESTAT1_MSK		(AO_CTRL_BASE + 0x8EC)
+#define AO_SC_PERI_VOTEEN			(AO_CTRL_BASE + 0x8F0)
+#define AO_SC_PERI_VOTEDIS			(AO_CTRL_BASE + 0x8F4)
+#define AO_SC_PERI_VOTESTAT			(AO_CTRL_BASE + 0x8F8)
+#define AO_SC_PERI_VOTE_MSK0			(AO_CTRL_BASE + 0x900)
+#define AO_SC_PERI_VOTE_MSK1			(AO_CTRL_BASE + 0x904)
+#define AO_SC_PERI_VOTESTAT0_MSK		(AO_CTRL_BASE + 0x908)
+#define AO_SC_PERI_VOTESTAT1_MSK		(AO_CTRL_BASE + 0x90C)
+#define AO_SC_ACPU_VOTEEN			(AO_CTRL_BASE + 0x910)
+#define AO_SC_ACPU_VOTEDIS			(AO_CTRL_BASE + 0x914)
+#define AO_SC_ACPU_VOTESTAT			(AO_CTRL_BASE + 0x918)
+#define AO_SC_ACPU_VOTE_MSK0			(AO_CTRL_BASE + 0x920)
+#define AO_SC_ACPU_VOTE_MSK1			(AO_CTRL_BASE + 0x924)
+#define AO_SC_ACPU_VOTESTAT0_MSK		(AO_CTRL_BASE + 0x928)
+#define AO_SC_ACPU_VOTESTAT1_MSK		(AO_CTRL_BASE + 0x92C)
+#define AO_SC_MCU_VOTEEN			(AO_CTRL_BASE + 0x930)
+#define AO_SC_MCU_VOTEDIS			(AO_CTRL_BASE + 0x934)
+#define AO_SC_MCU_VOTESTAT			(AO_CTRL_BASE + 0x938)
+#define AO_SC_MCU_VOTE_MSK0			(AO_CTRL_BASE + 0x940)
+#define AO_SC_MCU_VOTE_MSK1			(AO_CTRL_BASE + 0x944)
+#define AO_SC_MCU_VOTESTAT0_MSK			(AO_CTRL_BASE + 0x948)
+#define AO_SC_MCU_VOTESTAT1_MSK			(AO_CTRL_BASE + 0x94C)
+#define AO_SC_MCU_VOTE1EN			(AO_CTRL_BASE + 0x960)
+#define AO_SC_MCU_VOTE1DIS			(AO_CTRL_BASE + 0x964)
+#define AO_SC_MCU_VOTE1STAT			(AO_CTRL_BASE + 0x968)
+#define AO_SC_MCU_VOTE1_MSK0			(AO_CTRL_BASE + 0x970)
+#define AO_SC_MCU_VOTE1_MSK1			(AO_CTRL_BASE + 0x974)
+#define AO_SC_MCU_VOTE1STAT0_MSK		(AO_CTRL_BASE + 0x978)
+#define AO_SC_MCU_VOTE1STAT1_MSK		(AO_CTRL_BASE + 0x97C)
+#define AO_SC_MCU_VOTE2EN			(AO_CTRL_BASE + 0x980)
+#define AO_SC_MCU_VOTE2DIS			(AO_CTRL_BASE + 0x984)
+#define AO_SC_MCU_VOTE2STAT			(AO_CTRL_BASE + 0x988)
+#define AO_SC_MCU_VOTE2_MSK0			(AO_CTRL_BASE + 0x990)
+#define AO_SC_MCU_VOTE2_MSK1			(AO_CTRL_BASE + 0x994)
+#define AO_SC_MCU_VOTE2STAT0_MSK		(AO_CTRL_BASE + 0x998)
+#define AO_SC_MCU_VOTE2STAT1_MSK		(AO_CTRL_BASE + 0x99C)
+#define AO_SC_VOTE_CTRL				(AO_CTRL_BASE + 0x9A0)
+#define AO_SC_VOTE_STAT				(AO_CTRL_BASE + 0x9A4)
+#define AO_SC_ECONUM				(AO_CTRL_BASE + 0xF00)
+#define AO_SCCHIPID				(AO_CTRL_BASE + 0xF10)
+#define AO_SCSOCID				(AO_CTRL_BASE + 0xF1C)
+#define AO_SC_SOC_FPGA_RTL_DEF			(AO_CTRL_BASE + 0xFE0)
+#define AO_SC_SOC_FPGA_PR_DEF			(AO_CTRL_BASE + 0xFE4)
+#define AO_SC_SOC_FPGA_RES_DEF0			(AO_CTRL_BASE + 0xFE8)
+#define AO_SC_SOC_FPGA_RES_DEF1			(AO_CTRL_BASE + 0xFEC)
+#define AO_SC_XTAL_CTRL0			(AO_CTRL_BASE + 0x102)
+#define AO_SC_XTAL_CTRL1			(AO_CTRL_BASE + 0x102)
+#define AO_SC_XTAL_CTRL3			(AO_CTRL_BASE + 0x103)
+#define AO_SC_XTAL_CTRL5			(AO_CTRL_BASE + 0x103)
+#define AO_SC_XTAL_STAT0			(AO_CTRL_BASE + 0x106)
+#define AO_SC_XTAL_STAT1			(AO_CTRL_BASE + 0x107)
+#define AO_SC_EFUSE_CHIPID0			(AO_CTRL_BASE + 0x108)
+#define AO_SC_EFUSE_CHIPID1			(AO_CTRL_BASE + 0x108)
+#define AO_SC_EFUSE_SYS_CTRL			(AO_CTRL_BASE + 0x108)
+#define AO_SC_DEBUG_CTRL1			(AO_CTRL_BASE + 0x128)
+#define AO_SC_DBG_STAT				(AO_CTRL_BASE + 0x12B)
+#define AO_SC_ARM_DBG_KEY0			(AO_CTRL_BASE + 0x12B)
+#define AO_SC_RESERVED31			(AO_CTRL_BASE + 0x13A)
+#define AO_SC_RESERVED32			(AO_CTRL_BASE + 0x13A)
+#define AO_SC_RESERVED33			(AO_CTRL_BASE + 0x13A)
+#define AO_SC_RESERVED34			(AO_CTRL_BASE + 0x13A)
+#define AO_SC_RESERVED35			(AO_CTRL_BASE + 0x13B)
+#define AO_SC_RESERVED36			(AO_CTRL_BASE + 0x13B)
+#define AO_SC_RESERVED37			(AO_CTRL_BASE + 0x13B)
+#define AO_SC_RESERVED38			(AO_CTRL_BASE + 0x13B)
+#define AO_SC_ALWAYSON_SYS_CTRL0		(AO_CTRL_BASE + 0x148)
+#define AO_SC_ALWAYSON_SYS_CTRL1		(AO_CTRL_BASE + 0x148)
+#define AO_SC_ALWAYSON_SYS_CTRL2		(AO_CTRL_BASE + 0x148)
+#define AO_SC_ALWAYSON_SYS_CTRL3		(AO_CTRL_BASE + 0x148)
+#define AO_SC_ALWAYSON_SYS_CTRL10		(AO_CTRL_BASE + 0x14A)
+#define AO_SC_ALWAYSON_SYS_CTRL11		(AO_CTRL_BASE + 0x14A)
+#define AO_SC_ALWAYSON_SYS_STAT0		(AO_CTRL_BASE + 0x14C)
+#define AO_SC_ALWAYSON_SYS_STAT1		(AO_CTRL_BASE + 0x14C)
+#define AO_SC_ALWAYSON_SYS_STAT2		(AO_CTRL_BASE + 0x14C)
+#define AO_SC_ALWAYSON_SYS_STAT3		(AO_CTRL_BASE + 0x14C)
+#define AO_SC_PWUP_TIME0			(AO_CTRL_BASE + 0x188)
+#define AO_SC_PWUP_TIME1			(AO_CTRL_BASE + 0x188)
+#define AO_SC_PWUP_TIME2			(AO_CTRL_BASE + 0x188)
+#define AO_SC_PWUP_TIME3			(AO_CTRL_BASE + 0x188)
+#define AO_SC_PWUP_TIME4			(AO_CTRL_BASE + 0x189)
+#define AO_SC_PWUP_TIME5			(AO_CTRL_BASE + 0x189)
+#define AO_SC_PWUP_TIME6			(AO_CTRL_BASE + 0x189)
+#define AO_SC_PWUP_TIME7			(AO_CTRL_BASE + 0x189)
+#define AO_SC_SECURITY_CTRL1			(AO_CTRL_BASE + 0x1C0)
+#define AO_SC_SYSTEST_SLICER_CNT0		(AO_CTRL_BASE + 0x890)
+#define AO_SC_SYSTEST_SLICER_CNT1		(AO_CTRL_BASE + 0x894)
+
+#define AO_SC_SYS_CTRL0_MODE_NORMAL				0x004
+#define AO_SC_SYS_CTRL0_MODE_MASK				0x007
+
+#define AO_SC_SYS_CTRL1_AARM_WD_RST_CFG				(1 << 0)
+#define AO_SC_SYS_CTRL1_REMAP_SRAM_AARM				(1 << 1)
+#define AO_SC_SYS_CTRL1_EFUSEC_REMAP				(1 << 2)
+#define AO_SC_SYS_CTRL1_EXT_PLL_SEL				(1 << 3)
+#define AO_SC_SYS_CTRL1_MCU_WDG0_RSTMCU_CFG			(1 << 4)
+#define AO_SC_SYS_CTRL1_USIM0_HPD_DE_BOUNCE_CFG			(1 << 6)
+#define AO_SC_SYS_CTRL1_USIM0_HPD_OE_CFG			(1 << 7)
+#define AO_SC_SYS_CTRL1_USIM1_HPD_DE_BOUNCE_CFG			(1 << 8)
+#define AO_SC_SYS_CTRL1_USIM1_HPD_OE_CFG			(1 << 9)
+#define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG			(1 << 10)
+#define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG1			(1 << 11)
+#define AO_SC_SYS_CTRL1_USIM0_HPD_OE_SFT			(1 << 12)
+#define AO_SC_SYS_CTRL1_USIM1_HPD_OE_SFT			(1 << 13)
+#define AO_SC_SYS_CTRL1_MCU_CLKEN_HARDCFG			(1 << 15)
+#define AO_SC_SYS_CTRL1_AARM_WD_RST_CFG_MSK			(1 << 16)
+#define AO_SC_SYS_CTRL1_REMAP_SRAM_AARM_MSK			(1 << 17)
+#define AO_SC_SYS_CTRL1_EFUSEC_REMAP_MSK			(1 << 18)
+#define AO_SC_SYS_CTRL1_EXT_PLL_SEL_MSK				(1 << 19)
+#define AO_SC_SYS_CTRL1_MCU_WDG0_RSTMCU_CFG_MSK			(1 << 20)
+#define AO_SC_SYS_CTRL1_USIM0_HPD_DE_BOUNCE_CFG_MSK		(1 << 22)
+#define AO_SC_SYS_CTRL1_USIM0_HPD_OE_CFG_MSK			(1 << 23)
+#define AO_SC_SYS_CTRL1_USIM1_HPD_DE_BOUNCE_CFG_MSK		(1 << 24)
+#define AO_SC_SYS_CTRL1_USIM1_HPD_OE_CFG_MSK			(1 << 25)
+#define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG_MSK			(1 << 26)
+#define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG1_MSK		(1 << 27)
+#define AO_SC_SYS_CTRL1_USIM0_HPD_OE_SFT_MSK			(1 << 28)
+#define AO_SC_SYS_CTRL1_USIM1_HPD_OE_SFT_MSK			(1 << 29)
+#define AO_SC_SYS_CTRL1_MCU_CLKEN_HARDCFG_MSK			(1U << 31)
+
+#define AO_SC_SYS_CTRL2_MCU_SFT_RST_STAT_CLEAR			(1 << 26)
+#define AO_SC_SYS_CTRL2_MCU_WDG0_RST_STAT_CLEAR			(1 << 27)
+#define AO_SC_SYS_CTRL2_TSENSOR_RST_STAT_CLEAR			(1 << 28)
+#define AO_SC_SYS_CTRL2_ACPU_WDG_RST_STAT_CLEAR			(1 << 29)
+#define AO_SC_SYS_CTRL2_MCU_WDG1_RST_STAT_CLEAR			(1 << 30)
+#define AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR			(1U << 31)
+
+#define AO_SC_SYS_STAT0_MCU_RST_STAT				(1 << 25)
+#define AO_SC_SYS_STAT0_MCU_SOFTRST_STAT			(1 << 26)
+#define AO_SC_SYS_STAT0_MCU_WDGRST_STAT				(1 << 27)
+#define AO_SC_SYS_STAT0_TSENSOR_HARDRST_STAT			(1 << 28)
+#define AO_SC_SYS_STAT0_ACPU_WD_GLB_RST_STAT			(1 << 29)
+#define AO_SC_SYS_STAT0_CM3_WDG1_RST_STAT			(1 << 30)
+#define AO_SC_SYS_STAT0_GLB_SRST_STAT				(1U << 31)
+
+#define AO_SC_SYS_STAT1_MODE_STATUS				(1 << 0)
+#define AO_SC_SYS_STAT1_BOOT_SEL_LOCK				(1 << 16)
+#define AO_SC_SYS_STAT1_FUNC_MODE_LOCK				(1 << 17)
+#define AO_SC_SYS_STAT1_BOOT_MODE_LOCK				(1 << 19)
+#define AO_SC_SYS_STAT1_FUN_JTAG_MODE_OUT			(1 << 20)
+#define AO_SC_SYS_STAT1_SECURITY_BOOT_FLG			(1 << 27)
+#define AO_SC_SYS_STAT1_EFUSE_NANDBOOT_MSK			(1 << 28)
+#define AO_SC_SYS_STAT1_EFUSE_NAND_BITWIDE			(1 << 29)
+
+#define AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N			(1 << 0)
+#define AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N			(1 << 1)
+#define AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N			(1 << 2)
+#define AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N			(1 << 3)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_TIMER0_N		(1 << 4)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_TIMER1_N		(1 << 5)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_WDT0_N			(1 << 6)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_WDT1_N			(1 << 7)
+#define AO_SC_PERIPH_RSTDIS4_HRESET_IPC_S_N			(1 << 8)
+#define AO_SC_PERIPH_RSTDIS4_HRESET_IPC_NS_N			(1 << 9)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_EFUSEC_N			(1 << 10)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_WDT0_N			(1 << 12)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_WDT1_N			(1 << 13)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_WDT2_N			(1 << 14)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER0_N			(1 << 15)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER1_N			(1 << 16)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER2_N			(1 << 17)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER3_N			(1 << 18)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER4_N			(1 << 19)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER5_N			(1 << 20)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER6_N			(1 << 21)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER7_N			(1 << 22)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER8_N			(1 << 23)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_UART0_N			(1 << 24)
+#define AO_SC_PERIPH_RSTDIS4_RESET_RTC0_N			(1 << 25)
+#define AO_SC_PERIPH_RSTDIS4_RESET_RTC1_N			(1 << 26)
+#define AO_SC_PERIPH_RSTDIS4_PRESET_PMUSSI_N			(1 << 27)
+#define AO_SC_PERIPH_RSTDIS4_RESET_JTAG_AUTH_N			(1 << 28)
+#define AO_SC_PERIPH_RSTDIS4_RESET_CS_DAPB_ON_N			(1 << 29)
+#define AO_SC_PERIPH_RSTDIS4_MDM_SUBSYS_GLB			(1 << 30)
+
+#define AO_SC_PERIPH_CLKEN4_HCLK_MCU				(1 << 0)
+#define AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP				(1 << 3)
+#define AO_SC_PERIPH_CLKEN4_PCLK_CM3_TIMER0			(1 << 4)
+#define AO_SC_PERIPH_CLKEN4_PCLK_CM3_TIMER1			(1 << 5)
+#define AO_SC_PERIPH_CLKEN4_PCLK_CM3_WDT0			(1 << 6)
+#define AO_SC_PERIPH_CLKEN4_PCLK_CM3_WDT1			(1 << 7)
+#define AO_SC_PERIPH_CLKEN4_HCLK_IPC_S				(1 << 8)
+#define AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS				(1 << 9)
+#define AO_SC_PERIPH_CLKEN4_PCLK_EFUSEC				(1 << 10)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TZPC				(1 << 11)
+#define AO_SC_PERIPH_CLKEN4_PCLK_WDT0				(1 << 12)
+#define AO_SC_PERIPH_CLKEN4_PCLK_WDT1				(1 << 13)
+#define AO_SC_PERIPH_CLKEN4_PCLK_WDT2				(1 << 14)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER0				(1 << 15)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER1				(1 << 16)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER2				(1 << 17)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER3				(1 << 18)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER4				(1 << 19)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER5				(1 << 20)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER6				(1 << 21)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER7				(1 << 22)
+#define AO_SC_PERIPH_CLKEN4_PCLK_TIMER8				(1 << 23)
+#define AO_SC_PERIPH_CLKEN4_CLK_UART0				(1 << 24)
+#define AO_SC_PERIPH_CLKEN4_CLK_RTC0				(1 << 25)
+#define AO_SC_PERIPH_CLKEN4_CLK_RTC1				(1 << 26)
+#define AO_SC_PERIPH_CLKEN4_PCLK_PMUSSI				(1 << 27)
+#define AO_SC_PERIPH_CLKEN4_CLK_JTAG_AUTH			(1 << 28)
+#define AO_SC_PERIPH_CLKEN4_CLK_CS_DAPB_ON			(1 << 29)
+#define AO_SC_PERIPH_CLKEN4_CLK_PDM				(1 << 30)
+#define AO_SC_PERIPH_CLKEN4_CLK_SSI_PAD				(1U << 31)
+
+#define AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_CCPU			(1 << 0)
+#define AO_SC_PERIPH_CLKEN5_PCLK_EFUSEC_CCPU			(1 << 1)
+#define AO_SC_PERIPH_CLKEN5_HCLK_IPC_CCPU			(1 << 2)
+#define AO_SC_PERIPH_CLKEN5_HCLK_IPC_NS_CCPU			(1 << 3)
+#define AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_MCU			(1 << 16)
+#define AO_SC_PERIPH_CLKEN5_PCLK_EFUSEC_MCU			(1 << 17)
+#define AO_SC_PERIPH_CLKEN5_HCLK_IPC_MCU			(1 << 18)
+#define AO_SC_PERIPH_CLKEN5_HCLK_IPC_NS_MCU			(1 << 19)
+
+#define AO_SC_MCU_SUBSYS_CTRL3_RCLK_3				0x003
+#define AO_SC_MCU_SUBSYS_CTRL3_RCLK_MASK			0x007
+#define AO_SC_MCU_SUBSYS_CTRL3_CSSYS_CTRL_PROT			(1 << 3)
+#define AO_SC_MCU_SUBSYS_CTRL3_TCXO_AFC_OEN_CRG			(1 << 4)
+#define AO_SC_MCU_SUBSYS_CTRL3_AOB_IO_SEL18_USIM1		(1 << 8)
+#define AO_SC_MCU_SUBSYS_CTRL3_AOB_IO_SEL18_USIM0		(1 << 9)
+#define AO_SC_MCU_SUBSYS_CTRL3_AOB_IO_SEL18_SD			(1 << 10)
+#define AO_SC_MCU_SUBSYS_CTRL3_MCU_SUBSYS_CTRL3_RESERVED	(1 << 11)
+
+#define PCLK_TIMER1						(1 << 16)
+#define PCLK_TIMER0						(1 << 15)
+
+#endif /* HI6220_REGS_AO_H */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_peri.h b/plat/hisilicon/hikey/include/hi6220_regs_peri.h
new file mode 100644
index 0000000..77236e8
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_peri.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_REGS_PERI_H
+#define HI6220_REGS_PERI_H
+
+#define PERI_BASE				0xF7030000
+
+#define PERI_SC_PERIPH_CTRL1			(PERI_BASE + 0x000)
+#define PERI_SC_PERIPH_CTRL2			(PERI_BASE + 0x004)
+#define PERI_SC_PERIPH_CTRL3			(PERI_BASE + 0x008)
+#define PERI_SC_PERIPH_CTRL4			(PERI_BASE + 0x00c)
+#define PERI_SC_PERIPH_CTRL5			(PERI_BASE + 0x010)
+#define PERI_SC_PERIPH_CTRL6			(PERI_BASE + 0x014)
+#define PERI_SC_PERIPH_CTRL8			(PERI_BASE + 0x018)
+#define PERI_SC_PERIPH_CTRL9			(PERI_BASE + 0x01c)
+#define PERI_SC_PERIPH_CTRL10			(PERI_BASE + 0x020)
+#define PERI_SC_PERIPH_CTRL12			(PERI_BASE + 0x024)
+#define PERI_SC_PERIPH_CTRL13			(PERI_BASE + 0x028)
+#define PERI_SC_PERIPH_CTRL14			(PERI_BASE + 0x02c)
+
+#define PERI_SC_DDR_CTRL0			(PERI_BASE + 0x050)
+#define PERI_SC_PERIPH_STAT1			(PERI_BASE + 0x094)
+
+#define PERI_SC_PERIPH_CLKEN0			(PERI_BASE + 0x200)
+#define PERI_SC_PERIPH_CLKDIS0			(PERI_BASE + 0x204)
+#define PERI_SC_PERIPH_CLKSTAT0			(PERI_BASE + 0x208)
+#define PERI_SC_PERIPH_CLKEN1			(PERI_BASE + 0x210)
+#define PERI_SC_PERIPH_CLKDIS1			(PERI_BASE + 0x214)
+#define PERI_SC_PERIPH_CLKSTAT1			(PERI_BASE + 0x218)
+#define PERI_SC_PERIPH_CLKEN2			(PERI_BASE + 0x220)
+#define PERI_SC_PERIPH_CLKDIS2			(PERI_BASE + 0x224)
+#define PERI_SC_PERIPH_CLKSTAT2			(PERI_BASE + 0x228)
+#define PERI_SC_PERIPH_CLKEN3			(PERI_BASE + 0x230)
+#define PERI_SC_PERIPH_CLKDIS3			(PERI_BASE + 0x234)
+#define PERI_SC_PERIPH_CLKSTAT3			(PERI_BASE + 0x238)
+#define PERI_SC_PERIPH_CLKEN8			(PERI_BASE + 0x240)
+#define PERI_SC_PERIPH_CLKDIS8			(PERI_BASE + 0x244)
+#define PERI_SC_PERIPH_CLKSTAT8			(PERI_BASE + 0x248)
+#define PERI_SC_PERIPH_CLKEN9			(PERI_BASE + 0x250)
+#define PERI_SC_PERIPH_CLKDIS9			(PERI_BASE + 0x254)
+#define PERI_SC_PERIPH_CLKSTAT9			(PERI_BASE + 0x258)
+#define PERI_SC_PERIPH_CLKEN10			(PERI_BASE + 0x260)
+#define PERI_SC_PERIPH_CLKDIS10			(PERI_BASE + 0x264)
+#define PERI_SC_PERIPH_CLKSTAT10		(PERI_BASE + 0x268)
+#define PERI_SC_PERIPH_CLKEN12			(PERI_BASE + 0x270)
+#define PERI_SC_PERIPH_CLKDIS12			(PERI_BASE + 0x274)
+#define PERI_SC_PERIPH_CLKSTAT12		(PERI_BASE + 0x278)
+
+#define PERI_SC_PERIPH_RSTEN0			(PERI_BASE + 0x300)
+#define PERI_SC_PERIPH_RSTDIS0			(PERI_BASE + 0x304)
+#define PERI_SC_PERIPH_RSTSTAT0			(PERI_BASE + 0x308)
+#define PERI_SC_PERIPH_RSTEN1			(PERI_BASE + 0x310)
+#define PERI_SC_PERIPH_RSTDIS1			(PERI_BASE + 0x314)
+#define PERI_SC_PERIPH_RSTSTAT1			(PERI_BASE + 0x318)
+#define PERI_SC_PERIPH_RSTEN2			(PERI_BASE + 0x320)
+#define PERI_SC_PERIPH_RSTDIS2			(PERI_BASE + 0x324)
+#define PERI_SC_PERIPH_RSTSTAT2			(PERI_BASE + 0x328)
+#define PERI_SC_PERIPH_RSTEN3			(PERI_BASE + 0x330)
+#define PERI_SC_PERIPH_RSTDIS3			(PERI_BASE + 0x334)
+#define PERI_SC_PERIPH_RSTSTAT3			(PERI_BASE + 0x338)
+#define PERI_SC_PERIPH_RSTEN8			(PERI_BASE + 0x340)
+#define PERI_SC_PERIPH_RSTDIS8			(PERI_BASE + 0x344)
+#define PERI_SC_PERIPH_RSTSTAT8			(PERI_BASE + 0x338)
+
+#define PERI_SC_CLK_SEL0			(PERI_BASE + 0x400)
+#define PERI_SC_CLKCFG8BIT1			(PERI_BASE + 0x494)
+#define PERI_SC_CLKCFG8BIT2			(PERI_BASE + 0x498)
+#define PERI_SC_RESERVED8_ADDR			(PERI_BASE + 0xd04)
+
+/* PERI_SC_PERIPH_CTRL1 */
+#define PERI_CTRL1_ETR_AXI_CSYSREQ_N		(1 << 0)
+#define PERI_CTRL1_ETR_AXI_CSYSREQ_N		(1 << 0)
+#define PERI_CTRL1_HIFI_INT_MASK		(1 << 1)
+#define PERI_CTRL1_HIFI_ALL_INT_MASK		(1 << 2)
+#define PERI_CTRL1_ETR_AXI_CSYSREQ_N_MSK	(1 << 16)
+#define PERI_CTRL1_HIFI_INT_MASK_MSK		(1 << 17)
+#define PERI_CTRL1_HIFI_ALL_INT_MASK_MSK	(1 << 18)
+
+/* PERI_SC_PERIPH_CTRL2	*/
+#define PERI_CTRL2_MMC_CLK_PHASE_BYPASS_EN_MMC0	(1 << 0)
+#define PERI_CTRL2_MMC_CLK_PHASE_BYPASS_EN_MMC1	(1 << 2)
+#define PERI_CTRL2_NAND_SYS_MEM_SEL		(1 << 6)
+#define PERI_CTRL2_G3D_DDRT_AXI_SEL		(1 << 7)
+#define PERI_CTRL2_GU_MDM_BBP_TESTPIN_SEL	(1 << 8)
+#define PERI_CTRL2_CODEC_SSI_MASTER_CHECK	(1 << 9)
+#define PERI_CTRL2_FUNC_TEST_SOFT		(1 << 12)
+#define PERI_CTRL2_CSSYS_TS_ENABLE		(1 << 15)
+#define PERI_CTRL2_HIFI_RAMCTRL_S_EMA		(1 << 16)
+#define PERI_CTRL2_HIFI_RAMCTRL_S_EMAW		(1 << 20)
+#define PERI_CTRL2_HIFI_RAMCTRL_S_EMAS		(1 << 22)
+#define PERI_CTRL2_HIFI_RAMCTRL_S_RET1N		(1 << 26)
+#define PERI_CTRL2_HIFI_RAMCTRL_S_RET2N		(1 << 27)
+#define PERI_CTRL2_HIFI_RAMCTRL_S_PGEN		(1 << 28)
+
+/* PERI_SC_PERIPH_CTRL3 */
+#define PERI_CTRL3_HIFI_DDR_HARQMEM_ADDR	(1 << 0)
+#define PERI_CTRL3_HIFI_HARQMEMRMP_EN		(1 << 12)
+#define PERI_CTRL3_HARQMEM_SYS_MED_SEL		(1 << 13)
+#define PERI_CTRL3_SOC_AP_OCCUPY_GRP1		(1 << 14)
+#define PERI_CTRL3_SOC_AP_OCCUPY_GRP2		(1 << 16)
+#define PERI_CTRL3_SOC_AP_OCCUPY_GRP3		(1 << 18)
+#define PERI_CTRL3_SOC_AP_OCCUPY_GRP4		(1 << 20)
+#define PERI_CTRL3_SOC_AP_OCCUPY_GRP5		(1 << 22)
+#define PERI_CTRL3_SOC_AP_OCCUPY_GRP6		(1 << 24)
+
+/* PERI_SC_PERIPH_CTRL4 */
+#define PERI_CTRL4_PICO_FSELV			(1 << 0)
+#define PERI_CTRL4_FPGA_EXT_PHY_SEL		(1 << 3)
+#define PERI_CTRL4_PICO_REFCLKSEL		(1 << 4)
+#define PERI_CTRL4_PICO_SIDDQ			(1 << 6)
+#define PERI_CTRL4_PICO_SUSPENDM_SLEEPM		(1 << 7)
+#define PERI_CTRL4_PICO_OGDISABLE		(1 << 8)
+#define PERI_CTRL4_PICO_COMMONONN		(1 << 9)
+#define PERI_CTRL4_PICO_VBUSVLDEXT		(1 << 10)
+#define PERI_CTRL4_PICO_VBUSVLDEXTSEL		(1 << 11)
+#define PERI_CTRL4_PICO_VATESTENB		(1 << 12)
+#define PERI_CTRL4_PICO_SUSPENDM		(1 << 14)
+#define PERI_CTRL4_PICO_SLEEPM			(1 << 15)
+#define PERI_CTRL4_BC11_C			(1 << 16)
+#define PERI_CTRL4_BC11_B			(1 << 17)
+#define PERI_CTRL4_BC11_A			(1 << 18)
+#define PERI_CTRL4_BC11_GND			(1 << 19)
+#define PERI_CTRL4_BC11_FLOAT			(1 << 20)
+#define PERI_CTRL4_OTG_PHY_SEL			(1 << 21)
+#define PERI_CTRL4_USB_OTG_SS_SCALEDOWN_MODE	(1 << 22)
+#define PERI_CTRL4_OTG_DM_PULLDOWN		(1 << 24)
+#define PERI_CTRL4_OTG_DP_PULLDOWN		(1 << 25)
+#define PERI_CTRL4_OTG_IDPULLUP			(1 << 26)
+#define PERI_CTRL4_OTG_DRVBUS			(1 << 27)
+#define PERI_CTRL4_OTG_SESSEND			(1 << 28)
+#define PERI_CTRL4_OTG_BVALID			(1 << 29)
+#define PERI_CTRL4_OTG_AVALID			(1 << 30)
+#define PERI_CTRL4_OTG_VBUSVALID		(1U << 31)
+
+/* PERI_SC_PERIPH_CTRL5 */
+#define PERI_CTRL5_USBOTG_RES_SEL		(1 << 3)
+#define PERI_CTRL5_PICOPHY_ACAENB		(1 << 4)
+#define PERI_CTRL5_PICOPHY_BC_MODE		(1 << 5)
+#define PERI_CTRL5_PICOPHY_CHRGSEL		(1 << 6)
+#define PERI_CTRL5_PICOPHY_VDATSRCEND		(1 << 7)
+#define PERI_CTRL5_PICOPHY_VDATDETENB		(1 << 8)
+#define PERI_CTRL5_PICOPHY_DCDENB		(1 << 9)
+#define PERI_CTRL5_PICOPHY_IDDIG		(1 << 10)
+#define PERI_CTRL5_DBG_MUX			(1 << 11)
+
+/* PERI_SC_PERIPH_CTRL6 */
+#define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_EMA	(1 << 0)
+#define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_EMAW	(1 << 4)
+#define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_EMAS	(1 << 6)
+#define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_RET1N	(1 << 10)
+#define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_RET2N	(1 << 11)
+#define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_PGEN	(1 << 12)
+
+/* PERI_SC_PERIPH_CTRL8 */
+#define PERI_CTRL8_PICOPHY_TXRISETUNE0		(1 << 0)
+#define PERI_CTRL8_PICOPHY_TXPREEMPAMPTUNE0	(1 << 2)
+#define PERI_CTRL8_PICOPHY_TXRESTUNE0		(1 << 4)
+#define PERI_CTRL8_PICOPHY_TXHSSVTUNE0		(1 << 6)
+#define PERI_CTRL8_PICOPHY_COMPDISTUNE0		(1 << 8)
+#define PERI_CTRL8_PICOPHY_TXPREEMPPULSETUNE0	(1 << 11)
+#define PERI_CTRL8_PICOPHY_OTGTUNE0		(1 << 12)
+#define PERI_CTRL8_PICOPHY_SQRXTUNE0		(1 << 16)
+#define PERI_CTRL8_PICOPHY_TXVREFTUNE0		(1 << 20)
+#define PERI_CTRL8_PICOPHY_TXFSLSTUNE0		(1 << 28)
+
+/* PERI_SC_PERIPH_CTRL9	*/
+#define PERI_CTRL9_PICOPLY_TESTCLKEN		(1 << 0)
+#define PERI_CTRL9_PICOPLY_TESTDATAOUTSEL	(1 << 1)
+#define PERI_CTRL9_PICOPLY_TESTADDR		(1 << 4)
+#define PERI_CTRL9_PICOPLY_TESTDATAIN		(1 << 8)
+
+/*
+ * PERI_SC_PERIPH_CLKEN0
+ * PERI_SC_PERIPH_CLKDIS0
+ * PERI_SC_PERIPH_CLKSTAT0
+ */
+#define PERI_CLK0_MMC0				(1 << 0)
+#define PERI_CLK0_MMC1				(1 << 1)
+#define PERI_CLK0_MMC2				(1 << 2)
+#define PERI_CLK0_NANDC				(1 << 3)
+#define PERI_CLK0_USBOTG			(1 << 4)
+#define PERI_CLK0_PICOPHY			(1 << 5)
+#define PERI_CLK0_PLL				(1 << 6)
+
+/*
+ * PERI_SC_PERIPH_CLKEN1
+ * PERI_SC_PERIPH_CLKDIS1
+ * PERI_SC_PERIPH_CLKSTAT1
+ */
+#define PERI_CLK1_HIFI				(1 << 0)
+#define PERI_CLK1_DIGACODEC			(1 << 5)
+
+/*
+ * PERI_SC_PERIPH_CLKEN2
+ * PERI_SC_PERIPH_CLKDIS2
+ * PERI_SC_PERIPH_CLKSTAT2
+ */
+#define PERI_CLK2_IPF				(1 << 0)
+#define PERI_CLK2_SOCP				(1 << 1)
+#define PERI_CLK2_DMAC				(1 << 2)
+#define PERI_CLK2_SECENG			(1 << 3)
+#define PERI_CLK2_HPM0				(1 << 5)
+#define PERI_CLK2_HPM1				(1 << 6)
+#define PERI_CLK2_HPM2				(1 << 7)
+#define PERI_CLK2_HPM3				(1 << 8)
+
+/*
+ * PERI_SC_PERIPH_CLKEN3
+ * PERI_SC_PERIPH_CLKDIS3
+ * PERI_SC_PERIPH_CLKSTAT3
+ */
+#define PERI_CLK3_CSSYS				(1 << 0)
+#define PERI_CLK3_I2C0				(1 << 1)
+#define PERI_CLK3_I2C1				(1 << 2)
+#define PERI_CLK3_I2C2				(1 << 3)
+#define PERI_CLK3_I2C3				(1 << 4)
+#define PERI_CLK3_UART1				(1 << 5)
+#define PERI_CLK3_UART2				(1 << 6)
+#define PERI_CLK3_UART3				(1 << 7)
+#define PERI_CLK3_UART4				(1 << 8)
+#define PERI_CLK3_SSP				(1 << 9)
+#define PERI_CLK3_PWM				(1 << 10)
+#define PERI_CLK3_BLPWM				(1 << 11)
+#define PERI_CLK3_TSENSOR			(1 << 12)
+#define PERI_CLK3_GPS				(1 << 15)
+#define PERI_CLK3_TCXO_PAD0			(1 << 16)
+#define PERI_CLK3_TCXO_PAD1			(1 << 17)
+#define PERI_CLK3_DAPB				(1 << 18)
+#define PERI_CLK3_HKADC				(1 << 19)
+#define PERI_CLK3_CODEC_SSI			(1 << 20)
+#define PERI_CLK3_TZPC_DEP			(1 << 21)
+
+/*
+ * PERI_SC_PERIPH_CLKEN8
+ * PERI_SC_PERIPH_CLKDIS8
+ * PERI_SC_PERIPH_CLKSTAT8
+ */
+#define PERI_CLK8_RS0				(1 << 0)
+#define PERI_CLK8_RS2				(1 << 1)
+#define PERI_CLK8_RS3				(1 << 2)
+#define PERI_CLK8_MS0				(1 << 3)
+#define PERI_CLK8_MS2				(1 << 5)
+#define PERI_CLK8_XG2RAM0			(1 << 6)
+#define PERI_CLK8_X2SRAM			(1 << 7)
+#define PERI_CLK8_SRAM				(1 << 8)
+#define PERI_CLK8_ROM				(1 << 9)
+#define PERI_CLK8_HARQ				(1 << 10)
+#define PERI_CLK8_MMU				(1 << 11)
+#define PERI_CLK8_DDRC				(1 << 12)
+#define PERI_CLK8_DDRPHY			(1 << 13)
+#define PERI_CLK8_DDRPHY_REF			(1 << 14)
+#define PERI_CLK8_X2X_SYSNOC			(1 << 15)
+#define PERI_CLK8_X2X_CCPU			(1 << 16)
+#define PERI_CLK8_DDRT				(1 << 17)
+#define PERI_CLK8_DDRPACK_RS			(1 << 18)
+
+/*
+ * PERI_SC_PERIPH_CLKEN9
+ * PERI_SC_PERIPH_CLKDIS9
+ * PERI_SC_PERIPH_CLKSTAT9
+ */
+#define PERI_CLK9_CARM_DAP			(1 << 0)
+#define PERI_CLK9_CARM_ATB			(1 << 1)
+#define PERI_CLK9_CARM_LBUS			(1 << 2)
+#define PERI_CLK9_CARM_KERNEL			(1 << 3)
+
+/*
+ * PERI_SC_PERIPH_CLKEN10
+ * PERI_SC_PERIPH_CLKDIS10
+ * PERI_SC_PERIPH_CLKSTAT10
+ */
+#define PERI_CLK10_IPF_CCPU			(1 << 0)
+#define PERI_CLK10_SOCP_CCPU			(1 << 1)
+#define PERI_CLK10_SECENG_CCPU			(1 << 2)
+#define PERI_CLK10_HARQ_CCPU			(1 << 3)
+#define PERI_CLK10_IPF_MCU			(1 << 16)
+#define PERI_CLK10_SOCP_MCU			(1 << 17)
+#define PERI_CLK10_SECENG_MCU			(1 << 18)
+#define PERI_CLK10_HARQ_MCU			(1 << 19)
+
+/*
+ * PERI_SC_PERIPH_CLKEN12
+ * PERI_SC_PERIPH_CLKDIS12
+ * PERI_SC_PERIPH_CLKSTAT12
+ */
+#define PERI_CLK12_HIFI_SRC			(1 << 0)
+#define PERI_CLK12_MMC0_SRC			(1 << 1)
+#define PERI_CLK12_MMC1_SRC			(1 << 2)
+#define PERI_CLK12_MMC2_SRC			(1 << 3)
+#define PERI_CLK12_SYSPLL_DIV			(1 << 4)
+#define PERI_CLK12_TPIU_SRC			(1 << 5)
+#define PERI_CLK12_MMC0_HF			(1 << 6)
+#define PERI_CLK12_MMC1_HF			(1 << 7)
+#define PERI_CLK12_PLL_TEST_SRC			(1 << 8)
+#define PERI_CLK12_CODEC_SOC			(1 << 9)
+#define PERI_CLK12_MEDIA			(1 << 10)
+
+/*
+ * PERI_SC_PERIPH_RSTEN0
+ * PERI_SC_PERIPH_RSTDIS0
+ * PERI_SC_PERIPH_RSTSTAT0
+ */
+#define PERI_RST0_MMC0				(1 << 0)
+#define PERI_RST0_MMC1				(1 << 1)
+#define PERI_RST0_MMC2				(1 << 2)
+#define PERI_RST0_NANDC				(1 << 3)
+#define PERI_RST0_USBOTG_BUS			(1 << 4)
+#define PERI_RST0_POR_PICOPHY			(1 << 5)
+#define PERI_RST0_USBOTG			(1 << 6)
+#define PERI_RST0_USBOTG_32K			(1 << 7)
+
+/*
+ * PERI_SC_PERIPH_RSTEN1
+ * PERI_SC_PERIPH_RSTDIS1
+ * PERI_SC_PERIPH_RSTSTAT1
+ */
+#define PERI_RST1_HIFI				(1 << 0)
+#define PERI_RST1_DIGACODEC			(1 << 5)
+
+/*
+ * PERI_SC_PERIPH_RSTEN2
+ * PERI_SC_PERIPH_RSTDIS2
+ * PERI_SC_PERIPH_RSTSTAT2
+ */
+#define PERI_RST2_IPF				(1 << 0)
+#define PERI_RST2_SOCP				(1 << 1)
+#define PERI_RST2_DMAC				(1 << 2)
+#define PERI_RST2_SECENG			(1 << 3)
+#define PERI_RST2_ABB				(1 << 4)
+#define PERI_RST2_HPM0				(1 << 5)
+#define PERI_RST2_HPM1				(1 << 6)
+#define PERI_RST2_HPM2				(1 << 7)
+#define PERI_RST2_HPM3				(1 << 8)
+
+/*
+ * PERI_SC_PERIPH_RSTEN3
+ * PERI_SC_PERIPH_RSTDIS3
+ * PERI_SC_PERIPH_RSTSTAT3
+ */
+#define PERI_RST3_CSSYS				(1 << 0)
+#define PERI_RST3_I2C0				(1 << 1)
+#define PERI_RST3_I2C1				(1 << 2)
+#define PERI_RST3_I2C2				(1 << 3)
+#define PERI_RST3_I2C3				(1 << 4)
+#define PERI_RST3_UART1				(1 << 5)
+#define PERI_RST3_UART2				(1 << 6)
+#define PERI_RST3_UART3				(1 << 7)
+#define PERI_RST3_UART4				(1 << 8)
+#define PERI_RST3_SSP				(1 << 9)
+#define PERI_RST3_PWM				(1 << 10)
+#define PERI_RST3_BLPWM				(1 << 11)
+#define PERI_RST3_TSENSOR			(1 << 12)
+#define PERI_RST3_DAPB				(1 << 18)
+#define PERI_RST3_HKADC				(1 << 19)
+#define PERI_RST3_CODEC				(1 << 20)
+
+/*
+ * PERI_SC_PERIPH_RSTEN8
+ * PERI_SC_PERIPH_RSTDIS8
+ * PERI_SC_PERIPH_RSTSTAT8
+ */
+#define PERI_RST8_RS0				(1 << 0)
+#define PERI_RST8_RS2				(1 << 1)
+#define PERI_RST8_RS3				(1 << 2)
+#define PERI_RST8_MS0				(1 << 3)
+#define PERI_RST8_MS2				(1 << 5)
+#define PERI_RST8_XG2RAM0			(1 << 6)
+#define PERI_RST8_X2SRAM_TZMA			(1 << 7)
+#define PERI_RST8_SRAM				(1 << 8)
+#define PERI_RST8_HARQ				(1 << 10)
+#define PERI_RST8_DDRC				(1 << 12)
+#define PERI_RST8_DDRC_APB			(1 << 13)
+#define PERI_RST8_DDRPACK_APB			(1 << 14)
+#define PERI_RST8_DDRT				(1 << 17)
+
+#endif /* HI6220_REGS_PERI_H */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_pin.h b/plat/hisilicon/hikey/include/hi6220_regs_pin.h
new file mode 100644
index 0000000..05620ea
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_pin.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_REGS_PIN_H
+#define HI6220_REGS_PIN_H
+
+#define IOMG_BASE				0xF7010000
+
+#define IOMG_SD_CLK				(IOMG_BASE + 0x0C)
+#define IOMG_SD_CMD				(IOMG_BASE + 0x10)
+#define IOMG_SD_DATA0				(IOMG_BASE + 0x14)
+#define IOMG_SD_DATA1				(IOMG_BASE + 0x18)
+#define IOMG_SD_DATA2				(IOMG_BASE + 0x1C)
+#define IOMG_SD_DATA3				(IOMG_BASE + 0x20)
+#define IOMG_GPIO24				(IOMG_BASE + 0x140)
+
+#define IOMG_MUX_FUNC0				0
+#define IOMG_MUX_FUNC1				1
+#define IOMG_MUX_FUNC2				2
+
+#define IOCG1_BASE				0xF7010800
+#define IOCG2_BASE				0xF8001800
+
+#define IOCG_SD_CLK				(IOCG1_BASE + 0x0C)
+#define IOCG_SD_CMD				(IOCG1_BASE + 0x10)
+#define IOCG_SD_DATA0				(IOCG1_BASE + 0x14)
+#define IOCG_SD_DATA1				(IOCG1_BASE + 0x18)
+#define IOCG_SD_DATA2				(IOCG1_BASE + 0x1C)
+#define IOCG_SD_DATA3				(IOCG1_BASE + 0x20)
+#define IOCG_GPIO24				(IOCG1_BASE + 0x150)
+#define IOCG_GPIO8				(IOCG2_BASE + 0x30)
+
+#define IOCG_DRIVE_8MA				(2 << 4)
+#define IOCG_DRIVE_10MA				(3 << 4)
+#define IOCG_INPUT_16MA				0x64
+#define IOCG_INPUT_12MA				0x54
+#define IOCG_PULLDOWN				(1 << 1)
+#define IOCG_PULLUP				(1 << 0)
+
+#endif /* HI6220_REGS_PIN_H */
diff --git a/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h b/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h
new file mode 100644
index 0000000..404405b
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6220_REGS_PMCTRL_H
+#define HI6220_REGS_PMCTRL_H
+
+#define PMCTRL_BASE				0xF7032000
+
+#define PMCTRL_ACPUPLLCTRL			(PMCTRL_BASE + 0x000)
+#define PMCTRL_ACPUPLLFREQ			(PMCTRL_BASE + 0x004)
+#define PMCTRL_DDRPLL1CTRL			(PMCTRL_BASE + 0x010)
+#define PMCTRL_DDRPLL0CTRL			(PMCTRL_BASE + 0x030)
+#define PMCTRL_MEDPLLCTRL			(PMCTRL_BASE + 0x038)
+#define PMCTRL_ACPUPLLSEL			(PMCTRL_BASE + 0x100)
+#define PMCTRL_ACPUCLKDIV			(PMCTRL_BASE + 0x104)
+#define PMCTRL_ACPUSYSPLLCFG			(PMCTRL_BASE + 0x110)
+#define PMCTRL_ACPUCLKOFFCFG			(PMCTRL_BASE + 0x114)
+#define PMCTRL_ACPUPLLFRAC			(PMCTRL_BASE + 0x134)
+#define PMCTRL_ACPUPMUVOLUPTIME			(PMCTRL_BASE + 0x360)
+#define PMCTRL_ACPUPMUVOLDNTIME			(PMCTRL_BASE + 0x364)
+#define PMCTRL_ACPUVOLPMUADDR			(PMCTRL_BASE + 0x368)
+#define PMCTRL_ACPUVOLUPSTEP			(PMCTRL_BASE + 0x36c)
+#define PMCTRL_ACPUVOLDNSTEP			(PMCTRL_BASE + 0x370)
+#define PMCTRL_ACPUDFTVOL			(PMCTRL_BASE + 0x374)
+#define PMCTRL_ACPUDESTVOL			(PMCTRL_BASE + 0x378)
+#define PMCTRL_ACPUVOLTTIMEOUT			(PMCTRL_BASE + 0x37c)
+
+#define PMCTRL_ACPUPLLCTRL_EN_CFG		(1 << 0)
+
+#define PMCTRL_ACPUCLKDIV_CPUEXT_CFG_MASK	(3 << 0)
+#define PMCTRL_ACPUCLKDIV_DDR_CFG_MASK		(3 << 8)
+#define PMCTRL_ACPUCLKDIV_CPUEXT_STAT_MASK	(3 << 16)
+#define PMCTRL_ACPUCLKDIV_DDR_STAT_MASK		(3 << 24)
+
+#define PMCTRL_ACPUPLLSEL_ACPUPLL_CFG		(1 << 0)
+#define PMCTRL_ACPUPLLSEL_ACPUPLL_STAT		(1 << 1)
+#define PMCTRL_ACPUPLLSEL_SYSPLL_STAT		(1 << 2)
+
+#define PMCTRL_ACPUSYSPLL_CLKDIV_CFG_MASK	0x7
+#define PMCTRL_ACPUSYSPLL_CLKEN_CFG		(1 << 4)
+#define PMCTRL_ACPUSYSPLL_CLKDIV_SW		(3 << 12)
+
+#define PMCTRL_ACPUSYSPLLCFG_SYSPLL_CLKEN	(1 << 4)
+#define PMCTRL_ACPUSYSPLLCFG_CLKDIV_MASK	(3 << 12)
+
+#define PMCTRL_ACPUDESTVOL_DEST_VOL_MASK	0x7f
+#define PMCTRL_ACPUDESTVOL_CURR_VOL_MASK	(0x7f << 8)
+
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START   (0)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_END     (0)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_rst_START      (2)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_rst_END        (2)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_time_START     (4)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_time_END       (27)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START  (28)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_END    (28)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_lock_START     (29)
+#define SOC_PMCTRL_ACPUPLLCTRL_acpupll_lock_END       (29)
+
+#define SOC_PMCTRL_ACPUPLLFRAC_ADDR(base)   ((base) + (0x134))
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START   (12)
+
+#define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START   (0)
+#define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_END     (0)
+#define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START  (1)
+#define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_END    (1)
+#define SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START   (2)
+#define SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_END     (2)
+
+#define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START     (0)
+#define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_END       (1)
+#define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START   (8)
+#define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_END     (9)
+#define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START    (16)
+#define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_END      (17)
+#define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START  (24)
+#define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_END    (25)
+
+#define SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START   (0)
+#define SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END     (6)
+#define SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START  (8)
+#define SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_END    (14)
+
+#define SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START  (0)
+#define SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_END    (0)
+
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_cfg_START      (0)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_cfg_END        (2)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START    (4)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_END      (4)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_cfg_START  (8)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_cfg_END    (9)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_stat_START     (16)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_stat_END       (19)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_stat_START   (20)
+#define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_stat_END     (20)
+
+#endif /* HI6220_REGS_PMCTRL_H */
diff --git a/plat/hisilicon/hikey/include/hi6553.h b/plat/hisilicon/hikey/include/hi6553.h
new file mode 100644
index 0000000..fc991f8
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hi6553.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI6553_H
+#define HI6553_H
+
+#include <lib/mmio.h>
+
+#include <hi6220.h>
+
+#define HI6553_DISABLE6_XO_CLK			(PMUSSI_BASE + (0x036 << 2))
+
+#define DISABLE6_XO_CLK_BB			(1 << 0)
+#define DISABLE6_XO_CLK_CONN			(1 << 1)
+#define DISABLE6_XO_CLK_NFC			(1 << 2)
+#define DISABLE6_XO_CLK_RF1			(1 << 3)
+#define DISABLE6_XO_CLK_RF2			(1 << 4)
+
+#define HI6553_VERSION_REG			(PMUSSI_BASE + (0x000 << 2))
+#define HI6553_IRQ2_MASK			(PMUSSI_BASE + (0x008 << 2))
+#define HI6553_ENABLE2_LDO1_8			(PMUSSI_BASE + (0x029 << 2))
+#define HI6553_DISABLE2_LDO1_8			(PMUSSI_BASE + (0x02a << 2))
+#define HI6553_ONOFF_STATUS2_LDO1_8		(PMUSSI_BASE + (0x02b << 2))
+#define HI6553_ENABLE3_LDO9_16			(PMUSSI_BASE + (0x02c << 2))
+#define HI6553_DISABLE3_LDO9_16			(PMUSSI_BASE + (0x02d << 2))
+#define HI6553_ONOFF_STATUS3_LDO9_16		(PMUSSI_BASE + (0x02e << 2))
+#define HI6553_ENABLE4_LDO17_22			(PMUSSI_BASE + (0x02f << 2))
+#define HI6553_DISABLE4_LDO17_22		(PMUSSI_BASE + (0x030 << 2))
+#define HI6553_ONOFF_STATUS4_LDO17_22		(PMUSSI_BASE + (0x031 << 2))
+#define HI6553_PERI_EN_MARK			(PMUSSI_BASE + (0x040 << 2))
+#define HI6553_BUCK2_REG1			(PMUSSI_BASE + (0x04a << 2))
+#define HI6553_BUCK2_REG5			(PMUSSI_BASE + (0x04e << 2))
+#define HI6553_BUCK2_REG6			(PMUSSI_BASE + (0x04f << 2))
+#define HI6553_BUCK3_REG3			(PMUSSI_BASE + (0x054 << 2))
+#define HI6553_BUCK3_REG5			(PMUSSI_BASE + (0x056 << 2))
+#define HI6553_BUCK3_REG6			(PMUSSI_BASE + (0x057 << 2))
+#define HI6553_BUCK4_REG2			(PMUSSI_BASE + (0x05b << 2))
+#define HI6553_BUCK4_REG5			(PMUSSI_BASE + (0x05e << 2))
+#define HI6553_BUCK4_REG6			(PMUSSI_BASE + (0x05f << 2))
+#define HI6553_CLK_TOP0				(PMUSSI_BASE + (0x063 << 2))
+#define HI6553_CLK_TOP3				(PMUSSI_BASE + (0x066 << 2))
+#define HI6553_CLK_TOP4				(PMUSSI_BASE + (0x067 << 2))
+#define HI6553_VSET_BUCK2_ADJ			(PMUSSI_BASE + (0x06d << 2))
+#define HI6553_VSET_BUCK3_ADJ			(PMUSSI_BASE + (0x06e << 2))
+#define HI6553_LDO7_REG_ADJ			(PMUSSI_BASE + (0x078 << 2))
+#define HI6553_LDO10_REG_ADJ			(PMUSSI_BASE + (0x07b << 2))
+#define HI6553_LDO15_REG_ADJ			(PMUSSI_BASE + (0x080 << 2))
+#define HI6553_LDO19_REG_ADJ			(PMUSSI_BASE + (0x084 << 2))
+#define HI6553_LDO20_REG_ADJ			(PMUSSI_BASE + (0x085 << 2))
+#define HI6553_LDO21_REG_ADJ			(PMUSSI_BASE + (0x086 << 2))
+#define HI6553_LDO22_REG_ADJ			(PMUSSI_BASE + (0x087 << 2))
+#define HI6553_DR_LED_CTRL			(PMUSSI_BASE + (0x098 << 2))
+#define HI6553_DR_OUT_CTRL			(PMUSSI_BASE + (0x099 << 2))
+#define HI6553_DR3_ISET				(PMUSSI_BASE + (0x09a << 2))
+#define HI6553_DR3_START_DEL			(PMUSSI_BASE + (0x09b << 2))
+#define HI6553_DR4_ISET				(PMUSSI_BASE + (0x09c << 2))
+#define HI6553_DR4_START_DEL			(PMUSSI_BASE + (0x09d << 2))
+#define HI6553_DR345_TIM_CONF0			(PMUSSI_BASE + (0x0a0 << 2))
+#define HI6553_NP_REG_ADJ1			(PMUSSI_BASE + (0x0be << 2))
+#define HI6553_NP_REG_CHG			(PMUSSI_BASE + (0x0c0 << 2))
+#define HI6553_BUCK01_CTRL2			(PMUSSI_BASE + (0x0d9 << 2))
+#define HI6553_BUCK0_CTRL1			(PMUSSI_BASE + (0x0dd << 2))
+#define HI6553_BUCK0_CTRL5			(PMUSSI_BASE + (0x0e1 << 2))
+#define HI6553_BUCK0_CTRL7			(PMUSSI_BASE + (0x0e3 << 2))
+#define HI6553_BUCK1_CTRL1			(PMUSSI_BASE + (0x0e8 << 2))
+#define HI6553_BUCK1_CTRL5			(PMUSSI_BASE + (0x0ec << 2))
+#define HI6553_BUCK1_CTRL7			(PMUSSI_BASE + (0x0ef << 2))
+#define HI6553_CLK19M2_600_586_EN		(PMUSSI_BASE + (0x0fe << 2))
+
+#define LED_START_DELAY_TIME			0x00
+#define LED_ELEC_VALUE				0x07
+#define LED_LIGHT_TIME				0xf0
+#define LED_GREEN_ENABLE			(1 << 1)
+#define LED_OUT_CTRL				0x00
+
+#define PMU_HI6552_V300				0x30
+#define PMU_HI6552_V310				0x31
+
+#endif /* HI6553_H */
diff --git a/plat/hisilicon/hikey/include/hikey_def.h b/plat/hisilicon/hikey/include/hikey_def.h
new file mode 100644
index 0000000..4fb3e56
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hikey_def.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY_DEF_H
+#define HIKEY_DEF_H
+
+/* Always assume DDR is 1GB size. */
+#define DDR_BASE			0x0
+#define DDR_SIZE			0x40000000
+
+#define DEVICE_BASE			0xF4000000
+#define DEVICE_SIZE			0x05800000
+
+/* Memory location options for TSP */
+#define HIKEY_SRAM_ID		0
+#define HIKEY_DRAM_ID		1
+
+/*
+ * DDR for OP-TEE (32MB from 0x3E00000-0x3FFFFFFF) is divided in several
+ * regions
+ *   - Secure DDR (default is the top 16MB) used by OP-TEE
+ *   - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB)
+ *   - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature
+ *   - Non-secure DDR (8MB) reserved for OP-TEE's future use
+ */
+#define DDR_SEC_SIZE			0x01000000
+#define DDR_SEC_BASE			(DDR_BASE + DDR_SIZE - DDR_SEC_SIZE) /* 0x3F000000 */
+
+#define DDR_SDP_SIZE			0x00400000
+#define DDR_SDP_BASE			(DDR_SEC_BASE - 0x400000 /* align */ - \
+					DDR_SDP_SIZE)
+
+#define SRAM_BASE			0xFFF80000
+#define SRAM_SIZE			0x00012000
+
+/*
+ * PL011 related constants
+ */
+#define PL011_UART0_BASE		0xF8015000
+#define PL011_UART2_BASE		0xF7112000
+#define PL011_UART3_BASE		0xF7113000
+#define PL011_BAUDRATE			115200
+#define PL011_UART_CLK_IN_HZ		19200000
+
+#define HIKEY_USB_DESC_BASE		(DDR_BASE + 0x00800000)
+#define HIKEY_USB_DESC_SIZE		0x00100000
+#define HIKEY_USB_DATA_BASE		(DDR_BASE + 0x10000000)
+#define HIKEY_USB_DATA_SIZE		0x10000000
+#define HIKEY_FB_BUFFER_BASE		(HIKEY_USB_DATA_BASE)
+#define HIKEY_FB_BUFFER_SIZE		HIKEY_USB_DATA_SIZE
+#define HIKEY_FB_DOWNLOAD_BASE		(HIKEY_FB_BUFFER_BASE +		\
+					 HIKEY_FB_BUFFER_SIZE)
+#define HIKEY_FB_DOWNLOAD_SIZE		HIKEY_USB_DATA_SIZE
+
+#define HIKEY_USB_DESC_IN_BASE		(DDR_BASE + 0x00800000)
+#define HIKEY_USB_DESC_IN_SIZE		0x00040000
+#define HIKEY_USB_DESC_EP0_OUT_BASE	(HIKEY_USB_DESC_IN_BASE +	\
+					 HIKEY_USB_DESC_IN_SIZE)
+#define HIKEY_USB_DESC_EP0_OUT_SIZE	0x00040000
+#define HIKEY_USB_DESC_EPX_OUT_BASE	(HIKEY_USB_DESC_EP0_OUT_BASE +	\
+					 HIKEY_USB_DESC_EP0_OUT_SIZE)
+#define HIKEY_USB_DESC_EPX_OUT_SIZE	0x00080000
+
+#define HIKEY_MMC_DESC_BASE		(DDR_BASE + 0x03000000)
+#define HIKEY_MMC_DESC_SIZE		0x00100000
+
+/*
+ * HIKEY_MMC_DATA_BASE & HIKEY_MMC_DATA_SIZE are shared between fastboot
+ * and eMMC driver. Since it could avoid to memory copy.
+ * So this SRAM region is used twice. First, it's used in BL1 as temporary
+ * buffer in eMMC driver. Second, it's used by MCU in BL2. The SRAM region
+ * needs to be clear before used in BL2.
+ */
+#define HIKEY_MMC_DATA_BASE		(DDR_BASE + 0x10000000)
+#define HIKEY_MMC_DATA_SIZE		0x20000000
+#define HIKEY_NS_IMAGE_OFFSET		(DDR_BASE + 0x35000000)
+#define HIKEY_BL1_MMC_DESC_BASE		(SRAM_BASE)
+#define HIKEY_BL1_MMC_DESC_SIZE		0x00001000
+#define HIKEY_BL1_MMC_DATA_BASE		(HIKEY_BL1_MMC_DESC_BASE +	\
+					 HIKEY_BL1_MMC_DESC_SIZE)
+#define HIKEY_BL1_MMC_DATA_SIZE		0x0000B000
+
+#define EMMC_BASE			0
+#define HIKEY_FIP_BASE			(EMMC_BASE + (4 << 20))
+#define HIKEY_FIP_MAX_SIZE		(8 << 20)
+#define HIKEY_EMMC_RPMB_BASE		(EMMC_BASE + 0)
+#define HIKEY_EMMC_RPMB_MAX_SIZE	(128 << 10)
+#define HIKEY_EMMC_USERDATA_BASE	(EMMC_BASE + 0)
+#define HIKEY_EMMC_USERDATA_MAX_SIZE	(4 << 30)
+
+/*
+ * GIC400 interrupt handling related constants
+ */
+#define IRQ_SEC_PHY_TIMER			29
+#define IRQ_SEC_SGI_0				8
+#define IRQ_SEC_SGI_1				9
+#define IRQ_SEC_SGI_2				10
+#define IRQ_SEC_SGI_3				11
+#define IRQ_SEC_SGI_4				12
+#define IRQ_SEC_SGI_5				13
+#define IRQ_SEC_SGI_6				14
+#define IRQ_SEC_SGI_7				15
+#define IRQ_SEC_SGI_8				16
+
+#endif /* HIKEY_DEF_H */
diff --git a/plat/hisilicon/hikey/include/hikey_layout.h b/plat/hisilicon/hikey/include/hikey_layout.h
new file mode 100644
index 0000000..4b8dc53
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hikey_layout.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY_LAYOUT_H
+#define HIKEY_LAYOUT_H
+
+/*
+ * Platform memory map related constants
+ */
+#define XG2RAM0_BASE		0xF9800000
+#define XG2RAM0_SIZE		0x00400000
+
+/*
+ * BL1 is stored in XG2RAM0_HIRQ that is 784KB large (0xF980_0000~0xF98C_4000).
+ */
+#define ONCHIPROM_PARAM_BASE		(XG2RAM0_BASE + 0x700)
+#define LOADER_RAM_BASE			(XG2RAM0_BASE + 0x800)
+#define BL1_XG2RAM0_OFFSET		0x1000
+
+/*
+ * BL1 specific defines.
+ *
+ * Both loader and BL1_RO region stay in SRAM since they are used to simulate
+ * ROM.
+ * Loader is used to switch Hi6220 SoC from 32-bit to 64-bit mode.
+ *
+ * ++++++++++  0xF980_0000
+ * + loader +
+ * ++++++++++  0xF980_1000
+ * + BL1_RO +
+ * ++++++++++  0xF981_8000
+ * + BL1_RW +
+ * ++++++++++  0xF989_8000
+ */
+#define BL1_RO_BASE			(XG2RAM0_BASE + BL1_XG2RAM0_OFFSET)
+#define BL1_RO_LIMIT			(XG2RAM0_BASE + 0x18000)
+#define BL1_RW_BASE			(BL1_RO_LIMIT)	/* 0xf981_8000 */
+#define BL1_RW_SIZE			(0x00080000)
+#define BL1_RW_LIMIT			(0xF9898000)
+
+/*
+ * Non-Secure BL1U specific defines.
+ */
+#define NS_BL1U_BASE			(0xf9828000)
+#define NS_BL1U_SIZE			(0x00010000)
+#define NS_BL1U_LIMIT			(NS_BL1U_BASE + NS_BL1U_SIZE)
+
+/*
+ * BL2 specific defines.
+ *
+ * Both loader and BL2 region stay in SRAM.
+ * Loader is used to switch Hi6220 SoC from 32-bit to 64-bit mode.
+ *
+ * ++++++++++ 0xF980_0000
+ * + loader +
+ * ++++++++++ 0xF980_1000
+ * +  BL2   +
+ * ++++++++++ 0xF983_0000
+ */
+#define BL2_BASE			(BL1_RO_BASE)		/* 0xf980_1000 */
+#define BL2_LIMIT			(0xF9830000)		/* 0xf983_0000 */
+
+/*
+ * SCP_BL2 specific defines.
+ * In HiKey, SCP_BL2 means MCU firmware. It's loaded into the temporary buffer
+ * at 0x0100_0000. Then BL2 will parse the sections and loaded them into
+ * predefined separated buffers.
+ */
+#define SCP_BL2_BASE			(DDR_BASE + 0x01000000)
+#define SCP_BL2_LIMIT			(SCP_BL2_BASE + 0x00100000)
+#define SCP_BL2_SIZE			(SCP_BL2_LIMIT - SCP_BL2_BASE)
+
+/*
+ * BL31 specific defines.
+ */
+#define BL31_BASE			(0xF9858000)		/* 0xf985_8000 */
+#define BL31_LIMIT			(0xF9898000)
+
+/*
+ * BL3-2 specific defines.
+ */
+
+/*
+ * The TSP currently executes from TZC secured area of DRAM or SRAM.
+ */
+#define BL32_SRAM_BASE			BL31_LIMIT
+#define BL32_SRAM_LIMIT			(BL31_LIMIT+0x80000) /* 512K */
+
+#define BL32_DRAM_BASE			DDR_SEC_BASE
+#define BL32_DRAM_LIMIT			(DDR_SEC_BASE+DDR_SEC_SIZE)
+
+#ifdef SPD_opteed
+/* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */
+#define HIKEY_OPTEE_PAGEABLE_LOAD_BASE	(BL32_DRAM_LIMIT - HIKEY_OPTEE_PAGEABLE_LOAD_SIZE) /* 0x3FC0_0000 */
+#define HIKEY_OPTEE_PAGEABLE_LOAD_SIZE	0x400000 /* 4MB */
+#endif
+
+#if (HIKEY_TSP_RAM_LOCATION_ID == HIKEY_DRAM_ID)
+#define TSP_SEC_MEM_BASE		BL32_DRAM_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_DRAM_LIMIT - BL32_DRAM_BASE)
+#define BL32_BASE			BL32_DRAM_BASE
+#define BL32_LIMIT			BL32_DRAM_LIMIT
+#elif (HIKEY_TSP_RAM_LOCATION_ID == HIKEY_SRAM_ID)
+#define TSP_SEC_MEM_BASE		BL32_SRAM_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_SRAM_LIMIT - BL32_SRAM_BASE)
+#define BL32_BASE			BL32_SRAM_BASE
+#define BL32_LIMIT			BL32_SRAM_LIMIT
+#else
+#error "Currently unsupported HIKEY_TSP_LOCATION_ID value"
+#endif
+
+/* BL32 is mandatory in AArch32 */
+#ifdef __aarch64__
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+#endif
+
+#endif /* HIKEY_LAYOUT_H */
diff --git a/plat/hisilicon/hikey/include/hisi_ipc.h b/plat/hisilicon/hikey/include/hisi_ipc.h
new file mode 100644
index 0000000..b0c0ae8
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_ipc.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_IPC_H
+#define HISI_IPC_H
+
+#define HISI_IPC_CORE_ACPU		0x0
+
+#define HISI_IPC_MCU_INT_SRC_ACPU0_PD	10
+#define HISI_IPC_MCU_INT_SRC_ACPU1_PD	11
+#define HISI_IPC_MCU_INT_SRC_ACPU2_PD	12
+#define HISI_IPC_MCU_INT_SRC_ACPU3_PD	13
+#define HISI_IPC_MCU_INT_SRC_ACPU_PD	16
+#define HISI_IPC_MCU_INT_SRC_ACPU4_PD	26
+#define HISI_IPC_MCU_INT_SRC_ACPU5_PD	27
+#define HISI_IPC_MCU_INT_SRC_ACPU6_PD	28
+#define HISI_IPC_MCU_INT_SRC_ACPU7_PD	29
+
+#define HISI_IPC_SEM_CPUIDLE		27
+#define HISI_IPC_INT_SRC_NUM		32
+
+#define HISI_IPC_PM_ON			0
+#define HISI_IPC_PM_OFF			1
+
+#define HISI_IPC_OK			(0)
+#define HISI_IPC_ERROR			(-1)
+
+#define HISI_IPC_BASE_ADDR		(0xF7510000)
+#define HISI_IPC_CPU_RAW_INT_ADDR	(0xF7510420)
+#define HISI_IPC_ACPU_CTRL(i)		(0xF7510800 + (i << 3))
+
+void hisi_ipc_spin_lock(unsigned int signal);
+void hisi_ipc_spin_unlock(unsigned int signal);
+void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster);
+void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster);
+void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster);
+void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster);
+void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster);
+void hisi_ipc_cluster_suspend(unsigned int cpu, unsigned int cluster);
+void hisi_ipc_psci_system_off(void);
+int hisi_ipc_init(void);
+
+#endif /* HISI_IPC_H */
diff --git a/plat/hisilicon/hikey/include/hisi_mcu.h b/plat/hisilicon/hikey/include/hisi_mcu.h
new file mode 100644
index 0000000..731c51a
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_mcu.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_MCU_H
+#define HISI_MCU_H
+
+#include <stdint.h>
+
+extern void hisi_mcu_enable_sram(void);
+extern void hisi_mcu_start_run(void);
+extern int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size);
+
+#endif /* HISI_MCU_H */
diff --git a/plat/hisilicon/hikey/include/hisi_pwrc.h b/plat/hisilicon/hikey/include/hisi_pwrc.h
new file mode 100644
index 0000000..cbb4651
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_pwrc.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_PWRC_H
+#define HISI_PWRC_H
+
+#ifndef __ASSEMBLER__
+
+void hisi_pwrc_set_cluster_wfi(unsigned int id);
+void hisi_pwrc_set_core_bx_addr(unsigned int core,
+				unsigned int cluster,
+				uintptr_t entry_point);
+void hisi_pwrc_enable_debug(unsigned int core,
+			    unsigned int cluster);
+int hisi_pwrc_setup(void);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* HISI_PWRC_H */
diff --git a/plat/hisilicon/hikey/include/hisi_sip_svc.h b/plat/hisilicon/hikey/include/hisi_sip_svc.h
new file mode 100644
index 0000000..a1fad7a
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_sip_svc.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_SIP_SVC_H
+#define HISI_SIP_SVC_H
+
+/* SMC function IDs for SiP Service queries */
+
+#define HISI_SIP_SVC_CALL_COUNT		0x8200ff00
+#define HISI_SIP_SVC_UID			0x8200ff01
+/*					0x8200ff02 is reserved */
+#define HISI_SIP_SVC_VERSION			0x8200ff03
+
+/* HISI SiP Service Calls version numbers */
+#define HISI_SIP_SVC_VERSION_MAJOR		0x0
+#define HISI_SIP_SVC_VERSION_MINOR		0x1
+
+#endif /* HISI_SIP_SVC_H */
diff --git a/plat/hisilicon/hikey/include/hisi_sram_map.h b/plat/hisilicon/hikey/include/hisi_sram_map.h
new file mode 100644
index 0000000..f93e418
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_sram_map.h
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_SRAM_MAP_H
+#define HISI_SRAM_MAP_H
+
+/*
+ * SRAM Memory Region Layout
+ *
+ *  +-----------------------+
+ *  |  Low Power Mode       | 7KB
+ *  +-----------------------+
+ *  |  Secure OS            | 64KB
+ *  +-----------------------+
+ *  |  Software Flag        | 1KB
+ *  +-----------------------+
+ *
+ */
+
+#define SOC_SRAM_OFF_BASE_ADDR		(0xFFF80000)
+
+/* PM Section: 7KB */
+#define SRAM_PM_ADDR			(SOC_SRAM_OFF_BASE_ADDR)
+#define SRAM_PM_SIZE			(0x00001C00)
+
+/* TEE OS Section: 64KB */
+#define SRAM_TEEOS_ADDR			(SRAM_PM_ADDR + SRAM_PM_SIZE)
+#define SRAM_TEEOS_SIZE			(0x00010000)
+
+/* General Use Section: 1KB */
+#define SRAM_GENERAL_ADDR		(SRAM_TEEOS_ADDR + SRAM_TEEOS_SIZE)
+#define SRAM_GENERAL_SIZE		(0x00000400)
+
+/*
+ * General Usage Section Layout:
+ *
+ *  +-----------------------+
+ *  |  AP boot flag         | 64B
+ *  +-----------------------+
+ *  |  DICC flag            | 32B
+ *  +-----------------------+
+ *  |  Soft flag            | 256B
+ *  +-----------------------+
+ *  |  Thermal flag         | 128B
+ *  +-----------------------+
+ *  |  CSHELL               | 4B
+ *  +-----------------------+
+ *  |  Uart Switching       | 4B
+ *  +-----------------------+
+ *  |  ICC                  | 1024B
+ *  +-----------------------+
+ *  |  Memory Management    | 1024B
+ *  +-----------------------+
+ *  |  IFC                  | 32B
+ *  +-----------------------+
+ *  |  HIFI                 | 32B
+ *  +-----------------------+
+ *  |  DDR capacity         | 4B
+ *  +-----------------------+
+ *  |  Reserved             |
+ *  +-----------------------+
+ *
+ */
+
+/* App Core Boot Flags */
+#define MEMORY_AXI_ACPU_START_ADDR		(SRAM_GENERAL_ADDR)
+#define MEMORY_AXI_ACPU_START_SIZE		(64)
+
+#define MEMORY_AXI_SRESET_FLAG_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0000)
+#define MEMORY_AXI_SECOND_CPU_BOOT_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0004)
+#define MEMORY_AXI_READY_FLAG_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0008)
+#define MEMORY_AXI_FASTBOOT_ENTRY_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x000C)
+#define MEMORY_AXI_PD_CHARGE_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0010)
+#define MEMORY_AXI_DBG_ALARM_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0014)
+#define MEMORY_AXI_CHIP_ADDR			(MEMORY_AXI_ACPU_START_ADDR + 0x0018)
+#define MEMORY_AXI_BOARD_TYPE_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x001C)
+#define MEMORY_AXI_BOARD_ID_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0020)
+#define MEMORY_AXI_CHARGETYPE_FLAG_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0024)
+#define MEMORY_AXI_COLD_START_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0028)
+#define MEMORY_AXI_ANDROID_REBOOT_FLAG_ADDR	(MEMORY_AXI_ACPU_START_ADDR + 0x002C)
+#define MEMORY_AXI_ACPU_WDTRST_REBOOT_FLAG_ADDR	(MEMORY_AXI_ACPU_START_ADDR + 0x0030)
+#define MEMORY_AXI_ABNRST_BITMAP_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0034)
+#define MEMORY_AXI_32K_CLK_TYPE_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x0038)
+#define AXI_MODEM_PANIC_FLAG_ADDR		(MEMORY_AXI_ACPU_START_ADDR + 0x003C)
+#define AXI_MODEM_PANIC_FLAG			(0x68697369)
+#define MEMORY_AXI_ACPU_END_ADDR		(AXI_MODEM_PANIC_FLAG_ADDR + 4)
+
+/* DICC Flags */
+#define MEMORY_AXI_DICC_ADDR			(MEMORY_AXI_ACPU_START_ADDR + MEMORY_AXI_ACPU_START_SIZE)
+#define MEMORY_AXI_DICC_SIZE			(32)
+
+#define MEMORY_AXI_SOFT_FLAG_ADDR		(MEMORY_AXI_DICC_ADDR + MEMORY_AXI_DICC_SIZE)
+#define MEMORY_AXI_SOFT_FLAG_SIZE		(256)
+
+/* Thermal Flags */
+#define MEMORY_AXI_TEMP_PROTECT_ADDR		(MEMORY_AXI_SOFT_FLAG_ADDR + MEMORY_AXI_SOFT_FLAG_SIZE)
+#define MEMORY_AXI_TEMP_PROTECT_SIZE		(128)
+
+/* CSHELL */
+#define MEMORY_AXI_USB_CSHELL_ADDR		(MEMORY_AXI_TEMP_PROTECT_ADDR + MEMORY_AXI_TEMP_PROTECT_SIZE)
+#define MEMORY_AXI_USB_CSHELL_SIZE		(4)
+
+/* Uart and A/C Shell Switch Flags */
+#define MEMORY_AXI_UART_INOUT_ADDR		(MEMORY_AXI_USB_CSHELL_ADDR + MEMORY_AXI_USB_CSHELL_SIZE)
+#define MEMORY_AXI_UART_INOUT_SIZE		(4)
+
+/* IFC Flags */
+#define MEMORY_AXI_IFC_ADDR			(MEMORY_AXI_UART_INOUT_ADDR + MEMORY_AXI_UART_INOUT_SIZE)
+#define MEMORY_AXI_IFC_SIZE			(32)
+
+/* HIFI Data */
+#define MEMORY_AXI_HIFI_ADDR			(MEMORY_AXI_IFC_ADDR + MEMORY_AXI_IFC_SIZE)
+#define MEMORY_AXI_HIFI_SIZE			(32)
+
+/* CONFIG Flags */
+#define MEMORY_AXI_CONFIG_ADDR			(MEMORY_AXI_HIFI_ADDR + MEMORY_AXI_HIFI_SIZE)
+#define MEMORY_AXI_CONFIG_SIZE			(32)
+
+/* DDR Capacity Flags */
+#define MEMORY_AXI_DDR_CAPACITY_ADDR		(MEMORY_AXI_CONFIG_ADDR + MEMORY_AXI_CONFIG_SIZE)
+#define MEMORY_AXI_DDR_CAPACITY_SIZE		(4)
+
+/* USB Shell Flags */
+#define MEMORY_AXI_USB_SHELL_FLAG_ADDR		(MEMORY_AXI_DDR_CAPACITY_ADDR + MEMORY_AXI_DDR_CAPACITY_SIZE)
+#define MEMORY_AXI_USB_SHELL_FLAG_SIZE		(4)
+
+/* MCU WDT Switch Flag */
+#define MEMORY_AXI_MCU_WDT_FLAG_ADDR		(MEMORY_AXI_USB_SHELL_FLAG_ADDR + MEMORY_AXI_USB_SHELL_FLAG_SIZE)
+#define MEMORY_AXI_MCU_WDT_FLAG_SIZE		(4)
+
+/* TLDSP Mailbox MNTN */
+#define SRAM_DSP_MNTN_INFO_ADDR			(MEMORY_AXI_MCU_WDT_FLAG_ADDR + MEMORY_AXI_MCU_WDT_FLAG_SIZE)
+#define SRAM_DSP_MNTN_SIZE			(32)
+
+/* TLDSP ARM Mailbox Protect Flag */
+#define SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_ADDR	(SRAM_DSP_MNTN_INFO_ADDR + SRAM_DSP_MNTN_SIZE)
+#define SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_SIZE	(4)
+
+/* RTT Sleep Flag */
+#define SRAM_RTT_SLEEP_FLAG_ADDR                (SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_ADDR + SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_SIZE)
+#define SRAM_RTT_SLEEP_FLAG_SIZE                (32)
+
+/* LDSP Awake Flag */
+#define MEMORY_AXI_LDSP_AWAKE_ADDR              (SRAM_RTT_SLEEP_FLAG_ADDR + SRAM_RTT_SLEEP_FLAG_SIZE)
+#define MEMORY_AXI_LDSP_AWAKE_SIZE              (4)
+
+#define NVUPDATE_SUCCESS			0x5555AAAA
+#define NVUPDATE_FAILURE			0xAAAA5555
+
+/*
+ * Low Power Mode Region
+ */
+#define PWRCTRL_ACPU_ASM_SPACE_ADDR		(SRAM_PM_ADDR)
+#define PWRCTRL_ACPU_ASM_SPACE_SIZE		(SRAM_PM_SIZE)
+
+#define PWRCTRL_ACPU_ASM_MEM_BASE		(PWRCTRL_ACPU_ASM_SPACE_ADDR)
+#define PWRCTRL_ACPU_ASM_MEM_SIZE		(PWRCTRL_ACPU_ASM_SPACE_SIZE)
+#define PWRCTRL_ACPU_ASM_CODE_BASE		(PWRCTRL_ACPU_ASM_MEM_BASE + 0x200)
+#define PWRCTRL_ACPU_ASM_DATA_BASE		(PWRCTRL_ACPU_ASM_MEM_BASE + 0xE00)
+#define PWRCTRL_ACPU_ASM_DATA_SIZE		(0xE00)
+
+#define PWRCTRL_ACPU_ASM_D_C0_ADDR		(PWRCTRL_ACPU_ASM_DATA_BASE)
+#define PWRCTRL_ACPU_ASM_D_C0_MMU_PARA_AD	(PWRCTRL_ACPU_ASM_DATA_BASE + 0)
+#define PWRCTRL_ACPU_ASM_D_ARM_PARA_AD		(PWRCTRL_ACPU_ASM_DATA_BASE + 0x20)
+
+#define PWRCTRL_ACPU_ASM_D_COMM_ADDR		(PWRCTRL_ACPU_ASM_DATA_BASE + 0x700)
+
+#define PWRCTRL_ACPU_REBOOT			(PWRCTRL_ACPU_ASM_D_COMM_ADDR)
+#define PWRCTRL_ACPU_REBOOT_SIZE		(0x200)
+#define PWRCTRL_ACPU_ASM_SLICE_BAK_ADDR		(PWRCTRL_ACPU_REBOOT + PWRCTRL_ACPU_REBOOT_SIZE)
+#define PWRCTRL_ACPU_ASM_SLICE_BAK_SIZE		(4)
+#define PWRCTRL_ACPU_ASM_DEBUG_FLAG_ADDR	(PWRCTRL_ACPU_ASM_SLICE_BAK_ADDR + PWRCTRL_ACPU_ASM_SLICE_BAK_SIZE)
+#define PWRCTRL_ACPU_ASM_DEBUG_FLAG_SIZE	(4)
+#define EXCH_A_CORE_POWRCTRL_CONV_ADDR		(PWRCTRL_ACPU_ASM_DEBUG_FLAG_ADDR + PWRCTRL_ACPU_ASM_DEBUG_FLAG_SIZE)
+#define EXCH_A_CORE_POWRCTRL_CONV_SIZE		(4)
+
+/*
+ * Below region memory mapping is:
+ * 4 + 12 + 16 + 28 + 28 + 16 + 28 + 12 + 24 + 20 + 64 +
+ * 4 + 4 + 4 + 4 + 12 + 4 + 4 + 4 + 4 + 16 + 4 + 0x2BC +
+ * 24 + 20 + 12 + 16
+ */
+
+#define MEMORY_AXI_CPU_IDLE_ADDR		(EXCH_A_CORE_POWRCTRL_CONV_ADDR + EXCH_A_CORE_POWRCTRL_CONV_SIZE)
+#define MEMORY_AXI_CPU_IDLE_SIZE		(4)
+
+#define MEMORY_AXI_CUR_FREQ_ADDR		(MEMORY_AXI_CPU_IDLE_ADDR + MEMORY_AXI_CPU_IDLE_SIZE)
+#define MEMORY_AXI_CUR_FREQ_SIZE		(12)
+
+#define MEMORY_AXI_ACPU_FREQ_VOL_ADDR		(MEMORY_AXI_CUR_FREQ_ADDR + MEMORY_AXI_CUR_FREQ_SIZE)
+#define MEMORY_AXI_ACPU_FREQ_VOL_SIZE		(16 + 28 + 28)
+
+#define MEMORY_AXI_DDR_FREQ_VOL_ADDR		(MEMORY_AXI_ACPU_FREQ_VOL_ADDR + MEMORY_AXI_ACPU_FREQ_VOL_SIZE)
+#define MEMORY_AXI_DDR_FREQ_VOL_SIZE		(16 + 28)
+
+#define MEMORY_AXI_ACPU_FIQ_TEST_ADDR		(MEMORY_AXI_DDR_FREQ_VOL_ADDR + MEMORY_AXI_DDR_FREQ_VOL_SIZE)
+#define MEMORY_AXI_ACPU_FIQ_TEST_SIZE		(12)
+
+#define MEMORY_AXI_ACPU_FIQ_CPU_INFO_ADDR	(MEMORY_AXI_ACPU_FIQ_TEST_ADDR + MEMORY_AXI_ACPU_FIQ_TEST_SIZE)
+#define MEMORY_AXI_ACPU_FIQ_CPU_INFO_SIZE	(24)
+
+#define MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_ADDR	(MEMORY_AXI_ACPU_FIQ_CPU_INFO_ADDR + MEMORY_AXI_ACPU_FIQ_CPU_INFO_SIZE)
+#define MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_SIZE	(20)
+
+#define MEMORY_FREQDUMP_ADDR			(MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_ADDR + MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_SIZE)
+#define MEMORY_FREQDUMP_SIZE			(64)
+
+#define MEMORY_AXI_CCPU_LOG_ADDR		(MEMORY_FREQDUMP_ADDR + MEMORY_FREQDUMP_SIZE)
+#define MEMORY_AXI_CCPU_LOG_SIZE		(4)
+
+#define MEMORY_AXI_MCU_LOG_ADDR			(MEMORY_AXI_CCPU_LOG_ADDR + MEMORY_AXI_CCPU_LOG_SIZE)
+#define MEMORY_AXI_MCU_LOG_SIZE			(4)
+
+#define MEMORY_AXI_SEC_CORE_BOOT_ADDR		(MEMORY_AXI_MCU_LOG_ADDR + MEMORY_AXI_MCU_LOG_SIZE)
+#define MEMORY_AXI_SEC_CORE_BOOT_SIZE		(4)
+
+#define MEMORY_AXI_BBP_PS_VOTE_FLAG_ADDR	(MEMORY_AXI_SEC_CORE_BOOT_ADDR + MEMORY_AXI_SEC_CORE_BOOT_SIZE)
+#define MEMORY_AXI_BBP_PS_VOTE_FLAG_SIZE	(0x4)
+
+#define POLICY_AREA_RESERVED			(MEMORY_AXI_BBP_PS_VOTE_FLAG_ADDR + MEMORY_AXI_BBP_PS_VOTE_FLAG_SIZE)
+#define POLICY_AREA_RESERVED_SIZE		(12)
+
+#define DDR_POLICY_VALID_MAGIC			(POLICY_AREA_RESERVED + POLICY_AREA_RESERVED_SIZE)
+#define DDR_POLICY_VALID_MAGIC_SIZE		(4)
+
+#define DDR_POLICY_MAX_NUM			(DDR_POLICY_VALID_MAGIC + DDR_POLICY_VALID_MAGIC_SIZE)
+#define DDR_POLICY_MAX_NUM_SIZE			(4)
+
+#define DDR_POLICY_SUPPORT_NUM			(DDR_POLICY_MAX_NUM + DDR_POLICY_MAX_NUM_SIZE)
+#define DDR_POLICY_SUPPORT_NUM_SIZE		(4)
+
+#define DDR_POLICY_CUR_POLICY			(DDR_POLICY_SUPPORT_NUM + DDR_POLICY_SUPPORT_NUM_SIZE)
+#define DDR_POLICY_CUR_POLICY_SIZE		(4)
+
+#define ACPU_POLICY_VALID_MAGIC			(DDR_POLICY_CUR_POLICY + DDR_POLICY_CUR_POLICY_SIZE)
+#define ACPU_POLICY_VALID_MAGIC_SIZE		(4)
+
+#define ACPU_POLICY_MAX_NUM			(ACPU_POLICY_VALID_MAGIC + ACPU_POLICY_VALID_MAGIC_SIZE)
+#define ACPU_POLICY_MAX_NUM_SIZE		(4)
+
+#define ACPU_POLICY_SUPPORT_NUM			(ACPU_POLICY_MAX_NUM + ACPU_POLICY_MAX_NUM_SIZE)
+#define ACPU_POLICY_SUPPORT_NUM_SIZE		(4)
+
+#define ACPU_POLICY_CUR_POLICY			(ACPU_POLICY_SUPPORT_NUM + ACPU_POLICY_SUPPORT_NUM_SIZE)
+#define ACPU_POLICY_CUR_POLICY_SIZE		(4)
+
+#define LPDDR_OPTION_ADDR			(ACPU_POLICY_CUR_POLICY + ACPU_POLICY_CUR_POLICY_SIZE)
+#define LPDDR_OPTION_SIZE			(4)
+
+#define MEMORY_AXI_DDR_DDL_ADDR			(LPDDR_OPTION_ADDR + LPDDR_OPTION_SIZE)
+#define MEMORY_AXI_DDR_DDL_SIZE			(0x2BC)
+
+#define DDR_TEST_DFS_ADDR			(MEMORY_AXI_DDR_DDL_ADDR + MEMORY_AXI_DDR_DDL_SIZE)
+#define DDR_TEST_DFS_ADDR_SIZE			(4)
+
+#define DDR_TEST_DFS_TIMES_ADDR			(DDR_TEST_DFS_ADDR + DDR_TEST_DFS_ADDR_SIZE)
+#define DDR_TEST_DFS_TIMES_ADDR_SIZE		(4)
+
+#define DDR_TEST_QOS_ADDR			(DDR_TEST_DFS_TIMES_ADDR + DDR_TEST_DFS_TIMES_ADDR_SIZE)
+#define DDR_TEST_QOS_ADDR_SIZE			(4)
+
+#define DDR_TEST_FUN_ADDR			(DDR_TEST_QOS_ADDR + DDR_TEST_QOS_ADDR_SIZE)
+#define DDR_TEST_FUN_ADDR_SIZE			(4)
+
+#define BOARD_TYPE_ADDR				(DDR_TEST_FUN_ADDR + DDR_TEST_FUN_ADDR_SIZE)
+#define BOARD_ADDR_SIZE				(4)
+#define DDR_DFS_FREQ_ADDR			(BOARD_TYPE_ADDR + BOARD_ADDR_SIZE)
+#define DDR_DFS_FREQ_SIZE			(4)
+
+#define DDR_PASR_ADDR				(DDR_DFS_FREQ_ADDR + DDR_DFS_FREQ_SIZE)
+#define DDR_PASR_SIZE				(20)
+
+#define ACPU_DFS_FREQ_ADDR			(DDR_PASR_ADDR + DDR_PASR_SIZE)
+#define ACPU_DFS_FREQ_ADDR_SIZE			(12)
+
+#define ACPU_CHIP_MAX_FREQ			(ACPU_DFS_FREQ_ADDR + ACPU_DFS_FREQ_ADDR_SIZE)
+#define ACPU_CHIP_MAX_FREQ_SIZE			(4)
+
+#define MEMORY_MEDPLL_STATE_ADDR		(ACPU_CHIP_MAX_FREQ + ACPU_CHIP_MAX_FREQ_SIZE)
+#define MEMORY_MEDPLL_STATE_SIZE		(8)
+
+#define MEMORY_CCPU_LOAD_FLAG_ADDR		(MEMORY_MEDPLL_STATE_ADDR + MEMORY_MEDPLL_STATE_SIZE)
+#define MEMORY_CCPU_LOAD_FLAG_SIZE		(4)
+
+
+#define ACPU_CORE_BITS_ADDR			(MEMORY_CCPU_LOAD_FLAG_ADDR + MEMORY_CCPU_LOAD_FLAG_SIZE)
+#define ACPU_CORE_BITS_SIZE			(4)
+
+#define ACPU_CLUSTER_IDLE_ADDR			(ACPU_CORE_BITS_ADDR + ACPU_CORE_BITS_SIZE)
+#define ACPU_CLUSTER_IDLE_SIZE			(4)
+
+#define ACPU_A53_FLAGS_ADDR			(ACPU_CLUSTER_IDLE_ADDR + ACPU_CLUSTER_IDLE_SIZE)
+#define ACPU_A53_FLAGS_SIZE			(4)
+
+#define ACPU_POWER_STATE_QOS_ADDR		(ACPU_A53_FLAGS_ADDR+ACPU_A53_FLAGS_SIZE)
+#define ACPU_POWER_STATE_QOS_SIZE		(4)
+
+#define ACPU_UNLOCK_CORE_FLAGS_ADDR		(ACPU_POWER_STATE_QOS_ADDR+ACPU_POWER_STATE_QOS_SIZE)
+#define ACPU_UNLOCK_CORE_FLAGS_SIZE		(8)
+
+#define ACPU_SUBSYS_POWERDOWN_FLAGS_ADDR	(ACPU_UNLOCK_CORE_FLAGS_ADDR + ACPU_UNLOCK_CORE_FLAGS_SIZE)
+#define ACPU_SUBSYS_POWERDOWN_FLAGS_SIZE	(4)
+
+#define ACPU_CORE_POWERDOWN_FLAGS_ADDR		(ACPU_SUBSYS_POWERDOWN_FLAGS_ADDR + ACPU_SUBSYS_POWERDOWN_FLAGS_SIZE)
+#define ACPU_CORE_POWERDOWN_FLAGS_SIZE		(4)
+
+#define ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR	(ACPU_CORE_POWERDOWN_FLAGS_ADDR + ACPU_CORE_POWERDOWN_FLAGS_SIZE)
+#define ACPU_CLUSTER_POWERDOWN_FLAGS_SIZE	(4)
+
+#define ACPU_ARM64_FLAGA			(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR + ACPU_CLUSTER_POWERDOWN_FLAGS_SIZE)
+#define ACPU_ARM64_FLAGA_SIZE			(4)
+
+#define ACPU_ARM64_FLAGB			(ACPU_ARM64_FLAGA + ACPU_ARM64_FLAGA_SIZE)
+#define ACPU_ARM64_FLAGB_SIZE			(4)
+
+#define MCU_EXCEPTION_FLAGS_ADDR		(ACPU_ARM64_FLAGB + ACPU_ARM64_FLAGB_SIZE)
+#define MCU_EXCEPTION_FLAGS_SIZE		(4)
+
+#define ACPU_MASTER_CORE_STATE_ADDR		(MCU_EXCEPTION_FLAGS_ADDR + MCU_EXCEPTION_FLAGS_SIZE)
+#define ACPU_MASTER_CORE_STATE_SIZE		(4)
+
+#define PWRCTRL_AXI_RESERVED_ADDR		(ACPU_MASTER_CORE_STATE_ADDR + ACPU_MASTER_CORE_STATE_SIZE)
+
+#endif /* HISI_SRAM_MAP_H */
diff --git a/plat/hisilicon/hikey/include/plat_macros.S b/plat/hisilicon/hikey/include/plat_macros.S
new file mode 100644
index 0000000..9cd276a
--- /dev/null
+++ b/plat/hisilicon/hikey/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <hi6220.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+	mov_imm	x16, PLAT_ARM_GICD_BASE
+	mov_imm	x17, PLAT_ARM_GICC_BASE
+
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to cosole */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+2:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	1f
+	bl	asm_print_hex
+	adr	x4, spacer
+	bl	asm_print_str
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+	adr	x4, newline
+	bl	asm_print_str
+	b	2b
+1:
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (CCI400_BASE + SLAVE_IFACE_OFFSET(	\
+			CCI400_SL_IFACE3_CLUSTER_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (CCI400_BASE + SLAVE_IFACE_OFFSET(	\
+			CCI400_SL_IFACE4_CLUSTER_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/hisilicon/hikey/include/platform_def.h b/plat/hisilicon/hikey/include/platform_def.h
new file mode 100644
index 0000000..2537ac6
--- /dev/null
+++ b/plat/hisilicon/hikey/include/platform_def.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <hikey_def.h>
+#include <hikey_layout.h>		/* BL memory region sizes, etc */
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define HIKEY_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+/*
+ * Generic platform constants
+ */
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE		0x1000
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_CACHE_LINE_SIZE	64
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CORE_COUNT_PER_CLUSTER	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT *	\
+					 PLATFORM_CORE_COUNT_PER_CLUSTER)
+#define PLAT_MAX_PWR_LVL		(MPIDR_AFFLVL2)
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + 1)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+/* eMMC RPMB and eMMC User Data */
+#define MAX_IO_BLOCK_DEVICES		U(2)
+
+/* GIC related constants (no GICR in GIC-400) */
+#define PLAT_ARM_GICD_BASE		0xF6801000
+#define PLAT_ARM_GICC_BASE		0xF6802000
+#define PLAT_ARM_GICH_BASE		0xF6804000
+#define PLAT_ARM_GICV_BASE		0xF6806000
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+
+#if defined(IMAGE_BL1) || defined(IMAGE_BL32)
+#define MAX_XLAT_TABLES			3
+#endif
+
+#ifdef IMAGE_BL31
+#define MAX_XLAT_TABLES			4
+#endif
+
+#ifdef IMAGE_BL2
+#define MAX_XLAT_TABLES			4
+#endif
+
+#define MAX_MMAP_REGIONS		16
+
+/*
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ */
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/hisilicon/hikey/platform.mk b/plat/hisilicon/hikey/platform.mk
new file mode 100644
index 0000000..7fd897c
--- /dev/null
+++ b/plat/hisilicon/hikey/platform.mk
@@ -0,0 +1,164 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Non-TF Boot ROM
+BL2_AT_EL3	:=	1
+
+# On Hikey, the TSP can execute from TZC secure area in DRAM (default)
+# or SRAM.
+HIKEY_TSP_RAM_LOCATION	?=	dram
+ifeq (${HIKEY_TSP_RAM_LOCATION}, dram)
+  HIKEY_TSP_RAM_LOCATION_ID = HIKEY_DRAM_ID
+else ifeq (${HIKEY_TSP_RAM_LOCATION}, sram)
+  HIKEY_TSP_RAM_LOCATION_ID = HIKEY_SRAM_ID
+else
+  $(error "Currently unsupported HIKEY_TSP_RAM_LOCATION value")
+endif
+
+CONSOLE_BASE			:=	PL011_UART3_BASE
+CRASH_CONSOLE_BASE		:=	PL011_UART3_BASE
+PLAT_PARTITION_MAX_ENTRIES	:=	12
+PLAT_PL061_MAX_GPIOS		:=	160
+COLD_BOOT_SINGLE_CPU		:=	1
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+ENABLE_SVE_FOR_NS		:=	0
+
+# Process flags
+$(eval $(call add_define,HIKEY_TSP_RAM_LOCATION_ID))
+$(eval $(call add_define,CONSOLE_BASE))
+$(eval $(call add_define,CRASH_CONSOLE_BASE))
+$(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
+$(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES))
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
+endif
+
+USE_COHERENT_MEM	:=	1
+
+PLAT_INCLUDES		:=	-Iplat/hisilicon/hikey/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/arm/pl011/aarch64/pl011_console.S \
+				lib/xlat_tables/aarch64/xlat_tables.c	\
+				lib/xlat_tables/xlat_tables_common.c	\
+				plat/hisilicon/hikey/aarch64/hikey_common.c
+
+BL1_SOURCES		+=	bl1/tbbr/tbbr_img_desc.c		\
+				drivers/arm/pl061/pl061_gpio.c		\
+				drivers/arm/sp804/sp804_delay_timer.c	\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/gpio/gpio.c			\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/mmc/mmc.c			\
+				drivers/synopsys/emmc/dw_mmc.c		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/hisilicon/hikey/aarch64/hikey_helpers.S \
+				plat/hisilicon/hikey/hikey_bl1_setup.c	\
+				plat/hisilicon/hikey/hikey_bl_common.c	\
+				plat/hisilicon/hikey/hikey_io_storage.c
+
+BL2_SOURCES		+=	common/desc_image_load.c		\
+				drivers/arm/pl061/pl061_gpio.c		\
+				drivers/arm/sp804/sp804_delay_timer.c	\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/gpio/gpio.c			\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/mmc/mmc.c			\
+				drivers/synopsys/emmc/dw_mmc.c		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/hisilicon/hikey/aarch64/hikey_helpers.S \
+				plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c \
+				plat/hisilicon/hikey/hikey_bl2_setup.c	\
+				plat/hisilicon/hikey/hikey_bl_common.c	\
+				plat/hisilicon/hikey/hikey_security.c   \
+				plat/hisilicon/hikey/hikey_ddr.c	\
+				plat/hisilicon/hikey/hikey_image_load.c \
+				plat/hisilicon/hikey/hikey_io_storage.c	\
+				plat/hisilicon/hikey/hisi_dvfs.c	\
+				plat/hisilicon/hikey/hisi_mcu.c
+
+ifeq (${SPD},opteed)
+BL2_SOURCES		+=	lib/optee/optee_utils.c
+endif
+
+HIKEY_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				drivers/arm/sp804/sp804_delay_timer.c	\
+				drivers/delay_timer/delay_timer.c	\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/plat_psci_common.c	\
+				plat/hisilicon/hikey/aarch64/hikey_helpers.S \
+				plat/hisilicon/hikey/hikey_bl31_setup.c	\
+				plat/hisilicon/hikey/hikey_pm.c		\
+				plat/hisilicon/hikey/hikey_topology.c	\
+				plat/hisilicon/hikey/hisi_ipc.c		\
+				plat/hisilicon/hikey/hisi_pwrc.c	\
+				plat/hisilicon/hikey/hisi_pwrc_sram.S	\
+				${HIKEY_GIC_SOURCES}
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES		+=	plat/hisilicon/hikey/hisi_sip_svc.c			\
+				lib/pmf/pmf_smc.c
+endif
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+AUTH_SOURCES		:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c
+
+BL1_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/hisilicon/hikey/hikey_tbbr.c	\
+				plat/hisilicon/hikey/hikey_rotpk.S
+
+BL2_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/hisilicon/hikey/hikey_tbbr.c	\
+				plat/hisilicon/hikey/hikey_rotpk.S
+
+ROT_KEY		=	$(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH		=	$(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl1/hikey_rotpk.o: $(ROTPK_HASH)
+$(BUILD_PLAT)/bl2/hikey_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+# Enable workarounds for selected Cortex-A53 errata.
+ERRATA_A53_836870		:=	1
+ERRATA_A53_843419		:=	1
+ERRATA_A53_855873		:=	1
+
+WORKAROUND_CVE_2017_5715	:=	0
+
+FIP_ALIGN			:=	512
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
new file mode 100644
index 0000000..612a7f2
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include "../hikey960_def.h"
+#include "../hikey960_private.h"
+
+#define MAP_DDR		MAP_REGION_FLAT(DDR_BASE,			\
+					DDR_SIZE - DDR_SEC_SIZE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_DEVICE	MAP_REGION_FLAT(DEVICE_BASE,			\
+					DEVICE_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_BL1_RW	MAP_REGION_FLAT(BL1_RW_BASE,			\
+					BL1_RW_LIMIT - BL1_RW_BASE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DATA	MAP_REGION_FLAT(HIKEY960_UFS_DATA_BASE,		\
+					HIKEY960_UFS_DATA_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DESC	MAP_REGION_FLAT(HIKEY960_UFS_DESC_BASE,		\
+					HIKEY960_UFS_DESC_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_TSP_MEM	MAP_REGION_FLAT(TSP_SEC_MEM_BASE,		\
+					TSP_SEC_MEM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+/*
+ * Table of regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
+ * hikey960_init_mmu_elx() will give the available subset of that,
+ */
+#ifdef IMAGE_BL1
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_UFS_DATA,
+	MAP_BL1_RW,
+	MAP_UFS_DESC,
+	MAP_DEVICE,
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL2
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DDR,
+	MAP_DEVICE,
+	MAP_TSP_MEM,
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL31
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DEVICE,
+	MAP_TSP_MEM,
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL32
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DEVICE,
+	MAP_DDR,
+	{0}
+};
+#endif
+
+/*
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ */
+#define HIKEY960_CONFIGURE_MMU_EL(_el)					\
+	void hikey960_init_mmu_el##_el(unsigned long total_base,	\
+				unsigned long total_size,		\
+				unsigned long ro_start,			\
+				unsigned long ro_limit,			\
+				unsigned long coh_start,		\
+				unsigned long coh_limit)		\
+	{								\
+	       mmap_add_region(total_base, total_base,			\
+			       total_size,				\
+			       MT_MEMORY | MT_RW | MT_SECURE);		\
+	       mmap_add_region(ro_start, ro_start,			\
+			       ro_limit - ro_start,			\
+			       MT_MEMORY | MT_RO | MT_SECURE);		\
+	       mmap_add_region(coh_start, coh_start,			\
+			       coh_limit - coh_start,			\
+			       MT_DEVICE | MT_RW | MT_SECURE);		\
+	       mmap_add(hikey960_mmap);					\
+	       init_xlat_tables();					\
+									\
+	       enable_mmu_el##_el(0);					\
+	}
+
+/* Define EL1 and EL3 variants of the function initialising the MMU */
+HIKEY960_CONFIGURE_MMU_EL(1)
+HIKEY960_CONFIGURE_MMU_EL(3)
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+	return NS_BL1U_BASE;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 1920000;
+}
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
new file mode 100644
index 0000000..606f2d0
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <cortex_a73.h>
+#include "../hikey960_def.h"
+
+	.globl	plat_my_core_pos
+	.globl	platform_mem_init
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	plat_report_exception
+	.globl	plat_reset_handler
+	.globl	clr_ex
+	.globl	nop
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void platform_mem_init(void);
+	 *
+	 * We don't need to carry out any memory initialization
+	 * on HIKEY. The Secure RAM is accessible straight away.
+	 * -----------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	mov_imm	x1, PL011_UART_CLK_IN_HZ
+	mov_imm	x2, PL011_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, CRASH_CONSOLE_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * On HIKEY platform, it updates the LEDs
+	 * to indicate where we are
+	 * ---------------------------------------------
+	 */
+func plat_report_exception
+	mov	x8, x30
+
+	/* Turn on LED according to x0 (0 -- f) */
+	ldr	x2, =0xf7020000
+	and	x1, x0, #1
+	str	w1, [x2, #4]
+	and	x1, x0, #2
+	str	w1, [x2, #8]
+	and	x1, x0, #4
+	str	w1, [x2, #16]
+	and	x1, x0, #8
+	str	w1, [x2, #32]
+
+	mrs	x2, currentel
+	and	x2, x2, #0x0c
+	/* Check EL1 */
+	cmp	x2, #0x04
+	beq	plat_report_el1
+
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el3
+	bl	asm_print_hex
+
+	adr	x4, elr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el3
+	bl	asm_print_hex
+	b	plat_report_end
+
+plat_report_el1:
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el1
+	bl	asm_print_hex
+
+	adr	x4, elr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el1
+	bl	asm_print_hex
+plat_report_end:
+	mov	x30, x8
+	ret
+endfunc plat_report_exception
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * void clrex(void);
+	 * -----------------------------------------------------
+	 */
+func clr_ex
+	clrex
+	ret
+endfunc clr_ex
+
+	/* -----------------------------------------------------
+	 * void nop(void);
+	 * -----------------------------------------------------
+	 */
+func nop
+	nop
+	ret
+endfunc nop
+
+.section .rodata.rev_err_str, "aS"
+plat_err_str:
+	.asciz "\nPlatform exception reporting:"
+esr_el3_str:
+	.asciz "\nESR_EL3: "
+elr_el3_str:
+	.asciz "\nELR_EL3: "
+esr_el1_str:
+	.asciz "\nESR_EL1: "
+elr_el1_str:
+	.asciz "\nELR_EL1: "
diff --git a/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
new file mode 100644
index 0000000..a6a4949
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi3660.h>
+#include <hisi_ipc.h>
+#include "../../hikey960_private.h"
+
+#define IPC_MBX_SOURCE_REG(m)		(IPC_BASE + ((m) << 6))
+#define IPC_MBX_DSET_REG(m)		(IPC_BASE + ((m) << 6) + 0x04)
+#define IPC_MBX_DCLEAR_REG(m)		(IPC_BASE + ((m) << 6) + 0x08)
+#define IPC_MBX_DSTATUS_REG(m)		(IPC_BASE + ((m) << 6) + 0x0C)
+#define IPC_MBX_MODE_REG(m)		(IPC_BASE + ((m) << 6) + 0x10)
+#define IPC_MBX_IMASK_REG(m)		(IPC_BASE + ((m) << 6) + 0x14)
+#define IPC_MBX_ICLR_REG(m)		(IPC_BASE + ((m) << 6) + 0x18)
+#define IPC_MBX_SEND_REG(m)		(IPC_BASE + ((m) << 6) + 0x1C)
+#define IPC_MBX_DATA_REG(m, d)		(IPC_BASE + ((m) << 6) + 0x20 + \
+					 ((d) * 4))
+#define IPC_CPU_IMST_REG(m)		(IPC_BASE + ((m) << 3))
+#define IPC_LOCK_REG			(IPC_BASE + 0xA00)
+#define IPC_ACK_BIT_SHIFT		(1 << 7)
+#define IPC_UNLOCK_VALUE		(0x1ACCE551)
+
+/*********************************************************
+ *bit[31:24]:0~AP
+ *bit[23:16]:0x1~A15, 0x2~A7
+ *bit[15:8]:0~ON, 1~OFF
+ *bit[7:0]:0x3 cpu power mode
+ *********************************************************/
+#define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
+	((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
+
+/*********************************************************
+ *bit[15:8]:0~no idle, 1~idle
+ *bit[7:0]:cpux
+ *********************************************************/
+
+#define IPC_CMD_PARA(is_idle, cpu) \
+	((is_idle << 8) | (cpu))
+
+#define IPC_STATE_IDLE			0x10
+
+enum src_id {
+	SRC_IDLE = 0,
+	SRC_A15 = 1 << 0,
+	SRC_A7 = 1 << 1,
+	SRC_IOM3 = 1 << 2,
+	SRC_LPM3 = 1 << 3
+};
+
+/*lpm3's mailboxs are 13~17*/
+enum lpm3_mbox_id {
+	LPM3_MBX0 = 13,
+	LPM3_MBX1,
+	LPM3_MBX2,
+	LPM3_MBX3,
+	LPM3_MBX4,
+};
+
+static void cpu_relax(void)
+{
+	volatile int i;
+
+	for (i = 0; i < 10; i++)
+		nop();
+}
+
+static inline void
+hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
+{
+	unsigned int int_status = 0;
+
+	do {
+		int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
+		int_status &= 0xF0;
+		cpu_relax();
+	} while (int_status != IPC_ACK_BIT_SHIFT);
+
+	mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
+}
+
+static void
+hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
+			   unsigned int cmdtype, unsigned int cmdpara)
+{
+	unsigned int regval;
+	unsigned int mask;
+	unsigned int state;
+
+	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
+	/* wait for idle and occupy */
+	do {
+		state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
+		if (state == IPC_STATE_IDLE) {
+			mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
+			regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
+			if (regval == source)
+				break;
+		}
+		cpu_relax();
+
+	} while (1);
+
+	/* auto answer */
+	mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
+
+	mask = (~((int)source | SRC_LPM3) & 0x3F);
+	/* mask the other cpus */
+	mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
+	/* set data */
+	mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
+	mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
+	/* send cmd */
+	mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
+	/* wait ack and clear */
+	hisi_ipc_clear_ack(source, mbox);
+
+	/* release mailbox */
+	mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
+}
+
+void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
+			enum pm_mode mode)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
+	cmdpara = IPC_CMD_PARA(0, core);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
+			 unsigned int affinity_level)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	if (affinity_level == 0x3)
+		cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
+	else
+		cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
+
+	cmdpara = IPC_CMD_PARA(1, core);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
+	cmdpara = IPC_CMD_PARA(0, 0);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
+				unsigned int cmd_id)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
+	cmdpara = cmd_id;
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+int hisi_ipc_init(void)
+{
+	int ret = 0;
+	enum lpm3_mbox_id  i = LPM3_MBX0;
+
+	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
+	for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
+		mmio_write_32(IPC_MBX_MODE_REG(i), 1);
+		mmio_write_32(IPC_MBX_IMASK_REG(i),
+			      ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
+		mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
+	}
+
+	return ret;
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
new file mode 100644
index 0000000..91d8033
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <../hikey960_def.h>
+#include <hisi_ipc.h>
+#include "hisi_pwrc.h"
+
+
+/* resource lock api */
+#define RES0_LOCK_BASE		(SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE))
+#define RES1_LOCK_BASE		(SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE))
+#define RES2_LOCK_BASE		(SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE))
+
+#define LOCK_BIT			(0x1 << 28)
+#define LOCK_ID_MASK			(0x7u << 29)
+#define CPUIDLE_LOCK_ID(core)		(0x6 - (core))
+#define LOCK_UNLOCK_OFFSET		0x4
+#define LOCK_STAT_OFFSET		0x8
+
+#define CLUSTER0_CPUS_ONLINE_MASK	(0xF << 16)
+#define	CLUSTER1_CPUS_ONLINE_MASK	(0xF << 20)
+
+/* cpu hotplug flag api */
+#define SCTRL_BASE			(SOC_ACPU_SCTRL_BASE_ADDR)
+#define REG_SCBAKDATA3_OFFSET		(SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE))
+#define REG_SCBAKDATA8_OFFSET		(SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE))
+#define REG_SCBAKDATA9_OFFSET		(SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE))
+
+#define CPUIDLE_FLAG_REG(cluster) \
+			((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \
+			 REG_SCBAKDATA9_OFFSET)
+#define CLUSTER_IDLE_BIT				BIT(8)
+#define CLUSTER_IDLE_MASK		(CLUSTER_IDLE_BIT | 0x0F)
+
+#define AP_SUSPEND_FLAG			(1 << 16)
+
+#define CLUSTER_PWDN_IDLE		(0<<28)
+#define CLUSTER_PWDN_HOTPLUG		(1<<28)
+#define CLUSTER_PWDN_SR			(2<<28)
+
+#define CLUSTER0_PDC_OFFSET			0x260
+#define CLUSTER1_PDC_OFFSET			0x300
+
+#define PDC_EN_OFFSET				0x0
+#define PDC_COREPWRINTEN_OFFSET		0x4
+#define PDC_COREPWRINTSTAT_OFFSET	0x8
+#define PDC_COREGICMASK_OFFSET		0xc
+#define PDC_COREPOWERUP_OFFSET		0x10
+#define PDC_COREPOWERDN_OFFSET		0x14
+#define PDC_COREPOWERSTAT_OFFSET	0x18
+
+#define PDC_COREPWRSTAT_MASK   (0XFFFF)
+
+enum pdc_gic_mask {
+	PDC_MASK_GIC_WAKE_IRQ,
+	PDC_UNMASK_GIC_WAKE_IRQ
+};
+
+enum pdc_finish_int_mask {
+	PDC_DISABLE_FINISH_INT,
+	PDC_ENABLE_FINISH_INT
+};
+
+static void hisi_resource_lock(unsigned int lockid, unsigned int offset)
+{
+	unsigned int lock_id = (lockid << 29);
+	unsigned int lock_val =  lock_id | LOCK_BIT;
+	unsigned int lock_state;
+
+	do {
+		mmio_write_32(offset, lock_val);
+		lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset);
+	} while ((lock_state & LOCK_ID_MASK) != lock_id);
+}
+
+static void hisi_resource_unlock(unsigned int lockid, unsigned int offset)
+{
+	unsigned int lock_val = (lockid << 29) | LOCK_BIT;
+
+	mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val);
+}
+
+
+static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core)
+{
+	unsigned int lock_id;
+
+	lock_id = (cluster << 2) + core;
+
+	hisi_resource_lock(lock_id, RES2_LOCK_BASE);
+}
+
+static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core)
+{
+	unsigned int lock_id;
+
+	lock_id = (cluster << 2) + core;
+
+	hisi_resource_unlock(lock_id, RES2_LOCK_BASE);
+}
+
+/* get the resource lock */
+void hisi_cpuidle_lock(unsigned int cluster, unsigned int core)
+{
+	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
+
+	hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset);
+}
+
+/* release the resource lock */
+void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core)
+{
+	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
+
+	hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset);
+}
+
+unsigned int hisi_get_cpuidle_flag(unsigned int cluster)
+{
+	unsigned int val;
+
+	val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
+	val &= 0xF;
+
+	return val;
+}
+
+void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
+{
+	mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
+}
+
+void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
+{
+	mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
+
+}
+
+int hisi_test_ap_suspend_flag(void)
+{
+	unsigned int val1;
+	unsigned int val2;
+
+	val1 = mmio_read_32(CPUIDLE_FLAG_REG(0));
+	val1 &= AP_SUSPEND_FLAG;
+
+	val2 = mmio_read_32(CPUIDLE_FLAG_REG(1));
+	val2 &= AP_SUSPEND_FLAG;
+
+	val1 |= val2;
+	return (val1 != 0);
+}
+
+void hisi_set_cluster_pwdn_flag(unsigned int cluster,
+				unsigned int core, unsigned int value)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val &= ~(0x3U << ((2 * cluster) + 28));
+	val |= (value << (2 * cluster));
+	mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = val >> (16 + (cluster << 2));
+	val &= 0xF;
+	hisi_cpuhotplug_unlock(cluster, core);
+
+	return val;
+}
+
+unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = val >> (16 + (cluster << 2));
+	val &= 0xF;
+	hisi_cpuhotplug_unlock(cluster, core);
+
+	if (val)
+		return 0;
+	else
+		return 1;
+}
+
+void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int flag = BIT((cluster<<2) + core + 16);
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int flag = BIT((cluster<<2) + core + 16);
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+int cluster_is_powered_on(unsigned int cluster)
+{
+	unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	int ret;
+
+	if (cluster == 0)
+		ret = val & CLUSTER0_CPUS_ONLINE_MASK;
+	else
+		ret = val & CLUSTER1_CPUS_ONLINE_MASK;
+
+	return !!ret;
+}
+
+static void *hisi_get_pdc_addr(unsigned int cluster)
+{
+	void *pdc_base_addr;
+	uintptr_t addr;
+
+	if (cluster == 0)
+		addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
+	else
+		addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
+	pdc_base_addr = (void *)addr;
+
+	return pdc_base_addr;
+}
+
+static unsigned int hisi_get_pdc_stat(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
+
+	return val;
+}
+
+static int check_hotplug(unsigned int cluster, unsigned int boot_flag)
+{
+	unsigned int mask = 0xF;
+
+	if (hisi_test_ap_suspend_flag() ||
+	    ((boot_flag & mask) == mask))
+		return 0;
+
+	return 1;
+}
+
+int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
+{
+	unsigned int mask = 0xf << (core * 4);
+	unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
+	unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
+	unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
+
+	mask = (PDC_COREPWRSTAT_MASK & (~mask));
+	pdc_stat &= mask;
+
+	if ((boot_flag ^ cpuidle_flag) || pdc_stat ||
+	    check_hotplug(cluster, boot_flag))
+		return 0;
+	else
+		return 1;
+}
+
+void hisi_disable_pdc(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
+}
+
+void hisi_enable_pdc(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
+}
+
+void hisi_pdc_set_intmask(void *pdc_base_addr,
+			unsigned int core,
+			enum pdc_finish_int_mask intmask)
+{
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
+	if (intmask == PDC_ENABLE_FINISH_INT)
+		val |= BIT(core);
+	else
+		val &= ~BIT(core);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
+}
+
+static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
+					unsigned int core,
+					enum pdc_gic_mask gicmask)
+{
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
+	if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
+		val |= BIT(core);
+	else
+		val &= ~BIT(core);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
+}
+
+void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
+{
+	int i;
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	for (i = 0; i < 4; i++)
+		hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
+}
+
+static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
+				  enum pdc_gic_mask gicmask,
+				  enum pdc_finish_int_mask intmask)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
+		      BIT(core));
+}
+
+static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
+				  enum pdc_gic_mask gicmask,
+				  enum pdc_finish_int_mask intmask)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_powerup_core(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_powerdn_core(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
+{
+	hisi_ipc_pm_on_off(core, cluster, PM_ON);
+}
+
+void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
+		      (0x10001 << core));
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
+		      (0x10001 << core));
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
+{
+	hisi_ipc_pm_suspend(core, cluster, 0x3);
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
new file mode 100644
index 0000000..e0cb381
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_PWRC_H
+#define HISI_PWRC_H
+
+#include <hi3660.h>
+#include <hi3660_crg.h>
+
+#define PCTRL_BASE					(PCTRL_REG_BASE)
+#define CRG_BASE					(CRG_REG_BASE)
+
+#define SOC_CRGPERIPH_A53_PDCEN_ADDR(base)		((base) + (0x260))
+#define SOC_CRGPERIPH_MAIA_PDCEN_ADDR(base)		((base) + (0x300))
+
+#define SOC_PCTRL_RESOURCE0_LOCK_ADDR(base)		((base) + (0x400))
+#define SOC_PCTRL_RESOURCE0_UNLOCK_ADDR(base)		((base) + (0x404))
+#define SOC_PCTRL_RESOURCE0_LOCK_ST_ADDR(base)		((base) + (0x408))
+#define SOC_PCTRL_RESOURCE1_LOCK_ADDR(base)		((base) + (0x40C))
+#define SOC_PCTRL_RESOURCE1_UNLOCK_ADDR(base)		((base) + (0x410))
+#define SOC_PCTRL_RESOURCE1_LOCK_ST_ADDR(base)		((base) + (0x414))
+#define SOC_PCTRL_RESOURCE2_LOCK_ADDR(base)		((base) + (0x418))
+
+#define SOC_SCTRL_SCBAKDATA3_ADDR(base)			((base) + (0x418))
+#define SOC_SCTRL_SCBAKDATA8_ADDR(base)			((base) + (0x42C))
+#define SOC_SCTRL_SCBAKDATA9_ADDR(base)			((base) + (0x430))
+
+#define SOC_ACPU_SCTRL_BASE_ADDR			(0xFFF0A000)
+
+void hisi_cpuidle_lock(unsigned int cluster, unsigned int core);
+void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core);
+void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core);
+void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core);
+void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core);
+void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core);
+int cluster_is_powered_on(unsigned int cluster);
+void hisi_enter_core_idle(unsigned int cluster, unsigned int core);
+void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core);
+int hisi_test_ap_suspend_flag(void);
+void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core);
+
+
+/* pdc api */
+void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster);
+int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core);
+void hisi_disable_pdc(unsigned int cluster);
+void hisi_enable_pdc(unsigned int cluster);
+void hisi_powerup_core(unsigned int cluster, unsigned int core);
+void hisi_powerdn_core(unsigned int cluster, unsigned int core);
+void hisi_powerup_cluster(unsigned int cluster, unsigned int core);
+void hisi_powerdn_cluster(unsigned int cluster, unsigned int core);
+unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core);
+
+#endif /* HISI_PWRC_H */
diff --git a/plat/hisilicon/hikey960/hikey960_bl1_setup.c b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
new file mode 100644
index 0000000..4a7036c
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/tbbr/tbbr_img_desc.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi3660.h>
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+enum {
+	BOOT_MODE_RECOVERY = 0,
+	BOOT_MODE_NORMAL,
+	BOOT_MODE_MASK = 1,
+};
+
+/*
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted RAM
+ */
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+static console_pl011_t console;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t g0_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+			GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+			GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+	.gicd_base = GICD_REG_BASE,
+	.gicc_base = GICC_REG_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*
+ * Perform any BL1 specific platform actions.
+ */
+void bl1_early_platform_setup(void)
+{
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL1_RW_BASE;
+	bl1_tzram_layout.total_size = BL1_RW_SIZE;
+
+	INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+	     BL1_RAM_LIMIT - BL1_RAM_BASE); /* bl1_size */
+}
+
+/*
+ * Perform the very early platform specific architecture setup here. At the
+ * moment this only does basic initialization. Later architectural setup
+ * (bl1_arch_setup()) does not do anything platform specific.
+ */
+void bl1_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(bl1_tzram_layout.total_base,
+			      bl1_tzram_layout.total_size,
+			      BL1_RO_BASE,
+			      BL1_RO_LIMIT,
+			      BL_COHERENT_RAM_BASE,
+			      BL_COHERENT_RAM_END);
+}
+
+static void hikey960_ufs_reset(void)
+{
+	unsigned int data, mask;
+
+	mmio_write_32(CRG_PERDIS7_REG, 1 << 14);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+	do {
+		data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	} while (data & BIT_SYSCTRL_REF_CLOCK_EN);
+	/* use abb clk */
+	mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN);
+	mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16));
+	mdelay(1);
+	mmio_write_32(CRG_PEREN7_REG, 1 << 14);
+	mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+
+	mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while ((data & PERI_UFS_BIT) == 0);
+	mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN);
+	mdelay(1);
+	mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET);
+	/* clear SC_DIV_UFS_PERIBUS */
+	mask = SC_DIV_UFS_PERIBUS << 16;
+	mmio_write_32(CRG_CLKDIV17_REG, mask);
+	/* set SC_DIV_UFSPHY_CFG(3) */
+	mask = SC_DIV_UFSPHY_CFG_MASK << 16;
+	data = SC_DIV_UFSPHY_CFG(3);
+	mmio_write_32(CRG_CLKDIV16_REG, mask | data);
+	data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ;
+	data |= 0x39;
+	mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL);
+	mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG,
+			MASK_UFS_CLK_GATE_BYPASS);
+	mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS);
+
+	mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN);
+	mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN);
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT);
+	mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N);
+	mdelay(1);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET);
+	mdelay(20);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      0x03300330);
+
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while (data & PERI_UFS_BIT);
+}
+
+static void hikey960_ufs_init(void)
+{
+	dw_ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params));
+	ufs_params.reg_base = UFS_REG_BASE;
+	ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+	ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+
+	if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0)
+		hikey960_ufs_reset();
+	dw_ufs_init(&ufs_params);
+}
+
+/*
+ * Function which will perform any remaining platform-specific setup that can
+ * occur after the MMU and data cache have been enabled.
+ */
+void bl1_platform_setup(void)
+{
+	hikey960_clk_init();
+	hikey960_pmu_init();
+	hikey960_regulator_enable();
+	hikey960_tzc_init();
+	hikey960_peri_init();
+	hikey960_ufs_init();
+	hikey960_pinmux_init();
+	hikey960_gpio_init();
+	hikey960_io_setup();
+}
+
+/*
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or not.
+ */
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	unsigned int mode, ret;
+
+	mode = mmio_read_32(SCTRL_BAK_DATA0_REG);
+	switch (mode & BOOT_MODE_MASK) {
+	case BOOT_MODE_RECOVERY:
+		ret = NS_BL1U_IMAGE_ID;
+		break;
+	default:
+		WARN("Invalid boot mode is found:%d\n", mode);
+		panic();
+	}
+	return ret;
+}
+
+image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
+{
+	unsigned int index = 0;
+
+	while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
+		if (bl1_tbbr_image_descs[index].image_id == image_id)
+			return &bl1_tbbr_image_descs[index];
+		index++;
+	}
+
+	return NULL;
+}
+
+void bl1_plat_set_ep_info(unsigned int image_id,
+		entry_point_info_t *ep_info)
+{
+	unsigned int data = 0;
+	uintptr_t tmp = HIKEY960_NS_TMP_OFFSET;
+
+	if (image_id != NS_BL1U_IMAGE_ID)
+		panic();
+	/* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */
+	memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET,
+		NS_BL1U_SIZE);
+	memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE);
+	inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE);
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey960_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+	/* CNTFRQ is read-only in EL1 */
+	write_cntfrq_el0(plat_get_syscnt_freq2());
+	data = read_cpacr_el1();
+	do {
+		data |= 3 << 20;
+		write_cpacr_el1(data);
+		data = read_cpacr_el1();
+	} while ((data & (3 << 20)) != (3 << 20));
+	INFO("cpacr_el1:0x%x\n", data);
+
+	ep_info->args.arg0 = 0xffff & read_mpidr();
+	ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c b/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c
new file mode 100644
index 0000000..ba236d2
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+    {
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+#endif /* SCP_BL2_BASE */
+
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = EL3_PAYLOAD_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t,
+		    IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL31_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+	    .ep_info.args.arg1 = HIKEY960_BL31_PLAT_PARAM_VAL,
+#endif
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL31_BASE,
+	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+	    .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+    },
+
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+    {
+	    .image_id = BL32_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
+	    .ep_info.pc = BL32_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+    },
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the pager image.
+	 */
+    {
+	    .image_id = BL32_EXTRA1_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the paged image.
+	 */
+    {
+	    .image_id = BL32_EXTRA2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+#ifdef SPD_opteed
+	    .image_info.image_base = HIKEY960_OPTEE_PAGEABLE_LOAD_BASE,
+	    .image_info.image_max_size = HIKEY960_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+    {
+	    .image_id = BL33_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+	    .ep_info.pc = PRELOADED_BL33_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+# else
+	    .ep_info.pc = NS_BL1U_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = NS_BL1U_BASE,
+	    .image_info.image_max_size = 0x200000 /* 2MB */,
+# endif /* PRELOADED_BL33_BASE */
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    }
+#endif /* EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/hisilicon/hikey960/hikey960_bl2_setup.c b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
new file mode 100644
index 0000000..fc9ddab
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <drivers/dw_ufs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ufs.h>
+#include <lib/mmio.h>
+#ifdef SPD_opteed
+#include <lib/optee_utils.h>
+#endif
+
+#include <hi3660.h>
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+#define BL2_RW_BASE		(BL_CODE_END)
+
+static meminfo_t bl2_el3_tzram_layout;
+static console_pl011_t console;
+extern int load_lpm3(void);
+
+enum {
+	BOOT_MODE_RECOVERY = 0,
+	BOOT_MODE_NORMAL,
+	BOOT_MODE_MASK = 1,
+};
+
+/*******************************************************************************
+ * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
+ * Return 0 on success, -1 otherwise.
+ ******************************************************************************/
+int plat_hikey960_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	int i;
+	int *buf;
+
+	assert(scp_bl2_image_info->image_size < SCP_BL2_SIZE);
+
+	INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
+
+	INFO("BL2: SCP_BL2: 0x%lx@0x%x\n",
+	     scp_bl2_image_info->image_base,
+	     scp_bl2_image_info->image_size);
+
+	buf = (int *)scp_bl2_image_info->image_base;
+
+	INFO("BL2: SCP_BL2 HEAD:\n");
+	for (i = 0; i < 64; i += 4)
+		INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
+			buf[i], buf[i+1], buf[i+2], buf[i+3]);
+
+	buf = (int *)(scp_bl2_image_info->image_base +
+		      scp_bl2_image_info->image_size - 256);
+
+	INFO("BL2: SCP_BL2 TAIL:\n");
+	for (i = 0; i < 64; i += 4)
+		INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
+			buf[i], buf[i+1], buf[i+2], buf[i+3]);
+
+	INFO("BL2: SCP_BL2 transferred to SCP\n");
+
+	load_lpm3();
+	(void)buf;
+
+	return 0;
+}
+
+static void hikey960_ufs_reset(void)
+{
+	unsigned int data, mask;
+
+	mmio_write_32(CRG_PERDIS7_REG, 1 << 14);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+	do {
+		data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	} while (data & BIT_SYSCTRL_REF_CLOCK_EN);
+	/* use abb clk */
+	mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN);
+	mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16));
+	mdelay(1);
+	mmio_write_32(CRG_PEREN7_REG, 1 << 14);
+	mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+
+	mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while ((data & PERI_UFS_BIT) == 0);
+	mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN);
+	mdelay(1);
+	mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET);
+	/* clear SC_DIV_UFS_PERIBUS */
+	mask = SC_DIV_UFS_PERIBUS << 16;
+	mmio_write_32(CRG_CLKDIV17_REG, mask);
+	/* set SC_DIV_UFSPHY_CFG(3) */
+	mask = SC_DIV_UFSPHY_CFG_MASK << 16;
+	data = SC_DIV_UFSPHY_CFG(3);
+	mmio_write_32(CRG_CLKDIV16_REG, mask | data);
+	data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ;
+	data |= 0x39;
+	mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL);
+	mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG,
+			MASK_UFS_CLK_GATE_BYPASS);
+	mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS);
+
+	mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN);
+	mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN);
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT);
+	mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N);
+	mdelay(1);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET);
+	mdelay(20);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      0x03300330);
+
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while (data & PERI_UFS_BIT);
+}
+
+static void hikey960_init_ufs(void)
+{
+	dw_ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params_t));
+	ufs_params.reg_base = UFS_REG_BASE;
+	ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+	ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+	hikey960_ufs_reset();
+	dw_ufs_init(&ufs_params);
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t hikey960_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL3-2 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+#ifdef __aarch64__
+uint32_t hikey960_get_spsr_for_bl33_entry(void)
+{
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#else
+uint32_t hikey960_get_spsr_for_bl33_entry(void)
+{
+	unsigned int hyp_status, mode, spsr;
+
+	hyp_status = GET_VIRT_EXT(read_id_pfr1());
+
+	mode = (hyp_status) ? MODE32_hyp : MODE32_svc;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1,
+			SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#endif /* __aarch64__ */
+
+int hikey960_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#ifdef SPD_opteed
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+	assert(bl_mem_params);
+
+	switch (image_id) {
+#ifdef __aarch64__
+	case BL32_IMAGE_ID:
+#ifdef SPD_opteed
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+				&pager_mem_params->image_info,
+				&paged_mem_params->image_info);
+		if (err != 0) {
+			WARN("OPTEE header parse error.\n");
+		}
+#endif
+		bl_mem_params->ep_info.spsr = hikey960_get_spsr_for_bl32_entry();
+		break;
+#endif
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = hikey960_get_spsr_for_bl33_entry();
+		break;
+
+#ifdef SCP_BL2_BASE
+	case SCP_BL2_IMAGE_ID:
+		/* The subsequent handling of SCP_BL2 is platform specific */
+		err = plat_hikey960_bl2_handle_scp_bl2(&bl_mem_params->image_info);
+		if (err) {
+			WARN("Failure in platform-specific handling of SCP_BL2 image.\n");
+		}
+		break;
+#endif
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return hikey960_bl2_handle_post_image_load(image_id);
+}
+
+void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2,
+				  u_register_t arg3, u_register_t arg4)
+{
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+	/*
+	 * Allow BL2 to see the whole Trusted RAM.
+	 */
+	bl2_el3_tzram_layout.total_base = BL2_RW_BASE;
+	bl2_el3_tzram_layout.total_size = BL31_LIMIT - BL2_RW_BASE;
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(bl2_el3_tzram_layout.total_base,
+			      bl2_el3_tzram_layout.total_size,
+			      BL_CODE_BASE,
+			      BL_CODE_END,
+			      BL_COHERENT_RAM_BASE,
+			      BL_COHERENT_RAM_END);
+}
+
+void bl2_platform_setup(void)
+{
+	/* disable WDT0 */
+	if (mmio_read_32(WDT0_REG_BASE + WDT_LOCK_OFFSET) == WDT_LOCKED) {
+		mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, WDT_UNLOCK);
+		mmio_write_32(WDT0_REG_BASE + WDT_CONTROL_OFFSET, 0);
+		mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, 0);
+	}
+	hikey960_clk_init();
+	hikey960_pmu_init();
+	hikey960_regulator_enable();
+	hikey960_tzc_init();
+	hikey960_peri_init();
+	hikey960_pinmux_init();
+	hikey960_gpio_init();
+	hikey960_init_ufs();
+	hikey960_io_setup();
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
new file mode 100644
index 0000000..9383265
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <hi3660.h>
+#include <hisi_ipc.h>
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+static console_pl011_t console;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t g0_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+	.gicd_base = GICD_REG_BASE,
+	.gicc_base = GICC_REG_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+static const int cci_map[] = {
+	CCI400_SL_IFACE3_CLUSTER_IX,
+	CCI400_SL_IFACE4_CLUSTER_IX
+};
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	return NULL;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	unsigned int id, uart_base;
+	void *from_bl2;
+
+	from_bl2 = (void *) arg0;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Initialize CCI driver */
+	cci_init(CCI400_REG_BASE, cci_map, ARRAY_SIZE(cci_map));
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_ep_info.pc == 0)
+		panic();
+}
+
+void bl31_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(BL31_BASE,
+			BL31_LIMIT - BL31_BASE,
+			BL_CODE_BASE,
+			BL_CODE_END,
+			BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END);
+}
+
+static void hikey960_edma_init(void)
+{
+	int i;
+	uint32_t non_secure;
+
+	non_secure = EDMAC_SEC_CTRL_INTR_SEC | EDMAC_SEC_CTRL_GLOBAL_SEC;
+	mmio_write_32(EDMAC_SEC_CTRL, non_secure);
+
+	/* Channel 0 is reserved for LPM3, keep secure */
+	for (i = 1; i < EDMAC_CHANNEL_NUMS; i++) {
+		mmio_write_32(EDMAC_AXI_CONF(i), (1 << 6) | (1 << 18));
+	}
+}
+
+static void hikey960_iomcu_dma_init(void)
+{
+	int i;
+	uint32_t non_secure;
+
+	non_secure = IOMCU_DMAC_SEC_CTRL_INTR_SEC | IOMCU_DMAC_SEC_CTRL_GLOBAL_SEC;
+	mmio_write_32(IOMCU_DMAC_SEC_CTRL, non_secure);
+
+	/* channels 0-3 are reserved */
+	for (i = 4; i < IOMCU_DMAC_CHANNEL_NUMS; i++) {
+		mmio_write_32(IOMCU_DMAC_AXI_CONF(i), IOMCU_DMAC_AXI_CONF_ARPROT_NS |
+				 IOMCU_DMAC_AXI_CONF_AWPROT_NS);
+	}
+}
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey960_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	hikey960_edma_init();
+	hikey960_iomcu_dma_init();
+
+	hisi_ipc_init();
+}
+
+#ifdef SPD_none
+static uint64_t hikey_debug_fiq_handler(uint32_t id,
+					uint32_t flags,
+					void *handle,
+					void *cookie)
+{
+	int intr, intr_raw;
+
+	/* Acknowledge interrupt */
+	intr_raw = plat_ic_acknowledge_interrupt();
+	intr = plat_ic_get_interrupt_id(intr_raw);
+	ERROR("Invalid interrupt: intr=%d\n", intr);
+	console_flush();
+	panic();
+
+	return 0;
+}
+#endif
+
+void bl31_plat_runtime_setup(void)
+{
+#ifdef SPD_none
+	uint32_t flags;
+	int32_t rc;
+
+	flags = 0;
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+					     hikey_debug_fiq_handler,
+					     flags);
+	if (rc != 0)
+		panic();
+#endif
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl_common.c b/plat/hisilicon/hikey960/hikey960_bl_common.c
new file mode 100644
index 0000000..89adccb
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl_common.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi3660.h>
+#include "hikey960_private.h"
+
+void hikey960_clk_init(void)
+{
+	/* change ldi0 sel to ppll2 */
+	mmio_write_32(0xfff350b4, 0xf0002000);
+	/* ldi0 20' */
+	mmio_write_32(0xfff350bc, 0xfc004c00);
+}
+
+void hikey960_pmu_init(void)
+{
+	/* clear np_xo_abb_dig_START bit in PMIC_CLK_TOP_CTRL7 register */
+	mmio_clrbits_32(PMU_SSI0_CLK_TOP_CTRL7_REG, NP_XO_ABB_DIG);
+}
+
+static void hikey960_enable_ppll3(void)
+{
+	/* enable ppll3 */
+	mmio_write_32(PMC_PPLL3_CTRL0_REG, 0x4904305);
+	mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x2300000);
+	mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x6300000);
+}
+
+static void bus_idle_clear(unsigned int value)
+{
+	unsigned int pmc_value, value1, value2;
+	int timeout = 100;
+
+	pmc_value = value << 16;
+	pmc_value &= ~value;
+	mmio_write_32(PMC_NOC_POWER_IDLEREQ_REG, pmc_value);
+
+	for (;;) {
+		value1 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLEACK_REG);
+		value2 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLE_REG);
+		if (((value1 & value) == 0) && ((value2 & value) == 0))
+			break;
+		udelay(1);
+		timeout--;
+		if (timeout <= 0) {
+			WARN("%s timeout\n", __func__);
+			break;
+		}
+	}
+}
+
+static void set_vivobus_power_up(void)
+{
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00020002);
+	mmio_write_32(CRG_PEREN0_REG, 0x00001000);
+}
+
+static void set_dss_power_up(void)
+{
+	/* set edc0 133MHz = 1600MHz / 12 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0x003f000b);
+	/* set ldi0 ppl0 */
+	mmio_write_32(CRG_CLKDIV3_REG, 0xf0001000);
+	/* set ldi0 133MHz, 1600MHz / 12 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0xfc002c00);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000020);
+	udelay(100);
+	/* DISP CRG */
+	mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000010);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+	mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+	mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x0003b000);
+	mmio_write_32(CRG_PERDIS0_REG, 0x00002000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000040);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000006);
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000c00);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+	mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+	mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_DSS);
+	/* set edc0 400MHz for 2K 1600MHz / 4 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0x003f0003);
+	/* set ldi 266MHz, 1600MHz / 6 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0xfc001400);
+}
+
+static void set_vcodec_power_up(void)
+{
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00040004);
+	mmio_write_32(CRG_PEREN0_REG, 0x00000060);
+	mmio_write_32(CRG_PEREN2_REG, 0x10000000);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS0_REG, 0x00000018);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VCODEC);
+}
+
+static void set_vdec_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000004);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+	mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x00000800);
+	mmio_write_32(CRG_PERDIS2_REG, 0x20080000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000004);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000200);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+	mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VDEC);
+}
+
+static void set_venc_power_up(void)
+{
+	/* set venc ppll3 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x18001000);
+	/* set venc 258MHz, 1290MHz / 5 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x07c00100);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000002);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+	mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x00000400);
+	mmio_write_32(CRG_PERDIS2_REG, 0x40000100);
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000002);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+	mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VENC);
+	/* set venc 645MHz, 1290MHz / 2 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x07c00040);
+}
+
+static void set_isp_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000001);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+	mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+	mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS5_REG, 0x01000010);
+	mmio_write_32(CRG_PERDIS3_REG, 0x0bf00000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70000000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000001);
+	/* unreset */
+	mmio_write_32(CRG_ISP_SEC_RSTDIS_REG, 0x0000002f);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+	mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+	mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_ISP);
+	/* csi clk enable */
+	mmio_write_32(CRG_PEREN3_REG, 0x00700000);
+}
+
+static void set_ivp_power_up(void)
+{
+	/* set ivp ppll0 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0xc0000000);
+	/* set ivp 267MHz, 1600MHz / 6 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0x3c001400);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00200000);
+	udelay(100);
+	/* IVP CRG unreset */
+	mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000001);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+	mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS4_REG, 0x000000a8);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x01000000);
+	/* unreset */
+	mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000002);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+	mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_IVP);
+	/* set ivp 533MHz, 1600MHz / 3 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0x3c000800);
+}
+
+static void set_audio_power_up(void)
+{
+	unsigned int ret;
+	int timeout = 100;
+	/* mtcmos on */
+	mmio_write_32(SCTRL_SCPWREN_REG, 0x00000001);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+	mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+	mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+	mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+	mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(SCTRL_SCPERDIS1_REG, 0x0000000f);
+	mmio_write_32(SCTRL_SCPERDIS0_REG, 0x0c000000);
+	mmio_write_32(CRG_PERDIS5_REG, 0x00000080);
+	mmio_write_32(CRG_PERDIS0_REG, 0x04000000);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010000);
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80100000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(SCTRL_SCISODIS_REG, 0x00000001);
+	udelay(1);
+	/* unreset */
+	mmio_write_32(SCTRL_PERRSTDIS1_SEC_REG, 0x00000001);
+	mmio_write_32(SCTRL_SCPERRSTDIS0_REG, 0x00000780);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+	mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+	mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+	mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+	mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+	/* bus idle clear */
+	mmio_write_32(SCTRL_SCPERCTRL7_REG, 0x00040000);
+	for (;;) {
+		ret = mmio_read_32(SCTRL_SCPERSTAT6_REG);
+		if (((ret & (1 << 5)) == 0) && ((ret & (1 << 8)) == 0))
+			break;
+		udelay(1);
+		timeout--;
+		if (timeout <= 0) {
+			WARN("%s timeout\n", __func__);
+			break;
+		}
+	}
+	mmio_write_32(ASP_CFG_MMBUF_CTRL_REG, 0x00ff0000);
+}
+
+static void set_pcie_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(SCTRL_SCPWREN_REG, 0x00000010);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+	mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+	mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(SCTRL_SCPERDIS2_REG, 0x00104000);
+	mmio_write_32(CRG_PERDIS7_REG, 0x000003a0);
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(SCTRL_SCISODIS_REG, 0x00000030);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x8c000000);
+	/* clk enable */
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+	mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+	mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+}
+
+static void ispfunc_enable(void)
+{
+	/* enable ispfunc. Otherwise powerup isp_srt causes exception. */
+	mmio_write_32(0xfff35000, 0x00000008);
+	mmio_write_32(0xfff35460, 0xc004ffff);
+	mmio_write_32(0xfff35030, 0x02000000);
+	mdelay(10);
+}
+
+static void isps_control_clock(int flag)
+{
+	unsigned int ret;
+
+	/* flag: 0 -- disable clock, 1 -- enable clock */
+	if (flag) {
+		ret = mmio_read_32(0xe8420364);
+		ret |= 1;
+		mmio_write_32(0xe8420364, ret);
+	} else {
+		ret = mmio_read_32(0xe8420364);
+		ret &= ~1;
+		mmio_write_32(0xe8420364, ret);
+	}
+}
+
+static void set_isp_srt_power_up(void)
+{
+	unsigned int ret;
+
+	ispfunc_enable();
+	/* reset */
+	mmio_write_32(0xe8420374, 0x00000001);
+	mmio_write_32(0xe8420350, 0x00000000);
+	mmio_write_32(0xe8420358, 0x00000000);
+	/* mtcmos on */
+	mmio_write_32(0xfff35150, 0x00400000);
+	udelay(100);
+	/* clk enable */
+	isps_control_clock(1);
+	udelay(1);
+	isps_control_clock(0);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(0xfff35148, 0x08000000);
+	/* unreset */
+	ret = mmio_read_32(0xe8420374);
+	ret &= ~0x1;
+	mmio_write_32(0xe8420374, ret);
+	/* clk enable */
+	isps_control_clock(1);
+	/* enable clock gating for accessing csi registers */
+	mmio_write_32(0xe8420010, ~0);
+}
+
+void hikey960_regulator_enable(void)
+{
+	set_vivobus_power_up();
+	hikey960_enable_ppll3();
+	set_dss_power_up();
+	set_vcodec_power_up();
+	set_vdec_power_up();
+	set_venc_power_up();
+	set_isp_power_up();
+	set_ivp_power_up();
+	set_audio_power_up();
+	set_pcie_power_up();
+	set_isp_srt_power_up();
+
+	/* set ISP_CORE_CTRL_S to unsecure mode */
+	mmio_write_32(0xe8583800, 0x7);
+	/* set ISP_SUB_CTRL_S to unsecure mode */
+	mmio_write_32(0xe8583804, 0xf);
+}
+
+void hikey960_tzc_init(void)
+{
+	mmio_write_32(TZC_EN0_REG, 0x7fbff066);
+	mmio_write_32(TZC_EN1_REG, 0xfffff5fc);
+	mmio_write_32(TZC_EN2_REG, 0x0007005c);
+	mmio_write_32(TZC_EN3_REG, 0x37030700);
+	mmio_write_32(TZC_EN4_REG, 0xf63fefae);
+	mmio_write_32(TZC_EN5_REG, 0x000410fd);
+	mmio_write_32(TZC_EN6_REG, 0x0063ff68);
+	mmio_write_32(TZC_EN7_REG, 0x030000f3);
+	mmio_write_32(TZC_EN8_REG, 0x00000007);
+}
+
+void hikey960_peri_init(void)
+{
+	/* unreset */
+	mmio_setbits_32(CRG_PERRSTDIS4_REG, 1);
+}
+
+void hikey960_pinmux_init(void)
+{
+	unsigned int id;
+
+	hikey960_read_boardid(&id);
+	if (id == 5301) {
+		/* hikey960 hardware v2 */
+		/* GPIO150: LED */
+		mmio_write_32(IOMG_FIX_006_REG, 0);
+		/* GPIO151: LED */
+		mmio_write_32(IOMG_FIX_007_REG, 0);
+		/* GPIO189: LED */
+		mmio_write_32(IOMG_AO_011_REG, 0);
+		/* GPIO190: LED */
+		mmio_write_32(IOMG_AO_012_REG, 0);
+		/* GPIO46 */
+		mmio_write_32(IOMG_044_REG, 0);
+		/* GPIO202 */
+		mmio_write_32(IOMG_AO_023_REG, 0);
+		/* GPIO206 */
+		mmio_write_32(IOMG_AO_026_REG, 0);
+		/* GPIO219 - PD pullup */
+		mmio_write_32(IOMG_AO_039_REG, 0);
+		mmio_write_32(IOCG_AO_043_REG, 1 << 0);
+	}
+	/* GPIO005 - PMU SSI, 10mA */
+	mmio_write_32(IOCG_006_REG, 2 << 4);
+	/* GPIO213 - PCIE_CLKREQ_N */
+	mmio_write_32(IOMG_AO_033_REG, 1);
+}
+
+void hikey960_gpio_init(void)
+{
+	pl061_gpio_init();
+	pl061_gpio_register(GPIO0_BASE, 0);
+	pl061_gpio_register(GPIO1_BASE, 1);
+	pl061_gpio_register(GPIO2_BASE, 2);
+	pl061_gpio_register(GPIO3_BASE, 3);
+	pl061_gpio_register(GPIO4_BASE, 4);
+	pl061_gpio_register(GPIO5_BASE, 5);
+	pl061_gpio_register(GPIO6_BASE, 6);
+	pl061_gpio_register(GPIO7_BASE, 7);
+	pl061_gpio_register(GPIO8_BASE, 8);
+	pl061_gpio_register(GPIO9_BASE, 9);
+	pl061_gpio_register(GPIO10_BASE, 10);
+	pl061_gpio_register(GPIO11_BASE, 11);
+	pl061_gpio_register(GPIO12_BASE, 12);
+	pl061_gpio_register(GPIO13_BASE, 13);
+	pl061_gpio_register(GPIO14_BASE, 14);
+	pl061_gpio_register(GPIO15_BASE, 15);
+	pl061_gpio_register(GPIO16_BASE, 16);
+	pl061_gpio_register(GPIO17_BASE, 17);
+	pl061_gpio_register(GPIO18_BASE, 18);
+	pl061_gpio_register(GPIO19_BASE, 19);
+	pl061_gpio_register(GPIO20_BASE, 20);
+	pl061_gpio_register(GPIO21_BASE, 21);
+
+	/* PCIE_PERST_N output low */
+	gpio_set_direction(89, GPIO_DIR_OUT);
+	gpio_set_value(89, GPIO_LEVEL_LOW);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_boardid.c b/plat/hisilicon/hikey960/hikey960_boardid.c
new file mode 100644
index 0000000..1e1126f
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_boardid.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi3660.h>
+#include "hikey960_private.h"
+
+#define ADC_ADCIN0				0
+#define ADC_ADCIN1				1
+#define ADC_ADCIN2				2
+
+#define HKADC_DATA_GRADE0			0
+#define HKADC_DATA_GRADE1			100
+#define HKADC_DATA_GRADE2			300
+#define HKADC_DATA_GRADE3			500
+#define HKADC_DATA_GRADE4			700
+#define HKADC_DATA_GRADE5			900
+#define HKADC_DATA_GRADE6			1100
+#define HKADC_DATA_GRADE7			1300
+#define HKADC_DATA_GRADE8			1500
+#define HKADC_DATA_GRADE9			1700
+#define HKADC_DATA_GRADE10			1800
+
+#define BOARDID_VALUE0				0
+#define BOARDID_VALUE1				1
+#define BOARDID_VALUE2				2
+#define BOARDID_VALUE3				3
+#define BOARDID_VALUE4				4
+#define BOARDID_VALUE5				5
+#define BOARDID_VALUE6				6
+#define BOARDID_VALUE7				7
+#define BOARDID_VALUE8				8
+#define BOARDID_VALUE9				9
+#define BOARDID_UNKNOWN				0xF
+
+#define BOARDID3_BASE				5
+
+
+static void init_adc(void)
+{
+	/* reset hkadc */
+	mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
+	/* wait a few clock cycles */
+	udelay(2);
+	mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
+	udelay(2);
+	/* enable hkadc clock */
+	mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
+	udelay(2);
+	mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
+	udelay(2);
+}
+
+static int get_adc(unsigned int channel, unsigned int *value)
+{
+	unsigned int	data, value1, value0;
+
+	if (channel > HKADC_CHANNEL_MAX) {
+		WARN("invalid channel:%d\n", channel);
+		return -EFAULT;
+	}
+	/* configure the read/write operation for external HKADC */
+	mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
+	mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
+	mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
+	/* configure the number of accessing registers */
+	mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
+	/* configure delay of accessing registers */
+	mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
+	mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
+
+	/* start HKADC */
+	mmio_write_32(HKADC_DSP_START_REG, 1);
+	do {
+		data = mmio_read_32(HKADC_DSP_START_REG);
+	} while (data & 1);
+
+	/* convert AD result */
+	value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
+	value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
+
+	data = ((value1 << 4) & HKADC_VALUE_HIGH) |
+	       ((value0 >> 4) & HKADC_VALUE_LOW);
+	*value = data;
+	return 0;
+}
+
+static int get_value(unsigned int channel, unsigned int *value)
+{
+	int ret;
+
+	ret = get_adc(channel, value);
+	if (ret)
+		return ret;
+
+	/* convert ADC value to micro-volt */
+	ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
+	*value = ret;
+	return 0;
+}
+
+static int adcin_data_remap(unsigned int adcin_value)
+{
+	int	ret;
+
+	if (adcin_value < HKADC_DATA_GRADE1)
+		ret = BOARDID_VALUE0;
+	else if (adcin_value < HKADC_DATA_GRADE2)
+		ret = BOARDID_VALUE1;
+	else if (adcin_value < HKADC_DATA_GRADE3)
+		ret = BOARDID_VALUE2;
+	else if (adcin_value < HKADC_DATA_GRADE4)
+		ret = BOARDID_VALUE3;
+	else if (adcin_value < HKADC_DATA_GRADE5)
+		ret = BOARDID_VALUE4;
+	else if (adcin_value < HKADC_DATA_GRADE6)
+		ret = BOARDID_VALUE5;
+	else if (adcin_value < HKADC_DATA_GRADE7)
+		ret = BOARDID_VALUE6;
+	else if (adcin_value < HKADC_DATA_GRADE8)
+		ret = BOARDID_VALUE7;
+	else if (adcin_value < HKADC_DATA_GRADE9)
+		ret = BOARDID_VALUE8;
+	else if (adcin_value < HKADC_DATA_GRADE10)
+		ret = BOARDID_VALUE9;
+	else
+		ret = BOARDID_UNKNOWN;
+	return ret;
+}
+
+int hikey960_read_boardid(unsigned int *id)
+{
+	unsigned int	adcin0, adcin1, adcin2;
+	unsigned int	adcin0_remap, adcin1_remap, adcin2_remap;
+
+	assert(id != NULL);
+
+	init_adc();
+
+	/* read ADC channel0 data */
+	get_value(ADC_ADCIN0, &adcin0);
+	adcin0_remap = adcin_data_remap(adcin0);
+	if (adcin0_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	/* read ADC channel1 data */
+	get_value(ADC_ADCIN1, &adcin1);
+	adcin1_remap = adcin_data_remap(adcin1);
+	if (adcin1_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	/* read ADC channel2 data */
+	get_value(ADC_ADCIN2, &adcin2);
+	adcin2_remap = adcin_data_remap(adcin2);
+	if (adcin2_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
+		(adcin1_remap * 10) + adcin0_remap;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_def.h b/plat/hisilicon/hikey960/hikey960_def.h
new file mode 100644
index 0000000..4ea3acd
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_def.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY960_DEF_H
+#define HIKEY960_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#define DDR_BASE			0x0
+#define DDR_SIZE			0xE0000000
+
+#define DEVICE_BASE			0xE0000000
+#define DEVICE_SIZE			0x20000000
+
+/* Memory location options for TSP */
+#define HIKEY960_SRAM_ID	0
+#define HIKEY960_DRAM_ID	1
+
+/*
+ * DDR for OP-TEE (32MB from 0x3E00000-0x3FFFFFFF) is divided in several
+ * regions:
+ *   - Secure DDR (default is the top 16MB) used by OP-TEE
+ *   - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB)
+ *   - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature
+ *   - Non-secure DDR (8MB) reserved for OP-TEE's future use
+ */
+#define DDR_SEC_SIZE			0x01000000
+#define DDR_SEC_BASE			0x3F000000
+
+#define DDR_SDP_SIZE			0x00400000
+#define DDR_SDP_BASE			(DDR_SEC_BASE - 0x400000 /* align */ - \
+					DDR_SDP_SIZE)
+
+/*
+ * PL011 related constants
+ */
+#define PL011_UART5_BASE		0xFDF05000
+#define PL011_UART6_BASE		0xFFF32000
+#define PL011_BAUDRATE			115200
+#define PL011_UART_CLK_IN_HZ		19200000
+
+#define UFS_BASE			0
+/* FIP partition */
+#define HIKEY960_FIP_BASE		(UFS_BASE + 0x1400000)
+#define HIKEY960_FIP_MAX_SIZE		(12 << 20)
+
+#define HIKEY960_UFS_DESC_BASE		0x20000000
+#define HIKEY960_UFS_DESC_SIZE		0x00200000	/* 2MB */
+#define HIKEY960_UFS_DATA_BASE		0x10000000
+#define HIKEY960_UFS_DATA_SIZE		0x0A000000	/* 160MB */
+
+#endif /* HIKEY960_DEF_H */
diff --git a/plat/hisilicon/hikey960/hikey960_image_load.c b/plat/hisilicon/hikey960/hikey960_image_load.c
new file mode 100644
index 0000000..57cb1b2
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/hisilicon/hikey960/hikey960_io_storage.c b/plat/hisilicon/hikey960/hikey960_io_storage.c
new file mode 100644
index 0000000..a4e8389
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_io_storage.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/ufs.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/mmio.h>
+#include <lib/semihosting.h>
+#include <tools_share/firmware_image_package.h>
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+static const io_dev_connector_t *ufs_dev_con, *fip_dev_con;
+static uintptr_t ufs_dev_handle, fip_dev_handle;
+
+static int check_ufs(const uintptr_t spec);
+static int check_fip(const uintptr_t spec);
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size);
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size);
+
+static const io_block_spec_t ufs_fip_spec = {
+	.offset		= HIKEY960_FIP_BASE,
+	.length		= HIKEY960_FIP_MAX_SIZE,
+};
+
+static const io_block_dev_spec_t ufs_dev_spec = {
+	/* It's used as temp buffer in block driver. */
+	.buffer		= {
+		.offset	= HIKEY960_UFS_DATA_BASE,
+		.length	= HIKEY960_UFS_DATA_SIZE,
+	},
+	.ops		= {
+		.read	= ufs_read_lun3_blks,
+		.write	= ufs_write_lun3_blks,
+	},
+	.block_size	= UFS_BLOCK_SIZE,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&ufs_dev_handle,
+		(uintptr_t)&ufs_fip_spec,
+		check_ufs
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_bl2_uuid_spec,
+		check_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		check_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		check_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		check_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		check_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		check_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		check_fip
+	},
+	[SCP_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[SCP_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_cert_uuid_spec,
+		check_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		check_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		check_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		check_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int check_ufs(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(ufs_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void hikey960_io_setup(void)
+{
+	int result;
+
+	result = register_io_dev_block(&ufs_dev_con);
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(ufs_dev_con, (uintptr_t)&ufs_dev_spec,
+			     &ufs_dev_handle);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+	assert(result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)result;
+}
+
+/* Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
+
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size)
+{
+	return ufs_read_blocks(3, lba, buf, size);
+}
+
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size)
+{
+	return ufs_write_blocks(3, lba, buf, size);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_mcu_load.c b/plat/hisilicon/hikey960/hikey960_mcu_load.c
new file mode 100644
index 0000000..b9ae313
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_mcu_load.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <hi3660.h>
+
+#define ADDR_CONVERT(addr)		((addr) < 0x40000 ?	\
+					 (addr) + 0xFFF30000 :	\
+					 (addr) + 0x40000000)
+
+static void fw_data_init(void)
+{
+	unsigned long data_head_addr;
+	unsigned int *data_addr;
+
+	data_head_addr = mmio_read_32((uintptr_t) HISI_DATA_HEAD_BASE) + 0x14;
+	data_addr = (unsigned int *) ADDR_CONVERT(data_head_addr);
+
+	memcpy((void *)HISI_DATA0_BASE,
+	       (const void *)(unsigned long)ADDR_CONVERT(data_addr[0]),
+	       HISI_DATA0_SIZE);
+	memcpy((void *)HISI_DATA1_BASE,
+	       (const void *)(unsigned long)ADDR_CONVERT(data_addr[1]),
+	       HISI_DATA1_SIZE);
+}
+
+int load_lpm3(void)
+{
+	INFO("start fw loading\n");
+
+	fw_data_init();
+
+	flush_dcache_range((uintptr_t)HISI_RESERVED_MEM_BASE,
+			   HISI_RESERVED_MEM_SIZE);
+
+	sev();
+	sev();
+
+	INFO("fw load success\n");
+
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_pm.c b/plat/hisilicon/hikey960/hikey960_pm.c
new file mode 100644
index 0000000..ede893e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_pm.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <hi3660.h>
+#include <hi3660_crg.h>
+
+#include "drivers/pwrc/hisi_pwrc.h"
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+#define CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+#define DMAC_GLB_REG_SEC	0x694
+#define AXI_CONF_BASE		0x820
+
+static unsigned int uart_base;
+static console_pl011_t console;
+static uintptr_t hikey960_sec_entrypoint;
+
+static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
+{
+	unsigned long scr;
+
+	scr = read_scr_el3();
+
+	/* Enable Physical IRQ and FIQ to wake the CPU */
+	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+	/* Add barrier before CPU enter WFI state */
+	isb();
+	dsb();
+	wfi();
+
+	/*
+	 * Restore SCR to the original value, synchronisazion of
+	 * scr_el3 is done by eret while el3_exit to save some
+	 * execution cycles.
+	 */
+	write_scr_el3(scr);
+}
+
+static int hikey960_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+	int cluster_stat = cluster_is_powered_on(cluster);
+
+	hisi_set_cpu_boot_flag(cluster, core);
+
+	mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
+		      hikey960_sec_entrypoint >> 2);
+
+	if (cluster_stat)
+		hisi_powerup_core(cluster, core);
+	else
+		hisi_powerup_cluster(cluster, core);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void
+hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	clr_ex();
+	isb();
+	dsbsy();
+
+	gicv2_cpuif_disable();
+
+	hisi_clear_cpu_boot_flag(cluster, core);
+	hisi_powerdn_core(cluster, core);
+
+	/* check if any core is powered up */
+	if (hisi_test_cpu_down(cluster, core)) {
+
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+		isb();
+		dsbsy();
+
+		hisi_powerdn_cluster(cluster, core);
+	}
+}
+
+static void __dead2 hikey960_system_reset(void)
+{
+	dsb();
+	isb();
+	mdelay(2000);
+	mmio_write_32(SCTRL_SCPEREN1_REG,
+		      SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
+	mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
+	panic();
+}
+
+int hikey960_validate_power_state(unsigned int power_state,
+			       psci_power_state_t *req_state)
+{
+	unsigned int pstate = psci_get_pstate_type(power_state);
+	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
+					PLAT_MAX_RET_STATE;
+	} else {
+		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					PLAT_MAX_OFF_STATE;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		clr_ex();
+		isb();
+		dsbsy();
+
+		gicv2_cpuif_disable();
+
+		hisi_cpuidle_lock(cluster, core);
+		hisi_set_cpuidle_flag(cluster, core);
+		hisi_cpuidle_unlock(cluster, core);
+
+		mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
+		      hikey960_sec_entrypoint >> 2);
+
+		hisi_enter_core_idle(cluster, core);
+	}
+
+	/* Perform the common cluster specific operations */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		hisi_cpuidle_lock(cluster, core);
+		hisi_disable_pdc(cluster);
+
+		/* check if any core is powered up */
+		if (hisi_test_pwrdn_allcores(cluster, core)) {
+
+			cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+			isb();
+			dsbsy();
+
+			/* mask the pdc wakeup irq, then
+			 * enable pdc to power down the core
+			 */
+			hisi_pdc_mask_cluster_wakeirq(cluster);
+			hisi_enable_pdc(cluster);
+
+			hisi_cpuidle_unlock(cluster, core);
+
+			/* check the SR flag bit to determine
+			 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
+			 */
+			if (hisi_test_ap_suspend_flag())
+				hisi_enter_ap_suspend(cluster, core);
+			else
+				hisi_enter_cluster_idle(cluster, core);
+		} else {
+			/* enable pdc */
+			hisi_enable_pdc(cluster);
+			hisi_cpuidle_unlock(cluster, core);
+		}
+	}
+}
+
+static void hikey960_sr_dma_reinit(void)
+{
+	unsigned int ctr = 0;
+
+	mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
+
+	/* 1~15 channel is set non_secure */
+	for (ctr = 1; ctr <= 15; ctr++)
+		mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
+			      (1 << 6) | (1 << 18));
+}
+
+static void
+hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	/* Nothing to be done on waking up from retention from CPU level */
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	hisi_cpuidle_lock(cluster, core);
+	hisi_clear_cpuidle_flag(cluster, core);
+	hisi_cpuidle_unlock(cluster, core);
+
+	if (hisi_test_ap_suspend_flag()) {
+		hikey960_sr_dma_reinit();
+		gicv2_cpuif_enable();
+		console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ,
+				       PL011_BAUDRATE, &console);
+	}
+
+	hikey960_pwr_domain_on_finish(target_state);
+}
+
+static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static const plat_psci_ops_t hikey960_psci_ops = {
+	.cpu_standby			= hikey960_pwr_domain_standby,
+	.pwr_domain_on			= hikey960_pwr_domain_on,
+	.pwr_domain_on_finish		= hikey960_pwr_domain_on_finish,
+	.pwr_domain_off			= hikey960_pwr_domain_off,
+	.pwr_domain_suspend		= hikey960_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= hikey960_pwr_domain_suspend_finish,
+	.system_off			= NULL,
+	.system_reset			= hikey960_system_reset,
+	.validate_power_state		= hikey960_validate_power_state,
+	.validate_ns_entrypoint		= hikey960_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= hikey960_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	unsigned int id = 0;
+	int ret;
+
+	ret = hikey960_read_boardid(&id);
+	if (ret == 0) {
+		if (id == 5300U)
+			uart_base = PL011_UART5_BASE;
+		else
+			uart_base = PL011_UART6_BASE;
+	} else {
+		uart_base = PL011_UART6_BASE;
+	}
+
+	hikey960_sec_entrypoint = sec_entrypoint;
+
+	INFO("%s: sec_entrypoint=0x%lx\n", __func__,
+	     (unsigned long)hikey960_sec_entrypoint);
+
+	/*
+	 * Initialize PSCI ops struct
+	 */
+	*psci_ops = &hikey960_psci_ops;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_private.h b/plat/hisilicon/hikey960/hikey960_private.h
new file mode 100644
index 0000000..9a18dd6
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_private.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HIKEY960_PRIVATE_H
+#define HIKEY960_PRIVATE_H
+
+#include <common/bl_common.h>
+
+/*
+ * Function and variable prototypes
+ */
+void hikey960_init_mmu_el1(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey960_init_mmu_el3(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey960_io_setup(void);
+int hikey960_read_boardid(unsigned int *id);
+void hikey960_clk_init(void);
+void hikey960_pmu_init(void);
+void hikey960_regulator_enable(void);
+void hikey960_tzc_init(void);
+void hikey960_peri_init(void);
+void hikey960_pinmux_init(void);
+void hikey960_gpio_init(void);
+void set_retention_ticks(unsigned int val);
+void clr_retention_ticks(unsigned int val);
+void clr_ex(void);
+void nop(void);
+
+#endif /* HIKEY960_PRIVATE_H */
diff --git a/plat/hisilicon/hikey960/hikey960_rotpk.S b/plat/hisilicon/hikey960/hikey960_rotpk.S
new file mode 100644
index 0000000..f230ed6
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global hikey960_rotpk_hash
+	.global hikey960_rotpk_hash_end
+	.section .rodata.hikey960_rotpk_hash, "a"
+hikey960_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+hikey960_rotpk_hash_end:
diff --git a/plat/hisilicon/hikey960/hikey960_tbbr.c b/plat/hisilicon/hikey960/hikey960_tbbr.c
new file mode 100644
index 0000000..ed4da3b
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_tbbr.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char hikey960_rotpk_hash[], hikey960_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = hikey960_rotpk_hash;
+	*key_len = hikey960_rotpk_hash_end - hikey960_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_topology.c b/plat/hisilicon/hikey960/hikey960_topology.c
new file mode 100644
index 0000000..a242bb1
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_topology.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+/*
+ * The HiKey power domain tree descriptor. The cluster power domains
+ * are arranged so that when the PSCI generic code creates the power
+ * domain tree, the indices of the CPU power domain nodes it allocates
+ * match the linear indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char hikey960_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	1,
+	/* Number of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the second cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+/*******************************************************************************
+ * This function returns the HiKey topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return hikey960_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/hisilicon/hikey960/include/hi3660.h b/plat/hisilicon/hikey960/include/hi3660.h
new file mode 100644
index 0000000..7cc1ee0
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef HI3660_H
+#define HI3660_H
+
+#include <hi3660_crg.h>
+#include <hi3660_hkadc.h>
+#include <hi3660_mem_map.h>
+
+#define ASP_CFG_REG_BASE		0xE804E000
+
+#define ASP_CFG_MMBUF_CTRL_REG		(ASP_CFG_REG_BASE + 0x148)
+
+#define LP_RAM_BASE			0xFFF50000
+
+#define SCTRL_REG_BASE			0xFFF0A000
+
+#define SCTRL_CONTROL_REG		(SCTRL_REG_BASE + 0x000)
+#define SCTRL_CONTROL_SYS_MODE(x)	(((x) & 0xf) << 3)
+#define SCTRL_CONTROL_SYS_MODE_NORMAL	((1 << 2) << 3)
+#define SCTRL_CONTROL_SYS_MODE_SLOW	((1 << 1) << 3)
+#define SCTRL_CONTROL_SYS_MODE_MASK	(0xf << 3)
+#define SCTRL_CONTROL_MODE_CTRL_NORMAL	(1 << 2)
+#define SCTRL_CONTROL_MODE_CTRL_SLOW	(1 << 1)
+#define SCTRL_CONTROL_MODE_CTRL_MASK	0x7
+
+#define SCTRL_SCSYSSTAT_REG		(SCTRL_REG_BASE + 0x004)
+
+#define SCTRL_DEEPSLEEPED_REG		(SCTRL_REG_BASE + 0x008)
+#define SCTRL_EFUSE_USB_MASK		(1 << 30)
+#define SCTRL_EFUSE_USB_PLL		(1 << 30)
+#define SCTRL_EFUSE_USB_ABB		(0 << 30)
+#define SCTRL_EFUSE_UFS_MASK		(3 << 6)
+#define SCTRL_EFUSE_UFS_PLL		(1 << 6)
+#define SCTRL_EFUSE_UFS_ABB		(0 << 6)
+
+#define SCTRL_SCISOEN_REG		(SCTRL_REG_BASE + 0x040)
+#define SCTRL_SCISODIS_REG		(SCTRL_REG_BASE + 0x044)
+#define SCISO_MMBUFISO			(1 << 3)
+
+#define SCTRL_SCPWREN_REG		(SCTRL_REG_BASE + 0x060)
+#define SCPWREN_MMBUFPWREN		(1 << 3)
+
+#define SCTRL_PLL_CTRL0_REG		(SCTRL_REG_BASE + 0x100)
+#define SCTRL_PLL0_POSTDIV2(x)		(((x) & 0x7) << 23)
+#define SCTRL_PLL0_POSTDIV1(x)		(((x) & 0x7) << 20)
+#define SCTRL_PLL0_FBDIV(x)		(((x) & 0xfff) << 8)
+#define SCTRL_PLL0_REFDIV(x)		(((x) & 0x3f) << 2)
+#define SCTRL_PLL0_EN			(1 << 0)
+
+#define SCTRL_PLL_CTRL1_REG		(SCTRL_REG_BASE + 0x104)
+#define SCTRL_PLL0_CLK_NO_GATE		(1 << 26)
+#define SCTRL_PLL0_CFG_VLD		(1 << 25)
+#define SCTRL_PLL0_FRACDIV(x)		((x) & 0xFFFFFF)
+
+#define SCTRL_PLL_STAT_REG		(SCTRL_REG_BASE + 0x10C)
+#define SCTRL_PLL0_STAT			(1 << 0)
+
+#define SCTRL_SCPEREN0_REG		(SCTRL_REG_BASE + 0x160)
+#define SCTRL_SCPERDIS0_REG		(SCTRL_REG_BASE + 0x164)
+#define SCTRL_SCPERSTAT0_REG		(SCTRL_REG_BASE + 0x168)
+
+#define SCTRL_SCPEREN1_REG		(SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG		(SCTRL_REG_BASE + 0x174)
+#define SCTRL_SCPEREN1_REG		(SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG		(SCTRL_REG_BASE + 0x174)
+#define SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS	(1u << 31)
+#define SCPEREN_GT_PCLK_MMBUFCFG	(1 << 25)
+#define SCPEREN_GT_PCLK_MMBUF		(1 << 23)
+#define SCPEREN_GT_ACLK_MMBUF		(1 << 22)
+#define SCPEREN_GT_CLK_NOC_AOBUS2MMBUF	(1 << 6)
+
+#define SCTRL_SCPEREN2_REG		(SCTRL_REG_BASE + 0x190)
+#define SCTRL_SCPERDIS2_REG		(SCTRL_REG_BASE + 0x194)
+#define SCTRL_SCPERSTAT2_REG		(SCTRL_REG_BASE + 0x198)
+#define SCTRL_SCPERRSTEN0_REG		(SCTRL_REG_BASE + 0x200)
+#define SCTRL_SCPERRSTDIS0_REG		(SCTRL_REG_BASE + 0x204)
+#define SCTRL_SCPERRSTSTAT0_REG		(SCTRL_REG_BASE + 0x208)
+#define SCTRL_SCPERRSTEN1_REG		(SCTRL_REG_BASE + 0x20C)
+#define SCTRL_SCPERRSTDIS1_REG		(SCTRL_REG_BASE + 0x210)
+#define SCTRL_SCPERRSTSTAT1_REG		(SCTRL_REG_BASE + 0x214)
+#define IP_RST_MMBUFCFG			(1 << 12)
+#define IP_RST_MMBUF			(1 << 11)
+
+#define SCTRL_SCPERRSTEN2_REG		(SCTRL_REG_BASE + 0x218)
+#define SCTRL_SCPERRSTDIS2_REG		(SCTRL_REG_BASE + 0x21C)
+#define SCTRL_SCPERRSTSTAT2_REG		(SCTRL_REG_BASE + 0x220)
+
+#define SCTRL_SCCLKDIV2_REG		(SCTRL_REG_BASE + 0x258)
+#define SEL_CLK_MMBUF_MASK		(0x3 << 8)
+#define SEL_CLK_MMBUF_PLL0		(0x3 << 8)
+#define SCCLKDIV2_GT_PCLK_MMBUF		(1 << 7)
+
+#define SCTRL_SCCLKDIV4_REG		(SCTRL_REG_BASE + 0x260)
+#define GT_MMBUF_SYS			(1 << 13)
+#define GT_MMBUF_FLL			(1 << 12)
+#define GT_PLL_CLK_MMBUF		(1 << 11)
+
+#define SCTRL_SCCLKDIV6_REG		(SCTRL_REG_BASE + 0x268)
+
+#define SCTRL_SCPERCTRL7_REG		(SCTRL_REG_BASE + 0x31C)
+#define SCTRL_SCPERSTAT6_REG		(SCTRL_REG_BASE + 0x378)
+
+#define SCTRL_SCINNERSTAT_REG		(SCTRL_REG_BASE + 0x3A0)
+#define EMMC_UFS_SEL			(1 << 15)
+
+#define SCTRL_BAK_DATA0_REG		(SCTRL_REG_BASE + 0x40C)
+#define SCTRL_BAK_DATA4_REG		(SCTRL_REG_BASE + 0x41C)
+
+#define SCTRL_LPMCU_CLKEN_REG		(SCTRL_REG_BASE + 0x480)
+#define SCTRL_LPMCU_CLKDIS_REG		(SCTRL_REG_BASE + 0x484)
+#define SCTRL_LPMCU_RSTEN_REG		(SCTRL_REG_BASE + 0x500)
+#define SCTRL_LPMCU_RSTDIS_REG		(SCTRL_REG_BASE + 0x504)
+#define DDRC_SOFT_BIT			(1 << 6)
+#define DDRC_CLK_BIT			(1 << 5)
+
+#define SCTRL_SCPEREN0_SEC_REG		(SCTRL_REG_BASE + 0x900)
+#define SCTRL_SCPERDIS0_SEC_REG		(SCTRL_REG_BASE + 0x904)
+#define MMBUF_SEC_CTRL_MASK		(0xfff << 20)
+#define MMBUF_SEC_CTRL(x)		(((x) & 0xfff) << 20)
+
+#define SCTRL_PERRSTEN1_SEC_REG		(SCTRL_REG_BASE + 0xA50)
+#define SCTRL_PERRSTDIS1_SEC_REG	(SCTRL_REG_BASE + 0xA54)
+#define SCTRL_PERRSTSTAT1_SEC_REG	(SCTRL_REG_BASE + 0xA58)
+#define RST_ASP_SUBSYS_BIT		(1 << 0)
+
+#define SCTRL_PERRSTEN2_SEC_REG		(SCTRL_REG_BASE + 0xB50)
+#define SCTRL_PERRSTDIS2_SEC_REG	(SCTRL_REG_BASE + 0xB54)
+#define SCTRL_PERRSTSTAT2_SEC_REG	(SCTRL_REG_BASE + 0xB58)
+
+#define SCTRL_HISEECLKDIV_REG		(SCTRL_REG_BASE + 0xC28)
+#define SC_SEL_HISEE_PLL_MASK		(1 << 4)
+#define SC_SEL_HISEE_PLL0		(1 << 4)
+#define SC_SEL_HISEE_PLL2		(0 << 4)
+#define SC_DIV_HISEE_PLL_MASK		(7 << 16)
+#define SC_DIV_HISEE_PLL(x)		((x) & 0x7)
+
+#define SCTRL_SCSOCID0_REG		(SCTRL_REG_BASE + 0xE00)
+
+#define PMC_REG_BASE			0xFFF31000
+#define PMC_PPLL1_CTRL0_REG		(PMC_REG_BASE + 0x038)
+#define PMC_PPLL1_CTRL1_REG		(PMC_REG_BASE + 0x03C)
+#define PMC_PPLL2_CTRL0_REG		(PMC_REG_BASE + 0x040)
+#define PMC_PPLL2_CTRL1_REG		(PMC_REG_BASE + 0x044)
+#define PMC_PPLL3_CTRL0_REG		(PMC_REG_BASE + 0x048)
+#define PMC_PPLL3_CTRL1_REG		(PMC_REG_BASE + 0x04C)
+#define PPLLx_LOCK			(1 << 26)
+#define PPLLx_WITHOUT_CLK_GATE		(1 << 26)
+#define PPLLx_CFG_VLD			(1 << 25)
+#define PPLLx_INT_MOD			(1 << 24)
+#define PPLLx_POSTDIV2_MASK		(0x7 << 23)
+#define PPLLx_POSTDIV2(x)		(((x) & 0x7) << 23)
+#define PPLLx_POSTDIV1_MASK		(0x7 << 20)
+#define PPLLx_POSTDIV1(x)		(((x) & 0x7) << 20)
+#define PPLLx_FRACDIV_MASK		(0x00FFFFFF)
+#define PPLLx_FRACDIV(x)		((x) & 0x00FFFFFF)
+#define PPLLx_FBDIV_MASK		(0xfff << 8)
+#define PPLLx_FBDIV(x)			(((x) & 0xfff) << 8)
+#define PPLLx_REFDIV_MASK		(0x3f << 2)
+#define PPLLx_REFDIV(x)			(((x) & 0x3f) << 2)
+#define PPLLx_BP			(1 << 1)
+#define PPLLx_EN			(1 << 0)
+
+#define PMC_DDRLP_CTRL_REG		(PMC_REG_BASE + 0x30C)
+#define DDRC_CSYSREQ_CFG(x)		((x) & 0xF)
+
+#define PMC_NOC_POWER_IDLEREQ_REG	(PMC_REG_BASE + 0x380)
+#define PMC_NOC_POWER_IDLEREQ_IVP	(1 << 14)
+#define PMC_NOC_POWER_IDLEREQ_DSS	(1 << 13)
+#define PMC_NOC_POWER_IDLEREQ_VENC	(1 << 11)
+#define PMC_NOC_POWER_IDLEREQ_VDEC	(1 << 10)
+#define PMC_NOC_POWER_IDLEREQ_ISP	(1 << 5)
+#define PMC_NOC_POWER_IDLEREQ_VCODEC	(1 << 4)
+#define DDRPHY_BYPASS_MODE		(1 << 0)
+
+#define PMC_NOC_POWER_IDLEACK_REG	(PMC_REG_BASE + 0x384)
+#define PMC_NOC_POWER_IDLE_REG		(PMC_REG_BASE + 0x388)
+
+#define PMU_SSI0_REG_BASE		0xFFF34000
+
+#define PMU_SSI0_LDO8_CTRL0_REG		(PMU_SSI0_REG_BASE + (0x68 << 2))
+#define LDO8_CTRL0_EN_1_8V		0x02
+
+#define PMU_SSI0_CLK_TOP_CTRL7_REG	(PMU_SSI0_REG_BASE + (0x10C << 2))
+#define NP_XO_ABB_DIG			(1 << 1)
+
+#define LP_CONFIG_REG_BASE		0xFFF3F000
+
+#define DMAC_BASE			0xFDF30000
+
+#define CCI400_REG_BASE			0xE8100000
+#define CCI400_SL_IFACE3_CLUSTER_IX	0
+#define CCI400_SL_IFACE4_CLUSTER_IX	1
+
+#define GICD_REG_BASE			0xE82B1000
+#define GICC_REG_BASE			0xE82B2000
+/*
+ * GIC400 interrupt handling related constants
+ */
+#define IRQ_SEC_PHY_TIMER		29
+#define IRQ_SEC_SGI_0			8
+#define IRQ_SEC_SGI_1			9
+#define IRQ_SEC_SGI_2			10
+#define IRQ_SEC_SGI_3			11
+#define IRQ_SEC_SGI_4			12
+#define IRQ_SEC_SGI_5			13
+#define IRQ_SEC_SGI_6			14
+#define IRQ_SEC_SGI_7			15
+#define IRQ_SEC_SGI_8			16
+
+#define IPC_REG_BASE			0xE896A000
+#define IPC_BASE			(IPC_REG_BASE)
+
+#define IOMG_REG_BASE			0xE896C000
+
+/* GPIO46: HUB 3.3V enable. active low */
+#define IOMG_044_REG			(IOMG_REG_BASE + 0x0B0)
+#define IOMG_UART5_RX_REG		(IOMG_REG_BASE + 0x0BC)
+#define IOMG_UART5_TX_REG		(IOMG_REG_BASE + 0x0C0)
+
+#define IOCG_REG_BASE			0xE896C800
+
+/* GPIO005: PMIC SSI. (2 << 4) */
+#define IOCG_006_REG			(IOCG_REG_BASE + 0x018)
+
+#define TIMER9_REG_BASE			0xE8A00000
+
+#define WDT0_REG_BASE			0xE8A06000
+#define WDT1_REG_BASE			0xE8A07000
+#define WDT_CONTROL_OFFSET		0x008
+#define WDT_LOCK_OFFSET			0xC00
+
+#define WDT_UNLOCK			0x1ACCE551
+#define WDT_LOCKED			1
+
+#define PCTRL_REG_BASE			0xE8A09000
+#define PCTRL_PERI_CTRL3_REG		(PCTRL_REG_BASE + 0x010)
+#define PCTRL_PERI_CTRL24_REG		(PCTRL_REG_BASE + 0x064)
+
+#define GPIO0_BASE			UL(0xE8A0B000)
+#define GPIO1_BASE			UL(0xE8A0C000)
+#define GPIO2_BASE			UL(0xE8A0D000)
+#define GPIO3_BASE			UL(0xE8A0E000)
+#define GPIO4_BASE			UL(0xE8A0F000)
+#define GPIO5_BASE			UL(0xE8A10000)
+#define GPIO6_BASE			UL(0xE8A11000)
+#define GPIO7_BASE			UL(0xE8A12000)
+#define GPIO8_BASE			UL(0xE8A13000)
+#define GPIO9_BASE			UL(0xE8A14000)
+#define GPIO10_BASE			UL(0xE8A15000)
+#define GPIO11_BASE			UL(0xE8A16000)
+#define GPIO12_BASE			UL(0xE8A17000)
+#define GPIO13_BASE			UL(0xE8A18000)
+#define GPIO14_BASE			UL(0xE8A19000)
+#define GPIO15_BASE			UL(0xE8A1A000)
+#define GPIO16_BASE			UL(0xE8A1B000)
+#define GPIO17_BASE			UL(0xE8A1C000)
+#define GPIO20_BASE			UL(0xE8A1F000)
+#define GPIO21_BASE			UL(0xE8A20000)
+
+#define TZC_REG_BASE			0xE8A21000
+#define TZC_STAT0_REG			(TZC_REG_BASE + 0x800)
+#define TZC_EN0_REG			(TZC_REG_BASE + 0x804)
+#define TZC_DIS0_REG			(TZC_REG_BASE + 0x808)
+#define TZC_STAT1_REG			(TZC_REG_BASE + 0x80C)
+#define TZC_EN1_REG			(TZC_REG_BASE + 0x810)
+#define TZC_DIS1_REG			(TZC_REG_BASE + 0x814)
+#define TZC_STAT2_REG			(TZC_REG_BASE + 0x818)
+#define TZC_EN2_REG			(TZC_REG_BASE + 0x81C)
+#define TZC_DIS2_REG			(TZC_REG_BASE + 0x820)
+#define TZC_STAT3_REG			(TZC_REG_BASE + 0x824)
+#define TZC_EN3_REG			(TZC_REG_BASE + 0x828)
+#define TZC_DIS3_REG			(TZC_REG_BASE + 0x82C)
+#define TZC_STAT4_REG			(TZC_REG_BASE + 0x830)
+#define TZC_EN4_REG			(TZC_REG_BASE + 0x834)
+#define TZC_DIS4_REG			(TZC_REG_BASE + 0x838)
+#define TZC_STAT5_REG			(TZC_REG_BASE + 0x83C)
+#define TZC_EN5_REG			(TZC_REG_BASE + 0x840)
+#define TZC_DIS5_REG			(TZC_REG_BASE + 0x844)
+#define TZC_STAT6_REG			(TZC_REG_BASE + 0x848)
+#define TZC_EN6_REG			(TZC_REG_BASE + 0x84C)
+#define TZC_DIS6_REG			(TZC_REG_BASE + 0x850)
+#define TZC_STAT7_REG			(TZC_REG_BASE + 0x854)
+#define TZC_EN7_REG			(TZC_REG_BASE + 0x858)
+#define TZC_DIS7_REG			(TZC_REG_BASE + 0x85C)
+#define TZC_STAT8_REG			(TZC_REG_BASE + 0x860)
+#define TZC_EN8_REG			(TZC_REG_BASE + 0x864)
+#define TZC_DIS8_REG			(TZC_REG_BASE + 0x868)
+
+#define MMBUF_BASE			0xEA800000
+
+#define ACPU_DMCPACK0_BASE		0xEA900000
+
+#define ACPU_DMCPACK1_BASE		0xEA920000
+
+#define ACPU_DMCPACK2_BASE		0xEA940000
+
+#define ACPU_DMCPACK3_BASE		0xEA960000
+
+#define UART5_REG_BASE			0xFDF05000
+
+#define USB3OTG_REG_BASE		0xFF100000
+
+#define UFS_REG_BASE			0xFF3B0000
+
+#define UFS_SYS_REG_BASE		0xFF3B1000
+
+#define UFS_SYS_PSW_POWER_CTRL_REG	(UFS_SYS_REG_BASE + 0x004)
+#define UFS_SYS_PHY_ISO_EN_REG		(UFS_SYS_REG_BASE + 0x008)
+#define UFS_SYS_HC_LP_CTRL_REG		(UFS_SYS_REG_BASE + 0x00C)
+#define UFS_SYS_PHY_CLK_CTRL_REG	(UFS_SYS_REG_BASE + 0x010)
+#define UFS_SYS_PSW_CLK_CTRL_REG	(UFS_SYS_REG_BASE + 0x014)
+#define UFS_SYS_CLOCK_GATE_BYPASS_REG	(UFS_SYS_REG_BASE + 0x018)
+#define UFS_SYS_RESET_CTRL_EN_REG	(UFS_SYS_REG_BASE + 0x01C)
+#define UFS_SYS_MONITOR_HH_REG		(UFS_SYS_REG_BASE + 0x03C)
+#define UFS_SYS_UFS_SYSCTRL_REG		(UFS_SYS_REG_BASE + 0x05C)
+#define UFS_SYS_UFS_DEVICE_RESET_CTRL_REG	(UFS_SYS_REG_BASE + 0x060)
+#define UFS_SYS_UFS_APB_ADDR_MASK_REG	(UFS_SYS_REG_BASE + 0x064)
+
+#define BIT_UFS_PSW_ISO_CTRL			(1 << 16)
+#define BIT_UFS_PSW_MTCMOS_EN			(1 << 0)
+#define BIT_UFS_REFCLK_ISO_EN			(1 << 16)
+#define BIT_UFS_PHY_ISO_CTRL			(1 << 0)
+#define BIT_SYSCTRL_LP_ISOL_EN			(1 << 16)
+#define BIT_SYSCTRL_PWR_READY			(1 << 8)
+#define BIT_SYSCTRL_REF_CLOCK_EN		(1 << 24)
+#define MASK_SYSCTRL_REF_CLOCK_SEL		(3 << 8)
+#define MASK_SYSCTRL_CFG_CLOCK_FREQ		(0xFF)
+#define BIT_SYSCTRL_PSW_CLK_EN			(1 << 4)
+#define MASK_UFS_CLK_GATE_BYPASS		(0x3F)
+#define BIT_SYSCTRL_LP_RESET_N			(1 << 0)
+#define BIT_UFS_REFCLK_SRC_SE1			(1 << 0)
+#define MASK_UFS_SYSCTRL_BYPASS			(0x3F << 16)
+#define MASK_UFS_DEVICE_RESET			(1 << 16)
+#define BIT_UFS_DEVICE_RESET			(1 << 0)
+
+#define GPIO18_BASE			UL(0xFF3B4000)
+#define GPIO19_BASE			UL(0xFF3B5000)
+
+#define IOMG_FIX_REG_BASE		0xFF3B6000
+
+/* GPIO150: LED */
+#define IOMG_FIX_006_REG		(IOMG_FIX_REG_BASE + 0x018)
+/* GPIO151: LED */
+#define IOMG_FIX_007_REG		(IOMG_FIX_REG_BASE + 0x01C)
+
+#define IOMG_AO_REG_BASE		0xFFF11000
+
+/* GPIO189: LED */
+#define IOMG_AO_011_REG			(IOMG_AO_REG_BASE + 0x02C)
+/* GPIO190: LED */
+#define IOMG_AO_012_REG			(IOMG_AO_REG_BASE + 0x030)
+/* GPIO202: type C enable. active low */
+#define IOMG_AO_023_REG			(IOMG_AO_REG_BASE + 0x05C)
+/* GPIO206: USB switch. active low */
+#define IOMG_AO_026_REG			(IOMG_AO_REG_BASE + 0x068)
+/* GPIO219: PD interrupt. pull up */
+#define IOMG_AO_039_REG			(IOMG_AO_REG_BASE + 0x09C)
+/* GPIO213: PCIE_CLKREQ_N */
+#define IOMG_AO_033_REG			(IOMG_AO_REG_BASE + 0x084)
+
+#define IOCG_AO_REG_BASE		0xFFF1187C
+/* GPIO219: PD interrupt. pull up */
+#define IOCG_AO_043_REG			(IOCG_AO_REG_BASE + 0x030)
+
+#define EDMAC_BASE				0xfdf30000
+#define EDMAC_SEC_CTRL				(EDMAC_BASE + 0x694)
+#define EDMAC_AXI_CONF(x)			(EDMAC_BASE + 0x820 + (x << 6))
+#define EDMAC_SEC_CTRL_INTR_SEC			(1 << 1)
+#define EDMAC_SEC_CTRL_GLOBAL_SEC		(1 << 0)
+#define EDMAC_CHANNEL_NUMS				16
+
+#define IOMCU_DMAC_BASE			0xffd77000
+#define IOMCU_DMAC_SEC_CTRL		(IOMCU_DMAC_BASE + 0x694)
+#define IOMCU_DMAC_AXI_CONF(x)			(IOMCU_DMAC_BASE + 0x820 + ((x) << 6))
+#define IOMCU_DMAC_AXI_CONF_ARPROT_NS		(1 << 6)
+#define IOMCU_DMAC_AXI_CONF_AWPROT_NS		(1 << 18)
+#define IOMCU_DMAC_SEC_CTRL_INTR_SEC	(1 << 1)
+#define IOMCU_DMAC_SEC_CTRL_GLOBAL_SEC	(1 << 0)
+#define IOMCU_DMAC_CHANNEL_NUMS			8
+
+#endif /* HI3660_H */
diff --git a/plat/hisilicon/hikey960/include/hi3660_crg.h b/plat/hisilicon/hikey960/include/hi3660_crg.h
new file mode 100644
index 0000000..eb5a6c5
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_crg.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef HI3660_CRG_H
+#define HI3660_CRG_H
+
+#define CRG_REG_BASE			0xFFF35000
+
+#define CRG_PEREN0_REG			(CRG_REG_BASE + 0x000)
+#define CRG_PERDIS0_REG			(CRG_REG_BASE + 0x004)
+#define CRG_PERSTAT0_REG		(CRG_REG_BASE + 0x008)
+#define PEREN0_GT_CLK_AOMM		(1U << 31)
+
+#define CRG_PEREN1_REG			(CRG_REG_BASE + 0x010)
+#define CRG_PERDIS1_REG			(CRG_REG_BASE + 0x014)
+#define CRG_PERSTAT1_REG		(CRG_REG_BASE + 0x018)
+#define CRG_PEREN2_REG			(CRG_REG_BASE + 0x020)
+#define CRG_PERDIS2_REG			(CRG_REG_BASE + 0x024)
+#define CRG_PERSTAT2_REG		(CRG_REG_BASE + 0x028)
+#define PEREN2_HKADCSSI			(1 << 24)
+
+#define CRG_PEREN3_REG			(CRG_REG_BASE + 0x030)
+#define CRG_PERDIS3_REG			(CRG_REG_BASE + 0x034)
+
+#define CRG_PEREN4_REG			(CRG_REG_BASE + 0x040)
+#define CRG_PERDIS4_REG			(CRG_REG_BASE + 0x044)
+#define CRG_PERCLKEN4_REG		(CRG_REG_BASE + 0x048)
+#define CRG_PERSTAT4_REG		(CRG_REG_BASE + 0x04C)
+#define GT_ACLK_USB3OTG			(1 << 1)
+#define GT_CLK_USB3OTG_REF		(1 << 0)
+
+#define CRG_PEREN5_REG			(CRG_REG_BASE + 0x050)
+#define CRG_PERDIS5_REG			(CRG_REG_BASE + 0x054)
+#define CRG_PERSTAT5_REG		(CRG_REG_BASE + 0x058)
+#define CRG_PERRSTEN0_REG		(CRG_REG_BASE + 0x060)
+#define CRG_PERRSTDIS0_REG		(CRG_REG_BASE + 0x064)
+#define CRG_PERRSTSTAT0_REG		(CRG_REG_BASE + 0x068)
+#define CRG_PERRSTEN1_REG		(CRG_REG_BASE + 0x06C)
+#define CRG_PERRSTDIS1_REG		(CRG_REG_BASE + 0x070)
+#define CRG_PERRSTSTAT1_REG		(CRG_REG_BASE + 0x074)
+#define CRG_PERRSTEN2_REG		(CRG_REG_BASE + 0x078)
+#define CRG_PERRSTDIS2_REG		(CRG_REG_BASE + 0x07C)
+#define CRG_PERRSTSTAT2_REG		(CRG_REG_BASE + 0x080)
+#define PERRSTEN2_HKADCSSI		(1 << 24)
+
+#define CRG_PERRSTEN3_REG		(CRG_REG_BASE + 0x084)
+#define CRG_PERRSTDIS3_REG		(CRG_REG_BASE + 0x088)
+#define CRG_PERRSTSTAT3_REG		(CRG_REG_BASE + 0x08C)
+#define CRG_PERRSTEN4_REG		(CRG_REG_BASE + 0x090)
+#define CRG_PERRSTDIS4_REG		(CRG_REG_BASE + 0x094)
+#define CRG_PERRSTSTAT4_REG		(CRG_REG_BASE + 0x098)
+#define IP_RST_USB3OTG_MUX		(1 << 8)
+#define IP_RST_USB3OTG_AHBIF		(1 << 7)
+#define IP_RST_USB3OTG_32K		(1 << 6)
+#define IP_RST_USB3OTG			(1 << 5)
+#define IP_RST_USB3OTGPHY_POR		(1 << 3)
+
+#define CRG_PERRSTEN5_REG		(CRG_REG_BASE + 0x09C)
+#define CRG_PERRSTDIS5_REG		(CRG_REG_BASE + 0x0A0)
+#define CRG_PERRSTSTAT5_REG		(CRG_REG_BASE + 0x0A4)
+
+/* bit fields in CRG_PERI */
+#define PERI_PCLK_PCTRL_BIT		(1U << 31)
+#define PERI_TIMER12_BIT		(1 << 25)
+#define PERI_TIMER11_BIT		(1 << 24)
+#define PERI_TIMER10_BIT		(1 << 23)
+#define PERI_TIMER9_BIT			(1 << 22)
+#define PERI_UART5_BIT			(1 << 15)
+#define PERI_UFS_BIT			(1 << 12)
+#define PERI_ARST_UFS_BIT		(1 << 7)
+#define PERI_PPLL2_EN_CPU		(1 << 3)
+#define PERI_PWM_BIT			(1 << 0)
+#define PERI_DDRC_BIT			(1 << 0)
+#define PERI_DDRC_D_BIT			(1 << 4)
+#define PERI_DDRC_C_BIT			(1 << 3)
+#define PERI_DDRC_B_BIT			(1 << 2)
+#define PERI_DDRC_A_BIT			(1 << 1)
+#define PERI_DDRC_DMUX_BIT		(1 << 0)
+
+#define CRG_CLKDIV0_REG			(CRG_REG_BASE + 0x0A0)
+#define SC_DIV_LPMCU_MASK		((0x1F << 5) << 16)
+#define SC_DIV_LPMCU(x)			(((x) & 0x1F) << 5)
+
+#define CRG_CLKDIV1_REG			(CRG_REG_BASE + 0x0B0)
+#define SEL_LPMCU_PLL_MASK		((1 << 1) << 16)
+#define SEL_SYSBUS_MASK			((1 << 0) << 16)
+#define SEL_LPMCU_PLL1			(1 << 1)
+#define SEL_LPMCU_PLL0			(0 << 1)
+#define SEL_SYSBUS_PLL0			(1 << 0)
+#define SEL_SYSBUS_PLL1			(0 << 0)
+
+#define CRG_CLKDIV3_REG			(CRG_REG_BASE + 0x0B4)
+#define CRG_CLKDIV5_REG			(CRG_REG_BASE + 0x0BC)
+#define CRG_CLKDIV8_REG			(CRG_REG_BASE + 0x0C8)
+
+#define CRG_CLKDIV12_REG		(CRG_REG_BASE + 0x0D8)
+#define SC_DIV_A53HPM_MASK		(0x7 << 13)
+#define SC_DIV_A53HPM(x)		(((x) & 0x7) << 13)
+
+#define CRG_CLKDIV16_REG		(CRG_REG_BASE + 0x0E8)
+#define DDRC_CLK_SW_REQ_CFG_MASK	(0x3 << 12)
+#define DDRC_CLK_SW_REQ_CFG(x)		(((x) & 0x3) << 12)
+#define SC_DIV_UFSPHY_CFG_MASK		(0x3 << 9)
+#define SC_DIV_UFSPHY_CFG(x)		(((x) & 0x3) << 9)
+#define DDRCPLL_SW			(1 << 8)
+
+#define CRG_CLKDIV17_REG		(CRG_REG_BASE + 0x0EC)
+#define SC_DIV_UFS_PERIBUS		(1 << 14)
+
+#define CRG_CLKDIV18_REG		(CRG_REG_BASE + 0x0F0)
+#define CRG_CLKDIV19_REG		(CRG_REG_BASE + 0x0F4)
+#define CRG_CLKDIV20_REG		(CRG_REG_BASE + 0x0F8)
+#define CLKDIV20_GT_CLK_AOMM		(1 << 3)
+
+#define CRG_CLKDIV22_REG		(CRG_REG_BASE + 0x100)
+#define SEL_PLL_320M_MASK		(1 << 16)
+#define SEL_PLL2_320M			(1 << 0)
+#define SEL_PLL0_320M			(0 << 0)
+
+#define CRG_CLKDIV23_REG		(CRG_REG_BASE + 0x104)
+#define PERI_DDRC_SW_BIT		(1 << 13)
+#define DIV_CLK_DDRSYS_MASK		(0x3 << 10)
+#define DIV_CLK_DDRSYS(x)		(((x) & 0x3) << 10)
+#define GET_DIV_CLK_DDRSYS(x)		(((x) & DIV_CLK_DDRSYS_MASK) >> 10)
+#define DIV_CLK_DDRCFG_MASK		(0x6 << 5)
+#define DIV_CLK_DDRCFG(x)		(((x) & 0x6) << 5)
+#define GET_DIV_CLK_DDRCFG(x)		(((x) & DIV_CLK_DDRCFG_MASK) >> 5)
+#define DIV_CLK_DDRC_MASK		0x1F
+#define DIV_CLK_DDRC(x)			((x) & DIV_CLK_DDRC_MASK)
+#define GET_DIV_CLK_DDRC(x)		((x) & DIV_CLK_DDRC_MASK)
+
+#define CRG_CLKDIV25_REG		(CRG_REG_BASE + 0x10C)
+#define DIV_SYSBUS_PLL_MASK		(0xF << 16)
+#define DIV_SYSBUS_PLL(x)		((x) & 0xF)
+
+#define CRG_PERI_CTRL2_REG		(CRG_REG_BASE + 0x128)
+#define PERI_TIME_STAMP_CLK_MASK	(0x7 << 28)
+#define PERI_TIME_STAMP_CLK_DIV(x)	(((x) & 0x7) << 22)
+
+#define CRG_ISODIS_REG			(CRG_REG_BASE + 0x148)
+#define CRG_PERPWREN_REG		(CRG_REG_BASE + 0x150)
+
+#define CRG_PEREN7_REG			(CRG_REG_BASE + 0x420)
+#define CRG_PERDIS7_REG			(CRG_REG_BASE + 0x424)
+#define CRG_PERSTAT7_REG		(CRG_REG_BASE + 0x428)
+#define GT_CLK_UFSPHY_CFG		(1 << 14)
+
+#define CRG_PEREN8_REG			(CRG_REG_BASE + 0x430)
+#define CRG_PERDIS8_REG			(CRG_REG_BASE + 0x434)
+#define CRG_PERSTAT8_REG		(CRG_REG_BASE + 0x438)
+#define PERI_DMC_D_BIT			(1 << 22)
+#define PERI_DMC_C_BIT			(1 << 21)
+#define PERI_DMC_B_BIT			(1 << 20)
+#define PERI_DMC_A_BIT			(1 << 19)
+#define PERI_DMC_BIT			(1 << 18)
+
+#define CRG_PEREN11_REG			(CRG_REG_BASE + 0x460)
+#define PPLL1_GATE_CPU			(1 << 18)
+
+#define CRG_PERSTAT11_REG		(CRG_REG_BASE + 0x46C)
+#define PPLL3_EN_STAT			(1 << 21)
+#define PPLL2_EN_STAT			(1 << 20)
+#define PPLL1_EN_STAT			(1 << 19)
+
+#define CRG_IVP_SEC_RSTDIS_REG		(CRG_REG_BASE + 0xC04)
+#define CRG_ISP_SEC_RSTDIS_REG		(CRG_REG_BASE + 0xC84)
+
+#define CRG_RVBAR(c, n)			(0xE00 + (0x10 * c) + (0x4 * n))
+#define CRG_GENERAL_SEC_RSTEN_REG	(CRG_REG_BASE + 0xE20)
+#define CRG_GENERAL_SEC_RSTDIS_REG	(CRG_REG_BASE + 0xE24)
+#define IP_RST_GPIO0_SEC		(1 << 2)
+
+#define CRG_GENERAL_SEC_CLKDIV0_REG	(CRG_REG_BASE + 0xE90)
+#define SC_DIV_AO_HISE_MASK		3
+#define SC_DIV_AO_HISE(x)		((x) & 0x3)
+
+#endif /* HI3660_CRG_H */
diff --git a/plat/hisilicon/hikey960/include/hi3660_hkadc.h b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
new file mode 100644
index 0000000..dc9e813
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef HI3660_HKADC_H
+#define HI3660_HKADC_H
+
+#define HKADC_SSI_REG_BASE			0xE82B8000
+
+#define HKADC_DSP_START_REG			(HKADC_SSI_REG_BASE + 0x000)
+#define HKADC_WR_NUM_REG			(HKADC_SSI_REG_BASE + 0x008)
+#define HKADC_DSP_START_CLR_REG			(HKADC_SSI_REG_BASE + 0x01C)
+#define HKADC_WR01_DATA_REG			(HKADC_SSI_REG_BASE + 0x020)
+
+#define WR1_WRITE_MODE				(1U << 31)
+#define WR1_READ_MODE				(0 << 31)
+#define WR1_ADDR(x)				(((x) & 0x7F) << 24)
+#define WR1_DATA(x)				(((x) & 0xFF) << 16)
+#define WR0_WRITE_MODE				(1 << 15)
+#define WR0_READ_MODE				(0 << 15)
+#define WR0_ADDR(x)				(((x) & 0x7F) << 8)
+#define WR0_DATA(x)				((x) & 0xFF)
+
+#define HKADC_WR23_DATA_REG			(HKADC_SSI_REG_BASE + 0x024)
+#define HKADC_WR45_DATA_REG			(HKADC_SSI_REG_BASE + 0x028)
+#define HKADC_DELAY01_REG			(HKADC_SSI_REG_BASE + 0x030)
+#define HKADC_DELAY23_REG			(HKADC_SSI_REG_BASE + 0x034)
+#define HKADC_DELAY45_REG			(HKADC_SSI_REG_BASE + 0x038)
+#define HKADC_DSP_RD2_DATA_REG			(HKADC_SSI_REG_BASE + 0x048)
+#define HKADC_DSP_RD3_DATA_REG			(HKADC_SSI_REG_BASE + 0x04C)
+
+/* HKADC Internal Registers */
+#define HKADC_CTRL_ADDR				0x00
+#define HKADC_START_ADDR			0x01
+#define HKADC_DATA1_ADDR			0x03   /* high 8 bits */
+#define HKADC_DATA0_ADDR			0x04   /* low 8 bits */
+#define HKADC_MODE_CFG				0x0A
+
+#define HKADC_VALUE_HIGH			0x0FF0
+#define HKADC_VALUE_LOW				0x000F
+#define HKADC_VALID_VALUE			0x0FFF
+
+#define HKADC_CHANNEL_MAX			15
+#define HKADC_VREF_1V8				1800
+#define HKADC_ACCURACY				0x0FFF
+
+#define HKADC_WR01_VALUE			((HKADC_START_ADDR << 24) | \
+						 (0x1 << 16))
+#define HKADC_WR23_VALUE			((0x1u << 31) |		\
+						 (HKADC_DATA0_ADDR << 24) | \
+						 (1 << 15) |		\
+						 (HKADC_DATA1_ADDR << 8))
+#define HKADC_WR45_VALUE			(0x80)
+#define HKADC_CHANNEL0_DELAY01_VALUE		((0x0700 << 16) | 0xFFFF)
+#define HKADC_DELAY01_VALUE			((0x0700 << 16) | 0x0200)
+#define HKADC_DELAY23_VALUE			((0x00C8 << 16) | 0x00C8)
+#define START_DELAY_TIMEOUT			2000
+#define HKADC_WR_NUM_VALUE			4
+
+#endif /* HI3660_HKADC_H */
diff --git a/plat/hisilicon/hikey960/include/hi3660_mem_map.h b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
new file mode 100644
index 0000000..cadc4a4
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI3660_MEM_MAP_H
+#define HI3660_MEM_MAP_H
+
+#define HISI_DATA_HEAD_BASE		(0x89C44400)
+
+#define HISI_RESERVED_MEM_BASE		(0x89C80000)
+#define HISI_RESERVED_MEM_SIZE		(0x00040000)
+
+#define HISI_DATA0_BASE			(0x89C96180)
+#define HISI_DATA0_SIZE			(0x000003A0)
+#define HISI_DATA1_BASE			(0x89C93480)
+#define HISI_DATA1_SIZE			(0x00002D00)
+
+#endif /* HI3660_MEM_MAP_H */
diff --git a/plat/hisilicon/hikey960/include/hisi_ipc.h b/plat/hisilicon/hikey960/include/hisi_ipc.h
new file mode 100644
index 0000000..6a97968
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hisi_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HISI_IPC_H
+#define HISI_IPC_H
+
+enum pm_mode {
+	PM_ON = 0,
+	PM_OFF,
+};
+
+void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
+			enum pm_mode mode);
+void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
+			 unsigned int affinity_level);
+void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster);
+void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
+				unsigned int cmd_id);
+int hisi_ipc_init(void);
+
+#endif /* HISI_IPC_H */
diff --git a/plat/hisilicon/hikey960/include/plat_macros.S b/plat/hisilicon/hikey960/include/plat_macros.S
new file mode 100644
index 0000000..8765562
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <hi3660.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+	mov_imm	x16, GICD_REG_BASE
+	mov_imm	x17, GICC_REG_BASE
+
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to cosole */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+2:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	1f
+	bl	asm_print_hex
+	adr	x4, spacer
+	bl	asm_print_str
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+	adr	x4, newline
+	bl	asm_print_str
+	b	2b
+1:
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET(	\
+	                CCI400_SL_IFACE3_CLUSTER_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET(	\
+	                CCI400_SL_IFACE4_CLUSTER_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
new file mode 100644
index 0000000..f6edad6
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include "../hikey960_def.h"
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define HIKEY960_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+/*
+ * Generic platform constants
+ */
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE		0x1000
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_CACHE_LINE_SIZE	64
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CORE_COUNT_PER_CLUSTER	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_CORE_COUNT_PER_CLUSTER)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + 1)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+/* UFS RPMB and UFS User Data */
+#define MAX_IO_BLOCK_DEVICES		U(2)
+
+
+/*
+ * Platform memory map related constants
+ */
+
+/*
+ * BL1 specific defines.
+ */
+#define BL1_RO_BASE			(0x1AC00000)
+#define BL1_RO_LIMIT			(BL1_RO_BASE + 0x20000)
+#define BL1_RW_BASE			(BL1_RO_LIMIT)		/* 1AC2_0000 */
+#define BL1_RW_SIZE			(0x00188000)
+#define BL1_RW_LIMIT			(0x1B000000)
+
+/*
+ * BL2 specific defines.
+ */
+#define BL2_BASE			(0x1AC00000)
+#define BL2_LIMIT			(BL2_BASE + 0x58000)	/* 1AC5_8000 */
+
+/*
+ * BL31 specific defines.
+ */
+#define BL31_BASE			(BL2_LIMIT)		/* 1AC5_8000 */
+#define BL31_LIMIT			(BL31_BASE + 0x40000)	/* 1AC9_8000 */
+
+/*
+ * BL3-2 specific defines.
+ */
+
+/*
+ * The TSP currently executes from TZC secured area of DRAM.
+ */
+#define BL32_DRAM_BASE                  DDR_SEC_BASE
+#define BL32_DRAM_LIMIT                 (DDR_SEC_BASE+DDR_SEC_SIZE)
+
+#ifdef SPD_opteed
+/* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */
+#define HIKEY960_OPTEE_PAGEABLE_LOAD_BASE	(BL32_DRAM_LIMIT - HIKEY960_OPTEE_PAGEABLE_LOAD_SIZE) /* 0x3FC0_0000 */
+#define HIKEY960_OPTEE_PAGEABLE_LOAD_SIZE	0x400000 /* 4MB */
+#endif
+
+#if (HIKEY960_TSP_RAM_LOCATION_ID == HIKEY960_DRAM_ID)
+#define TSP_SEC_MEM_BASE		BL32_DRAM_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_DRAM_LIMIT - BL32_DRAM_BASE)
+#define BL32_BASE			BL32_DRAM_BASE
+#define BL32_LIMIT			BL32_DRAM_LIMIT
+#elif (HIKEY960_TSP_RAM_LOCATION_ID == HIKEY960_SRAM_ID)
+#error "SRAM storage of TSP payload is currently unsupported"
+#else
+#error "Currently unsupported HIKEY960_TSP_LOCATION_ID value"
+#endif
+
+/* BL32 is mandatory in AArch32 */
+#ifdef __aarch64__
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+#endif
+
+#define NS_BL1U_BASE			(BL31_LIMIT)		/* 1AC9_8000 */
+#define NS_BL1U_SIZE			(0x00100000)
+#define NS_BL1U_LIMIT			(NS_BL1U_BASE + NS_BL1U_SIZE)
+
+#define HIKEY960_NS_IMAGE_OFFSET	(0x1AC28000)	/* offset in l-loader */
+#define HIKEY960_NS_TMP_OFFSET		(0x1AE00000)
+
+#define SCP_BL2_BASE			(0x89C80000)
+#define SCP_BL2_SIZE			(0x00040000)
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || defined(IMAGE_BL32)
+#define MAX_XLAT_TABLES			3
+#endif
+
+#ifdef IMAGE_BL2
+#define MAX_XLAT_TABLES			4
+#endif
+
+#define MAX_MMAP_REGIONS		16
+
+/*
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ */
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
new file mode 100644
index 0000000..4f2c3c6
--- /dev/null
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -0,0 +1,149 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Non-TF Boot ROM
+BL2_AT_EL3	:=	1
+
+# On Hikey960, the TSP can execute from TZC secure area in DRAM.
+HIKEY960_TSP_RAM_LOCATION	?=	dram
+ifeq (${HIKEY960_TSP_RAM_LOCATION}, dram)
+  HIKEY960_TSP_RAM_LOCATION_ID = HIKEY960_DRAM_ID
+else ifeq (${HIKEY960_TSP_RAM_LOCATION}, sram)
+  HIKEY960_TSP_RAM_LOCATION_ID = HIKEY960_SRAM_ID
+else
+  $(error "Currently unsupported HIKEY960_TSP_RAM_LOCATION value")
+endif
+
+CRASH_CONSOLE_BASE		:=	PL011_UART6_BASE
+COLD_BOOT_SINGLE_CPU		:=	1
+PLAT_PL061_MAX_GPIOS		:=	176
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+ENABLE_SVE_FOR_NS		:=	0
+
+# Process flags
+$(eval $(call add_define,HIKEY960_TSP_RAM_LOCATION_ID))
+$(eval $(call add_define,CRASH_CONSOLE_BASE))
+$(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
+endif
+
+USE_COHERENT_MEM	:=	1
+
+PLAT_INCLUDES		:=	-Iplat/hisilicon/hikey960/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/arm/pl011/aarch64/pl011_console.S \
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				lib/xlat_tables/aarch64/xlat_tables.c	\
+				lib/xlat_tables/xlat_tables_common.c	\
+				plat/hisilicon/hikey960/aarch64/hikey960_common.c \
+				plat/hisilicon/hikey960/hikey960_boardid.c
+
+HIKEY960_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+BL1_SOURCES		+=	bl1/tbbr/tbbr_img_desc.c		\
+				drivers/arm/pl061/pl061_gpio.c		\
+				drivers/gpio/gpio.c			\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/synopsys/ufs/dw_ufs.c		\
+				drivers/ufs/ufs.c 			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl1_setup.c \
+				plat/hisilicon/hikey960/hikey960_bl_common.c \
+				plat/hisilicon/hikey960/hikey960_io_storage.c \
+				${HIKEY960_GIC_SOURCES}
+
+BL2_SOURCES		+=	common/desc_image_load.c		\
+				drivers/arm/pl061/pl061_gpio.c		\
+				drivers/gpio/gpio.c			\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/synopsys/ufs/dw_ufs.c		\
+				drivers/ufs/ufs.c			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c \
+				plat/hisilicon/hikey960/hikey960_bl2_setup.c \
+				plat/hisilicon/hikey960/hikey960_bl_common.c \
+				plat/hisilicon/hikey960/hikey960_image_load.c \
+				plat/hisilicon/hikey960/hikey960_io_storage.c \
+				plat/hisilicon/hikey960/hikey960_mcu_load.c
+
+ifeq (${SPD},opteed)
+BL2_SOURCES		+=	lib/optee/optee_utils.c
+endif
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				lib/cpus/aarch64/cortex_a53.S           \
+				lib/cpus/aarch64/cortex_a72.S		\
+				lib/cpus/aarch64/cortex_a73.S		\
+				plat/common/plat_psci_common.c  \
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl31_setup.c \
+				plat/hisilicon/hikey960/hikey960_pm.c	\
+				plat/hisilicon/hikey960/hikey960_topology.c \
+				plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c \
+				plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c \
+				${HIKEY960_GIC_SOURCES}
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+AUTH_SOURCES		:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c
+
+BL1_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/hisilicon/hikey960/hikey960_tbbr.c	\
+				plat/hisilicon/hikey960/hikey960_rotpk.S
+
+BL2_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/hisilicon/hikey960/hikey960_tbbr.c	\
+				plat/hisilicon/hikey960/hikey960_rotpk.S
+
+ROT_KEY		=	$(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH		=	$(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl1/hikey960_rotpk.o: $(ROTPK_HASH)
+$(BUILD_PLAT)/bl2/hikey960_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+# Enable workarounds for selected Cortex-A53 errata.
+ERRATA_A53_836870		:=	1
+ERRATA_A53_843419		:=	1
+ERRATA_A53_855873		:=	1
+
+FIP_ALIGN			:=	512
diff --git a/plat/hisilicon/poplar/aarch64/platform_common.c b/plat/hisilicon/poplar/aarch64/platform_common.c
new file mode 100644
index 0000000..fcd0a8b
--- /dev/null
+++ b/plat/hisilicon/poplar/aarch64/platform_common.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include "hi3798cv200.h"
+#include "platform_def.h"
+
+#define MAP_DDR		MAP_REGION_FLAT(DDR_BASE,			\
+					DDR_SIZE,			\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_DEVICE	MAP_REGION_FLAT(DEVICE_BASE,			\
+					DEVICE_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_TSP_MEM	MAP_REGION_FLAT(TSP_SEC_MEM_BASE,		\
+					TSP_SEC_MEM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#ifdef SPD_opteed
+#define MAP_OPTEE_PAGEABLE	MAP_REGION_FLAT(		\
+				POPLAR_OPTEE_PAGEABLE_LOAD_BASE,	\
+				POPLAR_OPTEE_PAGEABLE_LOAD_SIZE,	\
+				MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+static const mmap_region_t poplar_mmap[] = {
+	MAP_DDR,
+	MAP_DEVICE,
+	MAP_TSP_MEM,
+#ifdef SPD_opteed
+	MAP_OPTEE_PAGEABLE,
+#endif
+	{0}
+};
+
+#define DEFINE_CONFIGURE_MMU_EL(_el)					\
+	void plat_configure_mmu_el##_el(unsigned long total_base,	\
+				  unsigned long total_size,		\
+				  unsigned long ro_start,		\
+				  unsigned long ro_limit,		\
+				  unsigned long coh_start,		\
+				  unsigned long coh_limit)		\
+	{								\
+		mmap_add_region(total_base, total_base,			\
+				total_size,				\
+				MT_MEMORY | MT_RW | MT_SECURE);		\
+		mmap_add_region(ro_start, ro_start,			\
+				ro_limit - ro_start,			\
+				MT_MEMORY | MT_RO | MT_SECURE);		\
+		mmap_add_region(coh_start, coh_start,			\
+				coh_limit - coh_start,			\
+				MT_DEVICE | MT_RW | MT_SECURE);		\
+		mmap_add(poplar_mmap);					\
+		init_xlat_tables();					\
+									\
+		enable_mmu_el##_el(0);					\
+	}
+
+DEFINE_CONFIGURE_MMU_EL(3)
+DEFINE_CONFIGURE_MMU_EL(1)
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
diff --git a/plat/hisilicon/poplar/aarch64/poplar_helpers.S b/plat/hisilicon/poplar/aarch64/poplar_helpers.S
new file mode 100644
index 0000000..928dbef
--- /dev/null
+++ b/plat/hisilicon/poplar/aarch64/poplar_helpers.S
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_my_core_pos
+	.globl	poplar_calc_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	platform_mem_init
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses poplar_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	poplar_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int poplar_calc_core_pos(u_register_t mpidr)
+	 *  Helper function to calculate the core position.
+	 *  With this function: CorePos = (ClusterId * 4) +
+	 *  				  CoreId
+	 * -----------------------------------------------------
+	 */
+func poplar_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc poplar_calc_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, POPLAR_CRASH_UART_BASE
+	mov_imm	x1, POPLAR_CRASH_UART_CLK_IN_HZ
+	mov_imm	x2, POPLAR_CONSOLE_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, POPLAR_CRASH_UART_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, POPLAR_CRASH_UART_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on ARM
+	 * platforms. The Secure RAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/hisilicon/poplar/bl1_plat_setup.c b/plat/hisilicon/poplar/bl1_plat_setup.c
new file mode 100644
index 0000000..08ad67c
--- /dev/null
+++ b/plat/hisilicon/poplar/bl1_plat_setup.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/arm/pl061_gpio.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/mmc.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "hi3798cv200.h"
+#include "plat_private.h"
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+static meminfo_t bl2_tzram_layout;
+static console_pl011_t console;
+
+/*
+ * Cannot use default weak implementation in bl1_main.c because BL1 RW data is
+ * not at the top of the secure memory.
+ */
+int bl1_plat_handle_post_image_load(unsigned int image_id)
+{
+	image_desc_t *image_desc;
+	entry_point_info_t *ep_info;
+
+	if (image_id != BL2_IMAGE_ID)
+		return 0;
+
+	/* Get the image descriptor */
+	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+	assert(image_desc != NULL);
+
+	/* Get the entry point info */
+	ep_info = &image_desc->ep_info;
+
+	bl2_tzram_layout.total_base = BL2_BASE;
+	bl2_tzram_layout.total_size = BL32_LIMIT - BL2_BASE;
+
+	flush_dcache_range((uintptr_t)&bl2_tzram_layout, sizeof(meminfo_t));
+
+	ep_info->args.arg1 = (uintptr_t)&bl2_tzram_layout;
+
+	VERBOSE("BL1: BL2 memory layout address = %p\n",
+		(void *)&bl2_tzram_layout);
+
+	return 0;
+}
+
+void bl1_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	console_pl011_register(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL1_RW_BASE;
+	bl1_tzram_layout.total_size = BL1_RW_SIZE;
+
+	INFO("BL1: 0x%lx - 0x%lx [size = %zu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+	     BL1_RAM_LIMIT - BL1_RAM_BASE);
+}
+
+void bl1_plat_arch_setup(void)
+{
+	plat_configure_mmu_el3(bl1_tzram_layout.total_base,
+			       bl1_tzram_layout.total_size,
+			       BL1_RO_BASE, /* l-loader and BL1 ROM */
+			       BL1_RO_LIMIT,
+			       BL_COHERENT_RAM_BASE,
+			       BL_COHERENT_RAM_END);
+}
+
+void bl1_platform_setup(void)
+{
+	int i;
+#if !POPLAR_RECOVERY
+	struct mmc_device_info info;
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE);
+#endif
+
+	generic_delay_timer_init();
+
+	pl061_gpio_init();
+	for (i = 0; i < GPIO_MAX; i++)
+		pl061_gpio_register(GPIO_BASE(i), i);
+
+#if !POPLAR_RECOVERY
+	/* SoC-specific emmc register are initialized/configured by bootrom */
+	INFO("BL1: initializing emmc\n");
+	info.mmc_dev_type = MMC_IS_EMMC;
+	dw_mmc_init(&params, &info);
+#endif
+
+	plat_io_setup();
+}
+
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	return BL2_IMAGE_ID;
+}
diff --git a/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c b/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c
new file mode 100644
index 0000000..f683d75
--- /dev/null
+++ b/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+	{
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+#endif /* SCP_BL2_BASE */
+
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+	{
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = EL3_PAYLOAD_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t,
+		    IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+	{
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL31_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+	    .ep_info.args.arg1 = POPLAR_BL31_PLAT_PARAM_VAL,
+#endif
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL31_BASE,
+	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+	    .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+	},
+
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+	{
+	    .image_id = BL32_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
+	    .ep_info.pc = BL32_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the pager image.
+	 */
+	{
+	    .image_id = BL32_EXTRA1_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the paged image.
+	 */
+	{
+	    .image_id = BL32_EXTRA2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+#ifdef SPD_opteed
+	    .image_info.image_base = POPLAR_OPTEE_PAGEABLE_LOAD_BASE,
+	    .image_info.image_max_size = POPLAR_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+	{
+	    .image_id = BL33_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+	    .ep_info.pc = PRELOADED_BL33_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+# else
+	    .ep_info.pc = PLAT_POPLAR_NS_IMAGE_OFFSET,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = PLAT_POPLAR_NS_IMAGE_OFFSET,
+	    .image_info.image_max_size = DDR_BASE + DDR_SIZE -
+					PLAT_POPLAR_NS_IMAGE_OFFSET,
+# endif /* PRELOADED_BL33_BASE */
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+#endif /* EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/hisilicon/poplar/bl2_plat_setup.c b/plat/hisilicon/poplar/bl2_plat_setup.c
new file mode 100644
index 0000000..cc9d975
--- /dev/null
+++ b/plat/hisilicon/poplar/bl2_plat_setup.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/partition/partition.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <drivers/mmc.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <plat/common/platform.h>
+
+#include "hi3798cv200.h"
+#include "plat_private.h"
+
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+static console_pl011_t console;
+
+/*******************************************************************************
+ * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
+ * Return 0 on success, -1 otherwise.
+ ******************************************************************************/
+int plat_poplar_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	/*
+	 * This platform has no SCP_BL2 yet
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t poplar_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL3-2 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+#ifdef __aarch64__
+uint32_t poplar_get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#else
+uint32_t poplar_get_spsr_for_bl33_entry(void)
+{
+	unsigned int hyp_status, mode, spsr;
+
+	hyp_status = GET_VIRT_EXT(read_id_pfr1());
+
+	mode = (hyp_status) ? MODE32_hyp : MODE32_svc;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1,
+			SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#endif /* __aarch64__ */
+
+int poplar_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#ifdef SPD_opteed
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+
+	assert(bl_mem_params);
+
+	switch (image_id) {
+#ifdef __aarch64__
+	case BL32_IMAGE_ID:
+#ifdef SPD_opteed
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+				&pager_mem_params->image_info,
+				&paged_mem_params->image_info);
+		if (err != 0) {
+			WARN("OPTEE header parse error.\n");
+		}
+
+		/*
+		 * OP-TEE expect to receive DTB address in x2.
+		 * This will be copied into x2 by dispatcher.
+		 * Set this (arg3) if necessary
+		 */
+		/* bl_mem_params->ep_info.args.arg3 = PLAT_HIKEY_DT_BASE; */
+#endif
+		bl_mem_params->ep_info.spsr = poplar_get_spsr_for_bl32_entry();
+		break;
+#endif
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = poplar_get_spsr_for_bl33_entry();
+		break;
+
+#ifdef SCP_BL2_BASE
+	case SCP_BL2_IMAGE_ID:
+		/* The subsequent handling of SCP_BL2 is platform specific */
+		err = plat_poplar_bl2_handle_scp_bl2(&bl_mem_params->image_info);
+		if (err) {
+			WARN("Failure in platform-specific handling of SCP_BL2 image.\n");
+		}
+		break;
+#endif
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return poplar_bl2_handle_post_image_load(image_id);
+}
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			       u_register_t arg2, u_register_t arg3)
+{
+	struct meminfo *mem_layout = (struct meminfo *)arg1;
+#if !POPLAR_RECOVERY
+	struct mmc_device_info info;
+
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE);
+#endif
+
+	console_pl011_register(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Enable arch timer */
+	generic_delay_timer_init();
+
+	bl2_tzram_layout = *mem_layout;
+
+#if !POPLAR_RECOVERY
+	/* SoC-specific emmc register are initialized/configured by bootrom */
+	INFO("BL2: initializing emmc\n");
+	info.mmc_dev_type = MMC_IS_EMMC;
+	dw_mmc_init(&params, &info);
+#endif
+
+	plat_io_setup();
+}
+
+void bl2_plat_arch_setup(void)
+{
+	plat_configure_mmu_el1(bl2_tzram_layout.total_base,
+			       bl2_tzram_layout.total_size,
+			       BL_CODE_BASE,
+			       BL_CODE_END,
+			       BL_COHERENT_RAM_BASE,
+			       BL_COHERENT_RAM_END);
+}
+
+void bl2_platform_setup(void)
+{
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return PLAT_POPLAR_NS_IMAGE_OFFSET;
+#endif
+}
diff --git a/plat/hisilicon/poplar/bl31_plat_setup.c b/plat/hisilicon/poplar/bl31_plat_setup.c
new file mode 100644
index 0000000..981ef37
--- /dev/null
+++ b/plat/hisilicon/poplar/bl31_plat_setup.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "hi3798cv200.h"
+#include "plat_private.h"
+
+#define TZPC_SEC_ATTR_CTRL_VALUE (0x9DB98D45)
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static console_pl011_t console;
+
+static void hisi_tzpc_sec_init(void)
+{
+	mmio_write_32(HISI_TZPC_SEC_ATTR_CTRL, TZPC_SEC_ATTR_CTRL_VALUE);
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type));
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+	/*
+	 * None of the images on the ARM development platforms can have 0x0
+	 * as the entrypoint
+	 */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup common to ARM standard platforms.
+ * Here is an opportunity to copy parameters passed by the calling EL (S-EL1
+ * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be
+ * done before the MMU is initialized so that the memory layout can be used
+ * while creating page tables. BL2 has flushed this information to memory, so
+ * we are guaranteed to pick up good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	void *from_bl2;
+
+	from_bl2 = (void *) arg0;
+
+	console_pl011_register(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ,
+			       PL011_BAUDRATE, &console);
+
+	/* Init console for crash report */
+	plat_crash_console_init();
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_image_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0)
+		panic();
+}
+
+void bl31_platform_setup(void)
+{
+	/* Init arch timer */
+	generic_delay_timer_init();
+
+	/* Init GIC distributor and CPU interface */
+	poplar_gic_driver_init();
+	poplar_gic_init();
+
+	/* Init security properties of IP blocks */
+	hisi_tzpc_sec_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	/* do nothing */
+}
+
+void bl31_plat_arch_setup(void)
+{
+	plat_configure_mmu_el3(BL31_BASE,
+			       (BL31_LIMIT - BL31_BASE),
+			       BL_CODE_BASE,
+			       BL_CODE_END,
+			       BL_COHERENT_RAM_BASE,
+			       BL_COHERENT_RAM_END);
+
+	INFO("Boot BL33 from 0x%lx for %llu Bytes\n",
+	     bl33_image_ep_info.pc, bl33_image_ep_info.args.arg2);
+}
diff --git a/plat/hisilicon/poplar/include/hi3798cv200.h b/plat/hisilicon/poplar/include/hi3798cv200.h
new file mode 100644
index 0000000..e31f4b3
--- /dev/null
+++ b/plat/hisilicon/poplar/include/hi3798cv200.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HI3798CV200_H
+#define HI3798CV200_H
+
+#include <lib/utils_def.h>
+
+/* PL011 */
+#define PL011_UART0_BASE		(0xF8B00000)
+#define PL011_BAUDRATE			(115200)
+#define PL011_UART0_CLK_IN_HZ		(75000000)
+
+/* Sys Counter */
+#define SYS_COUNTER_FREQ_IN_TICKS	(24000000)
+#define SYS_COUNTER_FREQ_IN_MHZ		(24)
+
+/* Timer */
+#define SEC_TIMER0_BASE			(0xF8008000)
+#define TIMER00_LOAD			(SEC_TIMER0_BASE + 0x000)
+#define TIMER00_VALUE			(SEC_TIMER0_BASE + 0x004)
+#define TIMER00_CONTROL			(SEC_TIMER0_BASE + 0x008)
+#define TIMER00_BGLOAD			(SEC_TIMER0_BASE + 0x018)
+
+#define SEC_TIMER2_BASE			(0xF8009000)
+#define TIMER20_LOAD			(SEC_TIMER2_BASE + 0x000)
+#define TIMER20_VALUE			(SEC_TIMER2_BASE + 0x004)
+#define TIMER20_CONTROL			(SEC_TIMER2_BASE + 0x008)
+#define TIMER20_BGLOAD			(SEC_TIMER2_BASE + 0x018)
+
+/* GPIO */
+#define	GPIO_MAX			(13)
+#define	GPIO_BASE(x)			(x != 5 ?			\
+					0xf820000 + x * 0x1000 : 0xf8004000)
+
+/* SCTL */
+#define REG_BASE_SCTL			(0xF8000000)
+#define REG_SC_GEN12			(0x00B0)
+
+/* CRG */
+#define REG_BASE_CRG			(0xF8A22000)
+#define REG_CPU_LP			(0x48)
+#define REG_CPU_RST			(0x50)
+#define REG_PERI_CRG39			(0x9C)
+#define REG_PERI_CRG40			(0xA0)
+
+/* MCI */
+#define REG_BASE_MCI			(0xF9830000)
+#define MCI_CDETECT			(0x50)
+#define MCI_VERID			(0x6C)
+#define MCI_VERID_VALUE			(0x5342250A)
+#define MCI_VERID_VALUE2		(0x5342270A)
+
+/* EMMC */
+#define REG_EMMC_PERI_CRG		REG_PERI_CRG40
+#define REG_SDCARD_PERI_CRG		REG_PERI_CRG39
+#define EMMC_CLK_MASK			(0x7 << 8)
+#define EMMC_SRST_REQ			(0x1 << 4)
+#define EMMC_CKEN			(0x1 << 1)
+#define EMMC_BUS_CKEN			(0x1 << 0)
+#define EMMC_CLK_100M			(0 << 8)
+#define EMMC_CLK_50M			(1 << 8)
+#define EMMC_CLK_25M			(2 << 8)
+
+#define EMMC_DESC_SIZE			U(0x00100000) /* 1MB */
+#define EMMC_INIT_PARAMS(base)				\
+	{	.bus_width = MMC_BUS_WIDTH_8,		\
+		.clk_rate = 25 * 1000 * 1000,		\
+		.desc_base = (base),	\
+		.desc_size = EMMC_DESC_SIZE,		\
+		.flags =  MMC_FLAG_CMD23,		\
+		.reg_base = REG_BASE_MCI,		\
+	}
+
+/* GIC-400 */
+#define GICD_BASE			(0xF1001000)
+#define GICC_BASE			(0xF1002000)
+#define GICR_BASE			(0xF1000000)
+
+/* FIQ platform related define */
+#define HISI_IRQ_SEC_SGI_0		8
+#define HISI_IRQ_SEC_SGI_1		9
+#define HISI_IRQ_SEC_SGI_2		10
+#define HISI_IRQ_SEC_SGI_3		11
+#define HISI_IRQ_SEC_SGI_4		12
+#define HISI_IRQ_SEC_SGI_5		13
+#define HISI_IRQ_SEC_SGI_6		14
+#define HISI_IRQ_SEC_SGI_7		15
+#define HISI_IRQ_SEC_PPI_0		29
+#define HISI_IRQ_SEC_TIMER0		60
+#define HISI_IRQ_SEC_TIMER1		50
+#define HISI_IRQ_SEC_TIMER2		52
+#define HISI_IRQ_SEC_TIMER3		88
+#define HISI_IRQ_SEC_AXI		110
+
+/* Watchdog */
+#define HISI_WDG0_BASE			(0xF8A2C000)
+
+#define HISI_TZPC_BASE			(0xF8A80000)
+#define HISI_TZPC_SEC_ATTR_CTRL		(HISI_TZPC_BASE + 0x10)
+
+#endif /* HI3798CV200_H */
diff --git a/plat/hisilicon/poplar/include/plat_macros.S b/plat/hisilicon/poplar/include/plat_macros.S
new file mode 100644
index 0000000..82d10c1
--- /dev/null
+++ b/plat/hisilicon/poplar/include/plat_macros.S
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.section .rodata.gic_reg_name, "aS"
+	.macro plat_crash_print_regs
+	nop
+	.endm
diff --git a/plat/hisilicon/poplar/include/plat_private.h b/plat/hisilicon/poplar/include/plat_private.h
new file mode 100644
index 0000000..a34f138
--- /dev/null
+++ b/plat/hisilicon/poplar/include/plat_private.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <common/bl_common.h>
+
+#include "hi3798cv200.h"
+
+void plat_configure_mmu_el3(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long ro_start,
+			    unsigned long ro_limit,
+			    unsigned long coh_start,
+			    unsigned long coh_limit);
+
+void plat_configure_mmu_el1(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long ro_start,
+			    unsigned long ro_limit,
+			    unsigned long coh_start,
+			    unsigned long coh_limit);
+
+void plat_io_setup(void);
+
+unsigned int poplar_calc_core_pos(u_register_t mpidr);
+
+void poplar_gic_driver_init(void);
+void poplar_gic_init(void);
+void poplar_gic_cpuif_enable(void);
+void poplar_gic_pcpu_init(void);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/hisilicon/poplar/include/platform_def.h b/plat/hisilicon/poplar/include/platform_def.h
new file mode 100644
index 0000000..9783f8d
--- /dev/null
+++ b/plat/hisilicon/poplar/include/platform_def.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include "hi3798cv200.h"
+#include "poplar_layout.h"		/* BL memory region sizes, etc */
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define POPLAR_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define POPLAR_CRASH_UART_BASE		PL011_UART0_BASE
+#define POPLAR_CRASH_UART_CLK_IN_HZ	PL011_UART0_CLK_IN_HZ
+#define POPLAR_CONSOLE_BAUDRATE		PL011_BAUDRATE
+
+/* Generic platform constants */
+#define PLATFORM_STACK_SIZE		(0x800)
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+#define BOOT_EMMC_NAME			"l-loader.bin"
+
+#define PLATFORM_CACHE_LINE_SIZE	(64)
+#define PLATFORM_CLUSTER_COUNT		(1)
+#define PLATFORM_CORE_COUNT		(4)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	(4)
+
+/* IO framework user */
+#define MAX_IO_DEVICES			(4)
+#define MAX_IO_HANDLES			(4)
+#define MAX_IO_BLOCK_DEVICES		U(2)
+
+/* Memory size options */
+#define POPLAR_DRAM_SIZE_1G	0
+#define POPLAR_DRAM_SIZE_2G	1
+
+/* Memory map related constants */
+#define DDR_BASE			(0x00000000)
+
+#if (POPLAR_DRAM_SIZE_ID == POPLAR_DRAM_SIZE_2G)
+#define DDR_SIZE			(0x80000000)
+#elif (POPLAR_DRAM_SIZE_ID == POPLAR_DRAM_SIZE_1G)
+#define DDR_SIZE			(0x40000000)
+#else
+#error "Currently unsupported POPLAR_DRAM_SIZE_ID value"
+#endif
+
+#define DEVICE_BASE			(0xF0000000)
+#define DEVICE_SIZE			(0x0F000000)
+
+#define TEE_SEC_MEM_BASE		(0x70000000)
+#define TEE_SEC_MEM_SIZE		(0x10000000)
+
+/* Memory location options for TSP */
+#define POPLAR_SRAM_ID	0
+#define POPLAR_DRAM_ID	1
+
+/*
+ * DDR for OP-TEE (26MB from 0x02400000 -0x04000000) is divided in several
+ * regions:
+ *   - Secure DDR (default is the top 16MB) used by OP-TEE
+ *   - Non-secure DDR (4MB) reserved for OP-TEE's future use
+ *   - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature
+ *   - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB)
+ */
+#define DDR_SEC_SIZE			0x01000000
+#define DDR_SEC_BASE			0x03000000
+
+/*
+ * BL3-2 specific defines.
+ */
+
+/*
+ * The TSP currently executes from TZC secured area of DRAM.
+ */
+#define BL32_DRAM_BASE			0x03000000
+#define BL32_DRAM_LIMIT			0x04000000
+
+#ifdef SPD_opteed
+/* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */
+#define POPLAR_OPTEE_PAGEABLE_LOAD_SIZE	0x400000 /* 4MB */
+#define POPLAR_OPTEE_PAGEABLE_LOAD_BASE	(BL32_DRAM_LIMIT - POPLAR_OPTEE_PAGEABLE_LOAD_SIZE) /* 0x03C0_0000 */
+#endif
+
+#if (POPLAR_TSP_RAM_LOCATION_ID == POPLAR_DRAM_ID)
+#define TSP_SEC_MEM_BASE		BL32_DRAM_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_DRAM_LIMIT - BL32_DRAM_BASE)
+#define BL32_BASE			BL32_DRAM_BASE
+#define BL32_LIMIT			BL32_DRAM_LIMIT
+#elif (POPLAR_TSP_RAM_LOCATION_ID == POPLAR_SRAM_ID)
+#error "SRAM storage of TSP payload is currently unsupported"
+#else
+#error "Currently unsupported POPLAR_TSP_LOCATION_ID value"
+#endif
+
+/* BL32 is mandatory in AArch32 */
+#ifdef __aarch64__
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+#endif
+
+#define POPLAR_EMMC_DATA_BASE U(0x02200000)
+#define POPLAR_EMMC_DATA_SIZE EMMC_DESC_SIZE
+#define POPLAR_EMMC_DESC_BASE (POPLAR_EMMC_DATA_BASE + POPLAR_EMMC_DATA_SIZE)
+#define POPLAR_EMMC_DESC_SIZE EMMC_DESC_SIZE
+
+#define PLAT_POPLAR_NS_IMAGE_OFFSET	0x37000000
+
+/* Page table and MMU setup constants */
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+#define MAX_XLAT_TABLES			(4)
+#define MAX_MMAP_REGIONS		(16)
+
+#define CACHE_WRITEBACK_SHIFT		(6)
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/* Power states */
+#define PLAT_MAX_PWR_LVL		(MPIDR_AFFLVL1)
+#define PLAT_MAX_OFF_STATE		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+
+/* Interrupt controller */
+#define POPLAR_GICD_BASE	GICD_BASE
+#define POPLAR_GICC_BASE	GICC_BASE
+
+#define POPLAR_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_TIMER0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_TIMER1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_TIMER2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_TIMER3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(HISI_IRQ_SEC_AXI, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#define POPLAR_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/hisilicon/poplar/include/poplar_layout.h b/plat/hisilicon/poplar/include/poplar_layout.h
new file mode 100644
index 0000000..03047f9
--- /dev/null
+++ b/plat/hisilicon/poplar/include/poplar_layout.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POPLAR_LAYOUT_H
+#define POPLAR_LAYOUT_H
+
+/*
+ * Boot memory layout definitions for the HiSilicon Poplar board
+ */
+
+/*
+ * When Poplar is powered on, boot ROM verifies the initial content of
+ * boot media, loads it into low memory, and begins executing it
+ * in 32-bit mode.  The image loaded is "l-loader.bin", which contains
+ * a small amount code along with an embedded ARM Trusted Firmware
+ * BL1 image.  The main purpose of "l-loader" is to prepare the
+ * processor to execute the BL1 image in 64-bit mode, and to trigger
+ * that execution.
+ *
+ * Also embedded in "l-loader.bin" is a FIP image that contains
+ * other ARM Trusted Firmware images:  BL2; BL31; and for BL33,
+ * U-Boot.  When BL1 executes, it unpacks the BL2 image from the FIP
+ * image into a region of memory set aside to hold it.  Similarly,
+ * BL2 unpacks BL31 into memory reserved for it, and unpacks U-Boot
+ * into high memory.
+ *
+ * Because the BL1 code is embedded in "l-loader", its base address
+ * in memory is derived from the base address of the "l-loader"
+ * text section, together with an offset.  Memory space for BL2 is
+ * reserved immediately following BL1, and memory space is reserved
+ * for BL31 after that.  ARM Trusted Firmware requires each of these
+ * memory regions to be aligned on page boundaries, so the size of
+ * each region is a multiple of a page size (ending in 000).  Note
+ * that ARM Trusted Firmware requires the read-only and read-write
+ * regions of memory used for BL1 to be defined separately.
+ *
+ *    ---------------------
+ *    |  (unused memory)  |
+ *    +-------------------+	- - - - -
+ *    |  (l-loader text)  |               \
+ *    +-------------------+                \
+ *    |  BL1 (read-only)  | \               \
+ *    |- - - - - - - - - -| |               |
+ *    |  BL1 (read-write) | |               |
+ *    +-------------------+  >  BL Memory   |
+ *    |  Reserved for BL2 | |                > "l-loader.bin" image
+ *    +-------------------+ |               |
+ *    | Reserved for BL31 | /               |
+ *    +-------------------+                 |
+ *           . . .                          /
+ *    +-------------------+                /
+ *    |        FIP        |               /
+ *    +-------------------+	- - - - -
+ *           . . .
+ *    |  (unused memory)  |
+ *           . . .
+ *    +-------------------+
+ *    |Reserved for U-Boot|
+ *    +-------------------+
+ *           . . .
+ *    |  (unused memory)  |
+ *    ---------------------
+ *
+ * The size of each of these regions is defined below.  The base
+ * address of the "l-loader" TEXT section and the offset of the BL1
+ * image within that serve as anchors for defining the positions of
+ * all other regions.  The FIP is placed in a section of its own.
+ *
+ * A "BASE" is the memory address of the start of a region; a "LIMIT"
+ * marks its end.  A "SIZE" is the size of a region (in bytes).  An
+ * "OFFSET" is an offset to the start of a region relative to the
+ * base of the "l-loader" TEXT section (also a multiple of page size).
+ */
+#define LLOADER_TEXT_BASE		0x02001000	/* page aligned */
+#define BL1_OFFSET			0x0000D000	/* page multiple */
+#define FIP_BASE			0x02040000
+
+/*
+ * FIP_BASE_EMMC = 0x40000 - 0x1000
+ * = fip.bin offset - l-loader text offset
+ * in l-loader.bin
+ */
+#define FIP_BASE_EMMC			0x0003f000
+
+#define BL1_RO_SIZE			0x00008000	/* page multiple */
+#define BL1_RW_SIZE			0x00008000	/* page multiple */
+#define BL1_SIZE			(BL1_RO_SIZE + BL1_RW_SIZE)
+#define BL2_SIZE			0x0000d000	/* page multiple */
+#define BL31_SIZE			0x00014000
+#if !POPLAR_RECOVERY
+/*
+ * emmc partition1 4096KB
+ * - l-loader.bin 1984KB
+ * |- l-loader + bl1.bin 256KB
+ * |- fip.bin 1728KB (0x001b0000)
+ * - u-boot persistent data 64KB
+ * - uefi persistent data 2048KB
+ */
+#define FIP_SIZE			0x001b0000  /* absolute max */
+#else
+/*
+ * same as above, but bootrom can only load an image (l-loader.bin) of
+ * 1024KB max, so after deducting the size of l-loader + bl1.bin (256KB),
+ * that leaves 768KB (0x000c0000) for fip.bin
+ */
+#define FIP_SIZE			0x000c0000  /* absolute max */
+#endif
+
+     /* BL1_OFFSET */			/* (Defined above) */
+#define BL1_BASE			(LLOADER_TEXT_BASE + BL1_OFFSET)
+#define BL1_LIMIT			(BL1_BASE + BL1_SIZE)
+
+#define BL1_RO_OFFSET			(BL1_OFFSET)
+#define BL1_RO_BASE			(LLOADER_TEXT_BASE + BL1_RO_OFFSET)
+#define BL1_RO_LIMIT			(BL1_RO_BASE + BL1_RO_SIZE)
+
+#define BL1_RW_OFFSET			(BL1_RO_OFFSET + BL1_RO_SIZE)
+#define BL1_RW_BASE			(LLOADER_TEXT_BASE + BL1_RW_OFFSET)
+#define BL1_RW_LIMIT			(BL1_RW_BASE + BL1_RW_SIZE)
+
+#define BL2_OFFSET			(BL1_OFFSET + BL1_SIZE)
+#define BL2_BASE			(LLOADER_TEXT_BASE + BL2_OFFSET)
+#define BL2_LIMIT			(BL2_BASE + BL2_SIZE)
+
+#define BL31_OFFSET			(BL2_OFFSET + BL2_SIZE)
+#define BL31_BASE			(LLOADER_TEXT_BASE + BL31_OFFSET)
+#define BL31_LIMIT			(BL31_BASE + BL31_SIZE)
+
+#endif /* POPLAR_LAYOUT_H */
diff --git a/plat/hisilicon/poplar/plat_pm.c b/plat/hisilicon/poplar/plat_pm.c
new file mode 100644
index 0000000..67ebca1
--- /dev/null
+++ b/plat/hisilicon/poplar/plat_pm.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "hi3798cv200.h"
+#include "plat_private.h"
+
+#define REG_PERI_CPU_RVBARADDR		0xF8A80034
+#define REG_PERI_CPU_AARCH_MODE		0xF8A80030
+
+#define REG_CPU_LP_CPU_SW_BEGIN		10
+#define CPU_REG_COREPO_SRST		12
+#define CPU_REG_CORE_SRST		8
+
+static void poplar_cpu_standby(plat_local_state_t cpu_state)
+{
+	dsb();
+	wfi();
+}
+
+static int poplar_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu = plat_core_pos_by_mpidr(mpidr);
+	unsigned int regval, regval_bak;
+
+	/* Select 400MHz before start slave cores */
+	regval_bak = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP));
+	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), 0x206);
+	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), 0x606);
+
+	/* Clear the slave cpu arm_por_srst_req reset */
+	regval = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST));
+	regval &= ~(1 << (cpu + CPU_REG_COREPO_SRST));
+	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST), regval);
+
+	/* Clear the slave cpu reset */
+	regval = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST));
+	regval &= ~(1 << (cpu + CPU_REG_CORE_SRST));
+	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST), regval);
+
+	/* Restore cpu frequency */
+	regval = regval_bak & (~(1 << REG_CPU_LP_CPU_SW_BEGIN));
+	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), regval);
+	mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), regval_bak);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void poplar_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	assert(0);
+}
+
+static void poplar_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	assert(0);
+}
+
+static void poplar_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_MAX_OFF_STATE);
+
+	/* Enable the gic cpu interface */
+	poplar_gic_pcpu_init();
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	poplar_gic_cpuif_enable();
+}
+
+static void poplar_pwr_domain_suspend_finish(
+		const psci_power_state_t *target_state)
+{
+	assert(0);
+}
+
+static void __dead2 poplar_system_off(void)
+{
+	ERROR("Poplar System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 poplar_system_reset(void)
+{
+	mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0xc00), 0x1ACCE551);
+	mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0x0),   0x00000100);
+	mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0x8),   0x00000003);
+
+	wfi();
+	ERROR("Poplar System Reset: operation not handled.\n");
+	panic();
+}
+
+static int32_t poplar_validate_power_state(unsigned int power_state,
+					   psci_power_state_t *req_state)
+{
+	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+	int pstate = psci_get_pstate_type(power_state);
+
+	assert(req_state);
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY)
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+	else
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+
+	/* We expect the 'state id' to be zero */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+static int poplar_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint >= DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+static void poplar_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static const plat_psci_ops_t poplar_plat_psci_ops = {
+	.cpu_standby			= poplar_cpu_standby,
+	.pwr_domain_on			= poplar_pwr_domain_on,
+	.pwr_domain_off			= poplar_pwr_domain_off,
+	.pwr_domain_suspend		= poplar_pwr_domain_suspend,
+	.pwr_domain_on_finish		= poplar_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish	= poplar_pwr_domain_suspend_finish,
+	.system_off			= poplar_system_off,
+	.system_reset			= poplar_system_reset,
+	.validate_power_state		= poplar_validate_power_state,
+	.validate_ns_entrypoint		= poplar_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= poplar_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &poplar_plat_psci_ops;
+
+	mmio_write_32((uintptr_t)REG_PERI_CPU_AARCH_MODE, 0xF);
+	mmio_write_32((uintptr_t)REG_PERI_CPU_RVBARADDR, sec_entrypoint);
+	return 0;
+}
diff --git a/plat/hisilicon/poplar/plat_storage.c b/plat/hisilicon/poplar/plat_storage.c
new file mode 100644
index 0000000..a17e0f1
--- /dev/null
+++ b/plat/hisilicon/poplar/plat_storage.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/partition/partition.h>
+#include <lib/mmio.h>
+#include <lib/semihosting.h>
+#include <lib/utils.h>
+#include <tools_share/firmware_image_package.h>
+
+#if !POPLAR_RECOVERY
+static const io_dev_connector_t *emmc_dev_con;
+static uintptr_t emmc_dev_handle;
+static int open_emmc(const uintptr_t spec);
+
+static const io_block_spec_t emmc_fip_spec = {
+	.offset		= FIP_BASE_EMMC,
+	.length		= FIP_SIZE
+};
+
+static const io_block_dev_spec_t emmc_dev_spec = {
+	.buffer		= {
+		.offset	= POPLAR_EMMC_DATA_BASE,
+		.length	= POPLAR_EMMC_DATA_SIZE,
+	},
+	.ops		= {
+		.read	= mmc_read_blocks,
+		.write	= mmc_write_blocks,
+	},
+	.block_size	= MMC_BLOCK_SIZE,
+};
+#else
+static const io_dev_connector_t *mmap_dev_con;
+static uintptr_t mmap_dev_handle;
+static int open_mmap(const uintptr_t spec);
+
+static const io_block_spec_t loader_fip_spec = {
+	.offset		= FIP_BASE,
+	.length		= FIP_SIZE
+};
+#endif
+
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static int open_fip(const uintptr_t spec);
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+struct plat_io_policy {
+	uintptr_t	*dev_handle;
+	uintptr_t	image_spec;
+	int		(*check)(const uintptr_t spec);
+};
+
+static const struct plat_io_policy policies[] = {
+#if !POPLAR_RECOVERY
+	[FIP_IMAGE_ID] = {
+		&emmc_dev_handle,
+		(uintptr_t)&emmc_fip_spec,
+		open_emmc
+	},
+#else
+	[FIP_IMAGE_ID] = {
+		&mmap_dev_handle,
+		(uintptr_t)&loader_fip_spec,
+		open_mmap
+	},
+#endif
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+};
+
+#if !POPLAR_RECOVERY
+static int open_emmc(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(emmc_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(emmc_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			INFO("Using eMMC\n");
+			io_close(local_image_handle);
+		} else {
+			ERROR("error opening emmc\n");
+		}
+	} else {
+		ERROR("error initializing emmc\n");
+	}
+
+	return result;
+}
+#else
+static int open_mmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(mmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(mmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			INFO("Using mmap\n");
+			io_close(local_image_handle);
+		} else {
+			ERROR("error opening mmap\n");
+		}
+	} else {
+		ERROR("error initializing mmap\n");
+	}
+
+	return result;
+}
+#endif
+
+static int open_fip(const uintptr_t spec)
+{
+	uintptr_t local_image_handle;
+	int result;
+
+	result = io_dev_init(fip_dev_handle, (uintptr_t) FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			INFO("Using FIP\n");
+			io_close(local_image_handle);
+		} else {
+			ERROR("error opening fip\n");
+		}
+	} else {
+		ERROR("error initializing fip\n");
+	}
+
+	return result;
+}
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	const struct plat_io_policy *policy;
+	int result;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
+
+void plat_io_setup(void)
+{
+	int result;
+
+#if !POPLAR_RECOVERY
+	result = register_io_dev_block(&emmc_dev_con);
+#else
+	result = register_io_dev_memmap(&mmap_dev_con);
+#endif
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+#if !POPLAR_RECOVERY
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+#else
+	result = io_dev_open(fip_dev_con, (uintptr_t)&loader_fip_spec,
+				&fip_dev_handle);
+#endif
+	assert(result == 0);
+
+#if !POPLAR_RECOVERY
+	result = io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec,
+				&emmc_dev_handle);
+#else
+	result = io_dev_open(mmap_dev_con, (uintptr_t)NULL, &mmap_dev_handle);
+#endif
+	assert(result == 0);
+
+	(void) result;
+}
diff --git a/plat/hisilicon/poplar/plat_topology.c b/plat/hisilicon/poplar/plat_topology.c
new file mode 100644
index 0000000..764008e
--- /dev/null
+++ b/plat/hisilicon/poplar/plat_topology.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+#include "plat_private.h"
+
+const unsigned char hisi_power_domain_tree_desc[] = {
+	PLATFORM_CLUSTER_COUNT,
+	PLATFORM_CORE_COUNT,
+};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return hisi_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		return -1;
+
+	if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT)
+		return -1;
+
+	return poplar_calc_core_pos(mpidr);
+}
diff --git a/plat/hisilicon/poplar/platform.mk b/plat/hisilicon/poplar/platform.mk
new file mode 100644
index 0000000..b5d9867
--- /dev/null
+++ b/plat/hisilicon/poplar/platform.mk
@@ -0,0 +1,112 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# On Poplar, the TSP can execute from TZC secure area in DRAM.
+POPLAR_TSP_RAM_LOCATION	?=	dram
+ifeq (${POPLAR_TSP_RAM_LOCATION}, dram)
+  POPLAR_TSP_RAM_LOCATION_ID = POPLAR_DRAM_ID
+else ifeq (${POPLAR_TSP_RAM_LOCATION}, sram)
+  POPLAR_TSP_RAM_LOCATION_ID = POPLAR_SRAM_ID
+else
+  $(error "Currently unsupported POPLAR_TSP_RAM_LOCATION value")
+endif
+$(eval $(call add_define,POPLAR_TSP_RAM_LOCATION_ID))
+
+POPLAR_DRAM_SIZE ?= two_gig
+ifeq (${POPLAR_DRAM_SIZE}, two_gig)
+  POPLAR_DRAM_SIZE_ID = POPLAR_DRAM_SIZE_2G
+else ifeq (${POPLAR_DRAM_SIZE}, one_gig)
+  POPLAR_DRAM_SIZE_ID = POPLAR_DRAM_SIZE_1G
+else
+  $(error "Currently unsupported POPLAR_DRAM_SIZE value")
+endif
+$(eval $(call add_define,POPLAR_DRAM_SIZE_ID))
+
+POPLAR_RECOVERY		:= 0
+$(eval $(call add_define,POPLAR_RECOVERY))
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2))
+endif
+
+NEED_BL33			:= yes
+
+COLD_BOOT_SINGLE_CPU		:= 1
+PROGRAMMABLE_RESET_ADDRESS	:= 1
+CTX_INCLUDE_FPREGS		:= 1
+ERRATA_A53_855873		:= 1
+ERRATA_A53_835769		:= 1
+ERRATA_A53_843419		:= 1
+ENABLE_SVE_FOR_NS		:= 0
+WORKAROUND_CVE_2017_5715	:= 0
+
+PLAT_PL061_MAX_GPIOS 		:= 104
+$(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
+
+PLAT_INCLUDES	:=	-Iplat/hisilicon/poplar/include		\
+			-Iplat/hisilicon/poplar
+
+PLAT_BL_COMMON_SOURCES	:=						\
+		lib/xlat_tables/aarch64/xlat_tables.c			\
+		lib/xlat_tables/xlat_tables_common.c			\
+		drivers/delay_timer/generic_delay_timer.c		\
+		drivers/arm/gic/common/gic_common.c			\
+		drivers/arm/gic/v2/gicv2_helpers.c			\
+		drivers/delay_timer/delay_timer.c			\
+		drivers/arm/pl011/aarch64/pl011_console.S		\
+		drivers/arm/gic/v2/gicv2_main.c				\
+		plat/common/plat_gicv2.c				\
+		plat/hisilicon/poplar/aarch64/platform_common.c		\
+		plat/hisilicon/poplar/aarch64/poplar_helpers.S		\
+		plat/hisilicon/poplar/poplar_gicv2.c
+
+BL1_SOURCES	+=							\
+		lib/cpus/aarch64/cortex_a53.S				\
+		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/mmc/mmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
+		drivers/io/io_storage.c					\
+		drivers/io/io_block.c					\
+		drivers/gpio/gpio.c					\
+		drivers/io/io_fip.c					\
+		drivers/io/io_memmap.c					\
+		plat/hisilicon/poplar/bl1_plat_setup.c			\
+		plat/hisilicon/poplar/plat_storage.c
+
+BL2_SOURCES	+=      						\
+		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/mmc/mmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
+		drivers/io/io_storage.c					\
+		drivers/io/io_block.c					\
+		drivers/io/io_fip.c					\
+		drivers/gpio/gpio.c					\
+		drivers/io/io_memmap.c					\
+		plat/hisilicon/poplar/bl2_plat_setup.c			\
+		plat/hisilicon/poplar/plat_storage.c
+
+BL2_SOURCES	+=							\
+		plat/hisilicon/poplar/bl2_plat_mem_params_desc.c	\
+		plat/hisilicon/poplar/poplar_image_load.c		\
+		common/desc_image_load.c
+
+ifeq (${SPD},opteed)
+BL2_SOURCES	+=							\
+		lib/optee/optee_utils.c
+endif
+
+BL31_SOURCES	+=							\
+		lib/cpus/aarch64/aem_generic.S				\
+		lib/cpus/aarch64/cortex_a53.S				\
+		plat/common/plat_psci_common.c			\
+		plat/hisilicon/poplar/bl31_plat_setup.c			\
+		plat/hisilicon/poplar/plat_topology.c			\
+		plat/hisilicon/poplar/plat_pm.c
diff --git a/plat/hisilicon/poplar/poplar_gicv2.c b/plat/hisilicon/poplar/poplar_gicv2.c
new file mode 100644
index 0000000..59f7b76
--- /dev/null
+++ b/plat/hisilicon/poplar/poplar_gicv2.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv2.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t poplar_interrupt_props[] = {
+	POPLAR_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+	POPLAR_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+static const gicv2_driver_data_t poplar_gic_data = {
+	.gicd_base = POPLAR_GICD_BASE,
+	.gicc_base = POPLAR_GICC_BASE,
+	.interrupt_props = poplar_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(poplar_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/******************************************************************************
+ * Helper to initialize the GICv2 only driver.
+ *****************************************************************************/
+void poplar_gic_driver_init(void)
+{
+	gicv2_driver_init(&poplar_gic_data);
+}
+
+void poplar_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * Helper to enable the GICv2 CPU interface
+ *****************************************************************************/
+void poplar_gic_cpuif_enable(void)
+{
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * Helper to initialize the per cpu distributor interface in GICv2
+ *****************************************************************************/
+void poplar_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+}
diff --git a/plat/hisilicon/poplar/poplar_image_load.c b/plat/hisilicon/poplar/poplar_image_load.c
new file mode 100644
index 0000000..0ab1ca4
--- /dev/null
+++ b/plat/hisilicon/poplar/poplar_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/imx/common/aarch32/imx_uart_console.S b/plat/imx/common/aarch32/imx_uart_console.S
new file mode 100644
index 0000000..1c729b1
--- /dev/null
+++ b/plat/imx/common/aarch32/imx_uart_console.S
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#include "imx_uart.h"
+
+	.globl	console_imx_uart_register
+	.globl	console_imx_uart_putc
+	.globl	console_imx_uart_getc
+	.globl	console_imx_uart_flush
+
+func console_imx_uart_register
+	push	{r4, lr}
+	mov	r4, r3
+	cmp	r4, #0
+	beq	register_fail
+	str	r0, [r4, #CONSOLE_T_DRVDATA]
+
+	bl	console_imx_uart_core_init
+	cmp	r0, #0
+	bne	register_fail
+
+	mov	r0, r4
+	pop	{r4, lr}
+	finish_console_register imx_uart putc=1, getc=1, flush=1
+
+register_fail:
+	pop	{r4, pc}
+endfunc console_imx_uart_register
+
+func console_imx_uart_putc
+	ldr	r1, [r1, #CONSOLE_T_DRVDATA]
+	b console_imx_uart_core_putc
+endfunc console_imx_uart_putc
+
+func console_imx_uart_getc
+	ldr	r0, [r0, #CONSOLE_T_DRVDATA]
+	b console_imx_uart_core_getc
+endfunc console_imx_uart_getc
+
+func console_imx_uart_flush
+	ldr	r0, [r0, #CONSOLE_T_DRVDATA]
+	b console_imx_uart_core_flush
+endfunc console_imx_uart_flush
diff --git a/plat/imx/common/imx7_clock.c b/plat/imx/common/imx7_clock.c
new file mode 100644
index 0000000..6bd2e0e
--- /dev/null
+++ b/plat/imx/common/imx7_clock.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <imx_regs.h>
+#include <imx_clock.h>
+
+static void imx7_clock_uart_init(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < MXC_MAX_UART_NUM; i++)
+		imx_clock_disable_uart(i);
+}
+
+static void imx7_clock_wdog_init(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < MXC_MAX_WDOG_NUM; i++)
+		imx_clock_disable_wdog(i);
+}
+
+static void imx7_clock_usb_init(void)
+{
+	/* Disable the clock root */
+	imx_clock_target_clr(CCM_TRT_ID_USB_HSIC_CLK_ROOT, 0xFFFFFFFF);
+}
+
+void imx_clock_init(void)
+{
+	/*
+	 * The BootROM hands off to the next stage with the internal 24 MHz XTAL
+	 * crystal already clocking the main PLL, which is very handy.
+	 * Here we should enable whichever peripherals are required for ATF and
+	 * OPTEE.
+	 *
+	 * Subsequent stages in the boot process such as u-boot and Linux
+	 * already have a significant and mature code-base around clocks, so our
+	 * objective should be to enable what we need for ATF/OPTEE without
+	 * breaking any existing upstream code in Linux and u-boot.
+	 */
+
+	/* Initialize UART clocks */
+	imx7_clock_uart_init();
+
+	/* Watchdog clocks */
+
+	imx7_clock_wdog_init();
+
+	/* USB clocks */
+	imx7_clock_usb_init();
+
+}
diff --git a/plat/imx/common/imx8_helpers.S b/plat/imx/common/imx8_helpers.S
new file mode 100644
index 0000000..19293bf
--- /dev/null
+++ b/plat/imx/common/imx8_helpers.S
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cortex_a35.h>
+
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_calc_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_get_my_entrypoint
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	platform_mem_init
+	.globl  imx_mailbox_init
+
+	/* --------------------------------------------------------------------
+	 * Helper macro that reads the part number of the current CPU and jumps
+	 * to the given label if it matches the CPU MIDR provided.
+	 *
+	 * Clobbers x0.
+	 * --------------------------------------------------------------------
+	 */
+	.macro  jump_if_cpu_midr _cpu_midr, _label
+
+	mrs	x0, midr_el1
+	ubfx	x0, x0, MIDR_PN_SHIFT, #12
+	cmp     w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+	b.eq	\_label
+
+	.endm
+
+	/* ----------------------------------------------
+	 * The mailbox_base is used to distinguish warm/cold
+	 * reset. The mailbox_base is in the data section, not
+	 * in .bss, this allows function to start using this
+	 * variable before the runtime memory is initialized.
+	 * ----------------------------------------------
+	 */
+	.section .data.mailbox_base
+	.align 3
+	mailbox_base: .quad 0x0
+
+	/* ----------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary(void);
+	 * This function checks if this is the primary CPU
+	 * ----------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CPU_MASK)
+	cmp	x0, #PLAT_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* ----------------------------------------------
+	 * unsigned int plat_my_core_pos(void)
+	 * This Function uses the plat_calc_core_pos()
+	 * to get the index of the calling CPU.
+	 * ----------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and 	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/*
+	 * unsigned int plat_calc_core_pos(uint64_t mpidr)
+	 * helper function to calculate the core position.
+	 * With this function.
+	 */
+func plat_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and 	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_calc_core_pos
+
+	/* ---------------------------------------------
+	 * function to get the entrypoint.
+	 * ---------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	adrp	x1, mailbox_base
+	ldr	x0, [x1, :lo12:mailbox_base]
+	ret
+endfunc	plat_get_my_entrypoint
+
+func imx_mailbox_init
+	adrp	x1, mailbox_base
+	str	x0, [x1, :lo12:mailbox_base]
+	ret
+endfunc imx_mailbox_init
+
+func plat_secondary_cold_boot_setup
+	b	.
+endfunc plat_secondary_cold_boot_setup
+
+func plat_crash_console_init
+	mov	x0, #1
+	ret
+endfunc plat_crash_console_init
+
+func plat_crash_console_putc
+	ret
+endfunc plat_crash_console_putc
+
+func plat_crash_console_flush
+	mov	x0, #0
+	ret
+endfunc plat_crash_console_flush
+
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/imx/common/imx8_psci.c b/plat/imx/common/imx8_psci.c
new file mode 100644
index 0000000..91d3370
--- /dev/null
+++ b/plat/imx/common/imx8_psci.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <plat_imx8.h>
+#include <sci/sci.h>
+
+void __dead2 imx_system_off(void)
+{
+	sc_pm_set_sys_power_mode(ipc_handle, SC_PM_PW_MODE_OFF);
+	wfi();
+	ERROR("power off failed.\n");
+	panic();
+}
+
+void __dead2 imx_system_reset(void)
+{
+	sc_pm_reset(ipc_handle, SC_PM_RESET_TYPE_BOARD);
+	wfi();
+	ERROR("system reset failed.\n");
+	panic();
+}
+
+int imx_validate_power_state(unsigned int power_state,
+			 psci_power_state_t *req_state)
+{
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int pwr_type = psci_get_pstate_type(power_state);
+	int state_id = psci_get_pstate_id(power_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	if (pwr_type == PSTATE_TYPE_POWERDOWN) {
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+		if (!state_id)
+			req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_RET_STATE;
+		else
+			req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_OFF_STATE;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	/* CPU & cluster off, system in retention */
+	for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
+}
+
diff --git a/plat/imx/common/imx8_topology.c b/plat/imx/common/imx8_topology.c
new file mode 100644
index 0000000..5e14d17
--- /dev/null
+++ b/plat/imx/common/imx8_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+const unsigned char imx_power_domain_tree_desc[] = {
+	PWR_DOMAIN_AT_MAX_LVL,
+	PLATFORM_CLUSTER_COUNT,
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	PLATFORM_CLUSTER1_CORE_COUNT,
+};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return imx_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (cluster_id > PLATFORM_CLUSTER_COUNT ||
+		cpu_id > PLATFORM_MAX_CPU_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/imx/common/imx_aips.c b/plat/imx/common/imx_aips.c
new file mode 100644
index 0000000..532d9c0
--- /dev/null
+++ b/plat/imx/common/imx_aips.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <imx_aips.h>
+#include <imx_regs.h>
+
+static void imx_aips_set_default_access(struct aipstz_regs *aips_regs)
+{
+	int i;
+	uintptr_t addr;
+
+	/*
+	 * See section 4.7.7.1 AIPSTZ_MPR field descriptions
+	 * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016
+	 * 0111 ->
+	 *	0: Write Access from master not buffered
+	 *	1: Master is trusted for read access
+	 *	1: Master is trsuted for write access
+	 *	1: Access from master is not forced to user mode
+	 */
+	addr = (uintptr_t)&aips_regs->aipstz_mpr;
+	mmio_write_32(addr, 0x77777777);
+
+	/*
+	 * Helpfully the OPACR registers have the logical inversion of the above
+	 * See section 4.7.7.1 AIPSTZ_MPR field descriptions
+	 * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016
+	 * 0000 ->
+	 *	0: Write Access to the peripheral is not buffered by AIPSTZ
+	 *	0: The peripheral does not require supervisor priv to access
+	 *	0: Master is trsuted for write access
+	 *	0: Access from master is not forced to user mode
+	 */
+	for (i = 0; i < AIPSTZ_OAPCR_COUNT; i++) {
+		addr = (uintptr_t)&aips_regs->aipstz_opacr[i];
+		mmio_write_32(addr, 0x00000000);
+	}
+}
+
+void imx_aips_init(void)
+{
+	int i;
+	struct aipstz_regs *aips_regs[] = {
+		(struct aipstz_regs *)(AIPS1_BASE + AIPSTZ_CONFIG_OFFSET),
+		(struct aipstz_regs *)(AIPS2_BASE + AIPSTZ_CONFIG_OFFSET),
+		(struct aipstz_regs *)(AIPS3_BASE + AIPSTZ_CONFIG_OFFSET),
+	};
+
+	for (i = 0; i < ARRAY_SIZE(aips_regs); i++)
+		imx_aips_set_default_access(aips_regs[i]);
+}
diff --git a/plat/imx/common/imx_caam.c b/plat/imx/common/imx_caam.c
new file mode 100644
index 0000000..d9c141f
--- /dev/null
+++ b/plat/imx/common/imx_caam.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/mmio.h>
+
+#include <imx_caam.h>
+
+void imx_caam_init(void)
+{
+	struct caam_ctrl *caam = (struct caam_ctrl *)CAAM_AIPS_BASE;
+	uint32_t reg;
+	int i;
+
+	for (i = 0; i < CAAM_NUM_JOB_RINGS; i++) {
+		reg = mmio_read_32((uintptr_t)&caam->jr[i].jrmidr_ms);
+		reg |= JROWN_NS | JROWN_MID;
+		mmio_write_32((uintptr_t)&caam->jr[i].jrmidr_ms, reg);
+	}
+}
diff --git a/plat/imx/common/imx_clock.c b/plat/imx/common/imx_clock.c
new file mode 100644
index 0000000..743de55
--- /dev/null
+++ b/plat/imx/common/imx_clock.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_clock.h>
+
+void imx_clock_target_set(unsigned int id, uint32_t val)
+{
+	struct ccm *ccm = ((struct ccm *)CCM_BASE);
+	uintptr_t addr;
+
+	if (id > CCM_ROOT_CTRL_NUM)
+		return;
+
+	addr = (uintptr_t)&ccm->ccm_root_ctrl[id].ccm_target_root;
+	mmio_write_32(addr, val);
+}
+
+void imx_clock_target_clr(unsigned int id, uint32_t val)
+{
+	struct ccm *ccm = ((struct ccm *)CCM_BASE);
+	uintptr_t addr;
+
+	if (id > CCM_ROOT_CTRL_NUM)
+		return;
+
+	addr = (uintptr_t)&ccm->ccm_root_ctrl[id].ccm_target_root_clr;
+	mmio_write_32(addr, val);
+}
+
+void imx_clock_gate_enable(unsigned int id, bool enable)
+{
+	struct ccm *ccm = ((struct ccm *)CCM_BASE);
+	uintptr_t addr;
+
+	if (id > CCM_CLK_GATE_CTRL_NUM)
+		return;
+
+	/* TODO: add support for more than DOMAIN0 clocks */
+	if (enable)
+		addr = (uintptr_t)&ccm->ccm_clk_gate_ctrl[id].ccm_ccgr_set;
+	else
+		addr = (uintptr_t)&ccm->ccm_clk_gate_ctrl[id].ccm_ccgr_clr;
+
+	mmio_write_32(addr, CCM_CCGR_SETTING0_DOM_CLK_ALWAYS);
+}
+
+void imx_clock_enable_uart(unsigned int uart_id, uint32_t uart_clk_en_bits)
+{
+	unsigned int ccm_trgt_id = CCM_TRT_ID_UART1_CLK_ROOT + uart_id;
+	unsigned int ccm_ccgr_id = CCM_CCGR_ID_UART1 + uart_id;
+
+	/* Check for error */
+	if (uart_id > MXC_MAX_UART_NUM)
+		return;
+
+	/* Set target register values */
+	imx_clock_target_set(ccm_trgt_id, uart_clk_en_bits);
+
+	/* Enable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_id, true);
+}
+
+void imx_clock_disable_uart(unsigned int uart_id)
+{
+	unsigned int ccm_trgt_id = CCM_TRT_ID_UART1_CLK_ROOT + uart_id;
+	unsigned int ccm_ccgr_id = CCM_CCGR_ID_UART1 + uart_id;
+
+	/* Check for error */
+	if (uart_id > MXC_MAX_UART_NUM)
+		return;
+
+	/* Disable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_id, false);
+
+	/* Clear the target */
+	imx_clock_target_clr(ccm_trgt_id, 0xFFFFFFFF);
+}
+
+void imx_clock_enable_usdhc(unsigned int usdhc_id, uint32_t usdhc_clk_en_bits)
+{
+	unsigned int ccm_trgt_id = CCM_TRT_ID_USDHC1_CLK_ROOT + usdhc_id;
+	unsigned int ccm_ccgr_id = CCM_CCGR_ID_USBHDC1 + usdhc_id;
+
+	/* Check for error */
+	if (usdhc_id > MXC_MAX_USDHC_NUM)
+		return;
+
+	/* Set target register values */
+	imx_clock_target_set(ccm_trgt_id, usdhc_clk_en_bits);
+
+	/* Enable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_id, true);
+}
+
+void imx_clock_enable_wdog(unsigned int wdog_id)
+{
+	unsigned int ccm_ccgr_id = CCM_CCGR_ID_WDOG1 + wdog_id;
+
+	/* Check for error */
+	if (wdog_id > MXC_MAX_WDOG_NUM)
+		return;
+
+	/* Enable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_id, true);
+}
+
+void imx_clock_disable_wdog(unsigned int wdog_id)
+{
+	unsigned int ccm_trgt_id = CCM_TRT_ID_WDOG_CLK_ROOT;
+	unsigned int ccm_ccgr_id = CCM_CCGR_ID_WDOG1 + wdog_id;
+
+	/* Check for error */
+	if (wdog_id > MXC_MAX_WDOG_NUM)
+		return;
+
+	/* Disable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_id, false);
+
+	/* Clear the target */
+	imx_clock_target_clr(ccm_trgt_id, 0xFFFFFFFF);
+}
+
+void imx_clock_set_wdog_clk_root_bits(uint32_t wdog_clk_root_en_bits)
+{
+	/* Enable the common clock root just once */
+	imx_clock_target_set(CCM_TRT_ID_WDOG_CLK_ROOT, wdog_clk_root_en_bits);
+}
+
+void imx_clock_enable_usb(unsigned int ccm_ccgr_usb_id)
+{
+	/* Enable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_usb_id, true);
+}
+
+void imx_clock_disable_usb(unsigned int ccm_ccgr_usb_id)
+{
+	/* Disable the clock gate */
+	imx_clock_gate_enable(ccm_ccgr_usb_id, false);
+}
+
+void imx_clock_set_usb_clk_root_bits(uint32_t usb_clk_root_en_bits)
+{
+	/* Enable the common clock root just once */
+	imx_clock_target_set(CCM_TRT_ID_USB_HSIC_CLK_ROOT, usb_clk_root_en_bits);
+}
diff --git a/plat/imx/common/imx_csu.c b/plat/imx/common/imx_csu.c
new file mode 100644
index 0000000..7e165d9
--- /dev/null
+++ b/plat/imx/common/imx_csu.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_csu.h>
+#include <imx_regs.h>
+
+void imx_csu_init(void)
+{
+	int i;
+	uintptr_t *csl_reg = (uintptr_t *)CSU_BASE;
+
+	for (i = 0; i < MXC_MAX_CSU_REGS; i++, csl_reg++)
+		mmio_write_32((uintptr_t)csl_reg, CSU_CSL_OPEN_ACCESS);
+}
diff --git a/plat/imx/common/imx_io_mux.c b/plat/imx/common/imx_io_mux.c
new file mode 100644
index 0000000..75de5d1
--- /dev/null
+++ b/plat/imx/common/imx_io_mux.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_io_mux.h>
+
+void imx_io_muxc_set_pad_alt_function(uint32_t pad_mux_offset, uint32_t alt_function)
+{
+	uintptr_t addr = (uintptr_t)(MXC_IO_MUXC_BASE + pad_mux_offset);
+
+	mmio_write_32(addr, alt_function);
+}
+
+void imx_io_muxc_set_pad_features(uint32_t pad_feature_offset, uint32_t pad_features)
+{
+	uintptr_t addr = (uintptr_t)(MXC_IO_MUXC_BASE + pad_feature_offset);
+
+	mmio_write_32(addr, pad_features);
+}
diff --git a/plat/imx/common/imx_sip_handler.c b/plat/imx/common/imx_sip_handler.c
new file mode 100644
index 0000000..62048b6
--- /dev/null
+++ b/plat/imx/common/imx_sip_handler.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <services/std_svc.h>
+#include <string.h>
+#include <platform_def.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <imx_sip_svc.h>
+#include <sci/sci.h>
+
+#if defined(PLAT_imx8qm) || defined(PLAT_imx8qx)
+
+#ifdef PLAT_imx8qm
+const static int ap_cluster_index[PLATFORM_CLUSTER_COUNT] = {
+	SC_R_A53, SC_R_A72,
+};
+#endif
+
+static int imx_srtc_set_time(uint32_t year_mon,
+			unsigned long day_hour,
+			unsigned long min_sec)
+{
+	return sc_timer_set_rtc_time(ipc_handle,
+		year_mon >> 16, year_mon & 0xffff,
+		day_hour >> 16, day_hour & 0xffff,
+		min_sec >> 16, min_sec & 0xffff);
+}
+
+int imx_srtc_handler(uint32_t smc_fid,
+		    void *handle,
+		    u_register_t x1,
+		    u_register_t x2,
+		    u_register_t x3,
+		    u_register_t x4)
+{
+	int ret;
+
+	switch (x1) {
+	case IMX_SIP_SRTC_SET_TIME:
+		ret = imx_srtc_set_time(x2, x3, x4);
+		break;
+	default:
+		ret = SMC_UNK;
+	}
+
+	SMC_RET1(handle, ret);
+}
+
+static void imx_cpufreq_set_target(uint32_t cluster_id, unsigned long freq)
+{
+	sc_pm_clock_rate_t rate = (sc_pm_clock_rate_t)freq;
+
+#ifdef PLAT_imx8qm
+	sc_pm_set_clock_rate(ipc_handle, ap_cluster_index[cluster_id], SC_PM_CLK_CPU, &rate);
+#endif
+#ifdef PLAT_imx8qx
+	sc_pm_set_clock_rate(ipc_handle, SC_R_A35, SC_PM_CLK_CPU, &rate);
+#endif
+}
+
+int imx_cpufreq_handler(uint32_t smc_fid,
+		    u_register_t x1,
+		    u_register_t x2,
+		    u_register_t x3)
+{
+	switch (x1) {
+	case IMX_SIP_SET_CPUFREQ:
+		imx_cpufreq_set_target(x2, x3);
+		break;
+	default:
+		return SMC_UNK;
+	}
+
+	return 0;
+}
+
+static bool wakeup_src_irqsteer;
+
+bool imx_is_wakeup_src_irqsteer(void)
+{
+	return wakeup_src_irqsteer;
+}
+
+int imx_wakeup_src_handler(uint32_t smc_fid,
+		    u_register_t x1,
+		    u_register_t x2,
+		    u_register_t x3)
+{
+	switch (x1) {
+	case IMX_SIP_WAKEUP_SRC_IRQSTEER:
+		wakeup_src_irqsteer = true;
+		break;
+	case IMX_SIP_WAKEUP_SRC_SCU:
+		wakeup_src_irqsteer = false;
+		break;
+	default:
+		return SMC_UNK;
+	}
+
+	return SMC_OK;
+}
+
+int imx_otp_handler(uint32_t smc_fid,
+		void *handle,
+		u_register_t x1,
+		u_register_t x2)
+{
+	int ret;
+	uint32_t fuse;
+
+	switch (smc_fid) {
+	case IMX_SIP_OTP_READ:
+		ret = sc_misc_otp_fuse_read(ipc_handle, x1, &fuse);
+		SMC_RET2(handle, ret, fuse);
+		break;
+	case IMX_SIP_OTP_WRITE:
+		ret = sc_misc_otp_fuse_write(ipc_handle, x1, x2);
+		SMC_RET1(handle, ret);
+		break;
+	default:
+		ret = SMC_UNK;
+		SMC_RET1(handle, ret);
+		break;
+	}
+
+	return ret;
+}
+
+int imx_misc_set_temp_handler(uint32_t smc_fid,
+		    u_register_t x1,
+		    u_register_t x2,
+		    u_register_t x3,
+		    u_register_t x4)
+{
+	return sc_misc_set_temp(ipc_handle, x1, x2, x3, x4);
+}
+
+#endif /* defined(PLAT_imx8qm) || defined(PLAT_imx8qx) */
+
+static uint64_t imx_get_commit_hash(u_register_t x2,
+		    u_register_t x3,
+		    u_register_t x4)
+{
+	/* Parse the version_string */
+	char *parse = (char *)version_string;
+	uint64_t hash = 0;
+
+	do {
+		parse = strchr(parse, '-');
+		if (parse) {
+			parse += 1;
+			if (*(parse) == 'g') {
+				/* Default is 7 hexadecimal digits */
+				memcpy((void *)&hash, (void *)(parse + 1), 7);
+				break;
+			}
+		}
+
+	} while (parse != NULL);
+
+	return hash;
+}
+
+uint64_t imx_buildinfo_handler(uint32_t smc_fid,
+		    u_register_t x1,
+		    u_register_t x2,
+		    u_register_t x3,
+		    u_register_t x4)
+{
+	uint64_t ret;
+
+	switch (x1) {
+	case IMX_SIP_BUILDINFO_GET_COMMITHASH:
+		ret = imx_get_commit_hash(x2, x3, x4);
+		break;
+	default:
+		return SMC_UNK;
+	}
+
+	return ret;
+}
diff --git a/plat/imx/common/imx_sip_svc.c b/plat/imx/common/imx_sip_svc.c
new file mode 100644
index 0000000..4893b9f
--- /dev/null
+++ b/plat/imx/common/imx_sip_svc.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/pmf/pmf.h>
+#include <tools_share/uuid.h>
+#include <imx_sip_svc.h>
+
+static int32_t imx_sip_setup(void)
+{
+	return 0;
+}
+
+static uintptr_t imx_sip_handler(unsigned int smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	switch (smc_fid) {
+#if defined(PLAT_imx8mq)
+	case IMX_SIP_GET_SOC_INFO:
+		SMC_RET1(handle, imx_soc_info_handler(smc_fid, x1, x2, x3));
+		break;
+#endif
+#if (defined(PLAT_imx8qm) || defined(PLAT_imx8qx))
+	case  IMX_SIP_SRTC:
+		return imx_srtc_handler(smc_fid, handle, x1, x2, x3, x4);
+	case  IMX_SIP_CPUFREQ:
+		SMC_RET1(handle, imx_cpufreq_handler(smc_fid, x1, x2, x3));
+		break;
+	case  IMX_SIP_WAKEUP_SRC:
+		SMC_RET1(handle, imx_wakeup_src_handler(smc_fid, x1, x2, x3));
+	case IMX_SIP_OTP_READ:
+	case IMX_SIP_OTP_WRITE:
+		return imx_otp_handler(smc_fid, handle, x1, x2);
+	case IMX_SIP_MISC_SET_TEMP:
+		SMC_RET1(handle, imx_misc_set_temp_handler(smc_fid, x1, x2, x3, x4));
+#endif
+	case  IMX_SIP_BUILDINFO:
+		SMC_RET1(handle, imx_buildinfo_handler(smc_fid, x1, x2, x3, x4));
+	default:
+		WARN("Unimplemented i.MX SiP Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+		break;
+	}
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+		imx_sip_svc,
+		OEN_SIP_START,
+		OEN_SIP_END,
+		SMC_TYPE_FAST,
+		imx_sip_setup,
+		imx_sip_handler
+);
diff --git a/plat/imx/common/imx_snvs.c b/plat/imx/common/imx_snvs.c
new file mode 100644
index 0000000..9b3a737
--- /dev/null
+++ b/plat/imx/common/imx_snvs.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_snvs.h>
+
+void imx_snvs_init(void)
+{
+	struct snvs *snvs = (struct snvs *)SNVS_BASE;
+	uintptr_t addr;
+	uint32_t val;
+
+	addr = (uintptr_t)&snvs->hpcomr;
+	val = mmio_read_32(addr);
+	val |= HPCOMR_NPSWA_EN;
+	mmio_write_32(addr, val);
+}
diff --git a/plat/imx/common/imx_uart_console.S b/plat/imx/common/imx_uart_console.S
new file mode 100644
index 0000000..3bdeea2
--- /dev/null
+++ b/plat/imx/common/imx_uart_console.S
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#include "imx_uart.h"
+
+#define URXD  0x0  /* Receiver Register */
+#define UTXD  0x40 /* Transmitter Register */
+#define UTS   0xb4 /* UART Test Register (mx31) */
+#define  URXD_RX_DATA    (0xFF)
+
+	.globl	console_imx_uart_register
+	.globl	console_imx_uart_init
+	.globl	console_imx_uart_putc
+	.globl	console_imx_uart_getc
+	.globl	console_imx_uart_flush
+
+func console_imx_uart_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_DRVDATA]
+
+	bl	console_imx_uart_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register imx_uart putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_imx_uart_register
+
+func console_imx_uart_init
+	mov	w0, #1
+	ret
+endfunc console_imx_uart_init
+
+func console_imx_uart_putc
+	ldr	x1, [x1, #CONSOLE_T_DRVDATA]
+	cbz	x1, putc_error
+
+	/* Prepare '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+1:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #UTS]
+	tbz	w2, #6, 1b
+	mov	w2, #0xD
+	str	w2, [x1, #UTXD]
+2:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #UTS]
+	tbz	w2, #6, 2b
+	str	w0, [x1, #UTXD]
+	ret
+putc_error:
+	mov	w0, #-1
+	ret
+endfunc console_imx_uart_putc
+
+func console_imx_uart_getc
+	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+	cbz	x0, getc_error
+1:
+	ldr	w1, [x0, #UTS]
+	tbnz	w1, #5, 1b
+
+	ldr	w1, [x0, #URXD]
+	and	w0, w1, #URXD_RX_DATA
+
+	ret
+getc_error:
+	mov	w0, #-1
+	ret
+endfunc console_imx_uart_getc
+
+func console_imx_uart_flush
+	mov	x0, #0
+	ret
+endfunc console_imx_uart_flush
diff --git a/plat/imx/common/imx_wdog.c b/plat/imx/common/imx_wdog.c
new file mode 100644
index 0000000..af6d767
--- /dev/null
+++ b/plat/imx/common/imx_wdog.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_regs.h>
+#include <imx_wdog.h>
+
+static void imx_wdog_power_down(unsigned long base)
+{
+	struct wdog_regs *wdog = (struct wdog_regs *)base;
+
+	mmio_write_16((uintptr_t)&wdog->wmcr, 0);
+}
+
+void imx_wdog_init(void)
+{
+	imx_wdog_power_down(WDOG1_BASE);
+	imx_wdog_power_down(WDOG2_BASE);
+	imx_wdog_power_down(WDOG3_BASE);
+	imx_wdog_power_down(WDOG4_BASE);
+}
diff --git a/plat/imx/common/include/imx8_iomux.h b/plat/imx/common/include/imx8_iomux.h
new file mode 100644
index 0000000..0e93d98
--- /dev/null
+++ b/plat/imx/common/include/imx8_iomux.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8_IOMUX_H
+#define IMX8_IOMUX_H
+
+#define PADRING_IFMUX_EN_SHIFT		31
+#define PADRING_IFMUX_EN_MASK		(1 << PADRING_IFMUX_EN_SHIFT)
+#define PADRING_GP_EN_SHIFT		30
+#define PADRING_GP_EN_MASK		(1 << PADRING_GP_EN_SHIFT)
+#define PADRING_IFMUX_SHIFT		27
+#define PADRING_IFMUX_MASK		(0x7 << PADRING_IFMUX_SHIFT)
+#define PADRING_CONFIG_SHIFT		25
+#define PADRING_CONFIG_MASK		(0x3 << PADRING_CONFIG_SHIFT)
+#define PADRING_LPCONFIG_SHIFT		23
+#define PADRING_LPCONFIG_MASK		(0x3 << PADRING_LPCONFIG_SHIFT)
+#define PADRING_PULL_SHIFT		5
+#define PADRING_PULL_MASK		(0x3 << PADRING_PULL_SHIFT)
+#define PADRING_DSE_SHIFT		0
+#define PADRING_DSE_MASK		(0x7 << PADRING_DSE_SHIFT)
+
+#endif /* IMX8_IOMUX_H */
diff --git a/plat/imx/common/include/imx8_lpuart.h b/plat/imx/common/include/imx8_lpuart.h
new file mode 100644
index 0000000..0ea284f
--- /dev/null
+++ b/plat/imx/common/include/imx8_lpuart.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8_LPUART_H
+#define IMX8_LPUART_H
+
+#include <drivers/console.h>
+
+#define VERID	0x0
+#define PARAM	0x4
+#define GLOBAL	0x8
+#define PINCFG	0xC
+#define BAUD	0x10
+#define STAT	0x14
+#define CTRL	0x18
+#define DATA	0x1C
+#define MATCH	0x20
+#define MODIR	0x24
+#define FIFO	0x28
+#define WATER	0x2c
+
+#define US1_TDRE	(1 << 23)
+#define US1_RDRF	(1 << 21)
+
+#define CTRL_TE		(1 << 19)
+#define CTRL_RE		(1 << 18)
+
+#define FIFO_TXFE	0x80
+#define FIFO_RXFE	0x40
+
+#define WATER_TXWATER_OFF	1
+#define WATER_RXWATER_OFF	16
+
+#define LPUART_CTRL_PT_MASK	0x1
+#define LPUART_CTRL_PE_MASK	0x2
+#define LPUART_CTRL_M_MASK	0x10
+
+#define LPUART_BAUD_OSR_MASK                     (0x1F000000U)
+#define LPUART_BAUD_OSR_SHIFT                    (24U)
+#define LPUART_BAUD_OSR(x)                       (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_OSR_SHIFT)) & LPUART_BAUD_OSR_MASK)
+
+#define LPUART_BAUD_SBR_MASK                     (0x1FFFU)
+#define LPUART_BAUD_SBR_SHIFT                    (0U)
+#define LPUART_BAUD_SBR(x)                       (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_SBR_SHIFT)) & LPUART_BAUD_SBR_MASK)
+
+#define LPUART_BAUD_SBNS_MASK                    (0x2000U)
+#define LPUART_BAUD_BOTHEDGE_MASK                (0x20000U)
+#define LPUART_BAUD_M10_MASK                     (0x20000000U)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_lpuart_t;
+
+int console_lpuart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_lpuart_t *console);
+#endif /*__ASSEMBLER__*/
+
+#endif /* IMX8_LPUART_H */
diff --git a/plat/imx/common/include/imx8qm_pads.h b/plat/imx/common/include/imx8qm_pads.h
new file mode 100644
index 0000000..a5c1d2c
--- /dev/null
+++ b/plat/imx/common/include/imx8qm_pads.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file used to configure SoC pad list.
+ */
+
+#ifndef IMX8QM_PADS_H
+#define IMX8QM_PADS_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Pad Definitions
+ */
+/*@{*/
+#define SC_P_SIM0_CLK                            0	/* DMA.SIM0.CLK, LSIO.GPIO0.IO00 */
+#define SC_P_SIM0_RST                            1	/* DMA.SIM0.RST, LSIO.GPIO0.IO01 */
+#define SC_P_SIM0_IO                             2	/* DMA.SIM0.IO, LSIO.GPIO0.IO02 */
+#define SC_P_SIM0_PD                             3	/* DMA.SIM0.PD, DMA.I2C3.SCL, LSIO.GPIO0.IO03 */
+#define SC_P_SIM0_POWER_EN                       4	/* DMA.SIM0.POWER_EN, DMA.I2C3.SDA, LSIO.GPIO0.IO04 */
+#define SC_P_SIM0_GPIO0_00                       5	/* DMA.SIM0.POWER_EN, LSIO.GPIO0.IO05 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_SIM           6	/*  */
+#define SC_P_M40_I2C0_SCL                        7	/* M40.I2C0.SCL, M40.UART0.RX, M40.GPIO0.IO02, LSIO.GPIO0.IO06 */
+#define SC_P_M40_I2C0_SDA                        8	/* M40.I2C0.SDA, M40.UART0.TX, M40.GPIO0.IO03, LSIO.GPIO0.IO07 */
+#define SC_P_M40_GPIO0_00                        9	/* M40.GPIO0.IO00, M40.TPM0.CH0, DMA.UART4.RX, LSIO.GPIO0.IO08 */
+#define SC_P_M40_GPIO0_01                        10	/* M40.GPIO0.IO01, M40.TPM0.CH1, DMA.UART4.TX, LSIO.GPIO0.IO09 */
+#define SC_P_M41_I2C0_SCL                        11	/* M41.I2C0.SCL, M41.UART0.RX, M41.GPIO0.IO02, LSIO.GPIO0.IO10 */
+#define SC_P_M41_I2C0_SDA                        12	/* M41.I2C0.SDA, M41.UART0.TX, M41.GPIO0.IO03, LSIO.GPIO0.IO11 */
+#define SC_P_M41_GPIO0_00                        13	/* M41.GPIO0.IO00, M41.TPM0.CH0, DMA.UART3.RX, LSIO.GPIO0.IO12 */
+#define SC_P_M41_GPIO0_01                        14	/* M41.GPIO0.IO01, M41.TPM0.CH1, DMA.UART3.TX, LSIO.GPIO0.IO13 */
+#define SC_P_GPT0_CLK                            15	/* LSIO.GPT0.CLK, DMA.I2C1.SCL, LSIO.KPP0.COL4, LSIO.GPIO0.IO14 */
+#define SC_P_GPT0_CAPTURE                        16	/* LSIO.GPT0.CAPTURE, DMA.I2C1.SDA, LSIO.KPP0.COL5, LSIO.GPIO0.IO15 */
+#define SC_P_GPT0_COMPARE                        17	/* LSIO.GPT0.COMPARE, LSIO.PWM3.OUT, LSIO.KPP0.COL6, LSIO.GPIO0.IO16 */
+#define SC_P_GPT1_CLK                            18	/* LSIO.GPT1.CLK, DMA.I2C2.SCL, LSIO.KPP0.COL7, LSIO.GPIO0.IO17 */
+#define SC_P_GPT1_CAPTURE                        19	/* LSIO.GPT1.CAPTURE, DMA.I2C2.SDA, LSIO.KPP0.ROW4, LSIO.GPIO0.IO18 */
+#define SC_P_GPT1_COMPARE                        20	/* LSIO.GPT1.COMPARE, LSIO.PWM2.OUT, LSIO.KPP0.ROW5, LSIO.GPIO0.IO19 */
+#define SC_P_UART0_RX                            21	/* DMA.UART0.RX, SCU.UART0.RX, LSIO.GPIO0.IO20 */
+#define SC_P_UART0_TX                            22	/* DMA.UART0.TX, SCU.UART0.TX, LSIO.GPIO0.IO21 */
+#define SC_P_UART0_RTS_B                         23	/* DMA.UART0.RTS_B, LSIO.PWM0.OUT, DMA.UART2.RX, LSIO.GPIO0.IO22 */
+#define SC_P_UART0_CTS_B                         24	/* DMA.UART0.CTS_B, LSIO.PWM1.OUT, DMA.UART2.TX, LSIO.GPIO0.IO23 */
+#define SC_P_UART1_TX                            25	/* DMA.UART1.TX, DMA.SPI3.SCK, LSIO.GPIO0.IO24 */
+#define SC_P_UART1_RX                            26	/* DMA.UART1.RX, DMA.SPI3.SDO, LSIO.GPIO0.IO25 */
+#define SC_P_UART1_RTS_B                         27	/* DMA.UART1.RTS_B, DMA.SPI3.SDI, DMA.UART1.CTS_B, LSIO.GPIO0.IO26 */
+#define SC_P_UART1_CTS_B                         28	/* DMA.UART1.CTS_B, DMA.SPI3.CS0, DMA.UART1.RTS_B, LSIO.GPIO0.IO27 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLH        29	/*  */
+#define SC_P_SCU_PMIC_MEMC_ON                    30	/* SCU.GPIO0.IOXX_PMIC_MEMC_ON */
+#define SC_P_SCU_WDOG_OUT                        31	/* SCU.WDOG0.WDOG_OUT */
+#define SC_P_PMIC_I2C_SDA                        32	/* SCU.PMIC_I2C.SDA */
+#define SC_P_PMIC_I2C_SCL                        33	/* SCU.PMIC_I2C.SCL */
+#define SC_P_PMIC_EARLY_WARNING                  34	/* SCU.PMIC_EARLY_WARNING */
+#define SC_P_PMIC_INT_B                          35	/* SCU.DSC.PMIC_INT_B */
+#define SC_P_SCU_GPIO0_00                        36	/* SCU.GPIO0.IO00, SCU.UART0.RX, LSIO.GPIO0.IO28 */
+#define SC_P_SCU_GPIO0_01                        37	/* SCU.GPIO0.IO01, SCU.UART0.TX, LSIO.GPIO0.IO29 */
+#define SC_P_SCU_GPIO0_02                        38	/* SCU.GPIO0.IO02, SCU.GPIO0.IOXX_PMIC_GPU0_ON, LSIO.GPIO0.IO30 */
+#define SC_P_SCU_GPIO0_03                        39	/* SCU.GPIO0.IO03, SCU.GPIO0.IOXX_PMIC_GPU1_ON, LSIO.GPIO0.IO31 */
+#define SC_P_SCU_GPIO0_04                        40	/* SCU.GPIO0.IO04, SCU.GPIO0.IOXX_PMIC_A72_ON, LSIO.GPIO1.IO00 */
+#define SC_P_SCU_GPIO0_05                        41	/* SCU.GPIO0.IO05, SCU.GPIO0.IOXX_PMIC_A53_ON, LSIO.GPIO1.IO01 */
+#define SC_P_SCU_GPIO0_06                        42	/* SCU.GPIO0.IO06, SCU.TPM0.CH0, LSIO.GPIO1.IO02 */
+#define SC_P_SCU_GPIO0_07                        43	/* SCU.GPIO0.IO07, SCU.TPM0.CH1, SCU.DSC.RTC_CLOCK_OUTPUT_32K, LSIO.GPIO1.IO03 */
+#define SC_P_SCU_BOOT_MODE0                      44	/* SCU.DSC.BOOT_MODE0 */
+#define SC_P_SCU_BOOT_MODE1                      45	/* SCU.DSC.BOOT_MODE1 */
+#define SC_P_SCU_BOOT_MODE2                      46	/* SCU.DSC.BOOT_MODE2 */
+#define SC_P_SCU_BOOT_MODE3                      47	/* SCU.DSC.BOOT_MODE3 */
+#define SC_P_SCU_BOOT_MODE4                      48	/* SCU.DSC.BOOT_MODE4, SCU.PMIC_I2C.SCL */
+#define SC_P_SCU_BOOT_MODE5                      49	/* SCU.DSC.BOOT_MODE5, SCU.PMIC_I2C.SDA */
+#define SC_P_LVDS0_GPIO00                        50	/* LVDS0.GPIO0.IO00, LVDS0.PWM0.OUT, LSIO.GPIO1.IO04 */
+#define SC_P_LVDS0_GPIO01                        51	/* LVDS0.GPIO0.IO01, LSIO.GPIO1.IO05 */
+#define SC_P_LVDS0_I2C0_SCL                      52	/* LVDS0.I2C0.SCL, LVDS0.GPIO0.IO02, LSIO.GPIO1.IO06 */
+#define SC_P_LVDS0_I2C0_SDA                      53	/* LVDS0.I2C0.SDA, LVDS0.GPIO0.IO03, LSIO.GPIO1.IO07 */
+#define SC_P_LVDS0_I2C1_SCL                      54	/* LVDS0.I2C1.SCL, DMA.UART2.TX, LSIO.GPIO1.IO08 */
+#define SC_P_LVDS0_I2C1_SDA                      55	/* LVDS0.I2C1.SDA, DMA.UART2.RX, LSIO.GPIO1.IO09 */
+#define SC_P_LVDS1_GPIO00                        56	/* LVDS1.GPIO0.IO00, LVDS1.PWM0.OUT, LSIO.GPIO1.IO10 */
+#define SC_P_LVDS1_GPIO01                        57	/* LVDS1.GPIO0.IO01, LSIO.GPIO1.IO11 */
+#define SC_P_LVDS1_I2C0_SCL                      58	/* LVDS1.I2C0.SCL, LVDS1.GPIO0.IO02, LSIO.GPIO1.IO12 */
+#define SC_P_LVDS1_I2C0_SDA                      59	/* LVDS1.I2C0.SDA, LVDS1.GPIO0.IO03, LSIO.GPIO1.IO13 */
+#define SC_P_LVDS1_I2C1_SCL                      60	/* LVDS1.I2C1.SCL, DMA.UART3.TX, LSIO.GPIO1.IO14 */
+#define SC_P_LVDS1_I2C1_SDA                      61	/* LVDS1.I2C1.SDA, DMA.UART3.RX, LSIO.GPIO1.IO15 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_LVDSGPIO      62	/*  */
+#define SC_P_MIPI_DSI0_I2C0_SCL                  63	/* MIPI_DSI0.I2C0.SCL, LSIO.GPIO1.IO16 */
+#define SC_P_MIPI_DSI0_I2C0_SDA                  64	/* MIPI_DSI0.I2C0.SDA, LSIO.GPIO1.IO17 */
+#define SC_P_MIPI_DSI0_GPIO0_00                  65	/* MIPI_DSI0.GPIO0.IO00, MIPI_DSI0.PWM0.OUT, LSIO.GPIO1.IO18 */
+#define SC_P_MIPI_DSI0_GPIO0_01                  66	/* MIPI_DSI0.GPIO0.IO01, LSIO.GPIO1.IO19 */
+#define SC_P_MIPI_DSI1_I2C0_SCL                  67	/* MIPI_DSI1.I2C0.SCL, LSIO.GPIO1.IO20 */
+#define SC_P_MIPI_DSI1_I2C0_SDA                  68	/* MIPI_DSI1.I2C0.SDA, LSIO.GPIO1.IO21 */
+#define SC_P_MIPI_DSI1_GPIO0_00                  69	/* MIPI_DSI1.GPIO0.IO00, MIPI_DSI1.PWM0.OUT, LSIO.GPIO1.IO22 */
+#define SC_P_MIPI_DSI1_GPIO0_01                  70	/* MIPI_DSI1.GPIO0.IO01, LSIO.GPIO1.IO23 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO   71	/*  */
+#define SC_P_MIPI_CSI0_MCLK_OUT                  72	/* MIPI_CSI0.ACM.MCLK_OUT, LSIO.GPIO1.IO24 */
+#define SC_P_MIPI_CSI0_I2C0_SCL                  73	/* MIPI_CSI0.I2C0.SCL, LSIO.GPIO1.IO25 */
+#define SC_P_MIPI_CSI0_I2C0_SDA                  74	/* MIPI_CSI0.I2C0.SDA, LSIO.GPIO1.IO26 */
+#define SC_P_MIPI_CSI0_GPIO0_00                  75	/* MIPI_CSI0.GPIO0.IO00, DMA.I2C0.SCL, MIPI_CSI1.I2C0.SCL, LSIO.GPIO1.IO27 */
+#define SC_P_MIPI_CSI0_GPIO0_01                  76	/* MIPI_CSI0.GPIO0.IO01, DMA.I2C0.SDA, MIPI_CSI1.I2C0.SDA, LSIO.GPIO1.IO28 */
+#define SC_P_MIPI_CSI1_MCLK_OUT                  77	/* MIPI_CSI1.ACM.MCLK_OUT, LSIO.GPIO1.IO29 */
+#define SC_P_MIPI_CSI1_GPIO0_00                  78	/* MIPI_CSI1.GPIO0.IO00, DMA.UART4.RX, LSIO.GPIO1.IO30 */
+#define SC_P_MIPI_CSI1_GPIO0_01                  79	/* MIPI_CSI1.GPIO0.IO01, DMA.UART4.TX, LSIO.GPIO1.IO31 */
+#define SC_P_MIPI_CSI1_I2C0_SCL                  80	/* MIPI_CSI1.I2C0.SCL, LSIO.GPIO2.IO00 */
+#define SC_P_MIPI_CSI1_I2C0_SDA                  81	/* MIPI_CSI1.I2C0.SDA, LSIO.GPIO2.IO01 */
+#define SC_P_HDMI_TX0_TS_SCL                     82	/* HDMI_TX0.I2C0.SCL, DMA.I2C0.SCL, LSIO.GPIO2.IO02 */
+#define SC_P_HDMI_TX0_TS_SDA                     83	/* HDMI_TX0.I2C0.SDA, DMA.I2C0.SDA, LSIO.GPIO2.IO03 */
+#define SC_P_COMP_CTL_GPIO_3V3_HDMIGPIO          84	/*  */
+#define SC_P_ESAI1_FSR                           85	/* AUD.ESAI1.FSR, LSIO.GPIO2.IO04 */
+#define SC_P_ESAI1_FST                           86	/* AUD.ESAI1.FST, AUD.SPDIF0.EXT_CLK, LSIO.GPIO2.IO05 */
+#define SC_P_ESAI1_SCKR                          87	/* AUD.ESAI1.SCKR, LSIO.GPIO2.IO06 */
+#define SC_P_ESAI1_SCKT                          88	/* AUD.ESAI1.SCKT, AUD.SAI2.RXC, AUD.SPDIF0.EXT_CLK, LSIO.GPIO2.IO07 */
+#define SC_P_ESAI1_TX0                           89	/* AUD.ESAI1.TX0, AUD.SAI2.RXD, AUD.SPDIF0.RX, LSIO.GPIO2.IO08 */
+#define SC_P_ESAI1_TX1                           90	/* AUD.ESAI1.TX1, AUD.SAI2.RXFS, AUD.SPDIF0.TX, LSIO.GPIO2.IO09 */
+#define SC_P_ESAI1_TX2_RX3                       91	/* AUD.ESAI1.TX2_RX3, AUD.SPDIF0.RX, LSIO.GPIO2.IO10 */
+#define SC_P_ESAI1_TX3_RX2                       92	/* AUD.ESAI1.TX3_RX2, AUD.SPDIF0.TX, LSIO.GPIO2.IO11 */
+#define SC_P_ESAI1_TX4_RX1                       93	/* AUD.ESAI1.TX4_RX1, LSIO.GPIO2.IO12 */
+#define SC_P_ESAI1_TX5_RX0                       94	/* AUD.ESAI1.TX5_RX0, LSIO.GPIO2.IO13 */
+#define SC_P_SPDIF0_RX                           95	/* AUD.SPDIF0.RX, AUD.MQS.R, AUD.ACM.MCLK_IN1, LSIO.GPIO2.IO14 */
+#define SC_P_SPDIF0_TX                           96	/* AUD.SPDIF0.TX, AUD.MQS.L, AUD.ACM.MCLK_OUT1, LSIO.GPIO2.IO15 */
+#define SC_P_SPDIF0_EXT_CLK                      97	/* AUD.SPDIF0.EXT_CLK, DMA.DMA0.REQ_IN0, LSIO.GPIO2.IO16 */
+#define SC_P_SPI3_SCK                            98	/* DMA.SPI3.SCK, LSIO.GPIO2.IO17 */
+#define SC_P_SPI3_SDO                            99	/* DMA.SPI3.SDO, DMA.FTM.CH0, LSIO.GPIO2.IO18 */
+#define SC_P_SPI3_SDI                            100	/* DMA.SPI3.SDI, DMA.FTM.CH1, LSIO.GPIO2.IO19 */
+#define SC_P_SPI3_CS0                            101	/* DMA.SPI3.CS0, DMA.FTM.CH2, LSIO.GPIO2.IO20 */
+#define SC_P_SPI3_CS1                            102	/* DMA.SPI3.CS1, LSIO.GPIO2.IO21 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHB       103	/*  */
+#define SC_P_ESAI0_FSR                           104	/* AUD.ESAI0.FSR, LSIO.GPIO2.IO22 */
+#define SC_P_ESAI0_FST                           105	/* AUD.ESAI0.FST, LSIO.GPIO2.IO23 */
+#define SC_P_ESAI0_SCKR                          106	/* AUD.ESAI0.SCKR, LSIO.GPIO2.IO24 */
+#define SC_P_ESAI0_SCKT                          107	/* AUD.ESAI0.SCKT, LSIO.GPIO2.IO25 */
+#define SC_P_ESAI0_TX0                           108	/* AUD.ESAI0.TX0, LSIO.GPIO2.IO26 */
+#define SC_P_ESAI0_TX1                           109	/* AUD.ESAI0.TX1, LSIO.GPIO2.IO27 */
+#define SC_P_ESAI0_TX2_RX3                       110	/* AUD.ESAI0.TX2_RX3, LSIO.GPIO2.IO28 */
+#define SC_P_ESAI0_TX3_RX2                       111	/* AUD.ESAI0.TX3_RX2, LSIO.GPIO2.IO29 */
+#define SC_P_ESAI0_TX4_RX1                       112	/* AUD.ESAI0.TX4_RX1, LSIO.GPIO2.IO30 */
+#define SC_P_ESAI0_TX5_RX0                       113	/* AUD.ESAI0.TX5_RX0, LSIO.GPIO2.IO31 */
+#define SC_P_MCLK_IN0                            114	/* AUD.ACM.MCLK_IN0, AUD.ESAI0.RX_HF_CLK, AUD.ESAI1.RX_HF_CLK, LSIO.GPIO3.IO00 */
+#define SC_P_MCLK_OUT0                           115	/* AUD.ACM.MCLK_OUT0, AUD.ESAI0.TX_HF_CLK, AUD.ESAI1.TX_HF_CLK, LSIO.GPIO3.IO01 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHC       116	/*  */
+#define SC_P_SPI0_SCK                            117	/* DMA.SPI0.SCK, AUD.SAI0.RXC, LSIO.GPIO3.IO02 */
+#define SC_P_SPI0_SDO                            118	/* DMA.SPI0.SDO, AUD.SAI0.TXD, LSIO.GPIO3.IO03 */
+#define SC_P_SPI0_SDI                            119	/* DMA.SPI0.SDI, AUD.SAI0.RXD, LSIO.GPIO3.IO04 */
+#define SC_P_SPI0_CS0                            120	/* DMA.SPI0.CS0, AUD.SAI0.RXFS, LSIO.GPIO3.IO05 */
+#define SC_P_SPI0_CS1                            121	/* DMA.SPI0.CS1, AUD.SAI0.TXC, LSIO.GPIO3.IO06 */
+#define SC_P_SPI2_SCK                            122	/* DMA.SPI2.SCK, LSIO.GPIO3.IO07 */
+#define SC_P_SPI2_SDO                            123	/* DMA.SPI2.SDO, LSIO.GPIO3.IO08 */
+#define SC_P_SPI2_SDI                            124	/* DMA.SPI2.SDI, LSIO.GPIO3.IO09 */
+#define SC_P_SPI2_CS0                            125	/* DMA.SPI2.CS0, LSIO.GPIO3.IO10 */
+#define SC_P_SPI2_CS1                            126	/* DMA.SPI2.CS1, AUD.SAI0.TXFS, LSIO.GPIO3.IO11 */
+#define SC_P_SAI1_RXC                            127	/* AUD.SAI1.RXC, AUD.SAI0.TXD, LSIO.GPIO3.IO12 */
+#define SC_P_SAI1_RXD                            128	/* AUD.SAI1.RXD, AUD.SAI0.TXFS, LSIO.GPIO3.IO13 */
+#define SC_P_SAI1_RXFS                           129	/* AUD.SAI1.RXFS, AUD.SAI0.RXD, LSIO.GPIO3.IO14 */
+#define SC_P_SAI1_TXC                            130	/* AUD.SAI1.TXC, AUD.SAI0.TXC, LSIO.GPIO3.IO15 */
+#define SC_P_SAI1_TXD                            131	/* AUD.SAI1.TXD, AUD.SAI1.RXC, LSIO.GPIO3.IO16 */
+#define SC_P_SAI1_TXFS                           132	/* AUD.SAI1.TXFS, AUD.SAI1.RXFS, LSIO.GPIO3.IO17 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHT       133	/*  */
+#define SC_P_ADC_IN7                             134	/* DMA.ADC1.IN3, DMA.SPI1.CS1, LSIO.KPP0.ROW3, LSIO.GPIO3.IO25 */
+#define SC_P_ADC_IN6                             135	/* DMA.ADC1.IN2, DMA.SPI1.CS0, LSIO.KPP0.ROW2, LSIO.GPIO3.IO24 */
+#define SC_P_ADC_IN5                             136	/* DMA.ADC1.IN1, DMA.SPI1.SDI, LSIO.KPP0.ROW1, LSIO.GPIO3.IO23 */
+#define SC_P_ADC_IN4                             137	/* DMA.ADC1.IN0, DMA.SPI1.SDO, LSIO.KPP0.ROW0, LSIO.GPIO3.IO22 */
+#define SC_P_ADC_IN3                             138	/* DMA.ADC0.IN3, DMA.SPI1.SCK, LSIO.KPP0.COL3, LSIO.GPIO3.IO21 */
+#define SC_P_ADC_IN2                             139	/* DMA.ADC0.IN2, LSIO.KPP0.COL2, LSIO.GPIO3.IO20 */
+#define SC_P_ADC_IN1                             140	/* DMA.ADC0.IN1, LSIO.KPP0.COL1, LSIO.GPIO3.IO19 */
+#define SC_P_ADC_IN0                             141	/* DMA.ADC0.IN0, LSIO.KPP0.COL0, LSIO.GPIO3.IO18 */
+#define SC_P_MLB_SIG                             142	/* CONN.MLB.SIG, AUD.SAI3.RXC, LSIO.GPIO3.IO26 */
+#define SC_P_MLB_CLK                             143	/* CONN.MLB.CLK, AUD.SAI3.RXFS, LSIO.GPIO3.IO27 */
+#define SC_P_MLB_DATA                            144	/* CONN.MLB.DATA, AUD.SAI3.RXD, LSIO.GPIO3.IO28 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLHT       145	/*  */
+#define SC_P_FLEXCAN0_RX                         146	/* DMA.FLEXCAN0.RX, LSIO.GPIO3.IO29 */
+#define SC_P_FLEXCAN0_TX                         147	/* DMA.FLEXCAN0.TX, LSIO.GPIO3.IO30 */
+#define SC_P_FLEXCAN1_RX                         148	/* DMA.FLEXCAN1.RX, LSIO.GPIO3.IO31 */
+#define SC_P_FLEXCAN1_TX                         149	/* DMA.FLEXCAN1.TX, LSIO.GPIO4.IO00 */
+#define SC_P_FLEXCAN2_RX                         150	/* DMA.FLEXCAN2.RX, LSIO.GPIO4.IO01 */
+#define SC_P_FLEXCAN2_TX                         151	/* DMA.FLEXCAN2.TX, LSIO.GPIO4.IO02 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOTHR       152	/*  */
+#define SC_P_USB_SS3_TC0                         153	/* DMA.I2C1.SCL, CONN.USB_OTG1.PWR, LSIO.GPIO4.IO03 */
+#define SC_P_USB_SS3_TC1                         154	/* DMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO04 */
+#define SC_P_USB_SS3_TC2                         155	/* DMA.I2C1.SDA, CONN.USB_OTG1.OC, LSIO.GPIO4.IO05 */
+#define SC_P_USB_SS3_TC3                         156	/* DMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO06 */
+#define SC_P_COMP_CTL_GPIO_3V3_USB3IO            157	/*  */
+#define SC_P_USDHC1_RESET_B                      158	/* CONN.USDHC1.RESET_B, LSIO.GPIO4.IO07 */
+#define SC_P_USDHC1_VSELECT                      159	/* CONN.USDHC1.VSELECT, LSIO.GPIO4.IO08 */
+#define SC_P_USDHC2_RESET_B                      160	/* CONN.USDHC2.RESET_B, LSIO.GPIO4.IO09 */
+#define SC_P_USDHC2_VSELECT                      161	/* CONN.USDHC2.VSELECT, LSIO.GPIO4.IO10 */
+#define SC_P_USDHC2_WP                           162	/* CONN.USDHC2.WP, LSIO.GPIO4.IO11 */
+#define SC_P_USDHC2_CD_B                         163	/* CONN.USDHC2.CD_B, LSIO.GPIO4.IO12 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_VSELSEP       164	/*  */
+#define SC_P_ENET0_MDIO                          165	/* CONN.ENET0.MDIO, DMA.I2C4.SDA, LSIO.GPIO4.IO13 */
+#define SC_P_ENET0_MDC                           166	/* CONN.ENET0.MDC, DMA.I2C4.SCL, LSIO.GPIO4.IO14 */
+#define SC_P_ENET0_REFCLK_125M_25M               167	/* CONN.ENET0.REFCLK_125M_25M, CONN.ENET0.PPS, LSIO.GPIO4.IO15 */
+#define SC_P_ENET1_REFCLK_125M_25M               168	/* CONN.ENET1.REFCLK_125M_25M, CONN.ENET1.PPS, LSIO.GPIO4.IO16 */
+#define SC_P_ENET1_MDIO                          169	/* CONN.ENET1.MDIO, DMA.I2C4.SDA, LSIO.GPIO4.IO17 */
+#define SC_P_ENET1_MDC                           170	/* CONN.ENET1.MDC, DMA.I2C4.SCL, LSIO.GPIO4.IO18 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOCT        171	/*  */
+#define SC_P_QSPI1A_SS0_B                        172	/* LSIO.QSPI1A.SS0_B, LSIO.GPIO4.IO19 */
+#define SC_P_QSPI1A_SS1_B                        173	/* LSIO.QSPI1A.SS1_B, LSIO.QSPI1A.SCLK2, LSIO.GPIO4.IO20 */
+#define SC_P_QSPI1A_SCLK                         174	/* LSIO.QSPI1A.SCLK, LSIO.GPIO4.IO21 */
+#define SC_P_QSPI1A_DQS                          175	/* LSIO.QSPI1A.DQS, LSIO.GPIO4.IO22 */
+#define SC_P_QSPI1A_DATA3                        176	/* LSIO.QSPI1A.DATA3, DMA.I2C1.SDA, CONN.USB_OTG1.OC, LSIO.GPIO4.IO23 */
+#define SC_P_QSPI1A_DATA2                        177	/* LSIO.QSPI1A.DATA2, DMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO24 */
+#define SC_P_QSPI1A_DATA1                        178	/* LSIO.QSPI1A.DATA1, DMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO25 */
+#define SC_P_QSPI1A_DATA0                        179	/* LSIO.QSPI1A.DATA0, LSIO.GPIO4.IO26 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI1         180	/*  */
+#define SC_P_QSPI0A_DATA0                        181	/* LSIO.QSPI0A.DATA0 */
+#define SC_P_QSPI0A_DATA1                        182	/* LSIO.QSPI0A.DATA1 */
+#define SC_P_QSPI0A_DATA2                        183	/* LSIO.QSPI0A.DATA2 */
+#define SC_P_QSPI0A_DATA3                        184	/* LSIO.QSPI0A.DATA3 */
+#define SC_P_QSPI0A_DQS                          185	/* LSIO.QSPI0A.DQS */
+#define SC_P_QSPI0A_SS0_B                        186	/* LSIO.QSPI0A.SS0_B */
+#define SC_P_QSPI0A_SS1_B                        187	/* LSIO.QSPI0A.SS1_B, LSIO.QSPI0A.SCLK2 */
+#define SC_P_QSPI0A_SCLK                         188	/* LSIO.QSPI0A.SCLK */
+#define SC_P_QSPI0B_SCLK                         189	/* LSIO.QSPI0B.SCLK */
+#define SC_P_QSPI0B_DATA0                        190	/* LSIO.QSPI0B.DATA0 */
+#define SC_P_QSPI0B_DATA1                        191	/* LSIO.QSPI0B.DATA1 */
+#define SC_P_QSPI0B_DATA2                        192	/* LSIO.QSPI0B.DATA2 */
+#define SC_P_QSPI0B_DATA3                        193	/* LSIO.QSPI0B.DATA3 */
+#define SC_P_QSPI0B_DQS                          194	/* LSIO.QSPI0B.DQS */
+#define SC_P_QSPI0B_SS0_B                        195	/* LSIO.QSPI0B.SS0_B */
+#define SC_P_QSPI0B_SS1_B                        196	/* LSIO.QSPI0B.SS1_B, LSIO.QSPI0B.SCLK2 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0         197	/*  */
+#define SC_P_PCIE_CTRL0_CLKREQ_B                 198	/* HSIO.PCIE0.CLKREQ_B, LSIO.GPIO4.IO27 */
+#define SC_P_PCIE_CTRL0_WAKE_B                   199	/* HSIO.PCIE0.WAKE_B, LSIO.GPIO4.IO28 */
+#define SC_P_PCIE_CTRL0_PERST_B                  200	/* HSIO.PCIE0.PERST_B, LSIO.GPIO4.IO29 */
+#define SC_P_PCIE_CTRL1_CLKREQ_B                 201	/* HSIO.PCIE1.CLKREQ_B, DMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO30 */
+#define SC_P_PCIE_CTRL1_WAKE_B                   202	/* HSIO.PCIE1.WAKE_B, DMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO31 */
+#define SC_P_PCIE_CTRL1_PERST_B                  203	/* HSIO.PCIE1.PERST_B, DMA.I2C1.SCL, CONN.USB_OTG1.PWR, LSIO.GPIO5.IO00 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_PCIESEP       204	/*  */
+#define SC_P_USB_HSIC0_DATA                      205	/* CONN.USB_HSIC0.DATA, DMA.I2C1.SDA, LSIO.GPIO5.IO01 */
+#define SC_P_USB_HSIC0_STROBE                    206	/* CONN.USB_HSIC0.STROBE, DMA.I2C1.SCL, LSIO.GPIO5.IO02 */
+#define SC_P_CALIBRATION_0_HSIC                  207	/*  */
+#define SC_P_CALIBRATION_1_HSIC                  208	/*  */
+#define SC_P_EMMC0_CLK                           209	/* CONN.EMMC0.CLK, CONN.NAND.READY_B */
+#define SC_P_EMMC0_CMD                           210	/* CONN.EMMC0.CMD, CONN.NAND.DQS, AUD.MQS.R, LSIO.GPIO5.IO03 */
+#define SC_P_EMMC0_DATA0                         211	/* CONN.EMMC0.DATA0, CONN.NAND.DATA00, LSIO.GPIO5.IO04 */
+#define SC_P_EMMC0_DATA1                         212	/* CONN.EMMC0.DATA1, CONN.NAND.DATA01, LSIO.GPIO5.IO05 */
+#define SC_P_EMMC0_DATA2                         213	/* CONN.EMMC0.DATA2, CONN.NAND.DATA02, LSIO.GPIO5.IO06 */
+#define SC_P_EMMC0_DATA3                         214	/* CONN.EMMC0.DATA3, CONN.NAND.DATA03, LSIO.GPIO5.IO07 */
+#define SC_P_EMMC0_DATA4                         215	/* CONN.EMMC0.DATA4, CONN.NAND.DATA04, LSIO.GPIO5.IO08 */
+#define SC_P_EMMC0_DATA5                         216	/* CONN.EMMC0.DATA5, CONN.NAND.DATA05, LSIO.GPIO5.IO09 */
+#define SC_P_EMMC0_DATA6                         217	/* CONN.EMMC0.DATA6, CONN.NAND.DATA06, LSIO.GPIO5.IO10 */
+#define SC_P_EMMC0_DATA7                         218	/* CONN.EMMC0.DATA7, CONN.NAND.DATA07, LSIO.GPIO5.IO11 */
+#define SC_P_EMMC0_STROBE                        219	/* CONN.EMMC0.STROBE, CONN.NAND.CLE, LSIO.GPIO5.IO12 */
+#define SC_P_EMMC0_RESET_B                       220	/* CONN.EMMC0.RESET_B, CONN.NAND.WP_B, CONN.USDHC1.VSELECT, LSIO.GPIO5.IO13 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX        221	/*  */
+#define SC_P_USDHC1_CLK                          222	/* CONN.USDHC1.CLK, AUD.MQS.R */
+#define SC_P_USDHC1_CMD                          223	/* CONN.USDHC1.CMD, AUD.MQS.L, LSIO.GPIO5.IO14 */
+#define SC_P_USDHC1_DATA0                        224	/* CONN.USDHC1.DATA0, CONN.NAND.RE_N, LSIO.GPIO5.IO15 */
+#define SC_P_USDHC1_DATA1                        225	/* CONN.USDHC1.DATA1, CONN.NAND.RE_P, LSIO.GPIO5.IO16 */
+#define SC_P_CTL_NAND_RE_P_N                     226	/*  */
+#define SC_P_USDHC1_DATA2                        227	/* CONN.USDHC1.DATA2, CONN.NAND.DQS_N, LSIO.GPIO5.IO17 */
+#define SC_P_USDHC1_DATA3                        228	/* CONN.USDHC1.DATA3, CONN.NAND.DQS_P, LSIO.GPIO5.IO18 */
+#define SC_P_CTL_NAND_DQS_P_N                    229	/*  */
+#define SC_P_USDHC1_DATA4                        230	/* CONN.USDHC1.DATA4, CONN.NAND.CE0_B, AUD.MQS.R, LSIO.GPIO5.IO19 */
+#define SC_P_USDHC1_DATA5                        231	/* CONN.USDHC1.DATA5, CONN.NAND.RE_B, AUD.MQS.L, LSIO.GPIO5.IO20 */
+#define SC_P_USDHC1_DATA6                        232	/* CONN.USDHC1.DATA6, CONN.NAND.WE_B, CONN.USDHC1.WP, LSIO.GPIO5.IO21 */
+#define SC_P_USDHC1_DATA7                        233	/* CONN.USDHC1.DATA7, CONN.NAND.ALE, CONN.USDHC1.CD_B, LSIO.GPIO5.IO22 */
+#define SC_P_USDHC1_STROBE                       234	/* CONN.USDHC1.STROBE, CONN.NAND.CE1_B, CONN.USDHC1.RESET_B, LSIO.GPIO5.IO23 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL2         235	/*  */
+#define SC_P_USDHC2_CLK                          236	/* CONN.USDHC2.CLK, AUD.MQS.R, LSIO.GPIO5.IO24 */
+#define SC_P_USDHC2_CMD                          237	/* CONN.USDHC2.CMD, AUD.MQS.L, LSIO.GPIO5.IO25 */
+#define SC_P_USDHC2_DATA0                        238	/* CONN.USDHC2.DATA0, DMA.UART4.RX, LSIO.GPIO5.IO26 */
+#define SC_P_USDHC2_DATA1                        239	/* CONN.USDHC2.DATA1, DMA.UART4.TX, LSIO.GPIO5.IO27 */
+#define SC_P_USDHC2_DATA2                        240	/* CONN.USDHC2.DATA2, DMA.UART4.CTS_B, LSIO.GPIO5.IO28 */
+#define SC_P_USDHC2_DATA3                        241	/* CONN.USDHC2.DATA3, DMA.UART4.RTS_B, LSIO.GPIO5.IO29 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL3         242	/*  */
+#define SC_P_ENET0_RGMII_TXC                     243	/* CONN.ENET0.RGMII_TXC, CONN.ENET0.RCLK50M_OUT, CONN.ENET0.RCLK50M_IN, LSIO.GPIO5.IO30 */
+#define SC_P_ENET0_RGMII_TX_CTL                  244	/* CONN.ENET0.RGMII_TX_CTL, LSIO.GPIO5.IO31 */
+#define SC_P_ENET0_RGMII_TXD0                    245	/* CONN.ENET0.RGMII_TXD0, LSIO.GPIO6.IO00 */
+#define SC_P_ENET0_RGMII_TXD1                    246	/* CONN.ENET0.RGMII_TXD1, LSIO.GPIO6.IO01 */
+#define SC_P_ENET0_RGMII_TXD2                    247	/* CONN.ENET0.RGMII_TXD2, DMA.UART3.TX, VPU.TSI_S1.VID, LSIO.GPIO6.IO02 */
+#define SC_P_ENET0_RGMII_TXD3                    248	/* CONN.ENET0.RGMII_TXD3, DMA.UART3.RTS_B, VPU.TSI_S1.SYNC, LSIO.GPIO6.IO03 */
+#define SC_P_ENET0_RGMII_RXC                     249	/* CONN.ENET0.RGMII_RXC, DMA.UART3.CTS_B, VPU.TSI_S1.DATA, LSIO.GPIO6.IO04 */
+#define SC_P_ENET0_RGMII_RX_CTL                  250	/* CONN.ENET0.RGMII_RX_CTL, VPU.TSI_S0.VID, LSIO.GPIO6.IO05 */
+#define SC_P_ENET0_RGMII_RXD0                    251	/* CONN.ENET0.RGMII_RXD0, VPU.TSI_S0.SYNC, LSIO.GPIO6.IO06 */
+#define SC_P_ENET0_RGMII_RXD1                    252	/* CONN.ENET0.RGMII_RXD1, VPU.TSI_S0.DATA, LSIO.GPIO6.IO07 */
+#define SC_P_ENET0_RGMII_RXD2                    253	/* CONN.ENET0.RGMII_RXD2, CONN.ENET0.RMII_RX_ER, VPU.TSI_S0.CLK, LSIO.GPIO6.IO08 */
+#define SC_P_ENET0_RGMII_RXD3                    254	/* CONN.ENET0.RGMII_RXD3, DMA.UART3.RX, VPU.TSI_S1.CLK, LSIO.GPIO6.IO09 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB    255	/*  */
+#define SC_P_ENET1_RGMII_TXC                     256	/* CONN.ENET1.RGMII_TXC, CONN.ENET1.RCLK50M_OUT, CONN.ENET1.RCLK50M_IN, LSIO.GPIO6.IO10 */
+#define SC_P_ENET1_RGMII_TX_CTL                  257	/* CONN.ENET1.RGMII_TX_CTL, LSIO.GPIO6.IO11 */
+#define SC_P_ENET1_RGMII_TXD0                    258	/* CONN.ENET1.RGMII_TXD0, LSIO.GPIO6.IO12 */
+#define SC_P_ENET1_RGMII_TXD1                    259	/* CONN.ENET1.RGMII_TXD1, LSIO.GPIO6.IO13 */
+#define SC_P_ENET1_RGMII_TXD2                    260	/* CONN.ENET1.RGMII_TXD2, DMA.UART3.TX, VPU.TSI_S1.VID, LSIO.GPIO6.IO14 */
+#define SC_P_ENET1_RGMII_TXD3                    261	/* CONN.ENET1.RGMII_TXD3, DMA.UART3.RTS_B, VPU.TSI_S1.SYNC, LSIO.GPIO6.IO15 */
+#define SC_P_ENET1_RGMII_RXC                     262	/* CONN.ENET1.RGMII_RXC, DMA.UART3.CTS_B, VPU.TSI_S1.DATA, LSIO.GPIO6.IO16 */
+#define SC_P_ENET1_RGMII_RX_CTL                  263	/* CONN.ENET1.RGMII_RX_CTL, VPU.TSI_S0.VID, LSIO.GPIO6.IO17 */
+#define SC_P_ENET1_RGMII_RXD0                    264	/* CONN.ENET1.RGMII_RXD0, VPU.TSI_S0.SYNC, LSIO.GPIO6.IO18 */
+#define SC_P_ENET1_RGMII_RXD1                    265	/* CONN.ENET1.RGMII_RXD1, VPU.TSI_S0.DATA, LSIO.GPIO6.IO19 */
+#define SC_P_ENET1_RGMII_RXD2                    266	/* CONN.ENET1.RGMII_RXD2, CONN.ENET1.RMII_RX_ER, VPU.TSI_S0.CLK, LSIO.GPIO6.IO20 */
+#define SC_P_ENET1_RGMII_RXD3                    267	/* CONN.ENET1.RGMII_RXD3, DMA.UART3.RX, VPU.TSI_S1.CLK, LSIO.GPIO6.IO21 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA    268	/*  */
+/*@}*/
+
+#endif /* IMX8QM_PADS_H */
diff --git a/plat/imx/common/include/imx8qx_pads.h b/plat/imx/common/include/imx8qx_pads.h
new file mode 100644
index 0000000..5445aa1
--- /dev/null
+++ b/plat/imx/common/include/imx8qx_pads.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file used to configure SoC pad list.
+ */
+
+#ifndef IMX8QX_PADS_H
+#define IMX8QX_PADS_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Pad Definitions
+ */
+/*@{*/
+#define SC_P_PCIE_CTRL0_PERST_B                  0	/* HSIO.PCIE0.PERST_B, LSIO.GPIO4.IO00 */
+#define SC_P_PCIE_CTRL0_CLKREQ_B                 1	/* HSIO.PCIE0.CLKREQ_B, LSIO.GPIO4.IO01 */
+#define SC_P_PCIE_CTRL0_WAKE_B                   2	/* HSIO.PCIE0.WAKE_B, LSIO.GPIO4.IO02 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_PCIESEP       3	/*  */
+#define SC_P_USB_SS3_TC0                         4	/* ADMA.I2C1.SCL, CONN.USB_OTG1.PWR, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO03 */
+#define SC_P_USB_SS3_TC1                         5	/* ADMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO04 */
+#define SC_P_USB_SS3_TC2                         6	/* ADMA.I2C1.SDA, CONN.USB_OTG1.OC, CONN.USB_OTG2.OC, LSIO.GPIO4.IO05 */
+#define SC_P_USB_SS3_TC3                         7	/* ADMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO06 */
+#define SC_P_COMP_CTL_GPIO_3V3_USB3IO            8	/*  */
+#define SC_P_EMMC0_CLK                           9	/* CONN.EMMC0.CLK, CONN.NAND.READY_B, LSIO.GPIO4.IO07 */
+#define SC_P_EMMC0_CMD                           10	/* CONN.EMMC0.CMD, CONN.NAND.DQS, LSIO.GPIO4.IO08 */
+#define SC_P_EMMC0_DATA0                         11	/* CONN.EMMC0.DATA0, CONN.NAND.DATA00, LSIO.GPIO4.IO09 */
+#define SC_P_EMMC0_DATA1                         12	/* CONN.EMMC0.DATA1, CONN.NAND.DATA01, LSIO.GPIO4.IO10 */
+#define SC_P_EMMC0_DATA2                         13	/* CONN.EMMC0.DATA2, CONN.NAND.DATA02, LSIO.GPIO4.IO11 */
+#define SC_P_EMMC0_DATA3                         14	/* CONN.EMMC0.DATA3, CONN.NAND.DATA03, LSIO.GPIO4.IO12 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX0       15	/*  */
+#define SC_P_EMMC0_DATA4                         16	/* CONN.EMMC0.DATA4, CONN.NAND.DATA04, CONN.EMMC0.WP, LSIO.GPIO4.IO13 */
+#define SC_P_EMMC0_DATA5                         17	/* CONN.EMMC0.DATA5, CONN.NAND.DATA05, CONN.EMMC0.VSELECT, LSIO.GPIO4.IO14 */
+#define SC_P_EMMC0_DATA6                         18	/* CONN.EMMC0.DATA6, CONN.NAND.DATA06, CONN.MLB.CLK, LSIO.GPIO4.IO15 */
+#define SC_P_EMMC0_DATA7                         19	/* CONN.EMMC0.DATA7, CONN.NAND.DATA07, CONN.MLB.SIG, LSIO.GPIO4.IO16 */
+#define SC_P_EMMC0_STROBE                        20	/* CONN.EMMC0.STROBE, CONN.NAND.CLE, CONN.MLB.DATA, LSIO.GPIO4.IO17 */
+#define SC_P_EMMC0_RESET_B                       21	/* CONN.EMMC0.RESET_B, CONN.NAND.WP_B, LSIO.GPIO4.IO18 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX1       22	/*  */
+#define SC_P_USDHC1_RESET_B                      23	/* CONN.USDHC1.RESET_B, CONN.NAND.RE_N, ADMA.SPI2.SCK, LSIO.GPIO4.IO19 */
+#define SC_P_USDHC1_VSELECT                      24	/* CONN.USDHC1.VSELECT, CONN.NAND.RE_P, ADMA.SPI2.SDO, CONN.NAND.RE_B, LSIO.GPIO4.IO20 */
+#define SC_P_CTL_NAND_RE_P_N                     25	/*  */
+#define SC_P_USDHC1_WP                           26	/* CONN.USDHC1.WP, CONN.NAND.DQS_N, ADMA.SPI2.SDI, LSIO.GPIO4.IO21 */
+#define SC_P_USDHC1_CD_B                         27	/* CONN.USDHC1.CD_B, CONN.NAND.DQS_P, ADMA.SPI2.CS0, CONN.NAND.DQS, LSIO.GPIO4.IO22 */
+#define SC_P_CTL_NAND_DQS_P_N                    28	/*  */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_VSELSEP       29	/*  */
+#define SC_P_USDHC1_CLK                          30	/* CONN.USDHC1.CLK, ADMA.UART3.RX, LSIO.GPIO4.IO23 */
+#define SC_P_USDHC1_CMD                          31	/* CONN.USDHC1.CMD, CONN.NAND.CE0_B, ADMA.MQS.R, LSIO.GPIO4.IO24 */
+#define SC_P_USDHC1_DATA0                        32	/* CONN.USDHC1.DATA0, CONN.NAND.CE1_B, ADMA.MQS.L, LSIO.GPIO4.IO25 */
+#define SC_P_USDHC1_DATA1                        33	/* CONN.USDHC1.DATA1, CONN.NAND.RE_B, ADMA.UART3.TX, LSIO.GPIO4.IO26 */
+#define SC_P_USDHC1_DATA2                        34	/* CONN.USDHC1.DATA2, CONN.NAND.WE_B, ADMA.UART3.CTS_B, LSIO.GPIO4.IO27 */
+#define SC_P_USDHC1_DATA3                        35	/* CONN.USDHC1.DATA3, CONN.NAND.ALE, ADMA.UART3.RTS_B, LSIO.GPIO4.IO28 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL3         36	/*  */
+#define SC_P_ENET0_RGMII_TXC                     37	/* CONN.ENET0.RGMII_TXC, CONN.ENET0.RCLK50M_OUT, CONN.ENET0.RCLK50M_IN, CONN.NAND.CE1_B, LSIO.GPIO4.IO29 */
+#define SC_P_ENET0_RGMII_TX_CTL                  38	/* CONN.ENET0.RGMII_TX_CTL, CONN.USDHC1.RESET_B, LSIO.GPIO4.IO30 */
+#define SC_P_ENET0_RGMII_TXD0                    39	/* CONN.ENET0.RGMII_TXD0, CONN.USDHC1.VSELECT, LSIO.GPIO4.IO31 */
+#define SC_P_ENET0_RGMII_TXD1                    40	/* CONN.ENET0.RGMII_TXD1, CONN.USDHC1.WP, LSIO.GPIO5.IO00 */
+#define SC_P_ENET0_RGMII_TXD2                    41	/* CONN.ENET0.RGMII_TXD2, CONN.MLB.CLK, CONN.NAND.CE0_B, CONN.USDHC1.CD_B, LSIO.GPIO5.IO01 */
+#define SC_P_ENET0_RGMII_TXD3                    42	/* CONN.ENET0.RGMII_TXD3, CONN.MLB.SIG, CONN.NAND.RE_B, LSIO.GPIO5.IO02 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB0   43	/*  */
+#define SC_P_ENET0_RGMII_RXC                     44	/* CONN.ENET0.RGMII_RXC, CONN.MLB.DATA, CONN.NAND.WE_B, CONN.USDHC1.CLK, LSIO.GPIO5.IO03 */
+#define SC_P_ENET0_RGMII_RX_CTL                  45	/* CONN.ENET0.RGMII_RX_CTL, CONN.USDHC1.CMD, LSIO.GPIO5.IO04 */
+#define SC_P_ENET0_RGMII_RXD0                    46	/* CONN.ENET0.RGMII_RXD0, CONN.USDHC1.DATA0, LSIO.GPIO5.IO05 */
+#define SC_P_ENET0_RGMII_RXD1                    47	/* CONN.ENET0.RGMII_RXD1, CONN.USDHC1.DATA1, LSIO.GPIO5.IO06 */
+#define SC_P_ENET0_RGMII_RXD2                    48	/* CONN.ENET0.RGMII_RXD2, CONN.ENET0.RMII_RX_ER, CONN.USDHC1.DATA2, LSIO.GPIO5.IO07 */
+#define SC_P_ENET0_RGMII_RXD3                    49	/* CONN.ENET0.RGMII_RXD3, CONN.NAND.ALE, CONN.USDHC1.DATA3, LSIO.GPIO5.IO08 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB1   50	/*  */
+#define SC_P_ENET0_REFCLK_125M_25M               51	/* CONN.ENET0.REFCLK_125M_25M, CONN.ENET0.PPS, CONN.ENET1.PPS, LSIO.GPIO5.IO09 */
+#define SC_P_ENET0_MDIO                          52	/* CONN.ENET0.MDIO, ADMA.I2C3.SDA, CONN.ENET1.MDIO, LSIO.GPIO5.IO10 */
+#define SC_P_ENET0_MDC                           53	/* CONN.ENET0.MDC, ADMA.I2C3.SCL, CONN.ENET1.MDC, LSIO.GPIO5.IO11 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOCT        54	/*  */
+#define SC_P_ESAI0_FSR                           55	/* ADMA.ESAI0.FSR, CONN.ENET1.RCLK50M_OUT, ADMA.LCDIF.D00, CONN.ENET1.RGMII_TXC, CONN.ENET1.RCLK50M_IN */
+#define SC_P_ESAI0_FST                           56	/* ADMA.ESAI0.FST, CONN.MLB.CLK, ADMA.LCDIF.D01, CONN.ENET1.RGMII_TXD2, LSIO.GPIO0.IO01 */
+#define SC_P_ESAI0_SCKR                          57	/* ADMA.ESAI0.SCKR, ADMA.LCDIF.D02, CONN.ENET1.RGMII_TX_CTL, LSIO.GPIO0.IO02 */
+#define SC_P_ESAI0_SCKT                          58	/* ADMA.ESAI0.SCKT, CONN.MLB.SIG, ADMA.LCDIF.D03, CONN.ENET1.RGMII_TXD3, LSIO.GPIO0.IO03 */
+#define SC_P_ESAI0_TX0                           59	/* ADMA.ESAI0.TX0, CONN.MLB.DATA, ADMA.LCDIF.D04, CONN.ENET1.RGMII_RXC, LSIO.GPIO0.IO04 */
+#define SC_P_ESAI0_TX1                           60	/* ADMA.ESAI0.TX1, ADMA.LCDIF.D05, CONN.ENET1.RGMII_RXD3, LSIO.GPIO0.IO05 */
+#define SC_P_ESAI0_TX2_RX3                       61	/* ADMA.ESAI0.TX2_RX3, CONN.ENET1.RMII_RX_ER, ADMA.LCDIF.D06, CONN.ENET1.RGMII_RXD2, LSIO.GPIO0.IO06 */
+#define SC_P_ESAI0_TX3_RX2                       62	/* ADMA.ESAI0.TX3_RX2, ADMA.LCDIF.D07, CONN.ENET1.RGMII_RXD1, LSIO.GPIO0.IO07 */
+#define SC_P_ESAI0_TX4_RX1                       63	/* ADMA.ESAI0.TX4_RX1, ADMA.LCDIF.D08, CONN.ENET1.RGMII_TXD0, LSIO.GPIO0.IO08 */
+#define SC_P_ESAI0_TX5_RX0                       64	/* ADMA.ESAI0.TX5_RX0, ADMA.LCDIF.D09, CONN.ENET1.RGMII_TXD1, LSIO.GPIO0.IO09 */
+#define SC_P_SPDIF0_RX                           65	/* ADMA.SPDIF0.RX, ADMA.MQS.R, ADMA.LCDIF.D10, CONN.ENET1.RGMII_RXD0, LSIO.GPIO0.IO10 */
+#define SC_P_SPDIF0_TX                           66	/* ADMA.SPDIF0.TX, ADMA.MQS.L, ADMA.LCDIF.D11, CONN.ENET1.RGMII_RX_CTL, LSIO.GPIO0.IO11 */
+#define SC_P_SPDIF0_EXT_CLK                      67	/* ADMA.SPDIF0.EXT_CLK, ADMA.LCDIF.D12, CONN.ENET1.REFCLK_125M_25M, LSIO.GPIO0.IO12 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHB       68	/*  */
+#define SC_P_SPI3_SCK                            69	/* ADMA.SPI3.SCK, ADMA.LCDIF.D13, LSIO.GPIO0.IO13 */
+#define SC_P_SPI3_SDO                            70	/* ADMA.SPI3.SDO, ADMA.LCDIF.D14, LSIO.GPIO0.IO14 */
+#define SC_P_SPI3_SDI                            71	/* ADMA.SPI3.SDI, ADMA.LCDIF.D15, LSIO.GPIO0.IO15 */
+#define SC_P_SPI3_CS0                            72	/* ADMA.SPI3.CS0, ADMA.ACM.MCLK_OUT1, ADMA.LCDIF.HSYNC, LSIO.GPIO0.IO16 */
+#define SC_P_SPI3_CS1                            73	/* ADMA.SPI3.CS1, ADMA.I2C3.SCL, ADMA.LCDIF.RESET, ADMA.SPI2.CS0, ADMA.LCDIF.D16 */
+#define SC_P_MCLK_IN1                            74	/* ADMA.ACM.MCLK_IN1, ADMA.I2C3.SDA, ADMA.LCDIF.EN, ADMA.SPI2.SCK, ADMA.LCDIF.D17 */
+#define SC_P_MCLK_IN0                            75	/* ADMA.ACM.MCLK_IN0, ADMA.ESAI0.RX_HF_CLK, ADMA.LCDIF.VSYNC, ADMA.SPI2.SDI, LSIO.GPIO0.IO19 */
+#define SC_P_MCLK_OUT0                           76	/* ADMA.ACM.MCLK_OUT0, ADMA.ESAI0.TX_HF_CLK, ADMA.LCDIF.CLK, ADMA.SPI2.SDO, LSIO.GPIO0.IO20 */
+#define SC_P_UART1_TX                            77	/* ADMA.UART1.TX, LSIO.PWM0.OUT, LSIO.GPT0.CAPTURE, LSIO.GPIO0.IO21 */
+#define SC_P_UART1_RX                            78	/* ADMA.UART1.RX, LSIO.PWM1.OUT, LSIO.GPT0.COMPARE, LSIO.GPT1.CLK, LSIO.GPIO0.IO22 */
+#define SC_P_UART1_RTS_B                         79	/* ADMA.UART1.RTS_B, LSIO.PWM2.OUT, ADMA.LCDIF.D16, LSIO.GPT1.CAPTURE, LSIO.GPT0.CLK */
+#define SC_P_UART1_CTS_B                         80	/* ADMA.UART1.CTS_B, LSIO.PWM3.OUT, ADMA.LCDIF.D17, LSIO.GPT1.COMPARE, LSIO.GPIO0.IO24 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHK       81	/*  */
+#define SC_P_SAI0_TXD                            82	/* ADMA.SAI0.TXD, ADMA.SAI1.RXC, ADMA.SPI1.SDO, ADMA.LCDIF.D18, LSIO.GPIO0.IO25 */
+#define SC_P_SAI0_TXC                            83	/* ADMA.SAI0.TXC, ADMA.SAI1.TXD, ADMA.SPI1.SDI, ADMA.LCDIF.D19, LSIO.GPIO0.IO26 */
+#define SC_P_SAI0_RXD                            84	/* ADMA.SAI0.RXD, ADMA.SAI1.RXFS, ADMA.SPI1.CS0, ADMA.LCDIF.D20, LSIO.GPIO0.IO27 */
+#define SC_P_SAI0_TXFS                           85	/* ADMA.SAI0.TXFS, ADMA.SPI2.CS1, ADMA.SPI1.SCK, LSIO.GPIO0.IO28 */
+#define SC_P_SAI1_RXD                            86	/* ADMA.SAI1.RXD, ADMA.SAI0.RXFS, ADMA.SPI1.CS1, ADMA.LCDIF.D21, LSIO.GPIO0.IO29 */
+#define SC_P_SAI1_RXC                            87	/* ADMA.SAI1.RXC, ADMA.SAI1.TXC, ADMA.LCDIF.D22, LSIO.GPIO0.IO30 */
+#define SC_P_SAI1_RXFS                           88	/* ADMA.SAI1.RXFS, ADMA.SAI1.TXFS, ADMA.LCDIF.D23, LSIO.GPIO0.IO31 */
+#define SC_P_SPI2_CS0                            89	/* ADMA.SPI2.CS0, LSIO.GPIO1.IO00 */
+#define SC_P_SPI2_SDO                            90	/* ADMA.SPI2.SDO, LSIO.GPIO1.IO01 */
+#define SC_P_SPI2_SDI                            91	/* ADMA.SPI2.SDI, LSIO.GPIO1.IO02 */
+#define SC_P_SPI2_SCK                            92	/* ADMA.SPI2.SCK, LSIO.GPIO1.IO03 */
+#define SC_P_SPI0_SCK                            93	/* ADMA.SPI0.SCK, ADMA.SAI0.TXC, M40.I2C0.SCL, M40.GPIO0.IO00, LSIO.GPIO1.IO04 */
+#define SC_P_SPI0_SDI                            94	/* ADMA.SPI0.SDI, ADMA.SAI0.TXD, M40.TPM0.CH0, M40.GPIO0.IO02, LSIO.GPIO1.IO05 */
+#define SC_P_SPI0_SDO                            95	/* ADMA.SPI0.SDO, ADMA.SAI0.TXFS, M40.I2C0.SDA, M40.GPIO0.IO01, LSIO.GPIO1.IO06 */
+#define SC_P_SPI0_CS1                            96	/* ADMA.SPI0.CS1, ADMA.SAI0.RXC, ADMA.SAI1.TXD, ADMA.LCD_PWM0.OUT, LSIO.GPIO1.IO07 */
+#define SC_P_SPI0_CS0                            97	/* ADMA.SPI0.CS0, ADMA.SAI0.RXD, M40.TPM0.CH1, M40.GPIO0.IO03, LSIO.GPIO1.IO08 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHT       98	/*  */
+#define SC_P_ADC_IN1                             99	/* ADMA.ADC.IN1, M40.I2C0.SDA, M40.GPIO0.IO01, LSIO.GPIO1.IO09 */
+#define SC_P_ADC_IN0                             100	/* ADMA.ADC.IN0, M40.I2C0.SCL, M40.GPIO0.IO00, LSIO.GPIO1.IO10 */
+#define SC_P_ADC_IN3                             101	/* ADMA.ADC.IN3, M40.UART0.TX, M40.GPIO0.IO03, ADMA.ACM.MCLK_OUT0, LSIO.GPIO1.IO11 */
+#define SC_P_ADC_IN2                             102	/* ADMA.ADC.IN2, M40.UART0.RX, M40.GPIO0.IO02, ADMA.ACM.MCLK_IN0, LSIO.GPIO1.IO12 */
+#define SC_P_ADC_IN5                             103	/* ADMA.ADC.IN5, M40.TPM0.CH1, M40.GPIO0.IO05, LSIO.GPIO1.IO13 */
+#define SC_P_ADC_IN4                             104	/* ADMA.ADC.IN4, M40.TPM0.CH0, M40.GPIO0.IO04, LSIO.GPIO1.IO14 */
+#define SC_P_FLEXCAN0_RX                         105	/* ADMA.FLEXCAN0.RX, ADMA.SAI2.RXC, ADMA.UART0.RTS_B, ADMA.SAI1.TXC, LSIO.GPIO1.IO15 */
+#define SC_P_FLEXCAN0_TX                         106	/* ADMA.FLEXCAN0.TX, ADMA.SAI2.RXD, ADMA.UART0.CTS_B, ADMA.SAI1.TXFS, LSIO.GPIO1.IO16 */
+#define SC_P_FLEXCAN1_RX                         107	/* ADMA.FLEXCAN1.RX, ADMA.SAI2.RXFS, ADMA.FTM.CH2, ADMA.SAI1.TXD, LSIO.GPIO1.IO17 */
+#define SC_P_FLEXCAN1_TX                         108	/* ADMA.FLEXCAN1.TX, ADMA.SAI3.RXC, ADMA.DMA0.REQ_IN0, ADMA.SAI1.RXD, LSIO.GPIO1.IO18 */
+#define SC_P_FLEXCAN2_RX                         109	/* ADMA.FLEXCAN2.RX, ADMA.SAI3.RXD, ADMA.UART3.RX, ADMA.SAI1.RXFS, LSIO.GPIO1.IO19 */
+#define SC_P_FLEXCAN2_TX                         110	/* ADMA.FLEXCAN2.TX, ADMA.SAI3.RXFS, ADMA.UART3.TX, ADMA.SAI1.RXC, LSIO.GPIO1.IO20 */
+#define SC_P_UART0_RX                            111	/* ADMA.UART0.RX, ADMA.MQS.R, ADMA.FLEXCAN0.RX, SCU.UART0.RX, LSIO.GPIO1.IO21 */
+#define SC_P_UART0_TX                            112	/* ADMA.UART0.TX, ADMA.MQS.L, ADMA.FLEXCAN0.TX, SCU.UART0.TX, LSIO.GPIO1.IO22 */
+#define SC_P_UART2_TX                            113	/* ADMA.UART2.TX, ADMA.FTM.CH1, ADMA.FLEXCAN1.TX, LSIO.GPIO1.IO23 */
+#define SC_P_UART2_RX                            114	/* ADMA.UART2.RX, ADMA.FTM.CH0, ADMA.FLEXCAN1.RX, LSIO.GPIO1.IO24 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLH        115	/*  */
+#define SC_P_MIPI_DSI0_I2C0_SCL                  116	/* MIPI_DSI0.I2C0.SCL, MIPI_DSI1.GPIO0.IO02, LSIO.GPIO1.IO25 */
+#define SC_P_MIPI_DSI0_I2C0_SDA                  117	/* MIPI_DSI0.I2C0.SDA, MIPI_DSI1.GPIO0.IO03, LSIO.GPIO1.IO26 */
+#define SC_P_MIPI_DSI0_GPIO0_00                  118	/* MIPI_DSI0.GPIO0.IO00, ADMA.I2C1.SCL, MIPI_DSI0.PWM0.OUT, LSIO.GPIO1.IO27 */
+#define SC_P_MIPI_DSI0_GPIO0_01                  119	/* MIPI_DSI0.GPIO0.IO01, ADMA.I2C1.SDA, LSIO.GPIO1.IO28 */
+#define SC_P_MIPI_DSI1_I2C0_SCL                  120	/* MIPI_DSI1.I2C0.SCL, MIPI_DSI0.GPIO0.IO02, LSIO.GPIO1.IO29 */
+#define SC_P_MIPI_DSI1_I2C0_SDA                  121	/* MIPI_DSI1.I2C0.SDA, MIPI_DSI0.GPIO0.IO03, LSIO.GPIO1.IO30 */
+#define SC_P_MIPI_DSI1_GPIO0_00                  122	/* MIPI_DSI1.GPIO0.IO00, ADMA.I2C2.SCL, MIPI_DSI1.PWM0.OUT, LSIO.GPIO1.IO31 */
+#define SC_P_MIPI_DSI1_GPIO0_01                  123	/* MIPI_DSI1.GPIO0.IO01, ADMA.I2C2.SDA, LSIO.GPIO2.IO00 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO   124	/*  */
+#define SC_P_JTAG_TRST_B                         125	/* SCU.JTAG.TRST_B, SCU.WDOG0.WDOG_OUT */
+#define SC_P_PMIC_I2C_SCL                        126	/* SCU.PMIC_I2C.SCL, SCU.GPIO0.IOXX_PMIC_A35_ON, LSIO.GPIO2.IO01 */
+#define SC_P_PMIC_I2C_SDA                        127	/* SCU.PMIC_I2C.SDA, SCU.GPIO0.IOXX_PMIC_GPU_ON, LSIO.GPIO2.IO02 */
+#define SC_P_PMIC_INT_B                          128	/* SCU.DSC.PMIC_INT_B */
+#define SC_P_SCU_GPIO0_00                        129	/* SCU.GPIO0.IO00, SCU.UART0.RX, M40.UART0.RX, ADMA.UART3.RX, LSIO.GPIO2.IO03 */
+#define SC_P_SCU_GPIO0_01                        130	/* SCU.GPIO0.IO01, SCU.UART0.TX, M40.UART0.TX, ADMA.UART3.TX, SCU.WDOG0.WDOG_OUT */
+#define SC_P_SCU_PMIC_STANDBY                    131	/* SCU.DSC.PMIC_STANDBY */
+#define SC_P_SCU_BOOT_MODE0                      132	/* SCU.DSC.BOOT_MODE0 */
+#define SC_P_SCU_BOOT_MODE1                      133	/* SCU.DSC.BOOT_MODE1 */
+#define SC_P_SCU_BOOT_MODE2                      134	/* SCU.DSC.BOOT_MODE2, SCU.PMIC_I2C.SDA */
+#define SC_P_SCU_BOOT_MODE3                      135	/* SCU.DSC.BOOT_MODE3, SCU.PMIC_I2C.SCL, SCU.DSC.RTC_CLOCK_OUTPUT_32K */
+#define SC_P_CSI_D00                             136	/* CI_PI.D02, ADMA.SAI0.RXC */
+#define SC_P_CSI_D01                             137	/* CI_PI.D03, ADMA.SAI0.RXD */
+#define SC_P_CSI_D02                             138	/* CI_PI.D04, ADMA.SAI0.RXFS */
+#define SC_P_CSI_D03                             139	/* CI_PI.D05, ADMA.SAI2.RXC */
+#define SC_P_CSI_D04                             140	/* CI_PI.D06, ADMA.SAI2.RXD */
+#define SC_P_CSI_D05                             141	/* CI_PI.D07, ADMA.SAI2.RXFS */
+#define SC_P_CSI_D06                             142	/* CI_PI.D08, ADMA.SAI3.RXC */
+#define SC_P_CSI_D07                             143	/* CI_PI.D09, ADMA.SAI3.RXD */
+#define SC_P_CSI_HSYNC                           144	/* CI_PI.HSYNC, CI_PI.D00, ADMA.SAI3.RXFS */
+#define SC_P_CSI_VSYNC                           145	/* CI_PI.VSYNC, CI_PI.D01 */
+#define SC_P_CSI_PCLK                            146	/* CI_PI.PCLK, MIPI_CSI0.I2C0.SCL, ADMA.SPI1.SCK, LSIO.GPIO3.IO00 */
+#define SC_P_CSI_MCLK                            147	/* CI_PI.MCLK, MIPI_CSI0.I2C0.SDA, ADMA.SPI1.SDO, LSIO.GPIO3.IO01 */
+#define SC_P_CSI_EN                              148	/* CI_PI.EN, CI_PI.I2C.SCL, ADMA.I2C3.SCL, ADMA.SPI1.SDI, LSIO.GPIO3.IO02 */
+#define SC_P_CSI_RESET                           149	/* CI_PI.RESET, CI_PI.I2C.SDA, ADMA.I2C3.SDA, ADMA.SPI1.CS0, LSIO.GPIO3.IO03 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHD       150	/*  */
+#define SC_P_MIPI_CSI0_MCLK_OUT                  151	/* MIPI_CSI0.ACM.MCLK_OUT, LSIO.GPIO3.IO04 */
+#define SC_P_MIPI_CSI0_I2C0_SCL                  152	/* MIPI_CSI0.I2C0.SCL, MIPI_CSI0.GPIO0.IO02, LSIO.GPIO3.IO05 */
+#define SC_P_MIPI_CSI0_I2C0_SDA                  153	/* MIPI_CSI0.I2C0.SDA, MIPI_CSI0.GPIO0.IO03, LSIO.GPIO3.IO06 */
+#define SC_P_MIPI_CSI0_GPIO0_01                  154	/* MIPI_CSI0.GPIO0.IO01, ADMA.I2C0.SDA, LSIO.GPIO3.IO07 */
+#define SC_P_MIPI_CSI0_GPIO0_00                  155	/* MIPI_CSI0.GPIO0.IO00, ADMA.I2C0.SCL, LSIO.GPIO3.IO08 */
+#define SC_P_QSPI0A_DATA0                        156	/* LSIO.QSPI0A.DATA0, LSIO.GPIO3.IO09 */
+#define SC_P_QSPI0A_DATA1                        157	/* LSIO.QSPI0A.DATA1, LSIO.GPIO3.IO10 */
+#define SC_P_QSPI0A_DATA2                        158	/* LSIO.QSPI0A.DATA2, LSIO.GPIO3.IO11 */
+#define SC_P_QSPI0A_DATA3                        159	/* LSIO.QSPI0A.DATA3, LSIO.GPIO3.IO12 */
+#define SC_P_QSPI0A_DQS                          160	/* LSIO.QSPI0A.DQS, LSIO.GPIO3.IO13 */
+#define SC_P_QSPI0A_SS0_B                        161	/* LSIO.QSPI0A.SS0_B, LSIO.GPIO3.IO14 */
+#define SC_P_QSPI0A_SS1_B                        162	/* LSIO.QSPI0A.SS1_B, LSIO.GPIO3.IO15 */
+#define SC_P_QSPI0A_SCLK                         163	/* LSIO.QSPI0A.SCLK, LSIO.GPIO3.IO16 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0A        164	/*  */
+#define SC_P_QSPI0B_SCLK                         165	/* LSIO.QSPI0B.SCLK, LSIO.QSPI1A.SCLK, LSIO.KPP0.COL0, LSIO.GPIO3.IO17 */
+#define SC_P_QSPI0B_DATA0                        166	/* LSIO.QSPI0B.DATA0, LSIO.QSPI1A.DATA0, LSIO.KPP0.COL1, LSIO.GPIO3.IO18 */
+#define SC_P_QSPI0B_DATA1                        167	/* LSIO.QSPI0B.DATA1, LSIO.QSPI1A.DATA1, LSIO.KPP0.COL2, LSIO.GPIO3.IO19 */
+#define SC_P_QSPI0B_DATA2                        168	/* LSIO.QSPI0B.DATA2, LSIO.QSPI1A.DATA2, LSIO.KPP0.COL3, LSIO.GPIO3.IO20 */
+#define SC_P_QSPI0B_DATA3                        169	/* LSIO.QSPI0B.DATA3, LSIO.QSPI1A.DATA3, LSIO.KPP0.ROW0, LSIO.GPIO3.IO21 */
+#define SC_P_QSPI0B_DQS                          170	/* LSIO.QSPI0B.DQS, LSIO.QSPI1A.DQS, LSIO.KPP0.ROW1, LSIO.GPIO3.IO22 */
+#define SC_P_QSPI0B_SS0_B                        171	/* LSIO.QSPI0B.SS0_B, LSIO.QSPI1A.SS0_B, LSIO.KPP0.ROW2, LSIO.GPIO3.IO23 */
+#define SC_P_QSPI0B_SS1_B                        172	/* LSIO.QSPI0B.SS1_B, LSIO.QSPI1A.SS1_B, LSIO.KPP0.ROW3, LSIO.GPIO3.IO24 */
+#define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0B        173	/*  */
+/*@}*/
+
+#endif /* IMX8QX_PADS_H */
diff --git a/plat/imx/common/include/imx_aips.h b/plat/imx/common/include/imx_aips.h
new file mode 100644
index 0000000..1d41fe0
--- /dev/null
+++ b/plat/imx/common/include/imx_aips.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_AIPS_H
+#define IMX_AIPS_H
+
+#include <stdint.h>
+
+#define AIPSTZ_OAPCR_COUNT	0x05
+
+struct aipstz_regs {
+	uint32_t aipstz_mpr;
+	uint32_t res[15];
+	uint32_t aipstz_opacr[AIPSTZ_OAPCR_COUNT];
+};
+
+void imx_aips_init(void);
+
+#endif /* IMX_AIPS_H */
diff --git a/plat/imx/common/include/imx_caam.h b/plat/imx/common/include/imx_caam.h
new file mode 100644
index 0000000..335bd0f
--- /dev/null
+++ b/plat/imx/common/include/imx_caam.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_CAAM_H
+#define IMX_CAAM_H
+
+#include <stdint.h>
+#include <arch.h>
+#include <imx_regs.h>
+
+struct caam_job_ring {
+	uint32_t jrmidr_ms;
+	uint32_t jrmidr_ls;
+};
+
+struct caam_rtic_mid {
+	uint32_t rticmidr_ms;
+	uint32_t rticmidr_ls;
+};
+
+struct caam_deco {
+	uint32_t		deco_mid_ms;
+	uint32_t		deco_mid_ls;
+};
+
+#define JOB_RING_OFFSET 0x10
+#define DEBUGCTL_OFFSET	0x58
+#define RES2_SIZE (DEBUGCTL_OFFSET - JOB_RING_OFFSET - \
+	(sizeof(struct caam_job_ring) * CAAM_NUM_JOB_RINGS))
+
+#define RTIC_MID_OFFSET 0x60
+#define DECORR_OFFSET	0x9C
+#define RES3_SIZE (DECORR_OFFSET - RTIC_MID_OFFSET - \
+	(sizeof(struct caam_rtic_mid) * CAAM_NUM_RTIC))
+
+#define DECO_MID_OFFSET	0xA0
+#define DAR_OFFSET	0x120
+#define RES4_SIZE (DAR_OFFSET - DECO_MID_OFFSET - \
+	(sizeof(struct caam_deco) * CAAM_NUM_DECO))
+
+struct caam_ctrl {
+	uint32_t		res0;
+	uint32_t		mcfgr;
+	uint32_t		res1;
+	uint32_t		scfgr;
+	struct caam_job_ring	jr[CAAM_NUM_JOB_RINGS];
+	uint8_t			res2[RES2_SIZE];
+	uint32_t		debuctl;
+	uint32_t		jrstartr;
+	struct caam_rtic_mid	mid[CAAM_NUM_RTIC];
+	uint8_t			res3[RES3_SIZE];
+	uint32_t		decorr;
+	struct caam_deco	deco[CAAM_NUM_DECO];
+	uint8_t			res4[RES4_SIZE];
+	uint32_t		dar;
+	uint32_t		drr;
+} __packed;
+
+/* Job ring control bits */
+#define JROWN_NS		BIT(3)
+#define JROWN_MID		0x01
+
+/* Declare CAAM API */
+void imx_caam_init(void);
+
+#endif /* IMX_CAAM_H */
diff --git a/plat/imx/common/include/imx_clock.h b/plat/imx/common/include/imx_clock.h
new file mode 100644
index 0000000..d75dcff
--- /dev/null
+++ b/plat/imx/common/include/imx_clock.h
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_CLOCK_H
+#define IMX_CLOCK_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct ccm_pll_ctrl {
+	uint32_t ccm_pll_ctrl;
+	uint32_t ccm_pll_ctrl_set;
+	uint32_t ccm_pll_ctrl_clr;
+	uint32_t ccm_pll_ctrl_tog;
+};
+
+/* Clock gate control */
+struct ccm_clk_gate_ctrl {
+	uint32_t ccm_ccgr;
+	uint32_t ccm_ccgr_set;
+	uint32_t ccm_ccgr_clr;
+	uint32_t ccm_ccgr_tog;
+};
+
+#define CCM_CCGR_SETTING0_DOM_CLK_NONE		0
+#define CCM_CCGR_SETTING0_DOM_CLK_RUN		BIT(0)
+#define CCM_CCGR_SETTING0_DOM_CLK_RUN_WAIT	BIT(1)
+#define CCM_CCGR_SETTING0_DOM_CLK_ALWAYS	(BIT(1) | BIT(0))
+#define CCM_CCGR_SETTING1_DOM_CLK_NONE		0
+#define CCM_CCGR_SETTING1_DOM_CLK_RUN		BIT(4)
+#define CCM_CCGR_SETTING1_DOM_CLK_RUN_WAIT	BIT(5)
+#define CCM_CCGR_SETTING1_DOM_CLK_ALWAYS	(BIT(5) | BIT(4))
+#define CCM_CCGR_SETTING2_DOM_CLK_NONE		0
+#define CCM_CCGR_SETTING2_DOM_CLK_RUN		BIT(8)
+#define CCM_CCGR_SETTING2_DOM_CLK_RUN_WAIT	BIT(9)
+#define CCM_CCGR_SETTING2_DOM_CLK_ALWAYS	(BIT(9) | BIT(8))
+#define CCM_CCGR_SETTING3_DOM_CLK_NONE		0
+#define CCM_CCGR_SETTING3_DOM_CLK_RUN		BIT(12)
+#define CCM_CCGR_SETTING3_DOM_CLK_RUN_WAIT	BIT(13)
+#define CCM_CCGR_SETTING3_DOM_CLK_ALWAYS	(BIT(13) | BIT(12))
+
+enum {
+	CCM_CCGR_ID_ADC = 32,
+	CCM_CCGR_ID_AIPS1TZ = 10,
+	CCM_CCGR_ID_AIPS2TZ = 11,
+	CCM_CCGR_ID_AIPS3TZ = 12,
+	CCM_CCGR_ID_APBHDMA = 20,
+	CCM_CCGR_ID_CAAM = 36,
+	CCM_CCGR_ID_CM4 = 1,
+	CCM_CCGR_ID_CSI = 73,
+	CCM_CCGR_ID_CSU = 45,
+	CCM_CCGR_ID_DAP = 47,
+	CCM_CCGR_ID_DBGMON = 46,
+	CCM_CCGR_ID_DDRC = 19,
+	CCM_CCGR_ID_ECSPI1 = 120,
+	CCM_CCGR_ID_ECSPI2 = 121,
+	CCM_CCGR_ID_ECSPI3 = 122,
+	CCM_CCGR_ID_ECSPI4 = 123,
+	CCM_CCGR_ID_EIM = 22,
+	CCM_CCGR_ID_ENET1 = 112,
+	CCM_CCGR_ID_ENET2 = 113,
+	CCM_CCGR_ID_EPDC = 74,
+	CCM_CCGR_ID_FLEXCAN1 = 116,
+	CCM_CCGR_ID_FLEXCAN2 = 117,
+	CCM_CCGR_ID_FLEXTIMER1 = 128,
+	CCM_CCGR_ID_FLEXTIMER2 = 129,
+	CCM_CCGR_ID_GPIO1 = 160,
+	CCM_CCGR_ID_GPIO2 = 161,
+	CCM_CCGR_ID_GPIO3 = 162,
+	CCM_CCGR_ID_GPIO4 = 163,
+	CCM_CCGR_ID_GPIO5 = 164,
+	CCM_CCGR_ID_GPIO6 = 165,
+	CCM_CCGR_ID_GPIO7 = 166,
+	CCM_CCGR_ID_GPT1 = 124,
+	CCM_CCGR_ID_GPT2 = 125,
+	CCM_CCGR_ID_GPT3 = 126,
+	CCM_CCGR_ID_GPT4 = 127,
+	CCM_CCGR_ID_I2C1 = 136,
+	CCM_CCGR_ID_I2C2 = 137,
+	CCM_CCGR_ID_I2C3 = 138,
+	CCM_CCGR_ID_I2C4 = 139,
+	CCM_CCGR_ID_IOMUXC1 = 168,
+	CCM_CCGR_ID_IOMUXC2 = 169,
+	CCM_CCGR_ID_KPP = 120,
+	CCM_CCGR_ID_LCDIF = 75,
+	CCM_CCGR_ID_MIPI_CSI = 100,
+	CCM_CCGR_ID_MIPI_DSI = 101,
+	CCM_CCGR_ID_MIPI_PHY = 102,
+	CCM_CCGR_ID_MU = 39,
+	CCM_CCGR_ID_OCOTP = 35,
+	CCM_CCGR_ID_OCRAM = 17,
+	CCM_CCGR_ID_OCRAM_S = 18,
+	CCM_CCGR_ID_PCIE = 96,
+	CCM_CCGR_ID_PCIE_PHY = 96,
+	CCM_CCGR_ID_PERFMON1 = 68,
+	CCM_CCGR_ID_PERFMON2 = 69,
+	CCM_CCGR_ID_PWM1 = 132,
+	CCM_CCGR_ID_PWM2 = 133,
+	CCM_CCGR_ID_PWM3 = 134,
+	CCM_CCGR_ID_PMM4 = 135,
+	CCM_CCGR_ID_PXP = 76,
+	CCM_CCGR_ID_QOS1 = 42,
+	CCM_CCGR_ID_QOS2 = 43,
+	CCM_CCGR_ID_QOS3 = 44,
+	CCM_CCGR_ID_QUADSPI = 21,
+	CCM_CCGR_ID_RDC = 38,
+	CCM_CCGR_ID_ROMCP = 16,
+	CCM_CCGR_ID_SAI1 = 140,
+	CCM_CCGR_ID_SAI2 = 141,
+	CCM_CCGR_ID_SAI3 = 142,
+	CCM_CCGR_ID_SCTR = 34,
+	CCM_CCGR_ID_SDMA = 72,
+	CCM_CCGR_ID_SEC = 49,
+	CCM_CCGR_ID_SEMA42_1 = 64,
+	CCM_CCGR_ID_SEMA42_2 = 65,
+	CCM_CCGR_ID_SIM_DISPLAY = 5,
+	CCM_CCGR_ID_SIM_ENET = 6,
+	CCM_CCGR_ID_SIM_M = 7,
+	CCM_CCGR_ID_SIM_MAIN = 4,
+	CCM_CCGR_ID_SIM_S = 8,
+	CCM_CCGR_ID_SIM_WAKEUP = 9,
+	CCM_CCGR_ID_SIM1 = 144,
+	CCM_CCGR_ID_SIM2 = 145,
+	CCM_CCGR_ID_SIM_NAND = 20,
+	CCM_CCGR_ID_DISPLAY_CM4 = 1,
+	CCM_CCGR_ID_DRAM = 19,
+	CCM_CCGR_ID_SNVS = 37,
+	CCM_CCGR_ID_SPBA = 12,
+	CCM_CCGR_ID_TRACE = 48,
+	CCM_CCGR_ID_TZASC = 19,
+	CCM_CCGR_ID_UART1 = 148,
+	CCM_CCGR_ID_UART2 = 149,
+	CCM_CCGR_ID_UART3 = 150,
+	CCM_CCGR_ID_UART4 = 151,
+	CCM_CCGR_ID_UART5 = 152,
+	CCM_CCGR_ID_UART6 = 153,
+	CCM_CCGR_ID_UART7 = 154,
+	CCM_CCGR_ID_USB_HS = 40,
+	CCM_CCGR_ID_USB_IPG = 104,
+	CCM_CCGR_ID_USB_PHY_480MCLK = 105,
+	CCM_CCGR_ID_USB_OTG1_PHY = 106,
+	CCM_CCGR_ID_USB_OTG2_PHY = 107,
+	CCM_CCGR_ID_USBHDC1 = 108,
+	CCM_CCGR_ID_USBHDC2 = 109,
+	CCM_CCGR_ID_USBHDC3 = 110,
+	CCM_CCGR_ID_WDOG1 = 156,
+	CCM_CCGR_ID_WDOG2 = 157,
+	CCM_CCGR_ID_WDOG3 = 158,
+	CCM_CCGR_ID_WDOG4 = 159,
+};
+
+/* Clock target block */
+struct ccm_target_root_ctrl {
+	uint32_t ccm_target_root;
+	uint32_t ccm_target_root_set;
+	uint32_t ccm_target_root_clr;
+	uint32_t ccm_target_root_tog;
+	uint32_t ccm_misc;
+	uint32_t ccm_misc_set;
+	uint32_t ccm_misc_clr;
+	uint32_t ccm_misc_tog;
+	uint32_t ccm_post;
+	uint32_t ccm_post_set;
+	uint32_t ccm_post_clr;
+	uint32_t ccm_post_tog;
+	uint32_t ccm_pre;
+	uint32_t ccm_pre_set;
+	uint32_t ccm_pre_clr;
+	uint32_t ccm_pre_tog;
+	uint32_t reserved[0x0c];
+	uint32_t ccm_access_ctrl;
+	uint32_t ccm_access_ctrl_set;
+	uint32_t ccm_access_ctrl_clr;
+	uint32_t ccm_access_ctrl_tog;
+};
+
+#define CCM_TARGET_ROOT_ENABLE		BIT(28)
+#define CCM_TARGET_MUX(x)		(((x) - 1) << 24)
+#define CCM_TARGET_PRE_PODF(x)		(((x) - 1) << 16)
+#define CCM_TARGET_POST_PODF(x)		((x) - 1)
+
+/* Target root MUX values - selects the clock source for a block */
+/* ARM_A7_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_ARM_PLL			BIT(24)
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_ENET_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_DDR_PLL			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_SYS_PLL_PFD0		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* ARM_M4_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_ENET_PLL_DIV4		BIT(25)
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_SYS_PLL_PFD2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_DDR_PLL_DIV2		BIT(26)
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOTV_IDEO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ARM_M4_CLK_ROOTUSB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* MAIN_AXI_CLK_ROOT */
+
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_SYS_PLL_PFD1		BIT(24)
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_ENET_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_SYS_PLL_PFD5		BIT(26)
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_SYS_PLL_PFD7		((BIT(26) | BIT(25) | BIT(24))
+
+/* DISP_AXI_CLK_ROOT */
+
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_SYS_PLL_PFD1		BIT(24)
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_ENET_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_SYS_PLL_PFD6		BIT(26)
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_SYS_PLL_PFD7		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_VIDEO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* ENET_AXI_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_SYS_PLL_PFD2		BIT(24)
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_ENET_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_SYS_PLL_DIV2		BIT(26)
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_SYS_PLL_PFD4		((BIT(26) | BIT(25) | BIT(24))
+
+/* NAND_USDHC_BUS_CLK_ROOT */
+
+#define CM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AHB		BIT(24)
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_DDR_PLL_DIV2	BIT(25)
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_SYS_PLL_DIV2	(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_SYS_PLL_PFD2_DIV2	BIT(26)
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_SYS_PLL_PFD6	(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_ENET_PLL_DIV4	(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AUDIO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* AHB_CLK_ROOT */
+
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_SYS_PLL_PFD2			BIT(24)
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_DDR_PLL_DIV2			BIT(25)
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_SYS_PLL_PFD0			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_ENET_PLL_DIV8			BIT(26)
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_USB_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_AHB_CLK_ROOT_VIDEO_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* IPG_CLK_ROOT */
+#define CCM_TRGT_MUX_IPG_CLK_ROOT_AHB_CLK_ROOT			0
+
+/* DRAM_PHYM_CLK_ROOT */
+#define CCM_TRGT_MUX_DRAM_PHYM_CLK_ROOT_DDR_PLL			0
+#define CCM_TRGT_MUX_DRAM_PHYM_CLK_ROOT_DRAM_PHYM_ALT_CLK_ROOT	BIT(24)
+
+/* DRAM_CLK_ROOT */
+
+#define CCM_TRGT_MUX_DRAM_CLK_ROOT_DDR_PLL			0
+#define CCM_TRGT_MUX_DRAM_CLK_ROOT_DRAM_ALT_CLK_ROOT		BIT(24)
+
+/* DRAM_PHYM_ALT_CLK_ROOT */
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_DDR_PLL_DIV2	BIT(24)
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_SYS_PLL		BIT(25)
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_ENET_PLL_DIV2	(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_USB_PLL		BIT(26)
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_SYS_PLL_PFD7	(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_VIDEO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* DRAM_ALT_CLK_ROOT */
+
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_DDR_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_SYS_PLL			BIT(25)
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_ENET_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_USB_PLL			BIT(26)
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_SYS_PLL_PFD0		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_SYS_PLL_PFD2		((BIT(26) | BIT(25) | BIT(24))
+
+/* USB_HSIC_CLK_ROOT */
+
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL			BIT(24)
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_USB_PLL			BIT(25)
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD3		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD4		BIT(26)
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD5		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD6		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD7		((BIT(26) | BIT(25) | BIT(24))
+
+/* LCDIF_PIXEL_CLK_ROOT */
+
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_SYS_PLL_PFD5		BIT(24)
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_EXT_CLK3		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_SYS_PLL_PFD4		BIT(26)
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_SYS_PLL_PFD2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_USB_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* MIPI_DSI_CLK_ROOT */
+
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL_PFD5		BIT(24)
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL_PFD3		BIT(25)
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL_PFD0_DIV2	BIT(26)
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_DDR_PLL_DIV2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_AUDIO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* MIPI_CSI_CLK_ROOT */
+
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL_PFD4		BIT(24)
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL_PFD3		BIT(25)
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL_PFD0_DIV2	BIT(26)
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_DDR_PLL_DIV2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_AUDIO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* MIPI_DPHY_REF_CLK_ROOT */
+
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_SYS_PLL_DIV4	BIT(24)
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_DDR_PLL_DIV2	BIT(25)
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_SYS_PLL_PFD5	(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_REF_1M		BIT(26)
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_EXT_CLK2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_EXT_CLK3		((BIT(26) | BIT(25) | BIT(24))
+
+/* SAI1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_AUDIO_PLL			BIT(25)
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_SYS_PLL_PFD4			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_ENET_PLL_DIV8		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_SAI1_CLK_ROOT_EXT_CLK2			((BIT(26) | BIT(25) | BIT(24))
+
+/* SAI2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_AUDIO_PLL			BIT(25)
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_SYS_PLL_PFD4			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_ENET_PLL_DIV8		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_SAI2_CLK_ROOT_EXT_CLK2			((BIT(26) | BIT(25) | BIT(24))
+
+/* SAI3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_AUDIO_PLL			BIT(25)
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_SYS_PLL_PFD4			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_ENET_PLL_DIV8		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_SAI3_CLK_ROOT_EXT_CLK3			((BIT(26) | BIT(25) | BIT(24))
+
+/* ENET1_REF_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_ENET_PLL_DIV8		BIT(24)
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_ENET_PLL_DIV20		BIT(25)
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_ENET_PLL_DIV40		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_SYS_PLL_DIV4		BIT(26)
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_EXT_CLK4		((BIT(26) | BIT(25) | BIT(24))
+
+/* ENET1_TIME_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_AUDIO_PLL		BIT(25)
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK1		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK2		BIT(26)
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK3		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK4		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_VIDEO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* ENET_PHY_REF_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_ENET_PLL_DIV40	BIT(24)
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_ENET_PLL_DIV20	BIT(25)
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_ENET_PLL_DIV8	(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_DDR_PLL_DIV2		BIT(26)
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_SYS_PLL_PFD3		((BIT(26) | BIT(25) | BIT(24))
+
+/* EIM_CLK_ROOT */
+
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_PFD2			BIT(26)
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_PFD3			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_ENET_PLL_DIV8			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_EIM_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* NAND_CLK_ROOT */
+
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_SYS_PLL			BIT(24)
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_DDR_PLL_DIV2			BIT(25)
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_SYS_PLL_PFD0			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_SYS_PLL_PFD3			BIT(26)
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_ENET_PLL_DIV2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_ENET_PLL_DIV4		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_NAND_CLK_ROOT_VIDEO_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* QSPI_CLK_ROOT */
+
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD4			BIT(24)
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_DDR_PLL_DIV2			BIT(25)
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_ENET_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD3			BIT(26)
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD6			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD7			((BIT(26) | BIT(25) | BIT(24))
+
+/* USDHC1_CLK_ROOT */
+
+#define CM_TRGT_MUX_USDHC1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD0		BIT(24)
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_ENET_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD4		BIT(26)
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD6		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD7		((BIT(26) | BIT(25) | BIT(24))
+
+/* USDHC2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD0		BIT(24)
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_ENET_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD4		BIT(26)
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD6		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD7		((BIT(26) | BIT(25) | BIT(24))
+
+/* USDHC3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD0		BIT(24)
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_DDR_PLL_DIV2		BIT(25)
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_ENET_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD4		BIT(26)
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD2		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD6		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD7		((BIT(26) | BIT(25) | BIT(24))
+
+/* CAN1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_SYS_PLL_DIV4			BIT(24)
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_DDR_PLL_DIV2			BIT(25)
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_SYS_PLL			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_ENET_PLL_DIV25		BIT(26)
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_USB_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_EXT_CLK1			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_CAN1_CLK_ROOT_EXT_CLK4			((BIT(26) | BIT(25) | BIT(24))
+
+/* CAN2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_SYS_PLL_DIV4			BIT(24)
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_DDR_PLL_DIV2			BIT(25)
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_SYS_PLL			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_ENET_PLL_DIV25		BIT(26)
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_USB_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_EXT_CLK1			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_CAN2_CLK_ROOT_EXT_CLK3			((BIT(26) | BIT(25) | BIT(24))
+
+/* I2C1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_SYS_PLL_DIV4			BIT(24)
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_ENET_PLL_DIV20		BIT(25)
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_VIDEO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_USB_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_I2C1_CLK_ROOT_SYS_PLL_PFD2_DIV2		((BIT(26) | BIT(25) | BIT(24))
+
+/* I2C2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_SYS_PLL_DIV4			BIT(24)
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_ENET_PLL_DIV20		BIT(25)
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_VIDEO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_USB_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_I2C2_CLK_ROOT_SYS_PLL_PFD2_DIV2		((BIT(26) | BIT(25) | BIT(24))
+
+/* I2C3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_SYS_PLL_DIV4			BIT(24)
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_ENET_PLL_DIV20		BIT(25)
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_VIDEO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_USB_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_I2C3_CLK_ROOT_SYS_PLL_PFD2_DIV2		((BIT(26) | BIT(25) | BIT(24))
+
+/* I2C4_CLK_ROOT */
+
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_SYS_PLL_DIV4			BIT(24)
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_ENET_PLL_DIV20		BIT(25)
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_VIDEO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_USB_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_I2C4_CLK_ROOT_SYS_PLL_PFD2_DIV2		((BIT(26) | BIT(25) | BIT(24))
+
+/* UART1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_EXT_CLK4			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART1_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* UART2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_EXT_CLK3			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART2_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* UART3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_EXT_CLK4			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART3_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* UART4_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_EXT_CLK3			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART4_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* UART5_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_EXT_CLK4			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART5_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* UART6_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_EXT_CLK3			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART6_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* UART7_CLK_ROOT */
+
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_ENET_PLL_DIV10		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_EXT_CLK4			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_UART7_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* ECSPI1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL_PFD4		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_ENET_PLL_DIV4		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* ECSPI2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL_PFD4		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_ENET_PLL_DIV4		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* ECSPI3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL_PFD4		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_ENET_PLL_DIV4		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* ECSPI4_CLK_ROOT */
+
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL_DIV2		BIT(24)
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_ENET_PLL_DIV25		BIT(25)
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL_DIV4		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL			BIT(26)
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL_PFD4		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_ENET_PLL_DIV4		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* PWM1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_EXT_CLK1			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_PWM1_CLK_ROOT_VIDEO_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* PWM2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_EXT_CLK1			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_PWM2_CLK_ROOT_VIDEO_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* PWM3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_PWM3_CLK_ROOT_VIDEO_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* PWM4_CLK_ROOT */
+
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_AUDIO_PLL			BIT(26)
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_PWM4_CLK_ROOT_VIDEO_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* FLEXTIMER1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_SYS_PLL_DIV4		BIT(25)
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_AUDIO_PLL		BIT(26)
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_EXT_CLK3		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_VIDEO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* FLEXTIMER2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_SYS_PLL_DIV4		BIT(25)
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_AUDIO_PLL		BIT(26)
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_EXT_CLK3		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_VIDEO_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* Target SIM1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_USB_PLL			BIT(26)
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_ENET_PLL_DIV8		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_SIM1_CLK_ROOT_SYS_PLL_PFD7			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target SIM2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_USB_PLL			BIT(26)
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_VIDEO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_ENET_PLL_DIV8		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_SIM2_CLK_ROOT_SYS_PLL_PFD7			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target GPT1_CLK_ROOT */
+
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_SYS_PLL_PFD0			BIT(25)
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_REF_1M			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_GPT1_CLK_ROOT_EXT_CLK1			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target GPT2_CLK_ROOT */
+
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_SYS_PLL_PFD0			BIT(25)
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_REF_1M			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_GPT2_CLK_ROOT_EXT_CLK2			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target GPT3_CLK_ROOT */
+
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_SYS_PLL_PFD0			BIT(25)
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_REF_1M			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_GPT3_CLK_ROOT_EXT_CLK3			((BIT(26) | BIT(25) | BIT(24))
+
+/*Target GPT4_CLK_ROOT */
+
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_ENET_PLL_DIV10		BIT(24)
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_SYS_PLL_PFD0			BIT(25)
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_ENET_PLL_DIV25		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_VIDEO_PLL			BIT(26)
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_REF_1M			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_AUDIO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_GPT4_CLK_ROOT_EXT_CLK4			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target TRACE_CLK_ROOT */
+
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_SYS_PLL_DIV4		BIT(25)
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_DDR_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_ENET_PLL_DIV8		BIT(26)
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_USB_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_EXT_CLK2			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_TRACE_CLK_ROOT_EXT_CLK3			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target WDOG_CLK_ROOT */
+
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_SYS_PLL_PFD2_DIV2		BIT(24)
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_SYS_PLL_DIV4			BIT(25)
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_DDR_PLL_DIV2			(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_ENET_PLL_DIV8		BIT(26)
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_USB_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_REF_1M			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_WDOG_CLK_ROOT_SYS_PLL_PFD1_DIV2		((BIT(26) | BIT(25) | BIT(24))
+#define WDOG_DEFAULT_CLK_SELECT					(CCM_TARGET_ROOT_ENABLE |\
+								CCM_TRGT_MUX_WDOG_CLK_ROOT_OSC_24M)
+
+/* Target CSI_MCLK_CLK_ROOT */
+
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_OSC_24M			0
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_SYS_PLL_PFD2_DIV2	BIT(24)
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_SYS_PLL_DIV4		BIT(25)
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_DDR_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_ENET_PLL_DIV8		BIT(26)
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_USB_PLL			((BIT(26) | BIT(25) | BIT(24))
+
+/* Target AUDIO_MCLK_CLK_ROOT */
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_OSC_24M		0
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_SYS_PLL_PFD2_DIV2	BIT(24)
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_SYS_PLL_DIV4		BIT(25)
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_DDR_PLL_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_ENET_PLL_DIV8		BIT(26)
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_AUDIO_PLL		(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_VIDEO_PLL		(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_USB_PLL		((BIT(26) | BIT(25) | BIT(24))
+
+/* Target CCM_CLKO1 */
+#define CCM_TRGT_MUX_CCM_CLKO1_OSC_24M				0
+#define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL				BIT(24)
+#define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL_DIV2			BIT(25)
+#define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL_PFD0_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL_PFD3			BIT(26)
+#define CCM_TRGT_MUX_CCM_CLKO1_ENET_PLL_DIV2			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_CCM_CLKO1_DDR_PLL_DIV2			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_CCM_CLKO1_REF_1M				((BIT(26) | BIT(25) | BIT(24))
+
+/* Target CCM_CLKO2 */
+#define CCM_TRGT_MUX_CCM_CLKO2_OSC_24M				0
+#define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_DIV2			BIT(24)
+#define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_PFD0			BIT(25)
+#define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_PFD1_DIV2		(BIT(25) | BIT(24))
+#define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_PFD4			BIT(26)
+#define CCM_TRGT_MUX_CCM_CLKO2_AUDIO_PLL			(BIT(26) | BIT(24))
+#define CCM_TRGT_MUX_CCM_CLKO2_VIDEO_PLL			(BIT(26) | BIT(25))
+#define CCM_TRGT_MUX_CCM_CLKO2_OSC_32K				((BIT(26) | BIT(25) | BIT(24))
+
+/*
+ * See Table 5-11 in i.MX7 Solo Reference manual rev 0.1
+ * The indices must be calculated by dividing the offset by
+ * sizeof (struct ccm_target_root_ctrl) => 0x80 bytes for each index
+ */
+enum {
+	CCM_TRT_ID_ARM_A7_CLK_ROOT = 0,
+	CCM_TRT_ID_ARM_M4_CLK_ROOT = 1,
+	CCM_TRT_ID_MAIN_AXI_CLK_ROOT = 16,
+	CCM_TRT_ID_DISP_AXI_CLK_ROOT = 17,
+	CCM_TRT_ID_ENET_AXI_CLK_ROOT = 18,
+	CCM_TRT_ID_NAND_USDHC_BUS_CLK_ROOT = 19,
+	CCM_TRT_ID_AHB_CLK_ROOT = 32,
+	CCM_TRT_ID_IPG_CLK_ROOT = 33,
+	CCM_TRT_ID_DRAM_PHYM_CLK_ROOT = 48,
+	CCM_TRT_ID_DRAM_CLK_ROOT = 49,
+	CCM_TRT_ID_DRAM_PHYM_ALT_CLK_ROOT = 64,
+	CCM_TRT_ID_DRAM_ALT_CLK_ROOT = 65,
+	CCM_TRT_ID_USB_HSIC_CLK_ROOT = 66,
+	CCM_TRT_ID_LCDIF_PIXEL_CLK_ROOT = 70,
+	CCM_TRT_ID_MIPI_DSI_CLK_ROOT = 71,
+	CCM_TRT_ID_MIPI_CSI_CLK_ROOT = 72,
+	CCM_TRT_ID_MIPI_DPHY_REF_CLK_ROOT = 73,
+	CCM_TRT_ID_SAI1_CLK_ROOT = 74,
+	CCM_TRT_ID_SAI2_CLK_ROOT = 75,
+	CCM_TRT_ID_SAI3_CLK_ROOT = 76,
+	CCM_TRT_ID_ENET1_REF_CLK_ROOT = 78,
+	CCM_TRT_ID_ENET1_TIME_CLK_ROOT = 79,
+	CCM_TRT_ID_ENET_PHY_REF_CLK_ROOT = 82,
+	CCM_TRT_ID_EIM_CLK_ROOT = 83,
+	CCM_TRT_ID_NAND_CLK_ROOT = 84,
+	CCM_TRT_ID_QSPI_CLK_ROOT = 85,
+	CCM_TRT_ID_USDHC1_CLK_ROOT = 86,
+	CCM_TRT_ID_USDHC2_CLK_ROOT = 87,
+	CCM_TRT_ID_USDHC3_CLK_ROOT = 88,
+	CCM_TRT_ID_CAN1_CLK_ROOT = 89,
+	CCM_TRT_ID_CAN2_CLK_ROOT = 90,
+	CCM_TRT_ID_I2C1_CLK_ROOT = 91,
+	CCM_TRT_ID_I2C2_CLK_ROOT = 92,
+	CCM_TRT_ID_I2C3_CLK_ROOT = 93,
+	CCM_TRT_ID_I2C4_CLK_ROOT = 94,
+	CCM_TRT_ID_UART1_CLK_ROOT = 95,
+	CCM_TRT_ID_UART2_CLK_ROOT = 96,
+	CCM_TRT_ID_UART3_CLK_ROOT = 97,
+	CCM_TRT_ID_UART4_CLK_ROOT = 98,
+	CCM_TRT_ID_UART5_CLK_ROOT = 99,
+	CCM_TRT_ID_UART6_CLK_ROOT = 100,
+	CCM_TRT_ID_UART7_CLK_ROOT = 101,
+	CCM_TRT_ID_ECSPI1_CLK_ROOT = 102,
+	CCM_TRT_ID_ECSPI2_CLK_ROOT = 103,
+	CCM_TRT_ID_ECSPI3_CLK_ROOT = 104,
+	CCM_TRT_ID_ECSPI4_CLK_ROOT = 105,
+	CCM_TRT_ID_PWM1_CLK_ROOT = 106,
+	CCM_TRT_ID_PWM2_CLK_ROOT = 107,
+	CCM_TRT_ID_PWM3_CLK_ROOT = 108,
+	CCM_TRT_ID_PWM4_CLK_ROOT = 109,
+	CCM_TRT_ID_FLEXTIMER1_CLK_ROOT = 110,
+	CCM_TRT_ID_FLEXTIMER2_CLK_ROOT = 111,
+	CCM_TRT_ID_SIM1_CLK_ROOT = 112,
+	CCM_TRT_ID_SIM2_CLK_ROOT = 113,
+	CCM_TRT_ID_GPT1_CLK_ROOT = 114,
+	CCM_TRT_ID_GPT2_CLK_ROOT = 115,
+	CCM_TRT_ID_GPT3_CLK_ROOT = 116,
+	CCM_TRT_ID_GPT4_CLK_ROOT = 117,
+	CCM_TRT_ID_TRACE_CLK_ROOT = 118,
+	CCM_TRT_ID_WDOG_CLK_ROOT = 119,
+	CCM_TRT_ID_CSI_MCLK_CLK_ROOT = 120,
+	CCM_TRT_ID_AUDIO_MCLK_CLK_ROOT = 121,
+	CCM_TRT_ID_CCM_CLKO1 = 123,
+	CCM_TRT_ID_CCM_CLKO2 = 124,
+};
+
+#define CCM_MISC_VIOLATE		BIT(8)
+#define CCM_MISC_TIMEOUT		BIT(4)
+#define CCM_MISC_AUTHEN_FAIL		BIT(0)
+
+#define CCM_POST_BUSY2			BIT(31)
+#define CCM_POST_SELECT_BRANCH_A	BIT(28)
+#define CCM_POST_BUSY1			BIT(7)
+#define CCM_POST_POST_PODF(x)		((x) - 1)
+
+#define CCM_PRE_BUSY4			BIT(31)
+#define CCM_PRE_ENABLE_A		BIT(28)
+#define CCM_PRE_MUX_A(x)		(((x) - 1) << 24)
+#define CCM_PRE_BUSY3			BIT(19)
+#define CCM_PRE_PODF_A(x)		(((x) - 1) << 16)
+#define CCM_PRE_BUSY1			BIT(15)
+#define CCM_PRE_ENABLE_B		BIT(12)
+#define CCM_PRE_MUX_B(x)		(((x) - 1) << 8)
+#define CCM_PRE_BUSY0			BIT(3)
+#define CCM_PRE_POST_PODF(x)		((x) - 1)
+
+#define CCM_ACCESS_CTRL_LOCK		BIT(31)
+#define CCM_ACCESS_SEMA_ENABLE		BIT(28)
+#define CCM_ACCESS_DOM3_WHITELIST	BIT(27)
+#define CCM_ACCESS_DOM2_WHITELIST	BIT(26)
+#define CCM_ACCESS_DOM1_WHITELIST	BIT(25)
+#define CCM_ACCESS_DOM0_WHITELIST	BIT(24)
+#define CCM_ACCESS_MUTEX		BIT(20)
+#define CCM_ACCESS_OWNER_ID(x)		((x) << 16)
+#define CCM_ACCESS_DOM3_INFO(x)		((x) << 12)
+#define CCM_ACCESS_DOM2_INFO(x)		((x) << 8)
+#define CCM_ACCESS_DOM1_INFO(x)		((x) << 4)
+#define CCM_ACCESS_DOM0_INFO(x)		(x)
+
+#define CCM_PLL_CTRL_NUM	0x21
+#define CCM_CLK_GATE_CTRL_NUM	0xbf
+#define CCM_ROOT_CTRL_NUM	0x79
+
+struct ccm {
+	uint32_t ccm_gpr0;
+	uint32_t ccm_gpr0_set;
+	uint32_t ccm_gpr0_clr;
+	uint32_t ccm_grp0_tog;
+	uint32_t reserved[0x1fc];
+	struct ccm_pll_ctrl ccm_pll_ctrl[CCM_PLL_CTRL_NUM];
+	uint32_t reserved1[0xd7c];
+	struct ccm_clk_gate_ctrl ccm_clk_gate_ctrl[CCM_CLK_GATE_CTRL_NUM];
+	uint32_t reserved2[0xd04];
+	struct ccm_target_root_ctrl ccm_root_ctrl[CCM_ROOT_CTRL_NUM];
+};
+
+void imx_clock_target_set(unsigned int id, uint32_t val);
+void imx_clock_target_clr(unsigned int id, uint32_t val);
+void imx_clock_gate_enable(unsigned int id, bool enable);
+
+void imx_clock_init(void);
+
+void imx_clock_enable_uart(unsigned int uart_id, uint32_t uart_clk_en_bits);
+void imx_clock_disable_uart(unsigned int uart_id);
+void imx_clock_enable_usdhc(unsigned int usdhc_id, uint32_t usdhc_clk_en_bits);
+void imx_clock_set_wdog_clk_root_bits(uint32_t wdog_clk_root_en_bits);
+void imx_clock_enable_wdog(unsigned int wdog_id);
+void imx_clock_disable_wdog(unsigned int wdog_id);
+void imx_clock_enable_usb(unsigned int usb_id);
+void imx_clock_disable_usb(unsigned int usb_id);
+void imx_clock_set_usb_clk_root_bits(uint32_t usb_clk_root_en_bits);
+
+#endif /* IMX_CLOCK_H */
diff --git a/plat/imx/common/include/imx_csu.h b/plat/imx/common/include/imx_csu.h
new file mode 100644
index 0000000..879d10b
--- /dev/null
+++ b/plat/imx/common/include/imx_csu.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_CSU_H
+#define IMX_CSU_H
+
+#include <arch.h>
+
+/*
+ * Security Reference Manual for i.MX 7Dual and 7Solo Applications Processors,
+ * Rev. 0, 03/2017 Section 3.3.1
+ *
+ * Config secure level register (CSU_CSLn)
+ */
+#define CSU_CSL_LOCK_S1		BIT(24)
+#define CSU_CSL_NSW_S1		BIT(23)
+#define CSU_CSL_NUW_S1		BIT(22)
+#define CSU_CSL_SSW_S1		BIT(21)
+#define CSU_CSL_SUW_S1		BIT(20)
+#define CSU_CSL_NSR_S1		BIT(19)
+#define CSU_CSL_NUR_S1		BIT(18)
+#define CSU_CSL_SSR_S1		BIT(17)
+#define CSU_CSL_SUR_S1		BIT(16)
+#define CSU_CSL_LOCK_S2		BIT(8)
+#define CSU_CSL_NSW_S2		BIT(7)
+#define CSU_CSL_NUW_S2		BIT(6)
+#define CSU_CSL_SSW_S2		BIT(5)
+#define CSU_CSL_SUW_S2		BIT(4)
+#define CSU_CSL_NSR_S2		BIT(3)
+#define CSU_CSL_NUR_S2		BIT(2)
+#define CSU_CSL_SSR_S2		BIT(1)
+#define CSU_CSL_SUR_S2		BIT(0)
+
+#define CSU_CSL_OPEN_ACCESS  (CSU_CSL_NSW_S1 | CSU_CSL_NUW_S1 | CSU_CSL_SSW_S1 |\
+			      CSU_CSL_SUW_S1 | CSU_CSL_NSR_S1 | CSU_CSL_NUR_S1 |\
+			      CSU_CSL_SSR_S1 | CSU_CSL_SUR_S1 | CSU_CSL_NSW_S2 |\
+			      CSU_CSL_NUW_S2 | CSU_CSL_SSW_S2 | CSU_CSL_SUW_S2 |\
+			      CSU_CSL_NSR_S2 | CSU_CSL_NUR_S2 | CSU_CSL_SSR_S2 |\
+			      CSU_CSL_SUR_S2)
+void imx_csu_init(void);
+
+#endif /* IMX_CSU_H */
diff --git a/plat/imx/common/include/imx_hab.h b/plat/imx/common/include/imx_hab.h
new file mode 100644
index 0000000..22c0742
--- /dev/null
+++ b/plat/imx/common/include/imx_hab.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_HAB_H
+#define IMX_HAB_H
+
+#include <imx_hab_arch.h>
+#include <imx_regs.h>
+
+#define HAB_ROM_VECTOR_BASE\
+	(BOOTROM_BASE + HAB_CALLBACK_OFFSET)
+/*
+ * Section 4.5 of the High Assurance Boot Version 4 Application Programming
+ * Interface Reference Manual defines the ROM Vector table as coming after a 4
+ * byte header
+ *
+ * A series of function pointers are enumerated at fixed addresses, which are
+ * described below
+ */
+#define HAB_ROM_VECTOR_TABLE_ENTRY		(HAB_ROM_VECTOR_BASE + 0x04)
+#define HAB_ROM_VECTOR_TABLE_EXIT		(HAB_ROM_VECTOR_BASE + 0x08)
+#define HAB_ROM_VECTOR_TABLE_CHECK_TARGET	(HAB_ROM_VECTOR_BASE + 0x0C)
+#define HAB_ROM_VECTOR_TABLE_AUTHENTICATE_IMAGE	(HAB_ROM_VECTOR_BASE + 0x10)
+#define HAB_ROM_VECTOR_TABLE_RUN_DCD		(HAB_ROM_VECTOR_BASE + 0x14)
+#define HAB_ROM_VECTOR_TABLE_RUN_CSF		(HAB_ROM_VECTOR_BASE + 0x18)
+#define HAB_ROM_VECTOR_TABLE_ASSERT		(HAB_ROM_VECTOR_BASE + 0x1C)
+#define HAB_ROM_VECTOR_TABLE_REPORT_EVENT	(HAB_ROM_VECTOR_BASE + 0x20)
+#define HAB_ROM_VECTOR_TABLE_REPORT_STATUS	(HAB_ROM_VECTOR_BASE + 0x24)
+#define HAB_ROM_VECTOR_TABLE_FAILSAFE		(HAB_ROM_VECTOR_BASE + 0x28)
+
+#endif /* IMX_HAB_H */
diff --git a/plat/imx/common/include/imx_io_mux.h b/plat/imx/common/include/imx_io_mux.h
new file mode 100644
index 0000000..d588cfd
--- /dev/null
+++ b/plat/imx/common/include/imx_io_mux.h
@@ -0,0 +1,652 @@
+/*
+ * Copyright 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_IO_MUX_H
+#define IMX_IO_MUX_H
+
+#include <stdint.h>
+#include <lib/utils_def.h>
+
+/*
+ * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016
+ * Section 8.2.7 IOMUXC Memory Map/Register Definition
+ */
+
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO08_OFFSET		0x0014
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09_OFFSET		0x0018
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO10_OFFSET		0x001C
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO11_OFFSET		0x0020
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO12_OFFSET		0x0024
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO13_OFFSET		0x0028
+
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_OFFSET		0x002C
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_ALT1_SD3_CD_B	BIT(0)
+
+#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO15_OFFSET		0x0030
+
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA00_OFFSET	0x0034
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA01_OFFSET	0x0038
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA02_OFFSET	0x003C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA03_OFFSET	0x0040
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA04_OFFSET	0x0044
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA05_OFFSET	0x0048
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA06_OFFSET	0x004C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA07_OFFSET	0x0050
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA08_OFFSET	0x0054
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA09_OFFSET	0x0058
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA10_OFFSET	0x005C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA11_OFFSET	0x0060
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA12_OFFSET	0x0064
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA13_OFFSET	0x0068
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA14_OFFSET	0x006C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA15_OFFSET	0x0070
+
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCLK_OFFSET		0x0074
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDLE_OFFSET		0x0078
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDOE_OFFSET		0x007C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDSHR_OFFSET		0x0080
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE0_OFFSET		0x0084
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE1_OFFSET		0x0088
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE2_OFFSET		0x008C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE3_OFFSET		0x0090
+
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDCLK_OFFSET		0x0094
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDOE_OFFSET		0x0098
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDRL_OFFSET		0x009C
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDSP_OFFSET		0x00A0
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_BDR0_OFFSET		0x00A4
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_BDR1_OFFSET		0x00A8
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_PWR_COM_OFFSET	0x00AC
+#define IOMUXC_SW_MUX_CTL_PAD_EPDC_PWR_STAT_OFFSET	0x00B0
+
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_CLK_OFFSET		0x00B4
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_ENABLE_OFFSET		0x00B8
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_HSYNC_OFFSET		0x00BC
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_VSYNC_OFFSET		0x00C0
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_RESET_OFFSET		0x00C4
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA00_OFFSET		0x00C8
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA01_OFFSET		0x00CC
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA02_OFFSET		0x00D0
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA03_OFFSET		0x00D4
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA04_OFFSET		0x00D8
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA05_OFFSET		0x00DC
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA06_OFFSET		0x00E0
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA07_OFFSET		0x00E4
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA08_OFFSET		0x00E8
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA09_OFFSET		0x00EC
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA10_OFFSET		0x00F0
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA11_OFFSET		0x00F4
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA12_OFFSET		0x00F8
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA13_OFFSET		0x00FC
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA14_OFFSET		0x0100
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA15_OFFSET		0x0104
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA16_OFFSET		0x0108
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA17_OFFSET		0x010C
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA18_OFFSET		0x0110
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA19_OFFSET		0x0114
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA20_OFFSET		0x0118
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA21_OFFSET		0x011C
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA22_OFFSET		0x0120
+#define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA23_OFFSET		0x0124
+
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_OFFSET	0x0128
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT0_UART1_RX_DATA	0x00
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT1_I2C1_SCL	BIT(0)
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT2_PMIC_READY	BIT(1)
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT3_ECSPI1_SS1	(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT4_ENET2_1588_EVENT0_IN BIT(3)
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT5_GPIO4_IO0	(BIT(2) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT6_ENET1_MDIO	(BIT(2) | BIT(1))
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_SION		BIT(3)
+
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_OFFSET	0x012C
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT0_UART1_TX_DATA	0x00
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT1_I2C1_SDA	BIT(0)
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT2_SAI3_MCLK	BIT(1)
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT3_ECSPI1_SS2	(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT4_ENET2_1588_EVENT0_OUT BIT(3)
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT5_GPIO4_IO1	(BIT(2) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT6_ENET1_MDC	(BIT(2) | BIT(1))
+#define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_SION		BIT(3)
+
+#define IOMUXC_SW_MUX_CTL_PAD_UART2_RX_DATA_OFFSET	0x0130
+#define IOMUXC_SW_MUX_CTL_PAD_UART2_TX_DATA_OFFSET	0x0134
+#define IOMUXC_SW_MUX_CTL_PAD_UART3_RX_DATA_OFFSET	0x0138
+#define IOMUXC_SW_MUX_CTL_PAD_UART3_TX_DATA_OFFSET	0x013C
+#define IOMUXC_SW_MUX_CTL_PAD_UART3_RTS_B_OFFSET	0x0140
+#define IOMUXC_SW_MUX_CTL_PAD_UART3_CTS_B_OFFSET	0x0144
+
+#define IOMUXC_SW_MUX_CTL_PAD_I2C1_SCL_OFFSET		0x0148
+#define IOMUXC_SW_MUX_CTL_PAD_I2C1_SDA_OFFSET		0x014C
+#define IOMUXC_SW_MUX_CTL_PAD_I2C2_SCL_OFFSET		0x0150
+#define IOMUXC_SW_MUX_CTL_PAD_I2C2_SDA_OFFSET		0x0154
+#define IOMUXC_SW_MUX_CTL_PAD_I2C3_SCL_OFFSET		0x0158
+#define IOMUXC_SW_MUX_CTL_PAD_I2C3_SDA_OFFSET		0x015C
+
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_OFFSET		0x0160
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT0_I2C4_SCL		0x0
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT1_UART5_RX_DATA	BIT(0)
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT2_WDOG4_WDOG_B	BIT(1)
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT3_CSI_PIXCLK		(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT4_USB_OTG1_ID		BIT(2)
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT5_GPIO4_IO14		(BIT(2) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT6_EPDC_VCOM0		(BIT(2) | BIT(1))
+
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_OFFSET		0x0164
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT0_I2C4_SDA		0x0
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT1_UART5_TX_DATA	BIT(0)
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT2_WDOG4_WDOG_RST_B_DEB BIT(1)
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT3_CSI_MCLK		(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT4_USB_OTG2_ID		BIT(2)
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT5_GPIO4_IO15		(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT6_EPDC_VCOM1		(BIT(2) | BIT(1))
+
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_OFFSET	0x0168
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT0_ECSPI1_SCLK	0x00
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT1_UART6_RX_DATA	BIT(0)
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT2_SD2_DATA4	BIT(1)
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT3_CSI_DATA2	(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT5_GPIO4_IO16	(BIT(2) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT6_EPDC_PWR_COM	(BIT(2) | (BIT(1))
+
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_OFFSET	0x016C
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT0_ECSPI1_MOSI	0x00
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT1_UART6_TX_DATA	BIT(0)
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT2_SD2_DATA5	BIT(1)
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT3_CSI_DATA3	(BIT(1) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT5_GPIO4_IO17	(BIT(2) | BIT(0))
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT6_EPDC_PWR_STAT	(BIT(2) | (BIT(1))
+
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MISO_OFFSET	0x0170
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SS0_OFFSET		0x0174
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_SCLK_OFFSET	0x0178
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_MOSI_OFFSET	0x017C
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_MISO_OFFSET	0x0180
+#define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_SS0_OFFSET		0x0184
+
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_CD_B_OFFSET		0x0188
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_WP_OFFSET		0x018C
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_RESET_B_OFFSET	0x0190
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_CLK_OFFSET		0x0194
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_CMD_OFFSET		0x0198
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA0_OFFSET		0x019C
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA1_OFFSET		0x01A0
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2_OFFSET		0x01A4
+#define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA3_OFFSET		0x01A8
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_CD_B_OFFSET		0x01AC
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_WP_OFFSET		0x01B0
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_RESET_B_OFFSET	0x01B4
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_CLK_OFFSET		0x01B8
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_CMD_OFFSET		0x01BC
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA0_OFFSET		0x01C0
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA1_OFFSET		0x01C4
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA2_OFFSET		0x01C8
+#define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA3_OFFSET		0x01CC
+
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_CLK_OFFSET		0x01D0
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_CMD_OFFSET		0x01D4
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA0_OFFSET		0x01D8
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA1_OFFSET		0x01DC
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA2_OFFSET		0x01E0
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA3_OFFSET		0x01E4
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA4_OFFSET		0x01E8
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA5_OFFSET		0x01EC
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA6_OFFSET		0x01F0
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA7_OFFSET		0x01F4
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_STROBE_OFFSET		0x01F8
+#define IOMUXC_SW_MUX_CTL_PAD_SD3_RESET_B_OFFSET	0x01FC
+
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_RX_DATA_OFFSET	0x0200
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_TX_BCLK_OFFSET	0x0204
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_TX_SYNC_OFFSET	0x0208
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_TX_DATA_OFFSET	0x020C
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_RX_SYNC_OFFSET	0x0210
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_RX_BCLK_OFFSET	0x0214
+#define IOMUXC_SW_MUX_CTL_PAD_SAI1_MCLK_OFFSET		0x0218
+#define IOMUXC_SW_MUX_CTL_PAD_SAI2_TX_SYNC_OFFSET	0x021C
+#define IOMUXC_SW_MUX_CTL_PAD_SAI2_TX_BCLK_OFFSET	0x0220
+#define IOMUXC_SW_MUX_CTL_PAD_SAI2_RX_DATA_OFFSET	0x0224
+#define IOMUXC_SW_MUX_CTL_PAD_SAI2_TX_DATA_OFFSET	0x0228
+
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD0_OFFSET	0x022C
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD1_OFFSET	0x0230
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD2_OFFSET	0x0234
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD3_OFFSET	0x0238
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RX_CTL_OFFSET	0x023C
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RXC_OFFSET	0x0240
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD0_OFFSET	0x0244
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD1_OFFSET	0x0248
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD2_OFFSET	0x024C
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD3_OFFSET	0x0250
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TX_CTL_OFFSET	0x0254
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TXC_OFFSET	0x0258
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_CLK_OFFSET	0x025C
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_CLK_OFFSET	0x0260
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_CRS_OFFSET		0x0264
+#define IOMUXC_SW_MUX_CTL_PAD_ENET1_COL_OFFSET		0x0268
+
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO08_OFFSET		0x026C
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO09_OFFSET		0x0270
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO10_OFFSET		0x0274
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO11_OFFSET		0x0278
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO12_OFFSET		0x027C
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO13_OFFSET		0x0280
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO14_OFFSET		0x0284
+#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO15_OFFSET		0x0288
+
+#define IOMUXC_SW_PAD_CTL_PAD_JTAG_MOD_OFFSET		0x028C
+#define IOMUXC_SW_PAD_CTL_PAD_JTAG_TCK_OFFSET		0x0290
+#define IOMUXC_SW_PAD_CTL_PAD_JTAG_TDI_OFFSET		0x0294
+#define IOMUXC_SW_PAD_CTL_PAD_JTAG_TDO_OFFSET		0x0298
+#define IOMUXC_SW_PAD_CTL_PAD_JTAG_TMS_OFFSET		0x029C
+#define IOMUXC_SW_PAD_CTL_PAD_JTAG_TRST_B_OFFSET	0x02A0
+
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA00_OFFSET	0x02A4
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA01_OFFSET	0x02A8
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA02_OFFSET	0x02AC
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA03_OFFSET	0x02B0
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA04_OFFSET	0x02B4
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA05_OFFSET	0x02B8
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA06_OFFSET	0x02BC
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA07_OFFSET	0x02C0
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA08_OFFSET	0x02C4
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA09_OFFSET	0x02C8
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA10_OFFSET	0x02CC
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA11_OFFSET	0x02D0
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA12_OFFSET	0x02D4
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA13_OFFSET	0x02D8
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA14_OFFSET	0x02DC
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA15_OFFSET	0x02E0
+
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCLK_OFFSET		0x02E4
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDLE_OFFSET		0x02E8
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDOE_OFFSET		0x02EC
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDSHR_OFFSET		0x02F0
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE0_OFFSET		0x02F4
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE1_OFFSET		0x02F8
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE2_OFFSET		0x02FC
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE3_OFFSET		0x0300
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDCLK_OFFSET		0x0304
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDOE_OFFSET		0x0308
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDRL_OFFSET		0x030C
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDSP_OFFSET		0x0310
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_BDR0_OFFSET		0x0314
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_BDR1_OFFSET		0x0318
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_PWR_COM_OFFSET	0x031C
+#define IOMUXC_SW_PAD_CTL_PAD_EPDC_PWR_STAT_OFFSET	0x0320
+
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_CLK_OFFSET		0x0324
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_ENABLE_OFFSET		0x0328
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_HSYNC_OFFSET		0x032C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_VSYNC_OFFSET		0x0330
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_RESET_OFFSET		0x0334
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA00_OFFSET		0x0338
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA01_OFFSET		0x033C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA02_OFFSET		0x0340
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA03_OFFSET		0x0344
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA04_OFFSET		0x0348
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA05_OFFSET		0x034C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA06_OFFSET		0x0350
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA07_OFFSET		0x0354
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA08_OFFSET		0x0358
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA09_OFFSET		0x035C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA10_OFFSET		0x0360
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA11_OFFSET		0x0364
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA12_OFFSET		0x0368
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA13_OFFSET		0x036C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA14_OFFSET		0x0370
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA15_OFFSET		0x0374
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA16_OFFSET		0x0378
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA17_OFFSET		0x037C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA18_OFFSET		0x0380
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA19_OFFSET		0x0384
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA20_OFFSET		0x0388
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA21_OFFSET		0x038C
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA22_OFFSET		0x0390
+#define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA23_OFFSET		0x0394
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_OFFSET	0x0398
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_0_X1		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_1_X4		BIT(0)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_2_X2		BIT(1)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_3_X6		(BIT(1) | BIT(0))
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_SRE_FAST		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_SRE_SLOW		BIT(2)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_HYS_DIS		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_HYS_EN		BIT(3)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PE_DIS		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PE_EN		BIT(4)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_0_100K_PD	0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_1_5K_PU		BIT(5)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_2_47K_PU		BIT(6)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_3_100K_PU	(BIT(6) | BIT(5))
+
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_OFFSET	0x039C
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_0_X1		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_1_X4		BIT(0)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_2_X2		BIT(1)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_3_X6		(BIT(1) | BIT(0))
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_SRE_FAST		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_SRE_SLOW		BIT(2)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_HYS_DIS		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_HYS_EN		BIT(3)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PE_DIS		0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PE_EN		BIT(4)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_0_100K_PD	0
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_1_5K_PU		BIT(5)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_2_47K_PU		BIT(6)
+#define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_3_100K_PU	(BIT(6) | BIT(5))
+
+#define IOMUXC_SW_PAD_CTL_PAD_UART2_RX_DATA_OFFSET	0x03A0
+#define IOMUXC_SW_PAD_CTL_PAD_UART2_TX_DATA_OFFSET	0x03A4
+#define IOMUXC_SW_PAD_CTL_PAD_UART3_RX_DATA_OFFSET	0x03A8
+#define IOMUXC_SW_PAD_CTL_PAD_UART3_TX_DATA_OFFSET	0x03AC
+#define IOMUXC_SW_PAD_CTL_PAD_UART3_RTS_B_OFFSET	0x03B0
+#define IOMUXC_SW_PAD_CTL_PAD_UART3_CTS_B_OFFSET	0x03B4
+
+#define IOMUXC_SW_PAD_CTL_PAD_I2C1_SCL_OFFSET		0x03B8
+#define IOMUXC_SW_PAD_CTL_PAD_I2C1_SDA_OFFSET		0x03BC
+#define IOMUXC_SW_PAD_CTL_PAD_I2C2_SCL_OFFSET		0x03C0
+#define IOMUXC_SW_PAD_CTL_PAD_I2C2_SDA_OFFSET		0x03C4
+#define IOMUXC_SW_PAD_CTL_PAD_I2C3_SCL_OFFSET		0x03C8
+#define IOMUXC_SW_PAD_CTL_PAD_I2C3_SDA_OFFSET		0x03CC
+#define IOMUXC_SW_PAD_CTL_PAD_I2C4_SCL_OFFSET		0x03D0
+#define IOMUXC_SW_PAD_CTL_PAD_I2C4_SDA_OFFSET		0x03D4
+
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_OFFSET	0x03D8
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_0_X1	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_1_X4	BIT(0)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_2_X2	BIT(1)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_3_X6	(BIT(1) | BIT(0))
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_SRE_FAST	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_SRE_SLOW	BIT(2)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_HYS_DIS	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_HYS_EN	BIT(3)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PE_DIS	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PE_EN		BIT(4)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_0_100K_PD	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_1_5K_PU	BIT(5)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_2_47K_PU	BIT(6)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_3_100K_PU	(BIT(6) | BIT(5))
+
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_OFFSET	0x03DC
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_0_X1	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_1_X4	BIT(0)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_2_X2	BIT(1)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_3_X6	(BIT(1) | BIT(0))
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_SRE_FAST	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_SRE_SLOW	BIT(2)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_HYS_DIS	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_HYS_EN	BIT(3)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PE_DIS	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PE_EN		BIT(4)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_0_100K_PD	0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_1_5K_PU	BIT(5)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_2_47K_PU	BIT(6)
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_3_100K_PU	(BIT(6) | BIT(5))
+
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MISO_OFFSET	0x03E0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SS0_OFFSET		0x03E4
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_SCLK_OFFSET	0x03E8
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_MOSI_OFFSET	0x03EC
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_MISO_OFFSET	0x03F0
+#define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_SS0_OFFSET		0x03F4
+
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_CD_B_OFFSET		0x03F8
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_WP_OFFSET		0x03FC
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_RESET_B_OFFSET	0x0400
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_CLK_OFFSET		0x0404
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_CMD_OFFSET		0x0408
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA0_OFFSET		0x040C
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA1_OFFSET		0x0410
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2_OFFSET		0x0414
+#define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA3_OFFSET		0x0418
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_CD_B_OFFSET		0x041C
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_WP_OFFSET		0x0420
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_RESET_B_OFFSET	0x0424
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_CLK_OFFSET		0x0428
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_CMD_OFFSET		0x042C
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA0_OFFSET		0x0430
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA1_OFFSET		0x0434
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA2_OFFSET		0x0438
+#define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA3_OFFSET		0x043C
+
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_CLK_OFFSET		0x0440
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_CMD_OFFSET		0x0444
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA0_OFFSET		0x0448
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA1_OFFSET		0x044C
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA2_OFFSET		0x0450
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA3_OFFSET		0x0454
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA4_OFFSET		0x0458
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA5_OFFSET		0x045C
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA6_OFFSET		0x0460
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA7_OFFSET		0x0464
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_STROBE_OFFSET		0x0468
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_RESET_B_OFFSET	0x046C
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_0_X1		0
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_1_X4		BIT(0)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_2_X2		BIT(1)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_3_X6		(BIT(1) | BIT(0))
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_1_X4		BIT(0)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_SLEW_SLOW		BIT(2)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_SLEW_FAST		0
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_HYS			BIT(3)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_PE			BIT(4)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_PD_100K		(0 << 5)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_PU_5K			(1 << 5)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_PU_47K		(2 << 5)
+#define IOMUXC_SW_PAD_CTL_PAD_SD3_PU_100K		(3 << 5)
+
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_RX_DATA_OFFSET	0x0470
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_TX_BCLK_OFFSET	0x0474
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_TX_SYNC_OFFSET	0x0478
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_TX_DATA_OFFSET	0x047C
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_RX_SYNC_OFFSET	0x0480
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_RX_BCLK_OFFSET	0x0484
+#define IOMUXC_SW_PAD_CTL_PAD_SAI1_MCLK_OFFSET		0x0488
+#define IOMUXC_SW_PAD_CTL_PAD_SAI2_TX_SYNC_OFFSET	0x048C
+#define IOMUXC_SW_PAD_CTL_PAD_SAI2_TX_BCLK_OFFSET	0x0490
+#define IOMUXC_SW_PAD_CTL_PAD_SAI2_RX_DATA_OFFSET	0x0494
+#define IOMUXC_SW_PAD_CTL_PAD_SAI2_TX_DATA_OFFSET	0x0498
+
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD0_OFFSET	0x049C
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD1_OFFSET	0x04A0
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD2_OFFSET	0x04A4
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD3_OFFSET	0x04A8
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RX_CTL_OFFSET	0x04AC
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RXC_OFFSET	0x04B0
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD0_OFFSET	0x04B4
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD1_OFFSET	0x04B8
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD2_OFFSET	0x04BC
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD3_OFFSET	0x04C0
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TX_CTL_OFFSET	0x04C4
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TXC_OFFSET	0x04C8
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_CLK_OFFSET	0x04CC
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_CLK_OFFSET	0x04D0
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_CRS_OFFSET		0x04D4
+#define IOMUXC_SW_PAD_CTL_PAD_ENET1_COL_OFFSET		0x04D8
+
+#define IOMUXC_FLEXCAN1_RX_SELECT_INPUT_OFFSET		0x04DC
+#define IOMUXC_FLEXCAN2_RX_SELECT_INPUT_OFFSET		0x04E0
+
+#define IOMUXC_CCM_EXT_CLK_1_SELECT_INPUT_OFFSET	0x04E4
+#define IOMUXC_CCM_EXT_CLK_2_SELECT_INPUT_OFFSET	0x04E8
+#define IOMUXC_CCM_EXT_CLK_3_SELECT_INPUT_OFFSET	0x04EC
+#define IOMUXC_CCM_EXT_CLK_4_SELECT_INPUT_OFFSET	0x04F0
+
+#define IOMUXC_CCM_PMIC_READY_SELECT_INPUT_OFFSET	0x04F4
+
+#define IOMUXC_CSI_DATA2_SELECT_INPUT_OFFSET		0x04F8
+#define IOMUXC_CSI_DATA3_SELECT_INPUT_OFFSET		0x04FC
+#define IOMUXC_CSI_DATA4_SELECT_INPUT_OFFSET		0x0500
+#define IOMUXC_CSI_DATA5_SELECT_INPUT_OFFSET		0x0504
+#define IOMUXC_CSI_DATA6_SELECT_INPUT_OFFSET		0x0508
+#define IOMUXC_CSI_DATA7_SELECT_INPUT_OFFSET		0x050C
+#define IOMUXC_CSI_DATA8_SELECT_INPUT_OFFSET		0x0510
+#define IOMUXC_CSI_DATA9_SELECT_INPUT_OFFSET		0x0514
+#define IOMUXC_CSI_HSYNC_SELECT_INPUT_OFFSET		0x0518
+#define IOMUXC_CSI_PIXCLK_SELECT_INPUT_OFFSET		0x051C
+#define IOMUXC_CSI_VSYNC_SELECT_INPUT_OFFSET		0x0520
+
+#define IOMUXC_ECSPI1_SCLK_SELECT_INPUT_OFFSET		0x0524
+#define IOMUXC_ECSPI1_MISO_SELECT_INPUT_OFFSET		0x0528
+#define IOMUXC_ECSPI1_MOSI_SELECT_INPUT_OFFSET		0x052C
+#define IOMUXC_ECSPI1_SS0_B_SELECT_INPUT_OFFSET		0x0530
+#define IOMUXC_ECSPI2_SCLK_SELECT_INPUT_OFFSET		0x0534
+#define IOMUXC_ECSPI2_MISO_SELECT_INPUT_OFFSET		0x0538
+#define IOMUXC_ECSPI2_MOSI_SELECT_INPUT_OFFSET		0x053C
+#define IOMUXC_ECSPI2_SS0_B_SELECT_INPUT_OFFSET		0x0540
+#define IOMUXC_ECSPI3_SCLK_SELECT_INPUT_OFFSET		0x0544
+#define IOMUXC_ECSPI3_MISO_SELECT_INPUT_OFFSET		0x0548
+#define IOMUXC_ECSPI3_MOSI_SELECT_INPUT_OFFSET		0x054C
+#define IOMUXC_ECSPI3_SS0_B_SELECT_INPUT_OFFSET		0x0550
+#define IOMUXC_ECSPI4_SCLK_SELECT_INPUT_OFFSET		0x0554
+#define IOMUXC_ECSPI4_MISO_SELECT_INPUT_OFFSET		0x0558
+#define IOMUXC_ECSPI4_MOSI_SELECT_INPUT_OFFSET		0x055C
+#define IOMUXC_ECSPI4_SS0_B_SELECT_INPUT_OFFSET		0x0560
+
+#define IOMUXC_CCM_ENET1_REF_CLK_SELECT_INPUT_OFFSET	0x0564
+#define IOMUXC_ENET1_MDIO_SELECT_INPUT_OFFSET		0x0568
+#define IOMUXC_ENET1_RX_CLK_SELECT_INPUT_OFFSET		0x056C
+#define IOMUXC_CCM_ENET2_REF_CLK_SELECT_INPUT_OFFSET	0x0570
+#define IOMUXC_ENET2_MDIO_SELECT_INPUT_OFFSET		0x0574
+#define IOMUXC_ENET2_RX_CLK_SELECT_INPUT_OFFSET		0x0578
+
+#define IOMUXC_EPDC_PWR_IRQ_SELECT_INPUT_OFFSET		0x057C
+#define IOMUXC_EPDC_PWR_STAT_SELECT_INPUT_OFFSET	0x0580
+
+#define IOMUXC_FLEXTIMER1_CH0_SELECT_INPUT_OFFSET	0x0584
+#define IOMUXC_FLEXTIMER1_CH1_SELECT_INPUT_OFFSET	0x0588
+#define IOMUXC_FLEXTIMER1_CH2_SELECT_INPUT_OFFSET	0x058C
+#define IOMUXC_FLEXTIMER1_CH3_SELECT_INPUT_OFFSET	0x0590
+#define IOMUXC_FLEXTIMER1_CH4_SELECT_INPUT_OFFSET	0x0594
+#define IOMUXC_FLEXTIMER1_CH5_SELECT_INPUT_OFFSET	0x0598
+#define IOMUXC_FLEXTIMER1_CH6_SELECT_INPUT_OFFSET	0x059C
+#define IOMUXC_FLEXTIMER1_CH7_SELECT_INPUT_OFFSET	0x05A0
+#define IOMUXC_FLEXTIMER1_PHA_SELECT_INPUT_OFFSET	0x05A4
+#define IOMUXC_FLEXTIMER1_PHB_SELECT_INPUT_OFFSET	0x05A8
+#define IOMUXC_FLEXTIMER2_CH0_SELECT_INPUT_OFFSET	0x05AC
+#define IOMUXC_FLEXTIMER2_CH1_SELECT_INPUT_OFFSET	0x05B0
+#define IOMUXC_FLEXTIMER2_CH2_SELECT_INPUT_OFFSET	0x05B4
+#define IOMUXC_FLEXTIMER2_CH3_SELECT_INPUT_OFFSET	0x05B8
+#define IOMUXC_FLEXTIMER2_CH4_SELECT_INPUT_OFFSET	0x05BC
+#define IOMUXC_FLEXTIMER2_CH5_SELECT_INPUT_OFFSET	0x05C0
+#define IOMUXC_FLEXTIMER2_CH6_SELECT_INPUT_OFFSET	0x05C4
+#define IOMUXC_FLEXTIMER2_CH7_SELECT_INPUT_OFFSET	0x05C8
+#define IOMUXC_FLEXTIMER2_PHA_SELECT_INPUT_OFFSET	0x05CC
+#define IOMUXC_FLEXTIMER2_PHB_SELECT_INPUT_OFFSET	0x05D0
+
+#define IOMUXC_I2C1_SCL_SELECT_INPUT_OFFSET		0x05D4
+#define IOMUXC_I2C1_SDA_SELECT_INPUT_OFFSET		0x05D8
+#define IOMUXC_I2C2_SCL_SELECT_INPUT_OFFSET		0x05DC
+#define IOMUXC_I2C2_SDA_SELECT_INPUT_OFFSET		0x05E0
+#define IOMUXC_I2C3_SCL_SELECT_INPUT_OFFSET		0x05E4
+#define IOMUXC_I2C3_SDA_SELECT_INPUT_OFFSET		0x05E8
+#define IOMUXC_I2C4_SCL_SELECT_INPUT_OFFSET		0x05EC
+#define IOMUXC_I2C4_SDA_SELECT_INPUT_OFFSET		0x05F0
+
+#define IOMUXC_KPP_COL0_SELECT_INPUT_OFFSET		0x05F4
+#define IOMUXC_KPP_COL1_SELECT_INPUT_OFFSET		0x05F8
+#define IOMUXC_KPP_COL2_SELECT_INPUT_OFFSET		0x05FC
+#define IOMUXC_KPP_COL3_SELECT_INPUT_OFFSET		0x0600
+#define IOMUXC_KPP_COL4_SELECT_INPUT_OFFSET		0x0604
+#define IOMUXC_KPP_COL5_SELECT_INPUT_OFFSET		0x0608
+#define IOMUXC_KPP_COL6_SELECT_INPUT_OFFSET		0x060C
+#define IOMUXC_KPP_COL7_SELECT_INPUT_OFFSET		0x0610
+#define IOMUXC_KPP_ROW0_SELECT_INPUT_OFFSET		0x0614
+#define IOMUXC_KPP_ROW1_SELECT_INPUT_OFFSET		0x0618
+#define IOMUXC_KPP_ROW2_SELECT_INPUT_OFFSET		0x061C
+#define IOMUXC_KPP_ROW3_SELECT_INPUT_OFFSET		0x0620
+#define IOMUXC_KPP_ROW4_SELECT_INPUT_OFFSET		0x0624
+#define IOMUXC_KPP_ROW5_SELECT_INPUT_OFFSET		0x0628
+#define IOMUXC_KPP_ROW6_SELECT_INPUT_OFFSET		0x062C
+#define IOMUXC_KPP_ROW7_SELECT_INPUT_OFFSET		0x0630
+
+#define IOMUXC_LCD_BUSY_SELECT_INPUT_OFFSET		0x0634
+#define IOMUXC_LCD_DATA00_SELECT_INPUT_OFFSET		0x0638
+#define IOMUXC_LCD_DATA01_SELECT_INPUT_OFFSET		0x063C
+#define IOMUXC_LCD_DATA02_SELECT_INPUT_OFFSET		0x0640
+#define IOMUXC_LCD_DATA03_SELECT_INPUT_OFFSET		0x0644
+#define IOMUXC_LCD_DATA04_SELECT_INPUT_OFFSET		0x0648
+#define IOMUXC_LCD_DATA05_SELECT_INPUT_OFFSET		0x064C
+#define IOMUXC_LCD_DATA06_SELECT_INPUT_OFFSET		0x0650
+#define IOMUXC_LCD_DATA07_SELECT_INPUT_OFFSET		0x0654
+#define IOMUXC_LCD_DATA08_SELECT_INPUT_OFFSET		0x0658
+#define IOMUXC_LCD_DATA09_SELECT_INPUT_OFFSET		0x065C
+#define IOMUXC_LCD_DATA10_SELECT_INPUT_OFFSET		0x0660
+#define IOMUXC_LCD_DATA11_SELECT_INPUT_OFFSET		0x0664
+#define IOMUXC_LCD_DATA12_SELECT_INPUT_OFFSET		0x0668
+#define IOMUXC_LCD_DATA13_SELECT_INPUT_OFFSET		0x066C
+#define IOMUXC_LCD_DATA14_SELECT_INPUT_OFFSET		0x0670
+#define IOMUXC_LCD_DATA15_SELECT_INPUT_OFFSET		0x0674
+#define IOMUXC_LCD_DATA16_SELECT_INPUT_OFFSET		0x0678
+#define IOMUXC_LCD_DATA17_SELECT_INPUT_OFFSET		0x067C
+#define IOMUXC_LCD_DATA18_SELECT_INPUT_OFFSET		0x0680
+#define IOMUXC_LCD_DATA19_SELECT_INPUT_OFFSET		0x0684
+#define IOMUXC_LCD_DATA20_SELECT_INPUT_OFFSET		0x0688
+#define IOMUXC_LCD_DATA21_SELECT_INPUT_OFFSET		0x068C
+#define IOMUXC_LCD_DATA22_SELECT_INPUT_OFFSET		0x0690
+#define IOMUXC_LCD_DATA23_SELECT_INPUT_OFFSET		0x0694
+#define IOMUXC_LCD_VSYNC_SELECT_INPUT_OFFSET		0x0698
+
+#define IOMUXC_SAI1_RX_BCLK_SELECT_INPUT_OFFSET		0x069C
+#define IOMUXC_SAI1_RX_DATA_SELECT_INPUT_OFFSET		0x06A0
+#define IOMUXC_SAI1_RX_SYNC_SELECT_INPUT_OFFSET		0x06A4
+#define IOMUXC_SAI1_TX_BCLK_SELECT_INPUT_OFFSET		0x06A8
+#define IOMUXC_SAI1_TX_SYNC_SELECT_INPUT_OFFSET		0x06AC
+#define IOMUXC_SAI2_RX_BCLK_SELECT_INPUT_OFFSET		0x06B0
+#define IOMUXC_SAI2_RX_DATA_SELECT_INPUT_OFFSET		0x06B4
+#define IOMUXC_SAI2_RX_SYNC_SELECT_INPUT_OFFSET		0x06B8
+#define IOMUXC_SAI2_TX_BCLK_SELECT_INPUT_OFFSET		0x06BC
+#define IOMUXC_SAI2_TX_SYNC_SELECT_INPUT_OFFSET		0x06C0
+#define IOMUXC_SAI3_RX_BCLK_SELECT_INPUT_OFFSET		0x06C4
+#define IOMUXC_SAI3_RX_DATA_SELECT_INPUT_OFFSET		0x06C8
+#define IOMUXC_SAI3_RX_SYNC_SELECT_INPUT_OFFSET		0x06CC
+#define IOMUXC_SAI3_TX_BCLK_SELECT_INPUT_OFFSET		0x06D0
+#define IOMUXC_SAI3_TX_SYNC_SELECT_INPUT_OFFSET		0x06D4
+#define IOMUXC_SDMA_EVENTS0_SELECT_INPUT_OFFSET		0x06D8
+#define IOMUXC_SDMA_EVENTS1_SELECT_INPUT_OFFSET		0x06DC
+
+#define IOMUXC_SIM1_PORT1_PD_SELECT_INPUT_OFFSET	0x06E0
+#define IOMUXC_SIM1_PORT1_TRXD_SELECT_INPUT_OFFSET	0x06E4
+#define IOMUXC_SIM2_PORT1_PD_SELECT_INPUT_OFFSET	0x06E8
+#define IOMUXC_SIM2_PORT1_TRXD_SELECT_INPUT_OFFSET	0x06EC
+
+#define IOMUXC_UART1_RTS_B_SELECT_INPUT_OFFSET		0x06F0
+#define IOMUXC_UART1_RX_DATA_SELECT_INPUT_OFFSET	0x06F4
+#define IOMUXC_UART2_RTS_B_SELECT_INPUT_OFFSET		0x06F8
+#define IOMUXC_UART2_RX_DATA_SELECT_INPUT_OFFSET	0x06FC
+#define IOMUXC_UART3_RTS_B_SELECT_INPUT_OFFSET		0x0700
+#define IOMUXC_UART3_RX_DATA_SELECT_INPUT_OFFSET	0x0704
+#define IOMUXC_UART4_RTS_B_SELECT_INPUT_OFFSET		0x0708
+#define IOMUXC_UART4_RX_DATA_SELECT_INPUT_OFFSET	0x070C
+#define IOMUXC_UART5_RTS_B_SELECT_INPUT_OFFSET		0x0710
+
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_OFFSET	0x0714
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_I2C4_SCL_ALT1	0x00
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_I2C4_SDA_ALT1	BIT(0)
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_SAI1_RX_DATA_ALT2	BIT(1)
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_SAI1_TX_BCLK_ALT2	(BIT(1) | BIT(0))
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_GPIO1_IO06_ALT3	BIT(2)
+#define IOMUXC_UART5_RX_DATA_SELECT_INPUT_GPIO1_IO07_ALT3	(BIT(2) | BIT(1))
+
+#define IOMUXC_UART6_RTS_B_SELECT_INPUT_OFFSET		0x0718
+#define IOMUXC_UART6_RX_DATA_SELECT_INPUT_OFFSET	0x071C
+#define IOMUXC_UART7_RTS_B_SELECT_INPUT_OFFSET		0x0720
+#define IOMUXC_UART7_RX_DATA_SELECT_INPUT_OFFSET	0x0724
+
+#define IOMUXC_USB_OTG2_OC_SELECT_INPUT_OFFSET		0x0728
+#define IOMUXC_USB_OTG1_OC_SELECT_INPUT_OFFSET		0x072C
+#define IOMUXC_USB_OTG2_ID_SELECT_INPUT_OFFSET		0x0730
+#define IOMUXC_USB_OTG1_ID_SELECT_INPUT_OFFSET		0x0734
+#define IOMUXC_SD3_CD_B_SELECT_INPUT_OFFSET		0x0738
+#define IOMUXC_SD3_WP_SELECT_INPUT_OFFSET		0x073C
+
+/* Pad mux/feature set routines */
+
+void imx_io_muxc_set_pad_alt_function(uint32_t pad_mux_offset, uint32_t alt_function);
+void imx_io_muxc_set_pad_features(uint32_t pad_feature_offset, uint32_t pad_features);
+
+#endif /* IMX_IO_MUX_H */
diff --git a/plat/imx/common/include/imx_sip_svc.h b/plat/imx/common/include/imx_sip_svc.h
new file mode 100644
index 0000000..5898f7a
--- /dev/null
+++ b/plat/imx/common/include/imx_sip_svc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __IMX_SIP_SVC_H__
+#define __IMX_SIP_SVC_H__
+
+/* SMC function IDs for SiP Service queries */
+#define IMX_SIP_CPUFREQ			0xC2000001
+#define IMX_SIP_SET_CPUFREQ		0x00
+
+#define IMX_SIP_SRTC			0xC2000002
+#define IMX_SIP_SRTC_SET_TIME		0x00
+
+#define IMX_SIP_BUILDINFO			0xC2000003
+#define IMX_SIP_BUILDINFO_GET_COMMITHASH	0x00
+
+#define IMX_SIP_GET_SOC_INFO		0xC2000006
+
+#define IMX_SIP_WAKEUP_SRC		0xC2000009
+#define IMX_SIP_WAKEUP_SRC_SCU		0x1
+#define IMX_SIP_WAKEUP_SRC_IRQSTEER	0x2
+
+#define IMX_SIP_OTP_READ		0xC200000A
+#define IMX_SIP_OTP_WRITE		0xC200000B
+
+#define IMX_SIP_MISC_SET_TEMP		0xC200000C
+
+#if defined(PLAT_imx8mq)
+int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1,
+			 u_register_t x2, u_register_t x3);
+#endif
+
+#if (defined(PLAT_imx8qm) || defined(PLAT_imx8qx))
+int imx_cpufreq_handler(uint32_t smc_fid, u_register_t x1,
+			u_register_t x2, u_register_t x3);
+int imx_srtc_handler(uint32_t smc_fid, void *handle, u_register_t x1,
+		     u_register_t x2, u_register_t x3, u_register_t x4);
+int imx_wakeup_src_handler(uint32_t smc_fid, u_register_t x1,
+			   u_register_t x2, u_register_t x3);
+int imx_otp_handler(uint32_t smc_fid, void *handle,
+		    u_register_t x1, u_register_t x2);
+int imx_misc_set_temp_handler(uint32_t smc_fid, u_register_t x1,
+			      u_register_t x2, u_register_t x3,
+			      u_register_t x4);
+#endif
+uint64_t imx_buildinfo_handler(uint32_t smc_fid, u_register_t x1,
+			       u_register_t x2, u_register_t x3,
+			       u_register_t x4);
+
+#endif /* __IMX_SIP_SVC_H__ */
diff --git a/plat/imx/common/include/imx_snvs.h b/plat/imx/common/include/imx_snvs.h
new file mode 100644
index 0000000..0b3d108
--- /dev/null
+++ b/plat/imx/common/include/imx_snvs.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_SNVS_H
+#define IMX_SNVS_H
+
+#include <stdint.h>
+
+#include <arch.h>
+
+struct snvs {
+	uint32_t hplr;
+	uint32_t hpcomr;
+	uint32_t hpcr;
+	uint32_t hpsicr;
+	uint32_t hpsvcr;
+	uint32_t hpsr;
+	uint32_t hpsvsr;
+	uint32_t hphacivr;
+	uint32_t hphacr;
+	uint32_t hprtcmr;
+	uint32_t hprtclr;
+	uint32_t hptamr;
+	uint32_t hptalr;
+	uint32_t lplr;
+	uint32_t lpcr;
+	uint32_t lpmkcr;
+	uint32_t lpsvcr;
+	uint32_t lptgfcr;
+	uint32_t lptdcr;
+	uint32_t lpsr;
+	uint32_t lpsrtcmr;
+	uint32_t lpsrtclr;
+	uint32_t lptar;
+	uint32_t lpsmcmr;
+	uint32_t lpsmclr;
+	uint32_t lppgdr;
+	uint32_t lpgpr0_alias;
+	uint8_t  lpzmkr[32];
+	uint16_t res0;
+	uint32_t lpgpr0[4];
+	uint32_t lptdc2r;
+	uint32_t lptdsr;
+	uint32_t lptgf1cr;
+	uint32_t lptgf2cr;
+	uint32_t res1[4];
+	uint32_t lpat1cr;
+	uint32_t lpat2cr;
+	uint32_t lpat3cr;
+	uint32_t lpat4cr;
+	uint32_t lpat5cr;
+	uint32_t res2[3];
+	uint32_t lpatctlr;
+	uint32_t lpatclkr;
+	uint32_t lpatrc1r;
+	uint32_t lpatrc2r;
+	uint32_t res3[706];
+	uint32_t hpvidr1;
+	uint32_t hpvidr2;
+} __packed;
+
+/* Define the HPCOMR bits */
+#define HPCOMR_NPSWA_EN		BIT(31)
+#define HPCOMR_HAC_STOP		BIT(19)
+#define HPCOMR_HAC_CLEAR	BIT(18)
+#define HPCOMR_HAC_LOAD		BIT(17)
+#define HPCOMR_HAC_EN		BIT(16)
+#define HPCOMR_MKS_EN		BIT(13)
+#define HPCOMR_PROG_ZMK		BIT(12)
+#define HPCOMR_SW_LPSV		BIT(10)
+#define HPCOMR_SW_FSV		BIT(9)
+#define HPCOMR_SW_SV		BIT(8)
+#define HPCOMR_LP_SWR_DIS	BIT(5)
+#define HPCOMR_LP_SWR		BIT(4)
+#define HPCOMR_SSM_SFNS_DIS	BIT(2)
+#define HPCOMR_SSM_ST_DIS	BIT(1)
+#define HPCOMR_SSM_ST		BIT(0)
+
+void imx_snvs_init(void);
+
+#endif /* IMX_SNVS_H */
diff --git a/plat/imx/common/include/imx_uart.h b/plat/imx/common/include/imx_uart.h
new file mode 100644
index 0000000..cc1b531
--- /dev/null
+++ b/plat/imx/common/include/imx_uart.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_UART_H
+#define IMX_UART_H
+
+#include <drivers/console.h>
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_uart_t;
+
+int console_imx_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_uart_t *console);
+#endif /*__ASSEMBLER__*/
+
+#endif  /* IMX_UART_H */
diff --git a/plat/imx/common/include/imx_wdog.h b/plat/imx/common/include/imx_wdog.h
new file mode 100644
index 0000000..75a729a
--- /dev/null
+++ b/plat/imx/common/include/imx_wdog.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_WDOG_H
+#define IMX_WDOG_H
+
+#include <stdint.h>
+
+#include <arch.h>
+
+struct wdog_regs {
+	uint16_t wcr;
+	uint16_t wsr;
+	uint16_t wrsr;
+	uint16_t wicr;
+	uint16_t wmcr;
+};
+
+/* WCR bits */
+#define WCR_WDZST		BIT(0)
+#define WCR_WDBG		BIT(1)
+#define WCR_WDE			BIT(2)
+#define WCR_WDT			BIT(3)
+#define WCR_SRS			BIT(4)
+#define WCR_WDA			BIT(5)
+#define WCR_SRE			BIT(6)
+#define WCR_WDW			BIT(7)
+#define WCR_WT(x)		((x) << 8)
+
+/* WSR bits */
+#define WSR_FIRST		0x5555
+#define WSR_SECOND		0xAAAA
+
+/* WRSR bits */
+#define WRSR_SFTW		BIT(0)
+#define WRSR_TOUT		BIT(1)
+#define WRSR_POR		BIT(4)
+
+/* WICR bits */
+static inline int wicr_calc_wict(int sec, int half_sec)
+{
+	int wict_bits;
+
+	/* Represents WICR bits 7 - 0 */
+	wict_bits = ((sec << 1) | (half_sec ? 1 : 0));
+
+	return wict_bits;
+}
+
+#define WICR_WTIS		BIT(14)
+#define WICR_WIE		BIT(15)
+
+/* WMCR bits */
+#define WMCR_PDE		BIT(0)
+
+/* External facing API */
+void imx_wdog_init(void);
+
+#endif /* IMX_WDOG_H */
diff --git a/plat/imx/common/include/plat_imx8.h b/plat/imx/common/include/plat_imx8.h
new file mode 100644
index 0000000..be99b97
--- /dev/null
+++ b/plat/imx/common/include/plat_imx8.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_IMX8_H
+#define PLAT_IMX8_H
+
+#include <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+
+struct plat_gic_ctx {
+	gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT];
+	gicv3_dist_ctx_t dist_ctx;
+};
+
+unsigned int plat_calc_core_pos(uint64_t mpidr);
+void imx_mailbox_init(uintptr_t base_addr);
+void plat_gic_driver_init(void);
+void plat_gic_init(void);
+void plat_gic_cpuif_enable(void);
+void plat_gic_cpuif_disable(void);
+void plat_gic_pcpu_init(void);
+
+void __dead2 imx_system_off(void);
+void __dead2 imx_system_reset(void);
+int imx_validate_power_state(unsigned int power_state,
+			psci_power_state_t *req_state);
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state);
+bool imx_is_wakeup_src_irqsteer(void);
+void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx);
+void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx);
+
+#endif /* PLAT_IMX8_H */
diff --git a/plat/imx/common/include/plat_macros.S b/plat/imx/common/include/plat_macros.S
new file mode 100644
index 0000000..30cce0a
--- /dev/null
+++ b/plat/imx/common/include/plat_macros.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * the below macros print out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL3-1
+ */
+.macro plat_print_gic_regs
+	/* TODO */
+.endm
+
+/*
+ * the below macros print out relevant interconnect
+ * registers whenever an unhandled exception is
+ * taken in BL3-1
+ */
+.macro plat_print_interconnect_regs
+	/* TODO */
+.endm
+
+/* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant platform registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+      /* TODO */
+.endm
diff --git a/plat/imx/common/include/sci/sci.h b/plat/imx/common/include/sci/sci.h
new file mode 100644
index 0000000..2c45bb8
--- /dev/null
+++ b/plat/imx/common/include/sci/sci.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCI_H
+#define SCI_H
+
+/* Defines */
+
+/* Includes */
+
+#include <sci/sci_ipc.h>
+#include <sci/svc/pad/sci_pad_api.h>
+#include <sci/svc/pm/sci_pm_api.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/timer/sci_timer_api.h>
+#include <sci/svc/misc/sci_misc_api.h>
+
+#endif /* SCI_H */
diff --git a/plat/imx/common/include/sci/sci_ipc.h b/plat/imx/common/include/sci/sci_ipc.h
new file mode 100644
index 0000000..1167ea3
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_ipc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the IPC implementation.
+ */
+
+#ifndef SCI_IPC_H
+#define SCI_IPC_H
+
+/* Includes */
+
+#include <sci/sci_types.h>
+
+/* Defines */
+
+/* Types */
+
+/* Functions */
+
+/*!
+ * This function opens an IPC channel.
+ *
+ * @param[out]    ipc         return pointer for ipc handle
+ * @param[in]     id          id of channel to open
+ *
+ * @return Returns an error code (SC_ERR_NONE = success, SC_ERR_IPC
+ *         otherwise).
+ *
+ * The \a id parameter is implementation specific. Could be an MU
+ * address, pointer to a driver path, channel index, etc.
+ */
+sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id);
+
+/*!
+ * This function closes an IPC channel.
+ *
+ * @param[in]     ipc         id of channel to close
+ */
+void sc_ipc_close(sc_ipc_t ipc);
+
+/*!
+ * This function reads a message from an IPC channel.
+ *
+ * @param[in]     ipc         id of channel read from
+ * @param[out]    data        pointer to message buffer to read
+ *
+ * This function will block if no message is available to be read.
+ */
+void sc_ipc_read(sc_ipc_t ipc, void *data);
+
+/*!
+ * This function writes a message to an IPC channel.
+ *
+ * @param[in]     ipc         id of channel to write to
+ * @param[in]     data        pointer to message buffer to write
+ *
+ * This function will block if the outgoing buffer is full.
+ */
+void sc_ipc_write(sc_ipc_t ipc, void *data);
+
+sc_ipc_t ipc_handle;
+
+#endif /* SCI_IPC_H */
diff --git a/plat/imx/common/include/sci/sci_rpc.h b/plat/imx/common/include/sci/sci_rpc.h
new file mode 100644
index 0000000..60dbc27
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_rpc.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the RPC implementation.
+ */
+
+#ifndef SCI_RPC_H
+#define SCI_RPC_H
+
+/* Includes */
+
+#include <stdbool.h>
+
+#include <sci/sci_types.h>
+#include <sci/sci_ipc.h>
+
+/* Defines */
+
+#define SC_RPC_VERSION          1U
+
+#define SC_RPC_MAX_MSG          8U
+
+#define RPC_VER(MSG)            ((MSG)->version)
+#define RPC_SIZE(MSG)           ((MSG)->size)
+#define RPC_SVC(MSG)            ((MSG)->svc)
+#define RPC_FUNC(MSG)           ((MSG)->func)
+#define RPC_R8(MSG)             ((MSG)->func)
+#define RPC_I32(MSG, IDX)       ((MSG)->DATA.i32[(IDX) / 4U])
+#define RPC_I16(MSG, IDX)       ((MSG)->DATA.i16[(IDX) / 2U])
+#define RPC_I8(MSG, IDX)        ((MSG)->DATA.i8[(IDX)])
+#define RPC_U32(MSG, IDX)       ((MSG)->DATA.u32[(IDX) / 4U])
+#define RPC_U16(MSG, IDX)       ((MSG)->DATA.u16[(IDX) / 2U])
+#define RPC_U8(MSG, IDX)        ((MSG)->DATA.u8[(IDX)])
+
+#define SC_RPC_SVC_UNKNOWN      0U
+#define SC_RPC_SVC_RETURN       1U
+#define SC_RPC_SVC_PM           2U
+#define SC_RPC_SVC_RM           3U
+#define SC_RPC_SVC_TIMER        5U
+#define SC_RPC_SVC_PAD          6U
+#define SC_RPC_SVC_MISC         7U
+#define SC_RPC_SVC_IRQ          8U
+#define SC_RPC_SVC_ABORT        9U
+
+#define SC_RPC_ASYNC_STATE_RD_START      0U
+#define SC_RPC_ASYNC_STATE_RD_ACTIVE     1U
+#define SC_RPC_ASYNC_STATE_RD_DONE       2U
+#define SC_RPC_ASYNC_STATE_WR_START      3U
+#define SC_RPC_ASYNC_STATE_WR_ACTIVE     4U
+#define SC_RPC_ASYNC_STATE_WR_DONE       5U
+
+#define SC_RPC_MU_GIR_SVC       0x1U
+#define SC_RPC_MU_GIR_DBG       0x8U
+
+/* Types */
+
+typedef uint8_t sc_rpc_svc_t;
+
+typedef struct sc_rpc_msg_s {
+	uint8_t version;
+	uint8_t size;
+	uint8_t svc;
+	uint8_t func;
+	union {
+		int32_t i32[(SC_RPC_MAX_MSG - 1U)];
+		int16_t i16[(SC_RPC_MAX_MSG - 1U) * 2U];
+		int8_t i8[(SC_RPC_MAX_MSG - 1U) * 4U];
+		uint32_t u32[(SC_RPC_MAX_MSG - 1U)];
+		uint16_t u16[(SC_RPC_MAX_MSG - 1U) * 2U];
+		uint8_t u8[(SC_RPC_MAX_MSG - 1U) * 4U];
+	} DATA;
+} sc_rpc_msg_t;
+
+typedef uint8_t sc_rpc_async_state_t;
+
+typedef struct sc_rpc_async_msg_s {
+	sc_rpc_async_state_t state;
+	uint8_t wordIdx;
+	sc_rpc_msg_t msg;
+	uint32_t timeStamp;
+} sc_rpc_async_msg_t;
+
+/* Functions */
+
+/*!
+ * This is an internal function to send an RPC message over an IPC
+ * channel. It is called by client-side SCFW API function shims.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in,out] msg         handle to a message
+ * @param[in]     no_resp     response flag
+ *
+ * If \a no_resp is SC_FALSE then this function waits for a response
+ * and returns the result in \a msg.
+ */
+void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, bool no_resp);
+
+/*!
+ * This is an internal function to dispath an RPC call that has
+ * arrived via IPC over an MU. It is called by server-side SCFW.
+ *
+ * @param[in]     mu          MU message arrived on
+ * @param[in,out] msg         handle to a message
+ *
+ * The function result is returned in \a msg.
+ */
+void sc_rpc_dispatch(sc_rsrc_t mu, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates an RPC message and forwards on to the
+ * normal RPC API.  It is used only by hypervisors.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in,out] msg         handle to a message
+ *
+ * This function decodes a message, calls macros to translate the
+ * resources, pads, addresses, partitions, memory regions, etc. and
+ * then forwards on to the hypervisors SCFW API.Return results are
+ * translated back abd placed back into the message to be returned
+ * to the original API.
+ */
+void sc_rpc_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* SCI_RPC_H */
diff --git a/plat/imx/common/include/sci/sci_scfw.h b/plat/imx/common/include/sci/sci_scfw.h
new file mode 100644
index 0000000..a169f88
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_scfw.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCI_SCFW_H
+#define SCI_SCFW_H
+
+/* Includes */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+  #define   __I     volatile             /*!< Defines 'read only' permissions                 */
+#else
+  #define   __I     volatile const       /*!< Defines 'read only' permissions                 */
+#endif
+#define     __O     volatile             /*!< Defines 'write only' permissions                */
+#define     __IO    volatile             /*!< Defines 'read / write' permissions              */
+
+/*!
+ * This type is used to declare a handle for an IPC communication
+ * channel. Its meaning is specific to the IPC implementation.
+ */
+typedef uint64_t sc_ipc_t;
+
+/*!
+ * This type is used to declare an ID for an IPC communication
+ * channel. For the reference IPC implementation, this ID
+ * selects the base address of the MU used for IPC.
+ */
+typedef uint64_t sc_ipc_id_t;
+
+
+#endif /* SCI_SCFW_H */
diff --git a/plat/imx/common/include/sci/sci_types.h b/plat/imx/common/include/sci/sci_types.h
new file mode 100644
index 0000000..6ade01c
--- /dev/null
+++ b/plat/imx/common/include/sci/sci_types.h
@@ -0,0 +1,849 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file containing types used across multiple service APIs.
+ */
+
+#ifndef SCI_TYPES_H
+#define SCI_TYPES_H
+
+/* Includes */
+
+#include <sci/sci_scfw.h>
+
+/* Defines */
+
+/*!
+ * @name Defines for common frequencies
+ */
+/*@{*/
+#define SC_32KHZ            32768U	/* 32KHz */
+#define SC_10MHZ         10000000U	/* 10MHz */
+#define SC_20MHZ         20000000U	/* 20MHz */
+#define SC_25MHZ         25000000U	/* 25MHz */
+#define SC_27MHZ         27000000U	/* 27MHz */
+#define SC_40MHZ         40000000U	/* 40MHz */
+#define SC_45MHZ         45000000U	/* 45MHz */
+#define SC_50MHZ         50000000U	/* 50MHz */
+#define SC_60MHZ         60000000U	/* 60MHz */
+#define SC_66MHZ         66666666U	/* 66MHz */
+#define SC_74MHZ         74250000U	/* 74.25MHz */
+#define SC_80MHZ         80000000U	/* 80MHz */
+#define SC_83MHZ         83333333U	/* 83MHz */
+#define SC_84MHZ         84375000U	/* 84.37MHz */
+#define SC_100MHZ       100000000U	/* 100MHz */
+#define SC_125MHZ       125000000U	/* 125MHz */
+#define SC_133MHZ       133333333U	/* 133MHz */
+#define SC_135MHZ       135000000U	/* 135MHz */
+#define SC_150MHZ       150000000U	/* 150MHz */
+#define SC_160MHZ       160000000U	/* 160MHz */
+#define SC_166MHZ       166666666U	/* 166MHz */
+#define SC_175MHZ       175000000U	/* 175MHz */
+#define SC_180MHZ       180000000U	/* 180MHz */
+#define SC_200MHZ       200000000U	/* 200MHz */
+#define SC_250MHZ       250000000U	/* 250MHz */
+#define SC_266MHZ       266666666U	/* 266MHz */
+#define SC_300MHZ       300000000U	/* 300MHz */
+#define SC_312MHZ       312500000U	/* 312.5MHZ */
+#define SC_320MHZ       320000000U	/* 320MHz */
+#define SC_325MHZ       325000000U	/* 325MHz */
+#define SC_333MHZ       333333333U	/* 333MHz */
+#define SC_350MHZ       350000000U	/* 350MHz */
+#define SC_372MHZ       372000000U	/* 372MHz */
+#define SC_375MHZ       375000000U	/* 375MHz */
+#define SC_400MHZ       400000000U	/* 400MHz */
+#define SC_500MHZ       500000000U	/* 500MHz */
+#define SC_594MHZ       594000000U	/* 594MHz */
+#define SC_625MHZ       625000000U	/* 625MHz */
+#define SC_640MHZ       640000000U	/* 640MHz */
+#define SC_650MHZ       650000000U	/* 650MHz */
+#define SC_667MHZ       666666667U	/* 667MHz */
+#define SC_675MHZ       675000000U	/* 675MHz */
+#define SC_700MHZ       700000000U	/* 700MHz */
+#define SC_720MHZ       720000000U	/* 720MHz */
+#define SC_750MHZ       750000000U	/* 750MHz */
+#define SC_800MHZ       800000000U	/* 800MHz */
+#define SC_850MHZ       850000000U	/* 850MHz */
+#define SC_900MHZ       900000000U	/* 900MHz */
+#define SC_1000MHZ     1000000000U	/* 1GHz */
+#define SC_1056MHZ     1056000000U	/* 1.056GHz */
+#define SC_1188MHZ     1188000000U	/* 1.188GHz */
+#define SC_1260MHZ     1260000000U	/* 1.26GHz */
+#define SC_1280MHZ     1280000000U	/* 1.28GHz */
+#define SC_1300MHZ     1300000000U	/* 1.3GHz */
+#define SC_1400MHZ     1400000000U	/* 1.4GHz */
+#define SC_1500MHZ     1500000000U	/* 1.5GHz */
+#define SC_1600MHZ     1600000000U	/* 1.6GHz */
+#define SC_1800MHZ     1800000000U	/* 1.8GHz */
+#define SC_2000MHZ     2000000000U	/* 2.0GHz */
+#define SC_2112MHZ     2112000000U	/* 2.12GHz */
+/*@}*/
+
+/*!
+ * @name Defines for 24M related frequencies
+ */
+/*@{*/
+#define SC_8MHZ           8000000U	/* 8MHz */
+#define SC_12MHZ         12000000U	/* 12MHz */
+#define SC_19MHZ         19800000U	/* 19.8MHz */
+#define SC_24MHZ         24000000U	/* 24MHz */
+#define SC_48MHZ         48000000U	/* 48MHz */
+#define SC_120MHZ       120000000U	/* 120MHz */
+#define SC_132MHZ       132000000U	/* 132MHz */
+#define SC_144MHZ       144000000U	/* 144MHz */
+#define SC_192MHZ       192000000U	/* 192MHz */
+#define SC_211MHZ       211200000U	/* 211.2MHz */
+#define SC_240MHZ       240000000U	/* 240MHz */
+#define SC_264MHZ       264000000U	/* 264MHz */
+#define SC_352MHZ       352000000U	/* 352MHz */
+#define SC_360MHZ       360000000U	/* 360MHz */
+#define SC_384MHZ       384000000U	/* 384MHz */
+#define SC_396MHZ       396000000U	/* 396MHz */
+#define SC_432MHZ       432000000U	/* 432MHz */
+#define SC_480MHZ       480000000U	/* 480MHz */
+#define SC_600MHZ       600000000U	/* 600MHz */
+#define SC_744MHZ       744000000U	/* 744MHz */
+#define SC_792MHZ       792000000U	/* 792MHz */
+#define SC_864MHZ       864000000U	/* 864MHz */
+#define SC_960MHZ       960000000U	/* 960MHz */
+#define SC_1056MHZ     1056000000U	/* 1056MHz */
+#define SC_1200MHZ     1200000000U	/* 1.2GHz */
+#define SC_1464MHZ     1464000000U	/* 1.464GHz */
+#define SC_2400MHZ     2400000000U	/* 2.4GHz */
+/*@}*/
+
+/*!
+ * @name Defines for A/V related frequencies
+ */
+/*@{*/
+#define SC_62MHZ         62937500U	/* 62.9375MHz */
+#define SC_755MHZ       755250000U	/* 755.25MHz */
+/*@}*/
+
+/*!
+ * @name Defines for type widths
+ */
+/*@{*/
+#define SC_FADDR_W      36U	/* Width of sc_faddr_t */
+#define SC_BOOL_W       1U	/* Width of sc_bool_t */
+#define SC_ERR_W        4U	/* Width of sc_err_t */
+#define SC_RSRC_W       10U	/* Width of sc_rsrc_t */
+#define SC_CTRL_W       6U	/* Width of sc_ctrl_t */
+/*@}*/
+
+/*!
+ * @name Defines for sc_bool_t
+ */
+/*@{*/
+#define SC_FALSE        ((sc_bool_t) 0U)	/* True */
+#define SC_TRUE         ((sc_bool_t) 1U)	/* False */
+/*@}*/
+
+/*!
+ * @name Defines for sc_err_t.
+ */
+/*@{*/
+#define SC_ERR_NONE         0U	/* Success */
+#define SC_ERR_VERSION      1U	/* Incompatible API version */
+#define SC_ERR_CONFIG       2U	/* Configuration error */
+#define SC_ERR_PARM         3U	/* Bad parameter */
+#define SC_ERR_NOACCESS     4U	/* Permission error (no access) */
+#define SC_ERR_LOCKED       5U	/* Permission error (locked) */
+#define SC_ERR_UNAVAILABLE  6U	/* Unavailable (out of resources) */
+#define SC_ERR_NOTFOUND     7U	/* Not found */
+#define SC_ERR_NOPOWER      8U	/* No power */
+#define SC_ERR_IPC          9U	/* Generic IPC error */
+#define SC_ERR_BUSY         10U	/* Resource is currently busy/active */
+#define SC_ERR_FAIL         11U	/* General I/O failure */
+#define SC_ERR_LAST         12U
+/*@}*/
+
+/*!
+ * @name Defines for sc_rsrc_t.
+ */
+/*@{*/
+#define SC_R_A53                  0U
+#define SC_R_A53_0                1U
+#define SC_R_A53_1                2U
+#define SC_R_A53_2                3U
+#define SC_R_A53_3                4U
+#define SC_R_A72                  5U
+#define SC_R_A72_0                6U
+#define SC_R_A72_1                7U
+#define SC_R_A72_2                8U
+#define SC_R_A72_3                9U
+#define SC_R_CCI                  10U
+#define SC_R_DB                   11U
+#define SC_R_DRC_0                12U
+#define SC_R_DRC_1                13U
+#define SC_R_GIC_SMMU             14U
+#define SC_R_IRQSTR_M4_0          15U
+#define SC_R_IRQSTR_M4_1          16U
+#define SC_R_SMMU                 17U
+#define SC_R_GIC                  18U
+#define SC_R_DC_0_BLIT0           19U
+#define SC_R_DC_0_BLIT1           20U
+#define SC_R_DC_0_BLIT2           21U
+#define SC_R_DC_0_BLIT_OUT        22U
+#define SC_R_DC_0_CAPTURE0        23U
+#define SC_R_DC_0_CAPTURE1        24U
+#define SC_R_DC_0_WARP            25U
+#define SC_R_DC_0_INTEGRAL0       26U
+#define SC_R_DC_0_INTEGRAL1       27U
+#define SC_R_DC_0_VIDEO0          28U
+#define SC_R_DC_0_VIDEO1          29U
+#define SC_R_DC_0_FRAC0           30U
+#define SC_R_DC_0_FRAC1           31U
+#define SC_R_DC_0                 32U
+#define SC_R_GPU_2_PID0           33U
+#define SC_R_DC_0_PLL_0           34U
+#define SC_R_DC_0_PLL_1           35U
+#define SC_R_DC_1_BLIT0           36U
+#define SC_R_DC_1_BLIT1           37U
+#define SC_R_DC_1_BLIT2           38U
+#define SC_R_DC_1_BLIT_OUT        39U
+#define SC_R_DC_1_CAPTURE0        40U
+#define SC_R_DC_1_CAPTURE1        41U
+#define SC_R_DC_1_WARP            42U
+#define SC_R_DC_1_INTEGRAL0       43U
+#define SC_R_DC_1_INTEGRAL1       44U
+#define SC_R_DC_1_VIDEO0          45U
+#define SC_R_DC_1_VIDEO1          46U
+#define SC_R_DC_1_FRAC0           47U
+#define SC_R_DC_1_FRAC1           48U
+#define SC_R_DC_1                 49U
+#define SC_R_GPU_3_PID0           50U
+#define SC_R_DC_1_PLL_0           51U
+#define SC_R_DC_1_PLL_1           52U
+#define SC_R_SPI_0                53U
+#define SC_R_SPI_1                54U
+#define SC_R_SPI_2                55U
+#define SC_R_SPI_3                56U
+#define SC_R_UART_0               57U
+#define SC_R_UART_1               58U
+#define SC_R_UART_2               59U
+#define SC_R_UART_3               60U
+#define SC_R_UART_4               61U
+#define SC_R_EMVSIM_0             62U
+#define SC_R_EMVSIM_1             63U
+#define SC_R_DMA_0_CH0            64U
+#define SC_R_DMA_0_CH1            65U
+#define SC_R_DMA_0_CH2            66U
+#define SC_R_DMA_0_CH3            67U
+#define SC_R_DMA_0_CH4            68U
+#define SC_R_DMA_0_CH5            69U
+#define SC_R_DMA_0_CH6            70U
+#define SC_R_DMA_0_CH7            71U
+#define SC_R_DMA_0_CH8            72U
+#define SC_R_DMA_0_CH9            73U
+#define SC_R_DMA_0_CH10           74U
+#define SC_R_DMA_0_CH11           75U
+#define SC_R_DMA_0_CH12           76U
+#define SC_R_DMA_0_CH13           77U
+#define SC_R_DMA_0_CH14           78U
+#define SC_R_DMA_0_CH15           79U
+#define SC_R_DMA_0_CH16           80U
+#define SC_R_DMA_0_CH17           81U
+#define SC_R_DMA_0_CH18           82U
+#define SC_R_DMA_0_CH19           83U
+#define SC_R_DMA_0_CH20           84U
+#define SC_R_DMA_0_CH21           85U
+#define SC_R_DMA_0_CH22           86U
+#define SC_R_DMA_0_CH23           87U
+#define SC_R_DMA_0_CH24           88U
+#define SC_R_DMA_0_CH25           89U
+#define SC_R_DMA_0_CH26           90U
+#define SC_R_DMA_0_CH27           91U
+#define SC_R_DMA_0_CH28           92U
+#define SC_R_DMA_0_CH29           93U
+#define SC_R_DMA_0_CH30           94U
+#define SC_R_DMA_0_CH31           95U
+#define SC_R_I2C_0                96U
+#define SC_R_I2C_1                97U
+#define SC_R_I2C_2                98U
+#define SC_R_I2C_3                99U
+#define SC_R_I2C_4                100U
+#define SC_R_ADC_0                101U
+#define SC_R_ADC_1                102U
+#define SC_R_FTM_0                103U
+#define SC_R_FTM_1                104U
+#define SC_R_CAN_0                105U
+#define SC_R_CAN_1                106U
+#define SC_R_CAN_2                107U
+#define SC_R_DMA_1_CH0            108U
+#define SC_R_DMA_1_CH1            109U
+#define SC_R_DMA_1_CH2            110U
+#define SC_R_DMA_1_CH3            111U
+#define SC_R_DMA_1_CH4            112U
+#define SC_R_DMA_1_CH5            113U
+#define SC_R_DMA_1_CH6            114U
+#define SC_R_DMA_1_CH7            115U
+#define SC_R_DMA_1_CH8            116U
+#define SC_R_DMA_1_CH9            117U
+#define SC_R_DMA_1_CH10           118U
+#define SC_R_DMA_1_CH11           119U
+#define SC_R_DMA_1_CH12           120U
+#define SC_R_DMA_1_CH13           121U
+#define SC_R_DMA_1_CH14           122U
+#define SC_R_DMA_1_CH15           123U
+#define SC_R_DMA_1_CH16           124U
+#define SC_R_DMA_1_CH17           125U
+#define SC_R_DMA_1_CH18           126U
+#define SC_R_DMA_1_CH19           127U
+#define SC_R_DMA_1_CH20           128U
+#define SC_R_DMA_1_CH21           129U
+#define SC_R_DMA_1_CH22           130U
+#define SC_R_DMA_1_CH23           131U
+#define SC_R_DMA_1_CH24           132U
+#define SC_R_DMA_1_CH25           133U
+#define SC_R_DMA_1_CH26           134U
+#define SC_R_DMA_1_CH27           135U
+#define SC_R_DMA_1_CH28           136U
+#define SC_R_DMA_1_CH29           137U
+#define SC_R_DMA_1_CH30           138U
+#define SC_R_DMA_1_CH31           139U
+#define SC_R_UNUSED1              140U
+#define SC_R_UNUSED2              141U
+#define SC_R_UNUSED3              142U
+#define SC_R_UNUSED4              143U
+#define SC_R_GPU_0_PID0           144U
+#define SC_R_GPU_0_PID1           145U
+#define SC_R_GPU_0_PID2           146U
+#define SC_R_GPU_0_PID3           147U
+#define SC_R_GPU_1_PID0           148U
+#define SC_R_GPU_1_PID1           149U
+#define SC_R_GPU_1_PID2           150U
+#define SC_R_GPU_1_PID3           151U
+#define SC_R_PCIE_A               152U
+#define SC_R_SERDES_0             153U
+#define SC_R_MATCH_0              154U
+#define SC_R_MATCH_1              155U
+#define SC_R_MATCH_2              156U
+#define SC_R_MATCH_3              157U
+#define SC_R_MATCH_4              158U
+#define SC_R_MATCH_5              159U
+#define SC_R_MATCH_6              160U
+#define SC_R_MATCH_7              161U
+#define SC_R_MATCH_8              162U
+#define SC_R_MATCH_9              163U
+#define SC_R_MATCH_10             164U
+#define SC_R_MATCH_11             165U
+#define SC_R_MATCH_12             166U
+#define SC_R_MATCH_13             167U
+#define SC_R_MATCH_14             168U
+#define SC_R_PCIE_B               169U
+#define SC_R_SATA_0               170U
+#define SC_R_SERDES_1             171U
+#define SC_R_HSIO_GPIO            172U
+#define SC_R_MATCH_15             173U
+#define SC_R_MATCH_16             174U
+#define SC_R_MATCH_17             175U
+#define SC_R_MATCH_18             176U
+#define SC_R_MATCH_19             177U
+#define SC_R_MATCH_20             178U
+#define SC_R_MATCH_21             179U
+#define SC_R_MATCH_22             180U
+#define SC_R_MATCH_23             181U
+#define SC_R_MATCH_24             182U
+#define SC_R_MATCH_25             183U
+#define SC_R_MATCH_26             184U
+#define SC_R_MATCH_27             185U
+#define SC_R_MATCH_28             186U
+#define SC_R_LCD_0                187U
+#define SC_R_LCD_0_PWM_0          188U
+#define SC_R_LCD_0_I2C_0          189U
+#define SC_R_LCD_0_I2C_1          190U
+#define SC_R_PWM_0                191U
+#define SC_R_PWM_1                192U
+#define SC_R_PWM_2                193U
+#define SC_R_PWM_3                194U
+#define SC_R_PWM_4                195U
+#define SC_R_PWM_5                196U
+#define SC_R_PWM_6                197U
+#define SC_R_PWM_7                198U
+#define SC_R_GPIO_0               199U
+#define SC_R_GPIO_1               200U
+#define SC_R_GPIO_2               201U
+#define SC_R_GPIO_3               202U
+#define SC_R_GPIO_4               203U
+#define SC_R_GPIO_5               204U
+#define SC_R_GPIO_6               205U
+#define SC_R_GPIO_7               206U
+#define SC_R_GPT_0                207U
+#define SC_R_GPT_1                208U
+#define SC_R_GPT_2                209U
+#define SC_R_GPT_3                210U
+#define SC_R_GPT_4                211U
+#define SC_R_KPP                  212U
+#define SC_R_MU_0A                213U
+#define SC_R_MU_1A                214U
+#define SC_R_MU_2A                215U
+#define SC_R_MU_3A                216U
+#define SC_R_MU_4A                217U
+#define SC_R_MU_5A                218U
+#define SC_R_MU_6A                219U
+#define SC_R_MU_7A                220U
+#define SC_R_MU_8A                221U
+#define SC_R_MU_9A                222U
+#define SC_R_MU_10A               223U
+#define SC_R_MU_11A               224U
+#define SC_R_MU_12A               225U
+#define SC_R_MU_13A               226U
+#define SC_R_MU_5B                227U
+#define SC_R_MU_6B                228U
+#define SC_R_MU_7B                229U
+#define SC_R_MU_8B                230U
+#define SC_R_MU_9B                231U
+#define SC_R_MU_10B               232U
+#define SC_R_MU_11B               233U
+#define SC_R_MU_12B               234U
+#define SC_R_MU_13B               235U
+#define SC_R_ROM_0                236U
+#define SC_R_FSPI_0               237U
+#define SC_R_FSPI_1               238U
+#define SC_R_IEE                  239U
+#define SC_R_IEE_R0               240U
+#define SC_R_IEE_R1               241U
+#define SC_R_IEE_R2               242U
+#define SC_R_IEE_R3               243U
+#define SC_R_IEE_R4               244U
+#define SC_R_IEE_R5               245U
+#define SC_R_IEE_R6               246U
+#define SC_R_IEE_R7               247U
+#define SC_R_SDHC_0               248U
+#define SC_R_SDHC_1               249U
+#define SC_R_SDHC_2               250U
+#define SC_R_ENET_0               251U
+#define SC_R_ENET_1               252U
+#define SC_R_MLB_0                253U
+#define SC_R_DMA_2_CH0            254U
+#define SC_R_DMA_2_CH1            255U
+#define SC_R_DMA_2_CH2            256U
+#define SC_R_DMA_2_CH3            257U
+#define SC_R_DMA_2_CH4            258U
+#define SC_R_USB_0                259U
+#define SC_R_USB_1                260U
+#define SC_R_USB_0_PHY            261U
+#define SC_R_USB_2                262U
+#define SC_R_USB_2_PHY            263U
+#define SC_R_DTCP                 264U
+#define SC_R_NAND                 265U
+#define SC_R_LVDS_0               266U
+#define SC_R_LVDS_0_PWM_0         267U
+#define SC_R_LVDS_0_I2C_0         268U
+#define SC_R_LVDS_0_I2C_1         269U
+#define SC_R_LVDS_1               270U
+#define SC_R_LVDS_1_PWM_0         271U
+#define SC_R_LVDS_1_I2C_0         272U
+#define SC_R_LVDS_1_I2C_1         273U
+#define SC_R_LVDS_2               274U
+#define SC_R_LVDS_2_PWM_0         275U
+#define SC_R_LVDS_2_I2C_0         276U
+#define SC_R_LVDS_2_I2C_1         277U
+#define SC_R_M4_0_PID0            278U
+#define SC_R_M4_0_PID1            279U
+#define SC_R_M4_0_PID2            280U
+#define SC_R_M4_0_PID3            281U
+#define SC_R_M4_0_PID4            282U
+#define SC_R_M4_0_RGPIO           283U
+#define SC_R_M4_0_SEMA42          284U
+#define SC_R_M4_0_TPM             285U
+#define SC_R_M4_0_PIT             286U
+#define SC_R_M4_0_UART            287U
+#define SC_R_M4_0_I2C             288U
+#define SC_R_M4_0_INTMUX          289U
+#define SC_R_M4_0_SIM             290U
+#define SC_R_M4_0_WDOG            291U
+#define SC_R_M4_0_MU_0B           292U
+#define SC_R_M4_0_MU_0A0          293U
+#define SC_R_M4_0_MU_0A1          294U
+#define SC_R_M4_0_MU_0A2          295U
+#define SC_R_M4_0_MU_0A3          296U
+#define SC_R_M4_0_MU_1A           297U
+#define SC_R_M4_1_PID0            298U
+#define SC_R_M4_1_PID1            299U
+#define SC_R_M4_1_PID2            300U
+#define SC_R_M4_1_PID3            301U
+#define SC_R_M4_1_PID4            302U
+#define SC_R_M4_1_RGPIO           303U
+#define SC_R_M4_1_SEMA42          304U
+#define SC_R_M4_1_TPM             305U
+#define SC_R_M4_1_PIT             306U
+#define SC_R_M4_1_UART            307U
+#define SC_R_M4_1_I2C             308U
+#define SC_R_M4_1_INTMUX          309U
+#define SC_R_M4_1_SIM             310U
+#define SC_R_M4_1_WDOG            311U
+#define SC_R_M4_1_MU_0B           312U
+#define SC_R_M4_1_MU_0A0          313U
+#define SC_R_M4_1_MU_0A1          314U
+#define SC_R_M4_1_MU_0A2          315U
+#define SC_R_M4_1_MU_0A3          316U
+#define SC_R_M4_1_MU_1A           317U
+#define SC_R_SAI_0                318U
+#define SC_R_SAI_1                319U
+#define SC_R_SAI_2                320U
+#define SC_R_IRQSTR_SCU2          321U
+#define SC_R_IRQSTR_DSP           322U
+#define SC_R_UNUSED5              323U
+#define SC_R_OCRAM                324U
+#define SC_R_AUDIO_PLL_0          325U
+#define SC_R_PI_0                 326U
+#define SC_R_PI_0_PWM_0           327U
+#define SC_R_PI_0_PWM_1           328U
+#define SC_R_PI_0_I2C_0           329U
+#define SC_R_PI_0_PLL             330U
+#define SC_R_PI_1                 331U
+#define SC_R_PI_1_PWM_0           332U
+#define SC_R_PI_1_PWM_1           333U
+#define SC_R_PI_1_I2C_0           334U
+#define SC_R_PI_1_PLL             335U
+#define SC_R_SC_PID0              336U
+#define SC_R_SC_PID1              337U
+#define SC_R_SC_PID2              338U
+#define SC_R_SC_PID3              339U
+#define SC_R_SC_PID4              340U
+#define SC_R_SC_SEMA42            341U
+#define SC_R_SC_TPM               342U
+#define SC_R_SC_PIT               343U
+#define SC_R_SC_UART              344U
+#define SC_R_SC_I2C               345U
+#define SC_R_SC_MU_0B             346U
+#define SC_R_SC_MU_0A0            347U
+#define SC_R_SC_MU_0A1            348U
+#define SC_R_SC_MU_0A2            349U
+#define SC_R_SC_MU_0A3            350U
+#define SC_R_SC_MU_1A             351U
+#define SC_R_SYSCNT_RD            352U
+#define SC_R_SYSCNT_CMP           353U
+#define SC_R_DEBUG                354U
+#define SC_R_SYSTEM               355U
+#define SC_R_SNVS                 356U
+#define SC_R_OTP                  357U
+#define SC_R_VPU_PID0             358U
+#define SC_R_VPU_PID1             359U
+#define SC_R_VPU_PID2             360U
+#define SC_R_VPU_PID3             361U
+#define SC_R_VPU_PID4             362U
+#define SC_R_VPU_PID5             363U
+#define SC_R_VPU_PID6             364U
+#define SC_R_VPU_PID7             365U
+#define SC_R_VPU_UART             366U
+#define SC_R_VPUCORE              367U
+#define SC_R_VPUCORE_0            368U
+#define SC_R_VPUCORE_1            369U
+#define SC_R_VPUCORE_2            370U
+#define SC_R_VPUCORE_3            371U
+#define SC_R_DMA_4_CH0            372U
+#define SC_R_DMA_4_CH1            373U
+#define SC_R_DMA_4_CH2            374U
+#define SC_R_DMA_4_CH3            375U
+#define SC_R_DMA_4_CH4            376U
+#define SC_R_ISI_CH0              377U
+#define SC_R_ISI_CH1              378U
+#define SC_R_ISI_CH2              379U
+#define SC_R_ISI_CH3              380U
+#define SC_R_ISI_CH4              381U
+#define SC_R_ISI_CH5              382U
+#define SC_R_ISI_CH6              383U
+#define SC_R_ISI_CH7              384U
+#define SC_R_MJPEG_DEC_S0         385U
+#define SC_R_MJPEG_DEC_S1         386U
+#define SC_R_MJPEG_DEC_S2         387U
+#define SC_R_MJPEG_DEC_S3         388U
+#define SC_R_MJPEG_ENC_S0         389U
+#define SC_R_MJPEG_ENC_S1         390U
+#define SC_R_MJPEG_ENC_S2         391U
+#define SC_R_MJPEG_ENC_S3         392U
+#define SC_R_MIPI_0               393U
+#define SC_R_MIPI_0_PWM_0         394U
+#define SC_R_MIPI_0_I2C_0         395U
+#define SC_R_MIPI_0_I2C_1         396U
+#define SC_R_MIPI_1               397U
+#define SC_R_MIPI_1_PWM_0         398U
+#define SC_R_MIPI_1_I2C_0         399U
+#define SC_R_MIPI_1_I2C_1         400U
+#define SC_R_CSI_0                401U
+#define SC_R_CSI_0_PWM_0          402U
+#define SC_R_CSI_0_I2C_0          403U
+#define SC_R_CSI_1                404U
+#define SC_R_CSI_1_PWM_0          405U
+#define SC_R_CSI_1_I2C_0          406U
+#define SC_R_HDMI                 407U
+#define SC_R_HDMI_I2S             408U
+#define SC_R_HDMI_I2C_0           409U
+#define SC_R_HDMI_PLL_0           410U
+#define SC_R_HDMI_RX              411U
+#define SC_R_HDMI_RX_BYPASS       412U
+#define SC_R_HDMI_RX_I2C_0        413U
+#define SC_R_ASRC_0               414U
+#define SC_R_ESAI_0               415U
+#define SC_R_SPDIF_0              416U
+#define SC_R_SPDIF_1              417U
+#define SC_R_SAI_3                418U
+#define SC_R_SAI_4                419U
+#define SC_R_SAI_5                420U
+#define SC_R_GPT_5                421U
+#define SC_R_GPT_6                422U
+#define SC_R_GPT_7                423U
+#define SC_R_GPT_8                424U
+#define SC_R_GPT_9                425U
+#define SC_R_GPT_10               426U
+#define SC_R_DMA_2_CH5            427U
+#define SC_R_DMA_2_CH6            428U
+#define SC_R_DMA_2_CH7            429U
+#define SC_R_DMA_2_CH8            430U
+#define SC_R_DMA_2_CH9            431U
+#define SC_R_DMA_2_CH10           432U
+#define SC_R_DMA_2_CH11           433U
+#define SC_R_DMA_2_CH12           434U
+#define SC_R_DMA_2_CH13           435U
+#define SC_R_DMA_2_CH14           436U
+#define SC_R_DMA_2_CH15           437U
+#define SC_R_DMA_2_CH16           438U
+#define SC_R_DMA_2_CH17           439U
+#define SC_R_DMA_2_CH18           440U
+#define SC_R_DMA_2_CH19           441U
+#define SC_R_DMA_2_CH20           442U
+#define SC_R_DMA_2_CH21           443U
+#define SC_R_DMA_2_CH22           444U
+#define SC_R_DMA_2_CH23           445U
+#define SC_R_DMA_2_CH24           446U
+#define SC_R_DMA_2_CH25           447U
+#define SC_R_DMA_2_CH26           448U
+#define SC_R_DMA_2_CH27           449U
+#define SC_R_DMA_2_CH28           450U
+#define SC_R_DMA_2_CH29           451U
+#define SC_R_DMA_2_CH30           452U
+#define SC_R_DMA_2_CH31           453U
+#define SC_R_ASRC_1               454U
+#define SC_R_ESAI_1               455U
+#define SC_R_SAI_6                456U
+#define SC_R_SAI_7                457U
+#define SC_R_AMIX                 458U
+#define SC_R_MQS_0                459U
+#define SC_R_DMA_3_CH0            460U
+#define SC_R_DMA_3_CH1            461U
+#define SC_R_DMA_3_CH2            462U
+#define SC_R_DMA_3_CH3            463U
+#define SC_R_DMA_3_CH4            464U
+#define SC_R_DMA_3_CH5            465U
+#define SC_R_DMA_3_CH6            466U
+#define SC_R_DMA_3_CH7            467U
+#define SC_R_DMA_3_CH8            468U
+#define SC_R_DMA_3_CH9            469U
+#define SC_R_DMA_3_CH10           470U
+#define SC_R_DMA_3_CH11           471U
+#define SC_R_DMA_3_CH12           472U
+#define SC_R_DMA_3_CH13           473U
+#define SC_R_DMA_3_CH14           474U
+#define SC_R_DMA_3_CH15           475U
+#define SC_R_DMA_3_CH16           476U
+#define SC_R_DMA_3_CH17           477U
+#define SC_R_DMA_3_CH18           478U
+#define SC_R_DMA_3_CH19           479U
+#define SC_R_DMA_3_CH20           480U
+#define SC_R_DMA_3_CH21           481U
+#define SC_R_DMA_3_CH22           482U
+#define SC_R_DMA_3_CH23           483U
+#define SC_R_DMA_3_CH24           484U
+#define SC_R_DMA_3_CH25           485U
+#define SC_R_DMA_3_CH26           486U
+#define SC_R_DMA_3_CH27           487U
+#define SC_R_DMA_3_CH28           488U
+#define SC_R_DMA_3_CH29           489U
+#define SC_R_DMA_3_CH30           490U
+#define SC_R_DMA_3_CH31           491U
+#define SC_R_AUDIO_PLL_1          492U
+#define SC_R_AUDIO_CLK_0          493U
+#define SC_R_AUDIO_CLK_1          494U
+#define SC_R_MCLK_OUT_0           495U
+#define SC_R_MCLK_OUT_1           496U
+#define SC_R_PMIC_0               497U
+#define SC_R_PMIC_1               498U
+#define SC_R_SECO                 499U
+#define SC_R_CAAM_JR1             500U
+#define SC_R_CAAM_JR2             501U
+#define SC_R_CAAM_JR3             502U
+#define SC_R_SECO_MU_2            503U
+#define SC_R_SECO_MU_3            504U
+#define SC_R_SECO_MU_4            505U
+#define SC_R_HDMI_RX_PWM_0        506U
+#define SC_R_A35                  507U
+#define SC_R_A35_0                508U
+#define SC_R_A35_1                509U
+#define SC_R_A35_2                510U
+#define SC_R_A35_3                511U
+#define SC_R_DSP                  512U
+#define SC_R_DSP_RAM              513U
+#define SC_R_CAAM_JR1_OUT         514U
+#define SC_R_CAAM_JR2_OUT         515U
+#define SC_R_CAAM_JR3_OUT         516U
+#define SC_R_VPU_DEC_0            517U
+#define SC_R_VPU_ENC_0            518U
+#define SC_R_CAAM_JR0             519U
+#define SC_R_CAAM_JR0_OUT         520U
+#define SC_R_PMIC_2               521U
+#define SC_R_DBLOGIC              522U
+#define SC_R_HDMI_PLL_1           523U
+#define SC_R_BOARD_R0             524U
+#define SC_R_BOARD_R1             525U
+#define SC_R_BOARD_R2             526U
+#define SC_R_BOARD_R3             527U
+#define SC_R_BOARD_R4             528U
+#define SC_R_BOARD_R5             529U
+#define SC_R_BOARD_R6             530U
+#define SC_R_BOARD_R7             531U
+#define SC_R_MJPEG_DEC_MP         532U
+#define SC_R_MJPEG_ENC_MP         533U
+#define SC_R_VPU_TS_0             534U
+#define SC_R_VPU_MU_0             535U
+#define SC_R_VPU_MU_1             536U
+#define SC_R_VPU_MU_2             537U
+#define SC_R_VPU_MU_3             538U
+#define SC_R_VPU_ENC_1            539U
+#define SC_R_VPU                  540U
+#define SC_R_LAST                 541U
+#define SC_R_ALL                  ((sc_rsrc_t) UINT16_MAX)	/* All resources */
+/*@}*/
+
+/* NOTE - please add by replacing some of the UNUSED from above! */
+
+/*!
+ * Defnes for sc_ctrl_t.
+ */
+#define SC_C_TEMP                       0U
+#define SC_C_TEMP_HI                    1U
+#define SC_C_TEMP_LOW                   2U
+#define SC_C_PXL_LINK_MST1_ADDR         3U
+#define SC_C_PXL_LINK_MST2_ADDR         4U
+#define SC_C_PXL_LINK_MST_ENB           5U
+#define SC_C_PXL_LINK_MST1_ENB          6U
+#define SC_C_PXL_LINK_MST2_ENB          7U
+#define SC_C_PXL_LINK_SLV1_ADDR         8U
+#define SC_C_PXL_LINK_SLV2_ADDR         9U
+#define SC_C_PXL_LINK_MST_VLD           10U
+#define SC_C_PXL_LINK_MST1_VLD          11U
+#define SC_C_PXL_LINK_MST2_VLD          12U
+#define SC_C_SINGLE_MODE                13U
+#define SC_C_ID                         14U
+#define SC_C_PXL_CLK_POLARITY           15U
+#define SC_C_LINESTATE                  16U
+#define SC_C_PCIE_G_RST                 17U
+#define SC_C_PCIE_BUTTON_RST            18U
+#define SC_C_PCIE_PERST                 19U
+#define SC_C_PHY_RESET                  20U
+#define SC_C_PXL_LINK_RATE_CORRECTION   21U
+#define SC_C_PANIC                      22U
+#define SC_C_PRIORITY_GROUP             23U
+#define SC_C_TXCLK                      24U
+#define SC_C_CLKDIV                     25U
+#define SC_C_DISABLE_50                 26U
+#define SC_C_DISABLE_125                27U
+#define SC_C_SEL_125                    28U
+#define SC_C_MODE                       29U
+#define SC_C_SYNC_CTRL0                 30U
+#define SC_C_KACHUNK_CNT                31U
+#define SC_C_KACHUNK_SEL                32U
+#define SC_C_SYNC_CTRL1                 33U
+#define SC_C_DPI_RESET                  34U
+#define SC_C_MIPI_RESET                 35U
+#define SC_C_DUAL_MODE                  36U
+#define SC_C_VOLTAGE                    37U
+#define SC_C_PXL_LINK_SEL               38U
+#define SC_C_OFS_SEL                    39U
+#define SC_C_OFS_AUDIO                  40U
+#define SC_C_OFS_PERIPH                 41U
+#define SC_C_OFS_IRQ                    42U
+#define SC_C_RST0                       43U
+#define SC_C_RST1                       44U
+#define SC_C_SEL0                       45U
+#define SC_C_LAST                       46U
+
+#define SC_P_ALL        ((sc_pad_t) UINT16_MAX)	/* All pads */
+
+/* Types */
+
+/*!
+ * This type is used to store a boolean
+ */
+typedef uint8_t sc_bool_t;
+
+/*!
+ * This type is used to store a system (full-size) address.
+ */
+typedef uint64_t sc_faddr_t;
+
+/*!
+ * This type is used to indicate error response for most functions.
+ */
+typedef uint8_t sc_err_t;
+
+/*!
+ * This type is used to indicate a resource. Resources include peripherals
+ * and bus masters (but not memory regions). Note items from list should
+ * never be changed or removed (only added to at the end of the list).
+ */
+typedef uint16_t sc_rsrc_t;
+
+/*!
+ * This type is used to indicate a control.
+ */
+typedef uint8_t sc_ctrl_t;
+
+/*!
+ * This type is used to indicate a pad. Valid values are SoC specific.
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+typedef uint16_t sc_pad_t;
+
+/* Extra documentation of standard types */
+
+#ifdef DOXYGEN
+    /*!
+     * Type used to declare an 8-bit integer.
+     */
+typedef __INT8_TYPE__ int8_t;
+
+    /*!
+     * Type used to declare a 16-bit integer.
+     */
+typedef __INT16_TYPE__ int16_t;
+
+    /*!
+     * Type used to declare a 32-bit integer.
+     */
+typedef __INT32_TYPE__ int32_t;
+
+    /*!
+     * Type used to declare a 64-bit integer.
+     */
+typedef __INT64_TYPE__ int64_t;
+
+    /*!
+     * Type used to declare an 8-bit unsigned integer.
+     */
+typedef __UINT8_TYPE__ uint8_t;
+
+    /*!
+     * Type used to declare a 16-bit unsigned integer.
+     */
+typedef __UINT16_TYPE__ uint16_t;
+
+    /*!
+     * Type used to declare a 32-bit unsigned integer.
+     */
+typedef __UINT32_TYPE__ uint32_t;
+
+    /*!
+     * Type used to declare a 64-bit unsigned integer.
+     */
+typedef __UINT64_TYPE__ uint64_t;
+#endif
+
+#endif /* SCI_TYPES_H */
diff --git a/plat/imx/common/include/sci/svc/misc/sci_misc_api.h b/plat/imx/common/include/sci/svc/misc/sci_misc_api.h
new file mode 100644
index 0000000..d9dd49d
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/misc/sci_misc_api.h
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file containing the public API for the System Controller (SC)
+ * Miscellaneous (MISC) function.
+ *
+ * @addtogroup MISC_SVC (SVC) Miscellaneous Service
+ *
+ * Module for the Miscellaneous (MISC) service.
+ *
+ * @{
+ */
+
+#ifndef SC_MISC_API_H
+#define SC_MISC_API_H
+
+/* Includes */
+
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/sci_types.h>
+
+/* Defines */
+
+/*!
+ * @name Defines for type widths
+ */
+/*@{*/
+#define SC_MISC_DMA_GRP_W       5U	/* Width of sc_misc_dma_group_t */
+/*@}*/
+
+/*! Max DMA channel priority group */
+#define SC_MISC_DMA_GRP_MAX     31U
+
+/*!
+ * @name Defines for sc_misc_boot_status_t
+ */
+/*@{*/
+#define SC_MISC_BOOT_STATUS_SUCCESS     0U	/* Success */
+#define SC_MISC_BOOT_STATUS_SECURITY    1U	/* Security violation */
+/*@}*/
+
+/*!
+ * @name Defines for sc_misc_seco_auth_cmd_t
+ */
+/*@{*/
+#define SC_MISC_SECO_AUTH_SECO_FW       0U	/* SECO Firmware */
+#define SC_MISC_SECO_AUTH_HDMI_TX_FW    1U	/* HDMI TX Firmware */
+#define SC_MISC_SECO_AUTH_HDMI_RX_FW    2U	/* HDMI RX Firmware */
+/*@}*/
+
+/*!
+ * @name Defines for sc_misc_temp_t
+ */
+/*@{*/
+#define SC_MISC_TEMP                    0U	/* Temp sensor */
+#define SC_MISC_TEMP_HIGH               1U	/* Temp high alarm */
+#define SC_MISC_TEMP_LOW                2U	/* Temp low alarm */
+/*@}*/
+
+/*!
+ * @name Defines for sc_misc_seco_auth_cmd_t
+ */
+/*@{*/
+#define SC_MISC_AUTH_CONTAINER          0U	/* Authenticate container */
+#define SC_MISC_VERIFY_IMAGE            1U	/* Verify image */
+#define SC_MISC_REL_CONTAINER           2U	/* Release container */
+/*@}*/
+
+/* Types */
+
+/*!
+ * This type is used to store a DMA channel priority group.
+ */
+typedef uint8_t sc_misc_dma_group_t;
+
+/*!
+ * This type is used report boot status.
+ */
+typedef uint8_t sc_misc_boot_status_t;
+
+/*!
+ * This type is used to issue SECO authenticate commands.
+ */
+typedef uint8_t sc_misc_seco_auth_cmd_t;
+
+/*!
+ * This type is used report boot status.
+ */
+typedef uint8_t sc_misc_temp_t;
+
+/* Functions */
+
+/*!
+ * @name Control Functions
+ * @{
+ */
+
+/*!
+ * This function sets a miscellaneous control value.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource the control is associated with
+ * @param[in]     ctrl        control to change
+ * @param[in]     val         value to apply to the control
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent
+ *   of the owner
+ *
+ * Refer to the [Control List](@ref CONTROLS) for valid control values.
+ */
+sc_err_t sc_misc_set_control(sc_ipc_t ipc, sc_rsrc_t resource,
+			     sc_ctrl_t ctrl, uint32_t val);
+
+/*!
+ * This function gets a miscellaneous control value.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource the control is associated with
+ * @param[in]     ctrl        control to get
+ * @param[out]    val         pointer to return the control value
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent
+ *   of the owner
+ *
+ * Refer to the [Control List](@ref CONTROLS) for valid control values.
+ */
+sc_err_t sc_misc_get_control(sc_ipc_t ipc, sc_rsrc_t resource,
+			     sc_ctrl_t ctrl, uint32_t *val);
+
+/* @} */
+
+/*!
+ * @name DMA Functions
+ * @{
+ */
+
+/*!
+ * This function configures the max DMA channel priority group for a
+ * partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to assign \a max
+ * @param[in]     max         max priority group (0-31)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent
+ *   of the affected partition
+ *
+ * Valid \a max range is 0-31 with 0 being the lowest and 31 the highest.
+ * Default is the max priority group for the parent partition of \a pt.
+ */
+sc_err_t sc_misc_set_max_dma_group(sc_ipc_t ipc, sc_rm_pt_t pt,
+				   sc_misc_dma_group_t max);
+
+/*!
+ * This function configures the priority group for a DMA channel.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    DMA channel resource
+ * @param[in]     group       priority group (0-31)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the owner or parent
+ *   of the owner of the DMA channel
+ *
+ * Valid \a group range is 0-31 with 0 being the lowest and 31 the highest.
+ * The max value of \a group is limited by the partition max set using
+ * sc_misc_set_max_dma_group().
+ */
+sc_err_t sc_misc_set_dma_group(sc_ipc_t ipc, sc_rsrc_t resource,
+			       sc_misc_dma_group_t group);
+
+/* @} */
+
+/*!
+ * @name Security Functions
+ * @{
+ */
+
+/*!
+ * This function loads a SECO image.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     addr_src    address of image source
+ * @param[in]     addr_dst    address of image destination
+ * @param[in]     len         length of image to load
+ * @param[in]     fw          SC_TRUE = firmware load
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_PARM if word fuse index param out of range or invalid
+ * - SC_ERR_UNAVAILABLE if SECO not available
+ *
+ * This is used to load images via the SECO. Examples include SECO
+ * Firmware and IVT/CSF data used for authentication. These are usually
+ * loaded into SECO TCM. \a addr_src is in secure memory.
+ *
+ * See the Security Reference Manual (SRM) for more info.
+ */
+sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, sc_faddr_t addr_src,
+				 sc_faddr_t addr_dst, uint32_t len,
+				 sc_bool_t fw);
+
+/*!
+ * This function is used to authenticate a SECO image or command.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     cmd         authenticate command
+ * @param[in]     addr        address of/or metadata
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_PARM if word fuse index param out of range or invalid
+ * - SC_ERR_UNAVAILABLE if SECO not available
+ *
+ * This is used to authenticate a SECO image or issue a security
+ * command. \a addr often points to an container. It is also
+ * just data (or even unused) for some commands.
+ *
+ * See the Security Reference Manual (SRM) for more info.
+ */
+sc_err_t sc_misc_seco_authenticate(sc_ipc_t ipc,
+				   sc_misc_seco_auth_cmd_t cmd,
+				   sc_faddr_t addr);
+
+/*!
+ * This function securely writes a group of fuse words.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     addr        address of message block
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_UNAVAILABLE if SECO not available
+ *
+ * Note \a addr must be a pointer to a signed message block.
+ *
+ * See the Security Reference Manual (SRM) for more info.
+ */
+sc_err_t sc_misc_seco_fuse_write(sc_ipc_t ipc, sc_faddr_t addr);
+
+/*!
+ * This function securely enables debug.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     addr        address of message block
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_UNAVAILABLE if SECO not available
+ *
+ * Note \a addr must be a pointer to a signed message block.
+ *
+ * See the Security Reference Manual (SRM) for more info.
+ */
+sc_err_t sc_misc_seco_enable_debug(sc_ipc_t ipc, sc_faddr_t addr);
+
+/*!
+ * This function updates the lifecycle of the device.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     lifecycle   new lifecycle
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_UNAVAILABLE if SECO not available
+ *
+ * This message is used for going from Open to NXP Closed to OEM Closed.
+ *
+ * See the Security Reference Manual (SRM) for more info.
+ */
+sc_err_t sc_misc_seco_forward_lifecycle(sc_ipc_t ipc, uint32_t lifecycle);
+
+/*!
+ * This function updates the lifecycle to one of the return lifecycles.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     addr        address of message block
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_UNAVAILABLE if SECO not available
+ *
+ * Note \a addr must be a pointer to a signed message block.
+ *
+ * To switch back to NXP states (Full Field Return), message must be signed
+ * by NXP SRK. For OEM States (Partial Field Return), must be signed by OEM
+ * SRK.
+ *
+ * See the Security Reference Manual (SRM) for more info.
+ */
+sc_err_t sc_misc_seco_return_lifecycle(sc_ipc_t ipc, sc_faddr_t addr);
+
+/*!
+ * This function is used to return the SECO FW build info.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    version     pointer to return build number
+ * @param[out]    commit      pointer to return commit ID (git SHA-1)
+ */
+void sc_misc_seco_build_info(sc_ipc_t ipc, uint32_t *version, uint32_t *commit);
+
+/*!
+ * This function is used to return SECO chip info.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    lc          pointer to return lifecycle
+ * @param[out]    monotonic   pointer to return monotonic counter
+ * @param[out]    uid_l       pointer to return UID (lower 32 bits)
+ * @param[out]    uid_h       pointer to return UID (upper 32 bits)
+ */
+sc_err_t sc_misc_seco_chip_info(sc_ipc_t ipc, uint16_t *lc,
+				uint16_t *monotonic, uint32_t *uid_l,
+				uint32_t *uid_h);
+
+/* @} */
+
+/*!
+ * @name Debug Functions
+ * @{
+ */
+
+/*!
+ * This function is used output a debug character from the SCU UART.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     ch          character to output
+ */
+void sc_misc_debug_out(sc_ipc_t ipc, uint8_t ch);
+
+/*!
+ * This function starts/stops emulation waveform capture.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     enable      flag to enable/disable capture
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_UNAVAILABLE if not running on emulation
+ */
+sc_err_t sc_misc_waveform_capture(sc_ipc_t ipc, sc_bool_t enable);
+
+/*!
+ * This function is used to return the SCFW build info.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    build       pointer to return build number
+ * @param[out]    commit      pointer to return commit ID (git SHA-1)
+ */
+void sc_misc_build_info(sc_ipc_t ipc, uint32_t *build, uint32_t *commit);
+
+/*!
+ * This function is used to return the device's unique ID.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    id_l        pointer to return lower 32-bit of ID [31:0]
+ * @param[out]    id_h        pointer to return upper 32-bits of ID [63:32]
+ */
+void sc_misc_unique_id(sc_ipc_t ipc, uint32_t *id_l, uint32_t *id_h);
+
+/* @} */
+
+/*!
+ * @name Other Functions
+ * @{
+ */
+
+/*!
+ * This function configures the ARI match value for PCIe/SATA resources.
+ *
+ * @param[in]     ipc          IPC handle
+ * @param[in]     resource     match resource
+ * @param[in]     resource_mst PCIe/SATA master to match
+ * @param[in]     ari          ARI to match
+ * @param[in]     enable       enable match or not
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the owner or parent
+ *   of the owner of the resource and translation
+ *
+ * For PCIe, the ARI is the 16-bit value that includes the bus number,
+ * device number, and function number. For SATA, this value includes the
+ * FISType and PM_Port.
+ */
+sc_err_t sc_misc_set_ari(sc_ipc_t ipc, sc_rsrc_t resource,
+			 sc_rsrc_t resource_mst, uint16_t ari,
+			 sc_bool_t enable);
+
+/*!
+ * This function reports boot status.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     status      boot status
+ *
+ * This is used by SW partitions to report status of boot. This is
+ * normally used to report a boot failure.
+ */
+void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status);
+
+/*!
+ * This function tells the SCFW that a CPU is done booting.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     cpu         CPU that is done booting
+ *
+ * This is called by early booting CPUs to report they are done with
+ * initialization. After starting early CPUs, the SCFW halts the
+ * booting process until they are done. During this time, early
+ * CPUs can call the SCFW with lower latency as the SCFW is idle.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the CPU owner
+ */
+sc_err_t sc_misc_boot_done(sc_ipc_t ipc, sc_rsrc_t cpu);
+
+/*!
+ * This function reads a given fuse word index.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     word        fuse word index
+ * @param[out]    val         fuse read value
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_PARM if word fuse index param out of range or invalid
+ * - SC_ERR_NOACCESS if read operation failed
+ * - SC_ERR_LOCKED if read operation is locked
+ */
+sc_err_t sc_misc_otp_fuse_read(sc_ipc_t ipc, uint32_t word, uint32_t *val);
+
+/*!
+ * This function writes a given fuse word index.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     word        fuse word index
+ * @param[in]     val         fuse write value
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_PARM if word fuse index param out of range or invalid
+ * - SC_ERR_NOACCESS if write operation failed
+ * - SC_ERR_LOCKED if write operation is locked
+ */
+sc_err_t sc_misc_otp_fuse_write(sc_ipc_t ipc, uint32_t word, uint32_t val);
+
+/*!
+ * This function sets a temp sensor alarm.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource with sensor
+ * @param[in]     temp        alarm to set
+ * @param[in]     celsius     whole part of temp to set
+ * @param[in]     tenths      fractional part of temp to set
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * This function will enable the alarm interrupt if the temp requested is
+ * not the min/max temp. This enable automatically clears when the alarm
+ * occurs and this function has to be called again to re-enable.
+ *
+ * Return errors codes:
+ * - SC_ERR_PARM if parameters invalid
+ */
+sc_err_t sc_misc_set_temp(sc_ipc_t ipc, sc_rsrc_t resource,
+			  sc_misc_temp_t temp, int16_t celsius, int8_t tenths);
+
+/*!
+ * This function gets a temp sensor value.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource with sensor
+ * @param[in]     temp        value to get (sensor or alarm)
+ * @param[out]    celsius     whole part of temp to get
+ * @param[out]    tenths      fractional part of temp to get
+ *
+ * @return Returns and error code (SC_ERR_NONE = success).
+ *
+ * Return errors codes:
+ * - SC_ERR_PARM if parameters invalid
+ */
+sc_err_t sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource,
+			  sc_misc_temp_t temp, int16_t *celsius,
+			  int8_t *tenths);
+
+/*!
+ * This function returns the boot device.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    dev         pointer to return boot device
+ */
+void sc_misc_get_boot_dev(sc_ipc_t ipc, sc_rsrc_t *dev);
+
+/*!
+ * This function returns the current status of the ON/OFF button.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    status      pointer to return button status
+ */
+void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status);
+
+/* @} */
+
+#endif				/* SC_MISC_API_H */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/pad/sci_pad_api.h b/plat/imx/common/include/sci/svc/pad/sci_pad_api.h
new file mode 100644
index 0000000..dc23eed
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/pad/sci_pad_api.h
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file containing the public API for the System Controller (SC)
+ * Pad Control (PAD) function.
+ *
+ * @addtogroup PAD_SVC (SVC) Pad Service
+ *
+ * Module for the Pad Control (PAD) service.
+ *
+ * @details
+ *
+ * Pad configuration is managed by SC firmware. The pad configuration
+ * features supported by the SC firmware include:
+ *
+ * - Configuring the mux, input/output connection, and low-power isolation
+     mode.
+ * - Configuring the technology-specific pad setting such as drive strength,
+ *   pullup/pulldown, etc.
+ * - Configuring compensation for pad groups with dual voltage capability.
+ *
+ * Pad functions fall into one of three categories. Generic functions are
+ * common to all SoCs and all process technologies. SoC functions are raw
+ * low-level functions. Technology-specific functions are specific to the
+ * process technology.
+ *
+ * The list of pads is SoC specific.  Refer to the SoC [Pad List](@ref PADS)
+ * for valid pad values. Note that all pads exist on a die but may or
+ * may not be brought out by the specific package.  Mapping of pads to
+ * package pins/balls is documented in the associated Data Sheet. Some pads
+ * may not be brought out because the part (die+package) is defeatured and
+ * some pads may connect to the substrate in the package.
+ *
+ * Some pads (SC_P_COMP_*) that can be specified are not individual pads
+ * but are in fact pad groups. These groups have additional configuration
+ * that can be done using the sc_pad_set_gp_28fdsoi_comp() function. More
+ * info on these can be found in the associated Reference Manual.
+ *
+ * Pads are managed as a resource by the Resource Manager (RM).  They have
+ * assigned owners and only the owners can configure the pads. Some of the
+ * pads are reserved for use by the SCFW itself and this can be overriden
+ * with the implementation of board_config_sc(). Additionally, pads may
+ * be assigned to various other partitions via the implementation of
+ * board_system_config().
+ *
+ * Note muxing two input pads to the same IP functional signal will
+ * result in undefined behavior.
+ * @{
+ */
+
+#ifndef SCI_PAD_API_H
+#define SCI_PAD_API_H
+
+/* Includes */
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+
+/* Defines */
+
+/*!
+ * @name Defines for type widths
+ */
+/*@{*/
+#define SC_PAD_MUX_W            3	/* Width of mux parameter */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pad_config_t
+ */
+/*@{*/
+#define SC_PAD_CONFIG_NORMAL    0U	/* Normal */
+#define SC_PAD_CONFIG_OD        1U	/* Open Drain */
+#define SC_PAD_CONFIG_OD_IN     2U	/* Open Drain and input */
+#define SC_PAD_CONFIG_OUT_IN    3U	/* Output and input */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pad_iso_t
+ */
+/*@{*/
+#define SC_PAD_ISO_OFF          0U	/* ISO latch is transparent */
+#define SC_PAD_ISO_EARLY        1U	/* Follow EARLY_ISO */
+#define SC_PAD_ISO_LATE         2U	/* Follow LATE_ISO */
+#define SC_PAD_ISO_ON           3U	/* ISO latched data is held */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pad_28fdsoi_dse_t
+ */
+/*@{*/
+#define SC_PAD_28FDSOI_DSE_18V_1MA   0U	/* Drive strength of 1mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_2MA   1U	/* Drive strength of 2mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_4MA   2U	/* Drive strength of 4mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_6MA   3U	/* Drive strength of 6mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_8MA   4U	/* Drive strength of 8mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_10MA  5U	/* Drive strength of 10mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_12MA  6U	/* Drive strength of 12mA for 1.8v */
+#define SC_PAD_28FDSOI_DSE_18V_HS    7U	/* High-speed drive strength for 1.8v */
+#define SC_PAD_28FDSOI_DSE_33V_2MA   0U	/* Drive strength of 2mA for 3.3v */
+#define SC_PAD_28FDSOI_DSE_33V_4MA   1U	/* Drive strength of 4mA for 3.3v */
+#define SC_PAD_28FDSOI_DSE_33V_8MA   2U	/* Drive strength of 8mA for 3.3v */
+#define SC_PAD_28FDSOI_DSE_33V_12MA  3U	/* Drive strength of 12mA for 3.3v */
+#define SC_PAD_28FDSOI_DSE_DV_HIGH   0U	/* High drive strength for dual volt */
+#define SC_PAD_28FDSOI_DSE_DV_LOW    1U	/* Low drive strength for dual volt */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pad_28fdsoi_ps_t
+ */
+/*@{*/
+#define SC_PAD_28FDSOI_PS_KEEPER 0U	/* Bus-keeper (only valid for 1.8v) */
+#define SC_PAD_28FDSOI_PS_PU     1U	/* Pull-up */
+#define SC_PAD_28FDSOI_PS_PD     2U	/* Pull-down */
+#define SC_PAD_28FDSOI_PS_NONE   3U	/* No pull (disabled) */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pad_28fdsoi_pus_t
+ */
+/*@{*/
+#define SC_PAD_28FDSOI_PUS_30K_PD  0U	/* 30K pull-down */
+#define SC_PAD_28FDSOI_PUS_100K_PU 1U	/* 100K pull-up */
+#define SC_PAD_28FDSOI_PUS_3K_PU   2U	/* 3K pull-up */
+#define SC_PAD_28FDSOI_PUS_30K_PU  3U	/* 30K pull-up */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pad_wakeup_t
+ */
+/*@{*/
+#define SC_PAD_WAKEUP_OFF       0U	/* Off */
+#define SC_PAD_WAKEUP_CLEAR     1U	/* Clears pending flag */
+#define SC_PAD_WAKEUP_LOW_LVL   4U	/* Low level */
+#define SC_PAD_WAKEUP_FALL_EDGE 5U	/* Falling edge */
+#define SC_PAD_WAKEUP_RISE_EDGE 6U	/* Rising edge */
+#define SC_PAD_WAKEUP_HIGH_LVL  7U	/* High-level */
+/*@}*/
+
+/* Types */
+
+/*!
+ * This type is used to declare a pad config. It determines how the
+ * output data is driven, pull-up is controlled, and input signal is
+ * connected. Normal and OD are typical and only connect the input
+ * when the output is not driven.  The IN options are less common and
+ * force an input connection even when driving the output.
+ */
+typedef uint8_t sc_pad_config_t;
+
+/*!
+ * This type is used to declare a pad low-power isolation config.
+ * ISO_LATE is the most common setting. ISO_EARLY is only used when
+ * an output pad is directly determined by another input pad. The
+ * other two are only used when SW wants to directly contol isolation.
+ */
+typedef uint8_t sc_pad_iso_t;
+
+/*!
+ * This type is used to declare a drive strength. Note it is specific
+ * to 28FDSOI. Also note that valid values depend on the pad type.
+ */
+typedef uint8_t sc_pad_28fdsoi_dse_t;
+
+/*!
+ * This type is used to declare a pull select. Note it is specific
+ * to 28FDSOI.
+ */
+typedef uint8_t sc_pad_28fdsoi_ps_t;
+
+/*!
+ * This type is used to declare a pull-up select. Note it is specific
+ * to 28FDSOI HSIC pads.
+ */
+typedef uint8_t sc_pad_28fdsoi_pus_t;
+
+/*!
+ * This type is used to declare a wakeup mode of a pad.
+ */
+typedef uint8_t sc_pad_wakeup_t;
+
+/* Functions */
+
+/*!
+ * @name Generic Functions
+ * @{
+ */
+
+/*!
+ * This function configures the mux settings for a pad. This includes
+ * the signal mux, pad config, and low-power isolation mode.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     mux         mux setting
+ * @param[in]     config      pad config
+ * @param[in]     iso         low-power isolation mode
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Note muxing two input pads to the same IP functional signal will
+ * result in undefined behavior.
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set_mux(sc_ipc_t ipc, sc_pad_t pad,
+			uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso);
+
+/*!
+ * This function gets the mux settings for a pad. This includes
+ * the signal mux, pad config, and low-power isolation mode.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    mux         pointer to return mux setting
+ * @param[out]    config      pointer to return pad config
+ * @param[out]    iso         pointer to return low-power isolation mode
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_mux(sc_ipc_t ipc, sc_pad_t pad,
+			uint8_t *mux, sc_pad_config_t *config,
+			sc_pad_iso_t *iso);
+
+/*!
+ * This function configures the general purpose pad control. This
+ * is technology dependent and includes things like drive strength,
+ * slew rate, pull up/down, etc. Refer to the SoC Reference Manual
+ * for bit field details.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     ctrl        control value to set
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t ctrl);
+
+/*!
+ * This function gets the general purpose pad control. This
+ * is technology dependent and includes things like drive strength,
+ * slew rate, pull up/down, etc. Refer to the SoC Reference Manual
+ * for bit field details.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    ctrl        pointer to return control value
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t *ctrl);
+
+/*!
+ * This function configures the wakeup mode of the pad.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     wakeup      wakeup to set
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t wakeup);
+
+/*!
+ * This function gets the wakeup mode of a pad.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    wakeup      pointer to return wakeup
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t *wakeup);
+
+/*!
+ * This function configures a pad.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     mux         mux setting
+ * @param[in]     config      pad config
+ * @param[in]     iso         low-power isolation mode
+ * @param[in]     ctrl        control value
+ * @param[in]     wakeup      wakeup to set
+ *
+ * @see sc_pad_set_mux().
+ * @see sc_pad_set_gp().
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Note muxing two input pads to the same IP functional signal will
+ * result in undefined behavior.
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux,
+			sc_pad_config_t config, sc_pad_iso_t iso, uint32_t ctrl,
+			sc_pad_wakeup_t wakeup);
+
+/*!
+ * This function gets a pad's config.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    mux         pointer to return mux setting
+ * @param[out]    config      pointer to return pad config
+ * @param[out]    iso         pointer to return low-power isolation mode
+ * @param[out]    ctrl        pointer to return control value
+ * @param[out]    wakeup      pointer to return wakeup to set
+ *
+ * @see sc_pad_set_mux().
+ * @see sc_pad_set_gp().
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux,
+			sc_pad_config_t *config, sc_pad_iso_t *iso,
+			uint32_t *ctrl, sc_pad_wakeup_t *wakeup);
+
+/* @} */
+
+/*!
+ * @name SoC Specific Functions
+ * @{
+ */
+
+/*!
+ * This function configures the settings for a pad. This setting is SoC
+ * specific.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     val         value to set
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, uint32_t val);
+
+/*!
+ * This function gets the settings for a pad. This setting is SoC
+ * specific.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    val         pointer to return setting
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, uint32_t *val);
+
+/* @} */
+
+/*!
+ * @name Technology Specific Functions
+ * @{
+ */
+
+/*!
+ * This function configures the pad control specific to 28FDSOI.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     dse         drive strength
+ * @param[in]     ps          pull select
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner,
+ * - SC_ERR_UNAVAILABLE if process not applicable
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad,
+			       sc_pad_28fdsoi_dse_t dse,
+			       sc_pad_28fdsoi_ps_t ps);
+
+/*!
+ * This function gets the pad control specific to 28FDSOI.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    dse         pointer to return drive strength
+ * @param[out]    ps          pointer to return pull select
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner,
+ * - SC_ERR_UNAVAILABLE if process not applicable
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad,
+			       sc_pad_28fdsoi_dse_t *dse,
+			       sc_pad_28fdsoi_ps_t *ps);
+
+/*!
+ * This function configures the pad control specific to 28FDSOI.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     dse         drive strength
+ * @param[in]     hys         hysteresis
+ * @param[in]     pus         pull-up select
+ * @param[in]     pke         pull keeper enable
+ * @param[in]     pue         pull-up enable
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner,
+ * - SC_ERR_UNAVAILABLE if process not applicable
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_set_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad,
+				    sc_pad_28fdsoi_dse_t dse, sc_bool_t hys,
+				    sc_pad_28fdsoi_pus_t pus, sc_bool_t pke,
+				    sc_bool_t pue);
+
+/*!
+ * This function gets the pad control specific to 28FDSOI.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    dse         pointer to return drive strength
+ * @param[out]    hys         pointer to return hysteresis
+ * @param[out]    pus         pointer to return pull-up select
+ * @param[out]    pke         pointer to return pull keeper enable
+ * @param[out]    pue         pointer to return pull-up enable
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner,
+ * - SC_ERR_UNAVAILABLE if process not applicable
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad,
+				    sc_pad_28fdsoi_dse_t *dse, sc_bool_t *hys,
+				    sc_pad_28fdsoi_pus_t *pus, sc_bool_t *pke,
+				    sc_bool_t *pue);
+
+/*!
+ * This function configures the compensation control specific to 28FDSOI.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to configure
+ * @param[in]     compen      compensation/freeze mode
+ * @param[in]     fastfrz     fast freeze
+ * @param[in]     rasrcp      compensation code for PMOS
+ * @param[in]     rasrcn      compensation code for NMOS
+ * @param[in]     nasrc_sel   NASRC read select
+ * @param[in]     psw_ovr     2.5v override
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner,
+ * - SC_ERR_UNAVAILABLE if process not applicable
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ *
+ * Note \a psw_ovr is only applicable to pads supporting 2.5 volt
+ * operation (e.g. some Ethernet pads).
+ */
+sc_err_t sc_pad_set_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad,
+				    uint8_t compen, sc_bool_t fastfrz,
+				    uint8_t rasrcp, uint8_t rasrcn,
+				    sc_bool_t nasrc_sel, sc_bool_t psw_ovr);
+
+/*!
+ * This function gets the compensation control specific to 28FDSOI.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to query
+ * @param[out]    compen      pointer to return compensation/freeze mode
+ * @param[out]    fastfrz     pointer to return fast freeze
+ * @param[out]    rasrcp      pointer to return compensation code for PMOS
+ * @param[out]    rasrcn      pointer to return compensation code for NMOS
+ * @param[out]    nasrc_sel   pointer to return NASRC read select
+ * @param[out]    compok      pointer to return compensation status
+ * @param[out]    nasrc       pointer to return NASRCP/NASRCN
+ * @param[out]    psw_ovr     pointer to return the 2.5v override
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner,
+ * - SC_ERR_UNAVAILABLE if process not applicable
+ *
+ * Refer to the SoC [Pad List](@ref PADS) for valid pad values.
+ */
+sc_err_t sc_pad_get_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad,
+				    uint8_t *compen, sc_bool_t *fastfrz,
+				    uint8_t *rasrcp, uint8_t *rasrcn,
+				    sc_bool_t *nasrc_sel, sc_bool_t *compok,
+				    uint8_t *nasrc, sc_bool_t *psw_ovr);
+
+/* @} */
+
+#endif /* SCI_PAD_API_H */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/pm/sci_pm_api.h b/plat/imx/common/include/sci/svc/pm/sci_pm_api.h
new file mode 100644
index 0000000..76ca5c4
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/pm/sci_pm_api.h
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file containing the public API for the System Controller (SC)
+ * Power Management (PM) function. This includes functions for power state
+ * control, clock control, reset control, and wake-up event control.
+ *
+ * @addtogroup PM_SVC (SVC) Power Management Service
+ *
+ * Module for the Power Management (PM) service.
+ *
+ * @{
+ */
+
+#ifndef SCI_PM_API_H
+#define SCI_PM_API_H
+
+/* Includes */
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+
+/* Defines */
+
+/*!
+ * @name Defines for type widths
+ */
+/*@{*/
+#define SC_PM_POWER_MODE_W      2	/* Width of sc_pm_power_mode_t */
+#define SC_PM_CLOCK_MODE_W      3	/* Width of sc_pm_clock_mode_t */
+#define SC_PM_RESET_TYPE_W      2	/* Width of sc_pm_reset_type_t */
+#define SC_PM_RESET_REASON_W    3	/* Width of sc_pm_reset_reason_t */
+/*@}*/
+
+/*!
+ * @name Defines for clock indexes (sc_pm_clk_t)
+ */
+/*@{*/
+/*@}*/
+
+/*!
+ * @name Defines for ALL parameters
+ */
+/*@{*/
+#define SC_PM_CLK_ALL   UINT8_MAX	/* All clocks */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_power_mode_t
+ */
+/*@{*/
+#define SC_PM_PW_MODE_OFF       0U	/* Power off */
+#define SC_PM_PW_MODE_STBY      1U	/* Power in standby */
+#define SC_PM_PW_MODE_LP        2U	/* Power in low-power */
+#define SC_PM_PW_MODE_ON        3U	/* Power on */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_clk_t
+ */
+/*@{*/
+#define SC_PM_CLK_SLV_BUS       0U	/* Slave bus clock */
+#define SC_PM_CLK_MST_BUS       1U	/* Master bus clock */
+#define SC_PM_CLK_PER           2U	/* Peripheral clock */
+#define SC_PM_CLK_PHY           3U	/* Phy clock */
+#define SC_PM_CLK_MISC          4U	/* Misc clock */
+#define SC_PM_CLK_MISC0         0U	/* Misc 0 clock */
+#define SC_PM_CLK_MISC1         1U	/* Misc 1 clock */
+#define SC_PM_CLK_MISC2         2U	/* Misc 2 clock */
+#define SC_PM_CLK_MISC3         3U	/* Misc 3 clock */
+#define SC_PM_CLK_MISC4         4U	/* Misc 4 clock */
+#define SC_PM_CLK_CPU           2U	/* CPU clock */
+#define SC_PM_CLK_PLL           4U	/* PLL */
+#define SC_PM_CLK_BYPASS        4U	/* Bypass clock */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_clk_mode_t
+ */
+/*@{*/
+#define SC_PM_CLK_MODE_ROM_INIT        0U	/* Clock is initialized by ROM. */
+#define SC_PM_CLK_MODE_OFF             1U	/* Clock is disabled */
+#define SC_PM_CLK_MODE_ON              2U	/* Clock is enabled. */
+#define SC_PM_CLK_MODE_AUTOGATE_SW     3U	/* Clock is in SW autogate mode */
+#define SC_PM_CLK_MODE_AUTOGATE_HW     4U	/* Clock is in HW autogate mode */
+#define SC_PM_CLK_MODE_AUTOGATE_SW_HW  5U	/* Clock is in SW-HW autogate mode */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_clk_parent_t
+ */
+/*@{*/
+#define SC_PM_PARENT_XTAL              0U	/* Parent is XTAL. */
+#define SC_PM_PARENT_PLL0              1U	/* Parent is PLL0 */
+#define SC_PM_PARENT_PLL1              2U	/* Parent is PLL1 or PLL0/2 */
+#define SC_PM_PARENT_PLL2              3U	/* Parent in PLL2 or PLL0/4 */
+#define SC_PM_PARENT_BYPS              4U	/* Parent is a bypass clock. */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_reset_type_t
+ */
+/*@{*/
+#define SC_PM_RESET_TYPE_COLD          0U	/* Cold reset */
+#define SC_PM_RESET_TYPE_WARM          1U	/* Warm reset */
+#define SC_PM_RESET_TYPE_BOARD         2U	/* Board reset */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_reset_cause_t
+ */
+/*@{*/
+#define SC_PM_RESET_CAUSE_TEMP         0U	/* Reset due to temp panic alarm */
+#define SC_PM_RESET_CAUSE_FAULT        1U	/* Reset due to fault exception */
+#define SC_PM_RESET_CAUSE_IRQ          2U	/* Reset due to SCU reset IRQ */
+#define SC_PM_RESET_CAUSE_WDOG         3U	/* Reset due to SW WDOG */
+#define SC_PM_RESET_CAUSE_API          4U	/* Reset due to pm_reset() or monitor */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_reset_reason_t
+ */
+/*@{*/
+#define SC_PM_RESET_REASON_POR         0U	/* Power on reset */
+#define SC_PM_RESET_REASON_WARM        1U	/* Warm reset */
+#define SC_PM_RESET_REASON_SW          2U	/* Software reset */
+#define SC_PM_RESET_REASON_WDOG        3U	/* Watchdog reset */
+#define SC_PM_RESET_REASON_LOCKUP      4U	/* Lockup reset */
+#define SC_PM_RESET_REASON_TAMPER      5U	/* Tamper reset */
+#define SC_PM_RESET_REASON_TEMP        6U	/* Temp reset */
+#define SC_PM_RESET_REASON_LOW_VOLT    7U	/* Low voltage reset */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_sys_if_t
+ */
+/*@{*/
+#define SC_PM_SYS_IF_INTERCONNECT       0U	/* System interconnect */
+#define SC_PM_SYS_IF_MU                 1U	/* AP -> SCU message units */
+#define SC_PM_SYS_IF_OCMEM              2U	/* On-chip memory (ROM/OCRAM) */
+#define SC_PM_SYS_IF_DDR                3U	/* DDR memory */
+/*@}*/
+
+/*!
+ * @name Defines for sc_pm_wake_src_t
+ */
+/*@{*/
+#define SC_PM_WAKE_SRC_NONE             0U	/* No wake source, used for self-kill */
+#define SC_PM_WAKE_SRC_SCU              1U	/* Wakeup from SCU to resume CPU (IRQSTEER & GIC powered down) */
+#define SC_PM_WAKE_SRC_IRQSTEER         2U	/* Wakeup from IRQSTEER to resume CPU (GIC powered down) */
+#define SC_PM_WAKE_SRC_IRQSTEER_GIC     3U	/* Wakeup from IRQSTEER+GIC to wake CPU  (GIC clock gated) */
+#define SC_PM_WAKE_SRC_GIC              4U	/* Wakeup from GIC to wake CPU */
+/*@}*/
+
+/* Types */
+
+/*!
+ * This type is used to declare a power mode. Note resources only use
+ * SC_PM_PW_MODE_OFF and SC_PM_PW_MODE_ON. The other modes are used only
+ * as system power modes.
+ */
+typedef uint8_t sc_pm_power_mode_t;
+
+/*!
+ * This type is used to declare a clock.
+ */
+typedef uint8_t sc_pm_clk_t;
+
+/*!
+ * This type is used to declare a clock mode.
+ */
+typedef uint8_t sc_pm_clk_mode_t;
+
+/*!
+ * This type is used to declare the clock parent.
+ */
+typedef uint8_t sc_pm_clk_parent_t;
+
+/*!
+ * This type is used to declare clock rates.
+ */
+typedef uint32_t sc_pm_clock_rate_t;
+
+/*!
+ * This type is used to declare a desired reset type.
+ */
+typedef uint8_t sc_pm_reset_type_t;
+
+/*!
+ * This type is used to declare a desired reset type.
+ */
+typedef uint8_t sc_pm_reset_cause;
+
+/*!
+ * This type is used to declare a reason for a reset.
+ */
+typedef uint8_t sc_pm_reset_reason_t;
+
+/*!
+ * This type is used to specify a system-level interface to be power managed.
+ */
+typedef uint8_t sc_pm_sys_if_t;
+
+/*!
+ * This type is used to specify a wake source for CPU resources.
+ */
+typedef uint8_t sc_pm_wake_src_t;
+
+/* Functions */
+
+/*!
+ * @name Power Functions
+ * @{
+ */
+
+/*!
+ * This function sets the system power mode. Only the owner of the
+ * SC_R_SYSTEM resource can do this.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     mode        power mode to apply
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid mode,
+ * - SC_ERR_NOACCESS if caller not the owner of SC_R_SYSTEM
+ *
+ * @see sc_pm_set_sys_power_mode().
+ */
+sc_err_t sc_pm_set_sys_power_mode(sc_ipc_t ipc, sc_pm_power_mode_t mode);
+
+/*!
+ * This function sets the power mode of a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition
+ * @param[in]     mode        power mode to apply
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid partition or mode,
+ * - SC_ERR_NOACCESS if caller's partition is not the owner or
+ *   parent of \a pt
+ *
+ * The power mode of the partitions is a max power any resource will
+ * be set to. Calling this will result in all resources owned
+ * by \a pt to have their power changed to the lower of \a mode or the
+ * individual resource mode set using sc_pm_set_resource_power_mode().
+ */
+sc_err_t sc_pm_set_partition_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt,
+					sc_pm_power_mode_t mode);
+
+/*!
+ * This function gets the power mode of a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition
+ * @param[out]    mode        pointer to return power mode
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid partition
+ */
+sc_err_t sc_pm_get_sys_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt,
+				  sc_pm_power_mode_t *mode);
+
+/*!
+ * This function sets the power mode of a resource.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     mode        power mode to apply
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or mode,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner
+ *   or parent of the owner
+ *
+ * This function will record the individual resource power mode
+ * and change it if the requested mode is lower than or equal to the
+ * partition power mode set with sc_pm_set_partition_power_mode().
+ * In other words, the power mode of the resource will be the minimum
+ * of the resource power mode and the partition power mode.
+ *
+ * Note some resources are still not accessible even when powered up if bus
+ * transactions go through a fabric not powered up. Examples of this are
+ * resources in display and capture subsystems which require the display
+ * controller or the imaging subsytem to be powered up first.
+ *
+ * Not that resources are grouped into power domains by the underlying
+ * hardware. If any resource in the domain is on, the entire power domain
+ * will be on. Other power domains required to access the resource will
+ * also be turned on. Clocks required to access the peripheral will be
+ * turned on. Refer to the SoC RM for more info on power domains and access
+ * infrastructure (bus fabrics, clock domains, etc.).
+ */
+sc_err_t sc_pm_set_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				       sc_pm_power_mode_t mode);
+
+/*!
+ * This function gets the power mode of a resource.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[out]    mode        pointer to return power mode
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Note only SC_PM_PW_MODE_OFF and SC_PM_PW_MODE_ON are valid. The value
+ * returned does not reflect the power mode of the partition..
+ */
+sc_err_t sc_pm_get_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				       sc_pm_power_mode_t *mode);
+
+/*!
+ * This function requests the low power mode some of the resources
+ * can enter based on their state. This API is only valid for the
+ * following resources : SC_R_A53, SC_R_A53_0, SC_R_A53_1, SC_A53_2,
+ * SC_A53_3, SC_R_A72, SC_R_A72_0, SC_R_A72_1, SC_R_CC1, SC_R_A35,
+ * SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3.
+ * For all other resources it will return SC_ERR_PARAM.
+ * This function will set the low power mode the cores, cluster
+ * and cluster associated resources will enter when all the cores
+ * in a given cluster execute WFI
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     mode        power mode to apply
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ */
+sc_err_t sc_pm_req_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				  sc_pm_power_mode_t mode);
+
+/*!
+ * This function requests low-power mode entry for CPU/cluster
+ * resources. This API is only valid for the following resources:
+ * SC_R_A53, SC_R_A53_x, SC_R_A72, SC_R_A72_x, SC_R_A35, SC_R_A35_x,
+ * SC_R_CCI. For all other resources it will return SC_ERR_PARAM.
+ * For individual core resources, the specified power mode
+ * and wake source will be applied after the core has entered
+ * WFI.  For cluster resources, the specified power mode is
+ * applied after all cores in the cluster have entered low-power mode.
+ * For multicluster resources, the specified power mode is applied
+ * after all clusters have reached low-power mode.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     mode        power mode to apply
+ * @param[in]     wake_src    wake source for low-power exit
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ */
+sc_err_t sc_pm_req_cpu_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				      sc_pm_power_mode_t mode,
+				      sc_pm_wake_src_t wake_src);
+
+/*!
+ * This function is used to set the resume address of a CPU.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the CPU resource
+ * @param[in]     address     64-bit resume address
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or address,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of the
+ *   resource (CPU) owner
+ */
+sc_err_t sc_pm_set_cpu_resume_addr(sc_ipc_t ipc, sc_rsrc_t resource,
+				   sc_faddr_t address);
+
+/*!
+ * This function is used to set parameters for CPU resume from
+ * low-power mode.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the CPU resource
+ * @param[in]     isPrimary   set SC_TRUE if primary wake CPU
+ * @param[in]     address     64-bit resume address
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or address,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of the
+ *   resource (CPU) owner
+ */
+sc_err_t sc_pm_set_cpu_resume(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_bool_t isPrimary, sc_faddr_t address);
+
+/*!
+ * This function requests the power mode configuration for system-level
+ * interfaces including messaging units, interconnect, and memories.  This API
+ * is only valid for the following resources : SC_R_A53, SC_R_A72, and
+ * SC_R_M4_x_PID_y.  For all other resources, it will return SC_ERR_PARAM.
+ * The requested power mode will be captured and applied to system-level
+ * resources as system conditions allow.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     sys_if      system-level interface to be configured
+ * @param[in]     hpm         high-power mode for the system interface
+ * @param[in]     lpm         low-power mode for the system interface
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ */
+sc_err_t sc_pm_req_sys_if_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				     sc_pm_sys_if_t sys_if,
+				     sc_pm_power_mode_t hpm,
+				     sc_pm_power_mode_t lpm);
+
+/* @} */
+
+/*!
+ * @name Clock/PLL Functions
+ * @{
+ */
+
+/*!
+ * This function sets the rate of a resource's clock/PLL.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     clk         clock/PLL to affect
+ * @param[in,out] rate        pointer to rate to set,
+ *                            return actual rate
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or clock/PLL,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner
+ *   or parent of the owner,
+ * - SC_ERR_UNAVAILABLE if clock/PLL not applicable to this resource,
+ * - SC_ERR_LOCKED if rate locked (usually because shared clock/PLL)
+ *
+ * Refer to the [Clock List](@ref CLOCKS) for valid clock/PLL values.
+ */
+sc_err_t sc_pm_set_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_pm_clk_t clk, sc_pm_clock_rate_t *rate);
+
+/*!
+ * This function gets the rate of a resource's clock/PLL.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     clk         clock/PLL to affect
+ * @param[out]    rate        pointer to return rate
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or clock/PLL,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner
+ *   or parent of the owner,
+ * - SC_ERR_UNAVAILABLE if clock/PLL not applicable to this resource
+ *
+ * Refer to the [Clock List](@ref CLOCKS) for valid clock/PLL values.
+ */
+sc_err_t sc_pm_get_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_pm_clk_t clk, sc_pm_clock_rate_t *rate);
+
+/*!
+ * This function enables/disables a resource's clock.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     clk         clock to affect
+ * @param[in]     enable      enable if SC_TRUE; otherwise disabled
+ * @param[in]     autog       HW auto clock gating
+ *
+ * If \a resource is SC_R_ALL then all resources owned will be affected.
+ * No error will be returned.
+ *
+ * If \a clk is SC_PM_CLK_ALL, then an error will be returned if any
+ * of the available clocks returns an error.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or clock,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner
+ *   or parent of the owner,
+ * - SC_ERR_UNAVAILABLE if clock not applicable to this resource
+ *
+ * Refer to the [Clock List](@ref CLOCKS) for valid clock values.
+ */
+sc_err_t sc_pm_clock_enable(sc_ipc_t ipc, sc_rsrc_t resource,
+			    sc_pm_clk_t clk, sc_bool_t enable, sc_bool_t autog);
+
+/*!
+ * This function sets the parent of a resource's clock.
+ * This function should only be called when the clock is disabled.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     clk         clock to affect
+ * @param[in]     parent      New parent of the clock.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or clock,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner
+ *   or parent of the owner,
+ * - SC_ERR_UNAVAILABLE if clock not applicable to this resource
+ * - SC_ERR_BUSY if clock is currently enabled.
+ * - SC_ERR_NOPOWER if resource not powered
+ *
+ * Refer to the [Clock List](@ref CLOCKS) for valid clock values.
+ */
+sc_err_t sc_pm_set_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource,
+				sc_pm_clk_t clk, sc_pm_clk_parent_t parent);
+
+/*!
+ * This function gets the parent of a resource's clock.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the resource
+ * @param[in]     clk         clock to affect
+ * @param[out]     parent     pointer to return parent of clock.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or clock,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner
+ *   or parent of the owner,
+ * - SC_ERR_UNAVAILABLE if clock not applicable to this resource
+ *
+ * Refer to the [Clock List](@ref CLOCKS) for valid clock values.
+ */
+sc_err_t sc_pm_get_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource,
+				sc_pm_clk_t clk, sc_pm_clk_parent_t *parent);
+
+/* @} */
+
+/*!
+ * @name Reset Functions
+ * @{
+ */
+
+/*!
+ * This function is used to reset the system. Only the owner of the
+ * SC_R_SYSTEM resource can do this.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     type        reset type
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid type,
+ * - SC_ERR_NOACCESS if caller not the owner of SC_R_SYSTEM
+ *
+ * If this function returns, then the reset did not occur due to an
+ * invalid parameter.
+ */
+sc_err_t sc_pm_reset(sc_ipc_t ipc, sc_pm_reset_type_t type);
+
+/*!
+ * This function gets a caller's reset reason.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    reason      pointer to return reset reason
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_pm_reset_reason(sc_ipc_t ipc, sc_pm_reset_reason_t *reason);
+
+/*!
+ * This function is used to boot a partition.
+ *
+ * @param[in]     ipc          IPC handle
+ * @param[in]     pt           handle of partition to boot
+ * @param[in]     resource_cpu ID of the CPU resource to start
+ * @param[in]     boot_addr    64-bit boot address
+ * @param[in]     resource_mu  ID of the MU that must be powered
+ * @param[in]     resource_dev ID of the boot device that must be powered
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid partition, resource, or addr,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of the
+ *   partition to boot
+ */
+sc_err_t sc_pm_boot(sc_ipc_t ipc, sc_rm_pt_t pt,
+		    sc_rsrc_t resource_cpu, sc_faddr_t boot_addr,
+		    sc_rsrc_t resource_mu, sc_rsrc_t resource_dev);
+
+/*!
+ * This function is used to reboot the caller's partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     type        reset type
+ *
+ * If \a type is SC_PM_RESET_TYPE_COLD, then most peripherals owned by
+ * the calling partition will be reset if possible. SC state (partitions,
+ * power, clocks, etc.) is reset. The boot SW of the booting CPU must be
+ * able to handle peripherals that that are not reset.
+ *
+ * If \a type is SC_PM_RESET_TYPE_WARM, then only the boot CPU is reset.
+ * SC state (partitions, power, clocks, etc.) are NOT reset. The boot SW
+ * of the booting CPU must be able to handle peripherals and SC state that
+ * that are not reset.
+ *
+ * If \a type is SC_PM_RESET_TYPE_BOARD, then return with no action.
+ *
+ * If this function returns, then the reset did not occur due to an
+ * invalid parameter.
+ */
+void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type);
+
+/*!
+ * This function is used to reboot a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to reboot
+ * @param[in]     type        reset type
+ *
+ * If \a type is SC_PM_RESET_TYPE_COLD, then most peripherals owned by
+ * the calling partition will be reset if possible. SC state (partitions,
+ * power, clocks, etc.) is reset. The boot SW of the booting CPU must be
+ * able to handle peripherals that that are not reset.
+ *
+ * If \a type is SC_PM_RESET_TYPE_WARM, then only the boot CPU is reset.
+ * SC state (partitions, power, clocks, etc.) are NOT reset. The boot SW
+ * of the booting CPU must be able to handle peripherals and SC state that
+ * that are not reset.
+ *
+ * If \a type is SC_PM_RESET_TYPE_BOARD, then return with no action.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid partition or type
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt,
+ *
+ * Most peripherals owned by the partition will be reset if
+ * possible. SC state (partitions, power, clocks, etc.) is reset. The
+ * boot SW of the booting CPU must be able to handle peripherals that
+ * that are not reset.
+ */
+sc_err_t sc_pm_reboot_partition(sc_ipc_t ipc, sc_rm_pt_t pt,
+				sc_pm_reset_type_t type);
+
+/*!
+ * This function is used to start/stop a CPU.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    ID of the CPU resource
+ * @param[in]     enable      start if SC_TRUE; otherwise stop
+ * @param[in]     address     64-bit boot address
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid resource or address,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of the
+ *   resource (CPU) owner
+ */
+sc_err_t sc_pm_cpu_start(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t enable,
+			 sc_faddr_t address);
+
+/* @} */
+
+#endif /* SCI_PM_API_H */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/rm/sci_rm_api.h b/plat/imx/common/include/sci/svc/rm/sci_rm_api.h
new file mode 100644
index 0000000..df1bc40
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/rm/sci_rm_api.h
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file containing the public API for the System Controller (SC)
+ * Resource Management (RM) function. This includes functions for
+ * partitioning resources, pads, and memory regions.
+ *
+ * @addtogroup RM_SVC (SVC) Resource Management Service
+ *
+ * Module for the Resource Management (RM) service.
+ *
+ * @includedoc rm/details.dox
+ *
+ * @{
+ */
+
+#ifndef SCI_RM_API_H
+#define SCI_RM_API_H
+
+/* Includes */
+
+#include <sci/sci_types.h>
+
+/* Defines */
+
+/*!
+ * @name Defines for type widths
+ */
+/*@{*/
+#define SC_RM_PARTITION_W   5	/* Width of sc_rm_pt_t */
+#define SC_RM_MEMREG_W      6	/* Width of sc_rm_mr_t */
+#define SC_RM_DID_W         4	/* Width of sc_rm_did_t */
+#define SC_RM_SID_W         6	/* Width of sc_rm_sid_t */
+#define SC_RM_SPA_W         2	/* Width of sc_rm_spa_t */
+#define SC_RM_PERM_W        3	/* Width of sc_rm_perm_t */
+/*@}*/
+
+/*!
+ * @name Defines for ALL parameters
+ */
+/*@{*/
+#define SC_RM_PT_ALL        ((sc_rm_pt_t) UINT8_MAX)	/* All partitions */
+#define SC_RM_MR_ALL        ((sc_rm_mr_t) UINT8_MAX)	/* All memory regions */
+/*@}*/
+
+/*!
+ * @name Defines for sc_rm_spa_t
+ */
+/*@{*/
+#define SC_RM_SPA_PASSTHRU  0U	/* Pass through (attribute driven by master) */
+#define SC_RM_SPA_PASSSID   1U	/* Pass through and output on SID */
+#define SC_RM_SPA_ASSERT    2U	/* Assert (force to be secure/privileged) */
+#define SC_RM_SPA_NEGATE    3U	/* Negate (force to be non-secure/user) */
+/*@}*/
+
+/*!
+ * @name Defines for sc_rm_perm_t
+ */
+/*@{*/
+#define SC_RM_PERM_NONE         0U	/* No access */
+#define SC_RM_PERM_SEC_R        1U	/* Secure RO */
+#define SC_RM_PERM_SECPRIV_RW   2U	/* Secure privilege R/W */
+#define SC_RM_PERM_SEC_RW       3U	/* Secure R/W */
+#define SC_RM_PERM_NSPRIV_R     4U	/* Secure R/W, non-secure privilege RO */
+#define SC_RM_PERM_NS_R         5U	/* Secure R/W, non-secure RO */
+#define SC_RM_PERM_NSPRIV_RW    6U	/* Secure R/W, non-secure privilege R/W */
+#define SC_RM_PERM_FULL         7U	/* Full access */
+/*@}*/
+
+/* Types */
+
+/*!
+ * This type is used to declare a resource partition.
+ */
+typedef uint8_t sc_rm_pt_t;
+
+/*!
+ * This type is used to declare a memory region.
+ */
+typedef uint8_t sc_rm_mr_t;
+
+/*!
+ * This type is used to declare a resource domain ID used by the
+ * isolation HW.
+ */
+typedef uint8_t sc_rm_did_t;
+
+/*!
+ * This type is used to declare an SMMU StreamID.
+ */
+typedef uint16_t sc_rm_sid_t;
+
+/*!
+ * This type is a used to declare master transaction attributes.
+ */
+typedef uint8_t sc_rm_spa_t;
+
+/*!
+ * This type is used to declare a resource/memory region access permission.
+ * Refer to the XRDC2 Block Guide for more information.
+ */
+typedef uint8_t sc_rm_perm_t;
+
+/* Functions */
+
+/*!
+ * @name Partition Functions
+ * @{
+ */
+
+/*!
+ * This function requests that the SC create a new resource partition.
+ *
+ * @param[in]     ipc          IPC handle
+ * @param[out]    pt           return handle for partition; used for subsequent function
+ *                             calls associated with this partition
+ * @param[in]     secure       boolean indicating if this partition should be secure; only
+ *                             valid if caller is secure
+ * @param[in]     isolated     boolean indicating if this partition should be HW isolated
+ *                             via XRDC; set SC_TRUE if new DID is desired
+ * @param[in]     restricted   boolean indicating if this partition should be restricted; set
+ *                             SC_TRUE if masters in this partition cannot create new partitions
+ * @param[in]     grant        boolean indicating if this partition should always grant
+ *                             access and control to the parent
+ * @param[in]     coherent     boolean indicating if this partition is coherent;
+ *                             set SC_TRUE if only this partition will contain both AP clusters
+ *                             and they will be coherent via the CCI
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_ERR_PARM if caller's partition is not secure but a new secure partition is requested,
+ * - SC_ERR_LOCKED if caller's partition is locked,
+ * - SC_ERR_UNAVAILABLE if partition table is full (no more allocation space)
+ *
+ * Marking as non-secure prevents subsequent functions from configuring masters in this
+ * partition to assert the secure signal. If restricted then the new partition is limited
+ * in what functions it can call, especially those associated with managing partitions.
+ *
+ * The grant option is usually used to isolate a bus master's traffic to specific
+ * memory without isolating the peripheral interface of the master or the API
+ * controls of that master.
+ */
+sc_err_t sc_rm_partition_alloc(sc_ipc_t ipc, sc_rm_pt_t *pt, sc_bool_t secure,
+			       sc_bool_t isolated, sc_bool_t restricted,
+			       sc_bool_t grant, sc_bool_t coherent);
+
+/*!
+ * This function makes a partition confidential.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition that is granting
+ * @param[in]     retro       retroactive
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if \a pt out of range,
+ * - SC_ERR_NOACCESS if caller's not allowed to change \a pt
+ * - SC_ERR_LOCKED if partition \a pt is locked
+ *
+ * Call to make a partition confidential. Confidential means only this
+ * partition should be able to grant access permissions to this partition.
+ *
+ * If retroactive, then all resources owned by other partitions will have
+ * access rights for this partition removed, even if locked.
+ */
+sc_err_t sc_rm_set_confidential(sc_ipc_t ipc, sc_rm_pt_t pt, sc_bool_t retro);
+
+/*!
+ * This function frees a partition and assigns all resources to the caller.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to free
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if \a pt out of range or invalid,
+ * - SC_ERR_NOACCESS if \a pt is the SC partition,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt,
+ * - SC_ERR_LOCKED if \a pt or caller's partition is locked
+ *
+ * All resources, memory regions, and pads are assigned to the caller/parent.
+ * The partition watchdog is disabled (even if locked). DID is freed.
+ */
+sc_err_t sc_rm_partition_free(sc_ipc_t ipc, sc_rm_pt_t pt);
+
+/*!
+ * This function returns the DID of a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ *
+ * @return Returns the domain ID (DID) of the caller's partition.
+ *
+ * The DID is a SoC-specific internal ID used by the HW resource
+ * protection mechanism. It is only required by clients when using the
+ * SEMA42 module as the DID is sometimes connected to the master ID.
+ */
+sc_rm_did_t sc_rm_get_did(sc_ipc_t ipc);
+
+/*!
+ * This function forces a partition to use a specific static DID.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to assign \a did
+ * @param[in]     did         static DID to assign
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if \a pt or \a did out of range,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt,
+ * - SC_ERR_LOCKED if \a pt is locked
+ *
+ * Assumes no assigned resources or memory regions yet! The number of static
+ * DID is fixed by the SC at boot.
+ */
+sc_err_t sc_rm_partition_static(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_did_t did);
+
+/*!
+ * This function locks a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to lock
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if \a pt out of range,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt
+ *
+ * If a partition is locked it cannot be freed, have resources/pads assigned
+ * to/from it, memory regions created/assigned, DID changed, or parent changed.
+ */
+sc_err_t sc_rm_partition_lock(sc_ipc_t ipc, sc_rm_pt_t pt);
+
+/*!
+ * This function gets the partition handle of the caller.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    pt          return handle for caller's partition
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_rm_get_partition(sc_ipc_t ipc, sc_rm_pt_t *pt);
+
+/*!
+ * This function sets a new parent for a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition for which parent is to be
+ *                            changed
+ * @param[in]     pt_parent   handle of partition to set as parent
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt,
+ * - SC_ERR_LOCKED if either partition is locked
+ */
+sc_err_t sc_rm_set_parent(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_pt_t pt_parent);
+
+/*!
+ * This function moves all movable resources/pads owned by a source partition
+ * to a destination partition. It can be used to more quickly set up a new
+ * partition if a majority of the caller's resources are to be moved to a
+ * new partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt_src      handle of partition from which resources should
+ *                            be moved from
+ * @param[in]     pt_dst      handle of partition to which resources should be
+ *                            moved to
+ * @param[in]     move_rsrc   boolean to indicate if resources should be moved
+ * @param[in]     move_pads   boolean to indicate if pads should be moved
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * By default, all resources are movable. This can be changed using the
+ * sc_rm_set_resource_movable() function. Note all masters defaulted to SMMU
+ * bypass.
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not \a pt_src or the
+ *   parent of \a pt_src,
+ * - SC_ERR_LOCKED if either partition is locked
+ */
+sc_err_t sc_rm_move_all(sc_ipc_t ipc, sc_rm_pt_t pt_src, sc_rm_pt_t pt_dst,
+			sc_bool_t move_rsrc, sc_bool_t move_pads);
+
+/* @} */
+
+/*!
+ * @name Resource Functions
+ * @{
+ */
+
+/*!
+ * This function assigns ownership of a resource to a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to which resource should be
+ *                            assigned
+ * @param[in]     resource    resource to assign
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * This action resets the resource's master and peripheral attributes.
+ * Privilege attribute will be PASSTHRU, security attribute will be
+ * ASSERT if the partition si secure and NEGATE if it is not, and
+ * masters will defaulted to SMMU bypass. Access permissions will reset
+ * to SEC_RW for the owning partition only for secure partitions, FULL for
+ * non-secure. DEfault is no access by other partitions.
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent
+ *   of the owner,
+ * - SC_ERR_LOCKED if the owning partition or \a pt is locked
+ */
+sc_err_t sc_rm_assign_resource(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource);
+
+/*!
+ * This function flags resources as movable or not.
+ *
+ * @param[in]     ipc          IPC handle
+ * @param[in]     resource_fst first resource for which flag should be set
+ * @param[in]     resource_lst last resource for which flag should be set
+ * @param[in]     movable      movable flag (SC_TRUE is movable)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if resources are out of range,
+ * - SC_ERR_NOACCESS if caller's partition is not a parent of a resource owner,
+ * - SC_ERR_LOCKED if the owning partition is locked
+ *
+ * This function is used to determine the set of resources that will be
+ * moved using the sc_rm_move_all() function. All resources are movable
+ * by default so this function is normally used to prevent a set of
+ * resources from moving.
+ */
+sc_err_t sc_rm_set_resource_movable(sc_ipc_t ipc, sc_rsrc_t resource_fst,
+				    sc_rsrc_t resource_lst, sc_bool_t movable);
+
+/*!
+ * This function flags all of a subsystem's resources as movable
+ * or not.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource to use to identify subsystem
+ * @param[in]     movable     movable flag (SC_TRUE is movable)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if a function argument is out of range
+ *
+ * Note \a resource is used to find the associated subsystem. Only
+ * resources owned by the caller are set.
+ */
+sc_err_t sc_rm_set_subsys_rsrc_movable(sc_ipc_t ipc, sc_rsrc_t resource,
+				       sc_bool_t movable);
+
+/*!
+ * This function sets attributes for a resource which is a bus master (i.e.
+ * capable of DMA).
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    master resource for which attributes should apply
+ * @param[in]     sa          security attribute
+ * @param[in]     pa          privilege attribute
+ * @param[in]     smmu_bypass SMMU bypass mode
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not a parent of the resource owner,
+ * - SC_ERR_LOCKED if the owning partition is locked
+ *
+ * This function configures how the HW isolation will see bus transactions
+ * from the specified master. Note the security attribute will only be
+ * changed if the caller's partition is secure.
+ */
+sc_err_t sc_rm_set_master_attributes(sc_ipc_t ipc, sc_rsrc_t resource,
+				     sc_rm_spa_t sa, sc_rm_spa_t pa,
+				     sc_bool_t smmu_bypass);
+
+/*!
+ * This function sets the StreamID for a resource which is a bus master (i.e.
+ * capable of DMA).
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    master resource for which attributes should apply
+ * @param[in]     sid         StreamID
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent
+ *   of the owner,
+ * - SC_ERR_LOCKED if the owning partition is locked
+ *
+ * This function configures the SID attribute associated with all bus transactions
+ * from this master. Note 0 is not a valid SID as it is reserved to indicate
+ * bypass.
+ */
+sc_err_t sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_rm_sid_t sid);
+
+/*!
+ * This function sets access permissions for a peripheral resource.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    peripheral resource for which permissions should apply
+ * @param[in]     pt          handle of partition \a perm should by applied for
+ * @param[in]     perm        permissions to apply to \a resource for \a pt
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent
+ *   of the owner,
+ * - SC_ERR_LOCKED if the owning partition is locked
+ * - SC_ERR_LOCKED if the \a pt is confidential and the caller isn't \a pt
+ *
+ * This function configures how the HW isolation will restrict access to a
+ * peripheral based on the attributes of a transaction from bus master.
+ */
+sc_err_t sc_rm_set_peripheral_permissions(sc_ipc_t ipc, sc_rsrc_t resource,
+					  sc_rm_pt_t pt, sc_rm_perm_t perm);
+
+/*!
+ * This function gets ownership status of a resource.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource to check
+ *
+ * @return Returns a boolean (SC_TRUE if caller's partition owns the resource).
+ *
+ * If \a resource is out of range then SC_FALSE is returned.
+ */
+sc_bool_t sc_rm_is_resource_owned(sc_ipc_t ipc, sc_rsrc_t resource);
+
+/*!
+ * This function is used to test if a resource is a bus master.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource to check
+ *
+ * @return Returns a boolean (SC_TRUE if the resource is a bus master).
+ *
+ * If \a resource is out of range then SC_FALSE is returned.
+ */
+sc_bool_t sc_rm_is_resource_master(sc_ipc_t ipc, sc_rsrc_t resource);
+
+/*!
+ * This function is used to test if a resource is a peripheral.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource to check
+ *
+ * @return Returns a boolean (SC_TRUE if the resource is a peripheral).
+ *
+ * If \a resource is out of range then SC_FALSE is returned.
+ */
+sc_bool_t sc_rm_is_resource_peripheral(sc_ipc_t ipc, sc_rsrc_t resource);
+
+/*!
+ * This function is used to obtain info about a resource.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     resource    resource to inquire about
+ * @param[out]    sid         pointer to return StreamID
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if \a resource is out of range
+ */
+sc_err_t sc_rm_get_resource_info(sc_ipc_t ipc, sc_rsrc_t resource,
+				 sc_rm_sid_t *sid);
+
+/* @} */
+
+/*!
+ * @name Memory Region Functions
+ * @{
+ */
+
+/*!
+ * This function requests that the SC create a new memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    mr          return handle for region; used for
+ *                            subsequent function calls
+ *                            associated with this region
+ * @param[in]     addr_start  start address of region (physical)
+ * @param[in]     addr_end    end address of region (physical)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if the new memory region is misaligned,
+ * - SC_ERR_LOCKED if caller's partition is locked,
+ * - SC_ERR_PARM if the new memory region spans multiple existing regions,
+ * - SC_ERR_NOACCESS if caller's partition does not own the memory containing
+ *   the new region,
+ * - SC_ERR_UNAVAILABLE if memory region table is full (no more allocation
+ *   space)
+ *
+ * The area covered by the memory region must currently be owned by the caller.
+ * By default, the new region will have access permission set to allow the
+ * caller to access.
+ */
+sc_err_t sc_rm_memreg_alloc(sc_ipc_t ipc, sc_rm_mr_t *mr,
+			    sc_faddr_t addr_start, sc_faddr_t addr_end);
+
+/*!
+ * This function requests that the SC split a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     mr          handle of memory region to split
+ * @param[out]    mr_ret      return handle for new region; used for
+ *                            subsequent function calls
+ *                            associated with this region
+ * @param[in]     addr_start  start address of region (physical)
+ * @param[in]     addr_end    end address of region (physical)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if the new memory region is not start/end part of mr,
+ * - SC_ERR_LOCKED if caller's partition is locked,
+ * - SC_ERR_PARM if the new memory region spans multiple existing regions,
+ * - SC_ERR_NOACCESS if caller's partition does not own the memory containing
+ *   the new region,
+ * - SC_ERR_UNAVAILABLE if memory region table is full (no more allocation
+ *   space)
+ *
+ * Note the new region must start or end on the split region.
+ */
+sc_err_t sc_rm_memreg_split(sc_ipc_t ipc, sc_rm_mr_t mr,
+			    sc_rm_mr_t *mr_ret, sc_faddr_t addr_start,
+			    sc_faddr_t addr_end);
+
+/*!
+ * This function frees a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     mr          handle of memory region to free
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if \a mr out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not a parent of \a mr,
+ * - SC_ERR_LOCKED if the owning partition of \a mr is locked
+ */
+sc_err_t sc_rm_memreg_free(sc_ipc_t ipc, sc_rm_mr_t mr);
+
+/*!
+ * Internal SC function to find a memory region.
+ *
+ * @see sc_rm_find_memreg().
+ */
+/*!
+ * This function finds a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    mr          return handle for region; used for
+ *                            subsequent function calls
+ *                            associated with this region
+ * @param[in]     addr_start  start address of region to search for
+ * @param[in]     addr_end    end address of region to search for
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOTFOUND if region not found,
+ *
+ * Searches only for regions owned by the caller. Finds first
+ * region containing the range specified.
+ */
+sc_err_t sc_rm_find_memreg(sc_ipc_t ipc, sc_rm_mr_t *mr,
+			   sc_faddr_t addr_start, sc_faddr_t addr_end);
+
+/*!
+ * This function assigns ownership of a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to which memory region
+ *                            should be assigned
+ * @param[in]     mr          handle of memory region to assign
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the \a mr owner or parent
+ *   of the owner,
+ * - SC_ERR_LOCKED if the owning partition or \a pt is locked
+ */
+sc_err_t sc_rm_assign_memreg(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_mr_t mr);
+
+/*!
+ * This function sets access permissions for a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     mr          handle of memory region for which permissions
+ *                            should apply
+ * @param[in]     pt          handle of partition \a perm should by
+ *                            applied for
+ * @param[in]     perm        permissions to apply to \a mr for \a pt
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the region owner or parent
+ *   of the owner,
+ * - SC_ERR_LOCKED if the owning partition is locked
+ * - SC_ERR_LOCKED if the \a pt is confidential and the caller isn't \a pt
+ *
+ * This function configures how the HW isolation will restrict access to a
+ * memory region based on the attributes of a transaction from bus master.
+ */
+sc_err_t sc_rm_set_memreg_permissions(sc_ipc_t ipc, sc_rm_mr_t mr,
+				      sc_rm_pt_t pt, sc_rm_perm_t perm);
+
+/*!
+ * This function gets ownership status of a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     mr          handle of memory region to check
+ *
+ * @return Returns a boolean (SC_TRUE if caller's partition owns the
+ * memory region).
+ *
+ * If \a mr is out of range then SC_FALSE is returned.
+ */
+sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr);
+
+/*!
+ * This function is used to obtain info about a memory region.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     mr          handle of memory region to inquire about
+ * @param[out]    addr_start  pointer to return start address
+ * @param[out]    addr_end    pointer to return end address
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if \a mr is out of range
+ */
+sc_err_t sc_rm_get_memreg_info(sc_ipc_t ipc, sc_rm_mr_t mr,
+			       sc_faddr_t *addr_start, sc_faddr_t *addr_end);
+
+/* @} */
+
+/*!
+ * @name Pad Functions
+ * @{
+ */
+
+/*!
+ * This function assigns ownership of a pad to a partition.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          handle of partition to which pad should
+ *                            be assigned
+ * @param[in]     pad         pad to assign
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_NOACCESS if caller's partition is restricted,
+ * - SC_PARM if arguments out of range or invalid,
+ * - SC_ERR_NOACCESS if caller's partition is not the pad owner or parent
+ *   of the owner,
+ * - SC_ERR_LOCKED if the owning partition or \a pt is locked
+ */
+sc_err_t sc_rm_assign_pad(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pad_t pad);
+
+/*!
+ * This function flags pads as movable or not.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad_fst     first pad for which flag should be set
+ * @param[in]     pad_lst     last pad for which flag should be set
+ * @param[in]     movable     movable flag (SC_TRUE is movable)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_PARM if pads are out of range,
+ * - SC_ERR_NOACCESS if caller's partition is not a parent of a pad owner,
+ * - SC_ERR_LOCKED if the owning partition is locked
+ *
+ * This function is used to determine the set of pads that will be
+ * moved using the sc_rm_move_all() function. All pads are movable
+ * by default so this function is normally used to prevent a set of
+ * pads from moving.
+ */
+sc_err_t sc_rm_set_pad_movable(sc_ipc_t ipc, sc_pad_t pad_fst,
+			       sc_pad_t pad_lst, sc_bool_t movable);
+
+/*!
+ * This function gets ownership status of a pad.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pad         pad to check
+ *
+ * @return Returns a boolean (SC_TRUE if caller's partition owns the pad).
+ *
+ * If \a pad is out of range then SC_FALSE is returned.
+ */
+sc_bool_t sc_rm_is_pad_owned(sc_ipc_t ipc, sc_pad_t pad);
+
+/* @} */
+
+/*!
+ * @name Debug Functions
+ * @{
+ */
+
+/*!
+ * This function dumps the RM state for debug.
+ *
+ * @param[in]     ipc         IPC handle
+ */
+void sc_rm_dump(sc_ipc_t ipc);
+
+/* @} */
+
+#endif /* SCI_RM_API_H */
+
+/**@}*/
diff --git a/plat/imx/common/include/sci/svc/timer/sci_timer_api.h b/plat/imx/common/include/sci/svc/timer/sci_timer_api.h
new file mode 100644
index 0000000..f8423ab
--- /dev/null
+++ b/plat/imx/common/include/sci/svc/timer/sci_timer_api.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file containing the public API for the System Controller (SC)
+ * Timer function.
+ *
+ * @addtogroup TIMER_SVC (SVC) Timer Service
+ *
+ * Module for the Timer service. This includes support for the watchdog, RTC,
+ * and system counter. Note every resource partition has a watchdog it can
+ * use.
+ *
+ * @{
+ */
+
+#ifndef SC_TIMER_API_H
+#define SC_TIMER_API_H
+
+/* Includes */
+
+#include <sci/sci_types.h>
+
+/* Defines */
+
+/*!
+ * @name Defines for type widths
+ */
+/*@{*/
+#define SC_TIMER_ACTION_W   3U	/* Width of sc_timer_wdog_action_t */
+/*@}*/
+
+/*!
+ * @name Defines for sc_timer_wdog_action_t
+ */
+/*@{*/
+#define SC_TIMER_WDOG_ACTION_PARTITION      0U	/* Reset partition */
+#define SC_TIMER_WDOG_ACTION_WARM           1U	/* Warm reset system */
+#define SC_TIMER_WDOG_ACTION_COLD           2U	/* Cold reset system */
+#define SC_TIMER_WDOG_ACTION_BOARD          3U	/* Reset board */
+#define SC_TIMER_WDOG_ACTION_IRQ            4U	/* Only generate IRQs */
+/*@}*/
+
+/* Types */
+
+/*!
+ * This type is used to configure the watchdog action.
+ */
+typedef uint8_t sc_timer_wdog_action_t;
+
+/*!
+ * This type is used to declare a watchdog time value in milliseconds.
+ */
+typedef uint32_t sc_timer_wdog_time_t;
+
+/* Functions */
+
+/*!
+ * @name Watchdog Functions
+ * @{
+ */
+
+/*!
+ * This function sets the watchdog timeout in milliseconds. If not
+ * set then the timeout defaults to the max. Once locked this value
+ * cannot be changed.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     timeout     timeout period for the watchdog
+ *
+ * @return Returns an error code (SC_ERR_NONE = success, SC_ERR_LOCKED
+ *         = locked).
+ */
+sc_err_t sc_timer_set_wdog_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t timeout);
+
+/*!
+ * This function sets the watchdog pre-timeout in milliseconds. If not
+ * set then the pre-timeout defaults to the max. Once locked this value
+ * cannot be changed.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pre_timeout pre-timeout period for the watchdog
+ *
+ * When the pre-timeout expires an IRQ will be generated. Note this timeout
+ * clears when the IRQ is triggered. An IRQ is generated for the failing
+ * partition and all of its child partitions.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_set_wdog_pre_timeout(sc_ipc_t ipc,
+				       sc_timer_wdog_time_t pre_timeout);
+
+/*!
+ * This function starts the watchdog.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     lock        boolean indicating the lock status
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * If \a lock is set then the watchdog cannot be stopped or the timeout
+ * period changed.
+ */
+sc_err_t sc_timer_start_wdog(sc_ipc_t ipc, sc_bool_t lock);
+
+/*!
+ * This function stops the watchdog if it is not locked.
+ *
+ * @param[in]     ipc         IPC handle
+ *
+ * @return Returns an error code (SC_ERR_NONE = success, SC_ERR_LOCKED
+ *         = locked).
+ */
+sc_err_t sc_timer_stop_wdog(sc_ipc_t ipc);
+
+/*!
+ * This function pings (services, kicks) the watchdog resetting the time
+ * before expiration back to the timeout.
+ *
+ * @param[in]     ipc         IPC handle
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_ping_wdog(sc_ipc_t ipc);
+
+/*!
+ * This function gets the status of the watchdog. All arguments are
+ * in milliseconds.
+ *
+ * @param[in]     ipc             IPC handle
+ * @param[out]    timeout         pointer to return the timeout
+ * @param[out]    max_timeout     pointer to return the max timeout
+ * @param[out]    remaining_time  pointer to return the time remaining
+ *                                until trigger
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_get_wdog_status(sc_ipc_t ipc,
+				  sc_timer_wdog_time_t *timeout,
+				  sc_timer_wdog_time_t *max_timeout,
+				  sc_timer_wdog_time_t *remaining_time);
+
+/*!
+ * This function gets the status of the watchdog of a partition. All
+ * arguments are in milliseconds.
+ *
+ * @param[in]     ipc             IPC handle
+ * @param[in]     pt              partition to query
+ * @param[out]    enb             pointer to return enable status
+ * @param[out]    timeout         pointer to return the timeout
+ * @param[out]    remaining_time  pointer to return the time remaining
+ *                                until trigger
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_pt_get_wdog_status(sc_ipc_t ipc, sc_rm_pt_t pt,
+				     sc_bool_t *enb,
+				     sc_timer_wdog_time_t *timeout,
+				     sc_timer_wdog_time_t *remaining_time);
+
+/*!
+ * This function configures the action to be taken when a watchdog
+ * expires.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     pt          partition to affect
+ * @param[in]     action      action to take
+ *
+ * Default action is inherited from the parent.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid parameters,
+ * - SC_ERR_NOACCESS if caller's partition is not the SYSTEM owner,
+ * - SC_ERR_LOCKED if the watchdog is locked
+ */
+sc_err_t sc_timer_set_wdog_action(sc_ipc_t ipc,
+				  sc_rm_pt_t pt, sc_timer_wdog_action_t action);
+
+/* @} */
+
+/*!
+ * @name Real-Time Clock (RTC) Functions
+ * @{
+ */
+
+/*!
+ * This function sets the RTC time. Only the owner of the SC_R_SYSTEM
+ * resource can set the time.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     year        year (min 1970)
+ * @param[in]     mon         month (1-12)
+ * @param[in]     day         day of the month (1-31)
+ * @param[in]     hour        hour (0-23)
+ * @param[in]     min         minute (0-59)
+ * @param[in]     sec         second (0-59)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters,
+ * - SC_ERR_NOACCESS if caller's partition is not the SYSTEM owner
+ */
+sc_err_t sc_timer_set_rtc_time(sc_ipc_t ipc, uint16_t year, uint8_t mon,
+			       uint8_t day, uint8_t hour, uint8_t min,
+			       uint8_t sec);
+
+/*!
+ * This function gets the RTC time.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    year        pointer to return year (min 1970)
+ * @param[out]    mon         pointer to return month (1-12)
+ * @param[out]    day         pointer to return day of the month (1-31)
+ * @param[out]    hour        pointer to return hour (0-23)
+ * @param[out]    min         pointer to return minute (0-59)
+ * @param[out]    sec         pointer to return second (0-59)
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_get_rtc_time(sc_ipc_t ipc, uint16_t *year, uint8_t *mon,
+			       uint8_t *day, uint8_t *hour, uint8_t *min,
+			       uint8_t *sec);
+
+/*!
+ * This function gets the RTC time in seconds since 1/1/1970.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[out]    sec         pointer to return second
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_get_rtc_sec1970(sc_ipc_t ipc, uint32_t *sec);
+
+/*!
+ * This function sets the RTC alarm.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     year        year (min 1970)
+ * @param[in]     mon         month (1-12)
+ * @param[in]     day         day of the month (1-31)
+ * @param[in]     hour        hour (0-23)
+ * @param[in]     min         minute (0-59)
+ * @param[in]     sec         second (0-59)
+ *
+ * Note this alarm setting clears when the alarm is triggered.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters
+ */
+sc_err_t sc_timer_set_rtc_alarm(sc_ipc_t ipc, uint16_t year, uint8_t mon,
+				uint8_t day, uint8_t hour, uint8_t min,
+				uint8_t sec);
+
+/*!
+ * This function sets the RTC alarm (periodic mode).
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     sec         period in seconds
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters
+ */
+sc_err_t sc_timer_set_rtc_periodic_alarm(sc_ipc_t ipc, uint32_t sec);
+
+/*!
+ * This function cancels the RTC alarm.
+ *
+ * @param[in]     ipc         IPC handle
+ *
+ * Note this alarm setting clears when the alarm is triggered.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters
+ */
+sc_err_t sc_timer_cancel_rtc_alarm(sc_ipc_t ipc);
+
+/*!
+ * This function sets the RTC calibration value. Only the owner of the SC_R_SYSTEM
+ * resource can set the calibration.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     count       calbration count (-16 to 15)
+ *
+ * The calibration value is a 5-bit value including the sign bit, which is
+ * implemented in 2's complement. It is added or subtracted from the RTC on
+ * a perdiodic basis, once per 32768 cycles of the RTC clock.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ */
+sc_err_t sc_timer_set_rtc_calb(sc_ipc_t ipc, int8_t count);
+
+/* @} */
+
+/*!
+ * @name System Counter (SYSCTR) Functions
+ * @{
+ */
+
+/*!
+ * This function sets the SYSCTR alarm.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     ticks       number of 8MHz cycles
+ *
+ * Note this alarm setting clears when the alarm is triggered.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters
+ */
+sc_err_t sc_timer_set_sysctr_alarm(sc_ipc_t ipc, uint64_t ticks);
+
+/*!
+ * This function sets the SYSCTR alarm (periodic mode).
+ *
+ * @param[in]     ipc          IPC handle
+ * @param[in]     ticks        number of 8MHz cycles
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters
+ */
+sc_err_t sc_timer_set_sysctr_periodic_alarm(sc_ipc_t ipc, uint64_t ticks);
+
+/*!
+ * This function cancels the SYSCTR alarm.
+ *
+ * @param[in]     ipc         IPC handle
+ *
+ * Note this alarm setting clears when the alarm is triggered.
+ *
+ * @return Returns an error code (SC_ERR_NONE = success).
+ *
+ * Return errors:
+ * - SC_ERR_PARM if invalid time/date parameters
+ */
+sc_err_t sc_timer_cancel_sysctr_alarm(sc_ipc_t ipc);
+
+/* @} */
+
+#endif				/* SC_TIMER_API_H */
+
+/**@}*/
diff --git a/plat/imx/common/lpuart_console.S b/plat/imx/common/lpuart_console.S
new file mode 100644
index 0000000..d8dac2c
--- /dev/null
+++ b/plat/imx/common/lpuart_console.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#include "imx8_lpuart.h"
+
+	.globl	console_lpuart_register
+	.globl	console_lpuart_init
+	.globl	console_lpuart_putc
+	.globl	console_lpuart_getc
+	.globl	console_lpuart_flush
+
+func console_lpuart_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_DRVDATA]
+
+	bl	console_lpuart_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register lpuart putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_lpuart_register
+
+func console_lpuart_init
+	mov	w0, #1
+	ret
+endfunc console_lpuart_init
+
+func console_lpuart_putc
+	ldr	x1, [x1, #CONSOLE_T_DRVDATA]
+	cbz	x1, putc_error
+	/* Prepare '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+1:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #STAT]
+	tbz	w2, #23, 1b
+	mov	w2, #0xD
+	str	w2, [x1, #DATA]
+2:
+	/* Check if the transmit FIFO is full */
+	ldr	w2, [x1, #STAT]
+	tbz	w2, #23, 2b
+	str	w0, [x1, #DATA]
+	ret
+putc_error:
+	mov	w0, #-1
+	ret
+endfunc console_lpuart_putc
+
+func console_lpuart_getc
+	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+	cbz	x0, getc_error
+	/* Check if the receive FIFO state */
+	ret
+getc_error:
+	mov	w0, #-1
+	ret
+endfunc console_lpuart_getc
+
+func console_lpuart_flush
+	mov	x0, #0
+	ret
+endfunc console_lpuart_flush
diff --git a/plat/imx/common/plat_imx8_gic.c b/plat/imx/common/plat_imx8_gic.c
new file mode 100644
index 0000000..3a7dcfe
--- /dev/null
+++ b/plat/imx/common/plat_imx8_gic.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/arm_gicv3_common.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <plat_imx8.h>
+
+/* the GICv3 driver only needs to be initialized in EL3 */
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t g01s_interrupt_props[] = {
+	INTR_PROP_DESC(6, GIC_HIGHEST_SEC_PRIORITY,
+		       INTR_GROUP1S, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(7, GIC_HIGHEST_SEC_PRIORITY,
+		       INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+static unsigned int plat_imx_mpidr_to_core_pos(unsigned long mpidr)
+{
+	return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+const gicv3_driver_data_t arm_gic_data = {
+	.gicd_base = PLAT_GICD_BASE,
+	.gicr_base = PLAT_GICR_BASE,
+	.interrupt_props = g01s_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g01s_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = plat_imx_mpidr_to_core_pos,
+};
+
+void plat_gic_driver_init(void)
+{
+	/*
+	 * the GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in S-EL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#if IMAGE_BL31
+	gicv3_driver_init(&arm_gic_data);
+#endif
+}
+
+static __inline void plat_gicr_exit_sleep(void)
+{
+	unsigned int val = mmio_read_32(PLAT_GICR_BASE + GICR_WAKER);
+
+	/*
+	 * ProcessorSleep bit can ONLY be set to zero when
+	 * Quiescent bit and Sleep bit are both zero, so
+	 * need to make sure Quiescent bit and Sleep bit
+	 * are zero before clearing ProcessorSleep bit.
+	 */
+	if (val & WAKER_QSC_BIT) {
+		mmio_write_32(PLAT_GICR_BASE + GICR_WAKER, val & ~WAKER_SL_BIT);
+		/* Wait till the WAKER_QSC_BIT changes to 0 */
+		while ((mmio_read_32(PLAT_GICR_BASE + GICR_WAKER) & WAKER_QSC_BIT) != 0U)
+			;
+	}
+}
+
+void plat_gic_init(void)
+{
+	plat_gicr_exit_sleep();
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void plat_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void plat_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void plat_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
+
+void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx)
+{
+	/* save the gic rdist/dist context */
+	for (int i = 0; i < PLATFORM_CORE_COUNT; i++)
+		gicv3_rdistif_save(i, &ctx->rdist_ctx[i]);
+	gicv3_distif_save(&ctx->dist_ctx);
+}
+
+void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx)
+{
+	/* restore the gic rdist/dist context */
+	gicv3_distif_init_restore(&ctx->dist_ctx);
+	for (int i = 0; i < PLATFORM_CORE_COUNT; i++)
+		gicv3_rdistif_init_restore(i, &ctx->rdist_ctx[i]);
+}
diff --git a/plat/imx/common/sci/imx8_mu.c b/plat/imx/common/sci/imx8_mu.c
new file mode 100644
index 0000000..66e956d
--- /dev/null
+++ b/plat/imx/common/sci/imx8_mu.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "imx8_mu.h"
+
+void MU_Resume(uint32_t base)
+{
+	uint32_t reg, i;
+
+	reg = mmio_read_32(base + MU_ACR_OFFSET1);
+	/* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */
+	reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1
+			| MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1);
+	mmio_write_32(base + MU_ACR_OFFSET1, reg);
+
+	/* Enable all RX interrupts */
+	for (i = 0; i < MU_RR_COUNT; i++)
+		MU_EnableRxFullInt(base, i);
+}
+
+void MU_EnableRxFullInt(uint32_t base, uint32_t index)
+{
+	uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1);
+
+	reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1);
+	reg |= MU_CR_RIE0_MASK1 >> index;
+	mmio_write_32(base + MU_ACR_OFFSET1, reg);
+}
+
+void MU_EnableGeneralInt(uint32_t base, uint32_t index)
+{
+	uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1);
+
+	reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1);
+	reg |= MU_CR_GIE0_MASK1 >> index;
+	mmio_write_32(base + MU_ACR_OFFSET1, reg);
+}
+
+void MU_SendMessage(uint32_t base, uint32_t regIndex, uint32_t msg)
+{
+	uint32_t mask = MU_SR_TE0_MASK1 >> regIndex;
+
+	/* Wait TX register to be empty. */
+	while (!(mmio_read_32(base + MU_ASR_OFFSET1) & mask))
+		;
+	mmio_write_32(base + MU_ATR0_OFFSET1 + (regIndex * 4), msg);
+}
+
+void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg)
+{
+	uint32_t mask = MU_SR_RF0_MASK1 >> regIndex;
+
+	/* Wait RX register to be full. */
+	while (!(mmio_read_32(base + MU_ASR_OFFSET1) & mask))
+		;
+	*msg = mmio_read_32(base + MU_ARR0_OFFSET1 + (regIndex * 4));
+}
+
+void MU_Init(uint32_t base)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(base + MU_ACR_OFFSET1);
+	/* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */
+	reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1
+			| MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1);
+	mmio_write_32(base + MU_ACR_OFFSET1, reg);
+}
diff --git a/plat/imx/common/sci/imx8_mu.h b/plat/imx/common/sci/imx8_mu.h
new file mode 100644
index 0000000..7885219
--- /dev/null
+++ b/plat/imx/common/sci/imx8_mu.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#define MU_ATR0_OFFSET1		0x0
+#define MU_ARR0_OFFSET1		0x10
+#define MU_ASR_OFFSET1		0x20
+#define MU_ACR_OFFSET1		0x24
+#define MU_TR_COUNT1		4
+#define MU_RR_COUNT1		4
+
+#define MU_CR_GIEn_MASK1	(0xFu << 28)
+#define MU_CR_RIEn_MASK1	(0xF << 24)
+#define MU_CR_TIEn_MASK1	(0xF << 20)
+#define MU_CR_GIRn_MASK1	(0xF << 16)
+#define MU_CR_NMI_MASK1		(1 << 3)
+#define MU_CR_Fn_MASK1		0x7
+
+#define MU_SR_TE0_MASK1		(1 << 23)
+#define MU_SR_RF0_MASK1		(1 << 27)
+#define MU_CR_RIE0_MASK1	(1 << 27)
+#define MU_CR_GIE0_MASK1	(1U << 31)
+
+#define MU_TR_COUNT			4
+#define MU_RR_COUNT			4
+
+void MU_Init(uint32_t base);
+void MU_SendMessage(uint32_t base, uint32_t regIndex, uint32_t msg);
+void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg);
+void MU_EnableGeneralInt(uint32_t base, uint32_t index);
+void MU_EnableRxFullInt(uint32_t base, uint32_t index);
+void MU_Resume(uint32_t base);
diff --git a/plat/imx/common/sci/ipc.c b/plat/imx/common/sci/ipc.c
new file mode 100644
index 0000000..6491ca5
--- /dev/null
+++ b/plat/imx/common/sci/ipc.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <lib/bakery_lock.h>
+
+#include <sci/sci_scfw.h>
+#include <sci/sci_ipc.h>
+#include <sci/sci_rpc.h>
+#include "imx8_mu.h"
+
+DEFINE_BAKERY_LOCK(sc_ipc_bakery_lock);
+#define sc_ipc_lock_init()	bakery_lock_init(&sc_ipc_bakery_lock)
+#define sc_ipc_lock()		bakery_lock_get(&sc_ipc_bakery_lock)
+#define sc_ipc_unlock()		bakery_lock_release(&sc_ipc_bakery_lock)
+
+void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, bool no_resp)
+{
+	sc_ipc_lock();
+
+	sc_ipc_write(ipc, msg);
+	if (!no_resp)
+		sc_ipc_read(ipc, msg);
+
+	sc_ipc_unlock();
+}
+
+sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id)
+{
+	uint32_t base = id;
+	uint32_t i;
+
+	/* Get MU base associated with IPC channel */
+	if ((ipc == NULL) || (base == 0))
+		return SC_ERR_IPC;
+
+	sc_ipc_lock_init();
+
+	/* Init MU */
+	MU_Init(base);
+
+	/* Enable all RX interrupts */
+	for (i = 0; i < MU_RR_COUNT; i++) {
+		MU_EnableRxFullInt(base, i);
+	}
+
+	/* Return MU address as handle */
+	*ipc = (sc_ipc_t) id;
+
+	return SC_ERR_NONE;
+}
+
+void sc_ipc_close(sc_ipc_t ipc)
+{
+	uint32_t base = ipc;
+
+	if (base != 0)
+		MU_Init(base);
+}
+
+void sc_ipc_read(sc_ipc_t ipc, void *data)
+{
+	uint32_t base = ipc;
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+	uint8_t count = 0;
+
+	/* Check parms */
+	if ((base == 0) || (msg == NULL))
+		return;
+
+	/* Read first word */
+	MU_ReceiveMsg(base, 0, (uint32_t *) msg);
+	count++;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG) {
+		*((uint32_t *) msg) = 0;
+		return;
+	}
+
+	/* Read remaining words */
+	while (count < msg->size) {
+		MU_ReceiveMsg(base, count % MU_RR_COUNT,
+			&(msg->DATA.u32[count - 1]));
+		count++;
+	}
+}
+
+void sc_ipc_write(sc_ipc_t ipc, void *data)
+{
+	sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+	uint32_t base = ipc;
+	uint8_t count = 0;
+
+	/* Check parms */
+	if ((base == 0) || (msg == NULL))
+		return;
+
+	/* Check size */
+	if (msg->size > SC_RPC_MAX_MSG)
+		return;
+
+	/* Write first word */
+	MU_SendMessage(base, 0, *((uint32_t *) msg));
+	count++;
+
+	/* Write remaining words */
+	while (count < msg->size) {
+		MU_SendMessage(base, count % MU_TR_COUNT,
+			msg->DATA.u32[count - 1]);
+		count++;
+	}
+}
+
diff --git a/plat/imx/common/sci/sci_api.mk b/plat/imx/common/sci/sci_api.mk
new file mode 100644
index 0000000..92c7190
--- /dev/null
+++ b/plat/imx/common/sci/sci_api.mk
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL31_SOURCES	+=	plat/imx/common/sci/ipc.c			\
+			plat/imx/common/sci/imx8_mu.c			\
+			plat/imx/common/sci/svc/pad/pad_rpc_clnt.c	\
+			plat/imx/common/sci/svc/pm/pm_rpc_clnt.c	\
+			plat/imx/common/sci/svc/rm/rm_rpc_clnt.c	\
+			plat/imx/common/sci/svc/timer/timer_rpc_clnt.c	\
+			plat/imx/common/sci/svc/misc/misc_rpc_clnt.c
diff --git a/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c b/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c
new file mode 100644
index 0000000..080de6a
--- /dev/null
+++ b/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * File containing client-side RPC functions for the MISC service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup MISC_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/misc/sci_misc_api.h>
+#include <sci/sci_rpc.h>
+#include <stdlib.h>
+#include "sci_misc_rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_misc_set_control(sc_ipc_t ipc, sc_rsrc_t resource,
+			     sc_ctrl_t ctrl, uint32_t val)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_CONTROL;
+	RPC_U32(&msg, 0U) = (uint32_t)ctrl;
+	RPC_U32(&msg, 4U) = (uint32_t)val;
+	RPC_U16(&msg, 8U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 4U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_get_control(sc_ipc_t ipc, sc_rsrc_t resource,
+			     sc_ctrl_t ctrl, uint32_t *val)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_CONTROL;
+	RPC_U32(&msg, 0U) = (uint32_t)ctrl;
+	RPC_U16(&msg, 4U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (val != NULL)
+		*val = RPC_U32(&msg, 0U);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_set_max_dma_group(sc_ipc_t ipc, sc_rm_pt_t pt,
+				   sc_misc_dma_group_t max)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_MAX_DMA_GROUP;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)max;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_set_dma_group(sc_ipc_t ipc, sc_rsrc_t resource,
+			       sc_misc_dma_group_t group)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_DMA_GROUP;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)group;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, sc_faddr_t addr_src,
+				 sc_faddr_t addr_dst, uint32_t len,
+				 sc_bool_t fw)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_IMAGE_LOAD;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr_src >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr_src;
+	RPC_U32(&msg, 8U) = (uint32_t)(addr_dst >> 32U);
+	RPC_U32(&msg, 12U) = (uint32_t)addr_dst;
+	RPC_U32(&msg, 16U) = (uint32_t)len;
+	RPC_U8(&msg, 20U) = (uint8_t)fw;
+	RPC_SIZE(&msg) = 7U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_authenticate(sc_ipc_t ipc,
+				   sc_misc_seco_auth_cmd_t cmd, sc_faddr_t addr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_AUTHENTICATE;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr;
+	RPC_U8(&msg, 8U) = (uint8_t)cmd;
+	RPC_SIZE(&msg) = 4U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_fuse_write(sc_ipc_t ipc, sc_faddr_t addr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_FUSE_WRITE;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_enable_debug(sc_ipc_t ipc, sc_faddr_t addr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_ENABLE_DEBUG;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_forward_lifecycle(sc_ipc_t ipc, uint32_t lifecycle)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_FORWARD_LIFECYCLE;
+	RPC_U32(&msg, 0U) = (uint32_t)lifecycle;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_return_lifecycle(sc_ipc_t ipc, sc_faddr_t addr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_RETURN_LIFECYCLE;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+void sc_misc_seco_build_info(sc_ipc_t ipc, uint32_t *version, uint32_t *commit)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_BUILD_INFO;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (version != NULL)
+		*version = RPC_U32(&msg, 0U);
+
+	if (commit != NULL)
+		*commit = RPC_U32(&msg, 4U);
+}
+
+sc_err_t sc_misc_seco_chip_info(sc_ipc_t ipc, uint16_t *lc,
+				uint16_t *monotonic, uint32_t *uid_l,
+				uint32_t *uid_h)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_CHIP_INFO;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (uid_l != NULL)
+		*uid_l = RPC_U32(&msg, 0U);
+
+	if (uid_h != NULL)
+		*uid_h = RPC_U32(&msg, 4U);
+
+	if (lc != NULL)
+		*lc = RPC_U16(&msg, 8U);
+
+	if (monotonic != NULL)
+		*monotonic = RPC_U16(&msg, 10U);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+void sc_misc_debug_out(sc_ipc_t ipc, uint8_t ch)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_DEBUG_OUT;
+	RPC_U8(&msg, 0U) = (uint8_t)ch;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+}
+
+sc_err_t sc_misc_waveform_capture(sc_ipc_t ipc, sc_bool_t enable)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_WAVEFORM_CAPTURE;
+	RPC_U8(&msg, 0U) = (uint8_t)enable;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+void sc_misc_build_info(sc_ipc_t ipc, uint32_t *build, uint32_t *commit)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BUILD_INFO;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (build != NULL)
+		*build = RPC_U32(&msg, 0U);
+
+	if (commit != NULL)
+		*commit = RPC_U32(&msg, 4U);
+}
+
+void sc_misc_unique_id(sc_ipc_t ipc, uint32_t *id_l, uint32_t *id_h)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_UNIQUE_ID;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (id_l != NULL)
+		*id_l = RPC_U32(&msg, 0U);
+
+	if (id_h != NULL)
+		*id_h = RPC_U32(&msg, 4U);
+}
+
+sc_err_t sc_misc_set_ari(sc_ipc_t ipc, sc_rsrc_t resource,
+			 sc_rsrc_t resource_mst, uint16_t ari, sc_bool_t enable)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_ARI;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U16(&msg, 2U) = (uint16_t)resource_mst;
+	RPC_U16(&msg, 4U) = (uint16_t)ari;
+	RPC_U8(&msg, 6U) = (uint8_t)enable;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BOOT_STATUS;
+	RPC_U8(&msg, 0U) = (uint8_t)status;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_TRUE);
+}
+
+sc_err_t sc_misc_boot_done(sc_ipc_t ipc, sc_rsrc_t cpu)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BOOT_DONE;
+	RPC_U16(&msg, 0U) = (uint16_t)cpu;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_otp_fuse_read(sc_ipc_t ipc, uint32_t word, uint32_t *val)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_OTP_FUSE_READ;
+	RPC_U32(&msg, 0U) = (uint32_t)word;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (val != NULL)
+		*val = RPC_U32(&msg, 0U);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_otp_fuse_write(sc_ipc_t ipc, uint32_t word, uint32_t val)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_OTP_FUSE_WRITE;
+	RPC_U32(&msg, 0U) = (uint32_t)word;
+	RPC_U32(&msg, 4U) = (uint32_t)val;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_set_temp(sc_ipc_t ipc, sc_rsrc_t resource,
+			  sc_misc_temp_t temp, int16_t celsius, int8_t tenths)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_TEMP;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_I16(&msg, 2U) = (int16_t) celsius;
+	RPC_U8(&msg, 4U) = (uint8_t)temp;
+	RPC_I8(&msg, 5U) = (int8_t) tenths;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource,
+			  sc_misc_temp_t temp, int16_t *celsius,
+			  int8_t *tenths)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_TEMP;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)temp;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (celsius != NULL)
+		*celsius = RPC_I16(&msg, 0U);
+
+	result = RPC_R8(&msg);
+	if (tenths != NULL)
+		*tenths = RPC_I8(&msg, 2U);
+
+	return (sc_err_t)result;
+}
+
+void sc_misc_get_boot_dev(sc_ipc_t ipc, sc_rsrc_t *dev)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_BOOT_DEV;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (dev != NULL)
+		*dev = RPC_U16(&msg, 0U);
+}
+
+void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+	RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_BUTTON_STATUS;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (status != NULL)
+		*status = RPC_U8(&msg, 0U);
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/misc/sci_misc_rpc.h b/plat/imx/common/sci/svc/misc/sci_misc_rpc.h
new file mode 100644
index 0000000..03b1a51
--- /dev/null
+++ b/plat/imx/common/sci/svc/misc/sci_misc_rpc.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the MISC RPC implementation.
+ *
+ * @addtogroup MISC_SVC
+ * @{
+ */
+
+#ifndef SC_MISC_RPC_H
+#define SC_MISC_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Defines for RPC MISC function calls
+ */
+/*@{*/
+#define MISC_FUNC_UNKNOWN 0	/* Unknown function */
+#define MISC_FUNC_SET_CONTROL 1U	/* Index for misc_set_control() RPC call */
+#define MISC_FUNC_GET_CONTROL 2U	/* Index for misc_get_control() RPC call */
+#define MISC_FUNC_SET_MAX_DMA_GROUP 4U	/* Index for misc_set_max_dma_group() RPC call */
+#define MISC_FUNC_SET_DMA_GROUP 5U	/* Index for misc_set_dma_group() RPC call */
+#define MISC_FUNC_SECO_IMAGE_LOAD 8U	/* Index for misc_seco_image_load() RPC call */
+#define MISC_FUNC_SECO_AUTHENTICATE 9U	/* Index for misc_seco_authenticate() RPC call */
+#define MISC_FUNC_SECO_FUSE_WRITE 20U	/* Index for misc_seco_fuse_write() RPC call */
+#define MISC_FUNC_SECO_ENABLE_DEBUG 21U	/* Index for misc_seco_enable_debug() RPC call */
+#define MISC_FUNC_SECO_FORWARD_LIFECYCLE 22U	/* Index for misc_seco_forward_lifecycle() RPC call */
+#define MISC_FUNC_SECO_RETURN_LIFECYCLE 23U	/* Index for misc_seco_return_lifecycle() RPC call */
+#define MISC_FUNC_SECO_BUILD_INFO 24U	/* Index for misc_seco_build_info() RPC call */
+#define MISC_FUNC_SECO_CHIP_INFO 25U	/* Index for misc_seco_chip_info() RPC call */
+#define MISC_FUNC_DEBUG_OUT 10U	/* Index for misc_debug_out() RPC call */
+#define MISC_FUNC_WAVEFORM_CAPTURE 6U	/* Index for misc_waveform_capture() RPC call */
+#define MISC_FUNC_BUILD_INFO 15U	/* Index for misc_build_info() RPC call */
+#define MISC_FUNC_UNIQUE_ID 19U	/* Index for misc_unique_id() RPC call */
+#define MISC_FUNC_SET_ARI 3U	/* Index for misc_set_ari() RPC call */
+#define MISC_FUNC_BOOT_STATUS 7U	/* Index for misc_boot_status() RPC call */
+#define MISC_FUNC_BOOT_DONE 14U	/* Index for misc_boot_done() RPC call */
+#define MISC_FUNC_OTP_FUSE_READ 11U	/* Index for misc_otp_fuse_read() RPC call */
+#define MISC_FUNC_OTP_FUSE_WRITE 17U	/* Index for misc_otp_fuse_write() RPC call */
+#define MISC_FUNC_SET_TEMP 12U	/* Index for misc_set_temp() RPC call */
+#define MISC_FUNC_GET_TEMP 13U	/* Index for misc_get_temp() RPC call */
+#define MISC_FUNC_GET_BOOT_DEV 16U	/* Index for misc_get_boot_dev() RPC call */
+#define MISC_FUNC_GET_BUTTON_STATUS 18U	/* Index for misc_get_button_status() RPC call */
+/*@}*/
+
+/* Types */
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming MISC RPC request.
+ *
+ * @param[in]     caller_pt   caller partition
+ * @param[in]     msg         pointer to RPC message
+ */
+void misc_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an MISC RPC request.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     msg         pointer to RPC message
+ */
+void misc_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif				/* SC_MISC_RPC_H */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c b/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c
new file mode 100644
index 0000000..319d469
--- /dev/null
+++ b/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * File containing client-side RPC functions for the PAD service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup PAD_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <stdlib.h>
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/pad/sci_pad_api.h>
+#include <sci/sci_rpc.h>
+#include "sci_pad_rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_pad_set_mux(sc_ipc_t ipc, sc_pad_t pad,
+			uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_MUX;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_U8(&msg, 2U) = (uint8_t)mux;
+	RPC_U8(&msg, 3U) = (uint8_t)config;
+	RPC_U8(&msg, 4U) = (uint8_t)iso;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_mux(sc_ipc_t ipc, sc_pad_t pad,
+			uint8_t *mux, sc_pad_config_t *config,
+			sc_pad_iso_t *iso)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_MUX;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (mux != NULL) {
+		*mux = RPC_U8(&msg, 0U);
+	}
+
+	if (config != NULL) {
+		*config = RPC_U8(&msg, 1U);
+	}
+
+	if (iso != NULL) {
+		*iso = RPC_U8(&msg, 2U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t ctrl)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP;
+	RPC_U32(&msg, 0U) = (uint32_t)ctrl;
+	RPC_U16(&msg, 4U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t *ctrl)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (ctrl != NULL) {
+		*ctrl = RPC_U32(&msg, 0U);
+	}
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t wakeup)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_WAKEUP;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_U8(&msg, 2U) = (uint8_t)wakeup;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t *wakeup)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_WAKEUP;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (wakeup != NULL) {
+		*wakeup = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux,
+			sc_pad_config_t config, sc_pad_iso_t iso, uint32_t ctrl,
+			sc_pad_wakeup_t wakeup)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_ALL;
+	RPC_U32(&msg, 0U) = (uint32_t)ctrl;
+	RPC_U16(&msg, 4U) = (uint16_t)pad;
+	RPC_U8(&msg, 6U) = (uint8_t)mux;
+	RPC_U8(&msg, 7U) = (uint8_t)config;
+	RPC_U8(&msg, 8U) = (uint8_t)iso;
+	RPC_U8(&msg, 9U) = (uint8_t)wakeup;
+	RPC_SIZE(&msg) = 4U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux,
+			sc_pad_config_t *config, sc_pad_iso_t *iso,
+			uint32_t *ctrl, sc_pad_wakeup_t *wakeup)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_ALL;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (ctrl != NULL) {
+		*ctrl = RPC_U32(&msg, 0U);
+	}
+
+	result = RPC_R8(&msg);
+	if (mux != NULL) {
+		*mux = RPC_U8(&msg, 4U);
+	}
+
+	if (config != NULL) {
+		*config = RPC_U8(&msg, 5U);
+	}
+
+	if (iso != NULL) {
+		*iso = RPC_U8(&msg, 6U);
+	}
+
+	if (wakeup != NULL) {
+		*wakeup = RPC_U8(&msg, 7U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, uint32_t val)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET;
+	RPC_U32(&msg, 0U) = (uint32_t)val;
+	RPC_U16(&msg, 4U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, uint32_t *val)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (val != NULL) {
+		*val = RPC_U32(&msg, 0U);
+	}
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad,
+			       sc_pad_28fdsoi_dse_t dse, sc_pad_28fdsoi_ps_t ps)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_U8(&msg, 2U) = (uint8_t)dse;
+	RPC_U8(&msg, 3U) = (uint8_t)ps;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad,
+			       sc_pad_28fdsoi_dse_t *dse,
+			       sc_pad_28fdsoi_ps_t *ps)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (dse != NULL) {
+		*dse = RPC_U8(&msg, 0U);
+	}
+
+	if (ps != NULL) {
+		*ps = RPC_U8(&msg, 1U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad,
+				    sc_pad_28fdsoi_dse_t dse, sc_bool_t hys,
+				    sc_pad_28fdsoi_pus_t pus, sc_bool_t pke,
+				    sc_bool_t pue)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI_HSIC;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_U8(&msg, 2U) = (uint8_t)dse;
+	RPC_U8(&msg, 3U) = (uint8_t)pus;
+	RPC_U8(&msg, 4U) = (uint8_t)hys;
+	RPC_U8(&msg, 5U) = (uint8_t)pke;
+	RPC_U8(&msg, 6U) = (uint8_t)pue;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad,
+				    sc_pad_28fdsoi_dse_t *dse, sc_bool_t *hys,
+				    sc_pad_28fdsoi_pus_t *pus, sc_bool_t *pke,
+				    sc_bool_t *pue)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI_HSIC;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (dse != NULL) {
+		*dse = RPC_U8(&msg, 0U);
+	}
+
+	if (pus != NULL) {
+		*pus = RPC_U8(&msg, 1U);
+	}
+
+	if (hys != NULL) {
+		*hys = RPC_U8(&msg, 2U);
+	}
+
+	if (pke != NULL) {
+		*pke = RPC_U8(&msg, 3U);
+	}
+
+	if (pue != NULL) {
+		*pue = RPC_U8(&msg, 4U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad,
+				    uint8_t compen, sc_bool_t fastfrz,
+				    uint8_t rasrcp, uint8_t rasrcn,
+				    sc_bool_t nasrc_sel, sc_bool_t psw_ovr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI_COMP;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_U8(&msg, 2U) = (uint8_t)compen;
+	RPC_U8(&msg, 3U) = (uint8_t)rasrcp;
+	RPC_U8(&msg, 4U) = (uint8_t)rasrcn;
+	RPC_U8(&msg, 5U) = (uint8_t)fastfrz;
+	RPC_U8(&msg, 6U) = (uint8_t)nasrc_sel;
+	RPC_U8(&msg, 7U) = (uint8_t)psw_ovr;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad,
+				    uint8_t *compen, sc_bool_t *fastfrz,
+				    uint8_t *rasrcp, uint8_t *rasrcn,
+				    sc_bool_t *nasrc_sel, sc_bool_t *compok,
+				    uint8_t *nasrc, sc_bool_t *psw_ovr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+	RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI_COMP;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (compen != NULL) {
+		*compen = RPC_U8(&msg, 0U);
+	}
+
+	if (rasrcp != NULL) {
+		*rasrcp = RPC_U8(&msg, 1U);
+	}
+
+	if (rasrcn != NULL) {
+		*rasrcn = RPC_U8(&msg, 2U);
+	}
+
+	if (nasrc != NULL) {
+		*nasrc = RPC_U8(&msg, 3U);
+	}
+
+	if (fastfrz != NULL) {
+		*fastfrz = RPC_U8(&msg, 4U);
+	}
+
+	if (nasrc_sel != NULL) {
+		*nasrc_sel = RPC_U8(&msg, 5U);
+	}
+
+	if (compok != NULL) {
+		*compok = RPC_U8(&msg, 6U);
+	}
+
+	if (psw_ovr != NULL) {
+		*psw_ovr = RPC_U8(&msg, 7U);
+	}
+
+	return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pad/sci_pad_rpc.h b/plat/imx/common/sci/svc/pad/sci_pad_rpc.h
new file mode 100644
index 0000000..8e9c4bb
--- /dev/null
+++ b/plat/imx/common/sci/svc/pad/sci_pad_rpc.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the PAD RPC implementation.
+ *
+ * @addtogroup PAD_SVC
+ * @{
+ */
+
+#ifndef SCI_PAD_RPC_H
+#define SCI_PAD_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Defines for RPC PAD function calls
+ */
+/*@{*/
+#define PAD_FUNC_UNKNOWN 0	/* Unknown function */
+#define PAD_FUNC_SET_MUX 1U	/* Index for pad_set_mux() RPC call */
+#define PAD_FUNC_GET_MUX 6U	/* Index for pad_get_mux() RPC call */
+#define PAD_FUNC_SET_GP 2U	/* Index for pad_set_gp() RPC call */
+#define PAD_FUNC_GET_GP 7U	/* Index for pad_get_gp() RPC call */
+#define PAD_FUNC_SET_WAKEUP 4U	/* Index for pad_set_wakeup() RPC call */
+#define PAD_FUNC_GET_WAKEUP 9U	/* Index for pad_get_wakeup() RPC call */
+#define PAD_FUNC_SET_ALL 5U	/* Index for pad_set_all() RPC call */
+#define PAD_FUNC_GET_ALL 10U	/* Index for pad_get_all() RPC call */
+#define PAD_FUNC_SET 15U	/* Index for pad_set() RPC call */
+#define PAD_FUNC_GET 16U	/* Index for pad_get() RPC call */
+#define PAD_FUNC_SET_GP_28FDSOI 11U	/* Index for pad_set_gp_28fdsoi() RPC call */
+#define PAD_FUNC_GET_GP_28FDSOI 12U	/* Index for pad_get_gp_28fdsoi() RPC call */
+#define PAD_FUNC_SET_GP_28FDSOI_HSIC 3U	/* Index for pad_set_gp_28fdsoi_hsic() RPC call */
+#define PAD_FUNC_GET_GP_28FDSOI_HSIC 8U	/* Index for pad_get_gp_28fdsoi_hsic() RPC call */
+#define PAD_FUNC_SET_GP_28FDSOI_COMP 13U	/* Index for pad_set_gp_28fdsoi_comp() RPC call */
+#define PAD_FUNC_GET_GP_28FDSOI_COMP 14U	/* Index for pad_get_gp_28fdsoi_comp() RPC call */
+/*@}*/
+
+/* Types */
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming PAD RPC request.
+ *
+ * @param[in]     caller_pt   caller partition
+ * @param[in]     msg         pointer to RPC message
+ */
+void pad_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an PAD RPC request.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     msg         pointer to RPC message
+ */
+void pad_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* SCI_PAD_RPC_H */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c b/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c
new file mode 100644
index 0000000..66a57a1
--- /dev/null
+++ b/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * File containing client-side RPC functions for the PM service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup PM_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <stdlib.h>
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/pm/sci_pm_api.h>
+#include <sci/sci_rpc.h>
+
+#include "sci_pm_rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_pm_set_sys_power_mode(sc_ipc_t ipc, sc_pm_power_mode_t mode)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_SYS_POWER_MODE;
+	RPC_U8(&msg, 0U) = (uint8_t)mode;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_partition_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt,
+					sc_pm_power_mode_t mode)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_PARTITION_POWER_MODE;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)mode;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_sys_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt,
+				  sc_pm_power_mode_t *mode)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_SYS_POWER_MODE;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (mode != NULL) {
+		*mode = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				       sc_pm_power_mode_t mode)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_RESOURCE_POWER_MODE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)mode;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				       sc_pm_power_mode_t *mode)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_RESOURCE_POWER_MODE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (mode != NULL) {
+		*mode = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_req_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				  sc_pm_power_mode_t mode)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_LOW_POWER_MODE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)mode;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_req_cpu_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				      sc_pm_power_mode_t mode,
+				      sc_pm_wake_src_t wake_src)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_CPU_LOW_POWER_MODE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)mode;
+	RPC_U8(&msg, 3U) = (uint8_t)wake_src;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_cpu_resume_addr(sc_ipc_t ipc, sc_rsrc_t resource,
+				   sc_faddr_t address)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CPU_RESUME_ADDR;
+	RPC_U32(&msg, 0U) = (uint32_t)(address >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)address;
+	RPC_U16(&msg, 8U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 4U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_cpu_resume(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_bool_t isPrimary, sc_faddr_t address)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CPU_RESUME;
+	RPC_U32(&msg, 0U) = (uint32_t)(address >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)address;
+	RPC_U16(&msg, 8U) = (uint16_t)resource;
+	RPC_U8(&msg, 10U) = (uint8_t)isPrimary;
+	RPC_SIZE(&msg) = 4U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_req_sys_if_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+				     sc_pm_sys_if_t sys_if,
+				     sc_pm_power_mode_t hpm,
+				     sc_pm_power_mode_t lpm)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_SYS_IF_POWER_MODE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)sys_if;
+	RPC_U8(&msg, 3U) = (uint8_t)hpm;
+	RPC_U8(&msg, 4U) = (uint8_t)lpm;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_pm_clk_t clk, sc_pm_clock_rate_t *rate)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CLOCK_RATE;
+	RPC_U32(&msg, 0U) = *(uint32_t *)rate;
+	RPC_U16(&msg, 4U) = (uint16_t)resource;
+	RPC_U8(&msg, 6U) = (uint8_t)clk;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	*rate = RPC_U32(&msg, 0U);
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource,
+			      sc_pm_clk_t clk, sc_pm_clock_rate_t *rate)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_CLOCK_RATE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)clk;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (rate != NULL) {
+		*rate = RPC_U32(&msg, 0U);
+	}
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_clock_enable(sc_ipc_t ipc, sc_rsrc_t resource,
+			    sc_pm_clk_t clk, sc_bool_t enable, sc_bool_t autog)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_CLOCK_ENABLE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)clk;
+	RPC_U8(&msg, 3U) = (uint8_t)enable;
+	RPC_U8(&msg, 4U) = (uint8_t)autog;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource,
+				sc_pm_clk_t clk, sc_pm_clk_parent_t parent)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CLOCK_PARENT;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)clk;
+	RPC_U8(&msg, 3U) = (uint8_t)parent;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource,
+				sc_pm_clk_t clk, sc_pm_clk_parent_t *parent)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_CLOCK_PARENT;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)clk;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (parent != NULL) {
+		*parent = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_reset(sc_ipc_t ipc, sc_pm_reset_type_t type)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_RESET;
+	RPC_U8(&msg, 0U) = (uint8_t)type;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_reset_reason(sc_ipc_t ipc, sc_pm_reset_reason_t *reason)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_RESET_REASON;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (reason != NULL) {
+		*reason = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_boot(sc_ipc_t ipc, sc_rm_pt_t pt,
+		    sc_rsrc_t resource_cpu, sc_faddr_t boot_addr,
+		    sc_rsrc_t resource_mu, sc_rsrc_t resource_dev)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_BOOT;
+	RPC_U32(&msg, 0U) = (uint32_t)(boot_addr >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)boot_addr;
+	RPC_U16(&msg, 8U) = (uint16_t)resource_cpu;
+	RPC_U16(&msg, 10U) = (uint16_t)resource_mu;
+	RPC_U16(&msg, 12U) = (uint16_t)resource_dev;
+	RPC_U8(&msg, 14U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 5U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REBOOT;
+	RPC_U8(&msg, 0U) = (uint8_t)type;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_TRUE);
+
+	return;
+}
+
+sc_err_t sc_pm_reboot_partition(sc_ipc_t ipc, sc_rm_pt_t pt,
+				sc_pm_reset_type_t type)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REBOOT_PARTITION;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)type;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_cpu_start(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t enable,
+			 sc_faddr_t address)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+	RPC_FUNC(&msg) = (uint8_t)PM_FUNC_CPU_START;
+	RPC_U32(&msg, 0U) = (uint32_t)(address >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)address;
+	RPC_U16(&msg, 8U) = (uint16_t)resource;
+	RPC_U8(&msg, 10U) = (uint8_t)enable;
+	RPC_SIZE(&msg) = 4U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/pm/sci_pm_rpc.h b/plat/imx/common/sci/svc/pm/sci_pm_rpc.h
new file mode 100644
index 0000000..8bad3c7
--- /dev/null
+++ b/plat/imx/common/sci/svc/pm/sci_pm_rpc.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the PM RPC implementation.
+ *
+ * @addtogroup PM_SVC
+ * @{
+ */
+
+#ifndef SCI_PM_RPC_H
+#define SCI_PM_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Defines for RPC PM function calls
+ */
+/*@{*/
+#define PM_FUNC_UNKNOWN 0	/* Unknown function */
+#define PM_FUNC_SET_SYS_POWER_MODE 19U	/* Index for pm_set_sys_power_mode() RPC call */
+#define PM_FUNC_SET_PARTITION_POWER_MODE 1U	/* Index for pm_set_partition_power_mode() RPC call */
+#define PM_FUNC_GET_SYS_POWER_MODE 2U	/* Index for pm_get_sys_power_mode() RPC call */
+#define PM_FUNC_SET_RESOURCE_POWER_MODE 3U	/* Index for pm_set_resource_power_mode() RPC call */
+#define PM_FUNC_GET_RESOURCE_POWER_MODE 4U	/* Index for pm_get_resource_power_mode() RPC call */
+#define PM_FUNC_REQ_LOW_POWER_MODE 16U	/* Index for pm_req_low_power_mode() RPC call */
+#define PM_FUNC_REQ_CPU_LOW_POWER_MODE 20U	/* Index for pm_req_cpu_low_power_mode() RPC call */
+#define PM_FUNC_SET_CPU_RESUME_ADDR 17U	/* Index for pm_set_cpu_resume_addr() RPC call */
+#define PM_FUNC_SET_CPU_RESUME 21U	/* Index for pm_set_cpu_resume() RPC call */
+#define PM_FUNC_REQ_SYS_IF_POWER_MODE 18U	/* Index for pm_req_sys_if_power_mode() RPC call */
+#define PM_FUNC_SET_CLOCK_RATE 5U	/* Index for pm_set_clock_rate() RPC call */
+#define PM_FUNC_GET_CLOCK_RATE 6U	/* Index for pm_get_clock_rate() RPC call */
+#define PM_FUNC_CLOCK_ENABLE 7U	/* Index for pm_clock_enable() RPC call */
+#define PM_FUNC_SET_CLOCK_PARENT 14U	/* Index for pm_set_clock_parent() RPC call */
+#define PM_FUNC_GET_CLOCK_PARENT 15U	/* Index for pm_get_clock_parent() RPC call */
+#define PM_FUNC_RESET 13U	/* Index for pm_reset() RPC call */
+#define PM_FUNC_RESET_REASON 10U	/* Index for pm_reset_reason() RPC call */
+#define PM_FUNC_BOOT 8U		/* Index for pm_boot() RPC call */
+#define PM_FUNC_REBOOT 9U	/* Index for pm_reboot() RPC call */
+#define PM_FUNC_REBOOT_PARTITION 12U	/* Index for pm_reboot_partition() RPC call */
+#define PM_FUNC_CPU_START 11U	/* Index for pm_cpu_start() RPC call */
+/*@}*/
+
+/* Types */
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming PM RPC request.
+ *
+ * @param[in]     caller_pt   caller partition
+ * @param[in]     msg         pointer to RPC message
+ */
+void pm_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an PM RPC request.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     msg         pointer to RPC message
+ */
+void pm_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* SCI_PM_RPC_H */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c b/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c
new file mode 100644
index 0000000..16771a5
--- /dev/null
+++ b/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * File containing client-side RPC functions for the RM service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup RM_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <stdlib.h>
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/sci_rpc.h>
+
+#include "sci_rm_rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_rm_partition_alloc(sc_ipc_t ipc, sc_rm_pt_t *pt, sc_bool_t secure,
+			       sc_bool_t isolated, sc_bool_t restricted,
+			       sc_bool_t grant, sc_bool_t coherent)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_ALLOC;
+	RPC_U8(&msg, 0U) = (uint8_t)secure;
+	RPC_U8(&msg, 1U) = (uint8_t)isolated;
+	RPC_U8(&msg, 2U) = (uint8_t)restricted;
+	RPC_U8(&msg, 3U) = (uint8_t)grant;
+	RPC_U8(&msg, 4U) = (uint8_t)coherent;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (pt != NULL) {
+		*pt = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_confidential(sc_ipc_t ipc, sc_rm_pt_t pt, sc_bool_t retro)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_CONFIDENTIAL;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)retro;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_partition_free(sc_ipc_t ipc, sc_rm_pt_t pt)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_FREE;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_rm_did_t sc_rm_get_did(sc_ipc_t ipc)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_DID;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_rm_did_t) result;
+}
+
+sc_err_t sc_rm_partition_static(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_did_t did)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_STATIC;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)did;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_partition_lock(sc_ipc_t ipc, sc_rm_pt_t pt)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_LOCK;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_get_partition(sc_ipc_t ipc, sc_rm_pt_t *pt)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_PARTITION;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (pt != NULL) {
+		*pt = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_parent(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_pt_t pt_parent)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PARENT;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)pt_parent;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_move_all(sc_ipc_t ipc, sc_rm_pt_t pt_src, sc_rm_pt_t pt_dst,
+			sc_bool_t move_rsrc, sc_bool_t move_pads)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MOVE_ALL;
+	RPC_U8(&msg, 0U) = (uint8_t)pt_src;
+	RPC_U8(&msg, 1U) = (uint8_t)pt_dst;
+	RPC_U8(&msg, 2U) = (uint8_t)move_rsrc;
+	RPC_U8(&msg, 3U) = (uint8_t)move_pads;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_assign_resource(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_RESOURCE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_resource_movable(sc_ipc_t ipc, sc_rsrc_t resource_fst,
+				    sc_rsrc_t resource_lst, sc_bool_t movable)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_RESOURCE_MOVABLE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource_fst;
+	RPC_U16(&msg, 2U) = (uint16_t)resource_lst;
+	RPC_U8(&msg, 4U) = (uint8_t)movable;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_subsys_rsrc_movable(sc_ipc_t ipc, sc_rsrc_t resource,
+				       sc_bool_t movable)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_SUBSYS_RSRC_MOVABLE;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)movable;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_master_attributes(sc_ipc_t ipc, sc_rsrc_t resource,
+				     sc_rm_spa_t sa, sc_rm_spa_t pa,
+				     sc_bool_t smmu_bypass)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MASTER_ATTRIBUTES;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)sa;
+	RPC_U8(&msg, 3U) = (uint8_t)pa;
+	RPC_U8(&msg, 4U) = (uint8_t)smmu_bypass;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t sid)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MASTER_SID;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U16(&msg, 2U) = (uint16_t)sid;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_peripheral_permissions(sc_ipc_t ipc, sc_rsrc_t resource,
+					  sc_rm_pt_t pt, sc_rm_perm_t perm)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PERIPHERAL_PERMISSIONS;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_U8(&msg, 2U) = (uint8_t)pt;
+	RPC_U8(&msg, 3U) = (uint8_t)perm;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_bool_t sc_rm_is_resource_owned(sc_ipc_t ipc, sc_rsrc_t resource)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_OWNED;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_bool_t)result;
+}
+
+sc_bool_t sc_rm_is_resource_master(sc_ipc_t ipc, sc_rsrc_t resource)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_MASTER;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_bool_t)result;
+}
+
+sc_bool_t sc_rm_is_resource_peripheral(sc_ipc_t ipc, sc_rsrc_t resource)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_PERIPHERAL;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_bool_t)result;
+}
+
+sc_err_t sc_rm_get_resource_info(sc_ipc_t ipc, sc_rsrc_t resource,
+				 sc_rm_sid_t *sid)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_RESOURCE_INFO;
+	RPC_U16(&msg, 0U) = (uint16_t)resource;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (sid != NULL) {
+		*sid = RPC_U16(&msg, 0U);
+	}
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_memreg_alloc(sc_ipc_t ipc, sc_rm_mr_t *mr,
+			    sc_faddr_t addr_start, sc_faddr_t addr_end)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_ALLOC;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr_start >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr_start;
+	RPC_U32(&msg, 8U) = (uint32_t)(addr_end >> 32U);
+	RPC_U32(&msg, 12U) = (uint32_t)addr_end;
+	RPC_SIZE(&msg) = 5U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (mr != NULL) {
+		*mr = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_memreg_split(sc_ipc_t ipc, sc_rm_mr_t mr,
+			    sc_rm_mr_t *mr_ret, sc_faddr_t addr_start,
+			    sc_faddr_t addr_end)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_SPLIT;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr_start >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr_start;
+	RPC_U32(&msg, 8U) = (uint32_t)(addr_end >> 32U);
+	RPC_U32(&msg, 12U) = (uint32_t)addr_end;
+	RPC_U8(&msg, 16U) = (uint8_t)mr;
+	RPC_SIZE(&msg) = 6U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (mr_ret != NULL) {
+		*mr_ret = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_memreg_free(sc_ipc_t ipc, sc_rm_mr_t mr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_FREE;
+	RPC_U8(&msg, 0U) = (uint8_t)mr;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_find_memreg(sc_ipc_t ipc, sc_rm_mr_t *mr,
+			   sc_faddr_t addr_start, sc_faddr_t addr_end)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_FIND_MEMREG;
+	RPC_U32(&msg, 0U) = (uint32_t)(addr_start >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)addr_start;
+	RPC_U32(&msg, 8U) = (uint32_t)(addr_end >> 32U);
+	RPC_U32(&msg, 12U) = (uint32_t)addr_end;
+	RPC_SIZE(&msg) = 5U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	if (mr != NULL) {
+		*mr = RPC_U8(&msg, 0U);
+	}
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_assign_memreg(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_mr_t mr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_MEMREG;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)mr;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_memreg_permissions(sc_ipc_t ipc, sc_rm_mr_t mr,
+				      sc_rm_pt_t pt, sc_rm_perm_t perm)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MEMREG_PERMISSIONS;
+	RPC_U8(&msg, 0U) = (uint8_t)mr;
+	RPC_U8(&msg, 1U) = (uint8_t)pt;
+	RPC_U8(&msg, 2U) = (uint8_t)perm;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_MEMREG_OWNED;
+	RPC_U8(&msg, 0U) = (uint8_t)mr;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_bool_t)result;
+}
+
+sc_err_t sc_rm_get_memreg_info(sc_ipc_t ipc, sc_rm_mr_t mr,
+			       sc_faddr_t *addr_start, sc_faddr_t *addr_end)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_MEMREG_INFO;
+	RPC_U8(&msg, 0U) = (uint8_t)mr;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (addr_start != NULL) {
+		*addr_start =
+		    ((uint64_t) RPC_U32(&msg, 0U) << 32U) | RPC_U32(&msg, 4U);
+	}
+
+	if (addr_end != NULL) {
+		*addr_end =
+		    ((uint64_t) RPC_U32(&msg, 8U) << 32U) | RPC_U32(&msg, 12U);
+	}
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_assign_pad(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pad_t pad)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_PAD;
+	RPC_U16(&msg, 0U) = (uint16_t)pad;
+	RPC_U8(&msg, 2U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_pad_movable(sc_ipc_t ipc, sc_pad_t pad_fst,
+			       sc_pad_t pad_lst, sc_bool_t movable)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PAD_MOVABLE;
+	RPC_U16(&msg, 0U) = (uint16_t)pad_fst;
+	RPC_U16(&msg, 2U) = (uint16_t)pad_lst;
+	RPC_U8(&msg, 4U) = (uint8_t)movable;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_bool_t sc_rm_is_pad_owned(sc_ipc_t ipc, sc_pad_t pad)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_PAD_OWNED;
+	RPC_U8(&msg, 0U) = (uint8_t)pad;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_bool_t)result;
+}
+
+void sc_rm_dump(sc_ipc_t ipc)
+{
+	sc_rpc_msg_t msg;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+	RPC_FUNC(&msg) = (uint8_t)RM_FUNC_DUMP;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	return;
+}
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/rm/sci_rm_rpc.h b/plat/imx/common/sci/svc/rm/sci_rm_rpc.h
new file mode 100644
index 0000000..45d05f9
--- /dev/null
+++ b/plat/imx/common/sci/svc/rm/sci_rm_rpc.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the RM RPC implementation.
+ *
+ * @addtogroup RM_SVC
+ * @{
+ */
+
+#ifndef SCI_RM_RPC_H
+#define SCI_RM_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Defines for RPC RM function calls
+ */
+/*@{*/
+#define RM_FUNC_UNKNOWN 0	/* Unknown function */
+#define RM_FUNC_PARTITION_ALLOC 1U	/* Index for rm_partition_alloc() RPC call */
+#define RM_FUNC_SET_CONFIDENTIAL 31U	/* Index for rm_set_confidential() RPC call */
+#define RM_FUNC_PARTITION_FREE 2U	/* Index for rm_partition_free() RPC call */
+#define RM_FUNC_GET_DID 26U	/* Index for rm_get_did() RPC call */
+#define RM_FUNC_PARTITION_STATIC 3U	/* Index for rm_partition_static() RPC call */
+#define RM_FUNC_PARTITION_LOCK 4U	/* Index for rm_partition_lock() RPC call */
+#define RM_FUNC_GET_PARTITION 5U	/* Index for rm_get_partition() RPC call */
+#define RM_FUNC_SET_PARENT 6U	/* Index for rm_set_parent() RPC call */
+#define RM_FUNC_MOVE_ALL 7U	/* Index for rm_move_all() RPC call */
+#define RM_FUNC_ASSIGN_RESOURCE 8U	/* Index for rm_assign_resource() RPC call */
+#define RM_FUNC_SET_RESOURCE_MOVABLE 9U	/* Index for rm_set_resource_movable() RPC call */
+#define RM_FUNC_SET_SUBSYS_RSRC_MOVABLE 28U	/* Index for rm_set_subsys_rsrc_movable() RPC call */
+#define RM_FUNC_SET_MASTER_ATTRIBUTES 10U	/* Index for rm_set_master_attributes() RPC call */
+#define RM_FUNC_SET_MASTER_SID 11U	/* Index for rm_set_master_sid() RPC call */
+#define RM_FUNC_SET_PERIPHERAL_PERMISSIONS 12U	/* Index for rm_set_peripheral_permissions() RPC call */
+#define RM_FUNC_IS_RESOURCE_OWNED 13U	/* Index for rm_is_resource_owned() RPC call */
+#define RM_FUNC_IS_RESOURCE_MASTER 14U	/* Index for rm_is_resource_master() RPC call */
+#define RM_FUNC_IS_RESOURCE_PERIPHERAL 15U	/* Index for rm_is_resource_peripheral() RPC call */
+#define RM_FUNC_GET_RESOURCE_INFO 16U	/* Index for rm_get_resource_info() RPC call */
+#define RM_FUNC_MEMREG_ALLOC 17U	/* Index for rm_memreg_alloc() RPC call */
+#define RM_FUNC_MEMREG_SPLIT 29U	/* Index for rm_memreg_split() RPC call */
+#define RM_FUNC_MEMREG_FREE 18U	/* Index for rm_memreg_free() RPC call */
+#define RM_FUNC_FIND_MEMREG 30U	/* Index for rm_find_memreg() RPC call */
+#define RM_FUNC_ASSIGN_MEMREG 19U	/* Index for rm_assign_memreg() RPC call */
+#define RM_FUNC_SET_MEMREG_PERMISSIONS 20U	/* Index for rm_set_memreg_permissions() RPC call */
+#define RM_FUNC_IS_MEMREG_OWNED 21U	/* Index for rm_is_memreg_owned() RPC call */
+#define RM_FUNC_GET_MEMREG_INFO 22U	/* Index for rm_get_memreg_info() RPC call */
+#define RM_FUNC_ASSIGN_PAD 23U	/* Index for rm_assign_pad() RPC call */
+#define RM_FUNC_SET_PAD_MOVABLE 24U	/* Index for rm_set_pad_movable() RPC call */
+#define RM_FUNC_IS_PAD_OWNED 25U	/* Index for rm_is_pad_owned() RPC call */
+#define RM_FUNC_DUMP 27U	/* Index for rm_dump() RPC call */
+/*@}*/
+
+/* Types */
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming RM RPC request.
+ *
+ * @param[in]     caller_pt   caller partition
+ * @param[in]     msg         pointer to RPC message
+ */
+void rm_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an RM RPC request.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     msg         pointer to RPC message
+ */
+void rm_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* SCI_RM_RPC_H */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/timer/sci_timer_rpc.h b/plat/imx/common/sci/svc/timer/sci_timer_rpc.h
new file mode 100644
index 0000000..6716399
--- /dev/null
+++ b/plat/imx/common/sci/svc/timer/sci_timer_rpc.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * Header file for the TIMER RPC implementation.
+ *
+ * @addtogroup TIMER_SVC
+ * @{
+ */
+
+#ifndef SC_TIMER_RPC_H
+#define SC_TIMER_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/*!
+ * @name Defines for RPC TIMER function calls
+ */
+/*@{*/
+#define TIMER_FUNC_UNKNOWN 0	/* Unknown function */
+#define TIMER_FUNC_SET_WDOG_TIMEOUT 1U	/* Index for timer_set_wdog_timeout() RPC call */
+#define TIMER_FUNC_SET_WDOG_PRE_TIMEOUT 12U	/* Index for timer_set_wdog_pre_timeout() RPC call */
+#define TIMER_FUNC_START_WDOG 2U	/* Index for timer_start_wdog() RPC call */
+#define TIMER_FUNC_STOP_WDOG 3U	/* Index for timer_stop_wdog() RPC call */
+#define TIMER_FUNC_PING_WDOG 4U	/* Index for timer_ping_wdog() RPC call */
+#define TIMER_FUNC_GET_WDOG_STATUS 5U	/* Index for timer_get_wdog_status() RPC call */
+#define TIMER_FUNC_PT_GET_WDOG_STATUS 13U	/* Index for timer_pt_get_wdog_status() RPC call */
+#define TIMER_FUNC_SET_WDOG_ACTION 10U	/* Index for timer_set_wdog_action() RPC call */
+#define TIMER_FUNC_SET_RTC_TIME 6U	/* Index for timer_set_rtc_time() RPC call */
+#define TIMER_FUNC_GET_RTC_TIME 7U	/* Index for timer_get_rtc_time() RPC call */
+#define TIMER_FUNC_GET_RTC_SEC1970 9U	/* Index for timer_get_rtc_sec1970() RPC call */
+#define TIMER_FUNC_SET_RTC_ALARM 8U	/* Index for timer_set_rtc_alarm() RPC call */
+#define TIMER_FUNC_SET_RTC_PERIODIC_ALARM 14U	/* Index for timer_set_rtc_periodic_alarm() RPC call */
+#define TIMER_FUNC_CANCEL_RTC_ALARM 15U	/* Index for timer_cancel_rtc_alarm() RPC call */
+#define TIMER_FUNC_SET_RTC_CALB 11U	/* Index for timer_set_rtc_calb() RPC call */
+#define TIMER_FUNC_SET_SYSCTR_ALARM 16U	/* Index for timer_set_sysctr_alarm() RPC call */
+#define TIMER_FUNC_SET_SYSCTR_PERIODIC_ALARM 17U	/* Index for timer_set_sysctr_periodic_alarm() RPC call */
+#define TIMER_FUNC_CANCEL_SYSCTR_ALARM 18U	/* Index for timer_cancel_sysctr_alarm() RPC call */
+/*@}*/
+
+/* Types */
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming TIMER RPC request.
+ *
+ * @param[in]     caller_pt   caller partition
+ * @param[in]     msg         pointer to RPC message
+ */
+void timer_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an TIMER RPC request.
+ *
+ * @param[in]     ipc         IPC handle
+ * @param[in]     msg         pointer to RPC message
+ */
+void timer_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif				/* SC_TIMER_RPC_H */
+
+/**@}*/
diff --git a/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c b/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c
new file mode 100644
index 0000000..a82be96
--- /dev/null
+++ b/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*!
+ * File containing client-side RPC functions for the TIMER service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup TIMER_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <sci/sci_types.h>
+#include <sci/svc/rm/sci_rm_api.h>
+#include <sci/svc/timer/sci_timer_api.h>
+#include <sci/sci_rpc.h>
+#include <stdlib.h>
+#include "sci_timer_rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_timer_set_wdog_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t timeout)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_TIMEOUT;
+	RPC_U32(&msg, 0U) = (uint32_t)timeout;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_wdog_pre_timeout(sc_ipc_t ipc,
+				       sc_timer_wdog_time_t pre_timeout)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_PRE_TIMEOUT;
+	RPC_U32(&msg, 0U) = (uint32_t)pre_timeout;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_start_wdog(sc_ipc_t ipc, sc_bool_t lock)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_START_WDOG;
+	RPC_U8(&msg, 0U) = (uint8_t)lock;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_stop_wdog(sc_ipc_t ipc)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_STOP_WDOG;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_ping_wdog(sc_ipc_t ipc)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_PING_WDOG;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_get_wdog_status(sc_ipc_t ipc,
+				  sc_timer_wdog_time_t *timeout,
+				  sc_timer_wdog_time_t *max_timeout,
+				  sc_timer_wdog_time_t *remaining_time)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_WDOG_STATUS;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (timeout != NULL)
+		*timeout = RPC_U32(&msg, 0U);
+
+	if (max_timeout != NULL)
+		*max_timeout = RPC_U32(&msg, 4U);
+
+	if (remaining_time != NULL)
+		*remaining_time = RPC_U32(&msg, 8U);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_pt_get_wdog_status(sc_ipc_t ipc, sc_rm_pt_t pt,
+				     sc_bool_t *enb,
+				     sc_timer_wdog_time_t *timeout,
+				     sc_timer_wdog_time_t *remaining_time)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_PT_GET_WDOG_STATUS;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (timeout != NULL)
+		*timeout = RPC_U32(&msg, 0U);
+
+	if (remaining_time != NULL)
+		*remaining_time = RPC_U32(&msg, 4U);
+
+	result = RPC_R8(&msg);
+	if (enb != NULL)
+		*enb = RPC_U8(&msg, 8U);
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_wdog_action(sc_ipc_t ipc,
+				  sc_rm_pt_t pt, sc_timer_wdog_action_t action)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_ACTION;
+	RPC_U8(&msg, 0U) = (uint8_t)pt;
+	RPC_U8(&msg, 1U) = (uint8_t)action;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_time(sc_ipc_t ipc, uint16_t year, uint8_t mon,
+			       uint8_t day, uint8_t hour, uint8_t min,
+			       uint8_t sec)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_TIME;
+	RPC_U16(&msg, 0U) = (uint16_t)year;
+	RPC_U8(&msg, 2U) = (uint8_t)mon;
+	RPC_U8(&msg, 3U) = (uint8_t)day;
+	RPC_U8(&msg, 4U) = (uint8_t)hour;
+	RPC_U8(&msg, 5U) = (uint8_t)min;
+	RPC_U8(&msg, 6U) = (uint8_t)sec;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_get_rtc_time(sc_ipc_t ipc, uint16_t *year, uint8_t *mon,
+			       uint8_t *day, uint8_t *hour, uint8_t *min,
+			       uint8_t *sec)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_RTC_TIME;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (year != NULL)
+		*year = RPC_U16(&msg, 0U);
+
+	result = RPC_R8(&msg);
+	if (mon != NULL)
+		*mon = RPC_U8(&msg, 2U);
+
+	if (day != NULL)
+		*day = RPC_U8(&msg, 3U);
+
+	if (hour != NULL)
+		*hour = RPC_U8(&msg, 4U);
+
+	if (min != NULL)
+		*min = RPC_U8(&msg, 5U);
+
+	if (sec != NULL)
+		*sec = RPC_U8(&msg, 6U);
+
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_get_rtc_sec1970(sc_ipc_t ipc, uint32_t *sec)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_RTC_SEC1970;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	if (sec != NULL)
+		*sec = RPC_U32(&msg, 0U);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_alarm(sc_ipc_t ipc, uint16_t year, uint8_t mon,
+				uint8_t day, uint8_t hour, uint8_t min,
+				uint8_t sec)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_ALARM;
+	RPC_U16(&msg, 0U) = (uint16_t)year;
+	RPC_U8(&msg, 2U) = (uint8_t)mon;
+	RPC_U8(&msg, 3U) = (uint8_t)day;
+	RPC_U8(&msg, 4U) = (uint8_t)hour;
+	RPC_U8(&msg, 5U) = (uint8_t)min;
+	RPC_U8(&msg, 6U) = (uint8_t)sec;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_periodic_alarm(sc_ipc_t ipc, uint32_t sec)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_PERIODIC_ALARM;
+	RPC_U32(&msg, 0U) = (uint32_t)sec;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_cancel_rtc_alarm(sc_ipc_t ipc)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_CANCEL_RTC_ALARM;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_calb(sc_ipc_t ipc, int8_t count)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_CALB;
+	RPC_I8(&msg, 0U) = (int8_t) count;
+	RPC_SIZE(&msg) = 2U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_sysctr_alarm(sc_ipc_t ipc, uint64_t ticks)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_SYSCTR_ALARM;
+	RPC_U32(&msg, 0U) = (uint32_t)(ticks >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)ticks;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_sysctr_periodic_alarm(sc_ipc_t ipc, uint64_t ticks)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_SYSCTR_PERIODIC_ALARM;
+	RPC_U32(&msg, 0U) = (uint32_t)(ticks >> 32U);
+	RPC_U32(&msg, 4U) = (uint32_t)ticks;
+	RPC_SIZE(&msg) = 3U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_cancel_sysctr_alarm(sc_ipc_t ipc)
+{
+	sc_rpc_msg_t msg;
+	uint8_t result;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+	RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_CANCEL_SYSCTR_ALARM;
+	RPC_SIZE(&msg) = 1U;
+
+	sc_call_rpc(ipc, &msg, SC_FALSE);
+
+	result = RPC_R8(&msg);
+	return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/plat/imx/imx7/common/imx7.mk b/plat/imx/imx7/common/imx7.mk
new file mode 100644
index 0000000..849ddcd
--- /dev/null
+++ b/plat/imx/imx7/common/imx7.mk
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Architecture
+$(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING))
+
+TF_CFLAGS	+=	-mfpu=neon
+ASFLAGS		+=	-mfpu=neon
+
+# Platform
+PLAT_INCLUDES		:=	-Idrivers/imx/uart			\
+				-Iplat/imx/common/include		\
+				-Iplat/imx/imx7/include			\
+				-Idrivers/imx/timer			\
+				-Idrivers/imx/usdhc			\
+
+# Translation tables library
+include lib/xlat_tables_v2/xlat_tables.mk
+
+BL2_SOURCES		+=	common/desc_image_load.c			\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/mmc/mmc.c				\
+				drivers/io/io_block.c				\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				drivers/imx/timer/imx_gpt.c			\
+				drivers/imx/uart/imx_uart.c			\
+				drivers/imx/uart/imx_crash_uart.S		\
+				lib/aarch32/arm32_aeabi_divmod.c		\
+				lib/aarch32/arm32_aeabi_divmod_a32.S		\
+				lib/cpus/aarch32/cortex_a7.S			\
+				lib/optee/optee_utils.c				\
+				plat/imx/common/imx_aips.c			\
+				plat/imx/common/imx_caam.c			\
+				plat/imx/common/imx_clock.c			\
+				plat/imx/common/imx_csu.c			\
+				plat/imx/common/imx_io_mux.c			\
+				plat/imx/common/imx_snvs.c			\
+				plat/imx/common/imx_wdog.c			\
+				plat/imx/common/imx7_clock.c			\
+				plat/imx/imx7/common/imx7_bl2_mem_params_desc.c	\
+				plat/imx/imx7/common/imx7_bl2_el3_common.c	\
+				plat/imx/imx7/common/imx7_helpers.S		\
+				plat/imx/imx7/common/imx7_image_load.c		\
+				plat/imx/imx7/common/imx7_io_storage.c		\
+				plat/imx/common/aarch32/imx_uart_console.S	\
+				${XLAT_TABLES_LIB_SRCS}
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+AUTH_SOURCES	:=	drivers/auth/auth_mod.c			\
+			drivers/auth/crypto_mod.c		\
+			drivers/auth/img_parser_mod.c		\
+			drivers/auth/tbbr/tbbr_cot.c
+
+BL2_SOURCES		+=	${AUTH_SOURCES}					\
+				plat/common/tbbr/plat_tbbr.c			\
+				plat/imx/imx7/common/imx7_trusted_boot.c	\
+				plat/imx/imx7/common/imx7_rotpk.S
+
+ROT_KEY             = $(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH          = $(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(eval $(call MAKE_LIB_DIRS))
+
+$(BUILD_PLAT)/bl2/imx7_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+
+$(ROT_KEY): | $(BUILD_PLAT)
+	@echo "  OPENSSL $@"
+	@if [ ! -f $(ROT_KEY) ]; then \
+		openssl genrsa 2048 > $@ 2>/dev/null; \
+	fi
+
+$(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+# Add the build options to pack BLx images and kernel device tree
+# in the FIP if the platform requires.
+ifneq ($(BL2),)
+$(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert))
+endif
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2))
+endif
+ifneq ($(HW_CONFIG),)
+$(eval $(call TOOL_ADD_IMG,HW_CONFIG,--hw-config))
+endif
+
+# Verify build config
+# -------------------
+
+ifeq (${ARCH},aarch64)
+  $(error Error: AArch64 not supported on i.mx7)
+endif
diff --git a/plat/imx/imx7/common/imx7_bl2_el3_common.c b/plat/imx/imx7/common/imx7_bl2_el3_common.c
new file mode 100644
index 0000000..a1e2aaf
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_bl2_el3_common.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/mmc.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/mmio.h>
+#include <lib/optee_utils.h>
+#include <lib/utils.h>
+
+#include <imx_aips.h>
+#include <imx_caam.h>
+#include <imx_clock.h>
+#include <imx_csu.h>
+#include <imx_gpt.h>
+#include <imx_uart.h>
+#include <imx_snvs.h>
+#include <imx_wdog.h>
+#include <imx7_def.h>
+
+#ifndef AARCH32_SP_OPTEE
+#error "Must build with OPTEE support included"
+#endif
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+	return IMX7_UBOOT_BASE;
+}
+
+static uint32_t imx7_get_spsr_for_bl32_entry(void)
+{
+	return SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE,
+			   DISABLE_ALL_EXCEPTIONS);
+}
+
+static uint32_t imx7_get_spsr_for_bl33_entry(void)
+{
+	return SPSR_MODE32(MODE32_svc,
+			   plat_get_ns_image_entrypoint() & 0x1,
+			   SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+	bl_mem_params_node_t *hw_cfg_mem_params = NULL;
+
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+
+	assert(bl_mem_params);
+
+	switch (image_id) {
+	case BL32_IMAGE_ID:
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+					 &pager_mem_params->image_info,
+					 &paged_mem_params->image_info);
+		if (err != 0)
+			WARN("OPTEE header parse error.\n");
+
+		/*
+		 * When ATF loads the DTB the address of the DTB is passed in
+		 * arg2, if an hw config image is present use the base address
+		 * as DTB address an pass it as arg2
+		 */
+		hw_cfg_mem_params = get_bl_mem_params_node(HW_CONFIG_ID);
+
+		bl_mem_params->ep_info.args.arg0 =
+					bl_mem_params->ep_info.args.arg1;
+		bl_mem_params->ep_info.args.arg1 = 0;
+		if (hw_cfg_mem_params)
+			bl_mem_params->ep_info.args.arg2 =
+					hw_cfg_mem_params->image_info.image_base;
+		else
+			bl_mem_params->ep_info.args.arg2 = 0;
+		bl_mem_params->ep_info.args.arg3 = 0;
+		bl_mem_params->ep_info.spsr = imx7_get_spsr_for_bl32_entry();
+		break;
+
+	case BL33_IMAGE_ID:
+		/* AArch32 only core: OP-TEE expects NSec EP in register LR */
+		pager_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID);
+		assert(pager_mem_params);
+		pager_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc;
+
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = imx7_get_spsr_for_bl33_entry();
+		break;
+
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+	/* Setup the MMU here */
+}
+
+static void imx7_setup_system_counter(void)
+{
+	unsigned long freq = SYS_COUNTER_FREQ_IN_TICKS;
+
+	/* Set the frequency table index to our target frequency */
+	write_cntfrq(freq);
+
+	/* Enable system counter @ frequency table index 0, halt on debug */
+	mmio_write_32(SYS_CNTCTL_BASE + CNTCR_OFF,
+		      CNTCR_FCREQ(0) | CNTCR_HDBG | CNTCR_EN);
+}
+
+static void imx7_setup_wdog_clocks(void)
+{
+	uint32_t wdog_en_bits = (uint32_t)WDOG_DEFAULT_CLK_SELECT;
+
+	imx_clock_set_wdog_clk_root_bits(wdog_en_bits);
+	imx_clock_enable_wdog(0);
+	imx_clock_enable_wdog(1);
+	imx_clock_enable_wdog(2);
+	imx_clock_enable_wdog(3);
+}
+
+
+/*
+ * bl2_el3_early_platform_setup()
+ * MMU off
+ */
+void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2,
+				  u_register_t arg3, u_register_t arg4)
+{
+	static console_imx_uart_t console;
+	int console_scope = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME;
+
+	/* Initialize common components */
+	imx_aips_init();
+	imx_csu_init();
+	imx_snvs_init();
+	imx_gpt_ops_init(GPT1_BASE_ADDR);
+	imx_clock_init();
+	imx7_setup_system_counter();
+	imx7_setup_wdog_clocks();
+
+	/* Platform specific setup */
+	imx7_platform_setup(arg1, arg2, arg3, arg4);
+
+	/* Init UART, clock should be enabled in imx7_platform_setup() */
+	console_imx_uart_register(PLAT_IMX7_BOOT_UART_BASE,
+				  PLAT_IMX7_BOOT_UART_CLK_IN_HZ,
+				  PLAT_IMX7_CONSOLE_BAUDRATE,
+				  &console);
+	console_set_scope(&console.console, console_scope);
+
+	/* Open handles to persistent storage */
+	plat_imx7_io_setup();
+
+	/* Setup higher-level functionality CAAM, RTC etc */
+	imx_caam_init();
+	imx_wdog_init();
+
+	/* Print out the expected memory map */
+	VERBOSE("\tOPTEE       0x%08x-0x%08x\n", IMX7_OPTEE_BASE, IMX7_OPTEE_LIMIT);
+	VERBOSE("\tATF/BL2     0x%08x-0x%08x\n", BL2_RAM_BASE, BL2_RAM_LIMIT);
+	VERBOSE("\tSHRAM       0x%08x-0x%08x\n", SHARED_RAM_BASE, SHARED_RAM_LIMIT);
+	VERBOSE("\tFIP         0x%08x-0x%08x\n", IMX7_FIP_BASE, IMX7_FIP_LIMIT);
+	VERBOSE("\tDTB-OVERLAY 0x%08x-0x%08x\n", IMX7_DTB_OVERLAY_BASE, IMX7_DTB_OVERLAY_LIMIT);
+	VERBOSE("\tDTB         0x%08x-0x%08x\n", IMX7_DTB_BASE, IMX7_DTB_LIMIT);
+	VERBOSE("\tUBOOT/BL33  0x%08x-0x%08x\n", IMX7_UBOOT_BASE, IMX7_UBOOT_LIMIT);
+}
+
+/*
+ * bl2_platform_setup()
+ * MMU on - enabled by bl2_el3_plat_arch_setup()
+ */
+void bl2_platform_setup(void)
+{
+}
diff --git a/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c b/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c
new file mode 100644
index 0000000..f9b2983
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				      entry_point_info_t,
+				      SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.pc = BL32_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+				      image_info_t, 0),
+
+		.image_info.image_base = IMX7_OPTEE_BASE,
+		.image_info.image_max_size = IMX7_OPTEE_SIZE,
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+	{
+		.image_id = BL32_EXTRA1_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				      entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+				      image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+		.image_info.image_base = IMX7_OPTEE_BASE,
+		.image_info.image_max_size = IMX7_OPTEE_SIZE,
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+	{
+		/* This is a zero sized image so we don't set base or size */
+		.image_id = BL32_EXTRA2_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+	{
+		.image_id = BL33_IMAGE_ID,
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				      entry_point_info_t,
+				      NON_SECURE | EXECUTABLE),
+		# ifdef PRELOADED_BL33_BASE
+			.ep_info.pc = PRELOADED_BL33_BASE,
+
+			SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+					      VERSION_2, image_info_t,
+					      IMAGE_ATTRIB_SKIP_LOADING),
+		# else
+			.ep_info.pc = BL33_BASE,
+
+			SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+					      VERSION_2, image_info_t, 0),
+			.image_info.image_base = IMX7_UBOOT_BASE,
+			.image_info.image_max_size = IMX7_UBOOT_SIZE,
+		# endif /* PRELOADED_BL33_BASE */
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs);
diff --git a/plat/imx/imx7/common/imx7_helpers.S b/plat/imx/imx7/common/imx7_helpers.S
new file mode 100644
index 0000000..661fd29
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_helpers.S
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) Linaro 2018-2019 Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+#include <imx_hab.h>
+
+	.globl	platform_mem_init
+	.globl	plat_get_my_entrypoint
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	plat_panic_handler
+
+	/* ---------------------------------------------
+	 * int plat_mem_init(void)
+	 * Function to initialize memory.
+	 * The HAB hands off the DDR controller already
+	 * setup and ready to use.
+	 * Implement the mandatory function as a NOP
+	 * ---------------------------------------------
+	 */
+func platform_mem_init
+	bx	lr
+endfunc platform_mem_init
+
+func plat_get_my_entrypoint
+	mov	r0, #0
+	bx	lr
+endfunc plat_get_my_entrypoint
+
+func plat_crash_console_init
+	mov_imm	r0, PLAT_IMX7_BOOT_UART_BASE
+	mov_imm	r1, PLAT_IMX7_BOOT_UART_CLK_IN_HZ
+	mov_imm	r2, PLAT_IMX7_CONSOLE_BAUDRATE
+	b	imx_crash_uart_init
+endfunc plat_crash_console_init
+
+func plat_crash_console_putc
+	mov_imm r1, PLAT_IMX7_BOOT_UART_BASE
+	b	imx_crash_uart_putc
+endfunc plat_crash_console_putc
+
+func plat_crash_console_flush
+	/* Placeholder */
+	mov	r0, #0
+	bx	lr
+endfunc plat_crash_console_flush
+
+func plat_panic_handler
+	mov	r3, #HAB_ROM_VECTOR_TABLE_FAILSAFE
+	ldr	r3, [r3, #0]
+	blx	r3
+endfunc plat_panic_handler
diff --git a/plat/imx/imx7/common/imx7_image_load.c b/plat/imx/imx7/common/imx7_image_load.c
new file mode 100644
index 0000000..c3e47b9
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_image_load.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/imx/imx7/common/imx7_io_storage.c b/plat/imx/imx7/common/imx7_io_storage.c
new file mode 100644
index 0000000..977181d
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_io_storage.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/mmc.h>
+#include <tools_share/firmware_image_package.h>
+
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+
+#ifndef IMX7_FIP_MMAP
+static const io_dev_connector_t *mmc_dev_con;
+static uintptr_t mmc_dev_handle;
+
+static const io_block_spec_t mmc_fip_spec = {
+	.offset = IMX7_FIP_MMC_BASE,
+	.length = IMX7_FIP_SIZE
+};
+
+static const io_block_dev_spec_t mmc_dev_spec = {
+	/* It's used as temp buffer in block driver. */
+	.buffer		= {
+		.offset	= IMX7_FIP_BASE,
+		/* do we need a new value? */
+		.length = IMX7_FIP_SIZE
+	},
+	.ops		= {
+		.read	= mmc_read_blocks,
+		.write	= mmc_write_blocks,
+	},
+	.block_size	= MMC_BLOCK_SIZE,
+};
+
+static int open_mmc(const uintptr_t spec);
+
+#else
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = IMX7_FIP_BASE,
+	.length = IMX7_FIP_SIZE
+};
+static int open_memmap(const uintptr_t spec);
+#endif
+static int open_fip(const uintptr_t spec);
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+/* TODO: this structure is replicated multiple times. rationalize it ! */
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+static const struct plat_io_policy policies[] = {
+#ifndef IMX7_FIP_MMAP
+	[FIP_IMAGE_ID] = {
+		&mmc_dev_handle,
+		(uintptr_t)&mmc_fip_spec,
+		open_mmc
+	},
+#else
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+#endif
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		open_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+#ifndef IMX7_FIP_MMAP
+static int open_mmc(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(mmc_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(mmc_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+#else
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+#endif
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *policy->dev_handle;
+
+	return result;
+}
+
+void plat_imx7_io_setup(void)
+{
+	int result __unused;
+
+#ifndef IMX7_FIP_MMAP
+	result = register_io_dev_block(&mmc_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(mmc_dev_con, (uintptr_t)&mmc_dev_spec,
+			     &mmc_dev_handle);
+	assert(result == 0);
+
+#else
+	result = register_io_dev_memmap(&memmap_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+			     &memmap_dev_handle);
+	assert(result == 0);
+
+#endif
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+			     &fip_dev_handle);
+	assert(result == 0);
+}
diff --git a/plat/imx/imx7/common/imx7_rotpk.S b/plat/imx/imx7/common/imx7_rotpk.S
new file mode 100644
index 0000000..8bd53c2
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global imx7_rotpk_hash
+	.global imx7_rotpk_hash_end
+imx7_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+imx7_rotpk_hash_end:
diff --git a/plat/imx/imx7/common/imx7_trusted_boot.c b/plat/imx/imx7/common/imx7_trusted_boot.c
new file mode 100644
index 0000000..cd27128
--- /dev/null
+++ b/plat/imx/imx7/common/imx7_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char imx7_rotpk_hash[], imx7_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = imx7_rotpk_hash;
+	*key_len = imx7_rotpk_hash_end - imx7_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/imx/imx7/include/imx7_def.h b/plat/imx/imx7/include/imx7_def.h
new file mode 100644
index 0000000..77a8ca3
--- /dev/null
+++ b/plat/imx/imx7/include/imx7_def.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX7_DEF_H
+#define IMX7_DEF_H
+
+#include <stdint.h>
+
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_imx7_io_setup(void);
+void imx7_platform_setup(u_register_t arg1, u_register_t arg2,
+			 u_register_t arg3, u_register_t arg4);
+
+#endif /*IMX7_DEF_H */
diff --git a/plat/imx/imx7/include/imx_hab_arch.h b/plat/imx/imx7/include/imx_hab_arch.h
new file mode 100644
index 0000000..2a34c6a
--- /dev/null
+++ b/plat/imx/imx7/include/imx_hab_arch.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef IMX_HAB_ARCH_H
+#define IMX_HAB_ARCH_H
+
+/* Define the offset the High Assurance Boot callback table is at */
+#define HAB_CALLBACK_OFFSET	0x100
+
+#endif /* IMX_HAB_ARCH_H */
diff --git a/plat/imx/imx7/include/imx_regs.h b/plat/imx/imx7/include/imx_regs.h
new file mode 100644
index 0000000..3c7e20f
--- /dev/null
+++ b/plat/imx/imx7/include/imx_regs.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_REGS_H
+#define IMX_REGS_H
+
+/* Define the processor memory map */
+
+#define OCRAM_S_ALIAS_BASE		0x00000000	/* CM4 Alias Code */
+#define ROM_HIGH_BASE			0x00008000	/* ROM high 64k */
+#define ROM_HIGH_PROT_BASE		0x00017000	/* ROM high 64k protected */
+#define CAAM_BASE			0x00020000	/* CAAM block base address */
+#define OCRAM_S_BASE			0x00180000	/* OCRAM_S  */
+#define ROM_LOW_BASE			0x007f8000	/* ROM low 64k */
+#define OCRAM_BASE			0x00900000	/* OCRAM base */
+#define CM4_ALIAS_CODE_BASE		0x04000000	/* CM4 alias code */
+#define TCM_BASE			0x1fff0000	/* TCM */
+#define BOOTROM_CP_BASE			0x20020000	/* Boot ROM (all 96KB) */
+#define CM4_ALIAS_SYSTEM_BASE		0x20100000	/* CM4 Alias system */
+#define EIM_BASE			0x28000000	/* EIM */
+
+/* BootROM absolute base address */
+#define BOOTROM_BASE			0x00000000	/* BootROM */
+
+/* Peripherals like GPIO live in the AIPS range */
+#define AIPS1_BASE			0x30000000	/* AIPS1 */
+#define AIPS2_BASE			0x30400000	/* AIPS2 */
+#define AIPS3_BASE			0x30800000	/* AIPS3 */
+#define AIPS4_BASE			0x30c00000	/* AIPS4 */
+
+/* ARM peripherals like GIC */
+#define ARM_PERIPHERAL_GIC_BASE		0x31000000	/* GIC */
+
+/* Configuration ports */
+#define GPV0_BASE			0x32000000	/* Main config port */
+#define GPV1_BASE			0x32100000	/* Wakeup config port */
+#define GPV2_BASE			0x32200000	/* Per_s config port */
+#define GPV3_BASE			0x32300000	/* Per_m config port */
+#define GPV4_BASE			0x32400000	/* Enet config port */
+#define GPV5_BASE			0x32500000	/* Display config port */
+#define GPV6_BASE			0x32600000	/* M4 conig port */
+
+/* MMAP peripherals - like APBH DMA */
+#define APBH_DMA_BASE			0x33000000	/* APBH DMA block */
+
+/* QSPI RX BUFFERS */
+#define QSPI_RX_BUFFER_BASE		0x34000000	/* QSPI RX buffers */
+
+/* QSPI1 FLASH */
+#define QSPI_FLASH_BASE			0x60000000	/* QSPI1 flash */
+
+/* AIPS1 block addresses */
+#define AIPSTZ_CONFIG_OFFSET		0x001f0000
+#define CCM_BASE			(AIPS1_BASE + 0x380000)
+
+/* Define the maximum number of UART blocks on this SoC */
+#define MXC_UART1_BASE			(AIPS3_BASE + 0x060000)
+#define MXC_UART2_BASE			(AIPS3_BASE + 0x070000)
+#define MXC_UART3_BASE			(AIPS3_BASE + 0x080000)
+#define MXC_UART4_BASE			(AIPS3_BASE + 0x260000)
+#define MXC_UART5_BASE			(AIPS3_BASE + 0x270000)
+#define MXC_UART6_BASE			(AIPS3_BASE + 0x280000)
+#define MXC_UART7_BASE			(AIPS3_BASE + 0x290000)
+#define MXC_MAX_UART_NUM		0x07
+
+/* Define the maximum number of USDHCI blocks on this SoC */
+#define MXC_MAX_USDHC_NUM		3
+
+/* Define the number of CSU registers for this SoC */
+#define MXC_MAX_CSU_REGS		0x40
+#define CSU_BASE			(AIPS1_BASE + 0x3E0000)
+
+/* IO Mux block base */
+#define MXC_IO_MUXC_BASE		(AIPS1_BASE + 0x330000)
+
+/* SNVS base */
+#define SNVS_BASE			(AIPS1_BASE + 0x370000)
+
+/* GP Timer base */
+#define GPT1_BASE_ADDR			(AIPS1_BASE + 0x2d0000)
+
+/* MMC base */
+#define USDHC1_BASE			(AIPS1_BASE + 0xb40000)
+#define USDHC2_BASE			(AIPS1_BASE + 0xb50000)
+#define USDHC3_BASE			(AIPS1_BASE + 0xb60000)
+
+/* Arm optional memory mapped counter module base address */
+#define SYS_CNTCTL_BASE			(AIPS2_BASE + 0x2c0000)
+
+/* Define CAAM AIPS offset */
+#define CAAM_AIPS_BASE			(AIPS3_BASE + 0x100000)
+#define CAAM_NUM_JOB_RINGS		0x03
+#define CAAM_NUM_RTIC			0x04
+#define CAAM_NUM_DECO			0x01
+
+/* Define watchdog base addresses */
+#define WDOG1_BASE			(AIPS1_BASE + 0x280000)
+#define WDOG2_BASE			(AIPS1_BASE + 0x290000)
+#define WDOG3_BASE			(AIPS1_BASE + 0x2A0000)
+#define WDOG4_BASE			(AIPS1_BASE + 0x280000)
+
+/* Define the maximum number of WDOG blocks on this SoC */
+#define MXC_MAX_WDOG_NUM		0x04
+
+#endif /* IMX_REGS_H */
diff --git a/plat/imx/imx7/picopi/include/platform_def.h b/plat/imx/imx7/picopi/include/platform_def.h
new file mode 100644
index 0000000..1af1d0c
--- /dev/null
+++ b/plat/imx/imx7/picopi/include/platform_def.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_STACK_SIZE		0x1000
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	2
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define PICOPI_PRIMARY_CPU		0
+
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		2
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		0
+
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		1
+
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF		2
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		4
+#define PLAT_LOCAL_PSTATE_MASK		((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ * i.MX7 has a 32 byte cacheline size
+ * i.MX 7Dual Applications Processor Reference Manual, Rev. 1, 01/2018 pg 298
+ */
+#define CACHE_WRITEBACK_SHIFT		4
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Partition memory into secure BootROM, OCRAM_S, non-secure DRAM, secure DRAM
+ */
+#define BOOT_ROM_BASE			0x00000000
+#define BOOT_ROM_SIZE			0x00020000
+
+#define OCRAM_S_BASE			0x00180000
+#define OCRAM_S_SIZE			0x00008000
+
+/* Controller maps 2GB, board contains 512 MB. 0x80000000 - 0xa0000000 */
+#define DRAM_BASE			0x80000000
+#define DRAM_SIZE			0x20000000
+#define DRAM_LIMIT			(DRAM_BASE + DRAM_SIZE)
+
+/* Place OPTEE at minus 32 MB from the end of memory. 0x9e000000 - 0xa0000000 */
+#define IMX7_OPTEE_SIZE			0x02000000
+#define IMX7_OPTEE_BASE			(DRAM_LIMIT - IMX7_OPTEE_SIZE)
+#define IMX7_OPTEE_LIMIT		(IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE)
+
+/* Place ATF directly beneath OPTEE. 0x9df00000 - 0x9e000000 */
+#define BL2_RAM_SIZE			0x00100000
+#define BL2_RAM_BASE			(IMX7_OPTEE_BASE - BL2_RAM_SIZE)
+#define BL2_RAM_LIMIT			(BL2_RAM_BASE + BL2_RAM_SIZE)
+
+/* Optional Mailbox. Only relevant on i.MX7D. 0x9deff000 - 0x9df00000*/
+#define SHARED_RAM_SIZE			0x00001000
+#define SHARED_RAM_BASE			(BL2_RAM_BASE - SHARED_RAM_SIZE)
+#define SHARED_RAM_LIMIT		(SHARED_RAM_BASE + SHARED_RAM_SIZE)
+
+/* Define the absolute location of u-boot 0x87800000 - 0x87900000 */
+#define IMX7_UBOOT_SIZE			0x00100000
+#define IMX7_UBOOT_BASE			(DRAM_BASE + 0x7800000)
+#define IMX7_UBOOT_LIMIT		(IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE)
+
+/* Define FIP image absolute location 0x80000000 - 0x80100000 */
+#define IMX7_FIP_SIZE			0x00100000
+#define IMX7_FIP_BASE			(DRAM_BASE)
+#define IMX7_FIP_LIMIT			(IMX7_FIP_BASE + IMX7_FIP_SIZE)
+
+/* Define FIP image location at 1MB offset */
+#define IMX7_FIP_MMC_BASE		(1024 * 1024)
+
+/* Define the absolute location of DTB 0x83000000 - 0x83100000 */
+#define IMX7_DTB_SIZE			0x00100000
+#define IMX7_DTB_BASE			(DRAM_BASE + 0x03000000)
+#define IMX7_DTB_LIMIT			(IMX7_DTB_BASE + IMX7_DTB_SIZE)
+
+/* Define the absolute location of DTB Overlay 0x83100000 - 0x83101000 */
+#define IMX7_DTB_OVERLAY_SIZE		0x00001000
+#define IMX7_DTB_OVERLAY_BASE		IMX7_DTB_LIMIT
+#define IMX7_DTB_OVERLAY_LIMIT		(IMX7_DTB_OVERLAY_BASE + \
+					 IMX7_DTB_OVERLAY_SIZE)
+/*
+ * BL2 specific defines.
+ *
+ * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define BL2_BASE		BL2_RAM_BASE
+#define BL2_LIMIT		(BL2_RAM_BASE + BL2_RAM_SIZE)
+
+/*
+ * BL3-2/OPTEE
+ */
+# define BL32_BASE		IMX7_OPTEE_BASE
+# define BL32_LIMIT		(IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE)
+
+/*
+ * BL3-3/U-BOOT
+ */
+#define BL33_BASE		IMX7_UBOOT_BASE
+#define BL33_LIMIT		(IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE)
+
+/*
+ * ATF's view of memory
+ *
+ * 0xa0000000 +-----------------+
+ *            |       DDR       | BL32/OPTEE
+ * 0x9e000000 +-----------------+
+ *            |       DDR       | BL23 ATF
+ * 0x9df00000 +-----------------+
+ *            |       DDR       | Shared MBOX RAM
+ * 0x9de00000 +-----------------+
+ *            |       DDR       | Unallocated
+ * 0x87900000 +-----------------+
+ *            |       DDR       | BL33/U-BOOT
+ * 0x87800000 +-----------------+
+ *            |       DDR       | Unallocated
+ * 0x83100000 +-----------------+
+ *            |       DDR       | DTB
+ * 0x83000000 +-----------------+
+ *            |       DDR       | Unallocated
+ * 0x80100000 +-----------------+
+ *            |       DDR       | FIP
+ * 0x80000000 +-----------------+
+ *            |     SOC I/0     |
+ * 0x00a00000 +-----------------+
+ *            |      OCRAM      | Not used
+ * 0x00900000 +-----------------+
+ *            |     SOC I/0     |
+ * 0x00188000 +-----------------+
+ *            |     OCRAM_S     | Not used
+ * 0x00180000 +-----------------+
+ *            |     SOC I/0     |
+ * 0x00020000 +-----------------+
+ *            |     BootROM     | BL1
+ * 0x00000000 +-----------------+
+ */
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_MMAP_REGIONS		10
+#define MAX_XLAT_TABLES			6
+#define MAX_IO_DEVICES			2
+#define MAX_IO_HANDLES			3
+#define MAX_IO_BLOCK_DEVICES		1
+
+/* UART defines */
+#define PLAT_IMX7_BOOT_UART_BASE	MXC_UART5_BASE
+#define PLAT_IMX7_BOOT_UART_CLK_IN_HZ	24000000
+#define PLAT_IMX7_CONSOLE_BAUDRATE	115200
+
+/* MMC defines */
+#ifndef PLAT_PICOPI_SD
+#define PLAT_PICOPI_SD 3
+#endif
+
+#if PLAT_PICOPI_SD == 1
+#define PLAT_PICOPI_BOOT_MMC_BASE	USDHC1_BASE
+#endif /* PLAT_PICOPI_SD == 1 */
+
+#if PLAT_PICOPI_SD == 2
+#define PLAT_PICOPI_BOOT_MMC_BASE	USDHC2_BASE
+#endif /* PLAT_PICOPI_SD == 2 */
+
+#if PLAT_PICOPI_SD == 3
+#define PLAT_PICOPI_BOOT_MMC_BASE	USDHC3_BASE
+#endif /* PLAT_PICOPI_SD == 3 */
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	8000000		/* 8 MHz */
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c b/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c
new file mode 100644
index 0000000..3cf5c36
--- /dev/null
+++ b/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/mmc.h>
+#include <lib/utils.h>
+
+#include <imx_caam.h>
+#include <imx_clock.h>
+#include <imx_io_mux.h>
+#include <imx_uart.h>
+#include <imx_usdhc.h>
+#include <imx7_def.h>
+
+#define UART5_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			  CCM_TRGT_MUX_UART5_CLK_ROOT_OSC_24M)
+
+#define USDHC_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			  CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AHB |\
+			  CCM_TARGET_POST_PODF(2))
+
+#define USB_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL)
+
+#define PICOPI_UART5_RX_MUX \
+	IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT1_UART5_RX_DATA
+
+#define PICOPI_UART5_TX_MUX \
+	IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT1_UART5_TX_DATA
+
+#define PICOPI_SD3_FEATURES \
+	(IOMUXC_SW_PAD_CTL_PAD_SD3_PU_47K            | \
+	 IOMUXC_SW_PAD_CTL_PAD_SD3_PE                | \
+	 IOMUXC_SW_PAD_CTL_PAD_SD3_HYS               | \
+	 IOMUXC_SW_PAD_CTL_PAD_SD3_SLEW_SLOW         | \
+	 IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_3_X6)
+
+static void picopi_setup_pinmux(void)
+{
+	/* Configure UART5 TX */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_OFFSET,
+					 PICOPI_UART5_TX_MUX);
+	/* Configure UART5 RX */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_OFFSET,
+					 PICOPI_UART5_RX_MUX);
+
+	/* Configure USDHC3 */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_CLK_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_CMD_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA0_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA1_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA2_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA3_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA4_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA5_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA6_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA7_OFFSET, 0);
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_OFFSET,
+					 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_ALT1_SD3_CD_B);
+
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_CLK_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_CMD_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA0_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA1_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA2_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA3_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA4_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA5_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA6_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA7_OFFSET,
+				     PICOPI_SD3_FEATURES);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO14_OFFSET,
+				     PICOPI_SD3_FEATURES);
+}
+
+static void picopi_usdhc_setup(void)
+{
+	imx_usdhc_params_t params;
+	struct mmc_device_info info;
+
+	zeromem(&params, sizeof(imx_usdhc_params_t));
+	params.reg_base = PLAT_PICOPI_BOOT_MMC_BASE;
+	params.clk_rate = 25000000;
+	params.bus_width = MMC_BUS_WIDTH_8;
+	info.mmc_dev_type = MMC_IS_EMMC;
+	imx_usdhc_init(&params, &info);
+}
+
+static void picopi_setup_usb_clocks(void)
+{
+	uint32_t usb_en_bits = (uint32_t)USB_CLK_SELECT;
+
+	imx_clock_set_usb_clk_root_bits(usb_en_bits);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_IPG);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_PHY_480MCLK);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG1_PHY);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG2_PHY);
+}
+
+void imx7_platform_setup(u_register_t arg1, u_register_t arg2,
+			 u_register_t arg3, u_register_t arg4)
+{
+	uint32_t uart5_en_bits = (uint32_t)UART5_CLK_SELECT;
+	uint32_t usdhc_clock_sel = PLAT_PICOPI_SD - 1;
+
+	/* Initialize clocks etc */
+	imx_clock_enable_uart(4, uart5_en_bits);
+	imx_clock_enable_usdhc(usdhc_clock_sel, USDHC_CLK_SELECT);
+
+	picopi_setup_usb_clocks();
+
+	/* Setup pin-muxes */
+	picopi_setup_pinmux();
+
+	picopi_usdhc_setup();
+}
diff --git a/plat/imx/imx7/picopi/platform.mk b/plat/imx/imx7/picopi/platform.mk
new file mode 100644
index 0000000..5901001
--- /dev/null
+++ b/plat/imx/imx7/picopi/platform.mk
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Include imx7 common
+include plat/imx/imx7/common/imx7.mk
+
+# Platform
+PLAT_INCLUDES		+=	-Iplat/imx/imx7/picopi/include		    \
+
+BL2_SOURCES		+=	drivers/imx/usdhc/imx_usdhc.c		    \
+				plat/imx/imx7/picopi/picopi_bl2_el3_setup.c \
+
+# Build config flags
+# ------------------
+
+ARM_CORTEX_A7			:= yes
+WORKAROUND_CVE_2017_5715	:= 0
+
+RESET_TO_BL31			:= 0
+
+# Non-TF Boot ROM
+BL2_AT_EL3			:= 1
+
+# Indicate single-core
+COLD_BOOT_SINGLE_CPU		:= 1
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Use multi console API
+MULTI_CONSOLE_API		:= 1
+
+PLAT_PICOPI_UART		:=5
+$(eval $(call add_define,PLAT_PICOPI_UART))
diff --git a/plat/imx/imx7/warp7/include/platform_def.h b/plat/imx/imx7/warp7/include/platform_def.h
new file mode 100644
index 0000000..4f71908
--- /dev/null
+++ b/plat/imx/imx7/warp7/include/platform_def.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_STACK_SIZE		0x1000
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	2
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT + \
+					 PLATFORM_CLUSTER1_CORE_COUNT)
+
+#define WARP7_PRIMARY_CPU		0
+
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		2
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		0
+
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		1
+
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF		2
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		4
+#define PLAT_LOCAL_PSTATE_MASK		((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ * i.MX7 has a 32 byte cacheline size
+ * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016 pg 244
+ */
+#define CACHE_WRITEBACK_SHIFT		4
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Partition memory into secure BootROM, OCRAM_S, non-secure DRAM, secure DRAM
+ */
+#define BOOT_ROM_BASE			0x00000000
+#define BOOT_ROM_SIZE			0x00020000
+
+#define OCRAM_S_BASE			0x00180000
+#define OCRAM_S_SIZE			0x00008000
+
+/* Controller maps 2GB, board contains 512 MB. 0x80000000 - 0xa0000000 */
+#define DRAM_BASE			0x80000000
+#define DRAM_SIZE			0x20000000
+#define DRAM_LIMIT			(DRAM_BASE + DRAM_SIZE)
+
+/* Place OPTEE at minus 32 MB from the end of memory. 0x9e000000 - 0xa0000000 */
+#define IMX7_OPTEE_SIZE			0x02000000
+#define IMX7_OPTEE_BASE			(DRAM_LIMIT - IMX7_OPTEE_SIZE)
+#define IMX7_OPTEE_LIMIT		(IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE)
+
+/* Place ATF directly beneath OPTEE. 0x9df00000 - 0x9e000000 */
+#define BL2_RAM_SIZE			0x00100000
+#define BL2_RAM_BASE			(IMX7_OPTEE_BASE - BL2_RAM_SIZE)
+#define BL2_RAM_LIMIT			(BL2_RAM_BASE + BL2_RAM_SIZE)
+
+/* Optional Mailbox. Only relevant on i.MX7D. 0x9deff000 - 0x9df00000*/
+#define SHARED_RAM_SIZE			0x00001000
+#define SHARED_RAM_BASE			(BL2_RAM_BASE - SHARED_RAM_SIZE)
+#define SHARED_RAM_LIMIT		(SHARED_RAM_BASE + SHARED_RAM_SIZE)
+
+/* Define the absolute location of u-boot 0x87800000 - 0x87900000 */
+#define IMX7_UBOOT_SIZE			0x00100000
+#define IMX7_UBOOT_BASE			(DRAM_BASE + 0x7800000)
+#define IMX7_UBOOT_LIMIT		(IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE)
+
+/* Define FIP image absolute location 0x80000000 - 0x80100000 */
+#define IMX7_FIP_SIZE			0x00100000
+#define IMX7_FIP_BASE			(DRAM_BASE)
+#define IMX7_FIP_LIMIT			(IMX7_FIP_BASE + IMX7_FIP_SIZE)
+
+/* Define FIP image location at 1MB offset */
+#define IMX7_FIP_MMC_BASE		(1024 * 1024)
+
+/* Define the absolute location of DTB 0x83000000 - 0x83100000 */
+#define IMX7_DTB_SIZE			0x00100000
+#define IMX7_DTB_BASE			(DRAM_BASE + 0x03000000)
+#define IMX7_DTB_LIMIT			(IMX7_DTB_BASE + IMX7_DTB_SIZE)
+
+/* Define the absolute location of DTB Overlay 0x83100000 - 0x83101000 */
+#define IMX7_DTB_OVERLAY_SIZE		0x00001000
+#define IMX7_DTB_OVERLAY_BASE		IMX7_DTB_LIMIT
+#define IMX7_DTB_OVERLAY_LIMIT		(IMX7_DTB_OVERLAY_BASE + \
+					 IMX7_DTB_OVERLAY_SIZE)
+
+/*
+ * BL2 specific defines.
+ *
+ * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define BL2_BASE		BL2_RAM_BASE
+#define BL2_LIMIT		(BL2_RAM_BASE + BL2_RAM_SIZE)
+
+/*
+ * BL3-2/OPTEE
+ */
+# define BL32_BASE		IMX7_OPTEE_BASE
+# define BL32_LIMIT		(IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE)
+
+/*
+ * BL3-3/U-BOOT
+ */
+#define BL33_BASE		IMX7_UBOOT_BASE
+#define BL33_LIMIT		(IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE)
+
+/*
+ * ATF's view of memory
+ *
+ * 0xa0000000 +-----------------+
+ *            |       DDR       | BL32/OPTEE
+ * 0x9e000000 +-----------------+
+ *            |       DDR       | BL23 ATF
+ * 0x9df00000 +-----------------+
+ *            |       DDR       | Shared MBOX RAM
+ * 0x9de00000 +-----------------+
+ *            |       DDR       | Unallocated
+ * 0x87900000 +-----------------+
+ *            |       DDR       | BL33/U-BOOT
+ * 0x87800000 +-----------------+
+ *            |       DDR       | Unallocated
+ * 0x83101000 +-----------------+
+ *            |       DDR       | DTB Overlay
+ * 0x83100000 +-----------------+
+ *            |       DDR       | DTB
+ * 0x83000000 +-----------------+
+ *            |       DDR       | Unallocated
+ * 0x80100000 +-----------------+
+ *            |       DDR       | FIP
+ * 0x80000000 +-----------------+
+ *            |     SOC I/0     |
+ * 0x00a00000 +-----------------+
+ *            |      OCRAM      | Not used
+ * 0x00900000 +-----------------+
+ *            |     SOC I/0     |
+ * 0x00188000 +-----------------+
+ *            |     OCRAM_S     | Not used
+ * 0x00180000 +-----------------+
+ *            |     SOC I/0     |
+ * 0x00020000 +-----------------+
+ *            |     BootROM     | BL1
+ * 0x00000000 +-----------------+
+ */
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_MMAP_REGIONS		10
+#define MAX_XLAT_TABLES			6
+#define MAX_IO_DEVICES			2
+#define MAX_IO_HANDLES			3
+#define MAX_IO_BLOCK_DEVICES		1U
+
+/* UART defines */
+#if PLAT_WARP7_UART == 1
+#define PLAT_WARP7_UART_BASE		MXC_UART1_BASE
+#elif PLAT_WARP7_UART == 6
+#define IMX_UART_DTE
+#define PLAT_WARP7_UART_BASE		MXC_UART6_BASE
+#else
+#error "define PLAT_WARP7_UART=1 or PLAT_WARP7_UART=6"
+#endif
+
+#define PLAT_IMX7_BOOT_UART_BASE	PLAT_WARP7_UART_BASE
+#define PLAT_IMX7_BOOT_UART_CLK_IN_HZ	24000000
+#define PLAT_IMX7_CONSOLE_BAUDRATE	115200
+
+/* MMC defines */
+#ifndef PLAT_WARP7_SD
+#define PLAT_WARP7_SD 3
+#endif
+
+#if PLAT_WARP7_SD == 1
+#define PLAT_WARP7_BOOT_MMC_BASE	USDHC1_BASE
+#endif /* PLAT_WARP7_SD == 1 */
+
+#if PLAT_WARP7_SD == 2
+#define PLAT_WARP7_BOOT_MMC_BASE	USDHC2_BASE
+#endif /* PLAT_WARP7_SD == 2 */
+
+#if PLAT_WARP7_SD == 3
+#define PLAT_WARP7_BOOT_MMC_BASE	USDHC3_BASE
+#endif /* PLAT_WARP7_SD == 3 */
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	8000000		/* 8 MHz */
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx7/warp7/platform.mk b/plat/imx/imx7/warp7/platform.mk
new file mode 100644
index 0000000..ea0f001
--- /dev/null
+++ b/plat/imx/imx7/warp7/platform.mk
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Include imx7 common
+include plat/imx/imx7/common/imx7.mk
+
+# Platform
+PLAT_INCLUDES		+= -Iplat/imx/imx7/warp7/include
+
+BL2_SOURCES		+=	drivers/imx/usdhc/imx_usdhc.c			\
+				plat/imx/imx7/warp7/warp7_bl2_el3_setup.c
+
+# Build config flags
+# ------------------
+
+ARM_CORTEX_A7			:= yes
+WORKAROUND_CVE_2017_5715	:= 0
+
+RESET_TO_BL31			:= 0
+
+# Non-TF Boot ROM
+BL2_AT_EL3			:= 1
+
+# Indicate single-core
+COLD_BOOT_SINGLE_CPU		:= 1
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+PLAT_WARP7_UART			:=1
+$(eval $(call add_define,PLAT_WARP7_UART))
diff --git a/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c b/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c
new file mode 100644
index 0000000..935a411
--- /dev/null
+++ b/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/mmc.h>
+#include <lib/utils.h>
+
+#include <imx_caam.h>
+#include <imx_clock.h>
+#include <imx_io_mux.h>
+#include <imx_uart.h>
+#include <imx_usdhc.h>
+#include <imx7_def.h>
+
+#define UART1_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			  CCM_TRGT_MUX_UART1_CLK_ROOT_OSC_24M)
+
+#define UART6_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			  CCM_TRGT_MUX_UART6_CLK_ROOT_OSC_24M)
+
+#define USDHC_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			  CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AHB |\
+			  CCM_TARGET_POST_PODF(2))
+
+#define USB_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\
+			CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL)
+
+#define WARP7_UART1_TX_MUX \
+	IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT0_UART1_TX_DATA
+
+#define WARP7_UART1_TX_FEATURES \
+	(IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_3_100K_PU	| \
+	 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PE_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_HYS_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_1_X4)
+
+#define WARP7_UART1_RX_MUX \
+	IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT0_UART1_RX_DATA
+
+#define WARP7_UART1_RX_FEATURES \
+	(IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_3_100K_PU	| \
+	 IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PE_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_HYS_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_1_X4)
+
+#define WARP7_UART6_TX_MUX \
+	IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT1_UART6_TX_DATA
+
+#define WARP7_UART6_TX_FEATURES \
+	(IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_3_100K_PU		| \
+	 IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PE_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_HYS_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_1_X4)
+
+#define WARP7_UART6_RX_MUX \
+	IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT1_UART6_RX_DATA
+
+#define WARP7_UART6_RX_FEATURES \
+	(IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_3_100K_PU		| \
+	 IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PE_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_HYS_EN		| \
+	 IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_1_X4)
+
+static void warp7_setup_pinmux(void)
+{
+	/* Configure UART1 TX */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_OFFSET,
+					 WARP7_UART1_TX_MUX);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_OFFSET,
+				     WARP7_UART1_TX_FEATURES);
+
+	/* Configure UART1 RX */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_OFFSET,
+					 WARP7_UART1_RX_MUX);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_OFFSET,
+				     WARP7_UART1_RX_FEATURES);
+
+	/* Configure UART6 TX */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_OFFSET,
+					 WARP7_UART6_TX_MUX);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_OFFSET,
+				     WARP7_UART6_TX_FEATURES);
+
+	/* Configure UART6 RX */
+	imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_OFFSET,
+					 WARP7_UART6_RX_MUX);
+	imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_OFFSET,
+				     WARP7_UART6_RX_FEATURES);
+}
+
+static void warp7_usdhc_setup(void)
+{
+	imx_usdhc_params_t params;
+	struct mmc_device_info info;
+
+	zeromem(&params, sizeof(imx_usdhc_params_t));
+	params.reg_base = PLAT_WARP7_BOOT_MMC_BASE;
+	params.clk_rate = 25000000;
+	params.bus_width = MMC_BUS_WIDTH_8;
+	info.mmc_dev_type = MMC_IS_EMMC;
+	imx_usdhc_init(&params, &info);
+}
+
+static void warp7_setup_usb_clocks(void)
+{
+	uint32_t usb_en_bits = (uint32_t)USB_CLK_SELECT;
+
+	imx_clock_set_usb_clk_root_bits(usb_en_bits);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_IPG);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_PHY_480MCLK);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG1_PHY);
+	imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG2_PHY);
+}
+
+void imx7_platform_setup(u_register_t arg1, u_register_t arg2,
+			 u_register_t arg3, u_register_t arg4)
+{
+	uint32_t uart1_en_bits = (uint32_t)UART1_CLK_SELECT;
+	uint32_t uart6_en_bits = (uint32_t)UART6_CLK_SELECT;
+	uint32_t usdhc_clock_sel = PLAT_WARP7_SD - 1;
+
+	/* Initialize clocks etc */
+	imx_clock_enable_uart(0, uart1_en_bits);
+	imx_clock_enable_uart(5, uart6_en_bits);
+
+	imx_clock_enable_usdhc(usdhc_clock_sel, USDHC_CLK_SELECT);
+
+	warp7_setup_usb_clocks();
+
+	/* Setup pin-muxes */
+	warp7_setup_pinmux();
+
+	warp7_usdhc_setup();
+}
diff --git a/plat/imx/imx8m/gpc_common.c b/plat/imx/imx8m/gpc_common.c
new file mode 100644
index 0000000..eb2801c
--- /dev/null
+++ b/plat/imx/imx8m/gpc_common.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+static uint32_t gpc_imr_offset[] = { 0x30, 0x40, 0x1c0, 0x1d0, };
+
+#pragma weak imx_set_cpu_pwr_off
+#pragma weak imx_set_cpu_pwr_on
+#pragma weak imx_set_cpu_lpm
+#pragma weak imx_set_cluster_powerdown
+
+void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint)
+{
+	uint64_t temp_base;
+
+	temp_base = (uint64_t) sec_entrypoint;
+	temp_base >>= 2;
+
+	mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3),
+		((uint32_t)(temp_base >> 22) & 0xffff));
+	mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4,
+		((uint32_t)temp_base & 0x003fffff));
+}
+
+void imx_set_cpu_pwr_off(unsigned int core_id)
+{
+	/* enable the wfi power down of the core */
+	mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
+	/* assert the pcg pcr bit of the core */
+	mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+}
+
+void imx_set_cpu_pwr_on(unsigned int core_id)
+{
+	/* clear the wfi power down bit of the core */
+	mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id));
+	/* assert the ncpuporeset */
+	mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
+	/* assert the pcg pcr bit of the core */
+	mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+	/* sw power up the core */
+	mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id));
+
+	/* wait for the power up finished */
+	while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0)
+		;
+
+	/* deassert the pcg pcr bit of the core */
+	mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+	/* deassert the ncpuporeset */
+	mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id));
+}
+
+void imx_set_cpu_lpm(unsigned int core_id, bool pdn)
+{
+	if (pdn) {
+		/* enable the core WFI PDN & IRQ PUP */
+		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+				COREx_IRQ_WUP(core_id));
+		/* assert the pcg pcr bit of the core */
+		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+	} else {
+		/* disbale CORE WFI PDN & IRQ PUP */
+		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+				COREx_IRQ_WUP(core_id));
+		/* deassert the pcg pcr bit of the core */
+		mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+	}
+}
+
+/*
+ * the plat and noc can only be power up & down by slot method,
+ * slot0: plat power down; slot1: noc power down; slot2: noc power up;
+ * slot3: plat power up. plat's pup&pdn ack is used by default. if
+ * noc is config to power down, then noc's pdn ack should be used.
+ */
+static void imx_a53_plat_slot_config(bool pdn)
+{
+	if (pdn) {
+		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL);
+		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL);
+		mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_PLAT_PDN_ACK |
+			A53_PLAT_PUP_ACK);
+		mmio_setbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1);
+	} else {
+		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL);
+		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL);
+		mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK |
+			A53_DUMMY_PDN_ACK);
+		mmio_clrbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1);
+	}
+}
+
+void imx_set_cluster_standby(bool enter)
+{
+	/*
+	 * Enable BIT 6 of A53 AD register to make sure system
+	 * don't enter LPM mode.
+	 */
+	if (enter)
+		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
+	else
+		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6));
+}
+
+/* i.mx8mq need to override it */
+void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state)
+{
+	uint32_t val;
+
+	if (!is_local_state_run(power_state)) {
+		/* config C0~1's LPM, enable a53 clock off in LPM */
+		mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CLK_ON_LPM,
+			LPM_MODE(power_state));
+		/* config C2-3's LPM */
+		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, LPM_MODE(power_state));
+
+		/* enable PLAT/SCU power down */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		val &= ~EN_L2_WFI_PDN;
+		/* L2 cache memory is on in WAIT mode */
+		if (is_local_state_off(power_state))
+			val |= (L2PGE | EN_PLAT_PDN);
+		else
+			val |= EN_PLAT_PDN;
+
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+		imx_a53_plat_slot_config(true);
+	} else {
+		/* clear the slot and ack for cluster power down */
+		imx_a53_plat_slot_config(false);
+		/* reverse the cluster level setting */
+		mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, 0xf, A53_CLK_ON_LPM);
+		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, 0xf);
+
+		/* clear PLAT/SCU power down */
+		mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_AD, (L2PGE | EN_PLAT_PDN),
+			EN_L2_WFI_PDN);
+	}
+}
+
+static unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id)
+{
+	unsigned int n = id >> ISENABLER_SHIFT;
+
+	return mmio_read_32(base + GICD_ISENABLER + (n << 2));
+}
+
+/*
+ * gic's clock will be gated in system suspend, so gic has no ability to
+ * to wakeup the system, we need to config the imr based on the irq
+ * enable status in gic, then gpc will monitor the wakeup irq
+ */
+void imx_set_sys_wakeup(unsigned int last_core, bool pdn)
+{
+	uint32_t irq_mask;
+	uintptr_t gicd_base = PLAT_GICD_BASE;
+
+	if (pdn)
+		mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CORE_WUP_SRC(last_core),
+			IRQ_SRC_A53_WUP);
+	else
+		mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, IRQ_SRC_A53_WUP,
+			A53_CORE_WUP_SRC(last_core));
+
+	/* clear last core's IMR based on GIC's mask setting */
+	for (int i = 0; i < IRQ_IMR_NUM; i++) {
+		if (pdn)
+			/* set the wakeup irq base GIC */
+			irq_mask = ~gicd_read_isenabler(gicd_base, 32 * (i + 1));
+		else
+			irq_mask = IMR_MASK_ALL;
+
+		mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4,
+			      irq_mask);
+	}
+}
+
+#pragma weak imx_noc_slot_config
+/*
+ * this function only need to be override by platform
+ * that support noc power down, for example: imx8mm.
+ *  otherwize, keep it empty.
+ */
+void imx_noc_slot_config(bool pdn)
+{
+
+}
+
+/* this is common for all imx8m soc */
+void imx_set_sys_lpm(unsigned int last_core, bool retention)
+{
+	uint32_t val;
+
+	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+	val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
+		 SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE);
+
+	if (retention)
+		val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
+			SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE);
+
+	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+
+	/* config the noc power down */
+	imx_noc_slot_config(retention);
+
+	/* config wakeup irqs' mask in gpc */
+	imx_set_sys_wakeup(last_core, retention);
+}
+
+void imx_set_rbc_count(void)
+{
+	mmio_setbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN |
+		(0x8 << SLPCR_RBC_COUNT_SHIFT));
+}
+
+void imx_clear_rbc_count(void)
+{
+	mmio_clrbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN |
+		(0x3f << SLPCR_RBC_COUNT_SHIFT));
+}
diff --git a/plat/imx/imx8m/imx8m_caam.c b/plat/imx/imx8m/imx8m_caam.c
new file mode 100644
index 0000000..478005e
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_caam.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx8m_caam.h>
+
+void imx8m_caam_init(void)
+{
+	uint32_t sm_cmd;
+
+	/* Dealloc part 0 and 2 with current DID */
+	sm_cmd = (0 << SMC_PART_SHIFT | SMC_CMD_DEALLOC_PART);
+	mmio_write_32(SM_CMD, sm_cmd);
+
+	sm_cmd = (2 << SMC_PART_SHIFT | SMC_CMD_DEALLOC_PART);
+	mmio_write_32(SM_CMD, sm_cmd);
+
+	/* config CAAM JRaMID set MID to Cortex A */
+	mmio_write_32(CAAM_JR0MID, CAAM_NS_MID);
+	mmio_write_32(CAAM_JR1MID, CAAM_NS_MID);
+	mmio_write_32(CAAM_JR2MID, CAAM_NS_MID);
+
+	/* Alloc partition 0 writing SMPO and SMAGs */
+	mmio_write_32(SM_P0_PERM, 0xff);
+	mmio_write_32(SM_P0_SMAG2, 0xffffffff);
+	mmio_write_32(SM_P0_SMAG1, 0xffffffff);
+
+	/* Allocate page 0 and 1 to partition 0 with DID set */
+	sm_cmd = (0 << SMC_PAGE_SHIFT | 0 << SMC_PART_SHIFT |
+			SMC_CMD_ALLOC_PAGE);
+	mmio_write_32(SM_CMD, sm_cmd);
+
+	sm_cmd = (1 << SMC_PAGE_SHIFT | 0 << SMC_PART_SHIFT |
+			SMC_CMD_ALLOC_PAGE);
+	mmio_write_32(SM_CMD, sm_cmd);
+}
diff --git a/plat/imx/imx8m/imx8m_psci_common.c b/plat/imx/imx8m/imx8m_psci_common.c
new file mode 100644
index 0000000..d641628
--- /dev/null
+++ b/plat/imx/imx8m/imx8m_psci_common.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+/*
+ * below callback functions need to be override by i.mx8mq,
+ * for other i.mx8m soc, if no special requirement,
+ * reuse below ones.
+ */
+#pragma weak imx_validate_power_state
+#pragma weak imx_domain_suspend
+#pragma weak imx_domain_suspend_finish
+#pragma weak imx_get_sys_suspend_power_state
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+	/* The non-secure entrypoint should be in RAM space */
+	if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET)
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core_id;
+	uint64_t base_addr = BL31_BASE;
+
+	core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	imx_set_cpu_secure_entry(core_id, base_addr);
+	imx_set_cpu_pwr_on(core_id);
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	plat_gic_pcpu_init();
+	plat_gic_cpuif_enable();
+}
+
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	plat_gic_cpuif_disable();
+	imx_set_cpu_pwr_off(core_id);
+}
+
+int imx_validate_power_state(unsigned int power_state,
+			 psci_power_state_t *req_state)
+{
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int pwr_type = psci_get_pstate_type(power_state);
+	int state_id = psci_get_pstate_id(power_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	if (pwr_type == PSTATE_TYPE_STANDBY) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+	}
+
+	if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_RET_STATE;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_cpu_standby(plat_local_state_t cpu_state)
+{
+	dsb();
+	write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+	isb();
+
+	wfi();
+
+	write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+	isb();
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+	uint64_t base_addr = BL31_BASE;
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		plat_gic_cpuif_disable();
+		imx_set_cpu_secure_entry(core_id, base_addr);
+		imx_set_cpu_lpm(core_id, true);
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
+
+	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state)))
+		imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
+
+	if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
+		imx_set_sys_lpm(core_id, true);
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
+		imx_set_sys_lpm(core_id, false);
+
+	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
+		imx_clear_rbc_count();
+		imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN);
+	}
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		imx_set_cpu_lpm(core_id, false);
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+		isb();
+	}
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
+}
+
+void __dead2 imx_system_reset(void)
+{
+	uintptr_t wdog_base = IMX_WDOG_BASE;
+	unsigned int val;
+
+	/* WDOG_B reset */
+	val = mmio_read_16(wdog_base);
+#ifdef IMX_WDOG_B_RESET
+	val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE |
+		WDOG_WCR_WDT | WDOG_WCR_SRS;
+#else
+	val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS;
+#endif
+	mmio_write_16(wdog_base, val);
+
+	mmio_write_16(wdog_base + WDOG_WSR, 0x5555);
+	mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa);
+	while (1)
+		;
+}
+
+void __dead2 imx_system_off(void)
+{
+	mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV |
+			SNVS_LPCR_DP_EN | SNVS_LPCR_TOP);
+
+	while (1)
+		;
+}
+
+void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+	/*
+	 * before enter WAIT or STOP mode with PLAT(SCU) power down,
+	 * rbc count need to be enabled to make sure PLAT is
+	 * power down successfully even if the the wakeup IRQ is pending
+	 * early before the power down sequence. the RBC counter is
+	 * drived by the 32K OSC, so delay 30us to make sure the counter
+	 * is really running.
+	 */
+	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
+		imx_set_rbc_count();
+		udelay(30);
+	}
+
+	while (1)
+		wfi();
+}
diff --git a/plat/imx/imx8m/imx8mm/gpc.c b/plat/imx/imx8m/imx8mm/gpc.c
new file mode 100644
index 0000000..ab59292
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/gpc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <lib/smccc.h>
+#include <platform_def.h>
+#include <services/std_svc.h>
+
+#include <gpc.h>
+#include <imx_sip_svc.h>
+
+void imx_gpc_init(void)
+{
+	unsigned int val;
+	int i;
+
+	/* mask all the wakeup irq by default */
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0);
+	}
+
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+	/* use GIC wake_request to wakeup C0~C3 from LPM */
+	val |= 0x30c00000;
+	/* clear the MASTER0 LPM handshake */
+	val &= ~(1 << 6);
+	mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+	/* clear MASTER1 & MASTER2 mapping in CPU0(A53) */
+	mmio_clrbits_32(IMX_GPC_BASE + MST_CPU_MAPPING, (MASTER1_MAPPING |
+		MASTER2_MAPPING));
+
+	/* set all mix/PU in A53 domain */
+	mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xffff);
+
+	/*
+	 * Set the CORE & SCU power up timing:
+	 * SW = 0x1, SW2ISO = 0x1;
+	 * the CPU CORE and SCU power up timming counter
+	 * is drived  by 32K OSC, each domain's power up
+	 * latency is (SW + SW2ISO) / 32768
+	 */
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(0) + 0x4, 0x81);
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(1) + 0x4, 0x81);
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(2) + 0x4, 0x81);
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(3) + 0x4, 0x81);
+	mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR + 0x4, 0x81);
+	mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
+		      (0x59 << 10) | 0x5B | (0x2 << 20));
+
+	/* set DUMMY PDN/PUP ACK by default for A53 domain */
+	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53,
+		      A53_DUMMY_PUP_ACK | A53_DUMMY_PDN_ACK);
+
+	/* clear DSM by default */
+	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+	val &= ~SLPCR_EN_DSM;
+	/* enable the fast wakeup wait mode */
+	val |= SLPCR_A53_FASTWUP_WAIT_MODE;
+	/* clear the RBC */
+	val &= ~(0x3f << SLPCR_RBC_COUNT_SHIFT);
+	/* set the STBY_COUNT to 0x5, (128 * 30)us */
+	val &= ~(0x7 << SLPCR_STBY_COUNT_SHFT);
+	val |= (0x5 << SLPCR_STBY_COUNT_SHFT);
+	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+
+	/*
+	 * USB PHY power up needs to make sure RESET bit in SRC is clear,
+	 * otherwise, the PU power up bit in GPC will NOT self-cleared.
+	 * only need to do it once.
+	 */
+	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
+	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
+
+	/* enable all the power domain by default */
+	mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, 0x3fcf);
+}
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
new file mode 100644
index 0000000..c3cd0d0
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_uart.h>
+#include <imx_rdc.h>
+#include <imx8m_caam.h>
+#include <plat_imx8.h>
+
+static const mmap_region_t imx_mmap[] = {
+	MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW),
+	MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */
+	{0},
+};
+
+static const struct aipstz_cfg aipstz[] = {
+	{IMX_AIPSTZ1, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{IMX_AIPSTZ2, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{IMX_AIPSTZ3, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{IMX_AIPSTZ4, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{0},
+};
+
+static const struct imx_rdc_cfg rdc[] = {
+	/* Master domain assignment */
+	RDC_MDAn(0x1, DID1),
+
+	/* peripherals domain permission */
+
+	/* memory region */
+
+	/* Sentinel */
+	{0},
+};
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/* get SPSR for BL33 entry */
+static uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned long mode;
+	uint32_t spsr;
+
+	/* figure out what mode we enter the non-secure world */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+void bl31_tzc380_setup(void)
+{
+	unsigned int val;
+
+	val = mmio_read_32(IMX_IOMUX_GPR_BASE + 0x28);
+	if ((val & GPR_TZASC_EN) != GPR_TZASC_EN)
+		return;
+
+	tzc380_init(IMX_TZASC_BASE);
+
+	/*
+	 * Need to substact offset 0x40000000 from CPU address when
+	 * programming tzasc region for i.mx8mm.
+	 */
+
+	/* Enable 1G-5G S/NS RW */
+	tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) |
+		TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL);
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3)
+{
+	static console_uart_t console;
+	int i;
+
+	/* Enable CSU NS access permission */
+	for (i = 0; i < 64; i++) {
+		mmio_write_32(IMX_CSU_BASE + i * 4, 0x00ff00ff);
+	}
+
+	imx_aipstz_init(aipstz);
+
+	imx_rdc_init(rdc);
+
+	imx8m_caam_init();
+
+	console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+		IMX_CONSOLE_BAUDRATE, &console);
+	/* This console is only used for boot stage */
+	console_set_scope(&console.console, CONSOLE_FLAG_BOOT);
+
+	/*
+	 * tell BL3-1 where the non-secure software image is located
+	 * and the entry state information.
+	 */
+	bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+	bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+	bl31_tzc380_setup();
+}
+
+void bl31_plat_arch_setup(void)
+{
+	mmap_add_region(BL31_BASE, BL31_BASE, (BL31_LIMIT - BL31_BASE),
+		MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, (BL_CODE_END - BL_CODE_BASE),
+		MT_MEMORY | MT_RO | MT_SECURE);
+#if USE_COHERENT_MEM
+	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+		(BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE),
+		MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+	mmap_add(imx_mmap);
+
+	init_xlat_tables();
+
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	generic_delay_timer_init();
+
+	/* select the CKIL source to 32K OSC */
+	mmio_write_32(IMX_ANAMIX_BASE + ANAMIX_MISC_CTL, 0x1);
+
+	plat_gic_driver_init();
+	plat_gic_init();
+
+	imx_gpc_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+	if (type == SECURE)
+		return &bl32_image_ep_info;
+
+	return NULL;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return COUNTER_FREQUENCY;
+}
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_psci.c b/plat/imx/imx8m/imx8mm/imx8mm_psci.c
new file mode 100644
index 0000000..e558724
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/imx8mm_psci.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+	.pwr_domain_on = imx_pwr_domain_on,
+	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
+	.pwr_domain_off = imx_pwr_domain_off,
+	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
+	.validate_power_state = imx_validate_power_state,
+	.cpu_standby = imx_cpu_standby,
+	.pwr_domain_suspend = imx_domain_suspend,
+	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+	.system_reset = imx_system_reset,
+	.system_off = imx_system_off,
+};
+
+/* export the platform specific psci ops */
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	/* sec_entrypoint is used for warm reset */
+	imx_mailbox_init(sec_entrypoint);
+
+	*psci_ops = &imx_plat_psci_ops;
+
+	return 0;
+}
diff --git a/plat/imx/imx8m/imx8mm/include/platform_def.h b/plat/imx/imx8m/imx8mm/include/platform_def.h
new file mode 100644
index 0000000..de9e3b5
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/include/platform_def.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		0xB00
+#define CACHE_WRITEBACK_GRANULE		64
+
+#define PLAT_PRIMARY_CPU		0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define IMX_PWR_LVL0			MPIDR_AFFLVL0
+#define IMX_PWR_LVL1			MPIDR_AFFLVL1
+#define IMX_PWR_LVL2			MPIDR_AFFLVL2
+
+#define PWR_DOMAIN_AT_MAX_LVL		U(1)
+#define PLAT_MAX_PWR_LVL		U(2)
+#define PLAT_MAX_OFF_STATE		U(4)
+#define PLAT_MAX_RET_STATE		U(2)
+
+#define PLAT_WAIT_RET_STATE		U(1)
+#define PLAT_STOP_OFF_STATE		U(3)
+
+#define BL31_BASE			U(0x920000)
+#define BL31_LIMIT			U(0x940000)
+#define BL32_BASE			U(0xbe000000)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET		U(0x40200000)
+
+/* GICv3 base address */
+#define PLAT_GICD_BASE			U(0x38800000)
+#define PLAT_GICR_BASE			U(0x38880000)
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		16
+
+#define HAB_RVT_BASE			U(0x00000900) /* HAB_RVT for i.MX8MM */
+
+#define IMX_BOOT_UART_BASE		U(0x30890000)
+#define IMX_BOOT_UART_CLK_IN_HZ		24000000 /* Select 24MHz oscillator */
+
+#define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
+#define PLAT_CRASH_UART_CLK_IN_HZ	24000000
+#define IMX_CONSOLE_BAUDRATE		115200
+
+#define IMX_AIPSTZ1			U(0x301f0000)
+#define IMX_AIPSTZ2			U(0x305f0000)
+#define IMX_AIPSTZ3			U(0x309f0000)
+#define IMX_AIPSTZ4			U(0x32df0000)
+
+#define IMX_AIPS_BASE			U(0x30000000)
+#define IMX_AIPS_SIZE			U(0xC00000)
+#define IMX_GPV_BASE			U(0x32000000)
+#define IMX_GPV_SIZE			U(0x800000)
+#define IMX_AIPS1_BASE			U(0x30200000)
+#define IMX_AIPS4_BASE			U(0x32c00000)
+#define IMX_ANAMIX_BASE			U(0x30360000)
+#define IMX_CCM_BASE			U(0x30380000)
+#define IMX_SRC_BASE			U(0x30390000)
+#define IMX_GPC_BASE			U(0x303a0000)
+#define IMX_RDC_BASE			U(0x303d0000)
+#define IMX_CSU_BASE			U(0x303e0000)
+#define IMX_WDOG_BASE			U(0x30280000)
+#define IMX_SNVS_BASE			U(0x30370000)
+#define IMX_NOC_BASE			U(0x32700000)
+#define IMX_TZASC_BASE			U(0x32F80000)
+#define IMX_IOMUX_GPR_BASE		U(0x30340000)
+#define IMX_CAAM_BASE			U(0x30900000)
+#define IMX_DDRC_BASE			U(0x3d400000)
+#define IMX_DDRPHY_BASE			U(0x3c000000)
+#define IMX_DDR_IPS_BASE		U(0x3d000000)
+#define IMX_ROM_BASE			U(0x0)
+
+#define GPV_BASE			U(0x32000000)
+#define GPV_SIZE			U(0x800000)
+#define IMX_GIC_BASE			PLAT_GICD_BASE
+#define IMX_GIC_SIZE			U(0x200000)
+
+#define WDOG_WSR			U(0x2)
+#define WDOG_WCR_WDZST			BIT(0)
+#define WDOG_WCR_WDBG			BIT(1)
+#define WDOG_WCR_WDE			BIT(2)
+#define WDOG_WCR_WDT			BIT(3)
+#define WDOG_WCR_SRS			BIT(4)
+#define WDOG_WCR_WDA			BIT(5)
+#define WDOG_WCR_SRE			BIT(6)
+#define WDOG_WCR_WDW			BIT(7)
+
+#define SRC_A53RCR0			U(0x4)
+#define SRC_A53RCR1			U(0x8)
+#define SRC_OTG1PHY_SCR			U(0x20)
+#define SRC_OTG2PHY_SCR			U(0x24)
+#define SRC_GPR1_OFFSET			U(0x74)
+
+#define SNVS_LPCR			U(0x38)
+#define SNVS_LPCR_SRTC_ENV		BIT(0)
+#define SNVS_LPCR_DP_EN			BIT(5)
+#define SNVS_LPCR_TOP			BIT(6)
+
+#define IOMUXC_GPR10			U(0x28)
+#define GPR_TZASC_EN			BIT(0)
+#define GPR_TZASC_EN_LOCK		BIT(16)
+
+#define ANAMIX_MISC_CTL			U(0x124)
+
+#define MAX_CSU_NUM			U(64)
+
+#define OCRAM_S_BASE			U(0x00180000)
+#define OCRAM_S_SIZE			U(0x8000)
+#define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
+
+#define COUNTER_FREQUENCY		8000000 /* 8MHz */
+
+#define IMX_WDOG_B_RESET
diff --git a/plat/imx/imx8m/imx8mm/platform.mk b/plat/imx/imx8m/imx8mm/platform.mk
new file mode 100644
index 0000000..6d32dbb
--- /dev/null
+++ b/plat/imx/imx8m/imx8mm/platform.mk
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES		:=	-Iplat/imx/common/include		\
+				-Iplat/imx/imx8m/include		\
+				-Iplat/imx/imx8m/imx8mm/include
+
+IMX_GIC_SOURCES		:=	drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c   \
+				drivers/arm/gic/v3/gic500.c             \
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/common/gic_common.c	\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES		+=	plat/imx/common/imx8_helpers.S			\
+				plat/imx/imx8m/gpc_common.c			\
+				plat/imx/imx8m/imx_aipstz.c			\
+				plat/imx/imx8m/imx_rdc.c			\
+				plat/imx/imx8m/imx8m_caam.c			\
+				plat/imx/imx8m/imx8m_psci_common.c		\
+				plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c	\
+				plat/imx/imx8m/imx8mm/imx8mm_psci.c		\
+				plat/imx/imx8m/imx8mm/gpc.c			\
+				plat/imx/common/imx8_topology.c			\
+				plat/imx/common/imx_sip_handler.c		\
+				plat/imx/common/imx_sip_svc.c			\
+				plat/imx/common/imx_uart_console.S		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				lib/xlat_tables/xlat_tables_common.c		\
+				lib/cpus/aarch64/cortex_a53.S			\
+				drivers/arm/tzc/tzc380.c			\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				${IMX_GIC_SOURCES}
+
+USE_COHERENT_MEM	:=	1
+RESET_TO_BL31		:=	1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+
+ERRATA_A53_835769	:=	1
+ERRATA_A53_843419	:=	1
+ERRATA_A53_855873	:=	1
diff --git a/plat/imx/imx8m/imx8mq/gpc.c b/plat/imx/imx8m/imx8mq/gpc.c
new file mode 100644
index 0000000..942ae45
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/gpc.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+#include <services/std_svc.h>
+
+#include <gpc.h>
+
+/* use wfi power down the core */
+void imx_set_cpu_pwr_off(unsigned int core_id)
+{
+	/* enable the wfi power down of the core */
+	mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+			(1 << (core_id + 20)));
+	/* assert the pcg pcr bit of the core */
+	mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+};
+
+/* if out of lpm, we need to do reverse steps */
+void imx_set_cpu_lpm(unsigned int core_id, bool pdn)
+{
+	if (pdn) {
+		/* enable the core WFI PDN & IRQ PUP */
+		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+				(1 << (core_id + 20)) | COREx_IRQ_WUP(core_id));
+		/* assert the pcg pcr bit of the core */
+		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+	} else {
+		/* disable CORE WFI PDN & IRQ PUP */
+		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) |
+				COREx_IRQ_WUP(core_id));
+		/* deassert the pcg pcr bit of the core */
+		mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1);
+	}
+}
+
+void imx_pup_pdn_slot_config(int last_core, bool pdn)
+{
+	if (pdn) {
+		/* SLOT0 for A53 PLAT power down */
+		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN);
+		/* SLOT1 for A53 PLAT power up */
+		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP);
+		/* SLOT2 for A53 primary core power up */
+		mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core));
+		/* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */
+		mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
+			A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK);
+	} else {
+		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF);
+		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF);
+		mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF);
+		mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF,
+			A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK);
+	}
+}
+
+void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state)
+{
+	uint32_t val;
+
+	if (is_local_state_off(power_state)) {
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+		val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */
+		val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+		/* enable C2-3's STOP mode */
+		mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP);
+
+		/* enable PLAT/SCU power down */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		val &= ~EN_L2_WFI_PDN;
+		val |= L2PGE | EN_PLAT_PDN;
+		val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */
+		val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+		imx_pup_pdn_slot_config(last_core, true);
+
+		/* enable PLAT PGC */
+		mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
+	} else {
+		/* clear PLAT PGC */
+		mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1);
+
+		/* clear the slot and ack for cluster power down */
+		imx_pup_pdn_slot_config(last_core, false);
+
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+		val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */
+		val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+		/* set A53 LPM to RUN mode */
+		mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK);
+
+		/* clear PLAT/SCU power down */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		val |= EN_L2_WFI_PDN;
+		val &= ~(L2PGE | EN_PLAT_PDN);
+		val &= ~COREx_LPM_PUP(last_core);  /* disable C0's LPM PUP */
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+	}
+}
+
+void imx_gpc_init(void)
+{
+	uint32_t val;
+	int i;
+	/* mask all the interrupt by default */
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0);
+	}
+	/* Due to the hardware design requirement, need to make
+	 * sure GPR interrupt(#32) is unmasked during RUN mode to
+	 * avoid entering DSM mode by mistake.
+	 */
+	mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53, 0xFFFFFFFE);
+	mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53, 0xFFFFFFFE);
+	mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53, 0xFFFFFFFE);
+	mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53, 0xFFFFFFFE);
+
+	/* use external IRQs to wakeup C0~C3 from LPM */
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+	val |= IRQ_SRC_A53_WUP;
+	/* clear the MASTER0 LPM handshake */
+	val &= ~MASTER0_LPM_HSK;
+	mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+	/* mask M4 DSM trigger if M4 is NOT enabled */
+	mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK);
+
+	/* set all mix/PU in A53 domain */
+	mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd);
+
+	/* set SCU timming */
+	mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING,
+		      (0x59 << 10) | 0x5B | (0x2 << 20));
+
+	/* set DUMMY PDN/PUP ACK by default for A53 domain */
+	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK |
+		A53_DUMMY_PDN_ACK);
+
+	/* disable DSM mode by default */
+	mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK);
+
+	/*
+	 * USB PHY power up needs to make sure RESET bit in SRC is clear,
+	 * otherwise, the PU power up bit in GPC will NOT self-cleared.
+	 * only need to do it once.
+	 */
+	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
+	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
+
+	/* enable all the power domain by default */
+	mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, 0x3fcf);
+}
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
new file mode 100644
index 0000000..26a3b36
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/tzc380.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <gpc.h>
+#include <imx_aipstz.h>
+#include <imx_uart.h>
+#include <imx8m_caam.h>
+#include <plat_imx8.h>
+
+static const mmap_region_t imx_mmap[] = {
+	MAP_REGION_FLAT(GPV_BASE, GPV_SIZE, MT_DEVICE | MT_RW), /* GPV map */
+	MAP_REGION_FLAT(IMX_ROM_BASE, IMX_ROM_SIZE, MT_MEMORY | MT_RO), /* ROM map */
+	MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */
+	MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), /* GIC map */
+	{0},
+};
+
+static const struct aipstz_cfg aipstz[] = {
+	{AIPSTZ1_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{AIPSTZ2_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{AIPSTZ3_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{AIPSTZ4_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, },
+	{0},
+};
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static uint32_t imx_soc_revision;
+
+int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
+				u_register_t x3)
+{
+	return imx_soc_revision;
+}
+
+#define ANAMIX_DIGPROG		0x6c
+#define ROM_SOC_INFO_A0		0x800
+#define ROM_SOC_INFO_B0		0x83C
+#define OCOTP_SOC_INFO_B1	0x40
+
+static void imx8mq_soc_info_init(void)
+{
+	uint32_t rom_version;
+	uint32_t ocotp_val;
+
+	imx_soc_revision = mmio_read_32(IMX_ANAMIX_BASE + ANAMIX_DIGPROG);
+	rom_version = mmio_read_8(IMX_ROM_BASE + ROM_SOC_INFO_A0);
+	if (rom_version == 0x10)
+		return;
+
+	rom_version = mmio_read_8(IMX_ROM_BASE + ROM_SOC_INFO_B0);
+	if (rom_version == 0x20) {
+		imx_soc_revision &= ~0xff;
+		imx_soc_revision |= rom_version;
+		return;
+	}
+
+	/* 0xff0055aa is magic number for B1 */
+	ocotp_val = mmio_read_32(IMX_OCOTP_BASE + OCOTP_SOC_INFO_B1);
+	if (ocotp_val == 0xff0055aa) {
+		imx_soc_revision &= ~0xff;
+		imx_soc_revision |= 0x21;
+		return;
+	}
+}
+
+/* get SPSR for BL33 entry */
+static uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned long mode;
+	uint32_t spsr;
+
+	/* figure out what mode we enter the non-secure world */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+static void bl31_tz380_setup(void)
+{
+	unsigned int val;
+
+	val = mmio_read_32(IMX_IOMUX_GPR_BASE + IOMUXC_GPR10);
+	if ((val & GPR_TZASC_EN) != GPR_TZASC_EN)
+		return;
+
+	tzc380_init(IMX_TZASC_BASE);
+	/*
+	 * Need to substact offset 0x40000000 from CPU address when
+	 * programming tzasc region for i.mx8mq. Enable 1G-5G S/NS RW
+	 */
+	tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) |
+				TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL);
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			u_register_t arg2, u_register_t arg3)
+{
+	int i;
+	/* enable CSU NS access permission */
+	for (i = 0; i < 64; i++) {
+		mmio_write_32(IMX_CSU_BASE + i * 4, 0xffffffff);
+	}
+
+	imx_aipstz_init(aipstz);
+
+	imx8m_caam_init();
+
+#if DEBUG_CONSOLE
+	static console_uart_t console;
+
+	console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+		IMX_CONSOLE_BAUDRATE, &console);
+#endif
+	/*
+	 * tell BL3-1 where the non-secure software image is located
+	 * and the entry state information.
+	 */
+	bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+	bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+	bl31_tz380_setup();
+}
+
+void bl31_plat_arch_setup(void)
+{
+	mmap_add_region(BL31_BASE, BL31_BASE, (BL31_LIMIT - BL31_BASE),
+		MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, (BL_CODE_END - BL_CODE_BASE),
+		MT_MEMORY | MT_RO | MT_SECURE);
+
+	mmap_add(imx_mmap);
+
+#if USE_COHERENT_MEM
+	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+		BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+		MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+	/* setup xlat table */
+	init_xlat_tables();
+	/* enable the MMU */
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	generic_delay_timer_init();
+
+	/* init the GICv3 cpu and distributor interface */
+	plat_gic_driver_init();
+	plat_gic_init();
+
+	/* determine SOC revision for erratas */
+	imx8mq_soc_info_init();
+
+	/* gpc init */
+	imx_gpc_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+	if (type == SECURE)
+		return &bl32_image_ep_info;
+
+	return NULL;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return COUNTER_FREQUENCY;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	return;
+}
diff --git a/plat/imx/imx8m/imx8mq/imx8mq_psci.c b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
new file mode 100644
index 0000000..04e191f
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/imx8mq_psci.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <gpc.h>
+#include <imx8m_psci.h>
+#include <plat_imx8.h>
+
+int imx_validate_power_state(unsigned int power_state,
+			 psci_power_state_t *req_state)
+{
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int pwr_type = psci_get_pstate_type(power_state);
+	int state_id = psci_get_pstate_id(power_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	if (pwr_type == PSTATE_TYPE_STANDBY) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+	}
+
+	if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+	uint64_t base_addr = BL31_BASE;
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		/* disable the cpu interface */
+		plat_gic_cpuif_disable();
+		imx_set_cpu_secure_entry(core_id, base_addr);
+		imx_set_cpu_lpm(core_id, true);
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
+
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
+		imx_set_cluster_powerdown(core_id, true);
+	else
+		imx_set_cluster_standby(true);
+
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		imx_set_sys_lpm(core_id, true);
+	}
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* check the system level status */
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		imx_set_sys_lpm(core_id, false);
+		imx_clear_rbc_count();
+	}
+
+	/* check the cluster level power status */
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state)))
+		imx_set_cluster_powerdown(core_id, false);
+	else
+		imx_set_cluster_standby(false);
+
+	/* check the core level power status */
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		/* clear the core lpm setting */
+		imx_set_cpu_lpm(core_id, false);
+		/* enable the gic cpu interface */
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~0x4));
+		isb();
+	}
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
+
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
+}
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+	.pwr_domain_on = imx_pwr_domain_on,
+	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
+	.pwr_domain_off = imx_pwr_domain_off,
+	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
+	.validate_power_state = imx_validate_power_state,
+	.cpu_standby = imx_cpu_standby,
+	.pwr_domain_suspend = imx_domain_suspend,
+	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+	.system_reset = imx_system_reset,
+	.system_off = imx_system_off,
+};
+
+/* export the platform specific psci ops */
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	imx_mailbox_init(sec_entrypoint);
+	/* sec_entrypoint is used for warm reset */
+	*psci_ops = &imx_plat_psci_ops;
+
+	return 0;
+}
diff --git a/plat/imx/imx8m/imx8mq/include/platform_def.h b/plat/imx/imx8m/imx8mq/include/platform_def.h
new file mode 100644
index 0000000..3c212e3
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/include/platform_def.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		0x800
+#define CACHE_WRITEBACK_GRANULE		64
+
+#define PLAT_PRIMARY_CPU		0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define IMX_PWR_LVL0			MPIDR_AFFLVL0
+#define IMX_PWR_LVL1			MPIDR_AFFLVL1
+#define IMX_PWR_LVL2			MPIDR_AFFLVL2
+
+#define PWR_DOMAIN_AT_MAX_LVL		U(1)
+#define PLAT_MAX_PWR_LVL		U(2)
+#define PLAT_MAX_OFF_STATE		U(4)
+#define PLAT_MAX_RET_STATE		U(1)
+
+#define PLAT_WAIT_RET_STATE		PLAT_MAX_RET_STATE
+#define PLAT_WAIT_OFF_STATE		U(2)
+#define PLAT_STOP_OFF_STATE		U(3)
+
+#define BL31_BASE			U(0x910000)
+#define BL31_LIMIT			U(0x920000)
+#define BL32_BASE			U(0xfe000000)
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET		U(0x40200000)
+
+/* GICv3 base address */
+#define PLAT_GICD_BASE			U(0x38800000)
+#define PLAT_GICR_BASE			U(0x38880000)
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+
+#define MAX_XLAT_TABLES			4
+#define MAX_MMAP_REGIONS		14
+
+#define HAB_RVT_BASE			U(0x00000880) /* HAB_RVT for i.MX8MQ */
+
+#define IMX_BOOT_UART_BASE		U(0x30860000)
+#define IMX_BOOT_UART_CLK_IN_HZ		25000000 /* Select 25Mhz oscillator */
+#define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
+#define PLAT_CRASH_UART_CLK_IN_HZ	25000000
+#define IMX_CONSOLE_BAUDRATE		115200
+
+#define IMX_AIPS_BASE			U(0x30200000)
+#define IMX_AIPS_SIZE			U(0xC00000)
+#define IMX_AIPS1_BASE			U(0x30200000)
+#define IMX_AIPS3_ARB_BASE		U(0x30800000)
+#define IMX_OCOTP_BASE			U(0x30350000)
+#define IMX_ANAMIX_BASE			U(0x30360000)
+#define IMX_CCM_BASE			U(0x30380000)
+#define IMX_SRC_BASE			U(0x30390000)
+#define IMX_GPC_BASE			U(0x303a0000)
+#define IMX_RDC_BASE			U(0x303d0000)
+#define IMX_CSU_BASE			U(0x303e0000)
+#define IMX_WDOG_BASE			U(0x30280000)
+#define IMX_SNVS_BASE			U(0x30370000)
+#define IMX_NOC_BASE			U(0x32700000)
+#define IMX_TZASC_BASE			U(0x32F80000)
+#define IMX_CAAM_BASE			U(0x30900000)
+#define IMX_IOMUX_GPR_BASE		U(0x30340000)
+#define IMX_DDRC_BASE			U(0x3d400000)
+#define IMX_DDRPHY_BASE			U(0x3c000000)
+#define IMX_DDR_IPS_BASE		U(0x3d000000)
+
+#define IMX_ROM_BASE			U(0x00000000)
+#define IMX_ROM_SIZE			U(0x20000)
+
+#define AIPSTZ1_BASE			U(0x301f0000)
+#define AIPSTZ2_BASE			U(0x305f0000)
+#define AIPSTZ3_BASE			U(0x309f0000)
+#define AIPSTZ4_BASE			U(0x32df0000)
+
+#define GPV_BASE			U(0x32000000)
+#define GPV_SIZE			U(0x800000)
+#define IMX_GIC_BASE			PLAT_GICD_BASE
+#define IMX_GIC_SIZE			U(0x200000)
+
+#define WDOG_WSR			U(0x2)
+#define WDOG_WCR_WDZST			BIT(0)
+#define WDOG_WCR_WDBG			BIT(1)
+#define WDOG_WCR_WDE			BIT(2)
+#define WDOG_WCR_WDT			BIT(3)
+#define WDOG_WCR_SRS			BIT(4)
+#define WDOG_WCR_WDA			BIT(5)
+#define WDOG_WCR_SRE			BIT(6)
+#define WDOG_WCR_WDW			BIT(7)
+
+#define SRC_A53RCR0			U(0x4)
+#define SRC_A53RCR1			U(0x8)
+#define SRC_OTG1PHY_SCR			U(0x20)
+#define SRC_OTG2PHY_SCR			U(0x24)
+#define SRC_GPR1_OFFSET			U(0x74)
+
+#define SNVS_LPCR			U(0x38)
+#define SNVS_LPCR_SRTC_ENV		BIT(0)
+#define SNVS_LPCR_DP_EN			BIT(5)
+#define SNVS_LPCR_TOP			BIT(6)
+
+
+#define IOMUXC_GPR10			U(0x28)
+#define GPR_TZASC_EN			BIT(0)
+#define GPR_TZASC_EN_LOCK		BIT(16)
+
+#define OCRAM_S_BASE			U(0x00180000)
+#define OCRAM_S_SIZE			U(0x8000)
+#define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
+
+#define COUNTER_FREQUENCY		8000000 /* 8MHz */
+
+#define DEBUG_CONSOLE			0
+#define IMX_WDOG_B_RESET
diff --git a/plat/imx/imx8m/imx8mq/platform.mk b/plat/imx/imx8m/imx8mq/platform.mk
new file mode 100644
index 0000000..44ce555
--- /dev/null
+++ b/plat/imx/imx8m/imx8mq/platform.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES		:=	-Iplat/imx/common/include		\
+				-Iplat/imx/imx8m/include		\
+				-Iplat/imx/imx8m/imx8mq/include
+
+IMX_GIC_SOURCES		:=	drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c   \
+				drivers/arm/gic/v3/gic500.c             \
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/common/gic_common.c	\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES		+=	plat/imx/common/imx8_helpers.S			\
+				plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c	\
+				plat/imx/imx8m/imx8mq/imx8mq_psci.c		\
+				plat/imx/imx8m/gpc_common.c			\
+				plat/imx/imx8m/imx_aipstz.c			\
+				plat/imx/imx8m/imx8m_caam.c			\
+				plat/imx/imx8m/imx8m_psci_common.c		\
+				plat/imx/imx8m/imx8mq/gpc.c			\
+				plat/imx/common/imx8_topology.c			\
+				plat/imx/common/imx_sip_handler.c		\
+				plat/imx/common/imx_sip_svc.c			\
+				plat/imx/common/imx_uart_console.S		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				lib/xlat_tables/xlat_tables_common.c		\
+				lib/cpus/aarch64/cortex_a53.S			\
+				drivers/arm/tzc/tzc380.c			\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				${IMX_GIC_SOURCES}
+
+USE_COHERENT_MEM	:=	1
+RESET_TO_BL31		:=	1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+
+ERRATA_A53_835769	:=	1
+ERRATA_A53_843419	:=	1
+ERRATA_A53_855873	:=	1
diff --git a/plat/imx/imx8m/imx_aipstz.c b/plat/imx/imx8m/imx_aipstz.c
new file mode 100644
index 0000000..ecf8b1d
--- /dev/null
+++ b/plat/imx/imx8m/imx_aipstz.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_aipstz.h>
+
+void imx_aipstz_init(const struct aipstz_cfg *aipstz_cfg)
+{
+	const struct aipstz_cfg *aipstz = aipstz_cfg;
+
+	while (aipstz->base != 0U) {
+		mmio_write_32(aipstz->base + AIPSTZ_MPR0, aipstz->mpr0);
+		mmio_write_32(aipstz->base + AIPSTZ_MPR1, aipstz->mpr1);
+
+		for (int i = 0; i < AIPSTZ_OPACR_NUM; i++)
+			mmio_write_32(aipstz->base + OPACR_OFFSET(i), aipstz->opacr[i]);
+
+		aipstz++;
+	}
+}
diff --git a/plat/imx/imx8m/imx_rdc.c b/plat/imx/imx8m/imx_rdc.c
new file mode 100644
index 0000000..85de191
--- /dev/null
+++ b/plat/imx/imx8m/imx_rdc.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <imx_rdc.h>
+
+void imx_rdc_init(const struct imx_rdc_cfg *rdc_cfg)
+{
+	const struct imx_rdc_cfg *rdc = rdc_cfg;
+
+	while (rdc->type != RDC_INVALID) {
+		switch (rdc->type) {
+		case RDC_MDA:
+			/* MDA config */
+			mmio_write_32(MDAn(rdc->index), rdc->setting.rdc_mda);
+			break;
+		case RDC_PDAP:
+			/* peripheral access permission config */
+			mmio_write_32(PDAPn(rdc->index), rdc->setting.rdc_pdap);
+			break;
+		case RDC_MEM_REGION:
+			/* memory region access permission config */
+			mmio_write_32(MRSAn(rdc->index), rdc->setting.rdc_mem_region[0]);
+			mmio_write_32(MREAn(rdc->index), rdc->setting.rdc_mem_region[1]);
+			mmio_write_32(MRCn(rdc->index), rdc->setting.rdc_mem_region[2]);
+			break;
+		default:
+			break;
+		}
+
+		rdc++;
+	}
+}
diff --git a/plat/imx/imx8m/include/gpc.h b/plat/imx/imx8m/include/gpc.h
new file mode 100644
index 0000000..139132c
--- /dev/null
+++ b/plat/imx/imx8m/include/gpc.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_GPC_H
+#define IMX8M_GPC_H
+
+#define LPCR_A53_BSC			0x0
+#define LPCR_A53_BSC2			0x108
+#define LPCR_A53_AD			0x4
+#define LPCR_M4				0x8
+#define SLPCR				0x14
+#define MST_CPU_MAPPING			0x18
+#define MLPCR				0x20
+#define PGC_ACK_SEL_A53			0x24
+#define IMR1_CORE0_A53			0x30
+#define IMR1_CORE1_A53			0x40
+#define IMR1_CORE2_A53			0x1C0
+#define IMR1_CORE3_A53			0x1D0
+#define IMR1_CORE0_M4			0x50
+#define SLT0_CFG			0xB0
+#define GPC_PU_PWRHSK			0x1FC
+#define PGC_CPU_0_1_MAPPING		0xEC
+#define CPU_PGC_UP_TRG			0xF0
+#define PU_PGC_UP_TRG			0xF8
+#define CPU_PGC_DN_TRG			0xFC
+#define PU_PGC_DN_TRG			0x104
+#define A53_CORE0_PGC			0x800
+#define A53_PLAT_PGC			0x900
+#define PLAT_PGC_PCR			0x900
+#define PGC_SCU_TIMING			0x910
+
+#define MASK_DSM_TRIGGER_A53		BIT(31)
+#define IRQ_SRC_A53_WUP			BIT(30)
+#define IRQ_SRC_A53_WUP_SHIFT		30
+#define IRQ_SRC_C1			BIT(29)
+#define IRQ_SRC_C0			BIT(28)
+#define IRQ_SRC_C3			BIT(23)
+#define IRQ_SRC_C2			BIT(22)
+#define CPU_CLOCK_ON_LPM		BIT(14)
+#define A53_CLK_ON_LPM			BIT(14)
+#define MASTER0_LPM_HSK			BIT(6)
+
+#define L2PGE				BIT(31)
+#define EN_L2_WFI_PDN			BIT(5)
+#define EN_PLAT_PDN			BIT(4)
+
+#define SLPCR_EN_DSM			BIT(31)
+#define SLPCR_RBC_EN			BIT(30)
+#define SLPCR_A53_FASTWUP_STOP_MODE	BIT(17)
+#define SLPCR_A53_FASTWUP_WAIT_MODE	BIT(16)
+#define SLPCR_VSTBY			BIT(2)
+#define SLPCR_SBYOS			BIT(1)
+#define SLPCR_BYPASS_PMIC_READY		BIT(0)
+#define SLPCR_RBC_COUNT_SHIFT		24
+#define SLPCR_STBY_COUNT_SHFT		3
+
+#define A53_DUMMY_PDN_ACK		BIT(15)
+#define A53_DUMMY_PUP_ACK		BIT(31)
+#define A53_PLAT_PDN_ACK		BIT(2)
+#define A53_PLAT_PUP_ACK		BIT(18)
+
+#define PLAT_PUP_SLT_CTRL		BIT(9)
+#define PLAT_PDN_SLT_CTRL		BIT(8)
+
+#define SLT_PLAT_PDN			BIT(8)
+#define SLT_PLAT_PUP			BIT(9)
+
+#define MASTER1_MAPPING			BIT(1)
+#define MASTER2_MAPPING			BIT(2)
+
+/* helper macro */
+#define A53_LPM_MASK	U(0xF)
+#define A53_LPM_WAIT	U(0x5)
+#define A53_LPM_STOP	U(0xA)
+#define LPM_MODE(local_state)		((local_state) == PLAT_WAIT_RET_STATE ? A53_LPM_WAIT : A53_LPM_STOP)
+
+#define DSM_MODE_MASK	BIT(31)
+
+#define A53_CORE_WUP_SRC(core_id)	(1 << ((core_id) < 2 ? 28 + (core_id) : 22 + (core_id) - 2))
+#define COREx_PGC_PCR(core_id)		(0x800 + (core_id) * 0x40)
+#define COREx_WFI_PDN(core_id)		(1 << ((core_id) < 2 ? (core_id) * 2 : ((core_id) - 2) * 2 + 16))
+#define COREx_IRQ_WUP(core_id)		((core_id) < 2 ? (1 << ((core_id) * 2 + 8)) : (1 << ((core_id) * 2 + 20)))
+#define COREx_LPM_PUP(core_id)		((core_id) < 2 ? (1 << ((core_id) * 2 + 9)) : (1 << ((core_id) * 2 + 21)))
+#define SLTx_CFG(n)			((SLT0_CFG + ((n) * 4)))
+#define SLT_COREx_PUP(core_id)		(0x2 << ((core_id) * 2))
+
+#define IRQ_IMR_NUM	4
+#define IMR_MASK_ALL	0xffffffff
+
+/* function declare */
+void imx_gpc_init(void);
+void imx_set_cpu_secure_entry(unsigned int core_index, uintptr_t sec_entrypoint);
+void imx_set_cpu_pwr_off(unsigned int core_index);
+void imx_set_cpu_pwr_on(unsigned int core_index);
+void imx_set_cpu_lpm(unsigned int core_index, bool pdn);
+void imx_set_cluster_standby(bool retention);
+void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state);
+void imx_noc_slot_config(bool pdn);
+void imx_set_sys_wakeup(unsigned int last_core, bool pdn);
+void imx_set_sys_lpm(unsigned last_core, bool retention);
+void imx_set_rbc_count(void);
+void imx_clear_rbc_count(void);
+
+#endif /*IMX8M_GPC_H */
diff --git a/plat/imx/imx8m/include/imx8m_caam.h b/plat/imx/imx8m/include/imx8m_caam.h
new file mode 100644
index 0000000..84725b1
--- /dev/null
+++ b/plat/imx/imx8m/include/imx8m_caam.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_CAAM_H
+#define IMX8M_CAAM_H
+
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#define CAAM_JR0MID		(IMX_CAAM_BASE + 0x10)
+#define CAAM_JR1MID		(IMX_CAAM_BASE + 0x18)
+#define CAAM_JR2MID		(IMX_CAAM_BASE + 0x20)
+#define CAAM_NS_MID		(0x1)
+
+#define JR0_BASE		(IMX_CAAM_BASE + 0x1000)
+
+#define SM_P0_PERM		(JR0_BASE + 0xa04)
+#define SM_P0_SMAG2		(JR0_BASE + 0xa08)
+#define SM_P0_SMAG1		(JR0_BASE + 0xa0c)
+#define SM_CMD			(JR0_BASE + 0xbe4)
+
+/* secure memory command */
+#define SMC_PAGE_SHIFT		16
+#define SMC_PART_SHIFT		8
+
+#define SMC_CMD_ALLOC_PAGE	0x01	/* allocate page to this partition */
+#define SMC_CMD_DEALLOC_PART	0x03	/* deallocate partition */
+
+void imx8m_caam_init(void);
+
+#endif /* IMX8M_CAAM_H */
diff --git a/plat/imx/imx8m/include/imx8m_psci.h b/plat/imx/imx8m/include/imx8m_psci.h
new file mode 100644
index 0000000..4966403
--- /dev/null
+++ b/plat/imx/imx8m/include/imx8m_psci.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX8M_PSCI_H
+#define IMX8M_PSCI_H
+
+#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+int imx_pwr_domain_on(u_register_t mpidr);
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state);
+void imx_pwr_domain_off(const psci_power_state_t *target_state);
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint);
+int imx_validate_power_state(unsigned int power_state, psci_power_state_t *rq_state);
+void imx_cpu_standby(plat_local_state_t cpu_state);
+void imx_domain_suspend(const psci_power_state_t *target_state);
+void imx_domain_suspend_finish(const psci_power_state_t *target_state);
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state);
+void __dead2 imx_system_reset(void);
+void __dead2 imx_system_off(void);
+void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state);
+
+#endif /* IMX8M_PSCI_H */
diff --git a/plat/imx/imx8m/include/imx_aipstz.h b/plat/imx/imx8m/include/imx_aipstz.h
new file mode 100644
index 0000000..7616862
--- /dev/null
+++ b/plat/imx/imx8m/include/imx_aipstz.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_AIPSTZ_H
+#define IMX_AIPSTZ_H
+
+#include <lib/utils_def.h>
+
+#define AIPSTZ_MPR0		U(0x0)
+#define AIPSTZ_MPR1		U(0x4)
+
+#define AIPSTZ_OPACR_NUM	U(0x5)
+#define OPACR_OFFSET(i)		U((i) * 4 + 0x40)
+
+struct aipstz_cfg {
+	uintptr_t base;
+	uint32_t mpr0;
+	uint32_t mpr1;
+	uint32_t opacr[AIPSTZ_OPACR_NUM];
+};
+
+void imx_aipstz_init(const struct aipstz_cfg *aipstz_cfg);
+
+#endif /* IMX_AIPSTZ_H */
diff --git a/plat/imx/imx8m/include/imx_rdc.h b/plat/imx/imx8m/include/imx_rdc.h
new file mode 100644
index 0000000..6be8550
--- /dev/null
+++ b/plat/imx/imx8m/include/imx_rdc.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019, NXP. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_RDC_H
+#define IMX_RDC_H
+
+#include <lib/utils_def.h>
+
+#include <platform_def.h>
+
+#define MDAn(x)		(IMX_RDC_BASE + 0x200 + (x) * 4)
+#define PDAPn(x)	(IMX_RDC_BASE + 0x400 + (x) * 4)
+#define MRSAn(x)	(IMX_RDC_BASE + 0x800 + (x) * 4)
+#define MREAn(x)	(IMX_RDC_BASE + 0x804 + (x) * 4)
+#define MRCn(x)		(IMX_RDC_BASE + 0x808 + (x) * 4)
+
+#define LCK		BIT(31)
+#define SREQ		BIT(30)
+#define ENA		BIT(30)
+
+#define DID0		U(0x0)
+#define DID1		U(0x1)
+#define DID2		U(0x2)
+#define DID3		U(0x3)
+
+#define D3R		BIT(7)
+#define D3W		BIT(6)
+#define D2R		BIT(5)
+#define D2W		BIT(4)
+#define D1R		BIT(3)
+#define D1W		BIT(2)
+#define D0R		BIT(1)
+#define D0W		BIT(0)
+
+union rdc_setting {
+	uint32_t rdc_mda; /* Master Domain Assignment */
+	uint32_t rdc_pdap; /* Peripheral Domain Access Permissions */
+	uint32_t rdc_mem_region[3]; /* Memory Region Access Control */
+};
+
+enum rdc_type {
+	RDC_INVALID,
+	RDC_MDA,
+	RDC_PDAP,
+	RDC_MEM_REGION,
+};
+
+struct imx_rdc_cfg {
+	enum rdc_type type; /* config type Master, Peripheral or Memory region */
+	int index;
+	union rdc_setting setting;
+};
+
+#define RDC_MDAn(i, mda)	\
+	{RDC_MDA, (i), .setting.rdc_mda = (mda), }
+#define RDC_PDAPn(i, pdap)	\
+	{RDC_PDAP, (i), .setting.rdc_pdap = (pdap), }
+
+#define RDC_MEM_REGIONn(i, msa, mea, mrc)	\
+	{ RDC_MEM_REGION, (i), 			\
+	  .setting.rdc_mem_region[0] = (msa),	\
+	  .setting.rdc_mem_region[1] = (mea),	\
+	  .setting.rdc_mem_region[2] = (mrc),	\
+	}
+
+void imx_rdc_init(const struct imx_rdc_cfg *cfg);
+
+#endif /* IMX_RDC_H */
+
diff --git a/plat/imx/imx8qm/imx8qm_bl31_setup.c b/plat/imx/imx8qm/imx8qm_bl31_setup.c
new file mode 100644
index 0000000..c76de64
--- /dev/null
+++ b/plat/imx/imx8qm/imx8qm_bl31_setup.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <imx8qm_pads.h>
+#include <imx8_iomux.h>
+#include <imx8_lpuart.h>
+#include <plat_imx8.h>
+#include <sci/sci.h>
+#include <sec_rsrc.h>
+
+IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START);
+IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END);
+IMPORT_SYM(unsigned long, __RO_START__, BL31_RO_START);
+IMPORT_SYM(unsigned long, __RO_END__, BL31_RO_END);
+IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START);
+IMPORT_SYM(unsigned long, __RW_END__, BL31_RW_END);
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+#define UART_PAD_CTRL	(PADRING_IFMUX_EN_MASK | PADRING_GP_EN_MASK | \
+			(SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+			(SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+			(SC_PAD_28FDSOI_DSE_DV_LOW << PADRING_DSE_SHIFT) | \
+			(SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT))
+
+const static int imx8qm_cci_map[] = {
+	CLUSTER0_CCI_SLVAE_IFACE,
+	CLUSTER1_CCI_SLVAE_IFACE
+};
+
+static const mmap_region_t imx_mmap[] = {
+	MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW),
+	{0}
+};
+
+static uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned long mode;
+	uint32_t spsr;
+
+	/* figure out what mode we enter the non-secure world */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+
+	return spsr;
+}
+
+#if DEBUG_CONSOLE_A53
+static void lpuart32_serial_setbrg(unsigned int base, int baudrate)
+{
+	unsigned int sbr, osr, baud_diff, tmp_osr, tmp_sbr;
+	unsigned int diff1, diff2, tmp, rate;
+
+	if (baudrate == 0)
+		panic();
+
+	sc_pm_get_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate);
+
+	baud_diff = baudrate;
+	osr = 0;
+	sbr = 0;
+	for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
+		tmp_sbr = (rate / (baudrate * tmp_osr));
+		if (tmp_sbr == 0)
+			tmp_sbr = 1;
+
+		/* calculate difference in actual baud w/ current values */
+		diff1 = rate / (tmp_osr * tmp_sbr) - baudrate;
+		diff2 = rate / (tmp_osr * (tmp_sbr + 1));
+
+		/* select best values between sbr and sbr+1 */
+		if (diff1 > (baudrate - diff2)) {
+			diff1 = baudrate - diff2;
+			tmp_sbr++;
+		}
+
+		if (diff1 <= baud_diff) {
+			baud_diff = diff1;
+			osr = tmp_osr;
+			sbr = tmp_sbr;
+		}
+	}
+
+	tmp = mmio_read_32(IMX_BOOT_UART_BASE + BAUD);
+
+	if ((osr > 3) && (osr < 8))
+		tmp |= LPUART_BAUD_BOTHEDGE_MASK;
+
+	tmp &= ~LPUART_BAUD_OSR_MASK;
+	tmp |= LPUART_BAUD_OSR(osr - 1);
+	tmp &= ~LPUART_BAUD_SBR_MASK;
+	tmp |= LPUART_BAUD_SBR(sbr);
+
+	/* explicitly disable 10 bit mode & set 1 stop bit */
+	tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + BAUD, tmp);
+}
+
+static int lpuart32_serial_init(unsigned int base)
+{
+	unsigned int tmp;
+
+	/* disable TX & RX before enabling clocks */
+	tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL);
+	tmp &= ~(CTRL_TE | CTRL_RE);
+	mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + MODIR, 0);
+	mmio_write_32(IMX_BOOT_UART_BASE + FIFO, ~(FIFO_TXFE | FIFO_RXFE));
+
+	mmio_write_32(IMX_BOOT_UART_BASE + MATCH, 0);
+
+	/* provide data bits, parity, stop bit, etc */
+	lpuart32_serial_setbrg(base, IMX_BOOT_UART_BAUDRATE);
+
+	/* eight data bits no parity bit */
+	tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL);
+	tmp &= ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK);
+	mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + CTRL, CTRL_RE | CTRL_TE);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55);
+	mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55);
+	mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x0A);
+
+	return 0;
+}
+#endif
+
+void mx8_partition_resources(void)
+{
+	sc_rm_pt_t secure_part, os_part;
+	sc_rm_mr_t mr, mr_record = 64;
+	sc_faddr_t start, end;
+	bool owned, owned2;
+	sc_err_t err;
+	int i;
+
+	err = sc_rm_get_partition(ipc_handle, &secure_part);
+
+	err = sc_rm_partition_alloc(ipc_handle, &os_part, false, false,
+		false, false, false);
+
+	err = sc_rm_set_parent(ipc_handle, os_part, secure_part);
+
+	/* set secure resources to NOT-movable */
+	for (i = 0; i < ARRAY_SIZE(secure_rsrcs); i++) {
+		err = sc_rm_set_resource_movable(ipc_handle, secure_rsrcs[i],
+			secure_rsrcs[i], false);
+		if (err)
+			ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n",
+				secure_rsrcs[i], err);
+	}
+
+	owned = sc_rm_is_resource_owned(ipc_handle, SC_R_M4_0_PID0);
+	if (owned) {
+		err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_0_PID0,
+				SC_R_M4_0_PID0, false);
+		if (err)
+			ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n",
+				SC_R_M4_0_PID0, err);
+	}
+
+	owned2 = sc_rm_is_resource_owned(ipc_handle, SC_R_M4_1_PID0);
+	if (owned2) {
+		err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_1_PID0,
+				SC_R_M4_1_PID0, false);
+		if (err)
+			ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n",
+				SC_R_M4_1_PID0, err);
+	}
+	/* move all movable resources and pins to non-secure partition */
+	err = sc_rm_move_all(ipc_handle, secure_part, os_part, true, true);
+	if (err)
+		ERROR("sc_rm_move_all: %u\n", err);
+
+	/* iterate through peripherals to give NS OS part access */
+	for (i = 0; i < ARRAY_SIZE(ns_access_allowed); i++) {
+		err = sc_rm_set_peripheral_permissions(ipc_handle, ns_access_allowed[i],
+			os_part, SC_RM_PERM_FULL);
+		if (err)
+			ERROR("sc_rm_set_peripheral_permissions: rsrc %u, \
+				ret %u\n", ns_access_allowed[i], err);
+	}
+
+	if (owned) {
+		err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_0_PID0,
+				SC_R_M4_0_PID0, true);
+		if (err)
+			ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n",
+				SC_R_M4_0_PID0, err);
+		err = sc_rm_assign_resource(ipc_handle, os_part, SC_R_M4_0_PID0);
+		if (err)
+			ERROR("sc_rm_assign_resource: rsrc %u, ret %u\n",
+				SC_R_M4_0_PID0, err);
+	}
+	if (owned2) {
+		err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_1_PID0,
+				SC_R_M4_1_PID0, true);
+		if (err)
+			ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n",
+				SC_R_M4_1_PID0, err);
+		err = sc_rm_assign_resource(ipc_handle, os_part, SC_R_M4_1_PID0);
+		if (err)
+			ERROR("sc_rm_assign_resource: rsrc %u, ret %u\n",
+				SC_R_M4_1_PID0, err);
+	}
+
+	/*
+	 * sc_rm_set_peripheral_permissions
+	 * sc_rm_set_memreg_permissions
+	 * sc_rm_set_pin_movable
+	 */
+
+	for (mr = 0; mr < 64; mr++) {
+		owned = sc_rm_is_memreg_owned(ipc_handle, mr);
+		if (owned) {
+			err = sc_rm_get_memreg_info(ipc_handle, mr, &start, &end);
+			if (err)
+				ERROR("Memreg get info failed, %u\n", mr);
+			NOTICE("Memreg %u 0x%llx -- 0x%llx\n", mr, start, end);
+			if (BL31_BASE >= start && (BL31_LIMIT - 1) <= end) {
+				mr_record = mr; /* Record the mr for ATF running */
+			} else {
+				err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+				if (err)
+					ERROR("Memreg assign failed, 0x%llx -- 0x%llx, \
+						err %d\n", start, end, err);
+			}
+		}
+	}
+
+	if (mr_record != 64) {
+		err = sc_rm_get_memreg_info(ipc_handle, mr_record, &start, &end);
+		if (err)
+			ERROR("Memreg get info failed, %u\n", mr_record);
+		if ((BL31_LIMIT - 1) < end) {
+			err = sc_rm_memreg_alloc(ipc_handle, &mr, BL31_LIMIT, end);
+			if (err)
+				ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n",
+					(sc_faddr_t)BL31_LIMIT, end);
+			err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+			if (err)
+				ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n",
+					(sc_faddr_t)BL31_LIMIT, end);
+		}
+
+		if (start < (BL31_BASE - 1)) {
+			err = sc_rm_memreg_alloc(ipc_handle, &mr, start, BL31_BASE - 1);
+			if (err)
+				ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n",
+					start, (sc_faddr_t)BL31_BASE - 1);
+			err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+				if (err)
+					ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n",
+						start, (sc_faddr_t)BL31_BASE - 1);
+		}
+	}
+
+	if (err)
+		NOTICE("Partitioning Failed\n");
+	else
+		NOTICE("Non-secure Partitioning Succeeded\n");
+
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+#if DEBUG_CONSOLE
+	static console_lpuart_t console;
+#endif
+	if (sc_ipc_open(&ipc_handle, SC_IPC_BASE) != SC_ERR_NONE)
+		panic();
+
+#if DEBUG_CONSOLE_A53
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_UART_0, SC_PM_PW_MODE_ON);
+	sc_pm_clock_rate_t rate = 80000000;
+	sc_pm_set_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate);
+	sc_pm_clock_enable(ipc_handle, SC_R_UART_0, 2, true, false);
+
+	/* configure UART pads */
+	sc_pad_set(ipc_handle, SC_P_UART0_RX, UART_PAD_CTRL);
+	sc_pad_set(ipc_handle, SC_P_UART0_TX, UART_PAD_CTRL);
+	sc_pad_set(ipc_handle, SC_P_UART0_RTS_B, UART_PAD_CTRL);
+	sc_pad_set(ipc_handle, SC_P_UART0_CTS_B, UART_PAD_CTRL);
+	lpuart32_serial_init(IMX_BOOT_UART_BASE);
+#endif
+
+#if DEBUG_CONSOLE
+	console_lpuart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+		     IMX_CONSOLE_BAUDRATE, &console);
+#endif
+
+	/* turn on MU1 for non-secure OS/Hypervisor */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON);
+	/* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+	sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+	mmio_write_32(IMX_GPT_LPCG_BASE, mmio_read_32(IMX_GPT_LPCG_BASE) | (1 << 25));
+
+	/*
+	 * create new partition for non-secure OS/Hypervisor
+	 * uses global structs defined in sec_rsrc.h
+	 */
+	mx8_partition_resources();
+
+	bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+	bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+	/* init the first cluster's cci slave interface */
+	cci_init(PLAT_CCI_BASE, imx8qm_cci_map, PLATFORM_CLUSTER_COUNT);
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+void bl31_plat_arch_setup(void)
+{
+	unsigned long ro_start = BL31_RO_START;
+	unsigned long ro_size = BL31_RO_END - BL31_RO_START;
+	unsigned long rw_start = BL31_RW_START;
+	unsigned long rw_size = BL31_RW_END - BL31_RW_START;
+#if USE_COHERENT_MEM
+	unsigned long coh_start = BL31_COHERENT_RAM_START;
+	unsigned long coh_size = BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START;
+#endif
+
+	mmap_add_region(ro_start, ro_start, ro_size,
+		MT_RO | MT_MEMORY | MT_SECURE);
+	mmap_add_region(rw_start, rw_start, rw_size,
+		MT_RW | MT_MEMORY | MT_SECURE);
+	mmap_add(imx_mmap);
+
+#if USE_COHERENT_MEM
+	mmap_add_region(coh_start, coh_start, coh_size,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	/* setup xlat table */
+	init_xlat_tables();
+	/* enable the MMU */
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	plat_gic_driver_init();
+	plat_gic_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+	if (type == SECURE)
+		return &bl32_image_ep_info;
+
+	return NULL;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return COUNTER_FREQUENCY;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	return;
+}
diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c
new file mode 100644
index 0000000..bdba37c
--- /dev/null
+++ b/plat/imx/imx8qm/imx8qm_psci.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <plat_imx8.h>
+#include <sci/sci.h>
+
+#include "../../common/sci/imx8_mu.h"
+
+#define CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+const static int ap_core_index[PLATFORM_CORE_COUNT] = {
+	SC_R_A53_0, SC_R_A53_1, SC_R_A53_2,
+	SC_R_A53_3, SC_R_A72_0, SC_R_A72_1,
+};
+
+/* save gic dist/redist context when GIC is poewr down */
+static struct plat_gic_ctx imx_gicv3_ctx;
+static unsigned int gpt_lpcg, gpt_reg[2];
+
+static void imx_enable_irqstr_wakeup(void)
+{
+	uint32_t irq_mask;
+	gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
+
+	/* put IRQSTR into ON mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* enable the irqsteer to handle wakeup irq */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1);
+	for (int i = 0; i < 15; i++) {
+		irq_mask = dist_ctx->gicd_isenabler[i];
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask);
+	}
+
+	/* set IRQSTR low power mode */
+	if (imx_is_wakeup_src_irqsteer())
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
+	else
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
+static void imx_disable_irqstr_wakeup(void)
+{
+	/* put IRQSTR into ON from STBY mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* disable the irqsteer */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0);
+	for (int i = 0; i < 16; i++)
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0);
+
+	/* put IRQSTR into OFF mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+	int ret = PSCI_E_SUCCESS;
+	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	sc_pm_set_resource_power_mode(ipc_handle, cluster_id == 0 ?
+		SC_R_A53 : SC_R_A72, SC_PM_PW_MODE_ON);
+
+	if (cluster_id == 1)
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+
+	if (sc_pm_set_resource_power_mode(ipc_handle,
+		ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+		SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+		ERROR("core %d power on failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id);
+		ret = PSCI_E_INTERN_FAIL;
+	}
+
+	if (sc_pm_cpu_start(ipc_handle,
+		ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+		true, BL31_BASE) != SC_ERR_NONE) {
+		ERROR("boot core %d failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id);
+		ret = PSCI_E_INTERN_FAIL;
+	}
+
+	return ret;
+}
+
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	uint64_t mpidr = read_mpidr_el1();
+
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+	plat_gic_pcpu_init();
+	plat_gic_cpuif_enable();
+}
+
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	plat_gic_cpuif_disable();
+	sc_pm_req_cpu_low_power_mode(ipc_handle,
+		ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+		SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE);
+
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		cci_disable_snoop_dvm_reqs(cluster_id);
+		if (cluster_id == 1)
+			sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
+	}
+	printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id);
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		plat_gic_cpuif_disable();
+		sc_pm_set_cpu_resume(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			true, BL31_BASE);
+		sc_pm_req_cpu_low_power_mode(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
+
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		if (cluster_id == 1)
+			sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
+	}
+
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		plat_gic_cpuif_disable();
+
+		/* save gic context */
+		plat_gic_save(cpu_id, &imx_gicv3_ctx);
+		/* enable the irqsteer for wakeup */
+		imx_enable_irqstr_wakeup();
+
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+		/* Put GIC in LP mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
+		/* Save GPT clock and registers, then turn off its power */
+		gpt_lpcg = mmio_read_32(IMX_GPT_LPCG_BASE);
+		gpt_reg[0] = mmio_read_32(IMX_GPT_BASE);
+		gpt_reg[1] = mmio_read_32(IMX_GPT_BASE + 0x4);
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
+
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
+
+		sc_pm_set_cpu_resume(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			true, BL31_BASE);
+		if (imx_is_wakeup_src_irqsteer())
+			sc_pm_req_cpu_low_power_mode(ipc_handle,
+				ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+		else
+			sc_pm_req_cpu_low_power_mode(ipc_handle,
+				ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+	}
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* check the system level status */
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		MU_Resume(SC_IPC_BASE);
+
+		sc_pm_req_cpu_low_power_mode(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+
+		/* Put GIC/IRQSTR back to high power mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
+
+		/* Turn GPT power and restore its clock and registers */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+		sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+		mmio_write_32(IMX_GPT_BASE, gpt_reg[0]);
+		mmio_write_32(IMX_GPT_BASE + 0x4, gpt_reg[1]);
+		mmio_write_32(IMX_GPT_LPCG_BASE, gpt_lpcg);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
+
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
+
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+		/* restore gic context */
+		plat_gic_restore(cpu_id, &imx_gicv3_ctx);
+		/* disable the irqsteer wakeup */
+		imx_disable_irqstr_wakeup();
+
+		plat_gic_cpuif_enable();
+	}
+
+	/* check the cluster level power status */
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		if (cluster_id == 1)
+			sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+	}
+
+	/* check the core level power status */
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		sc_pm_set_cpu_resume(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			false, BL31_BASE);
+		sc_pm_req_cpu_low_power_mode(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+		isb();
+	}
+}
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+	return PSCI_E_SUCCESS;
+}
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+	.pwr_domain_on = imx_pwr_domain_on,
+	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
+	.pwr_domain_off = imx_pwr_domain_off,
+	.pwr_domain_suspend = imx_domain_suspend,
+	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
+	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+	.validate_power_state = imx_validate_power_state,
+	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
+	.system_off = imx_system_off,
+	.system_reset = imx_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	imx_mailbox_init(sec_entrypoint);
+	*psci_ops = &imx_plat_psci_ops;
+
+	/* make sure system sources power ON in low power mode by default */
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON);
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
+
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+
+	return 0;
+}
diff --git a/plat/imx/imx8qm/include/platform_def.h b/plat/imx/imx8qm/include/platform_def.h
new file mode 100644
index 0000000..138a4e1
--- /dev/null
+++ b/plat/imx/imx8qm/include/platform_def.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		0X400
+#define CACHE_WRITEBACK_GRANULE		64
+
+#define PLAT_PRIMARY_CPU		0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	2
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT + \
+					 PLATFORM_CLUSTER1_CORE_COUNT)
+
+#define IMX_PWR_LVL0			MPIDR_AFFLVL0
+#define IMX_PWR_LVL1			MPIDR_AFFLVL1
+#define IMX_PWR_LVL2			MPIDR_AFFLVL2
+
+#define PWR_DOMAIN_AT_MAX_LVL		U(1)
+#define PLAT_MAX_PWR_LVL		U(2)
+#define PLAT_MAX_OFF_STATE		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+
+#define BL31_BASE			0x80000000
+#define BL31_LIMIT			0x80020000
+
+#define PLAT_GICD_BASE			0x51a00000
+#define PLAT_GICR_BASE			0x51b00000
+#define PLAT_CCI_BASE			0x52090000
+#define CLUSTER0_CCI_SLVAE_IFACE	3
+#define CLUSTER1_CCI_SLVAE_IFACE	4
+#define IMX_BOOT_UART_BASE		0x5a060000
+#define IMX_BOOT_UART_BAUDRATE		115200
+#define IMX_BOOT_UART_CLK_IN_HZ		24000000
+#define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
+#define PLAT__CRASH_UART_CLK_IN_HZ	24000000
+#define IMX_CONSOLE_BAUDRATE		115200
+#define SC_IPC_BASE			0x5d1b0000
+#define IMX_GPT_LPCG_BASE		0x5d540000
+#define IMX_GPT_BASE			0x5d140000
+#define IMX_WUP_IRQSTR_BASE		0x51090000
+#define IMX_REG_BASE			0x50000000
+#define IMX_REG_SIZE			0x10000000
+
+#define COUNTER_FREQUENCY		8000000 /* 8MHz */
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET		0x80020000
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		12
+
+#define DEBUG_CONSOLE			0
+#define DEBUG_CONSOLE_A53		0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx8qm/include/sec_rsrc.h b/plat/imx/imx8qm/include/sec_rsrc.h
new file mode 100644
index 0000000..d16d051
--- /dev/null
+++ b/plat/imx/imx8qm/include/sec_rsrc.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* resources that are going to stay in secure partition */
+sc_rsrc_t secure_rsrcs[] = {
+	SC_R_MU_0A,
+	SC_R_A53,
+	SC_R_A53_0,
+	SC_R_A53_1,
+	SC_R_A53_2,
+	SC_R_A53_3,
+	SC_R_A72,
+	SC_R_A72_0,
+	SC_R_A72_1,
+	SC_R_GIC,
+	SC_R_GIC_SMMU,
+	SC_R_CCI,
+	SC_R_SYSTEM,
+	SC_R_IRQSTR_SCU2,
+	SC_R_GPT_0
+};
+
+/* resources that have register access for non-secure domain */
+sc_rsrc_t ns_access_allowed[] = {
+	SC_R_GIC,
+	SC_R_GIC_SMMU,
+	SC_R_CCI,
+	SC_R_GPT_0
+};
diff --git a/plat/imx/imx8qm/platform.mk b/plat/imx/imx8qm/platform.mk
new file mode 100644
index 0000000..3a772e5
--- /dev/null
+++ b/plat/imx/imx8qm/platform.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES		:=	-Iplat/imx/imx8qm/include		\
+				-Iplat/imx/common/include		\
+
+IMX_GIC_SOURCES	:=		drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c   \
+				drivers/arm/gic/v3/gic500.c             \
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/common/gic_common.c	\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES		+=	plat/imx/common/lpuart_console.S	\
+				plat/imx/common/imx8_helpers.S		\
+				plat/imx/imx8qm/imx8qm_bl31_setup.c	\
+				plat/imx/imx8qm/imx8qm_psci.c		\
+				plat/imx/common/imx8_topology.c		\
+				plat/imx/common/imx8_psci.c		\
+				plat/imx/common/imx_sip_svc.c		\
+				plat/imx/common/imx_sip_handler.c	\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				lib/xlat_tables/xlat_tables_common.c		\
+				lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a72.S			\
+				drivers/arm/cci/cci.c				\
+				${IMX_GIC_SOURCES}				\
+
+include plat/imx/common/sci/sci_api.mk
+
+USE_COHERENT_MEM	:=	1
+RESET_TO_BL31		:=	1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+ERRATA_A72_859971	:=	1
+
+ERRATA_A53_835769	:=	1
+ERRATA_A53_843419	:=	1
+ERRATA_A53_855873	:=	1
diff --git a/plat/imx/imx8qx/imx8qx_bl31_setup.c b/plat/imx/imx8qx/imx8qx_bl31_setup.c
new file mode 100644
index 0000000..bfe4052
--- /dev/null
+++ b/plat/imx/imx8qx/imx8qx_bl31_setup.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <imx8qx_pads.h>
+#include <imx8_iomux.h>
+#include <imx8_lpuart.h>
+#include <plat_imx8.h>
+#include <sci/sci.h>
+#include <sec_rsrc.h>
+
+IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START);
+IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END);
+IMPORT_SYM(unsigned long, __RO_START__, BL31_RO_START);
+IMPORT_SYM(unsigned long, __RO_END__, BL31_RO_END);
+IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START);
+IMPORT_SYM(unsigned long, __RW_END__, BL31_RW_END);
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+#define UART_PAD_CTRL	(PADRING_IFMUX_EN_MASK | PADRING_GP_EN_MASK | \
+			(SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \
+			(SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \
+			(SC_PAD_28FDSOI_DSE_DV_LOW << PADRING_DSE_SHIFT) | \
+			(SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT))
+
+static const mmap_region_t imx_mmap[] = {
+	MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW),
+	{0}
+};
+
+static uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned long mode;
+	uint32_t spsr;
+
+	/* figure out what mode we enter the non-secure world */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+#if DEBUG_CONSOLE_A35
+static void lpuart32_serial_setbrg(unsigned int base, int baudrate)
+{
+	unsigned int sbr, osr, baud_diff, tmp_osr, tmp_sbr;
+	unsigned int diff1, diff2, tmp, rate;
+
+	if (baudrate == 0)
+		panic();
+
+	sc_pm_get_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate);
+
+	baud_diff = baudrate;
+	osr = 0;
+	sbr = 0;
+	for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
+		tmp_sbr = (rate / (baudrate * tmp_osr));
+		if (tmp_sbr == 0)
+			tmp_sbr = 1;
+
+		/* calculate difference in actual baud w/ current values */
+		diff1 = rate / (tmp_osr * tmp_sbr) - baudrate;
+		diff2 = rate / (tmp_osr * (tmp_sbr + 1));
+
+		/* select best values between sbr and sbr+1 */
+		if (diff1 > (baudrate - diff2)) {
+			diff1 = baudrate - diff2;
+			tmp_sbr++;
+		}
+
+		if (diff1 <= baud_diff) {
+			baud_diff = diff1;
+			osr = tmp_osr;
+			sbr = tmp_sbr;
+		}
+	}
+
+	tmp = mmio_read_32(IMX_BOOT_UART_BASE + BAUD);
+
+	if ((osr > 3) && (osr < 8))
+		tmp |= LPUART_BAUD_BOTHEDGE_MASK;
+
+	tmp &= ~LPUART_BAUD_OSR_MASK;
+	tmp |= LPUART_BAUD_OSR(osr - 1);
+	tmp &= ~LPUART_BAUD_SBR_MASK;
+	tmp |= LPUART_BAUD_SBR(sbr);
+
+	/* explicitly disable 10 bit mode & set 1 stop bit */
+	tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + BAUD, tmp);
+}
+
+static int lpuart32_serial_init(unsigned int base)
+{
+	unsigned int tmp;
+
+	/* disable TX & RX before enabling clocks */
+	tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL);
+	tmp &= ~(CTRL_TE | CTRL_RE);
+	mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + MODIR, 0);
+	mmio_write_32(IMX_BOOT_UART_BASE + FIFO, ~(FIFO_TXFE | FIFO_RXFE));
+
+	mmio_write_32(IMX_BOOT_UART_BASE + MATCH, 0);
+
+	/* provide data bits, parity, stop bit, etc */
+	lpuart32_serial_setbrg(base, IMX_BOOT_UART_BAUDRATE);
+
+	/* eight data bits no parity bit */
+	tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL);
+	tmp &= ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK);
+	mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + CTRL, CTRL_RE | CTRL_TE);
+
+	mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55);
+	mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55);
+	mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x0A);
+
+	return 0;
+}
+#endif
+
+void imx8_partition_resources(void)
+{
+	sc_rm_pt_t secure_part, os_part;
+	sc_rm_mr_t mr, mr_record = 64;
+	sc_faddr_t start, end;
+	sc_err_t err;
+	bool owned;
+	int i;
+
+	err = sc_rm_get_partition(ipc_handle, &secure_part);
+	if (err)
+		ERROR("sc_rm_get_partition failed: %u\n", err);
+
+	err = sc_rm_partition_alloc(ipc_handle, &os_part, false, false,
+		false, false, false);
+	if (err)
+		ERROR("sc_rm_partition_alloc failed: %u\n", err);
+
+	err = sc_rm_set_parent(ipc_handle, os_part, secure_part);
+	if (err)
+		ERROR("sc_rm_set_parent: %u\n", err);
+
+	/* set secure resources to NOT-movable */
+	for (i = 0; i < (ARRAY_SIZE(secure_rsrcs)); i++) {
+		err = sc_rm_set_resource_movable(ipc_handle,
+			 secure_rsrcs[i], secure_rsrcs[i], false);
+		if (err)
+			ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n",
+				secure_rsrcs[i], err);
+	}
+
+	/* move all movable resources and pins to non-secure partition */
+	err = sc_rm_move_all(ipc_handle, secure_part, os_part, true, true);
+	if (err)
+		ERROR("sc_rm_move_all: %u\n", err);
+
+	/* iterate through peripherals to give NS OS part access */
+	for (i = 0; i < ARRAY_SIZE(ns_access_allowed); i++) {
+		err = sc_rm_set_peripheral_permissions(ipc_handle,
+			ns_access_allowed[i], os_part, SC_RM_PERM_FULL);
+		if (err)
+			ERROR("sc_rm_set_peripheral_permissions: rsrc %u, \
+				ret %u\n", ns_access_allowed[i], err);
+	}
+
+	/*
+	 * sc_rm_set_peripheral_permissions
+	 * sc_rm_set_memreg_permissions
+	 * sc_rm_set_pin_movable
+	 */
+	for (mr = 0; mr < 64; mr++) {
+		owned = sc_rm_is_memreg_owned(ipc_handle, mr);
+		if (owned) {
+			err = sc_rm_get_memreg_info(ipc_handle, mr, &start, &end);
+			if (err)
+				ERROR("Memreg get info failed, %u\n", mr);
+
+			NOTICE("Memreg %u 0x%llx -- 0x%llx\n", mr, start, end);
+			if (BL31_BASE >= start && (BL31_LIMIT - 1) <= end) {
+				mr_record = mr; /* Record the mr for ATF running */
+			} else {
+				err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+				if (err)
+					ERROR("Memreg assign failed, 0x%llx -- 0x%llx, \
+						err %d\n", start, end, err);
+			}
+		}
+	}
+
+	if (mr_record != 64) {
+		err = sc_rm_get_memreg_info(ipc_handle, mr_record, &start, &end);
+		if (err)
+			ERROR("Memreg get info failed, %u\n", mr_record);
+		if ((BL31_LIMIT - 1) < end) {
+			err = sc_rm_memreg_alloc(ipc_handle, &mr, BL31_LIMIT, end);
+			if (err)
+				ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n",
+					(sc_faddr_t)BL31_LIMIT, end);
+			err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+			if (err)
+				ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n",
+					(sc_faddr_t)BL31_LIMIT, end);
+		}
+
+		if (start < (BL31_BASE - 1)) {
+			err = sc_rm_memreg_alloc(ipc_handle, &mr, start, BL31_BASE - 1);
+			if (err)
+				ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n",
+					start, (sc_faddr_t)BL31_BASE - 1);
+			err = sc_rm_assign_memreg(ipc_handle, os_part, mr);
+			if (err)
+				ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n",
+					start, (sc_faddr_t)BL31_BASE - 1);
+		}
+	}
+
+	if (err)
+		NOTICE("Partitioning Failed\n");
+	else
+		NOTICE("Non-secure Partitioning Succeeded\n");
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+#if DEBUG_CONSOLE
+	static console_lpuart_t console;
+#endif
+	if (sc_ipc_open(&ipc_handle, SC_IPC_BASE) != SC_ERR_NONE)
+		panic();
+
+#if DEBUG_CONSOLE_A35
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_UART_0, SC_PM_PW_MODE_ON);
+	sc_pm_clock_rate_t rate = 80000000;
+	sc_pm_set_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate);
+	sc_pm_clock_enable(ipc_handle, SC_R_UART_0, 2, true, false);
+
+	/* Configure UART pads */
+	sc_pad_set(ipc_handle, SC_P_UART0_RX, UART_PAD_CTRL);
+	sc_pad_set(ipc_handle, SC_P_UART0_TX, UART_PAD_CTRL);
+	lpuart32_serial_init(IMX_BOOT_UART_BASE);
+#endif
+
+#if DEBUG_CONSOLE
+	console_lpuart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+		     IMX_CONSOLE_BAUDRATE, &console);
+#endif
+	/* Turn on MU1 for non-secure OS/Hypervisor */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON);
+
+	/* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+	sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+	mmio_write_32(IMX_GPT0_LPCG_BASE, mmio_read_32(IMX_GPT0_LPCG_BASE) | (1 << 25));
+
+	/*
+	 * create new partition for non-secure OS/Hypervisor
+	 * uses global structs defined in sec_rsrc.h
+	 */
+	imx8_partition_resources();
+
+	bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+	bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	unsigned long ro_start = BL31_RO_START;
+	unsigned long ro_size = BL31_RO_END - BL31_RO_START;
+	unsigned long rw_start = BL31_RW_START;
+	unsigned long rw_size = BL31_RW_END - BL31_RW_START;
+#if USE_COHERENT_MEM
+	unsigned long coh_start = BL31_COHERENT_RAM_START;
+	unsigned long coh_size = BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START;
+#endif
+
+	mmap_add_region(ro_start, ro_start, ro_size,
+		MT_RO | MT_MEMORY | MT_SECURE);
+	mmap_add_region(rw_start, rw_start, rw_size,
+		MT_RW | MT_MEMORY | MT_SECURE);
+	mmap_add(imx_mmap);
+
+#if USE_COHERENT_MEM
+	mmap_add_region(coh_start, coh_start, coh_size,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	init_xlat_tables();
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	plat_gic_driver_init();
+	plat_gic_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+	if (type == SECURE)
+		return &bl32_image_ep_info;
+
+	return NULL;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return COUNTER_FREQUENCY;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	return;
+}
diff --git a/plat/imx/imx8qx/imx8qx_psci.c b/plat/imx/imx8qx/imx8qx_psci.c
new file mode 100644
index 0000000..aab3a2d
--- /dev/null
+++ b/plat/imx/imx8qx/imx8qx_psci.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <plat_imx8.h>
+#include <sci/sci.h>
+
+#include "../../common/sci/imx8_mu.h"
+
+const static int ap_core_index[PLATFORM_CORE_COUNT] = {
+	SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3
+};
+
+/* save gic dist/redist context when GIC is power down */
+static struct plat_gic_ctx imx_gicv3_ctx;
+static unsigned int gpt_lpcg, gpt_reg[2];
+
+static void imx_enable_irqstr_wakeup(void)
+{
+	uint32_t irq_mask;
+	gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
+
+	/* put IRQSTR into ON mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* enable the irqsteer to handle wakeup irq */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1);
+	for (int i = 0; i < 15; i++) {
+		irq_mask = dist_ctx->gicd_isenabler[i];
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask);
+	}
+
+	/* set IRQSTR low power mode */
+	if (imx_is_wakeup_src_irqsteer())
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
+	else
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
+static void imx_disable_irqstr_wakeup(void)
+{
+	/* Put IRQSTEER back to ON mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* disable the irqsteer */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0);
+	for (int i = 0; i < 16; i++)
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0);
+
+	/* Put IRQSTEER into OFF mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+	int ret = PSCI_E_SUCCESS;
+	unsigned int cpu_id;
+
+	cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	printf("imx_pwr_domain_on cpu_id %d\n", cpu_id);
+
+	if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id],
+	    SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+		ERROR("core %d power on failed!\n", cpu_id);
+		ret = PSCI_E_INTERN_FAIL;
+	}
+
+	if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id],
+	    true, BL31_BASE) != SC_ERR_NONE) {
+		ERROR("boot core %d failed!\n", cpu_id);
+		ret = PSCI_E_INTERN_FAIL;
+	}
+
+	return ret;
+}
+
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	plat_gic_pcpu_init();
+	plat_gic_cpuif_enable();
+}
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+	return PSCI_E_SUCCESS;
+}
+
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	plat_gic_cpuif_disable();
+	sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+		SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE);
+	printf("turn off core:%d\n", cpu_id);
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) {
+		plat_gic_cpuif_disable();
+		sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE);
+		sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+			SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
+
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1]))
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
+
+	if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) {
+		plat_gic_cpuif_disable();
+
+		/* save gic context */
+		plat_gic_save(cpu_id, &imx_gicv3_ctx);
+		/* enable the irqsteer for wakeup */
+		imx_enable_irqstr_wakeup();
+
+		/* Save GPT clock and registers, then turn off its power */
+		gpt_lpcg = mmio_read_32(IMX_GPT0_LPCG_BASE);
+		gpt_reg[0] = mmio_read_32(IMX_GPT0_BASE);
+		gpt_reg[1] = mmio_read_32(IMX_GPT0_BASE + 0x4);
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+
+		/* Put GIC in OFF mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
+		sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE);
+		if (imx_is_wakeup_src_irqsteer())
+			sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+		else
+			sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+	}
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) {
+		MU_Resume(SC_IPC_BASE);
+
+		sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON);
+		sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+
+		/* Put GIC back to high power mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
+
+		/* restore gic context */
+		plat_gic_restore(cpu_id, &imx_gicv3_ctx);
+
+		/* Turn on GPT power and restore its clock and registers */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+		sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+		mmio_write_32(IMX_GPT0_BASE, gpt_reg[0]);
+		mmio_write_32(IMX_GPT0_BASE + 0x4, gpt_reg[1]);
+		mmio_write_32(IMX_GPT0_LPCG_BASE, gpt_lpcg);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+
+		/* disable the irqsteer wakeup */
+		imx_disable_irqstr_wakeup();
+
+		plat_gic_cpuif_enable();
+	}
+
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1]))
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
+
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) {
+		sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+		isb();
+	}
+}
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+	.pwr_domain_on = imx_pwr_domain_on,
+	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
+	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
+	.system_off = imx_system_off,
+	.system_reset = imx_system_reset,
+	.pwr_domain_off = imx_pwr_domain_off,
+	.pwr_domain_suspend = imx_domain_suspend,
+	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
+	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+	.validate_power_state = imx_validate_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	imx_mailbox_init(sec_entrypoint);
+	*psci_ops = &imx_plat_psci_ops;
+
+	/* make sure system sources power ON in low power mode by default */
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
+
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+
+	return 0;
+}
diff --git a/plat/imx/imx8qx/include/platform_def.h b/plat/imx/imx8qx/include/platform_def.h
new file mode 100644
index 0000000..108627f
--- /dev/null
+++ b/plat/imx/imx8qx/include/platform_def.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		0x400
+#define CACHE_WRITEBACK_GRANULE		64
+
+#define PLAT_PRIMARY_CPU		0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CORE_COUNT		4
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+
+#define PWR_DOMAIN_AT_MAX_LVL           U(1)
+#define PLAT_MAX_PWR_LVL                U(2)
+#define PLAT_MAX_OFF_STATE              U(2)
+#define PLAT_MAX_RET_STATE              U(1)
+
+#define BL31_BASE			0x80000000
+#define BL31_LIMIT			0x80020000
+
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		8
+
+#define PLAT_GICD_BASE			0x51a00000
+#define PLAT_GICR_BASE			0x51b00000
+#define IMX_BOOT_UART_BASE		0x5a060000
+#define IMX_BOOT_UART_BAUDRATE		115200
+#define IMX_BOOT_UART_CLK_IN_HZ		24000000
+#define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
+#define PLAT__CRASH_UART_CLK_IN_HZ	24000000
+#define IMX_CONSOLE_BAUDRATE		115200
+#define SC_IPC_BASE			0x5d1b0000
+#define IMX_GPT0_LPCG_BASE		0x5d540000
+#define IMX_GPT0_BASE			0x5d140000
+#define IMX_WUP_IRQSTR_BASE		0x51090000
+#define IMX_REG_BASE			0x50000000
+#define IMX_REG_SIZE			0x10000000
+
+#define COUNTER_FREQUENCY		8000000
+
+/* non-secure u-boot base */
+#define PLAT_NS_IMAGE_OFFSET		0x80020000
+
+#define DEBUG_CONSOLE			0
+#define DEBUG_CONSOLE_A35		0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/imx/imx8qx/include/sec_rsrc.h b/plat/imx/imx8qx/include/sec_rsrc.h
new file mode 100644
index 0000000..b7fe0e8
--- /dev/null
+++ b/plat/imx/imx8qx/include/sec_rsrc.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* resources that are going to stay in secure partition */
+sc_rsrc_t secure_rsrcs[] = {
+	SC_R_MU_0A,
+	SC_R_A35,
+	SC_R_A35_0,
+	SC_R_A35_1,
+	SC_R_A35_2,
+	SC_R_A35_3,
+	SC_R_GIC,
+	SC_R_SYSTEM,
+	SC_R_IRQSTR_SCU2,
+	SC_R_GPT_0
+};
+
+/* resources that have register access for non-secure domain */
+sc_rsrc_t ns_access_allowed[] = {
+	SC_R_GIC,
+	SC_R_GPT_0
+};
diff --git a/plat/imx/imx8qx/platform.mk b/plat/imx/imx8qx/platform.mk
new file mode 100644
index 0000000..d5629d1
--- /dev/null
+++ b/plat/imx/imx8qx/platform.mk
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES		:=	-Iplat/imx/imx8qx/include		\
+				-Iplat/imx/common/include		\
+
+IMX_GIC_SOURCES	:=		drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c	\
+				drivers/arm/gic/v3/gic500.c		\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/common/gic_common.c	\
+				plat/common/plat_gicv3.c		\
+				plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES		+=	plat/imx/common/lpuart_console.S	\
+				plat/imx/common/imx8_helpers.S		\
+				plat/imx/imx8qx/imx8qx_bl31_setup.c	\
+				plat/imx/imx8qx/imx8qx_psci.c		\
+				plat/imx/common/imx8_topology.c		\
+				plat/imx/common/imx8_psci.c		\
+				plat/imx/common/imx_sip_svc.c		\
+				plat/imx/common/imx_sip_handler.c	\
+				plat/common/plat_psci_common.c		\
+				lib/xlat_tables/xlat_tables_common.c	\
+				lib/xlat_tables/aarch64/xlat_tables.c	\
+				lib/cpus/aarch64/cortex_a35.S		\
+				${IMX_GIC_SOURCES}			\
+
+include plat/imx/common/sci/sci_api.mk
+
+USE_COHERENT_MEM	:=	1
+RESET_TO_BL31		:=	1
diff --git a/plat/intel/soc/agilex/bl2_plat_setup.c b/plat/intel/soc/agilex/bl2_plat_setup.c
new file mode 100644
index 0000000..e9ab928
--- /dev/null
+++ b/plat/intel/soc/agilex/bl2_plat_setup.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <platform_def.h>
+#include <socfpga_private.h>
+
+#include "agilex_clock_manager.h"
+#include "agilex_handoff.h"
+#include "agilex_mailbox.h"
+#include "agilex_memory_controller.h"
+#include "agilex_pinmux.h"
+#include "agilex_private.h"
+#include "agilex_reset_manager.h"
+#include "agilex_system_manager.h"
+
+#include "ccu/ncore_ccu.h"
+#include "qspi/cadence_qspi.h"
+#include "wdt/watchdog.h"
+
+
+const mmap_region_t agilex_plat_mmap[] = {
+	MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE,
+		MT_MEMORY | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE,
+		MT_NON_CACHEABLE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	{0},
+};
+
+boot_source_type boot_source;
+
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+				u_register_t x2, u_register_t x4)
+{
+	static console_16550_t console;
+	handoff reverse_handoff_ptr;
+
+	generic_delay_timer_init();
+
+	if (agilex_get_handoff(&reverse_handoff_ptr))
+		return;
+	config_pinmux(&reverse_handoff_ptr);
+	boot_source = reverse_handoff_ptr.boot_source;
+	config_clkmgr_handoff(&reverse_handoff_ptr);
+
+	enable_nonsecure_access();
+	deassert_peripheral_reset();
+	config_hps_hs_before_warm_reset();
+
+	watchdog_init(get_wdt_clk());
+
+	console_16550_register(PLAT_UART0_BASE, get_uart_clk(), PLAT_BAUDRATE,
+		&console);
+
+	socfpga_delay_timer_init();
+	init_ncore_ccu();
+	init_hard_memory_controller();
+	enable_ns_bridge_access();
+}
+
+
+void bl2_el3_plat_arch_setup(void)
+{
+
+	struct mmc_device_info info;
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL2_BASE, BL2_END - BL2_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE,
+			BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE),
+#if USE_COHERENT_MEM_BAR
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+#endif
+		{0},
+	};
+
+	setup_page_tables(bl_regions, agilex_plat_mmap);
+
+	enable_mmu_el3(0);
+
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(0x100000, get_mmc_clk());
+
+	info.mmc_dev_type = MMC_IS_SD;
+	info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3;
+
+	mailbox_init();
+
+	switch (boot_source) {
+	case BOOT_SOURCE_SDMMC:
+		dw_mmc_init(&params, &info);
+		socfpga_io_setup(boot_source);
+		break;
+
+	case BOOT_SOURCE_QSPI:
+		mailbox_set_qspi_open();
+		mailbox_set_qspi_direct();
+		cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL,
+			QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS,
+			QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0);
+		socfpga_io_setup(boot_source);
+		break;
+
+	default:
+		ERROR("Unsupported boot source\n");
+		panic();
+		break;
+	}
+}
+
+uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+
+	switch (image_id) {
+	case BL33_IMAGE_ID:
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = get_spsr_for_bl33_entry();
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl2_platform_setup(void)
+{
+}
+
diff --git a/plat/intel/soc/agilex/bl31_plat_setup.c b/plat/intel/soc/agilex/bl31_plat_setup.c
new file mode 100644
index 0000000..c8765e8
--- /dev/null
+++ b/plat/intel/soc/agilex/bl31_plat_setup.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <platform_def.h>
+
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ?
+			  &bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	static console_16550_t console;
+
+	console_16550_register(PLAT_UART0_BASE, PLAT_UART_CLOCK, PLAT_BAUDRATE,
+		&console);
+	/*
+	 * Check params passed from BL31 should not be NULL,
+	 */
+	void *from_bl2 = (void *) arg0;
+
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	/*
+	 * Copy BL32 (if populated by BL31) and BL33 entry point information.
+	 * They are stored in Secure RAM, in BL31's address space.
+	 */
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	while (bl_params) {
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+static const interrupt_prop_t s10_interrupt_props[] = {
+	PLAT_INTEL_AGX_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+	PLAT_INTEL_AGX_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+static const gicv2_driver_data_t plat_gicv2_gic_data = {
+	.gicd_base = PLAT_INTEL_AGX_GICD_BASE,
+	.gicc_base = PLAT_INTEL_AGX_GICC_BASE,
+	.interrupt_props = s10_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(s10_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+	/* Initialize the gic cpu and distributor interfaces */
+	gicv2_driver_init(&plat_gicv2_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+const mmap_region_t plat_agilex_mmap[] = {
+	MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE,
+		MT_NON_CACHEABLE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE, MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE, MT_DEVICE | MT_RW | MT_NS),
+	{0},
+};
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE,
+			BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE),
+#if USE_COHERENT_MEM
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+#endif
+		{0},
+	};
+
+	setup_page_tables(bl_regions, plat_agilex_mmap);
+	enable_mmu_el3(0);
+}
+
diff --git a/plat/intel/soc/agilex/include/agilex_clock_manager.h b/plat/intel/soc/agilex/include/agilex_clock_manager.h
new file mode 100644
index 0000000..73e6c4e
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_clock_manager.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CLOCKMANAGER_H
+#define CLOCKMANAGER_H
+
+#include "agilex_handoff.h"
+
+/* Clock Manager Registers */
+#define CLKMGR_OFFSET				0xffd10000
+
+#define CLKMGR_CTRL				0x0
+#define CLKMGR_STAT				0x4
+#define CLKMGR_INTRCLR				0x14
+
+/* Main PLL Group */
+#define CLKMGR_MAINPLL				0xffd10024
+#define CLKMGR_MAINPLL_EN			0x0
+#define CLKMGR_MAINPLL_BYPASS			0xc
+#define CLKMGR_MAINPLL_MPUCLK			0x18
+#define CLKMGR_MAINPLL_NOCCLK			0x1c
+#define CLKMGR_MAINPLL_NOCDIV			0x20
+#define CLKMGR_MAINPLL_PLLGLOB			0x24
+#define CLKMGR_MAINPLL_FDBCK			0x28
+#define CLKMGR_MAINPLL_MEM			0x2c
+#define CLKMGR_MAINPLL_MEMSTAT			0x30
+#define CLKMGR_MAINPLL_PLLC0			0x34
+#define CLKMGR_MAINPLL_PLLC1			0x38
+#define CLKMGR_MAINPLL_VCOCALIB			0x3c
+#define CLKMGR_MAINPLL_PLLC2			0x40
+#define CLKMGR_MAINPLL_PLLC3			0x44
+#define CLKMGR_MAINPLL_PLLM			0x48
+
+/* Peripheral PLL Group */
+#define CLKMGR_PERPLL				0xffd1007c
+#define CLKMGR_PERPLL_EN			0x0
+#define CLKMGR_PERPLL_BYPASS			0xc
+#define CLKMGR_PERPLL_EMACCTL			0x18
+#define CLKMGR_PERPLL_GPIODIV			0x1c
+#define CLKMGR_PERPLL_PLLGLOB			0x20
+#define CLKMGR_PERPLL_FDBCK			0x24
+#define CLKMGR_PERPLL_MEM			0x28
+#define CLKMGR_PERPLL_MEMSTAT			0x2c
+#define CLKMGR_PERPLL_PLLC0			0x30
+#define CLKMGR_PERPLL_PLLC1			0x34
+#define CLKMGR_PERPLL_VCOCALIB			0x38
+#define CLKMGR_PERPLL_PLLC2			0x3c
+#define CLKMGR_PERPLL_PLLC3			0x40
+#define CLKMGR_PERPLL_PLLM			0x44
+
+/* Altera Group */
+#define CLKMGR_ALTERA				0xffd100d0
+#define CLKMGR_ALTERA_JTAG			0x0
+#define CLKMGR_ALTERA_EMACACTR			0x4
+#define CLKMGR_ALTERA_EMACBCTR			0x8
+#define CLKMGR_ALTERA_EMACPTPCTR		0xc
+#define CLKMGR_ALTERA_GPIODBCTR			0x10
+#define CLKMGR_ALTERA_SDMMCCTR			0x14
+#define CLKMGR_ALTERA_S2FUSER0CTR		0x18
+#define CLKMGR_ALTERA_S2FUSER1CTR		0x1c
+#define CLKMGR_ALTERA_PSIREFCTR			0x20
+#define CLKMGR_ALTERA_EXTCNTRST			0x24
+
+/* Membus */
+#define CLKMGR_MEM_REQ				BIT(24)
+#define CLKMGR_MEM_WR				BIT(25)
+#define CLKMGR_MEM_ERR				BIT(26)
+#define CLKMGR_MEM_WDAT_OFFSET			16
+#define CLKMGR_MEM_ADDR				0x4027
+#define CLKMGR_MEM_WDAT				0x80
+
+/* Clock Manager Macros */
+#define CLKMGR_CTRL_BOOTMODE_SET_MSK		0x00000001
+#define CLKMGR_STAT_BUSY_E_BUSY			0x1
+#define CLKMGR_STAT_BUSY(x)			(((x) & 0x00000001) >> 0)
+#define CLKMGR_STAT_MAINPLLLOCKED(x)		(((x) & 0x00000100) >> 8)
+#define CLKMGR_STAT_PERPLLLOCKED(x)		(((x) & 0x00010000) >> 16)
+#define CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK	0x00000004
+#define CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK	0x00000008
+#define CLKMGR_INTOSC_HZ			460000000
+
+/* Main PLL Macros */
+#define CLKMGR_MAINPLL_EN_RESET			0x000000ff
+
+/* Peripheral PLL Macros */
+#define CLKMGR_PERPLL_EN_RESET			0x00000fff
+#define CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(x)	(((x) << 0) & 0x0000ffff)
+
+/* Altera Macros */
+#define CLKMGR_ALTERA_EXTCNTRST_RESET		0xff
+
+/* Shared Macros */
+#define CLKMGR_PSRC(x)				(((x) & 0x00030000) >> 16)
+#define CLKMGR_PSRC_MAIN			0
+#define CLKMGR_PSRC_PER				1
+
+#define CLKMGR_PLLGLOB_PSRC_EOSC1		0x0
+#define CLKMGR_PLLGLOB_PSRC_INTOSC		0x1
+#define CLKMGR_PLLGLOB_PSRC_F2S			0x2
+
+#define CLKMGR_PLLM_MDIV(x)			((x) & 0x000003ff)
+#define CLKMGR_PLLGLOB_PD_SET_MSK		0x00000001
+#define CLKMGR_PLLGLOB_RST_SET_MSK		0x00000002
+
+#define CLKMGR_PLLGLOB_REFCLKDIV(x)		(((x) & 0x00003f00) >> 8)
+#define CLKMGR_PLLGLOB_AREFCLKDIV(x)		(((x) & 0x00000f00) >> 8)
+#define CLKMGR_PLLGLOB_DREFCLKDIV(x)		(((x) & 0x00003000) >> 12)
+
+#define CLKMGR_VCOCALIB_HSCNT_SET(x)		(((x) << 0) & 0x000003ff)
+#define CLKMGR_VCOCALIB_MSCNT_SET(x)		(((x) << 16) & 0x00ff0000)
+
+
+typedef struct {
+	uint32_t  clk_freq_of_eosc1;
+	uint32_t  clk_freq_of_f2h_free;
+	uint32_t  clk_freq_of_cb_intosc_ls;
+} CLOCK_SOURCE_CONFIG;
+
+void config_clkmgr_handoff(handoff *hoff_ptr);
+uint32_t get_wdt_clk(void);
+uint32_t get_uart_clk(void);
+uint32_t get_mmc_clk(void);
+
+#endif
diff --git a/plat/intel/soc/agilex/include/agilex_handoff.h b/plat/intel/soc/agilex/include/agilex_handoff.h
new file mode 100644
index 0000000..2016406
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_handoff.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef	HANDOFF_H
+#define	HANDOFF_H
+
+#define HANDOFF_MAGIC_HEADER		0x424f4f54	/* BOOT */
+#define HANDOFF_MAGIC_PINMUX_SEL	0x504d5558	/* PMUX */
+#define HANDOFF_MAGIC_IOCTLR		0x494f4354	/* IOCT */
+#define HANDOFF_MAGIC_FPGA		0x46504741	/* FPGA */
+#define HANDOFF_MAGIC_IODELAY		0x444c4159	/* DLAY */
+#define HANDOFF_MAGIC_CLOCK		0x434c4b53	/* CLKS */
+#define HANDOFF_MAGIC_MISC		0x4d495343	/* MISC */
+
+typedef struct handoff_t {
+	/* header */
+	uint32_t	header_magic;
+	uint32_t	header_device;
+	uint32_t	_pad_0x08_0x10[2];
+
+	/* pinmux configuration - select */
+	uint32_t	pinmux_sel_magic;
+	uint32_t	pinmux_sel_length;
+	uint32_t	_pad_0x18_0x20[2];
+	uint32_t	pinmux_sel_array[96];	/* offset, value */
+
+	/* pinmux configuration - io control */
+	uint32_t	pinmux_io_magic;
+	uint32_t	pinmux_io_length;
+	uint32_t	_pad_0x1a8_0x1b0[2];
+	uint32_t	pinmux_io_array[96];	/* offset, value */
+
+	/* pinmux configuration - use fpga switch */
+	uint32_t	pinmux_fpga_magic;
+	uint32_t	pinmux_fpga_length;
+	uint32_t	_pad_0x338_0x340[2];
+	uint32_t	pinmux_fpga_array[42];	/* offset, value */
+	uint32_t	_pad_0x3e8_0x3f0[2];
+
+	/* pinmux configuration - io delay */
+	uint32_t	pinmux_delay_magic;
+	uint32_t	pinmux_delay_length;
+	uint32_t	_pad_0x3f8_0x400[2];
+	uint32_t	pinmux_iodelay_array[96];	/* offset, value */
+
+	/* clock configuration */
+	uint32_t	clock_magic;
+	uint32_t	clock_length;
+	uint32_t	_pad_0x588_0x590[2];
+	uint32_t	main_pll_mpuclk;
+	uint32_t	main_pll_nocclk;
+	uint32_t	main_pll_nocdiv;
+	uint32_t	main_pll_pllglob;
+	uint32_t	main_pll_fdbck;
+	uint32_t	main_pll_pllc0;
+	uint32_t	main_pll_pllc1;
+	uint32_t	main_pll_pllc2;
+	uint32_t	main_pll_pllc3;
+	uint32_t	main_pll_pllm;
+	uint32_t	per_pll_emacctl;
+	uint32_t	per_pll_gpiodiv;
+	uint32_t	per_pll_pllglob;
+	uint32_t	per_pll_fdbck;
+	uint32_t	per_pll_pllc0;
+	uint32_t	per_pll_pllc1;
+	uint32_t	per_pll_pllc2;
+	uint32_t	per_pll_pllc3;
+	uint32_t	per_pll_pllm;
+	uint32_t	alt_emacactr;
+	uint32_t	alt_emacbctr;
+	uint32_t	alt_emacptpctr;
+	uint32_t	alt_gpiodbctr;
+	uint32_t	alt_sdmmcctr;
+	uint32_t	alt_s2fuser0ctr;
+	uint32_t	alt_s2fuser1ctr;
+	uint32_t	alt_psirefctr;
+	uint32_t	hps_osc_clk_h;
+	uint32_t	fpga_clk_hz;
+	uint32_t	_pad_0x604_0x610[3];
+
+	/* misc configuration */
+	uint32_t	misc_magic;
+	uint32_t	misc_length;
+	uint32_t	_pad_0x618_0x620[2];
+	uint32_t	boot_source;
+} handoff;
+
+int verify_handoff_image(handoff *hoff_ptr, handoff *reverse_hoff_ptr);
+int agilex_get_handoff(handoff *hoff_ptr);
+
+#endif
+
+
diff --git a/plat/intel/soc/agilex/include/agilex_mailbox.h b/plat/intel/soc/agilex/include/agilex_mailbox.h
new file mode 100644
index 0000000..cd8be28
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_mailbox.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_MBOX_H
+#define AGX_MBOX_H
+
+#include <lib/utils_def.h>
+
+#define MBOX_OFFSET			0xffa30000
+
+#define MBOX_ATF_CLIENT_ID		0x1
+#define MBOX_JOB_ID			0x1
+
+/* Mailbox interrupt flags and masks */
+#define MBOX_INT_FLAG_COE		0x1
+#define MBOX_INT_FLAG_RIE		0x2
+#define MBOX_INT_FLAG_UAE		0x100
+#define MBOX_COE_BIT(INTERRUPT)		((INTERRUPT) & 0x3)
+#define MBOX_UAE_BIT(INTERRUPT)		(((INTERRUPT) & (1<<8)))
+
+/* Mailbox response and status */
+#define MBOX_RESP_BUFFER_SIZE		16
+#define MBOX_RESP_ERR(BUFFER)		((BUFFER) & 0x00000fff)
+#define MBOX_RESP_LEN(BUFFER)		(((BUFFER) & 0x007ff000) >> 12)
+#define MBOX_RESP_CLIENT_ID(BUFFER)	(((BUFFER) & 0xf0000000) >> 28)
+#define MBOX_RESP_JOB_ID(BUFFER)	(((BUFFER) & 0x0f000000) >> 24)
+#define MBOX_STATUS_UA_MASK		(1<<8)
+
+/* Mailbox command and response */
+#define MBOX_CMD_FREE_OFFSET		0x14
+#define MBOX_CMD_BUFFER_SIZE		32
+#define MBOX_CLIENT_ID_CMD(CLIENT_ID)	((CLIENT_ID) << 28)
+#define MBOX_JOB_ID_CMD(JOB_ID)		(JOB_ID<<24)
+#define MBOX_CMD_LEN_CMD(CMD_LEN)	((CMD_LEN) << 12)
+#define MBOX_INDIRECT			(1 << 11)
+#define MBOX_INSUFFICIENT_BUFFER	-2
+#define MBOX_CIN			0x00
+#define MBOX_ROUT			0x04
+#define MBOX_URG			0x08
+#define MBOX_INT			0x0C
+#define MBOX_COUT			0x20
+#define MBOX_RIN			0x24
+#define MBOX_STATUS			0x2C
+#define MBOX_CMD_BUFFER			0x40
+#define MBOX_RESP_BUFFER		0xC0
+
+#define MBOX_RESP_BUFFER_SIZE		16
+#define MBOX_RESP_OK			0
+#define MBOX_RESP_INVALID_CMD		1
+#define MBOX_RESP_UNKNOWN_BR		2
+#define MBOX_RESP_UNKNOWN		3
+#define MBOX_RESP_NOT_CONFIGURED	256
+
+/* Mailbox SDM doorbell */
+#define MBOX_DOORBELL_TO_SDM		0x400
+#define MBOX_DOORBELL_FROM_SDM		0x480
+
+/* Mailbox QSPI commands */
+#define MBOX_CMD_RESTART		2
+#define MBOX_CMD_QSPI_OPEN		50
+#define MBOX_CMD_QSPI_CLOSE		51
+#define MBOX_CMD_QSPI_DIRECT		59
+#define MBOX_CMD_GET_IDCODE		16
+#define MBOX_CMD_QSPI_SET_CS		52
+
+/* Mailbox REBOOT commands */
+#define MBOX_CMD_REBOOT_HPS		71
+
+/* Generic error handling */
+#define MBOX_TIMEOUT			-2047
+#define MBOX_NO_RESPONSE		-2
+#define MBOX_WRONG_ID			-3
+
+/* Mailbox status */
+#define RECONFIG_STATUS_STATE		0
+#define RECONFIG_STATUS_PIN_STATUS	2
+#define RECONFIG_STATUS_SOFTFUNC_STATUS 3
+#define PIN_STATUS_NSTATUS		(U(1) << 31)
+#define SOFTFUNC_STATUS_SEU_ERROR	(1 << 3)
+#define SOFTFUNC_STATUS_INIT_DONE	(1 << 1)
+#define SOFTFUNC_STATUS_CONF_DONE	(1 << 0)
+#define MBOX_CFGSTAT_STATE_CONFIG	0x10000000
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT	0x8200ff00
+#define SIP_SVC_UID		0x8200ff01
+#define SIP_SVC_VERSION		0x8200ff03
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR	0
+#define SIP_SVC_VERSION_MINOR	1
+
+/* Mailbox reconfiguration commands */
+#define MBOX_RECONFIG		6
+#define MBOX_RECONFIG_DATA	8
+#define MBOX_RECONFIG_STATUS	9
+
+/* Sip get memory */
+#define INTEL_SIP_SMC_FPGA_CONFIG_START			0xC2000001
+#define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM		0xC2000005
+#define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE		0xC2000004
+#define INTEL_SIP_SMC_FPGA_CONFIG_WRITE			0x42000002
+#define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE	0xC2000003
+#define INTEL_SIP_SMC_STATUS_OK				0
+#define INTEL_SIP_SMC_STATUS_ERROR			0x4
+#define INTEL_SIP_SMC_STATUS_BUSY			0x1
+#define INTEL_SIP_SMC_STATUS_REJECTED			0x2
+#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR			0x1000
+#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE			16777216
+
+void mailbox_set_int(int interrupt_input);
+int mailbox_init(void);
+void mailbox_set_qspi_close(void);
+void mailbox_set_qspi_open(void);
+void mailbox_set_qspi_direct(void);
+int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args,
+				int len, int urgent, uint32_t *response);
+void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args,
+				int len, int urgent);
+int mailbox_read_response(int job_id, uint32_t *response);
+int mailbox_get_qspi_clock(void);
+void mailbox_reset_cold(void);
+
+#endif
diff --git a/plat/intel/soc/agilex/include/agilex_memory_controller.h b/plat/intel/soc/agilex/include/agilex_memory_controller.h
new file mode 100644
index 0000000..419bd2e
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_memory_controller.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_MEMORYCONTROLLER_H
+#define AGX_MEMORYCONTROLLER_H
+
+#define AGX_MPFE_IOHMC_REG_DRAMADDRW			0xf80100a8
+#define AGX_MPFE_IOHMC_CTRLCFG0				0xf8010028
+#define AGX_MPFE_IOHMC_CTRLCFG1				0xf801002c
+#define AGX_MPFE_IOHMC_CTRLCFG2				0xf8010030
+#define AGX_MPFE_IOHMC_CTRLCFG3				0xf8010034
+#define AGX_MPFE_IOHMC_DRAMADDRW			0xf80100a8
+#define AGX_MPFE_IOHMC_DRAMTIMING0			0xf8010050
+#define AGX_MPFE_IOHMC_CALTIMING0			0xf801007c
+#define AGX_MPFE_IOHMC_CALTIMING1			0xf8010080
+#define AGX_MPFE_IOHMC_CALTIMING2			0xf8010084
+#define AGX_MPFE_IOHMC_CALTIMING3			0xf8010088
+#define AGX_MPFE_IOHMC_CALTIMING4			0xf801008c
+#define AGX_MPFE_IOHMC_CALTIMING9			0xf80100a0
+#define AGX_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(x) (((x) & 0x000000ff) >> 0)
+#define AGX_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(value)	\
+						(((value) & 0x00000060) >> 5)
+
+#define AGX_RSTMGR_BRGMODRST				0xffd1102c
+#define AGX_RSTMGR_BRGMODRST_DDRSCH			0x00000040
+
+#define AGX_MPFE_HMC_ADP_ECCCTRL1			0xf8011100
+#define AGX_MPFE_HMC_ADP_ECCCTRL2			0xf8011104
+#define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT		0xf8011218
+#define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE	0x000000ff
+#define AGX_MPFE_HMC_ADP_RSTHANDSHAKECTRL		0xf8011214
+
+
+#define AGX_MPFE_IOHMC_REG_CTRLCFG1			0xf801002c
+
+#define AGX_MPFE_IOHMC_REG_NIOSRESERVE0_OFST		0xf8010110
+
+#define IOHMC_DRAMADDRW_COL_ADDR_WIDTH(x)	(((x) & 0x0000001f) >> 0)
+#define IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(x)	(((x) & 0x000003e0) >> 5)
+#define IOHMC_DRAMADDRW_CS_ADDR_WIDTH(x)	(((x) & 0x00070000) >> 16)
+#define IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(x)	(((x) & 0x0000c000) >> 14)
+#define IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(x)	(((x) & 0x00003c00) >> 10)
+
+#define AGX_MPFE_DDR(x)					(0xf8000000 + x)
+#define AGX_MPFE_HMC_ADP_DDRCALSTAT			0xf801100c
+#define AGX_MPFE_DDR_MAIN_SCHED				0xf8000400
+#define AGX_MPFE_DDR_MAIN_SCHED_DDRCONF			0xf8000408
+#define AGX_MPFE_DDR_MAIN_SCHED_DDRTIMING		0xf800040c
+#define AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK		0x0000001f
+#define AGX_MPFE_DDR_MAIN_SCHED_DDRMODE			0xf8000410
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV		0xf800043c
+#define AGX_MPFE_DDR_MAIN_SCHED_READLATENCY		0xf8000414
+#define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE		0xf8000438
+#define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST	10
+#define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST	4
+#define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST	0
+#define AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(x)	(((x) << 0) & 0x0000001f)
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST	0
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK	(BIT(0) | BIT(1))
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST	2
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK	(BIT(2) | BIT(3))
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST	4
+#define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK	(BIT(4) | BIT(5))
+
+#define AGX_MPFE_HMC_ADP(x)				(0xf8011000 + (x))
+#define AGX_MPFE_HMC_ADP_HPSINTFCSEL			0xf8011210
+#define AGX_MPFE_HMC_ADP_DDRIOCTRL			0xf8011008
+#define HMC_ADP_DDRIOCTRL				0x8
+#define HMC_ADP_DDRIOCTRL_IO_SIZE(x)		(((x) & 0x00000003) >> 0)
+#define HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(x)	(((x) & 0x00003e00) >> 9)
+#define ADP_DRAMADDRWIDTH				0xe0
+
+#define ACT_TO_ACT_DIFF_BANK(value)		(((value) & 0x00fc0000) >> 18)
+#define ACT_TO_ACT(value)			(((value) & 0x0003f000) >> 12)
+#define ACT_TO_RDWR(value)			(((value) & 0x0000003f) >> 0)
+#define ACT_TO_ACT(value)			(((value) & 0x0003f000) >> 12)
+
+/* timing 2 */
+#define RD_TO_RD_DIFF_CHIP(value)		(((value) & 0x00000fc0) >> 6)
+#define RD_TO_WR_DIFF_CHIP(value)		(((value) & 0x3f000000) >> 24)
+#define RD_TO_WR(value)				(((value) & 0x00fc0000) >> 18)
+#define RD_TO_PCH(value)			(((value) & 0x00000fc0) >> 6)
+
+/* timing 3 */
+#define CALTIMING3_WR_TO_RD_DIFF_CHIP(value)	(((value) & 0x0003f000) >> 12)
+#define CALTIMING3_WR_TO_RD(value)		(((value) & 0x00000fc0) >> 6)
+
+/* timing 4 */
+#define PCH_TO_VALID(value)			(((value) & 0x00000fc0) >> 6)
+
+#define DDRTIMING_BWRATIO_OFST				31
+#define DDRTIMING_WRTORD_OFST				26
+#define DDRTIMING_RDTOWR_OFST				21
+#define DDRTIMING_BURSTLEN_OFST				18
+#define DDRTIMING_WRTOMISS_OFST				12
+#define DDRTIMING_RDTOMISS_OFST				6
+#define DDRTIMING_ACTTOACT_OFST				0
+
+#define ADP_DDRIOCTRL_IO_SIZE(x)			(((x) & 0x3) >> 0)
+
+#define DDRMODE_AUTOPRECHARGE_OFST			1
+#define DDRMODE_BWRATIOEXTENDED_OFST			0
+
+
+#define AGX_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(x)	(((x) & 0x7f) >> 0)
+#define AGX_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(x)	(((x) & 0x0f) >> 0)
+
+#define AGX_CCU_CPU0_MPRT_DDR				0xf7004400
+#define AGX_CCU_CPU0_MPRT_MEM0				0xf70045c0
+#define AGX_CCU_CPU0_MPRT_MEM1A				0xf70045e0
+#define AGX_CCU_CPU0_MPRT_MEM1B				0xf7004600
+#define AGX_CCU_CPU0_MPRT_MEM1C				0xf7004620
+#define AGX_CCU_CPU0_MPRT_MEM1D				0xf7004640
+#define AGX_CCU_CPU0_MPRT_MEM1E				0xf7004660
+#define AGX_CCU_IOM_MPRT_MEM0				0xf7018560
+#define AGX_CCU_IOM_MPRT_MEM1A				0xf7018580
+#define	AGX_CCU_IOM_MPRT_MEM1B				0xf70185a0
+#define	AGX_CCU_IOM_MPRT_MEM1C				0xf70185c0
+#define	AGX_CCU_IOM_MPRT_MEM1D				0xf70185e0
+#define	AGX_CCU_IOM_MPRT_MEM1E				0xf7018600
+
+#define AGX_NOC_FW_DDR_SCR				0xf8020200
+#define AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT	0xf802021c
+#define AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT		0xf8020218
+#define AGX_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT	0xf802029c
+#define AGX_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT	0xf8020298
+
+#define AGX_SOC_NOC_FW_DDR_SCR_ENABLE			0xf8020200
+#define AGX_SOC_NOC_FW_DDR_SCR_ENABLESET		0xf8020204
+#define AGX_CCU_NOC_DI_SET_MSK				0x10
+
+#define AGX_SYSMGR_CORE_HMC_CLK				0xffd120b4
+#define AGX_SYSMGR_CORE_HMC_CLK_STATUS			0x00000001
+
+#define AGX_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0(x)	(((x) & 0xffff) >> 0)
+#define AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_MSK		0x00000003
+#define AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_OFST		0
+#define AGX_MPFE_HMC_ADP_HPSINTFCSEL_ENABLE		0x001f1f1f
+#define AGX_IOHMC_CTRLCFG1_ENABLE_ECC_OFST		7
+
+#define AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK	0x00010000
+#define AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK		0x00000100
+#define AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK		0x00000001
+
+#define AGX_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK		0x00000001
+#define AGX_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK	0x00010000
+#define AGX_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK		0x00000100
+#define AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(value)		(((value) & 0x1) >> 0)
+
+
+#define AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(x)		(((x) & 0x00003) >> 0)
+#define IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(x)		(((x) & 0x03c00) >> 10)
+#define IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(x)	(((x) & 0x0c000) >> 14)
+#define IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(x)		(((x) & 0x0001f) >> 0)
+#define IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(x)		(((x) & 0x70000) >> 16)
+#define IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(x)		(((x) & 0x003e0) >> 5)
+
+#define AGX_SDRAM_0_LB_ADDR				0x0
+#define AGX_DDR_SIZE					0x40000000
+
+int init_hard_memory_controller(void);
+
+#endif
diff --git a/plat/intel/soc/agilex/include/agilex_noc.h b/plat/intel/soc/agilex/include/agilex_noc.h
new file mode 100644
index 0000000..22db3e2
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_noc.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_NOC_H
+#define AGX_NOC_H
+
+
+#define AXI_AP					(1<<0)
+#define FPGA2SOC				(1<<16)
+#define MPU					(1<<24)
+#define AGX_NOC_PER_SCR_NAND			0xffd21000
+#define AGX_NOC_PER_SCR_NAND_DATA		0xffd21004
+#define AGX_NOC_PER_SCR_USB0			0xffd2100c
+#define AGX_NOC_PER_SCR_USB1			0xffd21010
+#define AGX_NOC_PER_SCR_SPI_M0			0xffd2101c
+#define AGX_NOC_PER_SCR_SPI_M1			0xffd21020
+#define AGX_NOC_PER_SCR_SPI_S0			0xffd21024
+#define AGX_NOC_PER_SCR_SPI_S1			0xffd21028
+#define AGX_NOC_PER_SCR_EMAC0			0xffd2102c
+#define AGX_NOC_PER_SCR_EMAC1			0xffd21030
+#define AGX_NOC_PER_SCR_EMAC2			0xffd21034
+#define AGX_NOC_PER_SCR_SDMMC			0xffd21040
+#define AGX_NOC_PER_SCR_GPIO0			0xffd21044
+#define AGX_NOC_PER_SCR_GPIO1			0xffd21048
+#define AGX_NOC_PER_SCR_I2C0			0xffd21050
+#define AGX_NOC_PER_SCR_I2C1			0xffd21058
+#define AGX_NOC_PER_SCR_I2C2			0xffd2105c
+#define AGX_NOC_PER_SCR_I2C3			0xffd21060
+#define AGX_NOC_PER_SCR_SP_TIMER0		0xffd21064
+#define AGX_NOC_PER_SCR_SP_TIMER1		0xffd21068
+#define AGX_NOC_PER_SCR_UART0			0xffd2106c
+#define AGX_NOC_PER_SCR_UART1			0xffd21070
+
+
+#define AGX_NOC_SYS_SCR_DMA_ECC			0xffd21108
+#define AGX_NOC_SYS_SCR_EMAC0RX_ECC		0xffd2110c
+#define AGX_NOC_SYS_SCR_EMAC0TX_ECC		0xffd21110
+#define AGX_NOC_SYS_SCR_EMAC1RX_ECC		0xffd21114
+#define AGX_NOC_SYS_SCR_EMAC1TX_ECC		0xffd21118
+#define AGX_NOC_SYS_SCR_EMAC2RX_ECC		0xffd2111c
+#define AGX_NOC_SYS_SCR_EMAC2TX_ECC		0xffd21120
+#define AGX_NOC_SYS_SCR_NAND_ECC		0xffd2112c
+#define AGX_NOC_SYS_SCR_NAND_READ_ECC		0xffd21130
+#define AGX_NOC_SYS_SCR_NAND_WRITE_ECC		0xffd21134
+#define AGX_NOC_SYS_SCR_OCRAM_ECC		0xffd21138
+#define AGX_NOC_SYS_SCR_SDMMC_ECC		0xffd21140
+#define AGX_NOC_SYS_SCR_USB0_ECC		0xffd21144
+#define AGX_NOC_SYS_SCR_USB1_ECC		0xffd21148
+#define AGX_NOC_SYS_SCR_CLK_MGR			0xffd2114c
+#define AGX_NOC_SYS_SCR_IO_MGR			0xffd21154
+#define AGX_NOC_SYS_SCR_RST_MGR			0xffd21158
+#define AGX_NOC_SYS_SCR_SYS_MGR			0xffd2115c
+#define AGX_NOC_SYS_SCR_OSC0_TIMER		0xffd21160
+#define AGX_NOC_SYS_SCR_OSC1_TIMER		0xffd21164
+#define AGX_NOC_SYS_SCR_WATCHDOG0		0xffd21168
+#define AGX_NOC_SYS_SCR_WATCHDOG1		0xffd2116c
+#define AGX_NOC_SYS_SCR_WATCHDOG2		0xffd21170
+#define AGX_NOC_SYS_SCR_WATCHDOG3		0xffd21174
+#define AGX_NOC_SYS_SCR_DAP			0xffd21178
+#define AGX_NOC_SYS_SCR_L4_NOC_PROBES		0xffd21190
+#define AGX_NOC_SYS_SCR_L4_NOC_QOS		0xffd21194
+
+#define AGX_CCU_NOC_BRIDGE_CPU0_RAM		0xf7004688
+#define AGX_CCU_NOC_BRIDGE_IOM_RAM		0xf7004688
+
+#endif
diff --git a/plat/intel/soc/agilex/include/agilex_pinmux.h b/plat/intel/soc/agilex/include/agilex_pinmux.h
new file mode 100644
index 0000000..e6a7b34
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_pinmux.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_PINMUX_H
+#define AGX_PINMUX_H
+
+#define AGX_PINMUX_PIN0SEL		0xffd13000
+#define AGX_PINMUX_IO0CTRL		0xffd13130
+#define AGX_PINMUX_PINMUX_EMAC0_USEFPGA	0xffd13300
+#define AGX_PINMUX_IO0_DELAY		0xffd13400
+
+#include "agilex_handoff.h"
+
+void config_pinmux(handoff *handoff);
+
+#endif
+
diff --git a/plat/intel/soc/agilex/include/agilex_private.h b/plat/intel/soc/agilex/include/agilex_private.h
new file mode 100644
index 0000000..fc0e9fd
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_PRIVATE_H
+#define AGX_PRIVATE_H
+
+#define AGX_MMC_REG_BASE	0xff808000
+
+#define EMMC_DESC_SIZE		(1<<20)
+#define EMMC_INIT_PARAMS(base, clk)		\
+	{	.bus_width = MMC_BUS_WIDTH_4,	\
+		.clk_rate = (clk),		\
+		.desc_base = (base),		\
+		.desc_size = EMMC_DESC_SIZE,	\
+		.flags = 0,			\
+		.reg_base = AGX_MMC_REG_BASE	\
+	}
+
+typedef enum {
+	BOOT_SOURCE_FPGA = 0,
+	BOOT_SOURCE_SDMMC,
+	BOOT_SOURCE_NAND,
+	BOOT_SOURCE_RSVD,
+	BOOT_SOURCE_QSPI
+} boot_source_type;
+
+void enable_nonsecure_access(void);
+void socfpga_io_setup(int boot_source);
+
+#endif
diff --git a/plat/intel/soc/agilex/include/agilex_reset_manager.h b/plat/intel/soc/agilex/include/agilex_reset_manager.h
new file mode 100644
index 0000000..a1b6297
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_reset_manager.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_RESETMANAGER_H
+#define AGX_RESETMANAGER_H
+
+#define AGX_RSTMGR_HDSKEN				0xffd11010
+#define AGX_RSTMGR_PER0MODRST				0xffd11024
+#define AGX_RSTMGR_PER1MODRST				0xffd11028
+#define AGX_RSTMGR_BRGMODRST				0xffd1102c
+
+#define AGX_RSTMGR_PER0MODRST_EMAC0			0x00000001
+#define AGX_RSTMGR_PER0MODRST_EMAC1			0x00000002
+#define AGX_RSTMGR_PER0MODRST_EMAC2			0x00000004
+#define AGX_RSTMGR_PER0MODRST_USB0			0x00000008
+#define AGX_RSTMGR_PER0MODRST_USB1			0x00000010
+#define AGX_RSTMGR_PER0MODRST_NAND			0x00000020
+#define AGX_RSTMGR_PER0MODRST_SDMMC			0x00000080
+#define AGX_RSTMGR_PER0MODRST_EMAC0OCP			0x00000100
+#define AGX_RSTMGR_PER0MODRST_EMAC1OCP			0x00000200
+#define AGX_RSTMGR_PER0MODRST_EMAC2OCP			0x00000400
+#define AGX_RSTMGR_PER0MODRST_USB0OCP			0x00000800
+#define AGX_RSTMGR_PER0MODRST_USB1OCP			0x00001000
+#define AGX_RSTMGR_PER0MODRST_NANDOCP			0x00002000
+#define AGX_RSTMGR_PER0MODRST_SDMMCOCP			0x00008000
+#define AGX_RSTMGR_PER0MODRST_DMA			0x00010000
+#define AGX_RSTMGR_PER0MODRST_SPIM0			0x00020000
+#define AGX_RSTMGR_PER0MODRST_SPIM1			0x00040000
+#define AGX_RSTMGR_PER0MODRST_SPIS0			0x00080000
+#define AGX_RSTMGR_PER0MODRST_SPIS1			0x00100000
+#define AGX_RSTMGR_PER0MODRST_DMAOCP			0x00200000
+#define AGX_RSTMGR_PER0MODRST_EMACPTP			0x00400000
+#define AGX_RSTMGR_PER0MODRST_DMAIF0			0x01000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF1			0x02000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF2			0x04000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF3			0x08000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF4			0x10000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF5			0x20000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF6			0x40000000
+#define AGX_RSTMGR_PER0MODRST_DMAIF7			0x80000000
+
+#define AGX_RSTMGR_PER1MODRST_WATCHDOG0			0x1
+#define AGX_RSTMGR_PER1MODRST_WATCHDOG1			0x2
+#define AGX_RSTMGR_PER1MODRST_WATCHDOG2			0x4
+#define AGX_RSTMGR_PER1MODRST_WATCHDOG3			0x8
+#define AGX_RSTMGR_PER1MODRST_L4SYSTIMER0		0x00000010
+#define AGX_RSTMGR_PER1MODRST_L4SYSTIMER1		0x00000020
+#define AGX_RSTMGR_PER1MODRST_SPTIMER0			0x00000040
+#define AGX_RSTMGR_PER1MODRST_SPTIMER1			0x00000080
+#define AGX_RSTMGR_PER1MODRST_I2C0			0x00000100
+#define AGX_RSTMGR_PER1MODRST_I2C1			0x00000200
+#define AGX_RSTMGR_PER1MODRST_I2C2			0x00000400
+#define AGX_RSTMGR_PER1MODRST_I2C3			0x00000800
+#define AGX_RSTMGR_PER1MODRST_I2C4			0x00001000
+#define AGX_RSTMGR_PER1MODRST_UART0			0x00010000
+#define AGX_RSTMGR_PER1MODRST_UART1			0x00020000
+#define AGX_RSTMGR_PER1MODRST_GPIO0			0x01000000
+#define AGX_RSTMGR_PER1MODRST_GPIO1			0x02000000
+
+#define AGX_RSTMGR_HDSKEN_FPGAHSEN			0x00000004
+#define AGX_RSTMGR_HDSKEN_ETRSTALLEN			0x00000008
+#define AGX_RSTMGR_HDSKEN_L2FLUSHEN			0x00000100
+#define AGX_RSTMGR_HDSKEN_L3NOC_DBG			0x00010000
+#define AGX_RSTMGR_HDSKEN_DEBUG_L3NOC			0x00020000
+#define AGX_RSTMGR_HDSKEN_SDRSELFREFEN			0x00000001
+
+#define AGX_RSTMGR_BRGMODRST_SOC2FPGA			0x1
+#define AGX_RSTMGR_BRGMODRST_LWHPS2FPGA			0x2
+#define AGX_RSTMGR_BRGMODRST_FPGA2SOC			0x4
+#define AGX_RSTMGR_BRGMODRST_MPFE			0x40
+
+void deassert_peripheral_reset(void);
+void config_hps_hs_before_warm_reset(void);
+
+#endif
+
diff --git a/plat/intel/soc/agilex/include/agilex_system_manager.h b/plat/intel/soc/agilex/include/agilex_system_manager.h
new file mode 100644
index 0000000..381c2d3
--- /dev/null
+++ b/plat/intel/soc/agilex/include/agilex_system_manager.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AGX_SYSTEMMANAGER_H
+#define AGX_SYSTEMMANAGER_H
+
+#define AGX_FIREWALL_SOC2FPGA			0xffd21200
+#define AGX_FIREWALL_LWSOC2FPGA			0xffd21300
+
+#define AGX_NOC_FW_L4_PER_SCR_NAND_REGISTER	0xffd21000
+#define AGX_NOC_FW_L4_PER_SCR_NAND_DATA		0xffd21004
+#define AGX_NOC_FW_L4_PER_SCR_USB0_REGISTER	0xffd2100c
+#define AGX_NOC_FW_L4_PER_SCR_USB1_REGISTER	0xffd21010
+#define AGX_NOC_FW_L4_PER_SCR_SPI_MASTER0	0xffd2101c
+#define AGX_NOC_FW_L4_PER_SCR_SPI_MASTER1	0xffd21020
+#define AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE0	0xffd21024
+#define AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE1	0xffd21028
+#define AGX_NOC_FW_L4_PER_SCR_EMAC0		0xffd2102c
+#define AGX_NOC_FW_L4_PER_SCR_EMAC1		0xffd21030
+#define AGX_NOC_FW_L4_PER_SCR_EMAC2		0xffd21034
+#define AGX_NOC_FW_L4_PER_SCR_SDMMC		0xffd21040
+#define AGX_NOC_FW_L4_PER_SCR_GPIO0		0xffd21044
+#define AGX_NOC_FW_L4_PER_SCR_GPIO1		0xffd21048
+#define AGX_NOC_FW_L4_PER_SCR_I2C0		0xffd21050
+#define AGX_NOC_FW_L4_PER_SCR_I2C1		0xffd21054
+#define AGX_NOC_FW_L4_PER_SCR_I2C2		0xffd21058
+#define AGX_NOC_FW_L4_PER_SCR_I2C3		0xffd2105c
+#define AGX_NOC_FW_L4_PER_SCR_I2C4		0xffd21060
+#define AGX_NOC_FW_L4_PER_SCR_SP_TIMER0		0xffd21064
+#define AGX_NOC_FW_L4_PER_SCR_SP_TIMER1		0xffd21068
+#define AGX_NOC_FW_L4_PER_SCR_UART0		0xffd2106c
+#define AGX_NOC_FW_L4_PER_SCR_UART1		0xffd21070
+
+#define AGX_NOC_FW_L4_SYS_SCR_DMA_ECC		0xffd21108
+#define AGX_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC	0xffd2110c
+#define AGX_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC	0xffd21110
+#define AGX_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC	0xffd21114
+#define AGX_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC	0xffd21118
+#define AGX_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC	0xffd2111c
+#define AGX_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC	0xffd21120
+#define AGX_NOC_FW_L4_SYS_SCR_NAND_ECC		0xffd2112c
+#define AGX_NOC_FW_L4_SYS_SCR_NAND_READ_ECC	0xffd21130
+#define AGX_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC	0xffd21134
+#define AGX_NOC_FW_L4_SYS_SCR_OCRAM_ECC		0xffd21138
+#define AGX_NOC_FW_L4_SYS_SCR_SDMMC_ECC		0xffd21140
+#define AGX_NOC_FW_L4_SYS_SCR_USB0_ECC		0xffd21144
+#define AGX_NOC_FW_L4_SYS_SCR_USB1_ECC		0xffd21148
+#define AGX_NOC_FW_L4_SYS_SCR_CLK_MGR		0xffd2114c
+#define AGX_NOC_FW_L4_SYS_SCR_IO_MGR		0xffd21154
+#define AGX_NOC_FW_L4_SYS_SCR_RST_MGR		0xffd21158
+#define AGX_NOC_FW_L4_SYS_SCR_SYS_MGR		0xffd2115c
+#define AGX_NOC_FW_L4_SYS_SCR_OSC0_TIMER	0xffd21160
+#define AGX_NOC_FW_L4_SYS_SCR_OSC1_TIMER	0xffd21164
+#define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG0		0xffd21168
+#define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG1		0xffd2116c
+#define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG2		0xffd21170
+#define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG3		0xffd21174
+#define AGX_NOC_FW_L4_SYS_SCR_DAP		0xffd21178
+#define AGX_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES	0xffd21190
+#define AGX_NOC_FW_L4_SYS_SCR_L4_NOC_QOS	0xffd21194
+
+#define AGX_CCU_NOC_CPU0_RAMSPACE0_0		0xf7004688
+#define AGX_CCU_NOC_IOM_RAMSPACE0_0		0xf7018628
+
+#define AGX_SYSMGR_CORE(x)                      (0xffd12000 + (x))
+#define SYSMGR_BOOT_SCRATCH_COLD_0		0x200
+#define SYSMGR_BOOT_SCRATCH_COLD_1		0x204
+#define SYSMGR_BOOT_SCRATCH_COLD_2		0x208
+
+#define DISABLE_BRIDGE_FIREWALL			0x0ffe0101
+#define DISABLE_L4_FIREWALL	(BIT(0) | BIT(16) | BIT(24))
+
+void enable_nonsecure_access(void);
+void enable_ns_bridge_access(void);
+
+#endif
diff --git a/plat/intel/soc/agilex/include/platform_def.h b/plat/intel/soc/agilex/include/platform_def.h
new file mode 100644
index 0000000..277862a
--- /dev/null
+++ b/plat/intel/soc/agilex/include/platform_def.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <plat/common/common_def.h>
+
+
+#define PLAT_CPUID_RELEASE			0xffe1b000
+#define PLAT_SEC_ENTRY				0xffe1b008
+
+/* Define next boot image name and offset */
+#define PLAT_NS_IMAGE_OFFSET			0x50000
+#define PLAT_HANDOFF_OFFSET			0xFFE3F000
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT			"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH			aarch64
+
+/* Agilex supports up to 124GB RAM */
+#define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 39)
+#define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 39)
+
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLAT_PRIMARY_CPU			0
+#define PLAT_SECONDARY_ENTRY_BASE		0x01f78bf0
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE			0x2000
+
+/* PSCI related constant */
+#define PLAT_NUM_POWER_DOMAINS			5
+#define PLAT_MAX_PWR_LVL			1
+#define PLAT_MAX_RET_STATE			1
+#define PLAT_MAX_OFF_STATE			2
+#define PLATFORM_SYSTEM_COUNT			1
+#define PLATFORM_CLUSTER_COUNT			1
+#define PLATFORM_CLUSTER0_CORE_COUNT		4
+#define PLATFORM_CLUSTER1_CORE_COUNT		0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT + \
+					PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER		4
+
+/* Interrupt related constant */
+
+#define INTEL_AGX_IRQ_SEC_PHY_TIMER		29
+
+#define INTEL_AGX_IRQ_SEC_SGI_0			8
+#define INTEL_AGX_IRQ_SEC_SGI_1			9
+#define INTEL_AGX_IRQ_SEC_SGI_2			10
+#define INTEL_AGX_IRQ_SEC_SGI_3			11
+#define INTEL_AGX_IRQ_SEC_SGI_4			12
+#define INTEL_AGX_IRQ_SEC_SGI_5			13
+#define INTEL_AGX_IRQ_SEC_SGI_6			14
+#define INTEL_AGX_IRQ_SEC_SGI_7			15
+
+#define TSP_IRQ_SEC_PHY_TIMER		INTEL_AGX_IRQ_SEC_PHY_TIMER
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE + 1)
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+#define DRAM_BASE				(0x0)
+#define DRAM_SIZE				(0x80000000)
+
+#define OCRAM_BASE				(0xFFE00000)
+#define OCRAM_SIZE				(0x00040000)
+
+#define MEM64_BASE				(0x0100000000)
+#define MEM64_SIZE				(0x1F00000000)
+
+#define DEVICE1_BASE				(0x80000000)
+#define DEVICE1_SIZE				(0x60000000)
+
+#define DEVICE2_BASE				(0xF7000000)
+#define DEVICE2_SIZE				(0x08E00000)
+
+#define DEVICE3_BASE				(0xFFFC0000)
+#define DEVICE3_SIZE				(0x00008000)
+
+#define DEVICE4_BASE				(0x2000000000)
+#define DEVICE4_SIZE				(0x0100000000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL3-1 debug size plus a
+ * little space for growth.
+ */
+
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define BL1_RO_BASE	(0xffe00000)
+#define BL1_RO_LIMIT	(0xffe0f000)
+#define BL1_RW_BASE	(0xffe10000)
+#define BL1_RW_LIMIT	(0xffe1ffff)
+#define BL1_RW_SIZE	(0x14000)
+
+#define BL2_BASE	(0xffe00000)
+#define BL2_LIMIT	(0xffe1b000)
+
+#define BL31_BASE	(0xffe1c000)
+#define BL31_LIMIT	(0xffe3bfff)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		16
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT			6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_GIC_BASE			(0xFFFC0000)
+#define PLAT_GICC_BASE			(PLAT_GIC_BASE + 0x2000)
+#define PLAT_GICD_BASE			(PLAT_GIC_BASE + 0x1000)
+#define PLAT_GICR_BASE			0
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define PLAT_UART0_BASE		(0xFFC02000)
+#define PLAT_UART1_BASE		(0xFFC02100)
+
+#define CRASH_CONSOLE_BASE	PLAT_UART0_BASE
+
+#define PLAT_BAUDRATE		(115200)
+#define PLAT_UART_CLOCK		(100000000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define PLAT_SYS_COUNTER_FREQ_IN_TICKS	(400000000)
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ	(400)
+
+#define PLAT_INTEL_AGX_GICD_BASE	PLAT_GICD_BASE
+#define PLAT_INTEL_AGX_GICC_BASE	PLAT_GICC_BASE
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_INTEL_AGX_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
+			grp, GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+
+#define PLAT_INTEL_AGX_G0_IRQ_PROPS(grp)
+
+#define MAX_IO_HANDLES			4
+#define MAX_IO_DEVICES			4
+#define MAX_IO_BLOCK_DEVICES		2
+
+#endif /* PLATFORM_DEF_H */
+
diff --git a/plat/intel/soc/agilex/platform.mk b/plat/intel/soc/agilex/platform.mk
new file mode 100644
index 0000000..5d20462
--- /dev/null
+++ b/plat/intel/soc/agilex/platform.mk
@@ -0,0 +1,74 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2019, Intel Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+PLAT_INCLUDES		:=	\
+			-Iplat/intel/soc/agilex/include/		\
+			-Iplat/intel/soc/common/drivers/		\
+			-Iplat/intel/soc/common/include/
+
+PLAT_BL_COMMON_SOURCES	:=	\
+			drivers/arm/gic/common/gic_common.c		\
+			drivers/arm/gic/v2/gicv2_main.c			\
+			drivers/arm/gic/v2/gicv2_helpers.c		\
+			drivers/delay_timer/delay_timer.c		\
+			drivers/delay_timer/generic_delay_timer.c  	\
+			drivers/ti/uart/aarch64/16550_console.S		\
+			lib/xlat_tables/aarch64/xlat_tables.c 		\
+			lib/xlat_tables/xlat_tables_common.c 		\
+			plat/common/plat_gicv2.c			\
+			plat/intel/soc/common/aarch64/platform_common.c \
+			plat/intel/soc/common/aarch64/plat_helpers.S
+
+BL2_SOURCES     +=	\
+		common/desc_image_load.c				\
+		drivers/partition/partition.c				\
+		drivers/partition/gpt.c					\
+		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/mmc/mmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
+		drivers/io/io_storage.c					\
+		drivers/io/io_block.c					\
+		drivers/io/io_fip.c					\
+		drivers/gpio/gpio.c					\
+		drivers/intel/soc/stratix10/io/s10_memmap_qspi.c	\
+		lib/cpus/aarch64/cortex_a53.S				\
+		plat/intel/soc/agilex/bl2_plat_setup.c			\
+		plat/intel/soc/agilex/socfpga_storage.c			\
+                plat/intel/soc/common/bl2_plat_mem_params_desc.c	\
+		plat/intel/soc/agilex/soc/agilex_reset_manager.c	\
+		plat/intel/soc/agilex/soc/agilex_handoff.c		\
+		plat/intel/soc/agilex/soc/agilex_clock_manager.c	\
+		plat/intel/soc/agilex/soc/agilex_pinmux.c		\
+		plat/intel/soc/agilex/soc/agilex_memory_controller.c	\
+		plat/intel/soc/common/socfpga_delay_timer.c		\
+		plat/intel/soc/common/socfpga_image_load.c		\
+		plat/intel/soc/agilex/soc/agilex_system_manager.c	\
+		plat/intel/soc/agilex/soc/agilex_mailbox.c		\
+		plat/intel/soc/common/drivers/qspi/cadence_qspi.c	\
+		plat/intel/soc/common/drivers/wdt/watchdog.c		\
+		plat/intel/soc/common/drivers/ccu/ncore_ccu.c
+
+BL31_SOURCES	+=	\
+		drivers/arm/cci/cci.c					\
+		lib/cpus/aarch64/cortex_a53.S				\
+		lib/cpus/aarch64/aem_generic.S				\
+		plat/common/plat_psci_common.c				\
+		plat/intel/soc/agilex/socfpga_sip_svc.c			\
+		plat/intel/soc/agilex/bl31_plat_setup.c 		\
+		plat/intel/soc/agilex/socfpga_psci.c			\
+		plat/intel/soc/common/socfpga_topology.c		\
+		plat/intel/soc/common/socfpga_delay_timer.c		\
+		plat/intel/soc/agilex/soc/agilex_reset_manager.c	\
+		plat/intel/soc/agilex/soc/agilex_pinmux.c		\
+		plat/intel/soc/agilex/soc/agilex_clock_manager.c	\
+		plat/intel/soc/agilex/soc/agilex_handoff.c		\
+		plat/intel/soc/agilex/soc/agilex_mailbox.c
+
+PROGRAMMABLE_RESET_ADDRESS	:= 0
+BL2_AT_EL3			:= 1
+MULTI_CONSOLE_API		:= 1
+USE_COHERENT_MEM		:= 1
diff --git a/plat/intel/soc/agilex/soc/agilex_clock_manager.c b/plat/intel/soc/agilex/soc/agilex_clock_manager.c
new file mode 100644
index 0000000..218676a
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_clock_manager.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+
+#include "agilex_clock_manager.h"
+#include "agilex_handoff.h"
+#include "agilex_system_manager.h"
+
+
+uint32_t wait_pll_lock(void)
+{
+	uint32_t data;
+	uint32_t count = 0;
+
+	do {
+		data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT);
+		count++;
+		if (count >= 1000)
+			return -ETIMEDOUT;
+
+	} while ((CLKMGR_STAT_MAINPLLLOCKED(data) == 0) ||
+			(CLKMGR_STAT_PERPLLLOCKED(data) == 0));
+	return 0;
+}
+
+uint32_t wait_fsm(void)
+{
+	uint32_t data;
+	uint32_t count = 0;
+
+	do {
+		data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT);
+		count++;
+		if (count >= 1000)
+			return -ETIMEDOUT;
+
+	} while (CLKMGR_STAT_BUSY(data) == CLKMGR_STAT_BUSY_E_BUSY);
+
+	return 0;
+}
+
+uint32_t pll_source_sync_config(uint32_t pll_mem_offset)
+{
+	uint32_t val = 0;
+	uint32_t count = 0;
+	uint32_t req_status = 0;
+
+	val = (CLKMGR_MEM_WR | CLKMGR_MEM_REQ |
+		CLKMGR_MEM_WDAT << CLKMGR_MEM_WDAT_OFFSET | CLKMGR_MEM_ADDR);
+	mmio_write_32(pll_mem_offset, val);
+
+	do {
+		req_status = mmio_read_32(pll_mem_offset);
+		count++;
+	} while ((req_status & CLKMGR_MEM_REQ) && (count < 10));
+
+	if (count >= 100)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+uint32_t pll_source_sync_read(uint32_t pll_mem_offset)
+{
+	uint32_t val = 0;
+	uint32_t rdata = 0;
+	uint32_t count = 0;
+	uint32_t req_status = 0;
+
+	val = (CLKMGR_MEM_REQ | CLKMGR_MEM_ADDR);
+	mmio_write_32(pll_mem_offset, val);
+
+	do {
+		req_status = mmio_read_32(pll_mem_offset);
+		count++;
+	} while ((req_status & CLKMGR_MEM_REQ) && (count < 10));
+
+	if (count >= 100)
+		return -ETIMEDOUT;
+
+	rdata = mmio_read_32(pll_mem_offset + 0x4);
+	INFO("rdata (%x) = %x\n", pll_mem_offset + 0x4, rdata);
+
+	return 0;
+}
+
+void config_clkmgr_handoff(handoff *hoff_ptr)
+{
+	uint32_t mdiv, mscnt, hscnt;
+	uint32_t arefclk_div, drefclk_div;
+
+	/* Bypass all mainpllgrp's clocks */
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0x7);
+	wait_fsm();
+
+	/* Bypass all perpllgrp's clocks */
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0x7f);
+	wait_fsm();
+
+	/* Put both PLL in reset and power down */
+	mmio_clrbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB,
+			CLKMGR_PLLGLOB_PD_SET_MSK |
+			CLKMGR_PLLGLOB_RST_SET_MSK);
+	mmio_clrbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB,
+			CLKMGR_PLLGLOB_PD_SET_MSK |
+			CLKMGR_PLLGLOB_RST_SET_MSK);
+
+	/* Setup main PLL dividers */
+	mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->main_pll_pllm);
+
+	arefclk_div = CLKMGR_PLLGLOB_AREFCLKDIV(
+			hoff_ptr->main_pll_pllglob);
+	drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV(
+			hoff_ptr->main_pll_pllglob);
+
+	mscnt = 100 / (mdiv / BIT(drefclk_div));
+	if (!mscnt)
+		mscnt = 1;
+	hscnt = (mdiv * mscnt * BIT(drefclk_div) / arefclk_div) - 4;
+
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_VCOCALIB,
+			CLKMGR_VCOCALIB_HSCNT_SET(hscnt) |
+			CLKMGR_VCOCALIB_MSCNT_SET(mscnt));
+
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV,
+			hoff_ptr->main_pll_nocdiv);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB,
+			hoff_ptr->main_pll_pllglob);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_FDBCK,
+			hoff_ptr->main_pll_fdbck);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC0,
+			hoff_ptr->main_pll_pllc0);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC1,
+			hoff_ptr->main_pll_pllc1);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC2,
+			hoff_ptr->main_pll_pllc2);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC3,
+			hoff_ptr->main_pll_pllc3);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM,
+			hoff_ptr->main_pll_pllm);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MPUCLK,
+			hoff_ptr->main_pll_mpuclk);
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCCLK,
+			hoff_ptr->main_pll_nocclk);
+
+	/* Setup peripheral PLL dividers */
+	mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->per_pll_pllm);
+
+	arefclk_div = CLKMGR_PLLGLOB_AREFCLKDIV(
+			hoff_ptr->per_pll_pllglob);
+	drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV(
+			hoff_ptr->per_pll_pllglob);
+
+	mscnt = 100 / (mdiv / BIT(drefclk_div));
+	if (!mscnt)
+		mscnt = 1;
+	hscnt = (mdiv * mscnt * BIT(drefclk_div) / arefclk_div) - 4;
+
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_VCOCALIB,
+			CLKMGR_VCOCALIB_HSCNT_SET(hscnt) |
+			CLKMGR_VCOCALIB_MSCNT_SET(mscnt));
+
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EMACCTL,
+			hoff_ptr->per_pll_emacctl);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_GPIODIV,
+			CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(
+			hoff_ptr->per_pll_gpiodiv));
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB,
+			hoff_ptr->per_pll_pllglob);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_FDBCK,
+			hoff_ptr->per_pll_fdbck);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC0,
+			hoff_ptr->per_pll_pllc0);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC1,
+			hoff_ptr->per_pll_pllc1);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC2,
+			hoff_ptr->per_pll_pllc2);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC3,
+			hoff_ptr->per_pll_pllc3);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM,
+			hoff_ptr->per_pll_pllm);
+
+	/* Take both PLL out of reset and power up */
+	mmio_setbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB,
+			CLKMGR_PLLGLOB_PD_SET_MSK |
+			CLKMGR_PLLGLOB_RST_SET_MSK);
+	mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB,
+			CLKMGR_PLLGLOB_PD_SET_MSK |
+			CLKMGR_PLLGLOB_RST_SET_MSK);
+
+	wait_pll_lock();
+
+	pll_source_sync_config(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MEM);
+	pll_source_sync_read(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MEM);
+
+	pll_source_sync_config(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM);
+	pll_source_sync_read(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM);
+
+	/*Configure Ping Pong counters in altera group */
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACACTR,
+			hoff_ptr->alt_emacactr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACBCTR,
+			hoff_ptr->alt_emacbctr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACPTPCTR,
+			hoff_ptr->alt_emacptpctr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_GPIODBCTR,
+			hoff_ptr->alt_gpiodbctr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR,
+			hoff_ptr->alt_sdmmcctr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_S2FUSER0CTR,
+			hoff_ptr->alt_s2fuser0ctr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_S2FUSER1CTR,
+			hoff_ptr->alt_s2fuser1ctr);
+	mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_PSIREFCTR,
+			hoff_ptr->alt_psirefctr);
+
+	/* Take all PLLs out of bypass */
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0);
+	wait_fsm();
+
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0);
+	wait_fsm();
+
+	/* Clear loss lock  interrupt status register that */
+	/* might be set during configuration */
+	mmio_setbits_32(CLKMGR_OFFSET + CLKMGR_INTRCLR,
+			CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK |
+			CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK);
+
+	/* Take all ping pong counters out of reset */
+	mmio_clrbits_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EXTCNTRST,
+			CLKMGR_ALTERA_EXTCNTRST_RESET);
+
+	/* Set safe mode / out of boot mode */
+	mmio_clrbits_32(CLKMGR_OFFSET + CLKMGR_CTRL,
+		CLKMGR_CTRL_BOOTMODE_SET_MSK);
+	wait_fsm();
+
+	/* Enable mainpllgrp's software-managed clock */
+	mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_EN,
+			CLKMGR_MAINPLL_EN_RESET);
+	mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EN,
+			CLKMGR_PERPLL_EN_RESET);
+
+	/* Pass clock source frequency into scratch register */
+	mmio_write_32(AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_1),
+		hoff_ptr->hps_osc_clk_h);
+	mmio_write_32(AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_2),
+		hoff_ptr->fpga_clk_hz);
+}
+
+/* Extract reference clock from platform clock source */
+uint32_t get_ref_clk(uint32_t pllglob)
+{
+	uint32_t arefclkdiv, ref_clk;
+	uint32_t scr_reg;
+
+	switch (CLKMGR_PSRC(pllglob)) {
+	case CLKMGR_PLLGLOB_PSRC_EOSC1:
+		scr_reg = AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_1);
+		ref_clk = mmio_read_32(scr_reg);
+		break;
+	case CLKMGR_PLLGLOB_PSRC_INTOSC:
+		ref_clk = CLKMGR_INTOSC_HZ;
+		break;
+	case CLKMGR_PLLGLOB_PSRC_F2S:
+		scr_reg = AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_2);
+		ref_clk = mmio_read_32(scr_reg);
+		break;
+	default:
+		ref_clk = 0;
+		assert(0);
+		break;
+	}
+
+	arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob);
+	ref_clk /= arefclkdiv;
+
+	return ref_clk;
+}
+
+/* Calculate clock frequency based on parameter */
+uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc)
+{
+	uint32_t clk_psrc, mdiv, ref_clk;
+	uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg;
+
+	clk_psrc = mmio_read_32(CLKMGR_MAINPLL + psrc_reg);
+
+	switch (CLKMGR_PSRC(clk_psrc)) {
+	case CLKMGR_PSRC_MAIN:
+		pllm_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM;
+		pllc_reg = CLKMGR_MAINPLL + main_pllc;
+		pllglob_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB;
+		break;
+	case CLKMGR_PSRC_PER:
+		pllm_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM;
+		pllc_reg = CLKMGR_PERPLL + per_pllc;
+		pllglob_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB;
+		break;
+	default:
+		return 0;
+	}
+
+	ref_clk = get_ref_clk(mmio_read_32(pllglob_reg));
+	mdiv = CLKMGR_PLLM_MDIV(mmio_read_32(pllm_reg));
+	ref_clk *= mdiv;
+
+	pllc_div = mmio_read_32(pllc_reg) & 0x7ff;
+
+	return ref_clk / pllc_div;
+}
+
+/* Return L3 interconnect clock */
+uint32_t get_l3_clk(void)
+{
+	uint32_t l3_clk;
+
+	l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1,
+				CLKMGR_PERPLL_PLLC1);
+	return l3_clk;
+}
+
+/* Calculate clock frequency to be used for watchdog timer */
+uint32_t get_wdt_clk(void)
+{
+	uint32_t l3_clk, l4_sys_clk;
+
+	l3_clk = get_l3_clk();
+	l4_sys_clk = l3_clk / 4;
+
+	return l4_sys_clk;
+}
+
+/* Calculate clock frequency to be used for UART driver */
+uint32_t get_uart_clk(void)
+{
+	uint32_t data32, l3_clk, l4_sp_clk;
+
+	l3_clk = get_l3_clk();
+
+	data32 = mmio_read_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV);
+	data32 = (data32 >> 16) & 0x3;
+
+	l4_sp_clk = l3_clk >> data32;
+
+	return l4_sp_clk;
+}
+
+/* Calculate clock frequency to be used for SDMMC driver */
+uint32_t get_mmc_clk(void)
+{
+	uint32_t data32, mmc_clk;
+
+	mmc_clk = get_clk_freq(CLKMGR_ALTERA_SDMMCCTR,
+		CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3);
+
+	data32 = mmio_read_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR);
+	data32 = (data32 & 0x7ff) + 1;
+	mmc_clk = (mmc_clk / data32) / 4;
+
+	return mmc_clk;
+}
diff --git a/plat/intel/soc/agilex/soc/agilex_handoff.c b/plat/intel/soc/agilex/soc/agilex_handoff.c
new file mode 100644
index 0000000..a458686
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_handoff.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+#include <string.h>
+
+#include "agilex_handoff.h"
+
+#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) |	\
+				(((x) & 0x0000FF00) << 8) | ((x) << 24))
+
+int agilex_get_handoff(handoff *reverse_hoff_ptr)
+{
+	int i;
+	uint32_t *buffer;
+	handoff *handoff_ptr = (handoff *) PLAT_HANDOFF_OFFSET;
+
+	memcpy(reverse_hoff_ptr, handoff_ptr, sizeof(handoff));
+	buffer = (uint32_t *)reverse_hoff_ptr;
+
+	/* convert big endian to little endian */
+	for (i = 0; i < sizeof(handoff) / 4; i++)
+		buffer[i] = SWAP_UINT32(buffer[i]);
+
+	if (reverse_hoff_ptr->header_magic != HANDOFF_MAGIC_HEADER)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_sel_magic != HANDOFF_MAGIC_PINMUX_SEL)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_io_magic != HANDOFF_MAGIC_IOCTLR)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_fpga_magic != HANDOFF_MAGIC_FPGA)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_delay_magic != HANDOFF_MAGIC_IODELAY)
+		return -1;
+
+	return 0;
+}
diff --git a/plat/intel/soc/agilex/soc/agilex_mailbox.c b/plat/intel/soc/agilex/soc/agilex_mailbox.c
new file mode 100644
index 0000000..ebfea61
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_mailbox.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <common/debug.h>
+
+#include "agilex_mailbox.h"
+
+static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
+					int len)
+{
+	uint32_t cmd_free_offset;
+	int i;
+
+	cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
+
+	if (cmd_free_offset >= MBOX_CMD_BUFFER_SIZE) {
+		INFO("Insufficient buffer in mailbox\n");
+		return MBOX_INSUFFICIENT_BUFFER;
+	}
+
+
+	mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4),
+			header_cmd);
+
+
+	for (i = 0; i < len; i++) {
+		cmd_free_offset %= MBOX_CMD_BUFFER_SIZE;
+		mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER +
+				(cmd_free_offset++ * 4), args[i]);
+	}
+
+	cmd_free_offset %= MBOX_CMD_BUFFER_SIZE;
+	mmio_write_32(MBOX_OFFSET + MBOX_CIN, cmd_free_offset);
+
+	return 0;
+}
+
+int mailbox_read_response(int job_id, uint32_t *response)
+{
+	int rin = 0;
+	int rout = 0;
+	int response_length = 0;
+	int resp = 0;
+	int total_resp_len = 0;
+	int timeout = 100000;
+
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
+
+	while (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) {
+		if (timeout-- < 0)
+			return MBOX_NO_RESPONSE;
+	}
+
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
+
+	rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+	rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+	while (rout != rin) {
+		resp = mmio_read_32(MBOX_OFFSET +
+				    MBOX_RESP_BUFFER + ((rout++)*4));
+
+		rout %= MBOX_RESP_BUFFER_SIZE;
+		mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+		if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID ||
+		   MBOX_RESP_JOB_ID(resp) != job_id) {
+			return MBOX_WRONG_ID;
+		}
+
+		if (MBOX_RESP_ERR(resp) > 0) {
+			INFO("Error in response: %x\n", resp);
+			return -resp;
+		}
+		response_length = MBOX_RESP_LEN(resp);
+
+		while (response_length) {
+
+			response_length--;
+			resp = mmio_read_32(MBOX_OFFSET +
+						MBOX_RESP_BUFFER +
+						(rout)*4);
+			if (response) {
+				*(response + total_resp_len) = resp;
+				total_resp_len++;
+			}
+			rout++;
+			rout %= MBOX_RESP_BUFFER_SIZE;
+			mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+		}
+		return total_resp_len;
+	}
+
+	return MBOX_NO_RESPONSE;
+}
+
+
+int mailbox_poll_response(int job_id, int urgent, uint32_t *response)
+{
+	int timeout = 80000;
+	int rin = 0;
+	int rout = 0;
+	int response_length = 0;
+	int resp = 0;
+	int total_resp_len = 0;
+
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
+
+	while (1) {
+		while (timeout > 0 &&
+			mmio_read_32(MBOX_OFFSET +
+				MBOX_DOORBELL_FROM_SDM) != 1) {
+			timeout--;
+		}
+
+		if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) {
+			INFO("Timed out waiting for SDM");
+			return MBOX_TIMEOUT;
+		}
+
+		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
+
+		if (urgent & 1) {
+			if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
+				MBOX_STATUS_UA_MASK) ^
+				(urgent & MBOX_STATUS_UA_MASK)) {
+				mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
+				return 0;
+			}
+
+			mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
+			INFO("Error: Mailbox did not get UA");
+			return -1;
+		}
+
+		rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+		rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+		while (rout != rin) {
+			resp = mmio_read_32(MBOX_OFFSET +
+					    MBOX_RESP_BUFFER + ((rout++)*4));
+
+			rout %= MBOX_RESP_BUFFER_SIZE;
+			mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+			if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID ||
+			   MBOX_RESP_JOB_ID(resp) != job_id)
+				continue;
+
+			if (MBOX_RESP_ERR(resp) > 0) {
+				INFO("Error in response: %x\n", resp);
+				return -MBOX_RESP_ERR(resp);
+			}
+			response_length = MBOX_RESP_LEN(resp);
+
+			while (response_length) {
+
+				response_length--;
+				resp = mmio_read_32(MBOX_OFFSET +
+							MBOX_RESP_BUFFER +
+							(rout)*4);
+				if (response) {
+					*(response + total_resp_len) = resp;
+					total_resp_len++;
+				}
+				rout++;
+				rout %= MBOX_RESP_BUFFER_SIZE;
+				mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+			}
+			return total_resp_len;
+		}
+	}
+}
+
+void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args,
+			  int len, int urgent)
+{
+	if (urgent)
+		mmio_write_32(MBOX_OFFSET + MBOX_URG, 1);
+
+	fill_mailbox_circular_buffer(MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
+					MBOX_JOB_ID_CMD(job_id) |
+					MBOX_CMD_LEN_CMD(len) |
+					MBOX_INDIRECT |
+					cmd, args, len);
+}
+
+int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args,
+			  int len, int urgent, uint32_t *response)
+{
+	int status;
+
+	if (urgent) {
+		urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
+					MBOX_STATUS_UA_MASK;
+		mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd);
+		status = 0;
+	} else {
+		status = fill_mailbox_circular_buffer(
+			MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
+			MBOX_JOB_ID_CMD(job_id) |
+			cmd, args, len);
+	}
+
+	if (status)
+		return status;
+
+	return mailbox_poll_response(job_id, urgent, response);
+}
+
+void mailbox_set_int(int interrupt)
+{
+
+	mmio_write_32(MBOX_OFFSET+MBOX_INT, MBOX_COE_BIT(interrupt) |
+			MBOX_UAE_BIT(interrupt));
+}
+
+
+void mailbox_set_qspi_open(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, 0, 0, 0, 0);
+}
+
+void mailbox_set_qspi_direct(void)
+{
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0);
+}
+
+void mailbox_set_qspi_close(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, 0, 0, 0, 0);
+}
+
+int mailbox_get_qspi_clock(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0);
+}
+
+void mailbox_qspi_set_cs(int device_select)
+{
+	uint32_t cs_setting = device_select;
+
+	/* QSPI device select settings at 31:28 */
+	cs_setting = (cs_setting << 28);
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting,
+		1, 0, 0);
+}
+
+void mailbox_reset_cold(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, 0, 0, 0, 0);
+}
+
+int mailbox_init(void)
+{
+	int status = 0;
+
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE |
+			MBOX_INT_FLAG_UAE);
+	mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
+	status = mailbox_send_cmd(0, MBOX_CMD_RESTART, 0, 0, 1, 0);
+
+	if (status)
+		return status;
+
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+
+	return 0;
+}
+
diff --git a/plat/intel/soc/agilex/soc/agilex_memory_controller.c b/plat/intel/soc/agilex/soc/agilex_memory_controller.c
new file mode 100644
index 0000000..f09238c
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_memory_controller.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <platform_def.h>
+
+#include "agilex_memory_controller.h"
+
+#define ALT_CCU_NOC_DI_SET_MSK		0x10
+
+#define DDR_READ_LATENCY_DELAY		40
+#define MAX_MEM_CAL_RETRY		3
+#define PRE_CALIBRATION_DELAY		1
+#define POST_CALIBRATION_DELAY		1
+#define TIMEOUT_EMIF_CALIBRATION	1000
+#define CLEAR_EMIF_DELAY		50000
+#define CLEAR_EMIF_TIMEOUT		0x100000
+#define TIMEOUT_INT_RESP		10000
+
+#define DDR_CONFIG(A, B, C, R)	(((A) << 24) | ((B) << 16) | ((C) << 8) | (R))
+#define DDR_CONFIG_ELEMENTS	(sizeof(ddr_config)/sizeof(uint32_t))
+
+/* tWR = Min. 15ns constant, see JEDEC standard eg. DDR4 is JESD79-4.pdf */
+#define tWR_IN_NS 15
+
+void configure_hmc_adaptor_regs(void);
+void configure_ddr_sched_ctrl_regs(void);
+
+/* The followring are the supported configurations */
+uint32_t ddr_config[] = {
+	/* DDR_CONFIG(Address order,Bank,Column,Row) */
+	/* List for DDR3 or LPDDR3 (pinout order > chip, row, bank, column) */
+	DDR_CONFIG(0, 3, 10, 12),
+	DDR_CONFIG(0, 3,  9, 13),
+	DDR_CONFIG(0, 3, 10, 13),
+	DDR_CONFIG(0, 3,  9, 14),
+	DDR_CONFIG(0, 3, 10, 14),
+	DDR_CONFIG(0, 3, 10, 15),
+	DDR_CONFIG(0, 3, 11, 14),
+	DDR_CONFIG(0, 3, 11, 15),
+	DDR_CONFIG(0, 3, 10, 16),
+	DDR_CONFIG(0, 3, 11, 16),
+	DDR_CONFIG(0, 3, 12, 15),	/* 0xa */
+	/* List for DDR4 only (pinout order > chip, bank, row, column) */
+	DDR_CONFIG(1, 3, 10, 14),
+	DDR_CONFIG(1, 4, 10, 14),
+	DDR_CONFIG(1, 3, 10, 15),
+	DDR_CONFIG(1, 4, 10, 15),
+	DDR_CONFIG(1, 3, 10, 16),
+	DDR_CONFIG(1, 4, 10, 16),
+	DDR_CONFIG(1, 3, 10, 17),
+	DDR_CONFIG(1, 4, 10, 17),
+};
+
+static int match_ddr_conf(uint32_t ddr_conf)
+{
+	int i;
+
+	for (i = 0; i < DDR_CONFIG_ELEMENTS; i++) {
+		if (ddr_conf == ddr_config[i])
+			return i;
+	}
+	return 0;
+}
+
+static int check_hmc_clk(void)
+{
+	unsigned long timeout = 0;
+	uint32_t hmc_clk;
+
+	do {
+		hmc_clk = mmio_read_32(AGX_SYSMGR_CORE_HMC_CLK);
+		if (hmc_clk & AGX_SYSMGR_CORE_HMC_CLK_STATUS)
+			break;
+		udelay(1);
+	} while (++timeout < 1000);
+	if (timeout >= 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int clear_emif(void)
+{
+	uint32_t data;
+	unsigned long timeout;
+
+	mmio_write_32(AGX_MPFE_HMC_ADP_RSTHANDSHAKECTRL, 0);
+
+	timeout = 0;
+	do {
+		data = mmio_read_32(AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT);
+		if ((data & AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE) == 0)
+			break;
+		udelay(CLEAR_EMIF_DELAY);
+	} while (++timeout < CLEAR_EMIF_TIMEOUT);
+	if (timeout >= CLEAR_EMIF_TIMEOUT)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mem_calibration(void)
+{
+	int status;
+	uint32_t data;
+	unsigned long timeout;
+	unsigned long retry = 0;
+
+	udelay(PRE_CALIBRATION_DELAY);
+
+	do {
+		if (retry != 0)
+			INFO("DDR: Retrying DRAM calibration\n");
+
+		timeout = 0;
+		do {
+			data = mmio_read_32(AGX_MPFE_HMC_ADP_DDRCALSTAT);
+			if (AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 1)
+				break;
+			mdelay(1);
+		} while (++timeout < TIMEOUT_EMIF_CALIBRATION);
+
+		if (AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) {
+			status = clear_emif();
+			if (status)
+				ERROR("Failed to clear Emif\n");
+		} else {
+			break;
+		}
+	} while (++retry < MAX_MEM_CAL_RETRY);
+
+	if (AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) {
+		ERROR("DDR: DRAM calibration failed.\n");
+		status = -EIO;
+	} else {
+		INFO("DDR: DRAM calibration success.\n");
+		status = 0;
+	}
+
+	udelay(POST_CALIBRATION_DELAY);
+
+	return status;
+}
+
+int init_hard_memory_controller(void)
+{
+	int status;
+
+	status = check_hmc_clk();
+	if (status) {
+		ERROR("DDR: Error, HMC clock not running\n");
+		return status;
+	}
+
+/*	mmio_clrbits_32(AGX_RSTMGR_BRGMODRST, AGX_RSTMGR_BRGMODRST_DDRSCH);*/
+
+	status = mem_calibration();
+	if (status) {
+		ERROR("DDR: Memory Calibration Failed\n");
+		return status;
+	}
+
+	configure_hmc_adaptor_regs();
+/*	configure_ddr_sched_ctrl_regs();*/
+
+	return 0;
+}
+
+void configure_ddr_sched_ctrl_regs(void)
+{
+	uint32_t data, dram_addr_order, ddr_conf, bank, row, col,
+		rd_to_miss, wr_to_miss, burst_len, burst_len_ddr_clk,
+		burst_len_sched_clk, act_to_act, rd_to_wr, wr_to_rd, bw_ratio,
+		t_rtp, t_rp, t_rcd, rd_latency, tw_rin_clk_cycles,
+		bw_ratio_extended, auto_precharge = 0, act_to_act_bank, faw,
+		faw_bank, bus_rd_to_rd, bus_rd_to_wr, bus_wr_to_rd;
+
+	INFO("Init HPS NOC's DDR Scheduler.\n");
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG1);
+	dram_addr_order = AGX_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_DRAMADDRW);
+
+	col  = IOHMC_DRAMADDRW_COL_ADDR_WIDTH(data);
+	row  = IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(data);
+	bank = IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(data);
+
+	ddr_conf = match_ddr_conf(DDR_CONFIG(dram_addr_order, bank, col, row));
+
+	if (ddr_conf) {
+		mmio_clrsetbits_32(
+			AGX_MPFE_DDR_MAIN_SCHED_DDRCONF,
+			AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK,
+			AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(ddr_conf));
+	} else {
+		ERROR("DDR: Cannot find predefined ddrConf configuration.\n");
+	}
+
+	mmio_write_32(AGX_MPFE_HMC_ADP(ADP_DRAMADDRWIDTH), data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_DRAMTIMING0);
+	rd_latency = AGX_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING0);
+	act_to_act = ACT_TO_ACT(data);
+	t_rcd = ACT_TO_RDWR(data);
+	act_to_act_bank = ACT_TO_ACT_DIFF_BANK(data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING1);
+	rd_to_wr = RD_TO_WR(data);
+	bus_rd_to_rd = RD_TO_RD_DIFF_CHIP(data);
+	bus_rd_to_wr = RD_TO_WR_DIFF_CHIP(data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING2);
+	t_rtp = RD_TO_PCH(data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING3);
+	wr_to_rd = CALTIMING3_WR_TO_RD(data);
+	bus_wr_to_rd = CALTIMING3_WR_TO_RD_DIFF_CHIP(data);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING4);
+	t_rp = PCH_TO_VALID(data);
+
+	data = mmio_read_32(AGX_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL));
+	bw_ratio = ((HMC_ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 0 : 1);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG0);
+	burst_len = HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(data);
+	burst_len_ddr_clk = burst_len / 2;
+	burst_len_sched_clk = ((burst_len/2) / 2);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG0);
+	switch (AGX_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(data)) {
+	case 1:
+		/* DDR4 - 1333MHz */
+		/* 20 (19.995) clock cycles = 15ns */
+		/* Calculate with rounding */
+		tw_rin_clk_cycles = (((tWR_IN_NS * 1333) % 1000) >= 500) ?
+			((tWR_IN_NS * 1333) / 1000) + 1 :
+			((tWR_IN_NS * 1333) / 1000);
+		break;
+	default:
+		/* Others - 1066MHz or slower */
+		/* 16 (15.990) clock cycles = 15ns */
+		/* Calculate with rounding */
+		tw_rin_clk_cycles = (((tWR_IN_NS * 1066) % 1000) >= 500) ?
+			((tWR_IN_NS * 1066) / 1000) + 1 :
+			((tWR_IN_NS * 1066) / 1000);
+		break;
+	}
+
+	rd_to_miss = t_rtp + t_rp + t_rcd - burst_len_sched_clk;
+	wr_to_miss = ((rd_latency + burst_len_ddr_clk + 2 + tw_rin_clk_cycles)
+			/ 2) - rd_to_wr + t_rp + t_rcd;
+
+	mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_DDRTIMING,
+		bw_ratio << DDRTIMING_BWRATIO_OFST |
+		wr_to_rd << DDRTIMING_WRTORD_OFST|
+		rd_to_wr << DDRTIMING_RDTOWR_OFST |
+		burst_len_sched_clk << DDRTIMING_BURSTLEN_OFST |
+		wr_to_miss << DDRTIMING_WRTOMISS_OFST |
+		rd_to_miss << DDRTIMING_RDTOMISS_OFST |
+		act_to_act << DDRTIMING_ACTTOACT_OFST);
+
+	data = mmio_read_32(AGX_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL));
+	bw_ratio_extended = ((ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 1 : 0);
+
+	mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_DDRMODE,
+		bw_ratio_extended << DDRMODE_BWRATIOEXTENDED_OFST |
+		auto_precharge << DDRMODE_AUTOPRECHARGE_OFST);
+
+	mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_READLATENCY,
+		(rd_latency / 2) + DDR_READ_LATENCY_DELAY);
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING9);
+	faw = AGX_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(data);
+
+	faw_bank = 1; // always 1 because we always have 4 bank DDR.
+
+	mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE,
+		faw_bank << AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST |
+		faw << AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST |
+		act_to_act_bank << AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST);
+
+	mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV,
+		((bus_rd_to_rd
+			<< AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST)
+			& AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK) |
+		((bus_rd_to_wr
+			<< AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST)
+			& AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK) |
+		((bus_wr_to_rd
+			<< AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST)
+			& AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK));
+
+}
+
+unsigned long get_physical_dram_size(void)
+{
+	uint32_t data;
+	unsigned long ram_addr_width, ram_ext_if_io_width;
+
+	data = mmio_read_32(AGX_MPFE_HMC_ADP_DDRIOCTRL);
+	switch (AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(data)) {
+	case 0:
+		ram_ext_if_io_width = 16;
+		break;
+	case 1:
+		ram_ext_if_io_width = 32;
+		break;
+	case 2:
+		ram_ext_if_io_width = 64;
+		break;
+	default:
+		ram_ext_if_io_width = 0;
+		break;
+	}
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_REG_DRAMADDRW);
+	ram_addr_width = IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(data);
+
+	return (1 << ram_addr_width) * (ram_ext_if_io_width / 8);
+}
+
+
+
+void configure_hmc_adaptor_regs(void)
+{
+	uint32_t data;
+	uint32_t dram_io_width;
+
+	/* Configure DDR data rate */
+	dram_io_width = AGX_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0(
+		mmio_read_32(AGX_MPFE_IOHMC_REG_NIOSRESERVE0_OFST));
+	dram_io_width = (dram_io_width & 0xFF) >> 5;
+
+	data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG3);
+
+	dram_io_width |= (data & 0x4);
+
+	mmio_write_32(AGX_MPFE_HMC_ADP_DDRIOCTRL, dram_io_width);
+
+	/* Copy dram addr width from IOHMC to HMC ADP */
+	data = mmio_read_32(AGX_MPFE_IOHMC_DRAMADDRW);
+	mmio_write_32(AGX_MPFE_HMC_ADP(ADP_DRAMADDRWIDTH), data);
+
+	/* Enable nonsecure access to DDR */
+	mmio_write_32(AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT,
+			AGX_DDR_SIZE - 1);
+	mmio_write_32(AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT,
+			0x1f);
+
+	mmio_write_32(AGX_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT,
+			AGX_DDR_SIZE - 1);
+
+	mmio_write_32(AGX_SOC_NOC_FW_DDR_SCR_ENABLESET, BIT(0) | BIT(8));
+
+
+	/* ECC enablement */
+	data = mmio_read_32(AGX_MPFE_IOHMC_REG_CTRLCFG1);
+	if (data & (1 << AGX_IOHMC_CTRLCFG1_ENABLE_ECC_OFST)) {
+		mmio_clrsetbits_32(AGX_MPFE_HMC_ADP_ECCCTRL1,
+			AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK,
+			AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK);
+
+		mmio_clrsetbits_32(AGX_MPFE_HMC_ADP_ECCCTRL2,
+			AGX_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK,
+			AGX_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK);
+
+		mmio_clrsetbits_32(AGX_MPFE_HMC_ADP_ECCCTRL1,
+			AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK |
+			AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK,
+			AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK);
+		INFO("Scrubbing ECC\n");
+
+		/* ECC Scrubbing */
+		zeromem(DRAM_BASE, DRAM_SIZE);
+	} else {
+		INFO("ECC is disabled.\n");
+	}
+}
diff --git a/plat/intel/soc/agilex/soc/agilex_pinmux.c b/plat/intel/soc/agilex/soc/agilex_pinmux.c
new file mode 100644
index 0000000..eff1947
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_pinmux.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "agilex_pinmux.h"
+
+const uint32_t sysmgr_pinmux_array_sel[] = {
+	0x00000000, 0x00000001, /* usb */
+	0x00000004, 0x00000001,
+	0x00000008, 0x00000001,
+	0x0000000c, 0x00000001,
+	0x00000010, 0x00000001,
+	0x00000014, 0x00000001,
+	0x00000018, 0x00000001,
+	0x0000001c, 0x00000001,
+	0x00000020, 0x00000001,
+	0x00000024, 0x00000001,
+	0x00000028, 0x00000001,
+	0x0000002c, 0x00000001,
+	0x00000030, 0x00000000, /* emac0 */
+	0x00000034, 0x00000000,
+	0x00000038, 0x00000000,
+	0x0000003c, 0x00000000,
+	0x00000040, 0x00000000,
+	0x00000044, 0x00000000,
+	0x00000048, 0x00000000,
+	0x0000004c, 0x00000000,
+	0x00000050, 0x00000000,
+	0x00000054, 0x00000000,
+	0x00000058, 0x00000000,
+	0x0000005c, 0x00000000,
+	0x00000060, 0x00000008, /* gpio1 */
+	0x00000064, 0x00000008,
+	0x00000068, 0x00000005,  /* uart0 tx */
+	0x0000006c, 0x00000005,  /*  uart 0 rx */
+	0x00000070, 0x00000008,  /*  gpio */
+	0x00000074, 0x00000008,
+	0x00000078, 0x00000004, /* i2c1 */
+	0x0000007c, 0x00000004,
+	0x00000080, 0x00000007,  /* jtag */
+	0x00000084, 0x00000007,
+	0x00000088, 0x00000007,
+	0x0000008c, 0x00000007,
+	0x00000090, 0x00000001,  /* sdmmc data0 */
+	0x00000094, 0x00000001,
+	0x00000098, 0x00000001,
+	0x0000009c, 0x00000001,
+	0x00000100, 0x00000001,
+	0x00000104, 0x00000001,  /* sdmmc.data3 */
+	0x00000108, 0x00000008,  /* loan */
+	0x0000010c, 0x00000008,   /* gpio */
+	0x00000110, 0x00000008,
+	0x00000114, 0x00000008,  /* gpio1.io21 */
+	0x00000118, 0x00000005,  /* mdio0.mdio */
+	0x0000011c, 0x00000005  /* mdio0.mdc */
+};
+
+const uint32_t sysmgr_pinmux_array_ctrl[] = {
+	0x00000000, 0x00502c38, /* Q1_1 */
+	0x00000004, 0x00102c38,
+	0x00000008, 0x00502c38,
+	0x0000000c, 0x00502c38,
+	0x00000010, 0x00502c38,
+	0x00000014, 0x00502c38,
+	0x00000018, 0x00502c38,
+	0x0000001c, 0x00502c38,
+	0x00000020, 0x00502c38,
+	0x00000024, 0x00502c38,
+	0x00000028, 0x00502c38,
+	0x0000002c, 0x00502c38,
+	0x00000030, 0x00102c38, /* Q2_1 */
+	0x00000034, 0x00102c38,
+	0x00000038, 0x00502c38,
+	0x0000003c, 0x00502c38,
+	0x00000040, 0x00102c38,
+	0x00000044, 0x00102c38,
+	0x00000048, 0x00502c38,
+	0x0000004c, 0x00502c38,
+	0x00000050, 0x00102c38,
+	0x00000054, 0x00102c38,
+	0x00000058, 0x00502c38,
+	0x0000005c, 0x00502c38,
+	0x00000060, 0x00502c38, /* Q3_1 */
+	0x00000064, 0x00502c38,
+	0x00000068, 0x00102c38,
+	0x0000006c, 0x00502c38,
+	0x000000d0, 0x00502c38,
+	0x000000d4, 0x00502c38,
+	0x000000d8, 0x00542c38,
+	0x000000dc, 0x00542c38,
+	0x000000e0, 0x00502c38,
+	0x000000e4, 0x00502c38,
+	0x000000e8, 0x00102c38,
+	0x000000ec, 0x00502c38,
+	0x000000f0, 0x00502c38, /* Q4_1 */
+	0x000000f4, 0x00502c38,
+	0x000000f8, 0x00102c38,
+	0x000000fc, 0x00502c38,
+	0x00000100, 0x00502c38,
+	0x00000104, 0x00502c38,
+	0x00000108, 0x00102c38,
+	0x0000010c, 0x00502c38,
+	0x00000110, 0x00502c38,
+	0x00000114, 0x00502c38,
+	0x00000118, 0x00542c38,
+	0x0000011c, 0x00102c38
+};
+
+const uint32_t sysmgr_pinmux_array_fpga[] = {
+	0x00000000, 0x00000000,
+	0x00000004, 0x00000000,
+	0x00000008, 0x00000000,
+	0x0000000c, 0x00000000,
+	0x00000010, 0x00000000,
+	0x00000014, 0x00000000,
+	0x00000018, 0x00000000,
+	0x0000001c, 0x00000000,
+	0x00000020, 0x00000000,
+	0x00000028, 0x00000000,
+	0x0000002c, 0x00000000,
+	0x00000030, 0x00000000,
+	0x00000034, 0x00000000,
+	0x00000038, 0x00000000,
+	0x0000003c, 0x00000000,
+	0x00000040, 0x00000000,
+	0x00000044, 0x00000000,
+	0x00000048, 0x00000000,
+	0x00000050, 0x00000000,
+	0x00000054, 0x00000000,
+	0x00000058, 0x0000002a
+};
+
+const uint32_t sysmgr_pinmux_array_iodelay[] = {
+	0x00000000, 0x00000000,
+	0x00000004, 0x00000000,
+	0x00000008, 0x00000000,
+	0x0000000c, 0x00000000,
+	0x00000010, 0x00000000,
+	0x00000014, 0x00000000,
+	0x00000018, 0x00000000,
+	0x0000001c, 0x00000000,
+	0x00000020, 0x00000000,
+	0x00000024, 0x00000000,
+	0x00000028, 0x00000000,
+	0x0000002c, 0x00000000,
+	0x00000030, 0x00000000,
+	0x00000034, 0x00000000,
+	0x00000038, 0x00000000,
+	0x0000003c, 0x00000000,
+	0x00000040, 0x00000000,
+	0x00000044, 0x00000000,
+	0x00000048, 0x00000000,
+	0x0000004c, 0x00000000,
+	0x00000050, 0x00000000,
+	0x00000054, 0x00000000,
+	0x00000058, 0x00000000,
+	0x0000005c, 0x00000000,
+	0x00000060, 0x00000000,
+	0x00000064, 0x00000000,
+	0x00000068, 0x00000000,
+	0x0000006c, 0x00000000,
+	0x00000070, 0x00000000,
+	0x00000074, 0x00000000,
+	0x00000078, 0x00000000,
+	0x0000007c, 0x00000000,
+	0x00000080, 0x00000000,
+	0x00000084, 0x00000000,
+	0x00000088, 0x00000000,
+	0x0000008c, 0x00000000,
+	0x00000090, 0x00000000,
+	0x00000094, 0x00000000,
+	0x00000098, 0x00000000,
+	0x0000009c, 0x00000000,
+	0x00000100, 0x00000000,
+	0x00000104, 0x00000000,
+	0x00000108, 0x00000000,
+	0x0000010c, 0x00000000,
+	0x00000110, 0x00000000,
+	0x00000114, 0x00000000,
+	0x00000118, 0x00000000,
+	0x0000011c, 0x00000000
+};
+
+void config_pinmux(handoff *hoff_ptr)
+{
+	unsigned int i;
+
+	for (i = 0; i < 96; i += 2) {
+		mmio_write_32(AGX_PINMUX_PIN0SEL +
+			hoff_ptr->pinmux_sel_array[i],
+			hoff_ptr->pinmux_sel_array[i+1]);
+	}
+
+	for (i = 0; i < 96; i += 2) {
+		mmio_write_32(AGX_PINMUX_IO0CTRL +
+			hoff_ptr->pinmux_io_array[i],
+			hoff_ptr->pinmux_io_array[i+1]);
+	}
+
+	for (i = 0; i < 42; i += 2) {
+		mmio_write_32(AGX_PINMUX_PINMUX_EMAC0_USEFPGA +
+			hoff_ptr->pinmux_fpga_array[i],
+			hoff_ptr->pinmux_fpga_array[i+1]);
+	}
+
+	for (i = 0; i < 96; i += 2) {
+		mmio_write_32(AGX_PINMUX_IO0_DELAY +
+			hoff_ptr->pinmux_iodelay_array[i],
+			hoff_ptr->pinmux_iodelay_array[i+1]);
+	}
+
+}
+
diff --git a/plat/intel/soc/agilex/soc/agilex_reset_manager.c b/plat/intel/soc/agilex/soc/agilex_reset_manager.c
new file mode 100644
index 0000000..65d2029
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_reset_manager.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "agilex_reset_manager.h"
+
+void deassert_peripheral_reset(void)
+{
+	mmio_clrbits_32(AGX_RSTMGR_PER1MODRST,
+			AGX_RSTMGR_PER1MODRST_WATCHDOG0 |
+			AGX_RSTMGR_PER1MODRST_WATCHDOG1 |
+			AGX_RSTMGR_PER1MODRST_WATCHDOG2 |
+			AGX_RSTMGR_PER1MODRST_WATCHDOG3 |
+			AGX_RSTMGR_PER1MODRST_L4SYSTIMER0 |
+			AGX_RSTMGR_PER1MODRST_L4SYSTIMER1 |
+			AGX_RSTMGR_PER1MODRST_SPTIMER0 |
+			AGX_RSTMGR_PER1MODRST_SPTIMER1 |
+			AGX_RSTMGR_PER1MODRST_I2C0 |
+			AGX_RSTMGR_PER1MODRST_I2C1 |
+			AGX_RSTMGR_PER1MODRST_I2C2 |
+			AGX_RSTMGR_PER1MODRST_I2C3 |
+			AGX_RSTMGR_PER1MODRST_I2C4 |
+			AGX_RSTMGR_PER1MODRST_UART0 |
+			AGX_RSTMGR_PER1MODRST_UART1 |
+			AGX_RSTMGR_PER1MODRST_GPIO0 |
+			AGX_RSTMGR_PER1MODRST_GPIO1);
+
+	mmio_clrbits_32(AGX_RSTMGR_PER0MODRST,
+			AGX_RSTMGR_PER0MODRST_EMAC0OCP |
+			AGX_RSTMGR_PER0MODRST_EMAC1OCP |
+			AGX_RSTMGR_PER0MODRST_EMAC2OCP |
+			AGX_RSTMGR_PER0MODRST_USB0OCP |
+			AGX_RSTMGR_PER0MODRST_USB1OCP |
+			AGX_RSTMGR_PER0MODRST_NANDOCP |
+			AGX_RSTMGR_PER0MODRST_SDMMCOCP |
+			AGX_RSTMGR_PER0MODRST_DMAOCP);
+
+	mmio_clrbits_32(AGX_RSTMGR_PER0MODRST,
+			AGX_RSTMGR_PER0MODRST_EMAC0 |
+			AGX_RSTMGR_PER0MODRST_EMAC1 |
+			AGX_RSTMGR_PER0MODRST_EMAC2 |
+			AGX_RSTMGR_PER0MODRST_USB0 |
+			AGX_RSTMGR_PER0MODRST_USB1 |
+			AGX_RSTMGR_PER0MODRST_NAND |
+			AGX_RSTMGR_PER0MODRST_SDMMC |
+			AGX_RSTMGR_PER0MODRST_DMA |
+			AGX_RSTMGR_PER0MODRST_SPIM0 |
+			AGX_RSTMGR_PER0MODRST_SPIM1 |
+			AGX_RSTMGR_PER0MODRST_SPIS0 |
+			AGX_RSTMGR_PER0MODRST_SPIS1 |
+			AGX_RSTMGR_PER0MODRST_EMACPTP |
+			AGX_RSTMGR_PER0MODRST_DMAIF0 |
+			AGX_RSTMGR_PER0MODRST_DMAIF1 |
+			AGX_RSTMGR_PER0MODRST_DMAIF2 |
+			AGX_RSTMGR_PER0MODRST_DMAIF3 |
+			AGX_RSTMGR_PER0MODRST_DMAIF4 |
+			AGX_RSTMGR_PER0MODRST_DMAIF5 |
+			AGX_RSTMGR_PER0MODRST_DMAIF6 |
+			AGX_RSTMGR_PER0MODRST_DMAIF7);
+
+	mmio_clrbits_32(AGX_RSTMGR_BRGMODRST,
+			AGX_RSTMGR_BRGMODRST_MPFE);
+}
+
+void config_hps_hs_before_warm_reset(void)
+{
+	uint32_t or_mask = 0;
+
+	or_mask |= AGX_RSTMGR_HDSKEN_SDRSELFREFEN;
+	or_mask |= AGX_RSTMGR_HDSKEN_FPGAHSEN;
+	or_mask |= AGX_RSTMGR_HDSKEN_ETRSTALLEN;
+	or_mask |= AGX_RSTMGR_HDSKEN_L2FLUSHEN;
+	or_mask |= AGX_RSTMGR_HDSKEN_L3NOC_DBG;
+	or_mask |= AGX_RSTMGR_HDSKEN_DEBUG_L3NOC;
+
+	mmio_setbits_32(AGX_RSTMGR_HDSKEN, or_mask);
+}
+
diff --git a/plat/intel/soc/agilex/soc/agilex_system_manager.c b/plat/intel/soc/agilex/soc/agilex_system_manager.c
new file mode 100644
index 0000000..88e895d
--- /dev/null
+++ b/plat/intel/soc/agilex/soc/agilex_system_manager.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "agilex_system_manager.h"
+
+void enable_nonsecure_access(void)
+{
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_NAND_REGISTER, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_NAND_DATA, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_NAND_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_NAND_READ_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC,
+		DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_USB0_REGISTER, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_USB1_REGISTER, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_USB0_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_USB1_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_MASTER0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_MASTER1, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_EMAC0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_EMAC1, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_EMAC2, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SDMMC, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_SDMMC_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_GPIO0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_GPIO1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C1, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C2, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C3, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C4, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SP_TIMER1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_UART0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_PER_SCR_UART1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_DMA_ECC, DISABLE_L4_FIREWALL);
+
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_OCRAM_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_CLK_MGR, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_IO_MGR, DISABLE_L4_FIREWALL);
+
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_RST_MGR, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_SYS_MGR, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_OSC0_TIMER, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_OSC1_TIMER, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG0, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG1, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG2, DISABLE_L4_FIREWALL);
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG3, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_DAP, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_L4_NOC_QOS, DISABLE_L4_FIREWALL);
+}
+
+void enable_ns_bridge_access(void)
+{
+	mmio_write_32(AGX_FIREWALL_SOC2FPGA, DISABLE_BRIDGE_FIREWALL);
+	mmio_write_32(AGX_FIREWALL_LWSOC2FPGA, DISABLE_BRIDGE_FIREWALL);
+}
diff --git a/plat/intel/soc/agilex/socfpga_psci.c b/plat/intel/soc/agilex/socfpga_psci.c
new file mode 100644
index 0000000..04d8a0e
--- /dev/null
+++ b/plat/intel/soc/agilex/socfpga_psci.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "agilex_reset_manager.h"
+#include "agilex_mailbox.h"
+
+#define AGX_RSTMGR_OFST			0xffd11000
+#define AGX_RSTMGR_MPUMODRST_OFST	0x20
+
+uintptr_t *agilex_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY;
+uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE;
+
+/*******************************************************************************
+ * plat handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+void socfpga_cpu_standby(plat_local_state_t cpu_state)
+{
+	/*
+	 * Enter standby state
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
+	dsb();
+	wfi();
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+int socfpga_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+	if (cpu_id == -1)
+		return PSCI_E_INTERN_FAIL;
+
+	*cpuid_release = cpu_id;
+
+	/* release core reset */
+	mmio_setbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void socfpga_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* TODO: Prevent interrupts from spuriously waking up this cpu */
+	/* gicv2_cpuif_disable(); */
+
+	/* assert core reset */
+	mmio_setbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+	/* assert core reset */
+	mmio_setbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+
+	/* Enable the gic cpu interface */
+	gicv2_cpuif_enable();
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ ******************************************************************************/
+void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* release core reset */
+	mmio_clrbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+}
+
+/*******************************************************************************
+ * plat handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 socfpga_system_off(void)
+{
+	wfi();
+	ERROR("System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 socfpga_system_reset(void)
+{
+	INFO("assert Peripheral from Reset\r\n");
+
+	deassert_peripheral_reset();
+	mailbox_reset_cold();
+
+	while (1)
+		wfi();
+}
+
+int socfpga_validate_power_state(unsigned int power_state,
+				psci_power_state_t *req_state)
+{
+	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+	return PSCI_E_SUCCESS;
+}
+
+int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint)
+{
+	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
+	return PSCI_E_SUCCESS;
+}
+
+void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+const plat_psci_ops_t socfpga_psci_pm_ops = {
+	.cpu_standby = socfpga_cpu_standby,
+	.pwr_domain_on = socfpga_pwr_domain_on,
+	.pwr_domain_off = socfpga_pwr_domain_off,
+	.pwr_domain_suspend = socfpga_pwr_domain_suspend,
+	.pwr_domain_on_finish = socfpga_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish,
+	.system_off = socfpga_system_off,
+	.system_reset = socfpga_system_reset,
+	.validate_power_state = socfpga_validate_power_state,
+	.validate_ns_entrypoint = socfpga_validate_ns_entrypoint,
+	.get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	/* Save warm boot entrypoint.*/
+	*agilex_sec_entry = sec_entrypoint;
+
+	*psci_ops = &socfpga_psci_pm_ops;
+	return 0;
+}
diff --git a/plat/intel/soc/agilex/socfpga_sip_svc.c b/plat/intel/soc/agilex/socfpga_sip_svc.c
new file mode 100644
index 0000000..6a1c957
--- /dev/null
+++ b/plat/intel/soc/agilex/socfpga_sip_svc.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "agilex_mailbox.h"
+
+/* Number of SiP Calls implemented */
+#define SIP_NUM_CALLS		0x3
+
+/* Total buffer the driver can hold */
+#define FPGA_CONFIG_BUFFER_SIZE 4
+
+int current_block;
+int current_buffer;
+int current_id = 1;
+int max_blocks;
+uint32_t bytes_per_block;
+uint32_t blocks_submitted;
+uint32_t blocks_completed;
+
+struct fpga_config_info {
+	uint32_t addr;
+	int size;
+	int size_written;
+	uint32_t write_requested;
+	int subblocks_sent;
+	int block_number;
+};
+
+/*  SiP Service UUID */
+DEFINE_SVC_UUID2(intl_svc_uid,
+		0xa85273b0, 0xe85a, 0x4862, 0xa6, 0x2a,
+		0xfa, 0x88, 0x88, 0x17, 0x68, 0x81);
+
+uint64_t socfpga_sip_handler(uint32_t smc_fid,
+				   uint64_t x1,
+				   uint64_t x2,
+				   uint64_t x3,
+				   uint64_t x4,
+				   void *cookie,
+				   void *handle,
+				   uint64_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+struct fpga_config_info fpga_config_buffers[FPGA_CONFIG_BUFFER_SIZE];
+
+static void intel_fpga_sdm_write_buffer(struct fpga_config_info *buffer)
+{
+	uint32_t args[3];
+
+	while (max_blocks > 0 && buffer->size > buffer->size_written) {
+		if (buffer->size - buffer->size_written <=
+			bytes_per_block) {
+			args[0] = (1<<8);
+			args[1] = buffer->addr + buffer->size_written;
+			args[2] = buffer->size - buffer->size_written;
+			buffer->size_written +=
+				buffer->size - buffer->size_written;
+			buffer->subblocks_sent++;
+			mailbox_send_cmd_async(0x4,
+				MBOX_RECONFIG_DATA,
+				args, 3, 0);
+			current_buffer++;
+			current_buffer %= FPGA_CONFIG_BUFFER_SIZE;
+		} else {
+			args[0] = (1<<8);
+			args[1] = buffer->addr + buffer->size_written;
+			args[2] = bytes_per_block;
+			buffer->size_written += bytes_per_block;
+			mailbox_send_cmd_async(0x4,
+				MBOX_RECONFIG_DATA,
+				args, 3, 0);
+			buffer->subblocks_sent++;
+		}
+		max_blocks--;
+	}
+}
+
+static int intel_fpga_sdm_write_all(void)
+{
+	int i;
+
+	for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++)
+		intel_fpga_sdm_write_buffer(
+			&fpga_config_buffers[current_buffer]);
+
+	return 0;
+}
+
+uint32_t intel_mailbox_fpga_config_isdone(void)
+{
+	uint32_t args[2];
+	uint32_t response[6];
+	int status;
+
+	status = mailbox_send_cmd(1, MBOX_RECONFIG_STATUS, args, 0, 0,
+				response);
+
+	if (status < 0)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if (response[RECONFIG_STATUS_STATE] &&
+		response[RECONFIG_STATUS_STATE] != MBOX_CFGSTAT_STATE_CONFIG)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if (!(response[RECONFIG_STATUS_PIN_STATUS] & PIN_STATUS_NSTATUS))
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if (response[RECONFIG_STATUS_SOFTFUNC_STATUS] &
+		SOFTFUNC_STATUS_SEU_ERROR)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if ((response[RECONFIG_STATUS_SOFTFUNC_STATUS] &
+		SOFTFUNC_STATUS_CONF_DONE) &&
+		(response[RECONFIG_STATUS_SOFTFUNC_STATUS] &
+		SOFTFUNC_STATUS_INIT_DONE))
+		return INTEL_SIP_SMC_STATUS_OK;
+
+	return INTEL_SIP_SMC_STATUS_ERROR;
+}
+
+static int mark_last_buffer_xfer_completed(uint32_t *buffer_addr_completed)
+{
+	int i;
+
+	for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		if (fpga_config_buffers[i].block_number == current_block) {
+			fpga_config_buffers[i].subblocks_sent--;
+			if (fpga_config_buffers[i].subblocks_sent == 0
+			&& fpga_config_buffers[i].size <=
+			fpga_config_buffers[i].size_written) {
+				fpga_config_buffers[i].write_requested = 0;
+				current_block++;
+				*buffer_addr_completed =
+					fpga_config_buffers[i].addr;
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+unsigned int address_in_ddr(uint32_t *addr)
+{
+	if (((unsigned long long)addr > DRAM_BASE) &&
+		((unsigned long long)addr < DRAM_BASE + DRAM_SIZE))
+		return 0;
+
+	return -1;
+}
+
+int intel_fpga_config_completed_write(uint32_t *completed_addr,
+					uint32_t *count)
+{
+	uint32_t status = INTEL_SIP_SMC_STATUS_OK;
+	*count = 0;
+	int resp_len = 0;
+	uint32_t resp[5];
+	int all_completed = 1;
+	int count_check = 0;
+
+	if (address_in_ddr(completed_addr) != 0 || address_in_ddr(count) != 0)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	for (count_check = 0; count_check < 3; count_check++)
+		if (address_in_ddr(&completed_addr[*count + count_check]) != 0)
+			return INTEL_SIP_SMC_STATUS_ERROR;
+
+	resp_len = mailbox_read_response(0x4, resp);
+
+	while (resp_len >= 0 && *count < 3) {
+		max_blocks++;
+		if (mark_last_buffer_xfer_completed(
+			&completed_addr[*count]) == 0)
+			*count = *count + 1;
+		else
+			break;
+		resp_len = mailbox_read_response(0x4, resp);
+	}
+
+	if (*count <= 0) {
+		if (resp_len != MBOX_NO_RESPONSE &&
+			resp_len != MBOX_TIMEOUT && resp_len != 0) {
+			return INTEL_SIP_SMC_STATUS_ERROR;
+		}
+
+		*count = 0;
+	}
+
+	intel_fpga_sdm_write_all();
+
+	if (*count > 0)
+		status = INTEL_SIP_SMC_STATUS_OK;
+	else if (*count == 0)
+		status = INTEL_SIP_SMC_STATUS_BUSY;
+
+	for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		if (fpga_config_buffers[i].write_requested != 0) {
+			all_completed = 0;
+			break;
+		}
+	}
+
+	if (all_completed == 1)
+		return INTEL_SIP_SMC_STATUS_OK;
+
+	return status;
+}
+
+int intel_fpga_config_start(uint32_t config_type)
+{
+	uint32_t response[3];
+	int status = 0;
+
+	status = mailbox_send_cmd(2, MBOX_RECONFIG, 0, 0, 0,
+			response);
+
+	if (status < 0)
+		return status;
+
+	max_blocks = response[0];
+	bytes_per_block = response[1];
+
+	for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		fpga_config_buffers[i].size = 0;
+		fpga_config_buffers[i].size_written = 0;
+		fpga_config_buffers[i].addr = 0;
+		fpga_config_buffers[i].write_requested = 0;
+		fpga_config_buffers[i].block_number = 0;
+		fpga_config_buffers[i].subblocks_sent = 0;
+	}
+
+	blocks_submitted = 0;
+	current_block = 0;
+	current_buffer = 0;
+
+	return 0;
+}
+
+
+uint32_t intel_fpga_config_write(uint64_t mem, uint64_t size)
+{
+	int i = 0;
+	uint32_t status = INTEL_SIP_SMC_STATUS_OK;
+
+	if (mem < DRAM_BASE || mem > DRAM_BASE + DRAM_SIZE)
+		status = INTEL_SIP_SMC_STATUS_REJECTED;
+
+	if (mem + size > DRAM_BASE + DRAM_SIZE)
+		status = INTEL_SIP_SMC_STATUS_REJECTED;
+
+	for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		if (!fpga_config_buffers[i].write_requested) {
+			fpga_config_buffers[i].addr = mem;
+			fpga_config_buffers[i].size = size;
+			fpga_config_buffers[i].size_written = 0;
+			fpga_config_buffers[i].write_requested = 1;
+			fpga_config_buffers[i].block_number =
+				blocks_submitted++;
+			fpga_config_buffers[i].subblocks_sent = 0;
+			break;
+		}
+	}
+
+
+	if (i == FPGA_CONFIG_BUFFER_SIZE) {
+		status = INTEL_SIP_SMC_STATUS_REJECTED;
+		return status;
+	} else if (i == FPGA_CONFIG_BUFFER_SIZE - 1) {
+		status = INTEL_SIP_SMC_STATUS_BUSY;
+	}
+
+	intel_fpga_sdm_write_all();
+
+	return status;
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+
+uintptr_t sip_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	uint32_t status = INTEL_SIP_SMC_STATUS_OK;
+	uint32_t completed_addr[3];
+	uint32_t count = 0;
+
+	switch (smc_fid) {
+	case SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, intl_svc_uid);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_ISDONE:
+		status = intel_mailbox_fpga_config_isdone();
+		SMC_RET4(handle, status, 0, 0, 0);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM:
+		SMC_RET3(handle, INTEL_SIP_SMC_STATUS_OK,
+			INTEL_SIP_SMC_FPGA_CONFIG_ADDR,
+			INTEL_SIP_SMC_FPGA_CONFIG_SIZE -
+				INTEL_SIP_SMC_FPGA_CONFIG_ADDR);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_START:
+		status = intel_fpga_config_start(x1);
+		SMC_RET4(handle, status, 0, 0, 0);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_WRITE:
+		status = intel_fpga_config_write(x1, x2);
+		SMC_RET4(handle, status, 0, 0, 0);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE:
+		status = intel_fpga_config_completed_write(completed_addr,
+								&count);
+		switch (count) {
+		case 1:
+			SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+				completed_addr[0], 0, 0);
+			break;
+		case 2:
+			SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+				completed_addr[0],
+				completed_addr[1], 0);
+			break;
+		case 3:
+			SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+				completed_addr[0],
+				completed_addr[1],
+				completed_addr[2]);
+			break;
+		case 0:
+			SMC_RET4(handle, status, 0, 0, 0);
+			break;
+		default:
+			SMC_RET1(handle, INTEL_SIP_SMC_STATUS_ERROR);
+		}
+		break;
+
+	default:
+		return socfpga_sip_handler(smc_fid, x1, x2, x3, x4,
+			cookie, handle, flags);
+	}
+}
+
+DECLARE_RT_SVC(
+	agilex_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	sip_smc_handler
+);
+
+DECLARE_RT_SVC(
+	agilex_sip_svc_std,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_YIELD,
+	NULL,
+	sip_smc_handler
+);
diff --git a/plat/intel/soc/agilex/socfpga_storage.c b/plat/intel/soc/agilex/socfpga_storage.c
new file mode 100644
index 0000000..76dd81f
--- /dev/null
+++ b/plat/intel/soc/agilex/socfpga_storage.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/mmc.h>
+#include <drivers/partition/partition.h>
+#include <lib/mmio.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "agilex_private.h"
+
+#define PLAT_FIP_BASE		(0)
+#define PLAT_FIP_MAX_SIZE	(0x1000000)
+#define PLAT_MMC_DATA_BASE	(0xffe3c000)
+#define PLAT_MMC_DATA_SIZE	(0x2000)
+#define PLAT_QSPI_DATA_BASE	(0x3C00000)
+#define PLAT_QSPI_DATA_SIZE	(0x1000000)
+
+
+static const io_dev_connector_t *fip_dev_con;
+static const io_dev_connector_t *boot_dev_con;
+
+static uintptr_t fip_dev_handle;
+static uintptr_t boot_dev_handle;
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+uintptr_t a2_lba_offset;
+const char a2[] = {0xa2, 0x0};
+
+static const io_block_spec_t gpt_block_spec = {
+	.offset = 0,
+	.length = MMC_BLOCK_SIZE
+};
+
+static int check_fip(const uintptr_t spec);
+static int check_dev(const uintptr_t spec);
+
+static io_block_dev_spec_t boot_dev_spec;
+static int (*register_io_dev)(const io_dev_connector_t **);
+
+static io_block_spec_t fip_spec = {
+	.offset		= PLAT_FIP_BASE,
+	.length		= PLAT_FIP_MAX_SIZE,
+};
+
+struct plat_io_policy {
+	uintptr_t       *dev_handle;
+	uintptr_t       image_spec;
+	int             (*check)(const uintptr_t spec);
+};
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&boot_dev_handle,
+		(uintptr_t)&fip_spec,
+		check_dev
+	},
+	[BL2_IMAGE_ID] = {
+	  &fip_dev_handle,
+	  (uintptr_t)&bl2_uuid_spec,
+	  check_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		check_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t) &bl33_uuid_spec,
+		check_fip
+	},
+	[GPT_IMAGE_ID] = {
+		&boot_dev_handle,
+		(uintptr_t) &gpt_block_spec,
+		check_dev
+	},
+};
+
+static int check_dev(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(boot_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(boot_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0)
+			io_close(local_image_handle);
+	}
+	return result;
+}
+
+void socfpga_io_setup(int boot_source)
+{
+	int result;
+
+	switch (boot_source) {
+	case BOOT_SOURCE_SDMMC:
+		register_io_dev = &register_io_dev_block;
+		boot_dev_spec.buffer.offset	= PLAT_MMC_DATA_BASE;
+		boot_dev_spec.buffer.length	= MMC_BLOCK_SIZE;
+		boot_dev_spec.ops.read		= mmc_read_blocks;
+		boot_dev_spec.ops.write		= mmc_write_blocks;
+		boot_dev_spec.block_size	= MMC_BLOCK_SIZE;
+		break;
+
+	case BOOT_SOURCE_QSPI:
+		register_io_dev = &register_io_dev_memmap;
+		fip_spec.offset = fip_spec.offset + PLAT_QSPI_DATA_BASE;
+		break;
+
+	default:
+		ERROR("Unsupported boot source\n");
+		panic();
+		break;
+	}
+
+	result = (*register_io_dev)(&boot_dev_con);
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(boot_dev_con, (uintptr_t)&boot_dev_spec,
+			&boot_dev_handle);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+	assert(result == 0);
+
+	if (boot_source == BOOT_SOURCE_SDMMC) {
+		partition_init(GPT_IMAGE_ID);
+		fip_spec.offset = get_partition_entry(a2)->start;
+	}
+
+	(void)result;
+}
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
diff --git a/plat/intel/soc/common/aarch64/plat_helpers.S b/plat/intel/soc/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..00fe2d9
--- /dev/null
+++ b/plat/intel/soc/common/aarch64/plat_helpers.S
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	platform_is_primary_cpu
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl  plat_crash_console_flush
+	.globl	platform_mem_init
+
+	.globl plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Wait until the it gets reset signal from rstmgr gets populated */
+poll_mailbox:
+	wfi
+
+	mov_imm	x0, PLAT_SEC_ENTRY
+	ldr	x1, [x0]
+	mov_imm	x2, PLAT_CPUID_RELEASE
+	ldr	x3, [x2]
+	mrs	x4, mpidr_el1
+	and	x4, x4, #0xff
+	cmp	x3, x4
+	b.ne	poll_mailbox
+	br	x1
+endfunc plat_secondary_cold_boot_setup
+
+func platform_is_primary_cpu
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #PLAT_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc platform_is_primary_cpu
+
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	b   platform_is_primary_cpu
+endfunc plat_is_my_cpu_primary
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+func plat_get_my_entrypoint
+	mov_imm	x1, PLAT_SEC_ENTRY
+	ldr	x0, [x1]
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, PLAT_UART0_BASE
+	mov_imm	x1, PLAT_UART_CLOCK
+	mov_imm	x2, PLAT_BAUDRATE
+	b	console_16550_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(void)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm x1, PLAT_UART0_BASE
+	b	console_16550_core_putc
+endfunc plat_crash_console_putc
+
+func plat_crash_console_flush
+	mov_imm x0, CRASH_CONSOLE_BASE
+	b	console_16550_core_flush
+endfunc plat_crash_console_flush
+
+
+	/* --------------------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * Any memory init, relocation to be done before the
+	 * platform boots. Called very early in the boot process.
+	 * --------------------------------------------------------
+	 */
+func platform_mem_init
+	mov	x0, #0
+	ret
+endfunc platform_mem_init
diff --git a/plat/intel/soc/common/aarch64/platform_common.c b/plat/intel/soc/common/aarch64/platform_common.c
new file mode 100644
index 0000000..6d3d817
--- /dev/null
+++ b/plat/intel/soc/common/aarch64/platform_common.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+#include <socfpga_private.h>
+
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return PLAT_SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+unsigned long socfpga_get_ns_image_entrypoint(void)
+{
+	return PLAT_NS_IMAGE_OFFSET;
+}
+
+/******************************************************************************
+ * Gets SPSR for BL32 entry
+ *****************************************************************************/
+uint32_t socfpga_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/******************************************************************************
+ * Gets SPSR for BL33 entry
+ *****************************************************************************/
+uint32_t socfpga_get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
diff --git a/plat/intel/soc/common/bl2_plat_mem_params_desc.c b/plat/intel/soc/common/bl2_plat_mem_params_desc.c
new file mode 100644
index 0000000..4f75665
--- /dev/null
+++ b/plat/intel/soc/common/bl2_plat_mem_params_desc.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+	{
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+#endif /* SCP_BL2_BASE */
+
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+	{
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = EL3_PAYLOAD_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t,
+		    IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+	{
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL31_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL31_BASE,
+	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+	},
+#endif /* EL3_PAYLOAD_BASE */
+
+	{
+		.image_id = BL33_IMAGE_ID,
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+			VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+		.ep_info.pc = PLAT_NS_IMAGE_OFFSET,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+			VERSION_2, image_info_t, 0),
+		.image_info.image_base = PLAT_NS_IMAGE_OFFSET,
+		.image_info.image_max_size =
+			0x0 + 0x40000000 - PLAT_NS_IMAGE_OFFSET,
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/intel/soc/common/drivers/ccu/ncore_ccu.c b/plat/intel/soc/common/drivers/ccu/ncore_ccu.c
new file mode 100644
index 0000000..ac8218e
--- /dev/null
+++ b/plat/intel/soc/common/drivers/ccu/ncore_ccu.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <lib/mmio.h>
+
+#include "ncore_ccu.h"
+#include <platform_def.h>
+
+uint32_t poll_active_bit(uint32_t dir);
+
+static coh_ss_id_t subsystem_id;
+
+
+void get_subsystem_id(void)
+{
+	uint32_t snoop_filter, directory, coh_agent;
+
+	snoop_filter = CSIDR_NUM_SF(mmio_read_32(NCORE_CCU_CSR(NCORE_CSIDR)));
+	directory = CSUIDR_NUM_DIR(mmio_read_32(NCORE_CCU_CSR(NCORE_CSUIDR)));
+	coh_agent = CSUIDR_NUM_CAI(mmio_read_32(NCORE_CCU_CSR(NCORE_CSUIDR)));
+
+	subsystem_id.num_snoop_filter = snoop_filter + 1;
+	subsystem_id.num_directory = directory;
+	subsystem_id.num_coh_agent = coh_agent;
+}
+
+uint32_t directory_init(void)
+{
+	uint32_t dir_sf_mtn, dir_sf_en;
+	uint32_t dir, sf, ret;
+
+	for (dir = 0; dir < subsystem_id.num_directory; dir++) {
+
+		dir_sf_mtn = DIRECTORY_UNIT(dir, NCORE_DIRUSFMCR);
+		dir_sf_en = DIRECTORY_UNIT(dir, NCORE_DIRUSFER);
+
+		for (sf = 0; sf < subsystem_id.num_snoop_filter; sf++) {
+
+			/* Initialize All Entries */
+			mmio_write_32(dir_sf_mtn, SNOOP_FILTER_ID(sf));
+
+			/* Poll Active Bit */
+			ret = poll_active_bit(dir);
+			if (ret != 0) {
+				ERROR("Timeout during active bit polling");
+				return -ETIMEDOUT;
+			}
+
+			/* Snoope Filter Enable */
+			mmio_write_32(dir_sf_en, BIT(sf));
+		}
+	}
+
+	return 0;
+}
+
+uint32_t coherent_agent_intfc_init(void)
+{
+	uint32_t dir, ca, ca_id, ca_type, ca_snoop_en;
+
+	for (dir = 0; dir < subsystem_id.num_directory; dir++) {
+
+		ca_snoop_en = DIRECTORY_UNIT(dir, NCORE_DIRUCASER0);
+
+		for (ca = 0; ca < subsystem_id.num_coh_agent; ca++) {
+
+			ca_id = mmio_read_32(COH_AGENT_UNIT(ca, NCORE_CAIUIDR));
+
+			/* Coh Agent Snoop Enable */
+			if (CACHING_AGENT_BIT(ca_id))
+				mmio_write_32(ca_snoop_en, BIT(ca));
+
+			/* Coh Agent Snoop DVM Enable */
+			ca_type = CACHING_AGENT_TYPE(ca_id);
+			if (ca_type == ACE_W_DVM || ca_type == ACE_L_W_DVM)
+				mmio_write_32(NCORE_CCU_CSR(NCORE_CSADSER0),
+				BIT(ca));
+		}
+	}
+
+	return 0;
+}
+
+uint32_t poll_active_bit(uint32_t dir)
+{
+	uint32_t timeout = 80000;
+	uint32_t poll_dir =  DIRECTORY_UNIT(dir, NCORE_DIRUSFMAR);
+
+	while (timeout > 0) {
+		if (mmio_read_32(poll_dir) == 0)
+			return 0;
+		timeout--;
+	}
+
+	return -1;
+}
+
+void bypass_ocram_firewall(void)
+{
+	mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF1),
+			OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+	mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF2),
+			OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+	mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF3),
+			OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+	mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF4),
+			OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
+}
+
+uint32_t init_ncore_ccu(void)
+{
+	uint32_t status;
+
+	get_subsystem_id();
+	status = directory_init();
+	status = coherent_agent_intfc_init();
+	bypass_ocram_firewall();
+
+	return status;
+}
diff --git a/plat/intel/soc/common/drivers/ccu/ncore_ccu.h b/plat/intel/soc/common/drivers/ccu/ncore_ccu.h
new file mode 100644
index 0000000..d25ecac
--- /dev/null
+++ b/plat/intel/soc/common/drivers/ccu/ncore_ccu.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NCORE_CCU_H
+#define NCORE_CCU_H
+
+
+#define NCORE_CCU_OFFSET		0xf7000000
+
+
+/* Coherent Sub-System Address Map */
+#define NCORE_CAIU_OFFSET		0x00000
+#define NCORE_CAIU_SIZE			0x01000
+
+#define NCORE_NCBU_OFFSET		0x60000
+#define NCORE_NCBU_SIZE			0x01000
+
+#define NCORE_DIRU_OFFSET		0x80000
+#define NCORE_DIRU_SIZE			0x01000
+
+#define NCORE_CMIU_OFFSET		0xc0000
+#define NCORE_CMIU_SIZE			0x01000
+
+#define NCORE_CSR_OFFSET		0xff000
+#define NCORE_CSADSERO			0x00040
+#define NCORE_CSUIDR			0x00ff8
+#define NCORE_CSIDR			0x00ffc
+
+/* Directory Unit Register Map */
+#define NCORE_DIRUSFER			0x00010
+#define NCORE_DIRUMRHER			0x00070
+#define NCORE_DIRUSFMCR			0x00080
+#define NCORE_DIRUSFMAR			0x00084
+
+/* Coherent Agent Interface Unit Register Map */
+#define NCORE_CAIUIDR			0x00ffc
+
+/* Snoop Enable Register */
+#define NCORE_DIRUCASER0		0x00040
+#define NCORE_DIRUCASER1		0x00044
+#define NCORE_DIRUCASER2		0x00048
+#define NCORE_DIRUCASER3		0x0004c
+
+#define NCORE_CSADSER0			0x00040
+#define NCORE_CSADSER1			0x00044
+#define NCORE_CSADSER2			0x00048
+#define NCORE_CSADSER3			0x0004c
+
+/* Protocols Definition */
+#define ACE_W_DVM			0
+#define ACE_L_W_DVM			1
+#define ACE_WO_DVM			2
+#define ACE_L_WO_DVM			3
+
+/* Bypass OC Ram Firewall */
+#define NCORE_FW_OCRAM_BLK_BASE		0x100200
+#define NCORE_FW_OCRAM_BLK_CGF1		0x04
+#define NCORE_FW_OCRAM_BLK_CGF2		0x08
+#define NCORE_FW_OCRAM_BLK_CGF3		0x0c
+#define NCORE_FW_OCRAM_BLK_CGF4		0x10
+
+#define OCRAM_PRIVILEGED_MASK		BIT(29)
+#define OCRAM_SECURE_MASK		BIT(30)
+
+/* Macros */
+#define NCORE_CCU_REG(base)		(NCORE_CCU_OFFSET + (base))
+#define NCORE_CCU_CSR(reg)		(NCORE_CCU_REG(NCORE_CSR_OFFSET)\
+						+ (reg))
+#define NCORE_CCU_DIR(reg)		(NCORE_CCU_REG(NCORE_DIRU_OFFSET)\
+						+ (reg))
+#define NCORE_CCU_CAI(reg)		(NCORE_CCU_REG(NCORE_CAIU_OFFSET)\
+						+ (reg))
+
+#define DIRECTORY_UNIT(x, reg)		(NCORE_CCU_DIR(reg)\
+						+ NCORE_DIRU_SIZE * (x))
+#define COH_AGENT_UNIT(x, reg)		(NCORE_CCU_CAI(reg)\
+						+ NCORE_CAIU_SIZE * (x))
+
+#define COH_CPU0_BYPASS_REG(reg)	(NCORE_CCU_REG(NCORE_FW_OCRAM_BLK_BASE)\
+						+ (reg))
+
+#define CSUIDR_NUM_CMI(x)		(((x) & 0x3f000000) >> 24)
+#define CSUIDR_NUM_DIR(x)		(((x) & 0x003f0000) >> 16)
+#define CSUIDR_NUM_NCB(x)		(((x) & 0x00003f00) >> 8)
+#define CSUIDR_NUM_CAI(x)		(((x) & 0x0000007f) >> 0)
+
+#define CSIDR_NUM_SF(x)			(((x) & 0x007c0000) >> 18)
+
+#define SNOOP_FILTER_ID(x)		(((x) << 16))
+
+#define CACHING_AGENT_BIT(x)		(((x) & 0x08000) >> 15)
+#define CACHING_AGENT_TYPE(x)		(((x) & 0xf0000) >> 16)
+
+
+typedef struct coh_ss_id {
+	uint8_t num_coh_mem;
+	uint8_t num_directory;
+	uint8_t num_non_coh_bridge;
+	uint8_t num_coh_agent;
+	uint8_t num_snoop_filter;
+} coh_ss_id_t;
+
+uint32_t init_ncore_ccu(void);
+
+#endif
diff --git a/plat/intel/soc/common/drivers/qspi/cadence_qspi.c b/plat/intel/soc/common/drivers/qspi/cadence_qspi.c
new file mode 100644
index 0000000..0fd11ec
--- /dev/null
+++ b/plat/intel/soc/common/drivers/qspi/cadence_qspi.c
@@ -0,0 +1,828 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <string.h>
+#include <drivers/delay_timer.h>
+#include <drivers/console.h>
+
+#include "cadence_qspi.h"
+#include <platform_def.h>
+
+#define LESS(a, b)   (((a) < (b)) ? (a) : (b))
+#define MORE(a, b)   (((a) > (b)) ? (a) : (b))
+
+
+uint32_t qspi_device_size;
+int cad_qspi_cs;
+
+int cad_qspi_idle(void)
+{
+	return (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG)
+			& CAD_QSPI_CFG_IDLE) >> 31;
+}
+
+int cad_qspi_set_baudrate_div(uint32_t div)
+{
+	if (div > 0xf)
+		return CAD_INVALID;
+
+	mmio_clrsetbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG,
+			~CAD_QSPI_CFG_BAUDDIV_MSK,
+			CAD_QSPI_CFG_BAUDDIV(div));
+
+	return 0;
+}
+
+int cad_qspi_configure_dev_size(uint32_t addr_bytes,
+		uint32_t bytes_per_dev, uint32_t bytes_per_block)
+{
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVSZ,
+			CAD_QSPI_DEVSZ_ADDR_BYTES(addr_bytes) |
+			CAD_QSPI_DEVSZ_BYTES_PER_PAGE(bytes_per_dev) |
+			CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(bytes_per_block));
+	return 0;
+}
+
+int cad_qspi_set_read_config(uint32_t opcode, uint32_t instr_type,
+		uint32_t addr_type, uint32_t data_type,
+		uint32_t mode_bit, uint32_t dummy_clk_cycle)
+{
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVRD,
+			CAD_QSPI_DEV_OPCODE(opcode) |
+			CAD_QSPI_DEV_INST_TYPE(instr_type) |
+			CAD_QSPI_DEV_ADDR_TYPE(addr_type) |
+			CAD_QSPI_DEV_DATA_TYPE(data_type) |
+			CAD_QSPI_DEV_MODE_BIT(mode_bit) |
+			CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle));
+
+	return 0;
+}
+
+int cad_qspi_set_write_config(uint32_t opcode, uint32_t addr_type,
+		uint32_t data_type, uint32_t dummy_clk_cycle)
+{
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVWR,
+			CAD_QSPI_DEV_OPCODE(opcode) |
+			CAD_QSPI_DEV_ADDR_TYPE(addr_type) |
+			CAD_QSPI_DEV_DATA_TYPE(data_type) |
+			CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle));
+
+	return 0;
+}
+
+int cad_qspi_timing_config(uint32_t clkphase, uint32_t clkpol, uint32_t csda,
+		uint32_t csdads, uint32_t cseot, uint32_t cssot,
+		uint32_t rddatacap)
+{
+	uint32_t cfg = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG);
+
+	cfg &= CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK &
+		CAD_QSPI_CFG_SELCLKPOL_CLR_MSK;
+	cfg |= CAD_QSPI_SELCLKPHASE(clkphase) | CAD_QSPI_SELCLKPOL(clkpol);
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, cfg);
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DELAY,
+		CAD_QSPI_DELAY_CSSOT(cssot) | CAD_QSPI_DELAY_CSEOT(cseot) |
+		CAD_QSPI_DELAY_CSDADS(csdads) | CAD_QSPI_DELAY_CSDA(csda));
+
+	return 0;
+}
+
+int cad_qspi_stig_cmd_helper(int cs, uint32_t cmd)
+{
+	uint32_t count = 0;
+
+	/* chip select */
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG,
+			(mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG)
+			 & CAD_QSPI_CFG_CS_MSK) | CAD_QSPI_CFG_CS(cs));
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, cmd);
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD,
+			cmd | CAD_QSPI_FLASHCMD_EXECUTE);
+
+	do {
+		uint32_t reg = mmio_read_32(CAD_QSPI_OFFSET +
+					CAD_QSPI_FLASHCMD);
+		if (!(reg & CAD_QSPI_FLASHCMD_EXECUTE_STAT))
+			break;
+		count++;
+	} while (count < CAD_QSPI_COMMAND_TIMEOUT);
+
+	if (count >= CAD_QSPI_COMMAND_TIMEOUT) {
+		ERROR("Error sending QSPI command %x, timed out\n",
+				cmd);
+		return CAD_QSPI_ERROR;
+	}
+
+	return 0;
+}
+
+int cad_qspi_stig_cmd(uint32_t opcode, uint32_t dummy)
+{
+	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
+		ERROR("Faulty dummy bytes\n");
+		return -1;
+	}
+
+	return cad_qspi_stig_cmd_helper(cad_qspi_cs,
+			CAD_QSPI_FLASHCMD_OPCODE(opcode) |
+			CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(dummy));
+}
+
+int cad_qspi_stig_read_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes,
+		uint32_t *output)
+{
+	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
+		ERROR("Faulty dummy byes\n");
+		return -1;
+	}
+
+	if ((num_bytes > 8) || (num_bytes == 0))
+		return -1;
+
+	uint32_t cmd =
+		CAD_QSPI_FLASHCMD_OPCODE(opcode) |
+		CAD_QSPI_FLASHCMD_ENRDDATA(1) |
+		CAD_QSPI_FLASHCMD_NUMRDDATABYTES(num_bytes - 1) |
+		CAD_QSPI_FLASHCMD_ENCMDADDR(0) |
+		CAD_QSPI_FLASHCMD_ENMODEBIT(0) |
+		CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) |
+		CAD_QSPI_FLASHCMD_ENWRDATA(0) |
+		CAD_QSPI_FLASHCMD_NUMWRDATABYTES(0) |
+		CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy);
+
+	if (cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd)) {
+		ERROR("failed to send stig cmd\n");
+		return -1;
+	}
+
+	output[0] = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_RDDATA0);
+
+	if (num_bytes > 4) {
+		output[1] = mmio_read_32(CAD_QSPI_OFFSET +
+				CAD_QSPI_FLASHCMD_RDDATA1);
+	}
+
+	return 0;
+}
+
+int cad_qspi_stig_wr_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes,
+		uint32_t *input)
+{
+	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) {
+		ERROR("Faulty dummy byes\n");
+		return -1;
+	}
+
+	if ((num_bytes > 8) || (num_bytes == 0))
+		return -1;
+
+	uint32_t cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) |
+		CAD_QSPI_FLASHCMD_ENRDDATA(0) |
+		CAD_QSPI_FLASHCMD_NUMRDDATABYTES(0) |
+		CAD_QSPI_FLASHCMD_ENCMDADDR(0) |
+		CAD_QSPI_FLASHCMD_ENMODEBIT(0) |
+		CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) |
+		CAD_QSPI_FLASHCMD_ENWRDATA(1) |
+		CAD_QSPI_FLASHCMD_NUMWRDATABYTES(num_bytes - 1) |
+		CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy);
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA0, input[0]);
+
+	if (num_bytes > 4)
+		mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA1,
+				input[1]);
+
+	return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd);
+}
+
+int cad_qspi_stig_addr_cmd(uint32_t opcode, uint32_t dummy, uint32_t addr)
+{
+	uint32_t cmd;
+
+	if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1))
+		return -1;
+
+	cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) |
+		CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy) |
+		CAD_QSPI_FLASHCMD_ENCMDADDR(1) |
+		CAD_QSPI_FLASHCMD_NUMADDRBYTES(2);
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_ADDR, addr);
+
+	return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd);
+}
+
+int cad_qspi_device_bank_select(uint32_t bank)
+{
+	int status = 0;
+
+	status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
+	if (status != 0)
+		return status;
+
+	status = cad_qspi_stig_wr_cmd(CAD_QSPI_STIG_OPCODE_WREN_EXT_REG,
+			0, 1, &bank);
+	if (status != 0)
+		return status;
+
+	return cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WRDIS, 0);
+}
+
+int cad_qspi_device_status(uint32_t *status)
+{
+	return cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDSR, 0, 1, status);
+}
+
+#if CAD_QSPI_MICRON_N25Q_SUPPORT
+int cad_qspi_n25q_enable(void)
+{
+	cad_qspi_set_read_config(QSPI_FAST_READ, CAD_QSPI_INST_SINGLE,
+			CAD_QSPI_ADDR_FASTREAD, CAT_QSPI_ADDR_SINGLE_IO, 1,
+			0);
+	cad_qspi_set_write_config(QSPI_WRITE, 0, 0, 0);
+
+	return 0;
+}
+
+int cad_qspi_n25q_wait_for_program_and_erase(int program_only)
+{
+	uint32_t status, flag_sr;
+	int count = 0;
+
+	while (count < CAD_QSPI_COMMAND_TIMEOUT) {
+		status = cad_qspi_device_status(&status);
+		if (status != 0) {
+			ERROR("Error getting device status\n");
+			return -1;
+		}
+		if (!CAD_QSPI_STIG_SR_BUSY(status))
+			break;
+		count++;
+	}
+
+	if (count >= CAD_QSPI_COMMAND_TIMEOUT) {
+		ERROR("Timed out waiting for idle\n");
+		return -1;
+	}
+
+	count = 0;
+
+	while (count < CAD_QSPI_COMMAND_TIMEOUT) {
+		status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDFLGSR,
+				0, 1, &flag_sr);
+		if (status != 0) {
+			ERROR("Error waiting program and erase.\n");
+			return status;
+		}
+
+		if ((program_only &&
+			CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(flag_sr)) ||
+			(!program_only &&
+			CAD_QSPI_STIG_FLAGSR_ERASEREADY(flag_sr)))
+			break;
+	}
+
+	if (count >= CAD_QSPI_COMMAND_TIMEOUT)
+		ERROR("Timed out waiting for program and erase\n");
+
+	if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(flag_sr)) ||
+			(!program_only &&
+			CAD_QSPI_STIG_FLAGSR_ERASEERROR(flag_sr))) {
+		ERROR("Error programming/erasing flash\n");
+		cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_CLFSR, 0);
+		return -1;
+	}
+
+	return 0;
+}
+#endif
+
+int cad_qspi_indirect_read_start_bank(uint32_t flash_addr, uint32_t num_bytes)
+{
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDSTADDR, flash_addr);
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDCNT, num_bytes);
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD,
+			CAD_QSPI_INDRD_START |
+			CAD_QSPI_INDRD_IND_OPS_DONE);
+
+	return 0;
+}
+
+
+int cad_qspi_indirect_write_start_bank(uint32_t flash_addr,
+					uint32_t num_bytes)
+{
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRSTADDR, flash_addr);
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRCNT, num_bytes);
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR,
+			CAD_QSPI_INDWR_START |
+			CAD_QSPI_INDWR_INDDONE);
+
+	return 0;
+}
+
+int cad_qspi_indirect_write_finish(void)
+{
+#if CAD_QSPI_MICRON_N25Q_SUPPORT
+	return cad_qspi_n25q_wait_for_program_and_erase(1);
+#else
+	return 0;
+#endif
+
+}
+
+int cad_qspi_enable(void)
+{
+	int status;
+
+	mmio_setbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, CAD_QSPI_CFG_ENABLE);
+
+#if CAD_QSPI_MICRON_N25Q_SUPPORT
+	status = cad_qspi_n25q_enable();
+	if (status != 0)
+		return status;
+#endif
+	return 0;
+}
+
+int cad_qspi_enable_subsector_bank(uint32_t addr)
+{
+	int status = 0;
+
+	status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
+	if (status != 0)
+		return status;
+
+	status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0,
+					addr);
+	if (status != 0)
+		return status;
+
+#if CAD_QSPI_MICRON_N25Q_SUPPORT
+	status = cad_qspi_n25q_wait_for_program_and_erase(0);
+#endif
+	return status;
+}
+
+int cad_qspi_erase_subsector(uint32_t addr)
+{
+	int status = 0;
+
+	status = cad_qspi_device_bank_select(addr >> 24);
+	if (status != 0)
+		return status;
+
+	return cad_qspi_enable_subsector_bank(addr);
+}
+
+int cad_qspi_erase_sector(uint32_t addr)
+{
+	int status = 0;
+
+	status = cad_qspi_device_bank_select(addr >> 24);
+	if (status != 0)
+		return status;
+
+	status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0);
+	if (status != 0)
+		return status;
+
+	status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SEC_ERASE, 0,
+					addr);
+	if (status != 0)
+		return status;
+
+#if CAD_QSPI_MICRON_N25Q_SUPPORT
+	status = cad_qspi_n25q_wait_for_program_and_erase(0);
+#endif
+	return status;
+}
+
+void cad_qspi_calibration(uint32_t dev_clk, uint32_t qspi_clk_mhz)
+{
+	int status;
+	uint32_t dev_sclk_mhz = 27; /*min value to get biggest 0xF div factor*/
+	uint32_t data_cap_delay;
+	uint32_t sample_rdid;
+	uint32_t rdid;
+	uint32_t div_actual;
+	uint32_t div_bits;
+	int first_pass, last_pass;
+
+	/*1.  Set divider to bigger value (slowest SCLK)
+	 *2.  RDID and save the value
+	 */
+	div_actual = (qspi_clk_mhz + (dev_sclk_mhz - 1)) / dev_sclk_mhz;
+	div_bits = (((div_actual + 1) / 2) - 1);
+	status = cad_qspi_set_baudrate_div(0xf);
+
+	status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID,
+					0, 3, &sample_rdid);
+	if (status != 0)
+		return;
+
+	/*3. Set divider to the intended frequency
+	 *4.  Set the read delay = 0
+	 *5.  RDID and check whether the value is same as item 2
+	 *6.  Increase read delay and compared the value against item 2
+	 *7.  Find the range of read delay that have same as
+	 *    item 2 and divide it to 2
+	 */
+	div_actual = (qspi_clk_mhz + (dev_clk - 1)) / dev_clk;
+	div_bits = (((div_actual + 1) / 2) - 1);
+	status = cad_qspi_set_baudrate_div(div_bits);
+	if (status != 0)
+		return;
+
+	data_cap_delay = 0;
+	first_pass = -1;
+	last_pass = -1;
+
+	do {
+		if (status != 0)
+			break;
+		status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0,
+						3, &rdid);
+		if (status != 0)
+			break;
+		if (rdid == sample_rdid) {
+			if (first_pass == -1)
+				first_pass = data_cap_delay;
+			else
+				last_pass = data_cap_delay;
+		}
+
+		data_cap_delay++;
+
+		mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP,
+				CAD_QSPI_RDDATACAP_BYP(1) |
+				CAD_QSPI_RDDATACAP_DELAY(data_cap_delay));
+
+	} while (data_cap_delay < 0x10);
+
+	if (first_pass > 0) {
+		int diff = first_pass - last_pass;
+
+		data_cap_delay = first_pass + diff / 2;
+	}
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP,
+			CAD_QSPI_RDDATACAP_BYP(1) |
+			CAD_QSPI_RDDATACAP_DELAY(data_cap_delay));
+	status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid);
+
+	if (status != 0)
+		return;
+}
+
+int cad_qspi_int_disable(uint32_t mask)
+{
+	if (cad_qspi_idle() == 0)
+		return -1;
+
+	if ((CAD_QSPI_INT_STATUS_ALL & mask) == 0)
+		return -1;
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_IRQMSK, mask);
+	return 0;
+}
+
+void cad_qspi_set_chip_select(int cs)
+{
+	cad_qspi_cs = cs;
+}
+
+int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase,
+			uint32_t clk_pol, uint32_t csda, uint32_t csdads,
+			uint32_t cseot, uint32_t cssot, uint32_t rddatacap)
+{
+	int status = 0;
+	uint32_t qspi_desired_clk_freq;
+	uint32_t rdid = 0;
+	uint32_t cap_code;
+
+	INFO("Initializing Qspi\n");
+
+	if (cad_qspi_idle() == 0) {
+		ERROR("device not idle\n");
+		return -1;
+	}
+
+
+	status = cad_qspi_timing_config(clk_phase, clk_pol, csda, csdads,
+					cseot, cssot, rddatacap);
+
+	if (status != 0) {
+		ERROR("config set timing failure\n");
+		return status;
+	}
+
+	mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_REMAPADDR,
+			CAD_QSPI_REMAPADDR_VALUE_SET(0));
+
+	status = cad_qspi_int_disable(CAD_QSPI_INT_STATUS_ALL);
+	if (status != 0) {
+		ERROR("failed disable\n");
+		return status;
+	}
+
+	cad_qspi_set_baudrate_div(0xf);
+	status = cad_qspi_enable();
+	if (status != 0) {
+		ERROR("failed enable\n");
+		return status;
+	}
+
+	qspi_desired_clk_freq = 100;
+	cad_qspi_calibration(qspi_desired_clk_freq, 50000000);
+
+	status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3,
+					&rdid);
+
+	if (status != 0) {
+		ERROR("Error reading RDID\n");
+		return status;
+	}
+
+	/*
+	 * NOTE: The Size code seems to be a form of BCD (binary coded decimal).
+	 * The first nibble is the 10's digit and the second nibble is the 1's
+	 * digit in the number of bytes.
+	 *
+	 * Capacity ID samples:
+	 * 0x15 :   16 Mb =>   2 MiB => 1 << 21 ; BCD=15
+	 * 0x16 :   32 Mb =>   4 MiB => 1 << 22 ; BCD=16
+	 * 0x17 :   64 Mb =>   8 MiB => 1 << 23 ; BCD=17
+	 * 0x18 :  128 Mb =>  16 MiB => 1 << 24 ; BCD=18
+	 * 0x19 :  256 Mb =>  32 MiB => 1 << 25 ; BCD=19
+	 * 0x1a
+	 * 0x1b
+	 * 0x1c
+	 * 0x1d
+	 * 0x1e
+	 * 0x1f
+	 * 0x20 :  512 Mb =>  64 MiB => 1 << 26 ; BCD=20
+	 * 0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21
+	 */
+
+	cap_code = CAD_QSPI_STIG_RDID_CAPACITYID(rdid);
+
+	if (!(((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))) {
+		uint32_t decoded_cap = ((cap_code >> 4) * 10) +
+					(cap_code & 0xf);
+		qspi_device_size = 1 << (decoded_cap + 6);
+		INFO("QSPI Capacity: %x\n\n", qspi_device_size);
+
+	} else {
+		ERROR("Invalid CapacityID encountered: 0x%02x\n",
+				cap_code);
+		return -1;
+	}
+
+	cad_qspi_configure_dev_size(INTEL_QSPI_ADDR_BYTES,
+				INTEL_QSPI_BYTES_PER_DEV,
+				INTEL_BYTES_PER_BLOCK);
+
+	INFO("Flash size: %d Bytes\n", qspi_device_size);
+
+	return status;
+}
+
+int cad_qspi_indirect_page_bound_write(uint32_t offset,
+		uint8_t *buffer, uint32_t len)
+{
+	int status = 0, i;
+	uint32_t write_count, write_capacity, *write_data, space,
+		write_fill_level, sram_partition;
+
+	status = cad_qspi_indirect_write_start_bank(offset, len);
+	if (status != 0)
+		return status;
+
+	write_count = 0;
+	sram_partition = CAD_QSPI_SRAMPART_ADDR(mmio_read_32(CAD_QSPI_OFFSET +
+			 CAD_QSPI_SRAMPART));
+	write_capacity = (uint32_t) CAD_QSPI_SRAM_FIFO_ENTRY_COUNT -
+			sram_partition;
+
+	while (write_count < len) {
+		write_fill_level = CAD_QSPI_SRAMFILL_INDWRPART(
+					mmio_read_32(CAD_QSPI_OFFSET +
+							CAD_QSPI_SRAMFILL));
+		space = LESS(write_capacity - write_fill_level,
+				(len - write_count) / sizeof(uint32_t));
+		write_data = (uint32_t *)(buffer + write_count);
+		for (i = 0; i < space; ++i)
+			mmio_write_32(CAD_QSPIDATA_OFST, *write_data++);
+
+		write_count += space * sizeof(uint32_t);
+	}
+	return cad_qspi_indirect_write_finish();
+}
+
+int cad_qspi_read_bank(uint8_t *buffer, uint32_t offset, uint32_t size)
+{
+	int status;
+	uint32_t read_count = 0, *read_data;
+	int level = 1, count = 0, i;
+
+	status = cad_qspi_indirect_read_start_bank(offset, size);
+
+	if (status != 0)
+		return status;
+
+	while (read_count < size) {
+		do {
+			level = CAD_QSPI_SRAMFILL_INDRDPART(
+				mmio_read_32(CAD_QSPI_OFFSET +
+					CAD_QSPI_SRAMFILL));
+			read_data = (uint32_t *)(buffer + read_count);
+			for (i = 0; i < level; ++i)
+				*read_data++ = mmio_read_32(CAD_QSPIDATA_OFST);
+
+			read_count += level * sizeof(uint32_t);
+			count++;
+		} while (level > 0);
+	}
+
+	return 0;
+}
+
+int cad_qspi_write_bank(uint32_t offset, uint8_t *buffer, uint32_t size)
+{
+	int status = 0;
+	uint32_t page_offset  = offset & (CAD_QSPI_PAGE_SIZE - 1);
+	uint32_t write_size = LESS(size, CAD_QSPI_PAGE_SIZE - page_offset);
+
+	while (size) {
+		status = cad_qspi_indirect_page_bound_write(offset, buffer,
+							write_size);
+		if (status != 0)
+			break;
+
+		offset  += write_size;
+		buffer  += write_size;
+		size -= write_size;
+		write_size = LESS(size, CAD_QSPI_PAGE_SIZE);
+	}
+	return status;
+}
+
+int cad_qspi_read(void *buffer, uint32_t  offset, uint32_t  size)
+{
+	uint32_t bank_count, bank_addr, bank_offset, copy_len;
+	uint8_t *read_data;
+	int i, status;
+
+	status = 0;
+
+	if ((offset >= qspi_device_size) ||
+			(offset + size - 1 >= qspi_device_size) ||
+			(size == 0) ||
+			((long) ((int *)buffer) & 0x3)  ||
+			(offset & 0x3) ||
+			(size & 0x3)) {
+		ERROR("Invalid read parameter\n");
+		return -1;
+	}
+
+	if (CAD_QSPI_INDRD_RD_STAT(mmio_read_32(CAD_QSPI_OFFSET +
+						CAD_QSPI_INDRD))) {
+		ERROR("Read in progress\n");
+		return -1;
+	}
+
+	/*
+	 * bank_count : Number of bank(s) affected, including partial banks.
+	 * bank_addr  : Aligned address of the first bank,
+	 *		including partial bank.
+	 * bank_ofst  : The offset of the bank to read.
+	 *		Only used when reading the first bank.
+	 */
+	bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) -
+			CAD_QSPI_BANK_ADDR(offset) + 1;
+	bank_addr  = offset & CAD_QSPI_BANK_ADDR_MSK;
+	bank_offset  = offset & (CAD_QSPI_BANK_SIZE - 1);
+
+	read_data = (uint8_t *)buffer;
+
+	copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset);
+
+	for (i = 0; i < bank_count; ++i) {
+		status = cad_qspi_device_bank_select(CAD_QSPI_BANK_ADDR(
+								bank_addr));
+		if (status != 0)
+			break;
+		status = cad_qspi_read_bank(read_data, bank_offset, copy_len);
+		if (status != 0)
+			break;
+
+		bank_addr += CAD_QSPI_BANK_SIZE;
+		read_data += copy_len;
+		size -= copy_len;
+		bank_offset = 0;
+		copy_len = LESS(size, CAD_QSPI_BANK_SIZE);
+	}
+
+	return status;
+}
+
+int cad_qspi_erase(uint32_t offset, uint32_t size)
+{
+	int status = 0;
+	uint32_t subsector_offset  = offset & (CAD_QSPI_SUBSECTOR_SIZE - 1);
+	uint32_t erase_size = LESS(size,
+				CAD_QSPI_SUBSECTOR_SIZE - subsector_offset);
+
+	while (size) {
+		status = cad_qspi_erase_subsector(offset);
+		if (status != 0)
+			break;
+
+		offset  += erase_size;
+		size -= erase_size;
+		erase_size = LESS(size, CAD_QSPI_SUBSECTOR_SIZE);
+	}
+	return status;
+}
+
+int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size)
+{
+	int status, i;
+	uint32_t bank_count, bank_addr, bank_offset, copy_len;
+	uint8_t *write_data;
+
+	status = 0;
+
+	if ((offset >= qspi_device_size) ||
+			(offset + size - 1 >= qspi_device_size) ||
+			(size == 0) ||
+			((long)buffer & 0x3)  ||
+			(offset & 0x3) ||
+			(size & 0x3))
+		return -2;
+
+	if (CAD_QSPI_INDWR_RDSTAT(mmio_read_32(CAD_QSPI_OFFSET +
+						CAD_QSPI_INDWR))) {
+		ERROR("QSPI Error: Write in progress\n");
+		return -1;
+	}
+
+	bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) -
+			CAD_QSPI_BANK_ADDR(offset) + 1;
+	bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK;
+	bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1);
+
+	write_data = buffer;
+
+	copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset);
+
+	for (i = 0; i < bank_count; ++i) {
+		status = cad_qspi_device_bank_select(
+				CAD_QSPI_BANK_ADDR(bank_addr));
+		if (status != 0)
+			break;
+
+		status = cad_qspi_write_bank(bank_offset, write_data,
+						copy_len);
+		if (status != 0)
+			break;
+
+		bank_addr += CAD_QSPI_BANK_SIZE;
+		write_data += copy_len;
+		size -= copy_len;
+		bank_offset = 0;
+
+		copy_len = LESS(size, CAD_QSPI_BANK_SIZE);
+	}
+	return status;
+}
+
+int cad_qspi_update(void *Buffer, uint32_t offset, uint32_t size)
+{
+	int status = 0;
+
+	status = cad_qspi_erase(offset, size);
+	if (status != 0)
+		return status;
+
+	return cad_qspi_write(Buffer, offset, size);
+}
+
+void cad_qspi_reset(void)
+{
+	cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_EN, 0);
+	cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_MEM, 0);
+}
+
diff --git a/plat/intel/soc/common/drivers/qspi/cadence_qspi.h b/plat/intel/soc/common/drivers/qspi/cadence_qspi.h
new file mode 100644
index 0000000..cfef585
--- /dev/null
+++ b/plat/intel/soc/common/drivers/qspi/cadence_qspi.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CAD_QSPI_H
+#define CAD_QSPI_H
+
+#define CAD_QSPI_MICRON_N25Q_SUPPORT		1
+
+#define CAD_QSPI_OFFSET				0xff8d2000
+
+#define CAD_INVALID				-1
+#define CAD_QSPI_ERROR				-2
+
+#define CAD_QSPI_ADDR_FASTREAD			0
+#define CAD_QSPI_ADDR_FASTREAD_DUAL_IO		1
+#define CAD_QSPI_ADDR_FASTREAD_QUAD_IO		2
+#define CAT_QSPI_ADDR_SINGLE_IO			0
+#define CAT_QSPI_ADDR_DUAL_IO			1
+#define CAT_QSPI_ADDR_QUAD_IO			2
+
+#define CAD_QSPI_BANK_ADDR(x)			((x) >> 24)
+#define CAD_QSPI_BANK_ADDR_MSK			0xff000000
+
+#define CAD_QSPI_COMMAND_TIMEOUT		0x10000000
+
+#define CAD_QSPI_CFG				0x0
+#define CAD_QSPI_CFG_BAUDDIV_MSK		0xff87ffff
+#define CAD_QSPI_CFG_BAUDDIV(x)			(((x) << 19) & 0x780000)
+#define CAD_QSPI_CFG_CS_MSK			~0x3c00
+#define CAD_QSPI_CFG_CS(x)			(((x) << 11))
+#define CAD_QSPI_CFG_ENABLE			(1 << 0)
+#define CAD_QSPI_CFG_ENDMA_CLR_MSK		0xffff7fff
+#define CAD_QSPI_CFG_IDLE			(1U << 31)
+#define CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK	0xfffffffb
+#define CAD_QSPI_CFG_SELCLKPOL_CLR_MSK		0xfffffffd
+
+#define CAD_QSPIDATA_OFST			0xff900000
+
+#define CAD_QSPI_DELAY				0xc
+#define CAD_QSPI_DELAY_CSSOT(x)			(((x) & 0xff) << 0)
+#define CAD_QSPI_DELAY_CSEOT(x)			(((x) & 0xff) << 8)
+#define CAD_QSPI_DELAY_CSDADS(x)		(((x) & 0xff) << 16)
+#define CAD_QSPI_DELAY_CSDA(x)			(((x) & 0xff) << 24)
+
+#define CAD_QSPI_DEVSZ				0x14
+#define CAD_QSPI_DEVSZ_ADDR_BYTES(x)		((x) << 0)
+#define CAD_QSPI_DEVSZ_BYTES_PER_PAGE(x)	((x) << 4)
+#define CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(x)	((x) << 16)
+
+#define CAD_QSPI_DEVWR				0x8
+#define CAD_QSPI_DEVRD				0x4
+#define CAD_QSPI_DEV_OPCODE(x)			(((x) & 0xff) << 0)
+#define CAD_QSPI_DEV_INST_TYPE(x)		(((x) & 0x03) << 8)
+#define CAD_QSPI_DEV_ADDR_TYPE(x)		(((x) & 0x03) << 12)
+#define CAD_QSPI_DEV_DATA_TYPE(x)		(((x) & 0x03) << 16)
+#define CAD_QSPI_DEV_MODE_BIT(x)		(((x) & 0x01) << 20)
+#define CAD_QSPI_DEV_DUMMY_CLK_CYCLE(x)		(((x) & 0x0f) << 24)
+
+#define CAD_QSPI_FLASHCMD			0x90
+#define CAD_QSPI_FLASHCMD_ADDR			0x94
+#define CAD_QSPI_FLASHCMD_EXECUTE		0x1
+#define CAD_QSPI_FLASHCMD_EXECUTE_STAT		0x2
+#define CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX	5
+#define CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(x)	(((x) << 7) & 0x000f80)
+#define CAD_QSPI_FLASHCMD_OPCODE(x)		(((x) & 0xff) << 24)
+#define CAD_QSPI_FLASHCMD_ENRDDATA(x)		(((x) & 1) << 23)
+#define CAD_QSPI_FLASHCMD_NUMRDDATABYTES(x)	(((x) & 0xf) << 20)
+#define CAD_QSPI_FLASHCMD_ENCMDADDR(x)		(((x) & 1) << 19)
+#define CAD_QSPI_FLASHCMD_ENMODEBIT(x)		(((x) & 1) << 18)
+#define CAD_QSPI_FLASHCMD_NUMADDRBYTES(x)	(((x) & 0x3) << 16)
+#define CAD_QSPI_FLASHCMD_ENWRDATA(x)		(((x) & 1) << 15)
+#define CAD_QSPI_FLASHCMD_NUMWRDATABYTES(x)	(((x) & 0x7) << 12)
+#define CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(x)	(((x) & 0x1f) << 7)
+#define CAD_QSPI_FLASHCMD_RDDATA0		0xa0
+#define CAD_QSPI_FLASHCMD_RDDATA1		0xa4
+#define CAD_QSPI_FLASHCMD_WRDATA0		0xa8
+#define CAD_QSPI_FLASHCMD_WRDATA1		0xac
+
+#define CAD_QSPI_RDDATACAP			0x10
+#define CAD_QSPI_RDDATACAP_BYP(x)		(((x) & 1) << 0)
+#define CAD_QSPI_RDDATACAP_DELAY(x)		(((x) & 0xf) << 1)
+
+#define CAD_QSPI_REMAPADDR			0x24
+#define CAD_QSPI_REMAPADDR_VALUE_SET(x)		(((x) & 0xffffffff) << 0)
+
+#define CAD_QSPI_SRAMPART			0x18
+#define CAD_QSPI_SRAMFILL			0x2c
+#define CAD_QSPI_SRAMPART_ADDR(x)		(((x) >> 0) & 0x3ff)
+#define CAD_QSPI_SRAM_FIFO_ENTRY_COUNT		(512 / sizeof(uint32_t))
+#define CAD_QSPI_SRAMFILL_INDWRPART(x)		(((x) >> 16) & 0x00ffff)
+#define CAD_QSPI_SRAMFILL_INDRDPART(x)		(((x) >> 0) & 0x00ffff)
+
+#define CAD_QSPI_SELCLKPHASE(x)			(((x) & 1) << 2)
+#define CAD_QSPI_SELCLKPOL(x)			(((x) & 1) << 1)
+
+#define CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(x)	(((x) >> 7) & 1)
+#define CAD_QSPI_STIG_FLAGSR_ERASEREADY(x)	(((x) >> 7) & 1)
+#define CAD_QSPI_STIG_FLAGSR_ERASEERROR(x)	(((x) >> 5) & 1)
+#define CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(x)	(((x) >> 4) & 1)
+#define CAD_QSPI_STIG_OPCODE_CLFSR		0x50
+#define CAD_QSPI_STIG_OPCODE_RDID		0x9f
+#define CAD_QSPI_STIG_OPCODE_WRDIS		0x4
+#define CAD_QSPI_STIG_OPCODE_WREN		0x6
+#define CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE	0x20
+#define CAD_QSPI_STIG_OPCODE_SEC_ERASE		0xd8
+#define CAD_QSPI_STIG_OPCODE_WREN_EXT_REG	0xc5
+#define CAD_QSPI_STIG_OPCODE_DIE_ERASE		0xc4
+#define CAD_QSPI_STIG_OPCODE_BULK_ERASE		0xc7
+#define CAD_QSPI_STIG_OPCODE_RDSR		0x5
+#define CAD_QSPI_STIG_OPCODE_RDFLGSR		0x70
+#define CAD_QSPI_STIG_OPCODE_RESET_EN		0x66
+#define CAD_QSPI_STIG_OPCODE_RESET_MEM		0x99
+#define CAD_QSPI_STIG_RDID_CAPACITYID(x)	(((x) >> 16) & 0xff)
+#define CAD_QSPI_STIG_SR_BUSY(x)		(((x) >> 0) & 1)
+
+
+#define CAD_QSPI_INST_SINGLE			0
+#define CAD_QSPI_INST_DUAL			1
+#define CAD_QSPI_INST_QUAD			2
+
+#define CAD_QSPI_INDRDSTADDR			0x68
+#define CAD_QSPI_INDRDCNT			0x6c
+#define CAD_QSPI_INDRD				0x60
+#define CAD_QSPI_INDRD_RD_STAT(x)		(((x) >> 2) & 1)
+#define CAD_QSPI_INDRD_START			1
+#define CAD_QSPI_INDRD_IND_OPS_DONE		0x20
+
+#define CAD_QSPI_INDWR				0x70
+#define CAD_QSPI_INDWR_RDSTAT(x)		(((x) >> 2) & 1)
+#define CAD_QSPI_INDWRSTADDR			0x78
+#define CAD_QSPI_INDWRCNT			0x7c
+#define CAD_QSPI_INDWR				0x70
+#define CAD_QSPI_INDWR_START			0x1
+#define CAD_QSPI_INDWR_INDDONE			0x20
+
+#define CAD_QSPI_INT_STATUS_ALL			0x0000ffff
+
+#define CAD_QSPI_N25Q_DIE_SIZE			0x02000000
+#define CAD_QSPI_BANK_SIZE			0x01000000
+#define CAD_QSPI_PAGE_SIZE			0x00000100
+
+#define CAD_QSPI_IRQMSK				0x44
+
+#define CAD_QSPI_SUBSECTOR_SIZE			0x1000
+
+#define INTEL_QSPI_ADDR_BYTES			2
+#define INTEL_QSPI_BYTES_PER_DEV		256
+#define INTEL_BYTES_PER_BLOCK			16
+
+#define QSPI_FAST_READ				0xb
+
+#define QSPI_WRITE				0x2
+
+// QSPI CONFIGURATIONS
+
+#define QSPI_CONFIG_CPOL			1
+#define QSPI_CONFIG_CPHA			1
+
+#define QSPI_CONFIG_CSSOT			0x14
+#define QSPI_CONFIG_CSEOT			0x14
+#define QSPI_CONFIG_CSDADS			0xff
+#define QSPI_CONFIG_CSDA			0xc8
+
+int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase,
+	uint32_t clk_pol, uint32_t csda, uint32_t csdads,
+	uint32_t cseot, uint32_t cssot, uint32_t rddatacap);
+void cad_qspi_set_chip_select(int cs);
+int cad_qspi_erase(uint32_t offset, uint32_t size);
+int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size);
+int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size);
+int cad_qspi_update(void *buffer, uint32_t offset, uint32_t size);
+
+#endif
+
diff --git a/plat/intel/soc/common/drivers/wdt/watchdog.c b/plat/intel/soc/common/drivers/wdt/watchdog.c
new file mode 100644
index 0000000..0f89b4f
--- /dev/null
+++ b/plat/intel/soc/common/drivers/wdt/watchdog.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include "watchdog.h"
+
+
+/* Reset watchdog timer */
+void watchdog_sw_rst(void)
+{
+	mmio_write_32(WDT_CRR, WDT_SW_RST);
+}
+
+/* Print component information */
+void watchdog_info(void)
+{
+	INFO("Component Type    : %x\r\n", mmio_read_32(WDT_COMP_VERSION));
+	INFO("Component Version : %x\r\n", mmio_read_32(WDT_COMP_TYPE));
+}
+
+/* Check watchdog current status */
+void watchdog_status(void)
+{
+	if (mmio_read_32(WDT_CR) & 1) {
+		INFO("Watchdog Timer is currently enabled\n");
+		INFO("Current Counter : 0x%x\r\n", mmio_read_32(WDT_CCVR));
+	} else {
+		INFO("Watchdog Timer is currently disabled\n");
+	}
+}
+
+/* Initialize & enable watchdog */
+void watchdog_init(int watchdog_clk)
+{
+	uint8_t cycles_i = 0;
+	uint32_t wdt_cycles = WDT_MIN_CYCLES;
+	uint32_t top_init_cycles = WDT_PERIOD * watchdog_clk;
+
+	while ((cycles_i < 15) && (wdt_cycles < top_init_cycles)) {
+		wdt_cycles = (wdt_cycles << 1);
+		cycles_i++;
+	}
+
+	mmio_write_32(WDT_TORR, (cycles_i << 4) | cycles_i);
+
+	mmio_write_32(WDT_CR, WDT_CR_RMOD|WDT_CR_EN);
+}
diff --git a/plat/intel/soc/common/drivers/wdt/watchdog.h b/plat/intel/soc/common/drivers/wdt/watchdog.h
new file mode 100644
index 0000000..2c72463
--- /dev/null
+++ b/plat/intel/soc/common/drivers/wdt/watchdog.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CAD_WATCHDOG_H
+#define CAD_WATCHDOG_H
+
+#define WDT_BASE			(0xFFD00200)
+#define WDT_REG_SIZE_OFFSET		(0x4)
+#define WDT_MIN_CYCLES			(65536)
+#define WDT_PERIOD			(20)
+
+#define WDT_CR				(WDT_BASE + 0x0)
+#define WDT_TORR			(WDT_BASE + 0x4)
+
+#define WDT_CRR				(WDT_BASE + 0xC)
+
+#define WDT_CCVR			(WDT_BASE + 0x8)
+#define WDT_STAT			(WDT_BASE + 0x10)
+#define WDT_EOI				(WDT_BASE + 0x14)
+
+#define WDT_COMP_PARAM_1		(WDT_BASE + 0xF4)
+#define WDT_COMP_VERSION		(WDT_BASE + 0xF8)
+#define WDT_COMP_TYPE			(WDT_BASE + 0XFC)
+
+#define WDT_CR_RMOD			(0x0)
+#define WDT_CR_EN			(0x1)
+
+#define WDT_SW_RST			(0x76)
+
+
+void watchdog_init(int watchdog_clk);
+void watchdog_info(void);
+void watchdog_status(void);
+void watchdog_sw_rst(void);
+
+#endif
diff --git a/plat/intel/soc/common/include/plat_macros.S b/plat/intel/soc/common/include/plat_macros.S
new file mode 100644
index 0000000..43db9a2
--- /dev/null
+++ b/plat/intel/soc/common/include/plat_macros.S
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_def.h>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant platform registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/intel/soc/common/include/socfpga_private.h b/plat/intel/soc/common/include/socfpga_private.h
new file mode 100644
index 0000000..6ab1409
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_private.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_PRIVATE_H
+#define PLATFORM_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void socfgpa_configure_mmu_el3(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+
+
+void socfpga_configure_mmu_el1(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+
+void socfpga_delay_timer_init(void);
+
+void socfpga_gic_driver_init(void);
+
+uint32_t socfpga_get_spsr_for_bl32_entry(void);
+
+uint32_t socfpga_get_spsr_for_bl33_entry(void);
+
+unsigned long socfpga_get_ns_image_entrypoint(void);
+
+
+#endif /* PLATFORM_PRIVATE_H */
diff --git a/plat/intel/soc/common/socfpga_delay_timer.c b/plat/intel/soc/common/socfpga_delay_timer.c
new file mode 100644
index 0000000..ff8a556
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_delay_timer.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#define SOCFPGA_GLOBAL_TIMER		0xffd01000
+#define SOCFPGA_GLOBAL_TIMER_EN		0x3
+
+/********************************************************************
+ * The timer delay function
+ ********************************************************************/
+static uint32_t socfpga_get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter. The value is
+	 * clipped from 64 to 32 bits.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static const timer_ops_t plat_timer_ops = {
+	.get_timer_value    = socfpga_get_timer_value,
+	.clk_mult           = 1,
+	.clk_div	    = PLAT_SYS_COUNTER_FREQ_IN_MHZ,
+};
+
+void socfpga_delay_timer_init(void)
+{
+	timer_init(&plat_timer_ops);
+	mmio_write_32(SOCFPGA_GLOBAL_TIMER, SOCFPGA_GLOBAL_TIMER_EN);
+}
diff --git a/plat/intel/soc/common/socfpga_image_load.c b/plat/intel/soc/common/socfpga_image_load.c
new file mode 100644
index 0000000..67c02bc
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_image_load.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/intel/soc/common/socfpga_topology.c b/plat/intel/soc/common/socfpga_topology.c
new file mode 100644
index 0000000..ca1a91e
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_topology.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <lib/psci/psci.h>
+
+static const unsigned char plat_power_domain_tree_desc[] = {1, 4};
+
+/*******************************************************************************
+ * This function returns the default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return plat_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
+
diff --git a/plat/intel/soc/stratix10/bl2_plat_setup.c b/plat/intel/soc/stratix10/bl2_plat_setup.c
new file mode 100644
index 0000000..8e8b582
--- /dev/null
+++ b/plat/intel/soc/stratix10/bl2_plat_setup.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/gicv2.h>
+
+#include <drivers/generic_delay_timer.h>
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <errno.h>
+#include <drivers/io/io_storage.h>
+#include <common/image_decompress.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <socfpga_private.h>
+#include <drivers/synopsys/dw_mmc.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include "s10_memory_controller.h"
+#include "s10_reset_manager.h"
+#include "s10_clock_manager.h"
+#include "s10_handoff.h"
+#include "s10_pinmux.h"
+#include "stratix10_private.h"
+#include "include/s10_mailbox.h"
+#include "qspi/cadence_qspi.h"
+#include "wdt/watchdog.h"
+
+
+const mmap_region_t plat_stratix10_mmap[] = {
+	MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE,
+		MT_MEMORY | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE,
+		MT_NON_CACHEABLE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	{0},
+};
+
+boot_source_type boot_source;
+
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+				u_register_t x2, u_register_t x4)
+{
+	static console_16550_t console;
+	handoff reverse_handoff_ptr;
+
+	generic_delay_timer_init();
+
+	if (s10_get_handoff(&reverse_handoff_ptr))
+		return;
+	config_pinmux(&reverse_handoff_ptr);
+	boot_source = reverse_handoff_ptr.boot_source;
+
+	config_clkmgr_handoff(&reverse_handoff_ptr);
+	enable_nonsecure_access();
+	deassert_peripheral_reset();
+	config_hps_hs_before_warm_reset();
+
+	watchdog_init(get_wdt_clk(&reverse_handoff_ptr));
+
+	console_16550_register(PLAT_UART0_BASE, PLAT_UART_CLOCK, PLAT_BAUDRATE,
+		&console);
+
+	socfpga_delay_timer_init();
+	init_hard_memory_controller();
+}
+
+
+void bl2_el3_plat_arch_setup(void)
+{
+
+	struct mmc_device_info info;
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL2_BASE, BL2_END - BL2_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE,
+			BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE),
+#if USE_COHERENT_MEM_BAR
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+#endif
+		{0},
+	};
+
+	setup_page_tables(bl_regions, plat_stratix10_mmap);
+
+	enable_mmu_el3(0);
+
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(0x100000);
+
+	info.mmc_dev_type = MMC_IS_SD;
+	info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3;
+
+	switch (boot_source) {
+	case BOOT_SOURCE_SDMMC:
+		dw_mmc_init(&params, &info);
+		stratix10_io_setup(boot_source);
+		break;
+
+	case BOOT_SOURCE_QSPI:
+		mailbox_set_qspi_open();
+		mailbox_set_qspi_direct();
+		cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL,
+			QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS,
+			QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0);
+		stratix10_io_setup(boot_source);
+		break;
+
+	default:
+		ERROR("Unsupported boot source\n");
+		panic();
+		break;
+	}
+}
+
+uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+
+	switch (image_id) {
+	case BL33_IMAGE_ID:
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = get_spsr_for_bl33_entry();
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl2_platform_setup(void)
+{
+}
+
diff --git a/plat/intel/soc/stratix10/bl31_plat_setup.c b/plat/intel/soc/stratix10/bl31_plat_setup.c
new file mode 100644
index 0000000..7c9833b
--- /dev/null
+++ b/plat/intel/soc/stratix10/bl31_plat_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/arm/gicv2.h>
+#include <s10_mailbox.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "stratix10_private.h"
+#include "s10_handoff.h"
+#include "s10_reset_manager.h"
+#include "s10_memory_controller.h"
+#include "s10_pinmux.h"
+#include "s10_clock_manager.h"
+#include "s10_system_manager.h"
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ?
+			  &bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	static console_16550_t console;
+
+	console_16550_register(PLAT_UART0_BASE, PLAT_UART_CLOCK, PLAT_BAUDRATE,
+		&console);
+	/*
+	 * Check params passed from BL31 should not be NULL,
+	 */
+	void *from_bl2 = (void *) arg0;
+
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	/*
+	 * Copy BL32 (if populated by BL31) and BL33 entry point information.
+	 * They are stored in Secure RAM, in BL31's address space.
+	 */
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	while (bl_params) {
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+static const interrupt_prop_t s10_interrupt_props[] = {
+	PLAT_INTEL_S10_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+	PLAT_INTEL_S10_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+static const gicv2_driver_data_t plat_gicv2_gic_data = {
+	.gicd_base = PLAT_INTEL_S10_GICD_BASE,
+	.gicc_base = PLAT_INTEL_S10_GICC_BASE,
+	.interrupt_props = s10_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(s10_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+	/* Initialize the gic cpu and distributor interfaces */
+	gicv2_driver_init(&plat_gicv2_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+const mmap_region_t plat_stratix10_mmap[] = {
+	MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE,
+		MT_MEMORY | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE,
+		MT_NON_CACHEABLE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE,
+		MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE,
+		MT_DEVICE | MT_RW | MT_NS),
+	{0}
+};
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE,
+			BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE),
+#if USE_COHERENT_MEM
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+#endif
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_stratix10_mmap);
+	enable_mmu_el3(0);
+}
+
diff --git a/plat/intel/soc/stratix10/include/platform_def.h b/plat/intel/soc/stratix10/include/platform_def.h
new file mode 100644
index 0000000..a753acd
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/platform_def.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <plat/common/common_def.h>
+
+
+#define PLAT_CPUID_RELEASE			0xffe1b000
+#define PLAT_SEC_ENTRY				0xffe1b008
+
+/* Define next boot image name and offset */
+#define PLAT_NS_IMAGE_OFFSET			0x50000
+#define PLAT_HANDOFF_OFFSET			0xFFE3F000
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT			"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH			aarch64
+
+/* Stratix 10 supports up to 124GB RAM */
+#define PLAT_PHY_ADDR_SPACE_SIZE		(1ULL << 39)
+#define PLAT_VIRT_ADDR_SPACE_SIZE		(1ULL << 39)
+
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLAT_PRIMARY_CPU			0
+#define PLAT_SECONDARY_ENTRY_BASE		0x01f78bf0
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE			0x2000
+
+/* PSCI related constant */
+#define PLAT_NUM_POWER_DOMAINS		5
+#define PLAT_MAX_PWR_LVL		1
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		2
+#define PLATFORM_SYSTEM_COUNT			1
+#define PLATFORM_CLUSTER_COUNT			1
+#define PLATFORM_CLUSTER0_CORE_COUNT		4
+#define PLATFORM_CLUSTER1_CORE_COUNT		0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT + \
+					PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER		4
+
+/* Interrupt related constant */
+
+#define INTEL_S10_IRQ_SEC_PHY_TIMER		29
+
+#define INTEL_S10_IRQ_SEC_SGI_0		8
+#define INTEL_S10_IRQ_SEC_SGI_1		9
+#define INTEL_S10_IRQ_SEC_SGI_2		10
+#define INTEL_S10_IRQ_SEC_SGI_3		11
+#define INTEL_S10_IRQ_SEC_SGI_4		12
+#define INTEL_S10_IRQ_SEC_SGI_5		13
+#define INTEL_S10_IRQ_SEC_SGI_6		14
+#define INTEL_S10_IRQ_SEC_SGI_7		15
+
+#define TSP_IRQ_SEC_PHY_TIMER		INTEL_S10_IRQ_SEC_PHY_TIMER
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE + 1)
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+#define DRAM_BASE				(0x0)
+#define DRAM_SIZE				(0x80000000)
+
+#define OCRAM_BASE				(0xFFE00000)
+#define OCRAM_SIZE				(0x00040000)
+
+#define MEM64_BASE				(0x0100000000)
+#define MEM64_SIZE				(0x1F00000000)
+
+#define DEVICE1_BASE				(0x80000000)
+#define DEVICE1_SIZE				(0x60000000)
+
+#define DEVICE2_BASE				(0xF7000000)
+#define DEVICE2_SIZE				(0x08E00000)
+
+#define DEVICE3_BASE				(0xFFFC0000)
+#define DEVICE3_SIZE				(0x00008000)
+
+#define DEVICE4_BASE				(0x2000000000)
+#define DEVICE4_SIZE				(0x0100000000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL3-1 debug size plus a
+ * little space for growth.
+ */
+
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define BL1_RO_BASE	(0xffe00000)
+#define BL1_RO_LIMIT	(0xffe0f000)
+#define BL1_RW_BASE	(0xffe10000)
+#define BL1_RW_LIMIT	(0xffe1ffff)
+#define BL1_RW_SIZE	(0x14000)
+
+#define BL2_BASE	(0xffe00000)
+#define BL2_LIMIT	(0xffe1b000)
+
+#define BL31_BASE	(0xffe1c000)
+#define BL31_LIMIT	(0xffe3bfff)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		16
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT			6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_GIC_BASE			(0xFFFC0000)
+#define PLAT_GICC_BASE			(PLAT_GIC_BASE + 0x2000)
+#define PLAT_GICD_BASE			(PLAT_GIC_BASE + 0x1000)
+#define PLAT_GICR_BASE			0
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define PLAT_UART0_BASE		(0xFFC02000)
+#define PLAT_UART1_BASE		(0xFFC02100)
+
+#define CRASH_CONSOLE_BASE	PLAT_UART0_BASE
+
+#define PLAT_BAUDRATE			(115200)
+#define PLAT_UART_CLOCK		(100000000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define PLAT_SYS_COUNTER_FREQ_IN_TICKS	(400000000)
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ	(400)
+
+#define PLAT_INTEL_S10_GICD_BASE	PLAT_GICD_BASE
+#define PLAT_INTEL_S10_GICC_BASE	PLAT_GICC_BASE
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_INTEL_S10_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
+			grp, GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+
+#define PLAT_INTEL_S10_G0_IRQ_PROPS(grp)
+
+#define MAX_IO_HANDLES                   4
+#define MAX_IO_DEVICES                  4
+#define MAX_IO_BLOCK_DEVICES             2
+
+
+#endif /* __PLATFORM_DEF_H__ */
+
diff --git a/plat/intel/soc/stratix10/include/s10_clock_manager.h b/plat/intel/soc/stratix10/include/s10_clock_manager.h
new file mode 100644
index 0000000..99eb7a6
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_clock_manager.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CLOCKMANAGER_H__
+#define __CLOCKMANAGER_H__
+
+#include "s10_handoff.h"
+
+#define ALT_CLKMGR				0xffd10000
+
+#define ALT_CLKMGR_CTRL				0x0
+#define ALT_CLKMGR_STAT				0x4
+#define ALT_CLKMGR_INTRCLR			0x14
+#define ALT_CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK	0x00000004
+#define ALT_CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK	0x00000008
+
+#define ALT_CLKMGR_CTRL_BOOTMODE_SET_MSK	0x00000001
+#define ALT_CLKMGR_STAT_BUSY_E_BUSY		0x1
+#define ALT_CLKMGR_STAT_BUSY(x)			(((x) & 0x00000001) >> 0)
+#define ALT_CLKMGR_STAT_MAINPLLLOCKED(x)	(((x) & 0x00000100) >> 8)
+#define ALT_CLKMGR_STAT_PERPLLLOCKED(x)		(((x) & 0x00000200) >> 9)
+
+#define ALT_CLKMGR_MAINPLL			0xffd10030
+#define ALT_CLKMGR_MAINPLL_EN			0x0
+#define ALT_CLKMGR_MAINPLL_BYPASS		0xc
+#define ALT_CLKMGR_MAINPLL_MPUCLK		0x18
+#define ALT_CLKMGR_MAINPLL_NOCCLK		0x1c
+#define ALT_CLKMGR_MAINPLL_CNTR2CLK		0x20
+#define ALT_CLKMGR_MAINPLL_CNTR3CLK		0x24
+#define ALT_CLKMGR_MAINPLL_CNTR4CLK		0x28
+#define ALT_CLKMGR_MAINPLL_CNTR5CLK		0x2c
+#define ALT_CLKMGR_MAINPLL_CNTR6CLK		0x30
+#define ALT_CLKMGR_MAINPLL_CNTR7CLK		0x34
+#define ALT_CLKMGR_MAINPLL_CNTR8CLK		0x38
+#define ALT_CLKMGR_MAINPLL_CNTR9CLK		0x3c
+#define ALT_CLKMGR_MAINPLL_NOCDIV		0x40
+#define ALT_CLKMGR_MAINPLL_PLLGLOB		0x44
+#define ALT_CLKMGR_MAINPLL_FDBCK		0x48
+#define ALT_CLKMGR_MAINPLL_PLLC0		0x54
+#define ALT_CLKMGR_MAINPLL_PLLC1		0x58
+#define ALT_CLKMGR_MAINPLL_VCOCALIB		0x5c
+#define ALT_CLKMGR_MAINPLL_EN_RESET		0x000000ff
+#define ALT_CLKMGR_MAINPLL_FDBCK_MDIV(x)	(((x) & 0xff000000) >> 24)
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PD_SET_MSK	0x00000001
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV(x)	(((x) & 0x00003f00) >> 8)
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_RST_SET_MSK	0x00000002
+#define ALT_CLKMGR_MAINPLL_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000000ff)
+#define ALT_CLKMGR_MAINPLL_VCOCALIB_MSCNT_SET(x) (((x) << 9) & 0x0001fe00)
+
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC(x)	(((x) & 0x00030000) >> 16)
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_EOSC1	0x0
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_INTOSC	0x1
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_F2S	0x2
+
+#define ALT_CLKMGR_PERPLL			0xffd100a4
+#define ALT_CLKMGR_PERPLL_EN			0x0
+#define ALT_CLKMGR_PERPLL_BYPASS		0xc
+#define ALT_CLKMGR_PERPLL_CNTR2CLK		0x18
+#define ALT_CLKMGR_PERPLL_CNTR3CLK		0x1c
+#define ALT_CLKMGR_PERPLL_CNTR4CLK		0x20
+#define ALT_CLKMGR_PERPLL_CNTR5CLK		0x24
+#define ALT_CLKMGR_PERPLL_CNTR6CLK		0x28
+#define ALT_CLKMGR_PERPLL_CNTR7CLK		0x2c
+#define ALT_CLKMGR_PERPLL_CNTR8CLK		0x30
+#define ALT_CLKMGR_PERPLL_CNTR9CLK		0x34
+#define ALT_CLKMGR_PERPLL_GPIODIV		0x3c
+#define ALT_CLKMGR_PERPLL_EMACCTL		0x38
+#define ALT_CLKMGR_PERPLL_PLLGLOB		0x40
+#define ALT_CLKMGR_PERPLL_FDBCK			0x44
+#define ALT_CLKMGR_PERPLL_PLLC0			0x50
+#define ALT_CLKMGR_PERPLL_PLLC1			0x54
+#define ALT_CLKMGR_PERPLL_EN_RESET		0x00000fff
+#define ALT_CLKMGR_PERPLL_FDBCK_MDIV(x)		(((x) & 0xff000000) >> 24)
+#define ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(x) (((x) << 0) & 0x0000ffff)
+#define ALT_CLKMGR_PERPLL_PLLGLOB_PD_SET_MSK	0x00000001
+#define ALT_CLKMGR_PERPLL_PLLGLOB_REFCLKDIV(x)	(((x) & 0x00003f00) >> 8)
+#define ALT_CLKMGR_PERPLL_PLLGLOB_REFCLKDIV_SET(x) (((x) << 8) & 0x00003f00)
+#define ALT_CLKMGR_PERPLL_PLLGLOB_RST_SET_MSK	0x00000002
+#define ALT_CLKMGR_PERPLL_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000000ff)
+#define ALT_CLKMGR_PERPLL_VCOCALIB_MSCNT_SET(x) (((x) << 9) & 0x0001fe00)
+#define ALT_CLKMGR_PERPLL_VCOCALIB		0x58
+
+
+typedef struct {
+	uint32_t  clk_freq_of_eosc1;
+	uint32_t  clk_freq_of_f2h_free;
+	uint32_t  clk_freq_of_cb_intosc_ls;
+} CLOCK_SOURCE_CONFIG;
+
+void config_clkmgr_handoff(handoff *hoff_ptr);
+int get_wdt_clk(handoff *hoff_ptr);
+
+#endif
diff --git a/plat/intel/soc/stratix10/include/s10_handoff.h b/plat/intel/soc/stratix10/include/s10_handoff.h
new file mode 100644
index 0000000..1cc8d09
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_handoff.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef	_HANDOFF_H_
+#define	_HANDOFF_H_
+
+#define HANDOFF_MAGIC_HEADER	0x424f4f54	/* BOOT */
+#define HANDOFF_MAGIC_PINMUX_SEL	0x504d5558	/* PMUX */
+#define HANDOFF_MAGIC_IOCTLR	0x494f4354	/* IOCT */
+#define HANDOFF_MAGIC_FPGA		0x46504741	/* FPGA */
+#define HANDOFF_MAGIC_IODELAY	0x444c4159	/* DLAY */
+#define HANDOFF_MAGIC_CLOCK		0x434c4b53	/* CLKS */
+#define HANDOFF_MAGIC_MISC		0x4d495343	/* MISC */
+
+typedef struct handoff_t {
+	/* header */
+	uint32_t	header_magic;
+	uint32_t	header_device;
+	uint32_t	_pad_0x08_0x10[2];
+
+	/* pinmux configuration - select */
+	uint32_t	pinmux_sel_magic;
+	uint32_t	pinmux_sel_length;
+	uint32_t	_pad_0x18_0x20[2];
+	uint32_t	pinmux_sel_array[96];	/* offset, value */
+
+	/* pinmux configuration - io control */
+	uint32_t	pinmux_io_magic;
+	uint32_t	pinmux_io_length;
+	uint32_t	_pad_0x1a8_0x1b0[2];
+	uint32_t	pinmux_io_array[96];	/* offset, value */
+
+	/* pinmux configuration - use fpga switch */
+	uint32_t	pinmux_fpga_magic;
+	uint32_t	pinmux_fpga_length;
+	uint32_t	_pad_0x338_0x340[2];
+	uint32_t	pinmux_fpga_array[42];	/* offset, value */
+	uint32_t	_pad_0x3e8_0x3f0[2];
+
+	/* pinmux configuration - io delay */
+	uint32_t	pinmux_delay_magic;
+	uint32_t	pinmux_delay_length;
+	uint32_t	_pad_0x3f8_0x400[2];
+	uint32_t	pinmux_iodelay_array[96];	/* offset, value */
+
+	/* clock configuration */
+	uint32_t	clock_magic;
+	uint32_t	clock_length;
+	uint32_t	_pad_0x588_0x590[2];
+	uint32_t	main_pll_mpuclk;
+	uint32_t	main_pll_nocclk;
+	uint32_t	main_pll_cntr2clk;
+	uint32_t	main_pll_cntr3clk;
+	uint32_t	main_pll_cntr4clk;
+	uint32_t	main_pll_cntr5clk;
+	uint32_t	main_pll_cntr6clk;
+	uint32_t	main_pll_cntr7clk;
+	uint32_t	main_pll_cntr8clk;
+	uint32_t	main_pll_cntr9clk;
+	uint32_t	main_pll_nocdiv;
+	uint32_t	main_pll_pllglob;
+	uint32_t	main_pll_fdbck;
+	uint32_t	main_pll_pllc0;
+	uint32_t	main_pll_pllc1;
+	uint32_t	_pad_0x5cc_0x5d0[1];
+	uint32_t	per_pll_cntr2clk;
+	uint32_t	per_pll_cntr3clk;
+	uint32_t	per_pll_cntr4clk;
+	uint32_t	per_pll_cntr5clk;
+	uint32_t	per_pll_cntr6clk;
+	uint32_t	per_pll_cntr7clk;
+	uint32_t	per_pll_cntr8clk;
+	uint32_t	per_pll_cntr9clk;
+	uint32_t	per_pll_emacctl;
+	uint32_t	per_pll_gpiodiv;
+	uint32_t	per_pll_pllglob;
+	uint32_t	per_pll_fdbck;
+	uint32_t	per_pll_pllc0;
+	uint32_t	per_pll_pllc1;
+	uint32_t	hps_osc_clk_h;
+	uint32_t	fpga_clk_hz;
+
+	/* misc configuration */
+	uint32_t	misc_magic;
+	uint32_t	misc_length;
+	uint32_t	_pad_0x618_0x620[2];
+	uint32_t	boot_source;
+} handoff;
+
+int verify_handoff_image(handoff *hoff_ptr, handoff *reverse_hoff_ptr);
+int s10_get_handoff(handoff *hoff_ptr);
+
+#endif
+
+
diff --git a/plat/intel/soc/stratix10/include/s10_mailbox.h b/plat/intel/soc/stratix10/include/s10_mailbox.h
new file mode 100644
index 0000000..554c265
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_mailbox.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __S10_MBOX__
+#define __S10_MBOX__
+
+#define MBOX_OFFSET		0xffa30000
+
+#define MBOX_ATF_CLIENT_ID	0x1
+#define MBOX_JOB_ID		0x1
+
+/* Mailbox interrupt flags and masks */
+#define MBOX_INT_FLAG_COE	0x1
+#define MBOX_INT_FLAG_RIE	0x2
+#define MBOX_INT_FLAG_UAE	0x100
+#define MBOX_COE_BIT(INTERRUPT)	((INTERRUPT) & 0x3)
+#define MBOX_UAE_BIT(INTERRUPT)	(((INTERRUPT) & (1<<4)))
+
+/* Mailbox response and status */
+#define MBOX_RESP_BUFFER_SIZE	16
+#define MBOX_RESP_ERR(BUFFER)	((BUFFER) & 0x00000fff)
+#define MBOX_RESP_LEN(BUFFER)	(((BUFFER) & 0x007ff000) >> 12)
+#define MBOX_RESP_CLIENT_ID(BUFFER)	(((BUFFER) & 0xf0000000) >> 28)
+#define MBOX_RESP_JOB_ID(BUFFER)	(((BUFFER) & 0x0f000000) >> 24)
+#define MBOX_STATUS_UA_MASK	(1<<8)
+
+/* Mailbox command and response */
+#define MBOX_CMD_FREE_OFFSET	0x14
+#define MBOX_CMD_BUFFER_SIZE	32
+#define MBOX_CLIENT_ID_CMD(CLIENT_ID)	((CLIENT_ID) << 28)
+#define MBOX_JOB_ID_CMD(JOB_ID)	(JOB_ID<<24)
+#define MBOX_CMD_LEN_CMD(CMD_LEN)	((CMD_LEN) << 12)
+#define MBOX_INDIRECT			(1 << 11)
+#define MBOX_INSUFFICIENT_BUFFER	-2
+#define MBOX_CIN			0x00
+#define MBOX_ROUT			0x04
+#define MBOX_URG			0x08
+#define MBOX_INT			0x0C
+#define MBOX_COUT			0x20
+#define MBOX_RIN			0x24
+#define MBOX_STATUS			0x2C
+#define MBOX_CMD_BUFFER			0x40
+#define MBOX_RESP_BUFFER		0xC0
+
+#define MBOX_RESP_BUFFER_SIZE		16
+#define MBOX_RESP_OK			0
+#define MBOX_RESP_INVALID_CMD		1
+#define MBOX_RESP_UNKNOWN_BR		2
+#define MBOX_RESP_UNKNOWN		3
+#define MBOX_RESP_NOT_CONFIGURED	256
+
+/* Mailbox SDM doorbell */
+#define MBOX_DOORBELL_TO_SDM		0x400
+#define MBOX_DOORBELL_FROM_SDM		0x480
+
+/* Mailbox QSPI commands */
+#define MBOX_CMD_RESTART		2
+#define MBOX_CMD_QSPI_OPEN		50
+#define MBOX_CMD_QSPI_CLOSE		51
+#define MBOX_CMD_QSPI_DIRECT		59
+#define MBOX_CMD_GET_IDCODE		16
+#define MBOX_CMD_QSPI_SET_CS		52
+
+/* Mailbox REBOOT commands */
+#define MBOX_CMD_REBOOT_HPS		71
+
+/* Generic error handling */
+#define MBOX_TIMEOUT			-2047
+#define MBOX_NO_RESPONSE		-2
+#define MBOX_WRONG_ID			-3
+
+/* Mailbox status */
+#define RECONFIG_STATUS_STATE		0
+#define RECONFIG_STATUS_PIN_STATUS	2
+#define RECONFIG_STATUS_SOFTFUNC_STATUS 3
+#define PIN_STATUS_NSTATUS		(1U << 31)
+#define SOFTFUNC_STATUS_SEU_ERROR	(1 << 3)
+#define SOFTFUNC_STATUS_INIT_DONE	(1 << 1)
+#define SOFTFUNC_STATUS_CONF_DONE	(1 << 0)
+#define MBOX_CFGSTAT_STATE_CONFIG	0x10000000
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT	0x8200ff00
+#define SIP_SVC_UID		0x8200ff01
+#define SIP_SVC_VERSION		0x8200ff03
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR	0
+#define SIP_SVC_VERSION_MINOR	1
+
+/* Mailbox reconfiguration commands */
+#define MBOX_RECONFIG		6
+#define MBOX_RECONFIG_DATA	8
+#define MBOX_RECONFIG_STATUS	9
+
+/* Sip get memory */
+#define INTEL_SIP_SMC_FPGA_CONFIG_START			0xC2000001
+#define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM		0xC2000005
+#define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE		0xC2000004
+#define INTEL_SIP_SMC_FPGA_CONFIG_WRITE			0x42000002
+#define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE	0xC2000003
+#define INTEL_SIP_SMC_STATUS_OK				0
+#define INTEL_SIP_SMC_STATUS_ERROR			0x4
+#define INTEL_SIP_SMC_STATUS_BUSY			0x1
+#define INTEL_SIP_SMC_STATUS_REJECTED			0x2
+#define INTEL_SIP_SMC_FPGA_CONFIG_ADDR			0x1000
+#define INTEL_SIP_SMC_FPGA_CONFIG_SIZE			16777216
+
+void mailbox_set_int(int interrupt_input);
+int mailbox_init(void);
+void mailbox_set_qspi_close(void);
+void mailbox_set_qspi_open(void);
+void mailbox_set_qspi_direct(void);
+int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args,
+				int len, int urgent, uint32_t *response);
+void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args,
+				int len, int urgent);
+int mailbox_read_response(int job_id, uint32_t *response);
+int mailbox_get_qspi_clock(void);
+void mailbox_reset_cold(void);
+
+#endif
diff --git a/plat/intel/soc/stratix10/include/s10_memory_controller.h b/plat/intel/soc/stratix10/include/s10_memory_controller.h
new file mode 100644
index 0000000..ad7cb9d
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_memory_controller.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __S10_MEMORYCONTROLLER_H__
+#define __S10_MEMORYCONTROLLER_H__
+
+#define S10_MPFE_IOHMC_REG_DRAMADDRW			0xf80100a8
+#define S10_MPFE_IOHMC_CTRLCFG0				0xf8010028
+#define S10_MPFE_IOHMC_CTRLCFG1				0xf801002c
+#define S10_MPFE_IOHMC_DRAMADDRW			0xf80100a8
+#define S10_MPFE_IOHMC_DRAMTIMING0			0xf8010050
+#define S10_MPFE_IOHMC_CALTIMING0			0xf801007c
+#define S10_MPFE_IOHMC_CALTIMING1			0xf8010080
+#define S10_MPFE_IOHMC_CALTIMING2			0xf8010084
+#define S10_MPFE_IOHMC_CALTIMING3			0xf8010088
+#define S10_MPFE_IOHMC_CALTIMING4			0xf801008c
+#define S10_MPFE_IOHMC_CALTIMING9			0xf80100a0
+#define S10_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(x) (((x) & 0x000000ff) >> 0)
+#define S10_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(value)	\
+						(((value) & 0x00000060) >> 5)
+
+#define S10_RSTMGR_BRGMODRST				0xffd1102c
+#define S10_RSTMGR_BRGMODRST_DDRSCH			0x00000040
+
+#define S10_MPFE_HMC_ADP_ECCCTRL1			0xf8011100
+#define S10_MPFE_HMC_ADP_ECCCTRL2			0xf8011104
+#define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT		0xf8011218
+#define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE	0x000000ff
+#define S10_MPFE_HMC_ADP_RSTHANDSHAKECTRL		0xf8011214
+
+
+#define S10_MPFE_IOHMC_REG_CTRLCFG1			0xf801002c
+
+#define S10_MPFE_IOHMC_REG_NIOSRESERVE0_OFST		0xf8010110
+
+#define IOHMC_DRAMADDRW_COL_ADDR_WIDTH(x)	(((x) & 0x0000001f) >> 0)
+#define IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(x)	(((x) & 0x000003e0) >> 5)
+#define IOHMC_DRAMADDRW_CS_ADDR_WIDTH(x)	(((x) & 0x00070000) >> 16)
+#define IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(x)	(((x) & 0x0000c000) >> 14)
+#define IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(x)	(((x) & 0x00003c00) >> 10)
+
+#define S10_MPFE_DDR(x)					(0xf8000000 + x)
+#define S10_MPFE_HMC_ADP_DDRCALSTAT			0xf801100c
+#define S10_MPFE_DDR_MAIN_SCHED				0xf8000400
+#define S10_MPFE_DDR_MAIN_SCHED_DDRCONF			0xf8000408
+#define S10_MPFE_DDR_MAIN_SCHED_DDRTIMING		0xf800040c
+#define S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK		0x0000001f
+#define S10_MPFE_DDR_MAIN_SCHED_DDRMODE			0xf8000410
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV		0xf800043c
+#define S10_MPFE_DDR_MAIN_SCHED_READLATENCY		0xf8000414
+#define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE		0xf8000438
+#define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST	10
+#define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST	4
+#define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST	0
+#define S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(x)	(((x) << 0) & 0x0000001f)
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST	0
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK	(BIT(0) | BIT(1))
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST	2
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK	(BIT(2) | BIT(3))
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST	4
+#define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK	(BIT(4) | BIT(5))
+
+#define S10_MPFE_HMC_ADP(x)			(0xf8011000 + (x))
+#define S10_MPFE_HMC_ADP_HPSINTFCSEL		0xf8011210
+#define S10_MPFE_HMC_ADP_DDRIOCTRL		0xf8011008
+#define HMC_ADP_DDRIOCTRL			0x8
+#define HMC_ADP_DDRIOCTRL_IO_SIZE(x)		(((x) & 0x00000003) >> 0)
+#define HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(x)	(((x) & 0x00003e00) >> 9)
+#define ADP_DRAMADDRWIDTH			0xe0
+
+#define ACT_TO_ACT_DIFF_BANK(value) (((value) & 0x00fc0000) >> 18)
+#define ACT_TO_ACT(value) (((value) & 0x0003f000) >> 12)
+#define ACT_TO_RDWR(value) (((value) & 0x0000003f) >> 0)
+#define ACT_TO_ACT(value) (((value) & 0x0003f000) >> 12)
+
+/* timing 2 */
+#define RD_TO_RD_DIFF_CHIP(value) (((value) & 0x00000fc0) >> 6)
+#define RD_TO_WR_DIFF_CHIP(value) (((value) & 0x3f000000) >> 24)
+#define RD_TO_WR(value) (((value) & 0x00fc0000) >> 18)
+#define RD_TO_PCH(value) (((value) & 0x00000fc0) >> 6)
+
+/* timing 3 */
+#define CALTIMING3_WR_TO_RD_DIFF_CHIP(value) (((value) & 0x0003f000) >> 12)
+#define CALTIMING3_WR_TO_RD(value) (((value) & 0x00000fc0) >> 6)
+
+/* timing 4 */
+#define PCH_TO_VALID(value) (((value) & 0x00000fc0) >> 6)
+
+#define DDRTIMING_BWRATIO_OFST		31
+#define DDRTIMING_WRTORD_OFST			26
+#define DDRTIMING_RDTOWR_OFST			21
+#define DDRTIMING_BURSTLEN_OFST		18
+#define DDRTIMING_WRTOMISS_OFST		12
+#define DDRTIMING_RDTOMISS_OFST		6
+#define DDRTIMING_ACTTOACT_OFST		0
+
+#define ADP_DDRIOCTRL_IO_SIZE(x)	(((x) & 0x00000003) >> 0)
+
+#define DDRMODE_AUTOPRECHARGE_OFST 1
+#define DDRMODE_BWRATIOEXTENDED_OFST 0
+
+
+#define S10_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(x) (((x) & 0x0000007f) >> 0)
+#define S10_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(x) (((x) & 0x0000000f) >> 0)
+
+#define S10_CCU_CPU0_MPRT_DDR		0xf7004400
+#define S10_CCU_CPU0_MPRT_MEM0		0xf70045c0
+#define S10_CCU_CPU0_MPRT_MEM1A		0xf70045e0
+#define S10_CCU_CPU0_MPRT_MEM1B		0xf7004600
+#define S10_CCU_CPU0_MPRT_MEM1C		0xf7004620
+#define S10_CCU_CPU0_MPRT_MEM1D		0xf7004640
+#define S10_CCU_CPU0_MPRT_MEM1E		0xf7004660
+#define S10_CCU_IOM_MPRT_MEM0		0xf7018560
+#define S10_CCU_IOM_MPRT_MEM1A		0xf7018580
+#define	S10_CCU_IOM_MPRT_MEM1B		0xf70185a0
+#define	S10_CCU_IOM_MPRT_MEM1C		0xf70185c0
+#define	S10_CCU_IOM_MPRT_MEM1D		0xf70185e0
+#define	S10_CCU_IOM_MPRT_MEM1E		0xf7018600
+
+#define S10_NOC_FW_DDR_SCR				0xf8020100
+#define S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT	0xf802011c
+#define S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT		0xf8020118
+#define S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT	0xf802019c
+#define S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT	0xf8020198
+
+#define S10_SOC_NOC_FW_DDR_SCR_ENABLE			0xf8020100
+#define S10_CCU_NOC_DI_SET_MSK			0x10
+
+#define S10_SYSMGR_CORE_HMC_CLK			0xffd120b4
+#define S10_SYSMGR_CORE_HMC_CLK_STATUS		0x00000001
+
+#define S10_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0(x) (((x) & 0x0000ffff) >> 0)
+#define S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_MSK    0x00000003
+#define S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_OFST    0
+#define S10_MPFE_HMC_ADP_HPSINTFCSEL_ENABLE 0x001f1f1f
+#define S10_IOHMC_CTRLCFG1_ENABLE_ECC_OFST 7
+
+#define S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK    0x00010000
+#define S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK    0x00000100
+#define S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK    0x00000001
+
+#define S10_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK    0x00000001
+#define S10_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK    0x00010000
+#define S10_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK    0x00000100
+#define S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(value) (((value) & 0x00000001) >> 0)
+
+
+#define S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(x)	(((x) & 0x00000003) >> 0)
+#define IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) (((x) & 0x00003c00) >> 10)
+#define IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(x) (((x) & 0x0000c000) >> 14)
+#define IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(x) (((x) & 0x0000001f) >> 0)
+#define IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(x) (((x) & 0x00070000) >> 16)
+#define IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) (((x) & 0x000003e0) >> 5)
+
+#define S10_SDRAM_0_LB_ADDR 0x0
+
+int init_hard_memory_controller(void);
+
+#endif
diff --git a/plat/intel/soc/stratix10/include/s10_noc.h b/plat/intel/soc/stratix10/include/s10_noc.h
new file mode 100644
index 0000000..3e1e527
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_noc.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define AXI_AP				(1<<0)
+#define FPGA2SOC			(1<<16)
+#define MPU				(1<<24)
+#define S10_NOC_PER_SCR_NAND		0xffd21000
+#define S10_NOC_PER_SCR_NAND_DATA	0xffd21004
+#define S10_NOC_PER_SCR_USB0		0xffd2100c
+#define S10_NOC_PER_SCR_USB1		0xffd21010
+#define S10_NOC_PER_SCR_SPI_M0		0xffd2101c
+#define S10_NOC_PER_SCR_SPI_M1		0xffd21020
+#define S10_NOC_PER_SCR_SPI_S0		0xffd21024
+#define S10_NOC_PER_SCR_SPI_S1		0xffd21028
+#define S10_NOC_PER_SCR_EMAC0		0xffd2102c
+#define S10_NOC_PER_SCR_EMAC1		0xffd21030
+#define S10_NOC_PER_SCR_EMAC2		0xffd21034
+#define S10_NOC_PER_SCR_SDMMC		0xffd21040
+#define S10_NOC_PER_SCR_GPIO0		0xffd21044
+#define S10_NOC_PER_SCR_GPIO1		0xffd21048
+#define S10_NOC_PER_SCR_I2C0		0xffd21050
+#define S10_NOC_PER_SCR_I2C1		0xffd21058
+#define S10_NOC_PER_SCR_I2C2		0xffd2105c
+#define S10_NOC_PER_SCR_I2C3		0xffd21060
+#define S10_NOC_PER_SCR_SP_TIMER0	0xffd21064
+#define S10_NOC_PER_SCR_SP_TIMER1	0xffd21068
+#define S10_NOC_PER_SCR_UART0		0xffd2106c
+#define S10_NOC_PER_SCR_UART1		0xffd21070
+
+
+#define S10_NOC_SYS_SCR_DMA_ECC			0xffd21108
+#define S10_NOC_SYS_SCR_EMAC0RX_ECC		0xffd2110c
+#define S10_NOC_SYS_SCR_EMAC0TX_ECC		0xffd21110
+#define S10_NOC_SYS_SCR_EMAC1RX_ECC		0xffd21114
+#define S10_NOC_SYS_SCR_EMAC1TX_ECC		0xffd21118
+#define S10_NOC_SYS_SCR_EMAC2RX_ECC		0xffd2111c
+#define S10_NOC_SYS_SCR_EMAC2TX_ECC		0xffd21120
+#define S10_NOC_SYS_SCR_NAND_ECC		0xffd2112c
+#define S10_NOC_SYS_SCR_NAND_READ_ECC		0xffd21130
+#define S10_NOC_SYS_SCR_NAND_WRITE_ECC		0xffd21134
+#define S10_NOC_SYS_SCR_OCRAM_ECC		0xffd21138
+#define S10_NOC_SYS_SCR_SDMMC_ECC		0xffd21140
+#define S10_NOC_SYS_SCR_USB0_ECC		0xffd21144
+#define S10_NOC_SYS_SCR_USB1_ECC		0xffd21148
+#define S10_NOC_SYS_SCR_CLK_MGR			0xffd2114c
+#define S10_NOC_SYS_SCR_IO_MGR			0xffd21154
+#define S10_NOC_SYS_SCR_RST_MGR			0xffd21158
+#define S10_NOC_SYS_SCR_SYS_MGR			0xffd2115c
+#define S10_NOC_SYS_SCR_OSC0_TIMER		0xffd21160
+#define S10_NOC_SYS_SCR_OSC1_TIMER		0xffd21164
+#define S10_NOC_SYS_SCR_WATCHDOG0		0xffd21168
+#define S10_NOC_SYS_SCR_WATCHDOG1		0xffd2116c
+#define S10_NOC_SYS_SCR_WATCHDOG2		0xffd21170
+#define S10_NOC_SYS_SCR_WATCHDOG3		0xffd21174
+#define S10_NOC_SYS_SCR_DAP			0xffd21178
+#define S10_NOC_SYS_SCR_L4_NOC_PROBES		0xffd21190
+#define S10_NOC_SYS_SCR_L4_NOC_QOS		0xffd21194
+
+#define S10_CCU_NOC_BRIDGE_CPU0_RAM		0xf7004688
+#define S10_CCU_NOC_BRIDGE_IOM_RAM		0xf7004688
diff --git a/plat/intel/soc/stratix10/include/s10_pinmux.h b/plat/intel/soc/stratix10/include/s10_pinmux.h
new file mode 100644
index 0000000..a1ba29e
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_pinmux.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __S10_PINMUX_H__
+#define __S10_PINMUX_H__
+
+#define S10_PINMUX_PIN0SEL		0xffd13000
+#define S10_PINMUX_IO0CTRL		0xffd13130
+#define S10_PINMUX_PINMUX_EMAC0_USEFPGA	0xffd13300
+#define S10_PINMUX_IO0_DELAY		0xffd13400
+
+#include "s10_handoff.h"
+
+void config_pinmux(handoff *handoff);
+
+#endif
+
diff --git a/plat/intel/soc/stratix10/include/s10_reset_manager.h b/plat/intel/soc/stratix10/include/s10_reset_manager.h
new file mode 100644
index 0000000..731a8dd
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_reset_manager.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __S10_RESETMANAGER_H__
+#define __S10_RESETMANAGER_H__
+
+#define S10_RSTMGR_PER0MODRST				0xffd11024
+#define S10_RSTMGR_PER1MODRST				0xffd11028
+#define S10_RSTMGR_HDSKEN					0xffd11010
+
+#define S10_RSTMGR_PER0MODRST_EMAC0			0x00000001
+#define S10_RSTMGR_PER0MODRST_EMAC1			0x00000002
+#define S10_RSTMGR_PER0MODRST_EMAC2			0x00000004
+#define S10_RSTMGR_PER0MODRST_EMAC0OCP		0x00000100
+#define S10_RSTMGR_PER0MODRST_EMAC1OCP		0x00000200
+#define S10_RSTMGR_PER0MODRST_DMAOCP		0x00200000
+#define S10_RSTMGR_PER0MODRST_DMA			0x00010000
+#define S10_RSTMGR_PER0MODRST_EMAC0			0x00000001
+#define S10_RSTMGR_PER0MODRST_EMAC1			0x00000002
+#define S10_RSTMGR_PER0MODRST_EMAC2OCP		0x00000400
+#define S10_RSTMGR_PER0MODRST_EMAC2			0x00000004
+#define S10_RSTMGR_PER0MODRST_EMACPTP		0x00400000
+#define S10_RSTMGR_PER0MODRST_NANDOCP		0x00002000
+#define S10_RSTMGR_PER0MODRST_NAND			0x00000020
+#define S10_RSTMGR_PER0MODRST_SDMMCOCP		0x00008000
+#define S10_RSTMGR_PER0MODRST_SDMMC			0x00000080
+#define S10_RSTMGR_PER0MODRST_SPIM0			0x00020000
+#define S10_RSTMGR_PER0MODRST_SPIM1			0x00040000
+#define S10_RSTMGR_PER0MODRST_SPIS0			0x00080000
+#define S10_RSTMGR_PER0MODRST_SPIS1			0x00100000
+#define S10_RSTMGR_PER0MODRST_USB0OCP		0x00000800
+#define S10_RSTMGR_PER0MODRST_USB0			0x00000008
+#define S10_RSTMGR_PER0MODRST_USB1OCP		0x00001000
+#define S10_RSTMGR_PER0MODRST_USB1			0x00000010
+
+#define S10_RSTMGR_PER1MODRST_WATCHDOG0		0x1
+#define S10_RSTMGR_PER1MODRST_WATCHDOG1		0x2
+#define S10_RSTMGR_PER1MODRST_WATCHDOG2		0x4
+#define S10_RSTMGR_PER1MODRST_WATCHDOG3		0x8
+#define S10_RSTMGR_PER1MODRST_GPIO0			0x01000000
+#define S10_RSTMGR_PER1MODRST_GPIO0			0x01000000
+#define S10_RSTMGR_PER1MODRST_GPIO1			0x02000000
+#define S10_RSTMGR_PER1MODRST_GPIO1			0x02000000
+#define S10_RSTMGR_PER1MODRST_I2C0			0x00000100
+#define S10_RSTMGR_PER1MODRST_I2C0			0x00000100
+#define S10_RSTMGR_PER1MODRST_I2C1			0x00000200
+#define S10_RSTMGR_PER1MODRST_I2C1			0x00000200
+#define S10_RSTMGR_PER1MODRST_I2C2			0x00000400
+#define S10_RSTMGR_PER1MODRST_I2C2			0x00000400
+#define S10_RSTMGR_PER1MODRST_I2C3			0x00000800
+#define S10_RSTMGR_PER1MODRST_I2C3			0x00000800
+#define S10_RSTMGR_PER1MODRST_I2C4			0x00001000
+#define S10_RSTMGR_PER1MODRST_I2C4			0x00001000
+#define S10_RSTMGR_PER1MODRST_L4SYSTIMER0	0x00000010
+#define S10_RSTMGR_PER1MODRST_L4SYSTIMER1	0x00000020
+#define S10_RSTMGR_PER1MODRST_SPTIMER0		0x00000040
+#define S10_RSTMGR_PER1MODRST_SPTIMER0		0x00000040
+#define S10_RSTMGR_PER1MODRST_SPTIMER1		0x00000080
+#define S10_RSTMGR_PER1MODRST_SPTIMER1		0x00000080
+#define S10_RSTMGR_PER1MODRST_UART0			0x00010000
+#define S10_RSTMGR_PER1MODRST_UART0			0x00010000
+#define S10_RSTMGR_PER1MODRST_UART1			0x00020000
+#define S10_RSTMGR_PER1MODRST_UART1			0x00020000
+#define S10_RSTMGR_HDSKEN_DEBUG_L3NOC		0x00020000
+#define S10_RSTMGR_HDSKEN_ETRSTALLEN		0x00000008
+#define S10_RSTMGR_HDSKEN_FPGAHSEN			0x00000004
+#define S10_RSTMGR_HDSKEN_L2FLUSHEN			0x00000100
+#define S10_RSTMGR_HDSKEN_L3NOC_DBG			0x00010000
+
+#define S10_RSTMGR_HDSKEN_SDRSELFREFEN		0x00000001
+#define S10_RSTMGR_PER0MODRST_DMAIF0		0x01000000
+#define S10_RSTMGR_PER0MODRST_DMAIF1		0x02000000
+#define S10_RSTMGR_PER0MODRST_DMAIF2		0x04000000
+#define S10_RSTMGR_PER0MODRST_DMAIF3		0x08000000
+#define S10_RSTMGR_PER0MODRST_DMAIF4		0x10000000
+#define S10_RSTMGR_PER0MODRST_DMAIF5		0x20000000
+#define S10_RSTMGR_PER0MODRST_DMAIF6		0x40000000
+#define S10_RSTMGR_PER0MODRST_DMAIF7		0x80000000
+
+void deassert_peripheral_reset(void);
+void config_hps_hs_before_warm_reset(void);
+
+#endif
+
diff --git a/plat/intel/soc/stratix10/include/s10_system_manager.h b/plat/intel/soc/stratix10/include/s10_system_manager.h
new file mode 100644
index 0000000..4500c6f
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/s10_system_manager.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define S10_NOC_FW_L4_PER_SCR_NAND_REGISTER	0xffd21000
+#define S10_NOC_FW_L4_PER_SCR_NAND_DATA		0xffd21004
+#define S10_NOC_FW_L4_PER_SCR_USB0_REGISTER	0xffd2100c
+#define S10_NOC_FW_L4_PER_SCR_USB1_REGISTER	0xffd21010
+#define S10_NOC_FW_L4_PER_SCR_SPI_MASTER0	0xffd2101c
+#define S10_NOC_FW_L4_PER_SCR_SPI_MASTER1	0xffd21020
+#define S10_NOC_FW_L4_PER_SCR_SPI_SLAVE0	0xffd21024
+#define S10_NOC_FW_L4_PER_SCR_SPI_SLAVE1	0xffd21028
+#define S10_NOC_FW_L4_PER_SCR_EMAC0		0xffd2102c
+#define S10_NOC_FW_L4_PER_SCR_EMAC1		0xffd21030
+#define S10_NOC_FW_L4_PER_SCR_EMAC2		0xffd21034
+#define S10_NOC_FW_L4_PER_SCR_SDMMC		0xffd21040
+#define S10_NOC_FW_L4_PER_SCR_GPIO0		0xffd21044
+#define S10_NOC_FW_L4_PER_SCR_GPIO1		0xffd21048
+#define S10_NOC_FW_L4_PER_SCR_I2C0		0xffd21050
+#define S10_NOC_FW_L4_PER_SCR_I2C1		0xffd21054
+#define S10_NOC_FW_L4_PER_SCR_I2C2		0xffd21058
+#define S10_NOC_FW_L4_PER_SCR_I2C3		0xffd2105c
+#define S10_NOC_FW_L4_PER_SCR_I2C4		0xffd21060
+#define S10_NOC_FW_L4_PER_SCR_SP_TIMER0		0xffd21064
+#define S10_NOC_FW_L4_PER_SCR_SP_TIMER1		0xffd21068
+#define S10_NOC_FW_L4_PER_SCR_UART0		0xffd2106c
+#define S10_NOC_FW_L4_PER_SCR_UART1		0xffd21070
+
+#define S10_NOC_FW_L4_SYS_SCR_DMA_ECC		0xffd21108
+#define S10_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC	0xffd2110c
+#define S10_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC	0xffd21110
+#define S10_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC	0xffd21114
+#define S10_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC	0xffd21118
+#define S10_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC	0xffd2111c
+#define S10_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC	0xffd21120
+#define S10_NOC_FW_L4_SYS_SCR_NAND_ECC		0xffd2112c
+#define S10_NOC_FW_L4_SYS_SCR_NAND_READ_ECC	0xffd21130
+#define S10_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC	0xffd21134
+#define S10_NOC_FW_L4_SYS_SCR_OCRAM_ECC		0xffd21138
+#define S10_NOC_FW_L4_SYS_SCR_SDMMC_ECC		0xffd21140
+#define S10_NOC_FW_L4_SYS_SCR_USB0_ECC		0xffd21144
+#define S10_NOC_FW_L4_SYS_SCR_USB1_ECC		0xffd21148
+#define S10_NOC_FW_L4_SYS_SCR_CLK_MGR		0xffd2114c
+#define S10_NOC_FW_L4_SYS_SCR_IO_MGR		0xffd21154
+#define S10_NOC_FW_L4_SYS_SCR_RST_MGR		0xffd21158
+#define S10_NOC_FW_L4_SYS_SCR_SYS_MGR		0xffd2115c
+#define S10_NOC_FW_L4_SYS_SCR_OSC0_TIMER	0xffd21160
+#define S10_NOC_FW_L4_SYS_SCR_OSC1_TIMER	0xffd21164
+#define S10_NOC_FW_L4_SYS_SCR_WATCHDOG0		0xffd21168
+#define S10_NOC_FW_L4_SYS_SCR_WATCHDOG1		0xffd2116c
+#define S10_NOC_FW_L4_SYS_SCR_WATCHDOG2		0xffd21170
+#define S10_NOC_FW_L4_SYS_SCR_WATCHDOG3		0xffd21174
+#define S10_NOC_FW_L4_SYS_SCR_DAP		0xffd21178
+#define S10_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES	0xffd21190
+#define S10_NOC_FW_L4_SYS_SCR_L4_NOC_QOS	0xffd21194
+
+#define S10_CCU_NOC_CPU0_RAMSPACE0_0		0xf7004688
+#define S10_CCU_NOC_IOM_RAMSPACE0_0		0xf7018628
+
+#define S10_SYSMGR_CORE(x)			(0xffd12000 + (x))
+#define SYSMGR_MMC				0x28
+#define SYSMGR_MMC_DRVSEL(x)			(((x) & 0x7) << 0)
+
+
+#define DISABLE_L4_FIREWALL	(BIT(0) | BIT(16) | BIT(24))
+
+void enable_nonsecure_access(void);
+
diff --git a/plat/intel/soc/stratix10/include/stratix10_private.h b/plat/intel/soc/stratix10/include/stratix10_private.h
new file mode 100644
index 0000000..f437202
--- /dev/null
+++ b/plat/intel/soc/stratix10/include/stratix10_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __S10_PRIVATE_H__
+#define __S10_PRIVATE_H__
+
+#define S10_MMC_REG_BASE	0xff808000
+
+#define EMMC_DESC_SIZE		(1<<20)
+#define EMMC_INIT_PARAMS(base)			\
+	{	.bus_width = MMC_BUS_WIDTH_4,	\
+		.clk_rate = 50000000,		\
+		.desc_base = (base),		\
+		.desc_size = EMMC_DESC_SIZE,	\
+		.flags = 0,			\
+		.reg_base = S10_MMC_REG_BASE,	\
+		\
+	}
+
+typedef enum {
+	BOOT_SOURCE_FPGA = 0,
+	BOOT_SOURCE_SDMMC,
+	BOOT_SOURCE_NAND,
+	BOOT_SOURCE_RSVD,
+	BOOT_SOURCE_QSPI,
+} boot_source_type;
+
+void enable_nonsecure_access(void);
+void stratix10_io_setup(int boot_source);
+
+#endif
diff --git a/plat/intel/soc/stratix10/plat_psci.c b/plat/intel/soc/stratix10/plat_psci.c
new file mode 100644
index 0000000..f4a970e
--- /dev/null
+++ b/plat/intel/soc/stratix10/plat_psci.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <plat/common/platform.h>
+#include <lib/psci/psci.h>
+
+#include "platform_def.h"
+#include "s10_reset_manager.h"
+#include "s10_mailbox.h"
+
+#define S10_RSTMGR_OFST			0xffd11000
+#define S10_RSTMGR_MPUMODRST_OFST	0x20
+
+uintptr_t *stratix10_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY;
+uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE;
+
+/*******************************************************************************
+ * plat handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+	/*
+	 * Enter standby state
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
+	dsb();
+	wfi();
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+int plat_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+	if (cpu_id == -1)
+		return PSCI_E_INTERN_FAIL;
+
+	*cpuid_release = cpu_id;
+
+	/* release core reset */
+	mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void plat_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* TODO: Prevent interrupts from spuriously waking up this cpu */
+	/* gicv2_cpuif_disable(); */
+
+	/* assert core reset */
+	mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void plat_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+	/* assert core reset */
+	mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void plat_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+
+	/* Enable the gic cpu interface */
+	gicv2_cpuif_enable();
+}
+
+/*******************************************************************************
+ * plat handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ ******************************************************************************/
+void plat_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* release core reset */
+	mmio_clrbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST,
+		1 << cpu_id);
+}
+
+/*******************************************************************************
+ * plat handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 plat_system_off(void)
+{
+	wfi();
+	ERROR("System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 plat_system_reset(void)
+{
+	INFO("assert Peripheral from Reset\r\n");
+
+	deassert_peripheral_reset();
+	mailbox_reset_cold();
+
+	while (1)
+		wfi();
+}
+
+int plat_validate_power_state(unsigned int power_state,
+				psci_power_state_t *req_state)
+{
+	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+	return PSCI_E_SUCCESS;
+}
+
+int plat_validate_ns_entrypoint(unsigned long ns_entrypoint)
+{
+	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
+	return PSCI_E_SUCCESS;
+}
+
+void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+const plat_psci_ops_t plat_psci_pm_ops = {
+	.cpu_standby = plat_cpu_standby,
+	.pwr_domain_on = plat_pwr_domain_on,
+	.pwr_domain_off = plat_pwr_domain_off,
+	.pwr_domain_suspend = plat_pwr_domain_suspend,
+	.pwr_domain_on_finish = plat_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = plat_pwr_domain_suspend_finish,
+	.system_off = plat_system_off,
+	.system_reset = plat_system_reset,
+	.validate_power_state = plat_validate_power_state,
+	.validate_ns_entrypoint = plat_validate_ns_entrypoint,
+	.get_sys_suspend_power_state = plat_get_sys_suspend_power_state
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	/* Save warm boot entrypoint.*/
+	*stratix10_sec_entry = sec_entrypoint;
+
+	*psci_ops = &plat_psci_pm_ops;
+	return 0;
+}
diff --git a/plat/intel/soc/stratix10/plat_sip_svc.c b/plat/intel/soc/stratix10/plat_sip_svc.c
new file mode 100644
index 0000000..2c2332b
--- /dev/null
+++ b/plat/intel/soc/stratix10/plat_sip_svc.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <s10_mailbox.h>
+#include <tools_share/uuid.h>
+
+/* Number of SiP Calls implemented */
+#define SIP_NUM_CALLS		0x3
+
+/* Total buffer the driver can hold */
+#define FPGA_CONFIG_BUFFER_SIZE 4
+
+int current_block;
+int current_buffer;
+int current_id = 1;
+int max_blocks;
+uint32_t bytes_per_block;
+uint32_t blocks_submitted;
+uint32_t blocks_completed;
+
+struct fpga_config_info {
+	uint32_t addr;
+	int size;
+	int size_written;
+	uint32_t write_requested;
+	int subblocks_sent;
+	int block_number;
+};
+
+/*  SiP Service UUID */
+DEFINE_SVC_UUID2(intl_svc_uid,
+		0xa85273b0, 0xe85a, 0x4862, 0xa6, 0x2a,
+		0xfa, 0x88, 0x88, 0x17, 0x68, 0x81);
+
+uint64_t plat_sip_handler(uint32_t smc_fid,
+				   uint64_t x1,
+				   uint64_t x2,
+				   uint64_t x3,
+				   uint64_t x4,
+				   void *cookie,
+				   void *handle,
+				   uint64_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+struct fpga_config_info fpga_config_buffers[FPGA_CONFIG_BUFFER_SIZE];
+
+static void intel_fpga_sdm_write_buffer(struct fpga_config_info *buffer)
+{
+	uint32_t args[3];
+
+	while (max_blocks > 0 && buffer->size > buffer->size_written) {
+		if (buffer->size - buffer->size_written <=
+			bytes_per_block) {
+			args[0] = (1<<8);
+			args[1] = buffer->addr + buffer->size_written;
+			args[2] = buffer->size - buffer->size_written;
+			buffer->size_written +=
+				buffer->size - buffer->size_written;
+			buffer->subblocks_sent++;
+			mailbox_send_cmd_async(0x4,
+				MBOX_RECONFIG_DATA,
+				args, 3, 0);
+			current_buffer++;
+			current_buffer %= FPGA_CONFIG_BUFFER_SIZE;
+		} else {
+			args[0] = (1<<8);
+			args[1] = buffer->addr + buffer->size_written;
+			args[2] = bytes_per_block;
+			buffer->size_written += bytes_per_block;
+			mailbox_send_cmd_async(0x4,
+				MBOX_RECONFIG_DATA,
+				args, 3, 0);
+			buffer->subblocks_sent++;
+		}
+		max_blocks--;
+	}
+}
+
+static int intel_fpga_sdm_write_all(void)
+{
+	int i;
+
+	for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++)
+		intel_fpga_sdm_write_buffer(
+			&fpga_config_buffers[current_buffer]);
+
+	return 0;
+}
+
+uint32_t intel_mailbox_fpga_config_isdone(void)
+{
+	uint32_t args[2];
+	uint32_t response[6];
+	int status;
+
+	status = mailbox_send_cmd(1, MBOX_RECONFIG_STATUS, args, 0, 0,
+				response);
+
+	if (status < 0)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if (response[RECONFIG_STATUS_STATE] &&
+		response[RECONFIG_STATUS_STATE] != MBOX_CFGSTAT_STATE_CONFIG)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if (!(response[RECONFIG_STATUS_PIN_STATUS] & PIN_STATUS_NSTATUS))
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if (response[RECONFIG_STATUS_SOFTFUNC_STATUS] &
+		SOFTFUNC_STATUS_SEU_ERROR)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	if ((response[RECONFIG_STATUS_SOFTFUNC_STATUS] &
+		SOFTFUNC_STATUS_CONF_DONE) &&
+		(response[RECONFIG_STATUS_SOFTFUNC_STATUS] &
+		SOFTFUNC_STATUS_INIT_DONE))
+		return INTEL_SIP_SMC_STATUS_OK;
+
+	return INTEL_SIP_SMC_STATUS_ERROR;
+}
+
+static int mark_last_buffer_xfer_completed(uint32_t *buffer_addr_completed)
+{
+	int i;
+
+	for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		if (fpga_config_buffers[i].block_number == current_block) {
+			fpga_config_buffers[i].subblocks_sent--;
+			if (fpga_config_buffers[i].subblocks_sent == 0
+			&& fpga_config_buffers[i].size <=
+			fpga_config_buffers[i].size_written) {
+				fpga_config_buffers[i].write_requested = 0;
+				current_block++;
+				*buffer_addr_completed =
+					fpga_config_buffers[i].addr;
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+unsigned int address_in_ddr(uint32_t *addr)
+{
+	if (((unsigned long long)addr > DRAM_BASE) &&
+		((unsigned long long)addr < DRAM_BASE + DRAM_SIZE))
+		return 0;
+
+	return -1;
+}
+
+int intel_fpga_config_completed_write(uint32_t *completed_addr,
+					uint32_t *count)
+{
+	uint32_t status = INTEL_SIP_SMC_STATUS_OK;
+	*count = 0;
+	int resp_len = 0;
+	uint32_t resp[5];
+	int all_completed = 1;
+	int count_check = 0;
+
+	if (address_in_ddr(completed_addr) != 0 || address_in_ddr(count) != 0)
+		return INTEL_SIP_SMC_STATUS_ERROR;
+
+	for (count_check = 0; count_check < 3; count_check++)
+		if (address_in_ddr(&completed_addr[*count + count_check]) != 0)
+			return INTEL_SIP_SMC_STATUS_ERROR;
+
+	resp_len = mailbox_read_response(0x4, resp);
+
+	while (resp_len >= 0 && *count < 3) {
+		max_blocks++;
+		if (mark_last_buffer_xfer_completed(
+			&completed_addr[*count]) == 0)
+			*count = *count + 1;
+		else
+			break;
+		resp_len = mailbox_read_response(0x4, resp);
+	}
+
+	if (*count <= 0) {
+		if (resp_len != MBOX_NO_RESPONSE &&
+			resp_len != MBOX_TIMEOUT && resp_len != 0) {
+			return INTEL_SIP_SMC_STATUS_ERROR;
+		}
+
+		*count = 0;
+	}
+
+	intel_fpga_sdm_write_all();
+
+	if (*count > 0)
+		status = INTEL_SIP_SMC_STATUS_OK;
+	else if (*count == 0)
+		status = INTEL_SIP_SMC_STATUS_BUSY;
+
+	for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		if (fpga_config_buffers[i].write_requested != 0) {
+			all_completed = 0;
+			break;
+		}
+	}
+
+	if (all_completed == 1)
+		return INTEL_SIP_SMC_STATUS_OK;
+
+	return status;
+}
+
+int intel_fpga_config_start(uint32_t config_type)
+{
+	uint32_t response[3];
+	int status = 0;
+
+	status = mailbox_send_cmd(2, MBOX_RECONFIG, 0, 0, 0,
+			response);
+
+	if (status < 0)
+		return status;
+
+	max_blocks = response[0];
+	bytes_per_block = response[1];
+
+	for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		fpga_config_buffers[i].size = 0;
+		fpga_config_buffers[i].size_written = 0;
+		fpga_config_buffers[i].addr = 0;
+		fpga_config_buffers[i].write_requested = 0;
+		fpga_config_buffers[i].block_number = 0;
+		fpga_config_buffers[i].subblocks_sent = 0;
+	}
+
+	blocks_submitted = 0;
+	current_block = 0;
+	current_buffer = 0;
+
+	return 0;
+}
+
+
+uint32_t intel_fpga_config_write(uint64_t mem, uint64_t size)
+{
+	int i = 0;
+	uint32_t status = INTEL_SIP_SMC_STATUS_OK;
+
+	if (mem < DRAM_BASE || mem > DRAM_BASE + DRAM_SIZE)
+		status = INTEL_SIP_SMC_STATUS_REJECTED;
+
+	if (mem + size > DRAM_BASE + DRAM_SIZE)
+		status = INTEL_SIP_SMC_STATUS_REJECTED;
+
+	for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) {
+		if (!fpga_config_buffers[i].write_requested) {
+			fpga_config_buffers[i].addr = mem;
+			fpga_config_buffers[i].size = size;
+			fpga_config_buffers[i].size_written = 0;
+			fpga_config_buffers[i].write_requested = 1;
+			fpga_config_buffers[i].block_number =
+				blocks_submitted++;
+			fpga_config_buffers[i].subblocks_sent = 0;
+			break;
+		}
+	}
+
+
+	if (i == FPGA_CONFIG_BUFFER_SIZE) {
+		status = INTEL_SIP_SMC_STATUS_REJECTED;
+		return status;
+	} else if (i == FPGA_CONFIG_BUFFER_SIZE - 1) {
+		status = INTEL_SIP_SMC_STATUS_BUSY;
+	}
+
+	intel_fpga_sdm_write_all();
+
+	return status;
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+
+uintptr_t sip_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	uint32_t status = INTEL_SIP_SMC_STATUS_OK;
+	uint32_t completed_addr[3];
+	uint32_t count = 0;
+
+	switch (smc_fid) {
+	case SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, intl_svc_uid);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_ISDONE:
+		status = intel_mailbox_fpga_config_isdone();
+		SMC_RET4(handle, status, 0, 0, 0);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM:
+		SMC_RET3(handle, INTEL_SIP_SMC_STATUS_OK,
+			INTEL_SIP_SMC_FPGA_CONFIG_ADDR,
+			INTEL_SIP_SMC_FPGA_CONFIG_SIZE -
+				INTEL_SIP_SMC_FPGA_CONFIG_ADDR);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_START:
+		status = intel_fpga_config_start(x1);
+		SMC_RET4(handle, status, 0, 0, 0);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_WRITE:
+		status = intel_fpga_config_write(x1, x2);
+		SMC_RET4(handle, status, 0, 0, 0);
+		break;
+	case INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE:
+		status = intel_fpga_config_completed_write(completed_addr,
+								&count);
+		switch (count) {
+		case 1:
+			SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+				completed_addr[0], 0, 0);
+			break;
+		case 2:
+			SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+				completed_addr[0],
+				completed_addr[1], 0);
+			break;
+		case 3:
+			SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK,
+				completed_addr[0],
+				completed_addr[1],
+				completed_addr[2]);
+			break;
+		case 0:
+			SMC_RET4(handle, status, 0, 0, 0);
+			break;
+		default:
+			SMC_RET1(handle, INTEL_SIP_SMC_STATUS_ERROR);
+		}
+		break;
+
+	default:
+		return plat_sip_handler(smc_fid, x1, x2, x3, x4,
+			cookie, handle, flags);
+	}
+}
+
+DECLARE_RT_SVC(
+	s10_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	sip_smc_handler
+);
+
+DECLARE_RT_SVC(
+	s10_sip_svc_std,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_YIELD,
+	NULL,
+	sip_smc_handler
+);
diff --git a/plat/intel/soc/stratix10/plat_storage.c b/plat/intel/soc/stratix10/plat_storage.c
new file mode 100644
index 0000000..0b8b9cd
--- /dev/null
+++ b/plat/intel/soc/stratix10/plat_storage.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/mmc.h>
+#include <tools_share/firmware_image_package.h>
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <lib/mmio.h>
+#include <drivers/partition/partition.h>
+#include <lib/semihosting.h>
+#include <string.h>
+#include <lib/utils.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include "platform_def.h"
+#include "stratix10_private.h"
+
+#define STRATIX10_FIP_BASE		(0)
+#define STRATIX10_FIP_MAX_SIZE		(0x1000000)
+#define STRATIX10_MMC_DATA_BASE		(0xffe3c000)
+#define STRATIX10_MMC_DATA_SIZE		(0x2000)
+#define STRATIX10_QSPI_DATA_BASE	(0x3C00000)
+#define STRATIX10_QSPI_DATA_SIZE	(0x1000000)
+
+
+static const io_dev_connector_t *fip_dev_con;
+static const io_dev_connector_t *boot_dev_con;
+
+static uintptr_t fip_dev_handle;
+static uintptr_t boot_dev_handle;
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+uintptr_t a2_lba_offset;
+const char a2[] = {0xa2, 0x0};
+
+static const io_block_spec_t gpt_block_spec = {
+	.offset = 0,
+	.length = MMC_BLOCK_SIZE
+};
+
+static int check_fip(const uintptr_t spec);
+static int check_dev(const uintptr_t spec);
+
+static io_block_dev_spec_t boot_dev_spec;
+static int (*register_io_dev)(const io_dev_connector_t **);
+
+static io_block_spec_t fip_spec = {
+	.offset		= STRATIX10_FIP_BASE,
+	.length		= STRATIX10_FIP_MAX_SIZE,
+};
+
+struct plat_io_policy {
+	uintptr_t       *dev_handle;
+	uintptr_t       image_spec;
+	int             (*check)(const uintptr_t spec);
+};
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&boot_dev_handle,
+		(uintptr_t)&fip_spec,
+		check_dev
+	},
+	[BL2_IMAGE_ID] = {
+	  &fip_dev_handle,
+	  (uintptr_t)&bl2_uuid_spec,
+	  check_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		check_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t) &bl33_uuid_spec,
+		check_fip
+	},
+	[GPT_IMAGE_ID] = {
+		&boot_dev_handle,
+		(uintptr_t) &gpt_block_spec,
+		check_dev
+	},
+};
+
+static int check_dev(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(boot_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(boot_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0)
+			io_close(local_image_handle);
+	}
+	return result;
+}
+
+void stratix10_io_setup(int boot_source)
+{
+	int result;
+
+	switch (boot_source) {
+	case BOOT_SOURCE_SDMMC:
+		register_io_dev = &register_io_dev_block;
+		boot_dev_spec.buffer.offset	= STRATIX10_MMC_DATA_BASE;
+		boot_dev_spec.buffer.length	= MMC_BLOCK_SIZE;
+		boot_dev_spec.ops.read		= mmc_read_blocks;
+		boot_dev_spec.ops.write		= mmc_write_blocks;
+		boot_dev_spec.block_size	= MMC_BLOCK_SIZE;
+		break;
+
+	case BOOT_SOURCE_QSPI:
+		register_io_dev = &register_io_dev_memmap;
+		fip_spec.offset = fip_spec.offset + STRATIX10_QSPI_DATA_BASE;
+		break;
+
+	default:
+		ERROR("Unsupported boot source\n");
+		panic();
+		break;
+	}
+
+	result = (*register_io_dev)(&boot_dev_con);
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(boot_dev_con, (uintptr_t)&boot_dev_spec,
+			&boot_dev_handle);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+	assert(result == 0);
+
+	if (boot_source == BOOT_SOURCE_SDMMC) {
+		partition_init(GPT_IMAGE_ID);
+		fip_spec.offset = get_partition_entry(a2)->start;
+	}
+
+	(void)result;
+}
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
diff --git a/plat/intel/soc/stratix10/platform.mk b/plat/intel/soc/stratix10/platform.mk
new file mode 100644
index 0000000..34674b0
--- /dev/null
+++ b/plat/intel/soc/stratix10/platform.mk
@@ -0,0 +1,71 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES		:=	\
+			-Iplat/intel/soc/stratix10/include/		\
+			-Iplat/intel/soc/common/drivers/		\
+			-Iplat/intel/soc/common/include/
+
+PLAT_BL_COMMON_SOURCES	:=	\
+			lib/xlat_tables/xlat_tables_common.c 		\
+			lib/xlat_tables/aarch64/xlat_tables.c 		\
+			drivers/arm/gic/common/gic_common.c		\
+			drivers/arm/gic/v2/gicv2_main.c			\
+			drivers/arm/gic/v2/gicv2_helpers.c		\
+			plat/common/plat_gicv2.c			\
+			drivers/delay_timer/delay_timer.c		\
+			drivers/delay_timer/generic_delay_timer.c  	\
+			drivers/ti/uart/aarch64/16550_console.S		\
+			plat/intel/soc/common/aarch64/platform_common.c \
+			plat/intel/soc/common/aarch64/plat_helpers.S
+
+BL2_SOURCES     +=	\
+		drivers/partition/partition.c				\
+		drivers/partition/gpt.c					\
+		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/mmc/mmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
+		drivers/io/io_storage.c					\
+		drivers/io/io_block.c					\
+		drivers/io/io_fip.c					\
+		drivers/gpio/gpio.c					\
+		drivers/intel/soc/stratix10/io/s10_memmap_qspi.c	\
+		plat/intel/soc/stratix10/bl2_plat_setup.c		\
+		plat/intel/soc/stratix10/plat_storage.c			\
+                plat/intel/soc/common/bl2_plat_mem_params_desc.c	\
+		plat/intel/soc/stratix10/soc/s10_reset_manager.c	\
+		plat/intel/soc/stratix10/soc/s10_handoff.c		\
+		plat/intel/soc/stratix10/soc/s10_clock_manager.c	\
+		plat/intel/soc/stratix10/soc/s10_pinmux.c		\
+		plat/intel/soc/stratix10/soc/s10_memory_controller.c	\
+		plat/intel/soc/common/socfpga_delay_timer.c		\
+		lib/cpus/aarch64/cortex_a53.S				\
+		plat/intel/soc/common/socfpga_image_load.c		\
+		plat/intel/soc/stratix10/soc/s10_system_manager.c	\
+		common/desc_image_load.c				\
+		plat/intel/soc/stratix10/soc/s10_mailbox.c		\
+		plat/intel/soc/common/drivers/qspi/cadence_qspi.c	\
+		plat/intel/soc/common/drivers/wdt/watchdog.c
+
+BL31_SOURCES	+=	drivers/arm/cci/cci.c				\
+		lib/cpus/aarch64/cortex_a53.S				\
+			lib/cpus/aarch64/aem_generic.S			\
+			lib/cpus/aarch64/cortex_a53.S			\
+			plat/common/plat_psci_common.c			\
+			plat/intel/soc/stratix10/plat_sip_svc.c		\
+			plat/intel/soc/stratix10/bl31_plat_setup.c 	\
+			plat/intel/soc/stratix10/plat_psci.c		\
+			plat/intel/soc/common/socfpga_topology.c	\
+			plat/intel/soc/common/socfpga_delay_timer.c	\
+			plat/intel/soc/stratix10/soc/s10_reset_manager.c\
+			plat/intel/soc/stratix10/soc/s10_pinmux.c	\
+			plat/intel/soc/stratix10/soc/s10_clock_manager.c\
+			plat/intel/soc/stratix10/soc/s10_handoff.c	\
+			plat/intel/soc/stratix10/soc/s10_mailbox.c
+
+PROGRAMMABLE_RESET_ADDRESS	:= 0
+BL2_AT_EL3			:= 1
+USE_COHERENT_MEM		:= 1
diff --git a/plat/intel/soc/stratix10/soc/s10_clock_manager.c b/plat/intel/soc/stratix10/soc/s10_clock_manager.c
new file mode 100644
index 0000000..b4d0573
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_clock_manager.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include "s10_clock_manager.h"
+#include "s10_handoff.h"
+
+static const CLOCK_SOURCE_CONFIG  clk_source = {
+	/* clk_freq_of_eosc1 */
+	(uint32_t) 25000000,
+	/* clk_freq_of_f2h_free */
+	(uint32_t) 460000000,
+	/* clk_freq_of_cb_intosc_ls */
+	(uint32_t) 50000000,
+};
+
+void wait_pll_lock(void)
+{
+	uint32_t data;
+
+	do {
+		data = mmio_read_32(ALT_CLKMGR + ALT_CLKMGR_STAT);
+	} while ((ALT_CLKMGR_STAT_MAINPLLLOCKED(data) == 0) ||
+			(ALT_CLKMGR_STAT_PERPLLLOCKED(data) == 0));
+}
+
+void wait_fsm(void)
+{
+	uint32_t data;
+
+	do {
+		data = mmio_read_32(ALT_CLKMGR + ALT_CLKMGR_STAT);
+	} while (ALT_CLKMGR_STAT_BUSY(data) == ALT_CLKMGR_STAT_BUSY_E_BUSY);
+}
+
+void config_clkmgr_handoff(handoff *hoff_ptr)
+{
+	uint32_t m_div, refclk_div, mscnt, hscnt;
+
+	/* Bypass all mainpllgrp's clocks */
+	mmio_write_32(ALT_CLKMGR_MAINPLL +
+			ALT_CLKMGR_MAINPLL_BYPASS,
+			0x7);
+	wait_fsm();
+	/* Bypass all perpllgrp's clocks */
+	mmio_write_32(ALT_CLKMGR_PERPLL +
+			ALT_CLKMGR_PERPLL_BYPASS,
+			0x7f);
+	wait_fsm();
+
+	/* Setup main PLL dividers */
+	m_div = ALT_CLKMGR_MAINPLL_FDBCK_MDIV(hoff_ptr->main_pll_fdbck);
+	refclk_div = ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV(
+			hoff_ptr->main_pll_pllglob);
+	mscnt = 200 / ((6 + m_div) / refclk_div);
+	hscnt = (m_div + 6) * mscnt / refclk_div - 9;
+
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB,
+			hoff_ptr->main_pll_pllglob);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_FDBCK,
+			hoff_ptr->main_pll_fdbck);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_VCOCALIB,
+			ALT_CLKMGR_MAINPLL_VCOCALIB_HSCNT_SET(hscnt) |
+			ALT_CLKMGR_MAINPLL_VCOCALIB_MSCNT_SET(mscnt));
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLC0,
+			hoff_ptr->main_pll_pllc0);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLC1,
+			hoff_ptr->main_pll_pllc1);
+
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCDIV,
+			hoff_ptr->main_pll_nocdiv);
+
+	/* Setup peripheral PLL dividers */
+	m_div = ALT_CLKMGR_PERPLL_FDBCK_MDIV(hoff_ptr->per_pll_fdbck);
+	refclk_div = ALT_CLKMGR_PERPLL_PLLGLOB_REFCLKDIV(
+			hoff_ptr->per_pll_pllglob);
+	mscnt = 200 / ((6 + m_div) / refclk_div);
+	hscnt = (m_div + 6) * mscnt / refclk_div - 9;
+
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLGLOB,
+			hoff_ptr->per_pll_pllglob);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_FDBCK,
+			hoff_ptr->per_pll_fdbck);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_VCOCALIB,
+			ALT_CLKMGR_PERPLL_VCOCALIB_HSCNT_SET(hscnt) |
+			ALT_CLKMGR_PERPLL_VCOCALIB_MSCNT_SET(mscnt));
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLC0,
+			hoff_ptr->per_pll_pllc0);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLC1,
+			hoff_ptr->per_pll_pllc1);
+
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_GPIODIV,
+			ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(
+			hoff_ptr->per_pll_gpiodiv));
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_EMACCTL,
+			hoff_ptr->per_pll_emacctl);
+
+
+	/* Take both PLL out of reset and power up */
+	mmio_setbits_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB,
+			ALT_CLKMGR_MAINPLL_PLLGLOB_PD_SET_MSK |
+			ALT_CLKMGR_MAINPLL_PLLGLOB_RST_SET_MSK);
+	mmio_setbits_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLGLOB,
+			ALT_CLKMGR_PERPLL_PLLGLOB_PD_SET_MSK |
+			ALT_CLKMGR_PERPLL_PLLGLOB_RST_SET_MSK);
+
+	wait_pll_lock();
+
+	/* Dividers for C2 to C9 only init after PLLs are lock. */
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_MPUCLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCCLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR2CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR3CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR4CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR5CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR6CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR7CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR8CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR9CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR2CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR3CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR4CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR5CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR6CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR7CLK, 0xff);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR8CLK, 0xff);
+
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_MPUCLK,
+			hoff_ptr->main_pll_mpuclk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCCLK,
+			hoff_ptr->main_pll_nocclk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR2CLK,
+			hoff_ptr->main_pll_cntr2clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR3CLK,
+			hoff_ptr->main_pll_cntr3clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR4CLK,
+			hoff_ptr->main_pll_cntr4clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR5CLK,
+			hoff_ptr->main_pll_cntr5clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR6CLK,
+			hoff_ptr->main_pll_cntr6clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR7CLK,
+			hoff_ptr->main_pll_cntr7clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR8CLK,
+			hoff_ptr->main_pll_cntr8clk);
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR9CLK,
+			hoff_ptr->main_pll_cntr9clk);
+
+	/* Peripheral PLL Clock Source and Counters/Divider */
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR2CLK,
+			hoff_ptr->per_pll_cntr2clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR3CLK,
+			hoff_ptr->per_pll_cntr3clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR4CLK,
+			hoff_ptr->per_pll_cntr4clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR5CLK,
+			hoff_ptr->per_pll_cntr5clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR6CLK,
+			hoff_ptr->per_pll_cntr6clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR7CLK,
+			hoff_ptr->per_pll_cntr7clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR8CLK,
+			hoff_ptr->per_pll_cntr8clk);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR9CLK,
+			hoff_ptr->per_pll_cntr9clk);
+
+	/* Take all PLLs out of bypass */
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_BYPASS, 0);
+	wait_fsm();
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_BYPASS, 0);
+	wait_fsm();
+
+	/* Set safe mode/ out of boot mode */
+	mmio_clrbits_32(ALT_CLKMGR + ALT_CLKMGR_CTRL,
+		ALT_CLKMGR_CTRL_BOOTMODE_SET_MSK);
+	wait_fsm();
+
+	/* 10 Enable mainpllgrp's software-managed clock */
+	mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_EN,
+			ALT_CLKMGR_MAINPLL_EN_RESET);
+	mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_EN,
+			ALT_CLKMGR_PERPLL_EN_RESET);
+
+	/* Clear loss lock  interrupt status register that */
+	/* might be set during configuration */
+	mmio_write_32(ALT_CLKMGR + ALT_CLKMGR_INTRCLR,
+			ALT_CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK |
+			ALT_CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK);
+}
+
+int get_wdt_clk(handoff *hoff_ptr)
+{
+	int main_noc_base_clk, l3_main_free_clk, l4_sys_free_clk;
+	int data32, mdiv, refclkdiv, ref_clk;
+
+	data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB);
+
+	switch (ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC(data32)) {
+	case ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_EOSC1:
+		ref_clk = clk_source.clk_freq_of_eosc1;
+		break;
+	case ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_INTOSC:
+		ref_clk = clk_source.clk_freq_of_cb_intosc_ls;
+		break;
+	case ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_F2S:
+		ref_clk = clk_source.clk_freq_of_f2h_free;
+		break;
+	default:
+		ref_clk = 0;
+		assert(0);
+		break;
+	}
+
+	refclkdiv = ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV(data32);
+	data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_FDBCK);
+	mdiv = ALT_CLKMGR_MAINPLL_FDBCK_MDIV(data32);
+	ref_clk = (ref_clk / refclkdiv) * (6 + mdiv);
+
+	main_noc_base_clk = ref_clk / (hoff_ptr->main_pll_pllc1 & 0xff);
+	l3_main_free_clk = main_noc_base_clk / (hoff_ptr->main_pll_nocclk + 1);
+	l4_sys_free_clk = l3_main_free_clk / 4;
+
+	return l4_sys_free_clk;
+}
diff --git a/plat/intel/soc/stratix10/soc/s10_handoff.c b/plat/intel/soc/stratix10/soc/s10_handoff.c
new file mode 100644
index 0000000..1a4d5c3
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_handoff.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/gicv2.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <lib/mmio.h>
+#include <string.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "s10_handoff.h"
+
+#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) |	\
+				(((x) & 0x0000FF00) << 8) | ((x) << 24))
+
+int s10_get_handoff(handoff *reverse_hoff_ptr)
+{
+	int i;
+	uint32_t *buffer;
+	handoff *handoff_ptr = (handoff *) PLAT_HANDOFF_OFFSET;
+
+	memcpy(reverse_hoff_ptr, handoff_ptr, sizeof(handoff));
+	buffer = (uint32_t *)reverse_hoff_ptr;
+
+	/* convert big indian to little indian */
+	for (i = 0; i < sizeof(handoff) / 4; i++)
+		buffer[i] = SWAP_UINT32(buffer[i]);
+
+	if (reverse_hoff_ptr->header_magic != HANDOFF_MAGIC_HEADER)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_sel_magic != HANDOFF_MAGIC_PINMUX_SEL)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_io_magic != HANDOFF_MAGIC_IOCTLR)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_fpga_magic != HANDOFF_MAGIC_FPGA)
+		return -1;
+	if (reverse_hoff_ptr->pinmux_delay_magic != HANDOFF_MAGIC_IODELAY)
+		return -1;
+
+	return 0;
+}
diff --git a/plat/intel/soc/stratix10/soc/s10_mailbox.c b/plat/intel/soc/stratix10/soc/s10_mailbox.c
new file mode 100644
index 0000000..00a07f3
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_mailbox.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <common/debug.h>
+#include "s10_mailbox.h"
+
+static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args,
+					int len)
+{
+	uint32_t cmd_free_offset;
+	int i;
+
+	cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN);
+
+	if (cmd_free_offset >= MBOX_CMD_BUFFER_SIZE) {
+		INFO("Insufficient buffer in mailbox\n");
+		return MBOX_INSUFFICIENT_BUFFER;
+	}
+
+
+	mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4),
+			header_cmd);
+
+
+	for (i = 0; i < len; i++) {
+		cmd_free_offset %= MBOX_CMD_BUFFER_SIZE;
+		mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER +
+				(cmd_free_offset++ * 4), args[i]);
+	}
+
+	cmd_free_offset %= MBOX_CMD_BUFFER_SIZE;
+	mmio_write_32(MBOX_OFFSET + MBOX_CIN, cmd_free_offset);
+
+	return 0;
+}
+
+int mailbox_read_response(int job_id, uint32_t *response)
+{
+	int rin = 0;
+	int rout = 0;
+	int response_length = 0;
+	int resp = 0;
+	int total_resp_len = 0;
+	int timeout = 100000;
+
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
+
+	while (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) {
+		if (timeout-- < 0)
+			return MBOX_NO_RESPONSE;
+	}
+
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
+
+	rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+	rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+	while (rout != rin) {
+		resp = mmio_read_32(MBOX_OFFSET +
+				    MBOX_RESP_BUFFER + ((rout++)*4));
+
+		rout %= MBOX_RESP_BUFFER_SIZE;
+		mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+		if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID ||
+		   MBOX_RESP_JOB_ID(resp) != job_id) {
+			return MBOX_WRONG_ID;
+		}
+
+		if (MBOX_RESP_ERR(resp) > 0) {
+			INFO("Error in response: %x\n", resp);
+			return -resp;
+		}
+		response_length = MBOX_RESP_LEN(resp);
+
+		while (response_length) {
+
+			response_length--;
+			resp = mmio_read_32(MBOX_OFFSET +
+						MBOX_RESP_BUFFER +
+						(rout)*4);
+			if (response) {
+				*(response + total_resp_len) = resp;
+				total_resp_len++;
+			}
+			rout++;
+			rout %= MBOX_RESP_BUFFER_SIZE;
+			mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+		}
+		return total_resp_len;
+	}
+
+	return MBOX_NO_RESPONSE;
+}
+
+
+int mailbox_poll_response(int job_id, int urgent, uint32_t *response)
+{
+	int timeout = 80000;
+	int rin = 0;
+	int rout = 0;
+	int response_length = 0;
+	int resp = 0;
+	int total_resp_len = 0;
+
+	mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1);
+
+	while (1) {
+		while (timeout > 0 &&
+			mmio_read_32(MBOX_OFFSET +
+				MBOX_DOORBELL_FROM_SDM) != 1) {
+			timeout--;
+		}
+
+		if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) {
+			INFO("Timed out waiting for SDM");
+			return MBOX_TIMEOUT;
+		}
+
+		mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0);
+
+		if (urgent & 1) {
+			if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
+				MBOX_STATUS_UA_MASK) ^
+				(urgent & MBOX_STATUS_UA_MASK)) {
+				mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
+				return 0;
+			}
+
+			mmio_write_32(MBOX_OFFSET + MBOX_URG, 0);
+			INFO("Error: Mailbox did not get UA");
+			return -1;
+		}
+
+		rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN);
+		rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT);
+
+		while (rout != rin) {
+			resp = mmio_read_32(MBOX_OFFSET +
+					    MBOX_RESP_BUFFER + ((rout++)*4));
+
+			rout %= MBOX_RESP_BUFFER_SIZE;
+			mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+
+			if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID ||
+			   MBOX_RESP_JOB_ID(resp) != job_id)
+				continue;
+
+			if (MBOX_RESP_ERR(resp) > 0) {
+				INFO("Error in response: %x\n", resp);
+				return -MBOX_RESP_ERR(resp);
+			}
+			response_length = MBOX_RESP_LEN(resp);
+
+			while (response_length) {
+
+				response_length--;
+				resp = mmio_read_32(MBOX_OFFSET +
+							MBOX_RESP_BUFFER +
+							(rout)*4);
+				if (response) {
+					*(response + total_resp_len) = resp;
+					total_resp_len++;
+				}
+				rout++;
+				rout %= MBOX_RESP_BUFFER_SIZE;
+				mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout);
+			}
+			return total_resp_len;
+		}
+	}
+}
+
+void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args,
+			  int len, int urgent)
+{
+	if (urgent)
+		mmio_write_32(MBOX_OFFSET + MBOX_URG, 1);
+
+	fill_mailbox_circular_buffer(MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
+					MBOX_JOB_ID_CMD(job_id) |
+					MBOX_CMD_LEN_CMD(len) |
+					MBOX_INDIRECT |
+					cmd, args, len);
+}
+
+int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args,
+			  int len, int urgent, uint32_t *response)
+{
+	int status;
+
+	if (urgent) {
+		urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) &
+					MBOX_STATUS_UA_MASK;
+		mmio_write_32(MBOX_OFFSET + MBOX_URG, 1);
+	}
+
+	status = fill_mailbox_circular_buffer(
+			MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) |
+			MBOX_JOB_ID_CMD(job_id) |
+			cmd, args, len);
+
+	if (status)
+		return status;
+
+	return mailbox_poll_response(job_id, urgent, response);
+}
+
+void mailbox_set_int(int interrupt)
+{
+
+	mmio_write_32(MBOX_OFFSET+MBOX_INT, MBOX_COE_BIT(interrupt) |
+			MBOX_UAE_BIT(interrupt));
+}
+
+
+void mailbox_set_qspi_open(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, 0, 0, 0, 0);
+}
+
+void mailbox_set_qspi_direct(void)
+{
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0);
+}
+
+void mailbox_set_qspi_close(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, 0, 0, 0, 0);
+}
+
+int mailbox_get_qspi_clock(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	return mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0);
+}
+
+void mailbox_qspi_set_cs(int device_select)
+{
+	uint32_t cs_setting = device_select;
+
+	/* QSPI device select settings at 31:28 */
+	cs_setting = (cs_setting << 28);
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting,
+		1, 0, 0);
+}
+
+void mailbox_reset_cold(void)
+{
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, 0, 0, 0, 0);
+}
+
+int mailbox_init(void)
+{
+	int status = 0;
+
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+	status = mailbox_send_cmd(0, MBOX_CMD_RESTART, 0, 0, 1, 0);
+
+	if (status)
+		return status;
+
+	mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE);
+
+	return 0;
+}
+
diff --git a/plat/intel/soc/stratix10/soc/s10_memory_controller.c b/plat/intel/soc/stratix10/soc/s10_memory_controller.c
new file mode 100644
index 0000000..ed06f54
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_memory_controller.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <platform_def.h>
+#include <string.h>
+
+#include "s10_memory_controller.h"
+
+#define ALT_CCU_NOC_DI_SET_MSK 0x10
+
+#define DDR_READ_LATENCY_DELAY 40
+#define MAX_MEM_CAL_RETRY		3
+#define PRE_CALIBRATION_DELAY		1
+#define POST_CALIBRATION_DELAY		1
+#define TIMEOUT_EMIF_CALIBRATION	100
+#define CLEAR_EMIF_DELAY		50000
+#define CLEAR_EMIF_TIMEOUT		0x100000
+#define TIMEOUT_INT_RESP		10000
+
+#define DDR_CONFIG(A, B, C, R)	(((A) << 24) | ((B) << 16) | ((C) << 8) | (R))
+#define DDR_CONFIG_ELEMENTS	(sizeof(ddr_config)/sizeof(uint32_t))
+
+/* tWR = Min. 15ns constant, see JEDEC standard eg. DDR4 is JESD79-4.pdf */
+#define tWR_IN_NS 15
+
+void configure_hmc_adaptor_regs(void);
+void configure_ddr_sched_ctrl_regs(void);
+
+/* The followring are the supported configurations */
+uint32_t ddr_config[] = {
+	/* DDR_CONFIG(Address order,Bank,Column,Row) */
+	/* List for DDR3 or LPDDR3 (pinout order > chip, row, bank, column) */
+	DDR_CONFIG(0, 3, 10, 12),
+	DDR_CONFIG(0, 3,  9, 13),
+	DDR_CONFIG(0, 3, 10, 13),
+	DDR_CONFIG(0, 3,  9, 14),
+	DDR_CONFIG(0, 3, 10, 14),
+	DDR_CONFIG(0, 3, 10, 15),
+	DDR_CONFIG(0, 3, 11, 14),
+	DDR_CONFIG(0, 3, 11, 15),
+	DDR_CONFIG(0, 3, 10, 16),
+	DDR_CONFIG(0, 3, 11, 16),
+	DDR_CONFIG(0, 3, 12, 15),	/* 0xa */
+	/* List for DDR4 only (pinout order > chip, bank, row, column) */
+	DDR_CONFIG(1, 3, 10, 14),
+	DDR_CONFIG(1, 4, 10, 14),
+	DDR_CONFIG(1, 3, 10, 15),
+	DDR_CONFIG(1, 4, 10, 15),
+	DDR_CONFIG(1, 3, 10, 16),
+	DDR_CONFIG(1, 4, 10, 16),
+	DDR_CONFIG(1, 3, 10, 17),
+	DDR_CONFIG(1, 4, 10, 17),
+};
+
+static int match_ddr_conf(uint32_t ddr_conf)
+{
+	int i;
+
+	for (i = 0; i < DDR_CONFIG_ELEMENTS; i++) {
+		if (ddr_conf == ddr_config[i])
+			return i;
+	}
+	return 0;
+}
+
+static int check_hmc_clk(void)
+{
+	unsigned long timeout = 0;
+	uint32_t hmc_clk;
+
+	do {
+		hmc_clk = mmio_read_32(S10_SYSMGR_CORE_HMC_CLK);
+		if (hmc_clk & S10_SYSMGR_CORE_HMC_CLK_STATUS)
+			break;
+		udelay(1);
+	} while (++timeout < 1000);
+	if (timeout >= 1000)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int clear_emif(void)
+{
+	uint32_t data;
+	unsigned long timeout;
+
+	mmio_write_32(S10_MPFE_HMC_ADP_RSTHANDSHAKECTRL, 0);
+
+	timeout = 0;
+	do {
+		data = mmio_read_32(S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT);
+		if ((data & S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE) == 0)
+			break;
+		udelay(CLEAR_EMIF_DELAY);
+	} while (++timeout < CLEAR_EMIF_TIMEOUT);
+	if (timeout >= CLEAR_EMIF_TIMEOUT)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mem_calibration(void)
+{
+	int status = 0;
+	uint32_t data;
+	unsigned long timeout;
+	unsigned long retry = 0;
+
+	udelay(PRE_CALIBRATION_DELAY);
+
+	do {
+		if (retry != 0)
+			INFO("DDR: Retrying DRAM calibration\n");
+
+		timeout = 0;
+		do {
+			data = mmio_read_32(S10_MPFE_HMC_ADP_DDRCALSTAT);
+			if (S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 1)
+				break;
+			udelay(1);
+		} while (++timeout < TIMEOUT_EMIF_CALIBRATION);
+
+		if (S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) {
+			status = clear_emif();
+		if (status)
+			ERROR("Failed to clear Emif\n");
+		} else {
+			break;
+		}
+	} while (++retry < MAX_MEM_CAL_RETRY);
+
+	if (S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) {
+		ERROR("DDR: DRAM calibration failed.\n");
+		status = -EIO;
+	} else {
+		INFO("DDR: DRAM calibration success.\n");
+		status = 0;
+	}
+
+	udelay(POST_CALIBRATION_DELAY);
+
+	return status;
+}
+
+int init_hard_memory_controller(void)
+{
+	int status;
+
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_DDR, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM0, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1A, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1B, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1C, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1D, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1E, S10_CCU_NOC_DI_SET_MSK);
+
+	mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM0, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1A, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1B, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1C, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1D, S10_CCU_NOC_DI_SET_MSK);
+	mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1E, S10_CCU_NOC_DI_SET_MSK);
+
+	mmio_write_32(S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT, 0xFFFF0000);
+	mmio_write_32(S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT, 0x1F);
+
+	mmio_write_32(S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT, 0xFFFF0000);
+	mmio_write_32(S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT, 0x1F);
+	mmio_write_32(S10_SOC_NOC_FW_DDR_SCR_ENABLE, BIT(0) | BIT(8));
+
+	status = check_hmc_clk();
+	if (status) {
+		ERROR("DDR: Error, HMC clock not running\n");
+		return status;
+	}
+
+	mmio_clrbits_32(S10_RSTMGR_BRGMODRST, S10_RSTMGR_BRGMODRST_DDRSCH);
+
+	status = mem_calibration();
+	if (status) {
+		ERROR("DDR: Memory Calibration Failed\n");
+		return status;
+	}
+
+	configure_hmc_adaptor_regs();
+	configure_ddr_sched_ctrl_regs();
+
+	return 0;
+}
+
+void configure_ddr_sched_ctrl_regs(void)
+{
+	uint32_t data, dram_addr_order, ddr_conf, bank, row, col,
+		rd_to_miss, wr_to_miss, burst_len, burst_len_ddr_clk,
+		burst_len_sched_clk, act_to_act, rd_to_wr, wr_to_rd, bw_ratio,
+		t_rtp, t_rp, t_rcd, rd_latency, tw_rin_clk_cycles,
+		bw_ratio_extended, auto_precharge = 0, act_to_act_bank, faw,
+		faw_bank, bus_rd_to_rd, bus_rd_to_wr, bus_wr_to_rd;
+
+	INFO("Init HPS NOC's DDR Scheduler.\n");
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CTRLCFG1);
+	dram_addr_order = S10_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_DRAMADDRW);
+
+	col  = IOHMC_DRAMADDRW_COL_ADDR_WIDTH(data);
+	row  = IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(data);
+	bank = IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(data);
+
+	ddr_conf = match_ddr_conf(DDR_CONFIG(dram_addr_order, bank, col, row));
+
+	if (ddr_conf) {
+		mmio_clrsetbits_32(
+			S10_MPFE_DDR_MAIN_SCHED_DDRCONF,
+			S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK,
+			S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(ddr_conf));
+	} else {
+		ERROR("DDR: Cannot find predefined ddrConf configuration.\n");
+	}
+
+	mmio_write_32(S10_MPFE_HMC_ADP(ADP_DRAMADDRWIDTH), data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_DRAMTIMING0);
+	rd_latency = S10_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING0);
+	act_to_act = ACT_TO_ACT(data);
+	t_rcd = ACT_TO_RDWR(data);
+	act_to_act_bank = ACT_TO_ACT_DIFF_BANK(data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING1);
+	rd_to_wr = RD_TO_WR(data);
+	bus_rd_to_rd = RD_TO_RD_DIFF_CHIP(data);
+	bus_rd_to_wr = RD_TO_WR_DIFF_CHIP(data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING2);
+	t_rtp = RD_TO_PCH(data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING3);
+	wr_to_rd = CALTIMING3_WR_TO_RD(data);
+	bus_wr_to_rd = CALTIMING3_WR_TO_RD_DIFF_CHIP(data);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING4);
+	t_rp = PCH_TO_VALID(data);
+
+	data = mmio_read_32(S10_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL));
+	bw_ratio = ((HMC_ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 0 : 1);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CTRLCFG0);
+	burst_len = HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(data);
+	burst_len_ddr_clk = burst_len / 2;
+	burst_len_sched_clk = ((burst_len/2) / 2);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CTRLCFG0);
+	switch (S10_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(data)) {
+	case 1:
+		/* DDR4 - 1333MHz */
+		/* 20 (19.995) clock cycles = 15ns */
+		/* Calculate with rounding */
+		tw_rin_clk_cycles = (((tWR_IN_NS * 1333) % 1000) >= 500) ?
+			((tWR_IN_NS * 1333) / 1000) + 1 :
+			((tWR_IN_NS * 1333) / 1000);
+		break;
+	default:
+		/* Others - 1066MHz or slower */
+		/* 16 (15.990) clock cycles = 15ns */
+		/* Calculate with rounding */
+		tw_rin_clk_cycles = (((tWR_IN_NS * 1066) % 1000) >= 500) ?
+			((tWR_IN_NS * 1066) / 1000) + 1 :
+			((tWR_IN_NS * 1066) / 1000);
+		break;
+	}
+
+	rd_to_miss = t_rtp + t_rp + t_rcd - burst_len_sched_clk;
+	wr_to_miss = ((rd_latency + burst_len_ddr_clk + 2 + tw_rin_clk_cycles)
+			/ 2) - rd_to_wr + t_rp + t_rcd;
+
+	mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_DDRTIMING,
+		bw_ratio << DDRTIMING_BWRATIO_OFST |
+		wr_to_rd << DDRTIMING_WRTORD_OFST|
+		rd_to_wr << DDRTIMING_RDTOWR_OFST |
+		burst_len_sched_clk << DDRTIMING_BURSTLEN_OFST |
+		wr_to_miss << DDRTIMING_WRTOMISS_OFST |
+		rd_to_miss << DDRTIMING_RDTOMISS_OFST |
+		act_to_act << DDRTIMING_ACTTOACT_OFST);
+
+	data = mmio_read_32(S10_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL));
+	bw_ratio_extended = ((ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 1 : 0);
+
+	mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_DDRMODE,
+		bw_ratio_extended << DDRMODE_BWRATIOEXTENDED_OFST |
+		auto_precharge << DDRMODE_AUTOPRECHARGE_OFST);
+
+	mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_READLATENCY,
+		(rd_latency / 2) + DDR_READ_LATENCY_DELAY);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING9);
+	faw = S10_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(data);
+
+	faw_bank = 1; // always 1 because we always have 4 bank DDR.
+
+	mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_ACTIVATE,
+		faw_bank << S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST |
+		faw << S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST |
+		act_to_act_bank << S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST);
+
+	mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_DEVTODEV,
+		((bus_rd_to_rd
+			<< S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST)
+			& S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK) |
+		((bus_rd_to_wr
+			<< S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST)
+			& S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK) |
+		((bus_wr_to_rd
+			<< S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST)
+			& S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK));
+
+}
+
+unsigned long get_physical_dram_size(void)
+{
+	uint32_t data;
+	unsigned long ram_addr_width, ram_ext_if_io_width;
+
+	data = mmio_read_32(S10_MPFE_HMC_ADP_DDRIOCTRL);
+	switch (S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(data)) {
+	case 0:
+		ram_ext_if_io_width = 16;
+		break;
+	case 1:
+		ram_ext_if_io_width = 32;
+		break;
+	case 2:
+		ram_ext_if_io_width = 64;
+		break;
+	default:
+		ram_ext_if_io_width = 0;
+		break;
+	}
+
+	data = mmio_read_32(S10_MPFE_IOHMC_REG_DRAMADDRW);
+	ram_addr_width = IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(data) +
+		IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(data);
+
+	return (1 << ram_addr_width) * (ram_ext_if_io_width / 8);
+}
+
+
+
+void configure_hmc_adaptor_regs(void)
+{
+	uint32_t data;
+	uint32_t dram_io_width;
+
+	dram_io_width = S10_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0(
+		mmio_read_32(S10_MPFE_IOHMC_REG_NIOSRESERVE0_OFST));
+
+	dram_io_width = (dram_io_width & 0xFF) >> 5;
+
+	mmio_clrsetbits_32(S10_MPFE_HMC_ADP_DDRIOCTRL,
+		S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_MSK,
+		dram_io_width << S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_OFST);
+
+	mmio_write_32(S10_MPFE_HMC_ADP_HPSINTFCSEL,
+		S10_MPFE_HMC_ADP_HPSINTFCSEL_ENABLE);
+
+	data = mmio_read_32(S10_MPFE_IOHMC_REG_CTRLCFG1);
+	if (data & (1 << S10_IOHMC_CTRLCFG1_ENABLE_ECC_OFST)) {
+		mmio_clrsetbits_32(S10_MPFE_HMC_ADP_ECCCTRL1,
+			S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK,
+			S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK);
+
+		mmio_clrsetbits_32(S10_MPFE_HMC_ADP_ECCCTRL2,
+			S10_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK,
+			S10_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK);
+
+		mmio_clrsetbits_32(S10_MPFE_HMC_ADP_ECCCTRL1,
+			S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK |
+			S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK,
+			S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK);
+		INFO("Scrubbing ECC\n");
+
+		/* ECC Scrubbing */
+		zeromem(DRAM_BASE, DRAM_SIZE);
+	} else {
+		INFO("ECC is disabled.\n");
+	}
+}
+
diff --git a/plat/intel/soc/stratix10/soc/s10_pinmux.c b/plat/intel/soc/stratix10/soc/s10_pinmux.c
new file mode 100644
index 0000000..7fb4711
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_pinmux.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "s10_pinmux.h"
+
+const uint32_t sysmgr_pinmux_array_sel[] = {
+	0x00000000, 0x00000001, /* usb */
+	0x00000004, 0x00000001,
+	0x00000008, 0x00000001,
+	0x0000000c, 0x00000001,
+	0x00000010, 0x00000001,
+	0x00000014, 0x00000001,
+	0x00000018, 0x00000001,
+	0x0000001c, 0x00000001,
+	0x00000020, 0x00000001,
+	0x00000024, 0x00000001,
+	0x00000028, 0x00000001,
+	0x0000002c, 0x00000001,
+	0x00000030, 0x00000000, /* emac0 */
+	0x00000034, 0x00000000,
+	0x00000038, 0x00000000,
+	0x0000003c, 0x00000000,
+	0x00000040, 0x00000000,
+	0x00000044, 0x00000000,
+	0x00000048, 0x00000000,
+	0x0000004c, 0x00000000,
+	0x00000050, 0x00000000,
+	0x00000054, 0x00000000,
+	0x00000058, 0x00000000,
+	0x0000005c, 0x00000000,
+	0x00000060, 0x00000008, /* gpio1 */
+	0x00000064, 0x00000008,
+	0x00000068, 0x00000005,  /* uart0 tx */
+	0x0000006c, 0x00000005,  /*  uart 0 rx */
+	0x00000070, 0x00000008,  /*  gpio */
+	0x00000074, 0x00000008,
+	0x00000078, 0x00000004, /* i2c1 */
+	0x0000007c, 0x00000004,
+	0x00000080, 0x00000007,  /* jtag */
+	0x00000084, 0x00000007,
+	0x00000088, 0x00000007,
+	0x0000008c, 0x00000007,
+	0x00000090, 0x00000001,  /* sdmmc data0 */
+	0x00000094, 0x00000001,
+	0x00000098, 0x00000001,
+	0x0000009c, 0x00000001,
+	0x00000100, 0x00000001,
+	0x00000104, 0x00000001,  /* sdmmc.data3 */
+	0x00000108, 0x00000008,  /* loan */
+	0x0000010c, 0x00000008,   /* gpio */
+	0x00000110, 0x00000008,
+	0x00000114, 0x00000008,  /* gpio1.io21 */
+	0x00000118, 0x00000005,  /* mdio0.mdio */
+	0x0000011c, 0x00000005  /* mdio0.mdc */
+};
+
+const uint32_t sysmgr_pinmux_array_ctrl[] = {
+	0x00000000, 0x00502c38, /* Q1_1 */
+	0x00000004, 0x00102c38,
+	0x00000008, 0x00502c38,
+	0x0000000c, 0x00502c38,
+	0x00000010, 0x00502c38,
+	0x00000014, 0x00502c38,
+	0x00000018, 0x00502c38,
+	0x0000001c, 0x00502c38,
+	0x00000020, 0x00502c38,
+	0x00000024, 0x00502c38,
+	0x00000028, 0x00502c38,
+	0x0000002c, 0x00502c38,
+	0x00000030, 0x00102c38, /* Q2_1 */
+	0x00000034, 0x00102c38,
+	0x00000038, 0x00502c38,
+	0x0000003c, 0x00502c38,
+	0x00000040, 0x00102c38,
+	0x00000044, 0x00102c38,
+	0x00000048, 0x00502c38,
+	0x0000004c, 0x00502c38,
+	0x00000050, 0x00102c38,
+	0x00000054, 0x00102c38,
+	0x00000058, 0x00502c38,
+	0x0000005c, 0x00502c38,
+	0x00000060, 0x00502c38, /* Q3_1 */
+	0x00000064, 0x00502c38,
+	0x00000068, 0x00102c38,
+	0x0000006c, 0x00502c38,
+	0x000000d0, 0x00502c38,
+	0x000000d4, 0x00502c38,
+	0x000000d8, 0x00542c38,
+	0x000000dc, 0x00542c38,
+	0x000000e0, 0x00502c38,
+	0x000000e4, 0x00502c38,
+	0x000000e8, 0x00102c38,
+	0x000000ec, 0x00502c38,
+	0x000000f0, 0x00502c38, /* Q4_1 */
+	0x000000f4, 0x00502c38,
+	0x000000f8, 0x00102c38,
+	0x000000fc, 0x00502c38,
+	0x00000100, 0x00502c38,
+	0x00000104, 0x00502c38,
+	0x00000108, 0x00102c38,
+	0x0000010c, 0x00502c38,
+	0x00000110, 0x00502c38,
+	0x00000114, 0x00502c38,
+	0x00000118, 0x00542c38,
+	0x0000011c, 0x00102c38
+};
+
+const uint32_t sysmgr_pinmux_array_fpga[] = {
+	0x00000000, 0x00000000,
+	0x00000004, 0x00000000,
+	0x00000008, 0x00000000,
+	0x0000000c, 0x00000000,
+	0x00000010, 0x00000000,
+	0x00000014, 0x00000000,
+	0x00000018, 0x00000000,
+	0x0000001c, 0x00000000,
+	0x00000020, 0x00000000,
+	0x00000028, 0x00000000,
+	0x0000002c, 0x00000000,
+	0x00000030, 0x00000000,
+	0x00000034, 0x00000000,
+	0x00000038, 0x00000000,
+	0x0000003c, 0x00000000,
+	0x00000040, 0x00000000,
+	0x00000044, 0x00000000,
+	0x00000048, 0x00000000,
+	0x00000050, 0x00000000,
+	0x00000054, 0x00000000,
+	0x00000058, 0x0000002a
+};
+
+const uint32_t sysmgr_pinmux_array_iodelay[] = {
+	0x00000000, 0x00000000,
+	0x00000004, 0x00000000,
+	0x00000008, 0x00000000,
+	0x0000000c, 0x00000000,
+	0x00000010, 0x00000000,
+	0x00000014, 0x00000000,
+	0x00000018, 0x00000000,
+	0x0000001c, 0x00000000,
+	0x00000020, 0x00000000,
+	0x00000024, 0x00000000,
+	0x00000028, 0x00000000,
+	0x0000002c, 0x00000000,
+	0x00000030, 0x00000000,
+	0x00000034, 0x00000000,
+	0x00000038, 0x00000000,
+	0x0000003c, 0x00000000,
+	0x00000040, 0x00000000,
+	0x00000044, 0x00000000,
+	0x00000048, 0x00000000,
+	0x0000004c, 0x00000000,
+	0x00000050, 0x00000000,
+	0x00000054, 0x00000000,
+	0x00000058, 0x00000000,
+	0x0000005c, 0x00000000,
+	0x00000060, 0x00000000,
+	0x00000064, 0x00000000,
+	0x00000068, 0x00000000,
+	0x0000006c, 0x00000000,
+	0x00000070, 0x00000000,
+	0x00000074, 0x00000000,
+	0x00000078, 0x00000000,
+	0x0000007c, 0x00000000,
+	0x00000080, 0x00000000,
+	0x00000084, 0x00000000,
+	0x00000088, 0x00000000,
+	0x0000008c, 0x00000000,
+	0x00000090, 0x00000000,
+	0x00000094, 0x00000000,
+	0x00000098, 0x00000000,
+	0x0000009c, 0x00000000,
+	0x00000100, 0x00000000,
+	0x00000104, 0x00000000,
+	0x00000108, 0x00000000,
+	0x0000010c, 0x00000000,
+	0x00000110, 0x00000000,
+	0x00000114, 0x00000000,
+	0x00000118, 0x00000000,
+	0x0000011c, 0x00000000
+};
+
+void config_pinmux(handoff *hoff_ptr)
+{
+	unsigned int i;
+
+	for (i = 0; i < 96; i += 2) {
+		mmio_write_32(S10_PINMUX_PIN0SEL +
+			hoff_ptr->pinmux_sel_array[i],
+			hoff_ptr->pinmux_sel_array[i+1]);
+	}
+
+	for (i = 0; i < 96; i += 2) {
+		mmio_write_32(S10_PINMUX_IO0CTRL +
+			hoff_ptr->pinmux_io_array[i],
+			hoff_ptr->pinmux_io_array[i+1]);
+	}
+
+	for (i = 0; i < 42; i += 2) {
+		mmio_write_32(S10_PINMUX_PINMUX_EMAC0_USEFPGA +
+			hoff_ptr->pinmux_fpga_array[i],
+			hoff_ptr->pinmux_fpga_array[i+1]);
+	}
+
+	for (i = 0; i < 96; i += 2) {
+		mmio_write_32(S10_PINMUX_IO0_DELAY +
+			hoff_ptr->pinmux_iodelay_array[i],
+			hoff_ptr->pinmux_iodelay_array[i+1]);
+	}
+
+}
+
diff --git a/plat/intel/soc/stratix10/soc/s10_reset_manager.c b/plat/intel/soc/stratix10/soc/s10_reset_manager.c
new file mode 100644
index 0000000..8b7420b
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_reset_manager.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include "s10_reset_manager.h"
+
+void deassert_peripheral_reset(void)
+{
+	mmio_clrbits_32(S10_RSTMGR_PER1MODRST,
+			S10_RSTMGR_PER1MODRST_WATCHDOG0 |
+			S10_RSTMGR_PER1MODRST_WATCHDOG1 |
+			S10_RSTMGR_PER1MODRST_WATCHDOG2 |
+			S10_RSTMGR_PER1MODRST_WATCHDOG3 |
+			S10_RSTMGR_PER1MODRST_L4SYSTIMER0 |
+			S10_RSTMGR_PER1MODRST_L4SYSTIMER1 |
+			S10_RSTMGR_PER1MODRST_SPTIMER0 |
+			S10_RSTMGR_PER1MODRST_SPTIMER1 |
+			S10_RSTMGR_PER1MODRST_I2C0 |
+			S10_RSTMGR_PER1MODRST_I2C1 |
+			S10_RSTMGR_PER1MODRST_I2C2 |
+			S10_RSTMGR_PER1MODRST_I2C3 |
+			S10_RSTMGR_PER1MODRST_I2C4 |
+			S10_RSTMGR_PER1MODRST_UART0 |
+			S10_RSTMGR_PER1MODRST_UART1 |
+			S10_RSTMGR_PER1MODRST_GPIO0 |
+			S10_RSTMGR_PER1MODRST_GPIO1);
+
+	mmio_clrbits_32(S10_RSTMGR_PER0MODRST,
+			S10_RSTMGR_PER0MODRST_EMAC0OCP |
+			S10_RSTMGR_PER0MODRST_EMAC1OCP |
+			S10_RSTMGR_PER0MODRST_EMAC2OCP |
+			S10_RSTMGR_PER0MODRST_USB0OCP |
+			S10_RSTMGR_PER0MODRST_USB1OCP |
+			S10_RSTMGR_PER0MODRST_NANDOCP |
+			S10_RSTMGR_PER0MODRST_SDMMCOCP |
+			S10_RSTMGR_PER0MODRST_DMAOCP);
+
+	mmio_clrbits_32(S10_RSTMGR_PER0MODRST,
+			S10_RSTMGR_PER0MODRST_EMAC0 |
+			S10_RSTMGR_PER0MODRST_EMAC1 |
+			S10_RSTMGR_PER0MODRST_EMAC2 |
+			S10_RSTMGR_PER0MODRST_USB0 |
+			S10_RSTMGR_PER0MODRST_USB1 |
+			S10_RSTMGR_PER0MODRST_NAND |
+			S10_RSTMGR_PER0MODRST_SDMMC |
+			S10_RSTMGR_PER0MODRST_DMA |
+			S10_RSTMGR_PER0MODRST_SPIM0 |
+			S10_RSTMGR_PER0MODRST_SPIM1 |
+			S10_RSTMGR_PER0MODRST_SPIS0 |
+			S10_RSTMGR_PER0MODRST_SPIS1 |
+			S10_RSTMGR_PER0MODRST_EMACPTP |
+			S10_RSTMGR_PER0MODRST_DMAIF0 |
+			S10_RSTMGR_PER0MODRST_DMAIF1 |
+			S10_RSTMGR_PER0MODRST_DMAIF2 |
+			S10_RSTMGR_PER0MODRST_DMAIF3 |
+			S10_RSTMGR_PER0MODRST_DMAIF4 |
+			S10_RSTMGR_PER0MODRST_DMAIF5 |
+			S10_RSTMGR_PER0MODRST_DMAIF6 |
+			S10_RSTMGR_PER0MODRST_DMAIF7);
+
+}
+
+void config_hps_hs_before_warm_reset(void)
+{
+	uint32_t or_mask = 0;
+
+	or_mask |= S10_RSTMGR_HDSKEN_SDRSELFREFEN;
+	or_mask |= S10_RSTMGR_HDSKEN_FPGAHSEN;
+	or_mask |= S10_RSTMGR_HDSKEN_ETRSTALLEN;
+	or_mask |= S10_RSTMGR_HDSKEN_L2FLUSHEN;
+	or_mask |= S10_RSTMGR_HDSKEN_L3NOC_DBG;
+	or_mask |= S10_RSTMGR_HDSKEN_DEBUG_L3NOC;
+
+	mmio_setbits_32(S10_RSTMGR_HDSKEN, or_mask);
+}
+
diff --git a/plat/intel/soc/stratix10/soc/s10_system_manager.c b/plat/intel/soc/stratix10/soc/s10_system_manager.c
new file mode 100644
index 0000000..a2ed5a3
--- /dev/null
+++ b/plat/intel/soc/stratix10/soc/s10_system_manager.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include "s10_system_manager.h"
+
+void enable_nonsecure_access(void)
+{
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_NAND_REGISTER, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_NAND_DATA, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_NAND_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_NAND_READ_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC,
+		DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_USB0_REGISTER, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_USB1_REGISTER, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_USB0_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_USB1_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_MASTER0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_MASTER1, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_SLAVE0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_SLAVE1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_EMAC0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_EMAC1, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_EMAC2, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_SDMMC, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_SDMMC_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_GPIO0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_GPIO1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C1, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C2, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C3, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C4, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_SP_TIMER1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_UART0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_PER_SCR_UART1, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_DMA_ECC, DISABLE_L4_FIREWALL);
+
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_OCRAM_ECC, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_CLK_MGR, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_IO_MGR, DISABLE_L4_FIREWALL);
+
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_RST_MGR, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_SYS_MGR, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_OSC0_TIMER, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_OSC1_TIMER, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG0, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG1, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG2, DISABLE_L4_FIREWALL);
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG3, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_DAP, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES, DISABLE_L4_FIREWALL);
+
+	mmio_write_32(S10_NOC_FW_L4_SYS_SCR_L4_NOC_QOS, DISABLE_L4_FIREWALL);
+
+	mmio_clrbits_32(S10_CCU_NOC_CPU0_RAMSPACE0_0, 0x03);
+	mmio_clrbits_32(S10_CCU_NOC_IOM_RAMSPACE0_0, 0x03);
+
+	mmio_write_32(S10_SYSMGR_CORE(SYSMGR_MMC), SYSMGR_MMC_DRVSEL(3));
+
+}
+
diff --git a/plat/layerscape/board/ls1043/aarch64/ls1043_helpers.S b/plat/layerscape/board/ls1043/aarch64/ls1043_helpers.S
new file mode 100644
index 0000000..80524fc
--- /dev/null
+++ b/plat/layerscape/board/ls1043/aarch64/ls1043_helpers.S
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_reset_handler
+	.globl  plat_my_core_pos
+	.globl  platform_mem_init
+
+func plat_my_core_pos
+	mrs x0, mpidr_el1
+	and x1, x0, #MPIDR_CPU_MASK   //reserve the last 8 bits
+	and x0, x0, #MPIDR_CLUSTER_MASK
+	add x0, x1, x0, LSR #4  //4 cores
+	ret
+endfunc plat_my_core_pos
+
+func platform_mem_init
+	mov x29, x30
+	bl  inv_dcache_range
+
+//SDRAM_CFG
+	ldr w0, =0x1080000
+	ldr w1, =0x0c000c45
+	str w1, [x0, #0x110]
+//CS0_BNDS
+	ldr w1, =0x7f000000
+	str w1, [x0, #0x000]
+//CS0_CONFIG
+	ldr w1, =0x22030480
+	str w1, [x0, #0x080]
+//TIMING_CFG_0
+	ldr w1, =0x18005591
+	str w1, [x0, #0x104]
+//TIMING_CFG_1
+	ldr w1, =0x428cb4bb
+	str w1, [x0, #0x108]
+//TIMING_CFG_2
+	ldr w1, =0x11c14800
+	str w1, [x0, #0x10C]
+//TIMING_CFG_3
+	ldr w1, =0x00100c01
+	str w1, [x0, #0x100]
+//TIMING_CFG_4
+	ldr w1, =0x02000000
+	str w1, [x0, #0x160]
+//TIMING_CFG_5
+	ldr w1, =0x00144003
+	str w1, [x0, #0x164]
+//TIMING_CFG_7
+	ldr w1, =0x00003013
+	str w1, [x0, #0x16C]
+//TIMING_CFG_8
+	ldr w1, =0x00561102
+	str w1, [x0, #0x250]
+//SDRAM_CFG_2
+	ldr w1, =0x00114000
+	str w1, [x0, #0x114]
+//SDRAM_MODE
+	ldr w1, =0x10020103
+	str w1, [x0, #0x118]
+//SDRAM_MODE_2
+	ldr w1, =0x0
+	str w1, [x0, #0x11C]
+//SDRAM_INTERVAL
+	ldr w1, =0x18066018
+	str w1, [x0, #0x124]
+//DDR_WRLVL_CNTL
+	ldr w1, =0x07f675c6
+	str w1, [x0, #0x174]
+//DDR_WRLVL_CNTL_2
+	ldr w1, =0x00080907
+	str w1, [x0, #0x190]
+//DDR_WRLVL_CNTL_3
+	ldr w1, =0x0
+	str w1, [x0, #0x194]
+//DDR_CDR1
+	ldr w1, =0x00000480
+	str w1, [x0, #0xB28]
+//DDR_CDR2
+	ldr w1, =0x81a10000
+	str w1, [x0, #0xB2C]
+//SDRAM_CLK_CNTL
+	ldr w1, =0x00000003
+	str w1, [x0, #0x130]
+//DDR_ZQ_CNTL
+	ldr w1, =0x0507098a
+	str w1, [x0, #0x170]
+//SDRAM_MODE_9
+	ldr w1, =0x00050000
+	str w1, [x0, #0x220]
+//SDRAM_MODE_10
+	ldr w1, =0x00000004
+	str w1, [x0, #0x224]
+//CS0_CONFIG_2
+	ldr w1, =0x0
+	str w1, [x0, #0x0C0]
+//SDRAM_CFG
+	ldr w1, =0x08000cc5
+	str w1, [x0, #0x110]
+
+	mov w3,#0
+	ldr w4,=0xffffff01
+z_loop:
+delay_loop1:
+	sub w4, w4, #1
+	cmp w4, #0
+	b.gt    delay_loop1
+
+	ldr w1, [x0, #0x114]
+	add w3, w3, #1
+	cmp       w1, #0 //'\n'
+	b.eq       1f
+	cmp w3, #20
+	b.gt    1f
+	b z_loop
+
+1:
+	ldr w4,=0xffffff02
+delay_loop2:
+	sub w4, w4, #1
+	cmp w4, #0
+	b.gt        delay_loop2
+
+	ldr w1, =0x00000000
+	str w1, [x0]
+
+	ret x29
+endfunc	platform_mem_init
+
+func apply_platform_errata
+	/*TODO if needed*/
+	ret
+endfunc apply_platform_errata
+
+func plat_reset_handler
+	mov x29, x30
+	bl  apply_platform_errata
+
+	mov x30, x29
+	ret
+endfunc plat_reset_handler
diff --git a/plat/layerscape/board/ls1043/include/ls_def.h b/plat/layerscape/board/ls1043/include/ls_def.h
new file mode 100644
index 0000000..d8c66e3
--- /dev/null
+++ b/plat/layerscape/board/ls1043/include/ls_def.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LS_DEF_H
+#define LS_DEF_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/******************************************************************************
+ * Definitions common to all ARM standard platforms
+ *****************************************************************************/
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define LS_BL31_PLAT_PARAM_VAL		0x0f1e2d3c4b5a6978ULL
+
+#define LS_CACHE_WRITEBACK_SHIFT	6
+
+/*
+ * Macros mapping the MPIDR Affinity levels to Layerscape Platform Power levels. The
+ * power levels have a 1:1 mapping with the MPIDR affinity levels.
+ */
+#define LS_PWR_LVL0		MPIDR_AFFLVL0
+#define LS_PWR_LVL1		MPIDR_AFFLVL1
+#define LS_PWR_LVL2		MPIDR_AFFLVL2
+
+/*
+ *  Macros for local power states in Layerscape platforms encoded by State-ID field
+ *  within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define LS_LOCAL_STATE_RUN	U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define LS_LOCAL_STATE_RET	U(1)
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains
+ */
+#define LS_LOCAL_STATE_OFF	U(2)
+
+#define LS_MAP_NS_DRAM		MAP_REGION_FLAT( \
+					(LS_NS_DRAM_BASE), \
+					LS_DRAM1_SIZE, \
+					MT_DEVICE | MT_RW | MT_NS)
+
+#define LS_MAP_TSP_SEC_MEM	MAP_REGION_FLAT( \
+					TSP_SEC_MEM_BASE, \
+					TSP_SEC_MEM_SIZE, \
+				MT_DEVICE | MT_RW | MT_SECURE)
+
+
+#define LS_MAP_FLASH0_RW	MAP_REGION_FLAT(PLAT_LS_FLASH_BASE,\
+					PLAT_LS_FLASH_SIZE, \
+					MT_DEVICE | MT_RW)
+
+#define LS_MAP_CCSR		MAP_REGION_FLAT(PLAT_LS_CCSR_BASE, \
+					PLAT_LS_CCSR_SIZE, \
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+
+#define LS_MAP_CONSOLE		MAP_REGION_FLAT(PLAT_LS1043_DUART1_BASE, \
+					PLAT_LS1043_DUART_SIZE, \
+					MT_DEVICE | MT_RW | MT_NS)
+
+/*
+ * The number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU.
+ */
+/******************************************************************************
+ * Required platform porting definitions common to all ARM standard platforms
+ *****************************************************************************/
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		LS_LOCAL_STATE_RET
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		LS_LOCAL_STATE_OFF
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_GRANULE		(1 << LS_CACHE_WRITEBACK_SHIFT)
+
+/*
+ * One cache line needed for bakery locks on Layerscape platforms
+ */
+#define PLAT_PERCPU_BAKERY_LOCK_SIZE		(1 * CACHE_WRITEBACK_GRANULE)
+
+#endif /* LS_DEF_H */
diff --git a/plat/layerscape/board/ls1043/include/ns_access.h b/plat/layerscape/board/ls1043/include/ns_access.h
new file mode 100644
index 0000000..833a5df
--- /dev/null
+++ b/plat/layerscape/board/ls1043/include/ns_access.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef NS_ACCESS_H
+#define NS_ACCESS_H
+
+#include "fsl_csu.h"
+
+enum csu_cslx_ind {
+	CSU_CSLX_PCIE2_IO = 0,
+	CSU_CSLX_PCIE1_IO,
+	CSU_CSLX_MG2TPR_IP,
+	CSU_CSLX_IFC_MEM,
+	CSU_CSLX_OCRAM,
+	CSU_CSLX_GIC,
+	CSU_CSLX_PCIE1,
+	CSU_CSLX_OCRAM2,
+	CSU_CSLX_QSPI_MEM,
+	CSU_CSLX_PCIE2,
+	CSU_CSLX_SATA,
+	CSU_CSLX_USB1,
+	CSU_CSLX_QM_BM_SWPORTAL,
+	CSU_CSLX_PCIE3 = 16,
+	CSU_CSLX_PCIE3_IO,
+	CSU_CSLX_USB3 = 20,
+	CSU_CSLX_USB2,
+	CSU_CSLX_PFE = 23,
+	CSU_CSLX_SERDES = 32,
+	CSU_CSLX_QDMA,
+	CSU_CSLX_LPUART2,
+	CSU_CSLX_LPUART1,
+	CSU_CSLX_LPUART4,
+	CSU_CSLX_LPUART3,
+	CSU_CSLX_LPUART6,
+	CSU_CSLX_LPUART5,
+	CSU_CSLX_DSPI1 = 41,
+	CSU_CSLX_QSPI,
+	CSU_CSLX_ESDHC,
+	CSU_CSLX_IFC = 45,
+	CSU_CSLX_I2C1,
+	CSU_CSLX_USB_2,
+	CSU_CSLX_I2C3 = 48,
+	CSU_CSLX_I2C2,
+	CSU_CSLX_DUART2 = 50,
+	CSU_CSLX_DUART1,
+	CSU_CSLX_WDT2,
+	CSU_CSLX_WDT1,
+	CSU_CSLX_EDMA,
+	CSU_CSLX_SYS_CNT,
+	CSU_CSLX_DMA_MUX2,
+	CSU_CSLX_DMA_MUX1,
+	CSU_CSLX_DDR,
+	CSU_CSLX_QUICC,
+	CSU_CSLX_DCFG_CCU_RCPM = 60,
+	CSU_CSLX_SECURE_BOOTROM,
+	CSU_CSLX_SFP,
+	CSU_CSLX_TMU,
+	CSU_CSLX_SECURE_MONITOR,
+	CSU_CSLX_SCFG,
+	CSU_CSLX_FM = 66,
+	CSU_CSLX_SEC5_5,
+	CSU_CSLX_BM,
+	CSU_CSLX_QM,
+	CSU_CSLX_GPIO2 = 70,
+	CSU_CSLX_GPIO1,
+	CSU_CSLX_GPIO4,
+	CSU_CSLX_GPIO3,
+	CSU_CSLX_PLATFORM_CONT,
+	CSU_CSLX_CSU,
+	CSU_CSLX_IIC4 = 77,
+	CSU_CSLX_WDT4,
+	CSU_CSLX_WDT3,
+	CSU_CSLX_ESDHC2 = 80,
+	CSU_CSLX_WDT5 = 81,
+	CSU_CSLX_SAI2,
+	CSU_CSLX_SAI1,
+	CSU_CSLX_SAI4,
+	CSU_CSLX_SAI3,
+	CSU_CSLX_FTM2 = 86,
+	CSU_CSLX_FTM1,
+	CSU_CSLX_FTM4,
+	CSU_CSLX_FTM3,
+	CSU_CSLX_FTM6 = 90,
+	CSU_CSLX_FTM5,
+	CSU_CSLX_FTM8,
+	CSU_CSLX_FTM7,
+	CSU_CSLX_DSCR = 121,
+};
+
+static struct csu_ns_dev ns_dev[] = {
+	 {CSU_CSLX_PCIE2_IO, CSU_ALL_RW},
+	 {CSU_CSLX_PCIE1_IO, CSU_ALL_RW},
+	 {CSU_CSLX_MG2TPR_IP, CSU_ALL_RW},
+	 {CSU_CSLX_IFC_MEM, CSU_ALL_RW},
+	 {CSU_CSLX_OCRAM, CSU_ALL_RW},
+	 {CSU_CSLX_GIC, CSU_ALL_RW},
+	 {CSU_CSLX_PCIE1, CSU_ALL_RW},
+	 {CSU_CSLX_OCRAM2, CSU_ALL_RW},
+	 {CSU_CSLX_QSPI_MEM, CSU_ALL_RW},
+	 {CSU_CSLX_PCIE2, CSU_ALL_RW},
+	 {CSU_CSLX_SATA, CSU_ALL_RW},
+	 {CSU_CSLX_USB1, CSU_ALL_RW},
+	 {CSU_CSLX_QM_BM_SWPORTAL, CSU_ALL_RW},
+	 {CSU_CSLX_PCIE3, CSU_ALL_RW},
+	 {CSU_CSLX_PCIE3_IO, CSU_ALL_RW},
+	 {CSU_CSLX_USB3, CSU_ALL_RW},
+	 {CSU_CSLX_USB2, CSU_ALL_RW},
+	 {CSU_CSLX_PFE, CSU_ALL_RW},
+	 {CSU_CSLX_SERDES, CSU_ALL_RW},
+	 {CSU_CSLX_QDMA, CSU_ALL_RW},
+	 {CSU_CSLX_LPUART2, CSU_ALL_RW},
+	 {CSU_CSLX_LPUART1, CSU_ALL_RW},
+	 {CSU_CSLX_LPUART4, CSU_ALL_RW},
+	 {CSU_CSLX_LPUART3, CSU_ALL_RW},
+	 {CSU_CSLX_LPUART6, CSU_ALL_RW},
+	 {CSU_CSLX_LPUART5, CSU_ALL_RW},
+	 {CSU_CSLX_DSPI1, CSU_ALL_RW},
+	 {CSU_CSLX_QSPI, CSU_ALL_RW},
+	 {CSU_CSLX_ESDHC, CSU_ALL_RW},
+	 {CSU_CSLX_IFC, CSU_ALL_RW},
+	 {CSU_CSLX_I2C1, CSU_ALL_RW},
+	 {CSU_CSLX_USB_2, CSU_ALL_RW},
+	 {CSU_CSLX_I2C3, CSU_ALL_RW},
+	 {CSU_CSLX_I2C2, CSU_ALL_RW},
+	 {CSU_CSLX_DUART2, CSU_ALL_RW},
+	 {CSU_CSLX_DUART1, CSU_ALL_RW},
+	 {CSU_CSLX_WDT2, CSU_ALL_RW},
+	 {CSU_CSLX_WDT1, CSU_ALL_RW},
+	 {CSU_CSLX_EDMA, CSU_ALL_RW},
+	 {CSU_CSLX_SYS_CNT, CSU_ALL_RW},
+	 {CSU_CSLX_DMA_MUX2, CSU_ALL_RW},
+	 {CSU_CSLX_DMA_MUX1, CSU_ALL_RW},
+	 {CSU_CSLX_DDR, CSU_ALL_RW},
+	 {CSU_CSLX_QUICC, CSU_ALL_RW},
+	 {CSU_CSLX_DCFG_CCU_RCPM, CSU_ALL_RW},
+	 {CSU_CSLX_SECURE_BOOTROM, CSU_ALL_RW},
+	 {CSU_CSLX_SFP, CSU_ALL_RW},
+	 {CSU_CSLX_TMU, CSU_ALL_RW},
+	 {CSU_CSLX_SECURE_MONITOR, CSU_ALL_RW},
+	 {CSU_CSLX_SCFG, CSU_ALL_RW},
+	 {CSU_CSLX_FM, CSU_ALL_RW},
+	 {CSU_CSLX_SEC5_5, CSU_ALL_RW},
+	 {CSU_CSLX_BM, CSU_ALL_RW},
+	 {CSU_CSLX_QM, CSU_ALL_RW},
+	 {CSU_CSLX_GPIO2, CSU_ALL_RW},
+	 {CSU_CSLX_GPIO1, CSU_ALL_RW},
+	 {CSU_CSLX_GPIO4, CSU_ALL_RW},
+	 {CSU_CSLX_GPIO3, CSU_ALL_RW},
+	 {CSU_CSLX_PLATFORM_CONT, CSU_ALL_RW},
+	 {CSU_CSLX_CSU, CSU_ALL_RW},
+	 {CSU_CSLX_IIC4, CSU_ALL_RW},
+	 {CSU_CSLX_WDT4, CSU_ALL_RW},
+	 {CSU_CSLX_WDT3, CSU_ALL_RW},
+	 {CSU_CSLX_ESDHC2, CSU_ALL_RW},
+	 {CSU_CSLX_WDT5, CSU_ALL_RW},
+	 {CSU_CSLX_SAI2, CSU_ALL_RW},
+	 {CSU_CSLX_SAI1, CSU_ALL_RW},
+	 {CSU_CSLX_SAI4, CSU_ALL_RW},
+	 {CSU_CSLX_SAI3, CSU_ALL_RW},
+	 {CSU_CSLX_FTM2, CSU_ALL_RW},
+	 {CSU_CSLX_FTM1, CSU_ALL_RW},
+	 {CSU_CSLX_FTM4, CSU_ALL_RW},
+	 {CSU_CSLX_FTM3, CSU_ALL_RW},
+	 {CSU_CSLX_FTM6, CSU_ALL_RW},
+	 {CSU_CSLX_FTM5, CSU_ALL_RW},
+	 {CSU_CSLX_FTM8, CSU_ALL_RW},
+	 {CSU_CSLX_FTM7, CSU_ALL_RW},
+	 {CSU_CSLX_DSCR, CSU_ALL_RW},
+};
+
+#endif /* NS_ACCESS_H */
diff --git a/plat/layerscape/board/ls1043/include/plat_macros.S b/plat/layerscape/board/ls1043/include/plat_macros.S
new file mode 100644
index 0000000..1ae43ef
--- /dev/null
+++ b/plat/layerscape/board/ls1043/include/plat_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/layerscape/board/ls1043/include/platform_def.h b/plat/layerscape/board/ls1043/include/platform_def.h
new file mode 100644
index 0000000..b613000
--- /dev/null
+++ b/plat/layerscape/board/ls1043/include/platform_def.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <drivers/arm/tzc400.h>
+#include <lib/utils.h>
+#include <plat/common/common_def.h>
+
+#include "ls_def.h"
+
+#define FIRMWARE_WELCOME_STR_LS1043	"Welcome to LS1043 BL1 Phase\n"
+#define FIRMWARE_WELCOME_STR_LS1043_BL2	"Welcome to LS1043 BL2 Phase\n"
+#define FIRMWARE_WELCOME_STR_LS1043_BL31 "Welcome to LS1043 BL31 Phase\n"
+#define FIRMWARE_WELCOME_STR_LS1043_BL32 "Welcome to LS1043 BL32 Phase, TSP\n"
+
+/* Required platform porting definitions */
+#define PLAT_PRIMARY_CPU		0x0
+#define PLAT_MAX_PWR_LVL		LS_PWR_LVL1
+#define PLATFORM_CORE_COUNT		4
+#define COUNTER_FREQUENCY		25000000	/* 25MHz */
+
+/*
+ * Required LS standard platform porting definitions
+ */
+#define PLAT_LS_CLUSTER_COUNT			1
+#define PLAT_LS1043_CCI_CLUSTER0_SL_IFACE_IX	4
+#define LS1043_CLUSTER_COUNT			1
+#define LS1043_MAX_CPUS_PER_CLUSTER		4
+
+#define LS_DRAM1_BASE			0x80000000
+#define LS_DRAM2_BASE			0x880000000
+#define LS_DRAM2_SIZE			0x780000000	/* 30G */
+#define LS_DRAM1_SIZE			0x80000000	/* 2G */
+#define LS_NS_DRAM_BASE			LS_DRAM1_BASE
+/* 64M Secure Memory, in fact there a 2M non-secure hole on top of it */
+#define LS_SECURE_DRAM_SIZE		(64 * 1024 * 1024)
+#define LS_SECURE_DRAM_BASE		(LS_NS_DRAM_BASE + LS_DRAM1_SIZE - \
+						LS_SECURE_DRAM_SIZE)
+#define LS_NS_DRAM_SIZE			(LS_DRAM1_SIZE - LS_SECURE_DRAM_SIZE)
+
+/*
+ * By default, BL2 is in DDR memory.
+ * If LS_BL2_IN_OCRAM is defined, BL2 will in OCRAM
+ */
+/* #define LS_BL2_IN_OCRAM */
+
+#ifndef LS_BL2_IN_OCRAM
+/*
+ * on top of SECURE memory is 2M non-secure hole for OPTee,
+ *  1M secure memory below this hole will be used for BL2.
+ */
+#define LS_BL2_DDR_BASE			(LS_SECURE_DRAM_BASE + \
+						LS_SECURE_DRAM_SIZE \
+						- 3 * 1024 * 1024)
+#endif
+
+#define PLAT_LS_CCSR_BASE		0x1000000
+#define PLAT_LS_CCSR_SIZE		0xF000000
+
+/* Flash base address, currently ROM is not used for TF-A images on LS platforms */
+#define PLAT_LS_TRUSTED_ROM_BASE	0x60100000
+#define PLAT_LS_TRUSTED_ROM_SIZE	0x20000000	/* Flash size */
+#define PLAT_LS_FLASH_SIZE		0x20000000
+#define PLAT_LS_FLASH_BASE		0x60000000
+
+#define LS_SRAM_BASE			0x10000000
+#define LS_SRAM_LIMIT			0x10020000	/* 128K */
+#define LS_SRAM_SHARED_SIZE		0x1000		/* 4K */
+#define LS_SRAM_SIZE			(LS_SRAM_LIMIT - LS_SRAM_BASE)
+#define LS_BL_RAM_BASE			(LS_SRAM_BASE + LS_SRAM_SHARED_SIZE)
+
+#define PLAT_LS_FIP_MAX_SIZE		0x4000000
+
+/* Memory Layout */
+
+#define BL1_RO_BASE			PLAT_LS_TRUSTED_ROM_BASE
+#define BL1_RO_LIMIT			(PLAT_LS_TRUSTED_ROM_BASE	\
+					 + PLAT_LS_TRUSTED_ROM_SIZE)
+#define PLAT_LS_FIP_BASE		0x60120000
+
+#ifdef LS_BL2_IN_OCRAM
+/* BL2 is in OCRAM */
+#define PLAT_LS_MAX_BL1_RW_SIZE		(52 * 1024)		/* 52K */
+#define PLAT_LS_MAX_BL31_SIZE		(64 * 1024)		/* 64K */
+#define PLAT_LS_MAX_BL2_SIZE		(44 * 1024)		/* 44K */
+/* Reserve memory in OCRAM for BL31 Text and ROData segment */
+#define BL31_TEXT_RODATA_SIZE		(32 * 1024)		/* 32K */
+#else /* LS_BL2_IN_OCRAM */
+/* BL2 in DDR */
+#define PLAT_LS_MAX_BL1_RW_SIZE		(64 * 1024)		/* 64K */
+#define PLAT_LS_MAX_BL31_SIZE		(64 * 1024)		/* 64K */
+#define PLAT_LS_MAX_BL2_SIZE		(1 * 1024 * 1024)	/* 1M */
+#endif /* LS_BL2_IN_OCRAM */
+/*
+ * Put BL31 at the start of OCRAM.
+ */
+#define BL31_BASE			LS_SRAM_BASE
+#define BL31_LIMIT			(LS_SRAM_BASE + PLAT_LS_MAX_BL31_SIZE)
+
+#ifdef LS_BL2_IN_OCRAM
+/*
+ * BL2 follow BL31 Text and ROData region.
+ */
+#define BL2_BASE			(BL31_BASE + BL31_TEXT_RODATA_SIZE)
+#define BL2_LIMIT			(BL2_BASE + PLAT_LS_MAX_BL2_SIZE)
+
+#else
+/*
+ * BL2 in DDR memory.
+ */
+#define BL2_BASE			LS_BL2_DDR_BASE
+#define BL2_LIMIT			(BL2_BASE + PLAT_LS_MAX_BL2_SIZE)
+
+#endif
+
+/*
+ * Put BL1 RW at the top of the Trusted SRAM.
+ */
+#ifdef LS_BL2_IN_OCRAM
+#define BL1_RW_BASE			BL2_LIMIT
+#else
+#define BL1_RW_BASE			BL31_LIMIT
+#endif
+#define BL1_RW_LIMIT			LS_SRAM_LIMIT
+
+/* Put BL32 in secure memory */
+#define BL32_BASE		LS_SECURE_DRAM_BASE
+#define BL32_LIMIT		(LS_SECURE_DRAM_BASE + LS_SECURE_DRAM_SIZE)
+/* BL33 memory region */
+#define BL33_BASE		0x82000000
+#define BL33_LIMIT		(LS_NS_DRAM_BASE + LS_NS_DRAM_SIZE)
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+/*
+ * On ARM standard platforms, the TSP can execute from Trusted SRAM,
+ * Trusted DRAM (if available) or the DRAM region secured by the TrustZone
+ * controller.
+ */
+
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE)
+
+/*
+ * ID of the secure physical generic timer interrupt used by the TSP.
+ */
+#define TSP_IRQ_SEC_PHY_TIMER		29
+
+
+/*
+ * GIC related constants
+ */
+#define PLAT_LS1043_CCI_BASE		0x01180000
+#define GICD_BASE			0x01401000
+#define GICC_BASE			0x01402000
+#define GICD_BASE_64K			0x01410000
+#define GICC_BASE_64K			0x01420000
+
+#define DCFG_CCSR_SVR			0x1ee00a4
+#define REV1_0				0x10
+#define REV1_1				0x11
+#define GIC_ADDR_BIT			31
+#define SCFG_GIC400_ALIGN		0x1570188
+
+/* UART related definition */
+
+#define PLAT_LS1043_DUART1_BASE		0x021c0000
+#define PLAT_LS1043_DUART2_BASE		0x021d0000
+#define PLAT_LS1043_DUART_SIZE		0x10000
+
+#define PLAT_LS1043_UART_BASE		0x21c0500
+#define PLAT_LS1043_UART2_BASE		0x21c0600
+#define PLAT_LS1043_UART_CLOCK		400000000
+#define PLAT_LS1043_UART_BAUDRATE	115200
+/* Define UART to be used by TF-A log */
+#define LS_TF_UART_BASE		PLAT_LS1043_UART_BASE
+#define LS_TF_UART_CLOCK		PLAT_LS1043_UART_CLOCK
+#define LS_TF_UART_BAUDRATE		PLAT_LS1043_UART_BAUDRATE
+
+#define LS1043_SYS_CNTCTL_BASE		0x2B00000
+
+#define CONFIG_SYS_IMMR			0x01000000
+#define CONFIG_SYS_FSL_CSU_ADDR		(CONFIG_SYS_IMMR + 0x00510000)
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE		0x440
+#define MAX_MMAP_REGIONS		6
+#define MAX_XLAT_TABLES			4
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE		0x400
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			6
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE		0x400
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			4
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE		0x440
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			9
+#endif
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/layerscape/board/ls1043/include/soc_tzasc.h b/plat/layerscape/board/ls1043/include/soc_tzasc.h
new file mode 100644
index 0000000..46dfba0
--- /dev/null
+++ b/plat/layerscape/board/ls1043/include/soc_tzasc.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_TZASC_H
+#define SOC_TZASC_H
+
+#define MAX_NUM_TZC_REGION	3
+
+/* TZASC related constants */
+#define TZASC_CONFIGURATION_REG		0x000
+#define TZASC_SECURITY_INV_REG		0x034
+#define TZASC_SECURITY_INV_EN		0x1
+#define TZASC_REGIONS_REG		0x100
+/* As region address should address atleast 32KB memory. */
+#define TZASC_REGION_LOWADDR_MASK	0xFFFF8000
+#define TZASC_REGION_LOWADDR_OFFSET	0x0
+#define TZASC_REGION_HIGHADDR_OFFSET	0x4
+#define TZASC_REGION_ATTR_OFFSET	0x8
+#define TZASC_REGION_ENABLED		1
+#define TZASC_REGION_DISABLED		0
+#define TZASC_REGION_SIZE_32KB		0xE
+#define TZASC_REGION_SIZE_64KB		0xF
+#define TZASC_REGION_SIZE_128KB		0x10
+#define TZASC_REGION_SIZE_256KB		0x11
+#define TZASC_REGION_SIZE_512KB		0x12
+#define TZASC_REGION_SIZE_1MB		0x13
+#define TZASC_REGION_SIZE_2MB		0x14
+#define TZASC_REGION_SIZE_4MB		0x15
+#define TZASC_REGION_SIZE_8MB		0x16
+#define TZASC_REGION_SIZE_16MB		0x17
+#define TZASC_REGION_SIZE_32MB		0x18
+#define TZASC_REGION_SIZE_64MB		0x19
+#define TZASC_REGION_SIZE_128MB		0x1A
+#define TZASC_REGION_SIZE_256MB		0x1B
+#define TZASC_REGION_SIZE_512MB		0x1C
+#define TZASC_REGION_SIZE_1GB		0x1D
+#define TZASC_REGION_SIZE_2GB		0x1E
+#define TZASC_REGION_SIZE_4GB		0x1F
+#define TZASC_REGION_SIZE_8GB		0x20
+#define TZASC_REGION_SIZE_16GB		0x21
+#define TZASC_REGION_SIZE_32GB		0x22
+#define TZASC_REGION_SECURITY_SR	(1 << 3)
+#define TZASC_REGION_SECURITY_SW	(1 << 2)
+#define TZASC_REGION_SECURITY_SRW	(TZASC_REGION_SECURITY_SR| \
+						TZASC_REGION_SECURITY_SW)
+#define TZASC_REGION_SECURITY_NSR	(1 << 1)
+#define TZASC_REGION_SECURITY_NSW	1
+#define TZASC_REGION_SECURITY_NSRW	(TZASC_REGION_SECURITY_NSR| \
+						TZASC_REGION_SECURITY_NSW)
+
+#define CSU_SEC_ACCESS_REG_OFFSET	0x21C
+#define TZASC_BYPASS_MUX_DISABLE	0x4
+#define CCI_TERMINATE_BARRIER_TX	0x8
+#define CONFIG_SYS_FSL_TZASC_ADDR	0x1500000
+
+struct tzc380_reg {
+	unsigned int secure;
+	unsigned int enabled;
+	unsigned int low_addr;
+	unsigned int high_addr;
+	unsigned int size;
+	unsigned int sub_mask;
+};
+
+/* List of MAX_NUM_TZC_REGION TZC regions' boundaries and configurations. */
+
+static const struct tzc380_reg tzc380_reg_list[] = {
+	{
+		TZASC_REGION_SECURITY_NSRW,	/* .secure attr */
+		0x0,			/* .enabled */
+		0x0,			/* .lowaddr */
+		0x0,			/* .highaddr */
+		0x0,			/* .size */
+		0x0,			/* .submask */
+	},
+	{
+		TZASC_REGION_SECURITY_SRW,
+		TZASC_REGION_ENABLED,
+		0xFC000000,
+		0x0,
+		TZASC_REGION_SIZE_64MB,
+		0x80,			/* Disable region 7 */
+	},
+	/* reserve 2M non-scure memory for OPTEE public memory */
+	{
+		TZASC_REGION_SECURITY_SRW,
+		TZASC_REGION_ENABLED,
+		0xFF800000,
+		0x0,
+		TZASC_REGION_SIZE_8MB,
+		0xC0,			/* Disable region 6 & 7 */
+	},
+
+	{}
+};
+
+#endif /* SOC_TZASC_H */
diff --git a/plat/layerscape/board/ls1043/ls1043_bl1_setup.c b/plat/layerscape/board/ls1043/ls1043_bl1_setup.c
new file mode 100644
index 0000000..dfa4725
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_bl1_setup.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/mmio.h>
+
+#include "plat_ls.h"
+
+static const int cci_map[] = {
+	PLAT_LS1043_CCI_CLUSTER0_SL_IFACE_IX
+};
+
+void bl1_platform_setup(void)
+{
+	NOTICE(FIRMWARE_WELCOME_STR_LS1043);
+
+	ls_bl1_platform_setup();
+
+	/*
+	 * Initialize system level generic timer for Layerscape Socs.
+	 */
+	ls_delay_timer_init();
+
+	/* TODO: remove these DDR code */
+	VERBOSE("CS0_BNDS = %x\n", mmio_read_32(0x1080000 + 0x000));
+	mmio_write_32(0x1080000 + 0x000, 0x7f000000);
+	VERBOSE("CS0_BNDS = %x\n", mmio_read_32(0x1080000 + 0x000));
+}
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	ls_bl1_early_platform_setup();
+
+	/*
+	 * Initialize Interconnect for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	cci_init(PLAT_LS1043_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+
+	/*
+	 * Enable coherency in Interconnect for the primary CPU's cluster.
+	 */
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+
+}
+
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	return BL2_IMAGE_ID;
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_bl2_setup.c b/plat/layerscape/board/ls1043/ls1043_bl2_setup.c
new file mode 100644
index 0000000..c9db814
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_bl2_setup.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "plat_ls.h"
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3)
+{
+	ls_bl2_early_platform_setup((meminfo_t *)arg1);
+
+	/*
+	 * Initialize system level generic timer for Layerscape Socs.
+	 */
+	ls_delay_timer_init();
+}
+
+void bl2_platform_setup(void)
+{
+	NOTICE(FIRMWARE_WELCOME_STR_LS1043_BL2);
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_bl31_setup.c b/plat/layerscape/board/ls1043/ls1043_bl31_setup.c
new file mode 100644
index 0000000..6d15c11
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_bl31_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+
+#include "plat_ls.h"
+#include "fsl_csu.h"
+
+/* slave interfaces according to the RM */
+static const int cci_map[] = {
+	4,
+};
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3)
+{
+#ifdef LS_BL2_IN_OCRAM
+	unsigned long romem_base = (unsigned long)(&__TEXT_START__);
+	unsigned long romem_size = (unsigned long)(&__RODATA_END__)
+					- romem_base;
+
+	/* Check the Text and RO-Data region size */
+	if (romem_size > BL31_TEXT_RODATA_SIZE) {
+		ERROR("BL31 Text and RO-Data region size exceed reserved memory size\n");
+		panic();
+	}
+#endif
+
+	/*
+	 * Initialize system level generic timer for Layerscape Socs.
+	 */
+	ls_delay_timer_init();
+
+	ls_bl31_early_platform_setup((void *)arg0, (void *)arg3);
+
+	/*
+	 * Initialize the correct interconnect for this cluster during cold
+	 * boot. No need for locks as no other CPU is active.
+	 */
+	cci_init(PLAT_LS1043_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+
+	/*
+	 * Enable coherency in interconnect for the primary CPU's cluster.
+	 * Earlier bootloader stages might already do this (e.g. Trusted
+	 * Firmware's BL1 does it) but we can't assume so. There is no harm in
+	 * executing this code twice anyway.
+	 */
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+
+	/* Init CSU to enable non-secure access to peripherals */
+	enable_layerscape_ns_access();
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_err.c b/plat/layerscape/board/ls1043/ls1043_err.c
new file mode 100644
index 0000000..37077d4
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_err.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+/*
+ * Error handler
+ */
+void plat_error_handler(int err)
+{
+	switch (err) {
+	case -ENOENT:
+	case -EAUTH:
+		/* ToDo */
+		break;
+	default:
+		/* Unexpected error */
+		break;
+	}
+
+	/* Loop until the watchdog resets the system */
+	for (;;)
+		wfi();
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_psci.c b/plat/layerscape/board/ls1043/ls1043_psci.c
new file mode 100644
index 0000000..8e282cb
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_psci.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#define LS_SCFG_BASE			0x01570000
+/* register to store warm boot entry, big endian, higher 32bit */
+#define LS_SCFG_SCRATCHRW0_OFFSET	     0x600
+/* register to store warm boot entry, big endian, lower 32bit */
+#define LS_SCFG_SCRATCHRW1_OFFSET	     0x604
+#define LS_SCFG_COREBCR_OFFSET		     0x680
+
+#define LS_DCFG_BASE			0x01EE0000
+#define LS_DCFG_RSTCR_OFFSET		     0x0B0
+#define LS_DCFG_RSTRQMR1_OFFSET		     0x0C0
+#define LS_DCFG_BRR_OFFSET		     0x0E4
+
+#define LS_SCFG_CORE0_SFT_RST_OFFSET		0x130
+#define LS_SCFG_CORE1_SFT_RST_OFFSET		0x134
+#define LS_SCFG_CORE2_SFT_RST_OFFSET		0x138
+#define LS_SCFG_CORE3_SFT_RST_OFFSET		0x13C
+
+#define LS_SCFG_CORESRENCR_OFFSET		0x204
+
+#define LS_SCFG_RVBAR0_0_OFFSET			0x220
+#define LS_SCFG_RVBAR0_1_OFFSET			0x224
+
+#define LS_SCFG_RVBAR1_0_OFFSET			0x228
+#define LS_SCFG_RVBAR1_1_OFFSET			0x22C
+
+#define LS_SCFG_RVBAR2_0_OFFSET			0x230
+#define LS_SCFG_RVBAR2_1_OFFSET			0x234
+
+#define LS_SCFG_RVBAR3_0_OFFSET			0x238
+#define LS_SCFG_RVBAR3_1_OFFSET			0x23C
+
+/* the entry for core warm boot */
+static uintptr_t warmboot_entry;
+
+/* warm reset single core */
+static void ls1043_reset_core(int core_pos)
+{
+	assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);
+
+	/* set 0 in RVBAR, boot from bootrom at 0x0 */
+	mmio_write_32(LS_SCFG_BASE + LS_SCFG_RVBAR0_0_OFFSET + core_pos * 8,
+		      0);
+	mmio_write_32(LS_SCFG_BASE + LS_SCFG_RVBAR0_1_OFFSET + core_pos * 8,
+		      0);
+
+	dsb();
+	/* enable core soft reset */
+	mmio_write_32(LS_SCFG_BASE + LS_SCFG_CORESRENCR_OFFSET,
+		      htobe32(1U << 31));
+	dsb();
+	isb();
+	/* reset core */
+	mmio_write_32(LS_SCFG_BASE + LS_SCFG_CORE0_SFT_RST_OFFSET +
+			core_pos * 4, htobe32(1U << 31));
+	mdelay(10);
+}
+
+static void __dead2 ls1043_system_reset(void)
+{
+	/* clear reset request mask bits */
+	mmio_write_32(LS_DCFG_BASE + LS_DCFG_RSTRQMR1_OFFSET, 0);
+
+	/* set reset request bit */
+	mmio_write_32(LS_DCFG_BASE + LS_DCFG_RSTCR_OFFSET,
+		      htobe32((uint32_t)0x2));
+
+	/* system will reset; if fail, enter wfi */
+	dsb();
+	isb();
+	wfi();
+
+	panic();
+}
+
+
+static int ls1043_pwr_domain_on(u_register_t mpidr)
+{
+	int core_pos = plat_core_pos_by_mpidr(mpidr);
+	uint32_t core_mask, brr;
+
+	assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);
+	core_mask = 1 << core_pos;
+
+	/* set warm boot entry */
+	mmio_write_32(LS_SCFG_BASE + LS_SCFG_SCRATCHRW0_OFFSET,
+		htobe32((uint32_t)(warmboot_entry >> 32)));
+
+	mmio_write_32(LS_SCFG_BASE + LS_SCFG_SCRATCHRW1_OFFSET,
+		htobe32((uint32_t)warmboot_entry));
+
+	dsb();
+
+	brr = be32toh(mmio_read_32(LS_DCFG_BASE + LS_DCFG_BRR_OFFSET));
+	if (brr & core_mask) {
+		/* core has been released, must reset it to restart */
+		ls1043_reset_core(core_pos);
+
+		/* set bit in core boot control register to enable boot */
+		mmio_write_32(LS_SCFG_BASE + LS_SCFG_COREBCR_OFFSET,
+			htobe32(core_mask));
+
+	} else {
+		/* set bit in core boot control register to enable boot */
+		mmio_write_32(LS_SCFG_BASE + LS_SCFG_COREBCR_OFFSET,
+			htobe32(core_mask));
+
+		/* release core */
+		mmio_write_32(LS_DCFG_BASE + LS_DCFG_BRR_OFFSET,
+			      htobe32(brr | core_mask));
+	}
+
+	mdelay(20);
+
+	/* wake core in case it is in wfe */
+	dsb();
+	isb();
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void ls1043_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* Per cpu gic distributor setup */
+	gicv2_pcpu_distif_init();
+
+	/* Enable the gic CPU interface */
+	gicv2_cpuif_enable();
+}
+
+static void ls1043_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	/* Disable the gic CPU interface */
+	gicv2_cpuif_disable();
+}
+
+static plat_psci_ops_t ls1043_psci_pm_ops = {
+	.system_reset = ls1043_system_reset,
+	.pwr_domain_on = ls1043_pwr_domain_on,
+	.pwr_domain_on_finish = ls1043_pwr_domain_on_finish,
+	.pwr_domain_off = ls1043_pwr_domain_off,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	warmboot_entry = sec_entrypoint;
+	*psci_ops = &ls1043_psci_pm_ops;
+	return 0;
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_security.c b/plat/layerscape/board/ls1043/ls1043_security.c
new file mode 100644
index 0000000..18ae56e
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_security.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "plat_ls.h"
+
+/*
+ * We assume that all security programming is done by the primary core.
+ */
+void plat_ls_security_setup(void)
+{
+	tzc380_setup();
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_stack_protector.c b/plat/layerscape/board/ls1043/ls1043_stack_protector.c
new file mode 100644
index 0000000..8a1a4e5
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_stack_protector.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL)
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+	/*
+	 * Ideally, a random number should be returned instead of the
+	 * combination of a timer's value and a compile-time constant. As the
+	 * FVP does not have any random number generator, this is better than
+	 * nothing but not necessarily really secure.
+	 */
+	return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
diff --git a/plat/layerscape/board/ls1043/ls1043_topology.c b/plat/layerscape/board/ls1043/ls1043_topology.c
new file mode 100644
index 0000000..c9c6a9c
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls1043_topology.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+
+#include <lib/cassert.h>
+
+#include "plat_ls.h"
+#include "platform_def.h"
+
+unsigned char ls1043_power_domain_tree_desc[LS1043_CLUSTER_COUNT + 1];
+
+
+CASSERT(LS1043_CLUSTER_COUNT && LS1043_CLUSTER_COUNT <= 256,
+		assert_invalid_ls1043_cluster_count);
+
+/*******************************************************************************
+ * This function dynamically constructs the topology according to
+ * LS1043_CLUSTER_COUNT and returns it.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	int i;
+
+	ls1043_power_domain_tree_desc[0] = LS1043_CLUSTER_COUNT;
+
+	for (i = 0; i < LS1043_CLUSTER_COUNT; i++)
+		ls1043_power_domain_tree_desc[i + 1] =
+						LS1043_MAX_CPUS_PER_CLUSTER;
+
+	return ls1043_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function returns the core count within the cluster corresponding to
+ * `mpidr`.
+ ******************************************************************************/
+unsigned int plat_ls_get_cluster_core_count(u_register_t mpidr)
+{
+	return LS1043_MAX_CPUS_PER_CLUSTER;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	if (ls_check_mpidr(mpidr) == -1)
+		return -1;
+
+	return plat_ls_calc_core_pos(mpidr);
+}
diff --git a/plat/layerscape/board/ls1043/ls_gic.c b/plat/layerscape/board/ls1043/ls_gic.c
new file mode 100644
index 0000000..cba55ca
--- /dev/null
+++ b/plat/layerscape/board/ls1043/ls_gic.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <endian.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "soc.h"
+
+/*
+ * Get GIC offset
+ * For LS1043a rev1.0, GIC base address align with 4k.
+ * For LS1043a rev1.1, if DCFG_GIC400_ALIGN[GIC_ADDR_BIT]
+ * is set, GIC base address align with 4K, or else align
+ * with 64k.
+ */
+void get_gic_offset(uint32_t *gicc_base, uint32_t *gicd_base)
+{
+
+	uint32_t *ccsr_svr = (uint32_t *)DCFG_CCSR_SVR;
+	uint32_t *gic_align = (uint32_t *)SCFG_GIC400_ALIGN;
+	uint32_t val;
+	uint32_t soc_dev_id;
+
+	val = be32toh(mmio_read_32((uintptr_t)ccsr_svr));
+	soc_dev_id = val & (SVR_WO_E << 8);
+
+	if ((soc_dev_id == (SVR_LS1043A << 8) ||
+			soc_dev_id == (SVR_LS1043AE << 8)) &&
+			((val & 0xff) == REV1_1)) {
+		val = be32toh(mmio_read_32((uintptr_t)gic_align));
+		if (val & (1U << GIC_ADDR_BIT)) {
+			*gicc_base = GICC_BASE;
+			*gicd_base = GICD_BASE;
+		} else {
+			*gicc_base = GICC_BASE_64K;
+			*gicd_base = GICD_BASE_64K;
+		}
+	} else {
+		*gicc_base = GICC_BASE;
+		*gicd_base = GICD_BASE;
+	}
+}
diff --git a/plat/layerscape/board/ls1043/platform.mk b/plat/layerscape/board/ls1043/platform.mk
new file mode 100644
index 0000000..d716c61
--- /dev/null
+++ b/plat/layerscape/board/ls1043/platform.mk
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+USE_COHERENT_MEM		:=	0
+RESET_TO_BL31			:=	0
+ENABLE_STACK_PROTECTOR		:=	0
+LS1043_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+					drivers/arm/gic/v2/gicv2_main.c		\
+					drivers/arm/gic/v2/gicv2_helpers.c	\
+					plat/common/plat_gicv2.c		\
+					plat/layerscape/board/ls1043/ls_gic.c
+
+
+LS1043_INTERCONNECT_SOURCES	:= 	drivers/arm/cci/cci.c
+
+LS1043_SECURITY_SOURCES 	:=	plat/layerscape/common/ls_tzc380.c	\
+					plat/layerscape/board/ls1043/ls1043_security.c
+
+PLAT_INCLUDES			:=	-Iplat/layerscape/board/ls1043/include   \
+					-Iplat/layerscape/common/include	\
+
+PLAT_BL_COMMON_SOURCES		:=	plat/layerscape/common/aarch64/ls_console.S
+
+LS1043_CPU_LIBS			:=	lib/cpus/${ARCH}/aem_generic.S
+
+LS1043_CPU_LIBS			+=	lib/cpus/aarch64/cortex_a53.S
+
+BL1_SOURCES			+= 	plat/layerscape/board/ls1043/ls1043_bl1_setup.c		\
+					plat/layerscape/board/ls1043/ls1043_err.c			\
+					drivers/delay_timer/delay_timer.c \
+
+BL1_SOURCES     		+=	plat/layerscape/board/ls1043/${ARCH}/ls1043_helpers.S \
+					${LS1043_CPU_LIBS}					\
+					${LS1043_INTERCONNECT_SOURCES}		\
+					$(LS1043_SECURITY_SOURCES)
+
+
+BL2_SOURCES			+=	drivers/delay_timer/delay_timer.c		\
+					plat/layerscape/board/ls1043/ls1043_bl2_setup.c		\
+					plat/layerscape/board/ls1043/ls1043_err.c			\
+					${LS1043_SECURITY_SOURCES}
+
+
+BL31_SOURCES			+=	plat/layerscape/board/ls1043/ls1043_bl31_setup.c		\
+					plat/layerscape/board/ls1043/ls1043_topology.c		\
+					plat/layerscape/board/ls1043/aarch64/ls1043_helpers.S	\
+					plat/layerscape/board/ls1043/ls1043_psci.c		\
+					drivers/delay_timer/delay_timer.c		\
+					${LS1043_CPU_LIBS}					\
+					${LS1043_GIC_SOURCES}				\
+					${LS1043_INTERCONNECT_SOURCES}			\
+					${LS1043_SECURITY_SOURCES}
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_855873		:=	1
+
+ifneq (${ENABLE_STACK_PROTECTOR},0)
+PLAT_BL_COMMON_SOURCES		+=	plat/layerscape/board/ls1043/ls1043_stack_protector.c
+endif
+
+ifeq (${ARCH},aarch32)
+    NEED_BL32 := yes
+endif
+
+include plat/layerscape/common/ls_common.mk
diff --git a/plat/layerscape/board/ls1043/tsp/ls1043_tsp_setup.c b/plat/layerscape/board/ls1043/tsp/ls1043_tsp_setup.c
new file mode 100644
index 0000000..4fc019c
--- /dev/null
+++ b/plat/layerscape/board/ls1043/tsp/ls1043_tsp_setup.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "plat_ls.h"
+
+void tsp_early_platform_setup(void)
+{
+	ls_tsp_early_platform_setup();
+
+	/*Todo: Initialize the platform config for future decision making */
+}
diff --git a/plat/layerscape/board/ls1043/tsp/tsp-ls1043.mk b/plat/layerscape/board/ls1043/tsp/tsp-ls1043.mk
new file mode 100644
index 0000000..3941427
--- /dev/null
+++ b/plat/layerscape/board/ls1043/tsp/tsp-ls1043.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TSP source files specific to FVP platform
+BL32_SOURCES		+=	plat/layerscape/board/ls1043/ls1043_topology.c		\
+				plat/layerscape/board/ls1043/tsp/ls1043_tsp_setup.c		\
+				${LS1043_GIC_SOURCES}
+
+include plat/layerscape/common/tsp/ls_tsp.mk
diff --git a/plat/layerscape/common/aarch64/ls_bl2_mem_params_desc.c b/plat/layerscape/common/aarch64/ls_bl2_mem_params_desc.c
new file mode 100644
index 0000000..9410740
--- /dev/null
+++ b/plat/layerscape/common/aarch64/ls_bl2_mem_params_desc.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+#include <ls_def.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				VERSION_2, entry_point_info_t,
+				SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.pc = EL3_PAYLOAD_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				VERSION_2, image_info_t,
+				IMAGE_ATTRIB_PLAT_SETUP |
+				IMAGE_ATTRIB_SKIP_LOADING),
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				VERSION_2, entry_point_info_t,
+				SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.pc = BL31_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+		.ep_info.args.arg1 = LS_BL31_PLAT_PARAM_VAL,
+#endif
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+			VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+		.image_info.image_base = BL31_BASE,
+		.image_info.image_max_size = (BL31_LIMIT - BL31_BASE),
+
+# ifdef BL32_BASE
+		.next_handoff_image_id = BL32_IMAGE_ID,
+# else
+		.next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+	},
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+			VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
+		.ep_info.pc = BL32_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL32_BASE,
+		.image_info.image_max_size = (BL32_LIMIT - BL32_BASE),
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+	{
+		.image_id = BL33_IMAGE_ID,
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+			VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+		.ep_info.pc = PRELOADED_BL33_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				VERSION_2, image_info_t,
+				IMAGE_ATTRIB_SKIP_LOADING),
+# else
+		.ep_info.pc = BL33_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL33_BASE,
+		.image_info.image_max_size = LS_NS_DRAM_SIZE,
+# endif /* PRELOADED_BL33_BASE */
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+#endif /* EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/layerscape/common/aarch64/ls_console.S b/plat/layerscape/common/aarch64/ls_console.S
new file mode 100644
index 0000000..f8948b4
--- /dev/null
+++ b/plat/layerscape/common/aarch64/ls_console.S
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <console_macros.S>
+#include <assert_macros.S>
+#include "ls_16550.h"
+
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_ls_16550_core_init
+	.globl console_ls_16550_core_putc
+	.globl console_ls_16550_core_getc
+
+	.globl console_ls_16550_putc
+	.globl console_ls_16550_getc
+	.globl console_ls_16550_flush
+
+	/* -----------------------------------------------
+	 * int console_ls_16550_core_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x1, x2, x3
+	 * -----------------------------------------------
+	 */
+func console_ls_16550_core_init
+	/* Check the input base address */
+	cbz	x0, init_fail
+	/* Check baud rate and uart clock for sanity */
+	cbz	w1, init_fail
+	cbz	w2, init_fail
+
+	/* Program the baudrate */
+	/* Divisor =  Uart clock / (16 * baudrate) */
+	lsl	w2, w2, #4
+	udiv	w2, w1, w2
+	and	w1, w2, #0xff		/* w1 = DLL */
+	lsr	w2, w2, #8
+	and	w2, w2, #0xff		/* w2 = DLLM */
+	ldrb	w3, [x0, #UARTLCR]
+	orr	w3, w3, #UARTLCR_DLAB
+	strb	w3, [x0, #UARTLCR]	/* enable DLL, DLLM programming */
+	strb	w1, [x0, #UARTDLL]	/* program DLL */
+	strb	w2, [x0, #UARTDLLM]	/* program DLLM */
+	mov	w2, #~UARTLCR_DLAB
+	and	w3, w3, w2
+	strb	w3, [x0, #UARTLCR]	/* disable DLL, DLLM programming */
+
+	/* 8n1 */
+	mov	w3, #3
+	strb	w3, [x0, #UARTLCR]
+	/* no interrupt */
+	mov	w3, #0
+	strb	w3, [x0, #UARTIER]
+	/* enable fifo, DMA */
+	mov	w3, #(UARTFCR_FIFOEN |UARTFCR_TXCLR | UARTFCR_RXCLR)
+	strb	w3, [x0, #UARTFCR]
+	/* DTR + RTS */
+	mov	w3, #3
+	str	w3, [x0, #UARTMCR]
+	mov	w0, #1
+	ret
+init_fail:
+	mov	w0, #0
+	ret
+endfunc console_ls_16550_core_init
+
+	.globl console_ls_16550_register
+
+	/* -----------------------------------------------
+	 * int console_ls_16550_register(console_ls_16550_t *console,
+	 *	uintptr_t base, uint32_t clk, uint32_t baud)
+	 * Function to initialize and register a new 16550
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_ls_16550_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_ls_16550_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_16550_BASE]
+
+	bl	console_ls_16550_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register ls_16550 putc=1, getc=1, flush=1
+
+register_fail:
+	ret	x7
+endfunc console_ls_16550_register
+
+	/* --------------------------------------------------------
+	 * int console_ls_16550_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_ls_16550_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA //'\n'
+	b.ne	2f
+	/* Check if the transmit FIFO is full */
+1:	ldrb	w2, [x1, #UARTLSR]
+	and	w2, w2, #UARTLSR_THRE        /* #(UARTLSR_TEMT | UARTLSR_THRE)*/
+	cmp	w2, #(UARTLSR_THRE)
+	b.ne	1b
+	mov	w2, #0xD		/* '\r' */
+	strb	w2, [x1, #UARTTX]
+	ldrb	w2, [x1, #UARTFCR]
+	orr	w2, w2, #UARTFCR_TXCLR
+
+	/* Check if the transmit FIFO is full */
+2:	ldrb	w2, [x1, #UARTLSR]
+	and	w2, w2, #(UARTLSR_THRE)
+	cmp	w2, #(UARTLSR_THRE)
+	b.ne	2b
+	strb	w0, [x1, #UARTTX]
+	ret
+endfunc console_ls_16550_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_16550_putc(int c, console_ls_16550_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_ls_16550_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_16550_BASE]
+	b	console_ls_16550_core_putc
+endfunc console_ls_16550_putc
+
+	/* ---------------------------------------------
+	 * int console_ls_16550_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  x0 - console base address
+	 * Out : w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_ls_16550_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Check if the receive FIFO is empty */
+1:	ldrb	w1, [x0, #UARTLSR]
+	tbz	w1, #UARTLSR_RDR, 1b
+	ldrb	w0, [x0, #UARTRX]
+	ret
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+endfunc console_ls_16550_core_getc
+
+	/* ---------------------------------------------
+	 * int console_ls_16550_getc(console_ls_16550_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  x0 - pointer to console_t structure
+	 * Out : w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_ls_16550_getc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
+	b	console_ls_16550_core_getc
+endfunc console_ls_16550_getc
+
+	/* ---------------------------------------------
+	 * int console_ls_16550_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_ls_16550_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
+	/* Loop until the transmit FIFO is empty */
+1:	ldrb	w1, [x0, #UARTLSR]
+	and	w1, w1, #(UARTLSR_TEMT | UARTLSR_THRE)
+	cmp	w1, #(UARTLSR_TEMT | UARTLSR_THRE)
+	b.ne	1b
+
+	mov	w0, #0
+	ret
+endfunc console_ls_16550_core_flush
+
+	/* ---------------------------------------------
+	 * int console_ls_16550_flush(console_ls_16550_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_ls_16550_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
+	b	console_ls_16550_core_flush
+endfunc console_ls_16550_flush
diff --git a/plat/layerscape/common/aarch64/ls_helpers.S b/plat/layerscape/common/aarch64/ls_helpers.S
new file mode 100644
index 0000000..5aa5497
--- /dev/null
+++ b/plat/layerscape/common/aarch64/ls_helpers.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+#include <platform_def.h>
+
+	.weak	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.weak	platform_mem_init
+	.globl	plat_ls_calc_core_pos
+
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_ls_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_ls_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_ls_calc_core_pos(u_register_t mpidr)
+	 *  Helper function to calculate the core position.
+	 *  With this function: CorePos = (ClusterId * 4) +
+	 *  				  CoreId
+	 * -----------------------------------------------------
+	 */
+func plat_ls_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_ls_calc_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+
+	/* -----------------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Use normal console by default. Switch it to crash
+	 * mode so serial consoles become active again.
+	 * NOTE: This default implementation will only work for
+	 * crashes that occur after a normal console (marked
+	 * valid for the crash state) has been registered with
+	 * the console framework. To debug crashes that occur
+	 * earlier, the platform has to override these functions
+	 * with an implementation that initializes a console
+	 * driver with hardcoded parameters. See
+	 * docs/porting-guide.rst for more information.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_init
+#if defined(IMAGE_BL1)
+	/*
+	 * BL1 code can possibly crash so early that the data segment is not yet
+	 * accessible. Don't risk undefined behavior by trying to run the normal
+	 * console framework. Platforms that want to debug BL1 will need to
+	 * override this with custom functions that can run from registers only.
+	 */
+	mov	x0, #0
+	ret
+#else	/* IMAGE_BL1 */
+	mov	x3, x30
+	mov	x0, #CONSOLE_FLAG_CRASH
+	bl	console_switch_state
+	mov	x0, #1
+	ret	x3
+#endif
+endfunc plat_crash_console_init
+
+	/* -----------------------------------------------------
+	 * void plat_crash_console_putc(int character)
+	 * Output through the normal console by default.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_putc
+	b	console_putc
+endfunc plat_crash_console_putc
+
+	/* -----------------------------------------------------
+	 * void plat_crash_console_flush(void)
+	 * Flush normal console by default.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_flush
+	b	console_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on LS
+	 * platforms. The Secure SRAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/layerscape/common/include/fsl_csu.h b/plat/layerscape/common/include/fsl_csu.h
new file mode 100644
index 0000000..5cc88b1
--- /dev/null
+++ b/plat/layerscape/common/include/fsl_csu.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FSL_CSU_H
+#define FSL_CSU_H
+
+enum csu_cslx_access {
+	CSU_NS_SUP_R = 0x08,
+	CSU_NS_SUP_W = 0x80,
+	CSU_NS_SUP_RW = 0x88,
+	CSU_NS_USER_R = 0x04,
+	CSU_NS_USER_W = 0x40,
+	CSU_NS_USER_RW = 0x44,
+	CSU_S_SUP_R = 0x02,
+	CSU_S_SUP_W = 0x20,
+	CSU_S_SUP_RW = 0x22,
+	CSU_S_USER_R = 0x01,
+	CSU_S_USER_W = 0x10,
+	CSU_S_USER_RW = 0x11,
+	CSU_ALL_RW = 0xff,
+};
+
+struct csu_ns_dev {
+	uintptr_t ind;
+	uint32_t val;
+};
+
+void enable_layerscape_ns_access(void);
+
+#endif /* FSL_CSU_H */
diff --git a/plat/layerscape/common/include/ls_16550.h b/plat/layerscape/common/include/ls_16550.h
new file mode 100644
index 0000000..cb4514f
--- /dev/null
+++ b/plat/layerscape/common/include/ls_16550.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LS_16550_H
+#define LS_16550_H
+
+#include <drivers/console.h>
+
+/* UART16550 Registers */
+#define UARTTX			0x0
+#define UARTRX			0x0
+#define UARTDLL			0x0
+#define UARTIER			0x1
+#define UARTDLLM		0x1
+#define UARTFCR			0x2
+#define UARTLCR			0x3
+#define UARTLSR			0x5
+#define UARTMCR                 0x4
+
+/* FIFO Control Register bits */
+#define UARTFCR_FIFOMD_16450	(0 << 6)
+#define UARTFCR_FIFOMD_16550	(1 << 6)
+#define UARTFCR_RXTRIG_1	(0 << 6)
+#define UARTFCR_RXTRIG_4	(1 << 6)
+#define UARTFCR_RXTRIG_8	(2 << 6)
+#define UARTFCR_RXTRIG_16	(3 << 6)
+#define UARTFCR_TXTRIG_1	(0 << 4)
+#define UARTFCR_TXTRIG_4	(1 << 4)
+#define UARTFCR_TXTRIG_8	(2 << 4)
+#define UARTFCR_TXTRIG_16	(3 << 4)
+#define UARTFCR_DMAEN		(1 << 3)	/* Enable DMA mode */
+#define UARTFCR_TXCLR		(1 << 2)	/* Clear contents of Tx FIFO */
+#define UARTFCR_RXCLR		(1 << 1)	/* Clear contents of Rx FIFO */
+#define UARTFCR_FIFOEN		(1 << 0)	/* Enable the Tx/Rx FIFO */
+#define UARTFCR_64FIFO          (1 << 5)
+
+/* Line Control Register bits */
+#define UARTLCR_DLAB		(1 << 7)	/* Divisor Latch Access */
+#define UARTLCR_SETB		(1 << 6)	/* Set BREAK Condition */
+#define UARTLCR_SETP		(1 << 5)	/* Set Parity to LCR[4] */
+#define UARTLCR_EVEN		(1 << 4)	/* Even Parity Format */
+#define UARTLCR_PAR		(1 << 3)	/* Parity */
+#define UARTLCR_STOP		(1 << 2)	/* Stop Bit */
+#define UARTLCR_WORDSZ_5	0		/* Word Length of 5 */
+#define UARTLCR_WORDSZ_6	1		/* Word Length of 6 */
+#define UARTLCR_WORDSZ_7	2		/* Word Length of 7 */
+#define UARTLCR_WORDSZ_8	3		/* Word Length of 8 */
+
+/* Line Status Register bits */
+#define UARTLSR_RXFIFOEMT	(1 << 9)	/* Rx Fifo Empty */
+#define UARTLSR_TXFIFOFULL	(1 << 8)	/* Tx Fifo Full */
+#define UARTLSR_RXFIFOERR	(1 << 7)	/* Rx Fifo Error */
+#define UARTLSR_TEMT		(1 << 6)	/* Tx Shift Register Empty */
+#define UARTLSR_THRE		(1 << 5)	/* Tx Holding Register Empty */
+#define UARTLSR_BRK		(1 << 4)	/* Break Condition Detected */
+#define UARTLSR_FERR		(1 << 3)	/* Framing Error */
+#define UARTLSR_PERR		(1 << 3)	/* Parity Error */
+#define UARTLSR_OVRF		(1 << 2)	/* Rx Overrun Error */
+#define UARTLSR_RDR		(1 << 2)	/* Rx Data Ready */
+
+#define CONSOLE_T_16550_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_ls_16550_t;
+
+/*
+ * Initialize a new 16550 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_ls_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_ls_16550_t *console);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* LS_16550_H */
diff --git a/plat/layerscape/common/include/plat_ls.h b/plat/layerscape/common/include/plat_ls.h
new file mode 100644
index 0000000..e56670b
--- /dev/null
+++ b/plat/layerscape/common/include/plat_ls.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_LS_H
+#define PLAT_LS_H
+
+#include <stdint.h>
+
+#include <lib/el3_runtime/cpu_data.h>
+
+/* BL1 utility functions */
+void ls_bl1_platform_setup(void);
+void ls_bl1_early_platform_setup(void);
+
+/* BL2 utility functions */
+void ls_bl2_early_platform_setup(meminfo_t *mem_layout);
+uint32_t ls_get_spsr_for_bl32_entry(void);
+uint32_t ls_get_spsr_for_bl33_entry(void);
+
+/* BL3 utility functions */
+void ls_bl31_early_platform_setup(void *from_bl2,
+				void *plat_params_from_bl2);
+
+/* IO storage utility functions */
+void plat_ls_io_setup(void);
+
+
+void ls_setup_page_tables(uintptr_t total_base,
+			size_t total_size,
+			uintptr_t code_start,
+			uintptr_t code_limit,
+			uintptr_t rodata_start,
+			uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			, uintptr_t coh_start,
+			uintptr_t coh_limit
+#endif
+);
+
+/* PSCI utility functions */
+int ls_check_mpidr(u_register_t mpidr);
+
+/* Security utility functions */
+int tzc380_setup(void);
+
+/* Timer utility functions */
+uint64_t ls_get_timer(uint64_t start);
+void ls_delay_timer_init(void);
+
+/* TSP utility functions */
+void ls_tsp_early_platform_setup(void);
+
+/* Helper functions */
+unsigned int plat_ls_calc_core_pos(u_register_t mpidr);
+
+/* others */
+unsigned int plat_ls_get_cluster_core_count(u_register_t mpidr);
+
+#endif /* PLAT_LS_H */
diff --git a/plat/layerscape/common/include/soc.h b/plat/layerscape/common/include/soc.h
new file mode 100644
index 0000000..a5dc855
--- /dev/null
+++ b/plat/layerscape/common/include/soc.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+#include <stdint.h>
+
+#define SVR_WO_E		0xFFFFFEu
+#define SVR_LS1043A		0x879204u
+#define SVR_LS1043AE		0x879200u
+
+void get_gic_offset(uint32_t *gicc_base, uint32_t *gicd_base);
+
+#endif /* SOC_H */
diff --git a/plat/layerscape/common/ls_bl1_setup.c b/plat/layerscape/common/ls_bl1_setup.c
new file mode 100644
index 0000000..fff065e
--- /dev/null
+++ b/plat/layerscape/common/ls_bl1_setup.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+
+#include "ls_16550.h"
+#include "plat_ls.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL1*/
+static meminfo_t bl1_tzram_layout;
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*******************************************************************************
+ * BL1 specific platform actions shared between ARM standard platforms.
+ ******************************************************************************/
+void ls_bl1_early_platform_setup(void)
+{
+	static console_ls_16550_t console;
+
+#if !LS1043_DISABLE_TRUSTED_WDOG
+	/* TODO: Enable watchdog */
+
+#endif
+
+	/* Initialize the console to provide early debug support */
+	console_ls_16550_register(LS_TF_UART_BASE, LS_TF_UART_CLOCK,
+			       LS_TF_UART_BAUDRATE, &console);
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = LS_SRAM_BASE;
+	bl1_tzram_layout.total_size = LS_SRAM_SIZE;
+}
+
+/******************************************************************************
+ * Perform the very early platform specific architecture setup shared between
+ * ARM standard platforms. This only does basic initialization. Later
+ * architectural setup (bl1_arch_setup()) does not do anything platform
+ * specific.
+ *****************************************************************************/
+void ls_bl1_plat_arch_setup(void)
+{
+	ls_setup_page_tables(bl1_tzram_layout.total_base,
+			      bl1_tzram_layout.total_size,
+			      BL_CODE_BASE,
+			      BL1_CODE_END,
+			      BL1_RO_DATA_BASE,
+			      BL1_RO_DATA_END
+#if USE_COHERENT_MEM
+			      , BL_COHERENT_RAM_BASE,
+			      BL_COHERENT_RAM_END
+#endif
+			     );
+	VERBOSE("After setup the page tables\n");
+#ifdef __aarch64__
+	enable_mmu_el3(0);
+#else
+	enable_mmu_svc_mon(0);
+#endif /* __aarch64__ */
+	VERBOSE("After MMU enabled\n");
+}
+
+void bl1_plat_arch_setup(void)
+{
+	ls_bl1_plat_arch_setup();
+}
+
+/*
+ * Perform the platform specific architecture setup shared between
+ * ARM standard platforms.
+ */
+void ls_bl1_platform_setup(void)
+{
+	/* Initialise the IO layer and register platform IO devices */
+	plat_ls_io_setup();
+}
+
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
+{
+#if !LS1043_DISABLE_TRUSTED_WDOG
+	/*TODO: Disable watchdog before leaving BL1 */
+#endif
+}
diff --git a/plat/layerscape/common/ls_bl2_setup.c b/plat/layerscape/common/ls_bl2_setup.c
new file mode 100644
index 0000000..35f42e1
--- /dev/null
+++ b/plat/layerscape/common/ls_bl2_setup.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+
+#include "ls_16550.h"
+#include "plat_ls.h"
+#include "ls_def.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/*******************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ ******************************************************************************/
+void ls_bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+	static console_ls_16550_t console;
+
+	/* Initialize the console to provide early debug support */
+	console_ls_16550_register(LS_TF_UART_BASE, LS_TF_UART_CLOCK,
+			       LS_TF_UART_BAUDRATE, &console);
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+
+	/* Initialise the IO layer and register platform IO devices */
+	plat_ls_io_setup();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void ls_bl2_plat_arch_setup(void)
+{
+	ls_setup_page_tables(bl2_tzram_layout.total_base,
+			      bl2_tzram_layout.total_size,
+			      BL_CODE_BASE,
+			      BL_CODE_END,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_END
+#if USE_COHERENT_MEM
+			      , BL_COHERENT_RAM_BASE,
+			      BL_COHERENT_RAM_END
+#endif
+			      );
+
+#ifdef __aarch64__
+	enable_mmu_el1(0);
+#else
+	enable_mmu_svc_mon(0);
+#endif
+}
+
+void bl2_plat_arch_setup(void)
+{
+	ls_bl2_plat_arch_setup();
+}
+
+int ls_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+
+	assert(bl_mem_params);
+
+	switch (image_id) {
+#ifdef __aarch64__
+	case BL32_IMAGE_ID:
+		bl_mem_params->ep_info.spsr = ls_get_spsr_for_bl32_entry();
+		break;
+#endif
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = ls_get_spsr_for_bl33_entry();
+		break;
+	}
+
+	return err;
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return ls_bl2_handle_post_image_load(image_id);
+}
diff --git a/plat/layerscape/common/ls_bl31_setup.c b/plat/layerscape/common/ls_bl31_setup.c
new file mode 100644
index 0000000..03e5807
--- /dev/null
+++ b/plat/layerscape/common/ls_bl31_setup.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+
+#include "ls_16550.h"
+#include "plat_ls.h"
+#include "soc.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static const interrupt_prop_t g0_interrupt_props[] = {
+	INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+gicv2_driver_data_t ls_gic_data = {
+	.gicd_base = GICD_BASE,
+	.gicc_base = GICC_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for the
+ * security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type));
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup common to Layerscape platforms.
+ * Here is an opportunity to copy parameters passed by the calling EL (S-EL1
+ * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be
+ * done before the MMU is initialized so that the memory layout can be used
+ * while creating page tables. BL2 has flushed this information to memory, so
+ * we are guaranteed to pick up good data.
+ ******************************************************************************/
+void ls_bl31_early_platform_setup(void *from_bl2,
+				void *plat_params_from_bl2)
+{
+	static console_ls_16550_t console;
+
+	/* Initialize the console to provide early debug support */
+	console_ls_16550_register(LS_TF_UART_BASE, LS_TF_UART_CLOCK,
+				LS_TF_UART_BAUDRATE, &console);
+#if RESET_TO_BL31
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(from_bl2 == NULL);
+	assert(plat_params_from_bl2 == NULL);
+
+#ifdef BL32_BASE
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = ls_get_spsr_for_bl32_entry();
+#endif /* BL32_BASE */
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell BL31 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+
+	bl33_image_ep_info.spsr = ls_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#else /* RESET_TO_BL31 */
+
+	/*
+	 * In debug builds, we pass a special value in 'plat_params_from_bl2'
+	 * to verify platform parameters from BL2 to BL31.
+	 * In release builds, it's not used.
+	 */
+	assert(((unsigned long long)plat_params_from_bl2) ==
+		LS_BL31_PLAT_PARAM_VAL);
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_image_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0)
+		panic();
+
+#endif /* RESET_TO_BL31 */
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform setup common to Layerscape platforms
+ ******************************************************************************/
+void ls_bl31_platform_setup(void)
+{
+	uint32_t gicc_base, gicd_base;
+
+	NOTICE(FIRMWARE_WELCOME_STR_LS1043_BL31);
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	get_gic_offset(&gicc_base, &gicd_base);
+	ls_gic_data.gicd_base = (uintptr_t)gicd_base;
+	ls_gic_data.gicc_base = (uintptr_t)gicc_base;
+	gicv2_driver_init(&ls_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+#if RESET_TO_BL31
+	/*
+	 * Do initial security configuration to allow DRAM/device access
+	 * (if earlier BL has not already done so).
+	 */
+	plat_ls_security_setup();
+
+#endif /* RESET_TO_BL31 */
+
+	/* Enable and initialize the System level generic timer */
+	mmio_write_32(LS1043_SYS_CNTCTL_BASE + CNTCR_OFF,
+			CNTCR_FCREQ(0U) | CNTCR_EN);
+
+	VERBOSE("Leave arm_bl31_platform_setup\n");
+}
+
+/*******************************************************************************
+ * Perform any BL31 platform runtime setup prior to BL31 exit common to Layerscape
+ * platforms
+ ******************************************************************************/
+void ls_bl31_plat_runtime_setup(void)
+{
+	static console_ls_16550_t console;
+
+	/* Initialize the runtime console */
+	console_ls_16550_register(PLAT_LS1043_UART_BASE, PLAT_LS1043_UART_CLOCK,
+				PLAT_LS1043_UART_BAUDRATE, &console);
+}
+
+void bl31_platform_setup(void)
+{
+	ls_bl31_platform_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	ls_bl31_plat_runtime_setup();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup shared between
+ * Layerscape platforms. This only does basic initialization. Later
+ * architectural setup (bl31_arch_setup()) does not do anything platform
+ * specific.
+ ******************************************************************************/
+void ls_bl31_plat_arch_setup(void)
+{
+	ls_setup_page_tables(BL31_BASE,
+			      BL31_END - BL31_BASE,
+			      BL_CODE_BASE,
+			      BL_CODE_END,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_END
+#if USE_COHERENT_MEM
+			      , BL_COHERENT_RAM_BASE,
+			      BL_COHERENT_RAM_END
+#endif
+			      );
+	enable_mmu_el3(0);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	ls_bl31_plat_arch_setup();
+}
diff --git a/plat/layerscape/common/ls_common.c b/plat/layerscape/common/ls_common.c
new file mode 100644
index 0000000..23c0d00
--- /dev/null
+++ b/plat/layerscape/common/ls_common.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+const mmap_region_t *plat_ls_get_mmap(void);
+
+/*
+ * Table of memory regions for various BL stages to map using the MMU.
+ * This doesn't include Trusted SRAM as ls_setup_page_tables() already
+ * takes care of mapping it.
+ *
+ * The flash needs to be mapped as writable in order to erase the FIP's Table of
+ * Contents in case of unrecoverable error (see plat_error_handler()).
+ */
+#ifdef IMAGE_BL1
+const mmap_region_t plat_ls_mmap[] = {
+	LS_MAP_FLASH0_RW,
+	LS_MAP_NS_DRAM,
+	LS_MAP_CCSR,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2
+const mmap_region_t plat_ls_mmap[] = {
+	LS_MAP_FLASH0_RW,
+	LS_MAP_CCSR,
+	LS_MAP_NS_DRAM,
+	LS_MAP_TSP_SEC_MEM,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL31
+const mmap_region_t plat_ls_mmap[] = {
+	LS_MAP_CCSR,
+	LS_MAP_FLASH0_RW,
+	LS_MAP_NS_DRAM,
+	LS_MAP_TSP_SEC_MEM,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL32
+const mmap_region_t plat_ls_mmap[] = {
+	LS_MAP_CCSR,
+	LS_MAP_FLASH0_RW,
+	LS_MAP_TSP_SEC_MEM,
+	{0}
+};
+#endif
+/*
+ * Set up the page tables for the generic and platform-specific memory regions.
+ * The extents of the generic memory regions are specified by the function
+ * arguments and consist of:
+ * - Trusted SRAM seen by the BL image;
+ * - Code section;
+ * - Read-only data section;
+ * - Coherent memory region, if applicable.
+ */
+void ls_setup_page_tables(uintptr_t total_base,
+			   size_t total_size,
+			   uintptr_t code_start,
+			   uintptr_t code_limit,
+			   uintptr_t rodata_start,
+			   uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			   ,
+			   uintptr_t coh_start,
+			   uintptr_t coh_limit
+#endif
+			   )
+{
+	/* Now (re-)map the platform-specific memory regions */
+	mmap_add(plat_ls_get_mmap());
+	/*
+	 * Map the Trusted SRAM with appropriate memory attributes.
+	 * Subsequent mappings will adjust the attributes for specific regions.
+	 */
+	VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+		(void *) total_base, (void *) (total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+
+	/* Re-map the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *) code_start, (void *) code_limit);
+	mmap_add_region(code_start, code_start,
+			code_limit - code_start,
+			MT_CODE | MT_SECURE);
+
+	/* Re-map the read-only data section */
+	VERBOSE("Read-only data region: %p - %p\n",
+		(void *) rodata_start, (void *) rodata_limit);
+	mmap_add_region(rodata_start, rodata_start,
+			rodata_limit - rodata_start,
+			MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+	/* Re-map the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *) coh_start, (void *) coh_limit);
+	mmap_add_region(coh_start, coh_start,
+			coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	/* Create the page tables to reflect the above mappings */
+	init_xlat_tables();
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return LS_NS_DRAM_BASE;
+#endif
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t ls_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+#ifdef __aarch64__
+uint32_t ls_get_spsr_for_bl33_entry(void)
+{
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#else
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t ls_get_spsr_for_bl33_entry(void)
+{
+	unsigned int hyp_status, mode, spsr;
+
+	hyp_status = GET_VIRT_EXT(read_id_pfr1());
+
+	mode = (hyp_status) ? MODE32_hyp : MODE32_svc;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1,
+			SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+#endif /* __aarch64__ */
+
+/*******************************************************************************
+ * Returns Layerscape platform specific memory map regions.
+ ******************************************************************************/
+const mmap_region_t *plat_ls_get_mmap(void)
+{
+	return plat_ls_mmap;
+}
+
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	unsigned int counter_base_frequency;
+
+	counter_base_frequency = COUNTER_FREQUENCY;
+
+	return counter_base_frequency;
+}
diff --git a/plat/layerscape/common/ls_common.mk b/plat/layerscape/common/ls_common.mk
new file mode 100644
index 0000000..39867e6
--- /dev/null
+++ b/plat/layerscape/common/ls_common.mk
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+# Process LS1043_DISABLE_TRUSTED_WDOG flag
+# TODO:Temparally disabled it on development phase, not implemented yet
+LS1043_DISABLE_TRUSTED_WDOG	:=	1
+
+# On Layerscape platforms, separate the code and read-only data sections to allow
+# mapping the former as executable and the latter as execute-never.
+SEPARATE_CODE_AND_RODATA	:=	1
+
+COLD_BOOT_SINGLE_CPU		:=	1
+
+PLAT_BL_COMMON_SOURCES	+=	plat/layerscape/common/${ARCH}/ls_helpers.S		\
+				plat/layerscape/common/ls_common.c
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}
+
+BL1_SOURCES		+=			\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/layerscape/common/ls_timer.c			\
+				plat/layerscape/common/ls_bl1_setup.c			\
+				plat/layerscape/common/ls_io_storage.c
+
+BL2_SOURCES		+=	drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				plat/layerscape/common/ls_timer.c			\
+				plat/layerscape/common/ls_bl2_setup.c			\
+				plat/layerscape/common/ls_io_storage.c
+BL2_SOURCES		+=	plat/layerscape/common/${ARCH}/ls_bl2_mem_params_desc.c
+BL2_SOURCES		+=	plat/layerscape/common/ls_image_load.c		\
+					common/desc_image_load.c
+
+BL31_SOURCES		+=	plat/layerscape/common/ls_bl31_setup.c		\
+				plat/layerscape/common/ls_timer.c			\
+				plat/layerscape/common/ls_topology.c			\
+				plat/layerscape/common/ns_access.c		\
+				plat/common/plat_psci_common.c
diff --git a/plat/layerscape/common/ls_image_load.c b/plat/layerscape/common/ls_image_load.c
new file mode 100644
index 0000000..70c01f2
--- /dev/null
+++ b/plat/layerscape/common/ls_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.h>
+
+#include "ls_def.h"
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/layerscape/common/ls_io_storage.c b/plat/layerscape/common/ls_io_storage.c
new file mode 100644
index 0000000..71c2f45
--- /dev/null
+++ b/plat/layerscape/common/ls_io_storage.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <tools_share/firmware_image_package.h>
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = PLAT_LS_FIP_BASE,
+	.length = PLAT_LS_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+};
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+
+void ls_io_setup(void)
+{
+	int io_result;
+
+	io_result = register_io_dev_fip(&fip_dev_con);
+	assert(io_result == 0);
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&memmap_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+void plat_ls_io_setup(void)
+{
+	ls_io_setup();
+}
+
+int plat_ls_get_alt_image_source(
+	unsigned int image_id __unused,
+	uintptr_t *dev_handle __unused,
+	uintptr_t *image_spec __unused)
+{
+	/* By default do not try an alternative */
+	return -ENOENT;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy.
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	if (result == 0) {
+		*image_spec = policy->image_spec;
+		*dev_handle = *(policy->dev_handle);
+	} else {
+		VERBOSE("Trying alternative IO\n");
+		result = plat_ls_get_alt_image_source(image_id, dev_handle,
+						       image_spec);
+	}
+
+	return result;
+}
diff --git a/plat/layerscape/common/ls_timer.c b/plat/layerscape/common/ls_timer.c
new file mode 100644
index 0000000..021890b
--- /dev/null
+++ b/plat/layerscape/common/ls_timer.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#define TIMER_BASE_ADDR 0x02B00000
+
+uint64_t ls_get_timer(uint64_t start)
+{
+	return read_cntpct_el0() * 1000 / read_cntfrq_el0() - start;
+}
+
+static uint32_t ls_timeus_get_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter. The value is
+	 * clipped from 64 to 32 bits.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static const timer_ops_t ls_timer_ops = {
+	.get_timer_value	= ls_timeus_get_value,
+	.clk_mult		= 1,
+	.clk_div		= 25,
+};
+
+
+/*
+ * Initialise the nxp layerscape on-chip free rolling us counter as the delay
+ * timer.
+ */
+void ls_delay_timer_init(void)
+{
+	uintptr_t cntcr =  TIMER_BASE_ADDR;
+
+	mmio_write_32(cntcr, 0x1);
+
+	timer_init(&ls_timer_ops);
+}
diff --git a/plat/layerscape/common/ls_topology.c b/plat/layerscape/common/ls_topology.c
new file mode 100644
index 0000000..5b76087
--- /dev/null
+++ b/plat/layerscape/common/ls_topology.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "plat_ls.h"
+
+/*******************************************************************************
+ * This function validates an MPIDR by checking whether it falls within the
+ * acceptable bounds. An error code (-1) is returned if an incorrect mpidr
+ * is passed.
+ ******************************************************************************/
+int ls_check_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+	uint64_t valid_mask;
+
+	valid_mask = ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK);
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if (mpidr & valid_mask)
+		return -1;
+
+	if (cluster_id >= PLAT_LS_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= plat_ls_get_cluster_core_count(mpidr))
+		return -1;
+
+
+	return 0;
+}
diff --git a/plat/layerscape/common/ls_tzc380.c b/plat/layerscape/common/ls_tzc380.c
new file mode 100644
index 0000000..44f3fcd
--- /dev/null
+++ b/plat/layerscape/common/ls_tzc380.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <endian.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "soc_tzasc.h"
+
+int tzc380_set_region(unsigned int tzasc_base, unsigned int region_id,
+		unsigned int enabled, unsigned int low_addr,
+		unsigned int high_addr, unsigned int size,
+		unsigned int security, unsigned int subreg_disable_mask)
+{
+	unsigned int reg;
+	unsigned int reg_base;
+	unsigned int attr_value;
+
+	reg_base = (tzasc_base + TZASC_REGIONS_REG + (region_id << 4));
+
+	if (region_id == 0) {
+		reg = (reg_base + TZASC_REGION_ATTR_OFFSET);
+		mmio_write_32((uintptr_t)reg, ((security & 0xF) << 28));
+	} else {
+		reg = reg_base + TZASC_REGION_LOWADDR_OFFSET;
+		mmio_write_32((uintptr_t)reg,
+				(low_addr & TZASC_REGION_LOWADDR_MASK));
+
+		reg = reg_base + TZASC_REGION_HIGHADDR_OFFSET;
+		mmio_write_32((uintptr_t)reg, high_addr);
+
+		reg = reg_base + TZASC_REGION_ATTR_OFFSET;
+		attr_value = ((security & 0xF) << 28) |
+			((subreg_disable_mask & 0xFF) << 8) |
+			((size & 0x3F) << 1) | (enabled & 0x1);
+		mmio_write_32((uintptr_t)reg, attr_value);
+
+	}
+	return 0;
+}
+
+int tzc380_setup(void)
+{
+	int reg_id = 0;
+
+	INFO("Configuring TZASC-380\n");
+
+	/*
+	 * Configure CCI control override register to terminate all barrier
+	 * transactions
+	 */
+	mmio_write_32(PLAT_LS1043_CCI_BASE, CCI_TERMINATE_BARRIER_TX);
+
+	/* Configure CSU secure access register to disable TZASC bypass mux */
+	mmio_write_32((uintptr_t)(CONFIG_SYS_FSL_CSU_ADDR +
+				CSU_SEC_ACCESS_REG_OFFSET),
+			bswap32(TZASC_BYPASS_MUX_DISABLE));
+
+	for (reg_id = 0; reg_id < MAX_NUM_TZC_REGION; reg_id++) {
+		tzc380_set_region(CONFIG_SYS_FSL_TZASC_ADDR,
+				reg_id,
+				tzc380_reg_list[reg_id].enabled,
+				tzc380_reg_list[reg_id].low_addr,
+				tzc380_reg_list[reg_id].high_addr,
+				tzc380_reg_list[reg_id].size,
+				tzc380_reg_list[reg_id].secure,
+				tzc380_reg_list[reg_id].sub_mask);
+	}
+
+	return 0;
+}
diff --git a/plat/layerscape/common/ns_access.c b/plat/layerscape/common/ns_access.c
new file mode 100644
index 0000000..b84fdbd
--- /dev/null
+++ b/plat/layerscape/common/ns_access.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <endian.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "ns_access.h"
+
+static void enable_devices_ns_access(struct csu_ns_dev *ns_dev, uint32_t num)
+{
+	uint32_t *base = (uint32_t *)CONFIG_SYS_FSL_CSU_ADDR;
+	uint32_t *reg;
+	uint32_t val;
+	int i;
+
+	for (i = 0; i < num; i++) {
+		reg = base + ns_dev[i].ind / 2;
+		val = be32toh(mmio_read_32((uintptr_t)reg));
+		if (ns_dev[i].ind % 2 == 0) {
+			val &= 0x0000ffff;
+			val |= ns_dev[i].val << 16;
+		} else {
+			val &= 0xffff0000;
+			val |= ns_dev[i].val;
+		}
+		mmio_write_32((uintptr_t)reg, htobe32(val));
+	}
+}
+
+void enable_layerscape_ns_access(void)
+{
+	enable_devices_ns_access(ns_dev, ARRAY_SIZE(ns_dev));
+}
diff --git a/plat/layerscape/common/tsp/ls_tsp.mk b/plat/layerscape/common/tsp/ls_tsp.mk
new file mode 100644
index 0000000..7cb9781
--- /dev/null
+++ b/plat/layerscape/common/tsp/ls_tsp.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TSP source files common to ARM standard platforms
+BL32_SOURCES		+=	plat/layerscape/common/ls_topology.c			\
+				plat/layerscape/common/tsp/ls_tsp_setup.c		\
+				plat/common/aarch64/platform_mp_stack.S
diff --git a/plat/layerscape/common/tsp/ls_tsp_setup.c b/plat/layerscape/common/tsp/ls_tsp_setup.c
new file mode 100644
index 0000000..f3b6027
--- /dev/null
+++ b/plat/layerscape/common/tsp/ls_tsp_setup.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+
+#include "ls_16550.h"
+#include "plat_ls.h"
+#include "soc.h"
+
+static const interrupt_prop_t g0_interrupt_props[] = {
+	INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+gicv2_driver_data_t ls_gic_data = {
+	.gicd_base = GICD_BASE,
+	.gicc_base = GICC_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+void ls_tsp_early_platform_setup(void)
+{
+	static console_ls_16550_t console;
+	/*
+	 * Initialize a different console than already in use to display
+	 * messages from TSP
+	 */
+	console_ls_16550_register(PLAT_LS1043_UART2_BASE, PLAT_LS1043_UART_CLOCK,
+			PLAT_LS1043_UART_BAUDRATE, &console);
+	NOTICE(FIRMWARE_WELCOME_STR_LS1043_BL32);
+}
+
+/*******************************************************************************
+ * Perform platform specific setup placeholder
+ ******************************************************************************/
+void tsp_platform_setup(void)
+{
+	uint32_t gicc_base, gicd_base;
+
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	get_gic_offset(&gicc_base, &gicd_base);
+	ls_gic_data.gicd_base = (uintptr_t)gicd_base;
+	ls_gic_data.gicc_base = (uintptr_t)gicc_base;
+	gicv2_driver_init(&ls_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the MMU
+ ******************************************************************************/
+void tsp_plat_arch_setup(void)
+{
+	ls_setup_page_tables(BL32_BASE,
+			      (BL32_END - BL32_BASE),
+			      BL_CODE_BASE,
+			      BL_CODE_END,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_END
+#if USE_COHERENT_MEM
+			      , BL_COHERENT_RAM_BASE,
+			      BL_COHERENT_RAM_END
+#endif
+			      );
+	enable_mmu_el1(0);
+}
diff --git a/plat/layerscape/common/tsp/platform_tsp.h b/plat/layerscape/common/tsp/platform_tsp.h
new file mode 100644
index 0000000..260f66a
--- /dev/null
+++ b/plat/layerscape/common/tsp/platform_tsp.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_TSP_H
+#define PLATFORM_TSP_H
+
+/*******************************************************************************
+ * Mandatory TSP functions (only if platform contains a TSP)
+ ******************************************************************************/
+void tsp_early_platform_setup(void);
+void tsp_plat_arch_setup(void);
+void tsp_platform_setup(void);
+
+#endif /* PLATFORM_TSP_H */
diff --git a/plat/marvell/a3700/a3700/board/pm_src.c b/plat/marvell/a3700/a3700/board/pm_src.c
new file mode 100644
index 0000000..d6eca5d
--- /dev/null
+++ b/plat/marvell/a3700/a3700/board/pm_src.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <a3700_pm.h>
+#include <plat_marvell.h>
+
+/* This struct provides the PM wake up src configuration */
+static struct pm_wake_up_src_config wake_up_src_cfg = {
+	.wake_up_src_num = 3,
+	.wake_up_src[0] = {
+		.wake_up_src_type = WAKE_UP_SRC_GPIO,
+		.wake_up_data = {
+			.gpio_data.bank_num = 0, /* North Bridge */
+			.gpio_data.gpio_num = 14
+		}
+	},
+	.wake_up_src[1] = {
+		.wake_up_src_type = WAKE_UP_SRC_GPIO,
+		.wake_up_data = {
+			.gpio_data.bank_num = 1, /* South Bridge */
+			.gpio_data.gpio_num = 2
+		}
+	},
+	.wake_up_src[2] = {
+		.wake_up_src_type = WAKE_UP_SRC_UART1,
+	}
+};
+
+struct pm_wake_up_src_config *mv_wake_up_src_config_get(void)
+{
+	return &wake_up_src_cfg;
+}
+
diff --git a/plat/marvell/a3700/a3700/mvebu_def.h b/plat/marvell/a3700/a3700/mvebu_def.h
new file mode 100644
index 0000000..dad1085
--- /dev/null
+++ b/plat/marvell/a3700/a3700/mvebu_def.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a3700_plat_def.h>
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/a3700/a3700/plat_bl31_setup.c b/plat/marvell/a3700/a3700/plat_bl31_setup.c
new file mode 100644
index 0000000..6862a86
--- /dev/null
+++ b/plat/marvell/a3700/a3700/plat_bl31_setup.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <dram_win.h>
+#include <io_addr_dec.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+/* This routine does MPP initialization */
+static void marvell_bl31_mpp_init(void)
+{
+	mmio_clrbits_32(MVEBU_NB_GPIO_SEL_REG, 1 << MVEBU_GPIO_TW1_GPIO_EN_OFF);
+
+	/* Set hidden GPIO setting for SPI.
+	 * In north_bridge_pin_out_en_high register 13804,
+	 * bit 28 is the one which enables CS, CLK pins to be
+	 * output, need to set it to 1.
+	 * The initial value of this bit is 1, but in UART boot mode
+	 * initialization, this bit is disabled and the SPI CS and CLK pins
+	 * are used for downloading image purpose; so after downloading,
+	 * we should set this bit to 1 again to enable SPI CS and CLK pins.
+	 * And anyway, this bit value should be 1 in all modes,
+	 * so here we does not judge boot mode and set this bit to 1 always.
+	 */
+	mmio_setbits_32(MVEBU_NB_GPIO_OUTPUT_EN_HIGH_REG,
+			1 << MVEBU_GPIO_NB_SPI_PIN_MODE_OFF);
+}
+
+/* This function overruns the same function in marvell_bl31_setup.c */
+void bl31_plat_arch_setup(void)
+{
+	struct dec_win_config *io_dec_map;
+	uint32_t dec_win_num;
+	struct dram_win_map dram_wins_map;
+
+	marvell_bl31_plat_arch_setup();
+
+	/* MPP init */
+	marvell_bl31_mpp_init();
+
+	/* initialize the timer for delay functionality */
+	plat_delay_timer_init();
+
+	/* CPU address decoder windows initialization. */
+	cpu_wins_init();
+
+	/* fetch CPU-DRAM window mapping information by reading
+	 * CPU-DRAM decode windows (only the enabled ones)
+	 */
+	dram_win_map_build(&dram_wins_map);
+
+	/* Get IO address decoder windows */
+	if (marvell_get_io_dec_win_conf(&io_dec_map, &dec_win_num)) {
+		printf("No IO address decoder windows configurations found!\n");
+		return;
+	}
+
+	/* IO address decoder init */
+	if (init_io_addr_dec(&dram_wins_map, io_dec_map, dec_win_num)) {
+		printf("IO address decoder windows initialization failed!\n");
+		return;
+	}
+}
diff --git a/plat/marvell/a3700/a3700/platform.mk b/plat/marvell/a3700/a3700/platform.mk
new file mode 100644
index 0000000..4f7ac08
--- /dev/null
+++ b/plat/marvell/a3700/a3700/platform.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:	BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+include plat/marvell/a3700/common/a3700_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a3700/common/a3700_common.mk b/plat/marvell/a3700/common/a3700_common.mk
new file mode 100644
index 0000000..1e27567
--- /dev/null
+++ b/plat/marvell/a3700/common/a3700_common.mk
@@ -0,0 +1,171 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:	BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+MARVELL_PLAT_BASE		:= plat/marvell
+MARVELL_PLAT_INCLUDE_BASE	:= include/plat/marvell
+PLAT_FAMILY			:= a3700
+PLAT_FAMILY_BASE		:= $(MARVELL_PLAT_BASE)/$(PLAT_FAMILY)
+PLAT_INCLUDE_BASE		:= $(MARVELL_PLAT_INCLUDE_BASE)/$(PLAT_FAMILY)
+PLAT_COMMON_BASE		:= $(PLAT_FAMILY_BASE)/common
+MARVELL_DRV_BASE		:= drivers/marvell
+MARVELL_COMMON_BASE		:= $(MARVELL_PLAT_BASE)/common
+HANDLE_EA_EL3_FIRST		:= 1
+
+include $(MARVELL_PLAT_BASE)/marvell.mk
+
+#*********** A3700 *************
+DOIMAGEPATH	:= $(WTP)
+DOIMAGETOOL	:= $(DOIMAGEPATH)/wtptp/linux/tbb_linux
+
+ifeq ($(MARVELL_SECURE_BOOT),1)
+DOIMAGE_CFG	:= $(DOIMAGEPATH)/atf-tim.txt
+IMAGESPATH	:= $(DOIMAGEPATH)/tim/trusted
+
+TIMNCFG		:= $(DOIMAGEPATH)/atf-timN.txt
+TIMNSIG		:= $(IMAGESPATH)/timnsign.txt
+TIM2IMGARGS	:= -i $(DOIMAGE_CFG) -n $(TIMNCFG)
+TIMN_IMAGE	:= $$(grep "Image Filename:" -m 1 $(TIMNCFG) | cut -c 17-)
+else #MARVELL_SECURE_BOOT
+DOIMAGE_CFG	:= $(DOIMAGEPATH)/atf-ntim.txt
+IMAGESPATH	:= $(DOIMAGEPATH)/tim/untrusted
+TIM2IMGARGS	:= -i $(DOIMAGE_CFG)
+endif #MARVELL_SECURE_BOOT
+
+TIMBUILD	:= $(DOIMAGEPATH)/script/buildtim.sh
+TIM2IMG		:= $(DOIMAGEPATH)/script/tim2img.pl
+
+# WTMI_IMG is used to specify the customized RTOS image running over
+# Service CPU (CM3 processor). By the default, it points to a
+# baremetal binary of fuse programming in A3700_utils.
+WTMI_IMG	:= $(DOIMAGEPATH)/wtmi/fuse/build/fuse.bin
+
+# WTMI_SYSINIT_IMG is used for the system early initialization,
+# such as AVS settings, clock-tree setup and dynamic DDR PHY training.
+# After the initialization is done, this image will be wiped out
+# from the memory and CM3 will continue with RTOS image or other application.
+WTMI_SYSINIT_IMG	:= $(DOIMAGEPATH)/wtmi/sys_init/build/sys_init.bin
+
+# WTMI_MULTI_IMG is composed of CM3 RTOS image (WTMI_IMG)
+# and sys-init image (WTMI_SYSINIT_IMG).
+WTMI_MULTI_IMG		:= $(DOIMAGEPATH)/wtmi/build/wtmi.bin
+
+WTMI_ENC_IMG		:= $(DOIMAGEPATH)/wtmi/build/wtmi-enc.bin
+BUILD_UART		:= uart-images
+
+SRCPATH			:= $(dir $(BL33))
+
+CLOCKSPRESET		?= CPU_800_DDR_800
+
+DDR_TOPOLOGY		?= 0
+
+BOOTDEV			?= SPINOR
+PARTNUM			?= 0
+
+TIM_IMAGE		:= $$(grep "Image Filename:" -m 1 $(DOIMAGE_CFG) | cut -c 17-)
+TIMBLDARGS		:= $(MARVELL_SECURE_BOOT) $(BOOTDEV) $(IMAGESPATH) $(DOIMAGEPATH) $(CLOCKSPRESET) \
+				$(DDR_TOPOLOGY) $(PARTNUM) $(DEBUG) $(DOIMAGE_CFG) $(TIMNCFG) $(TIMNSIG) 1
+TIMBLDUARTARGS		:= $(MARVELL_SECURE_BOOT) UART $(IMAGESPATH) $(DOIMAGEPATH) $(CLOCKSPRESET) \
+				$(DDR_TOPOLOGY) 0 0 $(DOIMAGE_CFG) $(TIMNCFG) $(TIMNSIG) 0
+DOIMAGE_FLAGS		:= -r $(DOIMAGE_CFG) -v -D
+
+# GICV3
+$(eval $(call add_define,CONFIG_GICV3))
+
+# CCI-400
+$(eval $(call add_define,USE_CCI))
+
+MARVELL_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c	\
+				plat/common/plat_gicv3.c		\
+				drivers/arm/gic/v3/gic500.c
+
+PLAT_INCLUDES		:=	-I$(PLAT_FAMILY_BASE)/$(PLAT)		\
+				-I$(PLAT_COMMON_BASE)/include		\
+				-I$(PLAT_INCLUDE_BASE)/common		\
+				-I$(MARVELL_DRV_BASE)			\
+				-I$/drivers/arm/gic/common/
+
+PLAT_BL_COMMON_SOURCES	:=	$(PLAT_COMMON_BASE)/aarch64/a3700_common.c \
+				$(MARVELL_COMMON_BASE)/marvell_cci.c	   \
+				$(MARVELL_DRV_BASE)/uart/a3700_console.S
+
+BL1_SOURCES		+=	$(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
+				lib/cpus/aarch64/cortex_a53.S
+
+BL31_PORTING_SOURCES	:=	$(PLAT_FAMILY_BASE)/$(PLAT)/board/pm_src.c
+
+MARVELL_DRV		:=	$(MARVELL_DRV_BASE)/comphy/phy-comphy-3700.c
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				$(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
+				$(PLAT_COMMON_BASE)/plat_pm.c		\
+				$(PLAT_COMMON_BASE)/dram_win.c		\
+				$(PLAT_COMMON_BASE)/io_addr_dec.c	\
+				$(PLAT_COMMON_BASE)/marvell_plat_config.c     \
+				$(PLAT_COMMON_BASE)/a3700_ea.c		\
+				$(PLAT_FAMILY_BASE)/$(PLAT)/plat_bl31_setup.c \
+				$(MARVELL_COMMON_BASE)/marvell_ddr_info.c	\
+				$(MARVELL_COMMON_BASE)/marvell_gicv3.c	\
+				$(MARVELL_GIC_SOURCES)			\
+				drivers/arm/cci/cci.c			\
+				$(BL31_PORTING_SOURCES)			\
+				$(PLAT_COMMON_BASE)/a3700_sip_svc.c	\
+				$(MARVELL_DRV)
+
+mrvl_flash: ${BUILD_PLAT}/${FIP_NAME} ${DOIMAGETOOL}
+	$(shell truncate -s %128K ${BUILD_PLAT}/bl1.bin)
+	$(shell cat ${BUILD_PLAT}/bl1.bin ${BUILD_PLAT}/${FIP_NAME} > ${BUILD_PLAT}/${BOOT_IMAGE})
+	$(shell truncate -s %4 ${BUILD_PLAT}/${BOOT_IMAGE})
+	$(shell truncate -s %4 $(WTMI_IMG))
+	@echo
+	@echo "Building uart images"
+	$(TIMBUILD) $(TIMBLDUARTARGS)
+	@sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(DOIMAGE_CFG)
+	@sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(DOIMAGE_CFG)
+ifeq ($(MARVELL_SECURE_BOOT),1)
+	@sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(TIMNCFG)
+	@sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(TIMNCFG)
+endif
+	$(DOIMAGETOOL) $(DOIMAGE_FLAGS)
+	@if [ -e "$(TIMNCFG)" ]; then $(DOIMAGETOOL) -r $(TIMNCFG); fi
+	@rm -rf $(BUILD_PLAT)/$(BUILD_UART)*
+	@mkdir $(BUILD_PLAT)/$(BUILD_UART)
+	@mv -t $(BUILD_PLAT)/$(BUILD_UART) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG)
+	@find . -name "*_h.*" |xargs cp -ut $(BUILD_PLAT)/$(BUILD_UART)
+	@mv $(subst .bin,_h.bin,$(WTMI_MULTI_IMG)) $(BUILD_PLAT)/$(BUILD_UART)/wtmi_h.bin
+	@tar czf $(BUILD_PLAT)/$(BUILD_UART).tgz -C $(BUILD_PLAT) ./$(BUILD_UART)
+	@echo
+	@echo "Building flash image"
+	$(TIMBUILD) $(TIMBLDARGS)
+	sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(DOIMAGE_CFG)
+	sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(DOIMAGE_CFG)
+ifeq ($(MARVELL_SECURE_BOOT),1)
+	@sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(TIMNCFG)
+	@sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(TIMNCFG)
+	@echo -e "\n\t=======================================================\n";
+	@echo -e "\t  Secure boot. Encrypting wtmi and boot-image \n";
+	@echo -e "\t=======================================================\n";
+	@truncate -s %16 $(WTMI_MULTI_IMG)
+	@openssl enc -aes-256-cbc -e -in $(WTMI_MULTI_IMG) \
+	-out $(WTMI_ENC_IMG) \
+	-K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \
+	-iv `cat $(IMAGESPATH)/iv.txt` -p
+	@truncate -s %16 $(BUILD_PLAT)/$(BOOT_IMAGE);
+	@openssl enc -aes-256-cbc -e -in $(BUILD_PLAT)/$(BOOT_IMAGE) \
+	-out $(BUILD_PLAT)/$(BOOT_ENC_IMAGE) \
+	-K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \
+	-iv `cat $(IMAGESPATH)/iv.txt` -p
+endif
+	$(DOIMAGETOOL) $(DOIMAGE_FLAGS)
+	@if [ -e "$(TIMNCFG)" ]; then $(DOIMAGETOOL) -r $(TIMNCFG); fi
+	@if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then sed -i 's|$(WTMI_MULTI_IMG)|$(WTMI_ENC_IMG)|1;s|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1;' $(TIMNCFG); fi
+	$(TIM2IMG) $(TIM2IMGARGS) -o $(BUILD_PLAT)/$(FLASH_IMAGE)
+	@mv -t $(BUILD_PLAT) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG) $(WTMI_IMG) $(WTMI_SYSINIT_IMG) $(WTMI_MULTI_IMG)
+	@if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then mv -t $(BUILD_PLAT) $(WTMI_ENC_IMG) OtpHash.txt; fi
+	@find . -name "*.txt" | grep -E "CSK[[:alnum:]]_KeyHash.txt|Tim_msg.txt|TIMHash.txt" | xargs rm -f
diff --git a/plat/marvell/a3700/common/a3700_ea.c b/plat/marvell/a3700/common/a3700_ea.c
new file mode 100644
index 0000000..dd46beb
--- /dev/null
+++ b/plat/marvell/a3700/common/a3700_ea.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 Repk repk@triplefau.lt
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <arch_helpers.h>
+
+#define ADVK_SERROR_SYNDROME 0xbf000002
+
+void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+		void *handle, uint64_t flags)
+{
+	if (syndrome != ADVK_SERROR_SYNDROME) {
+		ERROR("Unhandled External Abort received on 0x%lx at EL3!\n",
+			read_mpidr_el1());
+		ERROR(" exception reason=%u syndrome=0x%llx\n", ea_reason,
+				syndrome);
+		panic();
+	}
+}
diff --git a/plat/marvell/a3700/common/a3700_sip_svc.c b/plat/marvell/a3700/common/a3700_sip_svc.c
new file mode 100644
index 0000000..e8ac5fc
--- /dev/null
+++ b/plat/marvell/a3700/common/a3700_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/smccc.h>
+
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+#include "comphy/phy-comphy-3700.h"
+
+/* Comphy related FID's */
+#define MV_SIP_COMPHY_POWER_ON	0x82000001
+#define MV_SIP_COMPHY_POWER_OFF	0x82000002
+#define MV_SIP_COMPHY_PLL_LOCK	0x82000003
+
+/* Miscellaneous FID's' */
+#define MV_SIP_DRAM_SIZE	0x82000010
+
+/* This macro is used to identify COMPHY related calls from SMC function ID */
+#define is_comphy_fid(fid)	\
+	((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_PLL_LOCK)
+
+uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
+			       u_register_t x1,
+			       u_register_t x2,
+			       u_register_t x3,
+			       u_register_t x4,
+			       void *cookie,
+			       void *handle,
+			       u_register_t flags)
+{
+	u_register_t ret;
+
+	VERBOSE("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx\n",
+		__func__, smc_fid, x1, x2);
+	if (is_comphy_fid(smc_fid)) {
+		if (x1 >= MAX_LANE_NR) {
+			ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n",
+			      __func__, smc_fid, x2);
+			SMC_RET1(handle, SMC_UNK);
+		}
+	}
+
+	switch (smc_fid) {
+	/* Comphy related FID's */
+	case MV_SIP_COMPHY_POWER_ON:
+		/* x1: comphy_index, x2: comphy_mode */
+		ret = mvebu_3700_comphy_power_on(x1, x2);
+		SMC_RET1(handle, ret);
+	case MV_SIP_COMPHY_POWER_OFF:
+		/* x1: comphy_index, x2: comphy_mode */
+		ret = mvebu_3700_comphy_power_off(x1, x2);
+		SMC_RET1(handle, ret);
+	case MV_SIP_COMPHY_PLL_LOCK:
+		/* x1: comphy_index, x2: comphy_mode */
+		ret = mvebu_3700_comphy_is_pll_locked(x1, x2);
+		SMC_RET1(handle, ret);
+	/* Miscellaneous FID's' */
+	case MV_SIP_DRAM_SIZE:
+		/* x1:  ap_base_addr */
+		ret = mvebu_get_dram_size(MVEBU_REGS_BASE);
+		SMC_RET1(handle, ret);
+
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	marvell_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	mrvl_sip_smc_handler
+);
diff --git a/plat/marvell/a3700/common/aarch64/a3700_common.c b/plat/marvell/a3700/common/aarch64/a3700_common.c
new file mode 100644
index 0000000..6351285
--- /dev/null
+++ b/plat/marvell/a3700/common/aarch64/a3700_common.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+#include <plat_marvell.h>
+
+/* MMU entry for internal (register) space access */
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_marvell_mmap[] = {
+	MARVELL_MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_marvell_mmap[] = {
+	MARVELL_MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MARVELL_MAP_DRAM,
+	{0}
+};
+#endif
+#if IMAGE_BL2U
+const mmap_region_t plat_marvell_mmap[] = {
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+#if IMAGE_BL31
+const mmap_region_t plat_marvell_mmap[] = {
+	MARVELL_MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MARVELL_MAP_DRAM,
+	{0}
+};
+#endif
+#if IMAGE_BL32
+const mmap_region_t plat_marvell_mmap[] = {
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+
+MARVELL_CASSERT_MMAP;
diff --git a/plat/marvell/a3700/common/aarch64/plat_helpers.S b/plat/marvell/a3700/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..90d76f0
--- /dev/null
+++ b/plat/marvell/a3700/common/aarch64/plat_helpers.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset. Right
+	 * now this is a stub function.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	mov	x0, #0
+	ret
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between cold and warm boot
+	 * For a cold boot, return 0.
+	 * For a warm boot, read the mailbox and return the address it contains.
+	 * A magic number is placed before entrypoint to avoid mistake caused by
+	 * uninitialized mailbox data area.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* Read first word and compare it with magic num */
+	mov_imm x0, PLAT_MARVELL_MAILBOX_BASE
+	ldr	x1, [x0]
+	mov_imm x2, PLAT_MARVELL_MAILBOX_MAGIC_NUM
+	cmp	x1, x2
+	/* If compare failed, return 0, i.e. cold boot */
+	beq	entrypoint
+	mov	x0, #0
+	ret
+entrypoint:
+	/* Second word contains the jump address */
+	add	x0, x0, #8
+	ldr	x0, [x0]
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #MVEBU_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
diff --git a/plat/marvell/a3700/common/dram_win.c b/plat/marvell/a3700/common/dram_win.c
new file mode 100644
index 0000000..694f6d4
--- /dev/null
+++ b/plat/marvell/a3700/common/dram_win.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <lib/mmio.h>
+
+#include <dram_win.h>
+#include <marvell_plat_priv.h>
+#include <mvebu.h>
+#include <plat_marvell.h>
+
+/* Armada 3700 has 5 configurable windows */
+#define MV_CPU_WIN_NUM		5
+
+#define CPU_WIN_DISABLED	0
+#define CPU_WIN_ENABLED		1
+
+/*
+ * There are 2 different cpu decode window configuration cases:
+ * - DRAM size is not over 2GB;
+ * - DRAM size is 4GB.
+ */
+enum cpu_win_config_num {
+	CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB = 0,
+	CPU_WIN_CONFIG_DRAM_4GB,
+	CPU_WIN_CONFIG_MAX
+};
+
+enum cpu_win_target {
+	CPU_WIN_TARGET_DRAM = 0,
+	CPU_WIN_TARGET_INTERNAL_REG,
+	CPU_WIN_TARGET_PCIE,
+	CPU_WIN_TARGET_PCIE_OVER_MCI,
+	CPU_WIN_TARGET_BOOT_ROM,
+	CPU_WIN_TARGET_MCI_EXTERNAL,
+	CPU_WIN_TARGET_RWTM_RAM = 7,
+	CPU_WIN_TARGET_CCI400_REG
+};
+
+struct cpu_win_configuration {
+	uint32_t		enabled;
+	enum cpu_win_target	target;
+	uint64_t		base_addr;
+	uint64_t		size;
+	uint64_t		remap_addr;
+};
+
+struct cpu_win_configuration mv_cpu_wins[CPU_WIN_CONFIG_MAX][MV_CPU_WIN_NUM] = {
+	/*
+	 * When total dram size is not over 2GB:
+	 * DDR window 0 is configured in tim header, its size may be not 512MB,
+	 * but the actual dram size, no need to configure it again;
+	 * other cpu windows are kept as default.
+	 */
+	{
+		/* enabled
+		 *	target
+		 *		base
+		 *			size
+		 *				remap
+		 */
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_DRAM,
+				0x0,
+					0x08000000,
+						0x0},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_MCI_EXTERNAL,
+				0xe0000000,
+					0x08000000,
+						0xe0000000},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_PCIE,
+				0xe8000000,
+					0x08000000,
+						0xe8000000},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_RWTM_RAM,
+				0xf0000000,
+					0x00020000,
+						0x1fff0000},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_PCIE_OVER_MCI,
+				0x80000000,
+					0x10000000,
+						0x80000000},
+	},
+
+	/*
+	 * If total dram size is more than 2GB, now there is only one case - 4GB
+	 *  dram; we will use below cpu windows configurations:
+	 *  - Internal Regs, CCI-400, Boot Rom and PCIe windows are kept as
+	 *    default;
+	 *  - Use 4 CPU decode windows for DRAM, which cover 3.375GB DRAM;
+	 *    DDR window 0 is configured in tim header with 2GB size, no need to
+	 *    configure it again here;
+	 *
+	 *	0xFFFFFFFF ---> |-----------------------|
+	 *			|	  Boot ROM	| 64KB
+	 *	0xFFF00000 ---> +-----------------------+
+	 *			:			:
+	 *	0xF0000000 ---> |-----------------------|
+	 *			|	  PCIE		| 128 MB
+	 *	0xE8000000 ---> |-----------------------|
+	 *			|	  DDR window 3	| 128 MB
+	 *	0xE0000000 ---> +-----------------------+
+	 *			:			:
+	 *	0xD8010000 ---> |-----------------------|
+	 *			|	  CCI Regs	| 64 KB
+	 *	0xD8000000 ---> +-----------------------+
+	 *			:			:
+	 *			:			:
+	 *	0xD2000000 ---> +-----------------------+
+	 *			|	 Internal Regs	| 32MB
+	 *	0xD0000000 ---> |-----------------------|
+	 *			 |	  DDR window 2	| 256 MB
+	 *	0xC0000000 ---> |-----------------------|
+	 *			|			|
+	 *			|	 DDR window 1	| 1 GB
+	 *			|			|
+	 *	0x80000000 ---> |-----------------------|
+	 *			|			|
+	 *			|			|
+	 *			|	 DDR window 0	| 2 GB
+	 *			|			|
+	 *			|			|
+	 *	0x00000000 ---> +-----------------------+
+	 */
+	{
+		/* win_id
+		 *	target
+		 *		base
+		 *			size
+		 *				remap
+		 */
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_DRAM,
+				0x0,
+					0x80000000,
+						0x0},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_DRAM,
+				0x80000000,
+					0x40000000,
+						0x80000000},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_DRAM,
+				0xc0000000,
+					0x10000000,
+						0xc0000000},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_DRAM,
+				0xe0000000,
+					0x08000000,
+						0xe0000000},
+		{CPU_WIN_ENABLED,
+			CPU_WIN_TARGET_PCIE,
+				0xe8000000,
+					0x08000000,
+						0xe8000000},
+	},
+};
+
+/*
+ * dram_win_map_build
+ *
+ * This function builds cpu dram windows mapping
+ * which includes base address and window size by
+ * reading cpu dram decode windows registers.
+ *
+ * @input: N/A
+ *
+ * @output:
+ *     - win_map: cpu dram windows mapping
+ *
+ * @return:  N/A
+ */
+void dram_win_map_build(struct dram_win_map *win_map)
+{
+	int32_t win_id;
+	struct dram_win *win;
+	uint32_t base_reg, ctrl_reg, size_reg, enabled, target;
+
+	memset(win_map, 0, sizeof(struct dram_win_map));
+	for (win_id = 0; win_id < DRAM_WIN_MAP_NUM_MAX; win_id++) {
+		ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id));
+		target = (ctrl_reg & CPU_DEC_CR_WIN_TARGET_MASK) >>
+			  CPU_DEC_CR_WIN_TARGET_OFFS;
+		enabled = ctrl_reg & CPU_DEC_CR_WIN_ENABLE;
+		/* Ignore invalid and non-dram windows*/
+		if ((enabled == 0) || (target != DRAM_CPU_DEC_TARGET_NUM))
+			continue;
+
+		win = win_map->dram_windows + win_map->dram_win_num;
+		base_reg = mmio_read_32(CPU_DEC_WIN_BASE_REG(win_id));
+		size_reg = mmio_read_32(CPU_DEC_WIN_SIZE_REG(win_id));
+		/* Base reg [15:0] corresponds to transaction address [39:16] */
+		win->base_addr = (base_reg & CPU_DEC_BR_BASE_MASK) >>
+				  CPU_DEC_BR_BASE_OFFS;
+		win->base_addr *= CPU_DEC_CR_WIN_SIZE_ALIGNMENT;
+		/*
+		 * Size reg [15:0] is programmed from LSB to MSB as a sequence
+		 * of 1s followed by a sequence of 0s and the number of 1s
+		 * specifies the size of the window in 64 KB granularity,
+		 * for example, a value of 00FFh specifies 256 x 64 KB = 16 MB
+		 */
+		win->win_size = (size_reg & CPU_DEC_CR_WIN_SIZE_MASK) >>
+				 CPU_DEC_CR_WIN_SIZE_OFFS;
+		win->win_size = (win->win_size + 1) *
+				 CPU_DEC_CR_WIN_SIZE_ALIGNMENT;
+
+		win_map->dram_win_num++;
+	}
+}
+
+static void cpu_win_set(uint32_t win_id, struct cpu_win_configuration *win_cfg)
+{
+	uint32_t base_reg, ctrl_reg, size_reg, remap_reg;
+
+	/* Disable window */
+	ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id));
+	ctrl_reg &= ~CPU_DEC_CR_WIN_ENABLE;
+	mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg);
+
+	/* For an disabled window, only disable it. */
+	if (!win_cfg->enabled)
+		return;
+
+	/* Set Base Register */
+	base_reg = (uint32_t)(win_cfg->base_addr /
+		   CPU_DEC_CR_WIN_SIZE_ALIGNMENT);
+	base_reg <<= CPU_DEC_BR_BASE_OFFS;
+	base_reg &= CPU_DEC_BR_BASE_MASK;
+	mmio_write_32(CPU_DEC_WIN_BASE_REG(win_id), base_reg);
+
+	/* Set Remap Register with the same value
+	 * as the <Base> field in Base Register
+	 */
+	remap_reg = (uint32_t)(win_cfg->remap_addr /
+		    CPU_DEC_CR_WIN_SIZE_ALIGNMENT);
+	remap_reg <<= CPU_DEC_RLR_REMAP_LOW_OFFS;
+	remap_reg &= CPU_DEC_RLR_REMAP_LOW_MASK;
+	mmio_write_32(CPU_DEC_REMAP_LOW_REG(win_id), remap_reg);
+
+	/* Set Size Register */
+	size_reg = (win_cfg->size / CPU_DEC_CR_WIN_SIZE_ALIGNMENT) - 1;
+	size_reg <<= CPU_DEC_CR_WIN_SIZE_OFFS;
+	size_reg &= CPU_DEC_CR_WIN_SIZE_MASK;
+	mmio_write_32(CPU_DEC_WIN_SIZE_REG(win_id), size_reg);
+
+	/* Set Control Register - set target id and enable window */
+	ctrl_reg &= ~CPU_DEC_CR_WIN_TARGET_MASK;
+	ctrl_reg |= (win_cfg->target << CPU_DEC_CR_WIN_TARGET_OFFS);
+	ctrl_reg |= CPU_DEC_CR_WIN_ENABLE;
+	mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg);
+}
+
+void cpu_wins_init(void)
+{
+	uint32_t cfg_idx, win_id;
+
+	if (mvebu_get_dram_size(MVEBU_REGS_BASE) <= _2GB_)
+		cfg_idx = CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB;
+	else
+		cfg_idx = CPU_WIN_CONFIG_DRAM_4GB;
+
+	/* Window 0 is configured always for DRAM in tim header
+	 * already, no need to configure it again here
+	 */
+	for (win_id = 1; win_id < MV_CPU_WIN_NUM; win_id++)
+		cpu_win_set(win_id, &mv_cpu_wins[cfg_idx][win_id]);
+}
+
diff --git a/plat/marvell/a3700/common/include/a3700_plat_def.h b/plat/marvell/a3700/common/include/a3700_plat_def.h
new file mode 100644
index 0000000..c7f40ad
--- /dev/null
+++ b/plat/marvell/a3700/common/include/a3700_plat_def.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef A3700_PLAT_DEF_H
+#define A3700_PLAT_DEF_H
+
+#include <marvell_def.h>
+
+
+#define MVEBU_MAX_CPUS_PER_CLUSTER	2
+
+#define MVEBU_PRIMARY_CPU		0x0
+
+/*
+ * The counter on A3700 is always fed from reference 25M clock (XTAL).
+ * However minimal CPU counter prescaler is 2, so the counter
+ * frequency will be divided by 2, the number is 12.5M
+ */
+#define COUNTER_FREQUENCY		12500000
+
+#define MVEBU_REGS_BASE			0xD0000000
+
+/*****************************************************************************
+ * MVEBU memory map related constants
+ *****************************************************************************
+ */
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE			MVEBU_REGS_BASE
+#define DEVICE0_SIZE			0x10000000
+
+/*****************************************************************************
+ * GIC-500 & interrupt handling related constants
+ *****************************************************************************
+ */
+/* Base MVEBU compatible GIC memory map */
+#define MVEBU_GICD_BASE			0x1D00000
+#define MVEBU_GICR_BASE			0x1D40000
+#define MVEBU_GICC_BASE			0x1D80000
+
+/* CCI-400 */
+#define MVEBU_CCI_BASE			0x8000000
+
+/*****************************************************************************
+ * North and south bridge register base
+ *****************************************************************************
+ */
+#define MVEBU_NB_REGS_BASE			(MVEBU_REGS_BASE + 0x13000)
+#define MVEBU_SB_REGS_BASE			(MVEBU_REGS_BASE + 0x18000)
+
+/*****************************************************************************
+ * GPIO registers related constants
+ *****************************************************************************
+ */
+/* North and south bridge GPIO register base address */
+#define MVEBU_NB_GPIO_REG_BASE			(MVEBU_NB_REGS_BASE + 0x800)
+#define MVEBU_NB_GPIO_IRQ_REG_BASE		(MVEBU_NB_REGS_BASE + 0xC00)
+#define MVEBU_SB_GPIO_REG_BASE			(MVEBU_SB_REGS_BASE + 0x800)
+#define MVEBU_SB_GPIO_IRQ_REG_BASE		(MVEBU_SB_REGS_BASE + 0xC00)
+#define MVEBU_NB_SB_IRQ_REG_BASE		(MVEBU_REGS_BASE + 0x8A00)
+
+/* North Bridge GPIO selection register */
+#define MVEBU_NB_GPIO_SEL_REG			(MVEBU_NB_GPIO_REG_BASE + 0x30)
+#define MVEBU_NB_GPIO_OUTPUT_EN_HIGH_REG	(MVEBU_NB_GPIO_REG_BASE + 0x04)
+/* I2C1 GPIO Enable bit offset */
+#define MVEBU_GPIO_TW1_GPIO_EN_OFF		(10)
+/* SPI pins mode bit offset */
+#define MVEBU_GPIO_NB_SPI_PIN_MODE_OFF		(28)
+
+/*****************************************************************************
+ * DRAM registers related constants
+ *****************************************************************************
+ */
+#define MVEBU_DRAM_REG_BASE			(MVEBU_REGS_BASE)
+
+/*****************************************************************************
+ * SB wake-up registers related constants
+ *****************************************************************************
+ */
+#define MVEBU_SB_WAKEUP_REG_BASE		(MVEBU_REGS_BASE + 0x19000)
+
+/*****************************************************************************
+ * PMSU registers related constants
+ *****************************************************************************
+ */
+#define MVEBU_PMSU_REG_BASE			(MVEBU_REGS_BASE + 0x14000)
+
+/*****************************************************************************
+ * North Bridge Step-Down Registers
+ *****************************************************************************
+ */
+#define MVEBU_NB_STEP_DOWN_REG_BASE		(MVEBU_REGS_BASE + 0x12800)
+
+/*****************************************************************************
+ * DRAM CS memory map register base
+ *****************************************************************************
+ */
+#define MVEBU_CS_MMAP_REG_BASE			(MVEBU_REGS_BASE + 0x200)
+
+/*****************************************************************************
+ * CPU decoder window registers related constants
+ *****************************************************************************
+ */
+#define MVEBU_CPU_DEC_WIN_REG_BASE		(MVEBU_REGS_BASE + 0xCF00)
+
+/*****************************************************************************
+ * AVS registers related constants
+ *****************************************************************************
+ */
+#define MVEBU_AVS_REG_BASE			(MVEBU_REGS_BASE + 0x11500)
+
+
+/*****************************************************************************
+ * AVS registers related constants
+ *****************************************************************************
+ */
+#define MVEBU_COMPHY_REG_BASE			(MVEBU_REGS_BASE + 0x18300)
+
+#endif /* A3700_PLAT_DEF_H */
diff --git a/plat/marvell/a3700/common/include/a3700_pm.h b/plat/marvell/a3700/common/include/a3700_pm.h
new file mode 100644
index 0000000..cc6cf43
--- /dev/null
+++ b/plat/marvell/a3700/common/include/a3700_pm.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef A3700_PM_H
+#define A3700_PM_H
+
+#include <stdint.h>
+
+/* supported wake up sources */
+enum pm_wake_up_src_type {
+	WAKE_UP_SRC_GPIO,
+	/* FOLLOWING SRC NOT SUPPORTED YET */
+	WAKE_UP_SRC_TIMER,
+	WAKE_UP_SRC_UART0,
+	WAKE_UP_SRC_UART1,
+	WAKE_UP_SRC_MAX,
+};
+
+struct pm_gpio_data {
+	/*
+	 * bank 0: North bridge GPIO
+	 * bank 1: South bridge GPIO
+	 */
+	uint32_t bank_num;
+	uint32_t gpio_num;
+};
+
+union pm_wake_up_src_data {
+	struct pm_gpio_data gpio_data;
+	/* delay in seconds */
+	uint32_t timer_delay;
+};
+
+struct pm_wake_up_src {
+	enum pm_wake_up_src_type wake_up_src_type;
+
+	union pm_wake_up_src_data wake_up_data;
+};
+
+struct pm_wake_up_src_config {
+	uint32_t	wake_up_src_num;
+	struct pm_wake_up_src wake_up_src[WAKE_UP_SRC_MAX];
+};
+
+struct pm_wake_up_src_config *mv_wake_up_src_config_get(void);
+
+#endif /* A3700_PM_H */
diff --git a/plat/marvell/a3700/common/include/ddr_info.h b/plat/marvell/a3700/common/include/ddr_info.h
new file mode 100644
index 0000000..254f78c
--- /dev/null
+++ b/plat/marvell/a3700/common/include/ddr_info.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef DDR_INFO_H
+#define DDR_INFO_H
+
+#define DRAM_MAX_IFACE			1
+#define DRAM_CH0_MMAP_LOW_OFFSET	0x200
+
+#endif /* DDR_INFO_H */
diff --git a/plat/marvell/a3700/common/include/dram_win.h b/plat/marvell/a3700/common/include/dram_win.h
new file mode 100644
index 0000000..26a0137
--- /dev/null
+++ b/plat/marvell/a3700/common/include/dram_win.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef DRAM_WIN_H
+#define DRAM_WIN_H
+
+#include <common/bl_common.h>
+
+#include <io_addr_dec.h>
+
+void dram_win_map_build(struct dram_win_map *win_map);
+void cpu_wins_init(void);
+
+#endif /* DRAM_WIN_H */
diff --git a/plat/marvell/a3700/common/include/io_addr_dec.h b/plat/marvell/a3700/common/include/io_addr_dec.h
new file mode 100644
index 0000000..42ef30b
--- /dev/null
+++ b/plat/marvell/a3700/common/include/io_addr_dec.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef IO_ADDR_DEC_H
+#define IO_ADDR_DEC_H
+
+#include <stdint.h>
+
+/* There are 5 configurable cpu decoder windows. */
+#define DRAM_WIN_MAP_NUM_MAX	5
+/* Target number for dram in cpu decoder windows. */
+#define DRAM_CPU_DEC_TARGET_NUM	0
+
+/*
+ * Not all configurable decode windows could be used for dram, some units have
+ * to reserve one decode window for other unit they have to communicate with;
+ * for example, DMA engineer has 3 configurable windows, but only two could be
+ * for dram while the last one has to be for pcie, so for DMA, its max_dram_win
+ * is 2.
+ */
+struct dec_win_config {
+	uint32_t dec_reg_base; /* IO address decoder register base address */
+	uint32_t win_attr;	/* IO address decoder windows attributes */
+	/* How many configurable dram decoder windows that this unit has; */
+	uint32_t max_dram_win;
+	/* The decoder windows number including remapping that this unit has */
+	uint32_t max_remap;
+	/* The offset between continuous decode windows
+	 * within the same unit, typically 0x10
+	 */
+	uint32_t win_offset;
+};
+
+struct dram_win {
+	uintptr_t base_addr;
+	uintptr_t win_size;
+};
+
+struct  dram_win_map {
+	int dram_win_num;
+	struct dram_win dram_windows[DRAM_WIN_MAP_NUM_MAX];
+};
+
+/*
+ * init_io_addr_dec
+ *
+ * This function initializes io address decoder windows by
+ * cpu dram window mapping information
+ *
+ * @input: N/A
+ *     - dram_wins_map: cpu dram windows mapping
+ *     - io_dec_config: io address decoder windows configuration
+ *     - io_unit_num: io address decoder unit number
+ * @output: N/A
+ *
+ * @return:  0 on success and others on failure
+ */
+int init_io_addr_dec(struct dram_win_map *dram_wins_map,
+		     struct dec_win_config *io_dec_config,
+		     uint32_t io_unit_num);
+
+#endif /* IO_ADDR_DEC_H */
diff --git a/plat/marvell/a3700/common/include/plat_macros.S b/plat/marvell/a3700/common/include/plat_macros.S
new file mode 100644
index 0000000..f689b4f
--- /dev/null
+++ b/plat/marvell/a3700/common/include/plat_macros.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <marvell_macros.S>
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC and
+ * CCI registers registers whenever an unhandled
+ * exception is taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+	mov_imm	x17, MVEBU_GICC_BASE
+	mov_imm	x16, MVEBU_GICD_BASE
+	marvell_print_gic_regs
+	print_cci_regs
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/marvell/a3700/common/include/platform_def.h b/plat/marvell/a3700/common/include/platform_def.h
new file mode 100644
index 0000000..591f045
--- /dev/null
+++ b/plat/marvell/a3700/common/include/platform_def.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#ifndef __ASSEMBLER__
+#include <stdio.h>
+#endif /* __ASSEMBLER__ */
+
+#include <board_marvell_def.h>
+#include <mvebu_def.h>
+
+/*
+ * Most platform porting definitions provided by included headers
+ */
+
+/*
+ * DRAM Memory layout:
+ *		+-----------------------+
+ *		:			:
+ *		:	Linux		:
+ * 0x04X00000-->+-----------------------+
+ *		|	BL3-3(u-boot)	|>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ *		|-----------------------|  }				       |
+ *		|	BL3-[0,1, 2]	|  }---------------------------------> |
+ *		|-----------------------|  }				||     |
+ *		|	BL2		|  }->FIP (loaded by            ||     |
+ *		|-----------------------|  }       BootROM to DRAM)     ||     |
+ *		|	FIP_TOC		|  }                            ||     |
+ * 0x04120000-->|-----------------------|				||     |
+ *		|	BL1 (RO)	|				||     |
+ * 0x04100000-->+-----------------------+				||     |
+ *		:			:				||     |
+ *		: Trusted SRAM section	:				\/     |
+ * 0x04040000-->+-----------------------+  Replaced by BL2  +----------------+ |
+ *		|	BL1 (RW)	|  <<<<<<<<<<<<<<<< | BL3-1 NOBITS   | |
+ * 0x04037000-->|-----------------------|  <<<<<<<<<<<<<<<< |----------------| |
+ *		|			|  <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | |
+ * 0x04023000-->|-----------------------|		    +----------------+ |
+ *		|	BL2		|				       |
+ *		|-----------------------|				       |
+ *		|			|				       |
+ * 0x04001000-->|-----------------------|				       |
+ *		|	Shared		|				       |
+ * 0x04000000-->+-----------------------+				       |
+ *		:			:				       |
+ *		:	Linux		:				       |
+ *		:			:				       |
+ *		|-----------------------|				       |
+ *		|			|	U-Boot(BL3-3) Loaded by BL2    |
+ *		|	U-Boot		|	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ * 0x00000000-->+-----------------------+
+ *
+ * Trusted SRAM section 0x4000000..0x4200000:
+ * ----------------------------------------
+ * SRAM_BASE		= 0x4001000
+ * BL2_BASE		= 0x4006000
+ * BL2_LIMIT		= BL31_BASE
+ * BL31_BASE		= 0x4023000 = (64MB + 256KB - 0x1D000)
+ * BL31_PROGBITS_LIMIT	= BL1_RW_BASE
+ * BL1_RW_BASE		= 0x4037000 = (64MB + 256KB - 0x9000)
+ * BL1_RW_LIMIT		= BL31_LIMIT = 0x4040000
+ *
+ *
+ * PLAT_MARVELL_FIP_BASE	= 0x4120000
+ */
+
+#define PLAT_MARVELL_ATF_BASE			0x4000000
+#define PLAT_MARVELL_ATF_LOAD_ADDR		\
+			(PLAT_MARVELL_ATF_BASE + 0x100000)
+
+#define PLAT_MARVELL_FIP_BASE			\
+			(PLAT_MARVELL_ATF_LOAD_ADDR + 0x20000)
+#define PLAT_MARVELL_FIP_MAX_SIZE		0x4000000
+
+#define PLAT_MARVELL_CLUSTER_CORE_COUNT		2
+/* DRAM[2MB..66MB] is used  as Trusted ROM */
+#define PLAT_MARVELL_TRUSTED_ROM_BASE		PLAT_MARVELL_ATF_LOAD_ADDR
+/* 64 MB TODO: reduce this to minimum needed according to fip image size*/
+#define PLAT_MARVELL_TRUSTED_ROM_SIZE		0x04000000
+/* Reserve 16M for SCP (Secure PayLoad) Trusted DRAM */
+#define PLAT_MARVELL_TRUSTED_DRAM_BASE		0x04400000
+#define PLAT_MARVELL_TRUSTED_DRAM_SIZE		0x01000000	/* 16 MB */
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_MARVELL_MAX_BL1_RW_SIZE		0xA000
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#define PLAT_MARVELL_MAX_BL2_SIZE		0xF000
+
+/*
+ * PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#define PLAT_MARVEL_MAX_BL31_SIZE		0x5D000
+
+#define PLAT_MARVELL_CPU_ENTRY_ADDR		BL1_RO_BASE
+
+/* GIC related definitions */
+#define PLAT_MARVELL_GICD_BASE		(MVEBU_REGS_BASE + MVEBU_GICD_BASE)
+#define PLAT_MARVELL_GICR_BASE		(MVEBU_REGS_BASE + MVEBU_GICR_BASE)
+#define PLAT_MARVELL_GICC_BASE		(MVEBU_REGS_BASE + MVEBU_GICC_BASE)
+
+#define PLAT_MARVELL_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, \
+			GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+
+#define PLAT_MARVELL_SHARED_RAM_CACHED		1
+
+/* CCI related constants */
+#define PLAT_MARVELL_CCI_BASE		(MVEBU_REGS_BASE + MVEBU_CCI_BASE)
+#define PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX	3
+#define PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX	4
+
+/*
+ * Load address of BL3-3 for this platform port
+ */
+#define PLAT_MARVELL_NS_IMAGE_OFFSET		0x0
+
+/* System Reference Clock*/
+#define PLAT_REF_CLK_IN_HZ			COUNTER_FREQUENCY
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_MARVELL_BOOT_UART_BASE		(MVEBU_REGS_BASE + 0x12000)
+#define PLAT_MARVELL_BOOT_UART_CLK_IN_HZ	25804800
+
+#define PLAT_MARVELL_CRASH_UART_BASE		PLAT_MARVELL_BOOT_UART_BASE
+#define PLAT_MARVELL_CRASH_UART_CLK_IN_HZ	PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
+
+#define PLAT_MARVELL_BL31_RUN_UART_BASE		PLAT_MARVELL_BOOT_UART_BASE
+#define PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ	PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
+
+/* Required platform porting definitions */
+#define PLAT_MAX_PWR_LVL			MPIDR_AFFLVL1
+
+/* System timer related constants */
+#define PLAT_MARVELL_NSTIMER_FRAME_ID		1
+
+/* Mailbox base address */
+#define PLAT_MARVELL_MAILBOX_BASE		\
+			(MARVELL_TRUSTED_SRAM_BASE + 0x400)
+#define PLAT_MARVELL_MAILBOX_SIZE		0x100
+#define PLAT_MARVELL_MAILBOX_MAGIC_NUM		0x6D72766C	/* mrvl */
+
+/* DRAM CS memory map registers related constants */
+#define MVEBU_CS_MMAP_LOW(cs_num)		\
+			(MVEBU_CS_MMAP_REG_BASE + (cs_num) * 0x8)
+#define MVEBU_CS_MMAP_ENABLE			0x1
+#define MVEBU_CS_MMAP_AREA_LEN_OFFS		16
+#define MVEBU_CS_MMAP_AREA_LEN_MASK		\
+			(0x1f << MVEBU_CS_MMAP_AREA_LEN_OFFS)
+#define MVEBU_CS_MMAP_START_ADDR_LOW_OFFS	23
+#define MVEBU_CS_MMAP_START_ADDR_LOW_MASK	\
+			(0x1ff << MVEBU_CS_MMAP_START_ADDR_LOW_OFFS)
+
+#define MVEBU_CS_MMAP_HIGH(cs_num)		\
+			(MVEBU_CS_MMAP_REG_BASE + 0x4 + (cs_num) * 0x8)
+
+/* DRAM max CS number */
+#define MVEBU_MAX_CS_MMAP_NUM			(2)
+
+/* CPU decoder window related constants */
+#define CPU_DEC_WIN_CTRL_REG(win_num)		\
+			(MVEBU_CPU_DEC_WIN_REG_BASE + (win_num) * 0x10)
+#define CPU_DEC_CR_WIN_ENABLE			0x1
+#define CPU_DEC_CR_WIN_TARGET_OFFS		4
+#define CPU_DEC_CR_WIN_TARGET_MASK		\
+			(0xf << CPU_DEC_CR_WIN_TARGET_OFFS)
+
+#define CPU_DEC_WIN_SIZE_REG(win_num)		\
+			(MVEBU_CPU_DEC_WIN_REG_BASE + 0x4 + (win_num) * 0x10)
+#define CPU_DEC_CR_WIN_SIZE_OFFS		0
+#define CPU_DEC_CR_WIN_SIZE_MASK		\
+			(0xffff << CPU_DEC_CR_WIN_SIZE_OFFS)
+#define CPU_DEC_CR_WIN_SIZE_ALIGNMENT		0x10000
+
+#define CPU_DEC_WIN_BASE_REG(win_num)		\
+			(MVEBU_CPU_DEC_WIN_REG_BASE + 0x8 + (win_num) * 0x10)
+#define CPU_DEC_BR_BASE_OFFS			0
+#define CPU_DEC_BR_BASE_MASK			\
+			(0xffff <<  CPU_DEC_BR_BASE_OFFS)
+
+#define CPU_DEC_REMAP_LOW_REG(win_num)		\
+			(MVEBU_CPU_DEC_WIN_REG_BASE + 0xC + (win_num) * 0x10)
+#define CPU_DEC_RLR_REMAP_LOW_OFFS		0
+#define CPU_DEC_RLR_REMAP_LOW_MASK		\
+			(0xffff <<  CPU_DEC_BR_BASE_OFFS)
+
+/* Securities */
+#define IRQ_SEC_OS_TICK_INT	MARVELL_IRQ_SEC_PHY_TIMER
+
+#define TRUSTED_DRAM_BASE	PLAT_MARVELL_TRUSTED_DRAM_BASE
+#define TRUSTED_DRAM_SIZE	PLAT_MARVELL_TRUSTED_DRAM_SIZE
+
+#ifdef BL32
+#define BL32_BASE		TRUSTED_DRAM_BASE
+#define BL32_LIMIT		TRUSTED_DRAM_SIZE
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/marvell/a3700/common/io_addr_dec.c b/plat/marvell/a3700/common/io_addr_dec.c
new file mode 100644
index 0000000..b27633c
--- /dev/null
+++ b/plat/marvell/a3700/common/io_addr_dec.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <io_addr_dec.h>
+#include <plat_marvell.h>
+
+#define MVEBU_DEC_WIN_CTRL_REG(base, win, off)	(MVEBU_REGS_BASE + (base) + \
+						(win) * (off))
+#define MVEBU_DEC_WIN_BASE_REG(base, win, off)	(MVEBU_REGS_BASE + (base) + \
+						(win) * (off) + 0x4)
+#define MVEBU_DEC_WIN_REMAP_REG(base, win, off)	(MVEBU_REGS_BASE + (base) + \
+						(win) * (off) + 0x8)
+
+#define MVEBU_DEC_WIN_CTRL_SIZE_OFF		(16)
+#define MVEBU_DEC_WIN_ENABLE			(0x1)
+#define MVEBU_DEC_WIN_CTRL_ATTR_OFF		(8)
+#define MVEBU_DEC_WIN_CTRL_TARGET_OFF		(4)
+#define MVEBU_DEC_WIN_CTRL_EN_OFF		(0)
+#define MVEBU_DEC_WIN_BASE_OFF			(16)
+
+#define MVEBU_WIN_BASE_SIZE_ALIGNMENT		(0x10000)
+
+/* There are up to 14 IO unit which need address decode in Armada-3700 */
+#define IO_UNIT_NUM_MAX				(14)
+
+#define MVEBU_MAX_ADDRSS_4GB			(0x100000000ULL)
+
+
+static void set_io_addr_dec_win(int win_id, uintptr_t base_addr,
+				uintptr_t win_size,
+				struct dec_win_config *dec_win)
+{
+	uint32_t ctrl = 0;
+	uint32_t base = 0;
+
+	/* set size */
+	ctrl = ((win_size / MVEBU_WIN_BASE_SIZE_ALIGNMENT) - 1) <<
+	       MVEBU_DEC_WIN_CTRL_SIZE_OFF;
+	/* set attr according to IO decode window */
+	ctrl |= dec_win->win_attr << MVEBU_DEC_WIN_CTRL_ATTR_OFF;
+	/* set target */
+	ctrl |= DRAM_CPU_DEC_TARGET_NUM << MVEBU_DEC_WIN_CTRL_TARGET_OFF;
+	/* set base */
+	base = (base_addr / MVEBU_WIN_BASE_SIZE_ALIGNMENT) <<
+	       MVEBU_DEC_WIN_BASE_OFF;
+
+	/* set base address*/
+	mmio_write_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base,
+		      win_id, dec_win->win_offset),
+		      base);
+	/* set remap window, some unit does not have remap window */
+	if (win_id < dec_win->max_remap)
+		mmio_write_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
+			      win_id, dec_win->win_offset), base);
+	/* set control register */
+	mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
+		      win_id, dec_win->win_offset), ctrl);
+	/* enable the address decode window at last to make it effective */
+	ctrl |= MVEBU_DEC_WIN_ENABLE << MVEBU_DEC_WIN_CTRL_EN_OFF;
+	mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
+		      win_id, dec_win->win_offset), ctrl);
+
+	INFO("set_io_addr_dec %d result: ctrl(0x%x) base(0x%x)",
+	     win_id, mmio_read_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base,
+	     win_id, dec_win->win_offset)),
+	     mmio_read_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base,
+			  win_id, dec_win->win_offset)));
+	if (win_id < dec_win->max_remap)
+		INFO(" remap(%x)\n",
+		     mmio_read_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base,
+		     win_id, dec_win->win_offset)));
+	else
+		INFO("\n");
+}
+
+/* Set io decode window */
+static int set_io_addr_dec(struct dram_win_map *win_map,
+			   struct dec_win_config *dec_win)
+{
+	struct dram_win *win;
+	int id;
+
+	/* disable all windows first */
+	for (id = 0; id < dec_win->max_dram_win; id++)
+		mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, id,
+			      dec_win->win_offset), 0);
+
+	/* configure IO decode windows for DRAM, inheritate DRAM size,
+	 * base and target from CPU-DRAM decode window and others
+	 * from hard coded IO decode window settings array.
+	 */
+	if (win_map->dram_win_num > dec_win->max_dram_win) {
+		/*
+		 * If cpu dram windows number exceeds the io decode windows
+		 * max number, then fill the first io decode window
+		 * with base(0) and size(4GB).
+		 */
+		set_io_addr_dec_win(0, 0, MVEBU_MAX_ADDRSS_4GB, dec_win);
+
+		return 0;
+	}
+
+	for (id = 0; id < win_map->dram_win_num; id++, win++) {
+		win = &win_map->dram_windows[id];
+		set_io_addr_dec_win(id, win->base_addr, win->win_size, dec_win);
+	}
+
+	return 0;
+}
+
+/*
+ * init_io_addr_dec
+ *
+ * This function initializes io address decoder windows by
+ * cpu dram window mapping information
+ *
+ * @input: N/A
+ *     - dram_wins_map: cpu dram windows mapping
+ *     - io_dec_config: io address decoder windows configuration
+ *     - io_unit_num: io address decoder unit number
+ * @output: N/A
+ *
+ * @return:  0 on success and others on failure
+ */
+int init_io_addr_dec(struct dram_win_map *dram_wins_map,
+		     struct dec_win_config *io_dec_config, uint32_t io_unit_num)
+{
+	int32_t index;
+	struct dec_win_config *io_dec_win;
+	int32_t ret;
+
+	INFO("Initializing IO address decode windows\n");
+
+	if (io_dec_config == NULL || io_unit_num == 0) {
+		ERROR("No IO address decoder windows configurations!\n");
+		return -1;
+	}
+
+	if (io_unit_num > IO_UNIT_NUM_MAX) {
+		ERROR("IO address decoder windows number %d is over max %d\n",
+		      io_unit_num, IO_UNIT_NUM_MAX);
+		return -1;
+	}
+
+	if (dram_wins_map == NULL) {
+		ERROR("No cpu dram decoder windows map!\n");
+		return -1;
+	}
+
+	for (index = 0; index < dram_wins_map->dram_win_num; index++)
+		INFO("DRAM mapping %d base(0x%lx) size(0x%lx)\n",
+		     index, dram_wins_map->dram_windows[index].base_addr,
+		     dram_wins_map->dram_windows[index].win_size);
+
+	/* Set address decode window for each IO */
+	for (index = 0; index < io_unit_num; index++) {
+		io_dec_win = io_dec_config + index;
+		ret = set_io_addr_dec(dram_wins_map, io_dec_win);
+		if (ret) {
+			ERROR("Failed to set IO address decode\n");
+			return -1;
+		}
+		INFO("Set IO decode window successfully, base(0x%x)",
+		     io_dec_win->dec_reg_base);
+		INFO(" win_attr(%x) max_dram_win(%d) max_remap(%d)",
+		     io_dec_win->win_attr, io_dec_win->max_dram_win,
+		     io_dec_win->max_remap);
+		INFO(" win_offset(%d)\n", io_dec_win->win_offset);
+	}
+
+	return 0;
+}
diff --git a/plat/marvell/a3700/common/marvell_plat_config.c b/plat/marvell/a3700/common/marvell_plat_config.c
new file mode 100644
index 0000000..3bf3d96
--- /dev/null
+++ b/plat/marvell/a3700/common/marvell_plat_config.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/bl_common.h>
+
+#include <io_addr_dec.h>
+#include <mvebu_def.h>
+
+struct dec_win_config io_dec_win_conf[] = {
+	/* dec_reg_base  win_attr  max_dram_win  max_remap  win_offset */
+	{0xc000,         0x3d,     2,       0,        0x08}, /* USB */
+	{0xc100,         0x3d,     3,       0,        0x10}, /* USB3 */
+	{0xc200,         0x3d,     2,       0,        0x10}, /* DMA */
+	{0xc300,         0x3d,     2,       0,        0x10}, /* NETA0 */
+	{0xc400,         0x3d,     2,       0,        0x10}, /* NETA1 */
+	{0xc500,         0x3d,     2,       0,        0x10}, /* PCIe */
+	{0xc800,         0x3d,     3,       0,        0x10}, /* SATA */
+	{0xca00,         0x3d,     3,       0,        0x08}, /* SD */
+	{0xcb00,         0x3d,     3,       0,        0x10}, /* eMMC */
+	{0xce00,	 0x3d,	   2,	    0,        0x08}, /* EIP97 */
+};
+
+int marvell_get_io_dec_win_conf(struct dec_win_config **win, uint32_t *size)
+{
+	*win = io_dec_win_conf;
+	*size = sizeof(io_dec_win_conf)/sizeof(struct dec_win_config);
+
+	return 0;
+}
+
diff --git a/plat/marvell/a3700/common/plat_pm.c b/plat/marvell/a3700/common/plat_pm.c
new file mode 100644
index 0000000..f8ce6fe
--- /dev/null
+++ b/plat/marvell/a3700/common/plat_pm.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:	BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#ifdef USE_CCI
+#include <drivers/arm/cci.h>
+#endif
+#include <lib/psci/psci.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <a3700_pm.h>
+#include <arch_helpers.h>
+#include <armada_common.h>
+#include <dram_win.h>
+#include <io_addr_dec.h>
+#include <mvebu.h>
+#include <mvebu_def.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+/* Warm reset register */
+#define MVEBU_WARM_RESET_REG		(MVEBU_NB_REGS_BASE + 0x840)
+#define MVEBU_WARM_RESET_MAGIC		0x1D1E
+
+/* North Bridge GPIO1 SEL register */
+#define MVEBU_NB_GPIO1_SEL_REG		(MVEBU_NB_REGS_BASE + 0x830)
+ #define MVEBU_NB_GPIO1_UART1_SEL	BIT(19)
+ #define MVEBU_NB_GPIO1_GPIO_25_26_EN	BIT(17)
+ #define MVEBU_NB_GPIO1_GPIO_19_EN	BIT(14)
+ #define MVEBU_NB_GPIO1_GPIO_18_EN	BIT(13)
+
+/* CPU 1 reset register */
+#define MVEBU_CPU_1_RESET_VECTOR	(MVEBU_REGS_BASE + 0x14044)
+#define MVEBU_CPU_1_RESET_REG		(MVEBU_REGS_BASE + 0xD00C)
+#define MVEBU_CPU_1_RESET_BIT		31
+
+/* IRQ register */
+#define MVEBU_NB_IRQ_STATUS_1_REG		(MVEBU_NB_SB_IRQ_REG_BASE)
+#define MVEBU_NB_IRQ_STATUS_2_REG		(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0x10)
+#define MVEBU_NB_IRQ_MASK_2_REG			(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0x18)
+#define MVEBU_SB_IRQ_STATUS_1_REG		(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0x40)
+#define MVEBU_SB_IRQ_STATUS_2_REG		(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0x50)
+#define MVEBU_NB_GPIO_IRQ_MASK_1_REG		(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0xC8)
+#define MVEBU_NB_GPIO_IRQ_MASK_2_REG		(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0xD8)
+#define MVEBU_SB_GPIO_IRQ_MASK_REG		(MVEBU_NB_SB_IRQ_REG_BASE + \
+						0xE8)
+#define MVEBU_NB_GPIO_IRQ_EN_LOW_REG		(MVEBU_NB_GPIO_IRQ_REG_BASE)
+#define MVEBU_NB_GPIO_IRQ_EN_HIGH_REG		(MVEBU_NB_GPIO_IRQ_REG_BASE + \
+						0x04)
+#define MVEBU_NB_GPIO_IRQ_STATUS_LOW_REG	(MVEBU_NB_GPIO_IRQ_REG_BASE + \
+						0x10)
+#define MVEBU_NB_GPIO_IRQ_STATUS_HIGH_REG	(MVEBU_NB_GPIO_IRQ_REG_BASE + \
+						0x14)
+#define MVEBU_NB_GPIO_IRQ_WK_LOW_REG		(MVEBU_NB_GPIO_IRQ_REG_BASE + \
+						0x18)
+#define MVEBU_NB_GPIO_IRQ_WK_HIGH_REG		(MVEBU_NB_GPIO_IRQ_REG_BASE + \
+						0x1C)
+#define MVEBU_SB_GPIO_IRQ_EN_REG		(MVEBU_SB_GPIO_IRQ_REG_BASE)
+#define MVEBU_SB_GPIO_IRQ_STATUS_REG		(MVEBU_SB_GPIO_IRQ_REG_BASE + \
+						0x10)
+#define MVEBU_SB_GPIO_IRQ_WK_REG		(MVEBU_SB_GPIO_IRQ_REG_BASE + \
+						0x18)
+
+/* PMU registers */
+#define MVEBU_PM_NB_PWR_CTRL_REG	(MVEBU_PMSU_REG_BASE)
+ #define MVEBU_PM_PWR_DN_CNT_SEL	BIT(28)
+ #define MVEBU_PM_SB_PWR_DWN		BIT(4)
+ #define MVEBU_PM_INTERFACE_IDLE	BIT(0)
+#define MVEBU_PM_NB_CPU_PWR_CTRL_REG	(MVEBU_PMSU_REG_BASE + 0x4)
+ #define MVEBU_PM_L2_FLUSH_EN		BIT(22)
+#define MVEBU_PM_NB_PWR_OPTION_REG	(MVEBU_PMSU_REG_BASE + 0x8)
+ #define MVEBU_PM_DDR_SR_EN		BIT(29)
+ #define MVEBU_PM_DDR_CLK_DIS_EN	BIT(28)
+ #define MVEBU_PM_WARM_RESET_EN		BIT(27)
+ #define MVEBU_PM_DDRPHY_PWRDWN_EN	BIT(23)
+ #define MVEBU_PM_DDRPHY_PAD_PWRDWN_EN	BIT(22)
+ #define MVEBU_PM_OSC_OFF_EN		BIT(21)
+ #define MVEBU_PM_TBG_OFF_EN		BIT(20)
+ #define MVEBU_PM_CPU_VDDV_OFF_EN	BIT(19)
+ #define MVEBU_PM_AVS_DISABLE_MODE	BIT(14)
+ #define MVEBU_PM_AVS_VDD2_MODE		BIT(13)
+ #define MVEBU_PM_AVS_HOLD_MODE		BIT(12)
+ #define MVEBU_PM_L2_SRAM_LKG_PD_EN	BIT(8)
+ #define MVEBU_PM_EIP_SRAM_LKG_PD_EN	BIT(7)
+ #define MVEBU_PM_DDRMC_SRAM_LKG_PD_EN	BIT(6)
+ #define MVEBU_PM_MCI_SRAM_LKG_PD_EN	BIT(5)
+ #define MVEBU_PM_MMC_SRAM_LKG_PD_EN	BIT(4)
+ #define MVEBU_PM_SATA_SRAM_LKG_PD_EN	BIT(3)
+ #define MVEBU_PM_DMA_SRAM_LKG_PD_EN	BIT(2)
+ #define MVEBU_PM_SEC_SRAM_LKG_PD_EN	BIT(1)
+ #define MVEBU_PM_CPU_SRAM_LKG_PD_EN	BIT(0)
+ #define MVEBU_PM_NB_SRAM_LKG_PD_EN	(MVEBU_PM_L2_SRAM_LKG_PD_EN |\
+	MVEBU_PM_EIP_SRAM_LKG_PD_EN | MVEBU_PM_DDRMC_SRAM_LKG_PD_EN |\
+	MVEBU_PM_MCI_SRAM_LKG_PD_EN | MVEBU_PM_MMC_SRAM_LKG_PD_EN |\
+	MVEBU_PM_SATA_SRAM_LKG_PD_EN | MVEBU_PM_DMA_SRAM_LKG_PD_EN |\
+	MVEBU_PM_SEC_SRAM_LKG_PD_EN | MVEBU_PM_CPU_SRAM_LKG_PD_EN)
+#define MVEBU_PM_NB_PWR_DEBUG_REG	(MVEBU_PMSU_REG_BASE + 0xC)
+ #define MVEBU_PM_NB_FORCE_CLK_ON	BIT(30)
+ #define MVEBU_PM_IGNORE_CM3_SLEEP	BIT(21)
+ #define MVEBU_PM_IGNORE_CM3_DEEP	BIT(20)
+#define MVEBU_PM_NB_WAKE_UP_EN_REG	(MVEBU_PMSU_REG_BASE + 0x2C)
+ #define MVEBU_PM_SB_WKP_NB_EN		BIT(31)
+ #define MVEBU_PM_NB_GPIO_WKP_EN	BIT(27)
+ #define MVEBU_PM_SOC_TIMER_WKP_EN	BIT(26)
+ #define MVEBU_PM_UART_WKP_EN		BIT(25)
+ #define MVEBU_PM_UART2_WKP_EN		BIT(19)
+ #define MVEBU_PM_CPU_TIMER_WKP_EN	BIT(17)
+ #define MVEBU_PM_NB_WKP_EN		BIT(16)
+ #define MVEBU_PM_CORE1_FIQ_IRQ_WKP_EN	BIT(13)
+ #define MVEBU_PM_CORE0_FIQ_IRQ_WKP_EN	BIT(12)
+#define MVEBU_PM_CPU_0_PWR_CTRL_REG	(MVEBU_PMSU_REG_BASE + 0x34)
+#define MVEBU_PM_CPU_1_PWR_CTRL_REG	(MVEBU_PMSU_REG_BASE + 0x38)
+ #define MVEBU_PM_CORE_SOC_PD		BIT(2)
+ #define MVEBU_PM_CORE_PROC_PD		BIT(1)
+ #define MVEBU_PM_CORE_PD		BIT(0)
+#define MVEBU_PM_CORE_1_RETURN_ADDR_REG	(MVEBU_PMSU_REG_BASE + 0x44)
+#define MVEBU_PM_CPU_VDD_OFF_INFO_1_REG	(MVEBU_PMSU_REG_BASE + 0x48)
+#define MVEBU_PM_CPU_VDD_OFF_INFO_2_REG	(MVEBU_PMSU_REG_BASE + 0x4C)
+ #define MVEBU_PM_LOW_POWER_STATE	BIT(0)
+#define MVEBU_PM_CPU_WAKE_UP_CONF_REG	(MVEBU_PMSU_REG_BASE + 0x54)
+ #define MVEBU_PM_CORE1_WAKEUP		BIT(13)
+ #define MVEBU_PM_CORE0_WAKEUP		BIT(12)
+#define MVEBU_PM_WAIT_DDR_RDY_VALUE	(0x15)
+#define MVEBU_PM_SB_CPU_PWR_CTRL_REG	(MVEBU_SB_WAKEUP_REG_BASE)
+  #define MVEBU_PM_SB_PM_START		BIT(0)
+#define MVEBU_PM_SB_PWR_OPTION_REG	(MVEBU_SB_WAKEUP_REG_BASE + 0x4)
+  #define MVEBU_PM_SDIO_PHY_PDWN_EN	BIT(17)
+  #define MVEBU_PM_SB_VDDV_OFF_EN	BIT(16)
+  #define MVEBU_PM_EBM_SRAM_LKG_PD_EN		BIT(11)
+  #define MVEBU_PM_PCIE_SRAM_LKG_PD_EN		BIT(10)
+  #define MVEBU_PM_GBE1_TX_SRAM_LKG_PD_EN	BIT(9)
+  #define MVEBU_PM_GBE1_RX_SRAM_LKG_PD_EN	BIT(8)
+  #define MVEBU_PM_GBE1_MIB_SRAM_LKG_PD_EN	BIT(7)
+  #define MVEBU_PM_GBE0_TX_SRAM_LKG_PD_EN	BIT(6)
+  #define MVEBU_PM_GBE0_RX_SRAM_LKG_PD_EN	BIT(5)
+  #define MVEBU_PM_GBE0_MIB_SRAM_LKG_PD_EN	BIT(4)
+  #define MVEBU_PM_SDIO_SRAM_LKG_PD_EN		BIT(3)
+  #define MVEBU_PM_USB2_SRAM_LKG_PD_EN		BIT(2)
+  #define MVEBU_PM_USB3_H_SRAM_LKG_PD_EN	BIT(1)
+  #define MVEBU_PM_SB_SRAM_LKG_PD_EN	(MVEBU_PM_EBM_SRAM_LKG_PD_EN |\
+	MVEBU_PM_PCIE_SRAM_LKG_PD_EN | MVEBU_PM_GBE1_TX_SRAM_LKG_PD_EN |\
+	MVEBU_PM_GBE1_RX_SRAM_LKG_PD_EN | MVEBU_PM_GBE1_MIB_SRAM_LKG_PD_EN |\
+	MVEBU_PM_GBE0_TX_SRAM_LKG_PD_EN | MVEBU_PM_GBE0_RX_SRAM_LKG_PD_EN |\
+	MVEBU_PM_GBE0_MIB_SRAM_LKG_PD_EN | MVEBU_PM_SDIO_SRAM_LKG_PD_EN |\
+	MVEBU_PM_USB2_SRAM_LKG_PD_EN | MVEBU_PM_USB3_H_SRAM_LKG_PD_EN)
+#define MVEBU_PM_SB_WK_EN_REG		(MVEBU_SB_WAKEUP_REG_BASE + 0x10)
+  #define MVEBU_PM_SB_GPIO_WKP_EN	BIT(24)
+  #define MVEBU_PM_SB_WKP_EN		BIT(20)
+
+/* DRAM registers */
+#define MVEBU_DRAM_STATS_CH0_REG	(MVEBU_DRAM_REG_BASE + 0x4)
+ #define MVEBU_DRAM_WCP_EMPTY		BIT(19)
+#define MVEBU_DRAM_CMD_0_REG		(MVEBU_DRAM_REG_BASE + 0x20)
+ #define MVEBU_DRAM_CH0_CMD0		BIT(28)
+ #define MVEBU_DRAM_CS_CMD0		BIT(24)
+ #define MVEBU_DRAM_WCB_DRAIN_REQ	BIT(1)
+#define MVEBU_DRAM_PWR_CTRL_REG		(MVEBU_DRAM_REG_BASE + 0x54)
+ #define MVEBU_DRAM_PHY_CLK_GATING_EN	BIT(1)
+ #define MVEBU_DRAM_PHY_AUTO_AC_OFF_EN	BIT(0)
+
+/* AVS registers */
+#define MVEBU_AVS_CTRL_2_REG		(MVEBU_AVS_REG_BASE + 0x8)
+ #define MVEBU_LOW_VDD_MODE_EN		BIT(6)
+
+/* Clock registers */
+#define MVEBU_NB_CLOCK_SEL_REG		(MVEBU_NB_REGS_BASE + 0x10)
+ #define MVEBU_A53_CPU_CLK_SEL		BIT(15)
+
+/* North Bridge Step-Down Registers */
+#define MVEBU_NB_STEP_DOWN_INT_EN_REG	MVEBU_NB_STEP_DOWN_REG_BASE
+ #define MVEBU_NB_GPIO_INT_WAKE_WCPU_CLK	BIT(8)
+
+#define MVEBU_NB_GPIO_18	18
+#define MVEBU_NB_GPIO_19	19
+#define MVEBU_NB_GPIO_25	25
+#define MVEBU_NB_GPIO_26	26
+
+typedef int (*wake_up_src_func)(union pm_wake_up_src_data *);
+
+struct wake_up_src_func_map {
+	enum pm_wake_up_src_type type;
+	wake_up_src_func func;
+};
+
+void marvell_psci_arch_init(int die_index)
+{
+}
+
+static void a3700_pm_ack_irq(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(MVEBU_NB_IRQ_STATUS_1_REG);
+	if (reg)
+		mmio_write_32(MVEBU_NB_IRQ_STATUS_1_REG, reg);
+
+	reg = mmio_read_32(MVEBU_NB_IRQ_STATUS_2_REG);
+	if (reg)
+		mmio_write_32(MVEBU_NB_IRQ_STATUS_2_REG, reg);
+
+	reg = mmio_read_32(MVEBU_SB_IRQ_STATUS_1_REG);
+	if (reg)
+		mmio_write_32(MVEBU_SB_IRQ_STATUS_1_REG, reg);
+
+	reg = mmio_read_32(MVEBU_SB_IRQ_STATUS_2_REG);
+	if (reg)
+		mmio_write_32(MVEBU_SB_IRQ_STATUS_2_REG, reg);
+
+	reg = mmio_read_32(MVEBU_NB_GPIO_IRQ_STATUS_LOW_REG);
+	if (reg)
+		mmio_write_32(MVEBU_NB_GPIO_IRQ_STATUS_LOW_REG, reg);
+
+	reg = mmio_read_32(MVEBU_NB_GPIO_IRQ_STATUS_HIGH_REG);
+	if (reg)
+		mmio_write_32(MVEBU_NB_GPIO_IRQ_STATUS_HIGH_REG, reg);
+
+	reg = mmio_read_32(MVEBU_SB_GPIO_IRQ_STATUS_REG);
+	if (reg)
+		mmio_write_32(MVEBU_SB_GPIO_IRQ_STATUS_REG, reg);
+}
+
+/*****************************************************************************
+ * A3700 handler called to check the validity of the power state
+ * parameter.
+ *****************************************************************************
+ */
+int a3700_validate_power_state(unsigned int power_state,
+			       psci_power_state_t *req_state)
+{
+	ERROR("%s needs to be implemented\n", __func__);
+	panic();
+}
+
+/*****************************************************************************
+ * A3700 handler called when a CPU is about to enter standby.
+ *****************************************************************************
+ */
+void a3700_cpu_standby(plat_local_state_t cpu_state)
+{
+	ERROR("%s needs to be implemented\n", __func__);
+	panic();
+}
+
+/*****************************************************************************
+ * A3700 handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ *****************************************************************************
+ */
+int a3700_pwr_domain_on(u_register_t mpidr)
+{
+	/* Set barrier */
+	dsbsy();
+
+	/* Set the cpu start address to BL1 entry point */
+	mmio_write_32(MVEBU_CPU_1_RESET_VECTOR,
+		      PLAT_MARVELL_CPU_ENTRY_ADDR >> 2);
+
+	/* Get the cpu out of reset */
+	mmio_clrbits_32(MVEBU_CPU_1_RESET_REG, BIT(MVEBU_CPU_1_RESET_BIT));
+	mmio_setbits_32(MVEBU_CPU_1_RESET_REG, BIT(MVEBU_CPU_1_RESET_BIT));
+
+	return 0;
+}
+
+/*****************************************************************************
+ * A3700 handler called to validate the entry point.
+ *****************************************************************************
+ */
+int a3700_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	return PSCI_E_SUCCESS;
+}
+
+/*****************************************************************************
+ * A3700 handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ *****************************************************************************
+ */
+void a3700_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_marvell_gic_cpuif_disable();
+
+	/* Core can not be powered down with pending IRQ,
+	 * acknowledge all the pending IRQ
+	 */
+	a3700_pm_ack_irq();
+}
+
+static void a3700_set_gen_pwr_off_option(void)
+{
+	/* Enable L2 flush -> processor state-machine option */
+	mmio_setbits_32(MVEBU_PM_NB_CPU_PWR_CTRL_REG, MVEBU_PM_L2_FLUSH_EN);
+
+	/*
+	 * North bridge cannot be VDD off (always ON).
+	 * The NB state machine support low power mode by its state machine.
+	 * This bit MUST be set for north bridge power down, e.g.,
+	 * OSC input cutoff(NOT TEST), SRAM power down, PMIC, etc.
+	 * It is not related to CPU VDD OFF!!
+	 */
+	mmio_clrbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_CPU_VDDV_OFF_EN);
+
+	/*
+	 * MUST: Switch CPU/AXI clock to OSC
+	 * NB state machine clock is always connected to OSC (slow clock).
+	 * But Core0/1/processor state machine's clock are connected to AXI
+	 *  clock. Now, AXI clock takes the TBG as clock source.
+	 * If using AXI clock, Core0/1/processor state machine may much faster
+	 * than NB state machine. It will cause problem in this case if cores
+	 * are released before north bridge gets ready.
+	 */
+	mmio_clrbits_32(MVEBU_NB_CLOCK_SEL_REG, MVEBU_A53_CPU_CLK_SEL);
+
+	/*
+	 * These register bits will trigger north bridge
+	 * power-down state machine regardless CM3 status.
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_DEBUG_REG, MVEBU_PM_IGNORE_CM3_SLEEP);
+	mmio_setbits_32(MVEBU_PM_NB_PWR_DEBUG_REG, MVEBU_PM_IGNORE_CM3_DEEP);
+
+	/*
+	 * SRAM => controlled by north bridge state machine.
+	 * Core VDD OFF is not related to CPU SRAM power down.
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_NB_SRAM_LKG_PD_EN);
+
+	/*
+	 * Idle AXI interface in order to get L2_WFI
+	 * L2 WFI is only asserted after CORE-0 and CORE-1 WFI asserted.
+	 * (only both core-0/1in WFI, L2 WFI will be issued by CORE.)
+	 * Once L2 WFI asserted, this bit is used for signalling assertion
+	 * to AXI IO masters.
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_CTRL_REG, MVEBU_PM_INTERFACE_IDLE);
+
+	/* Enable core0 and core1 VDD_OFF */
+	mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG, MVEBU_PM_CORE_PD);
+	mmio_setbits_32(MVEBU_PM_CPU_1_PWR_CTRL_REG, MVEBU_PM_CORE_PD);
+
+	/* Enable North bridge power down -
+	 * Both Cores MUST enable this bit to power down north bridge!
+	 */
+	mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG, MVEBU_PM_CORE_SOC_PD);
+	mmio_setbits_32(MVEBU_PM_CPU_1_PWR_CTRL_REG, MVEBU_PM_CORE_SOC_PD);
+
+	/* CA53 (processor domain) power down */
+	mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG, MVEBU_PM_CORE_PROC_PD);
+	mmio_setbits_32(MVEBU_PM_CPU_1_PWR_CTRL_REG, MVEBU_PM_CORE_PROC_PD);
+}
+
+static void a3700_en_ddr_self_refresh(void)
+{
+	/*
+	 * Both count is 16 bits and configurable. By default, osc stb cnt
+	 * is 0xFFF for lower 12 bits.
+	 * Thus, powerdown count is smaller than osc count.
+	 * This count is used for exiting DDR SR mode on wakeup event.
+	 * The powerdown count also has impact on the following
+	 * state changes: idle -> count-down -> ... (power-down, vdd off, etc)
+	 * Here, make stable counter shorter
+	 * Use power down count value instead of osc_stb_cnt to speed up
+	 * DDR self refresh exit
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_CTRL_REG, MVEBU_PM_PWR_DN_CNT_SEL);
+
+	/*
+	 * Enable DDR SR mode => controlled by north bridge state machine
+	 * Therefore, we must powerdown north bridge to trigger the DDR SR
+	 * mode switching.
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDR_SR_EN);
+	/* Disable DDR clock, otherwise DDR will not enter into SR mode. */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDR_CLK_DIS_EN);
+	/* Power down DDR PHY (PAD) */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDRPHY_PWRDWN_EN);
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG,
+			MVEBU_PM_DDRPHY_PAD_PWRDWN_EN);
+
+	/* Set wait time for DDR ready in ROM code */
+	mmio_write_32(MVEBU_PM_CPU_VDD_OFF_INFO_1_REG,
+		      MVEBU_PM_WAIT_DDR_RDY_VALUE);
+
+	/* DDR flush write buffer - mandatory */
+	mmio_write_32(MVEBU_DRAM_CMD_0_REG, MVEBU_DRAM_CH0_CMD0 |
+		      MVEBU_DRAM_CS_CMD0 | MVEBU_DRAM_WCB_DRAIN_REQ);
+	while ((mmio_read_32(MVEBU_DRAM_STATS_CH0_REG) &
+			     MVEBU_DRAM_WCP_EMPTY) != MVEBU_DRAM_WCP_EMPTY)
+		;
+
+	/* Trigger PHY reset after ddr out of self refresh =>
+	 * supply reset pulse for DDR phy after wake up
+	 */
+	mmio_setbits_32(MVEBU_DRAM_PWR_CTRL_REG, MVEBU_DRAM_PHY_CLK_GATING_EN |
+						 MVEBU_DRAM_PHY_AUTO_AC_OFF_EN);
+}
+
+static void a3700_pwr_dn_avs(void)
+{
+	/*
+	 * AVS power down - controlled by north bridge statemachine
+	 * Enable AVS power down by clear the AVS disable bit.
+	 */
+	mmio_clrbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_AVS_DISABLE_MODE);
+	/*
+	 * Should set BIT[12:13] to powerdown AVS.
+	 * 1. Enable AVS VDD2 mode
+	 * 2. After power down AVS, we must hold AVS output voltage.
+	 * 3. We can choose the lower VDD for AVS power down.
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_AVS_VDD2_MODE);
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_AVS_HOLD_MODE);
+
+	/* Enable low VDD mode, AVS will set CPU to lowest core VDD 747mV */
+	mmio_setbits_32(MVEBU_AVS_CTRL_2_REG, MVEBU_LOW_VDD_MODE_EN);
+}
+
+static void a3700_pwr_dn_tbg(void)
+{
+	/* Power down TBG */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_TBG_OFF_EN);
+}
+
+static void a3700_pwr_dn_sb(void)
+{
+	/* Enable south bridge power down option */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_CTRL_REG, MVEBU_PM_SB_PWR_DWN);
+
+	/* Enable SDIO_PHY_PWRDWN */
+	mmio_setbits_32(MVEBU_PM_SB_PWR_OPTION_REG, MVEBU_PM_SDIO_PHY_PDWN_EN);
+
+	/* Enable SRAM LRM on SB */
+	mmio_setbits_32(MVEBU_PM_SB_PWR_OPTION_REG, MVEBU_PM_SB_SRAM_LKG_PD_EN);
+
+	/* Enable SB Power Off */
+	mmio_setbits_32(MVEBU_PM_SB_PWR_OPTION_REG, MVEBU_PM_SB_VDDV_OFF_EN);
+
+	/* Kick off South Bridge Power Off */
+	mmio_setbits_32(MVEBU_PM_SB_CPU_PWR_CTRL_REG, MVEBU_PM_SB_PM_START);
+}
+
+static void a3700_set_pwr_off_option(void)
+{
+	/* Set general power off option */
+	a3700_set_gen_pwr_off_option();
+
+	/* Enable DDR self refresh in low power mode */
+	a3700_en_ddr_self_refresh();
+
+	/* Power down AVS */
+	a3700_pwr_dn_avs();
+
+	/* Power down TBG */
+	a3700_pwr_dn_tbg();
+
+	/* Power down south bridge, pay attention south bridge setting
+	 * should be done before
+	 */
+	a3700_pwr_dn_sb();
+}
+
+static void a3700_set_wake_up_option(void)
+{
+	/*
+	 * Enable the wakeup event for NB SOC => north-bridge
+	 * state-machine enablement on wake-up event
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_WAKE_UP_EN_REG, MVEBU_PM_NB_WKP_EN);
+
+	 /* Enable both core0 and core1 wakeup on demand */
+	mmio_setbits_32(MVEBU_PM_CPU_WAKE_UP_CONF_REG,
+			MVEBU_PM_CORE1_WAKEUP | MVEBU_PM_CORE0_WAKEUP);
+
+	/* Enable warm reset in low power mode */
+	mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_WARM_RESET_EN);
+}
+
+static void a3700_pm_en_nb_gpio(uint32_t gpio)
+{
+	/* For GPIO1 interrupt -- North bridge only */
+	if (gpio >= 32) {
+		/* GPIO int mask */
+		mmio_clrbits_32(MVEBU_NB_GPIO_IRQ_MASK_2_REG, BIT(gpio - 32));
+
+		/* NB_CPU_WAKE-up ENABLE GPIO int */
+		mmio_setbits_32(MVEBU_NB_GPIO_IRQ_EN_HIGH_REG, BIT(gpio - 32));
+	} else {
+		/* GPIO int mask */
+		mmio_clrbits_32(MVEBU_NB_GPIO_IRQ_MASK_1_REG, BIT(gpio));
+
+		/* NB_CPU_WAKE-up ENABLE GPIO int */
+		mmio_setbits_32(MVEBU_NB_GPIO_IRQ_EN_LOW_REG, BIT(gpio));
+	}
+
+	mmio_setbits_32(MVEBU_NB_STEP_DOWN_INT_EN_REG,
+			MVEBU_NB_GPIO_INT_WAKE_WCPU_CLK);
+
+	/* Enable using GPIO as wakeup event
+	 * (actually not only for north bridge)
+	 */
+	mmio_setbits_32(MVEBU_PM_NB_WAKE_UP_EN_REG, MVEBU_PM_NB_GPIO_WKP_EN |
+		MVEBU_PM_NB_WKP_EN | MVEBU_PM_CORE1_FIQ_IRQ_WKP_EN |
+		MVEBU_PM_CORE0_FIQ_IRQ_WKP_EN);
+}
+
+static void a3700_pm_en_sb_gpio(uint32_t gpio)
+{
+	/* Enable using GPIO as wakeup event */
+	mmio_setbits_32(MVEBU_PM_NB_WAKE_UP_EN_REG, MVEBU_PM_SB_WKP_NB_EN |
+		MVEBU_PM_NB_WKP_EN | MVEBU_PM_CORE1_FIQ_IRQ_WKP_EN |
+		MVEBU_PM_CORE0_FIQ_IRQ_WKP_EN);
+
+	/* SB GPIO Wake UP | South Bridge Wake Up Enable */
+	mmio_setbits_32(MVEBU_PM_SB_WK_EN_REG, MVEBU_PM_SB_GPIO_WKP_EN |
+			MVEBU_PM_SB_GPIO_WKP_EN);
+
+	/* GPIO int mask */
+	mmio_clrbits_32(MVEBU_SB_GPIO_IRQ_MASK_REG, BIT(gpio));
+
+	/* NB_CPU_WAKE-up ENABLE GPIO int */
+	mmio_setbits_32(MVEBU_SB_GPIO_IRQ_EN_REG, BIT(gpio));
+}
+
+int a3700_pm_src_gpio(union pm_wake_up_src_data *src_data)
+{
+	if (src_data->gpio_data.bank_num == 0)
+		/* North Bridge GPIO */
+		a3700_pm_en_nb_gpio(src_data->gpio_data.gpio_num);
+	else
+		a3700_pm_en_sb_gpio(src_data->gpio_data.gpio_num);
+	return 0;
+}
+
+int a3700_pm_src_uart1(union pm_wake_up_src_data *src_data)
+{
+	/* Clear Uart1 select */
+	mmio_clrbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_UART1_SEL);
+	/* set pin 19 gpio usage*/
+	mmio_setbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_GPIO_19_EN);
+	/* Enable gpio wake-up*/
+	a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_19);
+	/* set pin 18 gpio usage*/
+	mmio_setbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_GPIO_18_EN);
+	/* Enable gpio wake-up*/
+	a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_18);
+
+	return 0;
+}
+
+int a3700_pm_src_uart0(union pm_wake_up_src_data *src_data)
+{
+	/* set pin 25/26 gpio usage*/
+	mmio_setbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_GPIO_25_26_EN);
+	/* Enable gpio wake-up*/
+	a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_25);
+	/* Enable gpio wake-up*/
+	a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_26);
+
+	return 0;
+}
+
+struct wake_up_src_func_map src_func_table[WAKE_UP_SRC_MAX] = {
+	{WAKE_UP_SRC_GPIO, a3700_pm_src_gpio},
+	{WAKE_UP_SRC_UART1, a3700_pm_src_uart1},
+	{WAKE_UP_SRC_UART0, a3700_pm_src_uart0},
+	/* FOLLOWING SRC NOT SUPPORTED YET */
+	{WAKE_UP_SRC_TIMER, NULL}
+};
+
+static wake_up_src_func a3700_get_wake_up_src_func(
+						  enum pm_wake_up_src_type type)
+{
+	uint32_t loop;
+
+	for (loop = 0; loop < WAKE_UP_SRC_MAX; loop++) {
+		if (src_func_table[loop].type == type)
+			return src_func_table[loop].func;
+	}
+	return NULL;
+}
+
+static void a3700_set_wake_up_source(void)
+{
+	struct pm_wake_up_src_config *wake_up_src;
+	uint32_t loop;
+	wake_up_src_func src_func = NULL;
+
+	wake_up_src = mv_wake_up_src_config_get();
+	for (loop = 0; loop < wake_up_src->wake_up_src_num; loop++) {
+		src_func = a3700_get_wake_up_src_func(
+			   wake_up_src->wake_up_src[loop].wake_up_src_type);
+		if (src_func)
+			src_func(
+				&(wake_up_src->wake_up_src[loop].wake_up_data));
+	}
+}
+
+static void a3700_pm_save_lp_flag(void)
+{
+	/* Save the flag for enter the low power mode */
+	mmio_setbits_32(MVEBU_PM_CPU_VDD_OFF_INFO_2_REG,
+			MVEBU_PM_LOW_POWER_STATE);
+}
+
+static void a3700_pm_clear_lp_flag(void)
+{
+	/* Clear the flag for enter the low power mode */
+	mmio_clrbits_32(MVEBU_PM_CPU_VDD_OFF_INFO_2_REG,
+			MVEBU_PM_LOW_POWER_STATE);
+}
+
+static uint32_t a3700_pm_get_lp_flag(void)
+{
+	/* Get the flag for enter the low power mode */
+	return mmio_read_32(MVEBU_PM_CPU_VDD_OFF_INFO_2_REG) &
+			    MVEBU_PM_LOW_POWER_STATE;
+}
+
+/*****************************************************************************
+ * A3700 handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ *****************************************************************************
+ */
+void a3700_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_marvell_gic_cpuif_disable();
+
+	/* Save IRQ states */
+	plat_marvell_gic_irq_save();
+
+	/* Set wake up options */
+	a3700_set_wake_up_option();
+
+	/* Set wake up sources */
+	a3700_set_wake_up_source();
+
+	/* SoC can not be powered down with pending IRQ,
+	 * acknowledge all the pending IRQ
+	 */
+	a3700_pm_ack_irq();
+
+	/* Set power off options */
+	a3700_set_pwr_off_option();
+
+	/* Save the flag for enter the low power mode */
+	a3700_pm_save_lp_flag();
+
+	isb();
+}
+
+/*****************************************************************************
+ * A3700 handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ *****************************************************************************
+ */
+void a3700_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* arch specific configuration */
+	marvell_psci_arch_init(0);
+
+	/* Per-CPU interrupt initialization */
+	plat_marvell_gic_pcpu_init();
+	plat_marvell_gic_cpuif_enable();
+
+	/* Restore the per-cpu IRQ state */
+	if (a3700_pm_get_lp_flag())
+		plat_marvell_gic_irq_pcpu_restore();
+}
+
+/*****************************************************************************
+ * A3700 handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ *****************************************************************************
+ */
+void a3700_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	struct dec_win_config *io_dec_map;
+	uint32_t dec_win_num;
+	struct dram_win_map dram_wins_map;
+
+	/* arch specific configuration */
+	marvell_psci_arch_init(0);
+
+	/* Interrupt initialization */
+	plat_marvell_gic_init();
+
+	/* Restore IRQ states */
+	plat_marvell_gic_irq_restore();
+
+	/*
+	 * Initialize CCI for this cluster after resume from suspend state.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_marvell_interconnect_init();
+	/*
+	 * Enable CCI coherency for the primary CPU's cluster.
+	 * Platform specific PSCI code will enable coherency for other
+	 * clusters.
+	 */
+	plat_marvell_interconnect_enter_coherency();
+
+	/* CPU address decoder windows initialization. */
+	cpu_wins_init();
+
+	/* fetch CPU-DRAM window mapping information by reading
+	 * CPU-DRAM decode windows (only the enabled ones)
+	 */
+	dram_win_map_build(&dram_wins_map);
+
+	/* Get IO address decoder windows */
+	if (marvell_get_io_dec_win_conf(&io_dec_map, &dec_win_num)) {
+		printf("No IO address decoder windows configurations found!\n");
+		return;
+	}
+
+	/* IO address decoder init */
+	if (init_io_addr_dec(&dram_wins_map, io_dec_map, dec_win_num)) {
+		printf("IO address decoder windows initialization failed!\n");
+		return;
+	}
+
+	/* Clear low power mode flag */
+	a3700_pm_clear_lp_flag();
+}
+
+/*****************************************************************************
+ * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND
+ * call to get the `power_state` parameter. This allows the platform to encode
+ * the appropriate State-ID field within the `power_state` parameter which can
+ * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
+ *****************************************************************************
+ */
+void a3700_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	/* lower affinities use PLAT_MAX_OFF_STATE */
+	for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+/*****************************************************************************
+ * A3700 handlers to shutdown/reboot the system
+ *****************************************************************************
+ */
+static void __dead2 a3700_system_off(void)
+{
+	ERROR("%s needs to be implemented\n", __func__);
+	panic();
+}
+
+/*****************************************************************************
+ * A3700 handlers to reset the system
+ *****************************************************************************
+ */
+static void __dead2 a3700_system_reset(void)
+{
+	/* Clean the mailbox magic number to let it as act like cold boot */
+	mmio_write_32(PLAT_MARVELL_MAILBOX_BASE, 0x0);
+
+	dsbsy();
+
+	/* Flush data cache if the mail box shared RAM is cached */
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+	flush_dcache_range((uintptr_t)PLAT_MARVELL_MAILBOX_BASE,
+			   2 * sizeof(uint64_t));
+#endif
+
+	/* Trigger the warm reset */
+	mmio_write_32(MVEBU_WARM_RESET_REG, MVEBU_WARM_RESET_MAGIC);
+
+	/* Shouldn't get to this point */
+	panic();
+}
+
+/*****************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ *****************************************************************************
+ */
+const plat_psci_ops_t plat_arm_psci_pm_ops = {
+	.cpu_standby = a3700_cpu_standby,
+	.pwr_domain_on = a3700_pwr_domain_on,
+	.pwr_domain_off = a3700_pwr_domain_off,
+	.pwr_domain_suspend = a3700_pwr_domain_suspend,
+	.pwr_domain_on_finish = a3700_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = a3700_pwr_domain_suspend_finish,
+	.get_sys_suspend_power_state = a3700_get_sys_suspend_power_state,
+	.system_off = a3700_system_off,
+	.system_reset = a3700_system_reset,
+	.validate_power_state = a3700_validate_power_state,
+	.validate_ns_entrypoint = a3700_validate_ns_entrypoint
+};
diff --git a/plat/marvell/a8k/a70x0/board/dram_port.c b/plat/marvell/a8k/a70x0/board/dram_port.c
new file mode 100644
index 0000000..4fca7e3
--- /dev/null
+++ b/plat/marvell/a8k/a70x0/board/dram_port.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+}
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+/* FIXME: MISL board 2CS 4Gb x8 devices of micron - 2133P */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0} },
+	   SPEED_BIN_DDR_2133P,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_4GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	MV_DDR_32BIT_ECC_PUP8_BUS_MASK,	/* subphys mask */
+	MV_DDR_CFG_DEFAULT,		/* ddr configuration data source */
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+	/* Return the board topology as defined in the board code */
+	return &board_topology_map;
+}
diff --git a/plat/marvell/a8k/a70x0/board/marvell_plat_config.c b/plat/marvell/a8k/a70x0/board/marvell_plat_config.c
new file mode 100644
index 0000000..d126f55
--- /dev/null
+++ b/plat/marvell/a8k/a70x0/board/marvell_plat_config.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+	/* CP0 SPI1 CS0 Direct Mode access */
+	{0xf900,	0x1000000,	AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win,
+			       uint32_t *size, uintptr_t base)
+{
+	*win = amb_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(amb_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO_WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#ifndef IMAGE_BLE
+	/* MCI 0 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(0),	0x100000, MCI_0_TID},
+	/* MCI 1 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(1),	0x100000, MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+	return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+				  uint32_t *size)
+{
+	*win = io_win_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(io_win_memory_map);
+
+	return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map[] = {
+	/* PEX1_X1 window */
+	{0x00000000f7000000,	0x1000000,	PEX1_TID},
+	/* PEX2_X1 window */
+	{0x00000000f8000000,	0x1000000,	PEX2_TID},
+	{0x00000000c0000000,	0x30000000,	PEX2_TID},
+	{0x0000000800000000,	0x100000000,	PEX2_TID},
+	/* PEX0_X4 window */
+	{0x00000000f6000000,	0x1000000,	PEX0_TID},
+	/* SPI1_CS0 (RUNIT) window */
+	{0x00000000f9000000,	0x1000000,	RUNIT_TID},
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	*win = iob_memory_map;
+	*size = ARRAY_SIZE(iob_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {	/* IO window */
+#ifdef IMAGE_BLE
+	{0x00000000f2000000,	0x4000000,	IO_0_TID}, /* IO window */
+#else
+	{0x00000000f2000000,	0xe000000,	IO_0_TID},
+	{0x00000000c0000000,	0x30000000,	IO_0_TID}, /* IO window */
+	{0x0000000800000000,	0x100000000,	IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+	return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+			       uint32_t *size)
+{
+	*win = ccu_memory_map;
+	*size = ARRAY_SIZE(ccu_memory_map);
+
+	return 0;
+}
+
+#ifdef IMAGE_BLE
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+struct skip_image skip_im = {
+	.detection_method = GPIO,
+	.info.gpio.num = 33,
+	.info.gpio.button_state = HIGH,
+	.info.test.cp_ap = CP,
+	.info.test.cp_index = 0,
+};
+
+void *plat_marvell_get_skip_image_data(void)
+{
+	/* Return the skip_image configurations */
+	return &skip_im;
+}
+#endif
+#endif
diff --git a/plat/marvell/a8k/a70x0/mvebu_def.h b/plat/marvell/a8k/a70x0/mvebu_def.h
new file mode 100644
index 0000000..72bca12
--- /dev/null
+++ b/plat/marvell/a8k/a70x0/mvebu_def.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT		1	/* A70x0 has single CP0 */
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/a8k/a70x0/platform.mk b/plat/marvell/a8k/a70x0/platform.mk
new file mode 100644
index 0000000..d3a0167
--- /dev/null
+++ b/plat/marvell/a8k/a70x0/platform.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT		:= 0
+
+CP_NUM			:= 1
+$(eval $(call add_define,CP_NUM))
+
+DOIMAGE_SEC     	:=	tools/doimage/secure/sec_img_7K.cfg
+
+MARVELL_MOCHI_DRV	:=	drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/a70x0_amc/board/dram_port.c b/plat/marvell/a8k/a70x0_amc/board/dram_port.c
new file mode 100644
index 0000000..aecf6c5
--- /dev/null
+++ b/plat/marvell/a8k/a70x0_amc/board/dram_port.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+}
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+/* FIXME: MISL board 2CS 8Gb x8 devices of micron - 2133P */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0} },
+	   SPEED_BIN_DDR_2400T,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_8GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	MV_DDR_32BIT_ECC_PUP8_BUS_MASK,	/* subphys mask */
+	MV_DDR_CFG_DEFAULT,		/* ddr configuration data source */
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+	/* Return the board topology as defined in the board code */
+	return &board_topology_map;
+}
diff --git a/plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c b/plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c
new file mode 100644
index 0000000..f8a1c40
--- /dev/null
+++ b/plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win *amb_memory_map;
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	*win = amb_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(amb_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#ifndef IMAGE_BLE
+	/* MCI 0 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(0),	0x100000,	MCI_0_TID},
+	/* MCI 1 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(1),	0x100000,	MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+	return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+				  uint32_t *size)
+{
+	*win = io_win_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(io_win_memory_map);
+
+	return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map[] = {
+	/* PEX0_X4 window */
+	{0x00000000f6000000,	0x6000000,	PEX0_TID},
+	{0x00000000c0000000,    0x30000000,     PEX0_TID},
+	{0x0000000800000000,    0x200000000,    PEX0_TID},
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	*win = iob_memory_map;
+	*size = ARRAY_SIZE(iob_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {
+#ifdef IMAGE_BLE
+	{0x00000000f2000000,	0x4000000,	IO_0_TID}, /* IO window */
+#else
+	{0x00000000f2000000,	0xe000000,	IO_0_TID},
+	{0x00000000c0000000,    0x30000000,	IO_0_TID}, /* IO window */
+	{0x0000000800000000,    0x200000000,	IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+	return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+			       uint32_t *size)
+{
+	*win = ccu_memory_map;
+	*size = ARRAY_SIZE(ccu_memory_map);
+
+	return 0;
+}
+
+#ifdef IMAGE_BLE
+
+struct pci_hw_cfg *plat_get_pcie_hw_data(void)
+{
+	return NULL;
+}
+
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+struct skip_image skip_im = {
+	.detection_method = GPIO,
+	.info.gpio.num = 33,
+	.info.gpio.button_state = HIGH,
+	.info.test.cp_ap = CP,
+	.info.test.cp_index = 0,
+};
+
+void *plat_marvell_get_skip_image_data(void)
+{
+	/* Return the skip_image configurations */
+	return &skip_im;
+}
+#endif
+#endif
diff --git a/plat/marvell/a8k/a70x0_amc/mvebu_def.h b/plat/marvell/a8k/a70x0_amc/mvebu_def.h
new file mode 100644
index 0000000..cedf323
--- /dev/null
+++ b/plat/marvell/a8k/a70x0_amc/mvebu_def.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT		1	/* A70x0 has single CP0 */
+
+/***********************************************************************
+ * Required platform porting definitions common to all
+ * Management Compute SubSystems (MSS)
+ ***********************************************************************
+ */
+/*
+ * Load address of SCP_BL2
+ * SCP_BL2 is loaded to the same place as BL31.
+ * Once SCP_BL2 is transferred to the SCP,
+ * it is discarded and BL31 is loaded over the top.
+ */
+#ifdef SCP_IMAGE
+#define SCP_BL2_BASE		BL31_BASE
+#endif
+
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/a8k/a70x0_amc/platform.mk b/plat/marvell/a8k/a70x0_amc/platform.mk
new file mode 100644
index 0000000..d3a0167
--- /dev/null
+++ b/plat/marvell/a8k/a70x0_amc/platform.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT		:= 0
+
+CP_NUM			:= 1
+$(eval $(call add_define,CP_NUM))
+
+DOIMAGE_SEC     	:=	tools/doimage/secure/sec_img_7K.cfg
+
+MARVELL_MOCHI_DRV	:=	drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/a80x0/board/dram_port.c b/plat/marvell/a8k/a80x0/board/dram_port.c
new file mode 100644
index 0000000..02f4ffb
--- /dev/null
+++ b/plat/marvell/a8k/a80x0/board/dram_port.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#define MVEBU_AP_MPP_CTRL0_7_REG		MVEBU_AP_MPP_REGS(0)
+#define MVEBU_AP_MPP_CTRL4_OFFS			16
+#define MVEBU_AP_MPP_CTRL5_OFFS			20
+#define MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA		0x3
+#define MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA		0x3
+
+#define MVEBU_CP_MPP_CTRL37_OFFS		20
+#define MVEBU_CP_MPP_CTRL38_OFFS		24
+#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA	0x2
+#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA	0x2
+
+#define MVEBU_MPP_CTRL_MASK			0xf
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+	/* MISL board with 1CS 8Gb x4 devices of Micron 2400T */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x1, 0x0, 0, 0},	/* FIXME: change the cs mask for all 64 bit */
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0} },
+	   /* TODO: double check if the speed bin is 2400T */
+	   SPEED_BIN_DDR_2400T,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_8GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */
+	MV_DDR_CFG_SPD,			/* ddr configuration data source */
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+	/* Return the board topology as defined in the board code */
+	return &board_topology_map;
+}
+
+static void mpp_config(void)
+{
+	uintptr_t reg;
+	uint32_t val;
+
+	reg = MVEBU_CP_MPP_REGS(0, 4);
+	/* configure CP0 MPP 37 and 38 to i2c */
+	val = mmio_read_32(reg);
+	val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
+		(MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
+	val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA <<
+			MVEBU_CP_MPP_CTRL37_OFFS) |
+		(MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA <<
+			MVEBU_CP_MPP_CTRL38_OFFS);
+	mmio_write_32(reg, val);
+}
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
+
+	INFO("Gathering DRAM information\n");
+
+	if (tm->cfg_src == MV_DDR_CFG_SPD) {
+		/* configure MPPs to enable i2c */
+		mpp_config();
+
+		/* initialize i2c */
+		i2c_init((void *)MVEBU_CP0_I2C_BASE);
+
+		/* select SPD memory page 0 to access DRAM configuration */
+		i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+
+		/* read data from spd */
+		i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+			 sizeof(tm->spd_data.all_bytes));
+	}
+}
diff --git a/plat/marvell/a8k/a80x0/board/marvell_plat_config.c b/plat/marvell/a8k/a80x0/board/marvell_plat_config.c
new file mode 100644
index 0000000..7901dd2
--- /dev/null
+++ b/plat/marvell/a8k/a80x0/board/marvell_plat_config.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+	/* CP1 SPI1 CS0 Direct Mode access */
+	{0xf900,	0x1000000,	AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	*win = amb_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(amb_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+	/* CP1 (MCI0) internal regs */
+	{0x00000000f4000000,		0x2000000,  MCI_0_TID},
+#ifndef IMAGE_BLE
+	/* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
+	{0x00000000f9000000,		0x2000000,  MCI_0_TID},
+	/* PCIe1 on CP1*/
+	{0x00000000fb000000,		0x1000000,  MCI_0_TID},
+	/* PCIe2 on CP1*/
+	{0x00000000fc000000,		0x1000000,  MCI_0_TID},
+	/* MCI 0 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(0),	0x100000,  MCI_0_TID},
+	/* MCI 1 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(1),	0x100000,  MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+	return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+				  uint32_t *size)
+{
+	*win = io_win_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(io_win_memory_map);
+
+	return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map_cp0[] = {
+	/* CP0 */
+	/* PEX1_X1 window */
+	{0x00000000f7000000,	0x1000000,	PEX1_TID},
+	/* PEX2_X1 window */
+	{0x00000000f8000000,	0x1000000,	PEX2_TID},
+	/* PEX0_X4 window */
+	{0x00000000f6000000,	0x1000000,	PEX0_TID},
+	{0x00000000c0000000,	0x30000000,	PEX0_TID},
+	{0x0000000800000000,	0x100000000,	PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp1[] = {
+	/* CP1 */
+	/* SPI1_CS0 (RUNIT) window */
+	{0x00000000f9000000,	0x1000000,	RUNIT_TID},
+	/* PEX1_X1 window */
+	{0x00000000fb000000,	0x1000000,	PEX1_TID},
+	/* PEX2_X1 window */
+	{0x00000000fc000000,	0x1000000,	PEX2_TID},
+	/* PEX0_X4 window */
+	{0x00000000fa000000,	0x1000000,	PEX0_TID}
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	switch (base) {
+	case MVEBU_CP_REGS_BASE(0):
+		*win = iob_memory_map_cp0;
+		*size = ARRAY_SIZE(iob_memory_map_cp0);
+		return 0;
+	case MVEBU_CP_REGS_BASE(1):
+		*win = iob_memory_map_cp1;
+		*size = ARRAY_SIZE(iob_memory_map_cp1);
+		return 0;
+	default:
+		*size = 0;
+		*win = 0;
+		return 1;
+	}
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {
+#ifdef IMAGE_BLE
+	{0x00000000f2000000,	0x4000000,  IO_0_TID}, /* IO window */
+#else
+	{0x00000000f2000000,	0xe000000,  IO_0_TID}, /* IO window */
+	{0x00000000c0000000,	0x30000000,  IO_0_TID}, /* IO window */
+	{0x0000000800000000,	0x100000000,  IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+	return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap, struct addr_map_win **win,
+			       uint32_t *size)
+{
+	*win = ccu_memory_map;
+	*size = ARRAY_SIZE(ccu_memory_map);
+
+	return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * SoC PM configuration
+ *****************************************************************************
+ */
+/* CP GPIO should be used and the GPIOs should be within same GPIO register */
+struct power_off_method pm_cfg = {
+	.type = PMIC_GPIO,
+	.cfg.gpio.pin_count = 1,
+	.cfg.gpio.info = {{0, 35} },
+	.cfg.gpio.step_count = 7,
+	.cfg.gpio.seq = {1, 0, 1, 0, 1, 0, 1},
+	.cfg.gpio.delay_ms = 10,
+};
+
+void *plat_marvell_get_pm_cfg(void)
+{
+	/* Return the PM configurations */
+	return &pm_cfg;
+}
+
+/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
+#else
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+struct skip_image skip_im = {
+	.detection_method = GPIO,
+	.info.gpio.num = 33,
+	.info.gpio.button_state = HIGH,
+	.info.test.cp_ap = CP,
+	.info.test.cp_index = 0,
+};
+
+void *plat_marvell_get_skip_image_data(void)
+{
+	/* Return the skip_image configurations */
+	return &skip_im;
+}
+#endif
+#endif
diff --git a/plat/marvell/a8k/a80x0/board/phy-porting-layer.h b/plat/marvell/a8k/a80x0/board/phy-porting-layer.h
new file mode 100644
index 0000000..abd85b5
--- /dev/null
+++ b/plat/marvell/a8k/a80x0/board/phy-porting-layer.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PHY_PORTING_LAYER_H
+#define PHY_PORTING_LAYER_H
+
+#define MAX_LANE_NR		6
+
+static const struct xfi_params
+	xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	/* AP0 */
+	{
+		/* CP 0 */
+		{
+			{ 0 }, /* Comphy0 */
+			{ 0 }, /* Comphy1 */
+			{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
+			  .align90 = 0x5f,
+			  .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
+			  .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
+			  .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
+			  .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
+			  .valid = 0x1 }, /* Comphy2 */
+			{ 0 }, /* Comphy3 */
+			{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
+			  .align90 = 0x5f,
+			  .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
+			  .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
+			  .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
+			  .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
+			  .valid = 0x1 }, /* Comphy4 */
+			{ 0 }, /* Comphy5 */
+		},
+
+		/* CP 1 */
+		{
+			{ 0 }, /* Comphy0 */
+			{ 0 }, /* Comphy1 */
+			{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
+			  .align90 = 0x5f,
+			  .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
+			  .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
+			  .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
+			  .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
+			  .valid = 0x1 }, /* Comphy2 */
+			{ 0 }, /* Comphy3 */
+			{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf,
+			  .align90 = 0x5f,
+			  .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
+			  .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0,
+			  .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
+			  .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
+			  .valid = 0x1 }, /* Comphy4 */
+			{ 0 }, /* Comphy5 */
+		},
+	},
+};
+
+static const struct sata_params
+	sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	/* AP0 */
+	{
+		/* CP 0 */
+		{
+			{ 0 }, /* Comphy0 */
+			{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+			  .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+			  .g1_emph_en = 0x1, .g2_emph_en = 0x1,
+			  .g3_emph_en = 0x1,
+			  .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
+			  .g3_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
+			  .g3_tx_emph_en = 0x0,
+			  .g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
+			  .g3_tx_emph = 0x1,
+			  .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
+			  .g3_ffe_cap_sel = 0xf,
+			  .align90 = 0x61,
+			  .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
+			  .g3_rx_selmuff = 0x3,
+			  .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
+			  .g3_rx_selmufi = 0x3,
+			  .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
+			  .g3_rx_selmupf = 0x2,
+			  .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
+			  .g3_rx_selmupi = 0x2,
+			  .valid = 0x1
+			}, /* Comphy1 */
+			{ 0 }, /* Comphy2 */
+			{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+			 .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+			 .g1_emph_en = 0x1, .g2_emph_en = 0x1,
+			 .g3_emph_en = 0x1,
+			 .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
+			 .g3_tx_amp_adj = 0x1,
+			 .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
+			 .g3_tx_emph_en = 0x0,
+			 .g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
+			 .g3_tx_emph = 0x1,
+			 .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
+			 .g3_ffe_cap_sel = 0xf,
+			 .align90 = 0x61,
+			 .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
+			 .g3_rx_selmuff = 0x3,
+			 .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
+			 .g3_rx_selmufi = 0x3,
+			 .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
+			 .g3_rx_selmupf = 0x2,
+			 .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
+			 .g3_rx_selmupi = 0x2,
+			 .valid = 0x1
+			}, /* Comphy3 */
+			{ 0 }, /* Comphy4 */
+			{ 0 }, /* Comphy5 */
+		},
+
+		/* CP 1 */
+		{
+			{ 0 }, /* Comphy0 */
+			{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+			  .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+			  .g1_emph_en = 0x1, .g2_emph_en = 0x1,
+			  .g3_emph_en = 0x1,
+			  .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
+			  .g3_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
+			  .g3_tx_emph_en = 0x0,
+			  .g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
+			  .g3_tx_emph = 0x1,
+			  .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
+			  .g3_ffe_cap_sel = 0xf,
+			  .align90 = 0x61,
+			  .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
+			  .g3_rx_selmuff = 0x3,
+			  .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
+			  .g3_rx_selmufi = 0x3,
+			  .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
+			  .g3_rx_selmupf = 0x2,
+			  .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
+			  .g3_rx_selmupi = 0x2,
+			  .valid = 0x1
+			}, /* Comphy1 */
+			{ 0 }, /* Comphy2 */
+			{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+			  .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+			  .g1_emph_en = 0x1, .g2_emph_en = 0x1,
+			  .g3_emph_en = 0x1,
+			  .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
+			  .g3_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
+			  .g3_tx_emph_en = 0x0,
+			  .g1_tx_emph = 0x1, .g2_tx_emph = 0x1,
+			  .g3_tx_emph = 0x1,
+			  .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4,
+			  .g3_ffe_cap_sel = 0xf,
+			  .align90 = 0x61,
+			  .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
+			  .g3_rx_selmuff = 0x3,
+			  .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
+			  .g3_rx_selmufi = 0x3,
+			  .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
+			  .g3_rx_selmupf = 0x2,
+			  .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
+			  .g3_rx_selmupi = 0x2,
+			  .valid = 0x1
+			}, /* Comphy3 */
+			{ 0 }, /* Comphy4 */
+			{ 0 }, /* Comphy5 */
+
+		},
+	},
+};
+#endif /* PHY_PORTING_LAYER_H */
diff --git a/plat/marvell/a8k/a80x0/mvebu_def.h b/plat/marvell/a8k/a80x0/mvebu_def.h
new file mode 100644
index 0000000..3fa119a
--- /dev/null
+++ b/plat/marvell/a8k/a80x0/mvebu_def.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT		2	/* A80x0 has both CP0 & CP1 */
+#define I2C_SPD_ADDR		0x53	/* Access SPD data */
+#define I2C_SPD_P0_ADDR		0x36	/* Select SPD data page 0 */
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/a8k/a80x0/platform.mk b/plat/marvell/a8k/a80x0/platform.mk
new file mode 100644
index 0000000..00d24b2
--- /dev/null
+++ b/plat/marvell/a8k/a80x0/platform.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT		:= 0
+
+CP_NUM			:= 2
+$(eval $(call add_define,CP_NUM))
+
+DOIMAGE_SEC     	:=	tools/doimage/secure/sec_img_8K.cfg
+
+MARVELL_MOCHI_DRV	:=	drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
+PLAT_INCLUDES		+=	-Iplat/marvell/a8k/a80x0/board
diff --git a/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c b/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
new file mode 100644
index 0000000..2580852
--- /dev/null
+++ b/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/mentor/mi2cv.h>
+#include <lib/mmio.h>
+
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+#define MVEBU_CP_MPP_CTRL37_OFFS		20
+#define MVEBU_CP_MPP_CTRL38_OFFS		24
+#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA	0x2
+#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA	0x2
+
+#define MVEBU_MPP_CTRL_MASK			0xf
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+static struct mv_ddr_topology_map board_topology_map = {
+	/* Board with 1CS 8Gb x4 devices of Micron 2400T */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x1, 0x0, 0, 0},	/* FIXME: change the cs mask for all 64 bit */
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0},
+	      {0x1, 0x0, 0, 0} },
+	   /* TODO: double check if the speed bin is 2400T */
+	   SPEED_BIN_DDR_2400T,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_8GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	   MV_DDR_64BIT_BUS_MASK,	/* subphys mask */
+	   MV_DDR_CFG_SPD,		/* ddr configuration data source */
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+	/* Return the board topology as defined in the board code */
+	return &board_topology_map;
+}
+
+static void mpp_config(void)
+{
+	uint32_t val;
+	uintptr_t reg = MVEBU_CP_MPP_REGS(0, 4);
+
+	/* configure CP0 MPP 37 and 38 to i2c */
+	val = mmio_read_32(reg);
+	val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
+		(MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
+	val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA << MVEBU_CP_MPP_CTRL37_OFFS) |
+		(MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA << MVEBU_CP_MPP_CTRL38_OFFS);
+	mmio_write_32(reg, val);
+}
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
+
+	INFO("Gathering DRAM information\n");
+
+	if (tm->cfg_src == MV_DDR_CFG_SPD) {
+		/* configure MPPs to enable i2c */
+		mpp_config();
+		/* initialize the i2c */
+		i2c_init((void *)MVEBU_CP0_I2C_BASE);
+		/* select SPD memory page 0 to access DRAM configuration */
+		i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+		/* read data from spd */
+		i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
+			 sizeof(tm->spd_data.all_bytes));
+	}
+}
diff --git a/plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c b/plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c
new file mode 100644
index 0000000..fa4e144
--- /dev/null
+++ b/plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * GPIO Configuration
+ *****************************************************************************
+ */
+#define MPP_CONTROL_REGISTER		0xf2440018
+#define MPP_CONTROL_MPP_SEL_52_MASK	0xf0000
+#define GPIO_DATA_OUT1_REGISTER		0xf2440140
+#define GPIO_DATA_OUT_EN_CTRL1_REGISTER 0xf2440144
+#define GPIO52_MASK			0x100000
+
+/* Reset PCIe via GPIO number 52 */
+int marvell_gpio_config(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32(MPP_CONTROL_REGISTER);
+	reg |= MPP_CONTROL_MPP_SEL_52_MASK;
+	mmio_write_32(MPP_CONTROL_REGISTER, reg);
+
+	reg = mmio_read_32(GPIO_DATA_OUT1_REGISTER);
+	reg |= GPIO52_MASK;
+	mmio_write_32(GPIO_DATA_OUT1_REGISTER, reg);
+
+	reg = mmio_read_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER);
+	reg &= ~GPIO52_MASK;
+	mmio_write_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER, reg);
+	udelay(100);
+
+	return 0;
+}
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+	/* CP1 SPI1 CS0 Direct Mode access */
+	{0xf900,	0x1000000,	AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	*win = amb_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(amb_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+	/* CP1 (MCI0) internal regs */
+	{0x00000000f4000000,		0x2000000,  MCI_0_TID},
+#ifndef IMAGE_BLE
+	/* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
+	{0x00000000f9000000,		0x2000000,  MCI_0_TID},
+	/* PCIe1 on CP1*/
+	{0x00000000fb000000,		0x1000000,  MCI_0_TID},
+	/* PCIe2 on CP1*/
+	{0x00000000fc000000,		0x1000000,  MCI_0_TID},
+	/* MCI 0 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(0),	0x100000,   MCI_0_TID},
+	/* MCI 1 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(1),	0x100000,   MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+	return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+				  uint32_t *size)
+{
+	*win = io_win_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(io_win_memory_map);
+
+	return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map_cp0[] = {
+	/* CP0 */
+	/* PEX1_X1 window */
+	{0x00000000f7000000,	0x1000000,	PEX1_TID},
+	/* PEX2_X1 window */
+	{0x00000000f8000000,	0x1000000,	PEX2_TID},
+	/* PEX0_X4 window */
+	{0x00000000f6000000,	0x1000000,	PEX0_TID},
+	{0x00000000c0000000,	0x30000000,	PEX0_TID},
+	{0x0000000800000000,	0x100000000,	PEX0_TID},
+};
+
+struct addr_map_win iob_memory_map_cp1[] = {
+	/* CP1 */
+	/* SPI1_CS0 (RUNIT) window */
+	{0x00000000f9000000,	0x1000000,	RUNIT_TID},
+	/* PEX1_X1 window */
+	{0x00000000fb000000,	0x1000000,	PEX1_TID},
+	/* PEX2_X1 window */
+	{0x00000000fc000000,	0x1000000,	PEX2_TID},
+	/* PEX0_X4 window */
+	{0x00000000fa000000,	0x1000000,	PEX0_TID}
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	switch (base) {
+	case MVEBU_CP_REGS_BASE(0):
+		*win = iob_memory_map_cp0;
+		*size = ARRAY_SIZE(iob_memory_map_cp0);
+		return 0;
+	case MVEBU_CP_REGS_BASE(1):
+		*win = iob_memory_map_cp1;
+		*size = ARRAY_SIZE(iob_memory_map_cp1);
+		return 0;
+	default:
+		*size = 0;
+		*win = 0;
+		return 1;
+	}
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {
+#ifdef IMAGE_BLE
+	{0x00000000f2000000,	0x4000000,  IO_0_TID}, /* IO window */
+#else
+	{0x00000000f2000000,	0xe000000,  IO_0_TID}, /* IO window */
+	{0x00000000c0000000,	0x30000000,  IO_0_TID}, /* IO window */
+	{0x0000000800000000,	0x100000000,  IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+	return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+			       uint32_t *size)
+{
+	*win = ccu_memory_map;
+	*size = ARRAY_SIZE(ccu_memory_map);
+
+	return 0;
+}
+
+/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
+
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+void *plat_marvell_get_skip_image_data(void)
+{
+	/* No recovery button on A8k-MCBIN board */
+	return NULL;
+}
diff --git a/plat/marvell/a8k/a80x0_mcbin/mvebu_def.h b/plat/marvell/a8k/a80x0_mcbin/mvebu_def.h
new file mode 100644
index 0000000..3fa119a
--- /dev/null
+++ b/plat/marvell/a8k/a80x0_mcbin/mvebu_def.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT		2	/* A80x0 has both CP0 & CP1 */
+#define I2C_SPD_ADDR		0x53	/* Access SPD data */
+#define I2C_SPD_P0_ADDR		0x36	/* Select SPD data page 0 */
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/a8k/a80x0_mcbin/platform.mk b/plat/marvell/a8k/a80x0_mcbin/platform.mk
new file mode 100644
index 0000000..3749c37
--- /dev/null
+++ b/plat/marvell/a8k/a80x0_mcbin/platform.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT		:= 0
+
+CP_NUM			:= 2
+$(eval $(call add_define,CP_NUM))
+
+DOIMAGE_SEC     	:=	tools/doimage/secure/sec_img_8K.cfg
+
+MARVELL_MOCHI_DRV	:=	drivers/marvell/mochi/apn806_setup.c
+
+include plat/marvell/a8k/common/a8k_common.mk
+
+include plat/marvell/common/marvell_common.mk
diff --git a/plat/marvell/a8k/common/a8k_common.mk b/plat/marvell/a8k/common/a8k_common.mk
new file mode 100644
index 0000000..ccb662b
--- /dev/null
+++ b/plat/marvell/a8k/common/a8k_common.mk
@@ -0,0 +1,119 @@
+#
+# Copyright (C) 2016 - 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+include tools/marvell/doimage/doimage.mk
+
+PLAT_FAMILY		:= a8k
+PLAT_FAMILY_BASE	:= plat/marvell/$(PLAT_FAMILY)
+PLAT_INCLUDE_BASE	:= include/plat/marvell/$(PLAT_FAMILY)
+PLAT_COMMON_BASE	:= $(PLAT_FAMILY_BASE)/common
+MARVELL_DRV_BASE	:= drivers/marvell
+MARVELL_COMMON_BASE	:= plat/marvell/common
+
+MARVELL_SVC_TEST		:= 0
+$(eval $(call add_define,MARVELL_SVC_TEST))
+
+ERRATA_A72_859971	:= 1
+
+# Enable MSS support for a8k family
+MSS_SUPPORT		:= 1
+
+# Disable EL3 cache for power management
+BL31_CACHE_DISABLE	:= 1
+$(eval $(call add_define,BL31_CACHE_DISABLE))
+
+$(eval $(call add_define,PCI_EP_SUPPORT))
+$(eval $(call assert_boolean,PCI_EP_SUPPORT))
+
+AP_NUM			:= 1
+$(eval $(call add_define,AP_NUM))
+
+DOIMAGEPATH		?=	tools/marvell/doimage
+DOIMAGETOOL		?=	${DOIMAGEPATH}/doimage
+
+ROM_BIN_EXT ?= $(BUILD_PLAT)/ble.bin
+DOIMAGE_FLAGS	+= -b $(ROM_BIN_EXT) $(NAND_DOIMAGE_FLAGS) $(DOIMAGE_SEC_FLAGS)
+
+# This define specifies DDR type for BLE
+$(eval $(call add_define,CONFIG_DDR4))
+
+MARVELL_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+PLAT_INCLUDES		:=	-I$(PLAT_FAMILY_BASE)/$(PLAT)		\
+				-I$(PLAT_COMMON_BASE)/include		\
+				-I$(PLAT_INCLUDE_BASE)/common
+
+PLAT_BL_COMMON_SOURCES	:=	$(PLAT_COMMON_BASE)/aarch64/a8k_common.c \
+				drivers/ti/uart/aarch64/16550_console.S
+
+BLE_PORTING_SOURCES	:=	$(PLAT_FAMILY_BASE)/$(PLAT)/board/dram_port.c \
+				$(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
+
+MARVELL_MOCHI_DRV	+=	$(MARVELL_DRV_BASE)/mochi/cp110_setup.c
+
+BLE_SOURCES		:=	drivers/mentor/i2c/mi2cv.c		\
+				$(PLAT_COMMON_BASE)/plat_ble_setup.c	\
+				$(MARVELL_MOCHI_DRV)			\
+				$(PLAT_COMMON_BASE)/plat_pm.c		\
+				$(MARVELL_DRV_BASE)/ap807_clocks_init.c	\
+				$(MARVELL_DRV_BASE)/thermal.c		\
+				$(PLAT_COMMON_BASE)/plat_thermal.c	\
+				$(BLE_PORTING_SOURCES)			\
+				$(MARVELL_DRV_BASE)/ccu.c		\
+				$(MARVELL_DRV_BASE)/io_win.c
+
+BL1_SOURCES		+=	$(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \
+				lib/cpus/aarch64/cortex_a72.S
+
+MARVELL_DRV		:= 	$(MARVELL_DRV_BASE)/io_win.c	\
+				$(MARVELL_DRV_BASE)/iob.c	\
+				$(MARVELL_DRV_BASE)/mci.c	\
+				$(MARVELL_DRV_BASE)/amb_adec.c	\
+				$(MARVELL_DRV_BASE)/ccu.c	\
+				$(MARVELL_DRV_BASE)/cache_llc.c	\
+				$(MARVELL_DRV_BASE)/comphy/phy-comphy-cp110.c \
+				$(MARVELL_DRV_BASE)/mc_trustzone/mc_trustzone.c
+
+BL31_PORTING_SOURCES	:=	$(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a72.S		       \
+				$(PLAT_COMMON_BASE)/aarch64/plat_helpers.S     \
+				$(PLAT_COMMON_BASE)/aarch64/plat_arch_config.c \
+				$(PLAT_COMMON_BASE)/plat_pm.c		       \
+				$(PLAT_COMMON_BASE)/plat_bl31_setup.c	       \
+				$(MARVELL_COMMON_BASE)/marvell_gicv2.c	       \
+				$(MARVELL_COMMON_BASE)/mrvl_sip_svc.c	       \
+				$(MARVELL_COMMON_BASE)/marvell_ddr_info.c      \
+				$(BL31_PORTING_SOURCES)			       \
+				$(MARVELL_DRV)				       \
+				$(MARVELL_MOCHI_DRV)			       \
+				$(MARVELL_GIC_SOURCES)
+
+# Add trace functionality for PM
+BL31_SOURCES		+=	$(PLAT_COMMON_BASE)/plat_pm_trace.c
+
+# Force builds with BL2 image on a80x0 platforms
+ifndef SCP_BL2
+ $(error "Error: SCP_BL2 image is mandatory for a8k family")
+endif
+
+# MSS (SCP) build
+include $(PLAT_COMMON_BASE)/mss/mss_a8k.mk
+
+# BLE (ROM context execution code, AKA binary extension)
+BLE_PATH	?=  $(PLAT_COMMON_BASE)/ble
+
+include ${BLE_PATH}/ble.mk
+$(eval $(call MAKE_BL,e))
+
+mrvl_flash: ${BUILD_PLAT}/${FIP_NAME} ${DOIMAGETOOL} ${BUILD_PLAT}/ble.bin
+	$(shell truncate -s %128K ${BUILD_PLAT}/bl1.bin)
+	$(shell cat ${BUILD_PLAT}/bl1.bin ${BUILD_PLAT}/${FIP_NAME} > ${BUILD_PLAT}/${BOOT_IMAGE})
+	${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE}
+
diff --git a/plat/marvell/a8k/common/aarch64/a8k_common.c b/plat/marvell/a8k/common/aarch64/a8k_common.c
new file mode 100644
index 0000000..7c2bf31
--- /dev/null
+++ b/plat/marvell/a8k/common/aarch64/a8k_common.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+
+/* MMU entry for internal (register) space access */
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ */
+#if IMAGE_BL1
+const mmap_region_t plat_marvell_mmap[] = {
+	MARVELL_MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+#if IMAGE_BL2
+const mmap_region_t plat_marvell_mmap[] = {
+	MARVELL_MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MARVELL_MAP_DRAM,
+	{0}
+};
+#endif
+
+#if IMAGE_BL2U
+const mmap_region_t plat_marvell_mmap[] = {
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+
+#if IMAGE_BLE
+const mmap_region_t plat_marvell_mmap[] = {
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+
+#if IMAGE_BL31
+const mmap_region_t plat_marvell_mmap[] = {
+	MARVELL_MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MARVELL_MAP_DRAM,
+	{0}
+};
+#endif
+#if IMAGE_BL32
+const mmap_region_t plat_marvell_mmap[] = {
+	MAP_DEVICE0,
+	{0}
+};
+#endif
+
+MARVELL_CASSERT_MMAP;
diff --git a/plat/marvell/a8k/common/aarch64/plat_arch_config.c b/plat/marvell/a8k/common/aarch64/plat_arch_config.c
new file mode 100644
index 0000000..06dc841
--- /dev/null
+++ b/plat/marvell/a8k/common/aarch64/plat_arch_config.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/marvell/cache_llc.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#define CCU_HTC_ASET			(MVEBU_CCU_BASE(MVEBU_AP0) + 0x264)
+#define MVEBU_IO_AFFINITY		(0xF00)
+
+
+static void plat_enable_affinity(void)
+{
+	int cluster_id;
+	int affinity;
+
+	/* set CPU Affinity */
+	cluster_id = plat_my_core_pos() / PLAT_MARVELL_CLUSTER_CORE_COUNT;
+	affinity = (MVEBU_IO_AFFINITY | (1 << cluster_id));
+	mmio_write_32(CCU_HTC_ASET, affinity);
+
+	/* set barier */
+	isb();
+}
+
+void marvell_psci_arch_init(int die_index)
+{
+#if LLC_ENABLE
+	/* check if LLC is in exclusive mode
+	 * as L2 is configured to UniqueClean eviction
+	 * (in a8k reset handler)
+	 */
+	if (llc_is_exclusive(0) == 0)
+		ERROR("LLC should be configured to exclusice mode\n");
+#endif
+
+	/* Enable Affinity */
+	plat_enable_affinity();
+}
diff --git a/plat/marvell/a8k/common/aarch64/plat_helpers.S b/plat/marvell/a8k/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..fadc4c2
--- /dev/null
+++ b/plat/marvell/a8k/common/aarch64/plat_helpers.S
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <marvell_pm.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+	.globl  plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset. Right
+	 * now this is a stub function.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	mov	x0, #0
+	ret
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish
+	 * between a cold and warm boot
+	 * For a cold boot, return 0.
+	 * For a warm boot, read the mailbox and return the address it contains.
+	 *
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* Read first word and compare it with magic num */
+	mov_imm x0, PLAT_MARVELL_MAILBOX_BASE
+	ldr     x1, [x0]
+	mov_imm x2, MVEBU_MAILBOX_MAGIC_NUM
+	cmp     x1, x2
+	beq     warm_boot  /* If compare failed, return 0, i.e. cold boot */
+	mov     x0, #0
+	ret
+warm_boot:
+	mov_imm x1, MBOX_IDX_SEC_ADDR		/* Get the jump address */
+	subs	x1, x1, #1
+	mov	x2, #(MBOX_IDX_SEC_ADDR * 8)
+	lsl	x3, x2, x1
+	add     x0, x0, x3
+	ldr     x0, [x0]
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #MVEBU_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+        /* -----------------------------------------------------
+	 * void plat_reset_handler (void);
+         *
+	 * Platform specific configuration right after cpu is
+	 * is our of reset.
+	 *
+         * The plat_reset_handler can clobber x0 - x18, x30.
+         * -----------------------------------------------------
+         */
+func plat_reset_handler
+	/*
+	 * Note: the configurations below  should be done before MMU,
+	 *	  I Cache and L2are enabled.
+	 *	  The reset handler is executed right after reset
+	 * 	  and before Caches are enabled.
+	 */
+
+	/* Enable L1/L2 ECC and Parity */
+	mrs x5, s3_1_c11_c0_2  /* L2 Ctrl */
+	orr x5, x5, #(1 << 21) /* Enable L1/L2 cache ECC & Parity */
+	msr s3_1_c11_c0_2, x5  /* L2 Ctrl */
+
+#if LLC_ENABLE
+	/*
+	 * Enable L2 UniqueClean evictions
+	 *  Note: this configuration assumes that LLC is configured
+	 *	  in exclusive mode.
+	 *	  Later on in the code this assumption will be validated
+	 */
+	mrs x5, s3_1_c15_c0_0  /* L2 Ctrl */
+	orr x5, x5, #(1 << 14) /* Enable UniqueClean evictions with data */
+	msr s3_1_c15_c0_0, x5  /* L2 Ctrl */
+#endif
+
+	/* Instruction Barrier to allow msr command completion */
+	isb
+
+        ret
+endfunc plat_reset_handler
diff --git a/plat/marvell/a8k/common/ble/ble.ld.S b/plat/marvell/a8k/common/ble/ble.ld.S
new file mode 100644
index 0000000..d7a0592
--- /dev/null
+++ b/plat/marvell/a8k/common/ble/ble.ld.S
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(ble_main)
+
+MEMORY {
+    RAM (rwx): ORIGIN = BLE_BASE, LENGTH = BLE_LIMIT - BLE_BASE
+}
+
+SECTIONS
+{
+    . = BLE_BASE;
+
+    ro . : {
+        __RO_START__ = .;
+        *ble_main.o(.entry*)
+        *(.text*)
+        *(.rodata*)
+        __RO_END_UNALIGNED__ = .;
+        __RO_END__ = .;
+    } >RAM
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+    stacks . (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    .bss : {
+        __BSS_START__ = .;
+        *(.bss*)
+        __BSS_END__ = .;
+    } >RAM
+
+   /*
+    * Extend the BLE binary to the maximum size allocated for it in platform
+    * definition files and prevent overlapping between BLE BSS section and
+    * additional extensions that can follow the BLE in flash image preamble.
+    * This situation happens for instance when secure extension is added to
+    * the image preamble.
+    */
+   .fill LOADADDR(.bss) + SIZEOF(.bss) : {
+       FILL(0xDEADC0DE);
+       . = ORIGIN(RAM) + LENGTH(RAM) - 1;
+       BYTE(0x00)
+   } >RAM
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __RW_END__ = .;
+    __BLE_END__ = .;
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+}
diff --git a/plat/marvell/a8k/common/ble/ble.mk b/plat/marvell/a8k/common/ble/ble.mk
new file mode 100644
index 0000000..b24083f
--- /dev/null
+++ b/plat/marvell/a8k/common/ble/ble.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+MV_DDR_PATH		?=	drivers/marvell/mv_ddr
+
+MV_DDR_LIB		= 	$(CURDIR)/$(BUILD_PLAT)/ble/mv_ddr_lib.a
+LIBC_LIB		=	$(CURDIR)/$(BUILD_PLAT)/lib/libc.a
+BLE_LIBS		= 	$(MV_DDR_LIB) $(LIBC_LIB)
+PLAT_MARVELL		=	plat/marvell
+
+BLE_SOURCES		+= 	$(BLE_PATH)/ble_main.c				\
+				$(BLE_PATH)/ble_mem.S				\
+				drivers/delay_timer/delay_timer.c		\
+				$(PLAT_MARVELL)/common/aarch64/marvell_helpers.S \
+				$(PLAT_MARVELL)/common/plat_delay_timer.c	\
+				$(PLAT_MARVELL)/common/marvell_console.c
+
+PLAT_INCLUDES		+= 	-I$(MV_DDR_PATH)				\
+				-I$(CURDIR)/include				\
+				-I$(CURDIR)/include/lib/libc			\
+				-I$(CURDIR)/include/lib/libc/aarch64		\
+				-I$(CURDIR)/drivers/marvell
+
+BLE_LINKERFILE		:=	$(BLE_PATH)/ble.ld.S
+
+FORCE:
+
+$(MV_DDR_LIB): FORCE
+	@+make -C $(MV_DDR_PATH) --no-print-directory PLAT_INCLUDES="$(PLAT_INCLUDES)" PLATFORM=$(PLAT) ARCH=AARCH64 OBJ_DIR=$(CURDIR)/$(BUILD_PLAT)/ble
diff --git a/plat/marvell/a8k/common/ble/ble_main.c b/plat/marvell/a8k/common/ble/ble_main.c
new file mode 100644
index 0000000..5b3acec
--- /dev/null
+++ b/plat/marvell/a8k/common/ble/ble_main.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+
+#include <marvell_plat_priv.h>
+#include <marvell_pm.h>
+#include <plat_marvell.h>
+
+#define BR_FLAG_SILENT		0x1
+#define SKIP_IMAGE_CODE		0xDEADB002
+
+void mailbox_clean(void)
+{
+	uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+	memset(mailbox, 0, PLAT_MARVELL_MAILBOX_SIZE);
+}
+
+int exec_ble_main(int bootrom_flags)
+{
+	int skip = 0;
+	uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+	/*
+	 * In some situations, like boot from UART, bootrom will
+	 * request to avoid printing to console. in that case don't
+	 * initialize the console and prints will be ignored
+	 */
+	if ((bootrom_flags & BR_FLAG_SILENT) == 0)
+		marvell_console_boot_init();
+
+	NOTICE("Starting binary extension\n");
+
+	/* initialize time (for delay functionality) */
+	plat_delay_timer_init();
+
+	ble_plat_setup(&skip);
+
+	/* if there's skip image request, bootrom will load from the image
+	 * saved on the next address of the flash
+	 */
+	if (skip)
+		return SKIP_IMAGE_CODE;
+
+	/*
+	 * Check if the mailbox magic number is stored at index MBOX_IDX_MAGIC
+	 * and the suspend to RAM magic number at index MBOX_IDX_SUSPEND_MAGIC.
+	 * If the above is true, this is the recovery from suspend to RAM state.
+	 * In such case the mailbox should remain intact, since it stores the
+	 * warm boot jump address to be used by the TF-A in BL31.
+	 * Othervise the mailbox should be cleaned from a garbage data.
+	 */
+	if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
+	    mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE) {
+		NOTICE("Cold boot\n");
+		mailbox_clean();
+	} else {
+		void (*bootrom_exit)(void) =
+			(void (*)(void))mailbox[MBOX_IDX_ROM_EXIT_ADDR];
+
+		INFO("Recovery...\n");
+		/*
+		 * If this is recovery from suspend, two things has to be done:
+		 * 1. Define the DRAM region as executable memory for preparing
+		 *    jump to TF-A
+		 * 2. Instead of returning control to the BootROM, invalidate
+		 *    and flush caches, and continue execution at address stored
+		 *    in the mailbox.
+		 * This should be done until the BootROM have a native support
+		 * for the system restore flow.
+		 */
+		marvell_ble_prepare_exit();
+		bootrom_exit();
+	}
+
+	return 0;
+}
+
+/* NOTE: don't notify this function, all code must be added to exec_ble_main
+ * in order to keep the end of ble_main as a fixed address.
+ */
+int  __attribute__ ((section(".entry"))) ble_main(int bootrom_flags)
+{
+	volatile int ret;
+
+	ret = exec_ble_main(bootrom_flags);
+	return ret;
+}
diff --git a/plat/marvell/a8k/common/ble/ble_mem.S b/plat/marvell/a8k/common/ble/ble_mem.S
new file mode 100644
index 0000000..a48d546
--- /dev/null
+++ b/plat/marvell/a8k/common/ble/ble_mem.S
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <marvell_def.h>
+#include <platform_def.h>
+
+#define PTE_NON_EXEC_OFF	54	/* XN - eXecute Never bit offset - see VMSAv8-64 */
+
+	.globl marvell_ble_prepare_exit
+
+func marvell_ble_prepare_exit
+	/*
+	 * Read the page table base and set the first page to be executable.
+	 * This is required for jumping to DRAM for further execution.
+	 */
+	mrs	x0, ttbr0_el3
+	ldr     x1, [x0]
+	mov	x2, #1
+	bic	x1, x1, x2, lsl #PTE_NON_EXEC_OFF
+	str	x1, [x0]
+	tlbi	alle3
+	dsb	sy
+	isb
+	ret
+endfunc marvell_ble_prepare_exit
diff --git a/plat/marvell/a8k/common/include/a8k_plat_def.h b/plat/marvell/a8k/common/include/a8k_plat_def.h
new file mode 100644
index 0000000..de80315
--- /dev/null
+++ b/plat/marvell/a8k/common/include/a8k_plat_def.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef A8K_PLAT_DEF_H
+#define A8K_PLAT_DEF_H
+
+#include <marvell_def.h>
+
+#define MVEBU_PRIMARY_CPU		0x0
+#define MVEBU_AP0			0x0
+
+/* APN806 revision ID */
+#define MVEBU_CSS_GWD_CTRL_IIDR2_REG	(MVEBU_REGS_BASE + 0x610FCC)
+#define GWD_IIDR2_REV_ID_OFFSET		12
+#define GWD_IIDR2_REV_ID_MASK		0xF
+#define GWD_IIDR2_CHIP_ID_OFFSET	20
+#define GWD_IIDR2_CHIP_ID_MASK		(0xFFFu << GWD_IIDR2_CHIP_ID_OFFSET)
+
+#define CHIP_ID_AP806			0x806
+#define CHIP_ID_AP807			0x807
+
+#define COUNTER_FREQUENCY		25000000
+
+#define MVEBU_REGS_BASE			0xF0000000
+#define MVEBU_REGS_BASE_MASK		0xF0000000
+#define MVEBU_REGS_BASE_AP(ap)		MVEBU_REGS_BASE
+#define MVEBU_AP_IO_BASE(ap)		0xF2000000
+#define MVEBU_CP_OFFSET			0x2000000
+#define MVEBU_CP_REGS_BASE(cp_index)	(MVEBU_AP_IO_BASE(0) + \
+						(cp_index) * MVEBU_CP_OFFSET)
+#define MVEBU_RFU_BASE			(MVEBU_REGS_BASE + 0x6F0000)
+#define MVEBU_IO_WIN_BASE(ap_index)	(MVEBU_RFU_BASE)
+#define MVEBU_IO_WIN_GCR_OFFSET		(0x70)
+#define MVEBU_IO_WIN_MAX_WINS		(7)
+
+/* Misc SoC configurations Base */
+#define MVEBU_MISC_SOC_BASE		(MVEBU_REGS_BASE + 0x6F4300)
+
+#define MVEBU_CCU_BASE(ap_index)	(MVEBU_REGS_BASE + 0x4000)
+#define MVEBU_CCU_MAX_WINS		(8)
+
+#define MVEBU_LLC_BASE(ap_index)	(MVEBU_REGS_BASE + 0x8000)
+#define MVEBU_DRAM_MAC_BASE		(MVEBU_REGS_BASE + 0x20000)
+#define MVEBU_DRAM_PHY_BASE		(MVEBU_REGS_BASE + 0x20000)
+#define MVEBU_SMMU_BASE			(MVEBU_REGS_BASE + 0x100000)
+#define MVEBU_CP_MPP_REGS(cp_index, n)	(MVEBU_CP_REGS_BASE(cp_index) + \
+						0x440000 + ((n) << 2))
+#define MVEBU_PM_MPP_REGS(cp_index, n)	(MVEBU_CP_REGS_BASE(cp_index) + \
+						0x440000 + ((n / 8) << 2))
+#define MVEBU_CP_GPIO_DATA_OUT(cp_index, n) \
+					(MVEBU_CP_REGS_BASE(cp_index) + \
+					0x440100 + ((n > 31) ? 0x40 : 0x00))
+#define MVEBU_CP_GPIO_DATA_OUT_EN(cp_index, n) \
+					(MVEBU_CP_REGS_BASE(cp_index) + \
+					0x440104 + ((n > 31) ? 0x40 : 0x00))
+#define MVEBU_CP_GPIO_DATA_IN(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
+					0x440110 + ((n > 31) ? 0x40 : 0x00))
+#define MVEBU_AP_MPP_REGS(n)		(MVEBU_RFU_BASE + 0x4000 + ((n) << 2))
+#define MVEBU_AP_GPIO_REGS		(MVEBU_RFU_BASE + 0x5040)
+#define MVEBU_AP_GPIO_DATA_IN		(MVEBU_AP_GPIO_REGS + 0x10)
+#define MVEBU_AP_I2C_BASE		(MVEBU_REGS_BASE + 0x511000)
+#define MVEBU_CP0_I2C_BASE		(MVEBU_CP_REGS_BASE(0) + 0x701000)
+#define MVEBU_AP_EXT_TSEN_BASE		(MVEBU_RFU_BASE + 0x8084)
+
+#define MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap, win)	(MVEBU_REGS_BASE_AP(ap) + \
+							0x20080 + ((win) * 0x8))
+#define MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap, win)	(MVEBU_REGS_BASE_AP(ap) + \
+							0x20084 + ((win) * 0x8))
+
+/* MCI indirect access definitions */
+#define MCI_MAX_UNIT_ID				2
+/* SoC RFU / IHBx4 Control */
+#define MCIX4_REG_START_ADDRESS_REG(unit_id)	(MVEBU_RFU_BASE + \
+						0x4218 + (unit_id * 0x20))
+#define MCI_REMAP_OFF_SHIFT			8
+
+#define MVEBU_MCI_REG_BASE_REMAP(index)		(0xFD000000 + \
+						((index) * 0x1000000))
+
+#define MVEBU_PCIE_X4_MAC_BASE(x)	(MVEBU_CP_REGS_BASE(x) + 0x600000)
+#define MVEBU_COMPHY_BASE(x)		(MVEBU_CP_REGS_BASE(x) + 0x441000)
+#define MVEBU_HPIPE_BASE(x)		(MVEBU_CP_REGS_BASE(x) + 0x120000)
+#define MVEBU_CP_DFX_OFFSET		(0x400200)
+
+/*****************************************************************************
+ * MVEBU memory map related constants
+ *****************************************************************************
+ */
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE			MVEBU_REGS_BASE
+#define DEVICE0_SIZE			0x10000000
+
+/*****************************************************************************
+ * GIC-400 & interrupt handling related constants
+ *****************************************************************************
+ */
+/* Base MVEBU compatible GIC memory map */
+#define MVEBU_GICD_BASE			0x210000
+#define MVEBU_GICC_BASE			0x220000
+
+
+/*****************************************************************************
+ * AXI Configuration
+ *****************************************************************************
+ */
+#define MVEBU_AXI_ATTR_ARCACHE_OFFSET		4
+#define MVEBU_AXI_ATTR_ARCACHE_MASK		(0xF << \
+						 MVEBU_AXI_ATTR_ARCACHE_OFFSET)
+#define MVEBU_AXI_ATTR_ARDOMAIN_OFFSET		12
+#define MVEBU_AXI_ATTR_ARDOMAIN_MASK		(0x3 << \
+						 MVEBU_AXI_ATTR_ARDOMAIN_OFFSET)
+#define MVEBU_AXI_ATTR_AWCACHE_OFFSET		20
+#define MVEBU_AXI_ATTR_AWCACHE_MASK		(0xF << \
+						 MVEBU_AXI_ATTR_AWCACHE_OFFSET)
+#define MVEBU_AXI_ATTR_AWDOMAIN_OFFSET		28
+#define MVEBU_AXI_ATTR_AWDOMAIN_MASK		(0x3 << \
+						 MVEBU_AXI_ATTR_AWDOMAIN_OFFSET)
+
+/* SATA MBUS to AXI configuration */
+#define MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET	1
+#define MVEBU_SATA_M2A_AXI_ARCACHE_MASK		(0xF << \
+					MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET)
+#define MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET	5
+#define MVEBU_SATA_M2A_AXI_AWCACHE_MASK		(0xF << \
+					MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET)
+
+/* ARM cache attributes */
+#define CACHE_ATTR_BUFFERABLE			0x1
+#define CACHE_ATTR_CACHEABLE			0x2
+#define CACHE_ATTR_READ_ALLOC			0x4
+#define CACHE_ATTR_WRITE_ALLOC			0x8
+/* Domain */
+#define DOMAIN_NON_SHAREABLE			0x0
+#define DOMAIN_INNER_SHAREABLE			0x1
+#define DOMAIN_OUTER_SHAREABLE			0x2
+#define DOMAIN_SYSTEM_SHAREABLE			0x3
+
+/************************************************************************
+ * Required platform porting definitions common to all
+ * Management Compute SubSystems (MSS)
+ ************************************************************************
+ */
+/*
+ * Load address of SCP_BL2
+ * SCP_BL2 is loaded to the same place as BL31.
+ * Once SCP_BL2 is transferred to the SCP,
+ * it is discarded and BL31 is loaded over the top.
+ */
+#ifdef SCP_IMAGE
+#define SCP_BL2_BASE			BL31_BASE
+#define SCP_BL2_SIZE			BL31_LIMIT
+#endif
+
+#ifndef __ASSEMBLER__
+enum ap806_sar_target_dev {
+	SAR_PIDI_MCIX2		= 0x0,
+	SAR_MCIX4		= 0x1,
+	SAR_SPI			= 0x2,
+	SAR_SD			= 0x3,
+	SAR_PIDI_MCIX2_BD	= 0x4, /* BootRom disabled */
+	SAR_MCIX4_DB		= 0x5, /* BootRom disabled */
+	SAR_SPI_DB		= 0x6, /* BootRom disabled */
+	SAR_EMMC		= 0x7
+};
+
+enum io_win_target_ids {
+	MCI_0_TID	 = 0x0,
+	MCI_1_TID	 = 0x1,
+	MCI_2_TID	 = 0x2,
+	PIDI_TID	 = 0x3,
+	SPI_TID		 = 0x4,
+	STM_TID		 = 0x5,
+	BOOTROM_TID	 = 0x6,
+	IO_WIN_MAX_TID
+};
+
+enum ccu_target_ids {
+	IO_0_TID        = 0x00,
+	DRAM_0_TID      = 0x03,
+	IO_1_TID        = 0x0F,
+	CFG_REG_TID     = 0x10,
+	RAR_TID         = 0x20,
+	SRAM_TID        = 0x40,
+	DRAM_1_TID      = 0xC0,
+	CCU_MAX_TID,
+	INVALID_TID     = 0xFF
+};
+#endif /* __ASSEMBLER__ */
+
+#endif /* A8K_PLAT_DEF_H */
diff --git a/plat/marvell/a8k/common/include/ddr_info.h b/plat/marvell/a8k/common/include/ddr_info.h
new file mode 100644
index 0000000..e19036a
--- /dev/null
+++ b/plat/marvell/a8k/common/include/ddr_info.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#define DRAM_MAX_IFACE			1
+#define DRAM_CH0_MMAP_LOW_OFFSET	0x20200
diff --git a/plat/marvell/a8k/common/include/mentor_i2c_plat.h b/plat/marvell/a8k/common/include/mentor_i2c_plat.h
new file mode 100644
index 0000000..e03c448
--- /dev/null
+++ b/plat/marvell/a8k/common/include/mentor_i2c_plat.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+/* This driver provides I2C support for Marvell A8K and compatible SoCs */
+
+#ifndef MENTOR_I2C_PLAT_H
+#define MENTOR_I2C_PLAT_H
+
+#define CONFIG_SYS_TCLK			250000000
+#define CONFIG_SYS_I2C_SPEED		100000
+#define CONFIG_SYS_I2C_SLAVE		0x0
+
+#define I2C_CAN_UNSTUCK
+
+struct  mentor_i2c_regs {
+	uint32_t slave_address;
+	uint32_t data;
+	uint32_t control;
+	union {
+		uint32_t status;	/* when reading */
+		uint32_t baudrate;	/* when writing */
+	};
+	uint32_t xtnd_slave_addr;
+	uint32_t reserved[2];
+	uint32_t soft_reset;
+	uint8_t  reserved2[0xa0 - 0x20];
+	uint32_t unstuck;
+};
+
+#endif /* MENTOR_I2C_PLAT_H */
diff --git a/plat/marvell/a8k/common/include/plat_macros.S b/plat/marvell/a8k/common/include/plat_macros.S
new file mode 100644
index 0000000..8faccf0
--- /dev/null
+++ b/plat/marvell/a8k/common/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <marvell_macros.S>
+
+/*
+ * Required platform porting macros
+ * (Provided by included headers)
+ */
+.macro plat_crash_print_regs
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/marvell/a8k/common/include/platform_def.h b/plat/marvell/a8k/common/include/platform_def.h
new file mode 100644
index 0000000..b9c2e0e
--- /dev/null
+++ b/plat/marvell/a8k/common/include/platform_def.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#ifndef __ASSEMBLER__
+#include <stdio.h>
+#endif /* __ASSEMBLER__ */
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+
+#include <board_marvell_def.h>
+#include <mvebu_def.h>
+
+/*
+ * Most platform porting definitions provided by included headers
+ */
+
+/*
+ * DRAM Memory layout:
+ *		+-----------------------+
+ *		:			:
+ *		:	Linux		:
+ * 0x04X00000-->+-----------------------+
+ *		|	BL3-3(u-boot)	|>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ *		|-----------------------|  }				       |
+ *		|	BL3-[0,1, 2]	|  }---------------------------------> |
+ *		|-----------------------|  }				||     |
+ *		|	BL2		|  }->FIP (loaded by            ||     |
+ *		|-----------------------|  }       BootROM to DRAM)     ||     |
+ *		|	FIP_TOC		|  }                            ||     |
+ * 0x04120000-->|-----------------------|				||     |
+ *		|	BL1 (RO)	|				||     |
+ * 0x04100000-->+-----------------------+				||     |
+ *		:			:				||     |
+ *		: Trusted SRAM section	:				\/     |
+ * 0x04040000-->+-----------------------+  Replaced by BL2  +----------------+ |
+ *		|	BL1 (RW)	|  <<<<<<<<<<<<<<<< | BL3-1 NOBITS   | |
+ * 0x04037000-->|-----------------------|  <<<<<<<<<<<<<<<< |----------------| |
+ *		|			|  <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | |
+ * 0x04023000-->|-----------------------|		    +----------------+ |
+ *		|	BL2		|				       |
+ *		|-----------------------|				       |
+ *		|			|				       |
+ * 0x04001000-->|-----------------------|				       |
+ *		|	Shared		|				       |
+ * 0x04000000-->+-----------------------+				       |
+ *		:			:				       |
+ *		:	Linux		:				       |
+ *		:			:				       |
+ *		|-----------------------|				       |
+ *		|			|	U-Boot(BL3-3) Loaded by BL2    |
+ *		|	U-Boot		|	<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ * 0x00000000-->+-----------------------+
+ *
+ * Trusted SRAM section 0x4000000..0x4200000:
+ * ----------------------------------------
+ * SRAM_BASE		= 0x4001000
+ * BL2_BASE			= 0x4006000
+ * BL2_LIMIT		= BL31_BASE
+ * BL31_BASE		= 0x4023000 = (64MB + 256KB - 0x1D000)
+ * BL31_PROGBITS_LIMIT	= BL1_RW_BASE
+ * BL1_RW_BASE		= 0x4037000 = (64MB + 256KB - 0x9000)
+ * BL1_RW_LIMIT		= BL31_LIMIT = 0x4040000
+ *
+ *
+ * PLAT_MARVELL_FIP_BASE	= 0x4120000
+ */
+
+#define PLAT_MARVELL_SRAM_BASE			0xFFE1C048
+#define PLAT_MARVELL_SRAM_END			0xFFE78000
+
+#define PLAT_MARVELL_ATF_BASE			0x4000000
+#define PLAT_MARVELL_ATF_LOAD_ADDR		(PLAT_MARVELL_ATF_BASE + \
+								0x100000)
+
+#define PLAT_MARVELL_FIP_BASE			(PLAT_MARVELL_ATF_LOAD_ADDR + \
+								0x20000)
+#define PLAT_MARVELL_FIP_MAX_SIZE		0x4000000
+
+#define PLAT_MARVELL_NORTHB_COUNT		1
+
+#define PLAT_MARVELL_CLUSTER_COUNT		2
+#define PLAT_MARVELL_CLUSTER_CORE_COUNT		2
+
+#define PLAT_MARVELL_CORE_COUNT			(PLAT_MARVELL_CLUSTER_COUNT * \
+						PLAT_MARVELL_CLUSTER_CORE_COUNT)
+
+/* DRAM[2MB..66MB] is used as Trusted ROM */
+#define PLAT_MARVELL_TRUSTED_ROM_BASE		PLAT_MARVELL_ATF_LOAD_ADDR
+/* 64 MB TODO: reduce this to minimum needed according to fip image size */
+#define PLAT_MARVELL_TRUSTED_ROM_SIZE		0x04000000
+/* Reserve 16M for SCP (Secure PayLoad) Trusted DRAM */
+#define PLAT_MARVELL_TRUSTED_DRAM_BASE		0x04400000
+#define PLAT_MARVELL_TRUSTED_DRAM_SIZE		0x01000000	/* 16 MB */
+
+/*
+ * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
+ * plus a little space for growth.
+ */
+#define PLAT_MARVELL_MAX_BL1_RW_SIZE		0xA000
+
+/*
+ * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
+ * little space for growth.
+ */
+#define PLAT_MARVELL_MAX_BL2_SIZE		0xF000
+
+/*
+ * PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#define PLAT_MARVEL_MAX_BL31_SIZE		0x5D000
+
+#define PLAT_MARVELL_CPU_ENTRY_ADDR		BL1_RO_BASE
+
+/* GIC related definitions */
+#define PLAT_MARVELL_GICD_BASE		(MVEBU_REGS_BASE + MVEBU_GICD_BASE)
+#define PLAT_MARVELL_GICC_BASE		(MVEBU_REGS_BASE + MVEBU_GICC_BASE)
+
+#define PLAT_MARVELL_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_PIC0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
+			grp, GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_MARVELL_SHARED_RAM_CACHED		1
+
+/*
+ * Load address of BL3-3 for this platform port
+ */
+#define PLAT_MARVELL_NS_IMAGE_OFFSET		0x0
+
+/* System Reference Clock*/
+#define PLAT_REF_CLK_IN_HZ			COUNTER_FREQUENCY
+
+/*
+ * PL011 related constants
+ */
+#define PLAT_MARVELL_BOOT_UART_BASE		(MVEBU_REGS_BASE + 0x512000)
+#define PLAT_MARVELL_BOOT_UART_CLK_IN_HZ	200000000
+
+#define PLAT_MARVELL_CRASH_UART_BASE		PLAT_MARVELL_BOOT_UART_BASE
+#define PLAT_MARVELL_CRASH_UART_CLK_IN_HZ	PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
+
+#define PLAT_MARVELL_BL31_RUN_UART_BASE		PLAT_MARVELL_BOOT_UART_BASE
+#define PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ	PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
+
+/* Recovery image enable */
+#define PLAT_RECOVERY_IMAGE_ENABLE		0
+
+/* Required platform porting definitions */
+#define PLAT_MAX_PWR_LVL			MPIDR_AFFLVL1
+
+/* System timer related constants */
+#define PLAT_MARVELL_NSTIMER_FRAME_ID		1
+
+/* Mailbox base address (note the lower memory space
+ * is reserved for BLE data)
+ */
+#define PLAT_MARVELL_MAILBOX_BASE		(MARVELL_TRUSTED_SRAM_BASE \
+							+ 0x400)
+#define PLAT_MARVELL_MAILBOX_SIZE		0x100
+#define PLAT_MARVELL_MAILBOX_MAGIC_NUM		0x6D72766C	/* mrvl */
+
+/* Securities */
+#define IRQ_SEC_OS_TICK_INT			MARVELL_IRQ_SEC_PHY_TIMER
+
+#define TRUSTED_DRAM_BASE			PLAT_MARVELL_TRUSTED_DRAM_BASE
+#define TRUSTED_DRAM_SIZE			PLAT_MARVELL_TRUSTED_DRAM_SIZE
+
+#ifdef BL32
+#define BL32_BASE				TRUSTED_DRAM_BASE
+#define BL32_LIMIT				TRUSTED_DRAM_SIZE
+#endif
+
+#define MVEBU_PMU_IRQ_WA
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/marvell/a8k/common/mss/mss_a8k.mk b/plat/marvell/a8k/common/mss/mss_a8k.mk
new file mode 100644
index 0000000..58f23d8
--- /dev/null
+++ b/plat/marvell/a8k/common/mss/mss_a8k.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:	BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PLAT_MARVELL		:=	plat/marvell
+A8K_MSS_SOURCE		:=	$(PLAT_MARVELL)/a8k/common/mss
+
+BL2_SOURCES		+=	$(A8K_MSS_SOURCE)/mss_bl2_setup.c
+
+BL31_SOURCES		+=	$(A8K_MSS_SOURCE)/mss_pm_ipc.c
+
+PLAT_INCLUDES		+=	-I$(A8K_MSS_SOURCE)
+
+ifneq (${SCP_BL2},)
+# This define is used to inidcate the SCP image is present
+$(eval $(call add_define,SCP_IMAGE))
+endif
diff --git a/plat/marvell/a8k/common/mss/mss_bl2_setup.c b/plat/marvell/a8k/common/mss/mss_bl2_setup.c
new file mode 100644
index 0000000..728ee54
--- /dev/null
+++ b/plat/marvell/a8k/common/mss/mss_bl2_setup.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <marvell_plat_priv.h> /* timer functionality */
+
+#include "mss_scp_bootloader.h"
+
+/* IO windows configuration */
+#define IOW_GCR_OFFSET		(0x70)
+
+/* MSS windows configuration */
+#define MSS_AEBR(base)			(base + 0x160)
+#define MSS_AIBR(base)			(base + 0x164)
+#define MSS_AEBR_MASK			0xFFF
+#define MSS_AIBR_MASK			0xFFF
+
+#define MSS_EXTERNAL_SPACE		0x50000000
+#define MSS_EXTERNAL_ACCESS_BIT		28
+#define MSS_EXTERNAL_ADDR_MASK		0xfffffff
+#define MSS_INTERNAL_ACCESS_BIT		28
+
+struct addr_map_win ccu_mem_map[] = {
+	{MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID}
+};
+
+/* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors,
+ * the access to cp0 and cp1 need to be provided. More precisely it is
+ * required to:
+ *  - get the information about device id which is stored in CP0 registers
+ *    (to distinguish between cases where we have cp0 and cp1 or standalone cp0)
+ *  - get the access to cp which is needed for loading fw for cp0/cp1
+ *    coprocessors
+ * This function configures ccu windows accordingly.
+ *
+ * Note: there is no need to restore previous ccu configuration, since in next
+ * phase (BL31) the init_ccu will be called (via apn806_init/
+ * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten.
+ */
+static int bl2_plat_mmap_init(void)
+{
+	int cfg_num, win_id, cfg_idx;
+
+	cfg_num =  ARRAY_SIZE(ccu_mem_map);
+
+	/* CCU window-0 should not be counted - it's already used */
+	if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) {
+		ERROR("BL2: %s: trying to open too many windows\n", __func__);
+		return -1;
+	}
+
+	/* Enable required CCU windows
+	 * Do not touch CCU window 0,
+	 * it's used for the internal registers access
+	 */
+	for (cfg_idx = 0, win_id = 1; cfg_idx < cfg_num; cfg_idx++, win_id++) {
+		/* Enable required CCU windows */
+		ccu_win_check(&ccu_mem_map[cfg_idx]);
+		ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id);
+	}
+
+	/* Set the default target id to PIDI */
+	mmio_write_32(MVEBU_IO_WIN_BASE(MVEBU_AP0) + IOW_GCR_OFFSET, PIDI_TID);
+
+	return 0;
+}
+
+/*****************************************************************************
+ * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol.
+ * Return 0 on success, -1 otherwise.
+ *****************************************************************************
+ */
+int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	int ret;
+
+	INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
+
+	/* initialize time (for delay functionality) */
+	plat_delay_timer_init();
+
+	ret = bl2_plat_mmap_init();
+	if (ret != 0)
+		return ret;
+
+	ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base,
+		scp_bl2_image_info->image_size);
+
+	if (ret == 0)
+		INFO("BL2: SCP_BL2 transferred to SCP\n");
+	else
+		ERROR("BL2: SCP_BL2 transfer failure\n");
+
+	return ret;
+}
+
+uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx)
+{
+	return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000;
+}
+
+uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
+{
+	return MVEBU_REGS_BASE + 0x580000;
+}
+
+uint32_t bl2_plat_get_cp_count(int ap_idx)
+{
+	uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
+	/* A8040: two CPs.
+	 * A7040: one CP.
+	 */
+	if (revision == MVEBU_80X0_DEV_ID ||
+	    revision == MVEBU_80X0_CP115_DEV_ID)
+		return 2;
+	else
+		return 1;
+}
+
+uint32_t bl2_plat_get_ap_count(void)
+{
+	/* A8040 and A7040 have only one AP */
+	return 1;
+}
+
+void bl2_plat_configure_mss_windows(uintptr_t mss_regs)
+{
+	/* set AXI External and Internal Address Bus extension */
+	mmio_write_32(MSS_AEBR(mss_regs),
+		      ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK));
+	mmio_write_32(MSS_AIBR(mss_regs),
+		      ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK));
+}
diff --git a/plat/marvell/a8k/common/mss/mss_pm_ipc.c b/plat/marvell/a8k/common/mss/mss_pm_ipc.c
new file mode 100644
index 0000000..a070583
--- /dev/null
+++ b/plat/marvell/a8k/common/mss/mss_pm_ipc.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/psci/psci.h>
+#include <lib/mmio.h>
+
+#include <mss_pm_ipc.h>
+
+/*
+ * SISR is 32 bit interrupt register representing 32 interrupts
+ *
+ * +======+=============+=============+
+ * + Bits + 31          + 30 - 00     +
+ * +======+=============+=============+
+ * + Desc + MSS Msg Int + Reserved    +
+ * +======+=============+=============+
+ */
+#define MSS_SISR		(MVEBU_REGS_BASE + 0x5800D0)
+#define MSS_SISTR		(MVEBU_REGS_BASE + 0x5800D8)
+
+#define MSS_MSG_INT_MASK	(0x80000000)
+#define MSS_TIMER_BASE		(MVEBU_REGS_BASE_MASK + 0x580110)
+#define MSS_TRIGGER_TIMEOUT	(2000)
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_send
+ *
+ * DESCRIPTION: create and transmit IPC message
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
+			const psci_power_state_t *target_state)
+{
+	/* Transmit IPC message */
+#ifndef DISABLE_CLUSTER_LEVEL
+	mv_pm_ipc_msg_tx(channel_id, msg_id,
+			 (unsigned int)target_state->pwr_domain_state[
+					MPIDR_AFFLVL1]);
+#else
+	mv_pm_ipc_msg_tx(channel_id, msg_id, 0);
+#endif
+
+	return 0;
+}
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_trigger
+ *
+ * DESCRIPTION: Trigger IPC message interrupt to MSS
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_trigger(void)
+{
+	unsigned int timeout;
+	unsigned int t_end;
+	unsigned int t_start = mmio_read_32(MSS_TIMER_BASE);
+
+	mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK);
+
+	do {
+		/* wait while SCP process incoming interrupt */
+		if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK)
+			break;
+
+		/* check timeout */
+		t_end = mmio_read_32(MSS_TIMER_BASE);
+
+		timeout = ((t_start > t_end) ?
+			   (t_start - t_end) : (t_end - t_start));
+		if (timeout > MSS_TRIGGER_TIMEOUT) {
+			ERROR("PM MSG Trigger Timeout\n");
+			break;
+		}
+
+	} while (1);
+
+	return 0;
+}
diff --git a/plat/marvell/a8k/common/mss/mss_pm_ipc.h b/plat/marvell/a8k/common/mss/mss_pm_ipc.h
new file mode 100644
index 0000000..1dfa9fa
--- /dev/null
+++ b/plat/marvell/a8k/common/mss/mss_pm_ipc.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MSS_PM_IPC_H
+#define MSS_PM_IPC_H
+
+#include <mss_ipc_drv.h>
+
+/* Currently MSS does not support Cluster level Power Down */
+#define DISABLE_CLUSTER_LEVEL
+
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_send
+ *
+ * DESCRIPTION: create and transmit IPC message
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id,
+			const psci_power_state_t *target_state);
+
+/*****************************************************************************
+ * mss_pm_ipc_msg_trigger
+ *
+ * DESCRIPTION: Trigger IPC message interrupt to MSS
+ *****************************************************************************
+ */
+int mss_pm_ipc_msg_trigger(void);
+
+
+#endif /* MSS_PM_IPC_H */
diff --git a/plat/marvell/a8k/common/plat_bl1_setup.c b/plat/marvell/a8k/common/plat_bl1_setup.c
new file mode 100644
index 0000000..f9521c8
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_bl1_setup.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <lib/mmio.h>
+
+#include <plat_marvell.h>
+
+void marvell_bl1_setup_mpps(void)
+{
+	/* Enable UART MPPs.
+	 ** In a normal system, this is done by Bootrom.
+	 */
+	mmio_write_32(MVEBU_AP_MPP_REGS(1), 0x3000);
+	mmio_write_32(MVEBU_AP_MPP_REGS(2), 0x3000);
+}
diff --git a/plat/marvell/a8k/common/plat_bl31_setup.c b/plat/marvell/a8k/common/plat_bl31_setup.c
new file mode 100644
index 0000000..98b3966
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_bl31_setup.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/marvell/mci.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+#include <lib/mmio.h>
+
+#include <armada_common.h>
+#include <marvell_plat_priv.h>
+#include <marvell_pm.h>
+#include <mc_trustzone/mc_trustzone.h>
+#include <plat_marvell.h>
+#include <mss_ipc_drv.h>
+#include <mss_mem.h>
+
+/* In Armada-8k family AP806/AP807, CP0 connected to PIDI
+ * and CP1 connected to IHB via MCI #0
+ */
+#define MVEBU_MCI0		0
+
+static _Bool pm_fw_running;
+
+/* Set a weak stub for platforms that don't need to configure GPIO */
+#pragma weak marvell_gpio_config
+int marvell_gpio_config(void)
+{
+	return 0;
+}
+
+static void marvell_bl31_mpp_init(int cp)
+{
+	uint32_t reg;
+
+	/* need to do for CP#0 only */
+	if (cp)
+		return;
+
+
+	/*
+	 * Enable CP0 I2C MPPs (MPP: 37-38)
+	 * U-Boot rely on proper MPP settings for I2C EEPROM usage
+	 * (only for CP0)
+	 */
+	reg = mmio_read_32(MVEBU_CP_MPP_REGS(0, 4));
+	mmio_write_32(MVEBU_CP_MPP_REGS(0, 4), reg | 0x2200000);
+}
+
+void marvell_bl31_mss_init(void)
+{
+	struct mss_pm_ctrl_block *mss_pm_crtl =
+			(struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE;
+
+	/* Check that the image was loaded successfully */
+	if (mss_pm_crtl->handshake != HOST_ACKNOWLEDGMENT) {
+		NOTICE("MSS PM is not supported in this build\n");
+		return;
+	}
+
+	/* If we got here it means that the PM firmware is running */
+	pm_fw_running = 1;
+
+	INFO("MSS IPC init\n");
+
+	if (mss_pm_crtl->ipc_state == IPC_INITIALIZED)
+		mv_pm_ipc_init(mss_pm_crtl->ipc_base_address | MVEBU_REGS_BASE);
+}
+
+_Bool is_pm_fw_running(void)
+{
+	return pm_fw_running;
+}
+
+/* For TrusTzone we treat the "target" field of addr_map_win
+ * struct as attribute
+ */
+static const struct addr_map_win tz_map[] = {
+	{PLAT_MARVELL_ATF_BASE, 0x200000, TZ_PERM_ABORT}
+};
+
+/* Configure MC TrustZone regions */
+static void marvell_bl31_security_setup(void)
+{
+	int tz_nr, win_id;
+
+	tz_nr = ARRAY_SIZE(tz_map);
+
+	for (win_id = 0; win_id < tz_nr; win_id++)
+		tz_enable_win(MVEBU_AP0, tz_map, win_id);
+}
+
+/* This function overruns the same function in marvell_bl31_setup.c */
+void bl31_plat_arch_setup(void)
+{
+	int cp;
+	uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+	/* initialize the timer for mdelay/udelay functionality */
+	plat_delay_timer_init();
+
+	/* configure apn806 */
+	ap_init();
+
+	/* In marvell_bl31_plat_arch_setup, el3 mmu is configured.
+	 * el3 mmu configuration MUST be called after apn806_init, if not,
+	 * this will cause an hang in init_io_win
+	 * (after setting the IO windows GCR values).
+	 */
+	if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
+	    mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE)
+		marvell_bl31_plat_arch_setup();
+
+	for (cp = 0; cp < CP_COUNT; cp++) {
+	/* configure cp110 for CP0*/
+		if (cp == 1)
+			mci_initialize(MVEBU_MCI0);
+
+	/* initialize MCI & CP1 */
+		cp110_init(MVEBU_CP_REGS_BASE(cp),
+			   STREAM_ID_BASE + (cp * MAX_STREAM_ID_PER_CP));
+
+	/* Should be called only after setting IOB windows */
+		marvell_bl31_mpp_init(cp);
+	}
+
+	/* initialize IPC between MSS and ATF */
+	if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM ||
+	    mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE)
+		marvell_bl31_mss_init();
+
+	/* Configure GPIO */
+	marvell_gpio_config();
+
+	marvell_bl31_security_setup();
+}
diff --git a/plat/marvell/a8k/common/plat_ble_setup.c b/plat/marvell/a8k/common/plat_ble_setup.c
new file mode 100644
index 0000000..7f9e242
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_ble_setup.c
@@ -0,0 +1,735 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/marvell/ap807_clocks_init.h>
+#include <drivers/marvell/aro.h>
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/io_win.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/marvell/mochi/cp110_setup.h>
+
+#include <armada_common.h>
+#include <mv_ddr_if.h>
+#include <mvebu_def.h>
+#include <plat_marvell.h>
+
+/* Register for skip image use */
+#define SCRATCH_PAD_REG2		0xF06F00A8
+#define SCRATCH_PAD_SKIP_VAL		0x01
+#define NUM_OF_GPIO_PER_REG 32
+
+#define MMAP_SAVE_AND_CONFIG		0
+#define MMAP_RESTORE_SAVED		1
+
+/* SAR clock settings */
+#define MVEBU_AP_GEN_MGMT_BASE		(MVEBU_RFU_BASE + 0x8000)
+#define MVEBU_AP_SAR_REG_BASE(r)	(MVEBU_AP_GEN_MGMT_BASE + 0x200 +\
+								((r) << 2))
+
+#define SAR_CLOCK_FREQ_MODE_OFFSET	(0)
+#define SAR_CLOCK_FREQ_MODE_MASK	(0x1f << SAR_CLOCK_FREQ_MODE_OFFSET)
+#define SAR_PIDI_LOW_SPEED_OFFSET	(20)
+#define SAR_PIDI_LOW_SPEED_MASK		(1 << SAR_PIDI_LOW_SPEED_OFFSET)
+#define SAR_PIDI_LOW_SPEED_SHIFT	(15)
+#define SAR_PIDI_LOW_SPEED_SET		(1 << SAR_PIDI_LOW_SPEED_SHIFT)
+
+#define FREQ_MODE_AP_SAR_REG_NUM	(0)
+#define SAR_CLOCK_FREQ_MODE(v)		(((v) & SAR_CLOCK_FREQ_MODE_MASK) >> \
+					SAR_CLOCK_FREQ_MODE_OFFSET)
+
+#define AVS_I2C_EEPROM_ADDR		0x57	/* EEPROM */
+#define AVS_EN_CTRL_REG			(MVEBU_AP_GEN_MGMT_BASE + 0x130)
+#define AVS_ENABLE_OFFSET		(0)
+#define AVS_SOFT_RESET_OFFSET		(2)
+#define AVS_TARGET_DELTA_OFFSET		(21)
+
+#ifndef MVEBU_SOC_AP807
+	/* AP806 SVC bits */
+	#define AVS_LOW_VDD_LIMIT_OFFSET	(4)
+	#define AVS_HIGH_VDD_LIMIT_OFFSET	(12)
+	#define AVS_VDD_LOW_LIMIT_MASK	(0xFF << AVS_LOW_VDD_LIMIT_OFFSET)
+	#define AVS_VDD_HIGH_LIMIT_MASK	(0xFF << AVS_HIGH_VDD_LIMIT_OFFSET)
+#else
+	/* AP807 SVC bits */
+	#define AVS_LOW_VDD_LIMIT_OFFSET	(3)
+	#define AVS_HIGH_VDD_LIMIT_OFFSET	(13)
+	#define AVS_VDD_LOW_LIMIT_MASK	(0x3FF << AVS_LOW_VDD_LIMIT_OFFSET)
+	#define AVS_VDD_HIGH_LIMIT_MASK	(0x3FF << AVS_HIGH_VDD_LIMIT_OFFSET)
+#endif
+
+/* VDD limit is 0.9V for A70x0 @ CPU frequency < 1600MHz */
+#define AVS_A7K_LOW_CLK_VALUE		((0x80 << AVS_TARGET_DELTA_OFFSET) | \
+					 (0x1A << AVS_HIGH_VDD_LIMIT_OFFSET) | \
+					 (0x1A << AVS_LOW_VDD_LIMIT_OFFSET) | \
+					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
+					 (0x1 << AVS_ENABLE_OFFSET))
+/* VDD limit is 1.0V for all A80x0 devices */
+#define AVS_A8K_CLK_VALUE		((0x80 << AVS_TARGET_DELTA_OFFSET) | \
+					 (0x24 << AVS_HIGH_VDD_LIMIT_OFFSET) | \
+					 (0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \
+					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
+					 (0x1 << AVS_ENABLE_OFFSET))
+/* VDD limit is 0.82V for all A3900 devices
+ * AVS offsets are not the same as in A70x0
+ */
+#define AVS_A3900_CLK_VALUE		((0x80u << 24) | \
+					 (0x2c2 << 13) | \
+					 (0x2c2 << 3) | \
+					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
+					 (0x1 << AVS_ENABLE_OFFSET))
+/* VDD is 0.88V for 2GHz clock */
+#define AVS_A3900_HIGH_CLK_VALUE	((0x80u << 24) | \
+					 (0x2f5 << 13) | \
+					 (0x2f5 << 3) | \
+					 (0x1 << AVS_SOFT_RESET_OFFSET) | \
+					 (0x1 << AVS_ENABLE_OFFSET))
+
+#define MVEBU_AP_EFUSE_SRV_CTRL_REG	(MVEBU_AP_GEN_MGMT_BASE + 0x8)
+#define EFUSE_SRV_CTRL_LD_SELECT_OFFS	6
+#define EFUSE_SRV_CTRL_LD_SEL_USER_MASK	(1 << EFUSE_SRV_CTRL_LD_SELECT_OFFS)
+
+
+/*
+ * - Identification information in the LD-0 eFuse:
+ *	DRO:           LD0[74:65] - Not used by the SW
+ *	Revision:      LD0[78:75] - Not used by the SW
+ *	Bin:           LD0[80:79] - Not used by the SW
+ *	SW Revision:   LD0[115:113]
+ *	Cluster 1 PWR: LD0[193] - if set to 1, power down CPU Cluster-1
+ *				  resulting in 2 CPUs active only (7020)
+ */
+#define MVEBU_AP_LD_EFUSE_BASE		(MVEBU_AP_GEN_MGMT_BASE + 0xF00)
+/* Bits [94:63] - 32 data bits total */
+#define MVEBU_AP_LD0_94_63_EFUSE_OFFS	(MVEBU_AP_LD_EFUSE_BASE + 0x8)
+/* Bits [125:95] - 31 data bits total, 32nd bit is parity for bits [125:63] */
+#define MVEBU_AP_LD0_125_95_EFUSE_OFFS	(MVEBU_AP_LD_EFUSE_BASE + 0xC)
+/* Bits [220:189] - 32 data bits total */
+#define MVEBU_AP_LD0_220_189_EFUSE_OFFS	(MVEBU_AP_LD_EFUSE_BASE + 0x18)
+/* Offsets for the above 2 fields combined into single 64-bit value [125:63] */
+#define EFUSE_AP_LD0_DRO_OFFS		2		/* LD0[74:65] */
+#define EFUSE_AP_LD0_DRO_MASK		0x3FF
+#define EFUSE_AP_LD0_REVID_OFFS		12		/* LD0[78:75] */
+#define EFUSE_AP_LD0_REVID_MASK		0xF
+#define EFUSE_AP_LD0_BIN_OFFS		16		/* LD0[80:79] */
+#define EFUSE_AP_LD0_BIN_MASK		0x3
+#define EFUSE_AP_LD0_SWREV_OFFS		50		/* LD0[115:113] */
+#define EFUSE_AP_LD0_SWREV_MASK		0x7
+
+#ifndef MVEBU_SOC_AP807
+	/* AP806 AVS work points in the LD0 eFuse
+	 * SVC1 work point:     LD0[88:81]
+	 * SVC2 work point:     LD0[96:89]
+	 * SVC3 work point:     LD0[104:97]
+	 * SVC4 work point:     LD0[112:105]
+	 */
+	#define EFUSE_AP_LD0_SVC1_OFFS		18	/* LD0[88:81] */
+	#define EFUSE_AP_LD0_SVC2_OFFS		26	/* LD0[96:89] */
+	#define EFUSE_AP_LD0_SVC3_OFFS		34	/* LD0[104:97] */
+	#define EFUSE_AP_LD0_WP_MASK		0xFF
+#else
+	/* AP807 AVS work points in the LD0 eFuse
+	 * SVC1 work point:     LD0[91:81]
+	 * SVC2 work point:     LD0[102:92]
+	 * SVC3 work point:     LD0[113:103]
+	 */
+	#define EFUSE_AP_LD0_SVC1_OFFS		17	/* LD0[91:81] */
+	#define EFUSE_AP_LD0_SVC2_OFFS		28	/* LD0[102:92] */
+	#define EFUSE_AP_LD0_SVC3_OFFS		39	/* LD0[113:103] */
+	#define EFUSE_AP_LD0_WP_MASK		0x3FF
+#endif
+
+#define EFUSE_AP_LD0_SVC4_OFFS			42	/* LD0[112:105] */
+
+#define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS		4
+
+#if MARVELL_SVC_TEST
+#define MVEBU_CP_MPP_CTRL37_OFFS	20
+#define MVEBU_CP_MPP_CTRL38_OFFS	24
+#define MVEBU_CP_MPP_I2C_FUNC		2
+#define MVEBU_MPP_CTRL_MASK		0xf
+#endif
+
+/* Return the AP revision of the chip */
+static unsigned int ble_get_ap_type(void)
+{
+	unsigned int chip_rev_id;
+
+	chip_rev_id = mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG);
+	chip_rev_id = ((chip_rev_id & GWD_IIDR2_CHIP_ID_MASK) >>
+			GWD_IIDR2_CHIP_ID_OFFSET);
+
+	return chip_rev_id;
+}
+
+/******************************************************************************
+ * The routine allows to save the CCU and IO windows configuration during DRAM
+ * setup and restore them afterwards before exiting the BLE stage.
+ * Such window configuration is required since not all default settings coming
+ * from the HW and the BootROM allow access to peripherals connected to
+ * all available CPn components.
+ * For instance, when the boot device is located on CP0, the IO window to CP1
+ * is not opened automatically by the HW and if the DRAM SPD is located on CP1
+ * i2c channel, it cannot be read at BLE stage.
+ * Therefore the DRAM init procedure have to provide access to all available
+ * CPn peripherals during the BLE stage by setting the CCU IO window to all
+ * CPnph addresses and by enabling the IO windows accordingly.
+ * Additionally this function configures the CCU GCR to DRAM, which allows
+ * usage or more than 4GB DRAM as it configured by the default CCU DRAM window.
+ *
+ * IN:
+ *	MMAP_SAVE_AND_CONFIG	- save the existing configuration and update it
+ *	MMAP_RESTORE_SAVED	- restore saved configuration
+ * OUT:
+ *	NONE
+ ****************************************************************************
+ */
+static void ble_plat_mmap_config(int restore)
+{
+	if (restore == MMAP_RESTORE_SAVED) {
+		/* Restore all orig. settings that were modified by BLE stage */
+		ccu_restore_win_all(MVEBU_AP0);
+		/* Restore CCU */
+		iow_restore_win_all(MVEBU_AP0);
+		return;
+	}
+
+	/* Store original values */
+	ccu_save_win_all(MVEBU_AP0);
+	/* Save CCU */
+	iow_save_win_all(MVEBU_AP0);
+
+	init_ccu(MVEBU_AP0);
+	/* The configuration saved, now all the changes can be done */
+	init_io_win(MVEBU_AP0);
+}
+
+/****************************************************************************
+ * Setup Adaptive Voltage Switching - this is required for some platforms
+ ****************************************************************************
+ */
+#if !MARVELL_SVC_TEST
+static void ble_plat_avs_config(void)
+{
+	uint32_t freq_mode, device_id;
+	uint32_t avs_val = 0;
+
+	freq_mode =
+		SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
+						 FREQ_MODE_AP_SAR_REG_NUM)));
+	/* Check which SoC is running and act accordingly */
+	if (ble_get_ap_type() == CHIP_ID_AP807) {
+		/* Increase CPU voltage for higher CPU clock */
+		if (freq_mode == CPU_2000_DDR_1200_RCLK_1200)
+			avs_val = AVS_A3900_HIGH_CLK_VALUE;
+		else
+			avs_val = AVS_A3900_CLK_VALUE;
+	} else {
+		/* Check which SoC is running and act accordingly */
+		device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
+		switch (device_id) {
+		case MVEBU_80X0_DEV_ID:
+		case MVEBU_80X0_CP115_DEV_ID:
+			/* Always fix the default AVS value on A80x0 */
+			avs_val = AVS_A8K_CLK_VALUE;
+			break;
+		case MVEBU_70X0_DEV_ID:
+		case MVEBU_70X0_CP115_DEV_ID:
+			/* Fix AVS for CPU clocks lower than 1600MHz on A70x0 */
+			if ((freq_mode > CPU_1600_DDR_900_RCLK_900_2) &&
+			    (freq_mode < CPU_DDR_RCLK_INVALID))
+				avs_val = AVS_A7K_LOW_CLK_VALUE;
+			break;
+		default:
+			ERROR("Unsupported Device ID 0x%x\n", device_id);
+			return;
+		}
+	}
+
+	if (avs_val) {
+		VERBOSE("AVS: Setting AVS CTRL to 0x%x\n", avs_val);
+		mmio_write_32(AVS_EN_CTRL_REG, avs_val);
+	}
+}
+#endif
+/******************************************************************************
+ * Update or override current AVS work point value using data stored in EEPROM
+ * This is only required by QA/validation flows and activated by
+ * MARVELL_SVC_TEST flag.
+ *
+ * The function is expected to be called twice.
+ *
+ * First time with AVS value of 0 for testing if the EEPROM requests completely
+ * override the AVS value and bypass the eFuse test
+ *
+ * Second time - with non-zero AVS value obtained from eFuses as an input.
+ * In this case the EEPROM may contain AVS correction value (either positive
+ * or negative) that is added to the input AVS value and returned back for
+ * further processing.
+ ******************************************************************************
+ */
+static uint32_t avs_update_from_eeprom(uint32_t avs_workpoint)
+{
+	uint32_t new_wp = avs_workpoint;
+#if MARVELL_SVC_TEST
+	/* ---------------------------------------------------------------------
+	 * EEPROM  |  Data description (avs_step)
+	 * address |
+	 * ---------------------------------------------------------------------
+	 * 0x120   | AVS workpoint correction value
+	 *         | if not 0 and not 0xff, correct the AVS taken from eFuse
+	 *         | by the number of steps indicated by bit[6:0]
+	 *         | bit[7] defines correction direction.
+	 *         | If bit[7]=1, add the value from bit[6:0] to AVS workpoint,
+	 *         | othervise substruct this value from AVS workpoint.
+	 * ---------------------------------------------------------------------
+	 * 0x121   | AVS workpoint override value
+	 *         | Override the AVS workpoint with the value stored in this
+	 *         | byte. When running on AP806, the AVS workpoint is 7 bits
+	 *         | wide and override value is valid when bit[6:0] holds
+	 *         | value greater than zero and smaller than 0x33.
+	 *         | When running on AP807, the AVS workpoint is 10 bits wide.
+	 *         | Additional 2 MSB bits are supplied by EEPROM byte 0x122.
+	 *         | AVS override value is valid when byte @ 0x121 and bit[1:0]
+	 *         | of byte @ 0x122 combined have non-zero value.
+	 * ---------------------------------------------------------------------
+	 * 0x122   | Extended AVS workpoint override value
+	 *         | Valid only for AP807 platforms and must be less than 0x4
+	 * ---------------------------------------------------------------------
+	 */
+	static uint8_t  avs_step[3] = {0};
+	uintptr_t reg;
+	uint32_t val;
+	unsigned int ap_type = ble_get_ap_type();
+
+	/* Always happens on second call to this function */
+	if (avs_workpoint != 0) {
+		/* Get correction steps from the EEPROM */
+		if ((avs_step[0] != 0) && (avs_step[0] != 0xff)) {
+			NOTICE("AVS request to step %s by 0x%x from old 0x%x\n",
+				avs_step[0] & 0x80 ? "DOWN" : "UP",
+				avs_step[0] & 0x7f, new_wp);
+			if (avs_step[0] & 0x80)
+				new_wp -= avs_step[0] & 0x7f;
+			else
+				new_wp += avs_step[0] & 0x7f;
+		}
+
+		return new_wp;
+	}
+
+	/* AVS values are located in EEPROM
+	 * at CP0 i2c bus #0, device 0x57 offset 0x120
+	 * The SDA and SCK pins of CP0 i2c-0: MPP[38:37], i2c function 0x2.
+	 */
+	reg = MVEBU_CP_MPP_REGS(0, 4);
+	val = mmio_read_32(reg);
+	val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) |
+		 (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS));
+	val |= (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL37_OFFS) |
+		(MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL38_OFFS);
+	mmio_write_32(reg, val);
+
+	/* Init CP0 i2c-0 */
+	i2c_init((void *)(MVEBU_CP0_I2C_BASE));
+
+	/* Read EEPROM only once at the fist call! */
+	i2c_read(AVS_I2C_EEPROM_ADDR, 0x120, 2, avs_step, 3);
+	NOTICE("== SVC test build ==\n");
+	NOTICE("EEPROM holds values 0x%x, 0x%x and 0x%x\n",
+		avs_step[0], avs_step[1], avs_step[2]);
+
+	/* Override the AVS value? */
+	if ((ap_type != CHIP_ID_AP807) && (avs_step[1] < 0x33)) {
+		/* AP806 - AVS is 7 bits */
+		new_wp = avs_step[1];
+
+	} else if (ap_type == CHIP_ID_AP807 && (avs_step[2] < 0x4)) {
+		/* AP807 - AVS is 10 bits */
+		new_wp = avs_step[2];
+		new_wp <<= 8;
+		new_wp |= avs_step[1];
+	}
+
+	if (new_wp == 0)
+		NOTICE("Ignore BAD AVS Override value in EEPROM!\n");
+	else
+		NOTICE("Override AVS by EEPROM value 0x%x\n", new_wp);
+#endif /* MARVELL_SVC_TEST */
+	return new_wp;
+}
+
+/****************************************************************************
+ * SVC flow - v0.10
+ * The feature is intended to configure AVS value according to eFuse values
+ * that are burned individually for each SoC during the test process.
+ * Primary AVS value is stored in HD efuse and processed on power on
+ * by the HW engine
+ * Secondary AVS value is located in LD efuse and contains 4 work points for
+ * various CPU frequencies.
+ * The Secondary AVS value is only taken into account if the SW Revision stored
+ * in the efuse is greater than 0 and the CPU is running in a certain speed.
+ ****************************************************************************
+ */
+static void ble_plat_svc_config(void)
+{
+	uint32_t reg_val, avs_workpoint, freq_pidi_mode;
+	uint64_t efuse;
+	uint32_t device_id, single_cluster;
+	uint16_t  svc[4], perr[4], i, sw_ver;
+	unsigned int ap_type;
+
+	/* Set access to LD0 */
+	avs_workpoint = avs_update_from_eeprom(0);
+	if (avs_workpoint)
+		goto set_aws_wp;
+
+	/* Set access to LD0 */
+	reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG);
+	reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_OFFS;
+	mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val);
+
+	/* Obtain the value of LD0[125:63] */
+	efuse = mmio_read_32(MVEBU_AP_LD0_125_95_EFUSE_OFFS);
+	efuse <<= 32;
+	efuse |= mmio_read_32(MVEBU_AP_LD0_94_63_EFUSE_OFFS);
+
+	/* SW Revision:
+	 * Starting from SW revision 1 the SVC flow is supported.
+	 * SW version 0 (efuse not programmed) should follow the
+	 * regular AVS update flow.
+	 */
+	sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK;
+	if (sw_ver < 1) {
+		NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver);
+#if MARVELL_SVC_TEST
+		NOTICE("SVC_TEST: AVS bypassed\n");
+
+#else
+		ble_plat_avs_config();
+#endif
+		return;
+	}
+
+	/* Frequency mode from SAR */
+	freq_pidi_mode = SAR_CLOCK_FREQ_MODE(
+				mmio_read_32(
+					MVEBU_AP_SAR_REG_BASE(
+						FREQ_MODE_AP_SAR_REG_NUM)));
+
+	/* Decode all SVC work points */
+	svc[0] = (efuse >> EFUSE_AP_LD0_SVC1_OFFS) & EFUSE_AP_LD0_WP_MASK;
+	svc[1] = (efuse >> EFUSE_AP_LD0_SVC2_OFFS) & EFUSE_AP_LD0_WP_MASK;
+	svc[2] = (efuse >> EFUSE_AP_LD0_SVC3_OFFS) & EFUSE_AP_LD0_WP_MASK;
+
+	/* Fetch AP type to distinguish between AP806 and AP807 */
+	ap_type = ble_get_ap_type();
+
+	if (ap_type != CHIP_ID_AP807) {
+		svc[3] = (efuse >> EFUSE_AP_LD0_SVC4_OFFS)
+			 & EFUSE_AP_LD0_WP_MASK;
+		INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x\n",
+		     svc[0], svc[1], svc[2], svc[3]);
+	} else {
+		INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x\n",
+		     svc[0], svc[1], svc[2]);
+	}
+
+	/* Validate parity of SVC workpoint values */
+	for (i = 0; i < 4; i++) {
+		uint8_t parity, bit;
+
+		perr[i] = 0;
+
+		for (bit = 1, parity = svc[i] & 1; bit < 7; bit++)
+			parity ^= (svc[i] >> bit) & 1;
+
+		/* Starting from SW version 2, the parity check is mandatory */
+		if ((sw_ver > 1) && (parity != ((svc[i] >> 7) & 1)))
+			perr[i] = 1; /* register the error */
+	}
+
+	single_cluster = mmio_read_32(MVEBU_AP_LD0_220_189_EFUSE_OFFS);
+	single_cluster = (single_cluster >> EFUSE_AP_LD0_CLUSTER_DOWN_OFFS) & 1;
+
+	device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0));
+	if (device_id == MVEBU_80X0_DEV_ID ||
+	    device_id == MVEBU_80X0_CP115_DEV_ID) {
+		/* A8040/A8020 */
+		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
+			single_cluster == 0 ? "8040" : "8020", freq_pidi_mode);
+		switch (freq_pidi_mode) {
+		case CPU_1800_DDR_1200_RCLK_1200:
+		case CPU_1800_DDR_1050_RCLK_1050:
+			if (perr[1])
+				goto perror;
+			avs_workpoint = svc[1];
+			break;
+		case CPU_1600_DDR_1050_RCLK_1050:
+		case CPU_1600_DDR_900_RCLK_900_2:
+			if (perr[2])
+				goto perror;
+			avs_workpoint = svc[2];
+			break;
+		case CPU_1300_DDR_800_RCLK_800:
+		case CPU_1300_DDR_650_RCLK_650:
+			if (perr[3])
+				goto perror;
+			avs_workpoint = svc[3];
+			break;
+		case CPU_2000_DDR_1200_RCLK_1200:
+		case CPU_2000_DDR_1050_RCLK_1050:
+		default:
+			if (perr[0])
+				goto perror;
+			avs_workpoint = svc[0];
+			break;
+		}
+	} else if (device_id == MVEBU_70X0_DEV_ID ||
+		   device_id == MVEBU_70X0_CP115_DEV_ID) {
+		/* A7040/A7020/A6040 */
+		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
+			single_cluster == 0 ? "7040" : "7020", freq_pidi_mode);
+		switch (freq_pidi_mode) {
+		case CPU_1400_DDR_800_RCLK_800:
+			if (single_cluster) {/* 7020 */
+				if (perr[1])
+					goto perror;
+				avs_workpoint = svc[1];
+			} else {
+				if (perr[0])
+					goto perror;
+				avs_workpoint = svc[0];
+			}
+			break;
+		case CPU_1200_DDR_800_RCLK_800:
+			if (single_cluster) {/* 7020 */
+				if (perr[2])
+					goto perror;
+				avs_workpoint = svc[2];
+			} else {
+				if (perr[1])
+					goto perror;
+				avs_workpoint = svc[1];
+			}
+			break;
+		case CPU_800_DDR_800_RCLK_800:
+		case CPU_1000_DDR_800_RCLK_800:
+			if (single_cluster) {/* 7020 */
+				if (perr[3])
+					goto perror;
+				avs_workpoint = svc[3];
+			} else {
+				if (perr[2])
+					goto perror;
+				avs_workpoint = svc[2];
+			}
+			break;
+		case CPU_600_DDR_800_RCLK_800:
+			if (perr[3])
+				goto perror;
+			avs_workpoint = svc[3]; /* Same for 6040 and 7020 */
+			break;
+		case CPU_1600_DDR_800_RCLK_800: /* 7020 only */
+		default:
+			if (single_cluster) {/* 7020 */
+				if (perr[0])
+					goto perror;
+				avs_workpoint = svc[0];
+			} else
+				avs_workpoint = 0;
+			break;
+		}
+	} else if (device_id == MVEBU_3900_DEV_ID) {
+		NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n",
+		       "3900", freq_pidi_mode);
+		switch (freq_pidi_mode) {
+		case CPU_1600_DDR_1200_RCLK_1200:
+			if (perr[0])
+				goto perror;
+			avs_workpoint = svc[0];
+			break;
+		case CPU_1300_DDR_800_RCLK_800:
+			if (perr[1])
+				goto perror;
+			avs_workpoint = svc[1];
+			break;
+		default:
+			if (perr[0])
+				goto perror;
+			avs_workpoint = svc[0];
+			break;
+		}
+	} else {
+		ERROR("SVC: Unsupported Device ID 0x%x\n", device_id);
+		return;
+	}
+
+	/* Set AVS control if needed */
+	if (avs_workpoint == 0) {
+		ERROR("SVC: AVS work point not changed\n");
+		return;
+	}
+
+	/* Remove parity bit */
+	if (ap_type != CHIP_ID_AP807)
+		avs_workpoint &= 0x7F;
+
+	/* Update WP from EEPROM if needed */
+	avs_workpoint = avs_update_from_eeprom(avs_workpoint);
+
+set_aws_wp:
+	reg_val  = mmio_read_32(AVS_EN_CTRL_REG);
+	NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n",
+		(reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET,
+		avs_workpoint);
+	reg_val &= ~(AVS_VDD_LOW_LIMIT_MASK | AVS_VDD_HIGH_LIMIT_MASK);
+	reg_val |= 0x1 << AVS_ENABLE_OFFSET;
+	reg_val |= avs_workpoint << AVS_HIGH_VDD_LIMIT_OFFSET;
+	reg_val |= avs_workpoint << AVS_LOW_VDD_LIMIT_OFFSET;
+	mmio_write_32(AVS_EN_CTRL_REG, reg_val);
+	return;
+
+perror:
+	ERROR("Failed SVC WP[%d] parity check!\n", i);
+	ERROR("Ignoring the WP values\n");
+}
+
+#if PLAT_RECOVERY_IMAGE_ENABLE
+static int ble_skip_image_i2c(struct skip_image *skip_im)
+{
+	ERROR("skipping image using i2c is not supported\n");
+	/* not supported */
+	return 0;
+}
+
+static int ble_skip_image_other(struct skip_image *skip_im)
+{
+	ERROR("implementation missing for skip image request\n");
+	/* not supported, make your own implementation */
+	return 0;
+}
+
+static int ble_skip_image_gpio(struct skip_image *skip_im)
+{
+	unsigned int val;
+	unsigned int mpp_address = 0;
+	unsigned int offset = 0;
+
+	switch (skip_im->info.test.cp_ap) {
+	case(CP):
+		mpp_address = MVEBU_CP_GPIO_DATA_IN(skip_im->info.test.cp_index,
+						    skip_im->info.gpio.num);
+		if (skip_im->info.gpio.num > NUM_OF_GPIO_PER_REG)
+			offset = skip_im->info.gpio.num - NUM_OF_GPIO_PER_REG;
+		else
+			offset = skip_im->info.gpio.num;
+		break;
+	case(AP):
+		mpp_address = MVEBU_AP_GPIO_DATA_IN;
+		offset = skip_im->info.gpio.num;
+		break;
+	}
+
+	val = mmio_read_32(mpp_address);
+	val &= (1 << offset);
+	if ((!val && skip_im->info.gpio.button_state == HIGH) ||
+	    (val && skip_im->info.gpio.button_state == LOW)) {
+		mmio_write_32(SCRATCH_PAD_REG2, SCRATCH_PAD_SKIP_VAL);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * This function checks if there's a skip image request:
+ * return values:
+ * 1: (true) images request been made.
+ * 0: (false) no image request been made.
+ */
+static int  ble_skip_current_image(void)
+{
+	struct skip_image *skip_im;
+
+	/*fetching skip image info*/
+	skip_im = (struct skip_image *)plat_marvell_get_skip_image_data();
+
+	if (skip_im == NULL)
+		return 0;
+
+	/* check if skipping image request has already been made */
+	if (mmio_read_32(SCRATCH_PAD_REG2) == SCRATCH_PAD_SKIP_VAL)
+		return 0;
+
+	switch (skip_im->detection_method) {
+	case GPIO:
+		return ble_skip_image_gpio(skip_im);
+	case I2C:
+		return ble_skip_image_i2c(skip_im);
+	case USER_DEFINED:
+		return ble_skip_image_other(skip_im);
+	}
+
+	return 0;
+}
+#endif
+
+
+int ble_plat_setup(int *skip)
+{
+	int ret;
+	unsigned int freq_mode;
+
+	/* Power down unused CPUs */
+	plat_marvell_early_cpu_powerdown();
+
+	/*
+	 * Save the current CCU configuration and make required changes:
+	 * - Allow access to DRAM larger than 4GB
+	 * - Open memory access to all CPn peripherals
+	 */
+	ble_plat_mmap_config(MMAP_SAVE_AND_CONFIG);
+
+#if PLAT_RECOVERY_IMAGE_ENABLE
+	/* Check if there's a skip request to bootRom recovery Image */
+	if (ble_skip_current_image()) {
+		/* close memory access to all CPn peripherals. */
+		ble_plat_mmap_config(MMAP_RESTORE_SAVED);
+		*skip = 1;
+		return 0;
+	}
+#endif
+	/* Do required CP-110 setups for BLE stage */
+	cp110_ble_init(MVEBU_CP_REGS_BASE(0));
+
+	/* Setup AVS */
+	ble_plat_svc_config();
+
+	/* read clk option from sampled-at-reset register */
+	freq_mode =
+		SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE(
+						 FREQ_MODE_AP_SAR_REG_NUM)));
+
+	/* work with PLL clock driver in AP807 */
+	if (ble_get_ap_type() == CHIP_ID_AP807)
+		ap807_clocks_init(freq_mode);
+
+	/* Do required AP setups for BLE stage */
+	ap_ble_init();
+
+	/* Update DRAM topology (scan DIMM SPDs) */
+	plat_marvell_dram_update_topology();
+
+	/* Kick it in */
+	ret = dram_init();
+
+	/* Restore the original CCU configuration before exit from BLE */
+	ble_plat_mmap_config(MMAP_RESTORE_SAVED);
+
+	return ret;
+}
diff --git a/plat/marvell/a8k/common/plat_pm.c b/plat/marvell/a8k/common/plat_pm.c
new file mode 100644
index 0000000..d07601a
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_pm.c
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/cache_llc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <armada_common.h>
+#include <marvell_pm.h>
+#include <mss_pm_ipc.h>
+#include <plat_marvell.h>
+#include <plat_pm_trace.h>
+
+#define MVEBU_PRIVATE_UID_REG		0x30
+#define MVEBU_RFU_GLOBL_SW_RST		0x84
+#define MVEBU_CCU_RVBAR(cpu)		(MVEBU_REGS_BASE + 0x640 + (cpu * 4))
+#define MVEBU_CCU_CPU_UN_RESET(cpu)	(MVEBU_REGS_BASE + 0x650 + (cpu * 4))
+
+#define MPIDR_CPU_GET(mpidr)		((mpidr) & MPIDR_CPU_MASK)
+#define MPIDR_CLUSTER_GET(mpidr)	MPIDR_AFFLVL1_VAL((mpidr))
+
+#define MVEBU_GPIO_MASK(index)		(1 << (index % 32))
+#define MVEBU_MPP_MASK(index)		(0xF << (4 * (index % 8)))
+#define MVEBU_GPIO_VALUE(index, value)	(value << (index % 32))
+
+#define MVEBU_USER_CMD_0_REG		(MVEBU_DRAM_MAC_BASE + 0x20)
+#define MVEBU_USER_CMD_CH0_OFFSET	28
+#define MVEBU_USER_CMD_CH0_MASK		(1 << MVEBU_USER_CMD_CH0_OFFSET)
+#define MVEBU_USER_CMD_CH0_EN		(1 << MVEBU_USER_CMD_CH0_OFFSET)
+#define MVEBU_USER_CMD_CS_OFFSET	24
+#define MVEBU_USER_CMD_CS_MASK		(0xF << MVEBU_USER_CMD_CS_OFFSET)
+#define MVEBU_USER_CMD_CS_ALL		(0xF << MVEBU_USER_CMD_CS_OFFSET)
+#define MVEBU_USER_CMD_SR_OFFSET	6
+#define MVEBU_USER_CMD_SR_MASK		(0x3 << MVEBU_USER_CMD_SR_OFFSET)
+#define MVEBU_USER_CMD_SR_ENTER		(0x1 << MVEBU_USER_CMD_SR_OFFSET)
+#define MVEBU_MC_PWR_CTRL_REG		(MVEBU_DRAM_MAC_BASE + 0x54)
+#define MVEBU_MC_AC_ON_DLY_OFFSET	8
+#define MVEBU_MC_AC_ON_DLY_MASK		(0xF << MVEBU_MC_AC_ON_DLY_OFFSET)
+#define MVEBU_MC_AC_ON_DLY_DEF_VAR	(8 << MVEBU_MC_AC_ON_DLY_OFFSET)
+#define MVEBU_MC_AC_OFF_DLY_OFFSET	4
+#define MVEBU_MC_AC_OFF_DLY_MASK	(0xF << MVEBU_MC_AC_OFF_DLY_OFFSET)
+#define MVEBU_MC_AC_OFF_DLY_DEF_VAR	(0xC << MVEBU_MC_AC_OFF_DLY_OFFSET)
+#define MVEBU_MC_PHY_AUTO_OFF_OFFSET	0
+#define MVEBU_MC_PHY_AUTO_OFF_MASK	(1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET)
+#define MVEBU_MC_PHY_AUTO_OFF_EN	(1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET)
+
+/* this lock synchronize AP multiple cores execution with MSS */
+DEFINE_BAKERY_LOCK(pm_sys_lock);
+
+/* Weak definitions may be overridden in specific board */
+#pragma weak plat_marvell_get_pm_cfg
+
+/* AP806 CPU power down /power up definitions */
+enum CPU_ID {
+	CPU0,
+	CPU1,
+	CPU2,
+	CPU3
+};
+
+#define REG_WR_VALIDATE_TIMEOUT		(2000)
+
+#define FEATURE_DISABLE_STATUS_REG			\
+			(MVEBU_REGS_BASE + 0x6F8230)
+#define FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET	4
+#define FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK		\
+			(0x1 << FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET)
+
+#ifdef MVEBU_SOC_AP807
+	#define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET		1
+	#define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET	0
+#else
+	#define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET		0
+	#define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET	31
+#endif
+
+#define PWRC_CPUN_CR_REG(cpu_id)		\
+			(MVEBU_REGS_BASE + 0x680000 + (cpu_id * 0x10))
+#define PWRC_CPUN_CR_PWR_DN_RQ_MASK		\
+			(0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET)
+#define PWRC_CPUN_CR_ISO_ENABLE_OFFSET		16
+#define PWRC_CPUN_CR_ISO_ENABLE_MASK		\
+			(0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)
+#define PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK	\
+			(0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)
+
+#define CCU_B_PRCRN_REG(cpu_id)			\
+			(MVEBU_REGS_BASE + 0x1A50 + \
+			((cpu_id / 2) * (0x400)) + ((cpu_id % 2) * 4))
+#define CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET	0
+#define CCU_B_PRCRN_CPUPORESET_STATIC_MASK	\
+			(0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)
+
+/* power switch fingers */
+#define AP807_PWRC_LDO_CR0_REG			\
+			(MVEBU_REGS_BASE + 0x680000 + 0x100)
+#define AP807_PWRC_LDO_CR0_OFFSET		16
+#define AP807_PWRC_LDO_CR0_MASK			\
+			(0xff << AP807_PWRC_LDO_CR0_OFFSET)
+#define AP807_PWRC_LDO_CR0_VAL			0xfc
+
+/*
+ * Power down CPU:
+ * Used to reduce power consumption, and avoid SoC unnecessary temperature rise.
+ */
+static int plat_marvell_cpu_powerdown(int cpu_id)
+{
+	uint32_t	reg_val;
+	int		exit_loop = REG_WR_VALIDATE_TIMEOUT;
+
+	INFO("Powering down CPU%d\n", cpu_id);
+
+	/* 1. Isolation enable */
+	reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+	reg_val |= 0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET;
+	mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+	/* 2. Read and check Isolation enabled - verify bit set to 1 */
+	do {
+		reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+		exit_loop--;
+	} while (!(reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) &&
+		 exit_loop > 0);
+
+	/* 3. Switch off CPU power */
+	reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+	reg_val &= ~PWRC_CPUN_CR_PWR_DN_RQ_MASK;
+	mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+	/* 4. Read and check Switch Off - verify bit set to 0 */
+	exit_loop = REG_WR_VALIDATE_TIMEOUT;
+	do {
+		reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+		exit_loop--;
+	} while (reg_val & PWRC_CPUN_CR_PWR_DN_RQ_MASK && exit_loop > 0);
+
+	if (exit_loop <= 0)
+		goto cpu_poweroff_error;
+
+	/* 5. De-Assert power ready */
+	reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+	reg_val &= ~PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK;
+	mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+	/* 6. Assert CPU POR reset */
+	reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+	reg_val &= ~CCU_B_PRCRN_CPUPORESET_STATIC_MASK;
+	mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val);
+
+	/* 7. Read and poll on Validate the CPU is out of reset */
+	exit_loop = REG_WR_VALIDATE_TIMEOUT;
+	do {
+		reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+		exit_loop--;
+	} while (reg_val & CCU_B_PRCRN_CPUPORESET_STATIC_MASK && exit_loop > 0);
+
+	if (exit_loop <= 0)
+		goto cpu_poweroff_error;
+
+	INFO("Successfully powered down CPU%d\n", cpu_id);
+
+	return 0;
+
+cpu_poweroff_error:
+	ERROR("ERROR: Can't power down CPU%d\n", cpu_id);
+	return -1;
+}
+
+/*
+ * Power down CPUs 1-3 at early boot stage,
+ * to reduce power consumption and SoC temperature.
+ * This is triggered by BLE prior to DDR initialization.
+ *
+ * Note:
+ * All CPUs will be powered up by plat_marvell_cpu_powerup on Linux boot stage,
+ * which is triggered by PSCI ops (pwr_domain_on).
+ */
+int plat_marvell_early_cpu_powerdown(void)
+{
+	uint32_t cpu_cluster_status =
+		mmio_read_32(FEATURE_DISABLE_STATUS_REG) &
+			     FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK;
+	/* if cpu_cluster_status bit is set,
+	 * that means we have only single cluster
+	 */
+	int cluster_count = cpu_cluster_status ? 1 : 2;
+
+	INFO("Powering off unused CPUs\n");
+
+	/* CPU1 is in AP806 cluster-0, which always exists, so power it down */
+	if (plat_marvell_cpu_powerdown(CPU1) == -1)
+		return -1;
+
+	/*
+	 * CPU2-3 are in AP806 2nd cluster (cluster-1),
+	 * which doesn't exists in dual-core systems.
+	 * so need to check if we have dual-core (single cluster)
+	 * or quad-code (2 clusters)
+	 */
+	if (cluster_count == 2) {
+		/* CPU2-3 are part of 2nd cluster */
+		if (plat_marvell_cpu_powerdown(CPU2) == -1)
+			return -1;
+		if (plat_marvell_cpu_powerdown(CPU3) == -1)
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Power up CPU - part of Linux boot stage
+ */
+static int plat_marvell_cpu_powerup(u_register_t mpidr)
+{
+	uint32_t	reg_val;
+	int	cpu_id = MPIDR_CPU_GET(mpidr),
+		cluster = MPIDR_CLUSTER_GET(mpidr);
+	int	exit_loop = REG_WR_VALIDATE_TIMEOUT;
+
+	/* calculate absolute CPU ID */
+	cpu_id = cluster * PLAT_MARVELL_CLUSTER_CORE_COUNT + cpu_id;
+
+	INFO("Powering on CPU%d\n", cpu_id);
+
+#ifdef MVEBU_SOC_AP807
+	/* Activate 2 power switch fingers */
+	reg_val = mmio_read_32(AP807_PWRC_LDO_CR0_REG);
+	reg_val &= ~(AP807_PWRC_LDO_CR0_MASK);
+	reg_val |= (AP807_PWRC_LDO_CR0_VAL << AP807_PWRC_LDO_CR0_OFFSET);
+	mmio_write_32(AP807_PWRC_LDO_CR0_REG, reg_val);
+	udelay(100);
+#endif
+
+	/* 1. Switch CPU power ON */
+	reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+	reg_val |= 0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET;
+	mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+	/* 2. Wait for CPU on, up to 100 uSec: */
+	udelay(100);
+
+	/* 3. Assert power ready */
+	reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+	reg_val |= 0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET;
+	mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+	/* 4. Read & Validate power ready
+	 * used in order to generate 16 Host CPU cycles
+	 */
+	do {
+		reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+		exit_loop--;
+	} while (!(reg_val & (0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)) &&
+		 exit_loop > 0);
+
+	if (exit_loop <= 0)
+		goto cpu_poweron_error;
+
+	/* 5. Isolation disable */
+	reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+	reg_val &= ~PWRC_CPUN_CR_ISO_ENABLE_MASK;
+	mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val);
+
+	/* 6. Read and check Isolation enabled - verify bit set to 1 */
+	exit_loop = REG_WR_VALIDATE_TIMEOUT;
+	do {
+		reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id));
+		exit_loop--;
+	} while ((reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) &&
+		 exit_loop > 0);
+
+	/* 7. De Assert CPU POR reset & Core reset */
+	reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+	reg_val |= 0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET;
+	mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val);
+
+	/* 8. Read & Validate CPU POR reset */
+	exit_loop = REG_WR_VALIDATE_TIMEOUT;
+	do {
+		reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id));
+		exit_loop--;
+	} while (!(reg_val & (0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)) &&
+		 exit_loop > 0);
+
+	if (exit_loop <= 0)
+		goto cpu_poweron_error;
+
+	INFO("Successfully powered on CPU%d\n", cpu_id);
+
+	return 0;
+
+cpu_poweron_error:
+	ERROR("ERROR: Can't power up CPU%d\n", cpu_id);
+	return -1;
+}
+
+static int plat_marvell_cpu_on(u_register_t mpidr)
+{
+	int cpu_id;
+	int cluster;
+
+	/* Set barierr */
+	dsbsy();
+
+	/* Get cpu number - use CPU ID */
+	cpu_id =  MPIDR_CPU_GET(mpidr);
+
+	/* Get cluster number - use affinity level 1 */
+	cluster = MPIDR_CLUSTER_GET(mpidr);
+
+	/* Set CPU private UID */
+	mmio_write_32(MVEBU_REGS_BASE + MVEBU_PRIVATE_UID_REG, cluster + 0x4);
+
+	/* Set the cpu start address to BL1 entry point (align to 0x10000) */
+	mmio_write_32(MVEBU_CCU_RVBAR(cpu_id),
+		      PLAT_MARVELL_CPU_ENTRY_ADDR >> 16);
+
+	/* Get the cpu out of reset */
+	mmio_write_32(MVEBU_CCU_CPU_UN_RESET(cpu_id), 0x10001);
+
+	return 0;
+}
+
+/*****************************************************************************
+ * A8K handler called to check the validity of the power state
+ * parameter.
+ *****************************************************************************
+ */
+static int a8k_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != MARVELL_PWR_LVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MARVELL_PWR_LVL0] =
+					MARVELL_LOCAL_STATE_RET;
+	} else {
+		for (i = MARVELL_PWR_LVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					MARVELL_LOCAL_STATE_OFF;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+/*****************************************************************************
+ * A8K handler called when a CPU is about to enter standby.
+ *****************************************************************************
+ */
+static void a8k_cpu_standby(plat_local_state_t cpu_state)
+{
+	if (!is_pm_fw_running()) {
+		ERROR("%s: needs to be implemented\n", __func__);
+		panic();
+	}
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ *****************************************************************************
+ */
+static int a8k_pwr_domain_on(u_register_t mpidr)
+{
+	/* Power up CPU (CPUs 1-3 are powered off at start of BLE) */
+	plat_marvell_cpu_powerup(mpidr);
+
+	if (is_pm_fw_running()) {
+		unsigned int target =
+				((mpidr & 0xFF) + (((mpidr >> 8) & 0xFF) * 2));
+
+		/*
+		 * pm system synchronization - used to synchronize
+		 * multiple core access to MSS
+		 */
+		bakery_lock_get(&pm_sys_lock);
+
+		/* send CPU ON IPC Message to MSS */
+		mss_pm_ipc_msg_send(target, PM_IPC_MSG_CPU_ON, 0);
+
+		/* trigger IPC message to MSS */
+		mss_pm_ipc_msg_trigger();
+
+		/* pm system synchronization */
+		bakery_lock_release(&pm_sys_lock);
+
+		/* trace message */
+		PM_TRACE(TRACE_PWR_DOMAIN_ON | target);
+	} else {
+		/* proprietary CPU ON exection flow */
+		plat_marvell_cpu_on(mpidr);
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+ * A8K handler called to validate the entry point.
+ *****************************************************************************
+ */
+static int a8k_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	return PSCI_E_SUCCESS;
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	if (is_pm_fw_running()) {
+		unsigned int idx = plat_my_core_pos();
+
+		/* Prevent interrupts from spuriously waking up this cpu */
+		gicv2_cpuif_disable();
+
+		/* pm system synchronization - used to synchronize multiple
+		 * core access to MSS
+		 */
+		bakery_lock_get(&pm_sys_lock);
+
+		/* send CPU OFF IPC Message to MSS */
+		mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_OFF, target_state);
+
+		/* trigger IPC message to MSS */
+		mss_pm_ipc_msg_trigger();
+
+		/* pm system synchronization */
+		bakery_lock_release(&pm_sys_lock);
+
+		/* trace message */
+		PM_TRACE(TRACE_PWR_DOMAIN_OFF);
+	} else {
+		INFO("%s: is not supported without SCP\n", __func__);
+	}
+}
+
+/* Get PM config to power off the SoC */
+void *plat_marvell_get_pm_cfg(void)
+{
+	return NULL;
+}
+
+/*
+ * This function should be called on restore from
+ * "suspend to RAM" state when the execution flow
+ * has to bypass BootROM image to RAM copy and speed up
+ * the system recovery
+ *
+ */
+static void plat_marvell_exit_bootrom(void)
+{
+	marvell_exit_bootrom(PLAT_MARVELL_TRUSTED_ROM_BASE);
+}
+
+/*
+ * Prepare for the power off of the system via GPIO
+ */
+static void plat_marvell_power_off_gpio(struct power_off_method *pm_cfg,
+					register_t *gpio_addr,
+					register_t *gpio_data)
+{
+	unsigned int gpio;
+	unsigned int idx;
+	unsigned int shift;
+	unsigned int reg;
+	unsigned int addr;
+	gpio_info_t *info;
+	unsigned int tog_bits;
+
+	assert((pm_cfg->cfg.gpio.pin_count < PMIC_GPIO_MAX_NUMBER) &&
+	       (pm_cfg->cfg.gpio.step_count < PMIC_GPIO_MAX_TOGGLE_STEP));
+
+	/* Prepare GPIOs for PMIC */
+	for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) {
+		info = &pm_cfg->cfg.gpio.info[gpio];
+		/* Set PMIC GPIO to output mode */
+		reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT_EN(
+				   info->cp_index, info->gpio_index));
+		mmio_write_32(MVEBU_CP_GPIO_DATA_OUT_EN(
+			      info->cp_index, info->gpio_index),
+			      reg & ~MVEBU_GPIO_MASK(info->gpio_index));
+
+		/* Set the appropriate MPP to GPIO mode */
+		reg = mmio_read_32(MVEBU_PM_MPP_REGS(info->cp_index,
+						     info->gpio_index));
+		mmio_write_32(MVEBU_PM_MPP_REGS(info->cp_index,
+						info->gpio_index),
+			reg & ~MVEBU_MPP_MASK(info->gpio_index));
+	}
+
+	/* Wait for MPP & GPIO pre-configurations done */
+	mdelay(pm_cfg->cfg.gpio.delay_ms);
+
+	/* Toggle the GPIO values, and leave final step to be triggered
+	 * after  DDR self-refresh is enabled
+	 */
+	for (idx = 0; idx < pm_cfg->cfg.gpio.step_count; idx++) {
+		tog_bits = pm_cfg->cfg.gpio.seq[idx];
+
+		/* The GPIOs must be within same GPIO register,
+		 * thus could get the original value by first GPIO
+		 */
+		info = &pm_cfg->cfg.gpio.info[0];
+		reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT(
+				   info->cp_index, info->gpio_index));
+		addr = MVEBU_CP_GPIO_DATA_OUT(info->cp_index, info->gpio_index);
+
+		for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) {
+			shift = pm_cfg->cfg.gpio.info[gpio].gpio_index % 32;
+			if (GPIO_LOW == (tog_bits & (1 << gpio)))
+				reg &= ~(1 << shift);
+			else
+				reg |= (1 << shift);
+		}
+
+		/* Set the GPIO register, for last step just store
+		 * register address and values to system registers
+		 */
+		if (idx < pm_cfg->cfg.gpio.step_count - 1) {
+			mmio_write_32(MVEBU_CP_GPIO_DATA_OUT(
+				      info->cp_index, info->gpio_index), reg);
+			mdelay(pm_cfg->cfg.gpio.delay_ms);
+		} else {
+			/* Save GPIO register and address values for
+			 * finishing the power down operation later
+			 */
+			*gpio_addr = addr;
+			*gpio_data = reg;
+		}
+	}
+}
+
+/*
+ * Prepare for the power off of the system
+ */
+static void plat_marvell_power_off_prepare(struct power_off_method *pm_cfg,
+					   register_t *addr, register_t *data)
+{
+	switch (pm_cfg->type) {
+	case PMIC_GPIO:
+		plat_marvell_power_off_gpio(pm_cfg, addr, data);
+		break;
+	default:
+		break;
+	}
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	if (is_pm_fw_running()) {
+		unsigned int idx;
+
+		/* Prevent interrupts from spuriously waking up this cpu */
+		gicv2_cpuif_disable();
+
+		idx = plat_my_core_pos();
+
+		/* pm system synchronization - used to synchronize multiple
+		 * core access to MSS
+		 */
+		bakery_lock_get(&pm_sys_lock);
+
+		/* send CPU Suspend IPC Message to MSS */
+		mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_SUSPEND, target_state);
+
+		/* trigger IPC message to MSS */
+		mss_pm_ipc_msg_trigger();
+
+		/* pm system synchronization */
+		bakery_lock_release(&pm_sys_lock);
+
+		/* trace message */
+		PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND);
+	} else {
+		uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+		INFO("Suspending to RAM\n");
+
+		marvell_console_runtime_end();
+
+		/* Prevent interrupts from spuriously waking up this cpu */
+		gicv2_cpuif_disable();
+
+		mailbox[MBOX_IDX_SUSPEND_MAGIC] = MVEBU_MAILBOX_SUSPEND_STATE;
+		mailbox[MBOX_IDX_ROM_EXIT_ADDR] = (uintptr_t)&plat_marvell_exit_bootrom;
+
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+		flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE +
+		MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t),
+		2 * sizeof(uintptr_t));
+#endif
+		/* Flush and disable LLC before going off-power */
+		llc_disable(0);
+
+		isb();
+		/*
+		 * Do not halt here!
+		 * The function must return for allowing the caller function
+		 * psci_power_up_finish() to do the proper context saving and
+		 * to release the CPU lock.
+		 */
+	}
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* arch specific configuration */
+	marvell_psci_arch_init(0);
+
+	/* Interrupt initialization */
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	if (is_pm_fw_running()) {
+		/* trace message */
+		PM_TRACE(TRACE_PWR_DOMAIN_ON_FINISH);
+	}
+}
+
+/*****************************************************************************
+ * A8K handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ *****************************************************************************
+ */
+static void a8k_pwr_domain_suspend_finish(
+					const psci_power_state_t *target_state)
+{
+	if (is_pm_fw_running()) {
+		/* arch specific configuration */
+		marvell_psci_arch_init(0);
+
+		/* Interrupt initialization */
+		gicv2_cpuif_enable();
+
+		/* trace message */
+		PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND_FINISH);
+	} else {
+		uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+		/* Only primary CPU requres platform init */
+		if (!plat_my_core_pos()) {
+			/* Initialize the console to provide
+			 * early debug support
+			 */
+			marvell_console_runtime_init();
+
+			bl31_plat_arch_setup();
+			marvell_bl31_platform_setup();
+			/*
+			 * Remove suspend to RAM marker from the mailbox
+			 * for treating a regular reset as a cold boot
+			 */
+			mailbox[MBOX_IDX_SUSPEND_MAGIC] = 0;
+			mailbox[MBOX_IDX_ROM_EXIT_ADDR] = 0;
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+			flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE +
+			MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t),
+			2 * sizeof(uintptr_t));
+#endif
+		}
+	}
+}
+
+/*****************************************************************************
+ * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
+ * call to get the `power_state` parameter. This allows the platform to encode
+ * the appropriate State-ID field within the `power_state` parameter which can
+ * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
+ *****************************************************************************
+ */
+static void a8k_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	/* lower affinities use PLAT_MAX_OFF_STATE */
+	for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static void
+__dead2 a8k_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+	struct power_off_method *pm_cfg;
+	unsigned int srcmd;
+	unsigned int sdram_reg;
+	register_t gpio_data = 0, gpio_addr = 0;
+
+	if (is_pm_fw_running()) {
+		psci_power_down_wfi();
+		panic();
+	}
+
+	pm_cfg = (struct power_off_method *)plat_marvell_get_pm_cfg();
+
+	/* Prepare for power off */
+	plat_marvell_power_off_prepare(pm_cfg, &gpio_addr, &gpio_data);
+
+	/* First step to enable DDR self-refresh
+	 * to keep the data during suspend
+	 */
+	mmio_write_32(MVEBU_MC_PWR_CTRL_REG, 0x8C1);
+
+	/* Save DDR self-refresh second step register
+	 * and value to be issued later
+	 */
+	sdram_reg = MVEBU_USER_CMD_0_REG;
+	srcmd = mmio_read_32(sdram_reg);
+	srcmd &= ~(MVEBU_USER_CMD_CH0_MASK | MVEBU_USER_CMD_CS_MASK |
+		 MVEBU_USER_CMD_SR_MASK);
+	srcmd |= (MVEBU_USER_CMD_CH0_EN | MVEBU_USER_CMD_CS_ALL |
+		 MVEBU_USER_CMD_SR_ENTER);
+
+	/*
+	 * Wait for DRAM is done using registers access only.
+	 * At this stage any access to DRAM (procedure call) will
+	 * release it from the self-refresh mode
+	 */
+	__asm__ volatile (
+		/* Align to a cache line */
+		"	.balign 64\n\t"
+
+		/* Enter self refresh */
+		"	str %[srcmd], [%[sdram_reg]]\n\t"
+
+		/*
+		 * Wait 100 cycles for DDR to enter self refresh, by
+		 * doing 50 times two instructions.
+		 */
+		"	mov x1, #50\n\t"
+		"1:	subs x1, x1, #1\n\t"
+		"	bne 1b\n\t"
+
+		/* Issue the command to trigger the SoC power off */
+		"	str	%[gpio_data], [%[gpio_addr]]\n\t"
+
+		/* Trap the processor */
+		"	b .\n\t"
+		: : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
+		    [gpio_addr] "r" (gpio_addr),  [gpio_data] "r" (gpio_data)
+		: "x1");
+
+	panic();
+}
+
+/*****************************************************************************
+ * A8K handlers to shutdown/reboot the system
+ *****************************************************************************
+ */
+static void __dead2 a8k_system_off(void)
+{
+	ERROR("%s:  needs to be implemented\n", __func__);
+	panic();
+}
+
+void plat_marvell_system_reset(void)
+{
+	mmio_write_32(MVEBU_RFU_BASE + MVEBU_RFU_GLOBL_SW_RST, 0x0);
+}
+
+static void __dead2 a8k_system_reset(void)
+{
+	plat_marvell_system_reset();
+
+	/* we shouldn't get to this point */
+	panic();
+}
+
+/*****************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform layer will take care of registering the handlers with PSCI.
+ *****************************************************************************
+ */
+const plat_psci_ops_t plat_arm_psci_pm_ops = {
+	.cpu_standby = a8k_cpu_standby,
+	.pwr_domain_on = a8k_pwr_domain_on,
+	.pwr_domain_off = a8k_pwr_domain_off,
+	.pwr_domain_suspend = a8k_pwr_domain_suspend,
+	.pwr_domain_on_finish = a8k_pwr_domain_on_finish,
+	.get_sys_suspend_power_state = a8k_get_sys_suspend_power_state,
+	.pwr_domain_suspend_finish = a8k_pwr_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi = a8k_pwr_domain_pwr_down_wfi,
+	.system_off = a8k_system_off,
+	.system_reset = a8k_system_reset,
+	.validate_power_state = a8k_validate_power_state,
+	.validate_ns_entrypoint = a8k_validate_ns_entrypoint
+};
diff --git a/plat/marvell/a8k/common/plat_pm_trace.c b/plat/marvell/a8k/common/plat_pm_trace.c
new file mode 100644
index 0000000..f589ff3
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_pm_trace.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <mss_mem.h>
+#include <plat_pm_trace.h>
+
+#ifdef PM_TRACE_ENABLE
+
+/* core trace APIs */
+core_trace_func funcTbl[PLATFORM_CORE_COUNT] = {
+	pm_core_0_trace,
+	pm_core_1_trace,
+	pm_core_2_trace,
+	pm_core_3_trace};
+
+/*****************************************************************************
+ * pm_core0_trace
+ * pm_core1_trace
+ * pm_core2_trace
+ * pm_core_3trace
+ *
+ * This functions set trace info into core cyclic trace queue in MSS SRAM
+ * memory space
+ *****************************************************************************
+ */
+void pm_core_0_trace(unsigned int trace)
+{
+	unsigned int current_position_core_0 =
+			mmio_read_32(AP_MSS_ATF_CORE_0_CTRL_BASE);
+	mmio_write_32((AP_MSS_ATF_CORE_0_INFO_BASE  +
+		     (current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     mmio_read_32(AP_MSS_TIMER_BASE));
+	mmio_write_32((AP_MSS_ATF_CORE_0_INFO_TRACE +
+		     (current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     trace);
+	mmio_write_32(AP_MSS_ATF_CORE_0_CTRL_BASE,
+		     ((current_position_core_0 + 1) &
+		     AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+
+void pm_core_1_trace(unsigned int trace)
+{
+	unsigned int current_position_core_1 =
+			mmio_read_32(AP_MSS_ATF_CORE_1_CTRL_BASE);
+	mmio_write_32((AP_MSS_ATF_CORE_1_INFO_BASE +
+		     (current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     mmio_read_32(AP_MSS_TIMER_BASE));
+	mmio_write_32((AP_MSS_ATF_CORE_1_INFO_TRACE +
+		     (current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     trace);
+	mmio_write_32(AP_MSS_ATF_CORE_1_CTRL_BASE,
+		     ((current_position_core_1 + 1) &
+		     AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+
+void pm_core_2_trace(unsigned int trace)
+{
+	unsigned int current_position_core_2 =
+			mmio_read_32(AP_MSS_ATF_CORE_2_CTRL_BASE);
+	mmio_write_32((AP_MSS_ATF_CORE_2_INFO_BASE +
+		     (current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     mmio_read_32(AP_MSS_TIMER_BASE));
+	mmio_write_32((AP_MSS_ATF_CORE_2_INFO_TRACE +
+		     (current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     trace);
+	mmio_write_32(AP_MSS_ATF_CORE_2_CTRL_BASE,
+		     ((current_position_core_2 + 1) &
+		     AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+
+void pm_core_3_trace(unsigned int trace)
+{
+	unsigned int current_position_core_3 =
+			mmio_read_32(AP_MSS_ATF_CORE_3_CTRL_BASE);
+	mmio_write_32((AP_MSS_ATF_CORE_3_INFO_BASE +
+		     (current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     mmio_read_32(AP_MSS_TIMER_BASE));
+	mmio_write_32((AP_MSS_ATF_CORE_3_INFO_TRACE +
+		     (current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)),
+		     trace);
+	mmio_write_32(AP_MSS_ATF_CORE_3_CTRL_BASE,
+		     ((current_position_core_3 + 1) &
+		     AP_MSS_ATF_TRACE_SIZE_MASK));
+}
+#endif /* PM_TRACE_ENABLE */
diff --git a/plat/marvell/a8k/common/plat_thermal.c b/plat/marvell/a8k/common/plat_thermal.c
new file mode 100644
index 0000000..a2fc0d0
--- /dev/null
+++ b/plat/marvell/a8k/common/plat_thermal.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/marvell/thermal.h>
+#include <lib/mmio.h>
+
+#include <mvebu_def.h>
+
+#define THERMAL_TIMEOUT					1200
+
+#define THERMAL_SEN_CTRL_LSB_STRT_OFFSET		0
+#define THERMAL_SEN_CTRL_LSB_STRT_MASK			\
+				(0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET)
+#define THERMAL_SEN_CTRL_LSB_RST_OFFSET			1
+#define THERMAL_SEN_CTRL_LSB_RST_MASK			\
+				(0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET)
+#define THERMAL_SEN_CTRL_LSB_EN_OFFSET			2
+#define THERMAL_SEN_CTRL_LSB_EN_MASK			\
+				(0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET)
+
+#define THERMAL_SEN_CTRL_STATS_VALID_OFFSET		16
+#define THERMAL_SEN_CTRL_STATS_VALID_MASK		\
+				(0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET)
+#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET		0
+#define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK		\
+			(0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET)
+
+#define THERMAL_SEN_OUTPUT_MSB				512
+#define THERMAL_SEN_OUTPUT_COMP				1024
+
+struct tsen_regs {
+	uint32_t ext_tsen_ctrl_lsb;
+	uint32_t ext_tsen_ctrl_msb;
+	uint32_t ext_tsen_status;
+};
+
+static int ext_tsen_probe(struct tsen_config *tsen_cfg)
+{
+	uint32_t reg, timeout = 0;
+	struct tsen_regs *base;
+
+	if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) {
+		ERROR("initial thermal sensor configuration is missing\n");
+		return -1;
+	}
+	base = (struct tsen_regs *)tsen_cfg->regs_base;
+
+	INFO("initializing thermal sensor\n");
+
+	/* initialize thermal sensor hardware reset once */
+	reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb);
+	reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */
+	reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */
+	reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */
+	mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg);
+
+	reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
+	while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 &&
+	       timeout < THERMAL_TIMEOUT) {
+		udelay(100);
+		reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
+		timeout++;
+	}
+
+	if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) {
+		ERROR("thermal sensor is not ready\n");
+		return -1;
+	}
+
+	tsen_cfg->tsen_ready = 1;
+
+	VERBOSE("thermal sensor was initialized\n");
+
+	return 0;
+}
+
+static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp)
+{
+	uint32_t reg;
+	struct tsen_regs *base;
+
+	if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) {
+		ERROR("thermal sensor was not initialized\n");
+		return -1;
+	}
+	base = (struct tsen_regs *)tsen_cfg->regs_base;
+
+	reg = mmio_read_32((uintptr_t)&base->ext_tsen_status);
+	reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >>
+		THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET);
+
+	/*
+	 * TSEN output format is signed as a 2s complement number
+	 * ranging from-512 to +511. when MSB is set, need to
+	 * calculate the complement number
+	 */
+	if (reg >= THERMAL_SEN_OUTPUT_MSB)
+		reg -= THERMAL_SEN_OUTPUT_COMP;
+
+	if (tsen_cfg->tsen_divisor == 0) {
+		ERROR("thermal sensor divisor cannot be zero\n");
+		return -1;
+	}
+
+	*temp = ((tsen_cfg->tsen_gain * ((int)reg)) +
+		 tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor;
+
+	return 0;
+}
+
+static struct tsen_config tsen_cfg = {
+	.tsen_offset = 153400,
+	.tsen_gain = 425,
+	.tsen_divisor = 1000,
+	.tsen_ready = 0,
+	.regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE,
+	.ptr_tsen_probe = ext_tsen_probe,
+	.ptr_tsen_read = ext_tsen_read
+};
+
+struct tsen_config *marvell_thermal_config_get(void)
+{
+	return &tsen_cfg;
+}
diff --git a/plat/marvell/common/aarch64/marvell_bl2_mem_params_desc.c b/plat/marvell/common/aarch64/marvell_bl2_mem_params_desc.c
new file mode 100644
index 0000000..6a8e11c
--- /dev/null
+++ b/plat/marvell/common/aarch64/marvell_bl2_mem_params_desc.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <marvell_def.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef SCP_BL2_BASE
+	/* Fill SCP_BL2 related information if it exists */
+    {
+	    .image_id = SCP_BL2_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = SCP_BL2_BASE,
+	    .image_info.image_max_size = SCP_BL2_SIZE,
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+#endif /* SCP_BL2_BASE */
+
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload)*/
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = EL3_PAYLOAD_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t,
+		    IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    },
+
+#else /* EL3_PAYLOAD_BASE */
+
+	/* Fill BL31 related information */
+    {
+	    .image_id = BL31_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t,
+		    SECURE | EXECUTABLE | EP_FIRST_EXE),
+	    .ep_info.pc = BL31_BASE,
+	    .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+		    DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+	    .ep_info.args.arg3 = MARVELL_BL31_PLAT_PARAM_VAL,
+#endif
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+	    .image_info.image_base = BL31_BASE,
+	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+	    .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+    },
+
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+    {
+	    .image_id = BL32_IMAGE_ID,
+
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),
+	    .ep_info.pc = BL32_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = BL32_BASE,
+	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+    },
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+    {
+	    .image_id = BL33_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+	    .ep_info.pc = PRELOADED_BL33_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+# else
+	    .ep_info.pc = MARVELL_DRAM_BASE,
+
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = MARVELL_DRAM_BASE,
+	    .image_info.image_max_size = MARVELL_DRAM_SIZE,
+# endif /* PRELOADED_BL33_BASE */
+
+	    .next_handoff_image_id = INVALID_IMAGE_ID,
+    }
+#endif /* EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/marvell/common/aarch64/marvell_common.c b/plat/marvell/common/aarch64/marvell_common.c
new file mode 100644
index 0000000..21a62d4
--- /dev/null
+++ b/plat/marvell/common/aarch64/marvell_common.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <plat_marvell.h>
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_get_ns_image_entrypoint
+#pragma weak plat_marvell_get_mmap
+
+/*
+ * Set up the page tables for the generic and platform-specific memory regions.
+ * The extents of the generic memory regions are specified by the function
+ * arguments and consist of:
+ * - Trusted SRAM seen by the BL image;
+ * - Code section;
+ * - Read-only data section;
+ * - Coherent memory region, if applicable.
+ */
+void marvell_setup_page_tables(uintptr_t total_base,
+			       size_t total_size,
+			       uintptr_t code_start,
+			       uintptr_t code_limit,
+			       uintptr_t rodata_start,
+			       uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			       ,
+			       uintptr_t coh_start,
+			       uintptr_t coh_limit
+#endif
+			   )
+{
+	/*
+	 * Map the Trusted SRAM with appropriate memory attributes.
+	 * Subsequent mappings will adjust the attributes for specific regions.
+	 */
+	VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+		(void *) total_base, (void *) (total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+
+	/* Re-map the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *) code_start, (void *) code_limit);
+	mmap_add_region(code_start, code_start,
+			code_limit - code_start,
+			MT_CODE | MT_SECURE);
+
+	/* Re-map the read-only data section */
+	VERBOSE("Read-only data region: %p - %p\n",
+		(void *) rodata_start, (void *) rodata_limit);
+	mmap_add_region(rodata_start, rodata_start,
+			rodata_limit - rodata_start,
+			MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+	/* Re-map the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *) coh_start, (void *) coh_limit);
+	mmap_add_region(coh_start, coh_start,
+			coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	/* Now (re-)map the platform-specific memory regions */
+	mmap_add(plat_marvell_get_mmap());
+
+	/* Create the page tables to reflect the above mappings */
+	init_xlat_tables();
+}
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+	return PLAT_MARVELL_NS_IMAGE_OFFSET;
+}
+
+/*****************************************************************************
+ * Gets SPSR for BL32 entry
+ *****************************************************************************
+ */
+uint32_t marvell_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/*****************************************************************************
+ * Gets SPSR for BL33 entry
+ *****************************************************************************
+ */
+uint32_t marvell_get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+/*****************************************************************************
+ * Returns ARM platform specific memory map regions.
+ *****************************************************************************
+ */
+const mmap_region_t *plat_marvell_get_mmap(void)
+{
+	return plat_marvell_mmap;
+}
+
diff --git a/plat/marvell/common/aarch64/marvell_helpers.S b/plat/marvell/common/aarch64/marvell_helpers.S
new file mode 100644
index 0000000..6f625b9
--- /dev/null
+++ b/plat/marvell/common/aarch64/marvell_helpers.S
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <asm_macros.S>
+#include <cortex_a72.h>
+#ifndef PLAT_a3700
+#include <drivers/marvell/ccu.h>
+#include <drivers/marvell/cache_llc.h>
+#endif
+#include <marvell_def.h>
+#include <platform_def.h>
+
+	.weak	plat_marvell_calc_core_pos
+	.weak	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	platform_mem_init
+	.globl	disable_mmu_dcache
+	.globl	invalidate_tlb_all
+	.globl	platform_unmap_sram
+	.globl	disable_sram
+	.globl	disable_icache
+	.globl	invalidate_icache_all
+	.globl	marvell_exit_bootrom
+	.globl	ca72_l2_enable_unique_clean
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_marvell_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_marvell_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_marvell_calc_core_pos(uint64_t mpidr)
+	 *  Helper function to calculate the core position.
+	 *  With this function: CorePos = (ClusterId * 2) +
+	 *  				  CoreId
+	 * -----------------------------------------------------
+	 */
+func plat_marvell_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #7
+	ret
+endfunc plat_marvell_calc_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, PLAT_MARVELL_CRASH_UART_BASE
+	mov_imm	x1, PLAT_MARVELL_CRASH_UART_CLK_IN_HZ
+	mov_imm	x2, MARVELL_CONSOLE_BAUDRATE
+#ifdef PLAT_a3700
+	b	console_a3700_core_init
+#else
+	b	console_16550_core_init
+#endif
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, PLAT_MARVELL_CRASH_UART_BASE
+#ifdef PLAT_a3700
+
+	b	console_a3700_core_putc
+#else
+	b	console_16550_core_putc
+#endif
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, PLAT_MARVELL_CRASH_UART_BASE
+#ifdef PLAT_a3700
+	b	console_a3700_core_flush
+#else
+	b	console_16550_core_flush
+#endif
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on ARM
+	 * platforms. The Secure RAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* -----------------------------------------------------
+	 * Disable icache, dcache, and MMU
+	 * -----------------------------------------------------
+	 */
+func disable_mmu_dcache
+	mrs	x0, sctlr_el3
+	bic	x0, x0, 0x1		/* M bit - MMU */
+	bic	x0, x0, 0x4		/* C bit - Dcache L1 & L2 */
+	msr	sctlr_el3, x0
+	isb
+	b	mmu_off
+mmu_off:
+	ret
+endfunc disable_mmu_dcache
+
+	/* -----------------------------------------------------
+	 * Disable all TLB entries
+	 * -----------------------------------------------------
+	 */
+func invalidate_tlb_all
+	tlbi	alle3
+	dsb	sy
+	isb
+	ret
+endfunc invalidate_tlb_all
+
+	/* -----------------------------------------------------
+	 * Disable the i cache
+	 * -----------------------------------------------------
+	 */
+func disable_icache
+	mrs 	x0, sctlr_el3
+	bic	x0, x0, 0x1000	/* I bit - Icache L1 & L2 */
+	msr	sctlr_el3, x0
+	isb
+	ret
+endfunc disable_icache
+
+	/* -----------------------------------------------------
+	 * Disable all of the i caches
+	 * -----------------------------------------------------
+	 */
+func invalidate_icache_all
+	ic	ialluis
+	isb	sy
+	ret
+endfunc invalidate_icache_all
+
+	/* -----------------------------------------------------
+	 * Clear the SRAM enabling bit to unmap SRAM
+	 * -----------------------------------------------------
+	 */
+func platform_unmap_sram
+	ldr	x0, =CCU_SRAM_WIN_CR
+	str	wzr, [x0]
+	ret
+endfunc platform_unmap_sram
+
+	/* -----------------------------------------------------
+	 * Disable the SRAM
+	 * -----------------------------------------------------
+	 */
+func disable_sram
+	/* Disable the line lockings. They must be disabled expictly
+	 * or the OS will have problems using the cache */
+	ldr	x1, =MASTER_LLC_TC0_LOCK
+	str	wzr, [x1]
+
+	/* Invalidate all ways */
+	ldr	w1, =LLC_WAY_MASK
+	ldr	x0, =MASTER_L2X0_INV_WAY
+	str	w1, [x0]
+
+	/* Finally disable LLC */
+	ldr	x0, =MASTER_LLC_CTRL
+	str	wzr, [x0]
+
+	ret
+endfunc disable_sram
+
+	/* -----------------------------------------------------
+	 * Operation when exit bootROM:
+	 * Disable the MMU
+	 * Disable and invalidate the dcache
+	 * Unmap and disable the SRAM
+	 * Disable and invalidate the icache
+	 * -----------------------------------------------------
+	 */
+func marvell_exit_bootrom
+	/* Save the system restore address */
+	mov	x28, x0
+
+	/* Close the caches and MMU */
+	bl	disable_mmu_dcache
+
+	/*
+	 * There is nothing important in the caches now,
+	 * so invalidate them instead of cleaning.
+	 */
+	adr	x0, __RW_START__
+	adr	x1, __RW_END__
+	sub	x1, x1, x0
+	bl	inv_dcache_range
+	bl	invalidate_tlb_all
+
+	/*
+	 * Clean the memory mapping of SRAM
+	 * the DDR mapping will remain to enable boot image to execute
+	 */
+	bl	platform_unmap_sram
+
+	/* Disable the SRAM */
+	bl	disable_sram
+
+	/* Disable and invalidate icache */
+	bl	disable_icache
+	bl	invalidate_icache_all
+
+	mov	x0, x28
+	br	x0
+endfunc marvell_exit_bootrom
+
+	/*
+	 * Enable L2 UniqueClean evictions with data
+	 */
+func ca72_l2_enable_unique_clean
+
+	mrs	x0, CORTEX_A72_L2ACTLR_EL1
+	orr	x0, x0, #CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN
+	msr	CORTEX_A72_L2ACTLR_EL1, x0
+
+	ret
+endfunc ca72_l2_enable_unique_clean
diff --git a/plat/marvell/common/marvell_bl1_setup.c b/plat/marvell/common/marvell_bl1_setup.c
new file mode 100644
index 0000000..7b7cef3
--- /dev/null
+++ b/plat/marvell/common/marvell_bl1_setup.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/sp805.h>
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#include <plat_marvell.h>
+
+/* Weak definitions may be overridden in specific Marvell standard platform */
+#pragma weak bl1_early_platform_setup
+#pragma weak bl1_plat_arch_setup
+#pragma weak bl1_platform_setup
+#pragma weak bl1_plat_sec_mem_layout
+
+/* Data structure which holds the extents of the RAM for BL1*/
+static meminfo_t bl1_ram_layout;
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_ram_layout;
+}
+
+/*
+ * BL1 specific platform actions shared between Marvell standard platforms.
+ */
+void marvell_bl1_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	marvell_console_boot_init();
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_ram_layout.total_base = MARVELL_BL_RAM_BASE;
+	bl1_ram_layout.total_size = MARVELL_BL_RAM_SIZE;
+}
+
+void bl1_early_platform_setup(void)
+{
+	marvell_bl1_early_platform_setup();
+}
+
+/*
+ * Perform the very early platform specific architecture setup shared between
+ * MARVELL standard platforms. This only does basic initialization. Later
+ * architectural setup (bl1_arch_setup()) does not do anything platform
+ * specific.
+ */
+void marvell_bl1_plat_arch_setup(void)
+{
+	marvell_setup_page_tables(bl1_ram_layout.total_base,
+				  bl1_ram_layout.total_size,
+				  BL1_RO_BASE,
+				  BL1_RO_LIMIT,
+				  BL1_RO_DATA_BASE,
+				  BL1_RO_DATA_END
+#if USE_COHERENT_MEM
+				, BL_COHERENT_RAM_BASE,
+				  BL_COHERENT_RAM_END
+#endif
+				);
+	enable_mmu_el3(0);
+}
+
+void bl1_plat_arch_setup(void)
+{
+	marvell_bl1_plat_arch_setup();
+}
+
+/*
+ * Perform the platform specific architecture setup shared between
+ * MARVELL standard platforms.
+ */
+void marvell_bl1_platform_setup(void)
+{
+	/* Initialise the IO layer and register platform IO devices */
+	plat_marvell_io_setup();
+}
+
+void bl1_platform_setup(void)
+{
+	marvell_bl1_platform_setup();
+}
+
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
+{
+#ifdef EL3_PAYLOAD_BASE
+	/*
+	 * Program the EL3 payload's entry point address into the CPUs mailbox
+	 * in order to release secondary CPUs from their holding pen and make
+	 * them jump there.
+	 */
+	marvell_program_trusted_mailbox(ep_info->pc);
+	dsbsy();
+	sev();
+#endif
+}
diff --git a/plat/marvell/common/marvell_bl2_setup.c b/plat/marvell/common/marvell_bl2_setup.c
new file mode 100644
index 0000000..3c1c391
--- /dev/null
+++ b/plat/marvell/common/marvell_bl2_setup.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <lib/utils.h>
+
+#include <marvell_def.h>
+#include <plat_marvell.h>
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/* Weak definitions may be overridden in specific MARVELL standard platform */
+#pragma weak bl2_early_platform_setup2
+#pragma weak bl2_platform_setup
+#pragma weak bl2_plat_arch_setup
+#pragma weak bl2_plat_sec_mem_layout
+
+meminfo_t *bl2_plat_sec_mem_layout(void)
+{
+	return &bl2_tzram_layout;
+}
+
+/*****************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ *****************************************************************************
+ */
+void marvell_bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+	/* Initialize the console to provide early debug support */
+	marvell_console_boot_init();
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+
+	/* Initialise the IO layer and register platform IO devices */
+	plat_marvell_io_setup();
+}
+
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			       u_register_t arg2, u_register_t arg3)
+{
+	struct meminfo *mem_layout = (struct meminfo *)arg1;
+
+	marvell_bl2_early_platform_setup(mem_layout);
+}
+
+void bl2_platform_setup(void)
+{
+	/* Nothing to do */
+}
+
+/*****************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the mmu in a quick and dirty way.
+ *****************************************************************************
+ */
+void marvell_bl2_plat_arch_setup(void)
+{
+	marvell_setup_page_tables(bl2_tzram_layout.total_base,
+				  bl2_tzram_layout.total_size,
+				  BL_CODE_BASE,
+				  BL_CODE_END,
+				  BL_RO_DATA_BASE,
+				  BL_RO_DATA_END
+#if USE_COHERENT_MEM
+				, BL_COHERENT_RAM_BASE,
+				  BL_COHERENT_RAM_END
+#endif
+			      );
+	enable_mmu_el1(0);
+}
+
+void bl2_plat_arch_setup(void)
+{
+	marvell_bl2_plat_arch_setup();
+}
+
+int marvell_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+
+	assert(bl_mem_params);
+
+	switch (image_id) {
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = marvell_get_spsr_for_bl33_entry();
+		break;
+#ifdef SCP_BL2_BASE
+	case SCP_BL2_IMAGE_ID:
+		/* The subsequent handling of SCP_BL2 is platform specific */
+		err = bl2_plat_handle_scp_bl2(&bl_mem_params->image_info);
+		if (err) {
+			WARN("Failure in platform-specific handling of SCP_BL2 image.\n");
+		}
+		break;
+#endif
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return marvell_bl2_handle_post_image_load(image_id);
+}
+
diff --git a/plat/marvell/common/marvell_bl31_setup.c b/plat/marvell/common/marvell_bl31_setup.c
new file mode 100644
index 0000000..26ba906
--- /dev/null
+++ b/plat/marvell/common/marvell_bl31_setup.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#ifdef USE_CCI
+#include <drivers/arm/cci.h>
+#endif
+#include <drivers/console.h>
+#include <plat/common/platform.h>
+
+#include <marvell_def.h>
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak bl31_early_platform_setup2
+#pragma weak bl31_platform_setup
+#pragma weak bl31_plat_arch_setup
+#pragma weak bl31_plat_get_next_image_ep_info
+#pragma weak plat_get_syscnt_freq2
+
+/*****************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ *****************************************************************************
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type));
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+
+	return next_image_info;
+}
+
+/*****************************************************************************
+ * Perform any BL31 early platform setup common to ARM standard platforms.
+ * Here is an opportunity to copy parameters passed by the calling EL (S-EL1
+ * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be
+ * done before the MMU is initialized so that the memory layout can be used
+ * while creating page tables. BL2 has flushed this information to memory, so
+ * we are guaranteed to pick up good data.
+ *****************************************************************************
+ */
+void marvell_bl31_early_platform_setup(void *from_bl2,
+				       uintptr_t soc_fw_config,
+				       uintptr_t hw_config,
+				       void *plat_params_from_bl2)
+{
+	/* Initialize the console to provide early debug support */
+	marvell_console_boot_init();
+
+#if RESET_TO_BL31
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(from_bl2 == NULL);
+	assert(plat_params_from_bl2 == NULL);
+
+#ifdef BL32_BASE
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = marvell_get_spsr_for_bl32_entry();
+#endif /* BL32_BASE */
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell BL31 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = marvell_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#else
+	/*
+	 * In debug builds, we pass a special value in 'plat_params_from_bl2'
+	 * to verify platform parameters from BL2 to BL31.
+	 * In release builds, it's not used.
+	 */
+	assert(((unsigned long long)plat_params_from_bl2) ==
+		MARVELL_BL31_PLAT_PARAM_VAL);
+
+	/*
+	 * Check params passed from BL2 should not be NULL,
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2;
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params != NULL) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_image_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+#endif
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+
+{
+	marvell_bl31_early_platform_setup((void *)arg0, arg1, arg2,
+					  (void *)arg3);
+
+#ifdef USE_CCI
+	/*
+	 * Initialize CCI for this cluster during cold boot.
+	 * No need for locks as no other CPU is active.
+	 */
+	plat_marvell_interconnect_init();
+
+	/*
+	 * Enable CCI coherency for the primary CPU's cluster.
+	 * Platform specific PSCI code will enable coherency for other
+	 * clusters.
+	 */
+	plat_marvell_interconnect_enter_coherency();
+#endif
+}
+
+/*****************************************************************************
+ * Perform any BL31 platform setup common to ARM standard platforms
+ *****************************************************************************
+ */
+void marvell_bl31_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	plat_marvell_gic_driver_init();
+	plat_marvell_gic_init();
+
+	/* For Armada-8k-plus family, the SoC includes more than
+	 * a single AP die, but the default die that boots is AP #0.
+	 * For other families there is only one die (#0).
+	 * Initialize psci arch from die 0
+	 */
+	marvell_psci_arch_init(0);
+}
+
+/*****************************************************************************
+ * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM
+ * standard platforms
+ *****************************************************************************
+ */
+void marvell_bl31_plat_runtime_setup(void)
+{
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
+
+	/* Initialize the runtime console */
+	marvell_console_runtime_init();
+}
+
+void bl31_platform_setup(void)
+{
+	marvell_bl31_platform_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	marvell_bl31_plat_runtime_setup();
+}
+
+/*****************************************************************************
+ * Perform the very early platform specific architectural setup shared between
+ * ARM standard platforms. This only does basic initialization. Later
+ * architectural setup (bl31_arch_setup()) does not do anything platform
+ * specific.
+ *****************************************************************************
+ */
+void marvell_bl31_plat_arch_setup(void)
+{
+	marvell_setup_page_tables(BL31_BASE,
+				  BL31_END - BL31_BASE,
+				  BL_CODE_BASE,
+				  BL_CODE_END,
+				  BL_RO_DATA_BASE,
+				  BL_RO_DATA_END
+#if USE_COHERENT_MEM
+				, BL_COHERENT_RAM_BASE,
+				  BL_COHERENT_RAM_END
+#endif
+			);
+
+#if BL31_CACHE_DISABLE
+	enable_mmu_el3(DISABLE_DCACHE);
+	INFO("Cache is disabled in BL3\n");
+#else
+	enable_mmu_el3(0);
+#endif
+}
+
+void bl31_plat_arch_setup(void)
+{
+	marvell_bl31_plat_arch_setup();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return PLAT_REF_CLK_IN_HZ;
+}
diff --git a/plat/marvell/common/marvell_cci.c b/plat/marvell/common/marvell_cci.c
new file mode 100644
index 0000000..80351ae
--- /dev/null
+++ b/plat/marvell/common/marvell_cci.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <drivers/arm/cci.h>
+
+#include <plat_marvell.h>
+
+static const int cci_map[] = {
+	PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+/****************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way ARM CCI driver is initialised and used.
+ ****************************************************************************
+ */
+#pragma weak plat_marvell_interconnect_init
+#pragma weak plat_marvell_interconnect_enter_coherency
+#pragma weak plat_marvell_interconnect_exit_coherency
+
+
+/****************************************************************************
+ * Helper function to initialize ARM CCI driver.
+ ****************************************************************************
+ */
+void plat_marvell_interconnect_init(void)
+{
+	cci_init(PLAT_MARVELL_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+}
+
+/****************************************************************************
+ * Helper function to place current master into coherency
+ ****************************************************************************
+ */
+void plat_marvell_interconnect_enter_coherency(void)
+{
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/****************************************************************************
+ * Helper function to remove current master from coherency
+ ****************************************************************************
+ */
+void plat_marvell_interconnect_exit_coherency(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/marvell/common/marvell_common.mk b/plat/marvell/common/marvell_common.mk
new file mode 100644
index 0000000..f41d7a4
--- /dev/null
+++ b/plat/marvell/common/marvell_common.mk
@@ -0,0 +1,72 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+MARVELL_PLAT_BASE		:= plat/marvell
+MARVELL_PLAT_INCLUDE_BASE	:= include/plat/marvell
+
+include $(MARVELL_PLAT_BASE)/version.mk
+include $(MARVELL_PLAT_BASE)/marvell.mk
+
+VERSION_STRING			+=(Marvell-${SUBVERSION})
+
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# flag to switch from PLL to ARO
+ARO_ENABLE			:= 0
+$(eval $(call add_define,ARO_ENABLE))
+# Enable/Disable LLC
+LLC_ENABLE			:= 1
+$(eval $(call add_define,LLC_ENABLE))
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES		+=	-I$(MARVELL_PLAT_INCLUDE_BASE)/common	\
+				-I$(MARVELL_PLAT_INCLUDE_BASE)/common/aarch64
+
+
+PLAT_BL_COMMON_SOURCES  += ${XLAT_TABLES_LIB_SRCS} \
+				$(MARVELL_PLAT_BASE)/common/aarch64/marvell_common.c	\
+				$(MARVELL_PLAT_BASE)/common/aarch64/marvell_helpers.S	\
+				$(MARVELL_COMMON_BASE)/marvell_console.c
+
+BL1_SOURCES		+=	drivers/delay_timer/delay_timer.c			\
+				drivers/io/io_fip.c					\
+				drivers/io/io_memmap.c					\
+				drivers/io/io_storage.c					\
+				$(MARVELL_PLAT_BASE)/common/marvell_bl1_setup.c		\
+				$(MARVELL_PLAT_BASE)/common/marvell_io_storage.c	\
+				$(MARVELL_PLAT_BASE)/common/plat_delay_timer.c
+
+ifdef EL3_PAYLOAD_BASE
+# Need the arm_program_trusted_mailbox() function to release secondary CPUs from
+# their holding pen
+endif
+
+BL2_SOURCES		+=	drivers/io/io_fip.c					\
+				drivers/io/io_memmap.c					\
+				drivers/io/io_storage.c					\
+				common/desc_image_load.c				\
+				$(MARVELL_PLAT_BASE)/common/marvell_bl2_setup.c		\
+				$(MARVELL_PLAT_BASE)/common/marvell_io_storage.c	\
+				$(MARVELL_PLAT_BASE)/common/aarch64/marvell_bl2_mem_params_desc.c	\
+				$(MARVELL_PLAT_BASE)/common/marvell_image_load.c
+
+
+BL31_SOURCES		+=	$(MARVELL_PLAT_BASE)/common/marvell_bl31_setup.c	\
+				$(MARVELL_PLAT_BASE)/common/marvell_pm.c		\
+				$(MARVELL_PLAT_BASE)/common/marvell_topology.c		\
+				plat/common/plat_psci_common.c				\
+				$(MARVELL_PLAT_BASE)/common/plat_delay_timer.c		\
+				drivers/delay_timer/delay_timer.c
+
+# PSCI functionality
+$(eval $(call add_define,CONFIG_ARM64))
+
+# MSS (SCP) build
+ifeq (${MSS_SUPPORT}, 1)
+include $(MARVELL_PLAT_BASE)/common/mss/mss_common.mk
+endif
+
+fip: mrvl_flash
diff --git a/plat/marvell/common/marvell_console.c b/plat/marvell/common/marvell_console.c
new file mode 100644
index 0000000..22c5eb3
--- /dev/null
+++ b/plat/marvell/common/marvell_console.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+
+#include <plat_marvell.h>
+
+#ifdef PLAT_a3700
+#include <drivers/marvell/uart/a3700_console.h>
+
+static console_a3700_t marvell_boot_console;
+static console_a3700_t marvell_runtime_console;
+#else
+#include <drivers/ti/uart/uart_16550.h>
+
+static console_16550_t marvell_boot_console;
+static console_16550_t marvell_runtime_console;
+#endif
+
+/*******************************************************************************
+ * Functions that set up the console
+ ******************************************************************************/
+
+/* Initialize the console to provide early debug support */
+void marvell_console_boot_init(void)
+{
+	int rc =
+#ifdef PLAT_a3700
+	console_a3700_register(
+#else
+	console_16550_register(
+#endif
+				PLAT_MARVELL_BOOT_UART_BASE,
+				PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+				MARVELL_CONSOLE_BAUDRATE,
+				&marvell_boot_console);
+	if (rc == 0) {
+		/*
+		 * The crash console doesn't use the multi console API, it uses
+		 * the core console functions directly. It is safe to call panic
+		 * and let it print debug information.
+		 */
+		panic();
+	}
+
+	console_set_scope(&marvell_boot_console.console,
+			  CONSOLE_FLAG_BOOT);
+}
+
+void marvell_console_boot_end(void)
+{
+	(void)console_flush();
+
+	(void)console_unregister(&marvell_boot_console.console);
+}
+
+/* Initialize the runtime console */
+void marvell_console_runtime_init(void)
+{
+	int rc =
+#ifdef PLAT_a3700
+	console_a3700_register(
+#else
+	console_16550_register(
+#endif
+				PLAT_MARVELL_BOOT_UART_BASE,
+				PLAT_MARVELL_BOOT_UART_CLK_IN_HZ,
+				MARVELL_CONSOLE_BAUDRATE,
+				&marvell_runtime_console);
+	if (rc == 0)
+		panic();
+
+	console_set_scope(&marvell_runtime_console.console,
+			  CONSOLE_FLAG_RUNTIME);
+}
+
+void marvell_console_runtime_end(void)
+{
+	(void)console_flush();
+
+	(void)console_unregister(&marvell_runtime_console.console);
+}
diff --git a/plat/marvell/common/marvell_ddr_info.c b/plat/marvell/common/marvell_ddr_info.c
new file mode 100644
index 0000000..7340996
--- /dev/null
+++ b/plat/marvell/common/marvell_ddr_info.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <ddr_info.h>
+
+#define DRAM_CH0_MMAP_LOW_REG(iface, cs, base)	\
+	(base + DRAM_CH0_MMAP_LOW_OFFSET + (iface) * 0x10000 + (cs) * 0x8)
+#define DRAM_CH0_MMAP_HIGH_REG(iface, cs, base)	\
+	(DRAM_CH0_MMAP_LOW_REG(iface, cs, base) + 4)
+#define DRAM_CS_VALID_ENABLED_MASK		0x1
+#define DRAM_AREA_LENGTH_OFFS			16
+#define DRAM_AREA_LENGTH_MASK			(0x1f << DRAM_AREA_LENGTH_OFFS)
+#define DRAM_START_ADDRESS_L_OFFS		23
+#define DRAM_START_ADDRESS_L_MASK		\
+					(0x1ff << DRAM_START_ADDRESS_L_OFFS)
+#define DRAM_START_ADDR_HTOL_OFFS		32
+
+#define DRAM_MAX_CS_NUM				2
+
+#define DRAM_CS_ENABLED(iface, cs, base) \
+	(mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \
+	 DRAM_CS_VALID_ENABLED_MASK)
+#define GET_DRAM_REGION_SIZE_CODE(iface, cs, base) \
+	(mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \
+	DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS
+
+/* Mapping between DDR area length and real DDR size is specific and looks like
+ * bellow:
+ * 0 => 384 MB
+ * 1 => 768 MB
+ * 2 => 1536 MB
+ * 3 => 3 GB
+ * 4 => 6 GB
+ *
+ * 7 => 8 MB
+ * 8 => 16 MB
+ * 9 => 32 MB
+ * 10 => 64 MB
+ * 11 => 128 MB
+ * 12 => 256 MB
+ * 13 => 512 MB
+ * 14 => 1 GB
+ * 15 => 2 GB
+ * 16 => 4 GB
+ * 17 => 8 GB
+ * 18 => 16 GB
+ * 19 => 32 GB
+ * 20 => 64 GB
+ * 21 => 128 GB
+ * 22 => 256 GB
+ * 23 => 512 GB
+ * 24 => 1 TB
+ * 25 => 2 TB
+ * 26 => 4 TB
+ *
+ * to calculate real size we need to use two different formulas:
+ * -- GET_DRAM_REGION_SIZE_ODD for values 0-4 (DRAM_REGION_SIZE_ODD)
+ * -- GET_DRAM_REGION_SIZE_EVEN for values 7-26 (DRAM_REGION_SIZE_EVEN)
+ * using mentioned formulas we cover whole mapping between "Area length" value
+ * and real size (see above mapping).
+ */
+#define DRAM_REGION_SIZE_EVEN(C)	(((C) >= 7) && ((C) <= 26))
+#define GET_DRAM_REGION_SIZE_EVEN(C)	((uint64_t)1 << ((C) + 16))
+#define DRAM_REGION_SIZE_ODD(C)		((C) <= 4)
+#define GET_DRAM_REGION_SIZE_ODD(C)	((uint64_t)0x18000000 << (C))
+
+
+uint64_t mvebu_get_dram_size(uint64_t ap_base_addr)
+{
+	uint64_t mem_size = 0;
+	uint8_t region_code;
+	uint8_t cs, iface;
+
+	for (iface = 0; iface < DRAM_MAX_IFACE; iface++) {
+		for (cs = 0; cs < DRAM_MAX_CS_NUM; cs++) {
+
+			/* Exit loop on first disabled DRAM CS */
+			if (!DRAM_CS_ENABLED(iface, cs, ap_base_addr))
+				break;
+
+			/* Decode area length for current CS
+			 * from register value
+			 */
+			region_code =
+				GET_DRAM_REGION_SIZE_CODE(iface, cs,
+							  ap_base_addr);
+
+			if (DRAM_REGION_SIZE_EVEN(region_code)) {
+				mem_size +=
+					GET_DRAM_REGION_SIZE_EVEN(region_code);
+			} else if (DRAM_REGION_SIZE_ODD(region_code)) {
+				mem_size +=
+					GET_DRAM_REGION_SIZE_ODD(region_code);
+			} else {
+				WARN("%s: Invalid mem region (0x%x) CS#%d\n",
+				      __func__, region_code, cs);
+				return 0;
+			}
+		}
+	}
+
+	return mem_size;
+}
diff --git a/plat/marvell/common/marvell_gicv2.c b/plat/marvell/common/marvell_gicv2.c
new file mode 100644
index 0000000..2505c9f
--- /dev/null
+++ b/plat/marvell/common/marvell_gicv2.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_marvell.h>
+
+/*
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv2 driver is initialised and used.
+ */
+#pragma weak plat_marvell_gic_driver_init
+#pragma weak plat_marvell_gic_init
+
+#define A7K8K_PIC_CAUSE_REG		0xf03f0100
+#define A7K8K_PIC0_MASK_REG		0xf03f0108
+
+#define A7K8K_PIC_PMUOF_IRQ_MASK	(1 << 17)
+
+#define A7K8K_PIC_MAX_IRQS		32
+#define A7K8K_PIC_MAX_IRQ_MASK		((1UL << A7K8K_PIC_MAX_IRQS) - 1)
+
+#define A7K8K_ODMIN_SET_REG		0xf0300040
+#define A7K8K_ODMI_PMU_IRQ(idx)		((2 + idx) << 12)
+
+#define A7K8K_ODMI_PMU_GIC_IRQ(idx)	(130 + idx)
+
+static DEFINE_BAKERY_LOCK(a7k8k_irq_lock);
+
+/*
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ */
+static const interrupt_prop_t marvell_interrupt_props[] = {
+	PLAT_MARVELL_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
+	PLAT_MARVELL_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+/*
+ * Ideally `marvell_gic_data` structure definition should be a `const` but it is
+ * kept as modifiable for overwriting with different GICD and GICC base when
+ * running on FVP with VE memory map.
+ */
+static gicv2_driver_data_t marvell_gic_data = {
+	.gicd_base = PLAT_MARVELL_GICD_BASE,
+	.gicc_base = PLAT_MARVELL_GICC_BASE,
+	.interrupt_props = marvell_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/*
+ * ARM common helper to initialize the GICv2 only driver.
+ */
+void plat_marvell_gic_driver_init(void)
+{
+	gicv2_driver_init(&marvell_gic_data);
+}
+
+static uint64_t a7k8k_pmu_interrupt_handler(uint32_t id,
+					  uint32_t flags,
+					  void *handle,
+					  void *cookie)
+{
+	unsigned int idx = plat_my_core_pos();
+	uint32_t irq;
+
+	bakery_lock_get(&a7k8k_irq_lock);
+
+	/* Acknowledge IRQ */
+	irq = plat_ic_acknowledge_interrupt();
+
+	plat_ic_end_of_interrupt(irq);
+
+	if (irq != MARVELL_IRQ_PIC0) {
+		bakery_lock_release(&a7k8k_irq_lock);
+		return 0;
+	}
+
+	/* Acknowledge PMU overflow IRQ in PIC0 */
+	mmio_setbits_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
+
+	/* Trigger ODMI Frame IRQ */
+	mmio_write_32(A7K8K_ODMIN_SET_REG, A7K8K_ODMI_PMU_IRQ(idx));
+
+	bakery_lock_release(&a7k8k_irq_lock);
+
+	return 0;
+}
+
+void mvebu_pmu_interrupt_enable(void)
+{
+	unsigned int idx;
+	uint32_t flags;
+	int32_t rc;
+
+	/* Reset PIC */
+	mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
+	/* Unmask PMU overflow IRQ in PIC0 */
+	mmio_clrbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
+
+	/* Configure ODMI Frame IRQs as edge triggered */
+	for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++)
+		gicv2_interrupt_set_cfg(A7K8K_ODMI_PMU_GIC_IRQ(idx),
+					GIC_INTR_CFG_EDGE);
+
+	/*
+	 * Register IRQ handler as INTR_TYPE_S_EL1 as its the only valid type
+	 * for GICv2 in ARM-TF.
+	 */
+	flags = 0U;
+	set_interrupt_rm_flag((flags), (NON_SECURE));
+	rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+					     a7k8k_pmu_interrupt_handler,
+					     flags);
+	if (rc != 0)
+		panic();
+}
+
+void mvebu_pmu_interrupt_disable(void)
+{
+	/* Reset PIC */
+	mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
+	/* Mask PMU overflow IRQ in PIC0 */
+	mmio_setbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
+}
+
+void plat_marvell_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_set_pe_target_mask(plat_my_core_pos());
+	gicv2_cpuif_enable();
+}
diff --git a/plat/marvell/common/marvell_gicv3.c b/plat/marvell/common/marvell_gicv3.c
new file mode 100644
index 0000000..0bd5545
--- /dev/null
+++ b/plat/marvell/common/marvell_gicv3.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#include <marvell_def.h>
+#include <plat_marvell.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ ******************************************************************************
+ */
+#pragma weak plat_marvell_gic_driver_init
+#pragma weak plat_marvell_gic_init
+#pragma weak plat_marvell_gic_cpuif_enable
+#pragma weak plat_marvell_gic_cpuif_disable
+#pragma weak plat_marvell_gic_pcpu_init
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t marvell_interrupt_props[] = {
+	PLAT_MARVELL_G1S_IRQ_PROPS(INTR_GROUP1S),
+	PLAT_MARVELL_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory
+ */
+static gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+static gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+
+/*
+ * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
+ * to core position.
+ *
+ * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
+ * values read from GICR_TYPER don't have an MT field. To reuse the same
+ * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
+ * that read from GICR_TYPER.
+ *
+ * Assumptions:
+ *
+ *   - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
+ *   - No CPUs implemented in the system use affinity level 3.
+ */
+static unsigned int marvell_gicv3_mpidr_hash(u_register_t mpidr)
+{
+	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+	return plat_marvell_calc_core_pos(mpidr);
+}
+
+const gicv3_driver_data_t marvell_gic_data = {
+	.gicd_base = PLAT_MARVELL_GICD_BASE,
+	.gicr_base = PLAT_MARVELL_GICR_BASE,
+	.interrupt_props = marvell_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = marvell_gicv3_mpidr_hash
+};
+
+void plat_marvell_gic_driver_init(void)
+{
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#if IMAGE_BL31
+	gicv3_driver_init(&marvell_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * Marvell common helper to initialize the GIC. Only invoked by BL31
+ ******************************************************************************
+ */
+void plat_marvell_gic_init(void)
+{
+	/* Initialize GIC-600 Multi Chip feature,
+	 * only if the maximum number of north bridges
+	 * is more than 1 - otherwise no need for multi
+	 * chip feature initialization
+	 */
+#if (PLAT_MARVELL_NORTHB_COUNT > 1)
+	if (gic600_multi_chip_init())
+		ERROR("GIC-600 Multi Chip initialization failed\n");
+#endif
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Marvell common helper to enable the GIC CPU interface
+ ******************************************************************************
+ */
+void plat_marvell_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Marvell common helper to disable the GIC CPU interface
+ ******************************************************************************
+ */
+void plat_marvell_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Marvell common helper to init. the per-cpu redistributor interface in GICv3
+ ******************************************************************************
+ */
+void plat_marvell_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Marvell common helper to save SPI irq states in GICv3
+ ******************************************************************************
+ */
+void plat_marvell_gic_irq_save(void)
+{
+
+	/*
+	 * If an ITS is available, save its context before
+	 * the Redistributor using:
+	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
+	 * Additionally, an implementation-defined sequence may
+	 * be required to save the whole ITS state.
+	 */
+
+	/*
+	 * Save the GIC Redistributors and ITS contexts before the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to save the context of the CPU that is issuing
+	 * the SYSTEM SUSPEND call, i.e. the current CPU.
+	 */
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+	/* Save the GIC Distributor context */
+	gicv3_distif_save(&dist_ctx);
+
+	/*
+	 * From here, all the components of the GIC can be safely powered down
+	 * as long as there is an alternate way to handle wakeup interrupt
+	 * sources.
+	 */
+}
+
+/******************************************************************************
+ * Marvell common helper to restore SPI irq states in GICv3
+ ******************************************************************************
+ */
+void plat_marvell_gic_irq_restore(void)
+{
+	/* Restore the GIC Distributor context */
+	gicv3_distif_init_restore(&dist_ctx);
+
+	/*
+	 * Restore the GIC Redistributor and ITS contexts after the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to restore the context of the CPU that issued
+	 * the SYSTEM SUSPEND call.
+	 */
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+	/*
+	 * If an ITS is available, restore its context after
+	 * the Redistributor using:
+	 * gicv3_its_restore(gits_base, &its_ctx[i])
+	 * An implementation-defined sequence may be required to
+	 * restore the whole ITS state. The ITS must also be
+	 * re-enabled after this sequence has been executed.
+	 */
+}
+
+/******************************************************************************
+ * Marvell common helper to save per-cpu PPI irq states in GICv3
+ ******************************************************************************
+ */
+void plat_marvell_gic_irq_pcpu_save(void)
+{
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+}
+
+/******************************************************************************
+ * Marvell common helper to restore per-cpu PPI irq states in GICv3
+ ******************************************************************************
+ */
+void plat_marvell_gic_irq_pcpu_restore(void)
+{
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+}
diff --git a/plat/marvell/common/marvell_image_load.c b/plat/marvell/common/marvell_image_load.c
new file mode 100644
index 0000000..be16b08
--- /dev/null
+++ b/plat/marvell/common/marvell_image_load.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/marvell/common/marvell_io_storage.c b/plat/marvell/common/marvell_io_storage.c
new file mode 100644
index 0000000..065f956
--- /dev/null
+++ b/plat/marvell/common/marvell_io_storage.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_storage.h>
+#include <tools_share/firmware_image_package.h>
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = PLAT_MARVELL_FIP_BASE,
+	.length = PLAT_MARVELL_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+/* By default, Marvell platforms load images from the FIP */
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+};
+
+
+/* Weak definitions may be overridden in specific ARM standard platform */
+#pragma weak plat_marvell_io_setup
+#pragma weak plat_marvell_get_alt_image_source
+
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+
+void marvell_io_setup(void)
+{
+	int io_result;
+
+	io_result = register_io_dev_fip(&fip_dev_con);
+	assert(io_result == 0);
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&memmap_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+void plat_marvell_io_setup(void)
+{
+	marvell_io_setup();
+}
+
+int plat_marvell_get_alt_image_source(
+	unsigned int image_id __attribute__((unused)),
+	uintptr_t *dev_handle __attribute__((unused)),
+	uintptr_t *image_spec __attribute__((unused)))
+{
+	/* By default do not try an alternative */
+	return -ENOENT;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	if (result == 0) {
+		*image_spec = policy->image_spec;
+		*dev_handle = *(policy->dev_handle);
+	} else {
+		VERBOSE("Trying alternative IO\n");
+		result = plat_marvell_get_alt_image_source(image_id, dev_handle,
+						       image_spec);
+	}
+
+	return result;
+}
+
+/*
+ * See if a Firmware Image Package is available,
+ * by checking if TOC is valid or not.
+ */
+int marvell_io_is_toc_valid(void)
+{
+	int result;
+
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+
+	return result == 0;
+}
diff --git a/plat/marvell/common/marvell_pm.c b/plat/marvell/common/marvell_pm.c
new file mode 100644
index 0000000..3c675b2
--- /dev/null
+++ b/plat/marvell/common/marvell_pm.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+
+#include <marvell_pm.h>
+
+/* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */
+extern const plat_psci_ops_t plat_arm_psci_pm_ops;
+
+/*****************************************************************************
+ * Private function to program the mailbox for a cpu before it is released
+ * from reset. This function assumes that the mail box base is within
+ * the MARVELL_SHARED_RAM region
+ *****************************************************************************
+ */
+void marvell_program_mailbox(uintptr_t address)
+{
+	uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE;
+
+	/*
+	 * Ensure that the PLAT_MARVELL_MAILBOX_BASE is within
+	 * MARVELL_SHARED_RAM region.
+	 */
+	assert((PLAT_MARVELL_MAILBOX_BASE >= MARVELL_SHARED_RAM_BASE) &&
+	       ((PLAT_MARVELL_MAILBOX_BASE + sizeof(*mailbox)) <=
+	       (MARVELL_SHARED_RAM_BASE + MARVELL_SHARED_RAM_SIZE)));
+
+	mailbox[MBOX_IDX_MAGIC] = MVEBU_MAILBOX_MAGIC_NUM;
+	mailbox[MBOX_IDX_SEC_ADDR] = address;
+
+	/* Flush data cache if the mail box shared RAM is cached */
+#if PLAT_MARVELL_SHARED_RAM_CACHED
+	flush_dcache_range((uintptr_t)PLAT_MARVELL_MAILBOX_BASE +
+			   8 * MBOX_IDX_MAGIC,
+			   2 * sizeof(uint64_t));
+#endif
+}
+
+/*****************************************************************************
+ * The ARM Standard platform definition of platform porting API
+ * `plat_setup_psci_ops`.
+ *****************************************************************************
+ */
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &plat_arm_psci_pm_ops;
+
+	/* Setup mailbox with entry point. */
+	marvell_program_mailbox(sec_entrypoint);
+	return 0;
+}
diff --git a/plat/marvell/common/marvell_topology.c b/plat/marvell/common/marvell_topology.c
new file mode 100644
index 0000000..a40ff6f
--- /dev/null
+++ b/plat/marvell/common/marvell_topology.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <plat_marvell.h>
+
+/* The power domain tree descriptor */
+unsigned char marvell_power_domain_tree_desc[PLAT_MARVELL_CLUSTER_COUNT + 1];
+
+/*****************************************************************************
+ * This function dynamically constructs the topology according to
+ * PLAT_MARVELL_CLUSTER_COUNT and returns it.
+ *****************************************************************************
+ */
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	int i;
+
+	/*
+	 * The power domain tree does not have a single system level power
+	 * domain i.e. a single root node. The first entry in the power domain
+	 * descriptor specifies the number of power domains at the highest power
+	 * level.
+	 * For Marvell Platform this is the number of cluster power domains.
+	 */
+	marvell_power_domain_tree_desc[0] = PLAT_MARVELL_CLUSTER_COUNT;
+
+	for (i = 0; i < PLAT_MARVELL_CLUSTER_COUNT; i++)
+		marvell_power_domain_tree_desc[i + 1] =
+					PLAT_MARVELL_CLUSTER_CORE_COUNT;
+
+	return marvell_power_domain_tree_desc;
+}
+
+/*****************************************************************************
+ * This function validates an MPIDR by checking whether it falls within the
+ * acceptable bounds. An error code (-1) is returned if an incorrect mpidr
+ * is passed.
+ *****************************************************************************
+ */
+int marvell_check_mpidr(u_register_t mpidr)
+{
+	unsigned int nb_id, cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK |
+	    MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT))
+		return -1;
+
+	/* Get north bridge ID */
+	nb_id = MPIDR_AFFLVL3_VAL(mpidr);
+	cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (nb_id >= PLAT_MARVELL_CLUSTER_COUNT)
+		return -1;
+
+	if (cluster_id >= PLAT_MARVELL_CLUSTER_COUNT)
+		return -1;
+
+	if (cpu_id >= PLAT_MARVELL_CLUSTER_CORE_COUNT)
+		return -1;
+
+	return 0;
+}
+
+/*****************************************************************************
+ * This function implements a part of the critical interface between the PSCI
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ *****************************************************************************
+ */
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	if (marvell_check_mpidr(mpidr) == -1)
+		return -1;
+
+	return plat_marvell_calc_core_pos(mpidr);
+}
diff --git a/plat/marvell/common/mrvl_sip_svc.c b/plat/marvell/common/mrvl_sip_svc.c
new file mode 100644
index 0000000..0291024
--- /dev/null
+++ b/plat/marvell/common/mrvl_sip_svc.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/marvell/cache_llc.h>
+#include <drivers/marvell/mochi/ap_setup.h>
+#include <lib/smccc.h>
+
+#include <marvell_plat_priv.h>
+#include <plat_marvell.h>
+
+#include "comphy/phy-comphy-cp110.h"
+#include <stdbool.h>
+
+/* #define DEBUG_COMPHY */
+#ifdef DEBUG_COMPHY
+#define debug(format...) NOTICE(format)
+#else
+#define debug(format, arg...)
+#endif
+
+/* Comphy related FID's */
+#define MV_SIP_COMPHY_POWER_ON	0x82000001
+#define MV_SIP_COMPHY_POWER_OFF	0x82000002
+#define MV_SIP_COMPHY_PLL_LOCK	0x82000003
+#define MV_SIP_COMPHY_XFI_TRAIN	0x82000004
+#define MV_SIP_COMPHY_DIG_RESET	0x82000005
+
+/* Miscellaneous FID's' */
+#define MV_SIP_DRAM_SIZE	0x82000010
+#define MV_SIP_LLC_ENABLE	0x82000011
+#define MV_SIP_PMU_IRQ_ENABLE	0x82000012
+#define MV_SIP_PMU_IRQ_DISABLE	0x82000013
+
+#define MAX_LANE_NR		6
+#define MVEBU_COMPHY_OFFSET	0x441000
+#define MVEBU_CP_BASE_MASK	(~0xffffff)
+
+/* This macro is used to identify COMPHY related calls from SMC function ID */
+#define is_comphy_fid(fid)	\
+	((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_DIG_RESET)
+
+_Bool is_cp_range_valid(u_register_t *addr)
+{
+	int cp_nr;
+
+	*addr &= MVEBU_CP_BASE_MASK;
+	for (cp_nr = 0; cp_nr < CP_NUM; cp_nr++) {
+		if (*addr == MVEBU_CP_REGS_BASE(cp_nr))
+			return true;
+	}
+
+	return false;
+}
+
+uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
+			       u_register_t x1,
+			       u_register_t x2,
+			       u_register_t x3,
+			       u_register_t x4,
+			       void *cookie,
+			       void *handle,
+			       u_register_t flags)
+{
+	u_register_t ret;
+	int i;
+
+	debug("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx, x3 0x%lx\n",
+						 __func__, smc_fid, x1, x2, x3);
+
+	if (is_comphy_fid(smc_fid)) {
+		/* validate address passed via x1 */
+		if (!is_cp_range_valid(&x1)) {
+			ERROR("%s: Wrong smc (0x%x) address: %lx\n",
+			      __func__, smc_fid, x1);
+			SMC_RET1(handle, SMC_UNK);
+		}
+
+		x1 += MVEBU_COMPHY_OFFSET;
+
+		if (x2 >= MAX_LANE_NR) {
+			ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n",
+			      __func__, smc_fid, x2);
+			SMC_RET1(handle, SMC_UNK);
+		}
+	}
+
+	switch (smc_fid) {
+
+	/* Comphy related FID's */
+	case MV_SIP_COMPHY_POWER_ON:
+		/* x1:  comphy_base, x2: comphy_index, x3: comphy_mode */
+		ret = mvebu_cp110_comphy_power_on(x1, x2, x3);
+		SMC_RET1(handle, ret);
+	case MV_SIP_COMPHY_POWER_OFF:
+		/* x1:  comphy_base, x2: comphy_index */
+		ret = mvebu_cp110_comphy_power_off(x1, x2, x3);
+		SMC_RET1(handle, ret);
+	case MV_SIP_COMPHY_PLL_LOCK:
+		/* x1:  comphy_base, x2: comphy_index */
+		ret = mvebu_cp110_comphy_is_pll_locked(x1, x2);
+		SMC_RET1(handle, ret);
+	case MV_SIP_COMPHY_XFI_TRAIN:
+		/* x1:  comphy_base, x2: comphy_index */
+		ret = mvebu_cp110_comphy_xfi_rx_training(x1, x2);
+		SMC_RET1(handle, ret);
+	case MV_SIP_COMPHY_DIG_RESET:
+		/* x1:  comphy_base, x2: comphy_index, x3: mode, x4: command */
+		ret = mvebu_cp110_comphy_digital_reset(x1, x2, x3, x4);
+		SMC_RET1(handle, ret);
+
+	/* Miscellaneous FID's' */
+	case MV_SIP_DRAM_SIZE:
+		ret = mvebu_get_dram_size(MVEBU_REGS_BASE);
+		SMC_RET1(handle, ret);
+	case MV_SIP_LLC_ENABLE:
+		for (i = 0; i < ap_get_count(); i++)
+			llc_runtime_enable(i);
+
+		SMC_RET1(handle, 0);
+#ifdef MVEBU_PMU_IRQ_WA
+	case MV_SIP_PMU_IRQ_ENABLE:
+		mvebu_pmu_interrupt_enable();
+		SMC_RET1(handle, 0);
+	case MV_SIP_PMU_IRQ_DISABLE:
+		mvebu_pmu_interrupt_disable();
+		SMC_RET1(handle, 0);
+#endif
+
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	marvell_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	mrvl_sip_smc_handler
+);
diff --git a/plat/marvell/common/mss/mss_common.mk b/plat/marvell/common/mss/mss_common.mk
new file mode 100644
index 0000000..898b6dc
--- /dev/null
+++ b/plat/marvell/common/mss/mss_common.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+
+PLAT_MARVELL		:= 	plat/marvell
+MSS_SOURCE		:= 	$(PLAT_MARVELL)/common/mss
+
+BL2_SOURCES		+=	$(MSS_SOURCE)/mss_scp_bootloader.c		\
+				$(PLAT_MARVELL)/common/plat_delay_timer.c	\
+				drivers/delay_timer/delay_timer.c		\
+				$(MARVELL_DRV)					\
+				$(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c
+
+BL31_SOURCES		+=	$(MSS_SOURCE)/mss_ipc_drv.c
+
+PLAT_INCLUDES           +=      -I$(MSS_SOURCE)
diff --git a/plat/marvell/common/mss/mss_ipc_drv.c b/plat/marvell/common/mss/mss_ipc_drv.c
new file mode 100644
index 0000000..70ccfa5
--- /dev/null
+++ b/plat/marvell/common/mss/mss_ipc_drv.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <string.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_marvell.h>
+#include <mss_ipc_drv.h>
+
+#define IPC_MSG_BASE_MASK		MVEBU_REGS_BASE_MASK
+
+#define IPC_CH_NUM_OF_MSG		(16)
+#define IPC_CH_MSG_IDX			(-1)
+
+unsigned long mv_pm_ipc_msg_base;
+unsigned int  mv_pm_ipc_queue_size;
+
+unsigned int msg_sync;
+int msg_index = IPC_CH_MSG_IDX;
+
+/******************************************************************************
+ * mss_pm_ipc_init
+ *
+ * DESCRIPTION: Initialize PM IPC infrastructure
+ ******************************************************************************
+ */
+int mv_pm_ipc_init(unsigned long ipc_control_addr)
+{
+	struct mss_pm_ipc_ctrl *ipc_control =
+			(struct mss_pm_ipc_ctrl *)ipc_control_addr;
+
+	/* Initialize PM IPC control block */
+	mv_pm_ipc_msg_base     = ipc_control->msg_base_address |
+				 IPC_MSG_BASE_MASK;
+	mv_pm_ipc_queue_size   = ipc_control->queue_size;
+
+	return 0;
+}
+
+/******************************************************************************
+ * mv_pm_ipc_queue_addr_get
+ *
+ * DESCRIPTION: Returns the IPC queue address
+ ******************************************************************************
+ */
+unsigned int mv_pm_ipc_queue_addr_get(void)
+{
+	unsigned int addr;
+
+	inv_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
+	msg_index = msg_index + 1;
+	if (msg_index >= IPC_CH_NUM_OF_MSG)
+		msg_index = 0;
+
+	addr = (unsigned int)(mv_pm_ipc_msg_base +
+	       (msg_index * mv_pm_ipc_queue_size));
+
+	flush_dcache_range((uint64_t)&msg_index, sizeof(msg_index));
+
+	return addr;
+}
+
+/******************************************************************************
+ * mv_pm_ipc_msg_rx
+ *
+ * DESCRIPTION: Retrieve message from IPC channel
+ ******************************************************************************
+ */
+int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg)
+{
+	unsigned int addr = mv_pm_ipc_queue_addr_get();
+
+	msg->msg_reply = mmio_read_32(addr + IPC_MSG_REPLY_LOC);
+
+	return 0;
+}
+
+/******************************************************************************
+ * mv_pm_ipc_msg_tx
+ *
+ * DESCRIPTION: Send message via IPC channel
+ ******************************************************************************
+ */
+int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
+					unsigned int cluster_power_state)
+{
+	unsigned int addr = mv_pm_ipc_queue_addr_get();
+
+	/* Validate the entry for message placed by the host is free */
+	if (mmio_read_32(addr + IPC_MSG_STATE_LOC) == IPC_MSG_FREE) {
+		inv_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
+		msg_sync = msg_sync + 1;
+		flush_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync));
+
+		mmio_write_32(addr + IPC_MSG_SYNC_ID_LOC, msg_sync);
+		mmio_write_32(addr + IPC_MSG_ID_LOC, msg_id);
+		mmio_write_32(addr + IPC_MSG_CPU_ID_LOC, channel_id);
+		mmio_write_32(addr + IPC_MSG_POWER_STATE_LOC,
+			      cluster_power_state);
+		mmio_write_32(addr + IPC_MSG_STATE_LOC, IPC_MSG_OCCUPY);
+
+	} else {
+		ERROR("%s: FAILED\n", __func__);
+	}
+
+	return 0;
+}
diff --git a/plat/marvell/common/mss/mss_ipc_drv.h b/plat/marvell/common/mss/mss_ipc_drv.h
new file mode 100644
index 0000000..bcb4b2d
--- /dev/null
+++ b/plat/marvell/common/mss/mss_ipc_drv.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MSS_IPC_DRV_H
+#define MSS_IPC_DRV_H
+
+#include <lib/psci/psci.h>
+
+#define MV_PM_FW_IPC_VERSION_MAGIC	(0xCA530000) /* Do NOT change */
+/* Increament for each version */
+#define MV_PM_FW_IPC_VERSION_SEQ	(0x00000001)
+#define MV_PM_FW_IPC_VERSION		(MV_PM_FW_IPC_VERSION_MAGIC | \
+					 MV_PM_FW_IPC_VERSION_SEQ)
+
+#define IPC_MSG_STATE_LOC		(0x0)
+#define IPC_MSG_SYNC_ID_LOC		(0x4)
+#define IPC_MSG_ID_LOC			(0x8)
+#define IPC_MSG_RET_CH_ID_LOC	(0xC)
+#define IPC_MSG_CPU_ID_LOC		(0x10)
+#define IPC_MSG_CLUSTER_ID_LOC	(0x14)
+#define IPC_MSG_SYSTEM_ID_LOC	(0x18)
+#define IPC_MSG_POWER_STATE_LOC	(0x1C)
+#define IPC_MSG_REPLY_LOC		(0x20)
+#define IPC_MSG_RESERVED_LOC	(0x24)
+
+/* IPC initialization state */
+enum mss_pm_ipc_init_state {
+	IPC_UN_INITIALIZED	= 1,
+	IPC_INITIALIZED		= 2
+};
+
+/* IPC queue direction */
+enum mss_pm_ipc_init_msg_dir {
+	IPC_MSG_TX	= 0,
+	IPC_MSG_RX	= 1
+};
+
+/* IPC message state */
+enum mss_pm_ipc_msg_state {
+	IPC_MSG_FREE	= 1,
+	IPC_MSG_OCCUPY	= 2
+
+};
+
+/* IPC control block */
+struct mss_pm_ipc_ctrl {
+	unsigned int ctrl_base_address;
+	unsigned int msg_base_address;
+	unsigned int num_of_channels;
+	unsigned int channel_size;
+	unsigned int queue_size;
+};
+
+/* IPC message types */
+enum mss_pm_msg_id {
+	PM_IPC_MSG_CPU_SUSPEND		= 1,
+	PM_IPC_MSG_CPU_OFF		= 2,
+	PM_IPC_MSG_CPU_ON		= 3,
+	PM_IPC_MSG_SYSTEM_RESET		= 4,
+	PM_IPC_MSG_SYSTEM_SUSPEND	= 5,
+	PM_IPC_MAX_MSG
+};
+
+struct mss_pm_ipc_msg {
+	unsigned int	msg_sync_id;	/*
+					 * Sync number, validate message
+					 * reply corresponding to message
+					 * received
+					 */
+	unsigned int	msg_id;		/* Message Id */
+	unsigned int	ret_channel_id;	/* IPC channel reply */
+	unsigned int	cpu_id;		/* CPU Id */
+	unsigned int	cluster_id;	/* Cluster Id */
+	unsigned int	system_id;	/* System Id */
+	unsigned int	power_state;
+	unsigned int	msg_reply;	/* Message reply */
+};
+
+/* IPC queue */
+struct mss_pm_ipc_queue {
+	unsigned int	state;
+	struct mss_pm_ipc_msg		msg;
+};
+
+/* IPC channel */
+struct mss_pm_ipc_ch {
+	struct mss_pm_ipc_queue *tx_queue;
+	struct mss_pm_ipc_queue *rx_queue;
+};
+
+/*****************************************************************************
+ * mv_pm_ipc_init
+ *
+ * DESCRIPTION: Initialize PM IPC infrastructure
+ *****************************************************************************
+ */
+int mv_pm_ipc_init(unsigned long ipc_control_addr);
+
+/*****************************************************************************
+ * mv_pm_ipc_msg_rx
+ *
+ * DESCRIPTION: Retrieve message from IPC channel
+ *****************************************************************************
+ */
+int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg);
+
+/*****************************************************************************
+ * mv_pm_ipc_msg_tx
+ *
+ * DESCRIPTION: Send message via IPC channel
+ *****************************************************************************
+ */
+int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id,
+			unsigned int cluster_power_state);
+
+#endif /* MSS_IPC_DRV_H */
diff --git a/plat/marvell/common/mss/mss_mem.h b/plat/marvell/common/mss/mss_mem.h
new file mode 100644
index 0000000..5d68ac7
--- /dev/null
+++ b/plat/marvell/common/mss/mss_mem.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MSS_MEM_H
+#define MSS_MEM_H
+
+/* MSS SRAM Memory base */
+#define MSS_SRAM_PM_CONTROL_BASE		(MVEBU_REGS_BASE + 0x520000)
+
+enum mss_pm_ctrl_handshake {
+	MSS_UN_INITIALIZED	= 0,
+	MSS_COMPATIBILITY_ERROR	= 1,
+	MSS_ACKNOWLEDGMENT	= 2,
+	HOST_ACKNOWLEDGMENT	= 3
+};
+
+enum mss_pm_ctrl_rtos_env {
+	MSS_MULTI_PROCESS_ENV	= 0,
+	MSS_SINGLE_PROCESS_ENV	= 1,
+	MSS_MAX_PROCESS_ENV
+};
+
+struct mss_pm_ctrl_block {
+	/* This field is used to synchronize the Host
+	 * and MSS initialization sequence
+	 * Valid Values
+	 * 0 - Un-Initialized
+	 * 1 - Compatibility Error
+	 * 2 - MSS Acknowledgment
+	 * 3 - Host Acknowledgment
+	 */
+	unsigned int handshake;
+
+	/*
+	 * This field include Host IPC version. Once received by the MSS
+	 * It will be compared to MSS IPC version and set MSS Acknowledge to
+	 * "compatibility error" in case there is no match
+	 */
+	unsigned int ipc_version;
+	unsigned int ipc_base_address;
+	unsigned int ipc_state;
+
+	/* Following fields defines firmware core architecture */
+	unsigned int num_of_cores;
+	unsigned int num_of_clusters;
+	unsigned int num_of_cores_per_cluster;
+
+	/* Following fields define pm trace debug base address */
+	unsigned int pm_trace_ctrl_base_address;
+	unsigned int pm_trace_info_base_address;
+	unsigned int pm_trace_info_core_size;
+
+	unsigned int ctrl_blk_size;
+};
+
+#endif /* MSS_MEM_H */
diff --git a/plat/marvell/common/mss/mss_scp_bl2_format.h b/plat/marvell/common/mss/mss_scp_bl2_format.h
new file mode 100644
index 0000000..7cf8d32
--- /dev/null
+++ b/plat/marvell/common/mss/mss_scp_bl2_format.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MSS_SCP_BL2_FORMAT_H
+#define MSS_SCP_BL2_FORMAT_H
+
+#define MAX_NR_OF_FILES	5
+#define FILE_MAGIC	0xddd01ff
+#define HEADER_VERSION	0x1
+
+#define MSS_IDRAM_SIZE	0x10000 /* 64KB */
+#define MG_SRAM_SIZE	0x20000 /* 128KB */
+
+/* Types definitions */
+typedef struct file_header {
+	/* Magic specific for concatenated file (used for validation) */
+	uint32_t magic;
+	uint32_t nr_of_imgs;	/* Number of images concatenated */
+} file_header_t;
+
+/* Types definitions */
+enum cm3_t {
+	MSS_AP,
+	MSS_CP0,
+	MSS_CP1,
+	MSS_CP2,
+	MSS_CP3,
+	MG_CP0,
+	MG_CP1,
+};
+
+typedef struct img_header {
+	uint32_t type;		/* CM3 type, can be one of cm3_t */
+	uint32_t length;	/* Image length */
+	uint32_t version;	/* For sanity checks and future
+				 * extended functionality
+				 */
+} img_header_t;
+
+#endif /* MSS_SCP_BL2_FORMAT_H */
diff --git a/plat/marvell/common/mss/mss_scp_bootloader.c b/plat/marvell/common/mss/mss_scp_bootloader.c
new file mode 100644
index 0000000..7e442c6
--- /dev/null
+++ b/plat/marvell/common/mss/mss_scp_bootloader.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_pm_trace.h>
+#include <mss_scp_bootloader.h>
+#include <mss_ipc_drv.h>
+#include <mss_mem.h>
+#include <mss_scp_bl2_format.h>
+
+#define MSS_DMA_SRCBR(base)		(base + 0xC0)
+#define MSS_DMA_DSTBR(base)		(base + 0xC4)
+#define MSS_DMA_CTRLR(base)		(base + 0xC8)
+#define MSS_M3_RSTCR(base)		(base + 0xFC)
+
+#define MSS_DMA_CTRLR_SIZE_OFFSET	(0)
+#define MSS_DMA_CTRLR_REQ_OFFSET	(15)
+#define MSS_DMA_CTRLR_REQ_SET		(1)
+#define MSS_DMA_CTRLR_ACK_OFFSET	(12)
+#define MSS_DMA_CTRLR_ACK_MASK		(0x1)
+#define MSS_DMA_CTRLR_ACK_READY		(1)
+#define MSS_M3_RSTCR_RST_OFFSET		(0)
+#define MSS_M3_RSTCR_RST_OFF		(1)
+
+#define MSS_DMA_TIMEOUT			1000
+#define MSS_EXTERNAL_SPACE		0x50000000
+#define MSS_EXTERNAL_ADDR_MASK		0xfffffff
+
+#define DMA_SIZE			128
+
+#define MSS_HANDSHAKE_TIMEOUT		50
+
+static int mss_check_image_ready(volatile struct mss_pm_ctrl_block *mss_pm_crtl)
+{
+	int timeout = MSS_HANDSHAKE_TIMEOUT;
+
+	/* Wait for SCP to signal it's ready */
+	while ((mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) &&
+						(timeout-- > 0))
+		mdelay(1);
+
+	if (mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT)
+		return -1;
+
+	mss_pm_crtl->handshake = HOST_ACKNOWLEDGMENT;
+
+	return 0;
+}
+
+static int mss_image_load(uint32_t src_addr, uint32_t size, uintptr_t mss_regs)
+{
+	uint32_t i, loop_num, timeout;
+
+	/* Check if the img size is not bigger than ID-RAM size of MSS CM3 */
+	if (size > MSS_IDRAM_SIZE) {
+		ERROR("image is too big to fit into MSS CM3 memory\n");
+		return 1;
+	}
+
+	NOTICE("Loading MSS image from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
+	       src_addr, size, mss_regs);
+	/* load image to MSS RAM using DMA */
+	loop_num = (size / DMA_SIZE) + (((size & (DMA_SIZE - 1)) == 0) ? 0 : 1);
+
+	for (i = 0; i < loop_num; i++) {
+		/* write destination and source addresses */
+		mmio_write_32(MSS_DMA_SRCBR(mss_regs),
+			      MSS_EXTERNAL_SPACE |
+			      ((src_addr & MSS_EXTERNAL_ADDR_MASK) +
+			      (i * DMA_SIZE)));
+		mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
+
+		dsb(); /* make sure DMA data is ready before triggering it */
+
+		/* set the DMA control register */
+		mmio_write_32(MSS_DMA_CTRLR(mss_regs), ((MSS_DMA_CTRLR_REQ_SET
+			      << MSS_DMA_CTRLR_REQ_OFFSET) |
+			      (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET)));
+
+		/* Poll DMA_ACK at MSS_DMACTLR until it is ready */
+		timeout = MSS_DMA_TIMEOUT;
+		while (timeout) {
+			if ((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >>
+			     MSS_DMA_CTRLR_ACK_OFFSET & MSS_DMA_CTRLR_ACK_MASK)
+				== MSS_DMA_CTRLR_ACK_READY) {
+				break;
+			}
+
+			udelay(50);
+			timeout--;
+		}
+
+		if (timeout == 0) {
+			ERROR("\nDMA failed to load MSS image\n");
+			return 1;
+		}
+	}
+
+	bl2_plat_configure_mss_windows(mss_regs);
+
+	/* Release M3 from reset */
+	mmio_write_32(MSS_M3_RSTCR(mss_regs), (MSS_M3_RSTCR_RST_OFF <<
+		      MSS_M3_RSTCR_RST_OFFSET));
+
+	NOTICE("Done\n");
+
+	return 0;
+}
+
+/* Load image to MSS AP and do PM related initialization
+ * Note that this routine is different than other CM3 loading routines, because
+ * firmware for AP is dedicated for PM and therefore some additional PM
+ * initialization is required
+ */
+static int mss_ap_load_image(uintptr_t single_img,
+			     uint32_t image_size, uint32_t ap_idx)
+{
+	volatile struct mss_pm_ctrl_block *mss_pm_crtl;
+	int ret;
+
+	/* TODO: add PM Control Info from platform */
+	mss_pm_crtl = (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE;
+	mss_pm_crtl->ipc_version                = MV_PM_FW_IPC_VERSION;
+	mss_pm_crtl->num_of_clusters            = PLAT_MARVELL_CLUSTER_COUNT;
+	mss_pm_crtl->num_of_cores_per_cluster   =
+						PLAT_MARVELL_CLUSTER_CORE_COUNT;
+	mss_pm_crtl->num_of_cores               = PLAT_MARVELL_CLUSTER_COUNT *
+						PLAT_MARVELL_CLUSTER_CORE_COUNT;
+	mss_pm_crtl->pm_trace_ctrl_base_address = AP_MSS_ATF_CORE_CTRL_BASE;
+	mss_pm_crtl->pm_trace_info_base_address = AP_MSS_ATF_CORE_INFO_BASE;
+	mss_pm_crtl->pm_trace_info_core_size    = AP_MSS_ATF_CORE_INFO_SIZE;
+	VERBOSE("MSS Control Block = 0x%x\n", MSS_SRAM_PM_CONTROL_BASE);
+	VERBOSE("mss_pm_crtl->ipc_version                = 0x%x\n",
+		mss_pm_crtl->ipc_version);
+	VERBOSE("mss_pm_crtl->num_of_cores               = 0x%x\n",
+		mss_pm_crtl->num_of_cores);
+	VERBOSE("mss_pm_crtl->num_of_clusters            = 0x%x\n",
+		mss_pm_crtl->num_of_clusters);
+	VERBOSE("mss_pm_crtl->num_of_cores_per_cluster   = 0x%x\n",
+		mss_pm_crtl->num_of_cores_per_cluster);
+	VERBOSE("mss_pm_crtl->pm_trace_ctrl_base_address = 0x%x\n",
+		mss_pm_crtl->pm_trace_ctrl_base_address);
+	VERBOSE("mss_pm_crtl->pm_trace_info_base_address = 0x%x\n",
+		mss_pm_crtl->pm_trace_info_base_address);
+	VERBOSE("mss_pm_crtl->pm_trace_info_core_size    = 0x%x\n",
+		mss_pm_crtl->pm_trace_info_core_size);
+
+	/* TODO: add checksum to image */
+	VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n");
+
+	ret = mss_image_load(single_img, image_size,
+			     bl2_plat_get_ap_mss_regs(ap_idx));
+	if (ret != 0) {
+		ERROR("SCP Image load failed\n");
+		return -1;
+	}
+
+	/* check that the image was loaded successfully */
+	ret = mss_check_image_ready(mss_pm_crtl);
+	if (ret != 0)
+		NOTICE("SCP Image doesn't contain PM firmware\n");
+
+	return 0;
+}
+
+/* Load CM3 image (single_img) to CM3 pointed by cm3_type */
+static int load_img_to_cm3(enum cm3_t cm3_type,
+			   uintptr_t single_img, uint32_t image_size)
+{
+	int ret, ap_idx, cp_index;
+	uint32_t ap_count = bl2_plat_get_ap_count();
+
+	switch (cm3_type) {
+	case MSS_AP:
+		for (ap_idx = 0; ap_idx < ap_count; ap_idx++) {
+			NOTICE("Load image to AP%d MSS\n", ap_idx);
+			ret = mss_ap_load_image(single_img, image_size, ap_idx);
+			if (ret != 0)
+				return ret;
+		}
+		break;
+	case MSS_CP0:
+	case MSS_CP1:
+	case MSS_CP2:
+	case MSS_CP3:
+		/* MSS_AP = 0
+		 * MSS_CP1 = 1
+		 * .
+		 * .
+		 * MSS_CP3 = 4
+		 * Actual CP index is MSS_CPX - 1
+		 */
+		cp_index = cm3_type - 1;
+		for (ap_idx = 0; ap_idx < ap_count; ap_idx++) {
+			/* Check if we should load this image
+			 * according to number of CPs
+			 */
+			if (bl2_plat_get_cp_count(ap_idx) <= cp_index) {
+				NOTICE("Skipping MSS CP%d related image\n",
+				       cp_index);
+				break;
+			}
+
+			NOTICE("Load image to CP%d MSS AP%d\n",
+			       cp_index, ap_idx);
+			ret = mss_image_load(single_img, image_size,
+					     bl2_plat_get_cp_mss_regs(
+						     ap_idx, cp_index));
+			if (ret != 0) {
+				ERROR("SCP Image load failed\n");
+				return -1;
+			}
+		}
+		break;
+	case MG_CP0:
+		/* TODO: */
+		NOTICE("Load image to CP0 MG not supported\n");
+		break;
+	case MG_CP1:
+		/* TODO: */
+		NOTICE("Load image to CP1 MG not supported\n");
+		break;
+	default:
+		ERROR("SCP_BL2 wrong img format (cm3_type=%d)\n", cm3_type);
+		break;
+	}
+
+	return 0;
+}
+
+/* The Armada 8K has 5 service CPUs and Armada 7K has 3. Therefore it was
+ * required to provide a method for loading firmware to all of the service CPUs.
+ * To achieve that, the scp_bl2 image in fact is file containing up to 5
+ * concatenated firmwares and this routine splits concatenated image into single
+ * images dedicated for appropriate service CPU and then load them.
+ */
+static int split_and_load_bl2_image(void *image)
+{
+	file_header_t *file_hdr;
+	img_header_t *img_hdr;
+	uintptr_t single_img;
+	int i;
+
+	file_hdr = (file_header_t *)image;
+
+	if (file_hdr->magic != FILE_MAGIC) {
+		ERROR("SCP_BL2 wrong img format\n");
+		return -1;
+	}
+
+	if (file_hdr->nr_of_imgs > MAX_NR_OF_FILES) {
+		ERROR("SCP_BL2 concatenated image contains to many images\n");
+		return -1;
+	}
+
+	img_hdr = (img_header_t *)((uintptr_t)image + sizeof(file_header_t));
+	single_img = (uintptr_t)image + sizeof(file_header_t) +
+				    sizeof(img_header_t) * file_hdr->nr_of_imgs;
+
+	NOTICE("SCP_BL2 contains %d concatenated images\n",
+							  file_hdr->nr_of_imgs);
+	for (i = 0; i < file_hdr->nr_of_imgs; i++) {
+
+		/* Before loading make sanity check on header */
+		if (img_hdr->version != HEADER_VERSION) {
+			ERROR("Wrong header, img corrupted exiting\n");
+			return -1;
+		}
+
+		load_img_to_cm3(img_hdr->type, single_img, img_hdr->length);
+
+		/* Prepare offsets for next run */
+		single_img += img_hdr->length;
+		img_hdr++;
+	}
+
+	return 0;
+}
+
+int scp_bootloader_transfer(void *image, unsigned int image_size)
+{
+#ifdef SCP_BL2_BASE
+	assert((uintptr_t) image == SCP_BL2_BASE);
+#endif
+
+	VERBOSE("Concatenated img size %d\n", image_size);
+
+	if (image_size == 0) {
+		ERROR("SCP_BL2 image size can't be 0 (current size = 0x%x)\n",
+								    image_size);
+		return -1;
+	}
+
+	if (split_and_load_bl2_image(image))
+		return -1;
+
+	return 0;
+}
diff --git a/plat/marvell/common/mss/mss_scp_bootloader.h b/plat/marvell/common/mss/mss_scp_bootloader.h
new file mode 100644
index 0000000..4950d24
--- /dev/null
+++ b/plat/marvell/common/mss/mss_scp_bootloader.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MSS_SCP_BOOTLOADER_H
+#define MSS_SCP_BOOTLOADER_H
+
+int scp_bootloader_transfer(void *image, unsigned int image_size);
+uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx);
+uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx);
+uint32_t bl2_plat_get_cp_count(int ap_idx);
+uint32_t bl2_plat_get_ap_count(void);
+void bl2_plat_configure_mss_windows(uintptr_t mss_regs);
+int bl2_plat_mss_check_image_ready(void);
+
+#endif /* MSS_SCP_BOOTLOADER_H */
diff --git a/plat/marvell/common/plat_delay_timer.c b/plat/marvell/common/plat_delay_timer.c
new file mode 100644
index 0000000..2539752
--- /dev/null
+++ b/plat/marvell/common/plat_delay_timer.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+
+#include <mvebu_def.h>
+
+#define SYS_COUNTER_FREQ_IN_MHZ	(COUNTER_FREQUENCY/1000000)
+
+static uint32_t plat_get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static const timer_ops_t plat_timer_ops = {
+	.get_timer_value	= plat_get_timer_value,
+	.clk_mult		= 1,
+	.clk_div		= SYS_COUNTER_FREQ_IN_MHZ
+};
+
+void plat_delay_timer_init(void)
+{
+	timer_init(&plat_timer_ops);
+}
diff --git a/plat/marvell/marvell.mk b/plat/marvell/marvell.mk
new file mode 100644
index 0000000..d8be0dd
--- /dev/null
+++ b/plat/marvell/marvell.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+# Marvell images
+BOOT_IMAGE			:= boot-image.bin
+BOOT_ENC_IMAGE			:= boot-image-enc.bin
+FLASH_IMAGE			:= flash-image.bin
+
+# Make non-trusted image by default
+MARVELL_SECURE_BOOT		:= 0
+$(eval $(call add_define,MARVELL_SECURE_BOOT))
+
+# Enable compilation for Palladium emulation platform
+PALLADIUM			:= 0
+$(eval $(call add_define,PALLADIUM))
+
+ifeq (${MARVELL_SECURE_BOOT},1)
+DOIMAGE_SEC_FLAGS := -c $(DOIMAGE_SEC)
+DOIMAGE_LIBS_CHECK = \
+        if ! [ -d "/usr/include/mbedtls" ]; then \
+                        echo "****************************************" >&2; \
+                        echo "Missing mbedTLS installation! " >&2; \
+                        echo "Please download it from \"tls.mbed.org\"" >&2; \
+			echo "Alternatively on Debian/Ubuntu system install" >&2; \
+			echo "\"libmbedtls-dev\" package" >&2; \
+                        echo "Make sure to use version 2.1.0 or later" >&2; \
+                        echo "****************************************" >&2; \
+                exit 1; \
+        else if ! [ -f "/usr/include/libconfig.h" ]; then \
+                        echo "********************************************************" >&2; \
+                        echo "Missing Libconfig installation!" >&2; \
+                        echo "Please download it from \"www.hyperrealm.com/libconfig/\"" >&2; \
+                        echo "Alternatively on Debian/Ubuntu system install packages" >&2; \
+                        echo "\"libconfig8\" and \"libconfig8-dev\"" >&2; \
+                        echo "********************************************************" >&2; \
+                exit 1; \
+        fi \
+        fi
+else #MARVELL_SECURE_BOOT
+DOIMAGE_LIBS_CHECK =
+DOIMAGE_SEC_FLAGS =
+endif #MARVELL_SECURE_BOOT
+
+mrvl_clean:
+	@echo "  Doimage CLEAN"
+	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean
+
+${DOIMAGETOOL}: mrvl_clean
+	@$(DOIMAGE_LIBS_CHECK)
+	${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} VERSION=$(SUBVERSION) WTMI_IMG=$(WTMI_IMG)
+
+
diff --git a/plat/marvell/version.mk b/plat/marvell/version.mk
new file mode 100644
index 0000000..e072e12
--- /dev/null
+++ b/plat/marvell/version.mk
@@ -0,0 +1 @@
+SUBVERSION = devel-18.12.0
diff --git a/plat/mediatek/common/custom/oem_svc.c b/plat/mediatek/common/custom/oem_svc.c
new file mode 100644
index 0000000..27ee6aa
--- /dev/null
+++ b/plat/mediatek/common/custom/oem_svc.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#include <oem_svc.h>
+
+/* OEM Service UUID */
+DEFINE_SVC_UUID2(oem_svc_uid,
+	0xd0ad43b9, 0x9b06, 0xe411, 0x91, 0x91,
+	0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66);
+
+/* Setup OEM Services */
+static int32_t oem_svc_setup(void)
+{
+	/*
+	 * Invoke related module setup from here
+	 */
+
+	return 0;
+}
+
+/*******************************************************************************
+ * OEM top level handler for servicing SMCs.
+ ******************************************************************************/
+uintptr_t oem_smc_handler(uint32_t smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	WARN("Unimplemented OEM Call: 0x%x\n", smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/*
+ * Top-level OEM Service SMC handler. This handler will in turn dispatch
+ * calls to related SMC handler
+ */
+uintptr_t oem_svc_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	/*
+	 * Dispatch OEM calls to OEM Common handler and return its return value
+	 */
+	if (is_oem_fid(smc_fid)) {
+		return oem_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+					handle, flags);
+	}
+
+	switch (smc_fid) {
+	case OEM_SVC_CALL_COUNT:
+		/*
+		 * Return the number of OEM Service Calls.
+		 */
+		SMC_RET1(handle, OEM_SVC_NUM_CALLS);
+
+	case OEM_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, oem_svc_uid);
+
+	case OEM_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, OEM_VERSION_MAJOR, OEM_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented OEM Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Register OEM Service Calls as runtime service */
+DECLARE_RT_SVC(
+		oem_svc,
+		OEN_OEM_START,
+		OEN_OEM_END,
+		SMC_TYPE_FAST,
+		oem_svc_setup,
+		oem_svc_smc_handler
+);
diff --git a/plat/mediatek/common/custom/oem_svc.h b/plat/mediatek/common/custom/oem_svc.h
new file mode 100644
index 0000000..76f7c24
--- /dev/null
+++ b/plat/mediatek/common/custom/oem_svc.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OEM_SVC_H
+#define OEM_SVC_H
+
+/*******************************************************************************
+ * Defines for runtime services func ids
+ ******************************************************************************/
+/*
+ * Number of OEM calls (above) implemented.
+ */
+#define OEM_SVC_NUM_CALLS		3
+
+/*******************************************************************************
+ * Defines for OEM Service queries
+ ******************************************************************************/
+/* 0x83000000 - 0x8300FEFF is OEM service calls */
+#define OEM_SVC_CALL_COUNT		0x8300ff00
+#define OEM_SVC_UID			0x8300ff01
+/* 0x8300ff02 is reserved */
+#define OEM_SVC_VERSION			0x8300ff03
+/* 0x8300ff04 - 0x8300FFFF is reserved for future expansion */
+
+/* OEM Service Calls version numbers */
+#define OEM_VERSION_MAJOR		0x0
+#define OEM_VERSION_MINOR		0x1
+
+/* The macros below are used to identify OEM calls from the SMC function ID */
+/* SMC32 ID range from 0x83000000 to 0x83000FFF */
+/* SMC64 ID range from 0xC3000000 to 0xC3000FFF */
+#define OEM_FID_MASK			0xf000u
+#define OEM_FID_VALUE			0u
+#define is_oem_fid(_fid) \
+	(((_fid) & OEM_FID_MASK) == OEM_FID_VALUE)
+
+#define OEM_SVC_E_SUCCESS		0
+#define OEM_SVC_E_NOT_SUPPORTED		-1
+#define OEM_SVC_E_INVALID_PARAMS	-2
+
+#endif /* OEM_SVC_H */
diff --git a/plat/mediatek/common/drivers/uart/8250_console.S b/plat/mediatek/common/drivers/uart/8250_console.S
new file mode 100644
index 0000000..94a6c02
--- /dev/null
+++ b/plat/mediatek/common/drivers/uart/8250_console.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+#include <uart8250.h>
+
+	.globl	console_core_init
+	.globl	console_core_putc
+	.globl	console_core_getc
+	.globl	console_core_flush
+
+	/* -----------------------------------------------
+	 * int console_core_init(unsigned long base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : x1, x2, x3
+	 * -----------------------------------------------
+	 */
+func console_core_init
+	/* Check the input base address */
+	cbz	x0, core_init_fail
+	/* Check baud rate and uart clock for sanity */
+	cbz	w1, core_init_fail
+	cbz	w2, core_init_fail
+
+	/* Disable interrupt */
+	str	wzr, [x0, #UART_IER]
+
+	/* Force DTR and RTS to high */
+	mov	w3, #(UART_MCR_DTR | UART_MCR_RTS)
+	str	w3, [x0, #UART_MCR]
+
+	/* Check high speed */
+	movz	w3, #:abs_g1:115200
+	movk	w3, #:abs_g0_nc:115200
+	cmp	w2, w3
+	b.hi	1f
+
+	/* Non high speed */
+	lsl	w2, w2, #4
+	mov	w3, wzr
+	b	2f
+
+	/* High speed */
+1:	lsl	w2, w2, #2
+	mov	w3, #2
+
+	/* Set high speed UART register */
+2:	str	w3, [x0, #UART_HIGHSPEED]
+
+	/* Calculate divisor */
+	udiv	w3, w1, w2	/* divisor = uartclk / (quot * baudrate) */
+	msub	w1, w3, w2, w1	/* remainder = uartclk % (quot * baudrate) */
+	lsr	w2, w2, #1
+	cmp	w1, w2
+	cinc	w3, w3, hs
+
+	/* Set line configuration, access divisor latches */
+	mov	w1, #(UART_LCR_DLAB | UART_LCR_WLS_8)
+	str	w1, [x0, #UART_LCR]
+
+	/* Set the divisor */
+	and	w1, w3, #0xff
+	str	w1, [x0, #UART_DLL]
+	lsr	w1, w3, #8
+	and	w1, w1, #0xff
+	str	w1, [x0, #UART_DLH]
+
+	/* Hide the divisor latches */
+	mov	w1, #UART_LCR_WLS_8
+	str	w1, [x0, #UART_LCR]
+
+	/* Enable FIFOs, and clear receive and transmit */
+	mov	w1, #(UART_FCR_FIFO_EN | UART_FCR_CLEAR_RCVR |	\
+			UART_FCR_CLEAR_XMIT)
+	str	w1, [x0, #UART_FCR]
+
+	mov	w0, #1
+	ret
+core_init_fail:
+	mov	w0, wzr
+	ret
+endfunc console_core_init
+
+	/* --------------------------------------------------------
+	 * int console_core_putc(int c, unsigned long base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_core_putc
+	/* Check the input parameter */
+	cbz	x1, putc_error
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+
+	/* Check if the transmit FIFO is full */
+1:	ldr	w2, [x1, #UART_LSR]
+	and	w2, w2, #UART_LSR_THRE
+	cbz	w2, 1b
+	mov	w2, #0xD
+	str	w2, [x1, #UART_THR]
+
+	/* Check if the transmit FIFO is full */
+2:	ldr	w2, [x1, #UART_LSR]
+	and	w2, w2, #UART_LSR_THRE
+	cbz	w2, 2b
+	str	w0, [x1, #UART_THR]
+	ret
+putc_error:
+	mov	w0, #-1
+	ret
+endfunc console_core_putc
+
+	/* ---------------------------------------------
+	 * int console_core_getc(unsigned long base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on error.
+	 * In : x0 - console base address
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_core_getc
+	cbz	x0, getc_error
+
+	/* Check if the receive FIFO is empty */
+1:	ldr	w1, [x0, #UART_LSR]
+	tbz	w1, #UART_LSR_DR, 1b
+	ldr	w0, [x0, #UART_RBR]
+	ret
+getc_error:
+	mov	w0, #-1
+	ret
+endfunc console_core_getc
+
+	/* ---------------------------------------------
+	 * int console_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_core_flush
+	/* Placeholder */
+	mov	w0, #0
+	ret
+endfunc console_core_flush
diff --git a/plat/mediatek/common/drivers/uart/uart8250.h b/plat/mediatek/common/drivers/uart/uart8250.h
new file mode 100644
index 0000000..da7c7a1
--- /dev/null
+++ b/plat/mediatek/common/drivers/uart/uart8250.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef UART8250_H
+#define UART8250_H
+
+/* UART register */
+#define UART_RBR		0x00	/* Receive buffer register */
+#define UART_DLL		0x00	/* Divisor latch lsb */
+#define UART_THR		0x00	/* Transmit holding register */
+#define UART_DLH		0x04	/* Divisor latch msb */
+#define UART_IER		0x04	/* Interrupt enable register */
+#define UART_FCR		0x08	/* FIFO control register */
+#define UART_LCR		0x0c	/* Line control register */
+#define UART_MCR		0x10	/* Modem control register */
+#define UART_LSR		0x14	/* Line status register */
+#define UART_HIGHSPEED		0x24	/* High speed UART */
+
+/* FCR */
+#define UART_FCR_FIFO_EN	0x01	/* enable FIFO */
+#define UART_FCR_CLEAR_RCVR	0x02	/* clear the RCVR FIFO */
+#define UART_FCR_CLEAR_XMIT	0x04	/* clear the XMIT FIFO */
+
+/* LCR */
+#define UART_LCR_WLS_8		0x03	/* 8 bit character length */
+#define UART_LCR_DLAB		0x80	/* divisor latch access bit */
+
+/* MCR */
+#define UART_MCR_DTR		0x01
+#define UART_MCR_RTS		0x02
+
+/* LSR */
+#define UART_LSR_DR		0x01	/* Data ready */
+#define UART_LSR_THRE		0x20	/* Xmit holding register empty */
+
+#endif /* UART8250_H */
diff --git a/plat/mediatek/common/mtk_plat_common.c b/plat/mediatek/common/mtk_plat_common.c
new file mode 100644
index 0000000..a07a298
--- /dev/null
+++ b/plat/mediatek/common/mtk_plat_common.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include <mtk_plat_common.h>
+#include <mtk_sip_svc.h>
+#include <plat_private.h>
+
+struct atf_arg_t gteearg;
+
+void clean_top_32b_of_param(uint32_t smc_fid,
+				u_register_t *px1,
+				u_register_t *px2,
+				u_register_t *px3,
+				u_register_t *px4)
+{
+	/* if parameters from SMC32. Clean top 32 bits */
+	if (0 == (smc_fid & SMC_AARCH64_BIT)) {
+		*px1 = *px1 & SMC32_PARAM_MASK;
+		*px2 = *px2 & SMC32_PARAM_MASK;
+		*px3 = *px3 & SMC32_PARAM_MASK;
+		*px4 = *px4 & SMC32_PARAM_MASK;
+	}
+}
+
+#if MTK_SIP_KERNEL_BOOT_ENABLE
+static struct kernel_info k_info;
+
+static void save_kernel_info(uint64_t pc,
+			uint64_t r0,
+			uint64_t r1,
+			uint64_t k32_64)
+{
+	k_info.k32_64 = k32_64;
+	k_info.pc = pc;
+
+	if (LINUX_KERNEL_32 ==  k32_64) {
+		/* for 32 bits kernel */
+		k_info.r0 = 0;
+		/* machtype */
+		k_info.r1 = r0;
+		/* tags */
+		k_info.r2 = r1;
+	} else {
+		/* for 64 bits kernel */
+		k_info.r0 = r0;
+		k_info.r1 = r1;
+	}
+}
+
+uint64_t get_kernel_info_pc(void)
+{
+	return k_info.pc;
+}
+
+uint64_t get_kernel_info_r0(void)
+{
+	return k_info.r0;
+}
+
+uint64_t get_kernel_info_r1(void)
+{
+	return k_info.r1;
+}
+
+uint64_t get_kernel_info_r2(void)
+{
+	return k_info.r2;
+}
+
+void boot_to_kernel(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
+{
+	static uint8_t kernel_boot_once_flag;
+	/* only support in booting flow */
+	if (0 == kernel_boot_once_flag) {
+		kernel_boot_once_flag = 1;
+
+		console_init(gteearg.atf_log_port,
+			UART_CLOCK, UART_BAUDRATE);
+		INFO("save kernel info\n");
+		save_kernel_info(x1, x2, x3, x4);
+		bl31_prepare_kernel_entry(x4);
+		INFO("el3_exit\n");
+		console_uninit();
+	}
+}
+#endif
+
+uint32_t plat_get_spsr_for_bl33_entry(void)
+{
+	unsigned int mode;
+	uint32_t spsr;
+	unsigned int ee;
+	unsigned long daif;
+
+	INFO("Secondary bootloader is AArch32\n");
+	mode = MODE32_svc;
+	ee = 0;
+	/*
+	 * TODO: Choose async. exception bits if HYP mode is not
+	 * implemented according to the values of SCR.{AW, FW} bits
+	 */
+	daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
+
+	spsr = SPSR_MODE32(mode, 0, ee, daif);
+	return spsr;
+}
diff --git a/plat/mediatek/common/mtk_plat_common.h b/plat/mediatek/common/mtk_plat_common.h
new file mode 100644
index 0000000..55f4c51
--- /dev/null
+++ b/plat/mediatek/common/mtk_plat_common.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MTK_PLAT_COMMON_H
+#define MTK_PLAT_COMMON_H
+
+#include <stdint.h>
+
+#include <common/bl_common.h>
+#include <common/param_header.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+#define DEVINFO_SIZE 4
+#define LINUX_KERNEL_32 0
+#define SMC32_PARAM_MASK		(0xFFFFFFFF)
+
+struct atf_arg_t {
+	unsigned int atf_magic;
+	unsigned int tee_support;
+	unsigned int tee_entry;
+	unsigned int tee_boot_arg_addr;
+	unsigned int hwuid[4];     /* HW Unique id for t-base used */
+	unsigned int HRID[2];      /* HW random id for t-base used */
+	unsigned int atf_log_port;
+	unsigned int atf_log_baudrate;
+	unsigned int atf_log_buf_start;
+	unsigned int atf_log_buf_size;
+	unsigned int atf_irq_num;
+	unsigned int devinfo[DEVINFO_SIZE];
+	unsigned int atf_aee_debug_buf_start;
+	unsigned int atf_aee_debug_buf_size;
+};
+
+struct kernel_info {
+	uint64_t pc;
+	uint64_t r0;
+	uint64_t r1;
+	uint64_t r2;
+	uint64_t k32_64;
+};
+
+struct mtk_bl_param_t {
+	uint64_t bootarg_loc;
+	uint64_t bootarg_size;
+	uint64_t bl33_start_addr;
+	uint64_t tee_info_addr;
+};
+
+struct mtk_bl31_params {
+       param_header_t h;
+       image_info_t *bl31_image_info;
+       entry_point_info_t *bl32_ep_info;
+       image_info_t *bl32_image_info;
+       entry_point_info_t *bl33_ep_info;
+       image_info_t *bl33_image_info;
+};
+
+/* Declarations for mtk_plat_common.c */
+uint32_t plat_get_spsr_for_bl32_entry(void);
+uint32_t plat_get_spsr_for_bl33_entry(void);
+void clean_top_32b_of_param(uint32_t smc_fid, u_register_t *x1,
+				u_register_t *x2,
+				u_register_t *x3,
+				u_register_t *x4);
+void bl31_prepare_kernel_entry(uint64_t k32_64);
+void enable_ns_access_to_cpuectlr(void);
+void boot_to_kernel(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4);
+uint64_t get_kernel_info_pc(void);
+uint64_t get_kernel_info_r0(void);
+uint64_t get_kernel_info_r1(void);
+uint64_t get_kernel_info_r2(void);
+
+extern struct atf_arg_t gteearg;
+#endif /* MTK_PLAT_COMMON_H */
diff --git a/plat/mediatek/common/mtk_sip_svc.c b/plat/mediatek/common/mtk_sip_svc.c
new file mode 100644
index 0000000..dab0d45
--- /dev/null
+++ b/plat/mediatek/common/mtk_sip_svc.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include <mtk_plat_common.h>
+#include <mtk_sip_svc.h>
+#include <plat_sip_calls.h>
+
+/* Mediatek SiP Service UUID */
+DEFINE_SVC_UUID2(mtk_sip_svc_uid,
+	0xa42b58f7, 0x6242, 0x7d4d, 0x80, 0xe5,
+	0x8f, 0x95, 0x05, 0x00, 0x0f, 0x3d);
+
+#pragma weak mediatek_plat_sip_handler
+uintptr_t mediatek_plat_sip_handler(uint32_t smc_fid,
+				u_register_t x1,
+				u_register_t x2,
+				u_register_t x3,
+				u_register_t x4,
+				void *cookie,
+				void *handle,
+				u_register_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/*
+ * This function handles Mediatek defined SiP Calls */
+uintptr_t mediatek_sip_handler(uint32_t smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	uint32_t ns;
+
+	/* if parameter is sent from SMC32. Clean top 32 bits */
+	clean_top_32b_of_param(smc_fid, &x1, &x2, &x3, &x4);
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+	if (!ns) {
+		/* SiP SMC service secure world's call */
+		;
+	} else {
+		/* SiP SMC service normal world's call */
+		switch (smc_fid) {
+#if MTK_SIP_SET_AUTHORIZED_SECURE_REG_ENABLE
+		case MTK_SIP_SET_AUTHORIZED_SECURE_REG: {
+			/* only use ret here */
+			uint64_t ret;
+
+			ret = mt_sip_set_authorized_sreg((uint32_t)x1,
+				(uint32_t)x2);
+			SMC_RET1(handle, ret);
+		}
+#endif
+#if MTK_SIP_KERNEL_BOOT_ENABLE
+		case MTK_SIP_KERNEL_BOOT_AARCH32:
+			boot_to_kernel(x1, x2, x3, x4);
+			SMC_RET0(handle);
+#endif
+		default:
+			/* Do nothing in default case */
+			break;
+		}
+	}
+
+	return mediatek_plat_sip_handler(smc_fid, x1, x2, x3, x4,
+					cookie, handle, flags);
+
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+uintptr_t sip_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	switch (smc_fid) {
+	case SIP_SVC_CALL_COUNT:
+		/* Return the number of Mediatek SiP Service Calls. */
+		SMC_RET1(handle,
+			 MTK_COMMON_SIP_NUM_CALLS + MTK_PLAT_SIP_NUM_CALLS);
+
+	case SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, mtk_sip_svc_uid);
+
+	case SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, MTK_SIP_SVC_VERSION_MAJOR,
+			MTK_SIP_SVC_VERSION_MINOR);
+
+	default:
+		return mediatek_sip_handler(smc_fid, x1, x2, x3, x4,
+			cookie, handle, flags);
+	}
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	mediatek_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	sip_smc_handler
+);
diff --git a/plat/mediatek/common/mtk_sip_svc.h b/plat/mediatek/common/mtk_sip_svc.h
new file mode 100644
index 0000000..cd4096e
--- /dev/null
+++ b/plat/mediatek/common/mtk_sip_svc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MTK_SIP_SVC_H
+#define MTK_SIP_SVC_H
+
+#include <stdint.h>
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT		0x8200ff00
+#define SIP_SVC_UID			0x8200ff01
+/*					0x8200ff02 is reserved */
+#define SIP_SVC_VERSION			0x8200ff03
+
+/* Mediatek SiP Service Calls version numbers */
+#define MTK_SIP_SVC_VERSION_MAJOR	0x0
+#define MTK_SIP_SVC_VERSION_MINOR	0x1
+
+#define SMC_AARCH64_BIT		0x40000000
+
+/* Number of Mediatek SiP Calls implemented */
+#define MTK_COMMON_SIP_NUM_CALLS	4
+
+/* Mediatek SiP Service Calls function IDs */
+#define MTK_SIP_SET_AUTHORIZED_SECURE_REG	0x82000001
+
+/* For MTK SMC from Secure OS */
+/* 0x82000000 - 0x820000FF & 0xC2000000 - 0xC20000FF */
+#define MTK_SIP_KERNEL_BOOT_AARCH32		0x82000200
+#define MTK_SIP_KERNEL_BOOT_AARCH64		0xC2000200
+
+/* Mediatek SiP Calls error code */
+enum {
+	MTK_SIP_E_SUCCESS = 0,
+	MTK_SIP_E_INVALID_PARAM = -1,
+	MTK_SIP_E_NOT_SUPPORTED = -2,
+	MTK_SIP_E_INVALID_RANGE = -3,
+	MTK_SIP_E_PERMISSION_DENY = -4,
+	MTK_SIP_E_LOCK_FAIL = -5
+};
+
+/*
+ * This function should be implemented in Mediatek SOC directory. It fullfills
+ * MTK_SIP_SET_AUTHORIZED_SECURE_REG SiP call by checking the sreg with the
+ * predefined secure register list, if a match was found, set val to sreg.
+ *
+ * Return MTK_SIP_E_SUCCESS on success, and MTK_SIP_E_INVALID_PARAM on failure.
+ */
+uint64_t mt_sip_set_authorized_sreg(uint32_t sreg, uint32_t val);
+
+#endif /* MTK_SIP_SVC_H */
diff --git a/plat/mediatek/mt6795/aarch64/plat_helpers.S b/plat/mediatek/mt6795/aarch64/plat_helpers.S
new file mode 100644
index 0000000..94f9eae
--- /dev/null
+++ b/plat/mediatek/mt6795/aarch64/plat_helpers.S
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_report_exception
+	.globl	platform_is_primary_cpu
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	platform_mem_init
+
+
+	.macro crash_ram_log
+	 /*
+	 * Check teearg->atf_log_buf_size.
+	 * Exit if atf_log_buf_size equals 0
+	 */
+	adr	x2, ptr_atf_crash_flag
+	ldr	x2, [x2]
+	/* exit if ptr_atf_crash_flag equals NULL */
+	cbz x2, exit_putc
+
+	/*
+	 * set atf crash magic number
+	 */
+1:
+	adr	x2, ptr_atf_crash_flag
+	ldr	x2, [x2]
+	mov_imm x1, 0xdead1abf
+	/* p_atf_log_ctrl->atf_crash_flag = 0xdead1abf */
+	str	w1, [x2]
+	/* can't use w3 return addr, w4, start of buffer addr */
+	ldr	w2, [x2]
+	cmp	w2, w1
+	b.ne	1b
+
+	/*
+	 * get cpu id
+	 */
+	mrs	x1, mpidr_el1
+	/* refer to platform_get_core_pos */
+	and	x2, x1, #MPIDR_CPU_MASK
+	and	x1, x1, #MPIDR_CLUSTER_MASK
+	/* x1 = cpu id (cpu id = aff0 + aff1*4 ) */
+	add	x1, x2, x1, LSR #6
+
+	adr	x2, ptr_atf_except_write_pos_per_cpu
+	ldr	x2, [x2]
+	/*
+	 * plus (cpu_id * 8)-->
+	 * &p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id]
+	 * x2 = &p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id];
+	 */
+	add x2, x2, x1, LSL # 3
+	/* log write */
+	/* w1 = p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] */
+	ldr	x1, [x2]
+	/* *x1 = w0-->
+	 *  *(p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id]) = c)
+	 */
+	strb	w0, [x1]
+	/* w1++ */
+	add	x1, x1, #1
+	/* p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] = w1 */
+	str	x1, [x2]
+exit_putc:
+	.endm
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Do not do cold boot for secondary CPU */
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func platform_is_primary_cpu
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #PLAT_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc platform_is_primary_cpu
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, UART0_BASE
+	mov_imm	x1, UART_CLOCK
+	mov_imm	x2, UART_BAUDRATE
+	b	console_init
+	ret
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(void)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm x1, UART0_BASE
+	b	console_core_putc
+	ret
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush(int c)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, UART0_BASE
+	b	console_core_flush
+endfunc plat_crash_console_flush
+
+	/* --------------------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * Any memory init, relocation to be done before the
+	 * platform boots. Called very early in the boot process.
+	 * --------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
diff --git a/plat/mediatek/mt6795/bl31.ld.S b/plat/mediatek/mt6795/bl31.ld.S
new file mode 100644
index 0000000..cf68b71
--- /dev/null
+++ b/plat/mediatek/mt6795/bl31.ld.S
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl31_entrypoint)
+
+
+MEMORY {
+	RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_TZRAM_SIZE
+	RAM2 (rwx): ORIGIN = TZRAM2_BASE, LENGTH = TZRAM2_SIZE
+}
+
+
+SECTIONS
+{
+    . = BL31_BASE;
+
+    ASSERT(. == ALIGN(2048),
+           "vector base is not aligned on a 2K boundary.")
+
+    __RO_START__ = .;
+    vector . : {
+        *(.vectors)
+    } >RAM
+
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "BL31_BASE address is not aligned on a page boundary.")
+
+    ro . : {
+        *bl31_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as read-only,
+         * executable.  No RW data from the next section must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __RO_END__ = .;
+    } >RAM
+
+    ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
+           "cpu_ops not defined for this platform.")
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    /*
+     * .data must be placed at a lower address than the stacks if the stack
+     * protector is enabled. Alternatively, the .data.stack_protector_canary
+     * section can be placed independently of the main .data section.
+     */
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+#ifdef BL31_PROGBITS_LIMIT
+    ASSERT(. <= BL31_PROGBITS_LIMIT, "BL3-1 progbits has exceeded its limit.")
+#endif
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
+     */
+    .bss (NOLOAD) : ALIGN(16) {
+        __BSS_START__ = .;
+        *(.bss*)
+        *(COMMON)
+#if !USE_COHERENT_MEM
+        /*
+         * Bakery locks are stored in normal .bss memory
+         *
+         * Each lock's data is spread across multiple cache lines, one per CPU,
+         * but multiple locks can share the same cache line.
+         * The compiler will allocate enough memory for one CPU's bakery locks,
+         * the remaining cache lines are allocated by the linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __BAKERY_LOCK_START__ = .;
+        __PERCPU_BAKERY_LOCK_START__ = .;
+        *(bakery_lock)
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PERCPU_BAKERY_LOCK_END__ = .;
+        __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(__PERCPU_BAKERY_LOCK_END__ - __PERCPU_BAKERY_LOCK_START__);
+        . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __BAKERY_LOCK_END__ = .;
+#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
+    ASSERT(__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE,
+        "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements");
+#endif
+#endif
+        __BSS_END__ = .;
+        __RW_END__ = .;
+    } >RAM
+
+    ASSERT(. <= BL31_LIMIT, "BL3-1 image has exceeded its limit.")
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section. The tables are initialized to zero by the translation
+     * tables library.
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM2
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
+        __COHERENT_RAM_START__ = .;
+        /*
+         * Bakery locks are stored in coherent memory
+         *
+         * Each lock's data is contiguous and fully allocated by the compiler
+         */
+        *(bakery_lock)
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = ALIGN(PAGE_SIZE);
+        __COHERENT_RAM_END__ = .;
+    } >RAM2
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __BL31_END__ = .;
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+#if USE_COHERENT_MEM
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+    ASSERT(. <= TZRAM2_LIMIT, "TZRAM2 image has exceeded its limit.")
+}
diff --git a/plat/mediatek/mt6795/bl31_plat_setup.c b/plat/mediatek/mt6795/bl31_plat_setup.c
new file mode 100644
index 0000000..2051fe7
--- /dev/null
+++ b/plat/mediatek/mt6795/bl31_plat_setup.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+
+#include <mcucfg.h>
+#include <mt_cpuxgpt.h>
+#include <mtk_plat_common.h>
+#include <mtk_sip_svc.h>
+#include <plat_private.h>
+
+/*******************************************************************************
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted SRAM
+ ******************************************************************************/
+/*
+ * The next 2 constants identify the extents of the code & RO data region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
+ */
+IMPORT_SYM(unsigned long, __RO_START__,	BL31_RO_BASE);
+IMPORT_SYM(unsigned long, __RO_END__,	BL31_RO_LIMIT);
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL3-1 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static const int cci_map[] = {
+	PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+static uint32_t cci_map_length = ARRAY_SIZE(cci_map);
+
+/* Table of regions to map using the MMU.  */
+static const mmap_region_t plat_mmap[] = {
+	/* for TF text, RO, RW */
+	MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(RAM_CONSOLE_BASE & ~(PAGE_SIZE_MASK), RAM_CONSOLE_SIZE,
+						MT_DEVICE | MT_RW | MT_NS),
+	{ 0 }
+
+};
+
+/*******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+#define DEFINE_CONFIGURE_MMU_EL(_el)					\
+	void plat_configure_mmu_el ## _el(unsigned long total_base,	\
+				unsigned long total_size,	\
+				unsigned long ro_start,	\
+				unsigned long ro_limit,	\
+				unsigned long coh_start,	\
+				unsigned long coh_limit)	\
+	{								\
+		mmap_add_region(total_base, total_base,			\
+				total_size,				\
+				MT_MEMORY | MT_RW | MT_SECURE);		\
+		mmap_add_region(ro_start, ro_start,			\
+				ro_limit - ro_start,			\
+				MT_MEMORY | MT_RO | MT_SECURE);		\
+		mmap_add_region(coh_start, coh_start,			\
+				coh_limit - coh_start,			\
+				MT_DEVICE | MT_RW | MT_SECURE);		\
+		mmap_add(plat_mmap);					\
+		init_xlat_tables();					\
+									\
+		enable_mmu_el ## _el(0);				\
+	}
+
+/* Define EL3 variants of the function initialising the MMU */
+DEFINE_CONFIGURE_MMU_EL(3)
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void plat_cci_init(void)
+{
+	/* Initialize CCI driver */
+	cci_init(PLAT_MT_CCI_BASE, cci_map, cci_map_length);
+}
+
+void plat_cci_enable(void)
+{
+	/*
+	 * Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+void plat_cci_disable(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+
+static void platform_setup_cpu(void)
+{
+	/* setup big cores */
+	mmio_write_32((uintptr_t)&mt6795_mcucfg->mp1_config_res,
+		MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK);
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg, MP1_AINACTS);
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_clkenm_div,
+		MP1_SW_CG_GEN);
+	mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp1_rst_ctl,
+		MP1_L2RSTDISABLE);
+
+	/* set big cores arm64 boot mode */
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_cpucfg,
+		MP1_CPUCFG_64BIT);
+
+	/* set LITTLE cores arm64 boot mode */
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp0_rv_addr[0].rv_addr_hw,
+		MP0_CPUCFG_64BIT);
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ?
+			&bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	struct mtk_bl_param_t *pmtk_bl_param = (struct mtk_bl_param_t *)arg0;
+	struct atf_arg_t *teearg;
+	unsigned long long normal_base;
+	unsigned long long atf_base;
+
+	assert(pmtk_bl_param != NULL);
+	/*
+	 * Mediatek preloader(i.e, BL2) is in 32 bit state, high 32bits
+	 * of 64 bit GP registers are UNKNOWN if CPU warm reset from 32 bit
+	 * to 64 bit state. So we need to clear high 32bit,
+	 * which may be random value.
+	 */
+	pmtk_bl_param =
+	(struct mtk_bl_param_t *)((uint64_t)pmtk_bl_param & 0x00000000ffffffff);
+
+	teearg  = (struct atf_arg_t *)pmtk_bl_param->tee_info_addr;
+
+	console_init(teearg->atf_log_port, UART_CLOCK, UART_BAUDRATE);
+	memcpy((void *)&gteearg, (void *)teearg, sizeof(struct atf_arg_t));
+
+	normal_base = 0;
+    /* in ATF boot time, timer for cntpct_el0 is not initialized
+     * so it will not count now.
+     */
+	atf_base = read_cntpct_el0();
+	sched_clock_init(normal_base, atf_base);
+
+	VERBOSE("bl31_setup\n");
+
+	/* Populate entry point information for BL3-2 and BL3-3 */
+	SET_PARAM_HEAD(&bl32_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell BL3-1 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	/* BL33_START_ADDRESS */
+	bl33_image_ep_info.pc = pmtk_bl_param->bl33_start_addr;
+	bl33_image_ep_info.spsr = plat_get_spsr_for_bl33_entry();
+	bl33_image_ep_info.args.arg4 =  pmtk_bl_param->bootarg_loc;
+	bl33_image_ep_info.args.arg5 =  pmtk_bl_param->bootarg_size;
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+
+void bl31_platform_setup(void)
+{
+	platform_setup_cpu();
+
+	generic_delay_timer_init();
+
+	plat_mt_gic_driver_init();
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_mt_gic_init();
+
+	/* Topologies are best known to the platform. */
+	mt_setup_topology();
+}
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ * Init MTK propiartary log buffer control field.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	/* Enable non-secure access to CCI-400 registers */
+	mmio_write_32(CCI400_BASE + CCI_SEC_ACCESS_OFFSET, 0x1);
+
+	plat_cci_init();
+	plat_cci_enable();
+
+	if (gteearg.atf_log_buf_size != 0) {
+		INFO("mmap atf buffer : 0x%x, 0x%x\n\r",
+			gteearg.atf_log_buf_start,
+			gteearg.atf_log_buf_size);
+
+		mmap_add_region(
+			gteearg.atf_log_buf_start &
+			~(PAGE_SIZE_2MB_MASK),
+			gteearg.atf_log_buf_start &
+			~(PAGE_SIZE_2MB_MASK),
+			PAGE_SIZE_2MB,
+			MT_DEVICE | MT_RW | MT_NS);
+
+		INFO("mmap atf buffer (force 2MB aligned):0x%x, 0x%x\n",
+			(gteearg.atf_log_buf_start & ~(PAGE_SIZE_2MB_MASK)),
+		PAGE_SIZE_2MB);
+	}
+	/*
+	 * add TZRAM_BASE to memory map
+	 * then set RO and COHERENT to different attribute
+	 */
+	plat_configure_mmu_el3(
+		(TZRAM_BASE & ~(PAGE_SIZE_MASK)),
+		(TZRAM_SIZE & ~(PAGE_SIZE_MASK)),
+		(BL31_RO_BASE & ~(PAGE_SIZE_MASK)),
+		BL31_RO_LIMIT,
+		BL_COHERENT_RAM_BASE,
+		BL_COHERENT_RAM_END);
+	/* Initialize for ATF log buffer */
+	if (gteearg.atf_log_buf_size != 0) {
+		gteearg.atf_aee_debug_buf_size = ATF_AEE_BUFFER_SIZE;
+		gteearg.atf_aee_debug_buf_start =
+			gteearg.atf_log_buf_start +
+			gteearg.atf_log_buf_size - ATF_AEE_BUFFER_SIZE;
+		INFO("ATF log service is registered (0x%x, aee:0x%x)\n",
+			gteearg.atf_log_buf_start,
+			gteearg.atf_aee_debug_buf_start);
+	} else{
+		gteearg.atf_aee_debug_buf_size = 0;
+		gteearg.atf_aee_debug_buf_start = 0;
+	}
+
+	/* Platform code before bl31_main */
+	/* compatible to the earlier chipset */
+
+	/* Show to ATF log buffer & UART */
+	INFO("BL3-1: %s\n", version_string);
+	INFO("BL3-1: %s\n", build_message);
+
+}
+#if 0
+/* MTK Define */
+#define ACTLR_CPUECTLR_BIT    (1 << 1)
+
+void enable_ns_access_to_cpuectlr(void)
+{
+	unsigned int next_actlr;
+
+
+	/* ACTLR_EL1 do not implement CUPECTLR  */
+	next_actlr = read_actlr_el2();
+	next_actlr |= ACTLR_CPUECTLR_BIT;
+	write_actlr_el2(next_actlr);
+
+	next_actlr = read_actlr_el3();
+	next_actlr |= ACTLR_CPUECTLR_BIT;
+	write_actlr_el3(next_actlr);
+}
+#endif
+/*******************************************************************************
+ * This function prepare boot argument for 64 bit kernel entry
+ ******************************************************************************/
+static entry_point_info_t *bl31_plat_get_next_kernel64_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+	unsigned int mode;
+
+	mode = 0;
+
+	/* Kernel image is always non-secured */
+	next_image_info = &bl33_image_ep_info;
+
+	/* Figure out what mode we enter the non-secure world in */
+	if (el_implemented(2) != EL_IMPL_NONE) {
+		INFO("Kernel_EL2\n");
+		mode = MODE_EL2;
+	} else{
+		INFO("Kernel_EL1\n");
+		mode = MODE_EL1;
+	}
+
+	INFO("Kernel is 64Bit\n");
+	next_image_info->spsr =
+		SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	next_image_info->pc = get_kernel_info_pc();
+	next_image_info->args.arg0 = get_kernel_info_r0();
+	next_image_info->args.arg1 = get_kernel_info_r1();
+
+	INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx\n",
+				 next_image_info->pc,
+				 next_image_info->args.arg0,
+				 next_image_info->args.arg1);
+
+
+	SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * This function prepare boot argument for 32 bit kernel entry
+ ******************************************************************************/
+static entry_point_info_t *bl31_plat_get_next_kernel32_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+	unsigned int mode;
+
+	mode = 0;
+
+	/* Kernel image is always non-secured */
+	next_image_info = &bl33_image_ep_info;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = MODE32_hyp;
+	/*
+	* TODO: Consider the possibility of specifying the SPSR in
+	* the FIP ToC and allowing the platform to have a say as
+	* well.
+	*/
+
+	INFO("Kernel is 32Bit\n");
+	next_image_info->spsr =
+		SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE,
+		(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT));
+	next_image_info->pc = get_kernel_info_pc();
+	next_image_info->args.arg0 = get_kernel_info_r0();
+	next_image_info->args.arg1 = get_kernel_info_r1();
+	next_image_info->args.arg2 = get_kernel_info_r2();
+
+	INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx, r2=0x%lx\n",
+				 next_image_info->pc,
+				 next_image_info->args.arg0,
+				 next_image_info->args.arg1,
+				 next_image_info->args.arg2);
+
+
+	SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * This function prepare boot argument for kernel entrypoint
+ ******************************************************************************/
+void bl31_prepare_kernel_entry(uint64_t k32_64)
+{
+	entry_point_info_t *next_image_info;
+	uint32_t image_type;
+
+	/* Determine which image to execute next */
+	/* image_type = bl31_get_next_image_type(); */
+	image_type = NON_SECURE;
+
+	/* Program EL3 registers to enable entry into the next EL */
+	if (k32_64 == 0)
+		next_image_info = bl31_plat_get_next_kernel32_ep_info();
+	else
+		next_image_info = bl31_plat_get_next_kernel64_ep_info();
+
+	assert(next_image_info);
+	assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
+
+	INFO("BL3-1: Preparing for EL3 exit to %s world, Kernel\n",
+		(image_type == SECURE) ? "secure" : "normal");
+	INFO("BL3-1: Next image address = 0x%llx\n",
+		(unsigned long long) next_image_info->pc);
+	INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info->spsr);
+	cm_init_my_context(next_image_info);
+	cm_prepare_el3_exit(image_type);
+}
diff --git a/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c
new file mode 100644
index 0000000..3696f8e
--- /dev/null
+++ b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <mt_cpuxgpt.h>
+
+#define CPUXGPT_BASE	0x10200000
+#define INDEX_BASE		(CPUXGPT_BASE+0x0674)
+#define CTL_BASE		(CPUXGPT_BASE+0x0670)
+
+uint64_t normal_time_base;
+uint64_t atf_time_base;
+
+void sched_clock_init(uint64_t normal_base, uint64_t atf_base)
+{
+	normal_time_base = normal_base;
+	atf_time_base = atf_base;
+}
+
+uint64_t sched_clock(void)
+{
+	uint64_t cval;
+
+	cval = (((read_cntpct_el0() - atf_time_base)*1000)/
+		SYS_COUNTER_FREQ_IN_MHZ) + normal_time_base;
+	return cval;
+}
+
+/*
+  * Return: 0 - Trying to disable the CPUXGPT control bit,
+  * and not allowed to disable it.
+  * Return: 1 - reg_addr is not realted to disable the control bit.
+  */
+unsigned char check_cpuxgpt_write_permission(unsigned int reg_addr,
+	unsigned int reg_value)
+{
+	unsigned int idx;
+	unsigned int ctl_val;
+
+	if (reg_addr == CTL_BASE) {
+		idx = mmio_read_32(INDEX_BASE);
+
+		/* idx 0: CPUXGPT system control */
+		if (idx == 0) {
+			ctl_val = mmio_read_32(CTL_BASE);
+			if (ctl_val & 1) {
+				/*
+				 * if enable bit already set,
+				 * then bit 0 is not allow to set as 0
+				 */
+				if (!(reg_value & 1))
+					return 0;
+			}
+		}
+	}
+	return 1;
+}
+
diff --git a/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h
new file mode 100644
index 0000000..84df081
--- /dev/null
+++ b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPUXGPT_H
+#define MT_CPUXGPT_H
+
+/* REG */
+#define INDEX_CTL_REG       0x000
+#define INDEX_STA_REG       0x004
+#define INDEX_CNT_L_INIT    0x008
+#define INDEX_CNT_H_INIT    0x00C
+
+/* CTL_REG SET */
+#define EN_CPUXGPT          0x01
+#define EN_AHLT_DEBUG       0x02
+#define CLK_DIV1            (0x1 << 8)
+#define CLK_DIV2            (0x2 << 8)
+#define CLK_DIV4            (0x4 << 8)
+#define CLK_DIV_MASK        (~(0x7<<8))
+
+void generic_timer_backup(void);
+void sched_clock_init(uint64_t normal_base, uint64_t atf_base);
+uint64_t sched_clock(void);
+
+#endif /* MT_CPUXGPT_H */
diff --git a/plat/mediatek/mt6795/include/mcucfg.h b/plat/mediatek/mt6795/include/mcucfg.h
new file mode 100644
index 0000000..21c5394
--- /dev/null
+++ b/plat/mediatek/mt6795/include/mcucfg.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+struct mt6795_mcucfg_regs {
+	uint32_t mp0_ca7l_cache_config;
+	struct {
+		uint32_t mem_delsel0;
+		uint32_t mem_delsel1;
+	} mp0_cpu[4];
+	uint32_t mp0_cache_mem_delsel0;
+	uint32_t mp0_cache_mem_delsel1;
+	uint32_t mp0_axi_config;
+	uint32_t mp0_misc_config[2];
+	struct {
+		uint32_t rv_addr_lw;
+		uint32_t rv_addr_hw;
+	} mp0_rv_addr[4];
+	uint32_t mp0_ca7l_cfg_dis;
+	uint32_t mp0_ca7l_clken_ctrl;
+	uint32_t mp0_ca7l_rst_ctrl;
+	uint32_t mp0_ca7l_misc_config;
+	uint32_t mp0_ca7l_dbg_pwr_ctrl;
+	uint32_t mp0_rw_rsvd0;
+	uint32_t mp0_rw_rsvd1;
+	uint32_t mp0_ro_rsvd;
+	uint32_t reserved0_0[100];
+	uint32_t mp1_cpucfg;
+	uint32_t mp1_miscdbg;
+	uint32_t reserved0_1[13];
+	uint32_t mp1_rst_ctl;
+	uint32_t mp1_clkenm_div;
+	uint32_t reserved0_2[7];
+	uint32_t mp1_config_res;
+	uint32_t reserved0_3[13];
+	struct {
+		uint32_t rv_addr_lw;
+		uint32_t rv_addr_hw;
+	} mp1_rv_addr[2];
+	uint32_t reserved0_4[84];
+	uint32_t mp0_rst_status;		/* 0x400 */
+	uint32_t mp0_dbg_ctrl;
+	uint32_t mp0_dbg_flag;
+	uint32_t mp0_ca7l_ir_mon;
+	struct {
+		uint32_t pc_lw;
+		uint32_t pc_hw;
+		uint32_t fp_arch32;
+		uint32_t sp_arch32;
+		uint32_t fp_arch64_lw;
+		uint32_t fp_arch64_hw;
+		uint32_t sp_arch64_lw;
+		uint32_t sp_arch64_hw;
+	} mp0_dbg_core[4];
+	uint32_t dfd_ctrl;
+	uint32_t dfd_cnt_l;
+	uint32_t dfd_cnt_h;
+	uint32_t misccfg_mp0_rw_rsvd;
+	uint32_t misccfg_sec_vio_status0;
+	uint32_t misccfg_sec_vio_status1;
+	uint32_t reserved1[22];
+	uint32_t misccfg_rw_rsvd;		/* 0x500 */
+	uint32_t mcusys_dbg_mon_sel_a;
+	uint32_t mcusys_dbg_mon;
+	uint32_t reserved2[61];
+	uint32_t mcusys_config_a;		/* 0x600 */
+	uint32_t mcusys_config1_a;
+	uint32_t mcusys_gic_peribase_a;
+	uint32_t reserved3;
+	uint32_t sec_range0_start;		/* 0x610 */
+	uint32_t sec_range0_end;
+	uint32_t sec_range_enable;
+	uint32_t reserved4;
+	uint32_t int_pol_ctl[8];		/* 0x620 */
+	uint32_t aclken_div;			/* 0x640 */
+	uint32_t pclken_div;
+	uint32_t l2c_sram_ctrl;
+	uint32_t armpll_jit_ctrl;
+	uint32_t cci_addrmap;			/* 0x650 */
+	uint32_t cci_config;
+	uint32_t cci_periphbase;
+	uint32_t cci_nevntcntovfl;
+	uint32_t cci_clk_ctrl;			/* 0x660 */
+	uint32_t cci_acel_s1_ctrl;
+	uint32_t bus_fabric_dcm_ctrl;
+	uint32_t reserved5;
+	uint32_t xgpt_ctl;			/* 0x670 */
+	uint32_t xgpt_idx;
+	uint32_t ptpod2_ctl0;
+	uint32_t ptpod2_ctl1;
+	uint32_t mcusys_revid;
+	uint32_t mcusys_rw_rsvd0;
+	uint32_t mcusys_rw_rsvd1;
+};
+
+static struct mt6795_mcucfg_regs *const mt6795_mcucfg = (void *)MCUCFG_BASE;
+
+/* cpu boot mode */
+#define	MP0_CPUCFG_64BIT_SHIFT	12
+#define	MP1_CPUCFG_64BIT_SHIFT	28
+#define	MP0_CPUCFG_64BIT	(U(0xf) << MP0_CPUCFG_64BIT_SHIFT)
+#define	MP1_CPUCFG_64BIT	(U(0xf) << MP1_CPUCFG_64BIT_SHIFT)
+
+/* scu related */
+enum {
+	MP0_ACINACTM_SHIFT = 4,
+	MP1_ACINACTM_SHIFT = 0,
+	MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT,
+	MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT
+};
+
+enum {
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16,
+
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+	MP1_AINACTS_SHIFT = 4,
+	MP1_AINACTS = 1 << MP1_AINACTS_SHIFT
+};
+
+enum {
+	MP1_SW_CG_GEN_SHIFT = 12,
+	MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+	MP1_L2RSTDISABLE_SHIFT = 14,
+	MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT
+};
+
+#endif  /* MCUCFG_H */
diff --git a/plat/mediatek/mt6795/include/plat_macros.S b/plat/mediatek/mt6795/include/plat_macros.S
new file mode 100644
index 0000000..d198fdc
--- /dev/null
+++ b/plat/mediatek/mt6795/include/plat_macros.S
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL3-1.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm x16, BASE_GICD_BASE
+	mov_imm x17, BASE_GICC_BASE
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ------------------------------------------------
+	 * The below macro prints out relevant interconnect
+	 * registers whenever an unhandled exception is
+	 * taken in BL3-1.
+	 * Clobbers: x0 - x9, sp
+	 * ------------------------------------------------
+	 */
+	.macro plat_print_interconnect_regs
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
diff --git a/plat/mediatek/mt6795/include/plat_private.h b/plat/mediatek/mt6795/include/plat_private.h
new file mode 100644
index 0000000..f7450ca
--- /dev/null
+++ b/plat/mediatek/mt6795/include/plat_private.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <stdint.h>
+
+#include <lib/xlat_tables/xlat_tables.h>
+
+void plat_configure_mmu_el3(unsigned long total_base,
+					unsigned long total_size,
+					unsigned long,
+					unsigned long,
+					unsigned long,
+					unsigned long);
+
+void plat_cci_init(void);
+void plat_cci_enable(void);
+void plat_cci_disable(void);
+
+/* Declarations for plat_mt_gic.c */
+void plat_mt_gic_init(void);
+
+/* Declarations for plat_topology.c */
+int mt_setup_topology(void);
+void plat_delay_timer_init(void);
+
+void plat_mt_gic_driver_init(void);
+void plat_mt_gic_init(void);
+void plat_mt_gic_cpuif_enable(void);
+void plat_mt_gic_cpuif_disable(void);
+void plat_mt_gic_pcpu_init(void);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt6795/include/plat_sip_calls.h b/plat/mediatek/mt6795/include/plat_sip_calls.h
new file mode 100644
index 0000000..b9a1363
--- /dev/null
+++ b/plat/mediatek/mt6795/include/plat_sip_calls.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+/*******************************************************************************
+ * Plat SiP function constants
+ ******************************************************************************/
+#define MTK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt6795/include/platform_def.h b/plat/mediatek/mt6795/include/platform_def.h
new file mode 100644
index 0000000..301610d
--- /dev/null
+++ b/plat/mediatek/mt6795/include/platform_def.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+
+#define PLAT_PRIMARY_CPU  0x0
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define MT_BL31_PLAT_PARAM_VAL  0x0f1e2d3c4b5a6978ULL
+
+#define IO_PHYS             (0x10000000)
+#define INFRACFG_AO_BASE    (IO_PHYS + 0x1000)
+#define MCUCFG_BASE         (IO_PHYS + 0x200000)
+#define PERI_BASE           (IO_PHYS + 0x1000000)
+
+
+#define GPIO_BASE           (IO_PHYS + 0x370000)
+#define SPM_BASE            (IO_PHYS + 0x6000)
+#define RGU_BASE            (MCUCFG_BASE + 0x11000)
+#define PMIC_WRAP_BASE      (IO_PHYS + 0x10000)
+
+#define TRNG_base           (MCUCFG_BASE + 0x230000)
+#define MT_GIC_BASE         (0x10220000)
+#define MCU_SYS_SIZE        (0x700000)
+#define PLAT_MT_CCI_BASE    (IO_PHYS + 0x390000)
+
+/* Aggregate of all devices in the first GB */
+#define MTK_DEV_RNG0_BASE   IO_PHYS
+#define MTK_DEV_RNG0_SIZE   0x400000
+#define MTK_DEV_RNG1_BASE   (PERI_BASE)
+#define MTK_DEV_RNG1_SIZE   0x4000000
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE (PERI_BASE + 0x2000)
+
+#define UART_BAUDRATE   (921600)
+#define UART_CLOCK (26000000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	13000000
+#define SYS_COUNTER_FREQ_IN_MHZ		(SYS_COUNTER_FREQ_IN_TICKS/1000000)
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE      (MT_GIC_BASE+0x1000)
+#define BASE_GICC_BASE      (MT_GIC_BASE + 0x2000)
+#define BASE_GICR_BASE      (MT_GIC_BASE + 0x200000)
+#define BASE_GICH_BASE      (MT_GIC_BASE + 0x4000)
+#define BASE_GICV_BASE      (MT_GIC_BASE + 0x6000)
+
+#define INT_POL_CTL0        0x10200620
+#define GIC_PRIVATE_SIGNALS (32)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX  4
+#define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX  3
+
+/*******************************************************************************
+ * WDT Registers
+ ******************************************************************************/
+#define MTK_WDT_BASE                        (RGU_BASE)
+#define MTK_WDT_SIZE                        (0x1000)
+#define MTK_WDT_MODE                        (MTK_WDT_BASE+0x0000)
+#define MTK_WDT_LENGTH                      (MTK_WDT_BASE+0x0004)
+#define MTK_WDT_RESTART                     (MTK_WDT_BASE+0x0008)
+#define MTK_WDT_STATUS                      (MTK_WDT_BASE+0x000C)
+#define MTK_WDT_INTERVAL                    (MTK_WDT_BASE+0x0010)
+#define MTK_WDT_SWRST                       (MTK_WDT_BASE+0x0014)
+#define MTK_WDT_SWSYSRST                    (MTK_WDT_BASE+0x0018)
+#define MTK_WDT_NONRST_REG                  (MTK_WDT_BASE+0x0020)
+#define MTK_WDT_NONRST_REG2                 (MTK_WDT_BASE+0x0024)
+#define MTK_WDT_REQ_MODE                    (MTK_WDT_BASE+0x0030)
+#define MTK_WDT_REQ_IRQ_EN                  (MTK_WDT_BASE+0x0034)
+#define MTK_WDT_DEBUG_CTL                   (MTK_WDT_BASE+0x0040)
+
+/*WDT_STATUS*/
+#define MTK_WDT_STATUS_HWWDT_RST            (0x80000000)
+#define MTK_WDT_STATUS_SWWDT_RST            (0x40000000)
+#define MTK_WDT_STATUS_IRQWDT_RST           (0x20000000)
+#define MTK_WDT_STATUS_DEBUGWDT_RST         (0x00080000)
+#define MTK_WDT_STATUS_SPMWDT_RST           (0x0002)
+#define MTK_WDT_STATUS_SPM_THERMAL_RST      (0x0001)
+#define MTK_WDT_STATUS_THERMAL_DIRECT_RST   (1<<18)
+#define MTK_WDT_STATUS_SECURITY_RST         (1<<28)
+
+#define MTK_WDT_MODE_DUAL_MODE              0x0040
+#define MTK_WDT_MODE_IRQ                    0x0008
+#define MTK_WDT_MODE_KEY                    0x22000000
+#define MTK_WDT_MODE_EXTEN                  0x0004
+#define MTK_WDT_SWRST_KEY                   0x1209
+#define MTK_WDT_RESTART_KEY                 (0x1971)
+
+/* FIQ platform related define */
+#define MT_IRQ_SEC_SGI_0  8
+#define MT_IRQ_SEC_SGI_1  9
+#define MT_IRQ_SEC_SGI_2  10
+#define MT_IRQ_SEC_SGI_3  11
+#define MT_IRQ_SEC_SGI_4  12
+#define MT_IRQ_SEC_SGI_5  13
+#define MT_IRQ_SEC_SGI_6  14
+#define MT_IRQ_SEC_SGI_7  15
+
+#define FIQ_SMP_CALL_SGI  MT_IRQ_SEC_SGI_5
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT    "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH      aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x800
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR    "Booting Trusted Firmware\n"
+#define PLAT_MAX_PWR_LVL        U(2) /* MPIDR_AFFLVL2 */
+
+#define PLAT_MAX_RET_STATE	U(1)
+#define PLAT_MAX_OFF_STATE	U(2)
+
+#define PLATFORM_CACHE_LINE_SIZE      64
+#define PLATFORM_SYSTEM_COUNT         1
+#define PLATFORM_CLUSTER_COUNT        2
+#define PLATFORM_CLUSTER0_CORE_COUNT  4
+#define PLATFORM_CLUSTER1_CORE_COUNT  4
+#define PLATFORM_CORE_COUNT   (PLATFORM_CLUSTER1_CORE_COUNT + \
+					PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER 4
+#define PLATFORM_NUM_AFFS   (PLATFORM_SYSTEM_COUNT +  \
+					PLATFORM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* ATF Argument */
+#define ATF_ARG_SIZE      (0x800)
+
+/* TF txet, ro, rw, internal SRAM, Size: release: 80KB, debug: 92KB */
+#define TZRAM_BASE        (0x110000)
+#if DEBUG
+#define TZRAM_SIZE        (0x1C400)
+#else
+#define TZRAM_SIZE        (0x1C400)
+#endif
+#define TZRAM2_BASE	   0x00100000
+#define TZRAM2_SIZE	   0xDC00
+#define TZRAM2_LIMIT		(TZRAM2_BASE + TZRAM2_SIZE)
+
+#define RAM_CONSOLE_BASE  0x0012D000
+#define RAM_CONSOLE_SIZE  0x00001000
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL3-1 debug size plus a
+ * little space for growth.
+ */
+#define BL31_BASE           (TZRAM_BASE + 0x1000)
+#define BL31_LIMIT          (TZRAM_BASE + TZRAM_SIZE)
+#define BSS1_STACK_LIMIT    (TZRAM_BASE + TZRAM_SIZE)
+#define BL31_TZRAM_SIZE     (TZRAM_SIZE - ATF_ARG_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+#define MAX_XLAT_TABLES   7
+#define MAX_MMAP_REGIONS  16
+
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define CCI400_BASE                     0x10390000
+#define CCI400_SL_IFACE_CLUSTER0        4
+#define CCI400_SL_IFACE_CLUSTER1        3
+#define CCI400_SL_IFACE_INDEX(mpidr)  (mpidr & MPIDR_CLUSTER_MASK ? \
+					CCI400_SL_IFACE_CLUSTER1 :   \
+					CCI400_SL_IFACE_CLUSTER0)
+#define CCI_SEC_ACCESS_OFFSET           (0x8)
+
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT     6
+#define CACHE_WRITEBACK_GRANULE   (1 << CACHE_WRITEBACK_SHIFT)
+
+#define BL32_BASE                 (0x0)
+
+/*
+ * Load address of BL3-3 for this platform port
+ */
+#define LK_SIZE_LIMIT				(0x100000)
+#define PLAT_MTK_NS_IMAGE_OFFSET	(0x41E00000)
+/* 16KB */
+#define ATF_AEE_BUFFER_SIZE         (0x4000)
+#define PAGE_SIZE_2MB_MASK          (PAGE_SIZE_2MB - 1)
+#define IS_PAGE_2MB_ALIGNED(addr)   (((addr) & PAGE_SIZE_2MB_MASK) == 0)
+#define PAGE_SIZE_2MB               (1 << PAGE_SIZE_2MB_SHIFT)
+#define PAGE_SIZE_2MB_SHIFT         TWO_MB_SHIFT
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt6795/include/power_tracer.h b/plat/mediatek/mt6795/include/power_tracer.h
new file mode 100644
index 0000000..8c98dbd
--- /dev/null
+++ b/plat/mediatek/mt6795/include/power_tracer.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POWER_TRACER_H
+#define POWER_TRACER_H
+
+#define CPU_UP		0
+#define CPU_DOWN	1
+#define CPU_SUSPEND	2
+#define CLUSTER_UP	3
+#define CLUSTER_DOWN	4
+#define CLUSTER_SUSPEND	5
+
+void trace_power_flow(unsigned long mpidr, unsigned char mode);
+
+#endif /* POWER_TRACER_H */
diff --git a/plat/mediatek/mt6795/include/scu.h b/plat/mediatek/mt6795/include/scu.h
new file mode 100644
index 0000000..625418a
--- /dev/null
+++ b/plat/mediatek/mt6795/include/scu.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCU_H
+#define SCU_H
+
+void disable_scu(unsigned long mpidr);
+void enable_scu(unsigned long mpidr);
+
+#endif /* SCU_H */
diff --git a/plat/mediatek/mt6795/include/spm.h b/plat/mediatek/mt6795/include/spm.h
new file mode 100644
index 0000000..5227e1d
--- /dev/null
+++ b/plat/mediatek/mt6795/include/spm.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_H
+#define SPM_H
+
+#define SPM_POWERON_CONFIG_SET			(SPM_BASE + 0x000)
+#define SPM_POWER_ON_VAL0			(SPM_BASE + 0x010)
+#define SPM_POWER_ON_VAL1			(SPM_BASE + 0x014)
+#define SPM_CLK_SETTLE				(SPM_BASE + 0x100)
+#define SPM_CA7_CPU1_PWR_CON			(SPM_BASE + 0x218)
+#define SPM_CA7_CPU2_PWR_CON			(SPM_BASE + 0x21c)
+#define SPM_CA7_CPU3_PWR_CON			(SPM_BASE + 0x220)
+#define SPM_CA7_CPU1_L1_PDN			(SPM_BASE + 0x264)
+#define SPM_CA7_CPU2_L1_PDN			(SPM_BASE + 0x26c)
+#define SPM_CA7_CPU3_L1_PDN			(SPM_BASE + 0x274)
+#define SPM_MD32_SRAM_CON			(SPM_BASE + 0x2c8)
+#define SPM_PCM_CON0				(SPM_BASE + 0x310)
+#define SPM_PCM_CON1				(SPM_BASE + 0x314)
+#define SPM_PCM_IM_PTR				(SPM_BASE + 0x318)
+#define SPM_PCM_IM_LEN				(SPM_BASE + 0x31c)
+#define SPM_PCM_REG_DATA_INI			(SPM_BASE + 0x320)
+#define SPM_PCM_EVENT_VECTOR0			(SPM_BASE + 0x340)
+#define SPM_PCM_EVENT_VECTOR1			(SPM_BASE + 0x344)
+#define SPM_PCM_EVENT_VECTOR2			(SPM_BASE + 0x348)
+#define SPM_PCM_EVENT_VECTOR3			(SPM_BASE + 0x34c)
+#define SPM_PCM_MAS_PAUSE_MASK			(SPM_BASE + 0x354)
+#define SPM_PCM_PWR_IO_EN			(SPM_BASE + 0x358)
+#define SPM_PCM_TIMER_VAL			(SPM_BASE + 0x35c)
+#define SPM_PCM_TIMER_OUT			(SPM_BASE + 0x360)
+#define SPM_PCM_REG0_DATA			(SPM_BASE + 0x380)
+#define SPM_PCM_REG1_DATA			(SPM_BASE + 0x384)
+#define SPM_PCM_REG2_DATA			(SPM_BASE + 0x388)
+#define SPM_PCM_REG3_DATA			(SPM_BASE + 0x38c)
+#define SPM_PCM_REG4_DATA			(SPM_BASE + 0x390)
+#define SPM_PCM_REG5_DATA			(SPM_BASE + 0x394)
+#define SPM_PCM_REG6_DATA			(SPM_BASE + 0x398)
+#define SPM_PCM_REG7_DATA			(SPM_BASE + 0x39c)
+#define SPM_PCM_REG8_DATA			(SPM_BASE + 0x3a0)
+#define SPM_PCM_REG9_DATA			(SPM_BASE + 0x3a4)
+#define SPM_PCM_REG10_DATA			(SPM_BASE + 0x3a8)
+#define SPM_PCM_REG11_DATA			(SPM_BASE + 0x3ac)
+#define SPM_PCM_REG12_DATA			(SPM_BASE + 0x3b0)
+#define SPM_PCM_REG13_DATA			(SPM_BASE + 0x3b4)
+#define SPM_PCM_REG14_DATA			(SPM_BASE + 0x3b8)
+#define SPM_PCM_REG15_DATA			(SPM_BASE + 0x3bc)
+#define SPM_PCM_EVENT_REG_STA			(SPM_BASE + 0x3c0)
+#define SPM_PCM_FSM_STA				(SPM_BASE + 0x3c4)
+#define SPM_PCM_IM_HOST_RW_PTR			(SPM_BASE + 0x3c8)
+#define SPM_PCM_IM_HOST_RW_DAT			(SPM_BASE + 0x3cc)
+#define SPM_PCM_EVENT_VECTOR4			(SPM_BASE + 0x3d0)
+#define SPM_PCM_EVENT_VECTOR5			(SPM_BASE + 0x3d4)
+#define SPM_PCM_EVENT_VECTOR6			(SPM_BASE + 0x3d8)
+#define SPM_PCM_EVENT_VECTOR7			(SPM_BASE + 0x3dc)
+#define SPM_PCM_SW_INT_SET			(SPM_BASE + 0x3e0)
+#define SPM_PCM_SW_INT_CLEAR			(SPM_BASE + 0x3e4)
+#define SPM_CLK_CON				(SPM_BASE + 0x400)
+#define SPM_SLEEP_PTPOD2_CON			(SPM_BASE + 0x408)
+#define SPM_APMCU_PWRCTL			(SPM_BASE + 0x600)
+#define SPM_AP_DVFS_CON_SET			(SPM_BASE + 0x604)
+#define SPM_AP_STANBY_CON			(SPM_BASE + 0x608)
+#define SPM_PWR_STATUS				(SPM_BASE + 0x60c)
+#define SPM_PWR_STATUS_2ND			(SPM_BASE + 0x610)
+#define SPM_AP_BSI_REQ				(SPM_BASE + 0x614)
+#define SPM_SLEEP_TIMER_STA			(SPM_BASE + 0x720)
+#define SPM_SLEEP_WAKEUP_EVENT_MASK		(SPM_BASE + 0x810)
+#define SPM_SLEEP_CPU_WAKEUP_EVENT		(SPM_BASE + 0x814)
+#define SPM_SLEEP_MD32_WAKEUP_EVENT_MASK	(SPM_BASE + 0x818)
+#define SPM_PCM_WDT_TIMER_VAL			(SPM_BASE + 0x824)
+#define SPM_PCM_WDT_TIMER_OUT			(SPM_BASE + 0x828)
+#define SPM_PCM_MD32_MAILBOX			(SPM_BASE + 0x830)
+#define SPM_PCM_MD32_IRQ			(SPM_BASE + 0x834)
+#define SPM_SLEEP_ISR_MASK			(SPM_BASE + 0x900)
+#define SPM_SLEEP_ISR_STATUS			(SPM_BASE + 0x904)
+#define SPM_SLEEP_ISR_RAW_STA			(SPM_BASE + 0x910)
+#define SPM_SLEEP_MD32_ISR_RAW_STA		(SPM_BASE + 0x914)
+#define SPM_SLEEP_WAKEUP_MISC			(SPM_BASE + 0x918)
+#define SPM_SLEEP_BUS_PROTECT_RDY		(SPM_BASE + 0x91c)
+#define SPM_SLEEP_SUBSYS_IDLE_STA		(SPM_BASE + 0x920)
+#define SPM_PCM_RESERVE				(SPM_BASE + 0xb00)
+#define SPM_PCM_RESERVE2			(SPM_BASE + 0xb04)
+#define SPM_PCM_FLAGS				(SPM_BASE + 0xb08)
+#define SPM_PCM_SRC_REQ				(SPM_BASE + 0xb0c)
+#define SPM_PCM_DEBUG_CON			(SPM_BASE + 0xb20)
+#define SPM_CA7_CPU0_IRQ_MASK			(SPM_BASE + 0xb30)
+#define SPM_CA7_CPU1_IRQ_MASK			(SPM_BASE + 0xb34)
+#define SPM_CA7_CPU2_IRQ_MASK			(SPM_BASE + 0xb38)
+#define SPM_CA7_CPU3_IRQ_MASK			(SPM_BASE + 0xb3c)
+#define SPM_CA15_CPU0_IRQ_MASK			(SPM_BASE + 0xb40)
+#define SPM_CA15_CPU1_IRQ_MASK			(SPM_BASE + 0xb44)
+#define SPM_CA15_CPU2_IRQ_MASK			(SPM_BASE + 0xb48)
+#define SPM_CA15_CPU3_IRQ_MASK			(SPM_BASE + 0xb4c)
+#define SPM_PCM_PASR_DPD_0			(SPM_BASE + 0xb60)
+#define SPM_PCM_PASR_DPD_1			(SPM_BASE + 0xb64)
+#define SPM_PCM_PASR_DPD_2			(SPM_BASE + 0xb68)
+#define SPM_PCM_PASR_DPD_3			(SPM_BASE + 0xb6c)
+#define SPM_SLEEP_CA7_WFI0_EN			(SPM_BASE + 0xf00)
+#define SPM_SLEEP_CA7_WFI1_EN			(SPM_BASE + 0xf04)
+#define SPM_SLEEP_CA7_WFI2_EN			(SPM_BASE + 0xf08)
+#define SPM_SLEEP_CA7_WFI3_EN			(SPM_BASE + 0xf0c)
+#define SPM_SLEEP_CA15_WFI0_EN			(SPM_BASE + 0xf10)
+#define SPM_SLEEP_CA15_WFI1_EN			(SPM_BASE + 0xf14)
+#define SPM_SLEEP_CA15_WFI2_EN			(SPM_BASE + 0xf18)
+#define SPM_SLEEP_CA15_WFI3_EN			(SPM_BASE + 0xf1c)
+
+#define SPM_PROJECT_CODE	0xb16
+
+#define SPM_REGWR_EN		(1U << 0)
+#define SPM_REGWR_CFG_KEY	(SPM_PROJECT_CODE << 16)
+
+#define SPM_CPU_PDN_DIS		(1U << 0)
+#define SPM_INFRA_PDN_DIS	(1U << 1)
+#define SPM_DDRPHY_PDN_DIS	(1U << 2)
+#define SPM_DUALVCORE_PDN_DIS	(1U << 3)
+#define SPM_PASR_DIS		(1U << 4)
+#define SPM_DPD_DIS		(1U << 5)
+#define SPM_SODI_DIS		(1U << 6)
+#define SPM_MEMPLL_RESET	(1U << 7)
+#define SPM_MAINPLL_PDN_DIS	(1U << 8)
+#define SPM_CPU_DVS_DIS		(1U << 9)
+#define SPM_CPU_DORMANT		(1U << 10)
+#define SPM_EXT_VSEL_GPIO103	(1U << 11)
+#define SPM_DDR_HIGH_SPEED	(1U << 12)
+#define SPM_OPT			(1U << 13)
+
+#define POWER_ON_VAL1_DEF	0x01011820
+#define PCM_FSM_STA_DEF		0x48490
+#define PCM_END_FSM_STA_DEF	0x08490
+#define PCM_END_FSM_STA_MASK	0x3fff0
+#define PCM_HANDSHAKE_SEND1	0xbeefbeef
+
+#define PCM_WDT_TIMEOUT		(30 * 32768)
+#define PCM_TIMER_MAX		(0xffffffff - PCM_WDT_TIMEOUT)
+
+#define CON0_PCM_KICK		(1U << 0)
+#define CON0_IM_KICK		(1U << 1)
+#define CON0_IM_SLEEP_DVS	(1U << 3)
+#define CON0_PCM_SW_RESET	(1U << 15)
+#define CON0_CFG_KEY		(SPM_PROJECT_CODE << 16)
+
+#define CON1_IM_SLAVE		(1U << 0)
+#define CON1_MIF_APBEN		(1U << 3)
+#define CON1_PCM_TIMER_EN	(1U << 5)
+#define CON1_IM_NONRP_EN	(1U << 6)
+#define CON1_PCM_WDT_EN		(1U << 8)
+#define CON1_PCM_WDT_WAKE_MODE	(1U << 9)
+#define CON1_SPM_SRAM_SLP_B	(1U << 10)
+#define CON1_SPM_SRAM_ISO_B	(1U << 11)
+#define CON1_EVENT_LOCK_EN	(1U << 12)
+#define CON1_CFG_KEY		(SPM_PROJECT_CODE << 16)
+
+#define PCM_PWRIO_EN_R0		(1U << 0)
+#define PCM_PWRIO_EN_R7		(1U << 7)
+#define PCM_RF_SYNC_R0		(1U << 16)
+#define PCM_RF_SYNC_R2		(1U << 18)
+#define PCM_RF_SYNC_R6		(1U << 22)
+#define PCM_RF_SYNC_R7		(1U << 23)
+
+#define CC_SYSCLK0_EN_0		(1U << 0)
+#define CC_SYSCLK0_EN_1		(1U << 1)
+#define CC_SYSCLK1_EN_0		(1U << 2)
+#define CC_SYSCLK1_EN_1		(1U << 3)
+#define CC_SYSSETTLE_SEL	(1U << 4)
+#define CC_LOCK_INFRA_DCM	(1U << 5)
+#define CC_SRCLKENA_MASK_0	(1U << 6)
+#define CC_CXO32K_RM_EN_MD1	(1U << 9)
+#define CC_CXO32K_RM_EN_MD2	(1U << 10)
+#define CC_CLKSQ1_SEL		(1U << 12)
+#define CC_DISABLE_DORM_PWR	(1U << 14)
+#define CC_MD32_DCM_EN		(1U << 18)
+
+#define WFI_OP_AND		1
+#define WFI_OP_OR		0
+
+#define WAKE_MISC_PCM_TIMER	(1U << 19)
+#define WAKE_MISC_CPU_WAKE	(1U << 20)
+
+/* define WAKE_SRC_XXX */
+#define WAKE_SRC_SPM_MERGE	(1 << 0)
+#define WAKE_SRC_KP		(1 << 2)
+#define WAKE_SRC_WDT		(1 << 3)
+#define WAKE_SRC_GPT		(1 << 4)
+#define WAKE_SRC_EINT		(1 << 6)
+#define WAKE_SRC_LOW_BAT	(1 << 9)
+#define WAKE_SRC_MD32		(1 << 10)
+#define WAKE_SRC_USB_CD		(1 << 14)
+#define WAKE_SRC_USB_PDN	(1 << 15)
+#define WAKE_SRC_AFE		(1 << 20)
+#define WAKE_SRC_THERM		(1 << 21)
+#define WAKE_SRC_SYSPWREQ	(1 << 24)
+#define WAKE_SRC_SEJ		(1 << 27)
+#define WAKE_SRC_ALL_MD32	(1 << 28)
+#define WAKE_SRC_CPU_IRQ	(1 << 29)
+
+#endif /* SPM_H */
diff --git a/plat/mediatek/mt6795/plat_delay_timer.c b/plat/mediatek/mt6795/plat_delay_timer.c
new file mode 100644
index 0000000..965b653
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_delay_timer.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+
+static uint32_t plat_get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static const timer_ops_t plat_timer_ops = {
+	.get_timer_value	= plat_get_timer_value,
+	.clk_mult		= 1,
+	.clk_div		= SYS_COUNTER_FREQ_IN_MHZ,
+};
+
+void plat_delay_timer_init(void)
+{
+	timer_init(&plat_timer_ops);
+}
diff --git a/plat/mediatek/mt6795/plat_mt_gic.c b/plat/mediatek/mt6795/plat_mt_gic.c
new file mode 100644
index 0000000..20cb26d
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_mt_gic.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <plat/common/platform.h>
+
+static const interrupt_prop_t g0_interrupt_props[] = {
+	INTR_PROP_DESC(FIQ_SMP_CALL_SGI, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+gicv2_driver_data_t arm_gic_data = {
+	.gicd_base = BASE_GICD_BASE,
+	.gicc_base = BASE_GICC_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+void plat_mt_gic_driver_init(void)
+{
+	gicv2_driver_init(&arm_gic_data);
+}
+
+void plat_mt_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+void plat_mt_gic_cpuif_enable(void)
+{
+	gicv2_cpuif_enable();
+}
+
+void plat_mt_gic_cpuif_disable(void)
+{
+	gicv2_cpuif_disable();
+}
+
+void plat_mt_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+}
diff --git a/plat/mediatek/mt6795/plat_pm.c b/plat/mediatek/mt6795/plat_pm.c
new file mode 100644
index 0000000..0dfbd18
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_pm.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <mcucfg.h>
+#include <plat_private.h>
+#include <power_tracer.h>
+#include <scu.h>
+
+struct core_context {
+	unsigned long timer_data[8];
+	unsigned int count;
+	unsigned int rst;
+	unsigned int abt;
+	unsigned int brk;
+};
+
+struct cluster_context {
+	struct core_context core[PLATFORM_MAX_CPUS_PER_CLUSTER];
+};
+
+/*
+ * Top level structure to hold the complete context of a multi cluster system
+ */
+struct system_context {
+	struct cluster_context cluster[PLATFORM_CLUSTER_COUNT];
+};
+
+/*
+ * Top level structure which encapsulates the context of the entire system
+ */
+static struct system_context dormant_data[1];
+
+static inline struct cluster_context *system_cluster(
+						struct system_context *system,
+						uint32_t clusterid)
+{
+	return &system->cluster[clusterid];
+}
+
+static inline struct core_context *cluster_core(struct cluster_context *cluster,
+						uint32_t cpuid)
+{
+	return &cluster->core[cpuid];
+}
+
+static struct cluster_context *get_cluster_data(unsigned long mpidr)
+{
+	uint32_t clusterid;
+
+	clusterid = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	return system_cluster(dormant_data, clusterid);
+}
+
+static struct core_context *get_core_data(unsigned long mpidr)
+{
+	struct cluster_context *cluster;
+	uint32_t cpuid;
+
+	cluster = get_cluster_data(mpidr);
+	cpuid = mpidr & MPIDR_CPU_MASK;
+
+	return cluster_core(cluster, cpuid);
+}
+
+static void mt_save_generic_timer(unsigned long *container)
+{
+	uint64_t ctl;
+	uint64_t val;
+
+	__asm__ volatile("mrs	%x0, cntkctl_el1\n\t"
+			 "mrs	%x1, cntp_cval_el0\n\t"
+			 "stp	%x0, %x1, [%2, #0]"
+			 : "=&r" (ctl), "=&r" (val)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("mrs	%x0, cntp_tval_el0\n\t"
+			 "mrs	%x1, cntp_ctl_el0\n\t"
+			 "stp	%x0, %x1, [%2, #16]"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("mrs	%x0, cntv_tval_el0\n\t"
+			 "mrs	%x1, cntv_ctl_el0\n\t"
+			 "stp	%x0, %x1, [%2, #32]"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+}
+
+static void mt_restore_generic_timer(unsigned long *container)
+{
+	uint64_t ctl;
+	uint64_t val;
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #0]\n\t"
+			 "msr	cntkctl_el1, %x0\n\t"
+			 "msr	cntp_cval_el0, %x1"
+			 : "=&r" (ctl), "=&r" (val)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #16]\n\t"
+			 "msr	cntp_tval_el0, %x0\n\t"
+			 "msr	cntp_ctl_el0, %x1"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #32]\n\t"
+			 "msr	cntv_tval_el0, %x0\n\t"
+			 "msr	cntv_ctl_el0, %x1"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+}
+
+static void stop_generic_timer(void)
+{
+	/*
+	 * Disable the timer and mask the irq to prevent
+	 * suprious interrupts on this cpu interface. It
+	 * will bite us when we come back if we don't. It
+	 * will be replayed on the inbound cluster.
+	 */
+	uint64_t cntpctl = read_cntp_ctl_el0();
+
+	write_cntp_ctl_el0(clr_cntp_ctl_enable(cntpctl));
+}
+
+static void mt_cpu_save(unsigned long mpidr)
+{
+	struct core_context *core;
+
+	core = get_core_data(mpidr);
+	mt_save_generic_timer(core->timer_data);
+
+	/* disable timer irq, and upper layer should enable it again. */
+	stop_generic_timer();
+}
+
+static void mt_cpu_restore(unsigned long mpidr)
+{
+	struct core_context *core;
+
+	core = get_core_data(mpidr);
+	mt_restore_generic_timer(core->timer_data);
+}
+
+static void mt_platform_save_context(unsigned long mpidr)
+{
+	/* mcusys_save_context: */
+	mt_cpu_save(mpidr);
+}
+
+static void mt_platform_restore_context(unsigned long mpidr)
+{
+	/* mcusys_restore_context: */
+	mt_cpu_restore(mpidr);
+}
+
+/*******************************************************************************
+* Private function which is used to determine if any platform actions
+* should be performed for the specified affinity instance given its
+* state. Nothing needs to be done if the 'state' is not off or if this is not
+* the highest affinity level which will enter the 'state'.
+*******************************************************************************/
+static int32_t plat_do_plat_actions(unsigned int afflvl, unsigned int state)
+{
+	unsigned int max_phys_off_afflvl;
+
+	assert(afflvl <= MPIDR_AFFLVL2);
+
+	if (state != PSCI_STATE_OFF)
+		return -EAGAIN;
+
+	/*
+	 * Find the highest affinity level which will be suspended and postpone
+	 * all the platform specific actions until that level is hit.
+	 */
+	max_phys_off_afflvl = psci_get_max_phys_off_afflvl();
+	assert(max_phys_off_afflvl != PSCI_INVALID_DATA);
+	if (afflvl != max_phys_off_afflvl)
+		return -EAGAIN;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to enter
+ * standby.
+ ******************************************************************************/
+static void plat_affinst_standby(unsigned int power_state)
+{
+	unsigned int target_afflvl;
+
+	/* Sanity check the requested state */
+	target_afflvl = psci_get_pstate_afflvl(power_state);
+
+	/*
+	 * It's possible to enter standby only on affinity level 0 i.e. a cpu
+	 * on the MTK_platform. Ignore any other affinity level.
+	 */
+	if (target_afflvl == MPIDR_AFFLVL0) {
+		/*
+		 * Enter standby state. dsb is good practice before using wfi
+		 * to enter low power states.
+		 */
+		dsb();
+		wfi();
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * on. The level and mpidr determine the affinity instance.
+ ******************************************************************************/
+static int plat_affinst_on(unsigned long mpidr,
+		    unsigned long sec_entrypoint,
+		    unsigned int afflvl,
+		    unsigned int state)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned long cpu_id;
+	unsigned long cluster_id;
+	uintptr_t rv;
+
+	/*
+	 * It's possible to turn on only affinity level 0 i.e. a cpu
+	 * on the MTK_platform. Ignore any other affinity level.
+	 */
+	if (afflvl != MPIDR_AFFLVL0)
+		return rc;
+
+	cpu_id = mpidr & MPIDR_CPU_MASK;
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		rv = (uintptr_t)&mt6795_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw;
+	else
+		rv = (uintptr_t)&mt6795_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw;
+
+	mmio_write_32(rv, sec_entrypoint);
+	INFO("mt_on[%ld:%ld], entry %x\n",
+		cluster_id, cpu_id, mmio_read_32(rv));
+
+	return rc;
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * off. The level and mpidr determine the affinity instance. The 'state' arg.
+ * allows the platform to decide whether the cluster is being turned off and
+ * take apt actions.
+ *
+ * CAUTION: This function is called with coherent stacks so that caches can be
+ * turned off, flushed and coherency disabled. There is no guarantee that caches
+ * will remain turned on across calls to this function as each affinity level is
+ * dealt with. So do not write & read global variables across calls. It will be
+ * wise to do flush a write to the global to prevent unpredictable results.
+ ******************************************************************************/
+static void plat_affinst_off(unsigned int afflvl, unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_mt_gic_cpuif_disable();
+
+	trace_power_flow(mpidr, CPU_DOWN);
+
+	if (afflvl != MPIDR_AFFLVL0) {
+		/* Disable coherency if this cluster is to be turned off */
+		plat_cci_disable();
+
+		trace_power_flow(mpidr, CLUSTER_DOWN);
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be
+ * suspended. The level and mpidr determine the affinity instance. The 'state'
+ * arg. allows the platform to decide whether the cluster is being turned off
+ * and take apt actions.
+ *
+ * CAUTION: This function is called with coherent stacks so that caches can be
+ * turned off, flushed and coherency disabled. There is no guarantee that caches
+ * will remain turned on across calls to this function as each affinity level is
+ * dealt with. So do not write & read global variables across calls. It will be
+ * wise to do flush a write to the global to prevent unpredictable results.
+ ******************************************************************************/
+static void plat_affinst_suspend(unsigned long sec_entrypoint,
+			  unsigned int afflvl,
+			  unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned long cluster_id;
+	unsigned long cpu_id;
+	uintptr_t rv;
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	cpu_id = mpidr & MPIDR_CPU_MASK;
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		rv = (uintptr_t)&mt6795_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw;
+	else
+		rv = (uintptr_t)&mt6795_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw;
+
+	mmio_write_32(rv, sec_entrypoint);
+
+	if (afflvl >= MPIDR_AFFLVL0)
+		mt_platform_save_context(mpidr);
+
+	/* Perform the common cluster specific operations */
+	if (afflvl >= MPIDR_AFFLVL1) {
+		/* Disable coherency if this cluster is to be turned off */
+		plat_cci_disable();
+		disable_scu(mpidr);
+
+		trace_power_flow(mpidr, CLUSTER_SUSPEND);
+	}
+
+	if (afflvl >= MPIDR_AFFLVL2) {
+		/* Prevent interrupts from spuriously waking up this cpu */
+		plat_mt_gic_cpuif_disable();
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance has just been powered
+ * on after being turned off earlier. The level and mpidr determine the affinity
+ * instance. The 'state' arg. allows the platform to decide whether the cluster
+ * was turned off prior to wakeup and do what's necessary to setup it up
+ * correctly.
+ ******************************************************************************/
+static void plat_affinst_on_finish(unsigned int afflvl, unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	/* Perform the common cluster specific operations */
+	if (afflvl >= MPIDR_AFFLVL1) {
+		enable_scu(mpidr);
+
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+		trace_power_flow(mpidr, CLUSTER_UP);
+	}
+
+	/* Enable the gic cpu interface */
+	plat_mt_gic_cpuif_enable();
+	plat_mt_gic_pcpu_init();
+	trace_power_flow(mpidr, CPU_UP);
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance has just been powered
+ * on after having been suspended earlier. The level and mpidr determine the
+ * affinity instance.
+ ******************************************************************************/
+static void plat_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	if (afflvl >= MPIDR_AFFLVL2) {
+		/* Enable the gic cpu interface */
+		plat_mt_gic_init();
+		plat_mt_gic_cpuif_enable();
+	}
+
+	/* Perform the common cluster specific operations */
+	if (afflvl >= MPIDR_AFFLVL1) {
+		enable_scu(mpidr);
+
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+		trace_power_flow(mpidr, CLUSTER_UP);
+	}
+
+	if (afflvl >= MPIDR_AFFLVL0)
+		mt_platform_restore_context(mpidr);
+
+	plat_mt_gic_pcpu_init();
+}
+
+static unsigned int plat_get_sys_suspend_power_state(void)
+{
+	/* StateID: 0, StateType: 1(power down), PowerLevel: 2(system) */
+	return psci_make_powerstate(0, 1, 2);
+}
+
+/*******************************************************************************
+ * MTK handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 plat_system_off(void)
+{
+	INFO("MTK System Off\n");
+	wfi();
+	ERROR("MTK System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 plat_system_reset(void)
+{
+	/* Write the System Configuration Control Register */
+	INFO("MTK System Reset\n");
+
+	mmio_clrbits_32(MTK_WDT_BASE,
+		(MTK_WDT_MODE_DUAL_MODE | MTK_WDT_MODE_IRQ));
+	mmio_setbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN));
+	mmio_setbits_32(MTK_WDT_SWRST, MTK_WDT_SWRST_KEY);
+
+	wfi();
+	ERROR("MTK System Reset: operation not handled.\n");
+	panic();
+}
+
+/*******************************************************************************
+ * Export the platform handlers to enable psci to invoke them
+ ******************************************************************************/
+static const plat_pm_ops_t plat_plat_pm_ops = {
+	.affinst_standby		= plat_affinst_standby,
+	.affinst_on			= plat_affinst_on,
+	.affinst_off			= plat_affinst_off,
+	.affinst_suspend		= plat_affinst_suspend,
+	.affinst_on_finish		= plat_affinst_on_finish,
+	.affinst_suspend_finish		= plat_affinst_suspend_finish,
+	.system_off			= plat_system_off,
+	.system_reset			= plat_system_reset,
+	.get_sys_suspend_power_state	= plat_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops & initialize the mtk_platform power
+ * controller
+ ******************************************************************************/
+int platform_setup_pm(const plat_pm_ops_t **plat_ops)
+{
+	*plat_ops = &plat_plat_pm_ops;
+	return 0;
+}
diff --git a/plat/mediatek/mt6795/plat_topology.c b/plat/mediatek/mt6795/plat_topology.c
new file mode 100644
index 0000000..7425d26
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_topology.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+unsigned int plat_get_aff_count(unsigned int aff_lvl, unsigned long mpidr)
+{
+	/* Report 1 (absent) instance at levels higher that the cluster level */
+	if (aff_lvl > MPIDR_AFFLVL1)
+		return PLATFORM_SYSTEM_COUNT;
+
+	if (aff_lvl == MPIDR_AFFLVL1)
+		return PLATFORM_CLUSTER_COUNT;
+
+	return mpidr & 0x100 ? PLATFORM_CLUSTER1_CORE_COUNT :
+			       PLATFORM_CLUSTER0_CORE_COUNT;
+}
+
+unsigned int plat_get_aff_state(unsigned int aff_lvl, unsigned long mpidr)
+{
+	return aff_lvl <= MPIDR_AFFLVL2 ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT;
+}
+
+int mt_setup_topology(void)
+{
+	/* [TODO] Make topology configurable via SCC */
+	return 0;
+}
diff --git a/plat/mediatek/mt6795/platform.mk b/plat/mediatek/mt6795/platform.mk
new file mode 100644
index 0000000..4ab692d
--- /dev/null
+++ b/plat/mediatek/mt6795/platform.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MTK_PLAT		:=	plat/mediatek
+MTK_PLAT_SOC		:=	${MTK_PLAT}/${PLAT}
+
+# Add OEM customized codes
+OEMS				:= true
+MTK_SIP_KERNEL_BOOT_ENABLE := 1
+
+
+ifneq (${OEMS},none)
+  OEMS_INCLUDES		:= -I${MTK_PLAT}/common/custom/
+  OEMS_SOURCES		:=	${MTK_PLAT}/common/custom/oem_svc.c
+endif
+
+PLAT_INCLUDES		:=	-I${MTK_PLAT}/common/				\
+				-I${MTK_PLAT}/common/drivers/uart			\
+				-I${MTK_PLAT_SOC}/				\
+				-I${MTK_PLAT_SOC}/drivers/timer/			\
+				-I${MTK_PLAT_SOC}/include/					\
+				-Iinclude/plat/arm/common/					\
+				${OEMS_INCLUDES}
+
+PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/aarch64/xlat_tables.c			\
+				lib/xlat_tables/xlat_tables_common.c			\
+				plat/common/plat_gic.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				drivers/console/aarch64/console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				lib/cpus/aarch64/cortex_a53.S			\
+				${MTK_PLAT_SOC}/bl31_plat_setup.c		\
+				${MTK_PLAT_SOC}/plat_mt_gic.c			\
+				${MTK_PLAT}/common/mtk_sip_svc.c		\
+				${MTK_PLAT}/common/mtk_plat_common.c		\
+				${MTK_PLAT}/common/drivers/uart/8250_console.S		\
+				${MTK_PLAT_SOC}/aarch64/plat_helpers.S		\
+				${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c	\
+				${MTK_PLAT_SOC}/plat_delay_timer.c		\
+				${MTK_PLAT_SOC}/plat_pm.c			\
+				${MTK_PLAT_SOC}/plat_topology.c			\
+				${MTK_PLAT_SOC}/power_tracer.c			\
+				${MTK_PLAT_SOC}/scu.c		\
+				${OEMS_SOURCES}
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_826319	:=	1
+ERRATA_A53_836870	:=	1
+
+WORKAROUND_CVE_2017_5715	:=	0
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+
+$(eval $(call add_define,MTK_SIP_KERNEL_BOOT_ENABLE))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
diff --git a/plat/mediatek/mt6795/power_tracer.c b/plat/mediatek/mt6795/power_tracer.c
new file mode 100644
index 0000000..64d086d
--- /dev/null
+++ b/plat/mediatek/mt6795/power_tracer.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+
+#include <power_tracer.h>
+
+#define trace_log(...)  INFO("psci: " __VA_ARGS__)
+
+void trace_power_flow(unsigned long mpidr, unsigned char mode)
+{
+	switch (mode) {
+	case CPU_UP:
+		trace_log("core %lld:%lld ON\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CPU_DOWN:
+		trace_log("core %lld:%lld OFF\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CPU_SUSPEND:
+		trace_log("core %lld:%lld SUSPEND\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CLUSTER_UP:
+		trace_log("cluster %lld ON\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	case CLUSTER_DOWN:
+		trace_log("cluster %lld OFF\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	case CLUSTER_SUSPEND:
+		trace_log("cluster %lld SUSPEND\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	default:
+		trace_log("unknown power mode\n");
+		break;
+	}
+}
diff --git a/plat/mediatek/mt6795/scu.c b/plat/mediatek/mt6795/scu.c
new file mode 100644
index 0000000..3b74527
--- /dev/null
+++ b/plat/mediatek/mt6795/scu.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+
+void disable_scu(unsigned long mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg,
+			MP1_ACINACTM);
+	else
+		mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp0_axi_config,
+			MP0_ACINACTM);
+}
+
+void enable_scu(unsigned long mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg,
+			MP1_ACINACTM);
+	else
+		mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp0_axi_config,
+			MP0_ACINACTM);
+}
diff --git a/plat/mediatek/mt8173/aarch64/plat_helpers.S b/plat/mediatek/mt8173/aarch64/plat_helpers.S
new file mode 100644
index 0000000..983ebe3
--- /dev/null
+++ b/plat/mediatek/mt8173/aarch64/plat_helpers.S
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <mt8173_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_report_exception
+	.globl	platform_is_primary_cpu
+	.globl  plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* MT8173 Oak does not do cold boot for secondary CPU */
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func platform_is_primary_cpu
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #MT8173_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc platform_is_primary_cpu
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_my_core_pos(void);
+	 *
+	 * result: CorePos = CoreId + (ClusterId << 2)
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs     x0, mpidr_el1
+	and     x1, x0, #MPIDR_CPU_MASK
+	and     x0, x0, #MPIDR_CLUSTER_MASK
+	add     x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, MT8173_UART0_BASE
+	mov_imm	x1, MT8173_UART_CLOCK
+	mov_imm	x2, MT8173_BAUDRATE
+	b	console_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(void)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm x1, MT8173_UART0_BASE
+	b	console_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush(int c)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, MT8173_UART0_BASE
+	b	console_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/mediatek/mt8173/aarch64/platform_common.c b/plat/mediatek/mt8173/aarch64/platform_common.c
new file mode 100644
index 0000000..a2dbe3e
--- /dev/null
+++ b/plat/mediatek/mt8173/aarch64/platform_common.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <mt8173_def.h>
+
+static const int cci_map[] = {
+	PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+/* Table of regions to map using the MMU.  */
+const mmap_region_t plat_mmap[] = {
+	/* for TF text, RO, RW */
+	MAP_REGION_FLAT(TZRAM_BASE, TZRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+
+};
+
+/*******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+#define DEFINE_CONFIGURE_MMU_EL(_el)					\
+	void plat_configure_mmu_el ## _el(unsigned long total_base,	\
+					  unsigned long total_size,	\
+					  unsigned long ro_start,	\
+					  unsigned long ro_limit,	\
+					  unsigned long coh_start,	\
+					  unsigned long coh_limit)	\
+	{								\
+		mmap_add_region(total_base, total_base,			\
+				total_size,				\
+				MT_MEMORY | MT_RW | MT_SECURE);		\
+		mmap_add_region(ro_start, ro_start,			\
+				ro_limit - ro_start,			\
+				MT_MEMORY | MT_RO | MT_SECURE);		\
+		mmap_add_region(coh_start, coh_start,			\
+				coh_limit - coh_start,			\
+				MT_DEVICE | MT_RW | MT_SECURE);		\
+		mmap_add(plat_mmap);					\
+		init_xlat_tables();					\
+									\
+		enable_mmu_el ## _el(0);				\
+	}
+
+/* Define EL3 variants of the function initialising the MMU */
+DEFINE_CONFIGURE_MMU_EL(3)
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void plat_cci_init(void)
+{
+	/* Initialize CCI driver */
+	cci_init(PLAT_MT_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+}
+
+void plat_cci_enable(void)
+{
+	/*
+	 * Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+void plat_cci_disable(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
diff --git a/plat/mediatek/mt8173/bl31_plat_setup.c b/plat/mediatek/mt8173/bl31_plat_setup.c
new file mode 100644
index 0000000..ad81b16
--- /dev/null
+++ b/plat/mediatek/mt8173/bl31_plat_setup.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+
+#include <mcucfg.h>
+#include <mtcmos.h>
+#include <mtk_plat_common.h>
+#include <plat_private.h>
+#include <spm.h>
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+static void platform_setup_cpu(void)
+{
+	/* turn off all the little core's power except cpu 0 */
+	mtcmos_little_cpu_off();
+
+	/* setup big cores */
+	mmio_write_32((uintptr_t)&mt8173_mcucfg->mp1_config_res,
+		MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK);
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_miscdbg, MP1_AINACTS);
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_clkenm_div,
+		MP1_SW_CG_GEN);
+	mmio_clrbits_32((uintptr_t)&mt8173_mcucfg->mp1_rst_ctl,
+		MP1_L2RSTDISABLE);
+
+	/* set big cores arm64 boot mode */
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_cpucfg,
+		MP1_CPUCFG_64BIT);
+
+	/* set LITTLE cores arm64 boot mode */
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp0_rv_addr[0].rv_addr_hw,
+		MP0_CPUCFG_64BIT);
+
+	/* enable dcm control */
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->bus_fabric_dcm_ctrl,
+		ADB400_GRP_DCM_EN | CCI400_GRP_DCM_EN | ADBCLK_GRP_DCM_EN |
+		EMICLK_GRP_DCM_EN | ACLK_GRP_DCM_EN | L2C_IDLE_DCM_EN |
+		INFRACLK_PSYS_DYNAMIC_CG_EN);
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->l2c_sram_ctrl,
+		L2C_SRAM_DCM_EN);
+	mmio_setbits_32((uintptr_t)&mt8173_mcucfg->cci_clk_ctrl,
+		MCU_BUS_DCM_EN);
+}
+
+static void platform_setup_sram(void)
+{
+	/* protect BL31 memory from non-secure read/write access */
+	mmio_write_32(SRAMROM_SEC_ADDR, (uint32_t)(BL31_END + 0x3ff) & 0x3fc00);
+	mmio_write_32(SRAMROM_SEC_CTRL, 0x10000ff9);
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+	assert(next_image_info->h.type == PARAM_EP);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	console_init(MT8173_UART0_BASE, MT8173_UART_CLOCK, MT8173_BAUDRATE);
+
+	VERBOSE("bl31_setup\n");
+
+	bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info);
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+	platform_setup_cpu();
+	platform_setup_sram();
+
+	generic_delay_timer_init();
+
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_arm_gic_driver_init();
+	plat_arm_gic_init();
+
+	/* Initialize spm at boot time */
+	spm_boot_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	plat_cci_init();
+	plat_cci_enable();
+
+	plat_configure_mmu_el3(BL_CODE_BASE,
+			       BL_COHERENT_RAM_END - BL_CODE_BASE,
+			       BL_CODE_BASE,
+			       BL_CODE_END,
+			       BL_COHERENT_RAM_BASE,
+			       BL_COHERENT_RAM_END);
+}
+
diff --git a/plat/mediatek/mt8173/drivers/crypt/crypt.c b/plat/mediatek/mt8173/drivers/crypt/crypt.c
new file mode 100644
index 0000000..bfb3082
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/crypt/crypt.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <mtk_sip_svc.h>
+
+#define crypt_read32(offset)	\
+	mmio_read_32((uintptr_t)(CRYPT_BASE+((offset) * 4)))
+
+#define crypt_write32(offset, value)    \
+	mmio_write_32((uintptr_t)(CRYPT_BASE + ((offset) * 4)), (uint32_t)value)
+
+#define GET_L32(x) ((uint32_t)(x & 0xffffffff))
+#define GET_H32(x) ((uint32_t)((x >> 32) & 0xffffffff))
+
+#define REG_INIT 0
+#define REG_MSC 4
+#define REG_TRIG 256
+#define REG_STAT 512
+#define REG_CLR 513
+#define REG_INT 514
+#define REG_P68 768
+#define REG_P69 769
+#define REG_P70 770
+#define REG_P71 771
+#define REG_P72 772
+#define REG_D20 820
+#define KEY_SIZE 160
+#define KEY_LEN 40
+
+/* Wait until crypt is completed */
+uint64_t crypt_wait(void)
+{
+	crypt_write32(REG_TRIG, 0);
+	while (crypt_read32(REG_STAT) == 0)
+		;
+	udelay(100);
+	crypt_write32(REG_CLR, crypt_read32(REG_STAT));
+	crypt_write32(REG_INT, 0);
+	return MTK_SIP_E_SUCCESS;
+}
+
+static uint32_t record[4];
+/* Copy encrypted key to crypt engine */
+uint64_t crypt_set_hdcp_key_ex(uint64_t x1, uint64_t x2, uint64_t x3)
+{
+	uint32_t i = (uint32_t)x1;
+	uint32_t j = 0;
+
+	if (i > KEY_LEN)
+		return MTK_SIP_E_INVALID_PARAM;
+
+	if (i < KEY_LEN) {
+		crypt_write32(REG_MSC, 0x80ff3800);
+		crypt_write32(REG_INIT, 0);
+		crypt_write32(REG_INIT, 0xF);
+		crypt_write32(REG_CLR, 1);
+		crypt_write32(REG_INT, 0);
+
+		crypt_write32(REG_P68, 0x70);
+		crypt_write32(REG_P69, 0x1C0);
+		crypt_write32(REG_P70, 0x30);
+		crypt_write32(REG_P71, 0x4);
+		crypt_wait();
+
+		crypt_write32(REG_D20 + 4 * i, GET_L32(x2));
+		crypt_write32(REG_D20 + 4 * i + 1, GET_H32(x2));
+		crypt_write32(REG_D20 + 4 * i + 2, GET_L32(x3));
+		crypt_write32(REG_D20 + 4 * i + 3, GET_H32(x3));
+
+		crypt_write32(REG_P69, 0);
+		crypt_write32(REG_P68, 0x20);
+		crypt_write32(REG_P71, 0x34 + 4 * i);
+		crypt_write32(REG_P72, 0x34 + 4 * i);
+		crypt_wait();
+
+		for (j = 0; j < 4; j++) {
+			crypt_write32(REG_P68, 0x71);
+			crypt_write32(REG_P69, 0x34 + 4 * i + j);
+			crypt_write32(REG_P70, record[j]);
+			crypt_wait();
+		}
+	}
+	/* Prepare data for next iteration */
+	record[0] = GET_L32(x2);
+	record[1] = GET_H32(x2);
+	record[2] = GET_L32(x3);
+	record[3] = GET_H32(x3);
+	return MTK_SIP_E_SUCCESS;
+}
+
+/* Set key to hdcp */
+uint64_t crypt_set_hdcp_key_num(uint32_t num)
+{
+	if (num > KEY_LEN)
+		return MTK_SIP_E_INVALID_PARAM;
+
+	crypt_write32(REG_P68, 0x6A);
+	crypt_write32(REG_P69, 0x34 + 4 * num);
+	crypt_wait();
+	return MTK_SIP_E_SUCCESS;
+}
+
+/* Clear key in crypt engine */
+uint64_t crypt_clear_hdcp_key(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < KEY_SIZE; i++)
+		crypt_write32(REG_D20 + i, 0);
+	return MTK_SIP_E_SUCCESS;
+}
diff --git a/plat/mediatek/mt8173/drivers/crypt/crypt.h b/plat/mediatek/mt8173/drivers/crypt/crypt.h
new file mode 100644
index 0000000..1a691a6
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/crypt/crypt.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef CRYPT_H
+#define CRYPT_H
+
+#include <stdint.h>
+
+/* crypt function prototype */
+uint64_t crypt_set_hdcp_key_ex(uint64_t x1, uint64_t x2, uint64_t x3);
+uint64_t crypt_set_hdcp_key_num(uint32_t num);
+uint64_t crypt_clear_hdcp_key(void);
+
+#endif /* CRYPT_H */
diff --git a/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c
new file mode 100644
index 0000000..452ac22
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <mtcmos.h>
+#include <spm.h>
+#include <spm_mcdi.h>
+
+enum {
+	SRAM_ISOINT_B	= 1U << 6,
+	SRAM_CKISO	= 1U << 5,
+	PWR_CLK_DIS	= 1U << 4,
+	PWR_ON_2ND	= 1U << 3,
+	PWR_ON		= 1U << 2,
+	PWR_ISO		= 1U << 1,
+	PWR_RST_B	= 1U << 0
+};
+
+enum {
+	L1_PDN_ACK	= 1U << 8,
+	L1_PDN		= 1U << 0
+};
+
+enum {
+	LITTLE_CPU3	= 1U << 12,
+	LITTLE_CPU2	= 1U << 11,
+	LITTLE_CPU1	= 1U << 10,
+};
+
+enum {
+	SRAM_PDN           = 0xf << 8,
+	DIS_SRAM_ACK       = 0x1 << 12,
+	AUD_SRAM_ACK       = 0xf << 12,
+};
+
+enum {
+	DIS_PWR_STA_MASK   = 0x1 << 3,
+	AUD_PWR_STA_MASK   = 0x1 << 24,
+};
+
+#define SPM_VDE_PWR_CON				0x0210
+#define SPM_MFG_PWR_CON				0x0214
+#define SPM_VEN_PWR_CON				0x0230
+#define SPM_ISP_PWR_CON				0x0238
+#define SPM_DIS_PWR_CON				0x023c
+#define SPM_VEN2_PWR_CON			0x0298
+#define SPM_AUDIO_PWR_CON			0x029c
+#define SPM_MFG_2D_PWR_CON			0x02c0
+#define SPM_MFG_ASYNC_PWR_CON			0x02c4
+#define SPM_USB_PWR_CON				0x02cc
+
+#define MTCMOS_CTRL_SUCCESS			0
+#define MTCMOS_CTRL_ERROR			-1
+
+#define MTCMOS_CTRL_EN				(0x1 << 18)
+
+#define VDE_PWR_ON				0
+#define VEN_PWR_ON				1
+#define ISP_PWR_ON				2
+#define DIS_PWR_ON				3
+#define VEN2_PWR_ON				4
+#define AUDIO_PWR_ON				5
+#define MFG_ASYNC_PWR_ON			6
+#define MFG_2D_PWR_ON				7
+#define MFG_PWR_ON				8
+#define USB_PWR_ON				9
+
+#define VDE_PWR_OFF				10
+#define VEN_PWR_OFF				11
+#define ISP_PWR_OFF				12
+#define DIS_PWR_OFF				13
+#define VEN2_PWR_OFF				14
+#define AUDIO_PWR_OFF				15
+#define MFG_ASYNC_PWR_OFF			16
+#define MFG_2D_PWR_OFF				17
+#define MFG_PWR_OFF				18
+#define USB_PWR_OFF				19
+
+#define VDE_PWR_CON_PWR_STA			7
+#define VEN_PWR_CON_PWR_STA			21
+#define ISP_PWR_CON_PWR_STA			5
+#define DIS_PWR_CON_PWR_STA			3
+#define VEN2_PWR_CON_PWR_STA			20
+#define AUDIO_PWR_CON_PWR_STA			24
+#define MFG_ASYNC_PWR_CON_PWR_STA		23
+#define MFG_2D_PWR_CON_PWR_STA			22
+#define MFG_PWR_CON_PWR_STA			4
+#define USB_PWR_CON_PWR_STA			25
+
+/*
+ * Timeout if the ack is not signled after 1 second.
+ * According to designer, one mtcmos operation should be done
+ * around 10us.
+ */
+#define MTCMOS_ACK_POLLING_MAX_COUNT			10000
+#define MTCMOS_ACK_POLLING_INTERVAL			10
+
+static void mtcmos_ctrl_little_off(unsigned int linear_id)
+{
+	uint32_t reg_pwr_con;
+	uint32_t reg_l1_pdn;
+	uint32_t bit_cpu;
+
+	switch (linear_id) {
+	case 1:
+		reg_pwr_con = SPM_CA7_CPU1_PWR_CON;
+		reg_l1_pdn = SPM_CA7_CPU1_L1_PDN;
+		bit_cpu = LITTLE_CPU1;
+		break;
+	case 2:
+		reg_pwr_con = SPM_CA7_CPU2_PWR_CON;
+		reg_l1_pdn = SPM_CA7_CPU2_L1_PDN;
+		bit_cpu = LITTLE_CPU2;
+		break;
+	case 3:
+		reg_pwr_con = SPM_CA7_CPU3_PWR_CON;
+		reg_l1_pdn = SPM_CA7_CPU3_L1_PDN;
+		bit_cpu = LITTLE_CPU3;
+		break;
+	default:
+		/* should never come to here */
+		return;
+	}
+
+	/* enable register control */
+	mmio_write_32(SPM_POWERON_CONFIG_SET,
+			(SPM_PROJECT_CODE << 16) | (1U << 0));
+
+	mmio_setbits_32(reg_pwr_con, PWR_ISO);
+	mmio_setbits_32(reg_pwr_con, SRAM_CKISO);
+	mmio_clrbits_32(reg_pwr_con, SRAM_ISOINT_B);
+	mmio_setbits_32(reg_l1_pdn, L1_PDN);
+
+	while (!(mmio_read_32(reg_l1_pdn) & L1_PDN_ACK))
+		continue;
+
+	mmio_clrbits_32(reg_pwr_con, PWR_RST_B);
+	mmio_setbits_32(reg_pwr_con, PWR_CLK_DIS);
+	mmio_clrbits_32(reg_pwr_con, PWR_ON);
+	mmio_clrbits_32(reg_pwr_con, PWR_ON_2ND);
+
+	while ((mmio_read_32(SPM_PWR_STATUS) & bit_cpu) ||
+	       (mmio_read_32(SPM_PWR_STATUS_2ND) & bit_cpu))
+		continue;
+}
+
+void mtcmos_little_cpu_off(void)
+{
+	/* turn off little cpu 1 - 3 */
+	mtcmos_ctrl_little_off(1);
+	mtcmos_ctrl_little_off(2);
+	mtcmos_ctrl_little_off(3);
+}
+
+uint32_t wait_mtcmos_ack(uint32_t on, uint32_t pwr_ctrl, uint32_t spm_pwr_sta)
+{
+	int i = 0;
+	uint32_t cmp, pwr_sta, pwr_sta_2nd;
+
+	while (1) {
+		cmp = mmio_read_32(SPM_PCM_PASR_DPD_3) & pwr_ctrl;
+		pwr_sta = (mmio_read_32(SPM_PWR_STATUS) >> spm_pwr_sta) & 1;
+		pwr_sta_2nd =
+			(mmio_read_32(SPM_PWR_STATUS_2ND) >> spm_pwr_sta) & 1;
+		if (cmp && (pwr_sta == on) && (pwr_sta_2nd == on)) {
+			mmio_write_32(SPM_PCM_RESERVE2, 0);
+			return MTCMOS_CTRL_SUCCESS;
+		}
+		udelay(MTCMOS_ACK_POLLING_INTERVAL);
+		i++;
+		if (i > MTCMOS_ACK_POLLING_MAX_COUNT) {
+			INFO("MTCMOS control failed(%d), SPM_PWR_STA(%d),\n"
+				"SPM_PCM_RESERVE=0x%x,SPM_PCM_RESERVE2=0x%x,\n"
+				"SPM_PWR_STATUS=0x%x,SPM_PWR_STATUS_2ND=0x%x\n"
+				"SPM_PCM_PASR_DPD_3 = 0x%x\n",
+				on, spm_pwr_sta, mmio_read_32(SPM_PCM_RESERVE),
+				mmio_read_32(SPM_PCM_RESERVE2),
+				mmio_read_32(SPM_PWR_STATUS),
+				mmio_read_32(SPM_PWR_STATUS_2ND),
+				mmio_read_32(SPM_PCM_PASR_DPD_3));
+			mmio_write_32(SPM_PCM_RESERVE2, 0);
+			return MTCMOS_CTRL_ERROR;
+		}
+	}
+}
+
+uint32_t mtcmos_non_cpu_ctrl(uint32_t on, uint32_t mtcmos_num)
+{
+	uint32_t ret = MTCMOS_CTRL_SUCCESS;
+	uint32_t power_on;
+	uint32_t power_off;
+	uint32_t power_ctrl;
+	uint32_t power_status;
+
+	spm_lock_get();
+	spm_mcdi_prepare_for_mtcmos();
+	mmio_setbits_32(SPM_PCM_RESERVE, MTCMOS_CTRL_EN);
+
+	switch (mtcmos_num) {
+	case SPM_VDE_PWR_CON:
+		power_on = VDE_PWR_ON;
+		power_off = VDE_PWR_OFF;
+		power_status = VDE_PWR_CON_PWR_STA;
+		break;
+	case SPM_MFG_PWR_CON:
+		power_on = MFG_PWR_ON;
+		power_off = MFG_PWR_OFF;
+		power_status = MFG_PWR_CON_PWR_STA;
+		break;
+	case SPM_VEN_PWR_CON:
+		power_on = VEN_PWR_ON;
+		power_off = VEN_PWR_OFF;
+		power_status = VEN_PWR_CON_PWR_STA;
+		break;
+	case SPM_ISP_PWR_CON:
+		power_on = ISP_PWR_ON;
+		power_off = ISP_PWR_OFF;
+		power_status = ISP_PWR_CON_PWR_STA;
+		break;
+	case SPM_DIS_PWR_CON:
+		power_on = DIS_PWR_ON;
+		power_off = DIS_PWR_OFF;
+		power_status = DIS_PWR_CON_PWR_STA;
+		break;
+	case SPM_VEN2_PWR_CON:
+		power_on = VEN2_PWR_ON;
+		power_off = VEN2_PWR_OFF;
+		power_status = VEN2_PWR_CON_PWR_STA;
+		break;
+	case SPM_AUDIO_PWR_CON:
+		power_on = AUDIO_PWR_ON;
+		power_off = AUDIO_PWR_OFF;
+		power_status = AUDIO_PWR_CON_PWR_STA;
+		break;
+	case SPM_MFG_2D_PWR_CON:
+		power_on = MFG_2D_PWR_ON;
+		power_off = MFG_2D_PWR_OFF;
+		power_status = MFG_2D_PWR_CON_PWR_STA;
+		break;
+	case SPM_MFG_ASYNC_PWR_CON:
+		power_on = MFG_ASYNC_PWR_ON;
+		power_off = MFG_ASYNC_PWR_OFF;
+		power_status = MFG_ASYNC_PWR_CON_PWR_STA;
+		break;
+	case SPM_USB_PWR_CON:
+		power_on = USB_PWR_ON;
+		power_off = USB_PWR_OFF;
+		power_status = USB_PWR_CON_PWR_STA;
+		break;
+	default:
+		ret = MTCMOS_CTRL_ERROR;
+		INFO("No mapping MTCMOS(%d), ret = %d\n", mtcmos_num, ret);
+		break;
+	}
+	if (ret == MTCMOS_CTRL_SUCCESS) {
+		power_ctrl = on ? (1 << power_on) : (1 << power_off);
+		mmio_setbits_32(SPM_PCM_RESERVE2, power_ctrl);
+		ret = wait_mtcmos_ack(on, power_ctrl, power_status);
+		VERBOSE("0x%x(%d), PWR_STATUS(0x%x), ret(%d)\n",
+			power_ctrl, on, mmio_read_32(SPM_PWR_STATUS), ret);
+	}
+
+	mmio_clrbits_32(SPM_PCM_RESERVE, MTCMOS_CTRL_EN);
+	spm_lock_release();
+
+	return ret;
+}
diff --git a/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h
new file mode 100644
index 0000000..1e58027
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MTCMOS_H
+#define MTCMOS_H
+
+/*
+ * This function will turn off all the little core's power except cpu 0. The
+ * cores in cluster 0 are all powered when the system power on. The System
+ * Power Manager (SPM) will do nothing if it found the core's power was on
+ * during CPU_ON psci call.
+ */
+void mtcmos_little_cpu_off(void);
+uint32_t mtcmos_non_cpu_ctrl(uint32_t on, uint32_t mtcmos_num);
+
+#endif /* MTCMOS_H */
diff --git a/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.c b/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.c
new file mode 100644
index 0000000..8120d99
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <pmic_wrap_init.h>
+
+/* pmic wrap module wait_idle and read polling interval (in microseconds) */
+enum {
+	WAIT_IDLE_POLLING_DELAY_US	= 1,
+	READ_POLLING_DELAY_US		= 2
+};
+
+static inline uint32_t wait_for_state_idle(uint32_t timeout_us,
+					   void *wacs_register,
+					   void *wacs_vldclr_register,
+					   uint32_t *read_reg)
+{
+	uint32_t reg_rdata;
+	uint32_t retry;
+
+	retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
+		WAIT_IDLE_POLLING_DELAY_US;
+
+	do {
+		udelay(WAIT_IDLE_POLLING_DELAY_US);
+		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
+		/* if last read command timeout,clear vldclr bit
+		   read command state machine:FSM_REQ-->wfdle-->WFVLDCLR;
+		   write:FSM_REQ-->idle */
+		switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) &
+			RDATA_WACS_FSM_MASK)) {
+		case WACS_FSM_WFVLDCLR:
+			mmio_write_32((uintptr_t)wacs_vldclr_register, 1);
+			ERROR("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n");
+			break;
+		case WACS_FSM_WFDLE:
+			ERROR("WACS_FSM = WACS_FSM_WFDLE\n");
+			break;
+		case WACS_FSM_REQ:
+			ERROR("WACS_FSM = WACS_FSM_REQ\n");
+			break;
+		case WACS_FSM_IDLE:
+			goto done;
+		default:
+			break;
+		}
+
+		retry--;
+	} while (retry);
+
+done:
+	if (!retry)	/* timeout */
+		return E_PWR_WAIT_IDLE_TIMEOUT;
+
+	if (read_reg)
+		*read_reg = reg_rdata;
+	return 0;
+}
+
+static inline uint32_t wait_for_state_ready(uint32_t timeout_us,
+					    void *wacs_register,
+					    uint32_t *read_reg)
+{
+	uint32_t reg_rdata;
+	uint32_t retry;
+
+	retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
+
+	do {
+		udelay(READ_POLLING_DELAY_US);
+		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
+
+		if (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK)
+		    == WACS_FSM_WFVLDCLR)
+			break;
+
+		retry--;
+	} while (retry);
+
+	if (!retry) {	/* timeout */
+		ERROR("timeout when waiting for idle\n");
+		return E_PWR_WAIT_IDLE_TIMEOUT_READ;
+	}
+
+	if (read_reg)
+		*read_reg = reg_rdata;
+	return 0;
+}
+
+static int32_t pwrap_wacs2(uint32_t write,
+		    uint32_t adr,
+		    uint32_t wdata,
+		    uint32_t *rdata,
+		    uint32_t init_check)
+{
+	uint32_t reg_rdata = 0;
+	uint32_t wacs_write = 0;
+	uint32_t wacs_adr = 0;
+	uint32_t wacs_cmd = 0;
+	uint32_t return_value = 0;
+
+	if (init_check) {
+		reg_rdata = mmio_read_32((uintptr_t)&mt8173_pwrap->wacs2_rdata);
+		/* Prevent someone to used pwrap before pwrap init */
+		if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) &
+		    RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) {
+			ERROR("initialization isn't finished\n");
+			return E_PWR_NOT_INIT_DONE;
+		}
+	}
+	reg_rdata = 0;
+	/* Check IDLE in advance */
+	return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE,
+				&mt8173_pwrap->wacs2_rdata,
+				&mt8173_pwrap->wacs2_vldclr,
+				0);
+	if (return_value != 0) {
+		ERROR("wait_for_fsm_idle fail,return_value=%d\n", return_value);
+		goto FAIL;
+	}
+	wacs_write = write << 31;
+	wacs_adr = (adr >> 1) << 16;
+	wacs_cmd = wacs_write | wacs_adr | wdata;
+
+	mmio_write_32((uintptr_t)&mt8173_pwrap->wacs2_cmd, wacs_cmd);
+	if (write == 0) {
+		if (NULL == rdata) {
+			ERROR("rdata is a NULL pointer\n");
+			return_value = E_PWR_INVALID_ARG;
+			goto FAIL;
+		}
+		return_value = wait_for_state_ready(TIMEOUT_READ,
+					&mt8173_pwrap->wacs2_rdata,
+					&reg_rdata);
+		if (return_value != 0) {
+			ERROR("wait_for_fsm_vldclr fail,return_value=%d\n",
+				 return_value);
+			goto FAIL;
+		}
+		*rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT)
+			  & RDATA_WACS_RDATA_MASK);
+		mmio_write_32((uintptr_t)&mt8173_pwrap->wacs2_vldclr, 1);
+	}
+FAIL:
+	return return_value;
+}
+
+/* external API for pmic_wrap user */
+
+int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
+{
+	return pwrap_wacs2(0, adr, 0, rdata, 1);
+}
+
+int32_t pwrap_write(uint32_t adr, uint32_t wdata)
+{
+	return pwrap_wacs2(1, adr, wdata, 0, 1);
+}
diff --git a/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..0f09771
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_H
+#define PMIC_WRAP_INIT_H
+
+/* external API */
+int32_t pwrap_read(uint32_t adr, uint32_t *rdata);
+int32_t pwrap_write(uint32_t adr, uint32_t wdata);
+
+static struct mt8173_pmic_wrap_regs *const mt8173_pwrap =
+	(void *)PMIC_WRAP_BASE;
+
+/* timeout setting */
+enum {
+	TIMEOUT_RESET       = 50,	/* us */
+	TIMEOUT_READ        = 50,	/* us */
+	TIMEOUT_WAIT_IDLE   = 50	/* us */
+};
+
+/* PMIC_WRAP registers */
+struct mt8173_pmic_wrap_regs {
+	uint32_t mux_sel;
+	uint32_t wrap_en;
+	uint32_t dio_en;
+	uint32_t sidly;
+	uint32_t rddmy;
+	uint32_t si_ck_con;
+	uint32_t cshext_write;
+	uint32_t cshext_read;
+	uint32_t cslext_start;
+	uint32_t cslext_end;
+	uint32_t staupd_prd;
+	uint32_t staupd_grpen;
+	uint32_t reserved[4];
+	uint32_t staupd_man_trig;
+	uint32_t staupd_sta;
+	uint32_t wrap_sta;
+	uint32_t harb_init;
+	uint32_t harb_hprio;
+	uint32_t hiprio_arb_en;
+	uint32_t harb_sta0;
+	uint32_t harb_sta1;
+	uint32_t man_en;
+	uint32_t man_cmd;
+	uint32_t man_rdata;
+	uint32_t man_vldclr;
+	uint32_t wacs0_en;
+	uint32_t init_done0;
+	uint32_t wacs0_cmd;
+	uint32_t wacs0_rdata;
+	uint32_t wacs0_vldclr;
+	uint32_t wacs1_en;
+	uint32_t init_done1;
+	uint32_t wacs1_cmd;
+	uint32_t wacs1_rdata;
+	uint32_t wacs1_vldclr;
+	uint32_t wacs2_en;
+	uint32_t init_done2;
+	uint32_t wacs2_cmd;
+	uint32_t wacs2_rdata;
+	uint32_t wacs2_vldclr;
+	uint32_t int_en;
+	uint32_t int_flg_raw;
+	uint32_t int_flg;
+	uint32_t int_clr;
+	uint32_t sig_adr;
+	uint32_t sig_mode;
+	uint32_t sig_value;
+	uint32_t sig_errval;
+	uint32_t crc_en;
+	uint32_t timer_en;
+	uint32_t timer_sta;
+	uint32_t wdt_unit;
+	uint32_t wdt_src_en;
+	uint32_t wdt_flg;
+	uint32_t debug_int_sel;
+	uint32_t dvfs_adr0;
+	uint32_t dvfs_wdata0;
+	uint32_t dvfs_adr1;
+	uint32_t dvfs_wdata1;
+	uint32_t dvfs_adr2;
+	uint32_t dvfs_wdata2;
+	uint32_t dvfs_adr3;
+	uint32_t dvfs_wdata3;
+	uint32_t dvfs_adr4;
+	uint32_t dvfs_wdata4;
+	uint32_t dvfs_adr5;
+	uint32_t dvfs_wdata5;
+	uint32_t dvfs_adr6;
+	uint32_t dvfs_wdata6;
+	uint32_t dvfs_adr7;
+	uint32_t dvfs_wdata7;
+	uint32_t spminf_sta;
+	uint32_t cipher_key_sel;
+	uint32_t cipher_iv_sel;
+	uint32_t cipher_en;
+	uint32_t cipher_rdy;
+	uint32_t cipher_mode;
+	uint32_t cipher_swrst;
+	uint32_t dcm_en;
+	uint32_t dcm_dbc_prd;
+};
+
+enum {
+	RDATA_WACS_RDATA_SHIFT = 0,
+	RDATA_WACS_FSM_SHIFT = 16,
+	RDATA_WACS_REQ_SHIFT = 19,
+	RDATA_SYNC_IDLE_SHIFT,
+	RDATA_INIT_DONE_SHIFT,
+	RDATA_SYS_IDLE_SHIFT,
+};
+
+enum {
+	RDATA_WACS_RDATA_MASK = 0xffff,
+	RDATA_WACS_FSM_MASK = 0x7,
+	RDATA_WACS_REQ_MASK = 0x1,
+	RDATA_SYNC_IDLE_MASK = 0x1,
+	RDATA_INIT_DONE_MASK = 0x1,
+	RDATA_SYS_IDLE_MASK = 0x1,
+};
+
+/* WACS_FSM */
+enum {
+	WACS_FSM_IDLE            = 0x00,
+	WACS_FSM_REQ             = 0x02,
+	WACS_FSM_WFDLE           = 0x04,
+	WACS_FSM_WFVLDCLR        = 0x06,
+	WACS_INIT_DONE           = 0x01,
+	WACS_SYNC_IDLE           = 0x01,
+	WACS_SYNC_BUSY           = 0x00
+};
+
+/* error information flag */
+enum {
+	E_PWR_INVALID_ARG             = 1,
+	E_PWR_INVALID_RW              = 2,
+	E_PWR_INVALID_ADDR            = 3,
+	E_PWR_INVALID_WDAT            = 4,
+	E_PWR_INVALID_OP_MANUAL       = 5,
+	E_PWR_NOT_IDLE_STATE          = 6,
+	E_PWR_NOT_INIT_DONE           = 7,
+	E_PWR_NOT_INIT_DONE_READ      = 8,
+	E_PWR_WAIT_IDLE_TIMEOUT       = 9,
+	E_PWR_WAIT_IDLE_TIMEOUT_READ  = 10,
+	E_PWR_INIT_SIDLY_FAIL         = 11,
+	E_PWR_RESET_TIMEOUT           = 12,
+	E_PWR_TIMEOUT                 = 13,
+	E_PWR_INIT_RESET_SPI          = 20,
+	E_PWR_INIT_SIDLY              = 21,
+	E_PWR_INIT_REG_CLOCK          = 22,
+	E_PWR_INIT_ENABLE_PMIC        = 23,
+	E_PWR_INIT_DIO                = 24,
+	E_PWR_INIT_CIPHER             = 25,
+	E_PWR_INIT_WRITE_TEST         = 26,
+	E_PWR_INIT_ENABLE_CRC         = 27,
+	E_PWR_INIT_ENABLE_DEWRAP      = 28,
+	E_PWR_INIT_ENABLE_EVENT       = 29,
+	E_PWR_READ_TEST_FAIL          = 30,
+	E_PWR_WRITE_TEST_FAIL         = 31,
+	E_PWR_SWITCH_DIO              = 32
+};
+
+#endif /* PMIC_WRAP_INIT_H */
diff --git a/plat/mediatek/mt8173/drivers/rtc/rtc.c b/plat/mediatek/mt8173/drivers/rtc/rtc.c
new file mode 100644
index 0000000..2b9033e
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/rtc/rtc.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <mt8173_def.h>
+#include <pmic_wrap_init.h>
+#include <rtc.h>
+
+/* RTC busy status polling interval and retry count */
+enum {
+	RTC_WRTGR_POLLING_DELAY_MS	= 10,
+	RTC_WRTGR_POLLING_CNT		= 100
+};
+
+static uint16_t RTC_Read(uint32_t addr)
+{
+	uint32_t rdata = 0;
+
+	pwrap_read((uint32_t)addr, &rdata);
+	return (uint16_t)rdata;
+}
+
+static void RTC_Write(uint32_t addr, uint16_t data)
+{
+	pwrap_write((uint32_t)addr, (uint32_t)data);
+}
+
+static inline int32_t rtc_busy_wait(void)
+{
+	uint64_t retry = RTC_WRTGR_POLLING_CNT;
+
+	do {
+		mdelay(RTC_WRTGR_POLLING_DELAY_MS);
+		if (!(RTC_Read(RTC_BBPU) & RTC_BBPU_CBUSY))
+			return 1;
+		retry--;
+	} while (retry);
+
+	ERROR("[RTC] rtc cbusy time out!\n");
+	return 0;
+}
+
+static int32_t Write_trigger(void)
+{
+	RTC_Write(RTC_WRTGR, 1);
+	return rtc_busy_wait();
+}
+
+static int32_t Writeif_unlock(void)
+{
+	RTC_Write(RTC_PROT, RTC_PROT_UNLOCK1);
+	if (!Write_trigger())
+		return 0;
+	RTC_Write(RTC_PROT, RTC_PROT_UNLOCK2);
+	if (!Write_trigger())
+		return 0;
+
+	return 1;
+}
+
+void rtc_bbpu_power_down(void)
+{
+	uint16_t bbpu;
+
+	/* pull PWRBB low */
+	bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_PWREN;
+	if (Writeif_unlock()) {
+		RTC_Write(RTC_BBPU, bbpu);
+		if (!Write_trigger())
+			assert(0);
+	} else {
+		assert(0);
+	}
+}
diff --git a/plat/mediatek/mt8173/drivers/rtc/rtc.h b/plat/mediatek/mt8173/drivers/rtc/rtc.h
new file mode 100644
index 0000000..9c4ca49
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/rtc/rtc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+/* RTC registers */
+enum {
+	RTC_BBPU = 0xE000,
+	RTC_IRQ_STA = 0xE002,
+	RTC_IRQ_EN = 0xE004,
+	RTC_CII_EN = 0xE006
+};
+
+enum {
+	RTC_OSC32CON = 0xE026,
+	RTC_CON = 0xE03E,
+	RTC_WRTGR = 0xE03C
+};
+
+enum {
+	RTC_PDN1 = 0xE02C,
+	RTC_PDN2 = 0xE02E,
+	RTC_SPAR0 = 0xE030,
+	RTC_SPAR1 = 0xE032,
+	RTC_PROT = 0xE036,
+	RTC_DIFF = 0xE038,
+	RTC_CALI = 0xE03A
+};
+
+enum {
+	RTC_PROT_UNLOCK1 = 0x586A,
+	RTC_PROT_UNLOCK2 = 0x9136
+};
+
+enum {
+	RTC_BBPU_PWREN	= 1U << 0,
+	RTC_BBPU_BBPU	= 1U << 2,
+	RTC_BBPU_AUTO	= 1U << 3,
+	RTC_BBPU_CLRPKY	= 1U << 4,
+	RTC_BBPU_RELOAD	= 1U << 5,
+	RTC_BBPU_CBUSY	= 1U << 6
+};
+
+enum {
+	RTC_BBPU_KEY	= 0x43 << 8
+};
+
+void rtc_bbpu_power_down(void);
+
+#endif /* RTC_H */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm.c b/plat/mediatek/mt8173/drivers/spm/spm.c
new file mode 100644
index 0000000..1caab3b
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <spm.h>
+#include <spm_suspend.h>
+
+/*
+ * System Power Manager (SPM) is a hardware module, which controls cpu or
+ * system power for different power scenarios using different firmware, i.e.,
+ * - spm_hotplug.c for cpu power control in cpu hotplug flow.
+ * - spm_mcdi.c for cpu power control in cpu idle power saving state.
+ * - spm_suspend.c for system power control in system suspend scenario.
+ *
+ * This file provide utility functions common to hotplug, mcdi(idle), suspend
+ * power scenarios. A bakery lock (software lock) is incoporated to protect
+ * certain critical sections to avoid kicking different SPM firmware
+ * concurrently.
+ */
+
+#define SPM_SYSCLK_SETTLE       128	/* 3.9ms */
+
+DEFINE_BAKERY_LOCK(spm_lock);
+
+static int spm_hotplug_ready __section("tzfw_coherent_mem");
+static int spm_mcdi_ready __section("tzfw_coherent_mem");
+static int spm_suspend_ready __section("tzfw_coherent_mem");
+
+void spm_lock_init(void)
+{
+	bakery_lock_init(&spm_lock);
+}
+
+void spm_lock_get(void)
+{
+	bakery_lock_get(&spm_lock);
+}
+
+void spm_lock_release(void)
+{
+	bakery_lock_release(&spm_lock);
+}
+
+int is_mcdi_ready(void)
+{
+	return spm_mcdi_ready;
+}
+
+int is_hotplug_ready(void)
+{
+	return spm_hotplug_ready;
+}
+
+int is_suspend_ready(void)
+{
+	return spm_suspend_ready;
+}
+
+void set_mcdi_ready(void)
+{
+	spm_mcdi_ready = 1;
+	spm_hotplug_ready = 0;
+	spm_suspend_ready = 0;
+}
+
+void set_hotplug_ready(void)
+{
+	spm_mcdi_ready = 0;
+	spm_hotplug_ready = 1;
+	spm_suspend_ready = 0;
+}
+
+void set_suspend_ready(void)
+{
+	spm_mcdi_ready = 0;
+	spm_hotplug_ready = 0;
+	spm_suspend_ready = 1;
+}
+
+void clear_all_ready(void)
+{
+	spm_mcdi_ready = 0;
+	spm_hotplug_ready = 0;
+	spm_suspend_ready = 0;
+}
+
+void spm_register_init(void)
+{
+	mmio_write_32(SPM_POWERON_CONFIG_SET, SPM_REGWR_CFG_KEY | SPM_REGWR_EN);
+
+	mmio_write_32(SPM_POWER_ON_VAL0, 0);
+	mmio_write_32(SPM_POWER_ON_VAL1, POWER_ON_VAL1_DEF);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+
+	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET);
+	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY);
+	if (mmio_read_32(SPM_PCM_FSM_STA) != PCM_FSM_STA_DEF)
+		WARN("PCM reset failed\n");
+
+	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS);
+	mmio_write_32(SPM_PCM_CON1, CON1_CFG_KEY | CON1_EVENT_LOCK_EN |
+		CON1_SPM_SRAM_ISO_B | CON1_SPM_SRAM_SLP_B | CON1_MIF_APBEN);
+	mmio_write_32(SPM_PCM_IM_PTR, 0);
+	mmio_write_32(SPM_PCM_IM_LEN, 0);
+
+	mmio_write_32(SPM_CLK_CON, CC_SYSCLK0_EN_1 | CC_SYSCLK0_EN_0 |
+		CC_SYSCLK1_EN_0 | CC_SRCLKENA_MASK_0 | CC_CLKSQ1_SEL |
+		CC_CXO32K_RM_EN_MD2 | CC_CXO32K_RM_EN_MD1 | CC_MD32_DCM_EN);
+
+	mmio_write_32(SPM_SLEEP_ISR_MASK, 0xff0c);
+	mmio_write_32(SPM_SLEEP_ISR_STATUS, 0xc);
+	mmio_write_32(SPM_PCM_SW_INT_CLEAR, 0xff);
+	mmio_write_32(SPM_MD32_SRAM_CON, 0xff0);
+}
+
+void spm_reset_and_init_pcm(void)
+{
+	unsigned int con1;
+	int i = 0;
+
+	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET);
+	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY);
+	while (mmio_read_32(SPM_PCM_FSM_STA) != PCM_FSM_STA_DEF) {
+		i++;
+		if (i > 1000) {
+			i = 0;
+			WARN("PCM reset failed\n");
+			break;
+		}
+	}
+
+	mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS);
+
+	con1 = mmio_read_32(SPM_PCM_CON1) &
+		(CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN);
+	mmio_write_32(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_EVENT_LOCK_EN |
+		CON1_SPM_SRAM_ISO_B | CON1_SPM_SRAM_SLP_B |
+		CON1_IM_NONRP_EN | CON1_MIF_APBEN);
+}
+
+void spm_init_pcm_register(void)
+{
+	mmio_write_32(SPM_PCM_REG_DATA_INI, mmio_read_32(SPM_POWER_ON_VAL0));
+	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R0);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+
+	mmio_write_32(SPM_PCM_REG_DATA_INI, mmio_read_32(SPM_POWER_ON_VAL1));
+	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R7);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+}
+
+void spm_set_power_control(const struct pwr_ctrl *pwrctrl)
+{
+	mmio_write_32(SPM_AP_STANBY_CON, (!pwrctrl->md32_req_mask << 21) |
+					 (!pwrctrl->mfg_req_mask << 17) |
+					 (!pwrctrl->disp_req_mask << 16) |
+					 (!!pwrctrl->mcusys_idle_mask << 7) |
+					 (!!pwrctrl->ca15top_idle_mask << 6) |
+					 (!!pwrctrl->ca7top_idle_mask << 5) |
+					 (!!pwrctrl->wfi_op << 4));
+	mmio_write_32(SPM_PCM_SRC_REQ, (!!pwrctrl->pcm_apsrc_req << 0));
+	mmio_write_32(SPM_PCM_PASR_DPD_2, 0);
+
+	mmio_clrsetbits_32(SPM_CLK_CON, CC_SRCLKENA_MASK_0,
+		(pwrctrl->srclkenai_mask ? CC_SRCLKENA_MASK_0 : 0));
+
+	mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, !!pwrctrl->ca15_wfi0_en);
+	mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, !!pwrctrl->ca15_wfi1_en);
+	mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, !!pwrctrl->ca15_wfi2_en);
+	mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, !!pwrctrl->ca15_wfi3_en);
+	mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, !!pwrctrl->ca7_wfi0_en);
+	mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, !!pwrctrl->ca7_wfi1_en);
+	mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, !!pwrctrl->ca7_wfi2_en);
+	mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, !!pwrctrl->ca7_wfi3_en);
+}
+
+void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl)
+{
+	unsigned int val, mask;
+
+	if (pwrctrl->timer_val_cust == 0)
+		val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX;
+	else
+		val = pwrctrl->timer_val_cust;
+
+	mmio_write_32(SPM_PCM_TIMER_VAL, val);
+	mmio_setbits_32(SPM_PCM_CON1, CON1_CFG_KEY);
+
+	if (pwrctrl->wake_src_cust == 0)
+		mask = pwrctrl->wake_src;
+	else
+		mask = pwrctrl->wake_src_cust;
+
+	if (pwrctrl->syspwreq_mask)
+		mask &= ~WAKE_SRC_SYSPWREQ;
+
+	mmio_write_32(SPM_SLEEP_WAKEUP_EVENT_MASK, ~mask);
+	mmio_write_32(SPM_SLEEP_ISR_MASK, 0xfe04);
+}
+
+void spm_get_wakeup_status(struct wake_status *wakesta)
+{
+	wakesta->assert_pc = mmio_read_32(SPM_PCM_REG_DATA_INI);
+	wakesta->r12 = mmio_read_32(SPM_PCM_REG12_DATA);
+	wakesta->raw_sta = mmio_read_32(SPM_SLEEP_ISR_RAW_STA);
+	wakesta->wake_misc = mmio_read_32(SPM_SLEEP_WAKEUP_MISC);
+	wakesta->timer_out = mmio_read_32(SPM_PCM_TIMER_OUT);
+	wakesta->r13 = mmio_read_32(SPM_PCM_REG13_DATA);
+	wakesta->idle_sta = mmio_read_32(SPM_SLEEP_SUBSYS_IDLE_STA);
+	wakesta->debug_flag = mmio_read_32(SPM_PCM_PASR_DPD_3);
+	wakesta->event_reg = mmio_read_32(SPM_PCM_EVENT_REG_STA);
+	wakesta->isr = mmio_read_32(SPM_SLEEP_ISR_STATUS);
+}
+
+void spm_init_event_vector(const struct pcm_desc *pcmdesc)
+{
+	/* init event vector register */
+	mmio_write_32(SPM_PCM_EVENT_VECTOR0, pcmdesc->vec0);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR1, pcmdesc->vec1);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR2, pcmdesc->vec2);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR3, pcmdesc->vec3);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR4, pcmdesc->vec4);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR5, pcmdesc->vec5);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR6, pcmdesc->vec6);
+	mmio_write_32(SPM_PCM_EVENT_VECTOR7, pcmdesc->vec7);
+
+	/* event vector will be enabled by PCM itself */
+}
+
+void spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc)
+{
+	unsigned int ptr = 0, len, con0;
+
+	ptr = (unsigned int)(unsigned long)(pcmdesc->base);
+	len = pcmdesc->size - 1;
+	if (mmio_read_32(SPM_PCM_IM_PTR) != ptr ||
+	    mmio_read_32(SPM_PCM_IM_LEN) != len ||
+	    pcmdesc->sess > 2) {
+		mmio_write_32(SPM_PCM_IM_PTR, ptr);
+		mmio_write_32(SPM_PCM_IM_LEN, len);
+	} else {
+		mmio_setbits_32(SPM_PCM_CON1, CON1_CFG_KEY | CON1_IM_SLAVE);
+	}
+
+	/* kick IM to fetch (only toggle IM_KICK) */
+	con0 = mmio_read_32(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK);
+	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_IM_KICK);
+	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY);
+
+	/* kick IM to fetch (only toggle PCM_KICK) */
+	con0 = mmio_read_32(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK);
+	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_PCM_KICK);
+	mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY);
+}
+
+void spm_set_sysclk_settle(void)
+{
+	mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE);
+
+	INFO("settle = %u\n", mmio_read_32(SPM_CLK_SETTLE));
+}
+
+void spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl)
+{
+	unsigned int con1;
+
+	con1 = mmio_read_32(SPM_PCM_CON1) &
+		~(CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN);
+
+	mmio_write_32(SPM_PCM_CON1, CON1_CFG_KEY | con1);
+
+	if (mmio_read_32(SPM_PCM_TIMER_VAL) > PCM_TIMER_MAX)
+		mmio_write_32(SPM_PCM_TIMER_VAL, PCM_TIMER_MAX);
+
+	mmio_write_32(SPM_PCM_WDT_TIMER_VAL,
+		mmio_read_32(SPM_PCM_TIMER_VAL) + PCM_WDT_TIMEOUT);
+
+	mmio_write_32(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_PCM_WDT_EN);
+	mmio_write_32(SPM_PCM_PASR_DPD_0, 0);
+
+	mmio_write_32(SPM_PCM_MAS_PAUSE_MASK, 0xffffffff);
+	mmio_write_32(SPM_PCM_REG_DATA_INI, 0);
+	mmio_clrbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR);
+
+	mmio_write_32(SPM_PCM_FLAGS, pwrctrl->pcm_flags);
+
+	mmio_clrsetbits_32(SPM_CLK_CON, CC_LOCK_INFRA_DCM,
+		(pwrctrl->infra_dcm_lock ? CC_LOCK_INFRA_DCM : 0));
+
+	mmio_write_32(SPM_PCM_PWR_IO_EN,
+		(pwrctrl->r0_ctrl_en ? PCM_PWRIO_EN_R0 : 0) |
+		(pwrctrl->r7_ctrl_en ? PCM_PWRIO_EN_R7 : 0));
+}
+
+void spm_clean_after_wakeup(void)
+{
+	mmio_clrsetbits_32(SPM_PCM_CON1, CON1_PCM_WDT_EN, CON1_CFG_KEY);
+
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+	mmio_write_32(SPM_SLEEP_CPU_WAKEUP_EVENT, 0);
+	mmio_clrsetbits_32(SPM_PCM_CON1, CON1_PCM_TIMER_EN, CON1_CFG_KEY);
+
+	mmio_write_32(SPM_SLEEP_WAKEUP_EVENT_MASK, ~0);
+	mmio_write_32(SPM_SLEEP_ISR_MASK, 0xFF0C);
+	mmio_write_32(SPM_SLEEP_ISR_STATUS, 0xC);
+	mmio_write_32(SPM_PCM_SW_INT_CLEAR, 0xFF);
+}
+
+enum wake_reason_t spm_output_wake_reason(struct wake_status *wakesta)
+{
+	enum wake_reason_t wr;
+	int i;
+
+	wr = WR_UNKNOWN;
+
+	if (wakesta->assert_pc != 0) {
+		ERROR("PCM ASSERT AT %u, r12=0x%x, r13=0x%x, debug_flag=0x%x\n",
+		      wakesta->assert_pc, wakesta->r12, wakesta->r13,
+		      wakesta->debug_flag);
+		return WR_PCM_ASSERT;
+	}
+
+	if (wakesta->r12 & WAKE_SRC_SPM_MERGE) {
+		if (wakesta->wake_misc & WAKE_MISC_PCM_TIMER)
+			wr = WR_PCM_TIMER;
+		if (wakesta->wake_misc & WAKE_MISC_CPU_WAKE)
+			wr = WR_WAKE_SRC;
+	}
+
+	for (i = 1; i < 32; i++) {
+		if (wakesta->r12 & (1U << i))
+			wr = WR_WAKE_SRC;
+	}
+
+	if ((wakesta->event_reg & 0x100000) == 0) {
+		INFO("pcm sleep abort!\n");
+		wr = WR_PCM_ABORT;
+	}
+
+	INFO("timer_out = %u, r12 = 0x%x, r13 = 0x%x, debug_flag = 0x%x\n",
+	     wakesta->timer_out, wakesta->r12, wakesta->r13,
+	     wakesta->debug_flag);
+
+	INFO("raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n",
+	     wakesta->raw_sta, wakesta->idle_sta, wakesta->event_reg,
+	     wakesta->isr);
+
+	return wr;
+}
+
+void spm_boot_init(void)
+{
+	/* set spm transaction to secure mode */
+	mmio_write_32(DEVAPC0_APC_CON, 0x0);
+	mmio_write_32(DEVAPC0_MAS_SEC_0, 0x200);
+
+	/* Only CPU0 is online during boot, initialize cpu online reserve bit */
+	mmio_write_32(SPM_PCM_RESERVE, 0xFE);
+	mmio_clrbits_32(AP_PLL_CON3, 0xFFFFF);
+	mmio_clrbits_32(AP_PLL_CON4, 0xF);
+	spm_lock_init();
+	spm_register_init();
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm.h b/plat/mediatek/mt8173/drivers/spm/spm.h
new file mode 100644
index 0000000..403303a
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SPM_H
+#define SPM_H
+
+#define SPM_POWERON_CONFIG_SET			(SPM_BASE + 0x000)
+#define SPM_POWER_ON_VAL0			(SPM_BASE + 0x010)
+#define SPM_POWER_ON_VAL1			(SPM_BASE + 0x014)
+#define SPM_CLK_SETTLE				(SPM_BASE + 0x100)
+#define SPM_CA7_CPU1_PWR_CON			(SPM_BASE + 0x218)
+#define SPM_CA7_CPU2_PWR_CON			(SPM_BASE + 0x21c)
+#define SPM_CA7_CPU3_PWR_CON			(SPM_BASE + 0x220)
+#define SPM_CA7_CPU1_L1_PDN			(SPM_BASE + 0x264)
+#define SPM_CA7_CPU2_L1_PDN			(SPM_BASE + 0x26c)
+#define SPM_CA7_CPU3_L1_PDN			(SPM_BASE + 0x274)
+#define SPM_MD32_SRAM_CON			(SPM_BASE + 0x2c8)
+#define SPM_PCM_CON0				(SPM_BASE + 0x310)
+#define SPM_PCM_CON1				(SPM_BASE + 0x314)
+#define SPM_PCM_IM_PTR				(SPM_BASE + 0x318)
+#define SPM_PCM_IM_LEN				(SPM_BASE + 0x31c)
+#define SPM_PCM_REG_DATA_INI			(SPM_BASE + 0x320)
+#define SPM_PCM_EVENT_VECTOR0			(SPM_BASE + 0x340)
+#define SPM_PCM_EVENT_VECTOR1			(SPM_BASE + 0x344)
+#define SPM_PCM_EVENT_VECTOR2			(SPM_BASE + 0x348)
+#define SPM_PCM_EVENT_VECTOR3			(SPM_BASE + 0x34c)
+#define SPM_PCM_MAS_PAUSE_MASK			(SPM_BASE + 0x354)
+#define SPM_PCM_PWR_IO_EN			(SPM_BASE + 0x358)
+#define SPM_PCM_TIMER_VAL			(SPM_BASE + 0x35c)
+#define SPM_PCM_TIMER_OUT			(SPM_BASE + 0x360)
+#define SPM_PCM_REG0_DATA			(SPM_BASE + 0x380)
+#define SPM_PCM_REG1_DATA			(SPM_BASE + 0x384)
+#define SPM_PCM_REG2_DATA			(SPM_BASE + 0x388)
+#define SPM_PCM_REG3_DATA			(SPM_BASE + 0x38c)
+#define SPM_PCM_REG4_DATA			(SPM_BASE + 0x390)
+#define SPM_PCM_REG5_DATA			(SPM_BASE + 0x394)
+#define SPM_PCM_REG6_DATA			(SPM_BASE + 0x398)
+#define SPM_PCM_REG7_DATA			(SPM_BASE + 0x39c)
+#define SPM_PCM_REG8_DATA			(SPM_BASE + 0x3a0)
+#define SPM_PCM_REG9_DATA			(SPM_BASE + 0x3a4)
+#define SPM_PCM_REG10_DATA			(SPM_BASE + 0x3a8)
+#define SPM_PCM_REG11_DATA			(SPM_BASE + 0x3ac)
+#define SPM_PCM_REG12_DATA			(SPM_BASE + 0x3b0)
+#define SPM_PCM_REG13_DATA			(SPM_BASE + 0x3b4)
+#define SPM_PCM_REG14_DATA			(SPM_BASE + 0x3b8)
+#define SPM_PCM_REG15_DATA			(SPM_BASE + 0x3bc)
+#define SPM_PCM_EVENT_REG_STA			(SPM_BASE + 0x3c0)
+#define SPM_PCM_FSM_STA				(SPM_BASE + 0x3c4)
+#define SPM_PCM_IM_HOST_RW_PTR			(SPM_BASE + 0x3c8)
+#define SPM_PCM_IM_HOST_RW_DAT			(SPM_BASE + 0x3cc)
+#define SPM_PCM_EVENT_VECTOR4			(SPM_BASE + 0x3d0)
+#define SPM_PCM_EVENT_VECTOR5			(SPM_BASE + 0x3d4)
+#define SPM_PCM_EVENT_VECTOR6			(SPM_BASE + 0x3d8)
+#define SPM_PCM_EVENT_VECTOR7			(SPM_BASE + 0x3dc)
+#define SPM_PCM_SW_INT_SET			(SPM_BASE + 0x3e0)
+#define SPM_PCM_SW_INT_CLEAR			(SPM_BASE + 0x3e4)
+#define SPM_CLK_CON				(SPM_BASE + 0x400)
+#define SPM_SLEEP_PTPOD2_CON			(SPM_BASE + 0x408)
+#define SPM_APMCU_PWRCTL			(SPM_BASE + 0x600)
+#define SPM_AP_DVFS_CON_SET			(SPM_BASE + 0x604)
+#define SPM_AP_STANBY_CON			(SPM_BASE + 0x608)
+#define SPM_PWR_STATUS				(SPM_BASE + 0x60c)
+#define SPM_PWR_STATUS_2ND			(SPM_BASE + 0x610)
+#define SPM_AP_BSI_REQ				(SPM_BASE + 0x614)
+#define SPM_SLEEP_TIMER_STA			(SPM_BASE + 0x720)
+#define SPM_SLEEP_WAKEUP_EVENT_MASK		(SPM_BASE + 0x810)
+#define SPM_SLEEP_CPU_WAKEUP_EVENT		(SPM_BASE + 0x814)
+#define SPM_SLEEP_MD32_WAKEUP_EVENT_MASK	(SPM_BASE + 0x818)
+#define SPM_PCM_WDT_TIMER_VAL			(SPM_BASE + 0x824)
+#define SPM_PCM_WDT_TIMER_OUT			(SPM_BASE + 0x828)
+#define SPM_PCM_MD32_MAILBOX			(SPM_BASE + 0x830)
+#define SPM_PCM_MD32_IRQ			(SPM_BASE + 0x834)
+#define SPM_SLEEP_ISR_MASK			(SPM_BASE + 0x900)
+#define SPM_SLEEP_ISR_STATUS			(SPM_BASE + 0x904)
+#define SPM_SLEEP_ISR_RAW_STA			(SPM_BASE + 0x910)
+#define SPM_SLEEP_MD32_ISR_RAW_STA		(SPM_BASE + 0x914)
+#define SPM_SLEEP_WAKEUP_MISC			(SPM_BASE + 0x918)
+#define SPM_SLEEP_BUS_PROTECT_RDY		(SPM_BASE + 0x91c)
+#define SPM_SLEEP_SUBSYS_IDLE_STA		(SPM_BASE + 0x920)
+#define SPM_PCM_RESERVE				(SPM_BASE + 0xb00)
+#define SPM_PCM_RESERVE2			(SPM_BASE + 0xb04)
+#define SPM_PCM_FLAGS				(SPM_BASE + 0xb08)
+#define SPM_PCM_SRC_REQ				(SPM_BASE + 0xb0c)
+#define SPM_PCM_DEBUG_CON			(SPM_BASE + 0xb20)
+#define SPM_CA7_CPU0_IRQ_MASK			(SPM_BASE + 0xb30)
+#define SPM_CA7_CPU1_IRQ_MASK			(SPM_BASE + 0xb34)
+#define SPM_CA7_CPU2_IRQ_MASK			(SPM_BASE + 0xb38)
+#define SPM_CA7_CPU3_IRQ_MASK			(SPM_BASE + 0xb3c)
+#define SPM_CA15_CPU0_IRQ_MASK			(SPM_BASE + 0xb40)
+#define SPM_CA15_CPU1_IRQ_MASK			(SPM_BASE + 0xb44)
+#define SPM_CA15_CPU2_IRQ_MASK			(SPM_BASE + 0xb48)
+#define SPM_CA15_CPU3_IRQ_MASK			(SPM_BASE + 0xb4c)
+#define SPM_PCM_PASR_DPD_0			(SPM_BASE + 0xb60)
+#define SPM_PCM_PASR_DPD_1			(SPM_BASE + 0xb64)
+#define SPM_PCM_PASR_DPD_2			(SPM_BASE + 0xb68)
+#define SPM_PCM_PASR_DPD_3			(SPM_BASE + 0xb6c)
+#define SPM_SLEEP_CA7_WFI0_EN			(SPM_BASE + 0xf00)
+#define SPM_SLEEP_CA7_WFI1_EN			(SPM_BASE + 0xf04)
+#define SPM_SLEEP_CA7_WFI2_EN			(SPM_BASE + 0xf08)
+#define SPM_SLEEP_CA7_WFI3_EN			(SPM_BASE + 0xf0c)
+#define SPM_SLEEP_CA15_WFI0_EN			(SPM_BASE + 0xf10)
+#define SPM_SLEEP_CA15_WFI1_EN			(SPM_BASE + 0xf14)
+#define SPM_SLEEP_CA15_WFI2_EN			(SPM_BASE + 0xf18)
+#define SPM_SLEEP_CA15_WFI3_EN			(SPM_BASE + 0xf1c)
+
+#define AP_PLL_CON3		0x1020900c
+#define AP_PLL_CON4		0x10209010
+
+#define SPM_PROJECT_CODE	0xb16
+
+#define SPM_REGWR_EN		(1U << 0)
+#define SPM_REGWR_CFG_KEY	(SPM_PROJECT_CODE << 16)
+
+#define SPM_CPU_PDN_DIS		(1U << 0)
+#define SPM_INFRA_PDN_DIS	(1U << 1)
+#define SPM_DDRPHY_PDN_DIS	(1U << 2)
+#define SPM_DUALVCORE_PDN_DIS	(1U << 3)
+#define SPM_PASR_DIS		(1U << 4)
+#define SPM_DPD_DIS		(1U << 5)
+#define SPM_SODI_DIS		(1U << 6)
+#define SPM_MEMPLL_RESET	(1U << 7)
+#define SPM_MAINPLL_PDN_DIS	(1U << 8)
+#define SPM_CPU_DVS_DIS		(1U << 9)
+#define SPM_CPU_DORMANT		(1U << 10)
+#define SPM_EXT_VSEL_GPIO103	(1U << 11)
+#define SPM_DDR_HIGH_SPEED	(1U << 12)
+#define SPM_OPT			(1U << 13)
+
+#define POWER_ON_VAL1_DEF	0x01011820
+#define PCM_FSM_STA_DEF		0x48490
+#define PCM_END_FSM_STA_DEF	0x08490
+#define PCM_END_FSM_STA_MASK	0x3fff0
+#define PCM_HANDSHAKE_SEND1	0xbeefbeef
+
+#define PCM_WDT_TIMEOUT		(30 * 32768)
+#define PCM_TIMER_MAX		(0xffffffff - PCM_WDT_TIMEOUT)
+
+#define CON0_PCM_KICK		(1U << 0)
+#define CON0_IM_KICK		(1U << 1)
+#define CON0_IM_SLEEP_DVS	(1U << 3)
+#define CON0_PCM_SW_RESET	(1U << 15)
+#define CON0_CFG_KEY		(SPM_PROJECT_CODE << 16)
+
+#define CON1_IM_SLAVE		(1U << 0)
+#define CON1_MIF_APBEN		(1U << 3)
+#define CON1_PCM_TIMER_EN	(1U << 5)
+#define CON1_IM_NONRP_EN	(1U << 6)
+#define CON1_PCM_WDT_EN		(1U << 8)
+#define CON1_PCM_WDT_WAKE_MODE	(1U << 9)
+#define CON1_SPM_SRAM_SLP_B	(1U << 10)
+#define CON1_SPM_SRAM_ISO_B	(1U << 11)
+#define CON1_EVENT_LOCK_EN	(1U << 12)
+#define CON1_CFG_KEY		(SPM_PROJECT_CODE << 16)
+
+#define PCM_PWRIO_EN_R0		(1U << 0)
+#define PCM_PWRIO_EN_R7		(1U << 7)
+#define PCM_RF_SYNC_R0		(1U << 16)
+#define PCM_RF_SYNC_R2		(1U << 18)
+#define PCM_RF_SYNC_R6		(1U << 22)
+#define PCM_RF_SYNC_R7		(1U << 23)
+
+#define CC_SYSCLK0_EN_0		(1U << 0)
+#define CC_SYSCLK0_EN_1		(1U << 1)
+#define CC_SYSCLK1_EN_0		(1U << 2)
+#define CC_SYSCLK1_EN_1		(1U << 3)
+#define CC_SYSSETTLE_SEL	(1U << 4)
+#define CC_LOCK_INFRA_DCM	(1U << 5)
+#define CC_SRCLKENA_MASK_0	(1U << 6)
+#define CC_CXO32K_RM_EN_MD1	(1U << 9)
+#define CC_CXO32K_RM_EN_MD2	(1U << 10)
+#define CC_CLKSQ1_SEL		(1U << 12)
+#define CC_DISABLE_DORM_PWR	(1U << 14)
+#define CC_MD32_DCM_EN		(1U << 18)
+
+#define WFI_OP_AND		1
+#define WFI_OP_OR		0
+
+#define WAKE_MISC_PCM_TIMER	(1U << 19)
+#define WAKE_MISC_CPU_WAKE	(1U << 20)
+
+/* define WAKE_SRC_XXX */
+#define WAKE_SRC_SPM_MERGE	(1 << 0)
+#define WAKE_SRC_KP		(1 << 2)
+#define WAKE_SRC_WDT		(1 << 3)
+#define WAKE_SRC_GPT		(1 << 4)
+#define WAKE_SRC_EINT		(1 << 6)
+#define WAKE_SRC_LOW_BAT	(1 << 9)
+#define WAKE_SRC_MD32		(1 << 10)
+#define WAKE_SRC_USB_CD		(1 << 14)
+#define WAKE_SRC_USB_PDN	(1 << 15)
+#define WAKE_SRC_AFE		(1 << 20)
+#define WAKE_SRC_THERM		(1 << 21)
+#define WAKE_SRC_CIRQ		(1 << 22)
+#define WAKE_SRC_SYSPWREQ	(1 << 24)
+#define WAKE_SRC_SEJ		(1 << 27)
+#define WAKE_SRC_ALL_MD32	(1 << 28)
+#define WAKE_SRC_CPU_IRQ	(1 << 29)
+
+enum wake_reason_t {
+	WR_NONE = 0,
+	WR_UART_BUSY = 1,
+	WR_PCM_ASSERT = 2,
+	WR_PCM_TIMER = 3,
+	WR_PCM_ABORT = 4,
+	WR_WAKE_SRC = 5,
+	WR_UNKNOWN = 6,
+};
+
+struct pwr_ctrl {
+	unsigned int pcm_flags;
+	unsigned int pcm_flags_cust;
+	unsigned int pcm_reserve;
+	unsigned int timer_val;
+	unsigned int timer_val_cust;
+	unsigned int wake_src;
+	unsigned int wake_src_cust;
+	unsigned int wake_src_md32;
+	unsigned short r0_ctrl_en;
+	unsigned short r7_ctrl_en;
+	unsigned short infra_dcm_lock;
+	unsigned short pcm_apsrc_req;
+	unsigned short mcusys_idle_mask;
+	unsigned short ca15top_idle_mask;
+	unsigned short ca7top_idle_mask;
+	unsigned short wfi_op;
+	unsigned short ca15_wfi0_en;
+	unsigned short ca15_wfi1_en;
+	unsigned short ca15_wfi2_en;
+	unsigned short ca15_wfi3_en;
+	unsigned short ca7_wfi0_en;
+	unsigned short ca7_wfi1_en;
+	unsigned short ca7_wfi2_en;
+	unsigned short ca7_wfi3_en;
+	unsigned short disp_req_mask;
+	unsigned short mfg_req_mask;
+	unsigned short md32_req_mask;
+	unsigned short syspwreq_mask;
+	unsigned short srclkenai_mask;
+};
+
+struct wake_status {
+	unsigned int assert_pc;
+	unsigned int r12;
+	unsigned int raw_sta;
+	unsigned int wake_misc;
+	unsigned int timer_out;
+	unsigned int r13;
+	unsigned int idle_sta;
+	unsigned int debug_flag;
+	unsigned int event_reg;
+	unsigned int isr;
+};
+
+struct pcm_desc {
+	const char *version;		/* PCM code version */
+	const unsigned int *base;	/* binary array base */
+	const unsigned int size;	/* binary array size */
+	const unsigned char sess;	/* session number */
+	const unsigned char replace;	/* replace mode */
+
+	unsigned int vec0;		/* event vector 0 config */
+	unsigned int vec1;		/* event vector 1 config */
+	unsigned int vec2;		/* event vector 2 config */
+	unsigned int vec3;		/* event vector 3 config */
+	unsigned int vec4;		/* event vector 4 config */
+	unsigned int vec5;		/* event vector 5 config */
+	unsigned int vec6;		/* event vector 6 config */
+	unsigned int vec7;		/* event vector 7 config */
+};
+
+struct spm_lp_scen {
+	const struct pcm_desc *pcmdesc;
+	struct pwr_ctrl *pwrctrl;
+};
+
+#define EVENT_VEC(event, resume, imme, pc)	\
+	(((pc) << 16) |				\
+	 (!!(imme) << 6) |			\
+	 (!!(resume) << 5) |			\
+	 ((event) & 0x1f))
+
+#define spm_read(addr)		mmio_read_32(addr)
+#define spm_write(addr, val)	mmio_write_32(addr, val)
+
+#define is_cpu_pdn(flags)	(!((flags) & SPM_CPU_PDN_DIS))
+#define is_infra_pdn(flags)	(!((flags) & SPM_INFRA_PDN_DIS))
+#define is_ddrphy_pdn(flags)	(!((flags) & SPM_DDRPHY_PDN_DIS))
+
+static inline void set_pwrctrl_pcm_flags(struct pwr_ctrl *pwrctrl,
+					 unsigned int flags)
+{
+	flags &= ~SPM_EXT_VSEL_GPIO103;
+
+	if (pwrctrl->pcm_flags_cust == 0)
+		pwrctrl->pcm_flags = flags;
+	else
+		pwrctrl->pcm_flags = pwrctrl->pcm_flags_cust;
+}
+
+static inline void set_pwrctrl_pcm_data(struct pwr_ctrl *pwrctrl,
+					unsigned int data)
+{
+	pwrctrl->pcm_reserve = data;
+}
+
+void spm_reset_and_init_pcm(void);
+
+void spm_init_pcm_register(void);	/* init r0 and r7 */
+void spm_set_power_control(const struct pwr_ctrl *pwrctrl);
+void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl);
+
+void spm_get_wakeup_status(struct wake_status *wakesta);
+void spm_set_sysclk_settle(void);
+void spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl);
+void spm_clean_after_wakeup(void);
+enum wake_reason_t spm_output_wake_reason(struct wake_status *wakesta);
+void spm_register_init(void);
+void spm_go_to_hotplug(void);
+void spm_init_event_vector(const struct pcm_desc *pcmdesc);
+void spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc);
+void spm_set_sysclk_settle(void);
+int is_mcdi_ready(void);
+int is_hotplug_ready(void);
+int is_suspend_ready(void);
+void set_mcdi_ready(void);
+void set_hotplug_ready(void);
+void set_suspend_ready(void);
+void clear_all_ready(void);
+void spm_lock_init(void);
+void spm_lock_get(void);
+void spm_lock_release(void);
+void spm_boot_init(void);
+
+#endif /* SPM_H */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c
new file mode 100644
index 0000000..b2b9ada
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/mmio.h>
+#include <mt8173_def.h>
+#include <plat/common/platform.h>
+
+#include <spm.h>
+#include <spm_hotplug.h>
+#include <spm_mcdi.h>
+
+/*
+ * System Power Manager (SPM) is a hardware module, which controls cpu or
+ * system power for different power scenarios using different firmware.
+ * This driver controls the cpu power in cpu hotplug flow.
+ */
+
+#define PCM_HOTPLUG_VALID_MASK	0x0000ff00
+#define PCM_HOTPLUG_VALID_SHIFT	0x8
+
+/**********************************************************
+ * PCM sequence for CPU hotplug
+ **********************************************************/
+static const unsigned int hotplug_binary[] = {
+	0x1900001f, 0x1020020c, 0x1950001f, 0x1020020c, 0xa9400005, 0x00000001,
+	0xe1000005, 0x1910001f, 0x10006720, 0x814c9001, 0xd82000e5, 0x17c07c1f,
+	0x1900001f, 0x10001220, 0x1950001f, 0x10001220, 0xa15f0405, 0xe1000005,
+	0x1900001f, 0x10001228, 0x1950001f, 0x10001228, 0x810f1401, 0xd8200244,
+	0x17c07c1f, 0xe2e0006d, 0xe2e0002d, 0x1a00001f, 0x100062b8, 0x1910001f,
+	0x100062b8, 0xa9000004, 0x00000001, 0xe2000004, 0x1910001f, 0x100062b8,
+	0x81142804, 0xd8200444, 0x17c07c1f, 0xe2e0002c, 0xe2e0003c, 0xe2e0003e,
+	0xe2e0003a, 0xe2e00032, 0x1910001f, 0x1000660c, 0x81079001, 0x1950001f,
+	0x10006610, 0x81479401, 0xa1001404, 0xd8000584, 0x17c07c1f, 0x1900001f,
+	0x10006404, 0x1950001f, 0x10006404, 0xa1568405, 0xe1000005, 0xf0000000,
+	0x17c07c1f, 0x1900001f, 0x10006404, 0x1950001f, 0x10006404, 0x89400005,
+	0x0000dfff, 0xe1000005, 0xe2e00036, 0xe2e0003e, 0x1910001f, 0x1000660c,
+	0x81079001, 0x1950001f, 0x10006610, 0x81479401, 0x81001404, 0xd82008c4,
+	0x17c07c1f, 0xe2e0002e, 0x1a00001f, 0x100062b8, 0x1910001f, 0x100062b8,
+	0x89000004, 0x0000fffe, 0xe2000004, 0x1910001f, 0x100062b8, 0x81142804,
+	0xd8000ae4, 0x17c07c1f, 0xe2e0006e, 0xe2e0004e, 0xe2e0004c, 0xe2e0004d,
+	0x1900001f, 0x10001220, 0x1950001f, 0x10001220, 0x89400005, 0xbfffffff,
+	0xe1000005, 0x1900001f, 0x10001228, 0x1950001f, 0x10001228, 0x810f1401,
+	0xd8000ce4, 0x17c07c1f, 0x1900001f, 0x1020020c, 0x1950001f, 0x1020020c,
+	0x89400005, 0xfffffffe, 0xe1000005, 0xf0000000, 0x17c07c1f, 0x1212841f,
+	0xe2e00036, 0xe2e0003e, 0x1380201f, 0xe2e0003c, 0xe2a00000, 0x1b80001f,
+	0x20000080, 0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c,
+	0xe2e0004d, 0xf0000000, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f,
+	0xe2a00001, 0x1b80001f, 0x20000080, 0xe2e0002e, 0xe2e0003e, 0xe2e00032,
+	0xf0000000, 0x17c07c1f, 0x1212841f, 0xe2e00026, 0xe2e0002e, 0x1380201f,
+	0x1a00001f, 0x100062b4, 0x1910001f, 0x100062b4, 0x81322804, 0xe2000004,
+	0x81202804, 0xe2000004, 0x1b80001f, 0x20000034, 0x1910001f, 0x100062b4,
+	0x81142804, 0xd8001404, 0x17c07c1f, 0xe2e0000e, 0xe2e0000c, 0xe2e0000d,
+	0xf0000000, 0x17c07c1f, 0xe2e0002d, 0x1a00001f, 0x100062b4, 0x1910001f,
+	0x100062b4, 0xa1002804, 0xe2000004, 0xa1122804, 0xe2000004, 0x1b80001f,
+	0x20000080, 0x1910001f, 0x100062b4, 0x81142804, 0xd82016a4, 0x17c07c1f,
+	0xe2e0002f, 0xe2e0002b, 0xe2e00023, 0x1380201f, 0xe2e00022, 0xf0000000,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001, 0x1840001f, 0x00000001,
+	0x1840001f, 0x00000001, 0xa1d48407, 0x1b00001f, 0x2f7be75f, 0xe8208000,
+	0x10006354, 0xfffe7b47, 0xa1d10407, 0x1b80001f, 0x20000020, 0x17c07c1f,
+	0x1910001f, 0x10006b00, 0x81461001, 0xb14690a1, 0xd82044e5, 0x17c07c1f,
+	0x1910001f, 0x10006610, 0x81079001, 0xd80044e4, 0x17c07c1f, 0x1990001f,
+	0x10006b00, 0x81421801, 0x82429801, 0x81402405, 0xd80044e5, 0x17c07c1f,
+	0x1a40001f, 0x100062b0, 0x1280041f, 0xc24007a0, 0x17c07c1f, 0x1910001f,
+	0x10006b00, 0x81449001, 0xd8204be5, 0x17c07c1f, 0x1910001f, 0x10006b00,
+	0x81009001, 0xd8204984, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81051001,
+	0xd8204be4, 0x17c07c1f, 0x1910001f, 0x10006720, 0x81489001, 0xd82046c5,
+	0x17c07c1f, 0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc24010e0,
+	0x17c07c1f, 0x1910001f, 0x1000660c, 0x81051001, 0x1950001f, 0x10006610,
+	0x81451401, 0xa1001404, 0xd8004824, 0x17c07c1f, 0xd0004b00, 0x17c07c1f,
+	0x17c07c1f, 0x1910001f, 0x10006610, 0x81051001, 0xd8004be4, 0x17c07c1f,
+	0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc2400ee0, 0x17c07c1f,
+	0x1910001f, 0x10006b00, 0x89000004, 0xfffffdff, 0x1940001f, 0x10006b00,
+	0xe1400004, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81451001, 0xd8205305,
+	0x17c07c1f, 0x1910001f, 0x10006b00, 0x81011001, 0xd82050a4, 0x17c07c1f,
+	0x1910001f, 0x10006610, 0x81059001, 0xd8205304, 0x17c07c1f, 0x1910001f,
+	0x10006720, 0x81491001, 0xd8204de5, 0x17c07c1f, 0x1a40001f, 0x1000621c,
+	0x1a80001f, 0x1000626c, 0xc24010e0, 0x17c07c1f, 0x1910001f, 0x1000660c,
+	0x81059001, 0x1950001f, 0x10006610, 0x81459401, 0xa1001404, 0xd8004f44,
+	0x17c07c1f, 0xd0005220, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610,
+	0x81059001, 0xd8005304, 0x17c07c1f, 0x1a40001f, 0x1000621c, 0x1a80001f,
+	0x1000626c, 0xc2400ee0, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x89000004,
+	0xfffffbff, 0x1940001f, 0x10006b00, 0xe1400004, 0x17c07c1f, 0x1910001f,
+	0x10006b00, 0x81459001, 0xd8205a25, 0x17c07c1f, 0x1910001f, 0x10006b00,
+	0x81019001, 0xd82057c4, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81061001,
+	0xd8205a24, 0x17c07c1f, 0x1910001f, 0x10006720, 0x81499001, 0xd8205505,
+	0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274, 0xc24010e0,
+	0x17c07c1f, 0x1910001f, 0x1000660c, 0x81061001, 0x1950001f, 0x10006610,
+	0x81461401, 0xa1001404, 0xd8005664, 0x17c07c1f, 0xd0005940, 0x17c07c1f,
+	0x17c07c1f, 0x1910001f, 0x10006610, 0x81061001, 0xd8005a24, 0x17c07c1f,
+	0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274, 0xc2400ee0, 0x17c07c1f,
+	0x1910001f, 0x10006b00, 0x89000004, 0xfffff7ff, 0x1940001f, 0x10006b00,
+	0xe1400004, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81461001, 0xd8206185,
+	0x17c07c1f, 0x1910001f, 0x10006b00, 0x81021001, 0xd8205ec4, 0x17c07c1f,
+	0x1910001f, 0x10006610, 0x81081001, 0xd8206184, 0x17c07c1f, 0x1910001f,
+	0x10006720, 0x814a1001, 0xd8205c25, 0x17c07c1f, 0x1a40001f, 0x100062a0,
+	0x1280041f, 0xc2401540, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81081001,
+	0x1950001f, 0x10006610, 0x81481401, 0xa1001404, 0xd8005d64, 0x17c07c1f,
+	0xd00060a0, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81479001,
+	0x81881001, 0x69a00006, 0x00000000, 0x81401805, 0xd8206185, 0x17c07c1f,
+	0x1a40001f, 0x100062a0, 0x1280041f, 0xc2401240, 0x17c07c1f, 0x1910001f,
+	0x10006b00, 0x89000004, 0xffffefff, 0x1940001f, 0x10006b00, 0xe1400004,
+	0x17c07c1f, 0x1910001f, 0x10006b00, 0x81469001, 0xd82068e5, 0x17c07c1f,
+	0x1910001f, 0x10006b00, 0x81029001, 0xd8206624, 0x17c07c1f, 0x1910001f,
+	0x10006610, 0x81089001, 0xd82068e4, 0x17c07c1f, 0x1910001f, 0x10006720,
+	0x814a9001, 0xd8206385, 0x17c07c1f, 0x1a40001f, 0x100062a4, 0x1290841f,
+	0xc2401540, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81089001, 0x1950001f,
+	0x10006610, 0x81489401, 0xa1001404, 0xd80064c4, 0x17c07c1f, 0xd0006800,
+	0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81479001, 0x81889001,
+	0x69a00006, 0x00000000, 0x81401805, 0xd82068e5, 0x17c07c1f, 0x1a40001f,
+	0x100062a4, 0x1290841f, 0xc2401240, 0x17c07c1f, 0x1910001f, 0x10006b00,
+	0x89000004, 0xffffdfff, 0x1940001f, 0x10006b00, 0xe1400004, 0x1910001f,
+	0x10006610, 0x81479001, 0x81881001, 0x69600005, 0x00000000, 0xa1401805,
+	0x81889001, 0xa1401805, 0xd8006bc5, 0x17c07c1f, 0x1910001f, 0x10006b00,
+	0x81421001, 0x82429001, 0x82802405, 0xd8206bca, 0x17c07c1f, 0x1a40001f,
+	0x100062b0, 0x1280041f, 0xc2400000, 0x17c07c1f, 0x1990001f, 0x10006b00,
+	0x89800006, 0x00003f00, 0x69200006, 0x00000000, 0xd82041e4, 0x17c07c1f,
+	0x1990001f, 0x10006320, 0x69200006, 0xbeefbeef, 0xd8006dc4, 0x17c07c1f,
+	0xd00041e0, 0x17c07c1f, 0x1910001f, 0x10006358, 0x810b1001, 0xd8006dc4,
+	0x17c07c1f, 0x1980001f, 0xdeaddead, 0x19c0001f, 0x01411820, 0xf0000000
+};
+static const struct pcm_desc hotplug_pcm = {
+	.version	= "pcm_power_down_mt8173_V37",
+	.base		= hotplug_binary,
+	.size		= 888,
+	.sess		= 2,
+	.replace	= 0,
+};
+
+static struct pwr_ctrl hotplug_ctrl = {
+	.wake_src = 0,
+	.wake_src_md32 = 0,
+	.wfi_op = WFI_OP_OR,
+	.mcusys_idle_mask = 1,
+	.ca7top_idle_mask = 1,
+	.ca15top_idle_mask = 1,
+	.disp_req_mask = 1,
+	.mfg_req_mask = 1,
+	.md32_req_mask = 1,
+	.syspwreq_mask = 1,
+	.pcm_flags = 0,
+};
+
+static const struct spm_lp_scen spm_hotplug = {
+	.pcmdesc = &hotplug_pcm,
+	.pwrctrl = &hotplug_ctrl,
+};
+
+void spm_go_to_hotplug(void)
+{
+	const struct pcm_desc *pcmdesc = spm_hotplug.pcmdesc;
+	struct pwr_ctrl *pwrctrl = spm_hotplug.pwrctrl;
+
+	set_pwrctrl_pcm_flags(pwrctrl, 0);
+	spm_reset_and_init_pcm();
+	spm_kick_im_to_fetch(pcmdesc);
+	spm_set_power_control(pwrctrl);
+	spm_set_wakeup_event(pwrctrl);
+	spm_kick_pcm_to_run(pwrctrl);
+}
+
+void spm_clear_hotplug(void)
+{
+	/* Inform SPM that CPU wants to program CPU_WAKEUP_EVENT and
+	 * DISABLE_CPU_DROM */
+
+	mmio_write_32(SPM_PCM_REG_DATA_INI, PCM_HANDSHAKE_SEND1);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+
+	/* Wait SPM's response, can't use sleep api */
+	while ((mmio_read_32(SPM_PCM_FSM_STA) & PCM_END_FSM_STA_MASK)
+		!= PCM_END_FSM_STA_DEF)
+		;
+
+	/* no hotplug pcm running */
+	clear_all_ready();
+}
+
+void spm_hotplug_on(unsigned long mpidr)
+{
+	unsigned long linear_id;
+
+	linear_id = ((mpidr & MPIDR_CLUSTER_MASK) >> 6) |
+			(mpidr & MPIDR_CPU_MASK);
+
+	spm_lock_get();
+	if (is_hotplug_ready() == 0) {
+		spm_mcdi_wakeup_all_cores();
+		mmio_clrbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK);
+		spm_go_to_hotplug();
+		set_hotplug_ready();
+	}
+	/* turn on CPUx */
+	mmio_clrsetbits_32(SPM_PCM_RESERVE,
+		PCM_HOTPLUG_VALID_MASK | (1 << linear_id),
+		1 << (linear_id + PCM_HOTPLUG_VALID_SHIFT));
+	spm_lock_release();
+}
+
+void spm_hotplug_off(unsigned long mpidr)
+{
+	unsigned long linear_id;
+
+	linear_id = ((mpidr & MPIDR_CLUSTER_MASK) >> 6) |
+			(mpidr & MPIDR_CPU_MASK);
+
+	spm_lock_get();
+	if (is_hotplug_ready() == 0) {
+		spm_mcdi_wakeup_all_cores();
+		mmio_clrbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK);
+		spm_go_to_hotplug();
+		set_hotplug_ready();
+	}
+	mmio_clrsetbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK,
+		(1 << linear_id) |
+		(1 << (linear_id + PCM_HOTPLUG_VALID_SHIFT)));
+	spm_lock_release();
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h
new file mode 100644
index 0000000..00849a2
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SPM_HOTPLUG_H
+#define SPM_HOTPLUG_H
+
+void spm_clear_hotplug(void);
+void spm_hotplug_off(unsigned long mpidr);
+void spm_hotplug_on(unsigned long mpidr);
+
+#endif /* SPM_HOTPLUG_H */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c
new file mode 100644
index 0000000..ea5f2bb
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <mt8173_def.h>
+#include <spm.h>
+#include <spm_hotplug.h>
+#include <spm_mcdi.h>
+
+/*
+ * System Power Manager (SPM) is a hardware module, which controls cpu or
+ * system power for different power scenarios using different firmware.
+ * This driver controls the cpu power in cpu idle power saving state.
+ */
+
+#define WAKE_SRC_FOR_MCDI \
+	(WAKE_SRC_KP | WAKE_SRC_GPT | WAKE_SRC_EINT |		\
+	 WAKE_SRC_MD32 | WAKE_SRC_USB_CD | WAKE_SRC_USB_PDN |	\
+	 WAKE_SRC_AFE | WAKE_SRC_THERM | WAKE_SRC_CIRQ |	\
+	 WAKE_SRC_SYSPWREQ | WAKE_SRC_CPU_IRQ)
+#define PCM_MCDI_HANDSHAKE_SYNC	0xbeefbeef
+#define PCM_MCDI_HANDSHAKE_ACK	0xdeaddead
+#define PCM_MCDI_UPDATE_INFORM	0xabcdabcd
+#define PCM_MCDI_CKECK_DONE	0x12345678
+#define PCM_MCDI_ALL_CORE_AWAKE	0x0
+#define PCM_MCDI_OFFLOADED	0xaa55aa55
+#define PCM_MCDI_CA72_CPUTOP_PWRCTL	(0x1 << 16)
+#define PCM_MCDI_CA53_CPUTOP_PWRCTL	(0x1 << 17)
+#define PCM_MCDI_CA72_PWRSTA_SHIFT	16
+#define PCM_MCDI_CA53_PWRSTA_SHIFT	9
+
+static const unsigned int mcdi_binary[] = {
+	0x1a10001f, 0x10006b04, 0x1890001f, 0x10006b6c, 0x1a40001f, 0x10006210,
+	0x18d0001f, 0x10006210, 0x81002001, 0xd82001c4, 0x17c07c1f, 0xa0900402,
+	0xc2401540, 0x17c07c1f, 0x81052001, 0xd8200284, 0x17c07c1f, 0xa0950402,
+	0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x10006230, 0x18d0001f, 0x10006230,
+	0x8100a001, 0xd82003c4, 0x17c07c1f, 0xa0908402, 0xc2401540, 0x17c07c1f,
+	0x8105a001, 0xd8200484, 0x17c07c1f, 0xa0958402, 0xc2401b80, 0x17c07c1f,
+	0x1a40001f, 0x10006238, 0x18d0001f, 0x10006238, 0x81012001, 0xd82005c4,
+	0x17c07c1f, 0xa0910402, 0xc2401540, 0x17c07c1f, 0x81062001, 0xd8200684,
+	0x17c07c1f, 0xa0960402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x1000623c,
+	0x18d0001f, 0x1000623c, 0x8101a001, 0xd82007c4, 0x17c07c1f, 0xa0918402,
+	0xc2401540, 0x17c07c1f, 0x8106a001, 0xd8200884, 0x17c07c1f, 0xa0968402,
+	0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x10006298, 0x18d0001f, 0x10006298,
+	0x81022001, 0xd82009c4, 0x17c07c1f, 0xa0920402, 0xc2401540, 0x17c07c1f,
+	0x81072001, 0xd8200a84, 0x17c07c1f, 0xa0970402, 0xc2401b80, 0x17c07c1f,
+	0x1a40001f, 0x1000629c, 0x18d0001f, 0x1000629c, 0x8102a001, 0xd8200bc4,
+	0x17c07c1f, 0xa0928402, 0xc2401540, 0x17c07c1f, 0x8107a001, 0xd8200c84,
+	0x17c07c1f, 0xa0978402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x100062c4,
+	0x18d0001f, 0x100062c4, 0x81032001, 0xd8200dc4, 0x17c07c1f, 0xa0930402,
+	0xc2401540, 0x17c07c1f, 0x81082001, 0xd8200e84, 0x17c07c1f, 0xa0980402,
+	0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x100062c0, 0x18d0001f, 0x100062c0,
+	0x8103a001, 0xd8200fc4, 0x17c07c1f, 0xa0938402, 0xc2401540, 0x17c07c1f,
+	0x8108a001, 0xd8201084, 0x17c07c1f, 0xa0988402, 0xc2401b80, 0x17c07c1f,
+	0x1a40001f, 0x10006214, 0x18d0001f, 0x10006214, 0x81042001, 0xd82011c4,
+	0x17c07c1f, 0xa0940402, 0xc2401540, 0x17c07c1f, 0x81092001, 0xd8201284,
+	0x17c07c1f, 0xa0990402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x100062cc,
+	0x18d0001f, 0x100062cc, 0x8104a001, 0xd82013c4, 0x17c07c1f, 0xa0948402,
+	0xc2401540, 0x17c07c1f, 0x8109a001, 0xd8201484, 0x17c07c1f, 0xa0998402,
+	0xc2401b80, 0x17c07c1f, 0x1900001f, 0x10006b6c, 0x80802002, 0xe1000002,
+	0xf0000000, 0x17c07c1f, 0xa8c00003, 0x00000004, 0xe2400003, 0xa8c00003,
+	0x00000008, 0xe2400003, 0x1b80001f, 0x00000020, 0x88c00003, 0xffffffef,
+	0xe2400003, 0x88c00003, 0xfffffffd, 0xe2400003, 0xa8c00003, 0x00000001,
+	0xe2400003, 0x88c00003, 0xfffff0ff, 0xe2400003, 0x1b80001f, 0x20000080,
+	0x1a90001f, 0x10001220, 0x69200009, 0x1000623c, 0xd8001984, 0x17c07c1f,
+	0x69200009, 0x10006214, 0xd8001a64, 0x17c07c1f, 0xd0001b00, 0x17c07c1f,
+	0x1900001f, 0x10001220, 0x8a80000a, 0xfffffff9, 0xe100000a, 0xd0001b00,
+	0x17c07c1f, 0x1900001f, 0x10001220, 0x8a80000a, 0xff1fbfff, 0xe100000a,
+	0x1b80001f, 0x20000080, 0xf0000000, 0x17c07c1f, 0x1a90001f, 0x10001220,
+	0x69200009, 0x1000623c, 0xd8001d04, 0x17c07c1f, 0x69200009, 0x10006214,
+	0xd8001de4, 0x17c07c1f, 0xd0001e80, 0x17c07c1f, 0x1900001f, 0x10001220,
+	0xaa80000a, 0x00000006, 0xe100000a, 0xd0001e80, 0x17c07c1f, 0x1900001f,
+	0x10001220, 0xaa80000a, 0x00e04000, 0xe100000a, 0x1b80001f, 0x20000080,
+	0x69200009, 0x10006214, 0xd8001fe4, 0x17c07c1f, 0xa8c00003, 0x00000f00,
+	0xe2400003, 0xd0002040, 0x17c07c1f, 0xa8c00003, 0x00003f00, 0xe2400003,
+	0x1b80001f, 0x20000080, 0xa8c00003, 0x00000002, 0xe2400003, 0x88c00003,
+	0xfffffffe, 0xe2400003, 0xa8c00003, 0x00000010, 0xe2400003, 0x88c00003,
+	0xfffffffb, 0xe2400003, 0x88c00003, 0xfffffff7, 0xe2400003, 0xf0000000,
+	0x17c07c1f, 0xe2e00036, 0xe2e0003e, 0x1b80001f, 0x00000020, 0xe2e0003c,
+	0xe8208000, 0x10006244, 0x00000000, 0x1b80001f, 0x20000080, 0xe2e0007c,
+	0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d, 0xf0000000,
+	0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f, 0xe8208000, 0x10006244,
+	0x00000001, 0x1b80001f, 0x20000080, 0xe2e0002e, 0xe2e0003e, 0xe2e0003a,
+	0xe2e00032, 0x1b80001f, 0x00000020, 0xf0000000, 0x17c07c1f, 0xe2e00036,
+	0xe2e0003e, 0x1b80001f, 0x00000020, 0xe2e0003c, 0xe2a00000, 0x1b80001f,
+	0x20000080, 0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c,
+	0xe2e0004d, 0xf0000000, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f,
+	0xe2a00001, 0x1b80001f, 0x20000080, 0xe2e0002e, 0xe2e0003e, 0xe2e0003a,
+	0xe2e00032, 0xf0000000, 0x17c07c1f, 0xe2e00026, 0xe2e0002e, 0x1b80001f,
+	0x00000020, 0x1a00001f, 0x100062b4, 0x1910001f, 0x100062b4, 0x81322804,
+	0xe2000004, 0x81202804, 0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0000e,
+	0xe2e0000c, 0xe2e0000d, 0xf0000000, 0x17c07c1f, 0xe2e0002d, 0x1a00001f,
+	0x100062b4, 0x1910001f, 0x100062b4, 0xa1002804, 0xe2000004, 0xa1122804,
+	0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0002f, 0xe2e0002b, 0xe2e00023,
+	0x1b80001f, 0x00000020, 0xe2e00022, 0xf0000000, 0x17c07c1f, 0x1910001f,
+	0x1000660c, 0x1a10001f, 0x10006610, 0xa2002004, 0x89000008, 0x00030000,
+	0xd80036c4, 0x17c07c1f, 0x8207a001, 0xd82036c8, 0x17c07c1f, 0x1900001f,
+	0x1020020c, 0x1a10001f, 0x1020020c, 0xaa000008, 0x00000001, 0xe1000008,
+	0x1910001f, 0x1020020c, 0x81001001, 0xd8203184, 0x17c07c1f, 0x1910001f,
+	0x10006720, 0x820c9001, 0xd8203228, 0x17c07c1f, 0x1900001f, 0x10001220,
+	0x1a10001f, 0x10001220, 0xa21f0408, 0xe1000008, 0x1b80001f, 0x20000080,
+	0xe2e0006d, 0xe2e0002d, 0x1a00001f, 0x100062b8, 0x1910001f, 0x100062b8,
+	0xa9000004, 0x00000001, 0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0002c,
+	0xe2e0003c, 0xe2e0003e, 0xe2e0003a, 0xe2e00032, 0x1b80001f, 0x00000020,
+	0x1900001f, 0x10006404, 0x1a10001f, 0x10006404, 0xa2168408, 0xe1000008,
+	0xf0000000, 0x17c07c1f, 0x1a10001f, 0x10006610, 0x8207a001, 0xd8003e68,
+	0x17c07c1f, 0x1a10001f, 0x10006918, 0x8a000008, 0x00003030, 0xb900010c,
+	0x01000001, 0xd8203e64, 0x17c07c1f, 0x1900001f, 0x10006404, 0x1a10001f,
+	0x10006404, 0x8a000008, 0x0000dfff, 0xe1000008, 0xe2e00036, 0xe2e0003e,
+	0x1b80001f, 0x00000020, 0xe2e0002e, 0x1a00001f, 0x100062b8, 0x1910001f,
+	0x100062b8, 0x89000004, 0x0000fffe, 0xe2000004, 0x1b80001f, 0x20000080,
+	0xe2e0006e, 0xe2e0004e, 0xe2e0004c, 0xe2e0004d, 0x1900001f, 0x10001220,
+	0x1a10001f, 0x10001220, 0x8a000008, 0xbfffffff, 0xe1000008, 0x1b80001f,
+	0x20000080, 0x1900001f, 0x1020020c, 0x1a10001f, 0x1020020c, 0x8a000008,
+	0xfffffffe, 0xe1000008, 0x1910001f, 0x1020020c, 0x81001001, 0xd8003dc4,
+	0x17c07c1f, 0xf0000000, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001, 0x11407c1f, 0xe8208000,
+	0x10006310, 0x0b160008, 0x1900001f, 0x000f7bde, 0x1a00001f, 0x10200268,
+	0xe2000004, 0xe8208000, 0x10006600, 0x00000000, 0x69200006, 0xbeefbeef,
+	0xd8204584, 0x17c07c1f, 0x1910001f, 0x10006358, 0x810b1001, 0xd8004244,
+	0x17c07c1f, 0x1980001f, 0xdeaddead, 0x69200006, 0xabcdabcd, 0xd8204324,
+	0x17c07c1f, 0x88900001, 0x10006814, 0x1910001f, 0x10006400, 0x81271002,
+	0x1880001f, 0x10006600, 0xe0800004, 0x1910001f, 0x10006358, 0x810b1001,
+	0xd80044a4, 0x17c07c1f, 0x1980001f, 0x12345678, 0x60a07c05, 0x89100002,
+	0x10006600, 0x80801001, 0xd8007bc2, 0x17c07c1f, 0x1890001f, 0x10006b00,
+	0x82090801, 0xc8800008, 0x17c07c1f, 0x1b00001f, 0x3fffe7ff, 0x8a00000c,
+	0x3fffe7ff, 0xd82041c8, 0x17c07c1f, 0x1b80001f, 0xd0010000, 0x1a10001f,
+	0x10006720, 0x82002001, 0x82201408, 0xd8204988, 0x17c07c1f, 0x1a40001f,
+	0x10006200, 0x1a80001f, 0x1000625c, 0xc24028e0, 0x17c07c1f, 0xa1400405,
+	0x1a10001f, 0x10006720, 0x8200a001, 0x82209408, 0xd8204b28, 0x17c07c1f,
+	0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc24028e0, 0x17c07c1f,
+	0xa1508405, 0x1a10001f, 0x10006720, 0x82012001, 0x82211408, 0xd8204cc8,
+	0x17c07c1f, 0x1a40001f, 0x1000621c, 0x1a80001f, 0x1000626c, 0xc24028e0,
+	0x17c07c1f, 0xa1510405, 0x1a10001f, 0x10006720, 0x8201a001, 0x82219408,
+	0xd8204e68, 0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274,
+	0xc24028e0, 0x17c07c1f, 0xa1518405, 0x1a10001f, 0x10006720, 0x82022001,
+	0x82221408, 0xd8204fe8, 0x17c07c1f, 0x1a40001f, 0x100062a0, 0x1280041f,
+	0xc2402cc0, 0x17c07c1f, 0xa1520405, 0x1a10001f, 0x10006720, 0x8202a001,
+	0x82229408, 0xd8205168, 0x17c07c1f, 0x1a40001f, 0x100062a4, 0x1290841f,
+	0xc2402cc0, 0x17c07c1f, 0xa1528405, 0x1a10001f, 0x10006720, 0x82032001,
+	0x82231408, 0xd8205248, 0x17c07c1f, 0xa1530405, 0x1a10001f, 0x10006720,
+	0x8203a001, 0x82239408, 0xd8205328, 0x17c07c1f, 0xa1538405, 0x1a10001f,
+	0x10006b00, 0x8108a001, 0xd8205e84, 0x17c07c1f, 0x1910001f, 0x1000660c,
+	0x1a10001f, 0x10006610, 0xa2002004, 0x89000008, 0x00001e00, 0xd8005944,
+	0x17c07c1f, 0x82042001, 0xd8205948, 0x17c07c1f, 0x1900001f, 0x1020002c,
+	0x1a10001f, 0x1020002c, 0xaa000008, 0x00000010, 0xe1000008, 0x1910001f,
+	0x10006720, 0x820c1001, 0xd8205628, 0x17c07c1f, 0x1900001f, 0x10001250,
+	0x1a10001f, 0x10001250, 0xa2110408, 0xe1000008, 0x1b80001f, 0x20000080,
+	0x1900001f, 0x10001220, 0x1a10001f, 0x10001220, 0xa21e8408, 0xe1000008,
+	0x1b80001f, 0x20000080, 0x1a40001f, 0x10006208, 0xc24024e0, 0x17c07c1f,
+	0x1a10001f, 0x10006610, 0x82042001, 0xd8005e88, 0x17c07c1f, 0x1a10001f,
+	0x10006918, 0x8a000008, 0x00000f0f, 0xba00010c, 0x1fffe7ff, 0xd8205e88,
+	0x17c07c1f, 0x1a40001f, 0x10006208, 0xc24022a0, 0x17c07c1f, 0x1900001f,
+	0x10001250, 0x1a10001f, 0x10001250, 0x8a000008, 0xfffffffb, 0xe1000008,
+	0x1b80001f, 0x20000080, 0x1900001f, 0x10001220, 0x1a10001f, 0x10001220,
+	0x8a000008, 0xdfffffff, 0xe1000008, 0x1b80001f, 0x20000080, 0x1900001f,
+	0x1020002c, 0x1a10001f, 0x1020002c, 0x8a000008, 0xffffffef, 0xe1000008,
+	0x1a10001f, 0x10006b00, 0x81082001, 0xd8205fa4, 0x17c07c1f, 0x1a40001f,
+	0x100062b0, 0xc2402f20, 0x17c07c1f, 0x1b80001f, 0x20000208, 0xd8207b8c,
+	0x17c07c1f, 0x1a40001f, 0x100062b0, 0xc2403700, 0x17c07c1f, 0x81001401,
+	0xd8206424, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x81002001, 0xb1042081,
+	0xb900008c, 0x1fffe7ff, 0xd8206424, 0x17c07c1f, 0x1a40001f, 0x10006200,
+	0x1a80001f, 0x1000625c, 0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffffe,
+	0xe8208000, 0x10006f00, 0x00000000, 0xe8208000, 0x10006b30, 0x00000000,
+	0xe8208000, 0x100063e0, 0x00000001, 0x81009401, 0xd82067a4, 0x17c07c1f,
+	0x1a10001f, 0x10006918, 0x8100a001, 0xb104a081, 0xb900008c, 0x01000001,
+	0xd82067a4, 0x17c07c1f, 0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264,
+	0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffffd, 0xe8208000, 0x10006f04,
+	0x00000000, 0xe8208000, 0x10006b34, 0x00000000, 0xe8208000, 0x100063e0,
+	0x00000002, 0x81011401, 0xd8206b24, 0x17c07c1f, 0x1a10001f, 0x10006918,
+	0x81012001, 0xb1052081, 0xb900008c, 0x01000001, 0xd8206b24, 0x17c07c1f,
+	0x1a40001f, 0x1000621c, 0x1a80001f, 0x1000626c, 0xc24026e0, 0x17c07c1f,
+	0x89400005, 0xfffffffb, 0xe8208000, 0x10006f08, 0x00000000, 0xe8208000,
+	0x10006b38, 0x00000000, 0xe8208000, 0x100063e0, 0x00000004, 0x81019401,
+	0xd8206ea4, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8101a001, 0xb105a081,
+	0xb900008c, 0x01000001, 0xd8206ea4, 0x17c07c1f, 0x1a40001f, 0x10006220,
+	0x1a80001f, 0x10006274, 0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffff7,
+	0xe8208000, 0x10006f0c, 0x00000000, 0xe8208000, 0x10006b3c, 0x00000000,
+	0xe8208000, 0x100063e0, 0x00000008, 0x1a10001f, 0x10006610, 0x8207a001,
+	0xd8207608, 0x17c07c1f, 0x81021401, 0xd82072a4, 0x17c07c1f, 0x1a10001f,
+	0x10006918, 0x81022001, 0xb1062081, 0xb900008c, 0x01000001, 0xd82072a4,
+	0x17c07c1f, 0x1a40001f, 0x100062a0, 0x1280041f, 0xc2402a60, 0x17c07c1f,
+	0x89400005, 0xffffffef, 0xe8208000, 0x10006f10, 0x00000000, 0xe8208000,
+	0x10006b40, 0x00000000, 0xe8208000, 0x100063e0, 0x00000010, 0x81029401,
+	0xd8207604, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8102a001, 0xb106a081,
+	0xb900008c, 0x01000001, 0xd8207604, 0x17c07c1f, 0x1a40001f, 0x100062a4,
+	0x1290841f, 0xc2402a60, 0x17c07c1f, 0x89400005, 0xffffffdf, 0xe8208000,
+	0x10006f14, 0x00000000, 0xe8208000, 0x10006b44, 0x00000000, 0xe8208000,
+	0x100063e0, 0x00000020, 0x81031401, 0xd82078c4, 0x17c07c1f, 0x1a10001f,
+	0x10006918, 0x81032001, 0xb1072081, 0xb900008c, 0x01000001, 0xd82078c4,
+	0x17c07c1f, 0x89400005, 0xffffffbf, 0xe8208000, 0x10006f18, 0x00000000,
+	0xe8208000, 0x10006b48, 0x00000000, 0xe8208000, 0x100063e0, 0x00000040,
+	0x81039401, 0xd8207b84, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8103a001,
+	0xb107a081, 0xb900008c, 0x01000001, 0xd8207b84, 0x17c07c1f, 0x89400005,
+	0xffffff7f, 0xe8208000, 0x10006f1c, 0x00000000, 0xe8208000, 0x10006b4c,
+	0x00000000, 0xe8208000, 0x100063e0, 0x00000080, 0xd00041c0, 0x17c07c1f,
+	0xe8208000, 0x10006600, 0x00000000, 0x1ac0001f, 0x55aa55aa, 0x1940001f,
+	0xaa55aa55, 0x1b80001f, 0x00001000, 0xf0000000, 0x17c07c1f
+};
+
+static const struct pcm_desc mcdi_pcm = {
+	.version = "pcm_mcdi_mt8173_20160401_v1",
+	.base = mcdi_binary,
+	.size = 1001,
+	.sess = 2,
+	.replace = 0,
+};
+
+static struct pwr_ctrl mcdi_ctrl = {
+	.wake_src = WAKE_SRC_FOR_MCDI,
+	.wake_src_md32 = 0,
+	.wfi_op = WFI_OP_OR,
+	.mcusys_idle_mask = 1,
+	.ca7top_idle_mask = 1,
+	.ca15top_idle_mask = 1,
+	.disp_req_mask = 1,
+	.mfg_req_mask = 1,
+	.md32_req_mask = 1,
+};
+
+static const struct spm_lp_scen spm_mcdi = {
+	.pcmdesc = &mcdi_pcm,
+	.pwrctrl = &mcdi_ctrl,
+};
+
+void spm_mcdi_cpu_wake_up_event(int wake_up_event, int disable_dormant_power)
+{
+	if (((mmio_read_32(SPM_SLEEP_CPU_WAKEUP_EVENT) & 0x1) == 1)
+	    && ((mmio_read_32(SPM_CLK_CON) & CC_DISABLE_DORM_PWR) == 0)) {
+		/* MCDI is offload? */
+		INFO("%s: SPM_SLEEP_CPU_WAKEUP_EVENT:%x, SPM_CLK_CON %x",
+			__func__, mmio_read_32(SPM_SLEEP_CPU_WAKEUP_EVENT),
+			mmio_read_32(SPM_CLK_CON));
+		return;
+	}
+	/* Inform SPM that CPU wants to program CPU_WAKEUP_EVENT and
+	 * DISABLE_CPU_DROM */
+	mmio_write_32(SPM_PCM_REG_DATA_INI, PCM_MCDI_HANDSHAKE_SYNC);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+
+	/* Wait SPM's response, can't use sleep api */
+	while (mmio_read_32(SPM_PCM_REG6_DATA) != PCM_MCDI_HANDSHAKE_ACK)
+		;
+
+	if (disable_dormant_power) {
+		mmio_setbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR);
+		while (mmio_read_32(SPM_CLK_CON) !=
+			(mmio_read_32(SPM_CLK_CON) | CC_DISABLE_DORM_PWR))
+			;
+
+	} else {
+		mmio_clrbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR);
+		while (mmio_read_32(SPM_CLK_CON) !=
+			(mmio_read_32(SPM_CLK_CON) & ~CC_DISABLE_DORM_PWR))
+			;
+	}
+
+	mmio_write_32(SPM_SLEEP_CPU_WAKEUP_EVENT, wake_up_event);
+
+	while (mmio_read_32(SPM_SLEEP_CPU_WAKEUP_EVENT) != wake_up_event)
+		;
+
+	/* Inform SPM to see updated setting */
+	mmio_write_32(SPM_PCM_REG_DATA_INI, PCM_MCDI_UPDATE_INFORM);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+
+	while (mmio_read_32(SPM_PCM_REG6_DATA) != PCM_MCDI_CKECK_DONE)
+		;
+	/* END OF sequence */
+
+	mmio_write_32(SPM_PCM_REG_DATA_INI, 0x0);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6);
+	mmio_write_32(SPM_PCM_PWR_IO_EN, 0);
+}
+
+void spm_mcdi_wakeup_all_cores(void)
+{
+	if (is_mcdi_ready() == 0)
+		return;
+
+	spm_mcdi_cpu_wake_up_event(1, 1);
+	while (mmio_read_32(SPM_PCM_REG5_DATA) != PCM_MCDI_ALL_CORE_AWAKE)
+		;
+	spm_mcdi_cpu_wake_up_event(1, 0);
+	while (mmio_read_32(SPM_PCM_REG5_DATA) != PCM_MCDI_OFFLOADED)
+		;
+
+	spm_clean_after_wakeup();
+	clear_all_ready();
+}
+
+static void spm_mcdi_wfi_sel_enter(unsigned long mpidr)
+{
+	int core_id_val = mpidr & MPIDR_CPU_MASK;
+	int cluster_id = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	/* SPM WFI Select by core number */
+	if (cluster_id) {
+		switch (core_id_val) {
+		case 0:
+			mmio_write_32(SPM_CA15_CPU0_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, 1);
+			break;
+		case 1:
+			mmio_write_32(SPM_CA15_CPU1_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, 1);
+			break;
+		case 2:
+			mmio_write_32(SPM_CA15_CPU2_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, 1);
+			break;
+		case 3:
+			mmio_write_32(SPM_CA15_CPU3_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, 1);
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch (core_id_val) {
+		case 0:
+			mmio_write_32(SPM_CA7_CPU0_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, 1);
+			break;
+		case 1:
+			mmio_write_32(SPM_CA7_CPU1_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, 1);
+			break;
+		case 2:
+			mmio_write_32(SPM_CA7_CPU2_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, 1);
+			break;
+		case 3:
+			mmio_write_32(SPM_CA7_CPU3_IRQ_MASK, 1);
+			mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, 1);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void spm_mcdi_wfi_sel_leave(unsigned long mpidr)
+{
+	int core_id_val = mpidr & MPIDR_CPU_MASK;
+	int cluster_id = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	/* SPM WFI Select by core number */
+	if (cluster_id) {
+		switch (core_id_val) {
+		case 0:
+			mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, 0);
+			mmio_write_32(SPM_CA15_CPU0_IRQ_MASK, 0);
+			break;
+		case 1:
+			mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, 0);
+			mmio_write_32(SPM_CA15_CPU1_IRQ_MASK, 0);
+			break;
+		case 2:
+			mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, 0);
+			mmio_write_32(SPM_CA15_CPU2_IRQ_MASK, 0);
+			break;
+		case 3:
+			mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, 0);
+			mmio_write_32(SPM_CA15_CPU3_IRQ_MASK, 0);
+			break;
+		default:
+			break;
+		}
+	} else {
+		switch (core_id_val) {
+		case 0:
+			mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, 0);
+			mmio_write_32(SPM_CA7_CPU0_IRQ_MASK, 0);
+			break;
+		case 1:
+			mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, 0);
+			mmio_write_32(SPM_CA7_CPU1_IRQ_MASK, 0);
+			break;
+		case 2:
+			mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, 0);
+			mmio_write_32(SPM_CA7_CPU2_IRQ_MASK, 0);
+			break;
+		case 3:
+			mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, 0);
+			mmio_write_32(SPM_CA7_CPU3_IRQ_MASK, 0);
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void spm_mcdi_set_cputop_pwrctrl_for_cluster_off(unsigned long mpidr)
+{
+	unsigned long cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+	unsigned long cpu_id = mpidr & MPIDR_CPU_MASK;
+	unsigned int pwr_status, shift, i, flag = 0;
+
+	pwr_status = mmio_read_32(SPM_PWR_STATUS) |
+				 mmio_read_32(SPM_PWR_STATUS_2ND);
+
+	if (cluster_id) {
+		for (i = 0; i < PLATFORM_CLUSTER1_CORE_COUNT; i++) {
+			if (i == cpu_id)
+				continue;
+			shift = i + PCM_MCDI_CA72_PWRSTA_SHIFT;
+			flag |= (pwr_status & (1 << shift)) >> shift;
+		}
+		if (!flag)
+			mmio_setbits_32(SPM_PCM_RESERVE,
+					PCM_MCDI_CA72_CPUTOP_PWRCTL);
+	} else {
+		for (i = 0; i < PLATFORM_CLUSTER0_CORE_COUNT; i++) {
+			if (i == cpu_id)
+				continue;
+			shift = i + PCM_MCDI_CA53_PWRSTA_SHIFT;
+			flag |= (pwr_status & (1 << shift)) >> shift;
+		}
+		if (!flag)
+			mmio_setbits_32(SPM_PCM_RESERVE,
+					PCM_MCDI_CA53_CPUTOP_PWRCTL);
+	}
+}
+
+static void spm_mcdi_clear_cputop_pwrctrl_for_cluster_on(unsigned long mpidr)
+{
+	unsigned long cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		mmio_clrbits_32(SPM_PCM_RESERVE,
+				PCM_MCDI_CA72_CPUTOP_PWRCTL);
+	else
+		mmio_clrbits_32(SPM_PCM_RESERVE,
+				PCM_MCDI_CA53_CPUTOP_PWRCTL);
+}
+
+void spm_mcdi_prepare_for_mtcmos(void)
+{
+	const struct pcm_desc *pcmdesc = spm_mcdi.pcmdesc;
+	struct pwr_ctrl *pwrctrl = spm_mcdi.pwrctrl;
+
+	if (is_mcdi_ready() == 0) {
+		if (is_hotplug_ready() == 1)
+			spm_clear_hotplug();
+		set_pwrctrl_pcm_flags(pwrctrl, 0);
+		spm_reset_and_init_pcm();
+		spm_kick_im_to_fetch(pcmdesc);
+		spm_set_power_control(pwrctrl);
+		spm_set_wakeup_event(pwrctrl);
+		spm_kick_pcm_to_run(pwrctrl);
+		set_mcdi_ready();
+	}
+}
+
+void spm_mcdi_prepare_for_off_state(unsigned long mpidr, unsigned int afflvl)
+{
+	const struct pcm_desc *pcmdesc = spm_mcdi.pcmdesc;
+	struct pwr_ctrl *pwrctrl = spm_mcdi.pwrctrl;
+
+	spm_lock_get();
+	if (is_mcdi_ready() == 0) {
+		if (is_hotplug_ready() == 1)
+			spm_clear_hotplug();
+		set_pwrctrl_pcm_flags(pwrctrl, 0);
+		spm_reset_and_init_pcm();
+		spm_kick_im_to_fetch(pcmdesc);
+		spm_set_power_control(pwrctrl);
+		spm_set_wakeup_event(pwrctrl);
+		spm_kick_pcm_to_run(pwrctrl);
+		set_mcdi_ready();
+	}
+	spm_mcdi_wfi_sel_enter(mpidr);
+	if (afflvl == MPIDR_AFFLVL1)
+		spm_mcdi_set_cputop_pwrctrl_for_cluster_off(mpidr);
+	spm_lock_release();
+}
+
+void spm_mcdi_finish_for_on_state(unsigned long mpidr, unsigned int afflvl)
+{
+	unsigned long linear_id;
+
+	linear_id = ((mpidr & MPIDR_CLUSTER_MASK) >> 6) |
+			(mpidr & MPIDR_CPU_MASK);
+
+	spm_lock_get();
+	spm_mcdi_clear_cputop_pwrctrl_for_cluster_on(mpidr);
+	spm_mcdi_wfi_sel_leave(mpidr);
+	mmio_write_32(SPM_PCM_SW_INT_CLEAR, (0x1 << linear_id));
+	spm_lock_release();
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h
new file mode 100644
index 0000000..7f3f96e
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SPM_MCDI_H
+#define SPM_MCDI_H
+
+void spm_mcdi_wakeup_all_cores(void);
+void spm_mcdi_prepare_for_mtcmos(void);
+void spm_mcdi_prepare_for_off_state(unsigned long mpidr, unsigned int afflvl);
+void spm_mcdi_finish_for_on_state(unsigned long mpidr, unsigned int afflvl);
+
+#endif /* SPM_MCDI_H */
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_suspend.c b/plat/mediatek/mt8173/drivers/spm/spm_suspend.c
new file mode 100644
index 0000000..5021695
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_suspend.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <mt8173_def.h>
+#include <spm.h>
+#include <spm_suspend.h>
+
+/*
+ * System Power Manager (SPM) is a hardware module, which controls cpu or
+ * system power for different power scenarios using different firmware.
+ * This driver controls the system power in system suspend flow.
+ */
+
+#define WAKE_SRC_FOR_SUSPEND					\
+	(WAKE_SRC_KP | WAKE_SRC_EINT | WAKE_SRC_MD32 |		\
+	WAKE_SRC_USB_CD | WAKE_SRC_USB_PDN | WAKE_SRC_THERM |	\
+	WAKE_SRC_SYSPWREQ | WAKE_SRC_ALL_MD32)
+
+#define WAKE_SRC_FOR_MD32  0
+
+#define spm_is_wakesrc_invalid(wakesrc)	\
+	(!!((unsigned int)(wakesrc) & 0xc0003803))
+
+#define ARMCA15PLL_CON0		(APMIXED_BASE + 0x200)
+#define ARMCA15PLL_CON1		(APMIXED_BASE + 0x204)
+#define ARMCA15PLL_PWR_CON0	(APMIXED_BASE + 0x20c)
+#define ARMCA15PLL_PWR_ON	(1U << 0)
+#define ARMCA15PLL_ISO_EN	(1U << 1)
+#define ARMCA15PLL_EN		(1U << 0)
+
+const unsigned int spm_flags =
+	SPM_DUALVCORE_PDN_DIS | SPM_PASR_DIS | SPM_DPD_DIS |
+	SPM_CPU_DVS_DIS | SPM_OPT | SPM_INFRA_PDN_DIS;
+
+enum wake_reason_t spm_wake_reason = WR_NONE;
+
+/**********************************************************
+ * PCM sequence for cpu suspend
+ **********************************************************/
+static const unsigned int suspend_binary_ca7[] = {
+	0x81f58407, 0x81f68407, 0x803a0400, 0x803a8400, 0x1b80001f, 0x20000000,
+	0x80300400, 0x80318400, 0x80328400, 0xa1d28407, 0x81f20407, 0x81009801,
+	0xd8000244, 0x17c07c1f, 0x18c0001f, 0x10006234, 0xc0c032e0, 0x1200041f,
+	0x80310400, 0x1b80001f, 0x2000000a, 0xa0110400, 0x18c0001f, 0x100062c8,
+	0xe0e00010, 0xe0e00030, 0xe0e00070, 0xe0e000f0, 0x1b80001f, 0x2000001a,
+	0xe0e00ff0, 0xe8208000, 0x10006354, 0xfffe7fff, 0xe8208000, 0x10006834,
+	0x00000010, 0x81f00407, 0xa1dd0407, 0x81fd0407, 0xc2803800, 0x1290041f,
+	0x8880000c, 0x2f7be75f, 0xd8200722, 0x17c07c1f, 0xd82006a9, 0x17c07c1f,
+	0xe8208000, 0x10006814, 0x00000001, 0xc2803800, 0x1293841f, 0x1b00001f,
+	0x7fffe7ff, 0xd0000760, 0x17c07c1f, 0x1b00001f, 0x7ffff7ff, 0xf0000000,
+	0x17c07c1f, 0x80880001, 0xd8000842, 0x17c07c1f, 0xd00028e0, 0x1200041f,
+	0xe8208000, 0x10006834, 0x00000000, 0x1b00001f, 0x3fffe7ff, 0x1b80001f,
+	0x20000004, 0xd8200a0c, 0x17c07c1f, 0xe8208000, 0x10006834, 0x00000010,
+	0xd0001280, 0x17c07c1f, 0x18c0001f, 0x10006608, 0x1910001f, 0x10006608,
+	0x813b0404, 0xe0c00004, 0x1880001f, 0x10006320, 0xc0c03760, 0xe080000f,
+	0xd8200c03, 0x17c07c1f, 0x1b00001f, 0x7ffff7ff, 0xd0001280, 0x17c07c1f,
+	0xe080001f, 0xe8208000, 0x10006354, 0xffffffff, 0x18c0001f, 0x100062c8,
+	0xe0e000f0, 0xe0e00030, 0xe0e00000, 0x81009801, 0xd80010c4, 0x17c07c1f,
+	0x18c0001f, 0x10004094, 0x1910001f, 0x1020e374, 0xe0c00004, 0x18c0001f,
+	0x10004098, 0x1910001f, 0x1020e378, 0xe0c00004, 0x18c0001f, 0x10011094,
+	0x1910001f, 0x10213374, 0xe0c00004, 0x18c0001f, 0x10011098, 0x1910001f,
+	0x10213378, 0xe0c00004, 0x1910001f, 0x10213378, 0x18c0001f, 0x10006234,
+	0xc0c034a0, 0x17c07c1f, 0xc2803800, 0x1290841f, 0xa1d20407, 0x81f28407,
+	0xa1d68407, 0xa0128400, 0xa0118400, 0xa0100400, 0xa01a8400, 0xa01a0400,
+	0x19c0001f, 0x001c239f, 0x1b00001f, 0x3fffefff, 0xf0000000, 0x17c07c1f,
+	0x808d8001, 0xd8201502, 0x17c07c1f, 0x803d8400, 0x1b80001f, 0x2000001a,
+	0x80340400, 0x17c07c1f, 0x17c07c1f, 0x80310400, 0x81fa0407, 0x81f18407,
+	0x81f08407, 0xa1dc0407, 0x1b80001f, 0x200000b6, 0xd0002220, 0x17c07c1f,
+	0x1880001f, 0x20000208, 0x81011801, 0xd80016e4, 0x17c07c1f, 0xe8208000,
+	0x1000f600, 0xd2000000, 0x1380081f, 0x18c0001f, 0x10006240, 0xe0e00016,
+	0xe0e0001e, 0xe0e0000e, 0xe0e0000f, 0x80368400, 0x1380081f, 0x80370400,
+	0x1380081f, 0x80360400, 0x803e0400, 0x1380081f, 0x80380400, 0x803b0400,
+	0xa01d8400, 0x1b80001f, 0x20000034, 0x803d8400, 0x1b80001f, 0x20000152,
+	0x803d0400, 0x1380081f, 0x18c0001f, 0x1000f5c8, 0x1910001f, 0x1000f5c8,
+	0xa1000404, 0xe0c00004, 0x18c0001f, 0x100125c8, 0x1910001f, 0x100125c8,
+	0xa1000404, 0xe0c00004, 0x1910001f, 0x100125c8, 0x80340400, 0x17c07c1f,
+	0x17c07c1f, 0x80310400, 0xe8208000, 0x10000044, 0x00000100, 0x1b80001f,
+	0x20000068, 0x1b80001f, 0x2000000a, 0x18c0001f, 0x10006240, 0xe0e0000d,
+	0x81011801, 0xd8001f64, 0x17c07c1f, 0x18c0001f, 0x100040f4, 0x1910001f,
+	0x100040f4, 0xa11c8404, 0xe0c00004, 0x1b80001f, 0x2000000a, 0x813c8404,
+	0xe0c00004, 0x18c0001f, 0x100110f4, 0x1910001f, 0x100110f4, 0xa11c8404,
+	0xe0c00004, 0x1b80001f, 0x2000000a, 0x813c8404, 0xe0c00004, 0x1b80001f,
+	0x20000100, 0x81fa0407, 0x81f18407, 0x81f08407, 0xe8208000, 0x10006354,
+	0xfffe7b47, 0x18c0001f, 0x65930003, 0xc0c031c0, 0x17c07c1f, 0xc2803800,
+	0x1293041f, 0xa1d80407, 0xa1dc0407, 0x18c0001f, 0x10006608, 0x1910001f,
+	0x10006608, 0xa11b0404, 0xe0c00004, 0xc2803800, 0x1291041f, 0x8880000c,
+	0x2f7be75f, 0xd8202362, 0x17c07c1f, 0x1b00001f, 0x3fffe7ff, 0xd00023a0,
+	0x17c07c1f, 0x1b00001f, 0xbfffe7ff, 0xf0000000, 0x17c07c1f, 0x1890001f,
+	0x10006608, 0x808b0801, 0xd8202642, 0x17c07c1f, 0x1880001f, 0x10006320,
+	0xc0c03540, 0xe080000f, 0xd80027a3, 0x17c07c1f, 0xe080001f, 0xa1da0407,
+	0x81fc0407, 0xa0110400, 0xa0140400, 0xa01d8400, 0xd0003100, 0x17c07c1f,
+	0x1b80001f, 0x20000fdf, 0x1890001f, 0x10006608, 0x80c98801, 0x810a8801,
+	0x10918c1f, 0xa0939002, 0x8080080d, 0xd82028e2, 0x12007c1f, 0x1b00001f,
+	0x3fffe7ff, 0x1b80001f, 0x20000004, 0xd800318c, 0x17c07c1f, 0x1b00001f,
+	0xbfffe7ff, 0xd0003180, 0x17c07c1f, 0x81f80407, 0x81fc0407, 0x18c0001f,
+	0x65930006, 0xc0c031c0, 0x17c07c1f, 0x18c0001f, 0x65930007, 0xc0c031c0,
+	0x17c07c1f, 0x1880001f, 0x10006320, 0xc0c03540, 0xe080000f, 0xd80027a3,
+	0x17c07c1f, 0xe080001f, 0x18c0001f, 0x65930005, 0xc0c031c0, 0x17c07c1f,
+	0xa1da0407, 0xe8208000, 0x10000048, 0x00000100, 0x1b80001f, 0x20000068,
+	0xa0110400, 0xa0140400, 0x18c0001f, 0x1000f5c8, 0x1910001f, 0x1000f5c8,
+	0x81200404, 0xe0c00004, 0x18c0001f, 0x100125c8, 0x1910001f, 0x100125c8,
+	0x81200404, 0xe0c00004, 0x1910001f, 0x100125c8, 0xa01d0400, 0xa01b0400,
+	0xa0180400, 0x803d8400, 0xa01e0400, 0xa0160400, 0xa0170400, 0xa0168400,
+	0x1b80001f, 0x20000104, 0x81011801, 0xd80030c4, 0x17c07c1f, 0x18c0001f,
+	0x10006240, 0xc0c034a0, 0x17c07c1f, 0xe8208000, 0x1000f600, 0xd2000001,
+	0xd8000848, 0x17c07c1f, 0xc2803800, 0x1291841f, 0x1b00001f, 0x7ffff7ff,
+	0xf0000000, 0x17c07c1f, 0x1900001f, 0x10006830, 0xe1000003, 0x18c0001f,
+	0x10006834, 0xe0e00000, 0xe0e00001, 0xf0000000, 0x17c07c1f, 0xe0f07f16,
+	0x1380201f, 0xe0f07f1e, 0x1380201f, 0xe0f07f0e, 0x1b80001f, 0x20000104,
+	0xe0f07f0c, 0xe0f07f0d, 0xe0f07e0d, 0xe0f07c0d, 0xe0f0780d, 0xf0000000,
+	0xe0f0700d, 0xe0f07f0d, 0xe0f07f0f, 0xe0f07f1e, 0xf0000000, 0xe0f07f12,
+	0x11407c1f, 0x81f08407, 0x81f18407, 0x1b80001f, 0x20000001, 0xa1d08407,
+	0xa1d18407, 0x1392841f, 0x812ab401, 0x80ebb401, 0xa0c00c04, 0xd8203743,
+	0x17c07c1f, 0x80c01403, 0xd8203563, 0x01400405, 0xf0000000, 0xa1d00407,
+	0x1b80001f, 0x20000208, 0x80ea3401, 0xf0000000, 0x18c0001f, 0x10006b6c,
+	0x1910001f, 0x10006b6c, 0xa1002804, 0xf0000000, 0xe0c00004, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f,
+	0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001, 0xa1d48407, 0x1990001f,
+	0x10006b08, 0x1a50001f, 0x10006610, 0x8246a401, 0xe8208000, 0x10006b6c,
+	0x00000000, 0x1b00001f, 0x2f7be75f, 0x81469801, 0xd8004305, 0x17c07c1f,
+	0x1b80001f, 0xd00f0000, 0x8880000c, 0x2f7be75f, 0xd8005fa2, 0x17c07c1f,
+	0xd0004340, 0x17c07c1f, 0x1b80001f, 0x500f0000, 0xe8208000, 0x10006354,
+	0xfffe7b47, 0xc0c06c00, 0x81401801, 0xd80048e5, 0x17c07c1f, 0x81f60407,
+	0x18c0001f, 0x10006200, 0xc0c06060, 0x12807c1f, 0xe8208000, 0x1000625c,
+	0x00000001, 0x1b80001f, 0x20000080, 0xc0c06060, 0x1280041f, 0x18c0001f,
+	0x10006204, 0xc0c06400, 0x1280041f, 0x18c0001f, 0x10006208, 0xc0c06060,
+	0x12807c1f, 0xe8208000, 0x10006244, 0x00000001, 0x1b80001f, 0x20000080,
+	0xc0c06060, 0x1280041f, 0x18d0001f, 0x10200200, 0x18c0001f, 0x10006290,
+	0xc0c06060, 0x1280041f, 0xe8208000, 0x10006404, 0x00003101, 0xc2803800,
+	0x1292041f, 0x81469801, 0xd8204a45, 0x17c07c1f, 0x1b00001f, 0x2f7be75f,
+	0x1b80001f, 0x30000004, 0x8880000c, 0x2f7be75f, 0xd8005a02, 0x17c07c1f,
+	0xc0c06780, 0x17c07c1f, 0x18c0001f, 0x10006294, 0xe0f07fff, 0xe0e00fff,
+	0xe0e000ff, 0x81449801, 0xd8004c85, 0x17c07c1f, 0x1a00001f, 0x10006604,
+	0xe2200003, 0xc0c06840, 0x17c07c1f, 0xe2200005, 0xc0c06840, 0x17c07c1f,
+	0xa1d38407, 0xa1d98407, 0x1800001f, 0x00000012, 0x1800001f, 0x00000e12,
+	0x1800001f, 0x03800e12, 0x1800001f, 0x038e0e12, 0xe8208000, 0x10006310,
+	0x0b1600f8, 0x1940001f, 0x00000000, 0x12407c1f, 0x1b00001f, 0xbfffe7ff,
+	0x1b80001f, 0x90100000, 0x17c07c1f, 0xd8004fc5, 0x17c07c1f, 0x8247b001,
+	0x1940001f, 0xffffffff, 0x80c00400, 0xd82050c3, 0xa1d58407, 0xa1dd8407,
+	0x1b00001f, 0x3fffefff, 0xd0004ec0, 0x17c07c1f, 0x1890001f, 0x100063e8,
+	0x88c0000c, 0x2f7be75f, 0xd80052e3, 0x17c07c1f, 0x80c40001, 0xd8005263,
+	0x17c07c1f, 0x1b00001f, 0xbfffe7ff, 0xd00052a0, 0x17c07c1f, 0x1b00001f,
+	0x7ffff7ff, 0xd0004ec0, 0x17c07c1f, 0x80c40001, 0xd82053e3, 0x17c07c1f,
+	0xa1de0407, 0x1b00001f, 0x7fffe7ff, 0xd0004ec0, 0x17c07c1f, 0xe8208000,
+	0x10006814, 0x00000000, 0x18c0001f, 0x10006b00, 0xe0e00000, 0xe0c00009,
+	0x18c0001f, 0x10006294, 0xe0e001fe, 0xe0e003fc, 0xe0e007f8, 0xe0e00ff0,
+	0x1b80001f, 0x20000020, 0xe0f07ff0, 0xe0f07f00, 0x81449801, 0xd80057a5,
+	0x17c07c1f, 0x1a00001f, 0x10006604, 0xe2200002, 0xc0c06840, 0x17c07c1f,
+	0xe2200004, 0xc0c06840, 0x17c07c1f, 0x1b80001f, 0x200016a8, 0x1800001f,
+	0x03800e12, 0x1b80001f, 0x20000300, 0x1800001f, 0x00000e12, 0x1b80001f,
+	0x20000300, 0x1800001f, 0x00000012, 0x1b80001f, 0x20000104, 0x10007c1f,
+	0x81f38407, 0x81f98407, 0x81f90407, 0x81f40407, 0x1b80001f, 0x200016a8,
+	0x81401801, 0xd8005fa5, 0x17c07c1f, 0xe8208000, 0x10006404, 0x00002101,
+	0x18c0001f, 0x10006290, 0x1212841f, 0xc0c061e0, 0x12807c1f, 0xc0c061e0,
+	0x1280041f, 0x18c0001f, 0x10006208, 0x1212841f, 0xc0c061e0, 0x12807c1f,
+	0xe8208000, 0x10006244, 0x00000000, 0x1b80001f, 0x20000080, 0xc0c061e0,
+	0x1280041f, 0xe8208000, 0x10200268, 0x000ffffe, 0x18c0001f, 0x10006204,
+	0x1212841f, 0xc0c065a0, 0x1280041f, 0x18c0001f, 0x10006200, 0x1212841f,
+	0xc0c061e0, 0x12807c1f, 0xe8208000, 0x1000625c, 0x00000000, 0x1b80001f,
+	0x20000080, 0xc0c061e0, 0x1280041f, 0x19c0001f, 0x01411820, 0x1ac0001f,
+	0x55aa55aa, 0x10007c1f, 0xf0000000, 0xd800610a, 0x17c07c1f, 0xe2e0004f,
+	0xe2e0006f, 0xe2e0002f, 0xd82061aa, 0x17c07c1f, 0xe2e0002e, 0xe2e0003e,
+	0xe2e00032, 0xf0000000, 0x17c07c1f, 0xd80062aa, 0x17c07c1f, 0xe2e00036,
+	0xe2e0003e, 0x1380201f, 0xe2e0003c, 0xd82063ca, 0x17c07c1f, 0x1380201f,
+	0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d,
+	0xf0000000, 0x17c07c1f, 0x1a50001f, 0x10006610, 0x8246a401, 0xd8206569,
+	0x17c07c1f, 0xe2e0000d, 0xe2e0000c, 0xe2e0001c, 0xe2e0001e, 0xe2e00016,
+	0xe2e00012, 0xf0000000, 0x17c07c1f, 0x1a50001f, 0x10006610, 0x8246a401,
+	0xd8206749, 0x17c07c1f, 0xe2e00016, 0x1380201f, 0xe2e0001e, 0x1380201f,
+	0xe2e0001c, 0x1380201f, 0xe2e0000c, 0xe2e0000d, 0xf0000000, 0x17c07c1f,
+	0xa1d40407, 0x1391841f, 0xa1d90407, 0x1393041f, 0xf0000000, 0x17c07c1f,
+	0x18d0001f, 0x10006604, 0x10cf8c1f, 0xd8206843, 0x17c07c1f, 0xf0000000,
+	0x17c07c1f, 0xe8208000, 0x11008014, 0x00000002, 0xe8208000, 0x11008020,
+	0x00000101, 0xe8208000, 0x11008004, 0x000000d0, 0x1a00001f, 0x11008000,
+	0xd8006b0a, 0xe220005d, 0xd8206b2a, 0xe2200000, 0xe2200001, 0xe8208000,
+	0x11008024, 0x00000001, 0x1b80001f, 0x20000424, 0xf0000000, 0x17c07c1f,
+	0xa1d10407, 0x1b80001f, 0x20000020, 0xf0000000, 0x17c07c1f
+};
+
+/*
+ * PCM binary for suspend scenario
+ */
+static const struct pcm_desc suspend_pcm_ca7 = {
+	.version = "pcm_suspend_20150917_V4",
+	.base = suspend_binary_ca7,
+	.size = 869,
+	.sess = 2,
+	.replace = 0,
+	.vec0 = EVENT_VEC(11, 1, 0, 0),
+	.vec1 = EVENT_VEC(12, 1, 0, 61),
+	.vec2 = EVENT_VEC(30, 1, 0, 150),
+	.vec3 = EVENT_VEC(31, 1, 0, 287),
+};
+
+/*
+ * SPM settings for suspend scenario
+ */
+static struct pwr_ctrl spm_ctrl = {
+	.wake_src = WAKE_SRC_FOR_SUSPEND,
+	.wake_src_md32 = WAKE_SRC_FOR_MD32,
+	.r0_ctrl_en = 1,
+	.r7_ctrl_en = 1,
+	.infra_dcm_lock = 1,
+	.wfi_op = WFI_OP_AND,
+	.pcm_apsrc_req = 0,
+	.ca7top_idle_mask = 0,
+	.ca15top_idle_mask = 0,
+	.mcusys_idle_mask = 0,
+	.disp_req_mask = 0,
+	.mfg_req_mask = 0,
+	.md32_req_mask = 1,
+	.srclkenai_mask = 1,
+	.ca7_wfi0_en = 1,
+	.ca7_wfi1_en = 1,
+	.ca7_wfi2_en = 1,
+	.ca7_wfi3_en = 1,
+	.ca15_wfi0_en = 1,
+	.ca15_wfi1_en = 1,
+	.ca15_wfi2_en = 1,
+	.ca15_wfi3_en = 1,
+};
+
+/*
+ * go_to_sleep_before_wfi() - trigger SPM to enter suspend scenario
+ */
+static void go_to_sleep_before_wfi(const unsigned int spm_flags)
+{
+	struct pwr_ctrl *pwrctrl;
+
+	pwrctrl = &spm_ctrl;
+
+	set_pwrctrl_pcm_flags(pwrctrl, spm_flags);
+
+	spm_set_sysclk_settle();
+
+	INFO("sec = %u, wakesrc = 0x%x (%u)(%u)\n",
+	     pwrctrl->timer_val, pwrctrl->wake_src,
+	     is_cpu_pdn(pwrctrl->pcm_flags),
+	     is_infra_pdn(pwrctrl->pcm_flags));
+
+	spm_reset_and_init_pcm();
+	spm_init_pcm_register();
+	spm_set_power_control(pwrctrl);
+	spm_set_wakeup_event(pwrctrl);
+	spm_kick_pcm_to_run(pwrctrl);
+	spm_init_event_vector(&suspend_pcm_ca7);
+	spm_kick_im_to_fetch(&suspend_pcm_ca7);
+}
+
+/*
+ * go_to_sleep_after_wfi() - get wakeup reason after
+ * leaving suspend scenario and clean up SPM settings
+ */
+static enum wake_reason_t go_to_sleep_after_wfi(void)
+{
+	struct wake_status wakesta;
+	static enum wake_reason_t last_wr = WR_NONE;
+
+	spm_get_wakeup_status(&wakesta);
+	spm_clean_after_wakeup();
+	last_wr = spm_output_wake_reason(&wakesta);
+
+	return last_wr;
+}
+
+static void bigcore_pll_on(void)
+{
+	mmio_setbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_PWR_ON);
+	mmio_clrbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_ISO_EN);
+	mmio_setbits_32(ARMCA15PLL_CON0, ARMCA15PLL_EN);
+}
+
+static void bigcore_pll_off(void)
+{
+	mmio_clrbits_32(ARMCA15PLL_CON0, ARMCA15PLL_EN);
+	mmio_setbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_ISO_EN);
+	mmio_clrbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_PWR_ON);
+}
+
+void spm_system_suspend(void)
+{
+	bigcore_pll_off();
+	spm_lock_get();
+	go_to_sleep_before_wfi(spm_flags);
+	set_suspend_ready();
+	spm_lock_release();
+}
+
+void spm_system_suspend_finish(void)
+{
+	spm_lock_get();
+	spm_wake_reason = go_to_sleep_after_wfi();
+	INFO("spm_wake_reason=%d\n", spm_wake_reason);
+	clear_all_ready();
+	spm_lock_release();
+	bigcore_pll_on();
+	/* Add 20us delay for turning on PLL*/
+	udelay(20);
+}
diff --git a/plat/mediatek/mt8173/drivers/spm/spm_suspend.h b/plat/mediatek/mt8173/drivers/spm/spm_suspend.h
new file mode 100644
index 0000000..b00faa9
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/spm/spm_suspend.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef SPM_SUSPEND_H
+#define SPM_SUSPEND_H
+
+/* cpu dormant return code */
+#define CPU_DORMANT_RESET        0
+#define CPU_DORMANT_ABORT        1
+
+void spm_system_suspend(void);
+void spm_system_suspend_finish(void);
+
+#endif /* SPM_SUSPEND_H*/
diff --git a/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c
new file mode 100644
index 0000000..174a24d
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mt8173_def.h>
+#include <mt_cpuxgpt.h>
+
+static void write_cpuxgpt(unsigned int reg_index, unsigned int value)
+{
+	mmio_write_32((uintptr_t)&mt8173_mcucfg->xgpt_idx, reg_index);
+	mmio_write_32((uintptr_t)&mt8173_mcucfg->xgpt_ctl, value);
+}
+
+static void cpuxgpt_set_init_cnt(unsigned int countH, unsigned int countL)
+{
+	write_cpuxgpt(INDEX_CNT_H_INIT, countH);
+	/* update count when countL programmed */
+	write_cpuxgpt(INDEX_CNT_L_INIT, countL);
+}
+
+void generic_timer_backup(void)
+{
+	uint64_t cval;
+
+	cval = read_cntpct_el0();
+	cpuxgpt_set_init_cnt((uint32_t)(cval >> 32),
+			       (uint32_t)(cval & 0xffffffff));
+}
diff --git a/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h
new file mode 100644
index 0000000..8c0fe83
--- /dev/null
+++ b/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPUXGPT_H
+#define MT_CPUXGPT_H
+
+/* REG */
+#define INDEX_CNT_L_INIT    0x008
+#define INDEX_CNT_H_INIT    0x00C
+
+void generic_timer_backup(void);
+
+#endif /* MT_CPUXGPT_H */
diff --git a/plat/mediatek/mt8173/include/mcucfg.h b/plat/mediatek/mt8173/include/mcucfg.h
new file mode 100644
index 0000000..dedbc08
--- /dev/null
+++ b/plat/mediatek/mt8173/include/mcucfg.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#include <stdint.h>
+
+#include <mt8173_def.h>
+
+struct mt8173_mcucfg_regs {
+	uint32_t mp0_ca7l_cache_config;
+	struct {
+		uint32_t mem_delsel0;
+		uint32_t mem_delsel1;
+	} mp0_cpu[4];
+	uint32_t mp0_cache_mem_delsel0;
+	uint32_t mp0_cache_mem_delsel1;
+	uint32_t mp0_axi_config;
+	uint32_t mp0_misc_config[2];
+	struct {
+		uint32_t rv_addr_lw;
+		uint32_t rv_addr_hw;
+	} mp0_rv_addr[4];
+	uint32_t mp0_ca7l_cfg_dis;
+	uint32_t mp0_ca7l_clken_ctrl;
+	uint32_t mp0_ca7l_rst_ctrl;
+	uint32_t mp0_ca7l_misc_config;
+	uint32_t mp0_ca7l_dbg_pwr_ctrl;
+	uint32_t mp0_rw_rsvd0;
+	uint32_t mp0_rw_rsvd1;
+	uint32_t mp0_ro_rsvd;
+	uint32_t reserved0_0[100];
+	uint32_t mp1_cpucfg;
+	uint32_t mp1_miscdbg;
+	uint32_t reserved0_1[13];
+	uint32_t mp1_rst_ctl;
+	uint32_t mp1_clkenm_div;
+	uint32_t reserved0_2[7];
+	uint32_t mp1_config_res;
+	uint32_t reserved0_3[13];
+	struct {
+		uint32_t rv_addr_lw;
+		uint32_t rv_addr_hw;
+	} mp1_rv_addr[2];
+	uint32_t reserved0_4[84];
+	uint32_t mp0_rst_status;		/* 0x400 */
+	uint32_t mp0_dbg_ctrl;
+	uint32_t mp0_dbg_flag;
+	uint32_t mp0_ca7l_ir_mon;
+	struct {
+		uint32_t pc_lw;
+		uint32_t pc_hw;
+		uint32_t fp_arch32;
+		uint32_t sp_arch32;
+		uint32_t fp_arch64_lw;
+		uint32_t fp_arch64_hw;
+		uint32_t sp_arch64_lw;
+		uint32_t sp_arch64_hw;
+	} mp0_dbg_core[4];
+	uint32_t dfd_ctrl;
+	uint32_t dfd_cnt_l;
+	uint32_t dfd_cnt_h;
+	uint32_t misccfg_mp0_rw_rsvd;
+	uint32_t misccfg_sec_vio_status0;
+	uint32_t misccfg_sec_vio_status1;
+	uint32_t reserved1[22];
+	uint32_t misccfg_rw_rsvd;		/* 0x500 */
+	uint32_t mcusys_dbg_mon_sel_a;
+	uint32_t mcusys_dbg_mon;
+	uint32_t reserved2[61];
+	uint32_t mcusys_config_a;		/* 0x600 */
+	uint32_t mcusys_config1_a;
+	uint32_t mcusys_gic_peribase_a;
+	uint32_t reserved3;
+	uint32_t sec_range0_start;		/* 0x610 */
+	uint32_t sec_range0_end;
+	uint32_t sec_range_enable;
+	uint32_t reserved4;
+	uint32_t int_pol_ctl[8];		/* 0x620 */
+	uint32_t aclken_div;			/* 0x640 */
+	uint32_t pclken_div;
+	uint32_t l2c_sram_ctrl;
+	uint32_t armpll_jit_ctrl;
+	uint32_t cci_addrmap;			/* 0x650 */
+	uint32_t cci_config;
+	uint32_t cci_periphbase;
+	uint32_t cci_nevntcntovfl;
+	uint32_t cci_clk_ctrl;			/* 0x660 */
+	uint32_t cci_acel_s1_ctrl;
+	uint32_t bus_fabric_dcm_ctrl;
+	uint32_t reserved5;
+	uint32_t xgpt_ctl;			/* 0x670 */
+	uint32_t xgpt_idx;
+	uint32_t ptpod2_ctl0;
+	uint32_t ptpod2_ctl1;
+	uint32_t mcusys_revid;
+	uint32_t mcusys_rw_rsvd0;
+	uint32_t mcusys_rw_rsvd1;
+};
+
+static struct mt8173_mcucfg_regs *const mt8173_mcucfg = (void *)MCUCFG_BASE;
+
+/* cpu boot mode */
+#define	MP0_CPUCFG_64BIT_SHIFT	12
+#define	MP1_CPUCFG_64BIT_SHIFT	28
+#define	MP0_CPUCFG_64BIT	(U(0xf) << MP0_CPUCFG_64BIT_SHIFT)
+#define	MP1_CPUCFG_64BIT	(U(0xf) << MP1_CPUCFG_64BIT_SHIFT)
+
+/* scu related */
+enum {
+	MP0_ACINACTM_SHIFT = 4,
+	MP1_ACINACTM_SHIFT = 0,
+	MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT,
+	MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT
+};
+
+enum {
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16,
+
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+	MP1_AINACTS_SHIFT = 4,
+	MP1_AINACTS = 1 << MP1_AINACTS_SHIFT
+};
+
+enum {
+	MP1_SW_CG_GEN_SHIFT = 12,
+	MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+	MP1_L2RSTDISABLE_SHIFT = 14,
+	MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT
+};
+
+/* cci clock control related */
+enum {
+	MCU_BUS_DCM_EN	= 1 << 8
+};
+
+/* l2c sram control related */
+enum {
+	L2C_SRAM_DCM_EN = 1 << 0
+};
+
+/* bus fabric dcm control related */
+enum {
+	PSYS_ADB400_DCM_EN		= 1 << 29,
+	GPU_ADB400_DCM_EN		= 1 << 28,
+
+	EMI1_ADB400_DCM_EN		= 1 << 27,
+	EMI_ADB400_DCM_EN		= 1 << 26,
+	INFRA_ADB400_DCM_EN		= 1 << 25,
+	L2C_ADB400_DCM_EN		= 1 << 24,
+
+	MP0_ADB400_DCM_EN		= 1 << 23,
+	CCI400_CK_ONLY_DCM_EN		= 1 << 22,
+	L2C_IDLE_DCM_EN			= 1 << 21,
+
+	CA15U_ADB_DYNAMIC_CG_EN		= 1 << 19,
+	CA7L_ADB_DYNAMIC_CG_EN		= 1 << 18,
+	L2C_ADB_DYNAMIC_CG_EN		= 1 << 17,
+
+	EMICLK_EMI1_DYNAMIC_CG_EN	= 1 << 12,
+
+	INFRACLK_PSYS_DYNAMIC_CG_EN	= 1 << 11,
+	EMICLK_GPU_DYNAMIC_CG_EN	= 1 << 10,
+	EMICLK_EMI_DYNAMIC_CG_EN	= 1 << 8,
+
+	CCI400_SLV_RW_DCM_EN		= 1 << 7,
+	CCI400_SLV_DCM_EN		= 1 << 5,
+
+	ACLK_PSYS_DYNAMIC_CG_EN		= 1 << 3,
+	ACLK_GPU_DYNAMIC_CG_EN		= 1 << 2,
+	ACLK_EMI_DYNAMIC_CG_EN		= 1 << 1,
+	ACLK_INFRA_DYNAMIC_CG_EN	= 1 << 0,
+
+	/* adb400 related */
+	ADB400_GRP_DCM_EN = PSYS_ADB400_DCM_EN | GPU_ADB400_DCM_EN |
+			    EMI1_ADB400_DCM_EN | EMI_ADB400_DCM_EN |
+			    INFRA_ADB400_DCM_EN | L2C_ADB400_DCM_EN |
+			    MP0_ADB400_DCM_EN,
+
+	/* cci400 related */
+	CCI400_GRP_DCM_EN = CCI400_CK_ONLY_DCM_EN | CCI400_SLV_RW_DCM_EN |
+			    CCI400_SLV_DCM_EN,
+
+	/* adb clock related */
+	ADBCLK_GRP_DCM_EN = CA15U_ADB_DYNAMIC_CG_EN | CA7L_ADB_DYNAMIC_CG_EN |
+			    L2C_ADB_DYNAMIC_CG_EN,
+
+	/* emi clock related */
+	EMICLK_GRP_DCM_EN = EMICLK_EMI1_DYNAMIC_CG_EN |
+			    EMICLK_GPU_DYNAMIC_CG_EN |
+			    EMICLK_EMI_DYNAMIC_CG_EN,
+
+	/* bus clock related */
+	ACLK_GRP_DCM_EN = ACLK_PSYS_DYNAMIC_CG_EN | ACLK_GPU_DYNAMIC_CG_EN |
+			  ACLK_EMI_DYNAMIC_CG_EN | ACLK_INFRA_DYNAMIC_CG_EN,
+};
+
+#endif /* MCUCFG_H */
diff --git a/plat/mediatek/mt8173/include/mt8173_def.h b/plat/mediatek/mt8173/include/mt8173_def.h
new file mode 100644
index 0000000..58962f0
--- /dev/null
+++ b/plat/mediatek/mt8173/include/mt8173_def.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT8173_DEF_H
+#define MT8173_DEF_H
+
+#if RESET_TO_BL31
+#error "MT8173 is incompatible with RESET_TO_BL31!"
+#endif
+
+#define MT8173_PRIMARY_CPU	0x0
+
+/* Register base address */
+#define IO_PHYS			(0x10000000)
+#define INFRACFG_AO_BASE	(IO_PHYS + 0x1000)
+#define SRAMROM_SEC_BASE	(IO_PHYS + 0x1800)
+#define PERI_CON_BASE		(IO_PHYS + 0x3000)
+#define GPIO_BASE		(IO_PHYS + 0x5000)
+#define SPM_BASE		(IO_PHYS + 0x6000)
+#define RGU_BASE		(IO_PHYS + 0x7000)
+#define PMIC_WRAP_BASE		(IO_PHYS + 0xD000)
+#define DEVAPC0_BASE		(IO_PHYS + 0xE000)
+#define MCUCFG_BASE		(IO_PHYS + 0x200000)
+#define APMIXED_BASE		(IO_PHYS + 0x209000)
+#define TRNG_BASE		(IO_PHYS + 0x20F000)
+#define CRYPT_BASE		(IO_PHYS + 0x210000)
+#define MT_GIC_BASE		(IO_PHYS + 0x220000)
+#define PLAT_MT_CCI_BASE	(IO_PHYS + 0x390000)
+
+/* Aggregate of all devices in the first GB */
+#define MTK_DEV_RNG0_BASE	IO_PHYS
+#define MTK_DEV_RNG0_SIZE	0x400000
+#define MTK_DEV_RNG1_BASE	(IO_PHYS + 0x1000000)
+#define MTK_DEV_RNG1_SIZE	0x4000000
+
+/* SRAMROM related registers */
+#define SRAMROM_SEC_CTRL	(SRAMROM_SEC_BASE + 0x4)
+#define SRAMROM_SEC_ADDR	(SRAMROM_SEC_BASE + 0x8)
+
+/* DEVAPC0 related registers */
+#define DEVAPC0_MAS_SEC_0	(DEVAPC0_BASE + 0x500)
+#define DEVAPC0_APC_CON		(DEVAPC0_BASE + 0xF00)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define MT8173_UART0_BASE	(IO_PHYS + 0x01002000)
+#define MT8173_UART1_BASE	(IO_PHYS + 0x01003000)
+#define MT8173_UART2_BASE	(IO_PHYS + 0x01004000)
+#define MT8173_UART3_BASE	(IO_PHYS + 0x01005000)
+
+#define MT8173_BAUDRATE		(115200)
+#define MT8173_UART_CLOCK	(26000000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	13000000
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE		(MT_GIC_BASE + 0x1000)
+#define BASE_GICC_BASE		(MT_GIC_BASE + 0x2000)
+#define BASE_GICR_BASE		0	/* no GICR in GIC-400 */
+#define BASE_GICH_BASE		(MT_GIC_BASE + 0x4000)
+#define BASE_GICV_BASE		(MT_GIC_BASE + 0x6000)
+#define INT_POL_CTL0		0x10200620
+
+#define GIC_PRIVATE_SIGNALS	(32)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX	4
+#define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX	3
+
+/*******************************************************************************
+ * WDT related constants
+ ******************************************************************************/
+#define MTK_WDT_BASE		(RGU_BASE + 0)
+#define MTK_WDT_SWRST		(MTK_WDT_BASE + 0x0014)
+
+#define MTK_WDT_MODE_DUAL_MODE	0x0040
+#define MTK_WDT_MODE_IRQ	0x0008
+#define MTK_WDT_MODE_KEY	0x22000000
+#define MTK_WDT_MODE_EXTEN	0x0004
+#define MTK_WDT_SWRST_KEY	0x1209
+
+/* FIQ platform related define */
+#define MT_IRQ_SEC_SGI_0	8
+#define MT_IRQ_SEC_SGI_1	9
+#define MT_IRQ_SEC_SGI_2	10
+#define MT_IRQ_SEC_SGI_3	11
+#define MT_IRQ_SEC_SGI_4	12
+#define MT_IRQ_SEC_SGI_5	13
+#define MT_IRQ_SEC_SGI_6	14
+#define MT_IRQ_SEC_SGI_7	15
+
+/*
+ *  Macros for local power states in MTK platforms encoded by State-ID field
+ *  within the power-state parameter.
+ */
+/* Local power state for power domains in Run state. */
+#define MTK_LOCAL_STATE_RUN     0
+/* Local power state for retention. Valid only for CPU power domains */
+#define MTK_LOCAL_STATE_RET     1
+/* Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains
+ */
+#define MTK_LOCAL_STATE_OFF     2
+
+#if PSCI_EXTENDED_STATE_ID
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define MTK_LOCAL_PSTATE_WIDTH		4
+#define MTK_LOCAL_PSTATE_MASK		((1 << MTK_LOCAL_PSTATE_WIDTH) - 1)
+
+/* Macros to construct the composite power state */
+
+/* Make composite power state parameter till power level 0 */
+
+#define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+	(((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT))
+#else
+#define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+		((type) << PSTATE_TYPE_SHIFT))
+
+#endif /* __PSCI_EXTENDED_STATE_ID__ */
+
+/* Make composite power state parameter till power level 1 */
+#define mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl1_state) << MTK_LOCAL_PSTATE_WIDTH) | \
+		mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
+
+/* Make composite power state parameter till power level 2 */
+#define mtk_make_pwrstate_lvl2( \
+		lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl2_state) << (MTK_LOCAL_PSTATE_WIDTH * 2)) | \
+		mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type))
+
+
+#endif /* MT8173_DEF_H */
diff --git a/plat/mediatek/mt8173/include/plat_macros.S b/plat/mediatek/mt8173/include/plat_macros.S
new file mode 100644
index 0000000..ac9fb16
--- /dev/null
+++ b/plat/mediatek/mt8173/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <mt8173_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ---------------------------------------------
+	 * The below macro prints out relevant GIC and
+	 * CCI registers whenever an unhandled exception
+	 * is taken in BL3-1.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm x16, BASE_GICD_BASE
+	mov_imm x17, BASE_GICC_BASE
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
diff --git a/plat/mediatek/mt8173/include/plat_private.h b/plat/mediatek/mt8173/include/plat_private.h
new file mode 100644
index 0000000..cd92d34
--- /dev/null
+++ b/plat/mediatek/mt8173/include/plat_private.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_configure_mmu_el3(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long,
+			    unsigned long,
+			    unsigned long,
+			    unsigned long);
+
+void plat_cci_init(void);
+void plat_cci_enable(void);
+void plat_cci_disable(void);
+
+/* Declarations for plat_topology.c */
+int mt_setup_topology(void);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8173/include/plat_sip_calls.h b/plat/mediatek/mt8173/include/plat_sip_calls.h
new file mode 100644
index 0000000..88202cc
--- /dev/null
+++ b/plat/mediatek/mt8173/include/plat_sip_calls.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+/*******************************************************************************
+ * Plat SiP function constants
+ ******************************************************************************/
+#define MTK_PLAT_SIP_NUM_CALLS	6
+
+#define MTK_SIP_PWR_ON_MTCMOS			0x82000402
+#define MTK_SIP_PWR_OFF_MTCMOS			0x82000403
+#define MTK_SIP_PWR_MTCMOS_SUPPORT		0x82000404
+#define MTK_SIP_SET_HDCP_KEY_NUM		0x82000405
+#define MTK_SIP_CLR_HDCP_KEY			0x82000406
+#define MTK_SIP_SET_HDCP_KEY_EX			0x82000407
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8173/include/platform_def.h b/plat/mediatek/mt8173/include/platform_def.h
new file mode 100644
index 0000000..205e263
--- /dev/null
+++ b/plat/mediatek/mt8173/include/platform_def.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+#include "mt8173_def.h"
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x800
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLAT_MAX_PWR_LVL		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	2
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/*
+ * MT8173 SRAM memory layout
+ * 0x100000 +-------------------+
+ *          | shared mem (4KB)  |
+ * 0x101000 +-------------------+
+ *          |                   |
+ *          |   BL3-1 (124KB)   |
+ *          |                   |
+ * 0x120000 +-------------------+
+ *          |  reserved (64KB)  |
+ * 0x130000 +-------------------+
+ */
+/* TF txet, ro, rw, xlat table, coherent memory ... etc.
+ * Size: release: 128KB, debug: 128KB
+ */
+#define TZRAM_BASE		(0x100000)
+#if DEBUG
+#define TZRAM_SIZE		(0x20000)
+#else
+#define TZRAM_SIZE		(0x20000)
+#endif
+
+/* Reserved: 64KB */
+#define TZRAM2_BASE		(TZRAM_BASE + TZRAM_SIZE)
+#define TZRAM2_SIZE		(0x10000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL3-1 debug size plus a
+ * little space for growth.
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x1000)
+#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
+#define TZRAM2_LIMIT		(TZRAM2_BASE + TZRAM2_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_XLAT_TABLES		4
+#define MAX_MMAP_REGIONS	16
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+
+#define PLAT_ARM_GICD_BASE      BASE_GICD_BASE
+#define PLAT_ARM_GICC_BASE      BASE_GICC_BASE
+
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(MT_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt8173/include/power_tracer.h b/plat/mediatek/mt8173/include/power_tracer.h
new file mode 100644
index 0000000..195366d
--- /dev/null
+++ b/plat/mediatek/mt8173/include/power_tracer.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POWER_TRACER_H
+#define POWER_TRACER_H
+
+#define CPU_UP		0
+#define CPU_DOWN	1
+#define CPU_SUSPEND	2
+#define CLUSTER_UP	3
+#define CLUSTER_DOWN	4
+#define CLUSTER_SUSPEND	5
+
+void trace_power_flow(unsigned long mpidr, unsigned char mode);
+
+#endif /* POWER_TRACER_H */
diff --git a/plat/mediatek/mt8173/include/scu.h b/plat/mediatek/mt8173/include/scu.h
new file mode 100644
index 0000000..b1e9424
--- /dev/null
+++ b/plat/mediatek/mt8173/include/scu.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCU_H
+#define SCU_H
+
+void disable_scu(unsigned long mpidr);
+void enable_scu(unsigned long mpidr);
+
+#endif /* SCU_H */
diff --git a/plat/mediatek/mt8173/plat_mt_gic.c b/plat/mediatek/mt8173/plat_mt_gic.c
new file mode 100644
index 0000000..80b9010
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_mt_gic.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <lib/utils.h>
+
+#include <mt8173_def.h>
+
+const unsigned int mt_irq_sec_array[] = {
+	MT_IRQ_SEC_SGI_0,
+	MT_IRQ_SEC_SGI_1,
+	MT_IRQ_SEC_SGI_2,
+	MT_IRQ_SEC_SGI_3,
+	MT_IRQ_SEC_SGI_4,
+	MT_IRQ_SEC_SGI_5,
+	MT_IRQ_SEC_SGI_6,
+	MT_IRQ_SEC_SGI_7
+};
+
+void plat_mt_gic_init(void)
+{
+	arm_gic_init(BASE_GICC_BASE,
+		BASE_GICD_BASE,
+		BASE_GICR_BASE,
+		mt_irq_sec_array,
+		ARRAY_SIZE(mt_irq_sec_array));
+}
diff --git a/plat/mediatek/mt8173/plat_pm.c b/plat/mediatek/mt8173/plat_pm.c
new file mode 100644
index 0000000..1b52470
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_pm.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <mcucfg.h>
+#include <mt8173_def.h>
+#include <mt_cpuxgpt.h> /* generic_timer_backup() */
+#include <plat_private.h>
+#include <power_tracer.h>
+#include <rtc.h>
+#include <scu.h>
+#include <spm_hotplug.h>
+#include <spm_mcdi.h>
+#include <spm_suspend.h>
+
+#define MTK_PWR_LVL0	0
+#define MTK_PWR_LVL1	1
+#define MTK_PWR_LVL2	2
+
+/* Macros to read the MTK power domain state */
+#define MTK_CORE_PWR_STATE(state)	(state)->pwr_domain_state[MTK_PWR_LVL0]
+#define MTK_CLUSTER_PWR_STATE(state)	(state)->pwr_domain_state[MTK_PWR_LVL1]
+#define MTK_SYSTEM_PWR_STATE(state)	((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) ?\
+			(state)->pwr_domain_state[MTK_PWR_LVL2] : 0)
+
+#if PSCI_EXTENDED_STATE_ID
+/*
+ *  The table storing the valid idle power states. Ensure that the
+ *  array entries are populated in ascending order of state-id to
+ *  enable us to use binary search during power state validation.
+ *  The table must be terminated by a NULL entry.
+ */
+const unsigned int mtk_pm_idle_states[] = {
+	/* State-id - 0x001 */
+	mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN,
+		MTK_LOCAL_STATE_RET, MTK_PWR_LVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x002 */
+	mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN,
+		MTK_LOCAL_STATE_OFF, MTK_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x022 */
+	mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF,
+		MTK_LOCAL_STATE_OFF, MTK_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+#if PLAT_MAX_PWR_LVL > MTK_PWR_LVL1
+	/* State-id - 0x222 */
+	mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF,
+		MTK_LOCAL_STATE_OFF, MTK_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
+#endif
+	0,
+};
+#endif
+
+struct core_context {
+	unsigned long timer_data[8];
+	unsigned int count;
+	unsigned int rst;
+	unsigned int abt;
+	unsigned int brk;
+};
+
+struct cluster_context {
+	struct core_context core[PLATFORM_MAX_CPUS_PER_CLUSTER];
+};
+
+/*
+ * Top level structure to hold the complete context of a multi cluster system
+ */
+struct system_context {
+	struct cluster_context cluster[PLATFORM_CLUSTER_COUNT];
+};
+
+/*
+ * Top level structure which encapsulates the context of the entire system
+ */
+static struct system_context dormant_data[1];
+
+static inline struct cluster_context *system_cluster(
+						struct system_context *system,
+						uint32_t clusterid)
+{
+	return &system->cluster[clusterid];
+}
+
+static inline struct core_context *cluster_core(struct cluster_context *cluster,
+						uint32_t cpuid)
+{
+	return &cluster->core[cpuid];
+}
+
+static struct cluster_context *get_cluster_data(unsigned long mpidr)
+{
+	uint32_t clusterid;
+
+	clusterid = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	return system_cluster(dormant_data, clusterid);
+}
+
+static struct core_context *get_core_data(unsigned long mpidr)
+{
+	struct cluster_context *cluster;
+	uint32_t cpuid;
+
+	cluster = get_cluster_data(mpidr);
+	cpuid = mpidr & MPIDR_CPU_MASK;
+
+	return cluster_core(cluster, cpuid);
+}
+
+static void mt_save_generic_timer(unsigned long *container)
+{
+	uint64_t ctl;
+	uint64_t val;
+
+	__asm__ volatile("mrs	%x0, cntkctl_el1\n\t"
+			 "mrs	%x1, cntp_cval_el0\n\t"
+			 "stp	%x0, %x1, [%2, #0]"
+			 : "=&r" (ctl), "=&r" (val)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("mrs	%x0, cntp_tval_el0\n\t"
+			 "mrs	%x1, cntp_ctl_el0\n\t"
+			 "stp	%x0, %x1, [%2, #16]"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("mrs	%x0, cntv_tval_el0\n\t"
+			 "mrs	%x1, cntv_ctl_el0\n\t"
+			 "stp	%x0, %x1, [%2, #32]"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+}
+
+static void mt_restore_generic_timer(unsigned long *container)
+{
+	uint64_t ctl;
+	uint64_t val;
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #0]\n\t"
+			 "msr	cntkctl_el1, %x0\n\t"
+			 "msr	cntp_cval_el0, %x1"
+			 : "=&r" (ctl), "=&r" (val)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #16]\n\t"
+			 "msr	cntp_tval_el0, %x0\n\t"
+			 "msr	cntp_ctl_el0, %x1"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #32]\n\t"
+			 "msr	cntv_tval_el0, %x0\n\t"
+			 "msr	cntv_ctl_el0, %x1"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+}
+
+static inline uint64_t read_cntpctl(void)
+{
+	uint64_t cntpctl;
+
+	__asm__ volatile("mrs	%x0, cntp_ctl_el0"
+			 : "=r" (cntpctl) : : "memory");
+
+	return cntpctl;
+}
+
+static inline void write_cntpctl(uint64_t cntpctl)
+{
+	__asm__ volatile("msr	cntp_ctl_el0, %x0" : : "r"(cntpctl));
+}
+
+static void stop_generic_timer(void)
+{
+	/*
+	 * Disable the timer and mask the irq to prevent
+	 * suprious interrupts on this cpu interface. It
+	 * will bite us when we come back if we don't. It
+	 * will be replayed on the inbound cluster.
+	 */
+	uint64_t cntpctl = read_cntpctl();
+
+	write_cntpctl(clr_cntp_ctl_enable(cntpctl));
+}
+
+static void mt_cpu_save(unsigned long mpidr)
+{
+	struct core_context *core;
+
+	core = get_core_data(mpidr);
+	mt_save_generic_timer(core->timer_data);
+
+	/* disable timer irq, and upper layer should enable it again. */
+	stop_generic_timer();
+}
+
+static void mt_cpu_restore(unsigned long mpidr)
+{
+	struct core_context *core;
+
+	core = get_core_data(mpidr);
+	mt_restore_generic_timer(core->timer_data);
+}
+
+static void mt_platform_save_context(unsigned long mpidr)
+{
+	/* mcusys_save_context: */
+	mt_cpu_save(mpidr);
+}
+
+static void mt_platform_restore_context(unsigned long mpidr)
+{
+	/* mcusys_restore_context: */
+	mt_cpu_restore(mpidr);
+}
+
+static void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+	unsigned int scr;
+
+	scr = read_scr_el3();
+	write_scr_el3(scr | SCR_IRQ_BIT);
+	isb();
+	dsb();
+	wfi();
+	write_scr_el3(scr);
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * on. The level and mpidr determine the affinity instance.
+ ******************************************************************************/
+static uintptr_t secure_entrypoint;
+
+static int plat_power_domain_on(unsigned long mpidr)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned long cpu_id;
+	unsigned long cluster_id;
+	uintptr_t rv;
+
+	cpu_id = mpidr & MPIDR_CPU_MASK;
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		rv = (uintptr_t)&mt8173_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw;
+	else
+		rv = (uintptr_t)&mt8173_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw;
+
+	mmio_write_32(rv, secure_entrypoint);
+	INFO("mt_on[%ld:%ld], entry %x\n",
+		cluster_id, cpu_id, mmio_read_32(rv));
+
+	spm_hotplug_on(mpidr);
+	return rc;
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * off. The level and mpidr determine the affinity instance. The 'state' arg.
+ * allows the platform to decide whether the cluster is being turned off and
+ * take apt actions.
+ *
+ * CAUTION: This function is called with coherent stacks so that caches can be
+ * turned off, flushed and coherency disabled. There is no guarantee that caches
+ * will remain turned on across calls to this function as each affinity level is
+ * dealt with. So do not write & read global variables across calls. It will be
+ * wise to do flush a write to the global to prevent unpredictable results.
+ ******************************************************************************/
+static void plat_power_domain_off(const psci_power_state_t *state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	gicv2_cpuif_disable();
+
+	spm_hotplug_off(mpidr);
+
+	trace_power_flow(mpidr, CPU_DOWN);
+
+	if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) {
+		/* Disable coherency if this cluster is to be turned off */
+		plat_cci_disable();
+
+		trace_power_flow(mpidr, CLUSTER_DOWN);
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be
+ * suspended. The level and mpidr determine the affinity instance. The 'state'
+ * arg. allows the platform to decide whether the cluster is being turned off
+ * and take apt actions.
+ *
+ * CAUTION: This function is called with coherent stacks so that caches can be
+ * turned off, flushed and coherency disabled. There is no guarantee that caches
+ * will remain turned on across calls to this function as each affinity level is
+ * dealt with. So do not write & read global variables across calls. It will be
+ * wise to do flush a write to the global to prevent unpredictable results.
+ ******************************************************************************/
+static void plat_power_domain_suspend(const psci_power_state_t *state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned long cluster_id;
+	unsigned long cpu_id;
+	uintptr_t rv;
+
+	cpu_id = mpidr & MPIDR_CPU_MASK;
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		rv = (uintptr_t)&mt8173_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw;
+	else
+		rv = (uintptr_t)&mt8173_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw;
+
+	mmio_write_32(rv, secure_entrypoint);
+
+	if (MTK_SYSTEM_PWR_STATE(state) != MTK_LOCAL_STATE_OFF) {
+		spm_mcdi_prepare_for_off_state(mpidr, MTK_PWR_LVL0);
+		if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF)
+			spm_mcdi_prepare_for_off_state(mpidr, MTK_PWR_LVL1);
+	}
+
+	mt_platform_save_context(mpidr);
+
+	/* Perform the common cluster specific operations */
+	if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) {
+		/* Disable coherency if this cluster is to be turned off */
+		plat_cci_disable();
+	}
+
+	if (MTK_SYSTEM_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) {
+		disable_scu(mpidr);
+		generic_timer_backup();
+		spm_system_suspend();
+		/* Prevent interrupts from spuriously waking up this cpu */
+		gicv2_cpuif_disable();
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance has just been powered
+ * on after being turned off earlier. The level and mpidr determine the affinity
+ * instance. The 'state' arg. allows the platform to decide whether the cluster
+ * was turned off prior to wakeup and do what's necessary to setup it up
+ * correctly.
+ ******************************************************************************/
+void mtk_system_pwr_domain_resume(void);
+
+static void plat_power_domain_on_finish(const psci_power_state_t *state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF);
+
+	if ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) &&
+		(state->pwr_domain_state[MTK_PWR_LVL2] == MTK_LOCAL_STATE_OFF))
+		mtk_system_pwr_domain_resume();
+
+	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
+		plat_cci_enable();
+		trace_power_flow(mpidr, CLUSTER_UP);
+	}
+
+	if ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) &&
+		(state->pwr_domain_state[MTK_PWR_LVL2] == MTK_LOCAL_STATE_OFF))
+		return;
+
+	/* Enable the gic cpu interface */
+	gicv2_cpuif_enable();
+	gicv2_pcpu_distif_init();
+	trace_power_flow(mpidr, CPU_UP);
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance has just been powered
+ * on after having been suspended earlier. The level and mpidr determine the
+ * affinity instance.
+ ******************************************************************************/
+static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	if (state->pwr_domain_state[MTK_PWR_LVL0] == MTK_LOCAL_STATE_RET)
+		return;
+
+	if (MTK_SYSTEM_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) {
+		/* Enable the gic cpu interface */
+		plat_arm_gic_init();
+		spm_system_suspend_finish();
+		enable_scu(mpidr);
+	}
+
+	/* Perform the common cluster specific operations */
+	if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) {
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+	}
+
+	mt_platform_restore_context(mpidr);
+
+	if (MTK_SYSTEM_PWR_STATE(state) != MTK_LOCAL_STATE_OFF) {
+		spm_mcdi_finish_for_on_state(mpidr, MTK_PWR_LVL0);
+		if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF)
+			spm_mcdi_finish_for_on_state(mpidr, MTK_PWR_LVL1);
+	}
+
+	gicv2_pcpu_distif_init();
+}
+
+static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	assert(PLAT_MAX_PWR_LVL >= 2);
+
+	for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF;
+}
+
+/*******************************************************************************
+ * MTK handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 plat_system_off(void)
+{
+	INFO("MTK System Off\n");
+
+	rtc_bbpu_power_down();
+
+	wfi();
+	ERROR("MTK System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 plat_system_reset(void)
+{
+	/* Write the System Configuration Control Register */
+	INFO("MTK System Reset\n");
+
+	mmio_clrsetbits_32(MTK_WDT_BASE,
+		(MTK_WDT_MODE_DUAL_MODE | MTK_WDT_MODE_IRQ),
+		MTK_WDT_MODE_KEY);
+	mmio_setbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN));
+	mmio_setbits_32(MTK_WDT_SWRST, MTK_WDT_SWRST_KEY);
+
+	wfi();
+	ERROR("MTK System Reset: operation not handled.\n");
+	panic();
+}
+
+#if !PSCI_EXTENDED_STATE_ID
+static int plat_validate_power_state(unsigned int power_state,
+					psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != 0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MTK_PWR_LVL0] =
+					MTK_LOCAL_STATE_RET;
+	} else {
+		for (i = 0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					MTK_LOCAL_STATE_OFF;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+#else
+int plat_validate_power_state(unsigned int power_state,
+				psci_power_state_t *req_state)
+{
+	unsigned int state_id;
+	int i;
+
+	assert(req_state);
+
+	/*
+	 *  Currently we are using a linear search for finding the matching
+	 *  entry in the idle power state array. This can be made a binary
+	 *  search if the number of entries justify the additional complexity.
+	 */
+	for (i = 0; !!mtk_pm_idle_states[i]; i++) {
+		if (power_state == mtk_pm_idle_states[i])
+			break;
+	}
+
+	/* Return error if entry not found in the idle state array */
+	if (!mtk_pm_idle_states[i])
+		return PSCI_E_INVALID_PARAMS;
+
+	i = 0;
+	state_id = psci_get_pstate_id(power_state);
+
+	/* Parse the State ID and populate the state info parameter */
+	while (state_id) {
+		req_state->pwr_domain_state[i++] = state_id &
+						MTK_LOCAL_PSTATE_MASK;
+		state_id >>= MTK_LOCAL_PSTATE_WIDTH;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+#endif
+
+void mtk_system_pwr_domain_resume(void)
+{
+	console_init(MT8173_UART0_BASE, MT8173_UART_CLOCK, MT8173_BAUDRATE);
+
+	/* Assert system power domain is available on the platform */
+	assert(PLAT_MAX_PWR_LVL >= MTK_PWR_LVL2);
+
+	plat_arm_gic_init();
+}
+
+static const plat_psci_ops_t plat_plat_pm_ops = {
+	.cpu_standby			= plat_cpu_standby,
+	.pwr_domain_on			= plat_power_domain_on,
+	.pwr_domain_on_finish		= plat_power_domain_on_finish,
+	.pwr_domain_off			= plat_power_domain_off,
+	.pwr_domain_suspend		= plat_power_domain_suspend,
+	.pwr_domain_suspend_finish	= plat_power_domain_suspend_finish,
+	.system_off			= plat_system_off,
+	.system_reset			= plat_system_reset,
+	.validate_power_state		= plat_validate_power_state,
+	.get_sys_suspend_power_state	= plat_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &plat_plat_pm_ops;
+	secure_entrypoint = sec_entrypoint;
+	return 0;
+}
+
+/*
+ * The PSCI generic code uses this API to let the platform participate in state
+ * coordination during a power management operation. It compares the platform
+ * specific local power states requested by each cpu for a given power domain
+ * and returns the coordinated target power state that the domain should
+ * enter. A platform assigns a number to a local power state. This default
+ * implementation assumes that the platform assigns these numbers in order of
+ * increasing depth of the power state i.e. for two power states X & Y, if X < Y
+ * then X represents a shallower power state than Y. As a result, the
+ * coordinated target local power state for a power domain will be the minimum
+ * of the requested local power states.
+ */
+plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	plat_local_state_t target = PLAT_MAX_OFF_STATE, temp;
+
+	assert(ncpu);
+
+	do {
+		temp = *states++;
+		if (temp < target)
+			target = temp;
+	} while (--ncpu);
+
+	return target;
+}
diff --git a/plat/mediatek/mt8173/plat_sip_calls.c b/plat/mediatek/mt8173/plat_sip_calls.c
new file mode 100644
index 0000000..102feb2
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_sip_calls.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <crypt.h>
+#include <mtcmos.h>
+#include <mtk_sip_svc.h>
+#include <plat_sip_calls.h>
+
+/* Authorized secure register list */
+enum {
+	SREG_HDMI_COLOR_EN = 0x14000904
+};
+
+static const uint32_t authorized_sreg[] = {
+	SREG_HDMI_COLOR_EN
+};
+
+#define authorized_sreg_cnt	\
+	(sizeof(authorized_sreg) / sizeof(authorized_sreg[0]))
+
+uint64_t mt_sip_set_authorized_sreg(uint32_t sreg, uint32_t val)
+{
+	uint64_t i;
+
+	for (i = 0; i < authorized_sreg_cnt; i++) {
+		if (authorized_sreg[i] == sreg) {
+			mmio_write_32(sreg, val);
+			return MTK_SIP_E_SUCCESS;
+		}
+	}
+
+	return MTK_SIP_E_INVALID_PARAM;
+}
+
+static uint64_t mt_sip_pwr_on_mtcmos(uint32_t val)
+{
+	uint32_t ret;
+
+	ret = mtcmos_non_cpu_ctrl(1, val);
+	if (ret)
+		return MTK_SIP_E_INVALID_PARAM;
+	else
+		return MTK_SIP_E_SUCCESS;
+}
+
+static uint64_t mt_sip_pwr_off_mtcmos(uint32_t val)
+{
+	uint32_t ret;
+
+	ret = mtcmos_non_cpu_ctrl(0, val);
+	if (ret)
+		return MTK_SIP_E_INVALID_PARAM;
+	else
+		return MTK_SIP_E_SUCCESS;
+}
+
+static uint64_t mt_sip_pwr_mtcmos_support(void)
+{
+	return MTK_SIP_E_SUCCESS;
+}
+
+uint64_t mediatek_plat_sip_handler(uint32_t smc_fid,
+				   uint64_t x1,
+				   uint64_t x2,
+				   uint64_t x3,
+				   uint64_t x4,
+				   void *cookie,
+				   void *handle,
+				   uint64_t flags)
+{
+	uint64_t ret;
+
+	switch (smc_fid) {
+	case MTK_SIP_PWR_ON_MTCMOS:
+		ret = mt_sip_pwr_on_mtcmos((uint32_t)x1);
+		SMC_RET1(handle, ret);
+
+	case MTK_SIP_PWR_OFF_MTCMOS:
+		ret = mt_sip_pwr_off_mtcmos((uint32_t)x1);
+		SMC_RET1(handle, ret);
+
+	case MTK_SIP_PWR_MTCMOS_SUPPORT:
+		ret = mt_sip_pwr_mtcmos_support();
+		SMC_RET1(handle, ret);
+
+	case MTK_SIP_SET_HDCP_KEY_EX:
+		ret = crypt_set_hdcp_key_ex(x1, x2, x3);
+		SMC_RET1(handle, ret);
+
+	case MTK_SIP_SET_HDCP_KEY_NUM:
+		ret = crypt_set_hdcp_key_num((uint32_t)x1);
+		SMC_RET1(handle, ret);
+
+	case MTK_SIP_CLR_HDCP_KEY:
+		ret = crypt_clear_hdcp_key();
+		SMC_RET1(handle, ret);
+
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/mediatek/mt8173/plat_topology.c b/plat/mediatek/mt8173/plat_topology.c
new file mode 100644
index 0000000..23e7d2d
--- /dev/null
+++ b/plat/mediatek/mt8173/plat_topology.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+const unsigned char mtk_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	/* No of children for the second cluster node */
+	PLATFORM_CLUSTER1_CORE_COUNT
+};
+
+/*******************************************************************************
+ * This function returns the MT8173 default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return mtk_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/mediatek/mt8173/platform.mk b/plat/mediatek/mt8173/platform.mk
new file mode 100644
index 0000000..24e4ec6
--- /dev/null
+++ b/plat/mediatek/mt8173/platform.mk
@@ -0,0 +1,70 @@
+#
+# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MTK_PLAT		:=	plat/mediatek
+MTK_PLAT_SOC		:=	${MTK_PLAT}/${PLAT}
+
+PLAT_INCLUDES		:=	-I${MTK_PLAT}/common/				\
+				-I${MTK_PLAT}/common/drivers/uart/		\
+				-Iinclude/plat/arm/common/aarch64		\
+				-I${MTK_PLAT_SOC}/drivers/crypt/		\
+				-I${MTK_PLAT_SOC}/drivers/mtcmos/		\
+				-I${MTK_PLAT_SOC}/drivers/pmic/			\
+				-I${MTK_PLAT_SOC}/drivers/rtc/			\
+				-I${MTK_PLAT_SOC}/drivers/spm/			\
+				-I${MTK_PLAT_SOC}/drivers/timer/		\
+				-I${MTK_PLAT_SOC}/include/
+
+PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				plat/arm/common/arm_gicv2.c			\
+				plat/common/plat_gicv2.c
+
+BL31_SOURCES		+=	common/desc_image_load.c			\
+				drivers/arm/cci/cci.c				\
+				drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				drivers/console/aarch64/console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				lib/cpus/aarch64/aem_generic.S			\
+				lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a57.S			\
+				lib/cpus/aarch64/cortex_a72.S			\
+				${MTK_PLAT}/common/drivers/uart/8250_console.S	\
+				${MTK_PLAT}/common/mtk_plat_common.c		\
+				${MTK_PLAT}/common/mtk_sip_svc.c		\
+				${MTK_PLAT_SOC}/aarch64/plat_helpers.S		\
+				${MTK_PLAT_SOC}/aarch64/platform_common.c	\
+				${MTK_PLAT_SOC}/bl31_plat_setup.c		\
+				${MTK_PLAT_SOC}/drivers/crypt/crypt.c		\
+				${MTK_PLAT_SOC}/drivers/mtcmos/mtcmos.c		\
+				${MTK_PLAT_SOC}/drivers/pmic/pmic_wrap_init.c	\
+				${MTK_PLAT_SOC}/drivers/rtc/rtc.c		\
+				${MTK_PLAT_SOC}/drivers/spm/spm.c		\
+				${MTK_PLAT_SOC}/drivers/spm/spm_hotplug.c	\
+				${MTK_PLAT_SOC}/drivers/spm/spm_mcdi.c		\
+				${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c	\
+				${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c	\
+				${MTK_PLAT_SOC}/plat_pm.c			\
+				${MTK_PLAT_SOC}/plat_sip_calls.c		\
+				${MTK_PLAT_SOC}/plat_topology.c			\
+				${MTK_PLAT_SOC}/power_tracer.c			\
+				${MTK_PLAT_SOC}/scu.c
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_826319	:=	1
+ERRATA_A53_836870	:=	1
+ERRATA_A53_855873	:=	1
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+
+$(eval $(call add_define,MTK_SIP_SET_AUTHORIZED_SECURE_REG_ENABLE))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS		:=	0
diff --git a/plat/mediatek/mt8173/power_tracer.c b/plat/mediatek/mt8173/power_tracer.c
new file mode 100644
index 0000000..d1fcf9f
--- /dev/null
+++ b/plat/mediatek/mt8173/power_tracer.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+
+#include <power_tracer.h>
+
+#define trace_log(...)  INFO("psci: " __VA_ARGS__)
+
+void trace_power_flow(unsigned long mpidr, unsigned char mode)
+{
+	switch (mode) {
+	case CPU_UP:
+		trace_log("core %lld:%lld ON\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CPU_DOWN:
+		trace_log("core %lld:%lld OFF\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CPU_SUSPEND:
+		trace_log("core %lld:%lld SUSPEND\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CLUSTER_UP:
+		trace_log("cluster %lld ON\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	case CLUSTER_DOWN:
+		trace_log("cluster %lld OFF\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	case CLUSTER_SUSPEND:
+		trace_log("cluster %lld SUSPEND\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	default:
+		trace_log("unknown power mode\n");
+		break;
+	}
+}
diff --git a/plat/mediatek/mt8173/scu.c b/plat/mediatek/mt8173/scu.c
new file mode 100644
index 0000000..2524d72
--- /dev/null
+++ b/plat/mediatek/mt8173/scu.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+
+void disable_scu(unsigned long mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_miscdbg,
+			MP1_ACINACTM);
+	else
+		mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp0_axi_config,
+			MP0_ACINACTM);
+}
+
+void enable_scu(unsigned long mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		mmio_clrbits_32((uintptr_t)&mt8173_mcucfg->mp1_miscdbg,
+			MP1_ACINACTM);
+	else
+		mmio_clrbits_32((uintptr_t)&mt8173_mcucfg->mp0_axi_config,
+			MP0_ACINACTM);
+}
diff --git a/plat/mediatek/mt8183/aarch64/plat_helpers.S b/plat/mediatek/mt8183/aarch64/plat_helpers.S
new file mode 100644
index 0000000..5c39633
--- /dev/null
+++ b/plat/mediatek/mt8183/aarch64/plat_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl plat_is_my_cpu_primary
+	.globl plat_my_core_pos
+
+func plat_is_my_cpu_primary
+	mrs x0, mpidr_el1
+	and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp x0, #PLAT_PRIMARY_CPU
+	cset x0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_my_core_pos(void);
+	 *
+	 * result: CorePos = CoreId + (ClusterId << 2)
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs     x0, mpidr_el1
+	and     x1, x0, #MPIDR_CPU_MASK
+	and     x0, x0, #MPIDR_CLUSTER_MASK
+	add     x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
diff --git a/plat/mediatek/mt8183/aarch64/platform_common.c b/plat/mediatek/mt8183/aarch64/platform_common.c
new file mode 100644
index 0000000..31d1339
--- /dev/null
+++ b/plat/mediatek/mt8183/aarch64/platform_common.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <mcsi/mcsi.h>
+#include <platform_def.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+static const int cci_map[] = {
+	PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+/* Table of regions to map using the MMU.  */
+const mmap_region_t plat_mmap[] = {
+	/* for TF text, RO, RW */
+	MAP_REGION_FLAT(TZRAM_BASE, TZRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG2_BASE, MTK_DEV_RNG2_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+/*******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+void plat_configure_mmu_el3(uintptr_t total_base,
+			    uintptr_t total_size,
+			    uintptr_t ro_start,
+			    uintptr_t ro_limit,
+			    uintptr_t coh_start,
+			    uintptr_t coh_limit)
+{
+	mmap_add_region(total_base, total_base, total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+			MT_MEMORY | MT_RO | MT_SECURE);
+	mmap_add_region(coh_start, coh_start, coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+	mmap_add(plat_mmap);
+	init_xlat_tables();
+	enable_mmu_el3(0);
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void plat_mtk_cci_init(void)
+{
+	/* Initialize CCI driver */
+	mcsi_init(PLAT_MT_CCI_BASE, ARRAY_SIZE(cci_map));
+}
+
+void plat_mtk_cci_enable(void)
+{
+	/* Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+	cci_enable_cluster_coherency(read_mpidr());
+}
+
+void plat_mtk_cci_disable(void)
+{
+	cci_disable_cluster_coherency(read_mpidr());
+}
+
+void plat_mtk_cci_init_sf(void)
+{
+	/* Init mcsi snoop filter. */
+	cci_init_sf();
+}
diff --git a/plat/mediatek/mt8183/bl31_plat_setup.c b/plat/mediatek/mt8183/bl31_plat_setup.c
new file mode 100644
index 0000000..e623e96
--- /dev/null
+++ b/plat/mediatek/mt8183/bl31_plat_setup.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/common_def.h>
+#include <drivers/console.h>
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <mcucfg.h>
+#include <mt_gic_v3.h>
+#include <lib/mmio.h>
+#include <mtk_plat_common.h>
+#include <plat_debug.h>
+#include <plat_private.h>
+#include <platform_def.h>
+#include <scu.h>
+#include <drivers/ti/uart/uart_16550.h>
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+static void platform_setup_cpu(void)
+{
+	mmio_write_32((uintptr_t)&mt8183_mcucfg->mp0_rw_rsvd0, 0x00000001);
+
+	VERBOSE("addr of cci_adb400_dcm_config: 0x%x\n",
+		mmio_read_32((uintptr_t)&mt8183_mcucfg->cci_adb400_dcm_config));
+	VERBOSE("addr of sync_dcm_config: 0x%x\n",
+		mmio_read_32((uintptr_t)&mt8183_mcucfg->sync_dcm_config));
+
+	VERBOSE("mp0_spmc: 0x%x\n",
+		mmio_read_32((uintptr_t)&mt8183_mcucfg->mp0_cputop_spmc_ctl));
+	VERBOSE("mp1_spmc: 0x%x\n",
+		mmio_read_32((uintptr_t)&mt8183_mcucfg->mp1_cputop_spmc_ctl));
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+	assert(next_image_info->h.type == PARAM_EP);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	static console_16550_t console;
+
+	console_16550_register(UART0_BASE, UART_CLOCK, UART_BAUDRATE, &console);
+
+	NOTICE("MT8183 bl31_setup\n");
+
+	bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info);
+}
+
+
+/*******************************************************************************
+ * Perform any BL31 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+	platform_setup_cpu();
+	generic_delay_timer_init();
+
+	/* Initialize the GIC driver, CPU and distributor interfaces */
+	mt_gic_driver_init();
+	mt_gic_init();
+
+	/* Init mcsi SF */
+	plat_mtk_cci_init_sf();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	plat_mtk_cci_init();
+	plat_mtk_cci_enable();
+
+	enable_scu(read_mpidr());
+
+	plat_configure_mmu_el3(BL_CODE_BASE,
+			       BL_COHERENT_RAM_END - BL_CODE_BASE,
+			       BL_CODE_BASE,
+			       BL_CODE_END,
+			       BL_COHERENT_RAM_BASE,
+			       BL_COHERENT_RAM_END);
+}
diff --git a/plat/mediatek/mt8183/drivers/mcsi/mcsi.c b/plat/mediatek/mt8183/drivers/mcsi/mcsi.c
new file mode 100644
index 0000000..cbe7f0a
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/mcsi/mcsi.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <scu.h>
+#include <mcucfg.h>
+#include <drivers/delay_timer.h>
+#include <mcsi/mcsi.h>
+
+#define MAX_CLUSTERS		5
+
+static unsigned long cci_base_addr;
+static unsigned int cci_cluster_ix_to_iface[MAX_CLUSTERS];
+
+void mcsi_init(unsigned long cci_base,
+		unsigned int num_cci_masters)
+{
+	int i;
+
+	assert(cci_base);
+	assert(num_cci_masters < MAX_CLUSTERS);
+
+	cci_base_addr = cci_base;
+
+	for (i = 0; i < num_cci_masters; i++)
+		cci_cluster_ix_to_iface[i] = SLAVE_IFACE_OFFSET(i);
+}
+
+void mcsi_cache_flush(void)
+{
+	/* timeout is 10ms */
+	int timeout = 10000;
+
+	/* to make flush by SF safe, need to disable BIU DCM */
+	mmio_clrbits_32(CCI_CLK_CTRL, 1 << 8);
+	mmio_write_32(cci_base_addr + FLUSH_SF, 0x1);
+
+	for (; timeout; timeout--, udelay(1)) {
+		if ((mmio_read_32(cci_base_addr + FLUSH_SF) & 0x1) == 0x0)
+			break;
+	}
+
+	if (!timeout) {
+		INFO("SF lush timeout\n");
+		return;
+	}
+
+	/* enable BIU DCM as it was */
+	mmio_setbits_32(CCI_CLK_CTRL, 1 << 8);
+}
+
+static inline unsigned long get_slave_iface_base(unsigned long mpidr)
+{
+	/*
+	 * We assume the TF topology code allocates affinity instances
+	 * consecutively from zero.
+	 * It is a programming error if this is called without initializing
+	 * the slave interface to use for this cluster.
+	 */
+	unsigned int cluster_id =
+		(mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	assert(cluster_id < MAX_CLUSTERS);
+	assert(cci_cluster_ix_to_iface[cluster_id] != 0);
+
+	return cci_base_addr + cci_cluster_ix_to_iface[cluster_id];
+}
+
+void cci_enable_cluster_coherency(unsigned long mpidr)
+{
+	unsigned long slave_base;
+	unsigned int support_ability;
+	unsigned int config = 0;
+	unsigned int pending = 0;
+
+	assert(cci_base_addr);
+	slave_base  = get_slave_iface_base(mpidr);
+	support_ability = mmio_read_32(slave_base);
+
+	pending = (mmio_read_32(
+		   cci_base_addr + SNP_PENDING_REG)) >> SNP_PENDING;
+	while (pending) {
+		pending = (mmio_read_32(
+			   cci_base_addr + SNP_PENDING_REG)) >> SNP_PENDING;
+	}
+
+	if (support_ability & SNP_SUPPORT)
+		config |= SNOOP_EN_BIT;
+	if (support_ability & DVM_SUPPORT)
+		config |= DVM_EN_BIT;
+
+	mmio_write_32(slave_base, support_ability | config);
+
+	/* Wait for the dust to settle down */
+	while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING)
+		;
+}
+
+#if ERRATA_MCSIB_SW
+#pragma weak mcsib_sw_workaround_main
+#endif
+
+void cci_disable_cluster_coherency(unsigned long mpidr)
+{
+	unsigned long slave_base;
+	unsigned int config = 0;
+
+	assert(cci_base_addr);
+	slave_base = get_slave_iface_base(mpidr);
+
+	while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING)
+		;
+
+	config = mmio_read_32(slave_base);
+	config &= ~(DVM_EN_BIT | SNOOP_EN_BIT);
+
+	/* Disable Snoops and DVM messages */
+	mmio_write_32(slave_base, config);
+
+#if ERRATA_MCSIB_SW
+	mcsib_sw_workaround_main();
+#endif
+
+	/* Wait for the dust to settle down */
+	while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING)
+		;
+}
+
+void cci_secure_switch(unsigned int status)
+{
+	unsigned int config;
+
+	config = mmio_read_32(cci_base_addr + CENTRAL_CTRL_REG);
+	if (status == NS_ACC)
+		config |= SECURE_ACC_EN;
+	else
+		config &= ~SECURE_ACC_EN;
+	mmio_write_32(cci_base_addr + CENTRAL_CTRL_REG, config);
+}
+
+void cci_pmu_secure_switch(unsigned int status)
+{
+	unsigned int config;
+
+	config = mmio_read_32(cci_base_addr + CENTRAL_CTRL_REG);
+	if (status == NS_ACC)
+		config |= PMU_SECURE_ACC_EN;
+	else
+		config &= ~PMU_SECURE_ACC_EN;
+	mmio_write_32(cci_base_addr + CENTRAL_CTRL_REG, config);
+}
+
+void cci_init_sf(void)
+{
+	while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING)
+		;
+	/* init sf1 */
+	mmio_write_32(cci_base_addr + SF_INIT_REG, TRIG_SF1_INIT);
+	while (mmio_read_32(cci_base_addr + SF_INIT_REG) & TRIG_SF1_INIT)
+		;
+	while (!(mmio_read_32(cci_base_addr + SF_INIT_REG) & SF1_INIT_DONE))
+		;
+	/* init sf2 */
+	mmio_write_32(cci_base_addr + SF_INIT_REG, TRIG_SF2_INIT);
+	while (mmio_read_32(cci_base_addr + SF_INIT_REG) & TRIG_SF2_INIT)
+		;
+	while (!(mmio_read_32(cci_base_addr + SF_INIT_REG) & SF2_INIT_DONE))
+		;
+}
+
+void cci_interrupt_en(void)
+{
+	mmio_setbits_32(cci_base_addr + CENTRAL_CTRL_REG, INT_EN);
+}
+
+unsigned long cci_reg_access(unsigned int op, unsigned long offset,
+			     unsigned long val)
+{
+	unsigned long ret = 0;
+
+	if ((cci_base_addr == 0) || (offset > MSCI_MEMORY_SZ))
+		panic();
+
+	switch (op) {
+	case MCSI_REG_ACCESS_READ:
+		ret = mmio_read_32(cci_base_addr + offset);
+		break;
+	case MCSI_REG_ACCESS_WRITE:
+		mmio_write_32(cci_base_addr + offset, val);
+		dsb();
+		break;
+	case MCSI_REG_ACCESS_SET_BITMASK:
+		mmio_setbits_32(cci_base_addr + offset, val);
+		dsb();
+		break;
+	case MCSI_REG_ACCESS_CLEAR_BITMASK:
+		mmio_clrbits_32(cci_base_addr + offset, val);
+		dsb();
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
diff --git a/plat/mediatek/mt8183/drivers/mcsi/mcsi.h b/plat/mediatek/mt8183/drivers/mcsi/mcsi.h
new file mode 100644
index 0000000..863e7da
--- /dev/null
+++ b/plat/mediatek/mt8183/drivers/mcsi/mcsi.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCSI_H
+#define MCSI_H
+
+#define SLAVE_IFACE7_OFFSET		0x1700
+#define SLAVE_IFACE6_OFFSET		0x1600
+#define SLAVE_IFACE5_OFFSET		0x1500
+#define SLAVE_IFACE4_OFFSET		0x1400
+#define SLAVE_IFACE3_OFFSET		0x1300
+#define SLAVE_IFACE2_OFFSET		0x1200
+#define SLAVE_IFACE1_OFFSET		0x1100
+#define SLAVE_IFACE0_OFFSET		0x1000
+#define SLAVE_IFACE_OFFSET(index)	(SLAVE_IFACE0_OFFSET + \
+							(0x100 * (index)))
+/* Control and ID register offsets */
+#define CENTRAL_CTRL_REG		0x0
+#define ERR_FLAG_REG			0x4
+#define SF_INIT_REG			0x10
+#define SF_CTRL_REG			0x14
+#define DCM_CTRL_REG			0x18
+#define ERR_FLAG2_REG			0x20
+#define SNP_PENDING_REG			0x28
+#define ACP_PENDING_REG			0x2c
+#define FLUSH_SF			0x500
+#define SYS_CCE_CTRL			0x2000
+#define MST1_CTRL			0x2100
+#define MTS2_CTRL			0x2200
+#define XBAR_ARAW_ARB			0x3000
+#define XBAR_R_ARB			0x3004
+
+/* Slave interface register offsets */
+#define SNOOP_CTRL_REG			0x0
+#define QOS_CTRL_REG			0x4
+#define QOS_OVERRIDE_REG		0x8
+#define QOS_TARGET_REG			0xc
+#define BD_CTRL_REG			0x40
+
+/* Snoop Control register bit definitions */
+#define DVM_SUPPORT			(1U << 31)
+#define SNP_SUPPORT			(1 << 30)
+#define SHAREABLE_OVWRT			(1 << 2)
+#define DVM_EN_BIT			(1 << 1)
+#define SNOOP_EN_BIT			(1 << 0)
+#define SF2_INIT_DONE			(1 << 17)
+#define SF1_INIT_DONE			(1 << 16)
+#define TRIG_SF2_INIT			(1 << 1)
+#define TRIG_SF1_INIT			(1 << 0)
+
+/* Status register bit definitions */
+#define SNP_PENDING			31
+
+/* Status bit */
+#define NS_ACC				1
+#define S_ACC				0
+
+/* Central control register bit definitions */
+#define PMU_SECURE_ACC_EN		(1 << 4)
+#define INT_EN				(1 << 3)
+#define SECURE_ACC_EN			(1 << 2)
+#define DVM_DIS				(1 << 1)
+#define SNOOP_DIS			(1 << 0)
+
+#define MSCI_MEMORY_SZ			(0x10000)
+
+#define MCSI_REG_ACCESS_READ		(0x0)
+#define MCSI_REG_ACCESS_WRITE		(0x1)
+#define MCSI_REG_ACCESS_SET_BITMASK	(0x2)
+#define MCSI_REG_ACCESS_CLEAR_BITMASK	(0x3)
+
+#define NR_MAX_SLV			(7)
+
+/* ICCS */
+#define CACHE_INSTR_EN			(1 << 2)
+#define IDLE_CACHE			(1 << 3)
+#define USE_SHARED_CACHE		(1 << 4)
+#define CACHE_SHARED_PRE_EN		(1 << 5)
+#define CACHE_SHARED_POST_EN		(1 << 6)
+
+#define ACP_PENDING_MASK		(0x1007f)
+
+#define CCI_CLK_CTRL			(MCUCFG_BASE + 0x660)
+
+#ifndef __ASSEMBLER__
+
+#include <plat/common/common_def.h>
+#include <stdint.h>
+
+/* Function declarations */
+
+/*
+ * The MCSI driver must be initialized with the base address of the
+ * MCSI device in the platform memory map, and the cluster indices for
+ * the MCSI slave interfaces 3 and 4 respectively. These are the fully
+ * coherent ACE slave interfaces of MCSI.
+ * The cluster indices must either be 0 or 1, corresponding to the level 1
+ * affinity instance of the mpidr representing the cluster. A negative cluster
+ * index indicates that no cluster is present on that slave interface.
+ */
+void mcsi_init(unsigned long cci_base,
+		unsigned int num_cci_masters);
+void mcsi_cache_flush(void);
+
+void cci_enable_cluster_coherency(unsigned long mpidr);
+void cci_disable_cluster_coherency(unsigned long mpidr);
+
+void cci_secure_switch(unsigned int ns);
+void cci_init_sf(void);
+unsigned long cci_reg_access(unsigned int op, unsigned long offset, unsigned long val);
+
+#endif /* __ASSEMBLER__ */
+#endif /* MCSI_H */
diff --git a/plat/mediatek/mt8183/include/mcucfg.h b/plat/mediatek/mt8183/include/mcucfg.h
new file mode 100644
index 0000000..83ee88f
--- /dev/null
+++ b/plat/mediatek/mt8183/include/mcucfg.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT8183_MCUCFG_H
+#define MT8183_MCUCFG_H
+
+#include <platform_def.h>
+#include <stdint.h>
+
+struct mt8183_mcucfg_regs {
+	uint32_t mp0_ca7l_cache_config;		/* 0x0 */
+	struct {
+		uint32_t mem_delsel0;
+		uint32_t mem_delsel1;
+	} mp0_cpu[4];				/* 0x4 */
+	uint32_t mp0_cache_mem_delsel0;		/* 0x24 */
+	uint32_t mp0_cache_mem_delsel1;		/* 0x28 */
+	uint32_t mp0_axi_config;		/* 0x2C */
+	uint32_t mp0_misc_config[10];		/* 0x30 */
+	uint32_t mp0_ca7l_cfg_dis;		/* 0x58 */
+	uint32_t mp0_ca7l_clken_ctrl;		/* 0x5C */
+	uint32_t mp0_ca7l_rst_ctrl;		/* 0x60 */
+	uint32_t mp0_ca7l_misc_config;		/* 0x64 */
+	uint32_t mp0_ca7l_dbg_pwr_ctrl;		/* 0x68 */
+	uint32_t mp0_rw_rsvd0;			/* 0x6C */
+	uint32_t mp0_rw_rsvd1;			/* 0x70 */
+	uint32_t mp0_ro_rsvd;			/* 0x74 */
+	uint32_t reserved0_0[98];		/* 0x78 */
+	uint32_t mp1_ca7l_cache_config;		/* 0x200 */
+	uint32_t mp1_miscdbg;			/* 0x204 */
+	uint32_t reserved0_1[9];		/* 0x208 */
+	uint32_t mp1_axi_config;		/* 0x22C */
+	uint32_t mp1_misc_config[10];		/* 0x230 */
+	uint32_t reserved0_2[3];		/* 0x258 */
+	uint32_t mp1_ca7l_misc_config;		/* 0x264 */
+	uint32_t reserved0_3[310];		/* 0x268 */
+	uint32_t cci_adb400_dcm_config;		/* 0x740 */
+	uint32_t sync_dcm_config;		/* 0x744 */
+	uint32_t reserved0_4[16];		/* 0x748 */
+	uint32_t mp0_cputop_spmc_ctl;		/* 0x788 */
+	uint32_t mp1_cputop_spmc_ctl;		/* 0x78C */
+	uint32_t mp1_cputop_spmc_sram_ctl;	/* 0x790 */
+	uint32_t reserved0_5[23];		/* 0x794 */
+	uint32_t l2_cfg_mp0;			/* 0x7F0 */
+	uint32_t l2_cfg_mp1;			/* 0x7F4 */
+	uint32_t reserved0_6[1282];		/* 0x7F8 */
+	uint32_t cpusys0_sparkvretcntrl;	/* 0x1C00 */
+	uint32_t cpusys0_sparken;		/* 0x1C04 */
+	uint32_t cpusys0_amuxsel;		/* 0x1C08 */
+	uint32_t reserved0_7[9];		/* 0x1C0C */
+	uint32_t cpusys0_cpu0_spmc_ctl;		/* 0x1C30 */
+	uint32_t cpusys0_cpu1_spmc_ctl;		/* 0x1C34 */
+	uint32_t cpusys0_cpu2_spmc_ctl;		/* 0x1C38 */
+	uint32_t cpusys0_cpu3_spmc_ctl;		/* 0x1C3C */
+	uint32_t reserved0_8[370];		/* 0x1C40 */
+	uint32_t mp2_cpucfg;			/* 0x2208 */
+	uint32_t mp2_axi_config;		/* 0x220C */
+	uint32_t reserved0_9[36];		/* 0x2210 */
+	uint32_t mp2_cputop_spm_ctl;		/* 0x22A0 */
+	uint32_t mp2_cputop_spm_sta;		/* 0x22A4 */
+	uint32_t reserved0_10[98];		/* 0x22A8 */
+	uint32_t cpusys2_cpu0_spmc_ctl;		/* 0x2430 */
+	uint32_t cpusys2_cpu0_spmc_sta;		/* 0x2434 */
+	uint32_t cpusys2_cpu1_spmc_ctl;		/* 0x2438 */
+	uint32_t cpusys2_cpu1_spmc_sta;		/* 0x243C */
+	uint32_t reserved0_11[176];		/* 0x2440 */
+	uint32_t spark2ld0;			/* 0x2700 */
+	uint32_t reserved0_12[1355];		/* 0x2704 */
+	uint32_t cpusys1_cpu0_spmc_ctl;		/* 0x3C30 */
+	uint32_t cpusys1_cpu1_spmc_ctl;		/* 0x3C34 */
+	uint32_t cpusys1_cpu2_spmc_ctl;		/* 0x3C38 */
+	uint32_t cpusys1_cpu3_spmc_ctl;		/* 0x3C3C */
+};
+
+static struct mt8183_mcucfg_regs *const mt8183_mcucfg = (void *)MCUCFG_BASE;
+
+enum {
+	SW_SPARK_EN = 1 << 0,
+	SW_NO_WAIT_FOR_Q_CHANNEL = 1 << 1,
+	SW_FSM_OVERRIDE = 1 << 2,
+	SW_LOGIC_PRE1_PDB = 1 << 3,
+	SW_LOGIC_PRE2_PDB = 1 << 4,
+	SW_LOGIC_PDB = 1 << 5,
+	SW_ISO = 1 << 6,
+	SW_SRAM_SLEEPB = 0x3f << 7,
+	SW_SRAM_ISOINTB = 1 << 13,
+	SW_CLK_DIS = 1 << 14,
+	SW_CKISO = 1 << 15,
+	SW_PD = 0x3f << 16,
+	SW_HOT_PLUG_RESET = 1 << 22,
+	SW_PWR_ON_OVERRIDE_EN = 1 << 23,
+	SW_PWR_ON = 1 << 24,
+	SW_COQ_DIS = 1 << 25,
+	LOGIC_PDBO_ALL_OFF_ACK = 1 << 26,
+	LOGIC_PDBO_ALL_ON_ACK = 1 << 27,
+	LOGIC_PRE2_PDBO_ALL_ON_ACK = 1 << 28,
+	LOGIC_PRE1_PDBO_ALL_ON_ACK = 1 << 29
+};
+
+enum {
+	CPU_SW_SPARK_EN = 1 << 0,
+	CPU_SW_NO_WAIT_FOR_Q_CHANNEL = 1 << 1,
+	CPU_SW_FSM_OVERRIDE = 1 << 2,
+	CPU_SW_LOGIC_PRE1_PDB = 1 << 3,
+	CPU_SW_LOGIC_PRE2_PDB = 1 << 4,
+	CPU_SW_LOGIC_PDB = 1 << 5,
+	CPU_SW_ISO = 1 << 6,
+	CPU_SW_SRAM_SLEEPB = 1 << 7,
+	CPU_SW_SRAM_ISOINTB = 1 << 8,
+	CPU_SW_CLK_DIS = 1 << 9,
+	CPU_SW_CKISO = 1 << 10,
+	CPU_SW_PD = 0x1f << 11,
+	CPU_SW_HOT_PLUG_RESET = 1 << 16,
+	CPU_SW_POWR_ON_OVERRIDE_EN = 1 << 17,
+	CPU_SW_PWR_ON = 1 << 18,
+	CPU_SPARK2LDO_ALLSWOFF = 1 << 19,
+	CPU_PDBO_ALL_ON_ACK = 1 << 20,
+	CPU_PRE2_PDBO_ALLON_ACK = 1 << 21,
+	CPU_PRE1_PDBO_ALLON_ACK = 1 << 22
+};
+
+enum {
+	MP2_AXI_CONFIG_ACINACTM = 1 << 0,
+	MPx_AXI_CONFIG_ACINACTM = 1 << 4,
+	MPX_CA7_MISC_CONFIG_STANDBYWFIL2 = 1 << 28
+};
+
+enum {
+	MP0_CPU0_STANDBYWFE = 1 << 20,
+	MP0_CPU1_STANDBYWFE = 1 << 21,
+	MP0_CPU2_STANDBYWFE = 1 << 22,
+	MP0_CPU3_STANDBYWFE = 1 << 23
+};
+
+enum {
+	MP1_CPU0_STANDBYWFE = 1 << 20,
+	MP1_CPU1_STANDBYWFE = 1 << 21,
+	MP1_CPU2_STANDBYWFE = 1 << 22,
+	MP1_CPU3_STANDBYWFE = 1 << 23
+};
+
+enum {
+	B_SW_HOT_PLUG_RESET = 1 << 30,
+	B_SW_PD_OFFSET = 18,
+	B_SW_PD = 0x3f << B_SW_PD_OFFSET,
+	B_SW_SRAM_SLEEPB_OFFSET = 12,
+	B_SW_SRAM_SLEEPB = 0x3f << B_SW_SRAM_SLEEPB_OFFSET
+};
+
+enum {
+	B_SW_SRAM_ISOINTB = 1 << 9,
+	B_SW_ISO = 1 << 8,
+	B_SW_LOGIC_PDB = 1 << 7,
+	B_SW_LOGIC_PRE2_PDB = 1 << 6,
+	B_SW_LOGIC_PRE1_PDB = 1 << 5,
+	B_SW_FSM_OVERRIDE = 1 << 4,
+	B_SW_PWR_ON = 1 << 3,
+	B_SW_PWR_ON_OVERRIDE_EN = 1 << 2
+};
+
+enum {
+	B_FSM_STATE_OUT_OFFSET = 6,
+	B_FSM_STATE_OUT_MASK = 0x1f << B_FSM_STATE_OUT_OFFSET,
+	B_SW_LOGIC_PDBO_ALL_OFF_ACK = 1 << 5,
+	B_SW_LOGIC_PDBO_ALL_ON_ACK = 1 << 4,
+	B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK = 1 << 3,
+	B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK = 1 << 2,
+	B_FSM_OFF = 0 << B_FSM_STATE_OUT_OFFSET,
+	B_FSM_ON = 1 << B_FSM_STATE_OUT_OFFSET,
+	B_FSM_RET = 2 << B_FSM_STATE_OUT_OFFSET
+};
+
+/* APB Module infracfg_ao */
+enum {
+	INFRA_TOPAXI_PROTECTEN_1 = INFRACFG_AO_BASE + 0x250,
+	INFRA_TOPAXI_PROTECTSTA1_1 = INFRACFG_AO_BASE + 0x258,
+	INFRA_TOPAXI_PROTECTEN_1_SET = INFRACFG_AO_BASE + 0x2A8,
+	INFRA_TOPAXI_PROTECTEN_1_CLR = INFRACFG_AO_BASE + 0x2AC
+};
+
+enum {
+	IDX_PROTECT_MP0_CACTIVE = 10,
+	IDX_PROTECT_MP1_CACTIVE = 11,
+	IDX_PROTECT_ICC0_CACTIVE = 12,
+	IDX_PROTECT_ICD0_CACTIVE = 13,
+	IDX_PROTECT_ICC1_CACTIVE = 14,
+	IDX_PROTECT_ICD1_CACTIVE = 15,
+	IDX_PROTECT_L2C0_CACTIVE = 26,
+	IDX_PROTECT_L2C1_CACTIVE = 27
+};
+
+/* cpu boot mode */
+enum {
+	MP0_CPUCFG_64BIT_SHIFT = 12,
+	MP1_CPUCFG_64BIT_SHIFT = 28,
+	MP0_CPUCFG_64BIT = 0xf << MP0_CPUCFG_64BIT_SHIFT,
+	MP1_CPUCFG_64BIT = 0xfu << MP1_CPUCFG_64BIT_SHIFT
+};
+
+/* scu related */
+enum {
+	MP0_ACINACTM_SHIFT = 4,
+	MP1_ACINACTM_SHIFT = 4,
+	MP2_ACINACTM_SHIFT = 0,
+	MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT,
+	MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT,
+	MP2_ACINACTM = 1 << MP2_ACINACTM_SHIFT
+};
+
+enum {
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16,
+
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+	MP1_AINACTS_SHIFT = 4,
+	MP1_AINACTS = 1 << MP1_AINACTS_SHIFT
+};
+
+enum {
+	MP1_SW_CG_GEN_SHIFT = 12,
+	MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+	MP1_L2RSTDISABLE_SHIFT = 14,
+	MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT
+};
+
+#endif  /* MT8183_MCUCFG_H */
diff --git a/plat/mediatek/mt8183/include/mt_gic_v3.h b/plat/mediatek/mt8183/include/mt_gic_v3.h
new file mode 100644
index 0000000..e2706f4
--- /dev/null
+++ b/plat/mediatek/mt8183/include/mt_gic_v3.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GIC_V3_H
+#define MT_GIC_V3_H
+
+#include <lib/mmio.h>
+
+enum irq_schedule_mode {
+	SW_MODE,
+	HW_MODE
+};
+
+#define GIC_INT_MASK (MCUCFG_BASE + 0x5e8)
+#define GIC500_ACTIVE_SEL_SHIFT 3
+#define GIC500_ACTIVE_SEL_MASK (0x7 << GIC500_ACTIVE_SEL_SHIFT)
+#define GIC500_ACTIVE_CPU_SHIFT 16
+#define GIC500_ACTIVE_CPU_MASK (0xff << GIC500_ACTIVE_CPU_SHIFT)
+
+void mt_gic_driver_init(void);
+void mt_gic_init(void);
+void mt_gic_set_pending(uint32_t irq);
+uint32_t mt_gic_get_pending(uint32_t irq);
+void mt_gic_cpuif_enable(void);
+void mt_gic_cpuif_disable(void);
+void mt_gic_pcpu_init(void);
+void mt_gic_irq_save(void);
+void mt_gic_irq_restore(void);
+void mt_gic_sync_dcm_enable(void);
+void mt_gic_sync_dcm_disable(void);
+
+#endif /* MT_GIC_V3_H */
diff --git a/plat/mediatek/mt8183/include/plat_debug.h b/plat/mediatek/mt8183/include/plat_debug.h
new file mode 100644
index 0000000..e51a6ea
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_debug.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEBUG_H
+#define PLATFORM_DEBUG_H
+
+#define sync_writel(addr, val) \
+	do { mmio_write_32((addr), (val)); dsbsy(); } while (0)
+
+#define MCU_BIU_BASE			0x0c530000
+#define MISC1_CFG_BASE			0xb00
+#define CA15M_CFG_BASE			0x2000
+#define DFD_INTERNAL_CTL		(MCU_BIU_BASE + MISC1_CFG_BASE + 0x00)
+#define CA15M_DBG_CONTROL		(MCU_BIU_BASE + CA15M_CFG_BASE + 0x728)
+#define CA15M_PWR_RST_CTL		(MCU_BIU_BASE + CA15M_CFG_BASE + 0x08)
+#define VPROC_EXT_CTL			0x10006290
+
+#define CFG_SF_CTRL			0x0c510014
+#define CFG_SF_INI			0x0c510010
+
+#define BIT_CA15M_L2PARITY_EN		(1 << 1)
+#define BIT_CA15M_LASTPC_DIS		(1 << 8)
+
+#define MP1_CPUTOP_PWR_CON		0x10006218
+
+#define MCU_ALL_PWR_ON_CTRL		0x0c530b58
+#define PLAT_MTK_CIRCULAR_BUFFER_UNLOCK	0xefab4133
+#define PLAT_MTK_CIRCULAR_BUFFER_LOCK	0xefab4134
+
+extern void circular_buffer_setup(void);
+extern void l2c_parity_check_setup(void);
+extern void clear_all_on_mux(void);
+#endif /* PLATFORM_DEBUG_H */
diff --git a/plat/mediatek/mt8183/include/plat_macros.S b/plat/mediatek/mt8183/include/plat_macros.S
new file mode 100644
index 0000000..cac7769
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_macros.S
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ---------------------------------------------
+	 * The below macro prints out relevant GIC and
+	 * CCI registers whenever an unhandled exception
+	 * is taken in BL31.
+	 * Clobbers: x0 - x10, x26, x27, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm x26, BASE_GICD_BASE
+	mov_imm x27, BASE_GICC_BASE
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x27, #GICC_HPPIR]
+	ldr	w9, [x27, #GICC_AHPPIR]
+	ldr	w10, [x27, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x26, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x26
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
diff --git a/plat/mediatek/mt8183/include/plat_private.h b/plat/mediatek/mt8183/include/plat_private.h
new file mode 100644
index 0000000..0853934
--- /dev/null
+++ b/plat/mediatek/mt8183/include/plat_private.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_configure_mmu_el3(uintptr_t total_base,
+			    uintptr_t total_size,
+			    uintptr_t ro_start,
+			    uintptr_t ro_limit,
+			    uintptr_t coh_start,
+			    uintptr_t coh_limit);
+
+void plat_mtk_cci_init(void);
+void plat_mtk_cci_enable(void);
+void plat_mtk_cci_disable(void);
+void plat_mtk_cci_init_sf(void);
+
+/* Declarations for plat_topology.c */
+int mt_setup_topology(void);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8183/include/platform_def.h b/plat/mediatek/mt8183/include/platform_def.h
new file mode 100644
index 0000000..bc9022b
--- /dev/null
+++ b/plat/mediatek/mt8183/include/platform_def.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <drivers/arm/gic_common.h>
+
+#define PLAT_PRIMARY_CPU   0x0
+
+#define IO_PHYS            0x10000000
+#define INFRACFG_AO_BASE   (IO_PHYS + 0x1000)
+#define PERI_BASE          (IO_PHYS + 0x3000)
+#define GPIO_BASE          (IO_PHYS + 0x5000)
+#define SPM_BASE           (IO_PHYS + 0x6000)
+#define SLEEP_REG_MD_BASE  (IO_PHYS + 0xf000)
+#define RGU_BASE           (IO_PHYS + 0x7000)
+#define I2C4_BASE_SE       (IO_PHYS + 0x1008000)
+#define I2C2_BASE_SE       (IO_PHYS + 0x1009000)
+#define PMIC_WRAP_BASE     (IO_PHYS + 0xd000)
+#define MCUCFG_BASE        0x0c530000
+#define CFG_SF_CTRL        0x0c510014
+#define CFG_SF_INI         0x0c510010
+#define EMI_MPU_BASE       (IO_PHYS + 0x226000)
+#define TRNG_base          (IO_PHYS + 0x20f000)
+#define MT_GIC_BASE        0x0c000000
+#define PLAT_MT_CCI_BASE   0x0c500000
+#define CCI_SIZE           0x00010000
+#define EINT_BASE          0x1000b000
+#define DVFSRC_BASE        (IO_PHYS + 0x12000)
+
+#define SSPM_CFGREG_BASE   (IO_PHYS + 0x440000)
+#define SSPM_MBOX_3_BASE   (IO_PHYS + 0x480000)
+
+#define INFRACFG_AO_BASE   (IO_PHYS + 0x1000)
+
+#define APMIXEDSYS         (IO_PHYS + 0xC000)
+#define ARMPLL_LL_CON0     (APMIXEDSYS + 0x200)
+#define ARMPLL_L_CON0      (APMIXEDSYS + 0x210)
+#define MAINPLL_CON0       (APMIXEDSYS + 0x220)
+#define CCIPLL_CON0        (APMIXEDSYS + 0x290)
+
+#define TOP_CKMUXSEL       (INFRACFG_AO_BASE + 0x0)
+
+#define armpll_mux1_sel_big_mask    (0xf << 4)
+#define armpll_mux1_sel_big_ARMSPLL (0x1 << 4)
+#define armpll_mux1_sel_sml_mask    (0xf << 8)
+#define armpll_mux1_sel_sml_ARMSPLL (0x1 << 8)
+
+
+/* Aggregate of all devices in the first GB */
+#define MTK_DEV_RNG0_BASE    IO_PHYS
+#define MTK_DEV_RNG0_SIZE    0x490000
+#define MTK_DEV_RNG1_BASE    (IO_PHYS + 0x1000000)
+#define MTK_DEV_RNG1_SIZE    0x4000000
+#define MTK_DEV_RNG2_BASE    0x0c000000
+#define MTK_DEV_RNG2_SIZE    0x600000
+#define MT_MCUSYS_SIZE       0x90000
+#define RAM_CONSOLE_BASE     0x11d000
+#define RAM_CONSOLE_SIZE     0x1000
+
+/*******************************************************************************
+ * MSDC
+ ******************************************************************************/
+#define MSDC0_BASE          (IO_PHYS + 0x01230000)
+
+/*******************************************************************************
+ * MCUSYS related constants
+ ******************************************************************************/
+#define MT_L2_WRITE_ACCESS_RATE  (MCUCFG_BASE + 0x604)
+#define MP0_CA7L_CACHE_CONFIG    (MCUCFG_BASE + 0x7f0)
+#define MP1_CA7L_CACHE_CONFIG    (MCUCFG_BASE + 0x7f4)
+
+/*******************************************************************************
+ * GIC related constants
+ ******************************************************************************/
+#define MT_POLARITY_LOW     0
+#define MT_POLARITY_HIGH    1
+#define MT_EDGE_SENSITIVE   1
+#define MT_LEVEL_SENSITIVE  0
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE    (IO_PHYS + 0x01002000)
+
+#define UART_BAUDRATE 115200
+#define UART_CLOCK    26000000
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS    13000000
+#define SYS_COUNTER_FREQ_IN_MHZ      13
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE        MT_GIC_BASE
+#define BASE_GICC_BASE        (MT_GIC_BASE + 0x400000)
+#define MT_GIC_RDIST_BASE     (MT_GIC_BASE + 0x100000)
+#define BASE_GICR_BASE        (MT_GIC_BASE + 0x100000)
+#define BASE_GICH_BASE        (MT_GIC_BASE + 0x4000)
+#define BASE_GICV_BASE        (MT_GIC_BASE + 0x6000)
+#define INT_POL_CTL0          (MCUCFG_BASE + 0xa80)
+#define SEC_POL_CTL_EN0       (MCUCFG_BASE + 0xa00)
+#define GIC_SYNC_DCM          (MCUCFG_BASE + 0x758)
+#define GIC_SYNC_DCM_MASK     0x3
+#define GIC_SYNC_DCM_ON       0x3
+#define GIC_SYNC_DCM_OFF      0x0
+#define GIC_PRIVATE_SIGNALS   32
+
+#define PLAT_ARM_GICD_BASE BASE_GICD_BASE
+#define PLAT_ARM_GICC_BASE BASE_GICC_BASE
+
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) ( \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+INTR_PROP_DESC(MT_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)) \
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX    4
+#define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX    3
+
+/*******************************************************************************
+ * WDT Registers
+ ******************************************************************************/
+#define MTK_WDT_BASE            (IO_PHYS + 0x00007000)
+#define MTK_WDT_SIZE            0x1000
+#define MTK_WDT_MODE            (MTK_WDT_BASE + 0x0000)
+#define MTK_WDT_LENGTH          (MTK_WDT_BASE + 0x0004)
+#define MTK_WDT_RESTART         (MTK_WDT_BASE + 0x0008)
+#define MTK_WDT_STATUS          (MTK_WDT_BASE + 0x000C)
+#define MTK_WDT_INTERVAL        (MTK_WDT_BASE + 0x0010)
+#define MTK_WDT_SWRST           (MTK_WDT_BASE + 0x0014)
+#define MTK_WDT_SWSYSRST        (MTK_WDT_BASE + 0x0018)
+#define MTK_WDT_NONRST_REG      (MTK_WDT_BASE + 0x0020)
+#define MTK_WDT_NONRST_REG2     (MTK_WDT_BASE + 0x0024)
+#define MTK_WDT_REQ_MODE        (MTK_WDT_BASE + 0x0030)
+#define MTK_WDT_REQ_IRQ_EN      (MTK_WDT_BASE + 0x0034)
+#define MTK_WDT_EXT_REQ_CON     (MTK_WDT_BASE + 0x0038)
+#define MTK_WDT_DEBUG_CTL       (MTK_WDT_BASE + 0x0040)
+#define MTK_WDT_LATCH_CTL       (MTK_WDT_BASE + 0x0044)
+#define MTK_WDT_DEBUG_CTL2      (MTK_WDT_BASE + 0x00A0)
+#define MTK_WDT_COUNTER         (MTK_WDT_BASE + 0x0514)
+
+/* WDT_STATUS */
+#define MTK_WDT_STATUS_SPM_THERMAL_RST      (1 << 0)
+#define MTK_WDT_STATUS_SPM_RST              (1 << 1)
+#define MTK_WDT_STATUS_EINT_RST             (1 << 2)
+#define MTK_WDT_STATUS_SYSRST_RST           (1 << 3) /* from PMIC */
+#define MTK_WDT_STATUS_DVFSP_RST            (1 << 4)
+#define MTK_WDT_STATUS_PMCU_RST             (1 << 16)
+#define MTK_WDT_STATUS_MDDBG_RST            (1 << 17)
+#define MTK_WDT_STATUS_THERMAL_DIRECT_RST   (1 << 18)
+#define MTK_WDT_STATUS_DEBUG_RST            (1 << 19)
+#define MTK_WDT_STATUS_SECURITY_RST         (1 << 28)
+#define MTK_WDT_STATUS_IRQ_ASSERT           (1 << 29)
+#define MTK_WDT_STATUS_SW_WDT_RST           (1 << 30)
+#define MTK_WDT_STATUS_HW_WDT_RST           (1U << 31)
+
+/* RGU other related */
+#define MTK_WDT_MODE_DUAL_MODE    0x0040
+#define MTK_WDT_MODE_IRQ          0x0008
+#define MTK_WDT_MODE_KEY          0x22000000
+#define MTK_WDT_MODE_EXTEN        0x0004
+#define MTK_WDT_SWRST_KEY         0x1209
+#define MTK_WDT_RESTART_KEY       0x1971
+
+/*******************************************************************************
+ * TRNG Registers
+ ******************************************************************************/
+#define TRNG_BASE_ADDR       TRNG_base
+#define TRNG_BASE_SIZE       0x1000
+#define TRNG_CTRL            (TRNG_base + 0x0000)
+#define TRNG_TIME            (TRNG_base + 0x0004)
+#define TRNG_DATA            (TRNG_base + 0x0008)
+#define TRNG_PDN_base        0x10001000
+#define TRNG_PDN_BASE_ADDR   TRNG_PDN_BASE_ADDR
+#define TRNG_PDN_BASE_SIZE   0x1000
+#define TRNG_PDN_SET         (TRNG_PDN_base + 0x0088)
+#define TRNG_PDN_CLR         (TRNG_PDN_base + 0x008c)
+#define TRNG_PDN_STATUS      (TRNG_PDN_base + 0x0094)
+#define TRNG_CTRL_RDY        0x80000000
+#define TRNG_CTRL_START      0x00000001
+#define TRNG_PDN_VALUE       0x200
+
+/* FIQ platform related define */
+#define MT_IRQ_SEC_SGI_0    8
+#define MT_IRQ_SEC_SGI_1    9
+#define MT_IRQ_SEC_SGI_2    10
+#define MT_IRQ_SEC_SGI_3    11
+#define MT_IRQ_SEC_SGI_4    12
+#define MT_IRQ_SEC_SGI_5    13
+#define MT_IRQ_SEC_SGI_6    14
+#define MT_IRQ_SEC_SGI_7    15
+
+#define FIQ_SMP_CALL_SGI    13
+#define WDT_IRQ_BIT_ID      174
+#define ATF_LOG_IRQ_ID      277
+
+#define ATF_AMMS_IRQ_ID     338
+#define PCCIF1_IRQ0_BIT_ID  185
+#define PCCIF1_IRQ1_BIT_ID  186
+
+#define DEBUG_XLAT_TABLE    0
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT      "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH        aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if DEBUG_XLAT_TABLE
+#define PLATFORM_STACK_SIZE    0x800
+#elif IMAGE_BL1
+#define PLATFORM_STACK_SIZE    0x440
+#elif IMAGE_BL2
+#define PLATFORM_STACK_SIZE    0x400
+#elif IMAGE_BL31
+#define PLATFORM_STACK_SIZE    0x800
+#elif IMAGE_BL32
+#define PLATFORM_STACK_SIZE    0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR    "Booting Trusted Firmware\n"
+#define PLAT_MAX_PWR_LVL        U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+#define PLATFORM_CACHE_LINE_SIZE        64
+#define PLATFORM_SYSTEM_COUNT           1
+#define PLATFORM_CLUSTER_COUNT          2
+#define PLATFORM_CLUSTER0_CORE_COUNT    4
+#define PLATFORM_CLUSTER1_CORE_COUNT    4
+#define PLATFORM_CORE_COUNT             (PLATFORM_CLUSTER1_CORE_COUNT + \
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER   4
+#define PLATFORM_NUM_AFFS               (PLATFORM_SYSTEM_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+
+#define TZRAM_BASE          0x54600000
+#define TZRAM_SIZE          0x00020000
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#define BL31_BASE       (TZRAM_BASE + 0x1000)
+#define BL31_LIMIT      (TZRAM_BASE + TZRAM_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define MAX_XLAT_TABLES             4
+#define MAX_MMAP_REGIONS            16
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT    6
+#define CACHE_WRITEBACK_GRANULE  (1 << CACHE_WRITEBACK_SHIFT)
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt8183/include/power_tracer.h b/plat/mediatek/mt8183/include/power_tracer.h
new file mode 100644
index 0000000..c93be64
--- /dev/null
+++ b/plat/mediatek/mt8183/include/power_tracer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef POWER_TRACER_H
+#define POWER_TRACER_H
+
+#define CPU_UP		0
+#define CPU_DOWN	1
+#define CPU_SUSPEND	2
+#define CLUSTER_UP	3
+#define CLUSTER_DOWN	4
+#define CLUSTER_SUSPEND	5
+
+void trace_power_flow(u_register_t mpidr, unsigned char mode);
+
+#endif /* POWER_TRACER_H */
+
diff --git a/plat/mediatek/mt8183/include/scu.h b/plat/mediatek/mt8183/include/scu.h
new file mode 100644
index 0000000..96b80c5
--- /dev/null
+++ b/plat/mediatek/mt8183/include/scu.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCU_H
+#define SCU_H
+
+void disable_scu(u_register_t mpidr);
+void enable_scu(u_register_t mpidr);
+
+#endif /* SCU_H */
diff --git a/plat/mediatek/mt8183/plat_debug.c b/plat/mediatek/mt8183/plat_debug.c
new file mode 100644
index 0000000..51816db
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_debug.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat_debug.h>
+#include <platform_def.h>
+
+void circular_buffer_setup(void)
+{
+	/* Clear DBG_CONTROL.lastpc_disable to enable circular buffer */
+	sync_writel(CA15M_DBG_CONTROL,
+		    mmio_read_32(CA15M_DBG_CONTROL) & ~(BIT_CA15M_LASTPC_DIS));
+}
+
+void circular_buffer_unlock(void)
+{
+	unsigned int i;
+
+	/* Disable big vproc external off (set CPU_EXT_BUCK_ISO to 0x0) */
+	sync_writel(VPROC_EXT_CTL, mmio_read_32(VPROC_EXT_CTL) & ~(0x1 << 1));
+
+	/* Release vproc apb mask (set 0x0C53_2008[1] to 0x0) */
+	sync_writel(CA15M_PWR_RST_CTL, mmio_read_32(CA15M_PWR_RST_CTL) & ~(0x1 << 1));
+
+	for (i = 1; i <= 4; ++i)
+		sync_writel(MP1_CPUTOP_PWR_CON + i * 4,
+			    (mmio_read_32(MP1_CPUTOP_PWR_CON + i * 4) & ~(0x4))|(0x4));
+
+	/* Set DFD.en */
+	sync_writel(DFD_INTERNAL_CTL, 0x1);
+}
+
+void circular_buffer_lock(void)
+{
+	/* Clear DFD.en */
+	sync_writel(DFD_INTERNAL_CTL, 0x0);
+}
+
+void clear_all_on_mux(void)
+{
+	sync_writel(MCU_ALL_PWR_ON_CTRL,
+		    mmio_read_32(MCU_ALL_PWR_ON_CTRL) & ~(1 << 2));
+	sync_writel(MCU_ALL_PWR_ON_CTRL,
+		    mmio_read_32(MCU_ALL_PWR_ON_CTRL) & ~(1 << 1));
+}
+
+void l2c_parity_check_setup(void)
+{
+	/* Enable DBG_CONTROL.l2parity_en */
+	sync_writel(CA15M_DBG_CONTROL,
+		    mmio_read_32(CA15M_DBG_CONTROL) | BIT_CA15M_L2PARITY_EN);
+}
diff --git a/plat/mediatek/mt8183/plat_mt_gic.c b/plat/mediatek/mt8183/plat_mt_gic.c
new file mode 100644
index 0000000..2144379
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_mt_gic.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <bl31/interrupt_mgmt.h>
+#include <../drivers/arm/gic/v3/gicv3_private.h>
+#include <mt_gic_v3.h>
+#include <mtk_plat_common.h>
+#include "plat_private.h"
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#define NR_INT_POL_CTL         20
+
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory
+ */
+gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram");
+gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram");
+
+
+static unsigned int mt_mpidr_to_core_pos(u_register_t mpidr)
+{
+	return plat_core_pos_by_mpidr(mpidr);
+}
+
+gicv3_driver_data_t mt_gicv3_data = {
+	.gicd_base = MT_GIC_BASE,
+	.gicr_base = MT_GIC_RDIST_BASE,
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = mt_mpidr_to_core_pos,
+};
+
+void setup_int_schedule_mode(enum irq_schedule_mode mode,
+			     unsigned int active_cpu)
+{
+	assert(mode <= HW_MODE);
+	assert(active_cpu <= 0xFF);
+
+	if (mode == HW_MODE) {
+		mmio_write_32(GIC_INT_MASK,
+		(mmio_read_32(GIC_INT_MASK) & ~(GIC500_ACTIVE_SEL_MASK))
+		| (0x1 << GIC500_ACTIVE_SEL_SHIFT));
+	} else if (mode == SW_MODE) {
+		mmio_write_32(GIC_INT_MASK,
+		(mmio_read_32(GIC_INT_MASK) & ~(GIC500_ACTIVE_SEL_MASK)));
+	}
+
+	mmio_write_32(GIC_INT_MASK,
+		(mmio_read_32(GIC_INT_MASK) & ~(GIC500_ACTIVE_CPU_MASK))
+		| (active_cpu << GIC500_ACTIVE_CPU_SHIFT));
+	return;
+}
+
+void clear_sec_pol_ctl_en(void)
+{
+	unsigned int i;
+
+	/* total 19 polarity ctrl registers */
+	for (i = 0; i <= NR_INT_POL_CTL - 1; i++) {
+		mmio_write_32((SEC_POL_CTL_EN0 + (i * 4)), 0);
+	}
+	dsb();
+}
+
+void mt_gic_driver_init(void)
+{
+	gicv3_driver_init(&mt_gicv3_data);
+}
+
+void mt_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+
+	setup_int_schedule_mode(SW_MODE, 0xf);
+	clear_sec_pol_ctl_en();
+}
+
+void mt_gic_set_pending(uint32_t irq)
+{
+	gicv3_set_interrupt_pending(irq, plat_my_core_pos());
+}
+
+uint32_t mt_gic_get_pending(uint32_t irq)
+{
+	uint32_t bit = 1 << (irq % 32);
+
+	return (mmio_read_32(gicv3_driver_data->gicd_base +
+			     GICD_ISPENDR + irq / 32 * 4) & bit) ? 1 : 0;
+}
+
+void mt_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void mt_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void mt_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
+
+void mt_gic_irq_save(void)
+{
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+	gicv3_distif_save(&dist_ctx);
+}
+
+void mt_gic_irq_restore(void)
+{
+	gicv3_distif_init_restore(&dist_ctx);
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+}
+
+void mt_gic_sync_dcm_enable(void)
+{
+	unsigned int val = mmio_read_32(GIC_SYNC_DCM);
+
+	val &= ~GIC_SYNC_DCM_MASK;
+	mmio_write_32(GIC_SYNC_DCM, val | GIC_SYNC_DCM_ON);
+}
+
+void mt_gic_sync_dcm_disable(void)
+{
+	unsigned int val = mmio_read_32(GIC_SYNC_DCM);
+
+	val &= ~GIC_SYNC_DCM_MASK;
+	mmio_write_32(GIC_SYNC_DCM, val | GIC_SYNC_DCM_OFF);
+}
diff --git a/plat/mediatek/mt8183/plat_pm.c b/plat/mediatek/mt8183/plat_pm.c
new file mode 100644
index 0000000..dd54d70
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_pm.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* common headers */
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <errno.h>
+
+/* mediatek platform specific headers */
+#include <platform_def.h>
+#include <scu.h>
+#include <mtk_plat_common.h>
+#include <power_tracer.h>
+#include <plat_private.h>
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * on. The level and mpidr determine the affinity instance.
+ ******************************************************************************/
+static uintptr_t secure_entrypoint;
+
+static const plat_psci_ops_t plat_plat_pm_ops = {
+	.cpu_standby			= NULL,
+	.pwr_domain_on			= NULL,
+	.pwr_domain_on_finish		= NULL,
+	.pwr_domain_off			= NULL,
+	.pwr_domain_suspend		= NULL,
+	.pwr_domain_suspend_finish	= NULL,
+	.system_off			= NULL,
+	.system_reset			= NULL,
+	.validate_power_state		= NULL,
+	.get_sys_suspend_power_state	= NULL,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &plat_plat_pm_ops;
+	secure_entrypoint = sec_entrypoint;
+	return 0;
+}
diff --git a/plat/mediatek/mt8183/plat_topology.c b/plat/mediatek/mt8183/plat_topology.c
new file mode 100644
index 0000000..7b1dd03
--- /dev/null
+++ b/plat/mediatek/mt8183/plat_topology.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <lib/psci/psci.h>
+
+const unsigned char mtk_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* Number of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	/* Number of children for the second cluster node */
+	PLATFORM_CLUSTER1_CORE_COUNT
+};
+
+/*******************************************************************************
+ * This function returns the MT8173 default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return mtk_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/mediatek/mt8183/platform.mk b/plat/mediatek/mt8183/platform.mk
new file mode 100644
index 0000000..f0a598a
--- /dev/null
+++ b/plat/mediatek/mt8183/platform.mk
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MTK_PLAT      := plat/mediatek
+MTK_PLAT_SOC  := ${MTK_PLAT}/${PLAT}
+
+PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
+                 -I${MTK_PLAT_SOC}/drivers/                       \
+                 -I${MTK_PLAT_SOC}/include/
+
+PLAT_BL_COMMON_SOURCES := lib/xlat_tables/aarch64/xlat_tables.c       \
+                          lib/xlat_tables/xlat_tables_common.c        \
+                          plat/common/plat_psci_common.c              \
+                          plat/common/aarch64/crash_console_helpers.S
+
+BL31_SOURCES    += common/desc_image_load.c                              \
+                   drivers/arm/cci/cci.c                                 \
+                   drivers/arm/gic/common/gic_common.c                   \
+                   drivers/arm/gic/v3/arm_gicv3_common.c                 \
+                   drivers/arm/gic/v3/gicv3_helpers.c                    \
+                   drivers/arm/gic/v3/gic500.c                           \
+                   drivers/arm/gic/v3/gicv3_main.c                       \
+                   drivers/delay_timer/delay_timer.c                     \
+                   drivers/delay_timer/generic_delay_timer.c             \
+                   drivers/gpio/gpio.c                                   \
+                   drivers/ti/uart/aarch64/16550_console.S               \
+                   lib/cpus/aarch64/aem_generic.S                        \
+                   lib/cpus/aarch64/cortex_a53.S                         \
+                   lib/cpus/aarch64/cortex_a73.S                         \
+                   plat/common/plat_gicv3.c                              \
+                   ${MTK_PLAT}/common/mtk_plat_common.c                  \
+                   ${MTK_PLAT_SOC}/aarch64/plat_helpers.S                \
+                   ${MTK_PLAT_SOC}/aarch64/platform_common.c             \
+                   ${MTK_PLAT_SOC}/drivers/mcsi/mcsi.c                   \
+                   ${MTK_PLAT_SOC}/plat_pm.c                             \
+                   ${MTK_PLAT_SOC}/plat_topology.c                       \
+                   ${MTK_PLAT_SOC}/plat_mt_gic.c                         \
+                   ${MTK_PLAT_SOC}/bl31_plat_setup.c                     \
+                   ${MTK_PLAT_SOC}/plat_debug.c                          \
+                   ${MTK_PLAT_SOC}/scu.c
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_826319 := 0
+ERRATA_A53_836870 := 1
+ERRATA_A53_855873 := 1
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+MULTI_CONSOLE_API := 1
+
+MACH_MT8183 := 1
+$(eval $(call add_define,MACH_MT8183))
+
diff --git a/plat/mediatek/mt8183/scu.c b/plat/mediatek/mt8183/scu.c
new file mode 100644
index 0000000..c4f1c3f
--- /dev/null
+++ b/plat/mediatek/mt8183/scu.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mcucfg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void disable_scu(u_register_t mpidr)
+{
+	uintptr_t axi_config = 0;
+	uint32_t axi_value;
+
+	switch (mpidr & MPIDR_CLUSTER_MASK) {
+	case 0x000:
+		axi_config = (uintptr_t)&mt8183_mcucfg->mp0_axi_config;
+		axi_value = MP0_ACINACTM;
+		break;
+	case 0x100:
+		axi_config = (uintptr_t)&mt8183_mcucfg->mp2_axi_config;
+		axi_value = MP2_ACINACTM;
+		break;
+	default:
+		ERROR("%s: mpidr does not exist\n", __func__);
+		panic();
+	}
+	mmio_setbits_32(axi_config, axi_value);
+}
+
+void enable_scu(u_register_t mpidr)
+{
+	uintptr_t axi_config = 0;
+	uint32_t axi_value;
+
+	switch (mpidr & MPIDR_CLUSTER_MASK) {
+	case 0x000:
+		axi_config = (uintptr_t)&mt8183_mcucfg->mp0_axi_config;
+		axi_value = MP0_ACINACTM;
+		break;
+	case 0x100:
+		axi_config = (uintptr_t)&mt8183_mcucfg->mp2_axi_config;
+		axi_value = MP2_ACINACTM;
+		break;
+	default:
+		ERROR("%s: mpidr does not exist\n", __func__);
+		panic();
+	}
+	mmio_clrbits_32(axi_config, axi_value);
+}
diff --git a/plat/meson/gxbb/aarch64/gxbb_helpers.S b/plat/meson/gxbb/aarch64/gxbb_helpers.S
new file mode 100644
index 0000000..760d6c4
--- /dev/null
+++ b/plat/meson/gxbb/aarch64/gxbb_helpers.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_crash_console_flush
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	platform_mem_init
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_gxbb_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_my_core_pos(void);
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_gxbb_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr);
+	 * -----------------------------------------------------
+	 */
+func plat_gxbb_calc_core_pos
+	and	x0, x0, #MPIDR_CPU_MASK
+	ret
+endfunc plat_gxbb_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary(void);
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #GXBB_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* ---------------------------------------------
+	 * void platform_mem_init(void);
+	 * ---------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, GXBB_UART0_AO_BASE
+	mov_imm	x1, GXBB_UART0_AO_CLK_IN_HZ
+	mov_imm	x2, GXBB_UART_BAUDRATE
+	b	console_meson_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, GXBB_UART0_AO_BASE
+	b	console_meson_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, GXBB_UART0_AO_BASE
+	b	console_meson_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------
+	 * void plat_reset_handler(void);
+	 * ---------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
diff --git a/plat/meson/gxbb/gxbb_bl31_setup.c b/plat/meson/gxbb/gxbb_bl31_setup.c
new file mode 100644
index 0000000..b867a58
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_bl31_setup.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+#include "gxbb_private.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(type == NON_SECURE);
+
+	next_image_info = &bl33_image_ep_info;
+
+	/* None of the images can have 0x0 as the entrypoint. */
+	if (next_image_info->pc != 0U) {
+		return next_image_info;
+	} else {
+		return NULL;
+	}
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+struct gxbb_bl31_param {
+	param_header_t h;
+	image_info_t *bl31_image_info;
+	entry_point_info_t *bl32_ep_info;
+	image_info_t *bl32_image_info;
+	entry_point_info_t *bl33_ep_info;
+	image_info_t *bl33_image_info;
+};
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	struct gxbb_bl31_param *from_bl2;
+
+	/* Initialize the console to provide early debug support */
+	gxbb_console_init();
+
+	/*
+	 * In debug builds, we pass a special value in 'arg1' to verify platform
+	 * parameters from BL2 to BL31. In release builds it's not used.
+	 */
+	assert(arg1 == GXBB_BL31_PLAT_PARAM_VAL);
+
+	/* Check that params passed from BL2 are not NULL. */
+	from_bl2 = (struct gxbb_bl31_param *) arg0;
+
+	/* Check params passed from BL2 are not NULL. */
+	assert(from_bl2 != NULL);
+	assert(from_bl2->h.type == PARAM_BL31);
+	assert(from_bl2->h.version >= VERSION_1);
+
+	/*
+	 * Copy BL33 entry point information. It is stored in Secure RAM, in
+	 * BL2's address space.
+	 */
+	bl33_image_ep_info = *from_bl2->bl33_ep_info;
+
+	if (bl33_image_ep_info.pc == 0U) {
+		ERROR("BL31: BL33 entrypoint not obtained from BL2\n");
+		panic();
+	}
+}
+
+void bl31_plat_arch_setup(void)
+{
+	gxbb_setup_page_tables();
+
+	enable_mmu_el3(0);
+}
+
+/*******************************************************************************
+ * GICv2 driver setup information
+ ******************************************************************************/
+static const interrupt_prop_t gxbb_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+static const gicv2_driver_data_t gxbb_gic_data = {
+	.gicd_base = GXBB_GICD_BASE,
+	.gicc_base = GXBB_GICC_BASE,
+	.interrupt_props = gxbb_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(gxbb_interrupt_props),
+};
+
+void bl31_platform_setup(void)
+{
+	mhu_secure_init();
+
+	gicv2_driver_init(&gxbb_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	gxbb_thermal_unknown();
+}
diff --git a/plat/meson/gxbb/gxbb_common.c b/plat/meson/gxbb/gxbb_common.c
new file mode 100644
index 0000000..0ca15e8
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_common.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/ep_info.h>
+#include <drivers/meson/meson_console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*******************************************************************************
+ * Platform memory map regions
+ ******************************************************************************/
+#define MAP_NSDRAM0	MAP_REGION_FLAT(GXBB_NSDRAM0_BASE,		\
+					GXBB_NSDRAM0_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_NSDRAM1	MAP_REGION_FLAT(GXBB_NSDRAM1_BASE,		\
+					GXBB_NSDRAM1_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_SEC_DEVICE0	MAP_REGION_FLAT(GXBB_SEC_DEVICE0_BASE,		\
+					GXBB_SEC_DEVICE0_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE1	MAP_REGION_FLAT(GXBB_SEC_DEVICE1_BASE,		\
+					GXBB_SEC_DEVICE1_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_TZRAM	MAP_REGION_FLAT(GXBB_TZRAM_BASE,		\
+					GXBB_TZRAM_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE2	MAP_REGION_FLAT(GXBB_SEC_DEVICE2_BASE,		\
+					GXBB_SEC_DEVICE2_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE3	MAP_REGION_FLAT(GXBB_SEC_DEVICE3_BASE,		\
+					GXBB_SEC_DEVICE3_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+static const mmap_region_t gxbb_mmap[] = {
+	MAP_NSDRAM0,
+	MAP_NSDRAM1,
+	MAP_SEC_DEVICE0,
+	MAP_SEC_DEVICE1,
+	MAP_TZRAM,
+	MAP_SEC_DEVICE2,
+	MAP_SEC_DEVICE3,
+	{0}
+};
+
+/*******************************************************************************
+ * Per-image regions
+ ******************************************************************************/
+#define MAP_BL31	MAP_REGION_FLAT(BL31_BASE,			\
+				BL31_END - BL31_BASE,			\
+				MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_BL_CODE	MAP_REGION_FLAT(BL_CODE_BASE,			\
+				BL_CODE_END - BL_CODE_BASE,		\
+				MT_CODE | MT_SECURE)
+
+#define MAP_BL_RO_DATA	MAP_REGION_FLAT(BL_RO_DATA_BASE,		\
+				BL_RO_DATA_END - BL_RO_DATA_BASE,	\
+				MT_RO_DATA | MT_SECURE)
+
+#define MAP_BL_COHERENT	MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,		\
+				BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \
+				MT_DEVICE | MT_RW | MT_SECURE)
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+void gxbb_setup_page_tables(void)
+{
+#if IMAGE_BL31
+	const mmap_region_t gxbb_bl_mmap[] = {
+		MAP_BL31,
+		MAP_BL_CODE,
+		MAP_BL_RO_DATA,
+#if USE_COHERENT_MEM
+		MAP_BL_COHERENT,
+#endif
+		{0}
+	};
+#endif
+
+	mmap_add(gxbb_bl_mmap);
+
+	mmap_add(gxbb_mmap);
+
+	init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Function that sets up the console
+ ******************************************************************************/
+static console_meson_t gxbb_console;
+
+void gxbb_console_init(void)
+{
+	int rc = console_meson_register(GXBB_UART0_AO_BASE,
+					GXBB_UART0_AO_CLK_IN_HZ,
+					GXBB_UART_BAUDRATE,
+					&gxbb_console);
+	if (rc == 0) {
+		/*
+		 * The crash console doesn't use the multi console API, it uses
+		 * the core console functions directly. It is safe to call panic
+		 * and let it print debug information.
+		 */
+		panic();
+	}
+
+	console_set_scope(&gxbb_console.console,
+			  CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+}
+
+/*******************************************************************************
+ * Function that returns the system counter frequency
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+	uint32_t val;
+
+	val = mmio_read_32(GXBB_SYS_CPU_CFG7);
+	val &= 0xFDFFFFFF;
+	mmio_write_32(GXBB_SYS_CPU_CFG7, val);
+
+	val = mmio_read_32(GXBB_AO_TIMESTAMP_CNTL);
+	val &= 0xFFFFFE00;
+	mmio_write_32(GXBB_AO_TIMESTAMP_CNTL, val);
+
+	return GXBB_OSC24M_CLK_IN_HZ;
+}
diff --git a/plat/meson/gxbb/gxbb_def.h b/plat/meson/gxbb/gxbb_def.h
new file mode 100644
index 0000000..3e27097
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_def.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GXBB_DEF_H
+#define GXBB_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * System oscillator
+ ******************************************************************************/
+#define GXBB_OSC24M_CLK_IN_HZ			ULL(24000000) /* 24 MHz */
+
+/*******************************************************************************
+ * Memory regions
+ ******************************************************************************/
+#define GXBB_NSDRAM0_BASE			UL(0x01000000)
+#define GXBB_NSDRAM0_SIZE			UL(0x0F000000)
+
+#define GXBB_NSDRAM1_BASE			UL(0x10000000)
+#define GXBB_NSDRAM1_SIZE			UL(0x00100000)
+
+#define BL31_BASE				UL(0x10100000)
+#define BL31_SIZE				UL(0x000C0000)
+#define BL31_LIMIT				(BL31_BASE + BL31_SIZE)
+
+/* Shared memory used for SMC services */
+#define GXBB_SHARE_MEM_INPUT_BASE		UL(0x100FE000)
+#define GXBB_SHARE_MEM_OUTPUT_BASE		UL(0x100FF000)
+
+#define GXBB_SEC_DEVICE0_BASE			UL(0xC0000000)
+#define GXBB_SEC_DEVICE0_SIZE			UL(0x09000000)
+
+#define GXBB_SEC_DEVICE1_BASE			UL(0xD0040000)
+#define GXBB_SEC_DEVICE1_SIZE			UL(0x00008000)
+
+#define GXBB_TZRAM_BASE				UL(0xD9000000)
+#define GXBB_TZRAM_SIZE				UL(0x00014000)
+/* Top 0xC000 bytes (up to 0xD9020000) used by BL2 */
+
+/* Mailboxes */
+#define GXBB_MHU_SECURE_SCP_TO_AP_PAYLOAD	UL(0xD9013800)
+#define GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD	UL(0xD9013A00)
+#define GXBB_PSCI_MAILBOX_BASE			UL(0xD9013F00)
+
+#define GXBB_TZROM_BASE				UL(0xD9040000)
+#define GXBB_TZROM_SIZE				UL(0x00010000)
+
+#define GXBB_SEC_DEVICE2_BASE			UL(0xDA000000)
+#define GXBB_SEC_DEVICE2_SIZE			UL(0x00200000)
+
+#define GXBB_SEC_DEVICE3_BASE			UL(0xDA800000)
+#define GXBB_SEC_DEVICE3_SIZE			UL(0x00200000)
+
+/*******************************************************************************
+ * GIC-400 and interrupt handling related constants
+ ******************************************************************************/
+#define GXBB_GICD_BASE				UL(0xC4301000)
+#define GXBB_GICC_BASE				UL(0xC4302000)
+
+#define IRQ_SEC_PHY_TIMER			29
+
+#define IRQ_SEC_SGI_0				8
+#define IRQ_SEC_SGI_1				9
+#define IRQ_SEC_SGI_2				10
+#define IRQ_SEC_SGI_3				11
+#define IRQ_SEC_SGI_4				12
+#define IRQ_SEC_SGI_5				13
+#define IRQ_SEC_SGI_6				14
+#define IRQ_SEC_SGI_7				15
+
+/*******************************************************************************
+ * UART definitions
+ ******************************************************************************/
+#define GXBB_UART0_AO_BASE			UL(0xC81004C0)
+#define GXBB_UART0_AO_CLK_IN_HZ			GXBB_OSC24M_CLK_IN_HZ
+#define GXBB_UART_BAUDRATE			U(115200)
+
+/*******************************************************************************
+ * Memory-mapped I/O Registers
+ ******************************************************************************/
+#define GXBB_AO_TIMESTAMP_CNTL			UL(0xC81000B4)
+
+#define GXBB_SYS_CPU_CFG7			UL(0xC8834664)
+
+#define GXBB_AO_RTI_STATUS_REG3			UL(0xDA10001C)
+
+#define GXBB_HIU_MAILBOX_SET_0			UL(0xDA83C404)
+#define GXBB_HIU_MAILBOX_STAT_0			UL(0xDA83C408)
+#define GXBB_HIU_MAILBOX_CLR_0			UL(0xDA83C40C)
+#define GXBB_HIU_MAILBOX_SET_3			UL(0xDA83C428)
+#define GXBB_HIU_MAILBOX_STAT_3			UL(0xDA83C42C)
+#define GXBB_HIU_MAILBOX_CLR_3			UL(0xDA83C430)
+
+/*******************************************************************************
+ * System Monitor Call IDs and arguments
+ ******************************************************************************/
+#define GXBB_SM_GET_SHARE_MEM_INPUT_BASE	U(0x82000020)
+#define GXBB_SM_GET_SHARE_MEM_OUTPUT_BASE	U(0x82000021)
+
+#define GXBB_SM_EFUSE_READ			U(0x82000030)
+#define GXBB_SM_EFUSE_USER_MAX			U(0x82000033)
+
+#define GXBB_SM_JTAG_ON				U(0x82000040)
+#define GXBB_SM_JTAG_OFF			U(0x82000041)
+
+#define GXBB_JTAG_STATE_ON			U(0)
+#define GXBB_JTAG_STATE_OFF			U(1)
+
+#define GXBB_JTAG_M3_AO				U(0)
+#define GXBB_JTAG_M3_EE				U(1)
+#define GXBB_JTAG_A53_AO			U(2)
+#define GXBB_JTAG_A53_EE			U(3)
+
+#endif /* GXBB_DEF_H */
diff --git a/plat/meson/gxbb/gxbb_efuse.c b/plat/meson/gxbb/gxbb_efuse.c
new file mode 100644
index 0000000..edea542
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_efuse.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include "gxbb_private.h"
+
+#define EFUSE_BASE	0x140
+#define EFUSE_SIZE	0xC0
+
+uint64_t gxbb_efuse_read(void *dst, uint32_t offset, uint32_t size)
+{
+	if ((uint64_t)(offset + size) > (uint64_t)EFUSE_SIZE)
+		return 0;
+
+	return scpi_efuse_read(dst, offset + EFUSE_BASE, size);
+}
+
+uint64_t gxbb_efuse_user_max(void)
+{
+	return EFUSE_SIZE;
+}
diff --git a/plat/meson/gxbb/gxbb_mhu.c b/plat/meson/gxbb/gxbb_mhu.c
new file mode 100644
index 0000000..903ef41
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_mhu.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+static DEFINE_BAKERY_LOCK(mhu_lock);
+
+void mhu_secure_message_start(void)
+{
+	bakery_lock_get(&mhu_lock);
+
+	while (mmio_read_32(GXBB_HIU_MAILBOX_STAT_3) != 0)
+		;
+}
+
+void mhu_secure_message_send(uint32_t msg)
+{
+	mmio_write_32(GXBB_HIU_MAILBOX_SET_3, msg);
+
+	while (mmio_read_32(GXBB_HIU_MAILBOX_STAT_3) != 0)
+		;
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+	uint32_t val;
+
+	do {
+		val = mmio_read_32(GXBB_HIU_MAILBOX_STAT_0);
+	} while (val == 0);
+
+	return val;
+}
+
+void mhu_secure_message_end(void)
+{
+	mmio_write_32(GXBB_HIU_MAILBOX_CLR_0, 0xFFFFFFFF);
+
+	bakery_lock_release(&mhu_lock);
+}
+
+void mhu_secure_init(void)
+{
+	bakery_lock_init(&mhu_lock);
+
+	mmio_write_32(GXBB_HIU_MAILBOX_CLR_3, 0xFFFFFFFF);
+}
diff --git a/plat/meson/gxbb/gxbb_pm.c b/plat/meson/gxbb/gxbb_pm.c
new file mode 100644
index 0000000..59b9436
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_pm.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "gxbb_private.h"
+
+#define SCPI_POWER_ON		0
+#define SCPI_POWER_RETENTION	1
+#define SCPI_POWER_OFF		3
+
+#define SCPI_SYSTEM_SHUTDOWN	0
+#define SCPI_SYSTEM_REBOOT	1
+
+static uintptr_t gxbb_sec_entrypoint;
+static volatile uint32_t gxbb_cpu0_go;
+
+static void gxbb_program_mailbox(u_register_t mpidr, uint64_t value)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+	uintptr_t cpu_mailbox_addr = GXBB_PSCI_MAILBOX_BASE + (core << 4);
+
+	mmio_write_64(cpu_mailbox_addr, value);
+	flush_dcache_range(cpu_mailbox_addr, sizeof(uint64_t));
+}
+
+static void __dead2 gxbb_system_reset(void)
+{
+	INFO("BL31: PSCI_SYSTEM_RESET\n");
+
+	uint32_t status = mmio_read_32(GXBB_AO_RTI_STATUS_REG3);
+
+	NOTICE("BL31: Reboot reason: 0x%x\n", status);
+
+	status &= 0xFFFF0FF0;
+
+	console_flush();
+
+	mmio_write_32(GXBB_AO_RTI_STATUS_REG3, status);
+
+	int ret = scpi_sys_power_state(SCPI_SYSTEM_REBOOT);
+
+	if (ret != 0) {
+		ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret);
+		panic();
+	}
+
+	wfi();
+
+	ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
+	panic();
+}
+
+static void __dead2 gxbb_system_off(void)
+{
+	INFO("BL31: PSCI_SYSTEM_OFF\n");
+
+	unsigned int ret = scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
+
+	if (ret != 0) {
+		ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret);
+		panic();
+	}
+
+	gxbb_program_mailbox(read_mpidr_el1(), 0);
+
+	wfi();
+
+	ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
+	panic();
+}
+
+static int32_t gxbb_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == GXBB_PRIMARY_CPU) {
+		VERBOSE("BL31: Releasing CPU0 from wait loop...\n");
+
+		gxbb_cpu0_go = 1;
+		flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go));
+		dsb();
+		isb();
+
+		sev();
+
+		return PSCI_E_SUCCESS;
+	}
+
+	gxbb_program_mailbox(mpidr, gxbb_sec_entrypoint);
+	scpi_set_css_power_state(mpidr,
+				 SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON);
+	dmbsy();
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1());
+
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_LOCAL_STATE_OFF);
+
+	if (core == GXBB_PRIMARY_CPU) {
+		gxbb_cpu0_go = 0;
+		flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go));
+		dsb();
+		isb();
+	}
+
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+static void gxbb_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+	uintptr_t addr = GXBB_PSCI_MAILBOX_BASE + 8 + (core << 4);
+
+	mmio_write_32(addr, 0xFFFFFFFF);
+	flush_dcache_range(addr, sizeof(uint32_t));
+
+	gicv2_cpuif_disable();
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == GXBB_PRIMARY_CPU)
+		return;
+
+	scpi_set_css_power_state(mpidr,
+				 SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON);
+}
+
+static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t
+						 *target_state)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1());
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == GXBB_PRIMARY_CPU) {
+		VERBOSE("BL31: CPU0 entering wait loop...\n");
+
+		while (gxbb_cpu0_go == 0)
+			wfe();
+
+		VERBOSE("BL31: CPU0 resumed.\n");
+
+		write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT);
+	}
+
+	dsbsy();
+
+	for (;;)
+		wfi();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t gxbb_ops = {
+	.pwr_domain_on			= gxbb_pwr_domain_on,
+	.pwr_domain_on_finish		= gxbb_pwr_domain_on_finish,
+	.pwr_domain_off			= gxbb_pwr_domain_off,
+	.pwr_domain_pwr_down_wfi	= gxbb_pwr_domain_pwr_down_wfi,
+	.system_off			= gxbb_system_off,
+	.system_reset			= gxbb_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	gxbb_sec_entrypoint = sec_entrypoint;
+	*psci_ops = &gxbb_ops;
+	gxbb_cpu0_go = 0;
+	return 0;
+}
diff --git a/plat/meson/gxbb/gxbb_private.h b/plat/meson/gxbb/gxbb_private.h
new file mode 100644
index 0000000..910a42c
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_private.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GXBB_PRIVATE_H
+#define GXBB_PRIVATE_H
+
+#include <stdint.h>
+
+/* Utility functions */
+unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr);
+void gxbb_console_init(void);
+void gxbb_setup_page_tables(void);
+
+/* MHU functions */
+void mhu_secure_message_start(void);
+void mhu_secure_message_send(uint32_t msg);
+uint32_t mhu_secure_message_wait(void);
+void mhu_secure_message_end(void);
+void mhu_secure_init(void);
+
+/* SCPI functions */
+void scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state,
+			      uint32_t cluster_state, uint32_t css_state);
+uint32_t scpi_sys_power_state(uint64_t system_state);
+void scpi_jtag_set_state(uint32_t state, uint8_t select);
+uint32_t scpi_efuse_read(void *dst, uint32_t base, uint32_t size);
+void scpi_unknown_thermal(uint32_t arg0, uint32_t arg1,
+			  uint32_t arg2, uint32_t arg3);
+
+/* Peripherals */
+void gxbb_thermal_unknown(void);
+uint64_t gxbb_efuse_read(void *dst, uint32_t offset, uint32_t size);
+uint64_t gxbb_efuse_user_max(void);
+
+#endif /* GXBB_PRIVATE_H */
diff --git a/plat/meson/gxbb/gxbb_scpi.c b/plat/meson/gxbb/gxbb_scpi.c
new file mode 100644
index 0000000..83eeda2
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_scpi.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "gxbb_private.h"
+
+#define SIZE_SHIFT	20
+#define SIZE_MASK	0x1FF
+
+/*
+ * Note: The Amlogic SCP firmware uses the legacy SCPI protocol.
+ */
+#define SCPI_CMD_SET_CSS_POWER_STATE	0x04
+#define SCPI_CMD_SET_SYS_POWER_STATE	0x08
+
+#define SCPI_CMD_JTAG_SET_STATE		0xC0
+#define SCPI_CMD_EFUSE_READ		0xC2
+
+static inline uint32_t scpi_cmd(uint32_t command, uint32_t size)
+{
+	return command | (size << SIZE_SHIFT);
+}
+
+void scpi_secure_message_send(uint32_t command, uint32_t size)
+{
+	mhu_secure_message_send(scpi_cmd(command, size));
+}
+
+uint32_t scpi_secure_message_receive(void **message_out, size_t *size_out)
+{
+	uint32_t response = mhu_secure_message_wait();
+
+	size_t size = (response >> SIZE_SHIFT) & SIZE_MASK;
+
+	response &= ~(SIZE_MASK << SIZE_SHIFT);
+
+	if (size_out != NULL)
+		*size_out = size;
+
+	if (message_out != NULL)
+		*message_out = (void *)GXBB_MHU_SECURE_SCP_TO_AP_PAYLOAD;
+
+	return response;
+}
+
+void scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state,
+			      uint32_t cluster_state, uint32_t css_state)
+{
+	uint32_t state = (mpidr & 0x0F) | /* CPU ID */
+			 ((mpidr & 0xF00) >> 4) | /* Cluster ID */
+			 (cpu_state << 8) |
+			 (cluster_state << 12) |
+			 (css_state << 16);
+
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, state);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_SET_CSS_POWER_STATE, 4));
+	mhu_secure_message_wait();
+	mhu_secure_message_end();
+}
+
+uint32_t scpi_sys_power_state(uint64_t system_state)
+{
+	uint32_t *response;
+	size_t size;
+
+	mhu_secure_message_start();
+	mmio_write_8(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, system_state);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_SET_SYS_POWER_STATE, 1));
+	scpi_secure_message_receive((void *)&response, &size);
+	mhu_secure_message_end();
+
+	return *response;
+}
+
+void scpi_jtag_set_state(uint32_t state, uint8_t select)
+{
+	assert(state <= GXBB_JTAG_STATE_OFF);
+
+	if (select > GXBB_JTAG_A53_EE) {
+		WARN("BL31: Invalid JTAG select (0x%x).\n", select);
+		return;
+	}
+
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD,
+		      (state << 8) | (uint32_t)select);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_JTAG_SET_STATE, 4));
+	mhu_secure_message_wait();
+	mhu_secure_message_end();
+}
+
+uint32_t scpi_efuse_read(void *dst, uint32_t base, uint32_t size)
+{
+	uint32_t *response;
+	size_t resp_size;
+
+	if (size > 0x1FC)
+		return 0;
+
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, base);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 4, size);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_EFUSE_READ, 8));
+	scpi_secure_message_receive((void *)&response, &resp_size);
+	mhu_secure_message_end();
+
+	/*
+	 * response[0] is the size of the response message.
+	 * response[1 ... N] are the contents.
+	 */
+	if (*response != 0)
+		memcpy(dst, response + 1, *response);
+
+	return *response;
+}
+
+void scpi_unknown_thermal(uint32_t arg0, uint32_t arg1,
+			  uint32_t arg2, uint32_t arg3)
+{
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x0, arg0);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x4, arg1);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x8, arg2);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0xC, arg3);
+	mhu_secure_message_send(scpi_cmd(0xC3, 16));
+	mhu_secure_message_wait();
+	mhu_secure_message_end();
+}
diff --git a/plat/meson/gxbb/gxbb_sip_svc.c b/plat/meson/gxbb/gxbb_sip_svc.c
new file mode 100644
index 0000000..63c7dba
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_sip_svc.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include "gxbb_private.h"
+
+/*******************************************************************************
+ * This function is responsible for handling all SiP calls
+ ******************************************************************************/
+static uintptr_t gxbb_sip_handler(uint32_t smc_fid,
+				  u_register_t x1, u_register_t x2,
+				  u_register_t x3, u_register_t x4,
+				  void *cookie, void *handle,
+				  u_register_t flags)
+{
+	switch (smc_fid) {
+
+	case GXBB_SM_GET_SHARE_MEM_INPUT_BASE:
+		SMC_RET1(handle, GXBB_SHARE_MEM_INPUT_BASE);
+
+	case GXBB_SM_GET_SHARE_MEM_OUTPUT_BASE:
+		SMC_RET1(handle, GXBB_SHARE_MEM_OUTPUT_BASE);
+
+	case GXBB_SM_EFUSE_READ:
+	{
+		void *dst = (void *)GXBB_SHARE_MEM_OUTPUT_BASE;
+		uint64_t ret = gxbb_efuse_read(dst, (uint32_t)x1, x2);
+
+		SMC_RET1(handle, ret);
+	}
+	case GXBB_SM_EFUSE_USER_MAX:
+		SMC_RET1(handle,  gxbb_efuse_user_max());
+
+	case GXBB_SM_JTAG_ON:
+		scpi_jtag_set_state(GXBB_JTAG_STATE_ON, x1);
+		SMC_RET1(handle, 0);
+
+	case GXBB_SM_JTAG_OFF:
+		scpi_jtag_set_state(GXBB_JTAG_STATE_OFF, x1);
+		SMC_RET1(handle, 0);
+
+	default:
+		ERROR("BL31: Unhandled SIP SMC: 0x%08x\n", smc_fid);
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
+
+DECLARE_RT_SVC(
+	gxbb_sip_handler,
+
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	gxbb_sip_handler
+);
diff --git a/plat/meson/gxbb/gxbb_thermal.c b/plat/meson/gxbb/gxbb_thermal.c
new file mode 100644
index 0000000..b6048ee
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_thermal.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include "gxbb_private.h"
+
+static int32_t modules_initialized = -1;
+
+/*******************************************************************************
+ * Unknown commands related to something thermal-related
+ ******************************************************************************/
+void gxbb_thermal_unknown(void)
+{
+	uint16_t ret;
+
+	if (modules_initialized == -1) {
+		scpi_efuse_read(&ret, 0, 2);
+		modules_initialized = ret;
+	}
+
+	scpi_unknown_thermal(10, 2,  /* thermal */
+			     13, 1); /* thermalver */
+}
diff --git a/plat/meson/gxbb/gxbb_topology.c b/plat/meson/gxbb/gxbb_topology.c
new file mode 100644
index 0000000..eec2d34
--- /dev/null
+++ b/plat/meson/gxbb/gxbb_topology.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include "gxbb_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first node */
+	PLATFORM_CLUSTER0_CORE_COUNT
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return plat_gxbb_calc_core_pos(mpidr);
+}
diff --git a/plat/meson/gxbb/include/plat_macros.S b/plat/meson/gxbb/include/plat_macros.S
new file mode 100644
index 0000000..c721c21
--- /dev/null
+++ b/plat/meson/gxbb/include/plat_macros.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+
+	/* GICC registers */
+
+	mov_imm	x17, GXBB_GICC_BASE
+
+	adr	x6, gicc_regs
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	bl	str_in_crash_buf_print
+
+	/* GICD registers */
+
+	mov_imm	x16, GXBB_GICD_BASE
+
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/meson/gxbb/include/platform_def.h b/plat/meson/gxbb/include/platform_def.h
new file mode 100644
index 0000000..da4aedd
--- /dev/null
+++ b/plat/meson/gxbb/include/platform_def.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include "../gxbb_def.h"
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define GXBB_BL31_PLAT_PARAM_VAL	ULL(0x0F1E2D3C4B5A6978)
+
+#define PLATFORM_STACK_SIZE		UL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define GXBB_PRIMARY_CPU		U(0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/* Local power state for power-down. Valid for CPU and cluster power domains. */
+#define PLAT_LOCAL_STATE_OFF		U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		U(4)
+#define PLAT_LOCAL_PSTATE_MASK		((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/* Memory-related defines */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+
+#define MAX_MMAP_REGIONS		12
+#define MAX_XLAT_TABLES			5
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/meson/gxbb/platform.mk b/plat/meson/gxbb/platform.mk
new file mode 100644
index 0000000..9e65040
--- /dev/null
+++ b/plat/meson/gxbb/platform.mk
@@ -0,0 +1,69 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES		:=	-Iplat/meson/gxbb/include
+
+GXBB_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/meson/console/aarch64/meson_console.S \
+				plat/meson/gxbb/gxbb_common.c		\
+				plat/meson/gxbb/gxbb_topology.c		\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/plat_psci_common.c		\
+				plat/meson/gxbb/aarch64/gxbb_helpers.S	\
+				plat/meson/gxbb/gxbb_bl31_setup.c	\
+				plat/meson/gxbb/gxbb_efuse.c		\
+				plat/meson/gxbb/gxbb_mhu.c		\
+				plat/meson/gxbb/gxbb_pm.c		\
+				plat/meson/gxbb/gxbb_scpi.c		\
+				plat/meson/gxbb/gxbb_sip_svc.c		\
+				plat/meson/gxbb/gxbb_thermal.c		\
+				${GXBB_GIC_SOURCES}
+
+# Tune compiler for Cortex-A53
+ifeq ($(notdir $(CC)),armclang)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else
+    TF_CFLAGS_aarch64	+=	-mtune=cortex-a53
+endif
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_826319		:= 1
+ERRATA_A53_835769		:= 1
+ERRATA_A53_836870		:= 1
+ERRATA_A53_843419		:= 1
+ERRATA_A53_855873		:= 1
+
+WORKAROUND_CVE_2017_5715	:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Verify build config
+# -------------------
+
+ifneq (${RESET_TO_BL31}, 0)
+  $(error Error: gxbb needs RESET_TO_BL31=0)
+endif
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on gxbb)
+endif
diff --git a/plat/meson/gxl/aarch64/gxl_helpers.S b/plat/meson/gxl/aarch64/gxl_helpers.S
new file mode 100644
index 0000000..760d6c4
--- /dev/null
+++ b/plat/meson/gxl/aarch64/gxl_helpers.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_crash_console_flush
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	platform_mem_init
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_gxbb_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_my_core_pos(void);
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_gxbb_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr);
+	 * -----------------------------------------------------
+	 */
+func plat_gxbb_calc_core_pos
+	and	x0, x0, #MPIDR_CPU_MASK
+	ret
+endfunc plat_gxbb_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary(void);
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #GXBB_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* ---------------------------------------------
+	 * void platform_mem_init(void);
+	 * ---------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, GXBB_UART0_AO_BASE
+	mov_imm	x1, GXBB_UART0_AO_CLK_IN_HZ
+	mov_imm	x2, GXBB_UART_BAUDRATE
+	b	console_meson_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, GXBB_UART0_AO_BASE
+	b	console_meson_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, GXBB_UART0_AO_BASE
+	b	console_meson_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------
+	 * void plat_reset_handler(void);
+	 * ---------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
diff --git a/plat/meson/gxl/gxl_bl31_setup.c b/plat/meson/gxl/gxl_bl31_setup.c
new file mode 100644
index 0000000..b1da794
--- /dev/null
+++ b/plat/meson/gxl/gxl_bl31_setup.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <common/interrupt_props.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+#include "gxl_private.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl33_image_ep_info;
+static image_info_t bl30_image_info;
+static image_info_t bl301_image_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(type == NON_SECURE);
+
+	next_image_info = &bl33_image_ep_info;
+
+	/* None of the images can have 0x0 as the entrypoint. */
+	if (next_image_info->pc != 0U) {
+		return next_image_info;
+	} else {
+		return NULL;
+	}
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+struct gxl_bl31_param {
+	param_header_t h;
+	image_info_t *bl31_image_info;
+	entry_point_info_t *bl32_ep_info;
+	image_info_t *bl32_image_info;
+	entry_point_info_t *bl33_ep_info;
+	image_info_t *bl33_image_info;
+	image_info_t *scp_image_info[];
+};
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	struct gxl_bl31_param *from_bl2;
+
+	/* Initialize the console to provide early debug support */
+	gxbb_console_init();
+
+	/* Check that params passed from BL2 are not NULL. */
+	from_bl2 = (struct gxl_bl31_param *) arg0;
+
+	/* Check params passed from BL2 are not NULL. */
+	assert(from_bl2 != NULL);
+	assert(from_bl2->h.type == PARAM_BL31);
+	assert(from_bl2->h.version >= VERSION_1);
+
+	/*
+	 * Copy BL33 entry point information. It is stored in Secure RAM, in
+	 * BL2's address space.
+	 */
+	bl33_image_ep_info = *from_bl2->bl33_ep_info;
+
+	if (bl33_image_ep_info.pc == 0U) {
+		ERROR("BL31: BL33 entrypoint not obtained from BL2\n");
+		panic();
+	}
+
+	bl30_image_info = *from_bl2->scp_image_info[0];
+	bl301_image_info = *from_bl2->scp_image_info[1];
+}
+
+void bl31_plat_arch_setup(void)
+{
+	gxbb_setup_page_tables();
+
+	enable_mmu_el3(0);
+}
+
+static inline bool gxl_scp_ready(void)
+{
+	return GXBB_AO_RTI_SCP_IS_READY(mmio_read_32(GXBB_AO_RTI_SCP_STAT));
+}
+
+static inline void gxl_scp_boot(void)
+{
+	scpi_upload_scp_fw(bl30_image_info.image_base,
+			bl30_image_info.image_size, 0);
+	scpi_upload_scp_fw(bl301_image_info.image_base,
+			bl301_image_info.image_size, 1);
+	while (!gxl_scp_ready())
+		;
+}
+
+/*******************************************************************************
+ * GICv2 driver setup information
+ ******************************************************************************/
+static const interrupt_prop_t gxbb_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+};
+
+static const gicv2_driver_data_t gxbb_gic_data = {
+	.gicd_base = GXBB_GICD_BASE,
+	.gicc_base = GXBB_GICC_BASE,
+	.interrupt_props = gxbb_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(gxbb_interrupt_props),
+};
+
+void bl31_platform_setup(void)
+{
+	mhu_secure_init();
+
+	gicv2_driver_init(&gxbb_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	gxl_scp_boot();
+
+	gxbb_thermal_unknown();
+}
diff --git a/plat/meson/gxl/gxl_common.c b/plat/meson/gxl/gxl_common.c
new file mode 100644
index 0000000..e3bd604
--- /dev/null
+++ b/plat/meson/gxl/gxl_common.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/ep_info.h>
+#include <bl31/interrupt_mgmt.h>
+#include <meson_console.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <stdint.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+/*******************************************************************************
+ * Platform memory map regions
+ ******************************************************************************/
+#define MAP_NSDRAM0	MAP_REGION_FLAT(GXBB_NSDRAM0_BASE,		\
+					GXBB_NSDRAM0_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_NSDRAM1	MAP_REGION_FLAT(GXBB_NSDRAM1_BASE,		\
+					GXBB_NSDRAM1_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_SEC_DEVICE0	MAP_REGION_FLAT(GXBB_SEC_DEVICE0_BASE,		\
+					GXBB_SEC_DEVICE0_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE1	MAP_REGION_FLAT(GXBB_SEC_DEVICE1_BASE,		\
+					GXBB_SEC_DEVICE1_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_TZRAM	MAP_REGION_FLAT(GXBB_TZRAM_BASE,		\
+					GXBB_TZRAM_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE2	MAP_REGION_FLAT(GXBB_SEC_DEVICE2_BASE,		\
+					GXBB_SEC_DEVICE2_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE3	MAP_REGION_FLAT(GXBB_SEC_DEVICE3_BASE,		\
+					GXBB_SEC_DEVICE3_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+static const mmap_region_t gxbb_mmap[] = {
+	MAP_NSDRAM0,
+	MAP_NSDRAM1,
+	MAP_SEC_DEVICE0,
+	MAP_SEC_DEVICE1,
+	MAP_TZRAM,
+	MAP_SEC_DEVICE2,
+	MAP_SEC_DEVICE3,
+	{0}
+};
+
+/*******************************************************************************
+ * Per-image regions
+ ******************************************************************************/
+#define MAP_BL31	MAP_REGION_FLAT(BL31_BASE,			\
+				BL31_END - BL31_BASE,			\
+				MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_BL_CODE	MAP_REGION_FLAT(BL_CODE_BASE,			\
+				BL_CODE_END - BL_CODE_BASE,		\
+				MT_CODE | MT_SECURE)
+
+#define MAP_BL_RO_DATA	MAP_REGION_FLAT(BL_RO_DATA_BASE,		\
+				BL_RO_DATA_END - BL_RO_DATA_BASE,	\
+				MT_RO_DATA | MT_SECURE)
+
+#define MAP_BL_COHERENT	MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,		\
+				BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \
+				MT_DEVICE | MT_RW | MT_SECURE)
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+void gxbb_setup_page_tables(void)
+{
+#if IMAGE_BL31
+	const mmap_region_t gxbb_bl_mmap[] = {
+		MAP_BL31,
+		MAP_BL_CODE,
+		MAP_BL_RO_DATA,
+#if USE_COHERENT_MEM
+		MAP_BL_COHERENT,
+#endif
+		{0}
+	};
+#endif
+
+	mmap_add(gxbb_bl_mmap);
+
+	mmap_add(gxbb_mmap);
+
+	init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Function that sets up the console
+ ******************************************************************************/
+static console_meson_t gxbb_console;
+
+void gxbb_console_init(void)
+{
+	int rc = console_meson_register(GXBB_UART0_AO_BASE,
+					GXBB_UART0_AO_CLK_IN_HZ,
+					GXBB_UART_BAUDRATE,
+					&gxbb_console);
+	if (rc == 0) {
+		/*
+		 * The crash console doesn't use the multi console API, it uses
+		 * the core console functions directly. It is safe to call panic
+		 * and let it print debug information.
+		 */
+		panic();
+	}
+
+	console_set_scope(&gxbb_console.console,
+			  CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+}
+
+/*******************************************************************************
+ * Function that returns the system counter frequency
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+	uint32_t val;
+
+	val = mmio_read_32(GXBB_SYS_CPU_CFG7);
+	val &= 0xFDFFFFFF;
+	mmio_write_32(GXBB_SYS_CPU_CFG7, val);
+
+	val = mmio_read_32(GXBB_AO_TIMESTAMP_CNTL);
+	val &= 0xFFFFFE00;
+	mmio_write_32(GXBB_AO_TIMESTAMP_CNTL, val);
+
+	return GXBB_OSC24M_CLK_IN_HZ;
+}
diff --git a/plat/meson/gxl/gxl_def.h b/plat/meson/gxl/gxl_def.h
new file mode 100644
index 0000000..089fa8d
--- /dev/null
+++ b/plat/meson/gxl/gxl_def.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GXBB_DEF_H
+#define GXBB_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * System oscillator
+ ******************************************************************************/
+#define GXBB_OSC24M_CLK_IN_HZ			ULL(24000000) /* 24 MHz */
+
+/*******************************************************************************
+ * Memory regions
+ ******************************************************************************/
+#define GXBB_NSDRAM0_BASE			UL(0x01000000)
+#define GXBB_NSDRAM0_SIZE			UL(0x0F000000)
+
+#define GXBB_NSDRAM1_BASE			UL(0x10000000)
+#define GXBB_NSDRAM1_SIZE			UL(0x00100000)
+
+#define BL31_BASE				UL(0x05100000)
+#define BL31_SIZE				UL(0x000C0000)
+#define BL31_LIMIT				(BL31_BASE + BL31_SIZE)
+
+/* Shared memory used for SMC services */
+#define GXBB_SHARE_MEM_INPUT_BASE		UL(0x050FE000)
+#define GXBB_SHARE_MEM_OUTPUT_BASE		UL(0x050FF000)
+
+#define GXBB_SEC_DEVICE0_BASE			UL(0xC0000000)
+#define GXBB_SEC_DEVICE0_SIZE			UL(0x09000000)
+
+#define GXBB_SEC_DEVICE1_BASE			UL(0xD0040000)
+#define GXBB_SEC_DEVICE1_SIZE			UL(0x00008000)
+
+#define GXBB_TZRAM_BASE				UL(0xD9000000)
+#define GXBB_TZRAM_SIZE				UL(0x00014000)
+/* Top 0xC000 bytes (up to 0xD9020000) used by BL2 */
+
+/* Mailboxes */
+#define GXBB_MHU_SECURE_SCP_TO_AP_PAYLOAD	UL(0xD9013800)
+#define GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD	UL(0xD9013A00)
+#define GXBB_PSCI_MAILBOX_BASE			UL(0xD9013F00)
+
+// * [	 1K]	0xD901_3800 - 0xD901_3BFF	Secure Mailbox (3)
+// * [	 1K]	0xD901_3400 - 0xD901_37FF	High Mailbox (2) *
+// * [	 1K]	0xD901_3000 - 0xD901_33FF	High Mailbox (1) *
+
+#define GXBB_TZROM_BASE				UL(0xD9040000)
+#define GXBB_TZROM_SIZE				UL(0x00010000)
+
+#define GXBB_SEC_DEVICE2_BASE			UL(0xDA000000)
+#define GXBB_SEC_DEVICE2_SIZE			UL(0x00200000)
+
+#define GXBB_SEC_DEVICE3_BASE			UL(0xDA800000)
+#define GXBB_SEC_DEVICE3_SIZE			UL(0x00200000)
+
+/*******************************************************************************
+ * GIC-400 and interrupt handling related constants
+ ******************************************************************************/
+#define GXBB_GICD_BASE				UL(0xC4301000)
+#define GXBB_GICC_BASE				UL(0xC4302000)
+
+#define IRQ_SEC_PHY_TIMER			29
+
+#define IRQ_SEC_SGI_0				8
+#define IRQ_SEC_SGI_1				9
+#define IRQ_SEC_SGI_2				10
+#define IRQ_SEC_SGI_3				11
+#define IRQ_SEC_SGI_4				12
+#define IRQ_SEC_SGI_5				13
+#define IRQ_SEC_SGI_6				14
+#define IRQ_SEC_SGI_7				15
+
+/*******************************************************************************
+ * UART definitions
+ ******************************************************************************/
+#define GXBB_UART0_AO_BASE			UL(0xC81004C0)
+#define GXBB_UART0_AO_CLK_IN_HZ			GXBB_OSC24M_CLK_IN_HZ
+#define GXBB_UART_BAUDRATE			U(115200)
+
+/*******************************************************************************
+ * Memory-mapped I/O Registers
+ ******************************************************************************/
+#define GXBB_AO_TIMESTAMP_CNTL			UL(0xC81000B4)
+
+#define GXBB_SYS_CPU_CFG7			UL(0xC8834664)
+
+#define GXBB_AO_RTI_STATUS_REG3			UL(0xDA10001C)
+#define GXBB_AO_RTI_SCP_STAT			UL(0xDA10023C)
+#define GXBB_AO_RTI_SCP_READY_OFF		U(0x14)
+#define GXBB_A0_RTI_SCP_READY_MASK		U(3)
+#define GXBB_AO_RTI_SCP_IS_READY(v)		\
+	((((v) >> GXBB_AO_RTI_SCP_READY_OFF) & \
+	  GXBB_A0_RTI_SCP_READY_MASK) == GXBB_A0_RTI_SCP_READY_MASK)
+
+#define GXBB_HIU_MAILBOX_SET_0			UL(0xDA83C404)
+#define GXBB_HIU_MAILBOX_STAT_0			UL(0xDA83C408)
+#define GXBB_HIU_MAILBOX_CLR_0			UL(0xDA83C40C)
+#define GXBB_HIU_MAILBOX_SET_3			UL(0xDA83C428)
+#define GXBB_HIU_MAILBOX_STAT_3			UL(0xDA83C42C)
+#define GXBB_HIU_MAILBOX_CLR_3			UL(0xDA83C430)
+
+/*******************************************************************************
+ * System Monitor Call IDs and arguments
+ ******************************************************************************/
+#define GXBB_SM_GET_SHARE_MEM_INPUT_BASE	U(0x82000020)
+#define GXBB_SM_GET_SHARE_MEM_OUTPUT_BASE	U(0x82000021)
+
+#define GXBB_SM_EFUSE_READ			U(0x82000030)
+#define GXBB_SM_EFUSE_USER_MAX			U(0x82000033)
+
+#define GXBB_SM_JTAG_ON				U(0x82000040)
+#define GXBB_SM_JTAG_OFF			U(0x82000041)
+
+#define GXBB_JTAG_STATE_ON			U(0)
+#define GXBB_JTAG_STATE_OFF			U(1)
+
+#define GXBB_JTAG_M3_AO				U(0)
+#define GXBB_JTAG_M3_EE				U(1)
+#define GXBB_JTAG_A53_AO			U(2)
+#define GXBB_JTAG_A53_EE			U(3)
+
+#endif /* GXBB_DEF_H */
diff --git a/plat/meson/gxl/gxl_efuse.c b/plat/meson/gxl/gxl_efuse.c
new file mode 100644
index 0000000..b17d1b8
--- /dev/null
+++ b/plat/meson/gxl/gxl_efuse.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include "gxl_private.h"
+
+#define EFUSE_BASE	0x140
+#define EFUSE_SIZE	0xC0
+
+uint64_t gxbb_efuse_read(void *dst, uint32_t offset, uint32_t size)
+{
+	if ((uint64_t)(offset + size) > (uint64_t)EFUSE_SIZE)
+		return 0;
+
+	return scpi_efuse_read(dst, offset + EFUSE_BASE, size);
+}
+
+uint64_t gxbb_efuse_user_max(void)
+{
+	return EFUSE_SIZE;
+}
diff --git a/plat/meson/gxl/gxl_mhu.c b/plat/meson/gxl/gxl_mhu.c
new file mode 100644
index 0000000..4c1d5b6
--- /dev/null
+++ b/plat/meson/gxl/gxl_mhu.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+static DEFINE_BAKERY_LOCK(mhu_lock);
+
+void mhu_secure_message_start(void)
+{
+	bakery_lock_get(&mhu_lock);
+
+	while (mmio_read_32(GXBB_HIU_MAILBOX_STAT_3) != 0)
+		;
+}
+
+void mhu_secure_message_send(uint32_t msg)
+{
+	mmio_write_32(GXBB_HIU_MAILBOX_SET_3, msg);
+
+	while (mmio_read_32(GXBB_HIU_MAILBOX_STAT_3) != 0)
+		;
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+	uint32_t val;
+
+	do {
+		val = mmio_read_32(GXBB_HIU_MAILBOX_STAT_0);
+	} while (val == 0);
+
+	return val;
+}
+
+void mhu_secure_message_end(void)
+{
+	mmio_write_32(GXBB_HIU_MAILBOX_CLR_0, 0xFFFFFFFF);
+
+	bakery_lock_release(&mhu_lock);
+}
+
+void mhu_secure_init(void)
+{
+	bakery_lock_init(&mhu_lock);
+
+	mmio_write_32(GXBB_HIU_MAILBOX_CLR_3, 0xFFFFFFFF);
+}
diff --git a/plat/meson/gxl/gxl_pm.c b/plat/meson/gxl/gxl_pm.c
new file mode 100644
index 0000000..4a5d26e
--- /dev/null
+++ b/plat/meson/gxl/gxl_pm.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <drivers/console.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <lib/psci/psci.h>
+
+#include "gxl_private.h"
+
+#define SCPI_POWER_ON		0
+#define SCPI_POWER_RETENTION	1
+#define SCPI_POWER_OFF		3
+
+#define SCPI_SYSTEM_SHUTDOWN	0
+#define SCPI_SYSTEM_REBOOT	1
+
+static uintptr_t gxbb_sec_entrypoint;
+static volatile uint32_t gxbb_cpu0_go;
+
+static void gxl_pm_set_reset_addr(u_register_t mpidr, uint64_t value)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+	uintptr_t cpu_mailbox_addr = GXBB_PSCI_MAILBOX_BASE + (core << 4);
+
+	mmio_write_64(cpu_mailbox_addr, value);
+}
+
+static void gxl_pm_reset(u_register_t mpidr)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+	uintptr_t cpu_mailbox_addr = GXBB_PSCI_MAILBOX_BASE + (core << 4) + 8;
+
+	mmio_write_32(cpu_mailbox_addr, 0);
+}
+
+static void __dead2 gxbb_system_reset(void)
+{
+	INFO("BL31: PSCI_SYSTEM_RESET\n");
+
+	u_register_t mpidr = read_mpidr_el1();
+	uint32_t status = mmio_read_32(GXBB_AO_RTI_STATUS_REG3);
+	int ret;
+
+	NOTICE("BL31: Reboot reason: 0x%x\n", status);
+
+	status &= 0xFFFF0FF0;
+
+	console_flush();
+
+	mmio_write_32(GXBB_AO_RTI_STATUS_REG3, status);
+
+	ret = scpi_sys_power_state(SCPI_SYSTEM_REBOOT);
+
+	if (ret != 0) {
+		ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret);
+		panic();
+	}
+
+	gxl_pm_reset(mpidr);
+
+	wfi();
+
+	ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
+	panic();
+}
+
+static void __dead2 gxbb_system_off(void)
+{
+	INFO("BL31: PSCI_SYSTEM_OFF\n");
+
+	u_register_t mpidr = read_mpidr_el1();
+	int ret;
+
+	ret = scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
+
+	if (ret != 0) {
+		ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret);
+		panic();
+	}
+
+	gxl_pm_set_reset_addr(mpidr, 0);
+	gxl_pm_reset(mpidr);
+
+	wfi();
+
+	ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
+	panic();
+}
+
+static int32_t gxbb_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == GXBB_PRIMARY_CPU) {
+		VERBOSE("BL31: Releasing CPU0 from wait loop...\n");
+
+		gxbb_cpu0_go = 1;
+		flush_dcache_range((uintptr_t)&gxbb_cpu0_go,
+				sizeof(gxbb_cpu0_go));
+		dsb();
+		isb();
+
+		sev();
+
+		return PSCI_E_SUCCESS;
+	}
+
+	gxl_pm_set_reset_addr(mpidr, gxbb_sec_entrypoint);
+	scpi_set_css_power_state(mpidr,
+				 SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON);
+	dmbsy();
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1());
+
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_LOCAL_STATE_OFF);
+
+	if (core == GXBB_PRIMARY_CPU) {
+		gxbb_cpu0_go = 0;
+		flush_dcache_range((uintptr_t)&gxbb_cpu0_go,
+				sizeof(gxbb_cpu0_go));
+		dsb();
+		isb();
+	}
+
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+static void gxbb_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+
+	gicv2_cpuif_disable();
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == GXBB_PRIMARY_CPU)
+		return;
+
+	scpi_set_css_power_state(mpidr,
+				 SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON);
+}
+
+static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t
+						 *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = plat_gxbb_calc_core_pos(mpidr);
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == GXBB_PRIMARY_CPU) {
+		VERBOSE("BL31: CPU0 entering wait loop...\n");
+
+		while (gxbb_cpu0_go == 0)
+			wfe();
+
+		VERBOSE("BL31: CPU0 resumed.\n");
+
+		/*
+		 * Because setting CPU0's warm reset entrypoint through PSCI
+		 * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem
+		 * to work, jump to it manually.
+		 * In order to avoid an assert, mmu has to be disabled.
+		 */
+		disable_mmu_el3();
+		((void(*)(void))gxbb_sec_entrypoint)();
+	}
+
+	dsbsy();
+	gxl_pm_set_reset_addr(mpidr, 0);
+	gxl_pm_reset(mpidr);
+
+	for (;;)
+		wfi();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t gxbb_ops = {
+	.pwr_domain_on			= gxbb_pwr_domain_on,
+	.pwr_domain_on_finish		= gxbb_pwr_domain_on_finish,
+	.pwr_domain_off			= gxbb_pwr_domain_off,
+	.pwr_domain_pwr_down_wfi	= gxbb_pwr_domain_pwr_down_wfi,
+	.system_off			= gxbb_system_off,
+	.system_reset			= gxbb_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	gxbb_sec_entrypoint = sec_entrypoint;
+	*psci_ops = &gxbb_ops;
+	gxbb_cpu0_go = 0;
+	return 0;
+}
diff --git a/plat/meson/gxl/gxl_private.h b/plat/meson/gxl/gxl_private.h
new file mode 100644
index 0000000..913cbf6
--- /dev/null
+++ b/plat/meson/gxl/gxl_private.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GXBB_PRIVATE_H
+#define GXBB_PRIVATE_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Utility functions */
+unsigned int plat_gxbb_calc_core_pos(u_register_t mpidr);
+void gxbb_console_init(void);
+void gxbb_setup_page_tables(void);
+
+/* MHU functions */
+void mhu_secure_message_start(void);
+void mhu_secure_message_send(uint32_t msg);
+uint32_t mhu_secure_message_wait(void);
+void mhu_secure_message_end(void);
+void mhu_secure_init(void);
+
+/* SCPI functions */
+void scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state,
+			      uint32_t cluster_state, uint32_t css_state);
+uint32_t scpi_sys_power_state(uint64_t system_state);
+void scpi_jtag_set_state(uint32_t state, uint8_t select);
+uint32_t scpi_efuse_read(void *dst, uint32_t base, uint32_t size);
+void scpi_unknown_thermal(uint32_t arg0, uint32_t arg1,
+			  uint32_t arg2, uint32_t arg3);
+void scpi_upload_scp_fw(uintptr_t addr, size_t size, int send);
+
+/* Peripherals */
+void gxbb_thermal_unknown(void);
+uint64_t gxbb_efuse_read(void *dst, uint32_t offset, uint32_t size);
+uint64_t gxbb_efuse_user_max(void);
+
+#endif /* GXBB_PRIVATE_H */
diff --git a/plat/meson/gxl/gxl_scpi.c b/plat/meson/gxl/gxl_scpi.c
new file mode 100644
index 0000000..13d6524
--- /dev/null
+++ b/plat/meson/gxl/gxl_scpi.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <string.h>
+#include <crypto/sha_dma.h>
+
+#include "gxl_private.h"
+
+#define SIZE_SHIFT	20
+#define SIZE_MASK	0x1FF
+#define SIZE_FWBLK	0x200UL
+
+/*
+ * Note: The Amlogic SCP firmware uses the legacy SCPI protocol.
+ */
+#define SCPI_CMD_SET_CSS_POWER_STATE	0x04
+#define SCPI_CMD_SET_SYS_POWER_STATE	0x08
+
+#define SCPI_CMD_JTAG_SET_STATE		0xC0
+#define SCPI_CMD_EFUSE_READ		0xC2
+
+#define SCPI_CMD_COPY_FW 0xd4
+#define SCPI_CMD_SET_FW_ADDR 0xd3
+#define SCPI_CMD_FW_SIZE 0xd2
+
+static inline uint32_t scpi_cmd(uint32_t command, uint32_t size)
+{
+	return command | (size << SIZE_SHIFT);
+}
+
+static void scpi_secure_message_send(uint32_t command, uint32_t size)
+{
+	mhu_secure_message_send(scpi_cmd(command, size));
+}
+
+uint32_t scpi_secure_message_receive(void **message_out, size_t *size_out)
+{
+	uint32_t response = mhu_secure_message_wait();
+
+	size_t size = (response >> SIZE_SHIFT) & SIZE_MASK;
+
+	response &= ~(SIZE_MASK << SIZE_SHIFT);
+
+	if (size_out != NULL)
+		*size_out = size;
+
+	if (message_out != NULL)
+		*message_out = (void *)GXBB_MHU_SECURE_SCP_TO_AP_PAYLOAD;
+
+	return response;
+}
+
+void scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state,
+			      uint32_t cluster_state, uint32_t css_state)
+{
+	uint32_t state = (mpidr & 0x0F) | /* CPU ID */
+			 ((mpidr & 0xF00) >> 4) | /* Cluster ID */
+			 (cpu_state << 8) |
+			 (cluster_state << 12) |
+			 (css_state << 16);
+
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, state);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_SET_CSS_POWER_STATE, 4));
+	mhu_secure_message_wait();
+	mhu_secure_message_end();
+}
+
+uint32_t scpi_sys_power_state(uint64_t system_state)
+{
+	uint32_t *response;
+	size_t size;
+
+	mhu_secure_message_start();
+	mmio_write_8(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, system_state);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_SET_SYS_POWER_STATE, 1));
+	scpi_secure_message_receive((void *)&response, &size);
+	mhu_secure_message_end();
+
+	return *response;
+}
+
+void scpi_jtag_set_state(uint32_t state, uint8_t select)
+{
+	assert(state <= GXBB_JTAG_STATE_OFF);
+
+	if (select > GXBB_JTAG_A53_EE) {
+		WARN("BL31: Invalid JTAG select (0x%x).\n", select);
+		return;
+	}
+
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD,
+		      (state << 8) | (uint32_t)select);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_JTAG_SET_STATE, 4));
+	mhu_secure_message_wait();
+	mhu_secure_message_end();
+}
+
+uint32_t scpi_efuse_read(void *dst, uint32_t base, uint32_t size)
+{
+	uint32_t *response;
+	size_t resp_size;
+
+	if (size > 0x1FC)
+		return 0;
+
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, base);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 4, size);
+	mhu_secure_message_send(scpi_cmd(SCPI_CMD_EFUSE_READ, 8));
+	scpi_secure_message_receive((void *)&response, &resp_size);
+	mhu_secure_message_end();
+
+	/*
+	 * response[0] is the size of the response message.
+	 * response[1 ... N] are the contents.
+	 */
+	if (*response != 0)
+		memcpy(dst, response + 1, *response);
+
+	return *response;
+}
+
+void scpi_unknown_thermal(uint32_t arg0, uint32_t arg1,
+			  uint32_t arg2, uint32_t arg3)
+{
+	mhu_secure_message_start();
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x0, arg0);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x4, arg1);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x8, arg2);
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0xC, arg3);
+	mhu_secure_message_send(scpi_cmd(0xC3, 16));
+	mhu_secure_message_wait();
+	mhu_secure_message_end();
+}
+
+static inline void scpi_copy_scp_data(uint8_t *data, size_t len)
+{
+	void *dst = (void *)GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD;
+	size_t sz;
+
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, len);
+	scpi_secure_message_send(SCPI_CMD_FW_SIZE, len);
+	mhu_secure_message_wait();
+
+	for (sz = 0; sz < len; sz += SIZE_FWBLK) {
+		memcpy(dst, data + sz, MIN(SIZE_FWBLK, len - sz));
+		mhu_secure_message_send(SCPI_CMD_COPY_FW);
+	}
+}
+
+static inline void scpi_set_scp_addr(uint64_t addr, size_t len)
+{
+	volatile uint64_t *dst = (uint64_t *)GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD;
+
+	/*
+	 * It is ok as GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD is mapped as
+	 * non cachable
+	 */
+	*dst = addr;
+	scpi_secure_message_send(SCPI_CMD_SET_FW_ADDR, sizeof(addr));
+	mhu_secure_message_wait();
+
+	mmio_write_32(GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD, len);
+	scpi_secure_message_send(SCPI_CMD_FW_SIZE, len);
+	mhu_secure_message_wait();
+}
+
+static inline void scpi_send_fw_hash(uint8_t hash[], size_t len)
+{
+	void *dst = (void *)GXBB_MHU_SECURE_AP_TO_SCP_PAYLOAD;
+
+	memcpy(dst, hash, len);
+	mhu_secure_message_send(0xd0);
+	mhu_secure_message_send(0xd1);
+	mhu_secure_message_send(0xd5);
+	mhu_secure_message_end();
+}
+
+/**
+ * Upload a FW to SCP.
+ *
+ * @param addr: firmware data address
+ * @param size: size of firmware
+ * @param send: If set, actually copy the firmware in SCP memory otherwise only
+ *  send the firmware address.
+ */
+void scpi_upload_scp_fw(uintptr_t addr, size_t size, int send)
+{
+	struct asd_ctx ctx;
+
+	asd_sha_init(&ctx, ASM_SHA256);
+	asd_sha_update(&ctx, (void *)addr, size);
+	asd_sha_finalize(&ctx);
+
+	mhu_secure_message_start();
+	if (send == 0)
+		scpi_set_scp_addr(addr, size);
+	else
+		scpi_copy_scp_data((void *)addr, size);
+
+	scpi_send_fw_hash(ctx.digest, sizeof(ctx.digest));
+}
diff --git a/plat/meson/gxl/gxl_sip_svc.c b/plat/meson/gxl/gxl_sip_svc.c
new file mode 100644
index 0000000..74fbc80
--- /dev/null
+++ b/plat/meson/gxl/gxl_sip_svc.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+#include <common/runtime_svc.h>
+#include <stdint.h>
+
+#include "gxl_private.h"
+
+/*******************************************************************************
+ * This function is responsible for handling all SiP calls
+ ******************************************************************************/
+static uintptr_t gxbb_sip_handler(uint32_t smc_fid,
+				  u_register_t x1, u_register_t x2,
+				  u_register_t x3, u_register_t x4,
+				  void *cookie, void *handle,
+				  u_register_t flags)
+{
+	switch (smc_fid) {
+
+	case GXBB_SM_GET_SHARE_MEM_INPUT_BASE:
+		SMC_RET1(handle, GXBB_SHARE_MEM_INPUT_BASE);
+
+	case GXBB_SM_GET_SHARE_MEM_OUTPUT_BASE:
+		SMC_RET1(handle, GXBB_SHARE_MEM_OUTPUT_BASE);
+
+	case GXBB_SM_EFUSE_READ:
+	{
+		void *dst = (void *)GXBB_SHARE_MEM_OUTPUT_BASE;
+		uint64_t ret = gxbb_efuse_read(dst, (uint32_t)x1, x2);
+
+		SMC_RET1(handle, ret);
+	}
+	case GXBB_SM_EFUSE_USER_MAX:
+		SMC_RET1(handle,  gxbb_efuse_user_max());
+
+	case GXBB_SM_JTAG_ON:
+		scpi_jtag_set_state(GXBB_JTAG_STATE_ON, x1);
+		SMC_RET1(handle, 0);
+
+	case GXBB_SM_JTAG_OFF:
+		scpi_jtag_set_state(GXBB_JTAG_STATE_OFF, x1);
+		SMC_RET1(handle, 0);
+
+	default:
+		ERROR("BL31: Unhandled SIP SMC: 0x%08x\n", smc_fid);
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
+
+DECLARE_RT_SVC(
+	gxbb_sip_handler,
+
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	gxbb_sip_handler
+);
diff --git a/plat/meson/gxl/gxl_thermal.c b/plat/meson/gxl/gxl_thermal.c
new file mode 100644
index 0000000..3af1c6d
--- /dev/null
+++ b/plat/meson/gxl/gxl_thermal.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include "gxl_private.h"
+
+static int32_t modules_initialized = -1;
+
+/*******************************************************************************
+ * Unknown commands related to something thermal-related
+ ******************************************************************************/
+void gxbb_thermal_unknown(void)
+{
+	uint16_t ret;
+
+	if (modules_initialized == -1) {
+		scpi_efuse_read(&ret, 0, 2);
+		modules_initialized = ret;
+	}
+
+	scpi_unknown_thermal(10, 2,  /* thermal */
+			     13, 1); /* thermalver */
+}
diff --git a/plat/meson/gxl/gxl_topology.c b/plat/meson/gxl/gxl_topology.c
new file mode 100644
index 0000000..cca3ead
--- /dev/null
+++ b/plat/meson/gxl/gxl_topology.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+#include "gxl_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first node */
+	PLATFORM_CLUSTER0_CORE_COUNT
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return plat_gxbb_calc_core_pos(mpidr);
+}
diff --git a/plat/meson/gxl/include/plat_macros.S b/plat/meson/gxl/include/plat_macros.S
new file mode 100644
index 0000000..c721c21
--- /dev/null
+++ b/plat/meson/gxl/include/plat_macros.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+
+	/* GICC registers */
+
+	mov_imm	x17, GXBB_GICC_BASE
+
+	adr	x6, gicc_regs
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	bl	str_in_crash_buf_print
+
+	/* GICD registers */
+
+	mov_imm	x16, GXBB_GICD_BASE
+
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/meson/gxl/include/platform_def.h b/plat/meson/gxl/include/platform_def.h
new file mode 100644
index 0000000..b32ec56
--- /dev/null
+++ b/plat/meson/gxl/include/platform_def.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include "../gxl_def.h"
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define GXBB_BL31_PLAT_PARAM_VAL	ULL(0x0F1E2D3C4B5A6978)
+
+#define PLATFORM_STACK_SIZE		UL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define GXBB_PRIMARY_CPU		U(0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/* Local power state for power-down. Valid for CPU and cluster power domains. */
+#define PLAT_LOCAL_STATE_OFF		U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		U(4)
+#define PLAT_LOCAL_PSTATE_MASK		((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/* Memory-related defines */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+
+#define MAX_MMAP_REGIONS		12
+#define MAX_XLAT_TABLES			6
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/meson/gxl/platform.mk b/plat/meson/gxl/platform.mk
new file mode 100644
index 0000000..a788e96
--- /dev/null
+++ b/plat/meson/gxl/platform.mk
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+DOIMAGEPATH		?=	tools/meson
+DOIMAGETOOL		?=	${DOIMAGEPATH}/doimage
+
+PLAT_INCLUDES		:=	-Iinclude/drivers/meson/		\
+				-Iinclude/drivers/meson/gxl		\
+				-Iplat/meson/gxl/include
+
+GXBB_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/meson/console/aarch64/meson_console.S \
+				plat/meson/gxl/gxl_common.c		\
+				plat/meson/gxl/gxl_topology.c		\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/plat_psci_common.c		\
+				plat/meson/gxl/aarch64/gxl_helpers.S	\
+				plat/meson/gxl/gxl_bl31_setup.c		\
+				plat/meson/gxl/gxl_efuse.c		\
+				plat/meson/gxl/gxl_mhu.c		\
+				plat/meson/gxl/gxl_pm.c			\
+				plat/meson/gxl/gxl_scpi.c		\
+				plat/meson/gxl/gxl_sip_svc.c		\
+				plat/meson/gxl/gxl_thermal.c		\
+				drivers/meson/gxl/crypto/sha_dma.c	\
+				${GXBB_GIC_SOURCES}
+
+# Tune compiler for Cortex-A53
+ifeq ($(notdir $(CC)),armclang)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else
+    TF_CFLAGS_aarch64	+=	-mtune=cortex-a53
+endif
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_855873		:= 1
+ERRATA_A53_819472		:= 1
+ERRATA_A53_824069		:= 1
+ERRATA_A53_827319		:= 1
+
+WORKAROUND_CVE_2017_5715	:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Verify build config
+# -------------------
+
+ifneq (${RESET_TO_BL31}, 0)
+  $(error Error: gxl needs RESET_TO_BL31=0)
+endif
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on gxl)
+endif
+
+all: ${BUILD_PLAT}/bl31.img
+distclean realclean clean: cleanimage
+
+cleanimage:
+	${Q}${MAKE} -C ${DOIMAGEPATH} clean
+
+${DOIMAGETOOL}:
+	${Q}${MAKE} -C ${DOIMAGEPATH}
+
+${BUILD_PLAT}/bl31.img: ${BUILD_PLAT}/bl31.bin ${DOIMAGETOOL}
+	${DOIMAGETOOL} ${BUILD_PLAT}/bl31.bin ${BUILD_PLAT}/bl31.img
+
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
new file mode 100644
index 0000000..b47be6d
--- /dev/null
+++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <platform_def.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+
+#define MIDR_PN_CORTEX_A57		0xD07
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL3 bit definitions
+ ******************************************************************************/
+#define ACTLR_EL3_L2ACTLR_BIT		(U(1) << 6)
+#define ACTLR_EL3_L2ECTLR_BIT		(U(1) << 5)
+#define ACTLR_EL3_L2CTLR_BIT		(U(1) << 4)
+#define ACTLR_EL3_CPUECTLR_BIT		(U(1) << 1)
+#define ACTLR_EL3_CPUACTLR_BIT		(U(1) << 0)
+#define ACTLR_EL3_ENABLE_ALL_MASK	(ACTLR_EL3_L2ACTLR_BIT | \
+								ACTLR_EL3_L2ECTLR_BIT | \
+					 			ACTLR_EL3_L2CTLR_BIT | \
+					 			ACTLR_EL3_CPUECTLR_BIT | \
+					 			ACTLR_EL3_CPUACTLR_BIT)
+#define ACTLR_EL3_ENABLE_ALL_ACCESS	(ACTLR_EL3_L2ACTLR_BIT | \
+					 			ACTLR_EL3_L2ECTLR_BIT | \
+					 			ACTLR_EL3_L2CTLR_BIT | \
+					 			ACTLR_EL3_CPUECTLR_BIT | \
+					 			ACTLR_EL3_CPUACTLR_BIT)
+
+	/* Global functions */
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_get_my_entrypoint
+	.globl	plat_secondary_cold_boot_setup
+	.globl	platform_mem_init
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	tegra_secure_entrypoint
+	.globl	plat_reset_handler
+
+	/* Global variables */
+	.globl	tegra_sec_entry_point
+	.globl	ns_image_entrypoint
+	.globl	tegra_bl31_phys_base
+	.globl	tegra_console_base
+
+	/* ---------------------
+	 * Common CPU init code
+	 * ---------------------
+	 */
+.macro	cpu_init_common
+
+	/* ------------------------------------------------
+	 * We enable procesor retention, L2/CPUECTLR NS
+	 * access and ECC/Parity protection for A57 CPUs
+	 * ------------------------------------------------
+	 */
+	mrs	x0, midr_el1
+	mov	x1, #(MIDR_PN_MASK << MIDR_PN_SHIFT)
+	and	x0, x0, x1
+	lsr	x0, x0, #MIDR_PN_SHIFT
+	cmp	x0, #MIDR_PN_CORTEX_A57
+	b.ne	1f
+
+	/* ---------------------------
+	 * Enable processor retention
+	 * ---------------------------
+	 */
+	mrs	x0, CORTEX_A57_L2ECTLR_EL1
+	mov	x1, #RETENTION_ENTRY_TICKS_512
+	bic	x0, x0, #CORTEX_A57_L2ECTLR_RET_CTRL_MASK
+	orr	x0, x0, x1
+	msr	CORTEX_A57_L2ECTLR_EL1, x0
+	isb
+
+	mrs	x0, CORTEX_A57_ECTLR_EL1
+	mov	x1, #RETENTION_ENTRY_TICKS_512
+	bic	x0, x0, #CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK
+	orr	x0, x0, x1
+	msr	CORTEX_A57_ECTLR_EL1, x0
+	isb
+
+	/* -------------------------------------------------------
+	 * Enable L2 and CPU ECTLR RW access from non-secure world
+	 * -------------------------------------------------------
+	 */
+	mrs	x0, actlr_el3
+	mov	x1, #ACTLR_EL3_ENABLE_ALL_MASK
+	bic	x0, x0, x1
+	mov	x1, #ACTLR_EL3_ENABLE_ALL_ACCESS
+	orr	x0, x0, x1
+	msr	actlr_el3, x0
+	mrs	x0, actlr_el2
+	mov	x1, #ACTLR_EL3_ENABLE_ALL_MASK
+	bic	x0, x0, x1
+	mov	x1, #ACTLR_EL3_ENABLE_ALL_ACCESS
+	orr	x0, x0, x1
+	msr	actlr_el2, x0
+	isb
+
+	/* --------------------------------
+	 * Enable the cycle count register
+	 * --------------------------------
+	 */
+1:	mrs	x0, pmcr_el0
+	ubfx	x0, x0, #11, #5		// read PMCR.N field
+	mov	x1, #1
+	lsl	x0, x1, x0
+	sub	x0, x0, #1		// mask of event counters
+	orr	x0, x0, #0x80000000	// disable overflow intrs
+	msr	pmintenclr_el1, x0
+	msr	pmuserenr_el0, x1	// enable user mode access
+
+	/* ----------------------------------------------------------------
+	 * Allow non-privileged access to CNTVCT: Set CNTKCTL (Kernel Count
+	 * register), bit 1 (EL0VCTEN) to enable access to CNTVCT/CNTFRQ
+	 * registers from EL0.
+	 * ----------------------------------------------------------------
+	 */
+	mrs	x0, cntkctl_el1
+	orr	x0, x0, #EL0VCTEN_BIT
+	msr	cntkctl_el1, x0
+.endm
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary(void);
+	 *
+	 * This function checks if this is the Primary CPU
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #TEGRA_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* ----------------------------------------------------------
+	 * unsigned int plat_my_core_pos(void);
+	 *
+	 * result: CorePos = CoreId + (ClusterId * cpus per cluster)
+	 * ----------------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	lsr	x0, x0, #MPIDR_AFFINITY_BITS
+	mov	x2, #PLATFORM_MAX_CPUS_PER_CLUSTER
+	mul	x0, x0, x2
+	add	x0, x1, x0
+	ret
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned long plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between
+	 * a cold and warm boot. If the tegra_sec_entry_point for
+	 * this CPU is present, then it's a warm boot.
+	 *
+	 * -----------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	adr	x1, tegra_sec_entry_point
+	ldr	x0, [x1]
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* -----------------------------------------------------
+	 * int platform_get_core_pos(int mpidr);
+	 *
+	 * result: CorePos = (ClusterId * cpus per cluster) +
+	 *                   CoreId
+	 * -----------------------------------------------------
+	 */
+func platform_get_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	lsr	x0, x0, #MPIDR_AFFINITY_BITS
+	mov	x2, #PLATFORM_MAX_CPUS_PER_CLUSTER
+	mul	x0, x0, x2
+	add	x0, x1, x0
+	ret
+endfunc platform_get_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset. Right
+	 * now this is a stub function.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	mov	x0, #0
+	ret
+endfunc plat_secondary_cold_boot_setup
+
+	/* --------------------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * Any memory init, relocation to be done before the
+	 * platform boots. Called very early in the boot process.
+	 * --------------------------------------------------------
+	 */
+func platform_mem_init
+	mov	x0, #0
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov	x0, #0
+	adr	x1, tegra_console_base
+	ldr	x1, [x1]
+	cbz	x1, 1f
+	mov	w0, #1
+1:	ret
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(void)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	adr	x1, tegra_console_base
+	ldr	x1, [x1]
+	b	console_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	adr	x0, tegra_console_base
+	ldr	x0, [x0]
+	b	console_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------------
+	 * Function to handle a platform reset and store
+	 * input parameters passed by BL2.
+	 * ---------------------------------------------------
+	 */
+func plat_reset_handler
+
+	/* ----------------------------------------------------
+	 * Verify if we are running from BL31_BASE address
+	 * ----------------------------------------------------
+	 */
+	adr	x18, bl31_entrypoint
+	mov	x17, #BL31_BASE
+	cmp	x18, x17
+	b.eq	1f
+
+	/* ----------------------------------------------------
+	 * Copy the entire BL31 code to BL31_BASE if we are not
+	 * running from it already
+	 * ----------------------------------------------------
+	 */
+	mov	x0, x17
+	mov	x1, x18
+	mov	x2, #BL31_SIZE
+_loop16:
+	cmp	x2, #16
+	b.lo	_loop1
+	ldp	x3, x4, [x1], #16
+	stp	x3, x4, [x0], #16
+	sub	x2, x2, #16
+	b	_loop16
+	/* copy byte per byte */
+_loop1:
+	cbz	x2, _end
+	ldrb	w3, [x1], #1
+	strb	w3, [x0], #1
+	subs	x2, x2, #1
+	b.ne	_loop1
+
+	/* ----------------------------------------------------
+	 * Jump to BL31_BASE and start execution again
+	 * ----------------------------------------------------
+	 */
+_end:	mov	x0, x20
+	mov	x1, x21
+	br	x17
+1:
+
+	/* -----------------------------------
+	 * derive and save the phys_base addr
+	 * -----------------------------------
+	 */
+	adr	x17, tegra_bl31_phys_base
+	ldr	x18, [x17]
+	cbnz	x18, 1f
+	adr	x18, bl31_entrypoint
+	str	x18, [x17]
+
+1:	cpu_init_common
+
+	ret
+endfunc plat_reset_handler
+
+	/* ----------------------------------------
+	 * Secure entrypoint function for CPU boot
+	 * ----------------------------------------
+	 */
+func tegra_secure_entrypoint _align=6
+
+#if ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT
+
+	/* --------------------------------------------------------
+	 * Skip the invalidate BTB workaround for Tegra210B01 SKUs.
+	 * --------------------------------------------------------
+	 */
+	mov	x0, #TEGRA_MISC_BASE
+	add	x0, x0, #HARDWARE_REVISION_OFFSET
+	ldr	w1, [x0]
+	lsr	w1, w1, #CHIP_ID_SHIFT
+	and	w1, w1, #CHIP_ID_MASK
+	cmp	w1, #TEGRA_CHIPID_TEGRA21	/* T210? */
+	b.ne	2f
+	ldr	w1, [x0]
+	lsr	w1, w1, #MAJOR_VERSION_SHIFT
+	and	w1, w1, #MAJOR_VERSION_MASK
+	cmp	w1, #0x02			/* T210 B01? */
+	b.eq	2f
+
+	/* -------------------------------------------------------
+	 * Invalidate BTB along with I$ to remove any stale
+	 * entries from the branch predictor array.
+	 * -------------------------------------------------------
+	 */
+	mrs	x0, CORTEX_A57_CPUACTLR_EL1
+	orr	x0, x0, #1
+	msr	CORTEX_A57_CPUACTLR_EL1, x0	/* invalidate BTB and I$ together */
+	dsb	sy
+	isb
+	ic	iallu			/* actual invalidate */
+	dsb	sy
+	isb
+
+	mrs	x0, CORTEX_A57_CPUACTLR_EL1
+	bic	x0, x0, #1
+	msr	CORTEX_A57_CPUACTLR_EL1, X0	/* restore original CPUACTLR_EL1 */
+	dsb	sy
+	isb
+
+	.rept	7
+	nop				/* wait */
+	.endr
+
+	/* -----------------------------------------------
+	 * Extract OSLK bit and check if it is '1'. This
+	 * bit remains '0' for A53 on warm-resets. If '1',
+	 * turn off regional clock gating and request warm
+	 * reset.
+	 * -----------------------------------------------
+	 */
+	mrs	x0, oslsr_el1
+	and	x0, x0, #2
+	mrs	x1, mpidr_el1
+	bics	xzr, x0, x1, lsr #7	/* 0 = slow cluster or warm reset */
+	b.eq	restore_oslock
+	mov	x0, xzr
+	msr	oslar_el1, x0		/* os lock stays 0 across warm reset */
+	mov	x3, #3
+	movz	x4, #0x8000, lsl #48
+	msr	CORTEX_A57_CPUACTLR_EL1, x4	/* turn off RCG */
+	isb
+	msr	rmr_el3, x3		/* request warm reset */
+	isb
+	dsb	sy
+1:	wfi
+	b	1b
+
+	/* --------------------------------------------------
+	 * These nops are here so that speculative execution
+	 * won't harm us before we are done with warm reset.
+	 * --------------------------------------------------
+	 */
+	.rept	65
+	nop
+	.endr
+2:
+	/* --------------------------------------------------
+	 * Do not insert instructions here
+	 * --------------------------------------------------
+	 */
+#endif
+
+	/* --------------------------------------------------
+	 * Restore OS Lock bit
+	 * --------------------------------------------------
+	 */
+restore_oslock:
+	mov	x0, #1
+	msr	oslar_el1, x0
+
+	/* --------------------------------------------------
+	 * Get secure world's entry point and jump to it
+	 * --------------------------------------------------
+	 */
+	bl	plat_get_my_entrypoint
+	br	x0
+endfunc tegra_secure_entrypoint
+
+	.data
+	.align 3
+
+	/* --------------------------------------------------
+	 * CPU Secure entry point - resume from suspend
+	 * --------------------------------------------------
+	 */
+tegra_sec_entry_point:
+	.quad	0
+
+	/* --------------------------------------------------
+	 * NS world's cold boot entry point
+	 * --------------------------------------------------
+	 */
+ns_image_entrypoint:
+	.quad	0
+
+	/* --------------------------------------------------
+	 * BL31's physical base address
+	 * --------------------------------------------------
+	 */
+tegra_bl31_phys_base:
+	.quad	0
+
+	/* --------------------------------------------------
+	 * UART controller base for console init
+	 * --------------------------------------------------
+	 */
+tegra_console_base:
+	.quad	0
diff --git a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c
new file mode 100644
index 0000000..d7db604
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bpmp.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <stdbool.h>
+#include <string.h>
+#include <tegra_def.h>
+
+#define BPMP_TIMEOUT	500 /* 500ms */
+
+static uint32_t channel_base[NR_CHANNELS];
+static uint32_t bpmp_init_state = BPMP_INIT_PENDING;
+
+static uint32_t channel_field(unsigned int ch)
+{
+	return mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET) & CH_MASK(ch);
+}
+
+static bool master_free(unsigned int ch)
+{
+	return channel_field(ch) == MA_FREE(ch);
+}
+
+static bool master_acked(unsigned int ch)
+{
+	return channel_field(ch) == MA_ACKD(ch);
+}
+
+static void signal_slave(unsigned int ch)
+{
+	mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, CH_MASK(ch));
+}
+
+static void free_master(unsigned int ch)
+{
+	mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET,
+		      MA_ACKD(ch) ^ MA_FREE(ch));
+}
+
+/* should be called with local irqs disabled */
+int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,
+		void *ib_data, int ib_sz)
+{
+	unsigned int ch = (unsigned int)plat_my_core_pos();
+	mb_data_t *p = (mb_data_t *)(uintptr_t)channel_base[ch];
+	int32_t ret = -ETIMEDOUT, timeout = 0;
+
+	if (bpmp_init_state == BPMP_INIT_COMPLETE) {
+
+		/* loop until BPMP is free */
+		for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) {
+			if (master_free(ch) == true) {
+				break;
+			}
+
+			mdelay(1);
+		}
+
+		if (timeout != BPMP_TIMEOUT) {
+
+			/* generate the command struct */
+			p->code = mrq;
+			p->flags = DO_ACK;
+			(void)memcpy((void *)p->data, ob_data, (size_t)ob_sz);
+
+			/* signal command ready to the BPMP */
+			signal_slave(ch);
+			mmio_write_32(TEGRA_PRI_ICTLR_BASE + CPU_IEP_FIR_SET,
+				      (1U << INT_SHR_SEM_OUTBOX_FULL));
+
+			/* loop until the command is executed */
+			for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) {
+				if (master_acked(ch) == true) {
+					break;
+				}
+
+				mdelay(1);
+			}
+
+			if (timeout != BPMP_TIMEOUT) {
+
+				/* get the command response */
+				(void)memcpy(ib_data, (const void *)p->data,
+					     (size_t)ib_sz);
+
+				/* return error code */
+				ret = p->code;
+
+				/* free this channel */
+				free_master(ch);
+			}
+		}
+
+	} else {
+		/* return error code */
+		ret = -EINVAL;
+	}
+
+	if (timeout == BPMP_TIMEOUT) {
+		ERROR("Timed out waiting for bpmp's response\n");
+	}
+
+	return ret;
+}
+
+int tegra_bpmp_init(void)
+{
+	uint32_t val, base, timeout = BPMP_TIMEOUT;
+	unsigned int ch;
+	int ret = 0;
+
+	if (bpmp_init_state == BPMP_INIT_PENDING) {
+
+		/* check if the bpmp processor is alive. */
+		do {
+			val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
+			if (val != SIGN_OF_LIFE) {
+				mdelay(1);
+				timeout--;
+			}
+
+		} while ((val != SIGN_OF_LIFE) && (timeout > 0U));
+
+		if (val == SIGN_OF_LIFE) {
+
+			/* check if clock for the atomics block is enabled */
+			val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V);
+			if ((val & CAR_ENABLE_ATOMICS) == 0) {
+				ERROR("Clock to the atomics block is disabled\n");
+			}
+
+			/* check if the atomics block is out of reset */
+			val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V);
+			if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) {
+				ERROR("Reset to the atomics block is asserted\n");
+			}
+
+			/* base address to get the result from Atomics */
+			base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET;
+
+			/* channel area is setup by BPMP before signaling handshake */
+			for (ch = 0; ch < NR_CHANNELS; ch++) {
+
+				/* issue command to get the channel base address */
+				mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) |
+					      ATOMIC_CMD_GET);
+
+				/* get the base address for the channel */
+				channel_base[ch] = mmio_read_32(base);
+
+				/* increment result register offset */
+				base += 4U;
+			}
+
+			/* mark state as "initialized" */
+			bpmp_init_state = BPMP_INIT_COMPLETE;
+
+			/* the channel values have to be visible across all cpus */
+			flush_dcache_range((uint64_t)channel_base,
+					   sizeof(channel_base));
+			flush_dcache_range((uint64_t)&bpmp_init_state,
+					   sizeof(bpmp_init_state));
+
+			INFO("%s: done\n", __func__);
+
+		} else {
+			ERROR("BPMP not powered on\n");
+
+			/* bpmp is not present in the system */
+			bpmp_init_state = BPMP_NOT_PRESENT;
+
+			/* communication timed out */
+			ret = -ETIMEDOUT;
+		}
+	}
+
+	return ret;
+}
+
+void tegra_bpmp_suspend(void)
+{
+	/* freeze the interface */
+	if (bpmp_init_state == BPMP_INIT_COMPLETE) {
+		bpmp_init_state = BPMP_SUSPEND_ENTRY;
+		flush_dcache_range((uint64_t)&bpmp_init_state,
+				   sizeof(bpmp_init_state));
+	}
+}
+
+void tegra_bpmp_resume(void)
+{
+	uint32_t val, timeout = 0;
+
+	if (bpmp_init_state == BPMP_SUSPEND_ENTRY) {
+
+		/* check if the bpmp processor is alive. */
+		do {
+
+			val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
+			if (val != SIGN_OF_LIFE) {
+				mdelay(1);
+				timeout++;
+			}
+
+		} while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT));
+
+		if (val == SIGN_OF_LIFE) {
+
+			INFO("%s: BPMP took %d ms to resume\n", __func__, timeout);
+
+			/* mark state as "initialized" */
+			bpmp_init_state = BPMP_INIT_COMPLETE;
+
+			/* state has to be visible across all cpus */
+			flush_dcache_range((uint64_t)&bpmp_init_state,
+					   sizeof(bpmp_init_state));
+		} else {
+			ERROR("BPMP not powered on\n");
+		}
+	}
+}
diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c b/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c
new file mode 100644
index 0000000..68b450e
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bpmp_ipc.h>
+#include <debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <stdbool.h>
+#include <string.h>
+#include <tegra_def.h>
+
+#include "intf.h"
+#include "ivc.h"
+
+/**
+ * Holds IVC channel data
+ */
+struct ccplex_bpmp_channel_data {
+	/* Buffer for incoming data */
+	struct frame_data *ib;
+
+	/* Buffer for outgoing data */
+	struct frame_data *ob;
+};
+
+static struct ccplex_bpmp_channel_data s_channel;
+static struct ivc ivc_ccplex_bpmp_channel;
+
+/*
+ * Helper functions to access the HSP doorbell registers
+ */
+static inline uint32_t hsp_db_read(uint32_t reg)
+{
+	return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg));
+}
+
+static inline void hsp_db_write(uint32_t reg, uint32_t val)
+{
+	mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val);
+}
+
+/*******************************************************************************
+ *      IVC wrappers for CCPLEX <-> BPMP communication.
+ ******************************************************************************/
+
+static void tegra_bpmp_ring_bpmp_doorbell(void);
+
+/*
+ * Get the next frame where data can be written.
+ */
+static struct frame_data *tegra_bpmp_get_next_out_frame(void)
+{
+	struct frame_data *frame;
+	const struct ivc *ch = &ivc_ccplex_bpmp_channel;
+
+	frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch);
+	if (frame == NULL) {
+		ERROR("%s: Error in getting next frame, exiting\n", __func__);
+	} else {
+		s_channel.ob = frame;
+	}
+
+	return frame;
+}
+
+static void tegra_bpmp_signal_slave(void)
+{
+	(void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel);
+	tegra_bpmp_ring_bpmp_doorbell();
+}
+
+static int32_t tegra_bpmp_free_master(void)
+{
+	return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel);
+}
+
+static bool tegra_bpmp_slave_acked(void)
+{
+	struct frame_data *frame;
+	bool ret = true;
+
+	frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel);
+	if (frame == NULL) {
+		ret = false;
+	} else {
+		s_channel.ib = frame;
+	}
+
+	return ret;
+}
+
+static struct frame_data *tegra_bpmp_get_cur_in_frame(void)
+{
+	return s_channel.ib;
+}
+
+/*
+ * Enables BPMP to ring CCPlex doorbell
+ */
+static void tegra_bpmp_enable_ccplex_doorbell(void)
+{
+	uint32_t reg;
+
+	reg = hsp_db_read(HSP_DBELL_1_ENABLE);
+	reg |= HSP_MASTER_BPMP_BIT;
+	hsp_db_write(HSP_DBELL_1_ENABLE, reg);
+}
+
+/*
+ * CCPlex rings the BPMP doorbell
+ */
+static void tegra_bpmp_ring_bpmp_doorbell(void)
+{
+	/*
+	 * Any writes to this register has the same effect,
+	 * uses master ID of the write transaction and set
+	 * corresponding flag.
+	 */
+	hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT);
+}
+
+/*
+ * Returns true if CCPLex can ring BPMP doorbell, otherwise false.
+ * This also signals that BPMP is up and ready.
+ */
+static bool tegra_bpmp_can_ccplex_ring_doorbell(void)
+{
+	uint32_t reg;
+
+	/* check if ccplex can communicate with bpmp */
+	reg = hsp_db_read(HSP_DBELL_3_ENABLE);
+
+	return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U);
+}
+
+static int32_t tegra_bpmp_wait_for_slave_ack(void)
+{
+	uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
+
+	while (!tegra_bpmp_slave_acked() && (timeout != 0U)) {
+		udelay(1);
+		timeout--;
+	};
+
+	return ((timeout == 0U) ? -ETIMEDOUT : 0);
+}
+
+/*
+ * Notification from the ivc layer
+ */
+static void tegra_bpmp_ivc_notify(const struct ivc *ivc)
+{
+	(void)(ivc);
+
+	tegra_bpmp_ring_bpmp_doorbell();
+}
+
+/*
+ * Atomic send/receive API, which means it waits until slave acks
+ */
+static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out,
+			uint32_t size_out, void *p_in, uint32_t size_in)
+{
+	struct frame_data *frame = tegra_bpmp_get_next_out_frame();
+	const struct frame_data *f_in = NULL;
+	int32_t ret = 0;
+	void *p_fdata;
+
+	if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) ||
+	    (frame == NULL)) {
+		ERROR("%s: invalid parameters, exiting\n", __func__);
+		ret = -EINVAL;
+	}
+
+	if (ret == 0) {
+
+		/* prepare the command frame */
+		frame->mrq = mrq;
+		frame->flags = FLAG_DO_ACK;
+		p_fdata = frame->data;
+		(void)memcpy(p_fdata, p_out, (size_t)size_out);
+
+		/* signal the slave */
+		tegra_bpmp_signal_slave();
+
+		/* wait for slave to ack */
+		ret = tegra_bpmp_wait_for_slave_ack();
+		if (ret != 0) {
+			ERROR("failed waiting for the slave to ack\n");
+		}
+
+		/* retrieve the response frame */
+		if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL) &&
+		    (ret == 0)) {
+
+			f_in = tegra_bpmp_get_cur_in_frame();
+			if (f_in != NULL) {
+				ERROR("Failed to get next input frame!\n");
+			} else {
+				(void)memcpy(p_in, p_fdata, (size_t)size_in);
+			}
+		}
+
+		if (ret == 0) {
+			ret = tegra_bpmp_free_master();
+			if (ret != 0) {
+				ERROR("Failed to free master\n");
+			}
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Initializes the BPMP<--->CCPlex communication path.
+ */
+int32_t tegra_bpmp_ipc_init(void)
+{
+	size_t msg_size;
+	uint32_t frame_size, timeout;
+	int32_t error = 0;
+
+	/* allow bpmp to ring CCPLEX's doorbell */
+	tegra_bpmp_enable_ccplex_doorbell();
+
+	/* wait for BPMP to actually ring the doorbell */
+	timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
+	while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) {
+		udelay(1); /* bpmp turn-around time */
+		timeout--;
+	}
+
+	if (timeout == 0U) {
+		ERROR("%s: BPMP firmware is not ready\n", __func__);
+		return -ENOTSUP;
+	}
+
+	INFO("%s: BPMP handshake completed\n", __func__);
+
+	msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES);
+	frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size);
+	if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) {
+		ERROR("%s: carveout size is not sufficient\n", __func__);
+		return -EINVAL;
+	}
+
+	error = tegra_ivc_init(&ivc_ccplex_bpmp_channel,
+				(uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE,
+				(uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE,
+				1U, frame_size, tegra_bpmp_ivc_notify);
+	if (error != 0) {
+
+		ERROR("%s: IVC init failed (%d)\n", __func__, error);
+
+	} else {
+
+		/* reset channel */
+		tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel);
+
+		/* wait for notification from BPMP */
+		while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) {
+			/*
+			 * Interrupt BPMP with doorbell each time after
+			 * tegra_ivc_channel_notified() returns non zero
+			 * value.
+			 */
+			tegra_bpmp_ring_bpmp_doorbell();
+		}
+
+		INFO("%s: All communication channels initialized\n", __func__);
+	}
+
+	return error;
+}
+
+/* Handler to reset a hardware module */
+int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id)
+{
+	int32_t ret;
+	struct mrq_reset_request req = {
+		.cmd = (uint32_t)CMD_RESET_MODULE,
+		.reset_id = rst_id
+	};
+
+	/* only GPCDMA/XUSB_PADCTL resets are supported */
+	assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) ||
+	       (rst_id == TEGRA_RESET_ID_GPCDMA));
+
+	ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req,
+			(uint32_t)sizeof(req), NULL, 0);
+	if (ret != 0) {
+		ERROR("%s: failed for module %d with error %d\n", __func__,
+		      rst_id, ret);
+	}
+
+	return ret;
+}
+
+int tegra_bpmp_ipc_enable_clock(uint32_t clk_id)
+{
+	int ret;
+	struct mrq_clk_request req;
+
+	/* only SE clocks are supported */
+	if (clk_id != TEGRA_CLK_SE) {
+		return -ENOTSUP;
+	}
+
+	/* prepare the MRQ_CLK command */
+	req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id);
+
+	ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, sizeof(req),
+			NULL, 0);
+	if (ret != 0) {
+		ERROR("%s: failed for module %d with error %d\n", __func__,
+		      clk_id, ret);
+	}
+
+	return ret;
+}
+
+int tegra_bpmp_ipc_disable_clock(uint32_t clk_id)
+{
+	int ret;
+	struct mrq_clk_request req;
+
+	/* only SE clocks are supported */
+	if (clk_id != TEGRA_CLK_SE) {
+		return -ENOTSUP;
+	}
+
+	/* prepare the MRQ_CLK command */
+	req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id);
+
+	ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, sizeof(req),
+			NULL, 0);
+	if (ret != 0) {
+		ERROR("%s: failed for module %d with error %d\n", __func__,
+		      clk_id, ret);
+	}
+
+	return ret;
+}
diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h b/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h
new file mode 100644
index 0000000..7059c37
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef INTF_H
+#define INTF_H
+
+/**
+ * Flags used in IPC req
+ */
+#define FLAG_DO_ACK			(U(1) << 0)
+#define FLAG_RING_DOORBELL	(U(1) << 1)
+
+/* Bit 1 is designated for CCPlex in secure world */
+#define HSP_MASTER_CCPLEX_BIT	(U(1) << 1)
+/* Bit 19 is designated for BPMP in non-secure world */
+#define HSP_MASTER_BPMP_BIT		(U(1) << 19)
+/* Timeout to receive response from BPMP is 1 sec */
+#define TIMEOUT_RESPONSE_FROM_BPMP_US	U(1000000) /* in microseconds */
+
+/**
+ * IVC protocol defines and command/response frame
+ */
+
+/**
+ * IVC specific defines
+ */
+#define IVC_CMD_SZ_BYTES		U(128)
+#define IVC_DATA_SZ_BYTES		U(120)
+
+/**
+ * Holds frame data for an IPC request
+ */
+struct frame_data {
+	/* Identification as to what kind of data is being transmitted */
+	uint32_t mrq;
+
+	/* Flags for slave as to how to respond back */
+	uint32_t flags;
+
+	/* Actual data being sent */
+	uint8_t data[IVC_DATA_SZ_BYTES];
+};
+
+/**
+ * Commands send to the BPMP firmware
+ */
+
+/**
+ * MRQ command codes
+ */
+#define MRQ_RESET			U(20)
+#define MRQ_CLK				U(22)
+
+/**
+ * Reset sub-commands
+ */
+#define CMD_RESET_ASSERT		U(1)
+#define CMD_RESET_DEASSERT		U(2)
+#define CMD_RESET_MODULE		U(3)
+
+/**
+ * Used by the sender of an #MRQ_RESET message to request BPMP to
+ * assert or deassert a given reset line.
+ */
+struct __attribute__((packed)) mrq_reset_request {
+	/* reset action to perform (mrq_reset_commands) */
+	uint32_t cmd;
+	/* id of the reset to affected */
+	uint32_t reset_id;
+};
+
+/**
+ * MRQ_CLK sub-commands
+ *
+ */
+enum {
+	CMD_CLK_GET_RATE = 1,
+	CMD_CLK_SET_RATE = 2,
+	CMD_CLK_ROUND_RATE = 3,
+	CMD_CLK_GET_PARENT = 4,
+	CMD_CLK_SET_PARENT = 5,
+	CMD_CLK_IS_ENABLED = 6,
+	CMD_CLK_ENABLE = 7,
+	CMD_CLK_DISABLE = 8,
+	CMD_CLK_GET_ALL_INFO = 14,
+	CMD_CLK_GET_MAX_CLK_ID = 15,
+	CMD_CLK_MAX,
+};
+
+/**
+ * Used by the sender of an #MRQ_CLK message to control clocks. The
+ * clk_request is split into several sub-commands. Some sub-commands
+ * require no additional data. Others have a sub-command specific
+ * payload
+ *
+ * |sub-command                 |payload                |
+ * |----------------------------|-----------------------|
+ * |CMD_CLK_GET_RATE            |-                      |
+ * |CMD_CLK_SET_RATE            |clk_set_rate           |
+ * |CMD_CLK_ROUND_RATE          |clk_round_rate         |
+ * |CMD_CLK_GET_PARENT          |-                      |
+ * |CMD_CLK_SET_PARENT          |clk_set_parent         |
+ * |CMD_CLK_IS_ENABLED          |-                      |
+ * |CMD_CLK_ENABLE              |-                      |
+ * |CMD_CLK_DISABLE             |-                      |
+ * |CMD_CLK_GET_ALL_INFO        |-                      |
+ * |CMD_CLK_GET_MAX_CLK_ID      |-                      |
+ *
+ */
+struct mrq_clk_request {
+	/**
+	 * sub-command and clock id concatenated to 32-bit word.
+	 * - bits[31..24] is the sub-cmd.
+	 * - bits[23..0] is the clock id
+	 */
+	uint32_t cmd_and_id;
+};
+
+/**
+ * Macro to prepare the MRQ_CLK sub-command
+ */
+#define make_mrq_clk_cmd(cmd, id)	(((cmd) << 24) | (id & 0xFFFFFF))
+
+#endif /* INTF_H */
diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c b/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c
new file mode 100644
index 0000000..4212eca
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "ivc.h"
+
+/*
+ * IVC channel reset protocol.
+ *
+ * Each end uses its tx_channel.state to indicate its synchronization state.
+ */
+enum {
+	/*
+	 * This value is zero for backwards compatibility with services that
+	 * assume channels to be initially zeroed. Such channels are in an
+	 * initially valid state, but cannot be asynchronously reset, and must
+	 * maintain a valid state at all times.
+	 *
+	 * The transmitting end can enter the established state from the sync or
+	 * ack state when it observes the receiving endpoint in the ack or
+	 * established state, indicating that has cleared the counters in our
+	 * rx_channel.
+	 */
+	ivc_state_established = U(0),
+
+	/*
+	 * If an endpoint is observed in the sync state, the remote endpoint is
+	 * allowed to clear the counters it owns asynchronously with respect to
+	 * the current endpoint. Therefore, the current endpoint is no longer
+	 * allowed to communicate.
+	 */
+	ivc_state_sync = U(1),
+
+	/*
+	 * When the transmitting end observes the receiving end in the sync
+	 * state, it can clear the w_count and r_count and transition to the ack
+	 * state. If the remote endpoint observes us in the ack state, it can
+	 * return to the established state once it has cleared its counters.
+	 */
+	ivc_state_ack = U(2)
+};
+
+/*
+ * This structure is divided into two-cache aligned parts, the first is only
+ * written through the tx_channel pointer, while the second is only written
+ * through the rx_channel pointer. This delineates ownership of the cache lines,
+ * which is critical to performance and necessary in non-cache coherent
+ * implementations.
+ */
+struct ivc_channel_header {
+	struct {
+		/* fields owned by the transmitting end */
+		uint32_t w_count;
+		uint32_t state;
+		uint32_t w_rsvd[IVC_CHHDR_TX_FIELDS - 2];
+	};
+	struct {
+		/* fields owned by the receiving end */
+		uint32_t r_count;
+		uint32_t r_rsvd[IVC_CHHDR_RX_FIELDS - 1];
+	};
+};
+
+static inline bool ivc_channel_empty(const struct ivc *ivc,
+		volatile const struct ivc_channel_header *ch)
+{
+	/*
+	 * This function performs multiple checks on the same values with
+	 * security implications, so sample the counters' current values in
+	 * shared memory to ensure that these checks use the same values.
+	 */
+	uint32_t wr_count = ch->w_count;
+	uint32_t rd_count = ch->r_count;
+	bool ret = false;
+
+	(void)ivc;
+
+	/*
+	 * Perform an over-full check to prevent denial of service attacks where
+	 * a server could be easily fooled into believing that there's an
+	 * extremely large number of frames ready, since receivers are not
+	 * expected to check for full or over-full conditions.
+	 *
+	 * Although the channel isn't empty, this is an invalid case caused by
+	 * a potentially malicious peer, so returning empty is safer, because it
+	 * gives the impression that the channel has gone silent.
+	 */
+	if (((wr_count - rd_count) > ivc->nframes) || (wr_count == rd_count)) {
+		ret = true;
+	}
+
+	return ret;
+}
+
+static inline bool ivc_channel_full(const struct ivc *ivc,
+		volatile const struct ivc_channel_header *ch)
+{
+	uint32_t wr_count = ch->w_count;
+	uint32_t rd_count = ch->r_count;
+
+	(void)ivc;
+
+	/*
+	 * Invalid cases where the counters indicate that the queue is over
+	 * capacity also appear full.
+	 */
+	return ((wr_count - rd_count) >= ivc->nframes);
+}
+
+static inline uint32_t ivc_channel_avail_count(const struct ivc *ivc,
+		volatile const struct ivc_channel_header *ch)
+{
+	uint32_t wr_count = ch->w_count;
+	uint32_t rd_count = ch->r_count;
+
+	(void)ivc;
+
+	/*
+	 * This function isn't expected to be used in scenarios where an
+	 * over-full situation can lead to denial of service attacks. See the
+	 * comment in ivc_channel_empty() for an explanation about special
+	 * over-full considerations.
+	 */
+	return (wr_count - rd_count);
+}
+
+static inline void ivc_advance_tx(struct ivc *ivc)
+{
+	ivc->tx_channel->w_count++;
+
+	if (ivc->w_pos == (ivc->nframes - (uint32_t)1U)) {
+		ivc->w_pos = 0U;
+	} else {
+		ivc->w_pos++;
+	}
+}
+
+static inline void ivc_advance_rx(struct ivc *ivc)
+{
+	ivc->rx_channel->r_count++;
+
+	if (ivc->r_pos == (ivc->nframes - (uint32_t)1U)) {
+		ivc->r_pos = 0U;
+	} else {
+		ivc->r_pos++;
+	}
+}
+
+static inline int32_t ivc_check_read(const struct ivc *ivc)
+{
+	/*
+	 * tx_channel->state is set locally, so it is not synchronized with
+	 * state from the remote peer. The remote peer cannot reset its
+	 * transmit counters until we've acknowledged its synchronization
+	 * request, so no additional synchronization is required because an
+	 * asynchronous transition of rx_channel->state to ivc_state_ack is not
+	 * allowed.
+	 */
+	if (ivc->tx_channel->state != ivc_state_established) {
+		return -ECONNRESET;
+	}
+
+	/*
+	* Avoid unnecessary invalidations when performing repeated accesses to
+	* an IVC channel by checking the old queue pointers first.
+	* Synchronization is only necessary when these pointers indicate empty
+	* or full.
+	*/
+	if (!ivc_channel_empty(ivc, ivc->rx_channel)) {
+		return 0;
+	}
+
+	return ivc_channel_empty(ivc, ivc->rx_channel) ? -ENOMEM : 0;
+}
+
+static inline int32_t ivc_check_write(const struct ivc *ivc)
+{
+	if (ivc->tx_channel->state != ivc_state_established) {
+		return -ECONNRESET;
+	}
+
+	if (!ivc_channel_full(ivc, ivc->tx_channel)) {
+		return 0;
+	}
+
+	return ivc_channel_full(ivc, ivc->tx_channel) ? -ENOMEM : 0;
+}
+
+bool tegra_ivc_can_read(const struct ivc *ivc)
+{
+	return ivc_check_read(ivc) == 0;
+}
+
+bool tegra_ivc_can_write(const struct ivc *ivc)
+{
+	return ivc_check_write(ivc) == 0;
+}
+
+bool tegra_ivc_tx_empty(const struct ivc *ivc)
+{
+	return ivc_channel_empty(ivc, ivc->tx_channel);
+}
+
+static inline uintptr_t calc_frame_offset(uint32_t frame_index,
+	uint32_t frame_size, uint32_t frame_offset)
+{
+    return ((uintptr_t)frame_index * (uintptr_t)frame_size) +
+	    (uintptr_t)frame_offset;
+}
+
+static void *ivc_frame_pointer(const struct ivc *ivc,
+				volatile const struct ivc_channel_header *ch,
+				uint32_t frame)
+{
+	assert(frame < ivc->nframes);
+	return (void *)((uintptr_t)(&ch[1]) +
+		calc_frame_offset(frame, ivc->frame_size, 0));
+}
+
+int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read)
+{
+	const void *src;
+	int32_t result;
+
+	if (buf == NULL) {
+		return -EINVAL;
+	}
+
+	if (max_read > ivc->frame_size) {
+		return -E2BIG;
+	}
+
+	result = ivc_check_read(ivc);
+	if (result != 0) {
+		return result;
+	}
+
+	/*
+	 * Order observation of w_pos potentially indicating new data before
+	 * data read.
+	 */
+	dmbish();
+
+	src = ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos);
+
+	(void)memcpy(buf, src, max_read);
+
+	ivc_advance_rx(ivc);
+
+	/*
+	 * Ensure our write to r_pos occurs before our read from w_pos.
+	 */
+	dmbish();
+
+	/*
+	 * Notify only upon transition from full to non-full.
+	 * The available count can only asynchronously increase, so the
+	 * worst possible side-effect will be a spurious notification.
+	 */
+	if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) {
+		ivc->notify(ivc);
+	}
+
+	return (int32_t)max_read;
+}
+
+/* directly peek at the next frame rx'ed */
+void *tegra_ivc_read_get_next_frame(const struct ivc *ivc)
+{
+	if (ivc_check_read(ivc) != 0) {
+		return NULL;
+	}
+
+	/*
+	 * Order observation of w_pos potentially indicating new data before
+	 * data read.
+	 */
+	dmbld();
+
+	return ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos);
+}
+
+int32_t tegra_ivc_read_advance(struct ivc *ivc)
+{
+	/*
+	 * No read barriers or synchronization here: the caller is expected to
+	 * have already observed the channel non-empty. This check is just to
+	 * catch programming errors.
+	 */
+	int32_t result = ivc_check_read(ivc);
+	if (result != 0) {
+		return result;
+	}
+
+	ivc_advance_rx(ivc);
+
+	/*
+	 * Ensure our write to r_pos occurs before our read from w_pos.
+	 */
+	dmbish();
+
+	/*
+	 * Notify only upon transition from full to non-full.
+	 * The available count can only asynchronously increase, so the
+	 * worst possible side-effect will be a spurious notification.
+	 */
+	if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) {
+		ivc->notify(ivc);
+	}
+
+	return 0;
+}
+
+int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size)
+{
+	void *p;
+	int32_t result;
+
+	if ((buf == NULL) || (ivc == NULL)) {
+		return -EINVAL;
+	}
+
+	if (size > ivc->frame_size) {
+		return -E2BIG;
+	}
+
+	result = ivc_check_write(ivc);
+	if (result != 0) {
+		return result;
+	}
+
+	p = ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos);
+
+	(void)memset(p, 0, ivc->frame_size);
+	(void)memcpy(p, buf, size);
+
+	/*
+	 * Ensure that updated data is visible before the w_pos counter
+	 * indicates that it is ready.
+	 */
+	dmbst();
+
+	ivc_advance_tx(ivc);
+
+	/*
+	 * Ensure our write to w_pos occurs before our read from r_pos.
+	 */
+	dmbish();
+
+	/*
+	 * Notify only upon transition from empty to non-empty.
+	 * The available count can only asynchronously decrease, so the
+	 * worst possible side-effect will be a spurious notification.
+	 */
+	if (ivc_channel_avail_count(ivc, ivc->tx_channel) == 1U) {
+		ivc->notify(ivc);
+	}
+
+	return (int32_t)size;
+}
+
+/* directly poke at the next frame to be tx'ed */
+void *tegra_ivc_write_get_next_frame(const struct ivc *ivc)
+{
+	if (ivc_check_write(ivc) != 0) {
+		return NULL;
+	}
+
+	return ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos);
+}
+
+/* advance the tx buffer */
+int32_t tegra_ivc_write_advance(struct ivc *ivc)
+{
+	int32_t result = ivc_check_write(ivc);
+
+	if (result != 0) {
+		return result;
+	}
+
+	/*
+	 * Order any possible stores to the frame before update of w_pos.
+	 */
+	dmbst();
+
+	ivc_advance_tx(ivc);
+
+	/*
+	 * Ensure our write to w_pos occurs before our read from r_pos.
+	 */
+	dmbish();
+
+	/*
+	 * Notify only upon transition from empty to non-empty.
+	 * The available count can only asynchronously decrease, so the
+	 * worst possible side-effect will be a spurious notification.
+	 */
+	if (ivc_channel_avail_count(ivc, ivc->tx_channel) == (uint32_t)1U) {
+		ivc->notify(ivc);
+	}
+
+	return 0;
+}
+
+void tegra_ivc_channel_reset(const struct ivc *ivc)
+{
+	ivc->tx_channel->state = ivc_state_sync;
+	ivc->notify(ivc);
+}
+
+/*
+ * ===============================================================
+ *  IVC State Transition Table - see tegra_ivc_channel_notified()
+ * ===============================================================
+ *
+ *	local	remote	action
+ *	-----	------	-----------------------------------
+ *	SYNC	EST	<none>
+ *	SYNC	ACK	reset counters; move to EST; notify
+ *	SYNC	SYNC	reset counters; move to ACK; notify
+ *	ACK	EST	move to EST; notify
+ *	ACK	ACK	move to EST; notify
+ *	ACK	SYNC	reset counters; move to ACK; notify
+ *	EST	EST	<none>
+ *	EST	ACK	<none>
+ *	EST	SYNC	reset counters; move to ACK; notify
+ *
+ * ===============================================================
+ */
+int32_t tegra_ivc_channel_notified(struct ivc *ivc)
+{
+	uint32_t peer_state;
+
+	/* Copy the receiver's state out of shared memory. */
+	peer_state = ivc->rx_channel->state;
+
+	if (peer_state == (uint32_t)ivc_state_sync) {
+		/*
+		 * Order observation of ivc_state_sync before stores clearing
+		 * tx_channel.
+		 */
+		dmbld();
+
+		/*
+		 * Reset tx_channel counters. The remote end is in the SYNC
+		 * state and won't make progress until we change our state,
+		 * so the counters are not in use at this time.
+		 */
+		ivc->tx_channel->w_count = 0U;
+		ivc->rx_channel->r_count = 0U;
+
+		ivc->w_pos = 0U;
+		ivc->r_pos = 0U;
+
+		/*
+		 * Ensure that counters appear cleared before new state can be
+		 * observed.
+		 */
+		dmbst();
+
+		/*
+		 * Move to ACK state. We have just cleared our counters, so it
+		 * is now safe for the remote end to start using these values.
+		 */
+		ivc->tx_channel->state = ivc_state_ack;
+
+		/*
+		 * Notify remote end to observe state transition.
+		 */
+		ivc->notify(ivc);
+
+	} else if ((ivc->tx_channel->state == (uint32_t)ivc_state_sync) &&
+			(peer_state == (uint32_t)ivc_state_ack)) {
+		/*
+		 * Order observation of ivc_state_sync before stores clearing
+		 * tx_channel.
+		 */
+		dmbld();
+
+		/*
+		 * Reset tx_channel counters. The remote end is in the ACK
+		 * state and won't make progress until we change our state,
+		 * so the counters are not in use at this time.
+		 */
+		ivc->tx_channel->w_count = 0U;
+		ivc->rx_channel->r_count = 0U;
+
+		ivc->w_pos = 0U;
+		ivc->r_pos = 0U;
+
+		/*
+		 * Ensure that counters appear cleared before new state can be
+		 * observed.
+		 */
+		dmbst();
+
+		/*
+		 * Move to ESTABLISHED state. We know that the remote end has
+		 * already cleared its counters, so it is safe to start
+		 * writing/reading on this channel.
+		 */
+		ivc->tx_channel->state = ivc_state_established;
+
+		/*
+		 * Notify remote end to observe state transition.
+		 */
+		ivc->notify(ivc);
+
+	} else if (ivc->tx_channel->state == (uint32_t)ivc_state_ack) {
+		/*
+		 * At this point, we have observed the peer to be in either
+		 * the ACK or ESTABLISHED state. Next, order observation of
+		 * peer state before storing to tx_channel.
+		 */
+		dmbld();
+
+		/*
+		 * Move to ESTABLISHED state. We know that we have previously
+		 * cleared our counters, and we know that the remote end has
+		 * cleared its counters, so it is safe to start writing/reading
+		 * on this channel.
+		 */
+		ivc->tx_channel->state = ivc_state_established;
+
+		/*
+		 * Notify remote end to observe state transition.
+		 */
+		ivc->notify(ivc);
+
+	} else {
+		/*
+		 * There is no need to handle any further action. Either the
+		 * channel is already fully established, or we are waiting for
+		 * the remote end to catch up with our current state. Refer
+		 * to the diagram in "IVC State Transition Table" above.
+		 */
+	}
+
+	return ((ivc->tx_channel->state == (uint32_t)ivc_state_established) ? 0 : -EAGAIN);
+}
+
+size_t tegra_ivc_align(size_t size)
+{
+	return (size + (IVC_ALIGN - 1U)) & ~(IVC_ALIGN - 1U);
+}
+
+size_t tegra_ivc_total_queue_size(size_t queue_size)
+{
+	if ((queue_size & (IVC_ALIGN - 1U)) != 0U) {
+		ERROR("queue_size (%d) must be %d-byte aligned\n",
+				(int32_t)queue_size, IVC_ALIGN);
+		return 0;
+	}
+	return queue_size + sizeof(struct ivc_channel_header);
+}
+
+static int32_t check_ivc_params(uintptr_t queue_base1, uintptr_t queue_base2,
+		uint32_t nframes, uint32_t frame_size)
+{
+	assert((offsetof(struct ivc_channel_header, w_count)
+				& (IVC_ALIGN - 1U)) == 0U);
+	assert((offsetof(struct ivc_channel_header, r_count)
+				& (IVC_ALIGN - 1U)) == 0U);
+	assert((sizeof(struct ivc_channel_header) & (IVC_ALIGN - 1U)) == 0U);
+
+	if (((uint64_t)nframes * (uint64_t)frame_size) >= 0x100000000ULL) {
+		ERROR("nframes * frame_size overflows\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * The headers must at least be aligned enough for counters
+	 * to be accessed atomically.
+	 */
+	if ((queue_base1 & (IVC_ALIGN - 1U)) != 0U) {
+		ERROR("ivc channel start not aligned: %lx\n", queue_base1);
+		return -EINVAL;
+	}
+	if ((queue_base2 & (IVC_ALIGN - 1U)) != 0U) {
+		ERROR("ivc channel start not aligned: %lx\n", queue_base2);
+		return -EINVAL;
+	}
+
+	if ((frame_size & (IVC_ALIGN - 1U)) != 0U) {
+		ERROR("frame size not adequately aligned: %u\n",
+				frame_size);
+		return -EINVAL;
+	}
+
+	if (queue_base1 < queue_base2) {
+		if ((queue_base1 + ((uint64_t)frame_size * nframes)) > queue_base2) {
+			ERROR("queue regions overlap: %lx + %x, %x\n",
+					queue_base1, frame_size,
+					frame_size * nframes);
+			return -EINVAL;
+		}
+	} else {
+		if ((queue_base2 + ((uint64_t)frame_size * nframes)) > queue_base1) {
+			ERROR("queue regions overlap: %lx + %x, %x\n",
+					queue_base2, frame_size,
+					frame_size * nframes);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base,
+		uint32_t nframes, uint32_t frame_size,
+		ivc_notify_function notify)
+{
+	int32_t result;
+
+	/* sanity check input params */
+	if ((ivc == NULL) || (notify == NULL)) {
+		return -EINVAL;
+	}
+
+	result = check_ivc_params(rx_base, tx_base, nframes, frame_size);
+	if (result != 0) {
+		return result;
+	}
+
+	/*
+	 * All sizes that can be returned by communication functions should
+	 * fit in a 32-bit integer.
+	 */
+	if (frame_size > (1u << 31)) {
+		return -E2BIG;
+	}
+
+	ivc->rx_channel = (struct ivc_channel_header *)rx_base;
+	ivc->tx_channel = (struct ivc_channel_header *)tx_base;
+	ivc->notify = notify;
+	ivc->frame_size = frame_size;
+	ivc->nframes = nframes;
+	ivc->w_pos = 0U;
+	ivc->r_pos = 0U;
+
+	INFO("%s: done\n", __func__);
+
+	return 0;
+}
diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h b/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h
new file mode 100644
index 0000000..42e6a1f
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IVC_H
+#define IVC_H
+
+#include <lib/utils_def.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#define IVC_ALIGN		U(64)
+#define IVC_CHHDR_TX_FIELDS	U(16)
+#define IVC_CHHDR_RX_FIELDS	U(16)
+
+struct ivc;
+struct ivc_channel_header;
+
+/* callback handler for notify on receiving a response */
+typedef void (* ivc_notify_function)(const struct ivc *);
+
+struct ivc {
+	struct ivc_channel_header *rx_channel;
+	struct ivc_channel_header *tx_channel;
+	uint32_t w_pos;
+	uint32_t r_pos;
+	ivc_notify_function notify;
+	uint32_t nframes;
+	uint32_t frame_size;
+};
+
+int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base,
+		uint32_t nframes, uint32_t frame_size,
+		ivc_notify_function notify);
+size_t tegra_ivc_total_queue_size(size_t queue_size);
+size_t tegra_ivc_align(size_t size);
+int32_t tegra_ivc_channel_notified(struct ivc *ivc);
+void tegra_ivc_channel_reset(const struct ivc *ivc);
+int32_t tegra_ivc_write_advance(struct ivc *ivc);
+void *tegra_ivc_write_get_next_frame(const struct ivc *ivc);
+int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size);
+int32_t tegra_ivc_read_advance(struct ivc *ivc);
+void *tegra_ivc_read_get_next_frame(const struct ivc *ivc);
+int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read);
+bool tegra_ivc_tx_empty(const struct ivc *ivc);
+bool tegra_ivc_can_write(const struct ivc *ivc);
+bool tegra_ivc_can_read(const struct ivc *ivc);
+
+#endif /* IVC_H */
diff --git a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c
new file mode 100644
index 0000000..8f55554
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <cortex_a53.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <flowctrl.h>
+#include <lib/utils_def.h>
+#include <pmc.h>
+#include <tegra_def.h>
+
+#define CLK_RST_DEV_L_SET		0x300
+#define CLK_RST_DEV_L_CLR		0x304
+#define  CLK_BPMP_RST			(1 << 1)
+
+#define EVP_BPMP_RESET_VECTOR		0x200
+
+static const uint64_t flowctrl_offset_cpu_csr[4] = {
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16)
+};
+
+static const uint64_t flowctrl_offset_halt_cpu[4] = {
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16)
+};
+
+static const uint64_t flowctrl_offset_cc4_ctrl[4] = {
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8),
+	(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12)
+};
+
+static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val)
+{
+	mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val);
+	val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]);
+}
+
+static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val)
+{
+	mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val);
+	val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]);
+}
+
+static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val)
+{
+	mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val);
+	val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]);
+}
+
+static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
+{
+	uint32_t val;
+
+	val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ |
+	      FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ |
+	      FLOWCTRL_WAITEVENT;
+	tegra_fc_halt_cpu(cpu_id, val);
+
+	val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
+	      FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id);
+	tegra_fc_cpu_csr(cpu_id, val | csr);
+}
+
+/*******************************************************************************
+ * After this, no core can wake from C7 until the action is reverted.
+ * If a wake up event is asserted, the FC state machine will stall until
+ * the action is reverted.
+ ******************************************************************************/
+void tegra_fc_ccplex_pgexit_lock(void)
+{
+	unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
+	uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING;;
+	uint32_t icept_cpu_flags[] = {
+		INTERCEPT_EXIT_PG_CORE0,
+		INTERCEPT_EXIT_PG_CORE1,
+		INTERCEPT_EXIT_PG_CORE2,
+		INTERCEPT_EXIT_PG_CORE3
+	};
+
+	/* set the intercept flags */
+	for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) {
+
+		/* skip current CPU */
+		if (i == cpu)
+			continue;
+
+		/* enable power gate exit intercept locks */
+		flags |= icept_cpu_flags[i];
+	}
+
+	tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags);
+	(void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
+}
+
+/*******************************************************************************
+ * Revert the ccplex powergate exit locks
+ ******************************************************************************/
+void tegra_fc_ccplex_pgexit_unlock(void)
+{
+	/* clear lock bits, clear pending interrupts */
+	tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING);
+	(void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
+}
+
+/*******************************************************************************
+ * Powerdn the current CPU
+ ******************************************************************************/
+void tegra_fc_cpu_powerdn(uint32_t mpidr)
+{
+	int cpu = mpidr & MPIDR_CPU_MASK;
+
+	VERBOSE("CPU%d powering down...\n", cpu);
+	tegra_fc_prepare_suspend(cpu, 0);
+}
+
+/*******************************************************************************
+ * Suspend the current CPU cluster
+ ******************************************************************************/
+void tegra_fc_cluster_idle(uint32_t mpidr)
+{
+	int cpu = mpidr & MPIDR_CPU_MASK;
+	uint32_t val;
+
+	VERBOSE("Entering cluster idle state...\n");
+
+	tegra_fc_cc4_ctrl(cpu, 0);
+
+	/* hardware L2 flush is faster for A53 only */
+	tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
+		!!MPIDR_AFFLVL1_VAL(mpidr));
+
+	/* suspend the CPU cluster */
+	val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT;
+	tegra_fc_prepare_suspend(cpu, val);
+}
+
+/*******************************************************************************
+ * Power down the current CPU cluster
+ ******************************************************************************/
+void tegra_fc_cluster_powerdn(uint32_t mpidr)
+{
+	int cpu = mpidr & MPIDR_CPU_MASK;
+	uint32_t val;
+
+	VERBOSE("Entering cluster powerdn state...\n");
+
+	tegra_fc_cc4_ctrl(cpu, 0);
+
+	/* hardware L2 flush is faster for A53 only */
+	tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
+		read_midr() == CORTEX_A53_MIDR);
+
+	/* power down the CPU cluster */
+	val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
+	tegra_fc_prepare_suspend(cpu, val);
+}
+
+/*******************************************************************************
+ * Check if cluster idle or power down state is allowed from this CPU
+ ******************************************************************************/
+bool tegra_fc_is_ccx_allowed(void)
+{
+	unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
+	uint32_t val;
+	bool ccx_allowed = true;
+
+	for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) {
+
+		/* skip current CPU */
+		if (i == cpu)
+			continue;
+
+		/* check if all other CPUs are already halted */
+		val = mmio_read_32(flowctrl_offset_cpu_csr[i]);
+		if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) {
+			ccx_allowed = false;
+		}
+	}
+
+	return ccx_allowed;
+}
+
+/*******************************************************************************
+ * Suspend the entire SoC
+ ******************************************************************************/
+void tegra_fc_soc_powerdn(uint32_t mpidr)
+{
+	int cpu = mpidr & MPIDR_CPU_MASK;
+	uint32_t val;
+
+	VERBOSE("Entering SoC powerdn state...\n");
+
+	tegra_fc_cc4_ctrl(cpu, 0);
+
+	tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1);
+
+	val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
+	tegra_fc_prepare_suspend(cpu, val);
+
+	/* overwrite HALT register */
+	tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
+}
+
+/*******************************************************************************
+ * Power up the CPU
+ ******************************************************************************/
+void tegra_fc_cpu_on(int cpu)
+{
+	tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE);
+	tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK);
+}
+
+/*******************************************************************************
+ * Power down the CPU
+ ******************************************************************************/
+void tegra_fc_cpu_off(int cpu)
+{
+	uint32_t val;
+
+	/*
+	 * Flow controller powers down the CPU during wfi. The CPU would be
+	 * powered on when it receives any interrupt.
+	 */
+	val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
+		FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu);
+	tegra_fc_cpu_csr(cpu, val);
+	tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
+	tegra_fc_cc4_ctrl(cpu, 0);
+}
+
+/*******************************************************************************
+ * Inform the BPMP that we have completed the cluster power up
+ ******************************************************************************/
+void tegra_fc_lock_active_cluster(void)
+{
+	uint32_t val;
+
+	val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
+	val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK;
+	tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val);
+	val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
+}
+
+/*******************************************************************************
+ * Power ON BPMP processor
+ ******************************************************************************/
+void tegra_fc_bpmp_on(uint32_t entrypoint)
+{
+	/* halt BPMP */
+	tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
+
+	/* Assert BPMP reset */
+	mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
+
+	/* Set reset address (stored in PMC_SCRATCH39) */
+	mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint);
+	while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
+		; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
+
+	/* Wait for 2us before de-asserting the reset signal. */
+	udelay(2);
+
+	/* De-assert BPMP reset */
+	mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST);
+
+	/* Un-halt BPMP */
+	tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0);
+}
+
+/*******************************************************************************
+ * Power OFF BPMP processor
+ ******************************************************************************/
+void tegra_fc_bpmp_off(void)
+{
+	/* halt BPMP */
+	tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
+
+	/* Assert BPMP reset */
+	mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
+
+	/* Clear reset address */
+	mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0);
+	while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
+		; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
+}
+
+/*******************************************************************************
+ * Route legacy FIQ to the GICD
+ ******************************************************************************/
+void tegra_fc_enable_fiq_to_ccplex_routing(void)
+{
+	uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);
+
+	/* set the bit to pass FIQs to the GICD */
+	tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE);
+}
+
+/*******************************************************************************
+ * Disable routing legacy FIQ to the GICD
+ ******************************************************************************/
+void tegra_fc_disable_fiq_to_ccplex_routing(void)
+{
+	uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);
+
+	/* clear the bit to pass FIQs to the GICD */
+	tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE);
+}
diff --git a/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c b/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c
new file mode 100644
index 0000000..d68cdfd
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <gpcdma.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+#include <stdbool.h>
+#include <tegra_def.h>
+
+/* DMA channel registers */
+#define DMA_CH_CSR				U(0x0)
+#define DMA_CH_CSR_WEIGHT_SHIFT			U(10)
+#define DMA_CH_CSR_XFER_MODE_SHIFT		U(21)
+#define DMA_CH_CSR_DMA_MODE_MEM2MEM		U(4)
+#define DMA_CH_CSR_DMA_MODE_FIXEDPATTERN	U(6)
+#define DMA_CH_CSR_IRQ_MASK_ENABLE		(U(1) << 15)
+#define DMA_CH_CSR_RUN_ONCE			(U(1) << 27)
+#define DMA_CH_CSR_ENABLE			(U(1) << 31)
+
+#define DMA_CH_STAT				U(0x4)
+#define DMA_CH_STAT_BUSY			(U(1) << 31)
+
+#define DMA_CH_SRC_PTR				U(0xC)
+
+#define DMA_CH_DST_PTR				U(0x10)
+
+#define DMA_CH_HI_ADR_PTR			U(0x14)
+#define DMA_CH_HI_ADR_PTR_SRC_MASK		U(0xFF)
+#define DMA_CH_HI_ADR_PTR_DST_SHIFT		U(16)
+#define DMA_CH_HI_ADR_PTR_DST_MASK		U(0xFF)
+
+#define DMA_CH_MC_SEQ				U(0x18)
+#define DMA_CH_MC_SEQ_REQ_CNT_SHIFT		U(25)
+#define DMA_CH_MC_SEQ_REQ_CNT_VAL		U(0x10)
+#define DMA_CH_MC_SEQ_BURST_SHIFT		U(23)
+#define DMA_CH_MC_SEQ_BURST_16_WORDS		U(0x3)
+
+#define DMA_CH_WORD_COUNT			U(0x20)
+#define DMA_CH_FIXED_PATTERN			U(0x34)
+#define DMA_CH_TZ				U(0x38)
+#define DMA_CH_TZ_ACCESS_ENABLE			U(0)
+#define DMA_CH_TZ_ACCESS_DISABLE		U(3)
+
+#define MAX_TRANSFER_SIZE			(1U*1024U*1024U*1024U)	/* 1GB */
+#define GPCDMA_TIMEOUT_MS			U(100)
+#define GPCDMA_RESET_BIT			(U(1) << 1)
+
+static bool init_done;
+
+static void tegra_gpcdma_write32(uint32_t offset, uint32_t val)
+{
+	mmio_write_32(TEGRA_GPCDMA_BASE + offset, val);
+}
+
+static uint32_t tegra_gpcdma_read32(uint32_t offset)
+{
+	return mmio_read_32(TEGRA_GPCDMA_BASE + offset);
+}
+
+static void tegra_gpcdma_init(void)
+{
+	/* assert reset for DMA engine */
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_SET_REG_OFFSET,
+		      GPCDMA_RESET_BIT);
+
+	udelay(2);
+
+	/* de-assert reset for DMA engine */
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_CLR_REG_OFFSET,
+		      GPCDMA_RESET_BIT);
+}
+
+static void tegra_gpcdma_memcpy_priv(uint64_t dst_addr, uint64_t src_addr,
+				     uint32_t num_bytes, uint32_t mode)
+{
+	uint32_t val, timeout = 0;
+	int32_t ret = 0;
+
+	/* sanity check byte count */
+	if ((num_bytes > MAX_TRANSFER_SIZE) || ((num_bytes & 0x3U) != U(0))) {
+		ret = -EINVAL;
+	}
+
+	/* initialise GPCDMA block */
+	if (!init_done) {
+		tegra_gpcdma_init();
+		init_done = true;
+	}
+
+	/* make sure channel isn't busy */
+	val = tegra_gpcdma_read32(DMA_CH_STAT);
+	if ((val & DMA_CH_STAT_BUSY) == DMA_CH_STAT_BUSY) {
+		ERROR("DMA channel is busy\n");
+		ret = -EBUSY;
+	}
+
+	if (ret == 0) {
+
+		/* disable any DMA transfers */
+		tegra_gpcdma_write32(DMA_CH_CSR, 0);
+
+		/* enable DMA access to TZDRAM */
+		tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_ENABLE);
+
+		/* configure MC sequencer */
+		val = (DMA_CH_MC_SEQ_REQ_CNT_VAL << DMA_CH_MC_SEQ_REQ_CNT_SHIFT) |
+		      (DMA_CH_MC_SEQ_BURST_16_WORDS << DMA_CH_MC_SEQ_BURST_SHIFT);
+		tegra_gpcdma_write32(DMA_CH_MC_SEQ, val);
+
+		/* reset fixed pattern */
+		tegra_gpcdma_write32(DMA_CH_FIXED_PATTERN, 0);
+
+		/* populate src and dst address registers */
+		tegra_gpcdma_write32(DMA_CH_SRC_PTR, (uint32_t)src_addr);
+		tegra_gpcdma_write32(DMA_CH_DST_PTR, (uint32_t)dst_addr);
+
+		val = (uint32_t)((src_addr >> 32) & DMA_CH_HI_ADR_PTR_SRC_MASK);
+		val |= (uint32_t)(((dst_addr >> 32) & DMA_CH_HI_ADR_PTR_DST_MASK) <<
+			DMA_CH_HI_ADR_PTR_DST_SHIFT);
+		tegra_gpcdma_write32(DMA_CH_HI_ADR_PTR, val);
+
+		/* transfer size (in words) */
+		tegra_gpcdma_write32(DMA_CH_WORD_COUNT, ((num_bytes >> 2) - 1U));
+
+		/* populate value for CSR */
+		val = (mode << DMA_CH_CSR_XFER_MODE_SHIFT) |
+		      DMA_CH_CSR_RUN_ONCE | (U(1) << DMA_CH_CSR_WEIGHT_SHIFT) |
+		      DMA_CH_CSR_IRQ_MASK_ENABLE;
+		tegra_gpcdma_write32(DMA_CH_CSR, val);
+
+		/* enable transfer */
+		val = tegra_gpcdma_read32(DMA_CH_CSR);
+		val |= DMA_CH_CSR_ENABLE;
+		tegra_gpcdma_write32(DMA_CH_CSR, val);
+
+		/* wait till transfer completes */
+		do {
+
+			/* read the status */
+			val = tegra_gpcdma_read32(DMA_CH_STAT);
+			if ((val & DMA_CH_STAT_BUSY) != DMA_CH_STAT_BUSY) {
+				break;
+			}
+
+			mdelay(1);
+			timeout++;
+
+		} while (timeout < GPCDMA_TIMEOUT_MS);
+
+		/* flag timeout error */
+		if (timeout == GPCDMA_TIMEOUT_MS) {
+			ERROR("DMA transfer timed out\n");
+		}
+
+		dsbsy();
+
+		/* disable DMA access to TZDRAM */
+		tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_DISABLE);
+		isb();
+	}
+}
+
+/*******************************************************************************
+ * Memcpy using GPCDMA block (Mem2Mem copy)
+ ******************************************************************************/
+void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr,
+			 uint32_t num_bytes)
+{
+	tegra_gpcdma_memcpy_priv(dst_addr, src_addr, num_bytes,
+				 DMA_CH_CSR_DMA_MODE_MEM2MEM);
+}
+
+/*******************************************************************************
+ * Memset using GPCDMA block (Fixed pattern write)
+ ******************************************************************************/
+void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes)
+{
+	tegra_gpcdma_memcpy_priv(dst_addr, 0, num_bytes,
+				 DMA_CH_CSR_DMA_MODE_FIXEDPATTERN);
+}
diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c
new file mode 100644
index 0000000..92fa273
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <memctrl.h>
+#include <memctrl_v1.h>
+#include <tegra_def.h>
+
+/* Video Memory base and size (live values) */
+static uint64_t video_mem_base;
+static uint64_t video_mem_size;
+
+/*
+ * Init SMMU.
+ */
+void tegra_memctrl_setup(void)
+{
+	/*
+	 * Setup the Memory controller to allow only secure accesses to
+	 * the TZDRAM carveout
+	 */
+	INFO("Tegra Memory Controller (v1)\n");
+
+	/* allow translations for all MC engines */
+	tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_0_0,
+			(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
+	tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_1_0,
+			(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
+	tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_2_0,
+			(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
+	tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_3_0,
+			(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
+	tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_4_0,
+			(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
+
+	tegra_mc_write_32(MC_SMMU_ASID_SECURITY_0, MC_SMMU_ASID_SECURITY);
+
+	tegra_mc_write_32(MC_SMMU_TLB_CONFIG_0, MC_SMMU_TLB_CONFIG_0_RESET_VAL);
+	tegra_mc_write_32(MC_SMMU_PTC_CONFIG_0, MC_SMMU_PTC_CONFIG_0_RESET_VAL);
+
+	/* flush PTC and TLB */
+	tegra_mc_write_32(MC_SMMU_PTC_FLUSH_0, MC_SMMU_PTC_FLUSH_ALL);
+	(void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */
+	tegra_mc_write_32(MC_SMMU_TLB_FLUSH_0, MC_SMMU_TLB_FLUSH_ALL);
+
+	/* enable SMMU */
+	tegra_mc_write_32(MC_SMMU_CONFIG_0,
+			  MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE);
+	(void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */
+
+	/* video memory carveout */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
+			  (uint32_t)(video_mem_base >> 32));
+	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)video_mem_base);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size);
+}
+
+/*
+ * Restore Memory Controller settings after "System Suspend"
+ */
+void tegra_memctrl_restore_settings(void)
+{
+	tegra_memctrl_setup();
+}
+
+/*
+ * Secure the BL31 DRAM aperture.
+ *
+ * phys_base = physical base of TZDRAM aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	/*
+	 * Setup the Memory controller to allow only secure accesses to
+	 * the TZDRAM carveout
+	 */
+	INFO("Configuring TrustZone DRAM Memory Carveout\n");
+
+	tegra_mc_write_32(MC_SECURITY_CFG0_0, phys_base);
+	tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20);
+}
+
+/*
+ * Secure the BL31 TZRAM aperture.
+ *
+ * phys_base = physical base of TZRAM aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	/*
+	 * The v1 hardware controller does not have any registers
+	 * for setting up the on-chip TZRAM.
+	 */
+}
+
+static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
+				 unsigned long long non_overlap_area_size)
+{
+	int ret;
+
+	/*
+	 * Map the NS memory first, clean it and then unmap it.
+	 */
+	ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */
+				non_overlap_area_start, /* VA */
+				non_overlap_area_size, /* size */
+				MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */
+	assert(ret == 0);
+
+	zeromem((void *)non_overlap_area_start, non_overlap_area_size);
+	flush_dcache_range(non_overlap_area_start, non_overlap_area_size);
+
+	mmap_remove_dynamic_region(non_overlap_area_start,
+		non_overlap_area_size);
+}
+
+/*
+ * Program the Video Memory carveout region
+ *
+ * phys_base = physical base of aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	uintptr_t vmem_end_old = video_mem_base + (video_mem_size << 20);
+	uintptr_t vmem_end_new = phys_base + size_in_bytes;
+	unsigned long long non_overlap_area_size;
+
+	/*
+	 * Setup the Memory controller to restrict CPU accesses to the Video
+	 * Memory region
+	 */
+	INFO("Configuring Video Memory Carveout\n");
+
+	/*
+	 * Configure Memory Controller directly for the first time.
+	 */
+	if (video_mem_base == 0)
+		goto done;
+
+	/*
+	 * Clear the old regions now being exposed. The following cases
+	 * can occur -
+	 *
+	 * 1. clear whole old region (no overlap with new region)
+	 * 2. clear old sub-region below new base
+	 * 3. clear old sub-region above new end
+	 */
+	INFO("Cleaning previous Video Memory Carveout\n");
+
+	if (phys_base > vmem_end_old || video_mem_base > vmem_end_new) {
+		tegra_clear_videomem(video_mem_base, video_mem_size << 20);
+	} else {
+		if (video_mem_base < phys_base) {
+			non_overlap_area_size = phys_base - video_mem_base;
+			tegra_clear_videomem(video_mem_base, non_overlap_area_size);
+		}
+		if (vmem_end_old > vmem_end_new) {
+			non_overlap_area_size = vmem_end_old - vmem_end_new;
+			tegra_clear_videomem(vmem_end_new, non_overlap_area_size);
+		}
+	}
+
+done:
+	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(phys_base >> 32));
+	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
+
+	/* store new values */
+	video_mem_base = phys_base;
+	video_mem_size = size_in_bytes >> 20;
+}
+
+/*
+ * During boot, USB3 and flash media (SDMMC/SATA) devices need access to
+ * IRAM. Because these clients connect to the MC and do not have a direct
+ * path to the IRAM, the MC implements AHB redirection during boot to allow
+ * path to IRAM. In this mode, accesses to a programmed memory address aperture
+ * are directed to the AHB bus, allowing access to the IRAM. The AHB aperture
+ * is defined by the IRAM_BASE_LO and IRAM_BASE_HI registers, which are
+ * initialized to disable this aperture.
+ *
+ * Once bootup is complete, we must program IRAM base to 0xffffffff and
+ * IRAM top to 0x00000000, thus disabling access to IRAM. DRAM is then
+ * potentially accessible in this address range. These aperture registers
+ * also have an access_control/lock bit. After disabling the aperture, the
+ * access_control register should be programmed to lock the registers.
+ */
+void tegra_memctrl_disable_ahb_redirection(void)
+{
+	/* program the aperture registers */
+	tegra_mc_write_32(MC_IRAM_BASE_LO, 0xFFFFFFFF);
+	tegra_mc_write_32(MC_IRAM_TOP_LO, 0);
+	tegra_mc_write_32(MC_IRAM_BASE_TOP_HI, 0);
+
+	/* lock the aperture registers */
+	tegra_mc_write_32(MC_IRAM_REG_CTRL, MC_DISABLE_IRAM_CFG_WRITES);
+}
+
+void tegra_memctrl_clear_pending_interrupts(void)
+{
+	uint32_t mcerr;
+
+	/* check if there are any pending interrupts */
+	mcerr = mmio_read_32(TEGRA_MC_BASE + MC_INTSTATUS);
+
+	if (mcerr != (uint32_t)0U) { /* should not see error here */
+		WARN("MC_INTSTATUS = 0x%x (should be zero)\n", mcerr);
+		mmio_write_32((TEGRA_MC_BASE + MC_INTSTATUS),  mcerr);
+	}
+}
diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
new file mode 100644
index 0000000..a3ef5e1
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <mce.h>
+#include <memctrl.h>
+#include <memctrl_v2.h>
+#include <smmu.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+
+/* Video Memory base and size (live values) */
+static uint64_t video_mem_base;
+static uint64_t video_mem_size_mb;
+
+/*
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that will be overridden by a SoC.
+ */
+#pragma weak plat_memctrl_tzdram_setup
+
+void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes)
+{
+	; /* do nothing */
+}
+
+/*
+ * Init Memory controller during boot.
+ */
+void tegra_memctrl_setup(void)
+{
+	uint32_t val;
+	const uint32_t *mc_streamid_override_regs;
+	uint32_t num_streamid_override_regs;
+	const mc_streamid_security_cfg_t *mc_streamid_sec_cfgs;
+	uint32_t num_streamid_sec_cfgs;
+	const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings();
+	uint32_t i;
+
+	INFO("Tegra Memory Controller (v2)\n");
+
+	/* Program the SMMU pagesize */
+	tegra_smmu_init();
+
+	/* Get the settings from the platform */
+	assert(plat_mc_settings != NULL);
+	mc_streamid_override_regs = plat_mc_settings->streamid_override_cfg;
+	num_streamid_override_regs = plat_mc_settings->num_streamid_override_cfgs;
+	mc_streamid_sec_cfgs = plat_mc_settings->streamid_security_cfg;
+	num_streamid_sec_cfgs = plat_mc_settings->num_streamid_security_cfgs;
+
+	/* Program all the Stream ID overrides */
+	for (i = 0; i < num_streamid_override_regs; i++)
+		tegra_mc_streamid_write_32(mc_streamid_override_regs[i],
+			MC_STREAM_ID_MAX);
+
+	/* Program the security config settings for all Stream IDs */
+	for (i = 0; i < num_streamid_sec_cfgs; i++) {
+		val = mc_streamid_sec_cfgs[i].override_enable << 16 |
+		      mc_streamid_sec_cfgs[i].override_client_inputs << 8 |
+		      mc_streamid_sec_cfgs[i].override_client_ns_flag << 0;
+		tegra_mc_streamid_write_32(mc_streamid_sec_cfgs[i].offset, val);
+	}
+
+	/*
+	 * All requests at boot time, and certain requests during
+	 * normal run time, are physically addressed and must bypass
+	 * the SMMU. The client hub logic implements a hardware bypass
+	 * path around the Translation Buffer Units (TBU). During
+	 * boot-time, the SMMU_BYPASS_CTRL register (which defaults to
+	 * TBU_BYPASS mode) will be used to steer all requests around
+	 * the uninitialized TBUs. During normal operation, this register
+	 * is locked into TBU_BYPASS_SID config, which routes requests
+	 * with special StreamID 0x7f on the bypass path and all others
+	 * through the selected TBU. This is done to disable SMMU Bypass
+	 * mode, as it could be used to circumvent SMMU security checks.
+	 */
+	tegra_mc_write_32(MC_SMMU_BYPASS_CONFIG,
+			  MC_SMMU_BYPASS_CONFIG_SETTINGS);
+
+	/*
+	 * Re-configure MSS to allow ROC to deal with ordering of the
+	 * Memory Controller traffic. This is needed as the Memory Controller
+	 * boots with MSS having all control, but ROC provides a performance
+	 * boost as compared to MSS.
+	 */
+	if (plat_mc_settings->reconfig_mss_clients != NULL) {
+		plat_mc_settings->reconfig_mss_clients();
+	}
+
+	/* Program overrides for MC transactions */
+	if (plat_mc_settings->set_txn_overrides != NULL) {
+		plat_mc_settings->set_txn_overrides();
+	}
+}
+
+/*
+ * Restore Memory Controller settings after "System Suspend"
+ */
+void tegra_memctrl_restore_settings(void)
+{
+	const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings();
+
+	assert(plat_mc_settings != NULL);
+
+	/*
+	 * Re-configure MSS to allow ROC to deal with ordering of the
+	 * Memory Controller traffic. This is needed as the Memory Controller
+	 * resets during System Suspend with MSS having all control, but ROC
+	 * provides a performance boost as compared to MSS.
+	 */
+	if (plat_mc_settings->reconfig_mss_clients != NULL) {
+		plat_mc_settings->reconfig_mss_clients();
+	}
+
+	/* Program overrides for MC transactions */
+	if (plat_mc_settings->set_txn_overrides != NULL) {
+		plat_mc_settings->set_txn_overrides();
+	}
+
+	/* video memory carveout region */
+	if (video_mem_base != 0ULL) {
+		tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO,
+				  (uint32_t)video_mem_base);
+		tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
+				  (uint32_t)(video_mem_base >> 32));
+		tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size_mb);
+
+		/*
+		 * MCE propagates the VideoMem configuration values across the
+		 * CCPLEX.
+		 */
+		mce_update_gsc_videomem();
+	}
+}
+
+/*
+ * Secure the BL31 DRAM aperture.
+ *
+ * phys_base = physical base of TZDRAM aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	/*
+	 * Perform platform specific steps.
+	 */
+	plat_memctrl_tzdram_setup(phys_base, size_in_bytes);
+}
+
+/*
+ * Secure the BL31 TZRAM aperture.
+ *
+ * phys_base = physical base of TZRAM aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	uint32_t index;
+	uint32_t total_128kb_blocks = size_in_bytes >> 17;
+	uint32_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
+	uint32_t val;
+
+	INFO("Configuring TrustZone SRAM Memory Carveout\n");
+
+	/*
+	 * Reset the access configuration registers to restrict access
+	 * to the TZRAM aperture
+	 */
+	for (index = MC_TZRAM_CLIENT_ACCESS0_CFG0;
+	     index < ((uint32_t)MC_TZRAM_CARVEOUT_CFG + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
+	     index += 4U) {
+		tegra_mc_write_32(index, 0);
+	}
+
+	/*
+	 * Enable CPU access configuration registers to access the TZRAM aperture
+	 */
+	if (!tegra_chipid_is_t186()) {
+		val = tegra_mc_read_32(MC_TZRAM_CLIENT_ACCESS1_CFG0);
+		val |= TZRAM_ALLOW_MPCORER | TZRAM_ALLOW_MPCOREW;
+		tegra_mc_write_32(MC_TZRAM_CLIENT_ACCESS1_CFG0, val);
+	}
+
+	/*
+	 * Set the TZRAM base. TZRAM base must be 4k aligned, at least.
+	 */
+	assert((phys_base & (uint64_t)0xFFF) == 0U);
+	tegra_mc_write_32(MC_TZRAM_BASE_LO, (uint32_t)phys_base);
+	tegra_mc_write_32(MC_TZRAM_BASE_HI,
+		(uint32_t)(phys_base >> 32) & MC_GSC_BASE_HI_MASK);
+
+	/*
+	 * Set the TZRAM size
+	 *
+	 * total size = (number of 128KB blocks) + (number of remaining 4KB
+	 * blocks)
+	 *
+	 */
+	val = (residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
+	      total_128kb_blocks;
+	tegra_mc_write_32(MC_TZRAM_SIZE, val);
+
+	/*
+	 * Lock the configuration settings by disabling TZ-only lock
+	 * and locking the configuration against any future changes
+	 * at all.
+	 */
+	val = tegra_mc_read_32(MC_TZRAM_CARVEOUT_CFG);
+	val &= (uint32_t)~MC_GSC_ENABLE_TZ_LOCK_BIT;
+	val |= MC_GSC_LOCK_CFG_SETTINGS_BIT;
+	if (!tegra_chipid_is_t186()) {
+		val |= MC_GSC_ENABLE_CPU_SECURE_BIT;
+	}
+	tegra_mc_write_32(MC_TZRAM_CARVEOUT_CFG, val);
+
+	/*
+	 * MCE propagates the security configuration values across the
+	 * CCPLEX.
+	 */
+	mce_update_gsc_tzram();
+}
+
+static void tegra_lock_videomem_nonoverlap(uint64_t phys_base,
+					   uint64_t size_in_bytes)
+{
+	uint32_t index;
+	uint64_t total_128kb_blocks = size_in_bytes >> 17;
+	uint64_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
+	uint64_t val;
+
+	/*
+	 * Reset the access configuration registers to restrict access to
+	 * old Videomem aperture
+	 */
+	for (index = MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0;
+	     index < ((uint32_t)MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
+	     index += 4U) {
+		tegra_mc_write_32(index, 0);
+	}
+
+	/*
+	 * Set the base. It must be 4k aligned, at least.
+	 */
+	assert((phys_base & (uint64_t)0xFFF) == 0U);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, (uint32_t)phys_base);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI,
+		(uint32_t)(phys_base >> 32) & (uint32_t)MC_GSC_BASE_HI_MASK);
+
+	/*
+	 * Set the aperture size
+	 *
+	 * total size = (number of 128KB blocks) + (number of remaining 4KB
+	 * blocks)
+	 *
+	 */
+	val = (uint32_t)((residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
+			 total_128kb_blocks);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, (uint32_t)val);
+
+	/*
+	 * Lock the configuration settings by enabling TZ-only lock and
+	 * locking the configuration against any future changes from NS
+	 * world.
+	 */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_CFG,
+			  (uint32_t)MC_GSC_ENABLE_TZ_LOCK_BIT);
+
+	/*
+	 * MCE propagates the GSC configuration values across the
+	 * CCPLEX.
+	 */
+}
+
+static void tegra_unlock_videomem_nonoverlap(void)
+{
+	/* Clear the base */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, 0);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, 0);
+
+	/* Clear the size */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, 0);
+}
+
+static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
+				 unsigned long long non_overlap_area_size)
+{
+	int ret;
+
+	/*
+	 * Map the NS memory first, clean it and then unmap it.
+	 */
+	ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */
+				non_overlap_area_start, /* VA */
+				non_overlap_area_size, /* size */
+				MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */
+	assert(ret == 0);
+
+	zero_normalmem((void *)non_overlap_area_start, non_overlap_area_size);
+	flush_dcache_range(non_overlap_area_start, non_overlap_area_size);
+
+	(void)mmap_remove_dynamic_region(non_overlap_area_start,
+		non_overlap_area_size);
+}
+
+/*
+ * Program the Video Memory carveout region
+ *
+ * phys_base = physical base of aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	uintptr_t vmem_end_old = video_mem_base + (video_mem_size_mb << 20);
+	uintptr_t vmem_end_new = phys_base + size_in_bytes;
+	unsigned long long non_overlap_area_size;
+
+	/*
+	 * Setup the Memory controller to restrict CPU accesses to the Video
+	 * Memory region
+	 */
+	INFO("Configuring Video Memory Carveout\n");
+
+	/*
+	 * Configure Memory Controller directly for the first time.
+	 */
+	if (video_mem_base == 0U)
+		goto done;
+
+	/*
+	 * Lock the non overlapping memory being cleared so that other masters
+	 * do not accidently write to it. The memory would be unlocked once
+	 * the non overlapping region is cleared and the new memory
+	 * settings take effect.
+	 */
+	tegra_lock_videomem_nonoverlap(video_mem_base,
+				       video_mem_size_mb << 20);
+
+	/*
+	 * Clear the old regions now being exposed. The following cases
+	 * can occur -
+	 *
+	 * 1. clear whole old region (no overlap with new region)
+	 * 2. clear old sub-region below new base
+	 * 3. clear old sub-region above new end
+	 */
+	INFO("Cleaning previous Video Memory Carveout\n");
+
+	if ((phys_base > vmem_end_old) || (video_mem_base > vmem_end_new)) {
+		tegra_clear_videomem(video_mem_base,
+				     (uint32_t)video_mem_size_mb << 20U);
+	} else {
+		if (video_mem_base < phys_base) {
+			non_overlap_area_size = phys_base - video_mem_base;
+			tegra_clear_videomem(video_mem_base,
+					(uint32_t)non_overlap_area_size);
+		}
+		if (vmem_end_old > vmem_end_new) {
+			non_overlap_area_size = vmem_end_old - vmem_end_new;
+			tegra_clear_videomem(vmem_end_new,
+					(uint32_t)non_overlap_area_size);
+		}
+	}
+
+done:
+	/* program the Videomem aperture */
+	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base);
+	tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
+			  (uint32_t)(phys_base >> 32));
+	tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
+
+	/* unlock the previous locked nonoverlapping aperture */
+	tegra_unlock_videomem_nonoverlap();
+
+	/* store new values */
+	video_mem_base = phys_base;
+	video_mem_size_mb = size_in_bytes >> 20;
+
+	/*
+	 * MCE propagates the VideoMem configuration values across the
+	 * CCPLEX.
+	 */
+	mce_update_gsc_videomem();
+}
+
+/*
+ * This feature exists only for v1 of the Tegra Memory Controller.
+ */
+void tegra_memctrl_disable_ahb_redirection(void)
+{
+	; /* do nothing */
+}
+
+void tegra_memctrl_clear_pending_interrupts(void)
+{
+	; /* do nothing */
+}
diff --git a/plat/nvidia/tegra/common/drivers/pmc/pmc.c b/plat/nvidia/tegra/common/drivers/pmc/pmc.c
new file mode 100644
index 0000000..6c5a73b
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/pmc/pmc.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <pmc.h>
+#include <tegra_def.h>
+
+#define RESET_ENABLE	0x10U
+
+/* Module IDs used during power ungate procedure */
+static const uint32_t pmc_cpu_powergate_id[4] = {
+	14, /* CPU 0 */
+	9, /* CPU 1 */
+	10, /* CPU 2 */
+	11 /* CPU 3 */
+};
+
+/*******************************************************************************
+ * Power ungate CPU to start the boot process. CPU reset vectors must be
+ * populated before calling this function.
+ ******************************************************************************/
+void tegra_pmc_cpu_on(int32_t cpu)
+{
+	uint32_t val;
+
+	/*
+	 * Check if CPU is already power ungated
+	 */
+	val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
+	if ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U) {
+		/*
+		 * The PMC deasserts the START bit when it starts the power
+		 * ungate process. Loop till no power toggle is in progress.
+		 */
+		do {
+			val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE);
+		} while ((val & PMC_TOGGLE_START) != 0U);
+
+		/*
+		 * Start the power ungate procedure
+		 */
+		val = pmc_cpu_powergate_id[cpu] | PMC_TOGGLE_START;
+		tegra_pmc_write_32(PMC_PWRGATE_TOGGLE, val);
+
+		/*
+		 * The PMC deasserts the START bit when it starts the power
+		 * ungate process. Loop till powergate START bit is asserted.
+		 */
+		do {
+			val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE);
+		} while ((val & (1U << 8)) != 0U);
+
+		/* loop till the CPU is power ungated */
+		do {
+			val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
+		} while ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U);
+	}
+}
+
+/*******************************************************************************
+ * Setup CPU vectors for resume from deep sleep
+ ******************************************************************************/
+void tegra_pmc_cpu_setup(uint64_t reset_addr)
+{
+	uint32_t val;
+
+	tegra_pmc_write_32(PMC_SECURE_SCRATCH34,
+			   ((uint32_t)reset_addr & 0xFFFFFFFFU) | 1U);
+	val = (uint32_t)(reset_addr >> 32U);
+	tegra_pmc_write_32(PMC_SECURE_SCRATCH35, val & 0x7FFU);
+}
+
+/*******************************************************************************
+ * Lock CPU vectors to restrict further writes
+ ******************************************************************************/
+void tegra_pmc_lock_cpu_vectors(void)
+{
+	uint32_t val;
+
+	/* lock PMC_SECURE_SCRATCH22 */
+	val = tegra_pmc_read_32(PMC_SECURE_DISABLE2);
+	val |= PMC_SECURE_DISABLE2_WRITE22_ON;
+	tegra_pmc_write_32(PMC_SECURE_DISABLE2, val);
+
+	/* lock PMC_SECURE_SCRATCH34/35 */
+	val = tegra_pmc_read_32(PMC_SECURE_DISABLE3);
+	val |= (PMC_SECURE_DISABLE3_WRITE34_ON |
+		PMC_SECURE_DISABLE3_WRITE35_ON);
+	tegra_pmc_write_32(PMC_SECURE_DISABLE3, val);
+}
+
+/*******************************************************************************
+ * Find out if this is the last standing CPU
+ ******************************************************************************/
+bool tegra_pmc_is_last_on_cpu(void)
+{
+	int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
+	uint32_t val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);;
+	bool status = true;
+
+	/* check if this is the last standing CPU */
+	for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) {
+
+		/* skip the current CPU */
+		if (i == cpu)
+			continue;
+
+		/* are other CPUs already power gated? */
+		if ((val & ((uint32_t)1 << pmc_cpu_powergate_id[i])) != 0U) {
+			status = false;
+		}
+	}
+
+	return status;
+}
+
+/*******************************************************************************
+ * Handler to be called on exiting System suspend. Right now only DPD registers
+ * are cleared.
+ ******************************************************************************/
+void tegra_pmc_resume(void)
+{
+
+	/* Clear DPD sample */
+	mmio_write_32((TEGRA_PMC_BASE + PMC_IO_DPD_SAMPLE), 0x0);
+
+	/* Clear DPD Enable */
+	mmio_write_32((TEGRA_PMC_BASE + PMC_DPD_ENABLE_0), 0x0);
+}
+
+/*******************************************************************************
+ * Restart the system
+ ******************************************************************************/
+__dead2 void tegra_pmc_system_reset(void)
+{
+	uint32_t reg;
+
+	reg = tegra_pmc_read_32(PMC_CONFIG);
+	reg |= RESET_ENABLE;		/* restart */
+	tegra_pmc_write_32(PMC_CONFIG, reg);
+	wfi();
+
+	ERROR("Tegra System Reset: operation not handled.\n");
+	panic();
+}
diff --git a/plat/nvidia/tegra/common/drivers/smmu/smmu.c b/plat/nvidia/tegra/common/drivers/smmu/smmu.c
new file mode 100644
index 0000000..8c1b899
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/smmu/smmu.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+
+#include <smmu.h>
+#include <tegra_private.h>
+
+extern void memcpy16(void *dest, const void *src, unsigned int length);
+
+/* SMMU IDs currently supported by the driver */
+enum {
+	TEGRA_SMMU0 = 0U,
+	TEGRA_SMMU1,
+	TEGRA_SMMU2
+};
+
+static uint32_t tegra_smmu_read_32(uint32_t smmu_id, uint32_t off)
+{
+	uint32_t ret = 0U;
+
+#if defined(TEGRA_SMMU0_BASE)
+	if (smmu_id == TEGRA_SMMU0) {
+		ret = mmio_read_32(TEGRA_SMMU0_BASE + (uint64_t)off);
+	}
+#endif
+
+#if defined(TEGRA_SMMU1_BASE)
+	if (smmu_id == TEGRA_SMMU1) {
+		ret = mmio_read_32(TEGRA_SMMU1_BASE + (uint64_t)off);
+	}
+#endif
+
+#if defined(TEGRA_SMMU2_BASE)
+	if (smmu_id == TEGRA_SMMU2) {
+		ret = mmio_read_32(TEGRA_SMMU2_BASE + (uint64_t)off);
+	}
+#endif
+
+	return ret;
+}
+
+static void tegra_smmu_write_32(uint32_t smmu_id,
+			uint32_t off, uint32_t val)
+{
+#if defined(TEGRA_SMMU0_BASE)
+	if (smmu_id == TEGRA_SMMU0) {
+		mmio_write_32(TEGRA_SMMU0_BASE + (uint64_t)off, val);
+	}
+#endif
+
+#if defined(TEGRA_SMMU1_BASE)
+	if (smmu_id == TEGRA_SMMU1) {
+		mmio_write_32(TEGRA_SMMU1_BASE + (uint64_t)off, val);
+	}
+#endif
+
+#if defined(TEGRA_SMMU2_BASE)
+	if (smmu_id == TEGRA_SMMU2) {
+		mmio_write_32(TEGRA_SMMU2_BASE + (uint64_t)off, val);
+	}
+#endif
+}
+
+/*
+ * Save SMMU settings before "System Suspend" to TZDRAM
+ */
+void tegra_smmu_save_context(uint64_t smmu_ctx_addr)
+{
+	uint32_t i, num_entries = 0;
+	smmu_regs_t *smmu_ctx_regs;
+	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	uint64_t tzdram_base = params_from_bl2->tzdram_base;
+	uint64_t tzdram_end = tzdram_base + params_from_bl2->tzdram_size;
+	uint32_t reg_id1, pgshift, cb_size;
+
+	/* sanity check SMMU settings c*/
+	reg_id1 = mmio_read_32((TEGRA_SMMU0_BASE + SMMU_GNSR0_IDR1));
+	pgshift = ((reg_id1 & ID1_PAGESIZE) != 0U) ? 16U : 12U;
+	cb_size = ((uint32_t)2 << pgshift) * \
+	((uint32_t)1 << (((reg_id1 >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1U));
+
+	assert(!((pgshift != PGSHIFT) || (cb_size != CB_SIZE)));
+	assert((smmu_ctx_addr >= tzdram_base) && (smmu_ctx_addr <= tzdram_end));
+
+	/* get SMMU context table */
+	smmu_ctx_regs = plat_get_smmu_ctx();
+	assert(smmu_ctx_regs != NULL);
+
+	/*
+	 * smmu_ctx_regs[0].val contains the size of the context table minus
+	 * the last entry. Sanity check the table size before we start with
+	 * the context save operation.
+	 */
+	while ((smmu_ctx_regs[num_entries].reg != 0xFFFFFFFFU)) {
+		num_entries++;
+	}
+
+	/* panic if the sizes do not match */
+	if (num_entries != smmu_ctx_regs[0].val) {
+		ERROR("SMMU context size mismatch!");
+		panic();
+	}
+
+	/* save SMMU register values */
+	for (i = 1U; i < num_entries; i++) {
+		smmu_ctx_regs[i].val = mmio_read_32(smmu_ctx_regs[i].reg);
+	}
+
+	/* increment by 1 to take care of the last entry */
+	num_entries++;
+
+	/* Save SMMU config settings */
+	(void)memcpy16((uint8_t *)smmu_ctx_addr, (uint8_t *)smmu_ctx_regs,
+			(sizeof(smmu_regs_t) * num_entries));
+
+	/* save the SMMU table address */
+	mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SMMU_TABLE_ADDR_LO,
+		(uint32_t)smmu_ctx_addr);
+	mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SMMU_TABLE_ADDR_HI,
+		(uint32_t)(smmu_ctx_addr >> 32));
+}
+
+#define SMMU_NUM_CONTEXTS		64
+#define SMMU_CONTEXT_BANK_MAX_IDX	64
+
+/*
+ * Init SMMU during boot or "System Suspend" exit
+ */
+void tegra_smmu_init(void)
+{
+	uint32_t val, cb_idx, smmu_id, ctx_base;
+	uint32_t smmu_counter = plat_get_num_smmu_devices();
+
+	for (smmu_id = 0U; smmu_id < smmu_counter; smmu_id++) {
+		/* Program the SMMU pagesize and reset CACHE_LOCK bit */
+		val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
+		val |= SMMU_GSR0_PGSIZE_64K;
+		val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
+		tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val);
+
+		/* reset CACHE LOCK bit for NS Aux. Config. Register */
+		val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
+		val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
+		tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val);
+
+		/* disable TCU prefetch for all contexts */
+		ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS)
+				+ SMMU_CBn_ACTLR;
+		for (cb_idx = 0; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
+			val = tegra_smmu_read_32(smmu_id,
+				ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
+			val &= (uint32_t)~SMMU_CBn_ACTLR_CPRE_BIT;
+			tegra_smmu_write_32(smmu_id, ctx_base +
+				(SMMU_GSR0_PGSIZE_64K * cb_idx), val);
+		}
+
+		/* set CACHE LOCK bit for NS Aux. Config. Register */
+		val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
+		val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
+		tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val);
+
+		/* set CACHE LOCK bit for S Aux. Config. Register */
+		val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
+		val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
+		tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val);
+	}
+}
diff --git a/plat/nvidia/tegra/common/drivers/spe/shared_console.S b/plat/nvidia/tegra/common/drivers/spe/shared_console.S
new file mode 100644
index 0000000..c1fbc84
--- /dev/null
+++ b/plat/nvidia/tegra/common/drivers/spe/shared_console.S
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+
+#define CONSOLE_NUM_BYTES_SHIFT		24
+#define CONSOLE_FLUSH_DATA_TO_PORT	(1 << 26)
+#define CONSOLE_RING_DOORBELL		(1 << 31)
+#define CONSOLE_IS_BUSY			(1 << 31)
+#define CONSOLE_WRITE			(CONSOLE_RING_DOORBELL | CONSOLE_FLUSH_DATA_TO_PORT)
+
+	/*
+	 * This file contains a driver implementation to make use of the
+	 * real console implementation provided by the SPE firmware running
+	 * SoCs after Tegra186.
+	 *
+	 * This console is shared by multiple components and the SPE firmware
+	 * finally displays everything on the UART port.
+	 */
+
+	.globl	console_core_init
+	.globl	console_core_putc
+	.globl	console_core_getc
+	.globl	console_core_flush
+
+	/* -----------------------------------------------
+	 * int console_core_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. This
+	 * function will be accessed by console_init and
+	 * crash reporting.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * Out: return 1 on success else 0 on error
+	 * Clobber list : x1, x2
+	 * -----------------------------------------------
+	 */
+func console_core_init
+	/* Check the input base address */
+	cbz	x0, core_init_fail
+	mov	w0, #1
+	ret
+core_init_fail:
+	mov	w0, wzr
+	ret
+endfunc console_core_init
+
+	/* --------------------------------------------------------
+	 * int console_core_putc(int c, uintptr_t base_addr)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - console base address
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_core_putc
+	/* Check the input parameter */
+	cbz	x1, putc_error
+
+	/* Prepend '\r' to '\n' */
+	cmp	w0, #0xA
+	b.ne	2f
+
+	/* wait until spe is ready */
+1:	ldr	w2, [x1]
+	and	w2, w2, #CONSOLE_IS_BUSY
+	cbnz	w2, 1b
+
+	/* spe is ready */
+	mov	w2, #0xD		/* '\r' */
+	and	w2, w2, #0xFF
+	mov	w3, #(CONSOLE_WRITE | (1 << CONSOLE_NUM_BYTES_SHIFT))
+	orr	w2, w2, w3
+	str	w2, [x1]
+
+	/* wait until spe is ready */
+2:	ldr	w2, [x1]
+	and	w2, w2, #CONSOLE_IS_BUSY
+	cbnz	w2, 2b
+
+	/* spe is ready */
+	mov	w2, w0
+	and	w2, w2, #0xFF
+	mov	w3, #(CONSOLE_WRITE | (1 << CONSOLE_NUM_BYTES_SHIFT))
+	orr	w2, w2, w3
+	str	w2, [x1]
+
+	ret
+putc_error:
+	mov	w0, #-1
+	ret
+endfunc console_core_putc
+
+	/* ---------------------------------------------
+	 * int console_core_getc(uintptr_t base_addr)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on error.
+	 * In : x0 - console base address
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_core_getc
+	mov	w0, #-1
+	ret
+endfunc console_core_getc
+
+	/* ---------------------------------------------
+	 * int console_core_flush(uintptr_t base_addr)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - console base address
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_core_flush
+	cbz	x0, flush_error
+
+	/* flush console */
+	mov	w1, #CONSOLE_WRITE
+	str	w1, [x0]
+	mov	w0, #0
+	ret
+flush_error:
+	mov	w0, #-1
+	ret
+endfunc console_core_flush
diff --git a/plat/nvidia/tegra/common/lib/debug/profiler.c b/plat/nvidia/tegra/common/lib/debug/profiler.c
new file mode 100644
index 0000000..dd76a4e
--- /dev/null
+++ b/plat/nvidia/tegra/common/lib/debug/profiler.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*******************************************************************************
+ * The profiler stores the timestamps captured during cold boot to the shared
+ * memory for the non-secure world. The non-secure world driver parses the
+ * shared memory block and writes the contents to a file on the device, which
+ * can be later extracted for analysis.
+ *
+ * Profiler memory map
+ *
+ * TOP     ---------------------------      ---
+ *            Trusted OS timestamps         3KB
+ *         ---------------------------      ---
+ *         Trusted Firmware timestamps      1KB
+ * BASE    ---------------------------      ---
+ *
+ ******************************************************************************/
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <profiler.h>
+#include <stdbool.h>
+#include <string.h>
+
+static uint64_t shmem_base_addr;
+
+#define MAX_PROFILER_RECORDS	U(16)
+#define TAG_LEN_BYTES		U(56)
+
+/*******************************************************************************
+ * Profiler entry format
+ ******************************************************************************/
+typedef struct {
+	/* text explaining the timestamp location in code */
+	uint8_t tag[TAG_LEN_BYTES];
+	/* timestamp value */
+	uint64_t timestamp;
+} profiler_rec_t;
+
+static profiler_rec_t *head, *cur, *tail;
+static uint32_t tmr;
+static bool is_shmem_buf_mapped;
+
+/*******************************************************************************
+ * Initialise the profiling library
+ ******************************************************************************/
+void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
+{
+	uint64_t shmem_end_base;
+
+	assert(shmem_base != ULL(0));
+	assert(tmr_base != U(0));
+
+	/* store the buffer address */
+	shmem_base_addr = shmem_base;
+
+	/* calculate the base address of the last record */
+	shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
+			 (MAX_PROFILER_RECORDS - U(1)));
+
+	/* calculate the head, tail and cur values */
+	head = (profiler_rec_t *)shmem_base;
+	tail = (profiler_rec_t *)shmem_end_base;
+	cur = head;
+
+	/* timer used to get the current timestamp */
+	tmr = tmr_base;
+}
+
+/*******************************************************************************
+ * Add tag and timestamp to profiler
+ ******************************************************************************/
+void boot_profiler_add_record(const char *str)
+{
+	unsigned int len;
+
+	/* calculate the length of the tag */
+	if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
+		len = TAG_LEN_BYTES;
+	} else {
+		len = (unsigned int)strlen(str) + U(1);
+	}
+
+	if (head != NULL) {
+
+		/*
+		 * The profiler runs with/without MMU enabled. Check
+		 * if MMU is enabled and memmap the shmem buffer, in
+		 * case it is.
+		 */
+		if ((!is_shmem_buf_mapped) &&
+		    ((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
+
+			(void)mmap_add_dynamic_region(shmem_base_addr,
+					shmem_base_addr,
+					PROFILER_SIZE_BYTES,
+					(MT_NS | MT_RW | MT_EXECUTE_NEVER));
+
+			is_shmem_buf_mapped = true;
+		}
+
+		/* write the tag and timestamp to buffer */
+		(void)snprintf((char *)cur->tag, len, "%s", str);
+		cur->timestamp = mmio_read_32(tmr);
+
+		/* start from head if we reached the end */
+		if (cur == tail) {
+			cur = head;
+		} else {
+			cur++;
+		}
+	}
+}
+
+/*******************************************************************************
+ * Deinint the profiler
+ ******************************************************************************/
+void boot_profiler_deinit(void)
+{
+	if (shmem_base_addr != ULL(0)) {
+
+		/* clean up resources */
+		cur = NULL;
+		head = NULL;
+		tail = NULL;
+
+		/* flush the shmem for it to be visible to the NS world */
+		flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
+
+		/* unmap the shmem buffer */
+		if (is_shmem_buf_mapped) {
+			(void)mmap_remove_dynamic_region(shmem_base_addr,
+					PROFILER_SIZE_BYTES);
+		}
+	}
+}
diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c
new file mode 100644
index 0000000..a9d037f
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <cortex_a53.h>
+#include <cortex_a57.h>
+#include <denver.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+
+#include <memctrl.h>
+#include <profiler.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/* length of Trusty's input parameters (in bytes) */
+#define TRUSTY_PARAMS_LEN_BYTES	(4096*2)
+
+extern void memcpy16(void *dest, const void *src, unsigned int length);
+
+/*******************************************************************************
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted SRAM
+ ******************************************************************************/
+
+IMPORT_SYM(uint64_t, __RW_START__,	BL31_RW_START);
+IMPORT_SYM(uint64_t, __RW_END__,	BL31_RW_END);
+IMPORT_SYM(uint64_t, __RODATA_START__,	BL31_RODATA_BASE);
+IMPORT_SYM(uint64_t, __RODATA_END__,	BL31_RODATA_END);
+IMPORT_SYM(uint64_t, __TEXT_START__,	TEXT_START);
+IMPORT_SYM(uint64_t, __TEXT_END__,	TEXT_END);
+
+extern uint64_t tegra_bl31_phys_base;
+extern uint64_t tegra_console_base;
+
+static entry_point_info_t bl33_image_ep_info, bl32_image_ep_info;
+static plat_params_from_bl2_t plat_bl31_params_from_bl2 = {
+	.tzdram_size = TZDRAM_SIZE
+};
+static unsigned long bl32_mem_size;
+static unsigned long bl32_boot_params;
+
+/*******************************************************************************
+ * This variable holds the non-secure image entry address
+ ******************************************************************************/
+extern uint64_t ns_image_entrypoint;
+
+/*******************************************************************************
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that will be overridden by a SoC.
+ ******************************************************************************/
+#pragma weak plat_early_platform_setup
+#pragma weak plat_get_bl31_params
+#pragma weak plat_get_bl31_plat_params
+#pragma weak plat_late_platform_setup
+
+void plat_early_platform_setup(void)
+{
+	; /* do nothing */
+}
+
+struct tegra_bl31_params *plat_get_bl31_params(void)
+{
+	return NULL;
+}
+
+plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
+{
+	return NULL;
+}
+
+void plat_late_platform_setup(void)
+{
+	; /* do nothing */
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *ep =  NULL;
+
+	/* return BL32 entry point info if it is valid */
+	if (type == NON_SECURE) {
+		ep = &bl33_image_ep_info;
+	} else if ((type == SECURE) && (bl32_image_ep_info.pc != 0U)) {
+		ep = &bl32_image_ep_info;
+	}
+
+	return ep;
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'plat_params_from_bl2_t' structure. The BL2 image
+ * passes this platform specific information.
+ ******************************************************************************/
+plat_params_from_bl2_t *bl31_get_plat_params(void)
+{
+	return &plat_bl31_params_from_bl2;
+}
+
+/*******************************************************************************
+ * Perform any BL31 specific platform actions. Populate the BL33 and BL32 image
+ * info.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	struct tegra_bl31_params *arg_from_bl2 = (struct tegra_bl31_params *) arg0;
+	plat_params_from_bl2_t *plat_params = (plat_params_from_bl2_t *)arg1;
+	image_info_t bl32_img_info = { {0} };
+	uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
+	uint32_t console_clock;
+	int32_t ret;
+
+	/*
+	 * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
+	 * there's no argument to relay from a previous bootloader. Platforms
+	 * might use custom ways to get arguments, so provide handlers which
+	 * they can override.
+	 */
+	if (arg_from_bl2 == NULL) {
+		arg_from_bl2 = plat_get_bl31_params();
+	}
+	if (plat_params == NULL) {
+		plat_params = plat_get_bl31_plat_params();
+	}
+
+	/*
+	 * Copy BL3-3, BL3-2 entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	assert(arg_from_bl2 != NULL);
+	assert(arg_from_bl2->bl33_ep_info != NULL);
+	bl33_image_ep_info = *arg_from_bl2->bl33_ep_info;
+
+	if (arg_from_bl2->bl32_ep_info != NULL) {
+		bl32_image_ep_info = *arg_from_bl2->bl32_ep_info;
+		bl32_mem_size = arg_from_bl2->bl32_ep_info->args.arg0;
+		bl32_boot_params = arg_from_bl2->bl32_ep_info->args.arg2;
+	}
+
+	/*
+	 * Parse platform specific parameters
+	 */
+	assert(plat_params != NULL);
+	plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base;
+	plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size;
+	plat_bl31_params_from_bl2.uart_id = plat_params->uart_id;
+	plat_bl31_params_from_bl2.l2_ecc_parity_prot_dis = plat_params->l2_ecc_parity_prot_dis;
+	plat_bl31_params_from_bl2.sc7entry_fw_size = plat_params->sc7entry_fw_size;
+	plat_bl31_params_from_bl2.sc7entry_fw_base = plat_params->sc7entry_fw_base;
+
+	/*
+	 * It is very important that we run either from TZDRAM or TZSRAM base.
+	 * Add an explicit check here.
+	 */
+	if ((plat_bl31_params_from_bl2.tzdram_base != (uint64_t)BL31_BASE) &&
+	    (TEGRA_TZRAM_BASE != BL31_BASE)) {
+		panic();
+	}
+
+	/*
+	 * Reference clock used by the FPGAs is a lot slower.
+	 */
+	if (tegra_platform_is_fpga()) {
+		console_clock = TEGRA_BOOT_UART_CLK_13_MHZ;
+	} else {
+		console_clock = TEGRA_BOOT_UART_CLK_408_MHZ;
+	}
+
+	/*
+	 * Get the base address of the UART controller to be used for the
+	 * console
+	 */
+	tegra_console_base = plat_get_console_from_id(plat_params->uart_id);
+
+	if (tegra_console_base != 0U) {
+		/*
+		 * Configure the UART port to be used as the console
+		 */
+		(void)console_init(tegra_console_base, console_clock,
+			     TEGRA_CONSOLE_BAUDRATE);
+	}
+
+	/*
+	 * The previous bootloader passes the base address of the shared memory
+	 * location to store the boot profiler logs. Sanity check the
+	 * address and initialise the profiler library, if it looks ok.
+	 */
+	if (plat_params->boot_profiler_shmem_base != 0ULL) {
+
+		ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base,
+				PROFILER_SIZE_BYTES);
+		if (ret == (int32_t)0) {
+
+			/* store the membase for the profiler lib */
+			plat_bl31_params_from_bl2.boot_profiler_shmem_base =
+				plat_params->boot_profiler_shmem_base;
+
+			/* initialise the profiler library */
+			boot_profiler_init(plat_params->boot_profiler_shmem_base,
+					   TEGRA_TMRUS_BASE);
+		}
+	}
+
+	/*
+	 * Add timestamp for platform early setup entry.
+	 */
+	boot_profiler_add_record("[TF] early setup entry");
+
+	/*
+	 * Initialize delay timer
+	 */
+	tegra_delay_timer_init();
+
+	/* Early platform setup for Tegra SoCs */
+	plat_early_platform_setup();
+
+	/*
+	 * Do initial security configuration to allow DRAM/device access.
+	 */
+	tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base,
+			(uint32_t)plat_bl31_params_from_bl2.tzdram_size);
+
+	/*
+	 * The previous bootloader might not have placed the BL32 image
+	 * inside the TZDRAM. We check the BL32 image info to find out
+	 * the base/PC values and relocate the image if necessary.
+	 */
+	if (arg_from_bl2->bl32_image_info != NULL) {
+
+		bl32_img_info = *arg_from_bl2->bl32_image_info;
+
+		/* Relocate BL32 if it resides outside of the TZDRAM */
+		tzdram_start = plat_bl31_params_from_bl2.tzdram_base;
+		tzdram_end = plat_bl31_params_from_bl2.tzdram_base +
+				plat_bl31_params_from_bl2.tzdram_size;
+		bl32_start = bl32_img_info.image_base;
+		bl32_end = bl32_img_info.image_base + bl32_img_info.image_size;
+
+		assert(tzdram_end > tzdram_start);
+		assert(bl32_end > bl32_start);
+		assert(bl32_image_ep_info.pc > tzdram_start);
+		assert(bl32_image_ep_info.pc < tzdram_end);
+
+		/* relocate BL32 */
+		if ((bl32_start >= tzdram_end) || (bl32_end <= tzdram_start)) {
+
+			INFO("Relocate BL32 to TZDRAM\n");
+
+			(void)memcpy16((void *)(uintptr_t)bl32_image_ep_info.pc,
+				 (void *)(uintptr_t)bl32_start,
+				 bl32_img_info.image_size);
+
+			/* clean up non-secure intermediate buffer */
+			zeromem((void *)(uintptr_t)bl32_start,
+				bl32_img_info.image_size);
+		}
+	}
+
+	/*
+	 * Add timestamp for platform early setup exit.
+	 */
+	boot_profiler_add_record("[TF] early setup exit");
+
+	INFO("BL3-1: Boot CPU: %s Processor [%lx]\n",
+	     (((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK)
+	      == DENVER_IMPL) ? "Denver" : "ARM", read_mpidr());
+}
+
+#ifdef SPD_trusty
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+	args->arg0 = bl32_mem_size;
+	args->arg1 = bl32_boot_params;
+	args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
+
+	/* update EKS size */
+	if (args->arg4 != 0U) {
+		args->arg2 = args->arg4;
+	}
+
+	/* Profiler Carveout Base */
+	args->arg3 = args->arg5;
+}
+#endif
+
+/*******************************************************************************
+ * Initialize the gic, configure the SCR.
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+	/*
+	 * Add timestamp for platform setup entry.
+	 */
+	boot_profiler_add_record("[TF] plat setup entry");
+
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_gic_setup();
+
+	/*
+	 * Setup secondary CPU POR infrastructure.
+	 */
+	plat_secondary_setup();
+
+	/*
+	 * Initial Memory Controller configuration.
+	 */
+	tegra_memctrl_setup();
+
+	/*
+	 * Set up the TZRAM memory aperture to allow only secure world
+	 * access
+	 */
+	tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
+
+	/*
+	 * Late setup handler to allow platforms to performs additional
+	 * functionality.
+	 * This handler gets called with MMU enabled.
+	 */
+	plat_late_platform_setup();
+
+	/*
+	 * Add timestamp for platform setup exit.
+	 */
+	boot_profiler_add_record("[TF] plat setup exit");
+
+	INFO("BL3-1: Tegra platform setup complete\n");
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform runtime setup prior to BL3-1 cold boot exit
+ ******************************************************************************/
+void bl31_plat_runtime_setup(void)
+{
+	/*
+	 * During cold boot, it is observed that the arbitration
+	 * bit is set in the Memory controller leading to false
+	 * error interrupts in the non-secure world. To avoid
+	 * this, clean the interrupt status register before
+	 * booting into the non-secure world
+	 */
+	tegra_memctrl_clear_pending_interrupts();
+
+	/*
+	 * During boot, USB3 and flash media (SDMMC/SATA) devices need
+	 * access to IRAM. Because these clients connect to the MC and
+	 * do not have a direct path to the IRAM, the MC implements AHB
+	 * redirection during boot to allow path to IRAM. In this mode
+	 * accesses to a programmed memory address aperture are directed
+	 * to the AHB bus, allowing access to the IRAM. This mode must be
+	 * disabled before we jump to the non-secure world.
+	 */
+	tegra_memctrl_disable_ahb_redirection();
+
+	/*
+	 * Add final timestamp before exiting BL31.
+	 */
+	boot_profiler_add_record("[TF] bl31 exit");
+	boot_profiler_deinit();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	uint64_t rw_start = BL31_RW_START;
+	uint64_t rw_size = BL31_RW_END - BL31_RW_START;
+	uint64_t rodata_start = BL31_RODATA_BASE;
+	uint64_t rodata_size = BL31_RODATA_END - BL31_RODATA_BASE;
+	uint64_t code_base = TEXT_START;
+	uint64_t code_size = TEXT_END - TEXT_START;
+	const mmap_region_t *plat_mmio_map = NULL;
+#if USE_COHERENT_MEM
+	uint32_t coh_start, coh_size;
+#endif
+	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+
+	/*
+	 * Add timestamp for arch setup entry.
+	 */
+	boot_profiler_add_record("[TF] arch setup entry");
+
+	/* add MMIO space */
+	plat_mmio_map = plat_get_mmio_map();
+	if (plat_mmio_map != NULL) {
+		mmap_add(plat_mmio_map);
+	} else {
+		WARN("MMIO map not available\n");
+	}
+
+	/* add memory regions */
+	mmap_add_region(rw_start, rw_start,
+			rw_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(rodata_start, rodata_start,
+			rodata_size,
+			MT_RO_DATA | MT_SECURE);
+	mmap_add_region(code_base, code_base,
+			code_size,
+			MT_CODE | MT_SECURE);
+
+#if USE_COHERENT_MEM
+	coh_start = total_base + (BL_COHERENT_RAM_BASE - BL31_RO_BASE);
+	coh_size = BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE;
+
+	mmap_add_region(coh_start, coh_start,
+			coh_size,
+			(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE);
+#endif
+
+	/* map TZDRAM used by BL31 as coherent memory */
+	if (TEGRA_TZRAM_BASE == tegra_bl31_phys_base) {
+		mmap_add_region(params_from_bl2->tzdram_base,
+				params_from_bl2->tzdram_base,
+				BL31_SIZE,
+				MT_DEVICE | MT_RW | MT_SECURE);
+	}
+
+	/* set up translation tables */
+	init_xlat_tables();
+
+	/* enable the MMU */
+	enable_mmu_el3(0);
+
+	/*
+	 * Add timestamp for arch setup exit.
+	 */
+	boot_profiler_add_record("[TF] arch setup exit");
+
+	INFO("BL3-1: Tegra: MMU enabled\n");
+}
+
+/*******************************************************************************
+ * Check if the given NS DRAM range is valid
+ ******************************************************************************/
+int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes)
+{
+	uint64_t end = base + size_in_bytes - U(1);
+	int32_t ret = 0;
+
+	/*
+	 * Check if the NS DRAM address is valid
+	 */
+	if ((base < TEGRA_DRAM_BASE) || (base >= TEGRA_DRAM_END) ||
+	    (end > TEGRA_DRAM_END)) {
+
+		ERROR("NS address 0x%llx is out-of-bounds!\n", base);
+		ret = -EFAULT;
+	}
+
+	/*
+	 * TZDRAM aperture contains the BL31 and BL32 images, so we need
+	 * to check if the NS DRAM range overlaps the TZDRAM aperture.
+	 */
+	if ((base < (uint64_t)TZDRAM_END) && (end > tegra_bl31_phys_base)) {
+		ERROR("NS address 0x%llx overlaps TZDRAM!\n", base);
+		ret = -ENOTSUP;
+	}
+
+	/* valid NS address */
+	return ret;
+}
diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk
new file mode 100644
index 0000000..2a2f278
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_common.mk
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_INCLUDES		:=	-Iplat/nvidia/tegra/include/drivers \
+				-Iplat/nvidia/tegra/include/lib \
+				-Iplat/nvidia/tegra/include \
+				-Iplat/nvidia/tegra/include/${TARGET_SOC}
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}
+
+COMMON_DIR		:=	plat/nvidia/tegra/common
+
+TEGRA_GICv2_SOURCES	:=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				${COMMON_DIR}/tegra_gicv2.c
+
+BL31_SOURCES		+=	drivers/console/aarch64/console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/io/io_storage.c				\
+				${TEGRA_GICv2_SOURCES}				\
+				${COMMON_DIR}/aarch64/tegra_helpers.S		\
+				${COMMON_DIR}/drivers/pmc/pmc.c			\
+				${COMMON_DIR}/lib/debug/profiler.c		\
+				${COMMON_DIR}/tegra_bl31_setup.c		\
+				${COMMON_DIR}/tegra_delay_timer.c		\
+				${COMMON_DIR}/tegra_fiq_glue.c			\
+				${COMMON_DIR}/tegra_io_storage.c		\
+				${COMMON_DIR}/tegra_platform.c			\
+				${COMMON_DIR}/tegra_pm.c			\
+				${COMMON_DIR}/tegra_sip_calls.c			\
+				${COMMON_DIR}/tegra_topology.c
diff --git a/plat/nvidia/tegra/common/tegra_delay_timer.c b/plat/nvidia/tegra/common/tegra_delay_timer.c
new file mode 100644
index 0000000..63dcf41
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_delay_timer.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+static uint32_t tegra_timerus_get_value(void)
+{
+	return mmio_read_32(TEGRA_TMRUS_BASE);
+}
+
+/*
+ * Initialise the on-chip free rolling us counter as the delay
+ * timer.
+ */
+void tegra_delay_timer_init(void)
+{
+	static const timer_ops_t tegra_timer_ops = {
+		.get_timer_value	= tegra_timerus_get_value,
+		.clk_mult		= 1,
+		.clk_div		= 1,
+	};
+
+	timer_init(&tegra_timer_ops);
+}
diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c
new file mode 100644
index 0000000..60b5595
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <denver.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#if ENABLE_WDT_LEGACY_FIQ_HANDLING
+#include <flowctrl.h>
+#endif
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+/* Legacy FIQ used by earlier Tegra platforms */
+#define LEGACY_FIQ_PPI_WDT		28U
+
+static DEFINE_BAKERY_LOCK(tegra_fiq_lock);
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static uint64_t ns_fiq_handler_addr;
+static uint32_t fiq_handler_active;
+static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * Handler for FIQ interrupts
+ ******************************************************************************/
+static uint64_t tegra_fiq_interrupt_handler(uint32_t id,
+					  uint32_t flags,
+					  void *handle,
+					  void *cookie)
+{
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	el3_state_t *el3state_ctx = get_el3state_ctx(ctx);
+	uint32_t cpu = plat_my_core_pos();
+	uint32_t irq;
+
+	(void)id;
+	(void)flags;
+	(void)handle;
+	(void)cookie;
+
+	/*
+	 * Read the pending interrupt ID
+	 */
+	irq = plat_ic_get_pending_interrupt_id();
+
+	bakery_lock_get(&tegra_fiq_lock);
+
+	/*
+	 * Jump to NS world only if the NS world's FIQ handler has
+	 * been registered
+	 */
+	if (ns_fiq_handler_addr != 0U) {
+
+		/*
+		 * The FIQ was generated when the execution was in the non-secure
+		 * world. Save the context registers to start with.
+		 */
+		cm_el1_sysregs_context_save(NON_SECURE);
+
+		/*
+		 * Save elr_el3 and spsr_el3 from the saved context, and overwrite
+		 * the context with the NS fiq_handler_addr and SPSR value.
+		 */
+		fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3));
+		fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3));
+
+		/*
+		 * Set the new ELR to continue execution in the NS world using the
+		 * FIQ handler registered earlier.
+		 */
+		cm_set_elr_el3(NON_SECURE, ns_fiq_handler_addr);
+	}
+
+#if ENABLE_WDT_LEGACY_FIQ_HANDLING
+	/*
+	 * Tegra platforms that use LEGACY_FIQ as the watchdog timer FIQ
+	 * need to issue an IPI to other CPUs, to allow them to handle
+	 * the "system hung" scenario. This interrupt is passed to the GICD
+	 * via the Flow Controller. So, once we receive this interrupt,
+	 * disable the routing so that we can mark it as "complete" in the
+	 * GIC later.
+	 */
+	if (irq == LEGACY_FIQ_PPI_WDT) {
+		tegra_fc_disable_fiq_to_ccplex_routing();
+	}
+#endif
+
+	/*
+	 * Mark this interrupt as complete to avoid a FIQ storm.
+	 */
+	if (irq < 1022U) {
+		(void)plat_ic_acknowledge_interrupt();
+		plat_ic_end_of_interrupt(irq);
+	}
+
+	bakery_lock_release(&tegra_fiq_lock);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Setup handler for FIQ interrupts
+ ******************************************************************************/
+void tegra_fiq_handler_setup(void)
+{
+	uint32_t flags;
+	int32_t rc;
+
+	/* return if already registered */
+	if (fiq_handler_active == 0U) {
+		/*
+		 * Register an interrupt handler for FIQ interrupts generated for
+		 * NS interrupt sources
+		 */
+		flags = 0U;
+		set_interrupt_rm_flag((flags), (NON_SECURE));
+		rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+					tegra_fiq_interrupt_handler,
+					flags);
+		if (rc != 0) {
+			panic();
+		}
+
+		/* handler is now active */
+		fiq_handler_active = 1;
+	}
+}
+
+/*******************************************************************************
+ * Validate and store NS world's entrypoint for FIQ interrupts
+ ******************************************************************************/
+void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint)
+{
+	ns_fiq_handler_addr = entrypoint;
+}
+
+/*******************************************************************************
+ * Handler to return the NS EL1/EL0 CPU context
+ ******************************************************************************/
+int32_t tegra_fiq_get_intr_context(void)
+{
+	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);
+	uint32_t cpu = plat_my_core_pos();
+	uint64_t val;
+
+	/*
+	 * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so
+	 * that el3_exit() sends these values back to the NS world.
+	 */
+	write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3));
+	write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3));
+
+	val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0));
+	write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val));
+
+	val = read_ctx_reg((el1state_ctx), (uint32_t)(CTX_SP_EL1));
+	write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val));
+
+	return 0;
+}
diff --git a/plat/nvidia/tegra/common/tegra_gicv2.c b/plat/nvidia/tegra/common/tegra_gicv2.c
new file mode 100644
index 0000000..293df8d
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_gicv2.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/utils.h>
+
+#include <tegra_private.h>
+#include <tegra_def.h>
+
+/******************************************************************************
+ * Tegra common helper to setup the GICv2 driver data.
+ *****************************************************************************/
+void tegra_gic_setup(const interrupt_prop_t *interrupt_props,
+		     unsigned int interrupt_props_num)
+{
+	/*
+	 * Tegra GIC configuration settings
+	 */
+	static gicv2_driver_data_t tegra_gic_data;
+
+	/*
+	 * Register Tegra GICv2 driver
+	 */
+	tegra_gic_data.gicd_base = TEGRA_GICD_BASE;
+	tegra_gic_data.gicc_base = TEGRA_GICC_BASE;
+	tegra_gic_data.interrupt_props = interrupt_props;
+	tegra_gic_data.interrupt_props_num = interrupt_props_num;
+	gicv2_driver_init(&tegra_gic_data);
+}
+
+/******************************************************************************
+ * Tegra common helper to initialize the GICv2 only driver.
+ *****************************************************************************/
+void tegra_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * Tegra common helper to disable the GICv2 CPU interface
+ *****************************************************************************/
+void tegra_gic_cpuif_deactivate(void)
+{
+	gicv2_cpuif_disable();
+}
+
+/******************************************************************************
+ * Tegra common helper to initialize the per cpu distributor interface
+ * in GICv2
+ *****************************************************************************/
+void tegra_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
diff --git a/plat/nvidia/tegra/common/tegra_io_storage.c b/plat/nvidia/tegra/common/tegra_io_storage.c
new file mode 100644
index 0000000..21641aa
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_io_storage.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <plat/common/platform.h>
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy.
+ *
+ * This function is not supported at this time
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	return -ENOTSUP;
+}
diff --git a/plat/nvidia/tegra/common/tegra_platform.c b/plat/nvidia/tegra/common/tegra_platform.c
new file mode 100644
index 0000000..c1e4209
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_platform.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * Tegra platforms
+ ******************************************************************************/
+typedef enum tegra_platform {
+	TEGRA_PLATFORM_SILICON = 0U,
+	TEGRA_PLATFORM_QT,
+	TEGRA_PLATFORM_FPGA,
+	TEGRA_PLATFORM_EMULATION,
+	TEGRA_PLATFORM_LINSIM,
+	TEGRA_PLATFORM_UNIT_FPGA,
+	TEGRA_PLATFORM_VIRT_DEV_KIT,
+	TEGRA_PLATFORM_MAX,
+} tegra_platform_t;
+
+/*******************************************************************************
+ * Tegra macros defining all the SoC minor versions
+ ******************************************************************************/
+#define TEGRA_MINOR_QT			U(0)
+#define TEGRA_MINOR_FPGA		U(1)
+#define TEGRA_MINOR_ASIM_QT		U(2)
+#define TEGRA_MINOR_ASIM_LINSIM		U(3)
+#define TEGRA_MINOR_DSIM_ASIM_LINSIM	U(4)
+#define TEGRA_MINOR_UNIT_FPGA		U(5)
+#define TEGRA_MINOR_VIRT_DEV_KIT	U(6)
+
+/*******************************************************************************
+ * Tegra macros defining all the SoC pre_si_platform
+ ******************************************************************************/
+#define TEGRA_PRE_SI_QT			U(1)
+#define TEGRA_PRE_SI_FPGA		U(2)
+#define TEGRA_PRE_SI_UNIT_FPGA		U(3)
+#define TEGRA_PRE_SI_ASIM_QT		U(4)
+#define TEGRA_PRE_SI_ASIM_LINSIM	U(5)
+#define TEGRA_PRE_SI_DSIM_ASIM_LINSIM	U(6)
+#define TEGRA_PRE_SI_VDK		U(8)
+
+/*
+ * Read the chip ID value
+ */
+static uint32_t tegra_get_chipid(void)
+{
+	return mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET);
+}
+
+/*
+ * Read the chip's major version from chip ID value
+ */
+uint32_t tegra_get_chipid_major(void)
+{
+	return (tegra_get_chipid() >> MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK;
+}
+
+/*
+ * Read the chip's minor version from the chip ID value
+ */
+uint32_t tegra_get_chipid_minor(void)
+{
+	return (tegra_get_chipid() >> MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK;
+}
+
+/*
+ * Read the chip's pre_si_platform valus from the chip ID value
+ */
+static uint32_t tegra_get_chipid_pre_si_platform(void)
+{
+	return (tegra_get_chipid() >> PRE_SI_PLATFORM_SHIFT) & PRE_SI_PLATFORM_MASK;
+}
+
+bool tegra_chipid_is_t132(void)
+{
+	uint32_t chip_id = ((tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK);
+
+	return (chip_id == TEGRA_CHIPID_TEGRA13);
+}
+
+bool tegra_chipid_is_t186(void)
+{
+	uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK;
+
+	return (chip_id == TEGRA_CHIPID_TEGRA18);
+}
+
+bool tegra_chipid_is_t210(void)
+{
+	uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK;
+
+	return (chip_id == TEGRA_CHIPID_TEGRA21);
+}
+
+bool tegra_chipid_is_t210_b01(void)
+{
+	return (tegra_chipid_is_t210() && (tegra_get_chipid_major() == 0x2U));
+}
+
+/*
+ * Read the chip ID value and derive the platform
+ */
+static tegra_platform_t tegra_get_platform(void)
+{
+	uint32_t major, minor, pre_si_platform;
+	tegra_platform_t ret;
+
+	/* get the major/minor chip ID values */
+	major = tegra_get_chipid_major();
+	minor = tegra_get_chipid_minor();
+	pre_si_platform = tegra_get_chipid_pre_si_platform();
+
+	if (major == 0U) {
+		/*
+		 * The minor version number is used by simulation platforms
+		 */
+		switch (minor) {
+		/*
+		 * Cadence's QuickTurn emulation system is a Solaris-based
+		 * chip emulation system
+		 */
+		case TEGRA_MINOR_QT:
+		case TEGRA_MINOR_ASIM_QT:
+			ret = TEGRA_PLATFORM_QT;
+			break;
+
+		/*
+		 * FPGAs are used during early software/hardware development
+		 */
+		case TEGRA_MINOR_FPGA:
+			ret = TEGRA_PLATFORM_FPGA;
+			break;
+		/*
+		 * Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel
+		 * simulation framework.
+		 */
+		case TEGRA_MINOR_ASIM_LINSIM:
+		case TEGRA_MINOR_DSIM_ASIM_LINSIM:
+			ret = TEGRA_PLATFORM_LINSIM;
+			break;
+
+		/*
+		 * Unit FPGAs run the actual hardware block IP on the FPGA with
+		 * the other parts of the system using Linsim.
+		 */
+		case TEGRA_MINOR_UNIT_FPGA:
+			ret = TEGRA_PLATFORM_UNIT_FPGA;
+			break;
+		/*
+		 * The Virtualizer Development Kit (VDK) is the standard chip
+		 * development from Synopsis.
+		 */
+		case TEGRA_MINOR_VIRT_DEV_KIT:
+			ret = TEGRA_PLATFORM_VIRT_DEV_KIT;
+			break;
+
+		default:
+			ret = TEGRA_PLATFORM_MAX;
+			break;
+		}
+
+	} else if (pre_si_platform > 0U) {
+
+		switch (pre_si_platform) {
+		/*
+		 * Cadence's QuickTurn emulation system is a Solaris-based
+		 * chip emulation system
+		 */
+		case TEGRA_PRE_SI_QT:
+		case TEGRA_PRE_SI_ASIM_QT:
+			ret = TEGRA_PLATFORM_QT;
+			break;
+
+		/*
+		 * FPGAs are used during early software/hardware development
+		 */
+		case TEGRA_PRE_SI_FPGA:
+			ret = TEGRA_PLATFORM_FPGA;
+			break;
+		/*
+		 * Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel
+		 * simulation framework.
+		 */
+		case TEGRA_PRE_SI_ASIM_LINSIM:
+		case TEGRA_PRE_SI_DSIM_ASIM_LINSIM:
+			ret = TEGRA_PLATFORM_LINSIM;
+			break;
+
+		/*
+		 * Unit FPGAs run the actual hardware block IP on the FPGA with
+		 * the other parts of the system using Linsim.
+		 */
+		case TEGRA_PRE_SI_UNIT_FPGA:
+			ret = TEGRA_PLATFORM_UNIT_FPGA;
+			break;
+		/*
+		 * The Virtualizer Development Kit (VDK) is the standard chip
+		 * development from Synopsis.
+		 */
+		case TEGRA_PRE_SI_VDK:
+			ret = TEGRA_PLATFORM_VIRT_DEV_KIT;
+			break;
+
+		default:
+			ret = TEGRA_PLATFORM_MAX;
+			break;
+		}
+
+	} else {
+		/* Actual silicon platforms have a non-zero major version */
+		ret = TEGRA_PLATFORM_SILICON;
+	}
+
+	return ret;
+}
+
+bool tegra_platform_is_silicon(void)
+{
+	return ((tegra_get_platform() == TEGRA_PLATFORM_SILICON) ? true : false);
+}
+
+bool tegra_platform_is_qt(void)
+{
+	return ((tegra_get_platform() == TEGRA_PLATFORM_QT) ? true : false);
+}
+
+bool tegra_platform_is_linsim(void)
+{
+	tegra_platform_t plat = tegra_get_platform();
+
+	return (((plat == TEGRA_PLATFORM_LINSIM) ||
+	       (plat == TEGRA_PLATFORM_UNIT_FPGA)) ? true : false);
+}
+
+bool tegra_platform_is_fpga(void)
+{
+	return ((tegra_get_platform() == TEGRA_PLATFORM_FPGA) ? true : false);
+}
+
+bool tegra_platform_is_emulation(void)
+{
+	return (tegra_get_platform() == TEGRA_PLATFORM_EMULATION);
+}
+
+bool tegra_platform_is_unit_fpga(void)
+{
+	return ((tegra_get_platform() == TEGRA_PLATFORM_UNIT_FPGA) ? true : false);
+}
+
+bool tegra_platform_is_virt_dev_kit(void)
+{
+	return ((tegra_get_platform() == TEGRA_PLATFORM_VIRT_DEV_KIT) ? true : false);
+}
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c
new file mode 100644
index 0000000..e06a116
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_pm.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <memctrl.h>
+#include <pmc.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+extern uint64_t tegra_bl31_phys_base;
+extern uint64_t tegra_sec_entry_point;
+extern uint64_t tegra_console_base;
+
+/*
+ * tegra_fake_system_suspend acts as a boolean var controlling whether
+ * we are going to take fake system suspend code or normal system suspend code
+ * path. This variable is set inside the sip call handlers,when the kernel
+ * requests a SIP call to set the suspend debug flags.
+ */
+uint8_t tegra_fake_system_suspend;
+
+/*
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that will be overridden by a SoC.
+ */
+#pragma weak tegra_soc_pwr_domain_suspend_pwrdown_early
+#pragma weak tegra_soc_cpu_standby
+#pragma weak tegra_soc_pwr_domain_suspend
+#pragma weak tegra_soc_pwr_domain_on
+#pragma weak tegra_soc_pwr_domain_off
+#pragma weak tegra_soc_pwr_domain_on_finish
+#pragma weak tegra_soc_pwr_domain_power_down_wfi
+#pragma weak tegra_soc_prepare_system_reset
+#pragma weak tegra_soc_prepare_system_off
+#pragma weak tegra_soc_get_target_pwr_state
+
+int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
+{
+	(void)cpu_state;
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	(void)target_state;
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
+{
+	(void)mpidr;
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	(void)target_state;
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	(void)target_state;
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
+{
+	(void)target_state;
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_prepare_system_reset(void)
+{
+	return PSCI_E_SUCCESS;
+}
+
+__dead2 void tegra_soc_prepare_system_off(void)
+{
+	ERROR("Tegra System Off: operation not handled.\n");
+	panic();
+}
+
+plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
+					     const plat_local_state_t *states,
+					     uint32_t ncpu)
+{
+	plat_local_state_t target = PLAT_MAX_OFF_STATE, temp;
+	uint32_t num_cpu = ncpu;
+	const plat_local_state_t *local_state = states;
+
+	(void)lvl;
+
+	assert(ncpu != 0U);
+
+	do {
+		temp = *local_state;
+		if ((temp < target)) {
+			target = temp;
+		}
+		--num_cpu;
+		local_state++;
+	} while (num_cpu != 0U);
+
+	return target;
+}
+
+/*******************************************************************************
+ * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
+ * call to get the `power_state` parameter. This allows the platform to encode
+ * the appropriate State-ID field within the `power_state` parameter which can
+ * be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
+******************************************************************************/
+void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	/* all affinities use system suspend state id */
+	for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
+		req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN;
+	}
+}
+
+/*******************************************************************************
+ * Handler called when an affinity instance is about to enter standby.
+ ******************************************************************************/
+void tegra_cpu_standby(plat_local_state_t cpu_state)
+{
+	u_register_t saved_scr_el3;
+
+	(void)cpu_state;
+
+	/* Tegra SoC specific handler */
+	if (tegra_soc_cpu_standby(cpu_state) != PSCI_E_SUCCESS)
+		ERROR("%s failed\n", __func__);
+
+	saved_scr_el3 = read_scr_el3();
+
+	/*
+	 * As per ARM ARM D1.17.2, any physical IRQ interrupt received by the
+	 * PE will be treated as a wake-up event, if SCR_EL3.IRQ is set to '1',
+	 * irrespective of the value of the PSTATE.I bit value.
+	 */
+	write_scr_el3(saved_scr_el3 | SCR_IRQ_BIT);
+
+	/*
+	 * Enter standby state
+	 *
+	 * dsb & isb is good practice before using wfi to enter low power states
+	 */
+	dsb();
+	isb();
+	wfi();
+
+	/*
+	 * Restore saved scr_el3 that has IRQ bit cleared as we don't want EL3
+	 * handling any further interrupts
+	 */
+	write_scr_el3(saved_scr_el3);
+}
+
+/*******************************************************************************
+ * Handler called when an affinity instance is about to be turned on. The
+ * level and mpidr determine the affinity instance.
+ ******************************************************************************/
+int32_t tegra_pwr_domain_on(u_register_t mpidr)
+{
+	return tegra_soc_pwr_domain_on(mpidr);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void tegra_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	(void)tegra_soc_pwr_domain_off(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ * This handler is called with SMP and data cache enabled, when
+ * HW_ASSISTED_COHERENCY = 0
+ ******************************************************************************/
+void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
+{
+	tegra_soc_pwr_domain_suspend_pwrdown_early(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	(void)tegra_soc_pwr_domain_suspend(target_state);
+
+	/* Disable console if we are entering deep sleep. */
+	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+			PSTATE_ID_SOC_POWERDN) {
+		(void)console_uninit();
+	}
+
+	/* disable GICC */
+	tegra_gic_cpuif_deactivate();
+}
+
+/*******************************************************************************
+ * Handler called at the end of the power domain suspend sequence. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+__dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t
+					     *target_state)
+{
+	uint8_t pwr_state = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
+	uint64_t rmr_el3 = 0;
+
+	/* call the chip's power down handler */
+	(void)tegra_soc_pwr_domain_power_down_wfi(target_state);
+
+	/*
+	 * If we are in fake system suspend mode, ensure we start doing
+	 * procedures that help in looping back towards system suspend exit
+	 * instead of calling WFI by requesting a warm reset.
+	 * Else, just call WFI to enter low power state.
+	 */
+	if ((tegra_fake_system_suspend != 0U) &&
+	    (pwr_state == (uint8_t)PSTATE_ID_SOC_POWERDN)) {
+
+		/* warm reboot */
+		rmr_el3 = read_rmr_el3();
+		write_rmr_el3(rmr_el3 | RMR_WARM_RESET_CPU);
+
+	} else {
+		/* enter power down state */
+		wfi();
+	}
+
+	/* we can never reach here */
+	panic();
+}
+
+/*******************************************************************************
+ * Handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	const plat_params_from_bl2_t *plat_params;
+	uint32_t console_clock;
+
+	/*
+	 * Initialize the GIC cpu and distributor interfaces
+	 */
+	tegra_gic_init();
+
+	/*
+	 * Check if we are exiting from deep sleep.
+	 */
+	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+			PSTATE_ID_SOC_POWERDN) {
+
+		/*
+		 * Reference clock used by the FPGAs is a lot slower.
+		 */
+		if (tegra_platform_is_fpga()) {
+			console_clock = TEGRA_BOOT_UART_CLK_13_MHZ;
+		} else {
+			console_clock = TEGRA_BOOT_UART_CLK_408_MHZ;
+		}
+
+		/* Initialize the runtime console */
+		if (tegra_console_base != 0ULL) {
+			(void)console_init(tegra_console_base, console_clock,
+				     TEGRA_CONSOLE_BAUDRATE);
+		}
+
+		/*
+		 * Restore Memory Controller settings as it loses state
+		 * during system suspend.
+		 */
+		tegra_memctrl_restore_settings();
+
+		/*
+		 * Security configuration to allow DRAM/device access.
+		 */
+		plat_params = bl31_get_plat_params();
+		tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
+			(uint32_t)plat_params->tzdram_size);
+
+		/*
+		 * Set up the TZRAM memory aperture to allow only secure world
+		 * access
+		 */
+		tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
+	}
+
+	/*
+	 * Reset hardware settings.
+	 */
+	(void)tegra_soc_pwr_domain_on_finish(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ ******************************************************************************/
+void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	tegra_pwr_domain_on_finish(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when the system wants to be powered off
+ ******************************************************************************/
+__dead2 void tegra_system_off(void)
+{
+	INFO("Powering down system...\n");
+
+	tegra_soc_prepare_system_off();
+}
+
+/*******************************************************************************
+ * Handler called when the system wants to be restarted.
+ ******************************************************************************/
+__dead2 void tegra_system_reset(void)
+{
+	INFO("Restarting system...\n");
+
+	/* per-SoC system reset handler */
+	(void)tegra_soc_prepare_system_reset();
+
+	/*
+	 * Program the PMC in order to restart the system.
+	 */
+	tegra_pmc_system_reset();
+}
+
+/*******************************************************************************
+ * Handler called to check the validity of the power state parameter.
+ ******************************************************************************/
+int32_t tegra_validate_power_state(uint32_t power_state,
+				   psci_power_state_t *req_state)
+{
+	assert(req_state != NULL);
+
+	return tegra_soc_validate_power_state(power_state, req_state);
+}
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the non secure entrypoint.
+ ******************************************************************************/
+int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	int32_t ret = PSCI_E_INVALID_ADDRESS;
+
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) {
+		ret = PSCI_E_SUCCESS;
+	}
+
+	return ret;
+}
+
+/*******************************************************************************
+ * Export the platform handlers to enable psci to invoke them
+ ******************************************************************************/
+static const plat_psci_ops_t tegra_plat_psci_ops = {
+	.cpu_standby			= tegra_cpu_standby,
+	.pwr_domain_on			= tegra_pwr_domain_on,
+	.pwr_domain_off			= tegra_pwr_domain_off,
+	.pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early,
+	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
+	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi	= tegra_pwr_domain_power_down_wfi,
+	.system_off			= tegra_system_off,
+	.system_reset			= tegra_system_reset,
+	.validate_power_state		= tegra_validate_power_state,
+	.validate_ns_entrypoint		= tegra_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= tegra_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops and initialize Power Controller
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
+
+	/*
+	 * Flush entrypoint variable to PoC since it will be
+	 * accessed after a reset with the caches turned off.
+	 */
+	tegra_sec_entry_point = sec_entrypoint;
+	flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
+
+	/*
+	 * Reset hardware settings.
+	 */
+	(void)tegra_soc_pwr_domain_on_finish(&target_state);
+
+	/*
+	 * Initialize PSCI ops struct
+	 */
+	*psci_ops = &tegra_plat_psci_ops;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Platform handler to calculate the proper target power level at the
+ * specified affinity level
+ ******************************************************************************/
+plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	return tegra_soc_get_target_pwr_state(lvl, states, ncpu);
+}
diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c
new file mode 100644
index 0000000..957300e
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_sip_calls.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <memctrl.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * Common Tegra SiP SMCs
+ ******************************************************************************/
+#define TEGRA_SIP_NEW_VIDEOMEM_REGION		0x82000003
+#define TEGRA_SIP_FIQ_NS_ENTRYPOINT		0x82000005
+#define TEGRA_SIP_FIQ_NS_GET_CONTEXT		0x82000006
+#define TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND	0xC2000007
+
+/*******************************************************************************
+ * Fake system suspend mode control var
+ ******************************************************************************/
+extern uint8_t tegra_fake_system_suspend;
+
+/*******************************************************************************
+ * SoC specific SiP handler
+ ******************************************************************************/
+#pragma weak plat_sip_handler
+int32_t plat_sip_handler(uint32_t smc_fid,
+		     uint64_t x1,
+		     uint64_t x2,
+		     uint64_t x3,
+		     uint64_t x4,
+		     const void *cookie,
+		     void *handle,
+		     uint64_t flags)
+{
+	/* unused parameters */
+	(void)smc_fid;
+	(void)x1;
+	(void)x2;
+	(void)x3;
+	(void)x4;
+	(void)cookie;
+	(void)handle;
+	(void)flags;
+
+	return -ENOTSUP;
+}
+
+/*******************************************************************************
+ * This function is responsible for handling all SiP calls
+ ******************************************************************************/
+uintptr_t tegra_sip_handler(uint32_t smc_fid,
+			    u_register_t x1,
+			    u_register_t x2,
+			    u_register_t x3,
+			    u_register_t x4,
+			    void *cookie,
+			    void *handle,
+			    u_register_t flags)
+{
+	uint32_t regval, local_x2_32 = (uint32_t)x2;
+	int32_t err;
+
+	/* Check if this is a SoC specific SiP */
+	err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+	if (err == 0) {
+
+		SMC_RET1(handle, (uint64_t)err);
+
+	} else {
+
+		switch (smc_fid) {
+
+		case TEGRA_SIP_NEW_VIDEOMEM_REGION:
+
+			/*
+			 * Check if Video Memory overlaps TZDRAM (contains bl31/bl32)
+			 * or falls outside of the valid DRAM range
+			*/
+			err = bl31_check_ns_address(x1, local_x2_32);
+			if (err != 0) {
+				SMC_RET1(handle, (uint64_t)err);
+			}
+
+			/*
+			 * Check if Video Memory is aligned to 1MB.
+			 */
+			if (((x1 & 0xFFFFFU) != 0U) || ((local_x2_32 & 0xFFFFFU) != 0U)) {
+				ERROR("Unaligned Video Memory base address!\n");
+				SMC_RET1(handle, (uint64_t)-ENOTSUP);
+			}
+
+			/*
+			 * The GPU is the user of the Video Memory region. In order to
+			 * transition to the new memory region smoothly, we program the
+			 * new base/size ONLY if the GPU is in reset mode.
+			 */
+			regval = mmio_read_32(TEGRA_CAR_RESET_BASE +
+					      TEGRA_GPU_RESET_REG_OFFSET);
+			if ((regval & GPU_RESET_BIT) == 0U) {
+				ERROR("GPU not in reset! Video Memory setup failed\n");
+				SMC_RET1(handle, (uint64_t)-ENOTSUP);
+			}
+
+			/* new video memory carveout settings */
+			tegra_memctrl_videomem_setup(x1, local_x2_32);
+
+			/*
+			 * Ensure again that GPU is still in reset after VPR resize
+			 */
+			regval = mmio_read_32(TEGRA_CAR_RESET_BASE +
+					      TEGRA_GPU_RESET_REG_OFFSET);
+			if ((regval & GPU_RESET_BIT) == 0U) {
+				mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_GPU_SET_OFFSET,
+									GPU_SET_BIT);
+			}
+
+			SMC_RET1(handle, 0);
+
+		/*
+		 * The NS world registers the address of its handler to be
+		 * used for processing the FIQ. This is normally used by the
+		 * NS FIQ debugger driver to detect system hangs by programming
+		 * a watchdog timer to fire a FIQ interrupt.
+		 */
+		case TEGRA_SIP_FIQ_NS_ENTRYPOINT:
+
+			if (x1 == 0U) {
+				SMC_RET1(handle, SMC_UNK);
+			}
+
+			/*
+			 * TODO: Check if x1 contains a valid DRAM address
+			 */
+
+			/* store the NS world's entrypoint */
+			tegra_fiq_set_ns_entrypoint(x1);
+
+			SMC_RET1(handle, 0);
+
+		/*
+		 * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0
+		 * CPU context when the FIQ interrupt was triggered. This allows the
+		 * NS world to understand the CPU state when the watchdog interrupt
+		 * triggered.
+		 */
+		case TEGRA_SIP_FIQ_NS_GET_CONTEXT:
+
+			/* retrieve context registers when FIQ triggered */
+			(void)tegra_fiq_get_intr_context();
+
+			SMC_RET0(handle);
+
+		case TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND:
+			/*
+			 * System suspend fake mode is set if we are on VDK and we make
+			 * a debug SIP call. This mode ensures that we excercise debug
+			 * path instead of the regular code path to suit the pre-silicon
+			 * platform needs. These include replacing the call to WFI by
+			 * a warm reset request.
+			 */
+			if (tegra_platform_is_virt_dev_kit() != false) {
+
+				tegra_fake_system_suspend = 1;
+				SMC_RET1(handle, 0);
+			}
+
+			/*
+			 * We return to the external world as if this SIP is not
+			 * implemented in case, we are not running on VDK.
+			 */
+			break;
+
+		default:
+			ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+			break;
+		}
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	tegra_sip_fast,
+
+	(OEN_SIP_START),
+	(OEN_SIP_END),
+	(SMC_TYPE_FAST),
+	(NULL),
+	(tegra_sip_handler)
+);
diff --git a/plat/nvidia/tegra/common/tegra_topology.c b/plat/nvidia/tegra/common/tegra_topology.c
new file mode 100644
index 0000000..205b051
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_topology.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#pragma weak plat_core_pos_by_mpidr
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	u_register_t cluster_id, cpu_id;
+	int32_t result;
+
+	cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) &
+		     (u_register_t)MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) &
+		 (u_register_t)MPIDR_AFFLVL_MASK;
+
+	/* CorePos = CoreId + (ClusterId * cpus per cluster) */
+	result = (int32_t)cpu_id + ((int32_t)cluster_id *
+		 PLATFORM_MAX_CPUS_PER_CLUSTER);
+
+	if (cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) {
+		result = PSCI_E_NOT_PRESENT;
+	}
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER) {
+		result = PSCI_E_NOT_PRESENT;
+	}
+
+	return result;
+}
diff --git a/plat/nvidia/tegra/include/drivers/bpmp.h b/plat/nvidia/tegra/include/drivers/bpmp.h
new file mode 100644
index 0000000..dc3fb6b
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/bpmp.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BPMP_H
+#define BPMP_H
+
+#include <stdint.h>
+
+/* macro to enable clock to the Atomics block */
+#define CAR_ENABLE_ATOMICS	(1U << 16)
+
+/* command to get the channel base addresses from bpmp */
+#define ATOMIC_CMD_GET		4U
+
+/* Hardware IRQ # used to signal bpmp of an incoming command */
+#define INT_SHR_SEM_OUTBOX_FULL	6U
+
+/* macros to decode the bpmp's state */
+#define CH_MASK(ch)		((uint32_t)0x3 << ((ch) * 2U))
+#define MA_FREE(ch)		((uint32_t)0x2 << ((ch) * 2U))
+#define MA_ACKD(ch)		((uint32_t)0x3 << ((ch) * 2U))
+
+/* response from bpmp to indicate it has powered up */
+#define SIGN_OF_LIFE		0xAAAAAAAAU
+
+/* flags to indicate bpmp driver's state */
+#define BPMP_NOT_PRESENT	0xF00DBEEFU
+#define BPMP_INIT_COMPLETE	0xBEEFF00DU
+#define BPMP_INIT_PENDING	0xDEADBEEFU
+#define BPMP_SUSPEND_ENTRY	0xF00DCAFEU
+
+/* requests serviced by the bpmp */
+#define MRQ_PING		0
+#define MRQ_QUERY_TAG		1
+#define MRQ_DO_IDLE		2
+#define MRQ_TOLERATE_IDLE	3
+#define MRQ_MODULE_LOAD		4
+#define MRQ_MODULE_UNLOAD	5
+#define MRQ_SWITCH_CLUSTER	6
+#define MRQ_TRACE_MODIFY	7
+#define MRQ_WRITE_TRACE		8
+#define MRQ_THREADED_PING	9
+#define MRQ_CPUIDLE_USAGE	10
+#define MRQ_MODULE_MAIL		11
+#define MRQ_SCX_ENABLE		12
+#define MRQ_BPMPIDLE_USAGE	14
+#define MRQ_HEAP_USAGE		15
+#define MRQ_SCLK_SKIP_SET_RATE	16
+#define MRQ_ENABLE_SUSPEND	17
+#define MRQ_PASR_MASK		18
+#define MRQ_DEBUGFS		19
+#define MRQ_THERMAL		27
+
+/* Tegra PM states as known to BPMP */
+#define TEGRA_PM_CC1		9
+#define TEGRA_PM_CC4		12
+#define TEGRA_PM_CC6		14
+#define TEGRA_PM_CC7		15
+#define TEGRA_PM_SC1		17
+#define TEGRA_PM_SC2		18
+#define TEGRA_PM_SC3		19
+#define TEGRA_PM_SC4		20
+#define TEGRA_PM_SC7		23
+
+/* flag to indicate if entry into a CCx power state is allowed */
+#define BPMP_CCx_ALLOWED	0U
+
+/* number of communication channels to interact with the bpmp */
+#define NR_CHANNELS		4U
+
+/* flag to ask bpmp to acknowledge command packet */
+#define NO_ACK			(0U << 0U)
+#define DO_ACK			(1U << 0U)
+
+/* size of the command/response data */
+#define MSG_DATA_MAX_SZ		120U
+
+/**
+ * command/response packet to/from the bpmp
+ *
+ * command
+ * -------
+ * code: MRQ_* command
+ * flags: DO_ACK or NO_ACK
+ * data:
+ * 	[0] = cpu #
+ * 	[1] = cluster power state (TEGRA_PM_CCx)
+ * 	[2] = system power state (TEGRA_PM_SCx)
+ *
+ * response
+ * ---------
+ * code: error code
+ * flags: not used
+ * data:
+ * 	[0-3] = response value
+ */
+typedef struct mb_data {
+	int32_t code;
+	uint32_t flags;
+	uint8_t data[MSG_DATA_MAX_SZ];
+} mb_data_t;
+
+/**
+ * Function to initialise the interface with the bpmp
+ */
+int tegra_bpmp_init(void);
+
+/**
+ * Function to suspend the interface with the bpmp
+ */
+void tegra_bpmp_suspend(void);
+
+/**
+ * Function to resume the interface with the bpmp
+ */
+void tegra_bpmp_resume(void);
+
+/**
+ * Handler to send a MRQ_* command to the bpmp
+ */
+int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,
+		void *ib_data, int ib_sz);
+
+#endif /* BPMP_H */
diff --git a/plat/nvidia/tegra/include/drivers/bpmp_ipc.h b/plat/nvidia/tegra/include/drivers/bpmp_ipc.h
new file mode 100644
index 0000000..0d1e405
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/bpmp_ipc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __BPMP_IPC_H__
+#define __BPMP_IPC_H__
+
+#include <lib/utils_def.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * Currently supported reset identifiers
+ */
+#define TEGRA_RESET_ID_XUSB_PADCTL	U(114)
+#define TEGRA_RESET_ID_GPCDMA		U(70)
+
+/**
+ * Clock identifier for the SE device
+ */
+#define TEGRA_CLK_SE        U(124)
+
+/**
+ * Function to initialise the IPC with the bpmp
+ */
+int32_t tegra_bpmp_ipc_init(void);
+
+/**
+ * Handler to reset a module
+ */
+int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id);
+
+/**
+ * Handler to enable clock to a module. Only SE device is
+ * supported for now.
+ */
+int tegra_bpmp_ipc_enable_clock(uint32_t clk_id);
+
+/**
+ * Handler to disable clock to a module. Only SE device is
+ * supported for now.
+ */
+int tegra_bpmp_ipc_disable_clock(uint32_t clk_id);
+
+#endif /* __BPMP_IPC_H__ */
diff --git a/plat/nvidia/tegra/include/drivers/flowctrl.h b/plat/nvidia/tegra/include/drivers/flowctrl.h
new file mode 100644
index 0000000..54336b0
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/flowctrl.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FLOWCTRL_H
+#define FLOWCTRL_H
+
+#include <lib/mmio.h>
+
+#include <tegra_def.h>
+
+#define FLOWCTRL_HALT_CPU0_EVENTS	(0x0U)
+#define  FLOWCTRL_WAITEVENT		(2U << 29)
+#define  FLOWCTRL_WAIT_FOR_INTERRUPT	(4U << 29)
+#define  FLOWCTRL_JTAG_RESUME		(1U << 28)
+#define  FLOWCTRL_HALT_SCLK		(1U << 27)
+#define  FLOWCTRL_HALT_LIC_IRQ		(1U << 11)
+#define  FLOWCTRL_HALT_LIC_FIQ		(1U << 10)
+#define  FLOWCTRL_HALT_GIC_IRQ		(1U << 9)
+#define  FLOWCTRL_HALT_GIC_FIQ		(1U << 8)
+#define FLOWCTRL_HALT_BPMP_EVENTS	(0x4U)
+#define FLOWCTRL_CPU0_CSR		(0x8U)
+#define  FLOWCTRL_CSR_HALT_MASK		(1U << 22)
+#define  FLOWCTRL_CSR_PWR_OFF_STS	(1U << 16)
+#define  FLOWCTRL_CSR_INTR_FLAG		(1U << 15)
+#define  FLOWCTRL_CSR_EVENT_FLAG	(1U << 14)
+#define  FLOWCTRL_CSR_IMMEDIATE_WAKE	(1U << 3)
+#define  FLOWCTRL_CSR_ENABLE		(1U << 0)
+#define FLOWCTRL_HALT_CPU1_EVENTS	(0x14U)
+#define FLOWCTRL_CPU1_CSR		(0x18U)
+#define FLOW_CTLR_FLOW_DBG_QUAL		(0x50U)
+#define  FLOWCTRL_FIQ2CCPLEX_ENABLE	(1U << 28)
+#define FLOWCTRL_FC_SEQ_INTERCEPT	(0x5cU)
+#define  INTERCEPT_IRQ_PENDING		(0xffU)
+#define  INTERCEPT_HVC			(U(1) << 21)
+#define  INTERCEPT_ENTRY_CC4		(U(1) << 20)
+#define  INTERCEPT_ENTRY_PG_NONCPU	(U(1) << 19)
+#define  INTERCEPT_EXIT_PG_NONCPU	(U(1) << 18)
+#define  INTERCEPT_ENTRY_RG_CPU		(U(1) << 17)
+#define  INTERCEPT_EXIT_RG_CPU		(U(1) << 16)
+#define  INTERCEPT_ENTRY_PG_CORE0	(U(1) << 15)
+#define  INTERCEPT_EXIT_PG_CORE0	(U(1) << 14)
+#define  INTERCEPT_ENTRY_PG_CORE1	(U(1) << 13)
+#define  INTERCEPT_EXIT_PG_CORE1	(U(1) << 12)
+#define  INTERCEPT_ENTRY_PG_CORE2	(U(1) << 11)
+#define  INTERCEPT_EXIT_PG_CORE2	(U(1) << 10)
+#define  INTERCEPT_ENTRY_PG_CORE3	(U(1) << 9)
+#define  INTERCEPT_EXIT_PG_CORE3	(U(1) << 8)
+#define  INTERRUPT_PENDING_NONCPU	(U(1) << 7)
+#define  INTERRUPT_PENDING_CRAIL	(U(1) << 6)
+#define  INTERRUPT_PENDING_CORE0	(U(1) << 5)
+#define  INTERRUPT_PENDING_CORE1	(U(1) << 4)
+#define  INTERRUPT_PENDING_CORE2	(U(1) << 3)
+#define  INTERRUPT_PENDING_CORE3	(U(1) << 2)
+#define  CC4_INTERRUPT_PENDING		(U(1) << 1)
+#define  HVC_INTERRUPT_PENDING		(U(1) << 0)
+#define FLOWCTRL_CC4_CORE0_CTRL		(0x6cU)
+#define FLOWCTRL_WAIT_WFI_BITMAP	(0x100U)
+#define FLOWCTRL_L2_FLUSH_CONTROL	(0x94U)
+#define FLOWCTRL_BPMP_CLUSTER_CONTROL	(0x98U)
+#define  FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK	(1U << 2)
+
+#define FLOWCTRL_ENABLE_EXT		12U
+#define FLOWCTRL_ENABLE_EXT_MASK	3U
+#define FLOWCTRL_PG_CPU_NONCPU		0x1U
+#define FLOWCTRL_TURNOFF_CPURAIL	0x2U
+
+static inline uint32_t tegra_fc_read_32(uint32_t off)
+{
+	return mmio_read_32(TEGRA_FLOWCTRL_BASE + off);
+}
+
+static inline void tegra_fc_write_32(uint32_t off, uint32_t val)
+{
+	mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val);
+}
+
+void tegra_fc_bpmp_on(uint32_t entrypoint);
+void tegra_fc_bpmp_off(void);
+void tegra_fc_ccplex_pgexit_lock(void);
+void tegra_fc_ccplex_pgexit_unlock(void);
+void tegra_fc_cluster_idle(uint32_t midr);
+void tegra_fc_cpu_powerdn(uint32_t mpidr);
+void tegra_fc_cluster_powerdn(uint32_t midr);
+void tegra_fc_cpu_on(int cpu);
+void tegra_fc_cpu_off(int cpu);
+void tegra_fc_disable_fiq_to_ccplex_routing(void);
+void tegra_fc_enable_fiq_to_ccplex_routing(void);
+bool tegra_fc_is_ccx_allowed(void);
+void tegra_fc_lock_active_cluster(void);
+void tegra_fc_soc_powerdn(uint32_t midr);
+
+#endif /* FLOWCTRL_H */
diff --git a/plat/nvidia/tegra/include/drivers/gpcdma.h b/plat/nvidia/tegra/include/drivers/gpcdma.h
new file mode 100644
index 0000000..fb5486a
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/gpcdma.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __GPCDMA_H__
+#define __GPCDMA_H__
+
+#include <stdint.h>
+
+void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr,
+			    uint32_t num_bytes);
+void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes);
+
+#endif /* __GPCDMA_H__ */
diff --git a/plat/nvidia/tegra/include/drivers/mce.h b/plat/nvidia/tegra/include/drivers/mce.h
new file mode 100644
index 0000000..4470b6b
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/mce.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCE_H
+#define MCE_H
+
+#include <lib/mmio.h>
+
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * MCE commands
+ ******************************************************************************/
+typedef enum mce_cmd {
+	MCE_CMD_ENTER_CSTATE = 0U,
+	MCE_CMD_UPDATE_CSTATE_INFO = 1U,
+	MCE_CMD_UPDATE_CROSSOVER_TIME = 2U,
+	MCE_CMD_READ_CSTATE_STATS = 3U,
+	MCE_CMD_WRITE_CSTATE_STATS = 4U,
+	MCE_CMD_IS_SC7_ALLOWED = 5U,
+	MCE_CMD_ONLINE_CORE = 6U,
+	MCE_CMD_CC3_CTRL = 7U,
+	MCE_CMD_ECHO_DATA = 8U,
+	MCE_CMD_READ_VERSIONS = 9U,
+	MCE_CMD_ENUM_FEATURES = 10U,
+	MCE_CMD_ROC_FLUSH_CACHE_TRBITS = 11U,
+	MCE_CMD_ENUM_READ_MCA = 12U,
+	MCE_CMD_ENUM_WRITE_MCA = 13U,
+	MCE_CMD_ROC_FLUSH_CACHE = 14U,
+	MCE_CMD_ROC_CLEAN_CACHE = 15U,
+	MCE_CMD_ENABLE_LATIC = 16U,
+	MCE_CMD_UNCORE_PERFMON_REQ = 17U,
+	MCE_CMD_MISC_CCPLEX = 18U,
+	MCE_CMD_IS_CCX_ALLOWED = 0xFEU,
+	MCE_CMD_MAX = 0xFFU,
+} mce_cmd_t;
+
+#define MCE_CMD_MASK				0xFFU
+
+/*******************************************************************************
+ * Timeout value used to powerdown a core
+ ******************************************************************************/
+#define MCE_CORE_SLEEP_TIME_INFINITE		0xFFFFFFFFU
+
+/*******************************************************************************
+ * Struct to prepare UPDATE_CSTATE_INFO request
+ ******************************************************************************/
+typedef struct mce_cstate_info {
+	/* cluster cstate value */
+	uint32_t cluster;
+	/* ccplex cstate value */
+	uint32_t ccplex;
+	/* system cstate value */
+	uint32_t system;
+	/* force system state? */
+	uint8_t system_state_force;
+	/* wake mask value */
+	uint32_t wake_mask;
+	/* update the wake mask? */
+	uint8_t update_wake_mask;
+} mce_cstate_info_t;
+
+/* public interfaces */
+int mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1,
+		uint64_t arg2);
+int mce_update_reset_vector(void);
+int mce_update_gsc_videomem(void);
+int mce_update_gsc_tzdram(void);
+int mce_update_gsc_tzram(void);
+__dead2 void mce_enter_ccplex_state(uint32_t state_idx);
+void mce_update_cstate_info(const mce_cstate_info_t *cstate);
+void mce_verify_firmware_version(void);
+
+#endif /* MCE_H */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl.h b/plat/nvidia/tegra/include/drivers/memctrl.h
new file mode 100644
index 0000000..d5ef60d
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEMCTRL_H
+#define MEMCTRL_H
+
+void tegra_memctrl_setup(void);
+void tegra_memctrl_restore_settings(void);
+void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes);
+void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes);
+void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes);
+void tegra_memctrl_disable_ahb_redirection(void);
+void tegra_memctrl_clear_pending_interrupts(void);
+
+#endif /* MEMCTRL_H */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v1.h b/plat/nvidia/tegra/include/drivers/memctrl_v1.h
new file mode 100644
index 0000000..8e9f198
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v1.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEMCTRL_V1_H
+#define MEMCTRL_V1_H
+
+#include <lib/mmio.h>
+
+#include <tegra_def.h>
+
+/* SMMU registers */
+#define MC_SMMU_CONFIG_0			0x10U
+#define  MC_SMMU_CONFIG_0_SMMU_ENABLE_DISABLE	0U
+#define  MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE	1U
+#define MC_SMMU_TLB_CONFIG_0			0x14U
+#define  MC_SMMU_TLB_CONFIG_0_RESET_VAL		0x20000010U
+#define MC_SMMU_PTC_CONFIG_0			0x18U
+#define  MC_SMMU_PTC_CONFIG_0_RESET_VAL		0x2000003fU
+#define MC_SMMU_TLB_FLUSH_0			0x30U
+#define  TLB_FLUSH_VA_MATCH_ALL			0U
+#define  TLB_FLUSH_ASID_MATCH_DISABLE		0U
+#define  TLB_FLUSH_ASID_MATCH_SHIFT		31U
+#define  MC_SMMU_TLB_FLUSH_ALL		\
+	 (TLB_FLUSH_VA_MATCH_ALL | 	\
+	 (TLB_FLUSH_ASID_MATCH_DISABLE << TLB_FLUSH_ASID_MATCH_SHIFT))
+#define MC_SMMU_PTC_FLUSH_0			0x34U
+#define  MC_SMMU_PTC_FLUSH_ALL			0U
+#define MC_SMMU_ASID_SECURITY_0			0x38U
+#define  MC_SMMU_ASID_SECURITY			0U
+#define MC_SMMU_TRANSLATION_ENABLE_0_0		0x228U
+#define MC_SMMU_TRANSLATION_ENABLE_1_0		0x22cU
+#define MC_SMMU_TRANSLATION_ENABLE_2_0		0x230U
+#define MC_SMMU_TRANSLATION_ENABLE_3_0		0x234U
+#define MC_SMMU_TRANSLATION_ENABLE_4_0		0xb98U
+#define  MC_SMMU_TRANSLATION_ENABLE		(~0)
+
+/* MC IRAM aperture registers */
+#define MC_IRAM_BASE_LO				0x65CU
+#define MC_IRAM_TOP_LO				0x660U
+#define MC_IRAM_BASE_TOP_HI			0x980U
+#define MC_IRAM_REG_CTRL			0x964U
+#define  MC_DISABLE_IRAM_CFG_WRITES		1U
+
+static inline uint32_t tegra_mc_read_32(uint32_t off)
+{
+	return mmio_read_32(TEGRA_MC_BASE + off);
+}
+
+static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
+{
+	mmio_write_32(TEGRA_MC_BASE + off, val);
+}
+
+#endif /* MEMCTRL_V1_H */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v2.h b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
new file mode 100644
index 0000000..a4085e2
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v2.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MEMCTRL_V2_H
+#define MEMCTRL_V2_H
+
+#include <tegra_def.h>
+
+#ifndef __ASSEMBLER__
+
+#include <lib/mmio.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Structure to hold the transaction override settings to use to override
+ * client inputs
+ ******************************************************************************/
+typedef struct mc_txn_override_cfg {
+	uint32_t offset;
+	uint8_t cgid_tag;
+} mc_txn_override_cfg_t;
+
+#define mc_make_txn_override_cfg(off, val) \
+	{ \
+		.offset = MC_TXN_OVERRIDE_CONFIG_ ## off, \
+		.cgid_tag = MC_TXN_OVERRIDE_ ## val \
+	}
+
+/*******************************************************************************
+ * Structure to hold the Stream ID to use to override client inputs
+ ******************************************************************************/
+typedef struct mc_streamid_override_cfg {
+	uint32_t offset;
+	uint8_t stream_id;
+} mc_streamid_override_cfg_t;
+
+/*******************************************************************************
+ * Structure to hold the Stream ID Security Configuration settings
+ ******************************************************************************/
+typedef struct mc_streamid_security_cfg {
+	char *name;
+	uint32_t offset;
+	int override_enable;
+	int override_client_inputs;
+	int override_client_ns_flag;
+} mc_streamid_security_cfg_t;
+
+#define OVERRIDE_DISABLE				1U
+#define OVERRIDE_ENABLE					0U
+#define CLIENT_FLAG_SECURE				0U
+#define CLIENT_FLAG_NON_SECURE				1U
+#define CLIENT_INPUTS_OVERRIDE				1U
+#define CLIENT_INPUTS_NO_OVERRIDE			0U
+/*******************************************************************************
+ * StreamID to indicate no SMMU translations (requests to be steered on the
+ * SMMU bypass path)
+ ******************************************************************************/
+#define MC_STREAM_ID_MAX			0x7FU
+
+/*******************************************************************************
+ * Memory Controller SMMU Bypass config register
+ ******************************************************************************/
+#define MC_SMMU_BYPASS_CONFIG			0x1820U
+#define MC_SMMU_BYPASS_CTRL_MASK		0x3U
+#define MC_SMMU_BYPASS_CTRL_SHIFT		0U
+#define MC_SMMU_CTRL_TBU_BYPASS_ALL		(0U << MC_SMMU_BYPASS_CTRL_SHIFT)
+#define MC_SMMU_CTRL_TBU_RSVD			(1U << MC_SMMU_BYPASS_CTRL_SHIFT)
+#define MC_SMMU_CTRL_TBU_BYPASS_SPL_STREAMID	(2U << MC_SMMU_BYPASS_CTRL_SHIFT)
+#define MC_SMMU_CTRL_TBU_BYPASS_NONE		(3U << MC_SMMU_BYPASS_CTRL_SHIFT)
+#define MC_SMMU_BYPASS_CONFIG_WRITE_ACCESS_BIT	(1U << 31)
+#define MC_SMMU_BYPASS_CONFIG_SETTINGS		(MC_SMMU_BYPASS_CONFIG_WRITE_ACCESS_BIT | \
+						 MC_SMMU_CTRL_TBU_BYPASS_SPL_STREAMID)
+
+#define mc_make_sec_cfg(off, ns, ovrrd, access) \
+	{ \
+		.name = # off, \
+		.offset = MC_STREAMID_OVERRIDE_TO_SECURITY_CFG( \
+				MC_STREAMID_OVERRIDE_CFG_ ## off), \
+		.override_client_ns_flag = CLIENT_FLAG_ ## ns, \
+		.override_client_inputs = CLIENT_INPUTS_ ## ovrrd, \
+		.override_enable = OVERRIDE_ ## access \
+	}
+
+/*******************************************************************************
+ * Structure to hold Memory Controller's Configuration settings
+ ******************************************************************************/
+typedef struct tegra_mc_settings {
+	const uint32_t *streamid_override_cfg;
+	uint32_t num_streamid_override_cfgs;
+	const mc_streamid_security_cfg_t *streamid_security_cfg;
+	uint32_t num_streamid_security_cfgs;
+	const mc_txn_override_cfg_t *txn_override_cfg;
+	uint32_t num_txn_override_cfgs;
+	void (*reconfig_mss_clients)(void);
+	void (*set_txn_overrides)(void);
+} tegra_mc_settings_t;
+
+static inline uint32_t tegra_mc_read_32(uint32_t off)
+{
+	return mmio_read_32(TEGRA_MC_BASE + off);
+}
+
+static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
+{
+	mmio_write_32(TEGRA_MC_BASE + off, val);
+}
+
+static inline uint32_t tegra_mc_streamid_read_32(uint32_t off)
+{
+	return mmio_read_32(TEGRA_MC_STREAMID_BASE + off);
+}
+
+static inline void tegra_mc_streamid_write_32(uint32_t off, uint32_t val)
+{
+	mmio_write_32(TEGRA_MC_STREAMID_BASE + off, val);
+}
+
+#define mc_set_pcfifo_unordered_boot_so_mss(id, client) \
+	((uint32_t)~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \
+	 MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_UNORDERED)
+
+#define mc_set_pcfifo_ordered_boot_so_mss(id, client) \
+	 MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_ORDERED
+
+#define mc_set_tsa_passthrough(client) \
+	{ \
+		mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \
+			(TSA_CONFIG_STATIC0_CSW_##client##_RESET & \
+			 (uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
+			(uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
+	}
+
+#define mc_set_tsa_w_passthrough(client) \
+	{ \
+		mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \
+			(TSA_CONFIG_STATIC0_CSW_RESET_W & \
+			 (uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
+			(uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
+	}
+
+#define mc_set_tsa_r_passthrough(client) \
+	{ \
+		mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSR_##client, \
+			(TSA_CONFIG_STATIC0_CSR_RESET_R & \
+			 (uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
+			(uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
+	}
+
+#define mc_set_txn_override(client, normal_axi_id, so_dev_axi_id, normal_override, so_dev_override) \
+	{ \
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_##client, \
+				  MC_TXN_OVERRIDE_##normal_axi_id | \
+				  MC_TXN_OVERRIDE_CONFIG_COH_PATH_##so_dev_override##_SO_DEV | \
+				  MC_TXN_OVERRIDE_CONFIG_COH_PATH_##normal_override##_NORMAL | \
+				  MC_TXN_OVERRIDE_CONFIG_CGID_##so_dev_axi_id); \
+	}
+
+/*******************************************************************************
+ * Handler to read memory configuration settings
+ *
+ * Implemented by SoCs under tegra/soc/txxx
+ ******************************************************************************/
+tegra_mc_settings_t *tegra_get_mc_settings(void);
+
+/*******************************************************************************
+ * Handler to program the scratch registers with TZDRAM settings for the
+ * resume firmware.
+ *
+ * Implemented by SoCs under tegra/soc/txxx
+ ******************************************************************************/
+void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* MEMCTRL_V2_H */
diff --git a/plat/nvidia/tegra/include/drivers/pmc.h b/plat/nvidia/tegra/include/drivers/pmc.h
new file mode 100644
index 0000000..32252a2
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/pmc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMC_H
+#define PMC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <stdbool.h>
+
+#include <tegra_def.h>
+
+#define PMC_CONFIG				U(0x0)
+#define PMC_IO_DPD_SAMPLE			U(0x20)
+#define PMC_DPD_ENABLE_0			U(0x24)
+#define PMC_PWRGATE_STATUS			U(0x38)
+#define PMC_PWRGATE_TOGGLE			U(0x30)
+#define PMC_SECURE_SCRATCH0			U(0xb0)
+#define PMC_SECURE_SCRATCH5			U(0xc4)
+#define PMC_CRYPTO_OP_0				U(0xf4)
+#define  PMC_TOGGLE_START			U(0x100)
+#define PMC_SCRATCH39				U(0x138)
+#define PMC_SCRATCH41 				U(0x140)
+#define PMC_SECURE_SCRATCH6			U(0x224)
+#define PMC_SECURE_SCRATCH7			U(0x228)
+#define PMC_SECURE_DISABLE2			U(0x2c4)
+#define  PMC_SECURE_DISABLE2_WRITE22_ON		(U(1) << 28)
+#define PMC_SECURE_SCRATCH8			U(0x300)
+#define PMC_SECURE_SCRATCH79			U(0x41c)
+#define PMC_FUSE_CONTROL_0			U(0x450)
+#define PMC_SECURE_SCRATCH22			U(0x338)
+#define PMC_SECURE_DISABLE3			U(0x2d8)
+#define  PMC_SECURE_DISABLE3_WRITE34_ON		(U(1) << 20)
+#define  PMC_SECURE_DISABLE3_WRITE35_ON		(U(1) << 22)
+#define PMC_SECURE_SCRATCH34			U(0x368)
+#define PMC_SECURE_SCRATCH35			U(0x36c)
+#define PMC_SECURE_SCRATCH80			U(0xa98)
+#define PMC_SECURE_SCRATCH119			U(0xb34)
+#define PMC_SCRATCH201				U(0x844)
+
+static inline uint32_t tegra_pmc_read_32(uint32_t off)
+{
+	return mmio_read_32(TEGRA_PMC_BASE + off);
+}
+
+static inline void tegra_pmc_write_32(uint32_t off, uint32_t val)
+{
+	mmio_write_32(TEGRA_PMC_BASE + off, val);
+}
+
+void tegra_pmc_cpu_on(int32_t cpu);
+void tegra_pmc_cpu_setup(uint64_t reset_addr);
+bool tegra_pmc_is_last_on_cpu(void);
+void tegra_pmc_lock_cpu_vectors(void);
+void tegra_pmc_resume(void);
+__dead2 void tegra_pmc_system_reset(void);
+
+#endif /* PMC_H */
diff --git a/plat/nvidia/tegra/include/drivers/security_engine.h b/plat/nvidia/tegra/include/drivers/security_engine.h
new file mode 100644
index 0000000..4ab2f9a
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/security_engine.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURITY_ENGINE_H
+#define SECURITY_ENGINE_H
+
+/*******************************************************************************
+ * Structure definition
+ ******************************************************************************/
+
+/* Security Engine Linked List */
+struct tegra_se_ll {
+	/* DMA buffer address */
+	uint32_t addr;
+	/* Data length in DMA buffer */
+	uint32_t data_len;
+};
+
+#define SE_LL_MAX_BUFFER_NUM			4
+typedef struct tegra_se_io_lst {
+	volatile uint32_t last_buff_num;
+	volatile struct tegra_se_ll buffer[SE_LL_MAX_BUFFER_NUM];
+} tegra_se_io_lst_t __attribute__((aligned(4)));
+
+/* SE device structure */
+typedef struct tegra_se_dev {
+	/* Security Engine ID */
+	const int se_num;
+	/* SE base address */
+	const uint64_t se_base;
+	/* SE context size in AES blocks */
+	const uint32_t ctx_size_blks;
+	/* pointer to source linked list buffer */
+	tegra_se_io_lst_t *src_ll_buf;
+	/* pointer to destination linked list buffer */
+	tegra_se_io_lst_t *dst_ll_buf;
+	/* LP context buffer pointer */
+	uint32_t *ctx_save_buf;
+} tegra_se_dev_t;
+
+/* PKA1 device structure */
+typedef struct tegra_pka_dev {
+	/* PKA1 base address */
+	uint64_t pka_base;
+} tegra_pka_dev_t;
+
+/*******************************************************************************
+ * Public interface
+ ******************************************************************************/
+void tegra_se_init(void);
+int tegra_se_suspend(void);
+void tegra_se_resume(void);
+int tegra_se_save_tzram(void);
+
+#endif /* SECURITY_ENGINE_H */
diff --git a/plat/nvidia/tegra/include/drivers/smmu.h b/plat/nvidia/tegra/include/drivers/smmu.h
new file mode 100644
index 0000000..424a91a
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/smmu.h
@@ -0,0 +1,849 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMMU_H
+#define SMMU_H
+
+#include <lib/mmio.h>
+
+#include <memctrl_v2.h>
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * SMMU Register constants
+ ******************************************************************************/
+#define SMMU_CBn_SCTLR				(0x0U)
+#define SMMU_CBn_SCTLR_STAGE2			(0x0U)
+#define SMMU_CBn_ACTLR				(0x4U)
+#define SMMU_CBn_RESUME				(0x8U)
+#define SMMU_CBn_TCR2				(0x10U)
+#define SMMU_CBn_TTBR0_LO			(0x20U)
+#define SMMU_CBn_TTBR0_HI			(0x24U)
+#define SMMU_CBn_TTBR1_LO			(0x28U)
+#define SMMU_CBn_TTBR1_HI			(0x2cU)
+#define SMMU_CBn_TCR_LPAE			(0x30U)
+#define SMMU_CBn_TCR				(0x30U)
+#define SMMU_CBn_TCR_EAE_1			(0x30U)
+#define SMMU_CBn_TCR				(0x30U)
+#define SMMU_CBn_CONTEXTIDR			(0x34U)
+#define SMMU_CBn_CONTEXTIDR_EAE_1		(0x34U)
+#define SMMU_CBn_PRRR_MAIR0			(0x38U)
+#define SMMU_CBn_NMRR_MAIR1			(0x3cU)
+#define SMMU_CBn_SMMU_CBn_PAR			(0x50U)
+#define SMMU_CBn_SMMU_CBn_PAR0			(0x50U)
+#define SMMU_CBn_SMMU_CBn_PAR1			(0x54U)
+/*      SMMU_CBn_SMMU_CBn_PAR0_Fault		(0x50U) */
+/*      SMMU_CBn_SMMU_CBn_PAR0_Fault		(0x54U) */
+#define SMMU_CBn_FSR				(0x58U)
+#define SMMU_CBn_FSRRESTORE			(0x5cU)
+#define SMMU_CBn_FAR_LO				(0x60U)
+#define SMMU_CBn_FAR_HI				(0x64U)
+#define SMMU_CBn_FSYNR0				(0x68U)
+#define SMMU_CBn_IPAFAR_LO			(0x70U)
+#define SMMU_CBn_IPAFAR_HI			(0x74U)
+#define SMMU_CBn_TLBIVA_LO			(0x600U)
+#define SMMU_CBn_TLBIVA_HI			(0x604U)
+#define SMMU_CBn_TLBIVA_AARCH_32		(0x600U)
+#define SMMU_CBn_TLBIVAA_LO			(0x608U)
+#define SMMU_CBn_TLBIVAA_HI			(0x60cU)
+#define SMMU_CBn_TLBIVAA_AARCH_32		(0x608U)
+#define SMMU_CBn_TLBIASID			(0x610U)
+#define SMMU_CBn_TLBIALL			(0x618U)
+#define SMMU_CBn_TLBIVAL_LO			(0x620U)
+#define SMMU_CBn_TLBIVAL_HI			(0x624U)
+#define SMMU_CBn_TLBIVAL_AARCH_32		(0x618U)
+#define SMMU_CBn_TLBIVAAL_LO			(0x628U)
+#define SMMU_CBn_TLBIVAAL_HI			(0x62cU)
+#define SMMU_CBn_TLBIVAAL_AARCH_32		(0x628U)
+#define SMMU_CBn_TLBIIPAS2_LO			(0x630U)
+#define SMMU_CBn_TLBIIPAS2_HI			(0x634U)
+#define SMMU_CBn_TLBIIPAS2L_LO			(0x638U)
+#define SMMU_CBn_TLBIIPAS2L_HI			(0x63cU)
+#define SMMU_CBn_TLBSYNC			(0x7f0U)
+#define SMMU_CBn_TLBSTATUS			(0x7f4U)
+#define SMMU_CBn_ATSR				(0x800U)
+#define SMMU_CBn_PMEVCNTR0			(0xe00U)
+#define SMMU_CBn_PMEVCNTR1			(0xe04U)
+#define SMMU_CBn_PMEVCNTR2			(0xe08U)
+#define SMMU_CBn_PMEVCNTR3			(0xe0cU)
+#define SMMU_CBn_PMEVTYPER0			(0xe80U)
+#define SMMU_CBn_PMEVTYPER1			(0xe84U)
+#define SMMU_CBn_PMEVTYPER2			(0xe88U)
+#define SMMU_CBn_PMEVTYPER3			(0xe8cU)
+#define SMMU_CBn_PMCFGR				(0xf00U)
+#define SMMU_CBn_PMCR				(0xf04U)
+#define SMMU_CBn_PMCEID				(0xf20U)
+#define SMMU_CBn_PMCNTENSE			(0xf40U)
+#define SMMU_CBn_PMCNTENCLR			(0xf44U)
+#define SMMU_CBn_PMCNTENSET			(0xf48U)
+#define SMMU_CBn_PMINTENCLR			(0xf4cU)
+#define SMMU_CBn_PMOVSCLR			(0xf50U)
+#define SMMU_CBn_PMOVSSET			(0xf58U)
+#define SMMU_CBn_PMAUTHSTATUS			(0xfb8U)
+#define SMMU_GNSR0_CR0				(0x0U)
+#define SMMU_GNSR0_CR2				(0x8U)
+#define SMMU_GNSR0_ACR				(0x10U)
+#define SMMU_GNSR0_IDR0				(0x20U)
+#define SMMU_GNSR0_IDR1				(0x24U)
+#define SMMU_GNSR0_IDR2				(0x28U)
+#define SMMU_GNSR0_IDR7				(0x3cU)
+#define SMMU_GNSR0_GFAR_LO			(0x40U)
+#define SMMU_GNSR0_GFAR_HI			(0x44U)
+#define SMMU_GNSR0_GFSR				(0x48U)
+#define SMMU_GNSR0_GFSRRESTORE			(0x4cU)
+#define SMMU_GNSR0_GFSYNR0			(0x50U)
+#define SMMU_GNSR0_GFSYNR1			(0x54U)
+#define SMMU_GNSR0_GFSYNR1_v2			(0x54U)
+#define SMMU_GNSR0_TLBIVMID			(0x64U)
+#define SMMU_GNSR0_TLBIALLNSNH			(0x68U)
+#define SMMU_GNSR0_TLBIALLH			(0x6cU)
+#define SMMU_GNSR0_TLBGSYNC			(0x70U)
+#define SMMU_GNSR0_TLBGSTATUS			(0x74U)
+#define SMMU_GNSR0_TLBIVAH_LO			(0x78U)
+#define SMMU_GNSR0_TLBIVALH64_LO		(0xb0U)
+#define SMMU_GNSR0_TLBIVALH64_HI		(0xb4U)
+#define SMMU_GNSR0_TLBIVMIDS1			(0xb8U)
+#define SMMU_GNSR0_TLBIVAH64_LO			(0xc0U)
+#define SMMU_GNSR0_TLBIVAH64_HI			(0xc4U)
+#define SMMU_GNSR0_SMR0				(0x800U)
+#define SMMU_GNSR0_SMRn				(0x800U)
+#define SMMU_GNSR0_SMR1				(0x804U)
+#define SMMU_GNSR0_SMR2				(0x808U)
+#define SMMU_GNSR0_SMR3				(0x80cU)
+#define SMMU_GNSR0_SMR4				(0x810U)
+#define SMMU_GNSR0_SMR5				(0x814U)
+#define SMMU_GNSR0_SMR6				(0x818U)
+#define SMMU_GNSR0_SMR7				(0x81cU)
+#define SMMU_GNSR0_SMR8				(0x820U)
+#define SMMU_GNSR0_SMR9				(0x824U)
+#define SMMU_GNSR0_SMR10			(0x828U)
+#define SMMU_GNSR0_SMR11			(0x82cU)
+#define SMMU_GNSR0_SMR12			(0x830U)
+#define SMMU_GNSR0_SMR13			(0x834U)
+#define SMMU_GNSR0_SMR14			(0x838U)
+#define SMMU_GNSR0_SMR15			(0x83cU)
+#define SMMU_GNSR0_SMR16			(0x840U)
+#define SMMU_GNSR0_SMR17			(0x844U)
+#define SMMU_GNSR0_SMR18			(0x848U)
+#define SMMU_GNSR0_SMR19			(0x84cU)
+#define SMMU_GNSR0_SMR20			(0x850U)
+#define SMMU_GNSR0_SMR21			(0x854U)
+#define SMMU_GNSR0_SMR22			(0x858U)
+#define SMMU_GNSR0_SMR23			(0x85cU)
+#define SMMU_GNSR0_SMR24			(0x860U)
+#define SMMU_GNSR0_SMR25			(0x864U)
+#define SMMU_GNSR0_SMR26			(0x868U)
+#define SMMU_GNSR0_SMR27			(0x86cU)
+#define SMMU_GNSR0_SMR28			(0x870U)
+#define SMMU_GNSR0_SMR29			(0x874U)
+#define SMMU_GNSR0_SMR30			(0x878U)
+#define SMMU_GNSR0_SMR31			(0x87cU)
+#define SMMU_GNSR0_SMR32			(0x880U)
+#define SMMU_GNSR0_SMR33			(0x884U)
+#define SMMU_GNSR0_SMR34			(0x888U)
+#define SMMU_GNSR0_SMR35			(0x88cU)
+#define SMMU_GNSR0_SMR36			(0x890U)
+#define SMMU_GNSR0_SMR37			(0x894U)
+#define SMMU_GNSR0_SMR38			(0x898U)
+#define SMMU_GNSR0_SMR39			(0x89cU)
+#define SMMU_GNSR0_SMR40			(0x8a0U)
+#define SMMU_GNSR0_SMR41			(0x8a4U)
+#define SMMU_GNSR0_SMR42			(0x8a8U)
+#define SMMU_GNSR0_SMR43			(0x8acU)
+#define SMMU_GNSR0_SMR44			(0x8b0U)
+#define SMMU_GNSR0_SMR45			(0x8b4U)
+#define SMMU_GNSR0_SMR46			(0x8b8U)
+#define SMMU_GNSR0_SMR47			(0x8bcU)
+#define SMMU_GNSR0_SMR48			(0x8c0U)
+#define SMMU_GNSR0_SMR49			(0x8c4U)
+#define SMMU_GNSR0_SMR50			(0x8c8U)
+#define SMMU_GNSR0_SMR51			(0x8ccU)
+#define SMMU_GNSR0_SMR52			(0x8d0U)
+#define SMMU_GNSR0_SMR53			(0x8d4U)
+#define SMMU_GNSR0_SMR54			(0x8d8U)
+#define SMMU_GNSR0_SMR55			(0x8dcU)
+#define SMMU_GNSR0_SMR56			(0x8e0U)
+#define SMMU_GNSR0_SMR57			(0x8e4U)
+#define SMMU_GNSR0_SMR58			(0x8e8U)
+#define SMMU_GNSR0_SMR59			(0x8ecU)
+#define SMMU_GNSR0_SMR60			(0x8f0U)
+#define SMMU_GNSR0_SMR61			(0x8f4U)
+#define SMMU_GNSR0_SMR62			(0x8f8U)
+#define SMMU_GNSR0_SMR63			(0x8fcU)
+#define SMMU_GNSR0_SMR64			(0x900U)
+#define SMMU_GNSR0_SMR65			(0x904U)
+#define SMMU_GNSR0_SMR66			(0x908U)
+#define SMMU_GNSR0_SMR67			(0x90cU)
+#define SMMU_GNSR0_SMR68			(0x910U)
+#define SMMU_GNSR0_SMR69			(0x914U)
+#define SMMU_GNSR0_SMR70			(0x918U)
+#define SMMU_GNSR0_SMR71			(0x91cU)
+#define SMMU_GNSR0_SMR72			(0x920U)
+#define SMMU_GNSR0_SMR73			(0x924U)
+#define SMMU_GNSR0_SMR74			(0x928U)
+#define SMMU_GNSR0_SMR75			(0x92cU)
+#define SMMU_GNSR0_SMR76			(0x930U)
+#define SMMU_GNSR0_SMR77			(0x934U)
+#define SMMU_GNSR0_SMR78			(0x938U)
+#define SMMU_GNSR0_SMR79			(0x93cU)
+#define SMMU_GNSR0_SMR80			(0x940U)
+#define SMMU_GNSR0_SMR81			(0x944U)
+#define SMMU_GNSR0_SMR82			(0x948U)
+#define SMMU_GNSR0_SMR83			(0x94cU)
+#define SMMU_GNSR0_SMR84			(0x950U)
+#define SMMU_GNSR0_SMR85			(0x954U)
+#define SMMU_GNSR0_SMR86			(0x958U)
+#define SMMU_GNSR0_SMR87			(0x95cU)
+#define SMMU_GNSR0_SMR88			(0x960U)
+#define SMMU_GNSR0_SMR89			(0x964U)
+#define SMMU_GNSR0_SMR90			(0x968U)
+#define SMMU_GNSR0_SMR91			(0x96cU)
+#define SMMU_GNSR0_SMR92			(0x970U)
+#define SMMU_GNSR0_SMR93			(0x974U)
+#define SMMU_GNSR0_SMR94			(0x978U)
+#define SMMU_GNSR0_SMR95			(0x97cU)
+#define SMMU_GNSR0_SMR96			(0x980U)
+#define SMMU_GNSR0_SMR97			(0x984U)
+#define SMMU_GNSR0_SMR98			(0x988U)
+#define SMMU_GNSR0_SMR99			(0x98cU)
+#define SMMU_GNSR0_SMR100			(0x990U)
+#define SMMU_GNSR0_SMR101			(0x994U)
+#define SMMU_GNSR0_SMR102			(0x998U)
+#define SMMU_GNSR0_SMR103			(0x99cU)
+#define SMMU_GNSR0_SMR104			(0x9a0U)
+#define SMMU_GNSR0_SMR105			(0x9a4U)
+#define SMMU_GNSR0_SMR106			(0x9a8U)
+#define SMMU_GNSR0_SMR107			(0x9acU)
+#define SMMU_GNSR0_SMR108			(0x9b0U)
+#define SMMU_GNSR0_SMR109			(0x9b4U)
+#define SMMU_GNSR0_SMR110			(0x9b8U)
+#define SMMU_GNSR0_SMR111			(0x9bcU)
+#define SMMU_GNSR0_SMR112			(0x9c0U)
+#define SMMU_GNSR0_SMR113			(0x9c4U)
+#define SMMU_GNSR0_SMR114			(0x9c8U)
+#define SMMU_GNSR0_SMR115			(0x9ccU)
+#define SMMU_GNSR0_SMR116			(0x9d0U)
+#define SMMU_GNSR0_SMR117			(0x9d4U)
+#define SMMU_GNSR0_SMR118			(0x9d8U)
+#define SMMU_GNSR0_SMR119			(0x9dcU)
+#define SMMU_GNSR0_SMR120			(0x9e0U)
+#define SMMU_GNSR0_SMR121			(0x9e4U)
+#define SMMU_GNSR0_SMR122			(0x9e8U)
+#define SMMU_GNSR0_SMR123			(0x9ecU)
+#define SMMU_GNSR0_SMR124			(0x9f0U)
+#define SMMU_GNSR0_SMR125			(0x9f4U)
+#define SMMU_GNSR0_SMR126			(0x9f8U)
+#define SMMU_GNSR0_SMR127			(0x9fcU)
+#define SMMU_GNSR0_S2CR0			(0xc00U)
+#define SMMU_GNSR0_S2CRn			(0xc00U)
+#define SMMU_GNSR0_S2CRn			(0xc00U)
+#define SMMU_GNSR0_S2CR1			(0xc04U)
+#define SMMU_GNSR0_S2CR2			(0xc08U)
+#define SMMU_GNSR0_S2CR3			(0xc0cU)
+#define SMMU_GNSR0_S2CR4			(0xc10U)
+#define SMMU_GNSR0_S2CR5			(0xc14U)
+#define SMMU_GNSR0_S2CR6			(0xc18U)
+#define SMMU_GNSR0_S2CR7			(0xc1cU)
+#define SMMU_GNSR0_S2CR8			(0xc20U)
+#define SMMU_GNSR0_S2CR9			(0xc24U)
+#define SMMU_GNSR0_S2CR10			(0xc28U)
+#define SMMU_GNSR0_S2CR11			(0xc2cU)
+#define SMMU_GNSR0_S2CR12			(0xc30U)
+#define SMMU_GNSR0_S2CR13			(0xc34U)
+#define SMMU_GNSR0_S2CR14			(0xc38U)
+#define SMMU_GNSR0_S2CR15			(0xc3cU)
+#define SMMU_GNSR0_S2CR16			(0xc40U)
+#define SMMU_GNSR0_S2CR17			(0xc44U)
+#define SMMU_GNSR0_S2CR18			(0xc48U)
+#define SMMU_GNSR0_S2CR19			(0xc4cU)
+#define SMMU_GNSR0_S2CR20			(0xc50U)
+#define SMMU_GNSR0_S2CR21			(0xc54U)
+#define SMMU_GNSR0_S2CR22			(0xc58U)
+#define SMMU_GNSR0_S2CR23			(0xc5cU)
+#define SMMU_GNSR0_S2CR24			(0xc60U)
+#define SMMU_GNSR0_S2CR25			(0xc64U)
+#define SMMU_GNSR0_S2CR26			(0xc68U)
+#define SMMU_GNSR0_S2CR27			(0xc6cU)
+#define SMMU_GNSR0_S2CR28			(0xc70U)
+#define SMMU_GNSR0_S2CR29			(0xc74U)
+#define SMMU_GNSR0_S2CR30			(0xc78U)
+#define SMMU_GNSR0_S2CR31			(0xc7cU)
+#define SMMU_GNSR0_S2CR32			(0xc80U)
+#define SMMU_GNSR0_S2CR33			(0xc84U)
+#define SMMU_GNSR0_S2CR34			(0xc88U)
+#define SMMU_GNSR0_S2CR35			(0xc8cU)
+#define SMMU_GNSR0_S2CR36			(0xc90U)
+#define SMMU_GNSR0_S2CR37			(0xc94U)
+#define SMMU_GNSR0_S2CR38			(0xc98U)
+#define SMMU_GNSR0_S2CR39			(0xc9cU)
+#define SMMU_GNSR0_S2CR40			(0xca0U)
+#define SMMU_GNSR0_S2CR41			(0xca4U)
+#define SMMU_GNSR0_S2CR42			(0xca8U)
+#define SMMU_GNSR0_S2CR43			(0xcacU)
+#define SMMU_GNSR0_S2CR44			(0xcb0U)
+#define SMMU_GNSR0_S2CR45			(0xcb4U)
+#define SMMU_GNSR0_S2CR46			(0xcb8U)
+#define SMMU_GNSR0_S2CR47			(0xcbcU)
+#define SMMU_GNSR0_S2CR48			(0xcc0U)
+#define SMMU_GNSR0_S2CR49			(0xcc4U)
+#define SMMU_GNSR0_S2CR50			(0xcc8U)
+#define SMMU_GNSR0_S2CR51			(0xcccU)
+#define SMMU_GNSR0_S2CR52			(0xcd0U)
+#define SMMU_GNSR0_S2CR53			(0xcd4U)
+#define SMMU_GNSR0_S2CR54			(0xcd8U)
+#define SMMU_GNSR0_S2CR55			(0xcdcU)
+#define SMMU_GNSR0_S2CR56			(0xce0U)
+#define SMMU_GNSR0_S2CR57			(0xce4U)
+#define SMMU_GNSR0_S2CR58			(0xce8U)
+#define SMMU_GNSR0_S2CR59			(0xcecU)
+#define SMMU_GNSR0_S2CR60			(0xcf0U)
+#define SMMU_GNSR0_S2CR61			(0xcf4U)
+#define SMMU_GNSR0_S2CR62			(0xcf8U)
+#define SMMU_GNSR0_S2CR63			(0xcfcU)
+#define SMMU_GNSR0_S2CR64			(0xd00U)
+#define SMMU_GNSR0_S2CR65			(0xd04U)
+#define SMMU_GNSR0_S2CR66			(0xd08U)
+#define SMMU_GNSR0_S2CR67			(0xd0cU)
+#define SMMU_GNSR0_S2CR68			(0xd10U)
+#define SMMU_GNSR0_S2CR69			(0xd14U)
+#define SMMU_GNSR0_S2CR70			(0xd18U)
+#define SMMU_GNSR0_S2CR71			(0xd1cU)
+#define SMMU_GNSR0_S2CR72			(0xd20U)
+#define SMMU_GNSR0_S2CR73			(0xd24U)
+#define SMMU_GNSR0_S2CR74			(0xd28U)
+#define SMMU_GNSR0_S2CR75			(0xd2cU)
+#define SMMU_GNSR0_S2CR76			(0xd30U)
+#define SMMU_GNSR0_S2CR77			(0xd34U)
+#define SMMU_GNSR0_S2CR78			(0xd38U)
+#define SMMU_GNSR0_S2CR79			(0xd3cU)
+#define SMMU_GNSR0_S2CR80			(0xd40U)
+#define SMMU_GNSR0_S2CR81			(0xd44U)
+#define SMMU_GNSR0_S2CR82			(0xd48U)
+#define SMMU_GNSR0_S2CR83			(0xd4cU)
+#define SMMU_GNSR0_S2CR84			(0xd50U)
+#define SMMU_GNSR0_S2CR85			(0xd54U)
+#define SMMU_GNSR0_S2CR86			(0xd58U)
+#define SMMU_GNSR0_S2CR87			(0xd5cU)
+#define SMMU_GNSR0_S2CR88			(0xd60U)
+#define SMMU_GNSR0_S2CR89			(0xd64U)
+#define SMMU_GNSR0_S2CR90			(0xd68U)
+#define SMMU_GNSR0_S2CR91			(0xd6cU)
+#define SMMU_GNSR0_S2CR92			(0xd70U)
+#define SMMU_GNSR0_S2CR93			(0xd74U)
+#define SMMU_GNSR0_S2CR94			(0xd78U)
+#define SMMU_GNSR0_S2CR95			(0xd7cU)
+#define SMMU_GNSR0_S2CR96			(0xd80U)
+#define SMMU_GNSR0_S2CR97			(0xd84U)
+#define SMMU_GNSR0_S2CR98			(0xd88U)
+#define SMMU_GNSR0_S2CR99			(0xd8cU)
+#define SMMU_GNSR0_S2CR100			(0xd90U)
+#define SMMU_GNSR0_S2CR101			(0xd94U)
+#define SMMU_GNSR0_S2CR102			(0xd98U)
+#define SMMU_GNSR0_S2CR103			(0xd9cU)
+#define SMMU_GNSR0_S2CR104			(0xda0U)
+#define SMMU_GNSR0_S2CR105			(0xda4U)
+#define SMMU_GNSR0_S2CR106			(0xda8U)
+#define SMMU_GNSR0_S2CR107			(0xdacU)
+#define SMMU_GNSR0_S2CR108			(0xdb0U)
+#define SMMU_GNSR0_S2CR109			(0xdb4U)
+#define SMMU_GNSR0_S2CR110			(0xdb8U)
+#define SMMU_GNSR0_S2CR111			(0xdbcU)
+#define SMMU_GNSR0_S2CR112			(0xdc0U)
+#define SMMU_GNSR0_S2CR113			(0xdc4U)
+#define SMMU_GNSR0_S2CR114			(0xdc8U)
+#define SMMU_GNSR0_S2CR115			(0xdccU)
+#define SMMU_GNSR0_S2CR116			(0xdd0U)
+#define SMMU_GNSR0_S2CR117			(0xdd4U)
+#define SMMU_GNSR0_S2CR118			(0xdd8U)
+#define SMMU_GNSR0_S2CR119			(0xddcU)
+#define SMMU_GNSR0_S2CR120			(0xde0U)
+#define SMMU_GNSR0_S2CR121			(0xde4U)
+#define SMMU_GNSR0_S2CR122			(0xde8U)
+#define SMMU_GNSR0_S2CR123			(0xdecU)
+#define SMMU_GNSR0_S2CR124			(0xdf0U)
+#define SMMU_GNSR0_S2CR125			(0xdf4U)
+#define SMMU_GNSR0_S2CR126			(0xdf8U)
+#define SMMU_GNSR0_S2CR127			(0xdfcU)
+#define SMMU_GNSR0_PIDR0			(0xfe0U)
+#define SMMU_GNSR0_PIDR1			(0xfe4U)
+#define SMMU_GNSR0_PIDR2			(0xfe8U)
+#define SMMU_GNSR0_PIDR3			(0xfecU)
+#define SMMU_GNSR0_PIDR4			(0xfd0U)
+#define SMMU_GNSR0_PIDR5			(0xfd4U)
+#define SMMU_GNSR0_PIDR6			(0xfd8U)
+#define SMMU_GNSR0_PIDR7			(0xfdcU)
+#define SMMU_GNSR0_CIDR0			(0xff0U)
+#define SMMU_GNSR0_CIDR1			(0xff4U)
+#define SMMU_GNSR0_CIDR2			(0xff8U)
+#define SMMU_GNSR0_CIDR3			(0xffcU)
+#define SMMU_GNSR1_CBAR0			(0x0U)
+#define SMMU_GNSR1_CBARn			(0x0U)
+#define SMMU_GNSR1_CBFRSYNRA0			(0x400U)
+#define SMMU_GNSR1_CBA2R0			(0x800U)
+#define SMMU_GNSR1_CBAR1			(0x4U)
+#define SMMU_GNSR1_CBFRSYNRA1			(0x404U)
+#define SMMU_GNSR1_CBA2R1			(0x804U)
+#define SMMU_GNSR1_CBAR2			(0x8U)
+#define SMMU_GNSR1_CBFRSYNRA2			(0x408U)
+#define SMMU_GNSR1_CBA2R2			(0x808U)
+#define SMMU_GNSR1_CBAR3			(0xcU)
+#define SMMU_GNSR1_CBFRSYNRA3			(0x40cU)
+#define SMMU_GNSR1_CBA2R3			(0x80cU)
+#define SMMU_GNSR1_CBAR4			(0x10U)
+#define SMMU_GNSR1_CBFRSYNRA4			(0x410U)
+#define SMMU_GNSR1_CBA2R4			(0x810U)
+#define SMMU_GNSR1_CBAR5			(0x14U)
+#define SMMU_GNSR1_CBFRSYNRA5			(0x414U)
+#define SMMU_GNSR1_CBA2R5			(0x814U)
+#define SMMU_GNSR1_CBAR6			(0x18U)
+#define SMMU_GNSR1_CBFRSYNRA6			(0x418U)
+#define SMMU_GNSR1_CBA2R6			(0x818U)
+#define SMMU_GNSR1_CBAR7			(0x1cU)
+#define SMMU_GNSR1_CBFRSYNRA7			(0x41cU)
+#define SMMU_GNSR1_CBA2R7			(0x81cU)
+#define SMMU_GNSR1_CBAR8			(0x20U)
+#define SMMU_GNSR1_CBFRSYNRA8			(0x420U)
+#define SMMU_GNSR1_CBA2R8			(0x820U)
+#define SMMU_GNSR1_CBAR9			(0x24U)
+#define SMMU_GNSR1_CBFRSYNRA9			(0x424U)
+#define SMMU_GNSR1_CBA2R9			(0x824U)
+#define SMMU_GNSR1_CBAR10			(0x28U)
+#define SMMU_GNSR1_CBFRSYNRA10			(0x428U)
+#define SMMU_GNSR1_CBA2R10			(0x828U)
+#define SMMU_GNSR1_CBAR11			(0x2cU)
+#define SMMU_GNSR1_CBFRSYNRA11			(0x42cU)
+#define SMMU_GNSR1_CBA2R11			(0x82cU)
+#define SMMU_GNSR1_CBAR12			(0x30U)
+#define SMMU_GNSR1_CBFRSYNRA12			(0x430U)
+#define SMMU_GNSR1_CBA2R12			(0x830U)
+#define SMMU_GNSR1_CBAR13			(0x34U)
+#define SMMU_GNSR1_CBFRSYNRA13			(0x434U)
+#define SMMU_GNSR1_CBA2R13			(0x834U)
+#define SMMU_GNSR1_CBAR14			(0x38U)
+#define SMMU_GNSR1_CBFRSYNRA14			(0x438U)
+#define SMMU_GNSR1_CBA2R14			(0x838U)
+#define SMMU_GNSR1_CBAR15			(0x3cU)
+#define SMMU_GNSR1_CBFRSYNRA15			(0x43cU)
+#define SMMU_GNSR1_CBA2R15			(0x83cU)
+#define SMMU_GNSR1_CBAR16			(0x40U)
+#define SMMU_GNSR1_CBFRSYNRA16			(0x440U)
+#define SMMU_GNSR1_CBA2R16			(0x840U)
+#define SMMU_GNSR1_CBAR17			(0x44U)
+#define SMMU_GNSR1_CBFRSYNRA17			(0x444U)
+#define SMMU_GNSR1_CBA2R17			(0x844U)
+#define SMMU_GNSR1_CBAR18			(0x48U)
+#define SMMU_GNSR1_CBFRSYNRA18			(0x448U)
+#define SMMU_GNSR1_CBA2R18			(0x848U)
+#define SMMU_GNSR1_CBAR19			(0x4cU)
+#define SMMU_GNSR1_CBFRSYNRA19			(0x44cU)
+#define SMMU_GNSR1_CBA2R19			(0x84cU)
+#define SMMU_GNSR1_CBAR20			(0x50U)
+#define SMMU_GNSR1_CBFRSYNRA20			(0x450U)
+#define SMMU_GNSR1_CBA2R20			(0x850U)
+#define SMMU_GNSR1_CBAR21			(0x54U)
+#define SMMU_GNSR1_CBFRSYNRA21			(0x454U)
+#define SMMU_GNSR1_CBA2R21			(0x854U)
+#define SMMU_GNSR1_CBAR22			(0x58U)
+#define SMMU_GNSR1_CBFRSYNRA22			(0x458U)
+#define SMMU_GNSR1_CBA2R22			(0x858U)
+#define SMMU_GNSR1_CBAR23			(0x5cU)
+#define SMMU_GNSR1_CBFRSYNRA23			(0x45cU)
+#define SMMU_GNSR1_CBA2R23			(0x85cU)
+#define SMMU_GNSR1_CBAR24			(0x60U)
+#define SMMU_GNSR1_CBFRSYNRA24			(0x460U)
+#define SMMU_GNSR1_CBA2R24			(0x860U)
+#define SMMU_GNSR1_CBAR25			(0x64U)
+#define SMMU_GNSR1_CBFRSYNRA25			(0x464U)
+#define SMMU_GNSR1_CBA2R25			(0x864U)
+#define SMMU_GNSR1_CBAR26			(0x68U)
+#define SMMU_GNSR1_CBFRSYNRA26			(0x468U)
+#define SMMU_GNSR1_CBA2R26			(0x868U)
+#define SMMU_GNSR1_CBAR27			(0x6cU)
+#define SMMU_GNSR1_CBFRSYNRA27			(0x46cU)
+#define SMMU_GNSR1_CBA2R27			(0x86cU)
+#define SMMU_GNSR1_CBAR28			(0x70U)
+#define SMMU_GNSR1_CBFRSYNRA28			(0x470U)
+#define SMMU_GNSR1_CBA2R28			(0x870U)
+#define SMMU_GNSR1_CBAR29			(0x74U)
+#define SMMU_GNSR1_CBFRSYNRA29			(0x474U)
+#define SMMU_GNSR1_CBA2R29			(0x874U)
+#define SMMU_GNSR1_CBAR30			(0x78U)
+#define SMMU_GNSR1_CBFRSYNRA30			(0x478U)
+#define SMMU_GNSR1_CBA2R30			(0x878U)
+#define SMMU_GNSR1_CBAR31			(0x7cU)
+#define SMMU_GNSR1_CBFRSYNRA31			(0x47cU)
+#define SMMU_GNSR1_CBA2R31			(0x87cU)
+#define SMMU_GNSR1_CBAR32			(0x80U)
+#define SMMU_GNSR1_CBFRSYNRA32			(0x480U)
+#define SMMU_GNSR1_CBA2R32			(0x880U)
+#define SMMU_GNSR1_CBAR33			(0x84U)
+#define SMMU_GNSR1_CBFRSYNRA33			(0x484U)
+#define SMMU_GNSR1_CBA2R33			(0x884U)
+#define SMMU_GNSR1_CBAR34			(0x88U)
+#define SMMU_GNSR1_CBFRSYNRA34			(0x488U)
+#define SMMU_GNSR1_CBA2R34			(0x888U)
+#define SMMU_GNSR1_CBAR35			(0x8cU)
+#define SMMU_GNSR1_CBFRSYNRA35			(0x48cU)
+#define SMMU_GNSR1_CBA2R35			(0x88cU)
+#define SMMU_GNSR1_CBAR36			(0x90U)
+#define SMMU_GNSR1_CBFRSYNRA36			(0x490U)
+#define SMMU_GNSR1_CBA2R36			(0x890U)
+#define SMMU_GNSR1_CBAR37			(0x94U)
+#define SMMU_GNSR1_CBFRSYNRA37			(0x494U)
+#define SMMU_GNSR1_CBA2R37			(0x894U)
+#define SMMU_GNSR1_CBAR38			(0x98U)
+#define SMMU_GNSR1_CBFRSYNRA38			(0x498U)
+#define SMMU_GNSR1_CBA2R38			(0x898U)
+#define SMMU_GNSR1_CBAR39			(0x9cU)
+#define SMMU_GNSR1_CBFRSYNRA39			(0x49cU)
+#define SMMU_GNSR1_CBA2R39			(0x89cU)
+#define SMMU_GNSR1_CBAR40			(0xa0U)
+#define SMMU_GNSR1_CBFRSYNRA40			(0x4a0U)
+#define SMMU_GNSR1_CBA2R40			(0x8a0U)
+#define SMMU_GNSR1_CBAR41			(0xa4U)
+#define SMMU_GNSR1_CBFRSYNRA41			(0x4a4U)
+#define SMMU_GNSR1_CBA2R41			(0x8a4U)
+#define SMMU_GNSR1_CBAR42			(0xa8U)
+#define SMMU_GNSR1_CBFRSYNRA42			(0x4a8U)
+#define SMMU_GNSR1_CBA2R42			(0x8a8U)
+#define SMMU_GNSR1_CBAR43			(0xacU)
+#define SMMU_GNSR1_CBFRSYNRA43			(0x4acU)
+#define SMMU_GNSR1_CBA2R43			(0x8acU)
+#define SMMU_GNSR1_CBAR44			(0xb0U)
+#define SMMU_GNSR1_CBFRSYNRA44			(0x4b0U)
+#define SMMU_GNSR1_CBA2R44			(0x8b0U)
+#define SMMU_GNSR1_CBAR45			(0xb4U)
+#define SMMU_GNSR1_CBFRSYNRA45			(0x4b4U)
+#define SMMU_GNSR1_CBA2R45			(0x8b4U)
+#define SMMU_GNSR1_CBAR46			(0xb8U)
+#define SMMU_GNSR1_CBFRSYNRA46			(0x4b8U)
+#define SMMU_GNSR1_CBA2R46			(0x8b8U)
+#define SMMU_GNSR1_CBAR47			(0xbcU)
+#define SMMU_GNSR1_CBFRSYNRA47			(0x4bcU)
+#define SMMU_GNSR1_CBA2R47			(0x8bcU)
+#define SMMU_GNSR1_CBAR48			(0xc0U)
+#define SMMU_GNSR1_CBFRSYNRA48			(0x4c0U)
+#define SMMU_GNSR1_CBA2R48			(0x8c0U)
+#define SMMU_GNSR1_CBAR49			(0xc4U)
+#define SMMU_GNSR1_CBFRSYNRA49			(0x4c4U)
+#define SMMU_GNSR1_CBA2R49			(0x8c4U)
+#define SMMU_GNSR1_CBAR50			(0xc8U)
+#define SMMU_GNSR1_CBFRSYNRA50			(0x4c8U)
+#define SMMU_GNSR1_CBA2R50			(0x8c8U)
+#define SMMU_GNSR1_CBAR51			(0xccU)
+#define SMMU_GNSR1_CBFRSYNRA51			(0x4ccU)
+#define SMMU_GNSR1_CBA2R51			(0x8ccU)
+#define SMMU_GNSR1_CBAR52			(0xd0U)
+#define SMMU_GNSR1_CBFRSYNRA52			(0x4d0U)
+#define SMMU_GNSR1_CBA2R52			(0x8d0U)
+#define SMMU_GNSR1_CBAR53			(0xd4U)
+#define SMMU_GNSR1_CBFRSYNRA53			(0x4d4U)
+#define SMMU_GNSR1_CBA2R53			(0x8d4U)
+#define SMMU_GNSR1_CBAR54			(0xd8U)
+#define SMMU_GNSR1_CBFRSYNRA54			(0x4d8U)
+#define SMMU_GNSR1_CBA2R54			(0x8d8U)
+#define SMMU_GNSR1_CBAR55			(0xdcU)
+#define SMMU_GNSR1_CBFRSYNRA55			(0x4dcU)
+#define SMMU_GNSR1_CBA2R55			(0x8dcU)
+#define SMMU_GNSR1_CBAR56			(0xe0U)
+#define SMMU_GNSR1_CBFRSYNRA56			(0x4e0U)
+#define SMMU_GNSR1_CBA2R56			(0x8e0U)
+#define SMMU_GNSR1_CBAR57			(0xe4U)
+#define SMMU_GNSR1_CBFRSYNRA57			(0x4e4U)
+#define SMMU_GNSR1_CBA2R57			(0x8e4U)
+#define SMMU_GNSR1_CBAR58			(0xe8U)
+#define SMMU_GNSR1_CBFRSYNRA58			(0x4e8U)
+#define SMMU_GNSR1_CBA2R58			(0x8e8U)
+#define SMMU_GNSR1_CBAR59			(0xecU)
+#define SMMU_GNSR1_CBFRSYNRA59			(0x4ecU)
+#define SMMU_GNSR1_CBA2R59			(0x8ecU)
+#define SMMU_GNSR1_CBAR60			(0xf0U)
+#define SMMU_GNSR1_CBFRSYNRA60			(0x4f0U)
+#define SMMU_GNSR1_CBA2R60			(0x8f0U)
+#define SMMU_GNSR1_CBAR61			(0xf4U)
+#define SMMU_GNSR1_CBFRSYNRA61			(0x4f4U)
+#define SMMU_GNSR1_CBA2R61			(0x8f4U)
+#define SMMU_GNSR1_CBAR62			(0xf8U)
+#define SMMU_GNSR1_CBFRSYNRA62			(0x4f8U)
+#define SMMU_GNSR1_CBA2R62			(0x8f8U)
+#define SMMU_GNSR1_CBAR63			(0xfcU)
+#define SMMU_GNSR1_CBFRSYNRA63			(0x4fcU)
+#define SMMU_GNSR1_CBA2R63			(0x8fcU)
+
+/*******************************************************************************
+ * SMMU Global Secure Aux. Configuration Register
+ ******************************************************************************/
+#define SMMU_GSR0_SECURE_ACR			0x10U
+#define SMMU_GNSR_ACR				(SMMU_GSR0_SECURE_ACR + 0x400U)
+#define SMMU_GSR0_PGSIZE_SHIFT			16U
+#define SMMU_GSR0_PGSIZE_4K			(0U << SMMU_GSR0_PGSIZE_SHIFT)
+#define SMMU_GSR0_PGSIZE_64K			(1U << SMMU_GSR0_PGSIZE_SHIFT)
+#define SMMU_ACR_CACHE_LOCK_ENABLE_BIT		(1U << 26)
+
+/*******************************************************************************
+ * SMMU Global Aux. Control Register
+ ******************************************************************************/
+#define SMMU_CBn_ACTLR_CPRE_BIT			(1ULL << 1U)
+
+/*******************************************************************************
+ * SMMU configuration constants
+ ******************************************************************************/
+#define ID1_PAGESIZE				(1U << 31U)
+#define ID1_NUMPAGENDXB_SHIFT			28U
+#define ID1_NUMPAGENDXB_MASK			7U
+#define ID1_NUMS2CB_SHIFT			16U
+#define ID1_NUMS2CB_MASK			0xffU
+#define ID1_NUMCB_SHIFT				0U
+#define ID1_NUMCB_MASK				0xffU
+#define PGSHIFT					16U
+#define CB_SIZE					0x800000U
+
+typedef struct smmu_regs {
+	uint32_t reg;
+	uint32_t val;
+} smmu_regs_t;
+
+#define mc_make_sid_override_cfg(name) \
+	{ \
+		.reg = TEGRA_MC_STREAMID_BASE + MC_STREAMID_OVERRIDE_CFG_ ## name, \
+		.val = 0x00000000U, \
+	}
+
+#define mc_make_sid_security_cfg(name) \
+	{ \
+		.reg = TEGRA_MC_STREAMID_BASE + MC_STREAMID_OVERRIDE_TO_SECURITY_CFG(MC_STREAMID_OVERRIDE_CFG_ ## name), \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_gnsr0_sec_cfg(base_addr, name) \
+	{ \
+		.reg = base_addr + SMMU_GNSR0_ ## name, \
+		.val = 0x00000000U, \
+	}
+
+/*
+ * On ARM-SMMU, conditional offset to access secure aliases of non-secure registers
+ * is 0x400. So, add it to register address
+ */
+#define smmu_make_gnsr0_nsec_cfg(base_addr, name) \
+	{ \
+		.reg = base_addr + 0x400U + SMMU_GNSR0_ ## name, \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_gnsr0_smr_cfg(base_addr, n) \
+	{ \
+		.reg = base_addr + SMMU_GNSR0_SMR ## n, \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_gnsr0_s2cr_cfg(base_addr, n) \
+	{ \
+		.reg = base_addr + SMMU_GNSR0_S2CR ## n, \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_gnsr1_cbar_cfg(base_addr, n) \
+	{ \
+		.reg = base_addr + (1U << PGSHIFT) + SMMU_GNSR1_CBAR ## n, \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_gnsr1_cba2r_cfg(base_addr, n) \
+	{ \
+		.reg = base_addr + (1U << PGSHIFT) + SMMU_GNSR1_CBA2R ## n, \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_cb_cfg(base_addr, name, n) \
+	{ \
+		.reg = base_addr + (CB_SIZE >> 1) + (n * (1 << PGSHIFT)) \
+			+ SMMU_CBn_ ## name, \
+		.val = 0x00000000U, \
+	}
+
+#define smmu_make_smrg_group(base_addr, n)	\
+	smmu_make_gnsr0_smr_cfg(base_addr, n),	\
+	smmu_make_gnsr0_s2cr_cfg(base_addr, n),	\
+	smmu_make_gnsr1_cbar_cfg(base_addr, n),	\
+	smmu_make_gnsr1_cba2r_cfg(base_addr, n)	/* don't put "," here. */
+
+#define smmu_make_cb_group(base_addr, n)		\
+	smmu_make_cb_cfg(base_addr, SCTLR, n),	\
+	smmu_make_cb_cfg(base_addr, TCR2, n),	\
+	smmu_make_cb_cfg(base_addr, TTBR0_LO, n),	\
+	smmu_make_cb_cfg(base_addr, TTBR0_HI, n),	\
+	smmu_make_cb_cfg(base_addr, TCR, n),	\
+	smmu_make_cb_cfg(base_addr, PRRR_MAIR0, n),\
+	smmu_make_cb_cfg(base_addr, FSR, n),	\
+	smmu_make_cb_cfg(base_addr, FAR_LO, n),	\
+	smmu_make_cb_cfg(base_addr, FAR_HI, n),	\
+	smmu_make_cb_cfg(base_addr, FSYNR0, n)	/* don't put "," here. */
+
+#define smmu_make_cfg(base_addr)			\
+	smmu_make_gnsr0_nsec_cfg(base_addr, CR0),	\
+	smmu_make_gnsr0_sec_cfg(base_addr, IDR0),	\
+	smmu_make_gnsr0_sec_cfg(base_addr, IDR1),	\
+	smmu_make_gnsr0_sec_cfg(base_addr, IDR2),	\
+	smmu_make_gnsr0_nsec_cfg(base_addr, GFSR),	\
+	smmu_make_gnsr0_nsec_cfg(base_addr, GFSYNR0),	\
+	smmu_make_gnsr0_nsec_cfg(base_addr, GFSYNR1),	\
+	smmu_make_gnsr0_nsec_cfg(base_addr, TLBGSTATUS),\
+	smmu_make_gnsr0_nsec_cfg(base_addr, PIDR2),	\
+	smmu_make_smrg_group(base_addr, 0),		\
+	smmu_make_smrg_group(base_addr, 1),		\
+	smmu_make_smrg_group(base_addr, 2),		\
+	smmu_make_smrg_group(base_addr, 3),		\
+	smmu_make_smrg_group(base_addr, 4),		\
+	smmu_make_smrg_group(base_addr, 5),		\
+	smmu_make_smrg_group(base_addr, 6),		\
+	smmu_make_smrg_group(base_addr, 7),		\
+	smmu_make_smrg_group(base_addr, 8),		\
+	smmu_make_smrg_group(base_addr, 9),		\
+	smmu_make_smrg_group(base_addr, 10),		\
+	smmu_make_smrg_group(base_addr, 11),		\
+	smmu_make_smrg_group(base_addr, 12),		\
+	smmu_make_smrg_group(base_addr, 13),		\
+	smmu_make_smrg_group(base_addr, 14),		\
+	smmu_make_smrg_group(base_addr, 15),		\
+	smmu_make_smrg_group(base_addr, 16),		\
+	smmu_make_smrg_group(base_addr, 17),		\
+	smmu_make_smrg_group(base_addr, 18),		\
+	smmu_make_smrg_group(base_addr, 19),		\
+	smmu_make_smrg_group(base_addr, 20),		\
+	smmu_make_smrg_group(base_addr, 21),		\
+	smmu_make_smrg_group(base_addr, 22),		\
+	smmu_make_smrg_group(base_addr, 23),		\
+	smmu_make_smrg_group(base_addr, 24),		\
+	smmu_make_smrg_group(base_addr, 25),		\
+	smmu_make_smrg_group(base_addr, 26),		\
+	smmu_make_smrg_group(base_addr, 27),		\
+	smmu_make_smrg_group(base_addr, 28),		\
+	smmu_make_smrg_group(base_addr, 29),		\
+	smmu_make_smrg_group(base_addr, 30),		\
+	smmu_make_smrg_group(base_addr, 31),		\
+	smmu_make_smrg_group(base_addr, 32),		\
+	smmu_make_smrg_group(base_addr, 33),		\
+	smmu_make_smrg_group(base_addr, 34),		\
+	smmu_make_smrg_group(base_addr, 35),		\
+	smmu_make_smrg_group(base_addr, 36),		\
+	smmu_make_smrg_group(base_addr, 37),		\
+	smmu_make_smrg_group(base_addr, 38),		\
+	smmu_make_smrg_group(base_addr, 39),		\
+	smmu_make_smrg_group(base_addr, 40),		\
+	smmu_make_smrg_group(base_addr, 41),		\
+	smmu_make_smrg_group(base_addr, 42),		\
+	smmu_make_smrg_group(base_addr, 43),		\
+	smmu_make_smrg_group(base_addr, 44),		\
+	smmu_make_smrg_group(base_addr, 45),		\
+	smmu_make_smrg_group(base_addr, 46),		\
+	smmu_make_smrg_group(base_addr, 47),		\
+	smmu_make_smrg_group(base_addr, 48),		\
+	smmu_make_smrg_group(base_addr, 49),		\
+	smmu_make_smrg_group(base_addr, 50),		\
+	smmu_make_smrg_group(base_addr, 51),		\
+	smmu_make_smrg_group(base_addr, 52),		\
+	smmu_make_smrg_group(base_addr, 53),		\
+	smmu_make_smrg_group(base_addr, 54),		\
+	smmu_make_smrg_group(base_addr, 55),		\
+	smmu_make_smrg_group(base_addr, 56),		\
+	smmu_make_smrg_group(base_addr, 57),		\
+	smmu_make_smrg_group(base_addr, 58),		\
+	smmu_make_smrg_group(base_addr, 59),		\
+	smmu_make_smrg_group(base_addr, 60),		\
+	smmu_make_smrg_group(base_addr, 61),		\
+	smmu_make_smrg_group(base_addr, 62),		\
+	smmu_make_smrg_group(base_addr, 63),		\
+	smmu_make_cb_group(base_addr, 0),		\
+	smmu_make_cb_group(base_addr, 1),		\
+	smmu_make_cb_group(base_addr, 2),		\
+	smmu_make_cb_group(base_addr, 3),		\
+	smmu_make_cb_group(base_addr, 4),		\
+	smmu_make_cb_group(base_addr, 5),		\
+	smmu_make_cb_group(base_addr, 6),		\
+	smmu_make_cb_group(base_addr, 7),		\
+	smmu_make_cb_group(base_addr, 8),		\
+	smmu_make_cb_group(base_addr, 9),		\
+	smmu_make_cb_group(base_addr, 10),		\
+	smmu_make_cb_group(base_addr, 11),		\
+	smmu_make_cb_group(base_addr, 12),		\
+	smmu_make_cb_group(base_addr, 13),		\
+	smmu_make_cb_group(base_addr, 14),		\
+	smmu_make_cb_group(base_addr, 15),		\
+	smmu_make_cb_group(base_addr, 16),		\
+	smmu_make_cb_group(base_addr, 17),		\
+	smmu_make_cb_group(base_addr, 18),		\
+	smmu_make_cb_group(base_addr, 19),		\
+	smmu_make_cb_group(base_addr, 20),		\
+	smmu_make_cb_group(base_addr, 21),		\
+	smmu_make_cb_group(base_addr, 22),		\
+	smmu_make_cb_group(base_addr, 23),		\
+	smmu_make_cb_group(base_addr, 24),		\
+	smmu_make_cb_group(base_addr, 25),		\
+	smmu_make_cb_group(base_addr, 26),		\
+	smmu_make_cb_group(base_addr, 27),		\
+	smmu_make_cb_group(base_addr, 28),		\
+	smmu_make_cb_group(base_addr, 29),		\
+	smmu_make_cb_group(base_addr, 30),		\
+	smmu_make_cb_group(base_addr, 31),		\
+	smmu_make_cb_group(base_addr, 32),		\
+	smmu_make_cb_group(base_addr, 33),		\
+	smmu_make_cb_group(base_addr, 34),		\
+	smmu_make_cb_group(base_addr, 35),		\
+	smmu_make_cb_group(base_addr, 36),		\
+	smmu_make_cb_group(base_addr, 37),		\
+	smmu_make_cb_group(base_addr, 38),		\
+	smmu_make_cb_group(base_addr, 39),		\
+	smmu_make_cb_group(base_addr, 40),		\
+	smmu_make_cb_group(base_addr, 41),		\
+	smmu_make_cb_group(base_addr, 42),		\
+	smmu_make_cb_group(base_addr, 43),		\
+	smmu_make_cb_group(base_addr, 44),		\
+	smmu_make_cb_group(base_addr, 45),		\
+	smmu_make_cb_group(base_addr, 46),		\
+	smmu_make_cb_group(base_addr, 47),		\
+	smmu_make_cb_group(base_addr, 48),		\
+	smmu_make_cb_group(base_addr, 49),		\
+	smmu_make_cb_group(base_addr, 50),		\
+	smmu_make_cb_group(base_addr, 51),		\
+	smmu_make_cb_group(base_addr, 52),		\
+	smmu_make_cb_group(base_addr, 53),		\
+	smmu_make_cb_group(base_addr, 54),		\
+	smmu_make_cb_group(base_addr, 55),		\
+	smmu_make_cb_group(base_addr, 56),		\
+	smmu_make_cb_group(base_addr, 57),		\
+	smmu_make_cb_group(base_addr, 58),		\
+	smmu_make_cb_group(base_addr, 59),		\
+	smmu_make_cb_group(base_addr, 60),		\
+	smmu_make_cb_group(base_addr, 61),		\
+	smmu_make_cb_group(base_addr, 62),		\
+	smmu_make_cb_group(base_addr, 63)	/* don't put "," here. */
+
+#define smmu_bypass_cfg \
+	{ \
+		.reg = TEGRA_MC_BASE + MC_SMMU_BYPASS_CONFIG, \
+		.val = 0x00000000U, \
+	}
+
+#define _START_OF_TABLE_ \
+	{ \
+		.reg = 0xCAFE05C7U, \
+		.val = 0x00000000U, \
+	}
+
+#define _END_OF_TABLE_ \
+	{ \
+		.reg = 0xFFFFFFFFU, \
+		.val = 0xFFFFFFFFU, \
+	}
+
+
+void tegra_smmu_init(void);
+void tegra_smmu_save_context(uint64_t smmu_ctx_addr);
+smmu_regs_t *plat_get_smmu_ctx(void);
+uint32_t plat_get_num_smmu_devices(void);
+
+#endif /* SMMU_H */
diff --git a/plat/nvidia/tegra/include/drivers/tegra_gic.h b/plat/nvidia/tegra/include/drivers/tegra_gic.h
new file mode 100644
index 0000000..6106b40
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/tegra_gic.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __TEGRA_GIC_H__
+#define __TEGRA_GIC_H__
+
+#include <common/interrupt_props.h>
+
+/*******************************************************************************
+ * Per-CPU struct describing FIQ state to be stored
+ ******************************************************************************/
+typedef struct pcpu_fiq_state {
+	uint64_t elr_el3;
+	uint64_t spsr_el3;
+} pcpu_fiq_state_t;
+
+/*******************************************************************************
+ * Fucntion declarations
+ ******************************************************************************/
+void tegra_gic_cpuif_deactivate(void);
+void tegra_gic_init(void);
+void tegra_gic_pcpu_init(void);
+void tegra_gic_setup(const interrupt_prop_t *interrupt_props,
+		     unsigned int interrupt_props_num);
+
+#endif /* __TEGRA_GIC_H__ */
diff --git a/plat/nvidia/tegra/include/lib/profiler.h b/plat/nvidia/tegra/include/lib/profiler.h
new file mode 100644
index 0000000..60f8d80
--- /dev/null
+++ b/plat/nvidia/tegra/include/lib/profiler.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PROFILER_H__
+#define __PROFILER_H__
+
+/*******************************************************************************
+ * Number of bytes of memory used by the profiler on Tegra
+ ******************************************************************************/
+#define PROFILER_SIZE_BYTES	U(0x1000)
+
+void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base);
+void boot_profiler_add_record(const char *str);
+void boot_profiler_deinit(void);
+
+#endif /* __PROFILER_H__ */
diff --git a/plat/nvidia/tegra/include/plat_macros.S b/plat/nvidia/tegra/include/plat_macros.S
new file mode 100644
index 0000000..4f01e33
--- /dev/null
+++ b/plat/nvidia/tegra/include/plat_macros.S
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gicv2.h>
+#include <tegra_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+	mov_imm	x16, TEGRA_GICC_BASE
+
+	/* gicc base address is now in x16 */
+	adr	x6, gicc_regs	/* Load the gicc reg list to x6 */
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x16, #GICC_HPPIR]
+	ldr	w9, [x16, #GICC_AHPPIR]
+	ldr	w10, [x16, #GICC_CTLR]
+	/* Store to the crash buf and print to cosole */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	mov_imm	x16, TEGRA_GICD_BASE
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+2:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	1f
+	bl	asm_print_hex
+	adr	x4, spacer
+	bl	asm_print_str
+	ldr	w4, [x7], #4
+	bl	asm_print_hex
+	adr	x4, newline
+	bl	asm_print_str
+	b	2b
+1:
+.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h
new file mode 100644
index 0000000..eb55def
--- /dev/null
+++ b/plat/nvidia/tegra/include/platform_def.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include <tegra_def.h>
+
+/*
+ * Platform binary types for linking
+ */
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#ifdef IMAGE_BL31
+#define PLATFORM_STACK_SIZE 		U(0x400)
+#endif
+
+#define TEGRA_PRIMARY_CPU		U(0x0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_MAX_CPUS_PER_CLUSTER)
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + 1)
+
+/*******************************************************************************
+ * Platform console related constants
+ ******************************************************************************/
+#define TEGRA_CONSOLE_BAUDRATE		U(115200)
+#define TEGRA_BOOT_UART_CLK_13_MHZ	U(13000000)
+#define TEGRA_BOOT_UART_CLK_408_MHZ	U(408000000)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* Size of trusted dram */
+#define TZDRAM_SIZE			U(0x00400000)
+#define TZDRAM_END			(TZDRAM_BASE + TZDRAM_SIZE)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+#define BL31_SIZE			U(0x40000)
+#define BL31_BASE			TZDRAM_BASE
+#define BL31_LIMIT			(TZDRAM_BASE + BL31_SIZE - 1)
+#define BL32_BASE			(TZDRAM_BASE + BL31_SIZE)
+#define BL32_LIMIT			TZDRAM_END
+
+/*******************************************************************************
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(0x40) /* (U(1) << CACHE_WRITEBACK_SHIFT) */
+
+/*******************************************************************************
+ * Dummy macros to compile io_storage support
+ ******************************************************************************/
+#define MAX_IO_DEVICES			U(0)
+#define MAX_IO_HANDLES			U(0)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h
new file mode 100644
index 0000000..dfed2aa
--- /dev/null
+++ b/plat/nvidia/tegra/include/t132/tegra_def.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_DEF_H
+#define TEGRA_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
+ * call as the `state-id` field in the 'power state' parameter.
+ ******************************************************************************/
+#define PSTATE_ID_SOC_POWERDN	U(0xD)
+
+/*******************************************************************************
+ * Platform power states (used by PSCI framework)
+ *
+ * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
+ * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
+ ******************************************************************************/
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		(PSTATE_ID_SOC_POWERDN + U(1))
+
+/*******************************************************************************
+ * Chip specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 35)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 35)
+
+/*******************************************************************************
+ * GIC memory map
+ ******************************************************************************/
+#define TEGRA_GICD_BASE			U(0x50041000)
+#define TEGRA_GICC_BASE			U(0x50042000)
+
+/*******************************************************************************
+ * Tegra micro-seconds timer constants
+ ******************************************************************************/
+#define TEGRA_TMRUS_BASE		U(0x60005010)
+#define TEGRA_TMRUS_SIZE		U(0x1000)
+
+/*******************************************************************************
+ * Tegra Clock and Reset Controller constants
+ ******************************************************************************/
+#define TEGRA_CAR_RESET_BASE		U(0x60006000)
+#define TEGRA_GPU_RESET_REG_OFFSET	U(0x28C)
+#define TEGRA_GPU_RESET_GPU_SET_OFFSET	U(0x290)
+#define  GPU_RESET_BIT			(U(1) << 24)
+#define  GPU_SET_BIT			(U(1) << 24)
+
+/*******************************************************************************
+ * Tegra Flow Controller constants
+ ******************************************************************************/
+#define TEGRA_FLOWCTRL_BASE		U(0x60007000)
+
+/*******************************************************************************
+ * Tegra Secure Boot Controller constants
+ ******************************************************************************/
+#define TEGRA_SB_BASE			U(0x6000C200)
+
+/*******************************************************************************
+ * Tegra Exception Vectors constants
+ ******************************************************************************/
+#define TEGRA_EVP_BASE			U(0x6000F000)
+
+/*******************************************************************************
+ * Tegra Miscellaneous register constants
+ ******************************************************************************/
+#define TEGRA_MISC_BASE			U(0x70000000)
+#define  HARDWARE_REVISION_OFFSET	U(0x804)
+
+/*******************************************************************************
+ * Tegra UART controller base addresses
+ ******************************************************************************/
+#define TEGRA_UARTA_BASE		U(0x70006000)
+#define TEGRA_UARTB_BASE		U(0x70006040)
+#define TEGRA_UARTC_BASE		U(0x70006200)
+#define TEGRA_UARTD_BASE		U(0x70006300)
+#define TEGRA_UARTE_BASE		U(0x70006400)
+
+/*******************************************************************************
+ * Tegra Power Mgmt Controller constants
+ ******************************************************************************/
+#define TEGRA_PMC_BASE			U(0x7000E400)
+
+/*******************************************************************************
+ * Tegra Memory Controller constants
+ ******************************************************************************/
+#define TEGRA_MC_BASE			U(0x70019000)
+
+/* Memory Controller Interrupt Status */
+#define MC_INTSTATUS			0x00U
+
+/* TZDRAM carveout configuration registers */
+#define MC_SECURITY_CFG0_0		U(0x70)
+#define MC_SECURITY_CFG1_0		U(0x74)
+#define MC_SECURITY_CFG3_0		U(0x9BC)
+
+/* Video Memory carveout configuration registers */
+#define MC_VIDEO_PROTECT_BASE_HI	U(0x978)
+#define MC_VIDEO_PROTECT_BASE_LO	U(0x648)
+#define MC_VIDEO_PROTECT_SIZE_MB	U(0x64c)
+
+/*******************************************************************************
+ * Tegra TZRAM constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_BASE		U(0x7C010000)
+#define TEGRA_TZRAM_SIZE		U(0x10000)
+
+#endif /* TEGRA_DEF_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra186_private.h b/plat/nvidia/tegra/include/t186/tegra186_private.h
new file mode 100644
index 0000000..9e2c02b
--- /dev/null
+++ b/plat/nvidia/tegra/include/t186/tegra186_private.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA186_PRIVATE_H
+#define TEGRA186_PRIVATE_H
+
+void tegra186_cpu_reset_handler(void);
+uint64_t tegra186_get_cpu_reset_handler_base(void);
+uint64_t tegra186_get_cpu_reset_handler_size(void);
+uint64_t tegra186_get_smmu_ctx_offset(void);
+void tegra186_set_system_suspend_entry(void);
+
+#endif /* TEGRA186_PRIVATE_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra_def.h b/plat/nvidia/tegra/include/t186/tegra_def.h
new file mode 100644
index 0000000..da050a8
--- /dev/null
+++ b/plat/nvidia/tegra/include/t186/tegra_def.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_DEF_H
+#define TEGRA_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * MCE apertures used by the ARI interface
+ *
+ * Aperture 0 - Cpu0 (ARM Cortex A-57)
+ * Aperture 1 - Cpu1 (ARM Cortex A-57)
+ * Aperture 2 - Cpu2 (ARM Cortex A-57)
+ * Aperture 3 - Cpu3 (ARM Cortex A-57)
+ * Aperture 4 - Cpu4 (Denver15)
+ * Aperture 5 - Cpu5 (Denver15)
+ ******************************************************************************/
+#define MCE_ARI_APERTURE_0_OFFSET	U(0x0)
+#define MCE_ARI_APERTURE_1_OFFSET	U(0x10000)
+#define MCE_ARI_APERTURE_2_OFFSET	U(0x20000)
+#define MCE_ARI_APERTURE_3_OFFSET	U(0x30000)
+#define MCE_ARI_APERTURE_4_OFFSET	U(0x40000)
+#define MCE_ARI_APERTURE_5_OFFSET	U(0x50000)
+#define MCE_ARI_APERTURE_OFFSET_MAX	MCE_APERTURE_5_OFFSET
+
+/* number of apertures */
+#define MCE_ARI_APERTURES_MAX		U(6)
+
+/* each ARI aperture is 64KB */
+#define MCE_ARI_APERTURE_SIZE		U(0x10000)
+
+/*******************************************************************************
+ * CPU core id macros for the MCE_ONLINE_CORE ARI
+ ******************************************************************************/
+#define MCE_CORE_ID_MAX			U(8)
+#define MCE_CORE_ID_MASK		U(0x7)
+
+/*******************************************************************************
+ * These values are used by the PSCI implementation during the `CPU_SUSPEND`
+ * and `SYSTEM_SUSPEND` calls as the `state-id` field in the 'power state'
+ * parameter.
+ ******************************************************************************/
+#define PSTATE_ID_CORE_IDLE		U(6)
+#define PSTATE_ID_CORE_POWERDN		U(7)
+#define PSTATE_ID_SOC_POWERDN		U(2)
+
+/*******************************************************************************
+ * Platform power states (used by PSCI framework)
+ *
+ * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
+ * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
+ ******************************************************************************/
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(8)
+
+/*******************************************************************************
+ * Chip specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 35)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 35)
+
+/*******************************************************************************
+ * Secure IRQ definitions
+ ******************************************************************************/
+#define TEGRA186_TOP_WDT_IRQ		U(49)
+#define TEGRA186_AON_WDT_IRQ		U(50)
+
+#define TEGRA186_SEC_IRQ_TARGET_MASK	U(0xF3) /* 4 A57 - 2 Denver */
+
+/*******************************************************************************
+ * Tegra Miscellanous register constants
+ ******************************************************************************/
+#define TEGRA_MISC_BASE			U(0x00100000)
+#define  HARDWARE_REVISION_OFFSET	U(0x4)
+
+#define  MISCREG_PFCFG			U(0x200C)
+
+/*******************************************************************************
+ * Tegra TSA Controller constants
+ ******************************************************************************/
+#define TEGRA_TSA_BASE			U(0x02400000)
+
+/*******************************************************************************
+ * TSA configuration registers
+ ******************************************************************************/
+#define TSA_CONFIG_STATIC0_CSW_SESWR			U(0x4010)
+#define  TSA_CONFIG_STATIC0_CSW_SESWR_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_ETRW			U(0x4038)
+#define  TSA_CONFIG_STATIC0_CSW_ETRW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_SDMMCWAB			U(0x5010)
+#define  TSA_CONFIG_STATIC0_CSW_SDMMCWAB_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_AXISW			U(0x7008)
+#define  TSA_CONFIG_STATIC0_CSW_AXISW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_HDAW			U(0xA008)
+#define  TSA_CONFIG_STATIC0_CSW_HDAW_RESET		U(0x100)
+#define TSA_CONFIG_STATIC0_CSW_AONDMAW			U(0xB018)
+#define  TSA_CONFIG_STATIC0_CSW_AONDMAW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_SCEDMAW			U(0xD018)
+#define  TSA_CONFIG_STATIC0_CSW_SCEDMAW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_BPMPDMAW			U(0xD028)
+#define  TSA_CONFIG_STATIC0_CSW_BPMPDMAW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_APEDMAW			U(0x12018)
+#define  TSA_CONFIG_STATIC0_CSW_APEDMAW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_UFSHCW			U(0x13008)
+#define  TSA_CONFIG_STATIC0_CSW_UFSHCW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_AFIW			U(0x13018)
+#define  TSA_CONFIG_STATIC0_CSW_AFIW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_SATAW			U(0x13028)
+#define  TSA_CONFIG_STATIC0_CSW_SATAW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_EQOSW			U(0x13038)
+#define  TSA_CONFIG_STATIC0_CSW_EQOSW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW		U(0x15008)
+#define  TSA_CONFIG_STATIC0_CSW_XUSB_DEVW_RESET		U(0x1100)
+#define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW		U(0x15018)
+#define  TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW_RESET	U(0x1100)
+
+#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK		(ULL(0x3) << 11)
+#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU		(ULL(0) << 11)
+
+/*******************************************************************************
+ * Tegra General Purpose Centralised DMA constants
+ ******************************************************************************/
+#define TEGRA_GPCDMA_BASE		ULL(0x2610000)
+
+/*******************************************************************************
+ * Tegra Memory Controller constants
+ ******************************************************************************/
+#define TEGRA_MC_STREAMID_BASE		U(0x02C00000)
+#define TEGRA_MC_BASE			U(0x02C10000)
+
+/* General Security Carveout register macros */
+#define MC_GSC_CONFIG_REGS_SIZE		U(0x40)
+#define MC_GSC_LOCK_CFG_SETTINGS_BIT	(U(1) << 1)
+#define MC_GSC_ENABLE_TZ_LOCK_BIT	(ULL(1) << 0)
+#define MC_GSC_SIZE_RANGE_4KB_SHIFT	U(27)
+#define MC_GSC_BASE_LO_SHIFT		U(12)
+#define MC_GSC_BASE_LO_MASK		U(0xFFFFF)
+#define MC_GSC_BASE_HI_SHIFT		U(0)
+#define MC_GSC_BASE_HI_MASK		U(3)
+#define MC_GSC_ENABLE_CPU_SECURE_BIT    (U(1) << 31)
+
+/* TZDRAM carveout configuration registers */
+#define MC_SECURITY_CFG0_0		U(0x70)
+#define MC_SECURITY_CFG1_0		U(0x74)
+#define MC_SECURITY_CFG3_0		U(0x9BC)
+
+#define MC_SECURITY_BOM_MASK		(U(0xFFF) << 20)
+#define MC_SECURITY_SIZE_MB_MASK	(U(0x1FFF) << 0)
+#define MC_SECURITY_BOM_HI_MASK		(U(0x3) << 0)
+
+/* Video Memory carveout configuration registers */
+#define MC_VIDEO_PROTECT_BASE_HI	U(0x978)
+#define MC_VIDEO_PROTECT_BASE_LO	U(0x648)
+#define MC_VIDEO_PROTECT_SIZE_MB	U(0x64C)
+
+/*
+ * Carveout (MC_SECURITY_CARVEOUT24) registers used to clear the
+ * non-overlapping Video memory region
+ */
+#define MC_VIDEO_PROTECT_CLEAR_CFG	U(0x25A0)
+#define MC_VIDEO_PROTECT_CLEAR_BASE_LO	U(0x25A4)
+#define MC_VIDEO_PROTECT_CLEAR_BASE_HI	U(0x25A8)
+#define MC_VIDEO_PROTECT_CLEAR_SIZE	U(0x25AC)
+#define MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0	U(0x25B0)
+
+/* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */
+#define MC_TZRAM_CARVEOUT_CFG		U(0x2190)
+#define MC_TZRAM_BASE_LO		U(0x2194)
+#define MC_TZRAM_BASE_HI		U(0x2198)
+#define MC_TZRAM_SIZE			U(0x219C)
+#define MC_TZRAM_CLIENT_ACCESS0_CFG0	U(0x21A0)
+#define MC_TZRAM_CLIENT_ACCESS1_CFG0	U(0x21A4)
+#define  TZRAM_ALLOW_MPCORER		(U(1) << 7)
+#define  TZRAM_ALLOW_MPCOREW		(U(1) << 25)
+
+/*******************************************************************************
+ * Tegra UART Controller constants
+ ******************************************************************************/
+#define TEGRA_UARTA_BASE		U(0x03100000)
+#define TEGRA_UARTB_BASE		U(0x03110000)
+#define TEGRA_UARTC_BASE		U(0x0C280000)
+#define TEGRA_UARTD_BASE		U(0x03130000)
+#define TEGRA_UARTE_BASE		U(0x03140000)
+#define TEGRA_UARTF_BASE		U(0x03150000)
+#define TEGRA_UARTG_BASE		U(0x0C290000)
+
+/*******************************************************************************
+ * Tegra Fuse Controller related constants
+ ******************************************************************************/
+#define TEGRA_FUSE_BASE			U(0x03820000)
+#define  OPT_SUBREVISION		U(0x248)
+#define  SUBREVISION_MASK		U(0xFF)
+
+/*******************************************************************************
+ * GICv2 & interrupt handling related constants
+ ******************************************************************************/
+#define TEGRA_GICD_BASE			U(0x03881000)
+#define TEGRA_GICC_BASE			U(0x03882000)
+
+/*******************************************************************************
+ * Security Engine related constants
+ ******************************************************************************/
+#define TEGRA_SE0_BASE			U(0x03AC0000)
+#define  SE_MUTEX_WATCHDOG_NS_LIMIT	U(0x6C)
+#define TEGRA_PKA1_BASE			U(0x03AD0000)
+#define  PKA_MUTEX_WATCHDOG_NS_LIMIT	U(0x8144)
+#define TEGRA_RNG1_BASE			U(0x03AE0000)
+#define  RNG_MUTEX_WATCHDOG_NS_LIMIT	U(0xFE0)
+
+/*******************************************************************************
+ * Tegra Clock and Reset Controller constants
+ ******************************************************************************/
+#define TEGRA_CAR_RESET_BASE		U(0x05000000)
+#define TEGRA_GPU_RESET_REG_OFFSET	U(0x30)
+#define TEGRA_GPU_RESET_GPU_SET_OFFSET	U(0x34)
+#define  GPU_RESET_BIT			(U(1) << 0)
+#define  GPU_SET_BIT			(U(1) << 0)
+#define TEGRA_GPCDMA_RST_SET_REG_OFFSET	U(0x6A0004)
+#define TEGRA_GPCDMA_RST_CLR_REG_OFFSET	U(0x6A0008)
+
+/*******************************************************************************
+ * Tegra micro-seconds timer constants
+ ******************************************************************************/
+#define TEGRA_TMRUS_BASE		U(0x0C2E0000)
+#define TEGRA_TMRUS_SIZE		U(0x1000)
+
+/*******************************************************************************
+ * Tegra Power Mgmt Controller constants
+ ******************************************************************************/
+#define TEGRA_PMC_BASE			U(0x0C360000)
+
+/*******************************************************************************
+ * Tegra scratch registers constants
+ ******************************************************************************/
+#define TEGRA_SCRATCH_BASE		U(0x0C390000)
+#define  SECURE_SCRATCH_RSV1_LO		U(0x658)
+#define  SECURE_SCRATCH_RSV1_HI		U(0x65C)
+#define  SECURE_SCRATCH_RSV6		U(0x680)
+#define  SECURE_SCRATCH_RSV11_LO	U(0x6A8)
+#define  SECURE_SCRATCH_RSV11_HI	U(0x6AC)
+#define  SECURE_SCRATCH_RSV53_LO	U(0x7F8)
+#define  SECURE_SCRATCH_RSV53_HI	U(0x7FC)
+#define  SECURE_SCRATCH_RSV55_LO	U(0x808)
+#define  SECURE_SCRATCH_RSV55_HI	U(0x80C)
+
+#define SCRATCH_RESET_VECTOR_LO		SECURE_SCRATCH_RSV1_LO
+#define SCRATCH_RESET_VECTOR_HI		SECURE_SCRATCH_RSV1_HI
+#define SCRATCH_SECURE_BOOTP_FCFG	SECURE_SCRATCH_RSV6
+#define SCRATCH_SMMU_TABLE_ADDR_LO	SECURE_SCRATCH_RSV11_LO
+#define SCRATCH_SMMU_TABLE_ADDR_HI	SECURE_SCRATCH_RSV11_HI
+#define SCRATCH_BL31_PARAMS_ADDR	SECURE_SCRATCH_RSV53_LO
+#define SCRATCH_BL31_PLAT_PARAMS_ADDR	SECURE_SCRATCH_RSV53_HI
+#define SCRATCH_TZDRAM_ADDR_LO		SECURE_SCRATCH_RSV55_LO
+#define SCRATCH_TZDRAM_ADDR_HI		SECURE_SCRATCH_RSV55_HI
+
+/*******************************************************************************
+ * Tegra Memory Mapped Control Register Access constants
+ ******************************************************************************/
+#define TEGRA_MMCRAB_BASE		U(0x0E000000)
+
+/*******************************************************************************
+ * Tegra Memory Mapped Activity Monitor Register Access constants
+ ******************************************************************************/
+#define TEGRA_ARM_ACTMON_CTR_BASE	U(0x0E060000)
+#define TEGRA_DENVER_ACTMON_CTR_BASE	U(0x0E070000)
+
+/*******************************************************************************
+ * Tegra SMMU Controller constants
+ ******************************************************************************/
+#define TEGRA_SMMU0_BASE		U(0x12000000)
+
+/*******************************************************************************
+ * Tegra TZRAM constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_BASE		U(0x30000000)
+#define TEGRA_TZRAM_SIZE		U(0x40000)
+
+#endif /* TEGRA_DEF_H */
diff --git a/plat/nvidia/tegra/include/t186/tegra_mc_def.h b/plat/nvidia/tegra/include/t186/tegra_mc_def.h
new file mode 100644
index 0000000..d051a15
--- /dev/null
+++ b/plat/nvidia/tegra/include/t186/tegra_mc_def.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_MC_DEF_H
+#define TEGRA_MC_DEF_H
+
+/*******************************************************************************
+ * Memory Controller's PCFIFO client configuration registers
+ ******************************************************************************/
+#define MC_PCFIFO_CLIENT_CONFIG0				0xdd0U
+
+#define MC_PCFIFO_CLIENT_CONFIG1				0xdd4U
+#define  MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL			0x20000U
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_UNORDERED		(0U << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_MASK		(1U << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_UNORDERED		(0U << 21)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_MASK		(1U << 21)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_UNORDERED 	(0U << 29)
+#define  MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_MASK		(1U << 29)
+
+#define MC_PCFIFO_CLIENT_CONFIG2				0xdd8U
+#define  MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL			0x20000U
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_UNORDERED	(0U << 11)
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_MASK	(1U << 11)
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_UNORDERED	(0U << 13)
+#define  MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_MASK		(1U << 13)
+
+#define MC_PCFIFO_CLIENT_CONFIG3				0xddcU
+#define  MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL			0U
+#define  MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_UNORDERED	(0U << 7)
+#define  MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_MASK		(1U << 7)
+
+#define MC_PCFIFO_CLIENT_CONFIG4				0xde0U
+#define  MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL			0U
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_UNORDERED 	(0U << 1)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_MASK		(1U << 1)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_UNORDERED		(0U << 5)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_MASK		(1U << 5)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_UNORDERED 	(0U << 13)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_MASK		(1U << 13)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_UNORDERED 	(0U << 15)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_ORDERED 		(1U << 15)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_MASK		(1U << 15)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_UNORDERED	(0U << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_MASK		(1U << 17)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_UNORDERED	(0U << 22)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_MASK		(1U << 22)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_UNORDERED	(0U << 26)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_MASK		(1U << 26)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_UNORDERED	(0U << 30)
+#define  MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_MASK		(1U << 30)
+
+#define MC_PCFIFO_CLIENT_CONFIG5				0xbf4U
+#define  MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL			0U
+#define  MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_UNORDERED	(0U << 0)
+#define  MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_MASK		(1U << 0)
+
+/*******************************************************************************
+ * Stream ID Override Config registers
+ ******************************************************************************/
+#define MC_STREAMID_OVERRIDE_CFG_PTCR				0x000U
+#define MC_STREAMID_OVERRIDE_CFG_AFIR				0x070U
+#define MC_STREAMID_OVERRIDE_CFG_HDAR				0x0A8U
+#define MC_STREAMID_OVERRIDE_CFG_HOST1XDMAR			0x0B0U
+#define MC_STREAMID_OVERRIDE_CFG_NVENCSRD			0x0E0U
+#define MC_STREAMID_OVERRIDE_CFG_SATAR				0x0F8U
+#define MC_STREAMID_OVERRIDE_CFG_MPCORER			0x138U
+#define MC_STREAMID_OVERRIDE_CFG_NVENCSWR			0x158U
+#define MC_STREAMID_OVERRIDE_CFG_AFIW				0x188U
+#define MC_STREAMID_OVERRIDE_CFG_HDAW				0x1A8U
+#define MC_STREAMID_OVERRIDE_CFG_MPCOREW			0x1C8U
+#define MC_STREAMID_OVERRIDE_CFG_SATAW				0x1E8U
+#define MC_STREAMID_OVERRIDE_CFG_ISPRA				0x220U
+#define MC_STREAMID_OVERRIDE_CFG_ISPWA				0x230U
+#define MC_STREAMID_OVERRIDE_CFG_ISPWB				0x238U
+#define MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTR			0x250U
+#define MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTW			0x258U
+#define MC_STREAMID_OVERRIDE_CFG_XUSB_DEVR			0x260U
+#define MC_STREAMID_OVERRIDE_CFG_XUSB_DEVW			0x268U
+#define MC_STREAMID_OVERRIDE_CFG_TSECSRD			0x2A0U
+#define MC_STREAMID_OVERRIDE_CFG_TSECSWR			0x2A8U
+#define MC_STREAMID_OVERRIDE_CFG_GPUSRD				0x2C0U
+#define MC_STREAMID_OVERRIDE_CFG_GPUSWR				0x2C8U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCRA			0x300U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCRAA			0x308U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCR				0x310U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCRAB			0x318U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCWA			0x320U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCWAA			0x328U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCW				0x330U
+#define MC_STREAMID_OVERRIDE_CFG_SDMMCWAB			0x338U
+#define MC_STREAMID_OVERRIDE_CFG_VICSRD				0x360U
+#define MC_STREAMID_OVERRIDE_CFG_VICSWR				0x368U
+#define MC_STREAMID_OVERRIDE_CFG_VIW				0x390U
+#define MC_STREAMID_OVERRIDE_CFG_NVDECSRD			0x3C0U
+#define MC_STREAMID_OVERRIDE_CFG_NVDECSWR			0x3C8U
+#define MC_STREAMID_OVERRIDE_CFG_APER				0x3D0U
+#define MC_STREAMID_OVERRIDE_CFG_APEW				0x3D8U
+#define MC_STREAMID_OVERRIDE_CFG_NVJPGSRD			0x3F0U
+#define MC_STREAMID_OVERRIDE_CFG_NVJPGSWR			0x3F8U
+#define MC_STREAMID_OVERRIDE_CFG_SESRD				0x400U
+#define MC_STREAMID_OVERRIDE_CFG_SESWR				0x408U
+#define MC_STREAMID_OVERRIDE_CFG_ETRR				0x420U
+#define MC_STREAMID_OVERRIDE_CFG_ETRW				0x428U
+#define MC_STREAMID_OVERRIDE_CFG_TSECSRDB			0x430U
+#define MC_STREAMID_OVERRIDE_CFG_TSECSWRB			0x438U
+#define MC_STREAMID_OVERRIDE_CFG_GPUSRD2			0x440U
+#define MC_STREAMID_OVERRIDE_CFG_GPUSWR2			0x448U
+#define MC_STREAMID_OVERRIDE_CFG_AXISR				0x460U
+#define MC_STREAMID_OVERRIDE_CFG_AXISW				0x468U
+#define MC_STREAMID_OVERRIDE_CFG_EQOSR				0x470U
+#define MC_STREAMID_OVERRIDE_CFG_EQOSW				0x478U
+#define MC_STREAMID_OVERRIDE_CFG_UFSHCR				0x480U
+#define MC_STREAMID_OVERRIDE_CFG_UFSHCW				0x488U
+#define MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR			0x490U
+#define MC_STREAMID_OVERRIDE_CFG_BPMPR				0x498U
+#define MC_STREAMID_OVERRIDE_CFG_BPMPW				0x4A0U
+#define MC_STREAMID_OVERRIDE_CFG_BPMPDMAR			0x4A8U
+#define MC_STREAMID_OVERRIDE_CFG_BPMPDMAW			0x4B0U
+#define MC_STREAMID_OVERRIDE_CFG_AONR				0x4B8U
+#define MC_STREAMID_OVERRIDE_CFG_AONW				0x4C0U
+#define MC_STREAMID_OVERRIDE_CFG_AONDMAR			0x4C8U
+#define MC_STREAMID_OVERRIDE_CFG_AONDMAW			0x4D0U
+#define MC_STREAMID_OVERRIDE_CFG_SCER				0x4D8U
+#define MC_STREAMID_OVERRIDE_CFG_SCEW				0x4E0U
+#define MC_STREAMID_OVERRIDE_CFG_SCEDMAR			0x4E8U
+#define MC_STREAMID_OVERRIDE_CFG_SCEDMAW			0x4F0U
+#define MC_STREAMID_OVERRIDE_CFG_APEDMAR			0x4F8U
+#define MC_STREAMID_OVERRIDE_CFG_APEDMAW			0x500U
+#define MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR1			0x508U
+#define MC_STREAMID_OVERRIDE_CFG_VICSRD1			0x510U
+#define MC_STREAMID_OVERRIDE_CFG_NVDECSRD1			0x518U
+
+/*******************************************************************************
+ * Macro to calculate Security cfg register addr from StreamID Override register
+ ******************************************************************************/
+#define MC_STREAMID_OVERRIDE_TO_SECURITY_CFG(addr) ((addr) + (uint32_t)sizeof(uint32_t))
+
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_NO_OVERRIDE_SO_DEV		(0U << 4)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_NON_COHERENT_SO_DEV	(1U << 4)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SO_DEV		(2U << 4)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SNOOP_SO_DEV	(3U << 4)
+
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_NO_OVERRIDE_NORMAL		(0U << 8)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_NON_COHERENT_NORMAL	(1U << 8)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_NORMAL		(2U << 8)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SNOOP_NORMAL	(3U << 8)
+
+#define MC_TXN_OVERRIDE_CONFIG_CGID_SO_DEV_ZERO				(0U << 12)
+#define MC_TXN_OVERRIDE_CONFIG_CGID_SO_DEV_CLIENT_AXI_ID		(1U << 12)
+
+/*******************************************************************************
+ * Memory Controller transaction override config registers
+ ******************************************************************************/
+#define MC_TXN_OVERRIDE_CONFIG_HDAR				0x10a8U
+#define MC_TXN_OVERRIDE_CONFIG_BPMPW				0x14a0U
+#define MC_TXN_OVERRIDE_CONFIG_PTCR				0x1000U
+#define MC_TXN_OVERRIDE_CONFIG_NVDISPLAYR			0x1490U
+#define MC_TXN_OVERRIDE_CONFIG_EQOSW				0x1478U
+#define MC_TXN_OVERRIDE_CONFIG_NVJPGSWR				0x13f8U
+#define MC_TXN_OVERRIDE_CONFIG_ISPRA				0x1220U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCWAA				0x1328U
+#define MC_TXN_OVERRIDE_CONFIG_VICSRD				0x1360U
+#define MC_TXN_OVERRIDE_CONFIG_MPCOREW				0x11c8U
+#define MC_TXN_OVERRIDE_CONFIG_GPUSRD				0x12c0U
+#define MC_TXN_OVERRIDE_CONFIG_AXISR				0x1460U
+#define MC_TXN_OVERRIDE_CONFIG_SCEDMAW				0x14f0U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCW				0x1330U
+#define MC_TXN_OVERRIDE_CONFIG_EQOSR				0x1470U
+#define MC_TXN_OVERRIDE_CONFIG_APEDMAR				0x14f8U
+#define MC_TXN_OVERRIDE_CONFIG_NVENCSRD				0x10e0U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCRAB				0x1318U
+#define MC_TXN_OVERRIDE_CONFIG_VICSRD1				0x1510U
+#define MC_TXN_OVERRIDE_CONFIG_BPMPDMAR				0x14a8U
+#define MC_TXN_OVERRIDE_CONFIG_VIW				0x1390U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCRAA				0x1308U
+#define MC_TXN_OVERRIDE_CONFIG_AXISW				0x1468U
+#define MC_TXN_OVERRIDE_CONFIG_XUSB_DEVR			0x1260U
+#define MC_TXN_OVERRIDE_CONFIG_UFSHCR				0x1480U
+#define MC_TXN_OVERRIDE_CONFIG_TSECSWR				0x12a8U
+#define MC_TXN_OVERRIDE_CONFIG_GPUSWR				0x12c8U
+#define MC_TXN_OVERRIDE_CONFIG_SATAR				0x10f8U
+#define MC_TXN_OVERRIDE_CONFIG_XUSB_HOSTW			0x1258U
+#define MC_TXN_OVERRIDE_CONFIG_TSECSWRB				0x1438U
+#define MC_TXN_OVERRIDE_CONFIG_GPUSRD2				0x1440U
+#define MC_TXN_OVERRIDE_CONFIG_SCEDMAR				0x14e8U
+#define MC_TXN_OVERRIDE_CONFIG_GPUSWR2				0x1448U
+#define MC_TXN_OVERRIDE_CONFIG_AONDMAW				0x14d0U
+#define MC_TXN_OVERRIDE_CONFIG_APEDMAW				0x1500U
+#define MC_TXN_OVERRIDE_CONFIG_AONW				0x14c0U
+#define MC_TXN_OVERRIDE_CONFIG_HOST1XDMAR			0x10b0U
+#define MC_TXN_OVERRIDE_CONFIG_ETRR				0x1420U
+#define MC_TXN_OVERRIDE_CONFIG_SESWR				0x1408U
+#define MC_TXN_OVERRIDE_CONFIG_NVJPGSRD				0x13f0U
+#define MC_TXN_OVERRIDE_CONFIG_NVDECSRD				0x13c0U
+#define MC_TXN_OVERRIDE_CONFIG_TSECSRDB				0x1430U
+#define MC_TXN_OVERRIDE_CONFIG_BPMPDMAW				0x14b0U
+#define MC_TXN_OVERRIDE_CONFIG_APER				0x13d0U
+#define MC_TXN_OVERRIDE_CONFIG_NVDECSRD1			0x1518U
+#define MC_TXN_OVERRIDE_CONFIG_XUSB_HOSTR			0x1250U
+#define MC_TXN_OVERRIDE_CONFIG_ISPWA				0x1230U
+#define MC_TXN_OVERRIDE_CONFIG_SESRD				0x1400U
+#define MC_TXN_OVERRIDE_CONFIG_SCER				0x14d8U
+#define MC_TXN_OVERRIDE_CONFIG_AONR				0x14b8U
+#define MC_TXN_OVERRIDE_CONFIG_MPCORER				0x1138U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCWA				0x1320U
+#define MC_TXN_OVERRIDE_CONFIG_HDAW				0x11a8U
+#define MC_TXN_OVERRIDE_CONFIG_NVDECSWR				0x13c8U
+#define MC_TXN_OVERRIDE_CONFIG_UFSHCW				0x1488U
+#define MC_TXN_OVERRIDE_CONFIG_AONDMAR				0x14c8U
+#define MC_TXN_OVERRIDE_CONFIG_SATAW				0x11e8U
+#define MC_TXN_OVERRIDE_CONFIG_ETRW				0x1428U
+#define MC_TXN_OVERRIDE_CONFIG_VICSWR				0x1368U
+#define MC_TXN_OVERRIDE_CONFIG_NVENCSWR				0x1158U
+#define MC_TXN_OVERRIDE_CONFIG_AFIR				0x1070U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCWAB				0x1338U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCRA				0x1300U
+#define MC_TXN_OVERRIDE_CONFIG_NVDISPLAYR1			0x1508U
+#define MC_TXN_OVERRIDE_CONFIG_ISPWB				0x1238U
+#define MC_TXN_OVERRIDE_CONFIG_BPMPR				0x1498U
+#define MC_TXN_OVERRIDE_CONFIG_APEW				0x13d8U
+#define MC_TXN_OVERRIDE_CONFIG_SDMMCR				0x1310U
+#define MC_TXN_OVERRIDE_CONFIG_XUSB_DEVW			0x1268U
+#define MC_TXN_OVERRIDE_CONFIG_TSECSRD				0x12a0U
+#define MC_TXN_OVERRIDE_CONFIG_AFIW				0x1188U
+#define MC_TXN_OVERRIDE_CONFIG_SCEW				0x14e0U
+
+#define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_CGID			(1U << 0)
+#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV			(2U << 4)
+#define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_SO_DEV_CGID_SO_DEV_CLIENT	(1U << 12)
+
+/*******************************************************************************
+ * Non-SO_DEV transactions override values for CGID_TAG bitfield for the
+ * MC_TXN_OVERRIDE_CONFIG_{module} registers
+ ******************************************************************************/
+#define MC_TXN_OVERRIDE_CGID_TAG_DEFAULT			0U
+#define MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID			1U
+#define MC_TXN_OVERRIDE_CGID_TAG_ZERO				2U
+#define MC_TXN_OVERRIDE_CGID_TAG_ADR				3U
+#define MC_TXN_OVERRIDE_CGID_TAG_MASK				3ULL
+
+/*******************************************************************************
+ * Memory Controller Reset Control registers
+ ******************************************************************************/
+#define MC_CLIENT_HOTRESET_CTRL0				0x200U
+#define  MC_CLIENT_HOTRESET_CTRL0_RESET_VAL			0U
+#define  MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB			(1U << 0)
+#define  MC_CLIENT_HOTRESET_CTRL0_HC_FLUSH_ENB			(1U << 6)
+#define  MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB			(1U << 7)
+#define  MC_CLIENT_HOTRESET_CTRL0_ISP2_FLUSH_ENB		(1U << 8)
+#define  MC_CLIENT_HOTRESET_CTRL0_MPCORE_FLUSH_ENB		(1U << 9)
+#define  MC_CLIENT_HOTRESET_CTRL0_NVENC_FLUSH_ENB		(1U << 11)
+#define  MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB		(1U << 15)
+#define  MC_CLIENT_HOTRESET_CTRL0_VI_FLUSH_ENB			(1U << 17)
+#define  MC_CLIENT_HOTRESET_CTRL0_VIC_FLUSH_ENB			(1U << 18)
+#define  MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB		(1U << 19)
+#define  MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB		(1U << 20)
+#define  MC_CLIENT_HOTRESET_CTRL0_TSEC_FLUSH_ENB		(1U << 22)
+#define  MC_CLIENT_HOTRESET_CTRL0_SDMMC1A_FLUSH_ENB		(1U << 29)
+#define  MC_CLIENT_HOTRESET_CTRL0_SDMMC2A_FLUSH_ENB		(1U << 30)
+#define  MC_CLIENT_HOTRESET_CTRL0_SDMMC3A_FLUSH_ENB		(1U << 31)
+#define MC_CLIENT_HOTRESET_STATUS0				0x204U
+#define MC_CLIENT_HOTRESET_CTRL1				0x970U
+#define  MC_CLIENT_HOTRESET_CTRL1_RESET_VAL			0U
+#define  MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB		(1U << 0)
+#define  MC_CLIENT_HOTRESET_CTRL1_GPU_FLUSH_ENB			(1U << 2)
+#define  MC_CLIENT_HOTRESET_CTRL1_NVDEC_FLUSH_ENB		(1U << 5)
+#define  MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB			(1U << 6)
+#define  MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB			(1U << 7)
+#define  MC_CLIENT_HOTRESET_CTRL1_NVJPG_FLUSH_ENB		(1U << 8)
+#define  MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB			(1U << 12)
+#define  MC_CLIENT_HOTRESET_CTRL1_TSECB_FLUSH_ENB		(1U << 13)
+#define  MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB		(1U << 18)
+#define  MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB		(1U << 19)
+#define  MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB		(1U << 20)
+#define  MC_CLIENT_HOTRESET_CTRL1_NVDISPLAY_FLUSH_ENB		(1U << 21)
+#define  MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB		(1U << 22)
+#define  MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB			(1U << 23)
+#define  MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB			(1U << 24)
+#define MC_CLIENT_HOTRESET_STATUS1				0x974U
+
+#endif /* TEGRA_MC_DEF_H */
diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h
new file mode 100644
index 0000000..bbcfdc5
--- /dev/null
+++ b/plat/nvidia/tegra/include/t210/tegra_def.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_DEF_H
+#define TEGRA_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * Power down state IDs
+ ******************************************************************************/
+#define PSTATE_ID_CORE_POWERDN		U(7)
+#define PSTATE_ID_CLUSTER_IDLE		U(16)
+#define PSTATE_ID_SOC_POWERDN		U(27)
+
+/*******************************************************************************
+ * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
+ * call as the `state-id` field in the 'power state' parameter.
+ ******************************************************************************/
+#define PLAT_SYS_SUSPEND_STATE_ID	PSTATE_ID_SOC_POWERDN
+
+/*******************************************************************************
+ * Platform power states (used by PSCI framework)
+ *
+ * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
+ * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
+ ******************************************************************************/
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		(PSTATE_ID_SOC_POWERDN + U(1))
+
+/*******************************************************************************
+ * Chip specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 35)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 35)
+
+/*******************************************************************************
+ * SC7 entry firmware's header size
+ ******************************************************************************/
+#define SC7ENTRY_FW_HEADER_SIZE_BYTES	U(0x400)
+
+/*******************************************************************************
+ * iRAM memory constants
+ ******************************************************************************/
+#define TEGRA_IRAM_BASE			U(0x40000000)
+#define TEGRA_IRAM_A_SIZE		U(0x10000) /* 64KB */
+#define TEGRA_IRAM_SIZE			U(40000) /* 256KB */
+
+/*******************************************************************************
+ * GIC memory map
+ ******************************************************************************/
+#define TEGRA_GICD_BASE			U(0x50041000)
+#define TEGRA_GICC_BASE			U(0x50042000)
+
+/*******************************************************************************
+ * Secure IRQ definitions
+ ******************************************************************************/
+#define TEGRA210_WDT_CPU_LEGACY_FIQ		U(28)
+
+/*******************************************************************************
+ * Tegra Memory Select Switch Controller constants
+ ******************************************************************************/
+#define TEGRA_MSELECT_BASE		U(0x50060000)
+
+#define MSELECT_CONFIG			U(0x0)
+#define ENABLE_WRAP_INCR_MASTER2_BIT	(U(1) << U(29))
+#define ENABLE_WRAP_INCR_MASTER1_BIT	(U(1) << U(28))
+#define ENABLE_WRAP_INCR_MASTER0_BIT	(U(1) << U(27))
+#define UNSUPPORTED_TX_ERR_MASTER2_BIT	(U(1) << U(25))
+#define UNSUPPORTED_TX_ERR_MASTER1_BIT	(U(1) << U(24))
+#define ENABLE_UNSUP_TX_ERRORS		(UNSUPPORTED_TX_ERR_MASTER2_BIT | \
+					 UNSUPPORTED_TX_ERR_MASTER1_BIT)
+#define ENABLE_WRAP_TO_INCR_BURSTS	(ENABLE_WRAP_INCR_MASTER2_BIT | \
+					 ENABLE_WRAP_INCR_MASTER1_BIT | \
+					 ENABLE_WRAP_INCR_MASTER0_BIT)
+
+/*******************************************************************************
+ * Tegra Resource Semaphore constants
+ ******************************************************************************/
+#define TEGRA_RES_SEMA_BASE		0x60001000UL
+#define  STA_OFFSET			0UL
+#define  SET_OFFSET			4UL
+#define  CLR_OFFSET			8UL
+
+/*******************************************************************************
+ * Tegra Primary Interrupt Controller constants
+ ******************************************************************************/
+#define TEGRA_PRI_ICTLR_BASE		0x60004000UL
+#define  CPU_IEP_FIR_SET		0x18UL
+
+/*******************************************************************************
+ * Tegra micro-seconds timer constants
+ ******************************************************************************/
+#define TEGRA_TMRUS_BASE		U(0x60005010)
+#define TEGRA_TMRUS_SIZE		U(0x1000)
+
+/*******************************************************************************
+ * Tegra Clock and Reset Controller constants
+ ******************************************************************************/
+#define TEGRA_CAR_RESET_BASE		U(0x60006000)
+#define TEGRA_BOND_OUT_H		U(0x74)
+#define  APB_DMA_LOCK_BIT		(U(1) << 2)
+#define  AHB_DMA_LOCK_BIT		(U(1) << 1)
+#define TEGRA_BOND_OUT_U		U(0x78)
+#define  IRAM_D_LOCK_BIT		(U(1) << 23)
+#define  IRAM_C_LOCK_BIT		(U(1) << 22)
+#define  IRAM_B_LOCK_BIT		(U(1) << 21)
+#define TEGRA_GPU_RESET_REG_OFFSET	U(0x28C)
+#define TEGRA_GPU_RESET_GPU_SET_OFFSET	U(0x290)
+#define  GPU_RESET_BIT			(U(1) << 24)
+#define  GPU_SET_BIT			(U(1) << 24)
+#define TEGRA_RST_DEV_SET_Y		U(0x2a8)
+#define  NVENC_RESET_BIT		(U(1) << 27)
+#define  TSECB_RESET_BIT		(U(1) << 14)
+#define  APE_RESET_BIT			(U(1) << 6)
+#define  NVJPG_RESET_BIT		(U(1) << 3)
+#define  NVDEC_RESET_BIT		(U(1) << 2)
+#define TEGRA_RST_DEV_SET_L		U(0x300)
+#define  HOST1X_RESET_BIT		(U(1) << 28)
+#define  ISP_RESET_BIT			(U(1) << 23)
+#define  USBD_RESET_BIT			(U(1) << 22)
+#define  VI_RESET_BIT			(U(1) << 20)
+#define  SDMMC4_RESET_BIT		(U(1) << 15)
+#define  SDMMC1_RESET_BIT		(U(1) << 14)
+#define  SDMMC2_RESET_BIT		(U(1) << 9)
+#define TEGRA_RST_DEV_SET_H		U(0x308)
+#define  USB2_RESET_BIT			(U(1) << 26)
+#define  APBDMA_RESET_BIT		(U(1) << 2)
+#define  AHBDMA_RESET_BIT		(U(1) << 1)
+#define TEGRA_RST_DEV_SET_U		U(0x310)
+#define  XUSB_DEV_RESET_BIT		(U(1) << 31)
+#define  XUSB_HOST_RESET_BIT		(U(1) << 25)
+#define  TSEC_RESET_BIT			(U(1) << 19)
+#define  PCIE_RESET_BIT			(U(1) << 6)
+#define  SDMMC3_RESET_BIT		(U(1) << 5)
+#define TEGRA_RST_DEVICES_V		U(0x358)
+#define TEGRA_RST_DEVICES_W		U(0x35C)
+#define  ENTROPY_CLK_ENB_BIT		(U(1) << 21)
+#define TEGRA_CLK_OUT_ENB_V		U(0x360)
+#define  SE_CLK_ENB_BIT			(U(1) << 31)
+#define TEGRA_CLK_OUT_ENB_W		U(0x364)
+#define  ENTROPY_RESET_BIT 		(U(1) << 21)
+#define TEGRA_RST_DEV_SET_V		U(0x430)
+#define  SE_RESET_BIT			(U(1) << 31)
+#define  HDA_RESET_BIT			(U(1) << 29)
+#define  SATA_RESET_BIT			(U(1) << 28)
+#define TEGRA_RST_DEV_CLR_V		U(0x434)
+#define TEGRA_CLK_ENB_V			U(0x440)
+
+/*******************************************************************************
+ * Tegra Flow Controller constants
+ ******************************************************************************/
+#define TEGRA_FLOWCTRL_BASE		U(0x60007000)
+
+/*******************************************************************************
+ * Tegra AHB arbitration controller
+ ******************************************************************************/
+#define TEGRA_AHB_ARB_BASE		0x6000C000UL
+
+/*******************************************************************************
+ * Tegra Secure Boot Controller constants
+ ******************************************************************************/
+#define TEGRA_SB_BASE			U(0x6000C200)
+
+/*******************************************************************************
+ * Tegra Exception Vectors constants
+ ******************************************************************************/
+#define TEGRA_EVP_BASE			U(0x6000F000)
+
+/*******************************************************************************
+ * Tegra Miscellaneous register constants
+ ******************************************************************************/
+#define TEGRA_MISC_BASE			U(0x70000000)
+#define  HARDWARE_REVISION_OFFSET	U(0x804)
+#define  APB_SLAVE_SECURITY_ENABLE	U(0xC00)
+#define  PMC_SECURITY_EN_BIT		(U(1) << 13)
+#define  PINMUX_AUX_DVFS_PWM		U(0x3184)
+#define  PINMUX_PWM_TRISTATE		(U(1) << 4)
+
+/*******************************************************************************
+ * Tegra UART controller base addresses
+ ******************************************************************************/
+#define TEGRA_UARTA_BASE		U(0x70006000)
+#define TEGRA_UARTB_BASE		U(0x70006040)
+#define TEGRA_UARTC_BASE		U(0x70006200)
+#define TEGRA_UARTD_BASE		U(0x70006300)
+#define TEGRA_UARTE_BASE		U(0x70006400)
+
+/*******************************************************************************
+ * Tegra Fuse Controller related constants
+ ******************************************************************************/
+#define TEGRA_FUSE_BASE			0x7000F800UL
+#define FUSE_BOOT_SECURITY_INFO		0x268UL
+#define FUSE_ATOMIC_SAVE_CARVEOUT_EN	(0x1U << 7)
+#define FUSE_JTAG_SECUREID_VALID	(0x104UL)
+#define ECID_VALID			(0x1UL)
+
+
+/*******************************************************************************
+ * Tegra Power Mgmt Controller constants
+ ******************************************************************************/
+#define TEGRA_PMC_BASE			U(0x7000E400)
+#define TEGRA_PMC_SIZE			U(0xC00) /* 3k */
+
+/*******************************************************************************
+ * Tegra Atomics constants
+ ******************************************************************************/
+#define TEGRA_ATOMICS_BASE		0x70016000UL
+#define  TRIGGER0_REG_OFFSET		0UL
+#define  TRIGGER_WIDTH_SHIFT		4UL
+#define  TRIGGER_ID_SHIFT		16UL
+#define  RESULT0_REG_OFFSET		0xC00UL
+
+/*******************************************************************************
+ * Tegra Memory Controller constants
+ ******************************************************************************/
+#define TEGRA_MC_BASE			U(0x70019000)
+
+/* Memory Controller Interrupt Status */
+#define MC_INTSTATUS			0x00U
+
+/* TZDRAM carveout configuration registers */
+#define MC_SECURITY_CFG0_0		U(0x70)
+#define MC_SECURITY_CFG1_0		U(0x74)
+#define MC_SECURITY_CFG3_0		U(0x9BC)
+
+/* Video Memory carveout configuration registers */
+#define MC_VIDEO_PROTECT_BASE_HI	U(0x978)
+#define MC_VIDEO_PROTECT_BASE_LO	U(0x648)
+#define MC_VIDEO_PROTECT_SIZE_MB	U(0x64c)
+
+/* SMMU configuration registers*/
+#define MC_SMMU_PPCS_ASID_0		0x270U
+#define  PPCS_SMMU_ENABLE		(0x1U << 31)
+
+/*******************************************************************************
+ * Tegra CLDVFS constants
+ ******************************************************************************/
+#define TEGRA_CL_DVFS_BASE		U(0x70110000)
+#define DVFS_DFLL_CTRL			U(0x00)
+#define  ENABLE_OPEN_LOOP		U(1)
+#define  ENABLE_CLOSED_LOOP		U(2)
+#define DVFS_DFLL_OUTPUT_CFG		U(0x20)
+#define  DFLL_OUTPUT_CFG_I2C_EN_BIT	(U(1) << 30)
+#define  DFLL_OUTPUT_CFG_CLK_EN_BIT	(U(1) << 6)
+
+/*******************************************************************************
+ * Tegra SE constants
+ ******************************************************************************/
+#define TEGRA_SE1_BASE			U(0x70012000)
+#define TEGRA_SE2_BASE			U(0x70412000)
+#define TEGRA_PKA1_BASE			U(0x70420000)
+#define TEGRA_SE2_RANGE_SIZE		U(0x2000)
+#define SE_TZRAM_SECURITY		U(0x4)
+
+/*******************************************************************************
+ * Tegra TZRAM constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_BASE		U(0x7C010000)
+#define TEGRA_TZRAM_SIZE		U(0x10000)
+
+/*******************************************************************************
+ * Tegra TZRAM carveout constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_CARVEOUT_BASE	U(0x7C04C000)
+#define TEGRA_TZRAM_CARVEOUT_SIZE	U(0x4000)
+
+#endif /* TEGRA_DEF_H */
diff --git a/plat/nvidia/tegra/include/tegra_platform.h b/plat/nvidia/tegra/include/tegra_platform.h
new file mode 100644
index 0000000..d83ce48
--- /dev/null
+++ b/plat/nvidia/tegra/include/tegra_platform.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_PLATFORM_H
+#define TEGRA_PLATFORM_H
+
+#include <cdefs.h>
+#include <lib/utils_def.h>
+#include <stdbool.h>
+
+/*******************************************************************************
+ * Tegra major, minor version helper macros
+ ******************************************************************************/
+#define MAJOR_VERSION_SHIFT		U(0x4)
+#define MAJOR_VERSION_MASK		U(0xF)
+#define MINOR_VERSION_SHIFT		U(0x10)
+#define MINOR_VERSION_MASK		U(0xF)
+#define CHIP_ID_SHIFT			U(8)
+#define CHIP_ID_MASK			U(0xFF)
+#define PRE_SI_PLATFORM_SHIFT		U(0x14)
+#define PRE_SI_PLATFORM_MASK		U(0xF)
+
+/*******************************************************************************
+ * Tegra chip ID values
+ ******************************************************************************/
+#define TEGRA_CHIPID_TEGRA13		U(0x13)
+#define TEGRA_CHIPID_TEGRA21		U(0x21)
+#define TEGRA_CHIPID_TEGRA18		U(0x18)
+
+#ifndef __ASSEMBLER__
+
+/*
+ * Tegra chip ID major/minor identifiers
+ */
+uint32_t tegra_get_chipid_major(void);
+uint32_t tegra_get_chipid_minor(void);
+
+/*
+ * Tegra chip ID identifiers
+ */
+bool tegra_chipid_is_t132(void);
+bool tegra_chipid_is_t186(void);
+bool tegra_chipid_is_t210(void);
+bool tegra_chipid_is_t210_b01(void);
+
+/*
+ * Tegra platform identifiers
+ */
+bool tegra_platform_is_silicon(void);
+bool tegra_platform_is_qt(void);
+bool tegra_platform_is_emulation(void);
+bool tegra_platform_is_linsim(void);
+bool tegra_platform_is_fpga(void);
+bool tegra_platform_is_unit_fpga(void);
+bool tegra_platform_is_virt_dev_kit(void);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* TEGRA_PLATFORM_H */
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
new file mode 100644
index 0000000..cdd9e08
--- /dev/null
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TEGRA_PRIVATE_H
+#define TEGRA_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <tegra_gic.h>
+
+/*******************************************************************************
+ * Tegra DRAM memory base address
+ ******************************************************************************/
+#define TEGRA_DRAM_BASE		ULL(0x80000000)
+#define TEGRA_DRAM_END		ULL(0x27FFFFFFF)
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL1 bit definitions
+ ******************************************************************************/
+#define ACTLR_EL1_PMSTATE_MASK		(ULL(0xF) << 0)
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL2 bit definitions
+ ******************************************************************************/
+#define ACTLR_EL2_PMSTATE_MASK		(ULL(0xF) << 0)
+
+/*******************************************************************************
+ * Struct for parameters received from BL2
+ ******************************************************************************/
+typedef struct plat_params_from_bl2 {
+	/* TZ memory size */
+	uint64_t tzdram_size;
+	/* TZ memory base */
+	uint64_t tzdram_base;
+	/* UART port ID */
+	int32_t uart_id;
+	/* L2 ECC parity protection disable flag */
+	int32_t l2_ecc_parity_prot_dis;
+	/* SHMEM base address for storing the boot logs */
+	uint64_t boot_profiler_shmem_base;
+	/* System Suspend Entry Firmware size */
+	uint64_t sc7entry_fw_size;
+	/* System Suspend Entry Firmware base address */
+	uint64_t sc7entry_fw_base;
+} plat_params_from_bl2_t;
+
+/*******************************************************************************
+ * Helper function to access l2ctlr_el1 register on Cortex-A57 CPUs
+ ******************************************************************************/
+DEFINE_RENAME_SYSREG_RW_FUNCS(l2ctlr_el1, CORTEX_A57_L2CTLR_EL1)
+
+/*******************************************************************************
+ * Struct describing parameters passed to bl31
+ ******************************************************************************/
+struct tegra_bl31_params {
+       param_header_t h;
+       image_info_t *bl31_image_info;
+       entry_point_info_t *bl32_ep_info;
+       image_info_t *bl32_image_info;
+       entry_point_info_t *bl33_ep_info;
+       image_info_t *bl33_image_info;
+};
+
+/* Declarations for plat_psci_handlers.c */
+int32_t tegra_soc_validate_power_state(uint32_t power_state,
+		psci_power_state_t *req_state);
+
+/* Declarations for plat_setup.c */
+const mmap_region_t *plat_get_mmio_map(void);
+uint32_t plat_get_console_from_id(int32_t id);
+void plat_gic_setup(void);
+struct tegra_bl31_params *plat_get_bl31_params(void);
+plat_params_from_bl2_t *plat_get_bl31_plat_params(void);
+void plat_early_platform_setup(void);
+void plat_late_platform_setup(void);
+
+/* Declarations for plat_secondary.c */
+void plat_secondary_setup(void);
+int32_t plat_lock_cpu_vectors(void);
+
+/* Declarations for tegra_fiq_glue.c */
+void tegra_fiq_handler_setup(void);
+int tegra_fiq_get_intr_context(void);
+void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint);
+
+/* Declarations for tegra_security.c */
+void tegra_security_setup(void);
+void tegra_security_setup_videomem(uintptr_t base, uint64_t size);
+
+/* Declarations for tegra_pm.c */
+extern uint8_t tegra_fake_system_suspend;
+
+void tegra_pm_system_suspend_entry(void);
+void tegra_pm_system_suspend_exit(void);
+int32_t tegra_system_suspended(void);
+int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state);
+int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state);
+int32_t tegra_soc_pwr_domain_on(u_register_t mpidr);
+int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state);
+int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state);
+int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state);
+int32_t tegra_soc_prepare_system_reset(void);
+__dead2 void tegra_soc_prepare_system_off(void);
+plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
+					     const plat_local_state_t *states,
+					     uint32_t ncpu);
+void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state);
+void tegra_cpu_standby(plat_local_state_t cpu_state);
+int32_t tegra_pwr_domain_on(u_register_t mpidr);
+void tegra_pwr_domain_off(const psci_power_state_t *target_state);
+void tegra_pwr_domain_suspend(const psci_power_state_t *target_state);
+void __dead2 tegra_pwr_domain_power_down_wfi(const psci_power_state_t *target_state);
+void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state);
+void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state);
+__dead2 void tegra_system_off(void);
+__dead2 void tegra_system_reset(void);
+int32_t tegra_validate_power_state(uint32_t power_state,
+				   psci_power_state_t *req_state);
+int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint);
+
+/* Declarations for tegraXXX_pm.c */
+int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl);
+int tegra_prepare_cpu_on_finish(unsigned long mpidr);
+
+/* Declarations for tegra_bl31_setup.c */
+plat_params_from_bl2_t *bl31_get_plat_params(void);
+int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes);
+
+/* Declarations for tegra_delay_timer.c */
+void tegra_delay_timer_init(void);
+
+void tegra_secure_entrypoint(void);
+void tegra186_cpu_reset_handler(void);
+
+/* Declarations for tegra_sip_calls.c */
+uintptr_t tegra_sip_handler(uint32_t smc_fid,
+			    u_register_t x1,
+			    u_register_t x2,
+			    u_register_t x3,
+			    u_register_t x4,
+			    void *cookie,
+			    void *handle,
+			    u_register_t flags);
+int plat_sip_handler(uint32_t smc_fid,
+		     uint64_t x1,
+		     uint64_t x2,
+		     uint64_t x3,
+		     uint64_t x4,
+		     const void *cookie,
+		     void *handle,
+		     uint64_t flags);
+
+#endif /* TEGRA_PRIVATE_H */
diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk
new file mode 100644
index 0000000..0917d87
--- /dev/null
+++ b/plat/nvidia/tegra/platform.mk
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+SOC_DIR			:=	plat/nvidia/tegra/soc/${TARGET_SOC}
+
+# dump the state on crash console
+CRASH_REPORTING		:=	1
+$(eval $(call add_define,CRASH_REPORTING))
+
+# enable assert() for release/debug builds
+ENABLE_ASSERTIONS	:=	1
+PLAT_LOG_LEVEL_ASSERT	:=	40
+$(eval $(call add_define,PLAT_LOG_LEVEL_ASSERT))
+
+# enable dynamic memory mapping
+PLAT_XLAT_TABLES_DYNAMIC :=	1
+$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
+
+# Enable PSCI v1.0 extended state ID format
+PSCI_EXTENDED_STATE_ID	:=	1
+
+# code and read-only data should be put on separate memory pages
+SEPARATE_CODE_AND_RODATA :=	1
+
+# do not use coherent memory
+USE_COHERENT_MEM	:=	0
+
+# do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
+
+# enable D-cache early during CPU warmboot
+WARMBOOT_ENABLE_DCACHE_EARLY := 1
+
+# remove the standard libc
+OVERRIDE_LIBC		:=	1
+
+include plat/nvidia/tegra/common/tegra_common.mk
+include ${SOC_DIR}/platform_${TARGET_SOC}.mk
+
+# modify BUILD_PLAT to point to SoC specific build directory
+BUILD_PLAT	:=	${BUILD_BASE}/${PLAT}/${TARGET_SOC}/${BUILD_TYPE}
+
+# platform cflags (enable signed comparisons, disable stdlib)
+TF_CFLAGS	+= -Wsign-compare -nostdlib
+
+# override with necessary libc files for the Tegra platform
+override LIBC_SRCS :=	$(addprefix lib/libc/,		\
+			assert.c			\
+			memcpy.c			\
+			memmove.c			\
+			memset.c			\
+			printf.c			\
+			putchar.c			\
+			strlen.c			\
+			snprintf.c)
+
+INCLUDES	+=	-Iinclude/lib/libc		\
+			-Iinclude/lib/libc/$(ARCH)	\
+
+ifneq ($(findstring armlink,$(notdir $(LD))),)
+# o suppress warnings for section mismatches, undefined symbols
+# o use only those libraries that are specified in the input file
+#   list to resolve references
+# o create a static callgraph of functions
+# o resolve undefined symbols to el3_panic
+# o include only required sections
+TF_LDFLAGS	+= --diag_suppress=L6314,L6332 --no_scanlib --callgraph
+TF_LDFLAGS	+= --keep="*(__pubsub*)" --keep="*(rt_svc_descs*)" --keep="*(*cpu_ops)"
+ifeq (${ENABLE_PMF},1)
+TF_LDFLAGS	+= --keep="*(*pmf_svc_descs*)"
+endif
+endif
diff --git a/plat/nvidia/tegra/scat/bl31.scat b/plat/nvidia/tegra/scat/bl31.scat
new file mode 100644
index 0000000..2f5fd9e
--- /dev/null
+++ b/plat/nvidia/tegra/scat/bl31.scat
@@ -0,0 +1,284 @@
+#! armclang -E -x c
+
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#define PAGE_SIZE	(1024 * 4)
+
+LR_START BL31_BASE
+{
+	__BL31_START__ +0 FIXED EMPTY 0
+	{
+		/* placeholder */
+	}
+
+	/* BL31_BASE address must be aligned on a page boundary. */
+	ScatterAssert((ImageBase(__BL31_START__) AND 0xFFF) == 0)
+}
+
+LR_TEXT BL31_BASE
+{
+	__TEXT__ +0 FIXED
+	{
+		*(:gdef:bl31_entrypoint, +FIRST)
+		*(.text*)
+		*(.vectors)
+		.ANY1(+RO-CODE)
+	}
+
+	__TEXT_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0
+	{
+		/* section delimiter */
+	}
+}
+
+LR_RO_DATA +0
+{
+	__RODATA__ AlignExpr(ImageLimit(LR_TEXT), 0) FIXED
+	{
+		*(.rodata*)
+		.ANY2(+RO-DATA)
+	}
+
+	/* Ensure 8-byte alignment for descriptors and ensure inclusion */
+	__RT_SVC_DESCS__ AlignExpr(ImageLimit(__RODATA__), 8) FIXED
+	{
+		*(rt_svc_descs)
+	}
+
+#if ENABLE_PMF
+	/* Ensure 8-byte alignment for descriptors and ensure inclusion */
+	__PMF_SVC_DESCS__ AlignExpr(ImageLimit(__RT_SVC_DESCS__), 8) FIXED
+	{
+		*(pmf_svc_descs)
+	}
+#endif /* ENABLE_PMF */
+
+	/*
+	 * Ensure 8-byte alignment for cpu_ops so that its fields are also
+	 * aligned.
+	 */
+	__CPU_OPS__ AlignExpr(+0, 8) FIXED
+	{
+		*(cpu_ops)
+	}
+
+	/*
+	 * Keep the .got section in the RO section as it is patched
+	 * prior to enabling the MMU and having the .got in RO is better for
+	 * security. GOT is a table of addresses so ensure 8-byte alignment.
+	 */
+	__GOT__ AlignExpr(ImageLimit(__CPU_OPS__), 8) FIXED
+	{
+		*(.got)
+	}
+
+	/* Place pubsub sections for events */
+	__PUBSUB_EVENTS__ AlignExpr(+0, 8) EMPTY 0
+	{
+		/* placeholder */
+	}
+
+#include <lib/el3_runtime/pubsub_events.h>
+
+	__RODATA_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0
+	{
+		/* section delimiter */
+	}
+}
+
+	/* cpu_ops must always be defined */
+	ScatterAssert(ImageLength(__CPU_OPS__) > 0)
+
+#if ENABLE_SPM
+LR_SPM +0
+{
+	/*
+	 * Exception vectors of the SPM shim layer. They must be aligned to a 2K
+	 * address, but we need to place them in a separate page so that we can set
+	 * individual permissions to them, so the actual alignment needed is 4K.
+	 *
+	 * There's no need to include this into the RO section of BL31 because it
+	 * doesn't need to be accessed by BL31.
+	 */
+	__SPM_SHIM_EXCEPTIONS__ AlignExpr(ImageLimit(LR_RO_DATA), PAGE_SIZE) FIXED
+	{
+		*(.spm_shim_exceptions)
+	}
+
+	__SPM_SHIM_EXCEPTIONS_EPILOGUE__ AlignExpr(ImageLimit(__SPM_SHIM_EXCEPTIONS__), PAGE_SIZE) FIXED
+	{
+		/* placeholder */
+	}
+}
+#endif
+
+LR_RW_DATA +0
+{
+	__DATA__ AlignExpr(+0, 16) FIXED
+	{
+		*(.data*)
+		*(.constdata)
+		*(locale$$data)
+	}
+}
+
+LR_RELA +0
+{
+	/*
+	 * .rela.dyn needs to come after .data for the read-elf utility to parse
+	 * this section correctly. Ensure 8-byte alignment so that the fields of
+	 * RELA data structure are aligned.
+	 */
+	__RELA__ AlignExpr(ImageLimit(LR_RW_DATA), 8) FIXED
+	{
+		*(.rela.dyn)
+	}
+}
+
+#ifdef BL31_PROGBITS_LIMIT
+	/* BL31 progbits has exceeded its limit. */
+	ScatterAssert(ImageLimit(LR_RELA) <= BL31_PROGBITS_LIMIT)
+#endif
+
+LR_STACKS +0
+{
+	__STACKS__ AlignExpr(+0, 64) FIXED
+	{
+		*(tzfw_normal_stacks)
+	}
+}
+
+#define __BAKERY_LOCK_SIZE__		(ImageLimit(__BAKERY_LOCKS_EPILOGUE__) - \
+					 ImageBase(__BAKERY_LOCKS__))
+#define BAKERY_LOCK_SIZE		(__BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1))
+#define __PMF_TIMESTAMP_SIZE__		(ImageLimit(__PMF_TIMESTAMP__) - \
+					 ImageBase(__PMF_TIMESTAMP__))
+#define PER_CPU_TIMESTAMP_SIZE		(__PMF_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1))
+
+LR_BSS +0
+{
+	__BSS__ AlignExpr(ImageLimit(LR_STACKS), 256) FIXED
+	{
+		*(.bss*)
+		*(COMDAT)
+	}
+
+#if !USE_COHERENT_MEM
+	/*
+	 * Bakery locks are stored in normal .bss memory
+	 *
+	 * Each lock's data is spread across multiple cache lines, one per CPU,
+	 * but multiple locks can share the same cache line.
+	 * The compiler will allocate enough memory for one CPU's bakery locks,
+	 * the remaining cache lines are allocated by the linker script
+	 */
+	__BAKERY_LOCKS__ AlignExpr(ImageLimit(__BSS__), CACHE_WRITEBACK_GRANULE) FIXED
+	{
+		*(bakery_lock)
+	}
+
+	__BAKERY_LOCKS_EPILOGUE__ AlignExpr(ImageLimit(__BAKERY_LOCKS__), CACHE_WRITEBACK_GRANULE) FIXED EMPTY 0
+	{
+		/* section delimiter */
+	}
+
+	__PER_CPU_BAKERY_LOCKS__ ImageLimit(__BAKERY_LOCKS_EPILOGUE__) FIXED FILL 0 BAKERY_LOCK_SIZE
+	{
+		/* padded memory section to store per cpu bakery locks */
+	}
+
+#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
+	/* PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements */
+	ScatterAssert(__PER_CPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE)
+#endif
+#endif
+
+#if ENABLE_PMF
+	/*
+	 * Time-stamps are stored in normal .bss memory
+	 *
+	 * The compiler will allocate enough memory for one CPU's time-stamps,
+	 * the remaining memory for other CPU's is allocated by the
+	 * linker script
+	 */
+	__PMF_TIMESTAMP__ AlignExpr(+0, CACHE_WRITEBACK_GRANULE) FIXED EMPTY CACHE_WRITEBACK_GRANULE
+	{
+		/* store timestamps in this carved out memory */
+	}
+
+	__PMF_TIMESTAMP_EPILOGUE__ AlignExpr(ImageLimit(__PMF_TIMESTAMP__), CACHE_WRITEBACK_GRANULE) FIXED EMPTY 0
+	{
+		/*
+		 * placeholder to make __PMF_TIMESTAMP_START__ end on a
+		 * CACHE_WRITEBACK_GRANULE boundary
+		 */
+	}
+
+	__PER_CPU_TIMESTAMPS__ +0 FIXED FILL 0 PER_CPU_TIMESTAMP_SIZE
+	{
+		/* padded memory section to store per cpu timestamps */
+	}
+#endif /* ENABLE_PMF */
+}
+
+LR_XLAT_TABLE +0
+{
+	xlat_table +0 FIXED
+	{
+		*(xlat_table)
+	}
+}
+
+#if USE_COHERENT_MEM
+LR_COHERENT_RAM +0
+{
+	/*
+	 * The base address of the coherent memory section must be page-aligned (4K)
+	 * to guarantee that the coherent data are stored on their own pages and
+	 * are not mixed with normal data.  This is required to set up the correct
+	 * memory attributes for the coherent data page tables.
+	 */
+	__COHERENT_RAM__ AlignExpr(+0, PAGE_SIZE) FIXED
+	{
+		/*
+		 * Bakery locks are stored in coherent memory
+		 *
+		 * Each lock's data is contiguous and fully allocated by the compiler
+		 */
+		*(bakery_lock)
+		*(tzfw_coherent_mem)
+	}
+
+	__COHERENT_RAM_EPILOGUE_UNALIGNED__ +0 FIXED EMPTY 0
+	{
+		/* section delimiter */
+	}
+
+	/*
+	 * Memory page(s) mapped to this section will be marked
+	 * as device memory.  No other unexpected data must creep in.
+	 * Ensure the rest of the current memory page is unused.
+	 */
+	__COHERENT_RAM_EPILOGUE__ AlignExpr(ImageLimit(__COHERENT_RAM_START__), PAGE_SIZE) FIXED EMPTY 0
+	{
+		/* section delimiter */
+	}
+}
+#endif
+
+LR_END +0
+{
+	__BL31_END__ +0 FIXED EMPTY 0
+	{
+		/* placeholder */
+	}
+
+	/* BL31 image has exceeded its limit. */
+	ScatterAssert(ImageLimit(__BL31_END__) <= BL31_LIMIT)
+}
diff --git a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
new file mode 100644
index 0000000..bd3f46f
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <denver.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <flowctrl.h>
+#include <pmc.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+/*
+ * Register used to clear CPU reset signals. Each CPU has two reset
+ * signals: CPU reset (3:0) and Core reset (19:16)
+ */
+#define CPU_CMPLX_RESET_CLR		0x344
+#define CPU_CORE_RESET_MASK		0x10001
+
+/* Clock and Reset controller registers for system clock's settings */
+#define SCLK_RATE			0x30
+#define SCLK_BURST_POLICY		0x28
+#define SCLK_BURST_POLICY_DEFAULT	0x10000000
+
+static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
+
+int32_t tegra_soc_validate_power_state(unsigned int power_state,
+					psci_power_state_t *req_state)
+{
+	int state_id = psci_get_pstate_id(power_state);
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
+
+	/*
+	 * Sanity check the requested state id, power level and CPU number.
+	 * Currently T132 only supports SYSTEM_SUSPEND on last standing CPU
+	 * i.e. CPU 0
+	 */
+	if ((state_id != PSTATE_ID_SOC_POWERDN) || (cpu != 0)) {
+		ERROR("unsupported state id @ power level\n");
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	/* Set lower power states to PLAT_MAX_OFF_STATE */
+	for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+
+	/* Set the SYSTEM_SUSPEND state-id */
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
+		PSTATE_ID_SOC_POWERDN;
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_on(u_register_t mpidr)
+{
+	int cpu = mpidr & MPIDR_CPU_MASK;
+	uint32_t mask = CPU_CORE_RESET_MASK << cpu;
+
+	if (cpu_powergate_mask[cpu] == 0) {
+
+		/* Deassert CPU reset signals */
+		mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
+
+		/* Power on CPU using PMC */
+		tegra_pmc_cpu_on(cpu);
+
+		/* Fill in the CPU powergate mask */
+		cpu_powergate_mask[cpu] = 1;
+
+	} else {
+		/* Power on CPU using Flow Controller */
+		tegra_fc_cpu_on(cpu);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/*
+	 * Lock scratch registers which hold the CPU vectors
+	 */
+	tegra_pmc_lock_cpu_vectors();
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uint64_t val;
+
+	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
+
+	/* Disable DCO operations */
+	denver_disable_dco();
+
+	/* Power down the CPU */
+	val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK;
+	write_actlr_el1(val | DENVER_CPU_STATE_POWER_DOWN);
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	uint64_t val;
+
+#if ENABLE_ASSERTIONS
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
+
+	/* SYSTEM_SUSPEND only on CPU0 */
+	assert(cpu == 0);
+#endif
+
+	/* Allow restarting CPU #1 using PMC on suspend exit */
+	cpu_powergate_mask[1] = 0;
+
+	/* Program FC to enter suspend state */
+	tegra_fc_cpu_powerdn(read_mpidr());
+
+	/* Disable DCO operations */
+	denver_disable_dco();
+
+	/* Program the suspend state ID */
+	val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK;
+	write_actlr_el1(val | target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]);
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_prepare_system_reset(void)
+{
+	/*
+	 * Set System Clock (SCLK) to POR default so that the clock source
+	 * for the PMC APB clock would not be changed due to system reset.
+	 */
+	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
+		       SCLK_BURST_POLICY_DEFAULT);
+	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
+
+	/* Wait 1 ms to make sure clock source/device logic is stabilized. */
+	mdelay(1);
+
+	return PSCI_E_SUCCESS;
+}
diff --git a/plat/nvidia/tegra/soc/t132/plat_secondary.c b/plat/nvidia/tegra/soc/t132/plat_secondary.c
new file mode 100644
index 0000000..f46ad3b
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t132/plat_secondary.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <denver.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <pmc.h>
+#include <tegra_def.h>
+
+#define SB_CSR				0x0
+#define  SB_CSR_NS_RST_VEC_WR_DIS	(1 << 1)
+
+/* AARCH64 CPU reset vector */
+#define SB_AA64_RESET_LOW		0x30	/* width = 31:0 */
+#define SB_AA64_RESET_HI		0x34	/* width = 11:0 */
+
+/* AARCH32 CPU reset vector */
+#define EVP_CPU_RESET_VECTOR		0x100
+
+extern void tegra_secure_entrypoint(void);
+
+/*
+ * For T132, CPUs reset to AARCH32, so the reset vector is first
+ * armv8_trampoline which does a warm reset to AARCH64 and starts
+ * execution at the address in SB_AA64_RESET_LOW/SB_AA64_RESET_HI.
+ */
+__aligned(8) const uint32_t armv8_trampoline[] = {
+	0xE3A00003,		/* mov	r0, #3 */
+	0xEE0C0F50,		/* mcr	p15, 0, r0, c12, c0, 2 */
+	0xEAFFFFFE,		/* b	. */
+};
+
+/*******************************************************************************
+ * Setup secondary CPU vectors
+ ******************************************************************************/
+void plat_secondary_setup(void)
+{
+	uint32_t val;
+	uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint;
+
+	/*
+	 * For T132, CPUs reset to AARCH32, so the reset vector is first
+	 * armv8_trampoline, which does a warm reset to AARCH64 and starts
+	 * execution at the address in SCRATCH34/SCRATCH35.
+	 */
+	INFO("Setting up T132 CPU boot\n");
+
+	/* initial AARCH32 reset address */
+	tegra_pmc_write_32(PMC_SECURE_SCRATCH22,
+		(unsigned long)&armv8_trampoline);
+
+	/* set AARCH32 exception vector (read to flush) */
+	mmio_write_32(TEGRA_EVP_BASE + EVP_CPU_RESET_VECTOR,
+		(unsigned long)&armv8_trampoline);
+	val = mmio_read_32(TEGRA_EVP_BASE + EVP_CPU_RESET_VECTOR);
+
+	/* setup secondary CPU vector */
+	mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_LOW,
+			(reset_addr & 0xFFFFFFFF) | 1);
+	val = reset_addr >> 32;
+	mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_HI, val & 0x7FF);
+
+	/* configure PMC */
+	tegra_pmc_cpu_setup(reset_addr);
+	tegra_pmc_lock_cpu_vectors();
+}
diff --git a/plat/nvidia/tegra/soc/t132/plat_setup.c b/plat/nvidia/tegra/soc/t132/plat_setup.c
new file mode 100644
index 0000000..570acd9
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t132/plat_setup.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+/* sets of MMIO ranges setup */
+#define MMIO_RANGE_0_ADDR	0x50000000
+#define MMIO_RANGE_1_ADDR	0x60000000
+#define MMIO_RANGE_2_ADDR	0x70000000
+#define MMIO_RANGE_SIZE		0x200000
+
+/*
+ * Table of regions to map using the MMU.
+ */
+static const mmap_region_t tegra_mmap[] = {
+	MAP_REGION_FLAT(MMIO_RANGE_0_ADDR, MMIO_RANGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MMIO_RANGE_1_ADDR, MMIO_RANGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MMIO_RANGE_2_ADDR, MMIO_RANGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{0}
+};
+
+/*******************************************************************************
+ * Set up the pagetables as per the platform memory map & initialize the MMU
+ ******************************************************************************/
+const mmap_region_t *plat_get_mmio_map(void)
+{
+	/* MMIO space */
+	return tegra_mmap;
+}
+
+/*******************************************************************************
+ * The Tegra power domain tree has a single system level power domain i.e. a
+ * single root node. The first entry in the power domain descriptor specifies
+ * the number of power domains at the highest power level.
+ *******************************************************************************
+ */
+const unsigned char tegra_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	1,
+	/* No of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of CPU cores */
+	PLATFORM_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the Tegra default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return tegra_power_domain_tree_desc;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 12000000;
+}
+
+/*******************************************************************************
+ * Maximum supported UART controllers
+ ******************************************************************************/
+#define TEGRA132_MAX_UART_PORTS		5
+
+/*******************************************************************************
+ * This variable holds the UART port base addresses
+ ******************************************************************************/
+static uint32_t tegra132_uart_addresses[TEGRA132_MAX_UART_PORTS + 1] = {
+	0,	/* undefined - treated as an error case */
+	TEGRA_UARTA_BASE,
+	TEGRA_UARTB_BASE,
+	TEGRA_UARTC_BASE,
+	TEGRA_UARTD_BASE,
+	TEGRA_UARTE_BASE,
+};
+
+/*******************************************************************************
+ * Retrieve the UART controller base to be used as the console
+ ******************************************************************************/
+uint32_t plat_get_console_from_id(int id)
+{
+	if (id > TEGRA132_MAX_UART_PORTS)
+		return 0;
+
+	return tegra132_uart_addresses[id];
+}
+
+/*******************************************************************************
+ * Initialize the GIC and SGIs
+ ******************************************************************************/
+void plat_gic_setup(void)
+{
+	tegra_gic_setup(NULL, 0);
+	tegra_gic_init();
+}
diff --git a/plat/nvidia/tegra/soc/t132/plat_sip_calls.c b/plat/nvidia/tegra/soc/t132/plat_sip_calls.c
new file mode 100644
index 0000000..90c6bb2
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t132/plat_sip_calls.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+
+#include <tegra_private.h>
+
+#define NS_SWITCH_AARCH32	1
+#define SCR_RW_BITPOS		__builtin_ctz(SCR_RW_BIT)
+
+/*******************************************************************************
+ * Tegra132 SiP SMCs
+ ******************************************************************************/
+#define TEGRA_SIP_AARCH_SWITCH			0x82000004
+
+/*******************************************************************************
+ * SPSR settings for AARCH32/AARCH64 modes
+ ******************************************************************************/
+#define SPSR32		SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, \
+			DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)
+#define SPSR64		SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)
+
+/*******************************************************************************
+ * This function is responsible for handling all T132 SiP calls
+ ******************************************************************************/
+int plat_sip_handler(uint32_t smc_fid,
+		     uint64_t x1,
+		     uint64_t x2,
+		     uint64_t x3,
+		     uint64_t x4,
+		     const void *cookie,
+		     void *handle,
+		     uint64_t flags)
+{
+	switch (smc_fid) {
+
+	case TEGRA_SIP_AARCH_SWITCH:
+
+		/* clean up the high bits */
+		x1 = (uint32_t)x1;
+		x2 = (uint32_t)x2;
+
+		if (!x1 || x2 > NS_SWITCH_AARCH32) {
+			ERROR("%s: invalid parameters\n", __func__);
+			return -EINVAL;
+		}
+
+		/* x1 = ns entry point */
+		cm_set_elr_spsr_el3(NON_SECURE, x1,
+			(x2 == NS_SWITCH_AARCH32) ? SPSR32 : SPSR64);
+
+		/* switch NS world mode */
+		cm_write_scr_el3_bit(NON_SECURE, SCR_RW_BITPOS, !x2);
+
+		INFO("CPU switched to AARCH%s mode\n",
+			(x2 == NS_SWITCH_AARCH32) ? "32" : "64");
+		return 0;
+
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		break;
+	}
+
+	return -ENOTSUP;
+}
diff --git a/plat/nvidia/tegra/soc/t132/platform_t132.mk b/plat/nvidia/tegra/soc/t132/platform_t132.mk
new file mode 100644
index 0000000..bb7b7ee
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t132/platform_t132.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TZDRAM_BASE			:= 0xF5C00000
+$(eval $(call add_define,TZDRAM_BASE))
+
+PLATFORM_CLUSTER_COUNT		:= 1
+$(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
+
+PLATFORM_MAX_CPUS_PER_CLUSTER	:= 2
+$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
+
+MAX_XLAT_TABLES			:= 3
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS		:= 8
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
+BL31_SOURCES		+=	drivers/ti/uart/aarch64/16550_console.S		\
+				lib/cpus/aarch64/denver.S		\
+				${COMMON_DIR}/drivers/flowctrl/flowctrl.c	\
+				${COMMON_DIR}/drivers/memctrl/memctrl_v1.c	\
+				${SOC_DIR}/plat_psci_handlers.c		\
+				${SOC_DIR}/plat_sip_calls.c		\
+				${SOC_DIR}/plat_setup.c			\
+				${SOC_DIR}/plat_secondary.c
diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h b/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h
new file mode 100644
index 0000000..203f61a
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCE_PRIVATE_H
+#define MCE_PRIVATE_H
+
+#include <lib/mmio.h>
+
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * Macros to prepare CSTATE info request
+ ******************************************************************************/
+/* Description of the parameters for UPDATE_CSTATE_INFO request */
+#define CLUSTER_CSTATE_MASK			ULL(0x7)
+#define CLUSTER_CSTATE_SHIFT			U(0)
+#define CLUSTER_CSTATE_UPDATE_BIT		(ULL(1) << 7)
+#define CCPLEX_CSTATE_MASK			ULL(0x3)
+#define CCPLEX_CSTATE_SHIFT			ULL(8)
+#define CCPLEX_CSTATE_UPDATE_BIT		(ULL(1) << 15)
+#define SYSTEM_CSTATE_MASK			ULL(0xF)
+#define SYSTEM_CSTATE_SHIFT			ULL(16)
+#define SYSTEM_CSTATE_FORCE_UPDATE_SHIFT	ULL(22)
+#define SYSTEM_CSTATE_FORCE_UPDATE_BIT		(ULL(1) << 22)
+#define SYSTEM_CSTATE_UPDATE_BIT		(ULL(1) << 23)
+#define CSTATE_WAKE_MASK_UPDATE_BIT		(ULL(1) << 31)
+#define CSTATE_WAKE_MASK_SHIFT			ULL(32)
+#define CSTATE_WAKE_MASK_CLEAR			U(0xFFFFFFFF)
+
+/*******************************************************************************
+ * Auto-CC3 control macros
+ ******************************************************************************/
+#define MCE_AUTO_CC3_FREQ_MASK			U(0x1FF)
+#define MCE_AUTO_CC3_FREQ_SHIFT			U(0)
+#define MCE_AUTO_CC3_VTG_MASK			U(0x7F)
+#define MCE_AUTO_CC3_VTG_SHIFT			U(16)
+#define MCE_AUTO_CC3_ENABLE_BIT			(U(1) << 31)
+
+/*******************************************************************************
+ * Macros for the 'IS_SC7_ALLOWED' command
+ ******************************************************************************/
+#define MCE_SC7_ALLOWED_MASK			U(0x7)
+#define MCE_SC7_WAKE_TIME_SHIFT			U(32)
+
+/*******************************************************************************
+ * Macros for 'read/write ctats' commands
+ ******************************************************************************/
+#define MCE_CSTATE_STATS_TYPE_SHIFT		ULL(32)
+#define MCE_CSTATE_WRITE_DATA_LO_MASK		U(0xF)
+
+/*******************************************************************************
+ * Macros for 'update crossover threshold' command
+ ******************************************************************************/
+#define MCE_CROSSOVER_THRESHOLD_TIME_SHIFT	U(32)
+
+/*******************************************************************************
+ * MCA argument macros
+ ******************************************************************************/
+#define MCA_ARG_ERROR_MASK			U(0xFF)
+#define MCA_ARG_FINISH_SHIFT			U(24)
+#define MCA_ARG_FINISH_MASK			U(0xFF)
+
+/*******************************************************************************
+ * Uncore PERFMON ARI macros
+ ******************************************************************************/
+#define UNCORE_PERFMON_CMD_READ			U(0)
+#define UNCORE_PERFMON_CMD_WRITE		U(1)
+
+#define UNCORE_PERFMON_CMD_MASK			U(0xFF)
+#define UNCORE_PERFMON_UNIT_GRP_MASK		U(0xF)
+#define UNCORE_PERFMON_SELECTOR_MASK		U(0xF)
+#define UNCORE_PERFMON_REG_MASK			U(0xFF)
+#define UNCORE_PERFMON_CTR_MASK			U(0xFF)
+#define UNCORE_PERFMON_RESP_STATUS_MASK		U(0xFF)
+
+/*******************************************************************************
+ * Structure populated by arch specific code to export routines which perform
+ * common low level MCE functions
+ ******************************************************************************/
+typedef struct arch_mce_ops {
+	/*
+	 * This ARI request sets up the MCE to start execution on assertion
+	 * of STANDBYWFI, update the core power state and expected wake time,
+	 * then determine the proper power state to enter.
+	 */
+	int32_t (*enter_cstate)(uint32_t ari_base, uint32_t state,
+			    uint32_t wake_time);
+	/*
+	 * This ARI request allows updating of the CLUSTER_CSTATE,
+	 * CCPLEX_CSTATE, and SYSTEM_CSTATE register values.
+	 */
+	int32_t (*update_cstate_info)(uint32_t ari_base,
+				  uint32_t cluster,
+				  uint32_t ccplex,
+				  uint32_t system,
+				  uint8_t sys_state_force,
+				  uint32_t wake_mask,
+				  uint8_t update_wake_mask);
+	/*
+	 * This ARI request allows updating of power state crossover
+	 * threshold times. An index value specifies which crossover
+	 * state is being updated.
+	 */
+	int32_t (*update_crossover_time)(uint32_t ari_base,
+				     uint32_t type,
+				     uint32_t time);
+	/*
+	 * This ARI request allows read access to statistical information
+	 * related to power states.
+	 */
+	uint64_t (*read_cstate_stats)(uint32_t ari_base,
+				     uint32_t state);
+	/*
+	 * This ARI request allows write access to statistical information
+	 * related to power states.
+	 */
+	int32_t (*write_cstate_stats)(uint32_t ari_base,
+				  uint32_t state,
+				  uint32_t stats);
+	/*
+	 * This ARI request allows the CPU to understand the features
+	 * supported by the MCE firmware.
+	 */
+	uint64_t (*call_enum_misc)(uint32_t ari_base, uint32_t cmd,
+				   uint32_t data);
+	/*
+	 * This ARI request allows querying the CCPLEX to determine if
+	 * the CCx state is allowed given a target core C-state and wake
+	 * time. If the CCx state is allowed, the response indicates CCx
+	 * must be entered. If the CCx state is not allowed, the response
+	 * indicates CC6/CC7 can't be entered
+	 */
+	int32_t (*is_ccx_allowed)(uint32_t ari_base, uint32_t state,
+			      uint32_t wake_time);
+	/*
+	 * This ARI request allows querying the CCPLEX to determine if
+	 * the SC7 state is allowed given a target core C-state and wake
+	 * time. If the SC7 state is allowed, all cores but the associated
+	 * core are offlined (WAKE_EVENTS are set to 0) and the response
+	 * indicates SC7 must be entered. If the SC7 state is not allowed,
+	 * the response indicates SC7 can't be entered
+	 */
+	int32_t (*is_sc7_allowed)(uint32_t ari_base, uint32_t state,
+			      uint32_t wake_time);
+	/*
+	 * This ARI request allows a core to bring another offlined core
+	 * back online to the C0 state. Note that a core is offlined by
+	 * entering a C-state where the WAKE_MASK is all 0.
+	 */
+	int32_t (*online_core)(uint32_t ari_base, uint32_t cpuid);
+	/*
+	 * This ARI request allows the CPU to enable/disable Auto-CC3 idle
+	 * state.
+	 */
+	int32_t (*cc3_ctrl)(uint32_t ari_base,
+			uint32_t freq,
+			uint32_t volt,
+			uint8_t enable);
+	/*
+	 * This ARI request allows updating the reset vector register for
+	 * D15 and A57 CPUs.
+	 */
+	int32_t (*update_reset_vector)(uint32_t ari_base);
+	/*
+	 * This ARI request instructs the ROC to flush A57 data caches in
+	 * order to maintain coherency with the Denver cluster.
+	 */
+	int32_t (*roc_flush_cache)(uint32_t ari_base);
+	/*
+	 * This ARI request instructs the ROC to flush A57 data caches along
+	 * with the caches covering ARM code in order to maintain coherency
+	 * with the Denver cluster.
+	 */
+	int32_t (*roc_flush_cache_trbits)(uint32_t ari_base);
+	/*
+	 * This ARI request instructs the ROC to clean A57 data caches along
+	 * with the caches covering ARM code in order to maintain coherency
+	 * with the Denver cluster.
+	 */
+	int32_t (*roc_clean_cache)(uint32_t ari_base);
+	/*
+	 * This ARI request reads/writes the Machine Check Arch. (MCA)
+	 * registers.
+	 */
+	uint64_t (*read_write_mca)(uint32_t ari_base,
+			      uint64_t cmd,
+			      uint64_t *data);
+	/*
+	 * Some MC GSC (General Security Carveout) register values are
+	 * expected to be changed by TrustZone secure ARM code after boot.
+	 * Since there is no hardware mechanism for the CCPLEX to know
+	 * that an MC GSC register has changed to allow it to update its
+	 * own internal GSC register, there needs to be a mechanism that
+	 * can be used by ARM code to cause the CCPLEX to update its GSC
+	 * register value. This ARI request allows updating the GSC register
+	 * value for a certain carveout in the CCPLEX.
+	 */
+	int32_t (*update_ccplex_gsc)(uint32_t ari_base, uint32_t gsc_idx);
+	/*
+	 * This ARI request instructs the CCPLEX to either shutdown or
+	 * reset the entire system
+	 */
+	void (*enter_ccplex_state)(uint32_t ari_base, uint32_t state_idx);
+	/*
+	 * This ARI request reads/writes data from/to Uncore PERFMON
+	 * registers
+	 */
+	int32_t (*read_write_uncore_perfmon)(uint32_t ari_base,
+			uint64_t req, uint64_t *data);
+	/*
+	 * This ARI implements ARI_MISC_CCPLEX commands. This can be
+	 * used to enable/disable coresight clock gating.
+	 */
+	void (*misc_ccplex)(uint32_t ari_base, uint32_t index,
+			uint32_t value);
+} arch_mce_ops_t;
+
+/* declarations for ARI/NVG handler functions */
+int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time);
+int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
+	uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
+	uint8_t update_wake_mask);
+int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time);
+uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state);
+int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats);
+uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data);
+int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
+int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
+int32_t ari_online_core(uint32_t ari_base, uint32_t core);
+int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable);
+int32_t ari_reset_vector_update(uint32_t ari_base);
+int32_t ari_roc_flush_cache_trbits(uint32_t ari_base);
+int32_t ari_roc_flush_cache(uint32_t ari_base);
+int32_t ari_roc_clean_cache(uint32_t ari_base);
+uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data);
+int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx);
+void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx);
+int32_t ari_read_write_uncore_perfmon(uint32_t ari_base,
+		uint64_t req, uint64_t *data);
+void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value);
+
+int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time);
+int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
+		uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
+		uint8_t update_wake_mask);
+int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time);
+uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state);
+int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats);
+int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
+int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
+int32_t nvg_online_core(uint32_t ari_base, uint32_t core);
+int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable);
+
+extern void nvg_set_request_data(uint64_t req, uint64_t data);
+extern void nvg_set_request(uint64_t req);
+extern uint64_t nvg_get_result(void);
+#endif /* MCE_PRIVATE_H */
diff --git a/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h
new file mode 100644
index 0000000..ecfb3f4
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef T18X_ARI_H
+#define T18X_ARI_H
+
+/*
+ * ----------------------------------------------------------------------------
+ * t18x_ari.h
+ *
+ * Global ARI definitions.
+ * ----------------------------------------------------------------------------
+ */
+
+enum {
+	TEGRA_ARI_VERSION_MAJOR = 3U,
+	TEGRA_ARI_VERSION_MINOR = 1U,
+};
+
+typedef enum {
+	/* indexes below get the core lock */
+	TEGRA_ARI_MISC = 0U,
+	/* index 1 is deprecated */
+	/* index 2 is deprecated */
+	/* index 3 is deprecated */
+	TEGRA_ARI_ONLINE_CORE = 4U,
+
+	/* indexes below need cluster lock */
+	TEGRA_ARI_MISC_CLUSTER = 41U,
+	TEGRA_ARI_IS_CCX_ALLOWED = 42U,
+	TEGRA_ARI_CC3_CTRL = 43U,
+
+	/* indexes below need ccplex lock */
+	TEGRA_ARI_ENTER_CSTATE = 80U,
+	TEGRA_ARI_UPDATE_CSTATE_INFO = 81U,
+	TEGRA_ARI_IS_SC7_ALLOWED = 82U,
+	/* index 83 is deprecated */
+	TEGRA_ARI_PERFMON = 84U,
+	TEGRA_ARI_UPDATE_CCPLEX_GSC = 85U,
+	/* index 86 is depracated */
+	/* index 87 is deprecated */
+	TEGRA_ARI_ROC_FLUSH_CACHE_ONLY = 88U,
+	TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS = 89U,
+	TEGRA_ARI_MISC_CCPLEX = 90U,
+	TEGRA_ARI_MCA = 91U,
+	TEGRA_ARI_UPDATE_CROSSOVER = 92U,
+	TEGRA_ARI_CSTATE_STATS = 93U,
+	TEGRA_ARI_WRITE_CSTATE_STATS = 94U,
+	TEGRA_ARI_COPY_MISCREG_AA64_RST = 95U,
+	TEGRA_ARI_ROC_CLEAN_CACHE_ONLY = 96U,
+} tegra_ari_req_id_t;
+
+typedef enum {
+	TEGRA_ARI_MISC_ECHO = 0U,
+	TEGRA_ARI_MISC_VERSION = 1U,
+	TEGRA_ARI_MISC_FEATURE_LEAF_0 = 2U,
+} tegra_ari_misc_index_t;
+
+typedef enum {
+	TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF = 0U,
+	TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT = 1U,
+	TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL = 2U,
+	TEGRA_ARI_MISC_CCPLEX_EDBGREQ = 3U,
+} tegra_ari_misc_ccplex_index_t;
+
+typedef enum {
+	TEGRA_ARI_CORE_C0 = 0U,
+	TEGRA_ARI_CORE_C1 = 1U,
+	TEGRA_ARI_CORE_C6 = 6U,
+	TEGRA_ARI_CORE_C7 = 7U,
+	TEGRA_ARI_CORE_WARMRSTREQ = 8U,
+} tegra_ari_core_sleep_state_t;
+
+typedef enum {
+	TEGRA_ARI_CLUSTER_CC0 = 0U,
+	TEGRA_ARI_CLUSTER_CC1 = 1U,
+	TEGRA_ARI_CLUSTER_CC6 = 6U,
+	TEGRA_ARI_CLUSTER_CC7 = 7U,
+} tegra_ari_cluster_sleep_state_t;
+
+typedef enum {
+	TEGRA_ARI_CCPLEX_CCP0 = 0U,
+	TEGRA_ARI_CCPLEX_CCP1 = 1U,
+	TEGRA_ARI_CCPLEX_CCP3 = 3U,  /* obsoleted */
+} tegra_ari_ccplex_sleep_state_t;
+
+typedef enum {
+	TEGRA_ARI_SYSTEM_SC0 = 0U,
+	TEGRA_ARI_SYSTEM_SC1 = 1U,  /* obsoleted */
+	TEGRA_ARI_SYSTEM_SC2 = 2U,  /* obsoleted */
+	TEGRA_ARI_SYSTEM_SC3 = 3U,  /* obsoleted */
+	TEGRA_ARI_SYSTEM_SC4 = 4U,  /* obsoleted */
+	TEGRA_ARI_SYSTEM_SC7 = 7U,
+	TEGRA_ARI_SYSTEM_SC8 = 8U,
+} tegra_ari_system_sleep_state_t;
+
+typedef enum {
+	TEGRA_ARI_CROSSOVER_C1_C6 = 0U,
+	TEGRA_ARI_CROSSOVER_CC1_CC6 = 1U,
+	TEGRA_ARI_CROSSOVER_CC1_CC7 = 2U,
+	TEGRA_ARI_CROSSOVER_CCP1_CCP3 = 3U,  /* obsoleted */
+	TEGRA_ARI_CROSSOVER_CCP3_SC2 = 4U,  /* obsoleted */
+	TEGRA_ARI_CROSSOVER_CCP3_SC3 = 5U,  /* obsoleted */
+	TEGRA_ARI_CROSSOVER_CCP3_SC4 = 6U,  /* obsoleted */
+	TEGRA_ARI_CROSSOVER_CCP3_SC7 = 7U,  /* obsoleted */
+	TEGRA_ARI_CROSSOVER_SC0_SC7 = 7U,
+	TEGRA_ARI_CROSSOVER_CCP3_SC1 = 8U,  /* obsoleted */
+} tegra_ari_crossover_index_t;
+
+typedef enum {
+	TEGRA_ARI_CSTATE_STATS_CLEAR = 0U,
+	TEGRA_ARI_CSTATE_STATS_SC7_ENTRIES = 1U,
+	TEGRA_ARI_CSTATE_STATS_SC4_ENTRIES, /* obsoleted */
+	TEGRA_ARI_CSTATE_STATS_SC3_ENTRIES, /* obsoleted */
+	TEGRA_ARI_CSTATE_STATS_SC2_ENTRIES, /* obsoleted */
+	TEGRA_ARI_CSTATE_STATS_CCP3_ENTRIES, /* obsoleted */
+	TEGRA_ARI_CSTATE_STATS_A57_CC6_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_A57_CC7_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_D15_CC6_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_D15_CC7_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_D15_0_C6_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_D15_1_C6_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_D15_0_C7_ENTRIES = 14U,
+	TEGRA_ARI_CSTATE_STATS_D15_1_C7_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_A57_0_C7_ENTRIES = 18U,
+	TEGRA_ARI_CSTATE_STATS_A57_1_C7_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_A57_2_C7_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_A57_3_C7_ENTRIES,
+	TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0,
+	TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1,
+	TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 26U,
+	TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1,
+	TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2,
+	TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3,
+} tegra_ari_cstate_stats_index_t;
+
+typedef enum {
+	TEGRA_ARI_GSC_ALL = 0U,
+	TEGRA_ARI_GSC_BPMP = 6U,
+	TEGRA_ARI_GSC_APE = 7U,
+	TEGRA_ARI_GSC_SPE = 8U,
+	TEGRA_ARI_GSC_SCE = 9U,
+	TEGRA_ARI_GSC_APR = 10U,
+	TEGRA_ARI_GSC_TZRAM = 11U,
+	TEGRA_ARI_GSC_SE = 12U,
+	TEGRA_ARI_GSC_BPMP_TO_SPE = 16U,
+	TEGRA_ARI_GSC_SPE_TO_BPMP = 17U,
+	TEGRA_ARI_GSC_CPU_TZ_TO_BPMP = 18U,
+	TEGRA_ARI_GSC_BPMP_TO_CPU_TZ = 19U,
+	TEGRA_ARI_GSC_CPU_NS_TO_BPMP = 20U,
+	TEGRA_ARI_GSC_BPMP_TO_CPU_NS = 21U,
+	TEGRA_ARI_GSC_IPC_SE_SPE_SCE_BPMP = 22U,
+	TEGRA_ARI_GSC_SC7_RESUME_FW = 23U,
+	TEGRA_ARI_GSC_TZ_DRAM_IDX = 34U,
+	TEGRA_ARI_GSC_VPR_IDX = 35U,
+} tegra_ari_gsc_index_t;
+
+/* This macro will produce enums for __name##_LSB, __name##_MSB and __name##_MSK */
+#define TEGRA_ARI_ENUM_MASK_LSB_MSB(__name, __lsb, __msb) __name##_LSB = __lsb, __name##_MSB = __msb
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE, 0U, 2U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE_PRESENT, 7U, 7U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE, 8U, 9U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE_PRESENT, 15U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE, 16U, 19U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__IGNORE_CROSSOVERS, 22U, 22U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE_PRESENT, 23U, 23U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__WAKE_MASK_PRESENT, 31U, 31U),
+} tegra_ari_update_cstate_info_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL__EN, 0U, 0U),
+} tegra_ari_misc_ccplex_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_FREQ, 0U, 8U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_VOLT, 16U, 23U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__ENABLE, 31U, 31U),
+} tegra_ari_cc3_ctrl_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_MCA_NOP = 0U,
+	TEGRA_ARI_MCA_READ_SERR = 1U,
+	TEGRA_ARI_MCA_WRITE_SERR = 2U,
+	TEGRA_ARI_MCA_CLEAR_SERR = 4U,
+	TEGRA_ARI_MCA_REPORT_SERR = 5U,
+	TEGRA_ARI_MCA_READ_INTSTS = 6U,
+	TEGRA_ARI_MCA_WRITE_INTSTS = 7U,
+	TEGRA_ARI_MCA_READ_PREBOOT_SERR = 8U,
+} tegra_ari_mca_commands_t;
+
+typedef enum {
+	TEGRA_ARI_MCA_RD_WR_DPMU = 0U,
+	TEGRA_ARI_MCA_RD_WR_IOB = 1U,
+	TEGRA_ARI_MCA_RD_WR_MCB = 2U,
+	TEGRA_ARI_MCA_RD_WR_CCE = 3U,
+	TEGRA_ARI_MCA_RD_WR_CQX = 4U,
+	TEGRA_ARI_MCA_RD_WR_CTU = 5U,
+	TEGRA_ARI_MCA_RD_WR_JSR_MTS = 7U,
+	TEGRA_ARI_MCA_RD_BANK_INFO = 0x0fU,
+	TEGRA_ARI_MCA_RD_BANK_TEMPLATE = 0x10U,
+	TEGRA_ARI_MCA_RD_WR_SECURE_ACCESS_REGISTER = 0x11U,
+	TEGRA_ARI_MCA_RD_WR_GLOBAL_CONFIG_REGISTER = 0x12U,
+} tegra_ari_mca_rd_wr_indexes_t;
+
+typedef enum {
+	TEGRA_ARI_MCA_RD_WR_ASERRX_CTRL = 0U,
+	TEGRA_ARI_MCA_RD_WR_ASERRX_STATUS = 1U,
+	TEGRA_ARI_MCA_RD_WR_ASERRX_ADDR = 2U,
+	TEGRA_ARI_MCA_RD_WR_ASERRX_MISC1 = 3U,
+	TEGRA_ARI_MCA_RD_WR_ASERRX_MISC2 = 4U,
+} tegra_ari_mca_read_asserx_subindexes_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_SETTING_ENABLES_NS_PERMITTED, 0U, 0U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_READING_STATUS_NS_PERMITTED, 1U, 1U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_PENDING_MCA_ERRORS_NS_PERMITTED, 2U, 2U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_CLEARING_MCA_INTERRUPTS_NS_PERMITTED, 3U, 3U),
+} tegra_ari_mca_secure_register_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM_ERR, 16U, 16U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_CRAB_ERR, 17U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_RD_WR_N, 18U, 18U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UCODE_ERR, 19U, 19U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM, 20U, 23U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_ADDR, 0U, 41U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_UCODE_ERRCD, 42U, 52U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_PWM_ERR, 0U, 0U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_CRAB_ERR, 1U, 1U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_UCODE_ERR, 3U, 3U),
+} tegra_ari_mca_aserr0_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MSI_ERR, 16U, 16U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_IHI_ERR, 17U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CRI_ERR, 18U, 18U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MMCRAB_ERR, 19U, 19U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CSI_ERR, 20U, 20U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RD_WR_N, 21U, 21U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_REQ_ERRT, 22U, 23U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RESP_ERRT, 24U, 25U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AXI_ID, 0U, 7U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_ID, 8U, 27U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CID, 28U, 31U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CMD, 32U, 35U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MSI_ERR, 0U, 0U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_IHI_ERR, 1U, 1U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CRI_ERR, 2U, 2U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MMCRAB_ERR, 3U, 3U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CSI_ERR, 4U, 4U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_MISC_ADDR, 0U, 41U),
+} tegra_ari_mca_aserr1_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MC_ERR, 16U, 16U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SYSRAM_ERR, 17U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_CLIENT_ID, 18U, 19U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ID, 0U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_CMD, 18U, 21U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ADDR, 22U, 53U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_CTRL_EN_MC_ERR, 0U, 0U),
+} tegra_ari_mca_aserr2_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_TO_ERR, 16U, 16U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_STAT_ERR, 17U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_DST_ERR, 18U, 18U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UNC_ERR, 19U, 19U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MH_ERR, 20U, 20U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PERR, 21U, 21U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PSN_ERR, 22U, 22U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_CMD, 0U, 5U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_ADDR, 6U, 47U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TO, 0U, 0U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_DIV4, 1U, 1U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TLIMIT, 2U, 11U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_PSN_ERR_CORR_MSK, 12U, 25U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_MORE_INFO, 0U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TO_INFO, 18U, 43U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_SRC, 44U, 45U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TID, 46U, 52U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_TO_ERR, 0U, 0U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_STAT_ERR, 1U, 1U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_DST_ERR, 2U, 2U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_UNC_ERR, 3U, 3U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_MH_ERR, 4U, 4U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PERR, 5U, 5U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PSN_ERR, 6U, 19U),
+} tegra_ari_mca_aserr3_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SRC_ERR, 16U, 16U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_DST_ERR, 17U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_REQ_ERR, 18U, 18U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_RSP_ERR, 19U, 19U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_CTRL_EN_CPE_ERR, 0U, 0U),
+} tegra_ari_mca_aserr4_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_CTUPAR, 16U, 16U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MULTI, 17U, 17U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_SRC, 0U, 7U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ID, 8U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_DATA, 16U, 26U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_CMD, 32U, 35U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ADDR, 36U, 45U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_CTRL_EN_CTUPAR, 0U, 0U),
+} tegra_ari_mca_aserr5_bitmasks_t;
+
+typedef enum {
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_SERR_ERR_CODE, 0U, 15U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_AV, 58U, 58U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_MV, 59U, 59U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_EN, 60U, 60U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_UC, 61U, 61U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_OVF, 62U, 62U),
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_VAL, 63U, 63U),
+
+	TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_ADDR_TBD_INFO, 0U, 63U),
+} tegra_ari_mca_serr1_bitmasks_t;
+
+#undef TEGRA_ARI_ENUM_MASK_LSB_MSB
+
+typedef enum {
+	TEGRA_NVG_CHANNEL_PMIC = 0U,
+	TEGRA_NVG_CHANNEL_POWER_PERF = 1U,
+	TEGRA_NVG_CHANNEL_POWER_MODES = 2U,
+	TEGRA_NVG_CHANNEL_WAKE_TIME = 3U,
+	TEGRA_NVG_CHANNEL_CSTATE_INFO = 4U,
+	TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 = 5U,
+	TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC6 = 6U,
+	TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC7 = 7U,
+	TEGRA_NVG_CHANNEL_CROSSOVER_CCP1_CCP3 = 8U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC2 = 9U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC3 = 10U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC4 = 11U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC7 = 12U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CROSSOVER_SC0_SC7 = 12U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR = 13U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_SC7_ENTRIES = 14U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_SC4_ENTRIES = 15U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_SC3_ENTRIES = 16U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_SC2_ENTRIES = 17U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_CCP3_ENTRIES = 18U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC6_ENTRIES = 19U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC7_ENTRIES = 20U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC6_ENTRIES = 21U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC7_ENTRIES = 22U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C6_ENTRIES = 23U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C6_ENTRIES = 24U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C6_ENTRIES = 25U, /* Reserved (for Denver15 core 2) */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C6_ENTRIES = 26U, /* Reserved (for Denver15 core 3) */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C7_ENTRIES = 27U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C7_ENTRIES = 28U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C7_ENTRIES = 29U, /* Reserved (for Denver15 core 2) */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C7_ENTRIES = 30U, /*  Reserved (for Denver15 core 3) */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_0_C7_ENTRIES = 31U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_1_C7_ENTRIES = 32U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_2_C7_ENTRIES = 33U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_3_C7_ENTRIES = 34U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0 = 35U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1 = 36U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_2 = 37U, /* Reserved (for Denver15 core 2) */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_3 = 38U, /*  Reserved (for Denver15 core 3) */
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 39U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1 = 40U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2 = 41U,
+	TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3 = 42U,
+	TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = 43U,
+	TEGRA_NVG_CHANNEL_ONLINE_CORE = 44U,
+	TEGRA_NVG_CHANNEL_CC3_CTRL = 45U,
+	TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC1 = 46U,  /* obsoleted */
+	TEGRA_NVG_CHANNEL_LAST_INDEX,
+} tegra_nvg_channel_id_t;
+
+#endif /* T18X_ARI_H */
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S
new file mode 100644
index 0000000..e3591ce
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	nvg_set_request_data
+	.globl	nvg_set_request
+	.globl	nvg_get_result
+
+/* void nvg_set_request_data(uint64_t req, uint64_t data) */
+func nvg_set_request_data
+	msr	s3_0_c15_c1_2, x0
+	msr	s3_0_c15_c1_3, x1
+	ret
+endfunc nvg_set_request_data
+
+/* void nvg_set_request(uint64_t req) */
+func nvg_set_request
+	msr	s3_0_c15_c1_2, x0
+	ret
+endfunc nvg_set_request
+
+/* uint64_t nvg_get_result(void) */
+func nvg_get_result
+	mrs	x0, s3_0_c15_c1_3
+	ret
+endfunc nvg_get_result
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
new file mode 100644
index 0000000..a57bc11
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <denver.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <mce_private.h>
+#include <t18x_ari.h>
+
+/*******************************************************************************
+ * Register offsets for ARI request/results
+ ******************************************************************************/
+#define ARI_REQUEST			0x0U
+#define ARI_REQUEST_EVENT_MASK		0x4U
+#define ARI_STATUS			0x8U
+#define ARI_REQUEST_DATA_LO		0xCU
+#define ARI_REQUEST_DATA_HI		0x10U
+#define ARI_RESPONSE_DATA_LO		0x14U
+#define ARI_RESPONSE_DATA_HI		0x18U
+
+/* Status values for the current request */
+#define ARI_REQ_PENDING			1U
+#define ARI_REQ_ONGOING			3U
+#define ARI_REQUEST_VALID_BIT		(1U << 8)
+#define ARI_EVT_MASK_STANDBYWFI_BIT	(1U << 7)
+
+/* default timeout (us) to wait for ARI completion */
+#define ARI_MAX_RETRY_COUNT		U(2000000)
+
+/*******************************************************************************
+ * ARI helper functions
+ ******************************************************************************/
+static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg)
+{
+	return mmio_read_32((uint64_t)ari_base + (uint64_t)reg);
+}
+
+static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg)
+{
+	mmio_write_32((uint64_t)ari_base + (uint64_t)reg, val);
+}
+
+static inline uint32_t ari_get_request_low(uint32_t ari_base)
+{
+	return ari_read_32(ari_base, ARI_REQUEST_DATA_LO);
+}
+
+static inline uint32_t ari_get_request_high(uint32_t ari_base)
+{
+	return ari_read_32(ari_base, ARI_REQUEST_DATA_HI);
+}
+
+static inline uint32_t ari_get_response_low(uint32_t ari_base)
+{
+	return ari_read_32(ari_base, ARI_RESPONSE_DATA_LO);
+}
+
+static inline uint32_t ari_get_response_high(uint32_t ari_base)
+{
+	return ari_read_32(ari_base, ARI_RESPONSE_DATA_HI);
+}
+
+static inline void ari_clobber_response(uint32_t ari_base)
+{
+	ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_LO);
+	ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_HI);
+}
+
+static int32_t ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req,
+		uint32_t lo, uint32_t hi)
+{
+	uint32_t retries = (uint32_t)ARI_MAX_RETRY_COUNT;
+	uint32_t status;
+	int32_t ret = 0;
+
+	/* program the request, event_mask, hi and lo registers */
+	ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO);
+	ari_write_32(ari_base, hi, ARI_REQUEST_DATA_HI);
+	ari_write_32(ari_base, evt_mask, ARI_REQUEST_EVENT_MASK);
+	ari_write_32(ari_base, req | ARI_REQUEST_VALID_BIT, ARI_REQUEST);
+
+	/*
+	 * For commands that have an event trigger, we should bypass
+	 * ARI_STATUS polling, since MCE is waiting for SW to trigger
+	 * the event.
+	 */
+	if (evt_mask != 0U) {
+		ret = 0;
+	} else {
+		/* For shutdown/reboot commands, we dont have to check for timeouts */
+		if ((req == TEGRA_ARI_MISC_CCPLEX) &&
+		    ((lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) ||
+		     (lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) {
+				ret = 0;
+		} else {
+			/*
+			 * Wait for the command response for not more than the timeout
+			 */
+			while (retries != 0U) {
+
+				/* read the command status */
+				status = ari_read_32(ari_base, ARI_STATUS);
+				if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U) {
+					break;
+				}
+
+				/* delay 1 us */
+				udelay(1);
+
+				/* decrement the retry count */
+				retries--;
+			}
+
+			/* assert if the command timed out */
+			if (retries == 0U) {
+				ERROR("ARI request timed out: req %d on CPU %d\n",
+					req, plat_my_core_pos());
+				assert(retries != 0U);
+			}
+		}
+	}
+
+	return ret;
+}
+
+int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time)
+{
+	int32_t ret = 0;
+
+	/* check for allowed power state */
+	if ((state != TEGRA_ARI_CORE_C0) &&
+	    (state != TEGRA_ARI_CORE_C1) &&
+	    (state != TEGRA_ARI_CORE_C6) &&
+	    (state != TEGRA_ARI_CORE_C7)) {
+		ERROR("%s: unknown cstate (%d)\n", __func__, state);
+		ret = EINVAL;
+	} else {
+		/* clean the previous response state */
+		ari_clobber_response(ari_base);
+
+		/* Enter the cstate, to be woken up after wake_time (TSC ticks) */
+		ret = ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT,
+			(uint32_t)TEGRA_ARI_ENTER_CSTATE, state, wake_time);
+	}
+
+	return ret;
+}
+
+int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
+	uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
+	uint8_t update_wake_mask)
+{
+	uint64_t val = 0U;
+
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/* update CLUSTER_CSTATE? */
+	if (cluster != 0U) {
+		val |= (cluster & CLUSTER_CSTATE_MASK) |
+			CLUSTER_CSTATE_UPDATE_BIT;
+	}
+
+	/* update CCPLEX_CSTATE? */
+	if (ccplex != 0U) {
+		val |= ((ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
+			CCPLEX_CSTATE_UPDATE_BIT;
+	}
+
+	/* update SYSTEM_CSTATE? */
+	if (system != 0U) {
+		val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
+		       (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) |
+			SYSTEM_CSTATE_UPDATE_BIT);
+	}
+
+	/* update wake mask value? */
+	if (update_wake_mask != 0U) {
+		val |= CSTATE_WAKE_MASK_UPDATE_BIT;
+	}
+
+	/* set the updated cstate info */
+	return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CSTATE_INFO,
+				(uint32_t)val, wake_mask);
+}
+
+int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time)
+{
+	int32_t ret = 0;
+
+	/* sanity check crossover type */
+	if ((type == TEGRA_ARI_CROSSOVER_C1_C6) ||
+	    (type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) {
+		ret = EINVAL;
+	} else {
+		/* clean the previous response state */
+		ari_clobber_response(ari_base);
+
+		/* update crossover threshold time */
+		ret = ari_request_wait(ari_base, 0U,
+				(uint32_t)TEGRA_ARI_UPDATE_CROSSOVER, type, time);
+	}
+
+	return ret;
+}
+
+uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state)
+{
+	int32_t ret;
+	uint64_t result;
+
+	/* sanity check crossover type */
+	if (state == 0U) {
+		result = EINVAL;
+	} else {
+		/* clean the previous response state */
+		ari_clobber_response(ari_base);
+
+		ret = ari_request_wait(ari_base, 0U,
+				(uint32_t)TEGRA_ARI_CSTATE_STATS, state, 0U);
+		if (ret != 0) {
+			result = EINVAL;
+		} else {
+			result = (uint64_t)ari_get_response_low(ari_base);
+		}
+	}
+	return result;
+}
+
+int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats)
+{
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/* write the cstate stats */
+	return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_WRITE_CSTATE_STATS,
+			state, stats);
+}
+
+uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data)
+{
+	uint64_t resp;
+	int32_t ret;
+	uint32_t local_data = data;
+
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/* ARI_REQUEST_DATA_HI is reserved for commands other than 'ECHO' */
+	if (cmd != TEGRA_ARI_MISC_ECHO) {
+		local_data = 0U;
+	}
+
+	ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC, cmd, local_data);
+	if (ret != 0) {
+		resp = (uint64_t)ret;
+	} else {
+		/* get the command response */
+		resp = ari_get_response_low(ari_base);
+		resp |= ((uint64_t)ari_get_response_high(ari_base) << 32);
+	}
+
+	return resp;
+}
+
+int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
+{
+	int32_t ret;
+	uint32_t result;
+
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_IS_CCX_ALLOWED,
+			state & 0x7U, wake_time);
+	if (ret != 0) {
+		ERROR("%s: failed (%d)\n", __func__, ret);
+		result = 0U;
+	} else {
+		result = ari_get_response_low(ari_base) & 0x1U;
+	}
+
+	/* 1 = CCx allowed, 0 = CCx not allowed */
+	return (int32_t)result;
+}
+
+int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
+{
+	int32_t ret, result;
+
+	/* check for allowed power state */
+	if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
+	    (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
+		ERROR("%s: unknown cstate (%d)\n", __func__, state);
+		result = EINVAL;
+	} else {
+		/* clean the previous response state */
+		ari_clobber_response(ari_base);
+
+		ret = ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_IS_SC7_ALLOWED, state, wake_time);
+		if (ret != 0) {
+			ERROR("%s: failed (%d)\n", __func__, ret);
+			result = 0;
+		} else {
+			/* 1 = SC7 allowed, 0 = SC7 not allowed */
+			result = (ari_get_response_low(ari_base) != 0U) ? 1 : 0;
+		}
+	}
+
+	return result;
+}
+
+int32_t ari_online_core(uint32_t ari_base, uint32_t core)
+{
+	uint64_t cpu = read_mpidr() & (MPIDR_CPU_MASK);
+	uint64_t cluster = (read_mpidr() & (MPIDR_CLUSTER_MASK)) >>
+			   (MPIDR_AFFINITY_BITS);
+	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
+	int32_t ret;
+
+	/* construct the current CPU # */
+	cpu |= (cluster << 2);
+
+	/* sanity check target core id */
+	if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) {
+		ERROR("%s: unsupported core id (%d)\n", __func__, core);
+		ret = EINVAL;
+	} else {
+		/*
+		 * The Denver cluster has 2 CPUs only - 0, 1.
+		 */
+		if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) {
+			ERROR("%s: unknown core id (%d)\n", __func__, core);
+			ret = EINVAL;
+		} else {
+			/* clean the previous response state */
+			ari_clobber_response(ari_base);
+			ret = ari_request_wait(ari_base, 0U,
+				(uint32_t)TEGRA_ARI_ONLINE_CORE, core, 0U);
+		}
+	}
+
+	return ret;
+}
+
+int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable)
+{
+	uint32_t val;
+
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/*
+	 * If the enable bit is cleared, Auto-CC3 will be disabled by setting
+	 * the SW visible voltage/frequency request registers for all non
+	 * floorswept cores valid independent of StandbyWFI and disabling
+	 * the IDLE voltage/frequency request register. If set, Auto-CC3
+	 * will be enabled by setting the ARM SW visible voltage/frequency
+	 * request registers for all non floorswept cores to be enabled by
+	 * StandbyWFI or the equivalent signal, and always keeping the IDLE
+	 * voltage/frequency request register enabled.
+	 */
+	val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\
+		((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\
+		((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
+
+	return ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_CC3_CTRL, val, 0U);
+}
+
+int32_t ari_reset_vector_update(uint32_t ari_base)
+{
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/*
+	 * Need to program the CPU reset vector one time during cold boot
+	 * and SC7 exit
+	 */
+	(void)ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_COPY_MISCREG_AA64_RST, 0U, 0U);
+
+	return 0;
+}
+
+int32_t ari_roc_flush_cache_trbits(uint32_t ari_base)
+{
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	return ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS, 0U, 0U);
+}
+
+int32_t ari_roc_flush_cache(uint32_t ari_base)
+{
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	return ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_ONLY, 0U, 0U);
+}
+
+int32_t ari_roc_clean_cache(uint32_t ari_base)
+{
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	return ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_ROC_CLEAN_CACHE_ONLY, 0U, 0U);
+}
+
+uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data)
+{
+	uint64_t mca_arg_data, result = 0;
+	uint32_t resp_lo, resp_hi;
+	uint32_t mca_arg_err, mca_arg_finish;
+	int32_t ret;
+
+	/* Set data (write) */
+	mca_arg_data = (data != NULL) ? *data : 0ULL;
+
+	/* Set command */
+	ari_write_32(ari_base, (uint32_t)cmd, ARI_RESPONSE_DATA_LO);
+	ari_write_32(ari_base, (uint32_t)(cmd >> 32U), ARI_RESPONSE_DATA_HI);
+
+	ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MCA,
+			       (uint32_t)mca_arg_data,
+			       (uint32_t)(mca_arg_data >> 32U));
+	if (ret == 0) {
+		resp_lo = ari_get_response_low(ari_base);
+		resp_hi = ari_get_response_high(ari_base);
+
+		mca_arg_err = resp_lo & MCA_ARG_ERROR_MASK;
+		mca_arg_finish = (resp_hi >> MCA_ARG_FINISH_SHIFT) &
+				 MCA_ARG_FINISH_MASK;
+
+		if (mca_arg_finish == 0U) {
+			result = (uint64_t)mca_arg_err;
+		} else {
+			if (data != NULL) {
+				resp_lo = ari_get_request_low(ari_base);
+				resp_hi = ari_get_request_high(ari_base);
+				*data = ((uint64_t)resp_hi << 32U) |
+					 (uint64_t)resp_lo;
+			}
+		}
+	}
+
+	return result;
+}
+
+int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx)
+{
+	int32_t ret = 0;
+	/* sanity check GSC ID */
+	if (gsc_idx > TEGRA_ARI_GSC_VPR_IDX) {
+		ret = EINVAL;
+	} else {
+		/* clean the previous response state */
+		ari_clobber_response(ari_base);
+
+		/*
+		 * The MCE code will read the GSC carveout value, corrseponding to
+		 * the ID, from the MC registers and update the internal GSC registers
+		 * of the CCPLEX.
+		 */
+		(void)ari_request_wait(ari_base, 0U,
+				(uint32_t)TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0U);
+	}
+
+	return ret;
+}
+
+void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx)
+{
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/*
+	 * The MCE will shutdown or restart the entire system
+	 */
+	(void)ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_MISC_CCPLEX, state_idx, 0U);
+}
+
+int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req,
+		uint64_t *data)
+{
+	int32_t ret, result;
+	uint32_t val, req_status;
+	uint8_t req_cmd;
+
+	req_cmd = (uint8_t)(req & UNCORE_PERFMON_CMD_MASK);
+
+	/* clean the previous response state */
+	ari_clobber_response(ari_base);
+
+	/* sanity check input parameters */
+	if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) {
+		ERROR("invalid parameters\n");
+		result = EINVAL;
+	} else {
+		/*
+		 * For "write" commands get the value that has to be written
+		 * to the uncore perfmon registers
+		 */
+		val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ?
+			(uint32_t)*data : 0U;
+
+		ret = ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_PERFMON, val, (uint32_t)req);
+		if (ret != 0) {
+			result = ret;
+		} else {
+			/* read the command status value */
+			req_status = ari_get_response_high(ari_base) &
+					 UNCORE_PERFMON_RESP_STATUS_MASK;
+
+			/*
+			 * For "read" commands get the data from the uncore
+			 * perfmon registers
+			 */
+			req_status &= UNCORE_PERFMON_RESP_STATUS_MASK;
+			if ((req_status == 0U) && (req_cmd == UNCORE_PERFMON_CMD_READ)) {
+				*data = ari_get_response_low(ari_base);
+			}
+			result = (int32_t)req_status;
+		}
+	}
+
+	return result;
+}
+
+void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value)
+{
+	/*
+	 * This invokes the ARI_MISC_CCPLEX commands. This can be
+	 * used to enable/disable coresight clock gating.
+	 */
+
+	if ((index > TEGRA_ARI_MISC_CCPLEX_EDBGREQ) ||
+		((index == TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL) &&
+		(value > 1U))) {
+		ERROR("%s: invalid parameters \n", __func__);
+	} else {
+		/* clean the previous response state */
+		ari_clobber_response(ari_base);
+		(void)ari_request_wait(ari_base, 0U,
+			(uint32_t)TEGRA_ARI_MISC_CCPLEX, index, value);
+	}
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
new file mode 100644
index 0000000..9e42b2b
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/mmio.h>
+
+#include <mce.h>
+#include <mce_private.h>
+#include <t18x_ari.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+
+/* NVG functions handlers */
+static arch_mce_ops_t nvg_mce_ops = {
+	.enter_cstate = nvg_enter_cstate,
+	.update_cstate_info = nvg_update_cstate_info,
+	.update_crossover_time = nvg_update_crossover_time,
+	.read_cstate_stats = nvg_read_cstate_stats,
+	.write_cstate_stats = nvg_write_cstate_stats,
+	.call_enum_misc = ari_enumeration_misc,
+	.is_ccx_allowed = nvg_is_ccx_allowed,
+	.is_sc7_allowed = nvg_is_sc7_allowed,
+	.online_core = nvg_online_core,
+	.cc3_ctrl = nvg_cc3_ctrl,
+	.update_reset_vector = ari_reset_vector_update,
+	.roc_flush_cache = ari_roc_flush_cache,
+	.roc_flush_cache_trbits = ari_roc_flush_cache_trbits,
+	.roc_clean_cache = ari_roc_clean_cache,
+	.read_write_mca = ari_read_write_mca,
+	.update_ccplex_gsc = ari_update_ccplex_gsc,
+	.enter_ccplex_state = ari_enter_ccplex_state,
+	.read_write_uncore_perfmon = ari_read_write_uncore_perfmon,
+	.misc_ccplex = ari_misc_ccplex
+};
+
+/* ARI functions handlers */
+static arch_mce_ops_t ari_mce_ops = {
+	.enter_cstate = ari_enter_cstate,
+	.update_cstate_info = ari_update_cstate_info,
+	.update_crossover_time = ari_update_crossover_time,
+	.read_cstate_stats = ari_read_cstate_stats,
+	.write_cstate_stats = ari_write_cstate_stats,
+	.call_enum_misc = ari_enumeration_misc,
+	.is_ccx_allowed = ari_is_ccx_allowed,
+	.is_sc7_allowed = ari_is_sc7_allowed,
+	.online_core = ari_online_core,
+	.cc3_ctrl = ari_cc3_ctrl,
+	.update_reset_vector = ari_reset_vector_update,
+	.roc_flush_cache = ari_roc_flush_cache,
+	.roc_flush_cache_trbits = ari_roc_flush_cache_trbits,
+	.roc_clean_cache = ari_roc_clean_cache,
+	.read_write_mca = ari_read_write_mca,
+	.update_ccplex_gsc = ari_update_ccplex_gsc,
+	.enter_ccplex_state = ari_enter_ccplex_state,
+	.read_write_uncore_perfmon = ari_read_write_uncore_perfmon,
+	.misc_ccplex = ari_misc_ccplex
+};
+
+typedef struct {
+	uint32_t ari_base;
+	arch_mce_ops_t *ops;
+} mce_config_t;
+
+/* Table to hold the per-CPU ARI base address and function handlers */
+static mce_config_t mce_cfg_table[MCE_ARI_APERTURES_MAX] = {
+	{
+		/* A57 Core 0 */
+		.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_0_OFFSET,
+		.ops = &ari_mce_ops,
+	},
+	{
+		/* A57 Core 1 */
+		.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_1_OFFSET,
+		.ops = &ari_mce_ops,
+	},
+	{
+		/* A57 Core 2 */
+		.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_2_OFFSET,
+		.ops = &ari_mce_ops,
+	},
+	{
+		/* A57 Core 3 */
+		.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_3_OFFSET,
+		.ops = &ari_mce_ops,
+	},
+	{
+		/* D15 Core 0 */
+		.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_4_OFFSET,
+		.ops = &nvg_mce_ops,
+	},
+	{
+		/* D15 Core 1 */
+		.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_5_OFFSET,
+		.ops = &nvg_mce_ops,
+	}
+};
+
+static uint32_t mce_get_curr_cpu_ari_base(void)
+{
+	uint64_t mpidr = read_mpidr();
+	uint64_t cpuid = mpidr & MPIDR_CPU_MASK;
+	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
+
+	/*
+	 * T186 has 2 CPU clusters, one with Denver CPUs and the other with
+	 * ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU
+	 * numbers start from 0. In order to get the proper arch_mce_ops_t
+	 * struct, we have to convert the Denver CPU ids to the corresponding
+	 * indices in the mce_ops_table array.
+	 */
+	if (impl == DENVER_IMPL) {
+		cpuid |= 0x4U;
+	}
+
+	return mce_cfg_table[cpuid].ari_base;
+}
+
+static arch_mce_ops_t *mce_get_curr_cpu_ops(void)
+{
+	uint64_t mpidr = read_mpidr();
+	uint64_t cpuid = mpidr & MPIDR_CPU_MASK;
+	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) &
+			MIDR_IMPL_MASK;
+
+	/*
+	 * T186 has 2 CPU clusters, one with Denver CPUs and the other with
+	 * ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU
+	 * numbers start from 0. In order to get the proper arch_mce_ops_t
+	 * struct, we have to convert the Denver CPU ids to the corresponding
+	 * indices in the mce_ops_table array.
+	 */
+	if (impl == DENVER_IMPL) {
+		cpuid |= 0x4U;
+	}
+
+	return mce_cfg_table[cpuid].ops;
+}
+
+/*******************************************************************************
+ * Common handler for all MCE commands
+ ******************************************************************************/
+int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1,
+			uint64_t arg2)
+{
+	const arch_mce_ops_t *ops;
+	gp_regs_t *gp_regs = get_gpregs_ctx(cm_get_context(NON_SECURE));
+	uint32_t cpu_ari_base;
+	uint64_t ret64 = 0, arg3, arg4, arg5;
+	int32_t ret = 0;
+
+	assert(gp_regs != NULL);
+
+	/* get a pointer to the CPU's arch_mce_ops_t struct */
+	ops = mce_get_curr_cpu_ops();
+
+	/* get the CPU's ARI base address */
+	cpu_ari_base = mce_get_curr_cpu_ari_base();
+
+	switch (cmd) {
+	case (uint64_t)MCE_CMD_ENTER_CSTATE:
+		ret = ops->enter_cstate(cpu_ari_base, arg0, arg1);
+
+		break;
+
+	case (uint64_t)MCE_CMD_UPDATE_CSTATE_INFO:
+		/*
+		 * get the parameters required for the update cstate info
+		 * command
+		 */
+		arg3 = read_ctx_reg(gp_regs, CTX_GPREG_X4);
+		arg4 = read_ctx_reg(gp_regs, CTX_GPREG_X5);
+		arg5 = read_ctx_reg(gp_regs, CTX_GPREG_X6);
+
+		ret = ops->update_cstate_info(cpu_ari_base, (uint32_t)arg0,
+				(uint32_t)arg1, (uint32_t)arg2, (uint8_t)arg3,
+				(uint32_t)arg4, (uint8_t)arg5);
+
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, (0ULL));
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, (0ULL));
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, (0ULL));
+
+		break;
+
+	case (uint64_t)MCE_CMD_UPDATE_CROSSOVER_TIME:
+		ret = ops->update_crossover_time(cpu_ari_base, arg0, arg1);
+
+		break;
+
+	case (uint64_t)MCE_CMD_READ_CSTATE_STATS:
+		ret64 = ops->read_cstate_stats(cpu_ari_base, arg0);
+
+		/* update context to return cstate stats value */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
+		write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64));
+
+		break;
+
+	case (uint64_t)MCE_CMD_WRITE_CSTATE_STATS:
+		ret = ops->write_cstate_stats(cpu_ari_base, arg0, arg1);
+
+		break;
+
+	case (uint64_t)MCE_CMD_IS_CCX_ALLOWED:
+		ret = ops->is_ccx_allowed(cpu_ari_base, arg0, arg1);
+
+		/* update context to return CCx status value */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret));
+
+		break;
+
+	case (uint64_t)MCE_CMD_IS_SC7_ALLOWED:
+		ret = ops->is_sc7_allowed(cpu_ari_base, arg0, arg1);
+
+		/* update context to return SC7 status value */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret));
+		write_ctx_reg(gp_regs, CTX_GPREG_X3, (uint64_t)(ret));
+
+		break;
+
+	case (uint64_t)MCE_CMD_ONLINE_CORE:
+		ret = ops->online_core(cpu_ari_base, arg0);
+
+		break;
+
+	case (uint64_t)MCE_CMD_CC3_CTRL:
+		ret = ops->cc3_ctrl(cpu_ari_base, arg0, arg1, arg2);
+
+		break;
+
+	case (uint64_t)MCE_CMD_ECHO_DATA:
+		ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_ECHO,
+				arg0);
+
+		/* update context to return if echo'd data matched source */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, ((ret64 == arg0) ?
+			      1ULL : 0ULL));
+		write_ctx_reg(gp_regs, CTX_GPREG_X2, ((ret64 == arg0) ?
+			      1ULL : 0ULL));
+
+		break;
+
+	case (uint64_t)MCE_CMD_READ_VERSIONS:
+		ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION,
+			arg0);
+
+		/*
+		 * version = minor(63:32) | major(31:0). Update context
+		 * to return major and minor version number.
+		 */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
+		write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64 >> 32ULL));
+
+		break;
+
+	case (uint64_t)MCE_CMD_ENUM_FEATURES:
+		ret64 = ops->call_enum_misc(cpu_ari_base,
+				TEGRA_ARI_MISC_FEATURE_LEAF_0, arg0);
+
+		/* update context to return features value */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
+
+		break;
+
+	case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE_TRBITS:
+		ret = ops->roc_flush_cache_trbits(cpu_ari_base);
+
+		break;
+
+	case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE:
+		ret = ops->roc_flush_cache(cpu_ari_base);
+
+		break;
+
+	case (uint64_t)MCE_CMD_ROC_CLEAN_CACHE:
+		ret = ops->roc_clean_cache(cpu_ari_base);
+
+		break;
+
+	case (uint64_t)MCE_CMD_ENUM_READ_MCA:
+		ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1);
+
+		/* update context to return MCA data/error */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
+		write_ctx_reg(gp_regs, CTX_GPREG_X2, (arg1));
+		write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64));
+
+		break;
+
+	case (uint64_t)MCE_CMD_ENUM_WRITE_MCA:
+		ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1);
+
+		/* update context to return MCA error */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
+		write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64));
+
+		break;
+
+#if ENABLE_CHIP_VERIFICATION_HARNESS
+	case (uint64_t)MCE_CMD_ENABLE_LATIC:
+		/*
+		 * This call is not for production use. The constant value,
+		 * 0xFFFF0000, is specific to allowing for enabling LATIC on
+		 * pre-production parts for the chip verification harness.
+		 *
+		 * Enabling LATIC allows S/W to read the MINI ISPs in the
+		 * CCPLEX. The ISMs are used for various measurements relevant
+		 * to particular locations in the Silicon. They are small
+		 * counters which can be polled to determine how fast a
+		 * particular location in the Silicon is.
+		 */
+		ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(),
+			0xFFFF0000);
+
+		break;
+#endif
+
+	case (uint64_t)MCE_CMD_UNCORE_PERFMON_REQ:
+		ret = ops->read_write_uncore_perfmon(cpu_ari_base, arg0, &arg1);
+
+		/* update context to return data */
+		write_ctx_reg(gp_regs, CTX_GPREG_X1, (arg1));
+		break;
+
+	case (uint64_t)MCE_CMD_MISC_CCPLEX:
+		ops->misc_ccplex(cpu_ari_base, arg0, arg1);
+
+		break;
+
+	default:
+		ERROR("unknown MCE command (%llu)\n", cmd);
+		ret = EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*******************************************************************************
+ * Handler to update the reset vector for CPUs
+ ******************************************************************************/
+int32_t mce_update_reset_vector(void)
+{
+	const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
+
+	ops->update_reset_vector(mce_get_curr_cpu_ari_base());
+
+	return 0;
+}
+
+static int32_t mce_update_ccplex_gsc(tegra_ari_gsc_index_t gsc_idx)
+{
+	const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
+
+	ops->update_ccplex_gsc(mce_get_curr_cpu_ari_base(), gsc_idx);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Handler to update carveout values for Video Memory Carveout region
+ ******************************************************************************/
+int32_t mce_update_gsc_videomem(void)
+{
+	return mce_update_ccplex_gsc(TEGRA_ARI_GSC_VPR_IDX);
+}
+
+/*******************************************************************************
+ * Handler to update carveout values for TZDRAM aperture
+ ******************************************************************************/
+int32_t mce_update_gsc_tzdram(void)
+{
+	return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZ_DRAM_IDX);
+}
+
+/*******************************************************************************
+ * Handler to update carveout values for TZ SysRAM aperture
+ ******************************************************************************/
+int32_t mce_update_gsc_tzram(void)
+{
+	return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZRAM);
+}
+
+/*******************************************************************************
+ * Handler to shutdown/reset the entire system
+ ******************************************************************************/
+__dead2 void mce_enter_ccplex_state(uint32_t state_idx)
+{
+	const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
+
+	/* sanity check state value */
+	if ((state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) &&
+	    (state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT)) {
+		panic();
+	}
+
+	ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(), state_idx);
+
+	/* wait till the CCPLEX powers down */
+	for (;;) {
+		;
+	}
+
+}
+
+/*******************************************************************************
+ * Handler to issue the UPDATE_CSTATE_INFO request
+ ******************************************************************************/
+void mce_update_cstate_info(const mce_cstate_info_t *cstate)
+{
+	const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
+
+	/* issue the UPDATE_CSTATE_INFO request */
+	ops->update_cstate_info(mce_get_curr_cpu_ari_base(), cstate->cluster,
+		cstate->ccplex, cstate->system, cstate->system_state_force,
+		cstate->wake_mask, cstate->update_wake_mask);
+}
+
+/*******************************************************************************
+ * Handler to read the MCE firmware version and check if it is compatible
+ * with interface header the BL3-1 was compiled against
+ ******************************************************************************/
+void mce_verify_firmware_version(void)
+{
+	const arch_mce_ops_t *ops;
+	uint32_t cpu_ari_base;
+	uint64_t version;
+	uint32_t major, minor;
+
+	/*
+	 * MCE firmware is not supported on simulation platforms.
+	 */
+	if (tegra_platform_is_emulation()) {
+
+		INFO("MCE firmware is not supported\n");
+
+	} else {
+		/* get a pointer to the CPU's arch_mce_ops_t struct */
+		ops = mce_get_curr_cpu_ops();
+
+		/* get the CPU's ARI base address */
+		cpu_ari_base = mce_get_curr_cpu_ari_base();
+
+		/*
+		 * Read the MCE firmware version and extract the major and minor
+		 * version fields
+		 */
+		version = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, 0);
+		major = (uint32_t)version;
+		minor = (uint32_t)(version >> 32);
+
+		INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor,
+			TEGRA_ARI_VERSION_MAJOR, TEGRA_ARI_VERSION_MINOR);
+
+		/*
+		 * Verify that the MCE firmware version and the interface header
+		 * match
+		 */
+		if (major != TEGRA_ARI_VERSION_MAJOR) {
+			ERROR("ARI major version mismatch\n");
+			panic();
+		}
+
+		if (minor < TEGRA_ARI_VERSION_MINOR) {
+			ERROR("ARI minor version mismatch\n");
+			panic();
+		}
+	}
+}
diff --git a/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c
new file mode 100644
index 0000000..cbc9aa3
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <denver.h>
+#include <lib/mmio.h>
+
+#include <mce_private.h>
+#include <t18x_ari.h>
+#include <tegra_private.h>
+
+int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time)
+{
+	int32_t ret = 0;
+	uint64_t val = 0ULL;
+
+	(void)ari_base;
+
+	/* check for allowed power state */
+	if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
+	    (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
+		ERROR("%s: unknown cstate (%d)\n", __func__, state);
+		ret = EINVAL;
+	} else {
+		/* time (TSC ticks) until the core is expected to get a wake event */
+		nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, wake_time);
+
+		/* set the core cstate */
+		val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK;
+		write_actlr_el1(val | (uint64_t)state);
+	}
+
+	return ret;
+}
+
+/*
+ * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and
+ * SYSTEM_CSTATE values.
+ */
+int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
+		uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
+		uint8_t update_wake_mask)
+{
+	uint64_t val = 0ULL;
+
+	(void)ari_base;
+
+	/* update CLUSTER_CSTATE? */
+	if (cluster != 0U) {
+		val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) |
+			CLUSTER_CSTATE_UPDATE_BIT;
+	}
+
+	/* update CCPLEX_CSTATE? */
+	if (ccplex != 0U) {
+		val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
+			CCPLEX_CSTATE_UPDATE_BIT;
+	}
+
+	/* update SYSTEM_CSTATE? */
+	if (system != 0U) {
+		val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
+		       (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) |
+			SYSTEM_CSTATE_UPDATE_BIT);
+	}
+
+	/* update wake mask value? */
+	if (update_wake_mask != 0U) {
+		val |= CSTATE_WAKE_MASK_UPDATE_BIT;
+	}
+
+	/* set the wake mask */
+	val &= CSTATE_WAKE_MASK_CLEAR;
+	val |= ((uint64_t)wake_mask << CSTATE_WAKE_MASK_SHIFT);
+
+	/* set the updated cstate info */
+	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val);
+
+	return 0;
+}
+
+int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time)
+{
+	int32_t ret = 0;
+
+	(void)ari_base;
+
+	/* sanity check crossover type */
+	if (type > TEGRA_ARI_CROSSOVER_CCP3_SC1) {
+		ret = EINVAL;
+	} else {
+		/*
+		 * The crossover threshold limit types start from
+		 * TEGRA_CROSSOVER_TYPE_C1_C6 to TEGRA_CROSSOVER_TYPE_CCP3_SC7.
+		 * The command indices for updating the threshold be generated
+		 * by adding the type to the NVG_SET_THRESHOLD_CROSSOVER_C1_C6
+		 * command index.
+		 */
+		nvg_set_request_data((TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 +
+			(uint64_t)type), (uint64_t)time);
+	}
+
+	return ret;
+}
+
+uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state)
+{
+	uint64_t ret;
+
+	(void)ari_base;
+
+	/* sanity check state */
+	if (state == 0U) {
+		ret = EINVAL;
+	} else {
+		/*
+		 * The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES
+		 * to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for
+		 * reading the threshold can be generated by adding the type to
+		 * the NVG_CLEAR_CSTATE_STATS command index.
+		 */
+		nvg_set_request((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR +
+				(uint64_t)state));
+		ret = nvg_get_result();
+	}
+
+	return ret;
+}
+
+int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats)
+{
+	uint64_t val;
+
+	(void)ari_base;
+
+	/*
+	 * The only difference between a CSTATE_STATS_WRITE and
+	 * CSTATE_STATS_READ is the usage of the 63:32 in the request.
+	 * 63:32 are set to '0' for a read, while a write contains the
+	 * actual stats value to be written.
+	 */
+	val = ((uint64_t)stats << MCE_CSTATE_STATS_TYPE_SHIFT) | state;
+
+	/*
+	 * The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES
+	 * to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for
+	 * reading the threshold can be generated by adding the type to
+	 * the NVG_CLEAR_CSTATE_STATS command index.
+	 */
+	nvg_set_request_data((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR +
+			     (uint64_t)state), val);
+
+	return 0;
+}
+
+int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
+{
+	(void)ari_base;
+	(void)state;
+	(void)wake_time;
+
+	/* This does not apply to the Denver cluster */
+	return 0;
+}
+
+int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
+{
+	uint64_t val;
+	int32_t ret;
+
+	(void)ari_base;
+
+	/* check for allowed power state */
+	if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
+	    (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
+		ERROR("%s: unknown cstate (%d)\n", __func__, state);
+		ret = EINVAL;
+	} else {
+		/*
+		 * Request format -
+		 * 63:32 = wake time
+		 * 31:0 = C-state for this core
+		 */
+		val = ((uint64_t)wake_time << MCE_SC7_WAKE_TIME_SHIFT) |
+				((uint64_t)state & MCE_SC7_ALLOWED_MASK);
+
+		/* issue command to check if SC7 is allowed */
+		nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED, val);
+
+		/* 1 = SC7 allowed, 0 = SC7 not allowed */
+		ret = (nvg_get_result() != 0ULL) ? 1 : 0;
+	}
+
+	return ret;
+}
+
+int32_t nvg_online_core(uint32_t ari_base, uint32_t core)
+{
+	uint64_t cpu = read_mpidr() & MPIDR_CPU_MASK;
+	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
+	int32_t ret = 0;
+
+	(void)ari_base;
+
+	/* sanity check code id */
+	if ((core >= MCE_CORE_ID_MAX) || (cpu == core)) {
+		ERROR("%s: unsupported core id (%d)\n", __func__, core);
+		ret = EINVAL;
+	} else {
+		/*
+		 * The Denver cluster has 2 CPUs only - 0, 1.
+		 */
+		if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) {
+			ERROR("%s: unknown core id (%d)\n", __func__, core);
+			ret = EINVAL;
+		} else {
+			/* get a core online */
+			nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_ONLINE_CORE,
+				((uint64_t)core & MCE_CORE_ID_MASK));
+		}
+	}
+
+	return ret;
+}
+
+int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable)
+{
+	uint32_t val;
+
+	(void)ari_base;
+
+	/*
+	 * If the enable bit is cleared, Auto-CC3 will be disabled by setting
+	 * the SW visible voltage/frequency request registers for all non
+	 * floorswept cores valid independent of StandbyWFI and disabling
+	 * the IDLE voltage/frequency request register. If set, Auto-CC3
+	 * will be enabled by setting the ARM SW visible voltage/frequency
+	 * request registers for all non floorswept cores to be enabled by
+	 * StandbyWFI or the equivalent signal, and always keeping the IDLE
+	 * voltage/frequency request register enabled.
+	 */
+	val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\
+		((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\
+		((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
+
+	nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CC3_CTRL, (uint64_t)val);
+
+	return 0;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_memctrl.c b/plat/nvidia/tegra/soc/t186/plat_memctrl.c
new file mode 100644
index 0000000..df94396
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_memctrl.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+
+#include <mce.h>
+#include <memctrl_v2.h>
+#include <tegra_mc_def.h>
+#include <tegra_platform.h>
+
+/*******************************************************************************
+ * Array to hold stream_id override config register offsets
+ ******************************************************************************/
+const static uint32_t tegra186_streamid_override_regs[] = {
+	MC_STREAMID_OVERRIDE_CFG_PTCR,
+	MC_STREAMID_OVERRIDE_CFG_AFIR,
+	MC_STREAMID_OVERRIDE_CFG_HDAR,
+	MC_STREAMID_OVERRIDE_CFG_HOST1XDMAR,
+	MC_STREAMID_OVERRIDE_CFG_NVENCSRD,
+	MC_STREAMID_OVERRIDE_CFG_SATAR,
+	MC_STREAMID_OVERRIDE_CFG_MPCORER,
+	MC_STREAMID_OVERRIDE_CFG_NVENCSWR,
+	MC_STREAMID_OVERRIDE_CFG_AFIW,
+	MC_STREAMID_OVERRIDE_CFG_HDAW,
+	MC_STREAMID_OVERRIDE_CFG_MPCOREW,
+	MC_STREAMID_OVERRIDE_CFG_SATAW,
+	MC_STREAMID_OVERRIDE_CFG_ISPRA,
+	MC_STREAMID_OVERRIDE_CFG_ISPWA,
+	MC_STREAMID_OVERRIDE_CFG_ISPWB,
+	MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTR,
+	MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTW,
+	MC_STREAMID_OVERRIDE_CFG_XUSB_DEVR,
+	MC_STREAMID_OVERRIDE_CFG_XUSB_DEVW,
+	MC_STREAMID_OVERRIDE_CFG_TSECSRD,
+	MC_STREAMID_OVERRIDE_CFG_TSECSWR,
+	MC_STREAMID_OVERRIDE_CFG_GPUSRD,
+	MC_STREAMID_OVERRIDE_CFG_GPUSWR,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCRA,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCRAA,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCR,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCRAB,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCWA,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCWAA,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCW,
+	MC_STREAMID_OVERRIDE_CFG_SDMMCWAB,
+	MC_STREAMID_OVERRIDE_CFG_VICSRD,
+	MC_STREAMID_OVERRIDE_CFG_VICSWR,
+	MC_STREAMID_OVERRIDE_CFG_VIW,
+	MC_STREAMID_OVERRIDE_CFG_NVDECSRD,
+	MC_STREAMID_OVERRIDE_CFG_NVDECSWR,
+	MC_STREAMID_OVERRIDE_CFG_APER,
+	MC_STREAMID_OVERRIDE_CFG_APEW,
+	MC_STREAMID_OVERRIDE_CFG_NVJPGSRD,
+	MC_STREAMID_OVERRIDE_CFG_NVJPGSWR,
+	MC_STREAMID_OVERRIDE_CFG_SESRD,
+	MC_STREAMID_OVERRIDE_CFG_SESWR,
+	MC_STREAMID_OVERRIDE_CFG_ETRR,
+	MC_STREAMID_OVERRIDE_CFG_ETRW,
+	MC_STREAMID_OVERRIDE_CFG_TSECSRDB,
+	MC_STREAMID_OVERRIDE_CFG_TSECSWRB,
+	MC_STREAMID_OVERRIDE_CFG_GPUSRD2,
+	MC_STREAMID_OVERRIDE_CFG_GPUSWR2,
+	MC_STREAMID_OVERRIDE_CFG_AXISR,
+	MC_STREAMID_OVERRIDE_CFG_AXISW,
+	MC_STREAMID_OVERRIDE_CFG_EQOSR,
+	MC_STREAMID_OVERRIDE_CFG_EQOSW,
+	MC_STREAMID_OVERRIDE_CFG_UFSHCR,
+	MC_STREAMID_OVERRIDE_CFG_UFSHCW,
+	MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR,
+	MC_STREAMID_OVERRIDE_CFG_BPMPR,
+	MC_STREAMID_OVERRIDE_CFG_BPMPW,
+	MC_STREAMID_OVERRIDE_CFG_BPMPDMAR,
+	MC_STREAMID_OVERRIDE_CFG_BPMPDMAW,
+	MC_STREAMID_OVERRIDE_CFG_AONR,
+	MC_STREAMID_OVERRIDE_CFG_AONW,
+	MC_STREAMID_OVERRIDE_CFG_AONDMAR,
+	MC_STREAMID_OVERRIDE_CFG_AONDMAW,
+	MC_STREAMID_OVERRIDE_CFG_SCER,
+	MC_STREAMID_OVERRIDE_CFG_SCEW,
+	MC_STREAMID_OVERRIDE_CFG_SCEDMAR,
+	MC_STREAMID_OVERRIDE_CFG_SCEDMAW,
+	MC_STREAMID_OVERRIDE_CFG_APEDMAR,
+	MC_STREAMID_OVERRIDE_CFG_APEDMAW,
+	MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR1,
+	MC_STREAMID_OVERRIDE_CFG_VICSRD1,
+	MC_STREAMID_OVERRIDE_CFG_NVDECSRD1
+};
+
+/*******************************************************************************
+ * Array to hold the security configs for stream IDs
+ ******************************************************************************/
+const static mc_streamid_security_cfg_t tegra186_streamid_sec_cfgs[] = {
+	mc_make_sec_cfg(SCEW, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(AFIR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AFIW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVDISPLAYR1, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(XUSB_DEVR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(VICSRD1, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVENCSWR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(TSECSRDB, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AXISW, SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(SDMMCWAB, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AONDMAW, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(GPUSWR2, SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(SATAW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(UFSHCW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SDMMCR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SCEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(UFSHCR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SDMMCWAA, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SESWR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(MPCORER, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(PTCR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(BPMPW, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(ETRW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(GPUSRD, SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(VICSWR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SCEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(HDAW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(ISPWA, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(EQOSW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(XUSB_HOSTW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(TSECSWR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SDMMCRAA, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(VIW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AXISR, SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(SDMMCW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(BPMPDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(ISPRA, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVDECSWR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(XUSB_DEVW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVDECSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(MPCOREW, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVDISPLAYR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(BPMPDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(NVJPGSWR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVDECSRD1, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(TSECSRD, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVJPGSRD, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SDMMCWA, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SCER, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(XUSB_HOSTR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(VICSRD, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AONDMAR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AONW, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SDMMCRA, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(HOST1XDMAR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(EQOSR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SATAR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(BPMPR, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(HDAR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SDMMCRAB, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(ETRR, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(AONR, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(SESRD, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(NVENCSRD, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(GPUSWR, SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(TSECSWRB, NON_SECURE, NO_OVERRIDE, ENABLE),
+	mc_make_sec_cfg(ISPWB, NON_SECURE, OVERRIDE, ENABLE),
+	mc_make_sec_cfg(GPUSRD2, SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(APEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(APER, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(APEW, NON_SECURE, NO_OVERRIDE, DISABLE),
+	mc_make_sec_cfg(APEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
+};
+
+/*******************************************************************************
+ * Array to hold the transaction override configs
+ ******************************************************************************/
+const static mc_txn_override_cfg_t tegra186_txn_override_cfgs[] = {
+	mc_make_txn_override_cfg(BPMPW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(EQOSW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(NVJPGSWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SDMMCWAA, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(MPCOREW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SCEDMAW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SDMMCW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(AXISW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(TSECSWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(GPUSWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(XUSB_HOSTW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(TSECSWRB, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(GPUSWR2, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(AONDMAW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(AONW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SESWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(BPMPDMAW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SDMMCWA, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(HDAW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(NVDECSWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(UFSHCW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SATAW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(ETRW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(VICSWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(NVENCSWR, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SDMMCWAB, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(ISPWB, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(APEW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(XUSB_DEVW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(AFIW, CGID_TAG_ADR),
+	mc_make_txn_override_cfg(SCEW, CGID_TAG_ADR),
+};
+
+static void tegra186_memctrl_reconfig_mss_clients(void)
+{
+#if ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS
+	uint32_t val, wdata_0, wdata_1;
+
+	/*
+	 * Assert Memory Controller's HOTRESET_FLUSH_ENABLE signal for
+	 * boot and strongly ordered MSS clients to flush existing memory
+	 * traffic and stall future requests.
+	 */
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0);
+	assert(val == MC_CLIENT_HOTRESET_CTRL0_RESET_VAL);
+
+	wdata_0 = MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0);
+
+	/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
+	} while ((val & wdata_0) != wdata_0);
+
+	/* Wait one more time due to SW WAR for known legacy issue */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
+	} while ((val & wdata_0) != wdata_0);
+
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1);
+	assert(val == MC_CLIENT_HOTRESET_CTRL1_RESET_VAL);
+
+	wdata_1 = MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB |
+		  MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1);
+
+	/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
+	} while ((val & wdata_1) != wdata_1);
+
+	/* Wait one more time due to SW WAR for known legacy issue */
+	do {
+		val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
+	} while ((val & wdata_1) != wdata_1);
+
+	/*
+	 * Change MEMTYPE_OVERRIDE from SO_DEV -> PASSTHRU for boot and
+	 * strongly ordered MSS clients. ROC needs to be single point
+	 * of control on overriding the memory type. So, remove TSA's
+	 * memtype override.
+	 *
+	 * MC clients with default SO_DEV override still enabled at TSA:
+	 * AONW, BPMPW, SCEW, APEW
+	 */
+	mc_set_tsa_passthrough(AFIW);
+	mc_set_tsa_passthrough(HDAW);
+	mc_set_tsa_passthrough(SATAW);
+	mc_set_tsa_passthrough(XUSB_HOSTW);
+	mc_set_tsa_passthrough(XUSB_DEVW);
+	mc_set_tsa_passthrough(SDMMCWAB);
+	mc_set_tsa_passthrough(APEDMAW);
+	mc_set_tsa_passthrough(SESWR);
+	mc_set_tsa_passthrough(ETRW);
+	mc_set_tsa_passthrough(AXISW);
+	mc_set_tsa_passthrough(EQOSW);
+	mc_set_tsa_passthrough(UFSHCW);
+	mc_set_tsa_passthrough(BPMPDMAW);
+	mc_set_tsa_passthrough(AONDMAW);
+	mc_set_tsa_passthrough(SCEDMAW);
+
+	/* Parker has no IO Coherency support and need the following:
+	 * Ordered MC Clients on Parker are AFI, EQOS, SATA, XUSB.
+	 * ISO clients(DISP, VI, EQOS) should never snoop caches and
+	 *     don't need ROC/PCFIFO ordering.
+	 * ISO clients(EQOS) that need ordering should use PCFIFO ordering
+	 *     and bypass ROC ordering by using FORCE_NON_COHERENT path.
+	 * FORCE_NON_COHERENT/FORCE_COHERENT config take precedence
+	 *     over SMMU attributes.
+	 * Force all Normal memory transactions from ISO and non-ISO to be
+	 *     non-coherent(bypass ROC, avoid cache snoop to avoid perf hit).
+	 * Force the SO_DEV transactions from ordered ISO clients(EQOS) to
+	 *     non-coherent path and enable MC PCFIFO interlock for ordering.
+	 * Force the SO_DEV transactions from ordered non-ISO clients (PCIe,
+	 *     XUSB, SATA) to coherent so that the transactions are
+	 *     ordered by ROC.
+	 * PCFIFO ensure write ordering.
+	 * Read after Write ordering is maintained/enforced by MC clients.
+	 * Clients that need PCIe type write ordering must
+	 *     go through ROC ordering.
+	 * Ordering enable for Read clients is not necessary.
+	 * R5's and A9 would get necessary ordering from AXI and
+	 *     don't need ROC ordering enable:
+	 *     - MMIO ordering is through dev mapping and MMIO
+	 *       accesses bypass SMMU.
+	 *     - Normal memory is accessed through SMMU and ordering is
+	 *       ensured by client and AXI.
+	 *     - Ack point for Normal memory is WCAM in MC.
+	 *     - MMIO's can be early acked and AXI ensures dev memory ordering,
+	 *       Client ensures read/write direction change ordering.
+	 *     - See Bug 200312466 for more details.
+	 *
+	 * CGID_TAG_ADR is only present from T186 A02. As this code is common
+	 *    between A01 and A02, tegra_memctrl_set_overrides() programs
+	 *    CGID_TAG_ADR for the necessary clients on A02.
+	 */
+	mc_set_txn_override(HDAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(BPMPW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(PTCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVDISPLAYR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(EQOSW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVJPGSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(ISPRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCWAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(VICSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(MPCOREW, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
+	mc_set_txn_override(GPUSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(AXISR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SCEDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(EQOSR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	/* See bug 200131110 comment #35*/
+	mc_set_txn_override(APEDMAR, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVENCSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCRAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(VICSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(BPMPDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(VIW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCRAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(AXISW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(XUSB_DEVR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(UFSHCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(TSECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(GPUSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SATAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(XUSB_HOSTW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT);
+	mc_set_txn_override(TSECSWRB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(GPUSRD2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SCEDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(GPUSWR2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(AONDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	/* See bug 200131110 comment #35*/
+	mc_set_txn_override(APEDMAW, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(AONW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(HOST1XDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(ETRR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SESWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVJPGSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVDECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(TSECSRDB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(BPMPDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(APER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVDECSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(XUSB_HOSTR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(ISPWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SESRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SCER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(AONR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(MPCORER, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
+	mc_set_txn_override(SDMMCWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(HDAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVDECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(UFSHCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(AONDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SATAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT);
+	mc_set_txn_override(ETRW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(VICSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVENCSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	/* See bug 200131110 comment #35 */
+	mc_set_txn_override(AFIR, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCWAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(NVDISPLAYR1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(ISPWB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(BPMPR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(APEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(SDMMCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	mc_set_txn_override(XUSB_DEVW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT);
+	mc_set_txn_override(TSECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+	/*
+	 * See bug 200131110 comment #35 - there are no normal requests
+	 * and AWID for SO/DEV requests is hardcoded in RTL for a
+	 * particular PCIE controller
+	 */
+	mc_set_txn_override(AFIW, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_COHERENT);
+	mc_set_txn_override(SCEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
+
+	/*
+	 * At this point, ordering can occur at ROC. So, remove PCFIFO's
+	 * control over ordering requests.
+	 *
+	 * Change PCFIFO_*_ORDERED_CLIENT from ORDERED -> UNORDERED for
+	 * boot and strongly ordered MSS clients
+	 */
+	val = MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(1, AFIW) &
+		mc_set_pcfifo_unordered_boot_so_mss(1, HDAW) &
+		mc_set_pcfifo_unordered_boot_so_mss(1, SATAW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG1, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_HOSTW) &
+		mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_DEVW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG2, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(3, SDMMCWAB);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG3, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(4, SESWR) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, ETRW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, AXISW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, UFSHCW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, BPMPDMAW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, AONDMAW) &
+		mc_set_pcfifo_unordered_boot_so_mss(4, SCEDMAW);
+	/* EQOSW is the only client that has PCFIFO order enabled. */
+	val |= mc_set_pcfifo_ordered_boot_so_mss(4, EQOSW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG4, val);
+
+	val = MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL &
+		mc_set_pcfifo_unordered_boot_so_mss(5, APEDMAW);
+	tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG5, val);
+
+	/*
+	 * Deassert HOTRESET FLUSH_ENABLE for boot and strongly ordered MSS
+	 * clients to allow memory traffic from all clients to start passing
+	 * through ROC
+	 */
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0);
+	assert(val == wdata_0);
+
+	wdata_0 = MC_CLIENT_HOTRESET_CTRL0_RESET_VAL;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0);
+
+	val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1);
+	assert(val == wdata_1);
+
+	wdata_1 = MC_CLIENT_HOTRESET_CTRL1_RESET_VAL;
+	tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1);
+
+#endif
+}
+
+static void tegra186_memctrl_set_overrides(void)
+{
+	const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings();
+	const mc_txn_override_cfg_t *mc_txn_override_cfgs;
+	uint32_t num_txn_override_cfgs;
+	uint32_t i, val;
+
+	/* Get the settings from the platform */
+	assert(plat_mc_settings != NULL);
+	mc_txn_override_cfgs = plat_mc_settings->txn_override_cfg;
+	num_txn_override_cfgs = plat_mc_settings->num_txn_override_cfgs;
+
+	/*
+	 * Set the MC_TXN_OVERRIDE registers for write clients.
+	 */
+	if ((tegra_chipid_is_t186()) &&
+	    (!tegra_platform_is_silicon() ||
+	    (tegra_platform_is_silicon() && (tegra_get_chipid_minor() == 1U)))) {
+
+		/*
+		 * GPU and NVENC settings for Tegra186 simulation and
+		 * Silicon rev. A01
+		 */
+		val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR);
+		val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR,
+			val | MC_TXN_OVERRIDE_CGID_TAG_ZERO);
+
+		val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2);
+		val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2,
+			val | MC_TXN_OVERRIDE_CGID_TAG_ZERO);
+
+		val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR);
+		val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
+		tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR,
+			val | MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID);
+
+	} else {
+
+		/*
+		 * Settings for Tegra186 silicon rev. A02 and onwards.
+		 */
+		for (i = 0; i < num_txn_override_cfgs; i++) {
+			val = tegra_mc_read_32(mc_txn_override_cfgs[i].offset);
+			val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
+			tegra_mc_write_32(mc_txn_override_cfgs[i].offset,
+				val | mc_txn_override_cfgs[i].cgid_tag);
+		}
+	}
+}
+
+/*******************************************************************************
+ * Struct to hold the memory controller settings
+ ******************************************************************************/
+static tegra_mc_settings_t tegra186_mc_settings = {
+	.streamid_override_cfg = tegra186_streamid_override_regs,
+	.num_streamid_override_cfgs = (uint32_t)ARRAY_SIZE(tegra186_streamid_override_regs),
+	.streamid_security_cfg = tegra186_streamid_sec_cfgs,
+	.num_streamid_security_cfgs = (uint32_t)ARRAY_SIZE(tegra186_streamid_sec_cfgs),
+	.txn_override_cfg = tegra186_txn_override_cfgs,
+	.num_txn_override_cfgs = (uint32_t)ARRAY_SIZE(tegra186_txn_override_cfgs),
+	.reconfig_mss_clients = tegra186_memctrl_reconfig_mss_clients,
+	.set_txn_overrides = tegra186_memctrl_set_overrides,
+};
+
+/*******************************************************************************
+ * Handler to return the pointer to the memory controller's settings struct
+ ******************************************************************************/
+tegra_mc_settings_t *tegra_get_mc_settings(void)
+{
+	return &tegra186_mc_settings;
+}
+
+/*******************************************************************************
+ * Handler to program the scratch registers with TZDRAM settings for the
+ * resume firmware
+ ******************************************************************************/
+void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes)
+{
+	uint32_t val;
+
+	/*
+	 * Setup the Memory controller to allow only secure accesses to
+	 * the TZDRAM carveout
+	 */
+	INFO("Configuring TrustZone DRAM Memory Carveout\n");
+
+	tegra_mc_write_32(MC_SECURITY_CFG0_0, (uint32_t)phys_base);
+	tegra_mc_write_32(MC_SECURITY_CFG3_0, (uint32_t)(phys_base >> 32));
+	tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20);
+
+	/*
+	 * When TZ encryption is enabled, we need to setup TZDRAM
+	 * before CPU accesses TZ Carveout, else CPU will fetch
+	 * non-decrypted data. So save TZDRAM setting for SC7 resume
+	 * FW to restore.
+	 *
+	 * Scratch registers map:
+	 *  RSV55_0 = CFG1[12:0] | CFG0[31:20]
+	 *  RSV55_1 = CFG3[1:0]
+	 */
+	val = tegra_mc_read_32(MC_SECURITY_CFG1_0) & MC_SECURITY_SIZE_MB_MASK;
+	val |= tegra_mc_read_32(MC_SECURITY_CFG0_0) & MC_SECURITY_BOM_MASK;
+	mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_LO, val);
+
+	val = tegra_mc_read_32(MC_SECURITY_CFG3_0) & MC_SECURITY_BOM_HI_MASK;
+	mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_HI, val);
+
+	/*
+	 * MCE propagates the security configuration values across the
+	 * CCPLEX.
+	 */
+	(void)mce_update_gsc_tzdram();
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
new file mode 100644
index 0000000..11394c0
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <context.h>
+#include <cortex_a57.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <mce.h>
+#include <smmu.h>
+#include <stdbool.h>
+#include <t18x_ari.h>
+#include <tegra186_private.h>
+#include <tegra_private.h>
+
+extern void memcpy16(void *dest, const void *src, unsigned int length);
+
+/* state id mask */
+#define TEGRA186_STATE_ID_MASK		0xFU
+/* constants to get power state's wake time */
+#define TEGRA186_WAKE_TIME_MASK		0x0FFFFFF0U
+#define TEGRA186_WAKE_TIME_SHIFT	4U
+/* default core wake mask for CPU_SUSPEND */
+#define TEGRA186_CORE_WAKE_MASK		0x180cU
+/* context size to save during system suspend */
+#define TEGRA186_SE_CONTEXT_SIZE	3U
+
+static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
+static struct tegra_psci_percpu_data {
+	uint32_t wake_time;
+} __aligned(CACHE_WRITEBACK_GRANULE) tegra_percpu_data[PLATFORM_CORE_COUNT];
+
+int32_t tegra_soc_validate_power_state(uint32_t power_state,
+					psci_power_state_t *req_state)
+{
+	uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
+	uint32_t cpu = plat_my_core_pos();
+	int32_t ret = PSCI_E_SUCCESS;
+
+	/* save the core wake time (in TSC ticks)*/
+	tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK)
+			<< TEGRA186_WAKE_TIME_SHIFT;
+
+	/*
+	 * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that
+	 * the correct value is read in tegra_soc_pwr_domain_suspend(), which
+	 * is called with caches disabled. It is possible to read a stale value
+	 * from DRAM in that function, because the L2 cache is not flushed
+	 * unless the cluster is entering CC6/CC7.
+	 */
+	clean_dcache_range((uint64_t)&tegra_percpu_data[cpu],
+			sizeof(tegra_percpu_data[cpu]));
+
+	/* Sanity check the requested state id */
+	switch (state_id) {
+	case PSTATE_ID_CORE_IDLE:
+	case PSTATE_ID_CORE_POWERDN:
+
+		/* Core powerdown request */
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
+		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
+
+		break;
+
+	default:
+		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
+		ret = PSCI_E_INVALID_PARAMS;
+		break;
+	}
+
+	return ret;
+}
+
+int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	const plat_local_state_t *pwr_domain_state;
+	uint8_t stateid_afflvl0, stateid_afflvl2;
+	uint32_t cpu = plat_my_core_pos();
+	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	mce_cstate_info_t cstate_info = { 0 };
+	uint64_t smmu_ctx_base;
+	uint32_t val;
+
+	/* get the state ID */
+	pwr_domain_state = target_state->pwr_domain_state;
+	stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
+		TEGRA186_STATE_ID_MASK;
+	stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
+		TEGRA186_STATE_ID_MASK;
+
+	if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
+	    (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
+
+		/* Enter CPU idle/powerdown */
+		val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
+			(uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7;
+		(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val,
+				tegra_percpu_data[cpu].wake_time, 0U);
+
+	} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
+		/* save SE registers */
+		se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
+				SE_MUTEX_WATCHDOG_NS_LIMIT);
+		se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
+				RNG_MUTEX_WATCHDOG_NS_LIMIT);
+		se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
+				PKA_MUTEX_WATCHDOG_NS_LIMIT);
+
+		/* save 'Secure Boot' Processor Feature Config Register */
+		val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
+		mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
+
+		/* save SMMU context to TZDRAM */
+		smmu_ctx_base = params_from_bl2->tzdram_base +
+				tegra186_get_smmu_ctx_offset();
+		tegra_smmu_save_context((uintptr_t)smmu_ctx_base);
+
+		/* Prepare for system suspend */
+		cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
+		cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7;
+		cstate_info.system_state_force = 1;
+		cstate_info.update_wake_mask = 1;
+		mce_update_cstate_info(&cstate_info);
+
+		/* Loop until system suspend is allowed */
+		do {
+			val = (uint32_t)mce_command_handler(
+					(uint64_t)MCE_CMD_IS_SC7_ALLOWED,
+					(uint64_t)TEGRA_ARI_CORE_C7,
+					MCE_CORE_SLEEP_TIME_INFINITE,
+					0U);
+		} while (val == 0U);
+
+		/* Instruct the MCE to enter system suspend state */
+		(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
+			(uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
+
+		/* set system suspend state for house-keeping */
+		tegra186_set_system_suspend_entry();
+
+	} else {
+		; /* do nothing */
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Helper function to check if this is the last ON CPU in the cluster
+ ******************************************************************************/
+static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states,
+			uint32_t ncpu)
+{
+	plat_local_state_t target;
+	bool last_on_cpu = true;
+	uint32_t num_cpus = ncpu, pos = 0;
+
+	do {
+		target = states[pos];
+		if (target != PLAT_MAX_OFF_STATE) {
+			last_on_cpu = false;
+		}
+		--num_cpus;
+		pos++;
+	} while (num_cpus != 0U);
+
+	return last_on_cpu;
+}
+
+/*******************************************************************************
+ * Helper function to get target power state for the cluster
+ ******************************************************************************/
+static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
+			uint32_t ncpu)
+{
+	uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
+	uint32_t cpu = plat_my_core_pos();
+	int32_t ret;
+	plat_local_state_t target = states[core_pos];
+	mce_cstate_info_t cstate_info = { 0 };
+
+	/* CPU suspend */
+	if (target == PSTATE_ID_CORE_POWERDN) {
+		/* Program default wake mask */
+		cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK;
+		cstate_info.update_wake_mask = 1;
+		mce_update_cstate_info(&cstate_info);
+
+		/* Check if CCx state is allowed. */
+		ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
+				(uint64_t)TEGRA_ARI_CORE_C7,
+				tegra_percpu_data[cpu].wake_time,
+				0U);
+		if (ret == 0) {
+			target = PSCI_LOCAL_STATE_RUN;
+		}
+	}
+
+	/* CPU off */
+	if (target == PLAT_MAX_OFF_STATE) {
+		/* Enable cluster powerdn from last CPU in the cluster */
+		if (tegra_last_cpu_in_cluster(states, ncpu)) {
+			/* Enable CC7 state and turn off wake mask */
+			cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
+			cstate_info.update_wake_mask = 1;
+			mce_update_cstate_info(&cstate_info);
+
+			/* Check if CCx state is allowed. */
+			ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
+						  (uint64_t)TEGRA_ARI_CORE_C7,
+						  MCE_CORE_SLEEP_TIME_INFINITE,
+						  0U);
+			if (ret == 0) {
+				target = PSCI_LOCAL_STATE_RUN;
+			}
+
+		} else {
+
+			/* Turn off wake_mask */
+			cstate_info.update_wake_mask = 1;
+			mce_update_cstate_info(&cstate_info);
+			target = PSCI_LOCAL_STATE_RUN;
+		}
+	}
+
+	return target;
+}
+
+/*******************************************************************************
+ * Platform handler to calculate the proper target power level at the
+ * specified affinity level
+ ******************************************************************************/
+plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
+					     const plat_local_state_t *states,
+					     uint32_t ncpu)
+{
+	plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
+	uint32_t cpu = plat_my_core_pos();
+
+	/* System Suspend */
+	if ((lvl == (uint32_t)MPIDR_AFFLVL2) &&
+	    (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
+		target = PSTATE_ID_SOC_POWERDN;
+	}
+
+	/* CPU off, CPU suspend */
+	if (lvl == (uint32_t)MPIDR_AFFLVL1) {
+		target = tegra_get_afflvl1_pwr_state(states, ncpu);
+	}
+
+	/* target cluster/system state */
+	return target;
+}
+
+int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
+{
+	const plat_local_state_t *pwr_domain_state =
+		target_state->pwr_domain_state;
+	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
+		TEGRA186_STATE_ID_MASK;
+	uint64_t val;
+
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+		/*
+		 * The TZRAM loses power when we enter system suspend. To
+		 * allow graceful exit from system suspend, we need to copy
+		 * BL3-1 over to TZDRAM.
+		 */
+		val = params_from_bl2->tzdram_base +
+			tegra186_get_cpu_reset_handler_size();
+		memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
+			 (uintptr_t)BL31_END - (uintptr_t)BL31_BASE);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
+{
+	int32_t ret = PSCI_E_SUCCESS;
+	uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
+	uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
+			MPIDR_AFFINITY_BITS;
+
+	if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
+
+		ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
+		ret = PSCI_E_NOT_PRESENT;
+
+	} else {
+		/* construct the target CPU # */
+		target_cpu |= (target_cluster << 2);
+
+		(void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
+	}
+
+	return ret;
+}
+
+int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
+	uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
+	mce_cstate_info_t cstate_info = { 0 };
+	uint64_t impl, val;
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+
+	impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
+
+	/*
+	 * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
+	 * A02p and beyond).
+	 */
+	if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) {
+
+		val = read_l2ctlr_el1();
+		val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
+		write_l2ctlr_el1(val);
+	}
+
+	/*
+	 * Reset power state info for CPUs when onlining, we set
+	 * deepest power when offlining a core but that may not be
+	 * requested by non-secure sw which controls idle states. It
+	 * will re-init this info from non-secure software when the
+	 * core come online.
+	 */
+	if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
+
+		cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1;
+		cstate_info.update_wake_mask = 1;
+		mce_update_cstate_info(&cstate_info);
+	}
+
+	/*
+	 * Check if we are exiting from deep sleep and restore SE
+	 * context if we are.
+	 */
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
+		mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
+			se_regs[0]);
+		mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
+			se_regs[1]);
+		mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
+			se_regs[2]);
+
+		/* Init SMMU */
+		tegra_smmu_init();
+
+		/*
+		 * Reset power state info for the last core doing SC7
+		 * entry and exit, we set deepest power state as CC7
+		 * and SC7 for SC7 entry which may not be requested by
+		 * non-secure SW which controls idle states.
+		 */
+		cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
+		cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1;
+		cstate_info.update_wake_mask = 1;
+		mce_update_cstate_info(&cstate_info);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
+
+	(void)target_state;
+
+	/* Disable Denver's DCO operations */
+	if (impl == DENVER_IMPL) {
+		denver_disable_dco();
+	}
+
+	/* Turn off CPU */
+	(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
+			(uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
+
+	return PSCI_E_SUCCESS;
+}
+
+__dead2 void tegra_soc_prepare_system_off(void)
+{
+	/* power off the entire system */
+	mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF);
+
+	wfi();
+
+	/* wait for the system to power down */
+	for (;;) {
+		;
+	}
+}
+
+int32_t tegra_soc_prepare_system_reset(void)
+{
+	mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
+
+	return PSCI_E_SUCCESS;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_secondary.c b/plat/nvidia/tegra/soc/t186/plat_secondary.c
new file mode 100644
index 0000000..1650809
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_secondary.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <mce.h>
+#include <tegra186_private.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+#define MISCREG_AA64_RST_LOW		0x2004U
+#define MISCREG_AA64_RST_HIGH		0x2008U
+
+#define SCRATCH_SECURE_RSV1_SCRATCH_0	0x658U
+#define SCRATCH_SECURE_RSV1_SCRATCH_1	0x65CU
+
+#define CPU_RESET_MODE_AA64		1U
+
+extern void memcpy16(void *dest, const void *src, unsigned int length);
+
+/*******************************************************************************
+ * Setup secondary CPU vectors
+ ******************************************************************************/
+void plat_secondary_setup(void)
+{
+	uint32_t addr_low, addr_high;
+	const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
+	uint64_t cpu_reset_handler_base, cpu_reset_handler_size;
+
+	INFO("Setting up secondary CPU boot\n");
+
+	/*
+	 * The BL31 code resides in the TZSRAM which loses state
+	 * when we enter System Suspend. Copy the wakeup trampoline
+	 * code to TZDRAM to help us exit from System Suspend.
+	 */
+	cpu_reset_handler_base = tegra186_get_cpu_reset_handler_base();
+	cpu_reset_handler_size = tegra186_get_cpu_reset_handler_size();
+	(void)memcpy16((void *)(uintptr_t)params_from_bl2->tzdram_base,
+			(const void *)(uintptr_t)cpu_reset_handler_base,
+			cpu_reset_handler_size);
+
+	/* TZDRAM base will be used as the "resume" address */
+	addr_low = (uint32_t)params_from_bl2->tzdram_base | CPU_RESET_MODE_AA64;
+	addr_high = (uint32_t)((params_from_bl2->tzdram_base >> 32U) & 0x7ffU);
+
+	/* write lower 32 bits first, then the upper 11 bits */
+	mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low);
+	mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high);
+
+	/* save reset vector to be used during SYSTEM_SUSPEND exit */
+	mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO,
+			addr_low);
+	mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI,
+			addr_high);
+
+	/* update reset vector address to the CCPLEX */
+	(void)mce_update_reset_vector();
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_setup.c b/plat/nvidia/tegra/soc/t186/plat_setup.c
new file mode 100644
index 0000000..ef0ba4e
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_setup.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <context.h>
+#include <cortex_a57.h>
+#include <denver.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <mce.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * Tegra186 CPU numbers in cluster #0
+ *******************************************************************************
+ */
+#define TEGRA186_CLUSTER0_CORE2		2U
+#define TEGRA186_CLUSTER0_CORE3		3U
+
+/*******************************************************************************
+ * The Tegra power domain tree has a single system level power domain i.e. a
+ * single root node. The first entry in the power domain descriptor specifies
+ * the number of power domains at the highest power level.
+ *******************************************************************************
+ */
+static const uint8_t tegra_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	1,
+	/* No of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of CPU cores - cluster0 */
+	PLATFORM_MAX_CPUS_PER_CLUSTER,
+	/* No of CPU cores - cluster1 */
+	PLATFORM_MAX_CPUS_PER_CLUSTER
+};
+
+/*******************************************************************************
+ * This function returns the Tegra default topology tree information.
+ ******************************************************************************/
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+	return tegra_power_domain_tree_desc;
+}
+
+/*
+ * Table of regions to map using the MMU.
+ */
+static const mmap_region_t tegra_mmap[] = {
+	MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_TSA_BASE, 0x20000U, /* 128KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_MC_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_FUSE_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000U, /* 128KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000U, /* 256KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_TMRUS_BASE, 0x1000U, /* 4KB */
+			MT_DEVICE | MT_RO | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x10000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000U, /* 384KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_ARM_ACTMON_CTR_BASE, 0x20000U, /* 128KB - ARM/Denver */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x1000000U, /* 64KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{0}
+};
+
+/*******************************************************************************
+ * Set up the pagetables as per the platform memory map & initialize the MMU
+ ******************************************************************************/
+const mmap_region_t *plat_get_mmio_map(void)
+{
+	/* MMIO space */
+	return tegra_mmap;
+}
+
+/*******************************************************************************
+ * Handler to get the System Counter Frequency
+ ******************************************************************************/
+uint32_t plat_get_syscnt_freq2(void)
+{
+	return 31250000;
+}
+
+/*******************************************************************************
+ * Maximum supported UART controllers
+ ******************************************************************************/
+#define TEGRA186_MAX_UART_PORTS		7
+
+/*******************************************************************************
+ * This variable holds the UART port base addresses
+ ******************************************************************************/
+static uint32_t tegra186_uart_addresses[TEGRA186_MAX_UART_PORTS + 1] = {
+	0,	/* undefined - treated as an error case */
+	TEGRA_UARTA_BASE,
+	TEGRA_UARTB_BASE,
+	TEGRA_UARTC_BASE,
+	TEGRA_UARTD_BASE,
+	TEGRA_UARTE_BASE,
+	TEGRA_UARTF_BASE,
+	TEGRA_UARTG_BASE,
+};
+
+/*******************************************************************************
+ * Retrieve the UART controller base to be used as the console
+ ******************************************************************************/
+uint32_t plat_get_console_from_id(int32_t id)
+{
+	uint32_t ret;
+
+	if (id > TEGRA186_MAX_UART_PORTS) {
+		ret = 0;
+	} else {
+		ret = tegra186_uart_addresses[id];
+	}
+
+	return ret;
+}
+
+/*******************************************************************************
+ * Handler for early platform setup
+ ******************************************************************************/
+void plat_early_platform_setup(void)
+{
+	uint64_t impl, val;
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+
+	/* sanity check MCE firmware compatibility */
+	mce_verify_firmware_version();
+
+	impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
+
+	/*
+	 * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
+	 * A02p and beyond).
+	 */
+	if ((plat_params->l2_ecc_parity_prot_dis != 1) &&
+	    (impl != (uint64_t)DENVER_IMPL)) {
+
+		val = read_l2ctlr_el1();
+		val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
+		write_l2ctlr_el1(val);
+	}
+}
+
+/* Secure IRQs for Tegra186 */
+static const interrupt_prop_t tegra186_interrupt_props[] = {
+	INTR_PROP_DESC(TEGRA186_TOP_WDT_IRQ, GIC_HIGHEST_SEC_PRIORITY,
+			GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(TEGRA186_AON_WDT_IRQ, GIC_HIGHEST_SEC_PRIORITY,
+			GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE)
+};
+
+/*******************************************************************************
+ * Initialize the GIC and SGIs
+ ******************************************************************************/
+void plat_gic_setup(void)
+{
+	tegra_gic_setup(tegra186_interrupt_props, ARRAY_SIZE(tegra186_interrupt_props));
+	tegra_gic_init();
+
+	/*
+	 * Initialize the FIQ handler only if the platform supports any
+	 * FIQ interrupt sources.
+	 */
+	tegra_fiq_handler_setup();
+}
+
+/*******************************************************************************
+ * Return pointer to the BL31 params from previous bootloader
+ ******************************************************************************/
+struct tegra_bl31_params *plat_get_bl31_params(void)
+{
+	uint32_t val;
+
+	val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_ADDR);
+
+	return (struct tegra_bl31_params *)(uintptr_t)val;
+}
+
+/*******************************************************************************
+ * Return pointer to the BL31 platform params from previous bootloader
+ ******************************************************************************/
+plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
+{
+	uint32_t val;
+
+	val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_ADDR);
+
+	return (plat_params_from_bl2_t *)(uintptr_t)val;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	u_register_t cluster_id, cpu_id, pos;
+	int32_t ret;
+
+	cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK;
+
+	/*
+	 * Validate cluster_id by checking whether it represents
+	 * one of the two clusters present on the platform.
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if ((cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) ||
+	    (cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER)) {
+		ret = PSCI_E_NOT_PRESENT;
+	} else {
+		/* calculate the core position */
+		pos = cpu_id + (cluster_id << 2U);
+
+		/* check for non-existent CPUs */
+		if ((pos == TEGRA186_CLUSTER0_CORE2) || (pos == TEGRA186_CLUSTER0_CORE3)) {
+			ret = PSCI_E_NOT_PRESENT;
+		} else {
+			ret = (int32_t)pos;
+		}
+	}
+
+	return ret;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_sip_calls.c b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
new file mode 100644
index 0000000..4de8a9e
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_sip_calls.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <denver.h>
+#include <lib/el3_runtime/context_mgmt.h>
+
+#include <mce.h>
+#include <memctrl.h>
+#include <t18x_ari.h>
+#include <tegra_private.h>
+
+/*******************************************************************************
+ * Offset to read the ref_clk counter value
+ ******************************************************************************/
+#define REF_CLK_OFFSET		4ULL
+
+/*******************************************************************************
+ * Tegra186 SiP SMCs
+ ******************************************************************************/
+#define TEGRA_SIP_GET_ACTMON_CLK_COUNTERS		0xC2FFFE02
+#define TEGRA_SIP_MCE_CMD_ENTER_CSTATE			0xC2FFFF00
+#define TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO		0xC2FFFF01
+#define TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME		0xC2FFFF02
+#define TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS		0xC2FFFF03
+#define TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS		0xC2FFFF04
+#define TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED		0xC2FFFF05
+
+#define TEGRA_SIP_MCE_CMD_CC3_CTRL			0xC2FFFF07
+#define TEGRA_SIP_MCE_CMD_ECHO_DATA			0xC2FFFF08
+#define TEGRA_SIP_MCE_CMD_READ_VERSIONS			0xC2FFFF09
+#define TEGRA_SIP_MCE_CMD_ENUM_FEATURES			0xC2FFFF0A
+#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS	0xC2FFFF0B
+#define TEGRA_SIP_MCE_CMD_ENUM_READ_MCA			0xC2FFFF0C
+#define TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA		0xC2FFFF0D
+#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE		0xC2FFFF0E
+#define TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE		0xC2FFFF0F
+#define TEGRA_SIP_MCE_CMD_ENABLE_LATIC			0xC2FFFF10
+#define TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ		0xC2FFFF11
+#define TEGRA_SIP_MCE_CMD_MISC_CCPLEX			0xC2FFFF12
+
+/*******************************************************************************
+ * This function is responsible for handling all T186 SiP calls
+ ******************************************************************************/
+int32_t plat_sip_handler(uint32_t smc_fid,
+		     uint64_t x1,
+		     uint64_t x2,
+		     uint64_t x3,
+		     uint64_t x4,
+		     const void *cookie,
+		     void *handle,
+		     uint64_t flags)
+{
+	int32_t mce_ret, ret = 0;
+	uint32_t impl, cpu;
+	uint32_t base, core_clk_ctr, ref_clk_ctr;
+	uint32_t local_smc_fid = smc_fid;
+	uint64_t local_x1 = x1, local_x2 = x2, local_x3 = x3;
+
+	(void)x4;
+	(void)cookie;
+	(void)flags;
+
+	if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
+		/* 32-bit function, clear top parameter bits */
+
+		local_x1 = (uint32_t)x1;
+		local_x2 = (uint32_t)x2;
+		local_x3 = (uint32_t)x3;
+	}
+
+	/*
+	 * Convert SMC FID to SMC64, to support SMC32/SMC64 configurations
+	 */
+	local_smc_fid |= (SMC_64 << FUNCID_CC_SHIFT);
+
+	switch (local_smc_fid) {
+	/*
+	 * Micro Coded Engine (MCE) commands reside in the 0x82FFFF00 -
+	 * 0x82FFFFFF SiP SMC space
+	 */
+	case TEGRA_SIP_MCE_CMD_ENTER_CSTATE:
+	case TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO:
+	case TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME:
+	case TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS:
+	case TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS:
+	case TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED:
+	case TEGRA_SIP_MCE_CMD_CC3_CTRL:
+	case TEGRA_SIP_MCE_CMD_ECHO_DATA:
+	case TEGRA_SIP_MCE_CMD_READ_VERSIONS:
+	case TEGRA_SIP_MCE_CMD_ENUM_FEATURES:
+	case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS:
+	case TEGRA_SIP_MCE_CMD_ENUM_READ_MCA:
+	case TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA:
+	case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE:
+	case TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE:
+	case TEGRA_SIP_MCE_CMD_ENABLE_LATIC:
+	case TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ:
+	case TEGRA_SIP_MCE_CMD_MISC_CCPLEX:
+
+		/* clean up the high bits */
+		local_smc_fid &= MCE_CMD_MASK;
+
+		/* execute the command and store the result */
+		mce_ret = mce_command_handler(local_smc_fid, local_x1, local_x2, local_x3);
+		write_ctx_reg(get_gpregs_ctx(handle),
+			      CTX_GPREG_X0, (uint64_t)(mce_ret));
+		break;
+
+	/*
+	 * This function ID reads the Activity monitor's core/ref clock
+	 * counter values for a core/cluster.
+	 *
+	 * x1 = MPIDR of the target core
+	 * x2 = MIDR of the target core
+	 */
+	case TEGRA_SIP_GET_ACTMON_CLK_COUNTERS:
+
+		cpu = (uint32_t)x1 & MPIDR_CPU_MASK;
+		impl = ((uint32_t)x2 >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
+
+		/* sanity check target CPU number */
+		if (cpu > (uint32_t)PLATFORM_MAX_CPUS_PER_CLUSTER) {
+			ret = -EINVAL;
+		} else {
+			/* get the base address for the current CPU */
+			base = (impl == DENVER_IMPL) ? TEGRA_DENVER_ACTMON_CTR_BASE :
+				TEGRA_ARM_ACTMON_CTR_BASE;
+
+			/* read the clock counter values */
+			core_clk_ctr = mmio_read_32(base + (8ULL * cpu));
+			ref_clk_ctr = mmio_read_32(base + (8ULL * cpu) + REF_CLK_OFFSET);
+
+			/* return the counter values as two different parameters */
+			write_ctx_reg(get_gpregs_ctx(handle),
+				      CTX_GPREG_X1, (core_clk_ctr));
+			write_ctx_reg(get_gpregs_ctx(handle),
+				      CTX_GPREG_X2, (ref_clk_ctr));
+		}
+
+		break;
+
+	default:
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_smmu.c b/plat/nvidia/tegra/soc/t186/plat_smmu.c
new file mode 100644
index 0000000..b4a7fe5
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_smmu.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+
+#include <smmu.h>
+#include <tegra_def.h>
+#include <tegra_mc_def.h>
+
+#define MAX_NUM_SMMU_DEVICES	U(1)
+
+/*******************************************************************************
+ * Array to hold SMMU context for Tegra186
+ ******************************************************************************/
+static __attribute__((aligned(16))) smmu_regs_t tegra186_smmu_context[] = {
+	_START_OF_TABLE_,
+	mc_make_sid_security_cfg(SCEW),
+	mc_make_sid_security_cfg(AFIR),
+	mc_make_sid_security_cfg(NVDISPLAYR1),
+	mc_make_sid_security_cfg(XUSB_DEVR),
+	mc_make_sid_security_cfg(VICSRD1),
+	mc_make_sid_security_cfg(NVENCSWR),
+	mc_make_sid_security_cfg(TSECSRDB),
+	mc_make_sid_security_cfg(AXISW),
+	mc_make_sid_security_cfg(SDMMCWAB),
+	mc_make_sid_security_cfg(AONDMAW),
+	mc_make_sid_security_cfg(GPUSWR2),
+	mc_make_sid_security_cfg(SATAW),
+	mc_make_sid_security_cfg(UFSHCW),
+	mc_make_sid_security_cfg(AFIW),
+	mc_make_sid_security_cfg(SDMMCR),
+	mc_make_sid_security_cfg(SCEDMAW),
+	mc_make_sid_security_cfg(UFSHCR),
+	mc_make_sid_security_cfg(SDMMCWAA),
+	mc_make_sid_security_cfg(APEDMAW),
+	mc_make_sid_security_cfg(SESWR),
+	mc_make_sid_security_cfg(MPCORER),
+	mc_make_sid_security_cfg(PTCR),
+	mc_make_sid_security_cfg(BPMPW),
+	mc_make_sid_security_cfg(ETRW),
+	mc_make_sid_security_cfg(GPUSRD),
+	mc_make_sid_security_cfg(VICSWR),
+	mc_make_sid_security_cfg(SCEDMAR),
+	mc_make_sid_security_cfg(HDAW),
+	mc_make_sid_security_cfg(ISPWA),
+	mc_make_sid_security_cfg(EQOSW),
+	mc_make_sid_security_cfg(XUSB_HOSTW),
+	mc_make_sid_security_cfg(TSECSWR),
+	mc_make_sid_security_cfg(SDMMCRAA),
+	mc_make_sid_security_cfg(APER),
+	mc_make_sid_security_cfg(VIW),
+	mc_make_sid_security_cfg(APEW),
+	mc_make_sid_security_cfg(AXISR),
+	mc_make_sid_security_cfg(SDMMCW),
+	mc_make_sid_security_cfg(BPMPDMAW),
+	mc_make_sid_security_cfg(ISPRA),
+	mc_make_sid_security_cfg(NVDECSWR),
+	mc_make_sid_security_cfg(XUSB_DEVW),
+	mc_make_sid_security_cfg(NVDECSRD),
+	mc_make_sid_security_cfg(MPCOREW),
+	mc_make_sid_security_cfg(NVDISPLAYR),
+	mc_make_sid_security_cfg(BPMPDMAR),
+	mc_make_sid_security_cfg(NVJPGSWR),
+	mc_make_sid_security_cfg(NVDECSRD1),
+	mc_make_sid_security_cfg(TSECSRD),
+	mc_make_sid_security_cfg(NVJPGSRD),
+	mc_make_sid_security_cfg(SDMMCWA),
+	mc_make_sid_security_cfg(SCER),
+	mc_make_sid_security_cfg(XUSB_HOSTR),
+	mc_make_sid_security_cfg(VICSRD),
+	mc_make_sid_security_cfg(AONDMAR),
+	mc_make_sid_security_cfg(AONW),
+	mc_make_sid_security_cfg(SDMMCRA),
+	mc_make_sid_security_cfg(HOST1XDMAR),
+	mc_make_sid_security_cfg(EQOSR),
+	mc_make_sid_security_cfg(SATAR),
+	mc_make_sid_security_cfg(BPMPR),
+	mc_make_sid_security_cfg(HDAR),
+	mc_make_sid_security_cfg(SDMMCRAB),
+	mc_make_sid_security_cfg(ETRR),
+	mc_make_sid_security_cfg(AONR),
+	mc_make_sid_security_cfg(APEDMAR),
+	mc_make_sid_security_cfg(SESRD),
+	mc_make_sid_security_cfg(NVENCSRD),
+	mc_make_sid_security_cfg(GPUSWR),
+	mc_make_sid_security_cfg(TSECSWRB),
+	mc_make_sid_security_cfg(ISPWB),
+	mc_make_sid_security_cfg(GPUSRD2),
+	mc_make_sid_override_cfg(APER),
+	mc_make_sid_override_cfg(VICSRD),
+	mc_make_sid_override_cfg(NVENCSRD),
+	mc_make_sid_override_cfg(NVJPGSWR),
+	mc_make_sid_override_cfg(AONW),
+	mc_make_sid_override_cfg(BPMPR),
+	mc_make_sid_override_cfg(BPMPW),
+	mc_make_sid_override_cfg(HDAW),
+	mc_make_sid_override_cfg(NVDISPLAYR1),
+	mc_make_sid_override_cfg(APEDMAR),
+	mc_make_sid_override_cfg(AFIR),
+	mc_make_sid_override_cfg(AXISR),
+	mc_make_sid_override_cfg(VICSRD1),
+	mc_make_sid_override_cfg(TSECSRD),
+	mc_make_sid_override_cfg(BPMPDMAW),
+	mc_make_sid_override_cfg(MPCOREW),
+	mc_make_sid_override_cfg(XUSB_HOSTR),
+	mc_make_sid_override_cfg(GPUSWR),
+	mc_make_sid_override_cfg(XUSB_DEVR),
+	mc_make_sid_override_cfg(UFSHCW),
+	mc_make_sid_override_cfg(XUSB_HOSTW),
+	mc_make_sid_override_cfg(SDMMCWAB),
+	mc_make_sid_override_cfg(SATAW),
+	mc_make_sid_override_cfg(SCEDMAR),
+	mc_make_sid_override_cfg(HOST1XDMAR),
+	mc_make_sid_override_cfg(SDMMCWA),
+	mc_make_sid_override_cfg(APEDMAW),
+	mc_make_sid_override_cfg(SESWR),
+	mc_make_sid_override_cfg(AXISW),
+	mc_make_sid_override_cfg(AONDMAW),
+	mc_make_sid_override_cfg(TSECSWRB),
+	mc_make_sid_override_cfg(MPCORER),
+	mc_make_sid_override_cfg(ISPWB),
+	mc_make_sid_override_cfg(AONR),
+	mc_make_sid_override_cfg(BPMPDMAR),
+	mc_make_sid_override_cfg(HDAR),
+	mc_make_sid_override_cfg(SDMMCRA),
+	mc_make_sid_override_cfg(ETRW),
+	mc_make_sid_override_cfg(GPUSWR2),
+	mc_make_sid_override_cfg(EQOSR),
+	mc_make_sid_override_cfg(TSECSWR),
+	mc_make_sid_override_cfg(ETRR),
+	mc_make_sid_override_cfg(NVDECSRD),
+	mc_make_sid_override_cfg(TSECSRDB),
+	mc_make_sid_override_cfg(SDMMCRAA),
+	mc_make_sid_override_cfg(NVDECSRD1),
+	mc_make_sid_override_cfg(SDMMCR),
+	mc_make_sid_override_cfg(NVJPGSRD),
+	mc_make_sid_override_cfg(SCEDMAW),
+	mc_make_sid_override_cfg(SDMMCWAA),
+	mc_make_sid_override_cfg(APEW),
+	mc_make_sid_override_cfg(AONDMAR),
+	mc_make_sid_override_cfg(PTCR),
+	mc_make_sid_override_cfg(SCER),
+	mc_make_sid_override_cfg(ISPRA),
+	mc_make_sid_override_cfg(ISPWA),
+	mc_make_sid_override_cfg(VICSWR),
+	mc_make_sid_override_cfg(SESRD),
+	mc_make_sid_override_cfg(SDMMCW),
+	mc_make_sid_override_cfg(SDMMCRAB),
+	mc_make_sid_override_cfg(EQOSW),
+	mc_make_sid_override_cfg(GPUSRD2),
+	mc_make_sid_override_cfg(SCEW),
+	mc_make_sid_override_cfg(GPUSRD),
+	mc_make_sid_override_cfg(NVDECSWR),
+	mc_make_sid_override_cfg(XUSB_DEVW),
+	mc_make_sid_override_cfg(SATAR),
+	mc_make_sid_override_cfg(NVDISPLAYR),
+	mc_make_sid_override_cfg(VIW),
+	mc_make_sid_override_cfg(UFSHCR),
+	mc_make_sid_override_cfg(NVENCSWR),
+	mc_make_sid_override_cfg(AFIW),
+	smmu_make_cfg(TEGRA_SMMU0_BASE),
+	smmu_bypass_cfg,	/* TBU settings */
+	_END_OF_TABLE_,
+};
+
+/*******************************************************************************
+ * Handler to return the pointer to the SMMU's context struct
+ ******************************************************************************/
+smmu_regs_t *plat_get_smmu_ctx(void)
+{
+	/* index of _END_OF_TABLE_ */
+	tegra186_smmu_context[0].val = (uint32_t)(ARRAY_SIZE(tegra186_smmu_context)) - 1U;
+
+	return tegra186_smmu_context;
+}
+
+/*******************************************************************************
+ * Handler to return the support SMMU devices number
+ ******************************************************************************/
+uint32_t plat_get_num_smmu_devices(void)
+{
+	return MAX_NUM_SMMU_DEVICES;
+}
diff --git a/plat/nvidia/tegra/soc/t186/plat_trampoline.S b/plat/nvidia/tegra/soc/t186/plat_trampoline.S
new file mode 100644
index 0000000..db69234
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/plat_trampoline.S
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <memctrl_v2.h>
+#include <plat/common/common_def.h>
+#include <tegra_def.h>
+
+#define TEGRA186_STATE_SYSTEM_SUSPEND	0x5C7
+#define TEGRA186_STATE_SYSTEM_RESUME	0x600D
+#define TEGRA186_SMMU_CTX_SIZE		0x420
+
+	.globl	tegra186_cpu_reset_handler
+
+/* CPU reset handler routine */
+func tegra186_cpu_reset_handler _align=4
+	/* check if we are exiting system suspend state */
+	adr	x0, __tegra186_system_suspend_state
+	ldr	x1, [x0]
+	mov	x2, #TEGRA186_STATE_SYSTEM_SUSPEND
+	lsl	x2, x2, #16
+	add	x2, x2, #TEGRA186_STATE_SYSTEM_SUSPEND
+	cmp	x1, x2
+	bne	boot_cpu
+
+	/* set system resume state */
+	mov	x1, #TEGRA186_STATE_SYSTEM_RESUME
+	lsl	x1, x1, #16
+	mov	x2, #TEGRA186_STATE_SYSTEM_RESUME
+	add	x1, x1, x2
+	str	x1, [x0]
+	dsb	sy
+
+	/* prepare to relocate to TZSRAM */
+	mov	x0, #BL31_BASE
+	adr	x1, __tegra186_cpu_reset_handler_end
+	adr	x2, __tegra186_cpu_reset_handler_data
+	ldr	x2, [x2, #8]
+
+	/* memcpy16 */
+m_loop16:
+	cmp	x2, #16
+	b.lt	m_loop1
+	ldp	x3, x4, [x1], #16
+	stp	x3, x4, [x0], #16
+	sub	x2, x2, #16
+	b	m_loop16
+	/* copy byte per byte */
+m_loop1:
+	cbz	x2, boot_cpu
+	ldrb	w3, [x1], #1
+	strb	w3, [x0], #1
+	subs	x2, x2, #1
+	b.ne	m_loop1
+
+boot_cpu:
+	adr	x0, __tegra186_cpu_reset_handler_data
+	ldr	x0, [x0]
+	br	x0
+endfunc tegra186_cpu_reset_handler
+
+	/*
+	 * Tegra186 reset data (offset 0x0 - 0x430)
+	 *
+	 * 0x000: secure world's entrypoint
+	 * 0x008: BL31 size (RO + RW)
+	 * 0x00C: SMMU context start
+	 * 0x42C: SMMU context end
+	 */
+
+	.align 4
+	.type	__tegra186_cpu_reset_handler_data, %object
+	.globl	__tegra186_cpu_reset_handler_data
+__tegra186_cpu_reset_handler_data:
+	.quad	tegra_secure_entrypoint
+	.quad	__BL31_END__ - BL31_BASE
+
+	.globl	__tegra186_system_suspend_state
+__tegra186_system_suspend_state:
+	.quad	0
+
+	.align 4
+	.globl	__tegra186_smmu_context
+__tegra186_smmu_context:
+	.rept	TEGRA186_SMMU_CTX_SIZE
+	.quad	0
+	.endr
+	.size	__tegra186_cpu_reset_handler_data, \
+		. - __tegra186_cpu_reset_handler_data
+
+	.align 4
+	.globl	__tegra186_cpu_reset_handler_end
+__tegra186_cpu_reset_handler_end:
+
+	.globl tegra186_get_cpu_reset_handler_size
+	.globl tegra186_get_cpu_reset_handler_base
+	.globl tegra186_get_smmu_ctx_offset
+	.globl tegra186_set_system_suspend_entry
+
+/* return size of the CPU reset handler */
+func tegra186_get_cpu_reset_handler_size
+	adr	x0, __tegra186_cpu_reset_handler_end
+	adr	x1, tegra186_cpu_reset_handler
+	sub	x0, x0, x1
+	ret
+endfunc tegra186_get_cpu_reset_handler_size
+
+/* return the start address of the CPU reset handler */
+func tegra186_get_cpu_reset_handler_base
+	adr	x0, tegra186_cpu_reset_handler
+	ret
+endfunc tegra186_get_cpu_reset_handler_base
+
+/* return the size of the SMMU context */
+func tegra186_get_smmu_ctx_offset
+	adr	x0, __tegra186_smmu_context
+	adr	x1, tegra186_cpu_reset_handler
+	sub	x0, x0, x1
+	ret
+endfunc tegra186_get_smmu_ctx_offset
+
+/* set system suspend state before SC7 entry */
+func tegra186_set_system_suspend_entry
+	mov	x0, #TEGRA_MC_BASE
+	mov	x3, #MC_SECURITY_CFG3_0
+	ldr	w1, [x0, x3]
+	lsl	x1, x1, #32
+	mov	x3, #MC_SECURITY_CFG0_0
+	ldr	w2, [x0, x3]
+	orr	x3, x1, x2			/* TZDRAM base */
+	adr	x0, __tegra186_system_suspend_state
+	adr	x1, tegra186_cpu_reset_handler
+	sub	x2, x0, x1			/* offset in TZDRAM */
+	mov	x0, #TEGRA186_STATE_SYSTEM_SUSPEND
+	lsl	x0, x0, #16
+	add	x0, x0, #TEGRA186_STATE_SYSTEM_SUSPEND
+	str	x0, [x3, x2]			/* set value in TZDRAM */
+	dsb	sy
+	ret
+endfunc tegra186_set_system_suspend_entry
diff --git a/plat/nvidia/tegra/soc/t186/platform_t186.mk b/plat/nvidia/tegra/soc/t186/platform_t186.mk
new file mode 100644
index 0000000..fe15853
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t186/platform_t186.mk
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# platform configs
+ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS	:= 1
+$(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS))
+
+ENABLE_CHIP_VERIFICATION_HARNESS	:= 0
+$(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS))
+
+RESET_TO_BL31				:= 1
+
+PROGRAMMABLE_RESET_ADDRESS		:= 1
+
+COLD_BOOT_SINGLE_CPU			:= 1
+
+# platform settings
+TZDRAM_BASE				:= 0x30000000
+$(eval $(call add_define,TZDRAM_BASE))
+
+PLATFORM_CLUSTER_COUNT			:= 2
+$(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
+
+PLATFORM_MAX_CPUS_PER_CLUSTER		:= 4
+$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
+
+MAX_XLAT_TABLES				:= 24
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS			:= 25
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
+# platform files
+PLAT_INCLUDES		+=	-I${SOC_DIR}/drivers/include
+
+BL31_SOURCES		+=	drivers/ti/uart/aarch64/16550_console.S	\
+				lib/cpus/aarch64/denver.S		\
+				lib/cpus/aarch64/cortex_a57.S		\
+				${COMMON_DIR}/drivers/gpcdma/gpcdma.c	\
+				${COMMON_DIR}/drivers/memctrl/memctrl_v2.c \
+				${COMMON_DIR}/drivers/smmu/smmu.c	\
+				${SOC_DIR}/drivers/mce/mce.c		\
+				${SOC_DIR}/drivers/mce/ari.c		\
+				${SOC_DIR}/drivers/mce/nvg.c		\
+				${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \
+				${SOC_DIR}/plat_memctrl.c		\
+				${SOC_DIR}/plat_psci_handlers.c		\
+				${SOC_DIR}/plat_setup.c			\
+				${SOC_DIR}/plat_secondary.c		\
+				${SOC_DIR}/plat_sip_calls.c		\
+				${SOC_DIR}/plat_smmu.c			\
+				${SOC_DIR}/plat_trampoline.S
+
+# Enable workarounds for selected Cortex-A57 erratas.
+A57_DISABLE_NON_TEMPORAL_HINT	:=	1
+ERRATA_A57_806969		:=	1
+ERRATA_A57_813419		:=	1
+ERRATA_A57_813420		:=	1
+ERRATA_A57_826974		:=	1
+ERRATA_A57_826977		:=	1
+ERRATA_A57_828024		:=	1
+ERRATA_A57_829520		:=	1
+ERRATA_A57_833471		:=	1
diff --git a/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h
new file mode 100644
index 0000000..be1f9cc
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h
@@ -0,0 +1,659 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SE_PRIVATE_H
+#define SE_PRIVATE_H
+
+#include <stdbool.h>
+#include <security_engine.h>
+
+/*
+ * PMC registers
+ */
+
+/* Secure scratch registers */
+#define PMC_SECURE_SCRATCH4_OFFSET		0xC0U
+#define PMC_SECURE_SCRATCH5_OFFSET		0xC4U
+#define PMC_SECURE_SCRATCH6_OFFSET		0x224U
+#define PMC_SECURE_SCRATCH7_OFFSET		0x228U
+#define PMC_SECURE_SCRATCH116_OFFSET		0xB28U
+#define PMC_SECURE_SCRATCH117_OFFSET		0xB2CU
+#define PMC_SECURE_SCRATCH120_OFFSET		0xB38U
+#define PMC_SECURE_SCRATCH121_OFFSET		0xB3CU
+#define PMC_SECURE_SCRATCH122_OFFSET		0xB40U
+#define PMC_SECURE_SCRATCH123_OFFSET		0xB44U
+
+/*
+ * AHB arbitration memory write queue
+ */
+#define ARAHB_MEM_WRQUE_MST_ID_OFFSET		0xFCU
+#define ARAHB_MST_ID_SE2_MASK			(0x1U << 13)
+#define ARAHB_MST_ID_SE_MASK			(0x1U << 14)
+
+/**
+ * SE registers
+ */
+#define TEGRA_SE_AES_KEYSLOT_COUNT		16
+#define SE_MAX_LAST_BLOCK_SIZE			0xFFFFF
+
+/* SE Status register */
+#define SE_STATUS_OFFSET			0x800U
+#define SE_STATUS_SHIFT				0
+#define SE_STATUS_IDLE	\
+		((0U) << SE_STATUS_SHIFT)
+#define SE_STATUS_BUSY	\
+		((1U) << SE_STATUS_SHIFT)
+#define SE_STATUS(x)	\
+		((x) & ((0x3U) << SE_STATUS_SHIFT))
+
+#define SE_MEM_INTERFACE_SHIFT			2
+#define SE_MEM_INTERFACE_IDLE			0
+#define SE_MEM_INTERFACE_BUSY			1
+#define SE_MEM_INTERFACE(x)	((x) << SE_STATUS_SHIFT)
+
+/* SE register definitions */
+#define SE_SECURITY_REG_OFFSET			0x0
+#define SE_SECURITY_TZ_LOCK_SOFT_SHIFT		5
+#define SE_SECURE				0x0
+#define SE_SECURITY_TZ_LOCK_SOFT(x)	((x) << SE_SECURITY_TZ_LOCK_SOFT_SHIFT)
+
+#define SE_SEC_ENG_DIS_SHIFT			1
+#define SE_DISABLE_FALSE			0
+#define SE_DISABLE_TRUE				1
+#define SE_SEC_ENG_DISABLE(x)((x) << SE_SEC_ENG_DIS_SHIFT)
+
+/* SE config register */
+#define SE_CONFIG_REG_OFFSET			0x14U
+#define SE_CONFIG_ENC_ALG_SHIFT 		12
+#define SE_CONFIG_ENC_ALG_AES_ENC	\
+		((1U) << SE_CONFIG_ENC_ALG_SHIFT)
+#define SE_CONFIG_ENC_ALG_RNG	\
+		((2U) << SE_CONFIG_ENC_ALG_SHIFT)
+#define SE_CONFIG_ENC_ALG_SHA	\
+		((3U) << SE_CONFIG_ENC_ALG_SHIFT)
+#define SE_CONFIG_ENC_ALG_RSA	\
+		((4U) << SE_CONFIG_ENC_ALG_SHIFT)
+#define SE_CONFIG_ENC_ALG_NOP	\
+		((0U) << SE_CONFIG_ENC_ALG_SHIFT)
+#define SE_CONFIG_ENC_ALG(x)	\
+		((x) & ((0xFU) << SE_CONFIG_ENC_ALG_SHIFT))
+
+#define SE_CONFIG_DEC_ALG_SHIFT 		8
+#define SE_CONFIG_DEC_ALG_AES	\
+		((1U) << SE_CONFIG_DEC_ALG_SHIFT)
+#define SE_CONFIG_DEC_ALG_NOP	\
+		((0U) << SE_CONFIG_DEC_ALG_SHIFT)
+#define SE_CONFIG_DEC_ALG(x)	\
+		((x) & ((0xFU) << SE_CONFIG_DEC_ALG_SHIFT))
+
+#define SE_CONFIG_DST_SHIFT	 		2
+#define SE_CONFIG_DST_MEMORY	\
+		((0U) << SE_CONFIG_DST_SHIFT)
+#define SE_CONFIG_DST_HASHREG	\
+		((1U) << SE_CONFIG_DST_SHIFT)
+#define SE_CONFIG_DST_KEYTAB	\
+		((2U) << SE_CONFIG_DST_SHIFT)
+#define SE_CONFIG_DST_SRK	\
+		((3U) << SE_CONFIG_DST_SHIFT)
+#define SE_CONFIG_DST_RSAREG	\
+		((4U) << SE_CONFIG_DST_SHIFT)
+#define SE_CONFIG_DST(x)	\
+		((x) & ((0x7U) << SE_CONFIG_DST_SHIFT))
+
+#define SE_CONFIG_ENC_MODE_SHIFT		24
+#define SE_CONFIG_ENC_MODE_KEY128	\
+			((0UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_KEY192	\
+			((1UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_KEY256	\
+			((2UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_SHA1				\
+			((0UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_SHA224	\
+			((4UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_SHA256	\
+			((5UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_SHA384	\
+			((6UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE_SHA512	\
+			((7UL) << SE_CONFIG_ENC_MODE_SHIFT)
+#define SE_CONFIG_ENC_MODE(x)\
+			((x) & ((0xFFUL) << SE_CONFIG_ENC_MODE_SHIFT))
+
+#define SE_CONFIG_DEC_MODE_SHIFT		16
+#define SE_CONFIG_DEC_MODE_KEY128	\
+			((0UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_KEY192	\
+			((1UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_KEY256	\
+			((2UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_SHA1				\
+			((0UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_SHA224	\
+			((4UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_SHA256	\
+			((5UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_SHA384	\
+			((6UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE_SHA512	\
+			((7UL) << SE_CONFIG_DEC_MODE_SHIFT)
+#define SE_CONFIG_DEC_MODE(x)\
+			((x) & ((0xFFUL) << SE_CONFIG_DEC_MODE_SHIFT))
+
+
+/* DRBG random number generator config */
+#define SE_RNG_CONFIG_REG_OFFSET		0x340
+
+#define DRBG_MODE_SHIFT				0
+#define DRBG_MODE_NORMAL		\
+		((0U) << DRBG_MODE_SHIFT)
+#define DRBG_MODE_FORCE_INSTANTION  \
+		((1U) << DRBG_MODE_SHIFT)
+#define DRBG_MODE_FORCE_RESEED	  \
+		((2U) << DRBG_MODE_SHIFT)
+#define SE_RNG_CONFIG_MODE(x)   \
+		((x) & ((0x3U) << DRBG_MODE_SHIFT))
+
+#define DRBG_SRC_SHIFT				2
+#define DRBG_SRC_NONE	   \
+		((0U) << DRBG_SRC_SHIFT)
+#define DRBG_SRC_ENTROPY	\
+		((1U) << DRBG_SRC_SHIFT)
+#define DRBG_SRC_LFSR	   \
+		((2U) << DRBG_SRC_SHIFT)
+#define SE_RNG_SRC_CONFIG_MODE(x)   \
+		((x) & ((0x3U) << DRBG_SRC_SHIFT))
+
+/* DRBG random number generator entropy config */
+
+#define SE_RNG_SRC_CONFIG_REG_OFFSET		0x344U
+
+#define DRBG_RO_ENT_SRC_SHIFT			1
+#define DRBG_RO_ENT_SRC_ENABLE	\
+		((1U) << DRBG_RO_ENT_SRC_SHIFT)
+#define DRBG_RO_ENT_SRC_DISABLE	\
+		((0U) << DRBG_RO_ENT_SRC_SHIFT)
+#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x)	\
+		((x) & ((0x1U) << DRBG_RO_ENT_SRC_SHIFT))
+
+#define DRBG_RO_ENT_SRC_LOCK_SHIFT		0
+#define DRBG_RO_ENT_SRC_LOCK_ENABLE	\
+		((1U) << DRBG_RO_ENT_SRC_LOCK_SHIFT)
+#define DRBG_RO_ENT_SRC_LOCK_DISABLE	\
+		((0U) << DRBG_RO_ENT_SRC_LOCK_SHIFT)
+#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x)	\
+		((x) & ((0x1U) << DRBG_RO_ENT_SRC_LOCK_SHIFT))
+
+#define DRBG_RO_ENT_IGNORE_MEM_SHIFT		12
+#define DRBG_RO_ENT_IGNORE_MEM_ENABLE	\
+		((1U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT)
+#define DRBG_RO_ENT_IGNORE_MEM_DISABLE	\
+		((0U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT)
+#define SE_RNG_SRC_CONFIG_RO_ENT_IGNORE_MEM(x)	\
+		((x) & ((0x1U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT))
+
+#define SE_RNG_RESEED_INTERVAL_REG_OFFSET	0x348
+
+/* SE CRYPTO */
+#define SE_CRYPTO_REG_OFFSET			0x304
+#define SE_CRYPTO_HASH_SHIFT			0
+#define SE_CRYPTO_HASH_DISABLE	\
+		((0U) << SE_CRYPTO_HASH_SHIFT)
+#define SE_CRYPTO_HASH_ENABLE	\
+		((1U) << SE_CRYPTO_HASH_SHIFT)
+
+#define SE_CRYPTO_XOR_POS_SHIFT			1
+#define SE_CRYPTO_XOR_BYPASS	\
+		((0U) << SE_CRYPTO_XOR_POS_SHIFT)
+#define SE_CRYPTO_XOR_TOP	\
+		((2U) << SE_CRYPTO_XOR_POS_SHIFT)
+#define SE_CRYPTO_XOR_BOTTOM	\
+		((3U) << SE_CRYPTO_XOR_POS_SHIFT)
+
+#define SE_CRYPTO_INPUT_SEL_SHIFT		3
+#define SE_CRYPTO_INPUT_AHB 	\
+		((0U) << SE_CRYPTO_INPUT_SEL_SHIFT)
+#define SE_CRYPTO_INPUT_RANDOM	\
+		((1U) << SE_CRYPTO_INPUT_SEL_SHIFT)
+#define SE_CRYPTO_INPUT_AESOUT	\
+		((2U) << SE_CRYPTO_INPUT_SEL_SHIFT)
+#define SE_CRYPTO_INPUT_LNR_CTR \
+		((3U) << SE_CRYPTO_INPUT_SEL_SHIFT)
+
+#define SE_CRYPTO_VCTRAM_SEL_SHIFT		 5
+#define SE_CRYPTO_VCTRAM_AHB	\
+		((0U) << SE_CRYPTO_VCTRAM_SEL_SHIFT)
+#define SE_CRYPTO_VCTRAM_AESOUT \
+		((2U) << SE_CRYPTO_VCTRAM_SEL_SHIFT)
+#define SE_CRYPTO_VCTRAM_PREVAHB	\
+		((3U) << SE_CRYPTO_VCTRAM_SEL_SHIFT)
+
+#define SE_CRYPTO_IV_SEL_SHIFT			 7
+#define SE_CRYPTO_IV_ORIGINAL	\
+		((0U) << SE_CRYPTO_IV_SEL_SHIFT)
+#define SE_CRYPTO_IV_UPDATED	\
+		((1U) << SE_CRYPTO_IV_SEL_SHIFT)
+
+#define SE_CRYPTO_CORE_SEL_SHIFT		8
+#define SE_CRYPTO_CORE_DECRYPT	\
+		((0U) << SE_CRYPTO_CORE_SEL_SHIFT)
+#define SE_CRYPTO_CORE_ENCRYPT	\
+		((1U) << SE_CRYPTO_CORE_SEL_SHIFT)
+
+#define SE_CRYPTO_KEY_INDEX_SHIFT		24
+#define SE_CRYPTO_KEY_INDEX(x) (x << SE_CRYPTO_KEY_INDEX_SHIFT)
+
+#define SE_CRYPTO_MEMIF_AHB	\
+		((0U) << SE_CRYPTO_MEMIF_SHIFT)
+#define SE_CRYPTO_MEMIF_MCCIF	\
+		((1U) << SE_CRYPTO_MEMIF_SHIFT)
+#define SE_CRYPTO_MEMIF_SHIFT			31
+
+/* KEY TABLE */
+#define SE_KEYTABLE_REG_OFFSET			0x31C
+
+/* KEYIV PKT - key slot */
+#define SE_KEYTABLE_SLOT_SHIFT			4
+#define SE_KEYTABLE_SLOT(x)	(x << SE_KEYTABLE_SLOT_SHIFT)
+
+/* KEYIV PKT - KEYIV select */
+#define SE_KEYIV_PKT_KEYIV_SEL_SHIFT		3
+#define SE_CRYPTO_KEYIV_KEY	\
+		((0U) << SE_KEYIV_PKT_KEYIV_SEL_SHIFT)
+#define SE_CRYPTO_KEYIV_IVS	\
+		((1U) << SE_KEYIV_PKT_KEYIV_SEL_SHIFT)
+
+/* KEYIV PKT - IV select */
+#define SE_KEYIV_PKT_IV_SEL_SHIFT		2
+#define SE_CRYPTO_KEYIV_IVS_OIV	\
+		((0U) << SE_KEYIV_PKT_IV_SEL_SHIFT)
+#define SE_CRYPTO_KEYIV_IVS_UIV \
+		((1U) << SE_KEYIV_PKT_IV_SEL_SHIFT)
+
+/* KEYIV PKT - key word */
+#define SE_KEYIV_PKT_KEY_WORD_SHIFT		0
+#define SE_KEYIV_PKT_KEY_WORD(x)	\
+		((x) << SE_KEYIV_PKT_KEY_WORD_SHIFT)
+
+/* KEYIV PKT - iv word */
+#define SE_KEYIV_PKT_IV_WORD_SHIFT		0
+#define SE_KEYIV_PKT_IV_WORD(x)		\
+		((x) << SE_KEYIV_PKT_IV_WORD_SHIFT)
+
+/* SE OPERATION */
+#define SE_OPERATION_REG_OFFSET 		0x8U
+#define SE_OPERATION_SHIFT			0
+#define SE_OP_ABORT	\
+		((0x0U) << SE_OPERATION_SHIFT)
+#define SE_OP_START	\
+		((0x1U) << SE_OPERATION_SHIFT)
+#define SE_OP_RESTART	\
+		((0x2U) << SE_OPERATION_SHIFT)
+#define SE_OP_CTX_SAVE	\
+		((0x3U) << SE_OPERATION_SHIFT)
+#define SE_OP_RESTART_IN	\
+		((0x4U) << SE_OPERATION_SHIFT)
+#define SE_OPERATION(x)	\
+		((x) & ((0x7U) << SE_OPERATION_SHIFT))
+
+/* SE CONTEXT */
+#define SE_CTX_SAVE_CONFIG_REG_OFFSET		0x70
+#define SE_CTX_SAVE_WORD_QUAD_SHIFT		0
+#define SE_CTX_SAVE_WORD_QUAD(x)	\
+		(x << SE_CTX_SAVE_WORD_QUAD_SHIFT)
+#define SE_CTX_SAVE_WORD_QUAD_KEYS_0_3	\
+		((0U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
+#define SE_CTX_SAVE_WORD_QUAD_KEYS_4_7	\
+		((1U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
+#define SE_CTX_SAVE_WORD_QUAD_ORIG_IV	\
+		((2U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
+#define SE_CTX_SAVE_WORD_QUAD_UPD_IV	\
+		((3U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
+
+#define SE_CTX_SAVE_KEY_INDEX_SHIFT		8
+#define SE_CTX_SAVE_KEY_INDEX(x)	(x << SE_CTX_SAVE_KEY_INDEX_SHIFT)
+
+#define SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT	24
+#define SE_CTX_SAVE_STICKY_WORD_QUAD_STICKY_0_3	\
+		((0U) << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT)
+#define SE_CTX_SAVE_STICKY_WORD_QUAD_STICKY_4_7	\
+		((1U) << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT)
+#define SE_CTX_SAVE_STICKY_WORD_QUAD(x)	\
+		(x << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT)
+
+#define SE_CTX_SAVE_SRC_SHIFT			29
+#define SE_CTX_SAVE_SRC_STICKY_BITS	\
+		((0U) << SE_CTX_SAVE_SRC_SHIFT)
+#define SE_CTX_SAVE_SRC_RSA_KEYTABLE	\
+		((1U) << SE_CTX_SAVE_SRC_SHIFT)
+#define SE_CTX_SAVE_SRC_AES_KEYTABLE	\
+		((2U) << SE_CTX_SAVE_SRC_SHIFT)
+#define SE_CTX_SAVE_SRC_PKA1_STICKY_BITS	\
+		((3U) << SE_CTX_SAVE_SRC_SHIFT)
+#define SE_CTX_SAVE_SRC_MEM	\
+		((4U) << SE_CTX_SAVE_SRC_SHIFT)
+#define SE_CTX_SAVE_SRC_SRK	\
+		((6U) << SE_CTX_SAVE_SRC_SHIFT)
+#define SE_CTX_SAVE_SRC_PKA1_KEYTABLE	\
+		((7U) << SE_CTX_SAVE_SRC_SHIFT)
+
+#define SE_CTX_STICKY_WORD_QUAD_SHIFT		24
+#define SE_CTX_STICKY_WORD_QUAD_WORDS_0_3 \
+		((0U) << SE_CTX_STICKY_WORD_QUAD_SHIFT)
+#define SE_CTX_STICKY_WORD_QUAD_WORDS_4_7 \
+		((1U) << SE_CTX_STICKY_WORD_QUAD_SHIFT)
+#define SE_CTX_STICKY_WORD_QUAD(x)	 (x << SE_CTX_STICKY_WORD_QUAD_SHIFT)
+
+#define SE_CTX_SAVE_RSA_KEY_INDEX_SHIFT		16
+#define SE_CTX_SAVE_RSA_KEY_INDEX(x)				\
+			(x << SE_CTX_SAVE_RSA_KEY_INDEX_SHIFT)
+
+#define SE_CTX_RSA_WORD_QUAD_SHIFT		12
+#define SE_CTX_RSA_WORD_QUAD(x)	\
+			(x << SE_CTX_RSA_WORD_QUAD_SHIFT)
+
+#define SE_CTX_PKA1_WORD_QUAD_L_SHIFT		0
+#define SE_CTX_PKA1_WORD_QUAD_L_SIZE		\
+			((true ? 4:0) - \
+			(false ? 4:0) + 1)
+#define SE_CTX_PKA1_WORD_QUAD_L(x)\
+			(((x) << SE_CTX_PKA1_WORD_QUAD_L_SHIFT) & 0x1f)
+
+#define SE_CTX_PKA1_WORD_QUAD_H_SHIFT		12
+#define SE_CTX_PKA1_WORD_QUAD_H(x)\
+			((((x) >> SE_CTX_PKA1_WORD_QUAD_L_SIZE) & 0xf) \
+			<< SE_CTX_PKA1_WORD_QUAD_H_SHIFT)
+
+#define SE_RSA_KEY_INDEX_SLOT0_EXP		0
+#define SE_RSA_KEY_INDEX_SLOT0_MOD		1
+#define SE_RSA_KEY_INDEX_SLOT1_EXP		2
+#define SE_RSA_KEY_INDEX_SLOT1_MOD		3
+
+
+/* SE_CTX_SAVE_AUTO */
+#define SE_CTX_SAVE_AUTO_REG_OFFSET 		0x74U
+
+/* Enable */
+#define SE_CTX_SAVE_AUTO_ENABLE_SHIFT		0
+#define SE_CTX_SAVE_AUTO_DIS	\
+		((0U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT)
+#define SE_CTX_SAVE_AUTO_EN	\
+		((1U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT)
+#define SE_CTX_SAVE_AUTO_ENABLE(x)	\
+		((x) & ((0x1U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT))
+
+/* Lock */
+#define SE_CTX_SAVE_AUTO_LOCK_SHIFT 		8
+#define SE_CTX_SAVE_AUTO_LOCK_EN	\
+		((1U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT)
+#define SE_CTX_SAVE_AUTO_LOCK_DIS	\
+		((0U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT)
+#define SE_CTX_SAVE_AUTO_LOCK(x)	\
+		((x) & ((0x1U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT))
+
+/* Current context save number of blocks*/
+#define SE_CTX_SAVE_AUTO_CURR_CNT_SHIFT		16
+#define SE_CTX_SAVE_AUTO_CURR_CNT_MASK 		0x3FFU
+#define SE_CTX_SAVE_GET_BLK_COUNT(x)	\
+		(((x) >> SE_CTX_SAVE_AUTO_CURR_CNT_SHIFT) & \
+		SE_CTX_SAVE_AUTO_CURR_CNT_MASK)
+
+#define SE_CTX_SAVE_SIZE_BLOCKS_SE1		133
+#define SE_CTX_SAVE_SIZE_BLOCKS_SE2	 	646
+
+/* SE TZRAM OPERATION - only for SE1 */
+#define SE_TZRAM_OPERATION			0x540U
+
+#define SE_TZRAM_OP_MODE_SHIFT			1
+#define SE_TZRAM_OP_COMMAND_INIT		1
+#define SE_TZRAM_OP_COMMAND_SHIFT		0
+#define SE_TZRAM_OP_MODE_SAVE		\
+		((0U) << SE_TZRAM_OP_MODE_SHIFT)
+#define SE_TZRAM_OP_MODE_RESTORE	\
+		((1U) << SE_TZRAM_OP_MODE_SHIFT)
+#define SE_TZRAM_OP_MODE(x)		\
+		((x) & ((0x1U) << SE_TZRAM_OP_MODE_SHIFT))
+
+#define SE_TZRAM_OP_BUSY_SHIFT			2
+#define SE_TZRAM_OP_BUSY_OFF	\
+		((0U) << SE_TZRAM_OP_BUSY_SHIFT)
+#define SE_TZRAM_OP_BUSY_ON	\
+		((1U) << SE_TZRAM_OP_BUSY_SHIFT)
+#define SE_TZRAM_OP_BUSY(x)	\
+		((x) & ((0x1U) << SE_TZRAM_OP_BUSY_SHIFT))
+
+#define SE_TZRAM_OP_REQ_SHIFT			0
+#define SE_TZRAM_OP_REQ_IDLE	\
+		((0U) << SE_TZRAM_OP_REQ_SHIFT)
+#define SE_TZRAM_OP_REQ_INIT	\
+		((1U) << SE_TZRAM_OP_REQ_SHIFT)
+#define SE_TZRAM_OP_REQ(x)	\
+		((x) & ((0x1U) << SE_TZRAM_OP_REQ_SHIFT))
+
+/* SE Interrupt */
+#define SE_INT_STATUS_REG_OFFSET		0x10U
+#define SE_INT_OP_DONE_SHIFT			4
+#define SE_INT_OP_DONE_CLEAR	\
+		((0U) << SE_INT_OP_DONE_SHIFT)
+#define SE_INT_OP_DONE_ACTIVE	\
+		((1U) << SE_INT_OP_DONE_SHIFT)
+#define SE_INT_OP_DONE(x)	\
+		((x) & ((0x1U) << SE_INT_OP_DONE_SHIFT))
+
+/* SE TZRAM SECURITY */
+#define SE_TZRAM_SEC_REG_OFFSET			0x4
+
+#define SE_TZRAM_SEC_SETTING_SHIFT		 0
+#define SE_TZRAM_SECURE		\
+		((0UL) << SE_TZRAM_SEC_SETTING_SHIFT)
+#define SE_TZRAM_NONSECURE	 \
+		((1UL) << SE_TZRAM_SEC_SETTING_SHIFT)
+#define SE_TZRAM_SEC_SETTING(x)		\
+		((x) & ((0x1UL) << SE_TZRAM_SEC_SETTING_SHIFT))
+
+/* PKA1 KEY SLOTS */
+#define TEGRA_SE_PKA1_KEYSLOT_COUNT		4
+
+
+/* SE error status */
+#define SE_ERR_STATUS_REG_OFFSET		0x804U
+#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET	0x330
+#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT	0
+#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x)	\
+			(x << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT)
+
+#define SE_KEY_INDEX_SHIFT			8
+#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x)	(x << SE_KEY_INDEX_SHIFT)
+
+
+/* SE linked list (LL) register */
+#define SE_IN_LL_ADDR_REG_OFFSET		0x18U
+#define SE_OUT_LL_ADDR_REG_OFFSET		0x24U
+#define SE_BLOCK_COUNT_REG_OFFSET		0x318U
+
+/* AES data sizes */
+#define TEGRA_SE_KEY_256_SIZE			32
+#define TEGRA_SE_KEY_192_SIZE			24
+#define TEGRA_SE_KEY_128_SIZE			16
+#define TEGRA_SE_AES_BLOCK_SIZE 		16
+#define TEGRA_SE_AES_MIN_KEY_SIZE		16
+#define TEGRA_SE_AES_MAX_KEY_SIZE		32
+#define TEGRA_SE_AES_IV_SIZE			16
+
+#define TEGRA_SE_RNG_IV_SIZE			16
+#define TEGRA_SE_RNG_DT_SIZE			16
+#define TEGRA_SE_RNG_KEY_SIZE			16
+#define TEGRA_SE_RNG_SEED_SIZE	(TEGRA_SE_RNG_IV_SIZE + \
+									TEGRA_SE_RNG_KEY_SIZE + \
+									TEGRA_SE_RNG_DT_SIZE)
+#define TEGRA_SE_RSA512_DIGEST_SIZE		64
+#define TEGRA_SE_RSA1024_DIGEST_SIZE		128
+#define TEGRA_SE_RSA1536_DIGEST_SIZE		192
+#define TEGRA_SE_RSA2048_DIGEST_SIZE		256
+
+#define SE_KEY_TABLE_ACCESS_REG_OFFSET		0x284
+#define SE_KEY_READ_DISABLE_SHIFT		0
+
+#define SE_CTX_BUFER_SIZE			1072
+#define SE_CTX_DRBG_BUFER_SIZE			2112
+
+/* SE blobs size in bytes */
+#define SE_CTX_SAVE_RSA_KEY_LENGTH		1024
+#define SE_CTX_SAVE_RANDOM_DATA_SIZE		16
+#define SE_CTX_SAVE_STICKY_BITS_SIZE		16
+#define SE2_CONTEXT_SAVE_PKA1_STICKY_BITS_LENGTH 16
+#define SE2_CONTEXT_SAVE_PKA1_KEYS_LENGTH	8192
+#define SE_CTX_KNOWN_PATTERN_SIZE		16
+#define SE_CTX_KNOWN_PATTERN_SIZE_WORDS		(SE_CTX_KNOWN_PATTERN_SIZE/4)
+
+/* SE RSA */
+#define TEGRA_SE_RSA_KEYSLOT_COUNT		2
+#define SE_RSA_KEY_SIZE_REG_OFFSET		0x404
+#define SE_RSA_EXP_SIZE_REG_OFFSET		0x408
+#define SE_RSA_MAX_EXP_BIT_SIZE			2048
+#define SE_RSA_MAX_EXP_SIZE32	\
+		(SE_RSA_MAX_EXP_BIT_SIZE >> 5)
+#define SE_RSA_MAX_MOD_BIT_SIZE			2048
+#define SE_RSA_MAX_MOD_SIZE32	\
+		(SE_RSA_MAX_MOD_BIT_SIZE >> 5)
+
+/* SE_RSA_KEYTABLE_ADDR */
+#define SE_RSA_KEYTABLE_ADDR			0x420
+#define RSA_KEY_PKT_WORD_ADDR_SHIFT		0
+#define RSA_KEY_PKT_EXPMOD_SEL_SHIFT	\
+		((6U) << RSA_KEY_PKT_WORD_ADDR_SHIFT)
+#define RSA_KEY_MOD	\
+		((1U) << RSA_KEY_PKT_EXPMOD_SEL_SHIFT)
+#define RSA_KEY_EXP	\
+		((0U) << RSA_KEY_PKT_EXPMOD_SEL_SHIFT)
+#define RSA_KEY_PKT_SLOT_SHIFT			7
+#define RSA_KEY_SLOT_1	\
+		((0U) << RSA_KEY_PKT_SLOT_SHIFT)
+#define RSA_KEY_SLOT_2	\
+		((1U) << RSA_KEY_PKT_SLOT_SHIFT)
+#define RSA_KEY_PKT_INPUT_MODE_SHIFT		8
+#define RSA_KEY_REG_INPUT	\
+		((0U) << RSA_KEY_PKT_INPUT_MODE_SHIFT)
+#define RSA_KEY_DMA_INPUT	\
+		((1U) << RSA_KEY_PKT_INPUT_MODE_SHIFT)
+
+/* SE_RSA_KEYTABLE_DATA */
+#define SE_RSA_KEYTABLE_DATA			0x424
+
+/* SE_RSA_CONFIG register */
+#define SE_RSA_CONFIG				0x400
+#define RSA_KEY_SLOT_SHIFT			24
+#define RSA_KEY_SLOT(x) \
+		((x) << RSA_KEY_SLOT_SHIFT)
+
+/*******************************************************************************
+ * Structure definition
+ ******************************************************************************/
+
+/* SE context blob */
+#pragma pack(push, 1)
+typedef struct tegra_aes_key_slot {
+	/* 0 - 7 AES key */
+	uint32_t key[8];
+	/* 8 - 11 Original IV */
+	uint32_t oiv[4];
+	/* 12 - 15 Updated IV */
+	uint32_t uiv[4];
+} tegra_se_aes_key_slot_t;
+#pragma pack(pop)
+
+#pragma pack(push, 1)
+typedef struct tegra_se_context {
+	/* random number */
+	unsigned char rand_data[SE_CTX_SAVE_RANDOM_DATA_SIZE];
+	/* Sticky bits */
+	unsigned char sticky_bits[SE_CTX_SAVE_STICKY_BITS_SIZE * 2];
+	/* AES key slots */
+	tegra_se_aes_key_slot_t key_slots[TEGRA_SE_AES_KEYSLOT_COUNT];
+	/* RSA key slots */
+	unsigned char rsa_keys[SE_CTX_SAVE_RSA_KEY_LENGTH];
+} tegra_se_context_t;
+#pragma pack(pop)
+
+/* PKA context blob */
+#pragma pack(push, 1)
+typedef struct tegra_pka_context {
+	unsigned char sticky_bits[SE2_CONTEXT_SAVE_PKA1_STICKY_BITS_LENGTH];
+	unsigned char pka_keys[SE2_CONTEXT_SAVE_PKA1_KEYS_LENGTH];
+} tegra_pka_context_t;
+#pragma pack(pop)
+
+/* SE context blob */
+#pragma pack(push, 1)
+typedef struct tegra_se_context_blob {
+	/* SE context */
+	tegra_se_context_t se_ctx;
+	/* Known Pattern */
+	unsigned char known_pattern[SE_CTX_KNOWN_PATTERN_SIZE];
+} tegra_se_context_blob_t;
+#pragma pack(pop)
+
+/* SE2 and PKA1 context blob */
+#pragma pack(push, 1)
+typedef struct tegra_se2_context_blob {
+	/* SE2 context */
+	tegra_se_context_t se_ctx;
+	/* PKA1 context */
+	tegra_pka_context_t pka_ctx;
+	/* Known Pattern */
+	unsigned char known_pattern[SE_CTX_KNOWN_PATTERN_SIZE];
+} tegra_se2_context_blob_t;
+#pragma pack(pop)
+
+/* SE AES key type 128bit, 192bit, 256bit */
+typedef enum {
+	SE_AES_KEY128,
+	SE_AES_KEY192,
+	SE_AES_KEY256,
+} tegra_se_aes_key_type_t;
+
+/* SE RSA key slot */
+typedef struct tegra_se_rsa_key_slot {
+	/* 0 - 63 exponent key */
+	uint32_t exponent[SE_RSA_MAX_EXP_SIZE32];
+	/* 64 - 127 modulus key */
+	uint32_t modulus[SE_RSA_MAX_MOD_SIZE32];
+} tegra_se_rsa_key_slot_t;
+
+
+/*******************************************************************************
+ * Inline functions definition
+ ******************************************************************************/
+
+static inline uint32_t tegra_se_read_32(const tegra_se_dev_t *dev, uint32_t offset)
+{
+	return mmio_read_32(dev->se_base + offset);
+}
+
+static inline void tegra_se_write_32(const tegra_se_dev_t *dev, uint32_t offset, uint32_t val)
+{
+	mmio_write_32(dev->se_base + offset, val);
+}
+
+static inline uint32_t tegra_pka_read_32(tegra_pka_dev_t *dev, uint32_t offset)
+{
+	return mmio_read_32(dev->pka_base + offset);
+}
+
+static inline void tegra_pka_write_32(tegra_pka_dev_t *dev, uint32_t offset,
+uint32_t val)
+{
+	mmio_write_32(dev->pka_base + offset, val);
+}
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+int tegra_se_start_normal_operation(const tegra_se_dev_t *, uint32_t);
+int tegra_se_start_ctx_save_operation(const tegra_se_dev_t *, uint32_t);
+
+#endif /* SE_PRIVATE_H */
diff --git a/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c b/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c
new file mode 100644
index 0000000..8d7dbf9
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c
@@ -0,0 +1,1084 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <se_private.h>
+#include <security_engine.h>
+#include <tegra_platform.h>
+
+/*******************************************************************************
+ * Constants and Macros
+ ******************************************************************************/
+
+#define TIMEOUT_100MS	100U	// Timeout in 100ms
+#define RNG_AES_KEY_INDEX   1
+
+/*******************************************************************************
+ * Data structure and global variables
+ ******************************************************************************/
+
+/* The security engine contexts are formatted as follows:
+ *
+ * SE1 CONTEXT:
+ * #--------------------------------#
+ * |        Random Data   1 Block   |
+ * #--------------------------------#
+ * |        Sticky Bits   2 Blocks  |
+ * #--------------------------------#
+ * | Key Table           64 Blocks  |
+ * |     For each Key (x16):        |
+ * |      Key:         2 Blocks     |
+ * |      Original-IV: 1 Block      |
+ * |      Updated-IV:  1 Block      |
+ * #--------------------------------#
+ * |        RSA Keys     64 Blocks  |
+ * #--------------------------------#
+ * |        Known Pattern 1 Block   |
+ * #--------------------------------#
+ *
+ * SE2/PKA1 CONTEXT:
+ * #--------------------------------#
+ * |        Random Data   1 Block   |
+ * #--------------------------------#
+ * |        Sticky Bits   2 Blocks  |
+ * #--------------------------------#
+ * | Key Table           64 Blocks  |
+ * |     For each Key (x16):        |
+ * |      Key:         2 Blocks     |
+ * |      Original-IV: 1 Block      |
+ * |      Updated-IV:  1 Block      |
+ * #--------------------------------#
+ * |        RSA Keys     64 Blocks  |
+ * #--------------------------------#
+ * |        PKA sticky bits 1 Block |
+ * #--------------------------------#
+ * |        PKA keys    512 Blocks  |
+ * #--------------------------------#
+ * |        Known Pattern 1 Block   |
+ * #--------------------------------#
+ */
+
+/* Known pattern data */
+static const uint32_t se_ctx_known_pattern_data[SE_CTX_KNOWN_PATTERN_SIZE_WORDS] = {
+	/* 128 bit AES block */
+	0x0C0D0E0F,
+	0x08090A0B,
+	0x04050607,
+	0x00010203,
+};
+
+/* SE input and output linked list buffers */
+static tegra_se_io_lst_t se1_src_ll_buf;
+static tegra_se_io_lst_t se1_dst_ll_buf;
+
+/* SE2 input and output linked list buffers */
+static tegra_se_io_lst_t se2_src_ll_buf;
+static tegra_se_io_lst_t se2_dst_ll_buf;
+
+/* SE1 security engine device handle */
+static tegra_se_dev_t se_dev_1 = {
+	.se_num = 1,
+	/* Setup base address for se */
+	.se_base = TEGRA_SE1_BASE,
+	/* Setup context size in AES blocks */
+	.ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE1,
+	/* Setup SRC buffers for SE operations */
+	.src_ll_buf = &se1_src_ll_buf,
+	/* Setup DST buffers for SE operations */
+	.dst_ll_buf = &se1_dst_ll_buf,
+	/* Setup context save destination */
+	.ctx_save_buf = (uint32_t *)(TEGRA_TZRAM_CARVEOUT_BASE),
+};
+
+/* SE2 security engine device handle */
+static tegra_se_dev_t se_dev_2 = {
+	.se_num = 2,
+	/* Setup base address for se */
+	.se_base = TEGRA_SE2_BASE,
+	/* Setup context size in AES blocks */
+	.ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE2,
+	/* Setup SRC buffers for SE operations */
+	.src_ll_buf = &se2_src_ll_buf,
+	/* Setup DST buffers for SE operations */
+	.dst_ll_buf = &se2_dst_ll_buf,
+	/* Setup context save destination */
+	.ctx_save_buf = (uint32_t *)(TEGRA_TZRAM_CARVEOUT_BASE + 0x1000),
+};
+
+static bool ecid_valid;
+
+/*******************************************************************************
+ * Functions Definition
+ ******************************************************************************/
+
+static void tegra_se_make_data_coherent(const tegra_se_dev_t *se_dev)
+{
+	flush_dcache_range(((uint64_t)(se_dev->src_ll_buf)),
+			sizeof(tegra_se_io_lst_t));
+	flush_dcache_range(((uint64_t)(se_dev->dst_ll_buf)),
+			sizeof(tegra_se_io_lst_t));
+}
+
+/*
+ * Check that SE operation has completed after kickoff
+ * This function is invoked after an SE operation has been started,
+ * and it checks the following conditions:
+ * 1. SE_INT_STATUS = SE_OP_DONE
+ * 2. SE_STATUS = IDLE
+ * 3. AHB bus data transfer complete.
+ * 4. SE_ERR_STATUS is clean.
+ */
+static int32_t tegra_se_operation_complete(const tegra_se_dev_t *se_dev)
+{
+	uint32_t val = 0;
+	int32_t ret = 0;
+	uint32_t timeout;
+
+	/* Poll the SE interrupt register to ensure H/W operation complete */
+	val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
+	for (timeout = 0; (SE_INT_OP_DONE(val) == SE_INT_OP_DONE_CLEAR) &&
+			(timeout < TIMEOUT_100MS); timeout++) {
+		mdelay(1);
+		val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
+	}
+
+	if (timeout == TIMEOUT_100MS) {
+		ERROR("%s: ERR: Atomic context save operation timeout!\n",
+				__func__);
+		ret = -ETIMEDOUT;
+	}
+
+	/* Poll the SE status idle to ensure H/W operation complete */
+	if (ret == 0) {
+		val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
+		for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS);
+				timeout++) {
+			mdelay(1);
+			val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
+		}
+
+		if (timeout == TIMEOUT_100MS) {
+			ERROR("%s: ERR: MEM_INTERFACE and SE state "
+					"idle state timeout.\n", __func__);
+			ret = -ETIMEDOUT;
+		}
+	}
+
+	/* Check AHB bus transfer complete */
+	if (ret == 0) {
+		val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET);
+		for (timeout = 0; ((val & (ARAHB_MST_ID_SE_MASK | ARAHB_MST_ID_SE2_MASK)) != 0U) &&
+				(timeout < TIMEOUT_100MS); timeout++) {
+			mdelay(1);
+			val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET);
+		}
+
+		if (timeout == TIMEOUT_100MS) {
+			ERROR("%s: SE write over AHB timeout.\n", __func__);
+			ret = -ETIMEDOUT;
+		}
+	}
+
+	/* Ensure that no errors are thrown during operation */
+	if (ret == 0) {
+		val = tegra_se_read_32(se_dev, SE_ERR_STATUS_REG_OFFSET);
+		if (val != 0U) {
+			ERROR("%s: error during SE operation! 0x%x", __func__, val);
+			ret = -ENOTSUP;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Returns true if the SE engine is configured to perform SE context save in
+ * hardware.
+ */
+static inline bool tegra_se_atomic_save_enabled(const tegra_se_dev_t *se_dev)
+{
+	uint32_t val;
+
+	val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
+	return (SE_CTX_SAVE_AUTO_ENABLE(val) == SE_CTX_SAVE_AUTO_EN);
+}
+
+/*
+ * Wait for SE engine to be idle and clear pending interrupts before
+ * starting the next SE operation.
+ */
+static int32_t tegra_se_operation_prepare(const tegra_se_dev_t *se_dev)
+{
+	int32_t ret = 0;
+	uint32_t val = 0;
+	uint32_t timeout;
+
+	/* Wait for previous operation to finish */
+	val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
+	for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS); timeout++) {
+		mdelay(1);
+		val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET);
+	}
+
+	if (timeout == TIMEOUT_100MS) {
+		ERROR("%s: ERR: SE status is not idle!\n", __func__);
+		ret = -ETIMEDOUT;
+	}
+
+	/* Clear any pending interrupts from  previous operation */
+	val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET);
+	tegra_se_write_32(se_dev, SE_INT_STATUS_REG_OFFSET, val);
+	return ret;
+}
+
+/*
+ * SE atomic context save. At SC7 entry, SE driver triggers the
+ * hardware automatically performs the context save operation.
+ */
+static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev)
+{
+	int32_t ret = 0;
+	uint32_t val = 0;
+	uint32_t blk_count_limit = 0;
+	uint32_t block_count;
+
+	/* Check that previous operation is finalized */
+	ret = tegra_se_operation_prepare(se_dev);
+
+	/* Read the context save progress counter: block_count
+	 * Ensure no previous context save has been triggered
+	 * SE_CTX_SAVE_AUTO.CURR_CNT == 0
+	 */
+	if (ret == 0) {
+		val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
+		block_count = SE_CTX_SAVE_GET_BLK_COUNT(val);
+		if (block_count != 0U) {
+			ERROR("%s: ctx_save triggered multiple times\n",
+					__func__);
+			ret = -EALREADY;
+		}
+	}
+
+	/* Set the destination block count when the context save complete */
+	if (ret == 0) {
+		blk_count_limit = block_count + se_dev->ctx_size_blks;
+	}
+
+	/* Program SE_CONFIG register as for RNG operation
+	 * SE_CONFIG.ENC_ALG = RNG
+	 * SE_CONFIG.DEC_ALG = NOP
+	 * SE_CONFIG.ENC_MODE is ignored
+	 * SE_CONFIG.DEC_MODE is ignored
+	 * SE_CONFIG.DST = MEMORY
+	 */
+	if (ret == 0) {
+		val = (SE_CONFIG_ENC_ALG_RNG |
+			SE_CONFIG_DEC_ALG_NOP |
+			SE_CONFIG_DST_MEMORY);
+		tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
+
+		tegra_se_make_data_coherent(se_dev);
+
+		/* SE_CTX_SAVE operation */
+		tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET,
+				SE_OP_CTX_SAVE);
+
+		ret = tegra_se_operation_complete(se_dev);
+	}
+
+	/* Check that context has written the correct number of blocks */
+	if (ret == 0) {
+		val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET);
+		if (SE_CTX_SAVE_GET_BLK_COUNT(val) != blk_count_limit) {
+			ERROR("%s: expected %d blocks but %d were written\n",
+					__func__, blk_count_limit, val);
+			ret = -ECANCELED;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Security engine primitive operations, including normal operation
+ * and the context save operation.
+ */
+static int tegra_se_perform_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes,
+					bool context_save)
+{
+	uint32_t nblocks = nbytes / TEGRA_SE_AES_BLOCK_SIZE;
+	int ret = 0;
+
+	assert(se_dev);
+
+	/* Use device buffers for in and out */
+	tegra_se_write_32(se_dev, SE_OUT_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->dst_ll_buf)));
+	tegra_se_write_32(se_dev, SE_IN_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->src_ll_buf)));
+
+	/* Check that previous operation is finalized */
+	ret = tegra_se_operation_prepare(se_dev);
+	if (ret != 0) {
+		goto op_error;
+	}
+
+	/* Program SE operation size */
+	if (nblocks) {
+		tegra_se_write_32(se_dev, SE_BLOCK_COUNT_REG_OFFSET, nblocks - 1);
+	}
+
+	/* Make SE LL data coherent before the SE operation */
+	tegra_se_make_data_coherent(se_dev);
+
+	/* Start hardware operation */
+	if (context_save)
+		tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_CTX_SAVE);
+	else
+		tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_START);
+
+	/* Wait for operation to finish */
+	ret = tegra_se_operation_complete(se_dev);
+
+op_error:
+	return ret;
+}
+
+/*
+ * Normal security engine operations other than the context save
+ */
+int tegra_se_start_normal_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes)
+{
+	return tegra_se_perform_operation(se_dev, nbytes, false);
+}
+
+/*
+ * Security engine context save operation
+ */
+int tegra_se_start_ctx_save_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes)
+{
+	return tegra_se_perform_operation(se_dev, nbytes, true);
+}
+
+/*
+ * Security Engine sequence to generat SRK
+ * SE and SE2 will generate different SRK by different
+ * entropy seeds.
+ */
+static int tegra_se_generate_srk(const tegra_se_dev_t *se_dev)
+{
+	int ret = PSCI_E_INTERN_FAIL;
+	uint32_t val;
+
+	/* Confgure the following hardware register settings:
+	 * SE_CONFIG.DEC_ALG = NOP
+	 * SE_CONFIG.ENC_ALG = RNG
+	 * SE_CONFIG.DST = SRK
+	 * SE_OPERATION.OP = START
+	 * SE_CRYPTO_LAST_BLOCK = 0
+	 */
+	se_dev->src_ll_buf->last_buff_num = 0;
+	se_dev->dst_ll_buf->last_buff_num = 0;
+
+	/* Configure random number generator */
+	if (ecid_valid)
+		val = (DRBG_MODE_FORCE_INSTANTION | DRBG_SRC_ENTROPY);
+	else
+		val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_ENTROPY);
+	tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val);
+
+	/* Configure output destination = SRK */
+	val = (SE_CONFIG_ENC_ALG_RNG |
+		SE_CONFIG_DEC_ALG_NOP |
+		SE_CONFIG_DST_SRK);
+	tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
+
+	/* Perform hardware operation */
+	ret = tegra_se_start_normal_operation(se_dev, 0);
+
+	return ret;
+}
+
+/*
+ * Generate plain text random data to some memory location using
+ * SE/SE2's SP800-90 random number generator. The random data size
+ * must be some multiple of the AES block size (16 bytes).
+ */
+static int tegra_se_lp_generate_random_data(tegra_se_dev_t *se_dev)
+{
+	int ret = 0;
+	uint32_t val;
+
+	/* Set some arbitrary memory location to store the random data */
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	if (!se_dev->ctx_save_buf) {
+		ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__);
+		return PSCI_E_NOT_PRESENT;
+	}
+	se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(((tegra_se_context_t *)
+					se_dev->ctx_save_buf)->rand_data)));
+	se_dev->dst_ll_buf->buffer[0].data_len = SE_CTX_SAVE_RANDOM_DATA_SIZE;
+
+
+	/* Confgure the following hardware register settings:
+	 * SE_CONFIG.DEC_ALG = NOP
+	 * SE_CONFIG.ENC_ALG = RNG
+	 * SE_CONFIG.ENC_MODE = KEY192
+	 * SE_CONFIG.DST = MEMORY
+	 */
+	val = (SE_CONFIG_ENC_ALG_RNG |
+		SE_CONFIG_DEC_ALG_NOP |
+		SE_CONFIG_ENC_MODE_KEY192 |
+		SE_CONFIG_DST_MEMORY);
+	tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val);
+
+	/* Program the RNG options in SE_CRYPTO_CONFIG as follows:
+	 * XOR_POS = BYPASS
+	 * INPUT_SEL = RANDOM (Entropy or LFSR)
+	 * HASH_ENB = DISABLE
+	 */
+	val = (SE_CRYPTO_INPUT_RANDOM |
+		SE_CRYPTO_XOR_BYPASS |
+		SE_CRYPTO_CORE_ENCRYPT |
+		SE_CRYPTO_HASH_DISABLE |
+		SE_CRYPTO_KEY_INDEX(RNG_AES_KEY_INDEX) |
+		SE_CRYPTO_IV_ORIGINAL);
+	tegra_se_write_32(se_dev, SE_CRYPTO_REG_OFFSET, val);
+
+	/* Configure RNG */
+	if (ecid_valid)
+		val = (DRBG_MODE_FORCE_INSTANTION | DRBG_SRC_LFSR);
+	else
+		val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_LFSR);
+	tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val);
+
+	/* SE normal operation */
+	ret = tegra_se_start_normal_operation(se_dev, SE_CTX_SAVE_RANDOM_DATA_SIZE);
+
+	return ret;
+}
+
+/*
+ * Encrypt memory blocks with SRK as part of the security engine context.
+ * The data blocks include: random data and the known pattern data, where
+ * the random data is the first block and known pattern is the last block.
+ */
+static int tegra_se_lp_data_context_save(tegra_se_dev_t *se_dev,
+		uint64_t src_addr, uint64_t dst_addr, uint32_t data_size)
+{
+	int ret = 0;
+
+	se_dev->src_ll_buf->last_buff_num = 0;
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	se_dev->src_ll_buf->buffer[0].addr = src_addr;
+	se_dev->src_ll_buf->buffer[0].data_len = data_size;
+	se_dev->dst_ll_buf->buffer[0].addr = dst_addr;
+	se_dev->dst_ll_buf->buffer[0].data_len = data_size;
+
+	/* By setting the context source from memory and calling the context save
+	 * operation, the SE encrypts the memory data with SRK.
+	 */
+	tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, SE_CTX_SAVE_SRC_MEM);
+
+	ret = tegra_se_start_ctx_save_operation(se_dev, data_size);
+
+	return ret;
+}
+
+/*
+ * Context save the key table access control sticky bits and
+ * security status of each key-slot. The encrypted sticky-bits are
+ * 32 bytes (2 AES blocks) and formatted as the following structure:
+ * {	bit in registers			bit in context save
+ *	SECURITY_0[4]				158
+ *	SE_RSA_KEYTABLE_ACCE4SS_1[2:0]		157:155
+ *	SE_RSA_KEYTABLE_ACCE4SS_0[2:0]		154:152
+ *	SE_RSA_SECURITY_PERKEY_0[1:0]		151:150
+ *	SE_CRYPTO_KEYTABLE_ACCESS_15[7:0]	149:142
+ *	...,
+ *	SE_CRYPTO_KEYTABLE_ACCESS_0[7:0]	29:22
+ *	SE_CRYPTO_SECURITY_PERKEY_0[15:0]	21:6
+ *	SE_TZRAM_SECURITY_0[1:0]		5:4
+ *	SE_SECURITY_0[16]			3:3
+ *	SE_SECURITY_0[2:0] }			2:0
+ */
+static int tegra_se_lp_sticky_bits_context_save(tegra_se_dev_t *se_dev)
+{
+	int ret = PSCI_E_INTERN_FAIL;
+	uint32_t val = 0;
+
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	if (!se_dev->ctx_save_buf) {
+		ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__);
+		return PSCI_E_NOT_PRESENT;
+	}
+	se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(((tegra_se_context_t *)
+						se_dev->ctx_save_buf)->sticky_bits)));
+	se_dev->dst_ll_buf->buffer[0].data_len = SE_CTX_SAVE_STICKY_BITS_SIZE;
+
+	/*
+	 * The 1st AES block save the sticky-bits context 1 - 16 bytes (0 - 3 words).
+	 * The 2nd AES block save the sticky-bits context 17 - 32 bytes (4 - 7 words).
+	 */
+	for (int i = 0; i < 2; i++) {
+		val = SE_CTX_SAVE_SRC_STICKY_BITS |
+			SE_CTX_SAVE_STICKY_WORD_QUAD(i);
+		tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
+
+		/* SE context save operation */
+		ret = tegra_se_start_ctx_save_operation(se_dev,
+				SE_CTX_SAVE_STICKY_BITS_SIZE);
+		if (ret)
+			break;
+		se_dev->dst_ll_buf->buffer[0].addr += SE_CTX_SAVE_STICKY_BITS_SIZE;
+	}
+
+	return ret;
+}
+
+static int tegra_se_aeskeytable_context_save(tegra_se_dev_t *se_dev)
+{
+	uint32_t val = 0;
+	int ret = 0;
+
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	if (!se_dev->ctx_save_buf) {
+		ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__);
+		ret = -EINVAL;
+		goto aes_keytable_save_err;
+	}
+
+	/* AES key context save */
+	for (int slot = 0; slot < TEGRA_SE_AES_KEYSLOT_COUNT; slot++) {
+		se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
+						((tegra_se_context_t *)se_dev->
+						 ctx_save_buf)->key_slots[slot].key)));
+		se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE;
+		for (int i = 0; i < 2; i++) {
+			val = SE_CTX_SAVE_SRC_AES_KEYTABLE |
+				SE_CTX_SAVE_KEY_INDEX(slot) |
+				SE_CTX_SAVE_WORD_QUAD(i);
+			tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
+
+			/* SE context save operation */
+			ret = tegra_se_start_ctx_save_operation(se_dev,
+					TEGRA_SE_KEY_128_SIZE);
+			if (ret) {
+				ERROR("%s: ERR: AES key CTX_SAVE OP failed, "
+						"slot=%d, word_quad=%d.\n",
+						__func__, slot, i);
+				goto aes_keytable_save_err;
+			}
+			se_dev->dst_ll_buf->buffer[0].addr += TEGRA_SE_KEY_128_SIZE;
+		}
+
+		/* OIV context save */
+		se_dev->dst_ll_buf->last_buff_num = 0;
+		se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
+						((tegra_se_context_t *)se_dev->
+						 ctx_save_buf)->key_slots[slot].oiv)));
+		se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_IV_SIZE;
+
+		val = SE_CTX_SAVE_SRC_AES_KEYTABLE |
+			SE_CTX_SAVE_KEY_INDEX(slot) |
+			SE_CTX_SAVE_WORD_QUAD_ORIG_IV;
+		tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
+
+		/* SE context save operation */
+		ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_AES_IV_SIZE);
+		if (ret) {
+			ERROR("%s: ERR: OIV CTX_SAVE OP failed, slot=%d.\n",
+					__func__, slot);
+			goto aes_keytable_save_err;
+		}
+
+		/* UIV context save */
+		se_dev->dst_ll_buf->last_buff_num = 0;
+		se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
+						((tegra_se_context_t *)se_dev->
+						 ctx_save_buf)->key_slots[slot].uiv)));
+		se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_IV_SIZE;
+
+		val = SE_CTX_SAVE_SRC_AES_KEYTABLE |
+			SE_CTX_SAVE_KEY_INDEX(slot) |
+			SE_CTX_SAVE_WORD_QUAD_UPD_IV;
+		tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
+
+		/* SE context save operation */
+		ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_AES_IV_SIZE);
+		if (ret) {
+			ERROR("%s: ERR: UIV CTX_SAVE OP failed, slot=%d\n",
+					__func__, slot);
+			goto aes_keytable_save_err;
+		}
+	}
+
+aes_keytable_save_err:
+	return ret;
+}
+
+static int tegra_se_lp_rsakeytable_context_save(tegra_se_dev_t *se_dev)
+{
+	uint32_t val = 0;
+	int ret = 0;
+	/* First the modulus and then the exponent must be
+	 * encrypted and saved. This is repeated for SLOT 0
+	 * and SLOT 1. Hence the order:
+	 * SLOT 0 exponent : RSA_KEY_INDEX : 0
+	 * SLOT 0 modulus : RSA_KEY_INDEX : 1
+	 * SLOT 1 exponent : RSA_KEY_INDEX : 2
+	 * SLOT 1 modulus : RSA_KEY_INDEX : 3
+	 */
+	const unsigned int key_index_mod[TEGRA_SE_RSA_KEYSLOT_COUNT][2] = {
+		/* RSA key slot 0 */
+		{SE_RSA_KEY_INDEX_SLOT0_EXP, SE_RSA_KEY_INDEX_SLOT0_MOD},
+		/* RSA key slot 1 */
+		{SE_RSA_KEY_INDEX_SLOT1_EXP, SE_RSA_KEY_INDEX_SLOT1_MOD},
+	};
+
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
+					((tegra_se_context_t *)se_dev->
+					 ctx_save_buf)->rsa_keys)));
+	se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE;
+
+	for (int slot = 0; slot < TEGRA_SE_RSA_KEYSLOT_COUNT; slot++) {
+		/* loop for modulus and exponent */
+		for (int index = 0; index < 2; index++) {
+			for (int word_quad = 0; word_quad < 16; word_quad++) {
+				val = SE_CTX_SAVE_SRC_RSA_KEYTABLE |
+					SE_CTX_SAVE_RSA_KEY_INDEX(
+						key_index_mod[slot][index]) |
+					SE_CTX_RSA_WORD_QUAD(word_quad);
+				tegra_se_write_32(se_dev,
+					SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
+
+				/* SE context save operation */
+				ret = tegra_se_start_ctx_save_operation(se_dev,
+						TEGRA_SE_KEY_128_SIZE);
+				if (ret) {
+					ERROR("%s: ERR: slot=%d.\n",
+						__func__, slot);
+					goto rsa_keytable_save_err;
+				}
+
+				/* Update the pointer to the next word quad */
+				se_dev->dst_ll_buf->buffer[0].addr +=
+					TEGRA_SE_KEY_128_SIZE;
+			}
+		}
+	}
+
+rsa_keytable_save_err:
+	return ret;
+}
+
+static int tegra_se_pkakeytable_sticky_bits_save(tegra_se_dev_t *se_dev)
+{
+	int ret = 0;
+
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
+					((tegra_se2_context_blob_t *)se_dev->
+					 ctx_save_buf)->pka_ctx.sticky_bits)));
+	se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_BLOCK_SIZE;
+
+	/* PKA1 sticky bits are 1 AES block (16 bytes) */
+	tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET,
+			SE_CTX_SAVE_SRC_PKA1_STICKY_BITS |
+			SE_CTX_STICKY_WORD_QUAD_WORDS_0_3);
+
+	/* SE context save operation */
+	ret = tegra_se_start_ctx_save_operation(se_dev, 0);
+	if (ret) {
+		ERROR("%s: ERR: PKA1 sticky bits CTX_SAVE OP failed\n",
+				__func__);
+		goto pka_sticky_bits_save_err;
+	}
+
+pka_sticky_bits_save_err:
+	return ret;
+}
+
+static int tegra_se_pkakeytable_context_save(tegra_se_dev_t *se_dev)
+{
+	uint32_t val = 0;
+	int ret = 0;
+
+	se_dev->dst_ll_buf->last_buff_num = 0;
+	se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(
+					((tegra_se2_context_blob_t *)se_dev->
+					 ctx_save_buf)->pka_ctx.pka_keys)));
+	se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE;
+
+	/* for each slot, save word quad 0-127 */
+	for (int slot = 0; slot < TEGRA_SE_PKA1_KEYSLOT_COUNT; slot++) {
+		for (int word_quad = 0; word_quad < 512/4; word_quad++) {
+			val = SE_CTX_SAVE_SRC_PKA1_KEYTABLE |
+				SE_CTX_PKA1_WORD_QUAD_L((slot * 128) +
+						word_quad) |
+				SE_CTX_PKA1_WORD_QUAD_H((slot * 128) +
+						word_quad);
+			tegra_se_write_32(se_dev,
+					SE_CTX_SAVE_CONFIG_REG_OFFSET, val);
+
+			/* SE context save operation */
+			ret = tegra_se_start_ctx_save_operation(se_dev,
+					TEGRA_SE_KEY_128_SIZE);
+			if (ret) {
+				ERROR("%s: ERR: pka1 keytable ctx save error\n",
+						__func__);
+				goto pka_keytable_save_err;
+			}
+
+			/* Update the pointer to the next word quad */
+			se_dev->dst_ll_buf->buffer[0].addr +=
+				TEGRA_SE_KEY_128_SIZE;
+		}
+	}
+
+pka_keytable_save_err:
+	return ret;
+}
+
+static int tegra_se_save_SRK(tegra_se_dev_t *se_dev)
+{
+	tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET,
+			SE_CTX_SAVE_SRC_SRK);
+
+	/* SE context save operation */
+	return tegra_se_start_ctx_save_operation(se_dev, 0);
+}
+
+/*
+ *  Lock both SE from non-TZ clients.
+ */
+static inline void tegra_se_lock(tegra_se_dev_t *se_dev)
+{
+	uint32_t val;
+
+	assert(se_dev);
+	val = tegra_se_read_32(se_dev, SE_SECURITY_REG_OFFSET);
+	val |= SE_SECURITY_TZ_LOCK_SOFT(SE_SECURE);
+	tegra_se_write_32(se_dev, SE_SECURITY_REG_OFFSET, val);
+}
+
+/*
+ * Use SRK to encrypt SE state and save to TZRAM carveout
+ */
+static int tegra_se_context_save_sw(tegra_se_dev_t *se_dev)
+{
+	int err = 0;
+
+	assert(se_dev);
+
+	/* Lock entire SE/SE2 as TZ protected */
+	tegra_se_lock(se_dev);
+
+	INFO("%s: generate SRK\n", __func__);
+	/* Generate SRK */
+	err = tegra_se_generate_srk(se_dev);
+	if (err) {
+		ERROR("%s: ERR: SRK generation failed\n", __func__);
+		return err;
+	}
+
+	INFO("%s: generate random data\n", __func__);
+	/* Generate random data */
+	err = tegra_se_lp_generate_random_data(se_dev);
+	if (err) {
+		ERROR("%s: ERR: LP random pattern generation failed\n", __func__);
+		return err;
+	}
+
+	INFO("%s: encrypt random data\n", __func__);
+	/* Encrypt the random data block */
+	err = tegra_se_lp_data_context_save(se_dev,
+		((uint64_t)(&(((tegra_se_context_t *)se_dev->
+					ctx_save_buf)->rand_data))),
+		((uint64_t)(&(((tegra_se_context_t *)se_dev->
+					ctx_save_buf)->rand_data))),
+		SE_CTX_SAVE_RANDOM_DATA_SIZE);
+	if (err) {
+		ERROR("%s: ERR: random pattern encryption failed\n", __func__);
+		return err;
+	}
+
+	INFO("%s: save SE sticky bits\n", __func__);
+	/* Save AES sticky bits context */
+	err = tegra_se_lp_sticky_bits_context_save(se_dev);
+	if (err) {
+		ERROR("%s: ERR: sticky bits context save failed\n", __func__);
+		return err;
+	}
+
+	INFO("%s: save AES keytables\n", __func__);
+	/* Save AES key table context */
+	err = tegra_se_aeskeytable_context_save(se_dev);
+	if (err) {
+		ERROR("%s: ERR: LP keytable save failed\n", __func__);
+		return err;
+	}
+
+	/* RSA key slot table context save */
+	INFO("%s: save RSA keytables\n", __func__);
+	err = tegra_se_lp_rsakeytable_context_save(se_dev);
+	if (err) {
+		ERROR("%s: ERR: rsa key table context save failed\n", __func__);
+		return err;
+	}
+
+	/* Only SE2 has an interface with PKA1; thus, PKA1's context is saved
+	 * via SE2.
+	 */
+	if (se_dev->se_num == 2) {
+		/* Encrypt PKA1 sticky bits on SE2 only */
+		INFO("%s: save PKA sticky bits\n", __func__);
+		err = tegra_se_pkakeytable_sticky_bits_save(se_dev);
+		if (err) {
+			ERROR("%s: ERR: PKA sticky bits context save failed\n", __func__);
+			return err;
+		}
+
+		/* Encrypt PKA1 keyslots on SE2 only */
+		INFO("%s: save PKA keytables\n", __func__);
+		err = tegra_se_pkakeytable_context_save(se_dev);
+		if (err) {
+			ERROR("%s: ERR: PKA key table context save failed\n", __func__);
+			return err;
+		}
+	}
+
+	/* Encrypt known pattern */
+	if (se_dev->se_num == 1) {
+		err = tegra_se_lp_data_context_save(se_dev,
+			((uint64_t)(&se_ctx_known_pattern_data)),
+			((uint64_t)(&(((tegra_se_context_blob_t *)se_dev->ctx_save_buf)->known_pattern))),
+			SE_CTX_KNOWN_PATTERN_SIZE);
+	} else if (se_dev->se_num == 2) {
+		err = tegra_se_lp_data_context_save(se_dev,
+			((uint64_t)(&se_ctx_known_pattern_data)),
+			((uint64_t)(&(((tegra_se2_context_blob_t *)se_dev->ctx_save_buf)->known_pattern))),
+			SE_CTX_KNOWN_PATTERN_SIZE);
+	}
+	if (err) {
+		ERROR("%s: ERR: save LP known pattern failure\n", __func__);
+		return err;
+	}
+
+	/* Write lp context buffer address into PMC scratch register */
+	if (se_dev->se_num == 1) {
+		/* SE context address */
+		mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SECURE_SCRATCH117_OFFSET,
+				((uint64_t)(se_dev->ctx_save_buf)));
+	} else if (se_dev->se_num == 2) {
+		/* SE2 & PKA1 context address */
+		mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SECURE_SCRATCH116_OFFSET,
+				((uint64_t)(se_dev->ctx_save_buf)));
+	}
+
+	/* Saves SRK to PMC secure scratch registers for BootROM, which
+	 * verifies and restores the security engine context on warm boot.
+	 */
+	err = tegra_se_save_SRK(se_dev);
+	if (err < 0) {
+		ERROR("%s: ERR: LP SRK save failure\n", __func__);
+		return err;
+	}
+
+	INFO("%s: SE context save done \n", __func__);
+
+	return err;
+}
+
+/*
+ * Initialize the SE engine handle
+ */
+void tegra_se_init(void)
+{
+	uint32_t val = 0;
+	INFO("%s: start SE init\n", __func__);
+
+	/* Generate random SRK to initialize DRBG */
+	tegra_se_generate_srk(&se_dev_1);
+	tegra_se_generate_srk(&se_dev_2);
+
+	/* determine if ECID is valid */
+	val = mmio_read_32(TEGRA_FUSE_BASE + FUSE_JTAG_SECUREID_VALID);
+	ecid_valid = (val == ECID_VALID);
+
+	INFO("%s: SE init done\n", __func__);
+}
+
+static void tegra_se_enable_clocks(void)
+{
+	uint32_t val = 0;
+
+	/* Enable entropy clock */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W);
+	val |= ENTROPY_CLK_ENB_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val);
+
+	/* De-Assert Entropy Reset */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W);
+	val &= ~ENTROPY_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W, val);
+
+	/* Enable SE clock */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V);
+	val |= SE_CLK_ENB_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val);
+
+	/* De-Assert SE Reset */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V);
+	val &= ~SE_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V, val);
+}
+
+static void tegra_se_disable_clocks(void)
+{
+	uint32_t val = 0;
+
+	/* Disable entropy clock */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W);
+	val &= ~ENTROPY_CLK_ENB_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val);
+
+	/* Disable SE clock */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V);
+	val &= ~SE_CLK_ENB_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val);
+}
+
+/*
+ * Security engine power suspend entry point.
+ * This function is invoked from PSCI power domain suspend handler.
+ */
+int32_t tegra_se_suspend(void)
+{
+	int32_t ret = 0;
+	uint32_t val = 0;
+
+	/* SE does not use SMMU in EL3, disable SMMU.
+	 * This will be re-enabled by kernel on resume */
+	val = mmio_read_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0);
+	val &= ~PPCS_SMMU_ENABLE;
+	mmio_write_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0, val);
+
+	tegra_se_enable_clocks();
+
+	if (tegra_se_atomic_save_enabled(&se_dev_2) &&
+			tegra_se_atomic_save_enabled(&se_dev_1)) {
+		/* Atomic context save se2 and pka1 */
+		INFO("%s: SE2/PKA1 atomic context save\n", __func__);
+		if (ret == 0) {
+			ret = tegra_se_context_save_atomic(&se_dev_2);
+		}
+
+		/* Atomic context save se */
+		if (ret == 0) {
+			INFO("%s: SE1 atomic context save\n", __func__);
+			ret = tegra_se_context_save_atomic(&se_dev_1);
+		}
+
+		if (ret == 0) {
+			INFO("%s: SE atomic context save done\n", __func__);
+		}
+	} else if (!tegra_se_atomic_save_enabled(&se_dev_2) &&
+			!tegra_se_atomic_save_enabled(&se_dev_1)) {
+		/* SW context save se2 and pka1 */
+		INFO("%s: SE2/PKA1 legacy(SW) context save\n", __func__);
+		if (ret == 0) {
+			ret = tegra_se_context_save_sw(&se_dev_2);
+		}
+
+		/* SW context save se */
+		if (ret == 0) {
+			INFO("%s: SE1 legacy(SW) context save\n", __func__);
+			ret = tegra_se_context_save_sw(&se_dev_1);
+		}
+
+		if (ret == 0) {
+			INFO("%s: SE SW context save done\n", __func__);
+		}
+	} else {
+		ERROR("%s: One SE set for atomic CTX save, the other is not\n",
+			 __func__);
+	}
+
+	tegra_se_disable_clocks();
+
+	return ret;
+}
+
+/*
+ * Save TZRAM to shadow TZRAM in AON
+ */
+int32_t tegra_se_save_tzram(void)
+{
+	uint32_t val = 0;
+	int32_t ret = 0;
+	uint32_t timeout;
+
+	INFO("%s: SE TZRAM save start\n", __func__);
+	tegra_se_enable_clocks();
+
+	val = (SE_TZRAM_OP_REQ_INIT | SE_TZRAM_OP_MODE_SAVE);
+	tegra_se_write_32(&se_dev_1, SE_TZRAM_OPERATION, val);
+
+	val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION);
+	for (timeout = 0; (SE_TZRAM_OP_BUSY(val) == SE_TZRAM_OP_BUSY_ON) &&
+			(timeout < TIMEOUT_100MS); timeout++) {
+		mdelay(1);
+		val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION);
+	}
+
+	if (timeout == TIMEOUT_100MS) {
+		ERROR("%s: ERR: TZRAM save timeout!\n", __func__);
+		ret = -ETIMEDOUT;
+	}
+
+	if (ret == 0) {
+		INFO("%s: SE TZRAM save done!\n", __func__);
+	}
+
+	tegra_se_disable_clocks();
+
+	return ret;
+}
+
+/*
+ * The function is invoked by SE resume
+ */
+static void tegra_se_warm_boot_resume(const tegra_se_dev_t *se_dev)
+{
+	uint32_t val;
+
+	assert(se_dev);
+
+	/* Lock RNG source to ENTROPY on resume */
+	val = DRBG_RO_ENT_IGNORE_MEM_ENABLE |
+		DRBG_RO_ENT_SRC_LOCK_ENABLE |
+		DRBG_RO_ENT_SRC_ENABLE;
+	tegra_se_write_32(se_dev, SE_RNG_SRC_CONFIG_REG_OFFSET, val);
+
+	/* Set a random value to SRK to initialize DRBG */
+	tegra_se_generate_srk(se_dev);
+}
+
+/*
+ * The function is invoked on SC7 resume
+ */
+void tegra_se_resume(void)
+{
+	tegra_se_warm_boot_resume(&se_dev_1);
+	tegra_se_warm_boot_resume(&se_dev_2);
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
new file mode 100644
index 0000000..12241c2
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cortex_a57.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <bpmp.h>
+#include <flowctrl.h>
+#include <lib/utils.h>
+#include <memctrl.h>
+#include <pmc.h>
+#include <platform_def.h>
+#include <security_engine.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+#include <tegra_platform.h>
+
+/*
+ * Register used to clear CPU reset signals. Each CPU has two reset
+ * signals: CPU reset (3:0) and Core reset (19:16).
+ */
+#define CPU_CMPLX_RESET_CLR		0x454
+#define CPU_CORE_RESET_MASK		0x10001
+
+/* Clock and Reset controller registers for system clock's settings */
+#define SCLK_RATE			0x30
+#define SCLK_BURST_POLICY		0x28
+#define SCLK_BURST_POLICY_DEFAULT	0x10000000
+
+static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
+static bool tegra_bpmp_available = true;
+
+int32_t tegra_soc_validate_power_state(unsigned int power_state,
+					psci_power_state_t *req_state)
+{
+	int state_id = psci_get_pstate_id(power_state);
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+
+	/* Sanity check the requested state id */
+	switch (state_id) {
+	case PSTATE_ID_CORE_POWERDN:
+		/*
+		 * Core powerdown request only for afflvl 0
+		 */
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
+
+		break;
+
+	case PSTATE_ID_CLUSTER_IDLE:
+
+		/*
+		 * Cluster idle request for afflvl 0
+		 */
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PSTATE_ID_CORE_POWERDN;
+		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
+		break;
+
+	case PSTATE_ID_SOC_POWERDN:
+
+		/*
+		 * sc7entry-fw must be present in the system when the bpmp
+		 * firmware is not present, for a successful System Suspend
+		 * entry.
+		 */
+		if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base)
+			return PSCI_E_NOT_SUPPORTED;
+
+		/*
+		 * System powerdown request only for afflvl 2
+		 */
+		for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+
+		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
+			PLAT_SYS_SUSPEND_STATE_ID;
+
+		break;
+
+	default:
+		ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler to calculate the proper target power level at the
+ * specified affinity level.
+ ******************************************************************************/
+plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
+	int cpu = plat_my_core_pos();
+	int core_pos = read_mpidr() & MPIDR_CPU_MASK;
+	uint32_t bpmp_reply, data[3], val;
+	int ret;
+
+	/* get the power state at this level */
+	if (lvl == MPIDR_AFFLVL1)
+		target = *(states + core_pos);
+	if (lvl == MPIDR_AFFLVL2)
+		target = *(states + cpu);
+
+	if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) {
+
+		/* initialize the bpmp interface */
+		ret = tegra_bpmp_init();
+		if (ret != 0U) {
+
+			/*
+			 * flag to indicate that BPMP firmware is not
+			 * available and the CPU has to handle entry/exit
+			 * for all power states
+			 */
+			tegra_bpmp_available = false;
+
+			/* Cluster idle not allowed */
+			target = PSCI_LOCAL_STATE_RUN;
+
+			/*******************************************
+			 * BPMP is not present, so handle CC6 entry
+			 * from the CPU
+			 ******************************************/
+
+			/* check if cluster idle state has been enabled */
+			val = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL);
+			if (val == ENABLE_CLOSED_LOOP) {
+				/*
+				 * Acquire the cluster idle lock to stop
+				 * other CPUs from powering up.
+				 */
+				tegra_fc_ccplex_pgexit_lock();
+
+				/* Cluster idle only from the last standing CPU */
+				if (tegra_pmc_is_last_on_cpu() && tegra_fc_is_ccx_allowed()) {
+					/* Cluster idle allowed */
+					target = PSTATE_ID_CLUSTER_IDLE;
+				} else {
+					/* release cluster idle lock */
+					tegra_fc_ccplex_pgexit_unlock();
+				}
+			}
+		} else {
+
+			/* Cluster power-down */
+			data[0] = (uint32_t)cpu;
+			data[1] = TEGRA_PM_CC6;
+			data[2] = TEGRA_PM_SC1;
+			ret = tegra_bpmp_send_receive_atomic(MRQ_DO_IDLE,
+					(void *)&data, (int)sizeof(data),
+					(void *)&bpmp_reply,
+					(int)sizeof(bpmp_reply));
+
+			/* check if cluster power down is allowed */
+			if ((ret != 0L) || (bpmp_reply != BPMP_CCx_ALLOWED)) {
+
+				/* Cluster power down not allowed */
+				target = PSCI_LOCAL_STATE_RUN;
+			}
+		}
+
+	} else if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
+	    (target == PSTATE_ID_SOC_POWERDN)) {
+
+		/* System Suspend */
+		target = PSTATE_ID_SOC_POWERDN;
+
+	} else {
+		; /* do nothing */
+	}
+
+	return target;
+}
+
+int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr();
+	const plat_local_state_t *pwr_domain_state =
+		target_state->pwr_domain_state;
+	unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
+	unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
+	unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
+	uint32_t cfg;
+	int ret = PSCI_E_SUCCESS;
+	uint32_t val;
+
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
+		assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
+			(stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
+		assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
+			(stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
+
+		if (tegra_chipid_is_t210_b01()) {
+
+			/* Suspend se/se2 and pka1 */
+			if (tegra_se_suspend() != 0) {
+				ret = PSCI_E_INTERN_FAIL;
+			}
+		}
+
+	} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
+
+		assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN);
+
+		if (!tegra_bpmp_available) {
+
+			/*
+			 * When disabled, DFLL loses its state. Enable
+			 * open loop state for the DFLL as we dont want
+			 * garbage values being written to the pmic
+			 * when we enter cluster idle state.
+			 */
+			mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
+				      ENABLE_OPEN_LOOP);
+
+			/* Find if the platform uses OVR2/MAX77621 PMIC */
+			cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
+			if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
+				/* OVR2 */
+
+				/* PWM tristate */
+				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
+				val |= PINMUX_PWM_TRISTATE;
+				mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
+
+				/*
+				 * SCRATCH201[1] is being used to identify CPU
+				 * PMIC in warmboot code.
+				 * 0 : OVR2
+				 * 1 : MAX77621
+				 */
+				tegra_pmc_write_32(PMC_SCRATCH201, 0x0);
+			} else {
+				/* MAX77621 */
+				tegra_pmc_write_32(PMC_SCRATCH201, 0x2);
+			}
+		}
+
+		/* Prepare for cluster idle */
+		tegra_fc_cluster_idle(mpidr);
+
+	} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
+
+		/* Prepare for cpu powerdn */
+		tegra_fc_cpu_powerdn(mpidr);
+
+	} else {
+		ERROR("%s: Unknown state id (%d, %d, %d)\n", __func__,
+			stateid_afflvl2, stateid_afflvl1, stateid_afflvl0);
+		ret = PSCI_E_NOT_SUPPORTED;
+	}
+
+	return ret;
+}
+
+static void tegra_reset_all_dma_masters(void)
+{
+	uint32_t val, mask;
+
+	/*
+	 * Reset all possible DMA masters in the system.
+	 */
+	val = GPU_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val);
+
+	val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
+	      NVJPG_RESET_BIT | NVDEC_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val);
+
+	val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
+	      VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
+	      SDMMC2_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val);
+
+	val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val);
+
+	val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
+	      PCIE_RESET_BIT | SDMMC3_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val);
+
+	val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
+	mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val);
+
+	/*
+	 * If any of the DMA masters are still alive, assume
+	 * that the system has been compromised and reboot.
+	 */
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
+	mask = GPU_RESET_BIT;
+	if ((val & mask) != mask)
+		tegra_pmc_system_reset();
+
+	mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
+	      NVJPG_RESET_BIT | NVDEC_RESET_BIT;
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y);
+	if ((val & mask) != mask)
+		tegra_pmc_system_reset();
+
+	mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
+	       VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
+	       SDMMC2_RESET_BIT;
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L);
+	if ((val & mask) != mask)
+		tegra_pmc_system_reset();
+
+	mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H);
+	if ((val & mask) != mask)
+		tegra_pmc_system_reset();
+
+	mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
+	       PCIE_RESET_BIT | SDMMC3_RESET_BIT;
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U);
+	if ((val & mask) != mask)
+		tegra_pmc_system_reset();
+
+	val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V);
+	mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
+	if ((val & mask) != mask)
+		tegra_pmc_system_reset();
+}
+
+int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr();
+	const plat_local_state_t *pwr_domain_state =
+		target_state->pwr_domain_state;
+	unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL];
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+	uint32_t val;
+
+	if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
+
+		if (tegra_chipid_is_t210_b01()) {
+			/* Save tzram contents */
+			tegra_se_save_tzram();
+		}
+
+		/* de-init the interface */
+		tegra_bpmp_suspend();
+
+		/*
+		 * The CPU needs to load the System suspend entry firmware
+		 * if nothing is running on the BPMP.
+		 */
+		if (!tegra_bpmp_available) {
+
+			/*
+			 * BPMP firmware is not running on the co-processor, so
+			 * we need to explicitly load the firmware to enable
+			 * entry/exit to/from System Suspend and set the BPMP
+			 * on its way.
+			 */
+
+			/* Power off BPMP before we proceed */
+			tegra_fc_bpmp_off();
+
+			/* bond out IRAM banks B, C and D */
+			mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U,
+				IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT |
+				IRAM_D_LOCK_BIT);
+
+			/* bond out APB/AHB DMAs */
+			mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H,
+				APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT);
+
+			/* Power off BPMP before we proceed */
+			tegra_fc_bpmp_off();
+
+			/*
+			 * Reset all the hardware blocks that can act as DMA
+			 * masters on the bus.
+			 */
+			tegra_reset_all_dma_masters();
+
+			/* clean up IRAM of any cruft */
+			zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE,
+					TEGRA_IRAM_A_SIZE);
+
+			/* Copy the firmware to BPMP's internal RAM */
+			(void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
+				(const void *)(plat_params->sc7entry_fw_base + SC7ENTRY_FW_HEADER_SIZE_BYTES),
+				plat_params->sc7entry_fw_size - SC7ENTRY_FW_HEADER_SIZE_BYTES);
+
+			/* Power on the BPMP and execute from IRAM base */
+			tegra_fc_bpmp_on(TEGRA_IRAM_BASE);
+
+			/* Wait until BPMP powers up */
+			do {
+				val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
+			} while (val != SIGN_OF_LIFE);
+		}
+
+		/* enter system suspend */
+		tegra_fc_soc_powerdn(mpidr);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+	uint32_t cfg;
+	uint32_t val, entrypoint = 0;
+	uint64_t offset;
+
+	/* platform parameter passed by the previous bootloader */
+	if (plat_params->l2_ecc_parity_prot_dis != 1) {
+		/* Enable ECC Parity Protection for Cortex-A57 CPUs */
+		val = read_l2ctlr_el1();
+		val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
+		write_l2ctlr_el1(val);
+	}
+
+	/*
+	 * Check if we are exiting from SOC_POWERDN.
+	 */
+	if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
+			PLAT_SYS_SUSPEND_STATE_ID) {
+
+		/*
+		 * Security engine resume
+		 */
+		if (tegra_chipid_is_t210_b01()) {
+			tegra_se_resume();
+		}
+
+		/*
+		 * Lock scratch registers which hold the CPU vectors
+		 */
+		tegra_pmc_lock_cpu_vectors();
+
+		/*
+		 * Enable WRAP to INCR burst type conversions for
+		 * incoming requests on the AXI slave ports.
+		 */
+		val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
+		val &= ~ENABLE_UNSUP_TX_ERRORS;
+		val |= ENABLE_WRAP_TO_INCR_BURSTS;
+		mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
+
+		/*
+		 * Restore Boot and Power Management Processor (BPMP) reset
+		 * address and reset it, if it is supported by the platform.
+		 */
+		if (!tegra_bpmp_available) {
+			tegra_fc_bpmp_off();
+		} else {
+			entrypoint = tegra_pmc_read_32(PMC_SCRATCH39);
+			tegra_fc_bpmp_on(entrypoint);
+
+			/* initialise the interface */
+			tegra_bpmp_resume();
+		}
+
+		/* sc7entry-fw is part of TZDRAM area */
+		if (plat_params->sc7entry_fw_base != 0U) {
+			offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
+			tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
+				plat_params->tzdram_size + offset);
+
+			/* restrict PMC access to secure world */
+			val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
+			val |= PMC_SECURITY_EN_BIT;
+			mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
+		}
+	}
+
+	/*
+	 * Check if we are exiting cluster idle state
+	 */
+	if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
+			PSTATE_ID_CLUSTER_IDLE) {
+
+		if (!tegra_bpmp_available) {
+
+			/* PWM un-tristate */
+			cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
+			if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
+				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
+				val &= ~PINMUX_PWM_TRISTATE;
+				mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
+
+				/* make sure the setting took effect */
+				val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
+				assert((val & PINMUX_PWM_TRISTATE) == 0U);
+			}
+
+			/*
+			 * Restore operation mode for the DFLL ring
+			 * oscillator
+			 */
+			mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
+				      ENABLE_CLOSED_LOOP);
+
+			/* release cluster idle lock */
+			tegra_fc_ccplex_pgexit_unlock();
+		}
+	}
+
+	/*
+	 * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
+	 * used for power management and boot purposes. Inform the BPMP that
+	 * we have completed the cluster power up.
+	 */
+	tegra_fc_lock_active_cluster();
+
+	/*
+         * Resume PMC hardware block for Tegra210 platforms supporting sc7entry-fw
+         */
+	if (!tegra_chipid_is_t210_b01() && (plat_params->sc7entry_fw_base != 0U))
+		tegra_pmc_resume();
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_on(u_register_t mpidr)
+{
+	int cpu = mpidr & MPIDR_CPU_MASK;
+	uint32_t mask = CPU_CORE_RESET_MASK << cpu;
+
+	/* Deassert CPU reset signals */
+	mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
+
+	/* Turn on CPU using flow controller or PMC */
+	if (cpu_powergate_mask[cpu] == 0) {
+		tegra_pmc_cpu_on(cpu);
+		cpu_powergate_mask[cpu] = 1;
+	} else {
+		tegra_fc_cpu_on(cpu);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
+	return PSCI_E_SUCCESS;
+}
+
+int tegra_soc_prepare_system_reset(void)
+{
+	/*
+	 * Set System Clock (SCLK) to POR default so that the clock source
+	 * for the PMC APB clock would not be changed due to system reset.
+	 */
+	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
+		SCLK_BURST_POLICY_DEFAULT);
+	mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
+
+	/* Wait 1 ms to make sure clock source/device logic is stabilized. */
+	mdelay(1);
+
+	return PSCI_E_SUCCESS;
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_secondary.c b/plat/nvidia/tegra/soc/t210/plat_secondary.c
new file mode 100644
index 0000000..e0242cf
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_secondary.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <pmc.h>
+#include <tegra_def.h>
+
+#define SB_CSR				0x0
+#define  SB_CSR_NS_RST_VEC_WR_DIS	(1 << 1)
+
+/* CPU reset vector */
+#define SB_AA64_RESET_LOW		0x30	/* width = 31:0 */
+#define SB_AA64_RESET_HI		0x34	/* width = 11:0 */
+
+extern void tegra_secure_entrypoint(void);
+
+/*******************************************************************************
+ * Setup secondary CPU vectors
+ ******************************************************************************/
+void plat_secondary_setup(void)
+{
+	uint32_t val;
+	uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint;
+
+	INFO("Setting up secondary CPU boot\n");
+
+	/* setup secondary CPU vector */
+	mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_LOW,
+			(reset_addr & 0xFFFFFFFF) | 1);
+	val = reset_addr >> 32;
+	mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_HI, val & 0x7FF);
+
+	/* configure PMC */
+	tegra_pmc_cpu_setup(reset_addr);
+	tegra_pmc_lock_cpu_vectors();
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c
new file mode 100644
index 0000000..2a2d102
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_setup.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cortex_a57.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/console.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <bl31/interrupt_mgmt.h>
+
+#include <bpmp.h>
+#include <flowctrl.h>
+#include <memctrl.h>
+#include <plat/common/platform.h>
+#include <security_engine.h>
+#include <tegra_def.h>
+#include <tegra_platform.h>
+#include <tegra_private.h>
+
+/* sets of MMIO ranges setup */
+#define MMIO_RANGE_0_ADDR	0x50000000
+#define MMIO_RANGE_1_ADDR	0x60000000
+#define MMIO_RANGE_2_ADDR	0x70000000
+#define MMIO_RANGE_SIZE		0x200000
+
+/*
+ * Table of regions to map using the MMU.
+ */
+static const mmap_region_t tegra_mmap[] = {
+	MAP_REGION_FLAT(TEGRA_IRAM_BASE, 0x40000, /* 256KB */
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MMIO_RANGE_0_ADDR, MMIO_RANGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MMIO_RANGE_1_ADDR, MMIO_RANGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MMIO_RANGE_2_ADDR, MMIO_RANGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{0}
+};
+
+/*******************************************************************************
+ * Set up the pagetables as per the platform memory map & initialize the MMU
+ ******************************************************************************/
+const mmap_region_t *plat_get_mmio_map(void)
+{
+	/* Add the map region for security engine SE2 */
+	if (tegra_chipid_is_t210_b01()) {
+		mmap_add_region((uint64_t)TEGRA_SE2_BASE,
+				(uint64_t)TEGRA_SE2_BASE,
+				(uint64_t)TEGRA_SE2_RANGE_SIZE,
+				MT_DEVICE | MT_RW | MT_SECURE);
+	}
+
+	/* MMIO space */
+	return tegra_mmap;
+}
+
+/*******************************************************************************
+ * The Tegra power domain tree has a single system level power domain i.e. a
+ * single root node. The first entry in the power domain descriptor specifies
+ * the number of power domains at the highest power level.
+ *******************************************************************************
+ */
+const unsigned char tegra_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	1,
+	/* No of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of CPU cores - cluster0 */
+	PLATFORM_MAX_CPUS_PER_CLUSTER,
+	/* No of CPU cores - cluster1 */
+	PLATFORM_MAX_CPUS_PER_CLUSTER
+};
+
+/*******************************************************************************
+ * This function returns the Tegra default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return tegra_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * Handler to get the System Counter Frequency
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 19200000;
+}
+
+/*******************************************************************************
+ * Maximum supported UART controllers
+ ******************************************************************************/
+#define TEGRA210_MAX_UART_PORTS		5
+
+/*******************************************************************************
+ * This variable holds the UART port base addresses
+ ******************************************************************************/
+static uint32_t tegra210_uart_addresses[TEGRA210_MAX_UART_PORTS + 1] = {
+	0,	/* undefined - treated as an error case */
+	TEGRA_UARTA_BASE,
+	TEGRA_UARTB_BASE,
+	TEGRA_UARTC_BASE,
+	TEGRA_UARTD_BASE,
+	TEGRA_UARTE_BASE,
+};
+
+/*******************************************************************************
+ * Retrieve the UART controller base to be used as the console
+ ******************************************************************************/
+uint32_t plat_get_console_from_id(int id)
+{
+	if (id > TEGRA210_MAX_UART_PORTS)
+		return 0;
+
+	return tegra210_uart_addresses[id];
+}
+
+/*******************************************************************************
+ * Handler for early platform setup
+ ******************************************************************************/
+void plat_early_platform_setup(void)
+{
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+	uint64_t val;
+
+	/* platform parameter passed by the previous bootloader */
+	if (plat_params->l2_ecc_parity_prot_dis != 1) {
+		/* Enable ECC Parity Protection for Cortex-A57 CPUs */
+		val = read_l2ctlr_el1();
+		val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
+		write_l2ctlr_el1(val);
+	}
+
+	/* Initialize security engine driver */
+	if (tegra_chipid_is_t210_b01()) {
+		tegra_se_init();
+	}
+}
+
+/* Secure IRQs for Tegra186 */
+static const interrupt_prop_t tegra210_interrupt_props[] = {
+	INTR_PROP_DESC(TEGRA210_WDT_CPU_LEGACY_FIQ, GIC_HIGHEST_SEC_PRIORITY,
+			GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+};
+
+void plat_late_platform_setup(void)
+{
+	const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
+	uint64_t sc7entry_end, offset;
+	int ret;
+	uint32_t val;
+
+	/* memmap TZDRAM area containing the SC7 Entry Firmware */
+	if (plat_params->sc7entry_fw_base && plat_params->sc7entry_fw_size) {
+
+		assert(plat_params->sc7entry_fw_size <= TEGRA_IRAM_A_SIZE);
+
+		/*
+		 * Verify that the SC7 entry firmware resides inside the TZDRAM
+		 * aperture, _before_ the BL31 code and the start address is
+		 * exactly 1MB from BL31 base.
+		 */
+
+		/* sc7entry-fw must be _before_ BL31 base */
+		assert(plat_params->tzdram_base > plat_params->sc7entry_fw_base);
+
+		sc7entry_end = plat_params->sc7entry_fw_base +
+			       plat_params->sc7entry_fw_size;
+		assert(sc7entry_end < plat_params->tzdram_base);
+
+		/* sc7entry-fw start must be exactly 1MB behind BL31 base */
+		offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
+		assert(offset == 0x100000);
+
+		/* secure TZDRAM area */
+		tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
+			plat_params->tzdram_size + offset);
+
+		/* power off BPMP processor until SC7 entry */
+		tegra_fc_bpmp_off();
+
+		/* memmap SC7 entry firmware code */
+		ret = mmap_add_dynamic_region(plat_params->sc7entry_fw_base,
+				plat_params->sc7entry_fw_base,
+				plat_params->sc7entry_fw_size,
+				MT_SECURE | MT_RO_DATA);
+		assert(ret == 0);
+
+		/* restrict PMC access to secure world */
+		val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
+		val |= PMC_SECURITY_EN_BIT;
+		mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
+	}
+}
+
+/*******************************************************************************
+ * Initialize the GIC and SGIs
+ ******************************************************************************/
+void plat_gic_setup(void)
+{
+	tegra_gic_setup(tegra210_interrupt_props, ARRAY_SIZE(tegra210_interrupt_props));
+	tegra_gic_init();
+
+	/* Enable handling for FIQs */
+	tegra_fiq_handler_setup();
+
+	/*
+	 * Enable routing watchdog FIQs from the flow controller to
+	 * the GICD.
+	 */
+	tegra_fc_enable_fiq_to_ccplex_routing();
+}
diff --git a/plat/nvidia/tegra/soc/t210/plat_sip_calls.c b/plat/nvidia/tegra/soc/t210/plat_sip_calls.c
new file mode 100644
index 0000000..7e0f5c1
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/plat_sip_calls.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include <memctrl.h>
+#include <pmc.h>
+#include <tegra_private.h>
+#include <tegra_platform.h>
+#include <tegra_def.h>
+
+/*******************************************************************************
+ * PMC parameters
+ ******************************************************************************/
+#define PMC_READ 			U(0xaa)
+#define PMC_WRITE 			U(0xbb)
+
+/*******************************************************************************
+ * Tegra210 SiP SMCs
+ ******************************************************************************/
+#define TEGRA_SIP_PMC_COMMANDS		U(0xC2FFFE00)
+
+/*******************************************************************************
+ * This function is responsible for handling all T210 SiP calls
+ ******************************************************************************/
+int plat_sip_handler(uint32_t smc_fid,
+		     uint64_t x1,
+		     uint64_t x2,
+		     uint64_t x3,
+		     uint64_t x4,
+		     const void *cookie,
+		     void *handle,
+		     uint64_t flags)
+{
+	uint32_t val, ns;
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+	if (!ns)
+		SMC_RET1(handle, SMC_UNK);
+
+	switch (smc_fid) {
+	case TEGRA_SIP_PMC_COMMANDS:
+
+		/* check the address is within PMC range and is 4byte aligned */
+		if ((x2 >= TEGRA_PMC_SIZE) || (x2 & 0x3))
+			return -EINVAL;
+
+		/* pmc_secure_scratch registers are not accessible */
+		if (((x2 >= PMC_SECURE_SCRATCH0) && (x2 <= PMC_SECURE_SCRATCH5)) ||
+		    ((x2 >= PMC_SECURE_SCRATCH6) && (x2 <= PMC_SECURE_SCRATCH7)) ||
+		    ((x2 >= PMC_SECURE_SCRATCH8) && (x2 <= PMC_SECURE_SCRATCH79)) ||
+		    ((x2 >= PMC_SECURE_SCRATCH80) && (x2 <= PMC_SECURE_SCRATCH119)))
+				return -EFAULT;
+
+		/* PMC secure-only registers are not accessible */
+		if ((x2 == PMC_DPD_ENABLE_0) || (x2 == PMC_FUSE_CONTROL_0) ||
+		    (x2 == PMC_CRYPTO_OP_0))
+			return -EFAULT;
+
+		/* Perform PMC read/write */
+		if (x1 == PMC_READ) {
+			val = mmio_read_32((uint32_t)(TEGRA_PMC_BASE + x2));
+			write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, val);
+		} else if (x1 == PMC_WRITE) {
+			mmio_write_32((uint32_t)(TEGRA_PMC_BASE + x2), (uint32_t)x3);
+		} else {
+			return -EINVAL;
+		}
+
+		break;
+
+	default:
+		ERROR("%s: unsupported function ID\n", __func__);
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
diff --git a/plat/nvidia/tegra/soc/t210/platform_t210.mk b/plat/nvidia/tegra/soc/t210/platform_t210.mk
new file mode 100644
index 0000000..a11aef4
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t210/platform_t210.mk
@@ -0,0 +1,57 @@
+#
+# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TZDRAM_BASE				:= 0xFF800000
+$(eval $(call add_define,TZDRAM_BASE))
+
+ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT	:= 1
+$(eval $(call add_define,ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT))
+
+PLATFORM_CLUSTER_COUNT			:= 2
+$(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
+
+PLATFORM_MAX_CPUS_PER_CLUSTER		:= 4
+$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
+
+MAX_XLAT_TABLES				:= 10
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS			:= 16
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
+ENABLE_WDT_LEGACY_FIQ_HANDLING		:= 1
+$(eval $(call add_define,ENABLE_WDT_LEGACY_FIQ_HANDLING))
+
+PLAT_INCLUDES		+=	-I${SOC_DIR}/drivers/se
+
+BL31_SOURCES		+=	drivers/ti/uart/aarch64/16550_console.S		\
+				lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a57.S			\
+				${COMMON_DIR}/drivers/bpmp/bpmp.c		\
+				${COMMON_DIR}/drivers/flowctrl/flowctrl.c	\
+				${COMMON_DIR}/drivers/memctrl/memctrl_v1.c	\
+				${SOC_DIR}/plat_psci_handlers.c			\
+				${SOC_DIR}/plat_setup.c				\
+				${SOC_DIR}/drivers/se/security_engine.c		\
+				${SOC_DIR}/plat_secondary.c		\
+				${SOC_DIR}/plat_sip_calls.c
+
+# Enable workarounds for selected Cortex-A57 erratas.
+A57_DISABLE_NON_TEMPORAL_HINT	:=	1
+ERRATA_A57_826974		:=	1
+ERRATA_A57_826977		:=	1
+ERRATA_A57_828024		:=	1
+ERRATA_A57_829520		:=	1
+ERRATA_A57_833471		:=	1
+
+# Enable workarounds for selected Cortex-A53 erratas.
+A53_DISABLE_NON_TEMPORAL_HINT	:=	1
+ERRATA_A53_826319		:=	1
+ERRATA_A53_836870		:=	1
+ERRATA_A53_855873		:=	1
+
+# Skip L1 $ flush when powering down Cortex-A57 CPUs
+SKIP_A57_L1_FLUSH_PWR_DWN	:=	1
diff --git a/plat/qemu/aarch32/plat_helpers.S b/plat/qemu/aarch32/plat_helpers.S
new file mode 100644
index 0000000..aebcfa7
--- /dev/null
+++ b/plat/qemu/aarch32/plat_helpers.S
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_my_core_pos
+	.globl	plat_get_my_entrypoint
+	.globl	platform_mem_init
+	.globl	plat_qemu_calc_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl  plat_secondary_cold_boot_setup
+	.globl  plat_get_my_entrypoint
+	.globl  plat_is_my_cpu_primary
+
+
+func plat_my_core_pos
+	ldcopr	r0, MPIDR
+	b	plat_qemu_calc_core_pos
+endfunc plat_my_core_pos
+
+/*
+ *  unsigned int plat_qemu_calc_core_pos(u_register_t mpidr);
+ *  With this function: CorePos = (ClusterId * 4) + CoreId
+ */
+func plat_qemu_calc_core_pos
+	and	r1, r0, #MPIDR_CPU_MASK
+	and	r0, r0, #MPIDR_CLUSTER_MASK
+	add	r0, r1, r0, LSR #6
+	bx	lr
+endfunc plat_qemu_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	ldcopr	r0, MPIDR
+	ldr	r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	and	r0, r1
+	cmp	r0, #QEMU_PRIMARY_CPU
+	moveq	r0, #1
+	movne	r0, #0
+	bx	lr
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Calculate address of our hold entry */
+	bl	plat_my_core_pos
+	lsl	r0, r0, #PLAT_QEMU_HOLD_ENTRY_SHIFT
+	mov_imm	r2, PLAT_QEMU_HOLD_BASE
+
+	/* Wait until we have a go */
+poll_mailbox:
+	ldr	r1, [r2, r0]
+        cmp     r1, #0
+        beq     1f
+	mov_imm	r0, PLAT_QEMU_TRUSTED_MAILBOX_BASE
+	ldr	r1, [r0]
+	bx	r1
+1:
+	wfe
+	b	poll_mailbox
+endfunc plat_secondary_cold_boot_setup
+
+func plat_get_my_entrypoint
+	/* TODO support warm boot */
+	mov	r0, #0
+	bx	lr
+endfunc plat_get_my_entrypoint
+
+func platform_mem_init
+	bx	lr
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	r0, PLAT_QEMU_CRASH_UART_BASE
+	mov_imm	r1, PLAT_QEMU_CRASH_UART_CLK_IN_HZ
+	mov_imm	r2, PLAT_QEMU_CONSOLE_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	r1, PLAT_QEMU_CRASH_UART_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush(int c)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	r0, PLAT_QEMU_CRASH_UART_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
+
diff --git a/plat/qemu/aarch64/plat_helpers.S b/plat/qemu/aarch64/plat_helpers.S
new file mode 100644
index 0000000..13a5ee4
--- /dev/null
+++ b/plat/qemu/aarch64/plat_helpers.S
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_my_core_pos
+	.globl	plat_get_my_entrypoint
+	.globl	platform_mem_init
+	.globl	plat_qemu_calc_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl  plat_secondary_cold_boot_setup
+	.globl  plat_get_my_entrypoint
+	.globl  plat_is_my_cpu_primary
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_qemu_calc_core_pos
+endfunc plat_my_core_pos
+
+/*
+ *  unsigned int plat_qemu_calc_core_pos(u_register_t mpidr);
+ *  With this function: CorePos = (ClusterId * 4) + CoreId
+ */
+func plat_qemu_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_qemu_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #QEMU_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Calculate address of our hold entry */
+	bl	plat_my_core_pos
+	lsl	x0, x0, #PLAT_QEMU_HOLD_ENTRY_SHIFT
+	mov_imm	x2, PLAT_QEMU_HOLD_BASE
+
+	/* Wait until we have a go */
+poll_mailbox:
+	ldr	x1, [x2, x0]
+	cbz	x1, 1f
+	mov_imm	x0, PLAT_QEMU_TRUSTED_MAILBOX_BASE
+	ldr	x1, [x0]
+	br	x1
+1:
+	wfe
+	b	poll_mailbox
+endfunc plat_secondary_cold_boot_setup
+
+func plat_get_my_entrypoint
+	/* TODO support warm boot */
+	mov	x0, #0
+	ret
+endfunc plat_get_my_entrypoint
+
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm x0, PLAT_QEMU_CRASH_UART_BASE
+	mov_imm x1, PLAT_QEMU_CRASH_UART_CLK_IN_HZ
+	mov_imm x2, PLAT_QEMU_CONSOLE_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, PLAT_QEMU_CRASH_UART_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush(int c)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, PLAT_QEMU_CRASH_UART_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
+
diff --git a/plat/qemu/dt.c b/plat/qemu/dt.c
new file mode 100644
index 0000000..b1cd368
--- /dev/null
+++ b/plat/qemu/dt.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/psci/psci.h>
+
+#include "qemu_private.h"
+
+static int append_psci_compatible(void *fdt, int offs, const char *str)
+{
+	return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1);
+}
+
+int dt_add_psci_node(void *fdt)
+{
+	int offs;
+
+	if (fdt_path_offset(fdt, "/psci") >= 0) {
+		WARN("PSCI Device Tree node already exists!\n");
+		return 0;
+	}
+
+	offs = fdt_path_offset(fdt, "/");
+	if (offs < 0)
+		return -1;
+	offs = fdt_add_subnode(fdt, offs, "psci");
+	if (offs < 0)
+		return -1;
+	if (append_psci_compatible(fdt, offs, "arm,psci-1.0"))
+		return -1;
+	if (append_psci_compatible(fdt, offs, "arm,psci-0.2"))
+		return -1;
+	if (append_psci_compatible(fdt, offs, "arm,psci"))
+		return -1;
+	if (fdt_setprop_string(fdt, offs, "method", "smc"))
+		return -1;
+	if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_AARCH64))
+		return -1;
+	if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
+		return -1;
+	if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_AARCH64))
+		return -1;
+	if (fdt_setprop_u32(fdt, offs, "sys_poweroff", PSCI_SYSTEM_OFF))
+		return -1;
+	if (fdt_setprop_u32(fdt, offs, "sys_reset", PSCI_SYSTEM_RESET))
+		return -1;
+	return 0;
+}
+
+static int check_node_compat_prefix(void *fdt, int offs, const char *prefix)
+{
+	const size_t prefix_len = strlen(prefix);
+	size_t l;
+	int plen;
+	const char *prop;
+
+	prop = fdt_getprop(fdt, offs, "compatible", &plen);
+	if (!prop)
+		return -1;
+
+	while (plen > 0) {
+		if (memcmp(prop, prefix, prefix_len) == 0)
+			return 0; /* match */
+
+		l = strlen(prop) + 1;
+		prop += l;
+		plen -= l;
+	}
+
+	return -1;
+}
+
+int dt_add_psci_cpu_enable_methods(void *fdt)
+{
+	int offs = 0;
+
+	while (1) {
+		offs = fdt_next_node(fdt, offs, NULL);
+		if (offs < 0)
+			break;
+		if (fdt_getprop(fdt, offs, "enable-method", NULL))
+			continue; /* already set */
+		if (check_node_compat_prefix(fdt, offs, "arm,cortex-a"))
+			continue; /* no compatible */
+		if (fdt_setprop_string(fdt, offs, "enable-method", "psci"))
+			return -1;
+		/* Need to restart scanning as offsets may have changed */
+		offs = 0;
+	}
+	return 0;
+}
diff --git a/plat/qemu/include/plat_macros.S b/plat/qemu/include/plat_macros.S
new file mode 100644
index 0000000..b6cdb07
--- /dev/null
+++ b/plat/qemu/include/plat_macros.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+#include <platform_def.h>
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm	x17, GICC_BASE
+	mov_imm	x16, GICD_BASE
+	arm_print_gic_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/qemu/include/platform_def.h b/plat/qemu/include/platform_def.h
new file mode 100644
index 0000000..d7f77cc
--- /dev/null
+++ b/plat/qemu/include/platform_def.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define QEMU_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define PLATFORM_STACK_SIZE 0x1000
+
+#if ARM_ARCH_MAJOR == 7
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+#else
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CLUSTER1_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#endif
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT + \
+					 PLATFORM_CLUSTER1_CORE_COUNT)
+
+#define QEMU_PRIMARY_CPU		0
+
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF		2
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		4
+#define PLAT_LOCAL_PSTATE_MASK		((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Partition memory into secure ROM, non-secure DRAM, secure "SRAM",
+ * and secure DRAM.
+ */
+#define SEC_ROM_BASE			0x00000000
+#define SEC_ROM_SIZE			0x00020000
+
+#define NS_DRAM0_BASE			0x40000000
+#define NS_DRAM0_SIZE			0x3de00000
+
+#define SEC_SRAM_BASE			0x0e000000
+#define SEC_SRAM_SIZE			0x00060000
+
+#define SEC_DRAM_BASE			0x0e100000
+#define SEC_DRAM_SIZE			0x00f00000
+
+/* Load pageable part of OP-TEE 2MB above secure DRAM base */
+#define QEMU_OPTEE_PAGEABLE_LOAD_BASE	(SEC_DRAM_BASE + 0x00200000)
+#define QEMU_OPTEE_PAGEABLE_LOAD_SIZE	0x00400000
+
+/*
+ * ARM-TF lives in SRAM, partition it here
+ */
+
+#define SHARED_RAM_BASE			SEC_SRAM_BASE
+#define SHARED_RAM_SIZE			0x00001000
+
+#define PLAT_QEMU_TRUSTED_MAILBOX_BASE	SHARED_RAM_BASE
+#define PLAT_QEMU_TRUSTED_MAILBOX_SIZE	(8 + PLAT_QEMU_HOLD_SIZE)
+#define PLAT_QEMU_HOLD_BASE		(PLAT_QEMU_TRUSTED_MAILBOX_BASE + 8)
+#define PLAT_QEMU_HOLD_SIZE		(PLATFORM_CORE_COUNT * \
+					 PLAT_QEMU_HOLD_ENTRY_SIZE)
+#define PLAT_QEMU_HOLD_ENTRY_SHIFT	3
+#define PLAT_QEMU_HOLD_ENTRY_SIZE	(1 << PLAT_QEMU_HOLD_ENTRY_SHIFT)
+#define PLAT_QEMU_HOLD_STATE_WAIT	0
+#define PLAT_QEMU_HOLD_STATE_GO		1
+
+#define BL_RAM_BASE			(SHARED_RAM_BASE + SHARED_RAM_SIZE)
+#define BL_RAM_SIZE			(SEC_SRAM_SIZE - SHARED_RAM_SIZE)
+
+/*
+ * BL1 specific defines.
+ *
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using
+ * the current BL1 RW debug size plus a little space for growth.
+ */
+#define BL1_RO_BASE			SEC_ROM_BASE
+#define BL1_RO_LIMIT			(SEC_ROM_BASE + SEC_ROM_SIZE)
+#define BL1_RW_BASE			(BL1_RW_LIMIT - 0x12000)
+#define BL1_RW_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+
+/*
+ * BL2 specific defines.
+ *
+ * Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define BL2_BASE			(BL31_BASE - 0x25000)
+#define BL2_LIMIT			BL31_BASE
+
+/*
+ * BL3-1 specific defines.
+ *
+ * Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL3-1 debug size plus a little space for growth.
+ */
+#define BL31_BASE			(BL31_LIMIT - 0x20000)
+#define BL31_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+#define BL31_PROGBITS_LIMIT		BL1_RW_BASE
+
+
+/*
+ * BL3-2 specific defines.
+ *
+ * BL3-2 can execute from Secure SRAM, or Secure DRAM.
+ */
+#define BL32_SRAM_BASE			BL_RAM_BASE
+#define BL32_SRAM_LIMIT			BL31_BASE
+#define BL32_DRAM_BASE			SEC_DRAM_BASE
+#define BL32_DRAM_LIMIT			(SEC_DRAM_BASE + SEC_DRAM_SIZE)
+
+#define SEC_SRAM_ID			0
+#define SEC_DRAM_ID			1
+
+#if BL32_RAM_LOCATION_ID == SEC_SRAM_ID
+# define BL32_MEM_BASE			BL_RAM_BASE
+# define BL32_MEM_SIZE			BL_RAM_SIZE
+# define BL32_BASE			BL32_SRAM_BASE
+# define BL32_LIMIT			BL32_SRAM_LIMIT
+#elif BL32_RAM_LOCATION_ID == SEC_DRAM_ID
+# define BL32_MEM_BASE			SEC_DRAM_BASE
+# define BL32_MEM_SIZE			SEC_DRAM_SIZE
+# define BL32_BASE			BL32_DRAM_BASE
+# define BL32_LIMIT			BL32_DRAM_LIMIT
+#else
+# error "Unsupported BL32_RAM_LOCATION_ID value"
+#endif
+
+#define NS_IMAGE_OFFSET			0x60000000
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_MMAP_REGIONS		10
+#define MAX_XLAT_TABLES			6
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+
+/*
+ * PL011 related constants
+ */
+#define UART0_BASE			0x09000000
+#define UART1_BASE			0x09040000
+#define UART0_CLK_IN_HZ			1
+#define UART1_CLK_IN_HZ			1
+
+#define PLAT_QEMU_BOOT_UART_BASE	UART0_BASE
+#define PLAT_QEMU_BOOT_UART_CLK_IN_HZ	UART0_CLK_IN_HZ
+
+#define PLAT_QEMU_CRASH_UART_BASE	UART1_BASE
+#define PLAT_QEMU_CRASH_UART_CLK_IN_HZ	UART1_CLK_IN_HZ
+
+#define PLAT_QEMU_CONSOLE_BAUDRATE	115200
+
+#define QEMU_FLASH0_BASE		0x04000000
+#define QEMU_FLASH0_SIZE		0x04000000
+
+#define PLAT_QEMU_FIP_BASE		QEMU_FLASH0_BASE
+#define PLAT_QEMU_FIP_MAX_SIZE		QEMU_FLASH0_SIZE
+
+#define DEVICE0_BASE			0x08000000
+#define DEVICE0_SIZE			0x01000000
+#define DEVICE1_BASE			0x09000000
+#define DEVICE1_SIZE			0x00041000
+
+/*
+ * GIC related constants
+ */
+
+#define GICD_BASE			0x8000000
+#define GICC_BASE			0x8010000
+#define GICR_BASE			0x80A0000
+
+
+#define QEMU_IRQ_SEC_SGI_0		8
+#define QEMU_IRQ_SEC_SGI_1		9
+#define QEMU_IRQ_SEC_SGI_2		10
+#define QEMU_IRQ_SEC_SGI_3		11
+#define QEMU_IRQ_SEC_SGI_4		12
+#define QEMU_IRQ_SEC_SGI_5		13
+#define QEMU_IRQ_SEC_SGI_6		14
+#define QEMU_IRQ_SEC_SGI_7		15
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+#define PLATFORM_G1S_PROPS(grp)						\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_EDGE)
+
+#define PLATFORM_G0_PROPS(grp)
+
+/*
+ * DT related constants
+ */
+#define PLAT_QEMU_DT_BASE		NS_DRAM0_BASE
+#define PLAT_QEMU_DT_MAX_SIZE		0x100000
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	((1000 * 1000 * 1000) / 16)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/qemu/platform.mk b/plat/qemu/platform.mk
new file mode 100644
index 0000000..6b9749c
--- /dev/null
+++ b/plat/qemu/platform.mk
@@ -0,0 +1,186 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Use the GICv2 driver on QEMU by default
+QEMU_USE_GIC_DRIVER	:= QEMU_GICV2
+
+ifeq (${ARM_ARCH_MAJOR},7)
+# ARMv7 Qemu support in trusted firmware expects the Cortex-A15 model.
+# Qemu Cortex-A15 model does not implement the virtualization extension.
+# For this reason, we cannot set ARM_CORTEX_A15=yes and must define all
+# the ARMv7 build directives.
+MARCH32_DIRECTIVE 	:= 	-mcpu=cortex-a15
+$(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING))
+$(eval $(call add_define,ARMV7_SUPPORTS_GENERIC_TIMER))
+# Qemu expects a BL32 boot stage.
+NEED_BL32		:=	yes
+endif # ARMv7
+
+ifeq (${SPD},opteed)
+add-lib-optee 		:= 	yes
+endif
+ifeq ($(AARCH32_SP),optee)
+add-lib-optee 		:= 	yes
+endif
+
+include lib/libfdt/libfdt.mk
+
+ifeq ($(NEED_BL32),yes)
+$(eval $(call add_define,QEMU_LOAD_BL32))
+endif
+
+PLAT_PATH               :=      plat/qemu/
+PLAT_INCLUDES		:=	-Iplat/qemu/include
+
+ifeq (${ARM_ARCH_MAJOR},8)
+PLAT_INCLUDES		+=	-Iinclude/plat/arm/common/${ARCH}
+endif
+
+PLAT_BL_COMMON_SOURCES	:=	plat/qemu/qemu_common.c			  \
+				plat/qemu/qemu_console.c		  \
+				drivers/arm/pl011/${ARCH}/pl011_console.S \
+
+include lib/xlat_tables_v2/xlat_tables.mk
+PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+    include drivers/auth/mbedtls/mbedtls_crypto.mk
+    include drivers/auth/mbedtls/mbedtls_x509.mk
+
+    AUTH_SOURCES	:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c
+
+    BL1_SOURCES		+=	${AUTH_SOURCES}				\
+				bl1/tbbr/tbbr_img_desc.c		\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/qemu/qemu_trusted_boot.c	     	\
+				$(PLAT_PATH)/qemu_rotpk.S
+
+    BL2_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/qemu/qemu_trusted_boot.c	     	\
+				$(PLAT_PATH)/qemu_rotpk.S
+
+    ROT_KEY             = $(BUILD_PLAT)/rot_key.pem
+    ROTPK_HASH          = $(BUILD_PLAT)/rotpk_sha256.bin
+
+    $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+
+    $(BUILD_PLAT)/bl1/qemu_rotpk.o: $(ROTPK_HASH)
+    $(BUILD_PLAT)/bl2/qemu_rotpk.o: $(ROTPK_HASH)
+
+    certificates: $(ROT_KEY)
+
+    $(ROT_KEY):
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+    $(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
+BL1_SOURCES		+=	drivers/io/io_semihosting.c		\
+				drivers/io/io_storage.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				lib/semihosting/semihosting.c		\
+				lib/semihosting/${ARCH}/semihosting_call.S \
+				plat/qemu/qemu_io_storage.c		\
+				plat/qemu/${ARCH}/plat_helpers.S	\
+				plat/qemu/qemu_bl1_setup.c
+
+ifeq (${ARM_ARCH_MAJOR},8)
+BL1_SOURCES		+=	lib/cpus/aarch64/aem_generic.S		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a57.S
+else
+BL1_SOURCES		+=	lib/cpus/${ARCH}/cortex_a15.S
+endif
+
+BL2_SOURCES		+=	drivers/io/io_semihosting.c		\
+				drivers/io/io_storage.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				lib/semihosting/semihosting.c		\
+				lib/semihosting/${ARCH}/semihosting_call.S\
+				plat/qemu/qemu_io_storage.c		\
+				plat/qemu/${ARCH}/plat_helpers.S	\
+				plat/qemu/qemu_bl2_setup.c		\
+				plat/qemu/dt.c				\
+				plat/qemu/qemu_bl2_mem_params_desc.c	\
+				plat/qemu/qemu_image_load.c		\
+				common/desc_image_load.c
+
+ifeq ($(add-lib-optee),yes)
+BL2_SOURCES		+=	lib/optee/optee_utils.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	\
+				plat/common/plat_gicv2.c		\
+				plat/qemu/qemu_gicv2.c
+
+QEMU_GICV3_SOURCES	:=	drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/common/gic_common.c	\
+				plat/common/plat_gicv3.c		\
+				plat/qemu/qemu_gicv3.c
+
+ifeq (${QEMU_USE_GIC_DRIVER}, QEMU_GICV2)
+QEMU_GIC_SOURCES	:=	${QEMU_GICV2_SOURCES}
+else ifeq (${QEMU_USE_GIC_DRIVER}, QEMU_GICV3)
+QEMU_GIC_SOURCES	:=	${QEMU_GICV3_SOURCES}
+else
+$(error "Incorrect GIC driver chosen for QEMU platform")
+endif
+
+ifeq (${ARM_ARCH_MAJOR},8)
+BL31_SOURCES		+=	lib/cpus/aarch64/aem_generic.S		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a57.S		\
+				plat/common/plat_psci_common.c		\
+				plat/qemu/qemu_pm.c			\
+				plat/qemu/topology.c			\
+				plat/qemu/aarch64/plat_helpers.S	\
+				plat/qemu/qemu_bl31_setup.c		\
+				${QEMU_GIC_SOURCES}
+endif
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
+endif
+
+SEPARATE_CODE_AND_RODATA := 1
+ENABLE_STACK_PROTECTOR	 := 0
+ifneq ($(ENABLE_STACK_PROTECTOR), 0)
+	PLAT_BL_COMMON_SOURCES += plat/qemu/qemu_stack_protector.c
+endif
+
+BL32_RAM_LOCATION	:=	tdram
+ifeq (${BL32_RAM_LOCATION}, tsram)
+  BL32_RAM_LOCATION_ID = SEC_SRAM_ID
+else ifeq (${BL32_RAM_LOCATION}, tdram)
+  BL32_RAM_LOCATION_ID = SEC_DRAM_ID
+else
+  $(error "Unsupported BL32_RAM_LOCATION value")
+endif
+
+# Process flags
+$(eval $(call add_define,BL32_RAM_LOCATION_ID))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
diff --git a/plat/qemu/qemu_bl1_setup.c b/plat/qemu/qemu_bl1_setup.c
new file mode 100644
index 0000000..67f3327
--- /dev/null
+++ b/plat/qemu/qemu_bl1_setup.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+
+#include "qemu_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL1*/
+static meminfo_t bl1_tzram_layout;
+
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	qemu_console_init();
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL_RAM_BASE;
+	bl1_tzram_layout.total_size = BL_RAM_SIZE;
+}
+
+/******************************************************************************
+ * Perform the very early platform specific architecture setup.  This only
+ * does basic initialization. Later architectural setup (bl1_arch_setup())
+ * does not do anything platform specific.
+ *****************************************************************************/
+#ifdef __aarch64__
+#define QEMU_CONFIGURE_BL1_MMU(...)	qemu_configure_mmu_el3(__VA_ARGS__)
+#else
+#define QEMU_CONFIGURE_BL1_MMU(...)	qemu_configure_mmu_svc_mon(__VA_ARGS__)
+#endif
+
+void bl1_plat_arch_setup(void)
+{
+	QEMU_CONFIGURE_BL1_MMU(bl1_tzram_layout.total_base,
+				bl1_tzram_layout.total_size,
+				BL_CODE_BASE, BL1_CODE_END,
+				BL1_RO_DATA_BASE, BL1_RO_DATA_END,
+				BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
+}
+
+void bl1_platform_setup(void)
+{
+	plat_qemu_io_setup();
+}
diff --git a/plat/qemu/qemu_bl2_mem_params_desc.c b/plat/qemu/qemu_bl2_mem_params_desc.c
new file mode 100644
index 0000000..a01f2dc
--- /dev/null
+++ b/plat/qemu/qemu_bl2_mem_params_desc.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+#ifdef EL3_PAYLOAD_BASE
+	/* Fill EL3 payload related information (BL31 is EL3 payload) */
+	{ .image_id = BL31_IMAGE_ID,
+
+	  SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				entry_point_info_t,
+				SECURE | EXECUTABLE | EP_FIRST_EXE),
+	  .ep_info.pc = EL3_PAYLOAD_BASE,
+	  .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+				  DISABLE_ALL_EXCEPTIONS),
+
+	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t,
+				IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING),
+
+	  .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+#else /* EL3_PAYLOAD_BASE */
+#ifdef __aarch64__
+	/* Fill BL31 related information */
+	{ .image_id = BL31_IMAGE_ID,
+
+	  SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				entry_point_info_t,
+				SECURE | EXECUTABLE | EP_FIRST_EXE),
+	  .ep_info.pc = BL31_BASE,
+	  .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+				  DISABLE_ALL_EXCEPTIONS),
+# if DEBUG
+	  .ep_info.args.arg1 = QEMU_BL31_PLAT_PARAM_VAL,
+# endif
+	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t,
+				IMAGE_ATTRIB_PLAT_SETUP),
+	  .image_info.image_base = BL31_BASE,
+	  .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef QEMU_LOAD_BL32
+	  .next_handoff_image_id = BL32_IMAGE_ID,
+# else
+	  .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+	},
+#endif /* __aarch64__ */
+# ifdef QEMU_LOAD_BL32
+
+#ifdef __aarch64__
+#define BL32_EP_ATTRIBS		(SECURE | EXECUTABLE)
+#define BL32_IMG_ATTRIBS	0
+#else
+#define BL32_EP_ATTRIBS		(SECURE | EXECUTABLE | EP_FIRST_EXE)
+#define BL32_IMG_ATTRIBS	IMAGE_ATTRIB_PLAT_SETUP
+#endif
+
+	/* Fill BL32 related information */
+	{ .image_id = BL32_IMAGE_ID,
+
+	  SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				entry_point_info_t, BL32_EP_ATTRIBS),
+	  .ep_info.pc = BL32_BASE,
+
+	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+				image_info_t, BL32_IMG_ATTRIBS),
+
+	  .image_info.image_base = BL32_BASE,
+	  .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	  .next_handoff_image_id = BL33_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the
+	 * pager image.
+	 */
+	{ .image_id = BL32_EXTRA1_IMAGE_ID,
+
+	   SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				 entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	   SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+				 image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+	   .image_info.image_base = BL32_BASE,
+	   .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+	   .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the
+	 * paged image.
+	 */
+	{ .image_id = BL32_EXTRA2_IMAGE_ID,
+
+	   SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				 entry_point_info_t, SECURE | NON_EXECUTABLE),
+
+	   SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+				 image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE)
+	   .image_info.image_base = QEMU_OPTEE_PAGEABLE_LOAD_BASE,
+	   .image_info.image_max_size = QEMU_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+	   .next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+# endif /* QEMU_LOAD_BL32 */
+
+	/* Fill BL33 related information */
+	{ .image_id = BL33_IMAGE_ID,
+	  SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+				entry_point_info_t, NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+	  .ep_info.pc = PRELOADED_BL33_BASE,
+
+	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t,
+				IMAGE_ATTRIB_SKIP_LOADING),
+# else /* PRELOADED_BL33_BASE */
+	  .ep_info.pc = NS_IMAGE_OFFSET,
+
+	  SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t,
+				0),
+	  .image_info.image_base = NS_IMAGE_OFFSET,
+	  .image_info.image_max_size = NS_DRAM0_BASE + NS_DRAM0_SIZE -
+				       NS_IMAGE_OFFSET,
+# endif /* !PRELOADED_BL33_BASE */
+
+	  .next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+#endif /* !EL3_PAYLOAD_BASE */
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/qemu/qemu_bl2_setup.c b/plat/qemu/qemu_bl2_setup.c
new file mode 100644
index 0000000..4c97c8d
--- /dev/null
+++ b/plat/qemu/qemu_bl2_setup.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <lib/optee_utils.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include "qemu_private.h"
+
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			       u_register_t arg2, u_register_t arg3)
+{
+	meminfo_t *mem_layout = (void *)arg1;
+
+	/* Initialize the console to provide early debug support */
+	qemu_console_init();
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+
+	plat_qemu_io_setup();
+}
+
+static void security_setup(void)
+{
+	/*
+	 * This is where a TrustZone address space controller and other
+	 * security related peripherals, would be configured.
+	 */
+}
+
+static void update_dt(void)
+{
+	int ret;
+	void *fdt = (void *)(uintptr_t)PLAT_QEMU_DT_BASE;
+
+	ret = fdt_open_into(fdt, fdt, PLAT_QEMU_DT_MAX_SIZE);
+	if (ret < 0) {
+		ERROR("Invalid Device Tree at %p: error %d\n", fdt, ret);
+		return;
+	}
+
+	if (dt_add_psci_node(fdt)) {
+		ERROR("Failed to add PSCI Device Tree node\n");
+		return;
+	}
+
+	if (dt_add_psci_cpu_enable_methods(fdt)) {
+		ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
+		return;
+	}
+
+	ret = fdt_pack(fdt);
+	if (ret < 0)
+		ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, ret);
+}
+
+void bl2_platform_setup(void)
+{
+	security_setup();
+	update_dt();
+
+	/* TODO Initialize timer */
+}
+
+#ifdef __aarch64__
+#define QEMU_CONFIGURE_BL2_MMU(...)	qemu_configure_mmu_el1(__VA_ARGS__)
+#else
+#define QEMU_CONFIGURE_BL2_MMU(...)	qemu_configure_mmu_svc_mon(__VA_ARGS__)
+#endif
+
+void bl2_plat_arch_setup(void)
+{
+	QEMU_CONFIGURE_BL2_MMU(bl2_tzram_layout.total_base,
+			      bl2_tzram_layout.total_size,
+			      BL_CODE_BASE, BL_CODE_END,
+			      BL_RO_DATA_BASE, BL_RO_DATA_END,
+			      BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+static uint32_t qemu_get_spsr_for_bl32_entry(void)
+{
+#ifdef __aarch64__
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL3-2 image.
+	 */
+	return 0;
+#else
+	return SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE,
+			   DISABLE_ALL_EXCEPTIONS);
+#endif
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+static uint32_t qemu_get_spsr_for_bl33_entry(void)
+{
+	uint32_t spsr;
+#ifdef __aarch64__
+	unsigned int mode;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+#else
+	spsr = SPSR_MODE32(MODE32_svc,
+		    plat_get_ns_image_entrypoint() & 0x1,
+		    SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
+#endif
+	return spsr;
+}
+
+static int qemu_bl2_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE)
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+
+	assert(bl_mem_params);
+
+	switch (image_id) {
+	case BL32_IMAGE_ID:
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE)
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+					 &pager_mem_params->image_info,
+					 &paged_mem_params->image_info);
+		if (err != 0) {
+			WARN("OPTEE header parse error.\n");
+		}
+
+#if defined(SPD_opteed)
+		/*
+		 * OP-TEE expect to receive DTB address in x2.
+		 * This will be copied into x2 by dispatcher.
+		 */
+		bl_mem_params->ep_info.args.arg3 = PLAT_QEMU_DT_BASE;
+#else /* case AARCH32_SP_OPTEE */
+		bl_mem_params->ep_info.args.arg0 =
+					bl_mem_params->ep_info.args.arg1;
+		bl_mem_params->ep_info.args.arg1 = 0;
+		bl_mem_params->ep_info.args.arg2 = PLAT_QEMU_DT_BASE;
+		bl_mem_params->ep_info.args.arg3 = 0;
+#endif
+#endif
+		bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl32_entry();
+		break;
+
+	case BL33_IMAGE_ID:
+#ifdef AARCH32_SP_OPTEE
+		/* AArch32 only core: OP-TEE expects NSec EP in register LR */
+		pager_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID);
+		assert(pager_mem_params);
+		pager_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc;
+#endif
+
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl33_entry();
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return qemu_bl2_handle_post_image_load(image_id);
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+	return NS_IMAGE_OFFSET;
+}
diff --git a/plat/qemu/qemu_bl31_setup.c b/plat/qemu/qemu_bl31_setup.c
new file mode 100644
index 0000000..4d36b03
--- /dev/null
+++ b/plat/qemu/qemu_bl31_setup.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/bl_common.h>
+#include <plat/common/platform.h>
+
+#include "qemu_private.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL3-1 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup.  Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	/* Initialize the console to provide early debug support */
+	qemu_console_init();
+
+	/*
+	 * Check params passed from BL2
+	 */
+	bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
+
+	assert(params_from_bl2);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_image_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (!bl33_image_ep_info.pc)
+		panic();
+}
+
+void bl31_plat_arch_setup(void)
+{
+	qemu_configure_mmu_el3(BL31_BASE, (BL31_END - BL31_BASE),
+			      BL_CODE_BASE, BL_CODE_END,
+			      BL_RO_DATA_BASE, BL_RO_DATA_END,
+			      BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
+}
+
+void bl31_platform_setup(void)
+{
+	plat_qemu_gic_init();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image
+ * for the security state specified. BL3-3 corresponds to the non-secure
+ * image type while BL3-2 corresponds to the secure image type. A NULL
+ * pointer is returned if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type));
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+	/*
+	 * None of the images on the ARM development platforms can have 0x0
+	 * as the entrypoint
+	 */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
diff --git a/plat/qemu/qemu_common.c b/plat/qemu/qemu_common.c
new file mode 100644
index 0000000..56bf953
--- /dev/null
+++ b/plat/qemu/qemu_common.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "qemu_private.h"
+
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#ifdef DEVICE1_BASE
+#define MAP_DEVICE1	MAP_REGION_FLAT(DEVICE1_BASE,			\
+					DEVICE1_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+#endif
+
+#ifdef DEVICE2_BASE
+#define MAP_DEVICE2	MAP_REGION_FLAT(DEVICE2_BASE,			\
+					DEVICE2_SIZE,			\
+					MT_DEVICE | MT_RO | MT_SECURE)
+#endif
+
+#define MAP_SHARED_RAM	MAP_REGION_FLAT(SHARED_RAM_BASE,		\
+					SHARED_RAM_SIZE,		\
+					MT_DEVICE  | MT_RW | MT_SECURE)
+
+#define MAP_BL32_MEM	MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_NS_DRAM0	MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_FLASH0	MAP_REGION_FLAT(QEMU_FLASH0_BASE, QEMU_FLASH0_SIZE, \
+					MT_MEMORY | MT_RO | MT_SECURE)
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * arm_configure_mmu_elx() will give the available subset of that,
+ */
+#ifdef IMAGE_BL1
+static const mmap_region_t plat_qemu_mmap[] = {
+	MAP_FLASH0,
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+#ifdef MAP_DEVICE1
+	MAP_DEVICE1,
+#endif
+#ifdef MAP_DEVICE2
+	MAP_DEVICE2,
+#endif
+	{0}
+};
+#endif
+#ifdef IMAGE_BL2
+static const mmap_region_t plat_qemu_mmap[] = {
+	MAP_FLASH0,
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+#ifdef MAP_DEVICE1
+	MAP_DEVICE1,
+#endif
+#ifdef MAP_DEVICE2
+	MAP_DEVICE2,
+#endif
+	MAP_NS_DRAM0,
+	MAP_BL32_MEM,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL31
+static const mmap_region_t plat_qemu_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+#ifdef MAP_DEVICE1
+	MAP_DEVICE1,
+#endif
+	MAP_BL32_MEM,
+	{0}
+};
+#endif
+#ifdef IMAGE_BL32
+static const mmap_region_t plat_qemu_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+#ifdef MAP_DEVICE1
+	MAP_DEVICE1,
+#endif
+	{0}
+};
+#endif
+
+/*******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+
+#define DEFINE_CONFIGURE_MMU_EL(_el)					\
+	void qemu_configure_mmu_##_el(unsigned long total_base,	\
+				   unsigned long total_size,		\
+				   unsigned long code_start,		\
+				   unsigned long code_limit,		\
+				   unsigned long ro_start,		\
+				   unsigned long ro_limit,		\
+				   unsigned long coh_start,		\
+				   unsigned long coh_limit)		\
+	{								\
+		mmap_add_region(total_base, total_base,			\
+				total_size,				\
+				MT_MEMORY | MT_RW | MT_SECURE);		\
+		mmap_add_region(code_start, code_start,			\
+				code_limit - code_start,		\
+				MT_CODE | MT_SECURE);			\
+		mmap_add_region(ro_start, ro_start,			\
+				ro_limit - ro_start,			\
+				MT_RO_DATA | MT_SECURE);		\
+		mmap_add_region(coh_start, coh_start,			\
+				coh_limit - coh_start,			\
+				MT_DEVICE | MT_RW | MT_SECURE);		\
+		mmap_add(plat_qemu_mmap);				\
+		init_xlat_tables();					\
+									\
+		enable_mmu_##_el(0);					\
+	}
+
+/* Define EL1 and EL3 variants of the function initialising the MMU */
+#ifdef __aarch64__
+DEFINE_CONFIGURE_MMU_EL(el1)
+DEFINE_CONFIGURE_MMU_EL(el3)
+#else
+DEFINE_CONFIGURE_MMU_EL(svc_mon)
+#endif
+
+
diff --git a/plat/qemu/qemu_console.c b/plat/qemu/qemu_console.c
new file mode 100644
index 0000000..fec1828
--- /dev/null
+++ b/plat/qemu/qemu_console.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/console.h>
+#include <drivers/arm/pl011.h>
+
+static console_pl011_t console;
+
+void qemu_console_init(void)
+{
+	(void)console_pl011_register(PLAT_QEMU_BOOT_UART_BASE,
+			       PLAT_QEMU_BOOT_UART_CLK_IN_HZ,
+			       PLAT_QEMU_CONSOLE_BAUDRATE, &console);
+
+	console_set_scope(&console.console, CONSOLE_FLAG_BOOT |
+			  CONSOLE_FLAG_RUNTIME);
+}
+
diff --git a/plat/qemu/qemu_gicv2.c b/plat/qemu/qemu_gicv2.c
new file mode 100644
index 0000000..fb56622
--- /dev/null
+++ b/plat/qemu/qemu_gicv2.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gic_common.h>
+#include <platform_def.h>
+
+static const interrupt_prop_t qemu_interrupt_props[] = {
+	PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+	PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
+};
+
+static const struct gicv2_driver_data plat_gicv2_driver_data = {
+	.gicd_base = GICD_BASE,
+	.gicc_base = GICC_BASE,
+	.interrupt_props = qemu_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props),
+};
+
+void plat_qemu_gic_init(void)
+{
+	/* Initialize the gic cpu and distributor interfaces */
+	gicv2_driver_init(&plat_gicv2_driver_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+void qemu_pwr_gic_on_finish(void)
+{
+	/* TODO: This setup is needed only after a cold boot */
+	gicv2_pcpu_distif_init();
+
+	/* Enable the gic cpu interface */
+	gicv2_cpuif_enable();
+}
diff --git a/plat/qemu/qemu_gicv3.c b/plat/qemu/qemu_gicv3.c
new file mode 100644
index 0000000..28572c5
--- /dev/null
+++ b/plat/qemu/qemu_gicv3.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019, Linaro Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+
+static const interrupt_prop_t qemu_interrupt_props[] = {
+	PLATFORM_G1S_PROPS(INTR_GROUP1S),
+	PLATFORM_G0_PROPS(INTR_GROUP0)
+};
+
+static uintptr_t qemu_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static unsigned int qemu_mpidr_to_core_pos(unsigned long mpidr)
+{
+	return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t qemu_gicv3_driver_data = {
+	.gicd_base = GICD_BASE,
+	.gicr_base = GICR_BASE,
+	.interrupt_props = qemu_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = qemu_rdistif_base_addrs,
+	.mpidr_to_core_pos = qemu_mpidr_to_core_pos
+};
+
+void plat_qemu_gic_init(void)
+{
+	gicv3_driver_init(&qemu_gicv3_driver_data);
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void qemu_pwr_gic_on_finish(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
diff --git a/plat/qemu/qemu_image_load.c b/plat/qemu/qemu_image_load.c
new file mode 100644
index 0000000..9970d1d
--- /dev/null
+++ b/plat/qemu/qemu_image_load.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/desc_image_load.h>
+
+/*******************************************************************************
+ * This function is a wrapper of a common function which flushes the data
+ * structures so that they are visible in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function is a wrapper of a common function which returns the list of
+ * loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function is a wrapper of a common function which returns the data
+ * structures of the next BL image.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/qemu/qemu_io_storage.c b/plat/qemu/qemu_io_storage.c
new file mode 100644
index 0000000..0e81cd1
--- /dev/null
+++ b/plat/qemu/qemu_io_storage.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <drivers/io/io_semihosting.h>
+#include <drivers/io/io_storage.h>
+#include <lib/semihosting.h>
+#include <tools_share/firmware_image_package.h>
+
+/* Semihosting filenames */
+#define BL2_IMAGE_NAME			"bl2.bin"
+#define BL31_IMAGE_NAME			"bl31.bin"
+#define BL32_IMAGE_NAME			"bl32.bin"
+#define BL32_EXTRA1_IMAGE_NAME		"bl32_extra1.bin"
+#define BL32_EXTRA2_IMAGE_NAME		"bl32_extra2.bin"
+#define BL33_IMAGE_NAME			"bl33.bin"
+
+#if TRUSTED_BOARD_BOOT
+#define TRUSTED_BOOT_FW_CERT_NAME	"tb_fw.crt"
+#define TRUSTED_KEY_CERT_NAME		"trusted_key.crt"
+#define SOC_FW_KEY_CERT_NAME		"soc_fw_key.crt"
+#define TOS_FW_KEY_CERT_NAME		"tos_fw_key.crt"
+#define NT_FW_KEY_CERT_NAME		"nt_fw_key.crt"
+#define SOC_FW_CONTENT_CERT_NAME	"soc_fw_content.crt"
+#define TOS_FW_CONTENT_CERT_NAME	"tos_fw_content.crt"
+#define NT_FW_CONTENT_CERT_NAME		"nt_fw_content.crt"
+#endif /* TRUSTED_BOARD_BOOT */
+
+
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+static const io_dev_connector_t *sh_dev_con;
+static uintptr_t sh_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = PLAT_QEMU_FIP_BASE,
+	.length = PLAT_QEMU_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static const io_file_spec_t sh_file_spec[] = {
+	[BL2_IMAGE_ID] = {
+		.path = BL2_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL31_IMAGE_ID] = {
+		.path = BL31_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL32_IMAGE_ID] = {
+		.path = BL32_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		.path = BL32_EXTRA1_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		.path = BL32_EXTRA2_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[BL33_IMAGE_ID] = {
+		.path = BL33_IMAGE_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		.path = TRUSTED_BOOT_FW_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		.path = TRUSTED_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		.path = SOC_FW_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		.path = TOS_FW_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		.path = NT_FW_KEY_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		.path = SOC_FW_CONTENT_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		.path = TOS_FW_CONTENT_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		.path = NT_FW_CONTENT_CERT_NAME,
+		.mode = FOPEN_MODE_RB
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+/* By default, ARM platforms load images from the FIP */
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		open_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+static int open_semihosting(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if the file exists on semi-hosting.*/
+	result = io_dev_init(sh_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(sh_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Semi-hosting IO\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void plat_qemu_io_setup(void)
+{
+	int io_result;
+
+	io_result = register_io_dev_fip(&fip_dev_con);
+	assert(io_result == 0);
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&memmap_dev_handle);
+	assert(io_result == 0);
+
+	/* Register the additional IO devices on this platform */
+	io_result = register_io_dev_sh(&sh_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+static int get_alt_image_source(unsigned int image_id, uintptr_t *dev_handle,
+				  uintptr_t *image_spec)
+{
+	int result = open_semihosting((const uintptr_t)&sh_file_spec[image_id]);
+
+	if (result == 0) {
+		*dev_handle = sh_dev_handle;
+		*image_spec = (uintptr_t)&sh_file_spec[image_id];
+	}
+
+	return result;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	if (result == 0) {
+		*image_spec = policy->image_spec;
+		*dev_handle = *(policy->dev_handle);
+	} else {
+		VERBOSE("Trying alternative IO\n");
+		result = get_alt_image_source(image_id, dev_handle, image_spec);
+	}
+
+	return result;
+}
diff --git a/plat/qemu/qemu_pm.c b/plat/qemu/qemu_pm.c
new file mode 100644
index 0000000..a199688
--- /dev/null
+++ b/plat/qemu/qemu_pm.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "qemu_private.h"
+
+/*
+ * The secure entry point to be used on warm reset.
+ */
+static unsigned long secure_entrypoint;
+
+/* Make composite power state parameter till power level 0 */
+#if PSCI_EXTENDED_STATE_ID
+
+#define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		 ((type) << PSTATE_TYPE_SHIFT))
+#else
+#define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+		 ((type) << PSTATE_TYPE_SHIFT))
+#endif /* PSCI_EXTENDED_STATE_ID */
+
+
+#define qemu_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
+		 qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
+
+
+
+/*
+ *  The table storing the valid idle power states. Ensure that the
+ *  array entries are populated in ascending order of state-id to
+ *  enable us to use binary search during power state validation.
+ *  The table must be terminated by a NULL entry.
+ */
+static const unsigned int qemu_pm_idle_states[] = {
+	/* State-id - 0x01 */
+	qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
+				MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x02 */
+	qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
+				MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x22 */
+	qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF,
+				MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
+	0,
+};
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the power state
+ * parameter. The power state parameter has to be a composite power state.
+ ******************************************************************************/
+static int qemu_validate_power_state(unsigned int power_state,
+				psci_power_state_t *req_state)
+{
+	unsigned int state_id;
+	int i;
+
+	assert(req_state);
+
+	/*
+	 *  Currently we are using a linear search for finding the matching
+	 *  entry in the idle power state array. This can be made a binary
+	 *  search if the number of entries justify the additional complexity.
+	 */
+	for (i = 0; !!qemu_pm_idle_states[i]; i++) {
+		if (power_state == qemu_pm_idle_states[i])
+			break;
+	}
+
+	/* Return error if entry not found in the idle state array */
+	if (!qemu_pm_idle_states[i])
+		return PSCI_E_INVALID_PARAMS;
+
+	i = 0;
+	state_id = psci_get_pstate_id(power_state);
+
+	/* Parse the State ID and populate the state info parameter */
+	while (state_id) {
+		req_state->pwr_domain_state[i++] = state_id &
+						PLAT_LOCAL_PSTATE_MASK;
+		state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the non secure
+ * entrypoint.
+ ******************************************************************************/
+static int qemu_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint >= NS_DRAM0_BASE) &&
+	    (entrypoint < (NS_DRAM0_BASE + NS_DRAM0_SIZE)))
+		return PSCI_E_SUCCESS;
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+/*******************************************************************************
+ * Platform handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+static void qemu_cpu_standby(plat_local_state_t cpu_state)
+{
+
+	assert(cpu_state == PLAT_LOCAL_STATE_RET);
+
+	/*
+	 * Enter standby state
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	dsb();
+	wfi();
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int qemu_pwr_domain_on(u_register_t mpidr)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned pos = plat_core_pos_by_mpidr(mpidr);
+	uint64_t *hold_base = (uint64_t *)PLAT_QEMU_HOLD_BASE;
+
+	hold_base[pos] = PLAT_QEMU_HOLD_STATE_GO;
+	sev();
+
+	return rc;
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void qemu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	assert(0);
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void qemu_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	assert(0);
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void qemu_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_LOCAL_STATE_OFF);
+
+	qemu_pwr_gic_on_finish();
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ ******************************************************************************/
+void qemu_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	assert(0);
+}
+
+/*******************************************************************************
+ * Platform handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 qemu_system_off(void)
+{
+	ERROR("QEMU System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 qemu_system_reset(void)
+{
+	ERROR("QEMU System Reset: operation not handled.\n");
+	panic();
+}
+
+static const plat_psci_ops_t plat_qemu_psci_pm_ops = {
+	.cpu_standby = qemu_cpu_standby,
+	.pwr_domain_on = qemu_pwr_domain_on,
+	.pwr_domain_off = qemu_pwr_domain_off,
+	.pwr_domain_suspend = qemu_pwr_domain_suspend,
+	.pwr_domain_on_finish = qemu_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish,
+	.system_off = qemu_system_off,
+	.system_reset = qemu_system_reset,
+	.validate_power_state = qemu_validate_power_state,
+	.validate_ns_entrypoint = qemu_validate_ns_entrypoint
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	uintptr_t *mailbox = (void *) PLAT_QEMU_TRUSTED_MAILBOX_BASE;
+
+	*mailbox = sec_entrypoint;
+	secure_entrypoint = (unsigned long) sec_entrypoint;
+	*psci_ops = &plat_qemu_psci_pm_ops;
+
+	return 0;
+}
diff --git a/plat/qemu/qemu_private.h b/plat/qemu/qemu_private.h
new file mode 100644
index 0000000..46b1ca1
--- /dev/null
+++ b/plat/qemu/qemu_private.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef QEMU_PRIVATE_H
+#define QEMU_PRIVATE_H
+
+#include <stdint.h>
+
+void qemu_configure_mmu_svc_mon(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long code_start, unsigned long code_limit,
+			unsigned long ro_start, unsigned long ro_limit,
+			unsigned long coh_start, unsigned long coh_limit);
+
+void qemu_configure_mmu_el1(unsigned long total_base, unsigned long total_size,
+			unsigned long code_start, unsigned long code_limit,
+			unsigned long ro_start, unsigned long ro_limit,
+			unsigned long coh_start, unsigned long coh_limit);
+
+void qemu_configure_mmu_el3(unsigned long total_base, unsigned long total_size,
+			unsigned long code_start, unsigned long code_limit,
+			unsigned long ro_start, unsigned long ro_limit,
+			unsigned long coh_start, unsigned long coh_limit);
+
+void plat_qemu_io_setup(void);
+unsigned int plat_qemu_calc_core_pos(u_register_t mpidr);
+
+int dt_add_psci_node(void *fdt);
+int dt_add_psci_cpu_enable_methods(void *fdt);
+
+void qemu_console_init(void);
+
+void plat_qemu_gic_init(void);
+void qemu_pwr_gic_on_finish(void);
+
+#endif /* QEMU_PRIVATE_H */
diff --git a/plat/qemu/qemu_rotpk.S b/plat/qemu/qemu_rotpk.S
new file mode 100644
index 0000000..5d1b83f
--- /dev/null
+++ b/plat/qemu/qemu_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global qemu_rotpk_hash
+	.global qemu_rotpk_hash_end
+qemu_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+qemu_rotpk_hash_end:
diff --git a/plat/qemu/qemu_stack_protector.c b/plat/qemu/qemu_stack_protector.c
new file mode 100644
index 0000000..c226158
--- /dev/null
+++ b/plat/qemu/qemu_stack_protector.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL)
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+	/*
+	 * Ideally, a random number should be returned instead of the
+	 * combination of a timer's value and a compile-time constant.
+	 * As the virt platform does not have any random number generator,
+	 * this is better than nothing but not necessarily really secure.
+	 */
+	return RANDOM_CANARY_VALUE ^ read_cntpct_el0();
+}
+
diff --git a/plat/qemu/qemu_trusted_boot.c b/plat/qemu/qemu_trusted_boot.c
new file mode 100644
index 0000000..1ef7e43
--- /dev/null
+++ b/plat/qemu/qemu_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char qemu_rotpk_hash[], qemu_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = qemu_rotpk_hash;
+	*key_len = qemu_rotpk_hash_end - qemu_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/qemu/sp_min/sp_min-qemu.mk b/plat/qemu/sp_min/sp_min-qemu.mk
new file mode 100644
index 0000000..e93a0c2
--- /dev/null
+++ b/plat/qemu/sp_min/sp_min-qemu.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES		+=	plat/qemu/sp_min/sp_min_setup.c		\
+				plat/qemu/aarch32/plat_helpers.S	\
+				plat/qemu/qemu_pm.c			\
+				plat/qemu/topology.c
+
+BL32_SOURCES		+=	lib/cpus/aarch32/aem_generic.S		\
+				lib/cpus/aarch32/cortex_a15.S
+
+BL32_SOURCES		+=	plat/common/aarch32/platform_mp_stack.S \
+				plat/common/plat_psci_common.c \
+				plat/common/plat_gicv2.c
+
+
+BL32_SOURCES		+=	drivers/arm/gic/v2/gicv2_helpers.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/common/gic_common.c
diff --git a/plat/qemu/sp_min/sp_min_setup.c b/plat/qemu/sp_min/sp_min_setup.c
new file mode 100644
index 0000000..7ec657b
--- /dev/null
+++ b/plat/qemu/sp_min/sp_min_setup.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include "../qemu_private.h"
+
+#if RESET_TO_SP_MIN
+#error qemu does not support RESET_TO_SP_MIN
+#endif
+
+static entry_point_info_t bl33_image_ep_info;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+#define PLATFORM_G1S_PROPS(grp)						\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL),	\
+	INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,	\
+					   grp, GIC_INTR_CFG_LEVEL)
+
+#define PLATFORM_G0_PROPS(grp)
+
+static const interrupt_prop_t stih410_interrupt_props[] = {
+	PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0),
+	PLATFORM_G0_PROPS(GICV2_INTR_GROUP0)
+};
+
+static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
+
+static const struct gicv2_driver_data plat_gicv2_driver_data = {
+	.gicd_base = GICD_BASE,
+	.gicc_base = GICC_BASE,
+	.interrupt_props = stih410_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(stih410_interrupt_props),
+	.target_masks = target_mask_array,
+	.target_masks_num = ARRAY_SIZE(target_mask_array),
+};
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
+{
+	entry_point_info_t *next_image_info = &bl33_image_ep_info;
+
+	/*
+	 * None of the images on the ARM development platforms can have 0x0
+	 * as the entrypoint
+	 */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3)
+{
+	bl_params_t *params_from_bl2 = (bl_params_t *)arg0;
+
+	/* Initialize the console to provide early debug support */
+	qemu_console_init();
+
+	ERROR("qemu sp_min, console init\n");
+	/*
+	 * Check params passed from BL2
+	 */
+	assert(params_from_bl2);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 entry point information from BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (!bl33_image_ep_info.pc)
+		panic();
+}
+
+void sp_min_plat_arch_setup(void)
+{
+	qemu_configure_mmu_svc_mon(BL32_RO_BASE, BL32_END - BL32_RO_BASE,
+				  BL_CODE_BASE, BL_CODE_END,
+				  BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
+
+}
+
+void sp_min_platform_setup(void)
+{
+	/* Initialize the gic cpu and distributor interfaces */
+	gicv2_driver_init(&plat_gicv2_driver_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void sp_min_plat_fiq_handler(uint32_t id)
+{
+	VERBOSE("[sp_min] interrupt #%d\n", id);
+}
diff --git a/plat/qemu/topology.c b/plat/qemu/topology.c
new file mode 100644
index 0000000..6352706
--- /dev/null
+++ b/plat/qemu/topology.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include "qemu_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	/* Number of children for the second node */
+	PLATFORM_CLUSTER1_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return plat_qemu_calc_core_pos(mpidr);
+}
diff --git a/plat/renesas/rcar/aarch64/plat_helpers.S b/plat/renesas/rcar/aarch64/plat_helpers.S
new file mode 100644
index 0000000..61dd622
--- /dev/null
+++ b/plat/renesas/rcar/aarch64/plat_helpers.S
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <common/runtime_svc.h>
+#include <cortex_a57.h>
+#include <platform_def.h>
+
+#include "rcar_def.h"
+
+	.globl	plat_get_my_entrypoint
+	.extern	plat_set_my_stack
+	.globl	platform_mem_init
+
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	plat_invalidate_icache
+	.globl	plat_report_exception
+	.globl	plat_secondary_reset
+	.globl	plat_reset_handler
+	.globl	plat_my_core_pos
+	.extern	rcar_log_init
+
+	.extern console_rcar_init
+	.extern console_rcar_putc
+	.extern console_rcar_flush
+
+#if IMAGE_BL2
+	#define	INT_ID_MASK	(0x3ff)
+	.extern bl2_interrupt_error_type
+	.extern bl2_interrupt_error_id
+	.globl  bl2_enter_bl31
+	.extern gicv2_acknowledge_interrupt
+	.extern rcar_swdt_exec
+#endif
+
+	/* -----------------------------------------------------
+	 * void platform_get_core_pos (mpidr)
+	 * -----------------------------------------------------
+	 */
+func platform_get_core_pos
+	and     x1, x0, #MPIDR_CPU_MASK
+	and     x0, x0, #MPIDR_CLUSTER_MASK
+	add     x0, x1, x0, LSR #6
+	ret
+endfunc platform_get_core_pos
+
+	/* -----------------------------------------------------
+	 * void platform_my_core_pos
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs     x0, mpidr_el1
+	b	platform_get_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void platform_get_my_entrypoint (unsigned int mpid);
+	 *
+	 * Main job of this routine is to distinguish between
+	 * a cold and warm boot.
+	 * On a cold boot the secondaries first wait for the
+	 * platform to be initialized after which they are
+	 * hotplugged in. The primary proceeds to perform the
+	 * platform initialization.
+	 * On a warm boot, each cpu jumps to the address in its
+	 * mailbox.
+	 *
+	 * TODO: Not a good idea to save lr in a temp reg
+	 * -----------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	mrs	x0, mpidr_el1
+	mov	x9, x30 /* lr */
+
+#if defined(IMAGE_BL2)
+	/* always cold boot on bl2 */
+	mov	x0, #0
+	ret	x9
+#else
+       ldr 	x1, =BOOT_KIND_BASE
+       ldr	x21, [x1]
+
+	/* Check the reset info */
+	and	x1, x21, #0x000c
+	cmp	x1, #0x0008
+	beq	el3_panic
+	cmp	x1, #0x000c
+	beq	el3_panic
+
+	/* Check the boot kind */
+	and	x1, x21, #0x0003
+	cmp	x1, #0x0002
+	beq	el3_panic
+	cmp	x1, #0x0003
+	beq	el3_panic
+
+	/* warm boot or cold boot */
+	and	x1, x21, #1
+	cmp	x1, #0
+	bne	warm_reset
+
+	/* Cold boot */
+	mov	x0, #0
+	b	exit
+
+warm_reset:
+	/* --------------------------------------------------------------------
+	 * A per-cpu mailbox is maintained in the trusted SDRAM. Its flushed out
+	 * of the caches after every update using normal memory so its safe to
+	 * read it here with SO attributes
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	x10, =MBOX_BASE
+	bl	platform_get_core_pos
+	lsl	x0, x0, #CACHE_WRITEBACK_SHIFT
+	ldr	x0, [x10, x0]
+	cbz	x0, _panic
+exit:
+	ret	x9
+_panic:
+	b	do_panic
+#endif
+
+endfunc plat_get_my_entrypoint
+
+	/* ---------------------------------------------
+	 * plat_secondary_reset
+	 *
+	 * ---------------------------------------------
+	 */
+func plat_secondary_reset
+	mrs	x0, sctlr_el3
+	bic	x0, x0, #SCTLR_EE_BIT
+	msr	sctlr_el3, x0
+	isb
+
+	mrs	x0, cptr_el3
+	bic	w0, w0, #TCPAC_BIT
+	bic	w0, w0, #TTA_BIT
+	bic	w0, w0, #TFP_BIT
+	msr	cptr_el3, x0
+
+	mov_imm	x0, PARAMS_BASE
+	mov_imm	x2, BL31_BASE
+       ldr x3, =BOOT_KIND_BASE
+	mov x1, #0x1
+	str x1, [x3]
+	br	x2	/* jump to BL31 */
+	nop
+	nop
+	nop
+endfunc plat_secondary_reset
+
+	/* ---------------------------------------------
+	 * plat_enter_bl31
+	 *
+	 * ---------------------------------------------
+	 */
+func bl2_enter_bl31
+	mov	x20, x0
+        /*
+         * MMU needs to be disabled because both BL2 and BL31 execute
+         * in EL3, and therefore share the same address space.
+         * BL31 will initialize the address space according to its
+         * own requirement.
+         */
+#if RCAR_BL2_DCACHE == 1
+	/* Disable mmu and data cache */
+	bl	disable_mmu_el3
+	/* Data cache clean and invalidate */
+	mov	x0, #DCCISW
+	bl	dcsw_op_all
+	/* TLB invalidate all, EL3 */
+	tlbi	alle3
+#endif /* RCAR_BL2_DCACHE == 1 */
+	bl	disable_mmu_icache_el3
+	/* Invalidate instruction cache */
+	ic	iallu
+	dsb	sy
+	isb
+	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
+	msr	elr_el3, x0
+	msr	spsr_el3, x1
+	eret
+endfunc bl2_enter_bl31
+
+	/* -----------------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * Zero out the mailbox registers in the shared memory
+	 * and set the rcar_boot_kind_flag.
+	 * The mmu is turned off right now and only the primary can
+	 * ever execute this code. Secondaries will read the
+	 * mailboxes using SO accesses.
+	 * -----------------------------------------------------
+	 */
+func platform_mem_init
+#if !IMAGE_BL2
+	ldr	x0, =MBOX_BASE
+	mov	w1, #PLATFORM_CORE_COUNT
+loop:
+	str	xzr, [x0], #CACHE_WRITEBACK_GRANULE
+	subs	w1, w1, #1
+	b.gt	loop
+#endif
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * ---------------------------------------------
+	 */
+func plat_report_exception
+	/* Switch to SP_EL0 */
+	msr	spsel, #0
+#if IMAGE_BL2
+	mov	w1, #FIQ_SP_EL0
+	cmp	w0, w1
+	beq	rep_exec_fiq_elx
+	b	rep_exec_panic_type
+rep_exec_fiq_elx:
+	bl	gicv2_acknowledge_interrupt
+	mov	x2, #INT_ID_MASK
+	and	x0, x0, x2
+	mov	x1, #ARM_IRQ_SEC_WDT
+	cmp	x0, x1
+	bne	rep_exec_panic_id
+	mrs	x0, ELR_EL3
+	b	rcar_swdt_exec
+rep_exec_panic_type:
+	/* x0 is interrupt TYPE */
+	b	bl2_interrupt_error_type
+rep_exec_panic_id:
+	/* x0 is interrupt ID */
+	b	bl2_interrupt_error_id
+rep_exec_end:
+#endif
+	ret
+endfunc plat_report_exception
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize log area
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+#if IMAGE_BL2
+	mov	x0, #0
+#else
+	mov	x1, sp
+	mov_imm	x2, RCAR_CRASH_STACK
+	mov	sp, x2
+	str	x1, [sp, #-16]!
+	str	x30, [sp, #-16]!
+	bl	console_rcar_init
+	ldr	x30, [sp], #16
+	ldr	x1, [sp], #16
+	mov	sp, x1
+#endif
+	ret
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to store a character to log area
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov	x1, sp
+	mov_imm	x2, RCAR_CRASH_STACK
+	mov	sp, x2
+	str	x1, [sp, #-16]!
+	str	x30, [sp, #-16]!
+	str	x3, [sp, #-16]!
+	str	x4, [sp, #-16]!
+	str	x5, [sp, #-16]!
+	bl	console_rcar_putc
+	ldr	x5, [sp], #16
+	ldr	x4, [sp], #16
+	ldr	x3, [sp], #16
+	ldr	x30, [sp], #16
+	ldr	x1, [sp], #16
+	mov	sp, x1
+	ret
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	b	console_rcar_flush
+endfunc plat_crash_console_flush
+
+	/* --------------------------------------------------------------------
+	 * void plat_reset_handler(void);
+	 *
+	 * Before adding code in this function, refer to the guidelines in
+	 * docs/firmware-design.md to determine whether the code should reside
+	 * within the FIRST_RESET_HANDLER_CALL block or not.
+	 *
+	 * For R-Car H3:
+	 * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 * - Set the L2 Data setup latency to 1 (i.e. 1 cycles) for Cortex-A57
+	 * - Set the L2 Data RAM latency to 3 (i.e. 4 cycles) for Cortex-A57
+	 * For R-Car M3/M3N:
+	 * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57
+	 * - Set the L2 Data setup latency to 0 (i.e. 0 cycles) for Cortex-A57
+	 * - Set the L2 Data RAM latency to 3 (i.e. 4 cycles) for Cortex-A57
+	 *
+	 * --------------------------------------------------------------------
+	 */
+func plat_reset_handler
+	/*
+	 * On R-Car H3    :  x2 := 0
+	 * On R-Car M3/M3N:  x2 := 1
+	 */
+	/* read PRR */
+	ldr	x0, =0xFFF00044
+	ldr	w0, [x0]
+	ubfx	w0, w0, 8, 8
+	/* H3? */
+	cmp	w0, #0x4F
+	b.eq	RCARH3
+	/* set R-Car M3/M3N */
+	mov	x2, #1
+	b	CHK_A5x
+RCARH3:
+	/* set R-Car H3 */
+	mov	x2, #0
+	/* --------------------------------------------------------------------
+	 * Determine whether this code is executed on a Cortex-A53 or on a
+	 * Cortex-A57 core.
+	 * --------------------------------------------------------------------
+	 */
+CHK_A5x:
+	mrs	x0, midr_el1
+	ubfx	x1, x0, MIDR_PN_SHIFT, #12
+	cmp     w1, #((CORTEX_A57_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+	b.eq	A57
+	ret
+A57:
+	/* Get data from CORTEX_A57_L2CTLR_EL1	*/
+	mrs	x0, CORTEX_A57_L2CTLR_EL1
+	/*
+	 * On R-Car H3/M3/M3N
+	 *
+	 * L2 Tag RAM latency is bit8-6 of CORTEX_A57_L2CTLR_EL1
+	 * L2 Data RAM setup is bit5 of CORTEX_A57_L2CTLR_EL1
+	 * L2 Data RAM latency is bit2-0 of CORTEX_A57_L2CTLR_EL1
+	 */
+	/* clear bit of L2 RAM	*/
+	/* ~(0x1e7) -> x1	*/
+	mov	x1, #0x1e7
+	neg	x1, x1
+	/* clear bit of L2 RAM -> x0 */
+	and	x0, x0, x1
+	/* L2 Tag RAM latency (3 cycles) */
+	orr	x0, x0, #0x2 << 6
+	/* If M3/M3N then L2 RAM setup is 0 */
+	cbnz	x2, M3_L2
+	/* L2 Data RAM setup (1 cycle) */
+	orr	x0, x0, #0x1 << 5
+M3_L2:
+	/* L2 Data RAM latency (4 cycles) */
+	orr	x0, x0, #0x3
+	/* Store data to L2CTLR_EL1 */
+	msr	CORTEX_A57_L2CTLR_EL1, x0
+apply_l2_ram_latencies:
+	ret
+endfunc plat_reset_handler
+
+	/* ---------------------------------------------
+	 * void plat_invalidate_icache(void)
+	 * Instruction Cache Invalidate All to PoU
+	 * ---------------------------------------------
+	 */
+func plat_invalidate_icache
+	ic	iallu
+
+	ret
+endfunc plat_invalidate_icache
diff --git a/plat/renesas/rcar/aarch64/platform_common.c b/plat/renesas/rcar/aarch64/platform_common.c
new file mode 100644
index 0000000..b0a88cb
--- /dev/null
+++ b/plat/renesas/rcar/aarch64/platform_common.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_version.h"
+
+#if (IMAGE_BL2)
+extern void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *p);
+extern int32_t rcar_get_certificate(const int32_t name, uint32_t *cert);
+#endif
+
+const uint8_t version_of_renesas[VERSION_OF_RENESAS_MAXLEN]
+		__attribute__ ((__section__("ro"))) = VERSION_OF_RENESAS;
+
+#define MAP_SHARED_RAM		MAP_REGION_FLAT(RCAR_SHARED_MEM_BASE,	\
+					RCAR_SHARED_MEM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_FLASH0		MAP_REGION_FLAT(FLASH0_BASE,		\
+					FLASH0_SIZE,			\
+					MT_MEMORY | MT_RO | MT_SECURE)
+
+#define MAP_DRAM1_NS		MAP_REGION_FLAT(DRAM1_NS_BASE,		\
+					DRAM1_NS_SIZE,			\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_DEVICE_RCAR		MAP_REGION_FLAT(DEVICE_RCAR_BASE,	\
+					DEVICE_RCAR_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_DEVICE_RCAR2	MAP_REGION_FLAT(DEVICE_RCAR_BASE2,	\
+					DEVICE_RCAR_SIZE2,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SRAM		MAP_REGION_FLAT(DEVICE_SRAM_BASE,	\
+					DEVICE_SRAM_SIZE,		\
+					MT_MEMORY | MT_RO | MT_SECURE)
+
+#define MAP_SRAM_STACK		MAP_REGION_FLAT(DEVICE_SRAM_STACK_BASE,	\
+					DEVICE_SRAM_STACK_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_ATFW_CRASH  	MAP_REGION_FLAT(RCAR_BL31_CRASH_BASE,	\
+					RCAR_BL31_CRASH_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_ATFW_LOG		MAP_REGION_FLAT(RCAR_BL31_LOG_BASE,	\
+					RCAR_BL31_LOG_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+#if IMAGE_BL2
+#define MAP_DRAM0		MAP_REGION_FLAT(DRAM1_BASE,		\
+					DRAM1_SIZE,			\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_REG0		MAP_REGION_FLAT(DEVICE_RCAR_BASE,	\
+					DEVICE_RCAR_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_RAM0		MAP_REGION_FLAT(RCAR_SYSRAM_BASE,	\
+					RCAR_SYSRAM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_REG1		MAP_REGION_FLAT(REG1_BASE,		\
+					REG1_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_ROM			MAP_REGION_FLAT(ROM0_BASE,		\
+					ROM0_SIZE,			\
+					MT_MEMORY | MT_RO | MT_SECURE)
+
+#define MAP_REG2		MAP_REGION_FLAT(REG2_BASE,		\
+					REG2_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_DRAM1		MAP_REGION_FLAT(DRAM_40BIT_BASE,	\
+					DRAM_40BIT_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+#ifdef BL32_BASE
+#define MAP_BL32_MEM		MAP_REGION_FLAT(BL32_BASE,		\
+					BL32_LIMIT - BL32_BASE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+#if IMAGE_BL2
+static const mmap_region_t rcar_mmap[] = {
+	MAP_FLASH0,	/*   0x08000000 -   0x0BFFFFFF  RPC area            */
+	MAP_DRAM0,	/*   0x40000000 -   0xBFFFFFFF  DRAM area(Legacy)   */
+	MAP_REG0,	/*   0xE6000000 -   0xE62FFFFF  SoC register area   */
+	MAP_RAM0,	/*   0xE6300000 -   0xE6303FFF  System RAM area     */
+	MAP_REG1,	/*   0xE6400000 -   0xEAFFFFFF  SoC register area   */
+	MAP_ROM,	/*   0xEB100000 -   0xEB127FFF  boot ROM area       */
+	MAP_REG2,	/*   0xEC000000 -   0xFFFFFFFF  SoC register area   */
+	MAP_DRAM1,	/* 0x0400000000 - 0x07FFFFFFFF  DRAM area(4GB over) */
+	{0}
+};
+#endif
+
+#if IMAGE_BL31
+static const mmap_region_t rcar_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_ATFW_CRASH,
+	MAP_ATFW_LOG,
+	MAP_DEVICE_RCAR,
+	MAP_DEVICE_RCAR2,
+	MAP_SRAM,
+	MAP_SRAM_STACK,
+	{0}
+};
+#endif
+
+#if IMAGE_BL32
+static const mmap_region_t rcar_mmap[] = {
+	MAP_DEVICE0,
+	MAP_DEVICE1,
+	{0}
+};
+#endif
+
+CASSERT(ARRAY_SIZE(rcar_mmap) + RCAR_BL_REGIONS
+	<= MAX_MMAP_REGIONS, assert_max_mmap_regions);
+
+/*
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ */
+#if USE_COHERENT_MEM
+void rcar_configure_mmu_el3(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long ro_start,
+			    unsigned long ro_limit,
+			    unsigned long coh_start,
+			    unsigned long coh_limit)
+{
+	mmap_add_region(total_base, total_base, total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+			MT_MEMORY | MT_RO | MT_SECURE);
+	mmap_add_region(coh_start, coh_start, coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+	mmap_add(rcar_mmap);
+
+	init_xlat_tables();
+	enable_mmu_el3(0);
+}
+#else
+void rcar_configure_mmu_el3(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long ro_start,
+			    unsigned long ro_limit)
+{
+	mmap_add_region(total_base, total_base, total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+			MT_MEMORY | MT_RO | MT_SECURE);
+	mmap_add(rcar_mmap);
+
+	init_xlat_tables();
+	enable_mmu_el3(0);
+}
+#endif
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#if (IMAGE_BL2)
+	uint32_t cert, len;
+	uintptr_t dst;
+	int32_t ret;
+
+	ret = rcar_get_certificate(NON_TRUSTED_FW_CONTENT_CERT_ID, &cert);
+	if (ret) {
+		ERROR("%s : cert file load error", __func__);
+		return NS_IMAGE_OFFSET;
+	}
+
+	rcar_read_certificate((uint64_t) cert, &len, &dst);
+
+	return dst;
+#else
+	return NS_IMAGE_OFFSET;
+#endif
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	unsigned int freq;
+
+	freq = mmio_read_32(ARM_SYS_CNTCTL_BASE + CNTFID_OFF);
+	if (freq == 0)
+		panic();
+
+	return freq;
+}
+
+void plat_rcar_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+static const interrupt_prop_t interrupt_props[] = {
+#if IMAGE_BL2
+	INTR_PROP_DESC(ARM_IRQ_SEC_WDT, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+#else
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
+	INTR_PROP_DESC(ARM_IRQ_SEC_RPC, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_TIMER_UP, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_WDT, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_CRYPT, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_CRYPT_SecPKA, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(ARM_IRQ_SEC_CRYPT_PubPKA, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+#endif
+};
+
+static const gicv2_driver_data_t plat_gicv2_driver_data = {
+	.interrupt_props = interrupt_props,
+	.interrupt_props_num = (uint32_t) ARRAY_SIZE(interrupt_props),
+	.gicd_base = RCAR_GICD_BASE,
+	.gicc_base = RCAR_GICC_BASE,
+};
+
+void plat_rcar_gic_driver_init(void)
+{
+	gicv2_driver_init(&plat_gicv2_driver_data);
+}
diff --git a/plat/renesas/rcar/bl2_cpg_init.c b/plat/renesas/rcar/bl2_cpg_init.c
new file mode 100644
index 0000000..ed9b772
--- /dev/null
+++ b/plat/renesas/rcar/bl2_cpg_init.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+#include "cpg_registers.h"
+#include "rcar_private.h"
+
+static void bl2_secure_cpg_init(void);
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)
+static void bl2_realtime_cpg_init_h3(void);
+static void bl2_system_cpg_init_h3(void);
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3)
+static void bl2_realtime_cpg_init_m3(void);
+static void bl2_system_cpg_init_m3(void);
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N)
+static void bl2_realtime_cpg_init_m3n(void);
+static void bl2_system_cpg_init_m3n(void);
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_V3M)
+static void bl2_realtime_cpg_init_v3m(void);
+static void bl2_system_cpg_init_v3m(void);
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_E3)
+static void bl2_realtime_cpg_init_e3(void);
+static void bl2_system_cpg_init_e3(void);
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_D3)
+static void bl2_realtime_cpg_init_d3(void);
+static void bl2_system_cpg_init_d3(void);
+#endif
+
+typedef struct {
+	uintptr_t adr;
+	uint32_t val;
+} reg_setting_t;
+
+static void bl2_secure_cpg_init(void)
+{
+	uint32_t stop_cr2, reset_cr2;
+	uint32_t stop_cr4, reset_cr4;
+	uint32_t stop_cr5, reset_cr5;
+
+#if (RCAR_LSI == RCAR_D3)
+	reset_cr2 = 0x00000000U;
+	stop_cr2 = 0xFFFFFFFFU;
+#elif (RCAR_LSI == RCAR_E3)
+	reset_cr2 = 0x10000000U;
+	stop_cr2 = 0xEFFFFFFFU;
+#else
+	reset_cr2 = 0x14000000U;
+	stop_cr2 = 0xEBFFFFFFU;
+#endif
+
+#if (RCAR_LSI == RCAR_D3)
+	reset_cr4 = 0x00000000U;
+	stop_cr4 = 0xFFFFFFFFU;
+	reset_cr5 = 0x00000000U;
+	stop_cr5 = 0xFFFFFFFFU;
+#else
+	reset_cr4 = 0x80000003U;
+	stop_cr4 = 0x7FFFFFFFU;
+	reset_cr5 = 0x40000000U;
+	stop_cr5 = 0xBFFFFFFFU;
+#endif
+
+	/** Secure Module Stop Control Registers */
+	cpg_write(SCMSTPCR0, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR2, stop_cr2);
+	cpg_write(SCMSTPCR3, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR4, stop_cr4);
+	cpg_write(SCMSTPCR5, stop_cr5);
+	cpg_write(SCMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR8, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR9, 0xFFFDFFFFU);
+	cpg_write(SCMSTPCR10, 0xFFFFFFFFU);
+	cpg_write(SCMSTPCR11, 0xFFFFFFFFU);
+
+	/** Secure Software Reset Access Enable Control Registers */
+	cpg_write(SCSRSTECR0, 0x00000000U);
+	cpg_write(SCSRSTECR1, 0x00000000U);
+	cpg_write(SCSRSTECR2, reset_cr2);
+	cpg_write(SCSRSTECR3, 0x00000000U);
+	cpg_write(SCSRSTECR4, reset_cr4);
+	cpg_write(SCSRSTECR5, reset_cr5);
+	cpg_write(SCSRSTECR6, 0x00000000U);
+	cpg_write(SCSRSTECR7, 0x00000000U);
+	cpg_write(SCSRSTECR8, 0x00000000U);
+	cpg_write(SCSRSTECR9, 0x00020000U);
+	cpg_write(SCSRSTECR10, 0x00000000U);
+	cpg_write(SCSRSTECR11, 0x00000000U);
+}
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)
+static void bl2_realtime_cpg_init_h3(void)
+{
+	uint32_t cut = mmio_read_32(RCAR_PRR) & RCAR_CUT_MASK;
+	uint32_t cr0, cr8;
+
+	cr0 = (cut == RCAR_CUT_VER10 || cut == RCAR_CUT_VER11) ?
+	    0x00200000U : 0x00210000U;
+	cr8 = (cut == RCAR_CUT_VER10 || cut == RCAR_CUT_VER11) ?
+	    0x01F1FFF4U : 0x01F1FFF7U;
+
+	cpg_write(RMSTPCR0, cr0);
+	cpg_write(RMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR2, 0x040E0FDCU);
+	cpg_write(RMSTPCR3, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR4, 0x80000004U);
+	cpg_write(RMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(RMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR8, cr8);
+	cpg_write(RMSTPCR9, 0xFFFFFFFEU);
+	cpg_write(RMSTPCR10, 0xFFFEFFE0U);
+	cpg_write(RMSTPCR11, 0x000000B7U);
+}
+
+static void bl2_system_cpg_init_h3(void)
+{
+	/** System Module Stop Control Registers */
+	cpg_write(SMSTPCR0, 0x00210000U);
+	cpg_write(SMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR2, 0x040E2FDCU);
+	cpg_write(SMSTPCR3, 0xFFFFFBDFU);
+	cpg_write(SMSTPCR4, 0x80000004U);
+	cpg_write(SMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(SMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR8, 0x01F1FFF5U);
+	cpg_write(SMSTPCR9, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR10, 0xFFFEFFE0U);
+	cpg_write(SMSTPCR11, 0x000000B7U);
+}
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3)
+static void bl2_realtime_cpg_init_m3(void)
+{
+	/** Realtime Module Stop Control Registers */
+	cpg_write(RMSTPCR0, 0x00200000U);
+	cpg_write(RMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR2, 0x040E0FDCU);
+	cpg_write(RMSTPCR3, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR4, 0x80000004U);
+	cpg_write(RMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(RMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR8, 0x01F1FFF7U);
+	cpg_write(RMSTPCR9, 0xFFFFFFFEU);
+	cpg_write(RMSTPCR10, 0xFFFEFFE0U);
+	cpg_write(RMSTPCR11, 0x000000B7U);
+}
+
+static void bl2_system_cpg_init_m3(void)
+{
+	/** System Module Stop Control Registers */
+	cpg_write(SMSTPCR0, 0x00200000U);
+	cpg_write(SMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR2, 0x040E2FDCU);
+	cpg_write(SMSTPCR3, 0xFFFFFBDFU);
+	cpg_write(SMSTPCR4, 0x80000004U);
+	cpg_write(SMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(SMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR8, 0x01F1FFF7U);
+	cpg_write(SMSTPCR9, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR10, 0xFFFEFFE0U);
+	cpg_write(SMSTPCR11, 0x000000B7U);
+}
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N)
+static void bl2_realtime_cpg_init_m3n(void)
+{
+	/** Realtime Module Stop Control Registers */
+	cpg_write(RMSTPCR0, 0x00210000U);
+	cpg_write(RMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR2, 0x040E0FDCU);
+	cpg_write(RMSTPCR3, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR4, 0x80000004U);
+	cpg_write(RMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(RMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR8, 0x00F1FFF7U);
+	cpg_write(RMSTPCR9, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR10, 0xFFFFFFE0U);
+	cpg_write(RMSTPCR11, 0x000000B7U);
+}
+
+static void bl2_system_cpg_init_m3n(void)
+{
+	/* System Module Stop Control Registers */
+	cpg_write(SMSTPCR0, 0x00210000U);
+	cpg_write(SMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR2, 0x040E2FDCU);
+	cpg_write(SMSTPCR3, 0xFFFFFBDFU);
+	cpg_write(SMSTPCR4, 0x80000004U);
+	cpg_write(SMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(SMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR8, 0x00F1FFF7U);
+	cpg_write(SMSTPCR9, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR10, 0xFFFFFFE0U);
+	cpg_write(SMSTPCR11, 0x000000B7U);
+}
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_V3M)
+static void bl2_realtime_cpg_init_v3m(void)
+{
+	/* Realtime Module Stop Control Registers */
+	cpg_write(RMSTPCR0, 0x00230000U);
+	cpg_write(RMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR2, 0x14062FD8U);
+	cpg_write(RMSTPCR3, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR4, 0x80000184U);
+	cpg_write(RMSTPCR5, 0x83FFFFFFU);
+	cpg_write(RMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR8, 0x7FF3FFF4U);
+	cpg_write(RMSTPCR9, 0xFFFFFFFEU);
+}
+
+static void bl2_system_cpg_init_v3m(void)
+{
+	/* System Module Stop Control Registers */
+	cpg_write(SMSTPCR0, 0x00210000U);
+	cpg_write(SMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR2, 0x340E2FDCU);
+	cpg_write(SMSTPCR3, 0xFFFFFBDFU);
+	cpg_write(SMSTPCR4, 0x80000004U);
+	cpg_write(SMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(SMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR8, 0x01F1FFF5U);
+	cpg_write(SMSTPCR9, 0xFFFFFFFEU);
+}
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_E3)
+static void bl2_realtime_cpg_init_e3(void)
+{
+	/* Realtime Module Stop Control Registers */
+	cpg_write(RMSTPCR0, 0x00210000U);
+	cpg_write(RMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR2, 0x000E0FDCU);
+	cpg_write(RMSTPCR3, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR4, 0x80000004U);
+	cpg_write(RMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(RMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR8, 0x00F1FFF7U);
+	cpg_write(RMSTPCR9, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR10, 0xFFFFFFE8U);
+	cpg_write(RMSTPCR11, 0x000000B7U);
+}
+
+static void bl2_system_cpg_init_e3(void)
+{
+	/* System Module Stop Control Registers */
+	cpg_write(SMSTPCR0, 0x00210000U);
+	cpg_write(SMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR2, 0x000E2FDCU);
+	cpg_write(SMSTPCR3, 0xFFFFFBDFU);
+	cpg_write(SMSTPCR4, 0x80000004U);
+	cpg_write(SMSTPCR5, 0xC3FFFFFFU);
+	cpg_write(SMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR8, 0x00F1FFF7U);
+	cpg_write(SMSTPCR9, 0xFFFFFFDFU);
+	cpg_write(SMSTPCR10, 0xFFFFFFE8U);
+	cpg_write(SMSTPCR11, 0x000000B7U);
+}
+#endif
+
+#if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_D3)
+static void bl2_realtime_cpg_init_d3(void)
+{
+	/* Realtime Module Stop Control Registers */
+	cpg_write(RMSTPCR0, 0x00010000U);
+	cpg_write(RMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR2, 0x00060FDCU);
+	cpg_write(RMSTPCR3, 0xFFFFFFDFU);
+	cpg_write(RMSTPCR4, 0x80000184U);
+	cpg_write(RMSTPCR5, 0x83FFFFFFU);
+	cpg_write(RMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(RMSTPCR8, 0x00F1FFF7U);
+	cpg_write(RMSTPCR9, 0xF3F5E016U);
+	cpg_write(RMSTPCR10, 0xFFFEFFE0U);
+	cpg_write(RMSTPCR11, 0x000000B7U);
+}
+
+static void bl2_system_cpg_init_d3(void)
+{
+	/* System Module Stop Control Registers */
+	cpg_write(SMSTPCR0, 0x00010000U);
+	cpg_write(SMSTPCR1, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR2, 0x00060FDCU);
+	cpg_write(SMSTPCR3, 0xFFFFFBDFU);
+	cpg_write(SMSTPCR4, 0x00000084U);
+	cpg_write(SMSTPCR5, 0x83FFFFFFU);
+	cpg_write(SMSTPCR6, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR7, 0xFFFFFFFFU);
+	cpg_write(SMSTPCR8, 0x00F1FFF7U);
+	cpg_write(SMSTPCR9, 0xF3F5E016U);
+	cpg_write(SMSTPCR10, 0xFFFEFFE0U);
+	cpg_write(SMSTPCR11, 0x000000B7U);
+}
+#endif
+
+void bl2_cpg_init(void)
+{
+	uint32_t boot_cpu = mmio_read_32(RCAR_MODEMR) & MODEMR_BOOT_CPU_MASK;
+#if RCAR_LSI == RCAR_AUTO
+	uint32_t product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
+#endif
+	bl2_secure_cpg_init();
+
+	if (boot_cpu == MODEMR_BOOT_CPU_CA57 ||
+	    boot_cpu == MODEMR_BOOT_CPU_CA53) {
+#if RCAR_LSI == RCAR_AUTO
+
+		switch (product) {
+		case RCAR_PRODUCT_H3:
+			bl2_realtime_cpg_init_h3();
+			break;
+		case RCAR_PRODUCT_M3:
+			bl2_realtime_cpg_init_m3();
+			break;
+		case RCAR_PRODUCT_M3N:
+			bl2_realtime_cpg_init_m3n();
+			break;
+		case RCAR_PRODUCT_V3M:
+			bl2_realtime_cpg_init_v3m();
+			break;
+		case RCAR_PRODUCT_E3:
+			bl2_realtime_cpg_init_e3();
+			break;
+		case RCAR_PRODUCT_D3:
+			bl2_realtime_cpg_init_d3();
+			break;
+		default:
+			panic();
+			break;
+		}
+#elif (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)
+		bl2_realtime_cpg_init_h3();
+#elif RCAR_LSI == RCAR_M3
+		bl2_realtime_cpg_init_m3();
+#elif RCAR_LSI == RCAR_M3N
+		bl2_realtime_cpg_init_m3n();
+#elif RCAR_LSI == RCAR_V3M
+		bl2_realtime_cpg_init_v3m();
+#elif RCAR_LSI == RCAR_E3
+		bl2_realtime_cpg_init_e3();
+#elif RCAR_LSI == RCAR_D3
+		bl2_realtime_cpg_init_d3();
+#else
+#error "Don't have CPG initialize routine(unknown)."
+#endif
+	}
+}
+
+void bl2_system_cpg_init(void)
+{
+#if RCAR_LSI == RCAR_AUTO
+	uint32_t product = mmio_read_32(RCAR_PRR) & RCAR_PRODUCT_MASK;
+
+	switch (product) {
+	case RCAR_PRODUCT_H3:
+		bl2_system_cpg_init_h3();
+		break;
+	case RCAR_PRODUCT_M3:
+		bl2_system_cpg_init_m3();
+		break;
+	case RCAR_PRODUCT_M3N:
+		bl2_system_cpg_init_m3n();
+		break;
+	case RCAR_PRODUCT_V3M:
+		bl2_system_cpg_init_v3m();
+		break;
+	case RCAR_PRODUCT_E3:
+		bl2_system_cpg_init_e3();
+		break;
+	case RCAR_PRODUCT_D3:
+		bl2_system_cpg_init_d3();
+		break;
+	default:
+		panic();
+		break;
+	}
+#elif (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)
+	bl2_system_cpg_init_h3();
+#elif RCAR_LSI == RCAR_M3
+	bl2_system_cpg_init_m3();
+#elif RCAR_LSI == RCAR_M3N
+	bl2_system_cpg_init_m3n();
+#elif RCAR_LSI == RCAR_V3M
+	bl2_system_cpg_init_v3m();
+#elif RCAR_LSI == RCAR_E3
+	bl2_system_cpg_init_e3();
+#elif RCAR_LSI == RCAR_D3
+	bl2_system_cpg_init_d3();
+#else
+#error "Don't have CPG initialize routine(unknown)."
+#endif
+}
diff --git a/plat/renesas/rcar/bl2_interrupt_error.c b/plat/renesas/rcar/bl2_interrupt_error.c
new file mode 100644
index 0000000..d9a4b8e
--- /dev/null
+++ b/plat/renesas/rcar/bl2_interrupt_error.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+
+#include "rcar_def.h"
+
+#define SWDT_ERROR_ID	(1024U)
+#define SWDT_ERROR_TYPE	(16U)
+#define SWDT_CHAR_MAX	(13U)
+
+extern void rcar_swdt_release(void);
+
+void bl2_interrupt_error_id(uint32_t int_id)
+{
+	ERROR("\n");
+	if (int_id >= SWDT_ERROR_ID) {
+		ERROR("Unhandled exception occurred.\n");
+		ERROR("     Exception type = FIQ_SP_EL0\n");
+		panic();
+	}
+
+	/* Clear the interrupt request */
+	gicv2_end_of_interrupt((uint32_t) int_id);
+	rcar_swdt_release();
+	ERROR("Unhandled exception occurred.\n");
+	ERROR("     Exception type = FIQ_SP_EL0\n");
+	ERROR("     SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3());
+	ERROR("     ELR_EL3  = 0x%x\n", (uint32_t) read_elr_el3());
+	ERROR("     ESR_EL3  = 0x%x\n", (uint32_t) read_esr_el3());
+	ERROR("     FAR_EL3  = 0x%x\n", (uint32_t) read_far_el3());
+	ERROR("\n");
+	panic();
+}
+
+void bl2_interrupt_error_type(uint32_t ex_type)
+{
+	const uint8_t interrupt_ex[SWDT_ERROR_TYPE][SWDT_CHAR_MAX] = {
+		"SYNC SP EL0",
+		"IRQ SP EL0",
+		"FIQ SP EL0",
+		"SERR SP EL0",
+		"SYNC SP ELx",
+		"IRQ SP ELx",
+		"FIQ SP ELx",
+		"SERR SP ELx",
+		"SYNC AARCH64",
+		"IRQ AARCH64",
+		"FIQ AARCH64",
+		"SERR AARCH64",
+		"SYNC AARCH32",
+		"IRQ AARCH32",
+		"FIQ AARCH32",
+		"SERR AARCH32"
+	};
+	char msg[128];
+
+	/* Clear the interrupt request  */
+	if (ex_type >= SWDT_ERROR_TYPE) {
+		ERROR("\n");
+		ERROR("Unhandled exception occurred.\n");
+		ERROR("     Exception type = Unknown (%d)\n", ex_type);
+		goto loop;
+	}
+
+	rcar_swdt_release();
+	ERROR("\n");
+	ERROR("Unhandled exception occurred.\n");
+	snprintf(msg, sizeof(msg), "     Exception type = %s\n",
+		 &interrupt_ex[ex_type][0]);
+	ERROR("%s", msg);
+	switch (ex_type) {
+	case SYNC_EXCEPTION_SP_EL0:
+		ERROR("     SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3());
+		ERROR("     ELR_EL3  = 0x%x\n", (uint32_t) read_elr_el3());
+		ERROR("     ESR_EL3  = 0x%x\n", (uint32_t) read_esr_el3());
+		ERROR("     FAR_EL3  = 0x%x\n", (uint32_t) read_far_el3());
+		break;
+	case IRQ_SP_EL0:
+		ERROR("     SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3());
+		ERROR("     ELR_EL3  = 0x%x\n", (uint32_t) read_elr_el3());
+		ERROR("     IAR_EL3  = 0x%x\n", gicv2_acknowledge_interrupt());
+		break;
+	case FIQ_SP_EL0:
+		ERROR("     SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3());
+		ERROR("     ELR_EL3  = 0x%x\n", (uint32_t) read_elr_el3());
+		ERROR("     IAR_EL3  = 0x%x\n", gicv2_acknowledge_interrupt());
+		break;
+	case SERROR_SP_EL0:
+		ERROR("     SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3());
+		ERROR("     ELR_EL3  = 0x%x\n", (uint32_t) read_elr_el3());
+		ERROR("     ESR_EL3  = 0x%x\n", (uint32_t) read_esr_el3());
+		ERROR("     FAR_EL3  = 0x%x\n", (uint32_t) read_far_el3());
+		break;
+	default:
+		break;
+	}
+loop:
+	ERROR("\n");
+	panic();
+}
diff --git a/plat/renesas/rcar/bl2_plat_mem_params_desc.c b/plat/renesas/rcar/bl2_plat_mem_params_desc.c
new file mode 100644
index 0000000..3b124c7
--- /dev/null
+++ b/plat/renesas/rcar/bl2_plat_mem_params_desc.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#if (RCAR_BL33_EXECUTION_EL != 0) && (RCAR_BL33_EXECUTION_EL != 1)
+#error
+#endif
+
+#if (RCAR_BL33_EXECUTION_EL == 0)
+#define BL33_MODE MODE_EL1
+#else
+#define BL33_MODE MODE_EL2
+#endif
+
+extern uint64_t fdt_blob[PAGE_SIZE_4KB / sizeof(uint64_t)];
+
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+			entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.spsr = SPSR_64(MODE_EL3,
+			MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS),
+		.ep_info.pc = BL31_BASE,
+
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+			image_info_t, IMAGE_ATTRIB_PLAT_SETUP),
+		.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+		.image_info.image_base = BL31_BASE,
+
+# ifdef BL32_BASE
+		.next_handoff_image_id = BL32_IMAGE_ID,
+# else
+		.next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+	},
+# ifdef BL32_BASE
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+			entry_point_info_t, SECURE | EXECUTABLE),
+		.ep_info.pc = BL32_BASE,
+		.ep_info.spsr = 0,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+			image_info_t, 0),
+		.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+		.image_info.image_base = BL32_BASE,
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+#endif
+	{
+		.image_id = BL33_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2,
+			entry_point_info_t, NON_SECURE | EXECUTABLE),
+		.ep_info.spsr = SPSR_64(BL33_MODE, MODE_SP_ELX,
+			DISABLE_ALL_EXCEPTIONS),
+		.ep_info.pc = BL33_BASE,
+#ifdef RCAR_BL33_ARG0
+		.ep_info.args.arg0 = RCAR_BL33_ARG0,
+#endif
+		.ep_info.args.arg1 = (uintptr_t)fdt_blob,
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
+			image_info_t, 0),
+		.image_info.image_max_size =
+				(uint32_t) (DRAM_LIMIT - BL33_BASE),
+		.image_info.image_base = BL33_BASE,
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/renesas/rcar/bl2_plat_setup.c b/plat/renesas/rcar/bl2_plat_setup.c
new file mode 100644
index 0000000..3c9b56f
--- /dev/null
+++ b/plat/renesas/rcar/bl2_plat_setup.c
@@ -0,0 +1,1043 @@
+/*
+ * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl1/bl1.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#include "avs_driver.h"
+#include "boot_init_dram.h"
+#include "cpg_registers.h"
+#include "board.h"
+#include "emmc_def.h"
+#include "emmc_hal.h"
+#include "emmc_std.h"
+
+#if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR
+#include "iic_dvfs.h"
+#endif
+
+#include "io_common.h"
+#include "qos_init.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_version.h"
+#include "rom_api.h"
+
+IMPORT_SYM(unsigned long, __RO_START__, BL2_RO_BASE)
+IMPORT_SYM(unsigned long, __RO_END__, BL2_RO_LIMIT)
+
+#if USE_COHERENT_MEM
+IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL2_COHERENT_RAM_BASE)
+IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL2_COHERENT_RAM_LIMIT)
+#endif
+
+extern void plat_rcar_gic_driver_init(void);
+extern void plat_rcar_gic_init(void);
+extern void bl2_enter_bl31(const struct entry_point_info *bl_ep_info);
+extern void bl2_system_cpg_init(void);
+extern void bl2_secure_setting(void);
+extern void bl2_cpg_init(void);
+extern void rcar_io_emmc_setup(void);
+extern void rcar_io_setup(void);
+extern void rcar_swdt_release(void);
+extern void rcar_swdt_init(void);
+extern void rcar_rpc_init(void);
+extern void rcar_pfc_init(void);
+extern void rcar_dma_init(void);
+
+static void bl2_init_generic_timer(void);
+
+/* R-Car Gen3 product check */
+#if (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N)
+#define TARGET_PRODUCT			RCAR_PRODUCT_H3
+#define TARGET_NAME			"R-Car H3"
+#elif RCAR_LSI == RCAR_M3
+#define TARGET_PRODUCT			RCAR_PRODUCT_M3
+#define TARGET_NAME			"R-Car M3"
+#elif RCAR_LSI == RCAR_M3N
+#define TARGET_PRODUCT			RCAR_PRODUCT_M3N
+#define TARGET_NAME			"R-Car M3N"
+#elif RCAR_LSI == RCAR_V3M
+#define TARGET_PRODUCT			RCAR_PRODUCT_V3M
+#define TARGET_NAME			"R-Car V3M"
+#elif RCAR_LSI == RCAR_E3
+#define TARGET_PRODUCT			RCAR_PRODUCT_E3
+#define TARGET_NAME			"R-Car E3"
+#elif RCAR_LSI == RCAR_D3
+#define TARGET_PRODUCT			RCAR_PRODUCT_D3
+#define TARGET_NAME			"R-Car D3"
+#elif RCAR_LSI == RCAR_AUTO
+#define TARGET_NAME			"R-Car H3/M3/M3N/V3M"
+#endif
+
+#if (RCAR_LSI == RCAR_E3)
+#define GPIO_INDT			(GPIO_INDT6)
+#define GPIO_BKUP_TRG_SHIFT		((uint32_t)1U<<13U)
+#else
+#define GPIO_INDT			(GPIO_INDT1)
+#define GPIO_BKUP_TRG_SHIFT		((uint32_t)1U<<8U)
+#endif
+
+CASSERT((PARAMS_BASE + sizeof(bl2_to_bl31_params_mem_t) + 0x100)
+	 < (RCAR_SHARED_MEM_BASE + RCAR_SHARED_MEM_SIZE),
+	assert_bl31_params_do_not_fit_in_shared_memory);
+
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/* FDT with DRAM configuration */
+uint64_t fdt_blob[PAGE_SIZE_4KB / sizeof(uint64_t)];
+static void *fdt = (void *)fdt_blob;
+
+static void unsigned_num_print(unsigned long long int unum, unsigned int radix,
+				char *string)
+{
+	/* Just need enough space to store 64 bit decimal integer */
+	char num_buf[20];
+	int i = 0;
+	unsigned int rem;
+
+	do {
+		rem = unum % radix;
+		if (rem < 0xa)
+			num_buf[i] = '0' + rem;
+		else
+			num_buf[i] = 'a' + (rem - 0xa);
+		i++;
+		unum /= radix;
+	} while (unum > 0U);
+
+	while (--i >= 0)
+		*string++ = num_buf[i];
+}
+
+#if (RCAR_LOSSY_ENABLE == 1)
+typedef struct bl2_lossy_info {
+	uint32_t magic;
+	uint32_t a0;
+	uint32_t b0;
+} bl2_lossy_info_t;
+
+static void bl2_lossy_gen_fdt(uint32_t no, uint64_t start_addr,
+			      uint64_t end_addr, uint32_t format,
+			      uint32_t enable, int fcnlnode)
+{
+	const uint64_t fcnlsize = cpu_to_fdt64(end_addr - start_addr);
+	char nodename[40] = { 0 };
+	int ret, node;
+
+	/* Ignore undefined addresses */
+	if (start_addr == 0 && end_addr == 0)
+		return;
+
+	snprintf(nodename, sizeof(nodename), "lossy-decompression@");
+	unsigned_num_print(start_addr, 16, nodename + strlen(nodename));
+
+	node = ret = fdt_add_subnode(fdt, fcnlnode, nodename);
+	if (ret < 0) {
+		NOTICE("BL2: Cannot create FCNL node (ret=%i)\n", ret);
+		panic();
+	}
+
+	ret = fdt_setprop_string(fdt, node, "compatible",
+				 "renesas,lossy-decompression");
+	if (ret < 0) {
+		NOTICE("BL2: Cannot add FCNL compat string (ret=%i)\n", ret);
+		panic();
+	}
+
+	ret = fdt_appendprop_string(fdt, node, "compatible",
+				    "shared-dma-pool");
+	if (ret < 0) {
+		NOTICE("BL2: Cannot append FCNL compat string (ret=%i)\n", ret);
+		panic();
+	}
+
+	ret = fdt_setprop_u64(fdt, node, "reg", start_addr);
+	if (ret < 0) {
+		NOTICE("BL2: Cannot add FCNL reg prop (ret=%i)\n", ret);
+		panic();
+	}
+
+	ret = fdt_appendprop(fdt, node, "reg", &fcnlsize, sizeof(fcnlsize));
+	if (ret < 0) {
+		NOTICE("BL2: Cannot append FCNL reg size prop (ret=%i)\n", ret);
+		panic();
+	}
+
+	ret = fdt_setprop(fdt, node, "no-map", NULL, 0);
+	if (ret < 0) {
+		NOTICE("BL2: Cannot add FCNL no-map prop (ret=%i)\n", ret);
+		panic();
+	}
+
+	ret = fdt_setprop_u32(fdt, node, "renesas,formats", format);
+	if (ret < 0) {
+		NOTICE("BL2: Cannot add FCNL formats prop (ret=%i)\n", ret);
+		panic();
+	}
+}
+
+static void bl2_lossy_setting(uint32_t no, uint64_t start_addr,
+			      uint64_t end_addr, uint32_t format,
+			      uint32_t enable, int fcnlnode)
+{
+	bl2_lossy_info_t info;
+	uint32_t reg;
+
+	bl2_lossy_gen_fdt(no, start_addr, end_addr, format, enable, fcnlnode);
+
+	reg = format | (start_addr >> 20);
+	mmio_write_32(AXI_DCMPAREACRA0 + 0x8 * no, reg);
+	mmio_write_32(AXI_DCMPAREACRB0 + 0x8 * no, end_addr >> 20);
+	mmio_write_32(AXI_DCMPAREACRA0 + 0x8 * no, reg | enable);
+
+	info.magic = 0x12345678U;
+	info.a0 = mmio_read_32(AXI_DCMPAREACRA0 + 0x8 * no);
+	info.b0 = mmio_read_32(AXI_DCMPAREACRB0 + 0x8 * no);
+
+	mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no, info.magic);
+	mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no + 0x4, info.a0);
+	mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no + 0x8, info.b0);
+
+	NOTICE("     Entry %d: DCMPAREACRAx:0x%x DCMPAREACRBx:0x%x\n", no,
+	       mmio_read_32(AXI_DCMPAREACRA0 + 0x8 * no),
+	       mmio_read_32(AXI_DCMPAREACRB0 + 0x8 * no));
+}
+#endif
+
+void bl2_plat_flush_bl31_params(void)
+{
+	uint32_t product_cut, product, cut;
+	uint32_t boot_dev, boot_cpu;
+	uint32_t lcs, reg, val;
+
+	reg = mmio_read_32(RCAR_MODEMR);
+	boot_dev = reg & MODEMR_BOOT_DEV_MASK;
+
+	if (boot_dev == MODEMR_BOOT_DEV_EMMC_25X1 ||
+	    boot_dev == MODEMR_BOOT_DEV_EMMC_50X8)
+		emmc_terminate();
+
+	if ((reg & MODEMR_BOOT_CPU_MASK) != MODEMR_BOOT_CPU_CR7)
+		bl2_secure_setting();
+
+	reg = mmio_read_32(RCAR_PRR);
+	product_cut = reg & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	product = reg & RCAR_PRODUCT_MASK;
+	cut = reg & RCAR_CUT_MASK;
+
+	if (product == RCAR_PRODUCT_M3 && RCAR_CUT_VER30 > cut)
+		goto tlb;
+
+	if (product == RCAR_PRODUCT_H3 && RCAR_CUT_VER20 > cut)
+		goto tlb;
+
+	if (product == RCAR_PRODUCT_D3)
+		goto tlb;
+
+	/* Disable MFIS write protection */
+	mmio_write_32(MFISWPCNTR, MFISWPCNTR_PASSWORD | 1);
+
+tlb:
+	reg = mmio_read_32(RCAR_MODEMR);
+	boot_cpu = reg & MODEMR_BOOT_CPU_MASK;
+	if (boot_cpu != MODEMR_BOOT_CPU_CA57 &&
+	    boot_cpu != MODEMR_BOOT_CPU_CA53)
+		goto mmu;
+
+	if (product_cut == RCAR_PRODUCT_H3_CUT20) {
+		mmio_write_32(IPMMUVI0_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUVI1_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUPV0_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUPV1_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUPV2_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUPV3_IMSCTLR, IMSCTLR_DISCACHE);
+	} else if (product_cut == (RCAR_PRODUCT_M3N | RCAR_CUT_VER10) ||
+		   product_cut == (RCAR_PRODUCT_M3N | RCAR_CUT_VER11)) {
+		mmio_write_32(IPMMUVI0_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUPV0_IMSCTLR, IMSCTLR_DISCACHE);
+	} else if ((product_cut == (RCAR_PRODUCT_E3 | RCAR_CUT_VER10)) ||
+		   (product_cut == (RCAR_PRODUCT_E3 | RCAR_CUT_VER11))) {
+		mmio_write_32(IPMMUVI0_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUVP0_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUPV0_IMSCTLR, IMSCTLR_DISCACHE);
+	}
+
+	if (product_cut == (RCAR_PRODUCT_H3_CUT20) ||
+	    product_cut == (RCAR_PRODUCT_M3N | RCAR_CUT_VER10) ||
+	    product_cut == (RCAR_PRODUCT_M3N | RCAR_CUT_VER11) ||
+	    product_cut == (RCAR_PRODUCT_E3 | RCAR_CUT_VER10)) {
+		mmio_write_32(IPMMUHC_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMURT_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUMP_IMSCTLR, IMSCTLR_DISCACHE);
+
+		mmio_write_32(IPMMUDS0_IMSCTLR, IMSCTLR_DISCACHE);
+		mmio_write_32(IPMMUDS1_IMSCTLR, IMSCTLR_DISCACHE);
+	}
+
+mmu:
+	mmio_write_32(IPMMUMM_IMSCTLR, IPMMUMM_IMSCTLR_ENABLE);
+	mmio_write_32(IPMMUMM_IMAUXCTLR, IPMMUMM_IMAUXCTLR_NMERGE40_BIT);
+
+	val = rcar_rom_get_lcs(&lcs);
+	if (val) {
+		ERROR("BL2: Failed to get the LCS. (%d)\n", val);
+		panic();
+	}
+
+	if (lcs == LCS_SE)
+		mmio_clrbits_32(P_ARMREG_SEC_CTRL, P_ARMREG_SEC_CTRL_PROT);
+
+	rcar_swdt_release();
+	bl2_system_cpg_init();
+
+#if RCAR_BL2_DCACHE == 1
+	/* Disable data cache (clean and invalidate) */
+	disable_mmu_el3();
+#endif
+}
+
+static uint32_t is_ddr_backup_mode(void)
+{
+#if RCAR_SYSTEM_SUSPEND
+	static uint32_t reason = RCAR_COLD_BOOT;
+	static uint32_t once;
+
+#if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR
+	uint8_t data;
+#endif
+	if (once)
+		return reason;
+
+	once = 1;
+	if ((mmio_read_32(GPIO_INDT) & GPIO_BKUP_TRG_SHIFT) == 0)
+		return reason;
+
+#if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR
+	if (rcar_iic_dvfs_receive(PMIC, REG_KEEP10, &data)) {
+		ERROR("BL2: REG Keep10 READ ERROR.\n");
+		panic();
+	}
+
+	if (KEEP10_MAGIC != data)
+		reason = RCAR_WARM_BOOT;
+#else
+	reason = RCAR_WARM_BOOT;
+#endif
+	return reason;
+#else
+	return RCAR_COLD_BOOT;
+#endif
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+	u_register_t *boot_kind = (void *) BOOT_KIND_BASE;
+	bl_mem_params_node_t *bl_mem_params;
+
+	if (image_id != BL31_IMAGE_ID)
+		return 0;
+
+	bl_mem_params = get_bl_mem_params_node(image_id);
+
+	if (is_ddr_backup_mode() == RCAR_COLD_BOOT)
+		goto cold_boot;
+
+	*boot_kind  = RCAR_WARM_BOOT;
+	flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+
+	console_flush();
+	bl2_plat_flush_bl31_params();
+
+	/* will not return */
+	bl2_enter_bl31(&bl_mem_params->ep_info);
+
+cold_boot:
+	*boot_kind  = RCAR_COLD_BOOT;
+	flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+
+	return 0;
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	static bl2_to_bl31_params_mem_t *params;
+	bl_mem_params_node_t *bl_mem_params;
+
+	if (!params) {
+		params = (bl2_to_bl31_params_mem_t *) PARAMS_BASE;
+		memset((void *)PARAMS_BASE, 0, sizeof(*params));
+	}
+
+	bl_mem_params = get_bl_mem_params_node(image_id);
+
+	switch (image_id) {
+	case BL31_IMAGE_ID:
+		break;
+	case BL32_IMAGE_ID:
+		memcpy(&params->bl32_ep_info, &bl_mem_params->ep_info,
+			sizeof(entry_point_info_t));
+		break;
+	case BL33_IMAGE_ID:
+		memcpy(&params->bl33_ep_info, &bl_mem_params->ep_info,
+			sizeof(entry_point_info_t));
+		break;
+	}
+
+	return 0;
+}
+
+struct meminfo *bl2_plat_sec_mem_layout(void)
+{
+	return &bl2_tzram_layout;
+}
+
+static void bl2_populate_compatible_string(void *fdt)
+{
+	uint32_t board_type;
+	uint32_t board_rev;
+	uint32_t reg;
+	int ret;
+
+	/* Populate compatible string */
+	rcar_get_board_type(&board_type, &board_rev);
+	switch (board_type) {
+	case BOARD_SALVATOR_X:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,salvator-x");
+		break;
+	case BOARD_SALVATOR_XS:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,salvator-xs");
+		break;
+	case BOARD_STARTER_KIT:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,m3ulcb");
+		break;
+	case BOARD_STARTER_KIT_PRE:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,h3ulcb");
+		break;
+	case BOARD_EAGLE:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,eagle");
+		break;
+	case BOARD_EBISU:
+	case BOARD_EBISU_4D:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,ebisu");
+		break;
+	case BOARD_DRAAK:
+		ret = fdt_setprop_string(fdt, 0, "compatible",
+					 "renesas,draak");
+		break;
+	default:
+		NOTICE("BL2: Cannot set compatible string, board unsupported\n");
+		panic();
+	}
+
+	if (ret < 0) {
+		NOTICE("BL2: Cannot set compatible string (ret=%i)\n", ret);
+		panic();
+	}
+
+	reg = mmio_read_32(RCAR_PRR);
+	switch (reg & RCAR_PRODUCT_MASK) {
+	case RCAR_PRODUCT_H3:
+		ret = fdt_appendprop_string(fdt, 0, "compatible",
+					    "renesas,r8a7795");
+		break;
+	case RCAR_PRODUCT_M3:
+		ret = fdt_appendprop_string(fdt, 0, "compatible",
+					    "renesas,r8a7796");
+		break;
+	case RCAR_PRODUCT_M3N:
+		ret = fdt_appendprop_string(fdt, 0, "compatible",
+					    "renesas,r8a77965");
+		break;
+	case RCAR_PRODUCT_V3M:
+		ret = fdt_appendprop_string(fdt, 0, "compatible",
+					    "renesas,r8a77970");
+		break;
+	case RCAR_PRODUCT_E3:
+		ret = fdt_appendprop_string(fdt, 0, "compatible",
+					    "renesas,r8a77990");
+		break;
+	case RCAR_PRODUCT_D3:
+		ret = fdt_appendprop_string(fdt, 0, "compatible",
+					    "renesas,r8a77995");
+		break;
+	default:
+		NOTICE("BL2: Cannot set compatible string, SoC unsupported\n");
+		panic();
+	}
+
+	if (ret < 0) {
+		NOTICE("BL2: Cannot set compatible string (ret=%i)\n", ret);
+		panic();
+	}
+}
+
+static void bl2_advertise_dram_entries(uint64_t dram_config[8])
+{
+	char nodename[32] = { 0 };
+	uint64_t start, size;
+	uint64_t fdtsize;
+	int ret, node, chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		start = dram_config[2 * chan];
+		size = dram_config[2 * chan + 1];
+		if (!size)
+			continue;
+
+		NOTICE("BL2: CH%d: %llx - %llx, %lld %siB\n",
+			chan, start, start + size - 1,
+			(size >> 30) ? : size >> 20,
+			(size >> 30) ? "G" : "M");
+	}
+
+	/*
+	 * We add the DT nodes in reverse order here. The fdt_add_subnode()
+	 * adds the DT node before the first existing DT node, so we have
+	 * to add them in reverse order to get nodes sorted by address in
+	 * the resulting DT.
+	 */
+	for (chan = 3; chan >= 0; chan--) {
+		start = dram_config[2 * chan];
+		size = dram_config[2 * chan + 1];
+		if (!size)
+			continue;
+
+		/*
+		 * Channel 0 is mapped in 32bit space and the first
+		 * 128 MiB are reserved
+		 */
+		if (chan == 0) {
+			start = 0x48000000;
+			size -= 0x8000000;
+		}
+
+		fdtsize = cpu_to_fdt64(size);
+
+		snprintf(nodename, sizeof(nodename), "memory@");
+		unsigned_num_print(start, 16, nodename + strlen(nodename));
+		node = ret = fdt_add_subnode(fdt, 0, nodename);
+		if (ret < 0)
+			goto err;
+
+		ret = fdt_setprop_string(fdt, node, "device_type", "memory");
+		if (ret < 0)
+			goto err;
+
+		ret = fdt_setprop_u64(fdt, node, "reg", start);
+		if (ret < 0)
+			goto err;
+
+		ret = fdt_appendprop(fdt, node, "reg", &fdtsize,
+				     sizeof(fdtsize));
+		if (ret < 0)
+			goto err;
+	}
+
+	return;
+err:
+	NOTICE("BL2: Cannot add memory node to FDT (ret=%i)\n", ret);
+	panic();
+}
+
+static void bl2_advertise_dram_size(uint32_t product)
+{
+	uint64_t dram_config[8] = {
+		[0] = 0x400000000ULL,
+		[2] = 0x500000000ULL,
+		[4] = 0x600000000ULL,
+		[6] = 0x700000000ULL,
+	};
+
+	switch (product) {
+	case RCAR_PRODUCT_H3:
+#if (RCAR_DRAM_LPDDR4_MEMCONF == 0)
+		/* 4GB(1GBx4) */
+		dram_config[1] = 0x40000000ULL;
+		dram_config[3] = 0x40000000ULL;
+		dram_config[5] = 0x40000000ULL;
+		dram_config[7] = 0x40000000ULL;
+#elif (RCAR_DRAM_LPDDR4_MEMCONF == 1) && \
+      (RCAR_DRAM_CHANNEL        == 5) && \
+      (RCAR_DRAM_SPLIT          == 2)
+		/* 4GB(2GBx2 2ch split) */
+		dram_config[1] = 0x80000000ULL;
+		dram_config[3] = 0x80000000ULL;
+#elif (RCAR_DRAM_LPDDR4_MEMCONF == 1) && (RCAR_DRAM_CHANNEL == 15)
+		/* 8GB(2GBx4: default) */
+		dram_config[1] = 0x80000000ULL;
+		dram_config[3] = 0x80000000ULL;
+		dram_config[5] = 0x80000000ULL;
+		dram_config[7] = 0x80000000ULL;
+#endif /* RCAR_DRAM_LPDDR4_MEMCONF == 0 */
+		break;
+
+	case RCAR_PRODUCT_M3:
+#if (RCAR_GEN3_ULCB == 1)
+		/* 2GB(1GBx2 2ch split) */
+		dram_config[1] = 0x40000000ULL;
+		dram_config[5] = 0x40000000ULL;
+#else
+		/* 4GB(2GBx2 2ch split) */
+		dram_config[1] = 0x80000000ULL;
+		dram_config[5] = 0x80000000ULL;
+#endif
+		break;
+
+	case RCAR_PRODUCT_M3N:
+		/* 2GB(1GBx2) */
+		dram_config[1] = 0x80000000ULL;
+		break;
+
+	case RCAR_PRODUCT_V3M:
+		/* 1GB(512MBx2) */
+		dram_config[1] = 0x40000000ULL;
+		break;
+
+	case RCAR_PRODUCT_E3:
+#if (RCAR_DRAM_DDR3L_MEMCONF == 0)
+		/* 1GB(512MBx2) */
+		dram_config[1] = 0x40000000ULL;
+#elif (RCAR_DRAM_DDR3L_MEMCONF == 1)
+		/* 2GB(512MBx4) */
+		dram_config[1] = 0x80000000ULL;
+#elif (RCAR_DRAM_DDR3L_MEMCONF == 2)
+		/* 4GB(1GBx4) */
+		dram_config[1] = 0x100000000ULL;
+#endif /* RCAR_DRAM_DDR3L_MEMCONF == 0 */
+		break;
+
+	case RCAR_PRODUCT_D3:
+		/* 512MB */
+		dram_config[1] = 0x20000000ULL;
+		break;
+	}
+
+	bl2_advertise_dram_entries(dram_config);
+}
+
+void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2,
+				  u_register_t arg3, u_register_t arg4)
+{
+	uint32_t reg, midr, lcs, boot_dev, boot_cpu, sscg, type, rev;
+	uint32_t product, product_cut, major, minor;
+	int32_t ret;
+	const char *str;
+	const char *unknown = "unknown";
+	const char *cpu_ca57 = "CA57";
+	const char *cpu_ca53 = "CA53";
+	const char *product_m3n = "M3N";
+	const char *product_h3 = "H3";
+	const char *product_m3 = "M3";
+	const char *product_e3 = "E3";
+	const char *product_d3 = "D3";
+	const char *product_v3m = "V3M";
+	const char *lcs_secure = "SE";
+	const char *lcs_cm = "CM";
+	const char *lcs_dm = "DM";
+	const char *lcs_sd = "SD";
+	const char *lcs_fa = "FA";
+	const char *sscg_off = "PLL1 nonSSCG Clock select";
+	const char *sscg_on = "PLL1 SSCG Clock select";
+	const char *boot_hyper80 = "HyperFlash(80MHz)";
+	const char *boot_qspi40 = "QSPI Flash(40MHz)";
+	const char *boot_qspi80 = "QSPI Flash(80MHz)";
+	const char *boot_emmc25x1 = "eMMC(25MHz x1)";
+	const char *boot_emmc50x8 = "eMMC(50MHz x8)";
+#if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3)
+	const char *boot_hyper160 = "HyperFlash(150MHz)";
+#else
+	const char *boot_hyper160 = "HyperFlash(160MHz)";
+#endif
+#if (RCAR_LOSSY_ENABLE == 1)
+	int fcnlnode;
+#endif
+
+	bl2_init_generic_timer();
+
+	reg = mmio_read_32(RCAR_MODEMR);
+	boot_dev = reg & MODEMR_BOOT_DEV_MASK;
+	boot_cpu = reg & MODEMR_BOOT_CPU_MASK;
+
+	bl2_cpg_init();
+
+	if (boot_cpu == MODEMR_BOOT_CPU_CA57 ||
+	    boot_cpu == MODEMR_BOOT_CPU_CA53) {
+		rcar_pfc_init();
+		rcar_console_boot_init();
+	}
+
+	plat_rcar_gic_driver_init();
+	plat_rcar_gic_init();
+	rcar_swdt_init();
+
+	/* FIQ interrupts are taken to EL3 */
+	write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+
+	write_daifclr(DAIF_FIQ_BIT);
+
+	reg = read_midr();
+	midr = reg & (MIDR_PN_MASK << MIDR_PN_SHIFT);
+	switch (midr) {
+	case MIDR_CA57:
+		str = cpu_ca57;
+		break;
+	case MIDR_CA53:
+		str = cpu_ca53;
+		break;
+	default:
+		str = unknown;
+		break;
+	}
+
+	NOTICE("BL2: R-Car Gen3 Initial Program Loader(%s) Rev.%s\n", str,
+	       version_of_renesas);
+
+	reg = mmio_read_32(RCAR_PRR);
+	product_cut = reg & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	product = reg & RCAR_PRODUCT_MASK;
+
+	switch (product) {
+	case RCAR_PRODUCT_H3:
+		str = product_h3;
+		break;
+	case RCAR_PRODUCT_M3:
+		str = product_m3;
+		break;
+	case RCAR_PRODUCT_M3N:
+		str = product_m3n;
+		break;
+	case RCAR_PRODUCT_V3M:
+		str = product_v3m;
+		break;
+	case RCAR_PRODUCT_E3:
+		str = product_e3;
+		break;
+	case RCAR_PRODUCT_D3:
+		str = product_d3;
+		break;
+	default:
+		str = unknown;
+		break;
+	}
+
+	if ((RCAR_PRODUCT_M3 == product) &&
+	    (RCAR_CUT_VER20 == (reg & RCAR_MAJOR_MASK))) {
+		if (RCAR_M3_CUT_VER11 == (reg & RCAR_CUT_MASK)) {
+			/* M3 Ver.1.1 or Ver.1.2 */
+			NOTICE("BL2: PRR is R-Car %s Ver.1.1 / Ver.1.2\n",
+				str);
+		} else {
+			NOTICE("BL2: PRR is R-Car %s Ver.1.%d\n",
+				str,
+				(reg & RCAR_MINOR_MASK) + RCAR_M3_MINOR_OFFSET);
+		}
+	} else {
+		major = (reg & RCAR_MAJOR_MASK) >> RCAR_MAJOR_SHIFT;
+		major = major + RCAR_MAJOR_OFFSET;
+		minor = reg & RCAR_MINOR_MASK;
+		NOTICE("BL2: PRR is R-Car %s Ver.%d.%d\n", str, major, minor);
+	}
+
+	if (product == RCAR_PRODUCT_E3) {
+		reg = mmio_read_32(RCAR_MODEMR);
+		sscg = reg & RCAR_SSCG_MASK;
+		str = sscg == RCAR_SSCG_ENABLE ? sscg_on : sscg_off;
+		NOTICE("BL2: %s\n", str);
+	}
+
+	rcar_get_board_type(&type, &rev);
+
+	switch (type) {
+	case BOARD_SALVATOR_X:
+	case BOARD_KRIEK:
+	case BOARD_STARTER_KIT:
+	case BOARD_SALVATOR_XS:
+	case BOARD_EBISU:
+	case BOARD_STARTER_KIT_PRE:
+	case BOARD_EBISU_4D:
+	case BOARD_DRAAK:
+	case BOARD_EAGLE:
+		break;
+	default:
+		type = BOARD_UNKNOWN;
+		break;
+	}
+
+	if (type == BOARD_UNKNOWN || rev == BOARD_REV_UNKNOWN)
+		NOTICE("BL2: Board is %s Rev.---\n", GET_BOARD_NAME(type));
+	else {
+		NOTICE("BL2: Board is %s Rev.%d.%d\n",
+		       GET_BOARD_NAME(type),
+		       GET_BOARD_MAJOR(rev), GET_BOARD_MINOR(rev));
+	}
+
+#if RCAR_LSI != RCAR_AUTO
+	if (product != TARGET_PRODUCT) {
+		ERROR("BL2: IPL was been built for the %s.\n", TARGET_NAME);
+		ERROR("BL2: Please write the correct IPL to flash memory.\n");
+		panic();
+	}
+#endif
+	rcar_avs_init();
+	rcar_avs_setting();
+
+	switch (boot_dev) {
+	case MODEMR_BOOT_DEV_HYPERFLASH160:
+		str = boot_hyper160;
+		break;
+	case MODEMR_BOOT_DEV_HYPERFLASH80:
+		str = boot_hyper80;
+		break;
+	case MODEMR_BOOT_DEV_QSPI_FLASH40:
+		str = boot_qspi40;
+		break;
+	case MODEMR_BOOT_DEV_QSPI_FLASH80:
+		str = boot_qspi80;
+		break;
+	case MODEMR_BOOT_DEV_EMMC_25X1:
+#if RCAR_LSI == RCAR_D3
+		ERROR("BL2: Failed to Initialize. eMMC is not supported.\n");
+		panic();
+#endif
+		str = boot_emmc25x1;
+		break;
+	case MODEMR_BOOT_DEV_EMMC_50X8:
+#if RCAR_LSI == RCAR_D3
+		ERROR("BL2: Failed to Initialize. eMMC is not supported.\n");
+		panic();
+#endif
+		str = boot_emmc50x8;
+		break;
+	default:
+		str = unknown;
+		break;
+	}
+	NOTICE("BL2: Boot device is %s\n", str);
+
+	rcar_avs_setting();
+	reg = rcar_rom_get_lcs(&lcs);
+	if (reg) {
+		str = unknown;
+		goto lcm_state;
+	}
+
+	switch (lcs) {
+	case LCS_CM:
+		str = lcs_cm;
+		break;
+	case LCS_DM:
+		str = lcs_dm;
+		break;
+	case LCS_SD:
+		str = lcs_sd;
+		break;
+	case LCS_SE:
+		str = lcs_secure;
+		break;
+	case LCS_FA:
+		str = lcs_fa;
+		break;
+	default:
+		str = unknown;
+		break;
+	}
+
+lcm_state:
+	NOTICE("BL2: LCM state is %s\n", str);
+
+	rcar_avs_end();
+	is_ddr_backup_mode();
+
+	bl2_tzram_layout.total_base = BL31_BASE;
+	bl2_tzram_layout.total_size = BL31_LIMIT - BL31_BASE;
+
+	if (boot_cpu == MODEMR_BOOT_CPU_CA57 ||
+	    boot_cpu == MODEMR_BOOT_CPU_CA53) {
+		ret = rcar_dram_init();
+		if (ret) {
+			NOTICE("BL2: Failed to DRAM initialize (%d).\n", ret);
+			panic();
+		}
+		rcar_qos_init();
+	}
+
+	/* Set up FDT */
+	ret = fdt_create_empty_tree(fdt, sizeof(fdt_blob));
+	if (ret) {
+		NOTICE("BL2: Cannot allocate FDT for U-Boot (ret=%i)\n", ret);
+		panic();
+	}
+
+	/* Add platform compatible string */
+	bl2_populate_compatible_string(fdt);
+
+	/* Print DRAM layout */
+	bl2_advertise_dram_size(product);
+
+	if (boot_dev == MODEMR_BOOT_DEV_EMMC_25X1 ||
+	    boot_dev == MODEMR_BOOT_DEV_EMMC_50X8) {
+		if (rcar_emmc_init() != EMMC_SUCCESS) {
+			NOTICE("BL2: Failed to eMMC driver initialize.\n");
+			panic();
+		}
+		rcar_emmc_memcard_power(EMMC_POWER_ON);
+		if (rcar_emmc_mount() != EMMC_SUCCESS) {
+			NOTICE("BL2: Failed to eMMC mount operation.\n");
+			panic();
+		}
+	} else {
+		rcar_rpc_init();
+		rcar_dma_init();
+	}
+
+	reg = mmio_read_32(RST_WDTRSTCR);
+	reg &= ~WDTRSTCR_RWDT_RSTMSK;
+	reg |= WDTRSTCR_PASSWORD;
+	mmio_write_32(RST_WDTRSTCR, reg);
+
+	mmio_write_32(CPG_CPGWPR, CPGWPR_PASSWORD);
+	mmio_write_32(CPG_CPGWPCR, CPGWPCR_PASSWORD);
+
+	reg = mmio_read_32(RCAR_PRR);
+	if ((reg & RCAR_CPU_MASK_CA57) == RCAR_CPU_HAVE_CA57)
+		mmio_write_32(CPG_CA57DBGRCR,
+			      DBGCPUPREN | mmio_read_32(CPG_CA57DBGRCR));
+
+	if ((reg & RCAR_CPU_MASK_CA53) == RCAR_CPU_HAVE_CA53)
+		mmio_write_32(CPG_CA53DBGRCR,
+			      DBGCPUPREN | mmio_read_32(CPG_CA53DBGRCR));
+
+	if (product_cut == RCAR_PRODUCT_H3_CUT10) {
+		reg = mmio_read_32(CPG_PLL2CR);
+		reg &= ~((uint32_t) 1 << 5);
+		mmio_write_32(CPG_PLL2CR, reg);
+
+		reg = mmio_read_32(CPG_PLL4CR);
+		reg &= ~((uint32_t) 1 << 5);
+		mmio_write_32(CPG_PLL4CR, reg);
+
+		reg = mmio_read_32(CPG_PLL0CR);
+		reg &= ~((uint32_t) 1 << 12);
+		mmio_write_32(CPG_PLL0CR, reg);
+	}
+#if (RCAR_LOSSY_ENABLE == 1)
+	NOTICE("BL2: Lossy Decomp areas\n");
+
+	fcnlnode = fdt_add_subnode(fdt, 0, "reserved-memory");
+	if (fcnlnode < 0) {
+		NOTICE("BL2: Cannot create reserved mem node (ret=%i)\n",
+			fcnlnode);
+		panic();
+	}
+
+	bl2_lossy_setting(0, LOSSY_ST_ADDR0, LOSSY_END_ADDR0,
+			  LOSSY_FMT0, LOSSY_ENA_DIS0, fcnlnode);
+	bl2_lossy_setting(1, LOSSY_ST_ADDR1, LOSSY_END_ADDR1,
+			  LOSSY_FMT1, LOSSY_ENA_DIS1, fcnlnode);
+	bl2_lossy_setting(2, LOSSY_ST_ADDR2, LOSSY_END_ADDR2,
+			  LOSSY_FMT2, LOSSY_ENA_DIS2, fcnlnode);
+#endif
+
+	fdt_pack(fdt);
+	NOTICE("BL2: FDT at %p\n", fdt);
+
+	if (boot_dev == MODEMR_BOOT_DEV_EMMC_25X1 ||
+	    boot_dev == MODEMR_BOOT_DEV_EMMC_50X8)
+		rcar_io_emmc_setup();
+	else
+		rcar_io_setup();
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+#if RCAR_BL2_DCACHE == 1
+	NOTICE("BL2: D-Cache enable\n");
+	rcar_configure_mmu_el3(BL2_BASE,
+			       BL2_END - BL2_BASE,
+			       BL2_RO_BASE, BL2_RO_LIMIT
+#if USE_COHERENT_MEM
+			       , BL2_COHERENT_RAM_BASE, BL2_COHERENT_RAM_LIMIT
+#endif
+	    );
+#endif
+}
+
+void bl2_platform_setup(void)
+{
+
+}
+
+static void bl2_init_generic_timer(void)
+{
+/* FIXME: V3M 16.666 MHz ? */
+#if RCAR_LSI == RCAR_D3
+	uint32_t reg_cntfid = EXTAL_DRAAK;
+#elif RCAR_LSI == RCAR_E3
+	uint32_t reg_cntfid = EXTAL_EBISU;
+#else /* RCAR_LSI == RCAR_E3 */
+	uint32_t reg;
+	uint32_t reg_cntfid;
+	uint32_t modemr;
+	uint32_t modemr_pll;
+	uint32_t board_type;
+	uint32_t board_rev;
+	uint32_t pll_table[] = {
+		EXTAL_MD14_MD13_TYPE_0,	/* MD14/MD13 : 0b00 */
+		EXTAL_MD14_MD13_TYPE_1,	/* MD14/MD13 : 0b01 */
+		EXTAL_MD14_MD13_TYPE_2,	/* MD14/MD13 : 0b10 */
+		EXTAL_MD14_MD13_TYPE_3	/* MD14/MD13 : 0b11 */
+	};
+
+	modemr = mmio_read_32(RCAR_MODEMR);
+	modemr_pll = (modemr & MODEMR_BOOT_PLL_MASK);
+
+	/* Set frequency data in CNTFID0 */
+	reg_cntfid = pll_table[modemr_pll >> MODEMR_BOOT_PLL_SHIFT];
+	reg = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+	switch (modemr_pll) {
+	case MD14_MD13_TYPE_0:
+		rcar_get_board_type(&board_type, &board_rev);
+		if (BOARD_SALVATOR_XS == board_type) {
+			reg_cntfid = EXTAL_SALVATOR_XS;
+		}
+		break;
+	case MD14_MD13_TYPE_3:
+		if (RCAR_PRODUCT_H3_CUT10 == reg) {
+			reg_cntfid = reg_cntfid >> 1U;
+		}
+		break;
+	default:
+		/* none */
+		break;
+	}
+#endif /* RCAR_LSI == RCAR_E3 */
+	/* Update memory mapped and register based freqency */
+	write_cntfrq_el0((u_register_t )reg_cntfid);
+	mmio_write_32(ARM_SYS_CNTCTL_BASE + (uintptr_t)CNTFID_OFF, reg_cntfid);
+	/* Enable counter */
+	mmio_setbits_32(RCAR_CNTC_BASE + (uintptr_t)CNTCR_OFF,
+			(uint32_t)CNTCR_EN);
+}
diff --git a/plat/renesas/rcar/bl2_secure_setting.c b/plat/renesas/rcar/bl2_secure_setting.c
new file mode 100644
index 0000000..7473df5
--- /dev/null
+++ b/plat/renesas/rcar/bl2_secure_setting.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "axi_registers.h"
+#include "lifec_registers.h"
+#include "micro_delay.h"
+
+static void lifec_security_setting(void);
+static void axi_security_setting(void);
+
+static const struct {
+	uint32_t reg;
+	uint32_t val;
+} lifec[] = {
+	/** LIFEC0 (SECURITY) settings					*/
+	/* Security attribute setting for master ports                  */
+	/* Bit 0: ARM realtime core (Cortex-R7) master port             */
+	/*       0: Non-Secure                                          */
+	{
+	SEC_SRC, 0x0000001EU},
+	/** Security attribute setting for slave ports 0 to 15		*/
+	    /*      {SEC_SEL0,              0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL1,              0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL2,              0xFFFFFFFFU},                   */
+	    /* Bit19: AXI-Bus (Main Memory domain AXI) slave ports          */
+	    /*        0: registers accessed from secure resource only       */
+	    /* Bit 9: DBSC4 register access slave ports.                    */
+	    /*        0: registers accessed from secure resource only.      */
+#if (LIFEC_DBSC_PROTECT_ENABLE == 1)
+	{
+	SEC_SEL3, 0xFFF7FDFFU},
+#else
+	{
+	SEC_SEL3, 0xFFFFFFFFU},
+#endif
+	    /*      {SEC_SEL4,              0xFFFFFFFFU},                   */
+	    /* Bit 6: Boot ROM slave ports.                                 */
+	    /*        0: registers accessed from secure resource only       */
+	{
+	SEC_SEL5, 0xFFFFFFBFU},
+	    /* Bit13: SCEG PKA (secure APB) slave ports                     */
+	    /*        0: registers accessed from secure resource only       */
+	    /*        1: Reserved[R-Car E3]                                 */
+	    /* Bit12: SCEG PKA (public APB) slave ports                     */
+	    /*        0: registers accessed from secure resource only       */
+	    /*        1: Reserved[R-Car E3]                                 */
+	    /* Bit10: SCEG Secure Core slave ports                          */
+	    /*        0: registers accessed from secure resource only       */
+#if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3)
+	{
+	SEC_SEL6, 0xFFFFFBFFU},
+#else
+	{
+	SEC_SEL6, 0xFFFFCBFFU},
+#endif
+	    /*      {SEC_SEL7,              0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL8,              0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL9,              0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL10,             0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL11,             0xFFFFFFFFU},                   */
+	    /*      {SEC_SEL12,             0xFFFFFFFFU},                   */
+	    /* Bit22: RPC slave ports.                                      */
+	    /*        0: registers accessed from secure resource only.      */
+#if (RCAR_RPC_HYPERFLASH_LOCKED == 1)
+	    {SEC_SEL13,          0xFFBFFFFFU},
+#endif
+	    /* Bit27: System Timer (SCMT) slave ports                       */
+	    /*        0: registers accessed from secure resource only       */
+	    /* Bit26: System Watchdog Timer (SWDT) slave ports              */
+	    /*        0: registers accessed from secure resource only       */
+	{
+	SEC_SEL14, 0xF3FFFFFFU},
+	    /* Bit13: RST slave ports. */
+	    /*        0: registers accessed from secure resource only       */
+	    /* Bit 7: Life Cycle 0 slave ports                              */
+	    /*        0: registers accessed from secure resource only       */
+	{
+	SEC_SEL15, 0xFFFFFF3FU},
+	/** Security group 0 attribute setting for master ports 0	*/
+	/** Security group 1 attribute setting for master ports 0	*/
+	    /*      {SEC_GRP0CR0,           0x00000000U},                   */
+	    /*      {SEC_GRP1CR0,           0x00000000U},                   */
+	/** Security group 0 attribute setting for master ports 1	*/
+	/** Security group 1 attribute setting for master ports 1	*/
+	    /*      {SEC_GRP0CR1,           0x00000000U},                   */
+	    /*      {SEC_GRP1CR1,           0x00000000U},                   */
+	/** Security group 0 attribute setting for master ports 2 	*/
+	/** Security group 1 attribute setting for master ports 2 	*/
+	    /* Bit17: SCEG Secure Core master ports.                        */
+	    /*        SecurityGroup3                                        */
+	{
+	SEC_GRP0CR2, 0x00020000U}, {
+	SEC_GRP1CR2, 0x00020000U},
+	/** Security group 0 attribute setting for master ports 3 	*/
+	/** Security group 1 attribute setting for master ports 3 	*/
+	    /*      {SEC_GRP0CR3,           0x00000000U},                   */
+	    /*      {SEC_GRP1CR3,           0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 0 	*/
+	/** Security group 1 attribute setting for slave ports 0 	*/
+	    /*      {SEC_GRP0COND0,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND0,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 1 	*/
+	/** Security group 1 attribute setting for slave ports 1 	*/
+	    /*      {SEC_GRP0COND1,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND1,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 2 	*/
+	/** Security group 1 attribute setting for slave ports 2 	*/
+	    /*      {SEC_GRP0COND2,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND2,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 3	*/
+	/** Security group 1 attribute setting for slave ports 3	*/
+	    /* Bit19: AXI-Bus (Main Memory domain AXI) slave ports.         */
+	    /*        SecurityGroup3                                        */
+	    /* Bit 9: DBSC4 register access slave ports.                    */
+	    /*        SecurityGroup3                                        */
+#if (LIFEC_DBSC_PROTECT_ENABLE == 1)
+	{
+	SEC_GRP0COND3, 0x00080200U}, {
+	SEC_GRP1COND3, 0x00080200U},
+#else
+	{
+	SEC_GRP0COND3, 0x00000000U}, {
+	SEC_GRP1COND3, 0x00000000U},
+#endif
+	/** Security group 0 attribute setting for slave ports 4	*/
+	/** Security group 1 attribute setting for slave ports 4	*/
+	    /*      {SEC_GRP0COND4,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND4,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 5	*/
+	/** Security group 1 attribute setting for slave ports 5	*/
+	    /* Bit 6: Boot ROM slave ports                                  */
+	    /*        SecurityGroup3                                        */
+	{
+	SEC_GRP0COND5, 0x00000040U}, {
+	SEC_GRP1COND5, 0x00000040U},
+	/** Security group 0 attribute setting for slave ports 6	*/
+	/** Security group 1 attribute setting for slave ports 6	*/
+	    /* Bit13: SCEG PKA (secure APB) slave ports                     */
+	    /*        SecurityGroup3                                        */
+	    /*        Reserved[R-Car E3]                                    */
+	    /* Bit12: SCEG PKA (public APB) slave ports                     */
+	    /*        SecurityGroup3                                        */
+	    /*        Reserved[R-Car E3]                                    */
+	    /* Bit10: SCEG Secure Core slave ports                          */
+	    /*        SecurityGroup3                                        */
+#if RCAR_LSI == RCAR_E3
+	{
+	SEC_GRP0COND6, 0x00000400U}, {
+	SEC_GRP1COND6, 0x00000400U},
+#else
+	{
+	SEC_GRP0COND6, 0x00003400U}, {
+	SEC_GRP1COND6, 0x00003400U},
+#endif
+	/** Security group 0 attribute setting for slave ports 7	*/
+	/** Security group 1 attribute setting for slave ports 7	*/
+	    /*      {SEC_GRP0COND7,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND7,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 8	*/
+	/** Security group 1 attribute setting for slave ports 8	*/
+	    /*      {SEC_GRP0COND8,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND8,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 9	*/
+	/** Security group 1 attribute setting for slave ports 9	*/
+	    /*      {SEC_GRP0COND9,         0x00000000U},                   */
+	    /*      {SEC_GRP1COND9,         0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 10	*/
+	/** Security group 1 attribute setting for slave ports 10	*/
+	    /*      {SEC_GRP0COND10,        0x00000000U},                   */
+	    /*      {SEC_GRP1COND10,        0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 11	*/
+	/** Security group 1 attribute setting for slave ports 11	*/
+	    /*      {SEC_GRP0COND11,        0x00000000U},                   */
+	    /*      {SEC_GRP1COND11,        0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 12	*/
+	/** Security group 1 attribute setting for slave ports 12	*/
+	    /*      {SEC_GRP0COND12,        0x00000000U},                   */
+	    /*      {SEC_GRP1COND12,        0x00000000U},                   */
+	/** Security group 0 attribute setting for slave ports 13	*/
+	/** Security group 1 attribute setting for slave ports 13	*/
+	    /* Bit22: RPC slave ports.                                      */
+	    /*        SecurityGroup3                                        */
+#if (RCAR_RPC_HYPERFLASH_LOCKED == 1)
+	    {SEC_GRP0COND13,     0x00400000U},
+	    {SEC_GRP1COND13,     0x00400000U},
+#endif
+	/** Security group 0 attribute setting for slave ports 14	*/
+	/** Security group 1 attribute setting for slave ports 14	*/
+	    /* Bit26: System Timer (SCMT) slave ports                       */
+	    /*        SecurityGroup3                                        */
+	    /* Bit27: System Watchdog Timer (SWDT) slave ports              */
+	    /*        SecurityGroup3                                        */
+	{
+	SEC_GRP0COND14, 0x0C000000U}, {
+	SEC_GRP1COND14, 0x0C000000U},
+	/** Security group 0 attribute setting for slave ports 15	*/
+	/** Security group 1 attribute setting for slave ports 15 	*/
+	    /* Bit13: RST slave ports                                       */
+	    /*        SecurityGroup3                                        */
+	    /* Bit 7: Life Cycle 0 slave ports                              */
+	    /*        SecurityGroup3                                        */
+	    /* Bit 6: TDBG slave ports                                      */
+	    /*        SecurityGroup3                                        */
+	{
+	SEC_GRP0COND15, 0x000000C0U}, {
+	SEC_GRP1COND15, 0x000000C0U},
+	/** Security write protection attribute setting slave ports 0	*/
+	    /*      {SEC_READONLY0,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 1	*/
+	    /*      {SEC_READONLY1,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 2	*/
+	    /*      {SEC_READONLY2,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 3	*/
+	    /*      {SEC_READONLY3,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 4	*/
+	    /*      {SEC_READONLY4,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 5	*/
+	    /*      {SEC_READONLY5,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 6	*/
+	    /*      {SEC_READONLY6,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 7	*/
+	    /*      {SEC_READONLY7,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 8	*/
+	    /*      {SEC_READONLY8,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 9	*/
+	    /*      {SEC_READONLY9,         0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 10	*/
+	    /*      {SEC_READONLY10,        0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 11	*/
+	    /*      {SEC_READONLY11,        0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 12	*/
+	    /*      {SEC_READONLY12,        0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 13	*/
+	    /*      {SEC_READONLY13,        0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 14	*/
+	    /*      {SEC_READONLY14,        0x00000000U},                   */
+	/** Security write protection attribute setting slave ports 15	*/
+	    /*      {SEC_READONLY15,        0x00000000U}                    */
+};
+
+/* AXI settings */
+static const struct {
+	uint32_t reg;
+	uint32_t val;
+} axi[] = {
+	/* DRAM protection                      */
+	/* AXI dram protected area division     */
+	{
+	AXI_DPTDIVCR0,  0x0E0403F0U}, {
+	AXI_DPTDIVCR1,  0x0E0407E0U}, {
+	AXI_DPTDIVCR2,  0x0E080000U}, {
+	AXI_DPTDIVCR3,  0x0E080000U}, {
+	AXI_DPTDIVCR4,  0x0E080000U}, {
+	AXI_DPTDIVCR5,  0x0E080000U}, {
+	AXI_DPTDIVCR6,  0x0E080000U}, {
+	AXI_DPTDIVCR7,  0x0E080000U}, {
+	AXI_DPTDIVCR8,  0x0E080000U}, {
+	AXI_DPTDIVCR9,  0x0E080000U}, {
+	AXI_DPTDIVCR10, 0x0E080000U}, {
+	AXI_DPTDIVCR11, 0x0E080000U}, {
+	AXI_DPTDIVCR12, 0x0E080000U}, {
+	AXI_DPTDIVCR13, 0x0E080000U}, {
+	AXI_DPTDIVCR14, 0x0E080000U},
+	    /* AXI dram protected area setting      */
+	{
+	AXI_DPTCR0,  0x0E000000U}, {
+	AXI_DPTCR1,  0x0E000E0EU}, {
+	AXI_DPTCR2,  0x0E000000U}, {
+	AXI_DPTCR3,  0x0E000000U}, {
+	AXI_DPTCR4,  0x0E000000U}, {
+	AXI_DPTCR5,  0x0E000000U}, {
+	AXI_DPTCR6,  0x0E000000U}, {
+	AXI_DPTCR7,  0x0E000000U}, {
+	AXI_DPTCR8,  0x0E000000U}, {
+	AXI_DPTCR9,  0x0E000000U}, {
+	AXI_DPTCR10, 0x0E000000U}, {
+	AXI_DPTCR11, 0x0E000000U}, {
+	AXI_DPTCR12, 0x0E000000U}, {
+	AXI_DPTCR13, 0x0E000000U}, {
+	AXI_DPTCR14, 0x0E000000U}, {
+	AXI_DPTCR15, 0x0E000000U},
+	    /* SRAM ptotection                      */
+	    /* AXI sram protected area division     */
+	{
+	AXI_SPTDIVCR0,  0x0E0E6304U}, {
+	AXI_SPTDIVCR1,  0x0E0E6360U}, {
+	AXI_SPTDIVCR2,  0x0E0E6360U}, {
+	AXI_SPTDIVCR3,  0x0E0E6360U}, {
+	AXI_SPTDIVCR4,  0x0E0E6360U}, {
+	AXI_SPTDIVCR5,  0x0E0E6360U}, {
+	AXI_SPTDIVCR6,  0x0E0E6360U}, {
+	AXI_SPTDIVCR7,  0x0E0E6360U}, {
+	AXI_SPTDIVCR8,  0x0E0E6360U}, {
+	AXI_SPTDIVCR9,  0x0E0E6360U}, {
+	AXI_SPTDIVCR10, 0x0E0E6360U}, {
+	AXI_SPTDIVCR11, 0x0E0E6360U}, {
+	AXI_SPTDIVCR12, 0x0E0E6360U}, {
+	AXI_SPTDIVCR13, 0x0E0E6360U}, {
+	AXI_SPTDIVCR14, 0x0E0E6360U},
+	    /* AXI sram protected area setting      */
+	{
+	AXI_SPTCR0,  0x0E000E0EU}, {
+	AXI_SPTCR1,  0x0E000000U}, {
+	AXI_SPTCR2,  0x0E000000U}, {
+	AXI_SPTCR3,  0x0E000000U}, {
+	AXI_SPTCR4,  0x0E000000U}, {
+	AXI_SPTCR5,  0x0E000000U}, {
+	AXI_SPTCR6,  0x0E000000U}, {
+	AXI_SPTCR7,  0x0E000000U}, {
+	AXI_SPTCR8,  0x0E000000U}, {
+	AXI_SPTCR9,  0x0E000000U}, {
+	AXI_SPTCR10, 0x0E000000U}, {
+	AXI_SPTCR11, 0x0E000000U}, {
+	AXI_SPTCR12, 0x0E000000U}, {
+	AXI_SPTCR13, 0x0E000000U}, {
+	AXI_SPTCR14, 0x0E000000U}, {
+	AXI_SPTCR15, 0x0E000000U}
+};
+
+static void lifec_security_setting(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(lifec); i++)
+		mmio_write_32(lifec[i].reg, lifec[i].val);
+}
+
+/* SRAM/DRAM protection setting */
+static void axi_security_setting(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(axi); i++)
+		mmio_write_32(axi[i].reg, axi[i].val);
+}
+
+void bl2_secure_setting(void)
+{
+	const uint32_t delay = 10;
+
+	lifec_security_setting();
+	axi_security_setting();
+	rcar_micro_delay(delay);
+
+	return;
+}
diff --git a/plat/renesas/rcar/bl31_plat_setup.c b/plat/renesas/rcar/bl31_plat_setup.c
new file mode 100644
index 0000000..4fff233
--- /dev/null
+++ b/plat/renesas/rcar/bl31_plat_setup.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "pwrc.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "rcar_version.h"
+
+IMPORT_SYM(uint64_t, __RO_START__, BL31_RO_BASE)
+IMPORT_SYM(uint64_t, __RO_END__, BL31_RO_LIMIT)
+
+#if USE_COHERENT_MEM
+IMPORT_SYM(uint64_t, __COHERENT_RAM_START__, BL31_COHERENT_RAM_BASE)
+IMPORT_SYM(uint64_t, __COHERENT_RAM_END__, BL31_COHERENT_RAM_LIMIT)
+#endif
+
+extern void plat_rcar_gic_driver_init(void);
+extern void plat_rcar_gic_init(void);
+
+u_register_t rcar_boot_mpidr;
+
+static int cci_map[] = {
+	CCI500_CLUSTER0_SL_IFACE_IX_FOR_M3,
+	CCI500_CLUSTER1_SL_IFACE_IX_FOR_M3
+};
+
+void plat_cci_init(void)
+{
+	uint32_t prd;
+
+	prd = mmio_read_32(RCAR_PRR) & (RCAR_PRODUCT_MASK | RCAR_CUT_MASK);
+
+	if (RCAR_PRODUCT_H3_CUT10 == prd || RCAR_PRODUCT_H3_CUT11 == prd) {
+		cci_map[0U] = CCI500_CLUSTER0_SL_IFACE_IX;
+		cci_map[1U] = CCI500_CLUSTER1_SL_IFACE_IX;
+	}
+
+	cci_init(RCAR_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+}
+
+void plat_cci_enable(void)
+{
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+void plat_cci_disable(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	bl2_to_bl31_params_mem_t *from_bl2 = (bl2_to_bl31_params_mem_t *)
+					     PARAMS_BASE;
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ?
+		&from_bl2->bl33_ep_info : &from_bl2->bl32_ep_info;
+
+	return next_image_info->pc ? next_image_info : NULL;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	rcar_console_runtime_init();
+
+	NOTICE("BL3-1 : Rev.%s\n", version_of_renesas);
+
+#if RCAR_LSI != RCAR_D3
+	if (RCAR_CLUSTER_A53A57 == rcar_pwrc_get_cluster()) {
+		plat_cci_init();
+		plat_cci_enable();
+	}
+#endif
+}
+
+void bl31_plat_arch_setup(void)
+{
+	rcar_configure_mmu_el3(BL31_BASE,
+			       BL31_LIMIT - BL31_BASE,
+			       BL31_RO_BASE, BL31_RO_LIMIT
+#if USE_COHERENT_MEM
+			       , BL31_COHERENT_RAM_BASE, BL31_COHERENT_RAM_LIMIT
+#endif
+	    );
+	rcar_pwrc_code_copy_to_system_ram();
+}
+
+void bl31_platform_setup(void)
+{
+	plat_rcar_gic_driver_init();
+	plat_rcar_gic_init();
+
+	/* enable the system level generic timer */
+	mmio_write_32(RCAR_CNTC_BASE + CNTCR_OFF, CNTCR_FCREQ(U(0)) | CNTCR_EN);
+
+	rcar_pwrc_setup();
+#if 0
+	/* TODO: there is a broad number of rcar-gen3 SoC configurations; to
+	   support all of them, Renesas use the pwrc driver to discover what
+	   cores are on/off before announcing the topology.
+	   This code hasnt been ported yet
+	   */
+
+	rcar_setup_topology();
+#endif
+
+	/* mask should match the kernel's MPIDR_HWID_BITMASK so the core can be
+	   identified during cpuhotplug (check the kernel's psci migrate set of
+	   functions */
+	rcar_boot_mpidr = read_mpidr_el1() & 0x0000ffffU;
+}
diff --git a/plat/renesas/rcar/include/plat.ld.S b/plat/renesas/rcar/include/plat.ld.S
new file mode 100644
index 0000000..7aef324
--- /dev/null
+++ b/plat/renesas/rcar/include/plat.ld.S
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef RCAR_PLAT_LD_S
+#define RCAR_PLAT_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <platform_def.h>
+
+MEMORY {
+    SRAM (rwx): ORIGIN = BL31_SRAM_BASE, LENGTH = DEVICE_SRAM_SIZE
+    PRAM (r): ORIGIN = BL31_LIMIT - DEVICE_SRAM_SIZE, LENGTH = DEVICE_SRAM_SIZE
+}
+
+SECTIONS
+{
+	/* SRAM_COPY is in PRAM */
+	. = BL31_LIMIT - DEVICE_SRAM_SIZE;
+	__SRAM_COPY_START__ = .;
+
+	.system_ram : {
+		/* system ram start is in SRAM */
+		__system_ram_start__ = .;
+		*(.system_ram*)
+		*iic_dvfs.o(.rodata)
+	        __system_ram_end__ = .;
+	} >SRAM AT>PRAM
+
+    ASSERT(__BL31_END__ <= BL31_LIMIT - DEVICE_SRAM_SIZE,
+    "BL31 image too large - writing on top of SRAM!")
+
+}
+
+#endif /* RCAR_PLAT_LD_S */
diff --git a/plat/renesas/rcar/include/plat_macros.S b/plat/renesas/rcar/include/plat_macros.S
new file mode 100644
index 0000000..927cd39
--- /dev/null
+++ b/plat/renesas/rcar/include/plat_macros.S
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+
+#include "rcar_def.h"
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL3-1.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_print_gic_regs
+	mov_imm	x17, RCAR_GICC_BASE
+	mov_imm	x16, RCAR_GICD_BASE
+print_gicc_regs:
+	/* gicc base address is now in x17 */
+	adr	x6, gicc_regs	/* Load the gicc reg list to x6 */
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+	adr	x4, spacer
+	bl	asm_print_str
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ------------------------------------------------
+	 * The below macro prints out relevant interconnect
+	 * registers whenever an unhandled exception is
+	 * taken in BL3-1.
+	 * Clobbers: x0 - x9, sp
+	 * ------------------------------------------------
+	 */
+	.macro plat_print_interconnect_regs
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (CCI500_BASE + SLAVE_IFACE3_OFFSET)
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (CCI500_BASE + SLAVE_IFACE4_OFFSET)
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
+
+	.macro plat_crash_print_regs
+	plat_print_gic_regs
+	plat_print_interconnect_regs
+	.endm
diff --git a/plat/renesas/rcar/include/platform_def.h b/plat/renesas/rcar/include/platform_def.h
new file mode 100644
index 0000000..b7f0ca1
--- /dev/null
+++ b/plat/renesas/rcar/include/platform_def.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#ifndef __ASSEMBLER__
+#include <stdlib.h>
+#endif
+
+#include <arch.h>
+
+#include "rcar_def.h"
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT          "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH            aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+ #define FIRMWARE_WELCOME_STR	"Booting Rcar-gen3 Trusted Firmware\n"
+
+/* Size of cacheable stacks */
+#if IMAGE_BL1
+#if TRUSTED_BOARD_BOOT
+#define PLATFORM_STACK_SIZE 	U(0x1000)
+#else
+#define PLATFORM_STACK_SIZE 	U(0x440)
+#endif
+#elif IMAGE_BL2
+#if TRUSTED_BOARD_BOOT
+#define PLATFORM_STACK_SIZE 	U(0x1000)
+#else
+#define PLATFORM_STACK_SIZE 	U(0x400)
+#endif
+#elif IMAGE_BL31
+#define PLATFORM_STACK_SIZE 	U(0x400)
+#elif IMAGE_BL32
+#define PLATFORM_STACK_SIZE 	U(0x440)
+#endif
+
+#define BL332_IMAGE_ID		(NS_BL2U_IMAGE_ID + 1)
+#define BL333_IMAGE_ID		(NS_BL2U_IMAGE_ID + 2)
+#define BL334_IMAGE_ID		(NS_BL2U_IMAGE_ID + 3)
+#define BL335_IMAGE_ID		(NS_BL2U_IMAGE_ID + 4)
+#define BL336_IMAGE_ID		(NS_BL2U_IMAGE_ID + 5)
+#define BL337_IMAGE_ID		(NS_BL2U_IMAGE_ID + 6)
+#define BL338_IMAGE_ID		(NS_BL2U_IMAGE_ID + 7)
+
+#define BL332_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 8)
+#define BL333_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 9)
+#define BL334_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 10)
+#define BL335_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 11)
+#define BL336_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 12)
+#define BL337_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 13)
+#define BL338_KEY_CERT_ID	(NS_BL2U_IMAGE_ID + 14)
+
+#define BL332_CERT_ID		(NS_BL2U_IMAGE_ID + 15)
+#define BL333_CERT_ID		(NS_BL2U_IMAGE_ID + 16)
+#define BL334_CERT_ID		(NS_BL2U_IMAGE_ID + 17)
+#define BL335_CERT_ID		(NS_BL2U_IMAGE_ID + 18)
+#define BL336_CERT_ID		(NS_BL2U_IMAGE_ID + 19)
+#define BL337_CERT_ID		(NS_BL2U_IMAGE_ID + 20)
+#define BL338_CERT_ID		(NS_BL2U_IMAGE_ID + 21)
+
+/* io drivers id */
+#define FLASH_DEV_ID		U(0)
+#define EMMC_DEV_ID		U(1)
+
+/*
+ * R-Car H3 Cortex-A57
+ * L1:I/48KB(16KBx3way) D/32KB(16KBx2way) L2:2MB(128KBx16way)
+ *          Cortex-A53
+ * L1:I/32KB(16KBx2way) D/32KB(8KBx4way) L2:512KB(32KBx16way)
+ */
+#define PLATFORM_CACHE_LINE_SIZE	64
+#define PLATFORM_CLUSTER_COUNT		U(2)
+#define PLATFORM_CLUSTER0_CORE_COUNT	U(4)
+#define PLATFORM_CLUSTER1_CORE_COUNT	U(4)
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT + \
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + 1)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+#define MAX_IO_DEVICES			U(3)
+#define MAX_IO_HANDLES			U(4)
+
+/*******************************************************************************
+ * BL2 specific defines.
+ ******************************************************************************/
+/* Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth. */
+#define RCAR_SYSRAM_BASE		U(0xE6300000)
+#if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3)
+#define BL2_LIMIT			U(0xE6320000)
+#else
+#define BL2_LIMIT			U(0xE6360000)
+#endif
+
+#if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3)
+#define BL2_BASE			U(0xE6304000)
+#define BL2_IMAGE_LIMIT			U(0xE6318000)
+#elif (RCAR_LSI == RCAR_V3M)
+#define BL2_BASE			U(0xE6344000)
+#define BL2_IMAGE_LIMIT			U(0xE636E800)
+#else
+#define BL2_BASE			U(0xE6304000)
+#define BL2_IMAGE_LIMIT			U(0xE632E800)
+#endif
+#define RCAR_SYSRAM_SIZE		(BL2_BASE - RCAR_SYSRAM_BASE)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/* Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL3-1 debug size plus a little space for growth. */
+#define BL31_BASE		(RCAR_TRUSTED_SRAM_BASE)
+#define BL31_LIMIT		(RCAR_TRUSTED_SRAM_BASE + \
+				 RCAR_TRUSTED_SRAM_SIZE)
+#define	RCAR_BL31_LOG_BASE	(0x44040000)
+#define	RCAR_BL31_SDRAM_BTM	(RCAR_BL31_LOG_BASE + 0x14000)
+#define	RCAR_BL31_LOG_SIZE	(RCAR_BL31_SDRAM_BTM - RCAR_BL31_LOG_BASE)
+#define BL31_SRAM_BASE		(DEVICE_SRAM_BASE)
+#define BL31_SRAM_LIMIT		(DEVICE_SRAM_BASE + DEVICE_SRAM_SIZE)
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef SPD_NONE
+#define BL32_BASE		U(0x44100000)
+#define BL32_LIMIT		(BL32_BASE + U(0x100000))
+#endif
+
+/*******************************************************************************
+ * BL33
+ ******************************************************************************/
+#define BL33_BASE		DRAM1_NS_BASE
+
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#if IMAGE_BL1
+#define MAX_XLAT_TABLES		U(2)
+#elif IMAGE_BL2
+#define MAX_XLAT_TABLES		U(5)
+#elif IMAGE_BL31
+#define MAX_XLAT_TABLES		U(4)
+#elif IMAGE_BL32
+#define MAX_XLAT_TABLES		U(3)
+#endif
+
+#if IMAGE_BL2
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 40)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 40)
+#else
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#endif
+
+#define MAX_MMAP_REGIONS	(RCAR_MMAP_ENTRIES + RCAR_BL_REGIONS)
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT   (6)
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+/*******************************************************************************
+ * Size of the per-cpu data in bytes that should be reserved in the generic
+ * per-cpu data structure for the RCAR port.
+ ******************************************************************************/
+#if !USE_COHERENT_MEM
+#define PLAT_PCPU_DATA_SIZE	(2)
+#endif
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/renesas/rcar/include/rcar_def.h b/plat/renesas/rcar/include/rcar_def.h
new file mode 100644
index 0000000..ac7dc17
--- /dev/null
+++ b/plat/renesas/rcar/include/rcar_def.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_DEF_H
+#define RCAR_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+
+#define RCAR_PRIMARY_CPU		0x0
+#define RCAR_TRUSTED_SRAM_BASE		0x44000000
+#define RCAR_TRUSTED_SRAM_SIZE		0x0003E000
+#define RCAR_SHARED_MEM_BASE		(RCAR_TRUSTED_SRAM_BASE + \
+					RCAR_TRUSTED_SRAM_SIZE)
+#define RCAR_SHARED_MEM_SIZE		U(0x00001000)
+#define FLASH0_BASE			U(0x08000000)
+#define FLASH0_SIZE			U(0x04000000)
+#define FLASH_MEMORY_SIZE		U(0x04000000)	/* hyper flash */
+#define FLASH_TRANS_SIZE_UNIT		U(0x00000100)
+#define DEVICE_RCAR_BASE		U(0xE6000000)
+#define DEVICE_RCAR_SIZE		U(0x00300000)
+#define DEVICE_RCAR_BASE2		U(0xE6360000)
+#define DEVICE_RCAR_SIZE2		U(0x19CA0000)
+#define DEVICE_SRAM_BASE		U(0xE6300000)
+#define DEVICE_SRAM_SIZE		U(0x00002000)
+#define DEVICE_SRAM_STACK_BASE		(DEVICE_SRAM_BASE + DEVICE_SRAM_SIZE)
+#define DEVICE_SRAM_STACK_SIZE		U(0x00001000)
+#define DRAM_LIMIT			ULL(0x0000010000000000)
+#define DRAM1_BASE			U(0x40000000)
+#define DRAM1_SIZE			U(0x80000000)
+#define DRAM1_NS_BASE			(DRAM1_BASE + U(0x10000000))
+#define DRAM1_NS_SIZE			(DRAM1_SIZE - DRAM1_NS_BASE)
+#define	DRAM_40BIT_BASE			ULL(0x0400000000)
+#define	DRAM_40BIT_SIZE			ULL(0x0400000000)
+#define	DRAM_PROTECTED_BASE		ULL(0x43F00000)
+#define	DRAM_40BIT_PROTECTED_BASE	ULL(0x0403F00000)
+#define	DRAM_PROTECTED_SIZE		ULL(0x03F00000)
+#define	RCAR_BL31_CRASH_BASE		U(0x4403F000)
+#define	RCAR_BL31_CRASH_SIZE		U(0x00001000)
+/* Entrypoint mailboxes */
+#define MBOX_BASE			RCAR_SHARED_MEM_BASE
+#define MBOX_SIZE			0x200
+/* Base address where parameters to BL31 are stored */
+#define PARAMS_BASE			(MBOX_BASE + MBOX_SIZE)
+#define BOOT_KIND_BASE			(RCAR_SHARED_MEM_BASE + \
+					RCAR_SHARED_MEM_SIZE - 0x100)
+/* The number of regions like RO(code), coherent and data required by
+ * different BL stages which need to be mapped in the MMU */
+#if USE_COHERENT_MEM
+#define RCAR_BL_REGIONS			(3)
+#else
+#define RCAR_BL_REGIONS			(2)
+#endif
+/* The RCAR_MAX_MMAP_REGIONS depend on the number of entries in rcar_mmap[]
+ * defined for each BL stage in rcar_common.c. */
+#if IMAGE_BL2
+#define RCAR_MMAP_ENTRIES		(9)
+#endif
+#if IMAGE_BL31
+#define RCAR_MMAP_ENTRIES		(9)
+#endif
+#if IMAGE_BL2
+#define REG1_BASE			U(0xE6400000)
+#define REG1_SIZE			U(0x04C00000)
+#define ROM0_BASE			U(0xEB100000)
+#define ROM0_SIZE			U(0x00028000)
+#define REG2_BASE			U(0xEC000000)
+#define REG2_SIZE			U(0x14000000)
+#endif
+/* BL33  */
+#define NS_IMAGE_OFFSET			(DRAM1_BASE + U(0x09000000))
+/* BL31 */
+#define	RCAR_DEVICE_BASE		DEVICE_RCAR_BASE
+#define	RCAR_DEVICE_SIZE		(0x1A000000)
+#define	RCAR_LOG_RES_SIZE		(512/8)
+#define	RCAR_LOG_HEADER_SIZE		(16)
+#define	RCAR_LOG_OTHER_SIZE		(RCAR_LOG_HEADER_SIZE + \
+					RCAR_LOG_RES_SIZE)
+#define	RCAR_BL31_LOG_MAX		(RCAR_BL31_LOG_SIZE - \
+					RCAR_LOG_OTHER_SIZE)
+#define	RCAR_CRASH_STACK		RCAR_BL31_CRASH_BASE
+#define	AARCH64_SPACE_BASE		ULL(0x00000000000)
+#define	AARCH64_SPACE_SIZE		ULL(0x10000000000)
+/* CCI related constants */
+#define CCI500_BASE				U(0xF1200000)
+#define CCI500_CLUSTER0_SL_IFACE_IX		(2)
+#define CCI500_CLUSTER1_SL_IFACE_IX		(3)
+#define CCI500_CLUSTER0_SL_IFACE_IX_FOR_M3	(1)
+#define CCI500_CLUSTER1_SL_IFACE_IX_FOR_M3	(2)
+#define	RCAR_CCI_BASE				CCI500_BASE
+/* GIC */
+#define RCAR_GICD_BASE			U(0xF1010000)
+#define RCAR_GICR_BASE			U(0xF1010000)
+#define RCAR_GICC_BASE			U(0xF1020000)
+#define RCAR_GICH_BASE			U(0xF1040000)
+#define RCAR_GICV_BASE			U(0xF1060000)
+#define ARM_IRQ_SEC_PHY_TIMER		U(29)
+#define ARM_IRQ_SEC_SGI_0		U(8)
+#define ARM_IRQ_SEC_SGI_1		U(9)
+#define ARM_IRQ_SEC_SGI_2		U(10)
+#define ARM_IRQ_SEC_SGI_3		U(11)
+#define ARM_IRQ_SEC_SGI_4		U(12)
+#define ARM_IRQ_SEC_SGI_5		U(13)
+#define ARM_IRQ_SEC_SGI_6		U(14)
+#define ARM_IRQ_SEC_SGI_7		U(15)
+#define	ARM_IRQ_SEC_RPC			U(70)
+#define	ARM_IRQ_SEC_TIMER		U(166)
+#define	ARM_IRQ_SEC_TIMER_UP		U(171)
+#define	ARM_IRQ_SEC_WDT			U(173)
+#define	ARM_IRQ_SEC_CRYPT		U(102)
+#define	ARM_IRQ_SEC_CRYPT_SecPKA	U(97)
+#define	ARM_IRQ_SEC_CRYPT_PubPKA	U(98)
+/* Timer control */
+#define	RCAR_CNTC_BASE		U(0xE6080000)
+/* Reset */
+#define	RCAR_CPGWPR		U(0xE6150900)	/* CPG write protect    */
+#define	RCAR_MODEMR		U(0xE6160060)	/* Mode pin             */
+#define	RCAR_CA57RESCNT		U(0xE6160040)	/* Reset control A57    */
+#define	RCAR_CA53RESCNT		U(0xE6160044)	/* Reset control A53    */
+#define	RCAR_SRESCR		U(0xE6160110)	/* Soft Power On Reset  */
+#define	RCAR_CA53WUPCR		U(0xE6151010)	/* Wake-up control A53  */
+#define	RCAR_CA57WUPCR		U(0xE6152010)	/* Wake-up control A57  */
+#define	RCAR_CA53PSTR		U(0xE6151040)	/* Power status A53     */
+#define	RCAR_CA57PSTR		U(0xE6152040)	/* Power status A57     */
+#define	RCAR_CA53CPU0CR		U(0xE6151100)	/* CPU control  A53     */
+#define	RCAR_CA57CPU0CR		U(0xE6152100)	/* CPU control  A57     */
+#define	RCAR_CA53CPUCMCR	U(0xE6151184)	/* Common power A53     */
+#define	RCAR_CA57CPUCMCR	U(0xE6152184)	/* Common power A57     */
+#define	RCAR_WUPMSKCA57		U(0xE6180014)	/* Wake-up mask A57     */
+#define	RCAR_WUPMSKCA53		U(0xE6180018)	/* Wake-up mask A53     */
+/* SYSC	*/
+#define	RCAR_PWRSR3		U(0xE6180140)	/* Power stat A53-SCU   */
+#define	RCAR_PWRSR5		U(0xE61801C0)	/* Power stat A57-SCU   */
+#define	RCAR_SYSCIER		U(0xE618000C)	/* Interrupt enable     */
+#define	RCAR_SYSCIMR		U(0xE6180010)	/* Interrupt mask       */
+#define	RCAR_SYSCSR		U(0xE6180000)	/* SYSC status          */
+#define	RCAR_PWRONCR3		U(0xE618014C)	/* Power resume A53-SCU */
+#define	RCAR_PWRONCR5		U(0xE61801CC)	/* Power resume A57-SCU */
+#define	RCAR_PWROFFCR3		U(0xE6180144)	/* Power shutof A53-SCU */
+#define	RCAR_PWROFFCR5		U(0xE61801C4)	/* Power shutof A57-SCU */
+#define	RCAR_PWRER3		U(0xE6180154)	/* shutoff/resume error */
+#define	RCAR_PWRER5		U(0xE61801D4)	/* shutoff/resume error */
+#define	RCAR_SYSCISR		U(0xE6180004)	/* Interrupt status     */
+#define	RCAR_SYSCISCR		U(0xE6180008)	/* Interrupt stat clear */
+/* Product register */
+#define	RCAR_PRR			U(0xFFF00044)
+#define RCAR_PRODUCT_MASK		U(0x00007F00)
+#define RCAR_CUT_MASK			U(0x000000FF)
+#define RCAR_PRODUCT_H3			U(0x00004F00)
+#define RCAR_PRODUCT_M3			U(0x00005200)
+#define RCAR_PRODUCT_V3M		U(0x00005400)
+#define RCAR_PRODUCT_M3N		U(0x00005500)
+#define RCAR_PRODUCT_E3			U(0x00005700)
+#define RCAR_PRODUCT_D3			U(0x00005800)
+#define RCAR_CUT_VER10			U(0x00000000)
+#define RCAR_CUT_VER11			U(0x00000001)	/* H3/M3N/E3 Ver.1.1 */
+#define RCAR_M3_CUT_VER11		U(0x00000010)	/* M3 Ver.1.1/Ver.1.2 */
+#define RCAR_CUT_VER20			U(0x00000010)
+#define RCAR_CUT_VER30			U(0x00000020)
+#define RCAR_MAJOR_MASK			U(0x000000F0)
+#define RCAR_MINOR_MASK			U(0x0000000F)
+#define RCAR_PRODUCT_SHIFT		U(8)
+#define RCAR_MAJOR_SHIFT		U(4)
+#define RCAR_MINOR_SHIFT		U(0)
+#define RCAR_MAJOR_OFFSET		U(1)
+#define RCAR_M3_MINOR_OFFSET		U(2)
+#define RCAR_PRODUCT_H3_CUT10		(RCAR_PRODUCT_H3 | U(0x00))	/* 1.0 */
+#define RCAR_PRODUCT_H3_CUT11		(RCAR_PRODUCT_H3 | U(0x01))	/* 1.1 */
+#define RCAR_PRODUCT_H3_CUT20		(RCAR_PRODUCT_H3 | U(0x10))	/* 2.0 */
+#define RCAR_PRODUCT_M3_CUT10		(RCAR_PRODUCT_M3 | U(0x00))	/* 1.0 */
+#define RCAR_PRODUCT_M3_CUT11		(RCAR_PRODUCT_M3 | U(0x10))
+#define RCAR_CPU_MASK_CA57		U(0x80000000)
+#define RCAR_CPU_MASK_CA53		U(0x04000000)
+#define RCAR_CPU_HAVE_CA57		U(0x00000000)
+#define RCAR_CPU_HAVE_CA53		U(0x00000000)
+#define RCAR_SSCG_MASK			U(0x1000)	/* MD12 */
+#define RCAR_SSCG_ENABLE		U(0x1000)
+/* MD pin information */
+#define MODEMR_BOOT_CPU_MASK		U(0x000000C0)
+#define MODEMR_BOOT_CPU_CR7		U(0x000000C0)
+#define MODEMR_BOOT_CPU_CA57		U(0x00000000)
+#define MODEMR_BOOT_CPU_CA53		U(0x00000040)
+#define MODEMR_BOOT_DEV_MASK		U(0x0000001E)
+#define MODEMR_BOOT_DEV_HYPERFLASH160	U(0x00000004)
+#define MODEMR_BOOT_DEV_HYPERFLASH80	U(0x00000006)
+#define MODEMR_BOOT_DEV_QSPI_FLASH40	U(0x00000008)
+#define MODEMR_BOOT_DEV_QSPI_FLASH80	U(0x0000000C)
+#define MODEMR_BOOT_DEV_EMMC_25X1	U(0x0000000A)
+#define MODEMR_BOOT_DEV_EMMC_50X8	U(0x0000001A)
+#define MODEMR_BOOT_PLL_MASK		U(0x00006000)
+#define MODEMR_BOOT_PLL_SHIFT		U(13)
+/* Memory mapped Generic timer interfaces */
+#define ARM_SYS_CNTCTL_BASE		RCAR_CNTC_BASE
+/* MODEMR PLL masks and bitfield values */
+#define	CHECK_MD13_MD14			U(0x6000)
+#define	MD14_MD13_TYPE_0		U(0x0000)	/* MD14=0 MD13=0 */
+#define	MD14_MD13_TYPE_1		U(0x2000)	/* MD14=0 MD13=1 */
+#define	MD14_MD13_TYPE_2		U(0x4000)	/* MD14=1 MD13=0 */
+#define	MD14_MD13_TYPE_3		U(0x6000)	/* MD14=1 MD13=1 */
+/* Frequency of EXTAL(Hz) */
+#define	EXTAL_MD14_MD13_TYPE_0		U(8333300)	/* MD14=0 MD13=0 */
+#define	EXTAL_MD14_MD13_TYPE_1		U(10000000)	/* MD14=0 MD13=1 */
+#define	EXTAL_MD14_MD13_TYPE_2		U(12500000)	/* MD14=1 MD13=0 */
+#define	EXTAL_MD14_MD13_TYPE_3		U(16666600)	/* MD14=1 MD13=1 */
+#define	EXTAL_SALVATOR_XS		U(8320000)	/* Salvator-XS */
+#define EXTAL_EBISU			U(24000000)	/* Ebisu */
+#define EXTAL_DRAAK			U(24000000)	/* Draak */
+/* CPG write protect registers 	*/
+#define	CPGWPR_PASSWORD			(0x5A5AFFFFU)
+#define	CPGWPCR_PASSWORD		(0xA5A50000U)
+/* CA5x Debug Resource control registers */
+#define	CPG_CA57DBGRCR			(CPG_BASE + 0x2180U)
+#define	CPG_CA53DBGRCR			(CPG_BASE + 0x1180U)
+#define	DBGCPUPREN			((uint32_t)1U << 19U)
+#define	CPG_PLL0CR			(CPG_BASE + 0x00D8U)
+#define	CPG_PLL2CR			(CPG_BASE + 0x002CU)
+#define	CPG_PLL4CR			(CPG_BASE + 0x01F4U)
+/* RST Registers */
+#define	RST_BASE			(0xE6160000U)
+#define	RST_WDTRSTCR			(RST_BASE + 0x0054U)
+#define	WDTRSTCR_PASSWORD		(0xA55A0000U)
+#define	WDTRSTCR_RWDT_RSTMSK		((uint32_t)1U << 0U)
+/* MFIS Registers */
+#define	MFISWPCNTR_PASSWORD		(0xACCE0000U)
+#define	MFISWPCNTR			(0xE6260900U)
+/* IPMMU registers */
+#define IPMMU_MM_BASE			(0xE67B0000U)
+#define IPMMUMM_IMSCTLR			(IPMMU_MM_BASE + 0x0500U)
+#define IPMMUMM_IMAUXCTLR		(IPMMU_MM_BASE + 0x0504U)
+#define IPMMUMM_IMSCTLR_ENABLE		(0xC0000000U)
+#define IPMMUMM_IMAUXCTLR_NMERGE40_BIT	(0x01000000U)
+#define IMSCTLR_DISCACHE		(0xE0000000U)
+#define IPMMU_VP0_BASE			(0xFE990000U)
+#define IPMMUVP0_IMSCTLR		(IPMMU_VP0_BASE + 0x0500U)
+#define IPMMU_VI0_BASE			(0xFEBD0000U)
+#define IPMMUVI0_IMSCTLR		(IPMMU_VI0_BASE + 0x0500U)
+#define IPMMU_VI1_BASE			(0xFEBE0000U)
+#define IPMMUVI1_IMSCTLR		(IPMMU_VI1_BASE + 0x0500U)
+#define IPMMU_PV0_BASE			(0xFD800000U)
+#define IPMMUPV0_IMSCTLR		(IPMMU_PV0_BASE + 0x0500U)
+#define IPMMU_PV1_BASE			(0xFD950000U)
+#define IPMMUPV1_IMSCTLR		(IPMMU_PV1_BASE + 0x0500U)
+#define IPMMU_PV2_BASE			(0xFD960000U)
+#define IPMMUPV2_IMSCTLR		(IPMMU_PV2_BASE + 0x0500U)
+#define IPMMU_PV3_BASE			(0xFD970000U)
+#define IPMMUPV3_IMSCTLR		(IPMMU_PV3_BASE + 0x0500U)
+#define IPMMU_HC_BASE			(0xE6570000U)
+#define IPMMUHC_IMSCTLR			(IPMMU_HC_BASE + 0x0500U)
+#define IPMMU_RT_BASE			(0xFFC80000U)
+#define IPMMURT_IMSCTLR			(IPMMU_RT_BASE + 0x0500U)
+#define IPMMU_MP_BASE			(0xEC670000U)
+#define IPMMUMP_IMSCTLR			(IPMMU_MP_BASE + 0x0500U)
+#define IPMMU_DS0_BASE			(0xE6740000U)
+#define IPMMUDS0_IMSCTLR		(IPMMU_DS0_BASE + 0x0500U)
+#define IPMMU_DS1_BASE			(0xE7740000U)
+#define IPMMUDS1_IMSCTLR		(IPMMU_DS1_BASE + 0x0500U)
+/* ARMREG registers */
+#define	P_ARMREG_SEC_CTRL		(0xE62711F0U)
+#define	P_ARMREG_SEC_CTRL_PROT		(0x00000001U)
+/* MIDR */
+#define MIDR_CA57			(0x0D07U << MIDR_PN_SHIFT)
+#define MIDR_CA53			(0x0D03U << MIDR_PN_SHIFT)
+/* for SuspendToRAM */
+#define	GPIO_BASE			(0xE6050000U)
+#define	GPIO_INDT1			(GPIO_BASE + 0x100CU)
+#define GPIO_INDT6			(GPIO_BASE + 0x540CU)
+#define	RCAR_COLD_BOOT			(0x00U)
+#define	RCAR_WARM_BOOT			(0x01U)
+#if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR
+#define	KEEP10_MAGIC		(0x55U)
+#endif
+/* lossy registers */
+#define LOSSY_PARAMS_BASE 		(0x47FD7000U)
+#define	AXI_DCMPAREACRA0		(0xE6784100U)
+#define	AXI_DCMPAREACRB0		(0xE6784104U)
+#define LOSSY_ENABLE			(0x80000000U)
+#define LOSSY_DISABLE			(0x00000000U)
+#define LOSSY_FMT_YUVPLANAR		(0x00000000U)
+#define LOSSY_FMT_YUV422INTLV		(0x20000000U)
+#define LOSSY_FMT_ARGB8888		(0x40000000U)
+#define	LOSSY_ST_ADDR0			(0x54000000U)
+#define	LOSSY_END_ADDR0			(0x57000000U)
+#define	LOSSY_FMT0			LOSSY_FMT_YUVPLANAR
+#define	LOSSY_ENA_DIS0			LOSSY_ENABLE
+#define	LOSSY_ST_ADDR1			0x0U
+#define	LOSSY_END_ADDR1			0x0U
+#define	LOSSY_FMT1			LOSSY_FMT_ARGB8888
+#define	LOSSY_ENA_DIS1			LOSSY_DISABLE
+#define	LOSSY_ST_ADDR2			0x0U
+#define	LOSSY_END_ADDR2			0x0U
+#define	LOSSY_FMT2			LOSSY_FMT_YUV422INTLV
+#define	LOSSY_ENA_DIS2			LOSSY_DISABLE
+
+#endif /* RCAR_DEF_H */
diff --git a/plat/renesas/rcar/include/rcar_private.h b/plat/renesas/rcar/include/rcar_private.h
new file mode 100644
index 0000000..a76c023
--- /dev/null
+++ b/plat/renesas/rcar/include/rcar_private.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_PRIVATE_H
+#define RCAR_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <lib/bakery_lock.h>
+#include <lib/el3_runtime/cpu_data.h>
+
+typedef volatile struct mailbox {
+	unsigned long value __aligned(CACHE_WRITEBACK_GRANULE);
+} mailbox_t;
+
+/*
+ * This structure represents the superset of information that is passed to
+ * BL31 e.g. while passing control to it from BL2 which is bl31_params
+ * and bl31_plat_params and its elements
+ */
+typedef struct bl2_to_bl31_params_mem {
+	image_info_t bl32_image_info;
+	image_info_t bl33_image_info;
+	entry_point_info_t bl33_ep_info;
+	entry_point_info_t bl32_ep_info;
+} bl2_to_bl31_params_mem_t;
+
+#if USE_COHERENT_MEM
+#define RCAR_INSTANTIATE_LOCK	DEFINE_BAKERY_LOCK(rcar_lock);
+#define rcar_lock_init()	bakery_lock_init(&rcar_lock)
+#define rcar_lock_get()		bakery_lock_get(&rcar_lock)
+#define rcar_lock_release()	bakery_lock_release(&rcar_lock)
+#else
+/*
+ * Constants to specify how many bakery locks this platform implements. These
+ * are used if the platform chooses not to use coherent memory for bakery lock
+ * data structures.
+ */
+#define RCAR_MAX_BAKERIES	2
+#define RCAR_PWRC_BAKERY_ID	0
+
+/*
+ * Definition of structure which holds platform specific per-cpu data. Currently
+ * it holds only the bakery lock information for each cpu. Constants to
+ * specify how many bakeries this platform implements and bakery ids are
+ * specified in rcar_def.h
+ */
+typedef struct rcar_cpu_data {
+	bakery_info_t pcpu_bakery_info[RCAR_MAX_BAKERIES];
+} rcar_cpu_data_t;
+
+#define RCAR_CPU_DATA_LOCK_OFFSET	\
+	__builtin_offsetof(rcar_cpu_data_t, pcpu_bakery_info)
+/*
+ * Helper macros for bakery lock api when using the above rcar_cpu_data_t for
+ * bakery lock data structures. It assumes that the bakery_info is at the
+ * beginning of the platform specific per-cpu data.
+ */
+#define rcar_lock_init(_lock_arg)
+
+#define rcar_lock_get(_lock_arg) 					\
+	bakery_lock_get(_lock_arg, 					\
+		CPU_DATA_PLAT_PCPU_OFFSET + RCAR_CPU_DATA_LOCK_OFFSET)
+
+#define rcar_lock_release(_lock_arg)					\
+	bakery_lock_release(_lock_arg,	    				\
+		CPU_DATA_PLAT_PCPU_OFFSET + RCAR_CPU_DATA_LOCK_OFFSET)
+/* Ensure that the size of the RCAR specific per-cpu data structure and the size
+ * of the memory allocated in generic per-cpu data for the platform are the same
+ */
+CASSERT(PLAT_PCPU_DATA_SIZE == sizeof(rcar_cpu_data_t),
+	rcar_pcpu_data_size_mismatch);
+#endif
+/*
+ * Function and variable prototypes
+ */
+void rcar_configure_mmu_el3(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long ro_start, unsigned long ro_limit
+#if USE_COHERENT_MEM
+			    , unsigned long coh_start, unsigned long coh_limit
+#endif
+    );
+
+void rcar_setup_topology(void);
+void rcar_cci_disable(void);
+void rcar_cci_enable(void);
+void rcar_cci_init(void);
+
+void plat_invalidate_icache(void);
+void plat_cci_disable(void);
+void plat_cci_enable(void);
+void plat_cci_init(void);
+
+void mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit);
+void cpg_write(uintptr_t regadr, uint32_t regval);
+
+void rcar_console_boot_init(void);
+void rcar_console_boot_end(void);
+void rcar_console_runtime_init(void);
+void rcar_console_runtime_end(void);
+
+#endif /* RCAR_PRIVATE_H */
diff --git a/plat/renesas/rcar/include/rcar_version.h b/plat/renesas/rcar/include/rcar_version.h
new file mode 100644
index 0000000..2d400e0
--- /dev/null
+++ b/plat/renesas/rcar/include/rcar_version.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RCAR_VERSION_H
+#define RCAR_VERSION_H
+
+#include <arch_helpers.h>
+
+#define VERSION_OF_RENESAS		"2.0.4"
+#define	VERSION_OF_RENESAS_MAXLEN	(128)
+
+extern const uint8_t version_of_renesas[VERSION_OF_RENESAS_MAXLEN];
+
+#endif /* RCAR_VERSION_H */
diff --git a/plat/renesas/rcar/include/registers/axi_registers.h b/plat/renesas/rcar/include/registers/axi_registers.h
new file mode 100644
index 0000000..36cd58b
--- /dev/null
+++ b/plat/renesas/rcar/include/registers/axi_registers.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef AXI_REGISTERS_H
+#define AXI_REGISTERS_H
+
+/* AXI registers */
+
+/* AXI base address */
+#define	AXI_BASE	(0xE6780000U)
+
+/* address split */
+
+/* AXI address split control 0 */
+#define	AXI_ADSPLCR0	(AXI_BASE + 0x4008U)
+/* AXI address split control 1 */
+#define	AXI_ADSPLCR1	(AXI_BASE + 0x400CU)
+/* AXI address split control 2 */
+#define	AXI_ADSPLCR2	(AXI_BASE + 0x4010U)
+/* AXI address split control 3 */
+#define	AXI_ADSPLCR3	(AXI_BASE + 0x4014U)
+
+/* functional safety */
+
+/* AXI functional safety control */
+#define	AXI_FUSACR	(AXI_BASE + 0x4020U)
+
+/* decompression */
+
+/* AXI decompression area configuration A0 */
+#define	AXI_DCMPAREACRA0	(AXI_BASE + 0x4100U)
+/* AXI decompression area configuration B0 */
+#define	AXI_DCMPAREACRB0	(AXI_BASE + 0x4104U)
+/* AXI decompression area configuration A1 */
+#define	AXI_DCMPAREACRA1	(AXI_BASE + 0x4108U)
+/* AXI decompression area configuration B1 */
+#define	AXI_DCMPAREACRB1	(AXI_BASE + 0x410CU)
+/* AXI decompression area configuration A2 */
+#define	AXI_DCMPAREACRA2	(AXI_BASE + 0x4110U)
+/* AXI decompression area configuration B2 */
+#define	AXI_DCMPAREACRB2	(AXI_BASE + 0x4114U)
+/* AXI decompression area configuration A3 */
+#define	AXI_DCMPAREACRA3	(AXI_BASE + 0x4118U)
+/* AXI decompression area configuration B3 */
+#define	AXI_DCMPAREACRB3	(AXI_BASE + 0x411CU)
+/* AXI decompression area configuration A4 */
+#define	AXI_DCMPAREACRA4	(AXI_BASE + 0x4120U)
+/* AXI decompression area configuration B4 */
+#define	AXI_DCMPAREACRB4	(AXI_BASE + 0x4124U)
+/* AXI decompression area configuration A5 */
+#define	AXI_DCMPAREACRA5	(AXI_BASE + 0x4128U)
+/* AXI decompression area configuration B5 */
+#define	AXI_DCMPAREACRB5	(AXI_BASE + 0x412CU)
+/* AXI decompression area configuration A6 */
+#define	AXI_DCMPAREACRA6	(AXI_BASE + 0x4130U)
+/* AXI decompression area configuration B6 */
+#define	AXI_DCMPAREACRB6	(AXI_BASE + 0x4134U)
+/* AXI decompression area configuration A7 */
+#define	AXI_DCMPAREACRA7	(AXI_BASE + 0x4138U)
+/* AXI decompression area configuration B7 */
+#define	AXI_DCMPAREACRB7	(AXI_BASE + 0x413CU)
+/* AXI decompression area configuration A8 */
+#define	AXI_DCMPAREACRA8	(AXI_BASE + 0x4140U)
+/* AXI decompression area configuration B8 */
+#define	AXI_DCMPAREACRB8	(AXI_BASE + 0x4144U)
+/* AXI decompression area configuration A9 */
+#define	AXI_DCMPAREACRA9	(AXI_BASE + 0x4148U)
+/* AXI decompression area configuration B9 */
+#define	AXI_DCMPAREACRB9	(AXI_BASE + 0x414CU)
+/* AXI decompression area configuration A10 */
+#define	AXI_DCMPAREACRA10	(AXI_BASE + 0x4150U)
+/* AXI decompression area configuration B10 */
+#define	AXI_DCMPAREACRB10	(AXI_BASE + 0x4154U)
+/* AXI decompression area configuration A11 */
+#define	AXI_DCMPAREACRA11	(AXI_BASE + 0x4158U)
+/* AXI decompression area configuration B11 */
+#define	AXI_DCMPAREACRB11	(AXI_BASE + 0x415CU)
+/* AXI decompression area configuration A12 */
+#define	AXI_DCMPAREACRA12	(AXI_BASE + 0x4160U)
+/* AXI decompression area configuration B12 */
+#define	AXI_DCMPAREACRB12	(AXI_BASE + 0x4164U)
+/* AXI decompression area configuration A13 */
+#define	AXI_DCMPAREACRA13	(AXI_BASE + 0x4168U)
+/* AXI decompression area configuration B13 */
+#define	AXI_DCMPAREACRB13	(AXI_BASE + 0x416CU)
+/* AXI decompression area configuration A14 */
+#define	AXI_DCMPAREACRA14	(AXI_BASE + 0x4170U)
+/* AXI decompression area configuration B14 */
+#define	AXI_DCMPAREACRB14	(AXI_BASE + 0x4174U)
+/* AXI decompression area configuration A15 */
+#define	AXI_DCMPAREACRA15	(AXI_BASE + 0x4178U)
+/* AXI decompression area configuration B15 */
+#define	AXI_DCMPAREACRB15	(AXI_BASE + 0x417CU)
+/* AXI decompression shadow area configuration */
+#define	AXI_DCMPSHDWCR	(AXI_BASE + 0x4280U)
+
+/* SDRAM protection */
+
+/* AXI dram protected area division 0 */
+#define	AXI_DPTDIVCR0	(AXI_BASE + 0x4400U)
+/* AXI dram protected area division 1 */
+#define	AXI_DPTDIVCR1	(AXI_BASE + 0x4404U)
+/* AXI dram protected area division 2 */
+#define	AXI_DPTDIVCR2	(AXI_BASE + 0x4408U)
+/* AXI dram protected area division 3 */
+#define	AXI_DPTDIVCR3	(AXI_BASE + 0x440CU)
+/* AXI dram protected area division 4 */
+#define	AXI_DPTDIVCR4	(AXI_BASE + 0x4410U)
+/* AXI dram protected area division 5 */
+#define	AXI_DPTDIVCR5	(AXI_BASE + 0x4414U)
+/* AXI dram protected area division 6 */
+#define	AXI_DPTDIVCR6	(AXI_BASE + 0x4418U)
+/* AXI dram protected area division 7 */
+#define	AXI_DPTDIVCR7	(AXI_BASE + 0x441CU)
+/* AXI dram protected area division 8 */
+#define	AXI_DPTDIVCR8	(AXI_BASE + 0x4420U)
+/* AXI dram protected area division 9 */
+#define	AXI_DPTDIVCR9	(AXI_BASE + 0x4424U)
+/* AXI dram protected area division 10 */
+#define	AXI_DPTDIVCR10	(AXI_BASE + 0x4428U)
+/* AXI dram protected area division 11 */
+#define	AXI_DPTDIVCR11	(AXI_BASE + 0x442CU)
+/* AXI dram protected area division 12 */
+#define	AXI_DPTDIVCR12	(AXI_BASE + 0x4430U)
+/* AXI dram protected area division 13 */
+#define	AXI_DPTDIVCR13	(AXI_BASE + 0x4434U)
+/* AXI dram protected area division 14 */
+#define	AXI_DPTDIVCR14	(AXI_BASE + 0x4438U)
+
+/* AXI dram protected area setting 0 */
+#define	AXI_DPTCR0	(AXI_BASE + 0x4440U)
+/* AXI dram protected area setting 1 */
+#define	AXI_DPTCR1	(AXI_BASE + 0x4444U)
+/* AXI dram protected area setting 2 */
+#define	AXI_DPTCR2	(AXI_BASE + 0x4448U)
+/* AXI dram protected area setting 3 */
+#define	AXI_DPTCR3	(AXI_BASE + 0x444CU)
+/* AXI dram protected area setting 4 */
+#define	AXI_DPTCR4	(AXI_BASE + 0x4450U)
+/* AXI dram protected area setting 5 */
+#define	AXI_DPTCR5	(AXI_BASE + 0x4454U)
+/* AXI dram protected area setting 6 */
+#define	AXI_DPTCR6	(AXI_BASE + 0x4458U)
+/* AXI dram protected area setting 7 */
+#define	AXI_DPTCR7	(AXI_BASE + 0x445CU)
+/* AXI dram protected area setting 8 */
+#define	AXI_DPTCR8	(AXI_BASE + 0x4460U)
+/* AXI dram protected area setting 9 */
+#define	AXI_DPTCR9	(AXI_BASE + 0x4464U)
+/* AXI dram protected area setting 10 */
+#define	AXI_DPTCR10	(AXI_BASE + 0x4468U)
+/* AXI dram protected area setting 11 */
+#define	AXI_DPTCR11	(AXI_BASE + 0x446CU)
+/* AXI dram protected area setting 12 */
+#define	AXI_DPTCR12	(AXI_BASE + 0x4470U)
+/* AXI dram protected area setting 13 */
+#define	AXI_DPTCR13	(AXI_BASE + 0x4474U)
+/* AXI dram protected area setting 14 */
+#define	AXI_DPTCR14	(AXI_BASE + 0x4478U)
+/* AXI dram protected area setting 15 */
+#define	AXI_DPTCR15	(AXI_BASE + 0x447CU)
+
+/* SRAM protection */
+
+/* AXI sram protected area division 0 */
+#define	AXI_SPTDIVCR0	(AXI_BASE + 0x4500U)
+/* AXI sram protected area division 1 */
+#define	AXI_SPTDIVCR1	(AXI_BASE + 0x4504U)
+/* AXI sram protected area division 2 */
+#define	AXI_SPTDIVCR2	(AXI_BASE + 0x4508U)
+/* AXI sram protected area division 3 */
+#define	AXI_SPTDIVCR3	(AXI_BASE + 0x450CU)
+/* AXI sram protected area division 4 */
+#define	AXI_SPTDIVCR4	(AXI_BASE + 0x4510U)
+/* AXI sram protected area division 5 */
+#define	AXI_SPTDIVCR5	(AXI_BASE + 0x4514U)
+/* AXI sram protected area division 6 */
+#define	AXI_SPTDIVCR6	(AXI_BASE + 0x4518U)
+/* AXI sram protected area division 7 */
+#define	AXI_SPTDIVCR7	(AXI_BASE + 0x451CU)
+/* AXI sram protected area division 8 */
+#define	AXI_SPTDIVCR8	(AXI_BASE + 0x4520U)
+/* AXI sram protected area division 9 */
+#define	AXI_SPTDIVCR9	(AXI_BASE + 0x4524U)
+/* AXI sram protected area division 10 */
+#define	AXI_SPTDIVCR10	(AXI_BASE + 0x4528U)
+/* AXI sram protected area division 11 */
+#define	AXI_SPTDIVCR11	(AXI_BASE + 0x452CU)
+/* AXI sram protected area division 12 */
+#define	AXI_SPTDIVCR12	(AXI_BASE + 0x4530U)
+/* AXI sram protected area division 13 */
+#define	AXI_SPTDIVCR13	(AXI_BASE + 0x4534U)
+/* AXI sram protected area division 14 */
+#define	AXI_SPTDIVCR14	(AXI_BASE + 0x4538U)
+
+/* AXI sram protected area setting 0 */
+#define	AXI_SPTCR0	(AXI_BASE + 0x4540U)
+/* AXI sram protected area setting 1 */
+#define	AXI_SPTCR1	(AXI_BASE + 0x4544U)
+/* AXI sram protected area setting 2 */
+#define	AXI_SPTCR2	(AXI_BASE + 0x4548U)
+/* AXI sram protected area setting 3 */
+#define	AXI_SPTCR3	(AXI_BASE + 0x454CU)
+/* AXI sram protected area setting 4 */
+#define	AXI_SPTCR4	(AXI_BASE + 0x4550U)
+/* AXI sram protected area setting 5 */
+#define	AXI_SPTCR5	(AXI_BASE + 0x4554U)
+/* AXI sram protected area setting 6 */
+#define	AXI_SPTCR6	(AXI_BASE + 0x4558U)
+/* AXI sram protected area setting 7 */
+#define	AXI_SPTCR7	(AXI_BASE + 0x455CU)
+/* AXI sram protected area setting 8 */
+#define	AXI_SPTCR8	(AXI_BASE + 0x4560U)
+/* AXI sram protected area setting 9 */
+#define	AXI_SPTCR9	(AXI_BASE + 0x4564U)
+/* AXI sram protected area setting 10 */
+#define	AXI_SPTCR10	(AXI_BASE + 0x4568U)
+/* AXI sram protected area setting 11 */
+#define	AXI_SPTCR11	(AXI_BASE + 0x456CU)
+/* AXI sram protected area setting 12 */
+#define	AXI_SPTCR12	(AXI_BASE + 0x4570U)
+/* AXI sram protected area setting 13 */
+#define	AXI_SPTCR13	(AXI_BASE + 0x4574U)
+/* AXI sram protected area setting 14 */
+#define	AXI_SPTCR14	(AXI_BASE + 0x4578U)
+/* AXI sram protected area setting 15 */
+#define	AXI_SPTCR15	(AXI_BASE + 0x457CU)
+
+/* EDC base address */
+#define	EDC_BASE	(0xFF840000U)
+
+/* EDC edc enable */
+#define	EDC_EDCEN	(EDC_BASE + 0x0010U)
+/* EDC edc status 0 */
+#define	EDC_EDCST0	(EDC_BASE + 0x0020U)
+/* EDC edc status 1 */
+#define	EDC_EDCST1	(EDC_BASE + 0x0024U)
+/* EDC edc interrupt enable 0 */
+#define	EDC_EDCINTEN0	(EDC_BASE + 0x0040U)
+/* EDC edc interrupt enable 1 */
+#define	EDC_EDCINTEN1	(EDC_BASE + 0x0044U)
+
+#endif /* AXI_REGISTERS_H */
diff --git a/plat/renesas/rcar/include/registers/cpg_registers.h b/plat/renesas/rcar/include/registers/cpg_registers.h
new file mode 100644
index 0000000..0d698d9
--- /dev/null
+++ b/plat/renesas/rcar/include/registers/cpg_registers.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CPG_REGISTERS_H
+#define CPG_REGISTERS_H
+
+/* CPG base address */
+#define	CPG_BASE	(0xE6150000U)
+
+/* CPG system module stop control 2 */
+#define CPG_SMSTPCR2	(CPG_BASE + 0x0138U)
+/* CPG software reset 2 */
+#define CPG_SRCR2	(CPG_BASE + 0x00B0U)
+/* CPG module stop status 2 */
+#define CPG_MSTPSR2	(CPG_BASE + 0x0040U)
+/* CPG write protect */
+#define CPG_CPGWPR	(CPG_BASE + 0x0900U)
+/* CPG write protect control */
+#define CPG_CPGWPCR	(CPG_BASE + 0x0904U)
+/* CPG system module stop control 9 */
+#define CPG_SMSTPCR9    (CPG_BASE + 0x0994U)
+/* CPG module stop status 9 */
+#define CPG_MSTPSR9     (CPG_BASE + 0x09A4U)
+
+/* CPG (SECURITY) registers */
+
+/* Secure Module Stop Control Register 0 */
+#define	SCMSTPCR0	(CPG_BASE + 0x0B20U)
+/* Secure Module Stop Control Register 1 */
+#define	SCMSTPCR1	(CPG_BASE + 0x0B24U)
+/* Secure Module Stop Control Register 2 */
+#define	SCMSTPCR2	(CPG_BASE + 0x0B28U)
+/* Secure Module Stop Control Register 3 */
+#define	SCMSTPCR3	(CPG_BASE + 0x0B2CU)
+/* Secure Module Stop Control Register 4 */
+#define	SCMSTPCR4	(CPG_BASE + 0x0B30U)
+/* Secure Module Stop Control Register 5 */
+#define	SCMSTPCR5	(CPG_BASE + 0x0B34U)
+/* Secure Module Stop Control Register 6 */
+#define	SCMSTPCR6	(CPG_BASE + 0x0B38U)
+/* Secure Module Stop Control Register 7 */
+#define	SCMSTPCR7	(CPG_BASE + 0x0B3CU)
+/* Secure Module Stop Control Register 8 */
+#define	SCMSTPCR8	(CPG_BASE + 0x0B40U)
+/* Secure Module Stop Control Register 9 */
+#define	SCMSTPCR9	(CPG_BASE + 0x0B44U)
+/* Secure Module Stop Control Register 10 */
+#define	SCMSTPCR10	(CPG_BASE + 0x0B48U)
+/* Secure Module Stop Control Register 11 */
+#define	SCMSTPCR11	(CPG_BASE + 0x0B4CU)
+
+/* CPG (SECURITY) registers */
+
+/* Secure Software Reset Access Enable Control Register 0 */
+#define	SCSRSTECR0	(CPG_BASE + 0x0B80U)
+/* Secure Software Reset Access Enable Control Register 1 */
+#define	SCSRSTECR1	(CPG_BASE + 0x0B84U)
+/* Secure Software Reset Access Enable Control Register 2 */
+#define	SCSRSTECR2	(CPG_BASE + 0x0B88U)
+/* Secure Software Reset Access Enable Control Register 3 */
+#define	SCSRSTECR3	(CPG_BASE + 0x0B8CU)
+/* Secure Software Reset Access Enable Control Register 4 */
+#define	SCSRSTECR4	(CPG_BASE + 0x0B90U)
+/* Secure Software Reset Access Enable Control Register 5 */
+#define	SCSRSTECR5	(CPG_BASE + 0x0B94U)
+/* Secure Software Reset Access Enable Control Register 6 */
+#define	SCSRSTECR6	(CPG_BASE + 0x0B98U)
+/* Secure Software Reset Access Enable Control Register 7 */
+#define	SCSRSTECR7	(CPG_BASE + 0x0B9CU)
+/* Secure Software Reset Access Enable Control Register 8 */
+#define	SCSRSTECR8	(CPG_BASE + 0x0BA0U)
+/* Secure Software Reset Access Enable Control Register 9 */
+#define	SCSRSTECR9	(CPG_BASE + 0x0BA4U)
+/* Secure Software Reset Access Enable Control Register 10 */
+#define	SCSRSTECR10	(CPG_BASE + 0x0BA8U)
+/* Secure Software Reset Access Enable Control Register 11 */
+#define	SCSRSTECR11	(CPG_BASE + 0x0BACU)
+
+/* CPG (REALTIME) registers */
+
+/* Realtime Module Stop Control Register 0 */
+#define	RMSTPCR0	(CPG_BASE + 0x0110U)
+/* Realtime Module Stop Control Register 1 */
+#define	RMSTPCR1	(CPG_BASE + 0x0114U)
+/* Realtime Module Stop Control Register 2 */
+#define	RMSTPCR2	(CPG_BASE + 0x0118U)
+/* Realtime Module Stop Control Register 3 */
+#define	RMSTPCR3	(CPG_BASE + 0x011CU)
+/* Realtime Module Stop Control Register 4 */
+#define	RMSTPCR4	(CPG_BASE + 0x0120U)
+/* Realtime Module Stop Control Register 5 */
+#define	RMSTPCR5	(CPG_BASE + 0x0124U)
+/* Realtime Module Stop Control Register 6 */
+#define	RMSTPCR6	(CPG_BASE + 0x0128U)
+/* Realtime Module Stop Control Register 7 */
+#define	RMSTPCR7	(CPG_BASE + 0x012CU)
+/* Realtime Module Stop Control Register 8 */
+#define	RMSTPCR8	(CPG_BASE + 0x0980U)
+/* Realtime Module Stop Control Register 9 */
+#define	RMSTPCR9	(CPG_BASE + 0x0984U)
+/* Realtime Module Stop Control Register 10 */
+#define	RMSTPCR10	(CPG_BASE + 0x0988U)
+/* Realtime Module Stop Control Register 11 */
+#define	RMSTPCR11	(CPG_BASE + 0x098CU)
+
+/* CPG (SYSTEM) registers */
+
+/* System Module Stop Control Register 0 */
+#define	SMSTPCR0	(CPG_BASE + 0x0130U)
+/* System Module Stop Control Register 1 */
+#define	SMSTPCR1	(CPG_BASE + 0x0134U)
+/* System Module Stop Control Register 2 */
+#define	SMSTPCR2	(CPG_BASE + 0x0138U)
+/* System Module Stop Control Register 3 */
+#define	SMSTPCR3	(CPG_BASE + 0x013CU)
+/* System Module Stop Control Register 4 */
+#define	SMSTPCR4	(CPG_BASE + 0x0140U)
+/* System Module Stop Control Register 5 */
+#define	SMSTPCR5	(CPG_BASE + 0x0144U)
+/* System Module Stop Control Register 6 */
+#define	SMSTPCR6	(CPG_BASE + 0x0148U)
+/* System Module Stop Control Register 7 */
+#define	SMSTPCR7	(CPG_BASE + 0x014CU)
+/* System Module Stop Control Register 8 */
+#define	SMSTPCR8	(CPG_BASE + 0x0990U)
+/* System Module Stop Control Register 9 */
+#define	SMSTPCR9	(CPG_BASE + 0x0994U)
+/* System Module Stop Control Register 10 */
+#define	SMSTPCR10	(CPG_BASE + 0x0998U)
+/* System Module Stop Control Register 11 */
+#define	SMSTPCR11	(CPG_BASE + 0x099CU)
+
+#endif /* CPG_REGISTERS_H */
diff --git a/plat/renesas/rcar/include/registers/lifec_registers.h b/plat/renesas/rcar/include/registers/lifec_registers.h
new file mode 100644
index 0000000..de78760
--- /dev/null
+++ b/plat/renesas/rcar/include/registers/lifec_registers.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LIFEC_REGISTERS_H
+#define LIFEC_REGISTERS_H
+
+#define	LIFEC_SEC_BASE	(0xE6110000U)
+
+#define	SEC_SRC		(LIFEC_SEC_BASE + 0x0008U)
+#define	SEC_SEL0	(LIFEC_SEC_BASE + 0x0030U)
+#define	SEC_SEL1	(LIFEC_SEC_BASE + 0x0034U)
+#define	SEC_SEL2	(LIFEC_SEC_BASE + 0x0038U)
+#define	SEC_SEL3	(LIFEC_SEC_BASE + 0x003CU)
+#define	SEC_SEL4	(LIFEC_SEC_BASE + 0x0058U)
+#define	SEC_SEL5	(LIFEC_SEC_BASE + 0x005CU)
+#define SEC_SEL6	(LIFEC_SEC_BASE + 0x0060U)
+#define	SEC_SEL7	(LIFEC_SEC_BASE + 0x0064U)
+#define	SEC_SEL8	(LIFEC_SEC_BASE + 0x0068U)
+#define	SEC_SEL9	(LIFEC_SEC_BASE + 0x006CU)
+#define	SEC_SEL10	(LIFEC_SEC_BASE + 0x0070U)
+#define	SEC_SEL11	(LIFEC_SEC_BASE + 0x0074U)
+#define	SEC_SEL12	(LIFEC_SEC_BASE + 0x0078U)
+#define	SEC_SEL13	(LIFEC_SEC_BASE + 0x007CU)
+#define	SEC_SEL14	(LIFEC_SEC_BASE + 0x0080U)
+#define	SEC_SEL15	(LIFEC_SEC_BASE + 0x0084U)
+#define	SEC_GRP0CR0	(LIFEC_SEC_BASE + 0x0138U)
+#define	SEC_GRP1CR0	(LIFEC_SEC_BASE + 0x013CU)
+#define	SEC_GRP0CR1	(LIFEC_SEC_BASE + 0x0140U)
+#define	SEC_GRP1CR1	(LIFEC_SEC_BASE + 0x0144U)
+#define	SEC_GRP0CR2	(LIFEC_SEC_BASE + 0x0148U)
+#define	SEC_GRP1CR2	(LIFEC_SEC_BASE + 0x014CU)
+#define	SEC_GRP0CR3	(LIFEC_SEC_BASE + 0x0150U)
+#define	SEC_GRP1CR3	(LIFEC_SEC_BASE + 0x0154U)
+#define	SEC_GRP0COND0	(LIFEC_SEC_BASE + 0x0158U)
+#define	SEC_GRP1COND0	(LIFEC_SEC_BASE + 0x015CU)
+#define	SEC_GRP0COND1	(LIFEC_SEC_BASE + 0x0160U)
+#define	SEC_GRP1COND1	(LIFEC_SEC_BASE + 0x0164U)
+#define	SEC_GRP0COND2	(LIFEC_SEC_BASE + 0x0168U)
+#define	SEC_GRP1COND2	(LIFEC_SEC_BASE + 0x016CU)
+#define	SEC_GRP0COND3	(LIFEC_SEC_BASE + 0x0170U)
+#define	SEC_GRP1COND3	(LIFEC_SEC_BASE + 0x0174U)
+#define	SEC_GRP0COND4	(LIFEC_SEC_BASE + 0x0178U)
+#define	SEC_GRP1COND4	(LIFEC_SEC_BASE + 0x017CU)
+#define	SEC_GRP0COND5	(LIFEC_SEC_BASE + 0x0180U)
+#define	SEC_GRP1COND5	(LIFEC_SEC_BASE + 0x0184U)
+#define	SEC_GRP0COND6	(LIFEC_SEC_BASE + 0x0188U)
+#define	SEC_GRP1COND6	(LIFEC_SEC_BASE + 0x018CU)
+#define	SEC_GRP0COND7	(LIFEC_SEC_BASE + 0x0190U)
+#define	SEC_GRP1COND7	(LIFEC_SEC_BASE + 0x0194U)
+#define	SEC_GRP0COND8	(LIFEC_SEC_BASE + 0x0198U)
+#define	SEC_GRP1COND8	(LIFEC_SEC_BASE + 0x019CU)
+#define	SEC_GRP0COND9	(LIFEC_SEC_BASE + 0x01A0U)
+#define	SEC_GRP1COND9	(LIFEC_SEC_BASE + 0x01A4U)
+#define	SEC_GRP0COND10	(LIFEC_SEC_BASE + 0x01A8U)
+#define	SEC_GRP1COND10	(LIFEC_SEC_BASE + 0x01ACU)
+#define	SEC_GRP0COND11	(LIFEC_SEC_BASE + 0x01B0U)
+#define	SEC_GRP1COND11	(LIFEC_SEC_BASE + 0x01B4U)
+#define	SEC_GRP0COND12	(LIFEC_SEC_BASE + 0x01B8U)
+#define	SEC_GRP1COND12	(LIFEC_SEC_BASE + 0x01BCU)
+#define	SEC_GRP0COND13	(LIFEC_SEC_BASE + 0x01C0U)
+#define	SEC_GRP1COND13	(LIFEC_SEC_BASE + 0x01C4U)
+#define	SEC_GRP0COND14	(LIFEC_SEC_BASE + 0x01C8U)
+#define	SEC_GRP1COND14	(LIFEC_SEC_BASE + 0x01CCU)
+#define	SEC_GRP0COND15	(LIFEC_SEC_BASE + 0x01D0U)
+#define	SEC_GRP1COND15	(LIFEC_SEC_BASE + 0x01D4U)
+#define	SEC_READONLY0	(LIFEC_SEC_BASE + 0x01D8U)
+#define	SEC_READONLY1	(LIFEC_SEC_BASE + 0x01DCU)
+#define	SEC_READONLY2	(LIFEC_SEC_BASE + 0x01E0U)
+#define	SEC_READONLY3	(LIFEC_SEC_BASE + 0x01E4U)
+#define	SEC_READONLY4	(LIFEC_SEC_BASE + 0x01E8U)
+#define	SEC_READONLY5	(LIFEC_SEC_BASE + 0x01ECU)
+#define	SEC_READONLY6	(LIFEC_SEC_BASE + 0x01F0U)
+#define	SEC_READONLY7	(LIFEC_SEC_BASE + 0x01F4U)
+#define	SEC_READONLY8	(LIFEC_SEC_BASE + 0x01F8U)
+#define	SEC_READONLY9	(LIFEC_SEC_BASE + 0x01FCU)
+#define	SEC_READONLY10	(LIFEC_SEC_BASE + 0x0200U)
+#define	SEC_READONLY11	(LIFEC_SEC_BASE + 0x0204U)
+#define	SEC_READONLY12	(LIFEC_SEC_BASE + 0x0208U)
+#define	SEC_READONLY13	(LIFEC_SEC_BASE + 0x020CU)
+#define	SEC_READONLY14	(LIFEC_SEC_BASE + 0x0210U)
+#define	SEC_READONLY15	(LIFEC_SEC_BASE + 0x0214U)
+
+#define	LIFEC_SAFE_BASE	(0xE6120000U)
+#define	SAFE_GRP0CR0	(LIFEC_SAFE_BASE + 0x0138U)
+#define	SAFE_GRP1CR0	(LIFEC_SAFE_BASE + 0x013CU)
+#define	SAFE_GRP0CR1	(LIFEC_SAFE_BASE + 0x0140U)
+#define	SAFE_GRP1CR1	(LIFEC_SAFE_BASE + 0x0144U)
+#define	SAFE_GRP0CR2	(LIFEC_SAFE_BASE + 0x0148U)
+#define	SAFE_GRP1CR2	(LIFEC_SAFE_BASE + 0x014CU)
+#define	SAFE_GRP0CR3	(LIFEC_SAFE_BASE + 0x0150U)
+#define	SAFE_GRP1CR3	(LIFEC_SAFE_BASE + 0x0154U)
+#define	SAFE_GRP0COND0	(LIFEC_SAFE_BASE + 0x0158U)
+#define	SAFE_GRP1COND0	(LIFEC_SAFE_BASE + 0x015CU)
+#define	SAFE_GRP0COND1	(LIFEC_SAFE_BASE + 0x0160U)
+#define	SAFE_GRP1COND1	(LIFEC_SAFE_BASE + 0x0164U)
+#define	SAFE_GRP0COND2	(LIFEC_SAFE_BASE + 0x0168U)
+#define	SAFE_GRP1COND2	(LIFEC_SAFE_BASE + 0x016CU)
+#define	SAFE_GRP0COND3	(LIFEC_SAFE_BASE + 0x0170U)
+#define	SAFE_GRP1COND3	(LIFEC_SAFE_BASE + 0x0174U)
+#define	SAFE_GRP0COND4	(LIFEC_SAFE_BASE + 0x0178U)
+#define	SAFE_GRP1COND4	(LIFEC_SAFE_BASE + 0x017CU)
+#define	SAFE_GRP0COND5	(LIFEC_SAFE_BASE + 0x0180U)
+#define	SAFE_GRP1COND5	(LIFEC_SAFE_BASE + 0x0184U)
+#define	SAFE_GRP0COND6	(LIFEC_SAFE_BASE + 0x0188U)
+#define	SAFE_GRP1COND6	(LIFEC_SAFE_BASE + 0x018CU)
+#define	SAFE_GRP0COND7	(LIFEC_SAFE_BASE + 0x0190U)
+#define	SAFE_GRP1COND7	(LIFEC_SAFE_BASE + 0x0194U)
+#define	SAFE_GRP0COND8	(LIFEC_SAFE_BASE + 0x0198U)
+#define	SAFE_GRP1COND8	(LIFEC_SAFE_BASE + 0x019CU)
+#define	SAFE_GRP0COND9	(LIFEC_SAFE_BASE + 0x01A0U)
+#define	SAFE_GRP1COND9	(LIFEC_SAFE_BASE + 0x01A4U)
+#define	SAFE_GRP0COND10	(LIFEC_SAFE_BASE + 0x01A8U)
+#define	SAFE_GRP1COND10	(LIFEC_SAFE_BASE + 0x01ACU)
+#define	SAFE_GRP0COND11	(LIFEC_SAFE_BASE + 0x01B0U)
+#define	SAFE_GRP1COND11	(LIFEC_SAFE_BASE + 0x01B4U)
+#define	SAFE_GRP0COND12	(LIFEC_SAFE_BASE + 0x01B8U)
+#define	SAFE_GRP1COND12	(LIFEC_SAFE_BASE + 0x01BCU)
+#define	SAFE_GRP0COND13	(LIFEC_SAFE_BASE + 0x01C0U)
+#define	SAFE_GRP1COND13	(LIFEC_SAFE_BASE + 0x01C4U)
+#define	SAFE_GRP0COND14	(LIFEC_SAFE_BASE + 0x01C8U)
+#define	SAFE_GRP1COND14	(LIFEC_SAFE_BASE + 0x01CCU)
+#define	SAFE_GRP0COND15	(LIFEC_SAFE_BASE + 0x01D0U)
+#define	SAFE_GRP1COND15	(LIFEC_SAFE_BASE + 0x01D4U)
+#define	SAFE_READONLY0	(LIFEC_SAFE_BASE + 0x01D8U)
+#define	SAFE_READONLY1	(LIFEC_SAFE_BASE + 0x01DCU)
+#define	SAFE_READONLY2	(LIFEC_SAFE_BASE + 0x01E0U)
+#define	SAFE_READONLY3	(LIFEC_SAFE_BASE + 0x01E4U)
+#define	SAFE_READONLY4	(LIFEC_SAFE_BASE + 0x01E8U)
+#define	SAFE_READONLY5	(LIFEC_SAFE_BASE + 0x01ECU)
+#define	SAFE_READONLY6	(LIFEC_SAFE_BASE + 0x01F0U)
+#define	SAFE_READONLY7	(LIFEC_SAFE_BASE + 0x01F4U)
+#define	SAFE_READONLY8	(LIFEC_SAFE_BASE + 0x01F8U)
+#define	SAFE_READONLY9	(LIFEC_SAFE_BASE + 0x01FCU)
+#define	SAFE_READONLY10	(LIFEC_SAFE_BASE + 0x0200U)
+#define	SAFE_READONLY11	(LIFEC_SAFE_BASE + 0x0204U)
+#define	SAFE_READONLY12	(LIFEC_SAFE_BASE + 0x0208U)
+#define	SAFE_READONLY13	(LIFEC_SAFE_BASE + 0x020CU)
+#define	SAFE_READONLY14	(LIFEC_SAFE_BASE + 0x0210U)
+#define	SAFE_READONLY15	(LIFEC_SAFE_BASE + 0x0214U)
+
+#endif /* LIFEC_REGISTERS_H */
diff --git a/plat/renesas/rcar/plat_image_load.c b/plat/renesas/rcar/plat_image_load.c
new file mode 100644
index 0000000..9d814a6
--- /dev/null
+++ b/plat/renesas/rcar/plat_image_load.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+extern void bl2_plat_flush_bl31_params(void);
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+#if IMAGE_BL2
+	bl2_plat_flush_bl31_params();
+#endif
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/renesas/rcar/plat_pm.c b/plat/renesas/rcar/plat_pm.c
new file mode 100644
index 0000000..e678da5
--- /dev/null
+++ b/plat/renesas/rcar/plat_pm.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "iic_dvfs.h"
+#include "pwrc.h"
+#include "rcar_def.h"
+#include "rcar_private.h"
+#include "ulcb_cpld.h"
+
+#define	DVFS_SET_VID_0V		(0x00)
+#define	P_ALL_OFF		(0x80)
+#define	KEEPON_DDR1C		(0x08)
+#define	KEEPON_DDR0C		(0x04)
+#define	KEEPON_DDR1		(0x02)
+#define	KEEPON_DDR0		(0x01)
+
+#define SYSTEM_PWR_STATE(s)	((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+#define CLUSTER_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL1])
+#define CORE_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL0])
+
+extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
+extern void plat_rcar_gic_driver_init(void);
+extern void plat_rcar_gic_init(void);
+extern u_register_t rcar_boot_mpidr;
+
+static uintptr_t rcar_sec_entrypoint;
+
+static void rcar_program_mailbox(uint64_t mpidr, uint64_t address)
+{
+	mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
+	uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
+	unsigned long range;
+
+	rcar_mboxes[linear_id].value = address;
+	range = (unsigned long)&rcar_mboxes[linear_id];
+
+	flush_dcache_range(range, sizeof(range));
+}
+
+static void rcar_cpu_standby(plat_local_state_t cpu_state)
+{
+	uint32_t scr_el3 = read_scr_el3();
+
+	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
+	dsb();
+	wfi();
+	write_scr_el3(scr_el3);
+}
+
+static int rcar_pwr_domain_on(u_register_t mpidr)
+{
+	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
+	rcar_pwrc_cpuon(mpidr);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	uint32_t cluster_type = rcar_pwrc_get_cluster();
+	unsigned long mpidr = read_mpidr_el1();
+
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		if (cluster_type == RCAR_CLUSTER_A53A57)
+			plat_cci_enable();
+
+	rcar_pwrc_disable_interrupt_wakeup(mpidr);
+	rcar_program_mailbox(mpidr, 0);
+
+	gicv2_cpuif_enable();
+	gicv2_pcpu_distif_init();
+}
+
+static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
+{
+#if RCAR_LSI != RCAR_D3
+	uint32_t cluster_type = rcar_pwrc_get_cluster();
+#endif
+	unsigned long mpidr = read_mpidr_el1();
+
+	gicv2_cpuif_disable();
+	rcar_pwrc_cpuoff(mpidr);
+
+#if RCAR_LSI != RCAR_D3
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		if (cluster_type == RCAR_CLUSTER_A53A57)
+			plat_cci_disable();
+
+		rcar_pwrc_clusteroff(mpidr);
+	}
+#endif
+}
+
+static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	uint32_t cluster_type = rcar_pwrc_get_cluster();
+	unsigned long mpidr = read_mpidr_el1();
+
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
+	rcar_pwrc_enable_interrupt_wakeup(mpidr);
+	gicv2_cpuif_disable();
+	rcar_pwrc_cpuoff(mpidr);
+
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		if (cluster_type == RCAR_CLUSTER_A53A57)
+			plat_cci_disable();
+
+		rcar_pwrc_clusteroff(mpidr);
+	}
+
+#if RCAR_SYSTEM_SUSPEND
+	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		rcar_pwrc_suspend_to_ram();
+#endif
+}
+
+static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
+					   *target_state)
+{
+	uint32_t cluster_type = rcar_pwrc_get_cluster();
+
+	if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		goto finish;
+
+	plat_rcar_gic_driver_init();
+	plat_rcar_gic_init();
+
+	if (cluster_type == RCAR_CLUSTER_A53A57)
+		plat_cci_init();
+
+	rcar_pwrc_restore_timer_state();
+	rcar_pwrc_setup();
+	rcar_pwrc_code_copy_to_system_ram();
+
+#if RCAR_SYSTEM_SUSPEND
+	rcar_pwrc_init_suspend_to_ram();
+#endif
+finish:
+	rcar_pwr_domain_on_finish(target_state);
+}
+
+static void __dead2 rcar_system_off(void)
+{
+#if PMIC_ROHM_BD9571
+#if PMIC_LEVEL_MODE
+	if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
+		ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
+#else
+	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
+		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
+#endif
+#else
+	uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
+	int32_t rtn_on;
+
+	rtn_on = rcar_pwrc_cpu_on_check(cpu);
+
+	if (cpu == rcar_boot_mpidr)
+		panic();
+
+	if (rtn_on)
+		panic();
+
+	rcar_pwrc_cpuoff(cpu);
+	rcar_pwrc_clusteroff(cpu);
+
+#endif /* PMIC_ROHM_BD9571 */
+	wfi();
+	ERROR("RCAR System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 rcar_system_reset(void)
+{
+#if PMIC_ROHM_BD9571
+#if PMIC_LEVEL_MODE
+#if RCAR_SYSTEM_RESET_KEEPON_DDR
+	uint8_t mode;
+	int32_t error;
+
+	error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
+	if (error) {
+		ERROR("Failed send KEEP10 magic ret=%d \n", error);
+		goto done;
+	}
+
+	error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
+	if (error) {
+		ERROR("Failed recieve BKUP_Mode_Cnt ret=%d \n", error);
+		goto done;
+	}
+
+	mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
+	error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
+	if (error) {
+		ERROR("Failed send KEEPON_DDRx ret=%d \n", error);
+		goto done;
+	}
+
+	rcar_pwrc_set_suspend_to_ram();
+done:
+#else
+	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
+		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
+#endif
+#else
+#if (RCAR_GEN3_ULCB == 1)
+	rcar_cpld_reset_cpu();
+#endif
+#endif
+#else
+	rcar_pwrc_system_reset();
+#endif
+	wfi();
+
+	ERROR("RCAR System Reset: operation not handled.\n");
+	panic();
+}
+
+static int rcar_validate_power_state(unsigned int power_state,
+				    psci_power_state_t *req_state)
+{
+	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	unsigned int pstate = psci_get_pstate_type(power_state);
+	uint32_t i;
+
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+	} else {
+		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+	}
+
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+#if RCAR_SYSTEM_SUSPEND
+static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
+	int i;
+
+	if (mpidr != rcar_boot_mpidr)
+		goto deny;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+
+	return;
+deny:
+	/* deny system suspend entry */
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
+	for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
+}
+#endif
+
+static const plat_psci_ops_t rcar_plat_psci_ops = {
+	.cpu_standby			= rcar_cpu_standby,
+	.pwr_domain_on			= rcar_pwr_domain_on,
+	.pwr_domain_off			= rcar_pwr_domain_off,
+	.pwr_domain_suspend		= rcar_pwr_domain_suspend,
+	.pwr_domain_on_finish		= rcar_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish	= rcar_pwr_domain_suspend_finish,
+	.system_off			= rcar_system_off,
+	.system_reset			= rcar_system_reset,
+	.validate_power_state		= rcar_validate_power_state,
+#if RCAR_SYSTEM_SUSPEND
+	.get_sys_suspend_power_state 	= rcar_get_sys_suspend_power_state,
+#endif
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &rcar_plat_psci_ops;
+	rcar_sec_entrypoint = sec_entrypoint;
+
+#if RCAR_SYSTEM_SUSPEND
+	rcar_pwrc_init_suspend_to_ram();
+#endif
+	return 0;
+}
+
diff --git a/plat/renesas/rcar/plat_storage.c b/plat/renesas/rcar/plat_storage.c
new file mode 100644
index 0000000..05e3d9f
--- /dev/null
+++ b/plat/renesas/rcar/plat_storage.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/io/io_semihosting.h>
+
+#include "io_common.h"
+#include "io_rcar.h"
+#include "io_memdrv.h"
+#include "io_emmcdrv.h"
+#include "io_private.h"
+
+static uintptr_t emmcdrv_dev_handle;
+static uintptr_t memdrv_dev_handle;
+static uintptr_t rcar_dev_handle;
+
+static uintptr_t boot_io_drv_id;
+
+static const io_block_spec_t rcar_block_spec = {
+	.offset = FLASH0_BASE,
+	.length = FLASH0_SIZE
+};
+
+static const io_block_spec_t bl2_file_spec = {
+	.offset = BL2_IMAGE_ID,
+};
+
+static const io_block_spec_t bl31_file_spec = {
+	.offset = BL31_IMAGE_ID,
+};
+
+static const io_block_spec_t bl32_file_spec = {
+	.offset = BL32_IMAGE_ID,
+};
+
+static const io_block_spec_t bl33_file_spec = {
+	.offset = BL33_IMAGE_ID,
+};
+
+static const io_block_spec_t bl332_file_spec = {
+	.offset = BL332_IMAGE_ID,
+};
+
+static const io_block_spec_t bl333_file_spec = {
+	.offset = BL333_IMAGE_ID,
+};
+
+static const io_block_spec_t bl334_file_spec = {
+	.offset = BL334_IMAGE_ID,
+};
+
+static const io_block_spec_t bl335_file_spec = {
+	.offset = BL335_IMAGE_ID,
+};
+
+static const io_block_spec_t bl336_file_spec = {
+	.offset = BL336_IMAGE_ID,
+};
+
+static const io_block_spec_t bl337_file_spec = {
+	.offset = BL337_IMAGE_ID,
+};
+
+static const io_block_spec_t bl338_file_spec = {
+	.offset = BL338_IMAGE_ID,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_block_spec_t trusted_key_cert_file_spec = {
+	.offset = TRUSTED_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl31_key_cert_file_spec = {
+	.offset = SOC_FW_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl32_key_cert_file_spec = {
+	.offset = TRUSTED_OS_FW_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl33_key_cert_file_spec = {
+	.offset = NON_TRUSTED_FW_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl332_key_cert_file_spec = {
+	.offset = BL332_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl333_key_cert_file_spec = {
+	.offset = BL333_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl334_key_cert_file_spec = {
+	.offset = BL334_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl335_key_cert_file_spec = {
+	.offset = BL335_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl336_key_cert_file_spec = {
+	.offset = BL336_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl337_key_cert_file_spec = {
+	.offset = BL337_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl338_key_cert_file_spec = {
+	.offset = BL338_KEY_CERT_ID,
+};
+
+static const io_block_spec_t bl31_cert_file_spec = {
+	.offset = SOC_FW_CONTENT_CERT_ID,
+};
+
+static const io_block_spec_t bl32_cert_file_spec = {
+	.offset = TRUSTED_OS_FW_CONTENT_CERT_ID,
+};
+
+static const io_block_spec_t bl33_cert_file_spec = {
+	.offset = NON_TRUSTED_FW_CONTENT_CERT_ID,
+};
+
+static const io_block_spec_t bl332_cert_file_spec = {
+	.offset = BL332_CERT_ID,
+};
+
+static const io_block_spec_t bl333_cert_file_spec = {
+	.offset = BL333_CERT_ID,
+};
+
+static const io_block_spec_t bl334_cert_file_spec = {
+	.offset = BL334_CERT_ID,
+};
+
+static const io_block_spec_t bl335_cert_file_spec = {
+	.offset = BL335_CERT_ID,
+};
+
+static const io_block_spec_t bl336_cert_file_spec = {
+	.offset = BL336_CERT_ID,
+};
+
+static const io_block_spec_t bl337_cert_file_spec = {
+	.offset = BL337_CERT_ID,
+};
+
+static const io_block_spec_t bl338_cert_file_spec = {
+	.offset = BL338_CERT_ID,
+};
+#endif
+
+static int32_t open_emmcdrv(const uintptr_t spec);
+static int32_t open_memmap(const uintptr_t spec);
+static int32_t open_rcar(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	 int32_t(*check) (const uintptr_t spec);
+};
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+			  &memdrv_dev_handle,
+			  (uintptr_t) &rcar_block_spec,
+			  &open_memmap},
+	[BL2_IMAGE_ID] = {
+			  &rcar_dev_handle,
+			  (uintptr_t) &bl2_file_spec,
+			  &open_rcar},
+	[BL31_IMAGE_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl31_file_spec,
+			   &open_rcar},
+	[BL32_IMAGE_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl32_file_spec,
+			   &open_rcar},
+	[BL33_IMAGE_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl33_file_spec,
+			   &open_rcar},
+	[BL332_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl332_file_spec,
+			    &open_rcar},
+	[BL333_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl333_file_spec,
+			    &open_rcar},
+	[BL334_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl334_file_spec,
+			    &open_rcar},
+	[BL335_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl335_file_spec,
+			    &open_rcar},
+	[BL336_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl336_file_spec,
+			    &open_rcar},
+	[BL337_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl337_file_spec,
+			    &open_rcar},
+	[BL338_IMAGE_ID] = {
+			    &rcar_dev_handle,
+			    (uintptr_t) &bl338_file_spec,
+			    &open_rcar},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_KEY_CERT_ID] = {
+				 &rcar_dev_handle,
+				 (uintptr_t) &trusted_key_cert_file_spec,
+				 &open_rcar},
+	[SOC_FW_KEY_CERT_ID] = {
+				&rcar_dev_handle,
+				(uintptr_t) &bl31_key_cert_file_spec,
+				&open_rcar},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+				       &rcar_dev_handle,
+				       (uintptr_t) &bl32_key_cert_file_spec,
+				       &open_rcar},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+					&rcar_dev_handle,
+					(uintptr_t) &bl33_key_cert_file_spec,
+					&open_rcar},
+	[BL332_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl332_key_cert_file_spec,
+			       &open_rcar},
+	[BL333_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl333_key_cert_file_spec,
+			       &open_rcar},
+	[BL334_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl334_key_cert_file_spec,
+			       &open_rcar},
+	[BL335_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl335_key_cert_file_spec,
+			       &open_rcar},
+	[BL336_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl336_key_cert_file_spec,
+			       &open_rcar},
+	[BL337_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl337_key_cert_file_spec,
+			       &open_rcar},
+	[BL338_KEY_CERT_ID] = {
+			       &rcar_dev_handle,
+			       (uintptr_t) &bl338_key_cert_file_spec,
+			       &open_rcar},
+	[SOC_FW_CONTENT_CERT_ID] = {
+				    &rcar_dev_handle,
+				    (uintptr_t) &bl31_cert_file_spec,
+				    &open_rcar},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+					   &rcar_dev_handle,
+					   (uintptr_t) &bl32_cert_file_spec,
+					   &open_rcar},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+					    &rcar_dev_handle,
+					    (uintptr_t) &bl33_cert_file_spec,
+					    &open_rcar},
+	[BL332_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl332_cert_file_spec,
+			   &open_rcar},
+	[BL333_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl333_cert_file_spec,
+			   &open_rcar},
+	[BL334_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl334_cert_file_spec,
+			   &open_rcar},
+	[BL335_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl335_cert_file_spec,
+			   &open_rcar},
+	[BL336_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl336_cert_file_spec,
+			   &open_rcar},
+	[BL337_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl337_cert_file_spec,
+			   &open_rcar},
+	[BL338_CERT_ID] = {
+			   &rcar_dev_handle,
+			   (uintptr_t) &bl338_cert_file_spec,
+			   &open_rcar}, {
+#else
+				   {
+#endif
+					 0, 0, 0}
+};
+
+static io_drv_spec_t io_drv_spec_memdrv = {
+	FLASH0_BASE,
+	FLASH0_SIZE,
+	0,
+};
+
+static io_drv_spec_t io_drv_spec_emmcdrv = {
+	0,
+	0,
+	0,
+};
+
+static struct plat_io_policy drv_policies[]
+    __attribute__ ((section(".data"))) = {
+	/* FLASH_DEV_ID */
+	{
+	&memdrv_dev_handle,
+		    (uintptr_t) &io_drv_spec_memdrv, &open_memmap,},
+	    /* EMMC_DEV_ID */
+	{
+	&emmcdrv_dev_handle,
+		    (uintptr_t) &io_drv_spec_emmcdrv, &open_emmcdrv,}
+};
+
+static int32_t open_rcar(const uintptr_t spec)
+{
+	return io_dev_init(rcar_dev_handle, boot_io_drv_id);
+}
+
+static int32_t open_memmap(const uintptr_t spec)
+{
+	uintptr_t handle;
+	int32_t result;
+
+	result = io_dev_init(memdrv_dev_handle, 0);
+	if (result != IO_SUCCESS)
+		return result;
+
+	result = io_open(memdrv_dev_handle, spec, &handle);
+	if (result == IO_SUCCESS)
+		io_close(handle);
+
+	return result;
+}
+
+static int32_t open_emmcdrv(const uintptr_t spec)
+{
+	return io_dev_init(emmcdrv_dev_handle, 0);
+}
+
+void rcar_io_setup(void)
+{
+	const io_dev_connector_t *memmap;
+	const io_dev_connector_t *rcar;
+
+	boot_io_drv_id = FLASH_DEV_ID;
+
+	rcar_register_io_dev(&rcar);
+	rcar_register_io_dev_memdrv(&memmap);
+	io_dev_open(rcar, 0, &rcar_dev_handle);
+	io_dev_open(memmap, 0, &memdrv_dev_handle);
+}
+
+void rcar_io_emmc_setup(void)
+{
+	const io_dev_connector_t *rcar;
+	const io_dev_connector_t *emmc;
+
+	boot_io_drv_id = EMMC_DEV_ID;
+
+	rcar_register_io_dev(&rcar);
+	rcar_register_io_dev_emmcdrv(&emmc);
+	io_dev_open(rcar, 0, &rcar_dev_handle);
+	io_dev_open(emmc, 0, &emmcdrv_dev_handle);
+}
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	const struct plat_io_policy *policy;
+	int result;
+
+	policy = &policies[image_id];
+
+	result = policy->check(policy->image_spec);
+	if (result != IO_SUCCESS)
+		return result;
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return IO_SUCCESS;
+}
+
+int32_t plat_get_drv_source(uint32_t io_drv_id, uintptr_t *dev_handle,
+			    uintptr_t *image_spec)
+{
+	const struct plat_io_policy *policy;
+	int32_t result;
+
+	policy = &drv_policies[io_drv_id];
+
+	result = policy->check(policy->image_spec);
+	if (result != IO_SUCCESS)
+		return result;
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return IO_SUCCESS;
+}
diff --git a/plat/renesas/rcar/plat_topology.c b/plat/renesas/rcar/plat_topology.c
new file mode 100644
index 0000000..0d5880d
--- /dev/null
+++ b/plat/renesas/rcar/plat_topology.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/psci/psci.h>
+
+static const unsigned char rcar_power_domain_tree_desc[] = {
+	1,
+	PLATFORM_CLUSTER_COUNT,
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	PLATFORM_CLUSTER1_CORE_COUNT
+};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return rcar_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	if (cluster_id == 0 && cpu_id >= PLATFORM_CLUSTER0_CORE_COUNT)
+		return -1;
+
+	if (cluster_id == 1 && cpu_id >= PLATFORM_CLUSTER1_CORE_COUNT)
+		return -1;
+
+	return (cpu_id + cluster_id * PLATFORM_CLUSTER0_CORE_COUNT);
+}
+
diff --git a/plat/renesas/rcar/platform.mk b/plat/renesas/rcar/platform.mk
new file mode 100644
index 0000000..dc58e19
--- /dev/null
+++ b/plat/renesas/rcar/platform.mk
@@ -0,0 +1,472 @@
+#
+# Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PROGRAMMABLE_RESET_ADDRESS	:= 0
+COLD_BOOT_SINGLE_CPU		:= 1
+ARM_CCI_PRODUCT_ID		:= 500
+TRUSTED_BOARD_BOOT		:= 1
+RESET_TO_BL31			:= 1
+GENERATE_COT			:= 1
+BL2_AT_EL3			:= 1
+ENABLE_SVE_FOR_NS		:= 0
+MULTI_CONSOLE_API		:= 1
+
+CRASH_REPORTING			:= 1
+HANDLE_EA_EL3_FIRST		:= 1
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+ifeq (${SPD},none)
+  SPD_NONE:=1
+  $(eval $(call add_define,SPD_NONE))
+endif
+
+# LSI setting common define
+RCAR_H3:=0
+RCAR_M3:=1
+RCAR_M3N:=2
+RCAR_E3:=3
+RCAR_H3N:=4
+RCAR_D3:=5
+RCAR_V3M:=6
+RCAR_AUTO:=99
+$(eval $(call add_define,RCAR_H3))
+$(eval $(call add_define,RCAR_M3))
+$(eval $(call add_define,RCAR_M3N))
+$(eval $(call add_define,RCAR_E3))
+$(eval $(call add_define,RCAR_H3N))
+$(eval $(call add_define,RCAR_D3))
+$(eval $(call add_define,RCAR_V3M))
+$(eval $(call add_define,RCAR_AUTO))
+RCAR_CUT_10:=0
+RCAR_CUT_11:=1
+RCAR_CUT_13:=3
+RCAR_CUT_20:=10
+RCAR_CUT_30:=20
+$(eval $(call add_define,RCAR_CUT_10))
+$(eval $(call add_define,RCAR_CUT_11))
+$(eval $(call add_define,RCAR_CUT_13))
+$(eval $(call add_define,RCAR_CUT_20))
+$(eval $(call add_define,RCAR_CUT_30))
+
+ifndef LSI
+  $(error "Error: Unknown LSI. Please use LSI=<LSI name> to specify the LSI")
+else
+  ifeq (${LSI},AUTO)
+    RCAR_LSI:=${RCAR_AUTO}
+  else ifeq (${LSI},H3)
+    RCAR_LSI:=${RCAR_H3}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},10)
+        RCAR_LSI_CUT:=0
+      else ifeq (${LSI_CUT},11)
+        RCAR_LSI_CUT:=1
+      else ifeq (${LSI_CUT},20)
+        RCAR_LSI_CUT:=10
+      else ifeq (${LSI_CUT},30)
+        RCAR_LSI_CUT:=20
+      else
+        $(error "Error: ${LSI_CUT} is not supported.")
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else ifeq (${LSI},H3N)
+    RCAR_LSI:=${RCAR_H3N}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},30)
+        RCAR_LSI_CUT:=20
+      else
+        $(error "Error: ${LSI_CUT} is not supported.")
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else ifeq (${LSI},M3)
+    RCAR_LSI:=${RCAR_M3}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},10)
+        RCAR_LSI_CUT:=0
+      else ifeq (${LSI_CUT},11)
+        RCAR_LSI_CUT:=1
+      else ifeq (${LSI_CUT},13)
+        RCAR_LSI_CUT:=3
+      else ifeq (${LSI_CUT},30)
+        RCAR_LSI_CUT:=20
+      else
+        $(error "Error: ${LSI_CUT} is not supported.")
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else ifeq (${LSI},M3N)
+    RCAR_LSI:=${RCAR_M3N}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},10)
+        RCAR_LSI_CUT:=0
+      else ifeq (${LSI_CUT},11)
+        RCAR_LSI_CUT:=1
+      else
+        $(error "Error: ${LSI_CUT} is not supported.")
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else ifeq (${LSI},E3)
+    RCAR_LSI:=${RCAR_E3}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},10)
+        RCAR_LSI_CUT:=0
+      else ifeq (${LSI_CUT},11)
+        RCAR_LSI_CUT:=1
+      else
+        $(error "Error: ${LSI_CUT} is not supported.")
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else ifeq (${LSI},D3)
+    RCAR_LSI:=${RCAR_D3}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},10)
+        RCAR_LSI_CUT:=0
+      else
+        $(error "Error: ${LSI_CUT} is not supported.")
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else ifeq (${LSI},V3M)
+    RCAR_LSI:=${RCAR_V3M}
+    ifndef LSI_CUT
+      # enable compatible function.
+      RCAR_LSI_CUT_COMPAT := 1
+      $(eval $(call add_define,RCAR_LSI_CUT_COMPAT))
+    else
+      # disable compatible function.
+      ifeq (${LSI_CUT},10)
+        RCAR_LSI_CUT:=0
+      endif
+      ifeq (${LSI_CUT},20)
+        RCAR_LSI_CUT:=10
+      endif
+      $(eval $(call add_define,RCAR_LSI_CUT))
+    endif
+  else
+    $(error "Error: ${LSI} is not supported.")
+  endif
+  $(eval $(call add_define,RCAR_LSI))
+endif
+
+# lock RPC HYPERFLASH access by default
+# unlock to repogram the ATF firmware from u-boot
+ifndef RCAR_RPC_HYPERFLASH_LOCKED
+RCAR_RPC_HYPERFLASH_LOCKED := 1
+endif
+$(eval $(call add_define,RCAR_RPC_HYPERFLASH_LOCKED))
+
+# Process RCAR_SECURE_BOOT flag
+ifndef RCAR_SECURE_BOOT
+RCAR_SECURE_BOOT := 1
+endif
+$(eval $(call add_define,RCAR_SECURE_BOOT))
+
+# Process RCAR_QOS_TYPE flag
+ifndef RCAR_QOS_TYPE
+RCAR_QOS_TYPE := 0
+endif
+$(eval $(call add_define,RCAR_QOS_TYPE))
+
+# Process RCAR_DRAM_SPLIT flag
+ifndef RCAR_DRAM_SPLIT
+RCAR_DRAM_SPLIT := 0
+endif
+$(eval $(call add_define,RCAR_DRAM_SPLIT))
+
+# Process RCAR_BL33_EXECUTION_EL flag
+ifndef RCAR_BL33_EXECUTION_EL
+RCAR_BL33_EXECUTION_EL := 0
+endif
+$(eval $(call add_define,RCAR_BL33_EXECUTION_EL))
+
+# Process RCAR_AVS_SETTING_ENABLE flag
+ifeq (${RCAR_AVS_SETTING_ENABLE},0)
+AVS_SETTING_ENABLE := 0
+else
+AVS_SETTING_ENABLE := 1
+endif
+$(eval $(call add_define,AVS_SETTING_ENABLE))
+
+# Process RCAR_LOSSY_ENABLE flag
+ifndef RCAR_LOSSY_ENABLE
+RCAR_LOSSY_ENABLE := 0
+endif
+$(eval $(call add_define,RCAR_LOSSY_ENABLE))
+
+# Process LIFEC_DBSC_PROTECT_ENABLE flag
+ifndef LIFEC_DBSC_PROTECT_ENABLE
+LIFEC_DBSC_PROTECT_ENABLE := 1
+endif
+$(eval $(call add_define,LIFEC_DBSC_PROTECT_ENABLE))
+
+# Process PMIC_ROHM_BD9571 flag
+ifndef PMIC_ROHM_BD9571
+PMIC_ROHM_BD9571 := 1
+endif
+$(eval $(call add_define,PMIC_ROHM_BD9571))
+
+# Process PMIC_LEVEL_MODE flag
+ifndef PMIC_LEVEL_MODE
+PMIC_LEVEL_MODE := 1
+endif
+$(eval $(call add_define,PMIC_LEVEL_MODE))
+
+# Process RCAR_GEN3_ULCB flag
+ifndef RCAR_GEN3_ULCB
+RCAR_GEN3_ULCB := 0
+endif
+ifeq (${RCAR_GEN3_ULCB},1)
+ BOARD_DEFAULT := 0x10
+ $(eval $(call add_define,BOARD_DEFAULT))
+endif
+$(eval $(call add_define,RCAR_GEN3_ULCB))
+
+# Process RCAR_REF_INT flag
+ifndef RCAR_REF_INT
+RCAR_REF_INT :=0
+endif
+$(eval $(call add_define,RCAR_REF_INT))
+
+# Process RCAR_REWT_TRAINING flag
+ifndef RCAR_REWT_TRAINING
+RCAR_REWT_TRAINING := 1
+endif
+$(eval $(call add_define,RCAR_REWT_TRAINING))
+
+# Process RCAR_SYSTEM_SUSPEND flag
+ifndef RCAR_SYSTEM_SUSPEND
+RCAR_SYSTEM_SUSPEND := 1
+endif
+$(eval $(call add_define,RCAR_SYSTEM_SUSPEND))
+
+# SYSTEM_SUSPEND requires power control of PMIC etc.
+# When executing SYSTEM_SUSPEND other than Salvator-X, Salvator-XS and Ebisu,
+# processing equivalent to that implemented in PMIC_ROHM_BD9571 is necessary.
+ifeq (${RCAR_SYSTEM_SUSPEND},1)
+  ifeq (${PMIC_ROHM_BD9571},0)
+    $(error "Error: When you want RCAR_SYSTEM_SUSPEND to be enable, please also set PMIC_ROHM_BD9571 to enable.")
+  endif
+endif
+
+# Process RCAR_DRAM_LPDDR4_MEMCONF flag
+ifndef RCAR_DRAM_LPDDR4_MEMCONF
+RCAR_DRAM_LPDDR4_MEMCONF :=1
+endif
+$(eval $(call add_define,RCAR_DRAM_LPDDR4_MEMCONF))
+
+# Process RCAR_DRAM_DDR3L_MEMCONF flag
+ifndef RCAR_DRAM_DDR3L_MEMCONF
+RCAR_DRAM_DDR3L_MEMCONF :=1
+endif
+$(eval $(call add_define,RCAR_DRAM_DDR3L_MEMCONF))
+
+# Process RCAR_DRAM_DDR3L_MEMDUAL flag
+ifndef RCAR_DRAM_DDR3L_MEMDUAL
+RCAR_DRAM_DDR3L_MEMDUAL :=1
+endif
+$(eval $(call add_define,RCAR_DRAM_DDR3L_MEMDUAL))
+
+# Process RCAR_BL33_ARG0 flag
+ifdef RCAR_BL33_ARG0
+$(eval $(call add_define,RCAR_BL33_ARG0))
+endif
+
+#Process RCAR_BL2_DCACHE flag
+ifndef RCAR_BL2_DCACHE
+RCAR_BL2_DCACHE := 0
+endif
+$(eval $(call add_define,RCAR_BL2_DCACHE))
+
+# Process RCAR_DRAM_CHANNEL flag
+ifndef RCAR_DRAM_CHANNEL
+RCAR_DRAM_CHANNEL :=15
+endif
+$(eval $(call add_define,RCAR_DRAM_CHANNEL))
+
+#Process RCAR_SYSTEM_RESET_KEEPON_DDR flag
+ifndef RCAR_SYSTEM_RESET_KEEPON_DDR
+RCAR_SYSTEM_RESET_KEEPON_DDR := 0
+endif
+$(eval $(call add_define,RCAR_SYSTEM_RESET_KEEPON_DDR))
+
+# RCAR_SYSTEM_RESET_KEEPON_DDR requires power control of PMIC etc.
+# When executing SYSTEM_SUSPEND other than Salvator-X, Salvator-XS and Ebisu,
+# processing equivalent to that implemented in PMIC_ROHM_BD9571 is necessary.
+# Also, it is necessary to enable RCAR_SYSTEM_SUSPEND.
+ifeq (${RCAR_SYSTEM_RESET_KEEPON_DDR},1)
+  ifeq (${PMIC_ROHM_BD9571},0)
+    $(error "Error: When you want RCAR_SYSTEM_RESET_KEEPON_DDR to be enable, please also set PMIC_ROHM_BD9571 to enable.")
+  endif
+  ifeq (${RCAR_SYSTEM_SUSPEND},0)
+    $(error "Error: When you want RCAR_SYSTEM_RESET_KEEPON_DDR to be enable, please also set RCAR_SYSTEM_SUSPEND to enable.")
+  endif
+endif
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_835769  := 1
+ERRATA_A53_843419  := 1
+ERRATA_A53_855873  := 1
+
+# Enable workarounds for selected Cortex-A57 erratas.
+ERRATA_A57_859972  := 1
+ERRATA_A57_813419  := 1
+
+include drivers/staging/renesas/rcar/ddr/ddr.mk
+include drivers/renesas/rcar/qos/qos.mk
+include drivers/renesas/rcar/pfc/pfc.mk
+include lib/libfdt/libfdt.mk
+
+PLAT_INCLUDES	:=	-Idrivers/staging/renesas/rcar/ddr	\
+			-Idrivers/renesas/rcar/qos		\
+			-Idrivers/renesas/rcar/iic_dvfs		\
+			-Idrivers/renesas/rcar/board		\
+			-Idrivers/renesas/rcar/cpld/		\
+			-Idrivers/renesas/rcar/avs		\
+			-Idrivers/renesas/rcar/delay		\
+			-Idrivers/renesas/rcar/rom		\
+			-Idrivers/renesas/rcar/scif		\
+			-Idrivers/renesas/rcar/emmc		\
+			-Idrivers/renesas/rcar/pwrc		\
+			-Idrivers/renesas/rcar/io		\
+			-Iplat/renesas/rcar/include/registers	\
+			-Iplat/renesas/rcar/include		\
+			-Iplat/renesas/rcar
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/renesas/rcar/iic_dvfs/iic_dvfs.c \
+				plat/renesas/rcar/rcar_common.c
+
+RCAR_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+BL2_SOURCES	+=	${RCAR_GIC_SOURCES}				\
+			lib/cpus/aarch64/cortex_a53.S			\
+			lib/cpus/aarch64/cortex_a57.S			\
+			${LIBFDT_SRCS}					\
+			common/desc_image_load.c			\
+			plat/renesas/rcar/aarch64/platform_common.c	\
+			plat/renesas/rcar/aarch64/plat_helpers.S	\
+			plat/renesas/rcar/bl2_interrupt_error.c		\
+			plat/renesas/rcar/bl2_secure_setting.c		\
+			plat/renesas/rcar/bl2_plat_setup.c		\
+			plat/renesas/rcar/plat_storage.c		\
+			plat/renesas/rcar/bl2_plat_mem_params_desc.c	\
+			plat/renesas/rcar/plat_image_load.c		\
+			plat/renesas/rcar/bl2_cpg_init.c		\
+			drivers/renesas/rcar/console/rcar_printf.c	\
+			drivers/renesas/rcar/scif/scif.S		\
+			drivers/renesas/rcar/common.c			\
+			drivers/renesas/rcar/io/io_emmcdrv.c		\
+			drivers/renesas/rcar/io/io_memdrv.c		\
+			drivers/renesas/rcar/io/io_rcar.c		\
+			drivers/renesas/rcar/auth/auth_mod.c		\
+			drivers/renesas/rcar/rpc/rpc_driver.c		\
+			drivers/renesas/rcar/dma/dma_driver.c		\
+			drivers/renesas/rcar/avs/avs_driver.c		\
+			drivers/renesas/rcar/delay/micro_delay.c	\
+			drivers/renesas/rcar/emmc/emmc_interrupt.c	\
+			drivers/renesas/rcar/emmc/emmc_utility.c	\
+			drivers/renesas/rcar/emmc/emmc_mount.c		\
+			drivers/renesas/rcar/emmc/emmc_init.c		\
+			drivers/renesas/rcar/emmc/emmc_read.c		\
+			drivers/renesas/rcar/emmc/emmc_cmd.c		\
+			drivers/renesas/rcar/watchdog/swdt.c		\
+			drivers/renesas/rcar/rom/rom_api.c		\
+			drivers/renesas/rcar/board/board.c		\
+			drivers/io/io_storage.c
+
+BL31_SOURCES	+=	${RCAR_GIC_SOURCES}				\
+			lib/cpus/aarch64/cortex_a53.S			\
+			lib/cpus/aarch64/cortex_a57.S			\
+			plat/common/plat_psci_common.c			\
+			plat/renesas/rcar/plat_topology.c		\
+			plat/renesas/rcar/aarch64/plat_helpers.S	\
+			plat/renesas/rcar/aarch64/platform_common.c	\
+			plat/renesas/rcar/bl31_plat_setup.c		\
+			plat/renesas/rcar/plat_pm.c			\
+			drivers/renesas/rcar/console/rcar_console.S	\
+			drivers/renesas/rcar/console/rcar_printf.c	\
+			drivers/renesas/rcar/delay/micro_delay.c	\
+			drivers/renesas/rcar/pwrc/call_sram.S		\
+			drivers/renesas/rcar/pwrc/pwrc.c		\
+			drivers/renesas/rcar/common.c			\
+			drivers/arm/cci/cci.c
+
+ifeq (${RCAR_GEN3_ULCB},1)
+BL31_SOURCES		+=	drivers/renesas/rcar/cpld/ulcb_cpld.c
+endif
+
+include lib/xlat_tables_v2/xlat_tables.mk
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+PLAT_BL_COMMON_SOURCES	+=	${XLAT_TABLES_LIB_SRCS}
+
+# build the layout images for the bootrom and the necessary srecords
+rcar: rcar_layout_tool rcar_srecord
+distclean realclean clean: clean_layout_tool clean_srecord
+
+# layout images
+LAYOUT_TOOLPATH ?= tools/renesas/rcar_layout_create
+
+clean_layout_tool:
+	@echo "clean layout tool"
+	${Q}${MAKE} -C ${LAYOUT_TOOLPATH} clean
+
+.PHONY: rcar_layout_tool
+rcar_layout_tool:
+	@echo "generating layout srecs"
+	${Q}${MAKE} CPPFLAGS="-D=AARCH64" --no-print-directory -C ${LAYOUT_TOOLPATH}
+
+# srecords
+SREC_PATH	= ${BUILD_PLAT}
+BL2_ELF_SRC	= ${SREC_PATH}/bl2/bl2.elf
+BL31_ELF_SRC	= ${SREC_PATH}/bl31/bl31.elf
+
+clean_srecord:
+	@echo "clean bl2 and bl31 srecs"
+	rm -f ${SREC_PATH}/bl2.srec ${SREC_PATH}/bl31.srec
+
+.PHONY: rcar_srecord
+rcar_srecord: $(BL2_ELF_SRC) $(BL31_ELF_SRC)
+	@echo "generating srec: ${SREC_PATH}/bl2.srec"
+	$(Q)$(OC) -O srec --srec-forceS3 ${BL2_ELF_SRC}  ${SREC_PATH}/bl2.srec
+	@echo "generating srec: ${SREC_PATH}/bl31.srec"
+	$(Q)$(OC) -O srec --srec-forceS3 ${BL31_ELF_SRC} ${SREC_PATH}/bl31.srec
+
diff --git a/plat/renesas/rcar/rcar_common.c b/plat/renesas/rcar/rcar_common.c
new file mode 100644
index 0000000..4ea753f
--- /dev/null
+++ b/plat/renesas/rcar/rcar_common.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <drivers/console.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+#include <lib/mmio.h>
+
+#define CPG_BASE		0xE6150000
+#define CPG_MSTPSR3		0x0048
+#define MSTP318			(1 << 18)
+#define MSTP319			(1 << 19)
+#define PMSR			0x5c
+#define PMSR_L1FAEG		(1U << 31)
+#define PMSR_PMEL1RX		(1 << 23)
+#define PMCTLR			0x60
+#define PMSR_L1IATN		(1U << 31)
+
+static int rcar_pcie_fixup(unsigned int controller)
+{
+	uint32_t rcar_pcie_base[] = { 0xfe011000, 0xee811000 };
+	uint32_t addr = rcar_pcie_base[controller];
+	uint32_t cpg, pmsr;
+	int ret = 0;
+
+	/* Test if PCIECx is enabled */
+	cpg = mmio_read_32(CPG_BASE + CPG_MSTPSR3);
+	if (cpg & (MSTP318 << !controller))
+		return ret;
+
+	pmsr = mmio_read_32(addr + PMSR);
+
+	if ((pmsr & PMSR_PMEL1RX) && ((pmsr & 0x70000) != 0x30000)) {
+		/* Fix applicable */
+		mmio_write_32(addr + PMCTLR, PMSR_L1IATN);
+		while (!(mmio_read_32(addr + PMSR) & PMSR_L1FAEG))
+			;
+		mmio_write_32(addr + PMSR, PMSR_L1FAEG | PMSR_PMEL1RX);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/* RAS functions common to AArch64 ARM platforms */
+void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
+		void *handle, uint64_t flags)
+{
+	unsigned int fixed = 0;
+
+	fixed |= rcar_pcie_fixup(0);
+	fixed |= rcar_pcie_fixup(1);
+
+	if (fixed)
+		return;
+
+	ERROR("Unhandled External Abort received on 0x%lx at EL3!\n",
+			read_mpidr_el1());
+	ERROR(" exception reason=%u syndrome=0x%llx\n", ea_reason, syndrome);
+
+	panic();
+}
+
+#include <drivers/renesas/rcar/console/console.h>
+
+static console_rcar_t rcar_boot_console;
+static console_rcar_t rcar_runtime_console;
+
+void rcar_console_boot_init(void)
+{
+	int ret;
+
+	ret = console_rcar_register(0, 0, 0, &rcar_boot_console);
+	if (!ret)
+		panic();
+
+	console_set_scope(&rcar_boot_console.console, CONSOLE_FLAG_BOOT);
+}
+
+void rcar_console_boot_end(void)
+{
+}
+
+void rcar_console_runtime_init(void)
+{
+	int ret;
+
+	ret = console_rcar_register(1, 0, 0, &rcar_runtime_console);
+	if (!ret)
+		panic();
+
+	console_set_scope(&rcar_boot_console.console, CONSOLE_FLAG_RUNTIME);
+}
+
+void rcar_console_runtime_end(void)
+{
+}
diff --git a/plat/rockchip/common/aarch32/plat_helpers.S b/plat/rockchip/common/aarch32/plat_helpers.S
new file mode 100644
index 0000000..475c297
--- /dev/null
+++ b/plat/rockchip/common/aarch32/plat_helpers.S
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a12.h>
+#include <plat_private.h>
+#include <plat_pmu_macros.S>
+
+	.globl	cpuson_entry_point
+	.globl	cpuson_flags
+	.globl	platform_cpu_warmboot
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_report_exception
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_panic_handler
+
+	/*
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the SOC type and call the appropriate reset
+	 * handler.
+	 *
+	 */
+func plat_reset_handler
+	bx	lr
+endfunc plat_reset_handler
+
+func plat_my_core_pos
+	ldcopr	r0, MPIDR
+	and	r1, r0, #MPIDR_CPU_MASK
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+	and	r0, r0, #PLAT_RK_MPIDR_CLUSTER_MASK
+#else
+	and	r0, r0, #MPIDR_CLUSTER_MASK
+#endif
+	add	r0, r1, r0, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT
+	bx	lr
+endfunc plat_my_core_pos
+
+	/* --------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * --------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* rk3288 does not do cold boot for secondary CPU */
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+	ldcopr	r0, MPIDR
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+	ldr	r1, =(PLAT_RK_MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+#else
+	ldr	r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+#endif
+	and	r0, r1
+	cmp	r0, #PLAT_RK_PRIMARY_CPU
+	moveq	r0, #1
+	movne	r0, #0
+	bx	lr
+endfunc plat_is_my_cpu_primary
+
+	/* --------------------------------------------------------------------
+	 * void plat_panic_handler(void)
+	 * Call system reset function on panic. Set up an emergency stack so we
+	 * can run C functions (it only needs to last for a few calls until we
+	 * reboot anyway).
+	 * --------------------------------------------------------------------
+	 */
+func plat_panic_handler
+	bl	plat_set_my_stack
+	b	rockchip_soc_soft_reset
+endfunc plat_panic_handler
+
+	/* --------------------------------------------------------------------
+	 * void platform_cpu_warmboot (void);
+	 * cpus online or resume entrypoint
+	 * --------------------------------------------------------------------
+	 */
+func platform_cpu_warmboot _align=16
+	push	{ r4 - r7, lr }
+	ldcopr	r0, MPIDR
+	and	r5, r0, #MPIDR_CPU_MASK
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+	and	r6, r0, #PLAT_RK_MPIDR_CLUSTER_MASK
+#else
+	and	r6, r0, #MPIDR_CLUSTER_MASK
+#endif
+	mov	r0, r6
+
+	func_rockchip_clst_warmboot
+	/* --------------------------------------------------------------------
+	 * big cluster id is 1
+	 * big cores id is from 0-3, little cores id 4-7
+	 * --------------------------------------------------------------------
+	 */
+	add	r7, r5, r6, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT
+	/* --------------------------------------------------------------------
+	 * get per cpuup flag
+         * --------------------------------------------------------------------
+	 */
+	ldr	r4, =cpuson_flags
+	add	r4, r4, r7, lsl #2
+	ldr	r1, [r4]
+	/* --------------------------------------------------------------------
+	 * check cpuon reason
+         * --------------------------------------------------------------------
+	 */
+	cmp	r1, #PMU_CPU_AUTO_PWRDN
+	beq	boot_entry
+	cmp	r1, #PMU_CPU_HOTPLUG
+	beq	boot_entry
+	/* --------------------------------------------------------------------
+	 * If the boot core cpuson_flags or cpuson_entry_point is not
+	 * expection. force the core into wfe.
+	 * --------------------------------------------------------------------
+	 */
+wfe_loop:
+	wfe
+	b	wfe_loop
+boot_entry:
+	mov	r1, #0
+	str	r1, [r4]
+	/* --------------------------------------------------------------------
+	 * get per cpuup boot addr
+	 * --------------------------------------------------------------------
+	 */
+	ldr	r5, =cpuson_entry_point
+	ldr	r2, [r5, r7, lsl #2] /* ehem. #3 */
+	pop	{ r4 - r7, lr }
+
+	bx	r2
+endfunc platform_cpu_warmboot
+
+	/* --------------------------------------------------------------------
+	 * Per-CPU Secure entry point - resume or power up
+	 * --------------------------------------------------------------------
+	 */
+	.section tzfw_coherent_mem, "a"
+	.align  3
+cpuson_entry_point:
+	.rept	PLATFORM_CORE_COUNT
+	.quad	0
+	.endr
+cpuson_flags:
+	.rept	PLATFORM_CORE_COUNT
+	.word	0
+	.endr
+rockchip_clst_warmboot_data
diff --git a/plat/rockchip/common/aarch32/platform_common.c b/plat/rockchip/common/aarch32/platform_common.c
new file mode 100644
index 0000000..9030951
--- /dev/null
+++ b/plat/rockchip/common/aarch32/platform_common.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <plat_private.h>
+
+void plat_configure_mmu_svc_mon(unsigned long total_base,
+				unsigned long total_size,
+				unsigned long ro_start,
+				unsigned long ro_limit,
+				unsigned long coh_start,
+				unsigned long coh_limit)
+{
+	mmap_add_region(total_base, total_base, total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+	mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+			MT_MEMORY | MT_RO | MT_SECURE);
+	mmap_add_region(coh_start, coh_start, coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+	mmap_add(plat_rk_mmap);
+	rockchip_plat_mmu_svc_mon();
+	init_xlat_tables();
+	enable_mmu_svc_mon(0);
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+/*
+ * generic pm code does cci handling, but rockchip arm32 platforms
+ * have ever only 1 cluster, so nothing to do.
+ */
+void plat_cci_init(void)
+{
+}
+
+void plat_cci_enable(void)
+{
+}
+
+void plat_cci_disable(void)
+{
+}
diff --git a/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S
new file mode 100644
index 0000000..a05ae54
--- /dev/null
+++ b/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl pmu_cpuson_entrypoint
+	.macro pmusram_entry_func _name
+	.section .pmusram.entry, "ax"
+	.type \_name, %function
+	.cfi_startproc
+	\_name:
+	.endm
+
+pmusram_entry_func pmu_cpuson_entrypoint
+
+#if PSRAM_CHECK_WAKEUP_CPU
+check_wake_cpus:
+	ldcopr	r0, MPIDR
+	and	r1, r0, #MPIDR_CPU_MASK
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+	and	r0, r0, #PLAT_RK_MPIDR_CLUSTER_MASK
+#else
+	and	r0, r0, #MPIDR_CLUSTER_MASK
+#endif
+	orr	r0, r0, r1
+
+	/* primary_cpu */
+	ldr	r1, boot_mpidr
+	cmp	r0, r1
+	beq	sys_wakeup
+
+	/*
+	 * If the core is not the primary cpu,
+	 * force the core into wfe.
+	 */
+wfe_loop:
+	wfe
+	b	wfe_loop
+sys_wakeup:
+#endif
+
+#if PSRAM_DO_DDR_RESUME
+ddr_resume:
+	ldr	r2, =__bl32_sram_stack_end
+	mov     sp, r2
+	bl	dmc_resume
+#endif
+	bl	sram_restore
+sys_resume:
+	bl	sp_min_warm_entrypoint
+endfunc pmu_cpuson_entrypoint
diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
new file mode 100644
index 0000000..4af052b
--- /dev/null
+++ b/plat/rockchip/common/aarch64/plat_helpers.S
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <cortex_a53.h>
+#include <cortex_a72.h>
+#include <plat_private.h>
+#include <plat_pmu_macros.S>
+
+	.globl	cpuson_entry_point
+	.globl	cpuson_flags
+	.globl	platform_cpu_warmboot
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_report_exception
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_panic_handler
+
+	/*
+	 * void plat_reset_handler(void);
+	 *
+	 * Determine the SOC type and call the appropriate reset
+	 * handler.
+	 *
+	 */
+func plat_reset_handler
+	mrs x0, midr_el1
+	ubfx x0, x0, MIDR_PN_SHIFT, #12
+	cmp w0, #((CORTEX_A72_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+	b.eq	handler_a72
+	b	handler_end
+handler_a72:
+	/*
+	 * This handler does the following:
+	 * Set the L2 Data RAM latency for Cortex-A72.
+	 * Set the L2 Tag RAM latency to for Cortex-A72.
+	 */
+	mov x0, #((5 << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) |	\
+			 (0x1 << 5))
+	msr	CORTEX_A72_L2CTLR_EL1, x0
+	isb
+handler_end:
+	ret
+endfunc plat_reset_handler
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT
+	ret
+endfunc plat_my_core_pos
+
+	/* --------------------------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * --------------------------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* rk3368 does not do cold boot for secondary CPU */
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #PLAT_RK_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* --------------------------------------------------------------------
+	 * void plat_panic_handler(void)
+	 * Call system reset function on panic. Set up an emergency stack so we
+	 * can run C functions (it only needs to last for a few calls until we
+	 * reboot anyway).
+	 * --------------------------------------------------------------------
+	 */
+func plat_panic_handler
+	msr	spsel, #0
+	bl	plat_set_my_stack
+	b	rockchip_soc_soft_reset
+endfunc plat_panic_handler
+
+	/* --------------------------------------------------------------------
+	 * void platform_cpu_warmboot (void);
+	 * cpus online or resume enterpoint
+	 * --------------------------------------------------------------------
+	 */
+func platform_cpu_warmboot _align=16
+	mrs	x0, MPIDR_EL1
+	and	x19, x0, #MPIDR_CPU_MASK
+	and	x20, x0, #MPIDR_CLUSTER_MASK
+	mov	x0, x20
+	func_rockchip_clst_warmboot
+	/* --------------------------------------------------------------------
+	 * big cluster id is 1
+	 * big cores id is from 0-3, little cores id 4-7
+	 * --------------------------------------------------------------------
+	 */
+	add	x21, x19, x20, lsr #PLAT_RK_CLST_TO_CPUID_SHIFT
+	/* --------------------------------------------------------------------
+	 * get per cpuup flag
+         * --------------------------------------------------------------------
+	 */
+	adr	x4, cpuson_flags
+	add	x4, x4, x21, lsl #2
+	ldr	w1, [x4]
+	/* --------------------------------------------------------------------
+	 * check cpuon reason
+         * --------------------------------------------------------------------
+	 */
+	cmp	w1, PMU_CPU_AUTO_PWRDN
+	b.eq	boot_entry
+	cmp	w1, PMU_CPU_HOTPLUG
+	b.eq	boot_entry
+	/* --------------------------------------------------------------------
+	 * If the boot core cpuson_flags or cpuson_entry_point is not
+	 * expection. force the core into wfe.
+         * --------------------------------------------------------------------
+	 */
+wfe_loop:
+	wfe
+	b	wfe_loop
+boot_entry:
+	str	wzr, [x4]
+	/* --------------------------------------------------------------------
+	 * get per cpuup boot addr
+	 * --------------------------------------------------------------------
+	 */
+	adr	x5, cpuson_entry_point
+	ldr	x2, [x5, x21, lsl #3]
+	br	x2
+endfunc platform_cpu_warmboot
+
+	/* --------------------------------------------------------------------
+	 * Per-CPU Secure entry point - resume or power up
+	 * --------------------------------------------------------------------
+	 */
+	.section tzfw_coherent_mem, "a"
+	.align  3
+cpuson_entry_point:
+	.rept	PLATFORM_CORE_COUNT
+	.quad	0
+	.endr
+cpuson_flags:
+	.rept	PLATFORM_CORE_COUNT
+	.word	0
+	.endr
+rockchip_clst_warmboot_data
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
new file mode 100644
index 0000000..81e8520
--- /dev/null
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables.h>
+
+#include <plat_private.h>
+
+#ifdef PLAT_RK_CCI_BASE
+static const int cci_map[] = {
+	PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX
+};
+#endif
+
+/******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+#define DEFINE_CONFIGURE_MMU_EL(_el)					\
+	void plat_configure_mmu_el ## _el(unsigned long total_base,	\
+					  unsigned long total_size,	\
+					  unsigned long ro_start,	\
+					  unsigned long ro_limit,	\
+					  unsigned long coh_start,	\
+					  unsigned long coh_limit)	\
+	{								\
+		mmap_add_region(total_base, total_base,			\
+				total_size,				\
+				MT_MEMORY | MT_RW | MT_SECURE);		\
+		mmap_add_region(ro_start, ro_start,			\
+				ro_limit - ro_start,			\
+				MT_MEMORY | MT_RO | MT_SECURE);		\
+		mmap_add_region(coh_start, coh_start,			\
+				coh_limit - coh_start,			\
+				MT_DEVICE | MT_RW | MT_SECURE);		\
+		mmap_add(plat_rk_mmap);					\
+		rockchip_plat_mmu_el##_el();				\
+		init_xlat_tables();					\
+									\
+		enable_mmu_el ## _el(0);				\
+	}
+
+/* Define EL3 variants of the function initialising the MMU */
+DEFINE_CONFIGURE_MMU_EL(3)
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void plat_cci_init(void)
+{
+#ifdef PLAT_RK_CCI_BASE
+	/* Initialize CCI driver */
+	cci_init(PLAT_RK_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
+#endif
+}
+
+void plat_cci_enable(void)
+{
+	/*
+	 * Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+#ifdef PLAT_RK_CCI_BASE
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+#endif
+}
+
+void plat_cci_disable(void)
+{
+#ifdef PLAT_RK_CCI_BASE
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+#endif
+}
diff --git a/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
new file mode 100644
index 0000000..d91ee0e
--- /dev/null
+++ b/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl pmu_cpuson_entrypoint
+	.macro pmusram_entry_func _name
+	.section .pmusram.entry, "ax"
+	.type \_name, %function
+	.cfi_startproc
+	\_name:
+	.endm
+
+pmusram_entry_func pmu_cpuson_entrypoint
+
+#if PSRAM_CHECK_WAKEUP_CPU
+check_wake_cpus:
+	mrs	x0, MPIDR_EL1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	orr	x0, x0, x1
+
+	/* primary_cpu */
+	ldr	w1, boot_mpidr
+	cmp	w0, w1
+	b.eq	sys_wakeup
+
+	/*
+	 * If the core is not the primary cpu,
+	 * force the core into wfe.
+	 */
+wfe_loop:
+	wfe
+	b	wfe_loop
+sys_wakeup:
+#endif
+
+#if PSRAM_DO_DDR_RESUME
+ddr_resume:
+	ldr	x2, =__bl31_sram_stack_end
+	mov     sp, x2
+	bl	dmc_resume
+#endif
+	bl	sram_restore
+sys_resume:
+	bl	bl31_warm_entrypoint
+endfunc pmu_cpuson_entrypoint
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
new file mode 100644
index 0000000..11321d7
--- /dev/null
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+#pragma weak params_early_setup
+void params_early_setup(u_register_t plat_param_from_bl2)
+{
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	static console_16550_t console;
+	struct rockchip_bl31_params *arg_from_bl2 = (struct rockchip_bl31_params *) arg0;
+
+	params_early_setup(arg1);
+
+	if (rockchip_get_uart_base() != 0)
+		console_16550_register(rockchip_get_uart_base(),
+				       rockchip_get_uart_clock(),
+				       rockchip_get_uart_baudrate(), &console);
+
+	VERBOSE("bl31_setup\n");
+
+	/* Passing a NULL context is a critical programming error */
+	assert(arg_from_bl2);
+
+	assert(arg_from_bl2->h.type == PARAM_BL31);
+	assert(arg_from_bl2->h.version >= VERSION_1);
+
+	bl32_ep_info = *arg_from_bl2->bl32_ep_info;
+	bl33_ep_info = *arg_from_bl2->bl33_ep_info;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+	generic_delay_timer_init();
+	plat_rockchip_soc_init();
+
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_rockchip_gic_driver_init();
+	plat_rockchip_gic_init();
+	plat_rockchip_pmu_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	plat_cci_init();
+	plat_cci_enable();
+	plat_configure_mmu_el3(BL_CODE_BASE,
+			       BL_COHERENT_RAM_END - BL_CODE_BASE,
+			       BL_CODE_BASE,
+			       BL_CODE_END,
+			       BL_COHERENT_RAM_BASE,
+			       BL_COHERENT_RAM_END);
+}
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.c b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
new file mode 100644
index 0000000..e89fe1e
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#include "ddr_parameter.h"
+
+/*
+ *  The miniloader delivers the parameters about ddr usage info from address
+ * 0x02000000 and the data format is defined as below figure. It tells ATF the
+ * areas of ddr that are used by platform, we treat them as non-secure regions
+ * by default. Then we should parse the other part regions and configurate them
+ * as secure regions to avoid illegal access.
+ *
+ *			[ddr usage info data format]
+ * 0x02000000
+ * -----------------------------------------------------------------------------
+ * |       <name>        |  <size>   |      <description>                      |
+ * -----------------------------------------------------------------------------
+ * | count               |  4byte    | the array numbers of the                |
+ * |                     |           | 'addr_array' and 'size_array'           |
+ * -----------------------------------------------------------------------------
+ * | reserved            |  4byte    | just for 'addr_array' 8byte aligned     |
+ * -----------------------------------------------------------------------------
+ * | addr_array[count]   | per 8byte | memory region base address              |
+ * -----------------------------------------------------------------------------
+ * | size_array[count]   | per 8byte | memory region size (byte)               |
+ * -----------------------------------------------------------------------------
+ */
+
+/*
+ * function: read parameters info(ns-regions) and try to parse s-regions info
+ *
+ * @addr: head address to the ddr usage struct from miniloader
+ * @max_mb: the max ddr capacity(MB) that the platform support
+ */
+struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb)
+{
+	uint64_t base, top;
+	uint32_t i, addr_offset, size_offset;
+	struct param_ddr_usage p;
+
+	memset(&p, 0, sizeof(p));
+
+	/* read how many blocks of ns-regions, read from offset: 0x0 */
+	p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET);
+	if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) {
+		ERROR("over or zero region, nr=%d, max=%d\n",
+		      p.ns_nr, DDR_REGION_NR_MAX);
+		return p;
+	}
+
+	/* whole ddr regions boundary, it will be used when parse s-regions */
+	p.boundary = max_mb;
+
+	/* calculate ns-region base addr and size offset */
+	addr_offset = REGION_ADDR_OFFSET;
+	size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES;
+
+	/* read all ns-regions base and top address */
+	for (i = 0; i < p.ns_nr; i++) {
+		base = mmio_read_64(addr + addr_offset);
+		top = base + mmio_read_64(addr + size_offset);
+		/*
+		 * translate byte to MB and store info,
+		 * Miniloader will promise every ns-region is MB aligned.
+		 */
+		p.ns_base[i] = RG_SIZE_MB(base);
+		p.ns_top[i] = RG_SIZE_MB(top);
+
+		addr_offset += REGION_DATA_PER_BYTES;
+		size_offset += REGION_DATA_PER_BYTES;
+	}
+
+	/*
+	 * a s-region's base starts from previous ns-region's top, and a
+	 * s-region's top ends with next ns-region's base. maybe like this:
+	 *
+	 *	   case1: ns-regison start from 0MB
+	 *	 -----------------------------------------------
+	 *	 |    ns0   |  S0  |  ns1  |   S1  |    ns2    |
+	 *	0----------------------------------------------- max_mb
+	 *
+	 *
+	 *	   case2: ns-regison not start from 0MB
+	 *	 -----------------------------------------------
+	 *	 |    S0   |  ns0  |  ns1  |   ns2  |    S1    |
+	 *	0----------------------------------------------- max_mb
+	 */
+
+	/* like above case2 figure, ns-region is not start from 0MB */
+	if (p.ns_base[0] != 0) {
+		p.s_base[p.s_nr] = 0;
+		p.s_top[p.s_nr] = p.ns_base[0];
+		p.s_nr++;
+	}
+
+	/*
+	 * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0
+	 */
+	for (i = 0; i < p.ns_nr; i++) {
+		/*
+		 * if current ns-regions top covers boundary,
+		 * that means s-regions are all parsed yet, so finsh.
+		 */
+		if (p.ns_top[i] == p.boundary)
+			goto out;
+
+		/* s-region's base starts from previous ns-region's top */
+		p.s_base[p.s_nr] = p.ns_top[i];
+
+		/* s-region's top ends with next ns-region's base */
+		if (i + 1 < p.ns_nr)
+			p.s_top[p.s_nr] = p.ns_base[i + 1];
+		else
+			p.s_top[p.s_nr] = p.boundary;
+		p.s_nr++;
+	}
+out:
+	return p;
+}
diff --git a/plat/rockchip/common/drivers/parameter/ddr_parameter.h b/plat/rockchip/common/drivers/parameter/ddr_parameter.h
new file mode 100644
index 0000000..61349c4
--- /dev/null
+++ b/plat/rockchip/common/drivers/parameter/ddr_parameter.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DDR_PARAMETER_H
+#define DDR_PARAMETER_H
+
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+#define DDR_REGION_NR_MAX		10
+#define REGION_NR_OFFSET		0
+#define REGION_ADDR_OFFSET		8
+#define REGION_DATA_PER_BYTES		8
+#define RG_SIZE_MB(byte)		((byte) >> 20)
+
+/* unit: MB */
+struct param_ddr_usage {
+	uint64_t boundary;
+
+	uint32_t ns_nr;
+	uint64_t ns_base[DDR_REGION_NR_MAX];
+	uint64_t ns_top[DDR_REGION_NR_MAX];
+
+	uint32_t s_nr;
+	uint64_t s_base[DDR_REGION_NR_MAX];
+	uint64_t s_top[DDR_REGION_NR_MAX];
+};
+
+struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb);
+
+#endif /* DDR_PARAMETER_H */
diff --git a/plat/rockchip/common/drivers/pmu/pmu_com.h b/plat/rockchip/common/drivers/pmu/pmu_com.h
new file mode 100644
index 0000000..5359f73
--- /dev/null
+++ b/plat/rockchip/common/drivers/pmu/pmu_com.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_COM_H
+#define PMU_COM_H
+
+#ifndef CHECK_CPU_WFIE_BASE
+#define CHECK_CPU_WFIE_BASE (PMU_BASE + PMU_CORE_PWR_ST)
+#endif
+/*
+ * Use this macro to instantiate lock before it is used in below
+ * rockchip_pd_lock_xxx() macros
+ */
+DECLARE_BAKERY_LOCK(rockchip_pd_lock);
+
+/*
+ * These are wrapper macros to the powe domain Bakery Lock API.
+ */
+#define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock)
+#define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock)
+#define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock)
+
+/*****************************************************************************
+ * power domain on or off
+ *****************************************************************************/
+enum pmu_pd_state {
+	pmu_pd_on = 0,
+	pmu_pd_off = 1
+};
+
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak pmu_power_domain_ctr
+#pragma weak check_cpu_wfie
+
+static inline uint32_t pmu_power_domain_st(uint32_t pd)
+{
+	uint32_t pwrdn_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST) &  BIT(pd);
+
+	if (pwrdn_st)
+		return pmu_pd_off;
+	else
+		return pmu_pd_on;
+}
+
+static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
+{
+	uint32_t val;
+	uint32_t loop = 0;
+	int ret = 0;
+
+	rockchip_pd_lock_get();
+
+	val = mmio_read_32(PMU_BASE + PMU_PWRDN_CON);
+	if (pd_state == pmu_pd_off)
+		val |=  BIT(pd);
+	else
+		val &= ~BIT(pd);
+
+	mmio_write_32(PMU_BASE + PMU_PWRDN_CON, val);
+	dsb();
+
+	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if (pmu_power_domain_st(pd) != pd_state) {
+		WARN("%s: %d, %d, error!\n", __func__, pd, pd_state);
+		ret = -EINVAL;
+	}
+
+	rockchip_pd_lock_rls();
+
+	return ret;
+}
+
+static int check_cpu_wfie(uint32_t cpu_id, uint32_t wfie_msk)
+{
+	uint32_t cluster_id, loop = 0;
+
+	if (cpu_id >= PLATFORM_CLUSTER0_CORE_COUNT) {
+		cluster_id = 1;
+		cpu_id -= PLATFORM_CLUSTER0_CORE_COUNT;
+	} else {
+		cluster_id = 0;
+	}
+
+	/*
+	 * wfe/wfi tracking not possible, hopefully the host
+	 * was sucessful in enabling wfe/wfi.
+	 * We'll give a bit of additional time, like the kernel does.
+	 */
+	if ((cluster_id && clstb_cpu_wfe < 0) ||
+	    (!cluster_id && clstl_cpu_wfe < 0)) {
+		mdelay(1);
+		return 0;
+	}
+
+	if (cluster_id)
+		wfie_msk <<= (clstb_cpu_wfe + cpu_id);
+	else
+		wfie_msk <<= (clstl_cpu_wfe + cpu_id);
+
+	while (!(mmio_read_32(CHECK_CPU_WFIE_BASE) & wfie_msk) &&
+	       (loop < CHK_CPU_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if ((mmio_read_32(CHECK_CPU_WFIE_BASE) & wfie_msk) == 0) {
+		WARN("%s: %d, %d, %d, error!\n", __func__,
+		     cluster_id, cpu_id, wfie_msk);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#endif /* PMU_COM_H */
diff --git a/plat/rockchip/common/include/plat_macros.S b/plat/rockchip/common/include/plat_macros.S
new file mode 100644
index 0000000..691beeb
--- /dev/null
+++ b/plat/rockchip/common/include/plat_macros.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_MACROS_S
+#define ROCKCHIP_PLAT_MACROS_S
+
+#include <drivers/arm/cci.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+	.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ---------------------------------------------
+	 * The below utility macro prints out relevant GIC
+	 * and CCI registers whenever an unhandled
+	 * exception is taken in BL31.
+	 * Expects: GICD base in x26, GICC base in x27
+	 * Clobbers: x0 - x10, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+
+	mov_imm	x26, PLAT_RK_GICD_BASE
+	mov_imm	x27, PLAT_RK_GICC_BASE
+
+	/* Check for GICv3 system register access */
+	mrs	x7, id_aa64pfr0_el1
+	ubfx	x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x7, #1
+	b.ne	print_gicv2
+
+	/* Check for SRE enable */
+	mrs	x8, ICC_SRE_EL3
+	tst	x8, #ICC_SRE_SRE_BIT
+	b.eq	print_gicv2
+
+	/* Load the icc reg list to x6 */
+	adr	x6, icc_regs
+	/* Load the icc regs to gp regs used by str_in_crash_buf_print */
+	mrs	x8, ICC_HPPIR0_EL1
+	mrs	x9, ICC_HPPIR1_EL1
+	mrs	x10, ICC_CTLR_EL3
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	b	print_gic_common
+
+print_gicv2:
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x27, #GICC_HPPIR]
+	ldr	w9, [x27, #GICC_AHPPIR]
+	ldr	w10, [x27, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+print_gic_common:
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x26, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x26
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+
+#if PLATFORM_CLUSTER_COUNT > 1
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_RK_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_RK_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+#endif
+	.endm
+
+#endif /* ROCKCHIP_PLAT_MACROS_S */
diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h
new file mode 100644
index 0000000..95b850f
--- /dev/null
+++ b/plat/rockchip/common/include/plat_params.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PARAMS_H
+#define PLAT_PARAMS_H
+
+#include <stdint.h>
+
+#include <export/plat/rockchip/common/plat_params_exp.h>
+
+#endif /* PLAT_PARAMS_H */
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
new file mode 100644
index 0000000..63ebd4b
--- /dev/null
+++ b/plat/rockchip/common/include/plat_private.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <lib/mmio.h>
+#include <plat_params.h>
+
+#define __sramdata __attribute__((section(".sram.data")))
+#define __sramconst __attribute__((section(".sram.rodata")))
+#define __sramfunc __attribute__((section(".sram.text")))
+
+#define __pmusramdata __attribute__((section(".pmusram.data")))
+#define __pmusramconst __attribute__((section(".pmusram.rodata")))
+#define __pmusramfunc __attribute__((section(".pmusram.text")))
+
+extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end;
+extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
+extern uint32_t __bl31_sram_stack_start, __bl31_sram_stack_end;
+extern uint32_t __bl31_sram_text_real_end, __bl31_sram_data_real_end;
+extern uint32_t __sram_incbin_start, __sram_incbin_end;
+extern uint32_t __sram_incbin_real_end;
+
+struct rockchip_bl31_params {
+       param_header_t h;
+       image_info_t *bl31_image_info;
+       entry_point_info_t *bl32_ep_info;
+       image_info_t *bl32_image_info;
+       entry_point_info_t *bl33_ep_info;
+       image_info_t *bl33_image_info;
+};
+
+/******************************************************************************
+ * The register have write-mask bits, it is mean, if you want to set the bits,
+ * you needs set the write-mask bits at the same time,
+ * The write-mask bits is in high 16-bits.
+ * The fllowing macro definition helps access write-mask bits reg efficient!
+ ******************************************************************************/
+#define REG_MSK_SHIFT	16
+
+#ifndef WMSK_BIT
+#define WMSK_BIT(nr)		BIT((nr) + REG_MSK_SHIFT)
+#endif
+
+/* set one bit with write mask */
+#ifndef BIT_WITH_WMSK
+#define BIT_WITH_WMSK(nr)	(BIT(nr) | WMSK_BIT(nr))
+#endif
+
+#ifndef BITS_SHIFT
+#define BITS_SHIFT(bits, shift)	(bits << (shift))
+#endif
+
+#ifndef BITS_WITH_WMASK
+#define BITS_WITH_WMASK(bits, msk, shift)\
+	(BITS_SHIFT(bits, shift) | BITS_SHIFT(msk, (shift + REG_MSK_SHIFT)))
+#endif
+
+/******************************************************************************
+ * Function and variable prototypes
+ *****************************************************************************/
+#ifdef __aarch64__
+void plat_configure_mmu_el3(unsigned long total_base,
+			    unsigned long total_size,
+			    unsigned long,
+			    unsigned long,
+			    unsigned long,
+			    unsigned long);
+
+void rockchip_plat_mmu_el3(void);
+#else
+void plat_configure_mmu_svc_mon(unsigned long total_base,
+				unsigned long total_size,
+				unsigned long,
+				unsigned long,
+				unsigned long,
+				unsigned long);
+
+void rockchip_plat_mmu_svc_mon(void);
+#endif
+
+void plat_cci_init(void);
+void plat_cci_enable(void);
+void plat_cci_disable(void);
+
+void plat_delay_timer_init(void);
+
+void params_early_setup(u_register_t plat_params_from_bl2);
+
+void plat_rockchip_gic_driver_init(void);
+void plat_rockchip_gic_init(void);
+void plat_rockchip_gic_cpuif_enable(void);
+void plat_rockchip_gic_cpuif_disable(void);
+void plat_rockchip_gic_pcpu_init(void);
+
+void plat_rockchip_pmu_init(void);
+void plat_rockchip_soc_init(void);
+uintptr_t plat_get_sec_entrypoint(void);
+
+void platform_cpu_warmboot(void);
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void);
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void);
+struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count);
+struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void);
+void plat_rockchip_gpio_init(void);
+void plat_rockchip_save_gpio(void);
+void plat_rockchip_restore_gpio(void);
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint);
+int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl,
+				 plat_local_state_t lvl_state);
+int rockchip_soc_cores_pwr_dm_off(void);
+int rockchip_soc_sys_pwr_dm_suspend(void);
+int rockchip_soc_cores_pwr_dm_suspend(void);
+int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl,
+				     plat_local_state_t lvl_state);
+int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl,
+				       plat_local_state_t lvl_state);
+int rockchip_soc_cores_pwr_dm_on_finish(void);
+int rockchip_soc_sys_pwr_dm_resume(void);
+
+int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl,
+				    plat_local_state_t lvl_state);
+int rockchip_soc_cores_pwr_dm_resume(void);
+void __dead2 rockchip_soc_soft_reset(void);
+void __dead2 rockchip_soc_system_off(void);
+void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(
+				const psci_power_state_t *target_state);
+void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void);
+
+extern const unsigned char rockchip_power_domain_tree_desc[];
+
+extern void *pmu_cpuson_entrypoint;
+extern u_register_t cpuson_entry_point[PLATFORM_CORE_COUNT];
+extern uint32_t cpuson_flags[PLATFORM_CORE_COUNT];
+
+extern const mmap_region_t plat_rk_mmap[];
+
+uint32_t rockchip_get_uart_base(void);
+uint32_t rockchip_get_uart_baudrate(void);
+uint32_t rockchip_get_uart_clock(void);
+
+#endif /* __ASSEMBLER__ */
+
+/******************************************************************************
+ * cpu up status
+ * The bits of macro value is not more than 12 bits for cmp instruction!
+ ******************************************************************************/
+#define PMU_CPU_HOTPLUG		0xf00
+#define PMU_CPU_AUTO_PWRDN	0xf0
+#define PMU_CLST_RET	0xa5
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/rockchip/common/include/rockchip_sip_svc.h b/plat/rockchip/common/include/rockchip_sip_svc.h
new file mode 100644
index 0000000..340d653
--- /dev/null
+++ b/plat/rockchip/common/include/rockchip_sip_svc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ROCKCHIP_SIP_SVC_H
+#define ROCKCHIP_SIP_SVC_H
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT		0x8200ff00
+#define SIP_SVC_UID			0x8200ff01
+#define SIP_SVC_VERSION			0x8200ff03
+
+/* rockchip SiP Service Calls version numbers */
+#define RK_SIP_SVC_VERSION_MAJOR	0x0
+#define RK_SIP_SVC_VERSION_MINOR	0x1
+
+/* Number of ROCKCHIP SiP Calls implemented */
+#define RK_COMMON_SIP_NUM_CALLS		0x3
+
+enum {
+	RK_SIP_E_SUCCESS = 0,
+	RK_SIP_E_INVALID_PARAM = -1
+};
+
+#endif /* ROCKCHIP_SIP_SVC_H */
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
new file mode 100644
index 0000000..8c2e5e9
--- /dev/null
+++ b/plat/rockchip/common/params_setup.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <lib/bl_aux_params/bl_aux_params.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/gpio.h>
+#include <libfdt.h>
+#include <lib/coreboot.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_params.h>
+#include <plat_private.h>
+
+static struct bl_aux_gpio_info rst_gpio;
+static struct bl_aux_gpio_info poweroff_gpio;
+static struct bl_aux_gpio_info suspend_gpio[10];
+uint32_t suspend_gpio_cnt;
+static struct bl_aux_rk_apio_info suspend_apio;
+
+#if COREBOOT
+static int dt_process_fdt(u_register_t param_from_bl2)
+{
+	return -ENODEV;
+}
+#else
+static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
+static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE;
+static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK;
+static uint8_t fdt_buffer[0x10000];
+
+void *plat_get_fdt(void)
+{
+	return &fdt_buffer[0];
+}
+
+static void plat_rockchip_dt_process_fdt_uart(void *fdt)
+{
+	const char *path_name = "/chosen";
+	const char *prop_name = "stdout-path";
+	int node_offset;
+	int stdout_path_len;
+	const char *stdout_path;
+	const char *separator;
+	const char *baud_start;
+	char serial_char;
+	int serial_no;
+	uint32_t uart_base;
+	uint32_t baud;
+
+	node_offset = fdt_path_offset(fdt, path_name);
+	if (node_offset < 0)
+		return;
+
+	stdout_path = fdt_getprop(fdt, node_offset, prop_name,
+				  &stdout_path_len);
+	if (stdout_path == NULL)
+		return;
+
+	/*
+	 * We expect something like:
+	 *   "serial0:baudrate"
+	 */
+	if (strncmp("serial", stdout_path, 6) != 0)
+		return;
+
+	serial_char = stdout_path[6];
+	serial_no = serial_char - '0';
+
+	switch (serial_no) {
+	case 0:
+		uart_base = UART0_BASE;
+		break;
+	case 1:
+		uart_base = UART1_BASE;
+		break;
+	case 2:
+		uart_base = UART2_BASE;
+		break;
+#ifdef UART3_BASE
+	case 3:
+		uart_base = UART3_BASE;
+		break;
+#endif
+#ifdef UART4_BASE
+	case 4:
+		uart_base = UART4_BASE;
+		break;
+#endif
+#ifdef UART5_BASE
+	case 5:
+		uart_base = UART5_BASE;
+		break;
+#endif
+	default:
+		return;
+	}
+
+	rk_uart_base = uart_base;
+
+	separator = strchr(stdout_path, ':');
+	if (!separator)
+		return;
+
+	baud = 0;
+	baud_start = separator + 1;
+	while (*baud_start != '\0') {
+		/*
+		 * uart binding is <baud>{<parity>{<bits>{...}}}
+		 * So the baudrate either is the whole string, or
+		 * we end in the parity characters.
+		 */
+		if (*baud_start == 'n' || *baud_start == 'o' ||
+		    *baud_start == 'e')
+			break;
+
+		baud = baud * 10 + (*baud_start - '0');
+		baud_start++;
+	}
+
+	rk_uart_baudrate = baud;
+}
+
+static int dt_process_fdt(u_register_t param_from_bl2)
+{
+	void *fdt = plat_get_fdt();
+	int ret;
+
+	ret = fdt_open_into((void *)param_from_bl2, fdt, 0x10000);
+	if (ret < 0)
+		return ret;
+
+	plat_rockchip_dt_process_fdt_uart(fdt);
+
+	return 0;
+}
+#endif
+
+uint32_t rockchip_get_uart_base(void)
+{
+#if COREBOOT
+	return coreboot_serial.baseaddr;
+#else
+	return rk_uart_base;
+#endif
+}
+
+uint32_t rockchip_get_uart_baudrate(void)
+{
+#if COREBOOT
+	return coreboot_serial.baud;
+#else
+	return rk_uart_baudrate;
+#endif
+}
+
+uint32_t rockchip_get_uart_clock(void)
+{
+#if COREBOOT
+	return coreboot_serial.input_hertz;
+#else
+	return rk_uart_clock;
+#endif
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void)
+{
+	return &rst_gpio;
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void)
+{
+	return &poweroff_gpio;
+}
+
+struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count)
+{
+	*count = suspend_gpio_cnt;
+
+	return &suspend_gpio[0];
+}
+
+struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void)
+{
+	return &suspend_apio;
+}
+
+static bool rk_aux_param_handler(struct bl_aux_param_header *param)
+{
+	/* Store platform parameters for later processing if needed. */
+	switch (param->type) {
+	case BL_AUX_PARAM_RK_RESET_GPIO:
+		rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
+		return true;
+	case BL_AUX_PARAM_RK_POWEROFF_GPIO:
+		poweroff_gpio = ((struct bl_aux_param_gpio *)param)->gpio;
+		return true;
+	case BL_AUX_PARAM_RK_SUSPEND_GPIO:
+		if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) {
+			ERROR("Exceeded the supported suspend GPIO number.\n");
+			return true;
+		}
+		suspend_gpio[suspend_gpio_cnt++] =
+			((struct bl_aux_param_gpio *)param)->gpio;
+		return true;
+	case BL_AUX_PARAM_RK_SUSPEND_APIO:
+		suspend_apio = ((struct bl_aux_param_rk_apio *)param)->apio;
+		return true;
+	}
+
+	return false;
+}
+
+void params_early_setup(u_register_t plat_param_from_bl2)
+{
+	/*
+	 * Test if this is a FDT passed as a platform-specific parameter
+	 * block.
+	 */
+	if (!dt_process_fdt(plat_param_from_bl2))
+		return;
+
+	bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler);
+}
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
new file mode 100644
index 0000000..c9563c9
--- /dev/null
+++ b/plat/rockchip/common/plat_pm.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/psci/psci.h>
+
+#include <plat_private.h>
+
+/* Macros to read the rk power domain state */
+#define RK_CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define RK_CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define RK_SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+static uintptr_t rockchip_sec_entrypoint;
+
+#pragma weak rockchip_soc_cores_pwr_dm_on
+#pragma weak rockchip_soc_hlvl_pwr_dm_off
+#pragma weak rockchip_soc_cores_pwr_dm_off
+#pragma weak rockchip_soc_sys_pwr_dm_suspend
+#pragma weak rockchip_soc_cores_pwr_dm_suspend
+#pragma weak rockchip_soc_hlvl_pwr_dm_suspend
+#pragma weak rockchip_soc_hlvl_pwr_dm_on_finish
+#pragma weak rockchip_soc_cores_pwr_dm_on_finish
+#pragma weak rockchip_soc_sys_pwr_dm_resume
+#pragma weak rockchip_soc_hlvl_pwr_dm_resume
+#pragma weak rockchip_soc_cores_pwr_dm_resume
+#pragma weak rockchip_soc_soft_reset
+#pragma weak rockchip_soc_system_off
+#pragma weak rockchip_soc_sys_pd_pwr_dn_wfi
+#pragma weak rockchip_soc_cores_pd_pwr_dn_wfi
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl,
+				 plat_local_state_t lvl_state)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl,
+				     plat_local_state_t lvl_state)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl,
+				       plat_local_state_t lvl_state)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl,
+				    plat_local_state_t lvl_state)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+	return PSCI_E_NOT_SUPPORTED;
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	while (1)
+		;
+}
+
+void __dead2 rockchip_soc_system_off(void)
+{
+	while (1)
+		;
+}
+
+void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(
+				const psci_power_state_t *target_state)
+{
+	psci_power_down_wfi();
+}
+
+void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
+{
+	psci_power_down_wfi();
+}
+
+/*******************************************************************************
+ * Rockchip standard platform handler called to check the validity of the power
+ * state parameter.
+ ******************************************************************************/
+int rockchip_validate_power_state(unsigned int power_state,
+				  psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's probably to enter standby only on power level 0
+		 * ignore any other power level.
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
+					PLAT_MAX_RET_STATE;
+	} else {
+		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					PLAT_MAX_OFF_STATE;
+
+		for (i = (pwr_lvl + 1); i <= PLAT_MAX_PWR_LVL; i++)
+			req_state->pwr_domain_state[i] =
+					PLAT_MAX_RET_STATE;
+	}
+
+	/* We expect the 'state id' to be zero */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+void rockchip_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * RockChip handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+void rockchip_cpu_standby(plat_local_state_t cpu_state)
+{
+	unsigned int scr;
+
+	assert(cpu_state == PLAT_MAX_RET_STATE);
+
+	scr = read_scr_el3();
+	/* Enable PhysicalIRQ bit for NS world to wake the CPU */
+	write_scr_el3(scr | SCR_IRQ_BIT);
+	isb();
+	dsb();
+	wfi();
+
+	/*
+	 * Restore SCR to the original value, synchronisation of scr_el3 is
+	 * done by eret while el3_exit to save some execution cycles.
+	 */
+	write_scr_el3(scr);
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+int rockchip_pwr_domain_on(u_register_t mpidr)
+{
+	return rockchip_soc_cores_pwr_dm_on(mpidr, rockchip_sec_entrypoint);
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain is about to be turned off. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void rockchip_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uint32_t lvl;
+	plat_local_state_t lvl_state;
+	int ret;
+
+	assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
+
+	plat_rockchip_gic_cpuif_disable();
+
+	if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		plat_cci_disable();
+
+	rockchip_soc_cores_pwr_dm_off();
+
+	for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		lvl_state = target_state->pwr_domain_state[lvl];
+		ret = rockchip_soc_hlvl_pwr_dm_off(lvl, lvl_state);
+		if (ret == PSCI_E_NOT_SUPPORTED)
+			break;
+	}
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain is about to be suspended. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+void rockchip_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	uint32_t lvl;
+	plat_local_state_t lvl_state;
+	int ret;
+
+	if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_rockchip_gic_cpuif_disable();
+
+	if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		rockchip_soc_sys_pwr_dm_suspend();
+	else
+		rockchip_soc_cores_pwr_dm_suspend();
+
+	/* Perform the common cluster specific operations */
+	if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		plat_cci_disable();
+
+	if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		return;
+
+	for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		lvl_state = target_state->pwr_domain_state[lvl];
+		ret = rockchip_soc_hlvl_pwr_dm_suspend(lvl, lvl_state);
+		if (ret == PSCI_E_NOT_SUPPORTED)
+			break;
+	}
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void rockchip_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	uint32_t lvl;
+	plat_local_state_t lvl_state;
+	int ret;
+
+	assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
+
+	for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		lvl_state = target_state->pwr_domain_state[lvl];
+		ret = rockchip_soc_hlvl_pwr_dm_on_finish(lvl, lvl_state);
+		if (ret == PSCI_E_NOT_SUPPORTED)
+			break;
+	}
+
+	rockchip_soc_cores_pwr_dm_on_finish();
+
+	/* Perform the common cluster specific operations */
+	if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+	}
+
+	/* Enable the gic cpu interface */
+	plat_rockchip_gic_pcpu_init();
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_rockchip_gic_cpuif_enable();
+}
+
+/*******************************************************************************
+ * RockChip handler called when a power domain has just been powered on after
+ * having been suspended earlier. The target_state encodes the low power state
+ * that each level has woken up from.
+ * TODO: At the moment we reuse the on finisher and reinitialize the secure
+ * context. Need to implement a separate suspend finisher.
+ ******************************************************************************/
+void rockchip_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	uint32_t lvl;
+	plat_local_state_t lvl_state;
+	int ret;
+
+	/* Nothing to be done on waking up from retention from CPU level */
+	if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		rockchip_soc_sys_pwr_dm_resume();
+		goto comm_finish;
+	}
+
+	for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		lvl_state = target_state->pwr_domain_state[lvl];
+		ret = rockchip_soc_hlvl_pwr_dm_resume(lvl, lvl_state);
+		if (ret == PSCI_E_NOT_SUPPORTED)
+			break;
+	}
+
+	rockchip_soc_cores_pwr_dm_resume();
+
+	/*
+	 * Program the gic per-cpu distributor or re-distributor interface.
+	 * For sys power domain operation, resuming of the gic needs to operate
+	 * in rockchip_soc_sys_pwr_dm_resume(), according to the sys power mode
+	 * implements.
+	 */
+	plat_rockchip_gic_cpuif_enable();
+
+comm_finish:
+	/* Perform the common cluster specific operations */
+	if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+	}
+}
+
+/*******************************************************************************
+ * RockChip handlers to reboot the system
+ ******************************************************************************/
+static void __dead2 rockchip_system_reset(void)
+{
+	rockchip_soc_soft_reset();
+}
+
+/*******************************************************************************
+ * RockChip handlers to power off the system
+ ******************************************************************************/
+static void __dead2 rockchip_system_poweroff(void)
+{
+	rockchip_soc_system_off();
+}
+
+static void __dead2 rockchip_pd_pwr_down_wfi(
+		const psci_power_state_t *target_state)
+{
+	if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		rockchip_soc_sys_pd_pwr_dn_wfi();
+	else
+		rockchip_soc_cores_pd_pwr_dn_wfi(target_state);
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip
+ * standard
+ * platform layer will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+const plat_psci_ops_t plat_rockchip_psci_pm_ops = {
+	.cpu_standby = rockchip_cpu_standby,
+	.pwr_domain_on = rockchip_pwr_domain_on,
+	.pwr_domain_off = rockchip_pwr_domain_off,
+	.pwr_domain_suspend = rockchip_pwr_domain_suspend,
+	.pwr_domain_on_finish = rockchip_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi = rockchip_pd_pwr_down_wfi,
+	.system_reset = rockchip_system_reset,
+	.system_off = rockchip_system_poweroff,
+	.validate_power_state = rockchip_validate_power_state,
+	.get_sys_suspend_power_state = rockchip_get_sys_suspend_power_state
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &plat_rockchip_psci_pm_ops;
+	rockchip_sec_entrypoint = sec_entrypoint;
+	return 0;
+}
+
+uintptr_t plat_get_sec_entrypoint(void)
+{
+	assert(rockchip_sec_entrypoint);
+	return rockchip_sec_entrypoint;
+}
diff --git a/plat/rockchip/common/plat_topology.c b/plat/rockchip/common/plat_topology.c
new file mode 100644
index 0000000..4987eeb
--- /dev/null
+++ b/plat/rockchip/common/plat_topology.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+
+#include <plat_private.h>
+
+/*******************************************************************************
+ * This function returns the RockChip default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return rockchip_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	cpu_id = mpidr & MPIDR_AFFLVL_MASK;
+#ifdef PLAT_RK_MPIDR_CLUSTER_MASK
+	cluster_id = mpidr & PLAT_RK_MPIDR_CLUSTER_MASK;
+#else
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+#endif
+
+	cpu_id += (cluster_id >> PLAT_RK_CLST_TO_CPUID_SHIFT);
+
+	if (cpu_id >= PLATFORM_CORE_COUNT)
+		return -1;
+
+	return cpu_id;
+}
diff --git a/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S
new file mode 100644
index 0000000..6cea2ea
--- /dev/null
+++ b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <cpus_on_fixed_addr.h>
+
+	.globl sys_sleep_flag_sram
+	.globl pmu_cpuson_entrypoint
+
+	.macro pmusram_entry_func _name
+	.section .pmusram.entry, "ax"
+	.type \_name, %function
+	.cfi_startproc
+	\_name:
+	.endm
+
+pmusram_entry_func pmu_cpuson_entrypoint
+	adr	x5, sys_sleep_flag_sram
+	ldr	w2, [x5, #PSRAM_DT_PM_FLAG]
+
+	tbz	w2, #PM_WARM_BOOT_SHT, sys_resume_sp
+	ldr	x1, =platform_cpu_warmboot
+	br	x1
+sys_resume_sp:
+	adr	x5, sys_sleep_flag_sram
+	ldr	x1, [x5, #PSRAM_DT_SP]
+	mov	sp, x1
+ddr_resume:
+	ldr	x1, [x5, #PSRAM_DT_DDR_FUNC]
+	cmp	x1, #0
+	b.eq	sys_resume
+	blr	x1
+sys_resume:
+	ldr	x1, =bl31_warm_entrypoint
+	br	x1
+endfunc pmu_cpuson_entrypoint
+
+	.section .pmusram.data, "a"
+	.align  3
+sys_sleep_flag_sram:
+	.rept	PSRAM_DT_SIZE_WORDS
+	.word	0
+	.endr
diff --git a/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h
new file mode 100644
index 0000000..34af29a
--- /dev/null
+++ b/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CPU_ON_FIXED_ADDR_H__
+#define __CPU_ON_FIXED_ADDR_H__
+
+/*****************************************************************************
+ * define data offset in struct psram_data
+ *****************************************************************************/
+#define PSRAM_DT_SP		0x0
+#define PSRAM_DT_DDR_FUNC	0x8
+#define PSRAM_DT_DDR_DATA	0x10
+#define PSRAM_DT_DDRFLAG	0x18
+#define PSRAM_DT_MPIDR		0x1c
+#define PSRAM_DT_PM_FLAG	0x20
+#define PSRAM_DT_END		0x24
+
+/* reserve 4 byte */
+#define PSRAM_DT_END_RES4	(PSRAM_DT_END + 4)
+
+#define PSRAM_DT_SIZE_WORDS	(PSRAM_DT_END_RES4 / 4)
+
+#define PM_WARM_BOOT_SHT	0
+#define PM_WARM_BOOT_BIT	(1 << PM_WARM_BOOT_SHT)
+
+#ifndef __ASSEMBLER__
+
+struct psram_data_t {
+	uint64_t sp;
+	uint64_t ddr_func;
+	uint64_t ddr_data;
+	uint32_t ddr_flag;
+	uint32_t boot_mpidr;
+	uint32_t pm_flag;
+};
+
+CASSERT(__builtin_offsetof(struct psram_data_t, sp) == PSRAM_DT_SP,
+	assert_psram_dt_sp_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, ddr_func) == PSRAM_DT_DDR_FUNC,
+	assert_psram_dt_ddr_func_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, ddr_data) == PSRAM_DT_DDR_DATA,
+	assert_psram_dt_ddr_data_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, ddr_flag) == PSRAM_DT_DDRFLAG,
+	assert_psram_dt_ddr_flag_offset_mistmatch);
+CASSERT(__builtin_offsetof(struct psram_data_t, boot_mpidr) == PSRAM_DT_MPIDR,
+	assert_psram_dt_mpidr_offset_mistmatch);
+
+extern void *sys_sleep_flag_sram;
+
+#endif  /* __ASSEMBLER__ */
+
+#endif
diff --git a/plat/rockchip/common/rockchip_gicv2.c b/plat/rockchip/common/rockchip_gicv2.c
new file mode 100644
index 0000000..8db2b30
--- /dev/null
+++ b/plat/rockchip/common/rockchip_gicv2.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/utils.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv2 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_rockchip_gic_driver_init
+#pragma weak plat_rockchip_gic_init
+#pragma weak plat_rockchip_gic_cpuif_enable
+#pragma weak plat_rockchip_gic_cpuif_disable
+#pragma weak plat_rockchip_gic_pcpu_init
+
+/******************************************************************************
+ * List of interrupts.
+ *****************************************************************************/
+static const interrupt_prop_t g0_interrupt_props[] = {
+	PLAT_RK_GICV2_G0_IRQS
+};
+
+/*
+ * Ideally `rockchip_gic_data` structure definition should be a `const` but it
+ * is kept as modifiable for overwriting with different GICD and GICC base when
+ * running on FVP with VE memory map.
+ */
+gicv2_driver_data_t rockchip_gic_data = {
+	.gicd_base = PLAT_RK_GICD_BASE,
+	.gicc_base = PLAT_RK_GICC_BASE,
+	.interrupt_props = g0_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g0_interrupt_props),
+};
+
+/******************************************************************************
+ * RockChip common helper to initialize the GICv2 only driver.
+ *****************************************************************************/
+void plat_rockchip_gic_driver_init(void)
+{
+	gicv2_driver_init(&rockchip_gic_data);
+}
+
+void plat_rockchip_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * RockChip common helper to enable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_enable(void)
+{
+	gicv2_cpuif_enable();
+}
+
+/******************************************************************************
+ * RockChip common helper to disable the GICv2 CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_disable(void)
+{
+	gicv2_cpuif_disable();
+}
+
+/******************************************************************************
+ * RockChip common helper to initialize the per cpu distributor interface
+ * in GICv2
+ *****************************************************************************/
+void plat_rockchip_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+}
diff --git a/plat/rockchip/common/rockchip_gicv3.c b/plat/rockchip/common/rockchip_gicv3.c
new file mode 100644
index 0000000..edae2ef
--- /dev/null
+++ b/plat/rockchip/common/rockchip_gicv3.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_rockchip_gic_driver_init
+#pragma weak plat_rockchip_gic_init
+#pragma weak plat_rockchip_gic_cpuif_enable
+#pragma weak plat_rockchip_gic_cpuif_disable
+#pragma weak plat_rockchip_gic_pcpu_init
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t g01s_interrupt_props[] = {
+	PLAT_RK_GICV3_G0_IRQS,
+	PLAT_RK_GICV3_G1S_IRQS
+};
+
+static unsigned int plat_rockchip_mpidr_to_core_pos(unsigned long mpidr)
+{
+	return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+const gicv3_driver_data_t rockchip_gic_data = {
+	.gicd_base = PLAT_RK_GICD_BASE,
+	.gicr_base = PLAT_RK_GICR_BASE,
+	.interrupt_props = g01s_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g01s_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = plat_rockchip_mpidr_to_core_pos,
+};
+
+void plat_rockchip_gic_driver_init(void)
+{
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#ifdef IMAGE_BL31
+	gicv3_driver_init(&rockchip_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * RockChip common helper to initialize the GIC. Only invoked
+ * by BL31
+ *****************************************************************************/
+void plat_rockchip_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * RockChip common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * RockChip common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_rockchip_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * RockChip common helper to initialize the per-cpu redistributor interface
+ * in GICv3
+ *****************************************************************************/
+void plat_rockchip_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/rockchip/common/rockchip_sip_svc.c b/plat/rockchip/common/rockchip_sip_svc.c
new file mode 100644
index 0000000..27ef042
--- /dev/null
+++ b/plat/rockchip/common/rockchip_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <tools_share/uuid.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+/* Rockchip SiP Service UUID */
+DEFINE_SVC_UUID2(rk_sip_svc_uid,
+	0xe2c76fe8, 0x3e31, 0xe611, 0xb7, 0x0d,
+	0x8f, 0x88, 0xee, 0x74, 0x7b, 0x72);
+
+#pragma weak rockchip_plat_sip_handler
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+				    u_register_t x1,
+				    u_register_t x2,
+				    u_register_t x3,
+				    u_register_t x4,
+				    void *cookie,
+				    void *handle,
+				    u_register_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+uintptr_t sip_smc_handler(uint32_t smc_fid,
+			  u_register_t x1,
+			  u_register_t x2,
+			  u_register_t x3,
+			  u_register_t x4,
+			  void *cookie,
+			  void *handle,
+			  u_register_t flags)
+{
+	uint32_t ns;
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+	if (!ns)
+		SMC_RET1(handle, SMC_UNK);
+
+	switch (smc_fid) {
+	case SIP_SVC_CALL_COUNT:
+		/* Return the number of Rockchip SiP Service Calls. */
+		SMC_RET1(handle,
+			 RK_COMMON_SIP_NUM_CALLS + RK_PLAT_SIP_NUM_CALLS);
+
+	case SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, rk_sip_svc_uid);
+
+	case SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, RK_SIP_SVC_VERSION_MAJOR,
+			RK_SIP_SVC_VERSION_MINOR);
+
+	default:
+		return rockchip_plat_sip_handler(smc_fid, x1, x2, x3, x4,
+			cookie, handle, flags);
+	}
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	rockchip_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	sip_smc_handler
+);
diff --git a/plat/rockchip/common/sp_min_plat_setup.c b/plat/rockchip/common/sp_min_plat_setup.c
new file mode 100644
index 0000000..3f8767e
--- /dev/null
+++ b/plat/rockchip/common/sp_min_plat_setup.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+static entry_point_info_t bl33_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type.
+ * A NULL pointer is returned if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *sp_min_plat_get_bl33_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = &bl33_ep_info;
+
+	if (next_image_info->pc == 0U) {
+		return NULL;
+	}
+
+	return next_image_info;
+}
+
+#pragma weak params_early_setup
+void params_early_setup(u_register_t plat_param_from_bl2)
+{
+}
+
+unsigned int plat_is_my_cpu_primary(void);
+
+/*******************************************************************************
+ * Perform any BL32 specific platform actions.
+ ******************************************************************************/
+void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				  u_register_t arg2, u_register_t arg3)
+{
+	static console_16550_t console;
+	struct rockchip_bl31_params *arg_from_bl2 = (struct rockchip_bl31_params *) arg0;
+
+	params_early_setup(arg1);
+
+	if (rockchip_get_uart_base() != 0)
+		console_16550_register(rockchip_get_uart_base(),
+				       rockchip_get_uart_clock(),
+				       rockchip_get_uart_baudrate(), &console);
+
+	VERBOSE("sp_min_setup\n");
+
+	/* Passing a NULL context is a critical programming error */
+	assert(arg_from_bl2);
+
+	assert(arg_from_bl2->h.type == PARAM_BL31);
+	assert(arg_from_bl2->h.version >= VERSION_1);
+
+	bl33_ep_info = *arg_from_bl2->bl33_ep_info;
+}
+
+/*******************************************************************************
+ * Perform any sp_min platform setup code
+ ******************************************************************************/
+void sp_min_platform_setup(void)
+{
+	generic_delay_timer_init();
+	plat_rockchip_soc_init();
+
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_rockchip_gic_driver_init();
+	plat_rockchip_gic_init();
+	plat_rockchip_pmu_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void sp_min_plat_arch_setup(void)
+{
+	plat_cci_init();
+	plat_cci_enable();
+
+	plat_configure_mmu_svc_mon(BL_CODE_BASE,
+				   BL_COHERENT_RAM_END - BL_CODE_BASE,
+				   BL_CODE_BASE,
+				   BL_CODE_END,
+				   BL_COHERENT_RAM_BASE,
+				   BL_COHERENT_RAM_END);
+}
+
+void sp_min_plat_fiq_handler(uint32_t id)
+{
+	VERBOSE("[sp_min] interrupt #%d\n", id);
+}
diff --git a/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..a757621
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.globl	clst_warmboot_data
+
+.macro	func_rockchip_clst_warmboot
+.endm
+
+.macro rockchip_clst_warmboot_data
+clst_warmboot_data:
+	.rept	PLATFORM_CLUSTER_COUNT
+	.word	0
+	.endr
+.endm
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.c b/plat/rockchip/px30/drivers/pmu/pmu.c
new file mode 100644
index 0000000..0a2515d
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/pmu.c
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <cpus_on_fixed_addr.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <px30_def.h>
+#include <soc.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+#define rockchip_pd_lock_init()	bakery_lock_init(&rockchip_pd_lock)
+#define rockchip_pd_lock_get()	bakery_lock_get(&rockchip_pd_lock)
+#define rockchip_pd_lock_rls()	bakery_lock_release(&rockchip_pd_lock)
+
+static struct psram_data_t *psram_boot_cfg =
+	(struct psram_data_t *)&sys_sleep_flag_sram;
+
+/*
+ * There are two ways to powering on or off on core.
+ * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
+ *    it is core_pwr_pd mode
+ * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
+ *     then, if the core enter into wfi, it power domain will be
+ *     powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode
+ * so we need core_pm_cfg_info to distinguish which method be used now.
+ */
+
+static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT]
+#if USE_COHERENT_MEM
+__attribute__ ((section("tzfw_coherent_mem")))
+#endif
+;
+
+struct px30_sleep_ddr_data {
+	uint32_t clk_sel0;
+	uint32_t cru_mode_save;
+	uint32_t cru_pmu_mode_save;
+	uint32_t ddrc_hwlpctl;
+	uint32_t ddrc_pwrctrl;
+	uint32_t ddrgrf_con0;
+	uint32_t ddrgrf_con1;
+	uint32_t ddrstdby_con0;
+	uint32_t gpio0b_iomux;
+	uint32_t gpio0c_iomux;
+	uint32_t pmu_pwrmd_core_l;
+	uint32_t pmu_pwrmd_core_h;
+	uint32_t pmu_pwrmd_cmm_l;
+	uint32_t pmu_pwrmd_cmm_h;
+	uint32_t pmu_wkup_cfg2_l;
+	uint32_t pmu_cru_clksel_con0;
+	uint32_t pmugrf_soc_con0;
+	uint32_t pmusgrf_soc_con0;
+	uint32_t pmic_slp_iomux;
+	uint32_t pgrf_pvtm_con[2];
+	uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT];
+	uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT];
+	uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT];
+	uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS];
+};
+
+static struct px30_sleep_ddr_data ddr_data
+#if USE_COHERENT_MEM
+__attribute__ ((section("tzfw_coherent_mem")))
+#endif
+;
+
+static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
+{
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	return cores_pd_cfg_info[cpu_id];
+}
+
+static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
+{
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	cores_pd_cfg_info[cpu_id] = value;
+#if !USE_COHERENT_MEM
+	flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id],
+			   sizeof(uint32_t));
+#endif
+}
+
+static inline uint32_t pmu_power_domain_st(uint32_t pd)
+{
+	return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ?
+	       pmu_pd_off :
+	       pmu_pd_on;
+}
+
+static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
+{
+	uint32_t loop = 0;
+	int ret = 0;
+
+	rockchip_pd_lock_get();
+
+	mmio_write_32(PMU_BASE + PMU_PWRDN_CON,
+		      BITS_WITH_WMASK(pd_state, 0x1, pd));
+	dsb();
+
+	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if (pmu_power_domain_st(pd) != pd_state) {
+		WARN("%s: %d, %d, error!\n", __func__, pd, pd_state);
+		ret = -EINVAL;
+	}
+
+	rockchip_pd_lock_rls();
+
+	return ret;
+}
+
+static inline uint32_t pmu_bus_idle_st(uint32_t bus)
+{
+	return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) &&
+		  (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16)));
+}
+
+static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
+{
+	uint32_t wait_cnt = 0;
+
+	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ,
+		      BITS_WITH_WMASK(state, 0x1, bus));
+
+	while (pmu_bus_idle_st(bus) != state &&
+	       wait_cnt < BUS_IDLE_LOOP) {
+		udelay(1);
+		wait_cnt++;
+	}
+
+	if (pmu_bus_idle_st(bus) != state)
+		WARN("%s:idle_st=0x%x, bus_id=%d\n",
+		     __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus);
+}
+
+static void qos_save(void)
+{
+	/* scu powerdomain will power off, so cpu qos should be saved */
+	SAVE_QOS(ddr_data.cpu_qos, CPU);
+
+	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
+		SAVE_QOS(ddr_data.gpu_qos, GPU);
+	if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
+		SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M);
+		SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD);
+		SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR);
+		SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1);
+		SAVE_QOS(ddr_data.vip_qos, VIP);
+	}
+	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
+		SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD);
+		SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR);
+		SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0);
+		SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1);
+	}
+	if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
+		SAVE_QOS(ddr_data.vpu_qos, VPU);
+		SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
+	}
+	if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
+		SAVE_QOS(ddr_data.emmc_qos, EMMC);
+		SAVE_QOS(ddr_data.nand_qos, NAND);
+		SAVE_QOS(ddr_data.sdio_qos, SDIO);
+		SAVE_QOS(ddr_data.sfc_qos, SFC);
+	}
+	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
+		SAVE_QOS(ddr_data.gmac_qos, GMAC);
+	if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
+		SAVE_QOS(ddr_data.crypto_qos, CRYPTO);
+	if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
+		SAVE_QOS(ddr_data.sdmmc_qos, SDMMC);
+	if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
+		SAVE_QOS(ddr_data.usb_host_qos, USB_HOST);
+		SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG);
+	}
+}
+
+static void qos_restore(void)
+{
+	RESTORE_QOS(ddr_data.cpu_qos, CPU);
+
+	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
+		RESTORE_QOS(ddr_data.gpu_qos, GPU);
+	if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
+		RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M);
+		RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD);
+		RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR);
+		RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1);
+		RESTORE_QOS(ddr_data.vip_qos, VIP);
+	}
+	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
+		RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD);
+		RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR);
+		RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0);
+		RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1);
+	}
+	if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
+		RESTORE_QOS(ddr_data.vpu_qos, VPU);
+		RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
+	}
+	if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
+		RESTORE_QOS(ddr_data.emmc_qos, EMMC);
+		RESTORE_QOS(ddr_data.nand_qos, NAND);
+		RESTORE_QOS(ddr_data.sdio_qos, SDIO);
+		RESTORE_QOS(ddr_data.sfc_qos, SFC);
+	}
+	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
+		RESTORE_QOS(ddr_data.gmac_qos, GMAC);
+	if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
+		RESTORE_QOS(ddr_data.crypto_qos, CRYPTO);
+	if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
+		RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC);
+	if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
+		RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST);
+		RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG);
+	}
+}
+
+static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
+{
+	uint32_t state;
+
+	if (pmu_power_domain_st(pd_id) == pd_state)
+		goto out;
+
+	if (pd_state == pmu_pd_on)
+		pmu_power_domain_ctr(pd_id, pd_state);
+
+	state = (pd_state == pmu_pd_off) ? bus_idle : bus_active;
+
+	switch (pd_id) {
+	case PD_GPU:
+		pmu_bus_idle_req(BUS_ID_GPU, state);
+		break;
+	case PD_VI:
+		pmu_bus_idle_req(BUS_ID_VI, state);
+		break;
+	case PD_VO:
+		pmu_bus_idle_req(BUS_ID_VO, state);
+		break;
+	case PD_VPU:
+		pmu_bus_idle_req(BUS_ID_VPU, state);
+		break;
+	case PD_MMC_NAND:
+		pmu_bus_idle_req(BUS_ID_MMC, state);
+		break;
+	case PD_GMAC:
+		pmu_bus_idle_req(BUS_ID_GMAC, state);
+		break;
+	case PD_CRYPTO:
+		pmu_bus_idle_req(BUS_ID_CRYPTO, state);
+		break;
+	case PD_SDCARD:
+		pmu_bus_idle_req(BUS_ID_SDCARD, state);
+		break;
+	case PD_USB:
+		pmu_bus_idle_req(BUS_ID_USB, state);
+		break;
+	default:
+		break;
+	}
+
+	if (pd_state == pmu_pd_off)
+		pmu_power_domain_ctr(pd_id, pd_state);
+
+out:
+	return 0;
+}
+
+static uint32_t pmu_powerdomain_state;
+
+static void pmu_power_domains_suspend(void)
+{
+	uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
+
+	clk_gate_con_save(clkgt_save);
+	clk_gate_con_disable();
+	qos_save();
+
+	pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
+	pmu_set_power_domain(PD_GPU, pmu_pd_off);
+	pmu_set_power_domain(PD_VI, pmu_pd_off);
+	pmu_set_power_domain(PD_VO, pmu_pd_off);
+	pmu_set_power_domain(PD_VPU, pmu_pd_off);
+	pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off);
+	pmu_set_power_domain(PD_GMAC, pmu_pd_off);
+	pmu_set_power_domain(PD_CRYPTO, pmu_pd_off);
+	pmu_set_power_domain(PD_SDCARD, pmu_pd_off);
+	pmu_set_power_domain(PD_USB, pmu_pd_off);
+
+	clk_gate_con_restore(clkgt_save);
+}
+
+static void pmu_power_domains_resume(void)
+{
+	uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
+
+	clk_gate_con_save(clkgt_save);
+	clk_gate_con_disable();
+
+	if (!(pmu_powerdomain_state & BIT(PD_USB)))
+		pmu_set_power_domain(PD_USB, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_SDCARD)))
+		pmu_set_power_domain(PD_SDCARD, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_CRYPTO)))
+		pmu_set_power_domain(PD_CRYPTO, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_GMAC)))
+		pmu_set_power_domain(PD_GMAC, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND)))
+		pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_VPU)))
+		pmu_set_power_domain(PD_VPU, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_VO)))
+		pmu_set_power_domain(PD_VO, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_VI)))
+		pmu_set_power_domain(PD_VI, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_GPU)))
+		pmu_set_power_domain(PD_GPU, pmu_pd_on);
+
+	qos_restore();
+	clk_gate_con_restore(clkgt_save);
+}
+
+static int check_cpu_wfie(uint32_t cpu)
+{
+	uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu;
+
+	while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) &&
+	       (loop < WFEI_CHECK_LOOP)) {
+		udelay(1);
+		loop++;
+	}
+
+	if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) {
+		WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+	uint32_t cpu_pd, apm_value, cfg_info, loop = 0;
+
+	cpu_pd = PD_CPU0 + cpu_id;
+	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
+
+	if (cfg_info == core_pwr_pd) {
+		/* disable apm cfg */
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      WITH_16BITS_WMSK(CORES_PM_DISABLE));
+		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+			mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+				      WITH_16BITS_WMSK(CORES_PM_DISABLE));
+			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+		}
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
+	} else {
+		/* wait cpu down */
+		while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) {
+			udelay(2);
+			loop++;
+		}
+
+		/* return error if can't wait cpu down */
+		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+			WARN("%s:can't wait cpu down\n", __func__);
+			return -EINVAL;
+		}
+
+		/* power up cpu in power down state */
+		apm_value = BIT(core_pm_sft_wakeup_en);
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      WITH_16BITS_WMSK(apm_value));
+	}
+
+	return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
+{
+	uint32_t cpu_pd, apm_value;
+
+	cpu_pd = PD_CPU0 + cpu_id;
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
+		return 0;
+
+	if (pd_cfg == core_pwr_pd) {
+		if (check_cpu_wfie(cpu_id))
+			return -EINVAL;
+		/* disable apm cfg */
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      WITH_16BITS_WMSK(CORES_PM_DISABLE));
+		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+	} else {
+		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+		apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
+		if (pd_cfg == core_pwr_wfi_int)
+			apm_value |= BIT(core_pm_int_wakeup_en);
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      WITH_16BITS_WMSK(apm_value));
+	}
+
+	return 0;
+}
+
+static void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, cpu;
+
+	boot_cpu = plat_my_core_pos();
+
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		if (cpu == boot_cpu)
+			continue;
+		cpus_power_domain_off(cpu, core_pwr_pd);
+	}
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr,
+				 uint64_t entrypoint)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpu_id] = entrypoint;
+	dsb();
+
+	cpus_power_domain_on(cpu_id);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+		      WITH_16BITS_WMSK(CORES_PM_DISABLE));
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
+	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
+	dsb();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	/* Disable core_pm */
+	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+		      WITH_16BITS_WMSK(CORES_PM_DISABLE));
+
+	return PSCI_E_SUCCESS;
+}
+
+#define CLK_MSK_GATING(msk, con) \
+	mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff)
+#define CLK_MSK_UNGATING(msk, con) \
+	mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff)
+
+static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = {
+	0xe0ff, 0xffff, 0x0000, 0x0000,
+	0x0000, 0x0380, 0x0000, 0x0000,
+	0x07c0, 0x0000, 0x0000, 0x000f,
+	0x0061, 0x1f02, 0x0440, 0x1801,
+	0x004b, 0x0000
+};
+
+static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = {
+	0xf1ff, 0x0310
+};
+
+void clk_gate_suspend(void)
+{
+	int i;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) {
+		ddr_data.cru_clk_gate[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
+			mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+				      WITH_16BITS_WMSK(~clk_ungt_msk[i]));
+	}
+
+	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) {
+		ddr_data.cru_pmu_clk_gate[i] =
+			mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i));
+			mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+				      WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i]));
+	}
+}
+
+void clk_gate_resume(void)
+{
+	int i;
+
+	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+			      WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i]));
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+			      WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i]));
+}
+
+static void pvtm_32k_config(void)
+{
+	uint32_t  pvtm_freq_khz, pvtm_div;
+
+	ddr_data.pmu_cru_clksel_con0 =
+		mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0));
+
+	ddr_data.pgrf_pvtm_con[0] =
+		mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0);
+	ddr_data.pgrf_pvtm_con[1] =
+		mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1);
+
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+		      BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st));
+	dsb();
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+		      BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en));
+	dsb();
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT);
+	dsb();
+
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+		      BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st));
+
+	/* pmugrf_pvtm_st0 will be clear after PVTM start,
+	 * which will cost about 6 cycles of pvtm at least.
+	 * So we wait 30 cycles of pvtm for security.
+	 */
+	while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30)
+		;
+
+	dsb();
+	while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1))
+		;
+
+	pvtm_freq_khz =
+		(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 +
+		PVTM_CALC_CNT / 2) / PVTM_CALC_CNT;
+	pvtm_div = (pvtm_freq_khz + 16) / 32;
+
+	/* pvtm_div = div_factor << 2 + 1,
+	 * so div_factor = (pvtm_div - 1) >> 2.
+	 * But the operation ">> 2" will clear the low bit of pvtm_div,
+	 * so we don't have to do "- 1" for compasation
+	 */
+	pvtm_div = pvtm_div >> 2;
+	if (pvtm_div > 0x3f)
+		pvtm_div = 0x3f;
+
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+		      BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div));
+
+	/* select pvtm as 32k source */
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
+		      BITS_WITH_WMASK(1, 0x3U, 14));
+}
+
+static void pvtm_32k_config_restore(void)
+{
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
+		      ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3U, 14));
+
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
+		      WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0]));
+	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1,
+		      ddr_data.pgrf_pvtm_con[1]);
+}
+
+static void ddr_sleep_config(void)
+{
+	/* disable ddr pd, sr */
+	ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30);
+	mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0));
+
+	/* disable ddr auto gt */
+	ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4);
+	mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0));
+
+	/* disable ddr standby */
+	ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0);
+	mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0));
+	while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1)
+		;
+
+	/* ddr pmu ctrl */
+	ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0);
+	mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5));
+	dsb();
+	mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4));
+
+	/* ddr ret sel */
+	ddr_data.pmugrf_soc_con0 =
+		mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0));
+	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
+		      BITS_WITH_WMASK(0x0, 0x1, 12));
+}
+
+static void ddr_sleep_config_restore(void)
+{
+	/* restore ddr ret sel */
+	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
+		      ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12));
+
+	/* restore ddr pmu ctrl */
+	mmio_write_32(DDRGRF_BASE + 0x0,
+		      ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4));
+	dsb();
+	mmio_write_32(DDRGRF_BASE + 0x0,
+		      ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5));
+
+	/* restore ddr standby */
+	mmio_write_32(DDR_STDBY_BASE + 0x0,
+		      ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0));
+
+	/* restore ddr auto gt */
+	mmio_write_32(DDRGRF_BASE + 0x4,
+		      ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0));
+
+	/* restore ddr pd, sr */
+	mmio_write_32(DDR_UPCTL_BASE + 0x30,
+		      ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0));
+}
+
+static void pmu_sleep_config(void)
+{
+	uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi;
+	uint32_t pmu_wkup_cfg2_lo;
+	uint32_t clk_freq_khz;
+
+	/* save pmic_sleep iomux gpio0_a4 */
+	ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX);
+
+	ddr_data.pmu_pwrmd_core_l =
+			mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO);
+	ddr_data.pmu_pwrmd_core_h =
+			mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI);
+	ddr_data.pmu_pwrmd_cmm_l =
+			mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO);
+	ddr_data.pmu_pwrmd_cmm_h =
+			mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI);
+	ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO);
+
+	pwrmd_core_lo = BIT(pmu_global_int_dis) |
+			BIT(pmu_core_src_gt) |
+			BIT(pmu_cpu0_pd) |
+			BIT(pmu_clr_core) |
+			BIT(pmu_scu_pd) |
+			BIT(pmu_l2_idle) |
+			BIT(pmu_l2_flush) |
+			BIT(pmu_clr_bus2main) |
+			BIT(pmu_clr_peri2msch);
+
+	pwrmd_core_hi = BIT(pmu_dpll_pd_en) |
+			BIT(pmu_apll_pd_en) |
+			BIT(pmu_cpll_pd_en) |
+			BIT(pmu_gpll_pd_en) |
+			BIT(pmu_npll_pd_en);
+
+	pwrmd_com_lo = BIT(pmu_mode_en) |
+		       BIT(pmu_pll_pd) |
+		       BIT(pmu_pmu_use_if) |
+		       BIT(pmu_alive_use_if) |
+		       BIT(pmu_osc_dis) |
+		       BIT(pmu_sref_enter) |
+		       BIT(pmu_ddrc_gt) |
+		       BIT(pmu_clr_pmu) |
+		       BIT(pmu_clr_peri_pmu);
+
+	pwrmd_com_hi = BIT(pmu_clr_bus) |
+		       BIT(pmu_clr_msch) |
+		       BIT(pmu_wakeup_begin_cfg);
+
+	pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) |
+			   BIT(pmu_gpio_wkup_en) |
+			   BIT(pmu_timer_wkup_en);
+
+	/* set pmic_sleep iomux gpio0_a4 */
+	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
+		      BITS_WITH_WMASK(1, 0x3, 8));
+
+	clk_freq_khz = 32;
+
+	mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO,
+		      WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI,
+		      WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
+
+	mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO,
+		      WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI,
+		      WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
+
+	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO,
+		      WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI,
+		      WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16));
+
+	/* Pmu's clk has switched to 24M back When pmu FSM counts
+	 * the follow counters, so we should use 24M to calculate
+	 * these counters.
+	 */
+	mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO,
+		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI,
+		      WITH_16BITS_WMSK(24000 * 2 >> 16));
+
+	mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO,
+		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI,
+		      WITH_16BITS_WMSK(24000 * 2 >> 16));
+
+	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO,
+		      WITH_16BITS_WMSK(24000 * 5 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI,
+		      WITH_16BITS_WMSK(24000 * 5 >> 16));
+
+	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO,
+		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
+	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI,
+		      WITH_16BITS_WMSK(24000 * 2 >> 16));
+
+	/* Config pmu power mode and pmu wakeup source */
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
+		      WITH_16BITS_WMSK(pwrmd_core_lo));
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
+		      WITH_16BITS_WMSK(pwrmd_core_hi));
+
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
+		      WITH_16BITS_WMSK(pwrmd_com_lo));
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
+		      WITH_16BITS_WMSK(pwrmd_com_hi));
+
+	mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
+		      WITH_16BITS_WMSK(pmu_wkup_cfg2_lo));
+}
+
+static void pmu_sleep_restore(void)
+{
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
+		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l));
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
+		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h));
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
+		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l));
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
+		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h));
+	mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
+		      WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l));
+
+	/* restore pmic_sleep iomux */
+	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
+		      WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux));
+}
+
+static void soc_sleep_config(void)
+{
+	ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX);
+
+	pmu_sleep_config();
+
+	ddr_sleep_config();
+
+	pvtm_32k_config();
+}
+
+static void soc_sleep_restore(void)
+{
+	secure_timer_init();
+
+	pvtm_32k_config_restore();
+
+	ddr_sleep_config_restore();
+
+	pmu_sleep_restore();
+
+	mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX,
+		      WITH_16BITS_WMSK(ddr_data.gpio0c_iomux));
+}
+
+static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id)
+{
+	uint32_t delay = PLL_LOCKED_TIMEOUT;
+
+	while (delay > 0) {
+		if (mmio_read_32(pll_base + PLL_CON(1)) &
+		    PLL_LOCK_MSK)
+			break;
+		delay--;
+	}
+
+	if (delay == 0)
+		ERROR("Can't wait pll:%d lock\n", pll_id);
+}
+
+static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd)
+{
+	mmio_write_32(pll_base + PLL_CON(1),
+		      BITS_WITH_WMASK(1, 1U, 15));
+	if (pd)
+		mmio_write_32(pll_base + PLL_CON(1),
+			      BITS_WITH_WMASK(1, 1, 14));
+	else
+		mmio_write_32(pll_base + PLL_CON(1),
+			      BITS_WITH_WMASK(0, 1, 14));
+}
+
+static inline void pll_set_mode(uint32_t pll_id, uint32_t mode)
+{
+	uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id));
+
+	if (pll_id != GPLL_ID)
+		mmio_write_32(CRU_BASE + CRU_MODE, val);
+	else
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE,
+			      BITS_WITH_WMASK(mode, 0x3, 0));
+}
+
+static inline void pll_suspend(uint32_t pll_id)
+{
+	int i;
+	uint32_t pll_base;
+
+	if (pll_id != GPLL_ID)
+		pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
+	else
+		pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
+
+	/* save pll con */
+	for (i = 0; i < PLL_CON_CNT; i++)
+		ddr_data.cru_plls_con_save[pll_id][i] =
+				mmio_read_32(pll_base + PLL_CON(i));
+
+	/* slow mode */
+	pll_set_mode(pll_id, SLOW_MODE);
+}
+
+static inline void pll_resume(uint32_t pll_id)
+{
+	uint32_t mode, pll_base;
+
+	if (pll_id != GPLL_ID) {
+		pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
+		mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3;
+	} else {
+		pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
+		mode = ddr_data.cru_pmu_mode_save & 0x3;
+	}
+
+	/* if pll locked before suspend, we should wait atfer resume */
+	if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK)
+		pm_pll_wait_lock(pll_base, pll_id);
+
+	pll_set_mode(pll_id, mode);
+}
+
+static void pm_plls_suspend(void)
+{
+	ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE);
+	ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE);
+	ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0));
+
+	pll_suspend(GPLL_ID);
+	pll_suspend(NPLL_ID);
+	pll_suspend(CPLL_ID);
+	pll_suspend(APLL_ID);
+
+	/* core */
+	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+		      BITS_WITH_WMASK(0, 0xf, 0));
+
+	/* pclk_dbg */
+	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+		      BITS_WITH_WMASK(0, 0xf, 8));
+}
+
+static void pm_plls_resume(void)
+{
+	/* pclk_dbg */
+	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+		      ddr_data.clk_sel0 | BITS_WMSK(0xf, 8));
+
+	/* core */
+	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
+		      ddr_data.clk_sel0 | BITS_WMSK(0xf, 0));
+
+	pll_resume(APLL_ID);
+	pll_resume(CPLL_ID);
+	pll_resume(NPLL_ID);
+	pll_resume(GPLL_ID);
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	pmu_power_domains_suspend();
+
+	clk_gate_suspend();
+
+	soc_sleep_config();
+
+	pm_plls_suspend();
+
+	psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT;
+
+	pm_plls_resume();
+
+	soc_sleep_restore();
+
+	clk_gate_resume();
+
+	pmu_power_domains_resume();
+
+	plat_rockchip_gic_cpuif_enable();
+
+	return 0;
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	pll_set_mode(GPLL_ID, SLOW_MODE);
+	pll_set_mode(CPLL_ID, SLOW_MODE);
+	pll_set_mode(NPLL_ID, SLOW_MODE);
+	pll_set_mode(APLL_ID, SLOW_MODE);
+	dsb();
+
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
+	dsb();
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to execute valid codes.
+	 */
+	psci_power_down_wfi();
+}
+
+void __dead2 rockchip_soc_system_off(void)
+{
+	uint32_t val;
+
+	/* set pmic_sleep pin(gpio0_a4) to gpio mode */
+	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8));
+
+	/* config output */
+	val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR);
+	val |= BIT(4);
+	mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val);
+
+	/* config output high level */
+	val = mmio_read_32(GPIO0_BASE);
+	val |= BIT(4);
+	mmio_write_32(GPIO0_BASE, val);
+	dsb();
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to execute valid codes.
+	 */
+	psci_power_down_wfi();
+}
+
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for px30 SoCs */
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	uint32_t cpu;
+
+	rockchip_pd_lock_init();
+
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = 0;
+
+	psram_boot_cfg->ddr_func = (uint64_t)0;
+	psram_boot_cfg->ddr_data = (uint64_t)0;
+	psram_boot_cfg->sp = PSRAM_SP_TOP;
+	psram_boot_cfg->ddr_flag = 0x0;
+	psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
+	psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT;
+
+	nonboot_cpus_off();
+
+	/* Remap pmu_sram's base address to boot address */
+	mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0),
+		      BITS_WITH_WMASK(1, 0x1, 13));
+
+	INFO("%s: pd status %x\n",
+	     __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
+}
diff --git a/plat/rockchip/px30/drivers/pmu/pmu.h b/plat/rockchip/px30/drivers/pmu/pmu.h
new file mode 100644
index 0000000..416d1c1
--- /dev/null
+++ b/plat/rockchip/px30/drivers/pmu/pmu.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PMU_H__
+#define __PMU_H__
+
+/* Needed aligned 16 bytes for sp stack top */
+#define PSRAM_SP_TOP		((PMUSRAM_BASE + PMUSRAM_RSIZE) & ~0xf)
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WKUP_CFG0_LO		0x00
+#define PMU_WKUP_CFG0_HI		0x04
+#define PMU_WKUP_CFG1_LO		0x08
+#define PMU_WKUP_CFG1_HI		0x0c
+#define PMU_WKUP_CFG2_LO		0x10
+
+#define PMU_PWRDN_CON			0x18
+#define PMU_PWRDN_ST			0x20
+
+#define PMU_PWRMODE_CORE_LO		0x24
+#define PMU_PWRMODE_CORE_HI		0x28
+#define PMU_PWRMODE_COMMON_CON_LO	0x2c
+#define PMU_PWRMODE_COMMON_CON_HI	0x30
+
+#define PMU_SFT_CON			0x34
+#define PMU_INT_ST			0x44
+#define PMU_BUS_IDLE_REQ		0x64
+#define PMU_BUS_IDLE_ST			0x6c
+
+#define PMU_OSC_CNT_LO			0x74
+#define PMU_OSC_CNT_HI			0x78
+#define PMU_PLLLOCK_CNT_LO		0x7c
+#define PMU_PLLLOCK_CNT_HI		0x80
+#define PMU_PLLRST_CNT_LO		0x84
+#define PMU_PLLRST_CNT_HI		0x88
+#define PMU_STABLE_CNT_LO		0x8c
+#define PMU_STABLE_CNT_HI		0x90
+#define PMU_WAKEUP_RST_CLR_LO		0x9c
+#define PMU_WAKEUP_RST_CLR_HI		0xa0
+
+#define PMU_DDR_SREF_ST			0xa4
+
+#define PMU_SYS_REG0_LO			0xa8
+#define PMU_SYS_REG0_HI			0xac
+#define PMU_SYS_REG1_LO			0xb0
+#define PMU_SYS_REG1_HI			0xb4
+#define PMU_SYS_REG2_LO			0xb8
+#define PMU_SYS_REG2_HI			0xbc
+#define PMU_SYS_REG3_LO			0xc0
+#define PMU_SYS_REG3_HI			0xc4
+
+#define PMU_SCU_PWRDN_CNT_LO		0xc8
+#define PMU_SCU_PWRDN_CNT_HI		0xcc
+#define PMU_SCU_PWRUP_CNT_LO		0xd0
+#define PMU_SCU_PWRUP_CNT_HI		0xd4
+
+#define PMU_TIMEOUT_CNT_LO		0xd8
+#define PMU_TIMEOUT_CNT_HI		0xdc
+
+#define PMU_CPUAPM_CON(cpu)		(0xe0 + (cpu) * 0x4)
+
+#define CORES_PM_DISABLE	0x0
+#define CLST_CPUS_MSK		0xf
+
+#define PD_CTR_LOOP		500
+#define PD_CHECK_LOOP		500
+#define WFEI_CHECK_LOOP		500
+#define BUS_IDLE_LOOP		1000
+
+enum pmu_wkup_cfg2 {
+	pmu_cluster_wkup_en = 0,
+	pmu_gpio_wkup_en = 2,
+	pmu_sdio_wkup_en = 3,
+	pmu_sdmmc_wkup_en = 4,
+	pmu_uart0_wkup_en = 5,
+	pmu_timer_wkup_en = 6,
+	pmu_usbdev_wkup_en = 7,
+	pmu_sft_wkup_en = 8,
+	pmu_timeout_wkup_en = 10,
+};
+
+enum pmu_powermode_core_lo {
+	pmu_global_int_dis = 0,
+	pmu_core_src_gt = 1,
+	pmu_cpu0_pd = 3,
+	pmu_clr_core = 5,
+	pmu_scu_pd = 6,
+	pmu_l2_idle = 8,
+	pmu_l2_flush = 9,
+	pmu_clr_bus2main = 10,
+	pmu_clr_peri2msch = 11,
+};
+
+enum pmu_powermode_core_hi {
+	pmu_apll_pd_en = 3,
+	pmu_dpll_pd_en = 4,
+	pmu_cpll_pd_en = 5,
+	pmu_gpll_pd_en = 6,
+	pmu_npll_pd_en = 7,
+};
+
+enum pmu_powermode_common_lo {
+	pmu_mode_en = 0,
+	pmu_ddr_pd_en = 1,
+	pmu_wkup_rst = 3,
+	pmu_pll_pd = 4,
+	pmu_pmu_use_if = 6,
+	pmu_alive_use_if = 7,
+	pmu_osc_dis = 8,
+	pmu_input_clamp = 9,
+	pmu_sref_enter = 10,
+	pmu_ddrc_gt = 11,
+	pmu_ddrio_ret = 12,
+	pmu_ddrio_ret_deq = 13,
+	pmu_clr_pmu = 14,
+	pmu_clr_peri_pmu = 15,
+};
+
+enum pmu_powermode_common_hi {
+	pmu_clr_bus = 0,
+	pmu_clr_mmc = 1,
+	pmu_clr_msch = 2,
+	pmu_clr_nandc = 3,
+	pmu_clr_gmac = 4,
+	pmu_clr_vo = 5,
+	pmu_clr_vi = 6,
+	pmu_clr_gpu = 7,
+	pmu_clr_usb = 8,
+	pmu_clr_vpu = 9,
+	pmu_clr_crypto = 10,
+	pmu_wakeup_begin_cfg = 11,
+	pmu_peri_clk_src_gt = 12,
+	pmu_bus_clk_src_gt = 13,
+};
+
+enum pmu_pd_id {
+	PD_CPU0 = 0,
+	PD_CPU1 = 1,
+	PD_CPU2 = 2,
+	PD_CPU3 = 3,
+	PD_SCU = 4,
+	PD_USB = 5,
+	PD_DDR = 6,
+	PD_SDCARD = 8,
+	PD_CRYPTO = 9,
+	PD_GMAC = 10,
+	PD_MMC_NAND = 11,
+	PD_VPU = 12,
+	PD_VO = 13,
+	PD_VI = 14,
+	PD_GPU = 15,
+	PD_END = 16,
+};
+
+enum pmu_bus_id {
+	BUS_ID_BUS = 0,
+	BUS_ID_BUS2MAIN = 1,
+	BUS_ID_GPU = 2,
+	BUS_ID_CORE = 3,
+	BUS_ID_CRYPTO = 4,
+	BUS_ID_MMC = 5,
+	BUS_ID_GMAC = 6,
+	BUS_ID_VO = 7,
+	BUS_ID_VI = 8,
+	BUS_ID_SDCARD = 9,
+	BUS_ID_USB = 10,
+	BUS_ID_MSCH = 11,
+	BUS_ID_PERI = 12,
+	BUS_ID_PMU = 13,
+	BUS_ID_VPU = 14,
+	BUS_ID_PERI2MSCH = 15,
+};
+
+enum pmu_pd_state {
+	pmu_pd_on = 0,
+	pmu_pd_off = 1
+};
+
+enum pmu_bus_state {
+	bus_active = 0,
+	bus_idle = 1,
+};
+
+enum cores_pm_ctr_mode {
+	core_pwr_pd = 0,
+	core_pwr_wfi = 1,
+	core_pwr_wfi_int = 2
+};
+
+enum pmu_cores_pm_by_wfi {
+	core_pm_en = 0,
+	core_pm_int_wakeup_en,
+	core_pm_dis_int,
+	core_pm_sft_wakeup_en
+};
+
+/*****************************************************************************
+ * pmu_sgrf
+ *****************************************************************************/
+#define PMUSGRF_SOC_CON(i)	((i) * 0x4)
+
+/*****************************************************************************
+ * pmu_grf
+ *****************************************************************************/
+#define GPIO0A_IOMUX		0x0
+#define GPIO0B_IOMUX		0x4
+#define GPIO0C_IOMUX		0x8
+#define GPIO0A_PULL		0x10
+
+#define GPIO0L_SMT		0x38
+#define GPIO0H_SMT		0x3c
+
+#define PMUGRF_SOC_CON(i)	(0x100 + (i) * 4)
+
+#define PMUGRF_PVTM_CON0	0x180
+#define PMUGRF_PVTM_CON1	0x184
+#define PMUGRF_PVTM_ST0		0x190
+#define PMUGRF_PVTM_ST1		0x194
+
+#define PVTM_CALC_CNT		0x200
+
+#define PMUGRF_OS_REG(n)	(0x200 + (n) * 4)
+
+#define GPIO0A6_IOMUX_MSK	(0x3 << 12)
+#define GPIO0A6_IOMUX_GPIO	(0x0 << 12)
+#define GPIO0A6_IOMUX_RSTOUT	(0x1 << 12)
+#define GPIO0A6_IOMUX_SHTDN	(0x2 << 12)
+
+enum px30_pmugrf_pvtm_con0 {
+	pgrf_pvtm_st = 0,
+	pgrf_pvtm_en = 1,
+	pgrf_pvtm_div = 2,
+};
+
+/*****************************************************************************
+ * pmu_cru
+ *****************************************************************************/
+#define CRU_PMU_MODE			0x20
+#define CRU_PMU_CLKSEL_CON		0x40
+#define CRU_PMU_CLKSELS_CON(i)		(CRU_PMU_CLKSEL_CON + (i) * 4)
+#define CRU_PMU_CLKSEL_CON_CNT		5
+#define CRU_PMU_CLKGATE_CON		0x80
+#define CRU_PMU_CLKGATES_CON(i)		(CRU_PMU_CLKGATE_CON + (i) * 4)
+#define CRU_PMU_CLKGATE_CON_CNT		2
+#define CRU_PMU_ATCS_CON		0xc0
+#define CRU_PMU_ATCSS_CON(i)		(CRU_PMU_ATCS_CON + (i) * 4)
+#define CRU_PMU_ATCS_CON_CNT		2
+
+/*****************************************************************************
+ * pmusgrf
+ *****************************************************************************/
+#define PMUSGRF_RSTOUT_EN (0x7 << 10)
+#define PMUSGRF_RSTOUT_FST 10
+#define PMUSGRF_RSTOUT_TSADC 11
+#define PMUSGRF_RSTOUT_WDT 12
+
+#define PMUGRF_SOC_CON2_US_WMSK  (0x1fff << 16)
+#define PMUGRF_SOC_CON2_MAX_341US  0x1fff
+#define PMUGRF_SOC_CON2_200US  0x12c0
+
+#define PMUGRF_FAILSAFE_SHTDN_TSADC BIT(0)
+#define PMUGRF_FAILSAFE_SHTDN_WDT BIT(1)
+
+/*****************************************************************************
+ * QOS
+ *****************************************************************************/
+#define CPU_AXI_QOS_ID_COREID		0x00
+#define CPU_AXI_QOS_REVISIONID		0x04
+#define CPU_AXI_QOS_PRIORITY		0x08
+#define CPU_AXI_QOS_MODE		0x0c
+#define CPU_AXI_QOS_BANDWIDTH		0x10
+#define CPU_AXI_QOS_SATURATION		0x14
+#define CPU_AXI_QOS_EXTCONTROL		0x18
+#define CPU_AXI_QOS_NUM_REGS		0x07
+
+#define CPU_AXI_CPU_QOS_BASE		0xff508000
+#define CPU_AXI_GPU_QOS_BASE		0xff520000
+#define CPU_AXI_ISP_128M_QOS_BASE	0xff548000
+#define CPU_AXI_ISP_RD_QOS_BASE		0xff548080
+#define CPU_AXI_ISP_WR_QOS_BASE		0xff548100
+#define CPU_AXI_ISP_M1_QOS_BASE		0xff548180
+#define CPU_AXI_VIP_QOS_BASE		0xff548200
+#define CPU_AXI_RGA_RD_QOS_BASE		0xff550000
+#define CPU_AXI_RGA_WR_QOS_BASE		0xff550080
+#define CPU_AXI_VOP_M0_QOS_BASE		0xff550100
+#define CPU_AXI_VOP_M1_QOS_BASE		0xff550180
+#define CPU_AXI_VPU_QOS_BASE		0xff558000
+#define CPU_AXI_VPU_R128_QOS_BASE	0xff558080
+#define CPU_AXI_DCF_QOS_BASE		0xff500000
+#define CPU_AXI_DMAC_QOS_BASE		0xff500080
+#define CPU_AXI_CRYPTO_QOS_BASE		0xff510000
+#define CPU_AXI_GMAC_QOS_BASE		0xff518000
+#define CPU_AXI_EMMC_QOS_BASE		0xff538000
+#define CPU_AXI_NAND_QOS_BASE		0xff538080
+#define CPU_AXI_SDIO_QOS_BASE		0xff538100
+#define CPU_AXI_SFC_QOS_BASE		0xff538180
+#define CPU_AXI_SDMMC_QOS_BASE		0xff52c000
+#define CPU_AXI_USB_HOST_QOS_BASE	0xff540000
+#define CPU_AXI_USB_OTG_QOS_BASE	0xff540080
+
+#define PX30_CPU_AXI_SAVE_QOS(array, base) do { \
+	array[0] = mmio_read_32(base + CPU_AXI_QOS_ID_COREID); \
+	array[1] = mmio_read_32(base + CPU_AXI_QOS_REVISIONID); \
+	array[2] = mmio_read_32(base + CPU_AXI_QOS_PRIORITY); \
+	array[3] = mmio_read_32(base + CPU_AXI_QOS_MODE); \
+	array[4] = mmio_read_32(base + CPU_AXI_QOS_BANDWIDTH); \
+	array[5] = mmio_read_32(base + CPU_AXI_QOS_SATURATION); \
+	array[6] = mmio_read_32(base + CPU_AXI_QOS_EXTCONTROL); \
+} while (0)
+
+#define PX30_CPU_AXI_RESTORE_QOS(array, base) do { \
+	mmio_write_32(base + CPU_AXI_QOS_ID_COREID, array[0]); \
+	mmio_write_32(base + CPU_AXI_QOS_REVISIONID, array[1]); \
+	mmio_write_32(base + CPU_AXI_QOS_PRIORITY, array[2]); \
+	mmio_write_32(base + CPU_AXI_QOS_MODE, array[3]); \
+	mmio_write_32(base + CPU_AXI_QOS_BANDWIDTH, array[4]); \
+	mmio_write_32(base + CPU_AXI_QOS_SATURATION, array[5]); \
+	mmio_write_32(base + CPU_AXI_QOS_EXTCONTROL, array[6]); \
+} while (0)
+
+#define SAVE_QOS(array, NAME) \
+	PX30_CPU_AXI_SAVE_QOS(array, CPU_AXI_##NAME##_QOS_BASE)
+#define RESTORE_QOS(array, NAME) \
+	PX30_CPU_AXI_RESTORE_QOS(array, CPU_AXI_##NAME##_QOS_BASE)
+
+#endif /* __PMU_H__ */
diff --git a/plat/rockchip/px30/drivers/soc/soc.c b/plat/rockchip/px30/drivers/soc/soc.c
new file mode 100644
index 0000000..e00561d
--- /dev/null
+++ b/plat/rockchip/px30/drivers/soc/soc.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <ddr_parameter.h>
+#include <platform_def.h>
+#include <pmu.h>
+#include <px30_def.h>
+#include <soc.h>
+#include <rockchip_sip_svc.h>
+
+/* Aggregate of all devices in the first GB */
+#define PX30_DEV_RNG0_BASE	0xff000000
+#define PX30_DEV_RNG0_SIZE	0x00ff0000
+
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(PX30_DEV_RNG0_BASE, PX30_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SHARE_MEM_BASE, SHARE_MEM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PARAM_BASE, DDR_PARAM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+void clk_gate_con_save(uint32_t *clkgt_save)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		clkgt_save[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
+	j = i;
+	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++, j++)
+		clkgt_save[j] =
+			mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i));
+}
+
+void clk_gate_con_restore(uint32_t *clkgt_save)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+			      WITH_16BITS_WMSK(clkgt_save[i]));
+
+	j = i;
+	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++, j++)
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+			      WITH_16BITS_WMSK(clkgt_save[j]));
+}
+
+void clk_gate_con_disable(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+			      0xffff0000);
+
+	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++)
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
+			      0xffff0000);
+}
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG,
+		      TIMER_DIS);
+
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOAD_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOAD_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG,
+		      TIMER_EN | TIMER_FMODE);
+}
+
+static void sgrf_init(void)
+{
+	uint32_t i, val;
+	struct param_ddr_usage usg;
+
+	/* general secure regions */
+	usg = ddr_region_usage_parse(DDR_PARAM_BASE,
+				     PLAT_MAX_DDR_CAPACITY_MB);
+	for (i = 0; i < usg.s_nr; i++) {
+		/* enable secure */
+		val = mmio_read_32(FIREWALL_DDR_BASE +
+			      FIREWALL_DDR_FW_DDR_CON_REG);
+		val |= BIT(7 - i);
+		mmio_write_32(FIREWALL_DDR_BASE +
+			      FIREWALL_DDR_FW_DDR_CON_REG, val);
+		/* map top and base */
+		mmio_write_32(FIREWALL_DDR_BASE +
+			      FIREWALL_DDR_FW_DDR_RGN(7 - i),
+			      RG_MAP_SECURE(usg.s_top[i], usg.s_base[i]));
+	}
+
+	/* set ddr rgn0_top and rga0_top as 0 */
+	mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_RGN(0), 0x0);
+
+	/* set all slave ip into no-secure, except stimer */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4), SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7), SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(8), 0x00030000);
+
+	/* set master crypto to no-secure, dcf to secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), 0x000f0003);
+
+	/* set DMAC into no-secure */
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(0), DMA_IRQ_BOOT_NS);
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(1), DMA_PERI_CH_NS_15_0);
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(2), DMA_PERI_CH_NS_19_16);
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(3), DMA_MANAGER_BOOT_NS);
+
+	/* soft reset dma before use */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), DMA_SOFTRST_REQ);
+	udelay(5);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), DMA_SOFTRST_RLS);
+}
+
+static void soc_reset_config_all(void)
+{
+	uint32_t tmp;
+
+	/* tsadc and wdt can trigger a first rst */
+	tmp = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
+	tmp |= CRU_GLB_RST_TSADC_FST | CRU_GLB_RST_WDT_FST;
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, tmp);
+	return;
+	tmp = mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(3));
+	tmp &= ~(PMUGRF_FAILSAFE_SHTDN_TSADC | PMUGRF_FAILSAFE_SHTDN_WDT);
+	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(3), tmp);
+
+	/* wdt pin rst eable */
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(2),
+		      BIT_WITH_WMSK(GRF_SOC_CON2_NSWDT_RST_EN));
+}
+
+void px30_soc_reset_config(void)
+{
+	uint32_t tmp;
+
+	/* enable soc ip rst hold time cfg */
+	tmp = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
+	tmp |= BIT(CRU_GLB_RST_TSADC_EXT) | BIT(CRU_GLB_RST_WDT_EXT);
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, tmp);
+	/* soc ip rst hold time, 24m */
+	tmp = mmio_read_32(CRU_BASE + CRU_GLB_CNT_TH);
+	tmp &= ~CRU_GLB_CNT_RST_MSK;
+	tmp |= (CRU_GLB_CNT_RST_1MS / 2);
+	mmio_write_32(CRU_BASE + CRU_GLB_CNT_TH, tmp);
+
+	mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0),
+		      BIT_WITH_WMSK(PMUSGRF_RSTOUT_FST) |
+		      BIT_WITH_WMSK(PMUSGRF_RSTOUT_TSADC) |
+		      BIT_WITH_WMSK(PMUSGRF_RSTOUT_WDT));
+
+	/* rst_out pulse time */
+	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(2),
+		      PMUGRF_SOC_CON2_MAX_341US | PMUGRF_SOC_CON2_US_WMSK);
+
+	soc_reset_config_all();
+}
+
+void plat_rockchip_soc_init(void)
+{
+	secure_timer_init();
+	sgrf_init();
+}
diff --git a/plat/rockchip/px30/drivers/soc/soc.h b/plat/rockchip/px30/drivers/soc/soc.h
new file mode 100644
index 0000000..69f2de4
--- /dev/null
+++ b/plat/rockchip/px30/drivers/soc/soc.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SOC_H__
+#define __SOC_H__
+
+#include <plat_private.h>
+
+#ifndef BITS_WMSK
+#define BITS_WMSK(msk, shift)	((msk) << (shift + REG_MSK_SHIFT))
+#endif
+
+enum plls_id {
+	APLL_ID = 0,
+	DPLL_ID,
+	CPLL_ID,
+	NPLL_ID,
+	GPLL_ID,
+	END_PLL_ID,
+};
+
+enum pll_mode {
+	SLOW_MODE,
+	NORM_MODE,
+	DEEP_SLOW_MODE,
+};
+
+/***************************************************************************
+ * SGRF
+ ***************************************************************************/
+#define SGRF_SOC_CON(i)		((i) * 0x4)
+#define SGRF_DMAC_CON(i)	(0x30 + (i) * 0x4)
+
+#define SGRF_MST_S_ALL_NS	0xffffffff
+#define SGRF_SLV_S_ALL_NS	0xffff0000
+#define DMA_IRQ_BOOT_NS		0xffffffff
+#define DMA_PERI_CH_NS_15_0	0xffffffff
+#define DMA_PERI_CH_NS_19_16	0x000f000f
+#define DMA_MANAGER_BOOT_NS	0x00010001
+#define DMA_SOFTRST_REQ		BITS_WITH_WMASK(1, 0x1, 12)
+#define DMA_SOFTRST_RLS		BITS_WITH_WMASK(0, 0x1, 12)
+
+/***************************************************************************
+ * GRF
+ ***************************************************************************/
+#define GRF_SOC_CON(i)		(0x0400 + (i) * 4)
+#define GRF_PD_VO_CON0		0x0434
+#define GRF_SOC_STATUS0		0x0480
+#define GRF_CPU_STATUS0		0x0520
+#define GRF_CPU_STATUS1		0x0524
+#define GRF_SOC_NOC_CON0	0x0530
+#define GRF_SOC_NOC_CON1	0x0534
+
+#define CKECK_WFE_MSK		0x1
+#define CKECK_WFI_MSK		0x10
+#define CKECK_WFEI_MSK		0x11
+
+#define GRF_SOC_CON2_NSWDT_RST_EN 12
+
+/***************************************************************************
+ * DDR FIREWALL
+ ***************************************************************************/
+#define FIREWALL_DDR_FW_DDR_RGN(i)	((i) * 0x4)
+#define FIREWALL_DDR_FW_DDR_MST(i)	(0x20 + (i) * 0x4)
+#define FIREWALL_DDR_FW_DDR_CON_REG	0x40
+#define FIREWALL_DDR_FW_DDR_RGN_NUM	8
+#define FIREWALL_DDR_FW_DDR_MST_NUM	6
+
+#define PLAT_MAX_DDR_CAPACITY_MB	4096
+#define RG_MAP_SECURE(top, base)	((((top) - 1) << 16) | (base))
+
+/***************************************************************************
+ * cru
+ ***************************************************************************/
+#define CRU_MODE		0xa0
+#define CRU_MISC		0xa4
+#define CRU_GLB_CNT_TH	0xb0
+#define CRU_GLB_RST_ST	0xb4
+#define CRU_GLB_SRST_FST	0xb8
+#define CRU_GLB_SRST_SND	0xbc
+#define CRU_GLB_RST_CON		0xc0
+
+#define CRU_CLKSEL_CON		0x100
+#define CRU_CLKSELS_CON(i)	(CRU_CLKSEL_CON + (i) * 4)
+#define CRU_CLKSEL_CON_CNT	60
+
+#define CRU_CLKGATE_CON		0x200
+#define CRU_CLKGATES_CON(i)	(CRU_CLKGATE_CON + (i) * 4)
+#define CRU_CLKGATES_CON_CNT	18
+
+#define CRU_SOFTRST_CON		0x300
+#define CRU_SOFTRSTS_CON(n)	(CRU_SOFTRST_CON + ((n) * 4))
+#define CRU_SOFTRSTS_CON_CNT	12
+
+#define CRU_AUTOCS_CON0(id)	(0x400 + (id) * 8)
+#define CRU_AUTOCS_CON1(id)	(0x404 + (id) * 8)
+
+#define CRU_CONS_GATEID(i)	(16 * (i))
+#define GATE_ID(reg, bit)	((reg) * 16 + (bit))
+
+#define CRU_GLB_SRST_FST_VALUE	0xfdb9
+#define CRU_GLB_SRST_SND_VALUE	0xeca8
+
+#define CRU_GLB_RST_TSADC_EXT 6
+#define CRU_GLB_RST_WDT_EXT 7
+
+#define CRU_GLB_CNT_RST_MSK  0xffff
+#define CRU_GLB_CNT_RST_1MS  0x5DC0
+
+#define CRU_GLB_RST_TSADC_FST BIT(0)
+#define CRU_GLB_RST_WDT_FST BIT(1)
+
+/***************************************************************************
+ * pll
+ ***************************************************************************/
+#define CRU_PLL_CONS(id, i)	((id) * 0x20 + (i) * 4)
+#define PLL_CON(i)		((i) * 4)
+#define PLL_CON_CNT		5
+#define PLL_LOCK_MSK		BIT(10)
+#define PLL_MODE_SHIFT(id)	((id) == CPLL_ID ? \
+				  2 : \
+				  ((id) == DPLL_ID ? 4 : 2 * (id)))
+#define PLL_MODE_MSK(id)	(0x3 << PLL_MODE_SHIFT(id))
+
+#define PLL_LOCKED_TIMEOUT	600000U
+
+/***************************************************************************
+ * GPIO
+ ***************************************************************************/
+#define SWPORTA_DR		0x00
+#define SWPORTA_DDR		0x04
+#define GPIO_INTEN		0x30
+#define GPIO_INT_STATUS		0x40
+#define GPIO_NUMS		4
+
+/**************************************************
+ * secure timer
+ **************************************************/
+
+/* chanal0~5 */
+#define STIMER_CHN_BASE(n)	(STIME_BASE + 0x20 * (n))
+
+#define TIMER_LOAD_COUNT0	0x0
+#define TIMER_LOAD_COUNT1	0x4
+
+#define TIMER_CUR_VALUE0	0x8
+#define TIMER_CUR_VALUE1	0xc
+
+#define TIMER_CONTROL_REG	0x10
+#define TIMER_INTSTATUS		0x18
+
+#define TIMER_DIS		0x0
+#define TIMER_EN		0x1
+
+#define TIMER_FMODE		(0x0 << 1)
+#define TIMER_RMODE		(0x1 << 1)
+
+#define TIMER_LOAD_COUNT0_MSK	(0xffffffff)
+#define TIMER_LOAD_COUNT1_MSK	(0xffffffff00000000)
+
+void clk_gate_con_save(uint32_t *clkgt_save);
+void clk_gate_con_restore(uint32_t *clkgt_save);
+void clk_gate_con_disable(void);
+
+void secure_timer_init(void);
+void secure_timer_disable(void);
+void px30_soc_reset_config(void);
+
+#endif /* __SOC_H__ */
diff --git a/plat/rockchip/px30/include/plat.ld.S b/plat/rockchip/px30/include/plat.ld.S
new file mode 100644
index 0000000..44cca0d
--- /dev/null
+++ b/plat/rockchip/px30/include/plat.ld.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __ROCKCHIP_PLAT_LD_S__
+#define __ROCKCHIP_PLAT_LD_S__
+
+MEMORY {
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		KEEP(*(.pmusram.entry))
+
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+	} >PMUSRAM
+}
+
+#endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/px30/include/plat_sip_calls.h b/plat/rockchip/px30/include/plat_sip_calls.h
new file mode 100644
index 0000000..7b6a6a8
--- /dev/null
+++ b/plat/rockchip/px30/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_SIP_CALLS_H__
+#define __PLAT_SIP_CALLS_H__
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* __PLAT_SIP_CALLS_H__ */
diff --git a/plat/rockchip/px30/include/platform_def.h b/plat/rockchip/px30/include/platform_def.h
new file mode 100644
index 0000000..c101cdc
--- /dev/null
+++ b/plat/rockchip/px30/include/platform_def.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include <common_def.h>
+#include <px30_def.h>
+
+#define DEBUG_XLAT_TABLE 0
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if DEBUG_XLAT_TABLE
+#define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL1
+#define PLATFORM_STACK_SIZE 0x440
+#elif IMAGE_BL2
+#define PLATFORM_STACK_SIZE 0x400
+#elif IMAGE_BL31
+#define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL32
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	8
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		1
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		2
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF txet, ro, rw, Size: 512KB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x80000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted RAM
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x10000)
+#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ull << 32)
+#define ADDR_SPACE_SIZE		(1ull << 32)
+#define MAX_XLAT_TABLES		8
+#define MAX_MMAP_REGIONS	27
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE	PX30_GICD_BASE
+#define PLAT_RK_GICC_BASE	PX30_GICC_BASE
+
+#define PLAT_RK_UART_BASE	PX30_UART_BASE
+#define PLAT_RK_UART_CLOCK	PX30_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE	PX30_BAUDRATE
+
+#define PLAT_RK_PRIMARY_CPU	0x0
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rockchip/px30/plat_sip_calls.c b/plat/rockchip/px30/plat_sip_calls.c
new file mode 100644
index 0000000..a4b8e55
--- /dev/null
+++ b/plat/rockchip/px30/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+				    u_register_t x1,
+				    u_register_t x2,
+				    u_register_t x3,
+				    u_register_t x4,
+				    void *cookie,
+				    void *handle,
+				    u_register_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/rockchip/px30/platform.mk b/plat/rockchip/px30/platform.mk
new file mode 100644
index 0000000..ee85cd3
--- /dev/null
+++ b/plat/rockchip/px30/platform.mk
@@ -0,0 +1,65 @@
+#
+#Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+#SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+RK_PLAT			:=	plat/rockchip
+RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON		:=	${RK_PLAT}/common
+
+DISABLE_BIN_GENERATION	:=	1
+
+PLAT_INCLUDES		:=	-Idrivers/arm/gic/common/			\
+				-Idrivers/arm/gic/v2/				\
+				-Iinclude/plat/common/				\
+				-I${RK_PLAT_COMMON}/				\
+				-I${RK_PLAT_COMMON}/include/			\
+				-I${RK_PLAT_COMMON}/drivers/parameter/		\
+				-I${RK_PLAT_COMMON}/pmusram			\
+				-I${RK_PLAT_SOC}/				\
+				-I${RK_PLAT_SOC}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/include/
+
+RK_GIC_SOURCES         :=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				plat/common/aarch64/crash_console_helpers.S	\
+				${RK_PLAT}/common/rockchip_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	lib/bl_aux_params/bl_aux_params.c		\
+				lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				plat/common/plat_psci_common.c
+
+BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
+				common/desc_image_load.c			\
+				drivers/arm/cci/cci.c				\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/ti/uart/aarch64/16550_console.S		\
+				lib/cpus/aarch64/cortex_a35.S			\
+				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
+				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
+				${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c	\
+				${RK_PLAT_COMMON}/params_setup.c		\
+				${RK_PLAT_COMMON}/pmusram/cpus_on_fixed_addr.S	\
+				${RK_PLAT_COMMON}/plat_pm.c			\
+				${RK_PLAT_COMMON}/plat_topology.c		\
+				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+				${RK_PLAT_SOC}/drivers/soc/soc.c		\
+				${RK_PLAT_SOC}/plat_sip_calls.c
+
+ENABLE_PLAT_COMPAT	:=	0
+MULTI_CONSOLE_API	:=	1
+
+include lib/libfdt/libfdt.mk
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+$(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER))
+$(eval $(call add_define,PLAT_WARMBOOT_ADDR_NOT_ALIGN))
diff --git a/plat/rockchip/px30/px30_def.h b/plat/rockchip/px30/px30_def.h
new file mode 100644
index 0000000..9b8ccfc
--- /dev/null
+++ b/plat/rockchip/px30/px30_def.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PX30_DEF_H__
+#define __PX30_DEF_H__
+
+#define MAJOR_VERSION		(1)
+#define MINOR_VERSION		(0)
+
+#define SIZE_K(n)		((n) * 1024)
+
+#define WITH_16BITS_WMSK(bits)	(0xffff0000 | (bits))
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define PMU_BASE		0xff000000
+#define PMU_SIZE		SIZE_K(64)
+
+#define PMUGRF_BASE		0xff010000
+#define PMUGRF_SIZE		SIZE_K(64)
+
+#define PMUSRAM_BASE		0xff020000
+#define PMUSRAM_SIZE		SIZE_K(64)
+#define PMUSRAM_RSIZE		SIZE_K(8)
+
+#define UART0_BASE		0xff030000
+#define UART0_SIZE		SIZE_K(64)
+
+#define GPIO0_BASE		0xff040000
+#define GPIO0_SIZE		SIZE_K(64)
+
+#define PMUSGRF_BASE		0xff050000
+#define PMUSGRF_SIZE		SIZE_K(64)
+
+#define INTSRAM_BASE		0xff0e0000
+#define INTSRAM_SIZE		SIZE_K(64)
+
+#define SGRF_BASE		0xff11c000
+#define SGRF_SIZE		SIZE_K(16)
+
+#define GIC400_BASE		0xff130000
+#define GIC400_SIZE		SIZE_K(64)
+
+#define GRF_BASE		0xff140000
+#define GRF_SIZE		SIZE_K(64)
+
+#define UART1_BASE		0xff158000
+#define UART1_SIZE		SIZE_K(64)
+
+#define UART2_BASE		0xff160000
+#define UART2_SIZE		SIZE_K(64)
+
+#define UART5_BASE		0xff178000
+#define UART5_SIZE		SIZE_K(64)
+
+#define I2C0_BASE		0xff180000
+#define I2C0_SIZE		SIZE_K(64)
+
+#define PWM0_BASE		0xff200000
+#define PWM0_SIZE		SIZE_K(32)
+
+#define PWM1_BASE		0xff208000
+#define PWM1_SIZE		SIZE_K(32)
+
+#define NTIME_BASE		0xff210000
+#define NTIME_SIZE		SIZE_K(64)
+
+#define STIME_BASE		0xff220000
+#define STIME_SIZE		SIZE_K(64)
+
+#define DCF_BASE		0xff230000
+#define DCF_SIZE		SIZE_K(64)
+
+#define GPIO1_BASE		0xff250000
+#define GPIO1_SIZE		SIZE_K(64)
+
+#define GPIO2_BASE		0xff260000
+#define GPIO2_SIZE		SIZE_K(64)
+
+#define GPIO3_BASE		0xff270000
+#define GPIO3_SIZE		SIZE_K(64)
+
+#define DDR_PHY_BASE		0xff2a0000
+#define DDR_PHY_SIZE		SIZE_K(64)
+
+#define CRU_BASE		0xff2b0000
+#define CRU_SIZE		SIZE_K(32)
+
+#define CRU_BOOST_BASE		0xff2b8000
+#define CRU_BOOST_SIZE		SIZE_K(16)
+
+#define PMUCRU_BASE		0xff2bc000
+#define PMUCRU_SIZE		SIZE_K(16)
+
+#define VOP_BASE		0xff460000
+#define VOP_SIZE		SIZE_K(16)
+
+#define SERVER_MSCH_BASE	0xff530000
+#define SERVER_MSCH_SIZE	SIZE_K(64)
+
+#define FIREWALL_DDR_BASE	0xff534000
+#define FIREWALL_DDR_SIZE	SIZE_K(16)
+
+#define DDR_UPCTL_BASE		0xff600000
+#define DDR_UPCTL_SIZE		SIZE_K(64)
+
+#define DDR_MNTR_BASE		0xff610000
+#define DDR_MNTR_SIZE		SIZE_K(64)
+
+#define DDR_STDBY_BASE		0xff620000
+#define DDR_STDBY_SIZE		SIZE_K(64)
+
+#define DDRGRF_BASE		0xff630000
+#define DDRGRF_SIZE		SIZE_K(32)
+
+/**************************************************************************
+ * UART related constants
+ **************************************************************************/
+#define PX30_UART_BASE		UART2_BASE
+#define PX30_BAUDRATE		1500000
+#define PX30_UART_CLOCK		24000000
+
+/******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	24000000
+#define SYS_COUNTER_FREQ_IN_MHZ		24
+
+/******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base rk_platform compatible GIC memory map */
+#define PX30_GICD_BASE		(GIC400_BASE + 0x1000)
+#define PX30_GICC_BASE		(GIC400_BASE + 0x2000)
+#define PX30_GICR_BASE		0	/* no GICR in GIC-400 */
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define RK_IRQ_SEC_PHY_TIMER	29
+
+#define RK_IRQ_SEC_SGI_0	8
+#define RK_IRQ_SEC_SGI_1	9
+#define RK_IRQ_SEC_SGI_2	10
+#define RK_IRQ_SEC_SGI_3	11
+#define RK_IRQ_SEC_SGI_4	12
+#define RK_IRQ_SEC_SGI_5	13
+#define RK_IRQ_SEC_SGI_6	14
+#define RK_IRQ_SEC_SGI_7	15
+
+/*
+ * Define a list of Group 0 interrupts.
+ */
+#define PLAT_RK_GICV2_G0_IRQS						\
+	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),		\
+	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+#define SHARE_MEM_BASE		0x100000/* [1MB, 1MB+60K]*/
+#define SHARE_MEM_PAGE_NUM	15
+#define SHARE_MEM_SIZE		SIZE_K(SHARE_MEM_PAGE_NUM * 4)
+
+#define DDR_PARAM_BASE		0x02000000
+#define DDR_PARAM_SIZE		SIZE_K(4)
+
+#endif /* __PLAT_DEF_H__ */
diff --git a/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..2003749
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.macro	func_rockchip_clst_warmboot
+	/* Nothing to do for rk3288 */
+.endm
+
+.macro rockchip_clst_warmboot_data
+	/* Nothing to do for rk3288 */
+.endm
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.c b/plat/rockchip/rk3288/drivers/pmu/pmu.c
new file mode 100644
index 0000000..d6d7098
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3288_def.h>
+#include <secure.h>
+#include <soc.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+
+static uint32_t cpu_warm_boot_addr;
+
+static uint32_t store_pmu_pwrmode_con;
+static uint32_t store_sgrf_soc_con0;
+static uint32_t store_sgrf_cpu_con0;
+
+/* These enum are variants of low power mode */
+enum {
+	ROCKCHIP_ARM_OFF_LOGIC_NORMAL = 0,
+	ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1,
+};
+
+static inline int rk3288_pmu_bus_idle(uint32_t req, uint32_t idle)
+{
+	uint32_t mask = BIT(req);
+	uint32_t idle_mask = 0;
+	uint32_t idle_target = 0;
+	uint32_t val;
+	uint32_t wait_cnt = 0;
+
+	switch (req) {
+	case bus_ide_req_gpu:
+		idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu);
+		idle_target = (idle << pmu_idle_ack_gpu) |
+			      (idle << pmu_idle_gpu);
+		break;
+	case bus_ide_req_core:
+		idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core);
+		idle_target = (idle << pmu_idle_ack_core) |
+			      (idle << pmu_idle_core);
+		break;
+	case bus_ide_req_cpup:
+		idle_mask = BIT(pmu_idle_ack_cpup) | BIT(pmu_idle_cpup);
+		idle_target = (idle << pmu_idle_ack_cpup) |
+			      (idle << pmu_idle_cpup);
+		break;
+	case bus_ide_req_bus:
+		idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus);
+		idle_target = (idle << pmu_idle_ack_bus) |
+			      (idle << pmu_idle_bus);
+		break;
+	case bus_ide_req_dma:
+		idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma);
+		idle_target = (idle << pmu_idle_ack_dma) |
+			      (idle << pmu_idle_dma);
+		break;
+	case bus_ide_req_peri:
+		idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri);
+		idle_target = (idle << pmu_idle_ack_peri) |
+			      (idle << pmu_idle_peri);
+		break;
+	case bus_ide_req_video:
+		idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video);
+		idle_target = (idle << pmu_idle_ack_video) |
+			      (idle << pmu_idle_video);
+		break;
+	case bus_ide_req_hevc:
+		idle_mask = BIT(pmu_idle_ack_hevc) | BIT(pmu_idle_hevc);
+		idle_target = (idle << pmu_idle_ack_hevc) |
+			      (idle << pmu_idle_hevc);
+		break;
+	case bus_ide_req_vio:
+		idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio);
+		idle_target = (pmu_idle_ack_vio) |
+			      (idle << pmu_idle_vio);
+		break;
+	case bus_ide_req_alive:
+		idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive);
+		idle_target = (idle << pmu_idle_ack_alive) |
+			      (idle << pmu_idle_alive);
+		break;
+	default:
+		ERROR("%s: Unsupported the idle request\n", __func__);
+		break;
+	}
+
+	val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ);
+	if (idle)
+		val |= mask;
+	else
+		val &= ~mask;
+
+	mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val);
+
+	while ((mmio_read_32(PMU_BASE +
+	       PMU_BUS_IDE_ST) & idle_mask) != idle_target) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			WARN("%s:st=%x(%x)\n", __func__,
+			     mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST),
+			     idle_mask);
+	}
+
+	return 0;
+}
+
+static bool rk3288_sleep_disable_osc(void)
+{
+	static const uint32_t reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0,
+					       GRF_UOC2_CON0 };
+	uint32_t reg, i;
+
+	/*
+	 * if any usb phy is still on(GRF_SIDDQ==0), that means we need the
+	 * function of usb wakeup, so do not switch to 32khz, since the usb phy
+	 * clk does not connect to 32khz osc
+	 */
+	for (i = 0; i < ARRAY_SIZE(reg_offset); i++) {
+		reg = mmio_read_32(GRF_BASE + reg_offset[i]);
+		if (!(reg & GRF_SIDDQ))
+			return false;
+	}
+
+	return true;
+}
+
+static void pmu_set_sleep_mode(int level)
+{
+	uint32_t mode_set, mode_set1;
+	bool osc_disable = rk3288_sleep_disable_osc();
+
+	mode_set = BIT(pmu_mode_glb_int_dis) | BIT(pmu_mode_l2_flush_en) |
+		   BIT(pmu_mode_sref0_enter) | BIT(pmu_mode_sref1_enter) |
+		   BIT(pmu_mode_ddrc0_gt) | BIT(pmu_mode_ddrc1_gt) |
+		   BIT(pmu_mode_en) | BIT(pmu_mode_chip_pd) |
+		   BIT(pmu_mode_scu_pd);
+
+	mode_set1 = BIT(pmu_mode_clr_core) | BIT(pmu_mode_clr_cpup);
+
+	if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) {
+		/* arm off, logic deep sleep */
+		mode_set |= BIT(pmu_mode_bus_pd) | BIT(pmu_mode_pmu_use_lf) |
+			    BIT(pmu_mode_ddrio1_ret) |
+			    BIT(pmu_mode_ddrio0_ret) |
+			    BIT(pmu_mode_pmu_alive_use_lf) |
+			    BIT(pmu_mode_pll_pd);
+
+		if (osc_disable)
+			mode_set |= BIT(pmu_mode_osc_dis);
+
+		mode_set1 |= BIT(pmu_mode_clr_alive) | BIT(pmu_mode_clr_bus) |
+			     BIT(pmu_mode_clr_peri) | BIT(pmu_mode_clr_dma);
+
+		mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1,
+			      pmu_armint_wakeup_en);
+
+		/*
+		 * In deep suspend we use PMU_PMU_USE_LF to let the rk3288
+		 * switch its main clock supply to the alternative 32kHz
+		 * source. Therefore set 30ms on a 32kHz clock for pmic
+		 * stabilization. Similar 30ms on 24MHz for the other
+		 * mode below.
+		 */
+		mmio_write_32(PMU_BASE + PMU_STABL_CNT, 32 * 30);
+
+		/* only wait for stabilization, if we turned the osc off */
+		mmio_write_32(PMU_BASE + PMU_OSC_CNT,
+					 osc_disable ? 32 * 30 : 0);
+	} else {
+		/*
+		 * arm off, logic normal
+		 * if pmu_clk_core_src_gate_en is not set,
+		 * wakeup will be error
+		 */
+		mode_set |= BIT(pmu_mode_core_src_gt);
+
+		mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1,
+			      BIT(pmu_armint_wakeup_en) |
+			      BIT(pmu_gpioint_wakeup_en));
+
+		/* 30ms on a 24MHz clock for pmic stabilization */
+		mmio_write_32(PMU_BASE + PMU_STABL_CNT, 24000 * 30);
+
+		/* oscillator is still running, so no need to wait */
+		mmio_write_32(PMU_BASE + PMU_OSC_CNT, 0);
+	}
+
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, mode_set);
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON1, mode_set1);
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+	uint32_t cpu_pd;
+
+	cpu_pd = PD_CPU0 + cpu_id;
+
+	/* if the core has been on, power it off first */
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+		/* put core in reset - some sort of A12/A17 bug */
+		mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0),
+			      BIT(cpu_id) | (BIT(cpu_id) << 16));
+
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+	}
+
+	pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
+
+	/* pull core out of reset */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0), BIT(cpu_id) << 16);
+
+	return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id)
+{
+	uint32_t cpu_pd = PD_CPU0 + cpu_id;
+
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
+		return 0;
+
+	if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
+		return -EINVAL;
+
+	/* put core in reset - some sort of A12/A17 bug */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0),
+		      BIT(cpu_id) | (BIT(cpu_id) << 16));
+
+	pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+
+	return 0;
+}
+
+static void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, cpu;
+
+	boot_cpu = plat_my_core_pos();
+	boot_cpu = MPIDR_AFFLVL0_VAL(read_mpidr());
+
+	/* turn off noboot cpus */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		if (cpu == boot_cpu)
+			continue;
+
+		cpus_power_domain_off(cpu);
+	}
+}
+
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3288 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3288 SoCs */
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpu_id] = entrypoint;
+	dsb();
+
+	cpus_power_domain_on(cpu_id);
+
+	/*
+	 * We communicate with the bootrom to active the cpus other
+	 * than cpu0, after a blob of initialize code, they will
+	 * stay at wfe state, once they are actived, they will check
+	 * the mailbox:
+	 * sram_base_addr + 4: 0xdeadbeaf
+	 * sram_base_addr + 8: start address for pc
+	 * The cpu0 need to wait the other cpus other than cpu0 entering
+	 * the wfe state.The wait time is affected by many aspects.
+	 * (e.g: cpu frequency, bootrom frequency, sram frequency, ...)
+	 */
+	mdelay(1); /* ensure the cpus other than cpu0 to startup */
+
+	/* tell the bootrom mailbox where to start from */
+	mmio_write_32(SRAM_BASE + 8, cpu_warm_boot_addr);
+	mmio_write_32(SRAM_BASE + 4, 0xDEADBEAF);
+	dsb();
+	sev();
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, store_pmu_pwrmode_con);
+	mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0),
+		      store_sgrf_cpu_con0 | SGRF_DAPDEVICE_MSK);
+
+	/* disable fastboot mode */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0),
+		      store_sgrf_soc_con0 | SGRF_FAST_BOOT_DIS);
+
+	secure_watchdog_ungate();
+	clk_gate_con_restore();
+	clk_sel_con_restore();
+	clk_plls_resume();
+
+	secure_gic_init();
+	plat_rockchip_gic_init();
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	nonboot_cpus_off();
+
+	store_sgrf_cpu_con0 = mmio_read_32(SGRF_BASE + SGRF_CPU_CON(0));
+	store_sgrf_soc_con0 = mmio_read_32(SGRF_BASE + SGRF_SOC_CON(0));
+	store_pmu_pwrmode_con = mmio_read_32(PMU_BASE + PMU_PWRMODE_CON);
+
+	/* save clk-gates and ungate all for suspend */
+	clk_gate_con_save();
+	clk_gate_con_disable();
+	clk_sel_con_save();
+
+	pmu_set_sleep_mode(ROCKCHIP_ARM_OFF_LOGIC_NORMAL);
+
+	clk_plls_suspend();
+	secure_watchdog_gate();
+
+	/*
+	 * The dapswjdp can not auto reset before resume, that cause it may
+	 * access some illegal address during resume. Let's disable it before
+	 * suspend, and the MASKROM will enable it back.
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0), SGRF_DAPDEVICE_MSK);
+
+	/*
+	 * SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_FAST_BOOT_ENA);
+
+	/* boot-address of resuming system is from this register value */
+	mmio_write_32(SGRF_BASE + SGRF_FAST_BOOT_ADDR,
+		      (uint32_t)&pmu_cpuson_entrypoint);
+
+	/* flush all caches - otherwise we might loose the resume address */
+	dcsw_op_all(DC_OP_CISW);
+
+	return 0;
+}
+
+void rockchip_plat_mmu_svc_mon(void)
+{
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	uint32_t cpu;
+
+	cpu_warm_boot_addr = (uint32_t)platform_cpu_warmboot;
+
+	/* on boot all power-domains are on */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = pmu_pd_on;
+
+	nonboot_cpus_off();
+}
diff --git a/plat/rockchip/rk3288/drivers/pmu/pmu.h b/plat/rockchip/rk3288/drivers/pmu/pmu.h
new file mode 100644
index 0000000..06d5528
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/pmu/pmu.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+/* Allocate sp reginon in pmusram */
+#define PSRAM_SP_SIZE		0x80
+#define PSRAM_SP_BOTTOM		(PSRAM_SP_TOP - PSRAM_SP_SIZE)
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WAKEUP_CFG0		0x0
+#define PMU_WAKEUP_CFG1		0x4
+#define PMU_PWRDN_CON		0x8
+#define PMU_PWRDN_ST		0xc
+
+#define PMU_PWRMODE_CON		0x18
+#define PMU_BUS_IDE_REQ		0x10
+#define PMU_BUS_IDE_ST		0x14
+
+#define PMU_OSC_CNT		0x20
+#define PMU_PLL_CNT		0x24
+#define PMU_STABL_CNT		0x28
+#define PMU_DDRIO0_PWR_CNT	0x2c
+#define PMU_DDRIO1_PWR_CNT	0x30
+#define PMU_WKUPRST_CNT		0x44
+#define PMU_SFT_CON		0x48
+#define PMU_PWRMODE_CON1	0x90
+
+enum pmu_pdid {
+	PD_CPU0 = 0,
+	PD_CPU1,
+	PD_CPU2,
+	PD_CPU3,
+	PD_BUS = 5,
+	PD_PERI,
+	PD_VIO,
+	PD_VIDEO,
+	PD_GPU,
+	PD_SCU = 11,
+	PD_HEVC = 14,
+	PD_END
+};
+
+enum pmu_bus_ide {
+	bus_ide_req_bus = 0,
+	bus_ide_req_peri,
+	bus_ide_req_gpu,
+	bus_ide_req_video,
+	bus_ide_req_vio,
+	bus_ide_req_core,
+	bus_ide_req_alive,
+	bus_ide_req_dma,
+	bus_ide_req_cpup,
+	bus_ide_req_hevc,
+	bus_ide_req_end
+};
+
+enum pmu_pwrmode {
+	pmu_mode_en = 0,
+	pmu_mode_core_src_gt,
+	pmu_mode_glb_int_dis,
+	pmu_mode_l2_flush_en,
+	pmu_mode_bus_pd,
+	pmu_mode_cpu0_pd,
+	pmu_mode_scu_pd,
+	pmu_mode_pll_pd = 7,
+	pmu_mode_chip_pd,
+	pmu_mode_pwr_off_comb,
+	pmu_mode_pmu_alive_use_lf,
+	pmu_mode_pmu_use_lf,
+	pmu_mode_osc_dis = 12,
+	pmu_mode_input_clamp,
+	pmu_mode_wkup_rst,
+	pmu_mode_sref0_enter,
+	pmu_mode_sref1_enter,
+	pmu_mode_ddrio0_ret,
+	pmu_mode_ddrio1_ret,
+	pmu_mode_ddrc0_gt,
+	pmu_mode_ddrc1_gt,
+	pmu_mode_ddrio0_ret_deq,
+	pmu_mode_ddrio1_ret_deq,
+};
+
+enum pmu_pwrmode1 {
+	pmu_mode_clr_bus = 0,
+	pmu_mode_clr_core,
+	pmu_mode_clr_cpup,
+	pmu_mode_clr_alive,
+	pmu_mode_clr_dma,
+	pmu_mode_clr_peri,
+	pmu_mode_clr_gpu,
+	pmu_mode_clr_video,
+	pmu_mode_clr_hevc,
+	pmu_mode_clr_vio
+};
+
+enum pmu_sft_con {
+	pmu_sft_ddrio0_ret_cfg = 6,
+	pmu_sft_ddrio1_ret_cfg = 9,
+	pmu_sft_l2flsh = 15,
+};
+
+enum pmu_wakeup_cfg1 {
+	pmu_armint_wakeup_en = 0,
+	pmu_gpio_wakeup_negedge,
+	pmu_sdmmc0_wakeup_en,
+	pmu_gpioint_wakeup_en,
+};
+
+enum pmu_bus_idle_st {
+	pmu_idle_bus = 0,
+	pmu_idle_peri,
+	pmu_idle_gpu,
+	pmu_idle_video,
+	pmu_idle_vio,
+	pmu_idle_core,
+	pmu_idle_alive,
+	pmu_idle_dma,
+	pmu_idle_cpup,
+	pmu_idle_hevc,
+	pmu_idle_ack_bus = 16,
+	pmu_idle_ack_peri,
+	pmu_idle_ack_gpu,
+	pmu_idle_ack_video,
+	pmu_idle_ack_vio,
+	pmu_idle_ack_core,
+	pmu_idle_ack_alive,
+	pmu_idle_ack_dma,
+	pmu_idle_ack_cpup,
+	pmu_idle_ack_hevc,
+};
+
+#define CHECK_CPU_WFIE_BASE		(0)
+
+#define clstl_cpu_wfe		-1
+#define clstb_cpu_wfe		-1
+#define CKECK_WFEI_MSK		0
+
+
+#define PD_CTR_LOOP		500
+#define CHK_CPU_LOOP		500
+
+#define MAX_WAIT_CONUT 1000
+
+#endif /* PMU_H */
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.c b/plat/rockchip/rk3288/drivers/secure/secure.c
new file mode 100644
index 0000000..68994e4
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <plat_private.h>
+#include <secure.h>
+#include <soc.h>
+
+static void sgrf_ddr_rgn_global_bypass(uint32_t bypass)
+{
+	if (bypass)
+		/* set bypass (non-secure regions) for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21),
+			      SGRF_DDR_RGN_BYPS);
+	else
+		/* cancel bypass for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21),
+			      SGRF_DDR_RGN_NO_BYPS);
+}
+
+/**
+ * There are 8 + 1 regions for DDR secure control:
+ * DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB
+ * DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7
+ *
+ * SGRF_SOC_CON6 - start address of RGN_0 + control
+ * SGRF_SOC_CON7 - end address of RGN_0
+ * ...
+ * SGRF_SOC_CON20 - start address of the RGN_7 + control
+ * SGRF_SOC_CON21 - end address of the RGN_7 + RGN_X control
+ *
+ * @rgn - the DDR regions 0 ~ 7 which are can be configured.
+ * The @st and @ed indicate the start and end addresses for which to set
+ * the security, and the unit is byte. When the st_mb == 0, ed_mb == 0, the
+ * address range 0x0 ~ 0xfffff is secure.
+ *
+ * For example, if we would like to set the range [0, 32MB) is security via
+ * DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31.
+ */
+static void sgrf_ddr_rgn_config(uint32_t rgn, uintptr_t st, uintptr_t ed)
+{
+	uintptr_t st_mb, ed_mb;
+
+	assert(rgn <= 7);
+	assert(st < ed);
+
+	/* check aligned 1MB */
+	assert(st % SIZE_M(1) == 0);
+	assert(ed % SIZE_M(1) == 0);
+
+	st_mb = st / SIZE_M(1);
+	ed_mb = ed / SIZE_M(1);
+
+	/* set ddr region addr start */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
+		      BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_ADDR_WMSK, 0));
+
+	/* set ddr region addr end */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2) + 1),
+		      BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_ADDR_WMSK, 0));
+
+	/* select region security */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
+		      SGRF_DDR_RGN_SECURE_SEL);
+
+	/* enable region security */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)),
+		      SGRF_DDR_RGN_SECURE_EN);
+}
+
+void secure_watchdog_gate(void)
+{
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_GATE);
+}
+
+void secure_watchdog_ungate(void)
+{
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_UNGATE);
+}
+
+__pmusramfunc void sram_secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0);
+
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
+}
+
+void secure_gic_init(void)
+{
+	/* (re-)enable non-secure access to the gic*/
+	mmio_write_32(CORE_AXI_BUS_BASE + CORE_AXI_SECURITY0,
+		      AXI_SECURITY0_GIC);
+}
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0);
+
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
+}
+
+void secure_sgrf_init(void)
+{
+	/*
+	 * We use the first sram part to talk to the bootrom,
+	 * so make it secure.
+	 */
+	mmio_write_32(TZPC_BASE + TZPC_R0SIZE, TZPC_SRAM_SECURE_4K(1));
+
+	secure_gic_init();
+
+	/* set all master ip to non-secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), SGRF_SOC_CON2_MST_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), SGRF_SOC_CON3_MST_NS);
+
+	/* setting all configurable ip into non-secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4),
+		      SGRF_SOC_CON4_SECURE_WMSK /*TODO:|SGRF_STIMER_SECURE*/);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SOC_CON5_SECURE_WMSK);
+
+	/* secure dma to non-secure */
+	mmio_write_32(TZPC_BASE + TZPC_DECPROT1SET, 0xff);
+	mmio_write_32(TZPC_BASE + TZPC_DECPROT2SET, 0xff);
+	mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(1), 0x3800);
+	dsb();
+
+	/* rst dma1 */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1),
+		      RST_DMA1_MSK | (RST_DMA1_MSK << 16));
+	/* rst dma2 */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4),
+		      RST_DMA2_MSK | (RST_DMA2_MSK << 16));
+
+	dsb();
+
+	/* release dma1 rst*/
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), (RST_DMA1_MSK << 16));
+	/* release dma2 rst*/
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), (RST_DMA2_MSK << 16));
+}
+
+void secure_sgrf_ddr_rgn_init(void)
+{
+	sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE);
+	sgrf_ddr_rgn_global_bypass(0);
+}
diff --git a/plat/rockchip/rk3288/drivers/secure/secure.h b/plat/rockchip/rk3288/drivers/secure/secure.h
new file mode 100644
index 0000000..6c0b2b7
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/secure/secure.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+/******************************************************************************
+ * TZPC TrustZone controller
+ ******************************************************************************/
+
+#define TZPC_R0SIZE			0x0
+#define TZPC_SRAM_SECURE_4K(n)		((n) > 0x200 ? 0x200 : (n))
+#define TZPC_DECPROT1STAT		0x80c
+#define TZPC_DECPROT1SET		0x810
+#define TZPC_DECPROT1CLR		0x814
+#define TZPC_DECPROT2STAT		0x818
+#define TZPC_DECPROT2SET		0x818
+#define TZPC_DECPROT2CLR		0x820
+
+/**************************************************
+ * sgrf reg, offset
+ **************************************************/
+/*
+ * soc_con0-5 start at 0x0, soc_con6-... start art 0x50
+ * adjusted for the 5 lower registers
+ */
+#define SGRF_SOC_CON(n)			((((n) < 6) ? 0x0 : 0x38) + (n) * 4)
+#define SGRF_BUSDMAC_CON(n)		(0x20 + (n) * 4)
+#define SGRF_CPU_CON(n)			(0x40 + (n) * 4)
+#define SGRF_SOC_STATUS(n)		(0x100 + (n) * 4)
+#define SGRF_FAST_BOOT_ADDR		0x120
+
+/* SGRF_SOC_CON0 */
+#define SGRF_FAST_BOOT_ENA		BIT_WITH_WMSK(8)
+#define SGRF_FAST_BOOT_DIS		WMSK_BIT(8)
+#define SGRF_PCLK_WDT_GATE		BIT_WITH_WMSK(6)
+#define SGRF_PCLK_WDT_UNGATE		WMSK_BIT(6)
+#define SGRF_PCLK_STIMER_GATE		BIT_WITH_WMSK(4)
+
+#define SGRF_SOC_CON2_MST_NS		0xffe0ffe0
+#define SGRF_SOC_CON3_MST_NS		0x003f003f
+
+/* SGRF_SOC_CON4 */
+#define SGRF_SOC_CON4_SECURE_WMSK	0xffff0000
+#define SGRF_DDRC1_SECURE		BIT_WITH_WMSK(12)
+#define SGRF_DDRC0_SECURE		BIT_WITH_WMSK(11)
+#define SGRF_PMUSRAM_SECURE		BIT_WITH_WMSK(8)
+#define SGRF_WDT_SECURE			BIT_WITH_WMSK(7)
+#define SGRF_STIMER_SECURE		BIT_WITH_WMSK(6)
+
+/* SGRF_SOC_CON5 */
+#define SGRF_SLV_SEC_BYPS		BIT_WITH_WMSK(15)
+#define SGRF_SLV_SEC_NO_BYPS		WMSK_BIT(15)
+#define SGRF_SOC_CON5_SECURE_WMSK	0x00ff0000
+
+/* ddr regions in SGRF_SOC_CON6 and following */
+#define SGRF_DDR_RGN_SECURE_SEL		BIT_WITH_WMSK(15)
+#define SGRF_DDR_RGN_SECURE_EN		BIT_WITH_WMSK(14)
+#define SGRF_DDR_RGN_ADDR_WMSK		0x0fff
+
+/* SGRF_SOC_CON21 */
+/* All security of the DDR RGNs are bypassed */
+#define SGRF_DDR_RGN_BYPS		BIT_WITH_WMSK(15)
+#define SGRF_DDR_RGN_NO_BYPS		WMSK_BIT(15)
+
+/* SGRF_CPU_CON0 */
+#define SGRF_DAPDEVICE_ENA		BIT_WITH_WMSK(0)
+#define SGRF_DAPDEVICE_MSK		WMSK_BIT(0)
+
+/*****************************************************************************
+ * core-axi
+ *****************************************************************************/
+#define CORE_AXI_SECURITY0		0x08
+#define AXI_SECURITY0_GIC		BIT(0)
+
+/*****************************************************************************
+ * secure timer
+ *****************************************************************************/
+#define TIMER_LOAD_COUNT0		0x00
+#define TIMER_LOAD_COUNT1		0x04
+#define TIMER_CURRENT_VALUE0		0x08
+#define TIMER_CURRENT_VALUE1		0x0C
+#define TIMER_CONTROL_REG		0x10
+#define TIMER_INTSTATUS			0x18
+
+#define TIMER_EN			0x1
+
+#define STIMER1_BASE			(STIME_BASE + 0x20)
+
+/* export secure operating APIs */
+void secure_watchdog_gate(void);
+void secure_watchdog_ungate(void);
+void secure_gic_init(void);
+void secure_timer_init(void);
+void secure_sgrf_init(void);
+void secure_sgrf_ddr_rgn_init(void);
+__pmusramfunc void sram_secure_timer_init(void);
+
+#endif /* SECURE_H */
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.c b/plat/rockchip/rk3288/drivers/soc/soc.c
new file mode 100644
index 0000000..36f410b
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <rk3288_def.h>
+#include <soc.h>
+#include <secure.h>
+
+/* sleep data for pll suspend */
+static struct deepsleep_data_s slp_data;
+
+/* Table of regions to map using the MMU. */
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(STIME_BASE, STIME_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(TZPC_BASE, TZPC_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SRAM_BASE, SRAM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMU_BASE, PMU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART0_BASE, UART0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART1_BASE, UART1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART2_BASE, UART2_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART3_BASE, UART3_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART4_BASE, UART4_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CRU_BASE, CRU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GRF_BASE, GRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PCTL0_BASE, DDR_PCTL0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PHY0_BASE, DDR_PHY0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PCTL1_BASE, DDR_PCTL1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PHY1_BASE, DDR_PHY1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CORE_AXI_BUS_BASE, CORE_AXI_BUS_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+void plat_rockchip_soc_init(void)
+{
+	secure_timer_init();
+	secure_sgrf_init();
+	/*
+	 * We cannot enable ddr security at this point, as the kernel
+	 * seems to have an issue with it even living in the same 128MB
+	 * memory block. Only when moving the kernel to the second
+	 * 128MB block does it not conflict, but then we'd loose this
+	 * memory area for use. Late maybe enable
+	 * secure_sgrf_ddr_rgn_init();
+	 */
+}
+
+void regs_update_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift)
+{
+	uint32_t tmp, orig;
+
+	orig = mmio_read_32(addr);
+
+	tmp = orig & ~(mask << shift);
+	tmp |= (val & mask) << shift;
+
+	if (tmp != orig)
+		mmio_write_32(addr, tmp);
+	dsb();
+}
+
+static void pll_save(uint32_t pll_id)
+{
+	uint32_t *pll = slp_data.pll_con[pll_id];
+
+	pll[0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0));
+	pll[1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1));
+	pll[2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2));
+	pll[3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3));
+}
+
+void clk_plls_suspend(void)
+{
+	pll_save(NPLL_ID);
+	pll_save(CPLL_ID);
+	pll_save(GPLL_ID);
+	pll_save(APLL_ID);
+	slp_data.pll_mode = mmio_read_32(CRU_BASE + PLL_MODE_CON);
+
+	/*
+	 * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+	 * avoid crashes on resume. The Mask ROM on the system will
+	 * put APLL, CPLL, and GPLL into slow mode at resume time
+	 * anyway (which is why we restore them), but we might not
+	 * even make it to the Mask ROM if this isn't done at suspend
+	 * time.
+	 *
+	 * NOTE: only APLL truly matters here, but we'll do them all.
+	 */
+	mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
+}
+
+void clk_plls_resume(void)
+{
+	/* restore pll-modes */
+	mmio_write_32(CRU_BASE + PLL_MODE_CON,
+		      slp_data.pll_mode | REG_SOC_WMSK);
+}
+
+void clk_gate_con_save(void)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		slp_data.cru_gate_con[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
+}
+
+void clk_gate_con_disable(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), REG_SOC_WMSK);
+}
+
+void clk_gate_con_restore(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
+			      REG_SOC_WMSK | slp_data.cru_gate_con[i]);
+}
+
+void clk_sel_con_save(void)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < CRU_CLKSELS_CON_CNT; i++)
+		slp_data.cru_sel_con[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(i));
+}
+
+void clk_sel_con_restore(void)
+{
+	uint32_t i, val;
+
+	for (i = 0; i < CRU_CLKSELS_CON_CNT; i++) {
+		/* fractional dividers don't have write-masks */
+		if ((i >= 7 && i <= 9) ||
+		    (i >= 17 && i <= 20) ||
+		    (i == 23) || (i == 41))
+			val = slp_data.cru_sel_con[i];
+		else
+			val = slp_data.cru_sel_con[i] | REG_SOC_WMSK;
+
+		mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(i), val);
+	}
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	uint32_t temp_val;
+
+	/*
+	 * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+	 * avoid crashes on resume. The Mask ROM on the system will
+	 * put APLL, CPLL, and GPLL into slow mode at resume time
+	 * anyway (which is why we restore them), but we might not
+	 * even make it to the Mask ROM if this isn't done at suspend
+	 * time.
+	 *
+	 * NOTE: only APLL truly matters here, but we'll do them all.
+	 */
+	mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000);
+
+	temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON);
+	temp_val &= ~PMU_RST_MASK;
+	temp_val |= PMU_RST_BY_SECOND_SFT;
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val);
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8);
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to excute valid codes.
+	 */
+	while (1)
+		;
+}
diff --git a/plat/rockchip/rk3288/drivers/soc/soc.h b/plat/rockchip/rk3288/drivers/soc/soc.h
new file mode 100644
index 0000000..b96c4dc
--- /dev/null
+++ b/plat/rockchip/rk3288/drivers/soc/soc.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+enum plls_id {
+	APLL_ID = 0,
+	DPLL_ID,
+	CPLL_ID,
+	GPLL_ID,
+	NPLL_ID,
+	END_PLL_ID,
+};
+
+
+#define CYCL_24M_CNT_US(us)	(24 * (us))
+#define CYCL_24M_CNT_MS(ms)	((ms) * CYCL_24M_CNT_US(1000))
+
+/*****************************************************************************
+ * grf regs
+ *****************************************************************************/
+#define GRF_UOC0_CON0		0x320
+#define GRF_UOC1_CON0		0x334
+#define GRF_UOC2_CON0		0x348
+#define GRF_SIDDQ		BIT(13)
+
+/*****************************************************************************
+ * cru reg, offset
+ *****************************************************************************/
+#define CRU_SOFTRST_CON		0x1b8
+#define CRU_SOFTRSTS_CON(n)	(CRU_SOFTRST_CON + ((n) * 4))
+#define CRU_SOFTRSTS_CON_CNT	11
+
+#define RST_DMA1_MSK		0x4
+#define RST_DMA2_MSK		0x1
+
+#define CRU_CLKSEL_CON		0x60
+#define CRU_CLKSELS_CON(i)	(CRU_CLKSEL_CON + ((i) * 4))
+#define CRU_CLKSELS_CON_CNT	42
+
+#define CRU_CLKGATE_CON		0x160
+#define CRU_CLKGATES_CON(i)	(CRU_CLKGATE_CON + ((i) * 4))
+#define CRU_CLKGATES_CON_CNT	18
+
+#define CRU_GLB_SRST_FST	0x1b0
+#define CRU_GLB_SRST_SND	0x1b4
+#define CRU_GLB_RST_CON		0x1f0
+
+#define CRU_CONS_GATEID(i)	(16 * (i))
+#define GATE_ID(reg, bit)	(((reg) * 16) + (bit))
+
+#define PMU_RST_MASK		0x3
+#define PMU_RST_BY_FIRST_SFT	(0 << 2)
+#define PMU_RST_BY_SECOND_SFT	(1 << 2)
+#define PMU_RST_NOT_BY_SFT	(2 << 2)
+
+/***************************************************************************
+ * pll
+ ***************************************************************************/
+#define PLL_CON_COUNT		4
+#define PLL_CONS(id, i)		((id) * 0x10 + ((i) * 4))
+#define PLL_PWR_DN_MSK		BIT(1)
+#define PLL_PWR_DN		REG_WMSK_BITS(1, 1, 0x1)
+#define PLL_PWR_ON		REG_WMSK_BITS(0, 1, 0x1)
+#define PLL_RESET		REG_WMSK_BITS(1, 5, 0x1)
+#define PLL_RESET_RESUME	REG_WMSK_BITS(0, 5, 0x1)
+#define PLL_BYPASS_MSK		BIT(0)
+#define PLL_BYPASS_W_MSK	(PLL_BYPASS_MSK << 16)
+#define PLL_BYPASS		REG_WMSK_BITS(1, 0, 0x1)
+#define PLL_NO_BYPASS		REG_WMSK_BITS(0, 0, 0x1)
+
+#define PLL_MODE_CON		0x50
+
+struct deepsleep_data_s {
+	uint32_t pll_con[END_PLL_ID][PLL_CON_COUNT];
+	uint32_t pll_mode;
+	uint32_t cru_sel_con[CRU_CLKSELS_CON_CNT];
+	uint32_t cru_gate_con[CRU_CLKGATES_CON_CNT];
+};
+
+#define REG_W_MSK(bits_shift, msk) \
+		((msk) << ((bits_shift) + 16))
+#define REG_VAL_CLRBITS(val, bits_shift, msk) \
+		((val) & (~((msk) << bits_shift)))
+#define REG_SET_BITS(bits, bits_shift, msk) \
+		(((bits) & (msk)) << (bits_shift))
+#define REG_WMSK_BITS(bits, bits_shift, msk) \
+		(REG_W_MSK(bits_shift, msk) | \
+		REG_SET_BITS(bits, bits_shift, msk))
+#define REG_SOC_WMSK		0xffff0000
+
+#define regs_update_bit_set(addr, shift) \
+		regs_update_bits((addr), 0x1, 0x1, (shift))
+#define regs_update_bit_clr(addr, shift) \
+		regs_update_bits((addr), 0x0, 0x1, (shift))
+
+void regs_update_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift);
+void clk_plls_suspend(void);
+void clk_plls_resume(void);
+void clk_gate_con_save(void);
+void clk_gate_con_disable(void);
+void clk_gate_con_restore(void);
+void clk_sel_con_save(void);
+void clk_sel_con_restore(void);
+#endif /* SOC_H */
diff --git a/plat/rockchip/rk3288/include/plat_sip_calls.h b/plat/rockchip/rk3288/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3288/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/rockchip/rk3288/include/plat_sp_min.ld.S b/plat/rockchip/rk3288/include/plat_sp_min.ld.S
new file mode 100644
index 0000000..2878437
--- /dev/null
+++ b/plat/rockchip/rk3288/include/plat_sp_min.ld.S
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_LD_S
+#define ROCKCHIP_PLAT_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+MEMORY {
+    SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = SRAM_BASE;
+	ASSERT(. == ALIGN(PAGE_SIZE),
+		"SRAM_BASE address is not aligned on a page boundary.")
+
+	.text_sram : ALIGN(PAGE_SIZE) {
+		__bl32_sram_text_start = .;
+		*(.sram.text)
+		*(.sram.rodata)
+		__bl32_sram_text_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__bl32_sram_text_end = .;
+	} >SRAM
+	ASSERT((__bl32_sram_text_real_end - __bl32_sram_text_start) <=
+		SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit")
+
+	.data_sram : ALIGN(PAGE_SIZE) {
+		__bl32_sram_data_start = .;
+		*(.sram.data)
+		__bl32_sram_data_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__bl32_sram_data_end = .;
+	} >SRAM
+	ASSERT((__bl32_sram_data_real_end - __bl32_sram_data_start) <=
+		SRAM_DATA_LIMIT, ".data_sram has exceeded its limit")
+
+	.stack_sram : ALIGN(PAGE_SIZE) {
+		__bl32_sram_stack_start = .;
+		. += PAGE_SIZE;
+		__bl32_sram_stack_end = .;
+	} >SRAM
+
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+
+		__bl32_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl32_pmusram_text_end = .;
+
+		__bl32_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl32_pmusram_data_end = .;
+	} >PMUSRAM
+}
+
+#endif /* ROCKCHIP_PLAT_LD_S */
diff --git a/plat/rockchip/rk3288/include/platform_def.h b/plat/rockchip/rk3288/include/platform_def.h
new file mode 100644
index 0000000..e24aeff
--- /dev/null
+++ b/plat/rockchip/rk3288/include/platform_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <bl32_param.h>
+#include <rk3288_def.h>
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf32-littlearm"
+#define PLATFORM_LINKER_ARCH		arm
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x800
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	6
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		U(1)
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		18
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE		RK3288_GICD_BASE
+#define PLAT_RK_GICC_BASE		RK3288_GICC_BASE
+
+#define PLAT_RK_UART_BASE		UART2_BASE
+#define PLAT_RK_UART_CLOCK		RK3288_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE		RK3288_BAUDRATE
+
+/* ClusterId is always 0x5 on rk3288, filter it */
+#define PLAT_RK_MPIDR_CLUSTER_MASK	0
+#define PLAT_RK_PRIMARY_CPU		0x0
+
+#define PSRAM_DO_DDR_RESUME		0
+#define PSRAM_CHECK_WAKEUP_CPU		0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rockchip/rk3288/include/shared/bl32_param.h b/plat/rockchip/rk3288/include/shared/bl32_param.h
new file mode 100644
index 0000000..743dad4
--- /dev/null
+++ b/plat/rockchip/rk3288/include/shared/bl32_param.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL32_PARAM_H
+#define BL32_PARAM_H
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF txet, ro, rw, Size: 2MB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x200000)
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL32 at the top of the Trusted RAM
+ */
+#define BL32_BASE			(TZRAM_BASE + 0x100000)
+#define BL32_LIMIT			(TZRAM_BASE + TZRAM_SIZE)
+
+#endif /* BL32_PARAM_H */
diff --git a/plat/rockchip/rk3288/plat_sip_calls.c b/plat/rockchip/rk3288/plat_sip_calls.c
new file mode 100644
index 0000000..5918d58
--- /dev/null
+++ b/plat/rockchip/rk3288/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+				   u_register_t x1,
+				   u_register_t x2,
+				   u_register_t x3,
+				   u_register_t x4,
+				   void *cookie,
+				   void *handle,
+				   u_register_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/rockchip/rk3288/platform.mk b/plat/rockchip/rk3288/platform.mk
new file mode 100644
index 0000000..980fb6b
--- /dev/null
+++ b/plat/rockchip/rk3288/platform.mk
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ARM_CORTEX_A12		:=	yes
+ARM_ARCH_MAJOR		:=	7
+
+RK_PLAT			:=	plat/rockchip
+RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON		:=	${RK_PLAT}/common
+
+DISABLE_BIN_GENERATION	:=	1
+
+PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/				\
+				-I${RK_PLAT_COMMON}/include/			\
+				-I${RK_PLAT_COMMON}/aarch32/			\
+				-I${RK_PLAT_COMMON}/drivers/pmu/		\
+				-I${RK_PLAT_SOC}/				\
+				-I${RK_PLAT_SOC}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/drivers/secure/		\
+				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/include/			\
+				-I${RK_PLAT_SOC}/include/shared/		\
+
+RK_GIC_SOURCES         :=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				${RK_PLAT}/common/rockchip_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	lib/bl_aux_params/bl_aux_params.c		\
+				plat/common/aarch32/crash_console_helpers.S	\
+				plat/common/plat_psci_common.c
+
+PLAT_BL_COMMON_SOURCES	+=	lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch32/xlat_tables.c
+
+BL32_SOURCES		+=	${RK_GIC_SOURCES}				\
+				drivers/arm/cci/cci.c				\
+				drivers/ti/uart/aarch32/16550_console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				lib/cpus/aarch32/cortex_a12.S			\
+				${RK_PLAT_COMMON}/aarch32/plat_helpers.S	\
+				${RK_PLAT_COMMON}/params_setup.c		\
+				${RK_PLAT_COMMON}/aarch32/pmu_sram_cpus_on.S	\
+				${RK_PLAT_COMMON}/plat_pm.c			\
+				${RK_PLAT_COMMON}/plat_topology.c		\
+				${RK_PLAT_COMMON}/aarch32/platform_common.c	\
+				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+				${RK_PLAT_SOC}/plat_sip_calls.c			\
+				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+				${RK_PLAT_SOC}/drivers/secure/secure.c		\
+				${RK_PLAT_SOC}/drivers/soc/soc.c		\
+
+MULTI_CONSOLE_API	:=	1
+
+include lib/coreboot/coreboot.mk
+include lib/libfdt/libfdt.mk
+
+$(eval $(call add_define,PLAT_SP_MIN_EXTRA_LD_SCRIPT))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
+
+WORKAROUND_CVE_2017_5715	:=	0
diff --git a/plat/rockchip/rk3288/rk3288_def.h b/plat/rockchip/rk3288/rk3288_def.h
new file mode 100644
index 0000000..7bff865
--- /dev/null
+++ b/plat/rockchip/rk3288/rk3288_def.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RK3288_DEF_H
+#define RK3288_DEF_H
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define SIZE_K(n)		((n) * 1024)
+#define SIZE_M(n)		((n) * 1024 * 1024)
+
+#define SRAM_TEXT_LIMIT		(4 * 1024)
+#define SRAM_DATA_LIMIT		(4 * 1024)
+
+#define DDR_PCTL0_BASE		0xff610000
+#define DDR_PCTL0_SIZE		SIZE_K(64)
+
+#define DDR_PHY0_BASE		0xff620000
+#define DDR_PHY0_SIZE		SIZE_K(64)
+
+#define DDR_PCTL1_BASE		0xff630000
+#define DDR_PCTL1_SIZE		SIZE_K(64)
+
+#define DDR_PHY1_BASE		0xff640000
+#define DDR_PHY1_SIZE		SIZE_K(64)
+
+#define UART0_BASE		0xff180000
+#define UART0_SIZE		SIZE_K(64)
+
+#define UART1_BASE		0xff190000
+#define UART1_SIZE		SIZE_K(64)
+
+#define UART2_BASE		0xff690000
+#define UART2_SIZE		SIZE_K(64)
+
+#define UART3_BASE		0xff1b0000
+#define UART3_SIZE		SIZE_K(64)
+
+#define UART4_BASE		0xff1c0000
+#define UART4_SIZE		SIZE_K(64)
+
+/* 96k instead of 64k? */
+#define SRAM_BASE		0xff700000
+#define SRAM_SIZE		SIZE_K(64)
+
+#define PMUSRAM_BASE		0xff720000
+#define PMUSRAM_SIZE		SIZE_K(4)
+#define PMUSRAM_RSIZE		SIZE_K(4)
+
+#define PMU_BASE		0xff730000
+#define PMU_SIZE		SIZE_K(64)
+
+#define SGRF_BASE		0xff740000
+#define SGRF_SIZE		SIZE_K(64)
+
+#define CRU_BASE		0xff760000
+#define CRU_SIZE		SIZE_K(64)
+
+#define GRF_BASE		0xff770000
+#define GRF_SIZE		SIZE_K(64)
+
+/* timer 6+7 can be set as secure in SGRF */
+#define STIME_BASE		0xff810000
+#define STIME_SIZE		SIZE_K(64)
+
+#define SERVICE_BUS_BASE	0xffac0000
+#define SERVICE_BUS_SIZE	SIZE_K(64)
+
+#define TZPC_BASE		0xffb00000
+#define TZPC_SIZE		SIZE_K(64)
+
+#define GIC400_BASE		0xffc00000
+#define GIC400_SIZE		SIZE_K(64)
+
+#define CORE_AXI_BUS_BASE	0xffd00000
+#define CORE_AXI_BUS_SIZE	SIZE_M(1)
+
+#define COLD_BOOT_BASE		0xffff0000
+/**************************************************************************
+ * UART related constants
+ **************************************************************************/
+#define RK3288_BAUDRATE		115200
+#define RK3288_UART_CLOCK	24000000
+
+/******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	24000000
+
+/******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base rk_platform compatible GIC memory map */
+#define RK3288_GICD_BASE		(GIC400_BASE + 0x1000)
+#define RK3288_GICC_BASE		(GIC400_BASE + 0x2000)
+#define RK3288_GICR_BASE		0	/* no GICR in GIC-400 */
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define RK_IRQ_SEC_PHY_TIMER	29
+
+/* what are these, and are they present on rk3288? */
+#define RK_IRQ_SEC_SGI_0	8
+#define RK_IRQ_SEC_SGI_1	9
+#define RK_IRQ_SEC_SGI_2	10
+#define RK_IRQ_SEC_SGI_3	11
+#define RK_IRQ_SEC_SGI_4	12
+#define RK_IRQ_SEC_SGI_5	13
+#define RK_IRQ_SEC_SGI_6	14
+#define RK_IRQ_SEC_SGI_7	15
+
+/*
+ * Define a list of Group 0 interrupts.
+ */
+#define PLAT_RK_GICV2_G0_IRQS						\
+	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),		\
+	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+#endif /* RK3288_DEF_H */
diff --git a/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk b/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk
new file mode 100644
index 0000000..befdca3
--- /dev/null
+++ b/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES		+=	plat/common/aarch32/platform_mp_stack.S		\
+				plat/rockchip/common/sp_min_plat_setup.c
diff --git a/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..cd604d2
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.globl	clst_warmboot_data
+
+.macro	func_rockchip_clst_warmboot
+.endm
+
+.macro rockchip_clst_warmboot_data
+clst_warmboot_data:
+	.rept	PLATFORM_CLUSTER_COUNT
+	.word	0
+	.endr
+.endm
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.c b/plat/rockchip/rk3328/drivers/pmu/pmu.c
new file mode 100644
index 0000000..a17fef9
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3328_def.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+
+static struct rk3328_sleep_ddr_data ddr_data;
+static __sramdata struct rk3328_sleep_sram_data sram_data;
+
+static uint32_t cpu_warm_boot_addr;
+
+#pragma weak rk3328_pmic_suspend
+#pragma weak rk3328_pmic_resume
+
+static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
+{
+	uint32_t pd_reg, apm_reg;
+
+	pd_reg = mmio_read_32(PMU_BASE + PMU_PWRDN_CON) & BIT(cpu_id);
+	apm_reg = mmio_read_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id)) &
+			       BIT(core_pm_en);
+
+	if (pd_reg && !apm_reg)
+		return core_pwr_pd;
+	else if (!pd_reg && apm_reg)
+		return core_pwr_wfi;
+
+	ERROR("%s: 0x%x, 0x%x\n", __func__, pd_reg, apm_reg);
+	while (1)
+	;
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+	uint32_t cpu_pd, cfg_info;
+
+	cpu_pd = PD_CPU0 + cpu_id;
+	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
+
+	if (cfg_info == core_pwr_pd) {
+		/* disable apm cfg */
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      CORES_PM_DISABLE);
+
+		/* if the cores have be on, power off it firstly */
+		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+			mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+				      CORES_PM_DISABLE);
+			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+		}
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
+	} else {
+		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
+			return -EINVAL;
+		}
+
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      BIT(core_pm_sft_wakeup_en));
+	}
+
+	return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
+{
+	uint32_t cpu_pd, core_pm_value;
+
+	cpu_pd = PD_CPU0 + cpu_id;
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
+		return 0;
+
+	if (pd_cfg == core_pwr_pd) {
+		if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
+			return -EINVAL;
+		/* disable apm cfg */
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      CORES_PM_DISABLE);
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+	} else {
+		core_pm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
+		if (pd_cfg == core_pwr_wfi_int)
+			core_pm_value |= BIT(core_pm_int_wakeup_en);
+
+		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
+			      core_pm_value);
+	}
+
+	return 0;
+}
+
+static void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, cpu;
+
+	/* turn off noboot cpus */
+	boot_cpu = plat_my_core_pos();
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		if (cpu == boot_cpu)
+			continue;
+		cpus_power_domain_off(cpu, core_pwr_pd);
+	}
+}
+
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3328 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3328 SoCs */
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpu_id] = entrypoint;
+	dsb();
+
+	cpus_power_domain_on(cpu_id);
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi);
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
+	cpuson_entry_point[cpu_id] = (uintptr_t)plat_get_sec_entrypoint();
+	dsb();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE);
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE);
+
+	return 0;
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(CPLL_ID));
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(GPLL_ID));
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(NPLL_ID));
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(APLL_ID));
+	dsb();
+
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
+	dsb();
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to excute valid codes.
+	 */
+	while (1)
+		;
+}
+
+/*
+ * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328.
+ * If the PMIC is configed for responding the sleep pin to power off it,
+ * once the pin is output high,  it will get the pmic power off.
+ */
+void __dead2 rockchip_soc_system_off(void)
+{
+	uint32_t val;
+
+	/* gpio config */
+	val = mmio_read_32(GRF_BASE + GRF_GPIO2D_IOMUX);
+	val &= ~GPIO2_D2_GPIO_MODE;
+	mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX, val);
+
+	/* config output */
+	val = mmio_read_32(GPIO2_BASE + SWPORTA_DDR);
+	val |= GPIO2_D2;
+	mmio_write_32(GPIO2_BASE + SWPORTA_DDR, val);
+
+	/* config output high level */
+	val = mmio_read_32(GPIO2_BASE);
+	val |= GPIO2_D2;
+	mmio_write_32(GPIO2_BASE, val);
+	dsb();
+
+	while (1)
+		;
+}
+
+static uint32_t clk_ungt_msk[CRU_CLKGATE_NUMS] = {
+	0x187f, 0x0000, 0x010c, 0x0000, 0x0200,
+	0x0010, 0x0000, 0x0017, 0x001f, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0003, 0x0000,
+	0xf001, 0x27c0, 0x04D9, 0x03ff, 0x0000,
+	0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0003, 0x0008
+};
+
+static void clks_gating_suspend(uint32_t *ungt_msk)
+{
+	int i;
+
+	for (i = 0; i < CRU_CLKGATE_NUMS; i++) {
+		ddr_data.clk_ungt_save[i] =
+			mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
+			      ((~ungt_msk[i]) << 16) | 0xffff);
+	}
+}
+
+static void clks_gating_resume(void)
+{
+	int i;
+
+	for (i = 0; i < CRU_CLKGATE_NUMS; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
+			      ddr_data.clk_ungt_save[i] | 0xffff0000);
+}
+
+static inline void pm_pll_wait_lock(uint32_t pll_id)
+{
+	uint32_t delay = PLL_LOCKED_TIMEOUT;
+
+	while (delay > 0) {
+		if (mmio_read_32(CRU_BASE + PLL_CONS(pll_id, 1)) &
+		    PLL_IS_LOCKED)
+			break;
+		delay--;
+	}
+	if (delay == 0)
+		ERROR("lock-pll: %d\n", pll_id);
+}
+
+static inline void pll_pwr_dwn(uint32_t pll_id, uint32_t pd)
+{
+	mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
+		      BITS_WITH_WMASK(1U, 1U, 15));
+	if (pd)
+		mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
+			      BITS_WITH_WMASK(1, 1, 14));
+	else
+		mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
+			      BITS_WITH_WMASK(0, 1, 14));
+}
+
+static __sramfunc void dpll_suspend(void)
+{
+	int i;
+
+	/* slow mode */
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(DPLL_ID));
+
+	/* save pll con */
+	for (i = 0; i < CRU_PLL_CON_NUMS; i++)
+		sram_data.dpll_con_save[i] =
+				mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, i));
+	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
+		      BITS_WITH_WMASK(1U, 1U, 15));
+	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
+		      BITS_WITH_WMASK(1, 1, 14));
+}
+
+static __sramfunc void dpll_resume(void)
+{
+	uint32_t delay = PLL_LOCKED_TIMEOUT;
+
+	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
+		      BITS_WITH_WMASK(1U, 1U, 15));
+	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
+		      BITS_WITH_WMASK(0, 1, 14));
+	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
+		      sram_data.dpll_con_save[1] | 0xc0000000);
+
+	dsb();
+
+	while (delay > 0) {
+		if (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 1)) &
+				 PLL_IS_LOCKED)
+			break;
+		delay--;
+	}
+	if (delay == 0)
+		while (1)
+			;
+
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE,
+		      PLL_NORM_MODE(DPLL_ID));
+}
+
+static inline void pll_suspend(uint32_t pll_id)
+{
+	int i;
+
+	/* slow mode */
+	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(pll_id));
+
+	/* save pll con */
+	for (i = 0; i < CRU_PLL_CON_NUMS; i++)
+		ddr_data.cru_plls_con_save[pll_id][i] =
+				mmio_read_32(CRU_BASE + PLL_CONS(pll_id, i));
+
+	/* powerdown pll */
+	pll_pwr_dwn(pll_id, pmu_pd_off);
+}
+
+static inline void pll_resume(uint32_t pll_id)
+{
+	mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
+		      ddr_data.cru_plls_con_save[pll_id][1] | 0xc0000000);
+
+	pm_pll_wait_lock(pll_id);
+
+	if (PLL_IS_NORM_MODE(ddr_data.cru_mode_save, pll_id))
+		mmio_write_32(CRU_BASE + CRU_CRU_MODE,
+			      PLL_NORM_MODE(pll_id));
+}
+
+static void pm_plls_suspend(void)
+{
+	ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_CRU_MODE);
+	ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(0));
+	ddr_data.clk_sel1 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(1));
+	ddr_data.clk_sel18 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(18));
+	ddr_data.clk_sel20 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(20));
+	ddr_data.clk_sel24 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(24));
+	ddr_data.clk_sel38 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(38));
+	pll_suspend(NPLL_ID);
+	pll_suspend(CPLL_ID);
+	pll_suspend(GPLL_ID);
+	pll_suspend(APLL_ID);
+
+	/* core */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0),
+		      BITS_WITH_WMASK(0, 0x1f, 0));
+
+	/* pclk_dbg */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1),
+		      BITS_WITH_WMASK(0, 0xf, 0));
+
+	/* crypto */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20),
+		      BITS_WITH_WMASK(0, 0x1f, 0));
+
+	/* pwm0 */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24),
+		      BITS_WITH_WMASK(0, 0x7f, 8));
+
+	/* uart2 from 24M */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18),
+		      BITS_WITH_WMASK(2, 0x3, 8));
+
+	/* clk_rtc32k */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38),
+		      BITS_WITH_WMASK(767, 0x3fff, 0) |
+		      BITS_WITH_WMASK(2U, 0x3u, 14));
+}
+
+static void pm_plls_resume(void)
+{
+	/* clk_rtc32k */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38),
+		      ddr_data.clk_sel38 |
+		      BITS_WMSK(0x3fff, 0) |
+		      BITS_WMSK(0x3u, 14));
+
+	/* uart2 */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18),
+		      ddr_data.clk_sel18 | BITS_WMSK(0x3, 8));
+
+	/* pwm0 */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24),
+		      ddr_data.clk_sel24 | BITS_WMSK(0x7f, 8));
+
+	/* crypto */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20),
+		      ddr_data.clk_sel20 | BITS_WMSK(0x1f, 0));
+
+	/* pclk_dbg */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1),
+		      ddr_data.clk_sel1 | BITS_WMSK(0xf, 0));
+
+	/* core */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0),
+		      ddr_data.clk_sel0 | BITS_WMSK(0x1f, 0));
+
+	pll_pwr_dwn(APLL_ID, pmu_pd_on);
+	pll_pwr_dwn(GPLL_ID, pmu_pd_on);
+	pll_pwr_dwn(CPLL_ID, pmu_pd_on);
+	pll_pwr_dwn(NPLL_ID, pmu_pd_on);
+
+	pll_resume(APLL_ID);
+	pll_resume(GPLL_ID);
+	pll_resume(CPLL_ID);
+	pll_resume(NPLL_ID);
+}
+
+#define ARCH_TIMER_TICKS_PER_US (SYS_COUNTER_FREQ_IN_TICKS / 1000000)
+
+static __sramfunc void sram_udelay(uint32_t us)
+{
+	uint64_t pct_orig, pct_now;
+	uint64_t to_wait = ARCH_TIMER_TICKS_PER_US * us;
+
+	isb();
+	pct_orig = read_cntpct_el0();
+
+	do {
+		isb();
+		pct_now = read_cntpct_el0();
+	} while ((pct_now - pct_orig) <= to_wait);
+}
+
+/*
+ * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328.
+ * If the PMIC is configed for responding the sleep pin
+ * to get it into sleep mode,
+ * once the pin is output high,  it will get the pmic into sleep mode.
+ */
+__sramfunc void rk3328_pmic_suspend(void)
+{
+	sram_data.pmic_sleep_save = mmio_read_32(GRF_BASE + PMIC_SLEEP_REG);
+	sram_data.pmic_sleep_gpio_save[1] = mmio_read_32(GPIO2_BASE + 4);
+	sram_data.pmic_sleep_gpio_save[0] = mmio_read_32(GPIO2_BASE);
+	mmio_write_32(GRF_BASE + PMIC_SLEEP_REG, BITS_WITH_WMASK(0, 0x3, 4));
+	mmio_write_32(GPIO2_BASE + 4,
+		      sram_data.pmic_sleep_gpio_save[1] | BIT(26));
+	mmio_write_32(GPIO2_BASE,
+		      sram_data.pmic_sleep_gpio_save[0] | BIT(26));
+}
+
+__sramfunc void  rk3328_pmic_resume(void)
+{
+	mmio_write_32(GPIO2_BASE, sram_data.pmic_sleep_gpio_save[0]);
+	mmio_write_32(GPIO2_BASE + 4, sram_data.pmic_sleep_gpio_save[1]);
+	mmio_write_32(GRF_BASE + PMIC_SLEEP_REG,
+		      sram_data.pmic_sleep_save | BITS_WMSK(0xffffu, 0));
+	/* Resuming volt need a lot of time */
+	sram_udelay(100);
+}
+
+static __sramfunc void ddr_suspend(void)
+{
+	sram_data.pd_sr_idle_save = mmio_read_32(DDR_UPCTL_BASE +
+						 DDR_PCTL2_PWRCTL);
+	sram_data.pd_sr_idle_save &= SELFREF_EN;
+
+	mmio_clrbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL, SELFREF_EN);
+	sram_data.ddr_grf_con0 = mmio_read_32(DDR_GRF_BASE +
+					      DDRGRF_SOC_CON(0));
+	mmio_write_32(DDR_GRF_BASE, BIT_WITH_WMSK(14) | WMSK_BIT(15));
+
+	/*
+	 * Override csysreq from ddrc and
+	 * send valid csysreq signal to PMU,
+	 * csysreq is controlled by ddrc only
+	 */
+
+	/* in self-refresh */
+	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(0));
+	while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) &
+	       (0x03 << 12)) !=  (0x02 << 12))
+		;
+	/* ddr retention */
+	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(2));
+
+	/* ddr gating */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0),
+		      BITS_WITH_WMASK(0x7, 0x7, 4));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7),
+		      BITS_WITH_WMASK(1, 1, 4));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
+		      BITS_WITH_WMASK(0x1ff, 0x1ff, 1));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27),
+		      BITS_WITH_WMASK(0x3, 0x3, 0));
+
+	dpll_suspend();
+}
+
+__sramfunc  void dmc_restore(void)
+{
+	dpll_resume();
+
+	/* ddr gating */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0),
+		      BITS_WITH_WMASK(0, 0x7, 4));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7),
+		      BITS_WITH_WMASK(0, 1, 4));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
+		      BITS_WITH_WMASK(0, 0x1ff, 1));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27),
+		      BITS_WITH_WMASK(0, 0x3, 0));
+
+	/* ddr de_retention */
+	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(2));
+	/* exit self-refresh */
+	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(0));
+	while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) &
+		(0x03 << 12)) !=  (0x00 << 12))
+		;
+
+	mmio_write_32(DDR_GRF_BASE, sram_data.ddr_grf_con0 | 0xc0000000);
+	if (sram_data.pd_sr_idle_save)
+		mmio_setbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL,
+				SELFREF_EN);
+}
+
+static __sramfunc void sram_dbg_uart_suspend(void)
+{
+	sram_data.uart2_ier = mmio_read_32(UART2_BASE + UART_IER);
+	mmio_write_32(UART2_BASE + UART_IER, UART_INT_DISABLE);
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20002000);
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040004);
+}
+
+__sramfunc void sram_dbg_uart_resume(void)
+{
+	/* restore uart clk and reset fifo */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20000000);
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040000);
+	mmio_write_32(UART2_BASE + UART_FCR, UART_FIFO_RESET);
+	mmio_write_32(UART2_BASE + UART_IER, sram_data.uart2_ier);
+}
+
+static __sramfunc void sram_soc_enter_lp(void)
+{
+	uint32_t apm_value;
+
+	apm_value = BIT(core_pm_en) |
+		    BIT(core_pm_dis_int) |
+		    BIT(core_pm_int_wakeup_en);
+	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(PD_CPU0), apm_value);
+
+	dsb();
+	isb();
+err_loop:
+	wfi();
+	/*
+	 *Soc will enter low power mode and
+	 *do not return to here.
+	 */
+	goto err_loop;
+}
+
+__sramfunc void sram_suspend(void)
+{
+	/* disable mmu and icache */
+	disable_mmu_icache_el3();
+	tlbialle3();
+	dsbsy();
+	isb();
+
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+
+	/* ddr self-refresh and gating phy */
+	ddr_suspend();
+
+	rk3328_pmic_suspend();
+
+	sram_dbg_uart_suspend();
+
+	sram_soc_enter_lp();
+}
+
+void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
+{
+	sram_suspend();
+
+	/* should never reach here */
+	psci_power_down_wfi();
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	clks_gating_suspend(clk_ungt_msk);
+
+	pm_plls_suspend();
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	pm_plls_resume();
+
+	clks_gating_resume();
+
+	plat_rockchip_gic_cpuif_enable();
+
+	return 0;
+}
+
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for rk3328 SoCs */
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	uint32_t cpu;
+
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = 0;
+
+	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
+
+	/* the warm booting address of cpus */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+
+	nonboot_cpus_off();
+
+	INFO("%s: pd status 0x%x\n",
+	     __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
+}
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.h b/plat/rockchip/rk3328/drivers/pmu/pmu.h
new file mode 100644
index 0000000..dfb8912
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+#include <soc.h>
+
+struct rk3328_sleep_ddr_data {
+	uint32_t pmu_debug_enable;
+	uint32_t debug_iomux_save;
+	uint32_t pmic_sleep_save;
+	uint32_t pmu_wakeup_conf0;
+	uint32_t pmu_pwrmd_com;
+	uint32_t cru_mode_save;
+	uint32_t clk_sel0, clk_sel1, clk_sel18,
+		 clk_sel20, clk_sel24, clk_sel38;
+	uint32_t clk_ungt_save[CRU_CLKGATE_NUMS];
+	uint32_t cru_plls_con_save[MAX_PLL][CRU_PLL_CON_NUMS];
+};
+
+struct rk3328_sleep_sram_data {
+	uint32_t pmic_sleep_save;
+	uint32_t pmic_sleep_gpio_save[2];
+	uint32_t ddr_grf_con0;
+	uint32_t dpll_con_save[CRU_PLL_CON_NUMS];
+	uint32_t pd_sr_idle_save;
+	uint32_t uart2_ier;
+};
+
+/*****************************************************************************
+ * The ways of cores power domain contorlling
+ *****************************************************************************/
+enum cores_pm_ctr_mode {
+	core_pwr_pd = 0,
+	core_pwr_wfi = 1,
+	core_pwr_wfi_int = 2
+};
+
+enum pmu_cores_pm_by_wfi {
+	core_pm_en = 0,
+	core_pm_int_wakeup_en,
+	core_pm_dis_int,
+	core_pm_sft_wakeup_en
+};
+
+extern void *pmu_cpuson_entrypoint_start;
+extern void *pmu_cpuson_entrypoint_end;
+
+#define CORES_PM_DISABLE	0x0
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WAKEUP_CFG0		0x00
+#define PMU_PWRDN_CON		0x0c
+#define PMU_PWRDN_ST		0x10
+#define PMU_PWRMD_COM		0x18
+#define PMU_SFT_CON		0x1c
+#define PMU_INT_CON		0x20
+#define PMU_INT_ST		0x24
+#define PMU_POWER_ST		0x44
+#define PMU_CPUAPM_CON(n)	(0x80 + (n) * 4)
+#define PMU_SYS_REG(n)		(0xa0 + (n) * 4)
+
+#define CHECK_CPU_WFIE_BASE		(GRF_BASE + GRF_CPU_STATUS(1))
+
+enum pmu_core_pwrst_shift {
+	clst_cpu_wfe = 0,
+	clst_cpu_wfi = 4,
+};
+
+#define clstl_cpu_wfe (clst_cpu_wfe)
+#define clstb_cpu_wfe (clst_cpu_wfe)
+
+enum pmu_pd_id {
+	PD_CPU0 = 0,
+	PD_CPU1,
+	PD_CPU2,
+	PD_CPU3,
+};
+
+enum pmu_power_mode_common {
+	pmu_mode_en = 0,
+	sref_enter_en,
+	global_int_disable_cfg,
+	cpu0_pd_en,
+	wait_wakeup_begin_cfg = 4,
+	l2_flush_en,
+	l2_idle_en,
+	ddrio_ret_de_req,
+	ddrio_ret_en = 8,
+};
+
+enum pmu_sft_con {
+	upctl_c_sysreq_cfg = 0,
+	l2flushreq_req,
+	ddr_io_ret_cfg,
+	pmu_sft_ret_cfg,
+};
+
+#define CKECK_WFE_MSK		0x1
+#define CKECK_WFI_MSK		0x10
+#define CKECK_WFEI_MSK		0x11
+
+#define PD_CTR_LOOP		500
+#define CHK_CPU_LOOP		500
+#define MAX_WAIT_CONUT		1000
+
+#define WAKEUP_INT_CLUSTER_EN	0x1
+#define PMIC_SLEEP_REG		0x34
+
+#define PLL_IS_NORM_MODE(mode, pll_id)	\
+		((mode & (PLL_NORM_MODE(pll_id)) & 0xffff) != 0)
+
+#define CTLR_ENABLE_G1_BIT	BIT(1)
+#define UART_FIFO_EMPTY		BIT(6)
+
+#define UART_IER		0x04
+#define UART_FCR		0x08
+#define UART_LSR		0x14
+
+#define UART_INT_DISABLE	0x00
+#define UART_FIFO_RESET		0x07
+
+#endif /* PMU_H */
diff --git a/plat/rockchip/rk3328/drivers/soc/soc.c b/plat/rockchip/rk3328/drivers/soc/soc.c
new file mode 100644
index 0000000..59d8572
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/soc/soc.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <ddr_parameter.h>
+#include <plat_private.h>
+#include <rk3328_def.h>
+#include <soc.h>
+
+/* Table of regions to map using the MMU. */
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(UART0_BASE, UART0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART1_BASE, UART1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART2_BASE, UART2_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMU_BASE, PMU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GPIO0_BASE, GPIO0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GPIO1_BASE, GPIO1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GPIO2_BASE, GPIO2_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GPIO3_BASE, GPIO3_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CRU_BASE, CRU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GRF_BASE, GRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(FIREWALL_DDR_BASE, FIREWALL_DDR_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(FIREWALL_CFG_BASE, FIREWALL_CFG_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(STIME_BASE, STIME_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SHARE_MEM_BASE, SHARE_MEM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_GRF_BASE, DDR_GRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_UPCTL_BASE, DDR_UPCTL_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PWM_BASE, PWM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PARAM_BASE, DDR_PARAM_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(EFUSE8_BASE, EFUSE8_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(EFUSE32_BASE, EFUSE32_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PHY_BASE, DDR_PHY_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SERVER_MSCH_BASE, SERVER_MSCH_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_MONITOR_BASE, DDR_MONITOR_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(VOP_BASE, VOP_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOADE_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOADE_COUNT1, 0xffffffff);
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG, TIMER_EN);
+}
+
+void sgrf_init(void)
+{
+	uint32_t i, val;
+	struct param_ddr_usage usg;
+
+	/* general secure regions */
+	usg = ddr_region_usage_parse(DDR_PARAM_BASE,
+				     PLAT_MAX_DDR_CAPACITY_MB);
+	for (i = 0; i < usg.s_nr; i++) {
+		/* enable secure */
+		val = mmio_read_32(FIREWALL_DDR_BASE +
+			      FIREWALL_DDR_FW_DDR_CON_REG);
+		val |= BIT(7 - i);
+		mmio_write_32(FIREWALL_DDR_BASE +
+			      FIREWALL_DDR_FW_DDR_CON_REG, val);
+		/* map top and base */
+		mmio_write_32(FIREWALL_DDR_BASE +
+			      FIREWALL_DDR_FW_DDR_RGN(7 - i),
+			      RG_MAP_SECURE(usg.s_top[i], usg.s_base[i]));
+	}
+
+	/* set ddr rgn0_top and rga0_top as 0 */
+	mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_RGN(0), 0x0);
+
+	/* set all slave ip into no-secure, except stimer */
+	mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(0),
+		      SGRF_SLV_S_ALL_NS);
+	mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(1),
+		      SGRF_SLV_S_ALL_NS);
+	mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(2),
+		      SGRF_SLV_S_ALL_NS | STIMER_S);
+	mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(3),
+		      SGRF_SLV_S_ALL_NS);
+
+	/* set all master ip into no-secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), 0xf0000000);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), SGRF_MST_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4), SGRF_MST_S_ALL_NS);
+
+	/* set DMAC into no-secure */
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(3), DMA_IRQ_BOOT_NS);
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(4), DMA_PERI_CH_NS_15_0);
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(5), DMA_PERI_CH_NS_19_16);
+	mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(5), DMA_MANAGER_BOOT_NS);
+
+	/* soft reset dma before use */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(3), DMA_SOFTRST_REQ);
+	udelay(5);
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(3), DMA_SOFTRST_RLS);
+}
+
+void plat_rockchip_soc_init(void)
+{
+	secure_timer_init();
+	sgrf_init();
+
+	NOTICE("BL31:Rockchip release version: v%d.%d\n",
+	       MAJOR_VERSION, MINOR_VERSION);
+}
diff --git a/plat/rockchip/rk3328/drivers/soc/soc.h b/plat/rockchip/rk3328/drivers/soc/soc.h
new file mode 100644
index 0000000..a1f35b2
--- /dev/null
+++ b/plat/rockchip/rk3328/drivers/soc/soc.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+/******************************* stimer ***************************************/
+#define TIMER_LOADE_COUNT0	0x00
+#define TIMER_LOADE_COUNT1	0x04
+#define TIMER_CURRENT_VALUE0	0x08
+#define TIMER_CURRENT_VALUE1	0x0C
+#define TIMER_CONTROL_REG	0x10
+#define TIMER_INTSTATUS		0x18
+#define TIMER_EN		0x1
+
+extern const unsigned char rockchip_power_domain_tree_desc[];
+
+/**************************** read/write **************************************/
+#ifndef BITS_WMSK
+#define BITS_WMSK(msk, shift)	((msk) << (shift + REG_MSK_SHIFT))
+#endif
+
+/**************************** cru *********************************************/
+enum plls_id {
+	APLL_ID = 0,
+	DPLL_ID,
+	CPLL_ID,
+	GPLL_ID,
+	REVERVE,
+	NPLL_ID,
+	MAX_PLL,
+};
+
+#define CRU_CRU_MODE		0x0080
+#define CRU_CRU_MISC		0x0084
+#define CRU_GLB_SRST_FST	0x009c
+#define CRU_GLB_SRST_FST_VALUE	0xfdb9
+#define PLL_CONS(id, i)		(0x020 * (id) + ((i) * 4))
+#define CRU_CLKSEL_CON(i)	(0x100 + ((i) * 4))
+#define CRU_CLKSEL_NUMS		53
+#define CRU_CLKGATE_CON(i)	(0x200 + ((i) * 4))
+#define CRU_CLKGATE_NUMS	29
+#define CRU_SOFTRSTS_CON(n)	(0x300 + ((n) * 4))
+#define CRU_SOFTRSTS_NUMS	12
+#define CRU_PLL_CON_NUMS	5
+
+/* PLLn_CON1 */
+#define PLL_IS_LOCKED		BIT(10)
+/* PLLn_CON0 */
+#define PLL_BYPASS		BITS_WITH_WMASK(1, 0x1, 15)
+#define PLL_NO_BYPASS		BITS_WITH_WMASK(0, 0x1, 15)
+/* CRU_MODE */
+#define PLL_SLOW_MODE(id)	((id) == NPLL_ID) ?		\
+				BITS_WITH_WMASK(0, 0x1, 1) :	\
+				BITS_WITH_WMASK(0, 0x1, ((id) * 4))
+#define PLL_NORM_MODE(id)	((id) == NPLL_ID) ?		\
+				BITS_WITH_WMASK(1, 0x1, 1) :	\
+				BITS_WITH_WMASK(1, 0x1, ((id) * 4))
+
+#define CRU_GATEID_CONS(ID)	(0x200 + (ID / 16) * 4)
+#define CRU_CONS_GATEID(i)	(16 * (i))
+#define GATE_ID(reg, bit)	((reg * 16) + bit)
+
+#define PLL_LOCKED_TIMEOUT 600000U
+
+#define STIMER_CHN_BASE(n)	(STIME_BASE + 0x20 * (n))
+/************************** config regs ***************************************/
+#define FIREWALL_CFG_FW_SYS_CON(n)	(0x000 + (n) * 4)
+#define FIREWALL_DDR_FW_DDR_RGN(n)	(0x000 + (n) * 4)
+#define FIREWALL_DDR_FW_DDR_MST(n)	(0x020 + (n) * 4)
+#define FIREWALL_DDR_FW_DDR_CON_REG	(0x040)
+#define GRF_SOC_CON(n)			(0x400 + (n) * 4)
+#define GRF_SOC_STATUS(n)		(0x480 + (n) * 4)
+#define GRF_CPU_STATUS(n)		(0x520 + (n) * 4)
+#define GRF_OS_REG(n)			(0x5c8 + (n) * 4)
+#define DDRGRF_SOC_CON(n)		(0x000 + (n) * 4)
+#define DDRGRF_SOC_STATUS(n)		(0x100 + (n) * 4)
+#define SGRF_SOC_CON(n)			(0x000 + (n) * 4)
+#define SGRF_DMAC_CON(n)		(0x100 + (n) * 4)
+#define SGRF_HDCP_KEY_CON(n)		(0x280 + (n) * 4)
+
+#define DDR_PCTL2_PWRCTL		0x30
+/************************** regs func *****************************************/
+#define STIMER_S			BIT(23)
+#define SGRF_SLV_S_ALL_NS		0x0
+#define SGRF_MST_S_ALL_NS		0xffffffff
+#define DMA_IRQ_BOOT_NS			0xffffffff
+#define DMA_MANAGER_BOOT_NS		0x80008000
+#define DMA_PERI_CH_NS_15_0		0xffffffff
+#define DMA_PERI_CH_NS_19_16		0x000f000f
+#define DMA_SOFTRST_REQ			0x01000100
+#define DMA_SOFTRST_RLS			0x01000000
+
+#define SELFREF_EN			BIT(0)
+/************************** cpu ***********************************************/
+#define CPU_BOOT_ADDR_WMASK		0xffff0000
+#define CPU_BOOT_ADDR_ALIGN		16
+
+/************************** ddr secure region *********************************/
+#define PLAT_MAX_DDR_CAPACITY_MB	4096
+#define RG_MAP_SECURE(top, base)	((((top) - 1) << 16) | (base))
+
+/************************** gpio2_d2 ******************************************/
+#define SWPORTA_DR		0x00
+#define SWPORTA_DDR		0x04
+#define GPIO2_D2		BIT(26)
+#define GPIO2_D2_GPIO_MODE	0x30
+#define GRF_GPIO2D_IOMUX	0x34
+
+#endif /* SOC_H */
diff --git a/plat/rockchip/rk3328/include/plat.ld.S b/plat/rockchip/rk3328/include/plat.ld.S
new file mode 100644
index 0000000..e9bb3a2
--- /dev/null
+++ b/plat/rockchip/rk3328/include/plat.ld.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_LD_S
+#define ROCKCHIP_PLAT_LD_S
+
+MEMORY {
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+
+	} >PMUSRAM
+}
+
+#endif /* ROCKCHIP_PLAT_LD_S */
diff --git a/plat/rockchip/rk3328/include/platform_def.h b/plat/rockchip/rk3328/include/platform_def.h
new file mode 100644
index 0000000..3104d9f
--- /dev/null
+++ b/plat/rockchip/rk3328/include/platform_def.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+
+#include <rk3328_def.h>
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x800
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	6
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		U(1)
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF txet, ro, rw, Size: 512KB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x80000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted RAM
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x10000)
+#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+#define MAX_XLAT_TABLES		9
+#define MAX_MMAP_REGIONS	33
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE	RK3328_GICD_BASE
+#define PLAT_RK_GICC_BASE	RK3328_GICC_BASE
+
+#define PLAT_RK_UART_BASE	UART2_BASE
+#define PLAT_RK_UART_CLOCK	RK3328_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE	RK3328_BAUDRATE
+
+#define PLAT_RK_PRIMARY_CPU	0x0
+
+#define PSRAM_DO_DDR_RESUME	0
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
new file mode 100644
index 0000000..2be2be3
--- /dev/null
+++ b/plat/rockchip/rk3328/platform.mk
@@ -0,0 +1,64 @@
+#
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RK_PLAT			:=	plat/rockchip
+RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON		:=	${RK_PLAT}/common
+
+DISABLE_BIN_GENERATION	:=	1
+
+PLAT_INCLUDES		:=	-Idrivers/arm/gic/common/			\
+				-Idrivers/arm/gic/v2/			\
+				-I${RK_PLAT_COMMON}/                            \
+				-I${RK_PLAT_COMMON}/include/                    \
+				-I${RK_PLAT_COMMON}/aarch64/			\
+				-I${RK_PLAT_COMMON}/drivers/pmu/                \
+				-I${RK_PLAT_COMMON}/drivers/parameter/		\
+				-I${RK_PLAT_SOC}/				\
+				-I${RK_PLAT_SOC}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/include/
+
+RK_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				${RK_PLAT}/common/rockchip_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	lib/bl_aux_params/bl_aux_params.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				lib/xlat_tables/xlat_tables_common.c		\
+				plat/common/aarch64/crash_console_helpers.S	\
+				plat/common/plat_psci_common.c
+
+BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
+				drivers/arm/cci/cci.c				\
+				drivers/ti/uart/aarch64/16550_console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				lib/cpus/aarch64/aem_generic.S			\
+				lib/cpus/aarch64/cortex_a53.S			\
+				${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c	\
+				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+				${RK_PLAT_COMMON}/params_setup.c		\
+				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
+				${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S	\
+				${RK_PLAT_COMMON}/plat_pm.c			\
+				${RK_PLAT_COMMON}/plat_topology.c		\
+				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
+				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+				${RK_PLAT_SOC}/drivers/soc/soc.c
+
+include lib/coreboot/coreboot.mk
+include lib/libfdt/libfdt.mk
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+$(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
+
+WORKAROUND_CVE_2017_5715	:=	0
diff --git a/plat/rockchip/rk3328/rk3328_def.h b/plat/rockchip/rk3328/rk3328_def.h
new file mode 100644
index 0000000..60055e8
--- /dev/null
+++ b/plat/rockchip/rk3328/rk3328_def.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RK3328_DEF_H
+#define RK3328_DEF_H
+
+#define MAJOR_VERSION		(1)
+#define MINOR_VERSION		(2)
+
+#define SIZE_K(n)		((n) * 1024)
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define UART0_BASE		0xff110000
+#define UART0_SIZE		SIZE_K(64)
+
+#define UART1_BASE		0xff120000
+#define UART1_SIZE		SIZE_K(64)
+
+#define UART2_BASE		0xff130000
+#define UART2_SIZE		SIZE_K(64)
+
+#define PMU_BASE		0xff140000
+#define PMU_SIZE		SIZE_K(64)
+
+#define SGRF_BASE		0xff0d0000
+#define SGRF_SIZE		SIZE_K(64)
+
+#define CRU_BASE		0xff440000
+#define CRU_SIZE		SIZE_K(64)
+
+#define GRF_BASE		0xff100000
+#define GRF_SIZE		SIZE_K(64)
+
+#define GPIO0_BASE		0xff210000
+#define GPIO0_SIZE		SIZE_K(32)
+
+#define GPIO1_BASE		0xff220000
+#define GPIO1_SIZE		SIZE_K(32)
+
+#define GPIO2_BASE		0xff230000
+#define GPIO2_SIZE		SIZE_K(64)
+
+#define GPIO3_BASE		0xff240000
+#define GPIO3_SIZE		SIZE_K(64)
+
+#define STIME_BASE		0xff1d0000
+#define STIME_SIZE		SIZE_K(64)
+
+#define INTMEM_BASE		0xff090000
+#define INTMEM_SIZE		SIZE_K(32)
+
+#define SRAM_LDS_BASE		(INTMEM_BASE + SIZE_K(4))
+#define SRAM_LDS_SIZE		(INTMEM_SIZE - SIZE_K(4))
+
+#define PMUSRAM_BASE		INTMEM_BASE
+#define PMUSRAM_SIZE		SIZE_K(4)
+#define PMUSRAM_RSIZE		SIZE_K(4)
+
+#define VOP_BASE		0xff370000
+#define VOP_SIZE		SIZE_K(16)
+
+#define DDR_PHY_BASE		0xff400000
+#define DDR_PHY_SIZE		SIZE_K(4)
+
+#define SERVER_MSCH_BASE	0xff720000
+#define SERVER_MSCH_SIZE	SIZE_K(4)
+
+#define DDR_UPCTL_BASE		0xff780000
+#define DDR_UPCTL_SIZE		SIZE_K(12)
+
+#define DDR_MONITOR_BASE	0xff790000
+#define DDR_MONITOR_SIZE	SIZE_K(4)
+
+#define FIREWALL_DDR_BASE	0xff7c0000
+#define FIREWALL_DDR_SIZE	SIZE_K(64)
+
+#define FIREWALL_CFG_BASE	0xff7d0000
+#define FIREWALL_CFG_SIZE	SIZE_K(64)
+
+#define GIC400_BASE		0xff810000
+#define GIC400_SIZE		SIZE_K(64)
+
+#define DDR_GRF_BASE		0xff798000
+#define DDR_GRF_SIZE		SIZE_K(16)
+
+#define PWM_BASE		0xff1b0000
+#define PWM_SIZE		SIZE_K(64)
+
+#define DDR_PARAM_BASE		0x02000000
+#define DDR_PARAM_SIZE		SIZE_K(4)
+
+#define EFUSE8_BASE		0xff260000
+#define EFUSE8_SIZE		SIZE_K(4)
+
+#define EFUSE32_BASE		0xff0b0000
+#define EFUSE32_SIZE		SIZE_K(4)
+
+/**************************************************************************
+ * UART related constants
+ **************************************************************************/
+#define RK3328_BAUDRATE	1500000
+#define RK3328_UART_CLOCK	24000000
+
+/******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	24000000U
+#define SYS_COUNTER_FREQ_IN_MHZ		24
+
+/******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base rk_platform compatible GIC memory map */
+#define RK3328_GICD_BASE		(GIC400_BASE + 0x1000)
+#define RK3328_GICC_BASE		(GIC400_BASE + 0x2000)
+#define RK3328_GICR_BASE		0	/* no GICR in GIC-400 */
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define RK_IRQ_SEC_PHY_TIMER	29
+
+#define RK_IRQ_SEC_SGI_0	8
+#define RK_IRQ_SEC_SGI_1	9
+#define RK_IRQ_SEC_SGI_2	10
+#define RK_IRQ_SEC_SGI_3	11
+#define RK_IRQ_SEC_SGI_4	12
+#define RK_IRQ_SEC_SGI_5	13
+#define RK_IRQ_SEC_SGI_6	14
+#define RK_IRQ_SEC_SGI_7	15
+
+/*
+ * Define a list of Group 0 interrupts.
+ */
+#define PLAT_RK_GICV2_G0_IRQS						\
+	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),		\
+	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+#define SHARE_MEM_BASE          0x100000/* [1MB, 1MB+60K]*/
+#define SHARE_MEM_PAGE_NUM      15
+#define SHARE_MEM_SIZE          SIZE_K(SHARE_MEM_PAGE_NUM * 4)
+
+#endif /* RK3328_DEF_H */
diff --git a/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c
new file mode 100644
index 0000000..fa98eb3
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <ddr_rk3368.h>
+#include <pmu.h>
+#include <rk3368_def.h>
+#include <soc.h>
+
+/* GRF_SOC_STATUS0 */
+#define DPLL_LOCK		(0x1 << 2)
+
+/* GRF_DDRC0_CON0 */
+#define GRF_DDR_16BIT_EN	(((0x1 << 3) << 16) | (0x1 << 3))
+#define GRF_DDR_32BIT_EN	(((0x1 << 3) << 16) | (0x0 << 3))
+#define GRF_MOBILE_DDR_EN	(((0x1 << 4) << 16) | (0x1 << 4))
+#define GRF_MOBILE_DDR_DISB	(((0x1 << 4) << 16) | (0x0 << 4))
+#define GRF_DDR3_EN		(((0x1 << 2) << 16) | (0x1 << 2))
+#define GRF_LPDDR2_3_EN		(((0x1 << 2) << 16) | (0x0 << 2))
+
+/* PMUGRF_SOC_CON0 */
+#define ddrphy_bufferen_io_en(n)	((0x1 << (9 + 16)) | (n << 9))
+#define ddrphy_bufferen_core_en(n)	((0x1 << (8 + 16)) | (n << 8))
+
+struct PCTRL_TIMING_TAG {
+	uint32_t ddrfreq;
+	uint32_t TOGCNT1U;
+	uint32_t TINIT;
+	uint32_t TRSTH;
+	uint32_t TOGCNT100N;
+	uint32_t TREFI;
+	uint32_t TMRD;
+	uint32_t TRFC;
+	uint32_t TRP;
+	uint32_t TRTW;
+	uint32_t TAL;
+	uint32_t TCL;
+	uint32_t TCWL;
+	uint32_t TRAS;
+	uint32_t TRC;
+	uint32_t TRCD;
+	uint32_t TRRD;
+	uint32_t TRTP;
+	uint32_t TWR;
+	uint32_t TWTR;
+	uint32_t TEXSR;
+	uint32_t TXP;
+	uint32_t TXPDLL;
+	uint32_t TZQCS;
+	uint32_t TZQCSI;
+	uint32_t TDQS;
+	uint32_t TCKSRE;
+	uint32_t TCKSRX;
+	uint32_t TCKE;
+	uint32_t TMOD;
+	uint32_t TRSTL;
+	uint32_t TZQCL;
+	uint32_t TMRR;
+	uint32_t TCKESR;
+	uint32_t TDPD;
+	uint32_t TREFI_MEM_DDR3;
+};
+
+struct MSCH_SAVE_REG_TAG {
+	uint32_t ddrconf;
+	uint32_t ddrtiming;
+	uint32_t ddrmode;
+	uint32_t readlatency;
+	uint32_t activate;
+	uint32_t devtodev;
+};
+
+/* ddr suspend need save reg */
+struct PCTL_SAVE_REG_TAG {
+	uint32_t SCFG;
+	uint32_t CMDTSTATEN;
+	uint32_t MCFG1;
+	uint32_t MCFG;
+	uint32_t PPCFG;
+	struct PCTRL_TIMING_TAG pctl_timing;
+	/* DFI Control Registers */
+	uint32_t DFITCTRLDELAY;
+	uint32_t DFIODTCFG;
+	uint32_t DFIODTCFG1;
+	uint32_t DFIODTRANKMAP;
+	/* DFI Write Data Registers */
+	uint32_t DFITPHYWRDATA;
+	uint32_t DFITPHYWRLAT;
+	uint32_t DFITPHYWRDATALAT;
+	/* DFI Read Data Registers */
+	uint32_t DFITRDDATAEN;
+	uint32_t DFITPHYRDLAT;
+	/* DFI Update Registers */
+	uint32_t DFITPHYUPDTYPE0;
+	uint32_t DFITPHYUPDTYPE1;
+	uint32_t DFITPHYUPDTYPE2;
+	uint32_t DFITPHYUPDTYPE3;
+	uint32_t DFITCTRLUPDMIN;
+	uint32_t DFITCTRLUPDMAX;
+	uint32_t DFITCTRLUPDDLY;
+	uint32_t DFIUPDCFG;
+	uint32_t DFITREFMSKI;
+	uint32_t DFITCTRLUPDI;
+	/* DFI Status Registers */
+	uint32_t DFISTCFG0;
+	uint32_t DFISTCFG1;
+	uint32_t DFITDRAMCLKEN;
+	uint32_t DFITDRAMCLKDIS;
+	uint32_t DFISTCFG2;
+	/* DFI Low Power Register */
+	uint32_t DFILPCFG0;
+};
+
+struct DDRPHY_SAVE_REG_TAG {
+	uint32_t PHY_REG0;
+	uint32_t PHY_REG1;
+	uint32_t PHY_REGB;
+	uint32_t PHY_REGC;
+	uint32_t PHY_REG11;
+	uint32_t PHY_REG13;
+	uint32_t PHY_REG14;
+	uint32_t PHY_REG16;
+	uint32_t PHY_REG20;
+	uint32_t PHY_REG21;
+	uint32_t PHY_REG26;
+	uint32_t PHY_REG27;
+	uint32_t PHY_REG28;
+	uint32_t PHY_REG30;
+	uint32_t PHY_REG31;
+	uint32_t PHY_REG36;
+	uint32_t PHY_REG37;
+	uint32_t PHY_REG38;
+	uint32_t PHY_REG40;
+	uint32_t PHY_REG41;
+	uint32_t PHY_REG46;
+	uint32_t PHY_REG47;
+	uint32_t PHY_REG48;
+	uint32_t PHY_REG50;
+	uint32_t PHY_REG51;
+	uint32_t PHY_REG56;
+	uint32_t PHY_REG57;
+	uint32_t PHY_REG58;
+	uint32_t PHY_REGDLL;
+	uint32_t PHY_REGEC;
+	uint32_t PHY_REGED;
+	uint32_t PHY_REGEE;
+	uint32_t PHY_REGEF;
+	uint32_t PHY_REGFB;
+	uint32_t PHY_REGFC;
+	uint32_t PHY_REGFD;
+	uint32_t PHY_REGFE;
+};
+
+struct BACKUP_REG_TAG {
+	uint32_t tag;
+	uint32_t pctladdr;
+	struct PCTL_SAVE_REG_TAG pctl;
+	uint32_t phyaddr;
+	struct DDRPHY_SAVE_REG_TAG phy;
+	uint32_t nocaddr;
+	struct MSCH_SAVE_REG_TAG noc;
+	uint32_t pllselect;
+	uint32_t phypllockaddr;
+	uint32_t phyplllockmask;
+	uint32_t phyplllockval;
+	uint32_t pllpdstat;
+	uint32_t dpllmodeaddr;
+	uint32_t dpllslowmode;
+	uint32_t dpllnormalmode;
+	uint32_t dpllresetaddr;
+	uint32_t dpllreset;
+	uint32_t dplldereset;
+	uint32_t dpllconaddr;
+	uint32_t dpllcon[4];
+	uint32_t dplllockaddr;
+	uint32_t dplllockmask;
+	uint32_t dplllockval;
+	uint32_t ddrpllsrcdivaddr;
+	uint32_t ddrpllsrcdiv;
+	uint32_t retendisaddr;
+	uint32_t retendisval;
+	uint32_t grfregaddr;
+	uint32_t grfddrcreg;
+	uint32_t crupctlphysoftrstaddr;
+	uint32_t cruresetpctlphy;
+	uint32_t cruderesetphy;
+	uint32_t cruderesetpctlphy;
+	uint32_t physoftrstaddr;
+	uint32_t endtag;
+};
+
+static uint32_t ddr_get_phy_pll_freq(void)
+{
+	uint32_t ret = 0;
+	uint32_t fb_div, pre_div;
+
+	fb_div = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEC);
+	fb_div |= (mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGED) & 0x1) << 8;
+
+	pre_div = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEE) & 0xff;
+	ret = 2 * 24 * fb_div / (4 * pre_div);
+
+	return ret;
+}
+
+static void ddr_copy(uint32_t *pdest, uint32_t *psrc, uint32_t words)
+{
+	uint32_t i;
+
+	for (i = 0; i < words; i++)
+		pdest[i] = psrc[i];
+}
+
+static void ddr_get_dpll_cfg(uint32_t *p)
+{
+	uint32_t nmhz, NO, NF, NR;
+
+	nmhz = ddr_get_phy_pll_freq();
+	if (nmhz <= 150)
+		NO = 6;
+	else if (nmhz <= 250)
+		NO = 4;
+	else if (nmhz <= 500)
+		NO = 2;
+	else
+		NO = 1;
+
+	NR = 1;
+	NF = 2 * nmhz * NR * NO / 24;
+
+	p[0] = SET_NR(NR) | SET_NO(NO);
+	p[1] = SET_NF(NF);
+	p[2] = SET_NB(NF / 2);
+}
+
+void ddr_reg_save(uint32_t pllpdstat, uint64_t base_addr)
+{
+	struct BACKUP_REG_TAG *p_ddr_reg = (struct BACKUP_REG_TAG *)base_addr;
+	struct PCTL_SAVE_REG_TAG *pctl_tim = &p_ddr_reg->pctl;
+
+	p_ddr_reg->tag = 0x56313031;
+	p_ddr_reg->pctladdr = DDR_PCTL_BASE;
+	p_ddr_reg->phyaddr = DDR_PHY_BASE;
+	p_ddr_reg->nocaddr = SERVICE_BUS_BASE;
+
+	/* PCTLR */
+	ddr_copy((uint32_t *)&pctl_tim->pctl_timing.TOGCNT1U,
+		 (uint32_t *)(DDR_PCTL_BASE + DDR_PCTL_TOGCNT1U), 35);
+	pctl_tim->pctl_timing.TREFI |= DDR_UPD_REF_ENABLE;
+	pctl_tim->SCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_SCFG);
+	pctl_tim->CMDTSTATEN = mmio_read_32(DDR_PCTL_BASE +
+					    DDR_PCTL_CMDTSTATEN);
+	pctl_tim->MCFG1 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_MCFG1);
+	pctl_tim->MCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_MCFG);
+	pctl_tim->PPCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_PPCFG);
+	pctl_tim->pctl_timing.ddrfreq = mmio_read_32(DDR_PCTL_BASE +
+						     DDR_PCTL_TOGCNT1U * 2);
+	pctl_tim->DFITCTRLDELAY = mmio_read_32(DDR_PCTL_BASE +
+					       DDR_PCTL_DFITCTRLDELAY);
+	pctl_tim->DFIODTCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFIODTCFG);
+	pctl_tim->DFIODTCFG1 = mmio_read_32(DDR_PCTL_BASE +
+					    DDR_PCTL_DFIODTCFG1);
+	pctl_tim->DFIODTRANKMAP = mmio_read_32(DDR_PCTL_BASE +
+					       DDR_PCTL_DFIODTRANKMAP);
+	pctl_tim->DFITPHYWRDATA = mmio_read_32(DDR_PCTL_BASE +
+					       DDR_PCTL_DFITPHYWRDATA);
+	pctl_tim->DFITPHYWRLAT = mmio_read_32(DDR_PCTL_BASE +
+					      DDR_PCTL_DFITPHYWRLAT);
+	pctl_tim->DFITPHYWRDATALAT = mmio_read_32(DDR_PCTL_BASE +
+						  DDR_PCTL_DFITPHYWRDATALAT);
+	pctl_tim->DFITRDDATAEN = mmio_read_32(DDR_PCTL_BASE +
+					      DDR_PCTL_DFITRDDATAEN);
+	pctl_tim->DFITPHYRDLAT = mmio_read_32(DDR_PCTL_BASE +
+					      DDR_PCTL_DFITPHYRDLAT);
+	pctl_tim->DFITPHYUPDTYPE0 = mmio_read_32(DDR_PCTL_BASE +
+						 DDR_PCTL_DFITPHYUPDTYPE0);
+	pctl_tim->DFITPHYUPDTYPE1 = mmio_read_32(DDR_PCTL_BASE +
+						 DDR_PCTL_DFITPHYUPDTYPE1);
+	pctl_tim->DFITPHYUPDTYPE2 = mmio_read_32(DDR_PCTL_BASE +
+						 DDR_PCTL_DFITPHYUPDTYPE2);
+	pctl_tim->DFITPHYUPDTYPE3 = mmio_read_32(DDR_PCTL_BASE +
+						 DDR_PCTL_DFITPHYUPDTYPE3);
+	pctl_tim->DFITCTRLUPDMIN = mmio_read_32(DDR_PCTL_BASE +
+						DDR_PCTL_DFITCTRLUPDMIN);
+	pctl_tim->DFITCTRLUPDMAX = mmio_read_32(DDR_PCTL_BASE +
+						DDR_PCTL_DFITCTRLUPDMAX);
+	pctl_tim->DFITCTRLUPDDLY = mmio_read_32(DDR_PCTL_BASE +
+						DDR_PCTL_DFITCTRLUPDDLY);
+
+	pctl_tim->DFIUPDCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFIUPDCFG);
+	pctl_tim->DFITREFMSKI = mmio_read_32(DDR_PCTL_BASE +
+					     DDR_PCTL_DFITREFMSKI);
+	pctl_tim->DFITCTRLUPDI = mmio_read_32(DDR_PCTL_BASE +
+					      DDR_PCTL_DFITCTRLUPDI);
+	pctl_tim->DFISTCFG0 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFISTCFG0);
+	pctl_tim->DFISTCFG1 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFISTCFG1);
+	pctl_tim->DFITDRAMCLKEN = mmio_read_32(DDR_PCTL_BASE +
+					       DDR_PCTL_DFITDRAMCLKEN);
+	pctl_tim->DFITDRAMCLKDIS = mmio_read_32(DDR_PCTL_BASE +
+						DDR_PCTL_DFITDRAMCLKDIS);
+	pctl_tim->DFISTCFG2 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFISTCFG2);
+	pctl_tim->DFILPCFG0 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFILPCFG0);
+
+	/* PHY */
+	p_ddr_reg->phy.PHY_REG0 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG0);
+	p_ddr_reg->phy.PHY_REG1 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG1);
+	p_ddr_reg->phy.PHY_REGB = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGB);
+	p_ddr_reg->phy.PHY_REGC = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGC);
+	p_ddr_reg->phy.PHY_REG11 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG11);
+	p_ddr_reg->phy.PHY_REG13 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG13);
+	p_ddr_reg->phy.PHY_REG14 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG14);
+	p_ddr_reg->phy.PHY_REG16 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG16);
+	p_ddr_reg->phy.PHY_REG20 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG20);
+	p_ddr_reg->phy.PHY_REG21 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG21);
+	p_ddr_reg->phy.PHY_REG26 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG26);
+	p_ddr_reg->phy.PHY_REG27 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG27);
+	p_ddr_reg->phy.PHY_REG28 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG28);
+	p_ddr_reg->phy.PHY_REG30 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG30);
+	p_ddr_reg->phy.PHY_REG31 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG31);
+	p_ddr_reg->phy.PHY_REG36 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG36);
+	p_ddr_reg->phy.PHY_REG37 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG37);
+	p_ddr_reg->phy.PHY_REG38 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG38);
+	p_ddr_reg->phy.PHY_REG40 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG40);
+	p_ddr_reg->phy.PHY_REG41 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG41);
+	p_ddr_reg->phy.PHY_REG46 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG46);
+	p_ddr_reg->phy.PHY_REG47 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG47);
+	p_ddr_reg->phy.PHY_REG48 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG48);
+	p_ddr_reg->phy.PHY_REG50 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG50);
+	p_ddr_reg->phy.PHY_REG51 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG51);
+	p_ddr_reg->phy.PHY_REG56 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG56);
+	p_ddr_reg->phy.PHY_REG57 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG57);
+	p_ddr_reg->phy.PHY_REG58 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG58);
+	p_ddr_reg->phy.PHY_REGDLL = mmio_read_32(DDR_PHY_BASE +
+						 DDR_PHY_REGDLL);
+	p_ddr_reg->phy.PHY_REGEC = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEC);
+	p_ddr_reg->phy.PHY_REGED = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGED);
+	p_ddr_reg->phy.PHY_REGEE = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEE);
+	p_ddr_reg->phy.PHY_REGEF = 0;
+
+	if (mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG2) & 0x2) {
+		p_ddr_reg->phy.PHY_REGFB = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REG2C);
+		p_ddr_reg->phy.PHY_REGFC = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REG3C);
+		p_ddr_reg->phy.PHY_REGFD = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REG4C);
+		p_ddr_reg->phy.PHY_REGFE = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REG5C);
+	} else {
+		p_ddr_reg->phy.PHY_REGFB = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REGFB);
+		p_ddr_reg->phy.PHY_REGFC = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REGFC);
+		p_ddr_reg->phy.PHY_REGFD = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REGFD);
+		p_ddr_reg->phy.PHY_REGFE = mmio_read_32(DDR_PHY_BASE +
+							DDR_PHY_REGFE);
+	}
+
+	/* NOC */
+	p_ddr_reg->noc.ddrconf = mmio_read_32(SERVICE_BUS_BASE + MSCH_DDRCONF);
+	p_ddr_reg->noc.ddrtiming = mmio_read_32(SERVICE_BUS_BASE +
+						MSCH_DDRTIMING);
+	p_ddr_reg->noc.ddrmode = mmio_read_32(SERVICE_BUS_BASE + MSCH_DDRMODE);
+	p_ddr_reg->noc.readlatency = mmio_read_32(SERVICE_BUS_BASE +
+						  MSCH_READLATENCY);
+	p_ddr_reg->noc.activate = mmio_read_32(SERVICE_BUS_BASE +
+					       MSCH_ACTIVATE);
+	p_ddr_reg->noc.devtodev = mmio_read_32(SERVICE_BUS_BASE +
+					       MSCH_DEVTODEV);
+
+	p_ddr_reg->pllselect = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEE) * 0x1;
+	p_ddr_reg->phypllockaddr = GRF_BASE + GRF_SOC_STATUS0;
+	p_ddr_reg->phyplllockmask = GRF_DDRPHY_LOCK;
+	p_ddr_reg->phyplllockval = 0;
+
+	/* PLLPD */
+	p_ddr_reg->pllpdstat = pllpdstat;
+	/* DPLL */
+	p_ddr_reg->dpllmodeaddr = CRU_BASE + PLL_CONS(DPLL_ID, 3);
+	/* slow mode and power on */
+	p_ddr_reg->dpllslowmode = DPLL_WORK_SLOW_MODE | DPLL_POWER_DOWN;
+	p_ddr_reg->dpllnormalmode = DPLL_WORK_NORMAL_MODE;
+	p_ddr_reg->dpllresetaddr = CRU_BASE + PLL_CONS(DPLL_ID, 3);
+	p_ddr_reg->dpllreset = DPLL_RESET_CONTROL_NORMAL;
+	p_ddr_reg->dplldereset = DPLL_RESET_CONTROL_RESET;
+	p_ddr_reg->dpllconaddr = CRU_BASE + PLL_CONS(DPLL_ID, 0);
+
+	if (p_ddr_reg->pllselect == 0) {
+		p_ddr_reg->dpllcon[0] = (mmio_read_32(CRU_BASE +
+						      PLL_CONS(DPLL_ID, 0))
+							& 0xffff) |
+					(0xFFFFu << 16);
+		p_ddr_reg->dpllcon[1] = (mmio_read_32(CRU_BASE +
+						      PLL_CONS(DPLL_ID, 1))
+							& 0xffff);
+		p_ddr_reg->dpllcon[2] = (mmio_read_32(CRU_BASE +
+						      PLL_CONS(DPLL_ID, 2))
+							& 0xffff);
+		p_ddr_reg->dpllcon[3] = (mmio_read_32(CRU_BASE +
+						      PLL_CONS(DPLL_ID, 3))
+							& 0xffff) |
+					(0xFFFFu << 16);
+	} else {
+		ddr_get_dpll_cfg(&p_ddr_reg->dpllcon[0]);
+	}
+
+	p_ddr_reg->pllselect = 0;
+	p_ddr_reg->dplllockaddr = CRU_BASE + PLL_CONS(DPLL_ID, 1);
+	p_ddr_reg->dplllockmask = DPLL_STATUS_LOCK;
+	p_ddr_reg->dplllockval = DPLL_STATUS_LOCK;
+
+	/* SET_DDR_PLL_SRC */
+	p_ddr_reg->ddrpllsrcdivaddr = CRU_BASE + CRU_CLKSELS_CON(13);
+	p_ddr_reg->ddrpllsrcdiv = (mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(13))
+					& DDR_PLL_SRC_MASK)
+					| (DDR_PLL_SRC_MASK << 16);
+	p_ddr_reg->retendisaddr = PMU_BASE + PMU_PWRMD_COM;
+	p_ddr_reg->retendisval = PD_PERI_PWRDN_ENABLE;
+	p_ddr_reg->grfregaddr = GRF_BASE + GRF_DDRC0_CON0;
+	p_ddr_reg->grfddrcreg = (mmio_read_32(GRF_BASE + GRF_DDRC0_CON0) &
+					      DDR_PLL_SRC_MASK) |
+				 (DDR_PLL_SRC_MASK << 16);
+
+	/* pctl phy soft reset */
+	p_ddr_reg->crupctlphysoftrstaddr = CRU_BASE + CRU_SOFTRSTS_CON(10);
+	p_ddr_reg->cruresetpctlphy = DDRCTRL0_PSRSTN_REQ(1) |
+				     DDRCTRL0_SRSTN_REQ(1) |
+				     DDRPHY0_PSRSTN_REQ(1) |
+				     DDRPHY0_SRSTN_REQ(1);
+	p_ddr_reg->cruderesetphy = DDRCTRL0_PSRSTN_REQ(1) |
+				   DDRCTRL0_SRSTN_REQ(1) |
+				   DDRPHY0_PSRSTN_REQ(0) |
+				   DDRPHY0_SRSTN_REQ(0);
+
+	p_ddr_reg->cruderesetpctlphy = DDRCTRL0_PSRSTN_REQ(0) |
+				       DDRCTRL0_SRSTN_REQ(0) |
+				       DDRPHY0_PSRSTN_REQ(0) |
+				       DDRPHY0_SRSTN_REQ(0);
+
+	p_ddr_reg->physoftrstaddr = DDR_PHY_BASE + DDR_PHY_REG0;
+
+	p_ddr_reg->endtag = 0xFFFFFFFF;
+}
+
+/*
+ * "rk3368_ddr_reg_resume_V1.05.bin" is an executable bin which is generated
+ * by ARM DS5 for resuming ddr controller. If the soc wakes up from system
+ * suspend, ddr needs to be resumed and the resuming code needs to be run in
+ * sram. But there is not a way to pointing the resuming code to the PMUSRAM
+ * when linking .o files of bl31, so we use the
+ * "rk3368_ddr_reg_resume_V1.05.bin" whose code is position-independent and
+ * it can be loaded anywhere and run.
+ */
+static __aligned(4) unsigned int ddr_reg_resume[] = {
+	#include "rk3368_ddr_reg_resume_V1.05.bin"
+};
+
+uint32_t ddr_get_resume_code_size(void)
+{
+	return sizeof(ddr_reg_resume);
+}
+
+uint32_t ddr_get_resume_data_size(void)
+{
+	return sizeof(struct BACKUP_REG_TAG);
+}
+
+uint32_t *ddr_get_resume_code_base(void)
+{
+	return (unsigned int *)ddr_reg_resume;
+}
diff --git a/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h
new file mode 100644
index 0000000..6663bcb
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DDR_RK3368_H
+#define DDR_RK3368_H
+
+#define DDR_PCTL_SCFG		0x0
+#define DDR_PCTL_SCTL		0x4
+#define DDR_PCTL_STAT		0x8
+#define DDR_PCTL_INTRSTAT	0xc
+
+#define DDR_PCTL_MCMD		0x40
+#define DDR_PCTL_POWCTL		0x44
+#define DDR_PCTL_POWSTAT	0x48
+#define DDR_PCTL_CMDTSTAT	0x4c
+#define DDR_PCTL_CMDTSTATEN	0x50
+#define DDR_PCTL_MRRCFG0	0x60
+#define DDR_PCTL_MRRSTAT0	0x64
+#define DDR_PCTL_MRRSTAT1	0x68
+#define DDR_PCTL_MCFG1		0x7c
+#define DDR_PCTL_MCFG		0x80
+#define DDR_PCTL_PPCFG		0x84
+#define DDR_PCTL_MSTAT		0x88
+#define DDR_PCTL_LPDDR2ZQCFG	0x8c
+#define DDR_PCTL_DTUPDES		0x94
+#define DDR_PCTL_DTUNA			0x98
+#define DDR_PCTL_DTUNE			0x9c
+#define DDR_PCTL_DTUPRD0		0xa0
+#define DDR_PCTL_DTUPRD1		0xa4
+#define DDR_PCTL_DTUPRD2		0xa8
+#define DDR_PCTL_DTUPRD3		0xac
+#define DDR_PCTL_DTUAWDT		0xb0
+#define DDR_PCTL_TOGCNT1U		0xc0
+#define DDR_PCTL_TINIT			0xc4
+#define DDR_PCTL_TRSTH			0xc8
+#define DDR_PCTL_TOGCNT100N		0xcc
+#define DDR_PCTL_TREFI			0xd0
+#define DDR_PCTL_TMRD			0xd4
+#define DDR_PCTL_TRFC			0xd8
+#define DDR_PCTL_TRP			0xdc
+#define DDR_PCTL_TRTW			0xe0
+#define DDR_PCTL_TAL			0xe4
+#define DDR_PCTL_TCL			0xe8
+#define DDR_PCTL_TCWL			0xec
+#define DDR_PCTL_TRAS			0xf0
+#define DDR_PCTL_TRC			0xf4
+#define DDR_PCTL_TRCD			0xf8
+#define DDR_PCTL_TRRD			0xfc
+#define DDR_PCTL_TRTP			0x100
+#define DDR_PCTL_TWR			0x104
+#define DDR_PCTL_TWTR			0x108
+#define DDR_PCTL_TEXSR			0x10c
+#define DDR_PCTL_TXP			0x110
+#define DDR_PCTL_TXPDLL			0x114
+#define DDR_PCTL_TZQCS			0x118
+#define DDR_PCTL_TZQCSI			0x11c
+#define DDR_PCTL_TDQS			0x120
+#define DDR_PCTL_TCKSRE			0x124
+#define DDR_PCTL_TCKSRX			0x128
+#define DDR_PCTL_TCKE			0x12c
+#define DDR_PCTL_TMOD			0x130
+#define DDR_PCTL_TRSTL			0x134
+#define DDR_PCTL_TZQCL			0x138
+#define DDR_PCTL_TMRR			0x13c
+#define DDR_PCTL_TCKESR			0x140
+#define DDR_PCTL_TDPD			0x144
+#define DDR_PCTL_TREFI_MEM_DDR3	0x148
+#define DDR_PCTL_ECCCFG			0x180
+#define DDR_PCTL_ECCTST			0x184
+#define DDR_PCTL_ECCCLR			0x188
+#define DDR_PCTL_ECCLOG			0x18c
+#define DDR_PCTL_DTUWACTL		0x200
+#define DDR_PCTL_DTURACTL		0x204
+#define DDR_PCTL_DTUCFG			0x208
+#define DDR_PCTL_DTUECTL		0x20c
+#define DDR_PCTL_DTUWD0			0x210
+#define DDR_PCTL_DTUWD1			0x214
+#define DDR_PCTL_DTUWD2			0x218
+#define DDR_PCTL_DTUWD3			0x21c
+#define DDR_PCTL_DTUWDM			0x220
+#define DDR_PCTL_DTURD0			0x224
+#define DDR_PCTL_DTURD1			0x228
+#define DDR_PCTL_DTURD2			0x22c
+#define DDR_PCTL_DTURD3			0x230
+#define DDR_PCTL_DTULFSRWD		0x234
+#define DDR_PCTL_DTULFSRRD		0x238
+#define DDR_PCTL_DTUEAF			0x23c
+#define DDR_PCTL_DFITCTRLDELAY	0x240
+#define DDR_PCTL_DFIODTCFG		0x244
+#define DDR_PCTL_DFIODTCFG1		0x248
+#define DDR_PCTL_DFIODTRANKMAP		0x24c
+#define DDR_PCTL_DFITPHYWRDATA		0x250
+#define DDR_PCTL_DFITPHYWRLAT		0x254
+#define DDR_PCTL_DFITPHYWRDATALAT	0x258
+#define DDR_PCTL_DFITRDDATAEN		0x260
+#define DDR_PCTL_DFITPHYRDLAT		0x264
+#define DDR_PCTL_DFITPHYUPDTYPE0	0x270
+#define DDR_PCTL_DFITPHYUPDTYPE1	0x274
+#define DDR_PCTL_DFITPHYUPDTYPE2	0x278
+#define DDR_PCTL_DFITPHYUPDTYPE3	0x27c
+#define DDR_PCTL_DFITCTRLUPDMIN		0x280
+#define DDR_PCTL_DFITCTRLUPDMAX		0x284
+#define DDR_PCTL_DFITCTRLUPDDLY		0x288
+#define DDR_PCTL_DFIUPDCFG			0x290
+#define DDR_PCTL_DFITREFMSKI		0x294
+#define DDR_PCTL_DFITCTRLUPDI		0x298
+#define DDR_PCTL_DFITRCFG0			0x2ac
+#define DDR_PCTL_DFITRSTAT0			0x2b0
+#define DDR_PCTL_DFITRWRLVLEN		0x2b4
+#define DDR_PCTL_DFITRRDLVLEN		0x2b8
+#define DDR_PCTL_DFITRRDLVLGATEEN	0x2bc
+#define DDR_PCTL_DFISTSTAT0			0x2c0
+#define DDR_PCTL_DFISTCFG0			0x2c4
+#define DDR_PCTL_DFISTCFG1			0x2c8
+#define DDR_PCTL_DFITDRAMCLKEN		0x2d0
+#define DDR_PCTL_DFITDRAMCLKDIS		0x2d4
+#define DDR_PCTL_DFISTCFG2			0x2d8
+#define DDR_PCTL_DFISTPARCLR		0x2dc
+#define DDR_PCTL_DFISTPARLOG		0x2e0
+#define DDR_PCTL_DFILPCFG0			0x2f0
+#define DDR_PCTL_DFITRWRLVLRESP0	0x300
+#define DDR_PCTL_DFITRWRLVLRESP1	0x304
+#define DDR_PCTL_DFITRWRLVLRESP2	0x308
+#define DDR_PCTL_DFITRRDLVLRESP0	0x30c
+#define DDR_PCTL_DFITRRDLVLRESP1	0x310
+#define DDR_PCTL_DFITRRDLVLRESP2	0x314
+#define DDR_PCTL_DFITRWRLVLDELAY0	0x318
+#define DDR_PCTL_DFITRWRLVLDELAY1	0x31c
+#define DDR_PCTL_DFITRWRLVLDELAY2	0x320
+#define DDR_PCTL_DFITRRDLVLDELAY0	0x324
+#define DDR_PCTL_DFITRRDLVLDELAY1	0x328
+#define DDR_PCTL_DFITRRDLVLDELAY2	0x32c
+#define DDR_PCTL_DFITRRDLVLGATEDELAY0	0x330
+#define DDR_PCTL_DFITRRDLVLGATEDELAY1	0x334
+#define DDR_PCTL_DFITRRDLVLGATEDELAY2	0x338
+#define DDR_PCTL_DFITRCMD			0x33c
+#define DDR_PCTL_IPVR				0x3f8
+#define DDR_PCTL_IPTR				0x3fc
+
+/* DDR PHY REG */
+#define DDR_PHY_REG0		0x0
+#define DDR_PHY_REG1		0x4
+#define DDR_PHY_REG2		0x8
+#define DDR_PHY_REG3		0xc
+#define DDR_PHY_REG4		0x10
+#define DDR_PHY_REG5		0x14
+#define DDR_PHY_REG6		0x18
+#define DDR_PHY_REGB		0x2c
+#define DDR_PHY_REGC		0x30
+#define DDR_PHY_REG11		0x44
+#define DDR_PHY_REG12		0x48
+#define DDR_PHY_REG13		0x4c
+#define DDR_PHY_REG14		0x50
+#define DDR_PHY_REG16		0x58
+#define DDR_PHY_REG20		0x80
+#define DDR_PHY_REG21		0x84
+#define DDR_PHY_REG26		0x98
+#define DDR_PHY_REG27		0x9c
+#define DDR_PHY_REG28		0xa0
+#define DDR_PHY_REG2C		0xb0
+#define DDR_PHY_REG30		0xc0
+#define DDR_PHY_REG31		0xc4
+#define DDR_PHY_REG36		0xd8
+#define DDR_PHY_REG37		0xdc
+#define DDR_PHY_REG38		0xe0
+#define DDR_PHY_REG3C		0xf0
+#define DDR_PHY_REG40		0x100
+#define DDR_PHY_REG41		0x104
+#define DDR_PHY_REG46		0x118
+#define DDR_PHY_REG47		0x11c
+#define DDR_PHY_REG48		0x120
+#define DDR_PHY_REG4C		0x130
+#define DDR_PHY_REG50		0x140
+#define DDR_PHY_REG51		0x144
+#define DDR_PHY_REG56		0x158
+#define DDR_PHY_REG57		0x15c
+#define DDR_PHY_REG58		0x160
+#define DDR_PHY_REG5C		0x170
+#define DDR_PHY_REGDLL		0x290
+#define DDR_PHY_REGEC		0x3b0
+#define DDR_PHY_REGED		0x3b4
+#define DDR_PHY_REGEE		0x3b8
+#define DDR_PHY_REGEF		0x3bc
+#define DDR_PHY_REGF0		0x3c0
+#define DDR_PHY_REGF1		0x3c4
+#define DDR_PHY_REGF2		0x3c8
+#define DDR_PHY_REGFA		0x3e8
+#define DDR_PHY_REGFB		0x3ec
+#define DDR_PHY_REGFC		0x3f0
+#define DDR_PHY_REGFD		0x3f4
+#define DDR_PHY_REGFE		0x3f8
+#define DDR_PHY_REGFF		0x3fc
+
+/* MSCH REG define */
+#define MSCH_COREID			0x0
+#define MSCH_DDRCONF		0x8
+#define MSCH_DDRTIMING		0xc
+#define MSCH_DDRMODE		0x10
+#define MSCH_READLATENCY	0x14
+#define MSCH_ACTIVATE		0x38
+#define MSCH_DEVTODEV		0x3c
+
+#define SET_NR(n)      ((0x3f << (8 + 16)) | ((n - 1) << 8))
+#define SET_NO(n)      ((0xf << (0 + 16)) | ((n - 1) << 0))
+#define SET_NF(n)      ((n - 1) & 0x1fff)
+#define SET_NB(n)      ((n - 1) & 0xfff)
+#define PLLMODE(n)     ((0x3 << (8 + 16)) | (n << 8))
+
+/* GRF REG define */
+#define GRF_SOC_STATUS0		0x480
+#define GRF_DDRPHY_LOCK		(0x1 << 15)
+#define GRF_DDRC0_CON0		0x600
+
+/* CRU softreset ddr pctl, phy */
+#define DDRMSCH0_SRSTN_REQ(n)  (((0x1 << 10) << 16) | (n << 10))
+#define DDRCTRL0_PSRSTN_REQ(n) (((0x1 << 3) << 16) | (n << 3))
+#define DDRCTRL0_SRSTN_REQ(n)  (((0x1 << 2) << 16) | (n << 2))
+#define DDRPHY0_PSRSTN_REQ(n)  (((0x1 << 1) << 16) | (n << 1))
+#define DDRPHY0_SRSTN_REQ(n)   (((0x1 << 0) << 16) | (n << 0))
+
+/* CRU_DPLL_CON2 */
+#define DPLL_STATUS_LOCK		(1U << 31)
+
+/* CRU_DPLL_CON3 */
+#define DPLL_POWER_DOWN			((0x1 << (1 + 16)) | (0 << 1))
+#define DPLL_WORK_NORMAL_MODE		((0x3 << (8 + 16)) | (0 << 8))
+#define DPLL_WORK_SLOW_MODE		((0x3 << (8 + 16)) | (1 << 8))
+#define DPLL_RESET_CONTROL_NORMAL	((0x1 << (5 + 16)) | (0x0 << 5))
+#define DPLL_RESET_CONTROL_RESET	((0x1 << (5 + 16)) | (0x1 << 5))
+
+/* PMU_PWRDN_CON */
+#define PD_PERI_PWRDN_ENABLE		(1 << 13)
+
+#define DDR_PLL_SRC_MASK		0x13
+
+/* DDR_PCTL_TREFI */
+#define DDR_UPD_REF_ENABLE		(0X1u << 31)
+
+uint32_t ddr_get_resume_code_size(void);
+uint32_t ddr_get_resume_data_size(void);
+uint32_t *ddr_get_resume_code_base(void);
+void ddr_reg_save(uint32_t pllpdstat, uint64_t base_addr);
+
+#endif /* DDR_RK3368_H */
diff --git a/plat/rockchip/rk3368/drivers/ddr/rk3368_ddr_reg_resume_V1.05.bin b/plat/rockchip/rk3368/drivers/ddr/rk3368_ddr_reg_resume_V1.05.bin
new file mode 100644
index 0000000..cecd694
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/ddr/rk3368_ddr_reg_resume_V1.05.bin
@@ -0,0 +1,461 @@
+	0x14000088,
+	0xd10043ff,
+	0x5283ffe1,
+	0x52824902,
+	0x1b020400,
+	0x530d7c00,
+	0xb9000fe0,
+	0xb9400fe0,
+	0x340000a0,
+	0xb9400fe0,
+	0x51000401,
+	0xb9000fe1,
+	0x35ffffa0,
+	0x910043ff,
+	0xd65f03c0,
+	0x340000e2,
+	0xb9400023,
+	0xb9000003,
+	0x91001021,
+	0x91001000,
+	0x51000442,
+	0x35ffff62,
+	0xd65f03c0,
+	0xd10043ff,
+	0xb9400801,
+	0x12000821,
+	0xb9000fe1,
+	0xb9400fe1,
+	0x7100043f,
+	0x54000320,
+	0x52800021,
+	0x52800082,
+	0xb9400fe3,
+	0x34000143,
+	0x71000c7f,
+	0x54000100,
+	0x7100147f,
+	0x54000161,
+	0xb9000402,
+	0xb9400803,
+	0x12000863,
+	0x71000c7f,
+	0x54ffffa1,
+	0xb9000401,
+	0xb9400803,
+	0x12000863,
+	0x7100047f,
+	0x54ffffa1,
+	0xb9400803,
+	0x12000863,
+	0xb9000fe3,
+	0xb9400fe3,
+	0x7100047f,
+	0x54fffd61,
+	0x910043ff,
+	0xd65f03c0,
+	0xd10043ff,
+	0xb9400801,
+	0x12000821,
+	0xb9000fe1,
+	0xb9400fe1,
+	0x7100143f,
+	0x54000400,
+	0x52800021,
+	0x52800042,
+	0x52800063,
+	0xb9400fe4,
+	0x340000c4,
+	0x7100049f,
+	0x54000120,
+	0x71000c9f,
+	0x54000180,
+	0x14000010,
+	0xb9000401,
+	0xb9400804,
+	0x12000884,
+	0x7100049f,
+	0x54ffffa1,
+	0xb9000402,
+	0xb9400804,
+	0x12000884,
+	0x71000c9f,
+	0x54ffffa1,
+	0xb9000403,
+	0xb9400804,
+	0x12000884,
+	0x7100149f,
+	0x54ffffa1,
+	0xb9400804,
+	0x12000884,
+	0xb9000fe4,
+	0xb9400fe4,
+	0x7100149f,
+	0x54fffca1,
+	0x910043ff,
+	0xd65f03c0,
+	0xd10043ff,
+	0xb9400801,
+	0x12000821,
+	0xb9000fe1,
+	0xb9400fe1,
+	0x71000c3f,
+	0x54000400,
+	0x52800021,
+	0x52800042,
+	0x52800083,
+	0xb9400fe4,
+	0x34000164,
+	0x7100049f,
+	0x540001c0,
+	0x7100149f,
+	0x54000221,
+	0xb9000403,
+	0xb9400804,
+	0x12000884,
+	0x71000c9f,
+	0x54ffffa1,
+	0x1400000b,
+	0xb9000401,
+	0xb9400804,
+	0x12000884,
+	0x7100049f,
+	0x54ffffa1,
+	0xb9000402,
+	0xb9400804,
+	0x12000884,
+	0x71000c9f,
+	0x54ffffa1,
+	0xb9400804,
+	0x12000884,
+	0xb9000fe4,
+	0xb9400fe4,
+	0x71000c9f,
+	0x54fffca1,
+	0x910043ff,
+	0xd65f03c0,
+	0xd10103ff,
+	0xa9037bfd,
+	0x9100c3fd,
+	0xa9025ff6,
+	0xa90157f4,
+	0xf90007f3,
+	0xaa0003f3,
+	0xb9400674,
+	0xb9411276,
+	0xb941c660,
+	0xb941aa75,
+	0x7100041f,
+	0x54000261,
+	0xb9418e60,
+	0x321f0000,
+	0xb903b6c0,
+	0xb9418a60,
+	0xb903b2c0,
+	0xb9419260,
+	0xb903bac0,
+	0xb9418e60,
+	0x121e7800,
+	0xb903b6c0,
+	0xb941ca60,
+	0xb941ce61,
+	0xb941d262,
+	0xb9400003,
+	0xa030023,
+	0x6b22407f,
+	0x54ffffa0,
+	0x1400003b,
+	0xb941d660,
+	0x7100041f,
+	0x54000701,
+	0xb941da60,
+	0x3100041f,
+	0x54000080,
+	0xb941de61,
+	0x53007c00,
+	0xb9000001,
+	0xb941e660,
+	0x3100041f,
+	0x54000080,
+	0xb941ea61,
+	0x53007c00,
+	0xb9000001,
+	0xb941f260,
+	0x3100041f,
+	0x54000120,
+	0xaa1f03e1,
+	0x53007c00,
+	0x9107d262,
+	0xb8616843,
+	0xb8216803,
+	0x91001021,
+	0xf100203f,
+	0x54ffff81,
+	0x52800020,
+	0x97ffff3f,
+	0xb941e660,
+	0x3100041f,
+	0x54000080,
+	0xb941ee61,
+	0x53007c00,
+	0xb9000001,
+	0x52800020,
+	0x97ffff37,
+	0xb9420660,
+	0x3100041f,
+	0x54000100,
+	0xb9420a61,
+	0xb9420e62,
+	0x53007c00,
+	0xb9400003,
+	0xa030023,
+	0x6b22407f,
+	0x54ffffa1,
+	0xb9421260,
+	0x3100041f,
+	0x54000080,
+	0xb9421661,
+	0x53007c00,
+	0xb9000001,
+	0xb941da60,
+	0x3100041f,
+	0x54000080,
+	0xb941e261,
+	0x53007c00,
+	0xb9000001,
+	0xb9419660,
+	0xb903bec0,
+	0xb9422a60,
+	0x34000400,
+	0xb9422e61,
+	0x53007c17,
+	0xb90002e1,
+	0x52800140,
+	0x97ffff18,
+	0xb9423260,
+	0xb90002e0,
+	0x52800140,
+	0x97ffff14,
+	0xb9423660,
+	0xb90002e0,
+	0x52800140,
+	0x97ffff10,
+	0xb9423a60,
+	0x34000220,
+	0x53007c17,
+	0xb94002e0,
+	0x121c7400,
+	0xb90002e0,
+	0x52800020,
+	0x97ffff08,
+	0xb94002e0,
+	0x321e0000,
+	0xb90002e0,
+	0x528000a0,
+	0x97ffff03,
+	0xb94002e0,
+	0x321d0000,
+	0xb90002e0,
+	0x52800020,
+	0x97fffefe,
+	0xb9412a60,
+	0xb9004ec0,
+	0xb9412e60,
+	0xb90052c0,
+	0xb9413e60,
+	0xb9009ac0,
+	0xb9414260,
+	0xb9009ec0,
+	0xb9415260,
+	0xb900dac0,
+	0xb9415660,
+	0xb900dec0,
+	0xb9416660,
+	0xb9011ac0,
+	0xb9416a60,
+	0xb9011ec0,
+	0xb9417a60,
+	0xb9015ac0,
+	0xb9417e60,
+	0xb9015ec0,
+	0xb9418660,
+	0xb90292c0,
+	0xb9414660,
+	0xb900a2c0,
+	0xb9415a60,
+	0xb900e2c0,
+	0xb9416e60,
+	0xb90122c0,
+	0xb9418260,
+	0xb90162c0,
+	0xb9411660,
+	0xb90002c0,
+	0xb9411a60,
+	0xb90006c0,
+	0xb9411e60,
+	0xb9002ec0,
+	0xb9412260,
+	0xb90032c0,
+	0xb9412660,
+	0xb90046c0,
+	0xb9413260,
+	0xb9005ac0,
+	0xb9413660,
+	0xb90082c0,
+	0xb9413a60,
+	0xb90086c0,
+	0xb9414a60,
+	0xb900c2c0,
+	0xb9414e60,
+	0xb900c6c0,
+	0xb9415e60,
+	0xb90102c0,
+	0xb9416260,
+	0xb90106c0,
+	0xb9417260,
+	0xb90142c0,
+	0xb9417660,
+	0xb90146c0,
+	0x52800040,
+	0xb9000ac0,
+	0xb9411261,
+	0xb9419a60,
+	0xb900b020,
+	0xb9419a60,
+	0xb900b420,
+	0xb9419e60,
+	0xb900f020,
+	0xb9419e60,
+	0xb900f420,
+	0xb941a260,
+	0xb9013020,
+	0xb941a260,
+	0xb9013420,
+	0xb941a660,
+	0xb9017020,
+	0xb941a662,
+	0xaa1f03e0,
+	0xb9017422,
+	0x91008261,
+	0xb8606822,
+	0x8b000283,
+	0xb900c062,
+	0x91001000,
+	0xf102301f,
+	0x54ffff61,
+	0xb9400a60,
+	0xb9000280,
+	0xb9400e60,
+	0xb9005280,
+	0xb9401260,
+	0xb9007e80,
+	0xb9401660,
+	0xb9008280,
+	0xb9401a60,
+	0xb9008680,
+	0xb940ae60,
+	0xb9024280,
+	0xb940b260,
+	0xb9024680,
+	0xb940b660,
+	0xb9024a80,
+	0xb940ba60,
+	0xb9024e80,
+	0xb940be60,
+	0xb9025280,
+	0xb940c260,
+	0xb9025680,
+	0xb940c660,
+	0xb9025a80,
+	0xb940ca60,
+	0xb9026280,
+	0xb940ce60,
+	0xb9026680,
+	0xb940d260,
+	0xb9027280,
+	0xb940d660,
+	0xb9027680,
+	0xb940da60,
+	0xb9027a80,
+	0xb940de60,
+	0xb9027e80,
+	0xb940e260,
+	0xb9028280,
+	0xb940e660,
+	0xb9028680,
+	0xb940ea60,
+	0xb9028a80,
+	0xb940ee60,
+	0xb9029280,
+	0xb940f260,
+	0xb9029680,
+	0xb940f660,
+	0xb9029a80,
+	0xb940fa60,
+	0xb902c680,
+	0xb940fe60,
+	0xb902ca80,
+	0xb9410260,
+	0xb902d280,
+	0xb9410660,
+	0xb902d680,
+	0xb9410a60,
+	0xb902da80,
+	0xb9410e60,
+	0xb902f280,
+	0xb9422260,
+	0x3100041f,
+	0x540000c0,
+	0xb9422661,
+	0x53007c00,
+	0xb9000001,
+	0x52800020,
+	0x97fffe65,
+	0x52800020,
+	0xb9004680,
+	0xb9404a80,
+	0x3607ffe0,
+	0xb941ae60,
+	0xb9000aa0,
+	0xb941b260,
+	0xb9000ea0,
+	0xb941b660,
+	0xb90012a0,
+	0xb941ba60,
+	0xb90016a0,
+	0xb941be60,
+	0xb9003aa0,
+	0xb941c260,
+	0xb9003ea0,
+	0xb9422260,
+	0x3100041f,
+	0x54000080,
+	0x53007c00,
+	0x320083e1,
+	0xb9000001,
+	0xaa1403e0,
+	0x97fffe84,
+	0xb9421a60,
+	0x3100041f,
+	0x54000100,
+	0x53007c00,
+	0xb9421e61,
+	0xb9400002,
+	0x2a010041,
+	0xb9000001,
+	0x52800020,
+	0x97fffe43,
+	0xaa1403e0,
+	0x97fffea0,
+	0xb9422260,
+	0x3100041f,
+	0x54000080,
+	0x53007c00,
+	0x52a00021,
+	0xb9000001,
+	0xf94007f3,
+	0xa94157f4,
+	0xa9425ff6,
+	0xa9437bfd,
+	0x910103ff,
+	0xd65f03c0,
diff --git a/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..399f61c
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+.macro	func_rockchip_clst_warmboot
+	/* Nothing to do for rk3368 */
+.endm
+
+.macro rockchip_clst_warmboot_data
+	/* Nothing to do for rk3368 */
+.endm
diff --git a/plat/rockchip/rk3368/drivers/pmu/pmu.c b/plat/rockchip/rk3368/drivers/pmu/pmu.c
new file mode 100644
index 0000000..e277a18
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/pmu/pmu.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <ddr_rk3368.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <rk3368_def.h>
+#include <soc.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+
+static uint32_t cpu_warm_boot_addr;
+
+void rk3368_flash_l2_b(void)
+{
+	uint32_t wait_cnt = 0;
+
+	regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_l2flsh_clst_b);
+	dsb();
+
+	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST)
+		& BIT(clst_b_l2_flsh_done))) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			WARN("%s:reg %x,wait\n", __func__,
+			     mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
+	}
+
+	regs_updata_bit_clr(PMU_BASE + PMU_SFT_CON, pmu_sft_l2flsh_clst_b);
+}
+
+static inline int rk3368_pmu_bus_idle(uint32_t req, uint32_t idle)
+{
+	uint32_t mask = BIT(req);
+	uint32_t idle_mask = 0;
+	uint32_t idle_target = 0;
+	uint32_t val;
+	uint32_t wait_cnt = 0;
+
+	switch (req) {
+	case bus_ide_req_clst_l:
+		idle_mask = BIT(pmu_idle_ack_cluster_l);
+		idle_target = (idle << pmu_idle_ack_cluster_l);
+		break;
+
+	case bus_ide_req_clst_b:
+		idle_mask = BIT(pmu_idle_ack_cluster_b);
+		idle_target = (idle << pmu_idle_ack_cluster_b);
+		break;
+
+	case bus_ide_req_cxcs:
+		idle_mask = BIT(pmu_idle_ack_cxcs);
+		idle_target = ((!idle) << pmu_idle_ack_cxcs);
+		break;
+
+	case bus_ide_req_cci400:
+		idle_mask = BIT(pmu_idle_ack_cci400);
+		idle_target = ((!idle) << pmu_idle_ack_cci400);
+		break;
+
+	case bus_ide_req_gpu:
+		idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu);
+		idle_target = (idle << pmu_idle_ack_gpu) |
+			      (idle << pmu_idle_gpu);
+		break;
+
+	case bus_ide_req_core:
+		idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core);
+		idle_target = (idle << pmu_idle_ack_core) |
+			      (idle << pmu_idle_core);
+		break;
+
+	case bus_ide_req_bus:
+		idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus);
+		idle_target = (idle << pmu_idle_ack_bus) |
+			      (idle << pmu_idle_bus);
+		break;
+	case bus_ide_req_dma:
+		idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma);
+		idle_target = (idle << pmu_idle_ack_dma) |
+			      (idle << pmu_idle_dma);
+		break;
+
+	case bus_ide_req_peri:
+		idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri);
+		idle_target = (idle << pmu_idle_ack_peri) |
+			      (idle << pmu_idle_peri);
+		break;
+
+	case bus_ide_req_video:
+		idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video);
+		idle_target = (idle << pmu_idle_ack_video) |
+			      (idle << pmu_idle_video);
+		break;
+
+	case bus_ide_req_vio:
+		idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio);
+		idle_target = (pmu_idle_ack_vio) |
+			      (idle << pmu_idle_vio);
+		break;
+
+	case bus_ide_req_alive:
+		idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive);
+		idle_target = (idle << pmu_idle_ack_alive) |
+			      (idle << pmu_idle_alive);
+		break;
+
+	case bus_ide_req_pmu:
+		idle_mask = BIT(pmu_idle_ack_pmu) | BIT(pmu_idle_pmu);
+		idle_target = (idle << pmu_idle_ack_pmu) |
+			      (idle << pmu_idle_pmu);
+		break;
+
+	case bus_ide_req_msch:
+		idle_mask = BIT(pmu_idle_ack_msch) | BIT(pmu_idle_msch);
+		idle_target = (idle << pmu_idle_ack_msch) |
+			      (idle << pmu_idle_msch);
+		break;
+
+	case bus_ide_req_cci:
+		idle_mask = BIT(pmu_idle_ack_cci) | BIT(pmu_idle_cci);
+		idle_target = (idle << pmu_idle_ack_cci) |
+			      (idle << pmu_idle_cci);
+		break;
+
+	default:
+		ERROR("%s: Unsupported the idle request\n", __func__);
+		break;
+	}
+
+	val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ);
+	if (idle)
+		val |=	mask;
+	else
+		val &= ~mask;
+
+	mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val);
+
+	while ((mmio_read_32(PMU_BASE +
+	       PMU_BUS_IDE_ST) & idle_mask) != idle_target) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			WARN("%s:st=%x(%x)\n", __func__,
+			     mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST),
+			     idle_mask);
+	}
+
+	return 0;
+}
+
+void pmu_scu_b_pwrup(void)
+{
+	regs_updata_bit_clr(PMU_BASE + PMU_SFT_CON, pmu_sft_acinactm_clst_b);
+	rk3368_pmu_bus_idle(bus_ide_req_clst_b, 0);
+}
+
+static void pmu_scu_b_pwrdn(void)
+{
+	uint32_t wait_cnt = 0;
+
+	if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) &
+	     PM_PWRDM_CPUSB_MSK) != PM_PWRDM_CPUSB_MSK) {
+		ERROR("%s: not all cpus is off\n", __func__);
+		return;
+	}
+
+	rk3368_flash_l2_b();
+
+	regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_acinactm_clst_b);
+
+	while (!(mmio_read_32(PMU_BASE +
+	       PMU_CORE_PWR_ST) & BIT(clst_b_l2_wfi))) {
+		wait_cnt++;
+		if (!(wait_cnt % MAX_WAIT_CONUT))
+			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
+			      mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
+	}
+	rk3368_pmu_bus_idle(bus_ide_req_clst_b, 1);
+}
+
+static void pmu_sleep_mode_config(void)
+{
+	uint32_t pwrmd_core, pwrmd_com;
+
+	pwrmd_core = BIT(pmu_mdcr_cpu0_pd) |
+		     BIT(pmu_mdcr_scu_l_pd) |
+		     BIT(pmu_mdcr_l2_flush) |
+		     BIT(pmu_mdcr_l2_idle) |
+		     BIT(pmu_mdcr_clr_clst_l) |
+		     BIT(pmu_mdcr_clr_core) |
+		     BIT(pmu_mdcr_clr_cci) |
+		     BIT(pmu_mdcr_core_pd);
+
+	pwrmd_com = BIT(pmu_mode_en) |
+		    BIT(pmu_mode_sref_enter) |
+		    BIT(pmu_mode_pwr_off);
+
+	regs_updata_bit_set(PMU_BASE + PMU_WKUP_CFG2, pmu_cluster_l_wkup_en);
+	regs_updata_bit_set(PMU_BASE + PMU_WKUP_CFG2, pmu_cluster_b_wkup_en);
+	regs_updata_bit_clr(PMU_BASE + PMU_WKUP_CFG2, pmu_gpio_wkup_en);
+
+	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_24M_CNT_MS(2));
+	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT, CYCL_24M_CNT_US(100));
+	mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_24M_CNT_MS(2));
+	mmio_write_32(PMU_BASE + PMU_PWRMD_CORE, pwrmd_core);
+	mmio_write_32(PMU_BASE + PMU_PWRMD_COM, pwrmd_com);
+	dsb();
+}
+
+static void pmu_set_sleep_mode(void)
+{
+	pmu_sleep_mode_config();
+	soc_sleep_config();
+	regs_updata_bit_set(PMU_BASE + PMU_PWRMD_CORE, pmu_mdcr_global_int_dis);
+	regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_glbl_int_dis_b);
+	pmu_scu_b_pwrdn();
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2),
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
+}
+
+static int cpus_id_power_domain(uint32_t cluster,
+				uint32_t cpu,
+				uint32_t pd_state,
+				uint32_t wfie_msk)
+{
+	uint32_t pd;
+	uint64_t mpidr;
+
+	if (cluster)
+		pd = PD_CPUB0 + cpu;
+	else
+		pd = PD_CPUL0 + cpu;
+
+	if (pmu_power_domain_st(pd) == pd_state)
+		return 0;
+
+	if (pd_state == pmu_pd_off) {
+		mpidr = (cluster << MPIDR_AFF1_SHIFT) | cpu;
+		if (check_cpu_wfie(mpidr, wfie_msk))
+			return -EINVAL;
+	}
+
+	return pmu_power_domain_ctr(pd, pd_state);
+}
+
+static void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, boot_cluster, cpu;
+
+	boot_cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
+	boot_cluster = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
+
+	/* turn off noboot cpus */
+	for (cpu = 0; cpu < PLATFORM_CLUSTER0_CORE_COUNT; cpu++) {
+		if (!boot_cluster && (cpu == boot_cpu))
+			continue;
+		cpus_id_power_domain(0, cpu, pmu_pd_off, CKECK_WFEI_MSK);
+	}
+
+	for (cpu = 0; cpu < PLATFORM_CLUSTER1_CORE_COUNT; cpu++) {
+		if (boot_cluster && (cpu == boot_cpu))
+			continue;
+		cpus_id_power_domain(1, cpu, pmu_pd_off, CKECK_WFEI_MSK);
+	}
+}
+
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3368 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3368 SoCs */
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	uint32_t cpu, cluster;
+	uint32_t cpuon_id;
+
+	cpu = MPIDR_AFFLVL0_VAL(mpidr);
+	cluster = MPIDR_AFFLVL1_VAL(mpidr);
+
+	/* Make sure the cpu is off,Before power up the cpu! */
+	cpus_id_power_domain(cluster, cpu, pmu_pd_off, CKECK_WFEI_MSK);
+
+	cpuon_id = (cluster * PLATFORM_CLUSTER0_CORE_COUNT) + cpu;
+	assert(cpuon_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpuon_id] == 0);
+	cpuson_flags[cpuon_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpuon_id] = entrypoint;
+
+	/* Switch boot addr to pmusram */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1 + cluster),
+		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+	dsb();
+
+	cpus_id_power_domain(cluster, cpu, pmu_pd_on, CKECK_WFEI_MSK);
+
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1 + cluster),
+		      (COLD_BOOT_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+
+	return 0;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      (COLD_BOOT_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2),
+		      (COLD_BOOT_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+	pm_plls_resume();
+	pmu_scu_b_pwrup();
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	nonboot_cpus_off();
+	pmu_set_sleep_mode();
+
+	return 0;
+}
+
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for rk3368 SoCs */
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	uint32_t cpu;
+
+	/* register requires 32bits mode, switch it to 32 bits */
+	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
+
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = 0;
+
+	nonboot_cpus_off();
+	INFO("%s(%d): pd status %x\n", __func__, __LINE__,
+	     mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
+}
diff --git a/plat/rockchip/rk3368/drivers/pmu/pmu.h b/plat/rockchip/rk3368/drivers/pmu/pmu.h
new file mode 100644
index 0000000..b4d4807
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/pmu/pmu.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+/* Allocate sp reginon in pmusram */
+#define PSRAM_SP_SIZE		0x80
+#define PSRAM_SP_BOTTOM		(PSRAM_SP_TOP - PSRAM_SP_SIZE)
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WKUP_CFG0		0x0
+#define PMU_WKUP_CFG1		0x4
+#define PMU_WKUP_CFG2		0x8
+#define PMU_TIMEOUT_CNT		0x7c
+#define PMU_PWRDN_CON		0xc
+#define PMU_PWRDN_ST		0x10
+#define PMU_CORE_PWR_ST		0x38
+
+#define PMU_PWRMD_CORE		0x14
+#define PMU_PWRMD_COM		0x18
+#define PMU_SFT_CON			0x1c
+#define PMU_BUS_IDE_REQ		0x3c
+#define PMU_BUS_IDE_ST		0x40
+#define PMU_OSC_CNT			0x48
+#define PMU_PLLLOCK_CNT		0x4c
+#define PMU_PLLRST_CNT		0x50
+#define PMU_STABLE_CNT		0x54
+#define PMU_DDRIO_PWR_CNT	0x58
+#define PMU_WKUPRST_CNT		0x5c
+
+enum pmu_powermode_core {
+	pmu_mdcr_global_int_dis = 0,
+	pmu_mdcr_core_src_gt,
+	pmu_mdcr_clr_cci,
+	pmu_mdcr_cpu0_pd,
+	pmu_mdcr_clr_clst_l = 4,
+	pmu_mdcr_clr_core,
+	pmu_mdcr_scu_l_pd,
+	pmu_mdcr_core_pd,
+	pmu_mdcr_l2_idle = 8,
+	pmu_mdcr_l2_flush
+};
+
+/*
+ * the shift of bits for cores status
+ */
+enum pmu_core_pwrst_shift {
+	clstl_cpu_wfe = 2,
+	clstl_cpu_wfi = 6,
+	clstb_cpu_wfe = 12,
+	clstb_cpu_wfi = 16
+};
+
+enum pmu_pdid {
+	PD_CPUL0 = 0,
+	PD_CPUL1,
+	PD_CPUL2,
+	PD_CPUL3,
+	PD_SCUL,
+	PD_CPUB0 = 5,
+	PD_CPUB1,
+	PD_CPUB2,
+	PD_CPUB3,
+	PD_SCUB = 9,
+	PD_PERI = 13,
+	PD_VIDEO,
+	PD_VIO,
+	PD_GPU0,
+	PD_GPU1,
+	PD_END
+};
+
+enum pmu_bus_ide {
+	bus_ide_req_clst_l = 0,
+	bus_ide_req_clst_b,
+	bus_ide_req_gpu,
+	bus_ide_req_core,
+	bus_ide_req_bus = 4,
+	bus_ide_req_dma,
+	bus_ide_req_peri,
+	bus_ide_req_video,
+	bus_ide_req_vio = 8,
+	bus_ide_req_res0,
+	bus_ide_req_cxcs,
+	bus_ide_req_alive,
+	bus_ide_req_pmu = 12,
+	bus_ide_req_msch,
+	bus_ide_req_cci,
+	bus_ide_req_cci400 = 15,
+	bus_ide_req_end
+};
+
+enum pmu_powermode_common {
+	pmu_mode_en = 0,
+	pmu_mode_res0,
+	pmu_mode_bus_pd,
+	pmu_mode_wkup_rst,
+	pmu_mode_pll_pd = 4,
+	pmu_mode_pwr_off,
+	pmu_mode_pmu_use_if,
+	pmu_mode_pmu_alive_use_if,
+	pmu_mode_osc_dis = 8,
+	pmu_mode_input_clamp,
+	pmu_mode_sref_enter,
+	pmu_mode_ddrc_gt,
+	pmu_mode_ddrio_ret = 12,
+	pmu_mode_ddrio_ret_deq,
+	pmu_mode_clr_pmu,
+	pmu_mode_clr_alive,
+	pmu_mode_clr_bus = 16,
+	pmu_mode_clr_dma,
+	pmu_mode_clr_msch,
+	pmu_mode_clr_peri,
+	pmu_mode_clr_video = 20,
+	pmu_mode_clr_vio,
+	pmu_mode_clr_gpu,
+	pmu_mode_clr_mcu,
+	pmu_mode_clr_cxcs = 24,
+	pmu_mode_clr_cci400,
+	pmu_mode_res1,
+	pmu_mode_res2,
+	pmu_mode_res3 = 28,
+	pmu_mode_mclst
+};
+
+enum pmu_core_power_st {
+	clst_l_cpu_wfe = 2,
+	clst_l_cpu_wfi = 6,
+	clst_b_l2_flsh_done = 10,
+	clst_b_l2_wfi = 11,
+	clst_b_cpu_wfe = 12,
+	clst_b_cpu_wfi = 16,
+	mcu_sleeping = 20,
+};
+
+enum pmu_sft_con {
+	pmu_sft_acinactm_clst_b = 5,
+	pmu_sft_l2flsh_clst_b,
+	pmu_sft_glbl_int_dis_b = 9,
+	pmu_sft_ddrio_ret_cfg = 11,
+};
+
+enum pmu_wkup_cfg2 {
+	pmu_cluster_l_wkup_en = 0,
+	pmu_cluster_b_wkup_en,
+	pmu_gpio_wkup_en,
+	pmu_sdio_wkup_en,
+	pmu_sdmmc_wkup_en,
+	pmu_sim_wkup_en,
+	pmu_timer_wkup_en,
+	pmu_usbdev_wkup_en,
+	pmu_sft_wkup_en,
+	pmu_wdt_mcu_wkup_en,
+	pmu_timeout_wkup_en,
+};
+
+enum pmu_bus_idle_st {
+	pmu_idle_ack_cluster_l = 0,
+	pmu_idle_ack_cluster_b,
+	pmu_idle_ack_gpu,
+	pmu_idle_ack_core,
+	pmu_idle_ack_bus,
+	pmu_idle_ack_dma,
+	pmu_idle_ack_peri,
+	pmu_idle_ack_video,
+	pmu_idle_ack_vio,
+	pmu_idle_ack_cci = 10,
+	pmu_idle_ack_msch,
+	pmu_idle_ack_alive,
+	pmu_idle_ack_pmu,
+	pmu_idle_ack_cxcs,
+	pmu_idle_ack_cci400,
+	pmu_inactive_cluster_l,
+	pmu_inactive_cluster_b,
+	pmu_idle_gpu,
+	pmu_idle_core,
+	pmu_idle_bus,
+	pmu_idle_dma,
+	pmu_idle_peri,
+	pmu_idle_video,
+	pmu_idle_vio,
+	pmu_idle_cci = 26,
+	pmu_idle_msch,
+	pmu_idle_alive,
+	pmu_idle_pmu,
+	pmu_active_cxcs,
+	pmu_active_cci,
+};
+
+#define PM_PWRDM_CPUSB_MSK (0xf << 5)
+
+#define CKECK_WFE_MSK		0x1
+#define CKECK_WFI_MSK		0x10
+#define CKECK_WFEI_MSK		0x11
+
+#define PD_CTR_LOOP		500
+#define CHK_CPU_LOOP		500
+
+#define MAX_WAIT_CONUT 1000
+
+#endif /* PMU_H */
diff --git a/plat/rockchip/rk3368/drivers/soc/soc.c b/plat/rockchip/rk3368/drivers/soc/soc.c
new file mode 100644
index 0000000..7d51bb8
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/soc/soc.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include <plat_private.h>
+#include <rk3368_def.h>
+#include <soc.h>
+
+static uint32_t plls_con[END_PLL_ID][4];
+
+/* Table of regions to map using the MMU. */
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(CCI400_BASE, CCI400_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(STIME_BASE, STIME_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMU_BASE, PMU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART0_BASE, UART0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART1_BASE, UART1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART2_BASE, UART2_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART3_BASE, UART3_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART4_BASE, UART4_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CRU_BASE, CRU_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PCTL_BASE, DDR_PCTL_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DDR_PHY_BASE, DDR_PHY_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GRF_BASE, GRF_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SISE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	/* No of children for the second cluster node */
+	PLATFORM_CLUSTER1_CORE_COUNT
+};
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_BASE + TIMER_LOADE_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_BASE + TIMER_LOADE_COUNT1, 0xffffffff);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN);
+}
+
+void sgrf_init(void)
+{
+	/* setting all configurable ip into no-secure */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SOC_CON_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), SGRF_SOC_CON7_BITS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7), SGRF_SOC_CON_NS);
+
+	/* secure dma to no sesure */
+	mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(0), SGRF_BUSDMAC_CON0_NS);
+	mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(1), SGRF_BUSDMAC_CON1_NS);
+	dsb();
+
+	/* rst dma1 */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1),
+		      RST_DMA1_MSK | (RST_DMA1_MSK << 16));
+	/* rst dma2 */
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4),
+		      RST_DMA2_MSK | (RST_DMA2_MSK << 16));
+
+	dsb();
+
+	/* release dma1 rst*/
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), (RST_DMA1_MSK << 16));
+	/* release dma2 rst*/
+	mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), (RST_DMA2_MSK << 16));
+}
+
+void plat_rockchip_soc_init(void)
+{
+	secure_timer_init();
+	sgrf_init();
+}
+
+void regs_updata_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift)
+{
+	uint32_t tmp, orig;
+
+	orig = mmio_read_32(addr);
+
+	tmp = orig & ~(mask << shift);
+	tmp |= (val & mask) << shift;
+
+	if (tmp != orig)
+		mmio_write_32(addr, tmp);
+	dsb();
+}
+
+static void plls_suspend(uint32_t pll_id)
+{
+	plls_con[pll_id][0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0));
+	plls_con[pll_id][1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1));
+	plls_con[pll_id][2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2));
+	plls_con[pll_id][3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3));
+
+	mmio_write_32(CRU_BASE + PLL_CONS((pll_id), 3), PLL_SLOW_BITS);
+	mmio_write_32(CRU_BASE + PLL_CONS((pll_id), 3), PLL_BYPASS);
+}
+
+static void pm_plls_suspend(void)
+{
+	plls_suspend(NPLL_ID);
+	plls_suspend(CPLL_ID);
+	plls_suspend(GPLL_ID);
+	plls_suspend(ABPLL_ID);
+	plls_suspend(ALPLL_ID);
+}
+
+static inline void plls_resume(void)
+{
+	mmio_write_32(CRU_BASE + PLL_CONS(ABPLL_ID, 3),
+		      plls_con[ABPLL_ID][3] | PLL_BYPASS_W_MSK);
+	mmio_write_32(CRU_BASE + PLL_CONS(ALPLL_ID, 3),
+		      plls_con[ALPLL_ID][3] | PLL_BYPASS_W_MSK);
+	mmio_write_32(CRU_BASE + PLL_CONS(GPLL_ID, 3),
+		      plls_con[GPLL_ID][3] | PLL_BYPASS_W_MSK);
+	mmio_write_32(CRU_BASE + PLL_CONS(CPLL_ID, 3),
+		      plls_con[CPLL_ID][3] | PLL_BYPASS_W_MSK);
+	mmio_write_32(CRU_BASE + PLL_CONS(NPLL_ID, 3),
+		      plls_con[NPLL_ID][3] | PLL_BYPASS_W_MSK);
+}
+
+void soc_sleep_config(void)
+{
+	int i = 0;
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 0xffff0000);
+	pm_plls_suspend();
+
+	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
+		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 0xffff0000);
+}
+
+void pm_plls_resume(void)
+{
+	plls_resume();
+
+	mmio_write_32(CRU_BASE + PLL_CONS(ABPLL_ID, 3),
+		      plls_con[ABPLL_ID][3] | PLLS_MODE_WMASK);
+	mmio_write_32(CRU_BASE + PLL_CONS(ALPLL_ID, 3),
+		      plls_con[ALPLL_ID][3] | PLLS_MODE_WMASK);
+	mmio_write_32(CRU_BASE + PLL_CONS(GPLL_ID, 3),
+		      plls_con[GPLL_ID][3] | PLLS_MODE_WMASK);
+	mmio_write_32(CRU_BASE + PLL_CONS(CPLL_ID, 3),
+		      plls_con[CPLL_ID][3] | PLLS_MODE_WMASK);
+	mmio_write_32(CRU_BASE + PLL_CONS(NPLL_ID, 3),
+		      plls_con[NPLL_ID][3] | PLLS_MODE_WMASK);
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	uint32_t temp_val;
+
+	mmio_write_32(CRU_BASE + PLL_CONS((GPLL_ID), 3), PLL_SLOW_BITS);
+	mmio_write_32(CRU_BASE + PLL_CONS((CPLL_ID), 3), PLL_SLOW_BITS);
+	mmio_write_32(CRU_BASE + PLL_CONS((NPLL_ID), 3), PLL_SLOW_BITS);
+	mmio_write_32(CRU_BASE + PLL_CONS((ABPLL_ID), 3), PLL_SLOW_BITS);
+	mmio_write_32(CRU_BASE + PLL_CONS((ALPLL_ID), 3), PLL_SLOW_BITS);
+
+	temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON) |
+		   PMU_RST_BY_SECOND_SFT;
+
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val);
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8);
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to excute valid codes.
+	 */
+	while (1)
+	;
+}
diff --git a/plat/rockchip/rk3368/drivers/soc/soc.h b/plat/rockchip/rk3368/drivers/soc/soc.h
new file mode 100644
index 0000000..6c7a01b
--- /dev/null
+++ b/plat/rockchip/rk3368/drivers/soc/soc.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+enum plls_id {
+	ABPLL_ID = 0,
+	ALPLL_ID,
+	DPLL_ID,
+	CPLL_ID,
+	GPLL_ID,
+	NPLL_ID,
+	END_PLL_ID,
+};
+
+/*****************************************************************************
+ * secure timer
+ *****************************************************************************/
+#define TIMER_LOADE_COUNT0	0x00
+#define TIMER_LOADE_COUNT1	0x04
+#define TIMER_CURRENT_VALUE0	0x08
+#define TIMER_CURRENT_VALUE1	0x0C
+#define TIMER_CONTROL_REG	0x10
+#define TIMER_INTSTATUS		0x18
+
+#define TIMER_EN		0x1
+
+#define STIMER1_BASE		(STIME_BASE + 0x20)
+
+#define CYCL_24M_CNT_US(us)	(24 * us)
+#define CYCL_24M_CNT_MS(ms)	(ms * CYCL_24M_CNT_US(1000))
+
+/*****************************************************************************
+ * sgrf reg, offset
+ *****************************************************************************/
+#define SGRF_SOC_CON(n)		(0x0 + (n) * 4)
+#define SGRF_BUSDMAC_CON(n)	(0x100 + (n) * 4)
+
+#define SGRF_SOC_CON_NS		0xffff0000
+
+/*****************************************************************************
+ * con6[2]pmusram is security.
+ * con6[6]stimer is security.
+ *****************************************************************************/
+#define PMUSRAM_S_SHIFT		2
+#define PMUSRAM_S		1
+#define STIMER_S_SHIFT		6
+#define STIMER_S		1
+#define SGRF_SOC_CON7_BITS	((0xffffu << 16) | \
+				 (PMUSRAM_S << PMUSRAM_S_SHIFT) | \
+				 (STIMER_S << STIMER_S_SHIFT))
+
+#define SGRF_BUSDMAC_CON0_NS	0xfffcfff8
+#define SGRF_BUSDMAC_CON1_NS	0xffff0fff
+
+/*
+ * sgrf_soc_con1~2, mask and offset
+ */
+#define CPU_BOOT_ADDR_WMASK	0xffff0000
+#define CPU_BOOT_ADDR_ALIGN	16
+
+/*****************************************************************************
+ * cru reg, offset
+ *****************************************************************************/
+#define CRU_SOFTRST_CON		0x300
+#define CRU_SOFTRSTS_CON(n)	(CRU_SOFTRST_CON + ((n) * 4))
+#define CRU_SOFTRSTS_CON_CNT	15
+
+#define SOFTRST_DMA1		0x40004
+#define SOFTRST_DMA2		0x10001
+
+#define RST_DMA1_MSK		0x4
+#define RST_DMA2_MSK		0x0
+
+#define CRU_CLKSEL_CON		0x100
+#define CRU_CLKSELS_CON(i)	(CRU_CLKSEL_CON + ((i) * 4))
+#define CRU_CLKSEL_CON_CNT	56
+
+#define CRU_CLKGATE_CON		0x200
+#define CRU_CLKGATES_CON(i)	(CRU_CLKGATE_CON + ((i) * 4))
+#define CRU_CLKGATES_CON_CNT	25
+
+#define CRU_GLB_SRST_FST	0x280
+#define CRU_GLB_SRST_SND	0x284
+#define CRU_GLB_RST_CON		0x388
+
+#define CRU_CONS_GATEID(i)	(16 * (i))
+#define GATE_ID(reg, bit)	((reg * 16) + bit)
+
+#define PMU_RST_BY_SECOND_SFT	(BIT(1) << 2)
+#define PMU_RST_NOT_BY_SFT	(BIT(1) << 2)
+
+/***************************************************************************
+ * pll
+ ***************************************************************************/
+#define PLL_PWR_DN_MSK		(0x1 << 1)
+#define PLL_PWR_DN		REG_WMSK_BITS(1, 1, 0x1)
+#define PLL_PWR_ON		REG_WMSK_BITS(0, 1, 0x1)
+#define PLL_RESET		REG_WMSK_BITS(1, 5, 0x1)
+#define PLL_RESET_RESUME	REG_WMSK_BITS(0, 5, 0x1)
+#define PLL_BYPASS_MSK		(0x1 << 0)
+#define PLL_BYPASS_W_MSK	(PLL_BYPASS_MSK << 16)
+#define PLL_BYPASS		REG_WMSK_BITS(1, 0, 0x1)
+#define PLL_NO_BYPASS		REG_WMSK_BITS(0, 0, 0x1)
+#define PLL_MODE_SHIFT		8
+#define PLL_MODE_MSK		0x3
+#define PLLS_MODE_WMASK		(PLL_MODE_MSK << (16 + PLL_MODE_SHIFT))
+#define PLL_SLOW		0x0
+#define PLL_NORM		0x1
+#define PLL_DEEP		0x2
+#define PLL_SLOW_BITS		REG_WMSK_BITS(PLL_SLOW, 8, 0x3)
+#define PLL_NORM_BITS		REG_WMSK_BITS(PLL_NORM, 8, 0x3)
+#define PLL_DEEP_BITS		REG_WMSK_BITS(PLL_DEEP, 8, 0x3)
+
+#define PLL_CONS(id, i)		((id) * 0x10 + ((i) * 4))
+
+#define REG_W_MSK(bits_shift, msk) \
+		((msk) << ((bits_shift) + 16))
+#define REG_VAL_CLRBITS(val, bits_shift, msk) \
+		(val & (~(msk << bits_shift)))
+#define REG_SET_BITS(bits, bits_shift, msk) \
+		(((bits) & (msk)) << (bits_shift))
+#define REG_WMSK_BITS(bits, bits_shift, msk) \
+		(REG_W_MSK(bits_shift, msk) | \
+		REG_SET_BITS(bits, bits_shift, msk))
+
+#define regs_updata_bit_set(addr, shift) \
+		regs_updata_bits((addr), 0x1, 0x1, (shift))
+#define regs_updata_bit_clr(addr, shift) \
+		regs_updata_bits((addr), 0x0, 0x1, (shift))
+
+void regs_updata_bits(uintptr_t addr, uint32_t val,
+		      uint32_t mask, uint32_t shift);
+void soc_sleep_config(void);
+void pm_plls_resume(void);
+
+#endif /* SOC_H */
diff --git a/plat/rockchip/rk3368/include/plat.ld.S b/plat/rockchip/rk3368/include/plat.ld.S
new file mode 100644
index 0000000..e9bb3a2
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat.ld.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_LD_S
+#define ROCKCHIP_PLAT_LD_S
+
+MEMORY {
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+
+	} >PMUSRAM
+}
+
+#endif /* ROCKCHIP_PLAT_LD_S */
diff --git a/plat/rockchip/rk3368/include/plat_sip_calls.h b/plat/rockchip/rk3368/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/rockchip/rk3368/include/platform_def.h b/plat/rockchip/rk3368/include/platform_def.h
new file mode 100644
index 0000000..7b3cc6e
--- /dev/null
+++ b/plat/rockchip/rk3368/include/platform_def.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <rk3368_def.h>
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x800
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	8
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		U(1)
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF txet, ro, rw, Size: 512KB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x80000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted RAM
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x10000)
+#define BL31_LIMIT	(TZRAM_BASE + TZRAM_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+#define MAX_XLAT_TABLES		8
+#define MAX_MMAP_REGIONS	16
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE	RK3368_GICD_BASE
+#define PLAT_RK_GICC_BASE	RK3368_GICC_BASE
+
+#define PLAT_RK_UART_BASE	UART2_BASE
+#define PLAT_RK_UART_CLOCK	RK3368_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE	RK3368_BAUDRATE
+
+#define PLAT_RK_CCI_BASE	CCI400_BASE
+
+#define PLAT_RK_PRIMARY_CPU	0x0
+
+#define PSRAM_DO_DDR_RESUME	0
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rockchip/rk3368/plat_sip_calls.c b/plat/rockchip/rk3368/plat_sip_calls.c
new file mode 100644
index 0000000..5918d58
--- /dev/null
+++ b/plat/rockchip/rk3368/plat_sip_calls.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+				   u_register_t x1,
+				   u_register_t x2,
+				   u_register_t x3,
+				   u_register_t x4,
+				   void *cookie,
+				   void *handle,
+				   u_register_t flags)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
new file mode 100644
index 0000000..8812378
--- /dev/null
+++ b/plat/rockchip/rk3368/platform.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RK_PLAT			:=	plat/rockchip
+RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON		:=	${RK_PLAT}/common
+
+DISABLE_BIN_GENERATION	:=	1
+
+PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/				\
+				-I${RK_PLAT_COMMON}/include/			\
+				-I${RK_PLAT_COMMON}/aarch64/			\
+				-I${RK_PLAT_COMMON}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/				\
+				-I${RK_PLAT_SOC}/drivers/pmu/			\
+				-I${RK_PLAT_SOC}/drivers/soc/			\
+				-I${RK_PLAT_SOC}/drivers/ddr/			\
+				-I${RK_PLAT_SOC}/include/
+
+RK_GIC_SOURCES         :=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				${RK_PLAT}/common/rockchip_gicv2.c
+
+PLAT_BL_COMMON_SOURCES	:=	lib/bl_aux_params/bl_aux_params.c		\
+				lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				plat/common/aarch64/crash_console_helpers.S	\
+				plat/common/plat_psci_common.c
+
+BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
+				drivers/arm/cci/cci.c				\
+				drivers/ti/uart/aarch64/16550_console.S		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				lib/cpus/aarch64/cortex_a53.S			\
+				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
+				${RK_PLAT_COMMON}/params_setup.c                \
+				${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S	\
+				${RK_PLAT_COMMON}/plat_pm.c			\
+				${RK_PLAT_COMMON}/plat_topology.c		\
+				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
+				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+				${RK_PLAT_SOC}/plat_sip_calls.c			\
+				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+				${RK_PLAT_SOC}/drivers/soc/soc.c		\
+				${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c		\
+
+include lib/coreboot/coreboot.mk
+include lib/libfdt/libfdt.mk
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
+
+WORKAROUND_CVE_2017_5715	:=	0
diff --git a/plat/rockchip/rk3368/rk3368_def.h b/plat/rockchip/rk3368/rk3368_def.h
new file mode 100644
index 0000000..4b0fbab
--- /dev/null
+++ b/plat/rockchip/rk3368/rk3368_def.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RK3368_DEF_H
+#define RK3368_DEF_H
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
+
+#define CCI400_BASE		0xffb90000
+#define CCI400_SIZE		0x10000
+
+#define GIC400_BASE		0xffb70000
+#define GIC400_SIZE		0x10000
+
+#define STIME_BASE		0xff830000
+#define STIME_SIZE		0x10000
+
+#define CRU_BASE		0xff760000
+#define CRU_SIZE		0x10000
+
+#define GRF_BASE		0xff770000
+#define GRF_SIZE		0x10000
+
+#define SGRF_BASE		0xff740000
+#define SGRF_SIZE		0x10000
+
+#define PMU_BASE		0xff730000
+#define PMU_GRF_BASE		0xff738000
+#define PMU_SIZE		0x10000
+
+#define RK_INTMEM_BASE		0xff8c0000
+#define RK_INTMEM_SIZE		0x10000
+
+#define UART0_BASE		0xff180000
+#define UART0_SIZE		0x10000
+
+#define UART1_BASE		0xff190000
+#define UART1_SIZE		0x10000
+
+#define UART2_BASE		0xff690000
+#define UART2_SIZE		0x10000
+
+#define UART3_BASE		0xff1b0000
+#define UART3_SIZE		0x10000
+
+#define UART4_BASE		0xff1c0000
+#define UART4_SIZE		0x10000
+
+#define CRU_BASE		0xff760000
+
+#define PMUSRAM_BASE            0xff720000
+#define PMUSRAM_SIZE            0x10000
+#define PMUSRAM_RSIZE           0x1000
+
+#define DDR_PCTL_BASE		0xff610000
+#define DDR_PCTL_SIZE		0x10000
+
+#define DDR_PHY_BASE		0xff620000
+#define DDR_PHY_SIZE		0x10000
+
+#define SERVICE_BUS_BASE	0xffac0000
+#define SERVICE_BUS_SISE	0x50000
+
+#define COLD_BOOT_BASE		0xffff0000
+/**************************************************************************
+ * UART related constants
+ **************************************************************************/
+#define RK3368_BAUDRATE		115200
+#define RK3368_UART_CLOCK	24000000
+
+/******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	24000000
+
+/******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base rk_platform compatible GIC memory map */
+#define RK3368_GICD_BASE		(GIC400_BASE + 0x1000)
+#define RK3368_GICC_BASE		(GIC400_BASE + 0x2000)
+#define RK3368_GICR_BASE		0	/* no GICR in GIC-400 */
+
+/*****************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX	3
+#define PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX	4
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define RK_IRQ_SEC_PHY_TIMER	29
+
+#define RK_IRQ_SEC_SGI_0	8
+#define RK_IRQ_SEC_SGI_1	9
+#define RK_IRQ_SEC_SGI_2	10
+#define RK_IRQ_SEC_SGI_3	11
+#define RK_IRQ_SEC_SGI_4	12
+#define RK_IRQ_SEC_SGI_5	13
+#define RK_IRQ_SEC_SGI_6	14
+#define RK_IRQ_SEC_SGI_7	15
+
+/*
+ * Define a list of Group 0 interrupts.
+ */
+#define PLAT_RK_GICV2_G0_IRQS						\
+	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+#endif /* RK3368_DEF_H */
diff --git a/plat/rockchip/rk3399/drivers/dp/cdn_dp.c b/plat/rockchip/rk3399/drivers/dp/cdn_dp.c
new file mode 100644
index 0000000..aa71fde
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dp/cdn_dp.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cdefs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <lib/smccc.h>
+
+#include <cdn_dp.h>
+
+__asm__(
+	".pushsection .text.hdcp_handler, \"ax\", %progbits\n"
+	".global hdcp_handler\n"
+	".balign 4\n"
+	"hdcp_handler:\n"
+	".incbin \"" __XSTRING(HDCPFW) "\"\n"
+	".type hdcp_handler, %function\n"
+	".size hdcp_handler, .- hdcp_handler\n"
+	".popsection\n"
+);
+
+static uint64_t *hdcp_key_pdata;
+static struct cdn_dp_hdcp_key_1x key;
+
+int hdcp_handler(struct cdn_dp_hdcp_key_1x *key);
+
+uint64_t dp_hdcp_ctrl(uint64_t type)
+{
+	switch (type) {
+	case HDCP_KEY_DATA_START_TRANSFER:
+		memset(&key, 0x00, sizeof(key));
+		hdcp_key_pdata = (uint64_t *)&key;
+		return 0;
+	case HDCP_KEY_DATA_START_DECRYPT:
+		if (hdcp_key_pdata == (uint64_t *)(&key + 1))
+			return hdcp_handler(&key);
+		else
+			return PSCI_E_INVALID_PARAMS;
+		assert(0); /* Unreachable */
+	default:
+		return SMC_UNK;
+	}
+}
+
+uint64_t dp_hdcp_store_key(uint64_t x1,
+			   uint64_t x2,
+			   uint64_t x3,
+			   uint64_t x4,
+			   uint64_t x5,
+			   uint64_t x6)
+{
+	if (hdcp_key_pdata < (uint64_t *)&key ||
+		hdcp_key_pdata + 6 > (uint64_t *)(&key + 1))
+		return PSCI_E_INVALID_PARAMS;
+
+	hdcp_key_pdata[0] = x1;
+	hdcp_key_pdata[1] = x2;
+	hdcp_key_pdata[2] = x3;
+	hdcp_key_pdata[3] = x4;
+	hdcp_key_pdata[4] = x5;
+	hdcp_key_pdata[5] = x6;
+	hdcp_key_pdata += 6;
+
+	return 0;
+}
diff --git a/plat/rockchip/rk3399/drivers/dp/cdn_dp.h b/plat/rockchip/rk3399/drivers/dp/cdn_dp.h
new file mode 100644
index 0000000..c5cbae2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dp/cdn_dp.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CDN_DP_H
+#define CDN_DP_H
+
+#include <plat_private.h>
+
+enum {
+	CDN_DP_HDCP_1X_KSV_LEN = 5,
+	CDN_DP_HDCP_KSV_LEN = 8,
+	CDN_DP_HDCP_RESERVED_LEN = 10,
+	CDN_DP_HDCP_UID_LEN = 16,
+	CDN_DP_HDCP_SHA_LEN = 20,
+	CDN_DP_HDCP_DPK_LEN = 280,
+	CDN_DP_HDCP_1X_KEYS_LEN	= 285,
+	CDN_DP_HDCP_KEY_LEN = 326,
+};
+
+struct cdn_dp_hdcp_key_1x {
+	uint8_t ksv[CDN_DP_HDCP_KSV_LEN];
+	uint8_t device_key[CDN_DP_HDCP_DPK_LEN];
+	uint8_t sha1[CDN_DP_HDCP_SHA_LEN];
+	uint8_t uid[CDN_DP_HDCP_UID_LEN];
+	uint16_t seed;
+	uint8_t reserved[CDN_DP_HDCP_RESERVED_LEN];
+};
+
+#define HDCP_KEY_DATA_START_TRANSFER	0
+#define HDCP_KEY_DATA_START_DECRYPT	1
+#define HDCP_KEY_1X_STORE_DATA_ALIGN_SIZE	(6 * 64) / 8
+
+/* Checks the cdn_dp_hdcp_key_1x must be aligned on 6 x 64-bit word boundary */
+CASSERT(sizeof(struct cdn_dp_hdcp_key_1x) % HDCP_KEY_1X_STORE_DATA_ALIGN_SIZE, \
+	assert_hdcp_key_1x_store_data_align_size_mismatch);
+
+uint64_t dp_hdcp_ctrl(uint64_t type);
+
+uint64_t dp_hdcp_store_key(uint64_t x1,
+			   uint64_t x2,
+			   uint64_t x3,
+			   uint64_t x4,
+			   uint64_t x5,
+			   uint64_t x6);
+
+#endif /* CDN_DP_H */
diff --git a/plat/rockchip/rk3399/drivers/dp/hdcp.bin b/plat/rockchip/rk3399/drivers/dp/hdcp.bin
new file mode 100644
index 0000000..28db923
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dp/hdcp.bin
Binary files differ
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
new file mode 100644
index 0000000..3b627d2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -0,0 +1,2114 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <m0_ctl.h>
+#include <plat_private.h>
+#include "dfs.h"
+#include "dram.h"
+#include "dram_spec_timing.h"
+#include "pmu.h"
+#include "soc.h"
+#include "string.h"
+
+#define ENPER_CS_TRAINING_FREQ	(666)
+#define TDFI_LAT_THRESHOLD_FREQ	(928)
+#define PHY_DLL_BYPASS_FREQ	(260)
+
+static const struct pll_div dpll_rates_table[] = {
+
+	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */
+	{.mhz = 928, .refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1},
+	{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1},
+	{.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1},
+	{.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1},
+	{.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2},
+};
+
+struct rk3399_dram_status {
+	uint32_t current_index;
+	uint32_t index_freq[2];
+	uint32_t boot_freq;
+	uint32_t low_power_stat;
+	struct timing_related_config timing_config;
+	struct drv_odt_lp_config drv_odt_lp_cfg;
+};
+
+struct rk3399_saved_status {
+	uint32_t freq;
+	uint32_t low_power_stat;
+	uint32_t odt;
+};
+
+static struct rk3399_dram_status rk3399_dram_status;
+static struct rk3399_saved_status rk3399_suspend_status;
+static uint32_t wrdqs_delay_val[2][2][4];
+static uint32_t rddqs_delay_ps;
+
+static struct rk3399_sdram_default_config ddr3_default_config = {
+	.bl = 8,
+	.ap = 0,
+	.burst_ref_cnt = 1,
+	.zqcsi = 0
+};
+
+static struct rk3399_sdram_default_config lpddr3_default_config = {
+	.bl = 8,
+	.ap = 0,
+	.burst_ref_cnt = 1,
+	.zqcsi = 0
+};
+
+static struct rk3399_sdram_default_config lpddr4_default_config = {
+	.bl = 16,
+	.ap = 0,
+	.caodt = 240,
+	.burst_ref_cnt = 1,
+	.zqcsi = 0
+};
+
+static uint32_t get_cs_die_capability(struct rk3399_sdram_params *sdram_config,
+		uint8_t channel, uint8_t cs)
+{
+	struct rk3399_sdram_channel *ch = &sdram_config->ch[channel];
+	uint32_t bandwidth;
+	uint32_t die_bandwidth;
+	uint32_t die;
+	uint32_t cs_cap;
+	uint32_t row;
+
+	row = cs == 0 ? ch->cs0_row : ch->cs1_row;
+	bandwidth = 8 * (1 << ch->bw);
+	die_bandwidth = 8 * (1 << ch->dbw);
+	die = bandwidth / die_bandwidth;
+	cs_cap = (1 << (row + ((1 << ch->bk) / 4 + 1) + ch->col +
+		  (bandwidth / 16)));
+	if (ch->row_3_4)
+		cs_cap = cs_cap * 3 / 4;
+
+	return (cs_cap / die);
+}
+
+static void get_dram_drv_odt_val(uint32_t dram_type,
+				struct drv_odt_lp_config *drv_config)
+{
+	uint32_t tmp;
+	uint32_t mr1_val, mr3_val, mr11_val;
+
+	switch (dram_type) {
+	case DDR3:
+		mr1_val = (mmio_read_32(CTL_REG(0, 133)) >> 16) & 0xffff;
+		tmp = ((mr1_val >> 1) & 1) | ((mr1_val >> 4) & 1);
+		if (tmp)
+			drv_config->dram_side_drv = 34;
+		else
+			drv_config->dram_side_drv = 40;
+		tmp = ((mr1_val >> 2) & 1) | ((mr1_val >> 5) & 1) |
+		      ((mr1_val >> 7) & 1);
+		if (tmp == 0)
+			drv_config->dram_side_dq_odt = 0;
+		else if (tmp == 1)
+			drv_config->dram_side_dq_odt = 60;
+		else if (tmp == 3)
+			drv_config->dram_side_dq_odt = 40;
+		else
+			drv_config->dram_side_dq_odt = 120;
+		break;
+	case LPDDR3:
+		mr3_val = mmio_read_32(CTL_REG(0, 138)) & 0xf;
+		mr11_val = (mmio_read_32(CTL_REG(0, 139)) >> 24) & 0x3;
+		if (mr3_val == 0xb)
+			drv_config->dram_side_drv = 3448;
+		else if (mr3_val == 0xa)
+			drv_config->dram_side_drv = 4048;
+		else if (mr3_val == 0x9)
+			drv_config->dram_side_drv = 3440;
+		else if (mr3_val == 0x4)
+			drv_config->dram_side_drv = 60;
+		else if (mr3_val == 0x3)
+			drv_config->dram_side_drv = 48;
+		else if (mr3_val == 0x2)
+			drv_config->dram_side_drv = 40;
+		else
+			drv_config->dram_side_drv = 34;
+
+		if (mr11_val == 1)
+			drv_config->dram_side_dq_odt = 60;
+		else if (mr11_val == 2)
+			drv_config->dram_side_dq_odt = 120;
+		else if (mr11_val == 0)
+			drv_config->dram_side_dq_odt = 0;
+		else
+			drv_config->dram_side_dq_odt = 240;
+		break;
+	case LPDDR4:
+	default:
+		mr3_val = (mmio_read_32(CTL_REG(0, 138)) >> 3) & 0x7;
+		mr11_val = (mmio_read_32(CTL_REG(0, 139)) >> 24) & 0xff;
+
+		if ((mr3_val == 0) || (mr3_val == 7))
+			drv_config->dram_side_drv = 40;
+		else
+			drv_config->dram_side_drv = 240 / mr3_val;
+
+		tmp = mr11_val & 0x7;
+		if ((tmp == 7) || (tmp == 0))
+			drv_config->dram_side_dq_odt = 0;
+		else
+			drv_config->dram_side_dq_odt = 240 / tmp;
+
+		tmp = (mr11_val >> 4) & 0x7;
+		if ((tmp == 7) || (tmp == 0))
+			drv_config->dram_side_ca_odt = 0;
+		else
+			drv_config->dram_side_ca_odt = 240 / tmp;
+		break;
+	}
+}
+
+static void sdram_timing_cfg_init(struct timing_related_config *ptiming_config,
+				  struct rk3399_sdram_params *sdram_params,
+				  struct drv_odt_lp_config *drv_config)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < sdram_params->num_channels; i++) {
+		ptiming_config->dram_info[i].speed_rate = DDR3_DEFAULT;
+		ptiming_config->dram_info[i].cs_cnt = sdram_params->ch[i].rank;
+		for (j = 0; j < sdram_params->ch[i].rank; j++) {
+			ptiming_config->dram_info[i].per_die_capability[j] =
+			    get_cs_die_capability(sdram_params, i, j);
+		}
+	}
+	ptiming_config->dram_type = sdram_params->dramtype;
+	ptiming_config->ch_cnt = sdram_params->num_channels;
+	switch (sdram_params->dramtype) {
+	case DDR3:
+		ptiming_config->bl = ddr3_default_config.bl;
+		ptiming_config->ap = ddr3_default_config.ap;
+		break;
+	case LPDDR3:
+		ptiming_config->bl = lpddr3_default_config.bl;
+		ptiming_config->ap = lpddr3_default_config.ap;
+		break;
+	case LPDDR4:
+		ptiming_config->bl = lpddr4_default_config.bl;
+		ptiming_config->ap = lpddr4_default_config.ap;
+		ptiming_config->rdbi = 0;
+		ptiming_config->wdbi = 0;
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+	ptiming_config->dramds = drv_config->dram_side_drv;
+	ptiming_config->dramodt = drv_config->dram_side_dq_odt;
+	ptiming_config->caodt = drv_config->dram_side_ca_odt;
+	ptiming_config->odt = (mmio_read_32(PHY_REG(0, 5)) >> 16) & 0x1;
+}
+
+struct lat_adj_pair {
+	uint32_t cl;
+	uint32_t rdlat_adj;
+	uint32_t cwl;
+	uint32_t wrlat_adj;
+};
+
+const struct lat_adj_pair ddr3_lat_adj[] = {
+	{6, 5, 5, 4},
+	{8, 7, 6, 5},
+	{10, 9, 7, 6},
+	{11, 9, 8, 7},
+	{13, 0xb, 9, 8},
+	{14, 0xb, 0xa, 9}
+};
+
+const struct lat_adj_pair lpddr3_lat_adj[] = {
+	{3, 2, 1, 0},
+	{6, 5, 3, 2},
+	{8, 7, 4, 3},
+	{9, 8, 5, 4},
+	{10, 9, 6, 5},
+	{11, 9, 6, 5},
+	{12, 0xa, 6, 5},
+	{14, 0xc, 8, 7},
+	{16, 0xd, 8, 7}
+};
+
+const struct lat_adj_pair lpddr4_lat_adj[] = {
+	{6, 5, 4, 2},
+	{10, 9, 6, 4},
+	{14, 0xc, 8, 6},
+	{20, 0x11, 0xa, 8},
+	{24, 0x15, 0xc, 0xa},
+	{28, 0x18, 0xe, 0xc},
+	{32, 0x1b, 0x10, 0xe},
+	{36, 0x1e, 0x12, 0x10}
+};
+
+static uint32_t get_rdlat_adj(uint32_t dram_type, uint32_t cl)
+{
+	const struct lat_adj_pair *p;
+	uint32_t cnt;
+	uint32_t i;
+
+	if (dram_type == DDR3) {
+		p = ddr3_lat_adj;
+		cnt = ARRAY_SIZE(ddr3_lat_adj);
+	} else if (dram_type == LPDDR3) {
+		p = lpddr3_lat_adj;
+		cnt = ARRAY_SIZE(lpddr3_lat_adj);
+	} else {
+		p = lpddr4_lat_adj;
+		cnt = ARRAY_SIZE(lpddr4_lat_adj);
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (cl == p[i].cl)
+			return p[i].rdlat_adj;
+	}
+	/* fail */
+	return 0xff;
+}
+
+static uint32_t get_wrlat_adj(uint32_t dram_type, uint32_t cwl)
+{
+	const struct lat_adj_pair *p;
+	uint32_t cnt;
+	uint32_t i;
+
+	if (dram_type == DDR3) {
+		p = ddr3_lat_adj;
+		cnt = ARRAY_SIZE(ddr3_lat_adj);
+	} else if (dram_type == LPDDR3) {
+		p = lpddr3_lat_adj;
+		cnt = ARRAY_SIZE(lpddr3_lat_adj);
+	} else {
+		p = lpddr4_lat_adj;
+		cnt = ARRAY_SIZE(lpddr4_lat_adj);
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (cwl == p[i].cwl)
+			return p[i].wrlat_adj;
+	}
+	/* fail */
+	return 0xff;
+}
+
+#define PI_REGS_DIMM_SUPPORT	(0)
+#define PI_ADD_LATENCY	(0)
+#define PI_DOUBLEFREEK	(1)
+
+#define PI_PAD_DELAY_PS_VALUE	(1000)
+#define PI_IE_ENABLE_VALUE	(3000)
+#define PI_TSEL_ENABLE_VALUE	(700)
+
+static uint32_t get_pi_rdlat_adj(struct dram_timing_t *pdram_timing)
+{
+	/*[DLLSUBTYPE2] == "STD_DENALI_HS" */
+	uint32_t rdlat, delay_adder, ie_enable, hs_offset, tsel_adder,
+	    extra_adder, tsel_enable;
+
+	ie_enable = PI_IE_ENABLE_VALUE;
+	tsel_enable = PI_TSEL_ENABLE_VALUE;
+
+	rdlat = pdram_timing->cl + PI_ADD_LATENCY;
+	delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
+	if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
+		delay_adder++;
+	hs_offset = 0;
+	tsel_adder = 0;
+	extra_adder = 0;
+	/* rdlat = rdlat - (PREAMBLE_SUPPORT & 0x1); */
+	tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz);
+	if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0)
+		tsel_adder++;
+	delay_adder = delay_adder - 1;
+	if (tsel_adder > delay_adder)
+		extra_adder = tsel_adder - delay_adder;
+	else
+		extra_adder = 0;
+	if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
+		hs_offset = 2;
+	else
+		hs_offset = 1;
+
+	if (delay_adder > (rdlat - 1 - hs_offset)) {
+		rdlat = rdlat - tsel_adder;
+	} else {
+		if ((rdlat - delay_adder) < 2)
+			rdlat = 2;
+		else
+			rdlat = rdlat - delay_adder - extra_adder;
+	}
+
+	return rdlat;
+}
+
+static uint32_t get_pi_wrlat(struct dram_timing_t *pdram_timing,
+			     struct timing_related_config *timing_config)
+{
+	uint32_t tmp;
+
+	if (timing_config->dram_type == LPDDR3) {
+		tmp = pdram_timing->cl;
+		if (tmp >= 14)
+			tmp = 8;
+		else if (tmp >= 10)
+			tmp = 6;
+		else if (tmp == 9)
+			tmp = 5;
+		else if (tmp == 8)
+			tmp = 4;
+		else if (tmp == 6)
+			tmp = 3;
+		else
+			tmp = 1;
+	} else {
+		tmp = 1;
+	}
+
+	return tmp;
+}
+
+static uint32_t get_pi_wrlat_adj(struct dram_timing_t *pdram_timing,
+				 struct timing_related_config *timing_config)
+{
+	return get_pi_wrlat(pdram_timing, timing_config) + PI_ADD_LATENCY - 1;
+}
+
+static uint32_t get_pi_tdfi_phy_rdlat(struct dram_timing_t *pdram_timing,
+			struct timing_related_config *timing_config)
+{
+	/* [DLLSUBTYPE2] == "STD_DENALI_HS" */
+	uint32_t cas_lat, delay_adder, ie_enable, hs_offset, ie_delay_adder;
+	uint32_t mem_delay_ps, round_trip_ps;
+	uint32_t phy_internal_delay, lpddr_adder, dfi_adder, rdlat_delay;
+
+	ie_enable = PI_IE_ENABLE_VALUE;
+
+	delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
+	if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
+		delay_adder++;
+	delay_adder = delay_adder - 1;
+	if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
+		hs_offset = 2;
+	else
+		hs_offset = 1;
+
+	cas_lat = pdram_timing->cl + PI_ADD_LATENCY;
+
+	if (delay_adder > (cas_lat - 1 - hs_offset)) {
+		ie_delay_adder = 0;
+	} else {
+		ie_delay_adder = ie_enable / (1000000 / pdram_timing->mhz);
+		if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
+			ie_delay_adder++;
+	}
+
+	if (timing_config->dram_type == DDR3) {
+		mem_delay_ps = 0;
+	} else if (timing_config->dram_type == LPDDR4) {
+		mem_delay_ps = 3600;
+	} else if (timing_config->dram_type == LPDDR3) {
+		mem_delay_ps = 5500;
+	} else {
+		NOTICE("get_pi_tdfi_phy_rdlat:dramtype unsupport\n");
+		return 0;
+	}
+	round_trip_ps = 1100 + 500 + mem_delay_ps + 500 + 600;
+	delay_adder = round_trip_ps / (1000000 / pdram_timing->mhz);
+	if ((round_trip_ps % (1000000 / pdram_timing->mhz)) != 0)
+		delay_adder++;
+
+	phy_internal_delay = 5 + 2 + 4;
+	lpddr_adder = mem_delay_ps / (1000000 / pdram_timing->mhz);
+	if ((mem_delay_ps % (1000000 / pdram_timing->mhz)) != 0)
+		lpddr_adder++;
+	dfi_adder = 0;
+	phy_internal_delay = phy_internal_delay + 2;
+	rdlat_delay = delay_adder + phy_internal_delay +
+	    ie_delay_adder + lpddr_adder + dfi_adder;
+
+	rdlat_delay = rdlat_delay + 2;
+	return rdlat_delay;
+}
+
+static uint32_t get_pi_todtoff_min(struct dram_timing_t *pdram_timing,
+				   struct timing_related_config *timing_config)
+{
+	uint32_t tmp, todtoff_min_ps;
+
+	if (timing_config->dram_type == LPDDR3)
+		todtoff_min_ps = 2500;
+	else if (timing_config->dram_type == LPDDR4)
+		todtoff_min_ps = 1500;
+	else
+		todtoff_min_ps = 0;
+	/* todtoff_min */
+	tmp = todtoff_min_ps / (1000000 / pdram_timing->mhz);
+	if ((todtoff_min_ps % (1000000 / pdram_timing->mhz)) != 0)
+		tmp++;
+	return tmp;
+}
+
+static uint32_t get_pi_todtoff_max(struct dram_timing_t *pdram_timing,
+				   struct timing_related_config *timing_config)
+{
+	uint32_t tmp, todtoff_max_ps;
+
+	if ((timing_config->dram_type == LPDDR4)
+	    || (timing_config->dram_type == LPDDR3))
+		todtoff_max_ps = 3500;
+	else
+		todtoff_max_ps = 0;
+
+	/* todtoff_max */
+	tmp = todtoff_max_ps / (1000000 / pdram_timing->mhz);
+	if ((todtoff_max_ps % (1000000 / pdram_timing->mhz)) != 0)
+		tmp++;
+	return tmp;
+}
+
+static void gen_rk3399_ctl_params_f0(struct timing_related_config
+				     *timing_config,
+				     struct dram_timing_t *pdram_timing)
+{
+	uint32_t i;
+	uint32_t tmp, tmp1;
+
+	for (i = 0; i < timing_config->ch_cnt; i++) {
+		if (timing_config->dram_type == DDR3) {
+			tmp = ((700000 + 10) * timing_config->freq +
+				999) / 1000;
+			tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) +
+			    pdram_timing->tmod + pdram_timing->tzqinit;
+			mmio_write_32(CTL_REG(i, 5), tmp);
+
+			mmio_clrsetbits_32(CTL_REG(i, 22), 0xffff,
+					   pdram_timing->tdllk);
+
+			mmio_write_32(CTL_REG(i, 32),
+				      (pdram_timing->tmod << 8) |
+				       pdram_timing->tmrd);
+
+			mmio_clrsetbits_32(CTL_REG(i, 59), 0xffffu << 16,
+					   (pdram_timing->txsr -
+					    pdram_timing->trcd) << 16);
+		} else if (timing_config->dram_type == LPDDR4) {
+			mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1 +
+						     pdram_timing->tinit3);
+			mmio_write_32(CTL_REG(i, 32),
+				      (pdram_timing->tmrd << 8) |
+				      pdram_timing->tmrd);
+			mmio_clrsetbits_32(CTL_REG(i, 59), 0xffffu << 16,
+					   pdram_timing->txsr << 16);
+		} else {
+			mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1);
+			mmio_write_32(CTL_REG(i, 7), pdram_timing->tinit4);
+			mmio_write_32(CTL_REG(i, 32),
+				      (pdram_timing->tmrd << 8) |
+				      pdram_timing->tmrd);
+			mmio_clrsetbits_32(CTL_REG(i, 59), 0xffffu << 16,
+					   pdram_timing->txsr << 16);
+		}
+		mmio_write_32(CTL_REG(i, 6), pdram_timing->tinit3);
+		mmio_write_32(CTL_REG(i, 8), pdram_timing->tinit5);
+		mmio_clrsetbits_32(CTL_REG(i, 23), (0x7f << 16),
+				   ((pdram_timing->cl * 2) << 16));
+		mmio_clrsetbits_32(CTL_REG(i, 23), (0x1f << 24),
+				   (pdram_timing->cwl << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f, pdram_timing->al);
+		mmio_clrsetbits_32(CTL_REG(i, 26), 0xffffu << 16,
+				   (pdram_timing->trc << 24) |
+				   (pdram_timing->trrd << 16));
+		mmio_write_32(CTL_REG(i, 27),
+			      (pdram_timing->tfaw << 24) |
+			      (pdram_timing->trppb << 16) |
+			      (pdram_timing->twtr << 8) |
+			      pdram_timing->tras_min);
+
+		mmio_clrsetbits_32(CTL_REG(i, 31), 0xffu << 24,
+				   max(4, pdram_timing->trtp) << 24);
+		mmio_write_32(CTL_REG(i, 33), (pdram_timing->tcke << 24) |
+					      pdram_timing->tras_max);
+		mmio_clrsetbits_32(CTL_REG(i, 34), 0xff,
+				   max(1, pdram_timing->tckesr));
+		mmio_clrsetbits_32(CTL_REG(i, 39),
+				   (0x3f << 16) | (0xff << 8),
+				   (pdram_timing->twr << 16) |
+				   (pdram_timing->trcd << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 16,
+				   pdram_timing->tmrz << 16);
+		tmp = pdram_timing->tdal ? pdram_timing->tdal :
+		      (pdram_timing->twr + pdram_timing->trp);
+		mmio_clrsetbits_32(CTL_REG(i, 44), 0xff, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 45), 0xff, pdram_timing->trp);
+		mmio_write_32(CTL_REG(i, 48),
+			      ((pdram_timing->trefi - 8) << 16) |
+			      pdram_timing->trfc);
+		mmio_clrsetbits_32(CTL_REG(i, 52), 0xffff, pdram_timing->txp);
+		mmio_clrsetbits_32(CTL_REG(i, 53), 0xffffu << 16,
+				   pdram_timing->txpdll << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 55), 0xf << 24,
+				   pdram_timing->tcscke << 24);
+		mmio_clrsetbits_32(CTL_REG(i, 55), 0xff, pdram_timing->tmrri);
+		mmio_write_32(CTL_REG(i, 56),
+			      (pdram_timing->tzqcke << 24) |
+			      (pdram_timing->tmrwckel << 16) |
+			      (pdram_timing->tckehcs << 8) |
+			      pdram_timing->tckelcs);
+		mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff, pdram_timing->txsnr);
+		mmio_clrsetbits_32(CTL_REG(i, 62), 0xffffu << 16,
+				   (pdram_timing->tckehcmd << 24) |
+				   (pdram_timing->tckelcmd << 16));
+		mmio_write_32(CTL_REG(i, 63),
+			      (pdram_timing->tckelpd << 24) |
+			      (pdram_timing->tescke << 16) |
+			      (pdram_timing->tsr << 8) |
+			      pdram_timing->tckckel);
+		mmio_clrsetbits_32(CTL_REG(i, 64), 0xfff,
+				   (pdram_timing->tcmdcke << 8) |
+				   pdram_timing->tcsckeh);
+		mmio_clrsetbits_32(CTL_REG(i, 92), 0xffff << 8,
+				   (pdram_timing->tcksrx << 16) |
+				   (pdram_timing->tcksre << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 108), 0x1 << 24,
+				   (timing_config->dllbp << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 122), 0x3ff << 16,
+				   (pdram_timing->tvrcg_enable << 16));
+		mmio_write_32(CTL_REG(i, 123), (pdram_timing->tfc_long << 16) |
+					       pdram_timing->tvrcg_disable);
+		mmio_write_32(CTL_REG(i, 124),
+			      (pdram_timing->tvref_long << 16) |
+			      (pdram_timing->tckfspx << 8) |
+			      pdram_timing->tckfspe);
+		mmio_write_32(CTL_REG(i, 133), (pdram_timing->mr[1] << 16) |
+					       pdram_timing->mr[0]);
+		mmio_clrsetbits_32(CTL_REG(i, 134), 0xffff,
+				   pdram_timing->mr[2]);
+		mmio_clrsetbits_32(CTL_REG(i, 138), 0xffff,
+				   pdram_timing->mr[3]);
+		mmio_clrsetbits_32(CTL_REG(i, 139), 0xffu << 24,
+				   pdram_timing->mr11 << 24);
+		mmio_write_32(CTL_REG(i, 147),
+			      (pdram_timing->mr[1] << 16) |
+			      pdram_timing->mr[0]);
+		mmio_clrsetbits_32(CTL_REG(i, 148), 0xffff,
+				   pdram_timing->mr[2]);
+		mmio_clrsetbits_32(CTL_REG(i, 152), 0xffff,
+				   pdram_timing->mr[3]);
+		mmio_clrsetbits_32(CTL_REG(i, 153), 0xffu << 24,
+				   pdram_timing->mr11 << 24);
+		if (timing_config->dram_type == LPDDR4) {
+			mmio_clrsetbits_32(CTL_REG(i, 140), 0xffffu << 16,
+					   pdram_timing->mr12 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 142), 0xffffu << 16,
+					   pdram_timing->mr14 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 145), 0xffffu << 16,
+					   pdram_timing->mr22 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 154), 0xffffu << 16,
+					   pdram_timing->mr12 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 156), 0xffffu << 16,
+					   pdram_timing->mr14 << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 159), 0xffffu << 16,
+					   pdram_timing->mr22 << 16);
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 179), 0xfff << 8,
+				   pdram_timing->tzqinit << 8);
+		mmio_write_32(CTL_REG(i, 180), (pdram_timing->tzqcs << 16) |
+					       (pdram_timing->tzqinit / 2));
+		mmio_write_32(CTL_REG(i, 181), (pdram_timing->tzqlat << 16) |
+					       pdram_timing->tzqcal);
+		mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 8,
+				   pdram_timing->todton << 8);
+
+		if (timing_config->odt) {
+			mmio_setbits_32(CTL_REG(i, 213), 1 << 16);
+			if (timing_config->freq < 400)
+				tmp = 4 << 24;
+			else
+				tmp = 8 << 24;
+		} else {
+			mmio_clrbits_32(CTL_REG(i, 213), 1 << 16);
+			tmp = 2 << 24;
+		}
+
+		mmio_clrsetbits_32(CTL_REG(i, 216), 0x1f << 24, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 221), (0x3 << 16) | (0xf << 8),
+				   (pdram_timing->tdqsck << 16) |
+				   (pdram_timing->tdqsck_max << 8));
+		tmp =
+		    (get_wrlat_adj(timing_config->dram_type, pdram_timing->cwl)
+		     << 8) | get_rdlat_adj(timing_config->dram_type,
+					   pdram_timing->cl);
+		mmio_clrsetbits_32(CTL_REG(i, 284), 0xffff, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 82), 0xffffu << 16,
+				   (4 * pdram_timing->trefi) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 83), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			tmp = get_pi_wrlat(pdram_timing, timing_config);
+			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
+			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
+		} else {
+			tmp = 0;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 214), 0x3f << 16,
+				   (tmp & 0x3f) << 16);
+
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			/* min_rl_preamble = cl+TDQSCK_MIN -1 */
+			tmp = pdram_timing->cl +
+			    get_pi_todtoff_min(pdram_timing, timing_config) - 1;
+			/* todtoff_max */
+			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
+			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
+		} else {
+			tmp = pdram_timing->cl - pdram_timing->cwl;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 8,
+				   (tmp & 0x3f) << 8);
+
+		mmio_clrsetbits_32(CTL_REG(i, 275), 0xff << 16,
+				   (get_pi_tdfi_phy_rdlat(pdram_timing,
+							  timing_config) &
+				    0xff) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 277), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		mmio_clrsetbits_32(CTL_REG(i, 282), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		mmio_write_32(CTL_REG(i, 283), 20 * pdram_timing->trefi);
+
+		/* CTL_308 TDFI_CALVL_CAPTURE_F0:RW:16:10 */
+		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
+		if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp1++;
+		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
+		mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff << 16, tmp << 16);
+
+		/* CTL_308 TDFI_CALVL_CC_F0:RW:0:10 */
+		tmp = tmp + 18;
+		mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff, tmp);
+
+		/* CTL_314 TDFI_WRCSLAT_F0:RW:8:8 */
+		tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
+		if (timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) {
+			if (tmp1 == 0)
+				tmp = 0;
+			else if (tmp1 < 5)
+				tmp = tmp1 - 1;
+			else
+				tmp = tmp1 - 5;
+		} else {
+			tmp = tmp1 - 2;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 8, tmp << 8);
+
+		/* CTL_314 TDFI_RDCSLAT_F0:RW:0:8 */
+		if ((timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) &&
+		    (pdram_timing->cl >= 5))
+			tmp = pdram_timing->cl - 5;
+		else
+			tmp = pdram_timing->cl - 2;
+		mmio_clrsetbits_32(CTL_REG(i, 314), 0xff, tmp);
+	}
+}
+
+static void gen_rk3399_ctl_params_f1(struct timing_related_config
+				     *timing_config,
+				     struct dram_timing_t *pdram_timing)
+{
+	uint32_t i;
+	uint32_t tmp, tmp1;
+
+	for (i = 0; i < timing_config->ch_cnt; i++) {
+		if (timing_config->dram_type == DDR3) {
+			tmp =
+			    ((700000 + 10) * timing_config->freq + 999) / 1000;
+			tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) +
+			       pdram_timing->tmod + pdram_timing->tzqinit;
+			mmio_write_32(CTL_REG(i, 9), tmp);
+			mmio_clrsetbits_32(CTL_REG(i, 22), 0xffffu << 16,
+					   pdram_timing->tdllk << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
+					   (pdram_timing->tmod << 24) |
+					   (pdram_timing->tmrd << 16) |
+					   (pdram_timing->trtp << 8));
+			mmio_clrsetbits_32(CTL_REG(i, 60), 0xffffu << 16,
+					   (pdram_timing->txsr -
+					    pdram_timing->trcd) << 16);
+		} else if (timing_config->dram_type == LPDDR4) {
+			mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1 +
+						     pdram_timing->tinit3);
+			mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
+					   (pdram_timing->tmrd << 24) |
+					   (pdram_timing->tmrd << 16) |
+					   (pdram_timing->trtp << 8));
+			mmio_clrsetbits_32(CTL_REG(i, 60), 0xffffu << 16,
+					   pdram_timing->txsr << 16);
+		} else {
+			mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1);
+			mmio_write_32(CTL_REG(i, 11), pdram_timing->tinit4);
+			mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00,
+					   (pdram_timing->tmrd << 24) |
+					   (pdram_timing->tmrd << 16) |
+					   (pdram_timing->trtp << 8));
+			mmio_clrsetbits_32(CTL_REG(i, 60), 0xffffu << 16,
+					   pdram_timing->txsr << 16);
+		}
+		mmio_write_32(CTL_REG(i, 10), pdram_timing->tinit3);
+		mmio_write_32(CTL_REG(i, 12), pdram_timing->tinit5);
+		mmio_clrsetbits_32(CTL_REG(i, 24), (0x7f << 8),
+				   ((pdram_timing->cl * 2) << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 24), (0x1f << 16),
+				   (pdram_timing->cwl << 16));
+		mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f << 24,
+				   pdram_timing->al << 24);
+		mmio_clrsetbits_32(CTL_REG(i, 28), 0xffffff00,
+				   (pdram_timing->tras_min << 24) |
+				   (pdram_timing->trc << 16) |
+				   (pdram_timing->trrd << 8));
+		mmio_clrsetbits_32(CTL_REG(i, 29), 0xffffff,
+				   (pdram_timing->tfaw << 16) |
+				   (pdram_timing->trppb << 8) |
+				   pdram_timing->twtr);
+		mmio_write_32(CTL_REG(i, 35), (pdram_timing->tcke << 24) |
+					      pdram_timing->tras_max);
+		mmio_clrsetbits_32(CTL_REG(i, 36), 0xff,
+				   max(1, pdram_timing->tckesr));
+		mmio_clrsetbits_32(CTL_REG(i, 39), (0xffu << 24),
+				   (pdram_timing->trcd << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 40), 0x3f, pdram_timing->twr);
+		mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 24,
+				   pdram_timing->tmrz << 24);
+		tmp = pdram_timing->tdal ? pdram_timing->tdal :
+		      (pdram_timing->twr + pdram_timing->trp);
+		mmio_clrsetbits_32(CTL_REG(i, 44), 0xff << 8, tmp << 8);
+		mmio_clrsetbits_32(CTL_REG(i, 45), 0xff << 8,
+				   pdram_timing->trp << 8);
+		mmio_write_32(CTL_REG(i, 49),
+			      ((pdram_timing->trefi - 8) << 16) |
+			      pdram_timing->trfc);
+		mmio_clrsetbits_32(CTL_REG(i, 52), 0xffffu << 16,
+				   pdram_timing->txp << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 54), 0xffff,
+				   pdram_timing->txpdll);
+		mmio_clrsetbits_32(CTL_REG(i, 55), 0xff << 8,
+				   pdram_timing->tmrri << 8);
+		mmio_write_32(CTL_REG(i, 57), (pdram_timing->tmrwckel << 24) |
+					      (pdram_timing->tckehcs << 16) |
+					      (pdram_timing->tckelcs << 8) |
+					      pdram_timing->tcscke);
+		mmio_clrsetbits_32(CTL_REG(i, 58), 0xf, pdram_timing->tzqcke);
+		mmio_clrsetbits_32(CTL_REG(i, 61), 0xffff, pdram_timing->txsnr);
+		mmio_clrsetbits_32(CTL_REG(i, 64), 0xffffu << 16,
+				   (pdram_timing->tckehcmd << 24) |
+				   (pdram_timing->tckelcmd << 16));
+		mmio_write_32(CTL_REG(i, 65), (pdram_timing->tckelpd << 24) |
+					      (pdram_timing->tescke << 16) |
+					      (pdram_timing->tsr << 8) |
+					      pdram_timing->tckckel);
+		mmio_clrsetbits_32(CTL_REG(i, 66), 0xfff,
+				   (pdram_timing->tcmdcke << 8) |
+				   pdram_timing->tcsckeh);
+		mmio_clrsetbits_32(CTL_REG(i, 92), (0xffu << 24),
+				   (pdram_timing->tcksre << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 93), 0xff,
+				   pdram_timing->tcksrx);
+		mmio_clrsetbits_32(CTL_REG(i, 108), (0x1 << 25),
+				   (timing_config->dllbp << 25));
+		mmio_write_32(CTL_REG(i, 125),
+			      (pdram_timing->tvrcg_disable << 16) |
+			      pdram_timing->tvrcg_enable);
+		mmio_write_32(CTL_REG(i, 126), (pdram_timing->tckfspx << 24) |
+					       (pdram_timing->tckfspe << 16) |
+					       pdram_timing->tfc_long);
+		mmio_clrsetbits_32(CTL_REG(i, 127), 0xffff,
+				   pdram_timing->tvref_long);
+		mmio_clrsetbits_32(CTL_REG(i, 134), 0xffffu << 16,
+				   pdram_timing->mr[0] << 16);
+		mmio_write_32(CTL_REG(i, 135), (pdram_timing->mr[2] << 16) |
+					       pdram_timing->mr[1]);
+		mmio_clrsetbits_32(CTL_REG(i, 138), 0xffffu << 16,
+				   pdram_timing->mr[3] << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 140), 0xff, pdram_timing->mr11);
+		mmio_clrsetbits_32(CTL_REG(i, 148), 0xffffu << 16,
+				   pdram_timing->mr[0] << 16);
+		mmio_write_32(CTL_REG(i, 149), (pdram_timing->mr[2] << 16) |
+					       pdram_timing->mr[1]);
+		mmio_clrsetbits_32(CTL_REG(i, 152), 0xffffu << 16,
+				   pdram_timing->mr[3] << 16);
+		mmio_clrsetbits_32(CTL_REG(i, 154), 0xff, pdram_timing->mr11);
+		if (timing_config->dram_type == LPDDR4) {
+			mmio_clrsetbits_32(CTL_REG(i, 141), 0xffff,
+					   pdram_timing->mr12);
+			mmio_clrsetbits_32(CTL_REG(i, 143), 0xffff,
+					   pdram_timing->mr14);
+			mmio_clrsetbits_32(CTL_REG(i, 146), 0xffff,
+					   pdram_timing->mr22);
+			mmio_clrsetbits_32(CTL_REG(i, 155), 0xffff,
+					   pdram_timing->mr12);
+			mmio_clrsetbits_32(CTL_REG(i, 157), 0xffff,
+					   pdram_timing->mr14);
+			mmio_clrsetbits_32(CTL_REG(i, 160), 0xffff,
+					   pdram_timing->mr22);
+		}
+		mmio_write_32(CTL_REG(i, 182),
+			      ((pdram_timing->tzqinit / 2) << 16) |
+			      pdram_timing->tzqinit);
+		mmio_write_32(CTL_REG(i, 183), (pdram_timing->tzqcal << 16) |
+					       pdram_timing->tzqcs);
+		mmio_clrsetbits_32(CTL_REG(i, 184), 0x3f, pdram_timing->tzqlat);
+		mmio_clrsetbits_32(CTL_REG(i, 188), 0xfff,
+				   pdram_timing->tzqreset);
+		mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 16,
+				   pdram_timing->todton << 16);
+
+		if (timing_config->odt) {
+			mmio_setbits_32(CTL_REG(i, 213), (1 << 24));
+			if (timing_config->freq < 400)
+				tmp = 4 << 24;
+			else
+				tmp = 8 << 24;
+		} else {
+			mmio_clrbits_32(CTL_REG(i, 213), (1 << 24));
+			tmp = 2 << 24;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 217), 0x1f << 24, tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 221), 0xf << 24,
+				   (pdram_timing->tdqsck_max << 24));
+		mmio_clrsetbits_32(CTL_REG(i, 222), 0x3, pdram_timing->tdqsck);
+		mmio_clrsetbits_32(CTL_REG(i, 291), 0xffff,
+				   (get_wrlat_adj(timing_config->dram_type,
+						  pdram_timing->cwl) << 8) |
+				   get_rdlat_adj(timing_config->dram_type,
+						 pdram_timing->cl));
+
+		mmio_clrsetbits_32(CTL_REG(i, 84), 0xffff,
+				   (4 * pdram_timing->trefi) & 0xffff);
+
+		mmio_clrsetbits_32(CTL_REG(i, 84), 0xffffu << 16,
+				   ((2 * pdram_timing->trefi) & 0xffff) << 16);
+
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			tmp = get_pi_wrlat(pdram_timing, timing_config);
+			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
+			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
+		} else {
+			tmp = 0;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 214), 0x3f << 24,
+				   (tmp & 0x3f) << 24);
+
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			/* min_rl_preamble = cl + TDQSCK_MIN - 1 */
+			tmp = pdram_timing->cl +
+			      get_pi_todtoff_min(pdram_timing, timing_config);
+			tmp--;
+			/* todtoff_max */
+			tmp1 = get_pi_todtoff_max(pdram_timing, timing_config);
+			tmp = (tmp > tmp1) ? (tmp - tmp1) : 0;
+		} else {
+			tmp = pdram_timing->cl - pdram_timing->cwl;
+		}
+		mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 16,
+				   (tmp & 0x3f) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 275), 0xffu << 24,
+				   (get_pi_tdfi_phy_rdlat(pdram_timing,
+							  timing_config) &
+				    0xff) << 24);
+
+		mmio_clrsetbits_32(CTL_REG(i, 284), 0xffffu << 16,
+				   ((2 * pdram_timing->trefi) & 0xffff) << 16);
+
+		mmio_clrsetbits_32(CTL_REG(i, 289), 0xffff,
+				   (2 * pdram_timing->trefi) & 0xffff);
+
+		mmio_write_32(CTL_REG(i, 290), 20 * pdram_timing->trefi);
+
+		/* CTL_309 TDFI_CALVL_CAPTURE_F1:RW:16:10 */
+		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
+		if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp1++;
+		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
+		mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff << 16, tmp << 16);
+
+		/* CTL_309 TDFI_CALVL_CC_F1:RW:0:10 */
+		tmp = tmp + 18;
+		mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff, tmp);
+
+		/* CTL_314 TDFI_WRCSLAT_F1:RW:24:8 */
+		tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
+		if (timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) {
+			if (tmp1 == 0)
+				tmp = 0;
+			else if (tmp1 < 5)
+				tmp = tmp1 - 1;
+			else
+				tmp = tmp1 - 5;
+		} else {
+			tmp = tmp1 - 2;
+		}
+
+		mmio_clrsetbits_32(CTL_REG(i, 314), 0xffu << 24, tmp << 24);
+
+		/* CTL_314 TDFI_RDCSLAT_F1:RW:16:8 */
+		if ((timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) &&
+		    (pdram_timing->cl >= 5))
+			tmp = pdram_timing->cl - 5;
+		else
+			tmp = pdram_timing->cl - 2;
+		mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 16, tmp << 16);
+	}
+}
+
+static void gen_rk3399_enable_training(uint32_t ch_cnt, uint32_t nmhz)
+{
+		uint32_t i, tmp;
+
+		if (nmhz <= PHY_DLL_BYPASS_FREQ)
+			tmp = 0;
+		else
+			tmp = 1;
+
+		for (i = 0; i < ch_cnt; i++) {
+			mmio_clrsetbits_32(CTL_REG(i, 305), 1 << 16, tmp << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 71), 1, tmp);
+			mmio_clrsetbits_32(CTL_REG(i, 70), 1 << 8, 1 << 8);
+		}
+}
+
+static void gen_rk3399_disable_training(uint32_t ch_cnt)
+{
+	uint32_t i;
+
+	for (i = 0; i < ch_cnt; i++) {
+		mmio_clrbits_32(CTL_REG(i, 305), 1 << 16);
+		mmio_clrbits_32(CTL_REG(i, 71), 1);
+		mmio_clrbits_32(CTL_REG(i, 70), 1 << 8);
+	}
+}
+
+static void gen_rk3399_ctl_params(struct timing_related_config *timing_config,
+				  struct dram_timing_t *pdram_timing,
+				  uint32_t fn)
+{
+	if (fn == 0)
+		gen_rk3399_ctl_params_f0(timing_config, pdram_timing);
+	else
+		gen_rk3399_ctl_params_f1(timing_config, pdram_timing);
+}
+
+static void gen_rk3399_pi_params_f0(struct timing_related_config *timing_config,
+				    struct dram_timing_t *pdram_timing)
+{
+	uint32_t tmp, tmp1, tmp2;
+	uint32_t i;
+
+	for (i = 0; i < timing_config->ch_cnt; i++) {
+		/* PI_02 PI_TDFI_PHYMSTR_MAX_F0:RW:0:32 */
+		tmp = 4 * pdram_timing->trefi;
+		mmio_write_32(PI_REG(i, 2), tmp);
+		/* PI_03 PI_TDFI_PHYMSTR_RESP_F0:RW:0:16 */
+		tmp = 2 * pdram_timing->trefi;
+		mmio_clrsetbits_32(PI_REG(i, 3), 0xffff, tmp);
+		/* PI_07 PI_TDFI_PHYUPD_RESP_F0:RW:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 7), 0xffffu << 16, tmp << 16);
+
+		/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F0:RW:0:8 */
+		if (timing_config->dram_type == LPDDR4)
+			tmp = 2;
+		else
+			tmp = 0;
+		tmp = (pdram_timing->bl / 2) + 4 +
+		      (get_pi_rdlat_adj(pdram_timing) - 2) + tmp +
+		      get_pi_tdfi_phy_rdlat(pdram_timing, timing_config);
+		mmio_clrsetbits_32(PI_REG(i, 42), 0xff, tmp);
+		/* PI_43 PI_WRLAT_F0:RW:0:5 */
+		if (timing_config->dram_type == LPDDR3) {
+			tmp = get_pi_wrlat(pdram_timing, timing_config);
+			mmio_clrsetbits_32(PI_REG(i, 43), 0x1f, tmp);
+		}
+		/* PI_43 PI_ADDITIVE_LAT_F0:RW:8:6 */
+		mmio_clrsetbits_32(PI_REG(i, 43), 0x3f << 8,
+				   PI_ADD_LATENCY << 8);
+
+		/* PI_43 PI_CASLAT_LIN_F0:RW:16:7 */
+		mmio_clrsetbits_32(PI_REG(i, 43), 0x7f << 16,
+				   (pdram_timing->cl * 2) << 16);
+		/* PI_46 PI_TREF_F0:RW:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 46), 0xffffu << 16,
+				   pdram_timing->trefi << 16);
+		/* PI_46 PI_TRFC_F0:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 46), 0x3ff, pdram_timing->trfc);
+		/* PI_66 PI_TODTL_2CMD_F0:RW:24:8 */
+		if (timing_config->dram_type == LPDDR3) {
+			tmp = get_pi_todtoff_max(pdram_timing, timing_config);
+			mmio_clrsetbits_32(PI_REG(i, 66), 0xffu << 24,
+					   tmp << 24);
+		}
+		/* PI_72 PI_WR_TO_ODTH_F0:RW:16:6 */
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			tmp1 = get_pi_wrlat(pdram_timing, timing_config);
+			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
+			if (tmp1 > tmp2)
+				tmp = tmp1 - tmp2;
+			else
+				tmp = 0;
+		} else if (timing_config->dram_type == DDR3) {
+			tmp = 0;
+		}
+		mmio_clrsetbits_32(PI_REG(i, 72), 0x3f << 16, tmp << 16);
+		/* PI_73 PI_RD_TO_ODTH_F0:RW:8:6 */
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			/* min_rl_preamble = cl + TDQSCK_MIN - 1 */
+			tmp1 = pdram_timing->cl;
+			tmp1 += get_pi_todtoff_min(pdram_timing, timing_config);
+			tmp1--;
+			/* todtoff_max */
+			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
+			if (tmp1 > tmp2)
+				tmp = tmp1 - tmp2;
+			else
+				tmp = 0;
+		} else if (timing_config->dram_type == DDR3) {
+			tmp = pdram_timing->cl - pdram_timing->cwl;
+		}
+		mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 8, tmp << 8);
+		/* PI_89 PI_RDLAT_ADJ_F0:RW:16:8 */
+		tmp = get_pi_rdlat_adj(pdram_timing);
+		mmio_clrsetbits_32(PI_REG(i, 89), 0xff << 16, tmp << 16);
+		/* PI_90 PI_WRLAT_ADJ_F0:RW:16:8 */
+		tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
+		mmio_clrsetbits_32(PI_REG(i, 90), 0xff << 16, tmp << 16);
+		/* PI_91 PI_TDFI_WRCSLAT_F0:RW:16:8 */
+		tmp1 = tmp;
+		if (tmp1 == 0)
+			tmp = 0;
+		else if (tmp1 < 5)
+			tmp = tmp1 - 1;
+		else
+			tmp = tmp1 - 5;
+		mmio_clrsetbits_32(PI_REG(i, 91), 0xff << 16, tmp << 16);
+		/* PI_95 PI_TDFI_CALVL_CAPTURE_F0:RW:16:10 */
+		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
+		if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp1++;
+		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
+		mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff << 16, tmp << 16);
+		/* PI_95 PI_TDFI_CALVL_CC_F0:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff, tmp + 18);
+		/* PI_102 PI_TMRZ_F0:RW:8:5 */
+		mmio_clrsetbits_32(PI_REG(i, 102), 0x1f << 8,
+				   pdram_timing->tmrz << 8);
+		/* PI_111 PI_TDFI_CALVL_STROBE_F0:RW:8:4 */
+		tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz);
+		if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp1++;
+		/* pi_tdfi_calvl_strobe=tds_train+5 */
+		tmp = tmp1 + 5;
+		mmio_clrsetbits_32(PI_REG(i, 111), 0xf << 8, tmp << 8);
+		/* PI_116 PI_TCKEHDQS_F0:RW:16:6 */
+		tmp = 10000 / (1000000 / pdram_timing->mhz);
+		if ((10000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp++;
+		if (pdram_timing->mhz <= 100)
+			tmp = tmp + 1;
+		else
+			tmp = tmp + 8;
+		mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 16, tmp << 16);
+		/* PI_125 PI_MR1_DATA_F0_0:RW+:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 125), 0xffff << 8,
+				   pdram_timing->mr[1] << 8);
+		/* PI_133 PI_MR1_DATA_F0_1:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 133), 0xffff, pdram_timing->mr[1]);
+		/* PI_140 PI_MR1_DATA_F0_2:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 140), 0xffffu << 16,
+				   pdram_timing->mr[1] << 16);
+		/* PI_148 PI_MR1_DATA_F0_3:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 148), 0xffff, pdram_timing->mr[1]);
+		/* PI_126 PI_MR2_DATA_F0_0:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 126), 0xffff, pdram_timing->mr[2]);
+		/* PI_133 PI_MR2_DATA_F0_1:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 133), 0xffffu << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_141 PI_MR2_DATA_F0_2:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 141), 0xffff, pdram_timing->mr[2]);
+		/* PI_148 PI_MR2_DATA_F0_3:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 148), 0xffffu << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_156 PI_TFC_F0:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff,
+				   pdram_timing->tfc_long);
+		/* PI_158 PI_TWR_F0:RW:24:6 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 24,
+				   pdram_timing->twr << 24);
+		/* PI_158 PI_TWTR_F0:RW:16:6 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 16,
+				   pdram_timing->twtr << 16);
+		/* PI_158 PI_TRCD_F0:RW:8:8 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0xff << 8,
+				   pdram_timing->trcd << 8);
+		/* PI_158 PI_TRP_F0:RW:0:8 */
+		mmio_clrsetbits_32(PI_REG(i, 158), 0xff, pdram_timing->trp);
+		/* PI_157 PI_TRTP_F0:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 157), 0xffu << 24,
+				   pdram_timing->trtp << 24);
+		/* PI_159 PI_TRAS_MIN_F0:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 159), 0xffu << 24,
+				   pdram_timing->tras_min << 24);
+		/* PI_159 PI_TRAS_MAX_F0:RW:0:17 */
+		tmp = pdram_timing->tras_max * 99 / 100;
+		mmio_clrsetbits_32(PI_REG(i, 159), 0x1ffff, tmp);
+		/* PI_160 PI_TMRD_F0:RW:16:6 */
+		mmio_clrsetbits_32(PI_REG(i, 160), 0x3f << 16,
+				   pdram_timing->tmrd << 16);
+		/*PI_160 PI_TDQSCK_MAX_F0:RW:0:4 */
+		mmio_clrsetbits_32(PI_REG(i, 160), 0xf,
+				   pdram_timing->tdqsck_max);
+		/* PI_187 PI_TDFI_CTRLUPD_MAX_F0:RW:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 187), 0xffff << 8,
+				   (2 * pdram_timing->trefi) << 8);
+		/* PI_188 PI_TDFI_CTRLUPD_INTERVAL_F0:RW:0:32 */
+		mmio_clrsetbits_32(PI_REG(i, 188), 0xffffffff,
+				   20 * pdram_timing->trefi);
+	}
+}
+
+static void gen_rk3399_pi_params_f1(struct timing_related_config *timing_config,
+				    struct dram_timing_t *pdram_timing)
+{
+	uint32_t tmp, tmp1, tmp2;
+	uint32_t i;
+
+	for (i = 0; i < timing_config->ch_cnt; i++) {
+		/* PI_04 PI_TDFI_PHYMSTR_MAX_F1:RW:0:32 */
+		tmp = 4 * pdram_timing->trefi;
+		mmio_write_32(PI_REG(i, 4), tmp);
+		/* PI_05 PI_TDFI_PHYMSTR_RESP_F1:RW:0:16 */
+		tmp = 2 * pdram_timing->trefi;
+		mmio_clrsetbits_32(PI_REG(i, 5), 0xffff, tmp);
+		/* PI_12 PI_TDFI_PHYUPD_RESP_F1:RW:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 12), 0xffff, tmp);
+
+		/* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F1:RW:8:8 */
+		if (timing_config->dram_type == LPDDR4)
+			tmp = 2;
+		else
+			tmp = 0;
+		tmp = (pdram_timing->bl / 2) + 4 +
+		      (get_pi_rdlat_adj(pdram_timing) - 2) + tmp +
+		      get_pi_tdfi_phy_rdlat(pdram_timing, timing_config);
+		mmio_clrsetbits_32(PI_REG(i, 42), 0xff << 8, tmp << 8);
+		/* PI_43 PI_WRLAT_F1:RW:24:5 */
+		if (timing_config->dram_type == LPDDR3) {
+			tmp = get_pi_wrlat(pdram_timing, timing_config);
+			mmio_clrsetbits_32(PI_REG(i, 43), 0x1f << 24,
+					   tmp << 24);
+		}
+		/* PI_44 PI_ADDITIVE_LAT_F1:RW:0:6 */
+		mmio_clrsetbits_32(PI_REG(i, 44), 0x3f, PI_ADD_LATENCY);
+		/* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */
+		mmio_clrsetbits_32(PI_REG(i, 44), 0x7f << 8,
+				   (pdram_timing->cl * 2) << 8);
+		/* PI_47 PI_TREF_F1:RW:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 47), 0xffffu << 16,
+				   pdram_timing->trefi << 16);
+		/* PI_47 PI_TRFC_F1:RW:0:10 */
+		mmio_clrsetbits_32(PI_REG(i, 47), 0x3ff, pdram_timing->trfc);
+		/* PI_67 PI_TODTL_2CMD_F1:RW:8:8 */
+		if (timing_config->dram_type == LPDDR3) {
+			tmp = get_pi_todtoff_max(pdram_timing, timing_config);
+			mmio_clrsetbits_32(PI_REG(i, 67), 0xff << 8, tmp << 8);
+		}
+		/* PI_72 PI_WR_TO_ODTH_F1:RW:24:6 */
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			tmp1 = get_pi_wrlat(pdram_timing, timing_config);
+			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
+			if (tmp1 > tmp2)
+				tmp = tmp1 - tmp2;
+			else
+				tmp = 0;
+		} else if (timing_config->dram_type == DDR3) {
+			tmp = 0;
+		}
+		mmio_clrsetbits_32(PI_REG(i, 72), 0x3f << 24, tmp << 24);
+		/* PI_73 PI_RD_TO_ODTH_F1:RW:16:6 */
+		if ((timing_config->dram_type == LPDDR3) ||
+		    (timing_config->dram_type == LPDDR4)) {
+			/* min_rl_preamble = cl + TDQSCK_MIN - 1 */
+			tmp1 = pdram_timing->cl +
+			       get_pi_todtoff_min(pdram_timing, timing_config);
+			tmp1--;
+			/* todtoff_max */
+			tmp2 = get_pi_todtoff_max(pdram_timing, timing_config);
+			if (tmp1 > tmp2)
+				tmp = tmp1 - tmp2;
+			else
+				tmp = 0;
+		} else if (timing_config->dram_type == DDR3)
+			tmp = pdram_timing->cl - pdram_timing->cwl;
+
+		mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 16, tmp << 16);
+		/*P I_89 PI_RDLAT_ADJ_F1:RW:24:8 */
+		tmp = get_pi_rdlat_adj(pdram_timing);
+		mmio_clrsetbits_32(PI_REG(i, 89), 0xffu << 24, tmp << 24);
+		/* PI_90 PI_WRLAT_ADJ_F1:RW:24:8 */
+		tmp = get_pi_wrlat_adj(pdram_timing, timing_config);
+		mmio_clrsetbits_32(PI_REG(i, 90), 0xffu << 24, tmp << 24);
+		/* PI_91 PI_TDFI_WRCSLAT_F1:RW:24:8 */
+		tmp1 = tmp;
+		if (tmp1 == 0)
+			tmp = 0;
+		else if (tmp1 < 5)
+			tmp = tmp1 - 1;
+		else
+			tmp = tmp1 - 5;
+		mmio_clrsetbits_32(PI_REG(i, 91), 0xffu << 24, tmp << 24);
+		/*PI_96 PI_TDFI_CALVL_CAPTURE_F1:RW:16:10 */
+		/* tadr=20ns */
+		tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1;
+		if ((20000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp1++;
+		tmp = (tmp1 >> 1) + (tmp1 % 2) + 5;
+		mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff << 16, tmp << 16);
+		/* PI_96 PI_TDFI_CALVL_CC_F1:RW:0:10 */
+		tmp = tmp + 18;
+		mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff, tmp);
+		/*PI_103 PI_TMRZ_F1:RW:0:5 */
+		mmio_clrsetbits_32(PI_REG(i, 103), 0x1f, pdram_timing->tmrz);
+		/*PI_111 PI_TDFI_CALVL_STROBE_F1:RW:16:4 */
+		/* tds_train=ceil(2/ns) */
+		tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz);
+		if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp1++;
+		/* pi_tdfi_calvl_strobe=tds_train+5 */
+		tmp = tmp1 + 5;
+		mmio_clrsetbits_32(PI_REG(i, 111), 0xf << 16,
+				   tmp << 16);
+		/* PI_116 PI_TCKEHDQS_F1:RW:24:6 */
+		tmp = 10000 / (1000000 / pdram_timing->mhz);
+		if ((10000 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp++;
+		if (pdram_timing->mhz <= 100)
+			tmp = tmp + 1;
+		else
+			tmp = tmp + 8;
+		mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 24,
+				   tmp << 24);
+		/* PI_128 PI_MR1_DATA_F1_0:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 128), 0xffff, pdram_timing->mr[1]);
+		/* PI_135 PI_MR1_DATA_F1_1:RW+:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 135), 0xffff << 8,
+				   pdram_timing->mr[1] << 8);
+		/* PI_143 PI_MR1_DATA_F1_2:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 143), 0xffff, pdram_timing->mr[1]);
+		/* PI_150 PI_MR1_DATA_F1_3:RW+:8:16 */
+		mmio_clrsetbits_32(PI_REG(i, 150), 0xffff << 8,
+				   pdram_timing->mr[1] << 8);
+		/* PI_128 PI_MR2_DATA_F1_0:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 128), 0xffffu << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_136 PI_MR2_DATA_F1_1:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 136), 0xffff, pdram_timing->mr[2]);
+		/* PI_143 PI_MR2_DATA_F1_2:RW+:16:16 */
+		mmio_clrsetbits_32(PI_REG(i, 143), 0xffffu << 16,
+				   pdram_timing->mr[2] << 16);
+		/* PI_151 PI_MR2_DATA_F1_3:RW+:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 151), 0xffff, pdram_timing->mr[2]);
+		/* PI_156 PI_TFC_F1:RW:16:10 */
+		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff << 16,
+				   pdram_timing->tfc_long << 16);
+		/* PI_162 PI_TWR_F1:RW:8:6 */
+		mmio_clrsetbits_32(PI_REG(i, 162), 0x3f << 8,
+				   pdram_timing->twr << 8);
+		/* PI_162 PI_TWTR_F1:RW:0:6 */
+		mmio_clrsetbits_32(PI_REG(i, 162), 0x3f, pdram_timing->twtr);
+		/* PI_161 PI_TRCD_F1:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 161), 0xffu << 24,
+				   pdram_timing->trcd << 24);
+		/* PI_161 PI_TRP_F1:RW:16:8 */
+		mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 16,
+				   pdram_timing->trp << 16);
+		/* PI_161 PI_TRTP_F1:RW:8:8 */
+		mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 8,
+				   pdram_timing->trtp << 8);
+		/* PI_163 PI_TRAS_MIN_F1:RW:24:8 */
+		mmio_clrsetbits_32(PI_REG(i, 163), 0xffu << 24,
+				   pdram_timing->tras_min << 24);
+		/* PI_163 PI_TRAS_MAX_F1:RW:0:17 */
+		mmio_clrsetbits_32(PI_REG(i, 163), 0x1ffff,
+				   pdram_timing->tras_max * 99 / 100);
+		/* PI_164 PI_TMRD_F1:RW:16:6 */
+		mmio_clrsetbits_32(PI_REG(i, 164), 0x3f << 16,
+				   pdram_timing->tmrd << 16);
+		/* PI_164 PI_TDQSCK_MAX_F1:RW:0:4 */
+		mmio_clrsetbits_32(PI_REG(i, 164), 0xf,
+				   pdram_timing->tdqsck_max);
+		/* PI_189 PI_TDFI_CTRLUPD_MAX_F1:RW:0:16 */
+		mmio_clrsetbits_32(PI_REG(i, 189), 0xffff,
+				   2 * pdram_timing->trefi);
+		/* PI_190 PI_TDFI_CTRLUPD_INTERVAL_F1:RW:0:32 */
+		mmio_clrsetbits_32(PI_REG(i, 190), 0xffffffff,
+				   20 * pdram_timing->trefi);
+	}
+}
+
+static void gen_rk3399_pi_params(struct timing_related_config *timing_config,
+				 struct dram_timing_t *pdram_timing,
+				 uint32_t fn)
+{
+	if (fn == 0)
+		gen_rk3399_pi_params_f0(timing_config, pdram_timing);
+	else
+		gen_rk3399_pi_params_f1(timing_config, pdram_timing);
+}
+
+static void gen_rk3399_set_odt(uint32_t odt_en)
+{
+	uint32_t drv_odt_val;
+	uint32_t i;
+
+	for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) {
+		drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 16;
+		mmio_clrsetbits_32(PHY_REG(i, 5), 0x7 << 16, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 133), 0x7 << 16, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 261), 0x7 << 16, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 389), 0x7 << 16, drv_odt_val);
+		drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 24;
+		mmio_clrsetbits_32(PHY_REG(i, 6), 0x7 << 24, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 134), 0x7 << 24, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 262), 0x7 << 24, drv_odt_val);
+		mmio_clrsetbits_32(PHY_REG(i, 390), 0x7 << 24, drv_odt_val);
+	}
+}
+
+static void gen_rk3399_phy_dll_bypass(uint32_t mhz, uint32_t ch,
+		uint32_t index, uint32_t dram_type)
+{
+	uint32_t sw_master_mode = 0;
+	uint32_t rddqs_gate_delay, rddqs_latency, total_delay;
+	uint32_t i;
+
+	if (dram_type == DDR3)
+		total_delay = PI_PAD_DELAY_PS_VALUE;
+	else if (dram_type == LPDDR3)
+		total_delay = PI_PAD_DELAY_PS_VALUE + 2500;
+	else
+		total_delay = PI_PAD_DELAY_PS_VALUE + 1500;
+	/* total_delay + 0.55tck */
+	total_delay +=  (55 * 10000)/mhz;
+	rddqs_latency = total_delay * mhz / 1000000;
+	total_delay -= rddqs_latency * 1000000 / mhz;
+	rddqs_gate_delay = total_delay * 0x200 * mhz / 1000000;
+	if (mhz <= PHY_DLL_BYPASS_FREQ) {
+		sw_master_mode = 0xc;
+		mmio_setbits_32(PHY_REG(ch, 514), 1);
+		mmio_setbits_32(PHY_REG(ch, 642), 1);
+		mmio_setbits_32(PHY_REG(ch, 770), 1);
+
+		/* setting bypass mode slave delay */
+		for (i = 0; i < 4; i++) {
+			/* wr dq delay = -180deg + (0x60 / 4) * 20ps */
+			mmio_clrsetbits_32(PHY_REG(ch, 1 + 128 * i), 0x7ff << 8,
+					   0x4a0 << 8);
+			/* rd dqs/dq delay = (0x60 / 4) * 20ps */
+			mmio_clrsetbits_32(PHY_REG(ch, 11 + 128 * i), 0x3ff,
+					   0xa0);
+			/* rd rddqs_gate delay */
+			mmio_clrsetbits_32(PHY_REG(ch, 2 + 128 * i), 0x3ff,
+					   rddqs_gate_delay);
+			mmio_clrsetbits_32(PHY_REG(ch, 78 + 128 * i), 0xf,
+					   rddqs_latency);
+		}
+		for (i = 0; i < 3; i++)
+			/* adr delay */
+			mmio_clrsetbits_32(PHY_REG(ch, 513 + 128 * i),
+					   0x7ff << 16, 0x80 << 16);
+
+		if ((mmio_read_32(PHY_REG(ch, 86)) & 0xc00) == 0) {
+			/*
+			 * old status is normal mode,
+			 * and saving the wrdqs slave delay
+			 */
+			for (i = 0; i < 4; i++) {
+				/* save and clear wr dqs slave delay */
+				wrdqs_delay_val[ch][index][i] = 0x3ff &
+					(mmio_read_32(PHY_REG(ch, 63 + i * 128))
+					>> 16);
+				mmio_clrsetbits_32(PHY_REG(ch, 63 + i * 128),
+						   0x03ff << 16, 0 << 16);
+				/*
+				 * in normal mode the cmd may delay 1cycle by
+				 * wrlvl and in bypass mode making dqs also
+				 * delay 1cycle.
+				 */
+				mmio_clrsetbits_32(PHY_REG(ch, 78 + i * 128),
+						   0x07 << 8, 0x1 << 8);
+			}
+		}
+	} else if (mmio_read_32(PHY_REG(ch, 86)) & 0xc00) {
+		/* old status is bypass mode and restore wrlvl resume */
+		for (i = 0; i < 4; i++) {
+			mmio_clrsetbits_32(PHY_REG(ch, 63 + i * 128),
+					   0x03ff << 16,
+					   (wrdqs_delay_val[ch][index][i] &
+					    0x3ff) << 16);
+			/* resume phy_write_path_lat_add */
+			mmio_clrbits_32(PHY_REG(ch, 78 + i * 128), 0x07 << 8);
+		}
+	}
+
+	/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
+	mmio_clrsetbits_32(PHY_REG(ch, 86), 0xf << 8, sw_master_mode << 8);
+	mmio_clrsetbits_32(PHY_REG(ch, 214), 0xf << 8, sw_master_mode << 8);
+	mmio_clrsetbits_32(PHY_REG(ch, 342), 0xf << 8, sw_master_mode << 8);
+	mmio_clrsetbits_32(PHY_REG(ch, 470), 0xf << 8, sw_master_mode << 8);
+
+	/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
+	mmio_clrsetbits_32(PHY_REG(ch, 547), 0xf << 16, sw_master_mode << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 675), 0xf << 16, sw_master_mode << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 803), 0xf << 16, sw_master_mode << 16);
+}
+
+static void gen_rk3399_phy_params(struct timing_related_config *timing_config,
+				  struct drv_odt_lp_config *drv_config,
+				  struct dram_timing_t *pdram_timing,
+				  uint32_t fn)
+{
+	uint32_t tmp, i, div, j;
+	uint32_t mem_delay_ps, pad_delay_ps, total_delay_ps, delay_frac_ps;
+	uint32_t trpre_min_ps, gate_delay_ps, gate_delay_frac_ps;
+	uint32_t ie_enable, tsel_enable, cas_lat, rddata_en_ie_dly, tsel_adder;
+	uint32_t extra_adder, delta, hs_offset;
+
+	for (i = 0; i < timing_config->ch_cnt; i++) {
+
+		pad_delay_ps = PI_PAD_DELAY_PS_VALUE;
+		ie_enable = PI_IE_ENABLE_VALUE;
+		tsel_enable = PI_TSEL_ENABLE_VALUE;
+
+		mmio_clrsetbits_32(PHY_REG(i, 896), (0x3 << 8) | 1, fn << 8);
+
+		/* PHY_LOW_FREQ_SEL */
+		/* DENALI_PHY_913 1bit offset_0 */
+		if (timing_config->freq > 400)
+			mmio_clrbits_32(PHY_REG(i, 913), 1);
+		else
+			mmio_setbits_32(PHY_REG(i, 913), 1);
+
+		/* PHY_RPTR_UPDATE_x */
+		/* DENALI_PHY_87/215/343/471 4bit offset_16 */
+		tmp = 2500 / (1000000 / pdram_timing->mhz) + 3;
+		if ((2500 % (1000000 / pdram_timing->mhz)) != 0)
+			tmp++;
+		mmio_clrsetbits_32(PHY_REG(i, 87), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 215), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 343), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 471), 0xf << 16, tmp << 16);
+
+		/* PHY_PLL_CTRL */
+		/* DENALI_PHY_911 13bits offset_0 */
+		/* PHY_LP4_BOOT_PLL_CTRL */
+		/* DENALI_PHY_919 13bits offset_0 */
+		tmp = (1 << 12) | (2 << 7) | (1 << 1);
+		mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff, tmp);
+
+		/* PHY_PLL_CTRL_CA */
+		/* DENALI_PHY_911 13bits offset_16 */
+		/* PHY_LP4_BOOT_PLL_CTRL_CA */
+		/* DENALI_PHY_919 13bits offset_16 */
+		tmp = (2 << 7) | (1 << 5) | (1 << 1);
+		mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff << 16, tmp << 16);
+
+		/* PHY_TCKSRE_WAIT */
+		/* DENALI_PHY_922 4bits offset_24 */
+		if (pdram_timing->mhz <= 400)
+			tmp = 1;
+		else if (pdram_timing->mhz <= 800)
+			tmp = 3;
+		else if (pdram_timing->mhz <= 1000)
+			tmp = 4;
+		else
+			tmp = 5;
+		mmio_clrsetbits_32(PHY_REG(i, 922), 0xf << 24, tmp << 24);
+		/* PHY_CAL_CLK_SELECT_0:RW8:3 */
+		div = pdram_timing->mhz / (2 * 20);
+		for (j = 2, tmp = 1; j <= 128; j <<= 1, tmp++) {
+			if (div < j)
+				break;
+		}
+		mmio_clrsetbits_32(PHY_REG(i, 947), 0x7 << 8, tmp << 8);
+
+		if (timing_config->dram_type == DDR3) {
+			mem_delay_ps = 0;
+			trpre_min_ps = 1000;
+		} else if (timing_config->dram_type == LPDDR4) {
+			mem_delay_ps = 1500;
+			trpre_min_ps = 900;
+		} else if (timing_config->dram_type == LPDDR3) {
+			mem_delay_ps = 2500;
+			trpre_min_ps = 900;
+		} else {
+			ERROR("gen_rk3399_phy_params:dramtype unsupport\n");
+			return;
+		}
+		total_delay_ps = mem_delay_ps + pad_delay_ps;
+		delay_frac_ps = 1000 * total_delay_ps /
+				(1000000 / pdram_timing->mhz);
+		gate_delay_ps = delay_frac_ps + 1000 - (trpre_min_ps / 2);
+		gate_delay_frac_ps = gate_delay_ps % 1000;
+		tmp = gate_delay_frac_ps * 0x200 / 1000;
+		/* PHY_RDDQS_GATE_SLAVE_DELAY */
+		/* DENALI_PHY_77/205/333/461 10bits offset_16 */
+		mmio_clrsetbits_32(PHY_REG(i, 77), 0x2ff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 205), 0x2ff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 333), 0x2ff << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 461), 0x2ff << 16, tmp << 16);
+
+		tmp = gate_delay_ps / 1000;
+		/* PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST */
+		/* DENALI_PHY_10/138/266/394 4bit offset_0 */
+		mmio_clrsetbits_32(PHY_REG(i, 10), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 138), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 266), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp);
+		/* PHY_GTLVL_LAT_ADJ_START */
+		/* DENALI_PHY_80/208/336/464 4bits offset_16 */
+		tmp = rddqs_delay_ps / (1000000 / pdram_timing->mhz) + 2;
+		mmio_clrsetbits_32(PHY_REG(i, 80), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 208), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 336), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 464), 0xf << 16, tmp << 16);
+
+		cas_lat = pdram_timing->cl + PI_ADD_LATENCY;
+		rddata_en_ie_dly = ie_enable / (1000000 / pdram_timing->mhz);
+		if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0)
+			rddata_en_ie_dly++;
+		rddata_en_ie_dly = rddata_en_ie_dly - 1;
+		tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz);
+		if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0)
+			tsel_adder++;
+		if (rddata_en_ie_dly > tsel_adder)
+			extra_adder = rddata_en_ie_dly - tsel_adder;
+		else
+			extra_adder = 0;
+		delta = cas_lat - rddata_en_ie_dly;
+		if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK)
+			hs_offset = 2;
+		else
+			hs_offset = 1;
+		if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset))
+			tmp = 0;
+		else if ((delta == 2) || (delta == 1))
+			tmp = rddata_en_ie_dly - 0 - extra_adder;
+		else
+			tmp = extra_adder;
+		/* PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY */
+		/* DENALI_PHY_9/137/265/393 4bit offset_16 */
+		mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 16, tmp << 16);
+		mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 16, tmp << 16);
+		/* PHY_RDDATA_EN_TSEL_DLY */
+		/* DENALI_PHY_86/214/342/470 4bit offset_0 */
+		mmio_clrsetbits_32(PHY_REG(i, 86), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 214), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 342), 0xf, tmp);
+		mmio_clrsetbits_32(PHY_REG(i, 470), 0xf, tmp);
+
+		if (tsel_adder > rddata_en_ie_dly)
+			extra_adder = tsel_adder - rddata_en_ie_dly;
+		else
+			extra_adder = 0;
+		if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset))
+			tmp = tsel_adder;
+		else
+			tmp = rddata_en_ie_dly - 0 + extra_adder;
+		/* PHY_LP4_BOOT_RDDATA_EN_DLY */
+		/* DENALI_PHY_9/137/265/393 4bit offset_8 */
+		mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 8, tmp << 8);
+		mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 8, tmp << 8);
+		mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 8, tmp << 8);
+		mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 8, tmp << 8);
+		/* PHY_RDDATA_EN_DLY */
+		/* DENALI_PHY_85/213/341/469 4bit offset_24 */
+		mmio_clrsetbits_32(PHY_REG(i, 85), 0xf << 24, tmp << 24);
+		mmio_clrsetbits_32(PHY_REG(i, 213), 0xf << 24, tmp << 24);
+		mmio_clrsetbits_32(PHY_REG(i, 341), 0xf << 24, tmp << 24);
+		mmio_clrsetbits_32(PHY_REG(i, 469), 0xf << 24, tmp << 24);
+
+		if (pdram_timing->mhz <= ENPER_CS_TRAINING_FREQ) {
+			/*
+			 * Note:Per-CS Training is not compatible at speeds
+			 * under 533 MHz. If the PHY is running at a speed
+			 * less than 533MHz, all phy_per_cs_training_en_X
+			 * parameters must be cleared to 0.
+			 */
+
+			/*DENALI_PHY_84/212/340/468 1bit offset_16 */
+			mmio_clrbits_32(PHY_REG(i, 84), 0x1 << 16);
+			mmio_clrbits_32(PHY_REG(i, 212), 0x1 << 16);
+			mmio_clrbits_32(PHY_REG(i, 340), 0x1 << 16);
+			mmio_clrbits_32(PHY_REG(i, 468), 0x1 << 16);
+		} else {
+			mmio_setbits_32(PHY_REG(i, 84), 0x1 << 16);
+			mmio_setbits_32(PHY_REG(i, 212), 0x1 << 16);
+			mmio_setbits_32(PHY_REG(i, 340), 0x1 << 16);
+			mmio_setbits_32(PHY_REG(i, 468), 0x1 << 16);
+		}
+		gen_rk3399_phy_dll_bypass(pdram_timing->mhz, i, fn,
+					  timing_config->dram_type);
+	}
+}
+
+static int to_get_clk_index(unsigned int mhz)
+{
+	int pll_cnt, i;
+
+	pll_cnt = ARRAY_SIZE(dpll_rates_table);
+
+	/* Assumming rate_table is in descending order */
+	for (i = 0; i < pll_cnt; i++) {
+		if (mhz >= dpll_rates_table[i].mhz)
+			break;
+	}
+
+	/* if mhz lower than lowest frequency in table, use lowest frequency */
+	if (i == pll_cnt)
+		i = pll_cnt - 1;
+
+	return i;
+}
+
+uint32_t ddr_get_rate(void)
+{
+	uint32_t refdiv, postdiv1, fbdiv, postdiv2;
+
+	refdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) & 0x3f;
+	fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
+	postdiv1 =
+		(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 8) & 0x7;
+	postdiv2 =
+		(mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 12) & 0x7;
+
+	return (24 / refdiv * fbdiv / postdiv1 / postdiv2) * 1000 * 1000;
+}
+
+/*
+ * return: bit12: channel 1, external self-refresh
+ *         bit11: channel 1, stdby_mode
+ *         bit10: channel 1, self-refresh with controller and memory clock gate
+ *         bit9: channel 1, self-refresh
+ *         bit8: channel 1, power-down
+ *
+ *         bit4: channel 1, external self-refresh
+ *         bit3: channel 0, stdby_mode
+ *         bit2: channel 0, self-refresh with controller and memory clock gate
+ *         bit1: channel 0, self-refresh
+ *         bit0: channel 0, power-down
+ */
+uint32_t exit_low_power(void)
+{
+	uint32_t low_power = 0;
+	uint32_t channel_mask;
+	uint32_t tmp, i;
+
+	channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) &
+			0x3;
+	for (i = 0; i < 2; i++) {
+		if (!(channel_mask & (1 << i)))
+			continue;
+
+		/* exit stdby mode */
+		mmio_write_32(CIC_BASE + CIC_CTRL1,
+			      (1 << (i + 16)) | (0 << i));
+		/* exit external self-refresh */
+		tmp = i ? 12 : 8;
+		low_power |= ((mmio_read_32(PMU_BASE + PMU_SFT_CON) >> tmp) &
+			      0x1) << (4 + 8 * i);
+		mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp);
+		while (!(mmio_read_32(PMU_BASE + PMU_DDR_SREF_ST) & (1 << i)))
+			;
+		/* exit auto low-power */
+		mmio_clrbits_32(CTL_REG(i, 101), 0x7);
+		/* lp_cmd to exit */
+		if (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) !=
+		    0x40) {
+			while (mmio_read_32(CTL_REG(i, 200)) & 0x1)
+				;
+			mmio_clrsetbits_32(CTL_REG(i, 93), 0xffu << 24,
+					   0x69 << 24);
+			while (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) !=
+			       0x40)
+				;
+		}
+	}
+	return low_power;
+}
+
+void resume_low_power(uint32_t low_power)
+{
+	uint32_t channel_mask;
+	uint32_t tmp, i, val;
+
+	channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) &
+		       0x3;
+	for (i = 0; i < 2; i++) {
+		if (!(channel_mask & (1 << i)))
+			continue;
+
+		/* resume external self-refresh */
+		tmp = i ? 12 : 8;
+		val = (low_power >> (4 + 8 * i)) & 0x1;
+		mmio_setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp);
+		/* resume auto low-power */
+		val = (low_power >> (8 * i)) & 0x7;
+		mmio_setbits_32(CTL_REG(i, 101), val);
+		/* resume stdby mode */
+		val = (low_power >> (3 + 8 * i)) & 0x1;
+		mmio_write_32(CIC_BASE + CIC_CTRL1,
+			      (1 << (i + 16)) | (val << i));
+	}
+}
+
+static void dram_low_power_config(void)
+{
+	uint32_t tmp, i;
+	uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt;
+	uint32_t dram_type = rk3399_dram_status.timing_config.dram_type;
+
+	if (dram_type == DDR3)
+		tmp = (2 << 16) | (0x7 << 8);
+	else
+		tmp = (3 << 16) | (0x7 << 8);
+
+	for (i = 0; i < ch_cnt; i++)
+		mmio_clrsetbits_32(CTL_REG(i, 101), 0x70f0f, tmp);
+
+	/* standby idle */
+	mmio_write_32(CIC_BASE + CIC_CG_WAIT_TH, 0x640008);
+
+	if (ch_cnt == 2) {
+		mmio_write_32(GRF_BASE + GRF_DDRC1_CON1,
+			      (((0x1<<4) | (0x1<<5) | (0x1<<6) |
+				(0x1<<7)) << 16) |
+			      ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
+		mmio_write_32(CIC_BASE + CIC_CTRL1, 0x002a0028);
+	}
+
+	mmio_write_32(GRF_BASE + GRF_DDRC0_CON1,
+		      (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
+		      ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
+	mmio_write_32(CIC_BASE + CIC_CTRL1, 0x00150014);
+}
+
+void dram_dfs_init(void)
+{
+	uint32_t trefi0, trefi1, boot_freq;
+	uint32_t rddqs_adjust, rddqs_slave;
+
+	/* get sdram config for os reg */
+	get_dram_drv_odt_val(sdram_config.dramtype,
+			     &rk3399_dram_status.drv_odt_lp_cfg);
+	sdram_timing_cfg_init(&rk3399_dram_status.timing_config,
+			      &sdram_config,
+			      &rk3399_dram_status.drv_odt_lp_cfg);
+
+	trefi0 = ((mmio_read_32(CTL_REG(0, 48)) >> 16) & 0xffff) + 8;
+	trefi1 = ((mmio_read_32(CTL_REG(0, 49)) >> 16) & 0xffff) + 8;
+
+	rk3399_dram_status.index_freq[0] = trefi0 * 10 / 39;
+	rk3399_dram_status.index_freq[1] = trefi1 * 10 / 39;
+	rk3399_dram_status.current_index =
+		(mmio_read_32(CTL_REG(0, 111)) >> 16) & 0x3;
+	if (rk3399_dram_status.timing_config.dram_type == DDR3) {
+		rk3399_dram_status.index_freq[0] /= 2;
+		rk3399_dram_status.index_freq[1] /= 2;
+	}
+	boot_freq =
+		rk3399_dram_status.index_freq[rk3399_dram_status.current_index];
+	boot_freq = dpll_rates_table[to_get_clk_index(boot_freq)].mhz;
+	rk3399_dram_status.boot_freq = boot_freq;
+	rk3399_dram_status.index_freq[rk3399_dram_status.current_index] =
+		boot_freq;
+	rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1) &
+				      0x1] = 0;
+	rk3399_dram_status.low_power_stat = 0;
+	/*
+	 * following register decide if NOC stall the access request
+	 * or return error when NOC being idled. when doing ddr frequency
+	 * scaling in M0 or DCF, we need to make sure noc stall the access
+	 * request, if return error cpu may data abort when ddr frequency
+	 * changing. it don't need to set this register every times,
+	 * so we init this register in function dram_dfs_init().
+	 */
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(0), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(1), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(2), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(3), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(4), 0x70007000);
+
+	/* Disable multicast */
+	mmio_clrbits_32(PHY_REG(0, 896), 1);
+	mmio_clrbits_32(PHY_REG(1, 896), 1);
+	dram_low_power_config();
+
+	/*
+	 * If boot_freq isn't in the bypass mode, it can get the
+	 * rddqs_delay_ps from the result of gate training
+	 */
+	if (((mmio_read_32(PHY_REG(0, 86)) >> 8) & 0xf) != 0xc) {
+
+		/*
+		 * Select PHY's frequency set to current_index
+		 * index for get the result of gate Training
+		 * from registers
+		 */
+		mmio_clrsetbits_32(PHY_REG(0, 896), 0x3 << 8,
+				   rk3399_dram_status.current_index << 8);
+		rddqs_slave = (mmio_read_32(PHY_REG(0, 77)) >> 16) & 0x3ff;
+		rddqs_slave = rddqs_slave * 1000000 / boot_freq / 512;
+
+		rddqs_adjust = mmio_read_32(PHY_REG(0, 78)) & 0xf;
+		rddqs_adjust = rddqs_adjust * 1000000 / boot_freq;
+		rddqs_delay_ps = rddqs_slave + rddqs_adjust -
+				(1000000 / boot_freq / 2);
+	} else {
+		rddqs_delay_ps = 3500;
+	}
+}
+
+/*
+ * arg0: bit0-7: sr_idle; bit8-15:sr_mc_gate_idle; bit16-31: standby idle
+ * arg1: bit0-11: pd_idle; bit 16-27: srpd_lite_idle
+ * arg2: bit0: if odt en
+ */
+uint32_t dram_set_odt_pd(uint32_t arg0, uint32_t arg1, uint32_t arg2)
+{
+	struct drv_odt_lp_config *lp_cfg = &rk3399_dram_status.drv_odt_lp_cfg;
+	uint32_t *low_power = &rk3399_dram_status.low_power_stat;
+	uint32_t dram_type, ch_count, pd_tmp, sr_tmp, i;
+
+	dram_type = rk3399_dram_status.timing_config.dram_type;
+	ch_count = rk3399_dram_status.timing_config.ch_cnt;
+
+	lp_cfg->sr_idle = arg0 & 0xff;
+	lp_cfg->sr_mc_gate_idle = (arg0 >> 8) & 0xff;
+	lp_cfg->standby_idle = (arg0 >> 16) & 0xffff;
+	lp_cfg->pd_idle = arg1 & 0xfff;
+	lp_cfg->srpd_lite_idle = (arg1 >> 16) & 0xfff;
+
+	rk3399_dram_status.timing_config.odt = arg2 & 0x1;
+
+	exit_low_power();
+
+	*low_power = 0;
+
+	/* pd_idle en */
+	if (lp_cfg->pd_idle)
+		*low_power |= ((1 << 0) | (1 << 8));
+	/* sr_idle en srpd_lite_idle */
+	if (lp_cfg->sr_idle | lp_cfg->srpd_lite_idle)
+		*low_power |= ((1 << 1) | (1 << 9));
+	/* sr_mc_gate_idle */
+	if (lp_cfg->sr_mc_gate_idle)
+		*low_power |= ((1 << 2) | (1 << 10));
+	/* standbyidle */
+	if (lp_cfg->standby_idle) {
+		if (rk3399_dram_status.timing_config.ch_cnt == 2)
+			*low_power |= ((1 << 3) | (1 << 11));
+		else
+			*low_power |= (1 << 3);
+	}
+
+	pd_tmp = arg1;
+	if (dram_type != LPDDR4)
+		pd_tmp = arg1 & 0xfff;
+	sr_tmp = arg0 & 0xffff;
+	for (i = 0; i < ch_count; i++) {
+		mmio_write_32(CTL_REG(i, 102), pd_tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 103), 0xffff, sr_tmp);
+	}
+	mmio_write_32(CIC_BASE + CIC_IDLE_TH, (arg0 >> 16) & 0xffff);
+
+	return 0;
+}
+
+static void m0_configure_ddr(struct pll_div pll_div, uint32_t ddr_index)
+{
+	mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(pll_div.fbdiv));
+	mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON1,
+		      POSTDIV2(pll_div.postdiv2) | POSTDIV1(pll_div.postdiv1) |
+		      REFDIV(pll_div.refdiv));
+
+	mmio_write_32(M0_PARAM_ADDR + PARAM_DRAM_FREQ, pll_div.mhz);
+
+	mmio_write_32(M0_PARAM_ADDR + PARAM_FREQ_SELECT, ddr_index << 4);
+	dmbst();
+	m0_configure_execute_addr(M0_BINCODE_BASE);
+}
+
+static uint32_t prepare_ddr_timing(uint32_t mhz)
+{
+	uint32_t index;
+	struct dram_timing_t dram_timing;
+
+	rk3399_dram_status.timing_config.freq = mhz;
+
+	if (mhz < 300)
+		rk3399_dram_status.timing_config.dllbp = 1;
+	else
+		rk3399_dram_status.timing_config.dllbp = 0;
+
+	if (rk3399_dram_status.timing_config.odt == 1)
+		gen_rk3399_set_odt(1);
+
+	index = (rk3399_dram_status.current_index + 1) & 0x1;
+
+	/*
+	 * checking if having available gate traiing timing for
+	 * target freq.
+	 */
+	dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing);
+	gen_rk3399_ctl_params(&rk3399_dram_status.timing_config,
+			      &dram_timing, index);
+	gen_rk3399_pi_params(&rk3399_dram_status.timing_config,
+			     &dram_timing, index);
+	gen_rk3399_phy_params(&rk3399_dram_status.timing_config,
+			      &rk3399_dram_status.drv_odt_lp_cfg,
+			      &dram_timing, index);
+	rk3399_dram_status.index_freq[index] = mhz;
+
+	return index;
+}
+
+uint32_t ddr_set_rate(uint32_t hz)
+{
+	uint32_t low_power, index, ddr_index;
+	uint32_t mhz = hz / (1000 * 1000);
+
+	if (mhz ==
+	    rk3399_dram_status.index_freq[rk3399_dram_status.current_index])
+		return mhz;
+
+	index = to_get_clk_index(mhz);
+	mhz = dpll_rates_table[index].mhz;
+
+	ddr_index = prepare_ddr_timing(mhz);
+	gen_rk3399_enable_training(rk3399_dram_status.timing_config.ch_cnt,
+				   mhz);
+	if (ddr_index > 1)
+		goto out;
+
+	/*
+	 * Make sure the clock is enabled. The M0 clocks should be on all of the
+	 * time during S0.
+	 */
+	m0_configure_ddr(dpll_rates_table[index], ddr_index);
+	m0_start();
+	m0_wait_done();
+	m0_stop();
+
+	if (rk3399_dram_status.timing_config.odt == 0)
+		gen_rk3399_set_odt(0);
+
+	rk3399_dram_status.current_index = ddr_index;
+	low_power = rk3399_dram_status.low_power_stat;
+	resume_low_power(low_power);
+out:
+	gen_rk3399_disable_training(rk3399_dram_status.timing_config.ch_cnt);
+	return mhz;
+}
+
+uint32_t ddr_round_rate(uint32_t hz)
+{
+	int index;
+	uint32_t mhz = hz / (1000 * 1000);
+
+	index = to_get_clk_index(mhz);
+
+	return dpll_rates_table[index].mhz * 1000 * 1000;
+}
+
+void ddr_prepare_for_sys_suspend(void)
+{
+	uint32_t mhz =
+		rk3399_dram_status.index_freq[rk3399_dram_status.current_index];
+
+	/*
+	 * If we're not currently at the boot (assumed highest) frequency, we
+	 * need to change frequencies to configure out current index.
+	 */
+	rk3399_suspend_status.freq = mhz;
+	exit_low_power();
+	rk3399_suspend_status.low_power_stat =
+		rk3399_dram_status.low_power_stat;
+	rk3399_suspend_status.odt = rk3399_dram_status.timing_config.odt;
+	rk3399_dram_status.low_power_stat = 0;
+	rk3399_dram_status.timing_config.odt = 1;
+	if (mhz != rk3399_dram_status.boot_freq)
+		ddr_set_rate(rk3399_dram_status.boot_freq * 1000 * 1000);
+
+	/*
+	 * This will configure the other index to be the same frequency as the
+	 * current one. We retrain both indices on resume, so both have to be
+	 * setup for the same frequency.
+	 */
+	prepare_ddr_timing(rk3399_dram_status.boot_freq);
+}
+
+void ddr_prepare_for_sys_resume(void)
+{
+	/* Disable multicast */
+	mmio_clrbits_32(PHY_REG(0, 896), 1);
+	mmio_clrbits_32(PHY_REG(1, 896), 1);
+
+	/* The suspend code changes the current index, so reset it now. */
+	rk3399_dram_status.current_index =
+		(mmio_read_32(CTL_REG(0, 111)) >> 16) & 0x3;
+	rk3399_dram_status.low_power_stat =
+		rk3399_suspend_status.low_power_stat;
+	rk3399_dram_status.timing_config.odt = rk3399_suspend_status.odt;
+
+	/*
+	 * Set the saved frequency from suspend if it's different than the
+	 * current frequency.
+	 */
+	if (rk3399_suspend_status.freq !=
+	    rk3399_dram_status.index_freq[rk3399_dram_status.current_index]) {
+		ddr_set_rate(rk3399_suspend_status.freq * 1000 * 1000);
+		return;
+	}
+
+	gen_rk3399_set_odt(rk3399_dram_status.timing_config.odt);
+	resume_low_power(rk3399_dram_status.low_power_stat);
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.h b/plat/rockchip/rk3399/drivers/dram/dfs.h
new file mode 100644
index 0000000..172b2a7
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DFS_H
+#define DFS_H
+
+#include <stdint.h>
+
+struct rk3399_sdram_default_config {
+	unsigned char bl;
+	/* 1:auto precharge, 0:never auto precharge */
+	unsigned char ap;
+	/* dram driver strength */
+	unsigned char dramds;
+	/* dram ODT, if odt=0, this parameter invalid */
+	unsigned char dramodt;
+	/* ca ODT, if odt=0, this parameter invalid
+	 * only used by LPDDR4
+	 */
+	unsigned char caodt;
+	unsigned char burst_ref_cnt;
+	/* zqcs period, unit(s) */
+	unsigned char zqcsi;
+};
+
+struct drv_odt_lp_config {
+	uint32_t pd_idle;
+	uint32_t sr_idle;
+	uint32_t sr_mc_gate_idle;
+	uint32_t srpd_lite_idle;
+	uint32_t standby_idle;
+	uint32_t odt_en;
+
+	uint32_t dram_side_drv;
+	uint32_t dram_side_dq_odt;
+	uint32_t dram_side_ca_odt;
+};
+
+uint32_t ddr_set_rate(uint32_t hz);
+uint32_t ddr_round_rate(uint32_t hz);
+uint32_t ddr_get_rate(void);
+uint32_t dram_set_odt_pd(uint32_t arg0, uint32_t arg1, uint32_t arg2);
+void dram_dfs_init(void);
+void ddr_prepare_for_sys_suspend(void);
+void ddr_prepare_for_sys_resume(void);
+
+#endif /* DFS_H */
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
new file mode 100644
index 0000000..42b6294
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dram.h>
+#include <plat_private.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+__pmusramdata struct rk3399_sdram_params sdram_config;
+
+void dram_init(void)
+{
+	uint32_t os_reg2_val, i;
+
+	os_reg2_val = mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2));
+	sdram_config.dramtype = SYS_REG_DEC_DDRTYPE(os_reg2_val);
+	sdram_config.num_channels = SYS_REG_DEC_NUM_CH(os_reg2_val);
+	sdram_config.stride = (mmio_read_32(SGRF_BASE + SGRF_SOC_CON3_7(4)) >>
+				10) & 0x1f;
+
+	for (i = 0; i < 2; i++) {
+		struct rk3399_sdram_channel *ch = &sdram_config.ch[i];
+		struct rk3399_msch_timings *noc = &ch->noc_timings;
+
+		if (!(SYS_REG_DEC_CHINFO(os_reg2_val, i)))
+			continue;
+
+		ch->rank = SYS_REG_DEC_RANK(os_reg2_val, i);
+		ch->col = SYS_REG_DEC_COL(os_reg2_val, i);
+		ch->bk = SYS_REG_DEC_BK(os_reg2_val, i);
+		ch->bw = SYS_REG_DEC_BW(os_reg2_val, i);
+		ch->dbw = SYS_REG_DEC_DBW(os_reg2_val, i);
+		ch->row_3_4 = SYS_REG_DEC_ROW_3_4(os_reg2_val, i);
+		ch->cs0_row = SYS_REG_DEC_CS0_ROW(os_reg2_val, i);
+		ch->cs1_row = SYS_REG_DEC_CS1_ROW(os_reg2_val, i);
+		ch->ddrconfig = mmio_read_32(MSCH_BASE(i) + MSCH_DEVICECONF);
+
+		noc->ddrtiminga0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DDRTIMINGA0);
+		noc->ddrtimingb0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DDRTIMINGB0);
+		noc->ddrtimingc0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DDRTIMINGC0);
+		noc->devtodev0.d32 = mmio_read_32(MSCH_BASE(i) +
+				MSCH_DEVTODEV0);
+		noc->ddrmode.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRMODE);
+		noc->agingx0 = mmio_read_32(MSCH_BASE(i) + MSCH_AGINGX0);
+	}
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
new file mode 100644
index 0000000..0eb12cf
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_H
+#define DRAM_H
+
+#include <stdint.h>
+
+#include <dram_regs.h>
+#include <plat_private.h>
+
+enum {
+	DDR3 = 3,
+	LPDDR2 = 5,
+	LPDDR3 = 6,
+	LPDDR4 = 7,
+	UNUSED = 0xff
+};
+
+struct rk3399_ddr_pctl_regs {
+	uint32_t denali_ctl[CTL_REG_NUM];
+};
+
+struct rk3399_ddr_publ_regs {
+	/*
+	 * PHY registers from 0 to 90 for slice1.
+	 * These are used to restore slice1-4 on resume.
+	 */
+	uint32_t phy0[91];
+	/*
+	 * PHY registers from 512 to 895.
+	 * Only registers 0-37 of each 128 register range are used.
+	 */
+	uint32_t phy512[3][38];
+	uint32_t phy896[63];
+};
+
+struct rk3399_ddr_pi_regs {
+	uint32_t denali_pi[PI_REG_NUM];
+};
+union noc_ddrtiminga0 {
+	uint32_t d32;
+	struct {
+		unsigned acttoact : 6;
+		unsigned reserved0 : 2;
+		unsigned rdtomiss : 6;
+		unsigned reserved1 : 2;
+		unsigned wrtomiss : 6;
+		unsigned reserved2 : 2;
+		unsigned readlatency : 8;
+	} b;
+};
+
+union noc_ddrtimingb0 {
+	uint32_t d32;
+	struct {
+		unsigned rdtowr : 5;
+		unsigned reserved0 : 3;
+		unsigned wrtord : 5;
+		unsigned reserved1 : 3;
+		unsigned rrd : 4;
+		unsigned reserved2 : 4;
+		unsigned faw : 6;
+		unsigned reserved3 : 2;
+	} b;
+};
+
+union noc_ddrtimingc0 {
+	uint32_t d32;
+	struct {
+		unsigned burstpenalty : 4;
+		unsigned reserved0 : 4;
+		unsigned wrtomwr : 6;
+		unsigned reserved1 : 18;
+	} b;
+};
+
+union noc_devtodev0 {
+	uint32_t d32;
+	struct {
+		unsigned busrdtord : 3;
+		unsigned reserved0 : 1;
+		unsigned busrdtowr : 3;
+		unsigned reserved1 : 1;
+		unsigned buswrtord : 3;
+		unsigned reserved2 : 1;
+		unsigned buswrtowr : 3;
+		unsigned reserved3 : 17;
+	} b;
+};
+
+union noc_ddrmode {
+	uint32_t d32;
+	struct {
+		unsigned autoprecharge : 1;
+		unsigned bypassfiltering : 1;
+		unsigned fawbank : 1;
+		unsigned burstsize : 2;
+		unsigned mwrsize : 2;
+		unsigned reserved2 : 1;
+		unsigned forceorder : 8;
+		unsigned forceorderstate : 8;
+		unsigned reserved3 : 8;
+	} b;
+};
+
+struct rk3399_msch_timings {
+	union noc_ddrtiminga0 ddrtiminga0;
+	union noc_ddrtimingb0 ddrtimingb0;
+	union noc_ddrtimingc0 ddrtimingc0;
+	union noc_devtodev0 devtodev0;
+	union noc_ddrmode ddrmode;
+	uint32_t agingx0;
+};
+
+struct rk3399_sdram_channel {
+	unsigned char rank;
+	/* col = 0, means this channel is invalid */
+	unsigned char col;
+	/* 3:8bank, 2:4bank */
+	unsigned char bk;
+	/* channel buswidth, 2:32bit, 1:16bit, 0:8bit */
+	unsigned char bw;
+	/* die buswidth, 2:32bit, 1:16bit, 0:8bit */
+	unsigned char dbw;
+	/* row_3_4 = 1: 6Gb or 12Gb die
+	 * row_3_4 = 0: normal die, power of 2
+	 */
+	unsigned char row_3_4;
+	unsigned char cs0_row;
+	unsigned char cs1_row;
+	uint32_t ddrconfig;
+	struct rk3399_msch_timings noc_timings;
+};
+
+struct rk3399_sdram_params {
+	struct rk3399_sdram_channel ch[2];
+	uint32_t ddr_freq;
+	unsigned char dramtype;
+	unsigned char num_channels;
+	unsigned char stride;
+	unsigned char odt;
+	struct rk3399_ddr_pctl_regs pctl_regs;
+	struct rk3399_ddr_pi_regs pi_regs;
+	struct rk3399_ddr_publ_regs phy_regs;
+	uint32_t rx_cal_dqs[2][4];
+};
+
+extern __sramdata struct rk3399_sdram_params sdram_config;
+
+void dram_init(void);
+
+#endif /* DRAM_H */
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
new file mode 100644
index 0000000..3cdb7a2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <lib/utils.h>
+
+#include <dram.h>
+
+#include "dram_spec_timing.h"
+
+static const uint8_t ddr3_cl_cwl[][7] = {
+	/*
+	 * speed 0~330 331 ~ 400 401 ~ 533 534~666 667~800 801~933 934~1066
+	 * tCK>3 2.5~3 1.875~2.5 1.5~1.875 1.25~1.5 1.07~1.25 0.938~1.07
+	 * cl<<4, cwl  cl<<4, cwl  cl<<4, cwl
+	 */
+	/* DDR3_800D (5-5-5) */
+	{((5 << 4) | 5), ((5 << 4) | 5), 0, 0, 0, 0, 0},
+	/* DDR3_800E (6-6-6) */
+	{((5 << 4) | 5), ((6 << 4) | 5), 0, 0, 0, 0, 0},
+	/* DDR3_1066E (6-6-6) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), 0, 0, 0, 0},
+	/* DDR3_1066F (7-7-7) */
+	{((5 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), 0, 0, 0, 0},
+	/* DDR3_1066G (8-8-8) */
+	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), 0, 0, 0, 0},
+	/* DDR3_1333F (7-7-7) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7),
+	 0, 0, 0},
+	/* DDR3_1333G (8-8-8) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((8 << 4) | 7),
+	 0, 0, 0},
+	/* DDR3_1333H (9-9-9) */
+	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((9 << 4) | 7),
+	 0, 0, 0},
+	/* DDR3_1333J (10-10-10) */
+	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7),
+	 0, 0, 0},
+	/* DDR3_1600G (8-8-8) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7),
+	 ((8 << 4) | 8), 0, 0},
+	/* DDR3_1600H (9-9-9) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7),
+	 ((9 << 4) | 8), 0, 0},
+	/* DDR3_1600J (10-10-10) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7),
+	 ((10 << 4) | 8), 0, 0},
+	/* DDR3_1600K (11-11-11) */
+	{((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7),
+	 ((11 << 4) | 8), 0, 0},
+	/* DDR3_1866J (10-10-10) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7),
+	 ((9 << 4) | 8), ((11 << 4) | 9), 0},
+	/* DDR3_1866K (11-11-11) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((8 << 4) | 7),
+	 ((10 << 4) | 8), ((11 << 4) | 9), 0},
+	/* DDR3_1866L (12-12-12) */
+	{((6 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7),
+	 ((11 << 4) | 8), ((12 << 4) | 9), 0},
+	/* DDR3_1866M (13-13-13) */
+	{((6 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7),
+	 ((11 << 4) | 8), ((13 << 4) | 9), 0},
+	/* DDR3_2133K (11-11-11) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7),
+	 ((9 << 4) | 8), ((10 << 4) | 9), ((11 << 4) | 10)},
+	/* DDR3_2133L (12-12-12) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7),
+	 ((9 << 4) | 8), ((11 << 4) | 9), ((12 << 4) | 10)},
+	/* DDR3_2133M (13-13-13) */
+	{((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7),
+	 ((10 << 4) | 8), ((12 << 4) | 9), ((13 << 4) | 10)},
+	/* DDR3_2133N (14-14-14) */
+	{((6 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7),
+	 ((11 << 4) | 8), ((13 << 4) | 9), ((14 << 4) | 10)},
+	/* DDR3_DEFAULT */
+	{((6 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7),
+	 ((11 << 4) | 8), ((13 << 4) | 9), ((14 << 4) | 10)}
+};
+
+static const uint16_t ddr3_trc_tfaw[] = {
+	/* tRC      tFAW */
+	((50 << 8) | 50),	/* DDR3_800D (5-5-5) */
+	((53 << 8) | 50),	/* DDR3_800E (6-6-6) */
+
+	((49 << 8) | 50),	/* DDR3_1066E (6-6-6) */
+	((51 << 8) | 50),	/* DDR3_1066F (7-7-7) */
+	((53 << 8) | 50),	/* DDR3_1066G (8-8-8) */
+
+	((47 << 8) | 45),	/* DDR3_1333F (7-7-7) */
+	((48 << 8) | 45),	/* DDR3_1333G (8-8-8) */
+	((50 << 8) | 45),	/* DDR3_1333H (9-9-9) */
+	((51 << 8) | 45),	/* DDR3_1333J (10-10-10) */
+
+	((45 << 8) | 40),	/* DDR3_1600G (8-8-8) */
+	((47 << 8) | 40),	/* DDR3_1600H (9-9-9)*/
+	((48 << 8) | 40),	/* DDR3_1600J (10-10-10) */
+	((49 << 8) | 40),	/* DDR3_1600K (11-11-11) */
+
+	((45 << 8) | 35),	/* DDR3_1866J (10-10-10) */
+	((46 << 8) | 35),	/* DDR3_1866K (11-11-11) */
+	((47 << 8) | 35),	/* DDR3_1866L (12-12-12) */
+	((48 << 8) | 35),	/* DDR3_1866M (13-13-13) */
+
+	((44 << 8) | 35),	/* DDR3_2133K (11-11-11) */
+	((45 << 8) | 35),	/* DDR3_2133L (12-12-12) */
+	((46 << 8) | 35),	/* DDR3_2133M (13-13-13) */
+	((47 << 8) | 35),	/* DDR3_2133N (14-14-14) */
+
+	((53 << 8) | 50)	/* DDR3_DEFAULT */
+};
+
+static uint32_t get_max_speed_rate(struct timing_related_config *timing_config)
+{
+	if (timing_config->ch_cnt > 1)
+		return max(timing_config->dram_info[0].speed_rate,
+					timing_config->dram_info[1].speed_rate);
+	else
+		return timing_config->dram_info[0].speed_rate;
+}
+
+static uint32_t
+get_max_die_capability(struct timing_related_config *timing_config)
+{
+	uint32_t die_cap = 0;
+	uint32_t cs, ch;
+
+	for (ch = 0; ch < timing_config->ch_cnt; ch++) {
+		for (cs = 0; cs < timing_config->dram_info[ch].cs_cnt; cs++) {
+			die_cap = max(die_cap,
+				      timing_config->
+				      dram_info[ch].per_die_capability[cs]);
+		}
+	}
+	return die_cap;
+}
+
+/* tRSTL, 100ns */
+#define DDR3_TRSTL		(100)
+/* trsth, 500us */
+#define DDR3_TRSTH		(500000)
+/* trefi, 7.8us */
+#define DDR3_TREFI_7_8_US	(7800)
+/* tWR, 15ns */
+#define DDR3_TWR		(15)
+/* tRTP, max(4 tCK,7.5ns) */
+#define DDR3_TRTP		(7)
+/* tRRD = max(4nCK, 10ns) */
+#define DDR3_TRRD		(10)
+/* tCK */
+#define DDR3_TCCD		(4)
+/*tWTR, max(4 tCK,7.5ns)*/
+#define DDR3_TWTR		(7)
+/* tCK */
+#define DDR3_TRTW		(0)
+/* tRAS, 37.5ns(400MHz) 37.5ns(533MHz) */
+#define DDR3_TRAS		(37)
+/* ns */
+#define DDR3_TRFC_512MBIT	(90)
+/* ns */
+#define DDR3_TRFC_1GBIT		(110)
+/* ns */
+#define DDR3_TRFC_2GBIT		(160)
+/* ns */
+#define DDR3_TRFC_4GBIT		(300)
+/* ns */
+#define DDR3_TRFC_8GBIT		(350)
+
+/*pd and sr*/
+#define DDR3_TXP		(7) /* tXP, max(3 tCK, 7.5ns)( < 933MHz) */
+#define DDR3_TXPDLL		(24) /* tXPDLL, max(10 tCK, 24ns) */
+#define DDR3_TDLLK		(512) /* tXSR, tDLLK=512 tCK */
+#define DDR3_TCKE_400MHZ	(7) /* tCKE, max(3 tCK,7.5ns)(400MHz) */
+#define DDR3_TCKE_533MHZ	(6) /* tCKE, max(3 tCK,5.625ns)(533MHz) */
+#define DDR3_TCKSRE		(10) /* tCKSRX, max(5 tCK, 10ns) */
+
+/*mode register timing*/
+#define DDR3_TMOD		(15) /* tMOD, max(12 tCK,15ns) */
+#define DDR3_TMRD		(4) /* tMRD, 4 tCK */
+
+/* ZQ */
+#define DDR3_TZQINIT		(640) /* tZQinit, max(512 tCK, 640ns) */
+#define DDR3_TZQCS		(80) /* tZQCS, max(64 tCK, 80ns) */
+#define DDR3_TZQOPER		(320) /* tZQoper, max(256 tCK, 320ns) */
+
+/* Write leveling */
+#define DDR3_TWLMRD		(40) /* tCK */
+#define DDR3_TWLO		(9) /* max 7.5ns */
+#define DDR3_TWLDQSEN		(25) /* tCK */
+
+/*
+ * Description: depend on input parameter "timing_config",
+ *		and calculate all ddr3
+ *		spec timing to "pdram_timing"
+ * parameters:
+ *   input: timing_config
+ *   output: pdram_timing
+ */
+static void ddr3_get_parameter(struct timing_related_config *timing_config,
+			       struct dram_timing_t *pdram_timing)
+{
+	uint32_t nmhz = timing_config->freq;
+	uint32_t ddr_speed_bin = get_max_speed_rate(timing_config);
+	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
+	uint32_t tmp;
+
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
+	pdram_timing->mhz = nmhz;
+	pdram_timing->al = 0;
+	pdram_timing->bl = timing_config->bl;
+	if (nmhz <= 330)
+		tmp = 0;
+	else if (nmhz <= 400)
+		tmp = 1;
+	else if (nmhz <= 533)
+		tmp = 2;
+	else if (nmhz <= 666)
+		tmp = 3;
+	else if (nmhz <= 800)
+		tmp = 4;
+	else if (nmhz <= 933)
+		tmp = 5;
+	else
+		tmp = 6;
+
+	/* when dll bypss cl = cwl = 6 */
+	if (nmhz < 300) {
+		pdram_timing->cl = 6;
+		pdram_timing->cwl = 6;
+	} else {
+		pdram_timing->cl = (ddr3_cl_cwl[ddr_speed_bin][tmp] >> 4) & 0xf;
+		pdram_timing->cwl = ddr3_cl_cwl[ddr_speed_bin][tmp] & 0xf;
+	}
+
+	switch (timing_config->dramds) {
+	case 40:
+		tmp = DDR3_DS_40;
+		break;
+	case 34:
+	default:
+		tmp = DDR3_DS_34;
+		break;
+	}
+
+	if (timing_config->odt)
+		switch (timing_config->dramodt) {
+		case 60:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_60;
+			break;
+		case 40:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_40;
+			break;
+		case 120:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_120;
+			break;
+		case 0:
+		default:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS;
+			break;
+		}
+	else
+		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS;
+
+	pdram_timing->mr[2] = DDR3_MR2_CWL(pdram_timing->cwl);
+	pdram_timing->mr[3] = 0;
+
+	pdram_timing->trstl = ((DDR3_TRSTL * nmhz + 999) / 1000);
+	pdram_timing->trsth = ((DDR3_TRSTH * nmhz + 999) / 1000);
+	/* tREFI, average periodic refresh interval, 7.8us */
+	pdram_timing->trefi = ((DDR3_TREFI_7_8_US * nmhz + 999) / 1000);
+	/* base timing */
+	pdram_timing->trcd = pdram_timing->cl;
+	pdram_timing->trp = pdram_timing->cl;
+	pdram_timing->trppb = pdram_timing->cl;
+	tmp = ((DDR3_TWR * nmhz + 999) / 1000);
+	pdram_timing->twr = tmp;
+	pdram_timing->tdal = tmp + pdram_timing->trp;
+	if (tmp < 9) {
+		tmp = tmp - 4;
+	} else {
+		tmp += (tmp & 0x1) ? 1 : 0;
+		tmp = tmp >> 1;
+	}
+	if (pdram_timing->bl == 4)
+		pdram_timing->mr[0] = DDR3_BC4
+				| DDR3_CL(pdram_timing->cl)
+				| DDR3_WR(tmp);
+	else
+		pdram_timing->mr[0] = DDR3_BL8
+				| DDR3_CL(pdram_timing->cl)
+				| DDR3_WR(tmp);
+	tmp = ((DDR3_TRTP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->trtp = max(4, tmp);
+	pdram_timing->trc =
+		(((ddr3_trc_tfaw[ddr_speed_bin] >> 8) * nmhz + 999) / 1000);
+	tmp = ((DDR3_TRRD * nmhz + 999) / 1000);
+	pdram_timing->trrd = max(4, tmp);
+	pdram_timing->tccd = DDR3_TCCD;
+	tmp = ((DDR3_TWTR * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->twtr = max(4, tmp);
+	pdram_timing->trtw = DDR3_TRTW;
+	pdram_timing->tras_max = 9 * pdram_timing->trefi;
+	pdram_timing->tras_min = ((DDR3_TRAS * nmhz + (nmhz >> 1) + 999)
+		/ 1000);
+	pdram_timing->tfaw =
+		(((ddr3_trc_tfaw[ddr_speed_bin] & 0x0ff) * nmhz + 999)
+						/ 1000);
+	/* tRFC, 90ns(512Mb),110ns(1Gb),160ns(2Gb),300ns(4Gb),350ns(8Gb) */
+	if (ddr_capability_per_die <= 0x4000000)
+		tmp = DDR3_TRFC_512MBIT;
+	else if (ddr_capability_per_die <= 0x8000000)
+		tmp = DDR3_TRFC_1GBIT;
+	else if (ddr_capability_per_die <= 0x10000000)
+		tmp = DDR3_TRFC_2GBIT;
+	else if (ddr_capability_per_die <= 0x20000000)
+		tmp = DDR3_TRFC_4GBIT;
+	else
+		tmp = DDR3_TRFC_8GBIT;
+	pdram_timing->trfc = (tmp * nmhz + 999) / 1000;
+	pdram_timing->txsnr = max(5, (((tmp + 10) * nmhz + 999) / 1000));
+	pdram_timing->tdqsck_max = 0;
+	/*pd and sr*/
+	pdram_timing->txsr = DDR3_TDLLK;
+	tmp = ((DDR3_TXP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->txp = max(3, tmp);
+	tmp = ((DDR3_TXPDLL * nmhz + 999) / 1000);
+	pdram_timing->txpdll = max(10, tmp);
+	pdram_timing->tdllk = DDR3_TDLLK;
+	if (nmhz >= 533)
+		tmp = ((DDR3_TCKE_533MHZ * nmhz + 999) / 1000);
+	else
+		tmp = ((DDR3_TCKE_400MHZ * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->tcke = max(3, tmp);
+	pdram_timing->tckesr = (pdram_timing->tcke + 1);
+	tmp = ((DDR3_TCKSRE * nmhz + 999) / 1000);
+	pdram_timing->tcksre = max(5, tmp);
+	pdram_timing->tcksrx = max(5, tmp);
+	/*mode register timing*/
+	tmp = ((DDR3_TMOD * nmhz + 999) / 1000);
+	pdram_timing->tmod = max(12, tmp);
+	pdram_timing->tmrd = DDR3_TMRD;
+	pdram_timing->tmrr = 0;
+	/*ODT*/
+	pdram_timing->todton = pdram_timing->cwl - 2;
+	/*ZQ*/
+	tmp = ((DDR3_TZQINIT * nmhz + 999) / 1000);
+	pdram_timing->tzqinit = max(512, tmp);
+	tmp = ((DDR3_TZQCS * nmhz + 999) / 1000);
+	pdram_timing->tzqcs = max(64, tmp);
+	tmp = ((DDR3_TZQOPER * nmhz + 999) / 1000);
+	pdram_timing->tzqoper = max(256, tmp);
+	/* write leveling */
+	pdram_timing->twlmrd = DDR3_TWLMRD;
+	pdram_timing->twldqsen = DDR3_TWLDQSEN;
+	pdram_timing->twlo = ((DDR3_TWLO * nmhz + (nmhz >> 1) + 999) / 1000);
+}
+
+#define LPDDR2_TINIT1		(100) /* ns */
+#define LPDDR2_TINIT2		(5) /* tCK */
+#define LPDDR2_TINIT3		(200000) /* 200us */
+#define LPDDR2_TINIT4		(1000) /* 1us */
+#define LPDDR2_TINIT5		(10000) /* 10us */
+#define LPDDR2_TRSTL		(0) /* tCK */
+#define LPDDR2_TRSTH		(500000) /* 500us */
+#define LPDDR2_TREFI_3_9_US	(3900) /* 3.9us */
+#define LPDDR2_TREFI_7_8_US	(7800) /* 7.8us */
+
+/* base timing */
+#define LPDDR2_TRCD		(24) /* tRCD,15ns(Fast)18ns(Typ)24ns(Slow) */
+#define LPDDR2_TRP_PB		(18) /* tRPpb,15ns(Fast)18ns(Typ)24ns(Slow) */
+#define LPDDR2_TRP_AB_8_BANK	(21) /* tRPab,18ns(Fast)21ns(Typ)27ns(Slow) */
+#define LPDDR2_TWR		(15) /* tWR, max(3tCK,15ns) */
+#define LPDDR2_TRTP		(7) /* tRTP, max(2tCK, 7.5ns) */
+#define LPDDR2_TRRD		(10) /* tRRD, max(2tCK,10ns) */
+#define LPDDR2_TCCD		(2) /* tCK */
+#define LPDDR2_TWTR_GREAT_200MHZ	(7) /* ns */
+#define LPDDR2_TWTR_LITTLE_200MHZ	(10) /* ns */
+#define LPDDR2_TRTW		(0) /* tCK */
+#define LPDDR2_TRAS_MAX		(70000) /* 70us */
+#define LPDDR2_TRAS		(42) /* tRAS, max(3tCK,42ns) */
+#define LPDDR2_TFAW_GREAT_200MHZ	(50) /* max(8tCK,50ns) */
+#define LPDDR2_TFAW_LITTLE_200MHZ	(60) /* max(8tCK,60ns) */
+#define LPDDR2_TRFC_8GBIT	(210) /* ns */
+#define LPDDR2_TRFC_4GBIT	(130) /* ns */
+#define LPDDR2_TDQSCK_MIN	(2) /* tDQSCKmin, 2.5ns */
+#define LPDDR2_TDQSCK_MAX	(5) /* tDQSCKmax, 5.5ns */
+
+/*pd and sr*/
+#define LPDDR2_TXP		(7) /* tXP, max(2tCK,7.5ns) */
+#define LPDDR2_TXPDLL		(0)
+#define LPDDR2_TDLLK		(0) /* tCK */
+#define LPDDR2_TCKE		(3) /* tCK */
+#define LPDDR2_TCKESR		(15) /* tCKESR, max(3tCK,15ns) */
+#define LPDDR2_TCKSRE		(1) /* tCK */
+#define LPDDR2_TCKSRX		(2) /* tCK */
+
+/*mode register timing*/
+#define LPDDR2_TMOD		(0)
+#define LPDDR2_TMRD		(5) /* tMRD, (=tMRW), 5 tCK */
+#define LPDDR2_TMRR		(2) /* tCK */
+
+/*ZQ*/
+#define LPDDR2_TZQINIT		(1000) /* ns */
+#define LPDDR2_TZQCS		(90) /* tZQCS, max(6tCK,90ns) */
+#define LPDDR2_TZQCL		(360) /* tZQCL, max(6tCK,360ns) */
+#define LPDDR2_TZQRESET		(50) /* ZQreset, max(3tCK,50ns) */
+
+/*
+ * Description: depend on input parameter "timing_config",
+ *		and calculate all lpddr2
+ *		spec timing to "pdram_timing"
+ * parameters:
+ *   input: timing_config
+ *   output: pdram_timing
+ */
+static void lpddr2_get_parameter(struct timing_related_config *timing_config,
+				 struct dram_timing_t *pdram_timing)
+{
+	uint32_t nmhz = timing_config->freq;
+	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
+	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp;
+
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
+	pdram_timing->mhz = nmhz;
+	pdram_timing->al = 0;
+	pdram_timing->bl = timing_config->bl;
+
+	/*	   1066 933 800 667 533 400 333
+	 * RL,	 8	 7	 6	 5	 4	 3	 3
+	 * WL,	 4	 4	 3	 2	 2	 1	 1
+	 */
+	if (nmhz <= 266) {
+		pdram_timing->cl = 4;
+		pdram_timing->cwl = 2;
+		pdram_timing->mr[2] = LPDDR2_RL4_WL2;
+	} else if (nmhz <= 333) {
+		pdram_timing->cl = 5;
+		pdram_timing->cwl = 2;
+		pdram_timing->mr[2] = LPDDR2_RL5_WL2;
+	} else if (nmhz <= 400) {
+		pdram_timing->cl = 6;
+		pdram_timing->cwl = 3;
+		pdram_timing->mr[2] = LPDDR2_RL6_WL3;
+	} else if (nmhz <= 466) {
+		pdram_timing->cl = 7;
+		pdram_timing->cwl = 4;
+		pdram_timing->mr[2] = LPDDR2_RL7_WL4;
+	} else {
+		pdram_timing->cl = 8;
+		pdram_timing->cwl = 4;
+		pdram_timing->mr[2] = LPDDR2_RL8_WL4;
+	}
+	switch (timing_config->dramds) {
+	case 120:
+		pdram_timing->mr[3] = LPDDR2_DS_120;
+		break;
+	case 80:
+		pdram_timing->mr[3] = LPDDR2_DS_80;
+		break;
+	case 60:
+		pdram_timing->mr[3] = LPDDR2_DS_60;
+		break;
+	case 48:
+		pdram_timing->mr[3] = LPDDR2_DS_48;
+		break;
+	case 40:
+		pdram_timing->mr[3] = LPDDR2_DS_40;
+		break;
+	case 34:
+	default:
+		pdram_timing->mr[3] = LPDDR2_DS_34;
+		break;
+	}
+	pdram_timing->mr[0] = 0;
+
+	pdram_timing->tinit1 = (LPDDR2_TINIT1 * nmhz + 999) / 1000;
+	pdram_timing->tinit2 = LPDDR2_TINIT2;
+	pdram_timing->tinit3 = (LPDDR2_TINIT3 * nmhz + 999) / 1000;
+	pdram_timing->tinit4 = (LPDDR2_TINIT4 * nmhz + 999) / 1000;
+	pdram_timing->tinit5 = (LPDDR2_TINIT5 * nmhz + 999) / 1000;
+	pdram_timing->trstl = LPDDR2_TRSTL;
+	pdram_timing->trsth = (LPDDR2_TRSTH * nmhz + 999) / 1000;
+	/*
+	 * tREFI, average periodic refresh interval,
+	 * 15.6us(<256Mb) 7.8us(256Mb-1Gb) 3.9us(2Gb-8Gb)
+	 */
+	if (ddr_capability_per_die >= 0x10000000)
+		pdram_timing->trefi = (LPDDR2_TREFI_3_9_US * nmhz + 999)
+							/ 1000;
+	else
+		pdram_timing->trefi = (LPDDR2_TREFI_7_8_US * nmhz + 999)
+							/ 1000;
+	/* base timing */
+	tmp = ((LPDDR2_TRCD * nmhz + 999) / 1000);
+	pdram_timing->trcd = max(3, tmp);
+	/*
+	 * tRPpb, max(3tCK, 15ns(Fast) 18ns(Typ) 24ns(Slow),
+	 */
+	trppb_tmp = ((LPDDR2_TRP_PB * nmhz + 999) / 1000);
+	trppb_tmp = max(3, trppb_tmp);
+	pdram_timing->trppb = trppb_tmp;
+	/*
+	 * tRPab, max(3tCK, 4-bank:15ns(Fast) 18ns(Typ) 24ns(Slow),
+	 *	8-bank:18ns(Fast) 21ns(Typ) 27ns(Slow))
+	 */
+	trp_tmp = ((LPDDR2_TRP_AB_8_BANK * nmhz + 999) / 1000);
+	trp_tmp = max(3, trp_tmp);
+	pdram_timing->trp = trp_tmp;
+	twr_tmp = ((LPDDR2_TWR * nmhz + 999) / 1000);
+	twr_tmp = max(3, twr_tmp);
+	pdram_timing->twr = twr_tmp;
+	bl_tmp = (pdram_timing->bl == 16) ? LPDDR2_BL16 :
+			((pdram_timing->bl == 8) ? LPDDR2_BL8 : LPDDR2_BL4);
+	pdram_timing->mr[1] = bl_tmp | LPDDR2_N_WR(twr_tmp);
+	tmp = ((LPDDR2_TRTP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->trtp = max(2, tmp);
+	tras_tmp = ((LPDDR2_TRAS * nmhz + 999) / 1000);
+	tras_tmp = max(3, tras_tmp);
+	pdram_timing->tras_min = tras_tmp;
+	pdram_timing->tras_max = ((LPDDR2_TRAS_MAX * nmhz + 999) / 1000);
+	pdram_timing->trc = (tras_tmp + trp_tmp);
+	tmp = ((LPDDR2_TRRD * nmhz + 999) / 1000);
+	pdram_timing->trrd = max(2, tmp);
+	pdram_timing->tccd = LPDDR2_TCCD;
+	/* tWTR, max(2tCK, 7.5ns(533-266MHz)  10ns(200-166MHz)) */
+	if (nmhz > 200)
+		tmp = ((LPDDR2_TWTR_GREAT_200MHZ * nmhz + (nmhz >> 1) +
+			  999) / 1000);
+	else
+		tmp = ((LPDDR2_TWTR_LITTLE_200MHZ * nmhz + 999) / 1000);
+	pdram_timing->twtr = max(2, tmp);
+	pdram_timing->trtw = LPDDR2_TRTW;
+	if (nmhz <= 200)
+		pdram_timing->tfaw = (LPDDR2_TFAW_LITTLE_200MHZ * nmhz + 999)
+							/ 1000;
+	else
+		pdram_timing->tfaw = (LPDDR2_TFAW_GREAT_200MHZ * nmhz + 999)
+							/ 1000;
+	/* tRFC, 90ns(<=512Mb) 130ns(1Gb-4Gb) 210ns(8Gb) */
+	if (ddr_capability_per_die >= 0x40000000) {
+		pdram_timing->trfc =
+			(LPDDR2_TRFC_8GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR2_TRFC_8GBIT + 10) * nmhz + 999) / 1000);
+	} else {
+		pdram_timing->trfc =
+			(LPDDR2_TRFC_4GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR2_TRFC_4GBIT + 10) * nmhz + 999) / 1000);
+	}
+	if (tmp < 2)
+		tmp = 2;
+	pdram_timing->txsr = tmp;
+	pdram_timing->txsnr = tmp;
+	/* tdqsck use rounded down */
+	pdram_timing->tdqsck = ((LPDDR2_TDQSCK_MIN * nmhz + (nmhz >> 1))
+					/ 1000);
+	pdram_timing->tdqsck_max =
+			((LPDDR2_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999)
+					/ 1000);
+	/* pd and sr */
+	tmp = ((LPDDR2_TXP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->txp = max(2, tmp);
+	pdram_timing->txpdll = LPDDR2_TXPDLL;
+	pdram_timing->tdllk = LPDDR2_TDLLK;
+	pdram_timing->tcke = LPDDR2_TCKE;
+	tmp = ((LPDDR2_TCKESR * nmhz + 999) / 1000);
+	pdram_timing->tckesr = max(3, tmp);
+	pdram_timing->tcksre = LPDDR2_TCKSRE;
+	pdram_timing->tcksrx = LPDDR2_TCKSRX;
+	/* mode register timing */
+	pdram_timing->tmod = LPDDR2_TMOD;
+	pdram_timing->tmrd = LPDDR2_TMRD;
+	pdram_timing->tmrr = LPDDR2_TMRR;
+	/* ZQ */
+	pdram_timing->tzqinit = (LPDDR2_TZQINIT * nmhz + 999) / 1000;
+	tmp = ((LPDDR2_TZQCS * nmhz + 999) / 1000);
+	pdram_timing->tzqcs = max(6, tmp);
+	tmp = ((LPDDR2_TZQCL * nmhz + 999) / 1000);
+	pdram_timing->tzqoper = max(6, tmp);
+	tmp = ((LPDDR2_TZQRESET * nmhz + 999) / 1000);
+	pdram_timing->tzqreset = max(3, tmp);
+}
+
+#define LPDDR3_TINIT1		(100) /* ns */
+#define LPDDR3_TINIT2		(5) /* tCK */
+#define LPDDR3_TINIT3		(200000) /* 200us */
+#define LPDDR3_TINIT4		(1000) /* 1us */
+#define LPDDR3_TINIT5		(10000) /* 10us */
+#define LPDDR3_TRSTL		(0)
+#define LPDDR3_TRSTH		(0) /* 500us */
+#define LPDDR3_TREFI_3_9_US	(3900) /* 3.9us */
+
+/* base timging */
+#define LPDDR3_TRCD	(18) /* tRCD,15ns(Fast)18ns(Typ)24ns(Slow) */
+#define LPDDR3_TRP_PB	(18) /* tRPpb, 15ns(Fast) 18ns(Typ) 24ns(Slow) */
+#define LPDDR3_TRP_AB	(21) /* tRPab, 18ns(Fast) 21ns(Typ) 27ns(Slow) */
+#define LPDDR3_TWR	(15) /* tWR, max(4tCK,15ns) */
+#define LPDDR3_TRTP	(7) /* tRTP, max(4tCK, 7.5ns) */
+#define LPDDR3_TRRD	(10) /* tRRD, max(2tCK,10ns) */
+#define LPDDR3_TCCD	(4) /* tCK */
+#define LPDDR3_TWTR	(7) /* tWTR, max(4tCK, 7.5ns) */
+#define LPDDR3_TRTW	(0) /* tCK register min valid value */
+#define LPDDR3_TRAS_MAX	(70000) /* 70us */
+#define LPDDR3_TRAS	(42) /* tRAS, max(3tCK,42ns) */
+#define LPDDR3_TFAW	(50) /* tFAW,max(8tCK, 50ns) */
+#define LPDDR3_TRFC_8GBIT	(210) /* tRFC, 130ns(4Gb) 210ns(>4Gb) */
+#define LPDDR3_TRFC_4GBIT	(130) /* ns */
+#define LPDDR3_TDQSCK_MIN	(2) /* tDQSCKmin,2.5ns */
+#define LPDDR3_TDQSCK_MAX	(5) /* tDQSCKmax,5.5ns */
+
+/* pd and sr */
+#define LPDDR3_TXP	(7) /* tXP, max(3tCK,7.5ns) */
+#define LPDDR3_TXPDLL	(0)
+#define LPDDR3_TCKE	(7) /* tCKE, (max 7.5ns,3 tCK) */
+#define LPDDR3_TCKESR	(15) /* tCKESR, max(3tCK,15ns) */
+#define LPDDR3_TCKSRE	(2) /* tCKSRE=tCPDED, 2 tCK */
+#define LPDDR3_TCKSRX	(2) /* tCKSRX, 2 tCK */
+
+/* mode register timing */
+#define LPDDR3_TMOD	(0)
+#define LPDDR3_TMRD	(14) /* tMRD, (=tMRW), max(14ns, 10 tCK) */
+#define LPDDR3_TMRR	(4) /* tMRR, 4 tCK */
+#define LPDDR3_TMRRI	LPDDR3_TRCD
+
+/* ODT */
+#define LPDDR3_TODTON	(3) /* 3.5ns */
+
+/* ZQ */
+#define LPDDR3_TZQINIT	(1000) /* 1us */
+#define LPDDR3_TZQCS	(90) /* tZQCS, 90ns */
+#define LPDDR3_TZQCL	(360) /* 360ns */
+#define LPDDR3_TZQRESET	(50) /* ZQreset, max(3tCK,50ns) */
+/* write leveling */
+#define LPDDR3_TWLMRD	(40) /* ns */
+#define LPDDR3_TWLO	(20) /* ns */
+#define LPDDR3_TWLDQSEN	(25) /* ns */
+/* CA training */
+#define LPDDR3_TCACKEL	(10) /* tCK */
+#define LPDDR3_TCAENT	(10) /* tCK */
+#define LPDDR3_TCAMRD	(20) /* tCK */
+#define LPDDR3_TCACKEH	(10) /* tCK */
+#define LPDDR3_TCAEXT	(10) /* tCK */
+#define LPDDR3_TADR	(20) /* ns */
+#define LPDDR3_TMRZ	(3) /* ns */
+
+/* FSP */
+#define LPDDR3_TFC_LONG	(250) /* ns */
+
+/*
+ * Description: depend on input parameter "timing_config",
+ *		and calculate all lpddr3
+ *		spec timing to "pdram_timing"
+ * parameters:
+ *   input: timing_config
+ *   output: pdram_timing
+ */
+static void lpddr3_get_parameter(struct timing_related_config *timing_config,
+				 struct dram_timing_t *pdram_timing)
+{
+	uint32_t nmhz = timing_config->freq;
+	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
+	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp;
+
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
+	pdram_timing->mhz = nmhz;
+	pdram_timing->al = 0;
+	pdram_timing->bl = timing_config->bl;
+
+	/*
+	 * Only support Write Latency Set A here
+	 *     1066 933 800 733 667 600 533 400 166
+	 * RL, 16   14  12  11  10  9   8   6   3
+	 * WL, 8    8   6   6   6   5   4   3   1
+	 */
+	if (nmhz <= 400) {
+		pdram_timing->cl = 6;
+		pdram_timing->cwl = 3;
+		pdram_timing->mr[2] = LPDDR3_RL6_WL3;
+	} else if (nmhz <= 533) {
+		pdram_timing->cl = 8;
+		pdram_timing->cwl = 4;
+		pdram_timing->mr[2] = LPDDR3_RL8_WL4;
+	} else if (nmhz <= 600) {
+		pdram_timing->cl = 9;
+		pdram_timing->cwl = 5;
+		pdram_timing->mr[2] = LPDDR3_RL9_WL5;
+	} else if (nmhz <= 667) {
+		pdram_timing->cl = 10;
+		pdram_timing->cwl = 6;
+		pdram_timing->mr[2] = LPDDR3_RL10_WL6;
+	} else if (nmhz <= 733) {
+		pdram_timing->cl = 11;
+		pdram_timing->cwl = 6;
+		pdram_timing->mr[2] = LPDDR3_RL11_WL6;
+	} else if (nmhz <= 800) {
+		pdram_timing->cl = 12;
+		pdram_timing->cwl = 6;
+		pdram_timing->mr[2] = LPDDR3_RL12_WL6;
+	} else if (nmhz <= 933) {
+		pdram_timing->cl = 14;
+		pdram_timing->cwl = 8;
+		pdram_timing->mr[2] = LPDDR3_RL14_WL8;
+	} else {
+		pdram_timing->cl = 16;
+		pdram_timing->cwl = 8;
+		pdram_timing->mr[2] = LPDDR3_RL16_WL8;
+	}
+	switch (timing_config->dramds) {
+	case 80:
+		pdram_timing->mr[3] = LPDDR3_DS_80;
+		break;
+	case 60:
+		pdram_timing->mr[3] = LPDDR3_DS_60;
+		break;
+	case 48:
+		pdram_timing->mr[3] = LPDDR3_DS_48;
+		break;
+	case 40:
+		pdram_timing->mr[3] = LPDDR3_DS_40;
+		break;
+	case 3440:
+		pdram_timing->mr[3] = LPDDR3_DS_34D_40U;
+		break;
+	case 4048:
+		pdram_timing->mr[3] = LPDDR3_DS_40D_48U;
+		break;
+	case 3448:
+		pdram_timing->mr[3] = LPDDR3_DS_34D_48U;
+		break;
+	case 34:
+	default:
+		pdram_timing->mr[3] = LPDDR3_DS_34;
+		break;
+	}
+	pdram_timing->mr[0] = 0;
+	if (timing_config->odt)
+		switch (timing_config->dramodt) {
+		case 60:
+			pdram_timing->mr11 = LPDDR3_ODT_60;
+			break;
+		case 120:
+			pdram_timing->mr11 = LPDDR3_ODT_120;
+			break;
+		case 240:
+		default:
+			pdram_timing->mr11 = LPDDR3_ODT_240;
+			break;
+		}
+	else
+		pdram_timing->mr11 = LPDDR3_ODT_DIS;
+
+	pdram_timing->tinit1 = (LPDDR3_TINIT1 * nmhz + 999) / 1000;
+	pdram_timing->tinit2 = LPDDR3_TINIT2;
+	pdram_timing->tinit3 = (LPDDR3_TINIT3 * nmhz + 999) / 1000;
+	pdram_timing->tinit4 = (LPDDR3_TINIT4 * nmhz + 999) / 1000;
+	pdram_timing->tinit5 = (LPDDR3_TINIT5 * nmhz + 999) / 1000;
+	pdram_timing->trstl = LPDDR3_TRSTL;
+	pdram_timing->trsth = (LPDDR3_TRSTH * nmhz + 999) / 1000;
+	/* tREFI, average periodic refresh interval, 3.9us(4Gb-16Gb) */
+	pdram_timing->trefi = (LPDDR3_TREFI_3_9_US * nmhz + 999) / 1000;
+	/* base timing */
+	tmp = ((LPDDR3_TRCD * nmhz + 999) / 1000);
+	pdram_timing->trcd = max(3, tmp);
+	trppb_tmp = ((LPDDR3_TRP_PB * nmhz + 999) / 1000);
+	trppb_tmp = max(3, trppb_tmp);
+	pdram_timing->trppb = trppb_tmp;
+	trp_tmp = ((LPDDR3_TRP_AB * nmhz + 999) / 1000);
+	trp_tmp = max(3, trp_tmp);
+	pdram_timing->trp = trp_tmp;
+	twr_tmp = ((LPDDR3_TWR * nmhz + 999) / 1000);
+	twr_tmp = max(4, twr_tmp);
+	pdram_timing->twr = twr_tmp;
+	if (twr_tmp <= 6)
+		twr_tmp = 6;
+	else if (twr_tmp <= 8)
+		twr_tmp = 8;
+	else if (twr_tmp <= 12)
+		twr_tmp = twr_tmp;
+	else if (twr_tmp <= 14)
+		twr_tmp = 14;
+	else
+		twr_tmp = 16;
+	if (twr_tmp > 9)
+		pdram_timing->mr[2] |= (1 << 4); /*enable nWR > 9*/
+	twr_tmp = (twr_tmp > 9) ? (twr_tmp - 10) : (twr_tmp - 2);
+	bl_tmp = LPDDR3_BL8;
+	pdram_timing->mr[1] = bl_tmp | LPDDR3_N_WR(twr_tmp);
+	tmp = ((LPDDR3_TRTP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->trtp = max(4, tmp);
+	tras_tmp = ((LPDDR3_TRAS * nmhz + 999) / 1000);
+	tras_tmp = max(3, tras_tmp);
+	pdram_timing->tras_min = tras_tmp;
+	pdram_timing->trc = (tras_tmp + trp_tmp);
+	tmp = ((LPDDR3_TRRD * nmhz + 999) / 1000);
+	pdram_timing->trrd = max(2, tmp);
+	pdram_timing->tccd = LPDDR3_TCCD;
+	tmp = ((LPDDR3_TWTR * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->twtr = max(4, tmp);
+	pdram_timing->trtw =  ((LPDDR3_TRTW * nmhz + 999) / 1000);
+	pdram_timing->tras_max = ((LPDDR3_TRAS_MAX * nmhz + 999) / 1000);
+	tmp = (LPDDR3_TFAW * nmhz + 999) / 1000;
+	pdram_timing->tfaw = max(8, tmp);
+	if (ddr_capability_per_die > 0x20000000) {
+		pdram_timing->trfc =
+			(LPDDR3_TRFC_8GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR3_TRFC_8GBIT + 10) * nmhz + 999) / 1000);
+	} else {
+		pdram_timing->trfc =
+			(LPDDR3_TRFC_4GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR3_TRFC_4GBIT + 10) * nmhz + 999) / 1000);
+	}
+	pdram_timing->txsr = max(2, tmp);
+	pdram_timing->txsnr = max(2, tmp);
+	/* tdqsck use rounded down */
+	pdram_timing->tdqsck =
+			((LPDDR3_TDQSCK_MIN * nmhz + (nmhz >> 1))
+					/ 1000);
+	pdram_timing->tdqsck_max =
+			((LPDDR3_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999)
+					/ 1000);
+	/*pd and sr*/
+	tmp = ((LPDDR3_TXP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->txp = max(3, tmp);
+	pdram_timing->txpdll = LPDDR3_TXPDLL;
+	tmp = ((LPDDR3_TCKE * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->tcke = max(3, tmp);
+	tmp = ((LPDDR3_TCKESR * nmhz + 999) / 1000);
+	pdram_timing->tckesr = max(3, tmp);
+	pdram_timing->tcksre = LPDDR3_TCKSRE;
+	pdram_timing->tcksrx = LPDDR3_TCKSRX;
+	/*mode register timing*/
+	pdram_timing->tmod = LPDDR3_TMOD;
+	tmp = ((LPDDR3_TMRD * nmhz + 999) / 1000);
+	pdram_timing->tmrd = max(10, tmp);
+	pdram_timing->tmrr = LPDDR3_TMRR;
+	tmp = ((LPDDR3_TRCD * nmhz + 999) / 1000);
+	pdram_timing->tmrri = max(3, tmp);
+	/* ODT */
+	pdram_timing->todton = (LPDDR3_TODTON * nmhz + (nmhz >> 1) + 999)
+				/ 1000;
+	/* ZQ */
+	pdram_timing->tzqinit = (LPDDR3_TZQINIT * nmhz + 999) / 1000;
+	pdram_timing->tzqcs =
+		((LPDDR3_TZQCS * nmhz + 999) / 1000);
+	pdram_timing->tzqoper =
+		((LPDDR3_TZQCL * nmhz + 999) / 1000);
+	tmp = ((LPDDR3_TZQRESET * nmhz + 999) / 1000);
+	pdram_timing->tzqreset = max(3, tmp);
+	/* write leveling */
+	pdram_timing->twlmrd = (LPDDR3_TWLMRD * nmhz + 999) / 1000;
+	pdram_timing->twlo = (LPDDR3_TWLO * nmhz + 999) / 1000;
+	pdram_timing->twldqsen = (LPDDR3_TWLDQSEN * nmhz + 999) / 1000;
+	/* CA training */
+	pdram_timing->tcackel = LPDDR3_TCACKEL;
+	pdram_timing->tcaent = LPDDR3_TCAENT;
+	pdram_timing->tcamrd = LPDDR3_TCAMRD;
+	pdram_timing->tcackeh = LPDDR3_TCACKEH;
+	pdram_timing->tcaext = LPDDR3_TCAEXT;
+	pdram_timing->tadr = (LPDDR3_TADR * nmhz + 999) / 1000;
+	pdram_timing->tmrz = (LPDDR3_TMRZ * nmhz + 999) / 1000;
+	pdram_timing->tcacd = pdram_timing->tadr + 2;
+
+	/* FSP */
+	pdram_timing->tfc_long = (LPDDR3_TFC_LONG * nmhz + 999) / 1000;
+}
+
+#define LPDDR4_TINIT1	(200000) /* 200us */
+#define LPDDR4_TINIT2	(10) /* 10ns */
+#define LPDDR4_TINIT3	(2000000) /* 2ms */
+#define LPDDR4_TINIT4	(5) /* tCK */
+#define LPDDR4_TINIT5	(2000) /* 2us */
+#define LPDDR4_TRSTL		LPDDR4_TINIT1
+#define LPDDR4_TRSTH		LPDDR4_TINIT3
+#define LPDDR4_TREFI_3_9_US	(3900) /* 3.9us */
+
+/* base timging */
+#define LPDDR4_TRCD	(18) /* tRCD, max(18ns,4tCK) */
+#define LPDDR4_TRP_PB	(18) /* tRPpb, max(18ns, 4tCK) */
+#define LPDDR4_TRP_AB	(21) /* tRPab, max(21ns, 4tCK) */
+#define LPDDR4_TRRD	(10) /* tRRD, max(4tCK,10ns) */
+#define LPDDR4_TCCD_BL16	(8) /* tCK */
+#define LPDDR4_TCCD_BL32	(16) /* tCK */
+#define LPDDR4_TWTR	(10) /* tWTR, max(8tCK, 10ns) */
+#define LPDDR4_TRTW	(0) /* tCK register min valid value */
+#define LPDDR4_TRAS_MAX (70000) /* 70us */
+#define LPDDR4_TRAS	(42) /* tRAS, max(3tCK,42ns) */
+#define LPDDR4_TFAW	(40) /* tFAW,min 40ns) */
+#define LPDDR4_TRFC_12GBIT	(280) /* tRFC, 280ns(>=12Gb) */
+#define LPDDR4_TRFC_6GBIT	(180) /* 6Gb/8Gb 180ns */
+#define LPDDR4_TRFC_4GBIT	(130) /* 4Gb 130ns */
+#define LPDDR4_TDQSCK_MIN	(1) /* tDQSCKmin,1.5ns */
+#define LPDDR4_TDQSCK_MAX	(3) /* tDQSCKmax,3.5ns */
+#define LPDDR4_TPPD		(4) /* tCK */
+
+/* pd and sr */
+#define LPDDR4_TXP	(7) /* tXP, max(5tCK,7.5ns) */
+#define LPDDR4_TCKE	(7) /* tCKE, max(7.5ns,4 tCK) */
+#define LPDDR4_TESCKE	(1) /* tESCKE, max(1.75ns, 3tCK) */
+#define LPDDR4_TSR	(15) /* tSR, max(15ns, 3tCK) */
+#define LPDDR4_TCMDCKE	(1) /* max(1.75ns, 3tCK) */
+#define LPDDR4_TCSCKE	(1) /* 1.75ns */
+#define LPDDR4_TCKELCS	(5) /* max(5ns, 5tCK) */
+#define LPDDR4_TCSCKEH	(1) /* 1.75ns */
+#define LPDDR4_TCKEHCS	(7) /* max(7.5ns, 5tCK) */
+#define LPDDR4_TMRWCKEL	(14) /* max(14ns, 10tCK) */
+#define LPDDR4_TCKELCMD	(7) /* max(7.5ns, 3tCK) */
+#define LPDDR4_TCKEHCMD	(7) /* max(7.5ns, 3tCK) */
+#define LPDDR4_TCKELPD	(7) /* max(7.5ns, 3tCK) */
+#define LPDDR4_TCKCKEL	(7) /* max(7.5ns, 3tCK) */
+
+/* mode register timing */
+#define LPDDR4_TMRD	(14) /* tMRD, (=tMRW), max(14ns, 10 tCK) */
+#define LPDDR4_TMRR	(8) /* tMRR, 8 tCK */
+
+/* ODT */
+#define LPDDR4_TODTON	(3) /* 3.5ns */
+
+/* ZQ */
+#define LPDDR4_TZQCAL	(1000) /* 1us */
+#define LPDDR4_TZQLAT	(30) /* tZQLAT, max(30ns,8tCK) */
+#define LPDDR4_TZQRESET (50) /* ZQreset, max(3tCK,50ns) */
+#define LPDDR4_TZQCKE	(1) /* tZQCKE, max(1.75ns, 3tCK) */
+
+/* write leveling */
+#define LPDDR4_TWLMRD	(40) /* tCK */
+#define LPDDR4_TWLO	(20) /* ns */
+#define LPDDR4_TWLDQSEN (20) /* tCK */
+
+/* CA training */
+#define LPDDR4_TCAENT	(250) /* ns */
+#define LPDDR4_TADR	(20) /* ns */
+#define LPDDR4_TMRZ	(1) /* 1.5ns */
+#define LPDDR4_TVREF_LONG	(250) /* ns */
+#define LPDDR4_TVREF_SHORT	(100) /* ns */
+
+/* VRCG */
+#define LPDDR4_TVRCG_ENABLE	(200) /* ns */
+#define LPDDR4_TVRCG_DISABLE	(100) /* ns */
+
+/* FSP */
+#define LPDDR4_TFC_LONG		(250) /* ns */
+#define LPDDR4_TCKFSPE		(7) /* max(7.5ns, 4tCK) */
+#define LPDDR4_TCKFSPX		(7) /* max(7.5ns, 4tCK) */
+
+/*
+ * Description: depend on input parameter "timing_config",
+ *              and calculate all lpddr4
+ *              spec timing to "pdram_timing"
+ * parameters:
+ *   input: timing_config
+ *   output: pdram_timing
+ */
+static void lpddr4_get_parameter(struct timing_related_config *timing_config,
+				 struct dram_timing_t *pdram_timing)
+{
+	uint32_t nmhz = timing_config->freq;
+	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
+	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp;
+
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
+	pdram_timing->mhz = nmhz;
+	pdram_timing->al = 0;
+	pdram_timing->bl = timing_config->bl;
+
+	/*
+	 * Only support Write Latency Set A here
+	 *      2133 1866 1600 1333 1066 800 533 266
+	 *  RL, 36   32   28   24   20   14  10  6
+	 *  WL, 18   16   14   12   10   8   6   4
+	 * nWR, 40   34   30   24   20   16  10  6
+	 * nRTP,16   14   12   10   8    8   8   8
+	 */
+	tmp = (timing_config->bl == 32) ? 1 : 0;
+
+	/*
+	 * we always use WR preamble = 2tCK
+	 * RD preamble = Static
+	 */
+	tmp |= (1 << 2);
+	if (nmhz <= 266) {
+		pdram_timing->cl = 6;
+		pdram_timing->cwl = 4;
+		pdram_timing->twr = 6;
+		pdram_timing->trtp = 8;
+		pdram_timing->mr[2] = LPDDR4_RL6_NRTP8 | LPDDR4_A_WL4;
+	} else if (nmhz <= 533) {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 12;
+			pdram_timing->mr[2] = LPDDR4_RL12_NRTP8 | LPDDR4_A_WL6;
+		} else {
+			pdram_timing->cl = 10;
+			pdram_timing->mr[2] = LPDDR4_RL10_NRTP8 | LPDDR4_A_WL6;
+		}
+		pdram_timing->cwl = 6;
+		pdram_timing->twr = 10;
+		pdram_timing->trtp = 8;
+		tmp |= (1 << 4);
+	} else if (nmhz <= 800) {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 16;
+			pdram_timing->mr[2] = LPDDR4_RL16_NRTP8 | LPDDR4_A_WL8;
+		} else {
+			pdram_timing->cl = 14;
+			pdram_timing->mr[2] = LPDDR4_RL14_NRTP8 | LPDDR4_A_WL8;
+		}
+		pdram_timing->cwl = 8;
+		pdram_timing->twr = 16;
+		pdram_timing->trtp = 8;
+		tmp |= (2 << 4);
+	} else if (nmhz <= 1066) {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 22;
+			pdram_timing->mr[2] = LPDDR4_RL22_NRTP8 | LPDDR4_A_WL10;
+		} else {
+			pdram_timing->cl = 20;
+			pdram_timing->mr[2] = LPDDR4_RL20_NRTP8 | LPDDR4_A_WL10;
+		}
+		pdram_timing->cwl = 10;
+		pdram_timing->twr = 20;
+		pdram_timing->trtp = 8;
+		tmp |= (3 << 4);
+	} else if (nmhz <= 1333) {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 28;
+			pdram_timing->mr[2] = LPDDR4_RL28_NRTP10 |
+						LPDDR4_A_WL12;
+		} else {
+			pdram_timing->cl = 24;
+			pdram_timing->mr[2] = LPDDR4_RL24_NRTP10 |
+						LPDDR4_A_WL12;
+		}
+		pdram_timing->cwl = 12;
+		pdram_timing->twr = 24;
+		pdram_timing->trtp = 10;
+		tmp |= (4 << 4);
+	} else if (nmhz <= 1600) {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 32;
+			pdram_timing->mr[2] = LPDDR4_RL32_NRTP12 |
+						LPDDR4_A_WL14;
+		} else {
+			pdram_timing->cl = 28;
+			pdram_timing->mr[2] = LPDDR4_RL28_NRTP12 |
+						LPDDR4_A_WL14;
+		}
+		pdram_timing->cwl = 14;
+		pdram_timing->twr = 30;
+		pdram_timing->trtp = 12;
+		tmp |= (5 << 4);
+	} else if (nmhz <= 1866) {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 36;
+			pdram_timing->mr[2] = LPDDR4_RL36_NRTP14 |
+						LPDDR4_A_WL16;
+		} else {
+			pdram_timing->cl = 32;
+			pdram_timing->mr[2] = LPDDR4_RL32_NRTP14 |
+						LPDDR4_A_WL16;
+		}
+		pdram_timing->cwl = 16;
+		pdram_timing->twr = 34;
+		pdram_timing->trtp = 14;
+		tmp |= (6 << 4);
+	} else {
+		if (timing_config->rdbi) {
+			pdram_timing->cl = 40;
+			pdram_timing->mr[2] = LPDDR4_RL40_NRTP16 |
+						LPDDR4_A_WL18;
+		} else {
+			pdram_timing->cl = 36;
+			pdram_timing->mr[2] = LPDDR4_RL36_NRTP16 |
+						LPDDR4_A_WL18;
+		}
+		pdram_timing->cwl = 18;
+		pdram_timing->twr = 40;
+		pdram_timing->trtp = 16;
+		tmp |= (7 << 4);
+	}
+	pdram_timing->mr[1] = tmp;
+	tmp = (timing_config->rdbi ? LPDDR4_DBI_RD_EN : 0) |
+	      (timing_config->wdbi ? LPDDR4_DBI_WR_EN : 0);
+	switch (timing_config->dramds) {
+	case 240:
+		pdram_timing->mr[3] = LPDDR4_PDDS_240 | tmp;
+		break;
+	case 120:
+		pdram_timing->mr[3] = LPDDR4_PDDS_120 | tmp;
+		break;
+	case 80:
+		pdram_timing->mr[3] = LPDDR4_PDDS_80 | tmp;
+		break;
+	case 60:
+		pdram_timing->mr[3] = LPDDR4_PDDS_60 | tmp;
+		break;
+	case 48:
+		pdram_timing->mr[3] = LPDDR4_PDDS_48 | tmp;
+		break;
+	case 40:
+	default:
+		pdram_timing->mr[3] = LPDDR4_PDDS_40 | tmp;
+		break;
+	}
+	pdram_timing->mr[0] = 0;
+	if (timing_config->odt) {
+		switch (timing_config->dramodt) {
+		case 240:
+			tmp = LPDDR4_DQODT_240;
+			break;
+		case 120:
+			tmp = LPDDR4_DQODT_120;
+			break;
+		case 80:
+			tmp = LPDDR4_DQODT_80;
+			break;
+		case 60:
+			tmp = LPDDR4_DQODT_60;
+			break;
+		case 48:
+			tmp = LPDDR4_DQODT_48;
+			break;
+		case 40:
+		default:
+			tmp = LPDDR4_DQODT_40;
+			break;
+		}
+
+		switch (timing_config->caodt) {
+		case 240:
+			pdram_timing->mr11 = LPDDR4_CAODT_240 | tmp;
+			break;
+		case 120:
+			pdram_timing->mr11 = LPDDR4_CAODT_120 | tmp;
+			break;
+		case 80:
+			pdram_timing->mr11 = LPDDR4_CAODT_80 | tmp;
+			break;
+		case 60:
+			pdram_timing->mr11 = LPDDR4_CAODT_60 | tmp;
+			break;
+		case 48:
+			pdram_timing->mr11 = LPDDR4_CAODT_48 | tmp;
+			break;
+		case 40:
+		default:
+			pdram_timing->mr11 = LPDDR4_CAODT_40 | tmp;
+			break;
+		}
+	} else {
+		pdram_timing->mr11 = LPDDR4_CAODT_DIS | tmp;
+	}
+
+	pdram_timing->tinit1 = (LPDDR4_TINIT1 * nmhz + 999) / 1000;
+	pdram_timing->tinit2 = (LPDDR4_TINIT2 * nmhz + 999) / 1000;
+	pdram_timing->tinit3 = (LPDDR4_TINIT3 * nmhz + 999) / 1000;
+	pdram_timing->tinit4 = (LPDDR4_TINIT4 * nmhz + 999) / 1000;
+	pdram_timing->tinit5 = (LPDDR4_TINIT5 * nmhz + 999) / 1000;
+	pdram_timing->trstl = (LPDDR4_TRSTL * nmhz + 999) / 1000;
+	pdram_timing->trsth = (LPDDR4_TRSTH * nmhz + 999) / 1000;
+	/* tREFI, average periodic refresh interval, 3.9us(4Gb-16Gb) */
+	pdram_timing->trefi = (LPDDR4_TREFI_3_9_US * nmhz + 999) / 1000;
+	/* base timing */
+	tmp = ((LPDDR4_TRCD * nmhz + 999) / 1000);
+	pdram_timing->trcd = max(4, tmp);
+	trppb_tmp = ((LPDDR4_TRP_PB * nmhz + 999) / 1000);
+	trppb_tmp = max(4, trppb_tmp);
+	pdram_timing->trppb = trppb_tmp;
+	trp_tmp = ((LPDDR4_TRP_AB * nmhz + 999) / 1000);
+	trp_tmp = max(4, trp_tmp);
+	pdram_timing->trp = trp_tmp;
+	tras_tmp = ((LPDDR4_TRAS * nmhz + 999) / 1000);
+	tras_tmp = max(3, tras_tmp);
+	pdram_timing->tras_min = tras_tmp;
+	pdram_timing->trc = (tras_tmp + trp_tmp);
+	tmp = ((LPDDR4_TRRD * nmhz + 999) / 1000);
+	pdram_timing->trrd = max(4, tmp);
+	if (timing_config->bl == 32)
+		pdram_timing->tccd = LPDDR4_TCCD_BL16;
+	else
+		pdram_timing->tccd = LPDDR4_TCCD_BL32;
+	pdram_timing->tccdmw = 4 * pdram_timing->tccd;
+	tmp = ((LPDDR4_TWTR * nmhz + 999) / 1000);
+	pdram_timing->twtr = max(8, tmp);
+	pdram_timing->trtw =  ((LPDDR4_TRTW * nmhz + 999) / 1000);
+	pdram_timing->tras_max = ((LPDDR4_TRAS_MAX * nmhz + 999) / 1000);
+	pdram_timing->tfaw = (LPDDR4_TFAW * nmhz + 999) / 1000;
+	if (ddr_capability_per_die > 0x60000000) {
+		/* >= 12Gb */
+		pdram_timing->trfc =
+			(LPDDR4_TRFC_12GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR4_TRFC_12GBIT + 7) * nmhz + (nmhz >> 1) +
+				999) / 1000);
+	} else if (ddr_capability_per_die > 0x30000000) {
+		pdram_timing->trfc =
+			(LPDDR4_TRFC_6GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR4_TRFC_6GBIT + 7) * nmhz + (nmhz >> 1) +
+				999) / 1000);
+	} else {
+		pdram_timing->trfc =
+			(LPDDR4_TRFC_4GBIT * nmhz + 999) / 1000;
+		tmp = (((LPDDR4_TRFC_4GBIT + 7) * nmhz + (nmhz >> 1) +
+				999) / 1000);
+	}
+	pdram_timing->txsr = max(2, tmp);
+	pdram_timing->txsnr = max(2, tmp);
+	/* tdqsck use rounded down */
+	pdram_timing->tdqsck =  ((LPDDR4_TDQSCK_MIN * nmhz +
+				(nmhz >> 1)) / 1000);
+	pdram_timing->tdqsck_max =  ((LPDDR4_TDQSCK_MAX * nmhz +
+				(nmhz >> 1) + 999) / 1000);
+	pdram_timing->tppd = LPDDR4_TPPD;
+	/* pd and sr */
+	tmp = ((LPDDR4_TXP * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->txp = max(5, tmp);
+	tmp = ((LPDDR4_TCKE * nmhz + (nmhz >> 1) + 999) / 1000);
+	pdram_timing->tcke = max(4, tmp);
+	tmp = ((LPDDR4_TESCKE * nmhz +
+		((nmhz * 3) / 4) +
+		999) / 1000);
+	pdram_timing->tescke = max(3, tmp);
+	tmp = ((LPDDR4_TSR * nmhz + 999) / 1000);
+	pdram_timing->tsr = max(3, tmp);
+	tmp = ((LPDDR4_TCMDCKE * nmhz +
+		((nmhz * 3) / 4) +
+		999) / 1000);
+	pdram_timing->tcmdcke = max(3, tmp);
+	pdram_timing->tcscke = ((LPDDR4_TCSCKE * nmhz +
+		((nmhz * 3) / 4) +
+		999) / 1000);
+	tmp = ((LPDDR4_TCKELCS * nmhz + 999) / 1000);
+	pdram_timing->tckelcs = max(5, tmp);
+	pdram_timing->tcsckeh = ((LPDDR4_TCSCKEH * nmhz +
+		((nmhz * 3) / 4) +
+		999) / 1000);
+	tmp = ((LPDDR4_TCKEHCS * nmhz +
+		(nmhz >> 1) + 999) / 1000);
+	pdram_timing->tckehcs = max(5, tmp);
+	tmp = ((LPDDR4_TMRWCKEL * nmhz + 999) / 1000);
+	pdram_timing->tmrwckel = max(10, tmp);
+	tmp = ((LPDDR4_TCKELCMD * nmhz + (nmhz >> 1) +
+		999) / 1000);
+	pdram_timing->tckelcmd = max(3, tmp);
+	tmp = ((LPDDR4_TCKEHCMD * nmhz + (nmhz >> 1) +
+		999) / 1000);
+	pdram_timing->tckehcmd = max(3, tmp);
+	tmp = ((LPDDR4_TCKELPD * nmhz + (nmhz >> 1) +
+		999) / 1000);
+	pdram_timing->tckelpd = max(3, tmp);
+	tmp = ((LPDDR4_TCKCKEL * nmhz + (nmhz >> 1) +
+		999) / 1000);
+	pdram_timing->tckckel = max(3, tmp);
+	/* mode register timing */
+	tmp = ((LPDDR4_TMRD * nmhz + 999) / 1000);
+	pdram_timing->tmrd = max(10, tmp);
+	pdram_timing->tmrr = LPDDR4_TMRR;
+	pdram_timing->tmrri = pdram_timing->trcd + 3;
+	/* ODT */
+	pdram_timing->todton = (LPDDR4_TODTON * nmhz + (nmhz >> 1) + 999)
+				/ 1000;
+	/* ZQ */
+	pdram_timing->tzqcal = (LPDDR4_TZQCAL * nmhz + 999) / 1000;
+	tmp = ((LPDDR4_TZQLAT * nmhz + 999) / 1000);
+	pdram_timing->tzqlat = max(8, tmp);
+	tmp = ((LPDDR4_TZQRESET * nmhz + 999) / 1000);
+	pdram_timing->tzqreset = max(3, tmp);
+	tmp = ((LPDDR4_TZQCKE * nmhz +
+		((nmhz * 3) / 4) +
+		999) / 1000);
+	pdram_timing->tzqcke = max(3, tmp);
+	/* write leveling */
+	pdram_timing->twlmrd = LPDDR4_TWLMRD;
+	pdram_timing->twlo = (LPDDR4_TWLO * nmhz + 999) / 1000;
+	pdram_timing->twldqsen = LPDDR4_TWLDQSEN;
+	/* CA training */
+	pdram_timing->tcaent = (LPDDR4_TCAENT * nmhz + 999) / 1000;
+	pdram_timing->tadr = (LPDDR4_TADR * nmhz + 999) / 1000;
+	pdram_timing->tmrz = (LPDDR4_TMRZ * nmhz + (nmhz >> 1) + 999) / 1000;
+	pdram_timing->tvref_long = (LPDDR4_TVREF_LONG * nmhz + 999) / 1000;
+	pdram_timing->tvref_short = (LPDDR4_TVREF_SHORT * nmhz + 999) / 1000;
+	/* VRCG */
+	pdram_timing->tvrcg_enable = (LPDDR4_TVRCG_ENABLE * nmhz +
+					999) / 1000;
+	pdram_timing->tvrcg_disable = (LPDDR4_TVRCG_DISABLE * nmhz +
+					999) / 1000;
+	/* FSP */
+	pdram_timing->tfc_long = (LPDDR4_TFC_LONG * nmhz + 999) / 1000;
+	tmp = (LPDDR4_TCKFSPE * nmhz + (nmhz >> 1) + 999) / 1000;
+	pdram_timing->tckfspe = max(4, tmp);
+	tmp = (LPDDR4_TCKFSPX * nmhz + (nmhz >> 1) + 999) / 1000;
+	pdram_timing->tckfspx = max(4, tmp);
+}
+
+/*
+ * Description: depend on input parameter "timing_config",
+ *              and calculate correspond "dram_type"
+ *              spec timing to "pdram_timing"
+ * parameters:
+ *   input: timing_config
+ *   output: pdram_timing
+ * NOTE: MR ODT is set, need to disable by controller
+ */
+void dram_get_parameter(struct timing_related_config *timing_config,
+			struct dram_timing_t *pdram_timing)
+{
+	switch (timing_config->dram_type) {
+	case DDR3:
+		ddr3_get_parameter(timing_config, pdram_timing);
+		break;
+	case LPDDR2:
+		lpddr2_get_parameter(timing_config, pdram_timing);
+		break;
+	case LPDDR3:
+		lpddr3_get_parameter(timing_config, pdram_timing);
+		break;
+	case LPDDR4:
+		lpddr4_get_parameter(timing_config, pdram_timing);
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
new file mode 100644
index 0000000..9cda22c
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_SPEC_TIMING_H
+#define DRAM_SPEC_TIMING_H
+
+#include <stdint.h>
+
+enum ddr3_speed_rate {
+	/* 5-5-5 */
+	DDR3_800D = 0,
+	/* 6-6-6 */
+	DDR3_800E = 1,
+	/* 6-6-6 */
+	DDR3_1066E = 2,
+	/* 7-7-7 */
+	DDR3_1066F = 3,
+	/* 8-8-8 */
+	DDR3_1066G = 4,
+	/* 7-7-7 */
+	DDR3_1333F = 5,
+	/* 8-8-8 */
+	DDR3_1333G = 6,
+	/* 9-9-9 */
+	DDR3_1333H = 7,
+	/* 10-10-10 */
+	DDR3_1333J = 8,
+	/* 8-8-8 */
+	DDR3_1600G = 9,
+	/* 9-9-9 */
+	DDR3_1600H = 10,
+	/* 10-10-10 */
+	DDR3_1600J = 11,
+	/* 11-11-11 */
+	DDR3_1600K = 12,
+	/* 10-10-10 */
+	DDR3_1866J = 13,
+	/* 11-11-11 */
+	DDR3_1866K = 14,
+	/* 12-12-12 */
+	DDR3_1866L = 15,
+	/* 13-13-13 */
+	DDR3_1866M = 16,
+	/* 11-11-11 */
+	DDR3_2133K = 17,
+	/* 12-12-12 */
+	DDR3_2133L = 18,
+	/* 13-13-13 */
+	DDR3_2133M = 19,
+	/* 14-14-14 */
+	DDR3_2133N = 20,
+	DDR3_DEFAULT = 21,
+};
+
+#define max(a, b)  (((a) > (b)) ? (a) : (b))
+#define range(mi, val, ma)  (((ma) > (val)) ? (max(mi, val)) : (ma))
+
+struct dram_timing_t {
+	/* unit MHz */
+	uint32_t mhz;
+	/* some timing unit is us */
+	uint32_t tinit1;
+	uint32_t tinit2;
+	uint32_t tinit3;
+	uint32_t tinit4;
+	uint32_t tinit5;
+	/* reset low, DDR3:200us */
+	uint32_t trstl;
+	/* reset high to CKE high, DDR3:500us  */
+	uint32_t trsth;
+	uint32_t trefi;
+	/* base */
+	uint32_t trcd;
+	/* trp per bank */
+	uint32_t trppb;
+	/* trp all bank */
+	uint32_t trp;
+	uint32_t twr;
+	uint32_t tdal;
+	uint32_t trtp;
+	uint32_t trc;
+	uint32_t trrd;
+	uint32_t tccd;
+	uint32_t twtr;
+	uint32_t trtw;
+	uint32_t tras_max;
+	uint32_t tras_min;
+	uint32_t tfaw;
+	uint32_t trfc;
+	uint32_t tdqsck;
+	uint32_t tdqsck_max;
+	/* pd or sr */
+	uint32_t txsr;
+	uint32_t txsnr;
+	uint32_t txp;
+	uint32_t txpdll;
+	uint32_t tdllk;
+	uint32_t tcke;
+	uint32_t tckesr;
+	uint32_t tcksre;
+	uint32_t tcksrx;
+	uint32_t tdpd;
+	/* mode regiter timing */
+	uint32_t tmod;
+	uint32_t tmrd;
+	uint32_t tmrr;
+	uint32_t tmrri;
+	/* ODT */
+	uint32_t todton;
+	/* ZQ */
+	uint32_t tzqinit;
+	uint32_t tzqcs;
+	uint32_t tzqoper;
+	uint32_t tzqreset;
+	/* Write Leveling */
+	uint32_t twlmrd;
+	uint32_t twlo;
+	uint32_t twldqsen;
+	/* CA Training */
+	uint32_t tcackel;
+	uint32_t tcaent;
+	uint32_t tcamrd;
+	uint32_t tcackeh;
+	uint32_t tcaext;
+	uint32_t tadr;
+	uint32_t tmrz;
+	uint32_t tcacd;
+	/* mode register */
+	uint32_t mr[4];
+	uint32_t mr11;
+	/* lpddr4 spec */
+	uint32_t mr12;
+	uint32_t mr13;
+	uint32_t mr14;
+	uint32_t mr16;
+	uint32_t mr17;
+	uint32_t mr20;
+	uint32_t mr22;
+	uint32_t tccdmw;
+	uint32_t tppd;
+	uint32_t tescke;
+	uint32_t tsr;
+	uint32_t tcmdcke;
+	uint32_t tcscke;
+	uint32_t tckelcs;
+	uint32_t tcsckeh;
+	uint32_t tckehcs;
+	uint32_t tmrwckel;
+	uint32_t tzqcal;
+	uint32_t tzqlat;
+	uint32_t tzqcke;
+	uint32_t tvref_long;
+	uint32_t tvref_short;
+	uint32_t tvrcg_enable;
+	uint32_t tvrcg_disable;
+	uint32_t tfc_long;
+	uint32_t tckfspe;
+	uint32_t tckfspx;
+	uint32_t tckehcmd;
+	uint32_t tckelcmd;
+	uint32_t tckelpd;
+	uint32_t tckckel;
+	/* other */
+	uint32_t al;
+	uint32_t cl;
+	uint32_t cwl;
+	uint32_t bl;
+};
+
+struct dram_info_t {
+	/* speed_rate only used when DDR3 */
+	enum ddr3_speed_rate speed_rate;
+	/* 1: use CS0, 2: use CS0 and CS1 */
+	uint32_t cs_cnt;
+	/* give the max per-die capability on each rank/cs */
+	uint32_t per_die_capability[2];
+};
+
+struct timing_related_config {
+	struct dram_info_t dram_info[2];
+	uint32_t dram_type;
+	/* MHz */
+	uint32_t freq;
+	uint32_t ch_cnt;
+	uint32_t bl;
+	/* 1:auto precharge, 0:never auto precharge */
+	uint32_t ap;
+	/*
+	 * 1:dll bypass, 0:dll normal
+	 * dram and controller dll bypass at the same time
+	 */
+	uint32_t dllbp;
+	/* 1:odt enable, 0:odt disable */
+	uint32_t odt;
+	/* 1:enable, 0:disabe */
+	uint32_t rdbi;
+	uint32_t wdbi;
+	/* dram driver strength */
+	uint32_t dramds;
+	/* dram ODT, if odt=0, this parameter invalid */
+	uint32_t dramodt;
+	/*
+	 * ca ODT, if odt=0, this parameter invalid
+	 * it only used by LPDDR4
+	 */
+	uint32_t caodt;
+};
+
+/* mr0 for ddr3 */
+#define DDR3_BL8		(0)
+#define DDR3_BC4_8		(1)
+#define DDR3_BC4		(2)
+#define DDR3_CL(n)		(((((n) - 4) & 0x7) << 4)\
+				| ((((n) - 4) & 0x8) >> 1))
+#define DDR3_WR(n)		(((n) & 0x7) << 9)
+#define DDR3_DLL_RESET		(1 << 8)
+#define DDR3_DLL_DERESET	(0 << 8)
+
+/* mr1 for ddr3 */
+#define DDR3_DLL_ENABLE		(0)
+#define DDR3_DLL_DISABLE	(1)
+#define DDR3_MR1_AL(n)		(((n) & 0x3) << 3)
+
+#define DDR3_DS_40		(0)
+#define DDR3_DS_34		(1 << 1)
+#define DDR3_RTT_NOM_DIS	(0)
+#define DDR3_RTT_NOM_60		(1 << 2)
+#define DDR3_RTT_NOM_120	(1 << 6)
+#define DDR3_RTT_NOM_40		((1 << 2) | (1 << 6))
+#define DDR3_TDQS		(1 << 11)
+
+/* mr2 for ddr3 */
+#define DDR3_MR2_CWL(n)		((((n) - 5) & 0x7) << 3)
+#define DDR3_RTT_WR_DIS		(0)
+#define DDR3_RTT_WR_60		(1 << 9)
+#define DDR3_RTT_WR_120		(2 << 9)
+
+/*
+ * MR0 (Device Information)
+ * 0:DAI complete, 1:DAI still in progress
+ */
+#define LPDDR2_DAI		(0x1)
+/* 0:S2 or S4 SDRAM, 1:NVM */
+#define LPDDR2_DI		(0x1 << 1)
+/* 0:DNV not supported, 1:DNV supported */
+#define LPDDR2_DNVI		(0x1 << 2)
+#define LPDDR2_RZQI		(0x3 << 3)
+
+/*
+ * 00:RZQ self test not supported,
+ * 01:ZQ-pin may connect to VDDCA or float
+ * 10:ZQ-pin may short to GND.
+ * 11:ZQ-pin self test completed, no error condition detected.
+ */
+
+/* MR1 (Device Feature) */
+#define LPDDR2_BL4		(0x2)
+#define LPDDR2_BL8		(0x3)
+#define LPDDR2_BL16		(0x4)
+#define LPDDR2_N_WR(n)		(((n) - 2) << 5)
+
+/* MR2 (Device Feature 2) */
+#define LPDDR2_RL3_WL1		(0x1)
+#define LPDDR2_RL4_WL2		(0x2)
+#define LPDDR2_RL5_WL2		(0x3)
+#define LPDDR2_RL6_WL3		(0x4)
+#define LPDDR2_RL7_WL4		(0x5)
+#define LPDDR2_RL8_WL4		(0x6)
+
+/* MR3 (IO Configuration 1) */
+#define LPDDR2_DS_34		(0x1)
+#define LPDDR2_DS_40		(0x2)
+#define LPDDR2_DS_48		(0x3)
+#define LPDDR2_DS_60		(0x4)
+#define LPDDR2_DS_80		(0x6)
+/* optional */
+#define LPDDR2_DS_120		(0x7)
+
+/* MR4 (Device Temperature) */
+#define LPDDR2_TREF_MASK	(0x7)
+#define LPDDR2_4_TREF		(0x1)
+#define LPDDR2_2_TREF		(0x2)
+#define LPDDR2_1_TREF		(0x3)
+#define LPDDR2_025_TREF		(0x5)
+#define LPDDR2_025_TREF_DERATE	(0x6)
+
+#define LPDDR2_TUF		(0x1 << 7)
+
+/* MR8 (Basic configuration 4) */
+#define LPDDR2_S4		(0x0)
+#define LPDDR2_S2		(0x1)
+#define LPDDR2_N		(0x2)
+/* Unit:MB */
+#define LPDDR2_DENSITY(mr8)	(8 << (((mr8) >> 2) & 0xf))
+#define LPDDR2_IO_WIDTH(mr8)	(32 >> (((mr8) >> 6) & 0x3))
+
+/* MR10 (Calibration) */
+#define LPDDR2_ZQINIT		(0xff)
+#define LPDDR2_ZQCL		(0xab)
+#define LPDDR2_ZQCS		(0x56)
+#define LPDDR2_ZQRESET		(0xc3)
+
+/* MR16 (PASR Bank Mask), S2 SDRAM Only */
+#define LPDDR2_PASR_FULL	(0x0)
+#define LPDDR2_PASR_1_2		(0x1)
+#define LPDDR2_PASR_1_4		(0x2)
+#define LPDDR2_PASR_1_8		(0x3)
+
+/*
+ * MR0 (Device Information)
+ * 0:DAI complete,
+ * 1:DAI still in progress
+ */
+#define LPDDR3_DAI		(0x1)
+/*
+ * 00:RZQ self test not supported,
+ * 01:ZQ-pin may connect to VDDCA or float
+ * 10:ZQ-pin may short to GND.
+ * 11:ZQ-pin self test completed, no error condition detected.
+ */
+#define LPDDR3_RZQI		(0x3 << 3)
+/*
+ * 0:DRAM does not support WL(Set B),
+ * 1:DRAM support WL(Set B)
+ */
+#define LPDDR3_WL_SUPOT		(1 << 6)
+/*
+ * 0:DRAM does not support RL=3,nWR=3,WL=1;
+ * 1:DRAM supports RL=3,nWR=3,WL=1 for frequencies <=166
+ */
+#define LPDDR3_RL3_SUPOT	(1 << 7)
+
+/* MR1 (Device Feature) */
+#define LPDDR3_BL8		(0x3)
+#define LPDDR3_N_WR(n)		((n) << 5)
+
+/* MR2 (Device Feature 2), WL Set A,default */
+/* <=166MHz,optional*/
+#define LPDDR3_RL3_WL1		(0x1)
+/* <=400MHz*/
+#define LPDDR3_RL6_WL3		(0x4)
+/* <=533MHz*/
+#define LPDDR3_RL8_WL4		(0x6)
+/* <=600MHz*/
+#define LPDDR3_RL9_WL5		(0x7)
+/* <=667MHz,default*/
+#define LPDDR3_RL10_WL6		(0x8)
+/* <=733MHz*/
+#define LPDDR3_RL11_WL6		(0x9)
+/* <=800MHz*/
+#define LPDDR3_RL12_WL6		(0xa)
+/* <=933MHz*/
+#define LPDDR3_RL14_WL8		(0xc)
+/* <=1066MHz*/
+#define LPDDR3_RL16_WL8		(0xe)
+
+/* WL Set B, optional */
+/* <=667MHz,default*/
+#define LPDDR3_RL10_WL8		(0x8)
+/* <=733MHz*/
+#define LPDDR3_RL11_WL9		(0x9)
+/* <=800MHz*/
+#define LPDDR3_RL12_WL9		(0xa)
+/* <=933MHz*/
+#define LPDDR3_RL14_WL11	(0xc)
+/* <=1066MHz*/
+#define LPDDR3_RL16_WL13	(0xe)
+
+/* 1:enable nWR programming > 9(default)*/
+#define LPDDR3_N_WRE		(1 << 4)
+/* 1:Select WL Set B*/
+#define LPDDR3_WL_S		(1 << 6)
+/* 1:enable*/
+#define LPDDR3_WR_LEVEL		(1 << 7)
+
+/* MR3 (IO Configuration 1) */
+#define LPDDR3_DS_34		(0x1)
+#define LPDDR3_DS_40		(0x2)
+#define LPDDR3_DS_48		(0x3)
+#define LPDDR3_DS_60		(0x4)
+#define LPDDR3_DS_80		(0x6)
+#define LPDDR3_DS_34D_40U	(0x9)
+#define LPDDR3_DS_40D_48U	(0xa)
+#define LPDDR3_DS_34D_48U	(0xb)
+
+/* MR4 (Device Temperature) */
+#define LPDDR3_TREF_MASK	(0x7)
+/* SDRAM Low temperature operating limit exceeded */
+#define LPDDR3_LT_EXED		(0x0)
+#define LPDDR3_4_TREF		(0x1)
+#define LPDDR3_2_TREF		(0x2)
+#define LPDDR3_1_TREF		(0x3)
+#define LPDDR3_05_TREF		(0x4)
+#define LPDDR3_025_TREF		(0x5)
+#define LPDDR3_025_TREF_DERATE	(0x6)
+/* SDRAM High temperature operating limit exceeded */
+#define LPDDR3_HT_EXED		(0x7)
+
+/* 1:value has changed since last read of MR4 */
+#define LPDDR3_TUF		(0x1 << 7)
+
+/* MR8 (Basic configuration 4) */
+#define LPDDR3_S8		(0x3)
+#define LPDDR3_DENSITY(mr8)	(8 << (((mr8) >> 2) & 0xf))
+#define LPDDR3_IO_WIDTH(mr8)	(32 >> (((mr8) >> 6) & 0x3))
+
+/* MR10 (Calibration) */
+#define LPDDR3_ZQINIT		(0xff)
+#define LPDDR3_ZQCL		(0xab)
+#define LPDDR3_ZQCS		(0x56)
+#define LPDDR3_ZQRESET		(0xc3)
+
+/* MR11 (ODT Control) */
+#define LPDDR3_ODT_60		(1)
+#define LPDDR3_ODT_120		(2)
+#define LPDDR3_ODT_240		(3)
+#define LPDDR3_ODT_DIS		(0)
+
+/* MR2 (Device Feature 2) */
+/* RL & nRTP for DBI-RD Disabled */
+#define LPDDR4_RL6_NRTP8	(0x0)
+#define LPDDR4_RL10_NRTP8	(0x1)
+#define LPDDR4_RL14_NRTP8	(0x2)
+#define LPDDR4_RL20_NRTP8	(0x3)
+#define LPDDR4_RL24_NRTP10	(0x4)
+#define LPDDR4_RL28_NRTP12	(0x5)
+#define LPDDR4_RL32_NRTP14	(0x6)
+#define LPDDR4_RL36_NRTP16	(0x7)
+/* RL & nRTP for DBI-RD Disabled */
+#define LPDDR4_RL12_NRTP8	(0x1)
+#define LPDDR4_RL16_NRTP8	(0x2)
+#define LPDDR4_RL22_NRTP8	(0x3)
+#define LPDDR4_RL28_NRTP10	(0x4)
+#define LPDDR4_RL32_NRTP12	(0x5)
+#define LPDDR4_RL36_NRTP14	(0x6)
+#define LPDDR4_RL40_NRTP16	(0x7)
+/* WL Set A,default */
+#define LPDDR4_A_WL4		(0x0)
+#define LPDDR4_A_WL6		(0x1)
+#define LPDDR4_A_WL8		(0x2)
+#define LPDDR4_A_WL10		(0x3)
+#define LPDDR4_A_WL12		(0x4)
+#define LPDDR4_A_WL14		(0x5)
+#define LPDDR4_A_WL16		(0x6)
+#define LPDDR4_A_WL18		(0x7)
+/* WL Set B, optional */
+#define LPDDR4_B_WL4		(0x0 << 3)
+#define LPDDR4_B_WL8		(0x1 << 3)
+#define LPDDR4_B_WL12		(0x2 << 3)
+#define LPDDR4_B_WL18		(0x3 << 3)
+#define LPDDR4_B_WL22		(0x4 << 3)
+#define LPDDR4_B_WL26		(0x5 << 3)
+#define LPDDR4_B_WL30		(0x6 << 3)
+#define LPDDR4_B_WL34		(0x7 << 3)
+/* 1:Select WL Set B*/
+#define LPDDR4_WL_B		(1 << 6)
+/* 1:enable*/
+#define LPDDR4_WR_LEVEL		(1 << 7)
+
+/* MR3 */
+#define LPDDR4_VDDQ_2_5		(0)
+#define LPDDR4_VDDQ_3		(1)
+#define LPDDR4_WRPST_0_5_TCK	(0 << 1)
+#define LPDDR4_WRPST_1_5_TCK	(1 << 1)
+#define LPDDR4_PPR_EN		(1 << 2)
+/* PDDS */
+#define LPDDR4_PDDS_240		(0x1 << 3)
+#define LPDDR4_PDDS_120		(0x2 << 3)
+#define LPDDR4_PDDS_80		(0x3 << 3)
+#define LPDDR4_PDDS_60		(0x4 << 3)
+#define LPDDR4_PDDS_48		(0x5 << 3)
+#define LPDDR4_PDDS_40		(0x6 << 3)
+#define LPDDR4_DBI_RD_EN	(1 << 6)
+#define LPDDR4_DBI_WR_EN	(1 << 7)
+
+/* MR11 (ODT Control) */
+#define LPDDR4_DQODT_240	(1)
+#define LPDDR4_DQODT_120	(2)
+#define LPDDR4_DQODT_80		(3)
+#define LPDDR4_DQODT_60		(4)
+#define LPDDR4_DQODT_48		(5)
+#define LPDDR4_DQODT_40		(6)
+#define LPDDR4_DQODT_DIS	(0)
+#define LPDDR4_CAODT_240	(1 << 4)
+#define LPDDR4_CAODT_120	(2 << 4)
+#define LPDDR4_CAODT_80		(3 << 4)
+#define LPDDR4_CAODT_60		(4 << 4)
+#define LPDDR4_CAODT_48		(5 << 4)
+#define LPDDR4_CAODT_40		(6 << 4)
+#define LPDDR4_CAODT_DIS	(0 << 4)
+
+/*
+ * Description: depend on input parameter "timing_config",
+ *		and calculate correspond "dram_type"
+ *		spec timing to "pdram_timing"
+ * parameters:
+ *   input: timing_config
+ *   output: pdram_timing
+ * NOTE: MR ODT is set, need to disable by controller
+ */
+void dram_get_parameter(struct timing_related_config *timing_config,
+			struct dram_timing_t *pdram_timing);
+
+#endif /* DRAM_SPEC_TIMING_H */
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
new file mode 100644
index 0000000..7f9fad1
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <dram.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+#include <suspend.h>
+
+#define PMUGRF_OS_REG0			0x300
+#define PMUGRF_OS_REG1			0x304
+#define PMUGRF_OS_REG2			0x308
+#define PMUGRF_OS_REG3			0x30c
+
+#define CRU_SFTRST_DDR_CTRL(ch, n)	((0x1 << (8 + 16 + (ch) * 4)) | \
+					 ((n) << (8 + (ch) * 4)))
+#define CRU_SFTRST_DDR_PHY(ch, n)	((0x1 << (9 + 16 + (ch) * 4)) | \
+					 ((n) << (9 + (ch) * 4)))
+
+#define FBDIV_ENC(n)			((n) << 16)
+#define FBDIV_DEC(n)			(((n) >> 16) & 0xfff)
+#define POSTDIV2_ENC(n)			((n) << 12)
+#define POSTDIV2_DEC(n)			(((n) >> 12) & 0x7)
+#define POSTDIV1_ENC(n)			((n) << 8)
+#define POSTDIV1_DEC(n)			(((n) >> 8) & 0x7)
+#define REFDIV_ENC(n)			(n)
+#define REFDIV_DEC(n)			((n) & 0x3f)
+
+/* PMU CRU */
+#define PMUCRU_RSTNHOLD_CON0		0x120
+#define PMUCRU_RSTNHOLD_CON1		0x124
+
+#define PRESET_GPIO0_HOLD(n)		(((n) << 7) | WMSK_BIT(7))
+#define PRESET_GPIO1_HOLD(n)		(((n) << 8) | WMSK_BIT(8))
+
+#define SYS_COUNTER_FREQ_IN_MHZ		(SYS_COUNTER_FREQ_IN_TICKS / 1000000)
+
+__pmusramdata uint32_t dpll_data[PLL_CON_COUNT];
+__pmusramdata uint32_t cru_clksel_con6;
+
+/*
+ * Copy @num registers from @src to @dst
+ */
+static __pmusramfunc void sram_regcpy(uintptr_t dst, uintptr_t src,
+		uint32_t num)
+{
+	while (num--) {
+		mmio_write_32(dst, mmio_read_32(src));
+		dst += sizeof(uint32_t);
+		src += sizeof(uint32_t);
+	}
+}
+
+/*
+ * Copy @num registers from @src to @dst
+ * This is intentionally a copy of the sram_regcpy function. PMUSRAM functions
+ * cannot be called from code running in DRAM.
+ */
+static void dram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
+{
+	while (num--) {
+		mmio_write_32(dst, mmio_read_32(src));
+		dst += sizeof(uint32_t);
+		src += sizeof(uint32_t);
+	}
+}
+
+static __pmusramfunc uint32_t sram_get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static __pmusramfunc void sram_udelay(uint32_t usec)
+{
+	uint32_t start, cnt, delta, total_ticks;
+
+	/* counter is decreasing */
+	start = sram_get_timer_value();
+	total_ticks = usec * SYS_COUNTER_FREQ_IN_MHZ;
+	do {
+		cnt = sram_get_timer_value();
+		if (cnt > start) {
+			delta = UINT32_MAX - cnt;
+			delta += start;
+		} else
+			delta = start - cnt;
+	} while (delta <= total_ticks);
+}
+
+static __pmusramfunc void configure_sgrf(void)
+{
+	/*
+	 * SGRF_DDR_RGN_DPLL_CLK and SGRF_DDR_RGN_RTC_CLK:
+	 * IC ECO bug, need to set this register.
+	 *
+	 * SGRF_DDR_RGN_BYPS:
+	 * After the PD_CENTER suspend/resume, the DDR region
+	 * related registers in the SGRF will be reset, we
+	 * need to re-initialize them.
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+		      SGRF_DDR_RGN_DPLL_CLK |
+		      SGRF_DDR_RGN_RTC_CLK |
+		      SGRF_DDR_RGN_BYPS);
+}
+
+static __pmusramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
+		uint32_t phy)
+{
+	channel &= 0x1;
+	ctl &= 0x1;
+	phy &= 0x1;
+	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(4),
+		      CRU_SFTRST_DDR_CTRL(channel, ctl) |
+		      CRU_SFTRST_DDR_PHY(channel, phy));
+}
+
+static __pmusramfunc void phy_pctrl_reset(uint32_t ch)
+{
+	rkclk_ddr_reset(ch, 1, 1);
+	sram_udelay(10);
+	rkclk_ddr_reset(ch, 1, 0);
+	sram_udelay(10);
+	rkclk_ddr_reset(ch, 0, 0);
+	sram_udelay(10);
+}
+
+static __pmusramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
+{
+	uint32_t byte;
+
+	/* PHY_8/136/264/392 phy_per_cs_training_index_X 1bit offset_24 */
+	for (byte = 0; byte < 4; byte++)
+		mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 24,
+				   rank << 24);
+}
+
+static __pmusramfunc void select_per_cs_training_index(uint32_t ch,
+		uint32_t rank)
+{
+	/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
+	if ((mmio_read_32(PHY_REG(ch, 84)) >> 16) & 1)
+		set_cs_training_index(ch, rank);
+}
+
+static __pmusramfunc void override_write_leveling_value(uint32_t ch)
+{
+	uint32_t byte;
+
+	for (byte = 0; byte < 4; byte++) {
+		/*
+		 * PHY_8/136/264/392
+		 * phy_per_cs_training_multicast_en_X 1bit offset_16
+		 */
+		mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 16,
+				   1 << 16);
+		mmio_clrsetbits_32(PHY_REG(ch, 63 + (128 * byte)),
+				   0xffffu << 16,
+				   0x200 << 16);
+	}
+
+	/* CTL_200 ctrlupd_req 1bit offset_8 */
+	mmio_clrsetbits_32(CTL_REG(ch, 200), 0x1 << 8, 0x1 << 8);
+}
+
+static __pmusramfunc int data_training(uint32_t ch,
+		struct rk3399_sdram_params *sdram_params,
+		uint32_t training_flag)
+{
+	uint32_t obs_0, obs_1, obs_2, obs_3, obs_err = 0;
+	uint32_t rank = sdram_params->ch[ch].rank;
+	uint32_t rank_mask;
+	uint32_t i, tmp;
+
+	if (sdram_params->dramtype == LPDDR4)
+		rank_mask = (rank == 1) ? 0x5 : 0xf;
+	else
+		rank_mask = (rank == 1) ? 0x1 : 0x3;
+
+	/* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
+	mmio_setbits_32(PHY_REG(ch, 927), (1 << 22));
+
+	if (training_flag == PI_FULL_TRAINING) {
+		if (sdram_params->dramtype == LPDDR4) {
+			training_flag = PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING |
+					PI_READ_LEVELING |
+					PI_WDQ_LEVELING;
+		} else if (sdram_params->dramtype == LPDDR3) {
+			training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING;
+		} else if (sdram_params->dramtype == DDR3) {
+			training_flag = PI_WRITE_LEVELING |
+					PI_READ_GATE_TRAINING |
+					PI_READ_LEVELING;
+		}
+	}
+
+	/* ca training(LPDDR4,LPDDR3 support) */
+	if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) {
+		for (i = 0; i < 4; i++) {
+			if (!(rank_mask & (1 << i)))
+				continue;
+
+			select_per_cs_training_index(ch, i);
+			/* PI_100 PI_CALVL_EN:RW:8:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 100), 0x3 << 8, 0x2 << 8);
+
+			/* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 92),
+					   (0x1 << 16) | (0x3 << 24),
+					   (0x1 << 16) | (i << 24));
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * check status obs
+				 * PHY_532/660/788 phy_adr_calvl_obs1_:0:32
+				 */
+				obs_0 = mmio_read_32(PHY_REG(ch, 532));
+				obs_1 = mmio_read_32(PHY_REG(ch, 660));
+				obs_2 = mmio_read_32(PHY_REG(ch, 788));
+				if (((obs_0 >> 30) & 0x3) ||
+				    ((obs_1 >> 30) & 0x3) ||
+				    ((obs_2 >> 30) & 0x3))
+					obs_err = 1;
+				if ((((tmp >> 11) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 5) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 5) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 100), 0x3 << 8);
+	}
+
+	/* write leveling(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(ch, i);
+			/* PI_60 PI_WRLVL_EN:RW:8:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 60), 0x3 << 8, 0x2 << 8);
+			/* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 59),
+					   (0x1 << 8) | (0x3 << 16),
+					   (0x1 << 8) | (i << 16));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * check status obs, if error maybe can not
+				 * get leveling done PHY_40/168/296/424
+				 * phy_wrlvl_status_obs_X:0:13
+				 */
+				obs_0 = mmio_read_32(PHY_REG(ch, 40));
+				obs_1 = mmio_read_32(PHY_REG(ch, 168));
+				obs_2 = mmio_read_32(PHY_REG(ch, 296));
+				obs_3 = mmio_read_32(PHY_REG(ch, 424));
+				if (((obs_0 >> 12) & 0x1) ||
+				    ((obs_1 >> 12) & 0x1) ||
+				    ((obs_2 >> 12) & 0x1) ||
+				    ((obs_3 >> 12) & 0x1))
+					obs_err = 1;
+				if ((((tmp >> 10) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 4) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 4) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		override_write_leveling_value(ch);
+		mmio_clrbits_32(PI_REG(ch, 60), 0x3 << 8);
+	}
+
+	/* read gate training(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(ch, i);
+			/* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 24,
+					   0x2 << 24);
+			/*
+			 * PI_74 PI_RDLVL_GATE_REQ:WR:16:1
+			 * PI_RDLVL_CS:RW:24:2
+			 */
+			mmio_clrsetbits_32(PI_REG(ch, 74),
+					   (0x1 << 16) | (0x3 << 24),
+					   (0x1 << 16) | (i << 24));
+
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * check status obs
+				 * PHY_43/171/299/427
+				 *     PHY_GTLVL_STATUS_OBS_x:16:8
+				 */
+				obs_0 = mmio_read_32(PHY_REG(ch, 43));
+				obs_1 = mmio_read_32(PHY_REG(ch, 171));
+				obs_2 = mmio_read_32(PHY_REG(ch, 299));
+				obs_3 = mmio_read_32(PHY_REG(ch, 427));
+				if (((obs_0 >> (16 + 6)) & 0x3) ||
+				    ((obs_1 >> (16 + 6)) & 0x3) ||
+				    ((obs_2 >> (16 + 6)) & 0x3) ||
+				    ((obs_3 >> (16 + 6)) & 0x3))
+					obs_err = 1;
+				if ((((tmp >> 9) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 3) & 0x1) == 0x0) &&
+				    (obs_err == 0))
+					break;
+				else if ((((tmp >> 3) & 0x1) == 0x1) ||
+					 (obs_err == 1))
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 24);
+	}
+
+	/* read leveling(LPDDR4,LPDDR3,DDR3 support) */
+	if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) {
+		for (i = 0; i < rank; i++) {
+			select_per_cs_training_index(ch, i);
+			/* PI_80 PI_RDLVL_EN:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 16,
+					   0x2 << 16);
+			/* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 74),
+					   (0x1 << 8) | (0x3 << 24),
+					   (0x1 << 8) | (i << 24));
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+
+				/*
+				 * make sure status obs not report error bit
+				 * PHY_46/174/302/430
+				 *     phy_rdlvl_status_obs_X:16:8
+				 */
+				if ((((tmp >> 8) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 2) & 0x1) == 0x0))
+					break;
+				else if (((tmp >> 2) & 0x1) == 0x1)
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 16);
+	}
+
+	/* wdq leveling(LPDDR4 support) */
+	if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) {
+		for (i = 0; i < 4; i++) {
+			if (!(rank_mask & (1 << i)))
+				continue;
+
+			select_per_cs_training_index(ch, i);
+			/*
+			 * disable PI_WDQLVL_VREF_EN before wdq leveling?
+			 * PI_181 PI_WDQLVL_VREF_EN:RW:8:1
+			 */
+			mmio_clrbits_32(PI_REG(ch, 181), 0x1 << 8);
+			/* PI_124 PI_WDQLVL_EN:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 124), 0x3 << 16,
+					   0x2 << 16);
+			/* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */
+			mmio_clrsetbits_32(PI_REG(ch, 121),
+					   (0x1 << 8) | (0x3 << 16),
+					   (0x1 << 8) | (i << 16));
+			while (1) {
+				/* PI_174 PI_INT_STATUS:RD:8:18 */
+				tmp = mmio_read_32(PI_REG(ch, 174)) >> 8;
+				if ((((tmp >> 12) & 0x1) == 0x1) &&
+				    (((tmp >> 13) & 0x1) == 0x1) &&
+				    (((tmp >> 6) & 0x1) == 0x0))
+					break;
+				else if (((tmp >> 6) & 0x1) == 0x1)
+					return -1;
+			}
+			/* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */
+			mmio_write_32(PI_REG(ch, 175), 0x00003f7c);
+		}
+		mmio_clrbits_32(PI_REG(ch, 124), 0x3 << 16);
+	}
+
+	/* PHY_927 PHY_PAD_DQS_DRIVE  RPULL offset_22 */
+	mmio_clrbits_32(PHY_REG(ch, 927), (1 << 22));
+
+	return 0;
+}
+
+static __pmusramfunc void set_ddrconfig(
+		struct rk3399_sdram_params *sdram_params,
+		unsigned char channel, uint32_t ddrconfig)
+{
+	/* only need to set ddrconfig */
+	struct rk3399_sdram_channel *ch = &sdram_params->ch[channel];
+	unsigned int cs0_cap = 0;
+	unsigned int cs1_cap = 0;
+
+	cs0_cap = (1 << (ch->cs0_row + ch->col + ch->bk + ch->bw - 20));
+	if (ch->rank > 1)
+		cs1_cap = cs0_cap >> (ch->cs0_row - ch->cs1_row);
+	if (ch->row_3_4) {
+		cs0_cap = cs0_cap * 3 / 4;
+		cs1_cap = cs1_cap * 3 / 4;
+	}
+
+	mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICECONF,
+		      ddrconfig | (ddrconfig << 6));
+	mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICESIZE,
+		      ((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8));
+}
+
+static __pmusramfunc void dram_all_config(
+		struct rk3399_sdram_params *sdram_params)
+{
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		struct rk3399_sdram_channel *info = &sdram_params->ch[i];
+		struct rk3399_msch_timings *noc = &info->noc_timings;
+
+		if (sdram_params->ch[i].col == 0)
+			continue;
+
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGA0,
+			      noc->ddrtiminga0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGB0,
+			      noc->ddrtimingb0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGC0,
+			      noc->ddrtimingc0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DEVTODEV0,
+			      noc->devtodev0.d32);
+		mmio_write_32(MSCH_BASE(i) + MSCH_DDRMODE, noc->ddrmode.d32);
+
+		/* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */
+		if (sdram_params->ch[i].rank == 1)
+			mmio_setbits_32(CTL_REG(i, 276), 1 << 17);
+	}
+
+	DDR_STRIDE(sdram_params->stride);
+
+	/* reboot hold register set */
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_RLS |
+		      PRESET_GPIO0_HOLD(1) |
+		      PRESET_GPIO1_HOLD(1));
+	mmio_clrsetbits_32(CRU_BASE + CRU_GLB_RST_CON, 0x3, 0x3);
+}
+
+static __pmusramfunc void pctl_cfg(uint32_t ch,
+		struct rk3399_sdram_params *sdram_params)
+{
+	const uint32_t *params_ctl = sdram_params->pctl_regs.denali_ctl;
+	const uint32_t *params_pi = sdram_params->pi_regs.denali_pi;
+	const struct rk3399_ddr_publ_regs *phy_regs = &sdram_params->phy_regs;
+	uint32_t tmp, tmp1, tmp2, i;
+
+	/*
+	 * Workaround controller bug:
+	 * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed
+	 */
+	sram_regcpy(CTL_REG(ch, 1), (uintptr_t)&params_ctl[1],
+		    CTL_REG_NUM - 1);
+	mmio_write_32(CTL_REG(ch, 0), params_ctl[0]);
+	sram_regcpy(PI_REG(ch, 0), (uintptr_t)&params_pi[0],
+		    PI_REG_NUM);
+
+	sram_regcpy(PHY_REG(ch, 910), (uintptr_t)&phy_regs->phy896[910 - 896],
+		    3);
+
+	mmio_clrsetbits_32(CTL_REG(ch, 68), PWRUP_SREFRESH_EXIT,
+				PWRUP_SREFRESH_EXIT);
+
+	/* PHY_DLL_RST_EN */
+	mmio_clrsetbits_32(PHY_REG(ch, 957), 0x3 << 24, 1 << 24);
+	dmbst();
+
+	mmio_setbits_32(PI_REG(ch, 0), START);
+	mmio_setbits_32(CTL_REG(ch, 0), START);
+
+	/* wait lock */
+	while (1) {
+		tmp = mmio_read_32(PHY_REG(ch, 920));
+		tmp1 = mmio_read_32(PHY_REG(ch, 921));
+		tmp2 = mmio_read_32(PHY_REG(ch, 922));
+		if ((((tmp >> 16) & 0x1) == 0x1) &&
+		     (((tmp1 >> 16) & 0x1) == 0x1) &&
+		     (((tmp1 >> 0) & 0x1) == 0x1) &&
+		     (((tmp2 >> 0) & 0x1) == 0x1))
+			break;
+		/* if PLL bypass,don't need wait lock */
+		if (mmio_read_32(PHY_REG(ch, 911)) & 0x1)
+			break;
+	}
+
+	sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&phy_regs->phy896[0], 63);
+
+	for (i = 0; i < 4; i++)
+		sram_regcpy(PHY_REG(ch, 128 * i),
+			    (uintptr_t)&phy_regs->phy0[0], 91);
+
+	for (i = 0; i < 3; i++)
+		sram_regcpy(PHY_REG(ch, 512 + 128 * i),
+				(uintptr_t)&phy_regs->phy512[i][0], 38);
+}
+
+static __pmusramfunc int dram_switch_to_next_index(
+		struct rk3399_sdram_params *sdram_params)
+{
+	uint32_t ch, ch_count;
+	uint32_t fn = ((mmio_read_32(CTL_REG(0, 111)) >> 16) + 1) & 0x1;
+
+	mmio_write_32(CIC_BASE + CIC_CTRL0,
+		      (((0x3 << 4) | (1 << 2) | 1) << 16) |
+		      (fn << 4) | (1 << 2) | 1);
+	while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)))
+		;
+
+	mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002);
+	while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0)))
+		;
+
+	ch_count = sdram_params->num_channels;
+
+	/* LPDDR4 f2 cann't do training, all training will fail */
+	for (ch = 0; ch < ch_count; ch++) {
+		mmio_clrsetbits_32(PHY_REG(ch, 896), (0x3 << 8) | 1,
+				   fn << 8);
+
+		/* data_training failed */
+		if (data_training(ch, sdram_params, PI_FULL_TRAINING))
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Needs to be done for both channels at once in case of a shared reset signal
+ * between channels.
+ */
+static __pmusramfunc int pctl_start(uint32_t channel_mask,
+		struct rk3399_sdram_params *sdram_params)
+{
+	uint32_t count;
+	uint32_t byte;
+
+	mmio_setbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
+	mmio_setbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
+
+	/* need de-access IO retention before controller START */
+	if (channel_mask & (1 << 0))
+		mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 19));
+	if (channel_mask & (1 << 1))
+		mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 23));
+
+	/* PHY_DLL_RST_EN */
+	if (channel_mask & (1 << 0))
+		mmio_clrsetbits_32(PHY_REG(0, 957), 0x3 << 24,
+				   0x2 << 24);
+	if (channel_mask & (1 << 1))
+		mmio_clrsetbits_32(PHY_REG(1, 957), 0x3 << 24,
+				   0x2 << 24);
+
+	/* check ERROR bit */
+	if (channel_mask & (1 << 0)) {
+		count = 0;
+		while (!(mmio_read_32(CTL_REG(0, 203)) & (1 << 3))) {
+			/* CKE is low, loop 10ms */
+			if (count > 100)
+				return -1;
+
+			sram_udelay(100);
+			count++;
+		}
+
+		mmio_clrbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
+
+		/* Restore the PHY_RX_CAL_DQS value */
+		for (byte = 0; byte < 4; byte++)
+			mmio_clrsetbits_32(PHY_REG(0, 57 + 128 * byte),
+					   0xfff << 16,
+					   sdram_params->rx_cal_dqs[0][byte]);
+	}
+	if (channel_mask & (1 << 1)) {
+		count = 0;
+		while (!(mmio_read_32(CTL_REG(1, 203)) & (1 << 3))) {
+			/* CKE is low, loop 10ms */
+			if (count > 100)
+				return -1;
+
+			sram_udelay(100);
+			count++;
+		}
+
+		mmio_clrbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
+
+		/* Restore the PHY_RX_CAL_DQS value */
+		for (byte = 0; byte < 4; byte++)
+			mmio_clrsetbits_32(PHY_REG(1, 57 + 128 * byte),
+					   0xfff << 16,
+					   sdram_params->rx_cal_dqs[1][byte]);
+	}
+
+	return 0;
+}
+
+__pmusramfunc static void pmusram_restore_pll(int pll_id, uint32_t *src)
+{
+	mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE);
+
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK);
+
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK);
+
+	while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) &
+		(1U << 31)) == 0x0)
+		;
+}
+
+__pmusramfunc static void pmusram_enable_watchdog(void)
+{
+	/* Make the watchdog use the first global reset. */
+	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, 1 << 1);
+
+	/*
+	 * This gives the system ~8 seconds before reset. The pclk for the
+	 * watchdog is 4MHz on reset. The value of 0x9 in WDT_TORR means that
+	 * the watchdog will wait for 0x1ffffff cycles before resetting.
+	 */
+	mmio_write_32(WDT0_BASE + 4, 0x9);
+
+	/* Enable the watchdog */
+	mmio_setbits_32(WDT0_BASE, 0x1);
+
+	/* Magic reset the watchdog timer value for WDT_CRR. */
+	mmio_write_32(WDT0_BASE + 0xc, 0x76);
+
+	secure_watchdog_ungate();
+
+	/* The watchdog is in PD_ALIVE, so deidle it. */
+	mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, PMU_CLR_ALIVE);
+}
+
+void dmc_suspend(void)
+{
+	struct rk3399_sdram_params *sdram_params = &sdram_config;
+	struct rk3399_ddr_publ_regs *phy_regs;
+	uint32_t *params_ctl;
+	uint32_t *params_pi;
+	uint32_t refdiv, postdiv2, postdiv1, fbdiv;
+	uint32_t ch, byte, i;
+
+	phy_regs = &sdram_params->phy_regs;
+	params_ctl = sdram_params->pctl_regs.denali_ctl;
+	params_pi = sdram_params->pi_regs.denali_pi;
+
+	/* save dpll register and ddr clock register value to pmusram */
+	cru_clksel_con6 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON6);
+	for (i = 0; i < PLL_CON_COUNT; i++)
+		dpll_data[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, i));
+
+	fbdiv = dpll_data[0] & 0xfff;
+	postdiv2 = POSTDIV2_DEC(dpll_data[1]);
+	postdiv1 = POSTDIV1_DEC(dpll_data[1]);
+	refdiv = REFDIV_DEC(dpll_data[1]);
+
+	sdram_params->ddr_freq = ((fbdiv * 24) /
+				(refdiv * postdiv1 * postdiv2)) * MHz;
+
+	INFO("sdram_params->ddr_freq = %d\n", sdram_params->ddr_freq);
+	sdram_params->odt = (((mmio_read_32(PHY_REG(0, 5)) >> 16) &
+			       0x7) != 0) ? 1 : 0;
+
+	/* copy the registers CTL PI and PHY */
+	dram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
+
+	/* mask DENALI_CTL_00_DATA.START, only copy here, will trigger later */
+	params_ctl[0] &= ~(0x1 << 0);
+
+	dram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
+		    PI_REG_NUM);
+
+	/* mask DENALI_PI_00_DATA.START, only copy here, will trigger later*/
+	params_pi[0] &= ~(0x1 << 0);
+
+	dram_regcpy((uintptr_t)&phy_regs->phy0[0],
+			    PHY_REG(0, 0), 91);
+
+	for (i = 0; i < 3; i++)
+		dram_regcpy((uintptr_t)&phy_regs->phy512[i][0],
+			    PHY_REG(0, 512 + 128 * i), 38);
+
+	dram_regcpy((uintptr_t)&phy_regs->phy896[0], PHY_REG(0, 896), 63);
+
+	for (ch = 0; ch < sdram_params->num_channels; ch++) {
+		for (byte = 0; byte < 4; byte++)
+			sdram_params->rx_cal_dqs[ch][byte] = (0xfff << 16) &
+				mmio_read_32(PHY_REG(ch, 57 + byte * 128));
+	}
+
+	/* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */
+	phy_regs->phy896[957 - 896] &= ~(0x3 << 24);
+	phy_regs->phy896[957 - 896] |= 1 << 24;
+	phy_regs->phy896[0] |= 1;
+	phy_regs->phy896[0] &= ~(0x3 << 8);
+}
+
+__pmusramfunc void dmc_resume(void)
+{
+	struct rk3399_sdram_params *sdram_params = &sdram_config;
+	uint32_t channel_mask = 0;
+	uint32_t channel;
+
+	pmusram_enable_watchdog();
+	pmu_sgrf_rst_hld_release();
+	restore_pmu_rsthold();
+	sram_secure_timer_init();
+
+	/*
+	 * we switch ddr clock to abpll when suspend,
+	 * we set back to dpll here
+	 */
+	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON6,
+			cru_clksel_con6 | REG_SOC_WMSK);
+	pmusram_restore_pll(DPLL_ID, dpll_data);
+
+	configure_sgrf();
+
+retry:
+	for (channel = 0; channel < sdram_params->num_channels; channel++) {
+		phy_pctrl_reset(channel);
+		pctl_cfg(channel, sdram_params);
+	}
+
+	for (channel = 0; channel < 2; channel++) {
+		if (sdram_params->ch[channel].col)
+			channel_mask |= 1 << channel;
+	}
+
+	if (pctl_start(channel_mask, sdram_params) < 0)
+		goto retry;
+
+	for (channel = 0; channel < sdram_params->num_channels; channel++) {
+		/* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */
+		if (sdram_params->dramtype == LPDDR3)
+			sram_udelay(10);
+
+		/* If traning fail, retry to do it again. */
+		if (data_training(channel, sdram_params, PI_FULL_TRAINING))
+			goto retry;
+
+		set_ddrconfig(sdram_params, channel,
+			      sdram_params->ch[channel].ddrconfig);
+	}
+
+	dram_all_config(sdram_params);
+
+	/* Switch to index 1 and prepare for DDR frequency switch. */
+	dram_switch_to_next_index(sdram_params);
+}
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.h b/plat/rockchip/rk3399/drivers/dram/suspend.h
new file mode 100644
index 0000000..b99a926
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUSPEND_H
+#define SUSPEND_H
+
+#include <dram.h>
+
+#define KHz (1000)
+#define MHz (1000 * KHz)
+#define GHz (1000 * MHz)
+
+#define PI_CA_TRAINING		(1 << 0)
+#define PI_WRITE_LEVELING	(1 << 1)
+#define PI_READ_GATE_TRAINING	(1 << 2)
+#define PI_READ_LEVELING	(1 << 3)
+#define PI_WDQ_LEVELING		(1 << 4)
+#define PI_FULL_TRAINING	(0xff)
+
+void dmc_suspend(void);
+__pmusramfunc void dmc_resume(void);
+
+#endif /* SUSPEND_H */
diff --git a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
new file mode 100644
index 0000000..b8cba6d
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <soc.h>
+
+uint32_t gpio_port[] = {
+	GPIO0_BASE,
+	GPIO1_BASE,
+	GPIO2_BASE,
+	GPIO3_BASE,
+	GPIO4_BASE,
+};
+
+struct {
+	uint32_t swporta_dr;
+	uint32_t swporta_ddr;
+	uint32_t inten;
+	uint32_t intmask;
+	uint32_t inttype_level;
+	uint32_t int_polarity;
+	uint32_t debounce;
+	uint32_t ls_sync;
+} store_gpio[3];
+
+static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1];
+
+#define SWPORTA_DR	0x00
+#define SWPORTA_DDR	0x04
+#define INTEN		0x30
+#define INTMASK		0x34
+#define INTTYPE_LEVEL	0x38
+#define INT_POLARITY	0x3c
+#define DEBOUNCE	0x48
+#define LS_SYNC		0x60
+
+#define EXT_PORTA	0x50
+#define PMU_GPIO_PORT0	0
+#define PMU_GPIO_PORT1	1
+#define GPIO_PORT2	2
+#define GPIO_PORT3	3
+#define GPIO_PORT4	4
+
+#define PMU_GRF_GPIO0A_P	0x40
+#define GRF_GPIO2A_P		0xe040
+#define GPIO_P_MASK		0x03
+
+#define GET_GPIO_PORT(pin)	(pin / 32)
+#define GET_GPIO_NUM(pin)	(pin % 32)
+#define GET_GPIO_BANK(pin)	((pin % 32) / 8)
+#define GET_GPIO_ID(pin)	((pin % 32) % 8)
+
+/* returns old clock state, enables clock, in order to do GPIO access */
+static int gpio_get_clock(uint32_t gpio_number)
+{
+	uint32_t port = GET_GPIO_PORT(gpio_number);
+	uint32_t clock_state = 0;
+
+	assert(port < 5);
+
+	switch (port) {
+	case PMU_GPIO_PORT0:
+		clock_state = (mmio_read_32(PMUCRU_BASE +
+					    CRU_PMU_CLKGATE_CON(1)) >>
+					    PCLK_GPIO0_GATE_SHIFT) & 0x01;
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
+					      PCLK_GPIO0_GATE_SHIFT));
+		break;
+	case PMU_GPIO_PORT1:
+		clock_state = (mmio_read_32(PMUCRU_BASE +
+					    CRU_PMU_CLKGATE_CON(1)) >>
+					    PCLK_GPIO1_GATE_SHIFT) & 0x01;
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
+					      PCLK_GPIO1_GATE_SHIFT));
+		break;
+	case GPIO_PORT2:
+		clock_state = (mmio_read_32(CRU_BASE +
+					    CRU_CLKGATE_CON(31)) >>
+					    PCLK_GPIO2_GATE_SHIFT) & 0x01;
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
+					      PCLK_GPIO2_GATE_SHIFT));
+		break;
+	case GPIO_PORT3:
+		clock_state = (mmio_read_32(CRU_BASE +
+					    CRU_CLKGATE_CON(31)) >>
+					    PCLK_GPIO3_GATE_SHIFT) & 0x01;
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
+					      PCLK_GPIO3_GATE_SHIFT));
+		break;
+	case GPIO_PORT4:
+		clock_state = (mmio_read_32(CRU_BASE +
+					    CRU_CLKGATE_CON(31)) >>
+					    PCLK_GPIO4_GATE_SHIFT) & 0x01;
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
+					      PCLK_GPIO4_GATE_SHIFT));
+		break;
+	default:
+		break;
+	}
+
+	return clock_state;
+}
+
+/* restores old state of gpio clock */
+void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
+{
+	uint32_t port = GET_GPIO_PORT(gpio_number);
+
+	switch (port) {
+	case PMU_GPIO_PORT0:
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO0_GATE_SHIFT));
+		break;
+	case PMU_GPIO_PORT1:
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO1_GATE_SHIFT));
+		break;
+	case GPIO_PORT2:
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO2_GATE_SHIFT));
+		break;
+	case GPIO_PORT3:
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO3_GATE_SHIFT));
+
+		break;
+	case GPIO_PORT4:
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO4_GATE_SHIFT));
+		break;
+	default:
+		break;
+	}
+}
+
+static int get_pull(int gpio)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t bank = GET_GPIO_BANK(gpio);
+	uint32_t id = GET_GPIO_ID(gpio);
+	uint32_t val, clock_state;
+
+	assert((port < 5) && (bank < 4));
+
+	clock_state = gpio_get_clock(gpio);
+
+	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
+		val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
+				   port * 16 + bank * 4);
+		val = (val >> (id * 2)) & GPIO_P_MASK;
+	} else {
+		val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
+				   (port - 2) * 16 + bank * 4);
+		val = (val >> (id * 2)) & GPIO_P_MASK;
+	}
+	gpio_put_clock(gpio, clock_state);
+
+	/*
+	 * in gpio0a, gpio0b, gpio2c, gpio2d,
+	 * 00: Z
+	 * 01: pull down
+	 * 10: Z
+	 * 11: pull up
+	 * different with other gpio, so need to correct it
+	 */
+	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
+		if (val == 3)
+			val = GPIO_PULL_UP;
+		else if (val == 1)
+			val = GPIO_PULL_DOWN;
+		else
+			val = 0;
+	}
+
+	return val;
+}
+
+static void set_pull(int gpio, int pull)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t bank = GET_GPIO_BANK(gpio);
+	uint32_t id = GET_GPIO_ID(gpio);
+	uint32_t clock_state;
+
+	assert((port < 5) && (bank < 4));
+
+	clock_state = gpio_get_clock(gpio);
+
+	/*
+	 * in gpio0a, gpio0b, gpio2c, gpio2d,
+	 * 00: Z
+	 * 01: pull down
+	 * 10: Z
+	 * 11: pull up
+	 * different with other gpio, so need to correct it
+	 */
+	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
+		if (pull == GPIO_PULL_UP)
+			pull = 3;
+		else if (pull == GPIO_PULL_DOWN)
+			pull = 1;
+		else
+			pull = 0;
+	}
+
+	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
+		mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
+			      port * 16 + bank * 4,
+			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
+	} else {
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_P +
+			      (port - 2) * 16 + bank * 4,
+			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
+	}
+	gpio_put_clock(gpio, clock_state);
+}
+
+static void set_direction(int gpio, int direction)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	uint32_t clock_state;
+
+	assert((port < 5) && (num < 32));
+
+	clock_state = gpio_get_clock(gpio);
+
+	/*
+	 * in gpio.h
+	 * #define GPIO_DIR_OUT	0
+	 * #define GPIO_DIR_IN	1
+	 * but rk3399 gpio direction 1: output, 0: input
+	 * so need to revert direction value
+	 */
+	mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
+	gpio_put_clock(gpio, clock_state);
+}
+
+static int get_direction(int gpio)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	int direction, clock_state;
+
+	assert((port < 5) && (num < 32));
+
+	clock_state = gpio_get_clock(gpio);
+
+	/*
+	 * in gpio.h
+	 * #define GPIO_DIR_OUT	0
+	 * #define GPIO_DIR_IN	1
+	 * but rk3399 gpio direction 1: output, 0: input
+	 * so need to revert direction value
+	 */
+	direction = !((mmio_read_32(gpio_port[port] +
+				    SWPORTA_DDR) >> num) & 0x1);
+	gpio_put_clock(gpio, clock_state);
+
+	return direction;
+}
+
+static int get_value(int gpio)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	int value, clock_state;
+
+	assert((port < 5) && (num < 32));
+
+	clock_state = gpio_get_clock(gpio);
+	value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
+	gpio_put_clock(gpio, clock_state);
+
+	return value;
+}
+
+static void set_value(int gpio, int value)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	uint32_t clock_state;
+
+	assert((port < 5) && (num < 32));
+
+	clock_state = gpio_get_clock(gpio);
+	mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
+							 !!value << num);
+	gpio_put_clock(gpio, clock_state);
+}
+
+void plat_rockchip_save_gpio(void)
+{
+	int i;
+	uint32_t cru_gate_save;
+
+	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
+
+	/*
+	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
+	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
+	 * and we do not care gpio0 and gpio1 clock gate, since we never
+	 * gating them
+	 */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+	/*
+	 * since gpio0, gpio1 are pmugpio, they will keep ther value
+	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
+	 * register value
+	 */
+	for (i = 2; i < 5; i++) {
+		store_gpio[i - 2].swporta_dr =
+			mmio_read_32(gpio_port[i] + SWPORTA_DR);
+		store_gpio[i - 2].swporta_ddr =
+			mmio_read_32(gpio_port[i] + SWPORTA_DDR);
+		store_gpio[i - 2].inten =
+			mmio_read_32(gpio_port[i] + INTEN);
+		store_gpio[i - 2].intmask =
+			mmio_read_32(gpio_port[i] + INTMASK);
+		store_gpio[i - 2].inttype_level =
+			mmio_read_32(gpio_port[i] + INTTYPE_LEVEL);
+		store_gpio[i - 2].int_polarity =
+			mmio_read_32(gpio_port[i] + INT_POLARITY);
+		store_gpio[i - 2].debounce =
+			mmio_read_32(gpio_port[i] + DEBOUNCE);
+		store_gpio[i - 2].ls_sync =
+			mmio_read_32(gpio_port[i] + LS_SYNC);
+	}
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			cru_gate_save | REG_SOC_WMSK);
+
+	/*
+	 * gpio0, gpio1 in pmuiomux, they will keep ther value
+	 * when shutdown logic power rail, so only need to save gpio2 ~ gpio4
+	 * iomux register value
+	 */
+	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
+		store_grf_gpio[i] =
+			mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4);
+}
+
+void plat_rockchip_restore_gpio(void)
+{
+	int i;
+	uint32_t cru_gate_save;
+
+	for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++)
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
+		      REG_SOC_WMSK | store_grf_gpio[i]);
+
+	cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31));
+
+	/*
+	 * when shutdown logic, we need to save gpio2 ~ gpio4 register,
+	 * we need to enable gpio2 ~ gpio4 clock here, since it may be gating,
+	 * and we do not care gpio0 and gpio1 clock gate, since we never
+	 * gating them
+	 */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+	for (i = 2; i < 5; i++) {
+		mmio_write_32(gpio_port[i] + SWPORTA_DR,
+				store_gpio[i - 2].swporta_dr);
+		mmio_write_32(gpio_port[i] + SWPORTA_DDR,
+				store_gpio[i - 2].swporta_ddr);
+		mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten);
+		mmio_write_32(gpio_port[i] + INTMASK,
+				store_gpio[i - 2].intmask);
+		mmio_write_32(gpio_port[i] + INTTYPE_LEVEL,
+				store_gpio[i - 2].inttype_level);
+		mmio_write_32(gpio_port[i] + INT_POLARITY,
+				store_gpio[i - 2].int_polarity);
+		mmio_write_32(gpio_port[i] + DEBOUNCE,
+				store_gpio[i - 2].debounce);
+		mmio_write_32(gpio_port[i] + LS_SYNC,
+				store_gpio[i - 2].ls_sync);
+	}
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			cru_gate_save | REG_SOC_WMSK);
+}
+
+const gpio_ops_t rk3399_gpio_ops = {
+	.get_direction = get_direction,
+	.set_direction = set_direction,
+	.get_value = get_value,
+	.set_value = set_value,
+	.set_pull = set_pull,
+	.get_pull = get_pull,
+};
+
+void plat_rockchip_gpio_init(void)
+{
+	gpio_init(&rk3399_gpio_ops);
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/Makefile b/plat/rockchip/rk3399/drivers/m0/Makefile
new file mode 100644
index 0000000..79e09f0
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/Makefile
@@ -0,0 +1,125 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Cross Compile
+M0_CROSS_COMPILE ?= arm-none-eabi-
+
+# Build architecture
+ARCH		:= cortex-m0
+
+# Build platform
+PLAT_M0		?= rk3399m0
+PLAT_M0_PMU	?= rk3399m0pmu
+
+ifeq (${V},0)
+	Q=@
+else
+	Q=
+endif
+export Q
+
+.SUFFIXES:
+
+INCLUDES		+= -Iinclude/ \
+			   -I../../include/shared/
+
+# NOTE: Add C source files here
+C_SOURCES_COMMON	:= src/startup.c
+C_SOURCES		:= src/dram.c	\
+			   src/stopwatch.c
+C_SOURCES_PMU		:= src/suspend.c
+
+# Flags definition
+COMMON_FLAGS		:= -g -mcpu=$(ARCH) -mthumb -Wall -O3 -nostdlib -mfloat-abi=soft
+CFLAGS			:= -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-common
+ASFLAGS			:= -Wa,--gdwarf-2
+LDFLAGS			:= -Wl,--gc-sections -Wl,--build-id=none
+
+# Cross tool
+CC			:= ${M0_CROSS_COMPILE}gcc
+CPP			:= ${M0_CROSS_COMPILE}cpp
+AR			:= ${M0_CROSS_COMPILE}ar
+OC			:= ${M0_CROSS_COMPILE}objcopy
+OD			:= ${M0_CROSS_COMPILE}objdump
+NM			:= ${M0_CROSS_COMPILE}nm
+
+# NOTE: The line continuation '\' is required in the next define otherwise we
+# end up with a line-feed characer at the end of the last c filename.
+# Also bare this issue in mind if extending the list of supported filetypes.
+define SOURCES_TO_OBJS
+	$(notdir $(patsubst %.c,%.o,$(filter %.c,$(1)))) \
+	$(notdir $(patsubst %.S,%.o,$(filter %.S,$(1))))
+endef
+
+SOURCES_COMMON		:= $(C_SOURCES_COMMON)
+SOURCES 		:= $(C_SOURCES)
+SOURCES_PMU		:= $(C_SOURCES_PMU)
+OBJS_COMMON		:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES_COMMON)))
+OBJS 			:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES)))
+OBJS_PMU 		:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES_PMU)))
+LINKERFILE		:= $(BUILD)/$(PLAT_M0).ld
+MAPFILE			:= $(BUILD)/$(PLAT_M0).map
+MAPFILE_PMU		:= $(BUILD)/$(PLAT_M0_PMU).map
+ELF 			:= $(BUILD)/$(PLAT_M0).elf
+ELF_PMU			:= $(BUILD)/$(PLAT_M0_PMU).elf
+BIN 			:= $(BUILD)/$(PLAT_M0).bin
+BIN_PMU			:= $(BUILD)/$(PLAT_M0_PMU).bin
+LINKERFILE_SRC		:= src/$(PLAT_M0).ld.S
+
+# Function definition related compilation
+define MAKE_C
+$(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2))))
+-include $(patsubst %.o,%.d,$(OBJ))
+
+$(OBJ) : $(2)
+	@echo "  CC      $$<"
+	$$(Q)$$(CC) $$(COMMON_FLAGS) $$(CFLAGS) $$(INCLUDES) -MMD -MT $$@ -c $$< -o $$@
+endef
+
+define MAKE_S
+$(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2))))
+
+$(OBJ) : $(2)
+	@echo "  AS      $$<"
+	$$(Q)$$(CC) -x assembler-with-cpp $$(COMMON_FLAGS) $$(ASFLAGS) -c $$< -o $$@
+endef
+
+define MAKE_OBJS
+	$(eval C_OBJS := $(filter %.c,$(2)))
+	$(eval REMAIN := $(filter-out %.c,$(2)))
+	$(eval $(foreach obj,$(C_OBJS),$(call MAKE_C,$(1),$(obj),$(3))))
+
+	$(eval S_OBJS := $(filter %.S,$(REMAIN)))
+	$(eval REMAIN := $(filter-out %.S,$(REMAIN)))
+	$(eval $(foreach obj,$(S_OBJS),$(call MAKE_S,$(1),$(obj),$(3))))
+
+	$(and $(REMAIN),$(error Unexpected source files present: $(REMAIN)))
+endef
+
+.PHONY: all
+all: $(BIN) $(BIN_PMU)
+
+.DEFAULT_GOAL := all
+
+$(LINKERFILE): $(LINKERFILE_SRC)
+	$(CC) $(COMMON_FLAGS) $(INCLUDES) -P -E -D__LINKER__ -MMD -MF $@.d -MT $@ -o $@ $<
+-include $(LINKERFILE).d
+
+$(ELF) : $(OBJS) $(OBJS_COMMON) $(LINKERFILE)
+	@echo "  LD      $@"
+	$(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS) $(OBJS_COMMON)
+
+%.bin : %.elf
+	@echo "  BIN     $@"
+	$(Q)$(OC) -O binary $< $@
+
+$(ELF_PMU) : $(OBJS_COMMON) $(OBJS_PMU) $(LINKERFILE)
+	@echo "  LD      $@"
+	$(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE_PMU) -Wl,-T$(LINKERFILE) $(OBJS_PMU) $(OBJS_COMMON)
+
+$(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_COMMON),$(1)))
+$(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES),$(1)))
+$(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_PMU),$(1)))
diff --git a/plat/rockchip/rk3399/drivers/m0/include/addressmap.h b/plat/rockchip/rk3399/drivers/m0/include/addressmap.h
new file mode 100644
index 0000000..d431437
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/include/addressmap.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ADDRESSMAP_H
+#define ADDRESSMAP_H
+
+#include <addressmap_shared.h>
+
+/* Registers base address for M0 */
+#define MMIO_BASE			0x40000000
+
+#endif /* ADDRESSMAP_H */
diff --git a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
new file mode 100644
index 0000000..2e90694
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RK3399_MCU_H
+#define RK3399_MCU_H
+
+#include <addressmap.h>
+
+typedef unsigned int uint32_t;
+
+#define mmio_read_32(c)	({unsigned int __v = \
+				(*(volatile unsigned int *)(c)); __v; })
+#define mmio_write_32(c, v)	((*(volatile unsigned int *)(c)) = (v))
+
+#define mmio_clrbits_32(addr, clear) \
+		mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)))
+#define mmio_setbits_32(addr, set) \
+		mmio_write_32(addr, (mmio_read_32(addr)) | (set))
+#define mmio_clrsetbits_32(addr, clear, set) \
+		mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)) | (set))
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+void stopwatch_init_usecs_expire(unsigned int usecs);
+int stopwatch_expired(void);
+void stopwatch_reset(void);
+
+#endif /* RK3399_MCU_H */
diff --git a/plat/rockchip/rk3399/drivers/m0/src/dram.c b/plat/rockchip/rk3399/drivers/m0/src/dram.c
new file mode 100644
index 0000000..84e8884
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/dram.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <dram_regs.h>
+#include <m0_param.h>
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#include "misc_regs.h"
+#include "rk3399_mcu.h"
+
+static uint32_t gatedis_con0;
+
+static void idle_port(void)
+{
+	gatedis_con0 = mmio_read_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0);
+	mmio_write_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0, 0x3fffffff);
+
+	mmio_setbits_32(PMU_BASE + PMU_BUS_IDLE_REQ,
+			(1 << PMU_IDLE_REQ_MSCH0) | (1 << PMU_IDLE_REQ_MSCH1));
+	while ((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) &
+		((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0))) !=
+		((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0)))
+		continue;
+}
+
+static void deidle_port(void)
+{
+	mmio_clrbits_32(PMU_BASE + PMU_BUS_IDLE_REQ,
+			(1 << PMU_IDLE_REQ_MSCH0) | (1 << PMU_IDLE_REQ_MSCH1));
+	while (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) &
+	       ((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0)))
+		continue;
+
+	/* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */
+	mmio_write_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0, gatedis_con0);
+}
+
+static void ddr_set_pll(void)
+{
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_SLOW_MODE));
+
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_POWER_DOWN(1));
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON0,
+		      mmio_read_32(PARAM_ADDR + PARAM_DPLL_CON0));
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON1,
+		      mmio_read_32(PARAM_ADDR + PARAM_DPLL_CON1));
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_POWER_DOWN(0));
+
+	while ((mmio_read_32(CRU_BASE + CRU_DPLL_CON2) & (1u << 31)) == 0)
+		continue;
+
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_NORMAL_MODE));
+}
+
+__attribute__((noreturn)) void m0_main(void)
+{
+	mmio_setbits_32(PHY_REG(0, 927), (1 << 22));
+	mmio_setbits_32(PHY_REG(1, 927), (1 << 22));
+	idle_port();
+
+	mmio_write_32(CIC_BASE + CIC_CTRL0,
+		      (((0x3 << 4) | (1 << 2) | 1) << 16) |
+		      (1 << 2) | 1 |
+		      mmio_read_32(PARAM_ADDR + PARAM_FREQ_SELECT));
+	while ((mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)) == 0)
+		continue;
+
+	ddr_set_pll();
+	mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002);
+	while ((mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0)) == 0)
+		continue;
+
+	deidle_port();
+	mmio_clrbits_32(PHY_REG(0, 927), (1 << 22));
+	mmio_clrbits_32(PHY_REG(1, 927), (1 << 22));
+
+	mmio_write_32(PARAM_ADDR + PARAM_M0_DONE, M0_DONE_FLAG);
+
+	for (;;)
+		__asm__ volatile ("wfi");
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
new file mode 100644
index 0000000..bfe054e
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <m0_param.h>
+
+OUTPUT_FORMAT("elf32-littlearm")
+
+SECTIONS {
+	.m0_bin 0 : {
+		KEEP(*(.isr_vector))
+		ASSERT(. == 0xc0, "ISR vector has the wrong size.");
+		ASSERT(. == PARAM_ADDR, "M0 params should go right behind ISR table.");
+		. += PARAM_M0_SIZE;
+		*(.text*)
+		*(.rodata*)
+		*(.data*)
+		*(.bss*)
+		. = ALIGN(8);
+		*(.co_stack*)
+	}
+
+	/DISCARD/ : { *(.comment) *(.note*) }
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/startup.c b/plat/rockchip/rk3399/drivers/m0/src/startup.c
new file mode 100644
index 0000000..dfd8af2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/startup.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "rk3399_mcu.h"
+
+/* Stack configuration */
+#define STACK_SIZE	0x00000040
+__attribute__ ((section(".co_stack")))
+unsigned long pstack[STACK_SIZE];
+
+/* Macro definition */
+#define WEAK __attribute__ ((weak))
+
+/* System exception vector handler */
+__attribute__ ((used))
+void WEAK reset_handler(void);
+void WEAK nmi_handler(void);
+void WEAK hardware_fault_handler(void);
+void WEAK svc_handler(void);
+void WEAK pend_sv_handler(void);
+void WEAK systick_handler(void);
+
+extern int m0_main(void);
+
+/* Function prototypes */
+static void default_reset_handler(void);
+static void default_handler(void);
+
+/*
+ * The minimal vector table for a Cortex M3.  Note that the proper constructs
+ * must be placed on this to ensure that it ends up at physical address
+ * 0x00000000.
+ */
+__attribute__ ((used, section(".isr_vector")))
+void (* const g_pfnVectors[])(void) = {
+	/* core Exceptions */
+	(void *)&pstack[STACK_SIZE], /* the initial stack pointer */
+	reset_handler,
+	nmi_handler,
+	hardware_fault_handler,
+	0, 0, 0, 0, 0, 0, 0,
+	svc_handler,
+	0, 0,
+	pend_sv_handler,
+	systick_handler,
+
+	/* external exceptions */
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0
+};
+
+/**
+ * This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied m0_main() routine is called.
+ */
+static void default_reset_handler(void)
+{
+	/* call the application's entry point */
+	m0_main();
+}
+
+/**
+ * Provide weak aliases for each Exception handler to the Default_Handler.
+ * As they are weak aliases, any function with the same name will override
+ * this definition.
+ */
+#pragma weak reset_handler = default_reset_handler
+#pragma weak nmi_handler = default_handler
+#pragma weak hardware_fault_handler = default_handler
+#pragma weak svc_handler = default_handler
+#pragma weak pend_sv_handler = default_handler
+#pragma weak systick_handler = default_handler
+
+/**
+ * This is the code that gets called when the processor receives
+ * an unexpected interrupt.  This simply enters an infinite loop,
+ * preserving the system state for examination by a debugger.
+ */
+static void default_handler(void)
+{
+    /* go into an infinite loop. */
+	while (1)
+		;
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c b/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c
new file mode 100644
index 0000000..5af8caa
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <m0_param.h>
+#include "rk3399_mcu.h"
+
+/* use 24MHz SysTick */
+#define US_TO_CYCLE(US)	(US * 24)
+
+#define SYST_CST	0xe000e010
+/* enable counter */
+#define ENABLE		(1 << 0)
+/* count down to 0 does not cause SysTick exception to pend */
+#define TICKINT		(1 << 1)
+/* core clock used for SysTick */
+#define CLKSOURCE	(1 << 2)
+
+#define COUNTFLAG	(1 << 16)
+#define SYST_RVR	0xe000e014
+#define MAX_VALUE	0xffffff
+#define MAX_USECS	(MAX_VALUE / US_TO_CYCLE(1))
+#define SYST_CVR	0xe000e018
+#define SYST_CALIB	0xe000e01c
+
+unsigned int remaining_usecs;
+
+static inline void stopwatch_set_usecs(void)
+{
+	unsigned int cycle;
+	unsigned int usecs = MIN(MAX_USECS, remaining_usecs);
+
+	remaining_usecs -= usecs;
+	cycle = US_TO_CYCLE(usecs);
+	mmio_write_32(SYST_RVR, cycle);
+	mmio_write_32(SYST_CVR, 0);
+
+	mmio_write_32(SYST_CST, ENABLE | TICKINT | CLKSOURCE);
+}
+
+void stopwatch_init_usecs_expire(unsigned int usecs)
+{
+	/*
+	 * Enter an inifite loop if the stopwatch is in use. This will allow the
+	 * state to be analyzed with a debugger.
+	 */
+	if (mmio_read_32(SYST_CST) & ENABLE)
+		while (1)
+			;
+
+	remaining_usecs = usecs;
+	stopwatch_set_usecs();
+}
+
+int stopwatch_expired(void)
+{
+	int val = mmio_read_32(SYST_CST);
+	if ((val & COUNTFLAG) || !(val & ENABLE)) {
+		if (!remaining_usecs)
+			return 1;
+
+		stopwatch_set_usecs();
+	}
+
+	return 0;
+}
+
+void stopwatch_reset(void)
+{
+	mmio_clrbits_32(SYST_CST, ENABLE);
+	remaining_usecs = 0;
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/suspend.c b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
new file mode 100644
index 0000000..9ad2fa2
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pmu_regs.h>
+#include "rk3399_mcu.h"
+
+#define M0_SCR			0xe000ed10  /* System Control Register (SCR) */
+
+#define SCR_SLEEPDEEP_SHIFT	(1 << 2)
+
+__attribute__((noreturn)) void m0_main(void)
+{
+	unsigned int status_value;
+
+	/*
+	 * PMU sometimes doesn't clear power mode bit as it's supposed to due
+	 * to a hardware bug. Make the M0 clear it manually to be sure,
+	 * otherwise interrupts some cases with concurrent wake interrupts
+	 * we stay asleep forever.
+	 */
+	while (1) {
+		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
+		if (status_value) {
+			mmio_clrbits_32(PMU_BASE + PMU_PWRMODE_CON, 0x01);
+			break;
+		}
+	}
+
+	/*
+	 * FSM power secquence is .. -> ST_INPUT_CLAMP(step.17) -> .. ->
+	 * ST_WAKEUP_RESET -> ST_EXT_PWRUP-> ST_RELEASE_CLAMP ->
+	 * ST_24M_OSC_EN -> .. -> ST_WAKEUP_RESET_CLR(step.26) -> ..,
+	 * INPUT_CLAMP and WAKEUP_RESET will hold the SOC not affect by
+	 * power or other single glitch, but WAKEUP_RESET need work with 24MHz,
+	 * so between RELEASE_CLAMP and 24M_OSC_EN, there have a chance
+	 * that glitch will affect SOC, and mess up SOC status, so we
+	 * addressmap_shared software clamp between ST_INPUT_CLAMP and
+	 * ST_WAKEUP_RESET_CLR to avoid this happen.
+	 */
+	while (1) {
+		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
+		if (status_value >= 17)  {
+			mmio_setbits_32(PMU_BASE + PMU_SFT_CON, 0x02);
+			break;
+		}
+
+	}
+
+	while (1) {
+		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
+		if (status_value >= 26)  {
+			mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 0x02);
+			break;
+		}
+	}
+
+	for (;;)
+		__asm__ volatile ("wfi");
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
new file mode 100644
index 0000000..cad76ac
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <m0_ctl.h>
+#include <plat_private.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+void m0_init(void)
+{
+	/* secure config for M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7));
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), WMSK_BIT(12));
+
+	/* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */
+	mmio_setbits_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, 0x02);
+
+	/*
+	 * To switch the parent to xin24M and div == 1,
+	 *
+	 * We need to close most of the PLLs and clocks except the OSC 24MHz
+	 * durning suspend, and this should be enough to supplies the ddrfreq,
+	 * For the simple handle, we just keep the fixed 24MHz to supply the
+	 * suspend and ddrfreq directly.
+	 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0,
+		      BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8));
+
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2, WMSK_BIT(5));
+}
+
+void m0_configure_execute_addr(uintptr_t addr)
+{
+	/* set the execute address for M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3),
+		      BITS_WITH_WMASK((addr >> 12) & 0xffff,
+				      0xffffu, 0));
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7),
+		      BITS_WITH_WMASK((addr >> 28) & 0xf,
+				      0xfu, 0));
+}
+
+void m0_start(void)
+{
+	/* enable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0x0, 0xf, 0));
+
+	/* clean the PARAM_M0_DONE flag, mean that M0 will start working */
+	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_DONE, 0);
+	dmbst();
+
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x0, 0x4, 0));
+
+	udelay(5);
+	/* start M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x0, 0x20, 0));
+	dmbst();
+}
+
+void m0_stop(void)
+{
+	/* stop M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x24, 0x24, 0));
+
+	/* disable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0xf, 0xf, 0));
+}
+
+void m0_wait_done(void)
+{
+	do {
+		/*
+		 * Don't starve the M0 for access to SRAM, so delay before
+		 * reading the PARAM_M0_DONE value again.
+		 */
+		udelay(5);
+		dsb();
+	} while (mmio_read_32(M0_PARAM_ADDR + PARAM_M0_DONE) != M0_DONE_FLAG);
+
+	/*
+	 * Let the M0 settle into WFI before we leave. This is so we don't reset
+	 * the M0 in a bad spot which can cause problems with the M0.
+	 */
+	udelay(10);
+	dsb();
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
new file mode 100644
index 0000000..7542e22
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef M0_CTL_H
+#define M0_CTL_H
+
+#include <m0_param.h>
+
+#define M0_BINCODE_BASE 	((uintptr_t)rk3399m0_bin)
+#define M0_PARAM_ADDR		(M0_BINCODE_BASE + PARAM_ADDR)
+#define M0PMU_BINCODE_BASE	((uintptr_t)rk3399m0pmu_bin)
+
+/* pmu_fw.c */
+extern char rk3399m0_bin[];
+extern char rk3399m0_bin_end[];
+
+extern char rk3399m0pmu_bin[];
+extern char rk3399m0pmu_bin_end[];
+
+extern void m0_init(void);
+extern void m0_start(void);
+extern void m0_stop(void);
+extern void m0_wait_done(void);
+extern void m0_configure_execute_addr(uintptr_t addr);
+
+#endif /* M0_CTL_H */
diff --git a/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
new file mode 100644
index 0000000..546c09a
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+#include <pmu_regs.h>
+
+	.globl	clst_warmboot_data
+
+	.macro sram_func _name
+	.cfi_sections .debug_frame
+	.section .sram.text, "ax"
+	.type \_name, %function
+	.cfi_startproc
+	\_name:
+	.endm
+
+#define CRU_CLKSEL_CON6	0x118
+
+#define DDRCTL0_C_SYSREQ_CFG 0x0100
+#define DDRCTL1_C_SYSREQ_CFG 0x1000
+
+#define DDRC0_SREF_DONE_EXT 0x01
+#define DDRC1_SREF_DONE_EXT 0x04
+
+#define PLL_MODE_SHIFT	(0x8)
+#define PLL_NORMAL_MODE	((0x3 << (PLL_MODE_SHIFT + 16)) | \
+						 (0x1 << PLL_MODE_SHIFT))
+#define MPIDR_CLST_L_BITS 0x0
+	/*
+	 * For different socs, if we want to speed up warmboot,
+	 * we need to config some regs here.
+	 * If scu was suspend, we must resume related clk
+	 * from slow (24M) mode to normal mode first.
+	 * X0: MPIDR_EL1 & MPIDR_CLUSTER_MASK
+	 */
+.macro	func_rockchip_clst_warmboot
+	adr	x4, clst_warmboot_data
+	lsr	x5, x0, #6
+	ldr	w3, [x4, x5]
+	str	wzr, [x4, x5]
+	cmp	w3, #PMU_CLST_RET
+	b.ne	clst_warmboot_end
+	ldr	w6, =(PLL_NORMAL_MODE)
+	/*
+	 * core_l offset is CRU_BASE + 0xc,
+	 * core_b offset is CRU_BASE + 0x2c
+	 */
+	ldr	x7, =(CRU_BASE + 0xc)
+	lsr	x2, x0, #3
+	str	w6, [x7, x2]
+clst_warmboot_end:
+.endm
+
+.macro rockchip_clst_warmboot_data
+clst_warmboot_data:
+	.rept	PLATFORM_CLUSTER_COUNT
+	.word	0
+	.endr
+.endm
+
+	/* -----------------------------------------------
+	 * void sram_func_set_ddrctl_pll(uint32_t pll_src)
+	 * Function to switch the PLL source for ddrctrl
+	 * In: x0 - The PLL of the clk_ddrc clock source
+	 * out: None
+	 * Clobber list : x0 - x3, x5, x8 - x10
+	 * -----------------------------------------------
+	 */
+
+	.globl	sram_func_set_ddrctl_pll
+
+sram_func sram_func_set_ddrctl_pll
+	/* backup parameter */
+	mov	x8, x0
+
+	/* disable the MMU at EL3 */
+	mrs 	x9, sctlr_el3
+	bic	x10, x9, #(SCTLR_M_BIT)
+	msr 	sctlr_el3, x10
+	isb
+	dsb 	sy
+
+	/* enable ddrctl0_1 idle request */
+	mov	x5, PMU_BASE
+	ldr	w0, [x5, #PMU_SFT_CON]
+	orr	w0, w0, #DDRCTL0_C_SYSREQ_CFG
+	orr	w0, w0, #DDRCTL1_C_SYSREQ_CFG
+	str	w0, [x5, #PMU_SFT_CON]
+
+check_ddrc0_1_sref_enter:
+	ldr	w1, [x5, #PMU_DDR_SREF_ST]
+	and	w2, w1, #DDRC0_SREF_DONE_EXT
+	and	w3, w1, #DDRC1_SREF_DONE_EXT
+	orr	w2, w2, w3
+	cmp	w2, #(DDRC0_SREF_DONE_EXT | DDRC1_SREF_DONE_EXT)
+	b.eq	check_ddrc0_1_sref_enter
+
+	/*
+	 * select a PLL for ddrctrl:
+	 * x0 = 0: ALPLL
+	 * x0 = 1: ABPLL
+	 * x0 = 2: DPLL
+	 * x0 = 3: GPLLL
+	 */
+	mov     x5, CRU_BASE
+	lsl	w0, w8, #4
+	orr	w0, w0, #0x00300000
+	str 	w0, [x5, #CRU_CLKSEL_CON6]
+
+	/* disable ddrctl0_1 idle request */
+	mov	x5, PMU_BASE
+	ldr	w0, [x5, #PMU_SFT_CON]
+	bic	w0, w0, #DDRCTL0_C_SYSREQ_CFG
+	bic	w0, w0, #DDRCTL1_C_SYSREQ_CFG
+	str	w0, [x5, #PMU_SFT_CON]
+
+check_ddrc0_1_sref_exit:
+	ldr	w1, [x5, #PMU_DDR_SREF_ST]
+	and	w2, w1, #DDRC0_SREF_DONE_EXT
+	and	w3, w1, #DDRC1_SREF_DONE_EXT
+	orr	w2, w2, w3
+	cmp	w2, #0x0
+	b.eq	check_ddrc0_1_sref_exit
+
+	/* reenable the MMU at EL3 */
+	msr 	sctlr_el3, x9
+	isb
+	dsb 	sy
+
+	ret
+endfunc sram_func_set_ddrctl_pll
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
new file mode 100644
index 0000000..30941fd
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -0,0 +1,1606 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <drivers/gpio.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <dfs.h>
+#include <m0_ctl.h>
+#include <plat_params.h>
+#include <plat_private.h>
+#include <pmu.h>
+#include <pmu_com.h>
+#include <pwm.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+#include <suspend.h>
+
+DEFINE_BAKERY_LOCK(rockchip_pd_lock);
+
+static uint32_t cpu_warm_boot_addr;
+static char store_sram[SRAM_BIN_LIMIT + SRAM_TEXT_LIMIT + SRAM_DATA_LIMIT];
+static uint32_t store_cru[CRU_SDIO0_CON1 / 4 + 1];
+static uint32_t store_usbphy0[7];
+static uint32_t store_usbphy1[7];
+static uint32_t store_grf_io_vsel;
+static uint32_t store_grf_soc_con0;
+static uint32_t store_grf_soc_con1;
+static uint32_t store_grf_soc_con2;
+static uint32_t store_grf_soc_con3;
+static uint32_t store_grf_soc_con4;
+static uint32_t store_grf_soc_con7;
+static uint32_t store_grf_ddrc_con[4];
+static uint32_t store_wdt0[2];
+static uint32_t store_wdt1[2];
+static gicv3_dist_ctx_t dist_ctx;
+static gicv3_redist_ctx_t rdist_ctx;
+
+/*
+ * There are two ways to powering on or off on core.
+ * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
+ *    it is core_pwr_pd mode
+ * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
+ *     then, if the core enter into wfi, it power domain will be
+ *     powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode
+ * so we need core_pm_cfg_info to distinguish which method be used now.
+ */
+
+static uint32_t core_pm_cfg_info[PLATFORM_CORE_COUNT]
+#if USE_COHERENT_MEM
+__attribute__ ((section("tzfw_coherent_mem")))
+#endif
+;/* coheront */
+
+static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
+{
+	uint32_t bus_id = BIT(bus);
+	uint32_t bus_req;
+	uint32_t wait_cnt = 0;
+	uint32_t bus_state, bus_ack;
+
+	if (state)
+		bus_req = BIT(bus);
+	else
+		bus_req = 0;
+
+	mmio_clrsetbits_32(PMU_BASE + PMU_BUS_IDLE_REQ, bus_id, bus_req);
+
+	do {
+		bus_state = mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & bus_id;
+		bus_ack = mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK) & bus_id;
+		if (bus_state == bus_req && bus_ack == bus_req)
+			break;
+
+		wait_cnt++;
+		udelay(1);
+	} while (wait_cnt < MAX_WAIT_COUNT);
+
+	if (bus_state != bus_req || bus_ack != bus_req) {
+		INFO("%s:st=%x(%x)\n", __func__,
+		     mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST),
+		     bus_state);
+		INFO("%s:st=%x(%x)\n", __func__,
+		     mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK),
+		     bus_ack);
+	}
+}
+
+struct pmu_slpdata_s pmu_slpdata;
+
+static void qos_restore(void)
+{
+	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.gpu_qos, GPU);
+	if (pmu_power_domain_st(PD_ISP0) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.isp0_m0_qos, ISP0_M0);
+		RESTORE_QOS(pmu_slpdata.isp0_m1_qos, ISP0_M1);
+	}
+	if (pmu_power_domain_st(PD_ISP1) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.isp1_m0_qos, ISP1_M0);
+		RESTORE_QOS(pmu_slpdata.isp1_m1_qos, ISP1_M1);
+	}
+	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.vop_big_r, VOP_BIG_R);
+		RESTORE_QOS(pmu_slpdata.vop_big_w, VOP_BIG_W);
+		RESTORE_QOS(pmu_slpdata.vop_little, VOP_LITTLE);
+	}
+	if (pmu_power_domain_st(PD_HDCP) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.hdcp_qos, HDCP);
+	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.gmac_qos, GMAC);
+	if (pmu_power_domain_st(PD_CCI) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.cci_m0_qos, CCI_M0);
+		RESTORE_QOS(pmu_slpdata.cci_m1_qos, CCI_M1);
+	}
+	if (pmu_power_domain_st(PD_SD) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.sdmmc_qos, SDMMC);
+	if (pmu_power_domain_st(PD_EMMC) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.emmc_qos, EMMC);
+	if (pmu_power_domain_st(PD_SDIOAUDIO) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.sdio_qos, SDIO);
+	if (pmu_power_domain_st(PD_GIC) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.gic_qos, GIC);
+	if (pmu_power_domain_st(PD_RGA) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.rga_r_qos, RGA_R);
+		RESTORE_QOS(pmu_slpdata.rga_w_qos, RGA_W);
+	}
+	if (pmu_power_domain_st(PD_IEP) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.iep_qos, IEP);
+	if (pmu_power_domain_st(PD_USB3) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.usb_otg0_qos, USB_OTG0);
+		RESTORE_QOS(pmu_slpdata.usb_otg1_qos, USB_OTG1);
+	}
+	if (pmu_power_domain_st(PD_PERIHP) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.usb_host0_qos, USB_HOST0);
+		RESTORE_QOS(pmu_slpdata.usb_host1_qos, USB_HOST1);
+		RESTORE_QOS(pmu_slpdata.perihp_nsp_qos, PERIHP_NSP);
+	}
+	if (pmu_power_domain_st(PD_PERILP) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.dmac0_qos, DMAC0);
+		RESTORE_QOS(pmu_slpdata.dmac1_qos, DMAC1);
+		RESTORE_QOS(pmu_slpdata.dcf_qos, DCF);
+		RESTORE_QOS(pmu_slpdata.crypto0_qos, CRYPTO0);
+		RESTORE_QOS(pmu_slpdata.crypto1_qos, CRYPTO1);
+		RESTORE_QOS(pmu_slpdata.perilp_nsp_qos, PERILP_NSP);
+		RESTORE_QOS(pmu_slpdata.perilpslv_nsp_qos, PERILPSLV_NSP);
+		RESTORE_QOS(pmu_slpdata.peri_cm1_qos, PERI_CM1);
+	}
+	if (pmu_power_domain_st(PD_VDU) == pmu_pd_on)
+		RESTORE_QOS(pmu_slpdata.video_m0_qos, VIDEO_M0);
+	if (pmu_power_domain_st(PD_VCODEC) == pmu_pd_on) {
+		RESTORE_QOS(pmu_slpdata.video_m1_r_qos, VIDEO_M1_R);
+		RESTORE_QOS(pmu_slpdata.video_m1_w_qos, VIDEO_M1_W);
+	}
+}
+
+static void qos_save(void)
+{
+	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.gpu_qos, GPU);
+	if (pmu_power_domain_st(PD_ISP0) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.isp0_m0_qos, ISP0_M0);
+		SAVE_QOS(pmu_slpdata.isp0_m1_qos, ISP0_M1);
+	}
+	if (pmu_power_domain_st(PD_ISP1) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.isp1_m0_qos, ISP1_M0);
+		SAVE_QOS(pmu_slpdata.isp1_m1_qos, ISP1_M1);
+	}
+	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.vop_big_r, VOP_BIG_R);
+		SAVE_QOS(pmu_slpdata.vop_big_w, VOP_BIG_W);
+		SAVE_QOS(pmu_slpdata.vop_little, VOP_LITTLE);
+	}
+	if (pmu_power_domain_st(PD_HDCP) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.hdcp_qos, HDCP);
+	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.gmac_qos, GMAC);
+	if (pmu_power_domain_st(PD_CCI) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.cci_m0_qos, CCI_M0);
+		SAVE_QOS(pmu_slpdata.cci_m1_qos, CCI_M1);
+	}
+	if (pmu_power_domain_st(PD_SD) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.sdmmc_qos, SDMMC);
+	if (pmu_power_domain_st(PD_EMMC) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.emmc_qos, EMMC);
+	if (pmu_power_domain_st(PD_SDIOAUDIO) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.sdio_qos, SDIO);
+	if (pmu_power_domain_st(PD_GIC) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.gic_qos, GIC);
+	if (pmu_power_domain_st(PD_RGA) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.rga_r_qos, RGA_R);
+		SAVE_QOS(pmu_slpdata.rga_w_qos, RGA_W);
+	}
+	if (pmu_power_domain_st(PD_IEP) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.iep_qos, IEP);
+	if (pmu_power_domain_st(PD_USB3) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.usb_otg0_qos, USB_OTG0);
+		SAVE_QOS(pmu_slpdata.usb_otg1_qos, USB_OTG1);
+	}
+	if (pmu_power_domain_st(PD_PERIHP) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.usb_host0_qos, USB_HOST0);
+		SAVE_QOS(pmu_slpdata.usb_host1_qos, USB_HOST1);
+		SAVE_QOS(pmu_slpdata.perihp_nsp_qos, PERIHP_NSP);
+	}
+	if (pmu_power_domain_st(PD_PERILP) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.dmac0_qos, DMAC0);
+		SAVE_QOS(pmu_slpdata.dmac1_qos, DMAC1);
+		SAVE_QOS(pmu_slpdata.dcf_qos, DCF);
+		SAVE_QOS(pmu_slpdata.crypto0_qos, CRYPTO0);
+		SAVE_QOS(pmu_slpdata.crypto1_qos, CRYPTO1);
+		SAVE_QOS(pmu_slpdata.perilp_nsp_qos, PERILP_NSP);
+		SAVE_QOS(pmu_slpdata.perilpslv_nsp_qos, PERILPSLV_NSP);
+		SAVE_QOS(pmu_slpdata.peri_cm1_qos, PERI_CM1);
+	}
+	if (pmu_power_domain_st(PD_VDU) == pmu_pd_on)
+		SAVE_QOS(pmu_slpdata.video_m0_qos, VIDEO_M0);
+	if (pmu_power_domain_st(PD_VCODEC) == pmu_pd_on) {
+		SAVE_QOS(pmu_slpdata.video_m1_r_qos, VIDEO_M1_R);
+		SAVE_QOS(pmu_slpdata.video_m1_w_qos, VIDEO_M1_W);
+	}
+}
+
+static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
+{
+	uint32_t state;
+
+	if (pmu_power_domain_st(pd_id) == pd_state)
+		goto out;
+
+	if (pd_state == pmu_pd_on)
+		pmu_power_domain_ctr(pd_id, pd_state);
+
+	state = (pd_state == pmu_pd_off) ? BUS_IDLE : BUS_ACTIVE;
+
+	switch (pd_id) {
+	case PD_GPU:
+		pmu_bus_idle_req(BUS_ID_GPU, state);
+		break;
+	case PD_VIO:
+		pmu_bus_idle_req(BUS_ID_VIO, state);
+		break;
+	case PD_ISP0:
+		pmu_bus_idle_req(BUS_ID_ISP0, state);
+		break;
+	case PD_ISP1:
+		pmu_bus_idle_req(BUS_ID_ISP1, state);
+		break;
+	case PD_VO:
+		pmu_bus_idle_req(BUS_ID_VOPB, state);
+		pmu_bus_idle_req(BUS_ID_VOPL, state);
+		break;
+	case PD_HDCP:
+		pmu_bus_idle_req(BUS_ID_HDCP, state);
+		break;
+	case PD_TCPD0:
+		break;
+	case PD_TCPD1:
+		break;
+	case PD_GMAC:
+		pmu_bus_idle_req(BUS_ID_GMAC, state);
+		break;
+	case PD_CCI:
+		pmu_bus_idle_req(BUS_ID_CCIM0, state);
+		pmu_bus_idle_req(BUS_ID_CCIM1, state);
+		break;
+	case PD_SD:
+		pmu_bus_idle_req(BUS_ID_SD, state);
+		break;
+	case PD_EMMC:
+		pmu_bus_idle_req(BUS_ID_EMMC, state);
+		break;
+	case PD_EDP:
+		pmu_bus_idle_req(BUS_ID_EDP, state);
+		break;
+	case PD_SDIOAUDIO:
+		pmu_bus_idle_req(BUS_ID_SDIOAUDIO, state);
+		break;
+	case PD_GIC:
+		pmu_bus_idle_req(BUS_ID_GIC, state);
+		break;
+	case PD_RGA:
+		pmu_bus_idle_req(BUS_ID_RGA, state);
+		break;
+	case PD_VCODEC:
+		pmu_bus_idle_req(BUS_ID_VCODEC, state);
+		break;
+	case PD_VDU:
+		pmu_bus_idle_req(BUS_ID_VDU, state);
+		break;
+	case PD_IEP:
+		pmu_bus_idle_req(BUS_ID_IEP, state);
+		break;
+	case PD_USB3:
+		pmu_bus_idle_req(BUS_ID_USB3, state);
+		break;
+	case PD_PERIHP:
+		pmu_bus_idle_req(BUS_ID_PERIHP, state);
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	if (pd_state == pmu_pd_off)
+		pmu_power_domain_ctr(pd_id, pd_state);
+
+out:
+	return 0;
+}
+
+static uint32_t pmu_powerdomain_state;
+
+static void pmu_power_domains_suspend(void)
+{
+	clk_gate_con_save();
+	clk_gate_con_disable();
+	qos_save();
+	pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
+	pmu_set_power_domain(PD_GPU, pmu_pd_off);
+	pmu_set_power_domain(PD_TCPD0, pmu_pd_off);
+	pmu_set_power_domain(PD_TCPD1, pmu_pd_off);
+	pmu_set_power_domain(PD_VO, pmu_pd_off);
+	pmu_set_power_domain(PD_ISP0, pmu_pd_off);
+	pmu_set_power_domain(PD_ISP1, pmu_pd_off);
+	pmu_set_power_domain(PD_HDCP, pmu_pd_off);
+	pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_off);
+	pmu_set_power_domain(PD_GMAC, pmu_pd_off);
+	pmu_set_power_domain(PD_EDP, pmu_pd_off);
+	pmu_set_power_domain(PD_IEP, pmu_pd_off);
+	pmu_set_power_domain(PD_RGA, pmu_pd_off);
+	pmu_set_power_domain(PD_VCODEC, pmu_pd_off);
+	pmu_set_power_domain(PD_VDU, pmu_pd_off);
+	pmu_set_power_domain(PD_USB3, pmu_pd_off);
+	pmu_set_power_domain(PD_EMMC, pmu_pd_off);
+	pmu_set_power_domain(PD_VIO, pmu_pd_off);
+	pmu_set_power_domain(PD_SD, pmu_pd_off);
+	pmu_set_power_domain(PD_PERIHP, pmu_pd_off);
+	clk_gate_con_restore();
+}
+
+static void pmu_power_domains_resume(void)
+{
+	clk_gate_con_save();
+	clk_gate_con_disable();
+	if (!(pmu_powerdomain_state & BIT(PD_VDU)))
+		pmu_set_power_domain(PD_VDU, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_VCODEC)))
+		pmu_set_power_domain(PD_VCODEC, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_RGA)))
+		pmu_set_power_domain(PD_RGA, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_IEP)))
+		pmu_set_power_domain(PD_IEP, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_EDP)))
+		pmu_set_power_domain(PD_EDP, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_GMAC)))
+		pmu_set_power_domain(PD_GMAC, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_SDIOAUDIO)))
+		pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_HDCP)))
+		pmu_set_power_domain(PD_HDCP, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_ISP1)))
+		pmu_set_power_domain(PD_ISP1, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_ISP0)))
+		pmu_set_power_domain(PD_ISP0, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_VO)))
+		pmu_set_power_domain(PD_VO, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_TCPD1)))
+		pmu_set_power_domain(PD_TCPD1, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_TCPD0)))
+		pmu_set_power_domain(PD_TCPD0, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_GPU)))
+		pmu_set_power_domain(PD_GPU, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_USB3)))
+		pmu_set_power_domain(PD_USB3, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_EMMC)))
+		pmu_set_power_domain(PD_EMMC, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_VIO)))
+		pmu_set_power_domain(PD_VIO, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_SD)))
+		pmu_set_power_domain(PD_SD, pmu_pd_on);
+	if (!(pmu_powerdomain_state & BIT(PD_PERIHP)))
+		pmu_set_power_domain(PD_PERIHP, pmu_pd_on);
+	qos_restore();
+	clk_gate_con_restore();
+}
+
+void rk3399_flush_l2_b(void)
+{
+	uint32_t wait_cnt = 0;
+
+	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B));
+	dsb();
+
+	/*
+	 * The Big cluster flush L2 cache took ~4ms by default, give 10ms for
+	 * the enough margin.
+	 */
+	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) &
+		 BIT(L2_FLUSHDONE_CLUSTER_B))) {
+		wait_cnt++;
+		udelay(10);
+		if (wait_cnt == 10000 / 10)
+			WARN("L2 cache flush on suspend took longer than 10ms\n");
+	}
+
+	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B));
+}
+
+static void pmu_scu_b_pwrdn(void)
+{
+	uint32_t wait_cnt = 0;
+
+	if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) &
+	     (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) !=
+	     (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) {
+		ERROR("%s: not all cpus is off\n", __func__);
+		return;
+	}
+
+	rk3399_flush_l2_b();
+
+	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
+
+	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) &
+		 BIT(STANDBY_BY_WFIL2_CLUSTER_B))) {
+		wait_cnt++;
+		udelay(1);
+		if (wait_cnt >= MAX_WAIT_COUNT)
+			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
+			      mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
+	}
+}
+
+static void pmu_scu_b_pwrup(void)
+{
+	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
+}
+
+static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
+{
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	return core_pm_cfg_info[cpu_id];
+}
+
+static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
+{
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	core_pm_cfg_info[cpu_id] = value;
+#if !USE_COHERENT_MEM
+	flush_dcache_range((uintptr_t)&core_pm_cfg_info[cpu_id],
+			   sizeof(uint32_t));
+#endif
+}
+
+static int cpus_power_domain_on(uint32_t cpu_id)
+{
+	uint32_t cfg_info;
+	uint32_t cpu_pd = PD_CPUL0 + cpu_id;
+	/*
+	  * There are two ways to powering on or off on core.
+	  * 1) Control it power domain into on or off in PMU_PWRDN_CON reg
+	  * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
+	  *     then, if the core enter into wfi, it power domain will be
+	  *     powered off automatically.
+	  */
+
+	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
+
+	if (cfg_info == core_pwr_pd) {
+		/* disable core_pm cfg */
+		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
+			      CORES_PM_DISABLE);
+		/* if the cores have be on, power off it firstly */
+		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+			mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 0);
+			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+		}
+
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
+	} else {
+		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
+			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
+			return -EINVAL;
+		}
+
+		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
+			      BIT(core_pm_sft_wakeup_en));
+		dsb();
+	}
+
+	return 0;
+}
+
+static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
+{
+	uint32_t cpu_pd;
+	uint32_t core_pm_value;
+
+	cpu_pd = PD_CPUL0 + cpu_id;
+	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
+		return 0;
+
+	if (pd_cfg == core_pwr_pd) {
+		if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
+			return -EINVAL;
+
+		/* disable core_pm cfg */
+		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
+			      CORES_PM_DISABLE);
+
+		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
+	} else {
+		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
+
+		core_pm_value = BIT(core_pm_en);
+		if (pd_cfg == core_pwr_wfi_int)
+			core_pm_value |= BIT(core_pm_int_wakeup_en);
+		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
+			      core_pm_value);
+		dsb();
+	}
+
+	return 0;
+}
+
+static inline void clst_pwr_domain_suspend(plat_local_state_t lvl_state)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+	uint32_t pll_id, clst_st_msk, clst_st_chk_msk, pmu_st;
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+
+	if (lvl_state == PLAT_MAX_OFF_STATE) {
+		if (cpu_id < PLATFORM_CLUSTER0_CORE_COUNT) {
+			pll_id = ALPLL_ID;
+			clst_st_msk = CLST_L_CPUS_MSK;
+		} else {
+			pll_id = ABPLL_ID;
+			clst_st_msk = CLST_B_CPUS_MSK <<
+				       PLATFORM_CLUSTER0_CORE_COUNT;
+		}
+
+		clst_st_chk_msk = clst_st_msk & ~(BIT(cpu_id));
+
+		pmu_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
+
+		pmu_st &= clst_st_msk;
+
+		if (pmu_st == clst_st_chk_msk) {
+			mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3),
+				      PLL_SLOW_MODE);
+
+			clst_warmboot_data[pll_id] = PMU_CLST_RET;
+
+			pmu_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
+			pmu_st &= clst_st_msk;
+			if (pmu_st == clst_st_chk_msk)
+				return;
+			/*
+			 * it is mean that others cpu is up again,
+			 * we must resume the cfg at once.
+			 */
+			mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3),
+				      PLL_NOMAL_MODE);
+			clst_warmboot_data[pll_id] = 0;
+		}
+	}
+}
+
+static int clst_pwr_domain_resume(plat_local_state_t lvl_state)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+	uint32_t pll_id, pll_st;
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+
+	if (lvl_state == PLAT_MAX_OFF_STATE) {
+		if (cpu_id < PLATFORM_CLUSTER0_CORE_COUNT)
+			pll_id = ALPLL_ID;
+		else
+			pll_id = ABPLL_ID;
+
+		pll_st = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 3)) >>
+				 PLL_MODE_SHIFT;
+
+		if (pll_st != NORMAL_MODE) {
+			WARN("%s: clst (%d) is in error mode (%d)\n",
+			     __func__, pll_id, pll_st);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void nonboot_cpus_off(void)
+{
+	uint32_t boot_cpu, cpu;
+
+	boot_cpu = plat_my_core_pos();
+
+	/* turn off noboot cpus */
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
+		if (cpu == boot_cpu)
+			continue;
+		cpus_power_domain_off(cpu, core_pwr_pd);
+	}
+}
+
+int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
+	cpuson_entry_point[cpu_id] = entrypoint;
+	dsb();
+
+	cpus_power_domain_on(cpu_id);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_off(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl,
+				 plat_local_state_t lvl_state)
+{
+	if (lvl == MPIDR_AFFLVL1) {
+		clst_pwr_domain_suspend(lvl_state);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_suspend(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	assert(cpu_id < PLATFORM_CORE_COUNT);
+	assert(cpuson_flags[cpu_id] == 0);
+	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
+	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
+	dsb();
+
+	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl, plat_local_state_t lvl_state)
+{
+	if (lvl == MPIDR_AFFLVL1) {
+		clst_pwr_domain_suspend(lvl_state);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_on_finish(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
+		      CORES_PM_DISABLE);
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl,
+				       plat_local_state_t lvl_state)
+{
+	if (lvl == MPIDR_AFFLVL1) {
+		clst_pwr_domain_resume(lvl_state);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_cores_pwr_dm_resume(void)
+{
+	uint32_t cpu_id = plat_my_core_pos();
+
+	/* Disable core_pm */
+	mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE);
+
+	return PSCI_E_SUCCESS;
+}
+
+int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl, plat_local_state_t lvl_state)
+{
+	if (lvl == MPIDR_AFFLVL1) {
+		clst_pwr_domain_resume(lvl_state);
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/**
+ * init_pmu_counts - Init timing counts in the PMU register area
+ *
+ * At various points when we power up or down parts of the system we need
+ * a delay to wait for power / clocks to become stable.  The PMU has counters
+ * to help software do the delay properly.  Basically, it works like this:
+ * - Software sets up counter values
+ * - When software turns on something in the PMU, the counter kicks off
+ * - The hardware sets a bit automatically when the counter has finished and
+ *   software knows that the initialization is done.
+ *
+ * It's software's job to setup these counters.  The hardware power on default
+ * for these settings is conservative, setting everything to 0x5dc0
+ * (750 ms in 32 kHz counts or 1 ms in 24 MHz counts).
+ *
+ * Note that some of these counters are only really used at suspend/resume
+ * time (for instance, that's the only time we turn off/on the oscillator) and
+ * others are used during normal runtime (like turning on/off a CPU or GPU) but
+ * it doesn't hurt to init everything at boot.
+ *
+ * Also note that these counters can run off the 32 kHz clock or the 24 MHz
+ * clock.  While the 24 MHz clock can give us more precision, it's not always
+ * available (like when we turn the oscillator off at sleep time). The
+ * pmu_use_lf (lf: low freq) is available in power mode.  Current understanding
+ * is that counts work like this:
+ *    IF (pmu_use_lf == 0) || (power_mode_en == 0)
+ *      use the 24M OSC for counts
+ *    ELSE
+ *      use the 32K OSC for counts
+ *
+ * Notes:
+ * - There is a separate bit for the PMU called PMU_24M_EN_CFG.  At the moment
+ *   we always keep that 0.  This apparently choose between using the PLL as
+ *   the source for the PMU vs. the 24M clock.  If we ever set it to 1 we
+ *   should consider how it affects these counts (if at all).
+ * - The power_mode_en is documented to auto-clear automatically when we leave
+ *   "power mode".  That's why most clocks are on 24M.  Only timings used when
+ *   in "power mode" are 32k.
+ * - In some cases the kernel may override these counts.
+ *
+ * The PMU_STABLE_CNT / PMU_OSC_CNT / PMU_PLLLOCK_CNT are important CNTs
+ * in power mode, we need to ensure that they are available.
+ */
+static void init_pmu_counts(void)
+{
+	/* COUNTS FOR INSIDE POWER MODE */
+
+	/*
+	 * From limited testing, need PMU stable >= 2ms, but go overkill
+	 * and choose 30 ms to match testing on past SoCs.  Also let
+	 * OSC have 30 ms for stabilization.
+	 */
+	mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_32K_CNT_MS(30));
+	mmio_write_32(PMU_BASE + PMU_OSC_CNT, CYCL_32K_CNT_MS(30));
+
+	/* Unclear what these should be; try 3 ms */
+	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_CNT, CYCL_32K_CNT_MS(3));
+
+	/* Unclear what this should be, but set the default explicitly */
+	mmio_write_32(PMU_BASE + PMU_TIMEOUT_CNT, 0x5dc0);
+
+	/* COUNTS FOR OUTSIDE POWER MODE */
+
+	/* Put something sorta conservative here until we know better */
+	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_24M_CNT_MS(3));
+	mmio_write_32(PMU_BASE + PMU_DDRIO_PWRON_CNT, CYCL_24M_CNT_MS(1));
+	mmio_write_32(PMU_BASE + PMU_CENTER_PWRDN_CNT, CYCL_24M_CNT_MS(1));
+	mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_24M_CNT_MS(1));
+
+	/*
+	 * when we enable PMU_CLR_PERILP, it will shut down the SRAM, but
+	 * M0 code run in SRAM, and we need it to check whether cpu enter
+	 * FSM status, so we must wait M0 finish their code and enter WFI,
+	 * then we can shutdown SRAM, according FSM order:
+	 * ST_NORMAL->..->ST_SCU_L_PWRDN->..->ST_CENTER_PWRDN->ST_PERILP_PWRDN
+	 * we can add delay when shutdown ST_SCU_L_PWRDN to guarantee M0 get
+	 * the FSM status and enter WFI, then enable PMU_CLR_PERILP.
+	 */
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_MS(5));
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_US(1));
+
+	/*
+	 * Set CPU/GPU to 1 us.
+	 *
+	 * NOTE: Even though ATF doesn't configure the GPU we'll still setup
+	 * counts here.  After all ATF controls all these other bits and also
+	 * chooses which clock these counters use.
+	 */
+	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_24M_CNT_US(1));
+	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_24M_CNT_US(1));
+	mmio_write_32(PMU_BASE + PMU_GPU_PWRDN_CNT, CYCL_24M_CNT_US(1));
+	mmio_write_32(PMU_BASE + PMU_GPU_PWRUP_CNT, CYCL_24M_CNT_US(1));
+}
+
+static uint32_t clk_ddrc_save;
+
+static void sys_slp_config(void)
+{
+	uint32_t slp_mode_cfg = 0;
+
+	/* keep enabling clk_ddrc_bpll_src_en gate for DDRC */
+	clk_ddrc_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(3));
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), WMSK_BIT(1));
+
+	prepare_abpll_for_ddrctrl();
+	sram_func_set_ddrctl_pll(ABPLL_ID);
+
+	mmio_write_32(GRF_BASE + GRF_SOC_CON4, CCI_FORCE_WAKEUP);
+	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
+		      BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) |
+		      BIT_WITH_WMSK(PMU_CLR_QREQ_CCI500_HW) |
+		      BIT_WITH_WMSK(PMU_QGATING_CCI500_CFG));
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      BIT_WITH_WMSK(PMU_CLR_CORE_L_HW) |
+		      BIT_WITH_WMSK(PMU_CLR_CORE_L_2GIC_HW) |
+		      BIT_WITH_WMSK(PMU_CLR_GIC2_CORE_L_HW));
+
+	slp_mode_cfg = BIT(PMU_PWR_MODE_EN) |
+		       BIT(PMU_WKUP_RST_EN) |
+		       BIT(PMU_INPUT_CLAMP_EN) |
+		       BIT(PMU_POWER_OFF_REQ_CFG) |
+		       BIT(PMU_CPU0_PD_EN) |
+		       BIT(PMU_L2_FLUSH_EN) |
+		       BIT(PMU_L2_IDLE_EN) |
+		       BIT(PMU_SCU_PD_EN) |
+		       BIT(PMU_CCI_PD_EN) |
+		       BIT(PMU_CLK_CORE_SRC_GATE_EN) |
+		       BIT(PMU_ALIVE_USE_LF) |
+		       BIT(PMU_SREF0_ENTER_EN) |
+		       BIT(PMU_SREF1_ENTER_EN) |
+		       BIT(PMU_DDRC0_GATING_EN) |
+		       BIT(PMU_DDRC1_GATING_EN) |
+		       BIT(PMU_DDRIO0_RET_EN) |
+		       BIT(PMU_DDRIO0_RET_DE_REQ) |
+		       BIT(PMU_DDRIO1_RET_EN) |
+		       BIT(PMU_DDRIO1_RET_DE_REQ) |
+		       BIT(PMU_CENTER_PD_EN) |
+		       BIT(PMU_PERILP_PD_EN) |
+		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
+		       BIT(PMU_PLL_PD_EN) |
+		       BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
+		       BIT(PMU_OSC_DIS) |
+		       BIT(PMU_PMU_USE_LF);
+
+	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN));
+	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg);
+
+	mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW);
+	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K);
+	mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /* 32k iomux */
+}
+
+static void set_hw_idle(uint32_t hw_idle)
+{
+	mmio_setbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle);
+}
+
+static void clr_hw_idle(uint32_t hw_idle)
+{
+	mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle);
+}
+
+static uint32_t iomux_status[12];
+static uint32_t pull_mode_status[12];
+static uint32_t gpio_direction[3];
+static uint32_t gpio_2_4_clk_gate;
+
+static void suspend_apio(void)
+{
+	struct bl_aux_rk_apio_info *suspend_apio;
+	int i;
+
+	suspend_apio = plat_get_rockchip_suspend_apio();
+
+	if (!suspend_apio)
+		return;
+
+	/* save gpio2 ~ gpio4 iomux and pull mode */
+	for (i = 0; i < 12; i++) {
+		iomux_status[i] = mmio_read_32(GRF_BASE +
+				GRF_GPIO2A_IOMUX + i * 4);
+		pull_mode_status[i] = mmio_read_32(GRF_BASE +
+				GRF_GPIO2A_P + i * 4);
+	}
+
+	/* store gpio2 ~ gpio4 clock gate state */
+	gpio_2_4_clk_gate = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >>
+				PCLK_GPIO2_GATE_SHIFT) & 0x07;
+
+	/* enable gpio2 ~ gpio4 clock gate */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+	/* save gpio2 ~ gpio4 direction */
+	gpio_direction[0] = mmio_read_32(GPIO2_BASE + 0x04);
+	gpio_direction[1] = mmio_read_32(GPIO3_BASE + 0x04);
+	gpio_direction[2] = mmio_read_32(GPIO4_BASE + 0x04);
+
+	/* apio1 charge gpio3a0 ~ gpio3c7 */
+	if (suspend_apio->apio1) {
+
+		/* set gpio3a0 ~ gpio3c7 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO3A_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO3B_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO3C_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio3a0 ~ gpio3c7 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO3A_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO3B_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO3C_P, REG_SOC_WMSK | 0);
+
+		/* set gpio3a0 ~ gpio3c7 to input */
+		mmio_clrbits_32(GPIO3_BASE + 0x04, 0x00ffffff);
+	}
+
+	/* apio2 charge gpio2a0 ~ gpio2b4 */
+	if (suspend_apio->apio2) {
+
+		/* set gpio2a0 ~ gpio2b4 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO2B_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio2a0 ~ gpio2b4 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO2B_P, REG_SOC_WMSK | 0);
+
+		/* set gpio2a0 ~ gpio2b4 to input */
+		mmio_clrbits_32(GPIO2_BASE + 0x04, 0x00001fff);
+	}
+
+	/* apio3 charge gpio2c0 ~ gpio2d4*/
+	if (suspend_apio->apio3) {
+
+		/* set gpio2a0 ~ gpio2b4 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO2C_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio2c0 ~ gpio2d4 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO2C_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO2D_P, REG_SOC_WMSK | 0);
+
+		/* set gpio2c0 ~ gpio2d4 to input */
+		mmio_clrbits_32(GPIO2_BASE + 0x04, 0x1fff0000);
+	}
+
+	/* apio4 charge gpio4c0 ~ gpio4c7, gpio4d0 ~ gpio4d6 */
+	if (suspend_apio->apio4) {
+
+		/* set gpio4c0 ~ gpio4d6 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO4D_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio4c0 ~ gpio4d6 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO4D_P, REG_SOC_WMSK | 0);
+
+		/* set gpio4c0 ~ gpio4d6 to input */
+		mmio_clrbits_32(GPIO4_BASE + 0x04, 0x7fff0000);
+	}
+
+	/* apio5 charge gpio3d0 ~ gpio3d7, gpio4a0 ~ gpio4a7*/
+	if (suspend_apio->apio5) {
+		/* set gpio3d0 ~ gpio4a7 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO3D_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO4A_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio3d0 ~ gpio4a7 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO3D_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO4A_P, REG_SOC_WMSK | 0);
+
+		/* set gpio4c0 ~ gpio4d6 to input */
+		mmio_clrbits_32(GPIO3_BASE + 0x04, 0xff000000);
+		mmio_clrbits_32(GPIO4_BASE + 0x04, 0x000000ff);
+	}
+}
+
+static void resume_apio(void)
+{
+	struct bl_aux_rk_apio_info *suspend_apio;
+	int i;
+
+	suspend_apio = plat_get_rockchip_suspend_apio();
+
+	if (!suspend_apio)
+		return;
+
+	for (i = 0; i < 12; i++) {
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_P + i * 4,
+			      REG_SOC_WMSK | pull_mode_status[i]);
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
+			      REG_SOC_WMSK | iomux_status[i]);
+	}
+
+	/* set gpio2 ~ gpio4 direction back to store value */
+	mmio_write_32(GPIO2_BASE + 0x04, gpio_direction[0]);
+	mmio_write_32(GPIO3_BASE + 0x04, gpio_direction[1]);
+	mmio_write_32(GPIO4_BASE + 0x04, gpio_direction[2]);
+
+	/* set gpio2 ~ gpio4 clock gate back to store value */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(gpio_2_4_clk_gate, 0x07,
+				      PCLK_GPIO2_GATE_SHIFT));
+}
+
+static void suspend_gpio(void)
+{
+	struct bl_aux_gpio_info *suspend_gpio;
+	uint32_t count;
+	int i;
+
+	suspend_gpio = plat_get_rockchip_suspend_gpio(&count);
+
+	for (i = 0; i < count; i++) {
+		gpio_set_value(suspend_gpio[i].index, suspend_gpio[i].polarity);
+		gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT);
+		udelay(1);
+	}
+}
+
+static void resume_gpio(void)
+{
+	struct bl_aux_gpio_info *suspend_gpio;
+	uint32_t count;
+	int i;
+
+	suspend_gpio = plat_get_rockchip_suspend_gpio(&count);
+
+	for (i = count - 1; i >= 0; i--) {
+		gpio_set_value(suspend_gpio[i].index,
+			       !suspend_gpio[i].polarity);
+		gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT);
+		udelay(1);
+	}
+}
+
+void sram_save(void)
+{
+	size_t text_size = (char *)&__bl31_sram_text_real_end -
+			   (char *)&__bl31_sram_text_start;
+	size_t data_size = (char *)&__bl31_sram_data_real_end -
+			   (char *)&__bl31_sram_data_start;
+	size_t incbin_size = (char *)&__sram_incbin_real_end -
+			     (char *)&__sram_incbin_start;
+
+	memcpy(&store_sram[0], &__bl31_sram_text_start, text_size);
+	memcpy(&store_sram[text_size], &__bl31_sram_data_start, data_size);
+	memcpy(&store_sram[text_size + data_size], &__sram_incbin_start,
+	       incbin_size);
+}
+
+void sram_restore(void)
+{
+	size_t text_size = (char *)&__bl31_sram_text_real_end -
+			   (char *)&__bl31_sram_text_start;
+	size_t data_size = (char *)&__bl31_sram_data_real_end -
+			   (char *)&__bl31_sram_data_start;
+	size_t incbin_size = (char *)&__sram_incbin_real_end -
+			     (char *)&__sram_incbin_start;
+
+	memcpy(&__bl31_sram_text_start, &store_sram[0], text_size);
+	memcpy(&__bl31_sram_data_start, &store_sram[text_size], data_size);
+	memcpy(&__sram_incbin_start, &store_sram[text_size + data_size],
+	       incbin_size);
+}
+
+struct uart_debug {
+	uint32_t uart_dll;
+	uint32_t uart_dlh;
+	uint32_t uart_ier;
+	uint32_t uart_fcr;
+	uint32_t uart_mcr;
+	uint32_t uart_lcr;
+};
+
+#define UART_DLL	0x00
+#define UART_DLH	0x04
+#define UART_IER	0x04
+#define UART_FCR	0x08
+#define UART_LCR	0x0c
+#define UART_MCR	0x10
+#define UARTSRR		0x88
+
+#define UART_RESET	BIT(0)
+#define UARTFCR_FIFOEN	BIT(0)
+#define RCVR_FIFO_RESET	BIT(1)
+#define XMIT_FIFO_RESET	BIT(2)
+#define DIAGNOSTIC_MODE	BIT(4)
+#define UARTLCR_DLAB	BIT(7)
+
+static struct uart_debug uart_save;
+
+void suspend_uart(void)
+{
+	uint32_t uart_base = rockchip_get_uart_base();
+
+	if (uart_base == 0)
+		return;
+
+	uart_save.uart_lcr = mmio_read_32(uart_base + UART_LCR);
+	uart_save.uart_ier = mmio_read_32(uart_base + UART_IER);
+	uart_save.uart_mcr = mmio_read_32(uart_base + UART_MCR);
+	mmio_write_32(uart_base + UART_LCR,
+		      uart_save.uart_lcr | UARTLCR_DLAB);
+	uart_save.uart_dll = mmio_read_32(uart_base + UART_DLL);
+	uart_save.uart_dlh = mmio_read_32(uart_base + UART_DLH);
+	mmio_write_32(uart_base + UART_LCR, uart_save.uart_lcr);
+}
+
+void resume_uart(void)
+{
+	uint32_t uart_base = rockchip_get_uart_base();
+	uint32_t uart_lcr;
+
+	if (uart_base == 0)
+		return;
+
+	mmio_write_32(uart_base + UARTSRR,
+		      XMIT_FIFO_RESET | RCVR_FIFO_RESET | UART_RESET);
+
+	uart_lcr = mmio_read_32(uart_base + UART_LCR);
+	mmio_write_32(uart_base + UART_MCR, DIAGNOSTIC_MODE);
+	mmio_write_32(uart_base + UART_LCR, uart_lcr | UARTLCR_DLAB);
+	mmio_write_32(uart_base + UART_DLL, uart_save.uart_dll);
+	mmio_write_32(uart_base + UART_DLH, uart_save.uart_dlh);
+	mmio_write_32(uart_base + UART_LCR, uart_save.uart_lcr);
+	mmio_write_32(uart_base + UART_IER, uart_save.uart_ier);
+	mmio_write_32(uart_base + UART_FCR, UARTFCR_FIFOEN);
+	mmio_write_32(uart_base + UART_MCR, uart_save.uart_mcr);
+}
+
+void save_usbphy(void)
+{
+	store_usbphy0[0] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL0);
+	store_usbphy0[1] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL2);
+	store_usbphy0[2] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL3);
+	store_usbphy0[3] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL12);
+	store_usbphy0[4] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL13);
+	store_usbphy0[5] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL15);
+	store_usbphy0[6] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL16);
+
+	store_usbphy1[0] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL0);
+	store_usbphy1[1] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL2);
+	store_usbphy1[2] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL3);
+	store_usbphy1[3] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL12);
+	store_usbphy1[4] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL13);
+	store_usbphy1[5] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL15);
+	store_usbphy1[6] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL16);
+}
+
+void restore_usbphy(void)
+{
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL0,
+		      REG_SOC_WMSK | store_usbphy0[0]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL2,
+		      REG_SOC_WMSK | store_usbphy0[1]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL3,
+		      REG_SOC_WMSK | store_usbphy0[2]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL12,
+		      REG_SOC_WMSK | store_usbphy0[3]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL13,
+		      REG_SOC_WMSK | store_usbphy0[4]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL15,
+		      REG_SOC_WMSK | store_usbphy0[5]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL16,
+		      REG_SOC_WMSK | store_usbphy0[6]);
+
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL0,
+		      REG_SOC_WMSK | store_usbphy1[0]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL2,
+		      REG_SOC_WMSK | store_usbphy1[1]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL3,
+		      REG_SOC_WMSK | store_usbphy1[2]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL12,
+		      REG_SOC_WMSK | store_usbphy1[3]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL13,
+		      REG_SOC_WMSK | store_usbphy1[4]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL15,
+		      REG_SOC_WMSK | store_usbphy1[5]);
+	mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL16,
+		      REG_SOC_WMSK | store_usbphy1[6]);
+}
+
+void grf_register_save(void)
+{
+	int i;
+
+	store_grf_soc_con0 = mmio_read_32(GRF_BASE + GRF_SOC_CON(0));
+	store_grf_soc_con1 = mmio_read_32(GRF_BASE + GRF_SOC_CON(1));
+	store_grf_soc_con2 = mmio_read_32(GRF_BASE + GRF_SOC_CON(2));
+	store_grf_soc_con3 = mmio_read_32(GRF_BASE + GRF_SOC_CON(3));
+	store_grf_soc_con4 = mmio_read_32(GRF_BASE + GRF_SOC_CON(4));
+	store_grf_soc_con7 = mmio_read_32(GRF_BASE + GRF_SOC_CON(7));
+
+	for (i = 0; i < 4; i++)
+		store_grf_ddrc_con[i] =
+			mmio_read_32(GRF_BASE + GRF_DDRC0_CON0 + i * 4);
+
+	store_grf_io_vsel = mmio_read_32(GRF_BASE + GRF_IO_VSEL);
+}
+
+void grf_register_restore(void)
+{
+	int i;
+
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(0),
+		      REG_SOC_WMSK | store_grf_soc_con0);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(1),
+		      REG_SOC_WMSK | store_grf_soc_con1);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(2),
+		      REG_SOC_WMSK | store_grf_soc_con2);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(3),
+		      REG_SOC_WMSK | store_grf_soc_con3);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(4),
+		      REG_SOC_WMSK | store_grf_soc_con4);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(7),
+		      REG_SOC_WMSK | store_grf_soc_con7);
+
+	for (i = 0; i < 4; i++)
+		mmio_write_32(GRF_BASE + GRF_DDRC0_CON0 + i * 4,
+			      REG_SOC_WMSK | store_grf_ddrc_con[i]);
+
+	mmio_write_32(GRF_BASE + GRF_IO_VSEL, REG_SOC_WMSK | store_grf_io_vsel);
+}
+
+void cru_register_save(void)
+{
+	int i;
+
+	for (i = 0; i <= CRU_SDIO0_CON1; i = i + 4)
+		store_cru[i / 4] = mmio_read_32(CRU_BASE + i);
+}
+
+void cru_register_restore(void)
+{
+	int i;
+
+	for (i = 0; i <= CRU_SDIO0_CON1; i = i + 4) {
+
+		/*
+		 * since DPLL, CRU_CLKSEL_CON6 have been restore in
+		 * dmc_resume, ABPLL will resote later, so skip them
+		 */
+		if ((i == CRU_CLKSEL_CON6) ||
+		    (i >= CRU_PLL_CON(ABPLL_ID, 0) &&
+		     i <= CRU_PLL_CON(DPLL_ID, 5)))
+			continue;
+
+		if ((i == CRU_PLL_CON(ALPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(CPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(GPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(NPLL_ID, 2)) ||
+		    (i == CRU_PLL_CON(VPLL_ID, 2)))
+			mmio_write_32(CRU_BASE + i, store_cru[i / 4]);
+		/*
+		 * CRU_GLB_CNT_TH and CRU_CLKSEL_CON97~CRU_CLKSEL_CON107
+		 * not need do high 16bit mask
+		 */
+		else if ((i > 0x27c && i < 0x2b0) || (i == 0x508))
+			mmio_write_32(CRU_BASE + i, store_cru[i / 4]);
+		else
+			mmio_write_32(CRU_BASE + i,
+				      REG_SOC_WMSK | store_cru[i / 4]);
+	}
+}
+
+void wdt_register_save(void)
+{
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		store_wdt0[i] = mmio_read_32(WDT0_BASE + i * 4);
+		store_wdt1[i] = mmio_read_32(WDT1_BASE + i * 4);
+	}
+}
+
+void wdt_register_restore(void)
+{
+	int i;
+
+	for (i = 1; i >= 0; i--) {
+		mmio_write_32(WDT0_BASE + i * 4, store_wdt0[i]);
+		mmio_write_32(WDT1_BASE + i * 4, store_wdt1[i]);
+	}
+
+	/* write 0x76 to cnt_restart to keep watchdog alive */
+	mmio_write_32(WDT0_BASE + 0x0c, 0x76);
+	mmio_write_32(WDT1_BASE + 0x0c, 0x76);
+}
+
+int rockchip_soc_sys_pwr_dm_suspend(void)
+{
+	uint32_t wait_cnt = 0;
+	uint32_t status = 0;
+
+	ddr_prepare_for_sys_suspend();
+	dmc_suspend();
+	pmu_scu_b_pwrdn();
+
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+	gicv3_distif_save(&dist_ctx);
+
+	/* need to save usbphy before shutdown PERIHP PD */
+	save_usbphy();
+
+	pmu_power_domains_suspend();
+	set_hw_idle(BIT(PMU_CLR_CENTER1) |
+		    BIT(PMU_CLR_ALIVE) |
+		    BIT(PMU_CLR_MSCH0) |
+		    BIT(PMU_CLR_MSCH1) |
+		    BIT(PMU_CLR_CCIM0) |
+		    BIT(PMU_CLR_CCIM1) |
+		    BIT(PMU_CLR_CENTER) |
+		    BIT(PMU_CLR_PERILP) |
+		    BIT(PMU_CLR_PERILPM0) |
+		    BIT(PMU_CLR_GIC));
+	set_pmu_rsthold();
+	sys_slp_config();
+
+	m0_configure_execute_addr(M0PMU_BINCODE_BASE);
+	m0_start();
+
+	pmu_sgrf_rst_hld();
+
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
+		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) |
+		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_GIC2_CORE_B_SW));
+	dsb();
+	status = BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST) |
+		BIT(PMU_PWRDWN_REQ_CORE_B_SW_ST) |
+		BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST);
+	while ((mmio_read_32(PMU_BASE +
+	       PMU_ADB400_ST) & status) != status) {
+		wait_cnt++;
+		if (wait_cnt >= MAX_WAIT_COUNT) {
+			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
+			      mmio_read_32(PMU_BASE + PMU_ADB400_ST));
+			panic();
+		}
+		udelay(1);
+	}
+	mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
+
+	wdt_register_save();
+	secure_watchdog_gate();
+
+	/*
+	 * Disabling PLLs/PWM/DVFS is approaching WFI which is
+	 * the last steps in suspend.
+	 */
+	disable_dvfs_plls();
+	disable_pwms();
+	disable_nodvfs_plls();
+
+	suspend_apio();
+	suspend_gpio();
+	suspend_uart();
+	grf_register_save();
+	cru_register_save();
+	sram_save();
+	plat_rockchip_save_gpio();
+
+	return 0;
+}
+
+int rockchip_soc_sys_pwr_dm_resume(void)
+{
+	uint32_t wait_cnt = 0;
+	uint32_t status = 0;
+
+	plat_rockchip_restore_gpio();
+	cru_register_restore();
+	grf_register_restore();
+	wdt_register_restore();
+	resume_uart();
+	resume_apio();
+	resume_gpio();
+	enable_nodvfs_plls();
+	enable_pwms();
+	/* PWM regulators take time to come up; give 300us to be safe. */
+	udelay(300);
+	enable_dvfs_plls();
+
+	secure_sgrf_init();
+	secure_sgrf_ddr_rgn_init();
+
+	/* restore clk_ddrc_bpll_src_en gate */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3),
+		      BITS_WITH_WMASK(clk_ddrc_save, 0xff, 0));
+
+	/*
+	 * The wakeup status is not cleared by itself, we need to clear it
+	 * manually. Otherwise we will alway query some interrupt next time.
+	 *
+	 * NOTE: If the kernel needs to query this, we might want to stash it
+	 * somewhere.
+	 */
+	mmio_write_32(PMU_BASE + PMU_WAKEUP_STATUS, 0xffffffff);
+	mmio_write_32(PMU_BASE + PMU_WKUP_CFG4, 0x00);
+
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+
+	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
+		      WMSK_BIT(PMU_CLR_PREQ_CCI500_HW) |
+		      WMSK_BIT(PMU_CLR_QREQ_CCI500_HW) |
+		      WMSK_BIT(PMU_QGATING_CCI500_CFG));
+	dsb();
+	mmio_clrbits_32(PMU_BASE + PMU_PWRDN_CON,
+			BIT(PMU_SCU_B_PWRDWN_EN));
+
+	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
+		      WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
+		      WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_SW) |
+		      WMSK_BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW) |
+		      WMSK_BIT(PMU_CLR_CORE_L_HW) |
+		      WMSK_BIT(PMU_CLR_CORE_L_2GIC_HW) |
+		      WMSK_BIT(PMU_CLR_GIC2_CORE_L_HW));
+
+	status = BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST) |
+		BIT(PMU_PWRDWN_REQ_CORE_B_SW_ST) |
+		BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST);
+
+	while ((mmio_read_32(PMU_BASE +
+	   PMU_ADB400_ST) & status)) {
+		wait_cnt++;
+		if (wait_cnt >= MAX_WAIT_COUNT) {
+			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
+			      mmio_read_32(PMU_BASE + PMU_ADB400_ST));
+			panic();
+		}
+		udelay(1);
+	}
+
+	pmu_scu_b_pwrup();
+	pmu_power_domains_resume();
+
+	restore_abpll();
+	clr_hw_idle(BIT(PMU_CLR_CENTER1) |
+				BIT(PMU_CLR_ALIVE) |
+				BIT(PMU_CLR_MSCH0) |
+				BIT(PMU_CLR_MSCH1) |
+				BIT(PMU_CLR_CCIM0) |
+				BIT(PMU_CLR_CCIM1) |
+				BIT(PMU_CLR_CENTER) |
+				BIT(PMU_CLR_PERILP) |
+				BIT(PMU_CLR_PERILPM0) |
+				BIT(PMU_CLR_GIC));
+
+	gicv3_distif_init_restore(&dist_ctx);
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+	plat_rockchip_gic_cpuif_enable();
+	m0_stop();
+
+	restore_usbphy();
+
+	ddr_prepare_for_sys_resume();
+
+	return 0;
+}
+
+void __dead2 rockchip_soc_soft_reset(void)
+{
+	struct bl_aux_gpio_info *rst_gpio;
+
+	rst_gpio = plat_get_rockchip_gpio_reset();
+
+	if (rst_gpio) {
+		gpio_set_direction(rst_gpio->index, GPIO_DIR_OUT);
+		gpio_set_value(rst_gpio->index, rst_gpio->polarity);
+	} else {
+		soc_global_soft_reset();
+	}
+
+	while (1)
+		;
+}
+
+void __dead2 rockchip_soc_system_off(void)
+{
+	struct bl_aux_gpio_info *poweroff_gpio;
+
+	poweroff_gpio = plat_get_rockchip_gpio_poweroff();
+
+	if (poweroff_gpio) {
+		/*
+		 * if use tsadc over temp pin(GPIO1A6) as shutdown gpio,
+		 * need to set this pin iomux back to gpio function
+		 */
+		if (poweroff_gpio->index == TSADC_INT_PIN) {
+			mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1A_IOMUX,
+				      GPIO1A6_IOMUX);
+		}
+		gpio_set_direction(poweroff_gpio->index, GPIO_DIR_OUT);
+		gpio_set_value(poweroff_gpio->index, poweroff_gpio->polarity);
+	} else {
+		WARN("Do nothing when system off\n");
+	}
+
+	while (1)
+		;
+}
+
+void rockchip_plat_mmu_el3(void)
+{
+	size_t sram_size;
+
+	/* sram.text size */
+	sram_size = (char *)&__bl31_sram_text_end -
+		    (char *)&__bl31_sram_text_start;
+	mmap_add_region((unsigned long)&__bl31_sram_text_start,
+			(unsigned long)&__bl31_sram_text_start,
+			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
+
+	/* sram.data size */
+	sram_size = (char *)&__bl31_sram_data_end -
+		    (char *)&__bl31_sram_data_start;
+	mmap_add_region((unsigned long)&__bl31_sram_data_start,
+			(unsigned long)&__bl31_sram_data_start,
+			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	sram_size = (char *)&__bl31_sram_stack_end -
+		    (char *)&__bl31_sram_stack_start;
+	mmap_add_region((unsigned long)&__bl31_sram_stack_start,
+			(unsigned long)&__bl31_sram_stack_start,
+			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start;
+	mmap_add_region((unsigned long)&__sram_incbin_start,
+			(unsigned long)&__sram_incbin_start,
+			sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
+}
+
+void plat_rockchip_pmu_init(void)
+{
+	uint32_t cpu;
+
+	rockchip_pd_lock_init();
+
+	/* register requires 32bits mode, switch it to 32 bits */
+	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
+
+	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
+		cpuson_flags[cpu] = 0;
+
+	for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
+		clst_warmboot_data[cpu] = 0;
+
+	/* config cpu's warm boot address */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
+		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
+		      CPU_BOOT_ADDR_WMASK);
+	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_ENA, NOC_AUTO_ENABLE);
+
+	/*
+	 * Enable Schmitt trigger for better 32 kHz input signal, which is
+	 * important for suspend/resume reliability among other things.
+	 */
+	mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_SMT, GPIO0A0_SMT_ENABLE);
+
+	init_pmu_counts();
+
+	nonboot_cpus_off();
+
+	INFO("%s(%d): pd status %x\n", __func__, __LINE__,
+	     mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
new file mode 100644
index 0000000..74db82f
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_H
+#define PMU_H
+
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#include <soc.h>
+
+/* Allocate sp reginon in pmusram */
+#define PSRAM_SP_SIZE		0x80
+#define PSRAM_SP_BOTTOM		(PSRAM_SP_TOP - PSRAM_SP_SIZE)
+
+/*****************************************************************************
+ * Common define for per soc pmu.h
+ *****************************************************************************/
+/* The ways of cores power domain contorlling */
+enum cores_pm_ctr_mode {
+	core_pwr_pd = 0,
+	core_pwr_wfi = 1,
+	core_pwr_wfi_int = 2
+};
+
+/*****************************************************************************
+ * pmu con,reg
+ *****************************************************************************/
+#define PMU_WKUP_CFG(n)	((n) * 4)
+
+#define PMU_CORE_PM_CON(cpu)		(0xc0 + (cpu * 4))
+
+/* the shift of bits for cores status */
+enum pmu_core_pwrst_shift {
+	clstl_cpu_wfe = 2,
+	clstl_cpu_wfi = 6,
+	clstb_cpu_wfe = 12,
+	clstb_cpu_wfi = 16
+};
+
+#define CKECK_WFE_MSK		0x1
+#define CKECK_WFI_MSK		0x10
+#define CKECK_WFEI_MSK		0x11
+
+/* Specific features required  */
+#define AP_PWROFF		0x0a
+
+#define GPIO0A0_SMT_ENABLE	BITS_WITH_WMASK(1, 3, 0)
+#define GPIO1A6_IOMUX		BITS_WITH_WMASK(0, 3, 12)
+
+#define TSADC_INT_PIN		38
+#define CORES_PM_DISABLE	0x0
+
+#define PD_CTR_LOOP		10000
+#define CHK_CPU_LOOP		500
+#define MAX_WAIT_COUNT		1000
+
+#define	GRF_SOC_CON4		0x0e210
+
+#define PMUGRF_GPIO0A_SMT	0x0120
+#define PMUGRF_SOC_CON0		0x0180
+
+#define CCI_FORCE_WAKEUP	WMSK_BIT(8)
+#define EXTERNAL_32K		WMSK_BIT(0)
+
+#define PLL_PD_HW		0xff
+#define IOMUX_CLK_32K		0x00030002
+#define NOC_AUTO_ENABLE		0x3fffffff
+
+#define SAVE_QOS(array, NAME) \
+	RK3399_CPU_AXI_SAVE_QOS(array, CPU_AXI_##NAME##_QOS_BASE)
+#define RESTORE_QOS(array, NAME) \
+	RK3399_CPU_AXI_RESTORE_QOS(array, CPU_AXI_##NAME##_QOS_BASE)
+
+#define RK3399_CPU_AXI_SAVE_QOS(array, base) do { \
+	array[0] = mmio_read_32(base + CPU_AXI_QOS_ID_COREID); \
+	array[1] = mmio_read_32(base + CPU_AXI_QOS_REVISIONID); \
+	array[2] = mmio_read_32(base + CPU_AXI_QOS_PRIORITY); \
+	array[3] = mmio_read_32(base + CPU_AXI_QOS_MODE); \
+	array[4] = mmio_read_32(base + CPU_AXI_QOS_BANDWIDTH); \
+	array[5] = mmio_read_32(base + CPU_AXI_QOS_SATURATION); \
+	array[6] = mmio_read_32(base + CPU_AXI_QOS_EXTCONTROL); \
+} while (0)
+
+#define RK3399_CPU_AXI_RESTORE_QOS(array, base) do { \
+	mmio_write_32(base + CPU_AXI_QOS_ID_COREID, array[0]); \
+	mmio_write_32(base + CPU_AXI_QOS_REVISIONID, array[1]); \
+	mmio_write_32(base + CPU_AXI_QOS_PRIORITY, array[2]); \
+	mmio_write_32(base + CPU_AXI_QOS_MODE, array[3]); \
+	mmio_write_32(base + CPU_AXI_QOS_BANDWIDTH, array[4]); \
+	mmio_write_32(base + CPU_AXI_QOS_SATURATION, array[5]); \
+	mmio_write_32(base + CPU_AXI_QOS_EXTCONTROL, array[6]); \
+} while (0)
+
+struct pmu_slpdata_s {
+	uint32_t cci_m0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t cci_m1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t dmac0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t dmac1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t crypto0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t crypto1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t pmu_cm0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t peri_cm1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t gic_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t usb_otg0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t usb_otg1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t usb_host0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t usb_host1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t video_m0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t video_m1_r_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t video_m1_w_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t rga_r_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t rga_w_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vop_big_r[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vop_big_w[CPU_AXI_QOS_NUM_REGS];
+	uint32_t vop_little[CPU_AXI_QOS_NUM_REGS];
+	uint32_t iep_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp1_m0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp1_m1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp0_m0_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t isp0_m1_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t hdcp_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t perihp_nsp_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t perilp_nsp_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t perilpslv_nsp_qos[CPU_AXI_QOS_NUM_REGS];
+	uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS];
+};
+
+extern uint32_t clst_warmboot_data[PLATFORM_CLUSTER_COUNT];
+
+extern void sram_func_set_ddrctl_pll(uint32_t pll_src);
+
+#endif /* PMU_H */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
new file mode 100644
index 0000000..a09ad21
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* convoluted way to make sure that the define is pasted just the right way */
+#define _INCBIN(file, sym, sec) \
+	__asm__( \
+		".section " #sec "\n" \
+		".global " #sym "\n" \
+		".type " #sym ", %object\n" \
+		".align 4\n" \
+		#sym ":\n" \
+		".incbin \"" #file "\"\n" \
+		".size " #sym ", .-" #sym "\n" \
+		".global " #sym "_end\n" \
+		#sym "_end:\n" \
+	)
+
+#define INCBIN(file, sym, sec) _INCBIN(file, sym, sec)
+
+INCBIN(RK3399M0FW, rk3399m0_bin, ".sram.incbin");
+INCBIN(RK3399M0PMUFW, rk3399m0pmu_bin, ".pmusram.incbin");
diff --git a/plat/rockchip/rk3399/drivers/pwm/pwm.c b/plat/rockchip/rk3399/drivers/pwm/pwm.c
new file mode 100644
index 0000000..11c1565
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pwm/pwm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <pmu.h>
+#include <pwm.h>
+#include <soc.h>
+
+#define PWM0_IOMUX_PWM_EN		(1 << 0)
+#define PWM1_IOMUX_PWM_EN		(1 << 1)
+#define PWM2_IOMUX_PWM_EN		(1 << 2)
+#define PWM3_IOMUX_PWM_EN		(1 << 3)
+
+struct pwm_data_s {
+	uint32_t iomux_bitmask;
+	uint32_t enable_bitmask;
+};
+
+static struct pwm_data_s pwm_data;
+
+/*
+ * Disable the PWMs.
+ */
+void disable_pwms(void)
+{
+	uint32_t i, val;
+
+	pwm_data.iomux_bitmask = 0;
+
+	/* Save PWMs pinmux and change PWMs pinmux to GPIOs */
+	val = mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX);
+	if (((val >> GRF_GPIO4C2_IOMUX_SHIFT) &
+		GRF_IOMUX_2BIT_MASK) == GRF_GPIO4C2_IOMUX_PWM) {
+		pwm_data.iomux_bitmask |= PWM0_IOMUX_PWM_EN;
+		val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK,
+				    GRF_GPIO4C2_IOMUX_SHIFT);
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val);
+	}
+
+	val = mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX);
+	if (((val >> GRF_GPIO4C6_IOMUX_SHIFT) &
+		GRF_IOMUX_2BIT_MASK) == GRF_GPIO4C6_IOMUX_PWM) {
+		pwm_data.iomux_bitmask |= PWM1_IOMUX_PWM_EN;
+		val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK,
+				    GRF_GPIO4C6_IOMUX_SHIFT);
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val);
+	}
+
+	val = mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX);
+	if (((val >> PMUGRF_GPIO1C3_IOMUX_SHIFT) &
+		GRF_IOMUX_2BIT_MASK) == PMUGRF_GPIO1C3_IOMUX_PWM) {
+		pwm_data.iomux_bitmask |= PWM2_IOMUX_PWM_EN;
+		val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK,
+				    PMUGRF_GPIO1C3_IOMUX_SHIFT);
+		mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, val);
+	}
+
+	val = mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX);
+	if (((val >> PMUGRF_GPIO0A6_IOMUX_SHIFT) &
+		GRF_IOMUX_2BIT_MASK) == PMUGRF_GPIO0A6_IOMUX_PWM) {
+		pwm_data.iomux_bitmask |= PWM3_IOMUX_PWM_EN;
+		val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK,
+				    PMUGRF_GPIO0A6_IOMUX_SHIFT);
+		mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, val);
+	}
+
+	/* Disable the pwm channel */
+	pwm_data.enable_bitmask = 0;
+	for (i = 0; i < 4; i++) {
+		val = mmio_read_32(PWM_BASE + PWM_CTRL(i));
+		if ((val & PWM_ENABLE) != PWM_ENABLE)
+			continue;
+		pwm_data.enable_bitmask |= (1 << i);
+		mmio_write_32(PWM_BASE + PWM_CTRL(i), val & ~PWM_ENABLE);
+	}
+}
+
+/*
+ * Enable the PWMs.
+ */
+void enable_pwms(void)
+{
+	uint32_t i, val;
+
+	for (i = 0; i < 4; i++) {
+		val = mmio_read_32(PWM_BASE + PWM_CTRL(i));
+		if (!(pwm_data.enable_bitmask & (1 << i)))
+			continue;
+		mmio_write_32(PWM_BASE + PWM_CTRL(i), val | PWM_ENABLE);
+	}
+
+	/* Restore all IOMUXes */
+	if (pwm_data.iomux_bitmask & PWM3_IOMUX_PWM_EN) {
+		val = BITS_WITH_WMASK(PMUGRF_GPIO0A6_IOMUX_PWM,
+				    GRF_IOMUX_2BIT_MASK,
+				    PMUGRF_GPIO0A6_IOMUX_SHIFT);
+		mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, val);
+	}
+
+	if (pwm_data.iomux_bitmask & PWM2_IOMUX_PWM_EN) {
+		val = BITS_WITH_WMASK(PMUGRF_GPIO1C3_IOMUX_PWM,
+				    GRF_IOMUX_2BIT_MASK,
+				    PMUGRF_GPIO1C3_IOMUX_SHIFT);
+		mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, val);
+	}
+
+	if (pwm_data.iomux_bitmask & PWM1_IOMUX_PWM_EN) {
+		val = BITS_WITH_WMASK(GRF_GPIO4C6_IOMUX_PWM,
+				    GRF_IOMUX_2BIT_MASK,
+				    GRF_GPIO4C6_IOMUX_SHIFT);
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val);
+	}
+
+	if (pwm_data.iomux_bitmask & PWM0_IOMUX_PWM_EN) {
+		val = BITS_WITH_WMASK(GRF_GPIO4C2_IOMUX_PWM,
+				    GRF_IOMUX_2BIT_MASK,
+				    GRF_GPIO4C2_IOMUX_SHIFT);
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val);
+	}
+}
diff --git a/plat/rockchip/rk3399/drivers/pwm/pwm.h b/plat/rockchip/rk3399/drivers/pwm/pwm.h
new file mode 100644
index 0000000..d665392
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pwm/pwm.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PWM_H
+#define PWM_H
+
+void disable_pwms(void);
+void enable_pwms(void);
+
+#endif /* PWM_H */
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.c b/plat/rockchip/rk3399/drivers/secure/secure.c
new file mode 100644
index 0000000..8286f17
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/secure/secure.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <plat_private.h>
+#include <secure.h>
+#include <soc.h>
+
+static void sgrf_ddr_rgn_global_bypass(uint32_t bypass)
+{
+	if (bypass)
+		/* set bypass (non-secure regions) for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+			      SGRF_DDR_RGN_BYPS);
+	else
+		/* cancel bypass for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+			      SGRF_DDR_RGN_NO_BYPS);
+}
+
+/**
+ * There are 8 + 1 regions for DDR secure control:
+ * DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB
+ * DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7
+ *
+ * DDR_RGN_0 - start address of the RGN0
+ * DDR_RGN_8 - end address of the RGN0
+ * DDR_RGN_1 - start address of the RGN1
+ * DDR_RGN_9 - end address of the RGN1
+ * ...
+ * DDR_RGN_7 - start address of the RGN7
+ * DDR_RGN_15 - end address of the RGN7
+ * DDR_RGN_16 - bit 0 ~ 7 is bitmap for RGN0~7 secure,0: disable, 1: enable
+ *              bit 8 is setting for RGNx, the rest of the memory and region
+ *                which excludes RGN0~7, 0: disable, 1: enable
+ *              bit 9, the global secure configuration via bypass, 0: disable
+ *                bypass, 1: enable bypass
+ *
+ * @rgn - the DDR regions 0 ~ 7 which are can be configured.
+ * The @st_mb and @ed_mb indicate the start and end addresses for which to set
+ * the security, and the unit is megabyte. When the st_mb == 0, ed_mb == 0, the
+ * address range 0x0 ~ 0xfffff is secure.
+ *
+ * For example, if we would like to set the range [0, 32MB) is security via
+ * DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31.
+ */
+static void sgrf_ddr_rgn_config(uint32_t rgn,
+				uintptr_t st, uintptr_t ed)
+{
+	uintptr_t st_mb, ed_mb;
+
+	assert(rgn <= 7);
+	assert(st < ed);
+
+	/* check aligned 1MB */
+	assert(st % SIZE_M(1) == 0);
+	assert(ed % SIZE_M(1) == 0);
+
+	st_mb = st / SIZE_M(1);
+	ed_mb = ed / SIZE_M(1);
+
+	/* set ddr region addr start */
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(rgn),
+		      BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_0_16_WMSK, 0));
+
+	/* set ddr region addr end */
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(rgn + 8),
+		      BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_0_16_WMSK, 0));
+
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+		      BIT_WITH_WMSK(rgn));
+}
+
+void secure_watchdog_gate(void)
+{
+	/**
+	 * Disable CA53 and CM0 wdt pclk
+	 * BIT[8]: ca53 wdt pclk, 0: enable 1: disable
+	 * BIT[10]: cm0 wdt pclk, 0: enable 1: disable
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3),
+		      BIT_WITH_WMSK(PCLK_WDT_CA53_GATE_SHIFT) |
+		      BIT_WITH_WMSK(PCLK_WDT_CM0_GATE_SHIFT));
+}
+
+__pmusramfunc void secure_watchdog_ungate(void)
+{
+	/**
+	 * Enable CA53 and CM0 wdt pclk
+	 * BIT[8]: ca53 wdt pclk, 0: enable 1: disable
+	 * BIT[10]: cm0 wdt pclk, 0: enable 1: disable
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3),
+		      WMSK_BIT(PCLK_WDT_CA53_GATE_SHIFT) |
+		      WMSK_BIT(PCLK_WDT_CM0_GATE_SHIFT));
+}
+
+__pmusramfunc void sram_secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT1, 0xffffffff);
+
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
+		      TIMER_EN | TIMER_FMODE);
+}
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT1, 0xffffffff);
+
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
+		      TIMER_EN | TIMER_FMODE);
+}
+
+void secure_sgrf_init(void)
+{
+	/* security config for master */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5),
+		      REG_SOC_WMSK | SGRF_SOC_ALLMST_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6),
+		      REG_SOC_WMSK | SGRF_SOC_ALLMST_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7),
+		      REG_SOC_WMSK | SGRF_SOC_ALLMST_NS);
+
+	/* security config for slave */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(0),
+		      SGRF_PMU_SLV_S_CFGED |
+		      SGRF_PMU_SLV_CRYPTO1_NS);
+	mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(1),
+		      SGRF_SLV_S_WMSK | SGRF_PMUSRAM_S);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(0),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(1),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(2),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(3),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(4),
+		      SGRF_SLV_S_WMSK | SGRF_INTSRAM_S);
+}
+
+void secure_sgrf_ddr_rgn_init(void)
+{
+	sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE);
+	sgrf_ddr_rgn_global_bypass(0);
+}
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.h b/plat/rockchip/rk3399/drivers/secure/secure.h
new file mode 100644
index 0000000..e31c999
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/secure/secure.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_H
+#define SECURE_H
+
+/**************************************************
+ * sgrf reg, offset
+ **************************************************/
+#define SGRF_SOC_CON0_1(n)		(0xc000 + (n) * 4)
+#define SGRF_SOC_CON3_7(n)		(0xe00c + ((n) - 3) * 4)
+#define SGRF_SOC_CON8_15(n)		(0x8020 + ((n) - 8) * 4)
+#define SGRF_SOC_CON(n) 		(n < 3 ? SGRF_SOC_CON0_1(n) :\
+						(n < 8 ? SGRF_SOC_CON3_7(n) :\
+							 SGRF_SOC_CON8_15(n)))
+
+#define SGRF_PMU_SLV_CON0_1(n)		(0xc240 + ((n) - 0) * 4)
+#define SGRF_SLV_SECURE_CON0_4(n)	(0xe3c0 + ((n) - 0) * 4)
+#define SGRF_DDRRGN_CON0_16(n)		((n) * 4)
+#define SGRF_DDRRGN_CON20_34(n)		(0x50 + ((n) - 20) * 4)
+
+/* All of master in ns */
+#define SGRF_SOC_ALLMST_NS		0xffff
+
+/* security config for slave */
+#define SGRF_SLV_S_WMSK			0xffff0000
+#define SGRF_SLV_S_ALL_NS		0x0
+
+/* security config pmu slave ip */
+/* All of slaves  is ns */
+#define SGRF_PMU_SLV_S_NS		BIT_WITH_WMSK(0)
+/* slaves secure attr is configed */
+#define SGRF_PMU_SLV_S_CFGED		WMSK_BIT(0)
+#define SGRF_PMU_SLV_CRYPTO1_NS		WMSK_BIT(1)
+
+#define SGRF_PMUSRAM_S			BIT(8)
+
+#define SGRF_INTSRAM_S			BIT(13)
+
+/* ddr region */
+#define SGRF_DDR_RGN_0_16_WMSK		0x0fff  /* DDR RGN 0~16 size mask */
+
+#define SGRF_DDR_RGN_DPLL_CLK		BIT_WITH_WMSK(15) /* DDR PLL output clock */
+#define SGRF_DDR_RGN_RTC_CLK		BIT_WITH_WMSK(14) /* 32K clock for DDR PLL */
+
+/* All security of the DDR RGNs are bypass */
+#define SGRF_DDR_RGN_BYPS		BIT_WITH_WMSK(9)
+/* All security of the DDR RGNs are not bypass */
+#define SGRF_DDR_RGN_NO_BYPS		WMSK_BIT(9)
+
+/* The MST access the ddr rgn n with secure attribution */
+#define SGRF_L_MST_S_DDR_RGN(n)		BIT_WITH_WMSK((n))
+/* bits[16:8]*/
+#define SGRF_H_MST_S_DDR_RGN(n)		BIT_WITH_WMSK((n) + 8)
+
+#define SGRF_PMU_CON0			0x0c100
+#define SGRF_PMU_CON(n)   		(SGRF_PMU_CON0 + (n) * 4)
+
+/**************************************************
+ * secure timer
+ **************************************************/
+/* chanal0~5 */
+#define STIMER0_CHN_BASE(n)		(STIME_BASE + 0x20 * (n))
+/* chanal6~11 */
+#define STIMER1_CHN_BASE(n)		(STIME_BASE + 0x8000 + 0x20 * (n))
+
+ /* low 32 bits */
+#define TIMER_END_COUNT0		0x00
+ /* high 32 bits */
+#define TIMER_END_COUNT1		0x04
+
+#define TIMER_CURRENT_VALUE0		0x08
+#define TIMER_CURRENT_VALUE1		0x0C
+
+ /* low 32 bits */
+#define TIMER_INIT_COUNT0		0x10
+ /* high 32 bits */
+#define TIMER_INIT_COUNT1		0x14
+
+#define TIMER_INTSTATUS			0x18
+#define TIMER_CONTROL_REG		0x1c
+
+#define TIMER_EN			0x1
+
+#define TIMER_FMODE			(0x0 << 1)
+#define TIMER_RMODE			(0x1 << 1)
+
+/**************************************************
+ * secure WDT
+ **************************************************/
+#define PCLK_WDT_CA53_GATE_SHIFT	8
+#define PCLK_WDT_CM0_GATE_SHIFT		10
+
+/* export secure operating APIs */
+void secure_watchdog_gate(void);
+__pmusramfunc void secure_watchdog_ungate(void);
+void secure_timer_init(void);
+void secure_sgrf_init(void);
+void secure_sgrf_ddr_rgn_init(void);
+__pmusramfunc void sram_secure_timer_init(void);
+
+#endif /* SECURE_H */
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
new file mode 100644
index 0000000..c877dbd
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <dfs.h>
+#include <dram.h>
+#include <m0_ctl.h>
+#include <plat_private.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+/* Table of regions to map using the MMU.  */
+const mmap_region_t plat_rk_mmap[] = {
+	MAP_REGION_FLAT(DEV_RNG0_BASE, DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+
+	{ 0 }
+};
+
+/* The RockChip power domain tree descriptor */
+const unsigned char rockchip_power_domain_tree_desc[] = {
+	/* No of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* No of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+	/* No of children for the second cluster node */
+	PLATFORM_CLUSTER1_CORE_COUNT
+};
+
+/* sleep data for pll suspend */
+static struct deepsleep_data_s slp_data;
+
+/* sleep data that needs to be accessed from pmusram */
+__pmusramdata struct pmu_sleep_data pmu_slp_data;
+
+static void set_pll_slow_mode(uint32_t pll_id)
+{
+	if (pll_id == PPLL_ID)
+		mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3), PLL_SLOW_MODE);
+	else
+		mmio_write_32((CRU_BASE +
+			      CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE);
+}
+
+static void set_pll_normal_mode(uint32_t pll_id)
+{
+	if (pll_id == PPLL_ID)
+		mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3), PLL_NOMAL_MODE);
+	else
+		mmio_write_32(CRU_BASE +
+			      CRU_PLL_CON(pll_id, 3), PLL_NOMAL_MODE);
+}
+
+static void set_pll_bypass(uint32_t pll_id)
+{
+	if (pll_id == PPLL_ID)
+		mmio_write_32(PMUCRU_BASE +
+			      PMUCRU_PPLL_CON(3), PLL_BYPASS_MODE);
+	else
+		mmio_write_32(CRU_BASE +
+			      CRU_PLL_CON(pll_id, 3), PLL_BYPASS_MODE);
+}
+
+static void _pll_suspend(uint32_t pll_id)
+{
+	set_pll_slow_mode(pll_id);
+	set_pll_bypass(pll_id);
+}
+
+/**
+ * disable_dvfs_plls - To suspend the specific PLLs
+ *
+ * When we close the center logic, the DPLL will be closed,
+ * so we need to keep the ABPLL and switch to it to supply
+ * clock for DDR during suspend, then we should not close
+ * the ABPLL and exclude ABPLL_ID.
+ */
+void disable_dvfs_plls(void)
+{
+	_pll_suspend(CPLL_ID);
+	_pll_suspend(NPLL_ID);
+	_pll_suspend(VPLL_ID);
+	_pll_suspend(GPLL_ID);
+	_pll_suspend(ALPLL_ID);
+}
+
+/**
+ * disable_nodvfs_plls - To suspend the PPLL
+ */
+void disable_nodvfs_plls(void)
+{
+	_pll_suspend(PPLL_ID);
+}
+
+/**
+ * restore_pll - Copy PLL settings from memory to a PLL.
+ *
+ * This will copy PLL settings from an array in memory to the memory mapped
+ * registers for a PLL.
+ *
+ * Note that: above the PLL exclude PPLL.
+ *
+ * pll_id: One of the values from enum plls_id
+ * src: Pointer to the array of values to restore from
+ */
+static void restore_pll(int pll_id, uint32_t *src)
+{
+	/* Nice to have PLL off while configuring */
+	mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE);
+
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK);
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK);
+
+	/* Do PLL_CON3 since that will enable things */
+	mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK);
+
+	/* Wait for PLL lock done */
+	while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) &
+		0x80000000) == 0x0)
+		;
+}
+
+/**
+ * save_pll - Copy PLL settings a PLL to memory
+ *
+ * This will copy PLL settings from the memory mapped registers for a PLL to
+ * an array in memory.
+ *
+ * Note that: above the PLL exclude PPLL.
+ *
+ * pll_id: One of the values from enum plls_id
+ * src: Pointer to the array of values to save to.
+ */
+static void save_pll(uint32_t *dst, int pll_id)
+{
+	int i;
+
+	for (i = 0; i < PLL_CON_COUNT; i++)
+		dst[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, i));
+}
+
+/**
+ * prepare_abpll_for_ddrctrl - Copy DPLL settings to ABPLL
+ *
+ * This will copy DPLL settings from the memory mapped registers for a PLL to
+ * an array in memory.
+ */
+void prepare_abpll_for_ddrctrl(void)
+{
+	save_pll(slp_data.plls_con[ABPLL_ID], ABPLL_ID);
+	save_pll(slp_data.plls_con[DPLL_ID], DPLL_ID);
+
+	restore_pll(ABPLL_ID, slp_data.plls_con[DPLL_ID]);
+}
+
+void restore_abpll(void)
+{
+	restore_pll(ABPLL_ID, slp_data.plls_con[ABPLL_ID]);
+}
+
+void clk_gate_con_save(void)
+{
+	uint32_t i = 0;
+
+	for (i = 0; i < PMUCRU_GATE_COUNT; i++)
+		slp_data.pmucru_gate_con[i] =
+			mmio_read_32(PMUCRU_BASE + PMUCRU_GATE_CON(i));
+
+	for (i = 0; i < CRU_GATE_COUNT; i++)
+		slp_data.cru_gate_con[i] =
+			mmio_read_32(CRU_BASE + CRU_GATE_CON(i));
+}
+
+void clk_gate_con_disable(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < PMUCRU_GATE_COUNT; i++)
+		mmio_write_32(PMUCRU_BASE + PMUCRU_GATE_CON(i), REG_SOC_WMSK);
+
+	for (i = 0; i < CRU_GATE_COUNT; i++)
+		mmio_write_32(CRU_BASE + CRU_GATE_CON(i), REG_SOC_WMSK);
+}
+
+void clk_gate_con_restore(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < PMUCRU_GATE_COUNT; i++)
+		mmio_write_32(PMUCRU_BASE + PMUCRU_GATE_CON(i),
+			      REG_SOC_WMSK | slp_data.pmucru_gate_con[i]);
+
+	for (i = 0; i < CRU_GATE_COUNT; i++)
+		mmio_write_32(CRU_BASE + CRU_GATE_CON(i),
+			      REG_SOC_WMSK | slp_data.cru_gate_con[i]);
+}
+
+static void set_plls_nobypass(uint32_t pll_id)
+{
+	if (pll_id == PPLL_ID)
+		mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3),
+			      PLL_NO_BYPASS_MODE);
+	else
+		mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3),
+			      PLL_NO_BYPASS_MODE);
+}
+
+static void _pll_resume(uint32_t pll_id)
+{
+	set_plls_nobypass(pll_id);
+	set_pll_normal_mode(pll_id);
+}
+
+void set_pmu_rsthold(void)
+{
+	uint32_t rstnhold_cofig0;
+	uint32_t rstnhold_cofig1;
+
+	pmu_slp_data.pmucru_rstnhold_con0 = mmio_read_32(PMUCRU_BASE +
+					    PMUCRU_RSTNHOLD_CON0);
+	pmu_slp_data.pmucru_rstnhold_con1 = mmio_read_32(PMUCRU_BASE +
+					    PMUCRU_RSTNHOLD_CON1);
+	rstnhold_cofig0 = BIT_WITH_WMSK(PRESETN_NOC_PMU_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_INTMEM_PMU_HOLD) |
+			  BIT_WITH_WMSK(HRESETN_CM0S_PMU_HOLD) |
+			  BIT_WITH_WMSK(HRESETN_CM0S_NOC_PMU_HOLD) |
+			  BIT_WITH_WMSK(DRESETN_CM0S_PMU_HOLD) |
+			  BIT_WITH_WMSK(POESETN_CM0S_PMU_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_TIMER_PMU_0_1_HOLD) |
+			  BIT_WITH_WMSK(RESETN_TIMER_PMU_0_HOLD) |
+			  BIT_WITH_WMSK(RESETN_TIMER_PMU_1_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_UART_M0_PMU_HOLD) |
+			  BIT_WITH_WMSK(RESETN_UART_M0_PMU_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_WDT_PMU_HOLD);
+	rstnhold_cofig1 = BIT_WITH_WMSK(PRESETN_RKPWM_PMU_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_PMUGRF_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_SGRF_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_GPIO0_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_GPIO1_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_CRU_PMU_HOLD) |
+			  BIT_WITH_WMSK(PRESETN_PVTM_PMU_HOLD);
+
+	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON0, rstnhold_cofig0);
+	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1, rstnhold_cofig1);
+}
+
+void pmu_sgrf_rst_hld(void)
+{
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_HOLD);
+}
+
+/*
+ * When system reset in running state, we want the cpus to be reboot
+ * from maskrom (system reboot),
+ * the pmusgrf reset-hold bits needs to be released.
+ * When system wake up from system deep suspend, some soc will be reset
+ * when waked up,
+ * we want the bootcpu to be reboot from pmusram,
+ * the pmusgrf reset-hold bits needs to be held.
+ */
+__pmusramfunc void pmu_sgrf_rst_hld_release(void)
+{
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_RLS);
+}
+
+__pmusramfunc void restore_pmu_rsthold(void)
+{
+	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON0,
+		      pmu_slp_data.pmucru_rstnhold_con0 | REG_SOC_WMSK);
+	mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1,
+		      pmu_slp_data.pmucru_rstnhold_con1 | REG_SOC_WMSK);
+}
+
+/**
+ * enable_dvfs_plls - To resume the specific PLLs
+ *
+ * Please see the comment at the disable_dvfs_plls()
+ * we don't suspend the ABPLL, so don't need resume
+ * it too.
+ */
+void enable_dvfs_plls(void)
+{
+	_pll_resume(ALPLL_ID);
+	_pll_resume(GPLL_ID);
+	_pll_resume(VPLL_ID);
+	_pll_resume(NPLL_ID);
+	_pll_resume(CPLL_ID);
+}
+
+/**
+ * enable_nodvfs_plls - To resume the PPLL
+ */
+void enable_nodvfs_plls(void)
+{
+	_pll_resume(PPLL_ID);
+}
+
+void soc_global_soft_reset_init(void)
+{
+	mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1),
+		      CRU_PMU_SGRF_RST_RLS);
+
+	mmio_clrbits_32(CRU_BASE + CRU_GLB_RST_CON,
+			CRU_PMU_WDTRST_MSK | CRU_PMU_FIRST_SFTRST_MSK);
+}
+
+void __dead2 soc_global_soft_reset(void)
+{
+	set_pll_slow_mode(VPLL_ID);
+	set_pll_slow_mode(NPLL_ID);
+	set_pll_slow_mode(GPLL_ID);
+	set_pll_slow_mode(CPLL_ID);
+	set_pll_slow_mode(PPLL_ID);
+	set_pll_slow_mode(ABPLL_ID);
+	set_pll_slow_mode(ALPLL_ID);
+
+	dsb();
+
+	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
+
+	/*
+	 * Maybe the HW needs some times to reset the system,
+	 * so we do not hope the core to excute valid codes.
+	 */
+	while (1)
+		;
+}
+
+void plat_rockchip_soc_init(void)
+{
+	secure_timer_init();
+	secure_sgrf_init();
+	secure_sgrf_ddr_rgn_init();
+	soc_global_soft_reset_init();
+	plat_rockchip_gpio_init();
+	m0_init();
+	dram_init();
+	dram_dfs_init();
+}
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
new file mode 100644
index 0000000..8539337
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOC_H
+#define SOC_H
+
+#include <lib/utils.h>
+
+#define GLB_SRST_FST_CFG_VAL	0xfdb9
+#define GLB_SRST_SND_CFG_VAL	0xeca8
+
+#define PMUCRU_PPLL_CON(n)		((n) * 4)
+#define CRU_PLL_CON(pll_id, n)	((pll_id)  * 0x20 + (n) * 4)
+#define PLL_MODE_MSK			0x03
+#define PLL_MODE_SHIFT			0x08
+#define PLL_BYPASS_MSK			0x01
+#define PLL_BYPASS_SHIFT		0x01
+#define PLL_PWRDN_MSK			0x01
+#define PLL_PWRDN_SHIFT			0x0
+#define PLL_BYPASS			BIT(1)
+#define PLL_PWRDN			BIT(0)
+
+#define NO_PLL_BYPASS			(0x00)
+#define NO_PLL_PWRDN			(0x00)
+
+#define FBDIV(n)		((0xfff << 16) | n)
+#define POSTDIV2(n)		((0x7 << (12 + 16)) | (n << 12))
+#define POSTDIV1(n)		((0x7 << (8 + 16)) | (n << 8))
+#define REFDIV(n)		((0x3F << 16) | n)
+#define PLL_LOCK(n)		((n >> 31) & 0x1)
+
+#define PLL_SLOW_MODE			BITS_WITH_WMASK(SLOW_MODE,\
+						PLL_MODE_MSK, PLL_MODE_SHIFT)
+
+#define PLL_NOMAL_MODE			BITS_WITH_WMASK(NORMAL_MODE,\
+						PLL_MODE_MSK, PLL_MODE_SHIFT)
+
+#define PLL_BYPASS_MODE			BIT_WITH_WMSK(PLL_BYPASS_SHIFT)
+#define PLL_NO_BYPASS_MODE		WMSK_BIT(PLL_BYPASS_SHIFT)
+
+#define PLL_CON_COUNT			0x06
+#define CRU_CLKSEL_COUNT		108
+#define CRU_CLKSEL_CON(n)		(0x100 + (n) * 4)
+
+#define PMUCRU_CLKSEL_CONUT		0x06
+#define PMUCRU_CLKSEL_OFFSET		0x080
+#define REG_SIZE			0x04
+#define REG_SOC_WMSK			0xffff0000
+#define CLK_GATE_MASK			0x01
+
+#define PMUCRU_GATE_COUNT	0x03
+#define CRU_GATE_COUNT		0x23
+#define PMUCRU_GATE_CON(n)	(0x100 + (n) * 4)
+#define CRU_GATE_CON(n)	(0x300 + (n) * 4)
+
+#define PMUCRU_RSTNHOLD_CON0	0x120
+enum {
+	PRESETN_NOC_PMU_HOLD = 1,
+	PRESETN_INTMEM_PMU_HOLD,
+	HRESETN_CM0S_PMU_HOLD,
+	HRESETN_CM0S_NOC_PMU_HOLD,
+	DRESETN_CM0S_PMU_HOLD,
+	POESETN_CM0S_PMU_HOLD,
+	PRESETN_SPI3_HOLD,
+	RESETN_SPI3_HOLD,
+	PRESETN_TIMER_PMU_0_1_HOLD,
+	RESETN_TIMER_PMU_0_HOLD,
+	RESETN_TIMER_PMU_1_HOLD,
+	PRESETN_UART_M0_PMU_HOLD,
+	RESETN_UART_M0_PMU_HOLD,
+	PRESETN_WDT_PMU_HOLD
+};
+
+#define PMUCRU_RSTNHOLD_CON1	0x124
+enum {
+	PRESETN_I2C0_HOLD,
+	PRESETN_I2C4_HOLD,
+	PRESETN_I2C8_HOLD,
+	PRESETN_MAILBOX_PMU_HOLD,
+	PRESETN_RKPWM_PMU_HOLD,
+	PRESETN_PMUGRF_HOLD,
+	PRESETN_SGRF_HOLD,
+	PRESETN_GPIO0_HOLD,
+	PRESETN_GPIO1_HOLD,
+	PRESETN_CRU_PMU_HOLD,
+	PRESETN_INTR_ARB_HOLD,
+	PRESETN_PVTM_PMU_HOLD,
+	RESETN_I2C0_HOLD,
+	RESETN_I2C4_HOLD,
+	RESETN_I2C8_HOLD
+};
+
+enum plls_id {
+	ALPLL_ID = 0,
+	ABPLL_ID,
+	DPLL_ID,
+	CPLL_ID,
+	GPLL_ID,
+	NPLL_ID,
+	VPLL_ID,
+	PPLL_ID,
+	END_PLL_ID,
+};
+
+#define CLST_L_CPUS_MSK (0xf)
+#define CLST_B_CPUS_MSK (0x3)
+
+enum pll_work_mode {
+	SLOW_MODE = 0x00,
+	NORMAL_MODE = 0x01,
+	DEEP_SLOW_MODE = 0x02,
+};
+
+enum glb_sft_reset {
+	PMU_RST_BY_FIRST_SFT,
+	PMU_RST_BY_SECOND_SFT = BIT(2),
+	PMU_RST_NOT_BY_SFT = BIT(3),
+};
+
+struct pll_div {
+	uint32_t mhz;
+	uint32_t refdiv;
+	uint32_t fbdiv;
+	uint32_t postdiv1;
+	uint32_t postdiv2;
+	uint32_t frac;
+	uint32_t freq;
+};
+
+struct deepsleep_data_s {
+	uint32_t plls_con[END_PLL_ID][PLL_CON_COUNT];
+	uint32_t cru_gate_con[CRU_GATE_COUNT];
+	uint32_t pmucru_gate_con[PMUCRU_GATE_COUNT];
+};
+
+struct pmu_sleep_data {
+	uint32_t pmucru_rstnhold_con0;
+	uint32_t pmucru_rstnhold_con1;
+};
+
+/**************************************************
+ * pmugrf reg, offset
+ **************************************************/
+#define PMUGRF_OSREG(n)		(0x300 + (n) * 4)
+
+/**************************************************
+ * DCF reg, offset
+ **************************************************/
+#define DCF_DCF_CTRL		0x0
+#define DCF_DCF_ADDR		0x8
+#define DCF_DCF_ISR		0xc
+#define DCF_DCF_TOSET		0x14
+#define DCF_DCF_TOCMD		0x18
+#define DCF_DCF_CMD_CFG		0x1c
+
+/* DCF_DCF_ISR */
+#define DCF_TIMEOUT		(1 << 2)
+#define DCF_ERR			(1 << 1)
+#define	DCF_DONE		(1 << 0)
+
+/* DCF_DCF_CTRL */
+#define DCF_VOP_HW_EN		(1 << 2)
+#define DCF_STOP		(1 << 1)
+#define DCF_START		(1 << 0)
+
+#define CYCL_24M_CNT_US(us)	(24 * us)
+#define CYCL_24M_CNT_MS(ms)	(ms * CYCL_24M_CNT_US(1000))
+#define CYCL_32K_CNT_MS(ms)	(ms * 32)
+
+/**************************************************
+ * cru reg, offset
+ **************************************************/
+#define CRU_SOFTRST_CON(n)	(0x400 + (n) * 4)
+
+#define CRU_DMAC0_RST		BIT_WITH_WMSK(3)
+ /* reset release*/
+#define CRU_DMAC0_RST_RLS	WMSK_BIT(3)
+
+#define CRU_DMAC1_RST		BIT_WITH_WMSK(4)
+ /* reset release*/
+#define CRU_DMAC1_RST_RLS	WMSK_BIT(4)
+
+#define CRU_GLB_RST_CON		0x0510
+#define CRU_GLB_SRST_FST	0x0500
+#define CRU_GLB_SRST_SND	0x0504
+
+#define CRU_CLKGATE_CON(n)	(0x300 + n * 4)
+#define PCLK_GPIO2_GATE_SHIFT	3
+#define PCLK_GPIO3_GATE_SHIFT	4
+#define PCLK_GPIO4_GATE_SHIFT	5
+
+/**************************************************
+ * pmu cru reg, offset
+ **************************************************/
+#define CRU_PMU_RSTHOLD_CON(n)		(0x120 + n * 4)
+/* reset hold*/
+#define CRU_PMU_SGRF_RST_HOLD		BIT_WITH_WMSK(6)
+/* reset hold release*/
+#define CRU_PMU_SGRF_RST_RLS		WMSK_BIT(6)
+
+#define CRU_PMU_WDTRST_MSK		(0x1 << 4)
+#define CRU_PMU_WDTRST_EN		0x0
+
+#define CRU_PMU_FIRST_SFTRST_MSK	(0x3 << 2)
+#define CRU_PMU_FIRST_SFTRST_EN		0x0
+
+#define CRU_PMU_CLKGATE_CON(n)		(0x100 + n * 4)
+#define PCLK_GPIO0_GATE_SHIFT		3
+#define PCLK_GPIO1_GATE_SHIFT		4
+
+#define CPU_BOOT_ADDR_WMASK	0xffff0000
+#define CPU_BOOT_ADDR_ALIGN	16
+
+#define GRF_IOMUX_2BIT_MASK     0x3
+#define GRF_IOMUX_GPIO          0x0
+
+#define GRF_GPIO4C2_IOMUX_SHIFT         4
+#define GRF_GPIO4C2_IOMUX_PWM           0x1
+#define GRF_GPIO4C6_IOMUX_SHIFT         12
+#define GRF_GPIO4C6_IOMUX_PWM           0x1
+
+#define PWM_CNT(n)			(0x0000 + 0x10 * (n))
+#define PWM_PERIOD_HPR(n)		(0x0004 + 0x10 * (n))
+#define PWM_DUTY_LPR(n)			(0x0008 + 0x10 * (n))
+#define PWM_CTRL(n)			(0x000c + 0x10 * (n))
+
+#define PWM_DISABLE			(0 << 0)
+#define PWM_ENABLE			(1 << 0)
+
+/* grf reg offset */
+#define GRF_USBPHY0_CTRL0	0x4480
+#define GRF_USBPHY0_CTRL2	0x4488
+#define GRF_USBPHY0_CTRL3	0x448c
+#define GRF_USBPHY0_CTRL12	0x44b0
+#define GRF_USBPHY0_CTRL13	0x44b4
+#define GRF_USBPHY0_CTRL15	0x44bc
+#define GRF_USBPHY0_CTRL16	0x44c0
+
+#define GRF_USBPHY1_CTRL0	0x4500
+#define GRF_USBPHY1_CTRL2	0x4508
+#define GRF_USBPHY1_CTRL3	0x450c
+#define GRF_USBPHY1_CTRL12	0x4530
+#define GRF_USBPHY1_CTRL13	0x4534
+#define GRF_USBPHY1_CTRL15	0x453c
+#define GRF_USBPHY1_CTRL16	0x4540
+
+#define GRF_GPIO2A_IOMUX	0xe000
+#define GRF_GPIO2D_HE		0xe18c
+#define GRF_DDRC0_CON0		0xe380
+#define GRF_DDRC0_CON1		0xe384
+#define GRF_DDRC1_CON0		0xe388
+#define GRF_DDRC1_CON1		0xe38c
+#define GRF_SOC_CON_BASE	0xe200
+#define GRF_SOC_CON(n)		(GRF_SOC_CON_BASE + (n) * 4)
+#define GRF_IO_VSEL		0xe640
+
+#define CRU_CLKSEL_CON0		0x0100
+#define CRU_CLKSEL_CON6		0x0118
+#define CRU_SDIO0_CON1		0x058c
+#define PMUCRU_CLKSEL_CON0	0x0080
+#define PMUCRU_CLKGATE_CON2	0x0108
+#define PMUCRU_SOFTRST_CON0	0x0110
+#define PMUCRU_GATEDIS_CON0 0x0130
+#define PMUCRU_SOFTRST_CON(n)   (PMUCRU_SOFTRST_CON0 + (n) * 4)
+
+/* export related and operating SoC APIs */
+void __dead2 soc_global_soft_reset(void);
+void disable_dvfs_plls(void);
+void disable_nodvfs_plls(void);
+void enable_dvfs_plls(void);
+void enable_nodvfs_plls(void);
+void prepare_abpll_for_ddrctrl(void);
+void restore_abpll(void);
+void clk_gate_con_save(void);
+void clk_gate_con_disable(void);
+void clk_gate_con_restore(void);
+void set_pmu_rsthold(void);
+void pmu_sgrf_rst_hld(void);
+__pmusramfunc void pmu_sgrf_rst_hld_release(void);
+__pmusramfunc void restore_pmu_rsthold(void);
+#endif /* SOC_H */
diff --git a/plat/rockchip/rk3399/include/addressmap.h b/plat/rockchip/rk3399/include/addressmap.h
new file mode 100644
index 0000000..dc1c703
--- /dev/null
+++ b/plat/rockchip/rk3399/include/addressmap.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ADDRESSMAP_H
+#define ADDRESSMAP_H
+
+#include <addressmap_shared.h>
+
+/* Registers base address */
+#define MMIO_BASE		0xF8000000
+
+/* Aggregate of all devices in the first GB */
+#define DEV_RNG0_BASE		MMIO_BASE
+#define DEV_RNG0_SIZE		SIZE_M(125)
+
+#endif /* ADDRESSMAP_H */
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
new file mode 100644
index 0000000..cfa912f
--- /dev/null
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ROCKCHIP_PLAT_LD_S
+#define ROCKCHIP_PLAT_LD_S
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+MEMORY {
+    SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = SRAM_BASE;
+	ASSERT(. == ALIGN(PAGE_SIZE),
+		"SRAM_BASE address is not aligned on a page boundary.")
+
+	/*
+	 * The SRAM space allocation for RK3399
+	 * ----------------
+	 * | m0 code bin
+	 * ----------------
+	 * | sram text
+	 * ----------------
+	 * | sram data
+	 * ----------------
+	 */
+	.incbin_sram : ALIGN(PAGE_SIZE) {
+		__sram_incbin_start = .;
+		*(.sram.incbin)
+		 __sram_incbin_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__sram_incbin_end = .;
+	} >SRAM
+	ASSERT((__sram_incbin_real_end - __sram_incbin_start) <=
+		SRAM_BIN_LIMIT, ".incbin_sram has exceeded its limit")
+
+	.text_sram : ALIGN(PAGE_SIZE) {
+		__bl31_sram_text_start = .;
+		*(.sram.text)
+		*(.sram.rodata)
+		__bl31_sram_text_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__bl31_sram_text_end = .;
+	} >SRAM
+	ASSERT((__bl31_sram_text_real_end - __bl31_sram_text_start) <=
+		SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit")
+
+	.data_sram : ALIGN(PAGE_SIZE) {
+		__bl31_sram_data_start = .;
+		*(.sram.data)
+		__bl31_sram_data_real_end = .;
+		. = ALIGN(PAGE_SIZE);
+		__bl31_sram_data_end = .;
+	} >SRAM
+	ASSERT((__bl31_sram_data_real_end - __bl31_sram_data_start) <=
+		SRAM_DATA_LIMIT, ".data_sram has exceeded its limit")
+
+	.stack_sram : ALIGN(PAGE_SIZE) {
+		__bl31_sram_stack_start = .;
+		. += PAGE_SIZE;
+		__bl31_sram_stack_end = .;
+	} >SRAM
+
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+
+		/* M0 start address request 4K align */
+		. = ALIGN(4096);
+		__pmusram_incbin_start = .;
+		*(.pmusram.incbin)
+		__pmusram_incbin_end = .;
+
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+	} >PMUSRAM
+}
+
+#endif /* ROCKCHIP_PLAT_LD_S */
diff --git a/plat/rockchip/rk3399/include/plat_sip_calls.h b/plat/rockchip/rk3399/include/plat_sip_calls.h
new file mode 100644
index 0000000..66c4868
--- /dev/null
+++ b/plat/rockchip/rk3399/include/plat_sip_calls.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/rockchip/rk3399/include/platform_def.h b/plat/rockchip/rk3399/include/platform_def.h
new file mode 100644
index 0000000..2861a7d
--- /dev/null
+++ b/plat/rockchip/rk3399/include/platform_def.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include <bl31_param.h>
+#include <rk3399_def.h>
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if defined(IMAGE_BL1)
+#define PLATFORM_STACK_SIZE 0x440
+#elif defined(IMAGE_BL2)
+#define PLATFORM_STACK_SIZE 0x400
+#elif defined(IMAGE_BL31)
+#define PLATFORM_STACK_SIZE 0x800
+#elif defined(IMAGE_BL32)
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_MAX_AFFLVL		MPIDR_AFFLVL2
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	2
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
+					 PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	4
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
+					 PLATFORM_CLUSTER_COUNT +	\
+					 PLATFORM_CORE_COUNT)
+#define PLAT_RK_CLST_TO_CPUID_SHIFT	6
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+/*
+ * This macro defines the deepest retention state possible. A higher state
+ * id will represent an invalid or a power down state.
+ */
+#define PLAT_MAX_RET_STATE		U(1)
+
+/*
+ * This macro defines the deepest power down states possible. Any state ID
+ * higher than this is invalid.
+ */
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_VIRT_ADDR_SPACE_SIZE   (1ULL << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE    (1ULL << 32)
+#define MAX_XLAT_TABLES		20
+#define MAX_MMAP_REGIONS	25
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Define GICD and GICC and GICR base
+ */
+#define PLAT_RK_GICD_BASE	BASE_GICD_BASE
+#define PLAT_RK_GICR_BASE	BASE_GICR_BASE
+#define PLAT_RK_GICC_BASE	0
+
+#define PLAT_RK_UART_BASE		UART2_BASE
+#define PLAT_RK_UART_CLOCK		RK3399_UART_CLOCK
+#define PLAT_RK_UART_BAUDRATE		RK3399_BAUDRATE
+
+#define PLAT_RK_CCI_BASE		CCI500_BASE
+
+#define PLAT_RK_PRIMARY_CPU		0x0
+
+#define PSRAM_DO_DDR_RESUME	1
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rockchip/rk3399/include/shared/addressmap_shared.h b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
new file mode 100644
index 0000000..84a31b2
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ADDRESSMAP_SHARED_H
+#define ADDRESSMAP_SHARED_H
+
+#define SIZE_K(n)		((n) * 1024)
+#define SIZE_M(n)		((n) * 1024 * 1024)
+#define SRAM_TEXT_LIMIT		(4 * 1024)
+#define SRAM_DATA_LIMIT		(4 * 1024)
+#define SRAM_BIN_LIMIT		(4 * 1024)
+
+/*
+ * The parts of the shared defined registers address with AP and M0,
+ * let's note and mark the previous defines like this:
+ */
+#define GIC500_BASE		(MMIO_BASE + 0x06E00000)
+#define UART0_BASE		(MMIO_BASE + 0x07180000)
+#define UART1_BASE		(MMIO_BASE + 0x07190000)
+#define UART2_BASE		(MMIO_BASE + 0x071A0000)
+#define UART3_BASE		(MMIO_BASE + 0x071B0000)
+
+#define PMU_BASE		(MMIO_BASE + 0x07310000)
+#define PMUGRF_BASE		(MMIO_BASE + 0x07320000)
+#define SGRF_BASE		(MMIO_BASE + 0x07330000)
+#define PMUSRAM_BASE		(MMIO_BASE + 0x073B0000)
+#define PWM_BASE		(MMIO_BASE + 0x07420000)
+
+#define CIC_BASE		(MMIO_BASE + 0x07620000)
+#define PD_BUS0_BASE		(MMIO_BASE + 0x07650000)
+#define DCF_BASE		(MMIO_BASE + 0x076A0000)
+#define GPIO0_BASE		(MMIO_BASE + 0x07720000)
+#define GPIO1_BASE		(MMIO_BASE + 0x07730000)
+#define PMUCRU_BASE		(MMIO_BASE + 0x07750000)
+#define CRU_BASE		(MMIO_BASE + 0x07760000)
+#define GRF_BASE		(MMIO_BASE + 0x07770000)
+#define GPIO2_BASE		(MMIO_BASE + 0x07780000)
+#define GPIO3_BASE		(MMIO_BASE + 0x07788000)
+#define GPIO4_BASE		(MMIO_BASE + 0x07790000)
+#define WDT1_BASE		(MMIO_BASE + 0x07840000)
+#define WDT0_BASE		(MMIO_BASE + 0x07848000)
+#define TIMER_BASE		(MMIO_BASE + 0x07850000)
+#define STIME_BASE		(MMIO_BASE + 0x07860000)
+#define SRAM_BASE		(MMIO_BASE + 0x078C0000)
+#define SERVICE_NOC_0_BASE	(MMIO_BASE + 0x07A50000)
+#define DDRC0_BASE		(MMIO_BASE + 0x07A80000)
+#define SERVICE_NOC_1_BASE	(MMIO_BASE + 0x07A84000)
+#define DDRC1_BASE		(MMIO_BASE + 0x07A88000)
+#define SERVICE_NOC_2_BASE	(MMIO_BASE + 0x07A8C000)
+#define SERVICE_NOC_3_BASE	(MMIO_BASE + 0x07A90000)
+#define CCI500_BASE		(MMIO_BASE + 0x07B00000)
+#define COLD_BOOT_BASE		(MMIO_BASE + 0x07FF0000)
+
+/* Registers size */
+#define GIC500_SIZE		SIZE_M(2)
+#define UART0_SIZE		SIZE_K(64)
+#define UART1_SIZE		SIZE_K(64)
+#define UART2_SIZE		SIZE_K(64)
+#define UART3_SIZE		SIZE_K(64)
+#define PMU_SIZE		SIZE_K(64)
+#define PMUGRF_SIZE		SIZE_K(64)
+#define SGRF_SIZE		SIZE_K(64)
+#define PMUSRAM_SIZE		SIZE_K(64)
+#define PMUSRAM_RSIZE		SIZE_K(8)
+#define PWM_SIZE		SIZE_K(64)
+#define CIC_SIZE		SIZE_K(4)
+#define DCF_SIZE		SIZE_K(4)
+#define GPIO0_SIZE		SIZE_K(64)
+#define GPIO1_SIZE		SIZE_K(64)
+#define PMUCRU_SIZE		SIZE_K(64)
+#define CRU_SIZE		SIZE_K(64)
+#define GRF_SIZE		SIZE_K(64)
+#define GPIO2_SIZE		SIZE_K(32)
+#define GPIO3_SIZE		SIZE_K(32)
+#define GPIO4_SIZE		SIZE_K(32)
+#define STIME_SIZE		SIZE_K(64)
+#define SRAM_SIZE		SIZE_K(192)
+#define SERVICE_NOC_0_SIZE	SIZE_K(192)
+#define DDRC0_SIZE		SIZE_K(32)
+#define SERVICE_NOC_1_SIZE	SIZE_K(16)
+#define DDRC1_SIZE		SIZE_K(32)
+#define SERVICE_NOC_2_SIZE	SIZE_K(16)
+#define SERVICE_NOC_3_SIZE	SIZE_K(448)
+#define CCI500_SIZE		SIZE_M(1)
+#define PD_BUS0_SIZE		SIZE_K(448)
+
+/* DDR Registers address */
+#define CTL_BASE(ch)		(DDRC0_BASE + (ch) * 0x8000)
+#define CTL_REG(ch, n)		(CTL_BASE(ch) + (n) * 0x4)
+
+#define PI_OFFSET		0x800
+#define PI_BASE(ch)		(CTL_BASE(ch) + PI_OFFSET)
+#define PI_REG(ch, n)		(PI_BASE(ch) + (n) * 0x4)
+
+#define PHY_OFFSET		0x2000
+#define PHY_BASE(ch)		(CTL_BASE(ch) + PHY_OFFSET)
+#define PHY_REG(ch, n)		(PHY_BASE(ch) + (n) * 0x4)
+
+#define MSCH_BASE(ch)		(SERVICE_NOC_1_BASE + (ch) * 0x8000)
+
+#endif /* ADDRESSMAP_SHARED_H */
diff --git a/plat/rockchip/rk3399/include/shared/bl31_param.h b/plat/rockchip/rk3399/include/shared/bl31_param.h
new file mode 100644
index 0000000..e7f2226
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/bl31_param.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BL31_PARAM_H
+#define BL31_PARAM_H
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF text, ro, rw, Size: 1MB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x100000)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted RAM
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x1000)
+#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
+
+#endif /* BL31_PARAM_H */
diff --git a/plat/rockchip/rk3399/include/shared/dram_regs.h b/plat/rockchip/rk3399/include/shared/dram_regs.h
new file mode 100644
index 0000000..4d4ebf6
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/dram_regs.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_REGS_H
+#define DRAM_REGS_H
+
+#define CTL_REG_NUM		332
+#define PHY_REG_NUM		959
+#define PI_REG_NUM		200
+
+#define MSCH_ID_COREID		0x0
+#define MSCH_ID_REVISIONID	0x4
+#define MSCH_DEVICECONF		0x8
+#define MSCH_DEVICESIZE		0xc
+#define MSCH_DDRTIMINGA0	0x10
+#define MSCH_DDRTIMINGB0	0x14
+#define MSCH_DDRTIMINGC0	0x18
+#define MSCH_DEVTODEV0		0x1c
+#define MSCH_DDRMODE		0x110
+#define MSCH_AGINGX0		0x1000
+
+#define CIC_CTRL0		0x0
+#define CIC_CTRL1		0x4
+#define CIC_IDLE_TH		0x8
+#define CIC_CG_WAIT_TH		0xc
+#define CIC_STATUS0		0x10
+#define CIC_STATUS1		0x14
+#define CIC_CTRL2		0x18
+#define CIC_CTRL3		0x1c
+#define CIC_CTRL4		0x20
+
+/* DENALI_CTL_00 */
+#define START			1
+
+/* DENALI_CTL_68 */
+#define PWRUP_SREFRESH_EXIT	(1 << 16)
+
+/* DENALI_CTL_274 */
+#define MEM_RST_VALID		1
+
+#define PHY_DRV_ODT_Hi_Z	0x0
+#define PHY_DRV_ODT_240		0x1
+#define PHY_DRV_ODT_120		0x8
+#define PHY_DRV_ODT_80		0x9
+#define PHY_DRV_ODT_60		0xc
+#define PHY_DRV_ODT_48		0xd
+#define PHY_DRV_ODT_40		0xe
+#define PHY_DRV_ODT_34_3	0xf
+
+/*
+ * sys_reg bitfield struct
+ * [31] row_3_4_ch1
+ * [30] row_3_4_ch0
+ * [29:28] chinfo
+ * [27] rank_ch1
+ * [26:25] col_ch1
+ * [24] bk_ch1
+ * [23:22] cs0_row_ch1
+ * [21:20] cs1_row_ch1
+ * [19:18] bw_ch1
+ * [17:16] dbw_ch1;
+ * [15:13] ddrtype
+ * [12] channelnum
+ * [11] rank_ch0
+ * [10:9] col_ch0
+ * [8] bk_ch0
+ * [7:6] cs0_row_ch0
+ * [5:4] cs1_row_ch0
+ * [3:2] bw_ch0
+ * [1:0] dbw_ch0
+ */
+#define SYS_REG_ENC_ROW_3_4(n, ch)	((n) << (30 + (ch)))
+#define SYS_REG_DEC_ROW_3_4(n, ch)	(((n) >> (30 + (ch))) & 0x1)
+#define SYS_REG_ENC_CHINFO(ch)		(1 << (28 + (ch)))
+#define SYS_REG_DEC_CHINFO(n, ch)	(((n) >> (28 + (ch))) & 0x1)
+#define SYS_REG_ENC_DDRTYPE(n)		((n) << 13)
+#define SYS_REG_DEC_DDRTYPE(n)		(((n) >> 13) & 0x7)
+#define SYS_REG_ENC_NUM_CH(n)		(((n) - 1) << 12)
+#define SYS_REG_DEC_NUM_CH(n)		(1 + (((n) >> 12) & 0x1))
+#define SYS_REG_ENC_RANK(n, ch)		(((n) - 1) << (11 + (ch) * 16))
+#define SYS_REG_DEC_RANK(n, ch)		(1 + (((n) >> (11 + (ch) * 16)) & 0x1))
+#define SYS_REG_ENC_COL(n, ch)		(((n) - 9) << (9 + (ch) * 16))
+#define SYS_REG_DEC_COL(n, ch)		(9 + (((n) >> (9 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_BK(n, ch)		(((n) == 3 ? 0 : 1) << (8 + (ch) * 16))
+#define SYS_REG_DEC_BK(n, ch)		(3 - (((n) >> (8 + (ch) * 16)) & 0x1))
+#define SYS_REG_ENC_CS0_ROW(n, ch)	(((n) - 13) << (6 + (ch) * 16))
+#define SYS_REG_DEC_CS0_ROW(n, ch)	(13 + (((n) >> (6 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_CS1_ROW(n, ch)	(((n) - 13) << (4 + (ch) * 16))
+#define SYS_REG_DEC_CS1_ROW(n, ch)	(13 + (((n) >> (4 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_BW(n, ch)		((2 >> (n)) << (2 + (ch) * 16))
+#define SYS_REG_DEC_BW(n, ch)		(2 >> (((n) >> (2 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_DBW(n, ch)		((2 >> (n)) << (0 + (ch) * 16))
+#define SYS_REG_DEC_DBW(n, ch)		(2 >> (((n) >> (0 + (ch) * 16)) & 0x3))
+#define DDR_STRIDE(n)		mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(4), \
+					      (0x1f<<(10+16))|((n)<<10))
+
+#endif /* DRAM_REGS_H */
diff --git a/plat/rockchip/rk3399/include/shared/m0_param.h b/plat/rockchip/rk3399/include/shared/m0_param.h
new file mode 100644
index 0000000..a5311c9
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/m0_param.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef M0_PARAM_H
+#define M0_PARAM_H
+
+#define PARAM_ADDR		0xc0
+
+#define PARAM_M0_FUNC		0x00
+#define PARAM_DRAM_FREQ		0x04
+#define PARAM_DPLL_CON0		0x08
+#define PARAM_DPLL_CON1		0x0c
+#define PARAM_DPLL_CON2		0x10
+#define PARAM_DPLL_CON3		0x14
+#define PARAM_DPLL_CON4		0x18
+#define PARAM_DPLL_CON5		0x1c
+#define PARAM_FREQ_SELECT	0x20
+#define PARAM_M0_DONE		0x24
+#define PARAM_M0_SIZE		0x28
+#define M0_DONE_FLAG		0xf59ec39a
+
+#endif /* M0_PARAM_H */
diff --git a/plat/rockchip/rk3399/include/shared/misc_regs.h b/plat/rockchip/rk3399/include/shared/misc_regs.h
new file mode 100644
index 0000000..0160453
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/misc_regs.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MISC_REGS_H
+#define MISC_REGS_H
+
+/* CRU */
+#define CRU_DPLL_CON0		0x40
+#define CRU_DPLL_CON1		0x44
+#define CRU_DPLL_CON2		0x48
+#define CRU_DPLL_CON3		0x4c
+#define CRU_DPLL_CON4		0x50
+#define CRU_DPLL_CON5		0x54
+
+/* CRU_PLL_CON3 */
+#define PLL_SLOW_MODE		0
+#define PLL_NORMAL_MODE		1
+#define PLL_MODE(n)		((0x3 << (8 + 16)) | ((n) << 8))
+#define PLL_POWER_DOWN(n)	((0x1 << (0 + 16)) | ((n) << 0))
+
+/* PMU CRU */
+#define PMU_CRU_GATEDIS_CON0	0x130
+
+#endif /* MISC_REGS_H */
diff --git a/plat/rockchip/rk3399/include/shared/pmu_bits.h b/plat/rockchip/rk3399/include/shared/pmu_bits.h
new file mode 100644
index 0000000..2968d5b
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/pmu_bits.h
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_BITS_H
+#define PMU_BITS_H
+
+enum pmu_powerdomain_id {
+	PD_CPUL0 = 0,
+	PD_CPUL1,
+	PD_CPUL2,
+	PD_CPUL3,
+	PD_CPUB0,
+	PD_CPUB1,
+	PD_SCUL,
+	PD_SCUB,
+	PD_TCPD0,
+	PD_TCPD1,
+	PD_CCI,
+	PD_PERILP,
+	PD_PERIHP,
+	PD_CENTER,
+	PD_VIO,
+	PD_GPU,
+	PD_VCODEC,
+	PD_VDU,
+	PD_RGA,
+	PD_IEP,
+	PD_VO,
+	PD_ISP0 = 22,
+	PD_ISP1,
+	PD_HDCP,
+	PD_GMAC,
+	PD_EMMC,
+	PD_USB3,
+	PD_EDP,
+	PD_GIC,
+	PD_SD,
+	PD_SDIOAUDIO,
+	PD_END
+};
+
+enum powerdomain_state {
+	PMU_POWER_ON = 0,
+	PMU_POWER_OFF,
+};
+
+enum pmu_bus_id {
+	BUS_ID_GPU = 0,
+	BUS_ID_PERILP,
+	BUS_ID_PERIHP,
+	BUS_ID_VCODEC,
+	BUS_ID_VDU,
+	BUS_ID_RGA,
+	BUS_ID_IEP,
+	BUS_ID_VOPB,
+	BUS_ID_VOPL,
+	BUS_ID_ISP0,
+	BUS_ID_ISP1,
+	BUS_ID_HDCP,
+	BUS_ID_USB3,
+	BUS_ID_PERILPM0,
+	BUS_ID_CENTER,
+	BUS_ID_CCIM0,
+	BUS_ID_CCIM1,
+	BUS_ID_VIO,
+	BUS_ID_MSCH0,
+	BUS_ID_MSCH1,
+	BUS_ID_ALIVE,
+	BUS_ID_PMU,
+	BUS_ID_EDP,
+	BUS_ID_GMAC,
+	BUS_ID_EMMC,
+	BUS_ID_CENTER1,
+	BUS_ID_PMUM0,
+	BUS_ID_GIC,
+	BUS_ID_SD,
+	BUS_ID_SDIOAUDIO,
+};
+
+enum pmu_bus_state {
+	BUS_ACTIVE,
+	BUS_IDLE,
+};
+
+/* pmu_cpuapm bit */
+enum pmu_cores_pm_by_wfi {
+	core_pm_en = 0,
+	core_pm_int_wakeup_en,
+	core_pm_resv,
+	core_pm_sft_wakeup_en
+};
+
+enum pmu_wkup_cfg0 {
+	PMU_GPIO0A_POSE_WKUP_EN = 0,
+	PMU_GPIO0B_POSE_WKUP_EN = 8,
+	PMU_GPIO0C_POSE_WKUP_EN = 16,
+	PMU_GPIO0D_POSE_WKUP_EN = 24,
+};
+
+enum pmu_wkup_cfg1 {
+	PMU_GPIO0A_NEGEDGE_WKUP_EN = 0,
+	PMU_GPIO0B_NEGEDGE_WKUP_EN = 7,
+	PMU_GPIO0C_NEGEDGE_WKUP_EN = 16,
+	PMU_GPIO0D_NEGEDGE_WKUP_EN = 24,
+};
+
+enum pmu_wkup_cfg2 {
+	PMU_GPIO1A_POSE_WKUP_EN = 0,
+	PMU_GPIO1B_POSE_WKUP_EN = 7,
+	PMU_GPIO1C_POSE_WKUP_EN = 16,
+	PMU_GPIO1D_POSE_WKUP_EN = 24,
+};
+
+enum pmu_wkup_cfg3 {
+	PMU_GPIO1A_NEGEDGE_WKUP_EN = 0,
+	PMU_GPIO1B_NEGEDGE_WKUP_EN = 7,
+	PMU_GPIO1C_NEGEDGE_WKUP_EN = 16,
+	PMU_GPIO1D_NEGEDGE_WKUP_EN = 24,
+};
+
+/* pmu_wkup_cfg4 */
+enum pmu_wkup_cfg4 {
+	PMU_CLUSTER_L_WKUP_EN = 0,
+	PMU_CLUSTER_B_WKUP_EN,
+	PMU_GPIO_WKUP_EN,
+	PMU_SDIO_WKUP_EN,
+
+	PMU_SDMMC_WKUP_EN,
+	PMU_TIMER_WKUP_EN = 6,
+	PMU_USBDEV_WKUP_EN,
+
+	PMU_SFT_WKUP_EN,
+	PMU_M0_WDT_WKUP_EN,
+	PMU_TIMEOUT_WKUP_EN,
+	PMU_PWM_WKUP_EN,
+
+	PMU_PCIE_WKUP_EN = 13,
+};
+
+enum pmu_pwrdn_con {
+	PMU_A53_L0_PWRDWN_EN = 0,
+	PMU_A53_L1_PWRDWN_EN,
+	PMU_A53_L2_PWRDWN_EN,
+	PMU_A53_L3_PWRDWN_EN,
+
+	PMU_A72_B0_PWRDWN_EN,
+	PMU_A72_B1_PWRDWN_EN,
+	PMU_SCU_L_PWRDWN_EN,
+	PMU_SCU_B_PWRDWN_EN,
+
+	PMU_TCPD0_PWRDWN_EN,
+	PMU_TCPD1_PWRDWN_EN,
+	PMU_CCI_PWRDWN_EN,
+	PMU_PERILP_PWRDWN_EN,
+
+	PMU_PERIHP_PWRDWN_EN,
+	PMU_CENTER_PWRDWN_EN,
+	PMU_VIO_PWRDWN_EN,
+	PMU_GPU_PWRDWN_EN,
+
+	PMU_VCODEC_PWRDWN_EN,
+	PMU_VDU_PWRDWN_EN,
+	PMU_RGA_PWRDWN_EN,
+	PMU_IEP_PWRDWN_EN,
+
+	PMU_VO_PWRDWN_EN,
+	PMU_ISP0_PWRDWN_EN = 22,
+	PMU_ISP1_PWRDWN_EN,
+
+	PMU_HDCP_PWRDWN_EN,
+	PMU_GMAC_PWRDWN_EN,
+	PMU_EMMC_PWRDWN_EN,
+	PMU_USB3_PWRDWN_EN,
+
+	PMU_EDP_PWRDWN_EN,
+	PMU_GIC_PWRDWN_EN,
+	PMU_SD_PWRDWN_EN,
+	PMU_SDIOAUDIO_PWRDWN_EN,
+};
+
+enum pmu_pwrdn_st {
+	PMU_A53_L0_PWRDWN_ST = 0,
+	PMU_A53_L1_PWRDWN_ST,
+	PMU_A53_L2_PWRDWN_ST,
+	PMU_A53_L3_PWRDWN_ST,
+
+	PMU_A72_B0_PWRDWN_ST,
+	PMU_A72_B1_PWRDWN_ST,
+	PMU_SCU_L_PWRDWN_ST,
+	PMU_SCU_B_PWRDWN_ST,
+
+	PMU_TCPD0_PWRDWN_ST,
+	PMU_TCPD1_PWRDWN_ST,
+	PMU_CCI_PWRDWN_ST,
+	PMU_PERILP_PWRDWN_ST,
+
+	PMU_PERIHP_PWRDWN_ST,
+	PMU_CENTER_PWRDWN_ST,
+	PMU_VIO_PWRDWN_ST,
+	PMU_GPU_PWRDWN_ST,
+
+	PMU_VCODEC_PWRDWN_ST,
+	PMU_VDU_PWRDWN_ST,
+	PMU_RGA_PWRDWN_ST,
+	PMU_IEP_PWRDWN_ST,
+
+	PMU_VO_PWRDWN_ST,
+	PMU_ISP0_PWRDWN_ST = 22,
+	PMU_ISP1_PWRDWN_ST,
+
+	PMU_HDCP_PWRDWN_ST,
+	PMU_GMAC_PWRDWN_ST,
+	PMU_EMMC_PWRDWN_ST,
+	PMU_USB3_PWRDWN_ST,
+
+	PMU_EDP_PWRDWN_ST,
+	PMU_GIC_PWRDWN_ST,
+	PMU_SD_PWRDWN_ST,
+	PMU_SDIOAUDIO_PWRDWN_ST,
+
+};
+
+enum pmu_pll_con {
+	PMU_PLL_PD_CFG = 0,
+	PMU_SFT_PLL_PD = 8,
+};
+
+enum pmu_pwermode_con {
+	PMU_PWR_MODE_EN = 0,
+	PMU_WKUP_RST_EN,
+	PMU_INPUT_CLAMP_EN,
+	PMU_OSC_DIS,
+
+	PMU_ALIVE_USE_LF,
+	PMU_PMU_USE_LF,
+	PMU_POWER_OFF_REQ_CFG,
+	PMU_CHIP_PD_EN,
+
+	PMU_PLL_PD_EN,
+	PMU_CPU0_PD_EN,
+	PMU_L2_FLUSH_EN,
+	PMU_L2_IDLE_EN,
+
+	PMU_SCU_PD_EN,
+	PMU_CCI_PD_EN,
+	PMU_PERILP_PD_EN,
+	PMU_CENTER_PD_EN,
+
+	PMU_SREF0_ENTER_EN,
+	PMU_DDRC0_GATING_EN,
+	PMU_DDRIO0_RET_EN,
+	PMU_DDRIO0_RET_DE_REQ,
+
+	PMU_SREF1_ENTER_EN,
+	PMU_DDRC1_GATING_EN,
+	PMU_DDRIO1_RET_EN,
+	PMU_DDRIO1_RET_DE_REQ,
+
+	PMU_CLK_CENTER_SRC_GATE_EN = 26,
+	PMU_CLK_PERILP_SRC_GATE_EN,
+
+	PMU_CLK_CORE_SRC_GATE_EN,
+	PMU_DDRIO_RET_HW_DE_REQ,
+	PMU_SLP_OUTPUT_CFG,
+	PMU_MAIN_CLUSTER,
+};
+
+enum pmu_sft_con {
+	PMU_WKUP_SFT = 0,
+	PMU_INPUT_CLAMP_CFG,
+	PMU_OSC_DIS_CFG,
+	PMU_PMU_LF_EN_CFG,
+
+	PMU_ALIVE_LF_EN_CFG,
+	PMU_24M_EN_CFG,
+	PMU_DBG_PWRUP_L0_CFG,
+	PMU_WKUP_SFT_M0,
+
+	PMU_DDRCTL0_C_SYSREQ_CFG,
+	PMU_DDR0_IO_RET_CFG,
+
+	PMU_DDRCTL1_C_SYSREQ_CFG = 12,
+	PMU_DDR1_IO_RET_CFG,
+	DBG_PWRUP_B0_CFG = 15,
+
+	DBG_NOPWERDWN_L0_EN,
+	DBG_NOPWERDWN_L1_EN,
+	DBG_NOPWERDWN_L2_EN,
+	DBG_NOPWERDWN_L3_EN,
+
+	DBG_PWRUP_REQ_L_EN = 20,
+	CLUSTER_L_CLK_SRC_GATING_CFG,
+	L2_FLUSH_REQ_CLUSTER_L,
+	ACINACTM_CLUSTER_L_CFG,
+
+	DBG_NO_PWERDWN_B0_EN,
+	DBG_NO_PWERDWN_B1_EN,
+
+	DBG_PWRUP_REQ_B_EN = 28,
+	CLUSTER_B_CLK_SRC_GATING_CFG,
+	L2_FLUSH_REQ_CLUSTER_B,
+	ACINACTM_CLUSTER_B_CFG,
+};
+
+enum pmu_int_con {
+	PMU_PMU_INT_EN = 0,
+	PMU_PWRMD_WKUP_INT_EN,
+	PMU_WKUP_GPIO0_NEG_INT_EN,
+	PMU_WKUP_GPIO0_POS_INT_EN,
+	PMU_WKUP_GPIO1_NEG_INT_EN,
+	PMU_WKUP_GPIO1_POS_INT_EN,
+};
+
+enum pmu_int_st {
+	PMU_PWRMD_WKUP_INT_ST = 1,
+	PMU_WKUP_GPIO0_NEG_INT_ST,
+	PMU_WKUP_GPIO0_POS_INT_ST,
+	PMU_WKUP_GPIO1_NEG_INT_ST,
+	PMU_WKUP_GPIO1_POS_INT_ST,
+};
+
+enum pmu_gpio0_pos_int_con {
+	PMU_GPIO0A_POS_INT_EN = 0,
+	PMU_GPIO0B_POS_INT_EN = 8,
+	PMU_GPIO0C_POS_INT_EN = 16,
+	PMU_GPIO0D_POS_INT_EN = 24,
+};
+
+enum pmu_gpio0_neg_int_con {
+	PMU_GPIO0A_NEG_INT_EN = 0,
+	PMU_GPIO0B_NEG_INT_EN = 8,
+	PMU_GPIO0C_NEG_INT_EN = 16,
+	PMU_GPIO0D_NEG_INT_EN = 24,
+};
+
+enum pmu_gpio1_pos_int_con {
+	PMU_GPIO1A_POS_INT_EN = 0,
+	PMU_GPIO1B_POS_INT_EN = 8,
+	PMU_GPIO1C_POS_INT_EN = 16,
+	PMU_GPIO1D_POS_INT_EN = 24,
+};
+
+enum pmu_gpio1_neg_int_con {
+	PMU_GPIO1A_NEG_INT_EN = 0,
+	PMU_GPIO1B_NEG_INT_EN = 8,
+	PMU_GPIO1C_NEG_INT_EN = 16,
+	PMU_GPIO1D_NEG_INT_EN = 24,
+};
+
+enum pmu_gpio0_pos_int_st {
+	PMU_GPIO0A_POS_INT_ST = 0,
+	PMU_GPIO0B_POS_INT_ST = 8,
+	PMU_GPIO0C_POS_INT_ST = 16,
+	PMU_GPIO0D_POS_INT_ST = 24,
+};
+
+enum pmu_gpio0_neg_int_st {
+	PMU_GPIO0A_NEG_INT_ST = 0,
+	PMU_GPIO0B_NEG_INT_ST = 8,
+	PMU_GPIO0C_NEG_INT_ST = 16,
+	PMU_GPIO0D_NEG_INT_ST = 24,
+};
+
+enum pmu_gpio1_pos_int_st {
+	PMU_GPIO1A_POS_INT_ST = 0,
+	PMU_GPIO1B_POS_INT_ST = 8,
+	PMU_GPIO1C_POS_INT_ST = 16,
+	PMU_GPIO1D_POS_INT_ST = 24,
+};
+
+enum pmu_gpio1_neg_int_st {
+	PMU_GPIO1A_NEG_INT_ST = 0,
+	PMU_GPIO1B_NEG_INT_ST = 8,
+	PMU_GPIO1C_NEG_INT_ST = 16,
+	PMU_GPIO1D_NEG_INT_ST = 24,
+};
+
+/* pmu power down configure register 0x0050 */
+enum pmu_pwrdn_inten {
+	PMU_A53_L0_PWR_SWITCH_INT_EN = 0,
+	PMU_A53_L1_PWR_SWITCH_INT_EN,
+	PMU_A53_L2_PWR_SWITCH_INT_EN,
+	PMU_A53_L3_PWR_SWITCH_INT_EN,
+
+	PMU_A72_B0_PWR_SWITCH_INT_EN,
+	PMU_A72_B1_PWR_SWITCH_INT_EN,
+	PMU_SCU_L_PWR_SWITCH_INT_EN,
+	PMU_SCU_B_PWR_SWITCH_INT_EN,
+
+	PMU_TCPD0_PWR_SWITCH_INT_EN,
+	PMU_TCPD1_PWR_SWITCH_INT_EN,
+	PMU_CCI_PWR_SWITCH_INT_EN,
+	PMU_PERILP_PWR_SWITCH_INT_EN,
+
+	PMU_PERIHP_PWR_SWITCH_INT_EN,
+	PMU_CENTER_PWR_SWITCH_INT_EN,
+	PMU_VIO_PWR_SWITCH_INT_EN,
+	PMU_GPU_PWR_SWITCH_INT_EN,
+
+	PMU_VCODEC_PWR_SWITCH_INT_EN,
+	PMU_VDU_PWR_SWITCH_INT_EN,
+	PMU_RGA_PWR_SWITCH_INT_EN,
+	PMU_IEP_PWR_SWITCH_INT_EN,
+
+	PMU_VO_PWR_SWITCH_INT_EN,
+	PMU_ISP0_PWR_SWITCH_INT_EN = 22,
+	PMU_ISP1_PWR_SWITCH_INT_EN,
+
+	PMU_HDCP_PWR_SWITCH_INT_EN,
+	PMU_GMAC_PWR_SWITCH_INT_EN,
+	PMU_EMMC_PWR_SWITCH_INT_EN,
+	PMU_USB3_PWR_SWITCH_INT_EN,
+
+	PMU_EDP_PWR_SWITCH_INT_EN,
+	PMU_GIC_PWR_SWITCH_INT_EN,
+	PMU_SD_PWR_SWITCH_INT_EN,
+	PMU_SDIOAUDIO_PWR_SWITCH_INT_EN,
+};
+
+enum pmu_wkup_status {
+	PMU_WKUP_BY_CLSTER_L_INT = 0,
+	PMU_WKUP_BY_CLSTER_b_INT,
+	PMU_WKUP_BY_GPIO_INT,
+	PMU_WKUP_BY_SDIO_DET,
+
+	PMU_WKUP_BY_SDMMC_DET,
+	PMU_WKUP_BY_TIMER = 6,
+	PMU_WKUP_BY_USBDEV_DET,
+
+	PMU_WKUP_BY_M0_SFT,
+	PMU_WKUP_BY_M0_WDT_INT,
+	PMU_WKUP_BY_TIMEOUT,
+	PMU_WKUP_BY_PWM,
+
+	PMU_WKUP_BY_PCIE = 13,
+};
+
+enum pmu_bus_clr {
+	PMU_CLR_GPU = 0,
+	PMU_CLR_PERILP,
+	PMU_CLR_PERIHP,
+	PMU_CLR_VCODEC,
+
+	PMU_CLR_VDU,
+	PMU_CLR_RGA,
+	PMU_CLR_IEP,
+	PMU_CLR_VOPB,
+
+	PMU_CLR_VOPL,
+	PMU_CLR_ISP0,
+	PMU_CLR_ISP1,
+	PMU_CLR_HDCP,
+
+	PMU_CLR_USB3,
+	PMU_CLR_PERILPM0,
+	PMU_CLR_CENTER,
+	PMU_CLR_CCIM1,
+
+	PMU_CLR_CCIM0,
+	PMU_CLR_VIO,
+	PMU_CLR_MSCH0,
+	PMU_CLR_MSCH1,
+
+	PMU_CLR_ALIVE,
+	PMU_CLR_PMU,
+	PMU_CLR_EDP,
+	PMU_CLR_GMAC,
+
+	PMU_CLR_EMMC,
+	PMU_CLR_CENTER1,
+	PMU_CLR_PMUM0,
+	PMU_CLR_GIC,
+
+	PMU_CLR_SD,
+	PMU_CLR_SDIOAUDIO,
+};
+
+/* PMU bus idle request register */
+enum pmu_bus_idle_req {
+	PMU_IDLE_REQ_GPU = 0,
+	PMU_IDLE_REQ_PERILP,
+	PMU_IDLE_REQ_PERIHP,
+	PMU_IDLE_REQ_VCODEC,
+
+	PMU_IDLE_REQ_VDU,
+	PMU_IDLE_REQ_RGA,
+	PMU_IDLE_REQ_IEP,
+	PMU_IDLE_REQ_VOPB,
+
+	PMU_IDLE_REQ_VOPL,
+	PMU_IDLE_REQ_ISP0,
+	PMU_IDLE_REQ_ISP1,
+	PMU_IDLE_REQ_HDCP,
+
+	PMU_IDLE_REQ_USB3,
+	PMU_IDLE_REQ_PERILPM0,
+	PMU_IDLE_REQ_CENTER,
+	PMU_IDLE_REQ_CCIM0,
+
+	PMU_IDLE_REQ_CCIM1,
+	PMU_IDLE_REQ_VIO,
+	PMU_IDLE_REQ_MSCH0,
+	PMU_IDLE_REQ_MSCH1,
+
+	PMU_IDLE_REQ_ALIVE,
+	PMU_IDLE_REQ_PMU,
+	PMU_IDLE_REQ_EDP,
+	PMU_IDLE_REQ_GMAC,
+
+	PMU_IDLE_REQ_EMMC,
+	PMU_IDLE_REQ_CENTER1,
+	PMU_IDLE_REQ_PMUM0,
+	PMU_IDLE_REQ_GIC,
+
+	PMU_IDLE_REQ_SD,
+	PMU_IDLE_REQ_SDIOAUDIO,
+};
+
+/* pmu bus idle status register */
+enum pmu_bus_idle_st {
+	PMU_IDLE_ST_GPU = 0,
+	PMU_IDLE_ST_PERILP,
+	PMU_IDLE_ST_PERIHP,
+	PMU_IDLE_ST_VCODEC,
+
+	PMU_IDLE_ST_VDU,
+	PMU_IDLE_ST_RGA,
+	PMU_IDLE_ST_IEP,
+	PMU_IDLE_ST_VOPB,
+
+	PMU_IDLE_ST_VOPL,
+	PMU_IDLE_ST_ISP0,
+	PMU_IDLE_ST_ISP1,
+	PMU_IDLE_ST_HDCP,
+
+	PMU_IDLE_ST_USB3,
+	PMU_IDLE_ST_PERILPM0,
+	PMU_IDLE_ST_CENTER,
+	PMU_IDLE_ST_CCIM0,
+
+	PMU_IDLE_ST_CCIM1,
+	PMU_IDLE_ST_VIO,
+	PMU_IDLE_ST_MSCH0,
+	PMU_IDLE_ST_MSCH1,
+
+	PMU_IDLE_ST_ALIVE,
+	PMU_IDLE_ST_PMU,
+	PMU_IDLE_ST_EDP,
+	PMU_IDLE_ST_GMAC,
+
+	PMU_IDLE_ST_EMMC,
+	PMU_IDLE_ST_CENTER1,
+	PMU_IDLE_ST_PMUM0,
+	PMU_IDLE_ST_GIC,
+
+	PMU_IDLE_ST_SD,
+	PMU_IDLE_ST_SDIOAUDIO,
+};
+
+enum pmu_bus_idle_ack {
+	PMU_IDLE_ACK_GPU = 0,
+	PMU_IDLE_ACK_PERILP,
+	PMU_IDLE_ACK_PERIHP,
+	PMU_IDLE_ACK_VCODEC,
+
+	PMU_IDLE_ACK_VDU,
+	PMU_IDLE_ACK_RGA,
+	PMU_IDLE_ACK_IEP,
+	PMU_IDLE_ACK_VOPB,
+
+	PMU_IDLE_ACK_VOPL,
+	PMU_IDLE_ACK_ISP0,
+	PMU_IDLE_ACK_ISP1,
+	PMU_IDLE_ACK_HDCP,
+
+	PMU_IDLE_ACK_USB3,
+	PMU_IDLE_ACK_PERILPM0,
+	PMU_IDLE_ACK_CENTER,
+	PMU_IDLE_ACK_CCIM0,
+
+	PMU_IDLE_ACK_CCIM1,
+	PMU_IDLE_ACK_VIO,
+	PMU_IDLE_ACK_MSCH0,
+	PMU_IDLE_ACK_MSCH1,
+
+	PMU_IDLE_ACK_ALIVE,
+	PMU_IDLE_ACK_PMU,
+	PMU_IDLE_ACK_EDP,
+	PMU_IDLE_ACK_GMAC,
+
+	PMU_IDLE_ACK_EMMC,
+	PMU_IDLE_ACK_CENTER1,
+	PMU_IDLE_ACK_PMUM0,
+	PMU_IDLE_ACK_GIC,
+
+	PMU_IDLE_ACK_SD,
+	PMU_IDLE_ACK_SDIOAUDIO,
+};
+
+enum pmu_cci500_con {
+	PMU_PREQ_CCI500_CFG_SW = 0,
+	PMU_CLR_PREQ_CCI500_HW,
+	PMU_PSTATE_CCI500_0,
+	PMU_PSTATE_CCI500_1,
+
+	PMU_PSTATE_CCI500_2,
+	PMU_QREQ_CCI500_CFG_SW,
+	PMU_CLR_QREQ_CCI500_HW,
+	PMU_QGATING_CCI500_CFG,
+
+	PMU_PREQ_CCI500_CFG_SW_WMSK = 16,
+	PMU_CLR_PREQ_CCI500_HW_WMSK,
+	PMU_PSTATE_CCI500_0_WMSK,
+	PMU_PSTATE_CCI500_1_WMSK,
+
+	PMU_PSTATE_CCI500_2_WMSK,
+	PMU_QREQ_CCI500_CFG_SW_WMSK,
+	PMU_CLR_QREQ_CCI500_HW_WMSK,
+	PMU_QGATING_CCI500_CFG_WMSK,
+};
+
+enum pmu_adb400_con {
+	PMU_PWRDWN_REQ_CXCS_SW = 0,
+	PMU_PWRDWN_REQ_CORE_L_SW,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW,
+
+	PMU_PWRDWN_REQ_CORE_B_SW,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW,
+
+	PMU_CLR_CXCS_HW = 8,
+	PMU_CLR_CORE_L_HW,
+	PMU_CLR_CORE_L_2GIC_HW,
+	PMU_CLR_GIC2_CORE_L_HW,
+
+	PMU_CLR_CORE_B_HW,
+	PMU_CLR_CORE_B_2GIC_HW,
+	PMU_CLR_GIC2_CORE_B_HW,
+
+	PMU_PWRDWN_REQ_CXCS_SW_WMSK = 16,
+	PMU_PWRDWN_REQ_CORE_L_SW_WMSK,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_WMSK,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_WMSK,
+
+	PMU_PWRDWN_REQ_CORE_B_SW_WMSK,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_WMSK,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_WMSK,
+
+	PMU_CLR_CXCS_HW_WMSK = 24,
+	PMU_CLR_CORE_L_HW_WMSK,
+	PMU_CLR_CORE_L_2GIC_HW_WMSK,
+	PMU_CLR_GIC2_CORE_L_HW_WMSK,
+
+	PMU_CLR_CORE_B_HW_WMSK,
+	PMU_CLR_CORE_B_2GIC_HW_WMSK,
+	PMU_CLR_GIC2_CORE_B_HW_WMSK,
+};
+
+enum pmu_adb400_st {
+	PMU_PWRDWN_REQ_CXCS_SW_ST = 0,
+	PMU_PWRDWN_REQ_CORE_L_SW_ST,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_ST,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_ST,
+
+	PMU_PWRDWN_REQ_CORE_B_SW_ST,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST,
+
+	PMU_CLR_CXCS_HW_ST = 8,
+	PMU_CLR_CORE_L_HW_ST,
+	PMU_CLR_CORE_L_2GIC_HW_ST,
+	PMU_CLR_GIC2_CORE_L_HW_ST,
+
+	PMU_CLR_CORE_B_HW_ST,
+	PMU_CLR_CORE_B_2GIC_HW_ST,
+	PMU_CLR_GIC2_CORE_B_HW_ST,
+};
+
+enum pmu_pwrdn_con1 {
+	PMU_VD_SCU_L_PWRDN_EN = 0,
+	PMU_VD_SCU_B_PWRDN_EN,
+	PMU_VD_CENTER_PWRDN_EN,
+};
+
+enum pmu_core_pwr_st {
+	L2_FLUSHDONE_CLUSTER_L = 0,
+	STANDBY_BY_WFIL2_CLUSTER_L,
+
+	L2_FLUSHDONE_CLUSTER_B = 10,
+	STANDBY_BY_WFIL2_CLUSTER_B,
+};
+
+#endif /* PMU_BITS_H */
diff --git a/plat/rockchip/rk3399/include/shared/pmu_regs.h b/plat/rockchip/rk3399/include/shared/pmu_regs.h
new file mode 100644
index 0000000..43e785e
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/pmu_regs.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMU_REGS_H
+#define PMU_REGS_H
+
+#define PMU_WKUP_CFG0		0x00
+#define PMU_WKUP_CFG1		0x04
+#define PMU_WKUP_CFG2		0x08
+#define PMU_WKUP_CFG3		0x0c
+#define PMU_WKUP_CFG4		0x10
+#define PMU_PWRDN_CON		0x14
+#define PMU_PWRDN_ST		0x18
+#define PMU_PLL_CON		0x1c
+#define PMU_PWRMODE_CON		0x20
+#define PMU_SFT_CON		0x24
+#define PMU_INT_CON		0x28
+#define PMU_INT_ST		0x2c
+#define PMU_GPIO0_POS_INT_CON	0x30
+#define PMU_GPIO0_NEG_INT_CON	0x34
+#define PMU_GPIO1_POS_INT_CON	0x38
+#define PMU_GPIO1_NEG_INT_CON	0x3c
+#define PMU_GPIO0_POS_INT_ST	0x40
+#define PMU_GPIO0_NEG_INT_ST	0x44
+#define PMU_GPIO1_POS_INT_ST	0x48
+#define PMU_GPIO1_NEG_INT_ST	0x4c
+#define PMU_PWRDN_INTEN		0x50
+#define PMU_PWRDN_STATUS	0x54
+#define PMU_WAKEUP_STATUS	0x58
+#define PMU_BUS_CLR		0x5c
+#define PMU_BUS_IDLE_REQ	0x60
+#define PMU_BUS_IDLE_ST		0x64
+#define PMU_BUS_IDLE_ACK	0x68
+#define PMU_CCI500_CON		0x6c
+#define PMU_ADB400_CON		0x70
+#define PMU_ADB400_ST		0x74
+#define PMU_POWER_ST		0x78
+#define PMU_CORE_PWR_ST		0x7c
+#define PMU_OSC_CNT		0x80
+#define PMU_PLLLOCK_CNT		0x84
+#define PMU_PLLRST_CNT		0x88
+#define PMU_STABLE_CNT		0x8c
+#define PMU_DDRIO_PWRON_CNT	0x90
+#define PMU_WAKEUP_RST_CLR_CNT	0x94
+#define PMU_DDR_SREF_ST		0x98
+#define PMU_SCU_L_PWRDN_CNT	0x9c
+#define PMU_SCU_L_PWRUP_CNT	0xa0
+#define PMU_SCU_B_PWRDN_CNT	0xa4
+#define PMU_SCU_B_PWRUP_CNT	0xa8
+#define PMU_GPU_PWRDN_CNT	0xac
+#define PMU_GPU_PWRUP_CNT	0xb0
+#define PMU_CENTER_PWRDN_CNT	0xb4
+#define PMU_CENTER_PWRUP_CNT	0xb8
+#define PMU_TIMEOUT_CNT		0xbc
+#define PMU_CPU0APM_CON		0xc0
+#define PMU_CPU1APM_CON		0xc4
+#define PMU_CPU2APM_CON		0xc8
+#define PMU_CPU3APM_CON		0xcc
+#define PMU_CPU0BPM_CON		0xd0
+#define PMU_CPU1BPM_CON		0xd4
+#define PMU_NOC_AUTO_ENA	0xd8
+#define PMU_PWRDN_CON1		0xdc
+
+#define PMUGRF_GPIO0A_IOMUX	0x00
+#define PMUGRF_GPIO1A_IOMUX	0x10
+#define PMUGRF_GPIO1C_IOMUX	0x18
+
+#define PMUGRF_GPIO0A6_IOMUX_SHIFT      12
+#define PMUGRF_GPIO0A6_IOMUX_PWM        0x1
+#define PMUGRF_GPIO1C3_IOMUX_SHIFT      6
+#define PMUGRF_GPIO1C3_IOMUX_PWM        0x1
+
+#define CPU_AXI_QOS_ID_COREID		0x00
+#define CPU_AXI_QOS_REVISIONID		0x04
+#define CPU_AXI_QOS_PRIORITY		0x08
+#define CPU_AXI_QOS_MODE		0x0c
+#define CPU_AXI_QOS_BANDWIDTH		0x10
+#define CPU_AXI_QOS_SATURATION		0x14
+#define CPU_AXI_QOS_EXTCONTROL		0x18
+#define CPU_AXI_QOS_NUM_REGS		0x07
+
+#define CPU_AXI_CCI_M0_QOS_BASE		0xffa50000
+#define CPU_AXI_CCI_M1_QOS_BASE		0xffad8000
+#define CPU_AXI_DMAC0_QOS_BASE		0xffa64200
+#define CPU_AXI_DMAC1_QOS_BASE		0xffa64280
+#define CPU_AXI_DCF_QOS_BASE		0xffa64180
+#define CPU_AXI_CRYPTO0_QOS_BASE	0xffa64100
+#define CPU_AXI_CRYPTO1_QOS_BASE	0xffa64080
+#define CPU_AXI_PMU_CM0_QOS_BASE	0xffa68000
+#define CPU_AXI_PERI_CM1_QOS_BASE	0xffa64300
+#define CPU_AXI_GIC_QOS_BASE		0xffa78000
+#define CPU_AXI_SDIO_QOS_BASE		0xffa76000
+#define CPU_AXI_SDMMC_QOS_BASE		0xffa74000
+#define CPU_AXI_EMMC_QOS_BASE		0xffa58000
+#define CPU_AXI_GMAC_QOS_BASE		0xffa5c000
+#define CPU_AXI_USB_OTG0_QOS_BASE	0xffa70000
+#define CPU_AXI_USB_OTG1_QOS_BASE	0xffa70080
+#define CPU_AXI_USB_HOST0_QOS_BASE	0xffa60100
+#define CPU_AXI_USB_HOST1_QOS_BASE	0xffa60180
+#define CPU_AXI_GPU_QOS_BASE		0xffae0000
+#define CPU_AXI_VIDEO_M0_QOS_BASE	0xffab8000
+#define CPU_AXI_VIDEO_M1_R_QOS_BASE	0xffac0000
+#define CPU_AXI_VIDEO_M1_W_QOS_BASE	0xffac0080
+#define CPU_AXI_RGA_R_QOS_BASE		0xffab0000
+#define CPU_AXI_RGA_W_QOS_BASE		0xffab0080
+#define CPU_AXI_IEP_QOS_BASE		0xffa98000
+#define CPU_AXI_VOP_BIG_R_QOS_BASE	0xffac8000
+#define CPU_AXI_VOP_BIG_W_QOS_BASE	0xffac8080
+#define CPU_AXI_VOP_LITTLE_QOS_BASE	0xffad0000
+#define CPU_AXI_ISP0_M0_QOS_BASE	0xffaa0000
+#define CPU_AXI_ISP0_M1_QOS_BASE	0xffaa0080
+#define CPU_AXI_ISP1_M0_QOS_BASE	0xffaa8000
+#define CPU_AXI_ISP1_M1_QOS_BASE	0xffaa8080
+#define CPU_AXI_HDCP_QOS_BASE		0xffa90000
+#define CPU_AXI_PERIHP_NSP_QOS_BASE	0xffad8080
+#define CPU_AXI_PERILP_NSP_QOS_BASE	0xffad8180
+#define CPU_AXI_PERILPSLV_NSP_QOS_BASE	0xffad8100
+
+#define GRF_GPIO2A_IOMUX	0xe000
+#define GRF_GPIO2B_IOMUX	0xe004
+#define GRF_GPIO2C_IOMUX	0xe008
+#define GRF_GPIO2D_IOMUX	0xe00c
+#define GRF_GPIO3A_IOMUX	0xe010
+#define GRF_GPIO3B_IOMUX	0xe014
+#define GRF_GPIO3C_IOMUX	0xe018
+#define GRF_GPIO3D_IOMUX	0xe01c
+#define GRF_GPIO4A_IOMUX	0xe020
+#define GRF_GPIO4B_IOMUX	0xe024
+#define GRF_GPIO4C_IOMUX	0xe028
+#define GRF_GPIO4D_IOMUX	0xe02c
+
+#define GRF_GPIO2A_P		0xe040
+#define GRF_GPIO2B_P		0xe044
+#define GRF_GPIO2C_P		0xe048
+#define GRF_GPIO2D_P		0xe04C
+#define GRF_GPIO3A_P		0xe050
+#define GRF_GPIO3B_P		0xe054
+#define GRF_GPIO3C_P		0xe058
+#define GRF_GPIO3D_P		0xe05C
+#define GRF_GPIO4A_P		0xe060
+#define GRF_GPIO4B_P		0xe064
+#define GRF_GPIO4C_P		0xe068
+#define GRF_GPIO4D_P		0xe06C
+
+#endif /* PMU_REGS_H */
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
new file mode 100644
index 0000000..c2cc5b1
--- /dev/null
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+
+#include <cdn_dp.h>
+#include <dfs.h>
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+
+#define RK_SIP_DDR_CFG		0x82000008
+#define DRAM_INIT		0x00
+#define DRAM_SET_RATE		0x01
+#define DRAM_ROUND_RATE		0x02
+#define DRAM_SET_AT_SR		0x03
+#define DRAM_GET_BW		0x04
+#define DRAM_GET_RATE		0x05
+#define DRAM_CLR_IRQ		0x06
+#define DRAM_SET_PARAM		0x07
+#define DRAM_SET_ODT_PD		0x08
+
+#define RK_SIP_HDCP_CONTROL	0x82000009
+#define RK_SIP_HDCP_KEY_DATA64	0xC200000A
+
+uint32_t ddr_smc_handler(uint64_t arg0, uint64_t arg1,
+			 uint64_t id, uint64_t arg2)
+{
+	switch (id) {
+	case DRAM_SET_RATE:
+		return ddr_set_rate((uint32_t)arg0);
+	case DRAM_ROUND_RATE:
+		return ddr_round_rate((uint32_t)arg0);
+	case DRAM_GET_RATE:
+		return ddr_get_rate();
+	case DRAM_SET_ODT_PD:
+		dram_set_odt_pd(arg0, arg1, arg2);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+				    u_register_t x1,
+				    u_register_t x2,
+				    u_register_t x3,
+				    u_register_t x4,
+				    void *cookie,
+				    void *handle,
+				    u_register_t flags)
+{
+	uint64_t x5, x6;
+
+	switch (smc_fid) {
+	case RK_SIP_DDR_CFG:
+		SMC_RET1(handle, ddr_smc_handler(x1, x2, x3, x4));
+	case RK_SIP_HDCP_CONTROL:
+		SMC_RET1(handle, dp_hdcp_ctrl(x1));
+	case RK_SIP_HDCP_KEY_DATA64:
+		x5 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X5);
+		x6 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X6);
+		SMC_RET1(handle, dp_hdcp_store_key(x1, x2, x3, x4, x5, x6));
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
new file mode 100644
index 0000000..88fa8e9
--- /dev/null
+++ b/plat/rockchip/rk3399/platform.mk
@@ -0,0 +1,106 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RK_PLAT		:=	plat/rockchip
+RK_PLAT_SOC	:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON	:=	${RK_PLAT}/common
+
+DISABLE_BIN_GENERATION	:=	1
+
+PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/			\
+				-I${RK_PLAT_COMMON}/include/		\
+				-I${RK_PLAT_COMMON}/aarch64/		\
+				-I${RK_PLAT_COMMON}/drivers/pmu/	\
+				-I${RK_PLAT_SOC}/			\
+				-I${RK_PLAT_SOC}/drivers/pmu/		\
+				-I${RK_PLAT_SOC}/drivers/pwm/		\
+				-I${RK_PLAT_SOC}/drivers/secure/	\
+				-I${RK_PLAT_SOC}/drivers/soc/		\
+				-I${RK_PLAT_SOC}/drivers/dram/		\
+				-I${RK_PLAT_SOC}/drivers/dp/		\
+				-I${RK_PLAT_SOC}/include/		\
+				-I${RK_PLAT_SOC}/include/shared/	\
+
+RK_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c	\
+				drivers/arm/gic/v3/gic500.c		\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				${RK_PLAT}/common/rockchip_gicv3.c
+
+PLAT_BL_COMMON_SOURCES	:=	lib/bl_aux_params/bl_aux_params.c	\
+				lib/xlat_tables/xlat_tables_common.c	\
+				lib/xlat_tables/aarch64/xlat_tables.c	\
+				plat/common/aarch64/crash_console_helpers.S \
+				plat/common/plat_psci_common.c
+
+BL31_SOURCES	+=	${RK_GIC_SOURCES}				\
+			drivers/arm/cci/cci.c				\
+			drivers/ti/uart/aarch64/16550_console.S		\
+			drivers/delay_timer/delay_timer.c		\
+			drivers/delay_timer/generic_delay_timer.c	\
+			drivers/gpio/gpio.c				\
+			lib/cpus/aarch64/cortex_a53.S			\
+			lib/cpus/aarch64/cortex_a72.S			\
+			${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+			${RK_PLAT_COMMON}/bl31_plat_setup.c		\
+			${RK_PLAT_COMMON}/params_setup.c		\
+			${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S	\
+			${RK_PLAT_COMMON}/plat_pm.c			\
+			${RK_PLAT_COMMON}/plat_topology.c		\
+			${RK_PLAT_COMMON}/aarch64/platform_common.c	\
+			${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+			${RK_PLAT_SOC}/plat_sip_calls.c			\
+			${RK_PLAT_SOC}/drivers/dp/cdn_dp.c		\
+			${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c	\
+			${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+			${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c		\
+			${RK_PLAT_SOC}/drivers/pmu/m0_ctl.c		\
+			${RK_PLAT_SOC}/drivers/pwm/pwm.c		\
+			${RK_PLAT_SOC}/drivers/secure/secure.c		\
+			${RK_PLAT_SOC}/drivers/soc/soc.c		\
+			${RK_PLAT_SOC}/drivers/dram/dfs.c		\
+			${RK_PLAT_SOC}/drivers/dram/dram.c		\
+			${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c	\
+			${RK_PLAT_SOC}/drivers/dram/suspend.c
+
+include lib/coreboot/coreboot.mk
+include lib/libfdt/libfdt.mk
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_855873	:=	1
+
+# M0 source build
+PLAT_M0                 :=      ${PLAT}m0
+BUILD_M0		:=	${BUILD_PLAT}/m0
+
+RK3399M0FW=${BUILD_M0}/${PLAT_M0}.bin
+$(eval $(call add_define,RK3399M0FW))
+
+RK3399M0PMUFW=${BUILD_M0}/${PLAT_M0}pmu.bin
+$(eval $(call add_define,RK3399M0PMUFW))
+
+HDCPFW=${RK_PLAT_SOC}/drivers/dp/hdcp.bin
+$(eval $(call add_define,HDCPFW))
+
+# CCACHE_EXTRAFILES is needed because ccache doesn't handle .incbin
+export CCACHE_EXTRAFILES
+${BUILD_PLAT}/bl31/pmu_fw.o: CCACHE_EXTRAFILES=$(RK3399M0FW):$(RK3399M0PMUFW)
+${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c: $(RK3399M0FW)
+
+${BUILD_PLAT}/bl31/cdn_dp.o: CCACHE_EXTRAFILES=$(HDCPFW)
+${RK_PLAT_SOC}/drivers/dp/cdn_dp.c: $(HDCPFW)
+
+$(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},${BUILD_PLAT}))
+.PHONY: $(RK3399M0FW)
+$(RK3399M0FW): | ${BUILD_M0}
+	$(MAKE) -C ${RK_PLAT_SOC}/drivers/m0 BUILD=$(abspath ${BUILD_PLAT}/m0)
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:=	0
diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h
new file mode 100644
index 0000000..ba83242
--- /dev/null
+++ b/plat/rockchip/rk3399/rk3399_def.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RK3399_DEF_H
+#define RK3399_DEF_H
+
+#include <addressmap.h>
+
+#define RK3399_PRIMARY_CPU		0x0
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define RK_BL31_PLAT_PARAM_VAL		0x0f1e2d3c4b5a6978ULL
+
+/**************************************************************************
+ * UART related constants
+ **************************************************************************/
+#define RK3399_BAUDRATE			115200
+#define RK3399_UART_CLOCK		24000000
+
+/******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	24000000
+
+/* Base rockchip_platform compatible GIC memory map */
+#define BASE_GICD_BASE			(GIC500_BASE)
+#define BASE_GICR_BASE			(GIC500_BASE + SIZE_M(1))
+
+/*****************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX	0
+#define PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX	1
+
+/******************************************************************************
+ * sgi, ppi
+ ******************************************************************************/
+#define ARM_IRQ_SEC_PHY_TIMER		29
+
+#define ARM_IRQ_SEC_SGI_0		8
+#define ARM_IRQ_SEC_SGI_1		9
+#define ARM_IRQ_SEC_SGI_2		10
+#define ARM_IRQ_SEC_SGI_3		11
+#define ARM_IRQ_SEC_SGI_4		12
+#define ARM_IRQ_SEC_SGI_5		13
+#define ARM_IRQ_SEC_SGI_6		14
+#define ARM_IRQ_SEC_SGI_7		15
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_RK_GICV3_G1S_IRQS						\
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
+		       INTR_GROUP1S, GIC_INTR_CFG_LEVEL)
+
+#define PLAT_RK_GICV3_G0_IRQS						\
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
+		       INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+
+#endif /* RK3399_DEF_H */
diff --git a/plat/rpi3/aarch64/plat_helpers.S b/plat/rpi3/aarch64/plat_helpers.S
new file mode 100644
index 0000000..7974b60
--- /dev/null
+++ b/plat/rpi3/aarch64/plat_helpers.S
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+#include "../rpi3_hw.h"
+
+	.globl	plat_crash_console_flush
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	platform_mem_init
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_rpi3_calc_core_pos
+	.globl	plat_secondary_cold_boot_setup
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *
+	 *  This function uses the plat_rpi3_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_rpi3_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
+	 *
+	 *  CorePos = (ClusterId * 4) + CoreId
+	 * -----------------------------------------------------
+	 */
+func plat_rpi3_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_rpi3_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #RPI3_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Calculate address of our hold entry */
+	bl	plat_my_core_pos
+	lsl	x0, x0, #3
+	mov_imm	x2, PLAT_RPI3_TM_HOLD_BASE
+	add	x0, x0, x2
+
+	/*
+	 * This code runs way before requesting the warmboot of this core,
+	 * so it is possible to clear the mailbox before getting a request
+	 * to boot.
+	 */
+	mov	x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
+	str	x1,[x0]
+
+	/* Wait until we have a go */
+poll_mailbox:
+	wfe
+	ldr	x1, [x0]
+	cmp	x1, PLAT_RPI3_TM_HOLD_STATE_GO
+	bne	poll_mailbox
+
+	/* Jump to the provided entrypoint */
+	mov_imm	x0, PLAT_RPI3_TM_ENTRYPOINT
+	ldr	x1, [x0]
+	br	x1
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and a warm
+	 * boot.
+	 *
+	 * This functions returns:
+	 *  - 0 for a cold boot.
+	 *  - Any other value for a warm boot.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* TODO: support warm boot */
+	mov	x0, #0
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* ---------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * No need to carry out any memory initialization.
+	 * ---------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x3
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, PLAT_RPI3_UART_BASE
+	mov_imm	x1, PLAT_RPI3_UART_CLK_IN_HZ
+	mov_imm	x2, PLAT_RPI3_UART_BAUDRATE
+	b	console_16550_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, PLAT_RPI3_UART_BASE
+	b	console_16550_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, PLAT_RPI3_UART_BASE
+	b	console_16550_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------
+	 * void plat_reset_handler(void);
+	 * ---------------------------------------------
+	 */
+func plat_reset_handler
+	/* use the 19.2 MHz clock for the architected timer */
+	mov	x0, #RPI3_INTC_BASE_ADDRESS
+	mov	w1, #0x80000000
+	str	wzr, [x0, #RPI3_INTC_CONTROL_OFFSET]
+	str	w1, [x0, #RPI3_INTC_PRESCALER_OFFSET]
+	ret
+endfunc plat_reset_handler
diff --git a/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c b/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
new file mode 100644
index 0000000..715aec4
--- /dev/null
+++ b/plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+
+	/* Fill BL31 related information */
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.pc = BL31_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+		.ep_info.args.arg1 = RPI3_BL31_PLAT_PARAM_VAL,
+#endif
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_PLAT_SETUP),
+		.image_info.image_base = BL31_BASE,
+		.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+		.next_handoff_image_id = BL32_IMAGE_ID,
+# else
+		.next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+	},
+
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE),
+		.ep_info.pc = BL32_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL32_BASE,
+		.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the pager
+	 * image.
+	 */
+	{
+		.image_id = BL32_EXTRA1_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+		.image_info.image_base = BL32_BASE,
+		.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the paged
+	 * image.
+	 */
+	{
+		.image_id = BL32_EXTRA2_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+#ifdef SPD_opteed
+		.image_info.image_base = RPI3_OPTEE_PAGEABLE_LOAD_BASE,
+		.image_info.image_max_size = RPI3_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+	{
+		.image_id = BL33_IMAGE_ID,
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+		.ep_info.pc = PRELOADED_BL33_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+# else
+		.ep_info.pc = PLAT_RPI3_NS_IMAGE_OFFSET,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = PLAT_RPI3_NS_IMAGE_OFFSET,
+		.image_info.image_max_size = PLAT_RPI3_NS_IMAGE_MAX_SIZE,
+# endif /* PRELOADED_BL33_BASE */
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/rpi3/include/plat_macros.S b/plat/rpi3/include/plat_macros.S
new file mode 100644
index 0000000..c0c3967
--- /dev/null
+++ b/plat/rpi3/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant platform registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/rpi3/include/platform_def.h b/plat/rpi3/include/platform_def.h
new file mode 100644
index 0000000..4d90222
--- /dev/null
+++ b/plat/rpi3/include/platform_def.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include "../rpi3_hw.h"
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define RPI3_BL31_PLAT_PARAM_VAL	ULL(0x0F1E2D3C4B5A6978)
+
+#define PLATFORM_STACK_SIZE		ULL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define RPI3_PRIMARY_CPU		U(0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF		U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		U(4)
+#define PLAT_LOCAL_PSTATE_MASK		((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and
+ * secure DRAM. Note that this is all actually DRAM with different names,
+ * there is no Secure RAM in the Raspberry Pi 3.
+ */
+#if RPI3_USE_UEFI_MAP
+#define SEC_ROM_BASE			ULL(0x00000000)
+#define SEC_ROM_SIZE			ULL(0x00010000)
+
+/* FIP placed after ROM to append it to BL1 with very little padding. */
+#define PLAT_RPI3_FIP_BASE		ULL(0x00020000)
+#define PLAT_RPI3_FIP_MAX_SIZE		ULL(0x00010000)
+
+/* Reserve 2M of secure SRAM and DRAM, starting at 2M */
+#define SEC_SRAM_BASE			ULL(0x00200000)
+#define SEC_SRAM_SIZE			ULL(0x00100000)
+
+#define SEC_DRAM0_BASE			ULL(0x00300000)
+#define SEC_DRAM0_SIZE			ULL(0x00100000)
+
+/* Windows on ARM requires some RAM at 4M */
+#define NS_DRAM0_BASE			ULL(0x00400000)
+#define NS_DRAM0_SIZE			ULL(0x00C00000)
+#else
+#define SEC_ROM_BASE			ULL(0x00000000)
+#define SEC_ROM_SIZE			ULL(0x00020000)
+
+/* FIP placed after ROM to append it to BL1 with very little padding. */
+#define PLAT_RPI3_FIP_BASE		ULL(0x00020000)
+#define PLAT_RPI3_FIP_MAX_SIZE		ULL(0x001E0000)
+
+/* We have 16M of memory reserved starting at 256M */
+#define SEC_SRAM_BASE			ULL(0x10000000)
+#define SEC_SRAM_SIZE			ULL(0x00100000)
+
+#define SEC_DRAM0_BASE			ULL(0x10100000)
+#define SEC_DRAM0_SIZE			ULL(0x00F00000)
+/* End of reserved memory */
+
+#define NS_DRAM0_BASE			ULL(0x11000000)
+#define NS_DRAM0_SIZE			ULL(0x01000000)
+#endif /* RPI3_USE_UEFI_MAP */
+
+/*
+ * BL33 entrypoint.
+ */
+#define PLAT_RPI3_NS_IMAGE_OFFSET	NS_DRAM0_BASE
+#define PLAT_RPI3_NS_IMAGE_MAX_SIZE	NS_DRAM0_SIZE
+
+/*
+ * I/O registers.
+ */
+#define DEVICE0_BASE			RPI3_IO_BASE
+#define DEVICE0_SIZE			RPI3_IO_SIZE
+
+/*
+ * Arm TF lives in SRAM, partition it here
+ */
+#define SHARED_RAM_BASE			SEC_SRAM_BASE
+#define SHARED_RAM_SIZE			ULL(0x00001000)
+
+#define BL_RAM_BASE			(SHARED_RAM_BASE + SHARED_RAM_SIZE)
+#define BL_RAM_SIZE			(SEC_SRAM_SIZE - SHARED_RAM_SIZE)
+
+/*
+ * Mailbox to control the secondary cores.All secondary cores are held in a wait
+ * loop in cold boot. To release them perform the following steps (plus any
+ * additional barriers that may be needed):
+ *
+ *     uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT;
+ *     *entrypoint = ADDRESS_TO_JUMP_TO;
+ *
+ *     uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+ *     mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO;
+ *
+ *     sev();
+ */
+#define PLAT_RPI3_TRUSTED_MAILBOX_BASE	SHARED_RAM_BASE
+
+/* The secure entry point to be used on warm reset by all CPUs. */
+#define PLAT_RPI3_TM_ENTRYPOINT		PLAT_RPI3_TRUSTED_MAILBOX_BASE
+#define PLAT_RPI3_TM_ENTRYPOINT_SIZE	ULL(8)
+
+/* Hold entries for each CPU. */
+#define PLAT_RPI3_TM_HOLD_BASE		(PLAT_RPI3_TM_ENTRYPOINT + \
+					 PLAT_RPI3_TM_ENTRYPOINT_SIZE)
+#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE	ULL(8)
+#define PLAT_RPI3_TM_HOLD_SIZE		(PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE	(PLAT_RPI3_TM_ENTRYPOINT_SIZE + \
+					 PLAT_RPI3_TM_HOLD_SIZE)
+
+#define PLAT_RPI3_TM_HOLD_STATE_WAIT	ULL(0)
+#define PLAT_RPI3_TM_HOLD_STATE_GO	ULL(1)
+
+/*
+ * BL1 specific defines.
+ *
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ *
+ * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using
+ * the current BL1 RW debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL1_RW_SIZE		ULL(0x12000)
+
+#define BL1_RO_BASE			SEC_ROM_BASE
+#define BL1_RO_LIMIT			(SEC_ROM_BASE + SEC_ROM_SIZE)
+#define BL1_RW_BASE			(BL1_RW_LIMIT - PLAT_MAX_BL1_RW_SIZE)
+#define BL1_RW_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+
+/*
+ * BL2 specific defines.
+ *
+ * Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define PLAT_MAX_BL2_SIZE		ULL(0x2C000)
+
+#define BL2_BASE			(BL2_LIMIT - PLAT_MAX_BL2_SIZE)
+#define BL2_LIMIT			BL31_BASE
+
+/*
+ * BL31 specific defines.
+ *
+ * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL31_SIZE		ULL(0x20000)
+
+#define BL31_BASE			(BL31_LIMIT - PLAT_MAX_BL31_SIZE)
+#define BL31_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+#define BL31_PROGBITS_LIMIT		BL1_RW_BASE
+
+/*
+ * BL32 specific defines.
+ *
+ * BL32 can execute from Secure SRAM or Secure DRAM.
+ */
+#define BL32_SRAM_BASE			BL_RAM_BASE
+#define BL32_SRAM_LIMIT			BL31_BASE
+#define BL32_DRAM_BASE			SEC_DRAM0_BASE
+#define BL32_DRAM_LIMIT			(SEC_DRAM0_BASE + SEC_DRAM0_SIZE)
+
+#ifdef SPD_opteed
+/* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */
+#define RPI3_OPTEE_PAGEABLE_LOAD_SIZE	0x080000 /* 512KB */
+#define RPI3_OPTEE_PAGEABLE_LOAD_BASE	(BL32_DRAM_LIMIT - \
+					 RPI3_OPTEE_PAGEABLE_LOAD_SIZE)
+#endif
+
+#define SEC_SRAM_ID			0
+#define SEC_DRAM_ID			1
+
+#if RPI3_BL32_RAM_LOCATION_ID == SEC_SRAM_ID
+# define BL32_MEM_BASE			BL_RAM_BASE
+# define BL32_MEM_SIZE			BL_RAM_SIZE
+# define BL32_BASE			BL32_SRAM_BASE
+# define BL32_LIMIT			BL32_SRAM_LIMIT
+#elif RPI3_BL32_RAM_LOCATION_ID == SEC_DRAM_ID
+# define BL32_MEM_BASE			SEC_DRAM0_BASE
+# define BL32_MEM_SIZE			SEC_DRAM0_SIZE
+# define BL32_BASE			BL32_DRAM_BASE
+# define BL32_LIMIT			BL32_DRAM_LIMIT
+#else
+# error "Unsupported RPI3_BL32_RAM_LOCATION_ID value"
+#endif
+#define BL32_SIZE			(BL32_LIMIT - BL32_BASE)
+
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+
+/*
+ * Other memory-related defines.
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			4
+
+#define MAX_IO_DEVICES			U(3)
+#define MAX_IO_HANDLES			U(4)
+
+#define MAX_IO_BLOCK_DEVICES		U(1)
+
+/*
+ * Serial-related constants.
+ */
+#define PLAT_RPI3_UART_BASE		RPI3_MINI_UART_BASE
+#define PLAT_RPI3_UART_CLK_IN_HZ	RPI3_MINI_UART_CLK_IN_HZ
+#define PLAT_RPI3_UART_BAUDRATE		ULL(115200)
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	ULL(19200000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk
new file mode 100644
index 0000000..f238cd6
--- /dev/null
+++ b/plat/rpi3/platform.mk
@@ -0,0 +1,218 @@
+#
+# Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/libfdt/libfdt.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES		:=	-Iplat/rpi3/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/aarch64/16550_console.S	\
+				plat/rpi3/rpi3_common.c			\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL1_SOURCES		+=	drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/aarch64/platform_mp_stack.S	\
+				plat/rpi3/aarch64/plat_helpers.S	\
+				plat/rpi3/rpi3_bl1_setup.c		\
+				plat/rpi3/rpi3_io_storage.c		\
+				plat/rpi3/rpi3_mbox.c
+
+BL2_SOURCES		+=	common/desc_image_load.c		\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				drivers/gpio/gpio.c			\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				drivers/rpi3/gpio/rpi3_gpio.c		\
+				drivers/io/io_block.c			\
+				drivers/mmc/mmc.c			\
+				drivers/rpi3/sdhost/rpi3_sdhost.c	\
+				plat/common/aarch64/platform_mp_stack.S	\
+				plat/rpi3/aarch64/plat_helpers.S	\
+				plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \
+				plat/rpi3/rpi3_bl2_setup.c		\
+				plat/rpi3/rpi3_image_load.c		\
+				plat/rpi3/rpi3_io_storage.c
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/plat_psci_common.c		\
+				plat/rpi3/aarch64/plat_helpers.S	\
+				plat/rpi3/rpi3_bl31_setup.c		\
+				plat/rpi3/rpi3_pm.c			\
+				plat/rpi3/rpi3_topology.c		\
+				${LIBFDT_SRCS}
+
+# Tune compiler for Cortex-A53
+ifeq ($(notdir $(CC)),armclang)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else
+    TF_CFLAGS_aarch64	+=	-mtune=cortex-a53
+endif
+
+# Platform Makefile target
+# ------------------------
+
+RPI3_BL1_PAD_BIN	:=	${BUILD_PLAT}/bl1_pad.bin
+RPI3_ARMSTUB8_BIN	:=	${BUILD_PLAT}/armstub8.bin
+
+# Add new default target when compiling this platform
+all: armstub
+
+# This target concatenates BL1 and the FIP so that the base addresses match the
+# ones defined in the memory map
+armstub: bl1 fip
+	@echo "  CAT     $@"
+	${Q}cp ${BUILD_PLAT}/bl1.bin ${RPI3_BL1_PAD_BIN}
+	${Q}truncate --size=131072 ${RPI3_BL1_PAD_BIN}
+	${Q}cat ${RPI3_BL1_PAD_BIN} ${BUILD_PLAT}/fip.bin > ${RPI3_ARMSTUB8_BIN}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_826319		:= 1
+ERRATA_A53_835769		:= 1
+ERRATA_A53_836870		:= 1
+ERRATA_A53_843419		:= 1
+ERRATA_A53_855873		:= 1
+
+WORKAROUND_CVE_2017_5715	:= 0
+
+# Disable stack protector by default
+ENABLE_STACK_PROTECTOR	 	:= 0
+
+# Reset to BL31 isn't supported
+RESET_TO_BL31			:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Platform build flags
+# --------------------
+
+# BL33 images are in AArch64 by default
+RPI3_BL33_IN_AARCH32		:= 0
+
+# Assume that BL33 isn't the Linux kernel by default
+RPI3_DIRECT_LINUX_BOOT		:= 0
+
+# UART to use at runtime. -1 means the runtime UART is disabled.
+# Any other value means the default UART will be used.
+RPI3_RUNTIME_UART		:= -1
+
+# Use normal memory mapping for ROM, FIP, SRAM and DRAM
+RPI3_USE_UEFI_MAP		:= 0
+
+# BL32 location
+RPI3_BL32_RAM_LOCATION	:= tdram
+ifeq (${RPI3_BL32_RAM_LOCATION}, tsram)
+  RPI3_BL32_RAM_LOCATION_ID = SEC_SRAM_ID
+else ifeq (${RPI3_BL32_RAM_LOCATION}, tdram)
+  RPI3_BL32_RAM_LOCATION_ID = SEC_DRAM_ID
+else
+  $(error "Unsupported RPI3_BL32_RAM_LOCATION value")
+endif
+
+# Process platform flags
+# ----------------------
+
+$(eval $(call add_define,RPI3_BL32_RAM_LOCATION_ID))
+$(eval $(call add_define,RPI3_BL33_IN_AARCH32))
+$(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT))
+ifdef RPI3_PRELOADED_DTB_BASE
+$(eval $(call add_define,RPI3_PRELOADED_DTB_BASE))
+endif
+$(eval $(call add_define,RPI3_RUNTIME_UART))
+$(eval $(call add_define,RPI3_USE_UEFI_MAP))
+
+# Verify build config
+# -------------------
+#
+ifneq (${RPI3_DIRECT_LINUX_BOOT}, 0)
+  ifndef RPI3_PRELOADED_DTB_BASE
+    $(error Error: RPI3_PRELOADED_DTB_BASE needed if RPI3_DIRECT_LINUX_BOOT=1)
+  endif
+endif
+
+ifneq (${RESET_TO_BL31}, 0)
+  $(error Error: rpi3 needs RESET_TO_BL31=0)
+endif
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on rpi3)
+endif
+
+ifneq ($(ENABLE_STACK_PROTECTOR), 0)
+PLAT_BL_COMMON_SOURCES	+=	plat/rpi3/rpi3_rng.c			\
+				plat/rpi3/rpi3_stack_protector.c
+endif
+
+ifeq (${SPD},opteed)
+BL2_SOURCES	+=							\
+		lib/optee/optee_utils.c
+endif
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2))
+endif
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+    include drivers/auth/mbedtls/mbedtls_crypto.mk
+    include drivers/auth/mbedtls/mbedtls_x509.mk
+
+    AUTH_SOURCES	:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c
+
+    BL1_SOURCES		+=	${AUTH_SOURCES}				\
+				bl1/tbbr/tbbr_img_desc.c		\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/rpi3/rpi3_trusted_boot.c	     	\
+				plat/rpi3/rpi3_rotpk.S
+
+    BL2_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/rpi3/rpi3_trusted_boot.c	     	\
+				plat/rpi3/rpi3_rotpk.S
+
+    ROT_KEY             = $(BUILD_PLAT)/rot_key.pem
+    ROTPK_HASH          = $(BUILD_PLAT)/rotpk_sha256.bin
+
+    $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+
+    $(BUILD_PLAT)/bl1/rpi3_rotpk.o: $(ROTPK_HASH)
+    $(BUILD_PLAT)/bl2/rpi3_rotpk.o: $(ROTPK_HASH)
+
+    certificates: $(ROT_KEY)
+
+    $(ROT_KEY):
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+    $(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
diff --git a/plat/rpi3/rpi3_bl1_setup.c b/plat/rpi3/rpi3_bl1_setup.c
new file mode 100644
index 0000000..b869e9d
--- /dev/null
+++ b/plat/rpi3/rpi3_bl1_setup.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include "rpi3_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	rpi3_console_init();
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL_RAM_BASE;
+	bl1_tzram_layout.total_size = BL_RAM_SIZE;
+}
+
+/******************************************************************************
+ * Perform the very early platform specific architecture setup.  This only
+ * does basic initialization. Later architectural setup (bl1_arch_setup())
+ * does not do anything platform specific.
+ *****************************************************************************/
+void bl1_plat_arch_setup(void)
+{
+	rpi3_setup_page_tables(bl1_tzram_layout.total_base,
+			       bl1_tzram_layout.total_size,
+			       BL_CODE_BASE, BL1_CODE_END,
+			       BL1_RO_DATA_BASE, BL1_RO_DATA_END
+#if USE_COHERENT_MEM
+			       , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+			      );
+
+	enable_mmu_el3(0);
+}
+
+void bl1_platform_setup(void)
+{
+	uint32_t __unused rev;
+	int __unused rc;
+
+	rc = rpi3_vc_hardware_get_board_revision(&rev);
+
+	if (rc == 0) {
+		const char __unused *model, __unused *info;
+
+		switch (rev) {
+		case 0xA02082:
+			model = "Raspberry Pi 3 Model B";
+			info = "(1GB, Sony, UK)";
+			break;
+		case 0xA22082:
+			model = "Raspberry Pi 3 Model B";
+			info = "(1GB, Embest, China)";
+			break;
+		case 0xA020D3:
+			model = "Raspberry Pi 3 Model B+";
+			info = "(1GB, Sony, UK)";
+			break;
+		default:
+			model = "Unknown";
+			info = "(Unknown)";
+			ERROR("rpi3: Unknown board revision 0x%08x\n", rev);
+			break;
+		}
+
+		NOTICE("rpi3: Detected: %s %s [0x%08x]\n", model, info, rev);
+	} else {
+		ERROR("rpi3: Unable to detect board revision\n");
+	}
+
+	/* Initialise the IO layer and register platform IO devices */
+	plat_rpi3_io_setup();
+}
diff --git a/plat/rpi3/rpi3_bl2_setup.c b/plat/rpi3/rpi3_bl2_setup.c
new file mode 100644
index 0000000..b5e5835
--- /dev/null
+++ b/plat/rpi3/rpi3_bl2_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <lib/optee_utils.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+
+#include "rpi3_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/* rpi3 GPIO setup function. */
+static void rpi3_gpio_setup(void)
+{
+	struct rpi3_gpio_params params;
+
+	memset(&params, 0, sizeof(struct rpi3_gpio_params));
+	params.reg_base = RPI3_GPIO_BASE;
+
+	rpi3_gpio_init(&params);
+}
+
+/* Data structure which holds the MMC info */
+static struct mmc_device_info mmc_info;
+
+static void rpi3_sdhost_setup(void)
+{
+	struct rpi3_sdhost_params params;
+
+	memset(&params, 0, sizeof(struct rpi3_sdhost_params));
+	params.reg_base = RPI3_SDHOST_BASE;
+	params.bus_width = MMC_BUS_WIDTH_1;
+	params.clk_rate = 50000000;
+	mmc_info.mmc_dev_type = MMC_IS_SD_HC;
+	rpi3_sdhost_init(&params, &mmc_info);
+}
+
+/*******************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ ******************************************************************************/
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			       u_register_t arg2, u_register_t arg3)
+{
+	meminfo_t *mem_layout = (meminfo_t *) arg1;
+
+	/* Initialize the console to provide early debug support */
+	rpi3_console_init();
+
+	/* Enable arch timer */
+	generic_delay_timer_init();
+
+	/* Setup GPIO driver */
+	rpi3_gpio_setup();
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+
+	/* Setup SDHost driver */
+	rpi3_sdhost_setup();
+
+	plat_rpi3_io_setup();
+}
+
+void bl2_platform_setup(void)
+{
+	/*
+	 * This is where a TrustZone address space controller and other
+	 * security related peripherals would be configured.
+	 */
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here.
+ ******************************************************************************/
+void bl2_plat_arch_setup(void)
+{
+	rpi3_setup_page_tables(bl2_tzram_layout.total_base,
+			       bl2_tzram_layout.total_size,
+			       BL_CODE_BASE, BL_CODE_END,
+			       BL_RO_DATA_BASE, BL_RO_DATA_END
+#if USE_COHERENT_MEM
+			       , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+			      );
+
+	enable_mmu_el1(0);
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#ifdef SPD_opteed
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+
+	assert(bl_mem_params != NULL);
+
+	switch (image_id) {
+	case BL32_IMAGE_ID:
+#ifdef SPD_opteed
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+				&pager_mem_params->image_info,
+				&paged_mem_params->image_info);
+		if (err != 0)
+			WARN("OPTEE header parse error.\n");
+#endif
+		bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl32_entry();
+		break;
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
+
+		/* Shutting down the SDHost driver to let BL33 drives SDHost.*/
+		rpi3_sdhost_stop();
+		break;
+
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
diff --git a/plat/rpi3/rpi3_bl31_setup.c b/plat/rpi3/rpi3_bl31_setup.c
new file mode 100644
index 0000000..2f1bc64
--- /dev/null
+++ b/plat/rpi3/rpi3_bl31_setup.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#include "rpi3_private.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type) != 0);
+
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images can have 0x0 as the entrypoint. */
+	if (next_image_info->pc) {
+		return next_image_info;
+	} else {
+		return NULL;
+	}
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+
+{
+	/* Initialize the console to provide early debug support */
+	rpi3_console_init();
+
+	/*
+	 * In debug builds, a special value is passed in 'arg1' to verify
+	 * platform parameters from BL2 to BL31. Not used in release builds.
+	 */
+	assert(arg1 == RPI3_BL31_PLAT_PARAM_VAL);
+
+	/* Check that params passed from BL2 are not NULL. */
+	bl_params_t *params_from_bl2 = (bl_params_t *) arg0;
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID) {
+			bl32_image_ep_info = *bl_params->ep_info;
+		}
+
+		if (bl_params->image_id == BL33_IMAGE_ID) {
+			bl33_image_ep_info = *bl_params->ep_info;
+		}
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0) {
+		panic();
+	}
+
+#if RPI3_DIRECT_LINUX_BOOT
+# if RPI3_BL33_IN_AARCH32
+	/*
+	 * According to the file ``Documentation/arm/Booting`` of the Linux
+	 * kernel tree, Linux expects:
+	 * r0 = 0
+	 * r1 = machine type number, optional in DT-only platforms (~0 if so)
+	 * r2 = Physical address of the device tree blob
+	 */
+	VERBOSE("rpi3: Preparing to boot 32-bit Linux kernel\n");
+	bl33_image_ep_info.args.arg0 = 0U;
+	bl33_image_ep_info.args.arg1 = ~0U;
+	bl33_image_ep_info.args.arg2 = (u_register_t) RPI3_PRELOADED_DTB_BASE;
+# else
+	/*
+	 * According to the file ``Documentation/arm64/booting.txt`` of the
+	 * Linux kernel tree, Linux expects the physical address of the device
+	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
+	 * must be 0.
+	 */
+	VERBOSE("rpi3: Preparing to boot 64-bit Linux kernel\n");
+	bl33_image_ep_info.args.arg0 = (u_register_t) RPI3_PRELOADED_DTB_BASE;
+	bl33_image_ep_info.args.arg1 = 0ULL;
+	bl33_image_ep_info.args.arg2 = 0ULL;
+	bl33_image_ep_info.args.arg3 = 0ULL;
+# endif /* RPI3_BL33_IN_AARCH32 */
+#endif /* RPI3_DIRECT_LINUX_BOOT */
+}
+
+void bl31_plat_arch_setup(void)
+{
+	rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE,
+			       BL_CODE_BASE, BL_CODE_END,
+			       BL_RO_DATA_BASE, BL_RO_DATA_END
+#if USE_COHERENT_MEM
+			       , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+			      );
+
+	enable_mmu_el3(0);
+}
+
+#ifdef RPI3_PRELOADED_DTB_BASE
+/*
+ * Add information to the device tree (if any) about the reserved DRAM used by
+ * the Trusted Firmware.
+ */
+static void rpi3_dtb_add_mem_rsv(void)
+{
+	int i, regions, rc;
+	uint64_t addr, size;
+	void *dtb = (void *)RPI3_PRELOADED_DTB_BASE;
+
+	INFO("rpi3: Checking DTB...\n");
+
+	/* Return if no device tree is detected */
+	if (fdt_check_header(dtb) != 0)
+		return;
+
+	regions = fdt_num_mem_rsv(dtb);
+
+	VERBOSE("rpi3: Found %d mem reserve region(s)\n", regions);
+
+	/* We expect to find one reserved region that we can modify */
+	if (regions < 1)
+		return;
+
+	/*
+	 * Look for the region that corresponds to the default boot firmware. It
+	 * starts at address 0, and it is not needed when the default firmware
+	 * is replaced by this port of the Trusted Firmware.
+	 */
+	for (i = 0; i < regions; i++) {
+		if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0)
+			continue;
+
+		if (addr != 0x0)
+			continue;
+
+		VERBOSE("rpi3: Firmware mem reserve region found\n");
+
+		rc = fdt_del_mem_rsv(dtb, i);
+		if (rc != 0) {
+			INFO("rpi3: Can't remove mem reserve region (%d)\n", rc);
+		}
+
+		break;
+	}
+
+	if (i == regions) {
+		VERBOSE("rpi3: Firmware mem reserve region not found\n");
+	}
+
+	/*
+	 * Reserve all SRAM. As said in the documentation, this isn't actually
+	 * secure memory, so it is needed to tell BL33 that this is a reserved
+	 * memory region. It doesn't guarantee it won't use it, though.
+	 */
+	rc = fdt_add_mem_rsv(dtb, SEC_SRAM_BASE, SEC_SRAM_SIZE);
+	if (rc != 0) {
+		WARN("rpi3: Can't add mem reserve region (%d)\n", rc);
+	}
+
+	INFO("rpi3: Reserved 0x%llx - 0x%llx in DTB\n", SEC_SRAM_BASE,
+	     SEC_SRAM_BASE + SEC_SRAM_SIZE);
+}
+#endif
+
+void bl31_platform_setup(void)
+{
+#ifdef RPI3_PRELOADED_DTB_BASE
+	/* Only modify a DTB if we know where to look for it */
+	rpi3_dtb_add_mem_rsv();
+#endif
+}
diff --git a/plat/rpi3/rpi3_common.c b/plat/rpi3/rpi3_common.c
new file mode 100644
index 0000000..9b10974
--- /dev/null
+++ b/plat/rpi3/rpi3_common.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "rpi3_hw.h"
+#include "rpi3_private.h"
+
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SHARED_RAM	MAP_REGION_FLAT(SHARED_RAM_BASE,		\
+					SHARED_RAM_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#ifdef RPI3_PRELOADED_DTB_BASE
+#define MAP_NS_DTB	MAP_REGION_FLAT(RPI3_PRELOADED_DTB_BASE, 0x10000, \
+					MT_MEMORY | MT_RW | MT_NS)
+#endif
+
+#define MAP_NS_DRAM0	MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_FIP		MAP_REGION_FLAT(PLAT_RPI3_FIP_BASE,		\
+					PLAT_RPI3_FIP_MAX_SIZE,		\
+					MT_MEMORY | MT_RO | MT_NS)
+
+#define MAP_BL32_MEM	MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#ifdef SPD_opteed
+#define MAP_OPTEE_PAGEABLE	MAP_REGION_FLAT(		\
+				RPI3_OPTEE_PAGEABLE_LOAD_BASE,	\
+				RPI3_OPTEE_PAGEABLE_LOAD_SIZE,	\
+				MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ */
+#ifdef IMAGE_BL1
+static const mmap_region_t plat_rpi3_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MAP_FIP,
+#ifdef SPD_opteed
+	MAP_OPTEE_PAGEABLE,
+#endif
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL2
+static const mmap_region_t plat_rpi3_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MAP_FIP,
+	MAP_NS_DRAM0,
+#ifdef BL32_BASE
+	MAP_BL32_MEM,
+#endif
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL31
+static const mmap_region_t plat_rpi3_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+#ifdef RPI3_PRELOADED_DTB_BASE
+	MAP_NS_DTB,
+#endif
+#ifdef BL32_BASE
+	MAP_BL32_MEM,
+#endif
+	{0}
+};
+#endif
+
+/*******************************************************************************
+ * Function that sets up the console
+ ******************************************************************************/
+static console_16550_t rpi3_console;
+
+void rpi3_console_init(void)
+{
+	int console_scope = CONSOLE_FLAG_BOOT;
+#if RPI3_RUNTIME_UART != -1
+	console_scope |= CONSOLE_FLAG_RUNTIME;
+#endif
+	int rc = console_16550_register(PLAT_RPI3_UART_BASE,
+					PLAT_RPI3_UART_CLK_IN_HZ,
+					PLAT_RPI3_UART_BAUDRATE,
+					&rpi3_console);
+	if (rc == 0) {
+		/*
+		 * The crash console doesn't use the multi console API, it uses
+		 * the core console functions directly. It is safe to call panic
+		 * and let it print debug information.
+		 */
+		panic();
+	}
+
+	console_set_scope(&rpi3_console.console, console_scope);
+}
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
+			    uintptr_t code_start, uintptr_t code_limit,
+			    uintptr_t rodata_start, uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			    , uintptr_t coh_start, uintptr_t coh_limit
+#endif
+			    )
+{
+	/*
+	 * Map the Trusted SRAM with appropriate memory attributes.
+	 * Subsequent mappings will adjust the attributes for specific regions.
+	 */
+	VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+		(void *) total_base, (void *) (total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+
+	/* Re-map the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *) code_start, (void *) code_limit);
+	mmap_add_region(code_start, code_start,
+			code_limit - code_start,
+			MT_CODE | MT_SECURE);
+
+	/* Re-map the read-only data section */
+	VERBOSE("Read-only data region: %p - %p\n",
+		(void *) rodata_start, (void *) rodata_limit);
+	mmap_add_region(rodata_start, rodata_start,
+			rodata_limit - rodata_start,
+			MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+	/* Re-map the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *) coh_start, (void *) coh_limit);
+	mmap_add_region(coh_start, coh_start,
+			coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	mmap_add(plat_rpi3_mmap);
+
+	init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Return entrypoint of BL33.
+ ******************************************************************************/
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return PLAT_RPI3_NS_IMAGE_OFFSET;
+#endif
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t rpi3_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t rpi3_get_spsr_for_bl33_entry(void)
+{
+#if RPI3_BL33_IN_AARCH32
+	INFO("BL33 will boot in Non-secure AArch32 Hypervisor mode\n");
+	return SPSR_MODE32(MODE32_hyp, SPSR_T_ARM, SPSR_E_LITTLE,
+			   DISABLE_ALL_EXCEPTIONS);
+#else
+	return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+#endif
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+	ERROR("rpi3: Interrupt routed to EL3.\n");
+	return INTR_TYPE_INVAL;
+}
+
+uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state)
+{
+	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
+	       (type == INTR_TYPE_NS));
+
+	assert(sec_state_is_valid(security_state));
+
+	/* Non-secure interrupts are signalled on the IRQ line always. */
+	if (type == INTR_TYPE_NS)
+		return __builtin_ctz(SCR_IRQ_BIT);
+
+	/* Secure interrupts are signalled on the FIQ line always. */
+	return  __builtin_ctz(SCR_FIQ_BIT);
+}
diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h
new file mode 100644
index 0000000..1a86835
--- /dev/null
+++ b/plat/rpi3/rpi3_hw.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_HW_H
+#define RPI3_HW_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Peripherals
+ */
+
+#define RPI3_IO_BASE			ULL(0x3F000000)
+#define RPI3_IO_SIZE			ULL(0x01000000)
+
+/*
+ * ARM <-> VideoCore mailboxes
+ */
+#define RPI3_MBOX_OFFSET		ULL(0x0000B880)
+#define RPI3_MBOX_BASE			(RPI3_IO_BASE + RPI3_MBOX_OFFSET)
+/* VideoCore -> ARM */
+#define RPI3_MBOX0_READ_OFFSET		ULL(0x00000000)
+#define RPI3_MBOX0_PEEK_OFFSET		ULL(0x00000010)
+#define RPI3_MBOX0_SENDER_OFFSET	ULL(0x00000014)
+#define RPI3_MBOX0_STATUS_OFFSET	ULL(0x00000018)
+#define RPI3_MBOX0_CONFIG_OFFSET	ULL(0x0000001C)
+/* ARM -> VideoCore */
+#define RPI3_MBOX1_WRITE_OFFSET		ULL(0x00000020)
+#define RPI3_MBOX1_PEEK_OFFSET		ULL(0x00000030)
+#define RPI3_MBOX1_SENDER_OFFSET	ULL(0x00000034)
+#define RPI3_MBOX1_STATUS_OFFSET	ULL(0x00000038)
+#define RPI3_MBOX1_CONFIG_OFFSET	ULL(0x0000003C)
+/* Mailbox status constants */
+#define RPI3_MBOX_STATUS_FULL_MASK	U(0x80000000) /* Set if full */
+#define RPI3_MBOX_STATUS_EMPTY_MASK	U(0x40000000) /* Set if empty */
+
+/*
+ * Power management, reset controller, watchdog.
+ */
+#define RPI3_IO_PM_OFFSET		ULL(0x00100000)
+#define RPI3_PM_BASE			(RPI3_IO_BASE + RPI3_IO_PM_OFFSET)
+/* Registers on top of RPI3_PM_BASE. */
+#define RPI3_PM_RSTC_OFFSET		ULL(0x0000001C)
+#define RPI3_PM_RSTS_OFFSET		ULL(0x00000020)
+#define RPI3_PM_WDOG_OFFSET		ULL(0x00000024)
+/* Watchdog constants */
+#define RPI3_PM_PASSWORD		U(0x5A000000)
+#define RPI3_PM_RSTC_WRCFG_MASK		U(0x00000030)
+#define RPI3_PM_RSTC_WRCFG_FULL_RESET	U(0x00000020)
+/*
+ * The RSTS register is used by the VideoCore firmware when booting the
+ * Raspberry Pi to know which partition to boot from. The partition value is
+ * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware
+ * to indicate halt.
+ */
+#define RPI3_PM_RSTS_WRCFG_HALT		U(0x00000555)
+
+/*
+ * Hardware random number generator.
+ */
+#define RPI3_IO_RNG_OFFSET		ULL(0x00104000)
+#define RPI3_RNG_BASE			(RPI3_IO_BASE + RPI3_IO_RNG_OFFSET)
+#define RPI3_RNG_CTRL_OFFSET		ULL(0x00000000)
+#define RPI3_RNG_STATUS_OFFSET		ULL(0x00000004)
+#define RPI3_RNG_DATA_OFFSET		ULL(0x00000008)
+#define RPI3_RNG_INT_MASK_OFFSET	ULL(0x00000010)
+/* Enable/disable RNG */
+#define RPI3_RNG_CTRL_ENABLE		U(0x1)
+#define RPI3_RNG_CTRL_DISABLE		U(0x0)
+/* Number of currently available words */
+#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT	U(24)
+#define RPI3_RNG_STATUS_NUM_WORDS_MASK	U(0xFF)
+/* Value to mask interrupts caused by the RNG */
+#define RPI3_RNG_INT_MASK_DISABLE	U(0x1)
+
+/*
+ * Serial port (called 'Mini UART' in the BCM docucmentation).
+ */
+#define RPI3_IO_MINI_UART_OFFSET	ULL(0x00215040)
+#define RPI3_MINI_UART_BASE		(RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
+#define RPI3_MINI_UART_CLK_IN_HZ	ULL(500000000)
+
+/*
+ * GPIO controller
+ */
+#define RPI3_IO_GPIO_OFFSET		ULL(0x00200000)
+#define RPI3_GPIO_BASE			(RPI3_IO_BASE + RPI3_IO_GPIO_OFFSET)
+
+/*
+ * SDHost controller
+ */
+#define RPI3_IO_SDHOST_OFFSET           ULL(0x00202000)
+#define RPI3_SDHOST_BASE                (RPI3_IO_BASE + RPI3_IO_SDHOST_OFFSET)
+
+/*
+ * Local interrupt controller
+ */
+#define RPI3_INTC_BASE_ADDRESS			ULL(0x40000000)
+/* Registers on top of RPI3_INTC_BASE_ADDRESS */
+#define RPI3_INTC_CONTROL_OFFSET		ULL(0x00000000)
+#define RPI3_INTC_PRESCALER_OFFSET		ULL(0x00000008)
+#define RPI3_INTC_MBOX_CONTROL_OFFSET		ULL(0x00000050)
+#define RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ	ULL(0x00000080)
+#define RPI3_INTC_PENDING_FIQ_OFFSET		ULL(0x00000070)
+#define RPI3_INTC_PENDING_FIQ_MBOX3		ULL(0x00000080)
+
+#endif /* RPI3_HW_H */
diff --git a/plat/rpi3/rpi3_image_load.c b/plat/rpi3/rpi3_image_load.c
new file mode 100644
index 0000000..5394c6f
--- /dev/null
+++ b/plat/rpi3/rpi3_image_load.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/rpi3/rpi3_io_storage.c b/plat/rpi3/rpi3_io_storage.c
new file mode 100644
index 0000000..49c6a76
--- /dev/null
+++ b/plat/rpi3/rpi3_io_storage.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <tools_share/firmware_image_package.h>
+
+/* Semihosting filenames */
+#define BL2_IMAGE_NAME			"bl2.bin"
+#define BL31_IMAGE_NAME			"bl31.bin"
+#define BL32_IMAGE_NAME			"bl32.bin"
+#define BL33_IMAGE_NAME			"bl33.bin"
+
+#if TRUSTED_BOARD_BOOT
+#define TRUSTED_BOOT_FW_CERT_NAME	"tb_fw.crt"
+#define TRUSTED_KEY_CERT_NAME		"trusted_key.crt"
+#define SOC_FW_KEY_CERT_NAME		"soc_fw_key.crt"
+#define TOS_FW_KEY_CERT_NAME		"tos_fw_key.crt"
+#define NT_FW_KEY_CERT_NAME		"nt_fw_key.crt"
+#define SOC_FW_CONTENT_CERT_NAME	"soc_fw_content.crt"
+#define TOS_FW_CONTENT_CERT_NAME	"tos_fw_content.crt"
+#define NT_FW_CONTENT_CERT_NAME		"nt_fw_content.crt"
+#endif /* TRUSTED_BOARD_BOOT */
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = PLAT_RPI3_FIP_BASE,
+	.length = PLAT_RPI3_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+/* By default, load images from the FIP */
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		open_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void plat_rpi3_io_setup(void)
+{
+	int io_result;
+
+	io_result = register_io_dev_fip(&fip_dev_con);
+	assert(io_result == 0);
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&memmap_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	if (result == 0) {
+		*image_spec = policy->image_spec;
+		*dev_handle = *(policy->dev_handle);
+	}
+
+	return result;
+}
diff --git a/plat/rpi3/rpi3_mbox.c b/plat/rpi3/rpi3_mbox.c
new file mode 100644
index 0000000..2db605e
--- /dev/null
+++ b/plat/rpi3/rpi3_mbox.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "rpi3_hw.h"
+
+/* This struct must be aligned to 16 bytes */
+typedef struct __packed __aligned(16) rpi3_mbox_request {
+	uint32_t	size; /* Buffer size in bytes */
+	uint32_t	code; /* Request/response code */
+	uint32_t	tags[0];
+} rpi3_mbox_request_t;
+
+#define RPI3_MBOX_BUFFER_SIZE		U(256)
+static uint8_t __aligned(16) rpi3_mbox_buffer[RPI3_MBOX_BUFFER_SIZE];
+
+/* Constants to perform a request/check the status of a request. */
+#define RPI3_MBOX_PROCESS_REQUEST	U(0x00000000)
+#define RPI3_MBOX_REQUEST_SUCCESSFUL	U(0x80000000)
+#define RPI3_MBOX_REQUEST_ERROR		U(0x80000001)
+
+/* Command constants */
+#define RPI3_TAG_HARDWARE_GET_BOARD_REVISION	U(0x00010002)
+#define RPI3_TAG_END				U(0x00000000)
+
+#define RPI3_TAG_REQUEST		U(0x00000000)
+#define RPI3_TAG_IS_RESPONSE		U(0x80000000) /* Set if response */
+#define RPI3_TAG_RESPONSE_LENGTH_MASK	U(0x7FFFFFFF)
+
+#define RPI3_CHANNEL_ARM_TO_VC		U(0x8)
+#define RPI3_CHANNEL_MASK		U(0xF)
+
+#define RPI3_MAILBOX_MAX_RETRIES	U(1000000)
+
+/*******************************************************************************
+ * Helpers to send requests to the VideoCore using the mailboxes.
+ ******************************************************************************/
+static void rpi3_vc_mailbox_request_send(void)
+{
+	uint32_t st, data;
+	uintptr_t resp_addr, addr;
+	unsigned int retries;
+
+	/* This is the location of the request buffer */
+	addr = (uintptr_t) &rpi3_mbox_buffer;
+
+	/* Make sure that the changes are seen by the VideoCore */
+	flush_dcache_range(addr, RPI3_MBOX_BUFFER_SIZE);
+
+	/* Wait until the outbound mailbox is empty */
+	retries = 0U;
+
+	do {
+		st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX1_STATUS_OFFSET);
+
+		retries++;
+		if (retries == RPI3_MAILBOX_MAX_RETRIES) {
+			ERROR("rpi3: mbox: Send request timeout\n");
+			return;
+		}
+
+	} while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) == 0U);
+
+	/* Send base address of this message to start request */
+	mmio_write_32(RPI3_MBOX_BASE + RPI3_MBOX1_WRITE_OFFSET,
+		      RPI3_CHANNEL_ARM_TO_VC | (uint32_t) addr);
+
+	/* Wait until the inbound mailbox isn't empty */
+	retries = 0U;
+
+	do {
+		st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_STATUS_OFFSET);
+
+		retries++;
+		if (retries == RPI3_MAILBOX_MAX_RETRIES) {
+			ERROR("rpi3: mbox: Receive response timeout\n");
+			return;
+		}
+
+	} while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) != 0U);
+
+	/* Get location and channel */
+	data = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_READ_OFFSET);
+
+	if ((data & RPI3_CHANNEL_MASK) != RPI3_CHANNEL_ARM_TO_VC) {
+		ERROR("rpi3: mbox: Wrong channel: 0x%08x\n", data);
+		panic();
+	}
+
+	resp_addr = (uintptr_t)(data & ~RPI3_CHANNEL_MASK);
+	if (addr != resp_addr) {
+		ERROR("rpi3: mbox: Unexpected address: 0x%08x\n", data);
+		panic();
+	}
+
+	/* Make sure that the data seen by the CPU is up to date */
+	inv_dcache_range(addr, RPI3_MBOX_BUFFER_SIZE);
+}
+
+/*******************************************************************************
+ * Request board revision. Returns the revision and 0 on success, -1 on error.
+ ******************************************************************************/
+int rpi3_vc_hardware_get_board_revision(uint32_t *revision)
+{
+	uint32_t tag_request_size = sizeof(uint32_t);
+	rpi3_mbox_request_t *req = (rpi3_mbox_request_t *) rpi3_mbox_buffer;
+
+	assert(revision != NULL);
+
+	VERBOSE("rpi3: mbox: Sending request at %p\n", (void *)req);
+
+	req->size = sizeof(rpi3_mbox_buffer);
+	req->code = RPI3_MBOX_PROCESS_REQUEST;
+
+	req->tags[0] = RPI3_TAG_HARDWARE_GET_BOARD_REVISION;
+	req->tags[1] = tag_request_size; /* Space available for the response */
+	req->tags[2] = RPI3_TAG_REQUEST;
+	req->tags[3] = 0; /* Placeholder for the response */
+
+	req->tags[4] = RPI3_TAG_END;
+
+	rpi3_vc_mailbox_request_send();
+
+	if (req->code != RPI3_MBOX_REQUEST_SUCCESSFUL) {
+		ERROR("rpi3: mbox: Code = 0x%08x\n", req->code);
+		return -1;
+	}
+
+	if (req->tags[2] != (RPI3_TAG_IS_RESPONSE | tag_request_size)) {
+		ERROR("rpi3: mbox: get board revision failed (0x%08x)\n",
+		      req->tags[2]);
+		return -1;
+	}
+
+	*revision = req->tags[3];
+
+	return 0;
+}
diff --git a/plat/rpi3/rpi3_pm.c b/plat/rpi3/rpi3_pm.c
new file mode 100644
index 0000000..4f586b5
--- /dev/null
+++ b/plat/rpi3/rpi3_pm.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "rpi3_hw.h"
+
+/* Make composite power state parameter till power level 0 */
+#if PSCI_EXTENDED_STATE_ID
+
+#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		 ((type) << PSTATE_TYPE_SHIFT))
+
+#else
+
+#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+		 ((type) << PSTATE_TYPE_SHIFT))
+
+#endif /* PSCI_EXTENDED_STATE_ID */
+
+#define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
+		 rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
+
+/*
+ *  The table storing the valid idle power states. Ensure that the
+ *  array entries are populated in ascending order of state-id to
+ *  enable us to use binary search during power state validation.
+ *  The table must be terminated by a NULL entry.
+ */
+static const unsigned int rpi3_pm_idle_states[] = {
+	/* State-id - 0x01 */
+	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
+				MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x02 */
+	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
+				MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x22 */
+	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF,
+				MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
+	0,
+};
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the power state
+ * parameter. The power state parameter has to be a composite power state.
+ ******************************************************************************/
+static int rpi3_validate_power_state(unsigned int power_state,
+				     psci_power_state_t *req_state)
+{
+	unsigned int state_id;
+	int i;
+
+	assert(req_state != 0);
+
+	/*
+	 *  Currently we are using a linear search for finding the matching
+	 *  entry in the idle power state array. This can be made a binary
+	 *  search if the number of entries justify the additional complexity.
+	 */
+	for (i = 0; rpi3_pm_idle_states[i] != 0; i++) {
+		if (power_state == rpi3_pm_idle_states[i]) {
+			break;
+		}
+	}
+
+	/* Return error if entry not found in the idle state array */
+	if (!rpi3_pm_idle_states[i]) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	i = 0;
+	state_id = psci_get_pstate_id(power_state);
+
+	/* Parse the State ID and populate the state info parameter */
+	while (state_id) {
+		req_state->pwr_domain_state[i++] = state_id &
+						PLAT_LOCAL_PSTATE_MASK;
+		state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+static void rpi3_cpu_standby(plat_local_state_t cpu_state)
+{
+	assert(cpu_state == PLAT_LOCAL_STATE_RET);
+
+	/*
+	 * Enter standby state.
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	dsb();
+	wfi();
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int rpi3_pwr_domain_on(u_register_t mpidr)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned int pos = plat_core_pos_by_mpidr(mpidr);
+	uint64_t *hold_base = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+
+	assert(pos < PLATFORM_CORE_COUNT);
+
+	hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO;
+
+	/* Make sure that the write has completed */
+	dsb();
+	isb();
+
+	sev();
+
+	return rc;
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+static void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_LOCAL_STATE_OFF);
+}
+
+/*******************************************************************************
+ * Platform handlers for system reset and system off.
+ ******************************************************************************/
+
+/* 10 ticks (Watchdog timer = Timer clock / 16) */
+#define RESET_TIMEOUT	U(10)
+
+static void __dead2 rpi3_watchdog_reset(void)
+{
+	uint32_t rstc;
+
+	console_flush();
+
+	dsbsy();
+	isb();
+
+	mmio_write_32(RPI3_PM_BASE + RPI3_PM_WDOG_OFFSET,
+		      RPI3_PM_PASSWORD | RESET_TIMEOUT);
+
+	rstc = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET);
+	rstc &= ~RPI3_PM_RSTC_WRCFG_MASK;
+	rstc |= RPI3_PM_PASSWORD | RPI3_PM_RSTC_WRCFG_FULL_RESET;
+	mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET, rstc);
+
+	for (;;) {
+		wfi();
+	}
+}
+
+static void __dead2 rpi3_system_reset(void)
+{
+	INFO("rpi3: PSCI_SYSTEM_RESET: Invoking watchdog reset\n");
+
+	rpi3_watchdog_reset();
+}
+
+static void __dead2 rpi3_system_off(void)
+{
+	uint32_t rsts;
+
+	INFO("rpi3: PSCI_SYSTEM_OFF: Invoking watchdog reset\n");
+
+	/*
+	 * This function doesn't actually make the Raspberry Pi turn itself off,
+	 * the hardware doesn't allow it. It simply reboots it and the RSTS
+	 * value tells the bootcode.bin firmware not to continue the regular
+	 * bootflow and to stay in a low power mode.
+	 */
+
+	rsts = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET);
+	rsts |= RPI3_PM_PASSWORD | RPI3_PM_RSTS_WRCFG_HALT;
+	mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET, rsts);
+
+	rpi3_watchdog_reset();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
+	.cpu_standby = rpi3_cpu_standby,
+	.pwr_domain_on = rpi3_pwr_domain_on,
+	.pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
+	.system_off = rpi3_system_off,
+	.system_reset = rpi3_system_reset,
+	.validate_power_state = rpi3_validate_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	uintptr_t *entrypoint = (void *) PLAT_RPI3_TM_ENTRYPOINT;
+
+	*entrypoint = sec_entrypoint;
+	*psci_ops = &plat_rpi3_psci_pm_ops;
+
+	return 0;
+}
diff --git a/plat/rpi3/rpi3_private.h b/plat/rpi3/rpi3_private.h
new file mode 100644
index 0000000..53078f8
--- /dev/null
+++ b/plat/rpi3/rpi3_private.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_PRIVATE_H
+#define RPI3_PRIVATE_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+/* Utility functions */
+void rpi3_console_init(void);
+void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
+			    uintptr_t code_start, uintptr_t code_limit,
+			    uintptr_t rodata_start, uintptr_t rodata_limit
+#if USE_COHERENT_MEM
+			    , uintptr_t coh_start, uintptr_t coh_limit
+#endif
+			    );
+
+/* Optional functions required in the Raspberry Pi 3 port */
+unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
+
+/* BL2 utility functions */
+uint32_t rpi3_get_spsr_for_bl32_entry(void);
+uint32_t rpi3_get_spsr_for_bl33_entry(void);
+
+/* IO storage utility functions */
+void plat_rpi3_io_setup(void);
+
+/* Hardware RNG functions */
+void rpi3_rng_read(void *buf, size_t len);
+
+/* VideoCore firmware commands */
+int rpi3_vc_hardware_get_board_revision(uint32_t *revision);
+
+#endif /* RPI3_PRIVATE_H */
diff --git a/plat/rpi3/rpi3_rng.c b/plat/rpi3/rpi3_rng.c
new file mode 100644
index 0000000..fd69adb
--- /dev/null
+++ b/plat/rpi3/rpi3_rng.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+
+#include "rpi3_hw.h"
+
+/* Initial amount of values to discard */
+#define RNG_WARMUP_COUNT	U(0x40000)
+
+static void rpi3_rng_initialize(void)
+{
+	uint32_t int_mask, ctrl;
+
+	/* Return if it is already enabled */
+	ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET);
+	if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) {
+		return;
+	}
+
+	/* Mask interrupts */
+	int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET);
+	int_mask |= RPI3_RNG_INT_MASK_DISABLE;
+	mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask);
+
+	/* Discard several values when initializing to give it time to warmup */
+	mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT);
+
+	mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET,
+		      RPI3_RNG_CTRL_ENABLE);
+}
+
+static uint32_t rpi3_rng_get_word(void)
+{
+	size_t nwords;
+
+	do {
+		/* Get number of available words to read */
+		nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET)
+				       >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT)
+				       & RPI3_RNG_STATUS_NUM_WORDS_MASK;
+	} while (nwords == 0U);
+
+	return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET);
+}
+
+void rpi3_rng_read(void *buf, size_t len)
+{
+	uint32_t data;
+	size_t left = len;
+	uint32_t *dst = buf;
+
+	assert(buf != NULL);
+	assert(len != 0U);
+	assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0);
+
+	rpi3_rng_initialize();
+
+	while (left >= sizeof(uint32_t)) {
+		data = rpi3_rng_get_word();
+		*dst++ = data;
+		left -= sizeof(uint32_t);
+	}
+
+	if (left > 0U) {
+		data = rpi3_rng_get_word();
+		memcpy(dst, &data, left);
+	}
+}
diff --git a/plat/rpi3/rpi3_rotpk.S b/plat/rpi3/rpi3_rotpk.S
new file mode 100644
index 0000000..1c17b21
--- /dev/null
+++ b/plat/rpi3/rpi3_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global rpi3_rotpk_hash
+	.global rpi3_rotpk_hash_end
+rpi3_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+rpi3_rotpk_hash_end:
diff --git a/plat/rpi3/rpi3_stack_protector.c b/plat/rpi3/rpi3_stack_protector.c
new file mode 100644
index 0000000..6f49f61
--- /dev/null
+++ b/plat/rpi3/rpi3_stack_protector.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "rpi3_private.h"
+
+/* Get 128 bits of entropy and fuse the values together to form the canary. */
+#define TRNG_NBYTES	16U
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+	size_t i;
+	u_register_t buf[TRNG_NBYTES / sizeof(u_register_t)];
+	u_register_t ret = 0U;
+
+	rpi3_rng_read(buf, sizeof(buf));
+
+	for (i = 0U; i < ARRAY_SIZE(buf); i++)
+		ret ^= buf[i];
+
+	return ret;
+}
diff --git a/plat/rpi3/rpi3_topology.c b/plat/rpi3/rpi3_topology.c
new file mode 100644
index 0000000..200d41d
--- /dev/null
+++ b/plat/rpi3/rpi3_topology.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include "rpi3_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) {
+		return -1;
+	}
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+		return -1;
+	}
+
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+		return -1;
+	}
+
+	return plat_rpi3_calc_core_pos(mpidr);
+}
diff --git a/plat/rpi3/rpi3_trusted_boot.c b/plat/rpi3/rpi3_trusted_boot.c
new file mode 100644
index 0000000..f6c669f
--- /dev/null
+++ b/plat/rpi3/rpi3_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char rpi3_rotpk_hash[], rpi3_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = rpi3_rotpk_hash;
+	*key_len = rpi3_rotpk_hash_end - rpi3_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.c b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
new file mode 100644
index 0000000..925ed97
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <sq_common.h>
+#include "sq_mhu.h"
+
+/* SCP MHU secure channel registers */
+#define SCP_INTR_S_STAT		0x200
+#define SCP_INTR_S_SET		0x208
+#define SCP_INTR_S_CLEAR	0x210
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT		0x300
+#define CPU_INTR_S_SET		0x308
+#define CPU_INTR_S_CLEAR	0x310
+
+DEFINE_BAKERY_LOCK(sq_lock);
+
+/*
+ * Slot 31 is reserved because the MHU hardware uses this register bit to
+ * indicate a non-secure access attempt. The total number of available slots is
+ * therefore 31 [30:0].
+ */
+#define MHU_MAX_SLOT_ID		30
+
+void mhu_secure_message_start(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+
+	bakery_lock_get(&sq_lock);
+
+	/* Make sure any previous command has finished */
+	while (mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) &
+							(1 << slot_id))
+		;
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+	assert(!(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) &
+							(1 << slot_id)));
+
+	/* Send command to SCP */
+	mmio_write_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+	uint32_t response;
+
+	/* Wait for response from SCP */
+	while (!(response = mmio_read_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_STAT)))
+		;
+
+	return response;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+	assert(slot_id <= MHU_MAX_SLOT_ID);
+
+	/*
+	 * Clear any response we got by writing one in the relevant slot bit to
+	 * the CLEAR register
+	 */
+	mmio_write_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
+
+	bakery_lock_release(&sq_lock);
+}
+
+void mhu_secure_init(void)
+{
+	bakery_lock_init(&sq_lock);
+
+	/*
+	 * The STAT register resets to zero. Ensure it is in the expected state,
+	 * as a stale or garbage value would make us think it's a message we've
+	 * already sent.
+	 */
+	assert(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) == 0);
+}
+
+void plat_sq_pwrc_setup(void)
+{
+	mhu_secure_init();
+}
diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.h b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h
new file mode 100644
index 0000000..f6b5cc3
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_MHU_H
+#define SQ_MHU_H
+
+#include <stdint.h>
+
+void mhu_secure_message_start(unsigned int slot_id);
+void mhu_secure_message_send(unsigned int slot_id);
+uint32_t mhu_secure_message_wait(void);
+void mhu_secure_message_end(unsigned int slot_id);
+
+void mhu_secure_init(void);
+
+#endif /* SQ_MHU_H */
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scmi.c b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
new file mode 100644
index 0000000..e2013cc
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <scmi_sq.h>
+#include <sq_common.h>
+
+/*
+ * This file implements the SCP helper functions using SCMI protocol.
+ */
+
+DEFINE_BAKERY_LOCK(sq_scmi_lock);
+#define SQ_SCMI_LOCK_GET_INSTANCE	(&sq_scmi_lock)
+
+#define SQ_SCMI_PAYLOAD_BASE		PLAT_SQ_SCP_COM_SHARED_MEM_BASE
+#define MHU_CPU_INTR_S_SET_OFFSET	0x308
+
+const uint32_t sq_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
+	0,   1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
+	12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
+};
+
+static scmi_channel_plat_info_t sq_scmi_plat_info = {
+		.scmi_mbx_mem = SQ_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_SQ_MHU_BASE + MHU_CPU_INTR_S_SET_OFFSET,
+		.db_preserve_mask = 0xfffffffe,
+		.db_modify_mask = 0x1,
+		.ring_doorbell = &mhu_ring_doorbell,
+};
+
+/*
+ * SCMI power state parameter bit field encoding for SynQuacer platform.
+ *
+ * 31  20 19       16 15      12 11       8 7        4 3         0
+ * +-------------------------------------------------------------+
+ * | SBZ | Max level |  Level 3 |  Level 2 |  Level 1 |  Level 0 |
+ * |     |           |   state  |   state  |   state  |   state  |
+ * +-------------------------------------------------------------+
+ *
+ * `Max level` encodes the highest level that has a valid power state
+ * encoded in the power state.
+ */
+#define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT	16
+#define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH	4
+#define SCMI_PWR_STATE_MAX_PWR_LVL_MASK		\
+				((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level)		\
+		(_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\
+				<< SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
+#define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state)		\
+		(((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT)	\
+				& SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
+
+#define SCMI_PWR_STATE_LVL_WIDTH		4
+#define SCMI_PWR_STATE_LVL_MASK			\
+				((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state)		\
+		(_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK)	\
+				<< (SCMI_PWR_STATE_LVL_WIDTH * (_level))
+#define SCMI_GET_PWR_STATE_LVL(_power_state, _level)		\
+		(((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) &	\
+				SCMI_PWR_STATE_LVL_MASK)
+
+/*
+ * The SCMI power state enumeration for a power domain level
+ */
+typedef enum {
+	scmi_power_state_off = 0,
+	scmi_power_state_on = 1,
+	scmi_power_state_sleep = 2,
+} scmi_power_state_t;
+
+/*
+ * The global handle for invoking the SCMI driver APIs after the driver
+ * has been initialized.
+ */
+static void *sq_scmi_handle;
+
+/* The SCMI channel global object */
+static scmi_channel_t channel;
+
+/*
+ * Helper function to turn off a CPU power domain and
+ * its parent power domains if applicable.
+ */
+void sq_scmi_off(const struct psci_power_state *target_state)
+{
+	int lvl = 0, ret;
+	uint32_t scmi_pwr_state = 0;
+
+	/* At-least the CPU level should be specified to be OFF */
+	assert(target_state->pwr_domain_state[SQ_PWR_LVL0] ==
+							SQ_LOCAL_STATE_OFF);
+
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		if (target_state->pwr_domain_state[lvl] == SQ_LOCAL_STATE_RUN)
+			break;
+
+		assert(target_state->pwr_domain_state[lvl] ==
+							SQ_LOCAL_STATE_OFF);
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+				scmi_power_state_off);
+	}
+
+	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+	ret = scmi_pwr_state_set(sq_scmi_handle,
+		sq_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and
+ *its parent power domains if applicable.
+ */
+void sq_scmi_on(u_register_t mpidr)
+{
+	int lvl = 0, ret, core_pos;
+	uint32_t scmi_pwr_state = 0;
+
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+				scmi_power_state_on);
+
+	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);
+
+	ret = scmi_pwr_state_set(sq_scmi_handle,
+		sq_core_pos_to_scmi_dmn_id_map[core_pos],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+void __dead2 sq_scmi_system_off(int state)
+{
+	int ret;
+
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt from waking
+	 * up the AP from WFI.
+	 */
+	sq_gic_cpuif_disable();
+
+	/*
+	 * Issue SCMI command. First issue a graceful
+	 * request and if that fails force the request.
+	 */
+	ret = scmi_sys_pwr_state_set(sq_scmi_handle,
+			SCMI_SYS_PWR_FORCEFUL_REQ,
+			state);
+
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
+			state, ret);
+		panic();
+	}
+	wfi();
+	ERROR("SCMI set power state: operation not handled.\n");
+	panic();
+}
+
+/*
+ * Helper function to reset the system via SCMI.
+ */
+void __dead2 sq_scmi_sys_reboot(void)
+{
+	sq_scmi_system_off(SCMI_SYS_PWR_COLD_RESET);
+}
+
+static int scmi_ap_core_init(scmi_channel_t *ch)
+{
+#if PROGRAMMABLE_RESET_ADDRESS
+	uint32_t version;
+	int ret;
+
+	ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version);
+	if (ret != SCMI_E_SUCCESS) {
+		WARN("SCMI AP core protocol version message failed\n");
+		return -1;
+	}
+
+	if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) {
+		WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n",
+						version, SCMI_AP_CORE_PROTO_VER);
+		return -1;
+	}
+	INFO("SCMI AP core protocol version 0x%x detected\n", version);
+#endif
+	return 0;
+}
+
+void __init plat_sq_pwrc_setup(void)
+{
+	channel.info = &sq_scmi_plat_info;
+	channel.lock = SQ_SCMI_LOCK_GET_INSTANCE;
+	sq_scmi_handle = scmi_init(&channel);
+	if (sq_scmi_handle == NULL) {
+		ERROR("SCMI Initialization failed\n");
+		panic();
+	}
+	if (scmi_ap_core_init(&channel) < 0) {
+		ERROR("SCMI AP core protocol initialization failed\n");
+		panic();
+	}
+}
+
+uint32_t sq_scmi_get_draminfo(struct draminfo *info)
+{
+	scmi_get_draminfo(sq_scmi_handle, info);
+
+	return 0;
+}
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scp.c b/plat/socionext/synquacer/drivers/scp/sq_scp.c
new file mode 100644
index 0000000..e494022
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scp/sq_scp.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sq_common.h>
+#include "sq_scpi.h"
+
+/*
+ * Helper function to get dram information from SCP.
+ */
+uint32_t sq_scp_get_draminfo(struct draminfo *info)
+{
+#if SQ_USE_SCMI_DRIVER
+	sq_scmi_get_draminfo(info);
+#else
+	scpi_get_draminfo(info);
+#endif
+	return 0;
+}
diff --git a/plat/socionext/synquacer/drivers/scpi/sq_scpi.c b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
new file mode 100644
index 0000000..0cb75a0
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <sq_common.h>
+
+#include "sq_mhu.h"
+#include "sq_scpi.h"
+
+#define SCPI_SHARED_MEM_SCP_TO_AP	PLAT_SQ_SCP_COM_SHARED_MEM_BASE
+#define SCPI_SHARED_MEM_AP_TO_SCP	(PLAT_SQ_SCP_COM_SHARED_MEM_BASE \
+								 + 0x100)
+
+#define SCPI_CMD_HEADER_AP_TO_SCP		\
+	((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
+#define SCPI_CMD_PAYLOAD_AP_TO_SCP		\
+	((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
+
+/* ID of the MHU slot used for the SCPI protocol */
+#define SCPI_MHU_SLOT_ID		0
+
+static void scpi_secure_message_start(void)
+{
+	mhu_secure_message_start(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_send(size_t payload_size)
+{
+	/*
+	 * Ensure that any write to the SCPI payload area is seen by SCP before
+	 * we write to the MHU register. If these 2 writes were reordered by
+	 * the CPU then SCP would read stale payload data
+	 */
+	dmbst();
+
+	mhu_secure_message_send(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_receive(scpi_cmd_t *cmd)
+{
+	uint32_t mhu_status;
+
+	assert(cmd != NULL);
+
+	mhu_status = mhu_secure_message_wait();
+
+	/* Expect an SCPI message, reject any other protocol */
+	if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
+		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+			mhu_status);
+		panic();
+	}
+
+	/*
+	 * Ensure that any read to the SCPI payload area is done after reading
+	 * the MHU register. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data
+	 */
+	dmbld();
+
+	memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
+}
+
+static void scpi_secure_message_end(void)
+{
+	mhu_secure_message_end(SCPI_MHU_SLOT_ID);
+}
+
+int scpi_wait_ready(void)
+{
+	scpi_cmd_t scpi_cmd;
+	scpi_status_t status = SCP_OK;
+
+	VERBOSE("Waiting for SCP_READY command...\n");
+
+	/* Get a message from the SCP */
+	scpi_secure_message_start();
+	scpi_secure_message_receive(&scpi_cmd);
+	scpi_secure_message_end();
+
+	/* We are expecting 'SCP Ready', produce correct error if it's not */
+	if (scpi_cmd.id != SCPI_CMD_SCP_READY) {
+		ERROR("Unexpected SCP command: expected command #%u,"
+		      "got command #%u\n", SCPI_CMD_SCP_READY, scpi_cmd.id);
+		status = SCP_E_SUPPORT;
+	} else if (scpi_cmd.size != 0) {
+		ERROR("SCP_READY command has incorrect size: expected 0,"
+		      "got %u\n", scpi_cmd.size);
+		status = SCP_E_SIZE;
+	}
+
+	VERBOSE("Sending response for SCP_READY command\n");
+
+	/*
+	 * Send our response back to SCP.
+	 * We are using the same SCPI header, just update the status field.
+	 */
+	scpi_cmd.status = status;
+	scpi_secure_message_start();
+	memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd));
+	scpi_secure_message_send(0);
+	scpi_secure_message_end();
+
+	return status == SCP_OK ? 0 : -1;
+}
+
+void scpi_set_sq_power_state(unsigned int mpidr, scpi_power_state_t cpu_state,
+		scpi_power_state_t cluster_state, scpi_power_state_t sq_state)
+{
+	scpi_cmd_t *cmd;
+	uint32_t state = 0;
+	uint32_t *payload_addr;
+
+	state |= mpidr & 0x0f;	/* CPU ID */
+	state |= (mpidr & 0xf00) >> 4;	/* Cluster ID */
+	state |= cpu_state << 8;
+	state |= cluster_state << 12;
+	state |= sq_state << 16;
+
+	scpi_secure_message_start();
+
+	/* Populate the command header */
+	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+	cmd->id = SCPI_CMD_SET_POWER_STATE;
+	cmd->set = SCPI_SET_NORMAL;
+	cmd->sender = 0;
+	cmd->size = sizeof(state);
+	/* Populate the command payload */
+	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+	*payload_addr = state;
+	scpi_secure_message_send(sizeof(state));
+
+	/*
+	 * SCP does not reply to this command in order to avoid MHU interrupts
+	 * from the sender, which could interfere with its power state request.
+	 */
+	scpi_secure_message_end();
+}
+
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
+{
+	scpi_cmd_t *cmd;
+	uint8_t *payload_addr;
+	scpi_cmd_t response;
+
+	scpi_secure_message_start();
+
+	/* Populate the command header */
+	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+	cmd->id = SCPI_CMD_SYS_POWER_STATE;
+	cmd->set = 0;
+	cmd->sender = 0;
+	cmd->size = sizeof(*payload_addr);
+	/* Populate the command payload */
+	payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+	*payload_addr = system_state & 0xff;
+	scpi_secure_message_send(sizeof(*payload_addr));
+
+	scpi_secure_message_receive(&response);
+
+	scpi_secure_message_end();
+
+	return response.status;
+}
+
+uint32_t scpi_get_draminfo(struct draminfo *info)
+{
+	scpi_cmd_t *cmd;
+	struct {
+		scpi_cmd_t	cmd;
+		struct draminfo	info;
+	} response;
+	uint32_t mhu_status;
+
+	scpi_secure_message_start();
+
+	/* Populate the command header */
+	cmd		= SCPI_CMD_HEADER_AP_TO_SCP;
+	cmd->id		= SCPI_CMD_GET_DRAMINFO;
+	cmd->set	= SCPI_SET_EXTENDED;
+	cmd->sender	= 0;
+	cmd->size	= 0;
+
+	scpi_secure_message_send(0);
+
+	mhu_status = mhu_secure_message_wait();
+
+	/* Expect an SCPI message, reject any other protocol */
+	if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
+		ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+			mhu_status);
+		panic();
+	}
+
+	/*
+	 * Ensure that any read to the SCPI payload area is done after reading
+	 * the MHU register. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data
+	 */
+	dmbld();
+
+	memcpy(&response, (void *)SCPI_SHARED_MEM_SCP_TO_AP, sizeof(response));
+
+	scpi_secure_message_end();
+
+	if (response.cmd.status == SCP_OK)
+		*info = response.info;
+
+	return response.cmd.status;
+}
diff --git a/plat/socionext/synquacer/drivers/scpi/sq_scpi.h b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
new file mode 100644
index 0000000..eb6ce5c
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_SCPI_H
+#define SQ_SCPI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * An SCPI command consists of a header and a payload.
+ * The following structure describes the header. It is 64-bit long.
+ */
+typedef struct {
+	/* Command ID */
+	uint32_t id		: 7;
+	/* Set ID. Identifies whether this is a standard or extended command. */
+	uint32_t set		: 1;
+	/* Sender ID to match a reply. The value is sender specific. */
+	uint32_t sender		: 8;
+	/* Size of the payload in bytes (0 - 511) */
+	uint32_t size		: 9;
+	uint32_t reserved	: 7;
+	/*
+	 * Status indicating the success of a command.
+	 * See the enum below.
+	 */
+	uint32_t status;
+} scpi_cmd_t;
+
+typedef enum {
+	SCPI_SET_NORMAL = 0,	/* Normal SCPI commands */
+	SCPI_SET_EXTENDED	/* Extended SCPI commands */
+} scpi_set_t;
+
+enum {
+	SCP_OK = 0,	/* Success */
+	SCP_E_PARAM,	/* Invalid parameter(s) */
+	SCP_E_ALIGN,	/* Invalid alignment */
+	SCP_E_SIZE,	/* Invalid size */
+	SCP_E_HANDLER,	/* Invalid handler or callback */
+	SCP_E_ACCESS,	/* Invalid access or permission denied */
+	SCP_E_RANGE,	/* Value out of range */
+	SCP_E_TIMEOUT,	/* Time out has ocurred */
+	SCP_E_NOMEM,	/* Invalid memory area or pointer */
+	SCP_E_PWRSTATE,	/* Invalid power state */
+	SCP_E_SUPPORT,	/* Feature not supported or disabled */
+	SCPI_E_DEVICE,	/* Device error */
+	SCPI_E_BUSY,	/* Device is busy */
+};
+
+typedef uint32_t scpi_status_t;
+
+typedef enum {
+	SCPI_CMD_SCP_READY = 0x01,
+	SCPI_CMD_SET_POWER_STATE = 0x03,
+	SCPI_CMD_SYS_POWER_STATE = 0x05
+} scpi_command_t;
+
+typedef enum {
+	scpi_power_on = 0,
+	scpi_power_retention = 1,
+	scpi_power_off = 3,
+} scpi_power_state_t;
+
+typedef enum {
+	scpi_system_shutdown = 0,
+	scpi_system_reboot = 1,
+	scpi_system_reset = 2
+} scpi_system_state_t;
+
+extern int scpi_wait_ready(void);
+extern void scpi_set_sq_power_state(unsigned int mpidr,
+					scpi_power_state_t cpu_state,
+					scpi_power_state_t cluster_state,
+					scpi_power_state_t css_state);
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state);
+uint32_t scpi_get_draminfo(struct draminfo *info);
+
+#endif /* SQ_SCPI_H */
diff --git a/plat/socionext/synquacer/include/plat.ld.S b/plat/socionext/synquacer/include/plat.ld.S
new file mode 100644
index 0000000..a06fe2a
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat.ld.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SYNQUACER_PLAT_LD_S__
+#define SYNQUACER_PLAT_LD_S__
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#define SPM_SHIM_EXCEPTIONS_VMA		SP_DRAM
+
+MEMORY {
+	SP_DRAM (rw): ORIGIN = PLAT_SQ_SP_PRIV_BASE, LENGTH = PLAT_SQ_SP_PRIV_SIZE
+}
+
+SECTIONS
+{
+	/*
+	 * Put the page tables in secure DRAM so that the PTW can make cacheable
+	 * accesses, as the core SPM code expects. (The SRAM on SynQuacer does
+	 * not support inner shareable WBWA mappings so it is mapped normal
+	 * non-cacheable)
+	 */
+	sp_xlat_table (NOLOAD) : ALIGN(PAGE_SIZE) {
+		*(sp_xlat_table)
+		*(.bss.sp_base_xlat_table)
+	} >SP_DRAM
+}
+
+#endif /* SYNQUACER_PLAT_LD_S__ */
diff --git a/plat/socionext/synquacer/include/plat_macros.S b/plat/socionext/synquacer/include/plat_macros.S
new file mode 100644
index 0000000..932b21d
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat_macros.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+/*
+ * Print CCN registers
+ */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/socionext/synquacer/include/platform_def.h b/plat/socionext/synquacer/include/platform_def.h
new file mode 100644
index 0000000..7e54b39
--- /dev/null
+++ b/plat/socionext/synquacer/include/platform_def.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/* CPU topology */
+#define PLAT_MAX_CORES_PER_CLUSTER	2
+#define PLAT_CLUSTER_COUNT		12
+#define PLATFORM_CORE_COUNT		(PLAT_CLUSTER_COUNT *	\
+					 PLAT_MAX_CORES_PER_CLUSTER)
+
+/* Macros to read the SQ power domain state */
+#define SQ_PWR_LVL0		MPIDR_AFFLVL0
+#define SQ_PWR_LVL1		MPIDR_AFFLVL1
+#define SQ_PWR_LVL2		MPIDR_AFFLVL2
+
+#define SQ_CORE_PWR_STATE(state)	(state)->pwr_domain_state[SQ_PWR_LVL0]
+#define SQ_CLUSTER_PWR_STATE(state)	(state)->pwr_domain_state[SQ_PWR_LVL1]
+#define SQ_SYSTEM_PWR_STATE(state)	((PLAT_MAX_PWR_LVL > SQ_PWR_LVL1) ?\
+				(state)->pwr_domain_state[SQ_PWR_LVL2] : 0)
+
+#define PLAT_MAX_PWR_LVL		U(1)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+#define SQ_LOCAL_STATE_RUN		0
+#define SQ_LOCAL_STATE_RET		1
+#define SQ_LOCAL_STATE_OFF		2
+
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_XLAT_TABLES			8
+#define MAX_MMAP_REGIONS		8
+
+#define PLATFORM_STACK_SIZE		0x400
+
+#define BL31_BASE			0x04000000
+#define BL31_SIZE			0x00080000
+#define BL31_LIMIT			(BL31_BASE + BL31_SIZE)
+
+#define BL32_BASE			0xfc000000
+#define BL32_SIZE			0x03c00000
+#define BL32_LIMIT			(BL32_BASE + BL32_SIZE)
+
+#define PLAT_SQ_CCN_BASE		0x32000000
+#define PLAT_SQ_CLUSTER_TO_CCN_ID_MAP					\
+					0,	/* Cluster 0 */		\
+					18,	/* Cluster 1 */		\
+					11,	/* Cluster 2 */		\
+					29,	/* Cluster 3 */		\
+					35,	/* Cluster 4 */		\
+					17,	/* Cluster 5 */		\
+					12,	/* Cluster 6 */		\
+					30,	/* Cluster 7 */		\
+					14,	/* Cluster 8 */		\
+					32,	/* Cluster 9 */		\
+					15,	/* Cluster 10 */	\
+					33	/* Cluster 11 */
+
+/* UART related constants */
+#define PLAT_SQ_BOOT_UART_BASE		0x2A400000
+#define PLAT_SQ_BOOT_UART_CLK_IN_HZ	62500000
+#define SQ_CONSOLE_BAUDRATE		115200
+
+#define SQ_SYS_CNTCTL_BASE		0x2a430000
+
+#define SQ_SYS_TIMCTL_BASE		0x2a810000
+#define PLAT_SQ_NSTIMER_FRAME_ID	0
+
+#define DRAMINFO_BASE			0x2E00FFC0
+
+#define PLAT_SQ_MHU_BASE		0x45000000
+#define PLAT_MHUV2_BASE			0xFFFFFFFF /* MHUV2 is not supported */
+
+#define PLAT_SQ_SCP_COM_SHARED_MEM_BASE		0x45400000
+#define SCPI_CMD_GET_DRAMINFO			0x1
+
+#define SQ_BOOT_CFG_ADDR			0x45410000
+#define PLAT_SQ_PRIMARY_CPU_SHIFT		8
+#define PLAT_SQ_PRIMARY_CPU_BIT_WIDTH		6
+
+#define PLAT_SQ_GICD_BASE		0x30000000
+#define PLAT_SQ_GICR_BASE		0x30400000
+
+#define PLAT_SQ_GPIO_BASE		0x51000000
+
+#define PLAT_SPM_BUF_BASE		(BL32_LIMIT - 32 * PLAT_SPM_BUF_SIZE)
+#define PLAT_SPM_BUF_SIZE		ULL(0x10000)
+#define PLAT_SPM_SPM_BUF_EL0_MMAP	MAP_REGION2(PLAT_SPM_BUF_BASE, \
+						    PLAT_SPM_BUF_BASE, \
+						    PLAT_SPM_BUF_SIZE, \
+						    MT_RO_DATA | MT_SECURE | \
+						    MT_USER, PAGE_SIZE)
+
+#define PLAT_SP_IMAGE_NS_BUF_BASE	BL32_LIMIT
+#define PLAT_SP_IMAGE_NS_BUF_SIZE	ULL(0x200000)
+#define PLAT_SP_IMAGE_NS_BUF_MMAP	MAP_REGION2(PLAT_SP_IMAGE_NS_BUF_BASE, \
+						    PLAT_SP_IMAGE_NS_BUF_BASE, \
+						    PLAT_SP_IMAGE_NS_BUF_SIZE, \
+						    MT_RW_DATA | MT_NS | \
+						    MT_USER, PAGE_SIZE)
+
+#define PLAT_SP_IMAGE_STACK_PCPU_SIZE	ULL(0x10000)
+#define PLAT_SP_IMAGE_STACK_SIZE	(32 * PLAT_SP_IMAGE_STACK_PCPU_SIZE)
+#define PLAT_SP_IMAGE_STACK_BASE	(PLAT_SQ_SP_HEAP_BASE + PLAT_SQ_SP_HEAP_SIZE)
+
+#define PLAT_SQ_SP_IMAGE_SIZE		ULL(0x200000)
+#define PLAT_SQ_SP_IMAGE_MMAP		MAP_REGION2(BL32_BASE, BL32_BASE, \
+						    PLAT_SQ_SP_IMAGE_SIZE, \
+						    MT_CODE | MT_SECURE | \
+						    MT_USER, PAGE_SIZE)
+
+#define PLAT_SQ_SP_HEAP_BASE		(BL32_BASE + PLAT_SQ_SP_IMAGE_SIZE)
+#define PLAT_SQ_SP_HEAP_SIZE		ULL(0x800000)
+
+#define PLAT_SQ_SP_IMAGE_RW_MMAP	MAP_REGION2(PLAT_SQ_SP_HEAP_BASE, \
+						    PLAT_SQ_SP_HEAP_BASE, \
+						    (PLAT_SQ_SP_HEAP_SIZE + \
+						     PLAT_SP_IMAGE_STACK_SIZE), \
+						    MT_RW_DATA | MT_SECURE | \
+						    MT_USER, PAGE_SIZE)
+
+#define PLAT_SQ_SP_PRIV_BASE		(PLAT_SP_IMAGE_STACK_BASE + \
+					 PLAT_SP_IMAGE_STACK_SIZE)
+#define PLAT_SQ_SP_PRIV_SIZE		ULL(0x40000)
+
+#define PLAT_SP_PRI			0x20
+#define PLAT_PRI_BITS			2
+#define PLAT_SPM_COOKIE_0		ULL(0)
+#define PLAT_SPM_COOKIE_1		ULL(0)
+
+/* Total number of memory regions with distinct properties */
+#define PLAT_SP_IMAGE_NUM_MEM_REGIONS	6
+
+#define PLAT_SP_IMAGE_MMAP_REGIONS	30
+#define PLAT_SP_IMAGE_MAX_XLAT_TABLES	20
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME	"sp_xlat_table"
+
+#define PLAT_SQ_UART1_BASE		PLAT_SQ_BOOT_UART_BASE
+#define PLAT_SQ_UART1_SIZE		ULL(0x1000)
+#define PLAT_SQ_UART1_MMAP		MAP_REGION_FLAT(PLAT_SQ_UART1_BASE, \
+							PLAT_SQ_UART1_SIZE, \
+							MT_DEVICE | MT_RW | \
+							MT_NS | MT_PRIVILEGED)
+
+#define PLAT_SQ_PERIPH_BASE		0x50000000
+#define PLAT_SQ_PERIPH_SIZE		ULL(0x8000000)
+#define PLAT_SQ_PERIPH_MMAP		MAP_REGION_FLAT(PLAT_SQ_PERIPH_BASE, \
+							PLAT_SQ_PERIPH_SIZE, \
+							MT_DEVICE | MT_RW | \
+							MT_NS | MT_USER)
+
+#define PLAT_SQ_FLASH_BASE		0x08000000
+#define PLAT_SQ_FLASH_SIZE		ULL(0x8000000)
+#define PLAT_SQ_FLASH_MMAP		MAP_REGION_FLAT(PLAT_SQ_FLASH_BASE, \
+							PLAT_SQ_FLASH_SIZE, \
+							MT_DEVICE | MT_RW | \
+							MT_NS | MT_USER)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/socionext/synquacer/include/sq_common.h b/plat/socionext/synquacer/include/sq_common.h
new file mode 100644
index 0000000..a985822
--- /dev/null
+++ b/plat/socionext/synquacer/include/sq_common.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_COMMON_H
+#define SQ_COMMON_H
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+struct draminfo {
+	uint32_t	num_regions;
+	uint32_t	reserved;
+	uint64_t	base1;
+	uint64_t	size1;
+	uint64_t	base2;
+	uint64_t	size2;
+	uint64_t	base3;
+	uint64_t	size3;
+};
+
+uint32_t sq_scp_get_draminfo(struct draminfo *info);
+
+void plat_sq_pwrc_setup(void);
+
+void plat_sq_interconnect_init(void);
+void plat_sq_interconnect_enter_coherency(void);
+void plat_sq_interconnect_exit_coherency(void);
+
+unsigned int sq_calc_core_pos(u_register_t mpidr);
+
+void sq_gic_driver_init(void);
+void sq_gic_init(void);
+void sq_gic_cpuif_enable(void);
+void sq_gic_cpuif_disable(void);
+void sq_gic_pcpu_init(void);
+
+void sq_mmap_setup(uintptr_t total_base, size_t total_size,
+		   const struct mmap_region *mmap);
+
+/* SCMI API for power management by SCP */
+void sq_scmi_off(const struct psci_power_state *target_state);
+void sq_scmi_on(u_register_t mpidr);
+void __dead2 sq_scmi_sys_reboot(void);
+void __dead2 sq_scmi_system_off(int state);
+/* SCMI API for vendor specific protocol */
+uint32_t sq_scmi_get_draminfo(struct draminfo *info);
+
+#endif /* SQ_COMMON_H */
diff --git a/plat/socionext/synquacer/platform.mk b/plat/socionext/synquacer/platform.mk
new file mode 100644
index 0000000..fe1448f
--- /dev/null
+++ b/plat/socionext/synquacer/platform.mk
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+override RESET_TO_BL31			:= 1
+override PROGRAMMABLE_RESET_ADDRESS	:= 1
+override USE_COHERENT_MEM		:= 1
+override SEPARATE_CODE_AND_RODATA	:= 1
+override ENABLE_SVE_FOR_NS		:= 0
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_855873		:= 1
+# Enable SCMI support
+SQ_USE_SCMI_DRIVER		?= 0
+
+# Libraries
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_PATH		:=	plat/socionext/synquacer
+PLAT_INCLUDES		:=	-I$(PLAT_PATH)/include		\
+				-I$(PLAT_PATH)/drivers/scpi	\
+				-I$(PLAT_PATH)/drivers/mhu \
+				-Idrivers/arm/css/scmi \
+				-Idrivers/arm/css/scmi/vendor
+
+PLAT_BL_COMMON_SOURCES	+=	$(PLAT_PATH)/sq_helpers.S		\
+				drivers/arm/pl011/aarch64/pl011_console.S \
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES		+=	drivers/arm/ccn/ccn.c			\
+				drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				$(PLAT_PATH)/sq_bl31_setup.c		\
+				$(PLAT_PATH)/sq_ccn.c			\
+				$(PLAT_PATH)/sq_topology.c		\
+				$(PLAT_PATH)/sq_psci.c			\
+				$(PLAT_PATH)/sq_gicv3.c			\
+				$(PLAT_PATH)/sq_xlat_setup.c	\
+				$(PLAT_PATH)/drivers/scp/sq_scp.c
+
+ifeq (${SQ_USE_SCMI_DRIVER},0)
+BL31_SOURCES		+=	$(PLAT_PATH)/drivers/scpi/sq_scpi.c	\
+				$(PLAT_PATH)/drivers/mhu/sq_mhu.c
+else
+BL31_SOURCES		+=	$(PLAT_PATH)/drivers/scp/sq_scmi.c		\
+				drivers/arm/css/scmi/scmi_common.c		\
+				drivers/arm/css/scmi/scmi_pwr_dmn_proto.c	\
+				drivers/arm/css/scmi/scmi_sys_pwr_proto.c	\
+				drivers/arm/css/scmi/vendor/scmi_sq.c	\
+				drivers/arm/css/mhu/css_mhu_doorbell.c
+endif
+
+ifeq (${ENABLE_SPM},1)
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+BL31_SOURCES		+=	$(PLAT_PATH)/sq_spm.c
+endif
+
+ifeq (${SQ_USE_SCMI_DRIVER},1)
+$(eval $(call add_define,SQ_USE_SCMI_DRIVER))
+endif
diff --git a/plat/socionext/synquacer/sq_bl31_setup.c b/plat/socionext/synquacer/sq_bl31_setup.c
new file mode 100644
index 0000000..c78fe91
--- /dev/null
+++ b/plat/socionext/synquacer/sq_bl31_setup.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <lib/mmio.h>
+#include <sq_common.h>
+
+static console_pl011_t console;
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START);
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__,   SPM_SHIM_EXCEPTIONS_END);
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_LMA__,   SPM_SHIM_EXCEPTIONS_LMA);
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type));
+	return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t sq_get_spsr_for_bl32_entry(void)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t sq_get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	/* Initialize the console to provide early debug support */
+	(void)console_pl011_register(PLAT_SQ_BOOT_UART_BASE,
+			       PLAT_SQ_BOOT_UART_CLK_IN_HZ,
+			       SQ_CONSOLE_BAUDRATE, &console);
+
+	console_set_scope(&console.console, CONSOLE_FLAG_BOOT |
+			  CONSOLE_FLAG_RUNTIME);
+
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(arg0 == 0U);
+	assert(arg1 == 0U);
+
+	/* Initialize power controller before setting up topology */
+	plat_sq_pwrc_setup();
+
+#ifdef SPD_opteed
+	struct draminfo di = {0};
+
+	sq_scp_get_draminfo(&di);
+
+	/*
+	 * Check if OP-TEE has been loaded in Secure RAM allocated
+	 * from DRAM1 region
+	 */
+	if ((di.base1 + di.size1) <= BL32_BASE) {
+		NOTICE("OP-TEE has been loaded by SCP firmware\n");
+		/* Populate entry point information for BL32 */
+		SET_PARAM_HEAD(&bl32_image_ep_info,
+					PARAM_EP,
+					VERSION_1,
+					0);
+		SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+		bl32_image_ep_info.pc = BL32_BASE;
+		bl32_image_ep_info.spsr = sq_get_spsr_for_bl32_entry();
+	} else {
+		NOTICE("OP-TEE has not been loaded by SCP firmware\n");
+	}
+#endif /* SPD_opteed */
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell BL31 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	bl33_image_ep_info.pc = PRELOADED_BL33_BASE;
+	bl33_image_ep_info.spsr = sq_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+
+static void sq_configure_sys_timer(void)
+{
+	unsigned int reg_val;
+
+	reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
+	reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
+	reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
+	mmio_write_32(SQ_SYS_TIMCTL_BASE +
+		      CNTACR_BASE(PLAT_SQ_NSTIMER_FRAME_ID), reg_val);
+
+	reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_SQ_NSTIMER_FRAME_ID));
+	mmio_write_32(SQ_SYS_TIMCTL_BASE + CNTNSAR, reg_val);
+}
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the CCN interconnect */
+	plat_sq_interconnect_init();
+	plat_sq_interconnect_enter_coherency();
+
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	sq_gic_driver_init();
+	sq_gic_init();
+
+	/* Enable and initialize the System level generic timer */
+	mmio_write_32(SQ_SYS_CNTCTL_BASE + CNTCR_OFF,
+			CNTCR_FCREQ(0U) | CNTCR_EN);
+
+	/* Allow access to the System counter timer module */
+	sq_configure_sys_timer();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	struct draminfo *di = (struct draminfo *)(unsigned long)DRAMINFO_BASE;
+
+	sq_scp_get_draminfo(di);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	static const mmap_region_t secure_partition_mmap[] = {
+#if ENABLE_SPM && SPM_MM
+		MAP_REGION_FLAT(PLAT_SPM_BUF_BASE,
+				PLAT_SPM_BUF_SIZE,
+				MT_RW_DATA | MT_SECURE),
+		MAP_REGION_FLAT(PLAT_SQ_SP_PRIV_BASE,
+				PLAT_SQ_SP_PRIV_SIZE,
+				MT_RW_DATA | MT_SECURE),
+#endif
+		{0},
+	};
+
+	sq_mmap_setup(BL31_BASE, BL31_SIZE, secure_partition_mmap);
+	enable_mmu_el3(XLAT_TABLE_NC);
+
+#if ENABLE_SPM && SPM_MM
+	memcpy((void *)SPM_SHIM_EXCEPTIONS_START,
+	       (void *)SPM_SHIM_EXCEPTIONS_LMA,
+	       (uintptr_t)SPM_SHIM_EXCEPTIONS_END -
+	       (uintptr_t)SPM_SHIM_EXCEPTIONS_START);
+#endif
+}
+
+void bl31_plat_enable_mmu(uint32_t flags)
+{
+	enable_mmu_el3(flags | XLAT_TABLE_NC);
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	unsigned int counter_base_frequency;
+
+	/* Read the frequency from Frequency modes table */
+	counter_base_frequency = mmio_read_32(SQ_SYS_CNTCTL_BASE + CNTFID_OFF);
+
+	/* The first entry of the frequency modes table must not be 0 */
+	if (counter_base_frequency == 0)
+		panic();
+
+	return counter_base_frequency;
+}
diff --git a/plat/socionext/synquacer/sq_ccn.c b/plat/socionext/synquacer/sq_ccn.c
new file mode 100644
index 0000000..fa6ea87
--- /dev/null
+++ b/plat/socionext/synquacer/sq_ccn.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/ccn.h>
+
+static const unsigned char master_to_rn_id_map[] = {
+	PLAT_SQ_CLUSTER_TO_CCN_ID_MAP
+};
+
+static const ccn_desc_t sq_ccn_desc = {
+	.periphbase = PLAT_SQ_CCN_BASE,
+	.num_masters = ARRAY_SIZE(master_to_rn_id_map),
+	.master_to_rn_id_map = master_to_rn_id_map
+};
+
+/******************************************************************************
+ * Helper function to initialize SQ CCN driver.
+ *****************************************************************************/
+void plat_sq_interconnect_init(void)
+{
+	ccn_init(&sq_ccn_desc);
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_sq_interconnect_enter_coherency(void)
+{
+	ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_sq_interconnect_exit_coherency(void)
+{
+	ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/socionext/synquacer/sq_gicv3.c b/plat/socionext/synquacer/sq_gicv3.c
new file mode 100644
index 0000000..05318e3
--- /dev/null
+++ b/plat/socionext/synquacer/sq_gicv3.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#include "sq_common.h"
+
+static uintptr_t sq_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t sq_interrupt_props[] = {
+	/* G0 interrupts */
+
+	/* SGI0 */
+	INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+			GIC_INTR_CFG_EDGE),
+	/* SGI6 */
+	INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+			GIC_INTR_CFG_EDGE),
+
+	/* G1S interrupts */
+
+	/* Timer */
+	INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_LEVEL),
+	/* SGI1 */
+	INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_EDGE),
+	/* SGI2 */
+	INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_EDGE),
+	/* SGI3 */
+	INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_EDGE),
+	/* SGI4 */
+	INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_EDGE),
+	/* SGI5 */
+	INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_EDGE),
+	/* SGI7 */
+	INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+			GIC_INTR_CFG_EDGE)
+};
+
+static unsigned int sq_mpidr_to_core_pos(u_register_t mpidr)
+{
+	return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const struct gicv3_driver_data sq_gic_driver_data = {
+		.gicd_base = PLAT_SQ_GICD_BASE,
+		.gicr_base = PLAT_SQ_GICR_BASE,
+		.interrupt_props = sq_interrupt_props,
+		.interrupt_props_num = ARRAY_SIZE(sq_interrupt_props),
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = sq_rdistif_base_addrs,
+		.mpidr_to_core_pos = sq_mpidr_to_core_pos,
+};
+
+void sq_gic_driver_init(void)
+{
+	gicv3_driver_init(&sq_gic_driver_data);
+}
+
+void sq_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void sq_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void sq_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void sq_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/socionext/synquacer/sq_helpers.S b/plat/socionext/synquacer/sq_helpers.S
new file mode 100644
index 0000000..558aa15
--- /dev/null
+++ b/plat/socionext/synquacer/sq_helpers.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+	.global	sq_calc_core_pos
+	.global	plat_my_core_pos
+	.global	platform_mem_init
+	.global	plat_is_my_cpu_primary
+	.global plat_secondary_cold_boot_setup
+	.global	plat_crash_console_init
+	.global	plat_crash_console_putc
+	.global	plat_crash_console_flush
+
+/*
+ * unsigned int sq_calc_core_pos(u_register_t mpidr)
+ * core_pos = (cluster_id * max_cpus_per_cluster) + core_id
+ */
+func sq_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, lsr #7
+	ret
+endfunc sq_calc_core_pos
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	sq_calc_core_pos
+endfunc plat_my_core_pos
+
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+/*
+ * Secondary CPUs are placed in a holding pen, waiting for their mailbox
+ * to be populated. Note that all CPUs share the same mailbox ; therefore,
+ * populating it will release all CPUs from their holding pen. If
+ * finer-grained control is needed then this should be handled in the
+ * code that secondary CPUs jump to.
+ */
+func plat_secondary_cold_boot_setup
+	ldr	x0, sq_sec_entrypoint
+
+	/* Wait until the mailbox gets populated */
+poll_mailbox:
+	cbz	x0, 1f
+	br	x0
+1:
+	wfe
+	b	poll_mailbox
+endfunc plat_secondary_cold_boot_setup
+
+/*
+ * Find out whether the current cpu is the primary
+ * cpu (applicable only after a cold boot)
+ */
+func plat_is_my_cpu_primary
+	mov	x9, x30
+	bl	plat_my_core_pos
+	ldr	x1, =SQ_BOOT_CFG_ADDR
+	ldr	x1, [x1]
+	ubfx	x1, x1, #PLAT_SQ_PRIMARY_CPU_SHIFT, \
+			#PLAT_SQ_PRIMARY_CPU_BIT_WIDTH
+	cmp	x0, x1
+	cset	w0, eq
+	ret	x9
+endfunc plat_is_my_cpu_primary
+
+/*
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0, x1, x2
+ */
+func plat_crash_console_init
+	mov_imm x0, PLAT_SQ_BOOT_UART_BASE
+	mov_imm x1, PLAT_SQ_BOOT_UART_CLK_IN_HZ
+	mov_imm x2, SQ_CONSOLE_BAUDRATE
+	b	console_pl011_core_init
+endfunc plat_crash_console_init
+
+/*
+ * int plat_crash_console_putc(int c)
+ * Function to print a character on the crash
+ * console without a C Runtime.
+ * Clobber list : x1, x2
+ */
+func plat_crash_console_putc
+	mov_imm	x1, PLAT_SQ_BOOT_UART_BASE
+	b	console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+/*
+ * int plat_crash_console_flush(int c)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : return -1 on error else return 0.
+ * Clobber list : x0, x1
+ */
+func plat_crash_console_flush
+	mov_imm	x0, PLAT_SQ_BOOT_UART_BASE
+	b	console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/socionext/synquacer/sq_psci.c b/plat/socionext/synquacer/sq_psci.c
new file mode 100644
index 0000000..731b19a
--- /dev/null
+++ b/plat/socionext/synquacer/sq_psci.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/cassert.h>
+#include <lib/psci/psci.h>
+
+#include <sq_common.h>
+#include "sq_scpi.h"
+
+uintptr_t sq_sec_entrypoint;
+
+int sq_pwr_domain_on(u_register_t mpidr)
+{
+#if SQ_USE_SCMI_DRIVER
+	sq_scmi_on(mpidr);
+#else
+	/*
+	 * SCP takes care of powering up parent power domains so we
+	 * only need to care about level 0
+	 */
+	scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
+				 scpi_power_on);
+#endif
+
+	return PSCI_E_SUCCESS;
+}
+
+static void sq_pwr_domain_on_finisher_common(
+		const psci_power_state_t *target_state)
+{
+	assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
+
+	/*
+	 * Perform the common cluster specific operations i.e enable coherency
+	 * if this cluster was off.
+	 */
+	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
+		plat_sq_interconnect_enter_coherency();
+}
+
+void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* Assert that the system power domain need not be initialized */
+	assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
+
+	sq_pwr_domain_on_finisher_common(target_state);
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	sq_gic_pcpu_init();
+
+	/* Enable the gic cpu interface */
+	sq_gic_cpuif_enable();
+}
+
+#if !SQ_USE_SCMI_DRIVER
+static void sq_power_down_common(const psci_power_state_t *target_state)
+{
+	uint32_t cluster_state = scpi_power_on;
+	uint32_t system_state = scpi_power_on;
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	sq_gic_cpuif_disable();
+
+	/* Check if power down at system power domain level is requested */
+	if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
+		system_state = scpi_power_retention;
+
+	/* Cluster is to be turned off, so disable coherency */
+	if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
+		plat_sq_interconnect_exit_coherency();
+		cluster_state = scpi_power_off;
+	}
+
+	/*
+	 * Ask the SCP to power down the appropriate components depending upon
+	 * their state.
+	 */
+	scpi_set_sq_power_state(read_mpidr_el1(),
+				 scpi_power_off,
+				 cluster_state,
+				 system_state);
+}
+#endif
+
+void sq_pwr_domain_off(const psci_power_state_t *target_state)
+{
+#if SQ_USE_SCMI_DRIVER
+	sq_scmi_off(target_state);
+#else
+	sq_power_down_common(target_state);
+#endif
+}
+
+void __dead2 sq_system_off(void)
+{
+	volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
+
+	/* set PD[9] high to power off the system */
+	gpio[5] |= 0x2;		/* set output */
+	gpio[1] |= 0x2;		/* set high */
+	dmbst();
+
+	generic_delay_timer_init();
+
+	mdelay(1);
+
+	while (1) {
+		gpio[1] &= ~0x2;	/* set low */
+		dmbst();
+
+		mdelay(1);
+
+		gpio[1] |= 0x2;		/* set high */
+		dmbst();
+
+		mdelay(100);
+	}
+
+	wfi();
+	ERROR("SQ System Off: operation not handled.\n");
+	panic();
+}
+
+void __dead2 sq_system_reset(void)
+{
+#if SQ_USE_SCMI_DRIVER
+	sq_scmi_sys_reboot();
+#else
+	uint32_t response;
+
+	/* Send the system reset request to the SCP */
+	response = scpi_sys_power_state(scpi_system_reboot);
+
+	if (response != SCP_OK) {
+		ERROR("SQ System Reset: SCP error %u.\n", response);
+		panic();
+	}
+	wfi();
+	ERROR("SQ System Reset: operation not handled.\n");
+	panic();
+#endif
+}
+
+void sq_cpu_standby(plat_local_state_t cpu_state)
+{
+	unsigned int scr;
+
+	assert(cpu_state == SQ_LOCAL_STATE_RET);
+
+	scr = read_scr_el3();
+	/* Enable PhysicalIRQ bit for NS world to wake the CPU */
+	write_scr_el3(scr | SCR_IRQ_BIT);
+	isb();
+	dsb();
+	wfi();
+
+	/*
+	 * Restore SCR to the original value, synchronisation of scr_el3 is
+	 * done by eret while el3_exit to save some execution cycles.
+	 */
+	write_scr_el3(scr);
+}
+
+const plat_psci_ops_t sq_psci_ops = {
+	.pwr_domain_on		= sq_pwr_domain_on,
+	.pwr_domain_off		= sq_pwr_domain_off,
+	.pwr_domain_on_finish	= sq_pwr_domain_on_finish,
+	.cpu_standby		= sq_cpu_standby,
+	.system_off		= sq_system_off,
+	.system_reset		= sq_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	sq_sec_entrypoint = sec_entrypoint;
+	flush_dcache_range((uint64_t)&sq_sec_entrypoint,
+			   sizeof(sq_sec_entrypoint));
+
+	*psci_ops = &sq_psci_ops;
+
+	return 0;
+}
diff --git a/plat/socionext/synquacer/sq_spm.c b/plat/socionext/synquacer/sq_spm.c
new file mode 100644
index 0000000..01cce17
--- /dev/null
+++ b/plat/socionext/synquacer/sq_spm.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/secure_partition.h>
+
+static const mmap_region_t plat_arm_secure_partition_mmap[] = {
+	PLAT_SQ_FLASH_MMAP,
+	PLAT_SQ_UART1_MMAP,
+	PLAT_SQ_PERIPH_MMAP,
+	PLAT_SQ_SP_IMAGE_MMAP,
+	PLAT_SP_IMAGE_NS_BUF_MMAP,
+	PLAT_SQ_SP_IMAGE_RW_MMAP,
+	PLAT_SPM_SPM_BUF_EL0_MMAP,
+	{0}
+};
+
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static secure_partition_mp_info_t sp_mp_info[] = {
+	{0x80000000, 0}, {0x80000001, 0}, {0x80000100, 0}, {0x80000101, 0},
+	{0x80000200, 0}, {0x80000201, 0}, {0x80000300, 0}, {0x80000301, 0},
+	{0x80000400, 0}, {0x80000401, 0}, {0x80000500, 0}, {0x80000501, 0},
+	{0x80000600, 0}, {0x80000601, 0}, {0x80000700, 0}, {0x80000701, 0},
+	{0x80000800, 0}, {0x80000801, 0}, {0x80000900, 0}, {0x80000901, 0},
+	{0x80000a00, 0}, {0x80000a01, 0}, {0x80000b00, 0}, {0x80000b01, 0},
+};
+
+const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = {
+	.h.type			= PARAM_SP_IMAGE_BOOT_INFO,
+	.h.version		= VERSION_1,
+	.h.size			= sizeof(secure_partition_boot_info_t),
+	.h.attr			= 0,
+	.sp_mem_base		= BL32_BASE,
+	.sp_mem_limit		= BL32_LIMIT,
+	.sp_image_base		= BL32_BASE,
+	.sp_stack_base		= PLAT_SP_IMAGE_STACK_BASE,
+	.sp_heap_base		= PLAT_SQ_SP_HEAP_BASE,
+	.sp_ns_comm_buf_base	= PLAT_SP_IMAGE_NS_BUF_BASE,
+	.sp_shared_buf_base	= PLAT_SPM_BUF_BASE,
+	.sp_image_size		= PLAT_SQ_SP_IMAGE_SIZE,
+	.sp_pcpu_stack_size	= PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+	.sp_heap_size		= PLAT_SQ_SP_HEAP_SIZE,
+	.sp_ns_comm_buf_size	= PLAT_SP_IMAGE_NS_BUF_SIZE,
+	.sp_shared_buf_size	= PLAT_SPM_BUF_SIZE,
+	.num_sp_mem_regions	= PLAT_SP_IMAGE_NUM_MEM_REGIONS,
+	.num_cpus		= PLATFORM_CORE_COUNT,
+	.mp_info		= sp_mp_info,
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+	return plat_arm_secure_partition_mmap;
+}
+
+const struct secure_partition_boot_info *plat_get_secure_partition_boot_info(
+		void *cookie)
+{
+	return &plat_arm_secure_partition_boot_info;
+}
+
+static ehf_pri_desc_t sq_exceptions[] = {
+	EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
+};
+EHF_REGISTER_PRIORITIES(sq_exceptions, ARRAY_SIZE(sq_exceptions), PLAT_PRI_BITS);
diff --git a/plat/socionext/synquacer/sq_topology.c b/plat/socionext/synquacer/sq_topology.c
new file mode 100644
index 0000000..359997a
--- /dev/null
+++ b/plat/socionext/synquacer/sq_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include <sq_common.h>
+
+unsigned char sq_pd_tree_desc[PLAT_CLUSTER_COUNT + 1];
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cluster_id >= PLAT_CLUSTER_COUNT)
+		return -1;
+
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cpu_id >= PLAT_MAX_CORES_PER_CLUSTER)
+		return -1;
+
+	return sq_calc_core_pos(mpidr);
+}
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	int i;
+
+	sq_pd_tree_desc[0] = PLAT_CLUSTER_COUNT;
+
+	for (i = 0; i < PLAT_CLUSTER_COUNT; i++)
+		sq_pd_tree_desc[i + 1] = PLAT_MAX_CORES_PER_CLUSTER;
+
+	return sq_pd_tree_desc;
+}
diff --git a/plat/socionext/synquacer/sq_xlat_setup.c b/plat/socionext/synquacer/sq_xlat_setup.c
new file mode 100644
index 0000000..5d1669d
--- /dev/null
+++ b/plat/socionext/synquacer/sq_xlat_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#define SQ_REG_REGION_BASE	0x20000000ULL
+#define SQ_REG_REGION_SIZE	0x60000000ULL
+
+void sq_mmap_setup(uintptr_t total_base, size_t total_size,
+			 const struct mmap_region *mmap)
+{
+	VERBOSE("Trusted RAM seen by this BL image: %p - %p\n",
+		(void *)total_base, (void *)(total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_NON_CACHEABLE | MT_RW | MT_SECURE);
+
+	/* remap the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *)BL_CODE_BASE, (void *)BL_CODE_END);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			round_up(BL_CODE_END, PAGE_SIZE) - BL_CODE_BASE,
+			MT_NON_CACHEABLE | MT_RO | MT_SECURE);
+
+	/* Re-map the read-only data section */
+	VERBOSE("Read-only data region: %p - %p\n",
+		(void *)BL_RO_DATA_BASE, (void *)BL_RO_DATA_END);
+	mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
+			round_up(BL_RO_DATA_END, PAGE_SIZE) - BL_RO_DATA_BASE,
+			(MT_NON_CACHEABLE | MT_RO | MT_EXECUTE_NEVER |
+			 MT_SECURE));
+
+	/* remap the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *)BL_COHERENT_RAM_BASE, (void *)BL_COHERENT_RAM_END);
+	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/* register region */
+	mmap_add_region(SQ_REG_REGION_BASE, SQ_REG_REGION_BASE,
+			SQ_REG_REGION_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/* additional regions if needed */
+	if (mmap)
+		mmap_add(mmap);
+
+	init_xlat_tables();
+}
diff --git a/plat/socionext/uniphier/include/plat_macros.S b/plat/socionext/uniphier/include/plat_macros.S
new file mode 100644
index 0000000..d6d2579
--- /dev/null
+++ b/plat/socionext/uniphier/include/plat_macros.S
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/socionext/uniphier/include/platform_def.h b/plat/socionext/uniphier/include/platform_def.h
new file mode 100644
index 0000000..d4db3f5
--- /dev/null
+++ b/plat/socionext/uniphier/include/platform_def.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#define PLATFORM_STACK_SIZE		0x1000
+
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << (CACHE_WRITEBACK_SHIFT))
+
+/* topology */
+#define UNIPHIER_MAX_CPUS_PER_CLUSTER	4
+#define UNIPHIER_CLUSTER_COUNT		2
+
+#define PLATFORM_CORE_COUNT		\
+	((UNIPHIER_MAX_CPUS_PER_CLUSTER) * (UNIPHIER_CLUSTER_COUNT))
+
+#define PLAT_MAX_PWR_LVL		U(1)
+
+#define PLAT_MAX_OFF_STATE		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+
+#define BL2_BASE			ULL(0x80000000)
+#define BL2_LIMIT			ULL(0x80080000)
+
+/* 0x80080000-0x81000000: reserved for DSP */
+
+#define UNIPHIER_SEC_DRAM_BASE		0x81000000ULL
+#define UNIPHIER_SEC_DRAM_LIMIT		0x82000000ULL
+#define UNIPHIER_SEC_DRAM_SIZE		((UNIPHIER_SEC_DRAM_LIMIT) - \
+					 (UNIPHIER_SEC_DRAM_BASE))
+
+#define BL31_BASE			ULL(0x81000000)
+#define BL31_LIMIT			ULL(0x81080000)
+
+#define BL32_BASE			ULL(0x81080000)
+#define BL32_LIMIT			ULL(0x81180000)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+
+#define PLAT_XLAT_TABLES_DYNAMIC	1
+#define MAX_XLAT_TABLES			7
+#define MAX_MMAP_REGIONS		7
+
+#define MAX_IO_HANDLES			2
+#define MAX_IO_DEVICES			2
+#define MAX_IO_BLOCK_DEVICES		U(1)
+
+#define TSP_SEC_MEM_BASE		(BL32_BASE)
+#define TSP_SEC_MEM_SIZE		((BL32_LIMIT) - (BL32_BASE))
+#define TSP_IRQ_SEC_PHY_TIMER		29
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
new file mode 100644
index 0000000..d974584
--- /dev/null
+++ b/plat/socionext/uniphier/platform.mk
@@ -0,0 +1,123 @@
+#
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+override BL2_AT_EL3			:= 1
+override COLD_BOOT_SINGLE_CPU		:= 1
+override PROGRAMMABLE_RESET_ADDRESS	:= 1
+override USE_COHERENT_MEM		:= 1
+override ENABLE_SVE_FOR_NS		:= 0
+
+# Cortex-A53 revision r0p4-51rel0
+# needed for LD20, unneeded for LD11, PXs3 (no ACE)
+ERRATA_A53_855873		:= 1
+
+FIP_ALIGN			:= 512
+
+ifeq ($(NEED_BL32),yes)
+$(eval $(call add_define,UNIPHIER_LOAD_BL32))
+endif
+
+# Libraries
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_PATH		:=	plat/socionext/uniphier
+PLAT_INCLUDES		:=	-I$(PLAT_PATH)/include
+
+# common sources for BL2, BL31 (and BL32 if SPD=tspd)
+PLAT_BL_COMMON_SOURCES	+=	plat/common/aarch64/crash_console_helpers.S \
+				$(PLAT_PATH)/uniphier_console.S		\
+				$(PLAT_PATH)/uniphier_console_setup.c	\
+				$(PLAT_PATH)/uniphier_helpers.S		\
+				$(PLAT_PATH)/uniphier_soc_info.c	\
+				$(PLAT_PATH)/uniphier_xlat_setup.c	\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL2_SOURCES		+=	common/desc_image_load.c		\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				$(PLAT_PATH)/uniphier_bl2_setup.c	\
+				$(PLAT_PATH)/uniphier_boot_device.c	\
+				$(PLAT_PATH)/uniphier_emmc.c		\
+				$(PLAT_PATH)/uniphier_image_desc.c	\
+				$(PLAT_PATH)/uniphier_io_storage.c	\
+				$(PLAT_PATH)/uniphier_nand.c		\
+				$(PLAT_PATH)/uniphier_scp.c		\
+				$(PLAT_PATH)/uniphier_usb.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				$(PLAT_PATH)/uniphier_bl31_setup.c	\
+				$(PLAT_PATH)/uniphier_cci.c		\
+				$(PLAT_PATH)/uniphier_gicv3.c		\
+				$(PLAT_PATH)/uniphier_psci.c		\
+				$(PLAT_PATH)/uniphier_scp.c		\
+				$(PLAT_PATH)/uniphier_smp.S		\
+				$(PLAT_PATH)/uniphier_syscnt.c		\
+				$(PLAT_PATH)/uniphier_topology.c
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+BL2_SOURCES		+=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c		\
+				plat/common/tbbr/plat_tbbr.c		\
+				$(PLAT_PATH)/uniphier_rotpk.S		\
+				$(PLAT_PATH)/uniphier_tbbr.c
+
+ROT_KEY			= $(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH		= $(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl2/uniphier_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+
+endif
+
+ifeq (${FIP_GZIP},1)
+
+include lib/zlib/zlib.mk
+
+BL2_SOURCES		+=	common/image_decompress.c		\
+				$(ZLIB_SOURCES)
+
+$(eval $(call add_define,UNIPHIER_DECOMPRESS_GZIP))
+
+# compress all images loaded by BL2
+SCP_BL2_PRE_TOOL_FILTER	:= GZIP
+BL31_PRE_TOOL_FILTER	:= GZIP
+BL32_PRE_TOOL_FILTER	:= GZIP
+BL33_PRE_TOOL_FILTER	:= GZIP
+
+endif
+
+.PHONY: bl2_gzip
+bl2_gzip: $(BUILD_PLAT)/bl2.bin.gz
+%.gz: %
+	@echo "  GZIP    $@"
+	$(Q)gzip -n -f -9 $< --stdout > $@
diff --git a/plat/socionext/uniphier/tsp/tsp-uniphier.mk b/plat/socionext/uniphier/tsp/tsp-uniphier.mk
new file mode 100644
index 0000000..54d4f51
--- /dev/null
+++ b/plat/socionext/uniphier/tsp/tsp-uniphier.mk
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES		+=	plat/common/plat_gicv3.c		\
+				plat/common/aarch64/platform_mp_stack.S \
+				$(PLAT_PATH)/tsp/uniphier_tsp_setup.c
diff --git a/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c b/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c
new file mode 100644
index 0000000..0b232e0
--- /dev/null
+++ b/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+
+#include "../uniphier.h"
+
+#define BL32_SIZE		((BL32_END) - (BL32_BASE))
+
+void tsp_early_platform_setup(void)
+{
+	uniphier_console_setup();
+}
+
+void tsp_platform_setup(void)
+{
+}
+
+void tsp_plat_arch_setup(void)
+{
+	uniphier_mmap_setup(BL32_BASE, BL32_SIZE, NULL);
+	enable_mmu_el1(0);
+}
diff --git a/plat/socionext/uniphier/uniphier.h b/plat/socionext/uniphier/uniphier.h
new file mode 100644
index 0000000..648c2b9
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UNIPHIER_H
+#define UNIPHIER_H
+
+#include <stdint.h>
+#include <string.h>
+
+unsigned int uniphier_get_soc_type(void);
+unsigned int uniphier_get_soc_model(void);
+unsigned int uniphier_get_soc_revision(void);
+unsigned int uniphier_get_soc_id(void);
+
+#define UNIPHIER_SOC_LD11		0
+#define UNIPHIER_SOC_LD20		1
+#define UNIPHIER_SOC_PXS3		2
+#define UNIPHIER_SOC_UNKNOWN		0xffffffff
+
+unsigned int uniphier_get_boot_device(unsigned int soc);
+
+#define UNIPHIER_BOOT_DEVICE_EMMC	0
+#define UNIPHIER_BOOT_DEVICE_NAND	1
+#define UNIPHIER_BOOT_DEVICE_NOR	2
+#define UNIPHIER_BOOT_DEVICE_USB	3
+#define UNIPHIER_BOOT_DEVICE_RSV	0xffffffff
+
+unsigned int uniphier_get_boot_master(unsigned int soc);
+
+#define UNIPHIER_BOOT_MASTER_THIS	0
+#define UNIPHIER_BOOT_MASTER_SCP	1
+#define UNIPHIER_BOOT_MASTER_EXT	2
+
+void uniphier_console_setup(void);
+
+int uniphier_emmc_init(uintptr_t *block_dev_spec);
+int uniphier_nand_init(uintptr_t *block_dev_spec);
+int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec);
+
+int uniphier_io_setup(unsigned int soc);
+
+struct image_info;
+struct image_info *uniphier_get_image_info(unsigned int image_id);
+
+int uniphier_scp_is_running(void);
+void uniphier_scp_start(void);
+void uniphier_scp_open_com(void);
+void uniphier_scp_system_off(void);
+void uniphier_scp_system_reset(void);
+
+struct mmap_region;
+void uniphier_mmap_setup(uintptr_t total_base, size_t total_size,
+			 const struct mmap_region *mmap);
+
+void uniphier_cci_init(unsigned int soc);
+void uniphier_cci_enable(void);
+void uniphier_cci_disable(void);
+
+void uniphier_gic_driver_init(unsigned int soc);
+void uniphier_gic_init(void);
+void uniphier_gic_cpuif_enable(void);
+void uniphier_gic_cpuif_disable(void);
+void uniphier_gic_pcpu_init(void);
+
+unsigned int uniphier_calc_core_pos(u_register_t mpidr);
+
+#define UNIPHIER_NS_DRAM_BASE		0x84000000
+#define UNIPHIER_NS_DRAM_LIMIT		0x85000000
+#define UNIPHIER_NS_DRAM_SIZE		((UNIPHIER_NS_DRAM_LIMIT) - \
+					 (UNIPHIER_NS_DRAM_BASE))
+
+#define UNIPHIER_BL33_BASE		(UNIPHIER_NS_DRAM_BASE)
+#define UNIPHIER_BL33_MAX_SIZE		0x00100000
+
+#define UNIPHIER_SCP_BASE		((UNIPHIER_BL33_BASE) + \
+					 (UNIPHIER_BL33_MAX_SIZE))
+#define UNIPHIER_SCP_MAX_SIZE		0x00020000
+
+#define UNIPHIER_BLOCK_BUF_BASE		((UNIPHIER_SCP_BASE) + \
+					 (UNIPHIER_SCP_MAX_SIZE))
+#define UNIPHIER_BLOCK_BUF_SIZE		0x00100000
+
+#define UNIPHIER_IMAGE_BUF_BASE		((UNIPHIER_BLOCK_BUF_BASE) + \
+					 (UNIPHIER_BLOCK_BUF_SIZE))
+#define UNIPHIER_IMAGE_BUF_SIZE		((UNIPHIER_NS_DRAM_LIMIT) - \
+					 (UNIPHIER_IMAGE_BUF_BASE))
+
+#endif /* UNIPHIER_H */
diff --git a/plat/socionext/uniphier/uniphier_bl2_setup.c b/plat/socionext/uniphier/uniphier_bl2_setup.c
new file mode 100644
index 0000000..787b3ac
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl2_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/image_decompress.h>
+#include <drivers/io/io_storage.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+#include <tf_gunzip.h>
+#endif
+
+#include "uniphier.h"
+
+#define BL2_SIZE		((BL2_END) - (BL2_BASE))
+
+static int uniphier_bl2_kick_scp;
+
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+				  u_register_t x2, u_register_t x3)
+{
+	uniphier_console_setup();
+}
+
+static const struct mmap_region uniphier_bl2_mmap[] = {
+	/* for BL31, BL32 */
+	MAP_REGION_FLAT(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+	/* for SCP, BL33 */
+	MAP_REGION_FLAT(UNIPHIER_NS_DRAM_BASE, UNIPHIER_NS_DRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_NS),
+	{ .size = 0 },
+};
+
+void bl2_el3_plat_arch_setup(void)
+{
+	unsigned int soc;
+	int skip_scp = 0;
+	int ret;
+
+	uniphier_mmap_setup(BL2_BASE, BL2_SIZE, uniphier_bl2_mmap);
+	enable_mmu_el3(0);
+
+	soc = uniphier_get_soc_id();
+	if (soc == UNIPHIER_SOC_UNKNOWN) {
+		ERROR("unsupported SoC\n");
+		plat_error_handler(-ENOTSUP);
+	}
+
+	ret = uniphier_io_setup(soc);
+	if (ret) {
+		ERROR("failed to setup io devices\n");
+		plat_error_handler(ret);
+	}
+
+	switch (uniphier_get_boot_master(soc)) {
+	case UNIPHIER_BOOT_MASTER_THIS:
+		INFO("Booting from this SoC\n");
+		skip_scp = 1;
+		break;
+	case UNIPHIER_BOOT_MASTER_SCP:
+		INFO("Booting from on-chip SCP\n");
+		if (uniphier_scp_is_running()) {
+			INFO("SCP is already running. SCP_BL2 load will be skipped.\n");
+			skip_scp = 1;
+		}
+
+		/*
+		 * SCP must be kicked every time even if it is already running
+		 * because it polls this event after the reboot of the backend.
+		 */
+		uniphier_bl2_kick_scp = 1;
+		break;
+	case UNIPHIER_BOOT_MASTER_EXT:
+		INFO("Booting from external SCP\n");
+		skip_scp = 1;
+		break;
+	default:
+		plat_error_handler(-ENOTSUP);
+		break;
+	}
+
+	if (skip_scp) {
+		struct image_info *image_info;
+
+		image_info = uniphier_get_image_info(SCP_BL2_IMAGE_ID);
+		image_info->h.attr |= IMAGE_ATTRIB_SKIP_LOADING;
+	}
+}
+
+void bl2_platform_setup(void)
+{
+}
+
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
+
+void bl2_plat_preload_setup(void)
+{
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+	image_decompress_init(UNIPHIER_IMAGE_BUF_BASE,
+			      UNIPHIER_IMAGE_BUF_SIZE,
+			      gunzip);
+#endif
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+	image_decompress_prepare(uniphier_get_image_info(image_id));
+#endif
+	return 0;
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+	struct image_info *image_info;
+	int ret;
+
+	image_info = uniphier_get_image_info(image_id);
+
+	if (!(image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) {
+		ret = image_decompress(uniphier_get_image_info(image_id));
+		if (ret)
+			return ret;
+	}
+#endif
+
+	if (image_id == SCP_BL2_IMAGE_ID && uniphier_bl2_kick_scp)
+		uniphier_scp_start();
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_bl31_setup.c b/plat/socionext/uniphier/uniphier_bl31_setup.c
new file mode 100644
index 0000000..440e6aa
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl31_setup.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+#define BL31_SIZE		((BL31_END) - (BL31_BASE))
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type));
+	return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	void *from_bl2;
+
+	from_bl2 = (void *)arg0;
+
+	bl_params_node_t *bl_params = ((bl_params_t *)from_bl2)->head;
+
+	uniphier_console_setup();
+
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID)
+			bl32_image_ep_info = *bl_params->ep_info;
+
+		if (bl_params->image_id == BL33_IMAGE_ID)
+			bl33_image_ep_info = *bl_params->ep_info;
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0)
+		panic();
+}
+
+#define UNIPHIER_SYS_CNTCTL_BASE	0x60E00000
+
+void bl31_platform_setup(void)
+{
+	unsigned int soc;
+
+	soc = uniphier_get_soc_id();
+	if (soc == UNIPHIER_SOC_UNKNOWN) {
+		ERROR("unsupported SoC\n");
+		plat_error_handler(-ENOTSUP);
+	}
+
+	uniphier_cci_init(soc);
+	uniphier_cci_enable();
+
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	uniphier_gic_driver_init(soc);
+	uniphier_gic_init();
+
+	/* Enable and initialize the System level generic timer */
+	mmio_write_32(UNIPHIER_SYS_CNTCTL_BASE + CNTCR_OFF,
+		      CNTCR_FCREQ(0U) | CNTCR_EN);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	uniphier_mmap_setup(BL31_BASE, BL31_SIZE, NULL);
+	enable_mmu_el3(0);
+}
diff --git a/plat/socionext/uniphier/uniphier_boot_device.c b/plat/socionext/uniphier/uniphier_boot_device.c
new file mode 100644
index 0000000..462c085
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_boot_device.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_PINMON0		0x5f900100
+#define UNIPHIER_PINMON2		0x5f900108
+
+static int uniphier_ld11_is_usb_boot(uint32_t pinmon)
+{
+	return !!(~pinmon & 0x00000080);
+}
+
+static int uniphier_ld20_is_usb_boot(uint32_t pinmon)
+{
+	return !!(~pinmon & 0x00000780);
+}
+
+static int uniphier_pxs3_is_usb_boot(uint32_t pinmon)
+{
+	uint32_t pinmon2 = mmio_read_32(UNIPHIER_PINMON2);
+
+	return !!(pinmon2 & BIT(31));
+}
+
+static const unsigned int uniphier_ld11_boot_device_table[] = {
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_NOR,
+};
+
+static unsigned int uniphier_ld11_get_boot_device(uint32_t pinmon)
+{
+	unsigned int boot_sel = (pinmon >> 1) & 0x1f;
+
+	assert(boot_sel < ARRAY_SIZE(uniphier_ld11_boot_device_table));
+
+	return uniphier_ld11_boot_device_table[boot_sel];
+}
+
+static const unsigned int uniphier_pxs3_boot_device_table[] = {
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+};
+
+static unsigned int uniphier_pxs3_get_boot_device(uint32_t pinmon)
+{
+	unsigned int boot_sel = (pinmon >> 1) & 0xf;
+
+	assert(boot_sel < ARRAY_SIZE(uniphier_pxs3_boot_device_table));
+
+	return uniphier_pxs3_boot_device_table[boot_sel];
+}
+
+struct uniphier_boot_device_info {
+	int (*is_usb_boot)(uint32_t pinmon);
+	unsigned int (*get_boot_device)(uint32_t pinmon);
+};
+
+static const struct uniphier_boot_device_info uniphier_boot_device_info[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.is_usb_boot = uniphier_ld11_is_usb_boot,
+		.get_boot_device = uniphier_ld11_get_boot_device,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.is_usb_boot = uniphier_ld20_is_usb_boot,
+		.get_boot_device = uniphier_ld11_get_boot_device,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.is_usb_boot = uniphier_pxs3_is_usb_boot,
+		.get_boot_device = uniphier_pxs3_get_boot_device,
+	},
+};
+
+unsigned int uniphier_get_boot_device(unsigned int soc)
+{
+	const struct uniphier_boot_device_info *info;
+	uint32_t pinmon;
+
+	assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+	info = &uniphier_boot_device_info[soc];
+
+	pinmon = mmio_read_32(UNIPHIER_PINMON0);
+
+	if (!(pinmon & BIT(29)))
+		return UNIPHIER_BOOT_DEVICE_NOR;
+
+	if (info->is_usb_boot(pinmon))
+		return UNIPHIER_BOOT_DEVICE_USB;
+
+	return info->get_boot_device(pinmon);
+}
+
+static const bool uniphier_have_onchip_scp[] = {
+	[UNIPHIER_SOC_LD11] = true,
+	[UNIPHIER_SOC_LD20] = true,
+	[UNIPHIER_SOC_PXS3] = false,
+};
+
+unsigned int uniphier_get_boot_master(unsigned int soc)
+{
+	assert(soc < ARRAY_SIZE(uniphier_have_onchip_scp));
+
+	if (uniphier_have_onchip_scp[soc]) {
+		if (mmio_read_32(UNIPHIER_PINMON0) & BIT(27))
+			return UNIPHIER_BOOT_MASTER_THIS;
+		else
+			return UNIPHIER_BOOT_MASTER_SCP;
+	} else {
+		return UNIPHIER_BOOT_MASTER_EXT;
+	}
+}
diff --git a/plat/socionext/uniphier/uniphier_cci.c b/plat/socionext/uniphier/uniphier_cci.c
new file mode 100644
index 0000000..3ca1768
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_cci.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_CCI500_BASE	0x5FD00000
+
+static const int uniphier_cci_map[] = {1, 0};
+
+static void __uniphier_cci_init(void)
+{
+	cci_init(UNIPHIER_CCI500_BASE, uniphier_cci_map,
+		 ARRAY_SIZE(uniphier_cci_map));
+}
+
+static void __uniphier_cci_enable(void)
+{
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+static void __uniphier_cci_disable(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+struct uniphier_cci_ops {
+	void (*init)(void);
+	void (*enable)(void);
+	void (*disable)(void);
+};
+
+static const struct uniphier_cci_ops uniphier_cci_ops_table[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.init = NULL,
+		.enable = NULL,
+		.disable = NULL,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.init = __uniphier_cci_init,
+		.enable = __uniphier_cci_enable,
+		.disable = __uniphier_cci_disable,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.init = NULL,
+		.enable = NULL,
+		.disable = NULL,
+	},
+};
+
+static struct uniphier_cci_ops uniphier_cci_ops;
+
+void uniphier_cci_init(unsigned int soc)
+{
+	uniphier_cci_ops = uniphier_cci_ops_table[soc];
+	flush_dcache_range((uint64_t)&uniphier_cci_ops,
+			   sizeof(uniphier_cci_ops));
+
+	if (uniphier_cci_ops.init)
+		uniphier_cci_ops.init();
+}
+
+void uniphier_cci_enable(void)
+{
+	if (uniphier_cci_ops.enable)
+		uniphier_cci_ops.enable();
+}
+
+void uniphier_cci_disable(void)
+{
+	if (uniphier_cci_ops.disable)
+		uniphier_cci_ops.disable();
+}
diff --git a/plat/socionext/uniphier/uniphier_console.S b/plat/socionext/uniphier/uniphier_console.S
new file mode 100644
index 0000000..2c8dc8f
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.S
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+
+#include "uniphier_console.h"
+
+/*
+ * In: w0 - character to be printed
+ *     x1 - pointer to console structure
+ * Out: return the character written (always succeeds)
+ * Clobber: x2
+ */
+	.globl	uniphier_console_putc
+func uniphier_console_putc
+	ldr	x1, [x1, #CONSOLE_T_DRVDATA]
+
+	/* Wait until the transmitter FIFO gets empty */
+0:	ldr	w2, [x1, #UNIPHIER_UART_LSR]
+	tbz	w2, #UNIPHIER_UART_LSR_THRE_BIT, 0b
+
+	mov	w2, w0
+
+1:	str	w2, [x1, #UNIPHIER_UART_TX]
+
+	cmp	w2, #'\n'
+	b.ne	2f
+	mov	w2, #'\r'	/* Append '\r' to '\n' */
+	b	1b
+2:	ret
+endfunc uniphier_console_putc
+
+/*
+ * In: x0 - pointer to console structure
+ * Out: return the character read, or ERROR_NO_PENDING_CHAR if no character
+	is available
+ * Clobber: x1
+ */
+	.globl	uniphier_console_getc
+func uniphier_console_getc
+	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+
+	ldr	w1, [x0, #UNIPHIER_UART_LSR]
+	tbz	w1, #UNIPHIER_UART_LSR_DR_BIT, 0f
+
+	ldr	w0, [x0, #UNIPHIER_UART_RX]
+	ret
+
+0:	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+endfunc uniphier_console_getc
+
+/*
+ * In: x0 - pointer to console structure
+ * Out: return 0 (always succeeds)
+ * Clobber: x1
+ */
+	.global uniphier_console_flush
+func uniphier_console_flush
+	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+
+	/* wait until the transmitter gets empty */
+0:	ldr	w1, [x0, #UNIPHIER_UART_LSR]
+	tbz	w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
+
+	mov	w0, #0
+	ret
+endfunc uniphier_console_flush
diff --git a/plat/socionext/uniphier/uniphier_console.h b/plat/socionext/uniphier/uniphier_console.h
new file mode 100644
index 0000000..e35fc88
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UNIPHIER_CONSOLE_H
+#define UNIPHIER_CONSOLE_H
+
+#define UNIPHIER_UART_RX	0x00	/* In:  Receive buffer */
+#define UNIPHIER_UART_TX	0x00	/* Out: Transmit buffer */
+
+#define UNIPHIER_UART_FCR	0x0c	/* Char/FIFO Control Register */
+#define   UNIPHIER_UART_FCR_ENABLE_FIFO	0x01	/* Enable the FIFO */
+
+#define UNIPHIER_UART_LCR_MCR	0x10	/* Line/Modem Control Register */
+#define   UNIPHIER_UART_LCR_WLEN8	0x03	/* Wordlength: 8 bits */
+#define UNIPHIER_UART_LSR	0x14	/* Line Status Register */
+#define   UNIPHIER_UART_LSR_TEMT	0x40	/* Transmitter empty */
+#define   UNIPHIER_UART_LSR_TEMT_BIT	6	/* Transmitter empty */
+#define   UNIPHIER_UART_LSR_THRE_BIT	5	/* Transmit-hold-register empty */
+#define   UNIPHIER_UART_LSR_DR_BIT	0	/* Receiver data ready */
+#define UNIPHIER_UART_DLR	0x24	/* Divisor Latch Register */
+
+#endif /* UNIPHIER_CONSOLE_H */
diff --git a/plat/socionext/uniphier/uniphier_console_setup.c b/plat/socionext/uniphier/uniphier_console_setup.c
new file mode 100644
index 0000000..8185ec5
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console_setup.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+#include "uniphier_console.h"
+
+#define UNIPHIER_UART_BASE	0x54006800
+#define UNIPHIER_UART_END	0x54006c00
+#define UNIPHIER_UART_OFFSET	0x100
+
+struct uniphier_console {
+	struct console console;
+	uintptr_t base;
+};
+
+/* These callbacks are implemented in assembly to use crash_console_helpers.S */
+int uniphier_console_putc(int character, struct console *console);
+int uniphier_console_getc(struct console *console);
+int uniphier_console_flush(struct console *console);
+
+static struct uniphier_console uniphier_console = {
+	.console = {
+		.flags = CONSOLE_FLAG_BOOT |
+#if DEBUG
+			 CONSOLE_FLAG_RUNTIME |
+#endif
+			 CONSOLE_FLAG_CRASH,
+		.putc = uniphier_console_putc,
+		.getc = uniphier_console_getc,
+		.flush = uniphier_console_flush,
+	},
+};
+
+/*
+ * There are 4 UART ports available on this platform. By default, we want to
+ * use the same one as used in the previous firmware stage.
+ */
+static uintptr_t uniphier_console_get_base(void)
+{
+	uintptr_t base = UNIPHIER_UART_BASE;
+	uint32_t div;
+
+	while (base < UNIPHIER_UART_END) {
+		div = mmio_read_32(base + UNIPHIER_UART_DLR);
+		if (div)
+			return base;
+		base += UNIPHIER_UART_OFFSET;
+	}
+
+	return 0;
+}
+
+static void uniphier_console_init(uintptr_t base)
+{
+	mmio_write_32(base + UNIPHIER_UART_FCR, UNIPHIER_UART_FCR_ENABLE_FIFO);
+	mmio_write_32(base + UNIPHIER_UART_LCR_MCR,
+		      UNIPHIER_UART_LCR_WLEN8 << 8);
+}
+
+void uniphier_console_setup(void)
+{
+	uintptr_t base;
+
+	base = uniphier_console_get_base();
+	if (!base)
+		plat_error_handler(-EINVAL);
+
+	uniphier_console.base = base;
+	console_register(&uniphier_console.console);
+
+	/*
+	 * The hardware might be still printing characters queued up in the
+	 * previous firmware stage. Make sure the transmitter is empty before
+	 * any initialization. Otherwise, the console might get corrupted.
+	 */
+	console_flush();
+
+	uniphier_console_init(base);
+}
diff --git a/plat/socionext/uniphier/uniphier_emmc.c b/plat/socionext/uniphier/uniphier_emmc.c
new file mode 100644
index 0000000..4ac1f51
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_emmc.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define MMC_CMD_SWITCH			6
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD		9
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+
+#define EXT_CSD_PART_CONF		179	/* R/W */
+
+#define MMC_RSP_PRESENT BIT(0)
+#define MMC_RSP_136	BIT(1)		/* 136 bit response */
+#define MMC_RSP_CRC	BIT(2)		/* expect valid crc */
+#define MMC_RSP_BUSY	BIT(3)		/* card may send busy */
+#define MMC_RSP_OPCODE	BIT(4)		/* response contains opcode */
+
+#define MMC_RSP_NONE	(0)
+#define MMC_RSP_R1	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R1b	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | \
+			MMC_RSP_BUSY)
+#define MMC_RSP_R2	(MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
+#define MMC_RSP_R3	(MMC_RSP_PRESENT)
+#define MMC_RSP_R4	(MMC_RSP_PRESENT)
+#define MMC_RSP_R5	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R6	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R7	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+
+#define SDHCI_DMA_ADDRESS	0x00
+#define SDHCI_BLOCK_SIZE	0x04
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
+#define SDHCI_BLOCK_COUNT	0x06
+#define SDHCI_ARGUMENT		0x08
+#define SDHCI_TRANSFER_MODE	0x0C
+#define  SDHCI_TRNS_DMA		BIT(0)
+#define  SDHCI_TRNS_BLK_CNT_EN	BIT(1)
+#define  SDHCI_TRNS_ACMD12	BIT(2)
+#define  SDHCI_TRNS_READ	BIT(4)
+#define  SDHCI_TRNS_MULTI	BIT(5)
+#define SDHCI_COMMAND		0x0E
+#define  SDHCI_CMD_RESP_MASK	0x03
+#define  SDHCI_CMD_CRC		0x08
+#define  SDHCI_CMD_INDEX	0x10
+#define  SDHCI_CMD_DATA		0x20
+#define  SDHCI_CMD_ABORTCMD	0xC0
+#define  SDHCI_CMD_RESP_NONE	0x00
+#define  SDHCI_CMD_RESP_LONG	0x01
+#define  SDHCI_CMD_RESP_SHORT	0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+#define  SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff))
+#define SDHCI_RESPONSE		0x10
+#define SDHCI_HOST_CONTROL	0x28
+#define  SDHCI_CTRL_DMA_MASK	0x18
+#define   SDHCI_CTRL_SDMA	0x00
+#define SDHCI_BLOCK_GAP_CONTROL	0x2A
+#define SDHCI_SOFTWARE_RESET	0x2F
+#define  SDHCI_RESET_CMD	0x02
+#define  SDHCI_RESET_DATA	0x04
+#define SDHCI_INT_STATUS	0x30
+#define  SDHCI_INT_RESPONSE	BIT(0)
+#define  SDHCI_INT_DATA_END	BIT(1)
+#define  SDHCI_INT_DMA_END	BIT(3)
+#define  SDHCI_INT_ERROR	BIT(15)
+#define SDHCI_SIGNAL_ENABLE	0x38
+
+/* RCA assigned by Boot ROM */
+#define UNIPHIER_EMMC_RCA	0x1000
+
+struct uniphier_mmc_cmd {
+	unsigned int cmdidx;
+	unsigned int resp_type;
+	unsigned int cmdarg;
+	unsigned int is_data;
+};
+
+static int uniphier_emmc_block_addressing;
+
+static int uniphier_emmc_send_cmd(uintptr_t host_base,
+				  struct uniphier_mmc_cmd *cmd)
+{
+	uint32_t mode = 0;
+	uint32_t end_bit;
+	uint32_t stat, flags, dma_addr;
+
+	mmio_write_32(host_base + SDHCI_INT_STATUS, -1);
+	mmio_write_32(host_base + SDHCI_SIGNAL_ENABLE, 0);
+	mmio_write_32(host_base + SDHCI_ARGUMENT, cmd->cmdarg);
+
+	if (cmd->is_data)
+		mode = SDHCI_TRNS_DMA | SDHCI_TRNS_BLK_CNT_EN |
+			SDHCI_TRNS_ACMD12 | SDHCI_TRNS_READ |
+			SDHCI_TRNS_MULTI;
+
+	mmio_write_16(host_base + SDHCI_TRANSFER_MODE, mode);
+
+	if (!(cmd->resp_type & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->resp_type & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+	else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+	if (cmd->is_data)
+		flags |= SDHCI_CMD_DATA;
+
+	if (cmd->resp_type & MMC_RSP_BUSY || cmd->is_data)
+		end_bit = SDHCI_INT_DATA_END;
+	else
+		end_bit = SDHCI_INT_RESPONSE;
+
+	mmio_write_16(host_base + SDHCI_COMMAND,
+		      SDHCI_MAKE_CMD(cmd->cmdidx, flags));
+
+	do {
+		stat = mmio_read_32(host_base + SDHCI_INT_STATUS);
+		if (stat & SDHCI_INT_ERROR)
+			return -EIO;
+
+		if (stat & SDHCI_INT_DMA_END) {
+			mmio_write_32(host_base + SDHCI_INT_STATUS, stat);
+			dma_addr = mmio_read_32(host_base + SDHCI_DMA_ADDRESS);
+			mmio_write_32(host_base + SDHCI_DMA_ADDRESS, dma_addr);
+		}
+	} while (!(stat & end_bit));
+
+	return 0;
+}
+
+static int uniphier_emmc_switch_part(uintptr_t host_base, int part_num)
+{
+	struct uniphier_mmc_cmd cmd = {0};
+
+	cmd.cmdidx = MMC_CMD_SWITCH;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = (EXT_CSD_PART_CONF << 16) | (part_num << 8) | (3 << 24);
+
+	return uniphier_emmc_send_cmd(host_base, &cmd);
+}
+
+static int uniphier_emmc_is_over_2gb(uintptr_t host_base)
+{
+	struct uniphier_mmc_cmd cmd = {0};
+	uint32_t csd40, csd72;	/* CSD[71:40], CSD[103:72] */
+	int ret;
+
+	cmd.cmdidx = MMC_CMD_SEND_CSD;
+	cmd.resp_type = MMC_RSP_R2;
+	cmd.cmdarg = UNIPHIER_EMMC_RCA << 16;
+
+	ret = uniphier_emmc_send_cmd(host_base, &cmd);
+	if (ret)
+		return ret;
+
+	csd40 = mmio_read_32(host_base + SDHCI_RESPONSE + 4);
+	csd72 = mmio_read_32(host_base + SDHCI_RESPONSE + 8);
+
+	return !(~csd40 & 0xffc00380) && !(~csd72 & 0x3);
+}
+
+static int uniphier_emmc_load_image(uintptr_t host_base,
+				    uint32_t dev_addr,
+				    unsigned long load_addr,
+				    uint32_t block_cnt)
+{
+	struct uniphier_mmc_cmd cmd = {0};
+	uint8_t tmp;
+
+	assert((load_addr >> 32) == 0);
+
+	mmio_write_32(host_base + SDHCI_DMA_ADDRESS, load_addr);
+	mmio_write_16(host_base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 512));
+	mmio_write_16(host_base + SDHCI_BLOCK_COUNT, block_cnt);
+
+	tmp = mmio_read_8(host_base + SDHCI_HOST_CONTROL);
+	tmp &= ~SDHCI_CTRL_DMA_MASK;
+	tmp |= SDHCI_CTRL_SDMA;
+	mmio_write_8(host_base + SDHCI_HOST_CONTROL, tmp);
+
+	tmp = mmio_read_8(host_base + SDHCI_BLOCK_GAP_CONTROL);
+	tmp &= ~1;		/* clear Stop At Block Gap Request */
+	mmio_write_8(host_base + SDHCI_BLOCK_GAP_CONTROL, tmp);
+
+	cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = dev_addr;
+	cmd.is_data = 1;
+
+	return uniphier_emmc_send_cmd(host_base, &cmd);
+}
+
+static size_t uniphier_emmc_read(int lba, uintptr_t buf, size_t size)
+{
+	uintptr_t host_base = 0x5a000200;
+	int ret;
+
+	inv_dcache_range(buf, size);
+
+	if (!uniphier_emmc_block_addressing)
+		lba *= 512;
+
+	ret = uniphier_emmc_load_image(host_base, lba, buf, size / 512);
+
+	inv_dcache_range(buf, size);
+
+	return ret ? 0 : size;
+}
+
+static const struct io_block_dev_spec uniphier_emmc_dev_spec = {
+	.buffer = {
+		.offset = UNIPHIER_BLOCK_BUF_BASE,
+		.length = UNIPHIER_BLOCK_BUF_SIZE,
+	},
+	.ops = {
+		.read = uniphier_emmc_read,
+	},
+	.block_size = 512,
+};
+
+static int uniphier_emmc_hw_init(void)
+{
+	uintptr_t host_base = 0x5a000200;
+	struct uniphier_mmc_cmd cmd = {0};
+	int ret;
+
+	/*
+	 * deselect card before SEND_CSD command.
+	 * Do not check the return code.  It fails, but it is OK.
+	 */
+	cmd.cmdidx = MMC_CMD_SELECT_CARD;
+	cmd.resp_type = MMC_RSP_R1;
+
+	uniphier_emmc_send_cmd(host_base, &cmd); /* CMD7 (arg=0) */
+
+	/* reset CMD Line */
+	mmio_write_8(host_base + SDHCI_SOFTWARE_RESET,
+		     SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	while (mmio_read_8(host_base + SDHCI_SOFTWARE_RESET))
+		;
+
+	ret = uniphier_emmc_is_over_2gb(host_base);
+	if (ret < 0)
+		return ret;
+
+	uniphier_emmc_block_addressing = ret;
+
+	cmd.cmdarg = UNIPHIER_EMMC_RCA << 16;
+
+	/* select card again */
+	ret = uniphier_emmc_send_cmd(host_base, &cmd);
+	if (ret)
+		return ret;
+
+	/* switch to Boot Partition 1 */
+	ret = uniphier_emmc_switch_part(host_base, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int uniphier_emmc_init(uintptr_t *block_dev_spec)
+{
+	int ret;
+
+	ret = uniphier_emmc_hw_init();
+	if (ret)
+		return ret;
+
+	*block_dev_spec = (uintptr_t)&uniphier_emmc_dev_spec;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_gicv3.c b/plat/socionext/uniphier/uniphier_gicv3.c
new file mode 100644
index 0000000..266efe7
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_gicv3.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv3.h>
+#include <common/interrupt_props.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+static uintptr_t uniphier_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t uniphier_interrupt_props[] = {
+	/* G0 interrupts */
+
+	/* SGI0 */
+	INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+		       GIC_INTR_CFG_EDGE),
+	/* SGI6 */
+	INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+		       GIC_INTR_CFG_EDGE),
+
+	/* G1S interrupts */
+
+	/* Timer */
+	INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_LEVEL),
+	/* SGI1 */
+	INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_EDGE),
+	/* SGI2 */
+	INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_EDGE),
+	/* SGI3 */
+	INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_EDGE),
+	/* SGI4 */
+	INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_EDGE),
+	/* SGI5 */
+	INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_EDGE),
+	/* SGI7 */
+	INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+		       GIC_INTR_CFG_EDGE)
+};
+
+static unsigned int uniphier_mpidr_to_core_pos(u_register_t mpidr)
+{
+	return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const struct gicv3_driver_data uniphier_gic_driver_data[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.gicd_base = 0x5fe00000,
+		.gicr_base = 0x5fe40000,
+		.interrupt_props = uniphier_interrupt_props,
+		.interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = uniphier_rdistif_base_addrs,
+		.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.gicd_base = 0x5fe00000,
+		.gicr_base = 0x5fe80000,
+		.interrupt_props = uniphier_interrupt_props,
+		.interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = uniphier_rdistif_base_addrs,
+		.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.gicd_base = 0x5fe00000,
+		.gicr_base = 0x5fe80000,
+		.interrupt_props = uniphier_interrupt_props,
+		.interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = uniphier_rdistif_base_addrs,
+		.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+	},
+};
+
+void uniphier_gic_driver_init(unsigned int soc)
+{
+	assert(soc < ARRAY_SIZE(uniphier_gic_driver_data));
+
+	gicv3_driver_init(&uniphier_gic_driver_data[soc]);
+}
+
+void uniphier_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void uniphier_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void uniphier_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void uniphier_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/socionext/uniphier/uniphier_helpers.S b/plat/socionext/uniphier/uniphier_helpers.S
new file mode 100644
index 0000000..105cf9e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.global	uniphier_calc_core_pos
+	.global	plat_my_core_pos
+	.globl	platform_mem_init
+
+/*
+ * unsigned int uniphier_calc_core_pos(u_register_t mpidr)
+ * core_pos = (cluster_id * max_cpus_per_cluster) + core_id
+ */
+func uniphier_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	lsr	x0, x0, #MPIDR_AFFINITY_BITS
+	mov	x2, #UNIPHIER_MAX_CPUS_PER_CLUSTER
+	madd	x0, x0, x2, x1
+	ret
+endfunc uniphier_calc_core_pos
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	uniphier_calc_core_pos
+endfunc plat_my_core_pos
+
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/socionext/uniphier/uniphier_image_desc.c b/plat/socionext/uniphier/uniphier_image_desc.c
new file mode 100644
index 0000000..9e171e0
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_image_desc.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+
+#include "uniphier.h"
+
+static struct bl_mem_params_node uniphier_image_descs[] = {
+	{
+		.image_id = SCP_BL2_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = UNIPHIER_SCP_BASE,
+		.image_info.image_max_size = UNIPHIER_SCP_MAX_SIZE,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      NON_SECURE | NON_EXECUTABLE),
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL31_BASE,
+		.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.pc = BL31_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+
+#ifdef UNIPHIER_LOAD_BL32
+		.next_handoff_image_id = BL32_IMAGE_ID,
+#else
+		.next_handoff_image_id = BL33_IMAGE_ID,
+#endif
+	},
+#ifdef UNIPHIER_LOAD_BL32
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL32_BASE,
+		.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE),
+		.ep_info.pc = BL32_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+#endif
+	{
+		.image_id = BL33_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = UNIPHIER_BL33_BASE,
+		.image_info.image_max_size = UNIPHIER_BL33_MAX_SIZE,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      NON_SECURE | EXECUTABLE),
+		.ep_info.pc = UNIPHIER_BL33_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+};
+REGISTER_BL_IMAGE_DESCS(uniphier_image_descs)
+
+struct image_info *uniphier_get_image_info(unsigned int image_id)
+{
+	struct bl_mem_params_node *desc;
+
+	desc = get_bl_mem_params_node(image_id);
+	assert(desc);
+	return &desc->image_info;
+}
diff --git a/plat/socionext/uniphier/uniphier_io_storage.c b/plat/socionext/uniphier/uniphier_io_storage.c
new file mode 100644
index 0000000..b456bc5
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_io_storage.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_REGION_BASE	0x00000000ULL
+#define UNIPHIER_ROM_REGION_SIZE	0x10000000ULL
+
+#define UNIPHIER_OCM_REGION_BASE	0x30000000ULL
+#define UNIPHIER_OCM_REGION_SIZE	0x00040000ULL
+
+static const io_dev_connector_t *uniphier_fip_dev_con;
+static uintptr_t uniphier_fip_dev_handle;
+
+static const io_dev_connector_t *uniphier_backend_dev_con;
+static uintptr_t uniphier_backend_dev_handle;
+
+static io_block_spec_t uniphier_fip_spec = {
+	/* .offset will be set by the io_setup func */
+	.length = 0x00200000,
+};
+
+static const io_uuid_spec_t uniphier_bl2_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t uniphier_scp_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t uniphier_bl31_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t uniphier_bl32_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t uniphier_bl33_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t uniphier_tb_fw_cert_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t uniphier_trusted_key_cert_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_scp_fw_key_cert_spec = {
+	.uuid = UUID_SCP_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_soc_fw_key_cert_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_tos_fw_key_cert_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_nt_fw_key_cert_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_scp_fw_cert_spec = {
+	.uuid = UUID_SCP_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t uniphier_soc_fw_cert_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t uniphier_tos_fw_cert_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t uniphier_nt_fw_cert_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+struct uniphier_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	uintptr_t init_params;
+};
+
+static const struct uniphier_io_policy uniphier_io_policies[] = {
+	[FIP_IMAGE_ID] = {
+		.dev_handle = &uniphier_backend_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_fip_spec,
+	},
+	[BL2_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl2_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_scp_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[BL31_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl31_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[BL32_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl32_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[BL33_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl33_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_tb_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_trusted_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SCP_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_scp_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_soc_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_tos_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_nt_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SCP_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_scp_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_soc_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_tos_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_nt_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+#endif
+};
+
+static int uniphier_io_block_setup(size_t fip_offset, uintptr_t block_dev_spec)
+{
+	int ret;
+
+	uniphier_fip_spec.offset = fip_offset;
+
+	ret = register_io_dev_block(&uniphier_backend_dev_con);
+	if (ret)
+		return ret;
+
+	return io_dev_open(uniphier_backend_dev_con, block_dev_spec,
+			   &uniphier_backend_dev_handle);
+}
+
+static int uniphier_io_memmap_setup(size_t fip_offset)
+{
+	int ret;
+
+	uniphier_fip_spec.offset = fip_offset;
+
+	ret = mmap_add_dynamic_region(fip_offset, fip_offset,
+				      uniphier_fip_spec.length,
+				      MT_RO_DATA | MT_SECURE);
+	if (ret)
+		return ret;
+
+	ret = register_io_dev_memmap(&uniphier_backend_dev_con);
+	if (ret)
+		return ret;
+
+	return io_dev_open(uniphier_backend_dev_con, 0,
+			   &uniphier_backend_dev_handle);
+}
+
+static int uniphier_io_fip_setup(void)
+{
+	int ret;
+
+	ret = register_io_dev_fip(&uniphier_fip_dev_con);
+	if (ret)
+		return ret;
+
+	return io_dev_open(uniphier_fip_dev_con, 0, &uniphier_fip_dev_handle);
+}
+
+static int uniphier_io_emmc_setup(unsigned int soc_id)
+{
+	uintptr_t block_dev_spec;
+	int ret;
+
+	ret = uniphier_emmc_init(&block_dev_spec);
+	if (ret)
+		return ret;
+
+	return uniphier_io_block_setup(0x20000, block_dev_spec);
+}
+
+static int uniphier_io_nand_setup(unsigned int soc_id)
+{
+	uintptr_t block_dev_spec;
+	int ret;
+
+	ret = uniphier_nand_init(&block_dev_spec);
+	if (ret)
+		return ret;
+
+	return uniphier_io_block_setup(0x20000, block_dev_spec);
+}
+
+static int uniphier_io_nor_setup(unsigned int soc_id)
+{
+	return uniphier_io_memmap_setup(0x70000);
+}
+
+static int uniphier_io_usb_setup(unsigned int soc_id)
+{
+	uintptr_t block_dev_spec;
+	int ret;
+
+	/* use ROM API for loading images from USB storage */
+	ret = mmap_add_dynamic_region(UNIPHIER_ROM_REGION_BASE,
+				      UNIPHIER_ROM_REGION_BASE,
+				      UNIPHIER_ROM_REGION_SIZE,
+				      MT_CODE | MT_SECURE);
+	if (ret)
+		return ret;
+
+	/*
+	 * on-chip SRAM region: should be DEVICE attribute because the USB
+	 * load functions provided by the ROM use this memory region as a work
+	 * area, but do not cater to cache coherency.
+	 */
+	ret = mmap_add_dynamic_region(UNIPHIER_OCM_REGION_BASE,
+				      UNIPHIER_OCM_REGION_BASE,
+				      UNIPHIER_OCM_REGION_SIZE,
+				      MT_DEVICE | MT_RW | MT_SECURE);
+	if (ret)
+		return ret;
+
+	ret = uniphier_usb_init(soc_id, &block_dev_spec);
+	if (ret)
+		return ret;
+
+	return uniphier_io_block_setup(0x20000, block_dev_spec);
+}
+
+static int (* const uniphier_io_setup_table[])(unsigned int) = {
+	[UNIPHIER_BOOT_DEVICE_EMMC] = uniphier_io_emmc_setup,
+	[UNIPHIER_BOOT_DEVICE_NAND] = uniphier_io_nand_setup,
+	[UNIPHIER_BOOT_DEVICE_NOR] = uniphier_io_nor_setup,
+	[UNIPHIER_BOOT_DEVICE_USB] = uniphier_io_usb_setup,
+};
+
+int uniphier_io_setup(unsigned int soc_id)
+{
+	int (*io_setup)(unsigned int soc_id);
+	unsigned int boot_dev;
+	int ret;
+
+	boot_dev = uniphier_get_boot_device(soc_id);
+	if (boot_dev == UNIPHIER_BOOT_DEVICE_RSV)
+		return -EINVAL;
+
+	io_setup = uniphier_io_setup_table[boot_dev];
+	ret = io_setup(soc_id);
+	if (ret)
+		return ret;
+
+	ret = uniphier_io_fip_setup();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	uintptr_t init_params;
+
+	assert(image_id < ARRAY_SIZE(uniphier_io_policies));
+
+	*dev_handle = *uniphier_io_policies[image_id].dev_handle;
+	*image_spec = uniphier_io_policies[image_id].image_spec;
+	init_params = uniphier_io_policies[image_id].init_params;
+
+	return io_dev_init(*dev_handle, init_params);
+}
diff --git a/plat/socionext/uniphier/uniphier_nand.c b/plat/socionext/uniphier/uniphier_nand.c
new file mode 100644
index 0000000..27e10e4
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_nand.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define NAND_CMD_READ0		0
+#define NAND_CMD_READSTART	0x30
+
+#define DENALI_ECC_ENABLE			0x0e0
+#define DENALI_PAGES_PER_BLOCK			0x150
+#define DENALI_DEVICE_MAIN_AREA_SIZE		0x170
+#define DENALI_DEVICE_SPARE_AREA_SIZE		0x180
+#define DENALI_TWO_ROW_ADDR_CYCLES		0x190
+#define DENALI_INTR_STATUS0			0x410
+#define   DENALI_INTR_ECC_UNCOR_ERR			BIT(1)
+#define   DENALI_INTR_DMA_CMD_COMP			BIT(2)
+#define   DENALI_INTR_INT_ACT				BIT(12)
+
+#define DENALI_DMA_ENABLE			0x700
+
+#define DENALI_HOST_ADDR			0x00
+#define DENALI_HOST_DATA			0x10
+
+#define DENALI_MAP01				(1 << 26)
+#define DENALI_MAP10				(2 << 26)
+#define DENALI_MAP11				(3 << 26)
+
+#define DENALI_MAP11_CMD			((DENALI_MAP11) | 0)
+#define DENALI_MAP11_ADDR			((DENALI_MAP11) | 1)
+#define DENALI_MAP11_DATA			((DENALI_MAP11) | 2)
+
+#define DENALI_ACCESS_DEFAULT_AREA		0x42
+
+#define UNIPHIER_NAND_BBT_UNKNOWN		0xff
+
+struct uniphier_nand {
+	uintptr_t host_base;
+	uintptr_t reg_base;
+	int pages_per_block;
+	int page_size;
+	int two_row_addr_cycles;
+	uint8_t bbt[16];
+};
+
+struct uniphier_nand uniphier_nand;
+
+static void uniphier_nand_host_write(struct uniphier_nand *nand,
+				     uint32_t addr, uint32_t data)
+{
+	mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr);
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA, data);
+}
+
+static uint32_t uniphier_nand_host_read(struct uniphier_nand *nand,
+					uint32_t addr)
+{
+	mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr);
+	return mmio_read_32(nand->host_base + DENALI_HOST_DATA);
+}
+
+static int uniphier_nand_block_isbad(struct uniphier_nand *nand, int block)
+{
+	int page = nand->pages_per_block * block;
+	int column = nand->page_size;
+	uint8_t bbm;
+	uint32_t status;
+	int is_bad;
+
+	/* use cache if available */
+	if (block < ARRAY_SIZE(nand->bbt) &&
+	    nand->bbt[block] != UNIPHIER_NAND_BBT_UNKNOWN)
+		return nand->bbt[block];
+
+	mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 0);
+
+	mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1);
+
+	uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READ0);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, column & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (column >> 8) & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, page & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (page >> 8) & 0xff);
+	if (!nand->two_row_addr_cycles)
+		uniphier_nand_host_write(nand, DENALI_MAP11_ADDR,
+					 (page >> 16) & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READSTART);
+
+	do {
+		status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0);
+	} while (!(status & DENALI_INTR_INT_ACT));
+
+	bbm = uniphier_nand_host_read(nand, DENALI_MAP11_DATA);
+
+	is_bad = bbm != 0xff;
+
+	/* if possible, save the result for future re-use */
+	if (block < ARRAY_SIZE(nand->bbt))
+		nand->bbt[block] = is_bad;
+
+	if (is_bad)
+		WARN("found bad block at %d. skip.\n", block);
+
+	return is_bad;
+}
+
+static int uniphier_nand_read_pages(struct uniphier_nand *nand, uintptr_t buf,
+				    int page_start, int page_count)
+{
+	uint32_t status;
+
+	mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 1);
+	mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 1);
+
+	mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1);
+
+	/* use Data DMA (64bit) */
+	mmio_write_32(nand->host_base + DENALI_HOST_ADDR,
+		      DENALI_MAP10 | page_start);
+
+	/*
+	 * 1. setup transfer type, interrupt when complete,
+	 *    burst len = 64 bytes, the number of pages
+	 */
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA,
+		      0x01002000 | (64 << 16) | page_count);
+
+	/* 2. set memory low address */
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf);
+
+	/* 3. set memory high address */
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf >> 32);
+
+	do {
+		status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0);
+	} while (!(status & DENALI_INTR_DMA_CMD_COMP));
+
+	mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 0);
+
+	if (status & DENALI_INTR_ECC_UNCOR_ERR) {
+		ERROR("uncorrectable error in page range %d-%d",
+		      page_start, page_start + page_count - 1);
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+static size_t __uniphier_nand_read(struct uniphier_nand *nand, int lba,
+				   uintptr_t buf, size_t size)
+{
+	int pages_per_block = nand->pages_per_block;
+	int page_size = nand->page_size;
+	int blocks_to_skip = lba / pages_per_block;
+	int pages_to_read = div_round_up(size, page_size);
+	int page = lba % pages_per_block;
+	int block = 0;
+	uintptr_t p = buf;
+	int page_count, ret;
+
+	while (blocks_to_skip) {
+		ret = uniphier_nand_block_isbad(nand, block);
+		if (ret < 0)
+			goto out;
+
+		if (!ret)
+			blocks_to_skip--;
+
+		block++;
+	}
+
+	while (pages_to_read) {
+		ret = uniphier_nand_block_isbad(nand, block);
+		if (ret < 0)
+			goto out;
+
+		if (ret) {
+			block++;
+			continue;
+		}
+
+		page_count = MIN(pages_per_block - page, pages_to_read);
+
+		ret = uniphier_nand_read_pages(nand, p,
+					       block * pages_per_block + page,
+					       page_count);
+		if (ret)
+			goto out;
+
+		block++;
+		page = 0;
+		p += page_size * page_count;
+		pages_to_read -= page_count;
+	}
+
+out:
+	/* number of read bytes */
+	return MIN(size, p - buf);
+}
+
+static size_t uniphier_nand_read(int lba, uintptr_t buf, size_t size)
+{
+	size_t count;
+
+	inv_dcache_range(buf, size);
+
+	count = __uniphier_nand_read(&uniphier_nand, lba, buf, size);
+
+	inv_dcache_range(buf, size);
+
+	return count;
+}
+
+static struct io_block_dev_spec uniphier_nand_dev_spec = {
+	.buffer = {
+		.offset = UNIPHIER_BLOCK_BUF_BASE,
+		.length = UNIPHIER_BLOCK_BUF_SIZE,
+	},
+	.ops = {
+		.read = uniphier_nand_read,
+	},
+	/* fill .block_size at run-time */
+};
+
+static int uniphier_nand_hw_init(struct uniphier_nand *nand)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nand->bbt); i++)
+		nand->bbt[i] = UNIPHIER_NAND_BBT_UNKNOWN;
+
+	nand->host_base = 0x68000000;
+	nand->reg_base = 0x68100000;
+
+	nand->pages_per_block =
+			mmio_read_32(nand->reg_base + DENALI_PAGES_PER_BLOCK);
+
+	nand->page_size =
+		mmio_read_32(nand->reg_base + DENALI_DEVICE_MAIN_AREA_SIZE);
+
+	if (mmio_read_32(nand->reg_base + DENALI_TWO_ROW_ADDR_CYCLES) & BIT(0))
+		nand->two_row_addr_cycles = 1;
+
+	uniphier_nand_host_write(nand, DENALI_MAP10,
+				 DENALI_ACCESS_DEFAULT_AREA);
+
+	return 0;
+}
+
+int uniphier_nand_init(uintptr_t *block_dev_spec)
+{
+	int ret;
+
+	ret = uniphier_nand_hw_init(&uniphier_nand);
+	if (ret)
+		return ret;
+
+	uniphier_nand_dev_spec.block_size = uniphier_nand.page_size;
+
+	*block_dev_spec = (uintptr_t)&uniphier_nand_dev_spec;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
new file mode 100644
index 0000000..464252d
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_psci.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV0		0x59801200
+
+#define UNIPHIER_SLFRSTSEL		0x61843010
+#define   UNIPHIER_SLFRSTSEL_MASK		GENMASK(1, 0)
+#define UNIPHIER_SLFRSTCTL		0x61843014
+#define   UNIPHIER_SLFRSTCTL_RST		BIT(0)
+
+#define MPIDR_AFFINITY_INVALID		((u_register_t)-1)
+
+uintptr_t uniphier_sec_entrypoint;
+
+void uniphier_warmboot_entrypoint(void);
+void __dead2 uniphier_fake_pwr_down(void);
+u_register_t uniphier_holding_pen_release;
+static int uniphier_psci_scp_mode;
+
+static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
+{
+	uniphier_holding_pen_release = mpidr;
+	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
+			   sizeof(uniphier_holding_pen_release));
+
+	mmio_write_64(UNIPHIER_ROM_RSV0,
+		      (uint64_t)&uniphier_warmboot_entrypoint);
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uniphier_gic_cpuif_disable();
+}
+
+static void uniphier_psci_pwr_domain_on_finish(
+					const psci_power_state_t *target_state)
+{
+	uniphier_gic_pcpu_init();
+	uniphier_gic_cpuif_enable();
+
+	uniphier_cci_enable();
+}
+
+static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
+					const psci_power_state_t *target_state)
+{
+	/*
+	 * The Boot ROM cannot distinguish warm and cold resets.
+	 * Instead of the CPU reset, fake it.
+	 */
+	uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
+	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
+			   sizeof(uniphier_holding_pen_release));
+
+	uniphier_fake_pwr_down();
+}
+
+static void uniphier_self_system_reset(void)
+{
+	mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK);
+	mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST);
+}
+
+static void __dead2 uniphier_psci_system_off(void)
+{
+	if (uniphier_psci_scp_mode) {
+		uniphier_scp_system_off();
+	} else {
+		NOTICE("SCP is disabled; can't shutdown the system.\n");
+		NOTICE("Resetting the system instead.\n");
+		uniphier_self_system_reset();
+	}
+
+	wfi();
+	ERROR("UniPhier System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 uniphier_psci_system_reset(void)
+{
+	if (uniphier_psci_scp_mode)
+		uniphier_scp_system_reset();
+	else
+		uniphier_self_system_reset();
+
+	wfi();
+	ERROR("UniPhier System Reset: operation not handled.\n");
+	panic();
+}
+
+static const struct plat_psci_ops uniphier_psci_ops = {
+	.pwr_domain_on = uniphier_psci_pwr_domain_on,
+	.pwr_domain_off = uniphier_psci_pwr_domain_off,
+	.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
+	.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
+	.system_off = uniphier_psci_system_off,
+	.system_reset = uniphier_psci_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	uniphier_sec_entrypoint = sec_entrypoint;
+	flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
+			   sizeof(uniphier_sec_entrypoint));
+
+	uniphier_psci_scp_mode = uniphier_scp_is_running();
+	flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
+			   sizeof(uniphier_psci_scp_mode));
+
+	if (uniphier_psci_scp_mode)
+		uniphier_scp_open_com();
+
+	*psci_ops = &uniphier_psci_ops;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_rotpk.S b/plat/socionext/uniphier/uniphier_rotpk.S
new file mode 100644
index 0000000..21c44b6
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global uniphier_rotpk_hash
+	.global uniphier_rotpk_hash_end
+	.section .rodata.uniphier_rotpk_hash, "a"
+uniphier_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+uniphier_rotpk_hash_end:
diff --git a/plat/socionext/uniphier/uniphier_scp.c b/plat/socionext/uniphier/uniphier_scp.c
new file mode 100644
index 0000000..c608a25
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_scp.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV3		0x5980120c
+
+#define UNIPHIER_STMBE2COM		0x5f800030
+#define UNIPHIER_STMTOBEIRQ		0x5f800060
+#define UNIPHIER_BETOSTMIRQ0PT		0x5f800070
+#define UNIPHIER_BEIRQCLRPT		0x5f800072
+
+#define UNIPHIER_SCP_READY_MAGIC	0x0000b6a5
+
+#define UNIPHIER_SCP_PACKET_START	0xA0
+#define UNIPHIER_SCP_PACKET_END		0xA5
+#define UNIPHIER_SCP_PACKET_ESC		0xA6
+#define UNIPHIER_SCP_IS_CTRL_CODE(c)	(0xA0 <= (c) && (c) <= 0xA6)
+
+int uniphier_scp_is_running(void)
+{
+	return mmio_read_32(UNIPHIER_STMBE2COM) == UNIPHIER_SCP_READY_MAGIC;
+}
+
+void uniphier_scp_start(void)
+{
+	uint32_t tmp;
+
+	mmio_write_32(UNIPHIER_STMBE2COM + 4, UNIPHIER_SCP_BASE);
+	mmio_write_32(UNIPHIER_STMBE2COM, UNIPHIER_SCP_READY_MAGIC);
+
+	do {
+		tmp = mmio_read_32(UNIPHIER_ROM_RSV3);
+	} while (!(tmp & BIT(8)));
+
+	mmio_write_32(UNIPHIER_ROM_RSV3, tmp | BIT(9));
+}
+
+static void uniphier_scp_send_packet(const uint8_t *packet, int packet_len)
+{
+	uintptr_t reg = UNIPHIER_STMBE2COM;
+	uint32_t word;
+	int len, i;
+
+	while (packet_len) {
+		len = MIN(packet_len, 4);
+		word = 0;
+
+		for (i = 0; i < len; i++)
+			word |= *packet++ << (8 * i);
+
+		mmio_write_32(reg, word);
+		reg += 4;
+		packet_len -= len;
+	}
+
+	mmio_write_8(UNIPHIER_BETOSTMIRQ0PT, 0x55);
+
+	while (!(mmio_read_32(UNIPHIER_STMTOBEIRQ) & BIT(1)))
+		;
+	mmio_write_8(UNIPHIER_BEIRQCLRPT, BIT(1) | BIT(0));
+}
+
+static void uniphier_scp_send_cmd(const uint8_t *cmd, int cmd_len)
+{
+	uint8_t packet[32];	/* long enough */
+	uint8_t *p = packet;
+	uint8_t c;
+	int i;
+
+	*p++ = UNIPHIER_SCP_PACKET_START;
+	*p++ = cmd_len;
+
+	for (i = 0; i < cmd_len; i++) {
+		c = *cmd++;
+		if (UNIPHIER_SCP_IS_CTRL_CODE(c)) {
+			*p++ = UNIPHIER_SCP_PACKET_ESC;
+			*p++ = c ^ BIT(7);
+		} else {
+			*p++ = c;
+		}
+	}
+
+	*p++ = UNIPHIER_SCP_PACKET_END;
+
+	uniphier_scp_send_packet(packet, p - packet);
+}
+
+#define UNIPHIER_SCP_CMD(name, ...)					\
+static const uint8_t __uniphier_scp_##name##_cmd[] = {			\
+	__VA_ARGS__							\
+};									\
+void uniphier_scp_##name(void)						\
+{									\
+	uniphier_scp_send_cmd(__uniphier_scp_##name##_cmd,		\
+			      ARRAY_SIZE(__uniphier_scp_##name##_cmd));	\
+}
+
+UNIPHIER_SCP_CMD(open_com, 0x00, 0x00, 0x05)
+UNIPHIER_SCP_CMD(system_off, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01)
+UNIPHIER_SCP_CMD(system_reset, 0x00, 0x02, 0x00)
diff --git a/plat/socionext/uniphier/uniphier_smp.S b/plat/socionext/uniphier/uniphier_smp.S
new file mode 100644
index 0000000..d6cb9ff
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_smp.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	uniphier_warmboot_entrypoint
+	.globl	uniphier_fake_pwr_down
+
+func uniphier_warmboot_entrypoint
+	mrs	x0, mpidr_el1
+	mov_imm	x1, MPIDR_AFFINITY_MASK
+	and	x0, x0, x1
+	b	1f
+0:	wfe
+1:	ldr	x1, uniphier_holding_pen_release
+	cmp	x1, x0
+	b.ne	0b
+	ldr	x0, uniphier_sec_entrypoint
+	br	x0
+endfunc uniphier_warmboot_entrypoint
+
+func uniphier_fake_pwr_down
+	bl	disable_mmu_icache_el3
+	b	uniphier_warmboot_entrypoint
+endfunc uniphier_fake_pwr_down
diff --git a/plat/socionext/uniphier/uniphier_soc_info.c b/plat/socionext/uniphier/uniphier_soc_info.c
new file mode 100644
index 0000000..377532d
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_soc_info.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_REVISION		0x5f800000
+
+static unsigned int uniphier_get_revision_field(unsigned int mask,
+						unsigned int shift)
+{
+	uint32_t revision = mmio_read_32(UNIPHIER_REVISION);
+
+	return (revision >> shift) & mask;
+}
+
+unsigned int uniphier_get_soc_type(void)
+{
+	return uniphier_get_revision_field(0xff, 16);
+}
+
+unsigned int uniphier_get_soc_model(void)
+{
+	return uniphier_get_revision_field(0x07, 8);
+}
+
+unsigned int uniphier_get_soc_revision(void)
+{
+	return uniphier_get_revision_field(0x1f, 0);
+}
+
+unsigned int uniphier_get_soc_id(void)
+{
+	uint32_t type = uniphier_get_soc_type();
+
+	switch (type) {
+	case 0x31:
+		return UNIPHIER_SOC_LD11;
+	case 0x32:
+		return UNIPHIER_SOC_LD20;
+	case 0x35:
+		return UNIPHIER_SOC_PXS3;
+	default:
+		return UNIPHIER_SOC_UNKNOWN;
+	}
+}
diff --git a/plat/socionext/uniphier/uniphier_syscnt.c b/plat/socionext/uniphier/uniphier_syscnt.c
new file mode 100644
index 0000000..1937843
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_syscnt.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 50000000;
+}
diff --git a/plat/socionext/uniphier/uniphier_tbbr.c b/plat/socionext/uniphier/uniphier_tbbr.c
new file mode 100644
index 0000000..e31ca03
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_tbbr.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char uniphier_rotpk_hash[], uniphier_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = uniphier_rotpk_hash;
+	*key_len = uniphier_rotpk_hash_end - uniphier_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	/*
+	 * No support for non-volatile counter.  Update the ROT key to protect
+	 * the system against rollback.
+	 */
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 0;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/socionext/uniphier/uniphier_topology.c b/plat/socionext/uniphier/uniphier_topology.c
new file mode 100644
index 0000000..c106c98
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+static unsigned char uniphier_power_domain_tree_desc[UNIPHIER_CLUSTER_COUNT + 1];
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	int i;
+
+	uniphier_power_domain_tree_desc[0] = UNIPHIER_CLUSTER_COUNT;
+
+	for (i = 0; i < UNIPHIER_CLUSTER_COUNT; i++)
+		uniphier_power_domain_tree_desc[i + 1] =
+						UNIPHIER_MAX_CPUS_PER_CLUSTER;
+
+	return uniphier_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cluster_id >= UNIPHIER_CLUSTER_COUNT)
+		return -1;
+
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cpu_id >= UNIPHIER_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return uniphier_calc_core_pos(mpidr);
+}
diff --git a/plat/socionext/uniphier/uniphier_usb.c b/plat/socionext/uniphier/uniphier_usb.c
new file mode 100644
index 0000000..ef7079a
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_usb.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_LD11_USB_DESC_BASE	0x30010000
+#define UNIPHIER_LD20_USB_DESC_BASE	0x30014000
+#define UNIPHIER_PXS3_USB_DESC_BASE	0x30014000
+
+#define UNIPHIER_SRB_OCM_CONT		0x61200000
+
+struct uniphier_ld11_trans_op {
+	uint8_t __pad[48];
+};
+
+struct uniphier_ld11_op {
+	uint8_t __pad[56];
+	struct uniphier_ld11_trans_op *trans_op;
+	void *__pad2;
+	void *dev_desc;
+};
+
+struct uniphier_ld20_trans_op {
+	uint8_t __pad[40];
+};
+
+struct uniphier_ld20_op {
+	uint8_t __pad[192];
+	struct uniphier_ld20_trans_op *trans_op;
+	void *__pad2;
+	void *dev_desc;
+};
+
+struct uniphier_pxs3_op {
+	uint8_t __pad[184];
+	struct uniphier_ld20_trans_op *trans_op;
+	void *__pad2;
+	void *dev_desc;
+};
+
+static int (*__uniphier_usb_read)(int lba, uintptr_t buf, size_t size);
+
+static void uniphier_ld11_usb_init(void)
+{
+	struct uniphier_ld11_op *op = (void *)UNIPHIER_LD11_USB_DESC_BASE;
+
+	op->trans_op = (void *)(op + 1);
+
+	op->dev_desc = op->trans_op + 1;
+}
+
+static int uniphier_ld11_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
+				   unsigned int size, uintptr_t buf);
+	uintptr_t func_addr;
+
+	func_addr = uniphier_get_soc_revision() == 1 ? 0x3880 : 0x3958;
+	rom_usb_read = (__typeof(rom_usb_read))func_addr;
+
+	return rom_usb_read(UNIPHIER_LD11_USB_DESC_BASE, lba, size, buf);
+}
+
+static void uniphier_ld20_usb_init(void)
+{
+	struct uniphier_ld20_op *op = (void *)UNIPHIER_LD20_USB_DESC_BASE;
+
+	op->trans_op = (void *)(op + 1);
+
+	op->dev_desc = op->trans_op + 1;
+}
+
+static int uniphier_ld20_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
+				   unsigned int size, uintptr_t buf);
+	int ret;
+
+	rom_usb_read = (__typeof(rom_usb_read))0x37f0;
+
+	mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0x1ff);
+
+	/* ROM-API - return 1 on success, 0 on error */
+	ret = rom_usb_read(UNIPHIER_LD20_USB_DESC_BASE, lba, size, buf);
+
+	mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0);
+
+	return ret ? 0 : -1;
+}
+
+static void uniphier_pxs3_usb_init(void)
+{
+	struct uniphier_pxs3_op *op = (void *)UNIPHIER_PXS3_USB_DESC_BASE;
+
+	op->trans_op = (void *)(op + 1);
+
+	op->dev_desc = op->trans_op + 1;
+}
+
+static int uniphier_pxs3_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
+				   unsigned int size, uintptr_t buf);
+	int ret;
+
+	rom_usb_read = (__typeof(rom_usb_read))0x39e8;
+
+	/* ROM-API - return 1 on success, 0 on error */
+	ret = rom_usb_read(UNIPHIER_PXS3_USB_DESC_BASE, lba, size, buf);
+
+	return ret ? 0 : -1;
+}
+
+struct uniphier_usb_rom_param {
+	void (*init)(void);
+	int (*read)(int lba, uintptr_t buf, size_t size);
+};
+
+static const struct uniphier_usb_rom_param uniphier_usb_rom_params[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.init = uniphier_ld11_usb_init,
+		.read = uniphier_ld11_usb_read,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.init = uniphier_ld20_usb_init,
+		.read = uniphier_ld20_usb_read,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.init = uniphier_pxs3_usb_init,
+		.read = uniphier_pxs3_usb_read,
+	},
+};
+
+static size_t uniphier_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	int ret;
+
+	inv_dcache_range(buf, size);
+
+	ret = __uniphier_usb_read(lba, buf, size);
+
+	inv_dcache_range(buf, size);
+
+	return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec uniphier_usb_dev_spec = {
+	.buffer = {
+		.offset = UNIPHIER_BLOCK_BUF_BASE,
+		.length = UNIPHIER_BLOCK_BUF_SIZE,
+	},
+	.ops = {
+		.read = uniphier_usb_read,
+	},
+	.block_size = 512,
+};
+
+int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec)
+{
+	const struct uniphier_usb_rom_param *param;
+
+	assert(soc < ARRAY_SIZE(uniphier_usb_rom_params));
+	param = &uniphier_usb_rom_params[soc];
+
+	if (param->init)
+		param->init();
+
+	__uniphier_usb_read = param->read;
+
+	*block_dev_spec = (uintptr_t)&uniphier_usb_dev_spec;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_xlat_setup.c b/plat/socionext/uniphier/uniphier_xlat_setup.c
new file mode 100644
index 0000000..0faebc9
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_xlat_setup.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#define UNIPHIER_REG_REGION_BASE	0x50000000ULL
+#define UNIPHIER_REG_REGION_SIZE	0x20000000ULL
+
+void uniphier_mmap_setup(uintptr_t total_base, size_t total_size,
+			 const struct mmap_region *mmap)
+{
+	VERBOSE("Trusted RAM seen by this BL image: %p - %p\n",
+		(void *)total_base, (void *)(total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+
+	/* remap the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *)BL_CODE_BASE, (void *)BL_CODE_END);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			round_up(BL_CODE_END, PAGE_SIZE) - BL_CODE_BASE,
+			MT_CODE | MT_SECURE);
+
+	/* remap the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *)BL_COHERENT_RAM_BASE, (void *)BL_COHERENT_RAM_END);
+	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/* register region */
+	mmap_add_region(UNIPHIER_REG_REGION_BASE, UNIPHIER_REG_REGION_BASE,
+			UNIPHIER_REG_REGION_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/* additional regions if needed */
+	if (mmap)
+		mmap_add(mmap);
+
+	init_xlat_tables();
+}
diff --git a/plat/ti/k3/board/generic/board.mk b/plat/ti/k3/board/generic/board.mk
new file mode 100644
index 0000000..a342214
--- /dev/null
+++ b/plat/ti/k3/board/generic/board.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_BASE ?= 0x9e800000
+$(eval $(call add_define,BL32_BASE))
+
+PRELOADED_BL33_BASE ?= 0x80080000
+$(eval $(call add_define,PRELOADED_BL33_BASE))
+
+K3_HW_CONFIG_BASE ?= 0x82000000
+$(eval $(call add_define,K3_HW_CONFIG_BASE))
+
+PLAT_INCLUDES		+=	\
+				-Iplat/ti/k3/board/generic/include	\
diff --git a/plat/ti/k3/board/generic/include/board_def.h b/plat/ti/k3/board/generic/include/board_def.h
new file mode 100644
index 0000000..490b975
--- /dev/null
+++ b/plat/ti/k3/board/generic/include/board_def.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_DEF_H
+#define BOARD_DEF_H
+
+#include <lib/utils_def.h>
+
+/* The ports must be in order and contiguous */
+#define K3_CLUSTER0_CORE_COUNT		2
+#define K3_CLUSTER1_CORE_COUNT		2
+#define K3_CLUSTER2_CORE_COUNT		2
+#define K3_CLUSTER3_CORE_COUNT		2
+
+/*
+ * This RAM will be used for the bootloader including code, bss, and stacks.
+ * It may need to be increased if BL31 grows in size.
+ */
+#define SEC_SRAM_BASE			0x70000000 /* Base of MSMC SRAM */
+#define SEC_SRAM_SIZE			0x00020000 /* 128k */
+
+#define PLAT_MAX_OFF_STATE		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+
+#define PLAT_PROC_START_ID		32
+#define PLAT_PROC_DEVICE_START_ID	202
+
+#endif /* BOARD_DEF_H */
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
new file mode 100644
index 0000000..ee1eecf
--- /dev/null
+++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
@@ -0,0 +1,331 @@
+/*
+ * Texas Instruments K3 Secure Proxy Driver
+ *   Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "sec_proxy.h"
+
+/* SEC PROXY RT THREAD STATUS */
+#define RT_THREAD_STATUS			(0x0)
+#define RT_THREAD_STATUS_ERROR_SHIFT		(31)
+#define RT_THREAD_STATUS_ERROR_MASK		BIT(31)
+#define RT_THREAD_STATUS_CUR_CNT_SHIFT		(0)
+#define RT_THREAD_STATUS_CUR_CNT_MASK		GENMASK(7, 0)
+
+/* SEC PROXY SCFG THREAD CTRL */
+#define SCFG_THREAD_CTRL			(0x1000)
+#define SCFG_THREAD_CTRL_DIR_SHIFT		(31)
+#define SCFG_THREAD_CTRL_DIR_MASK		BIT(31)
+
+#define SEC_PROXY_THREAD(base, x)		((base) + (0x1000 * (x)))
+#define THREAD_IS_RX				(1)
+#define THREAD_IS_TX				(0)
+
+/**
+ * struct k3_sec_proxy_desc - Description of secure proxy integration
+ * @timeout_us:		Timeout for communication (in Microseconds)
+ * @max_msg_size:	Message size in bytes
+ * @data_start_offset:	Offset of the First data register of the thread
+ * @data_end_offset:	Offset of the Last data register of the thread
+ */
+struct k3_sec_proxy_desc {
+	uint32_t timeout_us;
+	uint16_t max_msg_size;
+	uint16_t data_start_offset;
+	uint16_t data_end_offset;
+};
+
+/**
+ * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread
+ * @name:	Thread Name
+ * @data:	Thread Data path region for target
+ * @scfg:	Secure Config Region for Thread
+ * @rt:		RealTime Region for Thread
+ */
+struct k3_sec_proxy_thread {
+	const char *name;
+	uintptr_t data;
+	uintptr_t scfg;
+	uintptr_t rt;
+};
+
+/**
+ * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
+ * @desc:	Description of the SoC integration
+ * @chans:	Array for valid thread instances
+ */
+struct k3_sec_proxy_mbox {
+	const struct k3_sec_proxy_desc desc;
+	struct k3_sec_proxy_thread threads[];
+};
+
+/*
+ * Thread ID #0: DMSC notify
+ * Thread ID #1: DMSC request response
+ * Thread ID #2: DMSC request high priority
+ * Thread ID #3: DMSC request low priority
+ * Thread ID #4: DMSC notify response
+ */
+#define SP_THREAD(_x) \
+	[_x] = { \
+		.name = #_x, \
+		.data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \
+		.scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \
+		.rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \
+	}
+
+static struct k3_sec_proxy_mbox spm = {
+	.desc = {
+		.timeout_us = SEC_PROXY_TIMEOUT_US,
+		.max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE,
+		.data_start_offset = 0x4,
+		.data_end_offset = 0x3C,
+	},
+	.threads = {
+		SP_THREAD(SP_NOTIFY),
+		SP_THREAD(SP_RESPONSE),
+		SP_THREAD(SP_HIGH_PRIORITY),
+		SP_THREAD(SP_LOW_PRIORITY),
+		SP_THREAD(SP_NOTIFY_RESP),
+	},
+};
+
+/**
+ * struct sec_msg_hdr - Message header for secure messages and responses
+ * @checksum:	CRC of message for integrity checking
+ */
+union sec_msg_hdr {
+	struct {
+		uint16_t checksum;
+		uint16_t reserved;
+	} __packed;
+	uint32_t data;
+};
+
+/**
+ * k3_sec_proxy_verify_thread() - Verify thread status before
+ *				  sending/receiving data
+ * @spt: Pointer to Secure Proxy thread description
+ * @dir: Direction of the thread
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt,
+					     uint32_t dir)
+{
+	/* Check for any errors already available */
+	if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
+	    RT_THREAD_STATUS_ERROR_MASK) {
+		ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
+		return -EINVAL;
+	}
+
+	/* Make sure thread is configured for right direction */
+	if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)
+	    != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) {
+		if (dir == THREAD_IS_TX)
+			ERROR("Trying to send data on RX Thread %s\n",
+			      spt->name);
+		else
+			ERROR("Trying to receive data on TX Thread %s\n",
+			      spt->name);
+		return -EINVAL;
+	}
+
+	/* Check the message queue before sending/receiving data */
+	uint32_t tick_start = (uint32_t)read_cntpct_el0();
+	uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000;
+	while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) {
+		VERBOSE("Waiting for thread %s to %s\n",
+			spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
+		if (((uint32_t)read_cntpct_el0() - tick_start) >
+		    (spm.desc.timeout_us * ticks_per_us)) {
+			ERROR("Timeout waiting for thread %s to %s\n",
+				spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill");
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * k3_sec_proxy_clear_rx_thread() - Clear Secure Proxy thread
+ *
+ * @id: Channel Identifier
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id)
+{
+	struct k3_sec_proxy_thread *spt = &spm.threads[id];
+
+	/* Check for any errors already available */
+	if (mmio_read_32(spt->rt + RT_THREAD_STATUS) &
+	    RT_THREAD_STATUS_ERROR_MASK) {
+		ERROR("Thread %s is corrupted, cannot send data\n", spt->name);
+		return -EINVAL;
+	}
+
+	/* Make sure thread is configured for right direction */
+	if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) {
+		ERROR("Cannot clear a transmit thread %s\n", spt->name);
+		return -EINVAL;
+	}
+
+	/* Read off messages from thread until empty */
+	uint32_t try_count = 10;
+	while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) {
+		if (!(try_count--)) {
+			ERROR("Could not clear all messages from thread %s\n", spt->name);
+			return -ETIMEDOUT;
+		}
+		WARN("Clearing message from thread %s\n", spt->name);
+		mmio_read_32(spt->data + spm.desc.data_end_offset);
+	}
+
+	return 0;
+}
+
+/**
+ * k3_sec_proxy_send() - Send data over a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg)
+{
+	struct k3_sec_proxy_thread *spt = &spm.threads[id];
+	union sec_msg_hdr secure_header;
+	int num_words, trail_bytes, i, ret;
+	uintptr_t data_reg;
+
+	ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX);
+	if (ret) {
+		ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
+		return ret;
+	}
+
+	/* Check the message size */
+	if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) {
+		ERROR("Thread %s message length %lu > max msg size\n",
+		      spt->name, msg->len);
+		return -EINVAL;
+	}
+
+	/* TODO: Calculate checksum */
+	secure_header.checksum = 0;
+
+	/* Send the secure header */
+	data_reg = spm.desc.data_start_offset;
+	mmio_write_32(spt->data + data_reg, secure_header.data);
+	data_reg += sizeof(uint32_t);
+
+	/* Send whole words */
+	num_words = msg->len / sizeof(uint32_t);
+	for (i = 0; i < num_words; i++) {
+		mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]);
+		data_reg += sizeof(uint32_t);
+	}
+
+	/* Send remaining bytes */
+	trail_bytes = msg->len % sizeof(uint32_t);
+	if (trail_bytes) {
+		uint32_t data_trail = 0;
+
+		i = msg->len - trail_bytes;
+		while (trail_bytes--) {
+			data_trail <<= 8;
+			data_trail |= msg->buf[i++];
+		}
+
+		mmio_write_32(spt->data + data_reg, data_trail);
+		data_reg += sizeof(uint32_t);
+	}
+	/*
+	 * 'data_reg' indicates next register to write. If we did not already
+	 * write on tx complete reg(last reg), we must do so for transmit
+	 */
+	if (data_reg <= spm.desc.data_end_offset)
+		mmio_write_32(spt->data + spm.desc.data_end_offset, 0);
+
+	VERBOSE("Message successfully sent on thread %s\n", spt->name);
+
+	return 0;
+}
+
+/**
+ * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg)
+{
+	struct k3_sec_proxy_thread *spt = &spm.threads[id];
+	union sec_msg_hdr secure_header;
+	uintptr_t data_reg;
+	int num_words, trail_bytes, i, ret;
+
+	ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX);
+	if (ret) {
+		ERROR("Thread %s verification failed (%d)\n", spt->name, ret);
+		return ret;
+	}
+
+	/* Read secure header */
+	data_reg = spm.desc.data_start_offset;
+	secure_header.data = mmio_read_32(spt->data + data_reg);
+	data_reg += sizeof(uint32_t);
+
+	/* Read whole words */
+	num_words = msg->len / sizeof(uint32_t);
+	for (i = 0; i < num_words; i++) {
+		((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg);
+		data_reg += sizeof(uint32_t);
+	}
+
+	/* Read remaining bytes */
+	trail_bytes = msg->len % sizeof(uint32_t);
+	if (trail_bytes) {
+		uint32_t data_trail = mmio_read_32(spt->data + data_reg);
+		data_reg += sizeof(uint32_t);
+
+		i = msg->len - trail_bytes;
+		while (trail_bytes--) {
+			msg->buf[i] = data_trail & 0xff;
+			data_trail >>= 8;
+		}
+	}
+
+	/*
+	 * 'data_reg' indicates next register to read. If we did not already
+	 * read on rx complete reg(last reg), we must do so for receive
+	 */
+	if (data_reg <= spm.desc.data_end_offset)
+		mmio_read_32(spt->data + spm.desc.data_end_offset);
+
+	/* TODO: Verify checksum */
+	(void)secure_header.checksum;
+
+	VERBOSE("Message successfully received from thread %s\n", spt->name);
+
+	return 0;
+}
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
new file mode 100644
index 0000000..6c4f5df
--- /dev/null
+++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
@@ -0,0 +1,67 @@
+/*
+ * Texas Instruments K3 Secure Proxy Driver
+ *   Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SEC_PROXY_H
+#define SEC_PROXY_H
+
+#include <stdint.h>
+
+/**
+ * enum k3_sec_proxy_chan_id - Secure Proxy thread IDs
+ *
+ * These the available IDs used in k3_sec_proxy_{send,recv}()
+ */
+enum k3_sec_proxy_chan_id {
+	SP_NOTIFY = 0,
+	SP_RESPONSE,
+	SP_HIGH_PRIORITY,
+	SP_LOW_PRIORITY,
+	SP_NOTIFY_RESP,
+};
+
+/**
+ * struct k3_sec_proxy_msg - Secure proxy message structure
+ * @len: Length of data in the Buffer
+ * @buf: Buffer pointer
+ *
+ * This is the structure for data used in k3_sec_proxy_{send,recv}()
+ */
+struct k3_sec_proxy_msg {
+	size_t len;
+	uint8_t *buf;
+};
+
+/**
+ * k3_sec_proxy_send() - Send data over a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id);
+
+/**
+ * k3_sec_proxy_send() - Send data over a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg);
+
+/**
+ * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
+ * @id: Channel Identifier
+ * @msg: Pointer to k3_sec_proxy_msg
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg);
+
+#endif /* SEC_PROXY_H */
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
new file mode 100644
index 0000000..ac33278
--- /dev/null
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
@@ -0,0 +1,1709 @@
+/*
+ * Texas Instruments System Control Interface Driver
+ *   Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <sec_proxy.h>
+
+#include "ti_sci_protocol.h"
+#include "ti_sci.h"
+
+/**
+ * struct ti_sci_desc - Description of SoC integration
+ * @host_id:		Host identifier representing the compute entity
+ * @max_msg_size:	Maximum size of data per message that can be handled
+ */
+struct ti_sci_desc {
+	uint8_t host_id;
+	int max_msg_size;
+};
+
+/**
+ * struct ti_sci_info - Structure representing a TI SCI instance
+ * @desc:	SoC description for this instance
+ * @seq:	Seq id used for verification for tx and rx message
+ */
+struct ti_sci_info {
+	const struct ti_sci_desc desc;
+	uint8_t seq;
+};
+
+static struct ti_sci_info info = {
+	.desc = {
+		.host_id = TI_SCI_HOST_ID,
+		.max_msg_size = TI_SCI_MAX_MESSAGE_SIZE,
+	},
+};
+
+/**
+ * struct ti_sci_xfer - Structure representing a message flow
+ * @tx_message:	Transmit message
+ * @rx_message:	Receive message
+ */
+struct ti_sci_xfer {
+	struct k3_sec_proxy_msg tx_message;
+	struct k3_sec_proxy_msg rx_message;
+};
+
+/**
+ * ti_sci_setup_one_xfer() - Setup one message type
+ *
+ * @msg_type:	Message type
+ * @msg_flags:	Flag to set for the message
+ * @tx_buf:	Buffer to be sent to mailbox channel
+ * @tx_message_size: transmit message size
+ * @rx_buf:	Buffer to be received from mailbox channel
+ * @rx_message_size: receive message size
+ *
+ * Helper function which is used by various command functions that are
+ * exposed to clients of this driver for allocating a message traffic event.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static int ti_sci_setup_one_xfer(uint16_t msg_type, uint32_t msg_flags,
+				 void *tx_buf,
+				 size_t tx_message_size,
+				 void *rx_buf,
+				 size_t rx_message_size,
+				 struct ti_sci_xfer *xfer)
+{
+	struct ti_sci_msg_hdr *hdr;
+
+	/* Ensure we have sane transfer sizes */
+	if (rx_message_size > info.desc.max_msg_size ||
+	    tx_message_size > info.desc.max_msg_size ||
+	    rx_message_size < sizeof(*hdr) ||
+	    tx_message_size < sizeof(*hdr))
+		return -ERANGE;
+
+	hdr = (struct ti_sci_msg_hdr *)tx_buf;
+	hdr->seq = ++info.seq;
+	hdr->type = msg_type;
+	hdr->host = info.desc.host_id;
+	hdr->flags = msg_flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
+
+	xfer->tx_message.buf = tx_buf;
+	xfer->tx_message.len = tx_message_size;
+
+	xfer->rx_message.buf = rx_buf;
+	xfer->rx_message.len = rx_message_size;
+
+	return 0;
+}
+
+/**
+ * ti_sci_get_response() - Receive response from mailbox channel
+ *
+ * @xfer:	Transfer to initiate and wait for response
+ * @chan:	Channel to receive the response
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static inline int ti_sci_get_response(struct ti_sci_xfer *xfer,
+				      enum k3_sec_proxy_chan_id chan)
+{
+	struct k3_sec_proxy_msg *msg = &xfer->rx_message;
+	struct ti_sci_msg_hdr *hdr;
+	unsigned int retry = 5;
+	int ret;
+
+	for (; retry > 0; retry--) {
+		/* Receive the response */
+		ret = k3_sec_proxy_recv(chan, msg);
+		if (ret) {
+			ERROR("Message receive failed (%d)\n", ret);
+			return ret;
+		}
+
+		/* msg is updated by Secure Proxy driver */
+		hdr = (struct ti_sci_msg_hdr *)msg->buf;
+
+		/* Sanity check for message response */
+		if (hdr->seq == info.seq)
+			break;
+		else
+			WARN("Message with sequence ID %u is not expected\n", hdr->seq);
+	}
+	if (!retry) {
+		ERROR("Timed out waiting for message\n");
+		return -EINVAL;
+	}
+
+	if (msg->len > info.desc.max_msg_size) {
+		ERROR("Unable to handle %lu xfer (max %d)\n",
+		      msg->len, info.desc.max_msg_size);
+		return -EINVAL;
+	}
+
+	if (!(hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK))
+		return -ENODEV;
+
+	return 0;
+}
+
+/**
+ * ti_sci_do_xfer() - Do one transfer
+ *
+ * @xfer:	Transfer to initiate and wait for response
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static inline int ti_sci_do_xfer(struct ti_sci_xfer *xfer)
+{
+	struct k3_sec_proxy_msg *msg = &xfer->tx_message;
+	int ret;
+
+	/* Clear any spurious messages in receive queue */
+	ret = k3_sec_proxy_clear_rx_thread(SP_RESPONSE);
+	if (ret) {
+		ERROR("Could not clear response queue (%d)\n", ret);
+		return ret;
+	}
+
+	/* Send the message */
+	ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, msg);
+	if (ret) {
+		ERROR("Message sending failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Get the response */
+	ret = ti_sci_get_response(xfer, SP_RESPONSE);
+	if (ret) {
+		ERROR("Failed to get response (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_get_revision() - Get the revision of the SCI entity
+ *
+ * Updates the SCI information in the internal data structure.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info)
+{
+	struct ti_sci_msg_hdr hdr;
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_VERSION, 0x0,
+				    &hdr, sizeof(hdr),
+				    rev_info, sizeof(*rev_info),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_set_state() - Set device state
+ *
+ * @id:		Device identifier
+ * @flags:	flags to setup for the device
+ * @state:	State to move the device to
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state)
+{
+	struct ti_sci_msg_req_set_device_state req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.id = id;
+	req.state = state;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_get_state() - Get device state
+ *
+ * @id:		Device Identifier
+ * @clcnt:	Pointer to Context Loss Count
+ * @resets:	pointer to resets
+ * @p_state:	pointer to p_state
+ * @c_state:	pointer to c_state
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+static int ti_sci_device_get_state(uint32_t id,  uint32_t *clcnt,
+				   uint32_t *resets, uint8_t *p_state,
+				   uint8_t *c_state)
+{
+	struct ti_sci_msg_req_get_device_state req;
+	struct ti_sci_msg_resp_get_device_state resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	if (!clcnt && !resets && !p_state && !c_state)
+		return -EINVAL;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.id = id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	if (clcnt)
+		*clcnt = resp.context_loss_count;
+	if (resets)
+		*resets = resp.resets;
+	if (p_state)
+		*p_state = resp.programmed_state;
+	if (c_state)
+		*c_state = resp.current_state;
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_get() - Request for device managed by TISCI
+ *
+ * @id:		Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get(uint32_t id)
+{
+	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON);
+}
+
+/**
+ * ti_sci_device_get_exclusive() - Exclusive request for device managed by TISCI
+ *
+ * @id:		Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * NOTE: This _exclusive version of the get API is for exclusive access to the
+ * device. Any other host in the system will fail to get this device after this
+ * call until exclusive access is released with device_put or a non-exclusive
+ * set call.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get_exclusive(uint32_t id)
+{
+	return ti_sci_device_set_state(id,
+				       MSG_FLAG_DEVICE_EXCLUSIVE,
+				       MSG_DEVICE_SW_STATE_ON);
+}
+
+/**
+ * ti_sci_device_idle() - Idle a device managed by TISCI
+ *
+ * @id:		Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_idle(uint32_t id)
+{
+	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_RETENTION);
+}
+
+/**
+ * ti_sci_device_idle_exclusive() - Exclusive idle a device managed by TISCI
+ *
+ * @id:		Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * NOTE: This _exclusive version of the idle API is for exclusive access to
+ * the device. Any other host in the system will fail to get this device after
+ * this call until exclusive access is released with device_put or a
+ * non-exclusive set call.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_idle_exclusive(uint32_t id)
+{
+	return ti_sci_device_set_state(id,
+				       MSG_FLAG_DEVICE_EXCLUSIVE,
+				       MSG_DEVICE_SW_STATE_RETENTION);
+}
+
+/**
+ * ti_sci_device_put() - Release a device managed by TISCI
+ *
+ * @id:		Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_put(uint32_t id)
+{
+	return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF);
+}
+
+/**
+ * ti_sci_device_put_no_wait() - Release a device without requesting or waiting
+ *				 for a response.
+ *
+ * @id:		Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_put_no_wait(uint32_t id)
+{
+	struct ti_sci_msg_req_set_device_state req;
+	struct ti_sci_msg_hdr *hdr;
+	struct k3_sec_proxy_msg tx_message;
+	int ret;
+
+	/* Ensure we have sane transfer size */
+	if (sizeof(req) > info.desc.max_msg_size)
+		return -ERANGE;
+
+	hdr = (struct ti_sci_msg_hdr *)&req;
+	hdr->seq = ++info.seq;
+	hdr->type = TI_SCI_MSG_SET_DEVICE_STATE;
+	hdr->host = info.desc.host_id;
+	/* Setup with NORESPONSE flag to keep response queue clean */
+	hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
+
+	req.id = id;
+	req.state = MSG_DEVICE_SW_STATE_AUTO_OFF;
+
+	tx_message.buf = (uint8_t *)&req;
+	tx_message.len = sizeof(req);
+
+	 /* Send message */
+	ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
+	if (ret) {
+		ERROR("Message sending failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Return without waiting for response */
+	return 0;
+}
+
+/**
+ * ti_sci_device_is_valid() - Is the device valid
+ *
+ * @id:		Device Identifier
+ *
+ * Return: 0 if all goes well and the device ID is valid, else return
+ *         appropriate error
+ */
+int ti_sci_device_is_valid(uint32_t id)
+{
+	uint8_t unused;
+
+	/* check the device state which will also tell us if the ID is valid */
+	return ti_sci_device_get_state(id, NULL, NULL, NULL, &unused);
+}
+
+/**
+ * ti_sci_device_get_clcnt() - Get context loss counter
+ *
+ * @id:		Device Identifier
+ * @count:	Pointer to Context Loss counter to populate
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count)
+{
+	return ti_sci_device_get_state(id, count, NULL, NULL, NULL);
+}
+
+/**
+ * ti_sci_device_is_idle() - Check if the device is requested to be idle
+ *
+ * @id:		Device Identifier
+ * @r_state:	true if requested to be idle
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_idle(uint32_t id, bool *r_state)
+{
+	int ret;
+	uint8_t state;
+
+	if (!r_state)
+		return -EINVAL;
+
+	ret = ti_sci_device_get_state(id, NULL, NULL, &state, NULL);
+	if (ret)
+		return ret;
+
+	*r_state = (state == MSG_DEVICE_SW_STATE_RETENTION);
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_is_stop() - Check if the device is requested to be stopped
+ *
+ * @id:		Device Identifier
+ * @r_state:	true if requested to be stopped
+ * @curr_state:	true if currently stopped
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_stop(uint32_t id, bool *r_state,  bool *curr_state)
+{
+	int ret;
+	uint8_t p_state, c_state;
+
+	if (!r_state && !curr_state)
+		return -EINVAL;
+
+	ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
+	if (ret)
+		return ret;
+
+	if (r_state)
+		*r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF);
+	if (curr_state)
+		*curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF);
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_is_on() - Check if the device is requested to be ON
+ *
+ * @id:		Device Identifier
+ * @r_state:	true if requested to be ON
+ * @curr_state:	true if currently ON and active
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_on(uint32_t id, bool *r_state,  bool *curr_state)
+{
+	int ret;
+	uint8_t p_state, c_state;
+
+	if (!r_state && !curr_state)
+		return -EINVAL;
+
+	ret =
+	    ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state);
+	if (ret)
+		return ret;
+
+	if (r_state)
+		*r_state = (p_state == MSG_DEVICE_SW_STATE_ON);
+	if (curr_state)
+		*curr_state = (c_state == MSG_DEVICE_HW_STATE_ON);
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_is_trans() - Check if the device is currently transitioning
+ *
+ * @id:		Device Identifier
+ * @curr_state:	true if currently transitioning
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_is_trans(uint32_t id, bool *curr_state)
+{
+	int ret;
+	uint8_t state;
+
+	if (!curr_state)
+		return -EINVAL;
+
+	ret = ti_sci_device_get_state(id, NULL, NULL, NULL, &state);
+	if (ret)
+		return ret;
+
+	*curr_state = (state == MSG_DEVICE_HW_STATE_TRANS);
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_set_resets() - Set resets for device managed by TISCI
+ *
+ * @id:			Device Identifier
+ * @reset_state:	Device specific reset bit field
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state)
+{
+	struct ti_sci_msg_req_set_device_resets req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_RESETS, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.id = id;
+	req.resets = reset_state;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_device_get_resets() - Get reset state for device managed by TISCI
+ *
+ * @id:			Device Identifier
+ * @reset_state:	Pointer to reset state to populate
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state)
+{
+	return ti_sci_device_get_state(id, NULL, reset_state, NULL, NULL);
+}
+
+/**
+ * ti_sci_clock_set_state() - Set clock state helper
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request,
+ *		Each device has its own set of clock inputs, This indexes
+ *		which clock input to modify
+ * @flags:	Header flags as needed
+ * @state:	State to request for the clock
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_set_state(uint32_t dev_id, uint8_t clk_id,
+			   uint32_t flags, uint8_t state)
+{
+	struct ti_sci_msg_req_set_clock_state req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_STATE, flags,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+	req.request_state = state;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_get_state() - Get clock state helper
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @programmed_state:	State requested for clock to move to
+ * @current_state:	State that the clock is currently in
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_get_state(uint32_t dev_id, uint8_t clk_id,
+			   uint8_t *programmed_state,
+			   uint8_t *current_state)
+{
+	struct ti_sci_msg_req_get_clock_state req;
+	struct ti_sci_msg_resp_get_clock_state resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	if (!programmed_state && !current_state)
+		return -EINVAL;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_STATE, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	if (programmed_state)
+		*programmed_state = resp.programmed_state;
+	if (current_state)
+		*current_state = resp.current_state;
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_get() - Get control of a clock from TI SCI
+
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @needs_ssc: 'true' iff Spread Spectrum clock is desired
+ * @can_change_freq: 'true' iff frequency change is desired
+ * @enable_input_term: 'true' iff input termination is desired
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id,
+		     bool needs_ssc, bool can_change_freq,
+		     bool enable_input_term)
+{
+	uint32_t flags = 0;
+
+	flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0;
+	flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0;
+	flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0;
+
+	return ti_sci_clock_set_state(dev_id, clk_id, flags,
+				      MSG_CLOCK_SW_STATE_REQ);
+}
+
+/**
+ * ti_sci_clock_idle() - Idle a clock which is in our control
+
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ *
+ * NOTE: This clock must have been requested by get_clock previously.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id)
+{
+	return ti_sci_clock_set_state(dev_id, clk_id, 0,
+				      MSG_CLOCK_SW_STATE_UNREQ);
+}
+
+/**
+ * ti_sci_clock_put() - Release a clock from our control
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ *
+ * NOTE: This clock must have been requested by get_clock previously.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id)
+{
+	return ti_sci_clock_set_state(dev_id, clk_id, 0,
+				      MSG_CLOCK_SW_STATE_AUTO);
+}
+
+/**
+ * ti_sci_clock_is_auto() - Is the clock being auto managed
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @req_state: state indicating if the clock is auto managed
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id, bool *req_state)
+{
+	uint8_t state = 0;
+	int ret;
+
+	if (!req_state)
+		return -EINVAL;
+
+	ret = ti_sci_clock_get_state(dev_id, clk_id, &state, NULL);
+	if (ret)
+		return ret;
+
+	*req_state = (state == MSG_CLOCK_SW_STATE_AUTO);
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_is_on() - Is the clock ON
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @req_state: state indicating if the clock is managed by us and enabled
+ * @curr_state: state indicating if the clock is ready for operation
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id,
+		       bool *req_state, bool *curr_state)
+{
+	uint8_t c_state = 0, r_state = 0;
+	int ret;
+
+	if (!req_state && !curr_state)
+		return -EINVAL;
+
+	ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
+	if (ret)
+		return ret;
+
+	if (req_state)
+		*req_state = (r_state == MSG_CLOCK_SW_STATE_REQ);
+	if (curr_state)
+		*curr_state = (c_state == MSG_CLOCK_HW_STATE_READY);
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_is_off() - Is the clock OFF
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @req_state: state indicating if the clock is managed by us and disabled
+ * @curr_state: state indicating if the clock is NOT ready for operation
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id,
+			bool *req_state, bool *curr_state)
+{
+	uint8_t c_state = 0, r_state = 0;
+	int ret;
+
+	if (!req_state && !curr_state)
+		return -EINVAL;
+
+	ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state);
+	if (ret)
+		return ret;
+
+	if (req_state)
+		*req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ);
+	if (curr_state)
+		*curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY);
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_set_parent() - Set the clock source of a specific device clock
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @parent_id:	Parent clock identifier to set
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id, uint8_t parent_id)
+{
+	struct ti_sci_msg_req_set_clock_parent req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_PARENT, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+	req.parent_id = parent_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_get_parent() - Get current parent clock source
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @parent_id:	Current clock parent
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id, uint8_t *parent_id)
+{
+	struct ti_sci_msg_req_get_clock_parent req;
+	struct ti_sci_msg_resp_get_clock_parent resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_PARENT, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	*parent_id = resp.parent_id;
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_get_num_parents() - Get num parents of the current clk source
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @num_parents: Returns he number of parents to the current clock.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id,
+				 uint8_t *num_parents)
+{
+	struct ti_sci_msg_req_get_clock_num_parents req;
+	struct ti_sci_msg_resp_get_clock_num_parents resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	*num_parents = resp.num_parents;
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_get_match_freq() - Find a good match for frequency
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @min_freq:	The minimum allowable frequency in Hz. This is the minimum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @target_freq: The target clock frequency in Hz. A frequency will be
+ *		processed as close to this target frequency as possible.
+ * @max_freq:	The maximum allowable frequency in Hz. This is the maximum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @match_freq:	Frequency match in Hz response.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id,
+				uint64_t min_freq, uint64_t target_freq,
+				uint64_t max_freq, uint64_t *match_freq)
+{
+	struct ti_sci_msg_req_query_clock_freq req;
+	struct ti_sci_msg_resp_query_clock_freq resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_QUERY_CLOCK_FREQ, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+	req.min_freq_hz = min_freq;
+	req.target_freq_hz = target_freq;
+	req.max_freq_hz = max_freq;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	*match_freq = resp.freq_hz;
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_set_freq() - Set a frequency for clock
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @min_freq:	The minimum allowable frequency in Hz. This is the minimum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @target_freq: The target clock frequency in Hz. A frequency will be
+ *		processed as close to this target frequency as possible.
+ * @max_freq:	The maximum allowable frequency in Hz. This is the maximum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq,
+			  uint64_t target_freq, uint64_t max_freq)
+{
+	struct ti_sci_msg_req_set_clock_freq req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_FREQ, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+	req.min_freq_hz = min_freq;
+	req.target_freq_hz = target_freq;
+	req.max_freq_hz = max_freq;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_clock_get_freq() - Get current frequency
+ *
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @freq:	Currently frequency in Hz
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq)
+{
+	struct ti_sci_msg_req_get_clock_freq req;
+	struct ti_sci_msg_resp_get_clock_freq resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_FREQ, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.dev_id = dev_id;
+	req.clk_id = clk_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	*freq = resp.freq_hz;
+
+	return 0;
+}
+
+/**
+ * ti_sci_core_reboot() - Command to request system reset
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_core_reboot(void)
+{
+	struct ti_sci_msg_req_reboot req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SYS_RESET, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_request() - Request a physical processor control
+ *
+ * @proc_id:	Processor ID this request is for
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_request(uint8_t proc_id)
+{
+	struct ti_sci_msg_req_proc_request req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_REQUEST, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_release() - Release a physical processor control
+ *
+ * @proc_id:	Processor ID this request is for
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_release(uint8_t proc_id)
+{
+	struct ti_sci_msg_req_proc_release req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_RELEASE, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_handover() - Handover a physical processor control to a host in
+ *                          the processor's access control list.
+ *
+ * @proc_id:	Processor ID this request is for
+ * @host_id:	Host ID to get the control of the processor
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id)
+{
+	struct ti_sci_msg_req_proc_handover req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_HANDOVER, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+	req.host_id = host_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_set_boot_cfg() - Set the processor boot configuration flags
+ *
+ * @proc_id:		Processor ID this request is for
+ * @config_flags_set:	Configuration flags to be set
+ * @config_flags_clear:	Configuration flags to be cleared
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector,
+			     uint32_t config_flags_set,
+			     uint32_t config_flags_clear)
+{
+	struct ti_sci_msg_req_set_proc_boot_config req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CONFIG, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+	req.bootvector_low = bootvector & TISCI_ADDR_LOW_MASK;
+	req.bootvector_high = (bootvector & TISCI_ADDR_HIGH_MASK) >>
+				TISCI_ADDR_HIGH_SHIFT;
+	req.config_flags_set = config_flags_set;
+	req.config_flags_clear = config_flags_clear;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_set_boot_ctrl() - Set the processor boot control flags
+ *
+ * @proc_id:			Processor ID this request is for
+ * @control_flags_set:		Control flags to be set
+ * @control_flags_clear:	Control flags to be cleared
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set,
+			      uint32_t control_flags_clear)
+{
+	struct ti_sci_msg_req_set_proc_boot_ctrl req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CTRL, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+	req.control_flags_set = control_flags_set;
+	req.control_flags_clear = control_flags_clear;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_set_boot_ctrl_no_wait() - Set the processor boot control flags
+ *					 without requesting or waiting for a
+ *					 response.
+ *
+ * @proc_id:			Processor ID this request is for
+ * @control_flags_set:		Control flags to be set
+ * @control_flags_clear:	Control flags to be cleared
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id,
+				      uint32_t control_flags_set,
+				      uint32_t control_flags_clear)
+{
+	struct ti_sci_msg_req_set_proc_boot_ctrl req;
+	struct ti_sci_msg_hdr *hdr;
+	struct k3_sec_proxy_msg tx_message;
+	int ret;
+
+	/* Ensure we have sane transfer size */
+	if (sizeof(req) > info.desc.max_msg_size)
+		return -ERANGE;
+
+	hdr = (struct ti_sci_msg_hdr *)&req;
+	hdr->seq = ++info.seq;
+	hdr->type = TISCI_MSG_SET_PROC_BOOT_CTRL;
+	hdr->host = info.desc.host_id;
+	/* Setup with NORESPONSE flag to keep response queue clean */
+	hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
+
+	req.processor_id = proc_id;
+	req.control_flags_set = control_flags_set;
+	req.control_flags_clear = control_flags_clear;
+
+	tx_message.buf = (uint8_t *)&req;
+	tx_message.len = sizeof(req);
+
+	 /* Send message */
+	ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
+	if (ret) {
+		ERROR("Message sending failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Return without waiting for response */
+	return 0;
+}
+
+/**
+ * ti_sci_proc_auth_boot_image() - Authenticate and load image and then set the
+ *                                 processor configuration flags
+ *
+ * @proc_id:	Processor ID this request is for
+ * @cert_addr:	Memory address at which payload image certificate is located
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr)
+{
+	struct ti_sci_msg_req_proc_auth_boot_image req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_AUTH_BOOT_IMIAGE, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+	req.cert_addr_low = cert_addr & TISCI_ADDR_LOW_MASK;
+	req.cert_addr_high = (cert_addr & TISCI_ADDR_HIGH_MASK) >>
+				TISCI_ADDR_HIGH_SHIFT;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_get_boot_status() - Get the processor boot status
+ *
+ * @proc_id:	Processor ID this request is for
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv,
+				uint32_t *cfg_flags,
+				uint32_t *ctrl_flags,
+				uint32_t *sts_flags)
+{
+	struct ti_sci_msg_req_get_proc_boot_status req;
+	struct ti_sci_msg_resp_get_proc_boot_status resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_GET_PROC_BOOT_STATUS, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	*bv = (resp.bootvector_low & TISCI_ADDR_LOW_MASK) |
+	      (((uint64_t)resp.bootvector_high << TISCI_ADDR_HIGH_SHIFT) &
+	       TISCI_ADDR_HIGH_MASK);
+	*cfg_flags = resp.config_flags;
+	*ctrl_flags = resp.control_flags;
+	*sts_flags = resp.status_flags;
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_wait_boot_status() - Wait for a processor boot status
+ *
+ * @proc_id:			Processor ID this request is for
+ * @num_wait_iterations		Total number of iterations we will check before
+ *				we will timeout and give up
+ * @num_match_iterations	How many iterations should we have continued
+ *				status to account for status bits glitching.
+ *				This is to make sure that match occurs for
+ *				consecutive checks. This implies that the
+ *				worst case should consider that the stable
+ *				time should at the worst be num_wait_iterations
+ *				num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us	Specifies how long to wait (in micro seconds)
+ *				between each status checks. This is the minimum
+ *				duration, and overhead of register reads and
+ *				checks are on top of this and can vary based on
+ *				varied conditions.
+ * @delay_before_iterations_us	Specifies how long to wait (in micro seconds)
+ *				before the very first check in the first
+ *				iteration of status check loop. This is the
+ *				minimum duration, and overhead of register
+ *				reads and checks are.
+ * @status_flags_1_set_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 0.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
+				 uint8_t num_match_iterations,
+				 uint8_t delay_per_iteration_us,
+				 uint8_t delay_before_iterations_us,
+				 uint32_t status_flags_1_set_all_wait,
+				 uint32_t status_flags_1_set_any_wait,
+				 uint32_t status_flags_1_clr_all_wait,
+				 uint32_t status_flags_1_clr_any_wait)
+{
+	struct ti_sci_msg_req_wait_proc_boot_status req;
+	struct ti_sci_msg_hdr resp;
+
+	struct ti_sci_xfer xfer;
+	int ret;
+
+	ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS, 0,
+				    &req, sizeof(req),
+				    &resp, sizeof(resp),
+				    &xfer);
+	if (ret) {
+		ERROR("Message alloc failed (%d)\n", ret);
+		return ret;
+	}
+
+	req.processor_id = proc_id;
+	req.num_wait_iterations = num_wait_iterations;
+	req.num_match_iterations = num_match_iterations;
+	req.delay_per_iteration_us = delay_per_iteration_us;
+	req.delay_before_iterations_us = delay_before_iterations_us;
+	req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
+	req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
+	req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
+	req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
+
+	ret = ti_sci_do_xfer(&xfer);
+	if (ret) {
+		ERROR("Transfer send failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * ti_sci_proc_wait_boot_status_no_wait() - Wait for a processor boot status
+ *					    without requesting or waiting for
+ *					    a response.
+ *
+ * @proc_id:			Processor ID this request is for
+ * @num_wait_iterations		Total number of iterations we will check before
+ *				we will timeout and give up
+ * @num_match_iterations	How many iterations should we have continued
+ *				status to account for status bits glitching.
+ *				This is to make sure that match occurs for
+ *				consecutive checks. This implies that the
+ *				worst case should consider that the stable
+ *				time should at the worst be num_wait_iterations
+ *				num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us	Specifies how long to wait (in micro seconds)
+ *				between each status checks. This is the minimum
+ *				duration, and overhead of register reads and
+ *				checks are on top of this and can vary based on
+ *				varied conditions.
+ * @delay_before_iterations_us	Specifies how long to wait (in micro seconds)
+ *				before the very first check in the first
+ *				iteration of status check loop. This is the
+ *				minimum duration, and overhead of register
+ *				reads and checks are.
+ * @status_flags_1_set_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 0.
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id,
+					 uint8_t num_wait_iterations,
+					 uint8_t num_match_iterations,
+					 uint8_t delay_per_iteration_us,
+					 uint8_t delay_before_iterations_us,
+					 uint32_t status_flags_1_set_all_wait,
+					 uint32_t status_flags_1_set_any_wait,
+					 uint32_t status_flags_1_clr_all_wait,
+					 uint32_t status_flags_1_clr_any_wait)
+{
+	struct ti_sci_msg_req_wait_proc_boot_status req;
+	struct ti_sci_msg_hdr *hdr;
+	struct k3_sec_proxy_msg tx_message;
+	int ret;
+
+	/* Ensure we have sane transfer size */
+	if (sizeof(req) > info.desc.max_msg_size)
+		return -ERANGE;
+
+	hdr = (struct ti_sci_msg_hdr *)&req;
+	hdr->seq = ++info.seq;
+	hdr->type = TISCI_MSG_WAIT_PROC_BOOT_STATUS;
+	hdr->host = info.desc.host_id;
+	/* Setup with NORESPONSE flag to keep response queue clean */
+	hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE;
+
+	req.processor_id = proc_id;
+	req.num_wait_iterations = num_wait_iterations;
+	req.num_match_iterations = num_match_iterations;
+	req.delay_per_iteration_us = delay_per_iteration_us;
+	req.delay_before_iterations_us = delay_before_iterations_us;
+	req.status_flags_1_set_all_wait = status_flags_1_set_all_wait;
+	req.status_flags_1_set_any_wait = status_flags_1_set_any_wait;
+	req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait;
+	req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait;
+
+	tx_message.buf = (uint8_t *)&req;
+	tx_message.len = sizeof(req);
+
+	 /* Send message */
+	ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message);
+	if (ret) {
+		ERROR("Message sending failed (%d)\n", ret);
+		return ret;
+	}
+
+	/* Return without waiting for response */
+	return 0;
+}
+
+/**
+ * ti_sci_init() - Basic initialization
+ *
+ * Return: 0 if all goes well, else appropriate error message
+ */
+int ti_sci_init(void)
+{
+	struct ti_sci_msg_resp_version rev_info;
+	int ret;
+
+	ret = ti_sci_get_revision(&rev_info);
+	if (ret) {
+		ERROR("Unable to communicate with control firmware (%d)\n", ret);
+		return ret;
+	}
+
+	INFO("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')\n",
+	     rev_info.abi_major, rev_info.abi_minor,
+	     rev_info.firmware_revision,
+	     rev_info.firmware_description);
+
+	return 0;
+}
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
new file mode 100644
index 0000000..c7b09b3
--- /dev/null
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.h
@@ -0,0 +1,216 @@
+/*
+ * Texas Instruments System Control Interface API
+ *   Based on Linux and U-Boot implementation
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TI_SCI_H
+#define TI_SCI_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**
+ * Device control operations
+ *
+ * - ti_sci_device_get - command to request for device managed by TISCI
+ * - ti_sci_device_get_exclusive - exclusively request a device
+ * - ti_sci_device_idle - Command to idle a device managed by TISCI
+ * - ti_sci_device_idle_exclusive - exclusively idle a device
+ * - ti_sci_device_put - command to release a device managed by TISCI
+ * - ti_sci_device_put_no_wait - release a device without waiting for response
+ * - ti_sci_device_is_valid - Is the device valid
+ * - ti_sci_device_get_clcnt - Get context loss counter
+ *              @count: Pointer to Context Loss counter to populate
+ * - ti_sci_device_is_idle - Check if the device is requested to be idle
+ *              @r_state: true if requested to be idle
+ * - ti_sci_device_is_stop - Check if the device is requested to be stopped
+ *              @r_state: true if requested to be stopped
+ *              @curr_state: true if currently stopped.
+ * - ti_sci_device_is_on - Check if the device is requested to be ON
+ *              @r_state: true if requested to be ON
+ *              @curr_state: true if currently ON and active
+ * - ti_sci_device_is_trans - Check if the device is currently transitioning
+ *              @curr_state: true if currently transitioning.
+ * - ti_sci_device_set_resets - Command to set resets for
+ *                              device managed by TISCI
+ *              @reset_state: Device specific reset bit field
+ * - ti_sci_device_get_resets - Get reset state for device managed by TISCI
+ *              @reset_state: Pointer to reset state to populate
+ *
+ * NOTE: for all these functions, the following are generic in nature:
+ * @id:		Device Identifier
+ * Returns 0 for successful request, else returns corresponding error message.
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ */
+int ti_sci_device_get(uint32_t id);
+int ti_sci_device_get_exclusive(uint32_t id);
+int ti_sci_device_idle(uint32_t id);
+int ti_sci_device_idle_exclusive(uint32_t id);
+int ti_sci_device_put(uint32_t id);
+int ti_sci_device_put_no_wait(uint32_t id);
+int ti_sci_device_is_valid(uint32_t id);
+int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count);
+int ti_sci_device_is_idle(uint32_t id, bool *r_state);
+int ti_sci_device_is_stop(uint32_t id, bool *r_state,  bool *curr_state);
+int ti_sci_device_is_on(uint32_t id, bool *r_state,  bool *curr_state);
+int ti_sci_device_is_trans(uint32_t id, bool *curr_state);
+int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state);
+int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state);
+
+/**
+ * Clock control operations
+ *
+ * - ti_sci_clock_get - Get control of a clock from TI SCI
+ *              @needs_ssc: 'true' iff Spread Spectrum clock is desired
+ *              @can_change_freq: 'true' iff frequency change is desired
+ *              @enable_input_term: 'true' iff input termination is desired
+ * - ti_sci_clock_idle - Idle a clock which is in our control
+ * - ti_sci_clock_put - Release a clock from our control
+ * - ti_sci_clock_is_auto - Is the clock being auto managed
+ *              @req_state: state indicating if the clock is auto managed
+ * - ti_sci_clock_is_on - Is the clock ON
+ *              @req_state: state indicating if the clock is managed by us and enabled
+ *              @curr_state: state indicating if the clock is ready for operation
+ * - ti_sci_clock_is_off - Is the clock OFF
+ *              @req_state: state indicating if the clock is managed by us and disabled
+ *              @curr_state: state indicating if the clock is NOT ready for operation
+ * - ti_sci_clock_set_parent - Set the clock source of a specific device clock
+ *              @parent_id: Parent clock identifier to set
+ * - ti_sci_clock_get_parent - Get current parent clock source
+ *              @parent_id: Current clock parent
+ * - ti_sci_clock_get_num_parents - Get num parents of the current clk source
+ *              @num_parents: Returns he number of parents to the current clock.
+ * - ti_sci_clock_get_match_freq - Find a good match for frequency
+ *              @match_freq: Frequency match in Hz response.
+ * - ti_sci_clock_set_freq - Set a frequency for clock
+ * - ti_sci_clock_get_freq - Get current frequency
+ *              @freq: Currently frequency in Hz
+ *
+ * NOTE: for all these functions, the following are generic in nature:
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has its own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @min_freq:	The minimum allowable frequency in Hz. This is the minimum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @target_freq: The target clock frequency in Hz. A frequency will be
+ *		processed as close to this target frequency as possible.
+ * @max_freq:	The maximum allowable frequency in Hz. This is the maximum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * Returns 0 for successful request, else returns corresponding error message.
+ *
+ * Request for the clock - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_clock with put_clock. No refcounting is
+ * managed by driver for that purpose.
+ */
+int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id,
+		     bool needs_ssc, bool can_change_freq,
+		     bool enable_input_term);
+int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id);
+int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id);
+int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id,
+			 bool *req_state);
+int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id,
+		       bool *req_state, bool *curr_state);
+int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id,
+			bool *req_state, bool *curr_state);
+int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id,
+			    uint8_t parent_id);
+int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id,
+			    uint8_t *parent_id);
+int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id,
+				 uint8_t *num_parents);
+int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id,
+				uint64_t min_freq, uint64_t target_freq,
+				uint64_t max_freq, uint64_t *match_freq);
+int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id,
+			  uint64_t min_freq, uint64_t target_freq,
+			  uint64_t max_freq);
+int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq);
+
+/**
+ * Core control operations
+ *
+ * - ti_sci_core_reboot() - Command to request system reset
+ *
+ * Return: 0 if all went well, else returns appropriate error value.
+ */
+int ti_sci_core_reboot(void);
+
+/**
+ * Processor control operations
+ *
+ * - ti_sci_proc_request - Command to request a physical processor control
+ * - ti_sci_proc_release - Command to release a physical processor control
+ * - ti_sci_proc_handover - Command to handover a physical processor control to
+ *                          a host in the processor's access control list.
+ *              @host_id: Host ID to get the control of the processor
+ * - ti_sci_proc_set_boot_cfg - Command to set the processor boot configuration flags
+ *              @config_flags_set: Configuration flags to be set
+ *              @config_flags_clear: Configuration flags to be cleared.
+ * - ti_sci_proc_set_boot_ctrl - Command to set the processor boot control flags
+ *              @control_flags_set: Control flags to be set
+ *              @control_flags_clear: Control flags to be cleared
+ * - ti_sci_proc_set_boot_ctrl_no_wait - Same as above without waiting for response
+ * - ti_sci_proc_auth_boot_image - Command to authenticate and load the image
+ *                                 and then set the processor configuration flags.
+ *              @cert_addr: Memory address at which payload image certificate is located.
+ * - ti_sci_proc_get_boot_status - Command to get the processor boot status
+ * - ti_sci_proc_wait_boot_status - Command to wait for a processor boot status
+ * - ti_sci_proc_wait_boot_status_no_wait - Same as above without waiting for response
+ *
+ * NOTE: for all these functions, the following are generic in nature:
+ * @proc_id:	Processor ID
+ * Returns 0 for successful request, else returns corresponding error message.
+ */
+int ti_sci_proc_request(uint8_t proc_id);
+int ti_sci_proc_release(uint8_t proc_id);
+int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id);
+int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector,
+			     uint32_t config_flags_set,
+			     uint32_t config_flags_clear);
+int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set,
+			      uint32_t control_flags_clear);
+int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id,
+				      uint32_t control_flags_set,
+				      uint32_t control_flags_clear);
+int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr);
+int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv,
+				uint32_t *cfg_flags,
+				uint32_t *ctrl_flags,
+				uint32_t *sts_flags);
+int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations,
+				 uint8_t num_match_iterations,
+				 uint8_t delay_per_iteration_us,
+				 uint8_t delay_before_iterations_us,
+				 uint32_t status_flags_1_set_all_wait,
+				 uint32_t status_flags_1_set_any_wait,
+				 uint32_t status_flags_1_clr_all_wait,
+				 uint32_t status_flags_1_clr_any_wait);
+int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id,
+					 uint8_t num_wait_iterations,
+					 uint8_t num_match_iterations,
+					 uint8_t delay_per_iteration_us,
+					 uint8_t delay_before_iterations_us,
+					 uint32_t status_flags_1_set_all_wait,
+					 uint32_t status_flags_1_set_any_wait,
+					 uint32_t status_flags_1_clr_all_wait,
+					 uint32_t status_flags_1_clr_any_wait);
+
+/**
+ * ti_sci_init() - Basic initialization
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+int ti_sci_init(void);
+
+#endif /* TI_SCI_H */
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
new file mode 100644
index 0000000..a921e51
--- /dev/null
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
@@ -0,0 +1,699 @@
+/*
+ * Texas Instruments System Control Interface (TISCI) Protocol
+ *
+ * Communication protocol with TI SCI hardware
+ * The system works in a message response protocol
+ * See: http://processors.wiki.ti.com/index.php/TISCI for details
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TI_SCI_PROTOCOL_H
+#define TI_SCI_PROTOCOL_H
+
+#include <stdint.h>
+
+/* Generic Messages */
+#define TI_SCI_MSG_ENABLE_WDT		0x0000
+#define TI_SCI_MSG_WAKE_RESET		0x0001
+#define TI_SCI_MSG_VERSION		0x0002
+#define TI_SCI_MSG_WAKE_REASON		0x0003
+#define TI_SCI_MSG_GOODBYE		0x0004
+#define TI_SCI_MSG_SYS_RESET		0x0005
+
+/* Device requests */
+#define TI_SCI_MSG_SET_DEVICE_STATE	0x0200
+#define TI_SCI_MSG_GET_DEVICE_STATE	0x0201
+#define TI_SCI_MSG_SET_DEVICE_RESETS	0x0202
+
+/* Clock requests */
+#define TI_SCI_MSG_SET_CLOCK_STATE	0x0100
+#define TI_SCI_MSG_GET_CLOCK_STATE	0x0101
+#define TI_SCI_MSG_SET_CLOCK_PARENT	0x0102
+#define TI_SCI_MSG_GET_CLOCK_PARENT	0x0103
+#define TI_SCI_MSG_GET_NUM_CLOCK_PARENTS 0x0104
+#define TI_SCI_MSG_SET_CLOCK_FREQ	0x010c
+#define TI_SCI_MSG_QUERY_CLOCK_FREQ	0x010d
+#define TI_SCI_MSG_GET_CLOCK_FREQ	0x010e
+
+/* Processor Control Messages */
+#define TISCI_MSG_PROC_REQUEST		0xc000
+#define TISCI_MSG_PROC_RELEASE		0xc001
+#define TISCI_MSG_PROC_HANDOVER		0xc005
+#define TISCI_MSG_SET_PROC_BOOT_CONFIG	0xc100
+#define TISCI_MSG_SET_PROC_BOOT_CTRL	0xc101
+#define TISCI_MSG_PROC_AUTH_BOOT_IMIAGE	0xc120
+#define TISCI_MSG_GET_PROC_BOOT_STATUS	0xc400
+#define TISCI_MSG_WAIT_PROC_BOOT_STATUS	0xc401
+
+/**
+ * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
+ * @type:	Type of messages: One of TI_SCI_MSG* values
+ * @host:	Host of the message
+ * @seq:	Message identifier indicating a transfer sequence
+ * @flags:	Flag for the message
+ */
+struct ti_sci_msg_hdr {
+	uint16_t type;
+	uint8_t host;
+	uint8_t seq;
+#define TI_SCI_MSG_FLAG(val)			(1 << (val))
+#define TI_SCI_FLAG_REQ_GENERIC_NORESPONSE	0x0
+#define TI_SCI_FLAG_REQ_ACK_ON_RECEIVED		TI_SCI_MSG_FLAG(0)
+#define TI_SCI_FLAG_REQ_ACK_ON_PROCESSED	TI_SCI_MSG_FLAG(1)
+#define TI_SCI_FLAG_RESP_GENERIC_NACK		0x0
+#define TI_SCI_FLAG_RESP_GENERIC_ACK		TI_SCI_MSG_FLAG(1)
+	/* Additional Flags */
+	uint32_t flags;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_version - Response for a message
+ * @hdr:		Generic header
+ * @firmware_description: String describing the firmware
+ * @firmware_revision:	Firmware revision
+ * @abi_major:		Major version of the ABI that firmware supports
+ * @abi_minor:		Minor version of the ABI that firmware supports
+ *
+ * In general, ABI version changes follow the rule that minor version increments
+ * are backward compatible. Major revision changes in ABI may not be
+ * backward compatible.
+ *
+ * Response to a generic message with message type TI_SCI_MSG_VERSION
+ */
+struct ti_sci_msg_resp_version {
+	struct ti_sci_msg_hdr hdr;
+#define FIRMWARE_DESCRIPTION_LENGTH 32
+	char firmware_description[FIRMWARE_DESCRIPTION_LENGTH];
+	uint16_t firmware_revision;
+	uint8_t abi_major;
+	uint8_t abi_minor;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_reboot - Reboot the SoC
+ * @hdr:	Generic Header
+ *
+ * Request type is TI_SCI_MSG_SYS_RESET, responded with a generic
+ * ACK/NACK message.
+ */
+struct ti_sci_msg_req_reboot {
+	struct ti_sci_msg_hdr hdr;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_set_device_state - Set the desired state of the device
+ * @hdr:		Generic header
+ * @id:	Indicates which device to modify
+ * @reserved: Reserved space in message, must be 0 for backward compatibility
+ * @state: The desired state of the device.
+ *
+ * Certain flags can also be set to alter the device state:
+ * + MSG_FLAG_DEVICE_WAKE_ENABLED - Configure the device to be a wake source.
+ * The meaning of this flag will vary slightly from device to device and from
+ * SoC to SoC but it generally allows the device to wake the SoC out of deep
+ * suspend states.
+ * + MSG_FLAG_DEVICE_RESET_ISO - Enable reset isolation for this device.
+ * + MSG_FLAG_DEVICE_EXCLUSIVE - Claim this device exclusively. When passed
+ * with STATE_RETENTION or STATE_ON, it will claim the device exclusively.
+ * If another host already has this device set to STATE_RETENTION or STATE_ON,
+ * the message will fail. Once successful, other hosts attempting to set
+ * STATE_RETENTION or STATE_ON will fail.
+ *
+ * Request type is TI_SCI_MSG_SET_DEVICE_STATE, responded with a generic
+ * ACK/NACK message.
+ */
+struct ti_sci_msg_req_set_device_state {
+	/* Additional hdr->flags options */
+#define MSG_FLAG_DEVICE_WAKE_ENABLED	TI_SCI_MSG_FLAG(8)
+#define MSG_FLAG_DEVICE_RESET_ISO	TI_SCI_MSG_FLAG(9)
+#define MSG_FLAG_DEVICE_EXCLUSIVE	TI_SCI_MSG_FLAG(10)
+	struct ti_sci_msg_hdr hdr;
+	uint32_t id;
+	uint32_t reserved;
+
+#define MSG_DEVICE_SW_STATE_AUTO_OFF	0
+#define MSG_DEVICE_SW_STATE_RETENTION	1
+#define MSG_DEVICE_SW_STATE_ON		2
+	uint8_t state;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_device_state - Request to get device.
+ * @hdr:		Generic header
+ * @id:		Device Identifier
+ *
+ * Request type is TI_SCI_MSG_GET_DEVICE_STATE, responded device state
+ * information
+ */
+struct ti_sci_msg_req_get_device_state {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_device_state - Response to get device request.
+ * @hdr:		Generic header
+ * @context_loss_count: Indicates how many times the device has lost context. A
+ *	driver can use this monotonic counter to determine if the device has
+ *	lost context since the last time this message was exchanged.
+ * @resets: Programmed state of the reset lines.
+ * @programmed_state:	The state as programmed by set_device.
+ *			- Uses the MSG_DEVICE_SW_* macros
+ * @current_state:	The actual state of the hardware.
+ *
+ * Response to request TI_SCI_MSG_GET_DEVICE_STATE.
+ */
+struct ti_sci_msg_resp_get_device_state {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t context_loss_count;
+	uint32_t resets;
+	uint8_t programmed_state;
+#define MSG_DEVICE_HW_STATE_OFF		0
+#define MSG_DEVICE_HW_STATE_ON		1
+#define MSG_DEVICE_HW_STATE_TRANS	2
+	uint8_t current_state;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_set_device_resets - Set the desired resets
+ *				configuration of the device
+ * @hdr:		Generic header
+ * @id:	Indicates which device to modify
+ * @resets: A bit field of resets for the device. The meaning, behavior,
+ *	and usage of the reset flags are device specific. 0 for a bit
+ *	indicates releasing the reset represented by that bit while 1
+ *	indicates keeping it held.
+ *
+ * Request type is TI_SCI_MSG_SET_DEVICE_RESETS, responded with a generic
+ * ACK/NACK message.
+ */
+struct ti_sci_msg_req_set_device_resets {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t id;
+	uint32_t resets;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_set_clock_state - Request to setup a Clock state
+ * @hdr:	Generic Header, Certain flags can be set specific to the clocks:
+ *		MSG_FLAG_CLOCK_ALLOW_SSC: Allow this clock to be modified
+ *		via spread spectrum clocking.
+ *		MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE: Allow this clock's
+ *		frequency to be changed while it is running so long as it
+ *		is within the min/max limits.
+ *		MSG_FLAG_CLOCK_INPUT_TERM: Enable input termination, this
+ *		is only applicable to clock inputs on the SoC pseudo-device.
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has it's own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @request_state: Request the state for the clock to be set to.
+ *		MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock,
+ *		it can be disabled, regardless of the state of the device
+ *		MSG_CLOCK_SW_STATE_AUTO: Allow the System Controller to
+ *		automatically manage the state of this clock. If the device
+ *		is enabled, then the clock is enabled. If the device is set
+ *		to off or retention, then the clock is internally set as not
+ *		being required by the device.(default)
+ *		MSG_CLOCK_SW_STATE_REQ:  Configure the clock to be enabled,
+ *		regardless of the state of the device.
+ *
+ * Normally, all required clocks are managed by TISCI entity, this is used
+ * only for specific control *IF* required. Auto managed state is
+ * MSG_CLOCK_SW_STATE_AUTO, in other states, TISCI entity assume remote
+ * will explicitly control.
+ *
+ * Request type is TI_SCI_MSG_SET_CLOCK_STATE, response is a generic
+ * ACK or NACK message.
+ */
+struct ti_sci_msg_req_set_clock_state {
+	/* Additional hdr->flags options */
+#define MSG_FLAG_CLOCK_ALLOW_SSC		TI_SCI_MSG_FLAG(8)
+#define MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE	TI_SCI_MSG_FLAG(9)
+#define MSG_FLAG_CLOCK_INPUT_TERM		TI_SCI_MSG_FLAG(10)
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint8_t clk_id;
+#define MSG_CLOCK_SW_STATE_UNREQ	0
+#define MSG_CLOCK_SW_STATE_AUTO		1
+#define MSG_CLOCK_SW_STATE_REQ		2
+	uint8_t request_state;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_clock_state - Request for clock state
+ * @hdr:	Generic Header
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has it's own set of clock inputs. This indexes
+ *		which clock input to get state of.
+ *
+ * Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state
+ * of the clock
+ */
+struct ti_sci_msg_req_get_clock_state {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint8_t clk_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_clock_state - Response to get clock state
+ * @hdr:	Generic Header
+ * @programmed_state: Any programmed state of the clock. This is one of
+ *		MSG_CLOCK_SW_STATE* values.
+ * @current_state: Current state of the clock. This is one of:
+ *		MSG_CLOCK_HW_STATE_NOT_READY: Clock is not ready
+ *		MSG_CLOCK_HW_STATE_READY: Clock is ready
+ *
+ * Response to TI_SCI_MSG_GET_CLOCK_STATE.
+ */
+struct ti_sci_msg_resp_get_clock_state {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t programmed_state;
+#define MSG_CLOCK_HW_STATE_NOT_READY	0
+#define MSG_CLOCK_HW_STATE_READY	1
+	uint8_t current_state;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_set_clock_parent - Set the clock parent
+ * @hdr:	Generic Header
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has it's own set of clock inputs. This indexes
+ *		which clock input to modify.
+ * @parent_id:	The new clock parent is selectable by an index via this
+ *		parameter.
+ *
+ * Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic
+ * ACK / NACK message.
+ */
+struct ti_sci_msg_req_set_clock_parent {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint8_t clk_id;
+	uint8_t parent_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_clock_parent - Get the clock parent
+ * @hdr:	Generic Header
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *		Each device has it's own set of clock inputs. This indexes
+ *		which clock input to get the parent for.
+ *
+ * Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information
+ */
+struct ti_sci_msg_req_get_clock_parent {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint8_t clk_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_clock_parent - Response with clock parent
+ * @hdr:	Generic Header
+ * @parent_id:	The current clock parent
+ *
+ * Response to TI_SCI_MSG_GET_CLOCK_PARENT.
+ */
+struct ti_sci_msg_resp_get_clock_parent {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t parent_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents
+ * @hdr:	Generic header
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *
+ * This request provides information about how many clock parent options
+ * are available for a given clock to a device. This is typically used
+ * for input clocks.
+ *
+ * Request type is TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, response is appropriate
+ * message, or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_get_clock_num_parents {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint8_t clk_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents
+ * @hdr:		Generic header
+ * @num_parents:	Number of clock parents
+ *
+ * Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS
+ */
+struct ti_sci_msg_resp_get_clock_num_parents {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t num_parents;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_query_clock_freq - Request to query a frequency
+ * @hdr:	Generic Header
+ * @dev_id:	Device identifier this request is for
+ * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @target_freq_hz: The target clock frequency. A frequency will be found
+ *		as close to this target frequency as possible.
+ * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @clk_id:	Clock identifier for the device for this request.
+ *
+ * NOTE: Normally clock frequency management is automatically done by TISCI
+ * entity. In case of specific requests, TISCI evaluates capability to achieve
+ * requested frequency within provided range and responds with
+ * result message.
+ *
+ * Request type is TI_SCI_MSG_QUERY_CLOCK_FREQ, response is appropriate message,
+ * or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_query_clock_freq {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint64_t min_freq_hz;
+	uint64_t target_freq_hz;
+	uint64_t max_freq_hz;
+	uint8_t clk_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_query_clock_freq - Response to a clock frequency query
+ * @hdr:	Generic Header
+ * @freq_hz:	Frequency that is the best match in Hz.
+ *
+ * Response to request type TI_SCI_MSG_QUERY_CLOCK_FREQ. NOTE: if the request
+ * cannot be satisfied, the message will be of type NACK.
+ */
+struct ti_sci_msg_resp_query_clock_freq {
+	struct ti_sci_msg_hdr hdr;
+	uint64_t freq_hz;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_set_clock_freq - Request to setup a clock frequency
+ * @hdr:	Generic Header
+ * @dev_id:	Device identifier this request is for
+ * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @target_freq_hz: The target clock frequency. The clock will be programmed
+ *		at a rate as close to this target frequency as possible.
+ * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
+ *		allowable programmed frequency and does not account for clock
+ *		tolerances and jitter.
+ * @clk_id:	Clock identifier for the device for this request.
+ *
+ * NOTE: Normally clock frequency management is automatically done by TISCI
+ * entity. In case of specific requests, TISCI evaluates capability to achieve
+ * requested range and responds with success/failure message.
+ *
+ * This sets the desired frequency for a clock within an allowable
+ * range. This message will fail on an enabled clock unless
+ * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally,
+ * if other clocks have their frequency modified due to this message,
+ * they also must have the MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled.
+ *
+ * Calling set frequency on a clock input to the SoC pseudo-device will
+ * inform the PMMC of that clock's frequency. Setting a frequency of
+ * zero will indicate the clock is disabled.
+ *
+ * Calling set frequency on clock outputs from the SoC pseudo-device will
+ * function similarly to setting the clock frequency on a device.
+ *
+ * Request type is TI_SCI_MSG_SET_CLOCK_FREQ, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_set_clock_freq {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint64_t min_freq_hz;
+	uint64_t target_freq_hz;
+	uint64_t max_freq_hz;
+	uint8_t clk_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency
+ * @hdr:	Generic Header
+ * @dev_id:	Device identifier this request is for
+ * @clk_id:	Clock identifier for the device for this request.
+ *
+ * NOTE: Normally clock frequency management is automatically done by TISCI
+ * entity. In some cases, clock frequencies are configured by host.
+ *
+ * Request type is TI_SCI_MSG_GET_CLOCK_FREQ, responded with clock frequency
+ * that the clock is currently at.
+ */
+struct ti_sci_msg_req_get_clock_freq {
+	struct ti_sci_msg_hdr hdr;
+	uint32_t dev_id;
+	uint8_t clk_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_resp_get_clock_freq - Response of clock frequency request
+ * @hdr:	Generic Header
+ * @freq_hz:	Frequency that the clock is currently on, in Hz.
+ *
+ * Response to request type TI_SCI_MSG_GET_CLOCK_FREQ.
+ */
+struct ti_sci_msg_resp_get_clock_freq {
+	struct ti_sci_msg_hdr hdr;
+	uint64_t freq_hz;
+} __packed;
+
+#define TISCI_ADDR_LOW_MASK		0x00000000ffffffff
+#define TISCI_ADDR_HIGH_MASK		0xffffffff00000000
+#define TISCI_ADDR_HIGH_SHIFT		32
+
+/**
+ * struct ti_sci_msg_req_proc_request - Request a processor
+ *
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ *
+ * Request type is TISCI_MSG_PROC_REQUEST, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_proc_request {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_proc_release - Release a processor
+ *
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ *
+ * Request type is TISCI_MSG_PROC_RELEASE, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_proc_release {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_proc_handover - Handover a processor to a host
+ *
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ * @host_id:		New Host we want to give control to
+ *
+ * Request type is TISCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_proc_handover {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint8_t host_id;
+} __packed;
+
+/* A53 Config Flags */
+#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_EN         0x00000001
+#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_NIDEN      0x00000002
+#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_SPIDEN     0x00000004
+#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_SPNIDEN    0x00000008
+#define PROC_BOOT_CFG_FLAG_ARMV8_AARCH32        0x00000100
+
+/* R5 Config Flags */
+#define PROC_BOOT_CFG_FLAG_R5_DBG_EN            0x00000001
+#define PROC_BOOT_CFG_FLAG_R5_DBG_NIDEN         0x00000002
+#define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP          0x00000100
+#define PROC_BOOT_CFG_FLAG_R5_TEINIT            0x00000200
+#define PROC_BOOT_CFG_FLAG_R5_NMFI_EN           0x00000400
+#define PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE       0x00000800
+#define PROC_BOOT_CFG_FLAG_R5_BTCM_EN           0x00001000
+#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN           0x00002000
+
+/**
+ * struct ti_sci_msg_req_set_proc_boot_config - Set Processor boot configuration
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ * @bootvector_low:	Lower 32bit (Little Endian) of boot vector
+ * @bootvector_high:	Higher 32bit (Little Endian) of boot vector
+ * @config_flags_set:	Optional Processor specific Config Flags to set.
+ *			Setting a bit here implies required bit sets to 1.
+ * @config_flags_clear:	Optional Processor specific Config Flags to clear.
+ *			Setting a bit here implies required bit gets cleared.
+ *
+ * Request type is TISCI_MSG_SET_PROC_BOOT_CONFIG, response is a generic
+ * ACK/NACK message.
+ */
+struct ti_sci_msg_req_set_proc_boot_config {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint32_t bootvector_low;
+	uint32_t bootvector_high;
+	uint32_t config_flags_set;
+	uint32_t config_flags_clear;
+} __packed;
+
+/* R5 Control Flags */
+#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT                0x00000001
+
+/**
+ * struct ti_sci_msg_req_set_proc_boot_ctrl - Set Processor boot control flags
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ * @config_flags_set:	Optional Processor specific Config Flags to set.
+ *			Setting a bit here implies required bit sets to 1.
+ * @config_flags_clear:	Optional Processor specific Config Flags to clear.
+ *			Setting a bit here implies required bit gets cleared.
+ *
+ * Request type is TISCI_MSG_SET_PROC_BOOT_CTRL, response is a generic ACK/NACK
+ * message.
+ */
+struct ti_sci_msg_req_set_proc_boot_ctrl {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint32_t control_flags_set;
+	uint32_t control_flags_clear;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_proc_auth_start_image - Authenticate and start image
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ * @cert_addr_low:	Lower 32bit (Little Endian) of certificate
+ * @cert_addr_high:	Higher 32bit (Little Endian) of certificate
+ *
+ * Request type is TISCI_MSG_PROC_AUTH_BOOT_IMAGE, response is a generic
+ * ACK/NACK message.
+ */
+struct ti_sci_msg_req_proc_auth_boot_image {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint32_t cert_addr_low;
+	uint32_t cert_addr_high;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_get_proc_boot_status - Get processor boot status
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ *
+ * Request type is TISCI_MSG_GET_PROC_BOOT_STATUS, response is appropriate
+ * message, or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_get_proc_boot_status {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+} __packed;
+
+/* ARMv8 Status Flags */
+#define PROC_BOOT_STATUS_FLAG_ARMV8_WFE			0x00000001
+#define PROC_BOOT_STATUS_FLAG_ARMV8_WFI			0x00000002
+
+/* R5 Status Flags */
+#define PROC_BOOT_STATUS_FLAG_R5_WFE			0x00000001
+#define PROC_BOOT_STATUS_FLAG_R5_WFI			0x00000002
+#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED		0x00000004
+#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED	0x00000100
+
+/**
+ * \brief Processor Status Response
+ * struct ti_sci_msg_resp_get_proc_boot_status - Processor boot status response
+ * @hdr:		Generic Header
+ * @processor_id:	ID of processor
+ * @bootvector_low:	Lower 32bit (Little Endian) of boot vector
+ * @bootvector_high:	Higher 32bit (Little Endian) of boot vector
+ * @config_flags:	Optional Processor specific Config Flags set.
+ * @control_flags:	Optional Processor specific Control Flags.
+ * @status_flags:	Optional Processor specific Status Flags set.
+ *
+ * Response to TISCI_MSG_GET_PROC_BOOT_STATUS.
+ */
+struct ti_sci_msg_resp_get_proc_boot_status {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint32_t bootvector_low;
+	uint32_t bootvector_high;
+	uint32_t config_flags;
+	uint32_t control_flags;
+	uint32_t status_flags;
+} __packed;
+
+/**
+ * struct ti_sci_msg_req_wait_proc_boot_status - Wait for a processor boot status
+ * @hdr:			Generic Header
+ * @processor_id:		ID of processor
+ * @num_wait_iterations		Total number of iterations we will check before
+ *				we will timeout and give up
+ * @num_match_iterations	How many iterations should we have continued
+ *				status to account for status bits glitching.
+ *				This is to make sure that match occurs for
+ *				consecutive checks. This implies that the
+ *				worst case should consider that the stable
+ *				time should at the worst be num_wait_iterations
+ *				num_match_iterations to prevent timeout.
+ * @delay_per_iteration_us	Specifies how long to wait (in micro seconds)
+ *				between each status checks. This is the minimum
+ *				duration, and overhead of register reads and
+ *				checks are on top of this and can vary based on
+ *				varied conditions.
+ * @delay_before_iterations_us	Specifies how long to wait (in micro seconds)
+ *				before the very first check in the first
+ *				iteration of status check loop. This is the
+ *				minimum duration, and overhead of register
+ *				reads and checks are.
+ * @status_flags_1_set_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 1.
+ * @status_flags_1_set_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 1.
+ * @status_flags_1_clr_all_wait	If non-zero, Specifies that all bits of the
+ *				status matching this field requested MUST be 0.
+ * @status_flags_1_clr_any_wait	If non-zero, Specifies that at least one of the
+ *				bits matching this field requested MUST be 0.
+ *
+ * Request type is TISCI_MSG_WAIT_PROC_BOOT_STATUS, response is appropriate
+ * message, or NACK in case of inability to satisfy request.
+ */
+struct ti_sci_msg_req_wait_proc_boot_status {
+	struct ti_sci_msg_hdr hdr;
+	uint8_t processor_id;
+	uint8_t num_wait_iterations;
+	uint8_t num_match_iterations;
+	uint8_t delay_per_iteration_us;
+	uint8_t delay_before_iterations_us;
+	uint32_t status_flags_1_set_all_wait;
+	uint32_t status_flags_1_set_any_wait;
+	uint32_t status_flags_1_clr_all_wait;
+	uint32_t status_flags_1_clr_any_wait;
+} __packed;
+
+#endif /* TI_SCI_PROTOCOL_H */
diff --git a/plat/ti/k3/common/k3_bl31_setup.c b/plat/ti/k3/common/k3_bl31_setup.c
new file mode 100644
index 0000000..8bd7362
--- /dev/null
+++ b/plat/ti/k3/common/k3_bl31_setup.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <k3_console.h>
+#include <k3_gicv3.h>
+#include <ti_sci.h>
+
+/* Table of regions to map using the MMU */
+const mmap_region_t plat_k3_mmap[] = {
+	MAP_REGION_FLAT(K3_USART_BASE,       K3_USART_SIZE,       MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(K3_GIC_BASE,         K3_GIC_SIZE,         MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SEC_PROXY_RT_BASE,   SEC_PROXY_RT_SIZE,   MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SEC_PROXY_SCFG_BASE, SEC_PROXY_SCFG_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SEC_PROXY_DATA_BASE, SEC_PROXY_DATA_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	{ /* sentinel */ }
+};
+
+/*
+ * Placeholder variables for maintaining information about the next image(s)
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+static uint32_t k3_get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned int mode;
+	uint32_t spsr;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup, such as console init and deciding on
+ * memory layout.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(arg0 == 0U);
+	assert(arg1 == 0U);
+
+	bl31_console_setup();
+
+#ifdef BL32_BASE
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+					  DISABLE_ALL_EXCEPTIONS);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+#endif
+
+	/* Populate entry point information for BL33 */
+	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+	bl33_image_ep_info.pc = PRELOADED_BL33_BASE;
+	bl33_image_ep_info.spsr = k3_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#ifdef K3_HW_CONFIG_BASE
+	/*
+	 * According to the file ``Documentation/arm64/booting.txt`` of the
+	 * Linux kernel tree, Linux expects the physical address of the device
+	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
+	 * must be 0.
+	 */
+	bl33_image_ep_info.args.arg0 = (u_register_t)K3_HW_CONFIG_BASE;
+	bl33_image_ep_info.args.arg1 = 0U;
+	bl33_image_ep_info.args.arg2 = 0U;
+	bl33_image_ep_info.args.arg3 = 0U;
+#endif
+}
+
+void bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL31_START,           BL31_END            - BL31_START,           MT_MEMORY  | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE,         BL_CODE_END         - BL_CODE_BASE,         MT_CODE    | MT_RO | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE,      BL_RO_DATA_END      - BL_RO_DATA_BASE,      MT_RO_DATA | MT_RO | MT_SECURE),
+#if USE_COHERENT_MEM
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE  | MT_RW | MT_SECURE),
+#endif
+		{ /* sentinel */ }
+	};
+
+	setup_page_tables(bl_regions, plat_k3_mmap);
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	k3_gic_driver_init(K3_GIC_BASE);
+	k3_gic_init();
+
+	ti_sci_init();
+}
+
+void platform_mem_init(void)
+{
+	/* Do nothing for now... */
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+/*
+ * Empty function to prevent the console from being uninitialized after BL33 is
+ * started and allow us to see messages from BL31.
+ */
+void bl31_plat_runtime_setup(void)
+{
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image
+ * for the security state specified. BL3-3 corresponds to the non-secure
+ * image type while BL3-2 corresponds to the secure image type. A NULL
+ * pointer is returned if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type));
+	next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info :
+						 &bl32_image_ep_info;
+	/*
+	 * None of the images on the ARM development platforms can have 0x0
+	 * as the entrypoint
+	 */
+	if (next_image_info->pc)
+		return next_image_info;
+
+	NOTICE("Requested nonexistent image\n");
+	return NULL;
+}
diff --git a/plat/ti/k3/common/k3_console.c b/plat/ti/k3/common/k3_console.c
new file mode 100644
index 0000000..ba0ddac
--- /dev/null
+++ b/plat/ti/k3/common/k3_console.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+
+#include <k3_console.h>
+
+void bl31_console_setup(void)
+{
+	static console_16550_t console;
+
+	/* Initialize the console to provide early debug support */
+	console_16550_register(K3_USART_BASE, K3_USART_CLK_SPEED,
+			       K3_USART_BAUD, &console);
+}
diff --git a/plat/ti/k3/common/k3_gicv3.c b/plat/ti/k3/common/k3_gicv3.c
new file mode 100644
index 0000000..1932eaa
--- /dev/null
+++ b/plat/ti/k3/common/k3_gicv3.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include <k3_gicv3.h>
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t k3_interrupt_props[] = {
+	PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S),
+	PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+static unsigned int k3_mpidr_to_core_pos(unsigned long mpidr)
+{
+	return (unsigned int)plat_core_pos_by_mpidr(mpidr);
+}
+
+gicv3_driver_data_t k3_gic_data = {
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.interrupt_props = k3_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(k3_interrupt_props),
+	.mpidr_to_core_pos = k3_mpidr_to_core_pos,
+};
+
+void k3_gic_driver_init(uintptr_t gic_base)
+{
+	/* GIC Distributor is always at the base of the IP */
+	uintptr_t gicd_base = gic_base;
+	/* GIC Redistributor base is run-time detected */
+	uintptr_t gicr_base = 0;
+
+	for (unsigned int gicr_shift = 18; gicr_shift < 21; gicr_shift++) {
+		uintptr_t gicr_check = gic_base + BIT(gicr_shift);
+		uint32_t iidr = mmio_read_32(gicr_check + GICR_IIDR);
+		if (iidr != 0) {
+			/* Found the GICR base */
+			gicr_base = gicr_check;
+			break;
+		}
+	}
+	/* Assert if we have not found the GICR base */
+	assert(gicr_base != 0);
+
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+	k3_gic_data.gicd_base = gicd_base;
+	k3_gic_data.gicr_base = gicr_base;
+	gicv3_driver_init(&k3_gic_data);
+}
+
+void k3_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void k3_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void k3_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void k3_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/ti/k3/common/k3_helpers.S b/plat/ti/k3/common/k3_helpers.S
new file mode 100644
index 0000000..3afca59
--- /dev/null
+++ b/plat/ti/k3/common/k3_helpers.S
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <platform_def.h>
+
+#define K3_BOOT_REASON_COLD_RESET 0x1
+
+	/* ------------------------------------------------------------------
+	 *  uintptr_t plat_get_my_entrypoint(void)
+	 * ------------------------------------------------------------------
+	 *
+	 * This function is called with the called with the MMU and caches
+	 * disabled (SCTLR_EL3.M = 0 and SCTLR_EL3.C = 0). The function is
+	 * responsible for distinguishing between a warm and cold reset for the
+	 * current CPU using platform-specific means. If it's a warm reset,
+	 * then it returns the warm reset entrypoint point provided to
+	 * plat_setup_psci_ops() during BL31 initialization. If it's a cold
+	 * reset then this function must return zero.
+	 *
+	 * This function does not follow the Procedure Call Standard used by
+	 * the Application Binary Interface for the ARM 64-bit architecture.
+	 * The caller should not assume that callee saved registers are
+	 * preserved across a call to this function.
+	 */
+	.globl	plat_get_my_entrypoint
+func plat_get_my_entrypoint
+	ldr x0, k3_boot_reason_data_store
+	cmp  x0, #K3_BOOT_REASON_COLD_RESET
+
+	/* We ONLY support cold boot at this point */
+	bne plat_unsupported_boot
+	mov	x0, #0
+	ret
+
+	/*
+	 * We self manage our boot reason.
+	 * At load time, we have just a default reason - which is cold reset
+	 */
+k3_boot_reason_data_store:
+	.word	K3_BOOT_REASON_COLD_RESET
+
+plat_unsupported_boot:
+	b plat_unsupported_boot
+
+endfunc plat_get_my_entrypoint
+
+	/* ------------------------------------------------------------------
+	 * unsigned int plat_my_core_pos(void)
+	 * ------------------------------------------------------------------
+	 *
+	 * This function returns the index of the calling CPU which is used as a
+	 * CPU-specific linear index into blocks of memory (for example while
+	 * allocating per-CPU stacks). This function will be invoked very early
+	 * in the initialization sequence which mandates that this function
+	 * should be implemented in assembly and should not rely on the
+	 * avalability of a C runtime environment. This function can clobber x0
+	 * - x8 and must preserve x9 - x29.
+	 *
+	 * This function plays a crucial role in the power domain topology
+	 * framework in PSCI and details of this can be found in Power Domain
+	 * Topology Design.
+	 */
+	.globl plat_my_core_pos
+func plat_my_core_pos
+	mrs	x0, MPIDR_EL1
+
+	and	x1, x0, #MPIDR_CLUSTER_MASK
+	lsr	x1, x1, #MPIDR_AFF1_SHIFT
+	and	x0, x0, #MPIDR_CPU_MASK
+
+	cmp	x1, 0
+	b.eq out
+	add	x0, x0, #K3_CLUSTER0_CORE_COUNT
+
+	cmp	x1, 1
+	b.eq out
+	add	x0, x0, #K3_CLUSTER1_CORE_COUNT
+
+	cmp	x1, 2
+	b.eq out
+	add	x0, x0, #K3_CLUSTER2_CORE_COUNT
+
+out:
+	ret
+endfunc plat_my_core_pos
+
+	/* --------------------------------------------------------------------
+	 * This handler does the following:
+	 * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A72
+	 * --------------------------------------------------------------------
+	 */
+	.globl plat_reset_handler
+func plat_reset_handler
+	/* Only on Cortex-A72 */
+	jump_if_cpu_midr CORTEX_A72_MIDR, a72
+	ret
+
+	/* Cortex-A72 specific settings */
+a72:
+	mrs x0, CORTEX_A72_L2CTLR_EL1
+	orr x0, x0, #(CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT)
+	msr CORTEX_A72_L2CTLR_EL1, x0
+	isb
+	ret
+endfunc plat_reset_handler
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+	.globl plat_crash_console_init
+func plat_crash_console_init
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	mov_imm	x1, CRASH_CONSOLE_CLK
+	mov_imm	x2, CRASH_CONSOLE_BAUD_RATE
+	mov w3, #0x0
+	b	console_16550_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(void)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+	.globl plat_crash_console_putc
+func plat_crash_console_putc
+	mov_imm	x1, CRASH_CONSOLE_BASE
+	b	console_16550_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+	.globl plat_crash_console_flush
+func plat_crash_console_flush
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	b	console_16550_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/ti/k3/common/k3_psci.c b/plat/ti/k3/common/k3_psci.c
new file mode 100644
index 0000000..de9cefe
--- /dev/null
+++ b/plat/ti/k3/common/k3_psci.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include <ti_sci_protocol.h>
+#include <k3_gicv3.h>
+#include <ti_sci.h>
+
+uintptr_t k3_sec_entrypoint;
+
+static void k3_cpu_standby(plat_local_state_t cpu_state)
+{
+	unsigned int scr;
+
+	scr = read_scr_el3();
+	/* Enable the Non secure interrupt to wake the CPU */
+	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+	isb();
+	/* dsb is good practice before using wfi to enter low power states */
+	dsb();
+	/* Enter standby state */
+	wfi();
+	/* Restore SCR */
+	write_scr_el3(scr);
+}
+
+static int k3_pwr_domain_on(u_register_t mpidr)
+{
+	int core_id, proc, device, ret;
+
+	core_id = plat_core_pos_by_mpidr(mpidr);
+	if (core_id < 0) {
+		ERROR("Could not get target core id: %d\n", core_id);
+		return PSCI_E_INTERN_FAIL;
+	}
+
+	proc = PLAT_PROC_START_ID + core_id;
+	device = PLAT_PROC_DEVICE_START_ID + core_id;
+
+	ret = ti_sci_proc_request(proc);
+	if (ret) {
+		ERROR("Request for processor failed: %d\n", ret);
+		return PSCI_E_INTERN_FAIL;
+	}
+
+	ret = ti_sci_proc_set_boot_cfg(proc, k3_sec_entrypoint, 0, 0);
+	if (ret) {
+		ERROR("Request to set core boot address failed: %d\n", ret);
+		return PSCI_E_INTERN_FAIL;
+	}
+
+	ret = ti_sci_device_get(device);
+	if (ret) {
+		ERROR("Request to start core failed: %d\n", ret);
+		return PSCI_E_INTERN_FAIL;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+void k3_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	int core_id, proc, device, ret;
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	k3_gic_cpuif_disable();
+
+	core_id = plat_my_core_pos();
+	proc = PLAT_PROC_START_ID + core_id;
+	device = PLAT_PROC_DEVICE_START_ID + core_id;
+
+	/* Start by sending wait for WFI command */
+	ret = ti_sci_proc_wait_boot_status_no_wait(proc,
+			/*
+			 * Wait maximum time to give us the best chance to get
+			 * to WFI before this command timeouts
+			 */
+			UINT8_MAX, 100, UINT8_MAX, UINT8_MAX,
+			/* Wait for WFI */
+			PROC_BOOT_STATUS_FLAG_ARMV8_WFI, 0, 0, 0);
+	if (ret) {
+		ERROR("Sending wait for WFI failed (%d)\n", ret);
+		return;
+	}
+
+	/* Now queue up the core shutdown request */
+	ret = ti_sci_device_put_no_wait(device);
+	if (ret) {
+		ERROR("Sending core shutdown message failed (%d)\n", ret);
+		return;
+	}
+}
+
+void k3_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* TODO: Indicate to System firmware about completion */
+
+	k3_gic_pcpu_init();
+	k3_gic_cpuif_enable();
+}
+
+static void __dead2 k3_system_reset(void)
+{
+	/* Send the system reset request to system firmware */
+	ti_sci_core_reboot();
+
+	while (true)
+		wfi();
+}
+
+static int k3_validate_power_state(unsigned int power_state,
+				   psci_power_state_t *req_state)
+{
+	/* TODO: perform the proper validation */
+
+	return PSCI_E_SUCCESS;
+}
+
+static int k3_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/* TODO: perform the proper validation */
+
+	return PSCI_E_SUCCESS;
+}
+
+static const plat_psci_ops_t k3_plat_psci_ops = {
+	.cpu_standby = k3_cpu_standby,
+	.pwr_domain_on = k3_pwr_domain_on,
+	.pwr_domain_off = k3_pwr_domain_off,
+	.pwr_domain_on_finish = k3_pwr_domain_on_finish,
+	.system_reset = k3_system_reset,
+	.validate_power_state = k3_validate_power_state,
+	.validate_ns_entrypoint = k3_validate_ns_entrypoint
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	k3_sec_entrypoint = sec_entrypoint;
+
+	*psci_ops = &k3_plat_psci_ops;
+
+	return 0;
+}
diff --git a/plat/ti/k3/common/k3_topology.c b/plat/ti/k3/common/k3_topology.c
new file mode 100644
index 0000000..139f1fd
--- /dev/null
+++ b/plat/ti/k3/common/k3_topology.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <lib/psci/psci.h>
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+	PLATFORM_SYSTEM_COUNT,
+	PLATFORM_CLUSTER_COUNT,
+	K3_CLUSTER0_CORE_COUNT,
+	K3_CLUSTER1_CORE_COUNT,
+	K3_CLUSTER2_CORE_COUNT,
+	K3_CLUSTER3_CORE_COUNT,
+};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (MPIDR_AFFLVL3_VAL(mpidr) > 0 ||
+	    MPIDR_AFFLVL2_VAL(mpidr) > 0) {
+		return -1;
+	}
+
+	if (cluster > 0)
+		core += K3_CLUSTER0_CORE_COUNT;
+	if (cluster > 1)
+		core += K3_CLUSTER1_CORE_COUNT;
+	if (cluster > 2)
+		core += K3_CLUSTER2_CORE_COUNT;
+	if (cluster > 3)
+		return -1;
+
+	return core;
+}
diff --git a/plat/ti/k3/common/plat_common.mk b/plat/ti/k3/common/plat_common.mk
new file mode 100644
index 0000000..20a94ef
--- /dev/null
+++ b/plat/ti/k3/common/plat_common.mk
@@ -0,0 +1,83 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# We don't use BL1 or BL2, so BL31 is the first image to execute
+RESET_TO_BL31		:=	1
+# Only one core starts up at first
+COLD_BOOT_SINGLE_CPU	:=	1
+# We can choose where a core starts executing
+PROGRAMMABLE_RESET_ADDRESS:=	1
+
+# System coherency is managed in hardware
+WARMBOOT_ENABLE_DCACHE_EARLY :=	1
+USE_COHERENT_MEM	:=	1
+
+# A53 erratum for SoC. (enable them all)
+ERRATA_A53_826319	:=	1
+ERRATA_A53_835769	:=	1
+ERRATA_A53_836870	:=	1
+ERRATA_A53_843419	:=	1
+ERRATA_A53_855873	:=	1
+
+# A72 Erratum for SoC
+ERRATA_A72_859971	:=	1
+
+CRASH_REPORTING		:= 1
+HANDLE_EA_EL3_FIRST	:= 1
+
+# Split out RO data into a non-executable section
+SEPARATE_CODE_AND_RODATA :=    1
+
+TI_16550_MDR_QUIRK	:=	1
+$(eval $(call add_define,TI_16550_MDR_QUIRK))
+
+# Allow customizing the UART baud rate
+K3_USART_BAUD		:=	115200
+$(eval $(call add_define,K3_USART_BAUD))
+
+# Libraries
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES		+=	\
+				-I${PLAT_PATH}/include			\
+				-I${PLAT_PATH}/common/drivers/sec_proxy	\
+				-I${PLAT_PATH}/common/drivers/ti_sci	\
+
+K3_CONSOLE_SOURCES	+=	\
+				drivers/ti/uart/aarch64/16550_console.S	\
+				${PLAT_PATH}/common/k3_console.c	\
+
+K3_GIC_SOURCES		+=	\
+				drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				${PLAT_PATH}/common/k3_gicv3.c		\
+
+K3_PSCI_SOURCES		+=	\
+				plat/common/plat_psci_common.c		\
+				${PLAT_PATH}/common/k3_psci.c		\
+
+K3_SEC_PROXY_SOURCES	+=	\
+				${PLAT_PATH}/common/drivers/sec_proxy/sec_proxy.c \
+
+K3_TI_SCI_SOURCES	+=	\
+				${PLAT_PATH}/common/drivers/ti_sci/ti_sci.c \
+
+PLAT_BL_COMMON_SOURCES	+=	\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				${XLAT_TABLES_LIB_SRCS}			\
+				${K3_CONSOLE_SOURCES}			\
+
+BL31_SOURCES		+=	\
+				${PLAT_PATH}/common/k3_bl31_setup.c	\
+				${PLAT_PATH}/common/k3_helpers.S	\
+				${PLAT_PATH}/common/k3_topology.c	\
+				${K3_GIC_SOURCES}			\
+				${K3_PSCI_SOURCES}			\
+				${K3_SEC_PROXY_SOURCES}			\
+				${K3_TI_SCI_SOURCES}			\
diff --git a/plat/ti/k3/include/k3_console.h b/plat/ti/k3/include/k3_console.h
new file mode 100644
index 0000000..6376ab3
--- /dev/null
+++ b/plat/ti/k3/include/k3_console.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef K3_CONSOLE_H
+#define K3_CONSOLE_H
+
+void bl31_console_setup(void);
+
+#endif /* K3_CONSOLE_H */
diff --git a/plat/ti/k3/include/k3_gicv3.h b/plat/ti/k3/include/k3_gicv3.h
new file mode 100644
index 0000000..2329a16
--- /dev/null
+++ b/plat/ti/k3/include/k3_gicv3.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef K3_GICV3_H
+#define K3_GICV3_H
+
+#include <stdint.h>
+
+void k3_gic_driver_init(uintptr_t gic_base);
+void k3_gic_init(void);
+void k3_gic_cpuif_enable(void);
+void k3_gic_cpuif_disable(void);
+void k3_gic_pcpu_init(void);
+
+#endif /* K3_GICV3_H */
diff --git a/plat/ti/k3/include/plat_macros.S b/plat/ti/k3/include/plat_macros.S
new file mode 100644
index 0000000..38056b5
--- /dev/null
+++ b/plat/ti/k3/include/plat_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant platform registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	/* STUB */
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/ti/k3/include/platform_def.h b/plat/ti/k3/include/platform_def.h
new file mode 100644
index 0000000..690c68e
--- /dev/null
+++ b/plat/ti/k3/include/platform_def.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+
+#include <board_def.h>
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stack */
+#if IMAGE_BL31
+#define PLATFORM_STACK_SIZE		0x800
+#else
+#define PLATFORM_STACK_SIZE		0x1000
+#endif
+
+#define PLATFORM_SYSTEM_COUNT		1
+#define PLATFORM_CORE_COUNT		(K3_CLUSTER0_CORE_COUNT + \
+					K3_CLUSTER1_CORE_COUNT + \
+					K3_CLUSTER2_CORE_COUNT + \
+					K3_CLUSTER3_CORE_COUNT)
+
+#define PLATFORM_CLUSTER_COUNT		((K3_CLUSTER0_CORE_COUNT != 0) + \
+					(K3_CLUSTER1_CORE_COUNT != 0) + \
+					(K3_CLUSTER2_CORE_COUNT != 0) + \
+					(K3_CLUSTER3_CORE_COUNT != 0))
+
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_SYSTEM_COUNT + \
+					PLATFORM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+
+/*******************************************************************************
+ * Memory layout constants
+ ******************************************************************************/
+
+/*
+ * ARM-TF lives in SRAM, partition it here
+ *
+ * BL3-1 specific defines.
+ *
+ * Put BL3-1 at the base of the Trusted SRAM.
+ */
+#define BL31_BASE			SEC_SRAM_BASE
+#define BL31_SIZE			SEC_SRAM_SIZE
+#define BL31_LIMIT			(BL31_BASE + BL31_SIZE)
+
+/*
+ * Defines the maximum number of translation tables that are allocated by the
+ * translation table library code. To minimize the amount of runtime memory
+ * used, choose the smallest value needed to map the required virtual addresses
+ * for each BL stage.
+ */
+#define MAX_XLAT_TABLES		8
+
+/*
+ * Defines the maximum number of regions that are allocated by the translation
+ * table library code. A region consists of physical base address, virtual base
+ * address, size and attributes (Device/Memory, RO/RW, Secure/Non-Secure), as
+ * defined in the `mmap_region_t` structure. The platform defines the regions
+ * that should be mapped. Then, the translation table library will create the
+ * corresponding tables and descriptors at runtime. To minimize the amount of
+ * runtime memory used, choose the smallest value needed to register the
+ * required regions for each BL stage.
+ */
+#define MAX_MMAP_REGIONS	11
+
+/*
+ * Defines the total size of the address space in bytes. For example, for a 32
+ * bit address space, this value should be `(1ull << 32)`.
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+/* Platform default console definitions */
+#ifndef K3_USART_BASE
+#define K3_USART_BASE 0x02800000
+#endif
+
+/* USART has a default size for address space */
+#define K3_USART_SIZE 0x1000
+
+#ifndef K3_USART_CLK_SPEED
+#define K3_USART_CLK_SPEED 48000000
+#endif
+
+/* Crash console defaults */
+#define CRASH_CONSOLE_BASE K3_USART_BASE
+#define CRASH_CONSOLE_CLK K3_USART_CLK_SPEED
+#define CRASH_CONSOLE_BAUD_RATE K3_USART_BAUD
+
+/* Timer frequency */
+#ifndef SYS_COUNTER_FREQ_IN_TICKS
+#define SYS_COUNTER_FREQ_IN_TICKS 200000000
+#endif
+
+/* Interrupt numbers */
+#define ARM_IRQ_SEC_PHY_TIMER		29
+
+#define ARM_IRQ_SEC_SGI_0		8
+#define ARM_IRQ_SEC_SGI_1		9
+#define ARM_IRQ_SEC_SGI_2		10
+#define ARM_IRQ_SEC_SGI_3		11
+#define ARM_IRQ_SEC_SGI_4		12
+#define ARM_IRQ_SEC_SGI_5		13
+#define ARM_IRQ_SEC_SGI_6		14
+#define ARM_IRQ_SEC_SGI_7		15
+
+/*
+ * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+
+#define K3_GIC_BASE	0x01800000
+#define K3_GIC_SIZE	0x200000
+
+#define SEC_PROXY_DATA_BASE	0x32C00000
+#define SEC_PROXY_DATA_SIZE	0x80000
+#define SEC_PROXY_SCFG_BASE	0x32800000
+#define SEC_PROXY_SCFG_SIZE	0x80000
+#define SEC_PROXY_RT_BASE	0x32400000
+#define SEC_PROXY_RT_SIZE	0x80000
+
+#define SEC_PROXY_TIMEOUT_US		1000000
+#define SEC_PROXY_MAX_MESSAGE_SIZE	56
+
+#define TI_SCI_HOST_ID			10
+#define TI_SCI_MAX_MESSAGE_SIZE		52
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/ti/k3/platform.mk b/plat/ti/k3/platform.mk
new file mode 100644
index 0000000..65d5cc2
--- /dev/null
+++ b/plat/ti/k3/platform.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PLAT_PATH	:=	plat/ti/k3
+TARGET_BOARD	?=	generic
+
+include ${PLAT_PATH}/common/plat_common.mk
+include ${PLAT_PATH}/board/${TARGET_BOARD}/board.mk
+
+# modify BUILD_PLAT to point to board specific build directory
+BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${TARGET_BOARD}/${BUILD_TYPE}
diff --git a/plat/xilinx/common/include/ipi.h b/plat/xilinx/common/include/ipi.h
new file mode 100644
index 0000000..483902e
--- /dev/null
+++ b/plat/xilinx/common/include/ipi.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Xilinx IPI management configuration data and macros */
+
+#ifndef IPI_H
+#define IPI_H
+
+#include <stdint.h>
+
+/*********************************************************************
+ * IPI mailbox status macros
+ ********************************************************************/
+#define IPI_MB_STATUS_IDLE		0
+#define IPI_MB_STATUS_SEND_PENDING	1
+#define IPI_MB_STATUS_RECV_PENDING	2
+
+/*********************************************************************
+ * IPI mailbox call is secure or not macros
+ ********************************************************************/
+#define IPI_MB_CALL_NOTSECURE	0
+#define IPI_MB_CALL_SECURE	1
+
+/*********************************************************************
+ * IPI secure check
+ ********************************************************************/
+#define IPI_SECURE_MASK  0x1U
+#define IPI_IS_SECURE(I) ((ipi_table[(I)].secure_only & \
+			   IPI_SECURE_MASK) ? 1 : 0)
+
+/*********************************************************************
+ * Struct definitions
+ ********************************************************************/
+
+/* structure to maintain IPI configuration information */
+struct ipi_config {
+	unsigned int ipi_bit_mask;
+	unsigned int ipi_reg_base;
+	unsigned char secure_only;
+};
+
+/*********************************************************************
+ * IPI APIs declarations
+ ********************************************************************/
+
+/* Initialize IPI configuration table */
+void ipi_config_table_init(const struct ipi_config *ipi_table,
+			   uint32_t total_ipi);
+
+/* Validate IPI mailbox access */
+int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure);
+
+/* Open the IPI mailbox */
+void ipi_mb_open(uint32_t local, uint32_t remote);
+
+/* Release the IPI mailbox */
+void ipi_mb_release(uint32_t local, uint32_t remote);
+
+/* Enquire IPI mailbox status */
+int ipi_mb_enquire_status(uint32_t local, uint32_t remote);
+
+/* Trigger notification on the IPI mailbox */
+void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking);
+
+/* Ack IPI mailbox notification */
+void ipi_mb_ack(uint32_t local, uint32_t remote);
+
+/* Disable IPI mailbox notification interrupt */
+void ipi_mb_disable_irq(uint32_t local, uint32_t remote);
+
+/* Enable IPI mailbox notification interrupt */
+void ipi_mb_enable_irq(uint32_t local, uint32_t remote);
+
+#endif /* IPI_H */
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
new file mode 100644
index 0000000..c0a51f0
--- /dev/null
+++ b/plat/xilinx/common/include/pm_common.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains definitions of commonly used macros and data types needed
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PM_COMMON_H
+#define PM_COMMON_H
+
+#include <stdint.h>
+#include <plat_pm_common.h>
+
+/**
+ * pm_ipi - struct for capturing IPI-channel specific info
+ * @local_ipi_id	Local IPI agent ID
+ * @remote_ipi_id	Remote IPI Agent ID
+ * @buffer_base	base address for payload buffer
+ */
+struct pm_ipi {
+	const uint32_t local_ipi_id;
+	const uint32_t remote_ipi_id;
+	const uintptr_t buffer_base;
+};
+
+/**
+ * pm_proc - struct for capturing processor related info
+ * @node_id	node-ID of the processor
+ * @pwrdn_mask	cpu-specific mask to be used for power control register
+ * @ipi		pointer to IPI channel structure
+ *		(in APU all processors share one IPI channel)
+ */
+struct pm_proc {
+	const uint32_t node_id;
+	const unsigned int pwrdn_mask;
+	const struct pm_ipi *ipi;
+};
+
+const struct pm_proc *pm_get_proc(unsigned int cpuid);
+
+#endif /* PM_COMMON_H */
diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h
new file mode 100644
index 0000000..16db5c5
--- /dev/null
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_IPI_H
+#define PM_IPI_H
+
+#include <plat_ipi.h>
+#include "pm_common.h"
+
+#define IPI_BLOCKING		1
+#define IPI_NON_BLOCKING	0
+
+int pm_ipi_init(const struct pm_proc *proc);
+
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+			       uint32_t payload[PAYLOAD_ARG_CNT]);
+enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
+					    uint32_t payload[PAYLOAD_ARG_CNT]);
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+				    uint32_t payload[PAYLOAD_ARG_CNT],
+				    unsigned int *value, size_t count);
+void pm_ipi_buff_read_callb(unsigned int *value, size_t count);
+void pm_ipi_irq_enable(const struct pm_proc *proc);
+void pm_ipi_irq_clear(const struct pm_proc *proc);
+uint32_t pm_ipi_irq_status(const struct pm_proc *proc);
+
+#endif /* PM_IPI_H */
diff --git a/plat/xilinx/common/ipi.c b/plat/xilinx/common/ipi.c
new file mode 100644
index 0000000..0b8020b
--- /dev/null
+++ b/plat/xilinx/common/ipi.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Xilinx IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+/*********************************************************************
+ * Macros definitions
+ ********************************************************************/
+
+/* IPI registers offsets macros */
+#define IPI_TRIG_OFFSET 0x00U
+#define IPI_OBR_OFFSET  0x04U
+#define IPI_ISR_OFFSET  0x10U
+#define IPI_IMR_OFFSET  0x14U
+#define IPI_IER_OFFSET  0x18U
+#define IPI_IDR_OFFSET  0x1CU
+
+/* IPI register start offset */
+#define IPI_REG_BASE(I) (ipi_table[(I)].ipi_reg_base)
+
+/* IPI register bit mask */
+#define IPI_BIT_MASK(I) (ipi_table[(I)].ipi_bit_mask)
+
+/* IPI configuration table */
+const static struct ipi_config *ipi_table;
+
+/* Total number of IPI */
+static uint32_t ipi_total;
+
+/**
+ * ipi_config_init() - Initialize IPI configuration data
+ *
+ * @ipi_config_table  - IPI configuration table
+ * @ipi_total - Total number of IPI available
+ *
+ */
+void ipi_config_table_init(const struct ipi_config *ipi_config_table,
+			   uint32_t total_ipi)
+{
+	ipi_table = ipi_config_table;
+	ipi_total = total_ipi;
+}
+
+/* is_ipi_mb_within_range() - verify if IPI mailbox is within range
+ *
+ * @local  - local IPI ID
+ * @remote - remote IPI ID
+ *
+ * return - 1 if within range, 0 if not
+ */
+static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote)
+{
+	int ret = 1;
+
+	if (remote >= ipi_total || local >= ipi_total)
+		ret = 0;
+
+	return ret;
+}
+
+/**
+ * ipi_mb_validate() - validate IPI mailbox access
+ *
+ * @local  - local IPI ID
+ * @remote - remote IPI ID
+ * @is_secure - indicate if the requester is from secure software
+ *
+ * return - 0 success, negative value for errors
+ */
+int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure)
+{
+	int ret = 0;
+
+	if (!is_ipi_mb_within_range(local, remote))
+		ret = -EINVAL;
+	else if (IPI_IS_SECURE(local) && !is_secure)
+		ret = -EPERM;
+	else if (IPI_IS_SECURE(remote) && !is_secure)
+		ret = -EPERM;
+
+	return ret;
+}
+
+/**
+ * ipi_mb_open() - Open IPI mailbox.
+ *
+ * @local  - local IPI ID
+ * @remote - remote IPI ID
+ *
+ */
+void ipi_mb_open(uint32_t local, uint32_t remote)
+{
+	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
+		      IPI_BIT_MASK(remote));
+	mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
+		      IPI_BIT_MASK(remote));
+}
+
+/**
+ * ipi_mb_release() - Open IPI mailbox.
+ *
+ * @local  - local IPI ID
+ * @remote - remote IPI ID
+ *
+ */
+void ipi_mb_release(uint32_t local, uint32_t remote)
+{
+	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
+		      IPI_BIT_MASK(remote));
+}
+
+/**
+ * ipi_mb_enquire_status() - Enquire IPI mailbox status
+ *
+ * @local  - local IPI ID
+ * @remote - remote IPI ID
+ *
+ * return - 0 idle, positive value for pending sending or receiving,
+ *          negative value for errors
+ */
+int ipi_mb_enquire_status(uint32_t local, uint32_t remote)
+{
+	int ret = 0;
+	uint32_t status;
+
+	status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
+	if (status & IPI_BIT_MASK(remote))
+		ret |= IPI_MB_STATUS_SEND_PENDING;
+	status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
+	if (status & IPI_BIT_MASK(remote))
+		ret |= IPI_MB_STATUS_RECV_PENDING;
+
+	return ret;
+}
+
+/* ipi_mb_notify() - Trigger IPI mailbox notification
+ *
+ * @local - local IPI ID
+ * @remote - remote IPI ID
+ * @is_blocking - if to trigger the notification in blocking mode or not.
+ *
+ * It sets the remote bit in the IPI agent trigger register.
+ *
+ */
+void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking)
+{
+	uint32_t status;
+
+	mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET,
+		      IPI_BIT_MASK(remote));
+	if (is_blocking) {
+		do {
+			status = mmio_read_32(IPI_REG_BASE(local) +
+					      IPI_OBR_OFFSET);
+		} while (status & IPI_BIT_MASK(remote));
+	}
+}
+
+/* ipi_mb_ack() - Ack IPI mailbox notification from the other end
+ *
+ * @local - local IPI ID
+ * @remote - remote IPI ID
+ *
+ * It will clear the remote bit in the isr register.
+ *
+ */
+void ipi_mb_ack(uint32_t local, uint32_t remote)
+{
+	mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
+		      IPI_BIT_MASK(remote));
+}
+
+/* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt
+ *
+ * @local - local IPI ID
+ * @remote - remote IPI ID
+ *
+ * It will mask the remote bit in the idr register.
+ *
+ */
+void ipi_mb_disable_irq(uint32_t local, uint32_t remote)
+{
+	mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
+		      IPI_BIT_MASK(remote));
+}
+
+/* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt
+ *
+ * @local - local IPI ID
+ * @remote - remote IPI ID
+ *
+ * It will mask the remote bit in the idr register.
+ *
+ */
+void ipi_mb_enable_irq(uint32_t local, uint32_t remote)
+{
+	mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET,
+		      IPI_BIT_MASK(remote));
+}
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
new file mode 100644
index 0000000..034cd5b
--- /dev/null
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <arch_helpers.h>
+
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#include "pm_ipi.h"
+
+
+DEFINE_BAKERY_LOCK(pm_secure_lock);
+
+/**
+ * pm_ipi_init() - Initialize IPI peripheral for communication with
+ *		   remote processor
+ *
+ * @proc	Pointer to the processor who is initiating request
+ * @return	On success, the initialization function must return 0.
+ *		Any other return value will cause the framework to ignore
+ *		the service
+ *
+ * Called from pm_setup initialization function
+ */
+int pm_ipi_init(const struct pm_proc *proc)
+{
+	bakery_lock_init(&pm_secure_lock);
+	ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
+
+	return 0;
+}
+
+/**
+ * pm_ipi_send_common() - Sends IPI request to the remote processor
+ * @proc	Pointer to the processor who is initiating request
+ * @payload	API id and call arguments to be written in IPI buffer
+ *
+ * Send an IPI request to the power controller. Caller needs to hold
+ * the 'pm_secure_lock' lock.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
+					     uint32_t payload[PAYLOAD_ARG_CNT],
+					     uint32_t is_blocking)
+{
+	unsigned int offset = 0;
+	uintptr_t buffer_base = proc->ipi->buffer_base +
+					IPI_BUFFER_TARGET_REMOTE_OFFSET +
+					IPI_BUFFER_REQ_OFFSET;
+
+	/* Write payload into IPI buffer */
+	for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
+		mmio_write_32(buffer_base + offset, payload[i]);
+		offset += PAYLOAD_ARG_SIZE;
+	}
+
+	/* Generate IPI to remote processor */
+	ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id,
+		      is_blocking);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor
+ *			        without blocking notification
+ * @proc	Pointer to the processor who is initiating request
+ * @payload	API id and call arguments to be written in IPI buffer
+ *
+ * Send an IPI request to the power controller.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
+					    uint32_t payload[PAYLOAD_ARG_CNT])
+{
+	enum pm_ret_status ret;
+
+	bakery_lock_get(&pm_secure_lock);
+
+	ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
+
+	bakery_lock_release(&pm_secure_lock);
+
+	return ret;
+}
+
+/**
+ * pm_ipi_send() - Sends IPI request to the remote processor
+ * @proc	Pointer to the processor who is initiating request
+ * @payload	API id and call arguments to be written in IPI buffer
+ *
+ * Send an IPI request to the power controller.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+			       uint32_t payload[PAYLOAD_ARG_CNT])
+{
+	enum pm_ret_status ret;
+
+	bakery_lock_get(&pm_secure_lock);
+
+	ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
+
+	bakery_lock_release(&pm_secure_lock);
+
+	return ret;
+}
+
+
+/**
+ * pm_ipi_buff_read() - Reads IPI response after remote processor has handled
+ *			interrupt
+ * @proc	Pointer to the processor who is waiting and reading response
+ * @value	Used to return value from IPI buffer element (optional)
+ * @count	Number of values to return in @value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
+					   unsigned int *value, size_t count)
+{
+	size_t i;
+	uintptr_t buffer_base = proc->ipi->buffer_base +
+				IPI_BUFFER_TARGET_REMOTE_OFFSET +
+				IPI_BUFFER_RESP_OFFSET;
+
+	/*
+	 * Read response from IPI buffer
+	 * buf-0: success or error+reason
+	 * buf-1: value
+	 * buf-2: unused
+	 * buf-3: unused
+	 */
+	for (i = 1; i <= count; i++) {
+		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
+		value++;
+	}
+
+	return mmio_read_32(buffer_base);
+}
+
+/**
+ * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has
+ *			      handled interrupt
+ * @value	Used to return value from IPI buffer element (optional)
+ * @count	Number of values to return in @value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+void pm_ipi_buff_read_callb(unsigned int *value, size_t count)
+{
+	size_t i;
+	uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE +
+				IPI_BUFFER_TARGET_LOCAL_OFFSET +
+				IPI_BUFFER_REQ_OFFSET;
+
+	if (count > IPI_BUFFER_MAX_WORDS)
+		count = IPI_BUFFER_MAX_WORDS;
+
+	for (i = 0; i <= count; i++) {
+		*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
+		value++;
+	}
+}
+
+/**
+ * pm_ipi_send_sync() - Sends IPI request to the remote processor
+ * @proc	Pointer to the processor who is initiating request
+ * @payload	API id and call arguments to be written in IPI buffer
+ * @value	Used to return value from IPI buffer element (optional)
+ * @count	Number of values to return in @value
+ *
+ * Send an IPI request to the power controller and wait for it to be handled.
+ *
+ * @return	Returns status, either success or error+reason and, optionally,
+ *		@value
+ */
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+				    uint32_t payload[PAYLOAD_ARG_CNT],
+				    unsigned int *value, size_t count)
+{
+	enum pm_ret_status ret;
+
+	bakery_lock_get(&pm_secure_lock);
+
+	ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
+	if (ret != PM_RET_SUCCESS)
+		goto unlock;
+
+	ret = pm_ipi_buff_read(proc, value, count);
+
+unlock:
+	bakery_lock_release(&pm_secure_lock);
+
+	return ret;
+}
+
+void pm_ipi_irq_enable(const struct pm_proc *proc)
+{
+	ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
+}
+
+void pm_ipi_irq_clear(const struct pm_proc *proc)
+{
+	ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
+}
+
+uint32_t pm_ipi_irq_status(const struct pm_proc *proc)
+{
+	int ret;
+
+	ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id,
+				    proc->ipi->remote_ipi_id);
+	if (ret & IPI_MB_STATUS_RECV_PENDING)
+		return 1;
+	else
+		return 0;
+}
diff --git a/plat/xilinx/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c
new file mode 100644
index 0000000..587b797
--- /dev/null
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include "../versal_def.h"
+#include "../versal_private.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_versal_mmap[] = {
+	MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+const mmap_region_t *plat_versal_get_mmap(void)
+{
+	return plat_versal_mmap;
+}
+
+static void versal_print_platform_name(void)
+{
+	NOTICE("ATF running on Xilinx %s\n", PLATFORM_NAME);
+}
+
+void versal_config_setup(void)
+{
+	uint32_t val;
+
+	versal_print_platform_name();
+
+	mmio_write_32(VERSAL_CRL_IOU_SWITCH_CTRL,
+		      VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT |
+		      (0x20 << VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT));
+
+	/* Global timer init - Program time stamp reference clk */
+	val = mmio_read_32(VERSAL_CRL_TIMESTAMP_REF_CTRL);
+	val |= VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
+	mmio_write_32(VERSAL_CRL_TIMESTAMP_REF_CTRL, val);
+
+	/* Clear reset of timestamp reg */
+	mmio_write_32(VERSAL_CRL_RST_TIMESTAMP_OFFSET, 0x0);
+
+	/* Program freq register in System counter and enable system counter. */
+	mmio_write_32(VERSAL_IOU_SCNTRS_BASE_FREQ, VERSAL_CPU_CLOCK);
+	mmio_write_32(VERSAL_IOU_SCNTRS_COUNTER_CONTROL_REG,
+		      VERSAL_IOU_SCNTRS_CONTROL_EN);
+
+	generic_delay_timer_init();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return VERSAL_CPU_CLOCK;
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return PLAT_VERSAL_NS_IMAGE_OFFSET;
+#endif
+}
diff --git a/plat/xilinx/versal/aarch64/versal_helpers.S b/plat/xilinx/versal/aarch64/versal_helpers.S
new file mode 100644
index 0000000..26eb052
--- /dev/null
+++ b/plat/xilinx/versal/aarch64/versal_helpers.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_is_my_cpu_primary
+	.globl	versal_calc_core_pos
+	.globl	platform_mem_init
+	.globl	plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * TODO: Should we read the PSYS register to make sure
+	 * that the request has gone through.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	mrs	x0, mpidr_el1
+
+	/*
+	 * There is no sane reason to come out of this wfi. This
+	 * cpu will be powered on and reset by the cpu_on pm api
+	 */
+	dsb	sy
+	bl	plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+	mov	x9, x30
+	bl	plat_my_core_pos
+	cmp	x0, #VERSAL_PRIMARY_CPU
+	cset	x0, eq
+	ret	x9
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the versal_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	versal_calc_core_pos
+endfunc plat_my_core_pos
+
+func versal_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc versal_calc_core_pos
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on VERSAL
+	 * platform. The Secure RAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
new file mode 100644
index 0000000..d7e07e0
--- /dev/null
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+#include "versal_private.h"
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static console_pl011_t versal_runtime_console;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type));
+
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+
+	return &bl32_image_ep_info;
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+
+	/* Initialize the console to provide early debug support */
+	int rc = console_pl011_register(VERSAL_UART_BASE,
+					VERSAL_UART_CLOCK,
+					VERSAL_UART_BAUDRATE,
+					&versal_runtime_console);
+	if (rc == 0)
+		panic();
+
+	console_set_scope(&versal_runtime_console.console, CONSOLE_FLAG_BOOT |
+			  CONSOLE_FLAG_RUNTIME);
+
+	/* Initialize the platform config for future decision making */
+	versal_config_setup();
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(arg0 == 0U);
+	assert(arg1 == 0U);
+
+	/*
+	 * Do initial security configuration to allow DRAM/device access. On
+	 * Base VERSAL only DRAM security is programmable (via TrustZone), but
+	 * other platforms might have more programmable security devices
+	 * present.
+	 */
+
+	/* Populate common information for BL32 and BL33 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+	/* use build time defaults in JTAG boot mode */
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = 0;
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+					  DISABLE_ALL_EXCEPTIONS);
+
+	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+	NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+}
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_versal_gic_driver_init();
+	plat_versal_gic_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+}
+
+/*
+ * Perform the very early platform specific architectural setup here.
+ */
+void bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+				MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+				MT_RO_DATA | MT_SECURE),
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+				BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+				MT_DEVICE | MT_RW | MT_SECURE),
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_versal_get_mmap());
+	enable_mmu_el3(0);
+}
diff --git a/plat/xilinx/versal/include/plat_macros.S b/plat/xilinx/versal/include/plat_macros.S
new file mode 100644
index 0000000..3a52212
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_macros.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#include "../include/platform_def.h"
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+	.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below utility macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL31 on Versal platform.
+	 * Expects: GICD base in x16, GICC base in x17
+	 * Clobbers: x0 - x10, sp
+	 * ---------------------------------------------
+	 */
+	.macro versal_print_gic_regs
+	/* Check for GICv3 system register access */
+	mrs	x7, id_aa64pfr0_el1
+	ubfx	x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x7, #1
+	b.ne	print_gicv2
+
+	/* Check for SRE enable */
+	mrs	x8, ICC_SRE_EL3
+	tst	x8, #ICC_SRE_SRE_BIT
+	b.eq	print_gicv2
+
+	/* Load the icc reg list to x6 */
+	adr	x6, icc_regs
+	/* Load the icc regs to gp regs used by str_in_crash_buf_print */
+	mrs	x8, ICC_HPPIR0_EL1
+	mrs	x9, ICC_HPPIR1_EL1
+	mrs	x10, ICC_CTLR_EL3
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	b	print_gic_common
+
+print_gicv2:
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+print_gic_common:
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm	x17, PLAT_VERSAL_GICD_BASE
+	mov_imm	x16, PLAT_VERSAL_GICR_BASE
+	versal_print_gic_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h
new file mode 100644
index 0000000..0c4b954
--- /dev/null
+++ b/plat/xilinx/versal/include/platform_def.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+
+#include "../versal_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE	0x440
+
+#define PLATFORM_CORE_COUNT		2
+#define PLAT_MAX_PWR_LVL		1
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		2
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#ifndef VERSAL_ATF_MEM_BASE
+# define BL31_BASE			0xfffea000
+# define BL31_LIMIT			0xffffffff
+#else
+# define BL31_BASE			(VERSAL_ATF_MEM_BASE)
+# define BL31_LIMIT			(VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_SIZE - 1)
+# ifdef VERSAL_ATF_MEM_PROGBITS_SIZE
+#  define BL31_PROGBITS_LIMIT		(VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef VERSAL_BL32_MEM_BASE
+# define BL32_BASE			0x60000000
+# define BL32_LIMIT			0x7fffffff
+#else
+# define BL32_BASE			(VERSAL_BL32_MEM_BASE)
+# define BL32_LIMIT			(VERSAL_BL32_MEM_BASE + VERSAL_BL32_MEM_SIZE - 1)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_VERSAL_NS_IMAGE_OFFSET	0x8000000
+#else
+# define PLAT_VERSAL_NS_IMAGE_OFFSET	PRELOADED_BL33_BASE
+#endif
+
+/*******************************************************************************
+ * TSP  specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE + 1)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
+#define TSP_IRQ_SEC_PHY_TIMER		ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define MAX_MMAP_REGIONS		7
+#define MAX_XLAT_TABLES			5
+
+#define CACHE_WRITEBACK_SHIFT	6
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_VERSAL_GICD_BASE	0xF9000000
+#define PLAT_VERSAL_GICR_BASE	0xF9080000
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_VERSAL_G1S_IRQS	VERSAL_IRQ_SEC_PHY_TIMER
+#define PLAT_VERSAL_G0_IRQS	VERSAL_IRQ_SEC_PHY_TIMER
+
+#define PLAT_VERSAL_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(VERSAL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_VERSAL_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
new file mode 100644
index 0000000..4a44369
--- /dev/null
+++ b/plat/xilinx/versal/plat_psci.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "versal_private.h"
+
+static uintptr_t versal_sec_entry;
+
+static int versal_nopmc_pwr_domain_on(u_register_t mpidr)
+{
+	uint32_t r;
+	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+	if (cpu_id == -1)
+		return PSCI_E_INTERN_FAIL;
+
+	/*
+	 * program RVBAR
+	 */
+	mmio_write_32(FPD_APU_RVBAR_L_0 + (cpu_id << 3), versal_sec_entry);
+	mmio_write_32(FPD_APU_RVBAR_H_0 + (cpu_id << 3), versal_sec_entry >> 32);
+
+	/*
+	 * clear VINITHI
+	 */
+	r = mmio_read_32(FPD_APU_CONFIG_0);
+	r &= ~(1 << FPD_APU_CONFIG_0_VINITHI_SHIFT << cpu_id);
+	mmio_write_32(FPD_APU_CONFIG_0, r);
+
+	/*
+	 * FIXME: Add power up sequence, By default it works
+	 * now without the need of it as it was powered up by
+	 * default.
+	 */
+
+	/*
+	 * clear power down request
+	 */
+	r = mmio_read_32(FPD_APU_PWRCTL);
+	r &= ~(1 << cpu_id);
+	mmio_write_32(FPD_APU_PWRCTL, r);
+
+	/*
+	 * release core reset
+	 */
+	r = mmio_read_32(CRF_RST_APU);
+	r &= ~((CRF_RST_APU_ACPU_PWRON_RESET |
+			CRF_RST_APU_ACPU_RESET) << cpu_id);
+	mmio_write_32(CRF_RST_APU, r);
+
+	return PSCI_E_SUCCESS;
+}
+
+void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* Enable the gic cpu interface */
+	plat_versal_gic_pcpu_init();
+
+	/* Program the gic per-cpu distributor or re-distributor interface */
+	plat_versal_gic_cpuif_enable();
+}
+
+static const struct plat_psci_ops versal_nopmc_psci_ops = {
+	.pwr_domain_on			= versal_nopmc_pwr_domain_on,
+	.pwr_domain_on_finish		= versal_pwr_domain_on_finish,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	versal_sec_entry = sec_entrypoint;
+
+	*psci_ops = &versal_nopmc_psci_ops;
+
+	return 0;
+}
diff --git a/plat/xilinx/versal/plat_topology.c b/plat/xilinx/versal/plat_topology.c
new file mode 100644
index 0000000..66d4fae
--- /dev/null
+++ b/plat/xilinx/versal/plat_topology.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+static const unsigned char plat_power_domain_tree_desc[] = {1, PLATFORM_CORE_COUNT};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c
new file mode 100644
index 0000000..642867d
--- /dev/null
+++ b/plat/xilinx/versal/plat_versal.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+#include "versal_private.h"
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		return -1;
+
+	if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT)
+		return -1;
+
+	return versal_calc_core_pos(mpidr);
+}
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
new file mode 100644
index 0000000..1c56364
--- /dev/null
+++ b/plat/xilinx/versal/platform.mk
@@ -0,0 +1,63 @@
+# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+SEPARATE_CODE_AND_RODATA := 1
+override RESET_TO_BL31 := 1
+PL011_GENERIC_UART := 1
+
+ifdef VERSAL_ATF_MEM_BASE
+    $(eval $(call add_define,VERSAL_ATF_MEM_BASE))
+
+    ifndef VERSAL_ATF_MEM_SIZE
+        $(error "VERSAL_ATF_BASE defined without VERSAL_ATF_SIZE")
+    endif
+    $(eval $(call add_define,VERSAL_ATF_MEM_SIZE))
+
+    ifdef VERSAL_ATF_MEM_PROGBITS_SIZE
+        $(eval $(call add_define,VERSAL_ATF_MEM_PROGBITS_SIZE))
+    endif
+endif
+
+ifdef VERSAL_BL32_MEM_BASE
+    $(eval $(call add_define,VERSAL_BL32_MEM_BASE))
+
+    ifndef VERSAL_BL32_MEM_SIZE
+        $(error "VERSAL_BL32_BASE defined without VERSAL_BL32_SIZE")
+    endif
+    $(eval $(call add_define,VERSAL_BL32_MEM_SIZE))
+endif
+
+VERSAL_PLATFORM ?= versal_virt
+$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
+
+VERSAL_CONSOLE	?=	pl011
+$(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
+
+PLAT_INCLUDES		:=	-Iplat/xilinx/versal/include/
+
+PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v3/gicv3_main.c			\
+				drivers/arm/gic/v3/gicv3_helpers.c		\
+				drivers/arm/pl011/aarch64/pl011_console.S	\
+				plat/common/aarch64/crash_console_helpers.S	\
+				plat/common/plat_gicv3.c			\
+				plat/xilinx/versal/aarch64/versal_helpers.S	\
+				plat/xilinx/versal/aarch64/versal_common.c
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a72.S			\
+				plat/common/plat_psci_common.c			\
+				plat/xilinx/versal/bl31_versal_setup.c		\
+				plat/xilinx/versal/plat_psci.c			\
+				plat/xilinx/versal/plat_versal.c		\
+				plat/xilinx/versal/plat_topology.c		\
+				plat/xilinx/versal/sip_svc_setup.c		\
+				plat/xilinx/versal/versal_gicv3.c
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
new file mode 100644
index 0000000..8f2180b
--- /dev/null
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+/* SMC function IDs for SiP Service queries */
+#define VERSAL_SIP_SVC_CALL_COUNT	0x8200ff00
+#define VERSAL_SIP_SVC_UID		0x8200ff01
+#define VERSAL_SIP_SVC_VERSION		0x8200ff03
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR	0
+#define SIP_SVC_VERSION_MINOR	1
+
+/* These macros are used to identify PM calls from the SMC function ID */
+#define PM_FID_MASK	0xf000u
+#define PM_FID_VALUE	0u
+#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(versal_sip_uuid,
+		0x2ab9e4ec, 0x93b9, 0x11e7, 0xa0, 0x19,
+		0xdf, 0xe0, 0xdb, 0xad, 0x0a, 0xe0);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Invokes PM setup
+ */
+static int32_t sip_svc_setup(void)
+{
+	return 0;
+}
+
+/**
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
+			     u_register_t x1,
+			     u_register_t x2,
+			     u_register_t x3,
+			     u_register_t x4,
+			     void *cookie,
+			     void *handle,
+			     u_register_t flags)
+{
+	/* Let PM SMC handler deal with PM-related requests */
+	switch (smc_fid) {
+	case VERSAL_SIP_SVC_CALL_COUNT:
+		/* PM functions + default functions */
+		SMC_RET1(handle, 2);
+
+	case VERSAL_SIP_SVC_UID:
+		SMC_UUID_RET(handle, versal_sip_uuid);
+
+	case VERSAL_SIP_SVC_VERSION:
+		SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+		sip_svc,
+		OEN_SIP_START,
+		OEN_SIP_END,
+		SMC_TYPE_FAST,
+		sip_svc_setup,
+		sip_svc_smc_handler);
diff --git a/plat/xilinx/versal/versal_def.h b/plat/xilinx/versal/versal_def.h
new file mode 100644
index 0000000..41c65b9
--- /dev/null
+++ b/plat/xilinx/versal/versal_def.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VERSAL_DEF_H
+#define VERSAL_DEF_H
+
+#include <plat/common/common_def.h>
+
+/* List all consoles */
+#define VERSAL_CONSOLE_ID_pl011	1
+#define VERSAL_CONSOLE_ID_pl011_0	1
+#define VERSAL_CONSOLE_ID_pl011_1	2
+#define VERSAL_CONSOLE_ID_dcc		3
+
+#define VERSAL_CONSOLE_IS(con)	(VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE)
+
+/* List all supported platforms */
+#define VERSAL_PLATFORM_ID_versal_virt	1
+
+#define VERSAL_PLATFORM_IS(con)	(VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
+
+/* Firmware Image Package */
+#define VERSAL_PRIMARY_CPU	0
+
+/*******************************************************************************
+ * memory map related constants
+ ******************************************************************************/
+#define DEVICE0_BASE		0xFF000000
+#define DEVICE0_SIZE		0x00E00000
+#define DEVICE1_BASE		0xF9000000
+#define DEVICE1_SIZE		0x00800000
+
+/* CRL */
+#define VERSAL_CRL				0xFF5E0000
+#define VERSAL_CRL_IOU_SWITCH_CTRL		(VERSAL_CRL + 0x114)
+#define VERSAL_CRL_TIMESTAMP_REF_CTRL		(VERSAL_CRL + 0x14C)
+#define VERSAL_CRL_RST_TIMESTAMP_OFFSET	(VERSAL_CRL + 0x348)
+
+#define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT	(1 << 25)
+#define VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT		(1 << 25)
+#define VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT		8
+
+/* IOU SCNTRS */
+#define VERSAL_IOU_SCNTRS			 0xFF140000
+#define VERSAL_IOU_SCNTRS_COUNTER_CONTROL_REG	(VERSAL_IOU_SCNTRS + 0x0)
+#define VERSAL_IOU_SCNTRS_BASE_FREQ		(VERSAL_IOU_SCNTRS + 0x20)
+
+#define VERSAL_IOU_SCNTRS_CONTROL_EN	1
+
+/*******************************************************************************
+ * IRQ constants
+ ******************************************************************************/
+#define VERSAL_IRQ_SEC_PHY_TIMER		29
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define VERSAL_UART0_BASE		0xFF000000
+#define VERSAL_UART1_BASE		0xFF010000
+
+#if VERSAL_CONSOLE_IS(pl011)
+# define VERSAL_UART_BASE	VERSAL_UART0_BASE
+#elif VERSAL_CONSOLE_IS(pl011_1)
+# define VERSAL_UART_BASE	VERSAL_UART1_BASE
+#else
+# error "invalid VERSAL_CONSOLE"
+#endif
+
+#define PLAT_VERSAL_CRASH_UART_BASE		VERSAL_UART_BASE
+#define PLAT_VERSAL_CRASH_UART_CLK_IN_HZ	VERSAL_UART_CLOCK
+#define VERSAL_CONSOLE_BAUDRATE			VERSAL_UART_BAUDRATE
+
+/*******************************************************************************
+ * Platform related constants
+ ******************************************************************************/
+#if VERSAL_PLATFORM_IS(versal_virt)
+# define PLATFORM_NAME		"Versal Virt"
+# define VERSAL_UART_CLOCK	25000000
+# define VERSAL_UART_BAUDRATE	115200
+# define VERSAL_CPU_CLOCK	62500000
+#endif
+
+/* Access control register defines */
+#define ACTLR_EL3_L2ACTLR_BIT	(1 << 6)
+#define ACTLR_EL3_CPUACTLR_BIT	(1 << 0)
+
+/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
+#define CRF_BASE		0xFD1A0000
+#define CRF_SIZE		0x00600000
+
+/* CRF registers and bitfields */
+#define CRF_RST_APU	(CRF_BASE + 0X00000300)
+
+#define CRF_RST_APU_ACPU_RESET		(1 << 0)
+#define CRF_RST_APU_ACPU_PWRON_RESET	(1 << 10)
+
+/* APU registers and bitfields */
+#define FPD_APU_BASE		0xFD5C0000
+#define FPD_APU_CONFIG_0	(FPD_APU_BASE + 0x20)
+#define FPD_APU_RVBAR_L_0	(FPD_APU_BASE + 0x40)
+#define FPD_APU_RVBAR_H_0	(FPD_APU_BASE + 0x44)
+#define FPD_APU_PWRCTL		(FPD_APU_BASE + 0x90)
+
+#define FPD_APU_CONFIG_0_VINITHI_SHIFT	8
+
+#endif /* VERSAL_DEF_H */
diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c
new file mode 100644
index 0000000..dcf23b4
--- /dev/null
+++ b/plat/xilinx/versal/versal_gicv3.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include "versal_private.h"
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_versal_gic_driver_init
+#pragma weak plat_versal_gic_init
+#pragma weak plat_versal_gic_cpuif_enable
+#pragma weak plat_versal_gic_cpuif_disable
+#pragma weak plat_versal_gic_pcpu_init
+#pragma weak plat_versal_gic_redistif_on
+#pragma weak plat_versal_gic_redistif_off
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t versal_interrupt_props[] = {
+	PLAT_VERSAL_G1S_IRQ_PROPS(INTR_GROUP1S),
+	PLAT_VERSAL_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory.
+ */
+static gicv3_redist_ctx_t rdist_ctx __section("versal_el3_tzc_dram");
+static gicv3_dist_ctx_t dist_ctx __section("versal_el3_tzc_dram");
+
+/*
+ * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
+ * to core position.
+ *
+ * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
+ * values read from GICR_TYPER don't have an MT field. To reuse the same
+ * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
+ * that read from GICR_TYPER.
+ *
+ * Assumptions:
+ *
+ *   - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
+ *   - No CPUs implemented in the system use affinity level 3.
+ */
+static unsigned int versal_gicv3_mpidr_hash(u_register_t mpidr)
+{
+	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+	return versal_calc_core_pos(mpidr);
+}
+
+static const gicv3_driver_data_t versal_gic_data __unused = {
+	.gicd_base = PLAT_VERSAL_GICD_BASE,
+	.gicr_base = PLAT_VERSAL_GICR_BASE,
+	.interrupt_props = versal_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(versal_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = versal_gicv3_mpidr_hash
+};
+
+void __init plat_versal_gic_driver_init(void)
+{
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#if IMAGE_BL31
+	gicv3_driver_init(&versal_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * Versal common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void __init plat_versal_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to initialize the per-cpu redistributor interface in
+ * GICv3
+ *****************************************************************************/
+void plat_versal_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_versal_gic_redistif_on(void)
+{
+	gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_versal_gic_redistif_off(void)
+{
+	gicv3_rdistif_off(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to save & restore the GICv3 on resume from system
+ * suspend
+ *****************************************************************************/
+void plat_versal_gic_save(void)
+{
+	/*
+	 * If an ITS is available, save its context before
+	 * the Redistributor using:
+	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
+	 * Additionnaly, an implementation-defined sequence may
+	 * be required to save the whole ITS state.
+	 */
+
+	/*
+	 * Save the GIC Redistributors and ITS contexts before the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to save the context of the CPU that is issuing
+	 * the SYSTEM SUSPEND call, i.e. the current CPU.
+	 */
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+	/* Save the GIC Distributor context */
+	gicv3_distif_save(&dist_ctx);
+
+	/*
+	 * From here, all the components of the GIC can be safely powered down
+	 * as long as there is an alternate way to handle wakeup interrupt
+	 * sources.
+	 */
+}
+
+void plat_versal_gic_resume(void)
+{
+	/* Restore the GIC Distributor context */
+	gicv3_distif_init_restore(&dist_ctx);
+
+	/*
+	 * Restore the GIC Redistributor and ITS contexts after the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to restore the context of the CPU that issued
+	 * the SYSTEM SUSPEND call.
+	 */
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+	/*
+	 * If an ITS is available, restore its context after
+	 * the Redistributor using:
+	 * gicv3_its_restore(gits_base, &its_ctx[i])
+	 * An implementation-defined sequence may be required to
+	 * restore the whole ITS state. The ITS must also be
+	 * re-enabled after this sequence has been executed.
+	 */
+}
diff --git a/plat/xilinx/versal/versal_private.h b/plat/xilinx/versal/versal_private.h
new file mode 100644
index 0000000..5d98d08
--- /dev/null
+++ b/plat/xilinx/versal/versal_private.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VERSAL_PRIVATE_H
+#define VERSAL_PRIVATE_H
+
+#include <lib/xlat_tables/xlat_tables.h>
+
+void versal_config_setup(void);
+
+const mmap_region_t *plat_versal_get_mmap(void);
+
+void plat_versal_gic_driver_init(void);
+void plat_versal_gic_init(void);
+void plat_versal_gic_cpuif_enable(void);
+void plat_versal_gic_cpuif_disable(void);
+void plat_versal_gic_pcpu_init(void);
+
+unsigned int versal_calc_core_pos(u_register_t mpidr);
+
+#endif /* VERSAL_PRIVATE_H */
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
new file mode 100644
index 0000000..8ff6c43
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_sys.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_arm_mmap[] = {
+	{ DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+	{ DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+	{ CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+	{0}
+};
+
+static unsigned int zynqmp_get_silicon_ver(void)
+{
+	static unsigned int ver;
+
+	if (!ver) {
+		ver = mmio_read_32(ZYNQMP_CSU_BASEADDR +
+				   ZYNQMP_CSU_VERSION_OFFSET);
+		ver &= ZYNQMP_SILICON_VER_MASK;
+		ver >>= ZYNQMP_SILICON_VER_SHIFT;
+	}
+
+	return ver;
+}
+
+unsigned int zynqmp_get_uart_clk(void)
+{
+	unsigned int ver = zynqmp_get_silicon_ver();
+
+	if (ver == ZYNQMP_CSU_VERSION_QEMU)
+		return 133000000;
+	else
+		return 100000000;
+}
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+static const struct {
+	unsigned int id;
+	unsigned int ver;
+	char *name;
+	bool evexists;
+} zynqmp_devices[] = {
+	{
+		.id = 0x10,
+		.name = "3EG",
+	},
+	{
+		.id = 0x10,
+		.ver = 0x2c,
+		.name = "3CG",
+	},
+	{
+		.id = 0x11,
+		.name = "2EG",
+	},
+	{
+		.id = 0x11,
+		.ver = 0x2c,
+		.name = "2CG",
+	},
+	{
+		.id = 0x20,
+		.name = "5EV",
+		.evexists = true,
+	},
+	{
+		.id = 0x20,
+		.ver = 0x100,
+		.name = "5EG",
+		.evexists = true,
+	},
+	{
+		.id = 0x20,
+		.ver = 0x12c,
+		.name = "5CG",
+	},
+	{
+		.id = 0x21,
+		.name = "4EV",
+		.evexists = true,
+	},
+	{
+		.id = 0x21,
+		.ver = 0x100,
+		.name = "4EG",
+		.evexists = true,
+	},
+	{
+		.id = 0x21,
+		.ver = 0x12c,
+		.name = "4CG",
+	},
+	{
+		.id = 0x30,
+		.name = "7EV",
+		.evexists = true,
+	},
+	{
+		.id = 0x30,
+		.ver = 0x100,
+		.name = "7EG",
+		.evexists = true,
+	},
+	{
+		.id = 0x30,
+		.ver = 0x12c,
+		.name = "7CG",
+	},
+	{
+		.id = 0x38,
+		.name = "9EG",
+	},
+	{
+		.id = 0x38,
+		.ver = 0x2c,
+		.name = "9CG",
+	},
+	{
+		.id = 0x39,
+		.name = "6EG",
+	},
+	{
+		.id = 0x39,
+		.ver = 0x2c,
+		.name = "6CG",
+	},
+	{
+		.id = 0x40,
+		.name = "11EG",
+	},
+	{ /* For testing purpose only */
+		.id = 0x50,
+		.ver = 0x2c,
+		.name = "15CG",
+	},
+	{
+		.id = 0x50,
+		.name = "15EG",
+	},
+	{
+		.id = 0x58,
+		.name = "19EG",
+	},
+	{
+		.id = 0x59,
+		.name = "17EG",
+	},
+	{
+		.id = 0x60,
+		.name = "28DR",
+	},
+	{
+		.id = 0x61,
+		.name = "21DR",
+	},
+	{
+		.id = 0x62,
+		.name = "29DR",
+	},
+	{
+		.id = 0x63,
+		.name = "23DR",
+	},
+	{
+		.id = 0x64,
+		.name = "27DR",
+	},
+	{
+		.id = 0x65,
+		.name = "25DR",
+	},
+};
+
+#define ZYNQMP_PL_STATUS_BIT	9
+#define ZYNQMP_PL_STATUS_MASK	BIT(ZYNQMP_PL_STATUS_BIT)
+#define ZYNQMP_CSU_VERSION_MASK	~(ZYNQMP_PL_STATUS_MASK)
+
+static char *zynqmp_get_silicon_idcode_name(void)
+{
+	uint32_t id, ver, chipid[2];
+	size_t i, j, len;
+	const char *name = "EG/EV";
+
+#ifdef IMAGE_BL32
+	/*
+	 * For BL32, get the chip id info directly by reading corresponding
+	 * registers instead of making pm call. This has limitation
+	 * that these registers should be configured to have access
+	 * from APU which is default case.
+	 */
+	chipid[0] = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+	chipid[1] = mmio_read_32(EFUSE_BASEADDR + EFUSE_IPDISABLE_OFFSET);
+#else
+	if (pm_get_chipid(chipid) != PM_RET_SUCCESS)
+		return "UNKN";
+#endif
+
+	id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
+			  ZYNQMP_CSU_IDCODE_SVD_MASK);
+	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+	ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT;
+
+	for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
+		if (zynqmp_devices[i].id == id &&
+		    zynqmp_devices[i].ver == (ver & ZYNQMP_CSU_VERSION_MASK))
+			break;
+	}
+
+	if (i >= ARRAY_SIZE(zynqmp_devices))
+		return "UNKN";
+
+	if (!zynqmp_devices[i].evexists)
+		return zynqmp_devices[i].name;
+
+	if (ver & ZYNQMP_PL_STATUS_MASK)
+		return zynqmp_devices[i].name;
+
+	len = strlen(zynqmp_devices[i].name) - 2;
+	for (j = 0; j < strlen(name); j++) {
+		zynqmp_devices[i].name[len] = name[j];
+		len++;
+	}
+	zynqmp_devices[i].name[len] = '\0';
+
+	return zynqmp_devices[i].name;
+}
+
+static unsigned int zynqmp_get_rtl_ver(void)
+{
+	uint32_t ver;
+
+	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+	ver &= ZYNQMP_RTL_VER_MASK;
+	ver >>= ZYNQMP_RTL_VER_SHIFT;
+
+	return ver;
+}
+
+static char *zynqmp_print_silicon_idcode(void)
+{
+	uint32_t id, maskid, tmp;
+
+	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+	tmp = id;
+	tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
+	       ZYNQMP_CSU_IDCODE_FAMILY_MASK;
+	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
+		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
+	if (tmp != maskid) {
+		ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
+		return "UNKN";
+	}
+	VERBOSE("Xilinx IDCODE 0x%x\n", id);
+	return zynqmp_get_silicon_idcode_name();
+}
+
+static unsigned int zynqmp_get_ps_ver(void)
+{
+	uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+
+	ver &= ZYNQMP_PS_VER_MASK;
+	ver >>= ZYNQMP_PS_VER_SHIFT;
+
+	return ver + 1;
+}
+
+static void zynqmp_print_platform_name(void)
+{
+	unsigned int ver = zynqmp_get_silicon_ver();
+	unsigned int rtl = zynqmp_get_rtl_ver();
+	char *label = "Unknown";
+
+	switch (ver) {
+	case ZYNQMP_CSU_VERSION_QEMU:
+		label = "QEMU";
+		break;
+	case ZYNQMP_CSU_VERSION_SILICON:
+		label = "silicon";
+		break;
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x\n",
+	       zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(),
+	       (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE);
+}
+#else
+static inline void zynqmp_print_platform_name(void) { }
+#endif
+
+unsigned int zynqmp_get_bootmode(void)
+{
+	uint32_t r;
+	unsigned int ret;
+
+	ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r);
+
+	if (ret != PM_RET_SUCCESS)
+		r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
+
+	return r & CRL_APB_BOOT_MODE_MASK;
+}
+
+void zynqmp_config_setup(void)
+{
+	zynqmp_print_platform_name();
+	generic_delay_timer_init();
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	unsigned int ver = zynqmp_get_silicon_ver();
+
+	if (ver == ZYNQMP_CSU_VERSION_QEMU)
+		return 50000000;
+	else
+		return mmio_read_32(IOU_SCNTRS_BASEFREQ);
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
new file mode 100644
index 0000000..beba664
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_is_my_cpu_primary
+	.globl	zynqmp_calc_core_pos
+	.globl	plat_my_core_pos
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+	.globl	platform_mem_init
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * TODO: Should we read the PSYS register to make sure
+	 * that the request has gone through.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	mrs	x0, mpidr_el1
+
+	/* Deactivate the gic cpu interface */
+	ldr	x1, =BASE_GICC_BASE
+	mov	w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1)
+	orr	w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
+	str	w0, [x1, #GICC_CTLR]
+
+	/*
+	 * There is no sane reason to come out of this wfi. This
+	 * cpu will be powered on and reset by the cpu_on pm api
+	 */
+	dsb	sy
+1:
+	no_ret	plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+	mov	x9, x30
+	bl	plat_my_core_pos
+	cmp	x0, #ZYNQMP_PRIMARY_CPU
+	cset	x0, eq
+	ret	x9
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the zynqmp_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	zynqmp_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int zynqmp_calc_core_pos(u_register_t mpidr)
+	 *  Helper function to calculate the core position.
+	 *  With this function: CorePos = (ClusterId * 4) +
+	 *  				  CoreId
+	 * -----------------------------------------------------
+	 */
+func zynqmp_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc zynqmp_calc_core_pos
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x4
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, ZYNQMP_CRASH_UART_BASE
+	mov_imm	x1, ZYNQMP_CRASH_UART_CLK_IN_HZ
+	mov_imm	x2, ZYNQMP_UART_BAUDRATE
+	b	console_cdns_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, ZYNQMP_CRASH_UART_BASE
+	b	console_cdns_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : r0
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, ZYNQMP_CRASH_UART_BASE
+	b	console_cdns_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on ARM
+	 * platforms. The Secure RAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
new file mode 100644
index 0000000..285a4eb
--- /dev/null
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type));
+
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+
+	return &bl32_image_ep_info;
+}
+
+/*
+ * Set the build time defaults. We want to do this when doing a JTAG boot
+ * or if we can't find any other config data.
+ */
+static inline void bl31_set_default_config(void)
+{
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+					  DISABLE_ALL_EXCEPTIONS);
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	/* Register the console to provide early debug support */
+	static console_cdns_t bl31_boot_console;
+	(void)console_cdns_register(ZYNQMP_UART_BASE,
+				       zynqmp_get_uart_clk(),
+				       ZYNQMP_UART_BAUDRATE,
+				       &bl31_boot_console);
+	console_set_scope(&bl31_boot_console.console,
+			  CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT);
+
+	/* Initialize the platform config for future decision making */
+	zynqmp_config_setup();
+
+	/* There are no parameters from BL2 if BL31 is a reset vector */
+	assert(arg0 == 0U);
+	assert(arg1 == 0U);
+
+	/*
+	 * Do initial security configuration to allow DRAM/device access. On
+	 * Base ZYNQMP only DRAM security is programmable (via TrustZone), but
+	 * other platforms might have more programmable security devices
+	 * present.
+	 */
+
+	/* Populate common information for BL32 and BL33 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+	if (zynqmp_get_bootmode() == ZYNQMP_BOOTMODE_JTAG) {
+		bl31_set_default_config();
+	} else {
+		/* use parameters from FSBL */
+		enum fsbl_handoff ret = fsbl_atf_handover(&bl32_image_ep_info,
+							  &bl33_image_ep_info);
+		if (ret == FSBL_HANDOFF_NO_STRUCT)
+			bl31_set_default_config();
+		else if (ret != FSBL_HANDOFF_SUCCESS)
+			panic();
+	}
+
+	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+	NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+}
+
+/* Enable the test setup */
+#ifndef ZYNQMP_TESTING
+static void zynqmp_testing_setup(void) { }
+#else
+static void zynqmp_testing_setup(void)
+{
+	uint32_t actlr_el3, actlr_el2;
+
+	/* Enable CPU ACTLR AND L2ACTLR RW access from non-secure world */
+	actlr_el3 = read_actlr_el3();
+	actlr_el2 = read_actlr_el2();
+
+	actlr_el3 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT;
+	actlr_el2 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT;
+	write_actlr_el3(actlr_el3);
+	write_actlr_el2(actlr_el2);
+}
+#endif
+
+#if ZYNQMP_WDT_RESTART
+static interrupt_type_handler_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+	/* Validate 'handler' and 'id' parameters */
+	if (!handler || id >= MAX_INTR_EL3)
+		return -EINVAL;
+
+	/* Check if a handler has already been registered */
+	if (type_el3_interrupt_table[id])
+		return -EALREADY;
+
+	type_el3_interrupt_table[id] = handler;
+
+	return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+					  void *handle, void *cookie)
+{
+	uint32_t intr_id;
+	interrupt_type_handler_t handler;
+
+	intr_id = plat_ic_get_pending_interrupt_id();
+	handler = type_el3_interrupt_table[intr_id];
+	if (handler != NULL)
+		handler(intr_id, flags, handle, cookie);
+
+	return 0;
+}
+#endif
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_arm_gic_driver_init();
+	plat_arm_gic_init();
+	zynqmp_testing_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+#if ZYNQMP_WDT_RESTART
+	uint64_t flags = 0;
+	uint64_t rc;
+
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+					     rdo_el3_interrupt_handler, flags);
+	if (rc)
+		panic();
+#endif
+}
+
+/*
+ * Perform the very early platform specific architectural setup here.
+ */
+void bl31_plat_arch_setup(void)
+{
+	plat_arm_interconnect_init();
+	plat_arm_interconnect_enter_coherency();
+
+
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+				MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+				MT_RO_DATA | MT_SECURE),
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+				BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+				MT_DEVICE | MT_RW | MT_SECURE),
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+	enable_mmu_el3(0);
+}
diff --git a/plat/xilinx/zynqmp/include/plat_ipi.h b/plat/xilinx/zynqmp/include/plat_ipi.h
new file mode 100644
index 0000000..bccd2f1
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_ipi.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* ZynqMP IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <stdint.h>
+#include <ipi.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_APU	0U
+#define IPI_ID_RPU0	1U
+#define IPI_ID_RPU1	2U
+#define IPI_ID_PMU0	3U
+#define IPI_ID_PMU1	4U
+#define IPI_ID_PMU2	5U
+#define IPI_ID_PMU3	6U
+#define IPI_ID_PL0	7U
+#define IPI_ID_PL1	8U
+#define IPI_ID_PL2	9U
+#define IPI_ID_PL3	10U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR	0xFF990000U
+
+#define IPI_BUFFER_APU_BASE	(IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMU_BASE	(IPI_BUFFER_BASEADDR + 0xE00U)
+
+#define IPI_BUFFER_LOCAL_BASE	IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE	IPI_BUFFER_PMU_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET	0x80U
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET	0x1C0U
+
+#define IPI_BUFFER_MAX_WORDS	8
+
+#define IPI_BUFFER_REQ_OFFSET	0x0U
+#define IPI_BUFFER_RESP_OFFSET	0x20U
+
+/*********************************************************************
+ * Platform specific IPI API declarations
+ ********************************************************************/
+
+/* Configure IPI table for zynqmp */
+void zynqmp_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/zynqmp/include/plat_macros.S b/plat/xilinx/zynqmp/include/plat_macros.S
new file mode 100644
index 0000000..bf1ff82
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_macros.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+#include <cci_macros.S>
+#include "zynqmp_def.h"
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm	x17, BASE_GICC_BASE
+	mov_imm	x16, BASE_GICD_BASE
+	arm_print_gic_regs
+	print_cci_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/xilinx/zynqmp/include/plat_pm_common.h b/plat/xilinx/zynqmp/include/plat_pm_common.h
new file mode 100644
index 0000000..1b371cc
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_pm_common.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains platform specific definitions of commonly used macros data types
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PLAT_PM_COMMON_H
+#define PLAT_PM_COMMON_H
+
+#include <stdint.h>
+#include <common/debug.h>
+#include "pm_defs.h"
+
+#define PAYLOAD_ARG_CNT		6U
+#define PAYLOAD_ARG_SIZE	4U	/* size in bytes */
+
+#define ZYNQMP_TZ_VERSION_MAJOR		1
+#define ZYNQMP_TZ_VERSION_MINOR		0
+#define ZYNQMP_TZ_VERSION		((ZYNQMP_TZ_VERSION_MAJOR << 16) | \
+					ZYNQMP_TZ_VERSION_MINOR)
+#endif /* _PLAT_PM_COMMON_H_ */
diff --git a/plat/xilinx/zynqmp/include/plat_private.h b/plat/xilinx/zynqmp/include/plat_private.h
new file mode 100644
index 0000000..8bdf429
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_private.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <stdint.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <drivers/cadence/cdns_uart.h>
+
+void zynqmp_config_setup(void);
+
+unsigned int zynqmp_calc_core_pos(u_register_t mpidr);
+
+/* ZynqMP specific functions */
+unsigned int zynqmp_get_uart_clk(void);
+unsigned int zynqmp_get_bootmode(void);
+
+/* For FSBL handover */
+enum fsbl_handoff {
+	FSBL_HANDOFF_SUCCESS = 0,
+	FSBL_HANDOFF_NO_STRUCT,
+	FSBL_HANDOFF_INVAL_STRUCT,
+	FSBL_HANDOFF_TOO_MANY_PARTS,
+};
+
+#if ZYNQMP_WDT_RESTART
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int request_intr_type_el3(uint32_t, interrupt_type_handler_t);
+#endif
+
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info,
+		       entry_point_info_t *bl33_image_ep_info);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
new file mode 100644
index 0000000..7b062fc
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+#include "zynqmp_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x440
+
+#define PLATFORM_CORE_COUNT		4
+#define PLAT_NUM_POWER_DOMAINS		5
+#define PLAT_MAX_PWR_LVL		U(1)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#ifndef ZYNQMP_ATF_MEM_BASE
+#if !DEBUG && defined(SPD_none)
+# define BL31_BASE			0xfffea000
+# define BL31_LIMIT			0xffffffff
+#else
+# define BL31_BASE			0x1000
+# define BL31_LIMIT			0x7ffff
+#endif
+#else
+# define BL31_BASE			(ZYNQMP_ATF_MEM_BASE)
+# define BL31_LIMIT			(ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_SIZE - 1)
+# ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE
+#  define BL31_PROGBITS_LIMIT		(ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef ZYNQMP_BL32_MEM_BASE
+# define BL32_BASE			0x60000000
+# define BL32_LIMIT			0x7fffffff
+#else
+# define BL32_BASE			(ZYNQMP_BL32_MEM_BASE)
+# define BL32_LIMIT			(ZYNQMP_BL32_MEM_BASE + ZYNQMP_BL32_MEM_SIZE - 1)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE	0x8000000
+#else
+# define PLAT_ARM_NS_IMAGE_BASE	PRELOADED_BL33_BASE
+#endif
+
+/*******************************************************************************
+ * TSP  specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE + 1)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
+#define TSP_IRQ_SEC_PHY_TIMER		ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_MMAP_REGIONS		7
+#define MAX_XLAT_TABLES			5
+
+#define CACHE_WRITEBACK_SHIFT   6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_ARM_GICD_BASE	BASE_GICD_BASE
+#define PLAT_ARM_GICC_BASE	BASE_GICC_BASE
+/*
+ * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#if !ZYNQMP_WDT_RESTART
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+#else
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL), \
+	INTR_PROP_DESC(IRQ_TTC3_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE)
+#endif
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h
new file mode 100644
index 0000000..8648b9a
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/zynqmp_def.h
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ZYNQMP_DEF_H
+#define ZYNQMP_DEF_H
+
+#include <plat/common/common_def.h>
+
+#define ZYNQMP_CONSOLE_ID_cadence	1
+#define ZYNQMP_CONSOLE_ID_cadence0	1
+#define ZYNQMP_CONSOLE_ID_cadence1	2
+#define ZYNQMP_CONSOLE_ID_dcc		3
+
+#define ZYNQMP_CONSOLE_IS(con)	(ZYNQMP_CONSOLE_ID_ ## con == ZYNQMP_CONSOLE)
+
+/* Firmware Image Package */
+#define ZYNQMP_PRIMARY_CPU		0
+
+/* Memory location options for Shared data and TSP in ZYNQMP */
+#define ZYNQMP_IN_TRUSTED_SRAM		0
+#define ZYNQMP_IN_TRUSTED_DRAM		1
+
+/*******************************************************************************
+ * ZYNQMP memory map related constants
+ ******************************************************************************/
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE		U(0xFF000000)
+#define DEVICE0_SIZE		U(0x00E00000)
+#define DEVICE1_BASE		U(0xF9000000)
+#define DEVICE1_SIZE		U(0x00800000)
+
+/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
+#define CRF_APB_BASE		U(0xFD1A0000)
+#define CRF_APB_SIZE		U(0x00600000)
+#define CRF_APB_CLK_BASE	U(0xFD1A0020)
+
+/* CRF registers and bitfields */
+#define CRF_APB_RST_FPD_APU	(CRF_APB_BASE + 0X00000104)
+
+#define CRF_APB_RST_FPD_APU_ACPU_RESET		(U(1) << 0)
+#define CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET	(U(1) << 10)
+
+/* CRL registers and bitfields */
+#define CRL_APB_BASE			U(0xFF5E0000)
+#define CRL_APB_BOOT_MODE_USER		(CRL_APB_BASE + 0x200)
+#define CRL_APB_RESET_CTRL		(CRL_APB_BASE + 0x218)
+#define CRL_APB_RST_LPD_TOP		(CRL_APB_BASE + 0x23C)
+#define CRL_APB_BOOT_PIN_CTRL		(CRL_APB_BASE + U(0x250))
+#define CRL_APB_CLK_BASE		U(0xFF5E0020)
+
+#define CRL_APB_RPU_AMBA_RESET		(U(1) << 2)
+#define CRL_APB_RPLL_CTRL_BYPASS	(U(1) << 3)
+
+#define CRL_APB_RESET_CTRL_SOFT_RESET	(U(1) << 4)
+
+#define CRL_APB_BOOT_MODE_MASK		(U(0xf) << 0)
+#define CRL_APB_BOOT_PIN_MASK		(U(0xf0f) << 0)
+#define CRL_APB_BOOT_DRIVE_PIN_1_SHIFT	U(9)
+#define CRL_APB_BOOT_ENABLE_PIN_1_SHIFT	U(1)
+#define CRL_APB_BOOT_ENABLE_PIN_1	(U(0x1) << \
+					CRL_APB_BOOT_ENABLE_PIN_1_SHIFT)
+#define CRL_APB_BOOT_DRIVE_PIN_1	(U(0x1) << \
+					CRL_APB_BOOT_DRIVE_PIN_1_SHIFT)
+#define ZYNQMP_BOOTMODE_JTAG		U(0)
+#define ZYNQMP_ULPI_RESET_VAL_HIGH	(CRL_APB_BOOT_ENABLE_PIN_1 | \
+					 CRL_APB_BOOT_DRIVE_PIN_1)
+#define ZYNQMP_ULPI_RESET_VAL_LOW	CRL_APB_BOOT_ENABLE_PIN_1
+
+/* system counter registers and bitfields */
+#define IOU_SCNTRS_BASE			0xFF260000
+#define IOU_SCNTRS_BASEFREQ		(IOU_SCNTRS_BASE + 0x20)
+
+/* APU registers and bitfields */
+#define APU_BASE		0xFD5C0000
+#define APU_CONFIG_0		(APU_BASE + 0x20)
+#define APU_RVBAR_L_0		(APU_BASE + 0x40)
+#define APU_RVBAR_H_0		(APU_BASE + 0x44)
+#define APU_PWRCTL		(APU_BASE + 0x90)
+
+#define APU_CONFIG_0_VINITHI_SHIFT	8
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK		1
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK		2
+#define APU_2_PWRCTL_CPUPWRDWNREQ_MASK		4
+#define APU_3_PWRCTL_CPUPWRDWNREQ_MASK		8
+
+/* PMU registers and bitfields */
+#define PMU_GLOBAL_BASE			0xFFD80000
+#define PMU_GLOBAL_CNTRL		(PMU_GLOBAL_BASE + 0)
+#define PMU_GLOBAL_GEN_STORAGE6		(PMU_GLOBAL_BASE + 0x48)
+#define PMU_GLOBAL_REQ_PWRUP_STATUS	(PMU_GLOBAL_BASE + 0x110)
+#define PMU_GLOBAL_REQ_PWRUP_EN		(PMU_GLOBAL_BASE + 0x118)
+#define PMU_GLOBAL_REQ_PWRUP_DIS	(PMU_GLOBAL_BASE + 0x11c)
+#define PMU_GLOBAL_REQ_PWRUP_TRIG	(PMU_GLOBAL_BASE + 0x120)
+
+#define PMU_GLOBAL_CNTRL_FW_IS_PRESENT	(1 << 4)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_ARM_CCI_BASE		0xFD6E0000
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX	3
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX	4
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+#define BASE_GICD_BASE		0xF9010000
+#define BASE_GICC_BASE		0xF9020000
+#define BASE_GICH_BASE		0xF9040000
+#define BASE_GICV_BASE		0xF9060000
+
+#if ZYNQMP_WDT_RESTART
+#define IRQ_SEC_IPI_APU		67
+#define IRQ_TTC3_1		77
+#define TTC3_BASE_ADDR		0xFF140000
+#define TTC3_INTR_REGISTER_1	(TTC3_BASE_ADDR + 0x54)
+#define TTC3_INTR_ENABLE_1	(TTC3_BASE_ADDR + 0x60)
+#endif
+
+#define ARM_IRQ_SEC_PHY_TIMER		29
+
+#define ARM_IRQ_SEC_SGI_0		8
+#define ARM_IRQ_SEC_SGI_1		9
+#define ARM_IRQ_SEC_SGI_2		10
+#define ARM_IRQ_SEC_SGI_3		11
+#define ARM_IRQ_SEC_SGI_4		12
+#define ARM_IRQ_SEC_SGI_5		13
+#define ARM_IRQ_SEC_SGI_6		14
+#define ARM_IRQ_SEC_SGI_7		15
+
+#define MAX_INTR_EL3			128
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define ZYNQMP_UART0_BASE		0xFF000000
+#define ZYNQMP_UART1_BASE		0xFF010000
+
+#if ZYNQMP_CONSOLE_IS(cadence) || ZYNQMP_CONSOLE_IS(dcc)
+# define ZYNQMP_UART_BASE	ZYNQMP_UART0_BASE
+#elif ZYNQMP_CONSOLE_IS(cadence1)
+# define ZYNQMP_UART_BASE	ZYNQMP_UART1_BASE
+#else
+# error "invalid ZYNQMP_CONSOLE"
+#endif
+
+#define ZYNQMP_CRASH_UART_BASE		ZYNQMP_UART_BASE
+/* impossible to call C routine how it is done now - hardcode any value */
+#define ZYNQMP_CRASH_UART_CLK_IN_HZ	100000000 /* FIXME */
+/* Must be non zero */
+#define ZYNQMP_UART_BAUDRATE		115200
+
+/* Silicon version detection */
+#define ZYNQMP_SILICON_VER_MASK		0xF000
+#define ZYNQMP_SILICON_VER_SHIFT	12
+#define ZYNQMP_CSU_VERSION_SILICON	0
+#define ZYNQMP_CSU_VERSION_QEMU		3
+
+#define ZYNQMP_RTL_VER_MASK		0xFF0
+#define ZYNQMP_RTL_VER_SHIFT		4
+
+#define ZYNQMP_PS_VER_MASK		0xF
+#define ZYNQMP_PS_VER_SHIFT		0
+
+#define ZYNQMP_CSU_BASEADDR		0xFFCA0000
+#define ZYNQMP_CSU_IDCODE_OFFSET	0x40
+
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT	0
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK	(0xFFF << \
+					ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT)
+#define ZYNQMP_CSU_IDCODE_XILINX_ID		0x093
+
+#define ZYNQMP_CSU_IDCODE_SVD_SHIFT		12
+#define ZYNQMP_CSU_IDCODE_SVD_MASK		(0x7 << \
+						 ZYNQMP_CSU_IDCODE_SVD_SHIFT)
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT	15
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK	(0xF << \
+					ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT	19
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK	(0x3 << \
+					ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT		21
+#define ZYNQMP_CSU_IDCODE_FAMILY_MASK		(0x7F << \
+					ZYNQMP_CSU_IDCODE_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY		0x23
+
+#define ZYNQMP_CSU_IDCODE_REVISION_SHIFT	28
+#define ZYNQMP_CSU_IDCODE_REVISION_MASK		(0xF << \
+					ZYNQMP_CSU_IDCODE_REVISION_SHIFT)
+#define ZYNQMP_CSU_IDCODE_REVISION		0
+
+#define ZYNQMP_CSU_VERSION_OFFSET	0x44
+
+/* Efuse */
+#define EFUSE_BASEADDR		0xFFCC0000
+#define EFUSE_IPDISABLE_OFFSET	0x1018
+#define EFUSE_IPDISABLE_VERSION	0x1FFU
+#define ZYNQMP_EFUSE_IPDISABLE_SHIFT	20
+
+/* Access control register defines */
+#define ACTLR_EL3_L2ACTLR_BIT	(1 << 6)
+#define ACTLR_EL3_CPUACTLR_BIT	(1 << 0)
+
+#define FPD_SLCR_BASEADDR		U(0xFD610000)
+#define IOU_SLCR_BASEADDR		U(0xFF180000)
+
+#define ZYNQMP_RPU_GLBL_CNTL			U(0xFF9A0000)
+#define ZYNQMP_RPU0_CFG				U(0xFF9A0100)
+#define ZYNQMP_RPU1_CFG				U(0xFF9A0200)
+#define ZYNQMP_SLSPLIT_MASK			U(0x08)
+#define ZYNQMP_TCM_COMB_MASK			U(0x40)
+#define ZYNQMP_SLCLAMP_MASK			U(0x10)
+#define ZYNQMP_VINITHI_MASK			U(0x04)
+
+/* Tap delay bypass */
+#define IOU_TAPDLY_BYPASS			U(0XFF180390)
+#define TAP_DELAY_MASK				U(0x7)
+
+/* SGMII mode */
+#define IOU_GEM_CTRL				U(0xFF180360)
+#define IOU_GEM_CLK_CTRL			U(0xFF180308)
+#define SGMII_SD_MASK				U(0x3)
+#define SGMII_SD_OFFSET				U(2)
+#define SGMII_PCS_SD_0				U(0x0)
+#define SGMII_PCS_SD_1				U(0x1)
+#define SGMII_PCS_SD_PHY			U(0x2)
+#define GEM_SGMII_MASK				U(0x4)
+#define GEM_CLK_CTRL_MASK			U(0xF)
+#define GEM_CLK_CTRL_OFFSET			U(5)
+#define GEM_RX_SRC_SEL_GTR			U(0x1)
+#define GEM_SGMII_MODE				U(0x4)
+
+/* SD DLL reset */
+#define ZYNQMP_SD_DLL_CTRL			U(0xFF180358)
+#define ZYNQMP_SD0_DLL_RST_MASK			U(0x00000004)
+#define ZYNQMP_SD0_DLL_RST			U(0x00000004)
+#define ZYNQMP_SD1_DLL_RST_MASK			U(0x00040000)
+#define ZYNQMP_SD1_DLL_RST			U(0x00040000)
+
+/* SD tap delay */
+#define ZYNQMP_SD_DLL_CTRL			U(0xFF180358)
+#define ZYNQMP_SD_ITAP_DLY			U(0xFF180314)
+#define ZYNQMP_SD_OTAP_DLY			U(0xFF180318)
+#define ZYNQMP_SD_TAP_OFFSET			U(16)
+#define ZYNQMP_SD_ITAPCHGWIN_MASK		U(0x200)
+#define ZYNQMP_SD_ITAPCHGWIN			U(0x200)
+#define ZYNQMP_SD_ITAPDLYENA_MASK		U(0x100)
+#define ZYNQMP_SD_ITAPDLYENA			U(0x100)
+#define ZYNQMP_SD_ITAPDLYSEL_MASK		U(0xFF)
+#define ZYNQMP_SD_OTAPDLYSEL_MASK		U(0x3F)
+#define ZYNQMP_SD_OTAPDLYENA_MASK		U(0x40)
+#define ZYNQMP_SD_OTAPDLYENA			U(0x40)
+
+/* Clock control registers */
+/* Full power domain clocks */
+#define CRF_APB_APLL_CTRL		(CRF_APB_CLK_BASE + 0x00)
+#define CRF_APB_DPLL_CTRL		(CRF_APB_CLK_BASE + 0x0c)
+#define CRF_APB_VPLL_CTRL		(CRF_APB_CLK_BASE + 0x18)
+#define CRF_APB_PLL_STATUS		(CRF_APB_CLK_BASE + 0x24)
+#define CRF_APB_APLL_TO_LPD_CTRL	(CRF_APB_CLK_BASE + 0x28)
+#define CRF_APB_DPLL_TO_LPD_CTRL	(CRF_APB_CLK_BASE + 0x2c)
+#define CRF_APB_VPLL_TO_LPD_CTRL	(CRF_APB_CLK_BASE + 0x30)
+/* Peripheral clocks */
+#define CRF_APB_ACPU_CTRL		(CRF_APB_CLK_BASE + 0x40)
+#define CRF_APB_DBG_TRACE_CTRL		(CRF_APB_CLK_BASE + 0x44)
+#define CRF_APB_DBG_FPD_CTRL		(CRF_APB_CLK_BASE + 0x48)
+#define CRF_APB_DP_VIDEO_REF_CTRL	(CRF_APB_CLK_BASE + 0x50)
+#define CRF_APB_DP_AUDIO_REF_CTRL	(CRF_APB_CLK_BASE + 0x54)
+#define CRF_APB_DP_STC_REF_CTRL		(CRF_APB_CLK_BASE + 0x5c)
+#define CRF_APB_DDR_CTRL		(CRF_APB_CLK_BASE + 0x60)
+#define CRF_APB_GPU_REF_CTRL		(CRF_APB_CLK_BASE + 0x64)
+#define CRF_APB_SATA_REF_CTRL		(CRF_APB_CLK_BASE + 0x80)
+#define CRF_APB_PCIE_REF_CTRL		(CRF_APB_CLK_BASE + 0x94)
+#define CRF_APB_GDMA_REF_CTRL		(CRF_APB_CLK_BASE + 0x98)
+#define CRF_APB_DPDMA_REF_CTRL		(CRF_APB_CLK_BASE + 0x9c)
+#define CRF_APB_TOPSW_MAIN_CTRL		(CRF_APB_CLK_BASE + 0xa0)
+#define CRF_APB_TOPSW_LSBUS_CTRL	(CRF_APB_CLK_BASE + 0xa4)
+#define CRF_APB_GTGREF0_REF_CTRL	(CRF_APB_CLK_BASE + 0xa8)
+#define CRF_APB_DBG_TSTMP_CTRL		(CRF_APB_CLK_BASE + 0xd8)
+
+/* Low power domain clocks */
+#define CRL_APB_IOPLL_CTRL		(CRL_APB_CLK_BASE + 0x00)
+#define CRL_APB_RPLL_CTRL		(CRL_APB_CLK_BASE + 0x10)
+#define CRL_APB_PLL_STATUS		(CRL_APB_CLK_BASE + 0x20)
+#define CRL_APB_IOPLL_TO_FPD_CTRL	(CRL_APB_CLK_BASE + 0x24)
+#define CRL_APB_RPLL_TO_FPD_CTRL	(CRL_APB_CLK_BASE + 0x28)
+/* Peripheral clocks */
+#define CRL_APB_USB3_DUAL_REF_CTRL	(CRL_APB_CLK_BASE + 0x2c)
+#define CRL_APB_GEM0_REF_CTRL		(CRL_APB_CLK_BASE + 0x30)
+#define CRL_APB_GEM1_REF_CTRL		(CRL_APB_CLK_BASE + 0x34)
+#define CRL_APB_GEM2_REF_CTRL		(CRL_APB_CLK_BASE + 0x38)
+#define CRL_APB_GEM3_REF_CTRL		(CRL_APB_CLK_BASE + 0x3c)
+#define CRL_APB_USB0_BUS_REF_CTRL	(CRL_APB_CLK_BASE + 0x40)
+#define CRL_APB_USB1_BUS_REF_CTRL	(CRL_APB_CLK_BASE + 0x44)
+#define CRL_APB_QSPI_REF_CTRL		(CRL_APB_CLK_BASE + 0x48)
+#define CRL_APB_SDIO0_REF_CTRL		(CRL_APB_CLK_BASE + 0x4c)
+#define CRL_APB_SDIO1_REF_CTRL		(CRL_APB_CLK_BASE + 0x50)
+#define CRL_APB_UART0_REF_CTRL		(CRL_APB_CLK_BASE + 0x54)
+#define CRL_APB_UART1_REF_CTRL		(CRL_APB_CLK_BASE + 0x58)
+#define CRL_APB_SPI0_REF_CTRL		(CRL_APB_CLK_BASE + 0x5c)
+#define CRL_APB_SPI1_REF_CTRL		(CRL_APB_CLK_BASE + 0x60)
+#define CRL_APB_CAN0_REF_CTRL		(CRL_APB_CLK_BASE + 0x64)
+#define CRL_APB_CAN1_REF_CTRL		(CRL_APB_CLK_BASE + 0x68)
+#define CRL_APB_CPU_R5_CTRL		(CRL_APB_CLK_BASE + 0x70)
+#define CRL_APB_IOU_SWITCH_CTRL		(CRL_APB_CLK_BASE + 0x7c)
+#define CRL_APB_CSU_PLL_CTRL		(CRL_APB_CLK_BASE + 0x80)
+#define CRL_APB_PCAP_CTRL		(CRL_APB_CLK_BASE + 0x84)
+#define CRL_APB_LPD_SWITCH_CTRL		(CRL_APB_CLK_BASE + 0x88)
+#define CRL_APB_LPD_LSBUS_CTRL		(CRL_APB_CLK_BASE + 0x8c)
+#define CRL_APB_DBG_LPD_CTRL		(CRL_APB_CLK_BASE + 0x90)
+#define CRL_APB_NAND_REF_CTRL		(CRL_APB_CLK_BASE + 0x94)
+#define CRL_APB_ADMA_REF_CTRL		(CRL_APB_CLK_BASE + 0x98)
+#define CRL_APB_PL0_REF_CTRL		(CRL_APB_CLK_BASE + 0xa0)
+#define CRL_APB_PL1_REF_CTRL		(CRL_APB_CLK_BASE + 0xa4)
+#define CRL_APB_PL2_REF_CTRL		(CRL_APB_CLK_BASE + 0xa8)
+#define CRL_APB_PL3_REF_CTRL		(CRL_APB_CLK_BASE + 0xac)
+#define CRL_APB_PL0_THR_CNT		(CRL_APB_CLK_BASE + 0xb4)
+#define CRL_APB_PL1_THR_CNT		(CRL_APB_CLK_BASE + 0xbc)
+#define CRL_APB_PL2_THR_CNT		(CRL_APB_CLK_BASE + 0xc4)
+#define CRL_APB_PL3_THR_CNT		(CRL_APB_CLK_BASE + 0xdc)
+#define CRL_APB_GEM_TSU_REF_CTRL	(CRL_APB_CLK_BASE + 0xe0)
+#define CRL_APB_DLL_REF_CTRL		(CRL_APB_CLK_BASE + 0xe4)
+#define CRL_APB_AMS_REF_CTRL		(CRL_APB_CLK_BASE + 0xe8)
+#define CRL_APB_I2C0_REF_CTRL		(CRL_APB_CLK_BASE + 0x100)
+#define CRL_APB_I2C1_REF_CTRL		(CRL_APB_CLK_BASE + 0x104)
+#define CRL_APB_TIMESTAMP_REF_CTRL	(CRL_APB_CLK_BASE + 0x108)
+#define IOU_SLCR_GEM_CLK_CTRL		(IOU_SLCR_BASEADDR + 0x308)
+#define IOU_SLCR_CAN_MIO_CTRL		(IOU_SLCR_BASEADDR + 0x304)
+#define FPD_SLCR_WDT_CLK_SEL		(FPD_SLCR_BASEADDR + 0x100)
+
+/* Global general storage register base address */
+#define GGS_BASEADDR		(0xFFD80030U)
+#define GGS_NUM_REGS		U(4)
+
+/* Persistent global general storage register base address */
+#define PGGS_BASEADDR		(0xFFD80050U)
+#define PGGS_NUM_REGS		U(4)
+
+/* Warm restart boot health status register and mask */
+#define PM_BOOT_HEALTH_STATUS_REG		(GGS_BASEADDR + U(0x10))
+#define PM_BOOT_HEALTH_STATUS_MASK		U(0x01)
+
+/*AFI registers */
+#define  AFIFM6_WRCTRL		U(13)
+#define  FABRIC_WIDTH		U(3)
+
+#endif /* ZYNQMP_DEF_H */
diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
new file mode 100644
index 0000000..c499d78
--- /dev/null
+++ b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+#include "ipi_mailbox_svc.h"
+#include "../../../services/spd/trusty/smcall.h"
+
+/*********************************************************************
+ * Macros definitions
+ ********************************************************************/
+
+/* IPI SMC calls macros: */
+#define IPI_SMC_OPEN_IRQ_MASK		0x00000001U /* IRQ enable bit in IPI
+						     * open SMC call
+						     */
+#define IPI_SMC_NOTIFY_BLOCK_MASK	0x00000001U /* Flag to indicate if
+						     * IPI notification needs
+						     * to be blocking.
+						     */
+#define IPI_SMC_ENQUIRY_DIRQ_MASK	0x00000001U /* Flag to indicate if
+						     * notification interrupt
+						     * to be disabled.
+						     */
+#define IPI_SMC_ACK_EIRQ_MASK		0x00000001U /* Flag to indicate if
+						     * notification interrupt
+						     * to be enable.
+						     */
+
+#define UNSIGNED32_MASK			0xFFFFFFFFU /* 32bit mask */
+
+/**
+ * ipi_smc_handler() - SMC handler for IPI SMC calls
+ *
+ * @smc_fid - Function identifier
+ * @x1 - x4 - Arguments
+ * @cookie  - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return  - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+			 uint64_t x3, uint64_t x4, void *cookie,
+			 void *handle, uint64_t flags)
+{
+	int ret;
+	uint32_t ipi_local_id;
+	uint32_t ipi_remote_id;
+	unsigned int is_secure;
+
+	ipi_local_id = x1 & UNSIGNED32_MASK;
+	ipi_remote_id = x2 & UNSIGNED32_MASK;
+
+	if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP)
+		is_secure = 1;
+	else
+		is_secure = 0;
+
+	/* Validate IPI mailbox access */
+	ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure);
+	if (ret)
+		SMC_RET1(handle, ret);
+
+	switch (SMC_FUNCTION(smc_fid)) {
+	case IPI_MAILBOX_OPEN:
+		ipi_mb_open(ipi_local_id, ipi_remote_id);
+		SMC_RET1(handle, 0);
+	case IPI_MAILBOX_RELEASE:
+		ipi_mb_release(ipi_local_id, ipi_remote_id);
+		SMC_RET1(handle, 0);
+	case IPI_MAILBOX_STATUS_ENQUIRY:
+	{
+		int disable_irq;
+
+		disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0;
+		ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id);
+		if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq)
+			ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
+		SMC_RET1(handle, ret);
+	}
+	case IPI_MAILBOX_NOTIFY:
+	{
+		uint32_t is_blocking;
+
+		is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0;
+		ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking);
+		SMC_RET1(handle, 0);
+	}
+	case IPI_MAILBOX_ACK:
+	{
+		int enable_irq;
+
+		enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0;
+		ipi_mb_ack(ipi_local_id, ipi_remote_id);
+		if (enable_irq)
+			ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
+		SMC_RET1(handle, 0);
+	}
+	case IPI_MAILBOX_ENABLE_IRQ:
+		ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
+		SMC_RET1(handle, 0);
+	case IPI_MAILBOX_DISABLE_IRQ:
+		ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
+		SMC_RET1(handle, 0);
+	default:
+		WARN("Unimplemented IPI service call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h
new file mode 100644
index 0000000..197c788
--- /dev/null
+++ b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* ZynqMP IPI mailbox doorbell service enums and defines */
+
+#ifndef IPI_MAILBOX_SVC_H
+#define IPI_MAILBOX_SVC_H
+
+#include <stdint.h>
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+/* IPI SMC function numbers enum definition */
+enum ipi_api_id {
+	/* IPI mailbox operations functions: */
+	IPI_MAILBOX_OPEN = 0x1000,
+	IPI_MAILBOX_RELEASE,
+	IPI_MAILBOX_STATUS_ENQUIRY,
+	IPI_MAILBOX_NOTIFY,
+	IPI_MAILBOX_ACK,
+	IPI_MAILBOX_ENABLE_IRQ,
+	IPI_MAILBOX_DISABLE_IRQ
+};
+
+/*********************************************************************
+ * IPI mailbox service APIs declarations
+ ********************************************************************/
+
+/* IPI SMC handler */
+uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+			 uint64_t x3, uint64_t x4, void *cookie, void *handle,
+			 uint64_t flags);
+
+#endif /* IPI_MAILBOX_SVC_H */
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
new file mode 100644
index 0000000..a32e089
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+uintptr_t zynqmp_sec_entry;
+
+void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+	VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
+
+	dsb();
+	wfi();
+}
+
+static int zynqmp_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+	const struct pm_proc *proc;
+
+	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+	if (cpu_id == -1)
+		return PSCI_E_INTERN_FAIL;
+
+	proc = pm_get_proc(cpu_id);
+	/* Clear power down request */
+	pm_client_wakeup(proc);
+
+	/* Send request to PMU to wake up selected APU CPU core */
+	pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_BLOCKING);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	gicv2_cpuif_disable();
+
+	/*
+	 * Send request to PMU to power down the appropriate APU CPU
+	 * core.
+	 * According to PSCI specification, CPU_off function does not
+	 * have resume address and CPU core can only be woken up
+	 * invoking CPU_on function, during which resume address will
+	 * be set.
+	 */
+	pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
+}
+
+static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	unsigned int state;
+	unsigned int cpu_id = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+		PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+	/* Send request to PMU to suspend this core */
+	pm_self_suspend(proc->node_id, MAX_LATENCY, state, zynqmp_sec_entry);
+
+	/* APU is to be turned off */
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		/* disable coherency */
+		plat_arm_interconnect_exit_coherency();
+	}
+}
+
+static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	gicv2_cpuif_enable();
+	gicv2_pcpu_distif_init();
+}
+
+static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+			__func__, i, target_state->pwr_domain_state[i]);
+
+	/* Clear the APU power control register for this cpu */
+	pm_client_wakeup(proc);
+
+	/* enable coherency */
+	plat_arm_interconnect_enter_coherency();
+	/* APU was turned off */
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		plat_arm_gic_init();
+	} else {
+		gicv2_cpuif_enable();
+		gicv2_pcpu_distif_init();
+	}
+}
+
+/*******************************************************************************
+ * ZynqMP handlers to shutdown/reboot the system
+ ******************************************************************************/
+
+static void __dead2 zynqmp_system_off(void)
+{
+	/* disable coherency */
+	plat_arm_interconnect_exit_coherency();
+
+	/* Send the power down request to the PMU */
+	pm_system_shutdown(PMF_SHUTDOWN_TYPE_SHUTDOWN,
+			   pm_get_shutdown_scope());
+
+	while (1)
+		wfi();
+}
+
+static void __dead2 zynqmp_system_reset(void)
+{
+	/* disable coherency */
+	plat_arm_interconnect_exit_coherency();
+
+	/* Send the system reset request to the PMU */
+	pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET,
+			   pm_get_shutdown_scope());
+
+	while (1)
+		wfi();
+}
+
+int zynqmp_validate_power_state(unsigned int power_state,
+				psci_power_state_t *req_state)
+{
+	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+	int pstate = psci_get_pstate_type(power_state);
+
+	assert(req_state);
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY)
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+	else
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+
+	/* We expect the 'state id' to be zero */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+int zynqmp_validate_ns_entrypoint(unsigned long ns_entrypoint)
+{
+	VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
+
+	/* FIXME: Actually validate */
+	return PSCI_E_SUCCESS;
+}
+
+void zynqmp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * Export the platform handlers to enable psci to invoke them
+ ******************************************************************************/
+static const struct plat_psci_ops zynqmp_psci_ops = {
+	.cpu_standby			= zynqmp_cpu_standby,
+	.pwr_domain_on			= zynqmp_pwr_domain_on,
+	.pwr_domain_off			= zynqmp_pwr_domain_off,
+	.pwr_domain_suspend		= zynqmp_pwr_domain_suspend,
+	.pwr_domain_on_finish		= zynqmp_pwr_domain_on_finish,
+	.pwr_domain_suspend_finish	= zynqmp_pwr_domain_suspend_finish,
+	.system_off			= zynqmp_system_off,
+	.system_reset			= zynqmp_system_reset,
+	.validate_power_state		= zynqmp_validate_power_state,
+	.validate_ns_entrypoint		= zynqmp_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= zynqmp_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	zynqmp_sec_entry = sec_entrypoint;
+
+	*psci_ops = &zynqmp_psci_ops;
+
+	return 0;
+}
diff --git a/plat/xilinx/zynqmp/plat_startup.c b/plat/xilinx/zynqmp/plat_startup.c
new file mode 100644
index 0000000..cd2c3ba
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_startup.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <plat_private.h>
+
+#include "zynqmp_def.h"
+
+/*
+ * ATFHandoffParams
+ * Parameter		bitfield	encoding
+ * -----------------------------------------------------------------------------
+ * Exec State		0		0 -> Aarch64, 1-> Aarch32
+ * endianness		1		0 -> LE, 1 -> BE
+ * secure (TZ)		2		0 -> Non secure, 1 -> secure
+ * EL			3:4		00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3
+ * CPU#			5:6		00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3
+ */
+
+#define FSBL_FLAGS_ESTATE_SHIFT		0
+#define FSBL_FLAGS_ESTATE_MASK		(1 << FSBL_FLAGS_ESTATE_SHIFT)
+#define FSBL_FLAGS_ESTATE_A64		0
+#define FSBL_FLAGS_ESTATE_A32		1
+
+#define FSBL_FLAGS_ENDIAN_SHIFT		1
+#define FSBL_FLAGS_ENDIAN_MASK		(1 << FSBL_FLAGS_ENDIAN_SHIFT)
+#define FSBL_FLAGS_ENDIAN_LE		0
+#define FSBL_FLAGS_ENDIAN_BE		1
+
+#define FSBL_FLAGS_TZ_SHIFT		2
+#define FSBL_FLAGS_TZ_MASK		(1 << FSBL_FLAGS_TZ_SHIFT)
+#define FSBL_FLAGS_NON_SECURE		0
+#define FSBL_FLAGS_SECURE		1
+
+#define FSBL_FLAGS_EL_SHIFT		3
+#define FSBL_FLAGS_EL_MASK		(3 << FSBL_FLAGS_EL_SHIFT)
+#define FSBL_FLAGS_EL0			0
+#define FSBL_FLAGS_EL1			1
+#define FSBL_FLAGS_EL2			2
+#define FSBL_FLAGS_EL3			3
+
+#define FSBL_FLAGS_CPU_SHIFT		5
+#define FSBL_FLAGS_CPU_MASK		(3 << FSBL_FLAGS_CPU_SHIFT)
+#define FSBL_FLAGS_A53_0		0
+#define FSBL_FLAGS_A53_1		1
+#define FSBL_FLAGS_A53_2		2
+#define FSBL_FLAGS_A53_3		3
+
+#define FSBL_MAX_PARTITIONS		8
+
+/* Structure corresponding to each partition entry */
+struct xfsbl_partition {
+	uint64_t entry_point;
+	uint64_t flags;
+};
+
+/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */
+struct xfsbl_atf_handoff_params {
+	uint8_t magic[4];
+	uint32_t num_entries;
+	struct xfsbl_partition partition[FSBL_MAX_PARTITIONS];
+};
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target CPU for @partition.
+ *
+ * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or FSBL_FLAGS_A53_3
+ */
+static int get_fsbl_cpu(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK;
+
+	return flags >> FSBL_FLAGS_CPU_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target exception level for @partition.
+ *
+ * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3
+ */
+static int get_fsbl_el(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK;
+
+	return flags >> FSBL_FLAGS_EL_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target security state for @partition.
+ *
+ * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE
+ */
+static int get_fsbl_ss(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK;
+
+	return flags >> FSBL_FLAGS_TZ_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target endianness for @partition.
+ *
+ * Return: SPSR_E_LITTLE or SPSR_E_BIG
+ */
+static int get_fsbl_endian(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK;
+
+	flags >>= FSBL_FLAGS_ENDIAN_SHIFT;
+
+	if (flags == FSBL_FLAGS_ENDIAN_BE)
+		return SPSR_E_BIG;
+	else
+		return SPSR_E_LITTLE;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target execution state for @partition.
+ *
+ * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64
+ */
+static int get_fsbl_estate(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK;
+
+	return flags >> FSBL_FLAGS_ESTATE_SHIFT;
+}
+
+/**
+ * Populates the bl32 and bl33 image info structures
+ * @bl32:	BL32 image info structure
+ * @bl33:	BL33 image info structure
+ *
+ * Process the handoff paramters from the FSBL and populate the BL32 and BL33
+ * image info structures accordingly.
+ *
+ * Return: Return the status of the handoff. The value will be from the
+ *         fsbl_handoff enum.
+ */
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
+{
+	uint64_t atf_handoff_addr;
+	const struct xfsbl_atf_handoff_params *ATFHandoffParams;
+
+	atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6);
+	assert((atf_handoff_addr < BL31_BASE) ||
+	       (atf_handoff_addr > (uint64_t)&__BL31_END__));
+	if (!atf_handoff_addr) {
+		WARN("BL31: No ATF handoff structure passed\n");
+		return FSBL_HANDOFF_NO_STRUCT;
+	}
+
+	ATFHandoffParams = (struct xfsbl_atf_handoff_params *)atf_handoff_addr;
+	if ((ATFHandoffParams->magic[0] != 'X') ||
+	    (ATFHandoffParams->magic[1] != 'L') ||
+	    (ATFHandoffParams->magic[2] != 'N') ||
+	    (ATFHandoffParams->magic[3] != 'X')) {
+		ERROR("BL31: invalid ATF handoff structure at %llx\n",
+		      atf_handoff_addr);
+		return FSBL_HANDOFF_INVAL_STRUCT;
+	}
+
+	VERBOSE("BL31: ATF handoff params at:0x%llx, entries:%u\n",
+		atf_handoff_addr, ATFHandoffParams->num_entries);
+	if (ATFHandoffParams->num_entries > FSBL_MAX_PARTITIONS) {
+		ERROR("BL31: ATF handoff params: too many partitions (%u/%u)\n",
+		      ATFHandoffParams->num_entries, FSBL_MAX_PARTITIONS);
+		return FSBL_HANDOFF_TOO_MANY_PARTS;
+	}
+
+	/*
+	 * we loop over all passed entries but only populate two image structs
+	 * (bl32, bl33). I.e. the last applicable images in the handoff
+	 * structure will be used for the hand off
+	 */
+	for (size_t i = 0; i < ATFHandoffParams->num_entries; i++) {
+		entry_point_info_t *image;
+		int target_estate, target_secure;
+		int target_cpu, target_endianness, target_el;
+
+		VERBOSE("BL31: %zd: entry:0x%llx, flags:0x%llx\n", i,
+			ATFHandoffParams->partition[i].entry_point,
+			ATFHandoffParams->partition[i].flags);
+
+		target_cpu = get_fsbl_cpu(&ATFHandoffParams->partition[i]);
+		if (target_cpu != FSBL_FLAGS_A53_0) {
+			WARN("BL31: invalid target CPU (%i)\n", target_cpu);
+			continue;
+		}
+
+		target_el = get_fsbl_el(&ATFHandoffParams->partition[i]);
+		if ((target_el == FSBL_FLAGS_EL3) ||
+		    (target_el == FSBL_FLAGS_EL0)) {
+			WARN("BL31: invalid exception level (%i)\n", target_el);
+			continue;
+		}
+
+		target_secure = get_fsbl_ss(&ATFHandoffParams->partition[i]);
+		if (target_secure == FSBL_FLAGS_SECURE &&
+		    target_el == FSBL_FLAGS_EL2) {
+			WARN("BL31: invalid security state (%i) for exception level (%i)\n",
+			     target_secure, target_el);
+			continue;
+		}
+
+		target_estate = get_fsbl_estate(&ATFHandoffParams->partition[i]);
+		target_endianness = get_fsbl_endian(&ATFHandoffParams->partition[i]);
+
+		if (target_secure == FSBL_FLAGS_SECURE) {
+			image = bl32;
+
+			if (target_estate == FSBL_FLAGS_ESTATE_A32)
+				bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
+							 target_endianness,
+							 DISABLE_ALL_EXCEPTIONS);
+			else
+				bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+						     DISABLE_ALL_EXCEPTIONS);
+		} else {
+			image = bl33;
+
+			if (target_estate == FSBL_FLAGS_ESTATE_A32) {
+				if (target_el == FSBL_FLAGS_EL2)
+					target_el = MODE32_hyp;
+				else
+					target_el = MODE32_sys;
+
+				bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM,
+							 target_endianness,
+							 DISABLE_ALL_EXCEPTIONS);
+			} else {
+				if (target_el == FSBL_FLAGS_EL2)
+					target_el = MODE_EL2;
+				else
+					target_el = MODE_EL1;
+
+				bl33->spsr = SPSR_64(target_el, MODE_SP_ELX,
+						     DISABLE_ALL_EXCEPTIONS);
+			}
+		}
+
+		VERBOSE("Setting up %s entry point to:%llx, el:%x\n",
+			target_secure == FSBL_FLAGS_SECURE ? "BL32" : "BL33",
+			ATFHandoffParams->partition[i].entry_point,
+			target_el);
+		image->pc = ATFHandoffParams->partition[i].entry_point;
+
+		if (target_endianness == SPSR_E_BIG)
+			EP_SET_EE(image->h.attr, EP_EE_BIG);
+		else
+			EP_SET_EE(image->h.attr, EP_EE_LITTLE);
+	}
+
+	return FSBL_HANDOFF_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/plat_topology.c b/plat/xilinx/zynqmp/plat_topology.c
new file mode 100644
index 0000000..aab24aa
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_topology.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+static const unsigned char plat_power_domain_tree_desc[] = {1, 4};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/zynqmp/plat_zynqmp.c b/plat/xilinx/zynqmp/plat_zynqmp.c
new file mode 100644
index 0000000..906ce1b
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_zynqmp.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		return -1;
+
+	if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT)
+		return -1;
+
+	return zynqmp_calc_core_pos(mpidr);
+}
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
new file mode 100644
index 0000000..bd7bc08
--- /dev/null
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -0,0 +1,88 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+override ERRATA_A53_855873 := 1
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+SEPARATE_CODE_AND_RODATA := 1
+ZYNQMP_WDT_RESTART := 0
+override RESET_TO_BL31 := 1
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS	:= 0
+
+WORKAROUND_CVE_2017_5715	:=	0
+
+ifdef ZYNQMP_ATF_MEM_BASE
+    $(eval $(call add_define,ZYNQMP_ATF_MEM_BASE))
+
+    ifndef ZYNQMP_ATF_MEM_SIZE
+        $(error "ZYNQMP_ATF_BASE defined without ZYNQMP_ATF_SIZE")
+    endif
+    $(eval $(call add_define,ZYNQMP_ATF_MEM_SIZE))
+
+    ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE
+        $(eval $(call add_define,ZYNQMP_ATF_MEM_PROGBITS_SIZE))
+    endif
+endif
+
+ifdef ZYNQMP_BL32_MEM_BASE
+    $(eval $(call add_define,ZYNQMP_BL32_MEM_BASE))
+
+    ifndef ZYNQMP_BL32_MEM_SIZE
+        $(error "ZYNQMP_BL32_BASE defined without ZYNQMP_BL32_SIZE")
+    endif
+    $(eval $(call add_define,ZYNQMP_BL32_MEM_SIZE))
+endif
+
+ZYNQMP_CONSOLE	?=	cadence
+$(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}))
+
+ifdef ZYNQMP_WDT_RESTART
+$(eval $(call add_define,ZYNQMP_WDT_RESTART))
+endif
+
+PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/aarch64/		\
+				-Iplat/xilinx/common/include/			\
+				-Iplat/xilinx/zynqmp/include/			\
+				-Iplat/xilinx/zynqmp/pm_service/		\
+				-Iplat/xilinx/zynqmp/ipi_mailbox_service/
+
+PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				drivers/cadence/uart/aarch64/cdns_console.S	\
+				plat/arm/common/arm_cci.c			\
+				plat/arm/common/arm_common.c			\
+				plat/arm/common/arm_gicv2.c			\
+				plat/common/plat_gicv2.c			\
+				plat/xilinx/common/ipi.c			\
+				plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S	\
+				plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
+				lib/cpus/aarch64/aem_generic.S			\
+				lib/cpus/aarch64/cortex_a53.S			\
+				plat/common/plat_psci_common.c			\
+				plat/xilinx/common/pm_service/pm_ipi.c		\
+				plat/xilinx/zynqmp/bl31_zynqmp_setup.c		\
+				plat/xilinx/zynqmp/plat_psci.c			\
+				plat/xilinx/zynqmp/plat_zynqmp.c		\
+				plat/xilinx/zynqmp/plat_startup.c		\
+				plat/xilinx/zynqmp/plat_topology.c		\
+				plat/xilinx/zynqmp/sip_svc_setup.c		\
+				plat/xilinx/zynqmp/zynqmp_ipi.c		\
+				plat/xilinx/zynqmp/pm_service/pm_svc_main.c	\
+				plat/xilinx/zynqmp/pm_service/pm_api_sys.c	\
+				plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c	\
+				plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c	\
+				plat/xilinx/zynqmp/pm_service/pm_api_clock.c	\
+				plat/xilinx/zynqmp/pm_service/pm_client.c	\
+				plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
new file mode 100644
index 0000000..85cffcb
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -0,0 +1,2868 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for clock control.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_clock.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+#define CLK_NODE_MAX			U(6)
+
+#define CLK_PARENTS_ID_LEN		U(16)
+#define CLK_TOPOLOGY_NODE_OFFSET	U(16)
+#define CLK_TOPOLOGY_PAYLOAD_LEN	U(12)
+#define CLK_PARENTS_PAYLOAD_LEN		U(12)
+#define CLK_TYPE_SHIFT			U(2)
+#define CLK_CLKFLAGS_SHIFT		U(8)
+#define CLK_TYPEFLAGS_SHIFT		U(24)
+
+#define CLK_EXTERNAL_PARENT	(PARENT_CLK_EXTERNAL << CLK_PARENTS_ID_LEN)
+
+#define NA_MULT					U(0)
+#define NA_DIV					U(0)
+#define NA_SHIFT				U(0)
+#define NA_WIDTH				U(0)
+#define NA_CLK_FLAGS				U(0)
+#define NA_TYPE_FLAGS				U(0)
+
+/* PLL nodes related definitions */
+#define PLL_PRESRC_MUX_SHIFT			U(20)
+#define PLL_PRESRC_MUX_WIDTH			U(3)
+#define PLL_POSTSRC_MUX_SHIFT			U(24)
+#define PLL_POSTSRC_MUX_WIDTH			U(3)
+#define PLL_DIV2_MUX_SHIFT			U(16)
+#define PLL_DIV2_MUX_WIDTH			U(1)
+#define PLL_BYPASS_MUX_SHIFT			U(3)
+#define PLL_BYPASS_MUX_WIDTH			U(1)
+
+/* Peripheral nodes related definitions */
+/* Peripheral Clocks */
+#define PERIPH_MUX_SHIFT			U(0)
+#define PERIPH_MUX_WIDTH			U(3)
+#define PERIPH_DIV1_SHIFT			U(8)
+#define PERIPH_DIV1_WIDTH			U(6)
+#define PERIPH_DIV2_SHIFT			U(16)
+#define PERIPH_DIV2_WIDTH			U(6)
+#define PERIPH_GATE_SHIFT			U(24)
+#define PERIPH_GATE_WIDTH			U(1)
+
+#define USB_GATE_SHIFT				U(25)
+
+/* External clock related definitions */
+
+#define EXT_CLK_MIO_DATA(mio)				\
+	[EXT_CLK_INDEX(EXT_CLK_MIO##mio)] = {		\
+		.name = "mio_clk_"#mio,			\
+	}
+
+#define EXT_CLK_INDEX(n)	(n - CLK_MAX_OUTPUT_CLK)
+
+/* Clock control related definitions */
+#define BIT_MASK(x, y) (((1U << (y)) - 1) << (x))
+
+#define ISPLL(id)	(id == CLK_APLL_INT ||	\
+			 id == CLK_DPLL_INT ||  \
+			 id == CLK_VPLL_INT ||  \
+			 id == CLK_IOPLL_INT || \
+			 id == CLK_RPLL_INT)
+
+
+#define PLLCTRL_BP_MASK				BIT(3)
+#define PLLCTRL_RESET_MASK			U(1)
+#define PLL_FRAC_OFFSET				U(8)
+#define PLL_FRAC_MODE				U(1)
+#define PLL_INT_MODE				U(0)
+#define PLL_FRAC_MODE_MASK			U(0x80000000)
+#define PLL_FRAC_MODE_SHIFT			U(31)
+#define PLL_FRAC_DATA_MASK			U(0xFFFF)
+#define PLL_FRAC_DATA_SHIFT			U(0)
+#define PLL_FBDIV_MASK				U(0x7F00)
+#define PLL_FBDIV_WIDTH				U(7)
+#define PLL_FBDIV_SHIFT				U(8)
+
+#define CLK_PLL_RESET_ASSERT			U(1)
+#define CLK_PLL_RESET_RELEASE			U(2)
+#define CLK_PLL_RESET_PULSE	(CLK_PLL_RESET_ASSERT | CLK_PLL_RESET_RELEASE)
+
+/* Common topology definitions */
+#define GENERIC_MUX					\
+	{						\
+		.type = TYPE_MUX,			\
+		.offset = PERIPH_MUX_SHIFT,		\
+		.width = PERIPH_MUX_WIDTH,		\
+		.clkflags = CLK_SET_RATE_NO_REPARENT |	\
+			    CLK_IS_BASIC,		\
+		.typeflags = NA_TYPE_FLAGS,		\
+		.mult = NA_MULT,			\
+		.div = NA_DIV,				\
+	}
+
+#define IGNORE_UNUSED_MUX				\
+	{						\
+		.type = TYPE_MUX,			\
+		.offset = PERIPH_MUX_SHIFT,		\
+		.width = PERIPH_MUX_WIDTH,		\
+		.clkflags = CLK_IGNORE_UNUSED |		\
+			    CLK_SET_RATE_NO_REPARENT |	\
+			    CLK_IS_BASIC,		\
+		.typeflags = NA_TYPE_FLAGS,		\
+		.mult = NA_MULT,			\
+		.div = NA_DIV,				\
+	}
+
+#define GENERIC_DIV(id)						\
+	{							\
+		.type = TYPE_DIV##id,				\
+		.offset = PERIPH_DIV##id##_SHIFT,		\
+		.width = PERIPH_DIV##id##_WIDTH,		\
+		.clkflags = CLK_SET_RATE_NO_REPARENT |		\
+			    CLK_IS_BASIC,			\
+		.typeflags = CLK_DIVIDER_ONE_BASED |		\
+			     CLK_DIVIDER_ALLOW_ZERO,		\
+		.mult = NA_MULT,				\
+		.div = NA_DIV,					\
+	}
+
+#define IGNORE_UNUSED_DIV(id)					\
+	{							\
+		.type = TYPE_DIV##id,				\
+		.offset = PERIPH_DIV##id##_SHIFT,		\
+		.width = PERIPH_DIV##id##_WIDTH,		\
+		.clkflags = CLK_IGNORE_UNUSED |			\
+			    CLK_SET_RATE_NO_REPARENT |		\
+			    CLK_IS_BASIC,			\
+		.typeflags = CLK_DIVIDER_ONE_BASED |		\
+			     CLK_DIVIDER_ALLOW_ZERO,		\
+		.mult = NA_MULT,				\
+		.div = NA_DIV,					\
+	}
+
+#define GENERIC_GATE						\
+	{							\
+		.type = TYPE_GATE,				\
+		.offset = PERIPH_GATE_SHIFT,			\
+		.width = PERIPH_GATE_WIDTH,			\
+		.clkflags = CLK_SET_RATE_PARENT |		\
+			    CLK_SET_RATE_GATE |			\
+			    CLK_IS_BASIC,			\
+		.typeflags = NA_TYPE_FLAGS,			\
+		.mult = NA_MULT,				\
+		.div = NA_DIV,					\
+	}
+
+#define IGNORE_UNUSED_GATE					\
+	{							\
+		.type = TYPE_GATE,				\
+		.offset = PERIPH_GATE_SHIFT,			\
+		.width = PERIPH_GATE_WIDTH,			\
+		.clkflags = CLK_SET_RATE_PARENT |		\
+			    CLK_IGNORE_UNUSED |			\
+			    CLK_IS_BASIC,			\
+		.typeflags = NA_TYPE_FLAGS,			\
+		.mult = NA_MULT,				\
+		.div = NA_DIV,					\
+	}
+
+/**
+ * struct pm_clock_node - Clock topology node information
+ * @type:	Topology type (mux/div1/div2/gate/pll/fixed factor)
+ * @offset:	Offset in control register
+ * @width:	Width of the specific type in control register
+ * @clkflags:	Clk specific flags
+ * @typeflags:	Type specific flags
+ * @mult:	Multiplier for fixed factor
+ * @div:	Divisor for fixed factor
+ */
+struct pm_clock_node {
+	uint16_t clkflags;
+	uint16_t typeflags;
+	uint8_t type;
+	uint8_t offset;
+	uint8_t width;
+	uint8_t mult:4;
+	uint8_t div:4;
+};
+
+/**
+ * struct pm_clock - Clock structure
+ * @name:	Clock name
+ * @control_reg:	Control register address
+ * @status_reg:	Status register address
+ * @parents:	Parents for first clock node. Lower byte indicates parent
+ *		clock id and upper byte indicate flags for that id.
+ * pm_clock_node:	Clock nodes
+ */
+struct pm_clock {
+	char name[CLK_NAME_LEN];
+	uint8_t num_nodes;
+	unsigned int control_reg;
+	unsigned int status_reg;
+	int32_t (*parents)[];
+	struct pm_clock_node(*nodes)[];
+};
+
+/**
+ * struct pm_clock - Clock structure
+ * @name:		Clock name
+ */
+struct pm_ext_clock {
+	char name[CLK_NAME_LEN];
+};
+
+/* PLL Clocks */
+static struct pm_clock_node generic_pll_nodes[] = {
+	{
+		.type = TYPE_PLL,
+		.offset = NA_SHIFT,
+		.width = NA_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node ignore_unused_pll_nodes[] = {
+	{
+		.type = TYPE_PLL,
+		.offset = NA_SHIFT,
+		.width = NA_WIDTH,
+		.clkflags = CLK_IGNORE_UNUSED | CLK_SET_RATE_NO_REPARENT,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node generic_pll_pre_src_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = PLL_PRESRC_MUX_SHIFT,
+		.width = PLL_PRESRC_MUX_WIDTH,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node generic_pll_half_nodes[] = {
+	{
+		.type = TYPE_FIXEDFACTOR,
+		.offset = NA_SHIFT,
+		.width = NA_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = 1,
+		.div = 2,
+	},
+};
+
+static struct pm_clock_node generic_pll_int_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = PLL_DIV2_MUX_SHIFT,
+		.width =  PLL_DIV2_MUX_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT |
+			    CLK_SET_RATE_PARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node generic_pll_post_src_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = PLL_POSTSRC_MUX_SHIFT,
+		.width = PLL_POSTSRC_MUX_WIDTH,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node generic_pll_system_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = PLL_BYPASS_MUX_SHIFT,
+		.width = PLL_BYPASS_MUX_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT |
+			    CLK_SET_RATE_PARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node acpu_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = PERIPH_MUX_SHIFT,
+		.width = PERIPH_MUX_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_DIV1,
+		.offset = PERIPH_DIV1_SHIFT,
+		.width = PERIPH_DIV1_WIDTH,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node generic_mux_div_nodes[] = {
+	GENERIC_MUX,
+	GENERIC_DIV(1),
+};
+
+static struct pm_clock_node generic_mux_div_gate_nodes[] = {
+	GENERIC_MUX,
+	GENERIC_DIV(1),
+	GENERIC_GATE,
+};
+
+static struct pm_clock_node generic_mux_div_unused_gate_nodes[] = {
+	GENERIC_MUX,
+	GENERIC_DIV(1),
+	IGNORE_UNUSED_GATE,
+};
+
+static struct pm_clock_node generic_mux_div_div_gate_nodes[] = {
+	GENERIC_MUX,
+	GENERIC_DIV(1),
+	GENERIC_DIV(2),
+	GENERIC_GATE,
+};
+
+static struct pm_clock_node dp_audio_video_ref_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = PERIPH_MUX_SHIFT,
+		.width = PERIPH_MUX_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT |
+			    CLK_SET_RATE_PARENT |
+			    CLK_FRAC | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_DIV1,
+		.offset = PERIPH_DIV1_SHIFT,
+		.width = PERIPH_DIV1_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
+			    CLK_FRAC | CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_DIV2,
+		.offset = PERIPH_DIV2_SHIFT,
+		.width = PERIPH_DIV2_WIDTH,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
+			    CLK_FRAC | CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = PERIPH_GATE_SHIFT,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_GATE |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node usb_nodes[] = {
+	GENERIC_MUX,
+	GENERIC_DIV(1),
+	GENERIC_DIV(2),
+	{
+		.type = TYPE_GATE,
+		.offset = USB_GATE_SHIFT,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC |
+			    CLK_SET_RATE_GATE,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node generic_domain_crossing_nodes[] = {
+	{
+		.type = TYPE_DIV1,
+		.offset = 8,
+		.width = 6,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node rpll_to_fpd_nodes[] = {
+	{
+		.type = TYPE_DIV1,
+		.offset = 8,
+		.width = 6,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node acpu_half_nodes[] = {
+	{
+		.type = TYPE_FIXEDFACTOR,
+		.offset = 0,
+		.width = 1,
+		.clkflags = 0,
+		.typeflags = 0,
+		.mult = 1,
+		.div = 2,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = 25,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_IGNORE_UNUSED |
+			    CLK_SET_RATE_PARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node acpu_full_nodes[] = {
+	{
+		.type = TYPE_GATE,
+		.offset = 24,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_IGNORE_UNUSED |
+			    CLK_SET_RATE_PARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node wdt_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 0,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node ddr_nodes[] = {
+	GENERIC_MUX,
+	{
+		.type = TYPE_DIV1,
+		.offset = 8,
+		.width = 6,
+		.clkflags = CLK_IS_BASIC | CLK_IS_CRITICAL,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node pl_nodes[] = {
+	GENERIC_MUX,
+	{
+		.type = TYPE_DIV1,
+		.offset = PERIPH_DIV1_SHIFT,
+		.width = PERIPH_DIV1_WIDTH,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_DIV2,
+		.offset = PERIPH_DIV2_SHIFT,
+		.width = PERIPH_DIV2_WIDTH,
+		.clkflags = CLK_IS_BASIC | CLK_SET_RATE_PARENT,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = PERIPH_GATE_SHIFT,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gpu_pp0_nodes[] = {
+	{
+		.type = TYPE_GATE,
+		.offset = 25,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gpu_pp1_nodes[] = {
+	{
+		.type = TYPE_GATE,
+		.offset = 26,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gem_nodes[] = {
+	GENERIC_MUX,
+	{
+		.type = TYPE_DIV1,
+		.offset = 8,
+		.width = 6,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_DIV2,
+		.offset = 16,
+		.width = 6,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = 25,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gem0_tx_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 1,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = 26,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gem1_tx_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 6,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = 26,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gem2_tx_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 11,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = 26,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gem3_tx_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 16,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	{
+		.type = TYPE_GATE,
+		.offset = 26,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node gem_tsu_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 20,
+		.width = 2,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node can0_mio_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 0,
+		.width = 7,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node can1_mio_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 15,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node can0_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 7,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node can1_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 22,
+		.width = 1,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node cpu_r5_core_nodes[] = {
+	{
+		.type = TYPE_GATE,
+		.offset = 25,
+		.width = PERIPH_GATE_WIDTH,
+		.clkflags = CLK_IGNORE_UNUSED |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node dll_ref_nodes[] = {
+	{
+		.type = TYPE_MUX,
+		.offset = 0,
+		.width = 3,
+		.clkflags = CLK_SET_RATE_PARENT |
+			    CLK_SET_RATE_NO_REPARENT |
+			    CLK_IS_BASIC,
+		.typeflags = NA_TYPE_FLAGS,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+};
+
+static struct pm_clock_node timestamp_ref_nodes[] = {
+	GENERIC_MUX,
+	{
+		.type = TYPE_DIV1,
+		.offset = 8,
+		.width = 6,
+		.clkflags = CLK_IS_BASIC,
+		.typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+		.mult = NA_MULT,
+		.div = NA_DIV,
+	},
+	IGNORE_UNUSED_GATE,
+};
+
+static int32_t can_mio_parents[] = {
+	EXT_CLK_MIO0, EXT_CLK_MIO1, EXT_CLK_MIO2, EXT_CLK_MIO3,
+	EXT_CLK_MIO4, EXT_CLK_MIO5, EXT_CLK_MIO6, EXT_CLK_MIO7,
+	EXT_CLK_MIO8, EXT_CLK_MIO9, EXT_CLK_MIO10, EXT_CLK_MIO11,
+	EXT_CLK_MIO12, EXT_CLK_MIO13, EXT_CLK_MIO14, EXT_CLK_MIO15,
+	EXT_CLK_MIO16, EXT_CLK_MIO17, EXT_CLK_MIO18, EXT_CLK_MIO19,
+	EXT_CLK_MIO20, EXT_CLK_MIO21, EXT_CLK_MIO22, EXT_CLK_MIO23,
+	EXT_CLK_MIO24, EXT_CLK_MIO25, EXT_CLK_MIO26, EXT_CLK_MIO27,
+	EXT_CLK_MIO28, EXT_CLK_MIO29, EXT_CLK_MIO30, EXT_CLK_MIO31,
+	EXT_CLK_MIO32, EXT_CLK_MIO33, EXT_CLK_MIO34, EXT_CLK_MIO35,
+	EXT_CLK_MIO36, EXT_CLK_MIO37, EXT_CLK_MIO38, EXT_CLK_MIO39,
+	EXT_CLK_MIO40, EXT_CLK_MIO41, EXT_CLK_MIO42, EXT_CLK_MIO43,
+	EXT_CLK_MIO44, EXT_CLK_MIO45, EXT_CLK_MIO46, EXT_CLK_MIO47,
+	EXT_CLK_MIO48, EXT_CLK_MIO49, EXT_CLK_MIO50, EXT_CLK_MIO51,
+	EXT_CLK_MIO52, EXT_CLK_MIO53, EXT_CLK_MIO54, EXT_CLK_MIO55,
+	EXT_CLK_MIO56, EXT_CLK_MIO57, EXT_CLK_MIO58, EXT_CLK_MIO59,
+	EXT_CLK_MIO60, EXT_CLK_MIO61, EXT_CLK_MIO62, EXT_CLK_MIO63,
+	EXT_CLK_MIO64, EXT_CLK_MIO65, EXT_CLK_MIO66, EXT_CLK_MIO67,
+	EXT_CLK_MIO68, EXT_CLK_MIO69, EXT_CLK_MIO70, EXT_CLK_MIO71,
+	EXT_CLK_MIO72, EXT_CLK_MIO73, EXT_CLK_MIO74, EXT_CLK_MIO75,
+	EXT_CLK_MIO76, EXT_CLK_MIO77, CLK_NA_PARENT
+};
+
+/* Clock array containing clock informaton */
+static struct pm_clock clocks[] = {
+	[CLK_APLL_INT] = {
+		.name = "apll_int",
+		.control_reg = CRF_APB_APLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_APLL_PRE_SRC, CLK_NA_PARENT}),
+		.nodes = &ignore_unused_pll_nodes,
+		.num_nodes = ARRAY_SIZE(ignore_unused_pll_nodes),
+	},
+	[CLK_APLL_PRE_SRC] = {
+		.name = "apll_pre_src",
+		.control_reg = CRF_APB_APLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_pre_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+	},
+	[CLK_APLL_HALF] = {
+		.name = "apll_half",
+		.control_reg = CRF_APB_APLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_APLL_INT, CLK_NA_PARENT}),
+		.nodes = &generic_pll_half_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+	},
+	[CLK_APLL_INT_MUX] = {
+		.name = "apll_int_mux",
+		.control_reg = CRF_APB_APLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_APLL_INT,
+			CLK_APLL_HALF,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_int_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+	},
+	[CLK_APLL_POST_SRC] = {
+		.name = "apll_post_src",
+		.control_reg = CRF_APB_APLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_post_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+	},
+	[CLK_APLL] = {
+		.name = "apll",
+		.control_reg = CRF_APB_APLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_APLL_INT_MUX,
+			CLK_APLL_POST_SRC,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_system_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+	},
+	[CLK_DPLL_INT] = {
+		.name = "dpll_int",
+		.control_reg = CRF_APB_DPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_DPLL_PRE_SRC, CLK_NA_PARENT}),
+		.nodes = &generic_pll_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_nodes),
+	},
+	[CLK_DPLL_PRE_SRC] = {
+		.name = "dpll_pre_src",
+		.control_reg = CRF_APB_DPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_pre_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+	},
+	[CLK_DPLL_HALF] = {
+		.name = "dpll_half",
+		.control_reg = CRF_APB_DPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_DPLL_INT, CLK_NA_PARENT}),
+		.nodes = &generic_pll_half_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+	},
+	[CLK_DPLL_INT_MUX] = {
+		.name = "dpll_int_mux",
+		.control_reg = CRF_APB_DPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_DPLL_INT,
+			CLK_DPLL_HALF,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_int_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+	},
+	[CLK_DPLL_POST_SRC] = {
+		.name = "dpll_post_src",
+		.control_reg = CRF_APB_DPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_post_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+	},
+	[CLK_DPLL] = {
+		.name = "dpll",
+		.control_reg = CRF_APB_DPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_DPLL_INT_MUX,
+			CLK_DPLL_POST_SRC,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_system_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+	},
+	[CLK_VPLL_INT] = {
+		.name = "vpll_int",
+		.control_reg = CRF_APB_VPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_VPLL_PRE_SRC, CLK_NA_PARENT}),
+		.nodes = &ignore_unused_pll_nodes,
+		.num_nodes = ARRAY_SIZE(ignore_unused_pll_nodes),
+	},
+	[CLK_VPLL_PRE_SRC] = {
+		.name = "vpll_pre_src",
+		.control_reg = CRF_APB_VPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_pre_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+	},
+	[CLK_VPLL_HALF] = {
+		.name = "vpll_half",
+		.control_reg = CRF_APB_VPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_VPLL_INT, CLK_NA_PARENT}),
+		.nodes = &generic_pll_half_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+	},
+	[CLK_VPLL_INT_MUX] = {
+		.name = "vpll_int_mux",
+		.control_reg = CRF_APB_VPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_VPLL_INT,
+			CLK_VPLL_HALF,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_int_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+	},
+	[CLK_VPLL_POST_SRC] = {
+		.name = "vpll_post_src",
+		.control_reg = CRF_APB_VPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_post_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+	},
+	[CLK_VPLL] = {
+		.name = "vpll",
+		.control_reg = CRF_APB_VPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_VPLL_INT_MUX,
+			CLK_VPLL_POST_SRC,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_system_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+	},
+	[CLK_IOPLL_INT] = {
+		.name = "iopll_int",
+		.control_reg = CRL_APB_IOPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_IOPLL_PRE_SRC, CLK_NA_PARENT}),
+		.nodes = &generic_pll_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_nodes),
+	},
+	[CLK_IOPLL_PRE_SRC] = {
+		.name = "iopll_pre_src",
+		.control_reg = CRL_APB_IOPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_pre_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+	},
+	[CLK_IOPLL_HALF] = {
+		.name = "iopll_half",
+		.control_reg = CRL_APB_IOPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_IOPLL_INT, CLK_NA_PARENT}),
+		.nodes = &generic_pll_half_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+	},
+	[CLK_IOPLL_INT_MUX] = {
+		.name = "iopll_int_mux",
+		.control_reg = CRL_APB_IOPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_INT,
+			CLK_IOPLL_HALF,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_int_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+	},
+	[CLK_IOPLL_POST_SRC] = {
+		.name = "iopll_post_src",
+		.control_reg = CRL_APB_IOPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_post_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+	},
+	[CLK_IOPLL] = {
+		.name = "iopll",
+		.control_reg = CRL_APB_IOPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_INT_MUX,
+			CLK_IOPLL_POST_SRC,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_system_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+	},
+	[CLK_RPLL_INT] = {
+		.name = "rpll_int",
+		.control_reg = CRL_APB_RPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_RPLL_PRE_SRC, CLK_NA_PARENT}),
+		.nodes = &generic_pll_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_nodes),
+	},
+	[CLK_RPLL_PRE_SRC] = {
+		.name = "rpll_pre_src",
+		.control_reg = CRL_APB_RPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+
+		.nodes = &generic_pll_pre_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+	},
+	[CLK_RPLL_HALF] = {
+		.name = "rpll_half",
+		.control_reg = CRL_APB_RPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {CLK_RPLL_INT, CLK_NA_PARENT}),
+		.nodes = &generic_pll_half_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+	},
+	[CLK_RPLL_INT_MUX] = {
+		.name = "rpll_int_mux",
+		.control_reg = CRL_APB_RPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_RPLL_INT,
+			CLK_RPLL_HALF,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_int_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+	},
+	[CLK_RPLL_POST_SRC] = {
+		.name = "rpll_post_src",
+		.control_reg = CRL_APB_RPLL_CTRL,
+		.status_reg = CRF_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_post_src_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+	},
+	[CLK_RPLL] = {
+		.name = "rpll",
+		.control_reg = CRL_APB_RPLL_CTRL,
+		.status_reg = CRL_APB_PLL_STATUS,
+		.parents = &((int32_t []) {
+			CLK_RPLL_INT_MUX,
+			CLK_RPLL_POST_SRC,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_pll_system_nodes,
+		.num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+	},
+	/* Peripheral Clocks */
+	[CLK_ACPU] = {
+		.name = "acpu",
+		.control_reg = CRF_APB_ACPU_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_APLL,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_VPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &acpu_nodes,
+		.num_nodes = ARRAY_SIZE(acpu_nodes),
+	},
+	[CLK_ACPU_FULL] = {
+		.name = "acpu_full",
+		.control_reg = CRF_APB_ACPU_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_ACPU | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+			CLK_NA_PARENT
+		}),
+		.nodes = &acpu_full_nodes,
+		.num_nodes = ARRAY_SIZE(acpu_full_nodes),
+	},
+	[CLK_DBG_TRACE] = {
+		.name = "dbg_trace",
+		.control_reg = CRF_APB_DBG_TRACE_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_APLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_DBG_FPD] = {
+		.name = "dbg_fpd",
+		.control_reg = CRF_APB_DBG_FPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_APLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_DBG_TSTMP] = {
+		.name = "dbg_tstmp",
+		.control_reg = CRF_APB_DBG_TSTMP_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_APLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_nodes),
+	},
+	[CLK_DP_VIDEO_REF] = {
+		.name = "dp_video_ref",
+		.control_reg = CRF_APB_DP_VIDEO_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_VPLL,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_RPLL_TO_FPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &dp_audio_video_ref_nodes,
+		.num_nodes = ARRAY_SIZE(dp_audio_video_ref_nodes),
+	},
+	[CLK_DP_AUDIO_REF] = {
+		.name = "dp_audio_ref",
+		.control_reg = CRF_APB_DP_AUDIO_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_VPLL,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_RPLL_TO_FPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &dp_audio_video_ref_nodes,
+		.num_nodes = ARRAY_SIZE(dp_audio_video_ref_nodes),
+	},
+	[CLK_DP_STC_REF] = {
+		.name = "dp_stc_ref",
+		.control_reg = CRF_APB_DP_STC_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_VPLL,
+			CLK_DUMMY_PARENT,
+			CLK_DPLL,
+			CLK_RPLL_TO_FPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_DPDMA_REF] = {
+		.name = "dpdma_ref",
+		.control_reg = CRF_APB_DPDMA_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_APLL,
+			CLK_DUMMY_PARENT,
+			CLK_VPLL,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_DDR_REF] = {
+		.name = "ddr_ref",
+		.control_reg = CRF_APB_DDR_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_DPLL,
+			CLK_VPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &ddr_nodes,
+		.num_nodes = ARRAY_SIZE(ddr_nodes),
+	},
+	[CLK_GPU_REF] = {
+		.name = "gpu_ref",
+		.control_reg = CRF_APB_GPU_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_VPLL,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_SATA_REF] = {
+		.name = "sata_ref",
+		.control_reg = CRF_APB_SATA_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_APLL,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_PCIE_REF] = {
+		.name = "pcie_ref",
+		.control_reg = CRF_APB_PCIE_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL_TO_FPD,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_GDMA_REF] = {
+		.name = "gdma_ref",
+		.control_reg = CRF_APB_GDMA_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_APLL,
+			CLK_DUMMY_PARENT,
+			CLK_VPLL,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_GTGREF0_REF] = {
+		.name = "gtgref0_ref",
+		.control_reg = CRF_APB_GTGREF0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL_TO_FPD,
+			CLK_DUMMY_PARENT,
+			CLK_APLL,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_TOPSW_MAIN] = {
+		.name = "topsw_main",
+		.control_reg = CRF_APB_TOPSW_MAIN_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_APLL,
+			CLK_DUMMY_PARENT,
+			CLK_VPLL,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_unused_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+	},
+	[CLK_TOPSW_LSBUS] = {
+		.name = "topsw_lsbus",
+		.control_reg = CRF_APB_TOPSW_LSBUS_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_APLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL_TO_FPD,
+			CLK_DPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_unused_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+	},
+	[CLK_IOU_SWITCH] = {
+		.name = "iou_switch",
+		.control_reg = CRL_APB_IOU_SWITCH_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_unused_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+	},
+	[CLK_GEM0_REF] = {
+		.name = "gem0_ref",
+		.control_reg = CRL_APB_GEM0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem_nodes,
+		.num_nodes = ARRAY_SIZE(gem_nodes),
+	},
+	[CLK_GEM1_REF] = {
+		.name = "gem1_ref",
+		.control_reg = CRL_APB_GEM1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem_nodes,
+		.num_nodes = ARRAY_SIZE(gem_nodes),
+	},
+	[CLK_GEM2_REF] = {
+		.name = "gem2_ref",
+		.control_reg = CRL_APB_GEM2_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem_nodes,
+		.num_nodes = ARRAY_SIZE(gem_nodes),
+	},
+	[CLK_GEM3_REF] = {
+		.name = "gem3_ref",
+		.control_reg = CRL_APB_GEM3_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem_nodes,
+		.num_nodes = ARRAY_SIZE(gem_nodes),
+	},
+	[CLK_USB0_BUS_REF] = {
+		.name = "usb0_bus_ref",
+		.control_reg = CRL_APB_USB0_BUS_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &usb_nodes,
+		.num_nodes = ARRAY_SIZE(usb_nodes),
+	},
+	[CLK_USB1_BUS_REF] = {
+		.name = "usb1_bus_ref",
+		.control_reg = CRL_APB_USB1_BUS_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &usb_nodes,
+		.num_nodes = ARRAY_SIZE(usb_nodes),
+	},
+	[CLK_USB3_DUAL_REF] = {
+		.name = "usb3_dual_ref",
+		.control_reg = CRL_APB_USB3_DUAL_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &usb_nodes,
+		.num_nodes = ARRAY_SIZE(usb_nodes),
+	},
+	[CLK_QSPI_REF] = {
+		.name = "qspi_ref",
+		.control_reg = CRL_APB_QSPI_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_SDIO0_REF] = {
+		.name = "sdio0_ref",
+		.control_reg = CRL_APB_SDIO0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_VPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_SDIO1_REF] = {
+		.name = "sdio1_ref",
+		.control_reg = CRL_APB_SDIO1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_VPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_UART0_REF] = {
+		.name = "uart0_ref",
+		.control_reg = CRL_APB_UART0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_UART1_REF] = {
+		.name = "uart1_ref",
+		.control_reg = CRL_APB_UART1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_SPI0_REF] = {
+		.name = "spi0_ref",
+		.control_reg = CRL_APB_SPI0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_SPI1_REF] = {
+		.name = "spi1_ref",
+		.control_reg = CRL_APB_SPI1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_CAN0_REF] = {
+		.name = "can0_ref",
+		.control_reg = CRL_APB_CAN0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_CAN1_REF] = {
+		.name = "can1_ref",
+		.control_reg = CRL_APB_CAN1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_NAND_REF] = {
+		.name = "nand_ref",
+		.control_reg = CRL_APB_NAND_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_GEM_TSU_REF] = {
+		.name = "gem_tsu_ref",
+		.control_reg = CRL_APB_GEM_TSU_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_DLL_REF] = {
+		.name = "dll_ref",
+		.control_reg = CRL_APB_DLL_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_RPLL,
+			CLK_NA_PARENT
+		}),
+		.nodes = &dll_ref_nodes,
+		.num_nodes = ARRAY_SIZE(dll_ref_nodes),
+	},
+	[CLK_ADMA_REF] = {
+		.name = "adma_ref",
+		.control_reg = CRL_APB_ADMA_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_DBG_LPD] = {
+		.name = "dbg_lpd",
+		.control_reg = CRL_APB_DBG_LPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_CPU_R5] = {
+		.name = "cpu_r5",
+		.control_reg = CRL_APB_CPU_R5_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_unused_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+	},
+	[CLK_CSU_PLL] = {
+		.name = "csu_pll",
+		.control_reg = CRL_APB_CSU_PLL_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_PCAP] = {
+		.name = "pcap",
+		.control_reg = CRL_APB_PCAP_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+	},
+	[CLK_LPD_LSBUS] = {
+		.name = "lpd_lsbus",
+		.control_reg = CRL_APB_LPD_LSBUS_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_unused_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+	},
+	[CLK_LPD_SWITCH] = {
+		.name = "lpd_switch",
+		.control_reg = CRL_APB_LPD_SWITCH_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_unused_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+	},
+	[CLK_I2C0_REF] = {
+		.name = "i2c0_ref",
+		.control_reg = CRL_APB_I2C0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_I2C1_REF] = {
+		.name = "i2c1_ref",
+		.control_reg = CRL_APB_I2C1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_TIMESTAMP_REF] = {
+		.name = "timestamp_ref",
+		.control_reg = CRL_APB_TIMESTAMP_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &timestamp_ref_nodes,
+		.num_nodes = ARRAY_SIZE(timestamp_ref_nodes),
+	},
+	[CLK_PL0_REF] = {
+		.name = "pl0_ref",
+		.control_reg = CRL_APB_PL0_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &pl_nodes,
+		.num_nodes = ARRAY_SIZE(pl_nodes),
+	},
+	[CLK_PL1_REF] = {
+		.name = "pl1_ref",
+		.control_reg = CRL_APB_PL1_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &pl_nodes,
+		.num_nodes = ARRAY_SIZE(pl_nodes),
+	},
+	[CLK_PL2_REF] = {
+		.name = "pl2_ref",
+		.control_reg = CRL_APB_PL2_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &pl_nodes,
+		.num_nodes = ARRAY_SIZE(pl_nodes),
+	},
+	[CLK_PL3_REF] = {
+		.name = "pl3_ref",
+		.control_reg = CRL_APB_PL3_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_IOPLL,
+			CLK_DUMMY_PARENT,
+			CLK_RPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &pl_nodes,
+		.num_nodes = ARRAY_SIZE(pl_nodes),
+	},
+	[CLK_AMS_REF] = {
+		.name = "ams_ref",
+		.control_reg = CRL_APB_AMS_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_RPLL,
+			CLK_DUMMY_PARENT,
+			CLK_IOPLL,
+			CLK_DPLL_TO_LPD,
+			CLK_NA_PARENT
+		}),
+		.nodes = &generic_mux_div_div_gate_nodes,
+		.num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+	},
+	[CLK_IOPLL_TO_FPD] = {
+		.name = "iopll_to_fpd",
+		.control_reg = CRL_APB_IOPLL_TO_FPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {CLK_IOPLL, CLK_NA_PARENT}),
+		.nodes = &generic_domain_crossing_nodes,
+		.num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+	},
+	[CLK_RPLL_TO_FPD] = {
+		.name = "rpll_to_fpd",
+		.control_reg = CRL_APB_RPLL_TO_FPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {CLK_RPLL, CLK_NA_PARENT}),
+		.nodes = &rpll_to_fpd_nodes,
+		.num_nodes = ARRAY_SIZE(rpll_to_fpd_nodes),
+	},
+	[CLK_APLL_TO_LPD] = {
+		.name = "apll_to_lpd",
+		.control_reg = CRF_APB_APLL_TO_LPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {CLK_APLL, CLK_NA_PARENT}),
+		.nodes = &generic_domain_crossing_nodes,
+		.num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+	},
+	[CLK_DPLL_TO_LPD] = {
+		.name = "dpll_to_lpd",
+		.control_reg = CRF_APB_DPLL_TO_LPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {CLK_DPLL, CLK_NA_PARENT}),
+		.nodes = &generic_domain_crossing_nodes,
+		.num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+	},
+	[CLK_VPLL_TO_LPD] = {
+		.name = "vpll_to_lpd",
+		.control_reg = CRF_APB_VPLL_TO_LPD_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {CLK_VPLL, CLK_NA_PARENT}),
+		.nodes = &generic_domain_crossing_nodes,
+		.num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+	},
+	/*
+	 * This clock control requires different registers for mux and gate.
+	 * Use control and status registers for the same.
+	 */
+	[CLK_GEM0_TX] = {
+		.name = "gem0_tx",
+		.control_reg = IOU_SLCR_GEM_CLK_CTRL,
+		.status_reg = CRL_APB_GEM0_REF_CTRL,
+		.parents = &((int32_t []) {
+			CLK_GEM0_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+			EXT_CLK_GEM0_EMIO | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem0_tx_nodes,
+		.num_nodes = ARRAY_SIZE(gem0_tx_nodes),
+	},
+	/*
+	 * This clock control requires different registers for mux and gate.
+	 * Use control and status registers for the same.
+	 */
+	[CLK_GEM1_TX] = {
+		.name = "gem1_tx",
+		.control_reg = IOU_SLCR_GEM_CLK_CTRL,
+		.status_reg = CRL_APB_GEM1_REF_CTRL,
+		.parents = &((int32_t []) {
+			CLK_GEM1_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+			EXT_CLK_GEM1_EMIO | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem1_tx_nodes,
+		.num_nodes = ARRAY_SIZE(gem1_tx_nodes),
+	},
+	/*
+	 * This clock control requires different registers for mux and gate.
+	 * Use control and status registers for the same.
+	 */
+	[CLK_GEM2_TX] = {
+		.name = "gem2_tx",
+		.control_reg = IOU_SLCR_GEM_CLK_CTRL,
+		.status_reg = CRL_APB_GEM2_REF_CTRL,
+		.parents = &((int32_t []) {
+			CLK_GEM2_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+			EXT_CLK_GEM2_EMIO | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem2_tx_nodes,
+		.num_nodes = ARRAY_SIZE(gem2_tx_nodes),
+	},
+	/*
+	 * This clock control requires different registers for mux and gate.
+	 * Use control and status registers for the same.
+	 */
+	[CLK_GEM3_TX] = {
+		.name = "gem3_tx",
+		.control_reg = IOU_SLCR_GEM_CLK_CTRL,
+		.status_reg = CRL_APB_GEM3_REF_CTRL,
+		.parents = &((int32_t []) {
+			CLK_GEM3_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+			EXT_CLK_GEM3_EMIO | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem3_tx_nodes,
+		.num_nodes = ARRAY_SIZE(gem3_tx_nodes),
+	},
+	[CLK_ACPU_HALF] = {
+		.name = "acpu_half",
+		.control_reg = CRF_APB_ACPU_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_ACPU | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+			CLK_NA_PARENT
+		}),
+		.nodes = &acpu_half_nodes,
+		.num_nodes = ARRAY_SIZE(acpu_half_nodes),
+	},
+	[CLK_WDT] = {
+		.name = "wdt",
+		.control_reg = FPD_SLCR_WDT_CLK_SEL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_TOPSW_LSBUS,
+			EXT_CLK_SWDT0 | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &wdt_nodes,
+		.num_nodes = ARRAY_SIZE(wdt_nodes),
+	},
+	[CLK_GPU_PP0_REF] = {
+		.name = "gpu_pp0_ref",
+		.control_reg = CRF_APB_GPU_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_GPU_REF | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gpu_pp0_nodes,
+		.num_nodes = ARRAY_SIZE(gpu_pp0_nodes),
+	},
+	[CLK_GPU_PP1_REF] = {
+		.name = "gpu_pp1_ref",
+		.control_reg = CRF_APB_GPU_REF_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_GPU_REF | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gpu_pp1_nodes,
+		.num_nodes = ARRAY_SIZE(gpu_pp1_nodes),
+	},
+	[CLK_GEM_TSU] = {
+		.name = "gem_tsu",
+		.control_reg = IOU_SLCR_GEM_CLK_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_GEM_TSU_REF,
+			CLK_GEM_TSU_REF,
+			EXT_CLK_MIO26 | CLK_EXTERNAL_PARENT,
+			EXT_CLK_MIO50_OR_MIO51 | CLK_EXTERNAL_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &gem_tsu_nodes,
+		.num_nodes = ARRAY_SIZE(gem_tsu_nodes),
+	},
+	[CLK_CPU_R5_CORE] = {
+		.name = "cpu_r5_core",
+		.control_reg = CRL_APB_CPU_R5_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_CPU_R5 | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+			CLK_DUMMY_PARENT,
+			CLK_NA_PARENT
+		}),
+		.nodes = &cpu_r5_core_nodes,
+		.num_nodes = ARRAY_SIZE(cpu_r5_core_nodes),
+	},
+	[CLK_CAN0_MIO] = {
+		.name = "can0_mio",
+		.control_reg = IOU_SLCR_CAN_MIO_CTRL,
+		.status_reg = 0,
+		.parents = &can_mio_parents,
+		.nodes = &can0_mio_nodes,
+		.num_nodes = ARRAY_SIZE(can0_mio_nodes),
+	},
+	[CLK_CAN1_MIO] = {
+		.name = "can1_mio",
+		.control_reg = IOU_SLCR_CAN_MIO_CTRL,
+		.status_reg = 0,
+		.parents = &can_mio_parents,
+		.nodes = &can1_mio_nodes,
+		.num_nodes = ARRAY_SIZE(can1_mio_nodes),
+	},
+	[CLK_CAN0] = {
+		.name = "can0",
+		.control_reg = IOU_SLCR_CAN_MIO_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_CAN0_REF,
+			CLK_CAN0_MIO,
+			CLK_NA_PARENT
+		}),
+		.nodes = &can0_nodes,
+		.num_nodes = ARRAY_SIZE(can0_nodes),
+	},
+	[CLK_CAN1] = {
+		.name = "can1",
+		.control_reg = IOU_SLCR_CAN_MIO_CTRL,
+		.status_reg = 0,
+		.parents = &((int32_t []) {
+			CLK_CAN1_REF,
+			CLK_CAN1_MIO,
+			CLK_NA_PARENT
+		}),
+		.nodes = &can1_nodes,
+		.num_nodes = ARRAY_SIZE(can1_nodes),
+	},
+};
+
+static struct pm_ext_clock ext_clocks[] = {
+	[EXT_CLK_INDEX(EXT_CLK_PSS_REF)] = {
+		.name = "pss_ref_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_VIDEO)] = {
+		.name = "video_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_PSS_ALT_REF)] = {
+		.name = "pss_alt_ref_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_AUX_REF)] = {
+		.name = "aux_ref_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_GT_CRX_REF)] = {
+		.name = "video_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_SWDT0)] = {
+		.name = "swdt0_ext_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_SWDT1)] = {
+		.name = "swdt1_ext_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_GEM0_EMIO)] = {
+		.name = "gem0_emio_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_GEM1_EMIO)] = {
+		.name = "gem1_emio_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_GEM2_EMIO)] = {
+		.name = "gem2_emio_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_GEM3_EMIO)] = {
+		.name = "gem3_emio_clk",
+	},
+	[EXT_CLK_INDEX(EXT_CLK_MIO50_OR_MIO51)] = {
+		.name = "mio_clk_50_51",
+	},
+	EXT_CLK_MIO_DATA(0),
+	EXT_CLK_MIO_DATA(1),
+	EXT_CLK_MIO_DATA(2),
+	EXT_CLK_MIO_DATA(3),
+	EXT_CLK_MIO_DATA(4),
+	EXT_CLK_MIO_DATA(5),
+	EXT_CLK_MIO_DATA(6),
+	EXT_CLK_MIO_DATA(7),
+	EXT_CLK_MIO_DATA(8),
+	EXT_CLK_MIO_DATA(9),
+	EXT_CLK_MIO_DATA(10),
+	EXT_CLK_MIO_DATA(11),
+	EXT_CLK_MIO_DATA(12),
+	EXT_CLK_MIO_DATA(13),
+	EXT_CLK_MIO_DATA(14),
+	EXT_CLK_MIO_DATA(15),
+	EXT_CLK_MIO_DATA(16),
+	EXT_CLK_MIO_DATA(17),
+	EXT_CLK_MIO_DATA(18),
+	EXT_CLK_MIO_DATA(19),
+	EXT_CLK_MIO_DATA(20),
+	EXT_CLK_MIO_DATA(21),
+	EXT_CLK_MIO_DATA(22),
+	EXT_CLK_MIO_DATA(23),
+	EXT_CLK_MIO_DATA(24),
+	EXT_CLK_MIO_DATA(25),
+	EXT_CLK_MIO_DATA(26),
+	EXT_CLK_MIO_DATA(27),
+	EXT_CLK_MIO_DATA(28),
+	EXT_CLK_MIO_DATA(29),
+	EXT_CLK_MIO_DATA(30),
+	EXT_CLK_MIO_DATA(31),
+	EXT_CLK_MIO_DATA(32),
+	EXT_CLK_MIO_DATA(33),
+	EXT_CLK_MIO_DATA(34),
+	EXT_CLK_MIO_DATA(35),
+	EXT_CLK_MIO_DATA(36),
+	EXT_CLK_MIO_DATA(37),
+	EXT_CLK_MIO_DATA(38),
+	EXT_CLK_MIO_DATA(39),
+	EXT_CLK_MIO_DATA(40),
+	EXT_CLK_MIO_DATA(41),
+	EXT_CLK_MIO_DATA(42),
+	EXT_CLK_MIO_DATA(43),
+	EXT_CLK_MIO_DATA(44),
+	EXT_CLK_MIO_DATA(45),
+	EXT_CLK_MIO_DATA(46),
+	EXT_CLK_MIO_DATA(47),
+	EXT_CLK_MIO_DATA(48),
+	EXT_CLK_MIO_DATA(49),
+	EXT_CLK_MIO_DATA(50),
+	EXT_CLK_MIO_DATA(51),
+	EXT_CLK_MIO_DATA(52),
+	EXT_CLK_MIO_DATA(53),
+	EXT_CLK_MIO_DATA(54),
+	EXT_CLK_MIO_DATA(55),
+	EXT_CLK_MIO_DATA(56),
+	EXT_CLK_MIO_DATA(57),
+	EXT_CLK_MIO_DATA(58),
+	EXT_CLK_MIO_DATA(59),
+	EXT_CLK_MIO_DATA(60),
+	EXT_CLK_MIO_DATA(61),
+	EXT_CLK_MIO_DATA(62),
+	EXT_CLK_MIO_DATA(63),
+	EXT_CLK_MIO_DATA(64),
+	EXT_CLK_MIO_DATA(65),
+	EXT_CLK_MIO_DATA(66),
+	EXT_CLK_MIO_DATA(67),
+	EXT_CLK_MIO_DATA(68),
+	EXT_CLK_MIO_DATA(69),
+	EXT_CLK_MIO_DATA(70),
+	EXT_CLK_MIO_DATA(71),
+	EXT_CLK_MIO_DATA(72),
+	EXT_CLK_MIO_DATA(73),
+	EXT_CLK_MIO_DATA(74),
+	EXT_CLK_MIO_DATA(75),
+	EXT_CLK_MIO_DATA(76),
+	EXT_CLK_MIO_DATA(77),
+};
+
+/* Array of clock which are invalid for this variant */
+static uint32_t pm_clk_invalid_list[] = {CLK_USB0, CLK_USB1, CLK_CSU_SPB,
+	CLK_ACPU_FULL,
+	CLK_ACPU_HALF,
+	CLK_APLL_TO_LPD,
+	CLK_DBG_FPD,
+	CLK_DBG_LPD,
+	CLK_DBG_TRACE,
+	CLK_DBG_TSTMP,
+	CLK_DDR_REF,
+	CLK_TOPSW_MAIN,
+	CLK_TOPSW_LSBUS,
+	CLK_GTGREF0_REF,
+	CLK_LPD_SWITCH,
+	CLK_LPD_LSBUS,
+	CLK_CPU_R5,
+	CLK_CPU_R5_CORE,
+	CLK_CSU_SPB,
+	CLK_CSU_PLL,
+	CLK_PCAP,
+	CLK_IOU_SWITCH,
+	CLK_DLL_REF,
+	CLK_TIMESTAMP_REF,
+};
+
+/**
+ * pm_clock_valid - Check if clock is valid or not
+ * @clock_id	Id of the clock to be queried
+ *
+ * This function is used to check if given clock is valid
+ * or not for the chip variant.
+ *
+ * List of invalid clocks are maintained in array list for
+ * different variants.
+ *
+ * Return: Returns 1 if clock is valid else 0.
+ */
+static bool pm_clock_valid(unsigned int clock_id)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(pm_clk_invalid_list); i++)
+		if (pm_clk_invalid_list[i] == clock_id)
+			return 0;
+
+	return 1;
+}
+
+/**
+ * pm_clock_type - Get clock's type
+ * @clock_id	Id of the clock to be queried
+ *
+ * This function is used to check type of clock (OUTPUT/EXTERNAL).
+ *
+ * Return: Returns type of clock (OUTPUT/EXTERNAL).
+ */
+static unsigned int pm_clock_type(unsigned int clock_id)
+{
+	return (clock_id < CLK_MAX_OUTPUT_CLK) ?
+		CLK_TYPE_OUTPUT : CLK_TYPE_EXTERNAL;
+}
+
+/**
+ * pm_api_clock_get_num_clocks() - PM call to request number of clocks
+ * @nclocks	Number of clocks
+ *
+ * This function is used by master to get number of clocks.
+ *
+ * @return	Returns success.
+ */
+enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks)
+{
+	*nclocks = CLK_MAX;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_name() - PM call to request a clock's name
+ * @clock_id	Clock ID
+ * @name	Name of clock (max 16 bytes)
+ *
+ * This function is used by master to get nmae of clock specified
+ * by given clock ID.
+ *
+ * @return	Returns success. In case of error, name data is 0.
+ */
+enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name)
+{
+	if (clock_id == CLK_MAX)
+		memcpy(name, END_OF_CLK, CLK_NAME_LEN);
+	else if (!pm_clock_valid(clock_id))
+		memset(name, 0, CLK_NAME_LEN);
+	else if (clock_id < CLK_MAX_OUTPUT_CLK)
+		memcpy(name, clocks[clock_id].name, CLK_NAME_LEN);
+	else
+		memcpy(name, ext_clocks[clock_id - CLK_MAX_OUTPUT_CLK].name,
+		       CLK_NAME_LEN);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_topology() - PM call to request a clock's topology
+ * @clock_id	Clock ID
+ * @index	Topology index for next toplogy node
+ * @topology	Buffer to store nodes in topology and flags
+ *
+ * This function is used by master to get topology information for the
+ * clock specified by given clock ID. Each response would return 3
+ * topology nodes. To get next nodes, caller needs to call this API with
+ * index of next node. Index starts from 0.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id,
+					     unsigned int index,
+					     uint32_t *topology)
+{
+	struct pm_clock_node *clock_nodes;
+	uint8_t num_nodes;
+	unsigned int i;
+
+	if (!pm_clock_valid(clock_id))
+		return PM_RET_ERROR_ARGS;
+
+	if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+
+	memset(topology, 0, CLK_TOPOLOGY_PAYLOAD_LEN);
+	clock_nodes = *clocks[clock_id].nodes;
+	num_nodes = clocks[clock_id].num_nodes;
+
+	/* Skip parent till index */
+	if (index >= num_nodes)
+		return PM_RET_SUCCESS;
+
+	for (i = 0; i < 3U; i++) {
+		if ((index + i) == num_nodes)
+			break;
+		topology[i] =  clock_nodes[index + i].type;
+		topology[i] |= clock_nodes[index + i].clkflags <<
+					CLK_CLKFLAGS_SHIFT;
+		topology[i] |= clock_nodes[index + i].typeflags <<
+					CLK_TYPEFLAGS_SHIFT;
+	}
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_fixedfactor_params() - PM call to request a clock's fixed
+ *					   factor parameters for fixed clock
+ * @clock_id	Clock ID
+ * @mul		Multiplication value
+ * @div		Divisor value
+ *
+ * This function is used by master to get fixed factor parameers for the
+ * fixed clock. This API is application only for the fixed clock.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_fixedfactor_params(unsigned int clock_id,
+						       uint32_t *mul,
+						       uint32_t *div)
+{
+	struct pm_clock_node *clock_nodes;
+	uint8_t num_nodes;
+	unsigned int type, i;
+
+	if (!pm_clock_valid(clock_id))
+		return PM_RET_ERROR_ARGS;
+
+	if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	clock_nodes = *clocks[clock_id].nodes;
+	num_nodes = clocks[clock_id].num_nodes;
+
+	for (i = 0; i < num_nodes; i++) {
+		type =  clock_nodes[i].type;
+		if (type == TYPE_FIXEDFACTOR) {
+			*mul = clock_nodes[i].mult;
+			*div = clock_nodes[i].div;
+			break;
+		}
+	}
+
+	/* Clock is not fixed clock */
+	if (i == num_nodes)
+		return PM_RET_ERROR_ARGS;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_parents() - PM call to request a clock's first 3 parents
+ * @clock_id	Clock ID
+ * @index	Index of next parent
+ * @parents	Parents of the given clock
+ *
+ * This function is used by master to get clock's parents information.
+ * This API will return 3 parents with a single response. To get other
+ * parents, master should call same API in loop with new parent index
+ * till error is returned.
+ *
+ * E.g First call should have index 0 which will return parents 0, 1 and
+ * 2. Next call, index should be 3 which will return parent 3,4 and 5 and
+ * so on.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_parents(unsigned int clock_id,
+					    unsigned int index,
+					    uint32_t *parents)
+{
+	unsigned int i;
+	int32_t *clk_parents;
+
+	if (!pm_clock_valid(clock_id))
+		return PM_RET_ERROR_ARGS;
+
+	if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	clk_parents = *clocks[clock_id].parents;
+	if (clk_parents == NULL)
+		return PM_RET_ERROR_ARGS;
+
+	memset(parents, 0, CLK_PARENTS_PAYLOAD_LEN);
+
+	/* Skip parent till index */
+	for (i = 0; i < index; i++)
+		if (clk_parents[i] == CLK_NA_PARENT)
+			return PM_RET_SUCCESS;
+
+	for (i = 0; i < 3; i++) {
+		parents[i] = clk_parents[index + i];
+		if (clk_parents[index + i] == CLK_NA_PARENT)
+			break;
+	}
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_attributes() - PM call to request a clock's attributes
+ * @clock_id	Clock ID
+ * @attr	Clock attributes
+ *
+ * This function is used by master to get clock's attributes
+ * (e.g. valid, clock type, etc).
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_attributes(unsigned int clock_id,
+					       uint32_t *attr)
+{
+	if (clock_id >= CLK_MAX)
+		return PM_RET_ERROR_ARGS;
+
+	/* Clock valid bit */
+	*attr = pm_clock_valid(clock_id);
+
+	/* Clock type (Output/External) */
+	*attr |= (pm_clock_type(clock_id) << CLK_TYPE_SHIFT);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * struct pm_pll - PLL related data required to map IOCTL-based PLL control
+ * implemented by linux to system-level EEMI APIs
+ * @nid:	PLL node ID
+ * @cid:	PLL clock ID
+ * @pre_src:	Pre-source PLL clock ID
+ * @post_src:	Post-source PLL clock ID
+ * @div2:	DIV2 PLL clock ID
+ * @bypass:	PLL output clock ID that maps to bypass select output
+ * @mode:	PLL mode currently set via IOCTL (PLL_FRAC_MODE/PLL_INT_MODE)
+ */
+struct pm_pll {
+	const enum pm_node_id nid;
+	const enum clock_id cid;
+	const enum clock_id pre_src;
+	const enum clock_id post_src;
+	const enum clock_id div2;
+	const enum clock_id bypass;
+	uint8_t mode;
+};
+
+static struct pm_pll pm_plls[] = {
+	{
+		.nid = NODE_IOPLL,
+		.cid = CLK_IOPLL_INT,
+		.pre_src = CLK_IOPLL_PRE_SRC,
+		.post_src = CLK_IOPLL_POST_SRC,
+		.div2 = CLK_IOPLL_INT_MUX,
+		.bypass = CLK_IOPLL,
+	}, {
+		.nid = NODE_RPLL,
+		.cid = CLK_RPLL_INT,
+		.pre_src = CLK_RPLL_PRE_SRC,
+		.post_src = CLK_RPLL_POST_SRC,
+		.div2 = CLK_RPLL_INT_MUX,
+		.bypass = CLK_RPLL,
+	}, {
+		.nid = NODE_APLL,
+		.cid = CLK_APLL_INT,
+		.pre_src = CLK_APLL_PRE_SRC,
+		.post_src = CLK_APLL_POST_SRC,
+		.div2 = CLK_APLL_INT_MUX,
+		.bypass = CLK_APLL,
+	}, {
+		.nid = NODE_VPLL,
+		.cid = CLK_VPLL_INT,
+		.pre_src = CLK_VPLL_PRE_SRC,
+		.post_src = CLK_VPLL_POST_SRC,
+		.div2 = CLK_VPLL_INT_MUX,
+		.bypass = CLK_VPLL,
+	}, {
+		.nid = NODE_DPLL,
+		.cid = CLK_DPLL_INT,
+		.pre_src = CLK_DPLL_PRE_SRC,
+		.post_src = CLK_DPLL_POST_SRC,
+		.div2 = CLK_DPLL_INT_MUX,
+		.bypass = CLK_DPLL,
+	},
+};
+
+/**
+ * pm_clock_get_pll() - Get PLL structure by PLL clock ID
+ * @clock_id	Clock ID of the target PLL
+ *
+ * @return	Pointer to PLL structure if found, NULL otherwise
+ */
+struct pm_pll *pm_clock_get_pll(enum clock_id clock_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(pm_plls); i++) {
+		if (pm_plls[i].cid == clock_id)
+			return &pm_plls[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * pm_clock_get_pll_node_id() - Get PLL node ID by PLL clock ID
+ * @clock_id	Clock ID of the target PLL
+ * @node_id	Location to store node ID of the target PLL
+ *
+ * @return	PM_RET_SUCCESS if node ID is found, PM_RET_ERROR_ARGS otherwise
+ */
+enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
+					    enum pm_node_id *node_id)
+{
+	struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+	if (pll) {
+		*node_id = pll->nid;
+		return PM_RET_SUCCESS;
+	}
+
+	return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * pm_clock_get_pll_by_related_clk() - Get PLL structure by PLL-related clock ID
+ * @clock_id	Clock ID
+ *
+ * @return	Pointer to PLL structure if found, NULL otherwise
+ */
+struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id)
+{
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(pm_plls); i++) {
+		if (pm_plls[i].pre_src == clock_id ||
+		    pm_plls[i].post_src == clock_id ||
+		    pm_plls[i].div2 == clock_id ||
+		    pm_plls[i].bypass == clock_id) {
+			return &pm_plls[i];
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * pm_clock_pll_enable() - "Enable" the PLL clock (lock the PLL)
+ * @pll: PLL to be locked
+ *
+ * This function is used to map IOCTL/linux-based PLL handling to system-level
+ * EEMI APIs
+ *
+ * Return: Error if the argument is not valid or status as returned by PMU
+ */
+enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll)
+{
+	if (!pll)
+		return PM_RET_ERROR_ARGS;
+
+	/* Set the PLL mode according to the buffered mode value */
+	if (pll->mode == PLL_FRAC_MODE)
+		return pm_pll_set_mode(pll->nid, PM_PLL_MODE_FRACTIONAL);
+
+	return pm_pll_set_mode(pll->nid, PM_PLL_MODE_INTEGER);
+}
+
+/**
+ * pm_clock_pll_disable - "Disable" the PLL clock (bypass/reset the PLL)
+ * @pll		PLL to be bypassed/reset
+ *
+ * This function is used to map IOCTL/linux-based PLL handling to system-level
+ * EEMI APIs
+ *
+ * Return: Error if the argument is not valid or status as returned by PMU
+ */
+enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll)
+{
+	if (!pll)
+		return PM_RET_ERROR_ARGS;
+
+	return pm_pll_set_mode(pll->nid, PM_PLL_MODE_RESET);
+}
+
+/**
+ * pm_clock_pll_get_state - Get state of the PLL
+ * @pll		Pointer to the target PLL structure
+ * @state	Location to store the state: 1/0 ("Enabled"/"Disabled")
+ *
+ * "Enable" actually means that the PLL is locked and its bypass is deasserted,
+ * "Disable" means that it is bypassed.
+ *
+ * Return: PM_RET_ERROR_ARGS error if the argument is not valid, success if
+ * returned state value is valid or an error if returned by PMU
+ */
+enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll,
+					  unsigned int *state)
+{
+	enum pm_ret_status status;
+	enum pm_pll_mode mode;
+
+	if (!pll || !state)
+		return PM_RET_ERROR_ARGS;
+
+	status = pm_pll_get_mode(pll->nid, &mode);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	if (mode == PM_PLL_MODE_RESET)
+		*state = 0;
+	else
+		*state = 1;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_pll_set_parent - Set the clock parent for PLL-related clock id
+ * @pll			Target PLL structure
+ * @clock_id		Id of the clock
+ * @parent_index	parent index (=mux select value)
+ *
+ * The whole clock-tree implementation relies on the fact that parent indexes
+ * match to the multiplexer select values. This function has to rely on that
+ * assumption as well => parent_index is actually the mux select value.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll,
+					   enum clock_id clock_id,
+					   unsigned int parent_index)
+{
+	if (!pll)
+		return PM_RET_ERROR_ARGS;
+	if (pll->pre_src == clock_id)
+		return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_PRE_SRC,
+					    parent_index);
+	if (pll->post_src == clock_id)
+		return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_POST_SRC,
+					    parent_index);
+	if (pll->div2 == clock_id)
+		return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_DIV2,
+					    parent_index);
+
+	return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * pm_clock_pll_get_parent - Get mux select value of PLL-related clock parent
+ * @pll			Target PLL structure
+ * @clock_id		Id of the clock
+ * @parent_index	parent index (=mux select value)
+ *
+ * This function is used by master to get parent index for PLL-related clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll,
+					   enum clock_id clock_id,
+					   unsigned int *parent_index)
+{
+	if (!pll)
+		return PM_RET_ERROR_ARGS;
+	if (pll->pre_src == clock_id)
+		return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_PRE_SRC,
+					    parent_index);
+	if (pll->post_src == clock_id)
+		return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_POST_SRC,
+					    parent_index);
+	if (pll->div2 == clock_id)
+		return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_DIV2,
+					    parent_index);
+	if (pll->bypass == clock_id) {
+		*parent_index = 0;
+		return PM_RET_SUCCESS;
+	}
+
+	return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * pm_clock_set_pll_mode() -  Set PLL mode
+ * @clock_id	PLL clock id
+ * @mode	Mode fractional/integer
+ *
+ * This function buffers/saves the PLL mode that is set.
+ *
+ * @return      Success if mode is buffered or error if an argument is invalid
+ */
+enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id,
+					 unsigned int mode)
+{
+	struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+	if (!pll || (mode != PLL_FRAC_MODE && mode != PLL_INT_MODE))
+		return PM_RET_ERROR_ARGS;
+	pll->mode = mode;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_get_pll_mode() -  Get PLL mode
+ * @clock_id	PLL clock id
+ * @mode	Location to store the mode (fractional/integer)
+ *
+ * This function returns buffered PLL mode.
+ *
+ * @return      Success if mode is stored or error if an argument is invalid
+ */
+enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id,
+					 unsigned int *mode)
+{
+	struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+	if (!pll || !mode)
+		return PM_RET_ERROR_ARGS;
+	*mode = pll->mode;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_id_is_valid() -  Check if given clock ID is valid
+ * @clock_id   ID of the clock to be checked
+ *
+ * @return     Returns success if clock_id is valid, otherwise an error
+ */
+enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id)
+{
+	if (!pm_clock_valid(clock_id))
+		return PM_RET_ERROR_ARGS;
+
+	if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_has_div() - Check if the clock has divider with given ID
+ * @clock_id	Clock ID
+ * @div_id	Divider ID
+ *
+ * @return	True(1)=clock has the divider, false(0)=otherwise
+ */
+uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id)
+{
+	uint32_t i;
+	struct pm_clock_node *nodes;
+
+	if (clock_id >= CLK_MAX_OUTPUT_CLK)
+		return 0;
+
+	nodes = *clocks[clock_id].nodes;
+	for (i = 0; i < clocks[clock_id].num_nodes; i++) {
+		if (nodes[i].type == TYPE_DIV1) {
+			if (div_id == PM_CLOCK_DIV0_ID)
+				return 1;
+		} else if (nodes[i].type == TYPE_DIV2) {
+			if (div_id == PM_CLOCK_DIV1_ID)
+				return 1;
+		}
+	}
+
+	return 0;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
new file mode 100644
index 0000000..9717ca8
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for clock control.
+ */
+
+#ifndef PM_API_CLOCK_H
+#define PM_API_CLOCK_H
+
+#include <lib/utils_def.h>
+
+#include "pm_common.h"
+
+#define CLK_NAME_LEN		U(15)
+#define MAX_PARENTS		U(100)
+#define CLK_NA_PARENT		-1
+#define CLK_DUMMY_PARENT	-2
+
+/* Flags for parent id */
+#define PARENT_CLK_SELF		U(0)
+#define PARENT_CLK_NODE1	U(1)
+#define PARENT_CLK_NODE2	U(2)
+#define PARENT_CLK_NODE3	U(3)
+#define PARENT_CLK_NODE4	U(4)
+#define PARENT_CLK_EXTERNAL	U(5)
+#define PARENT_CLK_MIO0_MIO77	U(6)
+
+#define CLK_SET_RATE_GATE	BIT(0) /* must be gated across rate change */
+#define CLK_SET_PARENT_GATE	BIT(1) /* must be gated across re-parent */
+#define CLK_SET_RATE_PARENT	BIT(2) /* propagate rate change up one level */
+#define CLK_IGNORE_UNUSED	BIT(3) /* do not gate even if unused */
+/* unused */
+#define CLK_IS_BASIC		BIT(5) /* Basic clk, can't do a to_clk_foo() */
+#define CLK_GET_RATE_NOCACHE	BIT(6) /* do not use the cached clk rate */
+#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
+#define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
+#define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to set rate */
+#define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
+/* parents need enable during gate/ungate, set rate and re-parent */
+#define CLK_OPS_PARENT_ENABLE	BIT(12)
+#define CLK_FRAC		BIT(13)
+
+#define CLK_DIVIDER_ONE_BASED		BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
+#define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK		BIT(3)
+#define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
+#define CLK_DIVIDER_READ_ONLY		BIT(5)
+#define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
+
+#define END_OF_CLK     "END_OF_CLK"
+
+//CLock Ids
+enum clock_id {
+	CLK_IOPLL,
+	CLK_RPLL,
+	CLK_APLL,
+	CLK_DPLL,
+	CLK_VPLL,
+	CLK_IOPLL_TO_FPD,
+	CLK_RPLL_TO_FPD,
+	CLK_APLL_TO_LPD,
+	CLK_DPLL_TO_LPD,
+	CLK_VPLL_TO_LPD,
+	CLK_ACPU,
+	CLK_ACPU_HALF,
+	CLK_DBG_FPD,
+	CLK_DBG_LPD,
+	CLK_DBG_TRACE,
+	CLK_DBG_TSTMP,
+	CLK_DP_VIDEO_REF,
+	CLK_DP_AUDIO_REF,
+	CLK_DP_STC_REF,
+	CLK_GDMA_REF,
+	CLK_DPDMA_REF,
+	CLK_DDR_REF,
+	CLK_SATA_REF,
+	CLK_PCIE_REF,
+	CLK_GPU_REF,
+	CLK_GPU_PP0_REF,
+	CLK_GPU_PP1_REF,
+	CLK_TOPSW_MAIN,
+	CLK_TOPSW_LSBUS,
+	CLK_GTGREF0_REF,
+	CLK_LPD_SWITCH,
+	CLK_LPD_LSBUS,
+	CLK_USB0_BUS_REF,
+	CLK_USB1_BUS_REF,
+	CLK_USB3_DUAL_REF,
+	CLK_USB0,
+	CLK_USB1,
+	CLK_CPU_R5,
+	CLK_CPU_R5_CORE,
+	CLK_CSU_SPB,
+	CLK_CSU_PLL,
+	CLK_PCAP,
+	CLK_IOU_SWITCH,
+	CLK_GEM_TSU_REF,
+	CLK_GEM_TSU,
+	CLK_GEM0_REF,
+	CLK_GEM1_REF,
+	CLK_GEM2_REF,
+	CLK_GEM3_REF,
+	CLK_GEM0_TX,
+	CLK_GEM1_TX,
+	CLK_GEM2_TX,
+	CLK_GEM3_TX,
+	CLK_QSPI_REF,
+	CLK_SDIO0_REF,
+	CLK_SDIO1_REF,
+	CLK_UART0_REF,
+	CLK_UART1_REF,
+	CLK_SPI0_REF,
+	CLK_SPI1_REF,
+	CLK_NAND_REF,
+	CLK_I2C0_REF,
+	CLK_I2C1_REF,
+	CLK_CAN0_REF,
+	CLK_CAN1_REF,
+	CLK_CAN0,
+	CLK_CAN1,
+	CLK_DLL_REF,
+	CLK_ADMA_REF,
+	CLK_TIMESTAMP_REF,
+	CLK_AMS_REF,
+	CLK_PL0_REF,
+	CLK_PL1_REF,
+	CLK_PL2_REF,
+	CLK_PL3_REF,
+	CLK_WDT,
+	CLK_IOPLL_INT,
+	CLK_IOPLL_PRE_SRC,
+	CLK_IOPLL_HALF,
+	CLK_IOPLL_INT_MUX,
+	CLK_IOPLL_POST_SRC,
+	CLK_RPLL_INT,
+	CLK_RPLL_PRE_SRC,
+	CLK_RPLL_HALF,
+	CLK_RPLL_INT_MUX,
+	CLK_RPLL_POST_SRC,
+	CLK_APLL_INT,
+	CLK_APLL_PRE_SRC,
+	CLK_APLL_HALF,
+	CLK_APLL_INT_MUX,
+	CLK_APLL_POST_SRC,
+	CLK_DPLL_INT,
+	CLK_DPLL_PRE_SRC,
+	CLK_DPLL_HALF,
+	CLK_DPLL_INT_MUX,
+	CLK_DPLL_POST_SRC,
+	CLK_VPLL_INT,
+	CLK_VPLL_PRE_SRC,
+	CLK_VPLL_HALF,
+	CLK_VPLL_INT_MUX,
+	CLK_VPLL_POST_SRC,
+	CLK_CAN0_MIO,
+	CLK_CAN1_MIO,
+	CLK_ACPU_FULL,
+	END_OF_OUTPUT_CLKS,
+};
+
+#define CLK_MAX_OUTPUT_CLK (unsigned int)(END_OF_OUTPUT_CLKS)
+
+//External clock ids
+enum {
+	EXT_CLK_PSS_REF = END_OF_OUTPUT_CLKS,
+	EXT_CLK_VIDEO,
+	EXT_CLK_PSS_ALT_REF,
+	EXT_CLK_AUX_REF,
+	EXT_CLK_GT_CRX_REF,
+	EXT_CLK_SWDT0,
+	EXT_CLK_SWDT1,
+	EXT_CLK_GEM0_EMIO,
+	EXT_CLK_GEM1_EMIO,
+	EXT_CLK_GEM2_EMIO,
+	EXT_CLK_GEM3_EMIO,
+	EXT_CLK_MIO50_OR_MIO51,
+	EXT_CLK_MIO0,
+	EXT_CLK_MIO1,
+	EXT_CLK_MIO2,
+	EXT_CLK_MIO3,
+	EXT_CLK_MIO4,
+	EXT_CLK_MIO5,
+	EXT_CLK_MIO6,
+	EXT_CLK_MIO7,
+	EXT_CLK_MIO8,
+	EXT_CLK_MIO9,
+	EXT_CLK_MIO10,
+	EXT_CLK_MIO11,
+	EXT_CLK_MIO12,
+	EXT_CLK_MIO13,
+	EXT_CLK_MIO14,
+	EXT_CLK_MIO15,
+	EXT_CLK_MIO16,
+	EXT_CLK_MIO17,
+	EXT_CLK_MIO18,
+	EXT_CLK_MIO19,
+	EXT_CLK_MIO20,
+	EXT_CLK_MIO21,
+	EXT_CLK_MIO22,
+	EXT_CLK_MIO23,
+	EXT_CLK_MIO24,
+	EXT_CLK_MIO25,
+	EXT_CLK_MIO26,
+	EXT_CLK_MIO27,
+	EXT_CLK_MIO28,
+	EXT_CLK_MIO29,
+	EXT_CLK_MIO30,
+	EXT_CLK_MIO31,
+	EXT_CLK_MIO32,
+	EXT_CLK_MIO33,
+	EXT_CLK_MIO34,
+	EXT_CLK_MIO35,
+	EXT_CLK_MIO36,
+	EXT_CLK_MIO37,
+	EXT_CLK_MIO38,
+	EXT_CLK_MIO39,
+	EXT_CLK_MIO40,
+	EXT_CLK_MIO41,
+	EXT_CLK_MIO42,
+	EXT_CLK_MIO43,
+	EXT_CLK_MIO44,
+	EXT_CLK_MIO45,
+	EXT_CLK_MIO46,
+	EXT_CLK_MIO47,
+	EXT_CLK_MIO48,
+	EXT_CLK_MIO49,
+	EXT_CLK_MIO50,
+	EXT_CLK_MIO51,
+	EXT_CLK_MIO52,
+	EXT_CLK_MIO53,
+	EXT_CLK_MIO54,
+	EXT_CLK_MIO55,
+	EXT_CLK_MIO56,
+	EXT_CLK_MIO57,
+	EXT_CLK_MIO58,
+	EXT_CLK_MIO59,
+	EXT_CLK_MIO60,
+	EXT_CLK_MIO61,
+	EXT_CLK_MIO62,
+	EXT_CLK_MIO63,
+	EXT_CLK_MIO64,
+	EXT_CLK_MIO65,
+	EXT_CLK_MIO66,
+	EXT_CLK_MIO67,
+	EXT_CLK_MIO68,
+	EXT_CLK_MIO69,
+	EXT_CLK_MIO70,
+	EXT_CLK_MIO71,
+	EXT_CLK_MIO72,
+	EXT_CLK_MIO73,
+	EXT_CLK_MIO74,
+	EXT_CLK_MIO75,
+	EXT_CLK_MIO76,
+	EXT_CLK_MIO77,
+	END_OF_CLKS,
+};
+
+#define CLK_MAX (unsigned int)(END_OF_CLKS)
+
+//CLock types
+#define CLK_TYPE_OUTPUT 0U
+#define	CLK_TYPE_EXTERNAL  1U
+
+//Topology types
+#define TYPE_INVALID 0U
+#define	TYPE_MUX 1U
+#define	TYPE_PLL 2U
+#define	TYPE_FIXEDFACTOR 3U
+#define	TYPE_DIV1 4U
+#define	TYPE_DIV2 5U
+#define	TYPE_GATE 6U
+
+struct pm_pll;
+struct pm_pll *pm_clock_get_pll(enum clock_id clock_id);
+struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id);
+uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id);
+
+enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name);
+enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks);
+enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id,
+					     unsigned int index,
+					     uint32_t *topology);
+enum pm_ret_status pm_api_clock_get_fixedfactor_params(unsigned int clock_id,
+						       uint32_t *mul,
+						       uint32_t *div);
+enum pm_ret_status pm_api_clock_get_parents(unsigned int clock_id,
+					    unsigned int index,
+					    uint32_t *parents);
+enum pm_ret_status pm_api_clock_get_attributes(unsigned int clock_id,
+					       uint32_t *attr);
+
+enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
+					    enum pm_node_id *node_id);
+enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id);
+
+enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll);
+enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll);
+enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll,
+					  unsigned int *state);
+enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll,
+					   enum clock_id clock_id,
+					   unsigned int parent_index);
+enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll,
+					   enum clock_id clock_id,
+					   unsigned int *parent_index);
+enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id,
+					 unsigned int mode);
+enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id,
+					 unsigned int *mode);
+
+#endif /* PM_API_CLOCK_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
new file mode 100644
index 0000000..44acb4b
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for ioctl.
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <zynqmp_def.h>
+
+#include "pm_api_clock.h"
+#include "pm_api_ioctl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+/**
+ * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode
+ * @mode	Buffer to store value of oper mode(Split/Lock-step)
+ *
+ * This function provides current configured RPU operational mode.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_rpu_oper_mode(unsigned int *mode)
+{
+	unsigned int val;
+
+	val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+	val &= ZYNQMP_SLSPLIT_MASK;
+	if (val == 0)
+		*mode = PM_RPU_MODE_LOCKSTEP;
+	else
+		*mode = PM_RPU_MODE_SPLIT;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_set_rpu_oper_mode () - Configure RPU operation mode
+ * @mode	Value to set for oper mode(Split/Lock-step)
+ *
+ * This function configures RPU operational mode(Split/Lock-step).
+ * It also sets TCM combined mode in RPU lock-step and TCM non-combined
+ * mode for RPU split mode. In case of Lock step mode, RPU1's output is
+ * clamped.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_rpu_oper_mode(unsigned int mode)
+{
+	unsigned int val;
+
+	if (mmio_read_32(CRL_APB_RST_LPD_TOP) && CRL_APB_RPU_AMBA_RESET)
+		return PM_RET_ERROR_ACCESS;
+
+	val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+
+	if (mode == PM_RPU_MODE_SPLIT) {
+		val |= ZYNQMP_SLSPLIT_MASK;
+		val &= ~ZYNQMP_TCM_COMB_MASK;
+		val &= ~ZYNQMP_SLCLAMP_MASK;
+	} else if (mode == PM_RPU_MODE_LOCKSTEP) {
+		val &= ~ZYNQMP_SLSPLIT_MASK;
+		val |= ZYNQMP_TCM_COMB_MASK;
+		val |= ZYNQMP_SLCLAMP_MASK;
+	} else {
+		return PM_RET_ERROR_ARGS;
+	}
+
+	mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_config_boot_addr() - Configure RPU boot address
+ * @nid		Node ID of RPU
+ * @value	Value to set for boot address (TCM/OCM)
+ *
+ * This function configures RPU boot address(memory).
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_config_boot_addr(enum pm_node_id nid,
+						    unsigned int value)
+{
+	unsigned int rpu_cfg_addr, val;
+
+	if (nid == NODE_RPU_0)
+		rpu_cfg_addr = ZYNQMP_RPU0_CFG;
+	else if (nid == NODE_RPU_1)
+		rpu_cfg_addr = ZYNQMP_RPU1_CFG;
+	else
+		return PM_RET_ERROR_ARGS;
+
+	val = mmio_read_32(rpu_cfg_addr);
+
+	if (value == PM_RPU_BOOTMEM_LOVEC)
+		val &= ~ZYNQMP_VINITHI_MASK;
+	else if (value == PM_RPU_BOOTMEM_HIVEC)
+		val |= ZYNQMP_VINITHI_MASK;
+	else
+		return PM_RET_ERROR_ARGS;
+
+	mmio_write_32(rpu_cfg_addr, val);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_config_tcm_comb() - Configure TCM combined mode
+ * @value	Value to set (Split/Combined)
+ *
+ * This function configures TCM to be in split mode or combined
+ * mode.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value)
+{
+	unsigned int val;
+
+	val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+
+	if (value == PM_RPU_TCM_SPLIT)
+		val &= ~ZYNQMP_TCM_COMB_MASK;
+	else if (value == PM_RPU_TCM_COMB)
+		val |= ZYNQMP_TCM_COMB_MASK;
+	else
+		return PM_RET_ERROR_ARGS;
+
+	mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_set_tapdelay_bypass() -  Enable/Disable tap delay bypass
+ * @type	Type of tap delay to enable/disable (e.g. QSPI)
+ * @value	Enable/Disable
+ *
+ * This function enable/disable tap delay bypass.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(unsigned int type,
+						       unsigned int value)
+{
+	if ((value != PM_TAPDELAY_BYPASS_ENABLE &&
+	     value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX)
+		return PM_RET_ERROR_ARGS;
+
+	return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type);
+}
+
+/**
+ * pm_ioctl_set_sgmii_mode() -  Set SGMII mode for the GEM device
+ * @nid		Node ID of the device
+ * @value	Enable/Disable
+ *
+ * This function enable/disable SGMII mode for the GEM device.
+ * While enabling SGMII mode, it also ties the GEM PCS Signal
+ * Detect to 1 and selects EMIO for RX clock generation.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid,
+						  unsigned int value)
+{
+	unsigned int val, mask, shift;
+	enum pm_ret_status ret;
+
+	if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE)
+		return PM_RET_ERROR_ARGS;
+
+	switch (nid) {
+	case NODE_ETH_0:
+		shift = 0;
+		break;
+	case NODE_ETH_1:
+		shift = 1;
+		break;
+	case NODE_ETH_2:
+		shift = 2;
+		break;
+	case NODE_ETH_3:
+		shift = 3;
+		break;
+	default:
+		return PM_RET_ERROR_ARGS;
+	}
+
+	if (value == PM_SGMII_DISABLE) {
+		mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift;
+		ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0U);
+	} else {
+		/* Tie the GEM PCS Signal Detect to 1 */
+		mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift;
+		val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift;
+		ret = pm_mmio_write(IOU_GEM_CTRL, mask, val);
+		if (ret != PM_RET_SUCCESS)
+			return ret;
+
+		/* Set the GEM to SGMII mode */
+		mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift;
+		val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE;
+		val <<= GEM_CLK_CTRL_OFFSET * shift;
+		ret =  pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val);
+	}
+
+	return ret;
+}
+
+/**
+ * pm_ioctl_sd_dll_reset() -  Reset DLL logic
+ * @nid		Node ID of the device
+ * @type	Reset type
+ *
+ * This function resets DLL logic for the SD device.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid,
+						unsigned int type)
+{
+	unsigned int mask, val;
+	enum pm_ret_status ret;
+
+	if (nid == NODE_SD_0) {
+		mask = ZYNQMP_SD0_DLL_RST_MASK;
+		val = ZYNQMP_SD0_DLL_RST;
+	} else if (nid == NODE_SD_1) {
+		mask = ZYNQMP_SD1_DLL_RST_MASK;
+		val = ZYNQMP_SD1_DLL_RST;
+	} else {
+		return PM_RET_ERROR_ARGS;
+	}
+
+	switch (type) {
+	case PM_DLL_RESET_ASSERT:
+	case PM_DLL_RESET_PULSE:
+		ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val);
+		if (ret != PM_RET_SUCCESS)
+			return ret;
+
+		if (type == PM_DLL_RESET_ASSERT)
+			break;
+		mdelay(1);
+		/* Fallthrough */
+	case PM_DLL_RESET_RELEASE:
+		ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0);
+		break;
+	default:
+		ret = PM_RET_ERROR_ARGS;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * pm_ioctl_sd_set_tapdelay() -  Set tap delay for the SD device
+ * @nid		Node ID of the device
+ * @type	Type of tap delay to set (input/output)
+ * @value	Value to set fot the tap delay
+ *
+ * This function sets input/output tap delay for the SD device.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid,
+						   enum tap_delay_type type,
+						   unsigned int value)
+{
+	unsigned int shift;
+	enum pm_ret_status ret;
+
+	if (nid == NODE_SD_0)
+		shift = 0;
+	else if (nid == NODE_SD_1)
+		shift = ZYNQMP_SD_TAP_OFFSET;
+	else
+		return PM_RET_ERROR_ARGS;
+
+	ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT);
+	if (ret != PM_RET_SUCCESS)
+		return ret;
+
+	if (type == PM_TAPDELAY_INPUT) {
+		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+				    (ZYNQMP_SD_ITAPCHGWIN_MASK << shift),
+				    (ZYNQMP_SD_ITAPCHGWIN << shift));
+		if (ret != PM_RET_SUCCESS)
+			goto reset_release;
+		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+				    (ZYNQMP_SD_ITAPDLYENA_MASK << shift),
+				    (ZYNQMP_SD_ITAPDLYENA << shift));
+		if (ret != PM_RET_SUCCESS)
+			goto reset_release;
+		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+				    (ZYNQMP_SD_ITAPDLYSEL_MASK << shift),
+				    (value << shift));
+		if (ret != PM_RET_SUCCESS)
+			goto reset_release;
+		ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+				    (ZYNQMP_SD_ITAPCHGWIN_MASK << shift), 0);
+	} else if (type == PM_TAPDELAY_OUTPUT) {
+		ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
+				    (ZYNQMP_SD_OTAPDLYENA_MASK << shift),
+				    (ZYNQMP_SD_OTAPDLYENA << shift));
+		if (ret != PM_RET_SUCCESS)
+			goto reset_release;
+		ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
+				    (ZYNQMP_SD_OTAPDLYSEL_MASK << shift),
+				    (value << shift));
+	} else {
+		ret = PM_RET_ERROR_ARGS;
+	}
+
+reset_release:
+	pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE);
+	return ret;
+}
+
+/**
+ * pm_ioctl_set_pll_frac_mode() -  Ioctl function for
+ *				   setting pll mode
+ * @pll     PLL clock id
+ * @mode    Mode fraction/integar
+ *
+ * This function sets PLL mode
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_pll_frac_mode
+			(unsigned int pll, unsigned int mode)
+{
+	return pm_clock_set_pll_mode(pll, mode);
+}
+
+/**
+ * pm_ioctl_get_pll_frac_mode() -  Ioctl function for
+ *				   getting pll mode
+ * @pll     PLL clock id
+ * @mode    Mode fraction/integar
+ *
+ * This function return current PLL mode
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_pll_frac_mode
+			(unsigned int pll, unsigned int *mode)
+{
+	return pm_clock_get_pll_mode(pll, mode);
+}
+
+/**
+ * pm_ioctl_set_pll_frac_data() -  Ioctl function for
+ *				   setting pll fraction data
+ * @pll     PLL clock id
+ * @data    fraction data
+ *
+ * This function sets fraction data.
+ * It is valid for fraction mode only.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_pll_frac_data
+			(unsigned int pll, unsigned int data)
+{
+	enum pm_node_id pll_nid;
+	enum pm_ret_status status;
+
+	/* Get PLL node ID using PLL clock ID */
+	status = pm_clock_get_pll_node_id(pll, &pll_nid);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	return pm_pll_set_parameter(pll_nid, PM_PLL_PARAM_DATA, data);
+}
+
+/**
+ * pm_ioctl_get_pll_frac_data() -  Ioctl function for
+ *				   getting pll fraction data
+ * @pll     PLL clock id
+ * @data    fraction data
+ *
+ * This function returns fraction data value.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_pll_frac_data
+			(unsigned int pll, unsigned int *data)
+{
+	enum pm_node_id pll_nid;
+	enum pm_ret_status status;
+
+	/* Get PLL node ID using PLL clock ID */
+	status = pm_clock_get_pll_node_id(pll, &pll_nid);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	return pm_pll_get_parameter(pll_nid, PM_PLL_PARAM_DATA, data);
+}
+
+/**
+ * pm_ioctl_write_ggs() - Ioctl function for writing
+ *			  global general storage (ggs)
+ * @index	GGS register index
+ * @value	Register value to be written
+ *
+ * This function writes value to GGS register.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_write_ggs(unsigned int index,
+					     unsigned int value)
+{
+	if (index >= GGS_NUM_REGS)
+		return PM_RET_ERROR_ARGS;
+
+	return pm_mmio_write(GGS_BASEADDR + (index << 2),
+			     0xFFFFFFFFU, value);
+}
+
+/**
+ * pm_ioctl_read_ggs() - Ioctl function for reading
+ *			 global general storage (ggs)
+ * @index	GGS register index
+ * @value	Register value
+ *
+ * This function returns GGS register value.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_read_ggs(unsigned int index,
+					    unsigned int *value)
+{
+	if (index >= GGS_NUM_REGS)
+		return PM_RET_ERROR_ARGS;
+
+	return pm_mmio_read(GGS_BASEADDR + (index << 2), value);
+}
+
+/**
+ * pm_ioctl_write_pggs() - Ioctl function for writing persistent
+ *			   global general storage (pggs)
+ * @index	PGGS register index
+ * @value	Register value to be written
+ *
+ * This function writes value to PGGS register.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_write_pggs(unsigned int index,
+					      unsigned int value)
+{
+	if (index >= PGGS_NUM_REGS)
+		return PM_RET_ERROR_ARGS;
+
+	return pm_mmio_write(PGGS_BASEADDR + (index << 2),
+			     0xFFFFFFFFU, value);
+}
+
+/**
+ * pm_ioctl_afi() - Ioctl function for writing afi values
+ *
+ * @index 	AFI register index
+ * @value	Register value to be written
+ *
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_afi(unsigned int index,
+					      unsigned int value)
+{
+	unsigned int mask;
+	unsigned int regarr[] = {0xFD360000,
+				0xFD360014,
+				0xFD370000,
+				0xFD370014,
+				0xFD380000,
+				0xFD380014,
+				0xFD390000,
+				0xFD390014,
+				0xFD3a0000,
+				0xFD3a0014,
+				0xFD3b0000,
+				0xFD3b0014,
+				0xFF9b0000,
+				0xFF9b0014,
+				0xFD615000,
+				0xFF419000,
+				};
+
+	if (index >= ARRAY_SIZE(regarr))
+		return PM_RET_ERROR_ARGS;
+
+	if (index < AFIFM6_WRCTRL)
+		mask = FABRIC_WIDTH;
+	else
+		mask = 0xf00;
+
+	return pm_mmio_write(regarr[index], mask, value);
+}
+
+/**
+ * pm_ioctl_read_pggs() - Ioctl function for reading persistent
+ *			  global general storage (pggs)
+ * @index	PGGS register index
+ * @value	Register value
+ *
+ * This function returns PGGS register value.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_read_pggs(unsigned int index,
+					     unsigned int *value)
+{
+	if (index >= PGGS_NUM_REGS)
+		return PM_RET_ERROR_ARGS;
+
+	return pm_mmio_read(PGGS_BASEADDR + (index << 2), value);
+}
+
+/**
+ * pm_ioctl_ulpi_reset() - Ioctl function for performing ULPI reset
+ *
+ * This function peerforms the ULPI reset sequence for resetting
+ * the ULPI transceiver.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_ulpi_reset(void)
+{
+	enum pm_ret_status ret;
+
+	ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+			    ZYNQMP_ULPI_RESET_VAL_HIGH);
+	if (ret != PM_RET_SUCCESS)
+		return ret;
+
+	/* Drive ULPI assert for atleast 1ms */
+	mdelay(1);
+
+	ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+			    ZYNQMP_ULPI_RESET_VAL_LOW);
+	if (ret != PM_RET_SUCCESS)
+		return ret;
+
+	/* Drive ULPI de-assert for atleast 1ms */
+	mdelay(1);
+
+	ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+			    ZYNQMP_ULPI_RESET_VAL_HIGH);
+
+	return ret;
+}
+
+/**
+ * pm_ioctl_set_boot_health_status() - Ioctl for setting healthy boot status
+ *
+ * This function sets healthy bit value to indicate boot health status
+ * to firmware.
+ *
+ * @return      Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_boot_health_status(unsigned int value)
+{
+	return pm_mmio_write(PM_BOOT_HEALTH_STATUS_REG,
+			     PM_BOOT_HEALTH_STATUS_MASK, value);
+}
+
+/**
+ * pm_api_ioctl() -  PM IOCTL API for device control and configs
+ * @node_id	Node ID of the device
+ * @ioctl_id	ID of the requested IOCTL
+ * @arg1	Argument 1 to requested IOCTL call
+ * @arg2	Argument 2 to requested IOCTL call
+ * @value	Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
+				unsigned int ioctl_id,
+				unsigned int arg1,
+				unsigned int arg2,
+				unsigned int *value)
+{
+	enum pm_ret_status ret;
+
+	switch (ioctl_id) {
+	case IOCTL_GET_RPU_OPER_MODE:
+		ret = pm_ioctl_get_rpu_oper_mode(value);
+		break;
+	case IOCTL_SET_RPU_OPER_MODE:
+		ret = pm_ioctl_set_rpu_oper_mode(arg1);
+		break;
+	case IOCTL_RPU_BOOT_ADDR_CONFIG:
+		ret = pm_ioctl_config_boot_addr(nid, arg1);
+		break;
+	case IOCTL_TCM_COMB_CONFIG:
+		ret = pm_ioctl_config_tcm_comb(arg1);
+		break;
+	case IOCTL_SET_TAPDELAY_BYPASS:
+		ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2);
+		break;
+	case IOCTL_SET_SGMII_MODE:
+		ret = pm_ioctl_set_sgmii_mode(nid, arg1);
+		break;
+	case IOCTL_SD_DLL_RESET:
+		ret = pm_ioctl_sd_dll_reset(nid, arg1);
+		break;
+	case IOCTL_SET_SD_TAPDELAY:
+		ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2);
+		break;
+	case IOCTL_SET_PLL_FRAC_MODE:
+		ret = pm_ioctl_set_pll_frac_mode(arg1, arg2);
+		break;
+	case IOCTL_GET_PLL_FRAC_MODE:
+		ret = pm_ioctl_get_pll_frac_mode(arg1, value);
+		break;
+	case IOCTL_SET_PLL_FRAC_DATA:
+		ret = pm_ioctl_set_pll_frac_data(arg1, arg2);
+		break;
+	case IOCTL_GET_PLL_FRAC_DATA:
+		ret = pm_ioctl_get_pll_frac_data(arg1, value);
+		break;
+	case IOCTL_WRITE_GGS:
+		ret = pm_ioctl_write_ggs(arg1, arg2);
+		break;
+	case IOCTL_READ_GGS:
+		ret = pm_ioctl_read_ggs(arg1, value);
+		break;
+	case IOCTL_WRITE_PGGS:
+		ret = pm_ioctl_write_pggs(arg1, arg2);
+		break;
+	case IOCTL_READ_PGGS:
+		ret = pm_ioctl_read_pggs(arg1, value);
+		break;
+	case IOCTL_ULPI_RESET:
+		ret = pm_ioctl_ulpi_reset();
+		break;
+	case IOCTL_SET_BOOT_HEALTH_STATUS:
+		ret = pm_ioctl_set_boot_health_status(arg1);
+		break;
+	case IOCTL_AFI:
+		ret = pm_ioctl_afi(arg1, arg2);
+		break;
+	default:
+		ret = PM_RET_ERROR_NOTSUPPORTED;
+		break;
+	}
+
+	return ret;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
new file mode 100644
index 0000000..337f732
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#ifndef PM_API_IOCTL_H
+#define PM_API_IOCTL_H
+
+#include "pm_common.h"
+
+//ioctl id
+enum {
+	IOCTL_GET_RPU_OPER_MODE,
+	IOCTL_SET_RPU_OPER_MODE,
+	IOCTL_RPU_BOOT_ADDR_CONFIG,
+	IOCTL_TCM_COMB_CONFIG,
+	IOCTL_SET_TAPDELAY_BYPASS,
+	IOCTL_SET_SGMII_MODE,
+	IOCTL_SD_DLL_RESET,
+	IOCTL_SET_SD_TAPDELAY,
+	 /* Ioctl for clock driver */
+	IOCTL_SET_PLL_FRAC_MODE,
+	IOCTL_GET_PLL_FRAC_MODE,
+	IOCTL_SET_PLL_FRAC_DATA,
+	IOCTL_GET_PLL_FRAC_DATA,
+	IOCTL_WRITE_GGS,
+	IOCTL_READ_GGS,
+	IOCTL_WRITE_PGGS,
+	IOCTL_READ_PGGS,
+	/* IOCTL for ULPI reset */
+	IOCTL_ULPI_RESET,
+	/* Set healthy bit value */
+	IOCTL_SET_BOOT_HEALTH_STATUS,
+	IOCTL_AFI,
+};
+
+//RPU operation mode
+#define	PM_RPU_MODE_LOCKSTEP 0U
+#define	PM_RPU_MODE_SPLIT 1U
+
+//RPU boot mem
+#define	PM_RPU_BOOTMEM_LOVEC 0U
+#define	PM_RPU_BOOTMEM_HIVEC 1U
+
+//RPU tcm mpde
+#define	PM_RPU_TCM_SPLIT 0U
+#define	PM_RPU_TCM_COMB 1U
+
+//tap delay signal type
+#define	PM_TAPDELAY_NAND_DQS_IN 0U
+#define	PM_TAPDELAY_NAND_DQS_OUT 1U
+#define	PM_TAPDELAY_QSPI 2U
+#define	PM_TAPDELAY_MAX 3U
+
+//tap delay bypass
+#define	PM_TAPDELAY_BYPASS_DISABLE 0U
+#define	PM_TAPDELAY_BYPASS_ENABLE 1U
+
+//sgmii mode
+#define	PM_SGMII_DISABLE 0U
+#define	PM_SGMII_ENABLE 1U
+
+enum tap_delay_type {
+	PM_TAPDELAY_INPUT,
+	PM_TAPDELAY_OUTPUT,
+};
+
+//dll reset type
+#define	PM_DLL_RESET_ASSERT 0U
+#define	PM_DLL_RESET_RELEASE 1U
+#define	PM_DLL_RESET_PULSE 2U
+
+enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
+				unsigned int ioctl_id,
+				unsigned int arg1,
+				unsigned int arg2,
+				unsigned int *value);
+#endif /* PM_API_IOCTL_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
new file mode 100644
index 0000000..a900057
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
@@ -0,0 +1,3041 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_pinctrl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+#define PINCTRL_FUNCTION_MASK			U(0xFE)
+#define PINCTRL_VOLTAGE_STATUS_MASK		U(0x01)
+#define NFUNCS_PER_PIN				U(13)
+#define PINCTRL_NUM_MIOS			U(78)
+#define MAX_PIN_PER_REG				U(26)
+#define PINCTRL_BANK_ADDR_STEP			U(28)
+
+#define PINCTRL_DRVSTRN0_REG_OFFSET		U(0)
+#define PINCTRL_DRVSTRN1_REG_OFFSET		U(4)
+#define PINCTRL_SCHCMOS_REG_OFFSET		U(8)
+#define PINCTRL_PULLCTRL_REG_OFFSET		U(12)
+#define PINCTRL_PULLSTAT_REG_OFFSET		U(16)
+#define PINCTRL_SLEWCTRL_REG_OFFSET		U(20)
+#define PINCTRL_VOLTAGE_STAT_REG_OFFSET		U(24)
+
+#define IOU_SLCR_BANK1_CTRL5			U(0XFF180164)
+
+#define PINCTRL_CFG_ADDR_OFFSET(addr, reg, miopin)			\
+	((addr) + 4 * PINCTRL_NUM_MIOS + PINCTRL_BANK_ADDR_STEP *	\
+	((miopin) / MAX_PIN_PER_REG) + (reg))
+
+#define PINCTRL_PIN_OFFSET(_miopin) \
+	((_miopin) - (MAX_PIN_PER_REG * ((_miopin) / MAX_PIN_PER_REG)))
+
+#define PINCTRL_REGVAL_TO_PIN_CONFIG(_pin, _val)			\
+	(((_val) >> PINCTRL_PIN_OFFSET(_pin)) & 0x1)
+
+static uint8_t pm_pinctrl_mux[NFUNCS_PER_PIN] = {
+	0x02, 0x04, 0x08, 0x10, 0x18,
+	0x00, 0x20, 0x40, 0x60, 0x80,
+	0xA0, 0xC0, 0xE0
+};
+
+struct pinctrl_function {
+	char name[FUNCTION_NAME_LEN];
+	uint16_t (*groups)[];
+	uint8_t regval;
+};
+
+/* Max groups for one pin */
+#define MAX_PIN_GROUPS	U(13)
+
+struct zynqmp_pin_group {
+	uint16_t (*groups)[];
+};
+
+static struct pinctrl_function pinctrl_functions[MAX_FUNCTION] =  {
+	[PINCTRL_FUNC_CAN0] = {
+		.name = "can0",
+		.regval = 0x20,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_CAN0_0,
+			PINCTRL_GRP_CAN0_1,
+			PINCTRL_GRP_CAN0_2,
+			PINCTRL_GRP_CAN0_3,
+			PINCTRL_GRP_CAN0_4,
+			PINCTRL_GRP_CAN0_5,
+			PINCTRL_GRP_CAN0_6,
+			PINCTRL_GRP_CAN0_7,
+			PINCTRL_GRP_CAN0_8,
+			PINCTRL_GRP_CAN0_9,
+			PINCTRL_GRP_CAN0_10,
+			PINCTRL_GRP_CAN0_11,
+			PINCTRL_GRP_CAN0_12,
+			PINCTRL_GRP_CAN0_13,
+			PINCTRL_GRP_CAN0_14,
+			PINCTRL_GRP_CAN0_15,
+			PINCTRL_GRP_CAN0_16,
+			PINCTRL_GRP_CAN0_17,
+			PINCTRL_GRP_CAN0_18,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_CAN1] = {
+		.name = "can1",
+		.regval = 0x20,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_CAN1_0,
+			PINCTRL_GRP_CAN1_1,
+			PINCTRL_GRP_CAN1_2,
+			PINCTRL_GRP_CAN1_3,
+			PINCTRL_GRP_CAN1_4,
+			PINCTRL_GRP_CAN1_5,
+			PINCTRL_GRP_CAN1_6,
+			PINCTRL_GRP_CAN1_7,
+			PINCTRL_GRP_CAN1_8,
+			PINCTRL_GRP_CAN1_9,
+			PINCTRL_GRP_CAN1_10,
+			PINCTRL_GRP_CAN1_11,
+			PINCTRL_GRP_CAN1_12,
+			PINCTRL_GRP_CAN1_13,
+			PINCTRL_GRP_CAN1_14,
+			PINCTRL_GRP_CAN1_15,
+			PINCTRL_GRP_CAN1_16,
+			PINCTRL_GRP_CAN1_17,
+			PINCTRL_GRP_CAN1_18,
+			PINCTRL_GRP_CAN1_19,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_ETHERNET0] = {
+		.name = "ethernet0",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_ETHERNET1] = {
+		.name = "ethernet1",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_ETHERNET2] = {
+		.name = "ethernet2",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_ETHERNET3] = {
+		.name = "ethernet3",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_GEMTSU0] = {
+		.name = "gemtsu0",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_GEMTSU0_0,
+			PINCTRL_GRP_GEMTSU0_1,
+			PINCTRL_GRP_GEMTSU0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_GPIO0] = {
+		.name = "gpio0",
+		.regval = 0x00,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_GPIO0_0,
+			PINCTRL_GRP_GPIO0_1,
+			PINCTRL_GRP_GPIO0_2,
+			PINCTRL_GRP_GPIO0_3,
+			PINCTRL_GRP_GPIO0_4,
+			PINCTRL_GRP_GPIO0_5,
+			PINCTRL_GRP_GPIO0_6,
+			PINCTRL_GRP_GPIO0_7,
+			PINCTRL_GRP_GPIO0_8,
+			PINCTRL_GRP_GPIO0_9,
+			PINCTRL_GRP_GPIO0_10,
+			PINCTRL_GRP_GPIO0_11,
+			PINCTRL_GRP_GPIO0_12,
+			PINCTRL_GRP_GPIO0_13,
+			PINCTRL_GRP_GPIO0_14,
+			PINCTRL_GRP_GPIO0_15,
+			PINCTRL_GRP_GPIO0_16,
+			PINCTRL_GRP_GPIO0_17,
+			PINCTRL_GRP_GPIO0_18,
+			PINCTRL_GRP_GPIO0_19,
+			PINCTRL_GRP_GPIO0_20,
+			PINCTRL_GRP_GPIO0_21,
+			PINCTRL_GRP_GPIO0_22,
+			PINCTRL_GRP_GPIO0_23,
+			PINCTRL_GRP_GPIO0_24,
+			PINCTRL_GRP_GPIO0_25,
+			PINCTRL_GRP_GPIO0_26,
+			PINCTRL_GRP_GPIO0_27,
+			PINCTRL_GRP_GPIO0_28,
+			PINCTRL_GRP_GPIO0_29,
+			PINCTRL_GRP_GPIO0_30,
+			PINCTRL_GRP_GPIO0_31,
+			PINCTRL_GRP_GPIO0_32,
+			PINCTRL_GRP_GPIO0_33,
+			PINCTRL_GRP_GPIO0_34,
+			PINCTRL_GRP_GPIO0_35,
+			PINCTRL_GRP_GPIO0_36,
+			PINCTRL_GRP_GPIO0_37,
+			PINCTRL_GRP_GPIO0_38,
+			PINCTRL_GRP_GPIO0_39,
+			PINCTRL_GRP_GPIO0_40,
+			PINCTRL_GRP_GPIO0_41,
+			PINCTRL_GRP_GPIO0_42,
+			PINCTRL_GRP_GPIO0_43,
+			PINCTRL_GRP_GPIO0_44,
+			PINCTRL_GRP_GPIO0_45,
+			PINCTRL_GRP_GPIO0_46,
+			PINCTRL_GRP_GPIO0_47,
+			PINCTRL_GRP_GPIO0_48,
+			PINCTRL_GRP_GPIO0_49,
+			PINCTRL_GRP_GPIO0_50,
+			PINCTRL_GRP_GPIO0_51,
+			PINCTRL_GRP_GPIO0_52,
+			PINCTRL_GRP_GPIO0_53,
+			PINCTRL_GRP_GPIO0_54,
+			PINCTRL_GRP_GPIO0_55,
+			PINCTRL_GRP_GPIO0_56,
+			PINCTRL_GRP_GPIO0_57,
+			PINCTRL_GRP_GPIO0_58,
+			PINCTRL_GRP_GPIO0_59,
+			PINCTRL_GRP_GPIO0_60,
+			PINCTRL_GRP_GPIO0_61,
+			PINCTRL_GRP_GPIO0_62,
+			PINCTRL_GRP_GPIO0_63,
+			PINCTRL_GRP_GPIO0_64,
+			PINCTRL_GRP_GPIO0_65,
+			PINCTRL_GRP_GPIO0_66,
+			PINCTRL_GRP_GPIO0_67,
+			PINCTRL_GRP_GPIO0_68,
+			PINCTRL_GRP_GPIO0_69,
+			PINCTRL_GRP_GPIO0_70,
+			PINCTRL_GRP_GPIO0_71,
+			PINCTRL_GRP_GPIO0_72,
+			PINCTRL_GRP_GPIO0_73,
+			PINCTRL_GRP_GPIO0_74,
+			PINCTRL_GRP_GPIO0_75,
+			PINCTRL_GRP_GPIO0_76,
+			PINCTRL_GRP_GPIO0_77,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_I2C0] = {
+		.name = "i2c0",
+		.regval = 0x40,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_I2C0_0,
+			PINCTRL_GRP_I2C0_1,
+			PINCTRL_GRP_I2C0_2,
+			PINCTRL_GRP_I2C0_3,
+			PINCTRL_GRP_I2C0_4,
+			PINCTRL_GRP_I2C0_5,
+			PINCTRL_GRP_I2C0_6,
+			PINCTRL_GRP_I2C0_7,
+			PINCTRL_GRP_I2C0_8,
+			PINCTRL_GRP_I2C0_9,
+			PINCTRL_GRP_I2C0_10,
+			PINCTRL_GRP_I2C0_11,
+			PINCTRL_GRP_I2C0_12,
+			PINCTRL_GRP_I2C0_13,
+			PINCTRL_GRP_I2C0_14,
+			PINCTRL_GRP_I2C0_15,
+			PINCTRL_GRP_I2C0_16,
+			PINCTRL_GRP_I2C0_17,
+			PINCTRL_GRP_I2C0_18,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_I2C1] = {
+		.name = "i2c1",
+		.regval = 0x40,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_I2C1_0,
+			PINCTRL_GRP_I2C1_1,
+			PINCTRL_GRP_I2C1_2,
+			PINCTRL_GRP_I2C1_3,
+			PINCTRL_GRP_I2C1_4,
+			PINCTRL_GRP_I2C1_5,
+			PINCTRL_GRP_I2C1_6,
+			PINCTRL_GRP_I2C1_7,
+			PINCTRL_GRP_I2C1_8,
+			PINCTRL_GRP_I2C1_9,
+			PINCTRL_GRP_I2C1_10,
+			PINCTRL_GRP_I2C1_11,
+			PINCTRL_GRP_I2C1_12,
+			PINCTRL_GRP_I2C1_13,
+			PINCTRL_GRP_I2C1_14,
+			PINCTRL_GRP_I2C1_15,
+			PINCTRL_GRP_I2C1_16,
+			PINCTRL_GRP_I2C1_17,
+			PINCTRL_GRP_I2C1_18,
+			PINCTRL_GRP_I2C1_19,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_MDIO0] = {
+		.name = "mdio0",
+		.regval = 0x60,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_MDIO0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_MDIO1] = {
+		.name = "mdio1",
+		.regval = 0x80,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_MDIO1_0,
+			PINCTRL_GRP_MDIO1_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_MDIO2] = {
+		.name = "mdio2",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_MDIO2_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_MDIO3] = {
+		.name = "mdio3",
+		.regval = 0xc0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_MDIO3_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_QSPI0] = {
+		.name = "qspi0",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_QSPI_FBCLK] = {
+		.name = "qspi_fbclk",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI_FBCLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_QSPI_SS] = {
+		.name = "qspi_ss",
+		.regval = 0x02,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI_SS,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SPI0] = {
+		.name = "spi0",
+		.regval = 0x80,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SPI0_0,
+			PINCTRL_GRP_SPI0_1,
+			PINCTRL_GRP_SPI0_2,
+			PINCTRL_GRP_SPI0_3,
+			PINCTRL_GRP_SPI0_4,
+			PINCTRL_GRP_SPI0_5,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SPI1] = {
+		.name = "spi1",
+		.regval = 0x80,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SPI1_0,
+			PINCTRL_GRP_SPI1_1,
+			PINCTRL_GRP_SPI1_2,
+			PINCTRL_GRP_SPI1_3,
+			PINCTRL_GRP_SPI1_4,
+			PINCTRL_GRP_SPI1_5,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SPI0_SS] = {
+		.name = "spi0_ss",
+		.regval = 0x80,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SPI0_0_SS0,
+			PINCTRL_GRP_SPI0_0_SS1,
+			PINCTRL_GRP_SPI0_0_SS2,
+			PINCTRL_GRP_SPI0_1_SS0,
+			PINCTRL_GRP_SPI0_1_SS1,
+			PINCTRL_GRP_SPI0_1_SS2,
+			PINCTRL_GRP_SPI0_2_SS0,
+			PINCTRL_GRP_SPI0_2_SS1,
+			PINCTRL_GRP_SPI0_2_SS2,
+			PINCTRL_GRP_SPI0_3_SS0,
+			PINCTRL_GRP_SPI0_3_SS1,
+			PINCTRL_GRP_SPI0_3_SS2,
+			PINCTRL_GRP_SPI0_4_SS0,
+			PINCTRL_GRP_SPI0_4_SS1,
+			PINCTRL_GRP_SPI0_4_SS2,
+			PINCTRL_GRP_SPI0_5_SS0,
+			PINCTRL_GRP_SPI0_5_SS1,
+			PINCTRL_GRP_SPI0_5_SS2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SPI1_SS] = {
+		.name = "spi1_ss",
+		.regval = 0x80,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SPI1_0_SS0,
+			PINCTRL_GRP_SPI1_0_SS1,
+			PINCTRL_GRP_SPI1_0_SS2,
+			PINCTRL_GRP_SPI1_1_SS0,
+			PINCTRL_GRP_SPI1_1_SS1,
+			PINCTRL_GRP_SPI1_1_SS2,
+			PINCTRL_GRP_SPI1_2_SS0,
+			PINCTRL_GRP_SPI1_2_SS1,
+			PINCTRL_GRP_SPI1_2_SS2,
+			PINCTRL_GRP_SPI1_3_SS0,
+			PINCTRL_GRP_SPI1_3_SS1,
+			PINCTRL_GRP_SPI1_3_SS2,
+			PINCTRL_GRP_SPI1_4_SS0,
+			PINCTRL_GRP_SPI1_4_SS1,
+			PINCTRL_GRP_SPI1_4_SS2,
+			PINCTRL_GRP_SPI1_5_SS0,
+			PINCTRL_GRP_SPI1_5_SS1,
+			PINCTRL_GRP_SPI1_5_SS2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO0] = {
+		.name = "sdio0",
+		.regval = 0x08,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_2,
+			PINCTRL_GRP_SDIO0_1BIT_0_3,
+			PINCTRL_GRP_SDIO0_1BIT_0_4,
+			PINCTRL_GRP_SDIO0_1BIT_0_5,
+			PINCTRL_GRP_SDIO0_1BIT_0_6,
+			PINCTRL_GRP_SDIO0_1BIT_0_7,
+			PINCTRL_GRP_SDIO0_1BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_2,
+			PINCTRL_GRP_SDIO0_1BIT_1_3,
+			PINCTRL_GRP_SDIO0_1BIT_1_4,
+			PINCTRL_GRP_SDIO0_1BIT_1_5,
+			PINCTRL_GRP_SDIO0_1BIT_1_6,
+			PINCTRL_GRP_SDIO0_1BIT_1_7,
+			PINCTRL_GRP_SDIO0_1BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_2,
+			PINCTRL_GRP_SDIO0_1BIT_2_3,
+			PINCTRL_GRP_SDIO0_1BIT_2_4,
+			PINCTRL_GRP_SDIO0_1BIT_2_5,
+			PINCTRL_GRP_SDIO0_1BIT_2_6,
+			PINCTRL_GRP_SDIO0_1BIT_2_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO0_PC] = {
+		.name = "sdio0_pc",
+		.regval = 0x08,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO0_0_PC,
+			PINCTRL_GRP_SDIO0_1_PC,
+			PINCTRL_GRP_SDIO0_2_PC,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO0_CD] = {
+		.name = "sdio0_cd",
+		.regval = 0x08,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO0_0_CD,
+			PINCTRL_GRP_SDIO0_1_CD,
+			PINCTRL_GRP_SDIO0_2_CD,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO0_WP] = {
+		.name = "sdio0_wp",
+		.regval = 0x08,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO0_0_WP,
+			PINCTRL_GRP_SDIO0_1_WP,
+			PINCTRL_GRP_SDIO0_2_WP,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO1] = {
+		.name = "sdio1",
+		.regval = 0x10,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_2,
+			PINCTRL_GRP_SDIO1_1BIT_0_3,
+			PINCTRL_GRP_SDIO1_1BIT_0_4,
+			PINCTRL_GRP_SDIO1_1BIT_0_5,
+			PINCTRL_GRP_SDIO1_1BIT_0_6,
+			PINCTRL_GRP_SDIO1_1BIT_0_7,
+			PINCTRL_GRP_SDIO1_1BIT_1_0,
+			PINCTRL_GRP_SDIO1_1BIT_1_1,
+			PINCTRL_GRP_SDIO1_1BIT_1_2,
+			PINCTRL_GRP_SDIO1_1BIT_1_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO1_PC] = {
+		.name = "sdio1_pc",
+		.regval = 0x10,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO1_0_PC,
+			PINCTRL_GRP_SDIO1_1_PC,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO1_CD] = {
+		.name = "sdio1_cd",
+		.regval = 0x10,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO1_0_CD,
+			PINCTRL_GRP_SDIO1_1_CD,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SDIO1_WP] = {
+		.name = "sdio1_wp",
+		.regval = 0x10,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SDIO1_0_WP,
+			PINCTRL_GRP_SDIO1_1_WP,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_NAND0] = {
+		.name = "nand0",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_NAND0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_NAND0_CE] = {
+		.name = "nand0_ce",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_NAND0_0_CE,
+			PINCTRL_GRP_NAND0_1_CE,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_NAND0_RB] = {
+		.name = "nand0_rb",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_NAND0_0_RB,
+			PINCTRL_GRP_NAND0_1_RB,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_NAND0_DQS] = {
+		.name = "nand0_dqs",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_NAND0_0_DQS,
+			PINCTRL_GRP_NAND0_1_DQS,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC0_CLK] = {
+		.name = "ttc0_clk",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC0_0_CLK,
+			PINCTRL_GRP_TTC0_1_CLK,
+			PINCTRL_GRP_TTC0_2_CLK,
+			PINCTRL_GRP_TTC0_3_CLK,
+			PINCTRL_GRP_TTC0_4_CLK,
+			PINCTRL_GRP_TTC0_5_CLK,
+			PINCTRL_GRP_TTC0_6_CLK,
+			PINCTRL_GRP_TTC0_7_CLK,
+			PINCTRL_GRP_TTC0_8_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC0_WAV] = {
+		.name = "ttc0_wav",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC0_0_WAV,
+			PINCTRL_GRP_TTC0_1_WAV,
+			PINCTRL_GRP_TTC0_2_WAV,
+			PINCTRL_GRP_TTC0_3_WAV,
+			PINCTRL_GRP_TTC0_4_WAV,
+			PINCTRL_GRP_TTC0_5_WAV,
+			PINCTRL_GRP_TTC0_6_WAV,
+			PINCTRL_GRP_TTC0_7_WAV,
+			PINCTRL_GRP_TTC0_8_WAV,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC1_CLK] = {
+		.name = "ttc1_clk",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC1_0_CLK,
+			PINCTRL_GRP_TTC1_1_CLK,
+			PINCTRL_GRP_TTC1_2_CLK,
+			PINCTRL_GRP_TTC1_3_CLK,
+			PINCTRL_GRP_TTC1_4_CLK,
+			PINCTRL_GRP_TTC1_5_CLK,
+			PINCTRL_GRP_TTC1_6_CLK,
+			PINCTRL_GRP_TTC1_7_CLK,
+			PINCTRL_GRP_TTC1_8_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC1_WAV] = {
+		.name = "ttc1_wav",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC1_0_WAV,
+			PINCTRL_GRP_TTC1_1_WAV,
+			PINCTRL_GRP_TTC1_2_WAV,
+			PINCTRL_GRP_TTC1_3_WAV,
+			PINCTRL_GRP_TTC1_4_WAV,
+			PINCTRL_GRP_TTC1_5_WAV,
+			PINCTRL_GRP_TTC1_6_WAV,
+			PINCTRL_GRP_TTC1_7_WAV,
+			PINCTRL_GRP_TTC1_8_WAV,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC2_CLK] = {
+		.name = "ttc2_clk",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC2_0_CLK,
+			PINCTRL_GRP_TTC2_1_CLK,
+			PINCTRL_GRP_TTC2_2_CLK,
+			PINCTRL_GRP_TTC2_3_CLK,
+			PINCTRL_GRP_TTC2_4_CLK,
+			PINCTRL_GRP_TTC2_5_CLK,
+			PINCTRL_GRP_TTC2_6_CLK,
+			PINCTRL_GRP_TTC2_7_CLK,
+			PINCTRL_GRP_TTC2_8_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC2_WAV] = {
+		.name = "ttc2_wav",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC2_0_WAV,
+			PINCTRL_GRP_TTC2_1_WAV,
+			PINCTRL_GRP_TTC2_2_WAV,
+			PINCTRL_GRP_TTC2_3_WAV,
+			PINCTRL_GRP_TTC2_4_WAV,
+			PINCTRL_GRP_TTC2_5_WAV,
+			PINCTRL_GRP_TTC2_6_WAV,
+			PINCTRL_GRP_TTC2_7_WAV,
+			PINCTRL_GRP_TTC2_8_WAV,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC3_CLK] = {
+		.name = "ttc3_clk",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC3_0_CLK,
+			PINCTRL_GRP_TTC3_1_CLK,
+			PINCTRL_GRP_TTC3_2_CLK,
+			PINCTRL_GRP_TTC3_3_CLK,
+			PINCTRL_GRP_TTC3_4_CLK,
+			PINCTRL_GRP_TTC3_5_CLK,
+			PINCTRL_GRP_TTC3_6_CLK,
+			PINCTRL_GRP_TTC3_7_CLK,
+			PINCTRL_GRP_TTC3_8_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TTC3_WAV] = {
+		.name = "ttc3_wav",
+		.regval = 0xa0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TTC3_0_WAV,
+			PINCTRL_GRP_TTC3_1_WAV,
+			PINCTRL_GRP_TTC3_2_WAV,
+			PINCTRL_GRP_TTC3_3_WAV,
+			PINCTRL_GRP_TTC3_4_WAV,
+			PINCTRL_GRP_TTC3_5_WAV,
+			PINCTRL_GRP_TTC3_6_WAV,
+			PINCTRL_GRP_TTC3_7_WAV,
+			PINCTRL_GRP_TTC3_8_WAV,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_UART0] = {
+		.name = "uart0",
+		.regval = 0xc0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_UART0_0,
+			PINCTRL_GRP_UART0_1,
+			PINCTRL_GRP_UART0_2,
+			PINCTRL_GRP_UART0_3,
+			PINCTRL_GRP_UART0_4,
+			PINCTRL_GRP_UART0_5,
+			PINCTRL_GRP_UART0_6,
+			PINCTRL_GRP_UART0_7,
+			PINCTRL_GRP_UART0_8,
+			PINCTRL_GRP_UART0_9,
+			PINCTRL_GRP_UART0_10,
+			PINCTRL_GRP_UART0_11,
+			PINCTRL_GRP_UART0_12,
+			PINCTRL_GRP_UART0_13,
+			PINCTRL_GRP_UART0_14,
+			PINCTRL_GRP_UART0_15,
+			PINCTRL_GRP_UART0_16,
+			PINCTRL_GRP_UART0_17,
+			PINCTRL_GRP_UART0_18,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_UART1] = {
+		.name = "uart1",
+		.regval = 0xc0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_UART1_0,
+			PINCTRL_GRP_UART1_1,
+			PINCTRL_GRP_UART1_2,
+			PINCTRL_GRP_UART1_3,
+			PINCTRL_GRP_UART1_4,
+			PINCTRL_GRP_UART1_5,
+			PINCTRL_GRP_UART1_6,
+			PINCTRL_GRP_UART1_7,
+			PINCTRL_GRP_UART1_8,
+			PINCTRL_GRP_UART1_9,
+			PINCTRL_GRP_UART1_10,
+			PINCTRL_GRP_UART1_11,
+			PINCTRL_GRP_UART1_12,
+			PINCTRL_GRP_UART1_13,
+			PINCTRL_GRP_UART1_14,
+			PINCTRL_GRP_UART1_15,
+			PINCTRL_GRP_UART1_16,
+			PINCTRL_GRP_UART1_17,
+			PINCTRL_GRP_UART1_18,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_USB0] = {
+		.name = "usb0",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_USB0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_USB1] = {
+		.name = "usb1",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_USB1_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SWDT0_CLK] = {
+		.name = "swdt0_clk",
+		.regval = 0x60,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SWDT0_0_CLK,
+			PINCTRL_GRP_SWDT0_1_CLK,
+			PINCTRL_GRP_SWDT0_2_CLK,
+			PINCTRL_GRP_SWDT0_3_CLK,
+			PINCTRL_GRP_SWDT0_4_CLK,
+			PINCTRL_GRP_SWDT0_5_CLK,
+			PINCTRL_GRP_SWDT0_6_CLK,
+			PINCTRL_GRP_SWDT0_7_CLK,
+			PINCTRL_GRP_SWDT0_8_CLK,
+			PINCTRL_GRP_SWDT0_9_CLK,
+			PINCTRL_GRP_SWDT0_10_CLK,
+			PINCTRL_GRP_SWDT0_11_CLK,
+			PINCTRL_GRP_SWDT0_12_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SWDT0_RST] = {
+		.name = "swdt0_rst",
+		.regval = 0x60,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SWDT0_0_RST,
+			PINCTRL_GRP_SWDT0_1_RST,
+			PINCTRL_GRP_SWDT0_2_RST,
+			PINCTRL_GRP_SWDT0_3_RST,
+			PINCTRL_GRP_SWDT0_4_RST,
+			PINCTRL_GRP_SWDT0_5_RST,
+			PINCTRL_GRP_SWDT0_6_RST,
+			PINCTRL_GRP_SWDT0_7_RST,
+			PINCTRL_GRP_SWDT0_8_RST,
+			PINCTRL_GRP_SWDT0_9_RST,
+			PINCTRL_GRP_SWDT0_10_RST,
+			PINCTRL_GRP_SWDT0_11_RST,
+			PINCTRL_GRP_SWDT0_12_RST,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SWDT1_CLK] = {
+		.name = "swdt1_clk",
+		.regval = 0x60,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SWDT1_0_CLK,
+			PINCTRL_GRP_SWDT1_1_CLK,
+			PINCTRL_GRP_SWDT1_2_CLK,
+			PINCTRL_GRP_SWDT1_3_CLK,
+			PINCTRL_GRP_SWDT1_4_CLK,
+			PINCTRL_GRP_SWDT1_5_CLK,
+			PINCTRL_GRP_SWDT1_6_CLK,
+			PINCTRL_GRP_SWDT1_7_CLK,
+			PINCTRL_GRP_SWDT1_8_CLK,
+			PINCTRL_GRP_SWDT1_9_CLK,
+			PINCTRL_GRP_SWDT1_10_CLK,
+			PINCTRL_GRP_SWDT1_11_CLK,
+			PINCTRL_GRP_SWDT1_12_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_SWDT1_RST] = {
+		.name = "swdt1_rst",
+		.regval = 0x60,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_SWDT1_0_RST,
+			PINCTRL_GRP_SWDT1_1_RST,
+			PINCTRL_GRP_SWDT1_2_RST,
+			PINCTRL_GRP_SWDT1_3_RST,
+			PINCTRL_GRP_SWDT1_4_RST,
+			PINCTRL_GRP_SWDT1_5_RST,
+			PINCTRL_GRP_SWDT1_6_RST,
+			PINCTRL_GRP_SWDT1_7_RST,
+			PINCTRL_GRP_SWDT1_8_RST,
+			PINCTRL_GRP_SWDT1_9_RST,
+			PINCTRL_GRP_SWDT1_10_RST,
+			PINCTRL_GRP_SWDT1_11_RST,
+			PINCTRL_GRP_SWDT1_12_RST,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_PMU0] = {
+		.name = "pmu0",
+		.regval = 0x08,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_PMU0_0,
+			PINCTRL_GRP_PMU0_1,
+			PINCTRL_GRP_PMU0_2,
+			PINCTRL_GRP_PMU0_3,
+			PINCTRL_GRP_PMU0_4,
+			PINCTRL_GRP_PMU0_5,
+			PINCTRL_GRP_PMU0_6,
+			PINCTRL_GRP_PMU0_7,
+			PINCTRL_GRP_PMU0_8,
+			PINCTRL_GRP_PMU0_9,
+			PINCTRL_GRP_PMU0_10,
+			PINCTRL_GRP_PMU0_11,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_PCIE0] = {
+		.name = "pcie0",
+		.regval = 0x04,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_PCIE0_0,
+			PINCTRL_GRP_PCIE0_1,
+			PINCTRL_GRP_PCIE0_2,
+			PINCTRL_GRP_PCIE0_3,
+			PINCTRL_GRP_PCIE0_4,
+			PINCTRL_GRP_PCIE0_5,
+			PINCTRL_GRP_PCIE0_6,
+			PINCTRL_GRP_PCIE0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_CSU0] = {
+		.name = "csu0",
+		.regval = 0x18,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_CSU0_0,
+			PINCTRL_GRP_CSU0_1,
+			PINCTRL_GRP_CSU0_2,
+			PINCTRL_GRP_CSU0_3,
+			PINCTRL_GRP_CSU0_4,
+			PINCTRL_GRP_CSU0_5,
+			PINCTRL_GRP_CSU0_6,
+			PINCTRL_GRP_CSU0_7,
+			PINCTRL_GRP_CSU0_8,
+			PINCTRL_GRP_CSU0_9,
+			PINCTRL_GRP_CSU0_10,
+			PINCTRL_GRP_CSU0_11,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_DPAUX0] = {
+		.name = "dpaux0",
+		.regval = 0x18,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_DPAUX0_0,
+			PINCTRL_GRP_DPAUX0_1,
+			PINCTRL_GRP_DPAUX0_2,
+			PINCTRL_GRP_DPAUX0_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_PJTAG0] = {
+		.name = "pjtag0",
+		.regval = 0x60,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_PJTAG0_0,
+			PINCTRL_GRP_PJTAG0_1,
+			PINCTRL_GRP_PJTAG0_2,
+			PINCTRL_GRP_PJTAG0_3,
+			PINCTRL_GRP_PJTAG0_4,
+			PINCTRL_GRP_PJTAG0_5,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TRACE0] = {
+		.name = "trace0",
+		.regval = 0xe0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TRACE0_0,
+			PINCTRL_GRP_TRACE0_1,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TRACE0_CLK] = {
+		.name = "trace0_clk",
+		.regval = 0xe0,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TRACE0_0_CLK,
+			PINCTRL_GRP_TRACE0_1_CLK,
+			PINCTRL_GRP_TRACE0_2_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_FUNC_TESTSCAN0] = {
+		.name = "testscan0",
+		.regval = 0x10,
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_TESTSCAN0_0,
+			END_OF_GROUPS,
+		}),
+	},
+};
+
+static struct zynqmp_pin_group zynqmp_pin_groups[MAX_PIN] = {
+	[PINCTRL_PIN_0] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_0,
+			PINCTRL_GRP_CAN1_0,
+			PINCTRL_GRP_I2C1_0,
+			PINCTRL_GRP_PJTAG0_0,
+			PINCTRL_GRP_SPI0_0,
+			PINCTRL_GRP_TTC3_0_CLK,
+			PINCTRL_GRP_UART1_0,
+			PINCTRL_GRP_TRACE0_0_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_1] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_1,
+			PINCTRL_GRP_CAN1_0,
+			PINCTRL_GRP_I2C1_0,
+			PINCTRL_GRP_PJTAG0_0,
+			PINCTRL_GRP_SPI0_0_SS2,
+			PINCTRL_GRP_TTC3_0_WAV,
+			PINCTRL_GRP_UART1_0,
+			PINCTRL_GRP_TRACE0_0_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_2] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_2,
+			PINCTRL_GRP_CAN0_0,
+			PINCTRL_GRP_I2C0_0,
+			PINCTRL_GRP_PJTAG0_0,
+			PINCTRL_GRP_SPI0_0_SS1,
+			PINCTRL_GRP_TTC2_0_CLK,
+			PINCTRL_GRP_UART0_0,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_3] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_3,
+			PINCTRL_GRP_CAN0_0,
+			PINCTRL_GRP_I2C0_0,
+			PINCTRL_GRP_PJTAG0_0,
+			PINCTRL_GRP_SPI0_0_SS0,
+			PINCTRL_GRP_TTC2_0_WAV,
+			PINCTRL_GRP_UART0_0,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_4] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_4,
+			PINCTRL_GRP_CAN1_1,
+			PINCTRL_GRP_I2C1_1,
+			PINCTRL_GRP_SWDT1_0_CLK,
+			PINCTRL_GRP_SPI0_0,
+			PINCTRL_GRP_TTC1_0_CLK,
+			PINCTRL_GRP_UART1_1,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_5] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI_SS,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_5,
+			PINCTRL_GRP_CAN1_1,
+			PINCTRL_GRP_I2C1_1,
+			PINCTRL_GRP_SWDT1_0_RST,
+			PINCTRL_GRP_SPI0_0,
+			PINCTRL_GRP_TTC1_0_WAV,
+			PINCTRL_GRP_UART1_1,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_6] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI_FBCLK,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_6,
+			PINCTRL_GRP_CAN0_1,
+			PINCTRL_GRP_I2C0_1,
+			PINCTRL_GRP_SWDT0_0_CLK,
+			PINCTRL_GRP_SPI1_0,
+			PINCTRL_GRP_TTC0_0_CLK,
+			PINCTRL_GRP_UART0_1,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_7] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI_SS,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_7,
+			PINCTRL_GRP_CAN0_1,
+			PINCTRL_GRP_I2C0_1,
+			PINCTRL_GRP_SWDT0_0_RST,
+			PINCTRL_GRP_SPI1_0_SS2,
+			PINCTRL_GRP_TTC0_0_WAV,
+			PINCTRL_GRP_UART0_1,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_8] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_8,
+			PINCTRL_GRP_CAN1_2,
+			PINCTRL_GRP_I2C1_2,
+			PINCTRL_GRP_SWDT1_1_CLK,
+			PINCTRL_GRP_SPI1_0_SS1,
+			PINCTRL_GRP_TTC3_1_CLK,
+			PINCTRL_GRP_UART1_2,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_9] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_NAND0_0_CE,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_9,
+			PINCTRL_GRP_CAN1_2,
+			PINCTRL_GRP_I2C1_2,
+			PINCTRL_GRP_SWDT1_1_RST,
+			PINCTRL_GRP_SPI1_0_SS0,
+			PINCTRL_GRP_TTC3_1_WAV,
+			PINCTRL_GRP_UART1_2,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_10] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_NAND0_0_RB,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_10,
+			PINCTRL_GRP_CAN0_2,
+			PINCTRL_GRP_I2C0_2,
+			PINCTRL_GRP_SWDT0_1_CLK,
+			PINCTRL_GRP_SPI1_0,
+			PINCTRL_GRP_TTC2_1_CLK,
+			PINCTRL_GRP_UART0_2,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_11] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_NAND0_0_RB,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_11,
+			PINCTRL_GRP_CAN0_2,
+			PINCTRL_GRP_I2C0_2,
+			PINCTRL_GRP_SWDT0_1_RST,
+			PINCTRL_GRP_SPI1_0,
+			PINCTRL_GRP_TTC2_1_WAV,
+			PINCTRL_GRP_UART0_2,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_12] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_QSPI0_0,
+			PINCTRL_GRP_NAND0_0_DQS,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_12,
+			PINCTRL_GRP_CAN1_3,
+			PINCTRL_GRP_I2C1_3,
+			PINCTRL_GRP_PJTAG0_1,
+			PINCTRL_GRP_SPI0_1,
+			PINCTRL_GRP_TTC1_1_CLK,
+			PINCTRL_GRP_UART1_3,
+			PINCTRL_GRP_TRACE0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_13] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_13,
+			PINCTRL_GRP_CAN1_3,
+			PINCTRL_GRP_I2C1_3,
+			PINCTRL_GRP_PJTAG0_1,
+			PINCTRL_GRP_SPI0_1_SS2,
+			PINCTRL_GRP_TTC1_1_WAV,
+			PINCTRL_GRP_UART1_3,
+			PINCTRL_GRP_TRACE0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_14] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_14,
+			PINCTRL_GRP_CAN0_3,
+			PINCTRL_GRP_I2C0_3,
+			PINCTRL_GRP_PJTAG0_1,
+			PINCTRL_GRP_SPI0_1_SS1,
+			PINCTRL_GRP_TTC0_1_CLK,
+			PINCTRL_GRP_UART0_3,
+			PINCTRL_GRP_TRACE0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_15] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_15,
+			PINCTRL_GRP_CAN0_3,
+			PINCTRL_GRP_I2C0_3,
+			PINCTRL_GRP_PJTAG0_1,
+			PINCTRL_GRP_SPI0_1_SS0,
+			PINCTRL_GRP_TTC0_1_WAV,
+			PINCTRL_GRP_UART0_3,
+			PINCTRL_GRP_TRACE0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_16] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_16,
+			PINCTRL_GRP_CAN1_4,
+			PINCTRL_GRP_I2C1_4,
+			PINCTRL_GRP_SWDT1_2_CLK,
+			PINCTRL_GRP_SPI0_1,
+			PINCTRL_GRP_TTC3_2_CLK,
+			PINCTRL_GRP_UART1_4,
+			PINCTRL_GRP_TRACE0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_17] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_17,
+			PINCTRL_GRP_CAN1_4,
+			PINCTRL_GRP_I2C1_4,
+			PINCTRL_GRP_SWDT1_2_RST,
+			PINCTRL_GRP_SPI0_1,
+			PINCTRL_GRP_TTC3_2_WAV,
+			PINCTRL_GRP_UART1_4,
+			PINCTRL_GRP_TRACE0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_4,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_18] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_0,
+			PINCTRL_GRP_GPIO0_18,
+			PINCTRL_GRP_CAN0_4,
+			PINCTRL_GRP_I2C0_4,
+			PINCTRL_GRP_SWDT0_2_CLK,
+			PINCTRL_GRP_SPI1_1,
+			PINCTRL_GRP_TTC2_2_CLK,
+			PINCTRL_GRP_UART0_4,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_5,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_19] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_1,
+			PINCTRL_GRP_GPIO0_19,
+			PINCTRL_GRP_CAN0_4,
+			PINCTRL_GRP_I2C0_4,
+			PINCTRL_GRP_SWDT0_2_RST,
+			PINCTRL_GRP_SPI1_1_SS2,
+			PINCTRL_GRP_TTC2_2_WAV,
+			PINCTRL_GRP_UART0_4,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_6,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_20] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_2,
+			PINCTRL_GRP_GPIO0_20,
+			PINCTRL_GRP_CAN1_5,
+			PINCTRL_GRP_I2C1_5,
+			PINCTRL_GRP_SWDT1_3_CLK,
+			PINCTRL_GRP_SPI1_1_SS1,
+			PINCTRL_GRP_TTC1_2_CLK,
+			PINCTRL_GRP_UART1_5,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_21] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_3,
+			PINCTRL_GRP_GPIO0_21,
+			PINCTRL_GRP_CAN1_5,
+			PINCTRL_GRP_I2C1_5,
+			PINCTRL_GRP_SWDT1_3_RST,
+			PINCTRL_GRP_SPI1_1_SS0,
+			PINCTRL_GRP_TTC1_2_WAV,
+			PINCTRL_GRP_UART1_5,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_2,
+			PINCTRL_GRP_SDIO0_1BIT_0_3,
+			PINCTRL_GRP_SDIO0_1BIT_0_4,
+			PINCTRL_GRP_SDIO0_1BIT_0_5,
+			PINCTRL_GRP_SDIO0_1BIT_0_6,
+			PINCTRL_GRP_SDIO0_1BIT_0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_22] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_4,
+			PINCTRL_GRP_GPIO0_22,
+			PINCTRL_GRP_CAN0_5,
+			PINCTRL_GRP_I2C0_5,
+			PINCTRL_GRP_SWDT0_3_CLK,
+			PINCTRL_GRP_SPI1_1,
+			PINCTRL_GRP_TTC0_2_CLK,
+			PINCTRL_GRP_UART0_5,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_0_0,
+			PINCTRL_GRP_SDIO0_4BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_0,
+			PINCTRL_GRP_SDIO0_1BIT_0_1,
+			PINCTRL_GRP_SDIO0_1BIT_0_2,
+			PINCTRL_GRP_SDIO0_1BIT_0_3,
+			PINCTRL_GRP_SDIO0_1BIT_0_4,
+			PINCTRL_GRP_SDIO0_1BIT_0_5,
+			PINCTRL_GRP_SDIO0_1BIT_0_6,
+			PINCTRL_GRP_SDIO0_1BIT_0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_23] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0_PC,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_5,
+			PINCTRL_GRP_GPIO0_23,
+			PINCTRL_GRP_CAN0_5,
+			PINCTRL_GRP_I2C0_5,
+			PINCTRL_GRP_SWDT0_3_RST,
+			PINCTRL_GRP_SPI1_1,
+			PINCTRL_GRP_TTC0_2_WAV,
+			PINCTRL_GRP_UART0_5,
+			PINCTRL_GRP_RESERVED,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_24] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0_CD,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_6,
+			PINCTRL_GRP_GPIO0_24,
+			PINCTRL_GRP_CAN1_6,
+			PINCTRL_GRP_I2C1_6,
+			PINCTRL_GRP_SWDT1_4_CLK,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TTC3_3_CLK,
+			PINCTRL_GRP_UART1_6,
+			PINCTRL_GRP_RESERVED,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_25] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_NAND0_0,
+			PINCTRL_GRP_SDIO0_0_WP,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_7,
+			PINCTRL_GRP_GPIO0_25,
+			PINCTRL_GRP_CAN1_6,
+			PINCTRL_GRP_I2C1_6,
+			PINCTRL_GRP_SWDT1_4_RST,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_TTC3_3_WAV,
+			PINCTRL_GRP_UART1_6,
+			PINCTRL_GRP_RESERVED,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_26] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_GEMTSU0_0,
+			PINCTRL_GRP_NAND0_1_CE,
+			PINCTRL_GRP_PMU0_0,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_8,
+			PINCTRL_GRP_GPIO0_26,
+			PINCTRL_GRP_CAN0_6,
+			PINCTRL_GRP_I2C0_6,
+			PINCTRL_GRP_PJTAG0_2,
+			PINCTRL_GRP_SPI0_2,
+			PINCTRL_GRP_TTC2_3_CLK,
+			PINCTRL_GRP_UART0_6,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_27] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_NAND0_1_RB,
+			PINCTRL_GRP_PMU0_1,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_0,
+			PINCTRL_GRP_GPIO0_27,
+			PINCTRL_GRP_CAN0_6,
+			PINCTRL_GRP_I2C0_6,
+			PINCTRL_GRP_PJTAG0_2,
+			PINCTRL_GRP_SPI0_2_SS2,
+			PINCTRL_GRP_TTC2_3_WAV,
+			PINCTRL_GRP_UART0_6,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_28] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_NAND0_1_RB,
+			PINCTRL_GRP_PMU0_2,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_0,
+			PINCTRL_GRP_GPIO0_28,
+			PINCTRL_GRP_CAN1_7,
+			PINCTRL_GRP_I2C1_7,
+			PINCTRL_GRP_PJTAG0_2,
+			PINCTRL_GRP_SPI0_2_SS1,
+			PINCTRL_GRP_TTC1_3_CLK,
+			PINCTRL_GRP_UART1_7,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_29] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_0,
+			PINCTRL_GRP_PMU0_3,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_1,
+			PINCTRL_GRP_GPIO0_29,
+			PINCTRL_GRP_CAN1_7,
+			PINCTRL_GRP_I2C1_7,
+			PINCTRL_GRP_PJTAG0_2,
+			PINCTRL_GRP_SPI0_2_SS0,
+			PINCTRL_GRP_TTC1_3_WAV,
+			PINCTRL_GRP_UART1_7,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_30] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_1,
+			PINCTRL_GRP_PMU0_4,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_1,
+			PINCTRL_GRP_GPIO0_30,
+			PINCTRL_GRP_CAN0_7,
+			PINCTRL_GRP_I2C0_7,
+			PINCTRL_GRP_SWDT0_4_CLK,
+			PINCTRL_GRP_SPI0_2,
+			PINCTRL_GRP_TTC0_3_CLK,
+			PINCTRL_GRP_UART0_7,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_31] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_2,
+			PINCTRL_GRP_PMU0_5,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_9,
+			PINCTRL_GRP_GPIO0_31,
+			PINCTRL_GRP_CAN0_7,
+			PINCTRL_GRP_I2C0_7,
+			PINCTRL_GRP_SWDT0_4_RST,
+			PINCTRL_GRP_SPI0_2,
+			PINCTRL_GRP_TTC0_3_WAV,
+			PINCTRL_GRP_UART0_7,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_32] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_NAND0_1_DQS,
+			PINCTRL_GRP_PMU0_6,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_10,
+			PINCTRL_GRP_GPIO0_32,
+			PINCTRL_GRP_CAN1_8,
+			PINCTRL_GRP_I2C1_8,
+			PINCTRL_GRP_SWDT1_5_CLK,
+			PINCTRL_GRP_SPI1_2,
+			PINCTRL_GRP_TTC3_4_CLK,
+			PINCTRL_GRP_UART1_8,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_33] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_3,
+			PINCTRL_GRP_PMU0_7,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_CSU0_11,
+			PINCTRL_GRP_GPIO0_33,
+			PINCTRL_GRP_CAN1_8,
+			PINCTRL_GRP_I2C1_8,
+			PINCTRL_GRP_SWDT1_5_RST,
+			PINCTRL_GRP_SPI1_2_SS2,
+			PINCTRL_GRP_TTC3_4_WAV,
+			PINCTRL_GRP_UART1_8,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_34] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_4,
+			PINCTRL_GRP_PMU0_8,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_2,
+			PINCTRL_GRP_GPIO0_34,
+			PINCTRL_GRP_CAN0_8,
+			PINCTRL_GRP_I2C0_8,
+			PINCTRL_GRP_SWDT0_5_CLK,
+			PINCTRL_GRP_SPI1_2_SS1,
+			PINCTRL_GRP_TTC2_4_CLK,
+			PINCTRL_GRP_UART0_8,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_35] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_5,
+			PINCTRL_GRP_PMU0_9,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_2,
+			PINCTRL_GRP_GPIO0_35,
+			PINCTRL_GRP_CAN0_8,
+			PINCTRL_GRP_I2C0_8,
+			PINCTRL_GRP_SWDT0_5_RST,
+			PINCTRL_GRP_SPI1_2_SS0,
+			PINCTRL_GRP_TTC2_4_WAV,
+			PINCTRL_GRP_UART0_8,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_36] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_6,
+			PINCTRL_GRP_PMU0_10,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_3,
+			PINCTRL_GRP_GPIO0_36,
+			PINCTRL_GRP_CAN1_9,
+			PINCTRL_GRP_I2C1_9,
+			PINCTRL_GRP_SWDT1_6_CLK,
+			PINCTRL_GRP_SPI1_2,
+			PINCTRL_GRP_TTC1_4_CLK,
+			PINCTRL_GRP_UART1_9,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_37] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET0_0,
+			PINCTRL_GRP_PCIE0_7,
+			PINCTRL_GRP_PMU0_11,
+			PINCTRL_GRP_TESTSCAN0_0,
+			PINCTRL_GRP_DPAUX0_3,
+			PINCTRL_GRP_GPIO0_37,
+			PINCTRL_GRP_CAN1_9,
+			PINCTRL_GRP_I2C1_9,
+			PINCTRL_GRP_SWDT1_6_RST,
+			PINCTRL_GRP_SPI1_2,
+			PINCTRL_GRP_TTC1_4_WAV,
+			PINCTRL_GRP_UART1_9,
+			PINCTRL_GRP_TRACE0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_38] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_38,
+			PINCTRL_GRP_CAN0_9,
+			PINCTRL_GRP_I2C0_9,
+			PINCTRL_GRP_PJTAG0_3,
+			PINCTRL_GRP_SPI0_3,
+			PINCTRL_GRP_TTC0_4_CLK,
+			PINCTRL_GRP_UART0_9,
+			PINCTRL_GRP_TRACE0_1_CLK,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_2,
+			PINCTRL_GRP_SDIO0_1BIT_1_3,
+			PINCTRL_GRP_SDIO0_1BIT_1_4,
+			PINCTRL_GRP_SDIO0_1BIT_1_5,
+			PINCTRL_GRP_SDIO0_1BIT_1_6,
+			PINCTRL_GRP_SDIO0_1BIT_1_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_39] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1_CD,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_39,
+			PINCTRL_GRP_CAN0_9,
+			PINCTRL_GRP_I2C0_9,
+			PINCTRL_GRP_PJTAG0_3,
+			PINCTRL_GRP_SPI0_3_SS2,
+			PINCTRL_GRP_TTC0_4_WAV,
+			PINCTRL_GRP_UART0_9,
+			PINCTRL_GRP_TRACE0_1_CLK,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_40] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_40,
+			PINCTRL_GRP_CAN1_10,
+			PINCTRL_GRP_I2C1_10,
+			PINCTRL_GRP_PJTAG0_3,
+			PINCTRL_GRP_SPI0_3_SS1,
+			PINCTRL_GRP_TTC3_5_CLK,
+			PINCTRL_GRP_UART1_10,
+			PINCTRL_GRP_TRACE0_1,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_2,
+			PINCTRL_GRP_SDIO0_1BIT_1_3,
+			PINCTRL_GRP_SDIO0_1BIT_1_4,
+			PINCTRL_GRP_SDIO0_1BIT_1_5,
+			PINCTRL_GRP_SDIO0_1BIT_1_6,
+			PINCTRL_GRP_SDIO0_1BIT_1_7,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_41] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_41,
+			PINCTRL_GRP_CAN1_10,
+			PINCTRL_GRP_I2C1_10,
+			PINCTRL_GRP_PJTAG0_3,
+			PINCTRL_GRP_SPI0_3_SS0,
+			PINCTRL_GRP_TTC3_5_WAV,
+			PINCTRL_GRP_UART1_10,
+			PINCTRL_GRP_TRACE0_1,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_0,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_42] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_42,
+			PINCTRL_GRP_CAN0_10,
+			PINCTRL_GRP_I2C0_10,
+			PINCTRL_GRP_SWDT0_6_CLK,
+			PINCTRL_GRP_SPI0_3,
+			PINCTRL_GRP_TTC2_5_CLK,
+			PINCTRL_GRP_UART0_10,
+			PINCTRL_GRP_TRACE0_1,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_1,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_43] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0_PC,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_43,
+			PINCTRL_GRP_CAN0_10,
+			PINCTRL_GRP_I2C0_10,
+			PINCTRL_GRP_SWDT0_6_RST,
+			PINCTRL_GRP_SPI0_3,
+			PINCTRL_GRP_TTC2_5_WAV,
+			PINCTRL_GRP_UART0_10,
+			PINCTRL_GRP_TRACE0_1,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_44] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0_WP,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_44,
+			PINCTRL_GRP_CAN1_11,
+			PINCTRL_GRP_I2C1_11,
+			PINCTRL_GRP_SWDT1_7_CLK,
+			PINCTRL_GRP_SPI1_3,
+			PINCTRL_GRP_TTC1_5_CLK,
+			PINCTRL_GRP_UART1_11,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_1_0,
+			PINCTRL_GRP_SDIO0_1BIT_1_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_45] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0_CD,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_45,
+			PINCTRL_GRP_CAN1_11,
+			PINCTRL_GRP_I2C1_11,
+			PINCTRL_GRP_SWDT1_7_RST,
+			PINCTRL_GRP_SPI1_3_SS2,
+			PINCTRL_GRP_TTC1_5_WAV,
+			PINCTRL_GRP_UART1_11,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_4,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_46] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_46,
+			PINCTRL_GRP_CAN0_11,
+			PINCTRL_GRP_I2C0_11,
+			PINCTRL_GRP_SWDT0_7_CLK,
+			PINCTRL_GRP_SPI1_3_SS1,
+			PINCTRL_GRP_TTC0_5_CLK,
+			PINCTRL_GRP_UART0_11,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_5,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_4,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_47] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_47,
+			PINCTRL_GRP_CAN0_11,
+			PINCTRL_GRP_I2C0_11,
+			PINCTRL_GRP_SWDT0_7_RST,
+			PINCTRL_GRP_SPI1_3_SS0,
+			PINCTRL_GRP_TTC0_5_WAV,
+			PINCTRL_GRP_UART0_11,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_6,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_5,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_48] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_48,
+			PINCTRL_GRP_CAN1_12,
+			PINCTRL_GRP_I2C1_12,
+			PINCTRL_GRP_SWDT1_8_CLK,
+			PINCTRL_GRP_SPI1_3,
+			PINCTRL_GRP_TTC3_6_CLK,
+			PINCTRL_GRP_UART1_12,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_1_1,
+			PINCTRL_GRP_SDIO0_1BIT_1_7,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_6,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_49] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1_PC,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_49,
+			PINCTRL_GRP_CAN1_12,
+			PINCTRL_GRP_I2C1_12,
+			PINCTRL_GRP_SWDT1_8_RST,
+			PINCTRL_GRP_SPI1_3,
+			PINCTRL_GRP_TTC3_6_WAV,
+			PINCTRL_GRP_UART1_12,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_50] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_GEMTSU0_1,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_1_WP,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_50,
+			PINCTRL_GRP_CAN0_12,
+			PINCTRL_GRP_I2C0_12,
+			PINCTRL_GRP_SWDT0_8_CLK,
+			PINCTRL_GRP_MDIO1_0,
+			PINCTRL_GRP_TTC2_6_CLK,
+			PINCTRL_GRP_UART0_12,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_2,
+			PINCTRL_GRP_SDIO1_1BIT_0_3,
+			PINCTRL_GRP_SDIO1_1BIT_0_4,
+			PINCTRL_GRP_SDIO1_1BIT_0_5,
+			PINCTRL_GRP_SDIO1_1BIT_0_6,
+			PINCTRL_GRP_SDIO1_1BIT_0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_51] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_GEMTSU0_2,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_51,
+			PINCTRL_GRP_CAN0_12,
+			PINCTRL_GRP_I2C0_12,
+			PINCTRL_GRP_SWDT0_8_RST,
+			PINCTRL_GRP_MDIO1_0,
+			PINCTRL_GRP_TTC2_6_WAV,
+			PINCTRL_GRP_UART0_12,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_4BIT_0_0,
+			PINCTRL_GRP_SDIO1_4BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_0,
+			PINCTRL_GRP_SDIO1_1BIT_0_1,
+			PINCTRL_GRP_SDIO1_1BIT_0_2,
+			PINCTRL_GRP_SDIO1_1BIT_0_3,
+			PINCTRL_GRP_SDIO1_1BIT_0_4,
+			PINCTRL_GRP_SDIO1_1BIT_0_5,
+			PINCTRL_GRP_SDIO1_1BIT_0_6,
+			PINCTRL_GRP_SDIO1_1BIT_0_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_52] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_52,
+			PINCTRL_GRP_CAN1_13,
+			PINCTRL_GRP_I2C1_13,
+			PINCTRL_GRP_PJTAG0_4,
+			PINCTRL_GRP_SPI0_4,
+			PINCTRL_GRP_TTC1_6_CLK,
+			PINCTRL_GRP_UART1_13,
+			PINCTRL_GRP_TRACE0_2_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_53] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_53,
+			PINCTRL_GRP_CAN1_13,
+			PINCTRL_GRP_I2C1_13,
+			PINCTRL_GRP_PJTAG0_4,
+			PINCTRL_GRP_SPI0_4_SS2,
+			PINCTRL_GRP_TTC1_6_WAV,
+			PINCTRL_GRP_UART1_13,
+			PINCTRL_GRP_TRACE0_2_CLK,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_54] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_54,
+			PINCTRL_GRP_CAN0_13,
+			PINCTRL_GRP_I2C0_13,
+			PINCTRL_GRP_PJTAG0_4,
+			PINCTRL_GRP_SPI0_4_SS1,
+			PINCTRL_GRP_TTC0_6_CLK,
+			PINCTRL_GRP_UART0_13,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_55] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_55,
+			PINCTRL_GRP_CAN0_13,
+			PINCTRL_GRP_I2C0_13,
+			PINCTRL_GRP_PJTAG0_4,
+			PINCTRL_GRP_SPI0_4_SS0,
+			PINCTRL_GRP_TTC0_6_WAV,
+			PINCTRL_GRP_UART0_13,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_56] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_56,
+			PINCTRL_GRP_CAN1_14,
+			PINCTRL_GRP_I2C1_14,
+			PINCTRL_GRP_SWDT1_9_CLK,
+			PINCTRL_GRP_SPI0_4,
+			PINCTRL_GRP_TTC3_7_CLK,
+			PINCTRL_GRP_UART1_14,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_57] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_57,
+			PINCTRL_GRP_CAN1_14,
+			PINCTRL_GRP_I2C1_14,
+			PINCTRL_GRP_SWDT1_9_RST,
+			PINCTRL_GRP_SPI0_4,
+			PINCTRL_GRP_TTC3_7_WAV,
+			PINCTRL_GRP_UART1_14,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_58] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_58,
+			PINCTRL_GRP_CAN0_14,
+			PINCTRL_GRP_I2C0_14,
+			PINCTRL_GRP_PJTAG0_5,
+			PINCTRL_GRP_SPI1_4,
+			PINCTRL_GRP_TTC2_7_CLK,
+			PINCTRL_GRP_UART0_14,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_59] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_59,
+			PINCTRL_GRP_CAN0_14,
+			PINCTRL_GRP_I2C0_14,
+			PINCTRL_GRP_PJTAG0_5,
+			PINCTRL_GRP_SPI1_4_SS2,
+			PINCTRL_GRP_TTC2_7_WAV,
+			PINCTRL_GRP_UART0_14,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_60] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_60,
+			PINCTRL_GRP_CAN1_15,
+			PINCTRL_GRP_I2C1_15,
+			PINCTRL_GRP_PJTAG0_5,
+			PINCTRL_GRP_SPI1_4_SS1,
+			PINCTRL_GRP_TTC1_7_CLK,
+			PINCTRL_GRP_UART1_15,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_61] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_61,
+			PINCTRL_GRP_CAN1_15,
+			PINCTRL_GRP_I2C1_15,
+			PINCTRL_GRP_PJTAG0_5,
+			PINCTRL_GRP_SPI1_4_SS0,
+			PINCTRL_GRP_TTC1_7_WAV,
+			PINCTRL_GRP_UART1_15,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_62] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_62,
+			PINCTRL_GRP_CAN0_15,
+			PINCTRL_GRP_I2C0_15,
+			PINCTRL_GRP_SWDT0_9_CLK,
+			PINCTRL_GRP_SPI1_4,
+			PINCTRL_GRP_TTC0_7_CLK,
+			PINCTRL_GRP_UART0_15,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_63] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET2_0,
+			PINCTRL_GRP_USB0_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_63,
+			PINCTRL_GRP_CAN0_15,
+			PINCTRL_GRP_I2C0_15,
+			PINCTRL_GRP_SWDT0_9_RST,
+			PINCTRL_GRP_SPI1_4,
+			PINCTRL_GRP_TTC0_7_WAV,
+			PINCTRL_GRP_UART0_15,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_64] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_64,
+			PINCTRL_GRP_CAN1_16,
+			PINCTRL_GRP_I2C1_16,
+			PINCTRL_GRP_SWDT1_10_CLK,
+			PINCTRL_GRP_SPI0_5,
+			PINCTRL_GRP_TTC3_8_CLK,
+			PINCTRL_GRP_UART1_16,
+			PINCTRL_GRP_TRACE0_2,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_2,
+			PINCTRL_GRP_SDIO0_1BIT_2_3,
+			PINCTRL_GRP_SDIO0_1BIT_2_4,
+			PINCTRL_GRP_SDIO0_1BIT_2_5,
+			PINCTRL_GRP_SDIO0_1BIT_2_6,
+			PINCTRL_GRP_SDIO0_1BIT_2_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_65] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2_CD,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_65,
+			PINCTRL_GRP_CAN1_16,
+			PINCTRL_GRP_I2C1_16,
+			PINCTRL_GRP_SWDT1_10_RST,
+			PINCTRL_GRP_SPI0_5_SS2,
+			PINCTRL_GRP_TTC3_8_WAV,
+			PINCTRL_GRP_UART1_16,
+			PINCTRL_GRP_TRACE0_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_66] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_66,
+			PINCTRL_GRP_CAN0_16,
+			PINCTRL_GRP_I2C0_16,
+			PINCTRL_GRP_SWDT0_10_CLK,
+			PINCTRL_GRP_SPI0_5_SS1,
+			PINCTRL_GRP_TTC2_8_CLK,
+			PINCTRL_GRP_UART0_16,
+			PINCTRL_GRP_TRACE0_2,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_2,
+			PINCTRL_GRP_SDIO0_1BIT_2_3,
+			PINCTRL_GRP_SDIO0_1BIT_2_4,
+			PINCTRL_GRP_SDIO0_1BIT_2_5,
+			PINCTRL_GRP_SDIO0_1BIT_2_6,
+			PINCTRL_GRP_SDIO0_1BIT_2_7,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_67] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_67,
+			PINCTRL_GRP_CAN0_16,
+			PINCTRL_GRP_I2C0_16,
+			PINCTRL_GRP_SWDT0_10_RST,
+			PINCTRL_GRP_SPI0_5_SS0,
+			PINCTRL_GRP_TTC2_8_WAV,
+			PINCTRL_GRP_UART0_16,
+			PINCTRL_GRP_TRACE0_2,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_68] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_68,
+			PINCTRL_GRP_CAN1_17,
+			PINCTRL_GRP_I2C1_17,
+			PINCTRL_GRP_SWDT1_11_CLK,
+			PINCTRL_GRP_SPI0_5,
+			PINCTRL_GRP_TTC1_8_CLK,
+			PINCTRL_GRP_UART1_17,
+			PINCTRL_GRP_TRACE0_2,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_69] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO1_1_WP,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_69,
+			PINCTRL_GRP_CAN1_17,
+			PINCTRL_GRP_I2C1_17,
+			PINCTRL_GRP_SWDT1_11_RST,
+			PINCTRL_GRP_SPI0_5,
+			PINCTRL_GRP_TTC1_8_WAV,
+			PINCTRL_GRP_UART1_17,
+			PINCTRL_GRP_TRACE0_2,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_70] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO1_1_PC,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_70,
+			PINCTRL_GRP_CAN0_17,
+			PINCTRL_GRP_I2C0_17,
+			PINCTRL_GRP_SWDT0_11_CLK,
+			PINCTRL_GRP_SPI1_5,
+			PINCTRL_GRP_TTC0_8_CLK,
+			PINCTRL_GRP_UART0_17,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_2_0,
+			PINCTRL_GRP_SDIO0_1BIT_2_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_71] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_71,
+			PINCTRL_GRP_CAN0_17,
+			PINCTRL_GRP_I2C0_17,
+			PINCTRL_GRP_SWDT0_11_RST,
+			PINCTRL_GRP_SPI1_5_SS2,
+			PINCTRL_GRP_TTC0_8_WAV,
+			PINCTRL_GRP_UART0_17,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_4,
+			PINCTRL_GRP_SDIO1_1BIT_1_0,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_72] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_72,
+			PINCTRL_GRP_CAN1_18,
+			PINCTRL_GRP_I2C1_18,
+			PINCTRL_GRP_SWDT1_12_CLK,
+			PINCTRL_GRP_SPI1_5_SS1,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_UART1_18,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_5,
+			PINCTRL_GRP_SDIO1_1BIT_1_1,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_73] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_73,
+			PINCTRL_GRP_CAN1_18,
+			PINCTRL_GRP_I2C1_18,
+			PINCTRL_GRP_SWDT1_12_RST,
+			PINCTRL_GRP_SPI1_5_SS0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_UART1_18,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_6,
+			PINCTRL_GRP_SDIO1_1BIT_1_2,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_74] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_74,
+			PINCTRL_GRP_CAN0_18,
+			PINCTRL_GRP_I2C0_18,
+			PINCTRL_GRP_SWDT0_12_CLK,
+			PINCTRL_GRP_SPI1_5,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_UART0_18,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_4BIT_2_1,
+			PINCTRL_GRP_SDIO0_1BIT_2_7,
+			PINCTRL_GRP_SDIO1_1BIT_1_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_75] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_ETHERNET3_0,
+			PINCTRL_GRP_USB1_0,
+			PINCTRL_GRP_SDIO0_2_PC,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_75,
+			PINCTRL_GRP_CAN0_18,
+			PINCTRL_GRP_I2C0_18,
+			PINCTRL_GRP_SWDT0_12_RST,
+			PINCTRL_GRP_SPI1_5,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_UART0_18,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_1BIT_1_0,
+			PINCTRL_GRP_SDIO1_1BIT_1_1,
+			PINCTRL_GRP_SDIO1_1BIT_1_2,
+			PINCTRL_GRP_SDIO1_1BIT_1_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_76] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO0_2_WP,
+			PINCTRL_GRP_SDIO1_4BIT_1_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_76,
+			PINCTRL_GRP_CAN1_19,
+			PINCTRL_GRP_I2C1_19,
+			PINCTRL_GRP_MDIO0_0,
+			PINCTRL_GRP_MDIO1_1,
+			PINCTRL_GRP_MDIO2_0,
+			PINCTRL_GRP_MDIO3_0,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_1BIT_1_0,
+			PINCTRL_GRP_SDIO1_1BIT_1_1,
+			PINCTRL_GRP_SDIO1_1BIT_1_2,
+			PINCTRL_GRP_SDIO1_1BIT_1_3,
+			END_OF_GROUPS,
+		}),
+	},
+	[PINCTRL_PIN_77] = {
+		.groups = &((uint16_t []) {
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_SDIO1_1_CD,
+			PINCTRL_GRP_RESERVED,
+			PINCTRL_GRP_GPIO0_77,
+			PINCTRL_GRP_CAN1_19,
+			PINCTRL_GRP_I2C1_19,
+			PINCTRL_GRP_MDIO0_0,
+			PINCTRL_GRP_MDIO1_1,
+			PINCTRL_GRP_MDIO2_0,
+			PINCTRL_GRP_MDIO3_0,
+			PINCTRL_GRP_RESERVED,
+			END_OF_GROUPS,
+		}),
+	},
+};
+
+/**
+ * pm_api_pinctrl_get_num_pins() - PM call to request number of pins
+ * @npins	Number of pins
+ *
+ * This function is used by master to get number of pins
+ *
+ * @return	Returns success.
+ */
+enum pm_ret_status pm_api_pinctrl_get_num_pins(unsigned int *npins)
+{
+	*npins = MAX_PIN;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_num_functions() - PM call to request number of functions
+ * @nfuncs	Number of functions
+ *
+ * This function is used by master to get number of functions
+ *
+ * @return	Returns success.
+ */
+enum pm_ret_status pm_api_pinctrl_get_num_functions(unsigned int *nfuncs)
+{
+	*nfuncs = MAX_FUNCTION;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_num_func_groups() - PM call to request number of
+ *					  function groups
+ * @fid		Function Id
+ * @ngroups	Number of function groups
+ *
+ * This function is used by master to get number of function groups
+ *
+ * @return	Returns success.
+ */
+enum pm_ret_status pm_api_pinctrl_get_num_func_groups(unsigned int fid,
+						      unsigned int *ngroups)
+{
+	int i = 0;
+	uint16_t *grps;
+
+	if (fid >= MAX_FUNCTION)
+		return PM_RET_ERROR_ARGS;
+
+	*ngroups = 0;
+
+	grps = *pinctrl_functions[fid].groups;
+	if (grps == NULL)
+		return PM_RET_SUCCESS;
+
+	while (grps[i++] != (uint16_t)END_OF_GROUPS)
+		(*ngroups)++;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_function_name() - PM call to request a function name
+ * @fid		Function ID
+ * @name	Name of function (max 16 bytes)
+ *
+ * This function is used by master to get name of function specified
+ * by given function ID.
+ *
+ * @return	Returns success. In case of error, name data is 0.
+ */
+enum pm_ret_status pm_api_pinctrl_get_function_name(unsigned int fid,
+						    char *name)
+{
+	if (fid >= MAX_FUNCTION)
+		memcpy(name, END_OF_FUNCTION, FUNCTION_NAME_LEN);
+	else
+		memcpy(name, pinctrl_functions[fid].name, FUNCTION_NAME_LEN);
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_function_groups() - PM call to request first 6 function
+ *					  groups of function Id
+ * @fid		Function ID
+ * @index	Index of next function groups
+ * @groups	Function groups
+ *
+ * This function is used by master to get function groups specified
+ * by given function Id. This API will return 6 function groups with
+ * a single response. To get other function groups, master should call
+ * same API in loop with new function groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return function groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * function groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_api_pinctrl_get_function_groups(unsigned int fid,
+						      unsigned int index,
+						      uint16_t *groups)
+{
+	unsigned int i;
+	uint16_t *grps;
+
+	if (fid >= MAX_FUNCTION)
+		return PM_RET_ERROR_ARGS;
+
+	memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN);
+
+	grps = *pinctrl_functions[fid].groups;
+	if (grps == NULL)
+		return PM_RET_SUCCESS;
+
+	/* Skip groups till index */
+	for (i = 0; i < index; i++)
+		if (grps[i] == (uint16_t)END_OF_GROUPS)
+			return PM_RET_SUCCESS;
+
+	for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+		groups[i] = grps[index + i];
+		if (groups[i] == (uint16_t)END_OF_GROUPS)
+			break;
+	}
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_pin_groups() - PM call to request first 6 pin
+ *				     groups of pin
+ * @pin		Pin
+ * @index	Index of next pin groups
+ * @groups	pin groups
+ *
+ * This function is used by master to get pin groups specified
+ * by given pin Id. This API will return 6 pin groups with
+ * a single response. To get other pin groups, master should call
+ * same API in loop with new pin groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return pin groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * pin groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_api_pinctrl_get_pin_groups(unsigned int pin,
+						 unsigned int index,
+						 uint16_t *groups)
+{
+	unsigned int i;
+	uint16_t *grps;
+
+	if (pin >= MAX_PIN)
+		return PM_RET_ERROR_ARGS;
+
+	memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN);
+
+	grps = *zynqmp_pin_groups[pin].groups;
+	if (!grps)
+		return PM_RET_SUCCESS;
+
+	/* Skip groups till index */
+	for (i = 0; i < index; i++)
+		if (grps[i] == (uint16_t)END_OF_GROUPS)
+			return PM_RET_SUCCESS;
+
+	for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+		groups[i] = grps[index + i];
+		if (groups[i] == (uint16_t)END_OF_GROUPS)
+			break;
+	}
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_function() - Read function id set for the given pin
+ * @pin		Pin number
+ * @nid		Node ID of function currently set for given pin
+ *
+ * This function provides the function currently set for the given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_pinctrl_get_function(unsigned int pin,
+					       unsigned int *id)
+{
+	unsigned int i = 0, j = 0;
+	enum pm_ret_status ret = PM_RET_SUCCESS;
+	unsigned int ctrlreg, val, gid;
+	uint16_t *grps;
+
+	ctrlreg = IOU_SLCR_BASEADDR + 4U * pin;
+	ret = pm_mmio_read(ctrlreg, &val);
+	if (ret != PM_RET_SUCCESS)
+		return ret;
+
+	val &= PINCTRL_FUNCTION_MASK;
+
+	for (i = 0; i < NFUNCS_PER_PIN; i++)
+		if (val == pm_pinctrl_mux[i])
+			break;
+
+	if (i == NFUNCS_PER_PIN)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	gid = *(*zynqmp_pin_groups[pin].groups + i);
+
+	for (i = 0; i < MAX_FUNCTION; i++) {
+		grps = *pinctrl_functions[i].groups;
+		if (grps == NULL)
+			continue;
+		if (val != pinctrl_functions[i].regval)
+			continue;
+
+		for (j = 0; grps[j] != (uint16_t)END_OF_GROUPS; j++) {
+			if (gid == grps[j]) {
+				*id = i;
+				goto done;
+			}
+		}
+	}
+	if (i == MAX_FUNCTION)
+		ret = PM_RET_ERROR_ARGS;
+done:
+	return ret;
+}
+
+/**
+ * pm_api_pinctrl_set_function() - Set function id set for the given pin
+ * @pin		Pin number
+ * @nid		Node ID of function to set for given pin
+ *
+ * This function provides the function currently set for the given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_pinctrl_set_function(unsigned int pin,
+					       unsigned int fid)
+{
+	int i, j;
+	unsigned int ctrlreg, val;
+	uint16_t *pgrps, *fgrps;
+
+	ctrlreg = IOU_SLCR_BASEADDR + 4U * pin;
+	val = pinctrl_functions[fid].regval;
+
+	for (i = 0; i < NFUNCS_PER_PIN; i++)
+		if (val == pm_pinctrl_mux[i])
+			break;
+
+	if (i == NFUNCS_PER_PIN)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	pgrps = *zynqmp_pin_groups[pin].groups;
+	if (!pgrps)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	fgrps = *pinctrl_functions[fid].groups;
+	if (!fgrps)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	for (i = 0; fgrps[i] != (uint16_t)END_OF_GROUPS; i++)
+		for (j = 0; pgrps[j] != (uint16_t)END_OF_GROUPS; j++)
+			if (fgrps[i] == pgrps[j])
+				goto match;
+
+	return PM_RET_ERROR_NOTSUPPORTED;
+
+match:
+	return pm_mmio_write(ctrlreg, PINCTRL_FUNCTION_MASK, val);
+}
+
+/**
+ * pm_api_pinctrl_set_config() - Set configuration parameter for given pin
+ * @pin: Pin for which configuration is to be set
+ * @param: Configuration parameter to be set
+ * @value: Value to be set for configuration parameter
+ *
+ * This function sets value of requested configuration parameter for given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_pinctrl_set_config(unsigned int pin,
+					     unsigned int param,
+					     unsigned int value)
+{
+	enum pm_ret_status ret;
+	unsigned int ctrlreg, mask, val, offset;
+
+	if (param >= PINCTRL_CONFIG_MAX)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	if (pin >=  PINCTRL_NUM_MIOS)
+		return PM_RET_ERROR_ARGS;
+
+	mask = 1 << PINCTRL_PIN_OFFSET(pin);
+
+	switch (param) {
+	case PINCTRL_CONFIG_SLEW_RATE:
+		if (value != PINCTRL_SLEW_RATE_FAST &&
+		    value != PINCTRL_SLEW_RATE_SLOW)
+			return PM_RET_ERROR_ARGS;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_SLEWCTRL_REG_OFFSET,
+					      pin);
+		val = value << PINCTRL_PIN_OFFSET(pin);
+		ret = pm_mmio_write(ctrlreg, mask, val);
+		break;
+	case PINCTRL_CONFIG_BIAS_STATUS:
+		if (value != PINCTRL_BIAS_ENABLE &&
+		    value != PINCTRL_BIAS_DISABLE)
+			return PM_RET_ERROR_ARGS;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_PULLSTAT_REG_OFFSET,
+					      pin);
+
+		offset = PINCTRL_PIN_OFFSET(pin);
+		if (ctrlreg == IOU_SLCR_BANK1_CTRL5)
+			offset = (offset < 12U) ?
+					(offset + 14U) : (offset - 12U);
+
+		val = value << offset;
+		mask = 1 << offset;
+		ret = pm_mmio_write(ctrlreg, mask, val);
+		break;
+	case PINCTRL_CONFIG_PULL_CTRL:
+
+		if (value != PINCTRL_BIAS_PULL_DOWN &&
+		    value != PINCTRL_BIAS_PULL_UP)
+			return PM_RET_ERROR_ARGS;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_PULLSTAT_REG_OFFSET,
+					      pin);
+
+		offset = PINCTRL_PIN_OFFSET(pin);
+		if (ctrlreg == IOU_SLCR_BANK1_CTRL5)
+			offset = (offset < 12U) ?
+					(offset + 14U) : (offset - 12U);
+
+		val = PINCTRL_BIAS_ENABLE << offset;
+		ret = pm_mmio_write(ctrlreg, 1 << offset, val);
+		if (ret != PM_RET_SUCCESS)
+			return ret;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_PULLCTRL_REG_OFFSET,
+					      pin);
+		val = value << PINCTRL_PIN_OFFSET(pin);
+		ret = pm_mmio_write(ctrlreg, mask, val);
+		break;
+	case PINCTRL_CONFIG_SCHMITT_CMOS:
+		if (value != PINCTRL_INPUT_TYPE_CMOS &&
+		    value != PINCTRL_INPUT_TYPE_SCHMITT)
+			return PM_RET_ERROR_ARGS;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_SCHCMOS_REG_OFFSET,
+					      pin);
+
+		val = value << PINCTRL_PIN_OFFSET(pin);
+		ret = pm_mmio_write(ctrlreg, mask, val);
+		break;
+	case PINCTRL_CONFIG_DRIVE_STRENGTH:
+		if (value > PINCTRL_DRIVE_STRENGTH_12MA)
+			return PM_RET_ERROR_ARGS;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_DRVSTRN0_REG_OFFSET,
+					      pin);
+		val = (value >> 1) << PINCTRL_PIN_OFFSET(pin);
+		ret = pm_mmio_write(ctrlreg, mask, val);
+		if (ret)
+			return ret;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_DRVSTRN1_REG_OFFSET,
+					      pin);
+		val = (value & 0x01U) << PINCTRL_PIN_OFFSET(pin);
+		ret = pm_mmio_write(ctrlreg, mask, val);
+		break;
+	default:
+		ERROR("Invalid parameter %u\n", param);
+		ret = PM_RET_ERROR_NOTSUPPORTED;
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * pm_api_pinctrl_get_config() - Get configuration parameter value for given pin
+ * @pin: Pin for which configuration is to be read
+ * @param: Configuration parameter to be read
+ * @value: buffer to store value of configuration parameter
+ *
+ * This function reads value of requested configuration parameter for given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_pinctrl_get_config(unsigned int pin,
+					     unsigned int param,
+					     unsigned int *value)
+{
+	enum pm_ret_status ret;
+	unsigned int ctrlreg, val;
+
+	if (param >= PINCTRL_CONFIG_MAX)
+		return PM_RET_ERROR_NOTSUPPORTED;
+
+	if (pin >=  PINCTRL_NUM_MIOS)
+		return PM_RET_ERROR_ARGS;
+
+	switch (param) {
+	case PINCTRL_CONFIG_SLEW_RATE:
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_SLEWCTRL_REG_OFFSET,
+					      pin);
+
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret != PM_RET_SUCCESS)
+			return ret;
+
+		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
+		break;
+	case PINCTRL_CONFIG_BIAS_STATUS:
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_PULLSTAT_REG_OFFSET,
+					      pin);
+
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret)
+			return ret;
+
+		if (ctrlreg == IOU_SLCR_BANK1_CTRL5)
+			val = ((val & 0x3FFF) << 12) | ((val >> 14) & 0xFFF);
+
+		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
+		break;
+	case PINCTRL_CONFIG_PULL_CTRL:
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_PULLCTRL_REG_OFFSET,
+					      pin);
+
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret)
+			return ret;
+
+		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
+		break;
+	case PINCTRL_CONFIG_SCHMITT_CMOS:
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_SCHCMOS_REG_OFFSET,
+					      pin);
+
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret)
+			return ret;
+
+		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
+		break;
+	case PINCTRL_CONFIG_DRIVE_STRENGTH:
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_DRVSTRN0_REG_OFFSET,
+					      pin);
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret)
+			return ret;
+
+		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val) << 1;
+
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_DRVSTRN1_REG_OFFSET,
+					      pin);
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret)
+			return ret;
+
+		*value |= PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
+		break;
+	case PINCTRL_CONFIG_VOLTAGE_STATUS:
+		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
+					      PINCTRL_VOLTAGE_STAT_REG_OFFSET,
+					      pin);
+
+		ret = pm_mmio_read(ctrlreg, &val);
+		if (ret)
+			return ret;
+
+		*value = val & PINCTRL_VOLTAGE_STATUS_MASK;
+		break;
+	default:
+		return PM_RET_ERROR_NOTSUPPORTED;
+	}
+
+	return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
new file mode 100644
index 0000000..9923c00
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#ifndef PM_API_PINCTRL_H
+#define PM_API_PINCTRL_H
+
+#include "pm_common.h"
+
+#define FUNCTION_NAME_LEN		U(16)
+#define GROUPS_PAYLOAD_LEN		U(12)
+#define NUM_GROUPS_PER_RESP		U(6)
+#define END_OF_FUNCTION			"END_OF_FUNCTION"
+#define END_OF_GROUPS			-1
+#define PINCTRL_GRP_RESERVED		-2
+
+//pinctrl function ids
+enum {
+	PINCTRL_FUNC_CAN0,
+	PINCTRL_FUNC_CAN1,
+	PINCTRL_FUNC_ETHERNET0,
+	PINCTRL_FUNC_ETHERNET1,
+	PINCTRL_FUNC_ETHERNET2,
+	PINCTRL_FUNC_ETHERNET3,
+	PINCTRL_FUNC_GEMTSU0,
+	PINCTRL_FUNC_GPIO0,
+	PINCTRL_FUNC_I2C0,
+	PINCTRL_FUNC_I2C1,
+	PINCTRL_FUNC_MDIO0,
+	PINCTRL_FUNC_MDIO1,
+	PINCTRL_FUNC_MDIO2,
+	PINCTRL_FUNC_MDIO3,
+	PINCTRL_FUNC_QSPI0,
+	PINCTRL_FUNC_QSPI_FBCLK,
+	PINCTRL_FUNC_QSPI_SS,
+	PINCTRL_FUNC_SPI0,
+	PINCTRL_FUNC_SPI1,
+	PINCTRL_FUNC_SPI0_SS,
+	PINCTRL_FUNC_SPI1_SS,
+	PINCTRL_FUNC_SDIO0,
+	PINCTRL_FUNC_SDIO0_PC,
+	PINCTRL_FUNC_SDIO0_CD,
+	PINCTRL_FUNC_SDIO0_WP,
+	PINCTRL_FUNC_SDIO1,
+	PINCTRL_FUNC_SDIO1_PC,
+	PINCTRL_FUNC_SDIO1_CD,
+	PINCTRL_FUNC_SDIO1_WP,
+	PINCTRL_FUNC_NAND0,
+	PINCTRL_FUNC_NAND0_CE,
+	PINCTRL_FUNC_NAND0_RB,
+	PINCTRL_FUNC_NAND0_DQS,
+	PINCTRL_FUNC_TTC0_CLK,
+	PINCTRL_FUNC_TTC0_WAV,
+	PINCTRL_FUNC_TTC1_CLK,
+	PINCTRL_FUNC_TTC1_WAV,
+	PINCTRL_FUNC_TTC2_CLK,
+	PINCTRL_FUNC_TTC2_WAV,
+	PINCTRL_FUNC_TTC3_CLK,
+	PINCTRL_FUNC_TTC3_WAV,
+	PINCTRL_FUNC_UART0,
+	PINCTRL_FUNC_UART1,
+	PINCTRL_FUNC_USB0,
+	PINCTRL_FUNC_USB1,
+	PINCTRL_FUNC_SWDT0_CLK,
+	PINCTRL_FUNC_SWDT0_RST,
+	PINCTRL_FUNC_SWDT1_CLK,
+	PINCTRL_FUNC_SWDT1_RST,
+	PINCTRL_FUNC_PMU0,
+	PINCTRL_FUNC_PCIE0,
+	PINCTRL_FUNC_CSU0,
+	PINCTRL_FUNC_DPAUX0,
+	PINCTRL_FUNC_PJTAG0,
+	PINCTRL_FUNC_TRACE0,
+	PINCTRL_FUNC_TRACE0_CLK,
+	PINCTRL_FUNC_TESTSCAN0,
+	END_FUNCTION,
+};
+
+#define MAX_FUNCTION (unsigned int)(END_FUNCTION)
+
+// pinctrl pin numbers
+enum {
+	PINCTRL_PIN_0,
+	PINCTRL_PIN_1,
+	PINCTRL_PIN_2,
+	PINCTRL_PIN_3,
+	PINCTRL_PIN_4,
+	PINCTRL_PIN_5,
+	PINCTRL_PIN_6,
+	PINCTRL_PIN_7,
+	PINCTRL_PIN_8,
+	PINCTRL_PIN_9,
+	PINCTRL_PIN_10,
+	PINCTRL_PIN_11,
+	PINCTRL_PIN_12,
+	PINCTRL_PIN_13,
+	PINCTRL_PIN_14,
+	PINCTRL_PIN_15,
+	PINCTRL_PIN_16,
+	PINCTRL_PIN_17,
+	PINCTRL_PIN_18,
+	PINCTRL_PIN_19,
+	PINCTRL_PIN_20,
+	PINCTRL_PIN_21,
+	PINCTRL_PIN_22,
+	PINCTRL_PIN_23,
+	PINCTRL_PIN_24,
+	PINCTRL_PIN_25,
+	PINCTRL_PIN_26,
+	PINCTRL_PIN_27,
+	PINCTRL_PIN_28,
+	PINCTRL_PIN_29,
+	PINCTRL_PIN_30,
+	PINCTRL_PIN_31,
+	PINCTRL_PIN_32,
+	PINCTRL_PIN_33,
+	PINCTRL_PIN_34,
+	PINCTRL_PIN_35,
+	PINCTRL_PIN_36,
+	PINCTRL_PIN_37,
+	PINCTRL_PIN_38,
+	PINCTRL_PIN_39,
+	PINCTRL_PIN_40,
+	PINCTRL_PIN_41,
+	PINCTRL_PIN_42,
+	PINCTRL_PIN_43,
+	PINCTRL_PIN_44,
+	PINCTRL_PIN_45,
+	PINCTRL_PIN_46,
+	PINCTRL_PIN_47,
+	PINCTRL_PIN_48,
+	PINCTRL_PIN_49,
+	PINCTRL_PIN_50,
+	PINCTRL_PIN_51,
+	PINCTRL_PIN_52,
+	PINCTRL_PIN_53,
+	PINCTRL_PIN_54,
+	PINCTRL_PIN_55,
+	PINCTRL_PIN_56,
+	PINCTRL_PIN_57,
+	PINCTRL_PIN_58,
+	PINCTRL_PIN_59,
+	PINCTRL_PIN_60,
+	PINCTRL_PIN_61,
+	PINCTRL_PIN_62,
+	PINCTRL_PIN_63,
+	PINCTRL_PIN_64,
+	PINCTRL_PIN_65,
+	PINCTRL_PIN_66,
+	PINCTRL_PIN_67,
+	PINCTRL_PIN_68,
+	PINCTRL_PIN_69,
+	PINCTRL_PIN_70,
+	PINCTRL_PIN_71,
+	PINCTRL_PIN_72,
+	PINCTRL_PIN_73,
+	PINCTRL_PIN_74,
+	PINCTRL_PIN_75,
+	PINCTRL_PIN_76,
+	PINCTRL_PIN_77,
+	END_PINS,
+};
+
+#define MAX_PIN (unsigned int)(END_PINS)
+
+// pinctrl group ids
+enum  {
+	PINCTRL_GRP_ETHERNET0_0,
+	PINCTRL_GRP_ETHERNET1_0,
+	PINCTRL_GRP_ETHERNET2_0,
+	PINCTRL_GRP_ETHERNET3_0,
+	PINCTRL_GRP_GEMTSU0_0,
+	PINCTRL_GRP_GEMTSU0_1,
+	PINCTRL_GRP_GEMTSU0_2,
+	PINCTRL_GRP_MDIO0_0,
+	PINCTRL_GRP_MDIO1_0,
+	PINCTRL_GRP_MDIO1_1,
+	PINCTRL_GRP_MDIO2_0,
+	PINCTRL_GRP_MDIO3_0,
+	PINCTRL_GRP_QSPI0_0,
+	PINCTRL_GRP_QSPI_SS,
+	PINCTRL_GRP_QSPI_FBCLK,
+	PINCTRL_GRP_SPI0_0,
+	PINCTRL_GRP_SPI0_0_SS0,
+	PINCTRL_GRP_SPI0_0_SS1,
+	PINCTRL_GRP_SPI0_0_SS2,
+	PINCTRL_GRP_SPI0_1,
+	PINCTRL_GRP_SPI0_1_SS0,
+	PINCTRL_GRP_SPI0_1_SS1,
+	PINCTRL_GRP_SPI0_1_SS2,
+	PINCTRL_GRP_SPI0_2,
+	PINCTRL_GRP_SPI0_2_SS0,
+	PINCTRL_GRP_SPI0_2_SS1,
+	PINCTRL_GRP_SPI0_2_SS2,
+	PINCTRL_GRP_SPI0_3,
+	PINCTRL_GRP_SPI0_3_SS0,
+	PINCTRL_GRP_SPI0_3_SS1,
+	PINCTRL_GRP_SPI0_3_SS2,
+	PINCTRL_GRP_SPI0_4,
+	PINCTRL_GRP_SPI0_4_SS0,
+	PINCTRL_GRP_SPI0_4_SS1,
+	PINCTRL_GRP_SPI0_4_SS2,
+	PINCTRL_GRP_SPI0_5,
+	PINCTRL_GRP_SPI0_5_SS0,
+	PINCTRL_GRP_SPI0_5_SS1,
+	PINCTRL_GRP_SPI0_5_SS2,
+	PINCTRL_GRP_SPI1_0,
+	PINCTRL_GRP_SPI1_0_SS0,
+	PINCTRL_GRP_SPI1_0_SS1,
+	PINCTRL_GRP_SPI1_0_SS2,
+	PINCTRL_GRP_SPI1_1,
+	PINCTRL_GRP_SPI1_1_SS0,
+	PINCTRL_GRP_SPI1_1_SS1,
+	PINCTRL_GRP_SPI1_1_SS2,
+	PINCTRL_GRP_SPI1_2,
+	PINCTRL_GRP_SPI1_2_SS0,
+	PINCTRL_GRP_SPI1_2_SS1,
+	PINCTRL_GRP_SPI1_2_SS2,
+	PINCTRL_GRP_SPI1_3,
+	PINCTRL_GRP_SPI1_3_SS0,
+	PINCTRL_GRP_SPI1_3_SS1,
+	PINCTRL_GRP_SPI1_3_SS2,
+	PINCTRL_GRP_SPI1_4,
+	PINCTRL_GRP_SPI1_4_SS0,
+	PINCTRL_GRP_SPI1_4_SS1,
+	PINCTRL_GRP_SPI1_4_SS2,
+	PINCTRL_GRP_SPI1_5,
+	PINCTRL_GRP_SPI1_5_SS0,
+	PINCTRL_GRP_SPI1_5_SS1,
+	PINCTRL_GRP_SPI1_5_SS2,
+	PINCTRL_GRP_SDIO0_0,
+	PINCTRL_GRP_SDIO0_1,
+	PINCTRL_GRP_SDIO0_2,
+	PINCTRL_GRP_SDIO0_4BIT_0_0,
+	PINCTRL_GRP_SDIO0_4BIT_0_1,
+	PINCTRL_GRP_SDIO0_4BIT_1_0,
+	PINCTRL_GRP_SDIO0_4BIT_1_1,
+	PINCTRL_GRP_SDIO0_4BIT_2_0,
+	PINCTRL_GRP_SDIO0_4BIT_2_1,
+	PINCTRL_GRP_SDIO0_1BIT_0_0,
+	PINCTRL_GRP_SDIO0_1BIT_0_1,
+	PINCTRL_GRP_SDIO0_1BIT_0_2,
+	PINCTRL_GRP_SDIO0_1BIT_0_3,
+	PINCTRL_GRP_SDIO0_1BIT_0_4,
+	PINCTRL_GRP_SDIO0_1BIT_0_5,
+	PINCTRL_GRP_SDIO0_1BIT_0_6,
+	PINCTRL_GRP_SDIO0_1BIT_0_7,
+	PINCTRL_GRP_SDIO0_1BIT_1_0,
+	PINCTRL_GRP_SDIO0_1BIT_1_1,
+	PINCTRL_GRP_SDIO0_1BIT_1_2,
+	PINCTRL_GRP_SDIO0_1BIT_1_3,
+	PINCTRL_GRP_SDIO0_1BIT_1_4,
+	PINCTRL_GRP_SDIO0_1BIT_1_5,
+	PINCTRL_GRP_SDIO0_1BIT_1_6,
+	PINCTRL_GRP_SDIO0_1BIT_1_7,
+	PINCTRL_GRP_SDIO0_1BIT_2_0,
+	PINCTRL_GRP_SDIO0_1BIT_2_1,
+	PINCTRL_GRP_SDIO0_1BIT_2_2,
+	PINCTRL_GRP_SDIO0_1BIT_2_3,
+	PINCTRL_GRP_SDIO0_1BIT_2_4,
+	PINCTRL_GRP_SDIO0_1BIT_2_5,
+	PINCTRL_GRP_SDIO0_1BIT_2_6,
+	PINCTRL_GRP_SDIO0_1BIT_2_7,
+	PINCTRL_GRP_SDIO0_0_PC,
+	PINCTRL_GRP_SDIO0_0_CD,
+	PINCTRL_GRP_SDIO0_0_WP,
+	PINCTRL_GRP_SDIO0_1_PC,
+	PINCTRL_GRP_SDIO0_1_CD,
+	PINCTRL_GRP_SDIO0_1_WP,
+	PINCTRL_GRP_SDIO0_2_PC,
+	PINCTRL_GRP_SDIO0_2_CD,
+	PINCTRL_GRP_SDIO0_2_WP,
+	PINCTRL_GRP_SDIO1_0,
+	PINCTRL_GRP_SDIO1_4BIT_0_0,
+	PINCTRL_GRP_SDIO1_4BIT_0_1,
+	PINCTRL_GRP_SDIO1_4BIT_1_0,
+	PINCTRL_GRP_SDIO1_1BIT_0_0,
+	PINCTRL_GRP_SDIO1_1BIT_0_1,
+	PINCTRL_GRP_SDIO1_1BIT_0_2,
+	PINCTRL_GRP_SDIO1_1BIT_0_3,
+	PINCTRL_GRP_SDIO1_1BIT_0_4,
+	PINCTRL_GRP_SDIO1_1BIT_0_5,
+	PINCTRL_GRP_SDIO1_1BIT_0_6,
+	PINCTRL_GRP_SDIO1_1BIT_0_7,
+	PINCTRL_GRP_SDIO1_1BIT_1_0,
+	PINCTRL_GRP_SDIO1_1BIT_1_1,
+	PINCTRL_GRP_SDIO1_1BIT_1_2,
+	PINCTRL_GRP_SDIO1_1BIT_1_3,
+	PINCTRL_GRP_SDIO1_0_PC,
+	PINCTRL_GRP_SDIO1_0_CD,
+	PINCTRL_GRP_SDIO1_0_WP,
+	PINCTRL_GRP_SDIO1_1_PC,
+	PINCTRL_GRP_SDIO1_1_CD,
+	PINCTRL_GRP_SDIO1_1_WP,
+	PINCTRL_GRP_NAND0_0,
+	PINCTRL_GRP_NAND0_0_CE,
+	PINCTRL_GRP_NAND0_0_RB,
+	PINCTRL_GRP_NAND0_0_DQS,
+	PINCTRL_GRP_NAND0_1_CE,
+	PINCTRL_GRP_NAND0_1_RB,
+	PINCTRL_GRP_NAND0_1_DQS,
+	PINCTRL_GRP_CAN0_0,
+	PINCTRL_GRP_CAN0_1,
+	PINCTRL_GRP_CAN0_2,
+	PINCTRL_GRP_CAN0_3,
+	PINCTRL_GRP_CAN0_4,
+	PINCTRL_GRP_CAN0_5,
+	PINCTRL_GRP_CAN0_6,
+	PINCTRL_GRP_CAN0_7,
+	PINCTRL_GRP_CAN0_8,
+	PINCTRL_GRP_CAN0_9,
+	PINCTRL_GRP_CAN0_10,
+	PINCTRL_GRP_CAN0_11,
+	PINCTRL_GRP_CAN0_12,
+	PINCTRL_GRP_CAN0_13,
+	PINCTRL_GRP_CAN0_14,
+	PINCTRL_GRP_CAN0_15,
+	PINCTRL_GRP_CAN0_16,
+	PINCTRL_GRP_CAN0_17,
+	PINCTRL_GRP_CAN0_18,
+	PINCTRL_GRP_CAN1_0,
+	PINCTRL_GRP_CAN1_1,
+	PINCTRL_GRP_CAN1_2,
+	PINCTRL_GRP_CAN1_3,
+	PINCTRL_GRP_CAN1_4,
+	PINCTRL_GRP_CAN1_5,
+	PINCTRL_GRP_CAN1_6,
+	PINCTRL_GRP_CAN1_7,
+	PINCTRL_GRP_CAN1_8,
+	PINCTRL_GRP_CAN1_9,
+	PINCTRL_GRP_CAN1_10,
+	PINCTRL_GRP_CAN1_11,
+	PINCTRL_GRP_CAN1_12,
+	PINCTRL_GRP_CAN1_13,
+	PINCTRL_GRP_CAN1_14,
+	PINCTRL_GRP_CAN1_15,
+	PINCTRL_GRP_CAN1_16,
+	PINCTRL_GRP_CAN1_17,
+	PINCTRL_GRP_CAN1_18,
+	PINCTRL_GRP_CAN1_19,
+	PINCTRL_GRP_UART0_0,
+	PINCTRL_GRP_UART0_1,
+	PINCTRL_GRP_UART0_2,
+	PINCTRL_GRP_UART0_3,
+	PINCTRL_GRP_UART0_4,
+	PINCTRL_GRP_UART0_5,
+	PINCTRL_GRP_UART0_6,
+	PINCTRL_GRP_UART0_7,
+	PINCTRL_GRP_UART0_8,
+	PINCTRL_GRP_UART0_9,
+	PINCTRL_GRP_UART0_10,
+	PINCTRL_GRP_UART0_11,
+	PINCTRL_GRP_UART0_12,
+	PINCTRL_GRP_UART0_13,
+	PINCTRL_GRP_UART0_14,
+	PINCTRL_GRP_UART0_15,
+	PINCTRL_GRP_UART0_16,
+	PINCTRL_GRP_UART0_17,
+	PINCTRL_GRP_UART0_18,
+	PINCTRL_GRP_UART1_0,
+	PINCTRL_GRP_UART1_1,
+	PINCTRL_GRP_UART1_2,
+	PINCTRL_GRP_UART1_3,
+	PINCTRL_GRP_UART1_4,
+	PINCTRL_GRP_UART1_5,
+	PINCTRL_GRP_UART1_6,
+	PINCTRL_GRP_UART1_7,
+	PINCTRL_GRP_UART1_8,
+	PINCTRL_GRP_UART1_9,
+	PINCTRL_GRP_UART1_10,
+	PINCTRL_GRP_UART1_11,
+	PINCTRL_GRP_UART1_12,
+	PINCTRL_GRP_UART1_13,
+	PINCTRL_GRP_UART1_14,
+	PINCTRL_GRP_UART1_15,
+	PINCTRL_GRP_UART1_16,
+	PINCTRL_GRP_UART1_17,
+	PINCTRL_GRP_UART1_18,
+	PINCTRL_GRP_I2C0_0,
+	PINCTRL_GRP_I2C0_1,
+	PINCTRL_GRP_I2C0_2,
+	PINCTRL_GRP_I2C0_3,
+	PINCTRL_GRP_I2C0_4,
+	PINCTRL_GRP_I2C0_5,
+	PINCTRL_GRP_I2C0_6,
+	PINCTRL_GRP_I2C0_7,
+	PINCTRL_GRP_I2C0_8,
+	PINCTRL_GRP_I2C0_9,
+	PINCTRL_GRP_I2C0_10,
+	PINCTRL_GRP_I2C0_11,
+	PINCTRL_GRP_I2C0_12,
+	PINCTRL_GRP_I2C0_13,
+	PINCTRL_GRP_I2C0_14,
+	PINCTRL_GRP_I2C0_15,
+	PINCTRL_GRP_I2C0_16,
+	PINCTRL_GRP_I2C0_17,
+	PINCTRL_GRP_I2C0_18,
+	PINCTRL_GRP_I2C1_0,
+	PINCTRL_GRP_I2C1_1,
+	PINCTRL_GRP_I2C1_2,
+	PINCTRL_GRP_I2C1_3,
+	PINCTRL_GRP_I2C1_4,
+	PINCTRL_GRP_I2C1_5,
+	PINCTRL_GRP_I2C1_6,
+	PINCTRL_GRP_I2C1_7,
+	PINCTRL_GRP_I2C1_8,
+	PINCTRL_GRP_I2C1_9,
+	PINCTRL_GRP_I2C1_10,
+	PINCTRL_GRP_I2C1_11,
+	PINCTRL_GRP_I2C1_12,
+	PINCTRL_GRP_I2C1_13,
+	PINCTRL_GRP_I2C1_14,
+	PINCTRL_GRP_I2C1_15,
+	PINCTRL_GRP_I2C1_16,
+	PINCTRL_GRP_I2C1_17,
+	PINCTRL_GRP_I2C1_18,
+	PINCTRL_GRP_I2C1_19,
+	PINCTRL_GRP_TTC0_0_CLK,
+	PINCTRL_GRP_TTC0_0_WAV,
+	PINCTRL_GRP_TTC0_1_CLK,
+	PINCTRL_GRP_TTC0_1_WAV,
+	PINCTRL_GRP_TTC0_2_CLK,
+	PINCTRL_GRP_TTC0_2_WAV,
+	PINCTRL_GRP_TTC0_3_CLK,
+	PINCTRL_GRP_TTC0_3_WAV,
+	PINCTRL_GRP_TTC0_4_CLK,
+	PINCTRL_GRP_TTC0_4_WAV,
+	PINCTRL_GRP_TTC0_5_CLK,
+	PINCTRL_GRP_TTC0_5_WAV,
+	PINCTRL_GRP_TTC0_6_CLK,
+	PINCTRL_GRP_TTC0_6_WAV,
+	PINCTRL_GRP_TTC0_7_CLK,
+	PINCTRL_GRP_TTC0_7_WAV,
+	PINCTRL_GRP_TTC0_8_CLK,
+	PINCTRL_GRP_TTC0_8_WAV,
+	PINCTRL_GRP_TTC1_0_CLK,
+	PINCTRL_GRP_TTC1_0_WAV,
+	PINCTRL_GRP_TTC1_1_CLK,
+	PINCTRL_GRP_TTC1_1_WAV,
+	PINCTRL_GRP_TTC1_2_CLK,
+	PINCTRL_GRP_TTC1_2_WAV,
+	PINCTRL_GRP_TTC1_3_CLK,
+	PINCTRL_GRP_TTC1_3_WAV,
+	PINCTRL_GRP_TTC1_4_CLK,
+	PINCTRL_GRP_TTC1_4_WAV,
+	PINCTRL_GRP_TTC1_5_CLK,
+	PINCTRL_GRP_TTC1_5_WAV,
+	PINCTRL_GRP_TTC1_6_CLK,
+	PINCTRL_GRP_TTC1_6_WAV,
+	PINCTRL_GRP_TTC1_7_CLK,
+	PINCTRL_GRP_TTC1_7_WAV,
+	PINCTRL_GRP_TTC1_8_CLK,
+	PINCTRL_GRP_TTC1_8_WAV,
+	PINCTRL_GRP_TTC2_0_CLK,
+	PINCTRL_GRP_TTC2_0_WAV,
+	PINCTRL_GRP_TTC2_1_CLK,
+	PINCTRL_GRP_TTC2_1_WAV,
+	PINCTRL_GRP_TTC2_2_CLK,
+	PINCTRL_GRP_TTC2_2_WAV,
+	PINCTRL_GRP_TTC2_3_CLK,
+	PINCTRL_GRP_TTC2_3_WAV,
+	PINCTRL_GRP_TTC2_4_CLK,
+	PINCTRL_GRP_TTC2_4_WAV,
+	PINCTRL_GRP_TTC2_5_CLK,
+	PINCTRL_GRP_TTC2_5_WAV,
+	PINCTRL_GRP_TTC2_6_CLK,
+	PINCTRL_GRP_TTC2_6_WAV,
+	PINCTRL_GRP_TTC2_7_CLK,
+	PINCTRL_GRP_TTC2_7_WAV,
+	PINCTRL_GRP_TTC2_8_CLK,
+	PINCTRL_GRP_TTC2_8_WAV,
+	PINCTRL_GRP_TTC3_0_CLK,
+	PINCTRL_GRP_TTC3_0_WAV,
+	PINCTRL_GRP_TTC3_1_CLK,
+	PINCTRL_GRP_TTC3_1_WAV,
+	PINCTRL_GRP_TTC3_2_CLK,
+	PINCTRL_GRP_TTC3_2_WAV,
+	PINCTRL_GRP_TTC3_3_CLK,
+	PINCTRL_GRP_TTC3_3_WAV,
+	PINCTRL_GRP_TTC3_4_CLK,
+	PINCTRL_GRP_TTC3_4_WAV,
+	PINCTRL_GRP_TTC3_5_CLK,
+	PINCTRL_GRP_TTC3_5_WAV,
+	PINCTRL_GRP_TTC3_6_CLK,
+	PINCTRL_GRP_TTC3_6_WAV,
+	PINCTRL_GRP_TTC3_7_CLK,
+	PINCTRL_GRP_TTC3_7_WAV,
+	PINCTRL_GRP_TTC3_8_CLK,
+	PINCTRL_GRP_TTC3_8_WAV,
+	PINCTRL_GRP_SWDT0_0_CLK,
+	PINCTRL_GRP_SWDT0_0_RST,
+	PINCTRL_GRP_SWDT0_1_CLK,
+	PINCTRL_GRP_SWDT0_1_RST,
+	PINCTRL_GRP_SWDT0_2_CLK,
+	PINCTRL_GRP_SWDT0_2_RST,
+	PINCTRL_GRP_SWDT0_3_CLK,
+	PINCTRL_GRP_SWDT0_3_RST,
+	PINCTRL_GRP_SWDT0_4_CLK,
+	PINCTRL_GRP_SWDT0_4_RST,
+	PINCTRL_GRP_SWDT0_5_CLK,
+	PINCTRL_GRP_SWDT0_5_RST,
+	PINCTRL_GRP_SWDT0_6_CLK,
+	PINCTRL_GRP_SWDT0_6_RST,
+	PINCTRL_GRP_SWDT0_7_CLK,
+	PINCTRL_GRP_SWDT0_7_RST,
+	PINCTRL_GRP_SWDT0_8_CLK,
+	PINCTRL_GRP_SWDT0_8_RST,
+	PINCTRL_GRP_SWDT0_9_CLK,
+	PINCTRL_GRP_SWDT0_9_RST,
+	PINCTRL_GRP_SWDT0_10_CLK,
+	PINCTRL_GRP_SWDT0_10_RST,
+	PINCTRL_GRP_SWDT0_11_CLK,
+	PINCTRL_GRP_SWDT0_11_RST,
+	PINCTRL_GRP_SWDT0_12_CLK,
+	PINCTRL_GRP_SWDT0_12_RST,
+	PINCTRL_GRP_SWDT1_0_CLK,
+	PINCTRL_GRP_SWDT1_0_RST,
+	PINCTRL_GRP_SWDT1_1_CLK,
+	PINCTRL_GRP_SWDT1_1_RST,
+	PINCTRL_GRP_SWDT1_2_CLK,
+	PINCTRL_GRP_SWDT1_2_RST,
+	PINCTRL_GRP_SWDT1_3_CLK,
+	PINCTRL_GRP_SWDT1_3_RST,
+	PINCTRL_GRP_SWDT1_4_CLK,
+	PINCTRL_GRP_SWDT1_4_RST,
+	PINCTRL_GRP_SWDT1_5_CLK,
+	PINCTRL_GRP_SWDT1_5_RST,
+	PINCTRL_GRP_SWDT1_6_CLK,
+	PINCTRL_GRP_SWDT1_6_RST,
+	PINCTRL_GRP_SWDT1_7_CLK,
+	PINCTRL_GRP_SWDT1_7_RST,
+	PINCTRL_GRP_SWDT1_8_CLK,
+	PINCTRL_GRP_SWDT1_8_RST,
+	PINCTRL_GRP_SWDT1_9_CLK,
+	PINCTRL_GRP_SWDT1_9_RST,
+	PINCTRL_GRP_SWDT1_10_CLK,
+	PINCTRL_GRP_SWDT1_10_RST,
+	PINCTRL_GRP_SWDT1_11_CLK,
+	PINCTRL_GRP_SWDT1_11_RST,
+	PINCTRL_GRP_SWDT1_12_CLK,
+	PINCTRL_GRP_SWDT1_12_RST,
+	PINCTRL_GRP_GPIO0_0,
+	PINCTRL_GRP_GPIO0_1,
+	PINCTRL_GRP_GPIO0_2,
+	PINCTRL_GRP_GPIO0_3,
+	PINCTRL_GRP_GPIO0_4,
+	PINCTRL_GRP_GPIO0_5,
+	PINCTRL_GRP_GPIO0_6,
+	PINCTRL_GRP_GPIO0_7,
+	PINCTRL_GRP_GPIO0_8,
+	PINCTRL_GRP_GPIO0_9,
+	PINCTRL_GRP_GPIO0_10,
+	PINCTRL_GRP_GPIO0_11,
+	PINCTRL_GRP_GPIO0_12,
+	PINCTRL_GRP_GPIO0_13,
+	PINCTRL_GRP_GPIO0_14,
+	PINCTRL_GRP_GPIO0_15,
+	PINCTRL_GRP_GPIO0_16,
+	PINCTRL_GRP_GPIO0_17,
+	PINCTRL_GRP_GPIO0_18,
+	PINCTRL_GRP_GPIO0_19,
+	PINCTRL_GRP_GPIO0_20,
+	PINCTRL_GRP_GPIO0_21,
+	PINCTRL_GRP_GPIO0_22,
+	PINCTRL_GRP_GPIO0_23,
+	PINCTRL_GRP_GPIO0_24,
+	PINCTRL_GRP_GPIO0_25,
+	PINCTRL_GRP_GPIO0_26,
+	PINCTRL_GRP_GPIO0_27,
+	PINCTRL_GRP_GPIO0_28,
+	PINCTRL_GRP_GPIO0_29,
+	PINCTRL_GRP_GPIO0_30,
+	PINCTRL_GRP_GPIO0_31,
+	PINCTRL_GRP_GPIO0_32,
+	PINCTRL_GRP_GPIO0_33,
+	PINCTRL_GRP_GPIO0_34,
+	PINCTRL_GRP_GPIO0_35,
+	PINCTRL_GRP_GPIO0_36,
+	PINCTRL_GRP_GPIO0_37,
+	PINCTRL_GRP_GPIO0_38,
+	PINCTRL_GRP_GPIO0_39,
+	PINCTRL_GRP_GPIO0_40,
+	PINCTRL_GRP_GPIO0_41,
+	PINCTRL_GRP_GPIO0_42,
+	PINCTRL_GRP_GPIO0_43,
+	PINCTRL_GRP_GPIO0_44,
+	PINCTRL_GRP_GPIO0_45,
+	PINCTRL_GRP_GPIO0_46,
+	PINCTRL_GRP_GPIO0_47,
+	PINCTRL_GRP_GPIO0_48,
+	PINCTRL_GRP_GPIO0_49,
+	PINCTRL_GRP_GPIO0_50,
+	PINCTRL_GRP_GPIO0_51,
+	PINCTRL_GRP_GPIO0_52,
+	PINCTRL_GRP_GPIO0_53,
+	PINCTRL_GRP_GPIO0_54,
+	PINCTRL_GRP_GPIO0_55,
+	PINCTRL_GRP_GPIO0_56,
+	PINCTRL_GRP_GPIO0_57,
+	PINCTRL_GRP_GPIO0_58,
+	PINCTRL_GRP_GPIO0_59,
+	PINCTRL_GRP_GPIO0_60,
+	PINCTRL_GRP_GPIO0_61,
+	PINCTRL_GRP_GPIO0_62,
+	PINCTRL_GRP_GPIO0_63,
+	PINCTRL_GRP_GPIO0_64,
+	PINCTRL_GRP_GPIO0_65,
+	PINCTRL_GRP_GPIO0_66,
+	PINCTRL_GRP_GPIO0_67,
+	PINCTRL_GRP_GPIO0_68,
+	PINCTRL_GRP_GPIO0_69,
+	PINCTRL_GRP_GPIO0_70,
+	PINCTRL_GRP_GPIO0_71,
+	PINCTRL_GRP_GPIO0_72,
+	PINCTRL_GRP_GPIO0_73,
+	PINCTRL_GRP_GPIO0_74,
+	PINCTRL_GRP_GPIO0_75,
+	PINCTRL_GRP_GPIO0_76,
+	PINCTRL_GRP_GPIO0_77,
+	PINCTRL_GRP_USB0_0,
+	PINCTRL_GRP_USB1_0,
+	PINCTRL_GRP_PMU0_0,
+	PINCTRL_GRP_PMU0_1,
+	PINCTRL_GRP_PMU0_2,
+	PINCTRL_GRP_PMU0_3,
+	PINCTRL_GRP_PMU0_4,
+	PINCTRL_GRP_PMU0_5,
+	PINCTRL_GRP_PMU0_6,
+	PINCTRL_GRP_PMU0_7,
+	PINCTRL_GRP_PMU0_8,
+	PINCTRL_GRP_PMU0_9,
+	PINCTRL_GRP_PMU0_10,
+	PINCTRL_GRP_PMU0_11,
+	PINCTRL_GRP_PCIE0_0,
+	PINCTRL_GRP_PCIE0_1,
+	PINCTRL_GRP_PCIE0_2,
+	PINCTRL_GRP_PCIE0_3,
+	PINCTRL_GRP_PCIE0_4,
+	PINCTRL_GRP_PCIE0_5,
+	PINCTRL_GRP_PCIE0_6,
+	PINCTRL_GRP_PCIE0_7,
+	PINCTRL_GRP_CSU0_0,
+	PINCTRL_GRP_CSU0_1,
+	PINCTRL_GRP_CSU0_2,
+	PINCTRL_GRP_CSU0_3,
+	PINCTRL_GRP_CSU0_4,
+	PINCTRL_GRP_CSU0_5,
+	PINCTRL_GRP_CSU0_6,
+	PINCTRL_GRP_CSU0_7,
+	PINCTRL_GRP_CSU0_8,
+	PINCTRL_GRP_CSU0_9,
+	PINCTRL_GRP_CSU0_10,
+	PINCTRL_GRP_CSU0_11,
+	PINCTRL_GRP_DPAUX0_0,
+	PINCTRL_GRP_DPAUX0_1,
+	PINCTRL_GRP_DPAUX0_2,
+	PINCTRL_GRP_DPAUX0_3,
+	PINCTRL_GRP_PJTAG0_0,
+	PINCTRL_GRP_PJTAG0_1,
+	PINCTRL_GRP_PJTAG0_2,
+	PINCTRL_GRP_PJTAG0_3,
+	PINCTRL_GRP_PJTAG0_4,
+	PINCTRL_GRP_PJTAG0_5,
+	PINCTRL_GRP_TRACE0_0,
+	PINCTRL_GRP_TRACE0_0_CLK,
+	PINCTRL_GRP_TRACE0_1,
+	PINCTRL_GRP_TRACE0_1_CLK,
+	PINCTRL_GRP_TRACE0_2,
+	PINCTRL_GRP_TRACE0_2_CLK,
+	PINCTRL_GRP_TESTSCAN0_0,
+};
+
+// pinctrl config parameters
+enum {
+	PINCTRL_CONFIG_SLEW_RATE,
+	PINCTRL_CONFIG_BIAS_STATUS,
+	PINCTRL_CONFIG_PULL_CTRL,
+	PINCTRL_CONFIG_SCHMITT_CMOS,
+	PINCTRL_CONFIG_DRIVE_STRENGTH,
+	PINCTRL_CONFIG_VOLTAGE_STATUS,
+	PINCTRL_CONFIG_MAX,
+};
+
+// pinctrl slew rate
+#define	PINCTRL_SLEW_RATE_FAST 0U
+#define	PINCTRL_SLEW_RATE_SLOW 1U
+
+// pinctrl bias status
+#define	PINCTRL_BIAS_DISABLE 0U
+#define	PINCTRL_BIAS_ENABLE 1U
+
+// pinctrl pull control
+#define	PINCTRL_BIAS_PULL_DOWN 0U
+#define	PINCTRL_BIAS_PULL_UP 1U
+
+// pinctrl schmitt cmos type
+#define PINCTRL_INPUT_TYPE_CMOS 0U
+#define	PINCTRL_INPUT_TYPE_SCHMITT 1U
+
+//pinctrl drive strength values
+#define	PINCTRL_DRIVE_STRENGTH_2MA 0U
+#define	PINCTRL_DRIVE_STRENGTH_4MA 1U
+#define	PINCTRL_DRIVE_STRENGTH_8MA 2U
+#define	PINCTRL_DRIVE_STRENGTH_12MA 3U
+
+enum pm_ret_status pm_api_pinctrl_set_function(unsigned int pin,
+					       unsigned int fid);
+enum pm_ret_status pm_api_pinctrl_get_function(unsigned int pin,
+					       unsigned int *id);
+enum pm_ret_status pm_api_pinctrl_set_config(unsigned int pin,
+					     unsigned int param,
+					     unsigned int value);
+enum pm_ret_status pm_api_pinctrl_get_config(unsigned int pin,
+					     unsigned int param,
+					     unsigned int *value);
+enum pm_ret_status pm_api_pinctrl_get_function_name(unsigned int fid,
+						    char *name);
+enum pm_ret_status pm_api_pinctrl_get_function_groups(unsigned int fid,
+						      unsigned int index,
+						      uint16_t *groups);
+enum pm_ret_status pm_api_pinctrl_get_pin_groups(unsigned int pin,
+						 unsigned int index,
+						 uint16_t *groups);
+enum pm_ret_status pm_api_pinctrl_get_num_pins(unsigned int *npins);
+enum pm_ret_status pm_api_pinctrl_get_num_functions(unsigned int *nfuncs);
+enum pm_ret_status pm_api_pinctrl_get_num_func_groups(unsigned int fid,
+						      unsigned int *ngroups);
+#endif /* PM_API_PINCTRL_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..e0b9816
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -0,0 +1,1512 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions and communication with PMU via
+ * IPI interrupts
+ */
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_clock.h"
+#include "pm_api_ioctl.h"
+#include "pm_api_pinctrl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+/* default shutdown/reboot scope is system(2) */
+static unsigned int pm_shutdown_scope = PMF_SHUTDOWN_SUBTYPE_SYSTEM;
+
+/**
+ * pm_get_shutdown_scope() - Get the currently set shutdown scope
+ *
+ * @return	Shutdown scope value
+ */
+unsigned int pm_get_shutdown_scope(void)
+{
+	return pm_shutdown_scope;
+}
+
+/**
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, arg0) {	\
+	pl[0] = (uint32_t)(arg0);	\
+}
+
+#define PM_PACK_PAYLOAD2(pl, arg0, arg1) {	\
+	pl[1] = (uint32_t)(arg1);		\
+	PM_PACK_PAYLOAD1(pl, arg0);		\
+}
+
+#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) {	\
+	pl[2] = (uint32_t)(arg2);			\
+	PM_PACK_PAYLOAD2(pl, arg0, arg1);		\
+}
+
+#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) {	\
+	pl[3] = (uint32_t)(arg3);			\
+	PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2);		\
+}
+
+#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) {	\
+	pl[4] = (uint32_t)(arg4);				\
+	PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3);		\
+}
+
+#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) {	\
+	pl[5] = (uint32_t)(arg5);					\
+	PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4);		\
+}
+
+/**
+ * pm_self_suspend() - PM call for processor to suspend itself
+ * @nid		Node id of the processor or subsystem
+ * @latency	Requested maximum wakeup latency (not supported)
+ * @state	Requested state
+ * @address	Resume address
+ *
+ * This is a blocking call, it will return only once PMU has responded.
+ * On a wakeup, resume address will be automatically set by PMU.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+				   unsigned int latency,
+				   unsigned int state,
+				   uintptr_t address)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	unsigned int cpuid = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpuid);
+
+	/*
+	 * Do client specific suspend operations
+	 * (e.g. set powerdown request bit)
+	 */
+	pm_client_suspend(proc, state);
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
+			 state, address, (address >> 32));
+	return pm_ipi_send_sync(proc, payload, NULL, 0);
+}
+
+/**
+ * pm_req_suspend() - PM call to request for another PU or subsystem to
+ *		      be suspended gracefully.
+ * @target	Node id of the targeted PU or subsystem
+ * @ack		Flag to specify whether acknowledge is requested
+ * @latency	Requested wakeup latency (not supported)
+ * @state	Requested state (not supported)
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_suspend(enum pm_node_id target,
+				  enum pm_request_ack ack,
+				  unsigned int latency, unsigned int state)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state);
+	if (ack == REQ_ACK_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_req_wakeup() - PM call for processor to wake up selected processor
+ *		     or subsystem
+ * @target	Node id of the processor or subsystem to wake up
+ * @ack		Flag to specify whether acknowledge requested
+ * @set_address	Resume address presence indicator
+ *				1 resume address specified, 0 otherwise
+ * @address	Resume address
+ *
+ * This API function is either used to power up another APU core for SMP
+ * (by PSCI) or to power up an entirely different PU or subsystem, such
+ * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be
+ * automatically set by PMU.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
+				 unsigned int set_address,
+				 uintptr_t address,
+				 enum pm_request_ack ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	uint64_t encoded_address;
+
+
+	/* encode set Address into 1st bit of address */
+	encoded_address = address;
+	encoded_address |= !!set_address;
+
+	/* Send request to the PMU to perform the wake of the PU */
+	PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address,
+			 encoded_address >> 32, ack);
+
+	if (ack == REQ_ACK_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_force_powerdown() - PM call to request for another PU or subsystem to
+ *			  be powered down forcefully
+ * @target	Node id of the targeted PU or subsystem
+ * @ack		Flag to specify whether acknowledge is requested
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
+				      enum pm_request_ack ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack);
+
+	if (ack == REQ_ACK_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_abort_suspend() - PM call to announce that a prior suspend request
+ *			is to be aborted.
+ * @reason	Reason for the abort
+ *
+ * Calling PU expects the PMU to abort the initiated suspend procedure.
+ * This is a non-blocking call without any acknowledge.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/*
+	 * Do client specific abort suspend operations
+	 * (e.g. enable interrupts and clear powerdown request bit)
+	 */
+	pm_client_abort_suspend();
+	/* Send request to the PMU */
+	/* TODO: allow passing the node ID of the affected CPU */
+	PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason,
+			 primary_proc->node_id);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
+ * @target	Node id of the targeted PU or subsystem
+ * @wkup_node	Node id of the wakeup peripheral
+ * @enable	Enable or disable the specified peripheral as wake source
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
+					enum pm_node_id wkup_node,
+					unsigned int enable)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node,
+			 enable);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_system_shutdown() - PM call to request a system shutdown or restart
+ * @type	Shutdown or restart? 0=shutdown, 1=restart, 2=setscope
+ * @subtype	Scope: 0=APU-subsystem, 1=PS, 2=system
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	if (type == PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY) {
+		/* Setting scope for subsequent PSCI reboot or shutdown */
+		pm_shutdown_scope = subtype;
+		return PM_RET_SUCCESS;
+	}
+
+	PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype);
+	return pm_ipi_send_non_blocking(primary_proc, payload);
+}
+
+/* APIs for managing PM slaves: */
+
+/**
+ * pm_req_node() - PM call to request a node with specific capabilities
+ * @nid		Node id of the slave
+ * @capabilities Requested capabilities of the slave
+ * @qos		Quality of service (not supported)
+ * @ack		Flag to specify whether acknowledge is requested
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+			       unsigned int capabilities,
+			       unsigned int qos,
+			       enum pm_request_ack ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack);
+
+	if (ack == REQ_ACK_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_set_requirement() - PM call to set requirement for PM slaves
+ * @nid		Node id of the slave
+ * @capabilities Requested capabilities of the slave
+ * @qos		Quality of service (not supported)
+ * @ack		Flag to specify whether acknowledge is requested
+ *
+ * This API function is to be used for slaves a PU already has requested
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+				      unsigned int capabilities,
+				      unsigned int qos,
+				      enum pm_request_ack ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos,
+			 ack);
+
+	if (ack == REQ_ACK_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_release_node() - PM call to release a node
+ * @nid		Node id of the slave
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_release_node(enum pm_node_id nid)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD2(payload, PM_RELEASE_NODE, nid);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_set_max_latency() - PM call to set wakeup latency requirements
+ * @nid		Node id of the slave
+ * @latency	Requested maximum wakeup latency
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
+				      unsigned int latency)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD3(payload, PM_SET_MAX_LATENCY, nid, latency);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/* Miscellaneous API functions */
+
+/**
+ * pm_get_api_version() - Get version number of PMU PM firmware
+ * @version	Returns 32-bit version number of PMU Power Management Firmware
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_api_version(unsigned int *version)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION);
+	return pm_ipi_send_sync(primary_proc, payload, version, 1);
+}
+
+/**
+ * pm_set_configuration() - PM call to set system configuration
+ * @phys_addr	Physical 32-bit address of data structure in memory
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_configuration(unsigned int phys_addr)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD2(payload, PM_SET_CONFIGURATION, phys_addr);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_init_finalize() - Call to notify PMU firmware that master has power
+ *			management enabled and that it has finished its
+ *			initialization
+ *
+ * @return	Status returned by the PMU firmware
+ */
+enum pm_ret_status pm_init_finalize(void)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD1(payload, PM_INIT_FINALIZE);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_node_status() - PM call to request a node's current status
+ * @nid		Node id
+ * @ret_buff	Buffer for the return values:
+ *		[0] - Current power state of the node
+ *		[1] - Current requirements for the node (slave nodes only)
+ *		[2] - Current usage status for the node (slave nodes only)
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_node_status(enum pm_node_id nid,
+				      uint32_t *ret_buff)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid);
+	return pm_ipi_send_sync(primary_proc, payload, ret_buff, 3);
+}
+
+/**
+ * pm_register_notifier() - Register the PU to be notified of PM events
+ * @nid		Node id of the slave
+ * @event	The event to be notified about
+ * @wake	Wake up on event
+ * @enable	Enable or disable the notifier
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_register_notifier(enum pm_node_id nid,
+					unsigned int event,
+					unsigned int wake,
+					unsigned int enable)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD5(payload, PM_REGISTER_NOTIFIER,
+			 nid, event, wake, enable);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_op_characteristic() - PM call to request operating characteristics
+ *				of a node
+ * @nid		Node id of the slave
+ * @type	Type of the operating characteristic
+ *		(power, temperature and latency)
+ * @result	Returns the operating characteristic for the requested node,
+ *		specified by the type
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
+					    enum pm_opchar_type type,
+					    uint32_t *result)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_GET_OP_CHARACTERISTIC, nid, type);
+	return pm_ipi_send_sync(primary_proc, payload, result, 1);
+}
+
+/* Direct-Control API functions */
+
+/**
+ * pm_reset_assert() - Assert reset
+ * @reset	Reset ID
+ * @assert	Assert (1) or de-assert (0)
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_assert(unsigned int reset,
+				   unsigned int assert)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_RESET_ASSERT, reset, assert);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_reset_get_status() - Get current status of a reset line
+ * @reset	Reset ID
+ * @reset_status Returns current status of selected reset line
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_get_status(unsigned int reset,
+				       unsigned int *reset_status)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset);
+	return pm_ipi_send_sync(primary_proc, payload, reset_status, 1);
+}
+
+/**
+ * pm_mmio_write() - Perform write to protected mmio
+ * @address	Address to write to
+ * @mask	Mask to apply
+ * @value	Value to write
+ *
+ * This function provides access to PM-related control registers
+ * that may not be directly accessible by a particular PU.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+				 unsigned int mask,
+				 unsigned int value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_mmio_read() - Read value from protected mmio
+ * @address	Address to write to
+ * @value	Value to write
+ *
+ * This function provides access to PM-related control registers
+ * that may not be directly accessible by a particular PU.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_fpga_load() - Load the bitstream into the PL.
+ *
+ * This function provides access to the xilfpga library to load
+ * the Bit-stream into PL.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ *
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * size:	Number of 32bit words
+ *
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_load(uint32_t address_low,
+				uint32_t address_high,
+				uint32_t size,
+				uint32_t flags)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low,
+						size, flags);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_fpga_get_status() - Read value from fpga status register
+ * @value       Value to read
+ *
+ * This function provides access to the xilfpga library to get
+ * the fpga status
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_get_status(unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_get_chipid() - Read silicon ID registers
+ * @value       Buffer for return values. Must be large enough
+ *		to hold 8 bytes.
+ *
+ * @return      Returns silicon ID registers
+ */
+enum pm_ret_status pm_get_chipid(uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID);
+	return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
+
+/**
+ * pm_secure_rsaaes() - Load the secure images.
+ *
+ * This function provides access to the xilsecure library to load
+ * the authenticated, encrypted, and authenicated/encrypted images.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ *
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * size:	Number of 32bit words
+ *
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_secure_rsaaes(uint32_t address_low,
+				uint32_t address_high,
+				uint32_t size,
+				uint32_t flags)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA_AES, address_high, address_low,
+			 size, flags);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_aes_engine() - Aes data blob encryption/decryption
+ * This function provides access to the xilsecure library to
+ * encrypt/decrypt data blobs.
+ *
+ * address_low: lower 32-bit address of the AesParams structure
+ *
+ * address_high: higher 32-bit address of the AesParams structure
+ *
+ * value:        Returned output value
+ *
+ * @return       Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_aes_engine(uint32_t address_high,
+				 uint32_t address_low,
+				 uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_SECURE_AES, address_high, address_low);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_pinctrl_request() - Request Pin from firmware
+ * @pin		Pin number to request
+ *
+ * This function requests pin from firmware.
+ *
+ * @return	Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_pinctrl_request(unsigned int pin)
+{
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_pinctrl_release() - Release Pin from firmware
+ * @pin		Pin number to release
+ *
+ * This function releases pin from firmware.
+ *
+ * @return	Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_pinctrl_release(unsigned int pin)
+{
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_pinctrl_get_function() - Read function id set for the given pin
+ * @pin		Pin number
+ * @nid		Node ID of function currently set for given pin
+ *
+ * This function provides the function currently set for the given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_get_function(unsigned int pin,
+					   enum pm_node_id *nid)
+{
+	return pm_api_pinctrl_get_function(pin, nid);
+}
+
+/**
+ * pm_pinctrl_set_function() - Set function id set for the given pin
+ * @pin		Pin number
+ * @nid		Node ID of function to set for given pin
+ *
+ * This function provides the function currently set for the given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_set_function(unsigned int pin,
+					   enum pm_node_id nid)
+{
+	return pm_api_pinctrl_set_function(pin, (unsigned int)nid);
+}
+
+/**
+ * pm_pinctrl_get_config() - Read value of requested config param for given pin
+ * @pin		Pin number
+ * @param	Parameter values to be read
+ * @value	Buffer for configuration Parameter value
+ *
+ * This function provides the configuration parameter value for the given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_get_config(unsigned int pin,
+					 unsigned int param,
+					 unsigned int *value)
+{
+	return pm_api_pinctrl_get_config(pin, param, value);
+}
+
+/**
+ * pm_pinctrl_set_config() - Read value of requested config param for given pin
+ * @pin		Pin number
+ * @param	Parameter to set
+ * @value	Parameter value to set
+ *
+ * This function provides the configuration parameter value for the given pin.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_set_config(unsigned int pin,
+					 unsigned int param,
+					 unsigned int value)
+{
+	return pm_api_pinctrl_set_config(pin, param, value);
+}
+
+/**
+ * pm_ioctl() -  PM IOCTL API for device control and configs
+ * @node_id	Node ID of the device
+ * @ioctl_id	ID of the requested IOCTL
+ * @arg1	Argument 1 to requested IOCTL call
+ * @arg2	Argument 2 to requested IOCTL call
+ * @out		Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+			    unsigned int ioctl_id,
+			    unsigned int arg1,
+			    unsigned int arg2,
+			    unsigned int *value)
+{
+	return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value);
+}
+
+/**
+ * pm_clock_get_num_clocks - PM call to request number of clocks
+ * @nclockss: Number of clocks
+ *
+ * This function is used by master to get number of clocks.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_clock_get_num_clocks(uint32_t *nclocks)
+{
+	return pm_api_clock_get_num_clocks(nclocks);
+}
+
+/**
+ * pm_clock_get_name() - PM call to request a clock's name
+ * @clock_id	Clock ID
+ * @name	Name of clock (max 16 bytes)
+ *
+ * This function is used by master to get nmae of clock specified
+ * by given clock ID.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_name(unsigned int clock_id, char *name)
+{
+	return pm_api_clock_get_name(clock_id, name);
+}
+
+/**
+ * pm_clock_get_topology() - PM call to request a clock's topology
+ * @clock_id	Clock ID
+ * @index	Topology index for next toplogy node
+ * @topology	Buffer to store nodes in topology and flags
+ *
+ * This function is used by master to get topology information for the
+ * clock specified by given clock ID. Each response would return 3
+ * topology nodes. To get next nodes, caller needs to call this API with
+ * index of next node. Index starts from 0.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_topology(unsigned int clock_id,
+						unsigned int index,
+						uint32_t *topology)
+{
+	return pm_api_clock_get_topology(clock_id, index, topology);
+}
+
+/**
+ * pm_clock_get_fixedfactor_params() - PM call to request a clock's fixed factor
+ *				 parameters for fixed clock
+ * @clock_id	Clock ID
+ * @mul		Multiplication value
+ * @div		Divisor value
+ *
+ * This function is used by master to get fixed factor parameers for the
+ * fixed clock. This API is application only for the fixed clock.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_fixedfactor_params(unsigned int clock_id,
+							  uint32_t *mul,
+							  uint32_t *div)
+{
+	return pm_api_clock_get_fixedfactor_params(clock_id, mul, div);
+}
+
+/**
+ * pm_clock_get_parents() - PM call to request a clock's first 3 parents
+ * @clock_id	Clock ID
+ * @index	Index of next parent
+ * @parents	Parents of the given clock
+ *
+ * This function is used by master to get clock's parents information.
+ * This API will return 3 parents with a single response. To get other
+ * parents, master should call same API in loop with new parent index
+ * till error is returned.
+ *
+ * E.g First call should have index 0 which will return parents 0, 1 and
+ * 2. Next call, index should be 3 which will return parent 3,4 and 5 and
+ * so on.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_parents(unsigned int clock_id,
+					       unsigned int index,
+					       uint32_t *parents)
+{
+	return pm_api_clock_get_parents(clock_id, index, parents);
+}
+
+/**
+ * pm_clock_get_attributes() - PM call to request a clock's attributes
+ * @clock_id	Clock ID
+ * @attr	Clock attributes
+ *
+ * This function is used by master to get clock's attributes
+ * (e.g. valid, clock type, etc).
+ *
+ * @return	Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_attributes(unsigned int clock_id,
+						  uint32_t *attr)
+{
+	return pm_api_clock_get_attributes(clock_id, attr);
+}
+
+/**
+ * pm_clock_gate() - Configure clock gate
+ * @clock_id	Id of the clock to be configured
+ * @enable	Flag 0=disable (gate the clock), !0=enable (activate the clock)
+ *
+ * @return	Error if an argument is not valid or status as returned by the
+ *		PM controller (PMU)
+ */
+static enum pm_ret_status pm_clock_gate(unsigned int clock_id,
+					unsigned char enable)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	enum pm_ret_status status;
+	enum pm_api_id api_id;
+
+	/* Check if clock ID is valid and return an error if it is not */
+	status = pm_clock_id_is_valid(clock_id);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	if (enable)
+		api_id = PM_CLOCK_ENABLE;
+	else
+		api_id = PM_CLOCK_DISABLE;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, api_id, clock_id);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_enable() - Enable the clock for given id
+ * @clock_id: Id of the clock to be enabled
+ *
+ * This function is used by master to enable the clock
+ * including peripherals and PLL clocks.
+ *
+ * @return:	Error if an argument is not valid or status as returned by the
+ *		pm_clock_gate
+ */
+enum pm_ret_status pm_clock_enable(unsigned int clock_id)
+{
+	struct pm_pll *pll;
+
+	/* First try to handle it as a PLL */
+	pll = pm_clock_get_pll(clock_id);
+	if (pll)
+		return pm_clock_pll_enable(pll);
+
+	/* It's an on-chip clock, PMU should configure clock's gate */
+	return pm_clock_gate(clock_id, 1);
+}
+
+/**
+ * pm_clock_disable - Disable the clock for given id
+ * @clock_id: Id of the clock to be disable
+ *
+ * This function is used by master to disable the clock
+ * including peripherals and PLL clocks.
+ *
+ * @return:	Error if an argument is not valid or status as returned by the
+ *		pm_clock_gate
+ */
+enum pm_ret_status pm_clock_disable(unsigned int clock_id)
+{
+	struct pm_pll *pll;
+
+	/* First try to handle it as a PLL */
+	pll = pm_clock_get_pll(clock_id);
+	if (pll)
+		return pm_clock_pll_disable(pll);
+
+	/* It's an on-chip clock, PMU should configure clock's gate */
+	return pm_clock_gate(clock_id, 0);
+}
+
+/**
+ * pm_clock_getstate - Get the clock state for given id
+ * @clock_id: Id of the clock to be queried
+ * @state: 1/0 (Enabled/Disabled)
+ *
+ * This function is used by master to get the state of clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getstate(unsigned int clock_id,
+				     unsigned int *state)
+{
+	struct pm_pll *pll;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	enum pm_ret_status status;
+
+	/* First try to handle it as a PLL */
+	pll = pm_clock_get_pll(clock_id);
+	if (pll)
+		return pm_clock_pll_get_state(pll, state);
+
+	/* Check if clock ID is a valid on-chip clock */
+	status = pm_clock_id_is_valid(clock_id);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETSTATE, clock_id);
+	return pm_ipi_send_sync(primary_proc, payload, state, 1);
+}
+
+/**
+ * pm_clock_setdivider - Set the clock divider for given id
+ * @clock_id: Id of the clock
+ * @divider: divider value
+ *
+ * This function is used by master to set divider for any clock
+ * to achieve desired rate.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_setdivider(unsigned int clock_id,
+				       unsigned int divider)
+{
+	enum pm_ret_status status;
+	enum pm_node_id nid;
+	enum pm_clock_div_id div_id;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	const uint32_t div0 = 0xFFFF0000;
+	const uint32_t div1 = 0x0000FFFF;
+	uint32_t val;
+
+	/* Get PLL node ID using PLL clock ID */
+	status = pm_clock_get_pll_node_id(clock_id, &nid);
+	if (status == PM_RET_SUCCESS)
+		return pm_pll_set_parameter(nid, PM_PLL_PARAM_FBDIV, divider);
+
+	/* Check if clock ID is a valid on-chip clock */
+	status = pm_clock_id_is_valid(clock_id);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	if (div0 == (divider & div0)) {
+		div_id = PM_CLOCK_DIV0_ID;
+		val = divider & ~div0;
+	} else if (div1 == (divider & div1)) {
+		div_id = PM_CLOCK_DIV1_ID;
+		val = (divider & ~div1) >> 16;
+	} else {
+		return PM_RET_ERROR_ARGS;
+	}
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD4(payload, PM_CLOCK_SETDIVIDER, clock_id, div_id, val);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_getdivider - Get the clock divider for given id
+ * @clock_id: Id of the clock
+ * @divider: divider value
+ *
+ * This function is used by master to get divider values
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getdivider(unsigned int clock_id,
+				       unsigned int *divider)
+{
+	enum pm_ret_status status;
+	enum pm_node_id nid;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	uint32_t val;
+
+	/* Get PLL node ID using PLL clock ID */
+	status = pm_clock_get_pll_node_id(clock_id, &nid);
+	if (status == PM_RET_SUCCESS)
+		return pm_pll_get_parameter(nid, PM_PLL_PARAM_FBDIV, divider);
+
+	/* Check if clock ID is a valid on-chip clock */
+	status = pm_clock_id_is_valid(clock_id);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	if (pm_clock_has_div(clock_id, PM_CLOCK_DIV0_ID)) {
+		/* Send request to the PMU to get div0 */
+		PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id,
+				 PM_CLOCK_DIV0_ID);
+		status = pm_ipi_send_sync(primary_proc, payload, &val, 1);
+		if (status != PM_RET_SUCCESS)
+			return status;
+		*divider = val;
+	}
+
+	if (pm_clock_has_div(clock_id, PM_CLOCK_DIV1_ID)) {
+		/* Send request to the PMU to get div1 */
+		PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id,
+				 PM_CLOCK_DIV1_ID);
+		status = pm_ipi_send_sync(primary_proc, payload, &val, 1);
+		if (status != PM_RET_SUCCESS)
+			return status;
+		*divider |= val << 16;
+	}
+
+	return status;
+}
+
+/**
+ * pm_clock_setrate - Set the clock rate for given id
+ * @clock_id: Id of the clock
+ * @rate: rate value in hz
+ *
+ * This function is used by master to set rate for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_setrate(unsigned int clock_id,
+				    uint64_t rate)
+{
+	return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/**
+ * pm_clock_getrate - Get the clock rate for given id
+ * @clock_id: Id of the clock
+ * @rate: rate value in hz
+ *
+ * This function is used by master to get rate
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getrate(unsigned int clock_id,
+				    uint64_t *rate)
+{
+	return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/**
+ * pm_clock_setparent - Set the clock parent for given id
+ * @clock_id: Id of the clock
+ * @parent_index: Index of the parent clock into clock's parents array
+ *
+ * This function is used by master to set parent for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_setparent(unsigned int clock_id,
+				      unsigned int parent_index)
+{
+	struct pm_pll *pll;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	enum pm_ret_status status;
+
+	/* First try to handle it as a PLL */
+	pll = pm_clock_get_pll_by_related_clk(clock_id);
+	if (pll)
+		return pm_clock_pll_set_parent(pll, clock_id, parent_index);
+
+	/* Check if clock ID is a valid on-chip clock */
+	status = pm_clock_id_is_valid(clock_id);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_CLOCK_SETPARENT, clock_id, parent_index);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_getparent - Get the clock parent for given id
+ * @clock_id: Id of the clock
+ * @parent_index: parent index
+ *
+ * This function is used by master to get parent index
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getparent(unsigned int clock_id,
+				      unsigned int *parent_index)
+{
+	struct pm_pll *pll;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	enum pm_ret_status status;
+
+	/* First try to handle it as a PLL */
+	pll = pm_clock_get_pll_by_related_clk(clock_id);
+	if (pll)
+		return pm_clock_pll_get_parent(pll, clock_id, parent_index);
+
+	/* Check if clock ID is a valid on-chip clock */
+	status = pm_clock_id_is_valid(clock_id);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETPARENT, clock_id);
+	return pm_ipi_send_sync(primary_proc, payload, parent_index, 1);
+}
+
+/**
+ * pm_pinctrl_get_num_pins - PM call to request number of pins
+ * @npins: Number of pins
+ *
+ * This function is used by master to get number of pins
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_num_pins(uint32_t *npins)
+{
+	return pm_api_pinctrl_get_num_pins(npins);
+}
+
+/**
+ * pm_pinctrl_get_num_functions - PM call to request number of functions
+ * @nfuncs: Number of functions
+ *
+ * This function is used by master to get number of functions
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_num_functions(uint32_t *nfuncs)
+{
+	return pm_api_pinctrl_get_num_functions(nfuncs);
+}
+
+/**
+ * pm_pinctrl_get_num_function_groups - PM call to request number of
+ *					function groups
+ * @fid: Id of function
+ * @ngroups: Number of function groups
+ *
+ * This function is used by master to get number of function groups specified
+ * by given function Id
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_num_function_groups(unsigned int fid,
+							     uint32_t *ngroups)
+{
+	return pm_api_pinctrl_get_num_func_groups(fid, ngroups);
+}
+
+/**
+ * pm_pinctrl_get_function_name - PM call to request function name
+ * @fid: Id of function
+ * @name: Name of function
+ *
+ * This function is used by master to get name of function specified
+ * by given function Id
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_function_name(unsigned int fid,
+						       char *name)
+{
+	return pm_api_pinctrl_get_function_name(fid, name);
+}
+
+/**
+ * pm_pinctrl_get_function_groups - PM call to request function groups
+ * @fid: Id of function
+ * @index: Index of next function groups
+ * @groups: Function groups
+ *
+ * This function is used by master to get function groups specified
+ * by given function Id. This API will return 6 function groups with
+ * a single response. To get other function groups, master should call
+ * same API in loop with new function groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return function groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * function groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_function_groups(unsigned int fid,
+							 unsigned int index,
+							 uint16_t *groups)
+{
+	return pm_api_pinctrl_get_function_groups(fid, index, groups);
+}
+
+/**
+ * pm_pinctrl_get_pin_groups - PM call to request pin groups
+ * @pin_id: Id of pin
+ * @index: Index of next pin groups
+ * @groups: pin groups
+ *
+ * This function is used by master to get pin groups specified
+ * by given pin Id. This API will return 6 pin groups with
+ * a single response. To get other pin groups, master should call
+ * same API in loop with new pin groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return pin groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * pin groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_pin_groups(unsigned int pin_id,
+						    unsigned int index,
+						    uint16_t *groups)
+{
+	return pm_api_pinctrl_get_pin_groups(pin_id, index, groups);
+}
+
+/**
+ * pm_query_data() -  PM API for querying firmware data
+ * @arg1	Argument 1 to requested IOCTL call
+ * @arg2	Argument 2 to requested IOCTL call
+ * @arg3	Argument 3 to requested IOCTL call
+ * @arg4	Argument 4 to requested IOCTL call
+ * @data	Returned output data
+ *
+ * This function returns requested data.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_query_data(enum pm_query_id qid,
+				 unsigned int arg1,
+				 unsigned int arg2,
+				 unsigned int arg3,
+				 unsigned int *data)
+{
+	enum pm_ret_status ret;
+
+	switch (qid) {
+	case PM_QID_CLOCK_GET_NAME:
+		ret = pm_clock_get_name(arg1, (char *)data);
+		break;
+	case PM_QID_CLOCK_GET_TOPOLOGY:
+		ret = pm_clock_get_topology(arg1, arg2, &data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
+		ret = pm_clock_get_fixedfactor_params(arg1, &data[1], &data[2]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_CLOCK_GET_PARENTS:
+		ret = pm_clock_get_parents(arg1, arg2, &data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_CLOCK_GET_ATTRIBUTES:
+		ret = pm_clock_get_attributes(arg1, &data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_PINCTRL_GET_NUM_PINS:
+		ret = pm_pinctrl_get_num_pins(&data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_PINCTRL_GET_NUM_FUNCTIONS:
+		ret = pm_pinctrl_get_num_functions(&data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS:
+		ret = pm_pinctrl_get_num_function_groups(arg1, &data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_PINCTRL_GET_FUNCTION_NAME:
+		ret = pm_pinctrl_get_function_name(arg1, (char *)data);
+		break;
+	case PM_QID_PINCTRL_GET_FUNCTION_GROUPS:
+		ret = pm_pinctrl_get_function_groups(arg1, arg2,
+						     (uint16_t *)&data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_PINCTRL_GET_PIN_GROUPS:
+		ret = pm_pinctrl_get_pin_groups(arg1, arg2,
+						(uint16_t *)&data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	case PM_QID_CLOCK_GET_NUM_CLOCKS:
+		ret = pm_clock_get_num_clocks(&data[1]);
+		data[0] = (unsigned int)ret;
+		break;
+	default:
+		ret = PM_RET_ERROR_ARGS;
+		WARN("Unimplemented query service call: 0x%x\n", qid);
+		break;
+	}
+
+	return ret;
+}
+
+enum pm_ret_status pm_sha_hash(uint32_t address_high,
+				    uint32_t address_low,
+				    uint32_t size,
+				    uint32_t flags)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_SECURE_SHA, address_high, address_low,
+				 size, flags);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+enum pm_ret_status pm_rsa_core(uint32_t address_high,
+				    uint32_t address_low,
+				    uint32_t size,
+				    uint32_t flags)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA, address_high, address_low,
+				 size, flags);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+enum pm_ret_status pm_secure_image(uint32_t address_low,
+				   uint32_t address_high,
+				   uint32_t key_lo,
+				   uint32_t key_hi,
+				   uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_SECURE_IMAGE, address_high, address_low,
+			 key_hi, key_lo);
+	return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
+
+/**
+ * pm_fpga_read - Perform the fpga configuration readback
+ *
+ * @reg_numframes: Configuration register offset (or) Number of frames to read
+ * @address_low: lower 32-bit Linear memory space address
+ * @address_high: higher 32-bit Linear memory space address
+ * @readback_type: Type of fpga readback operation
+ *		   0 -- Configuration Register readback
+ *		   1 -- Configuration Data readback
+ * @value:	Value to read
+ *
+ * This function provides access to the xilfpga library to read
+ * the PL configuration.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_fpga_read(uint32_t reg_numframes,
+				uint32_t address_low,
+				uint32_t address_high,
+				uint32_t readback_type,
+				uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_FPGA_READ, reg_numframes, address_low,
+			 address_high, readback_type);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/*
+ * pm_pll_set_parameter() - Set the PLL parameter value
+ * @nid		Node id of the target PLL
+ * @param_id	ID of the PLL parameter
+ * @value	Parameter value to be set
+ *
+ * Setting the parameter will have physical effect once the PLL mode is set to
+ * integer or fractional.
+ *
+ * @return	Error if an argument is not valid or status as returned by the
+ *		PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid,
+					enum pm_pll_param param_id,
+					unsigned int value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Check if given node ID is a PLL node */
+	if (nid < NODE_APLL || nid > NODE_IOPLL)
+		return PM_RET_ERROR_ARGS;
+
+	/* Check if parameter ID is valid and return an error if it's not */
+	if (param_id >= PM_PLL_PARAM_MAX)
+		return PM_RET_ERROR_ARGS;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD4(payload, PM_PLL_SET_PARAMETER, nid, param_id, value);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_parameter() - Get the PLL parameter value
+ * @nid		Node id of the target PLL
+ * @param_id	ID of the PLL parameter
+ * @value	Location to store the parameter value
+ *
+ * @return	Error if an argument is not valid or status as returned by the
+ *		PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+					enum pm_pll_param param_id,
+					unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Check if given node ID is a PLL node */
+	if (nid < NODE_APLL || nid > NODE_IOPLL)
+		return PM_RET_ERROR_ARGS;
+
+	/* Check if parameter ID is valid and return an error if it's not */
+	if (param_id >= PM_PLL_PARAM_MAX)
+		return PM_RET_ERROR_ARGS;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_PLL_GET_PARAMETER, nid, param_id);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_pll_set_mode() - Set the PLL mode
+ * @nid		Node id of the target PLL
+ * @mode	PLL mode to be set
+ *
+ * If reset mode is set the PM controller will first bypass the PLL and then
+ * assert the reset. If integer or fractional mode is set the PM controller will
+ * ensure that the complete PLL programming sequence is satisfied. After this
+ * function returns success the PLL is locked and its bypass is deasserted.
+ *
+ * @return	Error if an argument is not valid or status as returned by the
+ *		PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Check if given node ID is a PLL node */
+	if (nid < NODE_APLL || nid > NODE_IOPLL)
+		return PM_RET_ERROR_ARGS;
+
+	/* Check if PLL mode is valid */
+	if (mode >= PM_PLL_MODE_MAX)
+		return PM_RET_ERROR_ARGS;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_PLL_SET_MODE, nid, mode);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_mode() - Get the PLL mode
+ * @nid		Node id of the target PLL
+ * @mode	Location to store the mode of the PLL
+ *
+ * @return	Error if an argument is not valid or status as returned by the
+ *		PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Check if given node ID is a PLL node */
+	if (nid < NODE_APLL || nid > NODE_IOPLL)
+		return PM_RET_ERROR_ARGS;
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_PLL_GET_MODE, nid);
+	return pm_ipi_send_sync(primary_proc, payload, mode, 1);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
new file mode 100644
index 0000000..282ca3d
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_API_SYS_H
+#define PM_API_SYS_H
+
+#include <stdint.h>
+
+#include "pm_defs.h"
+
+enum pm_query_id {
+	PM_QID_INVALID,
+	PM_QID_CLOCK_GET_NAME,
+	PM_QID_CLOCK_GET_TOPOLOGY,
+	PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
+	PM_QID_CLOCK_GET_PARENTS,
+	PM_QID_CLOCK_GET_ATTRIBUTES,
+	PM_QID_PINCTRL_GET_NUM_PINS,
+	PM_QID_PINCTRL_GET_NUM_FUNCTIONS,
+	PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
+	PM_QID_PINCTRL_GET_FUNCTION_NAME,
+	PM_QID_PINCTRL_GET_FUNCTION_GROUPS,
+	PM_QID_PINCTRL_GET_PIN_GROUPS,
+	PM_QID_CLOCK_GET_NUM_CLOCKS,
+};
+
+/**********************************************************
+ * System-level API function declarations
+ **********************************************************/
+enum pm_ret_status pm_req_suspend(enum pm_node_id nid,
+				  enum pm_request_ack ack,
+				  unsigned int latency,
+				  unsigned int state);
+
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+				   unsigned int latency,
+				   unsigned int state,
+				   uintptr_t address);
+
+enum pm_ret_status pm_force_powerdown(enum pm_node_id nid,
+				      enum pm_request_ack ack);
+
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
+
+enum pm_ret_status pm_req_wakeup(enum pm_node_id nid,
+				 unsigned int set_address,
+				 uintptr_t address,
+				 enum pm_request_ack ack);
+
+enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
+					enum pm_node_id wkup_node,
+					unsigned int enable);
+
+enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype);
+
+enum pm_ret_status pm_init_suspend_cb(enum pm_suspend_reason reason,
+				      unsigned int latency,
+				      unsigned int state,
+				      unsigned int timeout);
+
+/* API functions for managing PM Slaves */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+			       unsigned int capabilities,
+			       unsigned int qos,
+			       enum pm_request_ack ack);
+enum pm_ret_status pm_release_node(enum pm_node_id nid);
+
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+				      unsigned int capabilities,
+				      unsigned int qos,
+				      enum pm_request_ack ack);
+enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
+				      unsigned int latency);
+
+/* Miscellaneous API functions */
+enum pm_ret_status pm_get_api_version(unsigned int *version);
+enum pm_ret_status pm_set_configuration(unsigned int phys_addr);
+enum pm_ret_status pm_init_finalize(void);
+enum pm_ret_status pm_get_node_status(enum pm_node_id node,
+				      uint32_t *ret_buff);
+enum pm_ret_status pm_register_notifier(enum pm_node_id nid,
+					unsigned int event,
+					unsigned int wake,
+					unsigned int enable);
+enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
+					    enum pm_opchar_type type,
+					    uint32_t *result);
+enum pm_ret_status pm_acknowledge_cb(enum pm_node_id nid,
+				     enum pm_ret_status status,
+				     unsigned int oppoint);
+enum pm_ret_status pm_notify_cb(enum pm_node_id nid,
+				unsigned int event,
+				unsigned int oppoint);
+
+/* Direct-Control API functions */
+enum pm_ret_status pm_reset_assert(unsigned int reset_id,
+				   unsigned int assert);
+enum pm_ret_status pm_reset_get_status(unsigned int reset_id,
+				       unsigned int *reset_status);
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+				 unsigned int mask,
+				 unsigned int value);
+enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value);
+enum pm_ret_status pm_fpga_load(uint32_t address_low,
+				uint32_t address_high,
+				uint32_t size,
+				uint32_t flags);
+enum pm_ret_status pm_fpga_get_status(unsigned int *value);
+
+enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status pm_secure_rsaaes(uint32_t address_high,
+				    uint32_t address_low,
+				    uint32_t size,
+				    uint32_t flags);
+unsigned int pm_get_shutdown_scope(void);
+enum pm_ret_status pm_pinctrl_request(unsigned int pin);
+enum pm_ret_status pm_pinctrl_release(unsigned int pin);
+enum pm_ret_status pm_pinctrl_get_function(unsigned int pin,
+					   enum pm_node_id *nid);
+enum pm_ret_status pm_pinctrl_set_function(unsigned int pin,
+					   enum pm_node_id nid);
+enum pm_ret_status pm_pinctrl_get_config(unsigned int pin,
+					 unsigned int param,
+					 unsigned int *value);
+enum pm_ret_status pm_pinctrl_set_config(unsigned int pin,
+					 unsigned int param,
+					 unsigned int value);
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+			    unsigned int ioctl_id,
+			    unsigned int arg1,
+			    unsigned int arg2,
+			    unsigned int *value);
+enum pm_ret_status pm_clock_enable(unsigned int clock_id);
+enum pm_ret_status pm_clock_disable(unsigned int clock_id);
+enum pm_ret_status pm_clock_getstate(unsigned int clock_id,
+				     unsigned int *state);
+enum pm_ret_status pm_clock_setdivider(unsigned int clock_id,
+				       unsigned int divider);
+enum pm_ret_status pm_clock_getdivider(unsigned int clock_id,
+				       unsigned int *divider);
+enum pm_ret_status pm_clock_setrate(unsigned int clock_id,
+				    uint64_t rate);
+enum pm_ret_status pm_clock_getrate(unsigned int clock_id,
+				    uint64_t *rate);
+enum pm_ret_status pm_clock_setparent(unsigned int clock_id,
+				      unsigned int parent_id);
+enum pm_ret_status pm_clock_getparent(unsigned int clock_id,
+				      unsigned int *parent_id);
+enum pm_ret_status pm_query_data(enum pm_query_id qid,
+				 unsigned int arg1,
+				 unsigned int arg2,
+				 unsigned int arg3,
+				 unsigned int *data);
+enum pm_ret_status pm_sha_hash(uint32_t address_high,
+				    uint32_t address_low,
+				    uint32_t size,
+				    uint32_t flags);
+enum pm_ret_status pm_rsa_core(uint32_t address_high,
+				    uint32_t address_low,
+				    uint32_t size,
+				    uint32_t flags);
+enum pm_ret_status pm_secure_image(uint32_t address_low,
+				   uint32_t address_high,
+				   uint32_t key_lo,
+				   uint32_t key_hi,
+				   uint32_t *value);
+
+enum pm_ret_status pm_fpga_read(uint32_t reg_numframes,
+				uint32_t address_low,
+				uint32_t address_high,
+				uint32_t readback_type,
+				uint32_t *value);
+enum pm_ret_status pm_aes_engine(uint32_t address_high,
+				 uint32_t address_low,
+				 uint32_t  *value);
+
+enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid,
+				enum pm_pll_param param_id,
+				unsigned int value);
+
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+				enum pm_pll_param param_id,
+				unsigned int *value);
+
+enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode);
+enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode);
+
+#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
new file mode 100644
index 0000000..163e891
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+#include <plat_ipi.h>
+#include <zynqmp_def.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+
+#define IRQ_MAX		84
+#define NUM_GICD_ISENABLER	((IRQ_MAX >> 5) + 1)
+#define UNDEFINED_CPUID		(~0)
+
+#define PM_SUSPEND_MODE_STD		0
+#define PM_SUSPEND_MODE_POWER_OFF	1
+
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+extern const struct pm_ipi apu_ipi;
+
+const struct pm_ipi apu_ipi = {
+	.local_ipi_id = IPI_ID_APU,
+	.remote_ipi_id = IPI_ID_PMU0,
+	.buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+static uint32_t suspend_mode = PM_SUSPEND_MODE_STD;
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+	{
+		.node_id = NODE_APU_0,
+		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = NODE_APU_1,
+		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = NODE_APU_2,
+		.pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK,
+		.ipi = &apu_ipi,
+	},
+	{
+		.node_id = NODE_APU_3,
+		.pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK,
+		.ipi = &apu_ipi,
+	},
+};
+
+/* Interrupt to PM node ID map */
+static enum pm_node_id irq_node_map[IRQ_MAX + 1] = {
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 3 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 7 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 11 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_NAND,
+	NODE_QSPI,	/* 15 */
+	NODE_GPIO,
+	NODE_I2C_0,
+	NODE_I2C_1,
+	NODE_SPI_0,	/* 19 */
+	NODE_SPI_1,
+	NODE_UART_0,
+	NODE_UART_1,
+	NODE_CAN_0,	/* 23 */
+	NODE_CAN_1,
+	NODE_UNKNOWN,
+	NODE_RTC,
+	NODE_RTC,	/* 27 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 31 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 35, NODE_IPI_APU */
+	NODE_TTC_0,
+	NODE_TTC_0,
+	NODE_TTC_0,
+	NODE_TTC_1,	/* 39 */
+	NODE_TTC_1,
+	NODE_TTC_1,
+	NODE_TTC_2,
+	NODE_TTC_2,	/* 43 */
+	NODE_TTC_2,
+	NODE_TTC_3,
+	NODE_TTC_3,
+	NODE_TTC_3,	/* 47 */
+	NODE_SD_0,
+	NODE_SD_1,
+	NODE_SD_0,
+	NODE_SD_1,	/* 51 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 55 */
+	NODE_UNKNOWN,
+	NODE_ETH_0,
+	NODE_ETH_0,
+	NODE_ETH_1,	/* 59 */
+	NODE_ETH_1,
+	NODE_ETH_2,
+	NODE_ETH_2,
+	NODE_ETH_3,	/* 63 */
+	NODE_ETH_3,
+	NODE_USB_0,
+	NODE_USB_0,
+	NODE_USB_0,	/* 67 */
+	NODE_USB_0,
+	NODE_USB_0,
+	NODE_USB_1,
+	NODE_USB_1,	/* 71 */
+	NODE_USB_1,
+	NODE_USB_1,
+	NODE_USB_1,
+	NODE_USB_0,	/* 75 */
+	NODE_USB_0,
+	NODE_ADMA,
+	NODE_ADMA,
+	NODE_ADMA,	/* 79 */
+	NODE_ADMA,
+	NODE_ADMA,
+	NODE_ADMA,
+	NODE_ADMA,	/* 83 */
+	NODE_ADMA,
+};
+
+/**
+ * irq_to_pm_node - Get PM node ID corresponding to the interrupt number
+ * @irq:	Interrupt number
+ *
+ * Return:	PM node ID corresponding to the specified interrupt
+ */
+static enum pm_node_id irq_to_pm_node(unsigned int irq)
+{
+	assert(irq <= IRQ_MAX);
+	return irq_node_map[irq];
+}
+
+/**
+ * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake
+ *				sources in the PMU firmware
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+	uint32_t reg_num;
+	uint8_t pm_wakeup_nodes_set[NODE_MAX];
+	uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4;
+
+	/* In case of power-off suspend, only NODE_EXTERN must be set */
+	if (suspend_mode == PM_SUSPEND_MODE_POWER_OFF) {
+		enum pm_ret_status ret;
+
+		ret = pm_set_wakeup_source(NODE_APU, NODE_EXTERN, 1);
+		/**
+		 * If NODE_EXTERN could not be set as wake source, proceed with
+		 * standard suspend (no one will wake the system otherwise)
+		 */
+		if (ret == PM_RET_SUCCESS)
+			return;
+	}
+
+	zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
+
+	for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
+
+		if (!reg)
+			continue;
+
+		while (reg) {
+			enum pm_node_id node;
+			uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+			idx = __builtin_ctz(lowest_set);
+			irq = base_irq + idx;
+
+			if (irq > IRQ_MAX)
+				break;
+
+			node = irq_to_pm_node(irq);
+			reg &= ~lowest_set;
+
+			if ((node != NODE_UNKNOWN) &&
+			    (!pm_wakeup_nodes_set[node])) {
+				ret = pm_set_wakeup_source(NODE_APU, node, 1);
+				pm_wakeup_nodes_set[node] = !ret;
+			}
+		}
+	}
+}
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @cpuid:	id of the cpu whose proc struct pointer should be returned
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc(unsigned int cpuid)
+{
+	if (cpuid < ARRAY_SIZE(pm_procs_all))
+		return &pm_procs_all[cpuid];
+
+	return NULL;
+}
+
+/**
+ * pm_get_proc_by_node() - returns pointer to the proc structure
+ * @nid:	node id of the processor
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+		if (nid == pm_procs_all[i].node_id)
+			return &pm_procs_all[i];
+	}
+	return NULL;
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID
+ * @nid:	node id of the processor
+ *
+ * Return: the cpu ID (starting from 0) for the subsystem
+ */
+static unsigned int pm_get_cpuid(enum pm_node_id nid)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+		if (pm_procs_all[i].node_id == nid)
+			return i;
+	}
+	return UNDEFINED_CPUID;
+}
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ */
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
+{
+	bakery_lock_get(&pm_client_secure_lock);
+
+	if (state == PM_STATE_SUSPEND_TO_RAM)
+		pm_client_set_wakeup_sources();
+
+	/* Set powerdown request */
+	mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
+
+	bakery_lock_release(&pm_client_secure_lock);
+}
+
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request
+ */
+void pm_client_abort_suspend(void)
+{
+	/* Enable interrupts at processor level (for current cpu) */
+	gicv2_cpuif_enable();
+
+	bakery_lock_get(&pm_client_secure_lock);
+
+	/* Clear powerdown request */
+	mmio_write_32(APU_PWRCTL,
+		 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
+
+	bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+	unsigned int cpuid = pm_get_cpuid(proc->node_id);
+
+	if (cpuid == UNDEFINED_CPUID)
+		return;
+
+	bakery_lock_get(&pm_client_secure_lock);
+
+	/* clear powerdown bit for affected cpu */
+	uint32_t val = mmio_read_32(APU_PWRCTL);
+	val &= ~(proc->pwrdn_mask);
+	mmio_write_32(APU_PWRCTL, val);
+
+	bakery_lock_release(&pm_client_secure_lock);
+}
+
+enum pm_ret_status pm_set_suspend_mode(uint32_t mode)
+{
+	if ((mode != PM_SUSPEND_MODE_STD) &&
+	    (mode != PM_SUSPEND_MODE_POWER_OFF))
+		return PM_RET_ERROR_ARGS;
+
+	suspend_mode = mode;
+	return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h
new file mode 100644
index 0000000..adbb76f
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains APU specific macros and macros to be defined depending on
+ * the execution environment.
+ */
+
+#ifndef PM_CLIENT_H
+#define PM_CLIENT_H
+
+#include "pm_common.h"
+#include "pm_defs.h"
+
+/* Functions to be implemented by each PU */
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
+void pm_client_abort_suspend(void);
+void pm_client_wakeup(const struct pm_proc *proc);
+enum pm_ret_status set_ocm_retention(void);
+enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
+
+/* Global variables to be set in pm_client.c */
+extern const struct pm_proc *primary_proc;
+
+#endif /* PM_CLIENT_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
new file mode 100644
index 0000000..cae36c9
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* ZynqMP power management enums and defines */
+
+#ifndef PM_DEFS_H
+#define PM_DEFS_H
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+/*
+ * Version number is a 32bit value, like:
+ * (PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR
+ */
+#define PM_VERSION_MAJOR	1
+#define PM_VERSION_MINOR	0
+
+#define PM_VERSION	((PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR)
+
+/* Capabilities for RAM */
+#define PM_CAP_ACCESS	0x1U
+#define PM_CAP_CONTEXT	0x2U
+
+#define MAX_LATENCY	(~0U)
+#define MAX_QOS		100U
+
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE		0x0U
+#define PM_STATE_SUSPEND_TO_RAM		0xFU
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+enum pm_api_id {
+	/* Miscellaneous API functions: */
+	PM_GET_API_VERSION = 1, /* Do not change or move */
+	PM_SET_CONFIGURATION,
+	PM_GET_NODE_STATUS,
+	PM_GET_OP_CHARACTERISTIC,
+	PM_REGISTER_NOTIFIER,
+	/* API for suspending of PUs: */
+	PM_REQ_SUSPEND,
+	PM_SELF_SUSPEND,
+	PM_FORCE_POWERDOWN,
+	PM_ABORT_SUSPEND,
+	PM_REQ_WAKEUP,
+	PM_SET_WAKEUP_SOURCE,
+	PM_SYSTEM_SHUTDOWN,
+	/* API for managing PM slaves: */
+	PM_REQ_NODE,
+	PM_RELEASE_NODE,
+	PM_SET_REQUIREMENT,
+	PM_SET_MAX_LATENCY,
+	/* Direct control API functions: */
+	PM_RESET_ASSERT,
+	PM_RESET_GET_STATUS,
+	PM_MMIO_WRITE,
+	PM_MMIO_READ,
+	PM_INIT_FINALIZE,
+	PM_FPGA_LOAD,
+	PM_FPGA_GET_STATUS,
+	PM_GET_CHIPID,
+	PM_SECURE_RSA_AES,
+	PM_SECURE_SHA,
+	PM_SECURE_RSA,
+	PM_PINCTRL_REQUEST,
+	PM_PINCTRL_RELEASE,
+	PM_PINCTRL_GET_FUNCTION,
+	PM_PINCTRL_SET_FUNCTION,
+	PM_PINCTRL_CONFIG_PARAM_GET,
+	PM_PINCTRL_CONFIG_PARAM_SET,
+	PM_IOCTL,
+	/* API to query information from firmware */
+	PM_QUERY_DATA,
+	/* Clock control API functions */
+	PM_CLOCK_ENABLE,
+	PM_CLOCK_DISABLE,
+	PM_CLOCK_GETSTATE,
+	PM_CLOCK_SETDIVIDER,
+	PM_CLOCK_GETDIVIDER,
+	PM_CLOCK_SETRATE,
+	PM_CLOCK_GETRATE,
+	PM_CLOCK_SETPARENT,
+	PM_CLOCK_GETPARENT,
+	PM_SECURE_IMAGE,
+	/* FPGA PL Readback */
+	PM_FPGA_READ,
+	PM_SECURE_AES,
+	/* PLL control API functions */
+	PM_PLL_SET_PARAMETER,
+	PM_PLL_GET_PARAMETER,
+	PM_PLL_SET_MODE,
+	PM_PLL_GET_MODE,
+	PM_API_MAX
+};
+
+enum pm_node_id {
+	NODE_UNKNOWN = 0,
+	NODE_APU,
+	NODE_APU_0,
+	NODE_APU_1,
+	NODE_APU_2,
+	NODE_APU_3,
+	NODE_RPU,
+	NODE_RPU_0,
+	NODE_RPU_1,
+	NODE_PLD,
+	NODE_FPD,
+	NODE_OCM_BANK_0,
+	NODE_OCM_BANK_1,
+	NODE_OCM_BANK_2,
+	NODE_OCM_BANK_3,
+	NODE_TCM_0_A,
+	NODE_TCM_0_B,
+	NODE_TCM_1_A,
+	NODE_TCM_1_B,
+	NODE_L2,
+	NODE_GPU_PP_0,
+	NODE_GPU_PP_1,
+	NODE_USB_0,
+	NODE_USB_1,
+	NODE_TTC_0,
+	NODE_TTC_1,
+	NODE_TTC_2,
+	NODE_TTC_3,
+	NODE_SATA,
+	NODE_ETH_0,
+	NODE_ETH_1,
+	NODE_ETH_2,
+	NODE_ETH_3,
+	NODE_UART_0,
+	NODE_UART_1,
+	NODE_SPI_0,
+	NODE_SPI_1,
+	NODE_I2C_0,
+	NODE_I2C_1,
+	NODE_SD_0,
+	NODE_SD_1,
+	NODE_DP,
+	NODE_GDMA,
+	NODE_ADMA,
+	NODE_NAND,
+	NODE_QSPI,
+	NODE_GPIO,
+	NODE_CAN_0,
+	NODE_CAN_1,
+	NODE_EXTERN,
+	NODE_APLL,
+	NODE_VPLL,
+	NODE_DPLL,
+	NODE_RPLL,
+	NODE_IOPLL,
+	NODE_DDR,
+	NODE_IPI_APU,
+	NODE_IPI_RPU_0,
+	NODE_GPU,
+	NODE_PCIE,
+	NODE_PCAP,
+	NODE_RTC,
+	NODE_LPD,
+	NODE_VCU,
+	NODE_IPI_RPU_1,
+	NODE_IPI_PL_0,
+	NODE_IPI_PL_1,
+	NODE_IPI_PL_2,
+	NODE_IPI_PL_3,
+	NODE_PL,
+	NODE_GEM_TSU,
+	NODE_SWDT_0,
+	NODE_SWDT_1,
+	NODE_CSU,
+	NODE_PJTAG,
+	NODE_TRACE,
+	NODE_TESTSCAN,
+	NODE_PMU,
+	NODE_MAX,
+};
+
+enum pm_request_ack {
+	REQ_ACK_NO = 1,
+	REQ_ACK_BLOCKING,
+	REQ_ACK_NON_BLOCKING,
+};
+
+enum pm_abort_reason {
+	ABORT_REASON_WKUP_EVENT = 100,
+	ABORT_REASON_PU_BUSY,
+	ABORT_REASON_NO_PWRDN,
+	ABORT_REASON_UNKNOWN,
+};
+
+enum pm_suspend_reason {
+	SUSPEND_REASON_PU_REQ = 201,
+	SUSPEND_REASON_ALERT,
+	SUSPEND_REASON_SYS_SHUTDOWN,
+};
+
+enum pm_ram_state {
+	PM_RAM_STATE_OFF = 1,
+	PM_RAM_STATE_RETENTION,
+	PM_RAM_STATE_ON,
+};
+
+enum pm_opchar_type {
+	PM_OPCHAR_TYPE_POWER = 1,
+	PM_OPCHAR_TYPE_TEMP,
+	PM_OPCHAR_TYPE_LATENCY,
+};
+
+/**
+ * @PM_RET_SUCCESS:		success
+ * @PM_RET_ERROR_ARGS:		illegal arguments provided
+ * @PM_RET_ERROR_ACCESS:	access rights violation
+ * @PM_RET_ERROR_TIMEOUT:	timeout in communication with PMU
+ * @PM_RET_ERROR_NOTSUPPORTED:	feature not supported
+ * @PM_RET_ERROR_PROC:		node is not a processor node
+ * @PM_RET_ERROR_API_ID:	illegal API ID
+ * @PM_RET_ERROR_OTHER:		other error
+ */
+enum pm_ret_status {
+	PM_RET_SUCCESS,
+	PM_RET_ERROR_ARGS,
+	PM_RET_ERROR_ACCESS,
+	PM_RET_ERROR_TIMEOUT,
+	PM_RET_ERROR_NOTSUPPORTED,
+	PM_RET_ERROR_PROC,
+	PM_RET_ERROR_API_ID,
+	PM_RET_ERROR_FAILURE,
+	PM_RET_ERROR_COMMUNIC,
+	PM_RET_ERROR_DOUBLEREQ,
+	PM_RET_ERROR_OTHER,
+};
+
+/**
+ * @PM_INITIAL_BOOT:	boot is a fresh system startup
+ * @PM_RESUME:		boot is a resume
+ * @PM_BOOT_ERROR:	error, boot cause cannot be identified
+ */
+enum pm_boot_status {
+	PM_INITIAL_BOOT,
+	PM_RESUME,
+	PM_BOOT_ERROR,
+};
+
+/**
+ * @PMF_SHUTDOWN_TYPE_SHUTDOWN:		shutdown
+ * @PMF_SHUTDOWN_TYPE_RESET:		reset/reboot
+ * @PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY:	set the shutdown/reboot scope
+ */
+enum pm_shutdown_type {
+	PMF_SHUTDOWN_TYPE_SHUTDOWN,
+	PMF_SHUTDOWN_TYPE_RESET,
+	PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY,
+};
+
+/**
+ * @PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM:	shutdown/reboot APU subsystem only
+ * @PMF_SHUTDOWN_SUBTYPE_PS_ONLY:	shutdown/reboot entire PS (but not PL)
+ * @PMF_SHUTDOWN_SUBTYPE_SYSTEM:	shutdown/reboot entire system
+ */
+enum pm_shutdown_subtype {
+	PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM,
+	PMF_SHUTDOWN_SUBTYPE_PS_ONLY,
+	PMF_SHUTDOWN_SUBTYPE_SYSTEM,
+};
+
+/**
+ * @PM_PLL_PARAM_DIV2:         Enable for divide by 2 function inside the PLL
+ * @PM_PLL_PARAM_FBDIV:        Feedback divisor integer portion for the PLL
+ * @PM_PLL_PARAM_DATA:         Feedback divisor fractional portion for the PLL
+ * @PM_PLL_PARAM_PRE_SRC:      Clock source for PLL input
+ * @PM_PLL_PARAM_POST_SRC:     Clock source for PLL Bypass mode
+ * @PM_PLL_PARAM_LOCK_DLY:     Lock circuit config settings for lock windowsize
+ * @PM_PLL_PARAM_LOCK_CNT:     Lock circuit counter setting
+ * @PM_PLL_PARAM_LFHF:         PLL loop filter high frequency capacitor control
+ * @PM_PLL_PARAM_CP:           PLL charge pump control
+ * @PM_PLL_PARAM_RES:          PLL loop filter resistor control
+ */
+enum pm_pll_param {
+	PM_PLL_PARAM_DIV2,
+	PM_PLL_PARAM_FBDIV,
+	PM_PLL_PARAM_DATA,
+	PM_PLL_PARAM_PRE_SRC,
+	PM_PLL_PARAM_POST_SRC,
+	PM_PLL_PARAM_LOCK_DLY,
+	PM_PLL_PARAM_LOCK_CNT,
+	PM_PLL_PARAM_LFHF,
+	PM_PLL_PARAM_CP,
+	PM_PLL_PARAM_RES,
+	PM_PLL_PARAM_MAX,
+};
+
+/**
+ * @PM_PLL_MODE_RESET:         PLL is in reset (not locked)
+ * @PM_PLL_MODE_INTEGER:       PLL is locked in integer mode
+ * @PM_PLL_MODE_FRACTIONAL:    PLL is locked in fractional mode
+ */
+enum pm_pll_mode {
+	PM_PLL_MODE_RESET,
+	PM_PLL_MODE_INTEGER,
+	PM_PLL_MODE_FRACTIONAL,
+	PM_PLL_MODE_MAX,
+};
+
+/**
+ * @PM_CLOCK_DIV0_ID:          Clock divider 0
+ * @PM_CLOCK_DIV1_ID:          Clock divider 1
+ */
+enum pm_clock_div_id {
+	PM_CLOCK_DIV0_ID,
+	PM_CLOCK_DIV1_ID,
+};
+
+#endif /* PM_DEFS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..faa2827
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for ZynqMP power management calls and
+ * IPI setup functions for communication with PMU.
+ */
+
+#include <errno.h>
+
+#include <common/runtime_svc.h>
+#if ZYNQMP_WDT_RESTART
+#include <arch_helpers.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#endif
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+
+#define PM_SET_SUSPEND_MODE	0xa02
+#define PM_GET_TRUSTZONE_VERSION	0xa03
+
+/* !0 - UP, 0 - DOWN */
+static int32_t pm_up = 0;
+
+#if ZYNQMP_WDT_RESTART
+static spinlock_t inc_lock;
+static int active_cores = 0;
+#endif
+
+
+/**
+ * pm_context - Structure which contains data for power management
+ * @api_version		version of PM API, must match with one on PMU side
+ * @payload		payload array used to store received
+ *			data from ipi buffer registers
+ */
+static struct {
+	uint32_t api_version;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+} pm_ctx;
+
+#if ZYNQMP_WDT_RESTART
+/**
+ * trigger_wdt_restart() - Trigger warm restart event to APU cores
+ *
+ * This function triggers SGI for all active APU CPUs. SGI handler then
+ * power down CPU and call system reset.
+ */
+static void trigger_wdt_restart(void)
+{
+	uint32_t core_count = 0;
+	uint32_t core_status[3];
+	uint32_t target_cpu_list = 0;
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		pm_get_node_status(NODE_APU_0 + i, core_status);
+		if (core_status[0] == 1) {
+			core_count++;
+			target_cpu_list |= (1 << i);
+		}
+	}
+
+	spin_lock(&inc_lock);
+	active_cores = core_count;
+	spin_unlock(&inc_lock);
+
+	INFO("Active Cores: %d\n", active_cores);
+
+	/* trigger SGI to active cores */
+	gicv2_raise_sgi(ARM_IRQ_SEC_SGI_7, target_cpu_list);
+}
+
+/**
+ * ttc_fiq_handler() - TTC Handler for timer event
+ * @id         number of the highest priority pending interrupt of the type
+ *             that this handler was registered for
+ * @flags      security state, bit[0]
+ * @handler    pointer to 'cpu_context' structure of the current CPU for the
+ *             security state specified in the 'flags' parameter
+ * @cookie     unused
+ *
+ * Function registered as INTR_TYPE_EL3 interrupt handler
+ *
+ * When WDT event is received in PMU, PMU needs to notify master to do cleanup
+ * if required. PMU sets up timer and starts timer to overflow in zero time upon
+ * WDT event. ATF handles this timer event and takes necessary action required
+ * for warm restart.
+ *
+ * In presence of non-secure software layers (EL1/2) sets the interrupt
+ * at registered entrance in GIC and informs that PMU responsed or demands
+ * action.
+ */
+static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle,
+                               void *cookie)
+{
+	INFO("BL31: Got TTC FIQ\n");
+
+	/* Clear TTC interrupt by reading interrupt register */
+	mmio_read_32(TTC3_INTR_REGISTER_1);
+
+	/* Disable the timer interrupts */
+	mmio_write_32(TTC3_INTR_ENABLE_1, 0);
+
+	trigger_wdt_restart();
+
+	return 0;
+}
+
+/**
+ * zynqmp_sgi7_irq() - Handler for SGI7 IRQ
+ * @id         number of the highest priority pending interrupt of the type
+ *             that this handler was registered for
+ * @flags      security state, bit[0]
+ * @handler    pointer to 'cpu_context' structure of the current CPU for the
+ *             security state specified in the 'flags' parameter
+ * @cookie     unused
+ *
+ * Function registered as INTR_TYPE_EL3 interrupt handler
+ *
+ * On receiving WDT event from PMU, ATF generates SGI7 to all running CPUs.
+ * In response to SGI7 interrupt, each CPUs do clean up if required and last
+ * running CPU calls system restart.
+ */
+static uint64_t __unused __dead2 zynqmp_sgi7_irq(uint32_t id, uint32_t flags,
+                                                void *handle, void *cookie)
+{
+	int i;
+	/* enter wfi and stay there */
+	INFO("Entering wfi\n");
+
+	spin_lock(&inc_lock);
+	active_cores--;
+
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(BASE_GICD_BASE + GICD_CPENDSGIR + 4 * i,
+				0xffffffff);
+	}
+
+	spin_unlock(&inc_lock);
+
+	if (active_cores == 0) {
+		pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET,
+				PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM);
+	}
+
+	/* enter wfi and stay there */
+	while (1)
+		wfi();
+}
+
+/**
+ * pm_wdt_restart_setup() - Setup warm restart interrupts
+ *
+ * This function sets up handler for SGI7 and TTC interrupts
+ * used for warm restart.
+ */
+static int pm_wdt_restart_setup(void)
+{
+	int ret;
+
+	/* register IRQ handler for SGI7 */
+	ret = request_intr_type_el3(ARM_IRQ_SEC_SGI_7, zynqmp_sgi7_irq);
+	if (ret) {
+		WARN("BL31: registering SGI7 interrupt failed\n");
+		goto err;
+	}
+
+	ret = request_intr_type_el3(IRQ_TTC3_1, ttc_fiq_handler);
+	if (ret)
+		WARN("BL31: registering TTC3 interrupt failed\n");
+
+err:
+	return ret;
+}
+#endif
+
+/**
+ * pm_setup() - PM service setup
+ *
+ * @return	On success, the initialization function must return 0.
+ *		Any other return value will cause the framework to ignore
+ *		the service
+ *
+ * Initialization functions for ZynqMP power management for
+ * communicaton with PMU.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ */
+int pm_setup(void)
+{
+	int status, ret;
+
+	status = pm_ipi_init(primary_proc);
+
+#if ZYNQMP_WDT_RESTART
+	status = pm_wdt_restart_setup();
+	if (status)
+		WARN("BL31: warm-restart setup failed\n");
+#endif
+
+	if (status >= 0) {
+		INFO("BL31: PM Service Init Complete: API v%d.%d\n",
+		     PM_VERSION_MAJOR, PM_VERSION_MINOR);
+		ret = 0;
+	} else {
+		INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
+		ret = status;
+	}
+
+	pm_up = !status;
+
+	return ret;
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie  - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return  - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+			uint64_t x4, void *cookie, void *handle, uint64_t flags)
+{
+	enum pm_ret_status ret;
+
+	uint32_t pm_arg[4];
+
+	/* Handle case where PM wasn't initialized properly */
+	if (!pm_up)
+		SMC_RET1(handle, SMC_UNK);
+
+	pm_arg[0] = (uint32_t)x1;
+	pm_arg[1] = (uint32_t)(x1 >> 32);
+	pm_arg[2] = (uint32_t)x2;
+	pm_arg[3] = (uint32_t)(x2 >> 32);
+
+	switch (smc_fid & FUNCID_NUM_MASK) {
+	/* PM API Functions */
+	case PM_SELF_SUSPEND:
+		ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+				      pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_REQ_SUSPEND:
+		ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+				     pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_REQ_WAKEUP:
+	{
+		/* Use address flag is encoded in the 1st bit of the low-word */
+		unsigned int set_addr = pm_arg[1] & 0x1;
+		uint64_t address = (uint64_t)pm_arg[2] << 32;
+
+		address |= pm_arg[1] & (~0x1);
+		ret = pm_req_wakeup(pm_arg[0], set_addr, address,
+				    pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+	}
+
+	case PM_FORCE_POWERDOWN:
+		ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_ABORT_SUSPEND:
+		ret = pm_abort_suspend(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SET_WAKEUP_SOURCE:
+		ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SYSTEM_SHUTDOWN:
+		ret = pm_system_shutdown(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_REQ_NODE:
+		ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_RELEASE_NODE:
+		ret = pm_release_node(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SET_REQUIREMENT:
+		ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
+					 pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SET_MAX_LATENCY:
+		ret = pm_set_max_latency(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_GET_API_VERSION:
+		/* Check is PM API version already verified */
+		if (pm_ctx.api_version == PM_VERSION) {
+			SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+				 ((uint64_t)PM_VERSION << 32));
+		}
+
+		ret = pm_get_api_version(&pm_ctx.api_version);
+		/*
+		 * Enable IPI IRQ
+		 * assume the rich OS is OK to handle callback IRQs now.
+		 * Even if we were wrong, it would not enable the IRQ in
+		 * the GIC.
+		 */
+		pm_ipi_irq_enable(primary_proc);
+		SMC_RET1(handle, (uint64_t)ret |
+			 ((uint64_t)pm_ctx.api_version << 32));
+
+	case PM_SET_CONFIGURATION:
+		ret = pm_set_configuration(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_INIT_FINALIZE:
+		ret = pm_init_finalize();
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_GET_NODE_STATUS:
+	{
+		uint32_t buff[3];
+
+		ret = pm_get_node_status(pm_arg[0], buff);
+		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
+			 (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
+	}
+
+	case PM_GET_OP_CHARACTERISTIC:
+	{
+		uint32_t result;
+
+		ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
+	}
+
+	case PM_REGISTER_NOTIFIER:
+		ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
+					   pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_RESET_ASSERT:
+		ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_RESET_GET_STATUS:
+	{
+		uint32_t reset_status;
+
+		ret = pm_reset_get_status(pm_arg[0], &reset_status);
+		SMC_RET1(handle, (uint64_t)ret |
+			 ((uint64_t)reset_status << 32));
+	}
+
+	/* PM memory access functions */
+	case PM_MMIO_WRITE:
+		ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_MMIO_READ:
+	{
+		uint32_t value;
+
+		ret = pm_mmio_read(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_FPGA_LOAD:
+		ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_FPGA_GET_STATUS:
+	{
+		uint32_t value;
+
+		ret = pm_fpga_get_status(&value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_GET_CHIPID:
+	{
+		uint32_t result[2];
+
+		ret = pm_get_chipid(result);
+		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
+			 result[1]);
+	}
+
+	case PM_SECURE_RSA_AES:
+		ret = pm_secure_rsaaes(pm_arg[0], pm_arg[1], pm_arg[2],
+				       pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_REQUEST:
+		ret = pm_pinctrl_request(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_RELEASE:
+		ret = pm_pinctrl_release(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_GET_FUNCTION:
+	{
+		uint32_t value = 0;
+
+		ret = pm_pinctrl_get_function(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_PINCTRL_SET_FUNCTION:
+		ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_CONFIG_PARAM_GET:
+	{
+		uint32_t value;
+
+		ret = pm_pinctrl_get_config(pm_arg[0], pm_arg[1], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_PINCTRL_CONFIG_PARAM_SET:
+		ret = pm_pinctrl_set_config(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_IOCTL:
+	{
+		uint32_t value;
+
+		ret = pm_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+			       pm_arg[3], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_QUERY_DATA:
+	{
+		uint32_t data[4] = { 0 };
+
+		ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+				    pm_arg[3], data);
+		SMC_RET2(handle, (uint64_t)data[0]  | ((uint64_t)data[1] << 32),
+			 (uint64_t)data[2] | ((uint64_t)data[3] << 32));
+	}
+
+	case PM_CLOCK_ENABLE:
+		ret = pm_clock_enable(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_DISABLE:
+		ret = pm_clock_disable(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETSTATE:
+	{
+		uint32_t value;
+
+		ret = pm_clock_getstate(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_CLOCK_SETDIVIDER:
+		ret = pm_clock_setdivider(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETDIVIDER:
+	{
+		uint32_t value;
+
+		ret = pm_clock_getdivider(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_CLOCK_SETRATE:
+		ret = pm_clock_setrate(pm_arg[0],
+		       ((uint64_t)pm_arg[2]) << 32 | pm_arg[1]);
+
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETRATE:
+	{
+		uint64_t value;
+
+		ret = pm_clock_getrate(pm_arg[0], &value);
+		SMC_RET2(handle, (uint64_t)ret |
+				  (((uint64_t)value & 0xFFFFFFFFU) << 32U),
+			 (value >> 32U) & 0xFFFFFFFFU);
+
+	}
+
+	case PM_CLOCK_SETPARENT:
+		ret = pm_clock_setparent(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETPARENT:
+	{
+		uint32_t value;
+
+		ret = pm_clock_getparent(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_GET_TRUSTZONE_VERSION:
+		SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+			 ((uint64_t)ZYNQMP_TZ_VERSION << 32));
+
+	case PM_SET_SUSPEND_MODE:
+		ret = pm_set_suspend_mode(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SECURE_SHA:
+		ret = pm_sha_hash(pm_arg[0], pm_arg[1], pm_arg[2],
+				pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SECURE_RSA:
+		ret = pm_rsa_core(pm_arg[0], pm_arg[1], pm_arg[2],
+				       pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SECURE_IMAGE:
+	{
+		uint32_t result[2];
+
+		ret = pm_secure_image(pm_arg[0], pm_arg[1], pm_arg[2],
+				      pm_arg[3], &result[0]);
+		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
+			 result[1]);
+	}
+
+	case PM_FPGA_READ:
+	{
+		uint32_t value;
+
+		ret = pm_fpga_read(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
+				   &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_SECURE_AES:
+	{
+		uint32_t value;
+
+		ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_PLL_SET_PARAMETER:
+		ret = pm_pll_set_parameter(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PLL_GET_PARAMETER:
+	{
+		uint32_t value;
+
+		ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
+	}
+
+	case PM_PLL_SET_MODE:
+		ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PLL_GET_MODE:
+	{
+		uint32_t mode;
+
+		ret = pm_pll_get_mode(pm_arg[0], &mode);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
+	}
+
+	default:
+		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
new file mode 100644
index 0000000..0968f64
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_SVC_MAIN_H
+#define PM_SVC_MAIN_H
+
+#include "pm_common.h"
+
+int pm_setup(void);
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+			uint64_t x4, void *cookie, void *handle,
+			uint64_t flags);
+
+#endif /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c
new file mode 100644
index 0000000..edb81f5
--- /dev/null
+++ b/plat/xilinx/zynqmp/sip_svc_setup.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include <plat_ipi.h>
+#include "ipi_mailbox_svc.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define ZYNQMP_SIP_SVC_CALL_COUNT	0x8200ff00
+#define ZYNQMP_SIP_SVC_UID		0x8200ff01
+#define ZYNQMP_SIP_SVC_VERSION		0x8200ff03
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR	0
+#define SIP_SVC_VERSION_MINOR	1
+
+/* These macros are used to identify PM, IPI calls from the SMC function ID */
+#define PM_FID_MASK	0xf000u
+#define PM_FID_VALUE	0u
+#define IPI_FID_VALUE	0x1000u
+#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(zynqmp_sip_uuid,
+	0x5c9b1b2a, 0x0586, 0x2340, 0xa6, 0x1b,
+	0xb9, 0x25, 0x82, 0x2d, 0xe3, 0xa5);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Invokes PM setup
+ */
+static int32_t sip_svc_setup(void)
+{
+	/* Configure IPI data for ZynqMP */
+	zynqmp_ipi_config_table_init();
+
+	/* PM implementation as SiP Service */
+	pm_setup();
+
+	return 0;
+}
+
+/**
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
+			      u_register_t x1,
+			      u_register_t x2,
+			      u_register_t x3,
+			      u_register_t x4,
+			      void *cookie,
+			      void *handle,
+			      u_register_t flags)
+{
+	/* Let PM SMC handler deal with PM-related requests */
+	if (is_pm_fid(smc_fid)) {
+		return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+				      flags);
+	}
+
+	/* Let IPI SMC handler deal with IPI-related requests */
+	if (is_ipi_fid(smc_fid)) {
+		return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+				      flags);
+	}
+
+	switch (smc_fid) {
+	case ZYNQMP_SIP_SVC_CALL_COUNT:
+		/* PM functions + default functions */
+		SMC_RET1(handle, PM_API_MAX + 2);
+
+	case ZYNQMP_SIP_SVC_UID:
+		SMC_UUID_RET(handle, zynqmp_sip_uuid);
+
+	case ZYNQMP_SIP_SVC_VERSION:
+		SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+		sip_svc,
+		OEN_SIP_START,
+		OEN_SIP_END,
+		SMC_TYPE_FAST,
+		sip_svc_setup,
+		sip_svc_smc_handler);
diff --git a/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
new file mode 100644
index 0000000..318b01d
--- /dev/null
+++ b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TSP source files specific to ZynqMP platform
+BL32_SOURCES		+=	plat/common/aarch64/platform_mp_stack.S		\
+				plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
diff --git a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
new file mode 100644
index 0000000..7f0ac74
--- /dev/null
+++ b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include <plat_private.h>
+#include <platform_tsp.h>
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+void tsp_early_platform_setup(void)
+{
+	/*
+	 * Register a different console than already in use to display
+	 * messages from TSP
+	 */
+	static console_cdns_t tsp_boot_console;
+	(void)console_cdns_register(ZYNQMP_UART_BASE,
+				       zynqmp_get_uart_clk(),
+				       ZYNQMP_UART_BAUDRATE,
+				       &tsp_boot_console);
+	console_set_scope(&tsp_boot_console.console,
+			  CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT);
+
+	/* Initialize the platform config for future decision making */
+	zynqmp_config_setup();
+}
+
+/*******************************************************************************
+ * Perform platform specific setup placeholder
+ ******************************************************************************/
+void tsp_platform_setup(void)
+{
+	plat_arm_gic_driver_init();
+	plat_arm_gic_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the MMU
+ ******************************************************************************/
+void tsp_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+		MAP_REGION_FLAT(BL32_BASE, BL32_END - BL32_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+			MT_RO_DATA | MT_SECURE),
+		MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_arm_get_mmap());
+	enable_mmu_el1(0);
+}
diff --git a/plat/xilinx/zynqmp/zynqmp_ipi.c b/plat/xilinx/zynqmp/zynqmp_ipi.c
new file mode 100644
index 0000000..f57369f
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_ipi.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Zynq UltraScale+ MPSoC IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+/* Zynqmp ipi configuration table */
+const static struct ipi_config zynqmp_ipi_table[] = {
+	/* APU IPI */
+	{
+		.ipi_bit_mask = 0x1,
+		.ipi_reg_base = 0xFF300000,
+		.secure_only = 0,
+	},
+	/* RPU0 IPI */
+	{
+		.ipi_bit_mask = 0x100,
+		.ipi_reg_base = 0xFF310000,
+		.secure_only = 0,
+	},
+	/* RPU1 IPI */
+	{
+		.ipi_bit_mask = 0x200,
+		.ipi_reg_base = 0xFF320000,
+		.secure_only = 0,
+	},
+	/* PMU0 IPI */
+	{
+		.ipi_bit_mask = 0x10000,
+		.ipi_reg_base = 0xFF330000,
+		.secure_only = IPI_SECURE_MASK,
+	},
+	/* PMU1 IPI */
+	{
+		.ipi_bit_mask = 0x20000,
+		.ipi_reg_base = 0xFF331000,
+		.secure_only = 0,
+	},
+	/* PMU2 IPI */
+	{
+		.ipi_bit_mask = 0x40000,
+		.ipi_reg_base = 0xFF332000,
+		.secure_only = IPI_SECURE_MASK,
+	},
+	/* PMU3 IPI */
+	{
+		.ipi_bit_mask = 0x80000,
+		.ipi_reg_base = 0xFF333000,
+		.secure_only = IPI_SECURE_MASK,
+	},
+	/* PL0 IPI */
+	{
+		.ipi_bit_mask = 0x1000000,
+		.ipi_reg_base = 0xFF340000,
+		.secure_only = 0,
+	},
+	/* PL1 IPI */
+	{
+		.ipi_bit_mask = 0x2000000,
+		.ipi_reg_base = 0xFF350000,
+		.secure_only = 0,
+	},
+	/* PL2 IPI */
+	{
+		.ipi_bit_mask = 0x4000000,
+		.ipi_reg_base = 0xFF360000,
+		.secure_only = 0,
+	},
+	/* PL3 IPI */
+	{
+		.ipi_bit_mask = 0x8000000,
+		.ipi_reg_base = 0xFF370000,
+		.secure_only = 0,
+	},
+};
+
+/**
+ * zynqmp_ipi_config_table_init() - Initialize ZynqMP IPI configuration data
+ *
+ */
+void zynqmp_ipi_config_table_init(void)
+{
+	ipi_config_table_init(zynqmp_ipi_table, ARRAY_SIZE(zynqmp_ipi_table));
+}
diff --git a/readme.rst b/readme.rst
new file mode 100644
index 0000000..6c93a4c
--- /dev/null
+++ b/readme.rst
@@ -0,0 +1,350 @@
+Trusted Firmware-A - version 2.1
+================================
+
+.. section-numbering::
+    :suffix: .
+
+.. contents::
+
+Trusted Firmware-A (TF-A) provides a reference implementation of secure world
+software for `Armv7-A and Armv8-A`_, including a `Secure Monitor`_ executing
+at Exception Level 3 (EL3). It implements various Arm interface standards,
+such as:
+
+-  The `Power State Coordination Interface (PSCI)`_
+-  `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT)`_
+-  `SMC Calling Convention`_
+-  `System Control and Management Interface (SCMI)`_
+-  `Software Delegated Exception Interface (SDEI)`_
+
+Where possible, the code is designed for reuse or porting to other Armv7-A and
+Armv8-A model and hardware platforms.
+
+This release provides a suitable starting point for productization of secure
+world boot and runtime firmware, in either the AArch32 or AArch64 execution
+states.
+
+Users are encouraged to do their own security validation, including penetration
+testing, on any secure world code derived from TF-A.
+
+Arm will continue development in collaboration with interested parties to
+provide a full reference implementation of Secure Monitor code and Arm standards
+to the benefit of all developers working with Armv7-A and Armv8-A TrustZone
+technology.
+
+Documentation contents
+----------------------
+
+The `Trusted Firmware-A Documentation Contents`_ page contains an overview of
+the documentation that is available, with links to facilitate easier browsing.
+
+License
+-------
+
+The software is provided under a BSD-3-Clause `license`_. Contributions to this
+project are accepted under the same license with developer sign-off as
+described in the `Contributing Guidelines`_.
+
+This project contains code from other projects as listed below. The original
+license text is included in those source files.
+
+-  The libc source code is derived from `FreeBSD`_ and `SCC`_. FreeBSD uses
+   various BSD licenses, including BSD-3-Clause and BSD-2-Clause. The SCC code
+   is used under the BSD-3-Clause license with the author's permission.
+
+-  The libfdt source code is disjunctively dual licensed
+   (GPL-2.0+ OR BSD-2-Clause). It is used by this project under the terms of
+   the BSD-2-Clause license. Any contributions to this code must be made under
+   the terms of both licenses.
+
+-  The LLVM compiler-rt source code is disjunctively dual licensed
+   (NCSA OR MIT). It is used by this project under the terms of the NCSA
+   license (also known as the University of Illinois/NCSA Open Source License),
+   which is a permissive license compatible with BSD-3-Clause. Any
+   contributions to this code must be made under the terms of both licenses.
+
+-  The zlib source code is licensed under the Zlib license, which is a
+   permissive license compatible with BSD-3-Clause.
+
+-  Some STMicroelectronics platform source code is disjunctively dual licensed
+   (GPL-2.0+ OR BSD-3-Clause). It is used by this project under the terms of the
+   BSD-3-Clause license. Any contributions to this code must be made under the
+   terms of both licenses.
+
+Functionality
+-------------
+
+-  Initialization of the secure world, for example exception vectors, control
+   registers and interrupts for the platform.
+
+-  Library support for CPU specific reset and power down sequences. This
+   includes support for errata workarounds and the latest Arm DynamIQ CPUs.
+
+-  Drivers to enable standard initialization of Arm System IP, for example
+   Generic Interrupt Controller (GIC), Cache Coherent Interconnect (CCI),
+   Cache Coherent Network (CCN), Network Interconnect (NIC) and TrustZone
+   Controller (TZC).
+
+-  A generic `SCMI`_ driver to interface with conforming power controllers, for
+   example the Arm System Control Processor (SCP).
+
+-  SMC (Secure Monitor Call) handling, conforming to the `SMC Calling
+   Convention`_ using an EL3 runtime services framework.
+
+-  `PSCI`_ library support for CPU, cluster and system power management
+   use-cases.
+   This library is pre-integrated with the AArch64 EL3 Runtime Software, and
+   is also suitable for integration with other AArch32 EL3 Runtime Software,
+   for example an AArch32 Secure OS.
+
+-  A minimal AArch32 Secure Payload (SP\_MIN) to demonstrate `PSCI`_ library
+   integration with AArch32 EL3 Runtime Software.
+
+-  Secure Monitor library code such as world switching, EL1 context management
+   and interrupt routing.
+   When a Secure-EL1 Payload (SP) is present, for example a Secure OS, the
+   AArch64 EL3 Runtime Software must be integrated with a Secure Payload
+   Dispatcher (SPD) component to customize the interaction with the SP.
+
+-  A Test SP and SPD to demonstrate AArch64 Secure Monitor functionality and SP
+   interaction with PSCI.
+
+-  SPDs for the `OP-TEE Secure OS`_, `NVIDIA Trusted Little Kernel`_
+   and `Trusty Secure OS`_.
+
+-  A Trusted Board Boot implementation, conforming to all mandatory TBBR
+   requirements. This includes image authentication, Firmware Update (or
+   recovery mode), and packaging of the various firmware images into a
+   Firmware Image Package (FIP).
+
+-  Pre-integration of TBB with the Arm CryptoCell product, to take advantage of
+   its hardware Root of Trust and crypto acceleration services.
+
+-  Reliability, Availability, and Serviceability (RAS) functionality, including
+
+   -  A Secure Partition Manager (SPM) to manage Secure Partitions in
+      Secure-EL0, which can be used to implement simple management and
+      security services.
+
+   -  An SDEI dispatcher to route interrupt-based SDEI events.
+
+   -  An Exception Handling Framework (EHF) that allows dispatching of EL3
+      interrupts to their registered handlers, to facilitate firmware-first
+      error handling.
+
+-  A dynamic configuration framework that enables each of the firmware images
+   to be configured at runtime if required by the platform. It also enables
+   loading of a hardware configuration (for example, a kernel device tree)
+   as part of the FIP, to be passed through the firmware stages.
+
+-  Support for alternative boot flows, for example to support platforms where
+   the EL3 Runtime Software is loaded using other firmware or a separate
+   secure system processor, or where a non-TF-A ROM expects BL2 to be loaded
+   at EL3.
+
+-  Support for the GCC, LLVM and Arm Compiler 6 toolchains.
+
+-  Support for combining several libraries into a "romlib" image that may be
+   shared across images to reduce memory footprint. The romlib image is stored
+   in ROM but is accessed through a jump-table that may be stored
+   in read-write memory, allowing for the library code to be patched.
+
+-  A prototype implementation of a Secure Partition Manager (SPM) that is based
+   on the SPCI Alpha 1 and SPRT draft specifications.
+
+-  Support for ARMv8.3 pointer authentication in the normal and secure worlds.
+   The use of pointer authentication in the normal world is enabled whenever
+   architectural support is available, without the need for additional build
+   flags. Use of pointer authentication in the secure world remains an
+   experimental configuration at this time and requires the ``ENABLE_PAUTH``
+   build flag to be set.
+
+-  Position-Independent Executable (PIE) support. Initially for BL31 only, with
+   further support to be added in a future release.
+
+For a full description of functionality and implementation details, please
+see the `Firmware Design`_ and supporting documentation. The `Change Log`_
+provides details of changes made since the last release.
+
+Platforms
+---------
+
+Various AArch32 and AArch64 builds of this release have been tested on r0, r1
+and r2 variants of the `Juno Arm Development Platform`_.
+
+The latest version of the AArch64 build of TF-A has been tested on the following
+Arm FVPs without shifted affinities, and that do not support threaded CPU cores
+(64-bit host machine only).
+
+The FVP models used are Version 11.6 Build 45, unless otherwise stated.
+
+-  ``FVP_Base_AEMv8A-AEMv8A``
+-  ``FVP_Base_AEMv8A-AEMv8A-AEMv8A-AEMv8A-CCN502``
+-  ``FVP_Base_RevC-2xAEMv8A``
+-  ``FVP_Base_Cortex-A32x4``
+-  ``FVP_Base_Cortex-A35x4``
+-  ``FVP_Base_Cortex-A53x4``
+-  ``FVP_Base_Cortex-A55x4+Cortex-A75x4``
+-  ``FVP_Base_Cortex-A55x4``
+-  ``FVP_Base_Cortex-A57x1-A53x1``
+-  ``FVP_Base_Cortex-A57x2-A53x4``
+-  ``FVP_Base_Cortex-A57x4-A53x4``
+-  ``FVP_Base_Cortex-A57x4``
+-  ``FVP_Base_Cortex-A72x4-A53x4``
+-  ``FVP_Base_Cortex-A72x4``
+-  ``FVP_Base_Cortex-A73x4-A53x4``
+-  ``FVP_Base_Cortex-A73x4``
+-  ``FVP_Base_Cortex-A75x4``
+-  ``FVP_Base_Cortex-A76x4``
+-  ``FVP_Base_Cortex-A76AEx4``
+-  ``FVP_Base_Cortex-A76AEx8``
+-  ``FVP_Base_Cortex-A77x4`` (Version 11.7 build 36)
+-  ``FVP_Base_Neoverse-N1x4``
+-  ``FVP_CSS_SGI-575`` (Version 11.3 build 42)
+-  ``FVP_CSS_SGM-775`` (Version 11.3 build 42)
+-  ``FVP_RD_E1Edge`` (Version 11.3 build 42)
+-  ``FVP_RD_N1Edge``
+-  ``Foundation_Platform``
+
+The latest version of the AArch32 build of TF-A has been tested on the following
+Arm FVPs without shifted affinities, and that do not support threaded CPU cores
+(64-bit host machine only).
+
+-  ``FVP_Base_AEMv8A-AEMv8A``
+-  ``FVP_Base_Cortex-A32x4``
+
+NOTE: The ``FVP_Base_RevC-2xAEMv8A`` FVP only supports shifted affinities.
+
+The Foundation FVP can be downloaded free of charge. The Base FVPs can be
+licensed from Arm. See the `Arm FVP website`_.
+
+All the above platforms have been tested with `Linaro Release 18.04`_.
+
+This release also contains the following platform support:
+
+-  Allwinner sun50i (A64, H5, and H6) SoCs
+-  Amlogic Meson S905 (GXBB)
+-  Amlogic Meson S905x (GXL)
+-  Arm Juno Software Development Platform
+-  Arm Neoverse N1 System Development Platform (N1SDP)
+-  Arm Neoverse Reference Design N1 Edge (RD-N1-Edge) FVP
+-  Arm Neoverse Reference Design E1 Edge (RD-E1-Edge) FVP
+-  Arm SGI-575 and SGM-775
+-  Arm Versatile Express FVP
+-  HiKey, HiKey960 and Poplar boards
+-  Intel Stratix 10 SoC FPGA
+-  Marvell Armada 3700 and 8K
+-  MediaTek MT6795 and MT8173 SoCs
+-  NVIDIA T132, T186 and T210 SoCs
+-  NXP QorIQ LS1043A, i.MX8MM, i.MX8MQ, i.MX8QX, i.MX8QM and i.MX7Solo WaRP7
+-  QEMU
+-  Raspberry Pi 3
+-  Renesas R-Car Generation 3
+-  RockChip RK3328, RK3368 and RK3399 SoCs
+-  Socionext UniPhier SoC family and SynQuacer SC2A11 SoCs
+-  STMicroelectronics STM32MP1
+-  Texas Instruments K3 SoCs
+-  Xilinx Versal and Zynq UltraScale + MPSoC
+
+Still to come
+-------------
+
+-  Support for additional platforms.
+
+-  Refinements to Position Independent Executable (PIE) support.
+
+-  Refinements to the SPCI-based SPM implementation as the draft SPCI and SPRT
+   specifications continue to evolve.
+
+-  Documentation enhancements.
+
+-  Ongoing support for new architectural features, CPUs and System IP.
+
+-  Ongoing support for new Arm system architecture specifications.
+
+-  Ongoing security hardening, optimization and quality improvements.
+
+For a full list of detailed issues in the current code, please see the `Change
+Log`_ and the `issue tracker`_.
+
+Getting started
+---------------
+
+See the `User Guide`_ for instructions on how to download, install, build and
+use TF-A with the Arm `FVP`_\ s.
+
+See the `Firmware Design`_ for information on how TF-A works.
+
+See the `Porting Guide`_ as well for information about how to use this
+software on another Armv7-A or Armv8-A platform.
+
+See the `Contributing Guidelines`_ for information on how to contribute to this
+project and the `Acknowledgments`_ file for a list of contributors to the
+project.
+
+Contact us
+~~~~~~~~~~
+
+We welcome any feedback on TF-A. If you think you have found a security
+vulnerability, please report this using the process defined in the TF-A
+`Security Center`_. For all other feedback, you can use either the
+`issue tracker`_ or our `mailing list`_.
+
+Arm licensees may contact Arm directly via their partner managers.
+
+Security advisories
+-------------------
+
+-  `Security Advisory TFV-1`_
+-  `Security Advisory TFV-2`_
+-  `Security Advisory TFV-3`_
+-  `Security Advisory TFV-4`_
+-  `Security Advisory TFV-5`_
+-  `Security Advisory TFV-6`_
+-  `Security Advisory TFV-7`_
+-  `Security Advisory TFV-8`_
+
+
+--------------
+
+*Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.*
+
+.. _Armv7-A and Armv8-A: https://developer.arm.com/products/architecture/a-profile
+.. _Secure Monitor: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php
+.. _Power State Coordination Interface (PSCI): PSCI_
+.. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
+.. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
+.. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf
+.. _System Control and Management Interface (SCMI): SCMI_
+.. _SCMI: http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf
+.. _Software Delegated Exception Interface (SDEI): SDEI_
+.. _SDEI: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf
+.. _Juno Arm Development Platform: http://www.arm.com/products/tools/development-boards/versatile-express/juno-arm-development-platform.php
+.. _Arm FVP website: FVP_
+.. _FVP: https://developer.arm.com/products/system-design/fixed-virtual-platforms
+.. _Linaro Release 18.04: https://community.arm.com/dev-platforms/b/documents/posts/linaro-release-notes-deprecated#LinaroRelease18.04
+.. _OP-TEE Secure OS: https://github.com/OP-TEE/optee_os
+.. _NVIDIA Trusted Little Kernel: http://nv-tegra.nvidia.com/gitweb/?p=3rdparty/ote_partner/tlk.git;a=summary
+.. _Trusty Secure OS: https://source.android.com/security/trusty
+.. _trustedfirmware.org: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+.. _issue tracker: https://developer.trustedfirmware.org/project/board/1/
+.. _mailing list: https://lists.trustedfirmware.org/mailman/listinfo/tf-a
+.. _Security Center: ./docs/process/security.rst
+.. _license: ./license.rst
+.. _Contributing Guidelines: ./docs/process/contributing.rst
+.. _Acknowledgments: ./docs/acknowledgements.rst
+.. _Firmware Design: ./docs/design/firmware-design.rst
+.. _Change Log: ./docs/change-log.rst
+.. _User Guide: ./docs/getting_started/user-guide.rst
+.. _Porting Guide: ./docs/getting_started/porting-guide.rst
+.. _FreeBSD: http://www.freebsd.org
+.. _SCC: http://www.simple-cc.org/
+.. _Security Advisory TFV-1: ./docs/security_advisories/security-advisory-tfv-1.rst
+.. _Security Advisory TFV-2: ./docs/security_advisories/security-advisory-tfv-2.rst
+.. _Security Advisory TFV-3: ./docs/security_advisories/security-advisory-tfv-3.rst
+.. _Security Advisory TFV-4: ./docs/security_advisories/security-advisory-tfv-4.rst
+.. _Security Advisory TFV-5: ./docs/security_advisories/security-advisory-tfv-5.rst
+.. _Security Advisory TFV-6: ./docs/security_advisories/security-advisory-tfv-6.rst
+.. _Security Advisory TFV-7: ./docs/security_advisories/security-advisory-tfv-7.rst
+.. _Security Advisory TFV-8: ./docs/security_advisories/security-advisory-tfv-8.rst
+.. _Trusted Firmware-A Documentation Contents: ./docs/contents.rst
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
new file mode 100644
index 0000000..1fc7827
--- /dev/null
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/cpus/errata_report.h>
+#include <lib/cpus/wa_cve_2017_5715.h>
+#include <lib/cpus/wa_cve_2018_3639.h>
+#include <lib/smccc.h>
+#include <services/arm_arch_svc.h>
+#include <smccc_helpers.h>
+
+static int32_t smccc_version(void)
+{
+	return MAKE_SMCCC_VERSION(SMCCC_MAJOR_VERSION, SMCCC_MINOR_VERSION);
+}
+
+static int32_t smccc_arch_features(u_register_t arg)
+{
+	switch (arg) {
+	case SMCCC_VERSION:
+	case SMCCC_ARCH_FEATURES:
+		return SMC_OK;
+#if WORKAROUND_CVE_2017_5715
+	case SMCCC_ARCH_WORKAROUND_1:
+		if (check_wa_cve_2017_5715() == ERRATA_NOT_APPLIES)
+			return 1;
+		return 0; /* ERRATA_APPLIES || ERRATA_MISSING */
+#endif
+
+#if WORKAROUND_CVE_2018_3639
+	case SMCCC_ARCH_WORKAROUND_2: {
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+		unsigned long long ssbs;
+
+		/*
+		 * Firmware doesn't have to carry out dynamic workaround if the
+		 * PE implements architectural Speculation Store Bypass Safe
+		 * (SSBS) feature.
+		 */
+		ssbs = (read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SSBS_SHIFT) &
+			ID_AA64PFR1_EL1_SSBS_MASK;
+
+		/*
+		 * If architectural SSBS is available on this PE, no firmware
+		 * mitigation via SMCCC_ARCH_WORKAROUND_2 is required.
+		 */
+		if (ssbs != SSBS_UNAVAILABLE)
+			return 1;
+
+		/*
+		 * On a platform where at least one CPU requires
+		 * dynamic mitigation but others are either unaffected
+		 * or permanently mitigated, report the latter as not
+		 * needing dynamic mitigation.
+		 */
+		if (wa_cve_2018_3639_get_disable_ptr() == NULL)
+			return 1;
+		/*
+		 * If we get here, this CPU requires dynamic mitigation
+		 * so report it as such.
+		 */
+		return 0;
+#else
+		/* Either the CPUs are unaffected or permanently mitigated */
+		return SMCCC_ARCH_NOT_REQUIRED;
+#endif
+	}
+#endif
+
+	/* Fallthrough */
+
+	default:
+		return SMC_UNK;
+	}
+}
+
+/*
+ * Top-level Arm Architectural Service SMC handler.
+ */
+static uintptr_t arm_arch_svc_smc_handler(uint32_t smc_fid,
+	u_register_t x1,
+	u_register_t x2,
+	u_register_t x3,
+	u_register_t x4,
+	void *cookie,
+	void *handle,
+	u_register_t flags)
+{
+	switch (smc_fid) {
+	case SMCCC_VERSION:
+		SMC_RET1(handle, smccc_version());
+	case SMCCC_ARCH_FEATURES:
+		SMC_RET1(handle, smccc_arch_features(x1));
+#if WORKAROUND_CVE_2017_5715
+	case SMCCC_ARCH_WORKAROUND_1:
+		/*
+		 * The workaround has already been applied on affected PEs
+		 * during entry to EL3.  On unaffected PEs, this function
+		 * has no effect.
+		 */
+		SMC_RET0(handle);
+#endif
+#if WORKAROUND_CVE_2018_3639
+	case SMCCC_ARCH_WORKAROUND_2:
+		/*
+		 * The workaround has already been applied on affected PEs
+		 * requiring dynamic mitigation during entry to EL3.
+		 * On unaffected or statically mitigated PEs, this function
+		 * has no effect.
+		 */
+		SMC_RET0(handle);
+#endif
+	default:
+		WARN("Unimplemented Arm Architecture Service Call: 0x%x \n",
+			smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Register Standard Service Calls as runtime service */
+DECLARE_RT_SVC(
+		arm_arch_svc,
+		OEN_ARM_START,
+		OEN_ARM_END,
+		SMC_TYPE_FAST,
+		NULL,
+		arm_arch_svc_smc_handler
+);
diff --git a/services/spd/opteed/opteed.mk b/services/spd/opteed/opteed.mk
new file mode 100644
index 0000000..643b054
--- /dev/null
+++ b/services/spd/opteed/opteed.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+OPTEED_DIR		:=	services/spd/opteed
+SPD_INCLUDES		:=
+
+SPD_SOURCES		:=	services/spd/opteed/opteed_common.c	\
+				services/spd/opteed/opteed_helpers.S	\
+				services/spd/opteed/opteed_main.c	\
+				services/spd/opteed/opteed_pm.c
+
+NEED_BL32		:=	yes
+
+# required so that optee code can control access to the timer registers
+NS_TIMER_SWITCH		:=	1
diff --git a/services/spd/opteed/opteed_common.c b/services/spd/opteed/opteed_common.c
new file mode 100644
index 0000000..9aa19c5
--- /dev/null
+++ b/services/spd/opteed/opteed_common.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+
+#include "opteed_private.h"
+
+/*******************************************************************************
+ * Given a OPTEE entrypoint info pointer, entry point PC, register width,
+ * cpu id & pointer to a context data structure, this function will
+ * initialize OPTEE context and entry point info for OPTEE.
+ ******************************************************************************/
+void opteed_init_optee_ep_state(struct entry_point_info *optee_entry_point,
+				uint32_t rw, uint64_t pc,
+				uint64_t pageable_part, uint64_t mem_limit,
+				uint64_t dt_addr, optee_context_t *optee_ctx)
+{
+	uint32_t ep_attr;
+
+	/* Passing a NULL context is a critical programming error */
+	assert(optee_ctx);
+	assert(optee_entry_point);
+	assert(pc);
+
+	/* Associate this context with the cpu specified */
+	optee_ctx->mpidr = read_mpidr_el1();
+	optee_ctx->state = 0;
+	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF);
+
+	cm_set_context(&optee_ctx->cpu_ctx, SECURE);
+
+	/* initialise an entrypoint to set up the CPU context */
+	ep_attr = SECURE | EP_ST_ENABLE;
+	if (read_sctlr_el3() & SCTLR_EE_BIT)
+		ep_attr |= EP_EE_BIG;
+	SET_PARAM_HEAD(optee_entry_point, PARAM_EP, VERSION_1, ep_attr);
+	optee_entry_point->pc = pc;
+	if (rw == OPTEE_AARCH64)
+		optee_entry_point->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+						  DISABLE_ALL_EXCEPTIONS);
+	else
+		optee_entry_point->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
+						      SPSR_E_LITTLE,
+						      DAIF_FIQ_BIT |
+							DAIF_IRQ_BIT |
+							DAIF_ABT_BIT);
+	zeromem(&optee_entry_point->args, sizeof(optee_entry_point->args));
+	optee_entry_point->args.arg0 = pageable_part;
+	optee_entry_point->args.arg1 = mem_limit;
+	optee_entry_point->args.arg2 = dt_addr;
+}
+
+/*******************************************************************************
+ * This function takes an OPTEE context pointer and:
+ * 1. Applies the S-EL1 system register context from optee_ctx->cpu_ctx.
+ * 2. Saves the current C runtime state (callee saved registers) on the stack
+ *    frame and saves a reference to this state.
+ * 3. Calls el3_exit() so that the EL3 system and general purpose registers
+ *    from the optee_ctx->cpu_ctx are used to enter the OPTEE image.
+ ******************************************************************************/
+uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx)
+{
+	uint64_t rc;
+
+	assert(optee_ctx != NULL);
+	assert(optee_ctx->c_rt_ctx == 0);
+
+	/* Apply the Secure EL1 system register context and switch to it */
+	assert(cm_get_context(SECURE) == &optee_ctx->cpu_ctx);
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+
+	rc = opteed_enter_sp(&optee_ctx->c_rt_ctx);
+#if ENABLE_ASSERTIONS
+	optee_ctx->c_rt_ctx = 0;
+#endif
+
+	return rc;
+}
+
+
+/*******************************************************************************
+ * This function takes an OPTEE context pointer and:
+ * 1. Saves the S-EL1 system register context tp optee_ctx->cpu_ctx.
+ * 2. Restores the current C runtime state (callee saved registers) from the
+ *    stack frame using the reference to this state saved in opteed_enter_sp().
+ * 3. It does not need to save any general purpose or EL3 system register state
+ *    as the generic smc entry routine should have saved those.
+ ******************************************************************************/
+void opteed_synchronous_sp_exit(optee_context_t *optee_ctx, uint64_t ret)
+{
+	assert(optee_ctx != NULL);
+	/* Save the Secure EL1 system register context */
+	assert(cm_get_context(SECURE) == &optee_ctx->cpu_ctx);
+	cm_el1_sysregs_context_save(SECURE);
+
+	assert(optee_ctx->c_rt_ctx != 0);
+	opteed_exit_sp(optee_ctx->c_rt_ctx, ret);
+
+	/* Should never reach here */
+	assert(0);
+}
diff --git a/services/spd/opteed/opteed_helpers.S b/services/spd/opteed/opteed_helpers.S
new file mode 100644
index 0000000..075a71b
--- /dev/null
+++ b/services/spd/opteed/opteed_helpers.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "opteed_private.h"
+
+	.global	opteed_enter_sp
+	/* ---------------------------------------------
+	 * This function is called with SP_EL0 as stack.
+	 * Here we stash our EL3 callee-saved registers
+	 * on to the stack as a part of saving the C
+	 * runtime and enter the secure payload.
+	 * 'x0' contains a pointer to the memory where
+	 * the address of the C runtime context is to be
+	 * saved.
+	 * ---------------------------------------------
+	 */
+func opteed_enter_sp
+	/* Make space for the registers that we're going to save */
+	mov	x3, sp
+	str	x3, [x0, #0]
+	sub	sp, sp, #OPTEED_C_RT_CTX_SIZE
+
+	/* Save callee-saved registers on to the stack */
+	stp	x19, x20, [sp, #OPTEED_C_RT_CTX_X19]
+	stp	x21, x22, [sp, #OPTEED_C_RT_CTX_X21]
+	stp	x23, x24, [sp, #OPTEED_C_RT_CTX_X23]
+	stp	x25, x26, [sp, #OPTEED_C_RT_CTX_X25]
+	stp	x27, x28, [sp, #OPTEED_C_RT_CTX_X27]
+	stp	x29, x30, [sp, #OPTEED_C_RT_CTX_X29]
+
+	/* ---------------------------------------------
+	 * Everything is setup now. el3_exit() will
+	 * use the secure context to restore to the
+	 * general purpose and EL3 system registers to
+	 * ERET into OPTEE.
+	 * ---------------------------------------------
+	 */
+	b	el3_exit
+endfunc opteed_enter_sp
+
+	/* ---------------------------------------------
+	 * This function is called 'x0' pointing to a C
+	 * runtime context saved in opteed_enter_sp().  It
+	 * restores the saved registers and jumps to
+	 * that runtime with 'x0' as the new sp. This
+	 * destroys the C runtime context that had been
+	 * built on the stack below the saved context by
+	 * the caller. Later the second parameter 'x1'
+	 * is passed as return value to the caller
+	 * ---------------------------------------------
+	 */
+	.global opteed_exit_sp
+func opteed_exit_sp
+	/* Restore the previous stack */
+	mov	sp, x0
+
+	/* Restore callee-saved registers on to the stack */
+	ldp	x19, x20, [x0, #(OPTEED_C_RT_CTX_X19 - OPTEED_C_RT_CTX_SIZE)]
+	ldp	x21, x22, [x0, #(OPTEED_C_RT_CTX_X21 - OPTEED_C_RT_CTX_SIZE)]
+	ldp	x23, x24, [x0, #(OPTEED_C_RT_CTX_X23 - OPTEED_C_RT_CTX_SIZE)]
+	ldp	x25, x26, [x0, #(OPTEED_C_RT_CTX_X25 - OPTEED_C_RT_CTX_SIZE)]
+	ldp	x27, x28, [x0, #(OPTEED_C_RT_CTX_X27 - OPTEED_C_RT_CTX_SIZE)]
+	ldp	x29, x30, [x0, #(OPTEED_C_RT_CTX_X29 - OPTEED_C_RT_CTX_SIZE)]
+
+	/* ---------------------------------------------
+	 * This should take us back to the instruction
+	 * after the call to the last opteed_enter_sp().
+	 * Place the second parameter to x0 so that the
+	 * caller will see it as a return value from the
+	 * original entry call
+	 * ---------------------------------------------
+	 */
+	mov	x0, x1
+	ret
+endfunc opteed_exit_sp
diff --git a/services/spd/opteed/opteed_main.c b/services/spd/opteed/opteed_main.c
new file mode 100644
index 0000000..160a693
--- /dev/null
+++ b/services/spd/opteed/opteed_main.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+/*******************************************************************************
+ * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a
+ * plug-in component to the Secure Monitor, registered as a runtime service. The
+ * SPD is expected to be a functional extension of the Secure Payload (SP) that
+ * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting
+ * the Trusted OS/Applications range to the dispatcher. The SPD will either
+ * handle the request locally or delegate it to the Secure Payload. It is also
+ * responsible for initialising and maintaining communication with the SP.
+ ******************************************************************************/
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#include "opteed_private.h"
+#include "teesmc_opteed.h"
+#include "teesmc_opteed_macros.h"
+
+/*******************************************************************************
+ * Address of the entrypoint vector table in OPTEE. It is
+ * initialised once on the primary core after a cold boot.
+ ******************************************************************************/
+struct optee_vectors *optee_vector_table;
+
+/*******************************************************************************
+ * Array to keep track of per-cpu OPTEE state
+ ******************************************************************************/
+optee_context_t opteed_sp_context[OPTEED_CORE_COUNT];
+uint32_t opteed_rw;
+
+static int32_t opteed_init(void);
+
+/*******************************************************************************
+ * This function is the handler registered for S-EL1 interrupts by the
+ * OPTEED. It validates the interrupt and upon success arranges entry into
+ * the OPTEE at 'optee_fiq_entry()' for handling the interrupt.
+ ******************************************************************************/
+static uint64_t opteed_sel1_interrupt_handler(uint32_t id,
+					    uint32_t flags,
+					    void *handle,
+					    void *cookie)
+{
+	uint32_t linear_id;
+	optee_context_t *optee_ctx;
+
+	/* Check the security state when the exception was generated */
+	assert(get_interrupt_src_ss(flags) == NON_SECURE);
+
+	/* Sanity check the pointer to this cpu's context */
+	assert(handle == cm_get_context(NON_SECURE));
+
+	/* Save the non-secure context before entering the OPTEE */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	/* Get a reference to this cpu's OPTEE context */
+	linear_id = plat_my_core_pos();
+	optee_ctx = &opteed_sp_context[linear_id];
+	assert(&optee_ctx->cpu_ctx == cm_get_context(SECURE));
+
+	cm_set_elr_el3(SECURE, (uint64_t)&optee_vector_table->fiq_entry);
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+
+	/*
+	 * Tell the OPTEE that it has to handle an FIQ (synchronously).
+	 * Also the instruction in normal world where the interrupt was
+	 * generated is passed for debugging purposes. It is safe to
+	 * retrieve this address from ELR_EL3 as the secure context will
+	 * not take effect until el3_exit().
+	 */
+	SMC_RET1(&optee_ctx->cpu_ctx, read_elr_el3());
+}
+
+/*******************************************************************************
+ * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type
+ * (aarch32/aarch64) if not already known and initialises the context for entry
+ * into OPTEE for its initialization.
+ ******************************************************************************/
+static int32_t opteed_setup(void)
+{
+	entry_point_info_t *optee_ep_info;
+	uint32_t linear_id;
+	uint64_t opteed_pageable_part;
+	uint64_t opteed_mem_limit;
+	uint64_t dt_addr;
+
+	linear_id = plat_my_core_pos();
+
+	/*
+	 * Get information about the Secure Payload (BL32) image. Its
+	 * absence is a critical failure.  TODO: Add support to
+	 * conditionally include the SPD service
+	 */
+	optee_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	if (!optee_ep_info) {
+		WARN("No OPTEE provided by BL2 boot loader, Booting device"
+			" without OPTEE initialization. SMC`s destined for OPTEE"
+			" will return SMC_UNK\n");
+		return 1;
+	}
+
+	/*
+	 * If there's no valid entry point for SP, we return a non-zero value
+	 * signalling failure initializing the service. We bail out without
+	 * registering any handlers
+	 */
+	if (!optee_ep_info->pc)
+		return 1;
+
+	opteed_rw = optee_ep_info->args.arg0;
+	opteed_pageable_part = optee_ep_info->args.arg1;
+	opteed_mem_limit = optee_ep_info->args.arg2;
+	dt_addr = optee_ep_info->args.arg3;
+
+	opteed_init_optee_ep_state(optee_ep_info,
+				opteed_rw,
+				optee_ep_info->pc,
+				opteed_pageable_part,
+				opteed_mem_limit,
+				dt_addr,
+				&opteed_sp_context[linear_id]);
+
+	/*
+	 * All OPTEED initialization done. Now register our init function with
+	 * BL31 for deferred invocation
+	 */
+	bl31_register_bl32_init(&opteed_init);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function passes control to the OPTEE image (BL32) for the first time
+ * on the primary cpu after a cold boot. It assumes that a valid secure
+ * context has already been created by opteed_setup() which can be directly
+ * used.  It also assumes that a valid non-secure context has been
+ * initialised by PSCI so it does not need to save and restore any
+ * non-secure state. This function performs a synchronous entry into
+ * OPTEE. OPTEE passes control back to this routine through a SMC.
+ ******************************************************************************/
+static int32_t opteed_init(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+	entry_point_info_t *optee_entry_point;
+	uint64_t rc;
+
+	/*
+	 * Get information about the OPTEE (BL32) image. Its
+	 * absence is a critical failure.
+	 */
+	optee_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
+	assert(optee_entry_point);
+
+	cm_init_my_context(optee_entry_point);
+
+	/*
+	 * Arrange for an entry into OPTEE. It will be returned via
+	 * OPTEE_ENTRY_DONE case
+	 */
+	rc = opteed_synchronous_sp_entry(optee_ctx);
+	assert(rc != 0);
+
+	return rc;
+}
+
+
+/*******************************************************************************
+ * This function is responsible for handling all SMCs in the Trusted OS/App
+ * range from the non-secure state as defined in the SMC Calling Convention
+ * Document. It is also responsible for communicating with the Secure
+ * payload to delegate work and return results back to the non-secure
+ * state. Lastly it will also return any information that OPTEE needs to do
+ * the work assigned to it.
+ ******************************************************************************/
+static uintptr_t opteed_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	cpu_context_t *ns_cpu_context;
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+	uint64_t rc;
+
+	/*
+	 * Determine which security state this SMC originated from
+	 */
+
+	if (is_caller_non_secure(flags)) {
+		/*
+		 * This is a fresh request from the non-secure client.
+		 * The parameters are in x1 and x2. Figure out which
+		 * registers need to be preserved, save the non-secure
+		 * state and send the request to the secure payload.
+		 */
+		assert(handle == cm_get_context(NON_SECURE));
+
+		cm_el1_sysregs_context_save(NON_SECURE);
+
+		/*
+		 * We are done stashing the non-secure context. Ask the
+		 * OPTEE to do the work now.
+		 */
+
+		/*
+		 * Verify if there is a valid context to use, copy the
+		 * operation type and parameters to the secure context
+		 * and jump to the fast smc entry point in the secure
+		 * payload. Entry into S-EL1 will take place upon exit
+		 * from this function.
+		 */
+		assert(&optee_ctx->cpu_ctx == cm_get_context(SECURE));
+
+		/* Set appropriate entry for SMC.
+		 * We expect OPTEE to manage the PSTATE.I and PSTATE.F
+		 * flags as appropriate.
+		 */
+		if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) {
+			cm_set_elr_el3(SECURE, (uint64_t)
+					&optee_vector_table->fast_smc_entry);
+		} else {
+			cm_set_elr_el3(SECURE, (uint64_t)
+					&optee_vector_table->yield_smc_entry);
+		}
+
+		cm_el1_sysregs_context_restore(SECURE);
+		cm_set_next_eret_context(SECURE);
+
+		write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
+			      CTX_GPREG_X4,
+			      read_ctx_reg(get_gpregs_ctx(handle),
+					   CTX_GPREG_X4));
+		write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
+			      CTX_GPREG_X5,
+			      read_ctx_reg(get_gpregs_ctx(handle),
+					   CTX_GPREG_X5));
+		write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
+			      CTX_GPREG_X6,
+			      read_ctx_reg(get_gpregs_ctx(handle),
+					   CTX_GPREG_X6));
+		/* Propagate hypervisor client ID */
+		write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
+			      CTX_GPREG_X7,
+			      read_ctx_reg(get_gpregs_ctx(handle),
+					   CTX_GPREG_X7));
+
+		SMC_RET4(&optee_ctx->cpu_ctx, smc_fid, x1, x2, x3);
+	}
+
+	/*
+	 * Returning from OPTEE
+	 */
+
+	switch (smc_fid) {
+	/*
+	 * OPTEE has finished initialising itself after a cold boot
+	 */
+	case TEESMC_OPTEED_RETURN_ENTRY_DONE:
+		/*
+		 * Stash the OPTEE entry points information. This is done
+		 * only once on the primary cpu
+		 */
+		assert(optee_vector_table == NULL);
+		optee_vector_table = (optee_vectors_t *) x1;
+
+		if (optee_vector_table) {
+			set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
+
+			/*
+			 * OPTEE has been successfully initialized.
+			 * Register power management hooks with PSCI
+			 */
+			psci_register_spd_pm_hook(&opteed_pm);
+
+			/*
+			 * Register an interrupt handler for S-EL1 interrupts
+			 * when generated during code executing in the
+			 * non-secure state.
+			 */
+			flags = 0;
+			set_interrupt_rm_flag(flags, NON_SECURE);
+			rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+						opteed_sel1_interrupt_handler,
+						flags);
+			if (rc)
+				panic();
+		}
+
+		/*
+		 * OPTEE reports completion. The OPTEED must have initiated
+		 * the original request through a synchronous entry into
+		 * OPTEE. Jump back to the original C runtime context.
+		 */
+		opteed_synchronous_sp_exit(optee_ctx, x1);
+		break;
+
+
+	/*
+	 * These function IDs is used only by OP-TEE to indicate it has
+	 * finished:
+	 * 1. turning itself on in response to an earlier psci
+	 *    cpu_on request
+	 * 2. resuming itself after an earlier psci cpu_suspend
+	 *    request.
+	 */
+	case TEESMC_OPTEED_RETURN_ON_DONE:
+	case TEESMC_OPTEED_RETURN_RESUME_DONE:
+
+
+	/*
+	 * These function IDs is used only by the SP to indicate it has
+	 * finished:
+	 * 1. suspending itself after an earlier psci cpu_suspend
+	 *    request.
+	 * 2. turning itself off in response to an earlier psci
+	 *    cpu_off request.
+	 */
+	case TEESMC_OPTEED_RETURN_OFF_DONE:
+	case TEESMC_OPTEED_RETURN_SUSPEND_DONE:
+	case TEESMC_OPTEED_RETURN_SYSTEM_OFF_DONE:
+	case TEESMC_OPTEED_RETURN_SYSTEM_RESET_DONE:
+
+		/*
+		 * OPTEE reports completion. The OPTEED must have initiated the
+		 * original request through a synchronous entry into OPTEE.
+		 * Jump back to the original C runtime context, and pass x1 as
+		 * return value to the caller
+		 */
+		opteed_synchronous_sp_exit(optee_ctx, x1);
+		break;
+
+	/*
+	 * OPTEE is returning from a call or being preempted from a call, in
+	 * either case execution should resume in the normal world.
+	 */
+	case TEESMC_OPTEED_RETURN_CALL_DONE:
+		/*
+		 * This is the result from the secure client of an
+		 * earlier request. The results are in x0-x3. Copy it
+		 * into the non-secure context, save the secure state
+		 * and return to the non-secure state.
+		 */
+		assert(handle == cm_get_context(SECURE));
+		cm_el1_sysregs_context_save(SECURE);
+
+		/* Get a reference to the non-secure context */
+		ns_cpu_context = cm_get_context(NON_SECURE);
+		assert(ns_cpu_context);
+
+		/* Restore non-secure state */
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+
+		SMC_RET4(ns_cpu_context, x1, x2, x3, x4);
+
+	/*
+	 * OPTEE has finished handling a S-EL1 FIQ interrupt. Execution
+	 * should resume in the normal world.
+	 */
+	case TEESMC_OPTEED_RETURN_FIQ_DONE:
+		/* Get a reference to the non-secure context */
+		ns_cpu_context = cm_get_context(NON_SECURE);
+		assert(ns_cpu_context);
+
+		/*
+		 * Restore non-secure state. There is no need to save the
+		 * secure system register context since OPTEE was supposed
+		 * to preserve it during S-EL1 interrupt handling.
+		 */
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+
+		SMC_RET0((uint64_t) ns_cpu_context);
+
+	default:
+		panic();
+	}
+}
+
+/* Define an OPTEED runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	opteed_fast,
+
+	OEN_TOS_START,
+	OEN_TOS_END,
+	SMC_TYPE_FAST,
+	opteed_setup,
+	opteed_smc_handler
+);
+
+/* Define an OPTEED runtime service descriptor for yielding SMC calls */
+DECLARE_RT_SVC(
+	opteed_std,
+
+	OEN_TOS_START,
+	OEN_TOS_END,
+	SMC_TYPE_YIELD,
+	NULL,
+	opteed_smc_handler
+);
diff --git a/services/spd/opteed/opteed_pm.c b/services/spd/opteed/opteed_pm.c
new file mode 100644
index 0000000..719eeb7
--- /dev/null
+++ b/services/spd/opteed/opteed_pm.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#include "opteed_private.h"
+
+/*******************************************************************************
+ * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any
+ * actions needed. Nothing at the moment.
+ ******************************************************************************/
+static void opteed_cpu_on_handler(u_register_t target_cpu)
+{
+}
+
+/*******************************************************************************
+ * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
+ * needed
+ ******************************************************************************/
+static int32_t opteed_cpu_off_handler(u_register_t unused)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+
+	assert(optee_vector_table);
+	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
+
+	/* Program the entry point and enter OPTEE */
+	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_off_entry);
+	rc = opteed_synchronous_sp_entry(optee_ctx);
+
+	/*
+	 * Read the response from OPTEE. A non-zero return means that
+	 * something went wrong while communicating with OPTEE.
+	 */
+	if (rc != 0)
+		panic();
+
+	/*
+	 * Reset OPTEE's context for a fresh start when this cpu is turned on
+	 * subsequently.
+	 */
+	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF);
+
+	 return 0;
+}
+
+/*******************************************************************************
+ * This cpu is being suspended. S-EL1 state must have been saved in the
+ * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
+ ******************************************************************************/
+static void opteed_cpu_suspend_handler(u_register_t max_off_pwrlvl)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+
+	assert(optee_vector_table);
+	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
+
+	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0,
+		      max_off_pwrlvl);
+
+	/* Program the entry point and enter OPTEE */
+	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_suspend_entry);
+	rc = opteed_synchronous_sp_entry(optee_ctx);
+
+	/*
+	 * Read the response from OPTEE. A non-zero return means that
+	 * something went wrong while communicating with OPTEE.
+	 */
+	if (rc != 0)
+		panic();
+
+	/* Update its context to reflect the state OPTEE is in */
+	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND);
+}
+
+/*******************************************************************************
+ * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits
+ * before passing control back to the Secure Monitor. Entry in S-El1 is done
+ * after initialising minimal architectural state that guarantees safe
+ * execution.
+ ******************************************************************************/
+static void opteed_cpu_on_finish_handler(u_register_t unused)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+	entry_point_info_t optee_on_entrypoint;
+
+	assert(optee_vector_table);
+	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF);
+
+	opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw,
+				(uint64_t)&optee_vector_table->cpu_on_entry,
+				0, 0, 0, optee_ctx);
+
+	/* Initialise this cpu's secure context */
+	cm_init_my_context(&optee_on_entrypoint);
+
+	/* Enter OPTEE */
+	rc = opteed_synchronous_sp_entry(optee_ctx);
+
+	/*
+	 * Read the response from OPTEE. A non-zero return means that
+	 * something went wrong while communicating with OPTEE.
+	 */
+	if (rc != 0)
+		panic();
+
+	/* Update its context to reflect the state OPTEE is in */
+	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
+}
+
+/*******************************************************************************
+ * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it
+ * completed the preceding suspend call. Use that context to program an entry
+ * into OPTEE to allow it to do any remaining book keeping
+ ******************************************************************************/
+static void opteed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+
+	assert(optee_vector_table);
+	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND);
+
+	/* Program the entry point, max_off_pwrlvl and enter the SP */
+	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
+		      CTX_GPREG_X0,
+		      max_off_pwrlvl);
+	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_resume_entry);
+	rc = opteed_synchronous_sp_entry(optee_ctx);
+
+	/*
+	 * Read the response from OPTEE. A non-zero return means that
+	 * something went wrong while communicating with OPTEE.
+	 */
+	if (rc != 0)
+		panic();
+
+	/* Update its context to reflect the state OPTEE is in */
+	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
+}
+
+/*******************************************************************************
+ * Return the type of OPTEE the OPTEED is dealing with. Report the current
+ * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
+ ******************************************************************************/
+static int32_t opteed_cpu_migrate_info(u_register_t *resident_cpu)
+{
+	return OPTEE_MIGRATE_INFO;
+}
+
+/*******************************************************************************
+ * System is about to be switched off. Allow the OPTEED/OPTEE to perform
+ * any actions needed.
+ ******************************************************************************/
+static void opteed_system_off(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+
+	assert(optee_vector_table);
+	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
+
+	/* Program the entry point */
+	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_off_entry);
+
+	/* Enter OPTEE. We do not care about the return value because we
+	 * must continue the shutdown anyway */
+	opteed_synchronous_sp_entry(optee_ctx);
+}
+
+/*******************************************************************************
+ * System is about to be reset. Allow the OPTEED/OPTEE to perform
+ * any actions needed.
+ ******************************************************************************/
+static void opteed_system_reset(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
+
+	assert(optee_vector_table);
+	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
+
+	/* Program the entry point */
+	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_reset_entry);
+
+	/* Enter OPTEE. We do not care about the return value because we
+	 * must continue the reset anyway */
+	opteed_synchronous_sp_entry(optee_ctx);
+}
+
+
+/*******************************************************************************
+ * Structure populated by the OPTEE Dispatcher to be given a chance to
+ * perform any OPTEE bookkeeping before PSCI executes a power mgmt.
+ * operation.
+ ******************************************************************************/
+const spd_pm_ops_t opteed_pm = {
+	.svc_on = opteed_cpu_on_handler,
+	.svc_off = opteed_cpu_off_handler,
+	.svc_suspend = opteed_cpu_suspend_handler,
+	.svc_on_finish = opteed_cpu_on_finish_handler,
+	.svc_suspend_finish = opteed_cpu_suspend_finish_handler,
+	.svc_migrate = NULL,
+	.svc_migrate_info = opteed_cpu_migrate_info,
+	.svc_system_off = opteed_system_off,
+	.svc_system_reset = opteed_system_reset,
+};
diff --git a/services/spd/opteed/opteed_private.h b/services/spd/opteed/opteed_private.h
new file mode 100644
index 0000000..242154f
--- /dev/null
+++ b/services/spd/opteed/opteed_private.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef OPTEED_PRIVATE_H
+#define OPTEED_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <lib/psci/psci.h>
+
+/*******************************************************************************
+ * OPTEE PM state information e.g. OPTEE is suspended, uninitialised etc
+ * and macros to access the state information in the per-cpu 'state' flags
+ ******************************************************************************/
+#define OPTEE_PSTATE_OFF		0
+#define OPTEE_PSTATE_ON			1
+#define OPTEE_PSTATE_SUSPEND		2
+#define OPTEE_PSTATE_SHIFT		0
+#define OPTEE_PSTATE_MASK		0x3
+#define get_optee_pstate(state)	((state >> OPTEE_PSTATE_SHIFT) & \
+				 OPTEE_PSTATE_MASK)
+#define clr_optee_pstate(state)	(state &= ~(OPTEE_PSTATE_MASK \
+					    << OPTEE_PSTATE_SHIFT))
+#define set_optee_pstate(st, pst) do {					       \
+					clr_optee_pstate(st);		       \
+					st |= (pst & OPTEE_PSTATE_MASK) <<     \
+						OPTEE_PSTATE_SHIFT;	       \
+				} while (0)
+
+
+/*******************************************************************************
+ * OPTEE execution state information i.e. aarch32 or aarch64
+ ******************************************************************************/
+#define OPTEE_AARCH32		MODE_RW_32
+#define OPTEE_AARCH64		MODE_RW_64
+
+/*******************************************************************************
+ * The OPTEED should know the type of OPTEE
+ ******************************************************************************/
+#define OPTEE_TYPE_UP		PSCI_TOS_NOT_UP_MIG_CAP
+#define OPTEE_TYPE_UPM		PSCI_TOS_UP_MIG_CAP
+#define OPTEE_TYPE_MP		PSCI_TOS_NOT_PRESENT_MP
+
+/*******************************************************************************
+ * OPTEE migrate type information as known to the OPTEED. We assume that
+ * the OPTEED is dealing with an MP Secure Payload.
+ ******************************************************************************/
+#define OPTEE_MIGRATE_INFO		OPTEE_TYPE_MP
+
+/*******************************************************************************
+ * Number of cpus that the present on this platform. TODO: Rely on a topology
+ * tree to determine this in the future to avoid assumptions about mpidr
+ * allocation
+ ******************************************************************************/
+#define OPTEED_CORE_COUNT		PLATFORM_CORE_COUNT
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define OPTEED_C_RT_CTX_X19		0x0
+#define OPTEED_C_RT_CTX_X20		0x8
+#define OPTEED_C_RT_CTX_X21		0x10
+#define OPTEED_C_RT_CTX_X22		0x18
+#define OPTEED_C_RT_CTX_X23		0x20
+#define OPTEED_C_RT_CTX_X24		0x28
+#define OPTEED_C_RT_CTX_X25		0x30
+#define OPTEED_C_RT_CTX_X26		0x38
+#define OPTEED_C_RT_CTX_X27		0x40
+#define OPTEED_C_RT_CTX_X28		0x48
+#define OPTEED_C_RT_CTX_X29		0x50
+#define OPTEED_C_RT_CTX_X30		0x58
+#define OPTEED_C_RT_CTX_SIZE		0x60
+#define OPTEED_C_RT_CTX_ENTRIES		(OPTEED_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+typedef uint32_t optee_vector_isn_t;
+
+typedef struct optee_vectors {
+	optee_vector_isn_t yield_smc_entry;
+	optee_vector_isn_t fast_smc_entry;
+	optee_vector_isn_t cpu_on_entry;
+	optee_vector_isn_t cpu_off_entry;
+	optee_vector_isn_t cpu_resume_entry;
+	optee_vector_isn_t cpu_suspend_entry;
+	optee_vector_isn_t fiq_entry;
+	optee_vector_isn_t system_off_entry;
+	optee_vector_isn_t system_reset_entry;
+} optee_vectors_t;
+
+/*
+ * The number of arguments to save during a SMC call for OPTEE.
+ * Currently only x1 and x2 are used by OPTEE.
+ */
+#define OPTEE_NUM_ARGS	0x2
+
+/* AArch64 callee saved general purpose register context structure. */
+DEFINE_REG_STRUCT(c_rt_regs, OPTEED_C_RT_CTX_ENTRIES);
+
+/*
+ * Compile time assertion to ensure that both the compiler and linker
+ * have the same double word aligned view of the size of the C runtime
+ * register context.
+ */
+CASSERT(OPTEED_C_RT_CTX_SIZE == sizeof(c_rt_regs_t),	\
+	assert_spd_c_rt_regs_size_mismatch);
+
+/*******************************************************************************
+ * Structure which helps the OPTEED to maintain the per-cpu state of OPTEE.
+ * 'state'          - collection of flags to track OPTEE state e.g. on/off
+ * 'mpidr'          - mpidr to associate a context with a cpu
+ * 'c_rt_ctx'       - stack address to restore C runtime context from after
+ *                    returning from a synchronous entry into OPTEE.
+ * 'cpu_ctx'        - space to maintain OPTEE architectural state
+ ******************************************************************************/
+typedef struct optee_context {
+	uint32_t state;
+	uint64_t mpidr;
+	uint64_t c_rt_ctx;
+	cpu_context_t cpu_ctx;
+} optee_context_t;
+
+/* OPTEED power management handlers */
+extern const spd_pm_ops_t opteed_pm;
+
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+struct optee_vectors;
+
+/*******************************************************************************
+ * Function & Data prototypes
+ ******************************************************************************/
+uint64_t opteed_enter_sp(uint64_t *c_rt_ctx);
+void __dead2 opteed_exit_sp(uint64_t c_rt_ctx, uint64_t ret);
+uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx);
+void __dead2 opteed_synchronous_sp_exit(optee_context_t *optee_ctx, uint64_t ret);
+void opteed_init_optee_ep_state(struct entry_point_info *optee_entry_point,
+				uint32_t rw,
+				uint64_t pc,
+				uint64_t pageable_part,
+				uint64_t mem_limit,
+				uint64_t dt_addr,
+				optee_context_t *optee_ctx);
+
+extern optee_context_t opteed_sp_context[OPTEED_CORE_COUNT];
+extern uint32_t opteed_rw;
+extern struct optee_vectors *optee_vector_table;
+#endif /*__ASSEMBLER__*/
+
+#endif /* OPTEED_PRIVATE_H */
diff --git a/services/spd/opteed/teesmc_opteed.h b/services/spd/opteed/teesmc_opteed.h
new file mode 100644
index 0000000..c82b58a
--- /dev/null
+++ b/services/spd/opteed/teesmc_opteed.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Copyright (c) 2014, Linaro Limited. All rights reserved. */
+
+#ifndef TEESMC_OPTEED_H
+#define TEESMC_OPTEED_H
+
+/*
+ * This file specifies SMC function IDs used when returning from TEE to the
+ * secure monitor.
+ *
+ * All SMC Function IDs indicates SMC32 Calling Convention but will carry
+ * full 64 bit values in the argument registers if invoked from Aarch64
+ * mode. This violates the SMC Calling Convention, but since this
+ * convention only coveres API towards Normal World it's something that
+ * only concerns the OP-TEE Dispatcher in Trusted Firmware-A and OP-TEE
+ * OS at Secure EL1.
+ */
+
+/*
+ * Issued when returning from initial entry.
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_ENTRY_DONE
+ * r1/x1	Pointer to entry vector
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_ENTRY_DONE		0
+#define TEESMC_OPTEED_RETURN_ENTRY_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_ENTRY_DONE)
+
+
+
+/*
+ * Issued when returning from "cpu_on" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_ON_DONE
+ * r1/x1	0 on success and anything else to indicate error condition
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_ON_DONE		1
+#define TEESMC_OPTEED_RETURN_ON_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_ON_DONE)
+
+/*
+ * Issued when returning from "cpu_off" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_OFF_DONE
+ * r1/x1	0 on success and anything else to indicate error condition
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_OFF_DONE		2
+#define TEESMC_OPTEED_RETURN_OFF_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_OFF_DONE)
+
+/*
+ * Issued when returning from "cpu_suspend" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_SUSPEND_DONE
+ * r1/x1	0 on success and anything else to indicate error condition
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_SUSPEND_DONE	3
+#define TEESMC_OPTEED_RETURN_SUSPEND_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_SUSPEND_DONE)
+
+/*
+ * Issued when returning from "cpu_resume" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_RESUME_DONE
+ * r1/x1	0 on success and anything else to indicate error condition
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_RESUME_DONE		4
+#define TEESMC_OPTEED_RETURN_RESUME_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_RESUME_DONE)
+
+/*
+ * Issued when returning from "std_smc" or "fast_smc" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_CALL_DONE
+ * r1-4/x1-4	Return value 0-3 which will passed to normal world in
+ *		r0-3/x0-3
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_CALL_DONE		5
+#define TEESMC_OPTEED_RETURN_CALL_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_CALL_DONE)
+
+/*
+ * Issued when returning from "fiq" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_FIQ_DONE
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_FIQ_DONE		6
+#define TEESMC_OPTEED_RETURN_FIQ_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_FIQ_DONE)
+
+/*
+ * Issued when returning from "system_off" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_SYSTEM_OFF_DONE
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_OFF_DONE	7
+#define TEESMC_OPTEED_RETURN_SYSTEM_OFF_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_OFF_DONE)
+
+/*
+ * Issued when returning from "system_reset" vector
+ *
+ * Register usage:
+ * r0/x0	SMC Function ID, TEESMC_OPTEED_RETURN_SYSTEM_RESET_DONE
+ */
+#define TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_RESET_DONE	8
+#define TEESMC_OPTEED_RETURN_SYSTEM_RESET_DONE \
+	TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_RESET_DONE)
+
+#endif /*TEESMC_OPTEED_H*/
diff --git a/services/spd/opteed/teesmc_opteed_macros.h b/services/spd/opteed/teesmc_opteed_macros.h
new file mode 100644
index 0000000..9d8a169
--- /dev/null
+++ b/services/spd/opteed/teesmc_opteed_macros.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef TEESMC_OPTEED_MACROS_H
+#define TEESMC_OPTEED_MACROS_H
+
+#include <common/runtime_svc.h>
+
+#define TEESMC_OPTEED_RV(func_num) \
+		((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \
+		 ((SMC_32) << FUNCID_CC_SHIFT) | \
+		 (62 << FUNCID_OEN_SHIFT) | \
+		 ((func_num) & FUNCID_NUM_MASK))
+
+#endif /* TEESMC_OPTEED_MACROS_H */
diff --git a/services/spd/tlkd/tlkd.mk b/services/spd/tlkd/tlkd.mk
new file mode 100644
index 0000000..56de0a6
--- /dev/null
+++ b/services/spd/tlkd/tlkd.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifeq (${ERROR_DEPRECATED},0)
+SPD_INCLUDES		:=	-Iinclude/bl32/payloads
+endif
+
+SPD_SOURCES		:=	services/spd/tlkd/tlkd_common.c		\
+				services/spd/tlkd/tlkd_helpers.S	\
+				services/spd/tlkd/tlkd_main.c		\
+				services/spd/tlkd/tlkd_pm.c
diff --git a/services/spd/tlkd/tlkd_common.c b/services/spd/tlkd/tlkd_common.c
new file mode 100644
index 0000000..dbe6c2e
--- /dev/null
+++ b/services/spd/tlkd/tlkd_common.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/el3_runtime/context_mgmt.h>
+
+#include "tlkd_private.h"
+
+#define AT_MASK		3
+
+/*******************************************************************************
+ * This function helps the SP to translate NS/S virtual addresses.
+ ******************************************************************************/
+uint64_t tlkd_va_translate(uintptr_t va, int type)
+{
+	uint64_t pa;
+
+	if (type & TLK_TRANSLATE_NS_VADDR) {
+
+		/* save secure context */
+		cm_el1_sysregs_context_save(SECURE);
+
+		/* restore non-secure context */
+		cm_el1_sysregs_context_restore(NON_SECURE);
+
+		/* switch NS bit to start using 64-bit, non-secure mappings */
+		write_scr(cm_get_scr_el3(NON_SECURE));
+		isb();
+	}
+
+	int at = type & AT_MASK;
+	switch (at) {
+	case 0:
+		ats12e1r(va);
+		break;
+	case 1:
+		ats12e1w(va);
+		break;
+	case 2:
+		ats12e0r(va);
+		break;
+	case 3:
+		ats12e0w(va);
+		break;
+	default:
+		assert(0); /* Unreachable */
+		break;
+	}
+
+	/* get the (NS/S) physical address */
+	isb();
+	pa = read_par_el1();
+
+	/* Restore secure state */
+	if (type & TLK_TRANSLATE_NS_VADDR) {
+
+		/* restore secure context */
+		cm_el1_sysregs_context_restore(SECURE);
+
+		/* switch NS bit to start using 32-bit, secure mappings */
+		write_scr(cm_get_scr_el3(SECURE));
+		isb();
+	}
+
+	return pa;
+}
+
+/*******************************************************************************
+ * Given a secure payload entrypoint, register width, cpu id & pointer to a
+ * context data structure, this function will create a secure context ready for
+ * programming an entry into the secure payload.
+ ******************************************************************************/
+void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point,
+			    uint32_t rw,
+			    uint64_t pc,
+			    tlk_context_t *tlk_ctx)
+{
+	uint32_t ep_attr, spsr;
+
+	/* Passing a NULL context is a critical programming error */
+	assert(tlk_ctx);
+	assert(tlk_entry_point);
+	assert(pc);
+
+	/* Associate this context with the cpu specified */
+	tlk_ctx->mpidr = read_mpidr_el1();
+	clr_yield_smc_active_flag(tlk_ctx->state);
+	cm_set_context(&tlk_ctx->cpu_ctx, SECURE);
+
+	if (rw == SP_AARCH64)
+		spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	else
+		spsr = SPSR_MODE32(MODE32_svc,
+				   SPSR_T_ARM,
+				   read_sctlr_el3() & SCTLR_EE_BIT,
+				   DISABLE_ALL_EXCEPTIONS);
+
+	/* initialise an entrypoint to set up the CPU context */
+	ep_attr = SECURE | EP_ST_ENABLE;
+	if (read_sctlr_el3() & SCTLR_EE_BIT)
+		ep_attr |= EP_EE_BIG;
+	SET_PARAM_HEAD(tlk_entry_point, PARAM_EP, VERSION_1, ep_attr);
+
+	tlk_entry_point->pc = pc;
+	tlk_entry_point->spsr = spsr;
+}
+
+/*******************************************************************************
+ * This function takes a TLK context pointer and:
+ * 1. Applies the S-EL1 system register context from tlk_ctx->cpu_ctx.
+ * 2. Saves the current C runtime state (callee saved registers) on the stack
+ *    frame and saves a reference to this state.
+ * 3. Calls el3_exit() so that the EL3 system and general purpose registers
+ *    from the tlk_ctx->cpu_ctx are used to enter the secure payload image.
+ ******************************************************************************/
+uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx)
+{
+	uint64_t rc;
+
+	/* Passing a NULL context is a critical programming error */
+	assert(tlk_ctx);
+
+	/* Apply the Secure EL1 system register context and switch to it */
+	assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx);
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+
+	rc = tlkd_enter_sp(&tlk_ctx->c_rt_ctx);
+#if ENABLE_ASSERTIONS
+	tlk_ctx->c_rt_ctx = 0;
+#endif
+
+	return rc;
+}
+
+/*******************************************************************************
+ * This function takes a TLK context pointer and:
+ * 1. Saves the S-EL1 system register context to tlk_ctx->cpu_ctx.
+ * 2. Restores the current C runtime state (callee saved registers) from the
+ *    stack frame using reference to this state saved in tlkd_enter_sp().
+ * 3. It does not need to save any general purpose or EL3 system register state
+ *    as the generic smc entry routine should have saved those.
+ ******************************************************************************/
+void tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx, uint64_t ret)
+{
+	/* Passing a NULL context is a critical programming error */
+	assert(tlk_ctx);
+
+	/* Save the Secure EL1 system register context */
+	assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx);
+	cm_el1_sysregs_context_save(SECURE);
+
+	assert(tlk_ctx->c_rt_ctx != 0);
+	tlkd_exit_sp(tlk_ctx->c_rt_ctx, ret);
+
+	/* Should never reach here */
+	assert(0);
+}
diff --git a/services/spd/tlkd/tlkd_helpers.S b/services/spd/tlkd/tlkd_helpers.S
new file mode 100644
index 0000000..6e616a6
--- /dev/null
+++ b/services/spd/tlkd/tlkd_helpers.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "tlkd_private.h"
+
+	.global tlkd_enter_sp
+	.global tlkd_exit_sp
+
+	/* ---------------------------------------------
+	 * This function is called with SP_EL0 as stack.
+	 * Here we stash our EL3 callee-saved registers
+	 * on to the stack as a part of saving the C
+	 * runtime and enter the secure payload.
+	 * 'x0' contains a pointer to the memory where
+	 * the address of the C runtime context is to be
+	 * saved.
+	 * ---------------------------------------------
+	 */
+func tlkd_enter_sp
+	/* Make space for the registers that we're going to save */
+	mov	x3, sp
+	str	x3, [x0, #0]
+	sub	sp, sp, #TLKD_C_RT_CTX_SIZE
+
+	/* Save callee-saved registers on to the stack */
+	stp	x19, x20, [sp, #TLKD_C_RT_CTX_X19]
+	stp	x21, x22, [sp, #TLKD_C_RT_CTX_X21]
+	stp	x23, x24, [sp, #TLKD_C_RT_CTX_X23]
+	stp	x25, x26, [sp, #TLKD_C_RT_CTX_X25]
+	stp	x27, x28, [sp, #TLKD_C_RT_CTX_X27]
+	stp	x29, x30, [sp, #TLKD_C_RT_CTX_X29]
+
+	/* ----------------------------------------------
+	 * Everything is setup now. el3_exit() will
+	 * use the secure context to restore to the
+	 * general purpose and EL3 system registers to
+	 * ERET into the secure payload.
+	 * ----------------------------------------------
+	 */
+	b	el3_exit
+endfunc tlkd_enter_sp
+
+	/* ----------------------------------------------
+	 * This function is called with 'x0' pointing to
+	 * a C runtime context saved in tlkd_enter_sp().
+	 * It restores the saved registers and jumps to
+	 * that runtime with 'x0' as the new sp. This
+	 * destroys the C runtime context that had been
+	 * built on the stack below the saved context by
+	 * the caller. Later the second parameter 'x1'
+	 * is passed as return value to the caller
+	 * ----------------------------------------------
+	 */
+func tlkd_exit_sp
+	/* Restore the previous stack */
+	mov	sp, x0
+
+	/* Restore callee-saved registers on to the stack */
+	ldp	x19, x20, [x0, #(TLKD_C_RT_CTX_X19 - TLKD_C_RT_CTX_SIZE)]
+	ldp	x21, x22, [x0, #(TLKD_C_RT_CTX_X21 - TLKD_C_RT_CTX_SIZE)]
+	ldp	x23, x24, [x0, #(TLKD_C_RT_CTX_X23 - TLKD_C_RT_CTX_SIZE)]
+	ldp	x25, x26, [x0, #(TLKD_C_RT_CTX_X25 - TLKD_C_RT_CTX_SIZE)]
+	ldp	x27, x28, [x0, #(TLKD_C_RT_CTX_X27 - TLKD_C_RT_CTX_SIZE)]
+	ldp	x29, x30, [x0, #(TLKD_C_RT_CTX_X29 - TLKD_C_RT_CTX_SIZE)]
+
+	/* ------------------------------------------------
+	 * This should take us back to the instruction
+	 * after the call to the last tlkd_enter_sp().
+	 * Place the second parameter to x0 so that the
+	 * caller will see it as a return value from the
+	 * original entry call
+	 * ------------------------------------------------
+	 */
+	mov	x0, x1
+	ret
+endfunc tlkd_exit_sp
diff --git a/services/spd/tlkd/tlkd_main.c b/services/spd/tlkd/tlkd_main.c
new file mode 100644
index 0000000..3cfc52d
--- /dev/null
+++ b/services/spd/tlkd/tlkd_main.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*******************************************************************************
+ * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a
+ * plug-in component to the Secure Monitor, registered as a runtime service. The
+ * SPD is expected to be a functional extension of the Secure Payload (SP) that
+ * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting
+ * the Trusted OS/Applications range to the dispatcher. The SPD will either
+ * handle the request locally or delegate it to the Secure Payload. It is also
+ * responsible for initialising and maintaining communication with the SP.
+ ******************************************************************************/
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl32/payloads/tlk.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#include "tlkd_private.h"
+
+extern const spd_pm_ops_t tlkd_pm_ops;
+
+/*******************************************************************************
+ * Per-cpu Secure Payload state
+ ******************************************************************************/
+tlk_context_t tlk_ctx;
+
+/*******************************************************************************
+ * CPU number on which TLK booted up
+ ******************************************************************************/
+static uint32_t boot_cpu;
+
+/* TLK UID: RFC-4122 compliant UUID (version-5, sha-1) */
+DEFINE_SVC_UUID2(tlk_uuid,
+	0xc9e911bd, 0xba2b, 0xee52, 0xb1, 0x72,
+	0x46, 0x1f, 0xba, 0x97, 0x7f, 0x63);
+
+static int32_t tlkd_init(void);
+
+/*******************************************************************************
+ * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
+ * (aarch32/aarch64) if not already known and initialises the context for entry
+ * into the SP for its initialisation.
+ ******************************************************************************/
+static int32_t tlkd_setup(void)
+{
+	entry_point_info_t *tlk_ep_info;
+
+	/*
+	 * Get information about the Secure Payload (BL32) image. Its
+	 * absence is a critical failure.
+	 */
+	tlk_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	if (!tlk_ep_info) {
+		WARN("No SP provided. Booting device without SP"
+			" initialization. SMC`s destined for SP"
+			" will return SMC_UNK\n");
+		return 1;
+	}
+
+	/*
+	 * If there's no valid entry point for SP, we return a non-zero value
+	 * signalling failure initializing the service. We bail out without
+	 * registering any handlers
+	 */
+	if (!tlk_ep_info->pc)
+		return 1;
+
+	/*
+	 * Inspect the SP image's SPSR and determine it's execution state
+	 * i.e whether AArch32 or AArch64.
+	 */
+	tlkd_init_tlk_ep_state(tlk_ep_info,
+		(tlk_ep_info->spsr >> MODE_RW_SHIFT) & MODE_RW_MASK,
+		tlk_ep_info->pc,
+		&tlk_ctx);
+
+	/*
+	 * All TLK SPD initialization done. Now register our init function
+	 * with BL31 for deferred invocation
+	 */
+	bl31_register_bl32_init(&tlkd_init);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This function passes control to the Secure Payload image (BL32) for the first
+ * time on the primary cpu after a cold boot. It assumes that a valid secure
+ * context has already been created by tlkd_setup() which can be directly
+ * used. This function performs a synchronous entry into the Secure payload.
+ * The SP passes control back to this routine through a SMC.
+ ******************************************************************************/
+static int32_t tlkd_init(void)
+{
+	entry_point_info_t *tlk_entry_point;
+
+	/*
+	 * Get information about the Secure Payload (BL32) image. Its
+	 * absence is a critical failure.
+	 */
+	tlk_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
+	assert(tlk_entry_point);
+
+	cm_init_my_context(tlk_entry_point);
+
+	/*
+	 * TLK runs only on a single CPU. Store the value of the boot
+	 * CPU for sanity checking later.
+	 */
+	boot_cpu = plat_my_core_pos();
+
+	/*
+	 * Arrange for an entry into the test secure payload.
+	 */
+	return tlkd_synchronous_sp_entry(&tlk_ctx);
+}
+
+/*******************************************************************************
+ * This function is responsible for handling all SMCs in the Trusted OS/App
+ * range from the non-secure state as defined in the SMC Calling Convention
+ * Document. It is also responsible for communicating with the Secure payload
+ * to delegate work and return results back to the non-secure state. Lastly it
+ * will also return any information that the secure payload needs to do the
+ * work assigned to it.
+ ******************************************************************************/
+static uintptr_t tlkd_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	cpu_context_t *ns_cpu_context;
+	gp_regs_t *gp_regs;
+	uint32_t ns;
+	uint64_t par;
+
+	/* Passing a NULL context is a critical programming error */
+	assert(handle);
+
+	/* These SMCs are only supported by a single CPU */
+	if (boot_cpu != plat_my_core_pos())
+		SMC_RET1(handle, SMC_UNK);
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+
+	switch (smc_fid) {
+
+	/*
+	 * This function ID is used by SP to indicate that it was
+	 * preempted by a non-secure world IRQ.
+	 */
+	case TLK_PREEMPTED:
+
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		assert(handle == cm_get_context(SECURE));
+		cm_el1_sysregs_context_save(SECURE);
+
+		/* Get a reference to the non-secure context */
+		ns_cpu_context = cm_get_context(NON_SECURE);
+		assert(ns_cpu_context);
+
+		/*
+		 * Restore non-secure state. There is no need to save the
+		 * secure system register context since the SP was supposed
+		 * to preserve it during S-EL1 interrupt handling.
+		 */
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+
+		SMC_RET1(ns_cpu_context, x1);
+
+	/*
+	 * This is a request from the non-secure context to:
+	 *
+	 * a. register shared memory with the SP for storing it's
+	 *    activity logs.
+	 * b. register shared memory with the SP for passing args
+	 *    required for maintaining sessions with the Trusted
+	 *    Applications.
+	 * c. register shared persistent buffers for secure storage
+	 * d. register NS DRAM ranges passed by Cboot
+	 * e. register Root of Trust parameters from Cboot for Verified Boot
+	 * f. open/close sessions
+	 * g. issue commands to the Trusted Apps
+	 * h. resume the preempted yielding SMC call.
+	 */
+	case TLK_REGISTER_LOGBUF:
+	case TLK_REGISTER_REQBUF:
+	case TLK_SS_REGISTER_HANDLER:
+	case TLK_REGISTER_NS_DRAM_RANGES:
+	case TLK_SET_ROOT_OF_TRUST:
+	case TLK_OPEN_TA_SESSION:
+	case TLK_CLOSE_TA_SESSION:
+	case TLK_TA_LAUNCH_OP:
+	case TLK_TA_SEND_EVENT:
+	case TLK_RESUME_FID:
+
+		if (!ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * This is a fresh request from the non-secure client.
+		 * The parameters are in x1 and x2. Figure out which
+		 * registers need to be preserved, save the non-secure
+		 * state and send the request to the secure payload.
+		 */
+		assert(handle == cm_get_context(NON_SECURE));
+
+		/*
+		 * Check if we are already processing a yielding SMC
+		 * call. Of all the supported fids, only the "resume"
+		 * fid expects the flag to be set.
+		 */
+		if (smc_fid == TLK_RESUME_FID) {
+			if (!get_yield_smc_active_flag(tlk_ctx.state))
+				SMC_RET1(handle, SMC_UNK);
+		} else {
+			if (get_yield_smc_active_flag(tlk_ctx.state))
+				SMC_RET1(handle, SMC_UNK);
+		}
+
+		cm_el1_sysregs_context_save(NON_SECURE);
+
+		/*
+		 * Verify if there is a valid context to use.
+		 */
+		assert(&tlk_ctx.cpu_ctx == cm_get_context(SECURE));
+
+		/*
+		 * Mark the SP state as active.
+		 */
+		set_yield_smc_active_flag(tlk_ctx.state);
+
+		/*
+		 * We are done stashing the non-secure context. Ask the
+		 * secure payload to do the work now.
+		 */
+		cm_el1_sysregs_context_restore(SECURE);
+		cm_set_next_eret_context(SECURE);
+
+		/*
+		 * TLK is a 32-bit Trusted OS and so expects the SMC
+		 * arguments via r0-r7. TLK expects the monitor frame
+		 * registers to be 64-bits long. Hence, we pass x0 in
+		 * r0-r1, x1 in r2-r3, x3 in r4-r5 and x4 in r6-r7.
+		 *
+		 * As smc_fid is a uint32 value, r1 contains 0.
+		 */
+		gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+		write_ctx_reg(gp_regs, CTX_GPREG_X4, (uint32_t)x2);
+		write_ctx_reg(gp_regs, CTX_GPREG_X5, (uint32_t)(x2 >> 32));
+		write_ctx_reg(gp_regs, CTX_GPREG_X6, (uint32_t)x3);
+		write_ctx_reg(gp_regs, CTX_GPREG_X7, (uint32_t)(x3 >> 32));
+		SMC_RET4(&tlk_ctx.cpu_ctx, smc_fid, 0, (uint32_t)x1,
+			(uint32_t)(x1 >> 32));
+
+	/*
+	 * Translate NS/EL1-S virtual addresses.
+	 *
+	 * x1 = virtual address
+	 * x3 = type (NS/S)
+	 *
+	 * Returns PA:lo in r0, PA:hi in r1.
+	 */
+	case TLK_VA_TRANSLATE:
+
+		/* Should be invoked only by secure world */
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/* NS virtual addresses are 64-bit long */
+		if (x3 & TLK_TRANSLATE_NS_VADDR)
+			x1 = (uint32_t)x1 | (x2 << 32);
+
+		if (!x1)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * TODO: Sanity check x1. This would require platform
+		 * support.
+		 */
+
+		/* virtual address and type: ns/s */
+		par = tlkd_va_translate(x1, x3);
+
+		/* return physical address in r0-r1 */
+		SMC_RET4(handle, (uint32_t)par, (uint32_t)(par >> 32), 0, 0);
+
+	/*
+	 * This is a request from the SP to mark completion of
+	 * a yielding function ID.
+	 */
+	case TLK_REQUEST_DONE:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * Mark the SP state as inactive.
+		 */
+		clr_yield_smc_active_flag(tlk_ctx.state);
+
+		/* Get a reference to the non-secure context */
+		ns_cpu_context = cm_get_context(NON_SECURE);
+		assert(ns_cpu_context);
+
+		/*
+		 * This is a request completion SMC and we must switch to
+		 * the non-secure world to pass the result.
+		 */
+		cm_el1_sysregs_context_save(SECURE);
+
+		/*
+		 * We are done stashing the secure context. Switch to the
+		 * non-secure context and return the result.
+		 */
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+		SMC_RET1(ns_cpu_context, x1);
+
+	/*
+	 * This function ID is used only by the SP to indicate it has
+	 * finished initialising itself after a cold boot
+	 */
+	case TLK_ENTRY_DONE:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * SP has been successfully initialized. Register power
+		 * management hooks with PSCI
+		 */
+		psci_register_spd_pm_hook(&tlkd_pm_ops);
+
+		/*
+		 * TLK reports completion. The SPD must have initiated
+		 * the original request through a synchronous entry
+		 * into the SP. Jump back to the original C runtime
+		 * context.
+		 */
+		tlkd_synchronous_sp_exit(&tlk_ctx, x1);
+		break;
+
+	/*
+	 * These function IDs are used only by TLK to indicate it has
+	 * finished:
+	 * 1. suspending itself after an earlier psci cpu_suspend
+	 *    request.
+	 * 2. resuming itself after an earlier psci cpu_suspend
+	 *    request.
+	 * 3. powering down after an earlier psci system_off/system_reset
+	 *    request.
+	 */
+	case TLK_SUSPEND_DONE:
+	case TLK_RESUME_DONE:
+	case TLK_SYSTEM_OFF_DONE:
+
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * TLK reports completion. TLKD must have initiated the
+		 * original request through a synchronous entry into the SP.
+		 * Jump back to the original C runtime context, and pass x1 as
+		 * return value to the caller
+		 */
+		tlkd_synchronous_sp_exit(&tlk_ctx, x1);
+		break;
+
+	/*
+	 * Return the number of service function IDs implemented to
+	 * provide service to non-secure
+	 */
+	case TOS_CALL_COUNT:
+		SMC_RET1(handle, TLK_NUM_FID);
+
+	/*
+	 * Return TLK's UID to the caller
+	 */
+	case TOS_UID:
+		SMC_UUID_RET(handle, tlk_uuid);
+
+	/*
+	 * Return the version of current implementation
+	 */
+	case TOS_CALL_VERSION:
+		SMC_RET2(handle, TLK_VERSION_MAJOR, TLK_VERSION_MINOR);
+
+	default:
+		WARN("%s: Unhandled SMC: 0x%x\n", __func__, smc_fid);
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/* Define a SPD runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	tlkd_tos_fast,
+
+	OEN_TOS_START,
+	OEN_TOS_END,
+	SMC_TYPE_FAST,
+	tlkd_setup,
+	tlkd_smc_handler
+);
+
+/* Define a SPD runtime service descriptor for yielding SMC calls */
+DECLARE_RT_SVC(
+	tlkd_tos_std,
+
+	OEN_TOS_START,
+	OEN_TOS_END,
+	SMC_TYPE_YIELD,
+	NULL,
+	tlkd_smc_handler
+);
+
+/* Define a SPD runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	tlkd_tap_fast,
+
+	OEN_TAP_START,
+	OEN_TAP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	tlkd_smc_handler
+);
+
+/* Define a SPD runtime service descriptor for yielding SMC calls */
+DECLARE_RT_SVC(
+	tlkd_tap_std,
+
+	OEN_TAP_START,
+	OEN_TAP_END,
+	SMC_TYPE_YIELD,
+	NULL,
+	tlkd_smc_handler
+);
diff --git a/services/spd/tlkd/tlkd_pm.c b/services/spd/tlkd/tlkd_pm.c
new file mode 100644
index 0000000..7d1959b
--- /dev/null
+++ b/services/spd/tlkd/tlkd_pm.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl32/payloads/tlk.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/psci/psci.h>
+
+#include "tlkd_private.h"
+
+extern tlk_context_t tlk_ctx;
+
+#define MPIDR_CPU0	0x80000000
+
+/*******************************************************************************
+ * Return the type of payload TLKD is dealing with. Report the current
+ * resident cpu (mpidr format) if it is a UP/UP migratable payload.
+ ******************************************************************************/
+static int32_t cpu_migrate_info(u_register_t *resident_cpu)
+{
+	/* the payload runs only on CPU0 */
+	*resident_cpu = MPIDR_CPU0;
+
+	/* Uniprocessor, not migrate capable payload */
+	return PSCI_TOS_NOT_UP_MIG_CAP;
+}
+
+/*******************************************************************************
+ * This cpu is being suspended. Inform TLK of the SYSTEM_SUSPEND event, so
+ * that it can pass this information to its Trusted Apps.
+ ******************************************************************************/
+static void cpu_suspend_handler(u_register_t suspend_level)
+{
+	gp_regs_t *gp_regs;
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
+	int32_t rc = 0;
+
+	/*
+	 * TLK runs only on CPU0 and suspends its Trusted Apps during
+	 * SYSTEM_SUSPEND. It has no role to play during CPU_SUSPEND.
+	 */
+	if ((cpu != 0) || (suspend_level != PLAT_MAX_PWR_LVL))
+		return;
+
+	/* pass system suspend event to TLK */
+	gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+	write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_SUSPEND);
+
+	/* Program the entry point and enter TLK */
+	rc = tlkd_synchronous_sp_entry(&tlk_ctx);
+
+	/*
+	 * Read the response from TLK. A non-zero return means that
+	 * something went wrong while communicating with it.
+	 */
+	if (rc != 0)
+		panic();
+}
+
+/*******************************************************************************
+ * This cpu is being resumed. Inform TLK of the SYSTEM_SUSPEND exit, so
+ * that it can pass this information to its Trusted Apps.
+ ******************************************************************************/
+static void cpu_resume_handler(u_register_t suspend_level)
+{
+	gp_regs_t *gp_regs;
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
+	int32_t rc = 0;
+
+	/*
+	 * TLK runs only on CPU0 and resumes its Trusted Apps during
+	 * SYSTEM_SUSPEND exit. It has no role to play during CPU_SUSPEND
+	 * exit.
+	 */
+	if ((cpu != 0) || (suspend_level != PLAT_MAX_PWR_LVL))
+		return;
+
+	/* pass system resume event to TLK */
+	gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+	write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_RESUME);
+
+	/* Program the entry point and enter TLK */
+	rc = tlkd_synchronous_sp_entry(&tlk_ctx);
+
+	/*
+	 * Read the response from TLK. A non-zero return means that
+	 * something went wrong while communicating with it.
+	 */
+	if (rc != 0)
+		panic();
+}
+
+/*******************************************************************************
+ * System is about to be reset. Inform the SP to allow any book-keeping
+ ******************************************************************************/
+static void system_off_handler(void)
+{
+	int cpu = read_mpidr() & MPIDR_CPU_MASK;
+	gp_regs_t *gp_regs;
+
+	/* TLK runs only on CPU0 */
+	if (cpu != 0)
+		return;
+
+	/* pass system off/reset events to TLK */
+	gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+	write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_OFF);
+
+	/*
+	 * Enter the SP. We do not care about the return value because we
+	 * must continue with the shutdown anyway.
+	 */
+	(void)tlkd_synchronous_sp_entry(&tlk_ctx);
+}
+
+/*******************************************************************************
+ * Structure populated by the Dispatcher to be given a chance to perform any
+ * bookkeeping before PSCI executes a power mgmt.  operation.
+ ******************************************************************************/
+const spd_pm_ops_t tlkd_pm_ops = {
+	.svc_migrate_info = cpu_migrate_info,
+	.svc_suspend = cpu_suspend_handler,
+	.svc_suspend_finish = cpu_resume_handler,
+	.svc_system_off = system_off_handler,
+	.svc_system_reset = system_off_handler
+};
diff --git a/services/spd/tlkd/tlkd_private.h b/services/spd/tlkd/tlkd_private.h
new file mode 100644
index 0000000..5d5d0e8
--- /dev/null
+++ b/services/spd/tlkd/tlkd_private.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TLKD_PRIVATE_H
+#define TLKD_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <lib/psci/psci.h>
+
+/*
+ * This flag is used by the TLKD to determine if the SP is servicing a yielding
+ * SMC request prior to programming the next entry into the SP e.g. if SP
+ * execution is preempted by a non-secure interrupt and handed control to the
+ * normal world. If another request which is distinct from what the SP was
+ * previously doing arrives, then this flag will be help the TLKD to either
+ * reject the new request or service it while ensuring that the previous context
+ * is not corrupted.
+ */
+#define YIELD_SMC_ACTIVE_FLAG_SHIFT	2
+#define YIELD_SMC_ACTIVE_FLAG_MASK	1
+#define get_yield_smc_active_flag(state)				\
+			(((state) >> YIELD_SMC_ACTIVE_FLAG_SHIFT)	\
+			& YIELD_SMC_ACTIVE_FLAG_MASK)
+#define set_yield_smc_active_flag(state)	((state) |=		\
+					 (1 << YIELD_SMC_ACTIVE_FLAG_SHIFT))
+#define clr_yield_smc_active_flag(state)	((state) &=		\
+					 ~(YIELD_SMC_ACTIVE_FLAG_MASK	\
+					 << YIELD_SMC_ACTIVE_FLAG_SHIFT))
+
+/*******************************************************************************
+ * Translate virtual address received from the NS world
+ ******************************************************************************/
+#define TLK_TRANSLATE_NS_VADDR		4
+
+/*******************************************************************************
+ * Secure Payload execution state information i.e. aarch32 or aarch64
+ ******************************************************************************/
+#define SP_AARCH32		MODE_RW_32
+#define SP_AARCH64		MODE_RW_64
+
+/*******************************************************************************
+ * Number of cpus that the present on this platform. TODO: Rely on a topology
+ * tree to determine this in the future to avoid assumptions about mpidr
+ * allocation
+ ******************************************************************************/
+#define TLKD_CORE_COUNT		PLATFORM_CORE_COUNT
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define TLKD_C_RT_CTX_X19		0x0
+#define TLKD_C_RT_CTX_X20		0x8
+#define TLKD_C_RT_CTX_X21		0x10
+#define TLKD_C_RT_CTX_X22		0x18
+#define TLKD_C_RT_CTX_X23		0x20
+#define TLKD_C_RT_CTX_X24		0x28
+#define TLKD_C_RT_CTX_X25		0x30
+#define TLKD_C_RT_CTX_X26		0x38
+#define TLKD_C_RT_CTX_X27		0x40
+#define TLKD_C_RT_CTX_X28		0x48
+#define TLKD_C_RT_CTX_X29		0x50
+#define TLKD_C_RT_CTX_X30		0x58
+#define TLKD_C_RT_CTX_SIZE		0x60
+#define TLKD_C_RT_CTX_ENTRIES		(TLKD_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+/* AArch64 callee saved general purpose register context structure. */
+DEFINE_REG_STRUCT(c_rt_regs, TLKD_C_RT_CTX_ENTRIES);
+
+/*
+ * Compile time assertion to ensure that both the compiler and linker
+ * have the same double word aligned view of the size of the C runtime
+ * register context.
+ */
+CASSERT(TLKD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t),	\
+	assert_tlkd_c_rt_regs_size_mismatch);
+
+/*******************************************************************************
+ * Structure which helps the SPD to maintain the per-cpu state of the SP.
+ * 'state'          - collection of flags to track SP state e.g. on/off
+ * 'mpidr'          - mpidr to associate a context with a cpu
+ * 'c_rt_ctx'       - stack address to restore C runtime context from after
+ *                    returning from a synchronous entry into the SP.
+ * 'cpu_ctx'        - space to maintain SP architectural state
+ * 'saved_tsp_args' - space to store arguments for TSP arithmetic operations
+ *                    which will queried using the TSP_GET_ARGS SMC by TSP.
+ ******************************************************************************/
+typedef struct tlk_context {
+	uint32_t state;
+	uint64_t mpidr;
+	uint64_t c_rt_ctx;
+	cpu_context_t cpu_ctx;
+} tlk_context_t;
+
+/*******************************************************************************
+ * Function & Data prototypes
+ ******************************************************************************/
+uint64_t tlkd_va_translate(uintptr_t va, int type);
+uint64_t tlkd_enter_sp(uint64_t *c_rt_ctx);
+void __dead2 tlkd_exit_sp(uint64_t c_rt_ctx, uint64_t ret);
+uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx);
+void __dead2 tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx,
+			uint64_t ret);
+void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point,
+				uint32_t rw,
+				uint64_t pc,
+				tlk_context_t *tlk_ctx);
+
+#endif /*__ASSEMBLER__*/
+
+#endif /* TLKD_PRIVATE_H */
diff --git a/services/spd/trusty/generic-arm64-smcall.c b/services/spd/trusty/generic-arm64-smcall.c
new file mode 100644
index 0000000..dfc3e71
--- /dev/null
+++ b/services/spd/trusty/generic-arm64-smcall.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <platform_def.h>
+
+#include "generic-arm64-smcall.h"
+
+int trusty_disable_serial_debug;
+
+struct dputc_state {
+	char linebuf[128];
+	unsigned l;
+};
+
+static struct dputc_state dputc_state[2];
+
+static void trusty_dputc(char ch, int secure)
+{
+	unsigned i;
+	struct dputc_state *s = &dputc_state[!secure];
+
+	if (trusty_disable_serial_debug)
+		return;
+
+	s->linebuf[s->l++] = ch;
+	if (s->l == sizeof(s->linebuf) || ch == '\n') {
+		if (secure)
+			printf("secure os: ");
+		else
+			printf("non-secure os: ");
+		for (i = 0; i < s->l; i++) {
+			putchar(s->linebuf[i]);
+		}
+		if (ch != '\n') {
+			printf(" <...>\n");
+		}
+		s->l = 0;
+	}
+}
+
+static uint64_t trusty_get_reg_base(uint32_t reg)
+{
+	switch (reg) {
+	case 0:
+		return PLAT_ARM_GICD_BASE;
+
+	case 1:
+		return PLAT_ARM_GICC_BASE;
+
+	default:
+		NOTICE("%s(0x%x) unknown reg\n", __func__, reg);
+		return SMC_UNK;
+	}
+}
+
+static uintptr_t trusty_generic_platform_smc(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	switch (smc_fid) {
+	case SMC_FC_DEBUG_PUTC:
+		trusty_dputc(x1, is_caller_secure(flags));
+		SMC_RET1(handle, 0);
+
+	case SMC_FC_GET_REG_BASE:
+	case SMC_FC64_GET_REG_BASE:
+		SMC_RET1(handle, trusty_get_reg_base(x1));
+
+	default:
+		NOTICE("%s(0x%x, 0x%lx) unknown smc\n", __func__, smc_fid, x1);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Define a SPD runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	trusty_fast,
+
+	SMC_ENTITY_PLATFORM_MONITOR,
+	SMC_ENTITY_PLATFORM_MONITOR,
+	SMC_TYPE_FAST,
+	NULL,
+	trusty_generic_platform_smc
+);
+
diff --git a/services/spd/trusty/generic-arm64-smcall.h b/services/spd/trusty/generic-arm64-smcall.h
new file mode 100644
index 0000000..06efc72
--- /dev/null
+++ b/services/spd/trusty/generic-arm64-smcall.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "smcall.h"
+
+#define	SMC_ENTITY_PLATFORM_MONITOR	61
+
+/*
+ * SMC calls implemented by EL3 monitor
+ */
+
+/*
+ * Write character in r1 to debug console
+ */
+#define SMC_FC_DEBUG_PUTC	SMC_FASTCALL_NR(SMC_ENTITY_PLATFORM_MONITOR, 0x0)
+
+/*
+ * Get register base address
+ * r1: SMC_GET_GIC_BASE_GICD or SMC_GET_GIC_BASE_GICC
+ */
+#define SMC_GET_GIC_BASE_GICD	0
+#define SMC_GET_GIC_BASE_GICC	1
+#define SMC_FC_GET_REG_BASE	SMC_FASTCALL_NR(SMC_ENTITY_PLATFORM_MONITOR, 0x1)
+#define SMC_FC64_GET_REG_BASE	SMC_FASTCALL64_NR(SMC_ENTITY_PLATFORM_MONITOR, 0x1)
diff --git a/services/spd/trusty/sm_err.h b/services/spd/trusty/sm_err.h
new file mode 100644
index 0000000..80a8748
--- /dev/null
+++ b/services/spd/trusty/sm_err.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SM_ERR_H
+#define SM_ERR_H
+
+/* Errors from the secure monitor */
+#define SM_ERR_UNDEFINED_SMC		0xFFFFFFFF /* Unknown SMC (defined by ARM DEN 0028A(0.9.0) */
+#define SM_ERR_INVALID_PARAMETERS	-2
+#define SM_ERR_INTERRUPTED		-3	/* Got interrupted. Call back with restart SMC */
+#define SM_ERR_UNEXPECTED_RESTART	-4	/* Got an restart SMC when we didn't expect it */
+#define SM_ERR_BUSY			-5	/* Temporarily busy. Call back with original args */
+#define SM_ERR_INTERLEAVED_SMC		-6	/* Got a trusted_service SMC when a restart SMC is required */
+#define SM_ERR_INTERNAL_FAILURE		-7	/* Unknown error */
+#define SM_ERR_NOT_SUPPORTED		-8
+#define SM_ERR_NOT_ALLOWED		-9	/* SMC call not allowed */
+#define SM_ERR_END_OF_INPUT		-10
+
+#endif /* SM_ERR_H */
diff --git a/services/spd/trusty/smcall.h b/services/spd/trusty/smcall.h
new file mode 100644
index 0000000..9c1c38c
--- /dev/null
+++ b/services/spd/trusty/smcall.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SMCALL_H
+#define SMCALL_H
+
+#define SMC_NUM_ENTITIES	64U
+#define SMC_NUM_ARGS		4U
+#define SMC_NUM_PARAMS		(SMC_NUM_ARGS - 1U)
+
+#define SMC_IS_FASTCALL(smc_nr)	((smc_nr) & 0x80000000U)
+#define SMC_IS_SMC64(smc_nr)	((smc_nr) & 0x40000000U)
+#define SMC_ENTITY(smc_nr)	(((smc_nr) & 0x3F000000U) >> 24U)
+#define SMC_FUNCTION(smc_nr)	((smc_nr) & 0x0000FFFFU)
+
+#define SMC_NR(entity, fn, fastcall, smc64)			\
+		(((((uint32_t)(fastcall)) & 0x1U) << 31U) |	\
+		(((smc64) & 0x1U) << 30U) |			\
+		(((entity) & 0x3FU) << 24U) |			\
+		((fn) & 0xFFFFU))
+
+#define SMC_FASTCALL_NR(entity, fn)	SMC_NR((entity), (fn), 1U, 0U)
+#define SMC_FASTCALL64_NR(entity, fn)	SMC_NR((entity), (fn), 1U, 1U)
+#define SMC_YIELDCALL_NR(entity, fn)	SMC_NR((entity), (fn), 0U, 0U)
+#define SMC_YIELDCALL64_NR(entity, fn)	SMC_NR((entity), (fn), 0U, 1U)
+
+#define	SMC_ENTITY_ARCH			0U	/* ARM Architecture calls */
+#define	SMC_ENTITY_CPU			1U	/* CPU Service calls */
+#define	SMC_ENTITY_SIP			2U	/* SIP Service calls */
+#define	SMC_ENTITY_OEM			3U	/* OEM Service calls */
+#define	SMC_ENTITY_STD			4U	/* Standard Service calls */
+#define	SMC_ENTITY_RESERVED		5U	/* Reserved for future use */
+#define	SMC_ENTITY_TRUSTED_APP		48U	/* Trusted Application calls */
+#define	SMC_ENTITY_TRUSTED_OS		50U	/* Trusted OS calls */
+#define SMC_ENTITY_LOGGING              51U	/* Used for secure -> nonsecure logging */
+#define	SMC_ENTITY_SECURE_MONITOR	60U	/* Trusted OS calls internal to secure monitor */
+
+/* FC = Fast call, YC = Yielding call */
+#define SMC_YC_RESTART_LAST	SMC_YIELDCALL_NR  (SMC_ENTITY_SECURE_MONITOR, 0U)
+#define SMC_YC_NOP		SMC_YIELDCALL_NR  (SMC_ENTITY_SECURE_MONITOR, 1U)
+
+/*
+ * Return from secure os to non-secure os with return value in r1
+ */
+#define SMC_YC_NS_RETURN	SMC_YIELDCALL_NR  (SMC_ENTITY_SECURE_MONITOR, 0U)
+
+#define SMC_FC_RESERVED		SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0U)
+#define SMC_FC_FIQ_EXIT		SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1U)
+#define SMC_FC_REQUEST_FIQ	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2U)
+#define SMC_FC_GET_NEXT_IRQ	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3U)
+#define SMC_FC_FIQ_ENTER	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 4U)
+
+#define SMC_FC64_SET_FIQ_HANDLER SMC_FASTCALL64_NR(SMC_ENTITY_SECURE_MONITOR, 5U)
+#define SMC_FC64_GET_FIQ_REGS	SMC_FASTCALL64_NR (SMC_ENTITY_SECURE_MONITOR, 6U)
+
+#define SMC_FC_CPU_SUSPEND	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 7U)
+#define SMC_FC_CPU_RESUME	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 8U)
+
+#define SMC_FC_AARCH_SWITCH	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 9U)
+#define SMC_FC_GET_VERSION_STR	SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 10U)
+
+/* Trusted OS entity calls */
+#define SMC_YC_VIRTIO_GET_DESCR	  SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 20U)
+#define SMC_YC_VIRTIO_START	  SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 21U)
+#define SMC_YC_VIRTIO_STOP	  SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 22U)
+
+#define SMC_YC_VDEV_RESET	  SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 23U)
+#define SMC_YC_VDEV_KICK_VQ	  SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 24U)
+#define SMC_YC_SET_ROT_PARAMS	  SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 65535U)
+
+#endif /* SMCALL_H */
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
new file mode 100644
index 0000000..d6c092c
--- /dev/null
+++ b/services/spd/trusty/trusty.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#include "sm_err.h"
+#include "smcall.h"
+
+/* macro to check if Hypervisor is enabled in the HCR_EL2 register */
+#define HYP_ENABLE_FLAG		0x286001U
+
+/* length of Trusty's input parameters (in bytes) */
+#define TRUSTY_PARAMS_LEN_BYTES	(4096U * 2)
+
+struct trusty_stack {
+	uint8_t space[PLATFORM_STACK_SIZE] __aligned(16);
+	uint32_t end;
+};
+
+struct trusty_cpu_ctx {
+	cpu_context_t	cpu_ctx;
+	void		*saved_sp;
+	uint32_t	saved_security_state;
+	int32_t		fiq_handler_active;
+	uint64_t	fiq_handler_pc;
+	uint64_t	fiq_handler_cpsr;
+	uint64_t	fiq_handler_sp;
+	uint64_t	fiq_pc;
+	uint64_t	fiq_cpsr;
+	uint64_t	fiq_sp_el1;
+	gp_regs_t	fiq_gpregs;
+	struct trusty_stack	secure_stack;
+};
+
+struct smc_args {
+	uint64_t	r0;
+	uint64_t	r1;
+	uint64_t	r2;
+	uint64_t	r3;
+	uint64_t	r4;
+	uint64_t	r5;
+	uint64_t	r6;
+	uint64_t	r7;
+};
+
+static struct trusty_cpu_ctx trusty_cpu_ctx[PLATFORM_CORE_COUNT];
+
+struct smc_args trusty_init_context_stack(void **sp, void *new_stack);
+struct smc_args trusty_context_switch_helper(void **sp, void *smc_params);
+
+static uint32_t current_vmid;
+
+static struct trusty_cpu_ctx *get_trusty_ctx(void)
+{
+	return &trusty_cpu_ctx[plat_my_core_pos()];
+}
+
+static bool is_hypervisor_mode(void)
+{
+	uint64_t hcr = read_hcr();
+
+	return ((hcr & HYP_ENABLE_FLAG) != 0U) ? true : false;
+}
+
+static struct smc_args trusty_context_switch(uint32_t security_state, uint64_t r0,
+					 uint64_t r1, uint64_t r2, uint64_t r3)
+{
+	struct smc_args args, ret_args;
+	struct trusty_cpu_ctx *ctx = get_trusty_ctx();
+	struct trusty_cpu_ctx *ctx_smc;
+
+	assert(ctx->saved_security_state != security_state);
+
+	args.r7 = 0;
+	if (is_hypervisor_mode()) {
+		/* According to the ARM DEN0028A spec, VMID is stored in x7 */
+		ctx_smc = cm_get_context(NON_SECURE);
+		assert(ctx_smc != NULL);
+		args.r7 = SMC_GET_GP(ctx_smc, CTX_GPREG_X7);
+	}
+	/* r4, r5, r6 reserved for future use. */
+	args.r6 = 0;
+	args.r5 = 0;
+	args.r4 = 0;
+	args.r3 = r3;
+	args.r2 = r2;
+	args.r1 = r1;
+	args.r0 = r0;
+
+	/*
+	 * To avoid the additional overhead in PSCI flow, skip FP context
+	 * saving/restoring in case of CPU suspend and resume, assuming that
+	 * when it's needed the PSCI caller has preserved FP context before
+	 * going here.
+	 */
+	if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME)
+		fpregs_context_save(get_fpregs_ctx(cm_get_context(security_state)));
+	cm_el1_sysregs_context_save(security_state);
+
+	ctx->saved_security_state = security_state;
+	ret_args = trusty_context_switch_helper(&ctx->saved_sp, &args);
+
+	assert(ctx->saved_security_state == ((security_state == 0U) ? 1U : 0U));
+
+	cm_el1_sysregs_context_restore(security_state);
+	if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME)
+		fpregs_context_restore(get_fpregs_ctx(cm_get_context(security_state)));
+
+	cm_set_next_eret_context(security_state);
+
+	return ret_args;
+}
+
+static uint64_t trusty_fiq_handler(uint32_t id,
+				   uint32_t flags,
+				   void *handle,
+				   void *cookie)
+{
+	struct smc_args ret;
+	struct trusty_cpu_ctx *ctx = get_trusty_ctx();
+
+	assert(!is_caller_secure(flags));
+
+	ret = trusty_context_switch(NON_SECURE, SMC_FC_FIQ_ENTER, 0, 0, 0);
+	if (ret.r0 != 0U) {
+		SMC_RET0(handle);
+	}
+
+	if (ctx->fiq_handler_active != 0) {
+		INFO("%s: fiq handler already active\n", __func__);
+		SMC_RET0(handle);
+	}
+
+	ctx->fiq_handler_active = 1;
+	(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);
+
+	write_ctx_reg(get_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);
+}
+
+static uint64_t trusty_set_fiq_handler(void *handle, uint64_t cpu,
+			uint64_t handler, uint64_t stack)
+{
+	struct trusty_cpu_ctx *ctx;
+
+	if (cpu >= (uint64_t)PLATFORM_CORE_COUNT) {
+		ERROR("%s: cpu %lld >= %d\n", __func__, cpu, PLATFORM_CORE_COUNT);
+		return (uint64_t)SM_ERR_INVALID_PARAMETERS;
+	}
+
+	ctx = &trusty_cpu_ctx[cpu];
+	ctx->fiq_handler_pc = handler;
+	ctx->fiq_handler_cpsr = SMC_GET_EL3(handle, CTX_SPSR_EL3);
+	ctx->fiq_handler_sp = stack;
+
+	SMC_RET1(handle, 0);
+}
+
+static uint64_t trusty_get_fiq_regs(void *handle)
+{
+	struct trusty_cpu_ctx *ctx = get_trusty_ctx();
+	uint64_t sp_el0 = read_ctx_reg(&ctx->fiq_gpregs, CTX_GPREG_SP_EL0);
+
+	SMC_RET4(handle, ctx->fiq_pc, ctx->fiq_cpsr, sp_el0, ctx->fiq_sp_el1);
+}
+
+static uint64_t trusty_fiq_exit(void *handle, uint64_t x1, uint64_t x2, uint64_t x3)
+{
+	struct smc_args ret;
+	struct trusty_cpu_ctx *ctx = get_trusty_ctx();
+
+	if (ctx->fiq_handler_active == 0) {
+		NOTICE("%s: fiq handler not active\n", __func__);
+		SMC_RET1(handle, (uint64_t)SM_ERR_INVALID_PARAMETERS);
+	}
+
+	ret = trusty_context_switch(NON_SECURE, SMC_FC_FIQ_EXIT, 0, 0, 0);
+	if (ret.r0 != 1U) {
+		INFO("%s(%p) SMC_FC_FIQ_EXIT returned unexpected value, %lld\n",
+		       __func__, handle, ret.r0);
+	}
+
+	/*
+	 * Restore register state to state recorded on fiq entry.
+	 *
+	 * x0, sp_el1, pc and cpsr need to be restored because el1 cannot
+	 * restore them.
+	 *
+	 * x1-x4 and x8-x17 need to be restored here because smc_handler64
+	 * corrupts them (el1 code also restored them).
+	 */
+	(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);
+	cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_pc, (uint32_t)ctx->fiq_cpsr);
+
+	SMC_RET0(handle);
+}
+
+static uintptr_t trusty_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	struct smc_args ret;
+	uint32_t vmid = 0U;
+	entry_point_info_t *ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+
+	/*
+	 * Return success for SET_ROT_PARAMS if Trusty is not present, as
+	 * Verified Boot is not even supported and returning success here
+	 * would not compromise the boot process.
+	 */
+	if ((ep_info == NULL) && (smc_fid == SMC_YC_SET_ROT_PARAMS)) {
+		SMC_RET1(handle, 0);
+	} else if (ep_info == NULL) {
+		SMC_RET1(handle, SMC_UNK);
+	} else {
+		; /* do nothing */
+	}
+
+	if (is_caller_secure(flags)) {
+		if (smc_fid == SMC_YC_NS_RETURN) {
+			ret = trusty_context_switch(SECURE, x1, 0, 0, 0);
+			SMC_RET8(handle, ret.r0, ret.r1, ret.r2, ret.r3,
+				 ret.r4, ret.r5, ret.r6, ret.r7);
+		}
+		INFO("%s (0x%x, 0x%lx, 0x%lx, 0x%lx, 0x%lx, %p, %p, 0x%lx) \
+		     cpu %d, unknown smc\n",
+		     __func__, smc_fid, x1, x2, x3, x4, cookie, handle, flags,
+		     plat_my_core_pos());
+		SMC_RET1(handle, SMC_UNK);
+	} else {
+		switch (smc_fid) {
+		case SMC_FC64_SET_FIQ_HANDLER:
+			return trusty_set_fiq_handler(handle, x1, x2, x3);
+		case SMC_FC64_GET_FIQ_REGS:
+			return trusty_get_fiq_regs(handle);
+		case SMC_FC_FIQ_EXIT:
+			return trusty_fiq_exit(handle, x1, x2, x3);
+		default:
+			if (is_hypervisor_mode())
+				vmid = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+			if ((current_vmid != 0) && (current_vmid != vmid)) {
+				/* This message will cause SMC mechanism
+				 * abnormal in multi-guest environment.
+				 * Change it to WARN in case you need it.
+				 */
+				VERBOSE("Previous SMC not finished.\n");
+				SMC_RET1(handle, SM_ERR_BUSY);
+			}
+			current_vmid = vmid;
+			ret = trusty_context_switch(NON_SECURE, smc_fid, x1,
+				x2, x3);
+			current_vmid = 0;
+			SMC_RET1(handle, ret.r0);
+		}
+	}
+}
+
+static int32_t trusty_init(void)
+{
+	entry_point_info_t *ep_info;
+	struct smc_args zero_args = {0};
+	struct trusty_cpu_ctx *ctx = get_trusty_ctx();
+	uint32_t cpu = plat_my_core_pos();
+	uint64_t reg_width = GET_RW(read_ctx_reg(get_el3state_ctx(&ctx->cpu_ctx),
+			       CTX_SPSR_EL3));
+
+	/*
+	 * Get information about the Trusty image. Its absence is a critical
+	 * failure.
+	 */
+	ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	assert(ep_info != NULL);
+
+	fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE)));
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	cm_set_context(&ctx->cpu_ctx, SECURE);
+	cm_init_my_context(ep_info);
+
+	/*
+	 * Adjust secondary cpu entry point for 32 bit images to the
+	 * end of exception vectors
+	 */
+	if ((cpu != 0U) && (reg_width == MODE_RW_32)) {
+		INFO("trusty: cpu %d, adjust entry point to 0x%lx\n",
+		     cpu, ep_info->pc + (1U << 5));
+		cm_set_elr_el3(SECURE, ep_info->pc + (1U << 5));
+	}
+
+	cm_el1_sysregs_context_restore(SECURE);
+	fpregs_context_restore(get_fpregs_ctx(cm_get_context(SECURE)));
+	cm_set_next_eret_context(SECURE);
+
+	ctx->saved_security_state = ~0U; /* initial saved state is invalid */
+	(void)trusty_init_context_stack(&ctx->saved_sp, &ctx->secure_stack.end);
+
+	(void)trusty_context_switch_helper(&ctx->saved_sp, &zero_args);
+
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE)));
+	cm_set_next_eret_context(NON_SECURE);
+
+	return 1;
+}
+
+static void trusty_cpu_suspend(uint32_t off)
+{
+	struct smc_args ret;
+
+	ret = trusty_context_switch(NON_SECURE, SMC_FC_CPU_SUSPEND, off, 0, 0);
+	if (ret.r0 != 0U) {
+		INFO("%s: cpu %d, SMC_FC_CPU_SUSPEND returned unexpected value, %lld\n",
+		     __func__, plat_my_core_pos(), ret.r0);
+	}
+}
+
+static void trusty_cpu_resume(uint32_t on)
+{
+	struct smc_args ret;
+
+	ret = trusty_context_switch(NON_SECURE, SMC_FC_CPU_RESUME, on, 0, 0);
+	if (ret.r0 != 0U) {
+		INFO("%s: cpu %d, SMC_FC_CPU_RESUME returned unexpected value, %lld\n",
+		     __func__, plat_my_core_pos(), ret.r0);
+	}
+}
+
+static int32_t trusty_cpu_off_handler(u_register_t max_off_lvl)
+{
+	trusty_cpu_suspend(max_off_lvl);
+
+	return 0;
+}
+
+static void trusty_cpu_on_finish_handler(u_register_t max_off_lvl)
+{
+	struct trusty_cpu_ctx *ctx = get_trusty_ctx();
+
+	if (ctx->saved_sp == NULL) {
+		(void)trusty_init();
+	} else {
+		trusty_cpu_resume(max_off_lvl);
+	}
+}
+
+static void trusty_cpu_suspend_handler(u_register_t max_off_lvl)
+{
+	trusty_cpu_suspend(max_off_lvl);
+}
+
+static void trusty_cpu_suspend_finish_handler(u_register_t max_off_lvl)
+{
+	trusty_cpu_resume(max_off_lvl);
+}
+
+static const spd_pm_ops_t trusty_pm = {
+	.svc_off = trusty_cpu_off_handler,
+	.svc_suspend = trusty_cpu_suspend_handler,
+	.svc_on_finish = trusty_cpu_on_finish_handler,
+	.svc_suspend_finish = trusty_cpu_suspend_finish_handler,
+};
+
+void plat_trusty_set_boot_args(aapcs64_params_t *args);
+
+#ifdef TSP_SEC_MEM_SIZE
+#pragma weak plat_trusty_set_boot_args
+void plat_trusty_set_boot_args(aapcs64_params_t *args)
+{
+	args->arg0 = TSP_SEC_MEM_SIZE;
+}
+#endif
+
+static int32_t trusty_setup(void)
+{
+	entry_point_info_t *ep_info;
+	uint32_t instr;
+	uint32_t flags;
+	int32_t ret;
+	bool aarch32 = false;
+
+	/* Get trusty's entry point info */
+	ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	if (ep_info == NULL) {
+		INFO("Trusty image missing.\n");
+		return -1;
+	}
+
+	/* memmap first page of trusty's code memory before peeking */
+	ret = mmap_add_dynamic_region(ep_info->pc, /* PA */
+			ep_info->pc, /* VA */
+			PAGE_SIZE, /* size */
+			MT_SECURE | MT_RW_DATA); /* attrs */
+	assert(ret == 0);
+
+	/* peek into trusty's code to see if we have a 32-bit or 64-bit image */
+	instr = *(uint32_t *)ep_info->pc;
+
+	if (instr >> 24 == 0xeaU) {
+		INFO("trusty: Found 32 bit image\n");
+		aarch32 = true;
+	} else if (instr >> 8 == 0xd53810U || instr >> 16 == 0x9400U) {
+		INFO("trusty: Found 64 bit image\n");
+	} else {
+		ERROR("trusty: Found unknown image, 0x%x\n", instr);
+		return -1;
+	}
+
+	/* unmap trusty's memory page */
+	(void)mmap_remove_dynamic_region(ep_info->pc, PAGE_SIZE);
+
+	SET_PARAM_HEAD(ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE);
+	if (!aarch32)
+		ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS);
+	else
+		ep_info->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
+					    SPSR_E_LITTLE,
+					    DAIF_FIQ_BIT |
+					    DAIF_IRQ_BIT |
+					    DAIF_ABT_BIT);
+	(void)memset(&ep_info->args, 0, sizeof(ep_info->args));
+	plat_trusty_set_boot_args(&ep_info->args);
+
+	/* register init handler */
+	bl31_register_bl32_init(trusty_init);
+
+	/* register power management hooks */
+	psci_register_spd_pm_hook(&trusty_pm);
+
+	/* register interrupt handler */
+	flags = 0;
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	ret = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+					      trusty_fiq_handler,
+					      flags);
+	if (ret != 0) {
+		ERROR("trusty: failed to register fiq handler, ret = %d\n", ret);
+	}
+
+	if (aarch32) {
+		entry_point_info_t *ns_ep_info;
+		uint32_t spsr;
+
+		ns_ep_info = bl31_plat_get_next_image_ep_info(NON_SECURE);
+		if (ns_ep_info == NULL) {
+			NOTICE("Trusty: non-secure image missing.\n");
+			return -1;
+		}
+		spsr = ns_ep_info->spsr;
+		if (GET_RW(spsr) == MODE_RW_64 && GET_EL(spsr) == MODE_EL2) {
+			spsr &= ~(MODE_EL_MASK << MODE_EL_SHIFT);
+			spsr |= MODE_EL1 << MODE_EL_SHIFT;
+		}
+		if (GET_RW(spsr) == MODE_RW_32 && GET_M32(spsr) == MODE32_hyp) {
+			spsr &= ~(MODE32_MASK << MODE32_SHIFT);
+			spsr |= MODE32_svc << MODE32_SHIFT;
+		}
+		if (spsr != ns_ep_info->spsr) {
+			NOTICE("Trusty: Switch bl33 from EL2 to EL1 (spsr 0x%x -> 0x%x)\n",
+			       ns_ep_info->spsr, spsr);
+			ns_ep_info->spsr = spsr;
+		}
+	}
+
+	return 0;
+}
+
+/* Define a SPD runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	trusty_fast,
+
+	OEN_TOS_START,
+	SMC_ENTITY_SECURE_MONITOR,
+	SMC_TYPE_FAST,
+	trusty_setup,
+	trusty_smc_handler
+);
+
+/* Define a SPD runtime service descriptor for yielding SMC calls */
+DECLARE_RT_SVC(
+	trusty_std,
+
+	OEN_TAP_START,
+	SMC_ENTITY_SECURE_MONITOR,
+	SMC_TYPE_YIELD,
+	NULL,
+	trusty_smc_handler
+);
diff --git a/services/spd/trusty/trusty.mk b/services/spd/trusty/trusty.mk
new file mode 100644
index 0000000..43b80bb
--- /dev/null
+++ b/services/spd/trusty/trusty.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+SPD_INCLUDES		:=
+
+SPD_SOURCES		:=	services/spd/trusty/trusty.c		\
+				services/spd/trusty/trusty_helpers.S
+
+ifeq (${TRUSTY_SPD_WITH_GENERIC_SERVICES},1)
+SPD_SOURCES		+=	services/spd/trusty/generic-arm64-smcall.c
+endif
+
+NEED_BL32		:=	yes
+
+CTX_INCLUDE_FPREGS	:=	1
diff --git a/services/spd/trusty/trusty_helpers.S b/services/spd/trusty/trusty_helpers.S
new file mode 100644
index 0000000..da5cb57
--- /dev/null
+++ b/services/spd/trusty/trusty_helpers.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+.macro push ra, rb, sp=sp
+	stp \ra, \rb, [\sp,#-16]!
+.endm
+
+.macro pop ra, rb, sp=sp
+	ldp \ra, \rb, [\sp], #16
+.endm
+
+	.global trusty_context_switch_helper
+func trusty_context_switch_helper
+	push	x8, xzr
+	push	x19, x20
+	push	x21, x22
+	push	x23, x24
+	push	x25, x26
+	push	x27, x28
+	push	x29, x30
+
+	mov	x9, sp
+	ldr	x10, [x0]
+	mov	sp, x10
+	str	x9, [x0]
+
+	pop	x29, x30
+	pop	x27, x28
+	pop	x25, x26
+	pop	x23, x24
+	pop	x21, x22
+	pop	x19, x20
+	pop	x8, xzr
+
+        ldr     x2, [x1]
+        ldr     x3, [x1, #0x08]
+        ldr     x4, [x1, #0x10]
+        ldr     x5, [x1, #0x18]
+        ldr     x6, [x1, #0x20]
+        ldr     x7, [x1, #0x28]
+        ldr     x10, [x1, #0x30]
+        ldr     x11, [x1, #0x38]
+
+        stp     x2, x3, [x8]
+        stp     x4, x5, [x8, #16]
+        stp     x6, x7, [x8, #32]
+        stp     x10, x11, [x8, #48]
+
+	ret
+endfunc trusty_context_switch_helper
+
+	.global trusty_init_context_stack
+func trusty_init_context_stack
+	push	x8, xzr, x1
+	push	xzr, xzr, x1
+	push	xzr, xzr, x1
+	push	xzr, xzr, x1
+	push	xzr, xzr, x1
+	push	xzr, xzr, x1
+	adr	x9, el3_exit
+	push	xzr, x9, x1
+	str	x1, [x0]
+	ret
+endfunc trusty_init_context_stack
diff --git a/services/spd/tspd/tspd.mk b/services/spd/tspd/tspd.mk
new file mode 100644
index 0000000..bda8338
--- /dev/null
+++ b/services/spd/tspd/tspd.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TSPD_DIR		:=	services/spd/tspd
+
+ifeq (${ERROR_DEPRECATED},0)
+SPD_INCLUDES		:=	-Iinclude/bl32/tsp
+endif
+
+SPD_SOURCES		:=	services/spd/tspd/tspd_common.c		\
+				services/spd/tspd/tspd_helpers.S	\
+				services/spd/tspd/tspd_main.c		\
+				services/spd/tspd/tspd_pm.c
+
+# This dispatcher is paired with a Test Secure Payload source and we intend to
+# build the Test Secure Payload along with this dispatcher.
+#
+# In cases where an associated Secure Payload lies outside this build
+# system/source tree, the the dispatcher Makefile can either invoke an external
+# build command or assume it pre-built
+
+BL32_ROOT		:=	bl32/tsp
+
+# Include SP's Makefile. The assumption is that the TSP's build system is
+# compatible with that of Trusted Firmware, and it'll add and populate necessary
+# build targets and variables
+include ${BL32_ROOT}/tsp.mk
+
+# Let the top-level Makefile know that we intend to build the SP from source
+NEED_BL32		:=	yes
+
+# Flag used to enable routing of non-secure interrupts to EL3 when they are
+# generated while the code is executing in S-EL1/0.
+TSP_NS_INTR_ASYNC_PREEMPT	:=	0
+
+ifeq ($(EL3_EXCEPTION_HANDLING),1)
+ifeq ($(TSP_NS_INTR_ASYNC_PREEMPT),0)
+$(error When EL3_EXCEPTION_HANDLING=1, TSP_NS_INTR_ASYNC_PREEMPT must also be 1)
+endif
+endif
+
+$(eval $(call assert_boolean,TSP_NS_INTR_ASYNC_PREEMPT))
+$(eval $(call add_define,TSP_NS_INTR_ASYNC_PREEMPT))
diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c
new file mode 100644
index 0000000..063fd01
--- /dev/null
+++ b/services/spd/tspd/tspd_common.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/utils.h>
+
+#include "tspd_private.h"
+
+/*******************************************************************************
+ * Given a secure payload entrypoint info pointer, entry point PC, register
+ * width, cpu id & pointer to a context data structure, this function will
+ * initialize tsp context and entry point info for the secure payload
+ ******************************************************************************/
+void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point,
+				uint32_t rw,
+				uint64_t pc,
+				tsp_context_t *tsp_ctx)
+{
+	uint32_t ep_attr;
+
+	/* Passing a NULL context is a critical programming error */
+	assert(tsp_ctx);
+	assert(tsp_entry_point);
+	assert(pc);
+
+	/*
+	 * We support AArch64 TSP for now.
+	 * TODO: Add support for AArch32 TSP
+	 */
+	assert(rw == TSP_AARCH64);
+
+	/* Associate this context with the cpu specified */
+	tsp_ctx->mpidr = read_mpidr_el1();
+	tsp_ctx->state = 0;
+	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
+	clr_yield_smc_active_flag(tsp_ctx->state);
+
+	cm_set_context(&tsp_ctx->cpu_ctx, SECURE);
+
+	/* initialise an entrypoint to set up the CPU context */
+	ep_attr = SECURE | EP_ST_ENABLE;
+	if (read_sctlr_el3() & SCTLR_EE_BIT)
+		ep_attr |= EP_EE_BIG;
+	SET_PARAM_HEAD(tsp_entry_point, PARAM_EP, VERSION_1, ep_attr);
+
+	tsp_entry_point->pc = pc;
+	tsp_entry_point->spsr = SPSR_64(MODE_EL1,
+					MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS);
+	zeromem(&tsp_entry_point->args, sizeof(tsp_entry_point->args));
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and:
+ * 1. Applies the S-EL1 system register context from tsp_ctx->cpu_ctx.
+ * 2. Saves the current C runtime state (callee saved registers) on the stack
+ *    frame and saves a reference to this state.
+ * 3. Calls el3_exit() so that the EL3 system and general purpose registers
+ *    from the tsp_ctx->cpu_ctx are used to enter the secure payload image.
+ ******************************************************************************/
+uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx)
+{
+	uint64_t rc;
+
+	assert(tsp_ctx != NULL);
+	assert(tsp_ctx->c_rt_ctx == 0);
+
+	/* Apply the Secure EL1 system register context and switch to it */
+	assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx);
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+
+	rc = tspd_enter_sp(&tsp_ctx->c_rt_ctx);
+#if ENABLE_ASSERTIONS
+	tsp_ctx->c_rt_ctx = 0;
+#endif
+
+	return rc;
+}
+
+
+/*******************************************************************************
+ * This function takes an SP context pointer and:
+ * 1. Saves the S-EL1 system register context tp tsp_ctx->cpu_ctx.
+ * 2. Restores the current C runtime state (callee saved registers) from the
+ *    stack frame using the reference to this state saved in tspd_enter_sp().
+ * 3. It does not need to save any general purpose or EL3 system register state
+ *    as the generic smc entry routine should have saved those.
+ ******************************************************************************/
+void tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret)
+{
+	assert(tsp_ctx != NULL);
+	/* Save the Secure EL1 system register context */
+	assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx);
+	cm_el1_sysregs_context_save(SECURE);
+
+	assert(tsp_ctx->c_rt_ctx != 0);
+	tspd_exit_sp(tsp_ctx->c_rt_ctx, ret);
+
+	/* Should never reach here */
+	assert(0);
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and abort any preempted SMC
+ * request.
+ * Return 1 if there was a preempted SMC request, 0 otherwise.
+ ******************************************************************************/
+int tspd_abort_preempted_smc(tsp_context_t *tsp_ctx)
+{
+	if (!get_yield_smc_active_flag(tsp_ctx->state))
+		return 0;
+
+	/* Abort any preempted SMC request */
+	clr_yield_smc_active_flag(tsp_ctx->state);
+
+	/*
+	 * Arrange for an entry into the test secure payload. It will
+	 * be returned via TSP_ABORT_DONE case in tspd_smc_handler.
+	 */
+	cm_set_elr_el3(SECURE,
+		       (uint64_t) &tsp_vectors->abort_yield_smc_entry);
+	uint64_t rc = tspd_synchronous_sp_entry(tsp_ctx);
+
+	if (rc != 0)
+		panic();
+
+	return 1;
+}
+
diff --git a/services/spd/tspd/tspd_helpers.S b/services/spd/tspd/tspd_helpers.S
new file mode 100644
index 0000000..f15d66b
--- /dev/null
+++ b/services/spd/tspd/tspd_helpers.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "tspd_private.h"
+
+	.global	tspd_enter_sp
+	/* ---------------------------------------------
+	 * This function is called with SP_EL0 as stack.
+	 * Here we stash our EL3 callee-saved registers
+	 * on to the stack as a part of saving the C
+	 * runtime and enter the secure payload.
+	 * 'x0' contains a pointer to the memory where
+	 * the address of the C runtime context is to be
+	 * saved.
+	 * ---------------------------------------------
+	 */
+func tspd_enter_sp
+	/* Make space for the registers that we're going to save */
+	mov	x3, sp
+	str	x3, [x0, #0]
+	sub	sp, sp, #TSPD_C_RT_CTX_SIZE
+
+	/* Save callee-saved registers on to the stack */
+	stp	x19, x20, [sp, #TSPD_C_RT_CTX_X19]
+	stp	x21, x22, [sp, #TSPD_C_RT_CTX_X21]
+	stp	x23, x24, [sp, #TSPD_C_RT_CTX_X23]
+	stp	x25, x26, [sp, #TSPD_C_RT_CTX_X25]
+	stp	x27, x28, [sp, #TSPD_C_RT_CTX_X27]
+	stp	x29, x30, [sp, #TSPD_C_RT_CTX_X29]
+
+	/* ---------------------------------------------
+	 * Everything is setup now. el3_exit() will
+	 * use the secure context to restore to the
+	 * general purpose and EL3 system registers to
+	 * ERET into the secure payload.
+	 * ---------------------------------------------
+	 */
+	b	el3_exit
+endfunc tspd_enter_sp
+
+	/* ---------------------------------------------
+	 * This function is called 'x0' pointing to a C
+	 * runtime context saved in tspd_enter_sp().  It
+	 * restores the saved registers and jumps to
+	 * that runtime with 'x0' as the new sp. This
+	 * destroys the C runtime context that had been
+	 * built on the stack below the saved context by
+	 * the caller. Later the second parameter 'x1'
+	 * is passed as return value to the caller
+	 * ---------------------------------------------
+	 */
+	.global tspd_exit_sp
+func tspd_exit_sp
+	/* Restore the previous stack */
+	mov	sp, x0
+
+	/* Restore callee-saved registers on to the stack */
+	ldp	x19, x20, [x0, #(TSPD_C_RT_CTX_X19 - TSPD_C_RT_CTX_SIZE)]
+	ldp	x21, x22, [x0, #(TSPD_C_RT_CTX_X21 - TSPD_C_RT_CTX_SIZE)]
+	ldp	x23, x24, [x0, #(TSPD_C_RT_CTX_X23 - TSPD_C_RT_CTX_SIZE)]
+	ldp	x25, x26, [x0, #(TSPD_C_RT_CTX_X25 - TSPD_C_RT_CTX_SIZE)]
+	ldp	x27, x28, [x0, #(TSPD_C_RT_CTX_X27 - TSPD_C_RT_CTX_SIZE)]
+	ldp	x29, x30, [x0, #(TSPD_C_RT_CTX_X29 - TSPD_C_RT_CTX_SIZE)]
+
+	/* ---------------------------------------------
+	 * This should take us back to the instruction
+	 * after the call to the last tspd_enter_sp().
+	 * Place the second parameter to x0 so that the
+	 * caller will see it as a return value from the
+	 * original entry call
+	 * ---------------------------------------------
+	 */
+	mov	x0, x1
+	ret
+endfunc tspd_exit_sp
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
new file mode 100644
index 0000000..f206724
--- /dev/null
+++ b/services/spd/tspd/tspd_main.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+/*******************************************************************************
+ * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a
+ * plug-in component to the Secure Monitor, registered as a runtime service. The
+ * SPD is expected to be a functional extension of the Secure Payload (SP) that
+ * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting
+ * the Trusted OS/Applications range to the dispatcher. The SPD will either
+ * handle the request locally or delegate it to the Secure Payload. It is also
+ * responsible for initialising and maintaining communication with the SP.
+ ******************************************************************************/
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+#include <tools_share/uuid.h>
+
+#include "tspd_private.h"
+
+/*******************************************************************************
+ * Address of the entrypoint vector table in the Secure Payload. It is
+ * initialised once on the primary core after a cold boot.
+ ******************************************************************************/
+tsp_vectors_t *tsp_vectors;
+
+/*******************************************************************************
+ * Array to keep track of per-cpu Secure Payload state
+ ******************************************************************************/
+tsp_context_t tspd_sp_context[TSPD_CORE_COUNT];
+
+
+/* TSP UID */
+DEFINE_SVC_UUID2(tsp_uuid,
+	0xa056305b, 0x9132, 0x7b42, 0x98, 0x11,
+	0x71, 0x68, 0xca, 0x50, 0xf3, 0xfa);
+
+int32_t tspd_init(void);
+
+/*
+ * This helper function handles Secure EL1 preemption. The preemption could be
+ * due Non Secure interrupts or EL3 interrupts. In both the cases we context
+ * switch to the normal world and in case of EL3 interrupts, it will again be
+ * routed to EL3 which will get handled at the exception vectors.
+ */
+uint64_t tspd_handle_sp_preemption(void *handle)
+{
+	cpu_context_t *ns_cpu_context;
+
+	assert(handle == cm_get_context(SECURE));
+	cm_el1_sysregs_context_save(SECURE);
+	/* Get a reference to the non-secure context */
+	ns_cpu_context = cm_get_context(NON_SECURE);
+	assert(ns_cpu_context);
+
+	/*
+	 * To allow Secure EL1 interrupt handler to re-enter TSP while TSP
+	 * is preempted, the secure system register context which will get
+	 * overwritten must be additionally saved. This is currently done
+	 * by the TSPD S-EL1 interrupt handler.
+	 */
+
+	/*
+	 * Restore non-secure state.
+	 */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_set_next_eret_context(NON_SECURE);
+
+	/*
+	 * The TSP was preempted during execution of a Yielding SMC Call.
+	 * Return back to the normal world with SMC_PREEMPTED as error
+	 * code in x0.
+	 */
+	SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
+}
+
+/*******************************************************************************
+ * This function is the handler registered for S-EL1 interrupts by the TSPD. It
+ * validates the interrupt and upon success arranges entry into the TSP at
+ * 'tsp_sel1_intr_entry()' for handling the interrupt.
+ ******************************************************************************/
+static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
+					    uint32_t flags,
+					    void *handle,
+					    void *cookie)
+{
+	uint32_t linear_id;
+	tsp_context_t *tsp_ctx;
+
+	/* Check the security state when the exception was generated */
+	assert(get_interrupt_src_ss(flags) == NON_SECURE);
+
+	/* Sanity check the pointer to this cpu's context */
+	assert(handle == cm_get_context(NON_SECURE));
+
+	/* Save the non-secure context before entering the TSP */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	/* Get a reference to this cpu's TSP context */
+	linear_id = plat_my_core_pos();
+	tsp_ctx = &tspd_sp_context[linear_id];
+	assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE));
+
+	/*
+	 * Determine if the TSP was previously preempted. Its last known
+	 * context has to be preserved in this case.
+	 * The TSP should return control to the TSPD after handling this
+	 * S-EL1 interrupt. Preserve essential EL3 context to allow entry into
+	 * the TSP at the S-EL1 interrupt entry point using the 'cpu_context'
+	 * structure. There is no need to save the secure system register
+	 * context since the TSP is supposed to preserve it during S-EL1
+	 * interrupt handling.
+	 */
+	if (get_yield_smc_active_flag(tsp_ctx->state)) {
+		tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
+						      CTX_SPSR_EL3);
+		tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
+						     CTX_ELR_EL3);
+#if TSP_NS_INTR_ASYNC_PREEMPT
+		/*Need to save the previously interrupted secure context */
+		memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE);
+#endif
+	}
+
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry,
+		    SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
+
+	cm_set_next_eret_context(SECURE);
+
+	/*
+	 * Tell the TSP that it has to handle a S-EL1 interrupt synchronously.
+	 * Also the instruction in normal world where the interrupt was
+	 * generated is passed for debugging purposes. It is safe to retrieve
+	 * this address from ELR_EL3 as the secure context will not take effect
+	 * until el3_exit().
+	 */
+	SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3());
+}
+
+#if TSP_NS_INTR_ASYNC_PREEMPT
+/*******************************************************************************
+ * This function is the handler registered for Non secure interrupts by the
+ * TSPD. It validates the interrupt and upon success arranges entry into the
+ * normal world for handling the interrupt.
+ ******************************************************************************/
+static uint64_t tspd_ns_interrupt_handler(uint32_t id,
+					    uint32_t flags,
+					    void *handle,
+					    void *cookie)
+{
+	/* Check the security state when the exception was generated */
+	assert(get_interrupt_src_ss(flags) == SECURE);
+
+	/*
+	 * Disable the routing of NS interrupts from secure world to EL3 while
+	 * interrupted on this core.
+	 */
+	disable_intr_rm_local(INTR_TYPE_NS, SECURE);
+
+	return tspd_handle_sp_preemption(handle);
+}
+#endif
+
+/*******************************************************************************
+ * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
+ * (aarch32/aarch64) if not already known and initialises the context for entry
+ * into the SP for its initialisation.
+ ******************************************************************************/
+static int32_t tspd_setup(void)
+{
+	entry_point_info_t *tsp_ep_info;
+	uint32_t linear_id;
+
+	linear_id = plat_my_core_pos();
+
+	/*
+	 * Get information about the Secure Payload (BL32) image. Its
+	 * absence is a critical failure.  TODO: Add support to
+	 * conditionally include the SPD service
+	 */
+	tsp_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	if (!tsp_ep_info) {
+		WARN("No TSP provided by BL2 boot loader, Booting device"
+			" without TSP initialization. SMC`s destined for TSP"
+			" will return SMC_UNK\n");
+		return 1;
+	}
+
+	/*
+	 * If there's no valid entry point for SP, we return a non-zero value
+	 * signalling failure initializing the service. We bail out without
+	 * registering any handlers
+	 */
+	if (!tsp_ep_info->pc)
+		return 1;
+
+	/*
+	 * We could inspect the SP image and determine its execution
+	 * state i.e whether AArch32 or AArch64. Assuming it's AArch64
+	 * for the time being.
+	 */
+	tspd_init_tsp_ep_state(tsp_ep_info,
+				TSP_AARCH64,
+				tsp_ep_info->pc,
+				&tspd_sp_context[linear_id]);
+
+#if TSP_INIT_ASYNC
+	bl31_set_next_image_type(SECURE);
+#else
+	/*
+	 * All TSPD initialization done. Now register our init function with
+	 * BL31 for deferred invocation
+	 */
+	bl31_register_bl32_init(&tspd_init);
+#endif
+	return 0;
+}
+
+/*******************************************************************************
+ * This function passes control to the Secure Payload image (BL32) for the first
+ * time on the primary cpu after a cold boot. It assumes that a valid secure
+ * context has already been created by tspd_setup() which can be directly used.
+ * It also assumes that a valid non-secure context has been initialised by PSCI
+ * so it does not need to save and restore any non-secure state. This function
+ * performs a synchronous entry into the Secure payload. The SP passes control
+ * back to this routine through a SMC.
+ ******************************************************************************/
+int32_t tspd_init(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+	entry_point_info_t *tsp_entry_point;
+	uint64_t rc;
+
+	/*
+	 * Get information about the Secure Payload (BL32) image. Its
+	 * absence is a critical failure.
+	 */
+	tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
+	assert(tsp_entry_point);
+
+	cm_init_my_context(tsp_entry_point);
+
+	/*
+	 * Arrange for an entry into the test secure payload. It will be
+	 * returned via TSP_ENTRY_DONE case
+	 */
+	rc = tspd_synchronous_sp_entry(tsp_ctx);
+	assert(rc != 0);
+
+	return rc;
+}
+
+
+/*******************************************************************************
+ * This function is responsible for handling all SMCs in the Trusted OS/App
+ * range from the non-secure state as defined in the SMC Calling Convention
+ * Document. It is also responsible for communicating with the Secure payload
+ * to delegate work and return results back to the non-secure state. Lastly it
+ * will also return any information that the secure payload needs to do the
+ * work assigned to it.
+ ******************************************************************************/
+static uintptr_t tspd_smc_handler(uint32_t smc_fid,
+			 u_register_t x1,
+			 u_register_t x2,
+			 u_register_t x3,
+			 u_register_t x4,
+			 void *cookie,
+			 void *handle,
+			 u_register_t flags)
+{
+	cpu_context_t *ns_cpu_context;
+	uint32_t linear_id = plat_my_core_pos(), ns;
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+	uint64_t rc;
+#if TSP_INIT_ASYNC
+	entry_point_info_t *next_image_info;
+#endif
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+
+	switch (smc_fid) {
+
+	/*
+	 * This function ID is used by TSP to indicate that it was
+	 * preempted by a normal world IRQ.
+	 *
+	 */
+	case TSP_PREEMPTED:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		return tspd_handle_sp_preemption(handle);
+
+	/*
+	 * This function ID is used only by the TSP to indicate that it has
+	 * finished handling a S-EL1 interrupt or was preempted by a higher
+	 * priority pending EL3 interrupt. Execution should resume
+	 * in the normal world.
+	 */
+	case TSP_HANDLED_S_EL1_INTR:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		assert(handle == cm_get_context(SECURE));
+
+		/*
+		 * Restore the relevant EL3 state which saved to service
+		 * this SMC.
+		 */
+		if (get_yield_smc_active_flag(tsp_ctx->state)) {
+			SMC_SET_EL3(&tsp_ctx->cpu_ctx,
+				    CTX_SPSR_EL3,
+				    tsp_ctx->saved_spsr_el3);
+			SMC_SET_EL3(&tsp_ctx->cpu_ctx,
+				    CTX_ELR_EL3,
+				    tsp_ctx->saved_elr_el3);
+#if TSP_NS_INTR_ASYNC_PREEMPT
+			/*
+			 * Need to restore the previously interrupted
+			 * secure context.
+			 */
+			memcpy(&tsp_ctx->cpu_ctx, &tsp_ctx->sp_ctx,
+				TSPD_SP_CTX_SIZE);
+#endif
+		}
+
+		/* Get a reference to the non-secure context */
+		ns_cpu_context = cm_get_context(NON_SECURE);
+		assert(ns_cpu_context);
+
+		/*
+		 * Restore non-secure state. There is no need to save the
+		 * secure system register context since the TSP was supposed
+		 * to preserve it during S-EL1 interrupt handling.
+		 */
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+
+		SMC_RET0((uint64_t) ns_cpu_context);
+
+	/*
+	 * This function ID is used only by the SP to indicate it has
+	 * finished initialising itself after a cold boot
+	 */
+	case TSP_ENTRY_DONE:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * Stash the SP entry points information. This is done
+		 * only once on the primary cpu
+		 */
+		assert(tsp_vectors == NULL);
+		tsp_vectors = (tsp_vectors_t *) x1;
+
+		if (tsp_vectors) {
+			set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
+
+			/*
+			 * TSP has been successfully initialized. Register power
+			 * management hooks with PSCI
+			 */
+			psci_register_spd_pm_hook(&tspd_pm);
+
+			/*
+			 * Register an interrupt handler for S-EL1 interrupts
+			 * when generated during code executing in the
+			 * non-secure state.
+			 */
+			flags = 0;
+			set_interrupt_rm_flag(flags, NON_SECURE);
+			rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+						tspd_sel1_interrupt_handler,
+						flags);
+			if (rc)
+				panic();
+
+#if TSP_NS_INTR_ASYNC_PREEMPT
+			/*
+			 * Register an interrupt handler for NS interrupts when
+			 * generated during code executing in secure state are
+			 * routed to EL3.
+			 */
+			flags = 0;
+			set_interrupt_rm_flag(flags, SECURE);
+
+			rc = register_interrupt_type_handler(INTR_TYPE_NS,
+						tspd_ns_interrupt_handler,
+						flags);
+			if (rc)
+				panic();
+
+			/*
+			 * Disable the NS interrupt locally.
+			 */
+			disable_intr_rm_local(INTR_TYPE_NS, SECURE);
+#endif
+		}
+
+
+#if TSP_INIT_ASYNC
+		/* Save the Secure EL1 system register context */
+		assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx);
+		cm_el1_sysregs_context_save(SECURE);
+
+		/* Program EL3 registers to enable entry into the next EL */
+		next_image_info = bl31_plat_get_next_image_ep_info(NON_SECURE);
+		assert(next_image_info);
+		assert(NON_SECURE ==
+				GET_SECURITY_STATE(next_image_info->h.attr));
+
+		cm_init_my_context(next_image_info);
+		cm_prepare_el3_exit(NON_SECURE);
+		SMC_RET0(cm_get_context(NON_SECURE));
+#else
+		/*
+		 * SP reports completion. The SPD must have initiated
+		 * the original request through a synchronous entry
+		 * into the SP. Jump back to the original C runtime
+		 * context.
+		 */
+		tspd_synchronous_sp_exit(tsp_ctx, x1);
+		break;
+#endif
+	/*
+	 * This function ID is used only by the SP to indicate it has finished
+	 * aborting a preempted Yielding SMC Call.
+	 */
+	case TSP_ABORT_DONE:
+
+	/*
+	 * These function IDs are used only by the SP to indicate it has
+	 * finished:
+	 * 1. turning itself on in response to an earlier psci
+	 *    cpu_on request
+	 * 2. resuming itself after an earlier psci cpu_suspend
+	 *    request.
+	 */
+	case TSP_ON_DONE:
+	case TSP_RESUME_DONE:
+
+	/*
+	 * These function IDs are used only by the SP to indicate it has
+	 * finished:
+	 * 1. suspending itself after an earlier psci cpu_suspend
+	 *    request.
+	 * 2. turning itself off in response to an earlier psci
+	 *    cpu_off request.
+	 */
+	case TSP_OFF_DONE:
+	case TSP_SUSPEND_DONE:
+	case TSP_SYSTEM_OFF_DONE:
+	case TSP_SYSTEM_RESET_DONE:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		/*
+		 * SP reports completion. The SPD must have initiated the
+		 * original request through a synchronous entry into the SP.
+		 * Jump back to the original C runtime context, and pass x1 as
+		 * return value to the caller
+		 */
+		tspd_synchronous_sp_exit(tsp_ctx, x1);
+		break;
+
+		/*
+		 * Request from non-secure client to perform an
+		 * arithmetic operation or response from secure
+		 * payload to an earlier request.
+		 */
+	case TSP_FAST_FID(TSP_ADD):
+	case TSP_FAST_FID(TSP_SUB):
+	case TSP_FAST_FID(TSP_MUL):
+	case TSP_FAST_FID(TSP_DIV):
+
+	case TSP_YIELD_FID(TSP_ADD):
+	case TSP_YIELD_FID(TSP_SUB):
+	case TSP_YIELD_FID(TSP_MUL):
+	case TSP_YIELD_FID(TSP_DIV):
+		if (ns) {
+			/*
+			 * This is a fresh request from the non-secure client.
+			 * The parameters are in x1 and x2. Figure out which
+			 * registers need to be preserved, save the non-secure
+			 * state and send the request to the secure payload.
+			 */
+			assert(handle == cm_get_context(NON_SECURE));
+
+			/* Check if we are already preempted */
+			if (get_yield_smc_active_flag(tsp_ctx->state))
+				SMC_RET1(handle, SMC_UNK);
+
+			cm_el1_sysregs_context_save(NON_SECURE);
+
+			/* Save x1 and x2 for use by TSP_GET_ARGS call below */
+			store_tsp_args(tsp_ctx, x1, x2);
+
+			/*
+			 * We are done stashing the non-secure context. Ask the
+			 * secure payload to do the work now.
+			 */
+
+			/*
+			 * Verify if there is a valid context to use, copy the
+			 * operation type and parameters to the secure context
+			 * and jump to the fast smc entry point in the secure
+			 * payload. Entry into S-EL1 will take place upon exit
+			 * from this function.
+			 */
+			assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE));
+
+			/* Set appropriate entry for SMC.
+			 * We expect the TSP to manage the PSTATE.I and PSTATE.F
+			 * flags as appropriate.
+			 */
+			if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) {
+				cm_set_elr_el3(SECURE, (uint64_t)
+						&tsp_vectors->fast_smc_entry);
+			} else {
+				set_yield_smc_active_flag(tsp_ctx->state);
+				cm_set_elr_el3(SECURE, (uint64_t)
+						&tsp_vectors->yield_smc_entry);
+#if TSP_NS_INTR_ASYNC_PREEMPT
+				/*
+				 * Enable the routing of NS interrupts to EL3
+				 * during processing of a Yielding SMC Call on
+				 * this core.
+				 */
+				enable_intr_rm_local(INTR_TYPE_NS, SECURE);
+#endif
+
+#if EL3_EXCEPTION_HANDLING
+				/*
+				 * With EL3 exception handling, while an SMC is
+				 * being processed, Non-secure interrupts can't
+				 * preempt Secure execution. However, for
+				 * yielding SMCs, we want preemption to happen;
+				 * so explicitly allow NS preemption in this
+				 * case, and supply the preemption return code
+				 * for TSP.
+				 */
+				ehf_allow_ns_preemption(TSP_PREEMPTED);
+#endif
+			}
+
+			cm_el1_sysregs_context_restore(SECURE);
+			cm_set_next_eret_context(SECURE);
+			SMC_RET3(&tsp_ctx->cpu_ctx, smc_fid, x1, x2);
+		} else {
+			/*
+			 * This is the result from the secure client of an
+			 * earlier request. The results are in x1-x3. Copy it
+			 * into the non-secure context, save the secure state
+			 * and return to the non-secure state.
+			 */
+			assert(handle == cm_get_context(SECURE));
+			cm_el1_sysregs_context_save(SECURE);
+
+			/* Get a reference to the non-secure context */
+			ns_cpu_context = cm_get_context(NON_SECURE);
+			assert(ns_cpu_context);
+
+			/* Restore non-secure state */
+			cm_el1_sysregs_context_restore(NON_SECURE);
+			cm_set_next_eret_context(NON_SECURE);
+			if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_YIELD) {
+				clr_yield_smc_active_flag(tsp_ctx->state);
+#if TSP_NS_INTR_ASYNC_PREEMPT
+				/*
+				 * Disable the routing of NS interrupts to EL3
+				 * after processing of a Yielding SMC Call on
+				 * this core is finished.
+				 */
+				disable_intr_rm_local(INTR_TYPE_NS, SECURE);
+#endif
+			}
+
+			SMC_RET3(ns_cpu_context, x1, x2, x3);
+		}
+		assert(0); /* Unreachable */
+
+	/*
+	 * Request from the non-secure world to abort a preempted Yielding SMC
+	 * Call.
+	 */
+	case TSP_FID_ABORT:
+		/* ABORT should only be invoked by normal world */
+		if (!ns) {
+			assert(0);
+			break;
+		}
+
+		assert(handle == cm_get_context(NON_SECURE));
+		cm_el1_sysregs_context_save(NON_SECURE);
+
+		/* Abort the preempted SMC request */
+		if (!tspd_abort_preempted_smc(tsp_ctx)) {
+			/*
+			 * If there was no preempted SMC to abort, return
+			 * SMC_UNK.
+			 *
+			 * Restoring the NON_SECURE context is not necessary as
+			 * the synchronous entry did not take place if the
+			 * return code of tspd_abort_preempted_smc is zero.
+			 */
+			cm_set_next_eret_context(NON_SECURE);
+			break;
+		}
+
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+		SMC_RET1(handle, SMC_OK);
+
+		/*
+		 * Request from non secure world to resume the preempted
+		 * Yielding SMC Call.
+		 */
+	case TSP_FID_RESUME:
+		/* RESUME should be invoked only by normal world */
+		if (!ns) {
+			assert(0);
+			break;
+		}
+
+		/*
+		 * This is a resume request from the non-secure client.
+		 * save the non-secure state and send the request to
+		 * the secure payload.
+		 */
+		assert(handle == cm_get_context(NON_SECURE));
+
+		/* Check if we are already preempted before resume */
+		if (!get_yield_smc_active_flag(tsp_ctx->state))
+			SMC_RET1(handle, SMC_UNK);
+
+		cm_el1_sysregs_context_save(NON_SECURE);
+
+		/*
+		 * We are done stashing the non-secure context. Ask the
+		 * secure payload to do the work now.
+		 */
+#if TSP_NS_INTR_ASYNC_PREEMPT
+		/*
+		 * Enable the routing of NS interrupts to EL3 during resumption
+		 * of a Yielding SMC Call on this core.
+		 */
+		enable_intr_rm_local(INTR_TYPE_NS, SECURE);
+#endif
+
+#if EL3_EXCEPTION_HANDLING
+		/*
+		 * Allow the resumed yielding SMC processing to be preempted by
+		 * Non-secure interrupts. Also, supply the preemption return
+		 * code for TSP.
+		 */
+		ehf_allow_ns_preemption(TSP_PREEMPTED);
+#endif
+
+		/* We just need to return to the preempted point in
+		 * TSP and the execution will resume as normal.
+		 */
+		cm_el1_sysregs_context_restore(SECURE);
+		cm_set_next_eret_context(SECURE);
+		SMC_RET0(&tsp_ctx->cpu_ctx);
+
+		/*
+		 * This is a request from the secure payload for more arguments
+		 * for an ongoing arithmetic operation requested by the
+		 * non-secure world. Simply return the arguments from the non-
+		 * secure client in the original call.
+		 */
+	case TSP_GET_ARGS:
+		if (ns)
+			SMC_RET1(handle, SMC_UNK);
+
+		get_tsp_args(tsp_ctx, x1, x2);
+		SMC_RET2(handle, x1, x2);
+
+	case TOS_CALL_COUNT:
+		/*
+		 * Return the number of service function IDs implemented to
+		 * provide service to non-secure
+		 */
+		SMC_RET1(handle, TSP_NUM_FID);
+
+	case TOS_UID:
+		/* Return TSP UID to the caller */
+		SMC_UUID_RET(handle, tsp_uuid);
+
+	case TOS_CALL_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, TSP_VERSION_MAJOR, TSP_VERSION_MINOR);
+
+	default:
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/* Define a SPD runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	tspd_fast,
+
+	OEN_TOS_START,
+	OEN_TOS_END,
+	SMC_TYPE_FAST,
+	tspd_setup,
+	tspd_smc_handler
+);
+
+/* Define a SPD runtime service descriptor for Yielding SMC Calls */
+DECLARE_RT_SVC(
+	tspd_std,
+
+	OEN_TOS_START,
+	OEN_TOS_END,
+	SMC_TYPE_YIELD,
+	NULL,
+	tspd_smc_handler
+);
diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c
new file mode 100644
index 0000000..b95ee8f
--- /dev/null
+++ b/services/spd/tspd/tspd_pm.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <bl32/tsp/tsp.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <plat/common/platform.h>
+
+#include "tspd_private.h"
+
+/*******************************************************************************
+ * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions
+ * needed. Nothing at the moment.
+ ******************************************************************************/
+static void tspd_cpu_on_handler(u_register_t target_cpu)
+{
+}
+
+/*******************************************************************************
+ * This cpu is being turned off. Allow the TSPD/TSP to perform any actions
+ * needed
+ ******************************************************************************/
+static int32_t tspd_cpu_off_handler(u_register_t unused)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+
+	assert(tsp_vectors);
+	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
+
+	/*
+	 * Abort any preempted SMC request before overwriting the SECURE
+	 * context.
+	 */
+	tspd_abort_preempted_smc(tsp_ctx);
+
+	/* Program the entry point and enter the TSP */
+	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_off_entry);
+	rc = tspd_synchronous_sp_entry(tsp_ctx);
+
+	/*
+	 * Read the response from the TSP. A non-zero return means that
+	 * something went wrong while communicating with the TSP.
+	 */
+	if (rc != 0)
+		panic();
+
+	/*
+	 * Reset TSP's context for a fresh start when this cpu is turned on
+	 * subsequently.
+	 */
+	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * This cpu is being suspended. S-EL1 state must have been saved in the
+ * resident cpu (mpidr format) if it is a UP/UP migratable TSP.
+ ******************************************************************************/
+static void tspd_cpu_suspend_handler(u_register_t max_off_pwrlvl)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+
+	assert(tsp_vectors);
+	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
+
+	/*
+	 * Abort any preempted SMC request before overwriting the SECURE
+	 * context.
+	 */
+	tspd_abort_preempted_smc(tsp_ctx);
+
+	/* Program the entry point and enter the TSP */
+	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_suspend_entry);
+	rc = tspd_synchronous_sp_entry(tsp_ctx);
+
+	/*
+	 * Read the response from the TSP. A non-zero return means that
+	 * something went wrong while communicating with the TSP.
+	 */
+	if (rc)
+		panic();
+
+	/* Update its context to reflect the state the TSP is in */
+	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND);
+}
+
+/*******************************************************************************
+ * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits
+ * before passing control back to the Secure Monitor. Entry in S-EL1 is done
+ * after initialising minimal architectural state that guarantees safe
+ * execution.
+ ******************************************************************************/
+static void tspd_cpu_on_finish_handler(u_register_t unused)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+	entry_point_info_t tsp_on_entrypoint;
+
+	assert(tsp_vectors);
+	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF);
+
+	tspd_init_tsp_ep_state(&tsp_on_entrypoint,
+				TSP_AARCH64,
+				(uint64_t) &tsp_vectors->cpu_on_entry,
+				tsp_ctx);
+
+	/* Initialise this cpu's secure context */
+	cm_init_my_context(&tsp_on_entrypoint);
+
+#if TSP_NS_INTR_ASYNC_PREEMPT
+	/*
+	 * Disable the NS interrupt locally since it will be enabled globally
+	 * within cm_init_my_context.
+	 */
+	disable_intr_rm_local(INTR_TYPE_NS, SECURE);
+#endif
+
+	/* Enter the TSP */
+	rc = tspd_synchronous_sp_entry(tsp_ctx);
+
+	/*
+	 * Read the response from the TSP. A non-zero return means that
+	 * something went wrong while communicating with the SP.
+	 */
+	if (rc != 0)
+		panic();
+
+	/* Update its context to reflect the state the SP is in */
+	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
+}
+
+/*******************************************************************************
+ * This cpu has resumed from suspend. The SPD saved the TSP context when it
+ * completed the preceding suspend call. Use that context to program an entry
+ * into the TSP to allow it to do any remaining book keeping
+ ******************************************************************************/
+static void tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)
+{
+	int32_t rc = 0;
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+
+	assert(tsp_vectors);
+	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND);
+
+	/* Program the entry point, max_off_pwrlvl and enter the SP */
+	write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
+		      CTX_GPREG_X0,
+		      max_off_pwrlvl);
+	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry);
+	rc = tspd_synchronous_sp_entry(tsp_ctx);
+
+	/*
+	 * Read the response from the TSP. A non-zero return means that
+	 * something went wrong while communicating with the TSP.
+	 */
+	if (rc != 0)
+		panic();
+
+	/* Update its context to reflect the state the SP is in */
+	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
+}
+
+/*******************************************************************************
+ * Return the type of TSP the TSPD is dealing with. Report the current resident
+ * cpu (mpidr format) if it is a UP/UP migratable TSP.
+ ******************************************************************************/
+static int32_t tspd_cpu_migrate_info(u_register_t *resident_cpu)
+{
+	return TSP_MIGRATE_INFO;
+}
+
+/*******************************************************************************
+ * System is about to be switched off. Allow the TSPD/TSP to perform
+ * any actions needed.
+ ******************************************************************************/
+static void tspd_system_off(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+
+	assert(tsp_vectors);
+	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
+
+	/*
+	 * Abort any preempted SMC request before overwriting the SECURE
+	 * context.
+	 */
+	tspd_abort_preempted_smc(tsp_ctx);
+
+	/* Program the entry point */
+	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry);
+
+	/* Enter the TSP. We do not care about the return value because we
+	 * must continue the shutdown anyway */
+	tspd_synchronous_sp_entry(tsp_ctx);
+}
+
+/*******************************************************************************
+ * System is about to be reset. Allow the TSPD/TSP to perform
+ * any actions needed.
+ ******************************************************************************/
+static void tspd_system_reset(void)
+{
+	uint32_t linear_id = plat_my_core_pos();
+	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
+
+	assert(tsp_vectors);
+	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
+
+	/*
+	 * Abort any preempted SMC request before overwriting the SECURE
+	 * context.
+	 */
+	tspd_abort_preempted_smc(tsp_ctx);
+
+	/* Program the entry point */
+	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry);
+
+	/*
+	 * Enter the TSP. We do not care about the return value because we
+	 * must continue the reset anyway
+	 */
+	tspd_synchronous_sp_entry(tsp_ctx);
+}
+
+/*******************************************************************************
+ * Structure populated by the TSP Dispatcher to be given a chance to perform any
+ * TSP bookkeeping before PSCI executes a power mgmt.  operation.
+ ******************************************************************************/
+const spd_pm_ops_t tspd_pm = {
+	.svc_on = tspd_cpu_on_handler,
+	.svc_off = tspd_cpu_off_handler,
+	.svc_suspend = tspd_cpu_suspend_handler,
+	.svc_on_finish = tspd_cpu_on_finish_handler,
+	.svc_suspend_finish = tspd_cpu_suspend_finish_handler,
+	.svc_migrate = NULL,
+	.svc_migrate_info = tspd_cpu_migrate_info,
+	.svc_system_off = tspd_system_off,
+	.svc_system_reset = tspd_system_reset
+};
diff --git a/services/spd/tspd/tspd_private.h b/services/spd/tspd/tspd_private.h
new file mode 100644
index 0000000..a81eb21
--- /dev/null
+++ b/services/spd/tspd/tspd_private.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TSPD_PRIVATE_H
+#define TSPD_PRIVATE_H
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <bl31/interrupt_mgmt.h>
+#include <context.h>
+#include <lib/psci/psci.h>
+
+/*******************************************************************************
+ * Secure Payload PM state information e.g. SP is suspended, uninitialised etc
+ * and macros to access the state information in the per-cpu 'state' flags
+ ******************************************************************************/
+#define TSP_PSTATE_OFF		0
+#define TSP_PSTATE_ON		1
+#define TSP_PSTATE_SUSPEND	2
+#define TSP_PSTATE_SHIFT	0
+#define TSP_PSTATE_MASK	0x3
+#define get_tsp_pstate(state)	((state >> TSP_PSTATE_SHIFT) & TSP_PSTATE_MASK)
+#define clr_tsp_pstate(state)	(state &= ~(TSP_PSTATE_MASK \
+					    << TSP_PSTATE_SHIFT))
+#define set_tsp_pstate(st, pst)	do {					       \
+					clr_tsp_pstate(st);		       \
+					st |= (pst & TSP_PSTATE_MASK) <<       \
+						TSP_PSTATE_SHIFT;	       \
+				} while (0);
+
+
+/*
+ * This flag is used by the TSPD to determine if the TSP is servicing a yielding
+ * SMC request prior to programming the next entry into the TSP e.g. if TSP
+ * execution is preempted by a non-secure interrupt and handed control to the
+ * normal world. If another request which is distinct from what the TSP was
+ * previously doing arrives, then this flag will be help the TSPD to either
+ * reject the new request or service it while ensuring that the previous context
+ * is not corrupted.
+ */
+#define YIELD_SMC_ACTIVE_FLAG_SHIFT	2
+#define YIELD_SMC_ACTIVE_FLAG_MASK	1
+#define get_yield_smc_active_flag(state)				\
+				((state >> YIELD_SMC_ACTIVE_FLAG_SHIFT) \
+				& YIELD_SMC_ACTIVE_FLAG_MASK)
+#define set_yield_smc_active_flag(state)	(state |=		\
+					1 << YIELD_SMC_ACTIVE_FLAG_SHIFT)
+#define clr_yield_smc_active_flag(state)	(state &=		\
+					~(YIELD_SMC_ACTIVE_FLAG_MASK	\
+					<< YIELD_SMC_ACTIVE_FLAG_SHIFT))
+
+/*******************************************************************************
+ * Secure Payload execution state information i.e. aarch32 or aarch64
+ ******************************************************************************/
+#define TSP_AARCH32		MODE_RW_32
+#define TSP_AARCH64		MODE_RW_64
+
+/*******************************************************************************
+ * The SPD should know the type of Secure Payload.
+ ******************************************************************************/
+#define TSP_TYPE_UP		PSCI_TOS_NOT_UP_MIG_CAP
+#define TSP_TYPE_UPM		PSCI_TOS_UP_MIG_CAP
+#define TSP_TYPE_MP		PSCI_TOS_NOT_PRESENT_MP
+
+/*******************************************************************************
+ * Secure Payload migrate type information as known to the SPD. We assume that
+ * the SPD is dealing with an MP Secure Payload.
+ ******************************************************************************/
+#define TSP_MIGRATE_INFO		TSP_TYPE_MP
+
+/*******************************************************************************
+ * Number of cpus that the present on this platform. TODO: Rely on a topology
+ * tree to determine this in the future to avoid assumptions about mpidr
+ * allocation
+ ******************************************************************************/
+#define TSPD_CORE_COUNT		PLATFORM_CORE_COUNT
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define TSPD_C_RT_CTX_X19		0x0
+#define TSPD_C_RT_CTX_X20		0x8
+#define TSPD_C_RT_CTX_X21		0x10
+#define TSPD_C_RT_CTX_X22		0x18
+#define TSPD_C_RT_CTX_X23		0x20
+#define TSPD_C_RT_CTX_X24		0x28
+#define TSPD_C_RT_CTX_X25		0x30
+#define TSPD_C_RT_CTX_X26		0x38
+#define TSPD_C_RT_CTX_X27		0x40
+#define TSPD_C_RT_CTX_X28		0x48
+#define TSPD_C_RT_CTX_X29		0x50
+#define TSPD_C_RT_CTX_X30		0x58
+#define TSPD_C_RT_CTX_SIZE		0x60
+#define TSPD_C_RT_CTX_ENTRIES		(TSPD_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve caller-saved registers of the
+ * SP context while performing a TSP preemption.
+ * Note: These offsets have to match with the offsets for the corresponding
+ * registers in cpu_context as we are using memcpy to copy the values from
+ * cpu_context to sp_ctx.
+ ******************************************************************************/
+#define TSPD_SP_CTX_X0		0x0
+#define TSPD_SP_CTX_X1		0x8
+#define TSPD_SP_CTX_X2		0x10
+#define TSPD_SP_CTX_X3		0x18
+#define TSPD_SP_CTX_X4		0x20
+#define TSPD_SP_CTX_X5		0x28
+#define TSPD_SP_CTX_X6		0x30
+#define TSPD_SP_CTX_X7		0x38
+#define TSPD_SP_CTX_X8		0x40
+#define TSPD_SP_CTX_X9		0x48
+#define TSPD_SP_CTX_X10		0x50
+#define TSPD_SP_CTX_X11		0x58
+#define TSPD_SP_CTX_X12		0x60
+#define TSPD_SP_CTX_X13		0x68
+#define TSPD_SP_CTX_X14		0x70
+#define TSPD_SP_CTX_X15		0x78
+#define TSPD_SP_CTX_X16		0x80
+#define TSPD_SP_CTX_X17		0x88
+#define TSPD_SP_CTX_SIZE	0x90
+#define TSPD_SP_CTX_ENTRIES		(TSPD_SP_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/cassert.h>
+
+/*
+ * The number of arguments to save during a SMC call for TSP.
+ * Currently only x1 and x2 are used by TSP.
+ */
+#define TSP_NUM_ARGS	0x2
+
+/* AArch64 callee saved general purpose register context structure. */
+DEFINE_REG_STRUCT(c_rt_regs, TSPD_C_RT_CTX_ENTRIES);
+
+/*
+ * Compile time assertion to ensure that both the compiler and linker
+ * have the same double word aligned view of the size of the C runtime
+ * register context.
+ */
+CASSERT(TSPD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t),	\
+	assert_spd_c_rt_regs_size_mismatch);
+
+/* SEL1 Secure payload (SP) caller saved register context structure. */
+DEFINE_REG_STRUCT(sp_ctx_regs, TSPD_SP_CTX_ENTRIES);
+
+/*
+ * Compile time assertion to ensure that both the compiler and linker
+ * have the same double word aligned view of the size of the C runtime
+ * register context.
+ */
+CASSERT(TSPD_SP_CTX_SIZE == sizeof(sp_ctx_regs_t),	\
+	assert_spd_sp_regs_size_mismatch);
+
+/*******************************************************************************
+ * Structure which helps the SPD to maintain the per-cpu state of the SP.
+ * 'saved_spsr_el3' - temporary copy to allow S-EL1 interrupt handling when
+ *                    the TSP has been preempted.
+ * 'saved_elr_el3'  - temporary copy to allow S-EL1 interrupt handling when
+ *                    the TSP has been preempted.
+ * 'state'          - collection of flags to track SP state e.g. on/off
+ * 'mpidr'          - mpidr to associate a context with a cpu
+ * 'c_rt_ctx'       - stack address to restore C runtime context from after
+ *                    returning from a synchronous entry into the SP.
+ * 'cpu_ctx'        - space to maintain SP architectural state
+ * 'saved_tsp_args' - space to store arguments for TSP arithmetic operations
+ *                    which will queried using the TSP_GET_ARGS SMC by TSP.
+ * 'sp_ctx'         - space to save the SEL1 Secure Payload(SP) caller saved
+ *                    register context after it has been preempted by an EL3
+ *                    routed NS interrupt and when a Secure Interrupt is taken
+ *                    to SP.
+ ******************************************************************************/
+typedef struct tsp_context {
+	uint64_t saved_elr_el3;
+	uint32_t saved_spsr_el3;
+	uint32_t state;
+	uint64_t mpidr;
+	uint64_t c_rt_ctx;
+	cpu_context_t cpu_ctx;
+	uint64_t saved_tsp_args[TSP_NUM_ARGS];
+#if TSP_NS_INTR_ASYNC_PREEMPT
+	sp_ctx_regs_t sp_ctx;
+#endif
+} tsp_context_t;
+
+/* Helper macros to store and retrieve tsp args from tsp_context */
+#define store_tsp_args(_tsp_ctx, _x1, _x2)		do {\
+				_tsp_ctx->saved_tsp_args[0] = _x1;\
+				_tsp_ctx->saved_tsp_args[1] = _x2;\
+			} while (0)
+
+#define get_tsp_args(_tsp_ctx, _x1, _x2)	do {\
+				_x1 = _tsp_ctx->saved_tsp_args[0];\
+				_x2 = _tsp_ctx->saved_tsp_args[1];\
+			} while (0)
+
+/* TSPD power management handlers */
+extern const spd_pm_ops_t tspd_pm;
+
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+typedef struct tsp_vectors tsp_vectors_t;
+
+/*******************************************************************************
+ * Function & Data prototypes
+ ******************************************************************************/
+uint64_t tspd_enter_sp(uint64_t *c_rt_ctx);
+void __dead2 tspd_exit_sp(uint64_t c_rt_ctx, uint64_t ret);
+uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx);
+void __dead2 tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret);
+void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point,
+				uint32_t rw,
+				uint64_t pc,
+				tsp_context_t *tsp_ctx);
+int tspd_abort_preempted_smc(tsp_context_t *tsp_ctx);
+
+uint64_t tspd_handle_sp_preemption(void *handle);
+
+extern tsp_context_t tspd_sp_context[TSPD_CORE_COUNT];
+extern tsp_vectors_t *tsp_vectors;
+#endif /*__ASSEMBLER__*/
+
+#endif /* TSPD_PRIVATE_H */
diff --git a/services/std_svc/sdei/sdei_dispatch.S b/services/std_svc/sdei/sdei_dispatch.S
new file mode 100644
index 0000000..8449e4b
--- /dev/null
+++ b/services/std_svc/sdei/sdei_dispatch.S
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	begin_sdei_synchronous_dispatch
+
+/*
+ * void begin_sdei_synchronous_dispatch(jmp_buf *buffer);
+ *
+ * Begin SDEI dispatch synchronously by setting up a jump point, and exiting
+ * EL3. This jump point is jumped to by the dispatcher after the event is
+ * completed by the client.
+ */
+func begin_sdei_synchronous_dispatch
+	stp	x30, xzr, [sp, #-16]!
+	bl	setjmp
+	cbz	x0, 1f
+	ldp	x30, xzr, [sp], #16
+	ret
+1:
+	b	el3_exit
+endfunc begin_sdei_synchronous_dispatch
diff --git a/services/std_svc/sdei/sdei_event.c b/services/std_svc/sdei/sdei_event.c
new file mode 100644
index 0000000..0b608e1
--- /dev/null
+++ b/services/std_svc/sdei/sdei_event.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <lib/utils.h>
+
+#include "sdei_private.h"
+
+#define MAP_OFF(_map, _mapping) ((_map) - (_mapping)->map)
+
+/*
+ * Get SDEI entry with the given mapping: on success, returns pointer to SDEI
+ * entry. On error, returns NULL.
+ *
+ * Both shared and private maps are stored in single-dimensional array. Private
+ * event entries are kept for each PE forming a 2D array.
+ */
+sdei_entry_t *get_event_entry(sdei_ev_map_t *map)
+{
+	const sdei_mapping_t *mapping;
+	sdei_entry_t *cpu_priv_base;
+	unsigned int base_idx;
+	long int idx;
+
+	if (is_event_private(map)) {
+		/*
+		 * For a private map, find the index of the mapping in the
+		 * array.
+		 */
+		mapping = SDEI_PRIVATE_MAPPING();
+		idx = MAP_OFF(map, mapping);
+
+		/* Base of private mappings for this CPU */
+		base_idx = plat_my_core_pos() * ((unsigned int) mapping->num_maps);
+		cpu_priv_base = &sdei_private_event_table[base_idx];
+
+		/*
+		 * Return the address of the entry at the same index in the
+		 * per-CPU event entry.
+		 */
+		return &cpu_priv_base[idx];
+	} else {
+		mapping = SDEI_SHARED_MAPPING();
+		idx = MAP_OFF(map, mapping);
+
+		return &sdei_shared_event_table[idx];
+	}
+}
+
+/*
+ * Find event mapping for a given interrupt number: On success, returns pointer
+ * to the event mapping. On error, returns NULL.
+ */
+sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared)
+{
+	const sdei_mapping_t *mapping;
+	sdei_ev_map_t *map;
+	unsigned int i;
+
+	/*
+	 * Look for a match in private and shared mappings, as requested. This
+	 * is a linear search. However, if the mappings are required to be
+	 * sorted, for large maps, we could consider binary search.
+	 */
+	mapping = shared ? SDEI_SHARED_MAPPING() : SDEI_PRIVATE_MAPPING();
+	iterate_mapping(mapping, i, map) {
+		if (map->intr == intr_num)
+			return map;
+	}
+
+	return NULL;
+}
+
+/*
+ * Find event mapping for a given event number: On success returns pointer to
+ * the event mapping. On error, returns NULL.
+ */
+sdei_ev_map_t *find_event_map(int ev_num)
+{
+	const sdei_mapping_t *mapping;
+	sdei_ev_map_t *map;
+	unsigned int i, j;
+
+	/*
+	 * Iterate through mappings to find a match. This is a linear search.
+	 * However, if the mappings are required to be sorted, for large maps,
+	 * we could consider binary search.
+	 */
+	for_each_mapping_type(i, mapping) {
+		iterate_mapping(mapping, j, map) {
+			if (map->ev_num == ev_num)
+				return map;
+		}
+	}
+
+	return NULL;
+}
diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c
new file mode 100644
index 0000000..fa1d3d2
--- /dev/null
+++ b/services/std_svc/sdei/sdei_intr_mgmt.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/cassert.h>
+#include <services/sdei.h>
+
+#include "sdei_private.h"
+
+/* x0-x17 GPREGS context */
+#define SDEI_SAVED_GPREGS	18U
+
+/* Maximum preemption nesting levels: Critical priority and Normal priority */
+#define MAX_EVENT_NESTING	2U
+
+/* Per-CPU SDEI state access macro */
+#define sdei_get_this_pe_state()	(&cpu_state[plat_my_core_pos()])
+
+/* Structure to store information about an outstanding dispatch */
+typedef struct sdei_dispatch_context {
+	sdei_ev_map_t *map;
+	uint64_t x[SDEI_SAVED_GPREGS];
+	jmp_buf *dispatch_jmp;
+
+	/* Exception state registers */
+	uint64_t elr_el3;
+	uint64_t spsr_el3;
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+	/* CVE-2018-3639 mitigation state */
+	uint64_t disable_cve_2018_3639;
+#endif
+} sdei_dispatch_context_t;
+
+/* Per-CPU SDEI state data */
+typedef struct sdei_cpu_state {
+	sdei_dispatch_context_t dispatch_stack[MAX_EVENT_NESTING];
+	unsigned short stack_top; /* Empty ascending */
+	bool pe_masked;
+	bool pending_enables;
+} sdei_cpu_state_t;
+
+/* SDEI states for all cores in the system */
+static sdei_cpu_state_t cpu_state[PLATFORM_CORE_COUNT];
+
+int64_t sdei_pe_mask(void)
+{
+	int64_t ret = 0;
+	sdei_cpu_state_t *state = sdei_get_this_pe_state();
+
+	/*
+	 * Return value indicates whether this call had any effect in the mask
+	 * status of this PE.
+	 */
+	if (!state->pe_masked) {
+		state->pe_masked = true;
+		ret = 1;
+	}
+
+	return ret;
+}
+
+void sdei_pe_unmask(void)
+{
+	unsigned int i;
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+	sdei_cpu_state_t *state = sdei_get_this_pe_state();
+	uint64_t my_mpidr = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
+
+	/*
+	 * If there are pending enables, iterate through the private mappings
+	 * and enable those bound maps that are in enabled state. Also, iterate
+	 * through shared mappings and enable interrupts of events that are
+	 * targeted to this PE.
+	 */
+	if (state->pending_enables) {
+		for_each_private_map(i, map) {
+			se = get_event_entry(map);
+			if (is_map_bound(map) && GET_EV_STATE(se, ENABLED))
+				plat_ic_enable_interrupt(map->intr);
+		}
+
+		for_each_shared_map(i, map) {
+			se = get_event_entry(map);
+
+			sdei_map_lock(map);
+			if (is_map_bound(map) && GET_EV_STATE(se, ENABLED) &&
+					(se->reg_flags == SDEI_REGF_RM_PE) &&
+					(se->affinity == my_mpidr)) {
+				plat_ic_enable_interrupt(map->intr);
+			}
+			sdei_map_unlock(map);
+		}
+	}
+
+	state->pending_enables = false;
+	state->pe_masked = false;
+}
+
+/* Push a dispatch context to the dispatch stack */
+static sdei_dispatch_context_t *push_dispatch(void)
+{
+	sdei_cpu_state_t *state = sdei_get_this_pe_state();
+	sdei_dispatch_context_t *disp_ctx;
+
+	/* Cannot have more than max events */
+	assert(state->stack_top < MAX_EVENT_NESTING);
+
+	disp_ctx = &state->dispatch_stack[state->stack_top];
+	state->stack_top++;
+
+	return disp_ctx;
+}
+
+/* Pop a dispatch context to the dispatch stack */
+static sdei_dispatch_context_t *pop_dispatch(void)
+{
+	sdei_cpu_state_t *state = sdei_get_this_pe_state();
+
+	if (state->stack_top == 0U)
+		return NULL;
+
+	assert(state->stack_top <= MAX_EVENT_NESTING);
+
+	state->stack_top--;
+
+	return &state->dispatch_stack[state->stack_top];
+}
+
+/* Retrieve the context at the top of dispatch stack */
+static sdei_dispatch_context_t *get_outstanding_dispatch(void)
+{
+	sdei_cpu_state_t *state = sdei_get_this_pe_state();
+
+	if (state->stack_top == 0U)
+		return NULL;
+
+	assert(state->stack_top <= MAX_EVENT_NESTING);
+
+	return &state->dispatch_stack[state->stack_top - 1U];
+}
+
+static sdei_dispatch_context_t *save_event_ctx(sdei_ev_map_t *map,
+		void *tgt_ctx)
+{
+	sdei_dispatch_context_t *disp_ctx;
+	const gp_regs_t *tgt_gpregs;
+	const el3_state_t *tgt_el3;
+
+	assert(tgt_ctx != NULL);
+	tgt_gpregs = get_gpregs_ctx(tgt_ctx);
+	tgt_el3 = get_el3state_ctx(tgt_ctx);
+
+	disp_ctx = push_dispatch();
+	assert(disp_ctx != NULL);
+	disp_ctx->map = map;
+
+	/* Save general purpose and exception registers */
+	memcpy(disp_ctx->x, tgt_gpregs, sizeof(disp_ctx->x));
+	disp_ctx->spsr_el3 = read_ctx_reg(tgt_el3, CTX_SPSR_EL3);
+	disp_ctx->elr_el3 = read_ctx_reg(tgt_el3, CTX_ELR_EL3);
+
+	return disp_ctx;
+}
+
+static void restore_event_ctx(const sdei_dispatch_context_t *disp_ctx, void *tgt_ctx)
+{
+	gp_regs_t *tgt_gpregs;
+	el3_state_t *tgt_el3;
+
+	assert(tgt_ctx != NULL);
+	tgt_gpregs = get_gpregs_ctx(tgt_ctx);
+	tgt_el3 = get_el3state_ctx(tgt_ctx);
+
+	CASSERT(sizeof(disp_ctx->x) == (SDEI_SAVED_GPREGS * sizeof(uint64_t)),
+			foo);
+
+	/* Restore general purpose and exception registers */
+	memcpy(tgt_gpregs, disp_ctx->x, sizeof(disp_ctx->x));
+	write_ctx_reg(tgt_el3, CTX_SPSR_EL3, disp_ctx->spsr_el3);
+	write_ctx_reg(tgt_el3, CTX_ELR_EL3, disp_ctx->elr_el3);
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+	cve_2018_3639_t *tgt_cve_2018_3639;
+	tgt_cve_2018_3639 = get_cve_2018_3639_ctx(tgt_ctx);
+
+	/* Restore CVE-2018-3639 mitigation state */
+	write_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE,
+		disp_ctx->disable_cve_2018_3639);
+#endif
+}
+
+static void save_secure_context(void)
+{
+	cm_el1_sysregs_context_save(SECURE);
+}
+
+/* Restore Secure context and arrange to resume it at the next ERET */
+static void restore_and_resume_secure_context(void)
+{
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+}
+
+/*
+ * Restore Non-secure context and arrange to resume it at the next ERET. Return
+ * pointer to the Non-secure context.
+ */
+static cpu_context_t *restore_and_resume_ns_context(void)
+{
+	cpu_context_t *ns_ctx;
+
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_set_next_eret_context(NON_SECURE);
+
+	ns_ctx = cm_get_context(NON_SECURE);
+	assert(ns_ctx != NULL);
+
+	return ns_ctx;
+}
+
+/*
+ * Populate the Non-secure context so that the next ERET will dispatch to the
+ * SDEI client.
+ */
+static void setup_ns_dispatch(sdei_ev_map_t *map, sdei_entry_t *se,
+		cpu_context_t *ctx, jmp_buf *dispatch_jmp)
+{
+	sdei_dispatch_context_t *disp_ctx;
+
+	/* Push the event and context */
+	disp_ctx = save_event_ctx(map, ctx);
+
+	/*
+	 * Setup handler arguments:
+	 *
+	 * - x0: Event number
+	 * - x1: Handler argument supplied at the time of event registration
+	 * - x2: Interrupted PC
+	 * - x3: Interrupted SPSR
+	 */
+	SMC_SET_GP(ctx, CTX_GPREG_X0, (uint64_t) map->ev_num);
+	SMC_SET_GP(ctx, CTX_GPREG_X1, se->arg);
+	SMC_SET_GP(ctx, CTX_GPREG_X2, disp_ctx->elr_el3);
+	SMC_SET_GP(ctx, CTX_GPREG_X3, disp_ctx->spsr_el3);
+
+	/*
+	 * Prepare for ERET:
+	 *
+	 * - Set PC to the registered handler address
+	 * - Set SPSR to jump to client EL with exceptions masked
+	 */
+	cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep,
+			SPSR_64(sdei_client_el(), MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS));
+
+#if DYNAMIC_WORKAROUND_CVE_2018_3639
+	cve_2018_3639_t *tgt_cve_2018_3639;
+	tgt_cve_2018_3639 = get_cve_2018_3639_ctx(ctx);
+
+	/* Save CVE-2018-3639 mitigation state */
+	disp_ctx->disable_cve_2018_3639 = read_ctx_reg(tgt_cve_2018_3639,
+		CTX_CVE_2018_3639_DISABLE);
+
+	/* Force SDEI handler to execute with mitigation enabled by default */
+	write_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE, 0);
+#endif
+
+	disp_ctx->dispatch_jmp = dispatch_jmp;
+}
+
+/* Handle a triggered SDEI interrupt while events were masked on this PE */
+static void handle_masked_trigger(sdei_ev_map_t *map, sdei_entry_t *se,
+		sdei_cpu_state_t *state, unsigned int intr_raw)
+{
+	uint64_t my_mpidr __unused = (read_mpidr_el1() & MPIDR_AFFINITY_MASK);
+	bool disable = false;
+
+	/* Nothing to do for event 0 */
+	if (map->ev_num == SDEI_EVENT_0)
+		return;
+
+	/*
+	 * For a private event, or for a shared event specifically routed to
+	 * this CPU, we disable interrupt, leave the interrupt pending, and do
+	 * EOI.
+	 */
+	if (is_event_private(map) || (se->reg_flags == SDEI_REGF_RM_PE))
+		disable = true;
+
+	if (se->reg_flags == SDEI_REGF_RM_PE)
+		assert(se->affinity == my_mpidr);
+
+	if (disable) {
+		plat_ic_disable_interrupt(map->intr);
+		plat_ic_set_interrupt_pending(map->intr);
+		plat_ic_end_of_interrupt(intr_raw);
+		state->pending_enables = true;
+
+		return;
+	}
+
+	/*
+	 * We just received a shared event with routing set to ANY PE. The
+	 * interrupt can't be delegated on this PE as SDEI events are masked.
+	 * However, because its routing mode is ANY, it is possible that the
+	 * event can be delegated on any other PE that hasn't masked events.
+	 * Therefore, we set the interrupt back pending so as to give other
+	 * suitable PEs a chance of handling it.
+	 */
+	assert(plat_ic_is_spi(map->intr) != 0);
+	plat_ic_set_interrupt_pending(map->intr);
+
+	/*
+	 * Leaving the same interrupt pending also means that the same interrupt
+	 * can target this PE again as soon as this PE leaves EL3. Whether and
+	 * how often that happens depends on the implementation of GIC.
+	 *
+	 * We therefore call a platform handler to resolve this situation.
+	 */
+	plat_sdei_handle_masked_trigger(my_mpidr, map->intr);
+
+	/* This PE is masked. We EOI the interrupt, as it can't be delegated */
+	plat_ic_end_of_interrupt(intr_raw);
+}
+
+/* SDEI main interrupt handler */
+int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle,
+		void *cookie)
+{
+	sdei_entry_t *se;
+	cpu_context_t *ctx;
+	sdei_ev_map_t *map;
+	const sdei_dispatch_context_t *disp_ctx;
+	unsigned int sec_state;
+	sdei_cpu_state_t *state;
+	uint32_t intr;
+	jmp_buf dispatch_jmp;
+	const uint64_t mpidr = read_mpidr_el1();
+
+	/*
+	 * To handle an event, the following conditions must be true:
+	 *
+	 * 1. Event must be signalled
+	 * 2. Event must be enabled
+	 * 3. This PE must be a target PE for the event
+	 * 4. PE must be unmasked for SDEI
+	 * 5. If this is a normal event, no event must be running
+	 * 6. If this is a critical event, no critical event must be running
+	 *
+	 * (1) and (2) are true when this function is running
+	 * (3) is enforced in GIC by selecting the appropriate routing option
+	 * (4) is satisfied by client calling PE_UNMASK
+	 * (5) and (6) is enforced using interrupt priority, the RPR, in GIC:
+	 *   - Normal SDEI events belong to Normal SDE priority class
+	 *   - Critical SDEI events belong to Critical CSDE priority class
+	 *
+	 * The interrupt has already been acknowledged, and therefore is active,
+	 * so no other PE can handle this event while we are at it.
+	 *
+	 * Find if this is an SDEI interrupt. There must be an event mapped to
+	 * this interrupt
+	 */
+	intr = plat_ic_get_interrupt_id(intr_raw);
+	map = find_event_map_by_intr(intr, (plat_ic_is_spi(intr) != 0));
+	if (map == NULL) {
+		ERROR("No SDEI map for interrupt %u\n", intr);
+		panic();
+	}
+
+	/*
+	 * Received interrupt number must either correspond to event 0, or must
+	 * be bound interrupt.
+	 */
+	assert((map->ev_num == SDEI_EVENT_0) || is_map_bound(map));
+
+	se = get_event_entry(map);
+	state = sdei_get_this_pe_state();
+
+	if (state->pe_masked) {
+		/*
+		 * Interrupts received while this PE was masked can't be
+		 * dispatched.
+		 */
+		SDEI_LOG("interrupt %u on %llx while PE masked\n", map->intr,
+				mpidr);
+		if (is_event_shared(map))
+			sdei_map_lock(map);
+
+		handle_masked_trigger(map, se, state, intr_raw);
+
+		if (is_event_shared(map))
+			sdei_map_unlock(map);
+
+		return 0;
+	}
+
+	/* Insert load barrier for signalled SDEI event */
+	if (map->ev_num == SDEI_EVENT_0)
+		dmbld();
+
+	if (is_event_shared(map))
+		sdei_map_lock(map);
+
+	/* Assert shared event routed to this PE had been configured so */
+	if (is_event_shared(map) && (se->reg_flags == SDEI_REGF_RM_PE)) {
+		assert(se->affinity == (mpidr & MPIDR_AFFINITY_MASK));
+	}
+
+	if (!can_sdei_state_trans(se, DO_DISPATCH)) {
+		SDEI_LOG("SDEI event 0x%x can't be dispatched; state=0x%x\n",
+				map->ev_num, se->state);
+
+		/*
+		 * If the event is registered, leave the interrupt pending so
+		 * that it's delivered when the event is enabled.
+		 */
+		if (GET_EV_STATE(se, REGISTERED))
+			plat_ic_set_interrupt_pending(map->intr);
+
+		/*
+		 * The interrupt was disabled or unregistered after the handler
+		 * started to execute, which means now the interrupt is already
+		 * disabled and we just need to EOI the interrupt.
+		 */
+		plat_ic_end_of_interrupt(intr_raw);
+
+		if (is_event_shared(map))
+			sdei_map_unlock(map);
+
+		return 0;
+	}
+
+	disp_ctx = get_outstanding_dispatch();
+	if (is_event_critical(map)) {
+		/*
+		 * If this event is Critical, and if there's an outstanding
+		 * dispatch, assert the latter is a Normal dispatch. Critical
+		 * events can preempt an outstanding Normal event dispatch.
+		 */
+		if (disp_ctx != NULL)
+			assert(is_event_normal(disp_ctx->map));
+	} else {
+		/*
+		 * If this event is Normal, assert that there are no outstanding
+		 * dispatches. Normal events can't preempt any outstanding event
+		 * dispatches.
+		 */
+		assert(disp_ctx == NULL);
+	}
+
+	sec_state = get_interrupt_src_ss(flags);
+
+	if (is_event_shared(map))
+		sdei_map_unlock(map);
+
+	SDEI_LOG("ACK %llx, ev:%d ss:%d spsr:%lx ELR:%lx\n", mpidr, map->ev_num,
+			sec_state, read_spsr_el3(), read_elr_el3());
+
+	ctx = handle;
+
+	/*
+	 * Check if we interrupted secure state. Perform a context switch so
+	 * that we can delegate to NS.
+	 */
+	if (sec_state == SECURE) {
+		save_secure_context();
+		ctx = restore_and_resume_ns_context();
+	}
+
+	/* Synchronously dispatch event */
+	setup_ns_dispatch(map, se, ctx, &dispatch_jmp);
+	begin_sdei_synchronous_dispatch(&dispatch_jmp);
+
+	/*
+	 * We reach here when client completes the event.
+	 *
+	 * If the cause of dispatch originally interrupted the Secure world,
+	 * resume Secure.
+	 *
+	 * No need to save the Non-secure context ahead of a world switch: the
+	 * Non-secure context was fully saved before dispatch, and has been
+	 * returned to its pre-dispatch state.
+	 */
+	if (sec_state == SECURE)
+		restore_and_resume_secure_context();
+
+	/*
+	 * The event was dispatched after receiving SDEI interrupt. With
+	 * the event handling completed, EOI the corresponding
+	 * interrupt.
+	 */
+	if ((map->ev_num != SDEI_EVENT_0) && !is_map_bound(map)) {
+		ERROR("Invalid SDEI mapping: ev=%u\n", map->ev_num);
+		panic();
+	}
+	plat_ic_end_of_interrupt(intr_raw);
+
+	return 0;
+}
+
+/*
+ * Explicitly dispatch the given SDEI event.
+ *
+ * When calling this API, the caller must be prepared for the SDEI dispatcher to
+ * restore and make Non-secure context as active. This call returns only after
+ * the client has completed the dispatch. Then, the Non-secure context will be
+ * active, and the following ERET will return to Non-secure.
+ *
+ * Should the caller require re-entry to Secure, it must restore the Secure
+ * context and program registers for ERET.
+ */
+int sdei_dispatch_event(int ev_num)
+{
+	sdei_entry_t *se;
+	sdei_ev_map_t *map;
+	cpu_context_t *ns_ctx;
+	sdei_dispatch_context_t *disp_ctx;
+	sdei_cpu_state_t *state;
+	jmp_buf dispatch_jmp;
+
+	/* Can't dispatch if events are masked on this PE */
+	state = sdei_get_this_pe_state();
+	if (state->pe_masked)
+		return -1;
+
+	/* Event 0 can't be dispatched */
+	if (ev_num == SDEI_EVENT_0)
+		return -1;
+
+	/* Locate mapping corresponding to this event */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return -1;
+
+	/* Only explicit events can be dispatched */
+	if (!is_map_explicit(map))
+		return -1;
+
+	/* Examine state of dispatch stack */
+	disp_ctx = get_outstanding_dispatch();
+	if (disp_ctx != NULL) {
+		/*
+		 * There's an outstanding dispatch. If the outstanding dispatch
+		 * is critical, no more dispatches are possible.
+		 */
+		if (is_event_critical(disp_ctx->map))
+			return -1;
+
+		/*
+		 * If the outstanding dispatch is Normal, only critical events
+		 * can be dispatched.
+		 */
+		if (is_event_normal(map))
+			return -1;
+	}
+
+	se = get_event_entry(map);
+	if (!can_sdei_state_trans(se, DO_DISPATCH))
+		return -1;
+
+	/* Activate the priority corresponding to the event being dispatched */
+	ehf_activate_priority(sdei_event_priority(map));
+
+	/*
+	 * Prepare for NS dispatch by restoring the Non-secure context and
+	 * marking that as active.
+	 */
+	ns_ctx = restore_and_resume_ns_context();
+
+	/* Dispatch event synchronously */
+	setup_ns_dispatch(map, se, ns_ctx, &dispatch_jmp);
+	begin_sdei_synchronous_dispatch(&dispatch_jmp);
+
+	/*
+	 * We reach here when client completes the event.
+	 *
+	 * Deactivate the priority level that was activated at the time of
+	 * explicit dispatch.
+	 */
+	ehf_deactivate_priority(sdei_event_priority(map));
+
+	return 0;
+}
+
+static void end_sdei_synchronous_dispatch(jmp_buf *buffer)
+{
+	longjmp(*buffer, 1);
+}
+
+int sdei_event_complete(bool resume, uint64_t pc)
+{
+	sdei_dispatch_context_t *disp_ctx;
+	sdei_entry_t *se;
+	sdei_ev_map_t *map;
+	cpu_context_t *ctx;
+	sdei_action_t act;
+	unsigned int client_el = sdei_client_el();
+
+	/* Return error if called without an active event */
+	disp_ctx = get_outstanding_dispatch();
+	if (disp_ctx == NULL)
+		return SDEI_EDENY;
+
+	/* Validate resumption point */
+	if (resume && (plat_sdei_validate_entry_point(pc, client_el) != 0))
+		return SDEI_EDENY;
+
+	map = disp_ctx->map;
+	assert(map != NULL);
+	se = get_event_entry(map);
+
+	if (is_event_shared(map))
+		sdei_map_lock(map);
+
+	act = resume ? DO_COMPLETE_RESUME : DO_COMPLETE;
+	if (!can_sdei_state_trans(se, act)) {
+		if (is_event_shared(map))
+			sdei_map_unlock(map);
+		return SDEI_EDENY;
+	}
+
+	if (is_event_shared(map))
+		sdei_map_unlock(map);
+
+	/* Having done sanity checks, pop dispatch */
+	(void) pop_dispatch();
+
+	SDEI_LOG("EOI:%lx, %d spsr:%lx elr:%lx\n", read_mpidr_el1(),
+			map->ev_num, read_spsr_el3(), read_elr_el3());
+
+	/*
+	 * Restore Non-secure to how it was originally interrupted. Once done,
+	 * it's up-to-date with the saved copy.
+	 */
+	ctx = cm_get_context(NON_SECURE);
+	restore_event_ctx(disp_ctx, ctx);
+
+	if (resume) {
+		/*
+		 * Complete-and-resume call. Prepare the Non-secure context
+		 * (currently active) for complete and resume.
+		 */
+		cm_set_elr_spsr_el3(NON_SECURE, pc, SPSR_64(client_el,
+					MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
+
+		/*
+		 * Make it look as if a synchronous exception were taken at the
+		 * supplied Non-secure resumption point. Populate SPSR and
+		 * ELR_ELx so that an ERET from there works as expected.
+		 *
+		 * The assumption is that the client, if necessary, would have
+		 * saved any live content in these registers before making this
+		 * call.
+		 */
+		if (client_el == MODE_EL2) {
+			write_elr_el2(disp_ctx->elr_el3);
+			write_spsr_el2(disp_ctx->spsr_el3);
+		} else {
+			/* EL1 */
+			write_elr_el1(disp_ctx->elr_el3);
+			write_spsr_el1(disp_ctx->spsr_el3);
+		}
+	}
+
+	/* End the outstanding dispatch */
+	end_sdei_synchronous_dispatch(disp_ctx->dispatch_jmp);
+
+	return 0;
+}
+
+int64_t sdei_event_context(void *handle, unsigned int param)
+{
+	sdei_dispatch_context_t *disp_ctx;
+
+	if (param >= SDEI_SAVED_GPREGS)
+		return SDEI_EINVAL;
+
+	/* Get outstanding dispatch on this CPU */
+	disp_ctx = get_outstanding_dispatch();
+	if (disp_ctx == NULL)
+		return SDEI_EDENY;
+
+	assert(disp_ctx->map != NULL);
+
+	if (!can_sdei_state_trans(get_event_entry(disp_ctx->map), DO_CONTEXT))
+		return SDEI_EDENY;
+
+	/*
+	 * No locking is required for the Running status as this is the only CPU
+	 * which can complete the event
+	 */
+
+	return (int64_t) disp_ctx->x[param];
+}
diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c
new file mode 100644
index 0000000..0424177
--- /dev/null
+++ b/services/std_svc/sdei/sdei_main.c
@@ -0,0 +1,1093 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <lib/cassert.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+
+#include "sdei_private.h"
+
+#define MAJOR_VERSION	1ULL
+#define MINOR_VERSION	0ULL
+#define VENDOR_VERSION	0ULL
+
+#define MAKE_SDEI_VERSION(_major, _minor, _vendor) \
+	((((_major)) << 48ULL) | (((_minor)) << 32ULL) | (_vendor))
+
+#define LOWEST_INTR_PRIORITY		0xff
+
+#define is_valid_affinity(_mpidr)	(plat_core_pos_by_mpidr(_mpidr) >= 0)
+
+CASSERT(PLAT_SDEI_CRITICAL_PRI < PLAT_SDEI_NORMAL_PRI,
+		sdei_critical_must_have_higher_priority);
+
+static unsigned int num_dyn_priv_slots, num_dyn_shrd_slots;
+
+/* Initialise SDEI map entries */
+static void init_map(sdei_ev_map_t *map)
+{
+	map->reg_count = 0;
+}
+
+/* Convert mapping to SDEI class */
+static sdei_class_t map_to_class(sdei_ev_map_t *map)
+{
+	return is_event_critical(map) ? SDEI_CRITICAL : SDEI_NORMAL;
+}
+
+/* Clear SDEI event entries except state */
+static void clear_event_entries(sdei_entry_t *se)
+{
+	se->ep = 0;
+	se->arg = 0;
+	se->affinity = 0;
+	se->reg_flags = 0;
+}
+
+/* Perform CPU-specific state initialisation */
+static void *sdei_cpu_on_init(const void *arg)
+{
+	unsigned int i;
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+
+	/* Initialize private mappings on this CPU */
+	for_each_private_map(i, map) {
+		se = get_event_entry(map);
+		clear_event_entries(se);
+		se->state = 0;
+	}
+
+	SDEI_LOG("Private events initialized on %lx\n", read_mpidr_el1());
+
+	/* All PEs start with SDEI events masked */
+	(void) sdei_pe_mask();
+
+	return NULL;
+}
+
+/* CPU initialisation after wakeup from suspend */
+static void *sdei_cpu_wakeup_init(const void *arg)
+{
+	SDEI_LOG("Events masked on %lx\n", read_mpidr_el1());
+
+	/* All PEs wake up with SDEI events masked */
+	sdei_pe_mask();
+
+	return 0;
+}
+
+/* Initialise an SDEI class */
+static void sdei_class_init(sdei_class_t class)
+{
+	unsigned int i;
+	bool zero_found __unused = false;
+	int ev_num_so_far __unused;
+	sdei_ev_map_t *map;
+
+	/* Sanity check and configuration of shared events */
+	ev_num_so_far = -1;
+	for_each_shared_map(i, map) {
+#if ENABLE_ASSERTIONS
+		/* Ensure mappings are sorted */
+		assert((ev_num_so_far < 0) || (map->ev_num > ev_num_so_far));
+
+		ev_num_so_far = map->ev_num;
+
+		/* Event 0 must not be shared */
+		assert(map->ev_num != SDEI_EVENT_0);
+
+		/* Check for valid event */
+		assert(map->ev_num >= 0);
+
+		/* Make sure it's a shared event */
+		assert(is_event_shared(map));
+
+		/* No shared mapping should have signalable property */
+		assert(!is_event_signalable(map));
+
+		/* Shared mappings can't be explicit */
+		assert(!is_map_explicit(map));
+#endif
+
+		/* Skip initializing the wrong priority */
+		if (map_to_class(map) != class)
+			continue;
+
+		/* Platform events are always bound, so set the bound flag */
+		if (is_map_dynamic(map)) {
+			assert(map->intr == SDEI_DYN_IRQ);
+			assert(is_event_normal(map));
+			num_dyn_shrd_slots++;
+		} else {
+			/* Shared mappings must be bound to shared interrupt */
+			assert(plat_ic_is_spi(map->intr) != 0);
+			set_map_bound(map);
+		}
+
+		init_map(map);
+	}
+
+	/* Sanity check and configuration of private events for this CPU */
+	ev_num_so_far = -1;
+	for_each_private_map(i, map) {
+#if ENABLE_ASSERTIONS
+		/* Ensure mappings are sorted */
+		assert((ev_num_so_far < 0) || (map->ev_num > ev_num_so_far));
+
+		ev_num_so_far = map->ev_num;
+
+		if (map->ev_num == SDEI_EVENT_0) {
+			zero_found = true;
+
+			/* Event 0 must be a Secure SGI */
+			assert(is_secure_sgi(map->intr));
+
+			/*
+			 * Event 0 can have only have signalable flag (apart
+			 * from being private
+			 */
+			assert(map->map_flags == (SDEI_MAPF_SIGNALABLE |
+						SDEI_MAPF_PRIVATE));
+		} else {
+			/* No other mapping should have signalable property */
+			assert(!is_event_signalable(map));
+		}
+
+		/* Check for valid event */
+		assert(map->ev_num >= 0);
+
+		/* Make sure it's a private event */
+		assert(is_event_private(map));
+
+		/*
+		 * Other than priority, explicit events can only have explicit
+		 * and private flags set.
+		 */
+		if (is_map_explicit(map)) {
+			assert((map->map_flags | SDEI_MAPF_CRITICAL) ==
+					(SDEI_MAPF_EXPLICIT | SDEI_MAPF_PRIVATE
+					| SDEI_MAPF_CRITICAL));
+		}
+#endif
+
+		/* Skip initializing the wrong priority */
+		if (map_to_class(map) != class)
+			continue;
+
+		/* Platform events are always bound, so set the bound flag */
+		if (map->ev_num != SDEI_EVENT_0) {
+			if (is_map_dynamic(map)) {
+				assert(map->intr == SDEI_DYN_IRQ);
+				assert(is_event_normal(map));
+				num_dyn_priv_slots++;
+			} else if (is_map_explicit(map)) {
+				/*
+				 * Explicit mappings don't have a backing
+				 * SDEI interrupt, but verify that anyway.
+				 */
+				assert(map->intr == SDEI_DYN_IRQ);
+			} else {
+				/*
+				 * Private mappings must be bound to private
+				 * interrupt.
+				 */
+				assert(plat_ic_is_ppi((unsigned) map->intr) != 0);
+				set_map_bound(map);
+			}
+		}
+
+		init_map(map);
+	}
+
+	/* Ensure event 0 is in the mapping */
+	assert(zero_found);
+
+	(void) sdei_cpu_on_init(NULL);
+}
+
+/* SDEI dispatcher initialisation */
+void sdei_init(void)
+{
+	sdei_class_init(SDEI_CRITICAL);
+	sdei_class_init(SDEI_NORMAL);
+
+	/* Register priority level handlers */
+	ehf_register_priority_handler(PLAT_SDEI_CRITICAL_PRI,
+			sdei_intr_handler);
+	ehf_register_priority_handler(PLAT_SDEI_NORMAL_PRI,
+			sdei_intr_handler);
+}
+
+/* Populate SDEI event entry */
+static void set_sdei_entry(sdei_entry_t *se, uint64_t ep, uint64_t arg,
+		unsigned int flags, uint64_t affinity)
+{
+	assert(se != NULL);
+
+	se->ep = ep;
+	se->arg = arg;
+	se->affinity = (affinity & MPIDR_AFFINITY_MASK);
+	se->reg_flags = flags;
+}
+
+static uint64_t sdei_version(void)
+{
+	return MAKE_SDEI_VERSION(MAJOR_VERSION, MINOR_VERSION, VENDOR_VERSION);
+}
+
+/* Validate flags and MPIDR values for REGISTER and ROUTING_SET calls */
+static int validate_flags(uint64_t flags, uint64_t mpidr)
+{
+	/* Validate flags */
+	switch (flags) {
+	case SDEI_REGF_RM_PE:
+		if (!is_valid_affinity(mpidr))
+			return SDEI_EINVAL;
+		break;
+	case SDEI_REGF_RM_ANY:
+		break;
+	default:
+		/* Unknown flags */
+		return SDEI_EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set routing of an SDEI event */
+static int sdei_event_routing_set(int ev_num, uint64_t flags, uint64_t mpidr)
+{
+	int ret;
+	unsigned int routing;
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+
+	ret = validate_flags(flags, mpidr);
+	if (ret != 0)
+		return ret;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	/* The event must not be private */
+	if (is_event_private(map))
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+
+	sdei_map_lock(map);
+
+	if (!is_map_bound(map) || is_event_private(map)) {
+		ret = SDEI_EINVAL;
+		goto finish;
+	}
+
+	if (!can_sdei_state_trans(se, DO_ROUTING)) {
+		ret = SDEI_EDENY;
+		goto finish;
+	}
+
+	/* Choose appropriate routing */
+	routing = (unsigned int) ((flags == SDEI_REGF_RM_ANY) ?
+		INTR_ROUTING_MODE_ANY : INTR_ROUTING_MODE_PE);
+
+	/* Update event registration flag */
+	se->reg_flags = (unsigned int) flags;
+
+	/*
+	 * ROUTING_SET is permissible only when event composite state is
+	 * 'registered, disabled, and not running'. This means that the
+	 * interrupt is currently disabled, and not active.
+	 */
+	plat_ic_set_spi_routing(map->intr, routing, (u_register_t) mpidr);
+
+finish:
+	sdei_map_unlock(map);
+
+	return ret;
+}
+
+/* Register handler and argument for an SDEI event */
+static int64_t sdei_event_register(int ev_num, uint64_t ep, uint64_t arg,
+		uint64_t flags, uint64_t mpidr)
+{
+	int ret;
+	unsigned int routing;
+	sdei_entry_t *se;
+	sdei_ev_map_t *map;
+	sdei_state_t backup_state;
+
+	if ((ep == 0U) || (plat_sdei_validate_entry_point(
+					ep, sdei_client_el()) != 0)) {
+		return SDEI_EINVAL;
+	}
+
+	ret = validate_flags(flags, mpidr);
+	if (ret != 0)
+		return ret;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	/* Private events always target the PE */
+	if (is_event_private(map))
+		flags = SDEI_REGF_RM_PE;
+
+	se = get_event_entry(map);
+
+	/*
+	 * Even though register operation is per-event (additionally for private
+	 * events, registration is required individually), it has to be
+	 * serialised with respect to bind/release, which are global operations.
+	 * So we hold the lock throughout, unconditionally.
+	 */
+	sdei_map_lock(map);
+
+	backup_state = se->state;
+	if (!can_sdei_state_trans(se, DO_REGISTER))
+		goto fallback;
+
+	/*
+	 * When registering for dynamic events, make sure it's been bound
+	 * already. This has to be the case as, without binding, the client
+	 * can't know about the event number to register for.
+	 */
+	if (is_map_dynamic(map) && !is_map_bound(map))
+		goto fallback;
+
+	if (is_event_private(map)) {
+		/* Multiple calls to register are possible for private events */
+		assert(map->reg_count >= 0);
+	} else {
+		/* Only single call to register is possible for shared events */
+		assert(map->reg_count == 0);
+	}
+
+	if (is_map_bound(map)) {
+		/* Meanwhile, did any PE ACK the interrupt? */
+		if (plat_ic_get_interrupt_active(map->intr) != 0U)
+			goto fallback;
+
+		/* The interrupt must currently owned by Non-secure */
+		if (plat_ic_get_interrupt_type(map->intr) != INTR_TYPE_NS)
+			goto fallback;
+
+		/*
+		 * Disable forwarding of new interrupt triggers to CPU
+		 * interface.
+		 */
+		plat_ic_disable_interrupt(map->intr);
+
+		/*
+		 * Any events that are triggered after register and before
+		 * enable should remain pending. Clear any previous interrupt
+		 * triggers which are pending (except for SGIs). This has no
+		 * affect on level-triggered interrupts.
+		 */
+		if (ev_num != SDEI_EVENT_0)
+			plat_ic_clear_interrupt_pending(map->intr);
+
+		/* Map interrupt to EL3 and program the correct priority */
+		plat_ic_set_interrupt_type(map->intr, INTR_TYPE_EL3);
+
+		/* Program the appropriate interrupt priority */
+		plat_ic_set_interrupt_priority(map->intr, sdei_event_priority(map));
+
+		/*
+		 * Set the routing mode for shared event as requested. We
+		 * already ensure that shared events get bound to SPIs.
+		 */
+		if (is_event_shared(map)) {
+			routing = (unsigned int) ((flags == SDEI_REGF_RM_ANY) ?
+				INTR_ROUTING_MODE_ANY : INTR_ROUTING_MODE_PE);
+			plat_ic_set_spi_routing(map->intr, routing,
+					(u_register_t) mpidr);
+		}
+	}
+
+	/* Populate event entries */
+	set_sdei_entry(se, ep, arg, (unsigned int) flags, mpidr);
+
+	/* Increment register count */
+	map->reg_count++;
+
+	sdei_map_unlock(map);
+
+	return 0;
+
+fallback:
+	/* Reinstate previous state */
+	se->state = backup_state;
+
+	sdei_map_unlock(map);
+
+	return SDEI_EDENY;
+}
+
+/* Enable SDEI event */
+static int64_t sdei_event_enable(int ev_num)
+{
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+	int ret;
+	bool before, after;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+	ret = SDEI_EDENY;
+
+	if (is_event_shared(map))
+		sdei_map_lock(map);
+
+	before = GET_EV_STATE(se, ENABLED);
+	if (!can_sdei_state_trans(se, DO_ENABLE))
+		goto finish;
+	after = GET_EV_STATE(se, ENABLED);
+
+	/*
+	 * Enable interrupt for bound events only if there's a change in enabled
+	 * state.
+	 */
+	if (is_map_bound(map) && (!before && after))
+		plat_ic_enable_interrupt(map->intr);
+
+	ret = 0;
+
+finish:
+	if (is_event_shared(map))
+		sdei_map_unlock(map);
+
+	return ret;
+}
+
+/* Disable SDEI event */
+static int sdei_event_disable(int ev_num)
+{
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+	int ret;
+	bool before, after;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+	ret = SDEI_EDENY;
+
+	if (is_event_shared(map))
+		sdei_map_lock(map);
+
+	before = GET_EV_STATE(se, ENABLED);
+	if (!can_sdei_state_trans(se, DO_DISABLE))
+		goto finish;
+	after = GET_EV_STATE(se, ENABLED);
+
+	/*
+	 * Disable interrupt for bound events only if there's a change in
+	 * enabled state.
+	 */
+	if (is_map_bound(map) && (before && !after))
+		plat_ic_disable_interrupt(map->intr);
+
+	ret = 0;
+
+finish:
+	if (is_event_shared(map))
+		sdei_map_unlock(map);
+
+	return ret;
+}
+
+/* Query SDEI event information */
+static int64_t sdei_event_get_info(int ev_num, int info)
+{
+	sdei_entry_t *se;
+	sdei_ev_map_t *map;
+
+	uint64_t flags;
+	bool registered;
+	uint64_t affinity;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+
+	if (is_event_shared(map))
+		sdei_map_lock(map);
+
+	/* Sample state under lock */
+	registered = GET_EV_STATE(se, REGISTERED);
+	flags = se->reg_flags;
+	affinity = se->affinity;
+
+	if (is_event_shared(map))
+		sdei_map_unlock(map);
+
+	switch (info) {
+	case SDEI_INFO_EV_TYPE:
+		return is_event_shared(map);
+
+	case SDEI_INFO_EV_NOT_SIGNALED:
+		return !is_event_signalable(map);
+
+	case SDEI_INFO_EV_PRIORITY:
+		return is_event_critical(map);
+
+	case SDEI_INFO_EV_ROUTING_MODE:
+		if (!is_event_shared(map))
+			return SDEI_EINVAL;
+		if (!registered)
+			return SDEI_EDENY;
+		return (flags == SDEI_REGF_RM_PE);
+
+	case SDEI_INFO_EV_ROUTING_AFF:
+		if (!is_event_shared(map))
+			return SDEI_EINVAL;
+		if (!registered)
+			return SDEI_EDENY;
+		if (flags != SDEI_REGF_RM_PE)
+			return SDEI_EINVAL;
+		return affinity;
+
+	default:
+		return SDEI_EINVAL;
+	}
+}
+
+/* Unregister an SDEI event */
+static int sdei_event_unregister(int ev_num)
+{
+	int ret = 0;
+	sdei_entry_t *se;
+	sdei_ev_map_t *map;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+
+	/*
+	 * Even though unregister operation is per-event (additionally for
+	 * private events, unregistration is required individually), it has to
+	 * be serialised with respect to bind/release, which are global
+	 * operations.  So we hold the lock throughout, unconditionally.
+	 */
+	sdei_map_lock(map);
+
+	if (!can_sdei_state_trans(se, DO_UNREGISTER)) {
+		/*
+		 * Even if the call is invalid, and the handler is running (for
+		 * example, having unregistered from a running handler earlier),
+		 * return pending error code; otherwise, return deny.
+		 */
+		ret = GET_EV_STATE(se, RUNNING) ? SDEI_EPEND : SDEI_EDENY;
+
+		goto finish;
+	}
+
+	map->reg_count--;
+	if (is_event_private(map)) {
+		/* Multiple calls to register are possible for private events */
+		assert(map->reg_count >= 0);
+	} else {
+		/* Only single call to register is possible for shared events */
+		assert(map->reg_count == 0);
+	}
+
+	if (is_map_bound(map)) {
+		plat_ic_disable_interrupt(map->intr);
+
+		/*
+		 * Clear pending interrupt. Skip for SGIs as they may not be
+		 * cleared on interrupt controllers.
+		 */
+		if (ev_num != SDEI_EVENT_0)
+			plat_ic_clear_interrupt_pending(map->intr);
+
+		assert(plat_ic_get_interrupt_type(map->intr) == INTR_TYPE_EL3);
+		plat_ic_set_interrupt_type(map->intr, INTR_TYPE_NS);
+		plat_ic_set_interrupt_priority(map->intr, LOWEST_INTR_PRIORITY);
+	}
+
+	clear_event_entries(se);
+
+	/*
+	 * If the handler is running at the time of unregister, return the
+	 * pending error code.
+	 */
+	if (GET_EV_STATE(se, RUNNING))
+		ret = SDEI_EPEND;
+
+finish:
+	sdei_map_unlock(map);
+
+	return ret;
+}
+
+/* Query status of an SDEI event */
+static int sdei_event_status(int ev_num)
+{
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+	sdei_state_t state;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+
+	if (is_event_shared(map))
+		sdei_map_lock(map);
+
+	/* State value directly maps to the expected return format */
+	state = se->state;
+
+	if (is_event_shared(map))
+		sdei_map_unlock(map);
+
+	return (int) state;
+}
+
+/* Bind an SDEI event to an interrupt */
+static int sdei_interrupt_bind(unsigned int intr_num)
+{
+	sdei_ev_map_t *map;
+	bool retry = true, shared_mapping;
+
+	/* SGIs are not allowed to be bound */
+	if (plat_ic_is_sgi(intr_num) != 0)
+		return SDEI_EINVAL;
+
+	shared_mapping = (plat_ic_is_spi(intr_num) != 0);
+	do {
+		/*
+		 * Bail out if there is already an event for this interrupt,
+		 * either platform-defined or dynamic.
+		 */
+		map = find_event_map_by_intr(intr_num, shared_mapping);
+		if (map != NULL) {
+			if (is_map_dynamic(map)) {
+				if (is_map_bound(map)) {
+					/*
+					 * Dynamic event, already bound. Return
+					 * event number.
+					 */
+					return map->ev_num;
+				}
+			} else {
+				/* Binding non-dynamic event */
+				return SDEI_EINVAL;
+			}
+		}
+
+		/*
+		 * The interrupt is not bound yet. Try to find a free slot to
+		 * bind it. Free dynamic mappings have their interrupt set as
+		 * SDEI_DYN_IRQ.
+		 */
+		map = find_event_map_by_intr(SDEI_DYN_IRQ, shared_mapping);
+		if (map == NULL)
+			return SDEI_ENOMEM;
+
+		/* The returned mapping must be dynamic */
+		assert(is_map_dynamic(map));
+
+		/*
+		 * We cannot assert for bound maps here, as we might be racing
+		 * with another bind.
+		 */
+
+		/* The requested interrupt must already belong to NS */
+		if (plat_ic_get_interrupt_type(intr_num) != INTR_TYPE_NS)
+			return SDEI_EDENY;
+
+		/*
+		 * Interrupt programming and ownership transfer are deferred
+		 * until register.
+		 */
+
+		sdei_map_lock(map);
+		if (!is_map_bound(map)) {
+			map->intr = intr_num;
+			set_map_bound(map);
+			retry = false;
+		}
+		sdei_map_unlock(map);
+	} while (retry);
+
+	return map->ev_num;
+}
+
+/* Release a bound SDEI event previously to an interrupt */
+static int sdei_interrupt_release(int ev_num)
+{
+	int ret = 0;
+	sdei_ev_map_t *map;
+	sdei_entry_t *se;
+
+	/* Check if valid event number */
+	map = find_event_map(ev_num);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	if (!is_map_dynamic(map))
+		return SDEI_EINVAL;
+
+	se = get_event_entry(map);
+
+	sdei_map_lock(map);
+
+	/* Event must have been unregistered before release */
+	if (map->reg_count != 0) {
+		ret = SDEI_EDENY;
+		goto finish;
+	}
+
+	/*
+	 * Interrupt release never causes the state to change. We only check
+	 * whether it's permissible or not.
+	 */
+	if (!can_sdei_state_trans(se, DO_RELEASE)) {
+		ret = SDEI_EDENY;
+		goto finish;
+	}
+
+	if (is_map_bound(map)) {
+		/*
+		 * Deny release if the interrupt is active, which means it's
+		 * probably being acknowledged and handled elsewhere.
+		 */
+		if (plat_ic_get_interrupt_active(map->intr) != 0U) {
+			ret = SDEI_EDENY;
+			goto finish;
+		}
+
+		/*
+		 * Interrupt programming and ownership transfer are already done
+		 * during unregister.
+		 */
+
+		map->intr = SDEI_DYN_IRQ;
+		clr_map_bound(map);
+	} else {
+		SDEI_LOG("Error release bound:%d cnt:%d\n", is_map_bound(map),
+				map->reg_count);
+		ret = SDEI_EINVAL;
+	}
+
+finish:
+	sdei_map_unlock(map);
+
+	return ret;
+}
+
+/* Perform reset of private SDEI events */
+static int sdei_private_reset(void)
+{
+	sdei_ev_map_t *map;
+	int ret = 0, final_ret = 0;
+	unsigned int i;
+
+	/* Unregister all private events */
+	for_each_private_map(i, map) {
+		/*
+		 * The unregister can fail if the event is not registered, which
+		 * is allowed, and a deny will be returned. But if the event is
+		 * running or unregister pending, the call fails.
+		 */
+		ret = sdei_event_unregister(map->ev_num);
+		if ((ret == SDEI_EPEND) && (final_ret == 0))
+			final_ret = SDEI_EDENY;
+	}
+
+	return final_ret;
+}
+
+/* Perform reset of shared SDEI events */
+static int sdei_shared_reset(void)
+{
+	const sdei_mapping_t *mapping;
+	sdei_ev_map_t *map;
+	int ret = 0, final_ret = 0;
+	unsigned int i, j;
+
+	/* Unregister all shared events */
+	for_each_shared_map(i, map) {
+		/*
+		 * The unregister can fail if the event is not registered, which
+		 * is allowed, and a deny will be returned. But if the event is
+		 * running or unregister pending, the call fails.
+		 */
+		ret = sdei_event_unregister(map->ev_num);
+		if ((ret == SDEI_EPEND) && (final_ret == 0))
+			final_ret = SDEI_EDENY;
+	}
+
+	if (final_ret != 0)
+		return final_ret;
+
+	/*
+	 * Loop through both private and shared mappings, and release all
+	 * bindings.
+	 */
+	for_each_mapping_type(i, mapping) {
+		iterate_mapping(mapping, j, map) {
+			/*
+			 * Release bindings for mappings that are dynamic and
+			 * bound.
+			 */
+			if (is_map_dynamic(map) && is_map_bound(map)) {
+				/*
+				 * Any failure to release would mean there is at
+				 * least a PE registered for the event.
+				 */
+				ret = sdei_interrupt_release(map->ev_num);
+				if ((ret != 0) && (final_ret == 0))
+					final_ret = ret;
+			}
+		}
+	}
+
+	return final_ret;
+}
+
+/* Send a signal to another SDEI client PE */
+static int sdei_signal(int ev_num, uint64_t target_pe)
+{
+	sdei_ev_map_t *map;
+
+	/* Only event 0 can be signalled */
+	if (ev_num != SDEI_EVENT_0)
+		return SDEI_EINVAL;
+
+	/* Find mapping for event 0 */
+	map = find_event_map(SDEI_EVENT_0);
+	if (map == NULL)
+		return SDEI_EINVAL;
+
+	/* The event must be signalable */
+	if (!is_event_signalable(map))
+		return SDEI_EINVAL;
+
+	/* Validate target */
+	if (plat_core_pos_by_mpidr(target_pe) < 0)
+		return SDEI_EINVAL;
+
+	/* Raise SGI. Platform will validate target_pe */
+	plat_ic_raise_el3_sgi((int) map->intr, (u_register_t) target_pe);
+
+	return 0;
+}
+
+/* Query SDEI dispatcher features */
+static uint64_t sdei_features(unsigned int feature)
+{
+	if (feature == SDEI_FEATURE_BIND_SLOTS) {
+		return FEATURE_BIND_SLOTS(num_dyn_priv_slots,
+				num_dyn_shrd_slots);
+	}
+
+	return (uint64_t) SDEI_EINVAL;
+}
+
+/* SDEI top level handler for servicing SMCs */
+uint64_t sdei_smc_handler(uint32_t smc_fid,
+			  uint64_t x1,
+			  uint64_t x2,
+			  uint64_t x3,
+			  uint64_t x4,
+			  void *cookie,
+			  void *handle,
+			  uint64_t flags)
+{
+
+	uint64_t x5;
+	unsigned int ss = (unsigned int) get_interrupt_src_ss(flags);
+	int64_t ret;
+	bool resume = false;
+	cpu_context_t *ctx = handle;
+	int ev_num = (int) x1;
+
+	if (ss != NON_SECURE)
+		SMC_RET1(ctx, SMC_UNK);
+
+	/* Verify the caller EL */
+	if (GET_EL(read_spsr_el3()) != sdei_client_el())
+		SMC_RET1(ctx, SMC_UNK);
+
+	switch (smc_fid) {
+	case SDEI_VERSION:
+		SDEI_LOG("> VER\n");
+		ret = (int64_t) sdei_version();
+		SDEI_LOG("< VER:%llx\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_REGISTER:
+		x5 = SMC_GET_GP(ctx, CTX_GPREG_X5);
+		SDEI_LOG("> REG(n:%d e:%llx a:%llx f:%x m:%llx)\n", ev_num,
+				x2, x3, (int) x4, x5);
+		ret = sdei_event_register(ev_num, x2, x3, x4, x5);
+		SDEI_LOG("< REG:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_ENABLE:
+		SDEI_LOG("> ENABLE(n:%d)\n", (int) x1);
+		ret = sdei_event_enable(ev_num);
+		SDEI_LOG("< ENABLE:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_DISABLE:
+		SDEI_LOG("> DISABLE(n:%d)\n", ev_num);
+		ret = sdei_event_disable(ev_num);
+		SDEI_LOG("< DISABLE:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_CONTEXT:
+		SDEI_LOG("> CTX(p:%d):%lx\n", (int) x1, read_mpidr_el1());
+		ret = sdei_event_context(ctx, (unsigned int) x1);
+		SDEI_LOG("< CTX:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_COMPLETE_AND_RESUME:
+		resume = true;
+		/* Fallthrough */
+
+	case SDEI_EVENT_COMPLETE:
+		SDEI_LOG("> COMPLETE(r:%u sta/ep:%llx):%lx\n",
+				(unsigned int) resume, x1, read_mpidr_el1());
+		ret = sdei_event_complete(resume, x1);
+		SDEI_LOG("< COMPLETE:%llx\n", ret);
+
+		/*
+		 * Set error code only if the call failed. If the call
+		 * succeeded, we discard the dispatched context, and restore the
+		 * interrupted context to a pristine condition, and therefore
+		 * shouldn't be modified. We don't return to the caller in this
+		 * case anyway.
+		 */
+		if (ret != 0)
+			SMC_RET1(ctx, ret);
+
+		SMC_RET0(ctx);
+
+	case SDEI_EVENT_STATUS:
+		SDEI_LOG("> STAT(n:%d)\n", ev_num);
+		ret = sdei_event_status(ev_num);
+		SDEI_LOG("< STAT:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_GET_INFO:
+		SDEI_LOG("> INFO(n:%d, %d)\n", ev_num, (int) x2);
+		ret = sdei_event_get_info(ev_num, (int) x2);
+		SDEI_LOG("< INFO:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_UNREGISTER:
+		SDEI_LOG("> UNREG(n:%d)\n", ev_num);
+		ret = sdei_event_unregister(ev_num);
+		SDEI_LOG("< UNREG:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_PE_UNMASK:
+		SDEI_LOG("> UNMASK:%lx\n", read_mpidr_el1());
+		sdei_pe_unmask();
+		SDEI_LOG("< UNMASK:%d\n", 0);
+		SMC_RET1(ctx, 0);
+
+	case SDEI_PE_MASK:
+		SDEI_LOG("> MASK:%lx\n", read_mpidr_el1());
+		ret = sdei_pe_mask();
+		SDEI_LOG("< MASK:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_INTERRUPT_BIND:
+		SDEI_LOG("> BIND(%d)\n", (int) x1);
+		ret = sdei_interrupt_bind((unsigned int) x1);
+		SDEI_LOG("< BIND:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_INTERRUPT_RELEASE:
+		SDEI_LOG("> REL(%d)\n", ev_num);
+		ret = sdei_interrupt_release(ev_num);
+		SDEI_LOG("< REL:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_SHARED_RESET:
+		SDEI_LOG("> S_RESET():%lx\n", read_mpidr_el1());
+		ret = sdei_shared_reset();
+		SDEI_LOG("< S_RESET:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_PRIVATE_RESET:
+		SDEI_LOG("> P_RESET():%lx\n", read_mpidr_el1());
+		ret = sdei_private_reset();
+		SDEI_LOG("< P_RESET:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_ROUTING_SET:
+		SDEI_LOG("> ROUTE_SET(n:%d f:%llx aff:%llx)\n", ev_num, x2, x3);
+		ret = sdei_event_routing_set(ev_num, x2, x3);
+		SDEI_LOG("< ROUTE_SET:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_FEATURES:
+		SDEI_LOG("> FTRS(f:%llx)\n", x1);
+		ret = (int64_t) sdei_features((unsigned int) x1);
+		SDEI_LOG("< FTRS:%llx\n", ret);
+		SMC_RET1(ctx, ret);
+
+	case SDEI_EVENT_SIGNAL:
+		SDEI_LOG("> SIGNAL(e:%d t:%llx)\n", ev_num, x2);
+		ret = sdei_signal(ev_num, x2);
+		SDEI_LOG("< SIGNAL:%lld\n", ret);
+		SMC_RET1(ctx, ret);
+
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	WARN("Unimplemented SDEI Call: 0x%x\n", smc_fid);
+	SMC_RET1(ctx, SMC_UNK);
+}
+
+/* Subscribe to PSCI CPU on to initialize per-CPU SDEI configuration */
+SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, sdei_cpu_on_init);
+
+/* Subscribe to PSCI CPU suspend finisher for per-CPU configuration */
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, sdei_cpu_wakeup_init);
diff --git a/services/std_svc/sdei/sdei_private.h b/services/std_svc/sdei/sdei_private.h
new file mode 100644
index 0000000..44a7301
--- /dev/null
+++ b/services/std_svc/sdei/sdei_private.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDEI_PRIVATE_H
+#define SDEI_PRIVATE_H
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <plat/common/platform.h>
+#include <services/sdei.h>
+#include <setjmp.h>
+
+#ifndef __aarch64__
+# error SDEI is implemented only for AArch64 systems
+#endif
+
+#ifndef PLAT_SDEI_CRITICAL_PRI
+# error Platform must define SDEI critical priority value
+#endif
+
+#ifndef PLAT_SDEI_NORMAL_PRI
+# error Platform must define SDEI normal priority value
+#endif
+
+/* Output SDEI logs as verbose */
+#define SDEI_LOG(...)	VERBOSE("SDEI: " __VA_ARGS__)
+
+/* SDEI handler unregistered state. This is the default state. */
+#define SDEI_STATE_UNREGISTERED		0U
+
+/* SDE event status values in bit position */
+#define SDEI_STATF_REGISTERED		0U
+#define SDEI_STATF_ENABLED		1U
+#define SDEI_STATF_RUNNING		2U
+
+/* SDEI SMC error codes */
+#define	SDEI_EINVAL	(-2)
+#define	SDEI_EDENY	(-3)
+#define	SDEI_EPEND	(-5)
+#define	SDEI_ENOMEM	(-10)
+
+/*
+ * 'info' parameter to SDEI_EVENT_GET_INFO SMC.
+ *
+ * Note that the SDEI v1.0 specification mistakenly enumerates the
+ * SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a
+ * future version.
+ */
+#define SDEI_INFO_EV_TYPE		0
+#define SDEI_INFO_EV_NOT_SIGNALED	1
+#define SDEI_INFO_EV_PRIORITY		2
+#define SDEI_INFO_EV_ROUTING_MODE	3
+#define SDEI_INFO_EV_ROUTING_AFF	4
+
+#define SDEI_PRIVATE_MAPPING()	(&sdei_global_mappings[SDEI_MAP_IDX_PRIV_])
+#define SDEI_SHARED_MAPPING()	(&sdei_global_mappings[SDEI_MAP_IDX_SHRD_])
+
+#define for_each_mapping_type(_i, _mapping) \
+	for ((_i) = 0, (_mapping) = &sdei_global_mappings[(_i)]; \
+			(_i) < SDEI_MAP_IDX_MAX_; \
+			(_i)++, (_mapping) = &sdei_global_mappings[(_i)])
+
+#define iterate_mapping(_mapping, _i, _map) \
+	for ((_map) = (_mapping)->map, (_i) = 0; \
+			(_i) < (_mapping)->num_maps; \
+			(_i)++, (_map)++)
+
+#define for_each_private_map(_i, _map) \
+	iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map)
+
+#define for_each_shared_map(_i, _map) \
+	iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map)
+
+/* SDEI_FEATURES */
+#define SDEI_FEATURE_BIND_SLOTS		0U
+#define BIND_SLOTS_MASK			0xffffU
+#define FEATURES_SHARED_SLOTS_SHIFT	16U
+#define FEATURES_PRIVATE_SLOTS_SHIFT	0U
+#define FEATURE_BIND_SLOTS(_priv, _shrd) \
+	(((((uint64_t) (_priv)) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \
+	 ((((uint64_t) (_shrd)) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT))
+
+#define GET_EV_STATE(_e, _s)	get_ev_state_bit(_e, SDEI_STATF_##_s)
+#define SET_EV_STATE(_e, _s)	clr_ev_state_bit(_e->state, SDEI_STATF_##_s)
+
+static inline bool is_event_private(sdei_ev_map_t *map)
+{
+	return ((map->map_flags & BIT_32(SDEI_MAPF_PRIVATE_SHIFT_)) != 0U);
+}
+
+static inline bool is_event_shared(sdei_ev_map_t *map)
+{
+	return !is_event_private(map);
+}
+
+static inline bool is_event_critical(sdei_ev_map_t *map)
+{
+	return ((map->map_flags & BIT_32(SDEI_MAPF_CRITICAL_SHIFT_)) != 0U);
+}
+
+static inline bool is_event_normal(sdei_ev_map_t *map)
+{
+	return !is_event_critical(map);
+}
+
+static inline bool is_event_signalable(sdei_ev_map_t *map)
+{
+	return ((map->map_flags & BIT_32(SDEI_MAPF_SIGNALABLE_SHIFT_)) != 0U);
+}
+
+static inline bool is_map_dynamic(sdei_ev_map_t *map)
+{
+	return ((map->map_flags & BIT_32(SDEI_MAPF_DYNAMIC_SHIFT_)) != 0U);
+}
+
+/*
+ * Checks whether an event is associated with an interrupt. Static events always
+ * return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been
+ * called on them. This can be used on both static or dynamic events to check
+ * for an associated interrupt.
+ */
+static inline bool is_map_bound(sdei_ev_map_t *map)
+{
+	return ((map->map_flags & BIT_32(SDEI_MAPF_BOUND_SHIFT_)) != 0U);
+}
+
+static inline void set_map_bound(sdei_ev_map_t *map)
+{
+	map->map_flags |= BIT_32(SDEI_MAPF_BOUND_SHIFT_);
+}
+
+static inline bool is_map_explicit(sdei_ev_map_t *map)
+{
+	return ((map->map_flags & BIT_32(SDEI_MAPF_EXPLICIT_SHIFT_)) != 0U);
+}
+
+static inline void clr_map_bound(sdei_ev_map_t *map)
+{
+	map->map_flags &= ~BIT_32(SDEI_MAPF_BOUND_SHIFT_);
+}
+
+static inline bool is_secure_sgi(unsigned int intr)
+{
+	return ((plat_ic_is_sgi(intr) != 0) &&
+			(plat_ic_get_interrupt_type(intr) == INTR_TYPE_EL3));
+}
+
+/*
+ * Determine EL of the client. If EL2 is implemented (hence the enabled HCE
+ * bit), deem EL2; otherwise, deem EL1.
+ */
+static inline unsigned int sdei_client_el(void)
+{
+	cpu_context_t *ns_ctx = cm_get_context(NON_SECURE);
+	el3_state_t *el3_ctx = get_el3state_ctx(ns_ctx);
+
+	return ((read_ctx_reg(el3_ctx, CTX_SCR_EL3) & SCR_HCE_BIT) != 0U) ?
+		MODE_EL2 : MODE_EL1;
+}
+
+static inline unsigned int sdei_event_priority(sdei_ev_map_t *map)
+{
+	return (unsigned int) (is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI :
+			PLAT_SDEI_NORMAL_PRI);
+}
+
+static inline bool get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no)
+{
+	return ((se->state & BIT_32(bit_no)) != 0U);
+}
+
+static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no)
+{
+	se->state &= ~BIT_32(bit_no);
+}
+
+/* SDEI actions for state transition */
+typedef enum {
+	/*
+	 * Actions resulting from client requests. These directly map to SMC
+	 * calls. Note that the state table columns are listed in this order
+	 * too.
+	 */
+	DO_REGISTER = 0,
+	DO_RELEASE = 1,
+	DO_ENABLE = 2,
+	DO_DISABLE = 3,
+	DO_UNREGISTER = 4,
+	DO_ROUTING = 5,
+	DO_CONTEXT = 6,
+	DO_COMPLETE = 7,
+	DO_COMPLETE_RESUME = 8,
+
+	/* Action for event dispatch */
+	DO_DISPATCH = 9,
+
+	DO_MAX,
+} sdei_action_t;
+
+typedef enum {
+	SDEI_NORMAL,
+	SDEI_CRITICAL
+} sdei_class_t;
+
+static inline void sdei_map_lock(sdei_ev_map_t *map)
+{
+	spin_lock(&map->lock);
+}
+
+static inline void sdei_map_unlock(sdei_ev_map_t *map)
+{
+	spin_unlock(&map->lock);
+}
+
+extern const sdei_mapping_t sdei_global_mappings[];
+extern sdei_entry_t sdei_private_event_table[];
+extern sdei_entry_t sdei_shared_event_table[];
+
+void init_sdei_state(void);
+
+sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared);
+sdei_ev_map_t *find_event_map(int ev_num);
+sdei_entry_t *get_event_entry(sdei_ev_map_t *map);
+
+int64_t sdei_event_context(void *handle, unsigned int param);
+int sdei_event_complete(bool resume, uint64_t pc);
+
+void sdei_pe_unmask(void);
+int64_t sdei_pe_mask(void);
+
+int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle,
+		void *cookie);
+bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act);
+void begin_sdei_synchronous_dispatch(jmp_buf *buffer);
+
+#endif /* SDEI_PRIVATE_H */
diff --git a/services/std_svc/sdei/sdei_state.c b/services/std_svc/sdei/sdei_state.c
new file mode 100644
index 0000000..1b448e6
--- /dev/null
+++ b/services/std_svc/sdei/sdei_state.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <lib/cassert.h>
+
+#include "sdei_private.h"
+
+/* Aliases for SDEI handler states: 'R'unning, 'E'nabled, and re'G'istered */
+#define r_		0U
+#define R_		(1u << SDEI_STATF_RUNNING)
+
+#define e_		0U
+#define E_		(1u << SDEI_STATF_ENABLED)
+
+#define g_		0U
+#define G_		(1u << SDEI_STATF_REGISTERED)
+
+/* All possible composite handler states */
+#define reg_		(r_ | e_ | g_)
+#define reG_		(r_ | e_ | G_)
+#define rEg_		(r_ | E_ | g_)
+#define rEG_		(r_ | E_ | G_)
+#define Reg_		(R_ | e_ | g_)
+#define ReG_		(R_ | e_ | G_)
+#define REg_		(R_ | E_ | g_)
+#define REG_		(R_ | E_ | G_)
+
+#define MAX_STATES	(REG_ + 1u)
+
+/* Invalid state */
+#define	SDEI_STATE_INVALID	((sdei_state_t) (-1))
+
+/* No change in state */
+#define	SDEI_STATE_NOP		((sdei_state_t) (-2))
+
+#define X___		SDEI_STATE_INVALID
+#define NOP_		SDEI_STATE_NOP
+
+/* Ensure special states don't overlap with valid ones */
+CASSERT(X___ > REG_, sdei_state_overlap_invalid);
+CASSERT(NOP_ > REG_, sdei_state_overlap_nop);
+
+/*
+ * SDEI handler state machine: refer to sections 6.1 and 6.1.2 of the SDEI v1.0
+ * specification (ARM DEN0054A).
+ *
+ * Not all calls contribute to handler state transition. This table is also used
+ * to validate whether a call is permissible at a given handler state:
+ *
+ *  - X___ denotes a forbidden transition;
+ *  - NOP_ denotes a permitted transition, but there's no change in state;
+ *  - Otherwise, XXX_ gives the new state.
+ *
+ * DISP[atch] is a transition added for the implementation, but is not mentioned
+ * in the spec.
+ *
+ * Those calls that the spec mentions as can be made any time don't picture in
+ * this table.
+ */
+
+static const sdei_state_t sdei_state_table[MAX_STATES][DO_MAX] = {
+/*
+ *	Action:		REG     REL	ENA	DISA	UREG	ROUT	CTX	COMP	COMPR	DISP
+ *	Notes:			[3]			[1]	[3]	[3][4]			[2]
+ */
+	/* Handler unregistered, disabled, and not running. This is the default state. */
+/* 0 */	[reg_] = {	reG_,	NOP_,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	},
+
+	/* Handler unregistered and running */
+/* 4 */	[Reg_] = {	X___,	X___,	X___,	X___,	X___,	X___,	NOP_,	reg_,	reg_,	X___,	},
+
+	/* Handler registered */
+/* 1 */	[reG_] = {	X___,	X___,	rEG_,	NOP_,	reg_,	NOP_,	X___,	X___,	X___,	X___,	},
+
+	/* Handler registered and running */
+/* 5 */	[ReG_] = {	X___,	X___,	REG_,	NOP_,	Reg_,	X___,	NOP_,	reG_,	reG_,	X___,	},
+
+	/* Handler registered and enabled */
+/* 3 */	[rEG_] = {	X___,	X___,	NOP_,	reG_,	reg_,	X___,	X___,	X___,	X___,	REG_,	},
+
+	/* Handler registered, enabled, and running */
+/* 7 */	[REG_] = {	X___,	X___,	NOP_,	ReG_,	Reg_,	X___,	NOP_,	rEG_,	rEG_,	X___,	},
+
+	/*
+	 * Invalid states: no valid transition would leave the handler in these
+	 * states; and no transition from these states is possible either.
+	 */
+
+	/*
+	 * Handler can't be enabled without being registered. I.e., XEg is
+	 * impossible.
+	 */
+/* 2 */	[rEg_] = {	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	},
+/* 6 */	[REg_] = {	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	X___,	},
+};
+
+/*
+ * [1] Unregister will always also disable the event, so the new state will have
+ *     Xeg.
+ * [2] Event is considered for dispatch only when it's both registered and
+ *     enabled.
+ * [3] Never causes change in state.
+ * [4] Only allowed when running.
+ */
+
+/*
+ * Given an action, transition the state of an event by looking up the state
+ * table above:
+ *
+ *  - Return false for invalid transition;
+ *  - Return true for valid transition that causes no change in state;
+ *  - Otherwise, update state and return true.
+ *
+ * This function assumes that the caller holds necessary locks. If the
+ * transition has constrains other than the state table describes, the caller is
+ * expected to restore the previous state. See sdei_event_register() for
+ * example.
+ */
+bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act)
+{
+	sdei_state_t next;
+
+	assert(act < DO_MAX);
+	if (se->state >= MAX_STATES) {
+		WARN(" event state invalid: %x\n", se->state);
+		return false;
+	}
+
+	next = sdei_state_table[se->state][act];
+	switch (next) {
+	case SDEI_STATE_INVALID:
+		return false;
+
+	case SDEI_STATE_NOP:
+		return true;
+
+	default:
+		/* Valid transition. Update state. */
+		SDEI_LOG(" event state 0x%x => 0x%x\n", se->state, next);
+		se->state = next;
+
+		return true;
+	}
+}
diff --git a/services/std_svc/spm/README.rst b/services/std_svc/spm/README.rst
new file mode 100644
index 0000000..63406a3
--- /dev/null
+++ b/services/std_svc/spm/README.rst
@@ -0,0 +1,3 @@
+This is a prototype loosely based on the SPCI Alpha and SPRT pre-alpha
+specifications. Any interface / platform API introduced for this is subject to
+change as it evolves.
diff --git a/services/std_svc/spm/aarch64/spm_helpers.S b/services/std_svc/spm/aarch64/spm_helpers.S
new file mode 100644
index 0000000..aa35811
--- /dev/null
+++ b/services/std_svc/spm/aarch64/spm_helpers.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "../spm_private.h"
+
+	.global spm_secure_partition_enter
+	.global spm_secure_partition_exit
+
+	/* ---------------------------------------------------------------------
+	 * This function is called with SP_EL0 as stack. Here we stash our EL3
+	 * callee-saved registers on to the stack as a part of saving the C
+	 * runtime and enter the secure payload.
+	 * 'x0' contains a pointer to the memory where the address of the C
+	 *  runtime context is to be saved.
+	 * ---------------------------------------------------------------------
+	 */
+func spm_secure_partition_enter
+	/* Make space for the registers that we're going to save */
+	mov	x3, sp
+	str	x3, [x0, #0]
+	sub	sp, sp, #SP_C_RT_CTX_SIZE
+
+	/* Save callee-saved registers on to the stack */
+	stp	x19, x20, [sp, #SP_C_RT_CTX_X19]
+	stp	x21, x22, [sp, #SP_C_RT_CTX_X21]
+	stp	x23, x24, [sp, #SP_C_RT_CTX_X23]
+	stp	x25, x26, [sp, #SP_C_RT_CTX_X25]
+	stp	x27, x28, [sp, #SP_C_RT_CTX_X27]
+	stp	x29, x30, [sp, #SP_C_RT_CTX_X29]
+
+	/* ---------------------------------------------------------------------
+	 * Everything is setup now. el3_exit() will use the secure context to
+	 * restore to the general purpose and EL3 system registers to ERET
+	 * into the secure payload.
+	 * ---------------------------------------------------------------------
+	 */
+	b	el3_exit
+endfunc spm_secure_partition_enter
+
+	/* ---------------------------------------------------------------------
+	 * This function is called with 'x0' pointing to a C runtime context
+	 * saved in spm_secure_partition_enter().
+	 * It restores the saved registers and jumps to that runtime with 'x0'
+	 * as the new SP register. This destroys the C runtime context that had
+	 * been built on the stack below the saved context by the caller. Later
+	 * the second parameter 'x1' is passed as a return value to the caller.
+	 * ---------------------------------------------------------------------
+	 */
+func spm_secure_partition_exit
+	/* Restore the previous stack */
+	mov	sp, x0
+
+	/* Restore callee-saved registers on to the stack */
+	ldp	x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)]
+	ldp	x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)]
+	ldp	x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)]
+	ldp	x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)]
+	ldp	x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)]
+	ldp	x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)]
+
+	/* ---------------------------------------------------------------------
+	 * This should take us back to the instruction after the call to the
+	 * last spm_secure_partition_enter().* Place the second parameter to x0
+	 * so that the caller will see it as a return value from the original
+	 * entry call.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	x0, x1
+	ret
+endfunc spm_secure_partition_exit
diff --git a/services/std_svc/spm/aarch64/spm_shim_exceptions.S b/services/std_svc/spm/aarch64/spm_shim_exceptions.S
new file mode 100644
index 0000000..dab6150
--- /dev/null
+++ b/services/std_svc/spm/aarch64/spm_shim_exceptions.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by the spm shim layer.
+ * -----------------------------------------------------------------------------
+ */
+	.globl	spm_shim_exceptions_ptr
+
+vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions
+
+	/* -----------------------------------------------------
+	 * Current EL with SP0 : 0x0 - 0x200
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry SynchronousExceptionSP0
+
+vector_entry IrqSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqSP0
+
+vector_entry FiqSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqSP0
+
+vector_entry SErrorSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorSP0
+
+	/* -----------------------------------------------------
+	 * Current EL with SPx: 0x200 - 0x400
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry SynchronousExceptionSPx
+
+vector_entry IrqSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqSPx
+
+vector_entry FiqSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqSPx
+
+vector_entry SErrorSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorSPx
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600. No exceptions
+	 * are handled since secure_partition does not implement
+	 * a lower EL
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA64, .spm_shim_exceptions
+	msr	tpidr_el1, x30
+	mrs	x30, esr_el1
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+	cmp	x30, #EC_AARCH64_SVC
+	b.eq 	do_smc
+
+	cmp	x30, #EC_AARCH32_SVC
+	b.eq	do_smc
+
+	cmp	x30, #EC_AARCH64_SYS
+	b.eq	handle_sys_trap
+
+	/* Fail in all the other cases */
+	b	panic
+
+	/* ---------------------------------------------
+	 * Tell SPM that we are done initialising
+	 * ---------------------------------------------
+	 */
+do_smc:
+	mrs	x30, tpidr_el1
+	smc	#0
+	eret
+
+	/* AArch64 system instructions trap are handled as a panic for now */
+handle_sys_trap:
+panic:
+	b	panic
+end_vector_entry SynchronousExceptionA64
+
+vector_entry IrqA64, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqA64
+
+vector_entry FiqA64, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqA64
+
+vector_entry SErrorA64, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorA64
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA32, .spm_shim_exceptions
+	b	.
+end_vector_entry SynchronousExceptionA32
+
+vector_entry IrqA32, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqA32
+
+vector_entry FiqA32, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqA32
+
+vector_entry SErrorA32, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorA32
diff --git a/services/std_svc/spm/spci.c b/services/std_svc/spm/spci.c
new file mode 100644
index 0000000..2e12a6c
--- /dev/null
+++ b/services/std_svc/spm/spci.c
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <services/spci_svc.h>
+#include <services/sprt_svc.h>
+#include <smccc_helpers.h>
+#include <sprt_host.h>
+
+#include "spm_private.h"
+
+/*******************************************************************************
+ * Macros to print UUIDs.
+ ******************************************************************************/
+#define PRINT_UUID_FORMAT	"%08x-%08x-%08x-%08x"
+#define PRINT_UUID_ARGS(x)	x[0], x[1], x[2], x[3]
+
+/*******************************************************************************
+ * Array of structs that contains information about all handles of Secure
+ * Services that are currently open.
+ ******************************************************************************/
+typedef enum spci_handle_status {
+	HANDLE_STATUS_CLOSED = 0,
+	HANDLE_STATUS_OPEN,
+} spci_handle_status_t;
+
+typedef struct spci_handle {
+	/* 16-bit value used as reference in all SPCI calls */
+	uint16_t handle;
+
+	/* Client ID of the client that requested the handle */
+	uint16_t client_id;
+
+	/* Current status of the handle */
+	spci_handle_status_t status;
+
+	/*
+	 * Context of the Secure Partition that provides the Secure Service
+	 * referenced by this handle.
+	 */
+	sp_context_t *sp_ctx;
+
+	/*
+	 * The same handle might be used for multiple requests, keep a reference
+	 * counter of them.
+	 */
+	unsigned int num_active_requests;
+} spci_handle_t;
+
+static spci_handle_t spci_handles[PLAT_SPCI_HANDLES_MAX_NUM];
+static spinlock_t spci_handles_lock;
+
+/*
+ * Given a handle and a client ID, return the element of the spci_handles
+ * array that contains the information of the handle. It can only return open
+ * handles. It returns NULL if it couldn't find the element in the array.
+ */
+static spci_handle_t *spci_handle_info_get(uint16_t handle, uint16_t client_id)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(spci_handles); i++) {
+		spci_handle_t *h = &(spci_handles[i]);
+
+		/* Only check for open handles */
+		if (h->status == HANDLE_STATUS_CLOSED) {
+			continue;
+		}
+
+		/* Check if either the handle or the client ID are different */
+		if ((h->handle != handle) || (h->client_id != client_id)) {
+			continue;
+		}
+
+		return h;
+	}
+
+	return NULL;
+}
+
+/*
+ * Returns a unique value for a handle. This function must be called while
+ * spci_handles_lock is locked. It returns 0 on success, -1 on error.
+ */
+static int spci_create_handle_value(uint16_t *handle)
+{
+	/*
+	 * Trivial implementation that relies on the fact that any handle will
+	 * be closed before 2^16 more handles have been opened.
+	 */
+	static uint16_t handle_count;
+
+	*handle = handle_count;
+
+	handle_count++;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Returns a unique token for a Secure Service request.
+ ******************************************************************************/
+static uint32_t spci_create_token_value(void)
+{
+	/*
+	 * Trivial implementation that relies on the fact that any response will
+	 * be read before 2^32 more service requests have been done.
+	 */
+	static uint32_t token_count;
+
+	return token_count++;
+}
+
+/*******************************************************************************
+ * This function looks for a Secure Partition that has a Secure Service
+ * identified by the given UUID. It returns a handle that the client can use to
+ * access the service, and an SPCI_*** error code.
+ ******************************************************************************/
+static uint64_t spci_service_handle_open_poll(void *handle, u_register_t x1,
+			u_register_t x2, u_register_t x3, u_register_t x4,
+			u_register_t x5, u_register_t x6, u_register_t x7)
+{
+	unsigned int i;
+	sp_context_t *sp_ptr;
+	uint16_t service_handle;
+
+	/* Bits 31:16 of w7 are reserved (MBZ). */
+	assert((x7 & 0xFFFF0000U) == 0);
+
+	uint16_t client_id = x7 & 0x0000FFFFU;
+	uint32_t uuid[4] = { x1, x2, x3, x4 };
+
+	/* Get pointer to the Secure Partition that handles this service */
+	sp_ptr = spm_sp_get_by_uuid(&uuid);
+	if (sp_ptr == NULL) {
+		WARN("SPCI: Service requested by client 0x%04x not found\n",
+		     client_id);
+		WARN("SPCI:   UUID: " PRINT_UUID_FORMAT "\n",
+		     PRINT_UUID_ARGS(uuid));
+
+		SMC_RET2(handle, SPCI_NOT_PRESENT, 0);
+	}
+
+	/* Get lock of the array of handles */
+	spin_lock(&spci_handles_lock);
+
+	/*
+	 * We need to record the client ID and Secure Partition that correspond
+	 * to this handle. Look for the first free entry in the array.
+	 */
+	for (i = 0; i < PLAT_SPCI_HANDLES_MAX_NUM; i++) {
+		if (spci_handles[i].status == HANDLE_STATUS_CLOSED) {
+			break;
+		}
+	}
+
+	if (i == PLAT_SPCI_HANDLES_MAX_NUM) {
+		spin_unlock(&spci_handles_lock);
+
+		WARN("SPCI: Can't open more handles. Client 0x%04x\n",
+		     client_id);
+		WARN("SPCI:   UUID: " PRINT_UUID_FORMAT "\n",
+		     PRINT_UUID_ARGS(uuid));
+
+		SMC_RET2(handle, SPCI_NO_MEMORY, 0);
+	}
+
+	/* Create new handle value */
+	if (spci_create_handle_value(&service_handle) != 0) {
+		spin_unlock(&spci_handles_lock);
+
+		WARN("SPCI: Can't create a new handle value. Client 0x%04x\n",
+		     client_id);
+		WARN("SPCI:   UUID: " PRINT_UUID_FORMAT "\n",
+		     PRINT_UUID_ARGS(uuid));
+
+		SMC_RET2(handle, SPCI_NO_MEMORY, 0);
+	}
+
+	/* Save all information about this handle */
+	spci_handles[i].status = HANDLE_STATUS_OPEN;
+	spci_handles[i].client_id = client_id;
+	spci_handles[i].handle = service_handle;
+	spci_handles[i].num_active_requests = 0U;
+	spci_handles[i].sp_ctx = sp_ptr;
+
+	/* Release lock of the array of handles */
+	spin_unlock(&spci_handles_lock);
+
+	VERBOSE("SPCI: Service handle request by client 0x%04x: 0x%04x\n",
+		client_id, service_handle);
+	VERBOSE("SPCI:   UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid));
+
+	/* The handle is returned in the top 16 bits of x1 */
+	SMC_RET2(handle, SPCI_SUCCESS, ((uint32_t)service_handle) << 16);
+}
+
+/*******************************************************************************
+ * This function closes a handle that a specific client uses to access a Secure
+ * Service. It returns a SPCI_*** error code.
+ ******************************************************************************/
+static uint64_t spci_service_handle_close(void *handle, u_register_t x1)
+{
+	spci_handle_t *handle_info;
+	uint16_t client_id = x1 & 0x0000FFFFU;
+	uint16_t service_handle = (x1 >> 16) & 0x0000FFFFU;
+
+	spin_lock(&spci_handles_lock);
+
+	handle_info = spci_handle_info_get(service_handle, client_id);
+
+	if (handle_info == NULL) {
+		spin_unlock(&spci_handles_lock);
+
+		WARN("SPCI: Tried to close invalid handle 0x%04x by client 0x%04x\n",
+		     service_handle, client_id);
+
+		SMC_RET1(handle, SPCI_INVALID_PARAMETER);
+	}
+
+	if (handle_info->status != HANDLE_STATUS_OPEN) {
+		spin_unlock(&spci_handles_lock);
+
+		WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x in status %d\n",
+			service_handle, client_id, handle_info->status);
+
+		SMC_RET1(handle, SPCI_INVALID_PARAMETER);
+	}
+
+	if (handle_info->num_active_requests != 0U) {
+		spin_unlock(&spci_handles_lock);
+
+		/* A handle can't be closed if there are requests left */
+		WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x with %d requests left\n",
+			service_handle, client_id,
+			handle_info->num_active_requests);
+
+		SMC_RET1(handle, SPCI_BUSY);
+	}
+
+	memset(handle_info, 0, sizeof(spci_handle_t));
+
+	handle_info->status = HANDLE_STATUS_CLOSED;
+
+	spin_unlock(&spci_handles_lock);
+
+	VERBOSE("SPCI: Closed handle 0x%04x by client 0x%04x.\n",
+		service_handle, client_id);
+
+	SMC_RET1(handle, SPCI_SUCCESS);
+}
+
+/*******************************************************************************
+ * This function requests a Secure Service from a given handle and client ID.
+ ******************************************************************************/
+static uint64_t spci_service_request_blocking(void *handle,
+			uint32_t smc_fid, u_register_t x1, u_register_t x2,
+			u_register_t x3, u_register_t x4, u_register_t x5,
+			u_register_t x6, u_register_t x7)
+{
+	spci_handle_t *handle_info;
+	sp_context_t *sp_ctx;
+	cpu_context_t *cpu_ctx;
+	uint32_t rx0;
+	u_register_t rx1, rx2, rx3;
+	uint16_t request_handle, client_id;
+
+	/* Get handle array lock */
+	spin_lock(&spci_handles_lock);
+
+	/* Get pointer to struct of this open handle and client ID. */
+	request_handle = (x7 >> 16U) & 0x0000FFFFU;
+	client_id = x7 & 0x0000FFFFU;
+
+	handle_info = spci_handle_info_get(request_handle, client_id);
+	if (handle_info == NULL) {
+		spin_unlock(&spci_handles_lock);
+
+		WARN("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Not found.\n");
+		WARN("  Handle 0x%04x. Client ID 0x%04x\n", request_handle,
+		     client_id);
+
+		SMC_RET1(handle, SPCI_BUSY);
+	}
+
+	/* Get pointer to the Secure Partition that handles the service */
+	sp_ctx = handle_info->sp_ctx;
+	assert(sp_ctx != NULL);
+	cpu_ctx = &(sp_ctx->cpu_ctx);
+
+	/* Blocking requests are only allowed if the queue is empty */
+	if (handle_info->num_active_requests > 0) {
+		spin_unlock(&spci_handles_lock);
+
+		SMC_RET1(handle, SPCI_BUSY);
+	}
+
+	if (spm_sp_request_increase_if_zero(sp_ctx) == -1) {
+		spin_unlock(&spci_handles_lock);
+
+		SMC_RET1(handle, SPCI_BUSY);
+	}
+
+	/* Prevent this handle from being closed */
+	handle_info->num_active_requests += 1;
+
+	/* Release handle lock */
+	spin_unlock(&spci_handles_lock);
+
+	/* Save the Normal world context */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	/* Wait until the Secure Partition is idle and set it to busy. */
+	sp_state_wait_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY);
+
+	/* Pass arguments to the Secure Partition */
+	struct sprt_queue_entry_message message = {
+		.type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
+		.client_id = client_id,
+		.service_handle = request_handle,
+		.session_id = x6,
+		.token = 0, /* No token needed for blocking requests */
+		.args = {smc_fid, x1, x2, x3, x4, x5}
+	};
+
+	spin_lock(&(sp_ctx->spm_sp_buffer_lock));
+	int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
+				   SPRT_QUEUE_NUM_BLOCKING);
+	spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
+	if (rc != 0) {
+		/*
+		 * This shouldn't happen, blocking requests can only be made if
+		 * the request queue is empty.
+		 */
+		assert(rc == -ENOMEM);
+		ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n");
+		panic();
+	}
+
+	/* Jump to the Secure Partition. */
+	rx0 = spm_sp_synchronous_entry(sp_ctx, 0);
+
+	/* Verify returned value */
+	if (rx0 != SPRT_PUT_RESPONSE_AARCH64) {
+		ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__, rx0);
+		panic();
+	}
+
+	rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
+	rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
+	rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
+
+	/* Flag Secure Partition as idle. */
+	assert(sp_ctx->state == SP_STATE_BUSY);
+	sp_state_set(sp_ctx, SP_STATE_IDLE);
+
+	/* Decrease count of requests. */
+	spin_lock(&spci_handles_lock);
+	handle_info->num_active_requests -= 1;
+	spin_unlock(&spci_handles_lock);
+	spm_sp_request_decrease(sp_ctx);
+
+	/* Restore non-secure state */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_set_next_eret_context(NON_SECURE);
+
+	SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
+}
+
+/*******************************************************************************
+ * This function handles the returned values from the Secure Partition.
+ ******************************************************************************/
+static void spci_handle_returned_values(const cpu_context_t *cpu_ctx,
+					uint64_t ret)
+{
+	if (ret == SPRT_PUT_RESPONSE_AARCH64) {
+		uint32_t token;
+		uint64_t x3, x4, x5, x6;
+
+		token = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1);
+		x3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3);
+		x4 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4);
+		x5 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5);
+		x6 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X6);
+
+		uint16_t client_id = x6 & 0xFFFFU;
+		uint16_t service_handle = x6 >> 16;
+
+		int rc = spm_response_add(client_id, service_handle, token,
+					  x3, x4, x5);
+		if (rc != 0) {
+			/*
+			 * This is error fatal because we can't return to the SP
+			 * from this SMC. The SP has crashed.
+			 */
+			panic();
+		}
+	} else if ((ret != SPRT_YIELD_AARCH64) &&
+		   (ret != SPM_SECURE_PARTITION_PREEMPTED)) {
+		ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret);
+		panic();
+	}
+}
+
+/*******************************************************************************
+ * This function requests a Secure Service from a given handle and client ID.
+ ******************************************************************************/
+static uint64_t spci_service_request_start(void *handle,
+			uint32_t smc_fid, u_register_t x1, u_register_t x2,
+			u_register_t x3, u_register_t x4, u_register_t x5,
+			u_register_t x6, u_register_t x7)
+{
+	spci_handle_t *handle_info;
+	sp_context_t *sp_ctx;
+	cpu_context_t *cpu_ctx;
+	uint16_t request_handle, client_id;
+	uint32_t token;
+
+	/* Get handle array lock */
+	spin_lock(&spci_handles_lock);
+
+	/* Get pointer to struct of this open handle and client ID. */
+	request_handle = (x7 >> 16U) & 0x0000FFFFU;
+	client_id = x7 & 0x0000FFFFU;
+
+	handle_info = spci_handle_info_get(request_handle, client_id);
+	if (handle_info == NULL) {
+		spin_unlock(&spci_handles_lock);
+
+		WARN("SPCI_SERVICE_TUN_REQUEST_START: Not found.\n"
+		     "  Handle 0x%04x. Client ID 0x%04x\n", request_handle,
+		     client_id);
+
+		SMC_RET1(handle, SPCI_INVALID_PARAMETER);
+	}
+
+	/* Get pointer to the Secure Partition that handles the service */
+	sp_ctx = handle_info->sp_ctx;
+	assert(sp_ctx != NULL);
+	cpu_ctx = &(sp_ctx->cpu_ctx);
+
+	/* Prevent this handle from being closed */
+	handle_info->num_active_requests += 1;
+
+	spm_sp_request_increase(sp_ctx);
+
+	/* Create new token for this request */
+	token = spci_create_token_value();
+
+	/* Release handle lock */
+	spin_unlock(&spci_handles_lock);
+
+	/* Pass arguments to the Secure Partition */
+	struct sprt_queue_entry_message message = {
+		.type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST,
+		.client_id = client_id,
+		.service_handle = request_handle,
+		.session_id = x6,
+		.token = token,
+		.args = {smc_fid, x1, x2, x3, x4, x5}
+	};
+
+	spin_lock(&(sp_ctx->spm_sp_buffer_lock));
+	int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message,
+				   SPRT_QUEUE_NUM_NON_BLOCKING);
+	spin_unlock(&(sp_ctx->spm_sp_buffer_lock));
+	if (rc != 0) {
+		WARN("SPCI_SERVICE_TUN_REQUEST_START: SPRT queue full.\n"
+		     "  Handle 0x%04x. Client ID 0x%04x\n", request_handle,
+		     client_id);
+		SMC_RET1(handle, SPCI_NO_MEMORY);
+	}
+
+	/* Try to enter the partition. If it's not possible, simply return. */
+	if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) {
+		SMC_RET2(handle, SPCI_SUCCESS, token);
+	}
+
+	/* Save the Normal world context */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	/*
+	 * This request is non-blocking and needs to be interruptible by
+	 * non-secure interrupts. Enable their routing to EL3 during the
+	 * processing of the Secure Partition's service on this core.
+	 */
+
+	/* Jump to the Secure Partition. */
+	uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
+
+	/* Handle returned values */
+	spci_handle_returned_values(cpu_ctx, ret);
+
+	/* Flag Secure Partition as idle. */
+	assert(sp_ctx->state == SP_STATE_BUSY);
+	sp_state_set(sp_ctx, SP_STATE_IDLE);
+
+	/* Restore non-secure state */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_set_next_eret_context(NON_SECURE);
+
+	SMC_RET2(handle, SPCI_SUCCESS, token);
+}
+
+/*******************************************************************************
+ * This function returns the response of a Secure Service given a handle, a
+ * client ID and a token. If not available, it will schedule a Secure Partition
+ * and give it CPU time.
+ ******************************************************************************/
+static uint64_t spci_service_request_resume(void *handle, u_register_t x1,
+					    u_register_t x7)
+{
+	int rc;
+	u_register_t rx1 = 0, rx2 = 0, rx3 = 0;
+	spci_handle_t *handle_info;
+	sp_context_t *sp_ctx;
+	cpu_context_t *cpu_ctx;
+	uint32_t token = (uint32_t) x1;
+	uint16_t client_id = x7 & 0x0000FFFF;
+	uint16_t service_handle = (x7 >> 16) & 0x0000FFFF;
+
+	/* Get pointer to struct of this open handle and client ID. */
+	spin_lock(&spci_handles_lock);
+
+	handle_info = spci_handle_info_get(service_handle, client_id);
+	if (handle_info == NULL) {
+		spin_unlock(&spci_handles_lock);
+		WARN("SPCI_SERVICE_REQUEST_RESUME: Not found.\n"
+		     "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n",
+		     client_id, service_handle, token);
+
+		SMC_RET1(handle, SPCI_INVALID_PARAMETER);
+	}
+
+	/* Get pointer to the Secure Partition that handles the service */
+	sp_ctx = handle_info->sp_ctx;
+	assert(sp_ctx != NULL);
+	cpu_ctx = &(sp_ctx->cpu_ctx);
+
+	spin_unlock(&spci_handles_lock);
+
+	/* Look for a valid response in the global queue */
+	rc = spm_response_get(client_id, service_handle, token,
+			      &rx1, &rx2, &rx3);
+	if (rc == 0) {
+		/* Decrease request count */
+		spin_lock(&spci_handles_lock);
+		handle_info->num_active_requests -= 1;
+		spin_unlock(&spci_handles_lock);
+		spm_sp_request_decrease(sp_ctx);
+
+		SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
+	}
+
+	/* Try to enter the partition. If it's not possible, simply return. */
+	if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) {
+		SMC_RET1(handle, SPCI_QUEUED);
+	}
+
+	/* Save the Normal world context */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	/*
+	 * This request is non-blocking and needs to be interruptible by
+	 * non-secure interrupts. Enable their routing to EL3 during the
+	 * processing of the Secure Partition's service on this core.
+	 */
+
+	/* Jump to the Secure Partition. */
+	uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1);
+
+	/* Handle returned values */
+	spci_handle_returned_values(cpu_ctx, ret);
+
+	/* Flag Secure Partition as idle. */
+	assert(sp_ctx->state == SP_STATE_BUSY);
+	sp_state_set(sp_ctx, SP_STATE_IDLE);
+
+	/* Restore non-secure state */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_set_next_eret_context(NON_SECURE);
+
+	/* Look for a valid response in the global queue */
+	rc = spm_response_get(client_id, service_handle, token,
+			      &rx1, &rx2, &rx3);
+	if (rc != 0) {
+		SMC_RET1(handle, SPCI_QUEUED);
+	}
+
+	/* Decrease request count */
+	spin_lock(&spci_handles_lock);
+	handle_info->num_active_requests -= 1;
+	spin_unlock(&spci_handles_lock);
+	spm_sp_request_decrease(sp_ctx);
+
+	/* Return response */
+	SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
+}
+
+/*******************************************************************************
+ * This function returns the response of a Secure Service given a handle, a
+ * client ID and a token.
+ ******************************************************************************/
+static uint64_t spci_service_get_response(void *handle, u_register_t x1,
+					    u_register_t x7)
+
+{
+	int rc;
+	u_register_t rx1 = 0, rx2 = 0, rx3 = 0;
+	spci_handle_t *handle_info;
+	uint32_t token = (uint32_t) x1;
+	uint16_t client_id = x7 & 0x0000FFFF;
+	uint16_t service_handle = (x7 >> 16) & 0x0000FFFF;
+
+	/* Get pointer to struct of this open handle and client ID. */
+
+	spin_lock(&spci_handles_lock);
+
+	handle_info = spci_handle_info_get(service_handle, client_id);
+	if (handle_info == NULL) {
+		spin_unlock(&spci_handles_lock);
+		WARN("SPCI_SERVICE_GET_RESPONSE: Not found.\n"
+		     "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n",
+		     client_id, service_handle, token);
+
+		SMC_RET1(handle, SPCI_INVALID_PARAMETER);
+	}
+
+	spin_unlock(&spci_handles_lock);
+
+	/* Look for a valid response in the global queue */
+	rc = spm_response_get(client_id, service_handle, token,
+			      &rx1, &rx2, &rx3);
+
+	if (rc != 0) {
+		SMC_RET1(handle, SPCI_QUEUED);
+	}
+
+	/* Decrease request count */
+	spin_lock(&spci_handles_lock);
+	handle_info->num_active_requests -= 1;
+	sp_context_t *sp_ctx;
+	sp_ctx = handle_info->sp_ctx;
+	spin_unlock(&spci_handles_lock);
+	spm_sp_request_decrease(sp_ctx);
+
+	/* Return response */
+	SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3);
+}
+
+/*******************************************************************************
+ * This function handles all SMCs in the range reserved for SPCI.
+ ******************************************************************************/
+static uintptr_t spci_smc_handler(uint32_t smc_fid, u_register_t x1,
+				  u_register_t x2, u_register_t x3,
+				  u_register_t x4, void *cookie, void *handle,
+				  u_register_t flags)
+{
+	uint32_t spci_fid;
+
+	/* SPCI only supported from the Non-secure world for now */
+	if (is_caller_non_secure(flags) == SMC_FROM_SECURE) {
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+	if ((smc_fid & SPCI_FID_TUN_FLAG) == 0) {
+
+		/* Miscellaneous calls */
+
+		spci_fid = (smc_fid >> SPCI_FID_MISC_SHIFT) & SPCI_FID_MISC_MASK;
+
+		switch (spci_fid) {
+
+		case SPCI_FID_VERSION:
+			SMC_RET1(handle, SPCI_VERSION_COMPILED);
+
+		case SPCI_FID_SERVICE_HANDLE_OPEN:
+		{
+			if ((smc_fid & SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT) != 0) {
+				/* Not supported for now */
+				WARN("SPCI_SERVICE_HANDLE_OPEN_NOTIFY not supported.\n");
+				SMC_RET1(handle, SPCI_INVALID_PARAMETER);
+			}
+
+			uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+			uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+			uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+			return spci_service_handle_open_poll(handle, x1, x2, x3,
+							     x4, x5, x6, x7);
+		}
+		case SPCI_FID_SERVICE_HANDLE_CLOSE:
+			return spci_service_handle_close(handle, x1);
+
+		case SPCI_FID_SERVICE_REQUEST_BLOCKING:
+		{
+			uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+			uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+			uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+			return spci_service_request_blocking(handle,
+					smc_fid, x1, x2, x3, x4, x5, x6, x7);
+		}
+
+		case SPCI_FID_SERVICE_REQUEST_START:
+		{
+			uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5);
+			uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6);
+			uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+			return spci_service_request_start(handle,
+					smc_fid, x1, x2, x3, x4, x5, x6, x7);
+		}
+
+		case SPCI_FID_SERVICE_GET_RESPONSE:
+		{
+			uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+			return spci_service_get_response(handle, x1, x7);
+		}
+
+		default:
+			break;
+		}
+
+	} else {
+
+		/* Tunneled calls */
+
+		spci_fid = (smc_fid >> SPCI_FID_TUN_SHIFT) & SPCI_FID_TUN_MASK;
+
+		switch (spci_fid) {
+
+		case SPCI_FID_SERVICE_REQUEST_RESUME:
+		{
+			uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7);
+
+			return spci_service_request_resume(handle, x1, x7);
+		}
+
+		default:
+			break;
+		}
+	}
+
+	WARN("SPCI: Unsupported call 0x%08x\n", smc_fid);
+	SMC_RET1(handle, SPCI_NOT_SUPPORTED);
+}
+
+DECLARE_RT_SVC(
+	spci_handler,
+	OEN_SPCI_START,
+	OEN_SPCI_END,
+	SMC_TYPE_FAST,
+	NULL,
+	spci_smc_handler
+);
diff --git a/services/std_svc/spm/spm.mk b/services/std_svc/spm/spm.mk
new file mode 100644
index 0000000..448aba4
--- /dev/null
+++ b/services/std_svc/spm/spm.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${SPD},none)
+        $(error "Error: SPD and SPM are incompatible build options.")
+endif
+ifneq (${ARCH},aarch64)
+        $(error "Error: SPM is only supported on aarch64.")
+endif
+
+include lib/sprt/sprt_host.mk
+
+SPM_SOURCES	:=	$(addprefix services/std_svc/spm/,	\
+			${ARCH}/spm_helpers.S			\
+			${ARCH}/spm_shim_exceptions.S		\
+			spci.c					\
+			spm_buffers.c				\
+			spm_main.c				\
+			spm_setup.c				\
+			spm_xlat.c				\
+			sprt.c)					\
+			${SPRT_LIB_SOURCES}
+
+INCLUDES	+=	${SPRT_LIB_INCLUDES}
+
+# Let the top-level Makefile know that we intend to include a BL32 image
+NEED_BL32		:=	yes
diff --git a/services/std_svc/spm/spm_buffers.c b/services/std_svc/spm/spm_buffers.c
new file mode 100644
index 0000000..79398ba
--- /dev/null
+++ b/services/std_svc/spm/spm_buffers.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <lib/spinlock.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+#include "./spm_private.h"
+
+/*******************************************************************************
+ * Secure Service response global array. All the responses to the requests done
+ * to the Secure Partition are stored here. They are removed from the array as
+ * soon as their value is read.
+ ******************************************************************************/
+struct sprt_response {
+	int is_valid;
+	uint32_t token;
+	uint16_t client_id, handle;
+	u_register_t x1, x2, x3;
+};
+
+static struct sprt_response responses[PLAT_SPM_RESPONSES_MAX];
+
+static spinlock_t responses_lock;
+
+/* Add response to the global response buffer. Returns 0 on success else -1. */
+int spm_response_add(uint16_t client_id, uint16_t handle, uint32_t token,
+		     u_register_t x1, u_register_t x2, u_register_t x3)
+{
+	spin_lock(&responses_lock);
+
+	/* Make sure that there isn't any other response with the same token. */
+	for (unsigned int i = 0U; i < ARRAY_SIZE(responses); i++) {
+		struct sprt_response *resp = &(responses[i]);
+
+		if ((resp->is_valid == 1) && (resp->token == token)) {
+			spin_unlock(&responses_lock);
+
+			return -1;
+		}
+	}
+
+	for (unsigned int i = 0U; i < ARRAY_SIZE(responses); i++) {
+		struct sprt_response *resp = &(responses[i]);
+
+		if (resp->is_valid == 0) {
+			resp->token = token;
+			resp->client_id = client_id;
+			resp->handle = handle;
+			resp->x1 = x1;
+			resp->x2 = x2;
+			resp->x3 = x3;
+
+			dmbish();
+
+			resp->is_valid = 1;
+
+			spin_unlock(&responses_lock);
+
+			return 0;
+		}
+	}
+
+	spin_unlock(&responses_lock);
+
+	return -1;
+}
+
+/*
+ * Returns a response from the requests array and removes it from it. Returns 0
+ * on success, -1 if it wasn't found.
+ */
+int spm_response_get(uint16_t client_id, uint16_t handle, uint32_t token,
+		     u_register_t *x1, u_register_t *x2, u_register_t *x3)
+{
+	spin_lock(&responses_lock);
+
+	for (unsigned int i = 0U; i < ARRAY_SIZE(responses); i++) {
+		struct sprt_response *resp = &(responses[i]);
+
+		/* Ignore invalid entries */
+		if (resp->is_valid == 0) {
+			continue;
+		}
+
+		/* Make sure that all the information matches the stored one */
+		if ((resp->token != token) || (resp->client_id != client_id) ||
+		    (resp->handle != handle)) {
+			continue;
+		}
+
+		*x1 = resp->x1;
+		*x2 = resp->x2;
+		*x3 = resp->x3;
+
+		dmbish();
+
+		resp->is_valid = 0;
+
+		spin_unlock(&responses_lock);
+
+		return 0;
+	}
+
+	spin_unlock(&responses_lock);
+
+	return -1;
+}
diff --git a/services/std_svc/spm/spm_main.c b/services/std_svc/spm/spm_main.c
new file mode 100644
index 0000000..3a63f1c
--- /dev/null
+++ b/services/std_svc/spm/spm_main.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/spm_svc.h>
+#include <services/sprt_svc.h>
+#include <smccc_helpers.h>
+
+#include "spm_private.h"
+
+/*******************************************************************************
+ * Secure Partition context information.
+ ******************************************************************************/
+sp_context_t sp_ctx_array[PLAT_SPM_MAX_PARTITIONS];
+
+/* Last Secure Partition last used by the CPU */
+sp_context_t *cpu_sp_ctx[PLATFORM_CORE_COUNT];
+
+void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx)
+{
+	assert(linear_id < PLATFORM_CORE_COUNT);
+
+	cpu_sp_ctx[linear_id] = sp_ctx;
+}
+
+sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id)
+{
+	assert(linear_id < PLATFORM_CORE_COUNT);
+
+	return cpu_sp_ctx[linear_id];
+}
+
+/*******************************************************************************
+ * Functions to keep track of how many requests a Secure Partition has received
+ * and hasn't finished.
+ ******************************************************************************/
+void spm_sp_request_increase(sp_context_t *sp_ctx)
+{
+	spin_lock(&(sp_ctx->request_count_lock));
+	sp_ctx->request_count++;
+	spin_unlock(&(sp_ctx->request_count_lock));
+}
+
+void spm_sp_request_decrease(sp_context_t *sp_ctx)
+{
+	spin_lock(&(sp_ctx->request_count_lock));
+	sp_ctx->request_count--;
+	spin_unlock(&(sp_ctx->request_count_lock));
+}
+
+/* Returns 0 if it was originally 0, -1 otherwise. */
+int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx)
+{
+	int ret = -1;
+
+	spin_lock(&(sp_ctx->request_count_lock));
+	if (sp_ctx->request_count == 0U) {
+		sp_ctx->request_count++;
+		ret = 0U;
+	}
+	spin_unlock(&(sp_ctx->request_count_lock));
+
+	return ret;
+}
+
+/*******************************************************************************
+ * This function returns a pointer to the context of the Secure Partition that
+ * handles the service specified by an UUID. It returns NULL if the UUID wasn't
+ * found.
+ ******************************************************************************/
+sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4])
+{
+	unsigned int i;
+
+	for (i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
+
+		sp_context_t *sp_ctx = &sp_ctx_array[i];
+
+		if (sp_ctx->is_present == 0) {
+			continue;
+		}
+
+		struct sp_rd_sect_service *rdsvc;
+
+		for (rdsvc = sp_ctx->rd.service; rdsvc != NULL;
+		     rdsvc = rdsvc->next) {
+			uint32_t *rd_uuid = (uint32_t *)(rdsvc->uuid);
+
+			if (memcmp(rd_uuid, svc_uuid, sizeof(*svc_uuid)) == 0) {
+				return sp_ctx;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/*******************************************************************************
+ * Set state of a Secure Partition context.
+ ******************************************************************************/
+void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
+{
+	spin_lock(&(sp_ptr->state_lock));
+	sp_ptr->state = state;
+	spin_unlock(&(sp_ptr->state_lock));
+}
+
+/*******************************************************************************
+ * Wait until the state of a Secure Partition is the specified one and change it
+ * to the desired state.
+ ******************************************************************************/
+void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
+{
+	int success = 0;
+
+	while (success == 0) {
+		spin_lock(&(sp_ptr->state_lock));
+
+		if (sp_ptr->state == from) {
+			sp_ptr->state = to;
+
+			success = 1;
+		}
+
+		spin_unlock(&(sp_ptr->state_lock));
+	}
+}
+
+/*******************************************************************************
+ * Check if the state of a Secure Partition is the specified one and, if so,
+ * change it to the desired state. Returns 0 on success, -1 on error.
+ ******************************************************************************/
+int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
+{
+	int ret = -1;
+
+	spin_lock(&(sp_ptr->state_lock));
+
+	if (sp_ptr->state == from) {
+		sp_ptr->state = to;
+
+		ret = 0;
+	}
+
+	spin_unlock(&(sp_ptr->state_lock));
+
+	return ret;
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and performs a synchronous entry
+ * into it.
+ ******************************************************************************/
+uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx, int can_preempt)
+{
+	uint64_t rc;
+	unsigned int linear_id = plat_my_core_pos();
+
+	assert(sp_ctx != NULL);
+
+	/* Assign the context of the SP to this CPU */
+	spm_cpu_set_sp_ctx(linear_id, sp_ctx);
+	cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
+
+	/* Restore the context assigned above */
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+
+	/* Invalidate TLBs at EL1. */
+	tlbivmalle1();
+	dsbish();
+
+	if (can_preempt == 1) {
+		enable_intr_rm_local(INTR_TYPE_NS, SECURE);
+	} else {
+		disable_intr_rm_local(INTR_TYPE_NS, SECURE);
+	}
+
+	/* Enter Secure Partition */
+	rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
+
+	/* Save secure state */
+	cm_el1_sysregs_context_save(SECURE);
+
+	return rc;
+}
+
+/*******************************************************************************
+ * This function returns to the place where spm_sp_synchronous_entry() was
+ * called originally.
+ ******************************************************************************/
+__dead2 void spm_sp_synchronous_exit(uint64_t rc)
+{
+	/* Get context of the SP in use by this CPU. */
+	unsigned int linear_id = plat_my_core_pos();
+	sp_context_t *ctx = spm_cpu_get_sp_ctx(linear_id);
+
+	/*
+	 * The SPM must have initiated the original request through a
+	 * synchronous entry into the secure partition. Jump back to the
+	 * original C runtime context with the value of rc in x0;
+	 */
+	spm_secure_partition_exit(ctx->c_rt_ctx, rc);
+
+	panic();
+}
+
+/*******************************************************************************
+ * This function is the handler registered for Non secure interrupts by the SPM.
+ * It validates the interrupt and upon success arranges entry into the normal
+ * world for handling the interrupt.
+ ******************************************************************************/
+static uint64_t spm_ns_interrupt_handler(uint32_t id, uint32_t flags,
+					  void *handle, void *cookie)
+{
+	/* Check the security state when the exception was generated */
+	assert(get_interrupt_src_ss(flags) == SECURE);
+
+	spm_sp_synchronous_exit(SPM_SECURE_PARTITION_PREEMPTED);
+}
+
+/*******************************************************************************
+ * Jump to each Secure Partition for the first time.
+ ******************************************************************************/
+static int32_t spm_init(void)
+{
+	uint64_t rc = 0;
+	sp_context_t *ctx;
+
+	for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) {
+
+		ctx = &sp_ctx_array[i];
+
+		if (ctx->is_present == 0) {
+			continue;
+		}
+
+		INFO("Secure Partition %u init...\n", i);
+
+		ctx->state = SP_STATE_RESET;
+
+		rc = spm_sp_synchronous_entry(ctx, 0);
+		if (rc != SPRT_YIELD_AARCH64) {
+			ERROR("Unexpected return value 0x%llx\n", rc);
+			panic();
+		}
+
+		ctx->state = SP_STATE_IDLE;
+
+		INFO("Secure Partition %u initialized.\n", i);
+	}
+
+	return rc;
+}
+
+/*******************************************************************************
+ * Initialize contexts of all Secure Partitions.
+ ******************************************************************************/
+int32_t spm_setup(void)
+{
+	int rc;
+	sp_context_t *ctx;
+	void *sp_base, *rd_base;
+	size_t sp_size, rd_size;
+	uint64_t flags = 0U;
+
+	/* Disable MMU at EL1 (initialized by BL2) */
+	disable_mmu_icache_el1();
+
+	/*
+	 * Non-blocking services can be interrupted by Non-secure interrupts.
+	 * Register an interrupt handler for NS interrupts when generated while
+	 * the CPU is in secure state. They are routed to EL3.
+	 */
+	set_interrupt_rm_flag(flags, SECURE);
+
+	uint64_t rc_int = register_interrupt_type_handler(INTR_TYPE_NS,
+				spm_ns_interrupt_handler, flags);
+	if (rc_int) {
+		ERROR("SPM: Failed to register NS interrupt handler with rc = %llx\n",
+		      rc_int);
+		panic();
+	}
+
+	/* Setup shim layer */
+	spm_exceptions_xlat_init_context();
+
+	/*
+	 * Setup all Secure Partitions.
+	 */
+	unsigned int i = 0U;
+
+	while (1) {
+		rc = plat_spm_sp_get_next_address(&sp_base, &sp_size,
+						&rd_base, &rd_size);
+		if (rc < 0) {
+			/* Reached the end of the package. */
+			break;
+		}
+
+		if (i >= PLAT_SPM_MAX_PARTITIONS) {
+			ERROR("Too many partitions in the package.\n");
+			panic();
+		}
+
+		ctx = &sp_ctx_array[i];
+
+		assert(ctx->is_present == 0);
+
+		/* Initialize context of the SP */
+		INFO("Secure Partition %u context setup start...\n", i);
+
+		/* Save location of the image in physical memory */
+		ctx->image_base = (uintptr_t)sp_base;
+		ctx->image_size = sp_size;
+
+		rc = plat_spm_sp_rd_load(&ctx->rd, rd_base, rd_size);
+		if (rc < 0) {
+			ERROR("Error while loading RD blob.\n");
+			panic();
+		}
+
+		spm_sp_setup(ctx);
+
+		ctx->is_present = 1;
+
+		INFO("Secure Partition %u setup done.\n", i);
+
+		i++;
+	}
+
+	if (i == 0U) {
+		ERROR("No present partitions in the package.\n");
+		panic();
+	}
+
+	/* Register init function for deferred init.  */
+	bl31_register_bl32_init(&spm_init);
+
+	return 0;
+}
diff --git a/services/std_svc/spm/spm_private.h b/services/std_svc/spm/spm_private.h
new file mode 100644
index 0000000..efc91cb
--- /dev/null
+++ b/services/std_svc/spm/spm_private.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_PRIVATE_H
+#define SPM_PRIVATE_H
+
+#include <context.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define SP_C_RT_CTX_X19		0x0
+#define SP_C_RT_CTX_X20		0x8
+#define SP_C_RT_CTX_X21		0x10
+#define SP_C_RT_CTX_X22		0x18
+#define SP_C_RT_CTX_X23		0x20
+#define SP_C_RT_CTX_X24		0x28
+#define SP_C_RT_CTX_X25		0x30
+#define SP_C_RT_CTX_X26		0x38
+#define SP_C_RT_CTX_X27		0x40
+#define SP_C_RT_CTX_X28		0x48
+#define SP_C_RT_CTX_X29		0x50
+#define SP_C_RT_CTX_X30		0x58
+
+#define SP_C_RT_CTX_SIZE	0x60
+#define SP_C_RT_CTX_ENTRIES	(SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+/* Value returned by spm_sp_synchronous_entry() when a partition is preempted */
+#define SPM_SECURE_PARTITION_PREEMPTED	U(0x1234)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <lib/spinlock.h>
+#include <services/sp_res_desc.h>
+
+typedef enum sp_state {
+	SP_STATE_RESET = 0,
+	SP_STATE_IDLE,
+	SP_STATE_BUSY
+} sp_state_t;
+
+typedef struct sp_context {
+	/* 1 if the partition is present, 0 otherwise */
+	int is_present;
+
+	/* Location of the image in physical memory */
+	unsigned long long image_base;
+	size_t image_size;
+
+	uint64_t c_rt_ctx;
+	cpu_context_t cpu_ctx;
+	struct sp_res_desc rd;
+
+	/* Translation tables context */
+	xlat_ctx_t *xlat_ctx_handle;
+	spinlock_t xlat_ctx_lock;
+
+	sp_state_t state;
+	spinlock_t state_lock;
+
+	unsigned int request_count;
+	spinlock_t request_count_lock;
+
+	/* Base and size of the shared SPM<->SP buffer */
+	uintptr_t spm_sp_buffer_base;
+	size_t spm_sp_buffer_size;
+	spinlock_t spm_sp_buffer_lock;
+} sp_context_t;
+
+/* Functions used to enter/exit a Secure Partition synchronously */
+uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx, int can_preempt);
+__dead2 void spm_sp_synchronous_exit(uint64_t rc);
+
+/* Assembly helpers */
+uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx);
+void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
+
+/* Secure Partition setup */
+void spm_sp_setup(sp_context_t *sp_ctx);
+
+/* Secure Partition state management helpers */
+void sp_state_set(sp_context_t *sp_ptr, sp_state_t state);
+void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to);
+int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to);
+
+/* Functions to keep track of the number of active requests per SP */
+void spm_sp_request_increase(sp_context_t *sp_ctx);
+void spm_sp_request_decrease(sp_context_t *sp_ctx);
+int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx);
+
+/* Functions related to the shim layer translation tables */
+void spm_exceptions_xlat_init_context(void);
+uint64_t *spm_exceptions_xlat_get_base_table(void);
+
+/* Functions related to the translation tables management */
+void spm_sp_xlat_context_alloc(sp_context_t *sp_ctx);
+void sp_map_memory_regions(sp_context_t *sp_ctx);
+
+/* Functions to handle Secure Partition contexts */
+void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx);
+sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id);
+sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4]);
+
+/* Functions to manipulate response and requests buffers */
+int spm_response_add(uint16_t client_id, uint16_t handle, uint32_t token,
+		     u_register_t x1, u_register_t x2, u_register_t x3);
+int spm_response_get(uint16_t client_id, uint16_t handle, uint32_t token,
+		     u_register_t *x1, u_register_t *x2, u_register_t *x3);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPM_PRIVATE_H */
diff --git a/services/std_svc/spm/spm_setup.c b/services/std_svc/spm/spm_setup.c
new file mode 100644
index 0000000..2ed44d1
--- /dev/null
+++ b/services/std_svc/spm/spm_setup.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <services/sp_res_desc.h>
+#include <sprt_host.h>
+
+#include "spm_private.h"
+#include "spm_shim_private.h"
+
+/* Setup context of the Secure Partition */
+void spm_sp_setup(sp_context_t *sp_ctx)
+{
+	cpu_context_t *ctx = &(sp_ctx->cpu_ctx);
+
+	/*
+	 * Initialize CPU context
+	 * ----------------------
+	 */
+
+	entry_point_info_t ep_info = {0};
+
+	SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE);
+
+	/* Setup entrypoint and SPSR */
+	ep_info.pc = sp_ctx->rd.attribute.entrypoint;
+	ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS);
+
+	/*
+	 * X0: Unused (MBZ).
+	 * X1: Unused (MBZ).
+	 * X2: cookie value (Implementation Defined)
+	 * X3: cookie value (Implementation Defined)
+	 * X4 to X7 = 0
+	 */
+	ep_info.args.arg0 = 0;
+	ep_info.args.arg1 = 0;
+	ep_info.args.arg2 = PLAT_SPM_COOKIE_0;
+	ep_info.args.arg3 = PLAT_SPM_COOKIE_1;
+
+	cm_setup_context(ctx, &ep_info);
+
+	/*
+	 * Setup translation tables
+	 * ------------------------
+	 */
+
+	/* Assign translation tables context. */
+	spm_sp_xlat_context_alloc(sp_ctx);
+
+	sp_map_memory_regions(sp_ctx);
+
+	/*
+	 * MMU-related registers
+	 * ---------------------
+	 */
+	xlat_ctx_t *xlat_ctx = sp_ctx->xlat_ctx_handle;
+
+	uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
+
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table,
+		      xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
+		      EL1_EL0_REGIME);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1,
+		      mmu_cfg_params[MMU_CFG_MAIR]);
+
+	/* Enable translations using TTBR1_EL1 */
+	int t1sz = 64 - __builtin_ctzll(SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE);
+	mmu_cfg_params[MMU_CFG_TCR] &= ~TCR_EPD1_BIT;
+	mmu_cfg_params[MMU_CFG_TCR] |=
+		((uint64_t)t1sz << TCR_T1SZ_SHIFT) |
+		TCR_SH1_INNER_SHAREABLE |
+		TCR_RGN1_OUTER_WBA | TCR_RGN1_INNER_WBA |
+		TCR_TG1_4K;
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1,
+		      mmu_cfg_params[MMU_CFG_TCR]);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1,
+		      mmu_cfg_params[MMU_CFG_TTBR0]);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR1_EL1,
+		      (uint64_t)spm_exceptions_xlat_get_base_table());
+
+	/* Setup SCTLR_EL1 */
+	u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1);
+
+	sctlr_el1 |=
+		/*SCTLR_EL1_RES1 |*/
+		/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
+		SCTLR_UCI_BIT							|
+		/* RW regions at xlat regime EL1&0 are forced to be XN. */
+		SCTLR_WXN_BIT							|
+		/* Don't trap to EL1 execution of WFI or WFE at EL0. */
+		SCTLR_NTWI_BIT | SCTLR_NTWE_BIT					|
+		/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
+		SCTLR_UCT_BIT							|
+		/* Don't trap to EL1 execution of DZ ZVA at EL0. */
+		SCTLR_DZE_BIT							|
+		/* Enable SP Alignment check for EL0 */
+		SCTLR_SA0_BIT							|
+		/* Allow cacheable data and instr. accesses to normal memory. */
+		SCTLR_C_BIT | SCTLR_I_BIT					|
+		/* Alignment fault checking enabled when at EL1 and EL0. */
+		SCTLR_A_BIT							|
+		/* Enable MMU. */
+		SCTLR_M_BIT
+	;
+
+	sctlr_el1 &= ~(
+		/* Explicit data accesses at EL0 are little-endian. */
+		SCTLR_E0E_BIT							|
+		/* Accesses to DAIF from EL0 are trapped to EL1. */
+		SCTLR_UMA_BIT
+	);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+
+	/*
+	 * Setup other system registers
+	 * ----------------------------
+	 */
+
+	/*
+	 * Shim exception vector base address. It is mapped at the start of the
+	 * address space accessed by TTBR1_EL1, which means that the base
+	 * address of the exception vectors depends on the size of the address
+	 * space specified in TCR_EL1.T1SZ.
+	 */
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1,
+		      UINT64_MAX - (SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE - 1ULL));
+
+	/*
+	 * FPEN: Allow the Secure Partition to access FP/SIMD registers.
+	 * Note that SPM will not do any saving/restoring of these registers on
+	 * behalf of the SP. This falls under the SP's responsibility.
+	 * 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,
+			CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
+
+	/*
+	 * Prepare shared buffers
+	 * ----------------------
+	 */
+
+	/* Initialize SPRT queues */
+	sprt_initialize_queues((void *)sp_ctx->spm_sp_buffer_base,
+			       sp_ctx->spm_sp_buffer_size);
+}
diff --git a/services/std_svc/spm/spm_shim_private.h b/services/std_svc/spm/spm_shim_private.h
new file mode 100644
index 0000000..fc510b1
--- /dev/null
+++ b/services/std_svc/spm/spm_shim_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_SHIM_PRIVATE_H
+#define SPM_SHIM_PRIVATE_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* Assembly source */
+IMPORT_SYM(uintptr_t, spm_shim_exceptions_ptr,		SPM_SHIM_EXCEPTIONS_PTR);
+
+/* Linker symbols */
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__,	SPM_SHIM_EXCEPTIONS_START);
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__,	SPM_SHIM_EXCEPTIONS_END);
+
+/* Definitions */
+
+#define SPM_SHIM_EXCEPTIONS_SIZE	\
+	(SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START)
+
+/*
+ * Use the smallest virtual address space size allowed in ARMv8.0 for
+ * compatibility.
+ */
+#define SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 25)
+#define SPM_SHIM_MMAP_REGIONS	1
+#define SPM_SHIM_XLAT_TABLES	1
+
+#endif /* SPM_SHIM_PRIVATE_H */
diff --git a/services/std_svc/spm/spm_xlat.c b/services/std_svc/spm/spm_xlat.c
new file mode 100644
index 0000000..5d5bc51
--- /dev/null
+++ b/services/std_svc/spm/spm_xlat.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <lib/object_pool.h>
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/sp_res_desc.h>
+
+#include "spm_private.h"
+#include "spm_shim_private.h"
+
+/*******************************************************************************
+ * Instantiation of translation table context
+ ******************************************************************************/
+
+/* Place translation tables by default along with the ones used by BL31. */
+#ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME	"xlat_table"
+#endif
+
+/*
+ * Allocate elements of the translation contexts for the Secure Partitions.
+ */
+
+/* Allocate an array of mmap_region per partition. */
+static struct mmap_region sp_mmap_regions[PLAT_SP_IMAGE_MMAP_REGIONS + 1]
+	[PLAT_SPM_MAX_PARTITIONS];
+static OBJECT_POOL(sp_mmap_regions_pool, sp_mmap_regions,
+	sizeof(mmap_region_t) * (PLAT_SP_IMAGE_MMAP_REGIONS + 1),
+	PLAT_SPM_MAX_PARTITIONS);
+
+/* Allocate individual translation tables. */
+static uint64_t sp_xlat_tables[XLAT_TABLE_ENTRIES]
+	[(PLAT_SP_IMAGE_MAX_XLAT_TABLES + 1) * PLAT_SPM_MAX_PARTITIONS]
+	__aligned(XLAT_TABLE_SIZE) __section(PLAT_SP_IMAGE_XLAT_SECTION_NAME);
+static OBJECT_POOL(sp_xlat_tables_pool, sp_xlat_tables,
+	XLAT_TABLE_ENTRIES * sizeof(uint64_t),
+	(PLAT_SP_IMAGE_MAX_XLAT_TABLES + 1) * PLAT_SPM_MAX_PARTITIONS);
+
+/* Allocate arrays. */
+static int sp_xlat_mapped_regions[PLAT_SP_IMAGE_MAX_XLAT_TABLES]
+	[PLAT_SPM_MAX_PARTITIONS];
+static OBJECT_POOL(sp_xlat_mapped_regions_pool, sp_xlat_mapped_regions,
+	sizeof(int) * PLAT_SP_IMAGE_MAX_XLAT_TABLES, PLAT_SPM_MAX_PARTITIONS);
+
+/* Allocate individual contexts. */
+static xlat_ctx_t sp_xlat_ctx[PLAT_SPM_MAX_PARTITIONS];
+static OBJECT_POOL(sp_xlat_ctx_pool, sp_xlat_ctx, sizeof(xlat_ctx_t),
+	PLAT_SPM_MAX_PARTITIONS);
+
+/* Get handle of Secure Partition translation context */
+void spm_sp_xlat_context_alloc(sp_context_t *sp_ctx)
+{
+	/* Allocate xlat context elements */
+
+	xlat_ctx_t *ctx = pool_alloc(&sp_xlat_ctx_pool);
+
+	struct mmap_region *mmap = pool_alloc(&sp_mmap_regions_pool);
+
+	uint64_t *base_table = pool_alloc(&sp_xlat_tables_pool);
+	uint64_t **tables = pool_alloc_n(&sp_xlat_tables_pool,
+					PLAT_SP_IMAGE_MAX_XLAT_TABLES);
+
+	int *mapped_regions = pool_alloc(&sp_xlat_mapped_regions_pool);
+
+	/* Calculate the size of the virtual address space needed */
+
+	uintptr_t va_size = 0U;
+	struct sp_rd_sect_mem_region *rdmem;
+
+	for (rdmem = sp_ctx->rd.mem_region; rdmem != NULL; rdmem = rdmem->next) {
+		uintptr_t end_va = (uintptr_t)rdmem->base +
+				   (uintptr_t)rdmem->size;
+
+		if (end_va > va_size)
+			va_size = end_va;
+	}
+
+	if (va_size == 0U) {
+		ERROR("No regions in resource description.\n");
+		panic();
+	}
+
+	/*
+	 * Get the power of two that is greater or equal to the top VA. The
+	 * values of base and size in the resource description are 32-bit wide
+	 * so the values will never overflow when using a uintptr_t.
+	 */
+	if (!IS_POWER_OF_TWO(va_size)) {
+		va_size = 1ULL <<
+			((sizeof(va_size) * 8) - __builtin_clzll(va_size));
+	}
+
+	if (va_size > PLAT_VIRT_ADDR_SPACE_SIZE) {
+		ERROR("Resource description requested too much virtual memory.\n");
+		panic();
+	}
+
+	uintptr_t min_va_size;
+
+	/* The following sizes are only valid for 4KB pages */
+	assert(PAGE_SIZE == (4U * 1024U));
+
+	if (is_armv8_4_ttst_present()) {
+		VERBOSE("Using ARMv8.4-TTST\n");
+		min_va_size = 1ULL << (64 - TCR_TxSZ_MAX_TTST);
+	} else {
+		min_va_size = 1ULL << (64 - TCR_TxSZ_MAX);
+	}
+
+	if (va_size < min_va_size) {
+		va_size = min_va_size;
+	}
+
+	/* Initialize xlat context */
+
+	xlat_setup_dynamic_ctx(ctx, PLAT_PHY_ADDR_SPACE_SIZE - 1ULL,
+			       va_size - 1ULL, mmap,
+			       PLAT_SP_IMAGE_MMAP_REGIONS, tables,
+			       PLAT_SP_IMAGE_MAX_XLAT_TABLES, base_table,
+			       EL1_EL0_REGIME, mapped_regions);
+
+	sp_ctx->xlat_ctx_handle = ctx;
+};
+
+/*******************************************************************************
+ * Translation table context used for S-EL1 exception vectors
+ ******************************************************************************/
+
+REGISTER_XLAT_CONTEXT2(spm_sel1, SPM_SHIM_MMAP_REGIONS, SPM_SHIM_XLAT_TABLES,
+		SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE,
+		EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME);
+
+void spm_exceptions_xlat_init_context(void)
+{
+	/* This region contains the exception vectors used at S-EL1. */
+	mmap_region_t sel1_exception_vectors =
+		MAP_REGION(SPM_SHIM_EXCEPTIONS_PTR,
+			   0x0UL,
+			   SPM_SHIM_EXCEPTIONS_SIZE,
+			   MT_CODE | MT_SECURE | MT_PRIVILEGED);
+
+	mmap_add_region_ctx(&spm_sel1_xlat_ctx,
+			    &sel1_exception_vectors);
+
+	init_xlat_tables_ctx(&spm_sel1_xlat_ctx);
+}
+
+uint64_t *spm_exceptions_xlat_get_base_table(void)
+{
+	return spm_sel1_xlat_ctx.base_table;
+}
+
+/*******************************************************************************
+ * Functions to allocate memory for regions.
+ ******************************************************************************/
+
+/*
+ * The region with base PLAT_SPM_HEAP_BASE and size PLAT_SPM_HEAP_SIZE is
+ * reserved for SPM to use as heap to allocate memory regions of Secure
+ * Partitions. This is only done at boot.
+ */
+static OBJECT_POOL(spm_heap_mem, (void *)PLAT_SPM_HEAP_BASE, 1U,
+		   PLAT_SPM_HEAP_SIZE);
+
+static uintptr_t spm_alloc_heap(size_t size)
+{
+	return (uintptr_t)pool_alloc_n(&spm_heap_mem, size);
+}
+
+/*******************************************************************************
+ * Functions to map memory regions described in the resource description.
+ ******************************************************************************/
+static unsigned int rdmem_attr_to_mmap_attr(uint32_t attr)
+{
+	unsigned int index = attr & RD_MEM_MASK;
+
+	const unsigned int mmap_attr_arr[8] = {
+		MT_DEVICE | MT_RW | MT_SECURE,	/* RD_MEM_DEVICE */
+		MT_CODE | MT_SECURE,		/* RD_MEM_NORMAL_CODE */
+		MT_MEMORY | MT_RW | MT_SECURE,	/* RD_MEM_NORMAL_DATA */
+		MT_MEMORY | MT_RW | MT_SECURE,	/* RD_MEM_NORMAL_BSS */
+		MT_RO_DATA | MT_SECURE,		/* RD_MEM_NORMAL_RODATA */
+		MT_MEMORY | MT_RW | MT_SECURE,	/* RD_MEM_NORMAL_SPM_SP_SHARED_MEM */
+		MT_MEMORY | MT_RW | MT_SECURE,	/* RD_MEM_NORMAL_CLIENT_SHARED_MEM */
+		MT_MEMORY | MT_RW | MT_SECURE	/* RD_MEM_NORMAL_MISCELLANEOUS */
+	};
+
+	if (index >= ARRAY_SIZE(mmap_attr_arr)) {
+		ERROR("Unsupported RD memory attributes 0x%x\n", attr);
+		panic();
+	}
+
+	return mmap_attr_arr[index];
+}
+
+/*
+ * The data provided in the resource description structure is not directly
+ * compatible with a mmap_region structure. This function handles the conversion
+ * and maps it.
+ */
+static void map_rdmem(sp_context_t *sp_ctx, struct sp_rd_sect_mem_region *rdmem)
+{
+	int rc;
+	mmap_region_t mmap;
+
+	/* Location of the SP image */
+	uintptr_t sp_size = sp_ctx->image_size;
+	uintptr_t sp_base_va = sp_ctx->rd.attribute.load_address;
+	unsigned long long sp_base_pa = sp_ctx->image_base;
+
+	/* Location of the memory region to map */
+	size_t rd_size = rdmem->size;
+	uintptr_t rd_base_va = rdmem->base;
+	unsigned long long rd_base_pa;
+
+	unsigned int memtype = rdmem->attr & RD_MEM_MASK;
+
+	if (rd_size == 0U) {
+		VERBOSE("Memory region '%s' is empty. Ignored.\n", rdmem->name);
+		return;
+	}
+
+	VERBOSE("Adding memory region '%s'\n", rdmem->name);
+
+	mmap.granularity = REGION_DEFAULT_GRANULARITY;
+
+	/* Check if the RD region is inside of the SP image or not */
+	int is_outside = (rd_base_va + rd_size <= sp_base_va) ||
+			 (sp_base_va + sp_size <= rd_base_va);
+
+	/* Set to 1 if it is needed to zero this region */
+	int zero_region = 0;
+
+	switch (memtype) {
+	case RD_MEM_DEVICE:
+		/* Device regions are mapped 1:1 */
+		rd_base_pa = rd_base_va;
+		break;
+
+	case RD_MEM_NORMAL_CODE:
+	case RD_MEM_NORMAL_RODATA:
+	{
+		if (is_outside == 1) {
+			ERROR("Code and rodata sections must be fully contained in the image.");
+			panic();
+		}
+
+		/* Get offset into the image */
+		rd_base_pa = sp_base_pa + rd_base_va - sp_base_va;
+		break;
+	}
+	case RD_MEM_NORMAL_DATA:
+	{
+		if (is_outside == 1) {
+			ERROR("Data sections must be fully contained in the image.");
+			panic();
+		}
+
+		rd_base_pa = spm_alloc_heap(rd_size);
+
+		/* Get offset into the image */
+		void *img_pa = (void *)(sp_base_pa + rd_base_va - sp_base_va);
+
+		VERBOSE("  Copying data from %p to 0x%llx\n", img_pa, rd_base_pa);
+
+		/* Map destination */
+		rc = mmap_add_dynamic_region(rd_base_pa, rd_base_pa,
+				rd_size, MT_MEMORY | MT_RW | MT_SECURE);
+		if (rc != 0) {
+			ERROR("Unable to map data region at EL3: %d\n", rc);
+			panic();
+		}
+
+		/* Copy original data to destination */
+		memcpy((void *)rd_base_pa, img_pa, rd_size);
+
+		/* Unmap destination region */
+		rc = mmap_remove_dynamic_region(rd_base_pa, rd_size);
+		if (rc != 0) {
+			ERROR("Unable to remove data region at EL3: %d\n", rc);
+			panic();
+		}
+
+		break;
+	}
+	case RD_MEM_NORMAL_MISCELLANEOUS:
+		/* Allow SPM to change the attributes of the region. */
+		mmap.granularity = PAGE_SIZE;
+		rd_base_pa = spm_alloc_heap(rd_size);
+		zero_region = 1;
+		break;
+
+	case RD_MEM_NORMAL_SPM_SP_SHARED_MEM:
+		if ((sp_ctx->spm_sp_buffer_base != 0) ||
+		    (sp_ctx->spm_sp_buffer_size != 0)) {
+			ERROR("A partition must have only one SPM<->SP buffer.\n");
+			panic();
+		}
+		rd_base_pa = spm_alloc_heap(rd_size);
+		zero_region = 1;
+		/* Save location of this buffer, it is needed by SPM */
+		sp_ctx->spm_sp_buffer_base = rd_base_pa;
+		sp_ctx->spm_sp_buffer_size = rd_size;
+		break;
+
+	case RD_MEM_NORMAL_CLIENT_SHARED_MEM:
+		/* Fallthrough */
+	case RD_MEM_NORMAL_BSS:
+		rd_base_pa = spm_alloc_heap(rd_size);
+		zero_region = 1;
+		break;
+
+	default:
+		panic();
+	}
+
+	mmap.base_pa = rd_base_pa;
+	mmap.base_va = rd_base_va;
+	mmap.size = rd_size;
+
+	/* Only S-EL0 mappings supported for now */
+	mmap.attr = rdmem_attr_to_mmap_attr(rdmem->attr) | MT_USER;
+
+	VERBOSE("  VA: 0x%lx PA: 0x%llx (0x%lx, attr: 0x%x)\n",
+		mmap.base_va, mmap.base_pa, mmap.size, mmap.attr);
+
+	/* Map region in the context of the Secure Partition */
+	mmap_add_region_ctx(sp_ctx->xlat_ctx_handle, &mmap);
+
+	if (zero_region == 1) {
+		VERBOSE("  Zeroing region...\n");
+
+		rc = mmap_add_dynamic_region(mmap.base_pa, mmap.base_pa,
+				mmap.size, MT_MEMORY | MT_RW | MT_SECURE);
+		if (rc != 0) {
+			ERROR("Unable to map memory at EL3 to zero: %d\n",
+			      rc);
+			panic();
+		}
+
+		zeromem((void *)mmap.base_pa, mmap.size);
+
+		/*
+		 * Unmap destination region unless it is the SPM<->SP buffer,
+		 * which must be used by SPM.
+		 */
+		if (memtype != RD_MEM_NORMAL_SPM_SP_SHARED_MEM) {
+			rc = mmap_remove_dynamic_region(rd_base_pa, rd_size);
+			if (rc != 0) {
+				ERROR("Unable to remove region at EL3: %d\n", rc);
+				panic();
+			}
+		}
+	}
+}
+
+void sp_map_memory_regions(sp_context_t *sp_ctx)
+{
+	struct sp_rd_sect_mem_region *rdmem;
+
+	for (rdmem = sp_ctx->rd.mem_region; rdmem != NULL; rdmem = rdmem->next) {
+		map_rdmem(sp_ctx, rdmem);
+	}
+
+	init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle);
+}
diff --git a/services/std_svc/spm/sprt.c b/services/std_svc/spm/sprt.c
new file mode 100644
index 0000000..20ad2af
--- /dev/null
+++ b/services/std_svc/spm/sprt.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <services/sprt_svc.h>
+#include <smccc_helpers.h>
+
+#include "spm_private.h"
+
+/*******************************************************************************
+ * Functions to manipulate memory regions
+ ******************************************************************************/
+
+/*
+ * Attributes are encoded using a different format in the SMC interface than in
+ * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
+ * converts an attributes value from the SMC format to the mmap_attr_t format by
+ * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
+ * The other fields are left as 0 because they are ignored by the function
+ * xlat_change_mem_attributes_ctx().
+ */
+static unsigned int smc_attr_to_mmap_attr(unsigned int attributes)
+{
+	unsigned int perm = attributes & SPRT_MEMORY_PERM_ATTR_MASK;
+
+	if (perm == SPRT_MEMORY_PERM_ATTR_RW) {
+		return MT_RW | MT_EXECUTE_NEVER | MT_USER;
+	} else if (perm ==  SPRT_MEMORY_PERM_ATTR_RO) {
+		return MT_RO | MT_EXECUTE_NEVER | MT_USER;
+	} else if (perm == SPRT_MEMORY_PERM_ATTR_RO_EXEC) {
+		return MT_RO | MT_USER;
+	} else {
+		return UINT_MAX;
+	}
+}
+
+/*
+ * This function converts attributes from the Trusted Firmware format into the
+ * SMC interface format.
+ */
+static unsigned int mmap_attr_to_smc_attr(unsigned int attr)
+{
+	unsigned int perm;
+
+	/* No access from EL0. */
+	if ((attr & MT_USER) == 0U)
+		return UINT_MAX;
+
+	if ((attr & MT_RW) != 0) {
+		assert(MT_TYPE(attr) != MT_DEVICE);
+		perm = SPRT_MEMORY_PERM_ATTR_RW;
+	} else {
+		if ((attr & MT_EXECUTE_NEVER) != 0U) {
+			perm = SPRT_MEMORY_PERM_ATTR_RO;
+		} else {
+			perm = SPRT_MEMORY_PERM_ATTR_RO_EXEC;
+		}
+	}
+
+	return perm << SPRT_MEMORY_PERM_ATTR_SHIFT;
+}
+
+static int32_t sprt_memory_perm_attr_get(sp_context_t *sp_ctx, uintptr_t base_va)
+{
+	uint32_t attributes;
+
+	spin_lock(&(sp_ctx->xlat_ctx_lock));
+
+	int ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+				     base_va, &attributes);
+
+	spin_unlock(&(sp_ctx->xlat_ctx_lock));
+
+	/* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */
+	assert((ret == 0) || (ret == -EINVAL));
+
+	if (ret != 0)
+		return SPRT_INVALID_PARAMETER;
+
+	unsigned int perm = mmap_attr_to_smc_attr(attributes);
+
+	if (perm == UINT_MAX)
+		return SPRT_INVALID_PARAMETER;
+
+	return SPRT_SUCCESS | perm;
+}
+
+static int32_t sprt_memory_perm_attr_set(sp_context_t *sp_ctx,
+		u_register_t page_address, u_register_t pages_count,
+		u_register_t smc_attributes)
+{
+	int ret;
+	uintptr_t base_va = (uintptr_t) page_address;
+	size_t size = pages_count * PAGE_SIZE;
+
+	VERBOSE("  Start address  : 0x%lx\n", base_va);
+	VERBOSE("  Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
+	VERBOSE("  Attributes     : 0x%lx\n", smc_attributes);
+
+	uint32_t mmap_attr = smc_attr_to_mmap_attr(smc_attributes);
+
+	if (mmap_attr == UINT_MAX) {
+		WARN("%s: Invalid memory attributes: 0x%lx\n", __func__,
+		     smc_attributes);
+		return SPRT_INVALID_PARAMETER;
+	}
+
+	/*
+	 * Perform some checks before actually trying to change the memory
+	 * attributes.
+	 */
+
+	spin_lock(&(sp_ctx->xlat_ctx_lock));
+
+	uint32_t attributes;
+
+	ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+				     base_va, &attributes);
+
+	if (ret != 0) {
+		spin_unlock(&(sp_ctx->xlat_ctx_lock));
+		return SPRT_INVALID_PARAMETER;
+	}
+
+	if ((attributes & MT_USER) == 0U) {
+		/* Prohibit changing attributes of S-EL1 regions */
+		spin_unlock(&(sp_ctx->xlat_ctx_lock));
+		return SPRT_INVALID_PARAMETER;
+	}
+
+	ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+					base_va, size, mmap_attr);
+
+	spin_unlock(&(sp_ctx->xlat_ctx_lock));
+
+	/* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */
+	assert((ret == 0) || (ret == -EINVAL));
+
+	return (ret == 0) ? SPRT_SUCCESS : SPRT_INVALID_PARAMETER;
+}
+
+/*******************************************************************************
+ * This function handles all SMCs in the range reserved for SPRT.
+ ******************************************************************************/
+static uintptr_t sprt_smc_handler(uint32_t smc_fid, u_register_t x1,
+				  u_register_t x2, u_register_t x3,
+				  u_register_t x4, void *cookie, void *handle,
+				  u_register_t flags)
+{
+	/* SPRT only supported from the Secure world */
+	if (is_caller_non_secure(flags) == SMC_FROM_NON_SECURE) {
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+	assert(handle == cm_get_context(SECURE));
+
+	/*
+	 * Only S-EL0 partitions are supported for now. Make the next ERET into
+	 * the partition jump directly to S-EL0 instead of S-EL1.
+	 */
+	cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
+
+	switch (smc_fid) {
+	case SPRT_VERSION:
+		SMC_RET1(handle, SPRT_VERSION_COMPILED);
+
+	case SPRT_PUT_RESPONSE_AARCH64:
+		spm_sp_synchronous_exit(SPRT_PUT_RESPONSE_AARCH64);
+
+	case SPRT_YIELD_AARCH64:
+		spm_sp_synchronous_exit(SPRT_YIELD_AARCH64);
+
+	case SPRT_MEMORY_PERM_ATTR_GET_AARCH64:
+	{
+		/* Get context of the SP in use by this CPU. */
+		unsigned int linear_id = plat_my_core_pos();
+		sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
+
+		SMC_RET1(handle, sprt_memory_perm_attr_get(sp_ctx, x1));
+	}
+
+	case SPRT_MEMORY_PERM_ATTR_SET_AARCH64:
+	{
+		/* Get context of the SP in use by this CPU. */
+		unsigned int linear_id = plat_my_core_pos();
+		sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
+
+		SMC_RET1(handle, sprt_memory_perm_attr_set(sp_ctx, x1, x2, x3));
+	}
+
+	default:
+		break;
+	}
+
+	WARN("SPRT: Unsupported call 0x%08x\n", smc_fid);
+	SMC_RET1(handle, SPRT_NOT_SUPPORTED);
+}
+
+DECLARE_RT_SVC(
+	sprt_handler,
+	OEN_SPRT_START,
+	OEN_SPRT_END,
+	SMC_TYPE_FAST,
+	NULL,
+	sprt_smc_handler
+);
diff --git a/services/std_svc/spm_mm/aarch64/spm_helpers.S b/services/std_svc/spm_mm/aarch64/spm_helpers.S
new file mode 100644
index 0000000..aa35811
--- /dev/null
+++ b/services/std_svc/spm_mm/aarch64/spm_helpers.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include "../spm_private.h"
+
+	.global spm_secure_partition_enter
+	.global spm_secure_partition_exit
+
+	/* ---------------------------------------------------------------------
+	 * This function is called with SP_EL0 as stack. Here we stash our EL3
+	 * callee-saved registers on to the stack as a part of saving the C
+	 * runtime and enter the secure payload.
+	 * 'x0' contains a pointer to the memory where the address of the C
+	 *  runtime context is to be saved.
+	 * ---------------------------------------------------------------------
+	 */
+func spm_secure_partition_enter
+	/* Make space for the registers that we're going to save */
+	mov	x3, sp
+	str	x3, [x0, #0]
+	sub	sp, sp, #SP_C_RT_CTX_SIZE
+
+	/* Save callee-saved registers on to the stack */
+	stp	x19, x20, [sp, #SP_C_RT_CTX_X19]
+	stp	x21, x22, [sp, #SP_C_RT_CTX_X21]
+	stp	x23, x24, [sp, #SP_C_RT_CTX_X23]
+	stp	x25, x26, [sp, #SP_C_RT_CTX_X25]
+	stp	x27, x28, [sp, #SP_C_RT_CTX_X27]
+	stp	x29, x30, [sp, #SP_C_RT_CTX_X29]
+
+	/* ---------------------------------------------------------------------
+	 * Everything is setup now. el3_exit() will use the secure context to
+	 * restore to the general purpose and EL3 system registers to ERET
+	 * into the secure payload.
+	 * ---------------------------------------------------------------------
+	 */
+	b	el3_exit
+endfunc spm_secure_partition_enter
+
+	/* ---------------------------------------------------------------------
+	 * This function is called with 'x0' pointing to a C runtime context
+	 * saved in spm_secure_partition_enter().
+	 * It restores the saved registers and jumps to that runtime with 'x0'
+	 * as the new SP register. This destroys the C runtime context that had
+	 * been built on the stack below the saved context by the caller. Later
+	 * the second parameter 'x1' is passed as a return value to the caller.
+	 * ---------------------------------------------------------------------
+	 */
+func spm_secure_partition_exit
+	/* Restore the previous stack */
+	mov	sp, x0
+
+	/* Restore callee-saved registers on to the stack */
+	ldp	x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)]
+	ldp	x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)]
+	ldp	x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)]
+	ldp	x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)]
+	ldp	x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)]
+	ldp	x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)]
+
+	/* ---------------------------------------------------------------------
+	 * This should take us back to the instruction after the call to the
+	 * last spm_secure_partition_enter().* Place the second parameter to x0
+	 * so that the caller will see it as a return value from the original
+	 * entry call.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	x0, x1
+	ret
+endfunc spm_secure_partition_exit
diff --git a/services/std_svc/spm_mm/aarch64/spm_shim_exceptions.S b/services/std_svc/spm_mm/aarch64/spm_shim_exceptions.S
new file mode 100644
index 0000000..dab6150
--- /dev/null
+++ b/services/std_svc/spm_mm/aarch64/spm_shim_exceptions.S
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <context.h>
+
+/* -----------------------------------------------------------------------------
+ * Very simple stackless exception handlers used by the spm shim layer.
+ * -----------------------------------------------------------------------------
+ */
+	.globl	spm_shim_exceptions_ptr
+
+vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions
+
+	/* -----------------------------------------------------
+	 * Current EL with SP0 : 0x0 - 0x200
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry SynchronousExceptionSP0
+
+vector_entry IrqSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqSP0
+
+vector_entry FiqSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqSP0
+
+vector_entry SErrorSP0, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorSP0
+
+	/* -----------------------------------------------------
+	 * Current EL with SPx: 0x200 - 0x400
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry SynchronousExceptionSPx
+
+vector_entry IrqSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqSPx
+
+vector_entry FiqSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqSPx
+
+vector_entry SErrorSPx, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorSPx
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch64 : 0x400 - 0x600. No exceptions
+	 * are handled since secure_partition does not implement
+	 * a lower EL
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA64, .spm_shim_exceptions
+	msr	tpidr_el1, x30
+	mrs	x30, esr_el1
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+	cmp	x30, #EC_AARCH64_SVC
+	b.eq 	do_smc
+
+	cmp	x30, #EC_AARCH32_SVC
+	b.eq	do_smc
+
+	cmp	x30, #EC_AARCH64_SYS
+	b.eq	handle_sys_trap
+
+	/* Fail in all the other cases */
+	b	panic
+
+	/* ---------------------------------------------
+	 * Tell SPM that we are done initialising
+	 * ---------------------------------------------
+	 */
+do_smc:
+	mrs	x30, tpidr_el1
+	smc	#0
+	eret
+
+	/* AArch64 system instructions trap are handled as a panic for now */
+handle_sys_trap:
+panic:
+	b	panic
+end_vector_entry SynchronousExceptionA64
+
+vector_entry IrqA64, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqA64
+
+vector_entry FiqA64, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqA64
+
+vector_entry SErrorA64, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorA64
+
+	/* -----------------------------------------------------
+	 * Lower EL using AArch32 : 0x600 - 0x800
+	 * -----------------------------------------------------
+	 */
+vector_entry SynchronousExceptionA32, .spm_shim_exceptions
+	b	.
+end_vector_entry SynchronousExceptionA32
+
+vector_entry IrqA32, .spm_shim_exceptions
+	b	.
+end_vector_entry IrqA32
+
+vector_entry FiqA32, .spm_shim_exceptions
+	b	.
+end_vector_entry FiqA32
+
+vector_entry SErrorA32, .spm_shim_exceptions
+	b	.
+end_vector_entry SErrorA32
diff --git a/services/std_svc/spm_mm/spm.mk b/services/std_svc/spm_mm/spm.mk
new file mode 100644
index 0000000..3aa10ee
--- /dev/null
+++ b/services/std_svc/spm_mm/spm.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${SPD},none)
+        $(error "Error: SPD and SPM are incompatible build options.")
+endif
+ifneq (${ARCH},aarch64)
+        $(error "Error: SPM is only supported on aarch64.")
+endif
+
+SPM_SOURCES	:=	$(addprefix services/std_svc/spm_mm/,	\
+			${ARCH}/spm_helpers.S			\
+			${ARCH}/spm_shim_exceptions.S		\
+			spm_main.c				\
+			spm_setup.c				\
+			spm_xlat.c)
+
+
+# Let the top-level Makefile know that we intend to include a BL32 image
+NEED_BL32		:=	yes
+
+# required so that SPM code executing at S-EL0 can access the timer registers
+NS_TIMER_SWITCH		:=	1
diff --git a/services/std_svc/spm_mm/spm_main.c b/services/std_svc/spm_mm/spm_main.c
new file mode 100644
index 0000000..7525763
--- /dev/null
+++ b/services/std_svc/spm_mm/spm_main.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <services/mm_svc.h>
+#include <services/secure_partition.h>
+#include <services/spm_svc.h>
+#include <smccc_helpers.h>
+
+#include "spm_private.h"
+
+/*******************************************************************************
+ * Secure Partition context information.
+ ******************************************************************************/
+static sp_context_t sp_ctx;
+
+/*******************************************************************************
+ * Set state of a Secure Partition context.
+ ******************************************************************************/
+void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
+{
+	spin_lock(&(sp_ptr->state_lock));
+	sp_ptr->state = state;
+	spin_unlock(&(sp_ptr->state_lock));
+}
+
+/*******************************************************************************
+ * Wait until the state of a Secure Partition is the specified one and change it
+ * to the desired state.
+ ******************************************************************************/
+void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
+{
+	int success = 0;
+
+	while (success == 0) {
+		spin_lock(&(sp_ptr->state_lock));
+
+		if (sp_ptr->state == from) {
+			sp_ptr->state = to;
+
+			success = 1;
+		}
+
+		spin_unlock(&(sp_ptr->state_lock));
+	}
+}
+
+/*******************************************************************************
+ * Check if the state of a Secure Partition is the specified one and, if so,
+ * change it to the desired state. Returns 0 on success, -1 on error.
+ ******************************************************************************/
+int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
+{
+	int ret = -1;
+
+	spin_lock(&(sp_ptr->state_lock));
+
+	if (sp_ptr->state == from) {
+		sp_ptr->state = to;
+
+		ret = 0;
+	}
+
+	spin_unlock(&(sp_ptr->state_lock));
+
+	return ret;
+}
+
+/*******************************************************************************
+ * This function takes an SP context pointer and performs a synchronous entry
+ * into it.
+ ******************************************************************************/
+static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx)
+{
+	uint64_t rc;
+
+	assert(sp_ctx != NULL);
+
+	/* Assign the context of the SP to this CPU */
+	cm_set_context(&(sp_ctx->cpu_ctx), SECURE);
+
+	/* Restore the context assigned above */
+	cm_el1_sysregs_context_restore(SECURE);
+	cm_set_next_eret_context(SECURE);
+
+	/* Invalidate TLBs at EL1. */
+	tlbivmalle1();
+	dsbish();
+
+	/* Enter Secure Partition */
+	rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx);
+
+	/* Save secure state */
+	cm_el1_sysregs_context_save(SECURE);
+
+	return rc;
+}
+
+/*******************************************************************************
+ * This function returns to the place where spm_sp_synchronous_entry() was
+ * called originally.
+ ******************************************************************************/
+__dead2 static void spm_sp_synchronous_exit(uint64_t rc)
+{
+	sp_context_t *ctx = &sp_ctx;
+
+	/*
+	 * The SPM must have initiated the original request through a
+	 * synchronous entry into the secure partition. Jump back to the
+	 * original C runtime context with the value of rc in x0;
+	 */
+	spm_secure_partition_exit(ctx->c_rt_ctx, rc);
+
+	panic();
+}
+
+/*******************************************************************************
+ * Jump to each Secure Partition for the first time.
+ ******************************************************************************/
+static int32_t spm_init(void)
+{
+	uint64_t rc;
+	sp_context_t *ctx;
+
+	INFO("Secure Partition init...\n");
+
+	ctx = &sp_ctx;
+
+	ctx->state = SP_STATE_RESET;
+
+	rc = spm_sp_synchronous_entry(ctx);
+	assert(rc == 0);
+
+	ctx->state = SP_STATE_IDLE;
+
+	INFO("Secure Partition initialized.\n");
+
+	return !rc;
+}
+
+/*******************************************************************************
+ * Initialize contexts of all Secure Partitions.
+ ******************************************************************************/
+int32_t spm_setup(void)
+{
+	sp_context_t *ctx;
+
+	/* Disable MMU at EL1 (initialized by BL2) */
+	disable_mmu_icache_el1();
+
+	/* Initialize context of the SP */
+	INFO("Secure Partition context setup start...\n");
+
+	ctx = &sp_ctx;
+
+	/* Assign translation tables context. */
+	ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
+
+	spm_sp_setup(ctx);
+
+	/* Register init function for deferred init.  */
+	bl31_register_bl32_init(&spm_init);
+
+	INFO("Secure Partition setup done.\n");
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Function to perform a call to a Secure Partition.
+ ******************************************************************************/
+uint64_t spm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
+{
+	uint64_t rc;
+	sp_context_t *sp_ptr = &sp_ctx;
+
+	/* Wait until the Secure Partition is idle and set it to busy. */
+	sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
+
+	/* Set values for registers on SP entry */
+	cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
+
+	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
+	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
+	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
+	write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
+
+	/* Jump to the Secure Partition. */
+	rc = spm_sp_synchronous_entry(sp_ptr);
+
+	/* Flag Secure Partition as idle. */
+	assert(sp_ptr->state == SP_STATE_BUSY);
+	sp_state_set(sp_ptr, SP_STATE_IDLE);
+
+	return rc;
+}
+
+/*******************************************************************************
+ * MM_COMMUNICATE handler
+ ******************************************************************************/
+static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
+			       uint64_t comm_buffer_address,
+			       uint64_t comm_size_address, void *handle)
+{
+	uint64_t rc;
+
+	/* Cookie. Reserved for future use. It must be zero. */
+	if (mm_cookie != 0U) {
+		ERROR("MM_COMMUNICATE: cookie is not zero\n");
+		SMC_RET1(handle, SPM_INVALID_PARAMETER);
+	}
+
+	if (comm_buffer_address == 0U) {
+		ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
+		SMC_RET1(handle, SPM_INVALID_PARAMETER);
+	}
+
+	if (comm_size_address != 0U) {
+		VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
+	}
+
+	/*
+	 * The current secure partition design mandates
+	 * - at any point, only a single core can be
+	 *   executing in the secure partiton.
+	 * - a core cannot be preempted by an interrupt
+	 *   while executing in secure partition.
+	 * Raise the running priority of the core to the
+	 * interrupt level configured for secure partition
+	 * so as to block any interrupt from preempting this
+	 * core.
+	 */
+	ehf_activate_priority(PLAT_SP_PRI);
+
+	/* Save the Normal world context */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	rc = spm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
+			 plat_my_core_pos());
+
+	/* Restore non-secure state */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_set_next_eret_context(NON_SECURE);
+
+	/*
+	 * Exited from secure partition. This core can take
+	 * interrupts now.
+	 */
+	ehf_deactivate_priority(PLAT_SP_PRI);
+
+	SMC_RET1(handle, rc);
+}
+
+/*******************************************************************************
+ * Secure Partition Manager SMC handler.
+ ******************************************************************************/
+uint64_t spm_smc_handler(uint32_t smc_fid,
+			 uint64_t x1,
+			 uint64_t x2,
+			 uint64_t x3,
+			 uint64_t x4,
+			 void *cookie,
+			 void *handle,
+			 uint64_t flags)
+{
+	unsigned int ns;
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+
+	if (ns == SMC_FROM_SECURE) {
+
+		/* Handle SMCs from Secure world. */
+
+		assert(handle == cm_get_context(SECURE));
+
+		/* Make next ERET jump to S-EL0 instead of S-EL1. */
+		cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
+
+		switch (smc_fid) {
+
+		case SPM_VERSION_AARCH32:
+			SMC_RET1(handle, SPM_VERSION_COMPILED);
+
+		case SP_EVENT_COMPLETE_AARCH64:
+			spm_sp_synchronous_exit(x1);
+
+		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
+			INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
+
+			if (sp_ctx.state != SP_STATE_RESET) {
+				WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
+				SMC_RET1(handle, SPM_NOT_SUPPORTED);
+			}
+			SMC_RET1(handle,
+				 spm_memory_attributes_get_smc_handler(
+					 &sp_ctx, x1));
+
+		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
+			INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
+
+			if (sp_ctx.state != SP_STATE_RESET) {
+				WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
+				SMC_RET1(handle, SPM_NOT_SUPPORTED);
+			}
+			SMC_RET1(handle,
+				 spm_memory_attributes_set_smc_handler(
+					&sp_ctx, x1, x2, x3));
+		default:
+			break;
+		}
+	} else {
+
+		/* Handle SMCs from Non-secure world. */
+
+		assert(handle == cm_get_context(NON_SECURE));
+
+		switch (smc_fid) {
+
+		case MM_VERSION_AARCH32:
+			SMC_RET1(handle, MM_VERSION_COMPILED);
+
+		case MM_COMMUNICATE_AARCH32:
+		case MM_COMMUNICATE_AARCH64:
+			return mm_communicate(smc_fid, x1, x2, x3, handle);
+
+		case SP_MEMORY_ATTRIBUTES_GET_AARCH64:
+		case SP_MEMORY_ATTRIBUTES_SET_AARCH64:
+			/* SMC interfaces reserved for secure callers. */
+			SMC_RET1(handle, SPM_NOT_SUPPORTED);
+
+		default:
+			break;
+		}
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/services/std_svc/spm_mm/spm_private.h b/services/std_svc/spm_mm/spm_private.h
new file mode 100644
index 0000000..ba94a4d
--- /dev/null
+++ b/services/std_svc/spm_mm/spm_private.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_PRIVATE_H
+#define SPM_PRIVATE_H
+
+#include <context.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define SP_C_RT_CTX_X19		0x0
+#define SP_C_RT_CTX_X20		0x8
+#define SP_C_RT_CTX_X21		0x10
+#define SP_C_RT_CTX_X22		0x18
+#define SP_C_RT_CTX_X23		0x20
+#define SP_C_RT_CTX_X24		0x28
+#define SP_C_RT_CTX_X25		0x30
+#define SP_C_RT_CTX_X26		0x38
+#define SP_C_RT_CTX_X27		0x40
+#define SP_C_RT_CTX_X28		0x48
+#define SP_C_RT_CTX_X29		0x50
+#define SP_C_RT_CTX_X30		0x58
+
+#define SP_C_RT_CTX_SIZE	0x60
+#define SP_C_RT_CTX_ENTRIES	(SP_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+typedef enum sp_state {
+	SP_STATE_RESET = 0,
+	SP_STATE_IDLE,
+	SP_STATE_BUSY
+} sp_state_t;
+
+typedef struct sp_context {
+	uint64_t c_rt_ctx;
+	cpu_context_t cpu_ctx;
+	xlat_ctx_t *xlat_ctx_handle;
+
+	sp_state_t state;
+	spinlock_t state_lock;
+} sp_context_t;
+
+/* Assembly helpers */
+uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx);
+void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret);
+
+void spm_sp_setup(sp_context_t *sp_ctx);
+
+xlat_ctx_t *spm_get_sp_xlat_context(void);
+
+int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx,
+					      uintptr_t base_va);
+int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx,
+					  u_register_t page_address,
+					  u_register_t pages_count,
+					  u_register_t smc_attributes);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* SPM_PRIVATE_H */
diff --git a/services/std_svc/spm_mm/spm_setup.c b/services/std_svc/spm_mm/spm_setup.c
new file mode 100644
index 0000000..aae6cd5
--- /dev/null
+++ b/services/std_svc/spm_mm/spm_setup.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <services/secure_partition.h>
+
+#include "spm_private.h"
+#include "spm_shim_private.h"
+
+/* Setup context of the Secure Partition */
+void spm_sp_setup(sp_context_t *sp_ctx)
+{
+	cpu_context_t *ctx = &(sp_ctx->cpu_ctx);
+
+	/*
+	 * Initialize CPU context
+	 * ----------------------
+	 */
+
+	entry_point_info_t ep_info = {0};
+
+	SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE);
+
+	/* Setup entrypoint and SPSR */
+	ep_info.pc = BL32_BASE;
+	ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS);
+
+	/*
+	 * X0: Virtual address of a buffer shared between EL3 and Secure EL0.
+	 *     The buffer will be mapped in the Secure EL1 translation regime
+	 *     with Normal IS WBWA attributes and RO data and Execute Never
+	 *     instruction access permissions.
+	 *
+	 * X1: Size of the buffer in bytes
+	 *
+	 * X2: cookie value (Implementation Defined)
+	 *
+	 * X3: cookie value (Implementation Defined)
+	 *
+	 * X4 to X7 = 0
+	 */
+	ep_info.args.arg0 = PLAT_SPM_BUF_BASE;
+	ep_info.args.arg1 = PLAT_SPM_BUF_SIZE;
+	ep_info.args.arg2 = PLAT_SPM_COOKIE_0;
+	ep_info.args.arg3 = PLAT_SPM_COOKIE_1;
+
+	cm_setup_context(ctx, &ep_info);
+
+	/*
+	 * SP_EL0: A non-zero value will indicate to the SP that the SPM has
+	 * initialized the stack pointer for the current CPU through
+	 * implementation defined means. The value will be 0 otherwise.
+	 */
+	write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0,
+			PLAT_SP_IMAGE_STACK_BASE + PLAT_SP_IMAGE_STACK_PCPU_SIZE);
+
+	/*
+	 * Setup translation tables
+	 * ------------------------
+	 */
+
+#if ENABLE_ASSERTIONS
+
+	/* Get max granularity supported by the platform. */
+	unsigned int max_granule = xlat_arch_get_max_supported_granule_size();
+
+	VERBOSE("Max translation granule size supported: %u KiB\n",
+		max_granule / 1024U);
+
+	unsigned int max_granule_mask = max_granule - 1U;
+
+	/* Base must be aligned to the max granularity */
+	assert((PLAT_SP_IMAGE_NS_BUF_BASE & max_granule_mask) == 0);
+
+	/* Size must be a multiple of the max granularity */
+	assert((PLAT_SP_IMAGE_NS_BUF_SIZE & max_granule_mask) == 0);
+
+#endif /* ENABLE_ASSERTIONS */
+
+	/* This region contains the exception vectors used at S-EL1. */
+	const mmap_region_t sel1_exception_vectors =
+		MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
+				SPM_SHIM_EXCEPTIONS_SIZE,
+				MT_CODE | MT_SECURE | MT_PRIVILEGED);
+	mmap_add_region_ctx(sp_ctx->xlat_ctx_handle,
+			    &sel1_exception_vectors);
+
+	mmap_add_ctx(sp_ctx->xlat_ctx_handle,
+		     plat_get_secure_partition_mmap(NULL));
+
+	init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle);
+
+	/*
+	 * MMU-related registers
+	 * ---------------------
+	 */
+	xlat_ctx_t *xlat_ctx = sp_ctx->xlat_ctx_handle;
+
+	uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
+
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table,
+		      xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
+		      EL1_EL0_REGIME);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1,
+		      mmu_cfg_params[MMU_CFG_MAIR]);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1,
+		      mmu_cfg_params[MMU_CFG_TCR]);
+
+	write_ctx_reg(get_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);
+
+	sctlr_el1 |=
+		/*SCTLR_EL1_RES1 |*/
+		/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
+		SCTLR_UCI_BIT							|
+		/* RW regions at xlat regime EL1&0 are forced to be XN. */
+		SCTLR_WXN_BIT							|
+		/* Don't trap to EL1 execution of WFI or WFE at EL0. */
+		SCTLR_NTWI_BIT | SCTLR_NTWE_BIT					|
+		/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
+		SCTLR_UCT_BIT							|
+		/* Don't trap to EL1 execution of DZ ZVA at EL0. */
+		SCTLR_DZE_BIT							|
+		/* Enable SP Alignment check for EL0 */
+		SCTLR_SA0_BIT							|
+		/* Allow cacheable data and instr. accesses to normal memory. */
+		SCTLR_C_BIT | SCTLR_I_BIT					|
+		/* Enable MMU. */
+		SCTLR_M_BIT
+	;
+
+	sctlr_el1 &= ~(
+		/* Explicit data accesses at EL0 are little-endian. */
+		SCTLR_E0E_BIT							|
+		/*
+		 * Alignment fault checking disabled when at EL1 and EL0 as
+		 * the UEFI spec permits unaligned accesses.
+		 */
+		SCTLR_A_BIT							|
+		/* Accesses to DAIF from EL0 are trapped to EL1. */
+		SCTLR_UMA_BIT
+	);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+
+	/*
+	 * Setup other system registers
+	 * ----------------------------
+	 */
+
+	/* Shim Exception Vector Base Address */
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1,
+			SPM_SHIM_EXCEPTIONS_PTR);
+
+	write_ctx_reg(get_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
+		      EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT);
+
+	/*
+	 * FPEN: Allow the Secure Partition to access FP/SIMD registers.
+	 * Note that SPM will not do any saving/restoring of these registers on
+	 * behalf of the SP. This falls under the SP's responsibility.
+	 * 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,
+			CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
+
+	/*
+	 * Prepare information in buffer shared between EL3 and S-EL0
+	 * ----------------------------------------------------------
+	 */
+
+	void *shared_buf_ptr = (void *) PLAT_SPM_BUF_BASE;
+
+	/* Copy the boot information into the shared buffer with the SP. */
+	assert((uintptr_t)shared_buf_ptr + sizeof(secure_partition_boot_info_t)
+	       <= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE));
+
+	assert(PLAT_SPM_BUF_BASE <= (UINTPTR_MAX - PLAT_SPM_BUF_SIZE + 1));
+
+	const secure_partition_boot_info_t *sp_boot_info =
+			plat_get_secure_partition_boot_info(NULL);
+
+	assert(sp_boot_info != NULL);
+
+	memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info,
+	       sizeof(secure_partition_boot_info_t));
+
+	/* Pointer to the MP information from the platform port. */
+	secure_partition_mp_info_t *sp_mp_info =
+		((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info;
+
+	assert(sp_mp_info != NULL);
+
+	/*
+	 * Point the shared buffer MP information pointer to where the info will
+	 * be populated, just after the boot info.
+	 */
+	((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info =
+		(secure_partition_mp_info_t *) ((uintptr_t)shared_buf_ptr
+				+ sizeof(secure_partition_boot_info_t));
+
+	/*
+	 * Update the shared buffer pointer to where the MP information for the
+	 * payload will be populated
+	 */
+	shared_buf_ptr = ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info;
+
+	/*
+	 * Copy the cpu information into the shared buffer area after the boot
+	 * information.
+	 */
+	assert(sp_boot_info->num_cpus <= PLATFORM_CORE_COUNT);
+
+	assert((uintptr_t)shared_buf_ptr
+	       <= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE -
+		       (sp_boot_info->num_cpus * sizeof(*sp_mp_info))));
+
+	memcpy(shared_buf_ptr, (const void *) sp_mp_info,
+		sp_boot_info->num_cpus * sizeof(*sp_mp_info));
+
+	/*
+	 * Calculate the linear indices of cores in boot information for the
+	 * secure partition and flag the primary CPU
+	 */
+	sp_mp_info = (secure_partition_mp_info_t *) shared_buf_ptr;
+
+	for (unsigned int index = 0; index < sp_boot_info->num_cpus; index++) {
+		u_register_t mpidr = sp_mp_info[index].mpidr;
+
+		sp_mp_info[index].linear_id = plat_core_pos_by_mpidr(mpidr);
+		if (plat_my_core_pos() == sp_mp_info[index].linear_id)
+			sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU;
+	}
+}
diff --git a/services/std_svc/spm_mm/spm_shim_private.h b/services/std_svc/spm_mm/spm_shim_private.h
new file mode 100644
index 0000000..7fe9692
--- /dev/null
+++ b/services/std_svc/spm_mm/spm_shim_private.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SPM_SHIM_PRIVATE_H
+#define SPM_SHIM_PRIVATE_H
+
+#include <stdint.h>
+
+#include <lib/utils_def.h>
+
+/* Assembly source */
+IMPORT_SYM(uintptr_t, spm_shim_exceptions_ptr,		SPM_SHIM_EXCEPTIONS_PTR);
+
+/* Linker symbols */
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__,	SPM_SHIM_EXCEPTIONS_START);
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__,	SPM_SHIM_EXCEPTIONS_END);
+
+/* Definitions */
+
+#define SPM_SHIM_EXCEPTIONS_SIZE	\
+	(SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START)
+
+#endif /* SPM_SHIM_PRIVATE_H */
diff --git a/services/std_svc/spm_mm/spm_xlat.c b/services/std_svc/spm_mm/spm_xlat.c
new file mode 100644
index 0000000..f54168e
--- /dev/null
+++ b/services/std_svc/spm_mm/spm_xlat.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <errno.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <plat/common/platform.h>
+#include <services/secure_partition.h>
+#include <services/spm_svc.h>
+
+#include "spm_private.h"
+#include "spm_shim_private.h"
+
+/* Place translation tables by default along with the ones used by BL31. */
+#ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME	"xlat_table"
+#endif
+
+/* Allocate and initialise the translation context for the secure partitions. */
+REGISTER_XLAT_CONTEXT2(sp,
+		       PLAT_SP_IMAGE_MMAP_REGIONS,
+		       PLAT_SP_IMAGE_MAX_XLAT_TABLES,
+		       PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE,
+		       EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME);
+
+/* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */
+static spinlock_t mem_attr_smc_lock;
+
+/* Get handle of Secure Partition translation context */
+xlat_ctx_t *spm_get_sp_xlat_context(void)
+{
+	return &sp_xlat_ctx;
+};
+
+/*
+ * Attributes are encoded using a different format in the SMC interface than in
+ * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
+ * converts an attributes value from the SMC format to the mmap_attr_t format by
+ * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
+ * The other fields are left as 0 because they are ignored by the function
+ * xlat_change_mem_attributes_ctx().
+ */
+static unsigned int smc_attr_to_mmap_attr(unsigned int attributes)
+{
+	unsigned int tf_attr = 0U;
+
+	unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
+			      >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
+
+	if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) {
+		tf_attr |= MT_RW | MT_USER;
+	} else if (access ==  SP_MEMORY_ATTRIBUTES_ACCESS_RO) {
+		tf_attr |= MT_RO | MT_USER;
+	} else {
+		/* Other values are reserved. */
+		assert(access ==  SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS);
+		/* The only requirement is that there's no access from EL0 */
+		tf_attr |= MT_RO | MT_PRIVILEGED;
+	}
+
+	if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) {
+		tf_attr |= MT_EXECUTE;
+	} else {
+		tf_attr |= MT_EXECUTE_NEVER;
+	}
+
+	return tf_attr;
+}
+
+/*
+ * This function converts attributes from the Trusted Firmware format into the
+ * SMC interface format.
+ */
+static unsigned int smc_mmap_to_smc_attr(unsigned int attr)
+{
+	unsigned int smc_attr = 0U;
+
+	unsigned int data_access;
+
+	if ((attr & MT_USER) == 0) {
+		/* No access from EL0. */
+		data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS;
+	} else {
+		if ((attr & MT_RW) != 0) {
+			assert(MT_TYPE(attr) != MT_DEVICE);
+			data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW;
+		} else {
+			data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO;
+		}
+	}
+
+	smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
+		    << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT;
+
+	if ((attr & MT_EXECUTE_NEVER) != 0U) {
+		smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC;
+	}
+
+	return smc_attr;
+}
+
+int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx,
+					      uintptr_t base_va)
+{
+	uint32_t attributes;
+
+	spin_lock(&mem_attr_smc_lock);
+
+	int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+				     base_va, &attributes);
+
+	spin_unlock(&mem_attr_smc_lock);
+
+	/* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */
+	assert((rc == 0) || (rc == -EINVAL));
+
+	if (rc == 0) {
+		return (int32_t) smc_mmap_to_smc_attr(attributes);
+	} else {
+		return SPM_INVALID_PARAMETER;
+	}
+}
+
+int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx,
+					  u_register_t page_address,
+					  u_register_t pages_count,
+					  u_register_t smc_attributes)
+{
+	uintptr_t base_va = (uintptr_t) page_address;
+	size_t size = (size_t) (pages_count * PAGE_SIZE);
+	uint32_t attributes = (uint32_t) smc_attributes;
+
+	INFO("  Start address  : 0x%lx\n", base_va);
+	INFO("  Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
+	INFO("  Attributes     : 0x%x\n", attributes);
+
+	spin_lock(&mem_attr_smc_lock);
+
+	int ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
+					base_va, size,
+					smc_attr_to_mmap_attr(attributes));
+
+	spin_unlock(&mem_attr_smc_lock);
+
+	/* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */
+	assert((ret == 0) || (ret == -EINVAL));
+
+	return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER;
+}
diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c
new file mode 100644
index 0000000..1d80fa3
--- /dev/null
+++ b/services/std_svc/std_svc_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/el3_runtime/cpu_data.h>
+#include <lib/pmf/pmf.h>
+#include <lib/psci/psci.h>
+#include <lib/runtime_instr.h>
+#include <services/sdei.h>
+#include <services/spm_svc.h>
+#include <services/std_svc.h>
+#include <smccc_helpers.h>
+#include <tools_share/uuid.h>
+
+/* Standard Service UUID */
+static uuid_t arm_svc_uid = {
+	{0x5b, 0x90, 0x8d, 0x10},
+	{0x63, 0xf8},
+	{0xe8, 0x47},
+	0xae, 0x2d,
+	{0xc0, 0xfb, 0x56, 0x41, 0xf6, 0xe2}
+};
+
+/* Setup Standard Services */
+static int32_t std_svc_setup(void)
+{
+	uintptr_t svc_arg;
+	int ret = 0;
+
+	svc_arg = get_arm_std_svc_args(PSCI_FID_MASK);
+	assert(svc_arg);
+
+	/*
+	 * PSCI is one of the specifications implemented as a Standard Service.
+	 * The `psci_setup()` also does EL3 architectural setup.
+	 */
+	if (psci_setup((const psci_lib_args_t *)svc_arg) != PSCI_E_SUCCESS) {
+		ret = 1;
+	}
+
+#if ENABLE_SPM
+	if (spm_setup() != 0) {
+		ret = 1;
+	}
+#endif
+
+#if SDEI_SUPPORT
+	/* SDEI initialisation */
+	sdei_init();
+#endif
+
+	return ret;
+}
+
+/*
+ * Top-level Standard Service SMC handler. This handler will in turn dispatch
+ * calls to PSCI SMC handler
+ */
+static uintptr_t std_svc_smc_handler(uint32_t smc_fid,
+			     u_register_t x1,
+			     u_register_t x2,
+			     u_register_t x3,
+			     u_register_t x4,
+			     void *cookie,
+			     void *handle,
+			     u_register_t flags)
+{
+	/*
+	 * Dispatch PSCI calls to PSCI SMC handler and return its return
+	 * value
+	 */
+	if (is_psci_fid(smc_fid)) {
+		uint64_t ret;
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+
+		/*
+		 * Flush cache line so that even if CPU power down happens
+		 * the timestamp update is reflected in memory.
+		 */
+		PMF_WRITE_TIMESTAMP(rt_instr_svc,
+		    RT_INSTR_ENTER_PSCI,
+		    PMF_CACHE_MAINT,
+		    get_cpu_data(cpu_data_pmf_ts[CPU_DATA_PMF_TS0_IDX]));
+#endif
+
+		ret = psci_smc_handler(smc_fid, x1, x2, x3, x4,
+		    cookie, handle, flags);
+
+#if ENABLE_RUNTIME_INSTRUMENTATION
+		PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
+		    RT_INSTR_EXIT_PSCI,
+		    PMF_NO_CACHE_MAINT);
+#endif
+
+		SMC_RET1(handle, ret);
+	}
+
+#if ENABLE_SPM && SPM_MM
+	/*
+	 * Dispatch SPM calls to SPM SMC handler and return its return
+	 * value
+	 */
+	if (is_spm_fid(smc_fid)) {
+		return spm_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+				       handle, flags);
+	}
+#endif
+
+#if SDEI_SUPPORT
+	if (is_sdei_fid(smc_fid)) {
+		return sdei_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+				flags);
+	}
+#endif
+
+	switch (smc_fid) {
+	case ARM_STD_SVC_CALL_COUNT:
+		/*
+		 * Return the number of Standard Service Calls. PSCI is the only
+		 * standard service implemented; so return number of PSCI calls
+		 */
+		SMC_RET1(handle, PSCI_NUM_CALLS);
+
+	case ARM_STD_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, arm_svc_uid);
+
+	case ARM_STD_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, STD_SVC_VERSION_MAJOR, STD_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented Standard Service Call: 0x%x \n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Register Standard Service Calls as runtime service */
+DECLARE_RT_SVC(
+		std_svc,
+
+		OEN_STD_START,
+		OEN_STD_END,
+		SMC_TYPE_FAST,
+		std_svc_setup,
+		std_svc_smc_handler
+);
diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile
new file mode 100644
index 0000000..c03629a
--- /dev/null
+++ b/tools/cert_create/Makefile
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PROJECT		:= cert_create
+PLAT		:= none
+V		?= 0
+DEBUG		:= 0
+BINARY		:= ${PROJECT}${BIN_EXT}
+OPENSSL_DIR	:= /usr
+USE_TBBR_DEFS   := 1
+
+OBJECTS := src/cert.o \
+           src/cmd_opt.o \
+           src/ext.o \
+           src/key.o \
+           src/main.o \
+           src/sha.o \
+           src/tbbr/tbb_cert.o \
+           src/tbbr/tbb_ext.o \
+           src/tbbr/tbb_key.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 (${USE_TBBR_DEFS},1)
+# In this case, cert_tool is platform-independent
+PLAT_MSG		:=	TBBR Generic
+PLAT_INCLUDE		:=	../../include/tools_share
+else
+PLAT_MSG		:=	${PLAT}
+
+TF_PLATFORM_ROOT		:=	../../plat/
+include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk
+
+PLAT_INCLUDE		:=	$(wildcard ${PLAT_DIR}include)
+
+ifeq ($(PLAT_INCLUDE),)
+  $(error "Error: Invalid platform '${PLAT}' has no include directory.")
+endif
+endif
+
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
+else
+  HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
+endif
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+$(eval $(call add_define,USE_TBBR_DEFS))
+HOSTCCFLAGS += ${DEFINES}
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INC_DIR := -I ./include -I ${PLAT_INCLUDE} -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__; \
+                const char platform_msg[] = "${PLAT_MSG}";' | \
+                ${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/cert_create/include/cert.h b/tools/cert_create/include/cert.h
new file mode 100644
index 0000000..39b45b5
--- /dev/null
+++ b/tools/cert_create/include/cert.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CERT_H
+#define CERT_H
+
+#include <openssl/ossl_typ.h>
+#include <openssl/x509.h>
+#include "ext.h"
+#include "key.h"
+
+#define CERT_MAX_EXT			5
+
+/*
+ * This structure contains information related to the generation of the
+ * certificates. All these fields must be known and specified at build time
+ * except for the file name, which is picked up from the command line at
+ * run time.
+ *
+ * One instance of this structure must be created for each of the certificates
+ * present in the chain of trust.
+ *
+ * If the issuer points to this same instance, the generated certificate will
+ * be self-signed.
+ */
+typedef struct cert_s cert_t;
+struct cert_s {
+	int id;			/* Unique identifier */
+
+	const char *opt;	/* Command line option to pass filename */
+	const char *fn;		/* Filename to save the certificate */
+	const char *cn;		/* Subject CN (Company Name) */
+	const char *help_msg;	/* Help message */
+
+	/* These fields must be defined statically */
+	int key;		/* Key to be signed */
+	int issuer;		/* Issuer certificate */
+	int ext[CERT_MAX_EXT];	/* Certificate extensions */
+	int num_ext;		/* Number of extensions in the certificate */
+
+	X509 *x;		/* X509 certificate container */
+};
+
+/* Exported API */
+int cert_init(void);
+cert_t *cert_get_by_opt(const char *opt);
+int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value);
+int cert_new(
+	int key_alg,
+	int md_alg,
+	cert_t *cert,
+	int days,
+	int ca,
+	STACK_OF(X509_EXTENSION) * sk);
+
+/* Macro to register the certificates used in the CoT */
+#define REGISTER_COT(_certs) \
+	cert_t *certs = &_certs[0]; \
+	const unsigned int num_certs = sizeof(_certs)/sizeof(_certs[0])
+
+/* Exported variables */
+extern cert_t *certs;
+extern const unsigned int num_certs;
+
+#endif /* CERT_H */
diff --git a/tools/cert_create/include/cmd_opt.h b/tools/cert_create/include/cmd_opt.h
new file mode 100644
index 0000000..10df00e
--- /dev/null
+++ b/tools/cert_create/include/cmd_opt.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. 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_CERT,
+	CMD_OPT_KEY,
+	CMD_OPT_EXT
+};
+
+/* 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/cert_create/include/debug.h b/tools/cert_create/include/debug.h
new file mode 100644
index 0000000..ee8f1f5
--- /dev/null
+++ b/tools/cert_create/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/cert_create/include/ext.h b/tools/cert_create/include/ext.h
new file mode 100644
index 0000000..9c0b5c3
--- /dev/null
+++ b/tools/cert_create/include/ext.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EXT_H
+#define EXT_H
+
+#include <openssl/x509v3.h>
+#include "key.h"
+
+/* Extension types supported */
+enum ext_type_e {
+	EXT_TYPE_NVCOUNTER,
+	EXT_TYPE_PKEY,
+	EXT_TYPE_HASH
+};
+
+/* NV-Counter types */
+enum nvctr_type_e {
+	NVCTR_TYPE_TFW,
+	NVCTR_TYPE_NTFW
+};
+
+/*
+ * This structure contains the relevant information to create the extensions
+ * to be included in the certificates. This extensions will be used to
+ * establish the chain of trust.
+ */
+typedef struct ext_s {
+	const char *oid;	/* OID of the extension */
+	const char *sn;		/* Short name */
+	const char *ln;		/* Long description */
+	const char *opt;	/* Command line option to specify data */
+	const char *help_msg;	/* Help message */
+	const char *arg;	/* Argument passed from command line */
+	int asn1_type;		/* OpenSSL ASN1 type of the extension data.
+				 * Supported types are:
+				 *   - V_ASN1_INTEGER
+				 *   - V_ASN1_OCTET_STRING
+				 */
+	int type;		/* See ext_type_e */
+
+	/* Extension attributes (depends on extension type) */
+	union {
+		int nvctr_type;	/* See nvctr_type_e */
+		int key;	/* Index into array of registered public keys */
+	} attr;
+
+	int alias;		/* In case OpenSSL provides an standard
+				 * extension of the same type, add the new
+				 * extension as an alias of this one
+				 */
+
+	X509V3_EXT_METHOD method; /* This field may be used to define a custom
+				   * function to print the contents of the
+				   * extension */
+
+	int optional;	/* This field may be used optionally to exclude an image */
+} ext_t;
+
+enum {
+	EXT_NON_CRIT = 0,
+	EXT_CRIT = !EXT_NON_CRIT,
+};
+
+/* Exported API */
+int ext_init(void);
+ext_t *ext_get_by_opt(const char *opt);
+X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
+		unsigned char *buf, size_t len);
+X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value);
+X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k);
+
+/* Macro to register the extensions used in the CoT */
+#define REGISTER_EXTENSIONS(_ext) \
+	ext_t *extensions = &_ext[0]; \
+	const unsigned int num_extensions = sizeof(_ext)/sizeof(_ext[0])
+
+/* Exported variables */
+extern ext_t *extensions;
+extern const unsigned int num_extensions;
+
+#endif /* EXT_H */
diff --git a/tools/cert_create/include/key.h b/tools/cert_create/include/key.h
new file mode 100644
index 0000000..310a77f
--- /dev/null
+++ b/tools/cert_create/include/key.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef KEY_H
+#define KEY_H
+
+#include <openssl/ossl_typ.h>
+
+#define RSA_KEY_BITS		2048
+
+/* Error codes */
+enum {
+	KEY_ERR_NONE,
+	KEY_ERR_MALLOC,
+	KEY_ERR_FILENAME,
+	KEY_ERR_OPEN,
+	KEY_ERR_LOAD
+};
+
+/* Supported key algorithms */
+enum {
+	KEY_ALG_RSA,		/* RSA PSS as defined by PKCS#1 v2.1 (default) */
+	KEY_ALG_RSA_1_5,	/* RSA as defined by PKCS#1 v1.5 */
+#ifndef OPENSSL_NO_EC
+	KEY_ALG_ECDSA,
+#endif /* OPENSSL_NO_EC */
+	KEY_ALG_MAX_NUM
+};
+
+/* Supported hash algorithms */
+enum{
+	HASH_ALG_SHA256,
+	HASH_ALG_SHA384,
+	HASH_ALG_SHA512,
+};
+
+/*
+ * This structure contains the relevant information to create the keys
+ * required to sign the certificates.
+ *
+ * One instance of this structure must be created for each key, usually in an
+ * array fashion. The filename is obtained at run time from the command line
+ * parameters
+ */
+typedef struct key_s {
+	int id;			/* Key id */
+	const char *opt;	/* Command line option to specify a key */
+	const char *help_msg;	/* Help message */
+	const char *desc;	/* Key description (debug purposes) */
+	char *fn;		/* Filename to load/store the key */
+	EVP_PKEY *key;		/* Key container */
+} key_t;
+
+/* Exported API */
+int key_init(void);
+key_t *key_get_by_opt(const char *opt);
+int key_new(key_t *key);
+int key_create(key_t *key, int type);
+int key_load(key_t *key, unsigned int *err_code);
+int key_store(key_t *key);
+
+/* Macro to register the keys used in the CoT */
+#define REGISTER_KEYS(_keys) \
+	key_t *keys = &_keys[0]; \
+	const unsigned int num_keys = sizeof(_keys)/sizeof(_keys[0])
+
+/* Exported variables */
+extern key_t *keys;
+extern const unsigned int num_keys;
+
+#endif /* KEY_H */
diff --git a/tools/cert_create/include/sha.h b/tools/cert_create/include/sha.h
new file mode 100644
index 0000000..4c55f37
--- /dev/null
+++ b/tools/cert_create/include/sha.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SHA_H
+#define SHA_H
+
+int sha_file(int md_alg, const char *filename, unsigned char *md);
+
+#endif /* SHA_H */
diff --git a/tools/cert_create/include/tbbr/tbb_cert.h b/tools/cert_create/include/tbbr/tbb_cert.h
new file mode 100644
index 0000000..628ef3a
--- /dev/null
+++ b/tools/cert_create/include/tbbr/tbb_cert.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBB_CERT_H
+#define TBB_CERT_H
+
+#include "cert.h"
+
+/*
+ * Enumerate the certificates that are used to establish the chain of trust
+ */
+enum {
+	TRUSTED_BOOT_FW_CERT,
+	TRUSTED_KEY_CERT,
+	SCP_FW_KEY_CERT,
+	SCP_FW_CONTENT_CERT,
+	SOC_FW_KEY_CERT,
+	SOC_FW_CONTENT_CERT,
+	TRUSTED_OS_FW_KEY_CERT,
+	TRUSTED_OS_FW_CONTENT_CERT,
+	NON_TRUSTED_FW_KEY_CERT,
+	NON_TRUSTED_FW_CONTENT_CERT,
+	FWU_CERT
+};
+
+#endif /* TBB_CERT_H */
diff --git a/tools/cert_create/include/tbbr/tbb_ext.h b/tools/cert_create/include/tbbr/tbb_ext.h
new file mode 100644
index 0000000..462aafc
--- /dev/null
+++ b/tools/cert_create/include/tbbr/tbb_ext.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef TBB_EXT_H
+#define TBB_EXT_H
+
+#include "ext.h"
+
+/* TBBR extensions */
+enum {
+	TRUSTED_FW_NVCOUNTER_EXT,
+	NON_TRUSTED_FW_NVCOUNTER_EXT,
+	TRUSTED_BOOT_FW_HASH_EXT,
+	TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
+	HW_CONFIG_HASH_EXT,
+	TRUSTED_WORLD_PK_EXT,
+	NON_TRUSTED_WORLD_PK_EXT,
+	SCP_FW_CONTENT_CERT_PK_EXT,
+	SCP_FW_HASH_EXT,
+	SOC_FW_CONTENT_CERT_PK_EXT,
+	SOC_AP_FW_HASH_EXT,
+	SOC_FW_CONFIG_HASH_EXT,
+	TRUSTED_OS_FW_CONTENT_CERT_PK_EXT,
+	TRUSTED_OS_FW_HASH_EXT,
+	TRUSTED_OS_FW_EXTRA1_HASH_EXT,
+	TRUSTED_OS_FW_EXTRA2_HASH_EXT,
+	TRUSTED_OS_FW_CONFIG_HASH_EXT,
+	NON_TRUSTED_FW_CONTENT_CERT_PK_EXT,
+	NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT,
+	NON_TRUSTED_FW_CONFIG_HASH_EXT,
+	SCP_FWU_CFG_HASH_EXT,
+	AP_FWU_CFG_HASH_EXT,
+	FWU_HASH_EXT
+};
+
+#endif /* TBB_EXT_H */
diff --git a/tools/cert_create/include/tbbr/tbb_key.h b/tools/cert_create/include/tbbr/tbb_key.h
new file mode 100644
index 0000000..47ad1de
--- /dev/null
+++ b/tools/cert_create/include/tbbr/tbb_key.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBB_KEY_H
+#define TBB_KEY_H
+
+#include "key.h"
+
+/*
+ * Enumerate the keys that are used to establish the chain of trust
+ */
+enum {
+	ROT_KEY,
+	TRUSTED_WORLD_KEY,
+	NON_TRUSTED_WORLD_KEY,
+	SCP_FW_CONTENT_CERT_KEY,
+	SOC_FW_CONTENT_CERT_KEY,
+	TRUSTED_OS_FW_CONTENT_CERT_KEY,
+	NON_TRUSTED_FW_CONTENT_CERT_KEY
+};
+
+#endif /* TBB_KEY_H */
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
new file mode 100644
index 0000000..8e8aee6
--- /dev/null
+++ b/tools/cert_create/src/cert.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/opensslv.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/x509v3.h>
+
+#if USE_TBBR_DEFS
+#include <tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+#include "cert.h"
+#include "cmd_opt.h"
+#include "debug.h"
+#include "key.h"
+#include "sha.h"
+
+#define SERIAL_RAND_BITS	64
+#define RSA_SALT_LEN		32
+
+int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
+{
+	BIGNUM *btmp;
+	int ret = 0;
+	if (b)
+		btmp = b;
+	else
+		btmp = BN_new();
+
+	if (!btmp)
+		return 0;
+
+	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
+		goto error;
+	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
+		goto error;
+
+	ret = 1;
+
+error:
+
+	if (!b)
+		BN_free(btmp);
+
+	return ret;
+}
+const EVP_MD *get_digest(int alg)
+{
+	switch (alg) {
+	case HASH_ALG_SHA256:
+		return EVP_sha256();
+	case HASH_ALG_SHA384:
+		return EVP_sha384();
+	case HASH_ALG_SHA512:
+		return EVP_sha512();
+	default:
+		return NULL;
+	}
+}
+
+int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
+{
+	X509_EXTENSION *ex;
+	X509V3_CTX ctx;
+
+	/* No configuration database */
+	X509V3_set_ctx_nodb(&ctx);
+
+	/* Set issuer and subject certificates in the context */
+	X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
+	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
+	if (!ex) {
+		ERR_print_errors_fp(stdout);
+		return 0;
+	}
+
+	X509_add_ext(subject, ex, -1);
+	X509_EXTENSION_free(ex);
+
+	return 1;
+}
+
+int cert_new(
+	int key_alg,
+	int md_alg,
+	cert_t *cert,
+	int days,
+	int ca,
+	STACK_OF(X509_EXTENSION) * sk)
+{
+	EVP_PKEY *pkey = keys[cert->key].key;
+	cert_t *issuer_cert = &certs[cert->issuer];
+	EVP_PKEY *ikey = keys[issuer_cert->key].key;
+	X509 *issuer = issuer_cert->x;
+	X509 *x;
+	X509_EXTENSION *ex;
+	X509_NAME *name;
+	ASN1_INTEGER *sno;
+	int i, num, rc = 0;
+	EVP_MD_CTX *mdCtx;
+	EVP_PKEY_CTX *pKeyCtx = NULL;
+
+	/* Create the certificate structure */
+	x = X509_new();
+	if (!x) {
+		return 0;
+	}
+
+	/* If we do not have a key, use the issuer key (the certificate will
+	 * become self signed). This happens in content certificates. */
+	if (!pkey) {
+		pkey = ikey;
+	}
+
+	/* If we do not have an issuer certificate, use our own (the certificate
+	 * will become self signed) */
+	if (!issuer) {
+		issuer = x;
+	}
+
+	mdCtx = EVP_MD_CTX_create();
+	if (mdCtx == NULL) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
+	/* Sign the certificate with the issuer key */
+	if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
+	/*
+	 * Set additional parameters if algorithm is RSA PSS. This is not
+	 * required for RSA 1.5 or ECDSA.
+	 */
+	if (key_alg == KEY_ALG_RSA) {
+		if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
+			ERR_print_errors_fp(stdout);
+			goto END;
+		}
+
+		if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
+			ERR_print_errors_fp(stdout);
+			goto END;
+		}
+
+		if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
+			ERR_print_errors_fp(stdout);
+			goto END;
+		}
+	}
+
+	/* x509.v3 */
+	X509_set_version(x, 2);
+
+	/* Random serial number */
+	sno = ASN1_INTEGER_new();
+	rand_serial(NULL, sno);
+	X509_set_serialNumber(x, sno);
+	ASN1_INTEGER_free(sno);
+
+	X509_gmtime_adj(X509_get_notBefore(x), 0);
+	X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
+	X509_set_pubkey(x, pkey);
+
+	/* Subject name */
+	name = X509_get_subject_name(x);
+	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+			(const unsigned char *)cert->cn, -1, -1, 0);
+	X509_set_subject_name(x, name);
+
+	/* Issuer name */
+	name = X509_get_issuer_name(x);
+	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
+	X509_set_issuer_name(x, name);
+
+	/* Add various extensions: standard extensions */
+	cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
+	cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
+	if (ca) {
+		cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
+		cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
+	} else {
+		cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
+	}
+
+	/* Add custom extensions */
+	if (sk != NULL) {
+		num = sk_X509_EXTENSION_num(sk);
+		for (i = 0; i < num; i++) {
+			ex = sk_X509_EXTENSION_value(sk, i);
+			X509_add_ext(x, ex, -1);
+		}
+	}
+
+	if (!X509_sign_ctx(x, mdCtx)) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
+	/* X509 certificate signed successfully */
+	rc = 1;
+	cert->x = x;
+
+END:
+	EVP_MD_CTX_destroy(mdCtx);
+	return rc;
+}
+
+int cert_init(void)
+{
+	cmd_opt_t cmd_opt;
+	cert_t *cert;
+	unsigned int i;
+
+	for (i = 0; i < num_certs; i++) {
+		cert = &certs[i];
+		cmd_opt.long_opt.name = cert->opt;
+		cmd_opt.long_opt.has_arg = required_argument;
+		cmd_opt.long_opt.flag = NULL;
+		cmd_opt.long_opt.val = CMD_OPT_CERT;
+		cmd_opt.help_msg = cert->help_msg;
+		cmd_opt_add(&cmd_opt);
+	}
+
+	return 0;
+}
+
+cert_t *cert_get_by_opt(const char *opt)
+{
+	cert_t *cert;
+	unsigned int i;
+
+	for (i = 0; i < num_certs; i++) {
+		cert = &certs[i];
+		if (0 == strcmp(cert->opt, opt)) {
+			return cert;
+		}
+	}
+
+	return NULL;
+}
diff --git a/tools/cert_create/src/cmd_opt.c b/tools/cert_create/src/cmd_opt.c
new file mode 100644
index 0000000..64180d1
--- /dev/null
+++ b/tools/cert_create/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/cert_create/src/ext.c b/tools/cert_create/src/ext.c
new file mode 100644
index 0000000..055ddbf
--- /dev/null
+++ b/tools/cert_create/src/ext.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#include "cmd_opt.h"
+#include "ext.h"
+
+DECLARE_ASN1_ITEM(ASN1_INTEGER)
+DECLARE_ASN1_ITEM(X509_ALGOR)
+DECLARE_ASN1_ITEM(ASN1_OCTET_STRING)
+
+typedef struct {
+	X509_ALGOR *hashAlgorithm;
+	ASN1_OCTET_STRING *dataHash;
+} HASH;
+
+ASN1_SEQUENCE(HASH) = {
+	ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR),
+	ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(HASH)
+
+DECLARE_ASN1_FUNCTIONS(HASH)
+IMPLEMENT_ASN1_FUNCTIONS(HASH)
+
+/*
+ * This function adds the TBB extensions to the internal extension list
+ * maintained by OpenSSL so they can be used later.
+ *
+ * It also initializes the methods to print the contents of the extension. If an
+ * alias is specified in the TBB extension, we reuse the methods of the alias.
+ * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are
+ * provided. Any other type will be printed as a raw ascii string.
+ *
+ * Return: 0 = success, Otherwise: error
+ */
+int ext_init(void)
+{
+	cmd_opt_t cmd_opt;
+	ext_t *ext;
+	X509V3_EXT_METHOD *m;
+	int nid, ret;
+	unsigned int i;
+
+	for (i = 0; i < num_extensions; i++) {
+		ext = &extensions[i];
+		/* Register command line option */
+		if (ext->opt) {
+			cmd_opt.long_opt.name = ext->opt;
+			cmd_opt.long_opt.has_arg = required_argument;
+			cmd_opt.long_opt.flag = NULL;
+			cmd_opt.long_opt.val = CMD_OPT_EXT;
+			cmd_opt.help_msg = ext->help_msg;
+			cmd_opt_add(&cmd_opt);
+		}
+		/* Register the extension OID in OpenSSL */
+		if (ext->oid == NULL) {
+			continue;
+		}
+		nid = OBJ_create(ext->oid, ext->sn, ext->ln);
+		if (ext->alias) {
+			X509V3_EXT_add_alias(nid, ext->alias);
+		} else {
+			m = &ext->method;
+			memset(m, 0x0, sizeof(X509V3_EXT_METHOD));
+			switch (ext->asn1_type) {
+			case V_ASN1_INTEGER:
+				m->it = ASN1_ITEM_ref(ASN1_INTEGER);
+				m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER;
+				m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER;
+				break;
+			case V_ASN1_OCTET_STRING:
+				m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING);
+				m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING;
+				m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING;
+				break;
+			default:
+				continue;
+			}
+			m->ext_nid = nid;
+			ret = X509V3_EXT_add(m);
+			if (!ret) {
+				ERR_print_errors_fp(stdout);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * Create a new extension
+ *
+ * Extension  ::=  SEQUENCE  {
+ *      id          OBJECT IDENTIFIER,
+ *      critical    BOOLEAN DEFAULT FALSE,
+ *      value       OCTET STRING  }
+ *
+ * Parameters:
+ *   pex: OpenSSL extension pointer (output parameter)
+ *   nid: extension identifier
+ *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
+ *   data: extension data. This data will be encapsulated in an Octet String
+ *
+ * Return: Extension address, NULL if error
+ */
+static
+X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len)
+{
+	X509_EXTENSION *ex;
+	ASN1_OCTET_STRING *ext_data;
+
+	/* Octet string containing the extension data */
+	ext_data = ASN1_OCTET_STRING_new();
+	ASN1_OCTET_STRING_set(ext_data, data, len);
+
+	/* Create the extension */
+	ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data);
+
+	/* The extension makes a copy of the data, so we can free this object */
+	ASN1_OCTET_STRING_free(ext_data);
+
+	return ex;
+}
+
+/*
+ * Creates a x509v3 extension containing a hash
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm  AlgorithmIdentifier,
+ *     digest           OCTET STRING
+ * }
+ *
+ * AlgorithmIdentifier ::=  SEQUENCE  {
+ *     algorithm        OBJECT IDENTIFIER,
+ *     parameters       ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
+ * Parameters:
+ *   nid: extension identifier
+ *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
+ *   md: hash algorithm
+ *   buf: pointer to the buffer that contains the hash
+ *   len: size of the hash in bytes
+ *
+ * Return: Extension address, NULL if error
+ */
+X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
+		unsigned char *buf, size_t len)
+{
+	X509_EXTENSION *ex;
+	ASN1_OCTET_STRING *octet;
+	HASH *hash;
+	ASN1_OBJECT *algorithm;
+	X509_ALGOR *x509_algor;
+	unsigned char *p = NULL;
+	int sz;
+
+	/* OBJECT_IDENTIFIER with hash algorithm */
+	algorithm = OBJ_nid2obj(EVP_MD_type(md));
+	if (algorithm == NULL) {
+		return NULL;
+	}
+
+	/* Create X509_ALGOR */
+	x509_algor = X509_ALGOR_new();
+	if (x509_algor == NULL) {
+		return NULL;
+	}
+	x509_algor->algorithm = algorithm;
+	x509_algor->parameter = ASN1_TYPE_new();
+	ASN1_TYPE_set(x509_algor->parameter, V_ASN1_NULL, NULL);
+
+	/* OCTET_STRING with the actual hash */
+	octet = ASN1_OCTET_STRING_new();
+	if (octet == NULL) {
+		X509_ALGOR_free(x509_algor);
+		return NULL;
+	}
+	ASN1_OCTET_STRING_set(octet, buf, len);
+
+	/* HASH structure containing algorithm + hash */
+	hash = HASH_new();
+	if (hash == NULL) {
+		ASN1_OCTET_STRING_free(octet);
+		X509_ALGOR_free(x509_algor);
+		return NULL;
+	}
+	hash->hashAlgorithm = x509_algor;
+	hash->dataHash = octet;
+
+	/* DER encoded HASH */
+	sz = i2d_HASH(hash, &p);
+	if ((sz <= 0) || (p == NULL)) {
+		HASH_free(hash);
+		X509_ALGOR_free(x509_algor);
+		return NULL;
+	}
+
+	/* Create the extension */
+	ex = ext_new(nid, crit, p, sz);
+
+	/* Clean up */
+	OPENSSL_free(p);
+	HASH_free(hash);
+
+	return ex;
+}
+
+/*
+ * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1
+ * Integer
+ *
+ * Parameters:
+ *   pex: OpenSSL extension pointer (output parameter)
+ *   nid: extension identifier
+ *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
+ *   value: nvcounter value
+ *
+ * Return: Extension address, NULL if error
+ */
+X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value)
+{
+	X509_EXTENSION *ex;
+	ASN1_INTEGER *counter;
+	unsigned char *p = NULL;
+	int sz;
+
+	/* Encode counter */
+	counter = ASN1_INTEGER_new();
+	ASN1_INTEGER_set(counter, value);
+	sz = i2d_ASN1_INTEGER(counter, &p);
+
+	/* Create the extension */
+	ex = ext_new(nid, crit, p, sz);
+
+	/* Free objects */
+	OPENSSL_free(p);
+	ASN1_INTEGER_free(counter);
+
+	return ex;
+}
+
+/*
+ * Creates a x509v3 extension containing a public key in DER format:
+ *
+ *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
+ *       algorithm            AlgorithmIdentifier,
+ *       subjectPublicKey     BIT STRING }
+ *
+ * Parameters:
+ *   pex: OpenSSL extension pointer (output parameter)
+ *   nid: extension identifier
+ *   crit: extension critical (EXT_NON_CRIT, EXT_CRIT)
+ *   k: key
+ *
+ * Return: Extension address, NULL if error
+ */
+X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k)
+{
+	X509_EXTENSION *ex;
+	unsigned char *p;
+	int sz;
+
+	/* Encode key */
+	BIO *mem = BIO_new(BIO_s_mem());
+	if (i2d_PUBKEY_bio(mem, k) <= 0) {
+		ERR_print_errors_fp(stderr);
+		return NULL;
+	}
+	p = (unsigned char *)OPENSSL_malloc(4096);
+	sz = BIO_read(mem, p, 4096);
+
+	/* Create the extension */
+	ex = ext_new(nid, crit, p, sz);
+
+	/* Clean up */
+	OPENSSL_free(p);
+
+	return ex;
+}
+
+ext_t *ext_get_by_opt(const char *opt)
+{
+	ext_t *ext;
+	unsigned int i;
+
+	/* Sequential search. This is not a performance concern since the number
+	 * of extensions is bounded and the code runs on a host machine */
+	for (i = 0; i < num_extensions; i++) {
+		ext = &extensions[i];
+		if (ext->opt && !strcmp(ext->opt, opt)) {
+			return ext;
+		}
+	}
+
+	return NULL;
+}
diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c
new file mode 100644
index 0000000..871f9ee
--- /dev/null
+++ b/tools/cert_create/src/key.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+#if USE_TBBR_DEFS
+#include <tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+#include "cert.h"
+#include "cmd_opt.h"
+#include "debug.h"
+#include "key.h"
+#include "sha.h"
+
+#define MAX_FILENAME_LEN		1024
+
+/*
+ * Create a new key container
+ */
+int key_new(key_t *key)
+{
+	/* Create key pair container */
+	key->key = EVP_PKEY_new();
+	if (key->key == NULL) {
+		return 0;
+	}
+
+	return 1;
+}
+
+static int key_create_rsa(key_t *key)
+{
+	BIGNUM *e;
+	RSA *rsa = NULL;
+
+	e = BN_new();
+	if (e == NULL) {
+		printf("Cannot create RSA exponent\n");
+		goto err;
+	}
+
+	if (!BN_set_word(e, RSA_F4)) {
+		printf("Cannot assign RSA exponent\n");
+		goto err;
+	}
+
+	rsa = RSA_new();
+	if (rsa == NULL) {
+		printf("Cannot create RSA key\n");
+		goto err;
+	}
+
+	if (!RSA_generate_key_ex(rsa, RSA_KEY_BITS, e, NULL)) {
+		printf("Cannot generate RSA key\n");
+		goto err;
+	}
+
+	if (!EVP_PKEY_assign_RSA(key->key, rsa)) {
+		printf("Cannot assign RSA key\n");
+		goto err;
+	}
+
+	return 1;
+err:
+	RSA_free(rsa);
+	BN_free(e);
+	return 0;
+}
+
+#ifndef OPENSSL_NO_EC
+static int key_create_ecdsa(key_t *key)
+{
+	EC_KEY *ec;
+
+	ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+	if (ec == NULL) {
+		printf("Cannot create EC key\n");
+		goto err;
+	}
+	if (!EC_KEY_generate_key(ec)) {
+		printf("Cannot generate EC key\n");
+		goto err;
+	}
+	EC_KEY_set_flags(ec, EC_PKEY_NO_PARAMETERS);
+	EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
+	if (!EVP_PKEY_assign_EC_KEY(key->key, ec)) {
+		printf("Cannot assign EC key\n");
+		goto err;
+	}
+
+	return 1;
+err:
+	EC_KEY_free(ec);
+	return 0;
+}
+#endif /* OPENSSL_NO_EC */
+
+typedef int (*key_create_fn_t)(key_t *key);
+static const key_create_fn_t key_create_fn[KEY_ALG_MAX_NUM] = {
+	key_create_rsa, 	/* KEY_ALG_RSA */
+	key_create_rsa, 	/* KEY_ALG_RSA_1_5 */
+#ifndef OPENSSL_NO_EC
+	key_create_ecdsa, 	/* KEY_ALG_ECDSA */
+#endif /* OPENSSL_NO_EC */
+};
+
+int key_create(key_t *key, int type)
+{
+	if (type >= KEY_ALG_MAX_NUM) {
+		printf("Invalid key type\n");
+		return 0;
+	}
+
+	if (key_create_fn[type]) {
+		return key_create_fn[type](key);
+	}
+
+	return 0;
+}
+
+int key_load(key_t *key, unsigned int *err_code)
+{
+	FILE *fp;
+	EVP_PKEY *k;
+
+	if (key->fn) {
+		/* Load key from file */
+		fp = fopen(key->fn, "r");
+		if (fp) {
+			k = PEM_read_PrivateKey(fp, &key->key, NULL, NULL);
+			fclose(fp);
+			if (k) {
+				*err_code = KEY_ERR_NONE;
+				return 1;
+			} else {
+				ERROR("Cannot load key from %s\n", key->fn);
+				*err_code = KEY_ERR_LOAD;
+			}
+		} else {
+			WARN("Cannot open file %s\n", key->fn);
+			*err_code = KEY_ERR_OPEN;
+		}
+	} else {
+		WARN("Key filename not specified\n");
+		*err_code = KEY_ERR_FILENAME;
+	}
+
+	return 0;
+}
+
+int key_store(key_t *key)
+{
+	FILE *fp;
+
+	if (key->fn) {
+		fp = fopen(key->fn, "w");
+		if (fp) {
+			PEM_write_PrivateKey(fp, key->key,
+					NULL, NULL, 0, NULL, NULL);
+			fclose(fp);
+			return 1;
+		} else {
+			ERROR("Cannot create file %s\n", key->fn);
+		}
+	} else {
+		ERROR("Key filename not specified\n");
+	}
+
+	return 0;
+}
+
+int key_init(void)
+{
+	cmd_opt_t cmd_opt;
+	key_t *key;
+	unsigned int i;
+
+	for (i = 0; i < num_keys; i++) {
+		key = &keys[i];
+		if (key->opt != NULL) {
+			cmd_opt.long_opt.name = key->opt;
+			cmd_opt.long_opt.has_arg = required_argument;
+			cmd_opt.long_opt.flag = NULL;
+			cmd_opt.long_opt.val = CMD_OPT_KEY;
+			cmd_opt.help_msg = key->help_msg;
+			cmd_opt_add(&cmd_opt);
+		}
+	}
+
+	return 0;
+}
+
+key_t *key_get_by_opt(const char *opt)
+{
+	key_t *key;
+	unsigned int i;
+
+	/* Sequential search. This is not a performance concern since the number
+	 * of keys is bounded and the code runs on a host machine */
+	for (i = 0; i < num_keys; i++) {
+		key = &keys[i];
+		if (0 == strcmp(key->opt, opt)) {
+			return key;
+		}
+	}
+
+	return NULL;
+}
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
new file mode 100644
index 0000000..ed56620
--- /dev/null
+++ b/tools/cert_create/src/main.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * 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 <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/x509v3.h>
+
+#if USE_TBBR_DEFS
+#include <tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+#include "cert.h"
+#include "cmd_opt.h"
+#include "debug.h"
+#include "ext.h"
+#include "key.h"
+#include "sha.h"
+#include "tbbr/tbb_cert.h"
+#include "tbbr/tbb_ext.h"
+#include "tbbr/tbb_key.h"
+
+/*
+ * Helper macros to simplify the code. This macro assigns the return value of
+ * the 'fn' function to 'v' and exits if the value is NULL.
+ */
+#define CHECK_NULL(v, fn) \
+	do { \
+		v = fn; \
+		if (v == NULL) { \
+			ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \
+			exit(1); \
+		} \
+	} while (0)
+
+/*
+ * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the
+ * NID is undefined.
+ */
+#define CHECK_OID(v, oid) \
+	do { \
+		v = OBJ_txt2nid(oid); \
+		if (v == NID_undef) { \
+			ERROR("Cannot find TBB extension %s\n", oid); \
+			exit(1); \
+		} \
+	} while (0)
+
+#define MAX_FILENAME_LEN		1024
+#define VAL_DAYS			7300
+#define ID_TO_BIT_MASK(id)		(1 << id)
+#define NUM_ELEM(x)			((sizeof(x)) / (sizeof(x[0])))
+#define HELP_OPT_MAX_LEN		128
+
+/* Global options */
+static int key_alg;
+static int hash_alg;
+static int new_keys;
+static int save_keys;
+static int print_cert;
+
+/* Info messages created in the Makefile */
+extern const char build_msg[];
+extern const char platform_msg[];
+
+
+static char *strdup(const char *str)
+{
+	int n = strlen(str) + 1;
+	char *dup = malloc(n);
+	if (dup) {
+		strcpy(dup, str);
+	}
+	return dup;
+}
+
+static const char *key_algs_str[] = {
+	[KEY_ALG_RSA] = "rsa",
+	[KEY_ALG_RSA_1_5] = "rsa_1_5",
+#ifndef OPENSSL_NO_EC
+	[KEY_ALG_ECDSA] = "ecdsa"
+#endif /* OPENSSL_NO_EC */
+};
+
+static const char *hash_algs_str[] = {
+	[HASH_ALG_SHA256] = "sha256",
+	[HASH_ALG_SHA384] = "sha384",
+	[HASH_ALG_SHA512] = "sha512",
+};
+
+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 certificate generation tool loads the binary images and\n"
+	       "optionally the RSA keys, and outputs the key and content\n"
+	       "certificates properly signed to implement the chain of trust.\n"
+	       "If keys are provided, they must be in PEM format.\n"
+	       "Certificates are generated in DER format.\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 (0 == strcmp(key_alg_str, key_algs_str[i])) {
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+static int get_hash_alg(const char *hash_alg_str)
+{
+	int i;
+
+	for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
+		if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+static void check_cmd_params(void)
+{
+	cert_t *cert;
+	ext_t *ext;
+	key_t *key;
+	int i, j;
+
+	/* Only save new keys */
+	if (save_keys && !new_keys) {
+		ERROR("Only new keys can be saved to disk\n");
+		exit(1);
+	}
+
+	/* Check that all required options have been specified in the
+	 * command line */
+	for (i = 0; i < num_certs; i++) {
+		cert = &certs[i];
+		if (cert->fn == NULL) {
+			/* Certificate not requested. Skip to the next one */
+			continue;
+		}
+
+		/* Check that all parameters required to create this certificate
+		 * have been specified in the command line */
+		for (j = 0; j < cert->num_ext; j++) {
+			ext = &extensions[cert->ext[j]];
+			switch (ext->type) {
+			case EXT_TYPE_NVCOUNTER:
+				/* Counter value must be specified */
+				if ((!ext->optional) && (ext->arg == NULL)) {
+					ERROR("Value for '%s' not specified\n",
+					      ext->ln);
+					exit(1);
+				}
+				break;
+			case EXT_TYPE_PKEY:
+				/* Key filename must be specified */
+				key = &keys[ext->attr.key];
+				if (!new_keys && key->fn == NULL) {
+					ERROR("Key '%s' required by '%s' not "
+					      "specified\n", key->desc,
+					      cert->cn);
+					exit(1);
+				}
+				break;
+			case EXT_TYPE_HASH:
+				/*
+				 * Binary image must be specified
+				 * unless it is explicitly made optional.
+				 */
+				if ((!ext->optional) && (ext->arg == NULL)) {
+					ERROR("Image for '%s' not specified\n",
+					      ext->ln);
+					exit(1);
+				}
+				break;
+			default:
+				ERROR("Unknown extension type '%d' in '%s'\n",
+				      ext->type, ext->ln);
+				exit(1);
+				break;
+			}
+		}
+	}
+}
+
+/* Common command line options */
+static const cmd_opt_t common_cmd_opt[] = {
+	{
+		{ "help", no_argument, NULL, 'h' },
+		"Print this message and exit"
+	},
+	{
+		{ "key-alg", required_argument, NULL, 'a' },
+		"Key algorithm: 'rsa' (default) - RSAPSS scheme as per \
+PKCS#1 v2.1, 'rsa_1_5' - RSA PKCS#1 v1.5, 'ecdsa'"
+	},
+	{
+		{ "hash-alg", required_argument, NULL, 's' },
+		"Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
+	},
+	{
+		{ "save-keys", no_argument, NULL, 'k' },
+		"Save key pairs into files. Filenames must be provided"
+	},
+	{
+		{ "new-keys", no_argument, NULL, 'n' },
+		"Generate new key pairs if no key files are provided"
+	},
+	{
+		{ "print-cert", no_argument, NULL, 'p' },
+		"Print the certificates in the standard output"
+	}
+};
+
+int main(int argc, char *argv[])
+{
+	STACK_OF(X509_EXTENSION) * sk;
+	X509_EXTENSION *cert_ext = NULL;
+	ext_t *ext;
+	key_t *key;
+	cert_t *cert;
+	FILE *file;
+	int i, j, ext_nid, nvctr;
+	int c, opt_idx = 0;
+	const struct option *cmd_opt;
+	const char *cur_opt;
+	unsigned int err_code;
+	unsigned char md[SHA512_DIGEST_LENGTH];
+	unsigned int  md_len;
+	const EVP_MD *md_info;
+
+	NOTICE("CoT Generation Tool: %s\n", build_msg);
+	NOTICE("Target platform: %s\n", platform_msg);
+
+	/* Set default options */
+	key_alg = KEY_ALG_RSA;
+	hash_alg = HASH_ALG_SHA256;
+
+	/* Add common command line options */
+	for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
+		cmd_opt_add(&common_cmd_opt[i]);
+	}
+
+	/* Initialize the certificates */
+	if (cert_init() != 0) {
+		ERROR("Cannot initialize certificates\n");
+		exit(1);
+	}
+
+	/* Initialize the keys */
+	if (key_init() != 0) {
+		ERROR("Cannot initialize keys\n");
+		exit(1);
+	}
+
+	/* Initialize the new types and register OIDs for the extensions */
+	if (ext_init() != 0) {
+		ERROR("Cannot initialize TBB extensions\n");
+		exit(1);
+	}
+
+	/* 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:hknps:", 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 'h':
+			print_help(argv[0], cmd_opt);
+			exit(0);
+		case 'k':
+			save_keys = 1;
+			break;
+		case 'n':
+			new_keys = 1;
+			break;
+		case 'p':
+			print_cert = 1;
+			break;
+		case 's':
+			hash_alg = get_hash_alg(optarg);
+			if (hash_alg < 0) {
+				ERROR("Invalid hash algorithm '%s'\n", optarg);
+				exit(1);
+			}
+			break;
+		case CMD_OPT_EXT:
+			cur_opt = cmd_opt_get_name(opt_idx);
+			ext = ext_get_by_opt(cur_opt);
+			ext->arg = strdup(optarg);
+			break;
+		case CMD_OPT_KEY:
+			cur_opt = cmd_opt_get_name(opt_idx);
+			key = key_get_by_opt(cur_opt);
+			key->fn = strdup(optarg);
+			break;
+		case CMD_OPT_CERT:
+			cur_opt = cmd_opt_get_name(opt_idx);
+			cert = cert_get_by_opt(cur_opt);
+			cert->fn = strdup(optarg);
+			break;
+		case '?':
+		default:
+			print_help(argv[0], cmd_opt);
+			exit(1);
+		}
+	}
+
+	/* Check command line arguments */
+	check_cmd_params();
+
+	/* Indicate SHA as image hash algorithm in the certificate
+	 * extension */
+	if (hash_alg == HASH_ALG_SHA384) {
+		md_info = EVP_sha384();
+		md_len  = SHA384_DIGEST_LENGTH;
+	} else if (hash_alg == HASH_ALG_SHA512) {
+		md_info = EVP_sha512();
+		md_len  = SHA512_DIGEST_LENGTH;
+	} else {
+		md_info = EVP_sha256();
+		md_len  = SHA256_DIGEST_LENGTH;
+	}
+
+	/* Load private keys from files (or generate new ones) */
+	for (i = 0 ; i < num_keys ; i++) {
+		if (!key_new(&keys[i])) {
+			ERROR("Failed to allocate key container\n");
+			exit(1);
+		}
+
+		/* First try to load the key from disk */
+		if (key_load(&keys[i], &err_code)) {
+			/* Key loaded successfully */
+			continue;
+		}
+
+		/* Key not loaded. Check the error code */
+		if (err_code == KEY_ERR_LOAD) {
+			/* File exists, but it does not contain a valid private
+			 * key. Abort. */
+			ERROR("Error loading '%s'\n", keys[i].fn);
+			exit(1);
+		}
+
+		/* File does not exist, could not be opened or no filename was
+		 * given */
+		if (new_keys) {
+			/* Try to create a new key */
+			NOTICE("Creating new key for '%s'\n", keys[i].desc);
+			if (!key_create(&keys[i], key_alg)) {
+				ERROR("Error creating key '%s'\n", keys[i].desc);
+				exit(1);
+			}
+		} else {
+			if (err_code == KEY_ERR_OPEN) {
+				ERROR("Error opening '%s'\n", keys[i].fn);
+			} else {
+				ERROR("Key '%s' not specified\n", keys[i].desc);
+			}
+			exit(1);
+		}
+	}
+
+	/* Create the certificates */
+	for (i = 0 ; i < num_certs ; i++) {
+
+		cert = &certs[i];
+
+		/* Create a new stack of extensions. This stack will be used
+		 * to create the certificate */
+		CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
+
+		for (j = 0 ; j < cert->num_ext ; j++) {
+
+			ext = &extensions[cert->ext[j]];
+
+			/* Get OpenSSL internal ID for this extension */
+			CHECK_OID(ext_nid, ext->oid);
+
+			/*
+			 * Three types of extensions are currently supported:
+			 *     - EXT_TYPE_NVCOUNTER
+			 *     - EXT_TYPE_HASH
+			 *     - EXT_TYPE_PKEY
+			 */
+			switch (ext->type) {
+			case EXT_TYPE_NVCOUNTER:
+				if (ext->arg) {
+					nvctr = atoi(ext->arg);
+					CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
+						EXT_CRIT, nvctr));
+				}
+				break;
+			case EXT_TYPE_HASH:
+				if (ext->arg == NULL) {
+					if (ext->optional) {
+						/* Include a hash filled with zeros */
+						memset(md, 0x0, SHA512_DIGEST_LENGTH);
+					} else {
+						/* Do not include this hash in the certificate */
+						break;
+					}
+				} else {
+					/* Calculate the hash of the file */
+					if (!sha_file(hash_alg, ext->arg, md)) {
+						ERROR("Cannot calculate hash of %s\n",
+							ext->arg);
+						exit(1);
+					}
+				}
+				CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
+						EXT_CRIT, md_info, md,
+						md_len));
+				break;
+			case EXT_TYPE_PKEY:
+				CHECK_NULL(cert_ext, ext_new_key(ext_nid,
+					EXT_CRIT, keys[ext->attr.key].key));
+				break;
+			default:
+				ERROR("Unknown extension type '%d' in %s\n",
+						ext->type, cert->cn);
+				exit(1);
+			}
+
+			/* Push the extension into the stack */
+			sk_X509_EXTENSION_push(sk, cert_ext);
+		}
+
+		/* Create certificate. Signed with corresponding key */
+		if (cert->fn && !cert_new(key_alg, hash_alg, cert, VAL_DAYS, 0, sk)) {
+			ERROR("Cannot create %s\n", cert->cn);
+			exit(1);
+		}
+
+		sk_X509_EXTENSION_free(sk);
+	}
+
+
+	/* Print the certificates */
+	if (print_cert) {
+		for (i = 0 ; i < num_certs ; i++) {
+			if (!certs[i].x) {
+				continue;
+			}
+			printf("\n\n=====================================\n\n");
+			X509_print_fp(stdout, certs[i].x);
+		}
+	}
+
+	/* Save created certificates to files */
+	for (i = 0 ; i < num_certs ; i++) {
+		if (certs[i].x && certs[i].fn) {
+			file = fopen(certs[i].fn, "w");
+			if (file != NULL) {
+				i2d_X509_fp(file, certs[i].x);
+				fclose(file);
+			} else {
+				ERROR("Cannot create file %s\n", certs[i].fn);
+			}
+		}
+	}
+
+	/* Save keys */
+	if (save_keys) {
+		for (i = 0 ; i < num_keys ; i++) {
+			if (!key_store(&keys[i])) {
+				ERROR("Cannot save %s\n", keys[i].desc);
+			}
+		}
+	}
+
+#ifndef OPENSSL_NO_ENGINE
+	ENGINE_cleanup();
+#endif
+	CRYPTO_cleanup_all_ex_data();
+
+	return 0;
+}
diff --git a/tools/cert_create/src/sha.c b/tools/cert_create/src/sha.c
new file mode 100644
index 0000000..3d977fb
--- /dev/null
+++ b/tools/cert_create/src/sha.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <openssl/sha.h>
+#include <stdio.h>
+#include "debug.h"
+#include "key.h"
+
+#define BUFFER_SIZE	256
+
+int sha_file(int md_alg, const char *filename, unsigned char *md)
+{
+	FILE *inFile;
+	SHA256_CTX shaContext;
+	SHA512_CTX sha512Context;
+	int bytes;
+	unsigned char data[BUFFER_SIZE];
+
+	if ((filename == NULL) || (md == NULL)) {
+		ERROR("%s(): NULL argument\n", __FUNCTION__);
+		return 0;
+	}
+
+	inFile = fopen(filename, "rb");
+	if (inFile == NULL) {
+		ERROR("Cannot read %s\n", filename);
+		return 0;
+	}
+
+	if (md_alg == HASH_ALG_SHA384) {
+		SHA384_Init(&sha512Context);
+		while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+			SHA384_Update(&sha512Context, data, bytes);
+		}
+		SHA384_Final(md, &sha512Context);
+	} else if (md_alg == HASH_ALG_SHA512) {
+		SHA512_Init(&sha512Context);
+		while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+			SHA512_Update(&sha512Context, data, bytes);
+		}
+		SHA512_Final(md, &sha512Context);
+	} else {
+		SHA256_Init(&shaContext);
+		while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) {
+			SHA256_Update(&shaContext, data, bytes);
+		}
+		SHA256_Final(md, &shaContext);
+	}
+
+	fclose(inFile);
+	return 1;
+}
diff --git a/tools/cert_create/src/tbbr/tbb_cert.c b/tools/cert_create/src/tbbr/tbb_cert.c
new file mode 100644
index 0000000..7fb32d8
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbb_cert.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "tbbr/tbb_cert.h"
+#include "tbbr/tbb_ext.h"
+#include "tbbr/tbb_key.h"
+
+/*
+ * Certificates used in the chain of trust
+ *
+ * The order of the certificates must follow the enumeration specified in
+ * tbb_cert.h. All certificates are self-signed, so the issuer certificate
+ * field points to itself.
+ */
+static cert_t tbb_certs[] = {
+	[TRUSTED_BOOT_FW_CERT] = {
+		.id = TRUSTED_BOOT_FW_CERT,
+		.opt = "tb-fw-cert",
+		.help_msg = "Trusted Boot FW Certificate (output file)",
+		.fn = NULL,
+		.cn = "Trusted Boot FW Certificate",
+		.key = ROT_KEY,
+		.issuer = TRUSTED_BOOT_FW_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			TRUSTED_BOOT_FW_HASH_EXT,
+			TRUSTED_BOOT_FW_CONFIG_HASH_EXT,
+			HW_CONFIG_HASH_EXT
+		},
+		.num_ext = 4
+	},
+	[TRUSTED_KEY_CERT] = {
+		.id = TRUSTED_KEY_CERT,
+		.opt = "trusted-key-cert",
+		.help_msg = "Trusted Key Certificate (output file)",
+		.fn = NULL,
+		.cn = "Trusted Key Certificate",
+		.key = ROT_KEY,
+		.issuer = TRUSTED_KEY_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			TRUSTED_WORLD_PK_EXT,
+			NON_TRUSTED_WORLD_PK_EXT
+		},
+		.num_ext = 3
+	},
+	[SCP_FW_KEY_CERT] = {
+		.id = SCP_FW_KEY_CERT,
+		.opt = "scp-fw-key-cert",
+		.help_msg = "SCP Firmware Key Certificate (output file)",
+		.fn = NULL,
+		.cn = "SCP Firmware Key Certificate",
+		.key = TRUSTED_WORLD_KEY,
+		.issuer = SCP_FW_KEY_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			SCP_FW_CONTENT_CERT_PK_EXT
+		},
+		.num_ext = 2
+	},
+	[SCP_FW_CONTENT_CERT] = {
+		.id = SCP_FW_CONTENT_CERT,
+		.opt = "scp-fw-cert",
+		.help_msg = "SCP Firmware Content Certificate (output file)",
+		.fn = NULL,
+		.cn = "SCP Firmware Content Certificate",
+		.key = SCP_FW_CONTENT_CERT_KEY,
+		.issuer = SCP_FW_CONTENT_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			SCP_FW_HASH_EXT
+		},
+		.num_ext = 2
+	},
+	[SOC_FW_KEY_CERT] = {
+		.id = SOC_FW_KEY_CERT,
+		.opt = "soc-fw-key-cert",
+		.help_msg = "SoC Firmware Key Certificate (output file)",
+		.fn = NULL,
+		.cn = "SoC Firmware Key Certificate",
+		.key = TRUSTED_WORLD_KEY,
+		.issuer = SOC_FW_KEY_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			SOC_FW_CONTENT_CERT_PK_EXT
+		},
+		.num_ext = 2
+	},
+	[SOC_FW_CONTENT_CERT] = {
+		.id = SOC_FW_CONTENT_CERT,
+		.opt = "soc-fw-cert",
+		.help_msg = "SoC Firmware Content Certificate (output file)",
+		.fn = NULL,
+		.cn = "SoC Firmware Content Certificate",
+		.key = SOC_FW_CONTENT_CERT_KEY,
+		.issuer = SOC_FW_CONTENT_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			SOC_AP_FW_HASH_EXT,
+			SOC_FW_CONFIG_HASH_EXT,
+		},
+		.num_ext = 3
+	},
+	[TRUSTED_OS_FW_KEY_CERT] = {
+		.id = TRUSTED_OS_FW_KEY_CERT,
+		.opt = "tos-fw-key-cert",
+		.help_msg = "Trusted OS Firmware Key Certificate (output file)",
+		.fn = NULL,
+		.cn = "Trusted OS Firmware Key Certificate",
+		.key = TRUSTED_WORLD_KEY,
+		.issuer = TRUSTED_OS_FW_KEY_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			TRUSTED_OS_FW_CONTENT_CERT_PK_EXT
+		},
+		.num_ext = 2
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT] = {
+		.id = TRUSTED_OS_FW_CONTENT_CERT,
+		.opt = "tos-fw-cert",
+		.help_msg = "Trusted OS Firmware Content Certificate (output file)",
+		.fn = NULL,
+		.cn = "Trusted OS Firmware Content Certificate",
+		.key = TRUSTED_OS_FW_CONTENT_CERT_KEY,
+		.issuer = TRUSTED_OS_FW_CONTENT_CERT,
+		.ext = {
+			TRUSTED_FW_NVCOUNTER_EXT,
+			TRUSTED_OS_FW_HASH_EXT,
+			TRUSTED_OS_FW_EXTRA1_HASH_EXT,
+			TRUSTED_OS_FW_EXTRA2_HASH_EXT,
+			TRUSTED_OS_FW_CONFIG_HASH_EXT,
+		},
+		.num_ext = 5
+	},
+	[NON_TRUSTED_FW_KEY_CERT] = {
+		.id = NON_TRUSTED_FW_KEY_CERT,
+		.opt = "nt-fw-key-cert",
+		.help_msg = "Non-Trusted Firmware Key Certificate (output file)",
+		.fn = NULL,
+		.cn = "Non-Trusted Firmware Key Certificate",
+		.key = NON_TRUSTED_WORLD_KEY,
+		.issuer = NON_TRUSTED_FW_KEY_CERT,
+		.ext = {
+			NON_TRUSTED_FW_NVCOUNTER_EXT,
+			NON_TRUSTED_FW_CONTENT_CERT_PK_EXT
+		},
+		.num_ext = 2
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT] = {
+		.id = NON_TRUSTED_FW_CONTENT_CERT,
+		.opt = "nt-fw-cert",
+		.help_msg = "Non-Trusted Firmware Content Certificate (output file)",
+		.fn = NULL,
+		.cn = "Non-Trusted Firmware Content Certificate",
+		.key = NON_TRUSTED_FW_CONTENT_CERT_KEY,
+		.issuer = NON_TRUSTED_FW_CONTENT_CERT,
+		.ext = {
+			NON_TRUSTED_FW_NVCOUNTER_EXT,
+			NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT,
+			NON_TRUSTED_FW_CONFIG_HASH_EXT,
+		},
+		.num_ext = 3
+	},
+	[FWU_CERT] = {
+		.id = FWU_CERT,
+		.opt = "fwu-cert",
+		.help_msg = "Firmware Update Certificate (output file)",
+		.fn = NULL,
+		.cn = "Firmware Update Certificate",
+		.key = ROT_KEY,
+		.issuer = FWU_CERT,
+		.ext = {
+			SCP_FWU_CFG_HASH_EXT,
+			AP_FWU_CFG_HASH_EXT,
+			FWU_HASH_EXT
+		},
+		.num_ext = 3
+	}
+};
+
+REGISTER_COT(tbb_certs);
diff --git a/tools/cert_create/src/tbbr/tbb_ext.c b/tools/cert_create/src/tbbr/tbb_ext.c
new file mode 100644
index 0000000..ee5377f
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbb_ext.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#if USE_TBBR_DEFS
+#include <tbbr_oid.h>
+#else
+#include <platform_oid.h>
+#endif
+
+#include "ext.h"
+#include "tbbr/tbb_ext.h"
+#include "tbbr/tbb_key.h"
+
+static ext_t tbb_ext[] = {
+	[TRUSTED_FW_NVCOUNTER_EXT] = {
+		.oid = TRUSTED_FW_NVCOUNTER_OID,
+		.opt = "tfw-nvctr",
+		.help_msg = "Trusted Firmware Non-Volatile counter value",
+		.sn = "TrustedWorldNVCounter",
+		.ln = "Trusted World Non-Volatile counter",
+		.asn1_type = V_ASN1_INTEGER,
+		.type = EXT_TYPE_NVCOUNTER,
+		.attr.nvctr_type = NVCTR_TYPE_TFW
+	},
+	[NON_TRUSTED_FW_NVCOUNTER_EXT] = {
+		.oid = NON_TRUSTED_FW_NVCOUNTER_OID,
+		.opt = "ntfw-nvctr",
+		.help_msg = "Non-Trusted Firmware Non-Volatile counter value",
+		.sn = "NormalWorldNVCounter",
+		.ln = "Non-Trusted Firmware Non-Volatile counter",
+		.asn1_type = V_ASN1_INTEGER,
+		.type = EXT_TYPE_NVCOUNTER,
+		.attr.nvctr_type = NVCTR_TYPE_NTFW
+	},
+	[TRUSTED_BOOT_FW_HASH_EXT] = {
+		.oid = TRUSTED_BOOT_FW_HASH_OID,
+		.opt = "tb-fw",
+		.help_msg = "Trusted Boot Firmware image file",
+		.sn = "TrustedBootFirmwareHash",
+		.ln = "Trusted Boot Firmware hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH
+	},
+	[TRUSTED_BOOT_FW_CONFIG_HASH_EXT] = {
+		.oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID,
+		.opt = "tb-fw-config",
+		.help_msg = "Trusted Boot Firmware Config file",
+		.sn = "TrustedBootFirmwareConfigHash",
+		.ln = "Trusted Boot Firmware Config hash",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[HW_CONFIG_HASH_EXT] = {
+		.oid = HW_CONFIG_HASH_OID,
+		.opt = "hw-config",
+		.help_msg = "HW Config file",
+		.sn = "HWConfigHash",
+		.ln = "HW Config hash",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[TRUSTED_WORLD_PK_EXT] = {
+		.oid = TRUSTED_WORLD_PK_OID,
+		.sn = "TrustedWorldPublicKey",
+		.ln = "Trusted World Public Key",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_PKEY,
+		.attr.key = TRUSTED_WORLD_KEY
+	},
+	[NON_TRUSTED_WORLD_PK_EXT] = {
+		.oid = NON_TRUSTED_WORLD_PK_OID,
+		.sn = "NonTrustedWorldPublicKey",
+		.ln = "Non-Trusted World Public Key",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_PKEY,
+		.attr.key = NON_TRUSTED_WORLD_KEY
+	},
+	[SCP_FW_CONTENT_CERT_PK_EXT] = {
+		.oid = SCP_FW_CONTENT_CERT_PK_OID,
+		.sn = "SCPFirmwareContentCertPK",
+		.ln = "SCP Firmware content certificate public key",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_PKEY,
+		.attr.key = SCP_FW_CONTENT_CERT_KEY
+	},
+	[SCP_FW_HASH_EXT] = {
+		.oid = SCP_FW_HASH_OID,
+		.opt = "scp-fw",
+		.help_msg = "SCP Firmware image file",
+		.sn = "SCPFirmwareHash",
+		.ln = "SCP Firmware hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH
+	},
+	[SOC_FW_CONTENT_CERT_PK_EXT] = {
+		.oid = SOC_FW_CONTENT_CERT_PK_OID,
+		.sn = "SoCFirmwareContentCertPK",
+		.ln = "SoC Firmware content certificate public key",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_PKEY,
+		.attr.key = SOC_FW_CONTENT_CERT_KEY
+	},
+	[SOC_AP_FW_HASH_EXT] = {
+		.oid = SOC_AP_FW_HASH_OID,
+		.opt = "soc-fw",
+		.help_msg = "SoC AP Firmware image file",
+		.sn = "SoCAPFirmwareHash",
+		.ln = "SoC AP Firmware hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH
+	},
+	[SOC_FW_CONFIG_HASH_EXT] = {
+		.oid = SOC_FW_CONFIG_HASH_OID,
+		.opt = "soc-fw-config",
+		.help_msg = "SoC Firmware Config file",
+		.sn = "SocFirmwareConfigHash",
+		.ln = "SoC Firmware Config hash",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_PK_EXT] = {
+		.oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID,
+		.sn = "TrustedOSFirmwareContentCertPK",
+		.ln = "Trusted OS Firmware content certificate public key",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_PKEY,
+		.attr.key = TRUSTED_OS_FW_CONTENT_CERT_KEY
+	},
+	[TRUSTED_OS_FW_HASH_EXT] = {
+		.oid = TRUSTED_OS_FW_HASH_OID,
+		.opt = "tos-fw",
+		.help_msg = "Trusted OS image file",
+		.sn = "TrustedOSHash",
+		.ln = "Trusted OS hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH
+	},
+	[TRUSTED_OS_FW_EXTRA1_HASH_EXT] = {
+		.oid = TRUSTED_OS_FW_EXTRA1_HASH_OID,
+		.opt = "tos-fw-extra1",
+		.help_msg = "Trusted OS Extra1 image file",
+		.sn = "TrustedOSExtra1Hash",
+		.ln = "Trusted OS Extra1 hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[TRUSTED_OS_FW_EXTRA2_HASH_EXT] = {
+		.oid = TRUSTED_OS_FW_EXTRA2_HASH_OID,
+		.opt = "tos-fw-extra2",
+		.help_msg = "Trusted OS Extra2 image file",
+		.sn = "TrustedOSExtra2Hash",
+		.ln = "Trusted OS Extra2 hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[TRUSTED_OS_FW_CONFIG_HASH_EXT] = {
+		.oid = TRUSTED_OS_FW_CONFIG_HASH_OID,
+		.opt = "tos-fw-config",
+		.help_msg = "Trusted OS Firmware Config file",
+		.sn = "TrustedOSFirmwareConfigHash",
+		.ln = "Trusted OS Firmware Config hash",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_PK_EXT] = {
+		.oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID,
+		.sn = "NonTrustedFirmwareContentCertPK",
+		.ln = "Non-Trusted Firmware content certificate public key",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_PKEY,
+		.attr.key = NON_TRUSTED_FW_CONTENT_CERT_KEY
+	},
+	[NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT] = {
+		.oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID,
+		.opt = "nt-fw",
+		.help_msg = "Non-Trusted World Bootloader image file",
+		.sn = "NonTrustedWorldBootloaderHash",
+		.ln = "Non-Trusted World hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH
+	},
+	[NON_TRUSTED_FW_CONFIG_HASH_EXT] = {
+		.oid = NON_TRUSTED_FW_CONFIG_HASH_OID,
+		.opt = "nt-fw-config",
+		.help_msg = "Non Trusted OS Firmware Config file",
+		.sn = "NonTrustedOSFirmwareConfigHash",
+		.ln = "Non-Trusted OS Firmware Config hash",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[SCP_FWU_CFG_HASH_EXT] = {
+		.oid = SCP_FWU_CFG_HASH_OID,
+		.opt = "scp-fwu-cfg",
+		.help_msg = "SCP Firmware Update Config image file",
+		.sn = "SCPFWUpdateConfig",
+		.ln = "SCP Firmware Update Config hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[AP_FWU_CFG_HASH_EXT] = {
+		.oid = AP_FWU_CFG_HASH_OID,
+		.opt = "ap-fwu-cfg",
+		.help_msg = "AP Firmware Update Config image file",
+		.sn = "APFWUpdateConfig",
+		.ln = "AP Firmware Update Config hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	},
+	[FWU_HASH_EXT] = {
+		.oid = FWU_HASH_OID,
+		.opt = "fwu",
+		.help_msg = "Firmware Updater image file",
+		.sn = "FWUpdaterHash",
+		.ln = "Firmware Updater hash (SHA256)",
+		.asn1_type = V_ASN1_OCTET_STRING,
+		.type = EXT_TYPE_HASH,
+		.optional = 1
+	}
+};
+
+REGISTER_EXTENSIONS(tbb_ext);
diff --git a/tools/cert_create/src/tbbr/tbb_key.c b/tools/cert_create/src/tbbr/tbb_key.c
new file mode 100644
index 0000000..a81f0e4
--- /dev/null
+++ b/tools/cert_create/src/tbbr/tbb_key.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "tbbr/tbb_key.h"
+
+/*
+ * Keys used to establish the chain of trust
+ *
+ * The order of the keys must follow the enumeration specified in tbb_key.h
+ */
+static key_t tbb_keys[] = {
+	[ROT_KEY] = {
+		.id = ROT_KEY,
+		.opt = "rot-key",
+		.help_msg = "Root Of Trust key (input/output file)",
+		.desc = "Root Of Trust key"
+	},
+	[TRUSTED_WORLD_KEY] = {
+		.id = TRUSTED_WORLD_KEY,
+		.opt = "trusted-world-key",
+		.help_msg = "Trusted World key (input/output file)",
+		.desc = "Trusted World key"
+	},
+	[NON_TRUSTED_WORLD_KEY] = {
+		.id = NON_TRUSTED_WORLD_KEY,
+		.opt = "non-trusted-world-key",
+		.help_msg = "Non Trusted World key (input/output file)",
+		.desc = "Non Trusted World key"
+	},
+	[SCP_FW_CONTENT_CERT_KEY] = {
+		.id = SCP_FW_CONTENT_CERT_KEY,
+		.opt = "scp-fw-key",
+		.help_msg = "SCP Firmware Content Certificate key (input/output file)",
+		.desc = "SCP Firmware Content Certificate key"
+	},
+	[SOC_FW_CONTENT_CERT_KEY] = {
+		.id = SOC_FW_CONTENT_CERT_KEY,
+		.opt = "soc-fw-key",
+		.help_msg = "SoC Firmware Content Certificate key (input/output file)",
+		.desc = "SoC Firmware Content Certificate key"
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_KEY] = {
+		.id = TRUSTED_OS_FW_CONTENT_CERT_KEY,
+		.opt = "tos-fw-key",
+		.help_msg = "Trusted OS Firmware Content Certificate key (input/output file)",
+		.desc = "Trusted OS Firmware Content Certificate key"
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_KEY] = {
+		.id = NON_TRUSTED_FW_CONTENT_CERT_KEY,
+		.opt = "nt-fw-key",
+		.help_msg = "Non Trusted Firmware Content Certificate key (input/output file)",
+		.desc = "Non Trusted Firmware Content Certificate key"
+	}
+};
+
+REGISTER_KEYS(tbb_keys);
diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile
new file mode 100644
index 0000000..ef35014
--- /dev/null
+++ b/tools/fiptool/Makefile
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+PROJECT := fiptool${BIN_EXT}
+OBJECTS := fiptool.o tbbr_config.o
+V ?= 0
+
+override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700
+HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG
+else
+  HOSTCCFLAGS += -O2
+endif
+LDLIBS := -lcrypto
+
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+INCLUDE_PATHS := -I../../include/tools_share
+
+HOSTCC ?= gcc
+
+.PHONY: all clean distclean
+
+all: ${PROJECT}
+
+${PROJECT}: ${OBJECTS} Makefile
+	@echo "  HOSTLD  $@"
+	${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+%.o: %.c %.h Makefile
+	@echo "  HOSTCC  $<"
+	${Q}${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
+
+clean:
+	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
diff --git a/tools/fiptool/Makefile.msvc b/tools/fiptool/Makefile.msvc
new file mode 100644
index 0000000..58dbb89
--- /dev/null
+++ b/tools/fiptool/Makefile.msvc
@@ -0,0 +1,30 @@
+#

+# Copyright (c) 2019, Arm Limited. All rights reserved.

+#

+# SPDX-License-Identifier: BSD-3-Clause

+#

+

+CC = cl.exe

+LD = link.exe

+

+FIPTOOL = fiptool.exe

+OBJECTS = fiptool.obj tbbr_config.obj win_posix.obj

+

+INC = -I. -I..\..\include\tools_share

+CFLAGS = $(CFLAGS) /nologo /Za /Zi /c /O2 /MT

+

+all: $(FIPTOOL)

+

+$(FIPTOOL): $(OBJECTS)

+	$(LD) /INCREMENTAL:NO /debug /nodefaultlib:libc.lib /out:$@ $(LIBS) $**

+

+.PHONY: clean realclean

+

+clean:

+	del /f /q $(OBJECTS) > nul

+

+realclean:

+	del /f /q $(OBJECTS) $(FIPTOOL) > nul

+

+.c.obj:

+	$(CC) -c $(CFLAGS) $(INC) $< -Fo$@

diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
new file mode 100644
index 0000000..80b498e
--- /dev/null
+++ b/tools/fiptool/fiptool.c
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fiptool.h"
+#include "tbbr_config.h"
+
+#define OPT_TOC_ENTRY 0
+#define OPT_PLAT_TOC_FLAGS 1
+#define OPT_ALIGN 2
+
+static int info_cmd(int argc, char *argv[]);
+static void info_usage(void);
+static int create_cmd(int argc, char *argv[]);
+static void create_usage(void);
+static int update_cmd(int argc, char *argv[]);
+static void update_usage(void);
+static int unpack_cmd(int argc, char *argv[]);
+static void unpack_usage(void);
+static int remove_cmd(int argc, char *argv[]);
+static void remove_usage(void);
+static int version_cmd(int argc, char *argv[]);
+static void version_usage(void);
+static int help_cmd(int argc, char *argv[]);
+static void usage(void);
+
+/* Available subcommands. */
+static cmd_t cmds[] = {
+	{ .name = "info",    .handler = info_cmd,    .usage = info_usage    },
+	{ .name = "create",  .handler = create_cmd,  .usage = create_usage  },
+	{ .name = "update",  .handler = update_cmd,  .usage = update_usage  },
+	{ .name = "unpack",  .handler = unpack_cmd,  .usage = unpack_usage  },
+	{ .name = "remove",  .handler = remove_cmd,  .usage = remove_usage  },
+	{ .name = "version", .handler = version_cmd, .usage = version_usage },
+	{ .name = "help",    .handler = help_cmd,    .usage = NULL          },
+};
+
+static image_desc_t *image_desc_head;
+static size_t nr_image_descs;
+static const uuid_t uuid_null;
+static int verbose;
+
+static void vlog(int prio, const char *msg, va_list ap)
+{
+	char *prefix[] = { "DEBUG", "WARN", "ERROR" };
+
+	fprintf(stderr, "%s: ", prefix[prio]);
+	vfprintf(stderr, msg, ap);
+	fputc('\n', stderr);
+}
+
+static void log_dbgx(const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	vlog(LOG_DBG, msg, ap);
+	va_end(ap);
+}
+
+static void log_warnx(const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	vlog(LOG_WARN, msg, ap);
+	va_end(ap);
+}
+
+static void log_err(const char *msg, ...)
+{
+	char buf[512];
+	va_list ap;
+
+	va_start(ap, msg);
+	snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
+	vlog(LOG_ERR, buf, ap);
+	va_end(ap);
+	exit(1);
+}
+
+static void log_errx(const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	vlog(LOG_ERR, msg, ap);
+	va_end(ap);
+	exit(1);
+}
+
+static char *xstrdup(const char *s, const char *msg)
+{
+	char *d;
+
+	d = strdup(s);
+	if (d == NULL)
+		log_errx("strdup: %s", msg);
+	return d;
+}
+
+static void *xmalloc(size_t size, const char *msg)
+{
+	void *d;
+
+	d = malloc(size);
+	if (d == NULL)
+		log_errx("malloc: %s", msg);
+	return d;
+}
+
+static void *xzalloc(size_t size, const char *msg)
+{
+	return memset(xmalloc(size, msg), 0, size);
+}
+
+static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename)
+{
+	if (fwrite(buf, 1, size, fp) != size)
+		log_errx("Failed to write %s", filename);
+}
+
+static image_desc_t *new_image_desc(const uuid_t *uuid,
+    const char *name, const char *cmdline_name)
+{
+	image_desc_t *desc;
+
+	desc = xzalloc(sizeof(*desc),
+	    "failed to allocate memory for image descriptor");
+	memcpy(&desc->uuid, uuid, sizeof(uuid_t));
+	desc->name = xstrdup(name,
+	    "failed to allocate memory for image name");
+	desc->cmdline_name = xstrdup(cmdline_name,
+	    "failed to allocate memory for image command line name");
+	desc->action = DO_UNSPEC;
+	return desc;
+}
+
+static void set_image_desc_action(image_desc_t *desc, int action,
+    const char *arg)
+{
+	assert(desc != NULL);
+
+	if (desc->action_arg != (char *)DO_UNSPEC)
+		free(desc->action_arg);
+	desc->action = action;
+	desc->action_arg = NULL;
+	if (arg != NULL)
+		desc->action_arg = xstrdup(arg,
+		    "failed to allocate memory for argument");
+}
+
+static void free_image_desc(image_desc_t *desc)
+{
+	free(desc->name);
+	free(desc->cmdline_name);
+	free(desc->action_arg);
+	if (desc->image) {
+		free(desc->image->buffer);
+		free(desc->image);
+	}
+	free(desc);
+}
+
+static void add_image_desc(image_desc_t *desc)
+{
+	image_desc_t **p = &image_desc_head;
+
+	while (*p)
+		p = &(*p)->next;
+
+	assert(*p == NULL);
+	*p = desc;
+	nr_image_descs++;
+}
+
+static void free_image_descs(void)
+{
+	image_desc_t *desc = image_desc_head, *tmp;
+
+	while (desc != NULL) {
+		tmp = desc->next;
+		free_image_desc(desc);
+		desc = tmp;
+		nr_image_descs--;
+	}
+	assert(nr_image_descs == 0);
+}
+
+static void fill_image_descs(void)
+{
+	toc_entry_t *toc_entry;
+
+	for (toc_entry = toc_entries;
+	     toc_entry->cmdline_name != NULL;
+	     toc_entry++) {
+		image_desc_t *desc;
+
+		desc = new_image_desc(&toc_entry->uuid,
+		    toc_entry->name,
+		    toc_entry->cmdline_name);
+		add_image_desc(desc);
+	}
+}
+
+static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
+{
+	image_desc_t *desc;
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
+			return desc;
+	return NULL;
+}
+
+static image_desc_t *lookup_image_desc_from_opt(const char *opt)
+{
+	image_desc_t *desc;
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		if (strcmp(desc->cmdline_name, opt) == 0)
+			return desc;
+	return NULL;
+}
+
+static void uuid_to_str(char *s, size_t len, const uuid_t *u)
+{
+	assert(len >= (_UUID_STR_LEN + 1));
+
+	snprintf(s, len,
+	    "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X",
+	    u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3],
+	    u->time_mid[0], u->time_mid[1],
+	    u->time_hi_and_version[0], u->time_hi_and_version[1],
+	    (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
+	    (u->node[0] << 8) | u->node[1],
+	    (u->node[2] << 8) | u->node[3],
+	    (u->node[4] << 8) | u->node[5]);
+}
+
+static void uuid_from_str(uuid_t *u, const char *s)
+{
+	int n;
+
+	if (s == NULL)
+		log_errx("UUID cannot be NULL");
+	if (strlen(s) != _UUID_STR_LEN)
+		log_errx("Invalid UUID: %s", s);
+
+	n = sscanf(s,
+	    "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+	    &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3],
+	    &u->time_mid[0], &u->time_mid[1],
+	    &u->time_hi_and_version[0], &u->time_hi_and_version[1],
+	    &u->clock_seq_hi_and_reserved, &u->clock_seq_low,
+	    &u->node[0], &u->node[1],
+	    &u->node[2], &u->node[3],
+	    &u->node[4], &u->node[5]);
+	/*
+	 * Given the format specifier above, we expect 16 items to be scanned
+	 * for a properly formatted UUID.
+	 */
+	if (n != 16)
+		log_errx("Invalid UUID: %s", s);
+}
+
+static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
+{
+	struct BLD_PLAT_STAT st;
+	FILE *fp;
+	char *buf, *bufend;
+	fip_toc_header_t *toc_header;
+	fip_toc_entry_t *toc_entry;
+	int terminated = 0;
+
+	fp = fopen(filename, "rb");
+	if (fp == NULL)
+		log_err("fopen %s", filename);
+
+	if (fstat(fileno(fp), &st) == -1)
+		log_err("fstat %s", filename);
+
+	buf = xmalloc(st.st_size, "failed to load file into memory");
+	if (fread(buf, 1, st.st_size, fp) != st.st_size)
+		log_errx("Failed to read %s", filename);
+	bufend = buf + st.st_size;
+	fclose(fp);
+
+	if (st.st_size < sizeof(fip_toc_header_t))
+		log_errx("FIP %s is truncated", filename);
+
+	toc_header = (fip_toc_header_t *)buf;
+	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
+
+	if (toc_header->name != TOC_HEADER_NAME)
+		log_errx("%s is not a FIP file", filename);
+
+	/* Return the ToC header if the caller wants it. */
+	if (toc_header_out != NULL)
+		*toc_header_out = *toc_header;
+
+	/* Walk through each ToC entry in the file. */
+	while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
+		image_t *image;
+		image_desc_t *desc;
+
+		/* Found the ToC terminator, we are done. */
+		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
+			terminated = 1;
+			break;
+		}
+
+		/*
+		 * Build a new image out of the ToC entry and add it to the
+		 * table of images.
+		 */
+		image = xzalloc(sizeof(*image),
+		    "failed to allocate memory for image");
+		image->toc_e = *toc_entry;
+		image->buffer = xmalloc(toc_entry->size,
+		    "failed to allocate image buffer, is FIP file corrupted?");
+		/* Overflow checks before memory copy. */
+		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address)
+			log_errx("FIP %s is corrupted", filename);
+		if (toc_entry->size + toc_entry->offset_address > st.st_size)
+			log_errx("FIP %s is corrupted", filename);
+
+		memcpy(image->buffer, buf + toc_entry->offset_address,
+		    toc_entry->size);
+
+		/* If this is an unknown image, create a descriptor for it. */
+		desc = lookup_image_desc_from_uuid(&toc_entry->uuid);
+		if (desc == NULL) {
+			char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
+
+			uuid_to_str(name, sizeof(name), &toc_entry->uuid);
+			snprintf(filename, sizeof(filename), "%s%s",
+			    name, ".bin");
+			desc = new_image_desc(&toc_entry->uuid, name, "blob");
+			desc->action = DO_UNPACK;
+			desc->action_arg = xstrdup(filename,
+			    "failed to allocate memory for blob filename");
+			add_image_desc(desc);
+		}
+
+		assert(desc->image == NULL);
+		desc->image = image;
+
+		toc_entry++;
+	}
+
+	if (terminated == 0)
+		log_errx("FIP %s does not have a ToC terminator entry",
+		    filename);
+	free(buf);
+	return 0;
+}
+
+static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
+{
+	struct BLD_PLAT_STAT st;
+	image_t *image;
+	FILE *fp;
+
+	assert(uuid != NULL);
+	assert(filename != NULL);
+
+	fp = fopen(filename, "rb");
+	if (fp == NULL)
+		log_err("fopen %s", filename);
+
+	if (fstat(fileno(fp), &st) == -1)
+		log_errx("fstat %s", filename);
+
+	image = xzalloc(sizeof(*image), "failed to allocate memory for image");
+	image->toc_e.uuid = *uuid;
+	image->buffer = xmalloc(st.st_size, "failed to allocate image buffer");
+	if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
+		log_errx("Failed to read %s", filename);
+	image->toc_e.size = st.st_size;
+
+	fclose(fp);
+	return image;
+}
+
+static int write_image_to_file(const image_t *image, const char *filename)
+{
+	FILE *fp;
+
+	fp = fopen(filename, "wb");
+	if (fp == NULL)
+		log_err("fopen");
+	xfwrite(image->buffer, image->toc_e.size, fp, filename);
+	fclose(fp);
+	return 0;
+}
+
+static struct option *add_opt(struct option *opts, size_t *nr_opts,
+    const char *name, int has_arg, int val)
+{
+	opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
+	if (opts == NULL)
+		log_err("realloc");
+	opts[*nr_opts].name = name;
+	opts[*nr_opts].has_arg = has_arg;
+	opts[*nr_opts].flag = NULL;
+	opts[*nr_opts].val = val;
+	++*nr_opts;
+	return opts;
+}
+
+static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
+    int has_arg)
+{
+	image_desc_t *desc;
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
+		    OPT_TOC_ENTRY);
+	return opts;
+}
+
+static void md_print(const unsigned char *md, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		printf("%02x", md[i]);
+}
+
+static int info_cmd(int argc, char *argv[])
+{
+	image_desc_t *desc;
+	fip_toc_header_t toc_header;
+
+	if (argc != 2)
+		info_usage();
+	argc--, argv++;
+
+	parse_fip(argv[0], &toc_header);
+
+	if (verbose) {
+		log_dbgx("toc_header[name]: 0x%llX",
+		    (unsigned long long)toc_header.name);
+		log_dbgx("toc_header[serial_number]: 0x%llX",
+		    (unsigned long long)toc_header.serial_number);
+		log_dbgx("toc_header[flags]: 0x%llX",
+		    (unsigned long long)toc_header.flags);
+	}
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image = desc->image;
+
+		if (image == NULL)
+			continue;
+		printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
+		       desc->name,
+		       (unsigned long long)image->toc_e.offset_address,
+		       (unsigned long long)image->toc_e.size,
+		       desc->cmdline_name);
+#ifndef _MSC_VER	/* We don't have SHA256 for Visual Studio. */
+		if (verbose) {
+			unsigned char md[SHA256_DIGEST_LENGTH];
+
+			SHA256(image->buffer, image->toc_e.size, md);
+			printf(", sha256=");
+			md_print(md, sizeof(md));
+		}
+#endif
+		putchar('\n');
+	}
+
+	return 0;
+}
+
+static void info_usage(void)
+{
+	printf("fiptool info FIP_FILENAME\n");
+	exit(1);
+}
+
+static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
+{
+	FILE *fp;
+	image_desc_t *desc;
+	fip_toc_header_t *toc_header;
+	fip_toc_entry_t *toc_entry;
+	char *buf;
+	uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
+	size_t nr_images = 0;
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next)
+		if (desc->image != NULL)
+			nr_images++;
+
+	buf_size = sizeof(fip_toc_header_t) +
+	    sizeof(fip_toc_entry_t) * (nr_images + 1);
+	buf = calloc(1, buf_size);
+	if (buf == NULL)
+		log_err("calloc");
+
+	/* Build up header and ToC entries from the image table. */
+	toc_header = (fip_toc_header_t *)buf;
+	toc_header->name = TOC_HEADER_NAME;
+	toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
+	toc_header->flags = toc_flags;
+
+	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
+
+	entry_offset = buf_size;
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image = desc->image;
+
+		if (image == NULL)
+			continue;
+		payload_size += image->toc_e.size;
+		entry_offset = (entry_offset + align - 1) & ~(align - 1);
+		image->toc_e.offset_address = entry_offset;
+		*toc_entry++ = image->toc_e;
+		entry_offset += image->toc_e.size;
+	}
+
+	/*
+	 * Append a null uuid entry to mark the end of ToC entries.
+	 * NOTE the offset address for the last toc_entry must match the fip
+	 * size.
+	 */
+	memset(toc_entry, 0, sizeof(*toc_entry));
+	toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
+
+	/* Generate the FIP file. */
+	fp = fopen(filename, "wb");
+	if (fp == NULL)
+		log_err("fopen %s", filename);
+
+	if (verbose)
+		log_dbgx("Metadata size: %zu bytes", buf_size);
+
+	xfwrite(buf, buf_size, fp, filename);
+
+	if (verbose)
+		log_dbgx("Payload size: %zu bytes", payload_size);
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image = desc->image;
+
+		if (image == NULL)
+			continue;
+		if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
+			log_errx("Failed to set file position");
+
+		xfwrite(image->buffer, image->toc_e.size, fp, filename);
+	}
+
+	if (fseek(fp, entry_offset, SEEK_SET))
+		log_errx("Failed to set file position");
+
+	pad_size = toc_entry->offset_address - entry_offset;
+	while (pad_size--)
+		fputc(0x0, fp);
+
+	free(buf);
+	fclose(fp);
+	return 0;
+}
+
+/*
+ * This function is shared between the create and update subcommands.
+ * The difference between the two subcommands is that when the FIP file
+ * is created, the parsing of an existing FIP is skipped.  This results
+ * in update_fip() creating the new FIP file from scratch because the
+ * internal image table is not populated.
+ */
+static void update_fip(void)
+{
+	image_desc_t *desc;
+
+	/* Add or replace images in the FIP file. */
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		image_t *image;
+
+		if (desc->action != DO_PACK)
+			continue;
+
+		image = read_image_from_file(&desc->uuid,
+		    desc->action_arg);
+		if (desc->image != NULL) {
+			if (verbose) {
+				log_dbgx("Replacing %s with %s",
+				    desc->cmdline_name,
+				    desc->action_arg);
+			}
+			free(desc->image);
+			desc->image = image;
+		} else {
+			if (verbose)
+				log_dbgx("Adding image %s",
+				    desc->action_arg);
+			desc->image = image;
+		}
+	}
+}
+
+static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
+{
+	unsigned long long flags;
+	char *endptr;
+
+	errno = 0;
+	flags = strtoull(arg, &endptr, 16);
+	if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
+		log_errx("Invalid platform ToC flags: %s", arg);
+	/* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
+	*toc_flags |= flags << 32;
+}
+
+static int is_power_of_2(unsigned long x)
+{
+	return x && !(x & (x - 1));
+}
+
+static unsigned long get_image_align(char *arg)
+{
+	char *endptr;
+	unsigned long align;
+
+	errno = 0;
+	align = strtoul(arg, &endptr, 0);
+	if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
+		log_errx("Invalid alignment: %s", arg);
+
+	return align;
+}
+
+static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
+{
+	char *p;
+
+	for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
+		if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
+			p += strlen("uuid=");
+			uuid_from_str(uuid, p);
+		} else if (strncmp(p, "file=", strlen("file=")) == 0) {
+			p += strlen("file=");
+			snprintf(filename, len, "%s", p);
+		}
+	}
+}
+
+static int create_cmd(int argc, char *argv[])
+{
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
+	unsigned long long toc_flags = 0;
+	unsigned long align = 1;
+
+	if (argc < 2)
+		create_usage();
+
+	opts = fill_common_opts(opts, &nr_opts, required_argument);
+	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
+	    OPT_PLAT_TOC_FLAGS);
+	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
+	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
+
+	while (1) {
+		int c, opt_index = 0;
+
+		c = getopt_long(argc, argv, "b:", opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case OPT_TOC_ENTRY: {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			set_image_desc_action(desc, DO_PACK, optarg);
+			break;
+		}
+		case OPT_PLAT_TOC_FLAGS:
+			parse_plat_toc_flags(optarg, &toc_flags);
+			break;
+		case OPT_ALIGN:
+			align = get_image_align(optarg);
+			break;
+		case 'b': {
+			char name[_UUID_STR_LEN + 1];
+			char filename[PATH_MAX] = { 0 };
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			    filename[0] == '\0')
+				create_usage();
+
+			desc = lookup_image_desc_from_uuid(&uuid);
+			if (desc == NULL) {
+				uuid_to_str(name, sizeof(name), &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(desc);
+			}
+			set_image_desc_action(desc, DO_PACK, filename);
+			break;
+		}
+		default:
+			create_usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	free(opts);
+
+	if (argc == 0)
+		create_usage();
+
+	update_fip();
+
+	pack_images(argv[0], toc_flags, align);
+	return 0;
+}
+
+static void create_usage(void)
+{
+	toc_entry_t *toc_entry = toc_entries;
+
+	printf("fiptool create [opts] FIP_FILENAME\n");
+	printf("\n");
+	printf("Options:\n");
+	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
+	printf("  --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
+	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
+	printf("\n");
+	printf("Specific images are packed with the following options:\n");
+	for (; toc_entry->cmdline_name != NULL; toc_entry++)
+		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
+		    toc_entry->name);
+	exit(1);
+}
+
+static int update_cmd(int argc, char *argv[])
+{
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
+	char outfile[PATH_MAX] = { 0 };
+	fip_toc_header_t toc_header = { 0 };
+	unsigned long long toc_flags = 0;
+	unsigned long align = 1;
+	int pflag = 0;
+
+	if (argc < 2)
+		update_usage();
+
+	opts = fill_common_opts(opts, &nr_opts, required_argument);
+	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
+	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
+	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
+	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
+	    OPT_PLAT_TOC_FLAGS);
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
+
+	while (1) {
+		int c, opt_index = 0;
+
+		c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case OPT_TOC_ENTRY: {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			set_image_desc_action(desc, DO_PACK, optarg);
+			break;
+		}
+		case OPT_PLAT_TOC_FLAGS:
+			parse_plat_toc_flags(optarg, &toc_flags);
+			pflag = 1;
+			break;
+		case 'b': {
+			char name[_UUID_STR_LEN + 1];
+			char filename[PATH_MAX] = { 0 };
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			    filename[0] == '\0')
+				update_usage();
+
+			desc = lookup_image_desc_from_uuid(&uuid);
+			if (desc == NULL) {
+				uuid_to_str(name, sizeof(name), &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(desc);
+			}
+			set_image_desc_action(desc, DO_PACK, filename);
+			break;
+		}
+		case OPT_ALIGN:
+			align = get_image_align(optarg);
+			break;
+		case 'o':
+			snprintf(outfile, sizeof(outfile), "%s", optarg);
+			break;
+		default:
+			update_usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	free(opts);
+
+	if (argc == 0)
+		update_usage();
+
+	if (outfile[0] == '\0')
+		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
+
+	if (access(argv[0], F_OK) == 0)
+		parse_fip(argv[0], &toc_header);
+
+	if (pflag)
+		toc_header.flags &= ~(0xffffULL << 32);
+	toc_flags = (toc_header.flags |= toc_flags);
+
+	update_fip();
+
+	pack_images(outfile, toc_flags, align);
+	return 0;
+}
+
+static void update_usage(void)
+{
+	toc_entry_t *toc_entry = toc_entries;
+
+	printf("fiptool update [opts] FIP_FILENAME\n");
+	printf("\n");
+	printf("Options:\n");
+	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
+	printf("  --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n");
+	printf("  --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
+	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
+	printf("\n");
+	printf("Specific images are packed with the following options:\n");
+	for (; toc_entry->cmdline_name != NULL; toc_entry++)
+		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
+		    toc_entry->name);
+	exit(1);
+}
+
+static int unpack_cmd(int argc, char *argv[])
+{
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
+	char outdir[PATH_MAX] = { 0 };
+	image_desc_t *desc;
+	int fflag = 0;
+	int unpack_all = 1;
+
+	if (argc < 2)
+		unpack_usage();
+
+	opts = fill_common_opts(opts, &nr_opts, required_argument);
+	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
+	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
+	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
+
+	while (1) {
+		int c, opt_index = 0;
+
+		c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case OPT_TOC_ENTRY: {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			set_image_desc_action(desc, DO_UNPACK, optarg);
+			unpack_all = 0;
+			break;
+		}
+		case 'b': {
+			char name[_UUID_STR_LEN + 1];
+			char filename[PATH_MAX] = { 0 };
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			    filename[0] == '\0')
+				unpack_usage();
+
+			desc = lookup_image_desc_from_uuid(&uuid);
+			if (desc == NULL) {
+				uuid_to_str(name, sizeof(name), &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(desc);
+			}
+			set_image_desc_action(desc, DO_UNPACK, filename);
+			unpack_all = 0;
+			break;
+		}
+		case 'f':
+			fflag = 1;
+			break;
+		case 'o':
+			snprintf(outdir, sizeof(outdir), "%s", optarg);
+			break;
+		default:
+			unpack_usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	free(opts);
+
+	if (argc == 0)
+		unpack_usage();
+
+	parse_fip(argv[0], NULL);
+
+	if (outdir[0] != '\0')
+		if (chdir(outdir) == -1)
+			log_err("chdir %s", outdir);
+
+	/* Unpack all specified images. */
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		char file[PATH_MAX];
+		image_t *image = desc->image;
+
+		if (!unpack_all && desc->action != DO_UNPACK)
+			continue;
+
+		/* Build filename. */
+		if (desc->action_arg == NULL)
+			snprintf(file, sizeof(file), "%s.bin",
+			    desc->cmdline_name);
+		else
+			snprintf(file, sizeof(file), "%s",
+			    desc->action_arg);
+
+		if (image == NULL) {
+			if (!unpack_all)
+				log_warnx("%s does not exist in %s",
+				    file, argv[0]);
+			continue;
+		}
+
+		if (access(file, F_OK) != 0 || fflag) {
+			if (verbose)
+				log_dbgx("Unpacking %s", file);
+			write_image_to_file(image, file);
+		} else {
+			log_warnx("File %s already exists, use --force to overwrite it",
+			    file);
+		}
+	}
+
+	return 0;
+}
+
+static void unpack_usage(void)
+{
+	toc_entry_t *toc_entry = toc_entries;
+
+	printf("fiptool unpack [opts] FIP_FILENAME\n");
+	printf("\n");
+	printf("Options:\n");
+	printf("  --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
+	printf("  --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
+	printf("  --out path\t\t\tSet the output directory path.\n");
+	printf("\n");
+	printf("Specific images are unpacked with the following options:\n");
+	for (; toc_entry->cmdline_name != NULL; toc_entry++)
+		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
+		    toc_entry->name);
+	printf("\n");
+	printf("If no options are provided, all images will be unpacked.\n");
+	exit(1);
+}
+
+static int remove_cmd(int argc, char *argv[])
+{
+	struct option *opts = NULL;
+	size_t nr_opts = 0;
+	char outfile[PATH_MAX] = { 0 };
+	fip_toc_header_t toc_header;
+	image_desc_t *desc;
+	unsigned long align = 1;
+	int fflag = 0;
+
+	if (argc < 2)
+		remove_usage();
+
+	opts = fill_common_opts(opts, &nr_opts, no_argument);
+	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
+	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
+	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
+	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
+	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
+
+	while (1) {
+		int c, opt_index = 0;
+
+		c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case OPT_TOC_ENTRY: {
+			image_desc_t *desc;
+
+			desc = lookup_image_desc_from_opt(opts[opt_index].name);
+			set_image_desc_action(desc, DO_REMOVE, NULL);
+			break;
+		}
+		case OPT_ALIGN:
+			align = get_image_align(optarg);
+			break;
+		case 'b': {
+			char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
+			uuid_t uuid = uuid_null;
+			image_desc_t *desc;
+
+			parse_blob_opt(optarg, &uuid,
+			    filename, sizeof(filename));
+
+			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
+				remove_usage();
+
+			desc = lookup_image_desc_from_uuid(&uuid);
+			if (desc == NULL) {
+				uuid_to_str(name, sizeof(name), &uuid);
+				desc = new_image_desc(&uuid, name, "blob");
+				add_image_desc(desc);
+			}
+			set_image_desc_action(desc, DO_REMOVE, NULL);
+			break;
+		}
+		case 'f':
+			fflag = 1;
+			break;
+		case 'o':
+			snprintf(outfile, sizeof(outfile), "%s", optarg);
+			break;
+		default:
+			remove_usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	free(opts);
+
+	if (argc == 0)
+		remove_usage();
+
+	if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
+		log_errx("File %s already exists, use --force to overwrite it",
+		    outfile);
+
+	if (outfile[0] == '\0')
+		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
+
+	parse_fip(argv[0], &toc_header);
+
+	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
+		if (desc->action != DO_REMOVE)
+			continue;
+
+		if (desc->image != NULL) {
+			if (verbose)
+				log_dbgx("Removing %s",
+				    desc->cmdline_name);
+			free(desc->image);
+			desc->image = NULL;
+		} else {
+			log_warnx("%s does not exist in %s",
+			    desc->cmdline_name, argv[0]);
+		}
+	}
+
+	pack_images(outfile, toc_header.flags, align);
+	return 0;
+}
+
+static void remove_usage(void)
+{
+	toc_entry_t *toc_entry = toc_entries;
+
+	printf("fiptool remove [opts] FIP_FILENAME\n");
+	printf("\n");
+	printf("Options:\n");
+	printf("  --align <value>\tEach image is aligned to <value> (default: 1).\n");
+	printf("  --blob uuid=...\tRemove an image with the given UUID.\n");
+	printf("  --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
+	printf("  --out FIP_FILENAME\tSet an alternative output FIP file.\n");
+	printf("\n");
+	printf("Specific images are removed with the following options:\n");
+	for (; toc_entry->cmdline_name != NULL; toc_entry++)
+		printf("  --%-16s\t%s\n", toc_entry->cmdline_name,
+		    toc_entry->name);
+	exit(1);
+}
+
+static int version_cmd(int argc, char *argv[])
+{
+#ifdef VERSION
+	puts(VERSION);
+#else
+	/* If built from fiptool directory, VERSION is not set. */
+	puts("Unknown version");
+#endif
+	return 0;
+}
+
+static void version_usage(void)
+{
+	printf("fiptool version\n");
+	exit(1);
+}
+
+static int help_cmd(int argc, char *argv[])
+{
+	int i;
+
+	if (argc < 2)
+		usage();
+	argc--, argv++;
+
+	for (i = 0; i < NELEM(cmds); i++) {
+		if (strcmp(cmds[i].name, argv[0]) == 0 &&
+		    cmds[i].usage != NULL)
+			cmds[i].usage();
+	}
+	if (i == NELEM(cmds))
+		printf("No help for subcommand '%s'\n", argv[0]);
+	return 0;
+}
+
+static void usage(void)
+{
+	printf("usage: fiptool [--verbose] <command> [<args>]\n");
+	printf("Global options supported:\n");
+	printf("  --verbose\tEnable verbose output for all commands.\n");
+	printf("\n");
+	printf("Commands supported:\n");
+	printf("  info\t\tList images contained in FIP.\n");
+	printf("  create\tCreate a new FIP with the given images.\n");
+	printf("  update\tUpdate an existing FIP with the given images.\n");
+	printf("  unpack\tUnpack images from FIP.\n");
+	printf("  remove\tRemove images from FIP.\n");
+	printf("  version\tShow fiptool version.\n");
+	printf("  help\t\tShow help for given command.\n");
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	int i, ret = 0;
+
+	while (1) {
+		int c, opt_index = 0;
+		static struct option opts[] = {
+			{ "verbose", no_argument, NULL, 'v' },
+			{ NULL, no_argument, NULL, 0 }
+		};
+
+		/*
+		 * Set POSIX mode so getopt stops at the first non-option
+		 * which is the subcommand.
+		 */
+		c = getopt_long(argc, argv, "+v", opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'v':
+			verbose = 1;
+			break;
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	/* Reset optind for subsequent getopt processing. */
+	optind = 0;
+
+	if (argc == 0)
+		usage();
+
+	fill_image_descs();
+	for (i = 0; i < NELEM(cmds); i++) {
+		if (strcmp(cmds[i].name, argv[0]) == 0) {
+			ret = cmds[i].handler(argc, argv);
+			break;
+		}
+	}
+	if (i == NELEM(cmds))
+		usage();
+	free_image_descs();
+	return ret;
+}
diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h
new file mode 100644
index 0000000..af3fcbd
--- /dev/null
+++ b/tools/fiptool/fiptool.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIPTOOL_H
+#define FIPTOOL_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <firmware_image_package.h>
+#include <uuid.h>
+
+#include "fiptool_platform.h"
+
+#define NELEM(x) (sizeof (x) / sizeof *(x))
+
+enum {
+	DO_UNSPEC = 0,
+	DO_PACK   = 1,
+	DO_UNPACK = 2,
+	DO_REMOVE = 3
+};
+
+enum {
+	LOG_DBG,
+	LOG_WARN,
+	LOG_ERR
+};
+
+typedef struct image_desc {
+	uuid_t             uuid;
+	char              *name;
+	char              *cmdline_name;
+	int                action;
+	char              *action_arg;
+	struct image      *image;
+	struct image_desc *next;
+} image_desc_t;
+
+typedef struct image {
+	struct fip_toc_entry toc_e;
+	void                *buffer;
+} image_t;
+
+typedef struct cmd {
+	char              *name;
+	int              (*handler)(int, char **);
+	void             (*usage)(void);
+} cmd_t;
+
+#endif /* FIPTOOL_H */
diff --git a/tools/fiptool/fiptool_platform.h b/tools/fiptool/fiptool_platform.h
new file mode 100644
index 0000000..9bfa298
--- /dev/null
+++ b/tools/fiptool/fiptool_platform.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/*
+ * Build platform specific handling.
+ * This allows for builds on non-Posix platforms
+ * e.g. Visual Studio on Windows
+ */
+
+#ifndef FIPTOOL_PLATFORM_H
+#define FIPTOOL_PLATFORM_H
+
+#ifndef _MSC_VER
+
+/* Not Visual Studio, so include Posix Headers. */
+# include <getopt.h>
+# include <openssl/sha.h>
+# include <unistd.h>
+
+# define  BLD_PLAT_STAT stat
+
+#else
+
+/* Visual Studio. */
+# include "win_posix.h"
+
+#endif
+
+#endif /* FIPTOOL_PLATFORM_H */
diff --git a/tools/fiptool/tbbr_config.c b/tools/fiptool/tbbr_config.c
new file mode 100644
index 0000000..86b8581
--- /dev/null
+++ b/tools/fiptool/tbbr_config.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <firmware_image_package.h>
+
+#include "tbbr_config.h"
+
+/* The images used depends on the platform. */
+toc_entry_t toc_entries[] = {
+	{
+		.name = "SCP Firmware Updater Configuration FWU SCP_BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
+		.cmdline_name = "scp-fwu-cfg"
+	},
+	{
+		.name = "AP Firmware Updater Configuration BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
+		.cmdline_name = "ap-fwu-cfg"
+	},
+	{
+		.name = "Firmware Updater NS_BL2U",
+		.uuid = UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
+		.cmdline_name = "fwu"
+	},
+	{
+		.name = "Non-Trusted Firmware Updater certificate",
+		.uuid = UUID_TRUSTED_FWU_CERT,
+		.cmdline_name = "fwu-cert"
+	},
+	{
+		.name = "Trusted Boot Firmware BL2",
+		.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+		.cmdline_name = "tb-fw"
+	},
+	{
+		.name = "SCP Firmware SCP_BL2",
+		.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+		.cmdline_name = "scp-fw"
+	},
+	{
+		.name = "EL3 Runtime Firmware BL31",
+		.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+		.cmdline_name = "soc-fw"
+	},
+	{
+		.name = "Secure Payload BL32 (Trusted OS)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32,
+		.cmdline_name = "tos-fw"
+	},
+	{
+		.name = "Secure Payload BL32 Extra1 (Trusted OS Extra1)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+		.cmdline_name = "tos-fw-extra1"
+	},
+	{
+		.name = "Secure Payload BL32 Extra2 (Trusted OS Extra2)",
+		.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+		.cmdline_name = "tos-fw-extra2"
+	},
+	{
+		.name = "Non-Trusted Firmware BL33",
+		.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+		.cmdline_name = "nt-fw"
+	},
+	/* Dynamic Configs */
+	{
+		.name = "HW_CONFIG",
+		.uuid = UUID_HW_CONFIG,
+		.cmdline_name = "hw-config"
+	},
+	{
+		.name = "TB_FW_CONFIG",
+		.uuid = UUID_TB_FW_CONFIG,
+		.cmdline_name = "tb-fw-config"
+	},
+	{
+		.name = "SOC_FW_CONFIG",
+		.uuid = UUID_SOC_FW_CONFIG,
+		.cmdline_name = "soc-fw-config"
+	},
+	{
+		.name = "TOS_FW_CONFIG",
+		.uuid = UUID_TOS_FW_CONFIG,
+		.cmdline_name = "tos-fw-config"
+	},
+	{
+		.name = "NT_FW_CONFIG",
+		.uuid = UUID_NT_FW_CONFIG,
+		.cmdline_name = "nt-fw-config"
+	},
+	/* Key Certificates */
+	{
+		.name = "Root Of Trust key certificate",
+		.uuid = UUID_ROT_KEY_CERT,
+		.cmdline_name = "rot-cert"
+	},
+	{
+		.name = "Trusted key certificate",
+		.uuid = UUID_TRUSTED_KEY_CERT,
+		.cmdline_name = "trusted-key-cert"
+	},
+	{
+		.name = "SCP Firmware key certificate",
+		.uuid = UUID_SCP_FW_KEY_CERT,
+		.cmdline_name = "scp-fw-key-cert"
+	},
+	{
+		.name = "SoC Firmware key certificate",
+		.uuid = UUID_SOC_FW_KEY_CERT,
+		.cmdline_name = "soc-fw-key-cert"
+	},
+	{
+		.name = "Trusted OS Firmware key certificate",
+		.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+		.cmdline_name = "tos-fw-key-cert"
+	},
+	{
+		.name = "Non-Trusted Firmware key certificate",
+		.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+		.cmdline_name = "nt-fw-key-cert"
+	},
+
+	/* Content certificates */
+	{
+		.name = "Trusted Boot Firmware BL2 certificate",
+		.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+		.cmdline_name = "tb-fw-cert"
+	},
+	{
+		.name = "SCP Firmware content certificate",
+		.uuid = UUID_SCP_FW_CONTENT_CERT,
+		.cmdline_name = "scp-fw-cert"
+	},
+	{
+		.name = "SoC Firmware content certificate",
+		.uuid = UUID_SOC_FW_CONTENT_CERT,
+		.cmdline_name = "soc-fw-cert"
+	},
+	{
+		.name = "Trusted OS Firmware content certificate",
+		.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+		.cmdline_name = "tos-fw-cert"
+	},
+	{
+		.name = "Non-Trusted Firmware content certificate",
+		.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+		.cmdline_name = "nt-fw-cert"
+	},
+	{
+		.name = NULL,
+		.uuid = { {0} },
+		.cmdline_name = NULL,
+	}
+};
diff --git a/tools/fiptool/tbbr_config.h b/tools/fiptool/tbbr_config.h
new file mode 100644
index 0000000..1fc6cad
--- /dev/null
+++ b/tools/fiptool/tbbr_config.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TBBR_CONFIG_H
+#define TBBR_CONFIG_H
+
+#include <stdint.h>
+
+#include <uuid.h>
+
+#define TOC_HEADER_SERIAL_NUMBER 0x12345678
+
+typedef struct toc_entry {
+	char         *name;
+	uuid_t        uuid;
+	char         *cmdline_name;
+} toc_entry_t;
+
+extern toc_entry_t toc_entries[];
+
+#endif /* TBBR_CONFIG_H */
diff --git a/tools/fiptool/win_posix.c b/tools/fiptool/win_posix.c
new file mode 100644
index 0000000..48feb16
--- /dev/null
+++ b/tools/fiptool/win_posix.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include "win_posix.h"
+
+/*
+ * This variable is set by getopt to the index of the next element of the
+ * argv array to be processed. Once getopt has found all of the option
+ * arguments, you can use this variable to determine where the remaining
+ * non-option arguments begin. The initial value of this variable is 1.
+ */
+int optind = 1;
+
+/*
+ * If the value of this variable is nonzero, then getopt prints an error
+ * message to the standard error stream if it encounters an unknown option
+ * default character or an option with a missing required argument.
+ * If you set this variable to zero, getopt does not print any messages,
+ * but it still returns the character ? to indicate an error.
+ */
+const int opterr; /* = 0; */
+/* const because we do not implement error printing.*/
+/* Not initialised to conform with the coding standard. */
+
+/*
+ * When getopt encounters an unknown option character or an option with a
+ * missing required argument, it stores that option character in this
+ * variable.
+ */
+int optopt;	/* = 0; */
+
+/*
+ * This variable is set by getopt to point at the value of the option
+ * argument, for those options that accept arguments.
+ */
+char *optarg;	/* = 0; */
+
+enum return_flags {
+	RET_ERROR = -1,
+	RET_END_OPT_LIST = -1,
+	RET_NO_PARAM = '?',
+	RET_NO_PARAM2 = ':',
+	RET_UNKNOWN_OPT = '?'
+};
+
+/*
+ * Common initialisation on entry.
+ */
+static
+void getopt_init(void)
+{
+	optarg = (char *)0;
+	optopt = 0;
+	/* optind may be zero with some POSIX uses.
+	 * For our purposes we just change it to 1.
+	 */
+	if (optind == 0)
+		optind = 1;
+}
+
+/*
+ * Common handling for a single letter option.
+ */
+static
+int getopt_1char(int argc,
+		 char *const argv[],
+		 const char *const opstring,
+		 const int optchar)
+{
+	size_t nlen = (opstring == 0) ? 0 : strlen(opstring);
+	size_t loptn;
+
+	for (loptn = 0; loptn < nlen; loptn++) {
+		if (optchar == opstring[loptn]) {
+			if (opstring[loptn + 1] == ':') {
+				/* Option has argument */
+				if (optind < argc) {
+					/* Found argument. */
+					assert(argv != 0);
+					optind++;
+					optarg = argv[optind++];
+					return optchar;
+				}
+				/* Missing argument. */
+				if (opstring[loptn + 2] == ':') {
+					/* OK if optional "x::". */
+					optind++;
+					return optchar;
+				}
+				/* Actual missing value. */
+				optopt = optchar;
+				return ((opstring[0] == ':')
+					? RET_NO_PARAM2
+					: RET_NO_PARAM);
+			}
+			/* No argument, just return option char */
+			optind++;
+			return optchar;
+		}
+	}
+	/*
+	 * If getopt finds an option character in argv that was not included in
+	 * options, ... it returns '?' and sets the external variable optopt to
+	 * the actual option character.
+	 */
+	optopt = optchar;
+	return RET_UNKNOWN_OPT;
+}
+
+int getopt(int argc,
+	   char *argv[],
+	   char *opstring)
+{
+	int result = RET_END_OPT_LIST;
+	size_t argn = 0;
+	size_t nlen = strlen(opstring);
+
+	getopt_init();
+	/* If we have an argument left to play with */
+	if ((argc > optind) && (argv != 0)) {
+		const char *arg = (const char *)argv[optind];
+
+		if ((arg != 0) && (arg[0] == '-'))
+			result = getopt_1char(argc, argv, opstring, arg[1]);
+	}
+
+	return result;
+}
+
+/*
+ * Match an argument value against an option name.
+ * Note that we only match over the shorter length of the pair, to allow
+ * for abbreviation or say --match=value
+ * Long option names may be abbreviated if the abbreviation is unique or an
+ * exact match for some defined option.
+ * A long option may take a parameter, of the form --opt=param or --opt param.
+*/
+static
+int optmatch(const char *argval, const char *optname)
+{
+	int result = 0;
+
+	while ((result == 0) && (*optname != 0) && (*argval != 0))
+		result = (*argval++) - (*optname++);
+	return result;
+}
+
+/* Handling for a single long option. */
+static
+int getopt_1long(const int argc,
+		 char *const argv[],
+		 const struct option *const longopts,
+		 const char *const optname,
+		 int *const indexptr)
+{
+	int result = RET_UNKNOWN_OPT;
+	size_t loptn = 0;
+
+	while (longopts[loptn].name != 0) {
+		if (optmatch(optname, longopts[loptn].name) == 0) {
+			/* We found a match. */
+			result = longopts[loptn].val;
+			if (indexptr != 0)
+				*indexptr = loptn;
+			switch (longopts[loptn].has_arg) {
+			case required_argument:
+				if ((optind + 1) >= argc) {
+					/* Missing argument. */
+					optopt = result;
+					return RET_NO_PARAM;
+				}
+				/* Fallthrough to get option value. */
+
+			case optional_argument:
+				if ((argc - optind) > 0) {
+					/* Found argument. */
+					optarg = argv[++optind];
+				}
+				/* Fallthrough to handle flag. */
+
+			case no_argument:
+				optind++;
+				if (longopts[loptn].flag != 0) {
+					*longopts[loptn].flag = result;
+					result = 0;
+				}
+				break;
+
+			}
+			return result;
+		}
+		++loptn;
+	}
+	/*
+	 * If getopt finds an option character in argv that was not included
+	 * in options, ... it returns '?' and sets the external variable
+	 * optopt to the actual option character.
+	 */
+	return RET_UNKNOWN_OPT;
+}
+
+/*
+ * getopt_long gets the next option argument from the argument list
+ * specified by the argv and argc arguments.  Options may be either short
+ * (single letter) as for getopt, or longer names (preceded by --).
+ */
+int getopt_long(int argc,
+		char *argv[],
+		const char *shortopts,
+		const struct option *longopts,
+		int *indexptr)
+{
+	int result = RET_END_OPT_LIST;
+
+	getopt_init();
+	/* If we have an argument left to play with */
+	if ((argc > optind) && (argv != 0)) {
+		const char *arg = argv[optind];
+
+		if ((arg != 0) && (arg[0] == '-')) {
+			if (arg[1] == '-') {
+				/* Looks like a long option. */
+				result = getopt_1long(argc,
+						      argv,
+						      longopts,
+						      &arg[2],
+						      indexptr);
+			} else {
+				result = getopt_1char(argc,
+						      argv,
+						      shortopts,
+						      arg[1]);
+			}
+		}
+	}
+	return result;
+}
+
+/*
+ * getopt_long_only gets the next option argument from the argument list
+ * specified by the argv and argc arguments.  Options may be either short
+ * or long as for getopt_long, but the long names may have a single '-'
+ * prefix too.
+ */
+int getopt_long_only(int argc,
+		     char *argv[],
+		     const char *shortopts,
+		     const struct option *longopts,
+		     int *indexptr)
+{
+	int result = RET_END_OPT_LIST;
+
+	getopt_init();
+	/* If we have an argument left to play with */
+	if ((argc > optind) && (argv != 0)) {
+		const char *arg = argv[optind];
+
+		if ((arg != 0) && (arg[0] == '-')) {
+			if (arg[1] == '-') {
+				/* Looks like a long option. */
+				result = getopt_1long(argc,
+						      argv,
+						      longopts,
+						      &arg[2],
+						      indexptr);
+			} else {
+				result = getopt_1long(argc,
+						      argv,
+						      longopts,
+						      &arg[1],
+						      indexptr);
+				if (result == RET_UNKNOWN_OPT) {
+					result = getopt_1char(argc,
+							      argv,
+							      shortopts,
+							      arg[1]);
+				}
+			}
+		}
+	}
+	return result;
+}
diff --git a/tools/fiptool/win_posix.h b/tools/fiptool/win_posix.h
new file mode 100644
index 0000000..836ffed
--- /dev/null
+++ b/tools/fiptool/win_posix.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef WIN_POSIX_H
+#define WIN_POSIX_H
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <direct.h>
+#include <io.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "uuid.h"
+
+/* Derive or provide Windows equivalents of Posix/GCC/Unix stuff. */
+#ifndef PATH_MAX
+# ifdef MAX_PATH
+#  define PATH_MAX MAX_PATH
+# else
+#  ifdef _MAX_PATH
+#   define MAX_PATH _MAX_PATH
+#   define PATH_MAX _MAX_PATH
+#  else
+#   define PATH_MAX 260
+#  endif
+# endif
+#endif
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+/*
+ * Platform specific names.
+ *
+ * Visual Studio deprecates a number of POSIX functions and only provides
+ * ISO C++ compliant alternatives (distinguished by their '_' prefix).
+ * These macros help provide a stopgap for that.
+ */
+
+/* fileno cannot be an inline function, because _fileno is a macro. */
+#define fileno(fileptr) _fileno(fileptr)
+
+/* _fstat uses the _stat structure, not stat. */
+#define BLD_PLAT_STAT	_stat
+
+/* Define flag values for _access. */
+#define F_OK	0
+
+
+/* getopt implementation for Windows: Data. */
+
+/* Legitimate values for option.has_arg. */
+enum has_arg_values {
+	no_argument,		/* No argument value required */
+	required_argument,	/* value must be specified. */
+	optional_argument	/* value may be specified. */
+};
+
+/* Long option table entry for get_opt_long. */
+struct option {
+	/* The name of the option. */
+	const char *name;
+
+	/*
+	 * Indicates whether the option takes an argument.
+	 * Possible values: see has_arg_values above.
+	 */
+	int has_arg;
+
+	/* If not null, when option present, *flag is set to val. */
+	int *flag;
+
+	/*
+	 * The value associated with this option to return
+	 * (and save in *flag when not null)
+	 */
+	int val;
+};
+
+/*
+ * This variable is set by getopt to point at the value of the option
+ * argument, for those options that accept arguments.
+ */
+extern char *optarg;
+
+/*
+ * When this variable is not zero, getopt emits an error message to stderr
+ * if it encounters an unspecified option, or a missing argument.
+ * Otherwise no message is reported.
+ */
+extern const int opterr;	/* const as NOT used in this implementation. */
+
+/*
+ * This variable is set by getopt to the index of the next element of the
+ * argv array to be processed. Once getopt has found all of the option
+ * arguments, you can use this variable to determine where the remaining
+ * non-option arguments begin. The initial value of this variable is 1.
+ */
+extern int optind;
+
+/*
+ * When getopt encounters an unknown option character or an option with a
+ * missing required argument, it stores that option character in this
+ * variable.
+ */
+extern int optopt;
+
+
+/*
+ * Platform specific names.
+ *
+ * Visual Studio deprecates a number of POSIX functions and only provides
+ * ISO C++ compliant alternatives (distinguished by their '_' prefix).
+ * These inline functions provide a stopgap for that.
+ */
+
+inline int access(const char *path, int mode)
+{
+	return _access(path, mode);
+}
+
+inline int chdir(const char *s)
+{
+	return _chdir(s);
+}
+
+inline int fstat(int fd, struct _stat *buffer)
+{
+	return _fstat(fd, buffer);
+}
+
+inline char *strdup(const char *s)
+{
+	return _strdup(s);
+}
+
+/*
+ * getopt implementation for Windows: Functions.
+ *
+ * Windows does not have the getopt family of functions, as it normally
+ * uses '/' instead of '-' as the command line option delimiter.
+ * These functions provide a Windows version that  uses '-', which precludes
+ * using '-' as the intial letter of a program argument.
+ * This is not seen as a problem in the specific instance of fiptool,
+ * and enables existing makefiles to work on a Windows build environment.
+ */
+
+/*
+ * The getopt function gets the next option argument from the argument list
+ * specified by the argv and argc arguments.
+ */
+int getopt(int argc,
+	   char *argv[],
+	   char *options);
+
+/*
+ * getopt_long gets the next option argument from the argument list
+ * specified by the argv and argc arguments.  Options may be either short
+ * (single letter) as for getopt, or longer names (preceded by --).
+ */
+int getopt_long(int argc,
+		char *argv[],
+		const char *shortopts,
+		const struct option *longopts,
+		int *indexptr);
+
+/*
+ * getopt_long_only gets the next option argument from the argument list
+ * specified by the argv and argc arguments.  Options may be either short
+ * or long as for getopt_long, but the long names may have a single '-'
+ * prefix, too.
+ */
+int getopt_long_only(int argc,
+			   char *argv[],
+			   const char *shortopts,
+			   const struct option *longopts,
+			   int *indexptr);
+
+#endif /* WIN_POSIX_H */
diff --git a/tools/marvell/doimage/Makefile b/tools/marvell/doimage/Makefile
new file mode 100644
index 0000000..9f0d89d
--- /dev/null
+++ b/tools/marvell/doimage/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+PROJECT = doimage
+OBJECTS = doimage.o
+
+HOSTCCFLAGS = -Wall -Werror
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG
+else
+  HOSTCCFLAGS += -O2
+endif
+
+ifeq (${MARVELL_SECURE_BOOT},1)
+DOIMAGE_CC_FLAGS := -DCONFIG_MVEBU_SECURE_BOOT
+DOIMAGE_LD_FLAGS := -lconfig -lmbedtls -lmbedcrypto -lmbedx509
+endif
+
+HOSTCCFLAGS += ${DOIMAGE_CC_FLAGS}
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INCLUDE_PATHS = -I.
+
+HOSTCC ?= gcc
+RM := rm -rf
+
+.PHONY: all clean
+
+all: ${PROJECT}
+
+${PROJECT}: ${OBJECTS} Makefile
+	@echo "  HOSTLD  $@"
+	${Q}${HOSTCC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@
+	@echo
+	@echo "Built $@ successfully"
+	@echo
+
+%.o: %.c Makefile
+	@echo "  HOSTCC  $<"
+	${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
+
+clean:
+	${Q}${RM} ${PROJECT}
+	${Q}${RM} ${OBJECTS}
diff --git a/tools/marvell/doimage/doimage.c b/tools/marvell/doimage/doimage.c
new file mode 100644
index 0000000..82fd375
--- /dev/null
+++ b/tools/marvell/doimage/doimage.c
@@ -0,0 +1,1762 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+#include <libconfig.h>	/* for parsing config file */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+/* mbedTLS stuff */
+#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ENTROPY_C) && \
+	defined(MBEDTLS_SHA256_C) && \
+	defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_FS_IO) && \
+	defined(MBEDTLS_CTR_DRBG_C)
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/md.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/x509.h>
+#else
+#error "Bad mbedTLS configuration!"
+#endif
+#endif /* CONFIG_MVEBU_SECURE_BOOT */
+
+#define MAX_FILENAME		256
+#define CSK_ARR_SZ		16
+#define CSK_ARR_EMPTY_FILE	"*"
+#define AES_KEY_BIT_LEN		256
+#define AES_KEY_BYTE_LEN	(AES_KEY_BIT_LEN >> 3)
+#define AES_BLOCK_SZ		16
+#define RSA_SIGN_BYTE_LEN	256
+#define MAX_RSA_DER_BYTE_LEN	524
+/* Number of address pairs in control array */
+#define CP_CTRL_EL_ARRAY_SZ	32
+
+#define VERSION_STRING		"Marvell(C) doimage utility version 3.2"
+
+/* A8K definitions */
+
+/* Extension header types */
+#define EXT_TYPE_SECURITY	0x1
+#define EXT_TYPE_BINARY		0x2
+
+#define MAIN_HDR_MAGIC		0xB105B002
+
+/* PROLOG alignment considerations:
+ *  128B: To allow supporting XMODEM protocol.
+ *  8KB: To align the boot image to the largest NAND page size, and simplify
+ *  the read operations from NAND.
+ *  We choose the largest page size, in order to use a single image for all
+ *  NAND page sizes.
+ */
+#define PROLOG_ALIGNMENT	(8 << 10)
+
+/* UART argument bitfield */
+#define UART_MODE_UNMODIFIED	0x0
+#define UART_MODE_DISABLE	0x1
+#define UART_MODE_UPDATE	0x2
+
+typedef struct _main_header {
+	uint32_t	magic;			/*  0-3  */
+	uint32_t	prolog_size;		/*  4-7  */
+	uint32_t	prolog_checksum;	/*  8-11 */
+	uint32_t	boot_image_size;	/* 12-15 */
+	uint32_t	boot_image_checksum;	/* 16-19 */
+	uint32_t	rsrvd0;			/* 20-23 */
+	uint32_t	load_addr;		/* 24-27 */
+	uint32_t	exec_addr;		/* 28-31 */
+	uint8_t		uart_cfg;		/*  32   */
+	uint8_t		baudrate;		/*  33   */
+	uint8_t		ext_count;		/*  34   */
+	uint8_t		aux_flags;		/*  35   */
+	uint32_t	io_arg_0;		/* 36-39 */
+	uint32_t	io_arg_1;		/* 40-43 */
+	uint32_t	io_arg_2;		/* 43-47 */
+	uint32_t	io_arg_3;		/* 48-51 */
+	uint32_t	rsrvd1;			/* 52-55 */
+	uint32_t	rsrvd2;			/* 56-59 */
+	uint32_t	rsrvd3;			/* 60-63 */
+} header_t;
+
+typedef struct _ext_header {
+	uint8_t		type;
+	uint8_t		offset;
+	uint16_t	reserved;
+	uint32_t	size;
+} ext_header_t;
+
+typedef struct _sec_entry {
+	uint8_t		kak_key[MAX_RSA_DER_BYTE_LEN];
+	uint32_t	jtag_delay;
+	uint32_t	box_id;
+	uint32_t	flash_id;
+	uint32_t	jtag_en;
+	uint32_t	encrypt_en;
+	uint32_t	efuse_dis;
+	uint8_t		header_sign[RSA_SIGN_BYTE_LEN];
+	uint8_t		image_sign[RSA_SIGN_BYTE_LEN];
+	uint8_t		csk_keys[CSK_ARR_SZ][MAX_RSA_DER_BYTE_LEN];
+	uint8_t		csk_sign[RSA_SIGN_BYTE_LEN];
+	uint32_t	cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ];
+	uint32_t	cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ];
+} sec_entry_t;
+
+/* A8K definitions end */
+
+/* UART argument bitfield */
+#define UART_MODE_UNMODIFIED	0x0
+#define UART_MODE_DISABLE	0x1
+#define UART_MODE_UPDATE	0x2
+
+#define uart_set_mode(arg, mode)	(arg |= (mode & 0x3))
+
+typedef struct _sec_options {
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	char aes_key_file[MAX_FILENAME+1];
+	char kak_key_file[MAX_FILENAME+1];
+	char csk_key_file[CSK_ARR_SZ][MAX_FILENAME+1];
+	uint32_t	box_id;
+	uint32_t	flash_id;
+	uint32_t	jtag_delay;
+	uint8_t		csk_index;
+	uint8_t		jtag_enable;
+	uint8_t		efuse_disable;
+	uint32_t	cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ];
+	uint32_t	cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ];
+	mbedtls_pk_context	kak_pk;
+	mbedtls_pk_context	csk_pk[CSK_ARR_SZ];
+	uint8_t		aes_key[AES_KEY_BYTE_LEN];
+	uint8_t		*encrypted_image;
+	uint32_t	enc_image_sz;
+#endif
+} sec_options;
+
+typedef struct _options {
+	char bin_ext_file[MAX_FILENAME+1];
+	char sec_cfg_file[MAX_FILENAME+1];
+	sec_options *sec_opts;
+	uint32_t  load_addr;
+	uint32_t  exec_addr;
+	uint32_t  baudrate;
+	uint8_t	  disable_print;
+	int8_t    key_index; /* For header signatures verification only */
+	uint32_t  nfc_io_args;
+} options_t;
+
+void usage_err(char *msg)
+{
+	fprintf(stderr, "Error: %s\n", msg);
+	fprintf(stderr, "run 'doimage -h' to get usage information\n");
+	exit(-1);
+}
+
+void usage(void)
+{
+	printf("\n\n%s\n\n", VERSION_STRING);
+	printf("Usage: doimage [options] <input_file> [output_file]\n");
+	printf("create bootrom image from u-boot and boot extensions\n\n");
+
+	printf("Arguments\n");
+	printf("  input_file   name of boot image file.\n");
+	printf("               if -p is used, name of the bootrom image file");
+	printf("               to parse.\n");
+	printf("  output_file  name of output bootrom image file\n");
+
+	printf("\nOptions\n");
+	printf("  -s        target SOC name. supports a8020,a7020\n");
+	printf("            different SOCs may have different boot image\n");
+	printf("            format so it's mandatory to know the target SOC\n");
+	printf("  -i        boot I/F name. supports nand, spi, nor\n");
+	printf("            This affects certain parameters coded in the\n");
+	printf("            image header\n");
+	printf("  -l        boot image load address. default is 0x0\n");
+	printf("  -e        boot image entry address. default is 0x0\n");
+	printf("  -b        binary extension image file.\n");
+	printf("            This image is executed before the boot image.\n");
+	printf("            This is typically used to initialize the memory ");
+	printf("            controller.\n");
+	printf("            Currently supports only a single file.\n");
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	printf("  -c        Make trusted boot image using parameters\n");
+	printf("            from the configuration file.\n");
+#endif
+	printf("  -p        Parse and display a pre-built boot image\n");
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	printf("  -k        Key index for RSA signatures verification\n");
+	printf("            when parsing the boot image\n");
+#endif
+	printf("  -m        Disable prints of bootrom and binary extension\n");
+	printf("  -u        UART baudrate used for bootrom prints.\n");
+	printf("            Must be multiple of 1200\n");
+	printf("  -h        Show this help message\n");
+	printf(" IO-ROM NFC-NAND boot parameters:\n");
+	printf("  -n        NAND device block size in KB [Default is 64KB].\n");
+	printf("  -t        NAND cell technology (SLC [Default] or MLC)\n");
+
+	exit(-1);
+}
+
+/* globals */
+static options_t opts = {
+	.bin_ext_file = "NA",
+	.sec_cfg_file = "NA",
+	.sec_opts = 0,
+	.load_addr = 0x0,
+	.exec_addr = 0x0,
+	.disable_print = 0,
+	.baudrate = 0,
+	.key_index = -1,
+};
+
+int get_file_size(char *filename)
+{
+	struct stat st;
+
+	if (stat(filename, &st) == 0)
+		return st.st_size;
+
+	return -1;
+}
+
+uint32_t checksum32(uint32_t *start, int len)
+{
+	uint32_t sum = 0;
+	uint32_t *startp = start;
+
+	do {
+		sum += *startp;
+		startp++;
+		len -= 4;
+	} while (len > 0);
+
+	return sum;
+}
+
+/*******************************************************************************
+ *    create_rsa_signature (memory buffer content)
+ *          Create RSASSA-PSS/SHA-256 signature for memory buffer
+ *          using RSA Private Key
+ *    INPUT:
+ *          pk_ctx     Private Key context
+ *          input      memory buffer
+ *          ilen       buffer length
+ *          pers       personalization string for seeding the RNG.
+ *                     For instance a private key file name.
+ *    OUTPUT:
+ *          signature  RSA-2048 signature
+ *    RETURN:
+ *          0 on success
+ */
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+int create_rsa_signature(mbedtls_pk_context	*pk_ctx,
+			 const unsigned char	*input,
+			 size_t			ilen,
+			 const char		*pers,
+			 uint8_t		*signature)
+{
+	mbedtls_entropy_context		entropy;
+	mbedtls_ctr_drbg_context	ctr_drbg;
+	unsigned char			hash[32];
+	unsigned char			buf[MBEDTLS_MPI_MAX_SIZE];
+	int				rval;
+
+	/* Not sure this is required,
+	 * but it's safer to start with empty buffers
+	 */
+	memset(hash, 0, sizeof(hash));
+	memset(buf, 0, sizeof(buf));
+
+	mbedtls_ctr_drbg_init(&ctr_drbg);
+	mbedtls_entropy_init(&entropy);
+
+	/* Seed the random number generator */
+	rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+				(const unsigned char *)pers, strlen(pers));
+	if (rval != 0) {
+		fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval);
+		goto sign_exit;
+	}
+
+	/* The PK context should be already initialized.
+	 * Set the padding type for this PK context
+	 */
+	mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk_ctx),
+				MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
+
+	/* First compute the SHA256 hash for the input blob */
+	mbedtls_sha256(input, ilen, hash, 0);
+
+	/* Then calculate the hash signature */
+	rval = mbedtls_rsa_rsassa_pss_sign(mbedtls_pk_rsa(*pk_ctx),
+					   mbedtls_ctr_drbg_random,
+					   &ctr_drbg,
+					   MBEDTLS_RSA_PRIVATE,
+					   MBEDTLS_MD_SHA256, 0, hash, buf);
+	if (rval != 0) {
+		fprintf(stderr,
+			"Failed to create RSA signature for %s. Error %d\n",
+			pers, rval);
+		goto sign_exit;
+	}
+	memcpy(signature, buf, 256);
+
+sign_exit:
+	mbedtls_ctr_drbg_free(&ctr_drbg);
+	mbedtls_entropy_free(&entropy);
+
+	return rval;
+} /* end of create_rsa_signature */
+
+/*******************************************************************************
+ *    verify_rsa_signature (memory buffer content)
+ *          Verify RSASSA-PSS/SHA-256 signature for memory buffer
+ *          using RSA Public Key
+ *    INPUT:
+ *          pub_key    Public Key buffer
+ *          ilen       Public Key buffer length
+ *          input      memory buffer
+ *          ilen       buffer length
+ *          pers       personalization string for seeding the RNG.
+ *          signature  RSA-2048 signature
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int verify_rsa_signature(const unsigned char	*pub_key,
+			 size_t			klen,
+			 const unsigned char	*input,
+			 size_t			ilen,
+			 const char		*pers,
+			 uint8_t		*signature)
+{
+	mbedtls_entropy_context		entropy;
+	mbedtls_ctr_drbg_context	ctr_drbg;
+	mbedtls_pk_context		pk_ctx;
+	unsigned char			hash[32];
+	int				rval;
+
+	/* Not sure this is required,
+	 * but it's safer to start with empty buffer
+	 */
+	memset(hash, 0, sizeof(hash));
+
+	mbedtls_pk_init(&pk_ctx);
+	mbedtls_ctr_drbg_init(&ctr_drbg);
+	mbedtls_entropy_init(&entropy);
+
+	/* Seed the random number generator */
+	rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+				(const unsigned char *)pers, strlen(pers));
+	if (rval != 0) {
+		fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval);
+		goto verify_exit;
+	}
+
+	/* Check ability to read the public key */
+	rval = mbedtls_pk_parse_public_key(&pk_ctx, pub_key,
+					   MAX_RSA_DER_BYTE_LEN);
+	if (rval != 0) {
+		fprintf(stderr, " Failed in pk_parse_public_key (%#x)!\n",
+			rval);
+		goto verify_exit;
+	}
+
+	/* Set the padding type for the new PK context */
+	mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk_ctx),
+				MBEDTLS_RSA_PKCS_V21,
+				MBEDTLS_MD_SHA256);
+
+	/* Compute the SHA256 hash for the input buffer */
+	mbedtls_sha256(input, ilen, hash, 0);
+
+	rval = mbedtls_rsa_rsassa_pss_verify(mbedtls_pk_rsa(pk_ctx),
+					     mbedtls_ctr_drbg_random,
+					     &ctr_drbg,
+					     MBEDTLS_RSA_PUBLIC,
+					     MBEDTLS_MD_SHA256, 0,
+					     hash, signature);
+	if (rval != 0)
+		fprintf(stderr, "Failed to verify signature (%d)!\n", rval);
+
+verify_exit:
+
+	mbedtls_pk_free(&pk_ctx);
+	mbedtls_ctr_drbg_free(&ctr_drbg);
+	mbedtls_entropy_free(&entropy);
+	return rval;
+} /* end of verify_rsa_signature */
+
+/*******************************************************************************
+ *    image_encrypt
+ *           Encrypt image buffer using AES-256-CBC scheme.
+ *           The resulting image is saved into opts.sec_opts->encrypted_image
+ *           and the adjusted image size into opts.sec_opts->enc_image_sz
+ *           First AES_BLOCK_SZ bytes of the output image contain IV
+ *    INPUT:
+ *          buf        Source buffer to encrypt
+ *          blen       Source buffer length
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int image_encrypt(uint8_t *buf, uint32_t blen)
+{
+	struct timeval		tv;
+	char			*ptmp = (char *)&tv;
+	unsigned char		digest[32];
+	unsigned char		IV[AES_BLOCK_SZ];
+	int			i, k;
+	mbedtls_aes_context	aes_ctx;
+	int			rval = -1;
+	uint8_t			*test_img = 0;
+
+	if (AES_BLOCK_SZ > 32) {
+		fprintf(stderr, "Unsupported AES block size %d\n",
+			AES_BLOCK_SZ);
+		return rval;
+	}
+
+	mbedtls_aes_init(&aes_ctx);
+	memset(IV, 0, AES_BLOCK_SZ);
+	memset(digest, 0, 32);
+
+	/* Generate initialization vector and init the AES engine
+	 * Use file name XOR current time and finally SHA-256
+	 * [0...AES_BLOCK_SZ-1]
+	 */
+	k = strlen(opts.sec_opts->aes_key_file);
+	if (k > AES_BLOCK_SZ)
+		k = AES_BLOCK_SZ;
+	memcpy(IV, opts.sec_opts->aes_key_file, k);
+	gettimeofday(&tv, 0);
+
+	for (i = 0, k = 0; i < AES_BLOCK_SZ; i++,
+	     k = (k+1) % sizeof(struct timeval))
+		IV[i] ^= ptmp[k];
+
+	/* compute SHA-256 digest of the results
+	 * and use it as the init vector (IV)
+	 */
+	mbedtls_sha256(IV, AES_BLOCK_SZ, digest, 0);
+	memcpy(IV, digest, AES_BLOCK_SZ);
+	mbedtls_aes_setkey_enc(&aes_ctx, opts.sec_opts->aes_key,
+			       AES_KEY_BIT_LEN);
+
+	/* The output image has to include extra space for IV
+	 * and to be aligned to the AES block size.
+	 * The input image buffer has to be already aligned to AES_BLOCK_SZ
+	 * and padded with zeroes
+	 */
+	opts.sec_opts->enc_image_sz = (blen + 2 * AES_BLOCK_SZ - 1) &
+				      ~(AES_BLOCK_SZ - 1);
+	opts.sec_opts->encrypted_image = calloc(opts.sec_opts->enc_image_sz, 1);
+	if (opts.sec_opts->encrypted_image == 0) {
+		fprintf(stderr, "Failed to allocate encrypted image!\n");
+		goto encrypt_exit;
+	}
+
+	/* Put IV into the output buffer next to the encrypted image
+	 * Since the IV is modified by the encryption function,
+	 * this should be done now
+	 */
+	memcpy(opts.sec_opts->encrypted_image +
+		   opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+		   IV, AES_BLOCK_SZ);
+	rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT,
+			     opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+			     IV, buf, opts.sec_opts->encrypted_image);
+	if (rval != 0) {
+		fprintf(stderr, "Failed to encrypt the image! Error %d\n",
+			rval);
+		goto encrypt_exit;
+	}
+
+	mbedtls_aes_free(&aes_ctx);
+
+	/* Try to decrypt the image and compare it with the original data */
+	mbedtls_aes_init(&aes_ctx);
+	mbedtls_aes_setkey_dec(&aes_ctx, opts.sec_opts->aes_key,
+			       AES_KEY_BIT_LEN);
+
+	test_img = calloc(opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, 1);
+	if (test_img == 0) {
+		fprintf(stderr, "Failed to allocate test image!d\n");
+		rval = -1;
+		goto encrypt_exit;
+	}
+
+	memcpy(IV, opts.sec_opts->encrypted_image +
+		   opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+		   AES_BLOCK_SZ);
+	rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT,
+			     opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
+			     IV, opts.sec_opts->encrypted_image, test_img);
+	if (rval != 0) {
+		fprintf(stderr, "Failed to decrypt the image! Error %d\n",
+			rval);
+		goto encrypt_exit;
+	}
+
+	for (i = 0; i < blen; i++) {
+		if (buf[i] != test_img[i]) {
+			fprintf(stderr, "Failed to compare the image after");
+			fprintf(stderr, " decryption! Byte count is %d\n", i);
+			rval = -1;
+			goto encrypt_exit;
+		}
+	}
+
+encrypt_exit:
+
+	mbedtls_aes_free(&aes_ctx);
+	if (test_img)
+		free(test_img);
+
+	return rval;
+} /* end of image_encrypt */
+
+/*******************************************************************************
+ *    verify_secure_header_signatures
+ *          Verify CSK array, header and image signatures and print results
+ *    INPUT:
+ *          main_hdr       Main header
+ *          sec_ext        Secure extension
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int verify_secure_header_signatures(header_t *main_hdr, sec_entry_t *sec_ext)
+{
+	uint8_t	*image = (uint8_t *)main_hdr + main_hdr->prolog_size;
+	uint8_t	signature[RSA_SIGN_BYTE_LEN];
+	int		rval = -1;
+
+	/* Save headers signature and reset it in the secure header */
+	memcpy(signature, sec_ext->header_sign, RSA_SIGN_BYTE_LEN);
+	memset(sec_ext->header_sign, 0, RSA_SIGN_BYTE_LEN);
+
+	fprintf(stdout, "\nCheck RSA Signatures\n");
+	fprintf(stdout, "#########################\n");
+	fprintf(stdout, "CSK Block Signature: ");
+	if (verify_rsa_signature(sec_ext->kak_key,
+				 MAX_RSA_DER_BYTE_LEN,
+				 &sec_ext->csk_keys[0][0],
+				 sizeof(sec_ext->csk_keys),
+				 "CSK Block Signature: ",
+				 sec_ext->csk_sign) != 0) {
+		fprintf(stdout, "ERROR\n");
+		goto ver_error;
+	}
+	fprintf(stdout, "OK\n");
+
+	if (opts.key_index != -1) {
+		fprintf(stdout, "Image Signature:     ");
+		if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index],
+					 MAX_RSA_DER_BYTE_LEN,
+					 image, main_hdr->boot_image_size,
+					 "Image Signature: ",
+					 sec_ext->image_sign) != 0) {
+			fprintf(stdout, "ERROR\n");
+			goto ver_error;
+		}
+		fprintf(stdout, "OK\n");
+
+		fprintf(stdout, "Header Signature:    ");
+		if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index],
+					 MAX_RSA_DER_BYTE_LEN,
+					 (uint8_t *)main_hdr,
+					 main_hdr->prolog_size,
+					 "Header Signature: ",
+					 signature) != 0) {
+			fprintf(stdout, "ERROR\n");
+			goto ver_error;
+		}
+		fprintf(stdout, "OK\n");
+	} else {
+		fprintf(stdout, "SKIP Image and Header Signatures");
+		fprintf(stdout, " check (undefined key index)\n");
+	}
+
+	rval = 0;
+
+ver_error:
+	memcpy(sec_ext->header_sign, signature, RSA_SIGN_BYTE_LEN);
+	return rval;
+}
+
+/*******************************************************************************
+ *    verify_and_copy_file_name_entry
+ *    INPUT:
+ *          element_name
+ *          element
+ *    OUTPUT:
+ *          copy_to
+ *    RETURN:
+ *          0 on success
+ */
+int verify_and_copy_file_name_entry(const char *element_name,
+				    const char *element, char *copy_to)
+{
+	int element_length = strlen(element);
+
+	if (element_length >= MAX_FILENAME) {
+		fprintf(stderr, "The file name %s for %s is too long (%d). ",
+			element, element_name, element_length);
+		fprintf(stderr, "Maximum allowed %d characters!\n",
+			MAX_FILENAME);
+		return -1;
+	} else if (element_length == 0) {
+		fprintf(stderr, "The file name for %s is empty!\n",
+			element_name);
+		return -1;
+	}
+	memcpy(copy_to, element, element_length);
+
+	return 0;
+}
+
+/*******************************************************************************
+ *    parse_sec_config_file
+ *          Read the secure boot configuration from a file
+ *          into internal structures
+ *    INPUT:
+ *          filename      File name
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int parse_sec_config_file(char *filename)
+{
+	config_t		sec_cfg;
+	int			array_sz, element, rval = -1;
+	const char		*cfg_string;
+	int32_t			cfg_int32;
+	const config_setting_t	*csk_array, *control_array;
+	sec_options		*sec_opt = 0;
+
+	config_init(&sec_cfg);
+
+	if (config_read_file(&sec_cfg, filename) != CONFIG_TRUE) {
+		fprintf(stderr, "Failed to read data from config file ");
+		fprintf(stderr, "%s\n\t%s at line %d\n",
+			filename, config_error_text(&sec_cfg),
+			config_error_line(&sec_cfg));
+		goto exit_parse;
+	}
+
+	sec_opt = (sec_options *)calloc(sizeof(sec_options), 1);
+	if (sec_opt == 0) {
+		fprintf(stderr,
+			"Cannot allocate memory for secure boot options!\n");
+		goto exit_parse;
+	}
+
+	/* KAK file name */
+	if (config_lookup_string(&sec_cfg, "kak_key_file",
+				 &cfg_string) != CONFIG_TRUE) {
+		fprintf(stderr, "The \"kak_key_file\" undefined!\n");
+		goto exit_parse;
+	}
+	if (verify_and_copy_file_name_entry("kak_key_file",
+					    cfg_string, sec_opt->kak_key_file))
+		goto exit_parse;
+
+
+	/* AES file name - can be empty/undefined */
+	if (config_lookup_string(&sec_cfg, "aes_key_file",
+				 &cfg_string) == CONFIG_TRUE) {
+		if (verify_and_copy_file_name_entry("aes_key_file",
+						    cfg_string,
+						    sec_opt->aes_key_file))
+			goto exit_parse;
+	}
+
+	/* CSK file names array */
+	csk_array = config_lookup(&sec_cfg, "csk_key_file");
+	if (csk_array == NULL) {
+		fprintf(stderr, "The \"csk_key_file\" undefined!\n");
+		goto exit_parse;
+	}
+	array_sz = config_setting_length(csk_array);
+	if (array_sz > CSK_ARR_SZ) {
+		fprintf(stderr, "The \"csk_key_file\" array is too big! ");
+		fprintf(stderr, "Only first %d elements will be used\n",
+			CSK_ARR_SZ);
+		array_sz = CSK_ARR_SZ;
+	} else if (array_sz == 0) {
+		fprintf(stderr, "The \"csk_key_file\" array is empty!\n");
+		goto exit_parse;
+	}
+
+	for (element = 0; element < array_sz; element++) {
+		cfg_string = config_setting_get_string_elem(csk_array, element);
+		if (verify_and_copy_file_name_entry(
+				"csk_key_file", cfg_string,
+				sec_opt->csk_key_file[element])) {
+			fprintf(stderr, "Bad csk_key_file[%d] entry!\n",
+				element);
+			goto exit_parse;
+		}
+	}
+
+	/* JTAG options */
+	if (config_lookup_bool(&sec_cfg, "jtag.enable",
+			       &cfg_int32) != CONFIG_TRUE) {
+		fprintf(stderr, "Error obtaining \"jtag.enable\" element. ");
+		fprintf(stderr, "Using default - FALSE\n");
+		cfg_int32 = 0;
+	}
+	sec_opt->jtag_enable = cfg_int32;
+
+	if (config_lookup_int(&sec_cfg, "jtag.delay",
+			      &cfg_int32) != CONFIG_TRUE) {
+		fprintf(stderr, "Error obtaining \"jtag.delay\" element. ");
+		fprintf(stderr, "Using default - 0us\n");
+		cfg_int32 = 0;
+	}
+	sec_opt->jtag_delay = cfg_int32;
+
+	/* eFUSE option */
+	if (config_lookup_bool(&sec_cfg, "efuse_disable",
+			       &cfg_int32) != CONFIG_TRUE) {
+		fprintf(stderr, "Error obtaining \"efuse_disable\" element. ");
+		fprintf(stderr, "Using default - TRUE\n");
+		cfg_int32 = 1;
+	}
+	sec_opt->efuse_disable = cfg_int32;
+
+	/* Box ID option */
+	if (config_lookup_int(&sec_cfg, "box_id", &cfg_int32) != CONFIG_TRUE) {
+		fprintf(stderr, "Error obtaining \"box_id\" element. ");
+		fprintf(stderr, "Using default - 0x0\n");
+		cfg_int32 = 0;
+	}
+	sec_opt->box_id = cfg_int32;
+
+	/* Flash ID option */
+	if (config_lookup_int(&sec_cfg, "flash_id",
+			      &cfg_int32) != CONFIG_TRUE) {
+		fprintf(stderr, "Error obtaining \"flash_id\" element. ");
+		fprintf(stderr, "Using default - 0x0\n");
+		cfg_int32 = 0;
+	}
+	sec_opt->flash_id = cfg_int32;
+
+	/* CSK index option */
+	if (config_lookup_int(&sec_cfg, "csk_key_index",
+			      &cfg_int32) != CONFIG_TRUE) {
+		fprintf(stderr, "Error obtaining \"flash_id\" element. ");
+		fprintf(stderr, "Using default - 0x0\n");
+		cfg_int32 = 0;
+	}
+	sec_opt->csk_index = cfg_int32;
+
+	/* Secure boot control array */
+	control_array = config_lookup(&sec_cfg, "control");
+	if (control_array != NULL) {
+		array_sz = config_setting_length(control_array);
+		if (array_sz == 0)
+			fprintf(stderr, "The \"control\" array is empty!\n");
+	} else {
+		fprintf(stderr, "The \"control\" is undefined!\n");
+		array_sz = 0;
+	}
+
+	for (element = 0; element < CP_CTRL_EL_ARRAY_SZ; element++) {
+		sec_opt->cp_ctrl_arr[element] =
+			config_setting_get_int_elem(control_array, element * 2);
+		sec_opt->cp_efuse_arr[element] =
+			config_setting_get_int_elem(control_array,
+						    element * 2 + 1);
+	}
+
+	opts.sec_opts = sec_opt;
+	rval = 0;
+
+exit_parse:
+	config_destroy(&sec_cfg);
+	if (sec_opt && (rval != 0))
+		free(sec_opt);
+	return rval;
+} /* end of parse_sec_config_file */
+
+int format_sec_ext(char *filename, FILE *out_fd)
+{
+	ext_header_t	header;
+	sec_entry_t	sec_ext;
+	int		index;
+	int		written;
+
+#define DER_BUF_SZ	1600
+
+	/* First, parse the configuration file */
+	if (parse_sec_config_file(filename)) {
+		fprintf(stderr,
+			"failed parsing configuration file %s\n", filename);
+		return 1;
+	}
+
+	/* Everything except signatures can be created at this stage */
+	header.type = EXT_TYPE_SECURITY;
+	header.offset = 0;
+	header.size = sizeof(sec_entry_t);
+	header.reserved = 0;
+
+	/* Bring up RSA context and read private keys from their files */
+	for (index = 0; index < (CSK_ARR_SZ + 1); index++) {
+		/* for every private key file */
+		mbedtls_pk_context	*pk_ctx = (index == CSK_ARR_SZ) ?
+					&opts.sec_opts->kak_pk :
+					&opts.sec_opts->csk_pk[index];
+		char		*fname = (index == CSK_ARR_SZ) ?
+					opts.sec_opts->kak_key_file :
+					opts.sec_opts->csk_key_file[index];
+		uint8_t		*out_der_key = (index == CSK_ARR_SZ) ?
+					sec_ext.kak_key :
+					sec_ext.csk_keys[index];
+		size_t		output_len;
+		unsigned char	output_buf[DER_BUF_SZ];
+		unsigned char	*der_buf_start;
+
+		/* Handle invalid/reserved file names */
+		if (strncmp(CSK_ARR_EMPTY_FILE, fname,
+			    strlen(CSK_ARR_EMPTY_FILE)) == 0) {
+			if (opts.sec_opts->csk_index == index) {
+				fprintf(stderr,
+					"CSK file with index %d cannot be %s\n",
+					index, CSK_ARR_EMPTY_FILE);
+				return 1;
+			} else if (index == CSK_ARR_SZ) {
+				fprintf(stderr, "KAK file name cannot be %s\n",
+					CSK_ARR_EMPTY_FILE);
+				return 1;
+			}
+			/* this key will be empty in CSK array */
+			continue;
+		}
+
+		mbedtls_pk_init(pk_ctx);
+		/* Read the private RSA key into the context
+		 * and verify it (no password)
+		 */
+		if (mbedtls_pk_parse_keyfile(pk_ctx, fname, "") != 0) {
+			fprintf(stderr,
+				"Cannot read RSA private key file %s\n", fname);
+			return 1;
+		}
+
+		/* Create a public key out of private one
+		 * and store it in DER format
+		 */
+		output_len = mbedtls_pk_write_pubkey_der(pk_ctx,
+							 output_buf,
+							 DER_BUF_SZ);
+		if (output_len < 0) {
+			fprintf(stderr,
+				"Failed to create DER coded PUB key (%s)\n",
+				fname);
+			return 1;
+		}
+		/* Data in the output buffer is aligned to the buffer end */
+		der_buf_start = output_buf + sizeof(output_buf) - output_len;
+		/* In the header DER data is aligned
+		 * to the start of appropriate field
+		 */
+		memcpy(out_der_key, der_buf_start, output_len);
+
+	} /* for every private key file */
+
+	/* The CSK block signature can be created here */
+	if (create_rsa_signature(&opts.sec_opts->kak_pk,
+				 &sec_ext.csk_keys[0][0],
+				 sizeof(sec_ext.csk_keys),
+				 opts.sec_opts->csk_key_file[
+					 opts.sec_opts->csk_index],
+				 sec_ext.csk_sign) != 0) {
+		fprintf(stderr, "Failed to sign CSK keys block!\n");
+		return 1;
+	}
+	/* Check that everything is correct */
+	if (verify_rsa_signature(sec_ext.kak_key, MAX_RSA_DER_BYTE_LEN,
+				 &sec_ext.csk_keys[0][0],
+				 sizeof(sec_ext.csk_keys),
+				 opts.sec_opts->kak_key_file,
+				 sec_ext.csk_sign) != 0) {
+		fprintf(stderr, "Failed to verify CSK keys block signature!\n");
+		return 1;
+	}
+
+	/* AES encryption stuff */
+	if (strlen(opts.sec_opts->aes_key_file) != 0) {
+		FILE		*in_fd;
+
+		in_fd = fopen(opts.sec_opts->aes_key_file, "rb");
+		if (in_fd == NULL) {
+			fprintf(stderr, "Failed to open AES key file %s\n",
+				opts.sec_opts->aes_key_file);
+			return 1;
+		}
+
+		/* Read the AES key in ASCII format byte by byte */
+		for (index = 0; index < AES_KEY_BYTE_LEN; index++) {
+			if (fscanf(in_fd, "%02hhx",
+			    opts.sec_opts->aes_key + index) != 1) {
+				fprintf(stderr,
+					"Failed to read AES key byte %d ",
+					index);
+				fprintf(stderr,
+					"from file %s\n",
+					opts.sec_opts->aes_key_file);
+				fclose(in_fd);
+				return 1;
+			}
+		}
+		fclose(in_fd);
+		sec_ext.encrypt_en = 1;
+	} else {
+		sec_ext.encrypt_en = 0;
+	}
+
+	/* Fill the rest of the trusted boot extension fields */
+	sec_ext.box_id		= opts.sec_opts->box_id;
+	sec_ext.flash_id	= opts.sec_opts->flash_id;
+	sec_ext.efuse_dis	= opts.sec_opts->efuse_disable;
+	sec_ext.jtag_delay	= opts.sec_opts->jtag_delay;
+	sec_ext.jtag_en		= opts.sec_opts->jtag_enable;
+
+	memcpy(sec_ext.cp_ctrl_arr,
+	       opts.sec_opts->cp_ctrl_arr,
+	       sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ);
+	memcpy(sec_ext.cp_efuse_arr,
+	       opts.sec_opts->cp_efuse_arr,
+	       sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ);
+
+	/* Write the resulting extension to file
+	 * (image and header signature fields are still empty)
+	 */
+
+	/* Write extension header */
+	written = fwrite(&header, sizeof(ext_header_t), 1, out_fd);
+	if (written != 1) {
+		fprintf(stderr,
+			"Failed to write SEC extension header to the file\n");
+		return 1;
+	}
+	/* Write extension body */
+	written = fwrite(&sec_ext, sizeof(sec_entry_t), 1, out_fd);
+	if (written != 1) {
+		fprintf(stderr,
+			"Failed to write SEC extension body to the file\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ *    finalize_secure_ext
+ *          Make final changes to secure extension - calculate image and header
+ *          signatures and encrypt the image if needed.
+ *          The main header checksum and image size fields updated accordingly
+ *    INPUT:
+ *          header       Main header
+ *          prolog_buf   the entire prolog buffer
+ *          prolog_size  prolog buffer length
+ *          image_buf    buffer containing the input binary image
+ *          image_size   image buffer size.
+ *    OUTPUT:
+ *          none
+ *    RETURN:
+ *          0 on success
+ */
+int finalize_secure_ext(header_t *header,
+			uint8_t *prolog_buf, uint32_t prolog_size,
+			uint8_t *image_buf, int image_size)
+{
+	int		cur_ext, offset;
+	uint8_t		*final_image = image_buf;
+	uint32_t	final_image_sz = image_size;
+	uint8_t		hdr_sign[RSA_SIGN_BYTE_LEN];
+	sec_entry_t	*sec_ext = 0;
+
+	/* Find the Trusted Boot Header between available extensions */
+	for (cur_ext = 0, offset = sizeof(header_t);
+	     cur_ext < header->ext_count; cur_ext++) {
+		ext_header_t *ext_hdr = (ext_header_t *)(prolog_buf + offset);
+
+		if (ext_hdr->type == EXT_TYPE_SECURITY) {
+			sec_ext = (sec_entry_t *)(prolog_buf + offset +
+				   sizeof(ext_header_t) + ext_hdr->offset);
+			break;
+		}
+
+		offset += sizeof(ext_header_t);
+		/* If offset is Zero, the extension follows its header */
+		if (ext_hdr->offset == 0)
+			offset += ext_hdr->size;
+	}
+
+	if (sec_ext == 0) {
+		fprintf(stderr, "Error: No Trusted Boot extension found!\n");
+		return -1;
+	}
+
+	if (sec_ext->encrypt_en) {
+		/* Encrypt the image if needed */
+		fprintf(stdout, "Encrypting the image...\n");
+
+		if (image_encrypt(image_buf, image_size) != 0) {
+			fprintf(stderr, "Failed to encrypt the image!\n");
+			return -1;
+		}
+
+		/* Image size and checksum should be updated after encryption.
+		 * This way the image could be verified by the BootROM
+		 * before decryption.
+		 */
+		final_image = opts.sec_opts->encrypted_image;
+		final_image_sz = opts.sec_opts->enc_image_sz;
+
+		header->boot_image_size = final_image_sz;
+		header->boot_image_checksum =
+			checksum32((uint32_t *)final_image, final_image_sz);
+	} /* AES encryption */
+
+	/* Create the image signature first, since it will be later
+	 * signed along with the header signature
+	 */
+	if (create_rsa_signature(&opts.sec_opts->csk_pk[
+					opts.sec_opts->csk_index],
+				 final_image, final_image_sz,
+				 opts.sec_opts->csk_key_file[
+					opts.sec_opts->csk_index],
+				 sec_ext->image_sign) != 0) {
+		fprintf(stderr, "Failed to sign image!\n");
+		return -1;
+	}
+	/* Check that the image signature is correct */
+	if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index],
+				 MAX_RSA_DER_BYTE_LEN,
+				 final_image, final_image_sz,
+				 opts.sec_opts->csk_key_file[
+					 opts.sec_opts->csk_index],
+				 sec_ext->image_sign) != 0) {
+		fprintf(stderr, "Failed to verify image signature!\n");
+		return -1;
+	}
+
+	/* Sign the headers and all the extensions block
+	 * when the header signature field is empty
+	 */
+	if (create_rsa_signature(&opts.sec_opts->csk_pk[
+					 opts.sec_opts->csk_index],
+				 prolog_buf, prolog_size,
+				 opts.sec_opts->csk_key_file[
+					 opts.sec_opts->csk_index],
+				 hdr_sign) != 0) {
+		fprintf(stderr, "Failed to sign header!\n");
+		return -1;
+	}
+	/* Check that the header signature is correct */
+	if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index],
+				 MAX_RSA_DER_BYTE_LEN,
+				 prolog_buf, prolog_size,
+				 opts.sec_opts->csk_key_file[
+					 opts.sec_opts->csk_index],
+				 hdr_sign) != 0) {
+		fprintf(stderr, "Failed to verify header signature!\n");
+		return -1;
+	}
+
+	/* Finally, copy the header signature into the trusted boot extension */
+	memcpy(sec_ext->header_sign, hdr_sign, RSA_SIGN_BYTE_LEN);
+
+	return 0;
+}
+
+#endif /* CONFIG_MVEBU_SECURE_BOOT */
+
+
+#define FMT_HEX		0
+#define FMT_DEC		1
+#define FMT_BIN		2
+#define FMT_NONE	3
+
+void do_print_field(unsigned int value, char *name,
+		    int start, int size, int format)
+{
+	fprintf(stdout, "[0x%05x : 0x%05x]  %-26s",
+		start, start + size - 1, name);
+
+	switch (format) {
+	case FMT_HEX:
+		printf("0x%x\n", value);
+		break;
+	case FMT_DEC:
+		printf("%d\n", value);
+		break;
+	default:
+		printf("\n");
+		break;
+	}
+}
+
+#define print_field(st, type, field, hex, base) \
+			do_print_field((int)st->field, #field, \
+			base + offsetof(type, field), sizeof(st->field), hex)
+
+int print_header(uint8_t *buf, int base)
+{
+	header_t *main_hdr;
+
+	main_hdr = (header_t *)buf;
+
+	fprintf(stdout, "########### Header ##############\n");
+	print_field(main_hdr, header_t, magic, FMT_HEX, base);
+	print_field(main_hdr, header_t, prolog_size, FMT_DEC, base);
+	print_field(main_hdr, header_t, prolog_checksum, FMT_HEX, base);
+	print_field(main_hdr, header_t, boot_image_size, FMT_DEC, base);
+	print_field(main_hdr, header_t, boot_image_checksum, FMT_HEX, base);
+	print_field(main_hdr, header_t, rsrvd0, FMT_HEX, base);
+	print_field(main_hdr, header_t, load_addr, FMT_HEX, base);
+	print_field(main_hdr, header_t, exec_addr, FMT_HEX, base);
+	print_field(main_hdr, header_t, uart_cfg, FMT_HEX, base);
+	print_field(main_hdr, header_t, baudrate, FMT_HEX, base);
+	print_field(main_hdr, header_t, ext_count, FMT_DEC, base);
+	print_field(main_hdr, header_t, aux_flags, FMT_HEX, base);
+	print_field(main_hdr, header_t, io_arg_0, FMT_HEX, base);
+	print_field(main_hdr, header_t, io_arg_1, FMT_HEX, base);
+	print_field(main_hdr, header_t, io_arg_2, FMT_HEX, base);
+	print_field(main_hdr, header_t, io_arg_3, FMT_HEX, base);
+	print_field(main_hdr, header_t, rsrvd1, FMT_HEX, base);
+	print_field(main_hdr, header_t, rsrvd2, FMT_HEX, base);
+	print_field(main_hdr, header_t, rsrvd3, FMT_HEX, base);
+
+	return sizeof(header_t);
+}
+
+int print_ext_hdr(ext_header_t *ext_hdr, int base)
+{
+	print_field(ext_hdr, ext_header_t, type, FMT_HEX, base);
+	print_field(ext_hdr, ext_header_t, offset, FMT_HEX, base);
+	print_field(ext_hdr, ext_header_t, reserved, FMT_HEX, base);
+	print_field(ext_hdr, ext_header_t, size, FMT_DEC, base);
+
+	return base + sizeof(ext_header_t);
+}
+
+void print_sec_ext(ext_header_t *ext_hdr, int base)
+{
+	sec_entry_t	*sec_entry;
+	uint32_t	new_base;
+
+	fprintf(stdout, "\n########### Secure extension ###########\n");
+
+	new_base = print_ext_hdr(ext_hdr, base);
+
+	sec_entry = (sec_entry_t *)(ext_hdr + 1);
+
+	do_print_field(0, "KAK key", new_base, MAX_RSA_DER_BYTE_LEN, FMT_NONE);
+	new_base += MAX_RSA_DER_BYTE_LEN;
+	print_field(sec_entry, sec_entry_t, jtag_delay, FMT_DEC, base);
+	print_field(sec_entry, sec_entry_t, box_id, FMT_HEX, base);
+	print_field(sec_entry, sec_entry_t, flash_id, FMT_HEX, base);
+	print_field(sec_entry, sec_entry_t, encrypt_en, FMT_DEC, base);
+	print_field(sec_entry, sec_entry_t, efuse_dis, FMT_DEC, base);
+	new_base += 6 * sizeof(uint32_t);
+	do_print_field(0, "header signature",
+		       new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
+	new_base += RSA_SIGN_BYTE_LEN;
+	do_print_field(0, "image signature",
+		       new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
+	new_base += RSA_SIGN_BYTE_LEN;
+	do_print_field(0, "CSK keys", new_base,
+		       CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN, FMT_NONE);
+	new_base += CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN;
+	do_print_field(0, "CSK block signature",
+		       new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
+	new_base += RSA_SIGN_BYTE_LEN;
+	do_print_field(0, "control", new_base,
+		       CP_CTRL_EL_ARRAY_SZ * 2, FMT_NONE);
+
+}
+
+void print_bin_ext(ext_header_t *ext_hdr, int base)
+{
+	fprintf(stdout, "\n########### Binary extension ###########\n");
+	base = print_ext_hdr(ext_hdr, base);
+	do_print_field(0, "binary image", base, ext_hdr->size, FMT_NONE);
+}
+
+int print_extension(void *buf, int base, int count, int ext_size)
+{
+	ext_header_t *ext_hdr = buf;
+	int pad = ext_size;
+	int curr_size;
+
+	while (count--) {
+		if (ext_hdr->type == EXT_TYPE_BINARY)
+			print_bin_ext(ext_hdr, base);
+		else if (ext_hdr->type == EXT_TYPE_SECURITY)
+			print_sec_ext(ext_hdr, base);
+
+		curr_size = sizeof(ext_header_t) + ext_hdr->size;
+		base += curr_size;
+		pad  -= curr_size;
+		ext_hdr = (ext_header_t *)((uintptr_t)ext_hdr + curr_size);
+	}
+
+	if (pad)
+		do_print_field(0, "padding", base, pad, FMT_NONE);
+
+	return ext_size;
+}
+
+int parse_image(uint8_t *buf, int size)
+{
+	int base = 0;
+	int ret = 1;
+	header_t *main_hdr;
+	uint32_t checksum, prolog_checksum;
+
+
+	fprintf(stdout,
+		"################### Prolog Start ######################\n\n");
+	main_hdr = (header_t *)buf;
+	base += print_header(buf, base);
+
+	if (main_hdr->ext_count)
+		base += print_extension(buf + base, base,
+					main_hdr->ext_count,
+					main_hdr->prolog_size -
+					sizeof(header_t));
+
+	if (base < main_hdr->prolog_size) {
+		fprintf(stdout, "\n########### Padding ##############\n");
+		do_print_field(0, "prolog padding",
+			       base, main_hdr->prolog_size - base, FMT_HEX);
+		base = main_hdr->prolog_size;
+	}
+	fprintf(stdout,
+		"\n################### Prolog End ######################\n");
+
+	fprintf(stdout,
+		"\n################### Boot image ######################\n");
+
+	do_print_field(0, "boot image", base, size - base - 4, FMT_NONE);
+
+	fprintf(stdout,
+		"################### Image end ########################\n");
+
+	/* Check sanity for certain values */
+	printf("\nChecking values:\n");
+
+	if (main_hdr->magic == MAIN_HDR_MAGIC) {
+		fprintf(stdout, "Headers magic:    OK!\n");
+	} else {
+		fprintf(stderr,
+			"\n****** ERROR: HEADER MAGIC 0x%08x != 0x%08x\n",
+			main_hdr->magic, MAIN_HDR_MAGIC);
+		goto error;
+	}
+
+	/* headers checksum */
+	/* clear the checksum field in header to calculate checksum */
+	prolog_checksum = main_hdr->prolog_checksum;
+	main_hdr->prolog_checksum = 0;
+	checksum = checksum32((uint32_t *)buf, main_hdr->prolog_size);
+
+	if (checksum == prolog_checksum) {
+		fprintf(stdout, "Headers checksum: OK!\n");
+	} else {
+		fprintf(stderr,
+			"\n***** ERROR: BAD HEADER CHECKSUM 0x%08x != 0x%08x\n",
+			checksum, prolog_checksum);
+		goto error;
+	}
+
+	/* boot image checksum */
+	checksum = checksum32((uint32_t *)(buf + main_hdr->prolog_size),
+			      main_hdr->boot_image_size);
+	if (checksum == main_hdr->boot_image_checksum) {
+		fprintf(stdout, "Image checksum:   OK!\n");
+	} else {
+		fprintf(stderr,
+			"\n****** ERROR: BAD IMAGE CHECKSUM 0x%08x != 0x%08x\n",
+			checksum, main_hdr->boot_image_checksum);
+		goto error;
+	}
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	/* RSA signatures */
+	if (main_hdr->ext_count) {
+		uint8_t		ext_num = main_hdr->ext_count;
+		ext_header_t	*ext_hdr = (ext_header_t *)(main_hdr + 1);
+		unsigned char	hash[32];
+		int		i;
+
+		while (ext_num--) {
+			if (ext_hdr->type == EXT_TYPE_SECURITY) {
+				sec_entry_t  *sec_entry =
+						(sec_entry_t *)(ext_hdr + 1);
+
+				ret = verify_secure_header_signatures(
+							main_hdr, sec_entry);
+				if (ret != 0) {
+					fprintf(stderr,
+						"\n****** FAILED TO VERIFY ");
+					fprintf(stderr,
+						"RSA SIGNATURES ********\n");
+					goto error;
+				}
+
+				mbedtls_sha256(sec_entry->kak_key,
+					       MAX_RSA_DER_BYTE_LEN, hash, 0);
+				fprintf(stdout,
+					">>>>>>>>>> KAK KEY HASH >>>>>>>>>>\n");
+				fprintf(stdout, "SHA256: ");
+				for (i = 0; i < 32; i++)
+					fprintf(stdout, "%02X", hash[i]);
+
+				fprintf(stdout,
+					"\n<<<<<<<<< KAK KEY HASH <<<<<<<<<\n");
+
+				break;
+			}
+			ext_hdr =
+				(ext_header_t *)((uint8_t *)(ext_hdr + 1) +
+				 ext_hdr->size);
+		}
+	}
+#endif
+
+	ret = 0;
+error:
+	return ret;
+}
+
+int format_bin_ext(char *filename, FILE *out_fd)
+{
+	ext_header_t header;
+	FILE *in_fd;
+	int size, written;
+	int aligned_size, pad_bytes;
+	char c;
+
+	in_fd = fopen(filename, "rb");
+	if (in_fd == NULL) {
+		fprintf(stderr, "failed to open bin extension file %s\n",
+			filename);
+		return 1;
+	}
+
+	size = get_file_size(filename);
+	if (size <= 0) {
+		fprintf(stderr, "bin extension file size is bad\n");
+		return 1;
+	}
+
+	/* Align extension size to 8 bytes */
+	aligned_size = (size + 7) & (~7);
+	pad_bytes    = aligned_size - size;
+
+	header.type = EXT_TYPE_BINARY;
+	header.offset = 0;
+	header.size = aligned_size;
+	header.reserved = 0;
+
+	/* Write header */
+	written = fwrite(&header, sizeof(ext_header_t), 1, out_fd);
+	if (written != 1) {
+		fprintf(stderr, "failed writing header to extension file\n");
+		return 1;
+	}
+
+	/* Write image */
+	while (size--) {
+		c = getc(in_fd);
+		fputc(c, out_fd);
+	}
+
+	while (pad_bytes--)
+		fputc(0, out_fd);
+
+	fclose(in_fd);
+
+	return 0;
+}
+
+/* ****************************************
+ *
+ * Write all extensions (binary, secure
+ * extensions) to file
+ *
+ * ****************************************/
+
+int format_extensions(char *ext_filename)
+{
+	FILE *out_fd;
+	int ret = 0;
+
+	out_fd = fopen(ext_filename, "wb");
+	if (out_fd == NULL) {
+		fprintf(stderr, "failed to open extension output file %s",
+			ext_filename);
+		return 1;
+	}
+
+	if (strncmp(opts.bin_ext_file, "NA", MAX_FILENAME)) {
+		if (format_bin_ext(opts.bin_ext_file, out_fd)) {
+			ret = 1;
+			goto error;
+		}
+	}
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	if (strncmp(opts.sec_cfg_file, "NA", MAX_FILENAME)) {
+		if (format_sec_ext(opts.sec_cfg_file, out_fd)) {
+			ret = 1;
+			goto error;
+		}
+	}
+#endif
+
+error:
+	fflush(out_fd);
+	fclose(out_fd);
+	return ret;
+}
+
+void update_uart(header_t *header)
+{
+	header->uart_cfg = 0;
+	header->baudrate = 0;
+
+	if (opts.disable_print)
+		uart_set_mode(header->uart_cfg, UART_MODE_DISABLE);
+
+	if (opts.baudrate)
+		header->baudrate = (opts.baudrate / 1200);
+}
+
+/* ****************************************
+ *
+ * Write the image prolog, i.e.
+ * main header and extensions, to file
+ *
+ * ****************************************/
+
+int write_prolog(int ext_cnt, char *ext_filename,
+		 uint8_t *image_buf, int image_size, FILE *out_fd)
+{
+	header_t		*header;
+	int main_hdr_size = sizeof(header_t);
+	int prolog_size = main_hdr_size;
+	FILE *ext_fd;
+	char *buf;
+	int written, read;
+	int ret = 1;
+
+
+	if (ext_cnt)
+		prolog_size +=  get_file_size(ext_filename);
+
+	prolog_size = ((prolog_size + PROLOG_ALIGNMENT) &
+		     (~(PROLOG_ALIGNMENT-1)));
+
+	/* Allocate a zeroed buffer to zero the padding bytes */
+	buf = calloc(prolog_size, 1);
+	if (buf == NULL) {
+		fprintf(stderr, "Error: failed allocating checksum buffer\n");
+		return 1;
+	}
+
+	header = (header_t *)buf;
+	header->magic       = MAIN_HDR_MAGIC;
+	header->prolog_size = prolog_size;
+	header->load_addr   = opts.load_addr;
+	header->exec_addr   = opts.exec_addr;
+	header->io_arg_0    = opts.nfc_io_args;
+	header->ext_count   = ext_cnt;
+	header->aux_flags   = 0;
+	header->boot_image_size = (image_size + 3) & (~0x3);
+	header->boot_image_checksum = checksum32((uint32_t *)image_buf,
+						 image_size);
+
+	update_uart(header);
+
+	/* Populate buffer with main header and extensions */
+	if (ext_cnt) {
+		ext_fd = fopen(ext_filename, "rb");
+		if (ext_fd == NULL) {
+			fprintf(stderr,
+				"Error: failed to open extensions file\n");
+			goto error;
+		}
+
+		read = fread(&buf[main_hdr_size],
+			     get_file_size(ext_filename), 1, ext_fd);
+		if (read != 1) {
+			fprintf(stderr,
+				"Error: failed to open extensions file\n");
+			goto error;
+		}
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+		/* Secure boot mode? */
+		if (opts.sec_opts != 0) {
+			ret = finalize_secure_ext(header, (uint8_t *)buf,
+						  prolog_size, image_buf,
+						  image_size);
+			if (ret != 0) {
+				fprintf(stderr, "Error: failed to handle ");
+				fprintf(stderr, "secure extension!\n");
+				goto error;
+			}
+		} /* secure boot mode */
+#endif
+	}
+
+	/* Update the total prolog checksum */
+	header->prolog_checksum = checksum32((uint32_t *)buf, prolog_size);
+
+	/* Now spill everything to output file */
+	written = fwrite(buf, prolog_size, 1, out_fd);
+	if (written != 1) {
+		fprintf(stderr,
+			"Error: failed to write prolog to output file\n");
+		goto error;
+	}
+
+	ret = 0;
+
+error:
+	free(buf);
+	return ret;
+}
+
+int write_boot_image(uint8_t *buf, uint32_t image_size, FILE *out_fd)
+{
+	int aligned_size;
+	int written;
+
+	/* Image size must be aligned to 4 bytes */
+	aligned_size = (image_size + 3) & (~0x3);
+
+	written = fwrite(buf, aligned_size, 1, out_fd);
+	if (written != 1) {
+		fprintf(stderr, "Error: Failed to write boot image\n");
+		goto error;
+	}
+
+	return 0;
+error:
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	char in_file[MAX_FILENAME+1] = { 0 };
+	char out_file[MAX_FILENAME+1] = { 0 };
+	char ext_file[MAX_FILENAME+1] = { 0 };
+	FILE *in_fd = NULL;
+	FILE *out_fd = NULL;
+	int parse = 0;
+	int ext_cnt = 0;
+	int opt;
+	int ret = 0;
+	int image_size;
+	uint8_t *image_buf = NULL;
+	int read;
+	size_t len;
+	uint32_t nand_block_size_kb, mlc_nand;
+
+	/* Create temporary file for building extensions
+	 * Use process ID for allowing multiple parallel runs
+	 */
+	snprintf(ext_file, MAX_FILENAME, "/tmp/ext_file-%x", getpid());
+
+	while ((opt = getopt(argc, argv, "hpms:i:l:e:a:b:u:n:t:c:k:")) != -1) {
+		switch (opt) {
+		case 'h':
+			usage();
+			break;
+		case 'l':
+			opts.load_addr = strtoul(optarg, NULL, 0);
+			break;
+		case 'e':
+			opts.exec_addr = strtoul(optarg, NULL, 0);
+			break;
+		case 'm':
+			opts.disable_print = 1;
+			break;
+		case 'u':
+			opts.baudrate = strtoul(optarg, NULL, 0);
+			break;
+		case 'b':
+			strncpy(opts.bin_ext_file, optarg, MAX_FILENAME);
+			ext_cnt++;
+			break;
+		case 'p':
+			parse = 1;
+			break;
+		case 'n':
+			nand_block_size_kb = strtoul(optarg, NULL, 0);
+			opts.nfc_io_args |= (nand_block_size_kb / 64);
+			break;
+		case 't':
+			mlc_nand = 0;
+			if (!strncmp("MLC", optarg, 3))
+				mlc_nand = 1;
+			opts.nfc_io_args |= (mlc_nand << 8);
+			break;
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+		case 'c': /* SEC extension */
+			strncpy(opts.sec_cfg_file, optarg, MAX_FILENAME);
+			ext_cnt++;
+			break;
+		case 'k':
+			opts.key_index = strtoul(optarg, NULL, 0);
+			break;
+#endif
+		default: /* '?' */
+			usage_err("Unknown argument");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* Check validity of inputes */
+	if (opts.load_addr % 8)
+		usage_err("Load address must be 8 bytes aligned");
+
+	if (opts.baudrate % 1200)
+		usage_err("Baudrate must be a multiple of 1200");
+
+	/* The remaining arguments are the input
+	 * and potentially output file
+	 */
+	/* Input file must exist so exit if not */
+	if (optind >= argc)
+		usage_err("missing input file name");
+
+	len = strlen(argv[optind]);
+	if (len > MAX_FILENAME)
+		usage_err("file name too long");
+	memcpy(in_file, argv[optind], len);
+	optind++;
+
+	/* Output file must exist in non parse mode */
+	if (optind < argc) {
+		len = strlen(argv[optind]);
+		if (len > MAX_FILENAME)
+			usage_err("file name too long");
+		memcpy(out_file, argv[optind], len);
+	} else if (!parse)
+		usage_err("missing output file name");
+
+	/* open the input file */
+	in_fd = fopen(in_file, "rb");
+	if (in_fd == NULL) {
+		printf("Error: Failed to open input file %s\n", in_file);
+		goto main_exit;
+	}
+
+	/* Read the input file to buffer */
+	image_size = get_file_size(in_file);
+	image_buf = calloc((image_size + AES_BLOCK_SZ - 1) &
+			   ~(AES_BLOCK_SZ - 1), 1);
+	if (image_buf == NULL) {
+		fprintf(stderr, "Error: failed allocating input buffer\n");
+		return 1;
+	}
+
+	read = fread(image_buf, image_size, 1, in_fd);
+	if (read != 1) {
+		fprintf(stderr, "Error: failed to read input file\n");
+		goto main_exit;
+	}
+
+	/* Parse the input image and leave */
+	if (parse) {
+		if (opts.key_index >= CSK_ARR_SZ) {
+			fprintf(stderr,
+				"Wrong key IDX value. Valid values 0 - %d\n",
+				CSK_ARR_SZ - 1);
+			goto main_exit;
+		}
+		ret = parse_image(image_buf, image_size);
+		goto main_exit;
+	}
+
+	/* Create a blob file from all extensions */
+	if (ext_cnt) {
+		ret = format_extensions(ext_file);
+		if (ret)
+			goto main_exit;
+	}
+
+	out_fd = fopen(out_file, "wb");
+	if (out_fd == NULL) {
+		fprintf(stderr,
+			"Error: Failed to open output file %s\n", out_file);
+		goto main_exit;
+	}
+
+	ret = write_prolog(ext_cnt, ext_file, image_buf, image_size, out_fd);
+	if (ret)
+		goto main_exit;
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	if (opts.sec_opts && (opts.sec_opts->encrypted_image != 0) &&
+	    (opts.sec_opts->enc_image_sz != 0)) {
+		ret = write_boot_image(opts.sec_opts->encrypted_image,
+				       opts.sec_opts->enc_image_sz, out_fd);
+	} else
+#endif
+		ret = write_boot_image(image_buf, image_size, out_fd);
+	if (ret)
+		goto main_exit;
+
+main_exit:
+	if (in_fd)
+		fclose(in_fd);
+
+	if (out_fd)
+		fclose(out_fd);
+
+	if (image_buf)
+		free(image_buf);
+
+	unlink(ext_file);
+
+#ifdef CONFIG_MVEBU_SECURE_BOOT
+	if (opts.sec_opts) {
+		if (opts.sec_opts->encrypted_image)
+			free(opts.sec_opts->encrypted_image);
+		free(opts.sec_opts);
+	}
+#endif
+	exit(ret);
+}
diff --git a/tools/marvell/doimage/doimage.mk b/tools/marvell/doimage/doimage.mk
new file mode 100644
index 0000000..2b751d4
--- /dev/null
+++ b/tools/marvell/doimage/doimage.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2018 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+
+DOIMAGE_FLAGS		?= 	-l 0x4100000 -e 0x4100000
+
+
+#NAND params
+#Open and update the below when using NAND as a boot device.
+
+CONFIG_MVEBU_NAND_BLOCK_SIZE	:= 256
+CONFIG_MVEBU_NAND_CELL_TYPE	:= SLC
+NAND_DOIMAGE_FLAGS := -t $(CONFIG_MVEBU_NAND_CELL_TYPE) -n $(CONFIG_MVEBU_NAND_BLOCK_SIZE)
diff --git a/tools/marvell/doimage/secure/aes_key.txt b/tools/marvell/doimage/secure/aes_key.txt
new file mode 100644
index 0000000..3e8a888
--- /dev/null
+++ b/tools/marvell/doimage/secure/aes_key.txt
@@ -0,0 +1 @@
+ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890
diff --git a/tools/marvell/doimage/secure/csk_priv_pem0.key b/tools/marvell/doimage/secure/csk_priv_pem0.key
new file mode 100644
index 0000000..0840c2a
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem0.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAm6jN6o2zQmtyUlvfkfDbSjPJ7Vlpp/KgK/eznoVBBsDIZakX
+cIgf8TSLpNVkc+ZE0f/n8X7mEZIyjuSBObLOm9vbkoZcR7DlKUL7RNNOUCv55Ozl
+hQwrzpH/uIyIJTvmek29G5wroi0wGbPoxzhelIRTjVCibleBWhYCmZQ6SIRmTY8L
+JT8VkX8I/Mhu62DjvxF3BnV6pXuh/FdgDN7MbldzM8Y+GOxVGi5Kcm5WHY7eyMxl
+4Y0Yko31Xv7T1PcXahVBIciT+11w+fLc4wQuCJ6GUf9JbzQ0ZllY/FdRG0AhuRMH
+zN0jAc/sKrIFoAErED6qlcoQg0vl7gmWN5x+2wIDAQABAoIBACtnPFOkw1FH6I6y
+c3qcMGlWW33FKsLb0nGwFfOjsGgTpU1Dgver3UxCnJWPsvzmPlZYBvK9saVAoLxb
+VvUhuJ6ZBXar5FtRJfUFak7cpL+SI5IDxFP++tAUwbtR5DyNoUyFFK/4Mep8sybX
+lZbHTwgWhb2nuEMQP09BR+RPAplpcitkIoPkhmbGfbt9Hsd25I3bb5Z9R4S/2Rcf
+7tmaxndQamij7/pUI7xtd8L6cMESJGIWrgEt/MaT2z8nNPE3EDctDSlH9yKqA2O7
+/LTfrxNDnw5gGRtOgahloThKljVM6pQa4mi91FufD67pHwnKn8urNbt8/3AWg6uU
+x4FzZdECgYEA0k2UYzBM+dU6T1bZZ176YI0cZrP1tbf/JwnZGHicQYS7lPLAqgfO
+u5oRQzuDimOXaV4xCPBO2nadd6aBxbZTXaglR7GG2uCHX6w2DnOr8/d66YTErTVV
+u7/Bf8gMKT9mM4rWPrOEXfXfF0fvcpkBQ+QDynIB37tx/mj2lXRkLx0CgYEAvXuX
+Dbe2QgSK0ajrcH7YJyx3RVx9RonOqL4yjCVCELmaDQd307Ef3j+gkd59XIewm+HA
+mPyeWEUd8EzH+UvjckfKFuF2I4lEUUWtVZTa7me7mvsFqeEOu5KusD4+Hs+B9Kqd
+3Evqcpj2lcMBI519Hvr9BTKfDBcH1EUos6A9rFcCgYAxsyPeTQvj/wBIv72hMFD7
+gF2159GpoFIsZ6dmoRpMYZHzIWtmw3GX5FEwEmCD1AV0YU41TpVUC7QrEq6Yiv4o
+pBQrXUkBcQ6NDaW4xJ1eip4Bkd7pEDGyrR6NlDlLhjAg/i6joskla3XNirKL4pzp
+7nj23vqSZToLZcLgjyEeAQKBgD5EvDo80j9VwMzvpxecB6qv+S4pG94vcWOQxYm6
+wMBATjjT6HP/9EoUPM9S/32F9er0QFfGRL8bT6Blix4I62Dl6KqmQy2gcXwH2tOS
+DHRmUIe40H6oQDAyHwg6HC4B4WInI6N+qzgnvnku0VQD8FdbAgVQQmY1t1PxulN1
+aG8XAoGAPWAr4i8KkVAx4wLlMF8E/ecKcsX1J0+UuKket7Dvk7xJfwtkSLPeV8Bp
+HuoHXMM3KYoZ93Hlto5rAT1VQhYuj7heU10v+9UtYTFHgaitptYmxovoCKKiZICl
+48aPUI377e5jQ6RhhGYy8ltKsJ80K1T9DIkThJPSS+9NAI+jrmg=
+-----END RSA PRIVATE KEY-----
diff --git a/tools/marvell/doimage/secure/csk_priv_pem1.key b/tools/marvell/doimage/secure/csk_priv_pem1.key
new file mode 100644
index 0000000..91d1aeb
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem1.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAgwHXB0AaIhT15Z9lHpQ2YT1W8i4oMvvRiLGQCrba5l7BJ03E
+ct0x3zagNKZEnpNndT4EAy98ihkhwVlUhxZCparJ2L3JsTs5RgV0wyQkQzwMLM8g
+QI5EMmJCgFAVRHmVICOsisGGfNVUHjGdGwPOipyQCsX2MAm3E139VpB7NYj+Q4IR
+4kvcb+59LZxKuRJTFKRDIqMGJu98P/ga70+YLXPCBPKSfnZnUppuaI86jF1E6xt8
+o7YtfEPCHDd2LXxKPZ670OapVqwo0t7ZSzEG63NkLp56FXc1OpfC69C8VPiZ8JqW
+wxvS/vL8MMCxsBnjSuqnmOAbcNR2GFtUwJOGwwIDAQABAoIBAFcfoiDwQHDp/531
+ownzBzcj0+67Q4Ckd3SwoVp+wJTz7wB0d3DsKX6IlYJuELRk0yjlVUXJDsnIbOpo
+vg4Yf7otGo9JqBh1imFGv6AHKRaNmIs0M/66nh/juNYcbAhd0w7MqrKcgRQDyy1J
+UXHl1jXYaPLBNDg+PcJjf1dSPp4axzmW2Pk2rXnJCsPcZXL/0YmEvqhfOze0GdjR
+hOkbbr6MPPVM66tA00xSwg9XEYJvHtwH6oB0rnANM8ieNK1mtcWkTU5di17CCrjS
+ohIhXQrdVpxt549EJoUqEFSgo8OOMm2npDbFrjlukb5euakvMacwoT1te79blSKf
+hrTvjgECgYEA0VqoFL0Vqe1qleikYDJ7S5xcv1oruEV31TeuBhDuf0c4PADCnBrV
+/RnCEYuXs6wCk60chHg5s0jxg+nGbiY6jRTHkJLRU3ZhDtrtfidEZ78GRzFF3shl
+Uzt7dHkKK1ZdiMH4sWzyRLom91TKWMrNKC1AD7v4/zjEXy6phall3ZcCgYEAoDJa
+0dIKvVCS6dM2E2kMqi/45mJqsJzFvYL1s4mbma/BAC47bBju/YEse90x+iIi3Gg/
+NoXmNfGPrtgdl+/J/Y6Pohxf/e7gGN71tYVETzgc2Jv09wqmzmTjCmo3wyepyWf+
+pIAE39kdhwnqXVw5xwOG1N3xrQ9TomOO+1QiXbUCgYAF84TJqiJehUA9aLKbhXPZ
+z2UXj3GkuFzSs9V/mKWe+qBPnFnr5BtnKX9JzmUOl3ovRoGEBoLlZNJwxIl+ghmx
+/wA5TOMkcz4JFRIhPu6D4HtGNNFepuWyewNkaThvyPG5vIHcUVOFvqDy8PcblRBF
+7xteFyLZ5nw2lHX/NbSOmwKBgFxLZqPIPcPArkPlGhyow1Ex/lbNkOZcDFkZIHHl
+8C3lYm62NCodW2PWjkh2shqInEkcDn9dObsOh1eWz8X/swJQplQhwPROMfJiUnHY
+a/iwPX5WrBXAn0X+Pgh8FdBsA5g0QDOKRkSplCd/APX08pzEXWQ60siAMhE3BuOq
+H3qZAoGAVnzFidlXuyn+fbNaNVepK9hbuoxHHbzYYWSkpi+73EchN8kXktC+AdEf
+owr9TPILbwWWJyisa3wW4xdbMifCgVLTedWZpZ09BENVqC+7g7ksX0pNMGYuFLOh
+Td7mFAgmclxG5UiKexajOLjjdnAsJyrDaNKhHn8NQNN6L93N0sE=
+-----END RSA PRIVATE KEY-----
diff --git a/tools/marvell/doimage/secure/csk_priv_pem2.key b/tools/marvell/doimage/secure/csk_priv_pem2.key
new file mode 100644
index 0000000..ea47ac5
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem2.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAjxTSTh57/5njUpE200+Qb3ySAn8lKeufgaa0K2Xc6Ri7lDZR
+ZJ2BPuQZV4lYGqgWUf0IOzNf2WnE2lPfVnLMx08h7NhBqJ83yJVajpr+itnOmW+r
+M7h76TFyuna1xz2kw1uhgI5Y4FRnJ4Cg4AexCSyViXSzEN/7LQwxa5z5WGDiNX5N
+3/tgjGu+dzSMOiIQhXwIcK/XaiQNm3WHqqnAhPb5Q9IBuuqBfpZoFfH4XmbFWrC8
+neSMMMxX5Ti9pKhLd1EsiaP0aUNQlF8gNWuC/tNaf+OCtwVelVa3sGSRjRFe06VQ
+sAE9oyXKri11yD5Dwp1xXivbpOrf7xjUe5gILwIDAQABAoIBABTr94CCxqDucKYP
+I9QsSzNyJKuGyfliQdWkea3q3C2ddzhJ5QbwXQjEM8xwAdkMAQ+GD2EQtxBEfgtq
+vjqW2MjAEnbefGNavL5w0GgP0+6bwLEA+ii67iuAFoWbfCMhKWmDiY8RwX8z+E13
+ao63sTRlN4x86v4pskG5CbTxpCg+8m7KklLns4SwRGf5gGQcgKRtNSR5nE4g2UNl
+dghbDdNlvUncm4zxUcTh0kquhF5Tef5w+6L7W8Hv9Pky3b1c2OK1BMhJlxYrtt69
+/zhIJs89CLx5ACfam+DT/xs0uUiuRQq/e1CCQLCnUO02JqpeN/schtDCd0ZWhbtB
+nT7fwTECgYEAx+COhys+7AZI0U+PeuTkI86GUsWHoBislXThxbxyGvMFjgyADZD+
+q/XEGAcxd4eTA1fr0Q9cLuuHZubjGQ7+OIXMZ6arXUsrmMrjRu3kHO+y6K6r4s8j
+5bxN/iQ0bymUtJRfJSLI172plszusiPWhCL5+yhYlNoh4mNZJuJnzXkCgYEAt0Gz
+07P19YPsxk5ow7ZnSNOMOkkEPP0SuHHWekMIK9KMjiRUSygOAk07zTL7MUoFn9Gy
+Prfi0ybFArNhIa4Xio3Fbjfig7rGgaApK4Y3d9A/CGPv/Nj7C2OTepqlEzRLmU9e
+Xw5yhbccCydXLyAYFAET2XHsmbewpvHyeYUSoOcCgYBRMJEUrOdhPmhDxZqVo/Zb
+6R887gnaaUtpZlHzXUnIUqEWA1PcruIT/b/KttlMIWEBQayDfkbGtFuK3AyxeBqh
+4Q+XpucC/W7XIMrTW/yGGIPG6nTdq6B8SFIyAojeArjp5T8Eua11nRAPNm1bJR2V
+DRQYBlp9FGIhMJPdLKhXmQKBgGeywSyR0COfBHPu2K+u3uFB/D7bJI/ScS54FHLY
+zZ3mpeylOCHTR6IbzDRAng31Ihue0KtW6P6tGJx/nv4tAltAADFvZDlAjqW5WLKt
+X2PoLlL0IlBFBEIclc6yBalJVWIqnG9TwJBT3oWdPGOJWLaxKWdJZSZS4J6HmLsV
+B0aPAoGAduLsOt8C5z48jPqmJxyPwsmT0Q424FccPMcvGOJ13yxq3xNsfAsbmg9l
+L2i/ktE0wCMA+Pm7cuFgxwD7xTr67POZgt9022KsOSonjPsIn24UQeP46vAX/Qtx
+Qf3sfvzf57vNy2Hybe38T8RsVOZla+v/QctfSfmb8Y95XL/SZzA=
+-----END RSA PRIVATE KEY-----
diff --git a/tools/marvell/doimage/secure/csk_priv_pem3.key b/tools/marvell/doimage/secure/csk_priv_pem3.key
new file mode 100644
index 0000000..e40a864
--- /dev/null
+++ b/tools/marvell/doimage/secure/csk_priv_pem3.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAlA/T/5IMTPTu+k5PeesB2oeP80Y6nq0ls8vXLul0TVEJoJ+O
+InbPYNqYPu4dbQQg/u8qp8BeXm2ujtJbBTcdn0jKIiDTKYEnlsGfUt9GHnuuzvFh
+rORSKuAolUqvo/zcSCo1uykaFvSuyTovSPlwllzSixD9XBbHfn3kXneiIUa45vsJ
+AyjTn2qCJt0WgvX42NTxH6Q/OWLeOuKTyRHf25eabucIv77KYy0mlEPq5jjiV5AJ
+gl5F1h5G8n07JCIWjkZ2QV4wr+Hv9uGNaSb0WGppBp4CbdQa0eUI75cKzz4WXqds
+HZaYiX/a8YC+EUfvqDD02vKREIKFL/1zL53P/wIDAQABAoIBAGzBj5w7oBNrGpr7
+qL9KEyt8xg0Q+gAR+Q6vXRlVXBtquiKk8Jd6I+vlxUz8RNsN3FrGPNPJpse/0yeP
+dlJHYNfedLNK3zCucPD4uln6LRw5B3d0sKV5dK2Px9+ZY5iWJQxRDPS0RTi1dCnV
+NmRo7P1Vo0WJLkFVbiYIvRVy1MGRfF9ejN41G6U4MoBAQ9WqLp+JasUMTspZI49a
+z8tOiJPT94MHBwbKnz8Mcq8sy02LR7U5h82+0T7JoRVix/OXiOoiQExNjZ9yGar0
+wBnl0SL1UW5UUaYzbyNH0mlMXLD+qowbDZM2pBWPfqXK+CMOsL6STIwnns7lY+ZJ
+ILbaVmECgYEA2kQXE1PZ25A87a81wCEld402WJ2KegrZC719EWv+xeoS72Ji8uv7
+V0PxVGJQOcG1N+dzJ5tN59SQ/NvVTrjwqNUxQqsygmWq/TcfGb9ONZRmyzcehYLb
+m4xTjqJKQ6Kwm5SoaCYmzEb/xaeLwLS9HmR9MdB1dxtDOLpjaK/8qPECgYEArait
+QhgaknlxG8pcAimPsEUrLHYWSFRE/MUk4+YvZg/5+YJ8csvY0SO2h0tF/ARwUrdI
+DaLEifHm4vqgN03K/0gqj7TKxcNlV16PvVx7Vz97xejdqdHZLDfAo4lcotsgvFQW
+zIqoQGGPLf6WhFixZ8mEYj8xnmzLGPvHQmf1h+8CgYEA0LDl917nIN4qw4ARPqDy
+t/pXCienrcUNfgIxwSSnNwj2DdjejzI+4VNfPbW6y16BLPCp1CbUOGOwNXTj4R9H
+S8Z8ESirZK5c7Tt1CyM1XlmEZ61OC43w+CsWAXz+0OiPQFLFKr+/vPXtvEjUgO7P
+HG4sniKZDccNYQIl5oTOaaECgYAPU4u3AZmWw9EPutRT/IcJ75DX47Qjvgw4os2W
+r4IPZ+mP88w39XW1P4mkdyg+DcY8BqD9Uxg1dHwEHEp3lw4LabsX48Thn1UaWOYm
+uDrKgHfUB7FIg5S/Kkx+ImliliRVerZoZvRiejnAvW9bTtiZaFeetCUU7lUeZ1o2
+qiYpUQKBgHQDfdDhguBGPKpkJ7pVwHkJA/lyRWaN1hwplw4TvX2oH14NsHg5Q5Fd
+lHqHFs2Ry/6X3bKgF0E6q4cx0V1Xnnj9sGsemlrHdiSxplDYRQql7X5OeYPGF/Bg
+ZTTG8rDwy+ey6EP9BZUb03hISx/LyMynOzjGl6uOcdAcy2d9Vno0
+-----END RSA PRIVATE KEY-----
diff --git a/tools/marvell/doimage/secure/kak_priv_pem.key b/tools/marvell/doimage/secure/kak_priv_pem.key
new file mode 100644
index 0000000..dfceaba
--- /dev/null
+++ b/tools/marvell/doimage/secure/kak_priv_pem.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAsj2cHcrE2pdyCqNr+oVcQULiRx6RivkrhLl2DTqWXpP33BPm
+MP0W0X0z98X7E3kZO+JIGRZ8q+6AWmUpL+53aOGItNeUgT7jQKViPJIo9ZcEnv/n
+PJqdgDd4xFhnwYMgq8uVYN9IPfaKDwB3EoOqjNox2JholUVxvLw6W8DAC8La3zwb
+0hiqtIlirQOQ/KaTHxC6dPYkrai+jSK5uAX7Vt8RKYg5qfDxSdZckmC2xVKYURhV
+bZAlyKki4h6f8CwYCJMQDpHL6mVYCuJ1Ju/OJEXvthDKD0CD2hwILhksdey3qMOC
+I5lHSO1b+sTvnVHGs65wI7A+ZYwnadMNvS9e2QIDAQABAoIBAH2uu9q2FEEe8SdX
+PNiWGQtbojsL7wzTzj/0lq2VVlqyc+AXmAWLMP/fDTn1vKlqhsSXNseZ96c0sgUL
+uBM4T7MA9WivauQH+C6pb6/OUFt8daG4SNGPJOg4NUweGmt1jyAUmeyJBWPL6GXT
+qiK//Q78/JECRxyaryyqfWwdak3flzfwONBJ03tQ9EO+L7hf9gAP7OYnAsuNp+Bz
+tj1xzNMumYYYiHvsEXx8UTe8HGrmYuO53ZY5fBLGB6Jj7hRlAHNfcdVDvvoBU5cI
+Zwi+5YsBuSP2Hr9Gt2Odu+KitH3gFdS0HIiDh44AT+Trj29NMANFDfkDbVHUmE0q
+YBL75NECgYEA2E+fJzdaYyyPIcvQgVM8g52hltR5IRgJICND3NOdB/Zb2teBGZh+
+1XJ6ZqQMDcOQZo0CMbX9UNRnf3NU55k48/EEITxCgUJTx/WdfJeTVlWGspt5+U/r
+hDnQmkePdU1en63+u9eqsla9+VhLwU3fl/pIOpsBAnoEzs3hMQZ1G0cCgYEA0vHH
+ilm3AztIoZlH3wgDAl2Gu5/YopqEofKA8G4Jp89rlkk919P/GNjEc6575wjgztDB
+0Xab+H7Nqxjs3HqQX/DTTuAxzAggBg3j/ijpHnmjrCHLeMT5ciyH+EH5Bg///cLq
++Cwn7aOWuSK1hGdDYxUycHylAYZXXFJzmEIEhN8CgYEA1qTrwPZkctTckyS0GiCG
+g/P/TLQ6HmTDaWiVBqPVxvjn3RjLuqJf+V5Hp2JRs7bDq39xFfMJExQyP34qWkbp
+BOe8uV4agDlY+ar4Q5IFWj40EzfEqWhsxCC6pt0rtbK4mqsFg1BWyfDZQnwjcAXe
+QejRk5YMQnDiJHSXaRaHTjECgYAv6ecvD624ODEJM63VhRZZ5TCDUY19caeKuXB8
+LCJZUY3Ydw5rBaY92I7Wz90o3yVhFJ3RnCVVTkgdAu5aLiS5BhSZJ+dntri/Z0xQ
+IK7C01JP+OUkq2kVe/Pued28eMnms+13LWBsY+oKZ03foyz1Ro1Ma6N3MzKIr9m9
+zdEE9QKBgECfoh0xE2T/cbJrtH0mwMCUM6eMVGq+yQBKNvuuPg6kaQUsah1n1rp6
+OyvjwRAXdhshszEzNTX1WTT6/i+vZX277Ax50pPo9UhQ9kVteVt1frN6+u5sy07V
+fg1f2+m0iFx4BD/irU0fzSyfGE+QkBnmXFBUNSYjp2PSqYIdufmW
+-----END RSA PRIVATE KEY-----
diff --git a/tools/marvell/doimage/secure/sec_img_7K.cfg b/tools/marvell/doimage/secure/sec_img_7K.cfg
new file mode 100644
index 0000000..459f731
--- /dev/null
+++ b/tools/marvell/doimage/secure/sec_img_7K.cfg
@@ -0,0 +1,29 @@
+# Trusted boot image extension definitions
+
+kak_key_file = "tools/doimage/secure/kak_priv_pem.key";
+
+# CSK keys array - 16 entries total.
+# Only a key with csk_key_index will be used for signing the image
+# use "*" string instead of file name for specifying an empty key
+csk_key_file = ["tools/doimage/secure/csk_priv_pem0.key",
+                "tools/doimage/secure/csk_priv_pem1.key",
+                "tools/doimage/secure/csk_priv_pem2.key",
+                "tools/doimage/secure/csk_priv_pem3.key",
+                "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*"];
+
+# index of CSK key in the array. Valid range is 0 to 15
+csk_key_index = 3;
+
+# AES-256 symmetric key for image encryption
+aes_key_file = "tools/doimage/secure/aes_key.txt";
+
+efuse_disable = false;
+jtag = { enable = true; delay = 20; };
+
+box_id = 0xdeadbeef;
+flash_id = 0xbaddf00d;
+
+# SecureBootControl and EfuseBurnControl registers array
+# Two register addresses for each connected CP
+# A7K - one CP, two register values
+control = [0xF2441920, 0xF2441940];
diff --git a/tools/marvell/doimage/secure/sec_img_8K.cfg b/tools/marvell/doimage/secure/sec_img_8K.cfg
new file mode 100644
index 0000000..a849dff
--- /dev/null
+++ b/tools/marvell/doimage/secure/sec_img_8K.cfg
@@ -0,0 +1,29 @@
+# Trusted boot image extension definitions
+
+kak_key_file = "tools/doimage/secure/kak_priv_pem.key";
+
+# CSK keys array - 16 entries total.
+# Only a key with csk_key_index will be used for signing the image
+# use "*" string instead of file name for specifying an empty key
+csk_key_file = ["tools/doimage/secure/csk_priv_pem0.key",
+                "tools/doimage/secure/csk_priv_pem1.key",
+                "tools/doimage/secure/csk_priv_pem2.key",
+                "tools/doimage/secure/csk_priv_pem3.key",
+                "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*"];
+
+# index of CSK key in the array. Valid range is 0 to 15
+csk_key_index = 3;
+
+# AES-256 symmetric key for image encryption
+aes_key_file = "tools/doimage/secure/aes_key.txt";
+
+efuse_disable = false;
+jtag = { enable = true; delay = 20; };
+
+box_id = 0xdeadbeef;
+flash_id = 0xbaddf00d;
+
+# SecureBootControl and EfuseBurnControl registers array
+# Two register addresses for each connected CP
+# A8K - two CP, four register values
+control = [0xF2441920, 0xF2441940, 0xF4441920, 0xF4441940];
diff --git a/tools/meson/Makefile b/tools/meson/Makefile
new file mode 100644
index 0000000..1a1d1f8
--- /dev/null
+++ b/tools/meson/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+PROJECT := doimage${BIN_EXT}
+OBJECTS := doimage.o
+V := 0
+
+HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE
+
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG
+else
+  HOSTCCFLAGS += -O2
+endif
+
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+HOSTCC := gcc
+
+.PHONY: all clean distclean
+
+all: ${PROJECT}
+
+${PROJECT}: ${OBJECTS} Makefile
+	@echo "  HOSTLD  $@"
+	${Q}${HOSTCC} ${OBJECTS} -o $@
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+%.o: %.c Makefile
+	@echo "  HOSTCC  $<"
+	${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@
+
+clean:
+	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
+
+distclean: clean
diff --git a/tools/meson/doimage.c b/tools/meson/doimage.c
new file mode 100644
index 0000000..b304038
--- /dev/null
+++ b/tools/meson/doimage.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019, Remi Pommarel <repk@triplefau.lt>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <endian.h>
+
+#define DEFAULT_PROGNAME "doimage"
+#define PROGNAME(argc, argv) (((argc) >= 1) ? ((argv)[0]) : DEFAULT_PROGNAME)
+
+#define BL31_MAGIC 0x12348765
+#define BL31_LOADADDR 0x05100000
+#define BUFLEN 512
+
+static inline void usage(char const *prog)
+{
+	fprintf(stderr, "Usage: %s <bl31.bin> <bl31.img>\n", prog);
+}
+
+static inline int fdwrite(int fd, uint8_t *data, size_t len)
+{
+	ssize_t nr;
+	size_t l;
+	int ret = -1;
+
+	for (l = 0; l < len; l += nr) {
+		nr = write(fd, data + l, len - l);
+		if (nr < 0) {
+			perror("Cannot write to bl31.img");
+			goto out;
+		}
+	}
+
+	ret = 0;
+out:
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	int fin, fout, ret = -1;
+	ssize_t len;
+	uint32_t data;
+	uint8_t buf[BUFLEN];
+
+	if (argc != 3) {
+		usage(PROGNAME(argc, argv));
+		goto out;
+	}
+
+	fin = open(argv[1], O_RDONLY);
+	if (fin < 0) {
+		perror("Cannot open bl31.bin");
+		goto out;
+	}
+
+	fout = open(argv[2], O_WRONLY | O_CREAT, 0660);
+	if (fout < 0) {
+		perror("Cannot open bl31.img");
+		goto closefin;
+	}
+
+	data = htole32(BL31_MAGIC);
+	if (fdwrite(fout, (uint8_t *)&data, sizeof(data)) < 0)
+		goto closefout;
+
+	lseek(fout, 8, SEEK_SET);
+	data = htole32(BL31_LOADADDR);
+	if (fdwrite(fout, (uint8_t *)&data, sizeof(data)) < 0)
+		goto closefout;
+
+	lseek(fout, 0x200, SEEK_SET);
+	while ((len = read(fin, buf, sizeof(buf))) > 0)
+		if (fdwrite(fout, buf, len) < 0)
+			goto closefout;
+	if (len < 0) {
+		perror("Cannot read bl31.bin");
+		goto closefout;
+	}
+
+	ret = 0;
+
+closefout:
+	close(fout);
+closefin:
+	close(fin);
+out:
+	return ret;
+}
diff --git a/tools/renesas/rcar_layout_create/makefile b/tools/renesas/rcar_layout_create/makefile
new file mode 100644
index 0000000..d585754
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/makefile
@@ -0,0 +1,121 @@
+#
+# Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+###################################################
+# makefile
+###################################################
+
+#output file name
+FILE_NAME_SA0   = bootparam_sa0
+FILE_NAME_SA6   = cert_header_sa6
+
+OUTPUT_FILE_SA0 = $(FILE_NAME_SA0).elf
+OUTPUT_FILE_SA6 = $(FILE_NAME_SA6).elf
+
+#object file name
+OBJ_FILE_SA0 =	sa0.o
+OBJ_FILE_SA6 =	sa6.o
+
+#linker script name
+MEMORY_DEF_SA0 = sa0.ld.S
+MEMORY_DEF_SA6 = sa6.ld.S
+
+###################################################
+# Convenience function for adding build definitions
+# $(eval $(call add_define,FOO)) will have:
+# -DFOO if $(FOO) is empty; -DFOO=$(FOO) otherwise
+define add_define
+DEFINES			+=	-D$(1)$(if $(value $(1)),=$(value $(1)),)
+endef
+
+# Process RCAR_SA0_SIZE flag
+ifndef RCAR_SA0_SIZE
+RCAR_SA0_SIZE := 1
+else
+ifeq (${RCAR_SA0_SIZE},0)
+RCAR_SA0_SIZE := 0
+else
+RCAR_SA0_SIZE := 1
+endif
+endif
+$(eval $(call add_define,RCAR_SA0_SIZE))
+
+# Process RCAR_SA6_TYPE flag
+ifndef RCAR_SA6_TYPE
+RCAR_SA6_TYPE := 0
+else
+ifeq (${RCAR_SA6_TYPE},0)
+RCAR_SA6_TYPE := 0
+else
+RCAR_SA6_TYPE := 1
+endif
+endif
+$(eval $(call add_define,RCAR_SA6_TYPE))
+
+# Handle different VMA adjustment on D3
+ifeq (${RCAR_LSI},${RCAR_D3})
+RCAR_VMA_ADJUST_ADDR := 0xE6320000
+else
+RCAR_VMA_ADJUST_ADDR := 0xE6312000
+endif
+$(eval $(call add_define,RCAR_VMA_ADJUST_ADDR))
+
+
+###################################################
+
+#c compiler
+CC = $(CROSS_COMPILE)gcc
+CFLAGS += ${DEFINES}
+CFLAGS += -I../../include/lib/stdlib
+
+#Linker
+LD = $(CROSS_COMPILE)ld
+
+#objcopy
+objcopy = $(CROSS_COMPILE)objcopy
+
+#clean
+CL = rm -f
+
+###################################################
+.SUFFIXES : .s .c .o
+
+###################################################
+# command
+
+.PHONY: all
+all: $(OUTPUT_FILE_SA0) $(OUTPUT_FILE_SA6)
+###################################################
+# Linker
+###################################################
+$(OUTPUT_FILE_SA0) : $(MEMORY_DEF_SA0) $(OBJ_FILE_SA0)
+	$(LD) $(OBJ_FILE_SA0)		 	\
+	-T $(MEMORY_DEF_SA0)			\
+	-o $(OUTPUT_FILE_SA0)			\
+	-Map $(FILE_NAME_SA0).map 		\
+
+	$(objcopy) -O srec --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3  $(OUTPUT_FILE_SA0) $(FILE_NAME_SA0).srec
+	$(objcopy) -O binary --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3  $(OUTPUT_FILE_SA0) $(FILE_NAME_SA0).bin
+
+$(OUTPUT_FILE_SA6) : $(MEMORY_DEF_SA6) $(OBJ_FILE_SA6)
+	$(LD) $(OBJ_FILE_SA6)		 	\
+	-T $(MEMORY_DEF_SA6)			\
+	-o $(OUTPUT_FILE_SA6)			\
+	-Map $(FILE_NAME_SA6).map 		\
+
+	$(objcopy) -O srec --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3  $(OUTPUT_FILE_SA6) $(FILE_NAME_SA6).srec
+	$(objcopy) -O binary --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3  $(OUTPUT_FILE_SA6) $(FILE_NAME_SA6).bin
+
+###################################################
+# Compile
+###################################################
+
+%.o:../%.c
+	$(CC) -c -I $< -o $@
+
+.PHONY: clean
+clean:
+	$(CL)  *.bin *.map *.srec *.elf *.o
diff --git a/tools/renesas/rcar_layout_create/sa0.c b/tools/renesas/rcar_layout_create/sa0.c
new file mode 100644
index 0000000..79354ec
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa0.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#define RCAR_SA0_SIZE_SMALL	(0)	/* for E3/D3 */
+#define RCAR_SA0_SIZE_NORMAL	(1)	/* for H3/M3/M3N */
+
+#define BL2_ADDRESS	(0xE6304000)	/* BL2 start address */
+
+#if (RCAR_SA0_SIZE == RCAR_SA0_SIZE_SMALL)
+#define BL2_SIZE	(80*1024/4)	/* BL2 size is 80KB(0x00005000) */
+#else  /* (RCAR_SA0_SIZE == RCAR_SA0_SIZE_SMALL) */
+#define BL2_SIZE	(170*1024/4)	/* BL2 size is 170KB(0x0000AA00) */
+#endif /* (RCAR_SA0_SIZE == RCAR_SA0_SIZE_SMALL) */
+
+/* SA0 */
+/* 0x00000000 */
+const unsigned int __attribute__ ((section (".sa0_bootrom"))) bootrom_paramA = 0x00000100;
+/* 0x00000080 (Map Type 3 for eMMC Boot)*/
+/* 0x000001D4 */
+const unsigned int __attribute__ ((section (".sa0_bl2dst_addr3"))) bl2dst_addr3 = BL2_ADDRESS;
+/* 0x000002E4 */
+const unsigned int __attribute__ ((section (".sa0_bl2dst_size3"))) bl2dst_size3 = BL2_SIZE;
+/* 0x00000C00 (Map Type 1 for HyperFlash/QSPI Flash Boot)*/
+/* 0x00000D54 */
+const unsigned int __attribute__ ((section (".sa0_bl2dst_addr1"))) bl2dst_addr1 = BL2_ADDRESS;
+/* 0x00000E64 */
+const unsigned int __attribute__ ((section (".sa0_bl2dst_size1"))) bl2dst_size1 = BL2_SIZE;
diff --git a/tools/renesas/rcar_layout_create/sa0.ld.S b/tools/renesas/rcar_layout_create/sa0.ld.S
new file mode 100644
index 0000000..98fee23
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa0.ld.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+SECTIONS
+{
+	. = 0x00000000;
+	.rodata : {
+		KEEP(*(.sa0_bootrom))
+		/* Map Type 3 for eMMC Boot */
+                /* A-side IPL content cert "Start Address" */
+		. = 0x000001D4;		/* H'00000080 + H'00000154 */
+		KEEP(*(.sa0_bl2dst_addr3))
+                /* A-side IPL content cert "Size" */
+		. = 0x000002E4;		/* H'00000080 + H'00000264 */
+		KEEP(*(.sa0_bl2dst_size3))
+		/* Map Type 1 for HyperFlash/QSPI Flash Boot */
+		/* A-side IPL content cert "Start Address" */
+		. = 0x00000D54;		/* H'00000C00 + H'00000154 */
+		KEEP(*(.sa0_bl2dst_addr1))
+		/* A-side IPL content cert "Size" */
+		. = 0x00000E64;		/* H'00000C00 + H'00000264 */
+		KEEP(*(.sa0_bl2dst_size1))
+	}
+
+}
diff --git a/tools/renesas/rcar_layout_create/sa6.c b/tools/renesas/rcar_layout_create/sa6.c
new file mode 100644
index 0000000..fa828b9
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa6.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#define RCAR_SA6_TYPE_HYPERFLASH	(0)
+#define RCAR_SA6_TYPE_EMMC		(1)
+
+#if (RCAR_SA6_TYPE == RCAR_SA6_TYPE_HYPERFLASH)
+
+/* Number of content cert for Non-secure Target Program(BL33x) */
+#define RCAR_IMAGE_NUM			(0x00000001U)
+/* Source address on flash for BL31 */
+#define RCAR_BL31SRC_ADDRESS		(0x001C0000U)
+/* Reserved */
+#define RCAR_BL31_PARTITION		(0x00000000U)
+/* Source address on flash for BL32 */
+#define RCAR_BL32SRC_ADDRESS		(0x00200000U)
+/* Reserved */
+#define RCAR_BL32_PARTITION		(0x00000000U)
+/* Source address on flash for BL33 */
+#define RCAR_BL33SRC_ADDRESS		(0x00640000U)
+/* Reserved */
+#define RCAR_BL33_PARTITION		(0x00000000U)
+#define RCAR_BL332SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL332_PARTITION		(0x00000000U)
+#define RCAR_BL333SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL333_PARTITION		(0x00000000U)
+#define RCAR_BL334SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL334_PARTITION		(0x00000000U)
+#define RCAR_BL335SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL335_PARTITION		(0x00000000U)
+#define RCAR_BL336SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL336_PARTITION		(0x00000000U)
+#define RCAR_BL337SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL337_PARTITION		(0x00000000U)
+#define RCAR_BL338SRC_ADDRESS		(0x00000000U)
+/* Reserved */
+#define RCAR_BL338_PARTITION		(0x00000000U)
+
+#else /* RCAR_SA6_TYPE == RCAR_SA6_TYPE_HYPERFLASH */
+
+/* Number of content cert for Non-secure Target Program(BL33x) */
+#define RCAR_IMAGE_NUM			(0x00000001U)
+/* Source address on eMMC for BL31 */
+#define RCAR_BL31SRC_ADDRESS		(0x00040000U)
+/* Source partition on eMMC for BL31 */
+#define RCAR_BL31_PARTITION		(0x00000001U)
+/* Source address on eMMC for BL32 */
+#define RCAR_BL32SRC_ADDRESS		(0x00200000U)
+/* Source partition on eMMC for BL32 */
+#define RCAR_BL32_PARTITION		(0x00000001U)
+/* Source address on eMMC for BL33 */
+#define RCAR_BL33SRC_ADDRESS		(0x00000000U)
+/* Source partition on eMMC for BL33 */
+#define RCAR_BL33_PARTITION		(0x00000002U)
+/* Reserved */
+#define RCAR_BL332SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL332_PARTITION		(0x00000000U)
+/* Reserved */
+#define RCAR_BL333SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL333_PARTITION		(0x00000000U)
+/* Reserved */
+#define RCAR_BL334SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL334_PARTITION		(0x00000000U)
+/* Reserved */
+#define RCAR_BL335SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL335_PARTITION		(0x00000000U)
+/* Reserved */
+#define RCAR_BL336SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL336_PARTITION		(0x00000000U)
+/* Reserved */
+#define RCAR_BL337SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL337_PARTITION		(0x00000000U)
+/* Reserved */
+#define RCAR_BL338SRC_ADDRESS		(0x00000000U)
+#define RCAR_BL338_PARTITION		(0x00000000U)
+
+#endif /* RCAR_SA6_TYPE == RCAR_SA6_TYPE_HYPERFLASH */
+
+/* Destination address for BL31 */
+#define RCAR_BL31DST_ADDRESS		(0x44000000U)
+#define RCAR_BL31DST_ADDRESSH		(0x00000000U)
+/* Destination size for BL31 */
+#define RCAR_BL31DST_SIZE		(0x00004000U)
+/* Destination address for BL32 */
+#define RCAR_BL32DST_ADDRESS		(0x44100000U)
+#define RCAR_BL32DST_ADDRESSH		(0x00000000U)
+/* Destination size for BL32 */
+#define RCAR_BL32DST_SIZE		(0x00040000U)
+/* Destination address for BL33 */
+#define RCAR_BL33DST_ADDRESS		(0x50000000U)
+#define RCAR_BL33DST_ADDRESSH		(0x00000000U)
+/* Destination size for BL33 */
+#define RCAR_BL33DST_SIZE		(0x00040000U)
+/* Reserved */
+#define RCAR_BL332DST_ADDRESS		(0x00000000U)
+#define RCAR_BL332DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL332DST_SIZE		(0x00000000U)
+/* Reserved */
+#define RCAR_BL333DST_ADDRESS		(0x00000000U)
+#define RCAR_BL333DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL333DST_SIZE		(0x00000000U)
+/* Reserved */
+#define RCAR_BL334DST_ADDRESS		(0x00000000U)
+#define RCAR_BL334DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL334DST_SIZE		(0x00000000U)
+/* Reserved */
+#define RCAR_BL335DST_ADDRESS		(0x00000000U)
+#define RCAR_BL335DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL335DST_SIZE		(0x00000000U)
+/* Reserved */
+#define RCAR_BL336DST_ADDRESS		(0x00000000U)
+#define RCAR_BL336DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL336DST_SIZE		(0x00000000U)
+/* Reserved */
+#define RCAR_BL337DST_ADDRESS		(0x00000000U)
+#define RCAR_BL337DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL337DST_SIZE		(0x00000000U)
+/* Reserved */
+#define RCAR_BL338DST_ADDRESS		(0x00000000U)
+#define RCAR_BL338DST_ADDRESSH		(0x00000000U)
+#define RCAR_BL338DST_SIZE		(0x00000000U)
+
+/* SA6 */
+const uint64_t __attribute__ ((section (".sa6_image_num")))	image_num	= RCAR_IMAGE_NUM;
+const uint64_t __attribute__ ((section (".sa6_bl31src_addr")))	bl31src_addr	= RCAR_BL31SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl31partition")))	bl31partition	= RCAR_BL31_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl32src_addr")))	bl32src_addr	= RCAR_BL32SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl32partition")))	bl32partition	= RCAR_BL32_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl33src_addr")))	bl33src_addr	= RCAR_BL33SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl33partition")))	bl33partition	= RCAR_BL33_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl332src_addr")))	bl332src_addr	= RCAR_BL332SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl332partition")))bl332partition	= RCAR_BL332_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl333src_addr")))	bl333src_addr	= RCAR_BL333SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl333partition")))bl333partition	= RCAR_BL333_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl334src_addr")))	bl334src_addr	= RCAR_BL334SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl334partition")))bl334partition	= RCAR_BL334_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl335src_addr")))	bl335src_addr	= RCAR_BL335SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl335partition")))bl335partition	= RCAR_BL335_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl336src_addr")))	bl336src_addr	= RCAR_BL336SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl336partition")))bl336partition	= RCAR_BL336_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl337src_addr")))	bl337src_addr	= RCAR_BL337SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl337partition")))bl337partition	= RCAR_BL337_PARTITION;
+const uint64_t __attribute__ ((section (".sa6_bl338src_addr")))	bl338src_addr	= RCAR_BL338SRC_ADDRESS;
+const uint64_t __attribute__ ((section (".sa6_bl338partition")))bl338partition	= RCAR_BL338_PARTITION;
+const uint32_t __attribute__ ((section (".sa6_bl31dst_addr")))	bl31dst_addr	= RCAR_BL31DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl31dst_addrh")))	bl31dst_addrh	= RCAR_BL31DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl31dst_size")))	bl31dst_size	= RCAR_BL31DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl32dst_addr")))	bl32dst_addr	= RCAR_BL32DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl32dst_addrh")))	bl32dst_addrh	= RCAR_BL32DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl32dst_size")))	bl32dst_size	= RCAR_BL32DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl33dst_addr")))	bl33dst_addr	= RCAR_BL33DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl33dst_addrh")))	bl33dst_addrh	= RCAR_BL33DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl33dst_size")))	bl33dst_size	= RCAR_BL33DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl332dst_addr")))	bl332dst_addr	= RCAR_BL332DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl332dst_addrh")))bl332dst_addrh	= RCAR_BL332DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl332dst_size"))) bl332dst_size	= RCAR_BL332DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl333dst_addr")))	bl333dst_addr	= RCAR_BL333DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl333dst_addrh")))bl333dst_addrh	= RCAR_BL333DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl333dst_size")))	bl333dst_size	= RCAR_BL333DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl334dst_addr")))	bl334dst_addr	= RCAR_BL334DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl334dst_addrh")))bl334dst_addrh	= RCAR_BL334DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl334dst_size")))	bl334dst_size	= RCAR_BL334DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl335dst_addr")))	bl335dst_addr	= RCAR_BL335DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl335dst_addrh")))bl335dst_addrh	= RCAR_BL335DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl335dst_size")))	bl335dst_size	= RCAR_BL335DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl336dst_addr")))	bl336dst_addr	= RCAR_BL336DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl336dst_addrh")))bl336dst_addrh	= RCAR_BL336DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl336dst_size")))	bl336dst_size	= RCAR_BL336DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl337dst_addr")))	bl337dst_addr	= RCAR_BL337DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl337dst_addrh")))bl337dst_addrh	= RCAR_BL337DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl337dst_size")))	bl337dst_size	= RCAR_BL337DST_SIZE;
+const uint32_t __attribute__ ((section (".sa6_bl338dst_addr")))	bl338dst_addr	= RCAR_BL338DST_ADDRESS;
+const uint32_t __attribute__ ((section (".sa6_bl338dst_addrh")))bl338dst_addrh	= RCAR_BL338DST_ADDRESSH;
+const uint32_t __attribute__ ((section (".sa6_bl338dst_size")))	bl338dst_size	= RCAR_BL338DST_SIZE;
diff --git a/tools/renesas/rcar_layout_create/sa6.ld.S b/tools/renesas/rcar_layout_create/sa6.ld.S
new file mode 100644
index 0000000..9ca0c1d
--- /dev/null
+++ b/tools/renesas/rcar_layout_create/sa6.ld.S
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+SECTIONS
+{
+	. = 0x00000000;
+	.rodata : {
+		KEEP(*(.sa6_image_num))
+		. = 0x00000008;
+		KEEP(*(.sa6_bl31src_addr))
+		. = 0x00000010;
+		KEEP(*(.sa6_bl31partition))
+		. = 0x00000018;
+		KEEP(*(.sa6_bl32src_addr))
+		. = 0x00000020;
+		KEEP(*(.sa6_bl32partition))
+		. = 0x00000028;
+		KEEP(*(.sa6_bl33src_addr))
+		. = 0x00000030;
+		KEEP(*(.sa6_bl33partition))
+		. = 0x00000038;
+		KEEP(*(.sa6_bl332src_addr))
+		. = 0x00000040;
+		KEEP(*(.sa6_bl332partition))
+		. = 0x00000048;
+		KEEP(*(.sa6_bl333src_addr))
+		. = 0x00000050;
+		KEEP(*(.sa6_bl333partition))
+		. = 0x00000058;
+		KEEP(*(.sa6_bl334src_addr))
+		. = 0x00000060;
+		KEEP(*(.sa6_bl334partition))
+		. = 0x00000068;
+		KEEP(*(.sa6_bl335src_addr))
+		. = 0x00000070;
+		KEEP(*(.sa6_bl335partition))
+		. = 0x00000078;
+		KEEP(*(.sa6_bl336src_addr))
+		. = 0x00000080;
+		KEEP(*(.sa6_bl336partition))
+		. = 0x00000088;
+		KEEP(*(.sa6_bl337src_addr))
+		. = 0x00000090;
+		KEEP(*(.sa6_bl337partition))
+		. = 0x00000098;
+		KEEP(*(.sa6_bl338src_addr))
+		. = 0x000000A0;
+		KEEP(*(.sa6_bl338partition))
+		. = 0x00000554;
+		KEEP(*(.sa6_bl31dst_addr))
+		. = 0x00000558;
+		KEEP(*(.sa6_bl31dst_addrh))
+		. = 0x00000664;
+		KEEP(*(.sa6_bl31dst_size))
+		. = 0x00000D54;
+		KEEP(*(.sa6_bl32dst_addr))
+		. = 0x00000D58;
+		KEEP(*(.sa6_bl32dst_addrh))
+		. = 0x00000E64;
+		KEEP(*(.sa6_bl32dst_size))
+		. = 0x00001554;
+		KEEP(*(.sa6_bl33dst_addr))
+		. = 0x00001558;
+		KEEP(*(.sa6_bl33dst_addrh))
+		. = 0x00001664;
+		KEEP(*(.sa6_bl33dst_size))
+		. = 0x00001D54;
+		KEEP(*(.sa6_bl332dst_addr))
+		. = 0x00001D58;
+		KEEP(*(.sa6_bl332dst_addrh))
+		. = 0x00001E64;
+		KEEP(*(.sa6_bl332dst_size))
+		. = 0x00002554;
+		KEEP(*(.sa6_bl333dst_addr))
+		. = 0x00002558;
+		KEEP(*(.sa6_bl333dst_addrh))
+		. = 0x00002664;
+		KEEP(*(.sa6_bl333dst_size))
+		. = 0x00002D54;
+		KEEP(*(.sa6_bl334dst_addr))
+		. = 0x00002D58;
+		KEEP(*(.sa6_bl334dst_addrh))
+		. = 0x00002E64;
+		KEEP(*(.sa6_bl334dst_size))
+		. = 0x00003554;
+		KEEP(*(.sa6_bl335dst_addr))
+		. = 0x00003558;
+		KEEP(*(.sa6_bl335dst_addrh))
+		. = 0x00003664;
+		KEEP(*(.sa6_bl335dst_size))
+		. = 0x00003D54;
+		KEEP(*(.sa6_bl336dst_addr))
+		. = 0x00003D58;
+		KEEP(*(.sa6_bl336dst_addrh))
+		. = 0x00003E64;
+		KEEP(*(.sa6_bl336dst_size))
+		. = 0x00004554;
+		KEEP(*(.sa6_bl337dst_addr))
+		. = 0x00004558;
+		KEEP(*(.sa6_bl337dst_addrh))
+		. = 0x00004664;
+		KEEP(*(.sa6_bl337dst_size))
+		. = 0x00004D54;
+		KEEP(*(.sa6_bl338dst_addr))
+		. = 0x00004D58;
+		KEEP(*(.sa6_bl338dst_addrh))
+		. = 0x00004E64;
+		KEEP(*(.sa6_bl338dst_size))
+	}
+
+}
diff --git a/tools/sptool/Makefile b/tools/sptool/Makefile
new file mode 100644
index 0000000..9325207
--- /dev/null
+++ b/tools/sptool/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+PROJECT := sptool${BIN_EXT}
+OBJECTS := sptool.o
+V ?= 0
+
+override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700
+HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG
+else
+  HOSTCCFLAGS += -O2
+endif
+
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+INCLUDE_PATHS := -I../../include/tools_share
+
+HOSTCC ?= gcc
+
+.PHONY: all clean distclean
+
+all: ${PROJECT}
+
+${PROJECT}: ${OBJECTS} Makefile
+	@echo "  HOSTLD  $@"
+	${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+%.o: %.c Makefile
+	@echo "  HOSTCC  $<"
+	${Q}${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@
+
+clean:
+	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
diff --git a/tools/sptool/sptool.c b/tools/sptool/sptool.c
new file mode 100644
index 0000000..a33b664
--- /dev/null
+++ b/tools/sptool/sptool.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sptool.h"
+
+#define PAGE_SIZE		4096
+
+/*
+ * Linked list of entries describing entries in the secure
+ * partition package.
+ */
+struct sp_entry_info {
+	/* Location of the files in the host's RAM. */
+	void *sp_data, *rd_data;
+
+	/* Size of the files. */
+	uint64_t sp_size, rd_size;
+
+	/* Location of the binary files inside the package output file */
+	uint64_t sp_offset, rd_offset;
+
+	struct sp_entry_info *next;
+};
+
+static struct sp_entry_info *sp_info_head;
+
+static uint64_t sp_count;
+
+/* Align an address to a power-of-two boundary. */
+static unsigned int align_to(unsigned int address, unsigned int boundary)
+{
+	unsigned int mask = boundary - 1U;
+
+	if ((address & mask) != 0U)
+		return (address + boundary) & ~mask;
+	else
+		return address;
+}
+
+/* Allocate a memory area of 'size' bytes and zero it. */
+static void *xzalloc(size_t size, const char *msg)
+{
+	void *d;
+
+	d = malloc(size);
+	if (d == NULL) {
+		fprintf(stderr, "error: malloc: %s\n", msg);
+		exit(1);
+	}
+
+	memset(d, 0, size);
+
+	return d;
+}
+
+/*
+ * Write 'size' bytes from 'buf' into the specified file stream.
+ * Exit the program on error.
+ */
+static void xfwrite(void *buf, size_t size, FILE *fp)
+{
+	if (fwrite(buf, 1, size, fp) != size) {
+		fprintf(stderr, "error: Failed to write to output file.\n");
+		exit(1);
+	}
+}
+
+/*
+ * Set the file position indicator for the specified file stream.
+ * Exit the program on error.
+ */
+static void xfseek(FILE *fp, long offset, int whence)
+{
+	if (fseek(fp, offset, whence) != 0) {
+		fprintf(stderr, "error: Failed to set file to offset 0x%lx (%d).\n",
+		       offset, whence);
+		perror(NULL);
+		exit(1);
+	}
+}
+
+static void cleanup(void)
+{
+	struct sp_entry_info *sp = sp_info_head;
+
+	while (sp != NULL) {
+		struct sp_entry_info *next = sp->next;
+
+		if (sp->sp_data != NULL)
+			free(sp->sp_data);
+
+		if (sp->rd_data != NULL)
+			free(sp->rd_data);
+
+		free(sp);
+
+		sp = next;
+	}
+
+	sp_count = 0;
+	sp_info_head = NULL;
+}
+
+/*
+ * Allocate a buffer big enough to store the content of the specified file and
+ * load the file into it. Fill 'size' with the file size. Exit the program on
+ * error.
+ */
+static void load_file(const char *path, void **ptr, uint64_t *size)
+{
+	FILE *f = fopen(path, "rb");
+	if (f == NULL) {
+		fprintf(stderr, "error: %s couldn't be opened.\n", path);
+		exit(1);
+	}
+
+	xfseek(f, 0, SEEK_END);
+	*size = ftell(f);
+	if (*size == 0) {
+		fprintf(stderr, "error: Size of %s is 0\n", path);
+		exit(1);
+	}
+
+	rewind(f);
+
+	*ptr = malloc(*size);
+	if (*ptr == NULL) {
+		fprintf(stderr, "error: Not enough memory to load %s\n", path);
+		exit(1);
+	}
+
+	if (fread(*ptr, *size, 1, f) != 1) {
+		fprintf(stderr, "error: Couldn't read %s\n", path);
+		exit(1);
+	}
+
+	fclose(f);
+}
+
+static void load_sp_rd(char *path)
+{
+	char *split_mark = strstr(path, ":");
+
+	*split_mark = '\0';
+
+	char *sp_path = path;
+	char *rd_path = split_mark + 1;
+
+	struct sp_entry_info *sp;
+
+	if (sp_info_head == NULL) {
+		sp_info_head = xzalloc(sizeof(struct sp_entry_info),
+			"Failed to allocate sp_entry_info struct");
+
+		sp = sp_info_head;
+	} else {
+		sp = sp_info_head;
+
+		while (sp->next != NULL) {
+			sp = sp->next;
+		}
+
+		sp->next = xzalloc(sizeof(struct sp_entry_info),
+			"Failed to allocate sp_entry_info struct");
+
+		sp = sp->next;
+	}
+
+	load_file(sp_path, &sp->sp_data, &sp->sp_size);
+	printf("Loaded image file %s (%lu bytes)\n", sp_path, sp->sp_size);
+
+	load_file(rd_path, &sp->rd_data, &sp->rd_size);
+	printf("Loaded RD file %s (%lu bytes)\n", rd_path, sp->rd_size);
+
+	sp_count++;
+}
+
+static void output_write(const char *path)
+{
+	struct sp_entry_info *sp;
+
+	if (sp_count == 0) {
+		fprintf(stderr, "error: At least one SP must be provided.\n");
+		exit(1);
+	}
+
+	/* The layout of the structs is specified in the header file sptool.h */
+
+	printf("Writing %lu partitions to output file.\n", sp_count);
+
+	unsigned int header_size = (sizeof(struct sp_pkg_header) * 8)
+				 + (sizeof(struct sp_pkg_entry) * 8 * sp_count);
+
+	FILE *f = fopen(path, "wb");
+	if (f == NULL) {
+		fprintf(stderr, "error: Failed to open %s\n", path);
+		exit(1);
+	}
+
+	unsigned int file_ptr = align_to(header_size, PAGE_SIZE);
+
+	/* First, save all partition images aligned to page boundaries */
+
+	sp = sp_info_head;
+
+	for (uint64_t i = 0; i < sp_count; i++) {
+		xfseek(f, file_ptr, SEEK_SET);
+
+		printf("Writing image %lu to offset 0x%x (0x%lx bytes)\n",
+		       i, file_ptr, sp->sp_size);
+
+		sp->sp_offset = file_ptr;
+		xfwrite(sp->sp_data, sp->sp_size, f);
+		file_ptr = align_to(file_ptr + sp->sp_size, PAGE_SIZE);
+		sp = sp->next;
+	}
+
+	/* Now, save resource description blobs aligned to 8 bytes */
+
+	sp = sp_info_head;
+
+	for (uint64_t i = 0; i < sp_count; i++) {
+		xfseek(f, file_ptr, SEEK_SET);
+
+		printf("Writing RD blob %lu to offset 0x%x (0x%lx bytes)\n",
+		       i, file_ptr, sp->rd_size);
+
+		sp->rd_offset = file_ptr;
+		xfwrite(sp->rd_data, sp->rd_size, f);
+		file_ptr = align_to(file_ptr + sp->rd_size, 8);
+		sp = sp->next;
+	}
+
+	/* Finally, write header */
+
+	uint64_t version = 0x1;
+	uint64_t sp_num = sp_count;
+
+	xfseek(f, 0, SEEK_SET);
+
+	xfwrite(&version, sizeof(uint64_t), f);
+	xfwrite(&sp_num, sizeof(uint64_t), f);
+
+	sp = sp_info_head;
+
+	for (unsigned int i = 0; i < sp_count; i++) {
+
+		uint64_t sp_offset, sp_size, rd_offset, rd_size;
+
+		sp_offset = sp->sp_offset;
+		sp_size = align_to(sp->sp_size, PAGE_SIZE);
+		rd_offset = sp->rd_offset;
+		rd_size = sp->rd_size;
+
+		xfwrite(&sp_offset, sizeof(uint64_t), f);
+		xfwrite(&sp_size, sizeof(uint64_t), f);
+		xfwrite(&rd_offset, sizeof(uint64_t), f);
+		xfwrite(&rd_size, sizeof(uint64_t), f);
+
+		sp = sp->next;
+	}
+
+	/* All information has been written now */
+
+	fclose(f);
+}
+
+static void usage(void)
+{
+	printf("usage: sptool ");
+#ifdef VERSION
+	printf(VERSION);
+#else
+	/* If built from sptool directory, VERSION is not set. */
+	printf("version unknown");
+#endif
+	printf(" [<args>]\n\n");
+
+	printf("This tool takes as inputs several image binary files and the\n"
+	       "resource description blobs as input and generates a package\n"
+	       "file that contains them.\n\n");
+	printf("Commands supported:\n");
+	printf("  -o <path>            Set output file path.\n");
+	printf("  -i <sp_path:rd_path> Add Secure Partition image and Resource\n"
+	       "                       Description blob (specified in two paths\n"
+	       "                       separated by a colon).\n");
+	printf("  -h                   Show this message.\n");
+	exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+	int ch;
+	const char *outname = NULL;
+
+	while ((ch = getopt(argc, argv, "hi:o:")) != -1) {
+		switch (ch) {
+		case 'i':
+			load_sp_rd(optarg);
+			break;
+		case 'o':
+			outname = optarg;
+			break;
+		case 'h':
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+	if (outname == NULL) {
+		fprintf(stderr, "error: An output file path must be provided.\n\n");
+		usage();
+		return 1;
+	}
+
+	output_write(outname);
+
+	cleanup();
+
+	return 0;
+}
diff --git a/tools/stm32image/Makefile b/tools/stm32image/Makefile
new file mode 100644
index 0000000..9c9b7b5
--- /dev/null
+++ b/tools/stm32image/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+PROJECT := stm32image${BIN_EXT}
+OBJECTS := stm32image.o
+V := 0
+
+HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE
+
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG
+else
+  HOSTCCFLAGS += -O2
+endif
+
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+HOSTCC := gcc
+
+.PHONY: all clean distclean
+
+all: ${PROJECT}
+
+${PROJECT}: ${OBJECTS} Makefile
+	@echo "  HOSTLD  $@"
+	${Q}${HOSTCC} ${OBJECTS} -o $@
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+%.o: %.c Makefile
+	@echo "  HOSTCC  $<"
+	${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@
+
+clean:
+	$(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS})
+
+distclean: clean
diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c
new file mode 100644
index 0000000..41024e2
--- /dev/null
+++ b/tools/stm32image/stm32image.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm/byteorder.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Magic = 'S' 'T' 'M' 0x32 */
+#define HEADER_MAGIC		__be32_to_cpu(0x53544D32)
+#define VER_MAJOR		2
+#define VER_MINOR		1
+#define VER_VARIANT		0
+#define HEADER_VERSION_V1	0x1
+#define TF_BINARY_TYPE		0x10
+
+/* Default option : bit0 => no signature */
+#define HEADER_DEFAULT_OPTION	(__cpu_to_le32(0x00000001))
+
+struct stm32_header {
+	uint32_t magic_number;
+	uint8_t image_signature[64];
+	uint32_t image_checksum;
+	uint8_t  header_version[4];
+	uint32_t image_length;
+	uint32_t image_entry_point;
+	uint32_t reserved1;
+	uint32_t load_address;
+	uint32_t reserved2;
+	uint32_t version_number;
+	uint32_t option_flags;
+	uint32_t ecdsa_algorithm;
+	uint8_t ecdsa_public_key[64];
+	uint8_t padding[83];
+	uint8_t binary_type;
+};
+
+static struct stm32_header stm32image_header;
+
+static void stm32image_default_header(struct stm32_header *ptr)
+{
+	if (!ptr) {
+		return;
+	}
+
+	ptr->magic_number = HEADER_MAGIC;
+	ptr->header_version[VER_MAJOR] = HEADER_VERSION_V1;
+	ptr->option_flags = HEADER_DEFAULT_OPTION;
+	ptr->ecdsa_algorithm = 1;
+	ptr->version_number = 0;
+	ptr->binary_type = TF_BINARY_TYPE;
+}
+
+static uint32_t stm32image_checksum(void *start, uint32_t len)
+{
+	uint32_t csum = 0;
+	uint32_t hdr_len = sizeof(struct stm32_header);
+	uint8_t *p;
+
+	if (len < hdr_len) {
+		return 0;
+	}
+
+	p = (unsigned char *)start + hdr_len;
+	len -= hdr_len;
+
+	while (len > 0) {
+		csum += *p;
+		p++;
+		len--;
+	}
+
+	return csum;
+}
+
+static void stm32image_print_header(const void *ptr)
+{
+	struct stm32_header *stm32hdr = (struct stm32_header *)ptr;
+
+	printf("Image Type   : ST Microelectronics STM32 V%d.%d\n",
+	       stm32hdr->header_version[VER_MAJOR],
+	       stm32hdr->header_version[VER_MINOR]);
+	printf("Image Size   : %lu bytes\n",
+	       (unsigned long)__le32_to_cpu(stm32hdr->image_length));
+	printf("Image Load   : 0x%08x\n",
+	       __le32_to_cpu(stm32hdr->load_address));
+	printf("Entry Point  : 0x%08x\n",
+	       __le32_to_cpu(stm32hdr->image_entry_point));
+	printf("Checksum     : 0x%08x\n",
+	       __le32_to_cpu(stm32hdr->image_checksum));
+	printf("Option     : 0x%08x\n",
+	       __le32_to_cpu(stm32hdr->option_flags));
+	printf("Version	   : 0x%08x\n",
+	       __le32_to_cpu(stm32hdr->version_number));
+}
+
+static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
+				  uint32_t loadaddr, uint32_t ep, uint32_t ver)
+{
+	struct stm32_header *stm32hdr = (struct stm32_header *)ptr;
+
+	stm32image_default_header(stm32hdr);
+
+	stm32hdr->load_address = __cpu_to_le32(loadaddr);
+	stm32hdr->image_entry_point = __cpu_to_le32(ep);
+	stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size -
+					     sizeof(struct stm32_header));
+	stm32hdr->image_checksum = stm32image_checksum(ptr, sbuf->st_size);
+	stm32hdr->version_number = __cpu_to_le32(ver);
+}
+
+static int stm32image_create_header_file(char *srcname, char *destname,
+					 uint32_t loadaddr, uint32_t entry,
+					 uint32_t version)
+{
+	int src_fd, dest_fd;
+	struct stat sbuf;
+	unsigned char *ptr;
+
+	dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
+	if (dest_fd == -1) {
+		fprintf(stderr, "Can't open %s: %s\n", destname,
+			strerror(errno));
+		return -1;
+	}
+
+	src_fd = open(srcname, O_RDONLY);
+	if (src_fd == -1) {
+		fprintf(stderr, "Can't open %s: %s\n", srcname,
+			strerror(errno));
+		return -1;
+	}
+
+	if (fstat(src_fd, &sbuf) < 0) {
+		return -1;
+	}
+
+	ptr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, src_fd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s\n", srcname);
+		return -1;
+	}
+
+	memset(&stm32image_header, 0, sizeof(struct stm32_header));
+
+	if (write(dest_fd, &stm32image_header, sizeof(struct stm32_header)) !=
+	    sizeof(struct stm32_header)) {
+		fprintf(stderr, "Write error %s: %s\n", destname,
+			strerror(errno));
+		return -1;
+	}
+
+	if (write(dest_fd, ptr, sbuf.st_size) != sbuf.st_size) {
+		fprintf(stderr, "Write error on %s: %s\n", destname,
+			strerror(errno));
+		return -1;
+	}
+
+	munmap((void *)ptr, sbuf.st_size);
+	close(src_fd);
+
+	if (fstat(dest_fd, &sbuf) < 0) {
+		return -1;
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+		   dest_fd, 0);
+
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s\n", srcname);
+		return -1;
+	}
+
+	stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr, entry, version);
+
+	stm32image_print_header(ptr);
+
+	munmap((void *)ptr, sbuf.st_size);
+	close(dest_fd);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, loadaddr = -1, entry = -1, err = 0, version = 0;
+	char *dest = NULL, *src = NULL;
+
+	while ((opt = getopt(argc, argv, ":s:d:l:e:v:")) != -1) {
+		switch (opt) {
+		case 's':
+			src = optarg;
+			break;
+		case 'd':
+			dest = optarg;
+			break;
+		case 'l':
+			loadaddr = strtol(optarg, NULL, 16);
+			break;
+		case 'e':
+			entry = strtol(optarg, NULL, 16);
+			break;
+		case 'v':
+			version = strtol(optarg, NULL, 10);
+			break;
+		default:
+			fprintf(stderr,
+				"Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point]\n",
+					argv[0]);
+			return -1;
+		}
+	}
+
+	if (!src) {
+		fprintf(stderr, "Missing -s option\n");
+		return -1;
+	}
+
+	if (!dest) {
+		fprintf(stderr, "Missing -d option\n");
+		return -1;
+	}
+
+	if (loadaddr == -1) {
+		fprintf(stderr, "Missing -l option\n");
+		return -1;
+	}
+
+	if (entry == -1) {
+		fprintf(stderr, "Missing -e option\n");
+		return -1;
+	}
+
+	err = stm32image_create_header_file(src, dest, loadaddr,
+					    entry, version);
+
+	return err;
+}